diff -urN linux-2.4.18/COPYING linux-2.4.19-pre5/COPYING --- linux-2.4.18/COPYING Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/COPYING Sat Mar 30 22:55:25 2002 @@ -307,7 +307,7 @@ the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -329,7 +329,7 @@ If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff -urN linux-2.4.18/CREDITS linux-2.4.19-pre5/CREDITS --- linux-2.4.18/CREDITS Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/CREDITS Sat Mar 30 22:55:37 2002 @@ -586,6 +586,13 @@ S: University of Michigan S: Ann Arbor, MI +N: Michael Cornwell +E: cornwell@acm.org +D: Original designer and co-author of ATA Taskfile +D: Kernel module SMART utilities +S: Santa Cruz, California +S: USA + N: Kees Cook E: cook@cpoint.net W: http://outflux.net/ @@ -1184,22 +1191,19 @@ N: Andre Hedrick E: andre@linux-ide.org -E: andre@aslab.com -E: andre@suse.com +E: andre@linuxdiskcert.org W: http://www.linux-ide.org/ +W: http://www.linuxdiskcert.org/ D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver D: Active-ATA-Chipset maddness.......... -D: Ultra DMA 100/66/33 -D: ATA-Disconnect +D: Ultra DMA 133/100/66/33 w/48-bit Addressing +D: ATA-Disconnect, ATA-TCQ D: ATA-Smart Kernel Daemon +D: Serial ATA +D: ATA Command Block and Taskfile S: Linux ATA Development (LAD) S: Concord, CA -S: ASL, Inc. 1-877-ASL-3535 -S: 1757 Houret Court, Milpitas, CA 95035 -S: SuSE Linux, Inc. -S: 580 Second Street, Suite 210 Oakland, CA 94607 -S: USA N: Jochen Hein E: jochen@jochen.org @@ -1574,8 +1578,10 @@ S: Luxembourg N: Gerd Knorr -E: kraxel@goldbach.in-berlin.de -D: SCSI CD-ROM driver hacking, vesafb, v4l, minor bug fixes +W: http://bytesex.org +E: kraxel@bytesex.org +E: kraxel@suse.de +D: video4linux, bttv, vesafb, some scsi, misc fixes N: Harald Koenig E: koenig@tat.physik.uni-tuebingen.de @@ -1652,6 +1658,13 @@ S: San Antonio, Texas 78269-1886 S: USA +N: Denis O. Kropp +E: dok@directfb.org +D: NeoMagic framebuffer driver +S: Badensche Str. 46 +S: 10715 Berlin +S: Germany + N: Andrzej M. Krzysztofowicz E: ankry@mif.pg.gda.pl D: Some 8-bit XT disk driver and devfs hacking @@ -1895,13 +1908,13 @@ S: USA N: Petko Manolov -E: petkan@dce.bg -D: USB ethernet (pegasus) driver -D: optimizing i[45]86 string routines -D: i386 task swithing hacks -S: 5, Vrah Mancho str. -S: 1324 Sofia -S: Bulgaria +E: petkan@users.sourceforge.net +D: USB ethernet pegasus/pegasus-II driver +D: i[45]86 optimized string routines +D: i386 task switching hacks +S: 482 Shadowgraph Dr. +S: San Jose, CA 95110 +S: USA N: Martin Mares E: mj@ucw.cz @@ -2130,6 +2143,10 @@ S: Fullarton 5063 S: South Australia +N. Wolfgang Muees +E: wmues@nexgo.de +D: Auerswald USB driver + N: Ian A. Murdock E: imurdock@gnu.ai.mit.edu D: Creator of Debian distribution @@ -2513,6 +2530,7 @@ N: Thiago Berlitz Rondon E: maluco@mileniumnet.com.br +W: http://vivaldi.linuxms.com.br/~maluco D: Miscellaneous kernel hacker S: R. Anhanguera, 1487 - Ipiranga S: 79080-740 - Campo Grande - Mato Grosso do Sul @@ -3265,9 +3283,10 @@ S: USA N: Richard Zidlicky -E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de -W: http://www.geocities.com/SiliconValley/Bay/2602/ +E: rz@linux-m68k.org, rdzidlic@geocities.com +W: http://www.geocities.com/rdzidlic D: Q40 port - see arch/m68k/q40/README +D: various m68k hacks S: Germany N: Werner Zimmermann diff -urN linux-2.4.18/Documentation/Changes linux-2.4.19-pre5/Documentation/Changes --- linux-2.4.18/Documentation/Changes Sun Dec 23 16:23:34 2001 +++ linux-2.4.19-pre5/Documentation/Changes Sat Mar 30 22:55:37 2002 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: May 9, 2001 +Last updated: February 13, 2002 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -54,7 +54,8 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.25 # tune2fs -o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs +o jfsutils 1.0.12 # fsck.jfs -V +o reiserfsprogs 3.x.1b # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -70,9 +71,9 @@ necessarily to users of other CPUs. Users of other CPUs should obtain information about their gcc version requirements from another source. -The recommended compiler for the kernel is gcc 2.95.3 or .4, and it +The recommended compiler for the kernel is gcc 2.95.x (x >= 3), and it should be used when you need absolute stability. You may use gcc 3.0.x -instead if you wish, although it may cause problems. Later versions of gcc +instead if you wish, although it may cause problems. Later versions of gcc have not received much testing for Linux kernel compilation, and there are almost certainly bugs (mainly, but not exclusively, in the kernel) that will need to be fixed in order to use these compilers. In any case, using @@ -106,14 +107,14 @@ your kernel. This change does, however, mean that you need a recent release of binutils. -If you can, upgrade to the latest 2.9.5 or 2.10 binutils release. Older +If you can, upgrade to the latest 2.9.5 or 2.1x binutils release. Older releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if at all possible. The later releases of 2.9.1.0.x (anything where x >= 22) can and do compile the kernel properly, but there are many benefits in -upgrading to 2.9.5 or 2.10 if you're up to it. +upgrading to 2.9.5 or 2.1x if you're up to it. -System utils -============ +System utilities +================ Architectural changes --------------------- @@ -171,6 +172,16 @@ The latest version of e2fsprogs fixes several bugs in fsck and debugfs. Obviously, it's a good idea to upgrade. +JFSutils +-------- + +The jfsutils package contains the utilities for the file system. +The following utilities are available: +o fsck.jfs - initiate replay of the transaction log, and check + and repair a JFS formatted partition. +o mkfs.jfs - create a JFS formatted partition. +o other file system utilities are also available in this package. + Reiserfsprogs ------------- @@ -267,8 +278,8 @@ Getting updated software ======================== -Compilers -********* +Kernel compilation +****************** egcs 1.1.2 (gcc 2.91.66) ------------------------ @@ -276,32 +287,22 @@ gcc 2.95.3 ---------- -o - -Gnu Make -******** +o Make 3.77 --------- o Binutils -******** - -2.9.1 series ------------- -o - -2.9.5 and 2.10 series ---------------------- -o +-------- +o System utilities **************** Util-linux ---------- -o +o Ksymoops -------- @@ -319,9 +320,13 @@ --------- o +JFSutils +--------- +o + Reiserfsprogs ------------- -o +o LVM toolset ----------- @@ -345,10 +350,10 @@ Powertweak ---------- -o +o -Network -******* +Networking +********** PPP --- diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.19-pre5/Documentation/Configure.help --- linux-2.4.18/Documentation/Configure.help Fri Mar 29 00:25:11 2002 +++ linux-2.4.19-pre5/Documentation/Configure.help Sat Mar 30 22:55:37 2002 @@ -723,6 +723,59 @@ say M here and read . The module will be called ide-floppy.o. +AWARD Bios Work-Around +CONFIG_IDEDISK_STROKE + Should you have a system w/ an AWARD Bios and your drives are larger + than 32GB and it will not boot, one is required to perform a few OEM + operations first. The option is called "STROKE" because it allows + one to "soft clip" the drive to work around a barrier limit. For + Maxtor drives it is called "jumpon.exe". Please search Maxtor's + web-site for "JUMPON.EXE". IBM has a similar tool at: + . + + If you are unsure, say N here. + +Raw Access to Media +CONFIG_IDE_TASK_IOCTL + This is a direct raw access to the media. It is a complex but + elegant solution to test and validate the domain of the hardware and + perform below the driver data recover if needed. This is the most + basic form of media-forensics. + + If you are unsure, say N here. + +Use Taskfile I/O +CONFIG_IDE_TASKFILE_IO + This is the "Jewel" of the patch. It will go away and become the new + driver core. Since all the chipsets/host side hardware deal w/ their + exceptions in "their local code" currently, adoption of a + standardized data-transport is the only logical solution. + Additionally we packetize the requests and gain rapid performance and + a reduction in system latency. Additionally by using a memory struct + for the commands we can redirect to a MMIO host hardware in the next + generation of controllers, specifically second generation Ultra133 + and Serial ATA. + + Since this is a major transition, it was deemed necessary to make the + driver paths buildable in separtate models. Therefore if using this + option fails for your arch then we need to address the needs for that + arch. + + If you want to test this functionality, say Y here. + +Force DMA +CONFIG_BLK_DEV_IDEDMA_FORCED + This is an old piece of lost code from Linux 2.0 Kernels. + + Generally say N here. + +DMA Only on Disks +CONFIG_IDEDMA_ONLYDISK + This is used if you know your ATAPI Devices are going to fail DMA + Transfers. + + Generally say N here. + SCSI emulation support CONFIG_BLK_DEV_IDESCSI This will provide SCSI host adapter emulation for IDE ATAPI devices, @@ -747,6 +800,14 @@ If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. +Use the NOOP Elevator (WARNING) +CONFIG_BLK_DEV_ELEVATOR_NOOP + If you are using a raid class top-level driver above the ATA/IDE core, + one may find a performance boost by preventing a merging and re-sorting + of the new requests. + + If unsure, say N. + ISA-PNP EIDE support CONFIG_BLK_DEV_ISAPNP If you have an ISA EIDE card that is PnP (Plug and Play) and @@ -1136,9 +1197,15 @@ SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 - This driver ensures (U)DMA support for SIS5513 chipset based - mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all - other DMA mode 2 limited chipsets are unsupported to date. + This driver ensures (U)DMA support for SIS5513 chipset family based + mainboards. + + The following chipsets are supported: + ATA16: SiS5511, SiS5513 + ATA33: SiS5591, SiS5597, SiS5598, SiS5600 + ATA66: SiS530, SiS540, SiS620, SiS630, SiS640 + ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740, + SiS745, SiS750 If you say Y here, you need to say Y to "Use DMA by default when available" as well. @@ -2513,6 +2580,19 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Local NAT support +CONFIG_IP_NF_NAT_LOCAL + This option enables support for NAT of locally originated connections. + Enable this if you need to use destination NAT on connections + originating from local processes on the nat box itself. + + Please note that you will need a recent version (>= 1.2.6a) + of the iptables userspace program in order to use this feature. + See http://www.iptables.org/ for download instructions. + + If unsure, say 'N'. + + Full NAT (Network Address Translation) CONFIG_IP_NF_NAT The Full NAT option allows masquerading, port forwarding and other @@ -3167,6 +3247,13 @@ via the file /proc/rtc and its behaviour is set by various ioctls on /dev/rtc. +Indy/I2 Hardware Watchdog +CONFIG_INDYDOG + Hardwaredriver for the Indy's/I2's watchdog. This is a + watchdog timer that will reboot the machine after a 60 second + timer expired and no process has written to /dev/watchdog during + that time. + Support the Bell Technologies HUB6 card CONFIG_HUB6 Say Y here to enable support in the dumb serial driver to support @@ -4207,6 +4294,16 @@ This driver supports the L7200 Color LCD. Say Y if you want graphics support. +NeoMagic display support (EXPERIMENTAL) +CONFIG_FB_NEOMAGIC + This driver supports notebooks with NeoMagic PCI chips. + Say Y if you have such a graphics card. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called neofb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + PowerMac "control" frame buffer device support CONFIG_FB_CONTROL This driver supports a frame buffer for the graphics adapter in the @@ -4796,6 +4893,13 @@ bits per pixel packed pixels on Mac. It supports variable font widths for low resolution screens. +Permedia3 support (EXPERIMENTAL) +CONFIG_FB_PM3 + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + HGA monochrome support CONFIG_FBCON_HGA This is the low level frame buffer console driver for Hercules mono @@ -6394,6 +6498,18 @@ boards supported by this driver, and for further information on the use of this driver. +SCSI tape drive support for Smart Array 5xxx +CONFIG_CISS_SCSI_TAPE + When enabled (Y), this option allows SCSI tape drives and SCSI medium + changers (tape robots) to be accessed via a Compaq 5xxx array + controller. (See Documentation/cciss.txt for more details.) + + "SCSI support" and "SCSI tape support" must also be enabled for this + option to work. + + When this option is disabled (N), the SCSI portion of the driver + is not compiled. + QuickNet Internet LineJack/PhoneJack support CONFIG_PHONE_IXJ Say M if you have a telephony card manufactured by Quicknet @@ -9588,6 +9704,21 @@ performance will be written to /proc/net/profile. If you don't know what it is about, you don't need it: say N. +Network packet generator +CONFIG_NET_PKTGEN + This module will inject preconfigured packets, at a configurable + rate, out of a given interface. It is used for network interface + stress testing and performance analysis. If you don't understand + what was just said, you don't neet it: say N. + + Documentation on how to use the packet generator can be found + at . + + This code is also available as a module called pktgen.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . + Wan interfaces support CONFIG_WAN Wide Area Networks (WANs), such as X.25, frame relay and leased @@ -9893,6 +10024,20 @@ . The module will be called i810-tco.o. +SliceCOM/PciCOM board support +CONFIG_COMX_HW_MUNICH + Hardware driver for the 'SliceCOM' (channelized E1) and 'PciCOM' + boards (X21) from the MultiGate family. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called comx-hw-munich.o. If you want to compile it + as a module, say M here and read . + + Read linux/Documentation/networking/slicecom.txt for help on + configuring and using SliceCOM interfaces. Further info on these cards + can be found at http://www.itc.hu or . + Support for HDLC and syncPPP protocols on MultiGate boards CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate @@ -10367,6 +10512,15 @@ Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also . +Broadcom Tigon3 support +CONFIG_TIGON3 + This driver supports Broadcom Tigon3 based gigabit Ethernet cards. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . This is + recommended. The module will be called tg3.o. + MyriCOM Gigabit Ethernet support CONFIG_MYRI_SBUS This driver supports MyriCOM Sbus gigabit Ethernet cards. @@ -12683,6 +12837,30 @@ If you have an MGE Ellipse UPS, or you see timeouts in HID transactions, say Y; otherwise say N. +EHCI (USB 2.0) support +CONFIG_USB_EHCI_HCD + The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 + "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. + If your USB host controller supports USB 2.0, you will likely want to + configure this Host Controller Driver. At this writing, the primary + implementation of EHCI is a chip from NEC, widely available in add-on + PCI cards, but implementations are in the works from other vendors + including Intel and Philips. Motherboard support is appearing. + + EHCI controllers are packaged with "companion" host controllers (OHCI + or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports + will connect to EHCI if it the device is high speed, otherwise they + connect to a companion controller. If you configure EHCI, you should + probably configure the OHCI (for NEC and some other vendors) USB Host + Controller Driver too. + + You may want to read . + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ehci-hcd.o. If you want to compile it as a + module, say M here and read . + UHCI (Intel PIIX4, VIA, ...) support CONFIG_USB_UHCI The Universal Host Controller Interface is a standard by Intel for @@ -12927,6 +13105,20 @@ The module will be called audio.o. If you want to compile it as a module, say M here and read . +EMI 2|6 USB Audio interface support +CONFIG_USB_EMI26 + This driver loads firmware to Emagic EMI 2|6 low latency USB + Audio interface. + + After firmware load the device is handled with standard linux + USB Audio driver. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called audio.o. If you want to compile it as a + module, say M here and read . + + USB Modem (CDC ACM) support CONFIG_USB_ACM This driver supports USB modems and ISDN adapters which support the @@ -12985,9 +13177,10 @@ USB Compaq iPAQ Driver CONFIG_USB_SERIAL_IPAQ - Say Y here if you want to connect to your Compaq iPAQ running - Windows CE 3.0 using a USB autosync cable. For information on using - the driver, read . + Say Y here if you want to connect to your Compaq iPAQ or HP Jornada + 548/568 running Windows CE 3.0 or PocketPC 2002 using a USB + cradle/cable. For information on using the driver, + read . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -13375,12 +13568,12 @@ Pegasus/Pegasus II based USB-Ethernet device support CONFIG_USB_PEGASUS - Say Y here if you know you have Pegasus or Pegasus II based adapter. + Say Y here if you know you have Pegasus or Pegasus-II based adapter. If in doubt then look at linux/drivers/usb/pegasus.h for the complete list of supported devices. If your particular adapter is not in the list and you are _sure_ it - is Pegasus or Pegasus II based then send me (pmanolov@lnxw.com) vendor - and device IDs. + is Pegasus or Pegasus-II based then send me (pmanolov@users.sourceforge.net) + vendor and device IDs. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -13621,6 +13814,16 @@ The module will be called rio500.o. If you want to compile it as a module, say M here and read . +USB Auerswald ISDN device support +CONFIG_USB_AUERSWALD + Say Y here if you want to connect an Auerswald USB ISDN Device + to your computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called auerswald.o. If you want to compile it as + a module, say M here and read . + D-Link DSB-R100 FM radio support CONFIG_USB_DSBR Say Y here if you want to connect this type of radio to your @@ -14674,10 +14877,12 @@ QNX4 file system support (read only) CONFIG_QNX4FS_FS - This is the file system used by the operating system QNX 4. Say Y if - you intend to mount QNX hard disks or floppies. Unless you say Y to - "QNX4FS read-write support" below, you will only be able to read - these file systems. + This is the file system used by the real-time operating systems + QNX 4 and QNX 6 (the latter is also called QNX RTP). + Further information is available at . + Say Y if you intend to mount QNX hard disks or floppies. + Unless you say Y to "QNX4FS read-write support" below, you will + only be able to read these file systems. This file system support is also available as a module ( = code which can be inserted in and removed from the running kernel @@ -14692,6 +14897,9 @@ CONFIG_QNX4FS_RW Say Y if you want to test write support for QNX4 file systems. + It's currently broken, so for now: + answer N. + Kernel automounter support CONFIG_AUTOFS_FS The automounter is a tool to automatically mount remote file systems @@ -17603,6 +17811,21 @@ The module is called shwdt.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Machine Check Exception +CONFIG_X86_MCE + Machine Check Exception support allows the processor to notify the + kernel if it detects a problem (e.g. overheating, component failure). + The action the kernel takes depends on the severity of the problem, + ranging from a warning message on the console, to halting the machine. + Your processor must be a Pentium or newer to support this - check the + flags in /proc/cpuinfo for mce. Note that some older Pentium systems + have a design flaw which leads to false MCE events - hence MCE is + disabled on all P5 processors, unless explicitly enabled with "mce" + as a boot argument. Similarly, if MCE is built in and creates a + problem on some new non-standard machine, you can boot with "nomce" + to disable it. MCE support simply ignores non-MCE processors like + the 386 and 486, so nearly everyone can say Y here. + Toshiba Laptop support CONFIG_TOSHIBA This adds a driver to safely access the System Management Mode of @@ -18943,8 +19166,11 @@ Yamaha YMF7xx PCI audio (native mode) CONFIG_SOUND_YMFPCI - Support for Yamaha cards including the YMF711, YMF715, YMF718, - YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital. + Support for Yamaha cards with the following chipsets: YMF724, + YMF724F, YMF740, YMF740C, YMF744, and YMF754. + + Two common cards that use this type of chip are Waveforce 192XG, + and Waveforce 192 Digital. Yamaha PCI legacy ports support CONFIG_SOUND_YMFPCI_LEGACY @@ -19504,6 +19730,10 @@ This enables the PCMCIA client driver for the Sedlbauer Speed Star and Speed Star II cards. +CONFIG_HISAX_AVM_A1_CS + This enables the PCMCIA client driver for the AVM A1 / Fritz!Card + PCMCIA cards. + ST5481 USB ISDN modem CONFIG_HISAX_ST5481 This enables the driver for ST5481 based USB ISDN adapters, @@ -20027,9 +20257,13 @@ Sun 3 support CONFIG_SUN3 This option enables support for the Sun 3 series of workstations. - Currently, only the Sun 3/80 is supported within the Sun 3x family. - You will also want to enable 68030 support. General Linux - information on the Sun 3x series (now discontinued) is at + Note that if this option is enabled, support for all other m68k + platforms above must be disabled in order to produce a working + kernel. + + Also, you will want to enable 68020 support below, and disable + all other CPU types. General Linux information on the Sun 3x series + (now discontinued) is at . If you don't want to compile a kernel for a Sun 3, say N. @@ -20037,8 +20271,8 @@ Sun 3X support CONFIG_SUN3X This option enables support for the Sun 3x series of workstations. - Be warned that this support is very experimental. You will also want - to say Y to 68020 support and N to the other processors below. + Currently, only the Sun 3/80 is supported within the Sun 3x family. + You will also want to enable 68030 support below General Linux information on the Sun 3x series (now discontinued) is at . @@ -20049,8 +20283,7 @@ ZS refers to a type of asynchronous serial port built in to the Sun3 and Sun3x workstations; if you have a Sun 3, you probably have these. Say 'Y' to support ZS ports directly. This option must be - enabled in order to support the - keyboard and mouse ports. + enabled in order to support the keyboard and mouse ports. Sun keyboard support CONFIG_SUN_KEYBOARD @@ -20348,6 +20581,17 @@ Hades. This increases the SCSI transfer rates at least ten times compared to PIO transfers. +Sun3 NCR5380 OBIO SCSI +CONFIG_SUN3_SCSI + This option will enable support for the OBIO (onboard io) NCR5380 + SCSI controller found in the Sun 3/50 and 3/60. Note that this + driver does not provide support for VME SCSI boards. + +Sun3x ESP SCSI +CONFIG_SUN3X_ESP + This option will enable support for the ESP SCSI controller found + onboard the Sun 3/80. + Ariadne support CONFIG_ARIADNE If you have a Village Tronic Ariadne Ethernet adapter, say Y. @@ -20410,6 +20654,19 @@ inserted in and removed from the running kernel whenever you want). The module is called apne.o. If you want to compile it as a module, say M here and read . + +Sun3/Sun3x on-board LANCE support +CONFIG_SUN3LANCE + This driver enables support for the on-board LANCE ethernet adapter + found on the Sun 3/50, 3/60, and 3/80 workstations. If you have + one of these workstations, and would like Ethernet, say Y. + Otherwise, say N. + +Sun3 on-board Intel 82586 support +CONFIG_SUN3_82586 + This driver enables support for the on-board Intel 82586 based Ethernet + adapter found on Sun 3/1xx and 3/2xx motherboards. Note that this driver + does not support 82586-based adapters on additional VME boards. Atari Lance support CONFIG_ATARILANCE diff -urN linux-2.4.18/Documentation/DocBook/Makefile linux-2.4.19-pre5/Documentation/DocBook/Makefile --- linux-2.4.18/Documentation/DocBook/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/DocBook/Makefile Sat Mar 30 22:55:25 2002 @@ -93,6 +93,8 @@ $(TOPDIR)/drivers/net/8390.c \ $(TOPDIR)/drivers/char/serial.c \ $(TOPDIR)/drivers/pci/pci.c \ + $(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \ + $(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \ $(TOPDIR)/drivers/block/ll_rw_blk.c \ $(TOPDIR)/drivers/sound/sound_core.c \ $(TOPDIR)/drivers/sound/sound_firmware.c \ diff -urN linux-2.4.18/Documentation/DocBook/kernel-api.tmpl linux-2.4.19-pre5/Documentation/DocBook/kernel-api.tmpl --- linux-2.4.18/Documentation/DocBook/kernel-api.tmpl Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/DocBook/kernel-api.tmpl Sat Mar 30 22:55:25 2002 @@ -162,6 +162,10 @@ PCI Support Library !Edrivers/pci/pci.c + PCI Hotplug Support Library +!Edrivers/hotplug/pci_hotplug_core.c +!Edrivers/hotplug/pci_hotplug_util.c + MCA Architecture MCA Device Functions !Earch/i386/kernel/mca.c diff -urN linux-2.4.18/Documentation/DocBook/kernel-locking.tmpl linux-2.4.19-pre5/Documentation/DocBook/kernel-locking.tmpl --- linux-2.4.18/Documentation/DocBook/kernel-locking.tmpl Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/DocBook/kernel-locking.tmpl Sat Mar 30 22:55:33 2002 @@ -788,8 +788,18 @@ - Note that the atomic operations are defined to act as both - read and write barriers on all platforms. + Note that the atomic operations do in general not act as memory + barriers. Instead you can insert a memory barrier before or + after atomic_inc() or + atomic_dec() by inserting + smp_mb__before_atomic_inc(), + smp_mb__after_atomic_inc(), + smp_mb__before_atomic_dec() or + smp_mb__after_atomic_dec() + respectively. The advantage of using those macros instead of + smp_mb() is, that they are cheaper on some + platforms. + diff -urN linux-2.4.18/Documentation/cachetlb.txt linux-2.4.19-pre5/Documentation/cachetlb.txt --- linux-2.4.18/Documentation/cachetlb.txt Sun Dec 23 16:23:34 2001 +++ linux-2.4.19-pre5/Documentation/cachetlb.txt Sat Mar 30 22:55:33 2002 @@ -339,7 +339,18 @@ If the icache does not snoop stores then this routine will need to flush it. + void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, unsigned long addr, int len) + This is called when the kernel stores into addresses that are + part of the address space of a user process (which may be some + other process than the current process). The addr argument + gives the virtual address in that process's address space, + page is the page which is being modified, and len indicates + how many bytes have been modified. The modified region must + not cross a page boundary. Currently this is only called from + kernel/ptrace.c. + void flush_icache_page(struct vm_area_struct *vma, struct page *page) - All the functionality of flush_icache_page can be implemented in - flush_dcache_page and update_mmu_cache. In 2.5 the hope is to - remove this interface completely. + This is called when a page-cache page is about to be mapped + into a user process' address space. It offers an opportunity + for a port to ensure d-cache/i-cache coherency if necessary. diff -urN linux-2.4.18/Documentation/cciss.txt linux-2.4.19-pre5/Documentation/cciss.txt --- linux-2.4.18/Documentation/cciss.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/cciss.txt Sat Mar 30 22:55:25 2002 @@ -100,7 +100,7 @@ can be informed of changes to the virtual SCSI bus which the driver presents to it in the usual way. For example: - echo add-single-device 3 2 1 0 > /proc/scsi/scsi + echo scsi add-single-device 3 2 1 0 > /proc/scsi/scsi to add a device on controller 3, bus 2, target 1, lun 0. Note that the driver makes an effort to preserve the devices positions diff -urN linux-2.4.18/Documentation/fb/matroxfb.txt linux-2.4.19-pre5/Documentation/fb/matroxfb.txt --- linux-2.4.18/Documentation/fb/matroxfb.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/fb/matroxfb.txt Sat Mar 30 22:55:25 2002 @@ -10,7 +10,7 @@ * It provides a nice large console (128 cols + 48 lines with 1024x768) without using tiny, unreadable fonts. - * You can run XF68_FBDev on top of /dev/fb0 + * You can run XF{68,86}_FBDev or XFree86 fbdev driver on top of /dev/fb0 * Most important: boot logo :-) Disadvantages: @@ -27,9 +27,6 @@ If you want, for example, enable a resolution of 1280x1024x24bpp you should pass to the kernel this command line: "video=matrox:vesa:0x1BB". -Note that the same line, if 'appended' as a lilo parameter in lilo.conf will -read "video=matrox:vesa:443" because lilo pass integer parameters as decimal -numbers to the kernel. You should compile in both vgacon (to boot if you remove you Matrox from box) and matroxfb (for graphics mode). You should not compile-in vesafb @@ -82,13 +79,16 @@ X11 === -XF68_FBDev should work just fine, but it is non-accelerated. On non-intel +XF{68,86}_FBDev should work just fine, but it is non-accelerated. On non-intel architectures there are some glitches for 24bpp videomodes. 8, 16 and 32bpp works fine. Running another (accelerated) X-Server like XF86_SVGA works too. But (at least) XFree servers have big troubles in multihead configurations (even on first -head, not even talking about second). +head, not even talking about second). Running XFree86 4.x accelerated mga +driver is possible, but you must not enable DRI - if you do, resolution and +color depth of your X desktop must match resolution and color depths of your +virtual consoles, otherwise X will corrupt accelerator settings. SVGALib diff -urN linux-2.4.18/Documentation/filesystems/Locking linux-2.4.19-pre5/Documentation/filesystems/Locking --- linux-2.4.18/Documentation/filesystems/Locking Sun Dec 23 16:23:34 2001 +++ linux-2.4.19-pre5/Documentation/filesystems/Locking Sat Mar 30 22:55:25 2002 @@ -156,7 +156,7 @@ block_flushpage() instead. ->releasepage() is called when the kernel is about to try to drop the buffers from the page in preparation for freeing it. It returns zero to -indicate that the buffers are (or may be) freeable. If ->flushpage is zero, +indicate that the buffers are (or may be) freeable. If ->releasepage is zero, the kernel assumes that the fs has no private interest in the buffers. Note: currently almost all instances of address_space methods are diff -urN linux-2.4.18/Documentation/filesystems/cramfs.txt linux-2.4.19-pre5/Documentation/filesystems/cramfs.txt --- linux-2.4.18/Documentation/filesystems/cramfs.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/filesystems/cramfs.txt Sat Mar 30 22:55:25 2002 @@ -10,7 +10,7 @@ You can't write to a cramfs filesystem (making it compressible and compact also makes it _very_ hard to update on-the-fly), so you have to -create the disk image with the "mkcramfs" utility in scripts/cramfs. +create the disk image with the "mkcramfs" utility. Usage Notes @@ -19,9 +19,7 @@ File sizes are limited to less than 16MB. Maximum filesystem size is a little over 256MB. (The last file on the -filesystem is allowed to extend past 256MB.) (Comments in mkcramfs.c -suggest that ROM sizes may be limited to 64MB, though that's not a -limitation in cramfs code.) +filesystem is allowed to extend past 256MB.) Only the low 8 bits of gid are stored. The current version of mkcramfs simply truncates to 8 bits, which is a potential security @@ -48,18 +46,28 @@ For /usr/share/magic ------------------- +-------------------- -0 long 0x28cd3d45 Linux cramfs ->4 long x size %d ->8 long x flags 0x%x ->12 long x future 0x%x +0 ulelong 0x28cd3d45 Linux cramfs offset 0 +>4 ulelong x size %d +>8 ulelong x flags 0x%x +>12 ulelong x future 0x%x >16 string >\0 signature "%.16s" ->32 long x fsid.crc 0x%x ->36 long x fsid.edition %d ->40 long x fsid.blocks %d ->44 long x fsid.files %d +>32 ulelong x fsid.crc 0x%x +>36 ulelong x fsid.edition %d +>40 ulelong x fsid.blocks %d +>44 ulelong x fsid.files %d >48 string >\0 name "%.16s" +512 ulelong 0x28cd3d45 Linux cramfs offset 512 +>516 ulelong x size %d +>520 ulelong x flags 0x%x +>524 ulelong x future 0x%x +>528 string >\0 signature "%.16s" +>544 ulelong x fsid.crc 0x%x +>548 ulelong x fsid.edition %d +>552 ulelong x fsid.blocks %d +>556 ulelong x fsid.files %d +>560 string >\0 name "%.16s" Hacker Notes diff -urN linux-2.4.18/Documentation/ia64/IRQ-redir.txt linux-2.4.19-pre5/Documentation/ia64/IRQ-redir.txt --- linux-2.4.18/Documentation/ia64/IRQ-redir.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/ia64/IRQ-redir.txt Sat Mar 30 22:55:25 2002 @@ -0,0 +1,69 @@ +IRQ affinity on IA64 platforms +------------------------------ + 07.01.2002, Erich Focht + + +By writing to /proc/irq/IRQ#/smp_affinity the interrupt routing can be +controlled. The behavior on IA64 platforms is slightly different from +that described in Documentation/IRQ-affinity.txt for i386 systems. + +Because of the usage of SAPIC mode and physical destination mode the +IRQ target is one particular CPU and cannot be a mask of several +CPUs. Only the first non-zero bit is taken into account. + + +Usage examples: + +The target CPU has to be specified as a hexadecimal CPU mask. The +first non-zero bit is the selected CPU. This format has been kept for +compatibility reasons with i386. + +Set the delivery mode of interrupt 41 to fixed and route the +interrupts to CPU #3 (logical CPU number) (2^3=0x08): + echo "8" >/proc/irq/41/smp_affinity + +Set the default route for IRQ number 41 to CPU 6 in lowest priority +delivery mode (redirectable): + echo "r 40" >/proc/irq/41/smp_affinity + +The output of the command + cat /proc/irq/IRQ#/smp_affinity +gives the target CPU mask for the specified interrupt vector. If the CPU +mask is preceeded by the character "r", the interrupt is redirectable +(i.e. lowest priority mode routing is used), otherwise its route is +fixed. + + + +Initialization and default behavior: + +If the platform features IRQ redirection (info provided by SAL) all +IO-SAPIC interrupts are initialized with CPU#0 as their default target +and the routing is the so called "lowest priority mode" (actually +fixed SAPIC mode with hint). The XTP chipset registers are used as hints +for the IRQ routing. Currently in Linux XTP registers can have three +values: + - minimal for an idle task, + - normal if any other task runs, + - maximal if the CPU is going to be switched off. +The IRQ is routed to the CPU with lowest XTP register value, the +search begins at the default CPU. Therefore most of the interrupts +will be handled by CPU #0. + +If the platform doesn't feature interrupt redirection IOSAPIC fixed +routing is used. The target CPUs are distributed in a round robin +manner. IRQs will be routed only to the selected target CPUs. Check +with + cat /proc/interrupts + + + +Comments: + +On large (multi-node) systems it is recommended to route the IRQs to +the node to which the corresponding device is connected. +For systems like the NEC AzusA we get IRQ node-affinity for free. This +is because usually the chipsets on each node redirect the interrupts +only to their own CPUs (as they cannot see the XTP registers on the +other nodes). + diff -urN linux-2.4.18/Documentation/networking/3c359.txt linux-2.4.19-pre5/Documentation/networking/3c359.txt --- linux-2.4.18/Documentation/networking/3c359.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/3c359.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,58 @@ + +3COM PCI TOKEN LINK VELOCITY XL TOKEN RING CARDS README + +Release 0.9.0 - Release + Jul 17th 2000 Mike Phillips + + 1.2.0 - Final + Feb 17th 2002 Mike Phillips + Updated for submission to the 2.4.x kernel. + +Thanks: + Terry Murphy from 3Com for tech docs and support, + Adam D. Ligas for testing the driver. + +Note: + This driver will NOT work with the 3C339 Token Ring cards, you need +to use the tms380 driver instead. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz and message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will open at the same speed as +its last opening. This can be hazardous if this speed does not match the speed +you want the ring to operate at. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +2/17/02 Mike Phillips + diff -urN linux-2.4.18/Documentation/networking/3c509.txt linux-2.4.19-pre5/Documentation/networking/3c509.txt --- linux-2.4.18/Documentation/networking/3c509.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/3c509.txt Sat Mar 30 22:55:37 2002 @@ -0,0 +1,210 @@ +Linux and the 3Com EtherLink III Series Ethercards (driver v1.18c and higher) +---------------------------------------------------------------------------- + +This file contains the instructions and caveats for v1.18c and higher versions +of the 3c509 driver. You should not use the driver without reading this file. + +release 1.0 +28 February 2002 +Current maintainer (corrections to): + David Ruggiero + +---------------------------------------------------------------------------- + +(0) Introduction + +The following are notes and information on using the 3Com EtherLink III series +ethercards in Linux. These cards are commonly known by the most widely-used +card's 3Com model number, 3c509. They are all 10mb/s ISA-bus cards and shouldn't +be (but sometimes are) confused with the similarly-numbered PCI-bus "3c905" +(aka "Vortex" or "Boomerang") series. Kernel support for the 3c509 family is +provided by the module 3c509.c, which has code to support all of the following +models: + + 3c509 (original ISA card) + 3c509B (later revision of the ISA card; supports full-duplex) + 3c589 (PCMCIA) + 3c589B (later revision of the 3c589; supports full-duplex) + 3c529 (MCA) + 3c579 (EISA) + +Large portions of this documentation were heavily borrowed from the guide +written the original author of the 3c509 driver, Donald Becker. The master +copy of that document, which contains notes on older versions of the driver, +currently resides on Scyld web server: http://www.scyld.com/network/3c509.html. + + +(1) Special Driver Features + +Overriding card settings + +The driver allows boot- or load-time overriding of the card's detected IOADDR, +IRQ, and transceiver settings, although this capability shouldn't generally be +needed except to enable full-duplex mode (see below). An example of the syntax +for LILO parameters for doing this: + + ether=10,0x310,3,0x3c509,eth0 + +This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and +transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts +with other card types when overriding the I/O address. When the driver is +loaded as a module, only the IRQ and transceiver setting may be overridden. +For example, setting two cards to 10base2/IRQ10 and AUI/IRQ11 is done by using +the xcvr and irq module options: + + options 3c509 xcvr=3,3 irq=10,11 + + +(2) Full-duplex mode + +The v1.18c driver added support for the 3c509B's full-duplex capabilities. +In order to enable and successfully use full-duplex mode, three conditions +must be met: + +(a) You must have a Etherlink III card model whose hardware supports full- +duplex operations. Currently, the only members of the 3c509 family that are +positively known to support full-duplex are the 3c509B (ISA bus) and 3c589B +(PCMCIA) cards. Cards without the "B" model designation do *not* support +full-duplex mode; these include the original 3c509 (no "B"), the original +3c589, the 3c529 (MCA bus), and the 3c579 (EISA bus). + +(b) You must be using your card's 10baseT transceiver (i.e., the RJ-45 +connector), not its AUI (thick-net) or 10base2 (thin-net/coax) interfaces. +AUI and 10base2 network cabling is physically incapable of full-duplex +operation. + +(c) Most importantly, your 3c509B must be connected to a link partner that is +itself full-duplex capable. This is almost certainly one of two things: a full- +duplex-capable Ethernet switch (*not* a hub), or a full-duplex-capable NIC on +another system that's connected directly to the 3c509B via a crossover cable. + +/////Extremely important caution concerning full-duplex mode///// +Understand that the 3c509B's hardware's full-duplex support is much more +limited than that provide by more modern network interface cards. Although +at the physical layer of the network it fully supports full-duplex operation, +the card was designed before the current Ethernet auto-negotiation (N-way) +spec was written. This means that the 3c509B family ***cannot and will not +auto-negotiate a full-duplex connection with its link partner under any +circumstances, no matter how it is initialized***. If the full-duplex mode +of the 3c509B is enabled, its link partner will very likely need to be +independently _forced_ into full-duplex mode as well; otherwise various nasty +failures will occur - at the very least, you'll see massive numbers of packet +collisions. This is one of very rare circumstances where disabling auto- +negotiation and forcing the duplex mode of a network interface card or switch +would ever be necessary or desirable. + + +(3) Available Transceiver Types + +For versions of the driver v1.18c and above, the available transceiver types are: + +0 transceiver type from EEPROM config (normally 10baseT); force half-duplex +1 AUI (thick-net / DB15 connector) +2 (undefined) +3 10base2 (thin-net == coax / BNC connector) +4 10baseT (RJ-45 connector); force half-duplex mode +8 transceiver type and duplex mode taken from card's EEPROM config settings +12 10baseT (RJ-45 connector); force full-duplex mode + +Prior to driver version 1.18c, only tranceiver codes 0-4 were supported. Note +that the new transceiver codes 8 and 12 are the *only* ones that will enable +full-duplex mode, no matter what the card's detected EEPROM settings might be. +This insured that merely upgrading the driver from an earlier version would +never automatically enable full-duplex mode in an existing installation; +it must always be explicitly enabled via one of these code in order to be +activated. + + +(4a) Interpretation of error messages and common problems + +Error Messages + +eth0: Infinite loop in interrupt, status 2011. +These are "mostly harmless" message indicating that the driver had too much +work during that interrupt cycle. With a status of 0x2011 you are receiving +packets faster than they can be removed from the card. This should be rare +or impossible in normal operation. Possible causes of this error report are: + + - a "green" mode enabled that slows the processor down when there is no + keyboard activitiy. + + - some other device or device driver hogging the bus or disabling interrupts. + Check /proc/interrupts for excessive interrupt counts. The timer tick + interrupt should always be incrementing faster than the others. + +No received packets +If a 3c509, 3c562 or 3c589 can successfully transmit packets, but never +receives packets (as reported by /proc/net/dev or 'ifconfig') you likely +have an interrupt line problem. Check /proc/interrupts to verify that the +card is actually generating interrupts. If the interrupt count is not +increasing you likely have a physical conflict with two devices trying to +use the same ISA IRQ line. The common conflict is with a sound card on IRQ10 +or IRQ5, and the easiest solution is to move the 3c509 to a different +interrupt line. If the device is receiving packets but 'ping' doesn't work, +you have a routing problem. + +Tx Carrier Errors Reported in /proc/net/dev +If an EtherLink III appears to transmit packets, but the "Tx carrier errors" +field in /proc/net/dev increments as quickly as the Tx packet count, you +likely have an unterminated network or the incorrect media tranceiver selected. + +3c509B card is not detected on machines with an ISA PnP BIOS. +While the updated driver works with most PnP BIOS programs, it does not work +with all. This can be fixed by disabling PnP support using the 3Com-supplied +setup program. + +3c509 card is not detected on overclocked machines +Increase the delay time in id_read_eeprom() from the current value, 500, +to an absurdly high value, such as 5000. + + +(4b) Decoding Status and Error Messages + +The bits in the main status register are: + +value description +0x01 Interrupt latch +0x02 Tx overrun, or Rx underrun +0x04 Tx complete +0x08 Tx FIFO room available +0x10 A complete Rx packet has arrived +0x20 A Rx packet has started to arrive +0x40 The driver has requested an interrupt +0x80 Statistics counter nearly full + +The bits in the transmit (Tx) status word are: + +value description +0x02 Out-of-window collision. +0x04 Status stack overflow (normally impossible). +0x08 16 collisions. +0x10 Tx underrun (not enough PCI bus bandwidth). +0x20 Tx jabber. +0x40 Tx interrupt requested. +0x80 Status is valid (this should always be set). + + +When a transmit error occurs the driver produces a status message such as + + eth0: Transmit error, Tx status register 82 + +The two values typically seen here are: + +0x82 +Out of window collision. This typically occurs when some other Ethernet +host is incorrectly set to full duplex on a half duplex network. + +0x88 +16 collisions. This typically occurs when the network is exceptionally busy +or when another host doesn't correctly back off after a collision. If this +error is mixed with 0x82 errors it is the result of a host incorrectly set +to full duplex (see above). + +Both of these errors are the result of network problems that should be +corrected. They do not represent driver malfunction. + + +(5) Revision history (this file) + +28Feb02 v1.0 DR New; major portions based on Becker original 3c509 docs + diff -urN linux-2.4.18/Documentation/networking/arcnet-hardware.txt linux-2.4.19-pre5/Documentation/networking/arcnet-hardware.txt --- linux-2.4.18/Documentation/networking/arcnet-hardware.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/networking/arcnet-hardware.txt Sat Mar 30 22:55:25 2002 @@ -2256,7 +2256,7 @@ When I got my two cards, one of them had this switch set to "enhanced". That card didn't work at all, it wasn't even recognized by the driver. The other card had this switch set to "compatible" and it behaved absolutely normally. I -guess that the switch on one of the cards, must have been changed accidently +guess that the switch on one of the cards, must have been changed accidentally when the card was taken out of its former host. The question remains unanswered, what is the purpose of the "enhanced" position? diff -urN linux-2.4.18/Documentation/networking/bonding.txt linux-2.4.19-pre5/Documentation/networking/bonding.txt --- linux-2.4.18/Documentation/networking/bonding.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/networking/bonding.txt Sat Mar 30 22:55:37 2002 @@ -271,7 +271,7 @@ If you wish to change the MAC address, you can set it with ifconfig: - # ifconfig bond0 ha ether 00:11:22:33:44:55 + # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): @@ -503,7 +503,7 @@ Resources and links =================== -Current developement on this driver is posted to: +Current development on this driver is posted to: - http://www.sourceforge.net/projects/bonding/ Donald Becker's Ethernet Drivers and diag programs may be found at : diff -urN linux-2.4.18/Documentation/networking/comx.txt linux-2.4.19-pre5/Documentation/networking/comx.txt --- linux-2.4.18/Documentation/networking/comx.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/networking/comx.txt Sat Mar 30 22:55:33 2002 @@ -24,6 +24,8 @@ LoCOMX (1x512 kbps passive board) MixCOM (1x512 or 2x512kbps passive board with a hardware watchdog an optional BRI interface and optional flashROM (1-32M)) +SliceCOM (1x2Mbps channelized E1 board) +PciCOM (X21) At the moment of writing this document, the (Cisco)-HDLC, LAPB, SyncPPP and Frame Relay (DTE, rfc1294 IP encapsulation with partially implemented Q933a @@ -72,7 +74,7 @@ To create the interface 'comx0' which is the first channel of a COMX card: insmod comx -# insmod comx-hw-comx ; insmod comx-proto-hdlc (these are usually +# insmod comx-hw-comx ; insmod comx-proto-ppp (these are usually autoloaded if you use the kernel module loader) mkdir /proc/comx/comx0 @@ -141,47 +143,45 @@ The MixCOM board doesn't require firmware, the driver communicates with it through I/O ports. You can have three of these cards in one machine. -THE HDLC LINE PROTOCOL DRIVER +THE SLICECOM DRIVER + +The SliceCOM board doesn't require firmware. You can have 4 of these cards +in one machine. The driver doesn't (yet) support shared interrupts, so +you will need a separate IRQ line for every board. +Read linux/Documentation/networking/slicecom.txt for help on configuring +this adapter. + +THE HDLC/PPP LINE PROTOCOL DRIVER + +The HDLC/SyncPPP line protocol driver uses the kernel's built-in syncppp +driver (syncppp.o). You don't have to manually select syncppp.o when building +the kernel, the dependencies compile it in automatically. -There's only one configurable parameter with this protocol: the 'keepalive' -value. You can set this in seconds or set to 'off'. Agree with the administrator -of your peer router on this setting. The default is 10 (seconds). -EXAMPLE + +EXAMPLE (setting up hw parameters, see above) + +# using HDLC: echo hdlc >/proc/comx/comx0/protocol echo 10 >/proc/comx/comx0/keepalive <- not necessary, 10 is the default ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 - -THE PPP LINE PROTOCOL DRIVER - -To use this driver, you have to have ppp-2.3.4, and have a modified version of -pppd (this pppd will work as async pppd to, the modifiactions merely relax -some restricions in order to be able to use non-async lines too. -If configured, this driver can use Van Jacobson TCP header compression (you'll -need the slhc.o module for this). -Additionally to use this protocol, enable async ppp in your kernel config, and -create the comx device special files in /dev. They're character special files -with major 88, and their names must be the same as their network interface -counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so -on). - -EXAMPLE - (setting up hw parameters, see above) + +# using PPP: echo ppp >/proc/comx/comx0/protocol ifconfig comx0 up -pppd comx0 1.2.3.4:5.6.7.8 persist <- with this option pppd won't exit - when the line goes down +ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 + THE LAPB LINE PROTOCOL DRIVER For this, you'll need to configure LAPB support (See 'LAPB Data Link Driver' in 'Network options' section) into your kernel (thanks to Jonathan Naylor for his excellent implementation). -comxlapb.o provides the following files in the appropriate directory +comx-proto-lapb.o provides the following files in the appropriate directory (the default values in parens): t1 (5), t2 (1), n2 (20), mode (DTE, STD) and window (7). Agree with the administrator of your peer router on these settings (most people use defaults, but you have to know if you are DTE or @@ -221,7 +221,7 @@ boardtype: Type of the hardware. Valid values are: - 'comx', 'hicomx', 'locomx', 'cmx'. + 'comx', 'hicomx', 'locomx', 'cmx', 'slicecom'. protocol: Data-link protocol on this channel. Can be: HDLC, LAPB, PPP, FRAD diff -urN linux-2.4.18/Documentation/networking/dl2k.txt linux-2.4.19-pre5/Documentation/networking/dl2k.txt --- linux-2.4.18/Documentation/networking/dl2k.txt Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/Documentation/networking/dl2k.txt Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ D-Link DL2000-based Gigabit Ethernet Adapter Installation for Linux - Jan 02, 2002 + Jan 29, 2002 Contents ======== @@ -199,8 +199,8 @@ 6 1000Mbps full duplex. By default, the NIC operates at autosense. - Note that only 1000mbps_fd and 1000mbps_hd - types are available for fiber adapter. + 1000mbps_fd and 1000mbps_hd types are only + available for fiber adapter. vlan=[0|1] - Specifies the VLAN ID. If vlan=0, the Virtual Local Area Network (VLAN) function is diff -urN linux-2.4.18/Documentation/networking/driver.txt linux-2.4.19-pre5/Documentation/networking/driver.txt --- linux-2.4.18/Documentation/networking/driver.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/driver.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,84 @@ +Documents about softnet driver issues in general can be found +at: + + http://www.firstfloor.org/~andi/softnet/ + +Transmit path guidelines: + +1) The hard_start_xmit method must never return '1' under any + normal circumstances. It is considered a hard error unless + there is no way your device can tell ahead of time when it's + transmit function will become busy. + + Instead it must maintain the queue properly. For example, + for a driver implementing scatter-gather this means: + + static int drv_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) + { + struct drv *dp = dev->priv; + + lock_tx(dp); + ... + /* This is a hard error log it. */ + if (TX_BUFFS_AVAIL(dp) <= (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + unlock_tx(dp); + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + return 1; + } + + ... queue packet to card ... + ... update tx consumer index ... + + if (TX_BUFFS_AVAIL(dp) <= (MAX_SKB_FRAGS + 1)) + netif_stop_queue(dev); + + ... + unlock_tx(dp); + ... + } + + And then at the end of your TX reclaimation event handling: + + if (netif_queue_stopped(dp->dev) && + TX_BUFFS_AVAIL(dp) > (MAX_SKB_FRAGS + 1)) + netif_wake_queue(dp->dev); + + For a non-scatter-gather supporting card, the three tests simply become: + + /* This is a hard error log it. */ + if (TX_BUFFS_AVAIL(dp) <= 0) + + and: + + if (TX_BUFFS_AVAIL(dp) == 0) + + and: + + if (netif_queue_stopped(dp->dev) && + TX_BUFFS_AVAIL(dp) > 0) + netif_wake_queue(dp->dev); + +2) Do not forget to update netdev->trans_start to jiffies after + each new tx packet is given to the hardware. + +3) Do not forget that once you return 0 from your hard_start_xmit + method, it is your driver's responsibility to free up the SKB + and in some finite amount of time. + + For example, this means that it is not allowed for your TX + mitigation scheme to let TX packets "hang out" in the TX + ring unreclaimed forever if no new TX packets are sent. + This error can deadlock sockets waiting for send buffer room + to be freed up. + + If you return 1 from the hard_start_xmit method, you must not keep + any reference to that SKB and you must not attempt to free it up. + +Probing guidelines: + +1) Any hardware layer address you obtain for your device should + be verified. For example, for ethernet check it with + linux/etherdevice.h:is_valid_ether_addr() diff -urN linux-2.4.18/Documentation/networking/ifenslave.c linux-2.4.19-pre5/Documentation/networking/ifenslave.c --- linux-2.4.18/Documentation/networking/ifenslave.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/networking/ifenslave.c Sat Mar 30 22:55:37 2002 @@ -38,6 +38,9 @@ * take care of this itself * - Try the SIOC*** versions of the bonding ioctls before using the * old versions + * - 2002/02/18 Erik Habbinga : + * - ifr2.ifr_flags was not initialized in the hwaddr_notset case, + * SIOCGIFFLAGS now called before hwaddr_notset test */ static char *version = @@ -288,19 +291,19 @@ hwaddr from it's first slave. - if !hwaddr_notset, assign the master's hwaddr to each slave */ - + + strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, + strerror(saved_errno)); + return 1; + } + if (hwaddr_notset) { /* we do nothing */ } else { /* we'll assign master's hwaddr to this slave */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - return 1; - } - if (ifr2.ifr_flags & IFF_UP) { ifr2.ifr_flags &= ~IFF_UP; if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { diff -urN linux-2.4.18/Documentation/networking/ip-sysctl.txt linux-2.4.19-pre5/Documentation/networking/ip-sysctl.txt --- linux-2.4.18/Documentation/networking/ip-sysctl.txt Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/Documentation/networking/ip-sysctl.txt Sat Mar 30 22:55:37 2002 @@ -126,7 +126,13 @@ if network conditions require more than default value. tcp_tw_recycle - BOOLEAN - Enable fast recycling TIME-WAIT sockets. Default value is 1. + Enable fast recycling TIME-WAIT sockets. Default value is 0. + It should not be changed without advice/request of technical + experts. + +tcp_tw_reuse - BOOLEAN + Allow to reuse TIME-WAIT sockets for new connections when it is + safe from protocol viewpoint. Default value is 0. It should not be changed without advice/request of technical experts. @@ -182,10 +188,7 @@ still did not receive an acknowledgement from connecting client. Default value is 1024 for systems with more than 128Mb of memory, and 128 for low memory machines. If server suffers of overload, - try to increase this number. Warning! If you make it greater - than 1024, it would be better to change TCP_SYNQ_HSIZE in - include/net/tcp.h to keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog - and to recompile kernel. + try to increase this number. tcp_window_scaling - BOOLEAN Enable window scaling as defined in RFC1323. @@ -357,6 +360,17 @@ mc_forwarding - BOOLEAN Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE and a multicast routing daemon is required. + +medium_id - INTEGER + Integer value used to differentiate the devices by the medium they + are attached to. Two devices can have different id values when + the broadcast packets are received only on one of them. + The default value 0 means that the device is the only interface + to its medium, value of -1 means that medium is not known. + + Currently, it is used to change the proxy_arp behavior: + the proxy_arp feature is enabled for packets forwarded between + two devices attached to different media. proxy_arp - BOOLEAN Do proxy arp. diff -urN linux-2.4.18/Documentation/networking/pktgen.txt linux-2.4.19-pre5/Documentation/networking/pktgen.txt --- linux-2.4.18/Documentation/networking/pktgen.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/pktgen.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,50 @@ +How to use the Linux packet generator module. + +1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it + in the place where insmod may find it. +2. Cut script "ipg" (see below). +3. Edit script to set preferred device and destination IP address. +4. Run in shell: ". ipg" +5. After this two commands are defined: + A. "pg" to start generator and to get results. + B. "pgset" to change generator parameters. F.e. + pgset "multiskb 1" use multiple SKBs for packet generation + pgset "multiskb 0" use single SKB for all transmits + pgset "pkt_size 9014" sets packet size to 9014 + pgset "frags 5" packet will consist of 5 fragments + pgset "count 200000" sets number of packets to send + pgset "ipg 5000" sets artificial gap inserted between packets + to 5000 nanoseconds + pgset "dst 10.0.0.1" sets IP destination address + (BEWARE! This generator is very aggressive!) + pgset "dstmac 00:00:00:00:00:00" sets MAC destination address + pgset stop aborts injection + + Also, ^C aborts generator. + +---- cut here + +#! /bin/sh + +modprobe pktgen.o + +function pgset() { + local result + + echo $1 > /proc/net/pg + + result=`cat /proc/net/pg | fgrep "Result: OK:"` + if [ "$result" = "" ]; then + cat /proc/net/pg | fgrep Result: + fi +} + +function pg() { + echo inject > /proc/net/pg + cat /proc/net/pg +} + +pgset "odev eth0" +pgset "dst 0.0.0.0" + +---- cut here diff -urN linux-2.4.18/Documentation/networking/ppp_generic.txt linux-2.4.19-pre5/Documentation/networking/ppp_generic.txt --- linux-2.4.18/Documentation/networking/ppp_generic.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/ppp_generic.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,432 @@ + PPP Generic Driver and Channel Interface + ---------------------------------------- + + Paul Mackerras + paulus@samba.org + 7 Feb 2002 + +The generic PPP driver in linux-2.4 provides an implementation of the +functionality which is of use in any PPP implementation, including: + +* the network interface unit (ppp0 etc.) +* the interface to the networking code +* PPP multilink: splitting datagrams between multiple links, and + ordering and combining received fragments +* the interface to pppd, via a /dev/ppp character device +* packet compression and decompression +* TCP/IP header compression and decompression +* detecting network traffic for demand dialling and for idle timeouts +* simple packet filtering + +For sending and receiving PPP frames, the generic PPP driver calls on +the services of PPP `channels'. A PPP channel encapsulates a +mechanism for transporting PPP frames from one machine to another. A +PPP channel implementation can be arbitrarily complex internally but +has a very simple interface with the generic PPP code: it merely has +to be able to send PPP frames, receive PPP frames, and optionally +handle ioctl requests. Currently there are PPP channel +implementations for asynchronous serial ports, synchronous serial +ports, and for PPP over ethernet. + +This architecture makes it possible to implement PPP multilink in a +natural and straightforward way, by allowing more than one channel to +be linked to each ppp network interface unit. The generic layer is +responsible for splitting datagrams on transmit and recombining them +on receive. + + +PPP channel API +--------------- + +See include/linux/ppp_channel.h for the declaration of the types and +functions used to communicate between the generic PPP layer and PPP +channels. + +Each channel has to provide two functions to the generic PPP layer, +via the ppp_channel.ops pointer: + +* start_xmit() is called by the generic layer when it has a frame to + send. The channel has the option of rejecting the frame for + flow-control reasons. In this case, start_xmit() should return 0 + and the channel should call the ppp_output_wakeup() function at a + later time when it can accept frames again, and the generic layer + will then attempt to retransmit the rejected frame(s). If the frame + is accepted, the start_xmit() function should return 1. + +* ioctl() provides an interface which can be used by a user-space + program to control aspects of the channel's behaviour. This + procedure will be called when a user-space program does an ioctl + system call on an instance of /dev/ppp which is bound to the + channel. (Usually it would only be pppd which would do this.) + +The generic PPP layer provides seven functions to channels: + +* ppp_register_channel() is called when a channel has been created, to + notify the PPP generic layer of its presence. For example, setting + a serial port to the PPPDISC line discipline causes the ppp_async + channel code to call this function. + +* ppp_unregister_channel() is called when a channel is to be + destroyed. For example, the ppp_async channel code calls this when + a hangup is detected on the serial port. + +* ppp_output_wakeup() is called by a channel when it has previously + rejected a call to its start_xmit function, and can now accept more + packets. + +* ppp_input() is called by a channel when it has received a complete + PPP frame. + +* ppp_input_error() is called by a channel when it has detected that a + frame has been lost or dropped (for example, because of a FCS (frame + check sequence) error). + +* ppp_channel_index() returns the channel index assigned by the PPP + generic layer to this channel. The channel should provide some way + (e.g. an ioctl) to transmit this back to user-space, as user-space + will need it to attach an instance of /dev/ppp to this channel. + +* ppp_unit_number() returns the unit number of the ppp network + interface to which this channel is connected, or -1 if the channel + is not connected. + +Connecting a channel to the ppp generic layer is initiated from the +channel code, rather than from the generic layer. The channel is +expected to have some way for a user-level process to control it +independently of the ppp generic layer. For example, with the +ppp_async channel, this is provided by the file descriptor to the +serial port. + +Generally a user-level process will initialize the underlying +communications medium and prepare it to do PPP. For example, with an +async tty, this can involve setting the tty speed and modes, issuing +modem commands, and then going through some sort of dialog with the +remote system to invoke PPP service there. We refer to this process +as `discovery'. Then the user-level process tells the medium to +become a PPP channel and register itself with the generic PPP layer. +The channel then has to report the channel number assigned to it back +to the user-level process. From that point, the PPP negotiation code +in the PPP daemon (pppd) can take over and perform the PPP +negotiation, accessing the channel through the /dev/ppp interface. + +At the interface to the PPP generic layer, PPP frames are stored in +skbuff structures and start with the two-byte PPP protocol number. +The frame does *not* include the 0xff `address' byte or the 0x03 +`control' byte that are optionally used in async PPP. Nor is there +any escaping of control characters, nor are there any FCS or framing +characters included. That is all the responsibility of the channel +code, if it is needed for the particular medium. That is, the skbuffs +presented to the start_xmit() function contain only the 2-byte +protocol number and the data, and the skbuffs presented to ppp_input() +must be in the same format. + +The channel must provide an instance of a ppp_channel struct to +represent the channel. The channel is free to use the `private' field +however it wishes. The channel should initialize the `mtu' and +`hdrlen' fields before calling ppp_register_channel() and not change +them until after ppp_unregister_channel() returns. The `mtu' field +represents the maximum size of the data part of the PPP frames, that +is, it does not include the 2-byte protocol number. + +If the channel needs some headroom in the skbuffs presented to it for +transmission (i.e., some space free in the skbuff data area before the +start of the PPP frame), it should set the `hdrlen' field of the +ppp_channel struct to the amount of headroom required. The generic +PPP layer will attempt to provide that much headroom but the channel +should still check if there is sufficient headroom and copy the skbuff +if there isn't. + +On the input side, channels should ideally provide at least 2 bytes of +headroom in the skbuffs presented to ppp_input(). The generic PPP +code does not require this but will be more efficient if this is done. + + +Buffering and flow control +-------------------------- + +The generic PPP layer has been designed to minimize the amount of data +that it buffers in the transmit direction. It maintains a queue of +transmit packets for the PPP unit (network interface device) plus a +queue of transmit packets for each attached channel. Normally the +transmit queue for the unit will contain at most one packet; the +exceptions are when pppd sends packets by writing to /dev/ppp, and +when the core networking code calls the generic layer's start_xmit() +function with the queue stopped, i.e. when the generic layer has +called netif_stop_queue(), which only happens on a transmit timeout. +The start_xmit function always accepts and queues the packet which it +is asked to transmit. + +Transmit packets are dequeued from the PPP unit transmit queue and +then subjected to TCP/IP header compression and packet compression +(Deflate or BSD-Compress compression), as appropriate. After this +point the packets can no longer be reordered, as the decompression +algorithms rely on receiving compressed packets in the same order that +they were generated. + +If multilink is not in use, this packet is then passed to the attached +channel's start_xmit() function. If the channel refuses to take +the packet, the generic layer saves it for later transmission. The +generic layer will call the channel's start_xmit() function again +when the channel calls ppp_output_wakeup() or when the core +networking code calls the generic layer's start_xmit() function +again. The generic layer contains no timeout and retransmission +logic; it relies on the core networking code for that. + +If multilink is in use, the generic layer divides the packet into one +or more fragments and puts a multilink header on each fragment. It +decides how many fragments to use based on the length of the packet +and the number of channels which are potentially able to accept a +fragment at the moment. A channel is potentially able to accept a +fragment if it doesn't have any fragments currently queued up for it +to transmit. The channel may still refuse a fragment; in this case +the fragment is queued up for the channel to transmit later. This +scheme has the effect that more fragments are given to higher- +bandwidth channels. It also means that under light load, the generic +layer will tend to fragment large packets across all the channels, +thus reducing latency, while under heavy load, packets will tend to be +transmitted as single fragments, thus reducing the overhead of +fragmentation. + + +SMP safety +---------- + +The PPP generic layer has been designed to be SMP-safe. Locks are +used around accesses to the internal data structures where necessary +to ensure their integrity. As part of this, the generic layer +requires that the channels adhere to certain requirements and in turn +provides certain guarantees to the channels. Essentially the channels +are required to provide the appropriate locking on the ppp_channel +structures that form the basis of the communication between the +channel and the generic layer. This is because the channel provides +the storage for the ppp_channel structure, and so the channel is +required to provide the guarantee that this storage exists and is +valid at the appropriate times. + +The generic layer requires these guarantees from the channel: + +* The ppp_channel object must exist from the time that + ppp_register_channel() is called until after the call to + ppp_unregister_channel() returns. + +* No thread may be in a call to any of ppp_input(), ppp_input_error(), + ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a + channel at the time that ppp_unregister_channel() is called for that + channel. + +* ppp_register_channel() and ppp_unregister_channel() must be called + from process context, not interrupt or softirq/BH context. + +* The remaining generic layer functions may be called at softirq/BH + level but must not be called from a hardware interrupt handler. + +* The generic layer may call the channel start_xmit() function at + softirq/BH level but will not call it at interrupt level. Thus the + start_xmit() function may not block. + +* The generic layer will only call the channel ioctl() function in + process context. + +The generic layer provides these guarantees to the channels: + +* The generic layer will not call the start_xmit() function for a + channel while any thread is already executing in that function for + that channel. + +* The generic layer will not call the ioctl() function for a channel + while any thread is already executing in that function for that + channel. + +* By the time a call to ppp_unregister_channel() returns, no thread + will be executing in a call from the generic layer to that channel's + start_xmit() or ioctl() function, and the generic layer will not + call either of those functions subsequently. + + +Interface to pppd +----------------- + +The PPP generic layer exports a character device interface called +/dev/ppp. This is used by pppd to control PPP interface units and +channels. Although there is only one /dev/ppp, each open instance of +/dev/ppp acts independently and can be attached either to a PPP unit +or a PPP channel. This is achieved using the file->private_data field +to point to a separate object for each open instance of /dev/ppp. In +this way an effect similar to Solaris' clone open is obtained, +allowing us to control an arbitrary number of PPP interfaces and +channels without having to fill up /dev with hundreds of device names. + +When /dev/ppp is opened, a new instance is created which is initially +unattached. Using an ioctl call, it can then be attached to an +existing unit, attached to a newly-created unit, or attached to an +existing channel. An instance attached to a unit can be used to send +and receive PPP control frames, using the read() and write() system +calls, along with poll() if necessary. Similarly, an instance +attached to a channel can be used to send and receive PPP frames on +that channel. + +In multilink terms, the unit represents the bundle, while the channels +represent the individual physical links. Thus, a PPP frame sent by a +write to the unit (i.e., to an instance of /dev/ppp attached to the +unit) will be subject to bundle-level compression and to fragmentation +across the individual links (if multilink is in use). In contrast, a +PPP frame sent by a write to the channel will be sent as-is on that +channel, without any multilink header. + +A channel is not initially attached to any unit. In this state it can +be used for PPP negotiation but not for the transfer of data packets. +It can then be connected to a PPP unit with an ioctl call, which +makes it available to send and receive data packets for that unit. + +The ioctl calls which are available on an instance of /dev/ppp depend +on whether it is unattached, attached to a PPP interface, or attached +to a PPP channel. The ioctl calls which are available on an +unattached instance are: + +* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp + instance the "owner" of the interface. The argument should point to + an int which is the desired unit number if >= 0, or -1 to assign the + lowest unused unit number. Being the owner of the interface means + that the interface will be shut down if this instance of /dev/ppp is + closed. + +* PPPIOCATTACH attaches this instance to an existing PPP interface. + The argument should point to an int containing the unit number. + This does not make this instance the owner of the PPP interface. + +* PPPIOCATTCHAN attaches this instance to an existing PPP channel. + The argument should point to an int containing the channel number. + +The ioctl calls available on an instance of /dev/ppp attached to a +channel are: + +* PPPIOCDETACH detaches the instance from the channel. This ioctl is + deprecated since the same effect can be achieved by closing the + instance. In order to prevent possible races this ioctl will fail + with an EINVAL error if more than one file descriptor refers to this + instance (i.e. as a result of dup(), dup2() or fork()). + +* PPPIOCCONNECT connects this channel to a PPP interface. The + argument should point to an int containing the interface unit + number. It will return an EINVAL error if the channel is already + connected to an interface, or ENXIO if the requested interface does + not exist. + +* PPPIOCDISCONN disconnects this channel from the PPP interface that + it is connected to. It will return an EINVAL error if the channel + is not connected to an interface. + +* All other ioctl commands are passed to the channel ioctl() function. + +The ioctl calls that are available on an instance that is attached to +an interface unit are: + +* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface. + The argument should point to an int containing the new MRU value. + +* PPPIOCSFLAGS sets flags which control the operation of the + interface. The argument should be a pointer to an int containing + the new flags value. The bits in the flags value that can be set + are: + SC_COMP_TCP enable transmit TCP header compression + SC_NO_TCP_CCID disable connection-id compression for + TCP header compression + SC_REJ_COMP_TCP disable receive TCP header decompression + SC_CCP_OPEN Compression Control Protocol (CCP) is + open, so inspect CCP packets + SC_CCP_UP CCP is up, may (de)compress packets + SC_LOOP_TRAFFIC send IP traffic to pppd + SC_MULTILINK enable PPP multilink fragmentation on + transmitted packets + SC_MP_SHORTSEQ expect short multilink sequence + numbers on received multilink fragments + SC_MP_XSHORTSEQ transmit short multilink sequence nos. + + The values of these flags are defined in . Note + that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and + SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option + is not selected. + +* PPPIOCGFLAGS returns the value of the status/control flags for the + interface unit. The argument should point to an int where the ioctl + will store the flags value. As well as the values listed above for + PPPIOCSFLAGS, the following bits may be set in the returned value: + SC_COMP_RUN CCP compressor is running + SC_DECOMP_RUN CCP decompressor is running + SC_DC_ERROR CCP decompressor detected non-fatal error + SC_DC_FERROR CCP decompressor detected fatal error + +* PPPIOCSCOMPRESS sets the parameters for packet compression or + decompression. The argument should point to a ppp_option_data + structure (defined in ), which contains a + pointer/length pair which should describe a block of memory + containing a CCP option specifying a compression method and its + parameters. The ppp_option_data struct also contains a `transmit' + field. If this is 0, the ioctl will affect the receive path, + otherwise the transmit path. + +* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit + number of this interface unit. + +* PPPIOCSDEBUG sets the debug flags for the interface to the value in + the int pointed to by the argument. Only the least significant bit + is used; if this is 1 the generic layer will print some debug + messages during its operation. This is only intended for debugging + the generic PPP layer code; it is generally not helpful for working + out why a PPP connection is failing. + +* PPPIOCGDEBUG returns the debug flags for the interface in the int + pointed to by the argument. + +* PPPIOCGIDLE returns the time, in seconds, since the last data + packets were sent and received. The argument should point to a + ppp_idle structure (defined in ). If the + CONFIG_PPP_FILTER option is enabled, the set of packets which reset + the transmit and receive idle timers is restricted to those which + pass the `active' packet filter. + +* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the + number of connection slots) for the TCP header compressor and + decompressor. The lower 16 bits of the int pointed to by the + argument specify the maximum connection-ID for the compressor. If + the upper 16 bits of that int are non-zero, they specify the maximum + connection-ID for the decompressor, otherwise the decompressor's + maximum connection-ID is set to 15. + +* PPPIOCSNPMODE sets the network-protocol mode for a given network + protocol. The argument should point to an npioctl struct (defined + in ). The `protocol' field gives the PPP protocol + number for the protocol to be affected, and the `mode' field + specifies what to do with packets for that protocol: + + NPMODE_PASS normal operation, transmit and receive packets + NPMODE_DROP silently drop packets for this protocol + NPMODE_ERROR drop packets and return an error on transmit + NPMODE_QUEUE queue up packets for transmit, drop received + packets + + At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as + NPMODE_DROP. + +* PPPIOCGNPMODE returns the network-protocol mode for a given + protocol. The argument should point to an npioctl struct with the + `protocol' field set to the PPP protocol number for the protocol of + interest. On return the `mode' field will be set to the network- + protocol mode for that protocol. + +* PPPIOCSPASS and PPPIOCSACTIVE set the `pass' and `active' packet + filters. These ioctls are only available if the CONFIG_PPP_FILTER + option is selected. The argument should point to a sock_fprog + structure (defined in ) containing the compiled BPF + instructions for the filter. Packets are dropped if they fail the + `pass' filter; otherwise, if they fail the `active' filter they are + passed but they do not reset the transmit or receive idle timer. + +* PPPIOCSMRRU enables or disables multilink processing for received + packets and sets the multilink MRRU (maximum reconstructed receive + unit). The argument should point to an int containing the new MRRU + value. If the MRRU value is 0, processing of received multilink + fragments is disabled. This ioctl is only available if the + CONFIG_PPP_MULTILINK option is selected. + +Last modified: 7-feb-2002 diff -urN linux-2.4.18/Documentation/networking/slicecom.hun linux-2.4.19-pre5/Documentation/networking/slicecom.hun --- linux-2.4.18/Documentation/networking/slicecom.hun Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/slicecom.hun Sat Mar 30 22:55:33 2002 @@ -0,0 +1,371 @@ + +SliceCOM adapter felhasznaloi dokumentacioja - 0.51 verziohoz + +Bartók István +Utolso modositas: Wed Aug 29 17:26:58 CEST 2001 + +----------------------------------------------------------------- + +Hasznalata: + +Forditas: + +Code maturity level options + [*] Prompt for development and/or incomplete code/drivers + +Network device support + Wan interfaces + MultiGate (COMX) synchronous + Support for MUNICH based boards: SliceCOM, PCICOM (NEW) + Support for HDLC and syncPPP... + + +A modulok betoltese: + +modprobe comx + +modprobe comx-proto-ppp # a Cisco-HDLC es a SyncPPP protokollt is + # ez a modul adja + +modprobe comx-hw-munich # a modul betoltodeskor azonnal jelent a + # syslogba a detektalt kartyakrol + + +Konfiguralas: + +# Ezen az interfeszen Cisco-HDLC vonali protokoll fog futni +# Az interfeszhez rendelt idoszeletek: 1,2 (128 kbit/sec-es vonal) +# (a G.703 keretben az elso adatot vivo idoszelet az 1-es) +# +mkdir /proc/comx/comx0.1/ +echo slicecom >/proc/comx/comx0.1/boardtype +echo hdlc >/proc/comx/comx0.1/protocol +echo 1 2 >/proc/comx/comx0.1/timeslots + + +# Ezen az interfeszen SyncPPP vonali protokoll fog futni +# Az interfeszhez rendelt idoszelet: 3 (64 kbit/sec-es vonal) +# +mkdir /proc/comx/comx0.2/ +echo slicecom >/proc/comx/comx0.2/boardtype +echo ppp >/proc/comx/comx0.2/protocol +echo 3 >/proc/comx/comx0.2/timeslots + +... + +ifconfig comx0.1 up +ifconfig comx0.2 up + +----------------------------------------------------------------- + +A COMX driverek default 20 csomagnyi transmit queue-t rendelnek a halozati +interfeszekhez. WAN halozatokban ennel hosszabbat is szokas hasznalni +(20 es 100 kozott), hogy a vonal kihasznaltsaga nagy terheles eseten jobb +legyen (bar ezzel megno a varhato kesleltetes a csomagok sorban allasa miatt): + +# ifconfig comx0 txqueuelen 50 + +Ezt a beallitasi lehetoseget csak az ujabb disztribuciok ifconfig parancsa +tamogatja (amik mar a 2.2 kernelekhez keszultek, mint a RedHat 6.1 vagy a +Debian 2.2). + +A 2.1-es Debian disztribuciohoz a http://www.debian.org/~rcw/2.2/netbase/ +cimrol toltheto le ujabb netbase csomag, ami mar ilyet tamogato ifconfig +parancsot tartalmaz. Bovebben a 2.2 kernel hasznalatarol Debian 2.1 alatt: +http://www.debian.org/releases/stable/running-kernel-2.2 + +----------------------------------------------------------------- + +A kartya LED-jeinek jelentese: + +piros - eg, ha Remote Alarm-ot kuld a tuloldal +zold - eg, ha a vett jelben megtalalja a keretszinkront + +Reszletesebben: + +piros: zold: jelentes: + +- - nincs keretszinkron (nincs jel, vagy rossz a jel) +- eg "minden rendben" +eg eg a vetel OK, de a tuloldal Remote Alarm-ot kuld +eg - ez nincs ertelmezve, egyelore funkcio nelkul + +----------------------------------------------------------------- + +Reszletesebb leiras a hardver beallitasi lehetosegeirol: + +Az altalanos,- es a protokoll-retegek beallitasi lehetosegeirol a 'comx.txt' +fajlban leirtak SliceCOM kartyanal is ervenyesek, itt csak a hardver-specifikus +beallitasi lehetosegek vannak osszefoglalva: + +Konfiguralasi interfesz a /proc/comx/ alatt: + +Minden timeslot-csoportnak kulon comx* interfeszt kell letrehozni mkdir-rel: +comx0, comx1, .. stb. Itt beallithato, hogy az adott interfesz hanyadik kartya +melyik timeslotja(i)bol alljon ossze. A Cisco-fele serial3:1 elnevezesek +(serial3:1 = a 3. kartyaban az 1-es idoszelet-csoport) Linuxon aliasing-ot +jelentenenek, ezert mi nem tudunk ilyen elnevezest hasznalni. + +Tobb kartya eseten a comx0.1, comx0.2, ... vagy slice0.1, slice0.2 nevek +hasznalhatoak. + +Tobb SliceCOM kartya is lehet egy gepben, de sajat interrupt kell mindegyiknek, +nem tud meg megosztott interruptot kezelni. + +Az egesz kartyat erinto beallitasok: + +Az ioport es irq beallitas nincs: amit a PCI BIOS kioszt a rendszernek, +azt hasznalja a driver. + + +comx0/boardnum - hanyadik SliceCOM kartya a gepben (a 'termeszetes' PCI + sorrendben ertve: ahogyan a /proc/pci-ban vagy az 'lspci' + kimeneteben megjelenik, altalaban az alaplapi PCI meghajto + aramkorokhoz kozelebb eso kartyak a kisebb sorszamuak) + + Default: 0 (0-tol kezdodik a szamolas) + + +Bar a kovetkezoket csak egy-egy interfeszen allitjuk at, megis az egesz kartya +mukodeset egyszerre allitjak. A megkotes hogy csak UP-ban levo interfeszen +hasznalhatoak, azert van, mert kulonben nem vart eredmenyekre vezetne egy ilyen +paranccsorozat: + + echo 0 >boardnum + echo internal >clock_source + echo 1 >boardnum + +- Ez a 0-s board clock_source-at allitana at. + +Ezek a beallitasok megmaradnak az osszes interfesz torlesekor, de torlodnek +a driver modul ki/betoltesekor. + + +comx0/clock_source - A Tx orajelforrasa, a Cisco-val hasonlatosra keszult. + Hasznalata: + + papaya:# echo line >/proc/comx/comx0/clock_source + papaya:# echo internal >/proc/comx/comx0/clock_source + + line - A Tx orajelet a vett adatfolyambol dekodolja, igyekszik + igazodni hozza. Ha nem lat orajelet az inputon, akkor + atall a sajat orajelgeneratorara. + internal - A Tx orajelet a sajat orajelgeneratora szolgaltatja. + + Default: line + + Normal osszeallitas eseten a tavkozlesi szolgaltato eszkoze + (pl. HDSL modem) adja az orajelet, ezert ez a default. + + +comx0/framing - A CRC4 ki/be kapcsolasa + + A CRC4: 16 PCM keretet (A PCM keret az, amibe a 32 darab 64 + kilobites csatorna van bemultiplexalva. Nem osszetevesztendo a HDLC + kerettel.) 2x8 -as csoportokra osztanak, es azokhoz 4-4 bites CRC-t + szamolnak. Elsosorban a vonal minosegenek a monitorozasara szolgal. + + papaya:~# echo crc4 >/proc/comx/comx0/framing + papaya:~# echo no-crc4 >/proc/comx/comx0/framing + + Default a 'crc4', a MATAV vonalak altalaban igy futnak. De ha nem + egyforma is a beallitas a vonal ket vegen, attol a forgalom altalaban + at tud menni. + + +comx0/linecode - A vonali kodolas beallitasa + + papaya:~# echo hdb3 >/proc/comx/comx0/linecode + papaya:~# echo ami >/proc/comx/comx0/linecode + + Default a 'hdb3', a MATAV vonalak igy futnak. + + (az AMI kodolas igen ritka E1-es vonalaknal). Ha ez a beallitas nem + egyezik a vonal ket vegen, akkor elofordulhat hogy a keretszinkron + osszejon, de CRC4-hibak es a vonalakon atvitt adatokban is hibak + keletkeznek (amit a HDLC/SyncPPP szinten CRC-hibaval jelez) + + +comx0/reg - a kartya aramkoreinek, a MUNICH (reg) es a FALC (lbireg) +comx0/lbireg regisztereinek kozvetlen elerese. Hasznalata: + + echo >reg 0x04 0x0 - a 4-es regiszterbe 0-t ir + echo >reg 0x104 - printk()-val kiirja a 4-es regiszter + tartalmat a syslogba. + + WARNING: ezek csak a fejleszteshez keszultek, sok galibat + lehet veluk okozni! + + +comx0/loopback - A kartya G.703 jelenek a visszahurkolasara is van lehetoseg: + + papaya:# echo none >/proc/comx/comx0/loopback + papaya:# echo local >/proc/comx/comx0/loopback + papaya:# echo remote >/proc/comx/comx0/loopback + + none - nincs visszahurkolas, normal mukodes + local - a kartya a sajat maga altal adott jelet kapja vissza + remote - a kartya a kivulrol vett jelet adja kifele + + Default: none + +----------------------------------------------------------------- + +Az interfeszhez (Cisco terminologiaban 'channel-group') kapcsolodo beallitasok: + +comx0/timeslots - mely timeslotok (idoszeletek) tartoznak az adott interfeszhez. + + papaya:~# cat /proc/comx/comx0/timeslots + 1 3 4 5 6 + papaya:~# + + Egy timeslot megkeresese (hanyas interfeszbe tartozik nalunk): + + papaya:~# grep ' 4' /proc/comx/comx*/timeslots + /proc/comx/comx0/timeslots:1 3 4 5 6 + papaya:~# + + Beallitasa: + papaya:~# echo '1 5 2 6 7 8' >/proc/comx/comx0/timeslots + + A timeslotok sorrendje nem szamit, '1 3 2' ugyanaz mint az '1 2 3'. + + Beallitashoz az adott interfesznek DOWN-ban kell lennie + (ifconfig comx0 down), de ugyanannak a kartyanak a tobbi interfesze + uzemelhet kozben. + + Beallitaskor leellenorzi, hogy az uj timeslotok nem utkoznek-e egy + masik interfesz timeslotjaival. Ha utkoznek, akkor nem allitja at. + + Mindig 10-es szamrendszerben tortenik a timeslotok ertelmezese, nehogy + a 08, 09 alaku felirast rosszul ertelmezze. + +----------------------------------------------------------------- + +Az interfeszek es a kartya allapotanak lekerdezese: + +- A ' '-szel kezdodo sorok az eredeti kimenetet, a //-rel kezdodo sorok a +magyarazatot jelzik. + + papaya:~$ cat /proc/comx/comx1/status + Interface administrative status is UP, modem status is UP, protocol is UP + Modem status changes: 0, Transmitter status is IDLE, tbusy: 0 + Interface load (input): 978376 / 947808 / 951024 bits/s (5s/5m/15m) + (output): 978376 / 947848 / 951024 bits/s (5s/5m/15m) + Debug flags: none + RX errors: len: 22, overrun: 1, crc: 0, aborts: 0 + buffer overrun: 0, pbuffer overrun: 0 + TX errors: underrun: 0 + Line keepalive (value: 10) status UP [0] + +// Itt kezdodik a hardver-specifikus resz: + Controller status: + No alarms + +// Alarm: hibajelzes: +// +// No alarms - minden rendben +// +// LOS - Loss Of Signal - nem erzekel jelet a bemeneten. +// AIS - Alarm Indication Signal - csak egymas utani 1-esek jonnek +// a bemeneten, a tuloldal igy is jelezheti hogy meghibasodott vagy +// nincs inicializalva. +// AUXP - Auxiliary Pattern Indication - 01010101.. sorozat jon a bemeneten. +// LFA - Loss of Frame Alignment - nincs keretszinkron +// RRA - Receive Remote Alarm - a tuloldal el, de hibat jelez. +// LMFA - Loss of CRC4 Multiframe Alignment - nincs CRC4-multikeret-szinkron +// NMF - No Multiframe alignment Found after 400 msec - ilyen alarm a no-crc4 +// es crc4 keretezesek eseten nincs, lasd lentebb +// +// Egyeb lehetseges hibajelzesek: +// +// Transmit Line Short - a kartya ugy erzi hogy az adasi kimenete rovidre +// van zarva, ezert kikapcsolta az adast. (nem feltetlenul veszi eszre +// a kulso rovidzarat) + +// A veteli oldal csomagjainak lancolt listai, debug celokra: + + Rx ring: + rafutott: 0 + lastcheck: 50845731, jiffies: 51314281 + base: 017b1858 + rx_desc_ptr: 0 + rx_desc_ptr: 017b1858 + hw_curr_ptr: 017b1858 + 06040000 017b1868 017b1898 c016ff00 + 06040000 017b1878 017b1e9c c016ff00 + 46040000 017b1888 017b24a0 c016ff00 + 06040000 017b1858 017b2aa4 c016ff00 + +// A kartyat hasznalo tobbi interfesz: a 0-s channel-group a comx1 interfesz, +// es az 1,2,...,16 timeslotok tartoznak hozza: + + Interfaces using this board: (channel-group, interface, timeslots) + 0 comx1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 1 comx2: 17 + 2 comx3: 18 + 3 comx4: 19 + 4 comx5: 20 + 5 comx6: 21 + 6 comx7: 22 + 7 comx8: 23 + 8 comx9: 24 + 9 comx10: 25 + 10 comx11: 26 + 11 comx12: 27 + 12 comx13: 28 + 13 comx14: 29 + 14 comx15: 30 + 15 comx16: 31 + +// Hany esemenyt kezelt le a driver egy-egy hardver-interrupt kiszolgalasanal: + + Interrupt work histogram: + hist[ 0]: 0 hist[ 1]: 2 hist[ 2]: 18574 hist[ 3]: 79 + hist[ 4]: 14 hist[ 5]: 1 hist[ 6]: 0 hist[ 7]: 1 + hist[ 8]: 0 hist[ 9]: 7 + +// Hany kikuldendo csomag volt mar a Tx-ringben amikor ujabb lett irva bele: + + Tx ring histogram: + hist[ 0]: 2329 hist[ 1]: 0 hist[ 2]: 0 hist[ 3]: 0 + +// Az E1-interfesz hiba-szamlaloi, az rfc2495-nek megfeleloen: +// (kb. a Cisco routerek "show controllers e1" formatumaban: http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/rbook/rinterfc.htm#xtocid25669126) + +Data in current interval (91 seconds elapsed): + 9516 Line Code Violations, 65 Path Code Violations, 2 E-Bit Errors + 0 Slip Secs, 2 Fr Loss Secs, 2 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 11 Unavail Secs +Data in Interval 1 (15 minutes): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs +Data in last 4 intervals (1 hour): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs +Data in last 96 intervals (24 hours): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs + +----------------------------------------------------------------- + +Nehany kulonlegesebb beallitasi lehetoseg (idovel beepulhetnek majd a driverbe): +Ezekkel sok galibat lehet okozni, nagyon ovatosan kell oket hasznalni! + + modified CRC-4, for improved interworking of CRC-4 and non-CRC-4 + devices: (lasd page 107 es g706 Annex B) + lbireg[ 0x1b ] |= 0x08 + lbireg[ 0x1c ] |= 0xc0 + - ilyenkor ertelmezett az NMF - 'No Multiframe alignment Found after + 400 msec' alarm. + + FALC - a vonali meghajto IC + local loop - a sajat adasomat halljam vissza + remote loop - a kivulrol jovo adast adom vissza + + Egy hibakeresesre hasznalhato dolog: + - 1-es timeslot local loop a FALC-ban: echo >lbireg 0x1d 0x21 + - local loop kikapcsolasa: echo >lbireg 0x1d 0x00 diff -urN linux-2.4.18/Documentation/networking/slicecom.txt linux-2.4.19-pre5/Documentation/networking/slicecom.txt --- linux-2.4.18/Documentation/networking/slicecom.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/networking/slicecom.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,369 @@ + +SliceCOM adapter user's documentation - for the 0.51 driver version + +Written by Bartók István + +English translation: Lakatos György +Mon Dec 11 15:28:42 CET 2000 + +Last modified: Wed Aug 29 17:25:37 CEST 2001 + +----------------------------------------------------------------- + +Usage: + +Compiling the kernel: + +Code maturity level options + [*] Prompt for development and/or incomplete code/drivers + +Network device support + Wan interfaces + MultiGate (COMX) synchronous + Support for MUNICH based boards: SliceCOM, PCICOM (NEW) + Support for HDLC and syncPPP... + + +Loading the modules: + +modprobe comx + +modprobe comx-proto-ppp # module for Cisco-HDLC and SyncPPP protocols + +modprobe comx-hw-munich # the module logs information by the kernel + # about the detected boards + + +Configuring the board: + +# This interface will use the Cisco-HDLC line protocol, +# the timeslices assigned are 1,2 (128 KiBit line speed) +# (the first data timeslice in the G.703 frame is no. 1) +# +mkdir /proc/comx/comx0.1/ +echo slicecom >/proc/comx/comx0.1/boardtype +echo hdlc >/proc/comx/comx0.1/protocol +echo 1 2 >/proc/comx/comx0.1/timeslots + + +# This interface uses SyncPPP line protocol, the assigned +# is no. 3 (64 KiBit line speed) +# +mkdir /proc/comx/comx0.2/ +echo slicecom >/proc/comx/comx0.2/boardtype +echo ppp >/proc/comx/comx0.2/protocol +echo 3 >/proc/comx/comx0.2/timeslots + +... + +ifconfig comx0.1 up +ifconfig comx0.2 up + +----------------------------------------------------------------- + +The COMX interfaces use a 10 packet transmit queue by default, however WAN +networks sometimes use bigger values (20 to 100), to utilize the line better +by large traffic (though the line delay increases because of more packets +join the queue). + +# ifconfig comx0 txqueuelen 50 + +This option is only supported by the ifconfig command of the later +distributions, which came with 2.2 kernels, such as RedHat 6.1 or Debian 2.2. + +You can download a newer netbase packet from +http://www.debian.org/~rcw/2.2/netbase/ for Debian 2.1, which has a new +ifconfig. You can get further information about using 2.2 kernel with +Debian 2.1 from http://www.debian.org/releases/stable/running-kernel-2.2 + +----------------------------------------------------------------- + +The SliceCom LEDs: + +red - on, if the interface is unconfigured, or it gets Remote Alarm-s +green - on, if the board finds frame-sync in the received signal + +A bit more detailed: + +red: green: meaning: + +- - no frame-sync, no signal received, or signal SNAFU. +- on "Everything is OK" +on on Recepion is ok, but the remote end sends Remote Alarm +on - The interface is unconfigured + +----------------------------------------------------------------- + +A more detailed description of the hardware setting options: + +The general and the protocol layer options described in the 'comx.txt' file +apply to the SliceCom as well, I only summarize the SliceCom hardware specific +settings below. + +The '/proc/comx' configuring interface: + +An interface directory should be created for every timeslot group with +'mkdir', e,g: 'comx0', 'comx1' etc. The timeslots can be assigned here to the +specific interface. The Cisco-like naming convention (serial3:1 - first +timeslot group of the 3rd. board) can't be used here, because these mean IP +aliasing in Linux. + +You can give any meaningful name to keep the configuration clear; +e.g: 'comx0.1', 'comx0.2', 'comx1.1', comx1.2', if you have two boards +with two interfaces each. + +Settings, which apply to the board: + +Neither 'io' nor 'irq' settings required, the driver uses the resources +given by the PCI BIOS. + +comx0/boardnum - board number of the SliceCom in the PC (using the 'natural' + PCI order) as listed in '/proc/pci' or the output of the + 'lspci' command, generally the slots nearer to the motherboard + PCI driver chips have the lower numbers. + + Default: 0 (the counting starts with 0) + +Though the options below are to be set on a single interface, they apply to the +whole board. The restriction, to use them on 'UP' interfaces, is because the +command sequence below could lead to unpredicable results. + + # echo 0 >boardnum + # echo internal >clock_source + # echo 1 >boardnum + +The sequence would set the clock source of board 0. + +These settings will persist after all the interfaces are cleared, but are +cleared when the driver module is unloaded and loaded again. + +comx0/clock_source - source of the transmit clock + Usage: + + # echo line >/proc/comx/comx0/clock_source + # echo internal >/proc/comx/comx0/clock_source + + line - The Tx clock is being decoded if the input data stream, + if no clock seen on the input, then the board will use it's + own clock generator. + + internal - The Tx clock is supplied by the builtin clock generator. + + Default: line + + Normally, the telecommunication company's end device (the HDSL + modem) provides the Tx clock, that's why 'line' is the default. + +comx0/framing - Switching CRC4 off/on + + CRC4: 16 PCM frames (The 32 64Kibit channels are multiplexed into a + PCM frame, nothing to do with HDLC frames) are divided into 2x8 + groups, each group has a 4 bit CRC. + + # echo crc4 >/proc/comx/comx0/framing + # echo no-crc4 >/proc/comx/comx0/framing + + Default is 'crc4', the Hungarian MATAV lines behave like this. + The traffic generally passes if this setting on both ends don't match. + +comx0/linecode - Setting the line coding + + # echo hdb3 >/proc/comx/comx0/linecode + # echo ami >/proc/comx/comx0/linecode + + Default a 'hdb3', MATAV lines use this. + + (AMI coding is rarely used with E1 lines). Frame sync may occur, if + this setting doesn't match the other end's, but CRC4 and data errors + will come, which will result in CRC errors on HDLC/SyncPPP level. + +comx0/reg - direct access to the board's MUNICH (reg) and FALC (lbireg) +comx0/lbireg circuit's registers + + # echo >reg 0x04 0x0 - write 0 to register 4 + # echo >reg 0x104 - write the contents of register 4 with + printk() to syslog + +WARNING! These are only for development purposes, messing with this will + result much trouble! + +comx0/loopback - Places a loop to the board's G.703 signals + + # echo none >/proc/comx/comx0/loopback + # echo local >/proc/comx/comx0/loopback + # echo remote >/proc/comx/comx0/loopback + + none - normal operation, no loop + local - the board receives it's own output + remote - the board sends the received data to the remote side + + Default: none + +----------------------------------------------------------------- + +Interface (channel group in Cisco terms) settings: + +comx0/timeslots - which timeslots belong to the given interface + + Setting: + + # echo '1 5 2 6 7 8' >/proc/comx/comx0/timeslots + + # cat /proc/comx/comx0/timeslots + 1 2 5 6 7 8 + # + + Finding a timeslot: + + # grep ' 4' /proc/comx/comx*/timeslots + /proc/comx/comx0/timeslots:1 3 4 5 6 + # + + The timeslots can be in any order, '1 2 3' is the same as '1 3 2'. + + The interface has to be DOWN during the setting ('ifconfig comx0 + down'), but the other interfaces could operate normally. + + The driver checks if the assigned timeslots are vacant, if not, then + the setting won't be applied. + + The timeslot values are treated as decimal numbers, not to misunderstand + values of 08, 09 form. + +----------------------------------------------------------------- + +Checking the interface and board status: + +- Lines beginning with ' ' (space) belong to the original output, the lines +which begin with '//' are the comments. + + papaya:~$ cat /proc/comx/comx1/status + Interface administrative status is UP, modem status is UP, protocol is UP + Modem status changes: 0, Transmitter status is IDLE, tbusy: 0 + Interface load (input): 978376 / 947808 / 951024 bits/s (5s/5m/15m) + (output): 978376 / 947848 / 951024 bits/s (5s/5m/15m) + Debug flags: none + RX errors: len: 22, overrun: 1, crc: 0, aborts: 0 + buffer overrun: 0, pbuffer overrun: 0 + TX errors: underrun: 0 + Line keepalive (value: 10) status UP [0] + +// The hardware specific part starts here: + Controller status: + No alarms + +// Alarm: +// +// No alarms - Everything OK +// +// LOS - Loss Of Signal - No signal sensed on the input +// AIS - Alarm Indication Signal - The remot side sends '11111111'-s, +// it tells, that there's an error condition, or it's not +// initialised. +// AUXP - Auxiliary Pattern Indication - 01010101.. received. +// LFA - Loss of Frame Alignment - no frame sync received. +// RRA - Receive Remote Alarm - the remote end's OK, but singnals error cond. +// LMFA - Loss of CRC4 Multiframe Alignment - no CRC4 multiframe sync. +// NMF - No Multiframe alignment Found after 400 msec - no such alarm using +// no-crc4 or crc4 framing, see below. +// +// Other possible error messages: +// +// Transmit Line Short - the board felt, that it's output is short-circuited, +// so it switched the transmission off. (The board can't definitely tell, +// that it's output is short-circuited.) + +// Chained list of the received packets, for debug purposes: + + Rx ring: + rafutott: 0 + lastcheck: 50845731, jiffies: 51314281 + base: 017b1858 + rx_desc_ptr: 0 + rx_desc_ptr: 017b1858 + hw_curr_ptr: 017b1858 + 06040000 017b1868 017b1898 c016ff00 + 06040000 017b1878 017b1e9c c016ff00 + 46040000 017b1888 017b24a0 c016ff00 + 06040000 017b1858 017b2aa4 c016ff00 + +// All the interfaces using the board: comx1, using the 1,2,...16 timeslots, +// comx2, using timeslot 17, etc. + + Interfaces using this board: (channel-group, interface, timeslots) + 0 comx1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 1 comx2: 17 + 2 comx3: 18 + 3 comx4: 19 + 4 comx5: 20 + 5 comx6: 21 + 6 comx7: 22 + 7 comx8: 23 + 8 comx9: 24 + 9 comx10: 25 + 10 comx11: 26 + 11 comx12: 27 + 12 comx13: 28 + 13 comx14: 29 + 14 comx15: 30 + 15 comx16: 31 + +// The number of events handled by the driver during an interrupt cycle: + + Interrupt work histogram: + hist[ 0]: 0 hist[ 1]: 2 hist[ 2]: 18574 hist[ 3]: 79 + hist[ 4]: 14 hist[ 5]: 1 hist[ 6]: 0 hist[ 7]: 1 + hist[ 8]: 0 hist[ 9]: 7 + +// The number of packets to send in the Tx ring, when a new one arrived: + + Tx ring histogram: + hist[ 0]: 2329 hist[ 1]: 0 hist[ 2]: 0 hist[ 3]: 0 + +// The error counters of the E1 interface, according to the RFC2495, +// (similar to the Cisco "show controllers e1" command's output: +// http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/rbook/rinterfc.htm#xtocid25669126) + +Data in current interval (91 seconds elapsed): + 9516 Line Code Violations, 65 Path Code Violations, 2 E-Bit Errors + 0 Slip Secs, 2 Fr Loss Secs, 2 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 11 Unavail Secs +Data in Interval 1 (15 minutes): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs +Data in last 4 intervals (1 hour): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs +Data in last 96 intervals (24 hours): + 0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors + 0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins + 0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs + +----------------------------------------------------------------- + +Some unique options, (may get into the driver later): +Treat them very carefully, these can cause much trouble! + + modified CRC-4, for improved interworking of CRC-4 and non-CRC-4 + devices: (see page 107 and g706 Annex B) + lbireg[ 0x1b ] |= 0x08 + lbireg[ 0x1c ] |= 0xc0 + + - The NMF - 'No Multiframe alignment Found after 400 msec' alarm + comes into account. + + FALC - the line driver chip. + local loop - I hear my transmission back. + remote loop - I echo the remote transmission back. + + Something useful for finding errors: + + - local loop for timeslot 1 in the FALC chip: + + # echo >lbireg 0x1d 0x21 + + - Swithing the loop off: + + # echo >lbireg 0x1d 0x00 diff -urN linux-2.4.18/Documentation/pci.txt linux-2.4.19-pre5/Documentation/pci.txt --- linux-2.4.18/Documentation/pci.txt Sun Dec 23 16:23:35 2001 +++ linux-2.4.19-pre5/Documentation/pci.txt Sat Mar 30 22:55:33 2002 @@ -156,6 +156,11 @@ 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. + If you want to use the PCI Memory-Write-Invalidate transaction, +call pci_set_mwi(). This enables bit PCI_COMMAND bit for Mem-Wr-Inval +and also ensures that the cache line size register is set correctly. +Make sure to check the return value of pci_set_mwi(), not all architectures +may support Memory-Write-Invalidate. 4. How to access PCI config space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -202,6 +207,8 @@ pci_resource_len() Returns the byte length of a PCI region pci_set_drvdata() Set private driver data pointer for a pci_dev pci_get_drvdata() Return private driver data pointer for a pci_dev +pci_set_mwi() Enable Memory-Write-Invalidate transactions. +pci_clear_mwi() Disable Memory-Write-Invalidate transactions. 7. Miscellaneous hints diff -urN linux-2.4.18/Documentation/power/pci.txt linux-2.4.19-pre5/Documentation/power/pci.txt --- linux-2.4.18/Documentation/power/pci.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/power/pci.txt Sat Mar 30 22:55:25 2002 @@ -63,7 +63,7 @@ callbacks. This currently takes place only during APM state transitions. Upon going to sleep, the PCI subsystem walks its device tree twice. Both times, it does -a depth first walk of the device tree. The first walk saves each of the device's state +a depth first walk of the device tree. The first walk saves each of the device's state and checks for devices that will prevent the system from entering a global power state. The next walk then places the devices in a low power state. @@ -104,7 +104,7 @@ ----------------- Usage: - pci_restore_state(dev,buffer); + pci_restore_state(dev, buffer); Description: Restore previously saved config space. (First 64 bytes only); @@ -117,7 +117,7 @@ ------------------- Usage: - pci_set_power_state(dev,state); + pci_set_power_state(dev, state); Description: Transition device to low power state using PCI PM Capabilities registers. @@ -132,7 +132,7 @@ --------------- Usage: - pci_enable_wake(dev,state,enable); + pci_enable_wake(dev, state, enable); Description: Enable device to generate PME# during low power state using PCI PM @@ -155,7 +155,7 @@ struct pci_driver: int (*save_state) (struct pci_dev *dev, u32 state); - int (*suspend)(struct pci_dev *dev, u32 state); + int (*suspend) (struct pci_dev *dev, u32 state); int (*resume) (struct pci_dev *dev); int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); @@ -178,7 +178,7 @@ The driver can also interpret this function as a notification that it may be entering a sleep state in the near future. If it knows that the device cannot enter the -requested state, either because of lack of support for it, or because the devices is +requested state, either because of lack of support for it, or because the device is middle of some critical operation, then it should fail. This function should not be used to set any state in the device or the driver because diff -urN linux-2.4.18/Documentation/sound/OPL3-SA2 linux-2.4.19-pre5/Documentation/sound/OPL3-SA2 --- linux-2.4.18/Documentation/sound/OPL3-SA2 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/sound/OPL3-SA2 Sat Mar 30 22:55:25 2002 @@ -65,7 +65,7 @@ ------------ In previous kernels (2.2.x), some configuration was required to -get the driver to talk to the card. Being the new millenium and +get the driver to talk to the card. Being the new millennium and all, the 2.4.x kernels now support auto-configuration if ISA PnP support is configured in. Theoretically, the driver even supports having more than one card in this case. diff -urN linux-2.4.18/Documentation/sound/README.OSS linux-2.4.19-pre5/Documentation/sound/README.OSS --- linux-2.4.18/Documentation/sound/README.OSS Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/sound/README.OSS Sat Mar 30 22:55:25 2002 @@ -542,7 +542,7 @@ SoftOSS keeps the samples loaded on the system's RAM so much RAM is required. SoftOSS should never be used on machines with less than 16 MB - of RAM since this is potentially dangerous (you may accidently run out + of RAM since this is potentially dangerous (you may accidentally run out of memory which probably crashes the machine). SoftOSS implements the wave table API originally designed for GUS. For diff -urN linux-2.4.18/Documentation/sound/rme96xx linux-2.4.19-pre5/Documentation/sound/rme96xx --- linux-2.4.18/Documentation/sound/rme96xx Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/sound/rme96xx Sat Mar 30 22:55:37 2002 @@ -0,0 +1,767 @@ +Beta release of the rme96xx (driver for RME 96XX cards like the +"Hammerfall" and the "Hammerfall light") + +Important: The driver module has to be installed on a freshly rebooted system, +otherwise the driver might not be able to acquire its buffers. + +features: + + - OSS programming interface (i.e. runs with standard OSS soundsoftware) + - OSS/Multichannel interface (OSS multichannel is done by just aquiring + more than 2 channels). The driver does not use more than one device + ( yet .. this feature may be implemented later ) + - more than one RME card supported + +The driver uses a specific multichannel interface, which I will document +when the driver gets stable. (take a look at the defines in rme96xx.h, +which adds blocked multichannel formats i.e instead of +lrlrlrlr --> llllrrrr etc. + +Use the "rmectrl" programm to look at the status of the card .. +or use xrmectrl, a GUI interface for the ctrl program. + +What you can do with the rmectrl program is to set the stereo device for +OSS emulation (e.g. if you use SPDIF out). + +You do: + +./ctrl offset 24 24 + +which makes the stereo device use channels 25 and 26. + +Guenter Geiger + +copy the first part of the attached source code into rmectrl.c +and the second part into xrmectrl (or get the program from +http://gige.xdv.org/pages/soft/pages/rme) + +to compile: gcc -o rmectrl rmectrl.c +------------------------------ snip ------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rme96xx.h" + +/* + remctrl.c + (C) 2000 Guenter Geiger + HP20020201 - Heiko Purnhagen +*/ + +/* # define DEVICE_NAME "/dev/mixer" */ +# define DEVICE_NAME "/dev/mixer1" + + +void usage(void) +{ + fprintf(stderr,"usage: rmectrl [/dev/mixer] [command [options]]\n\n"); + fprintf(stderr,"where command is one of:\n"); + fprintf(stderr," help show this help\n"); + fprintf(stderr," status show status bits\n"); + fprintf(stderr," control show control bits\n"); + fprintf(stderr," mix show mixer/offset status\n"); + fprintf(stderr," master set sync master\n"); + fprintf(stderr," pro set spdif out pro\n"); + fprintf(stderr," emphasis set spdif out emphasis\n"); + fprintf(stderr," dolby set spdif out no audio\n"); + fprintf(stderr," optout set spdif out optical\n"); + fprintf(stderr," wordclock set sync wordclock\n"); + fprintf(stderr," spdifin set spdif in (0=optical,1=coax,2=intern)\n"); + fprintf(stderr," syncref set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n"); + fprintf(stderr," adat1cd set ADAT1 on internal CD\n"); + fprintf(stderr," offset set dev (0..3) offset (0..25)\n"); + exit(-1); +} + + +int main(int argc, char* argv[]) +{ + int cards; + int ret; + int i; + double ft; + int fd, fdwr; + int param,orig; + rme_status_t stat; + rme_ctrl_t ctrl; + char *device; + int argidx; + + if (argc < 2) + usage(); + + if (*argv[1]=='/') { + device = argv[1]; + argidx = 2; + } + else { + device = DEVICE_NAME; + argidx = 1; + } + + fprintf(stdout,"mixer device %s\n",device); + if ((fd = open(device,O_RDONLY)) < 0) { + fprintf(stdout,"opening device failed\n"); + exit(-1); + } + + if ((fdwr = open(device,O_WRONLY)) < 0) { + fprintf(stdout,"opening device failed\n"); + exit(-1); + } + + if (argc < argidx+1) + usage(); + + if (!strcmp(argv[argidx],"help")) + usage(); + if (!strcmp(argv[argidx],"-h")) + usage(); + if (!strcmp(argv[argidx],"--help")) + usage(); + + if (!strcmp(argv[argidx],"status")) { + ioctl(fd,SOUND_MIXER_PRIVATE2,&stat); + fprintf(stdout,"stat.irq %d\n",stat.irq); + fprintf(stdout,"stat.lockmask %d\n",stat.lockmask); + fprintf(stdout,"stat.sr48 %d\n",stat.sr48); + fprintf(stdout,"stat.wclock %d\n",stat.wclock); + fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint); + fprintf(stdout,"stat.syncmask %d\n",stat.syncmask); + fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed); + fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy); + fprintf(stdout,"stat.tc_out %d\n",stat.tc_out); + fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate); + fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error); + fprintf(stdout,"stat.bufid %d\n",stat.bufid); + fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid); + exit (0); + } + + if (!strcmp(argv[argidx],"control")) { + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + fprintf(stdout,"ctrl.start %d\n",ctrl.start); + fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency); + fprintf(stdout,"ctrl.master %d\n",ctrl.master); + fprintf(stdout,"ctrl.ie %d\n",ctrl.ie); + fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48); + fprintf(stdout,"ctrl.spare %d\n",ctrl.spare); + fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed); + fprintf(stdout,"ctrl.pro %d\n",ctrl.pro); + fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis); + fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby); + fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out); + fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock); + fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in); + fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref); + fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset); + fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select); + fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock); + fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write); + fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd); + exit (0); + } + + if (!strcmp(argv[argidx],"mix")) { + rme_mixer mix; + int i; + + for (i=0; i<4; i++) { + mix.devnr = i; + ioctl(fd,SOUND_MIXER_PRIVATE1,&mix); + if (mix.devnr == i) { + fprintf(stdout,"devnr %d\n",mix.devnr); + fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset); + fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset); + } + } + exit (0); + } + +/* the control flags */ + + if (argc < argidx+2) + usage(); + + if (!strcmp(argv[argidx],"master")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("master = %d\n",val); + ctrl.master = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"pro")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("pro = %d\n",val); + ctrl.pro = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"emphasis")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("emphasis = %d\n",val); + ctrl.emphasis = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"dolby")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("dolby = %d\n",val); + ctrl.dolby = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"optout")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("optout = %d\n",val); + ctrl.opt_out = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"wordclock")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("wordclock = %d\n",val); + ctrl.wordclock = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"spdifin")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("spdifin = %d\n",val); + ctrl.spdif_in = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"syncref")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("syncref = %d\n",val); + ctrl.sync_ref = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + + if (!strcmp(argv[argidx],"adat1cd")) { + int val = atoi(argv[argidx+1]); + ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl); + printf("adat1cd = %d\n",val); + ctrl.adat1_cd = val; + ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl); + exit (0); + } + +/* setting offset */ + + if (argc < argidx+4) + usage(); + + if (!strcmp(argv[argidx],"offset")) { + rme_mixer mix; + + mix.devnr = atoi(argv[argidx+1]); + + mix.i_offset = atoi(argv[argidx+2]); + mix.o_offset = atoi(argv[argidx+3]); + ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix); + fprintf(stdout,"devnr %d\n",mix.devnr); + fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset); + fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset); + exit (0); + } + + usage(); + exit (0); /* to avoid warning */ +} + + +---------------------------- -------------------------------- +#!/usr/bin/wish + +# xrmectrl +# (C) 2000 Guenter Geiger +# HP20020201 - Heiko Purnhagen + +#set defaults "-relief ridged" +set CTRLPROG "./rmectrl" +if {$argc} { + set CTRLPROG "$CTRLPROG $argv" +} +puts "CTRLPROG $CTRLPROG" + +frame .butts +button .butts.exit -text "Exit" -command "exit" -relief ridge +#button .butts.state -text "State" -command "get_all" + +pack .butts.exit -side left +pack .butts -side bottom + + +# +# STATUS +# + +frame .status + +# Sampling Rate + +frame .status.sr +label .status.sr.text -text "Sampling Rate" -justify left +radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times +radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times +radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times +radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times + +pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3 + +# Lock + +frame .status.lock +label .status.lock.text -text "Lock" -justify left +checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times +checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times +checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times + +pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3 + +# Sync + +frame .status.sync +label .status.sync.text -text "Sync" -justify left +checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times +checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times +checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times + +pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3 + +# Timecode + +frame .status.tc +label .status.tc.text -text "Timecode" -justify left +checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times +checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times +checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times + +pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3 + +# SPDIF In + +frame .status.spdif +label .status.spdif.text -text "SPDIF In" -justify left +label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times +checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times + +pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3 + +pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1 + + +# +# CONTROL +# + +proc setprof {} { + global CTRLPROG + global spprof + exec $CTRLPROG pro $spprof +} + +proc setemph {} { + global CTRLPROG + global spemph + exec $CTRLPROG emphasis $spemph +} + +proc setnoaud {} { + global CTRLPROG + global spnoaud + exec $CTRLPROG dolby $spnoaud +} + +proc setoptical {} { + global CTRLPROG + global spoptical + exec $CTRLPROG optout $spoptical +} + +proc setspdifin {} { + global CTRLPROG + global spdifin + exec $CTRLPROG spdifin [expr $spdifin - 1] +} + +proc setsyncsource {} { + global CTRLPROG + global syncsource + exec $CTRLPROG syncref [expr $syncsource -1] +} + + +proc setmaster {} { + global CTRLPROG + global master + exec $CTRLPROG master $master +} + +proc setwordclock {} { + global CTRLPROG + global wordclock + exec $CTRLPROG wordclock $wordclock +} + +proc setadat1cd {} { + global CTRLPROG + global adat1cd + exec $CTRLPROG adat1cd $adat1cd +} + + +frame .control + +# SPDIF In & SPDIF Out + + +frame .control.spdif + +frame .control.spdif.in +label .control.spdif.in.text -text "SPDIF In" -justify left +radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times +radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times +radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times + +checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times + +pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd + +label .control.spdif.space + +frame .control.spdif.out +label .control.spdif.out.text -text "SPDIF Out" -justify left +checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times +checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times +checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times +checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times + +pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom + +pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1 + +# Sync Mode & Sync Source + +frame .control.sync +frame .control.sync.mode +label .control.sync.mode.text -text "Sync Mode" -justify left +checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times +checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times + +pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc + +label .control.sync.space + +frame .control.sync.src +label .control.sync.src.text -text "Sync Source" -justify left +radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times +radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times +radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times +radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times + +pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom + +pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1 + +label .control.space -text "" -width 10 + +# Buffer Size + +frame .control.buf +label .control.buf.text -text "Buffer Size (Latency)" -justify left +radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times +radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times +radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times +radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times +radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times +radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times +radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times +radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times + +pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3 + +# Offset + +frame .control.offset + +frame .control.offset.in +label .control.offset.in.text -text "Offset In" -justify left +label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times +label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times +label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times +label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times + +pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3 + +label .control.offset.space + +frame .control.offset.out +label .control.offset.out.text -text "Offset Out" -justify left +label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times +label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times +label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times +label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times + +pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom + +pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1 + + +pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1 + + +label .statustext -text Status -justify center -relief ridge +label .controltext -text Control -justify center -relief ridge + +label .statusspace +label .controlspace + +pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1 + + +proc get_bit {output sstr} { + set idx1 [string last [concat $sstr 1] $output] + set idx1 [expr $idx1 != -1] + return $idx1 +} + +proc get_val {output sstr} { + set val [string wordend $output [string last $sstr $output]] + set val [string range $output $val [expr $val+1]] + return $val +} + +proc get_val2 {output sstr} { + set val [string wordend $output [string first $sstr $output]] + set val [string range $output $val [expr $val+2]] + return $val +} + +proc get_control {} { + global spprof + global spemph + global spnoaud + global spoptical + global spdifin + global ssrate + global master + global wordclock + global syncsource + global CTRLPROG + + set f [open "| $CTRLPROG control" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + + set spprof [ get_bit $ooo "pro"] + set spemph [ get_bit $ooo "emphasis"] + set spnoaud [ get_bit $ooo "dolby"] + set spoptical [ get_bit $ooo "opt_out"] + set spdifin [ expr [ get_val $ooo "spdif_in"] + 1] + set ssrate [ expr [ get_val $ooo "latency"] + 1] + set master [ expr [ get_val $ooo "master"]] + set wordclock [ expr [ get_val $ooo "wordclock"]] + set syncsource [ expr [ get_val $ooo "sync_ref"] + 1] +} + +proc get_status {} { + global srate + global ctrlcom + + global adatlock1 + global adatlock2 + global adatlock3 + + global adatsync1 + global adatsync2 + global adatsync3 + + global tcbusy + global tcout + global tcvalid + + global spdiferr + global crystal + global .status.spdif.text + global CTRLPROG + + + set f [open "| $CTRLPROG status" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + +# samplerate + + set idx1 [string last "sr48 1" $ooo] + set idx2 [string last "doublespeed 1" $ooo] + if {$idx1 >= 0} { + set fact1 48000 + } else { + set fact1 44100 + } + + if {$idx2 >= 0} { + set fact2 2 + } else { + set fact2 1 + } + set srate [expr $fact1 * $fact2] +# ADAT lock + + set val [get_val $ooo lockmask] + set adatlock1 0 + set adatlock2 0 + set adatlock3 0 + if {[expr $val & 1]} { + set adatlock3 1 + } + if {[expr $val & 2]} { + set adatlock2 1 + } + if {[expr $val & 4]} { + set adatlock1 1 + } + +# ADAT sync + set val [get_val $ooo syncmask] + set adatsync1 0 + set adatsync2 0 + set adatsync3 0 + + if {[expr $val & 1]} { + set adatsync3 1 + } + if {[expr $val & 2]} { + set adatsync2 1 + } + if {[expr $val & 4]} { + set adatsync1 1 + } + +# TC busy + + set tcbusy [get_bit $ooo "busy"] + set tcout [get_bit $ooo "out"] + set tcvalid [get_bit $ooo "valid"] + set spdiferr [expr [get_bit $ooo "spdif_error"] == 0] + +# 000=64kHz, 100=88.2kHz, 011=96kHz +# 111=32kHz, 110=44.1kHz, 101=48kHz + + set val [get_val $ooo crystalrate] + + set crystal "--.- kHz" + if {$val == 0} { + set crystal "64 kHz" + } + if {$val == 4} { + set crystal "88.2 kHz" + } + if {$val == 3} { + set crystal "96 kHz" + } + if {$val == 7} { + set crystal "32 kHz" + } + if {$val == 6} { + set crystal "44.1 kHz" + } + if {$val == 5} { + set crystal "48 kHz" + } + .status.spdif.sr configure -text $crystal +} + +proc get_offset {} { + global inoffset + global outoffset + global CTRLPROG + + set f [open "| $CTRLPROG mix" r+] + set ooo [read $f 1000] + close $f +# puts $ooo + + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off0 configure -text "dev\#0: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off0 configure -text "dev\#0: $val" + } else { + .control.offset.in.off0 configure -text "dev\#0: -" + .control.offset.out.off0 configure -text "dev\#0: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off1 configure -text "dev\#1: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off1 configure -text "dev\#1: $val" + } else { + .control.offset.in.off1 configure -text "dev\#1: -" + .control.offset.out.off1 configure -text "dev\#1: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off2 configure -text "dev\#2: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off2 configure -text "dev\#2: $val" + } else { + .control.offset.in.off2 configure -text "dev\#2: -" + .control.offset.out.off2 configure -text "dev\#2: -" + } + if { [string match "*devnr*" $ooo] } { + set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end] + set val [get_val2 $ooo i_offset] + .control.offset.in.off3 configure -text "dev\#3: $val" + set val [get_val2 $ooo o_offset] + .control.offset.out.off3 configure -text "dev\#3: $val" + } else { + .control.offset.in.off3 configure -text "dev\#3: -" + .control.offset.out.off3 configure -text "dev\#3: -" + } +} + + +proc get_all {} { +get_status +get_control +get_offset +} + +# main +while {1} { + after 200 + get_all + update +} diff -urN linux-2.4.18/Documentation/sysctl/vm.txt linux-2.4.19-pre5/Documentation/sysctl/vm.txt --- linux-2.4.18/Documentation/sysctl/vm.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/sysctl/vm.txt Sat Mar 30 22:55:25 2002 @@ -21,6 +21,7 @@ - buffermem - freepages - kswapd +- max_map_count - overcommit_memory - page-cluster - pagecache @@ -167,6 +168,19 @@ and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +max_map_count: + +This file contains the maximum number of memory map areas a +process may have. Memory map areas are used as a side-effect +of calling malloc, directly by mmap and mprotect, and also +when loading shared libraries. + +While most applications need less than a thousand maps, +certain programs, particularly malloc debuggers, may consume +lots of them, e.g. up to one or two maps per allocation. ============================================================== diff -urN linux-2.4.18/Documentation/usb/auerswald.txt linux-2.4.19-pre5/Documentation/usb/auerswald.txt --- linux-2.4.18/Documentation/usb/auerswald.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/usb/auerswald.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,30 @@ + Auerswald USB kernel driver + =========================== + +What is it? What can I do with it? +================================== +The auerswald USB kernel driver connects your linux 2.4.x +system to the auerswald usb-enabled devices. + +There are two types of auerswald usb devices: +a) small PBX systems (ISDN) +b) COMfort system telephones (ISDN) + +The driver installation creates the devices +/dev/usb/auer0..15. These devices carry a vendor- +specific protocol. You may run all auerswald java +software on it. The java software needs a native +library "libAuerUsbJNINative.so" installed on +your system. This library is available from +auerswald and shipped as part of the java software. + +You may create the devices with: + mknod -m 666 /dev/usb/auer0 c 180 112 + ... + mknod -m 666 /dev/usb/auer15 c 180 127 + +Future plans +============ +- Connection to ISDN4LINUX (the hisax interface) + +The maintainer of this driver is wmues@nexgo.de diff -urN linux-2.4.18/Documentation/usb/ehci.txt linux-2.4.19-pre5/Documentation/usb/ehci.txt --- linux-2.4.18/Documentation/usb/ehci.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/usb/ehci.txt Sat Mar 30 22:55:25 2002 @@ -0,0 +1,164 @@ +18-Dec-2001 + +The EHCI driver is used to talk to high speed USB 2.0 devices using +USB 2.0-capable host controller hardware. The USB 2.0 standard is +compatible with the USB 1.1 standard. It defines three transfer speeds: + + - "High Speed" 480 Mbit/sec (60 MByte/sec) + - "Full Speed" 12 Mbit/sec (1.5 MByte/sec) + - "Low Speed" 1.5 Mbit/sec + +USB 1.1 only addressed full speed and low speed. High speed devices +can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds. + +USB 1.1 devices may also be used on USB 2.0 systems. When plugged +into an EHCI controller, they are given to a USB 1.1 "companion" +controller, which is a OHCI or UHCI controller as normally used with +such devices. When USB 1.1 devices plug into USB 2.0 hubs, they +interact with the EHCI controller through a "Transaction Translator" +(TT) in the hub, which turns low or full speed transactions into +high speed "split transactions" that don't waste transfer bandwidth. + +At this writing, high speed devices are finally beginning to appear. +While usb-storage devices have been available for some time (working +quite speedily on the 2.4 version of this driver), hubs have only +very recently become available. + +Note that USB 2.0 support involves more than just EHCI. It requires +other changes to the Linux-USB core APIs, including the hub driver, +but those changes haven't needed to really change the basic "usbcore" +APIs exposed to USB device drivers. + +- David Brownell + + + +FUNCTIONALITY + +This driver is regularly tested on x86 hardware, and has also been +used on PPC hardware so big/little endianneess issues should be gone. +It's believed to do all the right PCI magic so that I/O works even on +systems with interesting DMA mapping issues. + +At this writing the driver should comfortably handle all control and bulk +transfers, including requests to USB 1.1 devices through transaction +translators (TTs) in USB 2.0 hubs. However, there some situations where +the hub driver needs to clear TT error state, which it doesn't yet do. + +Interrupt transfer support is newly functional and not yet as robust as +control and bulk traffic. As yet there is no support for split transaction +scheduling for interrupt transfers, which means among other things that +connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work. +Connect them to USB 1.1 hubs, or to a root hub. + +Isochronous (ISO) transfer support is not yet working. No production +high speed devices are available which would need it (though high quality +webcams are in the works!). Note that split transaction support for ISO +transfers can't share much code with the code for high speed ISO transfers, +since EHCI represents these with a different data structure. + +The EHCI root hub code should hand off USB 1.1 devices to its companion +controller. This driver doesn't need to know anything about those +drivers; a OHCI or UHCI driver that works already doesn't need to change +just because the EHCI driver is also present. + +There are some issues with power management; suspend/resume doesn't +behave quite right at the moment. + + +USE BY + +Assuming you have an EHCI controller (on a PCI card or motherboard) +and have compiled this driver as a module, load this like: + + # modprobe ehci-hcd + +and remove it by: + + # rmmod ehci-hcd + +You should also have a driver for a "companion controller", such as +"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci". In case of any trouble +with the EHCI driver, remove its module and then the driver for that +companion controller will take over (at lower speed) all the devices +that were previously handled by the EHCI driver. + +Module parameters (pass to "modprobe") include: + + log2_irq_thresh (default 0): + Log2 of default interrupt delay, in microframes. The default + value is 0, indicating 1 microframe (125 usec). Maximum value + is 6, indicating 2^6 = 64 microframes. This controls how often + the EHCI controller can issue interrupts. + +The EHCI interrupt handler just acknowledges interrupts and schedules +a tasklet to handle whatever needs handling. That keeps latencies low, +no matter how often interrupts are issued. + +Device drivers shouldn't care whether they're running over EHCI or not, +but they may want to check for "usb_device->speed == USB_SPEED_HIGH". +High speed devices can do things that full speed (or low speed) ones +can't, such as "high bandwidth" periodic (interrupt or ISO) transfers. + + +PERFORMANCE + +USB 2.0 throughput is gated by two main factors: how fast the host +controller can process requests, and how fast devices can respond to +them. The 480 Mbit/sec "raw transfer rate" is obeyed by all devices, +but aggregate throughput is also affected by issues like delays between +individual high speed packets, driver intelligence, and of course the +overall system load. Latency is also a performance concern. + +Bulk transfers are most often used where throughput is an issue. It's +good to keep in mind that bulk transfers are always in 512 byte packets, +and at most 13 of those fit into one USB 2.0 microframe. Eight USB 2.0 +microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec. + +Hardware Performance + +At this writing, individual USB 2.0 devices tend to max out at around +20 MByte/sec transfer rates. This is of course subject to change; +and some devices now go faster, while others go slower. + +The NEC implementation of EHCI seems to have a hardware bottleneck +at around 28 MByte/sec aggregate transfer rate. While this is clearly +enough for a single device at 20 MByte/sec, putting three such devices +onto one bus does not get you 60 MByte/sec. The issue appears to be +that the controller hardware won't do concurrent USB and PCI access, +so that it's only trying six (or maybe seven) USB transactions each +microframe rather than thirteen. (Seems like a reasonable trade off +for a product that beat all the others to market by over a year!) +It's expected that newer implementations will better this, throwing +more silicon real estate at the problem so that new motherboard chip +sets will get closer to that 60 MByte/sec target. + +There's a minimum latency of one microframe (125 usec) for the host +to receive interrupts from the EHCI controller indicating completion +of requests. That latency is tunable; there's a module option. By +default ehci-hcd driver uses the minimum latency, which means that if +you issue a control or bulk request you can often expect to learn that +it completed in less than 250 usec (depending on transfer size). + +Software Performance + +To get even 20 MByte/sec transfer rates, Linux-USB device drivers will +need to keep the EHCI queue full. That means issuing large requests, +or using bulk queuing if a series of small requests needs to be issued. +When drivers don't do that, their performance results will show it. + +In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is +going to waste more than half the USB 2.0 bandwidth. Delays between the +I/O completion and the driver issuing the next request will take longer +than the I/O. If that same loop used 16 KB chunks, it'd be better; a +sequence of 128 KB chunks would waste a lot less. + +But rather than depending on such large I/O buffers to make synchronous +I/O be efficient, it's better to just queue all several (bulk) requests +to the HC, and wait for them all to complete (or be canceled on error). +Such URB queuing should work with all the USB 1.1 HC drivers too. + +TBD: Interrupt and ISO transfer performance issues. Those periodic +transfers are fully scheduled, so the main issue is likely to be how +to trigger "high bandwidth" modes. + diff -urN linux-2.4.18/Documentation/usb/ibmcam.txt linux-2.4.19-pre5/Documentation/usb/ibmcam.txt --- linux-2.4.18/Documentation/usb/ibmcam.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/usb/ibmcam.txt Sat Mar 30 22:55:25 2002 @@ -25,12 +25,19 @@ SUPPORTED CAMERAS: -IBM "C-It" camera, also known as "Xirlink PC Camera" +Xirlink "C-It" camera, also known as "IBM PC Camera". The device uses proprietary ASIC (and compression method); it is manufactured by Xirlink. See http://www.xirlink.com/ http://www.ibmpccamera.com or http://www.c-itnow.com/ for details and pictures. +This very chipset ("X Chip", as marked at the factory) +is used in several other cameras, and they are supported +as well: + +- IBM NetCamera +- Veo Stingray + 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). This @@ -50,12 +57,30 @@ Such type of cameras is referred to as "model 2". They are supported (with exception of 352x288 native mode). +Some IBM NetCameras (Model 4) are made to generate only compressed +video streams. This is great for performance, but unfortunately +nobody knows how to decompress the stream :-( Therefore, these +cameras are *unsupported* and if you try to use one of those, all +you get is random colored horizontal streaks, not the image! +If you have one of those cameras, you probably should return it +to the store and get something that is supported. + +Tell me more about all that "model" business +-------------------------------------------- + +I just invented model numbers to uniquely identify flavors of the +hardware/firmware that were sold. It was very confusing to use +brand names or some other internal numbering schemes. So I found +by experimentation that all Xirlink chipsets fall into four big +classes, and I called them "models". Each model is programmed in +its own way, and each model sends back the video in its own way. + Quirks of Model 2 cameras: ------------------------- Model 2 does not have hardware contrast control. Corresponding V4L -control is not used at the moment. It may be possible to implement -contrast control in software, at cost of extra processor cycles. +control is implemented in software, which is not very nice to your +CPU, but at least it works. This driver provides 352x288 mode by switching the camera into quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting @@ -67,17 +92,24 @@ the frame rate at slowest setting, but I had to move it pretty much down the scale (so that framerate option barely matters). I also noticed that camera after first powering up produces frames slightly faster than during -consecutive uses. All this means that if you use videosize=2 (which is +consecutive uses. All this means that if you use 352x288 (which is default), be warned - you may encounter broken picture on first connect; try to adjust brightness - brighter image is slower, so USB will be able to send all data. However if you regularly use Model 2 cameras you may -prefer videosize=1 which makes perfectly good I420, with no scaling and +prefer 176x144 which makes perfectly good I420, with no scaling and lesser demands on USB (300 Kbits per second, or 26 frames per second). +Another strange effect of 352x288 mode is the fine vertical grid visible +on some colored surfaces. I am sure it is caused by me not understanding +what the camera is trying to say. Blame trade secrets for that. + The camera that I had also has a hardware quirk: if disconnected, it needs few minutes to "relax" before it can be plugged in again (poorly designed USB processor reset circuit?) +[Veo Stingray with Product ID 0x800C is also Model 2, but I haven't +observed this particular flaw in it.] + Model 2 camera can be programmed for very high sensitivity (even starlight may be enough), this makes it convenient for tinkering with. The driver code has enough comments to help a programmer to tweak the camera @@ -98,12 +130,14 @@ precompile all modules, so you can go directly to the next section "HOW TO USE THE DRIVER". -The driver consists of two files in usb/ directory: -ibmcam.c and ibmcam.h These files are included into the -Linux kernel build process if you configure the kernel -for CONFIG_USB_IBMCAM. Run "make xconfig" and in USB section -you will find the IBM camera driver. Select it, save the -configuration and recompile. +The ibmcam driver uses usbvideo helper library (module), +so if you are studying the ibmcam code you will be led there. + +The driver itself consists of only one file in usb/ directory: +ibmcam.c. This file is included into the Linux kernel build +process if you configure the kernel for CONFIG_USB_IBMCAM. +Run "make xconfig" and in USB section you will find the IBM +camera driver. Select it, save the configuration and recompile. HOW TO USE THE DRIVER: @@ -112,6 +146,13 @@ settings than V4L can operate, so some settings are done using module options. +To begin with, on most modern Linux distributions the driver +will be automatically loaded whenever you plug the supported +camera in. Therefore, you don't need to do anything. However +if you want to experiment with some module parameters then +you can load and unload the driver manually, with camera +plugged in or unplugged. + Typically module is installed with command 'modprobe', like this: # modprobe ibmcam framerate=1 @@ -138,7 +179,7 @@ init_hue Integer 0-255 [128] init_hue=115 lighting Integer 0-2* [1] lighting=2 sharpness Integer 0-6* [4] sharpness=3 -videosize Integer 0-2* [2] videosize=1 +size Integer 0-2* [2] size=1 Options for Model 2 only: @@ -181,6 +222,11 @@ this is a little faster but may produce flicker if frame rate is too high and Isoc data gets lost. + FLAGS_NO_DECODING 128 This flag turns the video stream + decoder off, and dumps the raw + Isoc data from the camera into + the reading process. Useful to + developers, but not to users. framerate This setting controls frame rate of the camera. This is an approximate setting (in terms of "worst" ... "best") @@ -227,35 +273,38 @@ be greeted with "snowy" image. Default is 4. Model 2 cameras do not support this feature. -videosize This setting chooses one if three image sizes that are - supported by this driver. Camera supports more, but +size This setting chooses one of several image sizes that are + supported by this driver. Cameras may support more, but it's difficult to reverse-engineer all formats. Following video sizes are supported: - videosize=0 128x96 (Model 1 only) - videosize=1 176x144 - videosize=2 352x288 - videosize=3 320x240 (Model 2 only) - videosize=4 352x240 (Model 2 only) + size=0 128x96 (Model 1 only) + size=1 160x120 + size=2 176x144 + size=3 320x240 (Model 2 only) + size=4 352x240 (Model 2 only) + size=5 352x288 + size=6 640x480 (Model 3 only) - The last one (352x288) is the native size of the sensor - array, so it's the best resolution camera (Model 1) can + The 352x288 is the native size of the Model 1 sensor + array, so it's the best resolution the camera can yield. The best resolution of Model 2 is 176x144, and larger images are produced by stretching the bitmap. + Model 3 has sensor with 640x480 grid, and it works too, + but the frame rate will be exceptionally low (1-2 FPS); + it may be still OK for some applications, like security. Choose the image size you need. The smaller image can support faster frame rate. Default is 352x288. +For more information and the Troubleshooting FAQ visit this URL: + + http://www.linux-usb.org/ibmcam/ + WHAT NEEDS TO BE DONE: -- The box freezes if camera is unplugged after being used (OHCI). - Workaround: remove usb-ohci module first. -- On occasion camera (model 1) does not start properly (xawtv reports - errors), or camera produces negative image (funny colors.) - Workaround: reload the driver module. Reason: [1]. - The button on the camera is not used. I don't know how to get to it. I know now how to read button on Model 2, but what to do with it? -[1] - Camera reports its status back to the driver; however I don't know what returned data means. If camera fails at some initialization stage then something should be done, and I don't do that because @@ -263,26 +312,13 @@ concern because Model 2 uses different commands which do not return status (and seem to complete successfully every time). -VIDEO SIZE AND IMAGE SIZE - -Camera produces picture X by Y pixels. This is camera-specific and can be -altered by programming the camera accordingly. This image is placed onto -larger (or equal) area W by H, this is V4L image. At this time the driver -uses V4L image size (W by H) 352x288 pixels because many programs (such -as xawtv) expect quite specific sizes and don't want to deal with arbitrary, -camera-specific sizes. However this approach "hides" real image size, and -application always sees the camera as producing only 352x288 image. It is -possible to change the V4L image size to 128x96, and then if camera is -switched to 128x96 mode then xawtv will correctly accept this image size. But -many other popular sizes (such as 176x144) will not be welcomed. This is the -reason why all camera images are at this time placed onto 352x288 "canvas", -and size of that canvas (V4L) is reported to applications. It will be easy -to add options to control the canvas size, but it will be application- -specific because not all applications are ready to work with variety of -camera-specific sizes. +- Some flavors of Model 4 NetCameras produce only compressed video + streams, and I don't know how to decode them. CREDITS: The code is based in no small part on the CPiA driver by Johannes Erdfelt, Randy Dunlap, and others. Big thanks to them for their pioneering work on that and the USB stack. + +I also thank John Lightsey for his donation of the Veo Stingray camera. diff -urN linux-2.4.18/Documentation/usb/proc_usb_info.txt linux-2.4.19-pre5/Documentation/usb/proc_usb_info.txt --- linux-2.4.18/Documentation/usb/proc_usb_info.txt Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/usb/proc_usb_info.txt Sat Mar 30 22:55:37 2002 @@ -1,32 +1,99 @@ /proc/bus/usb filesystem output =============================== -(version 2000.08.15) +(version 2002.03.18) -The /proc filesystem for USB devices generates -/proc/bus/usb/drivers and /proc/bus/usb/devices. +The /proc filesystem for USB devices provides /proc/bus/usb/drivers +and /proc/bus/usb/devices, as well as /proc/bus/usb/BBB/DDD files. -/proc/bus/usb/drivers lists the registered drivers, -one per line, with each driver's USB minor dev node -number range if applicable. -**NOTE**: If /proc/bus/usb appears empty, you need - to mount the filesystem, issue the command (as root): +**NOTE**: If /proc/bus/usb appears empty, and a host controller + driver has been linked, then you need to mount the + filesystem. Issue the command (as root): - mount -t usbdevfs none /proc/bus/usb + mount -t usbfs none /proc/bus/usb An alternative and more permanent method would be to add - none /proc/bus/usb usbdevfs defaults 0 0 + none /proc/bus/usb usbfs defaults 0 0 - to /etc/fstab. This will mount usbdevfs at each reboot. + to /etc/fstab. This will mount usbfs at each reboot. You can then issue `cat /proc/bus/usb/devices` to extract - USB device information. + USB device information, and user mode drivers can use usbfs + to interact with USB devices. -For more information on mounting the usbdevfs file system, see the + There are a number of mount options supported by usbfs. + Consult the source code (linux/drivers/usb/inode.c) for + information about those options. + +**NOTE**: The filesystem has been renamed from "usbdevfs" to + "usbfs", to reduce confusion with "devfs". You may + still see references to the older "usbdevfs" name. + +For more information on mounting the usbfs file system, see the "USB Device Filesystem" section of the USB Guide. The latest copy of the USB Guide can be found at http://www.linux-usb.org/ + +THE /proc/bus/usb/BBB/DDD FILES: +-------------------------------- +Each connected USB device has one file. The BBB indicates the bus +number. The DDD indicates the device address on that bus. Both +of these numbers are assigned sequentially, and can be reused, so +you can't rely on them for stable access to devices. For example, +it's relatively common for devices to re-enumerate while they are +still connected (perhaps someone jostled their power supply, hub, +or USB cable), so a device might be 002/027 when you first connect +it and 002/048 sometime later. + +These files can be read as binary data. The binary data consists +of first the device descriptor, then the descriptors for each +configuration of the device. That information is also shown in +text form by the /proc/bus/usb/devices file, described later. + +These files may also be used to write user-level drivers for the USB +devices. You would open the /proc/bus/usb/BBB/DDD file read/write, +read its descriptors to make sure it's the device you expect, and then +bind to an interface (or perhaps several) using an ioctl call. You +would issue more ioctls to the device to communicate to it using +control, bulk, or other kinds of USB transfers. The IOCTLs are +listed in the file, and at this writing the +source code (linux/drivers/usb/devio.c) is the primary reference +for how to access devices through those files. + +Note that since by default these BBB/DDD files are writable only by +root, only root can write such user mode drivers. You can selectively +grant read/write permissions to other users by using "chmod". Also, +usbfs mount options such as "devmode=0666" may be helpful. + + + +THE /proc/bus/usb/drivers FILE: +------------------------------- +Each of the USB device drivers linked into your kernel (statically, +or dynamically using "modprobe") is listed in the "drivers" file. +Here's an example from one system: + + usbdevfs + hub + 0- 15: usblp + usbnet + serial + usb-storage + pegasus + +If you see this file, "usbdevfs" and "hub" will always be listed, +since those are part of the "usbcore" framework. + +Drivers that use the USB major number (180) to provide character devices +will include a range of minor numbers, as shown above for the "usblp" +(actually "printer.o") module. USB device drivers can of course use any +major number, but it's easy to use the USB range since there's explicit +support for subdividing it in the USB device driver framework. + + +THE /proc/bus/usb/devices FILE: +------------------------------- In /proc/bus/usb/devices, each device's output has multiple lines of ASCII output. I made it ASCII instead of binary on purpose, so that someone @@ -34,8 +101,6 @@ auxiliary program. However, with an auxiliary program, the numbers in the first 4 columns of each "T:" line (topology info: Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram. -(I think. I haven't proved this, but I have tested it with 3 -different topo/connections and it looked possible.) Each line is tagged with a one-character ID for that line: @@ -73,14 +138,30 @@ | |__Bus number |__Topology info tag + Speed may be: + 1.5 Mbit/s for low speed USB + 12 Mbit/s for full speed USB + 480 Mbit/s for high speed USB (added for USB 2.0) + Bandwidth info: B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd -| | | |__Number if isochronous requests +| | | |__Number of isochronous requests | | |__Number of interrupt requests | |__Total Bandwidth allocated to this bus |__Bandwidth info tag + Bandwidth allocation is an approximation of how much of one frame + (millisecond) is in use. It reflects only periodic transfers, which + are the only transfers that reserve bandwidth. Control and bulk + transfers use all other bandwidth, including reserved bandwidth that + is not used for transfers (such as for short packets). + + The percentage is how much of the "reserved" bandwidth is scheduled by + those transfers. For a low or full speed bus (loosely, "USB 1.1"), + 90% of the bus bandwidth is reserved. For a high speed bus (loosely, + "USB 2.0") 80% is reserved. + Device descriptor info & Product ID info: @@ -109,37 +190,55 @@ S: Manufacturer=ssss | |__Manufacturer of this device as read from the device. +| For USB host controller drivers (virtual root hubs) this may +| be omitted, or (for newer drivers) will identify the kernel +| version and the driver which provides this hub emulation. |__String info tag S: Product=ssss -| |__Product description of this device as read from the device, -| except that it is a generated string for USB host controllers -| (virtual root hubs), in the form "USB *HCI Root Hub". +| |__Product description of this device as read from the device. +| For older USB host controller drivers (virtual root hubs) this +| indicates the driver; for newer ones, it's a product (and vendor) +| description that often comes from the kernel's PCI ID database. |__String info tag S: SerialNumber=ssss -| |__Serial Number of this device as read from the device, -| except that it is a generated string for USB host controllers -| (virtual root hubs), and represents the host controller's -| unique identification in the system (currently I/O or -| memory-mapped base address). +| |__Serial Number of this device as read from the device. +| For USB host controller drivers (virtual root hubs) this is +| some unique ID, normally a bus ID (address or slot name) that +| can't be shared with any other device. |__String info tag + Configuration descriptor info: -C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA -| | | | |__MaxPower in mA -| | | |__Attributes -| | |__ConfiguratioNumber -| |__NumberOfInterfaces +C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA +| | | | | |__MaxPower in mA +| | | | |__Attributes +| | | |__ConfiguratioNumber +| | |__NumberOfInterfaces +| |__ "*" indicates the active configuration (others are " ") |__Config info tag + + USB devices may have multiple configurations, each of which act + rather differently. For example, a bus-powered configuration + might be much less capable than one that is self-powered. Only + one device configuration can be active at a time; most devices + have only one configuration. + + Each configuration consists of one or more interfaces. Each + interface serves a distinct "function", which is typically bound + to a different USB device driver. One common example is a USB + speaker with an audio interface for playback, and a HID interface + for use with software volume control. Interface descriptor info (can be multiple per Config): I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss | | | | | | | |__Driver name +| | | | | | | or "(none)" | | | | | | |__InterfaceProtocol | | | | | |__InterfaceSubClass | | | | |__InterfaceClass @@ -148,16 +247,38 @@ | |__InterfaceNumber |__Interface info tag + A given interface may have one or more "alternate" settings. + For example, default settings may not use more than a small + amount of periodic bandwidth. To use significant fractions + of bus bandwidth, drivers must select a non-default altsetting. + + Only one setting for an interface may be active at a time, and + only one driver may bind to an interface at a time. Most devices + have only one alternate setting per interface. + Endpoint descriptor info (can be multiple per Interface): E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms -E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms -| | | | |__Interval +| | | | |__Interval (max) between transfers | | | |__EndpointMaxPacketSize | | |__Attributes(EndpointType) | |__EndpointAddress(I=In,O=Out) |__Endpoint info tag + + The interval is nonzero for all periodic (interrupt or isochronous) + endpoints. For high speed endpoints the transfer interval may be + measured in microseconds rather than milliseconds. + + For high speed periodic endpoints, the "MaxPacketSize" reflects + the per-microframe data transfer size. For "high bandwidth" + endpoints, that can reflect two or three packets (for up to + 3KBytes every 125 usec) per endpoint. + + With the Linux-USB stack, periodic bandwidth reservations use the + transfer intervals and sizes provided by URBs, which can be less + than those found in endpoint descriptor. + ======================================================================= diff -urN linux-2.4.18/Documentation/usb/usb-serial.txt linux-2.4.19-pre5/Documentation/usb/usb-serial.txt --- linux-2.4.18/Documentation/usb/usb-serial.txt Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/Documentation/usb/usb-serial.txt Sat Mar 30 22:55:33 2002 @@ -95,12 +95,13 @@ Kroah-Hartman at greg@kroah.com -Compaq iPAQ driver +Compaq iPAQ and HP Jornada driver - This driver can be used to connect to Compaq iPAQ PDAs running - Windows CE 3.0 using a USB autosync cable. It has been tested only on - the Compaq H3135. It should work with the H3600 and later models too. - It may work with other CE based handhelds as well. + This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs + running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It + has been tested only on the Compaq H3135, but is rumoured to work on + with the H3600 and later models as well as the Jornada 548 and 568. + With minor modifications, it may work for other CE based handhelds too. The driver presents a serial interface (usually on /dev/ttyUSB0) over which one may run ppp and establish a TCP/IP link to the iPAQ. Once this @@ -109,11 +110,14 @@ kbytes/sec for download/upload to the iPAQ. The driver works intermittently with the usb-uhci driver but quite - reliably with the uhci driver. Make sure you have the right driver - loaded - usb-uhci is often the default. + reliably with the uhci driver. However, performance is much better + with usb-uhci. It does not seem to work with ohci at all. You must setup hotplug to invoke pppd as soon as the iPAQ is connected. - A ppp script like the one below may be used: + A ppp script like the one below should be kept in the file + /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no + options in /etc/ppp/options or ~/.ppprc which conflict with the ones + given below. #!/bin/bash @@ -133,7 +137,7 @@ On connecting the cable, you should see the usual "Device Connected", "User Authenticated" messages flash by on your iPAQ. Once connected, you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ - and other synce utilities from the Linux side. Remember to enable IP + and xcerdisp, synce utilities from the Linux side. Remember to enable IP forwarding. To use Pocket IE, follow the instructions given at diff -urN linux-2.4.18/Documentation/video4linux/bttv/CARDLIST linux-2.4.19-pre5/Documentation/video4linux/bttv/CARDLIST --- linux-2.4.18/Documentation/video4linux/bttv/CARDLIST Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/video4linux/bttv/CARDLIST Sat Mar 30 22:55:25 2002 @@ -7,13 +7,13 @@ card=5 - Diamond DTV2000 card=6 - AVerMedia TVPhone card=7 - MATRIX-Vision MV-Delta - card=8 - Fly Video II (Bt848) - card=9 - TurboTV + card=8 - FlyVideo II (Bt848) LR26 + card=9 - IXMicro TurboTV card=10 - Hauppauge (bt878) card=11 - MIRO PCTV pro card=12 - ADS Technologies Channel Surfer TV card=13 - AVerMedia TVCapture 98 - card=14 - Aimslab VHX + card=14 - Aimslab Video Highway Xtreme (VHX) card=15 - Zoltrix TV-Max card=16 - Pixelview PlayTV (bt878) card=17 - Leadtek WinView 601 @@ -21,7 +21,7 @@ card=19 - LifeView FlyKit w/o Tuner card=20 - CEI Raffles Card card=21 - Lucky Star Image World ConferenceTV - card=22 - Phoebe Tv Master + FM + card=22 - Phoebe Tv Master + FM (CPH050) card=23 - Modular Technology MM205 PCTV, bt878 card=24 - [many vendors] CPH05X/06X (bt878) card=25 - Terratec/Vobis TV-Boostar @@ -54,12 +54,12 @@ card=52 - Pinnacle PCTV Studio Pro card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS card=54 - Lifetec LT 9415 TV (LR90 Rev.F) - card=55 - BESTBUY Easy TV + card=55 - BESTBUY Easy TV (CPH031) card=56 - FlyVideo '98/FM - card=57 - GrandTec 'Grand Video Capture' - card=58 - Phoebe TV Master Only (No FM) - card=59 - TV Capturer - card=60 - MM100PCTV + card=57 - GrandTec 'Grand Video Capture' (Bt848) + card=58 - Phoebe TV Master Only (No FM) CPH060 + card=59 - TV Capturer (CPH03X) + card=60 - Modular Technology MM100PCTV card=61 - AG Electronics GMV1 card=62 - BESTBUY Easy TV (bt878) card=63 - ATI TV-Wonder @@ -72,6 +72,12 @@ card=70 - PV-BT878P+ card=71 - Flyvideo 98EZ (capture only) card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) + card=73 - Sensoray 311 + card=74 - RemoteVision MX (RV605) + card=75 - Powercolor MTV878/ MTV878R/ MTV878F + card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) + card=77 - GrandTec Multi Capture Card (Bt878) + card=78 - AOPEN VA1000 tuner.o type=0 - Temic PAL (4002 FH5) @@ -94,7 +100,7 @@ type=17 - Philips NTSC_M (MK2) type=18 - Temic PAL_I (4066 FY5) type=19 - Temic PAL* auto (4006 FN5) - type=20 - Temic PAL (4009 FR5) + type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5) type=21 - Temic NTSC (4039 FR5) type=22 - Temic PAL/SECAM multi (4046 FM5) type=23 - Philips PAL_DK diff -urN linux-2.4.18/Documentation/video4linux/bttv/Cards linux-2.4.19-pre5/Documentation/video4linux/bttv/Cards --- linux-2.4.18/Documentation/video4linux/bttv/Cards Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/video4linux/bttv/Cards Sat Mar 30 22:55:25 2002 @@ -15,6 +15,10 @@ All other cards only differ by additional components as tuners, sound decoders, EEPROMs, teletext decoders ... +Unsupported Cards: +------------------ +Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by this driver. + MATRIX Vision ------------- @@ -137,20 +141,37 @@ 1851:1850 = Flyvideo 98 1851:1851 = Flyvideo 98 EZ (capture only) 2) There is a print on the PCB: - LR25 = Flyvideo (Zoran) - LR37 Rev.C = Capture only (ZR36120 + SAA7110) + LR25 = Flyvideo (Zoran ZR36120, SAA7110A) + LR26 Rev.N = Flyvideo II (Bt848) + Rev.O = Flyvideo II (Bt878) + LR37 Rev.C = Flyvideo EZ (Capture only, ZR36120 + SAA7110) + LR38 Rev.A1= Flyvideo II EZ (Bt848 capture only) LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID) - LR50 Rev.W = Flyvideo 98 (no eeprom) + Rev.W = Flyvideo 98 (no eeprom) LR51 Rev.E = Flyvideo 98 EZ (capture only) LR90 = Flyvideo 2000 series - LR90 Rev.F = Lifetec/Medion LT 9815 + LR91 = Stereo daughter card for LR90 LR97 = Flyvideo DVBS + LR138 Rev.C= Flyvideo 2000 (SAA7130) + or Flyvideo 3000 (SAA7134) w/Stereo TV + These exist in variations w/FM and w/Remote sometimes denoted + by suffixes "FM" and "R". + + Lifeview.com.tw states (Feb. 2002): + "The FlyVideo2000 and FlyVideo2000s product name have renamed to FlyVideo98." + Their Bt8x8 cards are listed as discontinued. + Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?). + The new Flyvideo 2000/3000 are SAA7130/SAA7134 based. + Flyvideo 2100/3100 are half-sized cards (for system integrators etc.) "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany) this name is re-used for LR50 Rev.W. - The Lifeview website has even more names: Flyvideo III,2100,3000,3100. + The Lifeview website mentioned Flyvideo III at some time, but such a card + has never been seen. These cards are sold by many OEMs too. + FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) + Typhoon TV card series: ----------------------- @@ -176,6 +197,7 @@ Guillemot --------- + Maxi-TV PCI (ZR36120) Maxi TV Video 2 = LR50 Rev.Q (FI1216MF, PAL BG+SECAM) Maxi TV Video 3 = CPH064 (PAL BG + SECAM) @@ -208,3 +230,163 @@ Genius/Kye ---------- Video Wonder/Genius Internet Video Kit = LR37 Rev.C + Video Wonder Pro II (848 or 878) = LR26 + +Tekram +------ + VideoCap C205 (Bt848) + VideoCap C210 (Zoran ZR36120 +Philips) + CaptureTV M200 (ISA) + CaptureTV M205 (Bt848) + +Lucky Star +---------- + Image World Conference TV = LR50 Rev. Q + +Leadtek +------- + WinView 601 (Bt848) + WinView 610 (Zoran) + WinFast2000 + +KNC One +------- + TV-Station + TV-Station SE (+Software Bundle) + TV-Station pro (+TV stereo) + TV-Station FM (+Radio) + TV-Station RDS (+RDS) + +PV951 cards: +------------ + These are sold as: + Boeder TV-FM Video Capture Card + Titanmedia Supervision TV-2400 + Provideo PV951 TF + 3DeMon PV951 + MediaForte TV-Vision PV951 + Yoko PV951 + +Highscreen +---------- + TV Karte = LR50 Rev.S + TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, TDA9821) "ceb105.pcb" + +Zoltrix +------- + Face To Face TV MAX (Bt848) (PCB "VP-8482 Rev1.3") + Genie TV (Bt878) (PCB "VP-8790 Rev 2.1") + +AVerMedia +--------- + AVer FunTV Lite (ISA, AV3001 chipset) "M101.C" + AVerTV + AVerTV Stereo + AVerTV Studio (w/FM) + AVerMedia TV98 with Remote + AVerMedia TV/FM98 Stereo + AVerMedia TVCAM98 + TVCapture (Bt848) + TVPhone (Bt848) + TVCapture98 (="AVerMedia TV98" in USA) (Bt878) + TVPhone98 (Bt878, w/FM) + + PCB PCI-ID Model-Name Eeprom Tuner Sound Country + -------------------------------------------------------------------- + M1A8-A -- AVer TV-Phone FM1216 -- + M168-T 1461:0003 AVerTV Studio 48:17 FM1216 TDA9840T D (1) w/FM w/Remote + M168-U 1461:0004 TVCapture98 40:11 FI1216 -- D w/Remote + M168II-B 1461:0003 Medion MD9592 48:16 FM1216 TDA9873H D w/FM + + (1) Daughterboard MB68-A with TDA9820T and TDA9840T + +Aimslab +------- + Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757) + +IXMicro +------- + IXTV BT848 + IXTV BT878 + TurboTV (Bt848) + +Lifetec/Medion/Tevion/Aldi +------- + LT9415/MD9415 = LR90 Rev. F + MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H) + +Modular Technologies (www.modulartech.com) UK +-------------------- + MM100 PCTV (Bt848) + MM205 PCTV (Bt878) + MM210 PCTV (Bt878) (Galaxy TV) + +Terratec +-------- + Terra TV+ Version 1.0 (Bt848), "ceb105.PCB" printed on the PCB, TDA9821 + Terra TV+ Version 1.1 (Bt878), "LR74 Rev.E" printed on the PCB, TDA9821 + Terra TValueRadio, "LR102 Rev.C" printed on the PCB + Terra TV/Radio+ Version 1.0, "80-CP2830100-0" TTTV3 printed on the PCB, i + "CPH010-E83" on the back, SAA6588T, TDA9873H + Terra TValue Version BT878, "80-CP2830110-0 TTTV4" printed on the PCB, + "CPH011-D83" on back + Terra TValue Version 1.0 "ceb105.PCB" (really identical to Terra TV+ Version 1.0) + + LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade) + + +Technisat +--------- + Mediafocus I (ZR36120/ZR36125) + Mediafocus II (SAA7146) + +Siemens +------- + Multimedia eXtension Board (MXB) (SAA7146, SAA7111) + +Stradis +------- + SDM275,SDM250,SDM026,SDM025 (SAA7146, IBMMPEG2): MPEG2 decoder only + +Powercolor +---------- + MTV878 + MTV878R w/Remote Control + MTV878F w/Remote Control w/FM radio + +Pinnacle +-------- + Mirovideo PCTV (Bt848) + Mirovideo PCTV SE (Bt848) + Mirovideo PCTV Pro (Bt848 + Daughterboard) + Studio PCTV Rave (Bt878 w/o infrared) + Studio PCTV + Studio PCTV Pro (Bt878 stereo w/ FM) + + DC1+ (ISA) + DC10 (zr36057 + zr36060 + saa7110 + adv7176) + DC10+ (zr36067 + zr36060 + saa7110 + adv7176) + DC20 + DC30 + DC30+ (zr36067 + zr36050 + zr36016 + vpx3220 + adv7176) + +Lenco +----- + MXR-9565 (=Technisat Mediafocus?) + MXR-9571 (Bt848) + MXR-9575 + MXR-9477 (Bt878) + MXTV-9578CP (= Prolink PV-BT878P+4E) + +Iomega +------ + Buz (Zoran zr36067 + zr36060 + SAA7111 + SAA7185) + +LML +--- + LML33 (zr36067 + zr36060 + bt819+ bt856) + +Grandtec +-------- + Grand Video Capture (Bt848) + Multi Capture Card (Bt878) diff -urN linux-2.4.18/Documentation/video4linux/bttv/Insmod-options linux-2.4.19-pre5/Documentation/video4linux/bttv/Insmod-options --- linux-2.4.18/Documentation/video4linux/bttv/Insmod-options Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/video4linux/bttv/Insmod-options Sat Mar 30 22:55:25 2002 @@ -28,7 +28,7 @@ default is 0 (off). irq_debug=0/1 irq handler debug messages. default is 0 (off). - gbuffers=2-64 number of capture buffers for mmap'ed capture. + gbuffers=2-32 number of capture buffers for mmap'ed capture. default is 2. gbufsize= size of capture buffers. default and maximum value is 0x208000 (~2MB) @@ -38,6 +38,13 @@ push used by bttv. bttv will disable overlay by default on this hardware to avoid crashes. With this insmod option you can override this. + automute=0/1 Automatically mutes the sound if there is + no TV signal, on by default. You might try + to disable this if you have bad input signal + quality which leading to unwanted sound + dropouts. + chroma_agc=0/1 AGC of chroma signal, off by default. + adc_crush=0/1 Luminance ADC crush, on by default. bttv_gpio=0/1 gpiomask= @@ -89,6 +96,8 @@ insmod args for tda9874a: tda9874a_SIF=1/2 select sound IF input pin (1 or 2) (default is pin 1) + tda9874a_AMSEL=0/1 auto-mute select for NICAM (default=0) + Please read note 3 below! tda9874a_STD=n select TV sound standard (0..8): 0 - A2, B/G 1 - A2, M (Korea) @@ -100,11 +109,20 @@ 7 - NICAM, D/K (default) 8 - NICAM, L - Note: tda9874a is very similar to tda9874 (without 'A'-suffix), but - this driver will not work for the latter device (will not load). - Note: tda9874a and tda9875 (which is supported separately by + Note 1: tda9874a supports both tda9874h (old) and tda9874a (new) chips. + Note 2: tda9874h/a and tda9875 (which is supported separately by tda9875.o) use the same i2c address so both modules should not be used at the same time. + Note 3: Using tda9874a_AMSEL option depends on your TV card design! + AMSEL=0: auto-mute will switch between NICAM sound + and the sound on 1st carrier (i.e. FM mono or AM). + AMSEL=1: auto-mute will switch between NICAM sound + and the analog mono input (MONOIN pin). + If tda9874a decoder on your card has MONOIN pin not connected, then + use only tda9874_AMSEL=0 or don't specify this option at all. + For example: + card=65 (FlyVideo 2000S) - set AMSEL=1 or AMSEL=0 + card=72 (Prolink PV-BT878P rev.9B) - set AMSEL=0 only msp3400.o The driver for the msp34xx sound processor chips. If you have a diff -urN linux-2.4.18/Documentation/video4linux/bttv/README.freeze linux-2.4.19-pre5/Documentation/video4linux/bttv/README.freeze --- linux-2.4.18/Documentation/video4linux/bttv/README.freeze Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/video4linux/bttv/README.freeze Sat Mar 30 22:55:25 2002 @@ -0,0 +1,65 @@ + +If the box freezes hard with bttv ... +===================================== + +It might be a bttv driver bug. It also might be bad hardware. It also +might be something else ... + +Just mailing me "bttv freezes" isn't going to help much. This README +has a few hints how you can help to pin down the problem. + + +bttv bugs +--------- + +If some version works and another doesn't it is likely to be a driver +bug. It is very helpful if you can tell where exactly it broke +(i.e. the last working and the first broken version). + +With a hard freeze you probably doesn't find anything in the logfiles. +The only way to capture any kernel messages is to hook up a serial +console and let some terminal application log the messages. /me uses +screen. See Documentation/serial-console.txt for details on setting +up a serial console. + +Read Documentation/oops-tracing.txt to learn how to get any useful +information out of a register+stack dump printed by the kernel on +protection faults (so-called "kernel oops"). + +If you run into some kind of deadlock, you can try to dump a call trace +for each process using sysrq-t (see Documentation/sysrq.txt). ksymoops +will translate these dumps into kernel symbols too. This way it is +possible to figure where *exactly* some process in "D" state is stuck. + +I've seen reports that bttv 0.7.x crashes whereas 0.8.x works rock solid +for some people. Thus probably a small buglet left somewhere in bttv +0.7.x. I have no idea where exactly, it works stable for me and alot of +other people. But in case you have problems with the 0.7.x versions you +can give 0.8.x a try ... + + +hardware bugs +------------- + +Some hardware can't deal with PCI-PCI transfers (i.e. grabber => vga). +Sometimes problems show up with bttv just because of the high load on +the PCI bus. The bt848/878 chips have a few workarounds for known +incompatibilities, see README.quirks. + +Some mainboard have problems to deal correctly with multiple devices +doing DMA at the same time. bttv + ide seems to cause this sometimes, +if this is the case you likely see freezes only with video and hard disk +access at the same time. Updating the IDE driver to get the latest and +greatest workarounds for hardware bugs might fix these problems. + + +other +----- + +IRQ sharing is known to cause problems in some cases. It works just +fine in theory and many configurations. Neverless it might be worth a +try to shuffle around the PCI cards to give bttv another IRQ or make +it share the IRQ with some other piece of hardware. IRQ sharing with +VGA cards seems to cause trouble sometimes. I've also seen funny +effects with bttv sharing the IRQ with the ACPI bridge (and +apci-enabled kernel). diff -urN linux-2.4.18/Documentation/video4linux/bttv/Sound-FAQ linux-2.4.19-pre5/Documentation/video4linux/bttv/Sound-FAQ --- linux-2.4.18/Documentation/video4linux/bttv/Sound-FAQ Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/Documentation/video4linux/bttv/Sound-FAQ Sat Mar 30 22:55:25 2002 @@ -62,7 +62,7 @@ { [ ... ] u32 gpiomask; - u32 audiomux[5]; /* audio mux: tuner, radio, external, internal, mute */ + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ }; gpiomask specifies which pins are used to control the audio mux chip. @@ -127,6 +127,9 @@ *_modulename - hint whenever some card needs this or that audio module loaded to work properly. has_radio - whenever this TV card has a radio tuner. +no_msp34xx - "1" disables loading of msp3400.o module +no_tda9875 - "1" disables loading of tda9875.o module +needs_tvaudio - set to "1" to load tvaudio.o module If some config item is specified both from the tvcards array and as insmod option, the insmod option takes precedence. diff -urN linux-2.4.18/Documentation/watchdog-api.txt linux-2.4.19-pre5/Documentation/watchdog-api.txt --- linux-2.4.18/Documentation/watchdog-api.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/Documentation/watchdog-api.txt Sat Mar 30 22:55:33 2002 @@ -0,0 +1,390 @@ +The Linux Watchdog driver API. + +Copyright 2002 Christer Weingel + +Some parts of this document are copied verbatim from the sbc60xxwdt +driver which is (c) Copyright 2000 Jakob Oestergaard + +This document describes the state of the Linux 2.4.18 kernel. + +Introduction: + +A Watchdog Timer (WDT) is a hardware circuit that can reset the +computer system in case of a software fault. You probably knew that +already. + +Usually a userspace daemon will notify the kernel watchdog driver via the +/dev/watchdog special device file that userspace is still alive, at +regular intervals. When such a notification occurs, the driver will +usually tell the hardware watchdog that everything is in order, and +that the watchdog should wait for yet another little while to reset +the system. If userspace fails (RAM error, kernel bug, whatever), the +notifications cease to occur, and the hardware watchdog will reset the +system (causing a reboot) after the timeout occurs. + +The Linux watchdog API is a rather AD hoc construction and different +drivers implement different, and sometimes incompatible, parts of it. +This file is an attempt to document the existing usage and allow +future driver writers to use it as a reference. + +The simplest API: + +All drivers support the basic mode of operation, where the watchdog +activates as soon as /dev/watchdog is opened and will reboot unless +the watchdog is pinged within a certain time, this time is called the +timeout or margin. The simplest way to ping the watchdog is to write +some data to the device. So a very simple watchdog daemon would look +like this: + +int main(int argc, const char *argv[]) { + int fd=open("/dev/watchdog",O_WRONLY); + if (fd==-1) { + perror("watchdog"); + exit(1); + } + while(1) { + write(fd, "\0", 1); + sleep(10); + } +} + +A more advanced driver could for example check that a HTTP server is +still responding before doing the write call to ping the watchdog. + +When the device is closed, the watchdog is disabled. This is not +always such a good idea, since if there is a bug in the watchdog +daemon and it crashes the system will not reboot. Because of this, +some of the drivers support the configuration option "Disable watchdog +shutdown on close", CONFIG_WATCHDOG_NOWAYOUT. If it is set to Y when +compiling the kernel, there is no way of disabling the watchdog once +it has been started. So, if the watchdog dameon crashes, the system +will reboot after the timeout has passed. + +Some other drivers will not disable the watchdog, unless a specific +magic character 'V' has been sent /dev/watchdog just before closing +the file. If the userspace daemon closes the file without sending +this special character, the driver will assume that the daemon (and +userspace in general) died, and will stop pinging the watchdog without +disabling it first. This will then cause a reboot. + +The ioctl API: + +All conforming drivers also support an ioctl API. + +Pinging the watchdog using an ioctl: + +All drivers that have an ioctl interface support at least one ioctl, +KEEPALIVE. This ioctl does exactly the same thing as a write to the +watchdog device, so the main loop in the above program could be +replaced with: + + while (1) { + ioctl(fd, WDIOC_KEEPALIVE, 0); + sleep(10); + } + +the argument to the ioctl is ignored. + +Setting and getting the timeout: + +For some drivers it is possible to modify the watchdog timeout on the +fly with the SETTIMEOUT ioctl, those drivers have the WDIOF_SETTIMEOUT +flag set in their option field. The argument is an integer +representing the timeout in seconds. The driver returns the real +timeout used in the same variable, and this timeout might differ from +the requested one due to limitation of the hardware. + + int timeout = 45; + ioctl(fd, WDIOC_SETTIMEOUT, &timeout); + printf("The timeout was set to %d seconds\n", timeout); + +This example might actually print "The timeout was set to 60 seconds" +if the device has a granularity of minutes for its timeout. + +Starting with the Linux 2.4.18 kernel, it is possible to query the +current timeout using the GETTIMEOUT ioctl. + + ioctl(fd, WDIOC_GETTIMEOUT, &timeout); + printf("The timeout was is %d seconds\n", timeout); + +Envinronmental monitoring: + +All watchdog drivers are required return more information about the system, +some do temperature, fan and power level monitoring, some can tell you +the reason for the last reboot of the system. The GETSUPPORT ioctl is +available to ask what the device can do: + + struct watchdog_info ident; + ioctl(fd, WDIOC_GETSUPPORT, &ident); + +the fields returned in the ident struct are: + + identity a string identifying the watchdog driver + firmware_version the firmware version of the card if available + options a flags describing what the device supports + +the options field can have the following bits set, and describes what +kind of information that the GET_STATUS and GET_BOOT_STATUS ioctls can +return. [FIXME -- Is this correct?] + + WDIOF_OVERHEAT Reset due to CPU overheat + +The machine was last rebooted by the watchdog because the thermal limit was +exceeded + + WDIOF_FANFAULT Fan failed + +A system fan monitored by the watchdog card has failed + + WDIOF_EXTERN1 External relay 1 + +External monitoring relay/source 1 was triggered. Controllers intended for +real world applications include external monitoring pins that will trigger +a reset. + + WDIOF_EXTERN2 External relay 2 + +External monitoring relay/source 2 was triggered + + WDIOF_POWERUNDER Power bad/power fault + +The machine is showing an undervoltage status + + WDIOF_CARDRESET Card previously reset the CPU + +The last reboot was caused by the watchdog card + + WDIOF_POWEROVER Power over voltage + +The machine is showing an overvoltage status. Note that if one level is +under and one over both bits will be set - this may seem odd but makes +sense. + + WDIOF_KEEPALIVEPING Keep alive ping reply + +The watchdog saw a keepalive ping since it was last queried. + + WDIOF_SETTIMEOUT Can set/get the timeout + + +For those drivers that return any bits set in the option field, the +GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current +status, and the status at the last reboot, respectively. + + int flags; + ioctl(fd, WDIOC_GETSTATUS, &flags); + + or + + ioctl(fd, WDIOC_GETBOOTSTATUS, &flags); + +Note that not all devices support these two calls, and some only +support the GETBOOTSTATUS call. + +Some drivers can measure the temperature using the GETTEMP ioctl. The +returned value is the temperature in degrees farenheit. + + int temperature; + ioctl(fd, WDIOC_GETTEMP, &temperature); + +Finally the SETOPTIONS ioctl can be used to control some aspects of +the cards operation; right now the pcwd driver is the only one +supporting thiss ioctl. + + int options = 0; + ioctl(fd, WDIOC_SETOPTIONS, options); + +The following options are available: + + WDIOS_DISABLECARD Turn off the watchdog timer + WDIOS_ENABLECARD Turn on the watchdog timer + WDIOS_TEMPPANIC Kernel panic on temperature trip + +[FIXME -- better explanations] + +Implementations in the current drivers in the kernel tree: + +Here I have tried to summarize what the different drivers support and +where they do strange things compared to the other drivers. + +acquirewdt.c -- Acquire Single Board Computer + + This driver has a hardcoded timeout of 1 minute + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns KEEPALIVEPING. GETSTATUS will return 1 if + the device is open, 0 if not. [FIXME -- isn't this rather + silly? To be able to use the ioctl, the device must be open + and so GETSTATUS will always return 1]. + +advantechwdt.c -- Advantech Single Board Computer + + Timeout that defaults to 60 seconds, supports SETTIMEOUT. + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT. + The GETSTATUS call returns if the device is open or not. + [FIXME -- silliness again?] + +eurotechwdt.c -- Eurotech CPU-1220/1410 + + The timeout can be set using the SETTIMEOUT ioctl and defaults + to 60 seconds. + + Also has a module parameter "ev", event type which controls + what should happen on a timeout, the string "int" or anything + else that causes a reboot. [FIXME -- better description] + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns CARDRESET and WDIOF_SETTIMEOUT but + GETSTATUS is not supported and GETBOOTSTATUS just returns 0. + +i810-tco.c -- Intel 810 chipset + + Also has support for a lot of other i8x0 stuff, but the + watchdog is one of the things. + + The timeout is set using the module parameter "i810_margin", + which is in steps of 0.6 seconds where 2 $@ + $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@ %.o: %.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< diff -urN linux-2.4.18/arch/alpha/Makefile linux-2.4.19-pre5/arch/alpha/Makefile --- linux-2.4.18/arch/alpha/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/Makefile Sat Mar 30 22:55:25 2002 @@ -40,20 +40,20 @@ CFLAGS := $(CFLAGS) -mcpu=pca56 mcpu_done := y endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny) - CFLAGS := $(CFLAGS) -mcpu=ev56 - mcpu_done := y - endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS),ny) - ifeq ($(have_mcpu_pca56),y) - CFLAGS := $(CFLAGS) -mcpu=pca56 - else - CFLAGS := $(CFLAGS) -mcpu=ev56 - endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS)$(have_mcpu_pca56),nyy) + CFLAGS := $(CFLAGS) -mcpu=pca56 mcpu_done := y endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny) CFLAGS := $(CFLAGS) -mcpu=ev4 + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV56),ny) + CFLAGS := $(CFLAGS) -mcpu=ev56 + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV5),ny) + CFLAGS := $(CFLAGS) -mcpu=ev5 mcpu_done := y endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy) diff -urN linux-2.4.18/arch/alpha/config.in linux-2.4.19-pre5/arch/alpha/config.in --- linux-2.4.18/arch/alpha/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/config.in Sat Mar 30 22:55:25 2002 @@ -102,19 +102,44 @@ then define_bool CONFIG_ALPHA_EB64P y fi -if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ] +if [ "$CONFIG_ALPHA_ALCOR" = "y" ] then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 366MHz)?' CONFIG_ALPHA_EV56 fi -if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +if [ "$CONFIG_ALPHA_EB164" = "y" ] +then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_PC164" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ] +then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y + define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_MIKASA" = "y" ] then bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO if [ "$CONFIG_ALPHA_PRIMO" = "y" ] then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 333MHz)?' CONFIG_ALPHA_EV56 + else + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y + fi +fi +if [ "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + bool 'EV5 CPU (model 5/xxx)?' CONFIG_ALPHA_PRIMO + if [ "$CONFIG_ALPHA_PRIMO" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 333MHz)?' CONFIG_ALPHA_EV56 else define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y @@ -135,6 +160,7 @@ -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y define_bool CONFIG_ALPHA_CIA y define_bool CONFIG_ALPHA_PYXIS y fi @@ -159,10 +185,12 @@ then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_MCPCIA y + bool 'EV56 CPU (speed >= 400MHz)?' CONFIG_ALPHA_EV56 fi if [ "$CONFIG_ALPHA_RX164" = "y" ] then define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y define_bool CONFIG_ALPHA_POLARIS y fi if [ "$CONFIG_ALPHA_JENSEN" = "y" ] diff -urN linux-2.4.18/arch/alpha/kernel/alpha_ksyms.c linux-2.4.19-pre5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.4.18/arch/alpha/kernel/alpha_ksyms.c Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/arch/alpha/kernel/alpha_ksyms.c Sat Mar 30 22:55:37 2002 @@ -214,6 +214,7 @@ EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(__cpu_number_map); +EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_on_cpu); diff -urN linux-2.4.18/arch/alpha/kernel/entry.S linux-2.4.19-pre5/arch/alpha/kernel/entry.S --- linux-2.4.18/arch/alpha/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/kernel/entry.S Sat Mar 30 22:55:37 2002 @@ -10,7 +10,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 378 +#define NR_SYSCALLS 382 /* * These offsets must match with alpha_mv in . @@ -1148,3 +1148,9 @@ .quad sys_gettid .quad sys_readahead .quad sys_ni_syscall /* 380, sys_security */ + .quad sys_tkill + +/* Remember to update everything, kids. */ +.ifne (. - sys_call_table) - (NR_SYSCALLS * 8) +.err +.endif diff -urN linux-2.4.18/arch/alpha/kernel/pci_iommu.c linux-2.4.19-pre5/arch/alpha/kernel/pci_iommu.c --- linux-2.4.18/arch/alpha/kernel/pci_iommu.c Sun Mar 3 17:17:04 2002 +++ linux-2.4.19-pre5/arch/alpha/kernel/pci_iommu.c Sat Mar 30 22:55:25 2002 @@ -217,9 +217,14 @@ } /* If the machine doesn't define a pci_tbi routine, we have to - assume it doesn't support sg mapping. */ + assume it doesn't support sg mapping, and, since we tried to + use direct_map above, it now must be considered an error. */ if (! alpha_mv.mv_pci_tbi) { - printk(KERN_WARNING "pci_map_single failed: no hw sg\n"); + static int been_here = 0; /* Only print the message once. */ + if (!been_here) { + printk(KERN_WARNING "pci_map_single: no HW sg\n"); + been_here = 1; + } return 0; } diff -urN linux-2.4.18/arch/alpha/kernel/signal.c linux-2.4.19-pre5/arch/alpha/kernel/signal.c --- linux-2.4.18/arch/alpha/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -717,9 +717,7 @@ default: lock_kernel(); - sigaddset(¤t->pending.signal, signr); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } continue; diff -urN linux-2.4.18/arch/alpha/kernel/smp.c linux-2.4.19-pre5/arch/alpha/kernel/smp.c --- linux-2.4.18/arch/alpha/kernel/smp.c Sun Dec 23 16:23:35 2001 +++ linux-2.4.19-pre5/arch/alpha/kernel/smp.c Sat Mar 30 22:55:33 2002 @@ -184,9 +184,23 @@ */ wait_boot_cpu_to_stop(cpuid); mb(); + try_again: calibrate_delay(); smp_store_cpu_info(cpuid); + + { +#define LPJ(c) ((long)cpu_data[c].loops_per_jiffy) + static int tries = 3; + long diff = LPJ(boot_cpuid) - LPJ(cpuid); + if (diff < 0) diff = -diff; + + if (diff > LPJ(boot_cpuid)/10 && --tries) { + printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid); + goto try_again; + } + } + /* * Allow master to continue only after we written * the loops_per_jiffy. @@ -1065,7 +1079,8 @@ } void -flush_icache_page(struct vm_area_struct *vma, struct page *page) +flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) { struct mm_struct *mm = vma->vm_mm; diff -urN linux-2.4.18/arch/alpha/math-emu/math.c linux-2.4.19-pre5/arch/alpha/math-emu/math.c --- linux-2.4.18/arch/alpha/math-emu/math.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/math-emu/math.c Sat Mar 30 22:55:37 2002 @@ -220,12 +220,12 @@ FP_CONV(S,D,1,1,SR,DB); goto pack_s; } else { - /* CVTST need do nothing else but copy the - bits and repack. */ + vb = alpha_read_fp_reg_s(fb); + FP_UNPACK_SP(SB, &vb); DR_c = DB_c; DR_s = DB_s; DR_e = DB_e; - DR_f = DB_f; + DR_f = SB_f << (52 - 23); goto pack_d; } diff -urN linux-2.4.18/arch/alpha/mm/init.c linux-2.4.19-pre5/arch/alpha/mm/init.c --- linux-2.4.18/arch/alpha/mm/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/mm/init.c Sat Mar 30 22:55:37 2002 @@ -380,7 +380,7 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %ldk freed\n", + printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); } @@ -395,7 +395,7 @@ free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - __start) >> 10); + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - __start) >> 10); } #endif diff -urN linux-2.4.18/arch/alpha/mm/numa.c linux-2.4.19-pre5/arch/alpha/mm/numa.c --- linux-2.4.18/arch/alpha/mm/numa.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/alpha/mm/numa.c Sat Mar 30 22:55:37 2002 @@ -312,7 +312,7 @@ printk("."); \ } while(0) -#define clobber(p, size) memset((p)->virtual, 0xaa, (size)) +#define clobber(p, size) memset(page_address(p), 0xaa, (size)) void __init mem_stress(void) { diff -urN linux-2.4.18/arch/arm/Makefile linux-2.4.19-pre5/arch/arm/Makefile --- linux-2.4.18/arch/arm/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/Makefile Sat Mar 30 22:55:37 2002 @@ -39,10 +39,12 @@ tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 +CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float @@ -74,6 +76,8 @@ ifeq ($(CONFIG_ARCH_EBSA110),y) MACHINE = ebsa110 +CFLAGS_3c589_cs :=-DISA_SIXTEEN_BIT_PERIPHERAL +export CFLAGS_3c589_cs endif ifeq ($(CONFIG_ARCH_CLPS7500),y) @@ -121,6 +125,10 @@ MACHINE = integrator endif +ifeq ($(CONFIG_ARCH_MX1ADS),y) +MACHINE = mx1ads +endif + ifeq ($(CONFIG_ARCH_CAMELOT),y) MACHINE = epxa10db endif @@ -130,11 +138,15 @@ MACHINE = clps711x endif +ifeq ($(CONFIG_ARCH_FORTUNET),y) +TEXTADDR = 0xc0008000 +endif + ifeq ($(CONFIG_ARCH_ANAKIN),y) MACHINE = anakin endif -export MACHINE PROCESSOR TEXTADDR GZFLAGS +export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT # Only set INCDIR if its not already defined above # Grr, ?= doesn't work as all the other assignment operators do. Make bug? @@ -207,6 +219,7 @@ arch/arm/vmlinux.lds MRPROPER_FILES += \ + arch/arm/tools/constants.h* \ include/asm-arm/arch \ include/asm-arm/proc \ include/asm-arm/constants.h* \ @@ -254,7 +267,7 @@ @( \ CFG=$(@:_config=); \ if [ -f arch/arm/def-configs/$$CFG ]; then \ - [ -f .config ] && $(MV) .config .config.old; \ + [ -f .config ] && mv -f .config .config.old; \ cp arch/arm/def-configs/$$CFG .config; \ echo "*** Default configuration for $$CFG installed"; \ echo "*** Next, you may run 'make oldconfig'"; \ diff -urN linux-2.4.18/arch/arm/boot/Makefile linux-2.4.19-pre5/arch/arm/boot/Makefile --- linux-2.4.18/arch/arm/boot/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/Makefile Sat Mar 30 22:55:37 2002 @@ -54,6 +54,14 @@ INITRD_VIRT = 0xc0800000 endif +ifeq ($(CONFIG_ARCH_MX1ADS),y) +ZTEXTADDR = 0x08008000 +endif + +ifeq ($(CONFIG_ARCH_CAMELOT),y) +ZTEXTADDR = 0x00008000 +endif + ifeq ($(CONFIG_ARCH_NEXUSPCI),y) ZTEXTADDR = 0x40008000 endif diff -urN linux-2.4.18/arch/arm/boot/compressed/Makefile linux-2.4.19-pre5/arch/arm/boot/compressed/Makefile --- linux-2.4.18/arch/arm/boot/compressed/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/Makefile Sat Mar 30 22:55:37 2002 @@ -9,7 +9,7 @@ HEAD = head.o OBJS = misc.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_BOOT) FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -33,6 +33,14 @@ OBJS += head-integrator.o endif +ifeq ($(CONFIG_ARCH_MX1ADS),y) +OBJS += head-mx1ads.o +endif + +ifeq ($(CONFIG_ARCH_CAMELOT),y) +OBJS += head-epxa10db.o +endif + ifeq ($(CONFIG_ARCH_FTVPCI),y) OBJS += head-ftvpci.o endif @@ -84,12 +92,12 @@ font.o: $(FONTC) $(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC) -vmlinux.lds: vmlinux.lds.in +vmlinux.lds: vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot/Makefile $(TOPDIR)/.config @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@ clean:; rm -f vmlinux core piggy* vmlinux.lds -.PHONY: vmlinux.lds clean +.PHONY: clean misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c diff -urN linux-2.4.18/arch/arm/boot/compressed/head-epxa10db.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-epxa10db.S --- linux-2.4.18/arch/arm/boot/compressed/head-epxa10db.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-epxa10db.S Sat Mar 30 22:55:37 2002 @@ -0,0 +1,5 @@ +#include +#include + + .section ".start", #alloc, #execinstr + mov r7, #MACH_TYPE_CAMELOT diff -urN linux-2.4.18/arch/arm/boot/compressed/head-mx1ads.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-mx1ads.S --- linux-2.4.18/arch/arm/boot/compressed/head-mx1ads.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-mx1ads.S Sat Mar 30 22:55:37 2002 @@ -0,0 +1,4 @@ +#include + + .section ".start", #alloc, #execinstr + mov r7, #MACH_TYPE_MX1ADS diff -urN linux-2.4.18/arch/arm/boot/compressed/head-shark.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-shark.S --- linux-2.4.18/arch/arm/boot/compressed/head-shark.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-shark.S Sat Mar 30 22:55:37 2002 @@ -1,5 +1,5 @@ /* The head-file for the Shark - * by Alexander Schulz + * by Alexander Schulz * * Does the following: * - get the memory layout from firmware. This can only be done as long as the mmu diff -urN linux-2.4.18/arch/arm/boot/compressed/head.S linux-2.4.19-pre5/arch/arm/boot/compressed/head.S --- linux-2.4.18/arch/arm/boot/compressed/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/head.S Sat Mar 30 22:55:37 2002 @@ -18,14 +18,14 @@ * Please select one of the following when turning on debugging. */ #ifdef DEBUG -#if 0 /* DC21285-type */ +#if defined(CONFIG_DEBUG_DC21285_PORT) .macro loadsp, rb mov \rb, #0x7c000000 .endm .macro writeb, rb strb \rb, [r3, #0x3f8] .endm -#elif 0 /* RiscPC-type */ +#elif defined(CONFIG_ARCH_RPC) .macro loadsp, rb mov \rb, #0x03000000 orr \rb, \rb, #0x00010000 @@ -33,13 +33,25 @@ .macro writeb, rb strb \rb, [r3, #0x3f8 << 2] .endm -#elif 0 /* integrator-type */ +#elif defined(CONFIG_ARCH_INTEGRATOR) .macro loadsp, rb mov \rb, #0x16000000 .endm .macro writeb, rb strb \rb, [r3, #0] .endm +#elif defined(CONFIG_ARCH_SA1100) + .macro loadsp, rb + mov \rb, #0x80000000 @ physical base address +# if defined(CONFIG_DEBUG_LL_SER3) + add \rb, \rb, #0x00050000 @ Ser3 +# else + add \rb, \rb, #0x00010000 @ Ser1 +# endif + .endm + .macro writeb, rb + str \rb, [r3, #0x14] @ UTDR + .endm #else #error no serial architecture defined #endif @@ -64,7 +76,7 @@ kphex r7, 8 /* architecture id */ kputc #':' mrc p15, 0, r0, c1, c0 - kphex r0, 8 /* control reg + kphex r0, 8 /* control reg */ kputc #'\n' kphex r5, 8 /* decompressed kernel start */ kputc #'-' @@ -218,7 +230,8 @@ ldr r1, proc_sa1110_type eor r1, r1, r6 movs r1, r1, lsr #4 - movne pc, lr +@ movne pc, lr + bne cache_off 1: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer diff -urN linux-2.4.18/arch/arm/boot/compressed/misc.c linux-2.4.19-pre5/arch/arm/boot/compressed/misc.c --- linux-2.4.18/arch/arm/boot/compressed/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/misc.c Sat Mar 30 22:55:37 2002 @@ -18,6 +18,8 @@ unsigned int __machine_arch_type; +#include + #include #include #include diff -urN linux-2.4.18/arch/arm/boot/compressed/ofw-shark.c linux-2.4.19-pre5/arch/arm/boot/compressed/ofw-shark.c --- linux-2.4.18/arch/arm/boot/compressed/ofw-shark.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/boot/compressed/ofw-shark.c Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/boot/compressed/ofw-shark.c * - * by Alexander Schulz + * by Alexander Schulz * * This file is used to get some basic information * about the memory layout of the shark we are running diff -urN linux-2.4.18/arch/arm/config.in linux-2.4.19-pre5/arch/arm/config.in --- linux-2.4.18/arch/arm/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/config.in Sat Mar 30 22:55:37 2002 @@ -43,6 +43,7 @@ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ LinkUp-L7200 CONFIG_ARCH_L7200 \ + Motorola-MX1ADS CONFIG_ARCH_MX1ADS \ RiscPC CONFIG_ARCH_RPC \ SA1100-based CONFIG_ARCH_SA1100 \ Shark CONFIG_ARCH_SHARK" RiscPC @@ -85,7 +86,14 @@ 32MB CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD fi -dep_bool ' Compaq iPAQ H3600' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3600/H3700' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3800' CONFIG_SA1100_H3800 $CONFIG_ARCH_SA1100 +if [ "$CONFIG_SA1100_H3100" = "y" -o "$CONFIG_SA1100_H3600" = "y" -o "$CONFIG_SA1100_H3800" = "y" ]; then + define_bool CONFIG_SA1100_H3XXX y +else + define_bool CONFIG_SA1100_H3XXX n +fi #dep_bool ' Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100 dep_bool ' Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100 if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then @@ -93,8 +101,10 @@ fi dep_bool ' FlexaNet' CONFIG_SA1100_FLEXANET $CONFIG_ARCH_SA1100 dep_bool ' FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100 +dep_bool ' Frodo' CONFIG_SA1100_FRODO $CONFIG_ARCH_SA1100 dep_bool ' GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100 dep_bool ' GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100 +dep_bool ' HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100 dep_bool ' HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100 dep_bool ' HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100 dep_bool ' Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100 @@ -103,6 +113,8 @@ dep_bool ' OmniMeter' CONFIG_SA1100_OMNIMETER $CONFIG_ARCH_SA1100 dep_bool ' Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100 dep_bool ' PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100 +dep_bool ' PT System 3' CONFIG_SA1100_PT_SYSTEM3 $CONFIG_ARCH_SA1100 +dep_bool ' Shannon' CONFIG_SA1100_SHANNON $CONFIG_ARCH_SA1100 dep_bool ' Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100 dep_bool ' Simpad' CONFIG_SA1100_SIMPAD $CONFIG_ARCH_SA1100 dep_bool ' Tulsa' CONFIG_SA1100_PFS168 $CONFIG_ARCH_SA1100 @@ -116,18 +128,28 @@ "$CONFIG_SA1100_PFS168" = "y" -o \ "$CONFIG_SA1100_XP860" = "y" -o \ "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \ - "$CONFIG_SA1100_ADSBITSY" = "y" ]; then + "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \ + "$CONFIG_SA1100_ADSBITSY" = "y" -o \ + "$CONFIG_SA1100_BADGE4" = "y" ]; then define_bool CONFIG_SA1111 y define_int CONFIG_FORCE_MAX_ZONEORDER 9 fi + +#dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100 +#dep_tristate ' Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB +#dep_tristate ' Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB + +dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600 endmenu mainmenu_option next_comment comment 'CLPS711X/EP721X Implementations' +dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X dep_bool ' CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X dep_bool ' CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X dep_bool ' EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X dep_bool ' P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X +dep_bool ' FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X # XXX Maybe these should indicate register compatibility # instead of being mutually exclusive. @@ -205,7 +227,7 @@ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \ "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_L7200" = "y" -o "$CONFIG_ARCH_ANAKIN" = "y" -o \ - "$CONFIG_ARCH_CAMELOT" = "y" ]; then + "$CONFIG_ARCH_CAMELOT" = "y" -o "$CONFIG_ARCH_MX1ADS" = "y" ]; then define_bool CONFIG_CPU_32v4 y else define_bool CONFIG_CPU_32v4 n @@ -247,11 +269,17 @@ fi # ARM920T -if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then - bool 'Support ARM920T processor' CONFIG_CPU_ARM920T +if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then + define_bool CONFIG_CPU_ARM920T y else - define_bool CONFIG_CPU_ARM920T n + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM920T processor' CONFIG_CPU_ARM920T + else + define_bool CONFIG_CPU_ARM920T n + fi fi + + if [ "$CONFIG_CPU_ARM920T" = "y" ]; then bool ' ARM920T CPU idle' CONFIG_CPU_ARM920_CPU_IDLE bool ' ARM920T I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON @@ -261,6 +289,21 @@ fi fi +# ARM922T +if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then + define_bool CONFIG_CPU_ARM922T y +else + define_bool CONFIG_CPU_ARM922T n +fi +if [ "$CONFIG_CPU_ARM922T" = "y" ]; then + bool ' ARM922T CPU idle' CONFIG_CPU_ARM922_CPU_IDLE + bool ' ARM922T I-Cache on' CONFIG_CPU_ARM922_I_CACHE_ON + bool ' ARM922T D-Cache on' CONFIG_CPU_ARM922_D_CACHE_ON + if [ "$CONFIG_CPU_ARM922_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM922T' CONFIG_CPU_ARM922_WRITETHROUGH + fi +fi + # ARM926T if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then bool 'Support ARM926T processor' CONFIG_CPU_ARM926T @@ -404,7 +447,8 @@ "$CONFIG_ARCH_P720T" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" -o \ "$CONFIG_ARCH_CAMELOT" = "y" -o \ - "$CONFIG_ARCH_ANAKIN" = "y" ]; then + "$CONFIG_ARCH_ANAKIN" = "y" -o \ + "$CONFIG_ARCH_MX1ADS" = "y" ]; then string 'Default kernel command string' CONFIG_CMDLINE "" fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ @@ -554,7 +598,8 @@ "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_P720T" = "y" -o \ - "$CONFIG_ARCH_ANAKIN" = "y" ]; then + "$CONFIG_ARCH_ANAKIN" = "y" -o \ + "$CONFIG_ARCH_MX1ADS" = "y" ]; then define_bool CONFIG_PC_KEYMAP y fi if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then @@ -594,15 +639,19 @@ # Always compile kernel with framepointer (until 2.4 real comes out) # Bug reports aren't much use without this. bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER -bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO -bool 'Debug memory allocations' CONFIG_DEBUG_SLAB -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 + +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL +dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL +dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL +dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose kernel error messages' CONFIG_DEBUG_ERRORS $CONFIG_DEBUG_KERNEL # These options are only for real kernel hackers who want to get their hands dirty. -dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL -dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE -dep_bool ' kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X +dep_bool ' Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL +dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE +dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X endmenu diff -urN linux-2.4.18/arch/arm/def-configs/badge4 linux-2.4.19-pre5/arch/arm/def-configs/badge4 --- linux-2.4.18/arch/arm/def-configs/badge4 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/def-configs/badge4 Sat Mar 30 22:55:37 2002 @@ -0,0 +1,1136 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +CONFIG_SA1100_BADGE4=y +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1111=y +CONFIG_FORCE_MAX_ZONEORDER=9 +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=y +CONFIG_NET=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +CONFIG_FPE_FASTFPE=m +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +# CONFIG_PM is not set +CONFIG_ARTHUR=m +CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=m +# CONFIG_PARPORT_PC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=0 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +# CONFIG_MTD_CFI_B4 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +CONFIG_MTD_RAM=y +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +CONFIG_AIRO_CS=m +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=y +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=y +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +CONFIG_IRLAN=y +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set +# CONFIG_IRPORT_SIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=y + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +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 is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_PHILIPSPAR is not set +CONFIG_I2C_ELV=m +CONFIG_I2C_VELLEMAN=m +# CONFIG_I2C_BIT_SA1100_GPIO is not set +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ELEKTOR=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m + +# +# L3 serial bus support +# +CONFIG_L3=y +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +CONFIG_L3_SA1111=y +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_SOFT_WATCHDOG=m +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_21285_WATCHDOG is not set +# CONFIG_977_WATCHDOG is not set +CONFIG_SA1100_WATCHDOG=m +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=m +CONFIG_SA1100_RTC=m +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +CONFIG_MINIX_FS=m +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=m + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX 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_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_SA1100=y +CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_ASSABET_UDA1341 is not set +# CONFIG_SOUND_H3600_UDA1341 is not set +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +CONFIG_SOUND_SA1111_UDA1341=y +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +CONFIG_MCP=y +CONFIG_MCP_SA1100=y +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +CONFIG_USB_OHCI_SA1111=y + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=y +CONFIG_USB_BLUETOOTH=m +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DEBUG=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +# CONFIG_USB_STV680 is not set +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_DABUSB=m + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +# CONFIG_USB_SERIAL_IPAQ is not set +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +# CONFIG_USB_SERIAL_KLSI is not set +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN linux-2.4.18/arch/arm/def-configs/flexanet linux-2.4.19-pre5/arch/arm/def-configs/flexanet --- linux-2.4.18/arch/arm/def-configs/flexanet Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/def-configs/flexanet Sat Mar 30 22:55:37 2002 @@ -8,6 +8,8 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set # # Code maturity level options @@ -25,17 +27,19 @@ # # System Type # +# CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_ARCA5K is not set # CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y -# CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_SHARK is not set # # Archimedes/A5000 Implementations @@ -44,22 +48,32 @@ # # Archimedes/A5000 Implementations (select only ONE) # +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set # # Footbridge Implementations # +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set # # SA11x0 Implementations # # CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set # CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_CERF is not set -# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_H3600 is not set # CONFIG_SA1100_EXTENEX1 is not set CONFIG_SA1100_FLEXANET=y # CONFIG_SA1100_FREEBIRD is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set # CONFIG_SA1100_JORNADA720 is not set # CONFIG_SA1100_HUW_WEBPANEL is not set # CONFIG_SA1100_ITSY is not set @@ -68,7 +82,9 @@ # CONFIG_SA1100_OMNIMETER is not set # CONFIG_SA1100_PANGOLIN is not set # CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set # CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set # CONFIG_SA1100_PFS168 is not set # CONFIG_SA1100_VICTOR is not set # CONFIG_SA1100_XP860 is not set @@ -76,11 +92,17 @@ CONFIG_SA1100_USB=y CONFIG_SA1100_USB_NETLINK=y # CONFIG_SA1100_USB_CHAR is not set -# CONFIG_SA1100_FREQUENCY_SCALE is not set # # CLPS711X/EP721X Implementations # +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set @@ -97,32 +119,40 @@ # CONFIG_CPU_ARM710 is not set # CONFIG_CPU_ARM720T is not set # CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set # CONFIG_CPU_ARM1020 is not set # CONFIG_CPU_SA110 is not set CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set CONFIG_DISCONTIGMEM=y -# CONFIG_CPU_BIG_ENDIAN is not set # # General setup # # CONFIG_PCI is not set -# CONFIG_ISA is not set +CONFIG_ISA=y # CONFIG_ISA_DMA is not set -# CONFIG_CPU_CLOCK is not set +CONFIG_CPU_FREQ=y CONFIG_HOTPLUG=y # # PCMCIA/CardBus support # CONFIG_PCMCIA=y +# CONFIG_I82092 is not set # CONFIG_I82365 is not set # CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set CONFIG_PCMCIA_SA1100=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# CONFIG_FPE_NWFPE=y CONFIG_FPE_FASTFPE=y CONFIG_KCORE_ELF=y @@ -130,7 +160,7 @@ # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_PM is not set +CONFIG_PM=y # CONFIG_ARTHUR is not set CONFIG_CMDLINE="" CONFIG_LEDS=y @@ -149,7 +179,7 @@ CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set CONFIG_MTD_PARTITIONS=y -# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_REDBOOT_PARTS=y # CONFIG_MTD_BOOTLDR_PARTS is not set # CONFIG_MTD_AFS_PARTS is not set @@ -165,43 +195,42 @@ # RAM/ROM/Flash chip drivers # CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_VIRTUAL_ER is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_NOSWAP=y # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set -# CONFIG_MTD_CFI_LART_BIT_SWAP is not set # CONFIG_MTD_CFI_GEOMETRY is not set CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_AMDSTD is not set -# CONFIG_MTD_SHARP is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set # CONFIG_MTD_JEDEC is not set # # Mapping drivers for chip access # # CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_SUN_UFLASH is not set # CONFIG_MTD_NORA is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_SC520CDP is not set -# CONFIG_MTD_NETSC520 is not set -# CONFIG_MTD_SBC_GXX is not set -# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set # CONFIG_MTD_IQ80310 is not set -# CONFIG_MTD_CFI_FLAGADM is not set -# CONFIG_MTD_ARMFLASH is not set +# CONFIG_MTD_PCI is not set # # Self-contained MTD device drivers # +# CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set # # Disk-On-Chip Device Drivers @@ -220,11 +249,17 @@ # Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y @@ -235,6 +270,13 @@ # Multi-device support (RAID and LVM) # # CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -258,6 +300,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -293,42 +336,75 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set CONFIG_NET_VENDOR_SMC=y # CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set # CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set CONFIG_SMC9194=y # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # # Wireless LAN (non-hamradio) # -# CONFIG_NET_RADIO is not set +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=m +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y # # Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set # @@ -347,8 +423,10 @@ # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set # CONFIG_NET_PCMCIA_RADIO is not set -CONFIG_PCMCIA_NETCARD=y # # Amateur Radio support @@ -378,20 +456,33 @@ CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set # CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set CONFIG_BLK_DEV_IDECS=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # # IDE chipset support/bugfixes # # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support @@ -402,6 +493,10 @@ # I2O device support # # CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # # ISDN subsystem @@ -412,6 +507,10 @@ # Input core support # # CONFIG_INPUT 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 # # Character devices @@ -419,21 +518,38 @@ CONFIG_VT=y # CONFIG_VT_CONSOLE is not set # CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set CONFIG_SERIAL_SA1100=y -# CONFIG_SERIAL_SA1100_OLD is not set CONFIG_SERIAL_SA1100_CONSOLE=y CONFIG_SA1100_DEFAULT_BAUDRATE=57600 +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=32 -CONFIG_UCB1200=y -CONFIG_TOUCHSCREEN_UCB1200=y -CONFIG_AUDIO_UCB1200=y -CONFIG_ADC_UCB1200=y -# CONFIG_TOUCHSCREEN_BITSY is not set -# CONFIG_PROFILER is not set # # I2C support @@ -441,37 +557,35 @@ # CONFIG_I2C is not set # -# Mice +# L3 serial bus support # -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set # -# Joysticks +# Other L3 adapters # +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set # -# Game port support -# - -# -# Gameport joysticks -# - -# -# Serial port support +# Mice # +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set # -# Serial port joysticks +# Joysticks # +# CONFIG_INPUT_GAMEPORT is not set # -# Parallel port joysticks +# Input core support is needed for gameports # # -# Parport support is needed for parallel port joysticks +# Input core support is needed for joysticks # # CONFIG_QIC02_TAPE is not set @@ -479,6 +593,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_SA1100_RTC=y @@ -509,44 +624,74 @@ # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_CRAMFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set CONFIG_RAMFS=y # CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -CONFIG_ROMFS_FS=y +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -562,6 +707,7 @@ # CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set @@ -573,15 +719,17 @@ # CONFIG_PC_KEYMAP=y # CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y # # Frame-buffer support # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set CONFIG_FB_SA1100=y -# CONFIG_FB_E1355 is not set +# CONFIG_FB_CYBER2000 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB2=y @@ -597,28 +745,49 @@ # Sound # CONFIG_SOUND=y -# CONFIG_SOUND_SA1100_SSP is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX 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_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_SA1100 is not set +# CONFIG_SOUND_UDA1341 is not set +# CONFIG_SOUND_ASSABET_UDA1341 is not set +# CONFIG_SOUND_H3600_UDA1341 is not set +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set # CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set # -# USB support +# Multimedia Capabilities Port drivers # -CONFIG_USB=y -CONFIG_USB_DEBUG=y +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set # -# Miscellaneous USB options +# USB support # -# CONFIG_USB_DEVICEFS is not set -# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB is not set # # USB Controllers @@ -626,15 +795,22 @@ # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set # CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set # # USB Device Class drivers # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -652,40 +828,83 @@ # CONFIG_USB_DC2XX is not set # CONFIG_USB_MDC800 is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set # # USB Multimedia devices # -# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set -# CONFIG_USB_NET1080 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set # # USB port drivers # +# CONFIG_USB_USS720 is not set # # USB Serial Converter support # # CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set # -# USB misc drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set # +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# # Kernel hacking # # CONFIG_NO_FRAME_POINTER is not set -CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set -CONFIG_MAGIC_SYSRQ=y +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN linux-2.4.18/arch/arm/def-configs/fortunet linux-2.4.19-pre5/arch/arm/def-configs/fortunet --- linux-2.4.18/arch/arm/def-configs/fortunet Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/def-configs/fortunet Sat Mar 30 22:55:37 2002 @@ -0,0 +1,593 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +CONFIG_ARCH_CLPS711X=y +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +CONFIG_ARCH_FORTUNET=y +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +CONFIG_CPU_ARM720T=y +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_ARM_THUMB is not set +# CONFIG_DISCONTIGMEM is not set + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_FPE_NWFPE is not set +CONFIG_FPE_FASTFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +CONFIG_MTD_FORTUNET=y +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +# CONFIG_INET is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET_AUNUDP is not set +# CONFIG_ECONET_NATIVE is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +# CONFIG_NETDEVICES is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Synchronous Serial Interface +# +# CONFIG_SSI is not set +# CONFIG_SSI_CLPS711X is not set +# CONFIG_SSI_JUNO is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +CONFIG_SERIAL_CLPS711X=y +CONFIG_SERIAL_CLPS711X_CONSOLE=y +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +# CONFIG_JFFS_PROC_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set +# CONFIG_DEBUG_LL_SER3 is not set diff -urN linux-2.4.18/arch/arm/def-configs/frodo linux-2.4.19-pre5/arch/arm/def-configs/frodo --- linux-2.4.18/arch/arm/def-configs/frodo Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/def-configs/frodo Sat Mar 30 22:55:37 2002 @@ -0,0 +1,618 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1100_FRODO=y +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_FPE_NWFPE is not set +CONFIG_FPE_FASTFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttySA0,9600 ramdisk_size=4096 root=/dev/ram idebus=33" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +# CONFIG_NETDEVICES is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=9600 +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN linux-2.4.18/arch/arm/def-configs/jornada720 linux-2.4.19-pre5/arch/arm/def-configs/jornada720 --- linux-2.4.18/arch/arm/def-configs/jornada720 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/def-configs/jornada720 Sat Mar 30 22:55:37 2002 @@ -1,11 +1,15 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # CONFIG_ARM=y # CONFIG_EISA is not set # CONFIG_SBUS is not set # CONFIG_MCA is not set CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set # # Code maturity level options @@ -23,24 +27,23 @@ # # System Type # +# CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_ARCA5K is not set # CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y -# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_SHARK is not set # # Archimedes/A5000 Implementations # - -# -# Archimedes/A5000 Implementations (select only ONE) -# # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set @@ -58,12 +61,18 @@ # # CONFIG_SA1100_ASSABET is not set # CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set # CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_CERF is not set -# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set # CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set # CONFIG_SA1100_FREEBIRD is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set CONFIG_SA1100_JORNADA720=y # CONFIG_SA1100_HUW_WEBPANEL is not set # CONFIG_SA1100_ITSY is not set @@ -72,70 +81,75 @@ # CONFIG_SA1100_OMNIMETER is not set # CONFIG_SA1100_PANGOLIN is not set # CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set # CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set # CONFIG_SA1100_PFS168 is not set # CONFIG_SA1100_VICTOR is not set # CONFIG_SA1100_XP860 is not set # CONFIG_SA1100_YOPY is not set CONFIG_SA1111=y +CONFIG_FORCE_MAX_ZONEORDER=9 # CONFIG_SA1100_USB is not set # CONFIG_SA1100_USB_NETLINK is not set # CONFIG_SA1100_USB_CHAR is not set -# CONFIG_SA1100_FREQUENCY_SCALE is not set -# CONFIG_SA1100_VOLTAGE_SCALE is not set +# CONFIG_REGISTERS is not set # # CLPS711X/EP721X Implementations # +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set # CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set - -# -# Processor Type -# # CONFIG_CPU_32v3 is not set CONFIG_CPU_32v4=y # CONFIG_CPU_ARM610 is not set # CONFIG_CPU_ARM710 is not set # CONFIG_CPU_ARM720T is not set # CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set # CONFIG_CPU_ARM1020 is not set # CONFIG_CPU_SA110 is not set CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set CONFIG_DISCONTIGMEM=y # # General setup # - -# -# Please ensure that you have read the help on the next option -# -# CONFIG_ANGELBOOT is not set # CONFIG_PCI is not set -# CONFIG_ISA is not set +CONFIG_ISA=y # CONFIG_ISA_DMA is not set +# CONFIG_CPU_FREQ is not set CONFIG_HOTPLUG=y # # PCMCIA/CardBus support # CONFIG_PCMCIA=y +# CONFIG_I82092 is not set # CONFIG_I82365 is not set # CONFIG_TCIC is not set # CONFIG_PCMCIA_CLPS6700 is not set CONFIG_PCMCIA_SA1100=y +# CONFIG_MERCURY_BACKPAQ is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_FPE_NWFPE=y -# CONFIG_FPE_FASTFPE is not set +CONFIG_FPE_FASTFPE=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=m @@ -145,10 +159,8 @@ # CONFIG_APM is not set # CONFIG_ARTHUR is not set CONFIG_CMDLINE="keepinitrd" -# CONFIG_PFS168_CMDLINE is not set # CONFIG_LEDS is not set -# CONFIG_ALIGNMENT_TRAP is not set -# CONFIG_UCB1200 is not set +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support @@ -159,63 +171,72 @@ # Memory Technology Devices (MTD) # CONFIG_MTD=y -# CONFIG_MTD_DEBUG is not set - -# -# Disk-On-Chip Device Drivers -# -# CONFIG_MTD_DOC1000 is not set -# CONFIG_MTD_DOC2000 is not set -# CONFIG_MTD_DOC2001 is not set -# CONFIG_MTD_DOCPROBE is not set - -# -# RAM/ROM Device Drivers -# -# CONFIG_MTD_PMC551 is not set -# CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_RAM is not set -# CONFIG_MTD_ROM is not set -# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_BOOTLDR_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set # -# Linearly Mapped Flash Device Drivers +# RAM/ROM/Flash chip drivers # CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set # CONFIG_MTD_AMDSTD is not set # CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# # CONFIG_MTD_PHYSMAP is not set # CONFIG_MTD_NORA is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_SC520CDP is not set -# CONFIG_MTD_SBC_MEDIAGX is not set -# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set CONFIG_MTD_SA1100=y +# CONFIG_MTD_H3600_BACKPAQ is not set # CONFIG_MTD_DC21285 is not set # CONFIG_MTD_IQ80310 is not set -# CONFIG_MTD_CSTM_CFI_JEDEC is not set -# CONFIG_MTD_JEDEC is not set -# CONFIG_MTD_MIXMEM is not set -# CONFIG_MTD_OCTAGON is not set -# CONFIG_MTD_VMAX is not set # -# NAND Flash Device Drivers +# Self-contained MTD device drivers # -# CONFIG_MTD_NAND is not set -# CONFIG_MTD_NAND_SPIA is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set # -# User Modules And Translation Layers +# NAND Flash Device Drivers # -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -# CONFIG_FTL is not set -# CONFIG_NFTL is not set +# CONFIG_MTD_NAND is not set # # Plug and Play configuration @@ -246,6 +267,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -258,7 +280,7 @@ # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set -# CONFIG_FILTER is not set +CONFIG_FILTER=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -282,10 +304,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# +# CONFIG_VLAN_8021Q is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -318,7 +337,6 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) @@ -329,18 +347,44 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PPP is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # # Wireless LAN (non-hamradio) # -# CONFIG_NET_RADIO is not set +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +CONFIG_WAVELAN=m +CONFIG_ARLAN=m +CONFIG_AIRONET4500=m +CONFIG_AIRONET4500_NONCS=m +# CONFIG_AIRONET4500_PNP is not set +# CONFIG_AIRONET4500_PCI is not set +# CONFIG_AIRONET4500_ISA is not set +# CONFIG_AIRONET4500_I365 is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_NET_WIRELESS=y # # Token Ring devices @@ -366,11 +410,11 @@ CONFIG_PCMCIA_NMCLAN=m CONFIG_PCMCIA_SMC91C92=m CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_PCMCIA_AXNET is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set CONFIG_NET_PCMCIA_RADIO=y # CONFIG_PCMCIA_RAYCS is not set -# CONFIG_PCMCIA_HERMES is not set # CONFIG_PCMCIA_NETWAVE is not set CONFIG_PCMCIA_WAVELAN=m CONFIG_AIRONET4500_CS=m @@ -384,10 +428,6 @@ # IrDA (infrared) support # CONFIG_IRDA=m - -# -# IrDA protocols -# CONFIG_IRLAN=m # CONFIG_IRNET is not set CONFIG_IRCOMM=m @@ -397,28 +437,19 @@ # # Infrared-port device drivers # - -# -# SIR device drivers -# # CONFIG_IRTTY_SIR is not set # CONFIG_IRPORT_SIR is not set - -# -# FIR device drivers -# +# CONFIG_DONGLE is not set +# CONFIG_USB_IRDA is not set # CONFIG_NSC_FIR is not set # CONFIG_WINBOND_FIR is not set # CONFIG_TOSHIBA_FIR is not set # CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set CONFIG_SA1100_FIR=m # -# Dongle support -# -# CONFIG_DONGLE is not set - -# # ATA/IDE/MFM/RLL support # CONFIG_IDE=m @@ -427,10 +458,6 @@ # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=m - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=m @@ -445,14 +472,10 @@ # CONFIG_BLK_DEV_COMMERIAL is not set # CONFIG_BLK_DEV_TIVO is not set CONFIG_BLK_DEV_IDECS=m -# CONFIG_BLK_DEV_IDECD is not set +CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set @@ -460,6 +483,9 @@ # CONFIG_IDEDMA_AUTO is not set # CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support @@ -483,7 +509,13 @@ # # Input core support # -# CONFIG_INPUT is not set +CONFIG_INPUT=y +# CONFIG_INPUT_KEYBDEV is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set # # Character devices @@ -493,19 +525,37 @@ CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set CONFIG_SERIAL_SA1100=y CONFIG_SERIAL_SA1100_CONSOLE=y CONFIG_SA1100_DEFAULT_BAUDRATE=115200 -# CONFIG_TOUCHSCREEN_UCB1200 is not set -# CONFIG_TOUCHSCREEN_BITSY is not set -CONFIG_PROFILER=m -# CONFIG_PFS168_SPI is not set -# CONFIG_PFS168_DTMF is not set -# CONFIG_PFS168_MISC is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=32 +# CONFIG_NEWTONKBD is not set # # I2C support @@ -513,6 +563,15 @@ # CONFIG_I2C is not set # +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# # Mice # # CONFIG_BUSMOUSE is not set @@ -524,11 +583,33 @@ # # Joysticks # -# CONFIG_JOYSTICK is not set - -# -# Input core support is needed for joysticks -# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set # CONFIG_QIC02_TAPE is not set # @@ -553,12 +634,13 @@ # # PCMCIA character devices # -CONFIG_PCMCIA_SERIAL_CS=m +# CONFIG_PCMCIA_SERIAL_CS is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set +# CONFIG_V4L2_DEV is not set # # File systems @@ -568,37 +650,45 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=m +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_CRAMFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=2 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set CONFIG_RAMFS=y -# CONFIG_ISO9660_FS is not set +CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +# CONFIG_DRIVERFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -608,6 +698,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=m CONFIG_NFS_V3=y # CONFIG_ROOT_NFS is not set @@ -616,8 +707,7 @@ CONFIG_SUNRPC=m CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -CONFIG_SMB_FS=m -# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set @@ -627,59 +717,22 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_SMB_NLS=y -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_UTF8 is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set # # Console drivers # CONFIG_PC_KEYMAP=y # CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y # # Frame-buffer support @@ -687,16 +740,17 @@ CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set # CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set CONFIG_FB_EPSON1356=y # CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_SA1100 is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y # CONFIG_FBCON_MFB is not set # CONFIG_FBCON_CFB2 is not set # CONFIG_FBCON_CFB4 is not set -CONFIG_FBCON_CFB8=y +# CONFIG_FBCON_CFB8 is not set CONFIG_FBCON_CFB16=y # CONFIG_FBCON_CFB24 is not set # CONFIG_FBCON_CFB32 is not set @@ -721,10 +775,10 @@ # Sound # CONFIG_SOUND=m -CONFIG_SOUND_UDA1341=m -# CONFIG_SOUND_SA1100_SSP is not set +# CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_CS4281 is not set # CONFIG_SOUND_ES1370 is not set @@ -733,28 +787,121 @@ # CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_MAESTRO3 is not set # CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX 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_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_SA1100=m +# CONFIG_SOUND_UDA1341 is not set +# CONFIG_SOUND_ASSABET_UDA1341 is not set +# CONFIG_SOUND_H3600_UDA1341 is not set +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set # CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_WAVEARTIST is not set # CONFIG_SOUND_TVMIXER is not set # +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# # USB support # # CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking # # CONFIG_NO_FRAME_POINTER is not set -CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set -# CONFIG_MAGIC_SYSRQ is not set # CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y # CONFIG_DEBUG_DC21285_PORT is not set # CONFIG_DEBUG_CLPS711X_UART2 is not set +# CONFIG_DEBUG_LL_SER3 is not set diff -urN linux-2.4.18/arch/arm/def-configs/shannon linux-2.4.19-pre5/arch/arm/def-configs/shannon --- linux-2.4.18/arch/arm/def-configs/shannon Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/def-configs/shannon Sat Mar 30 22:55:37 2002 @@ -0,0 +1,737 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_OBSOLETE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +CONFIG_SA1100_SHANNON=y +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_IQ80310 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +CONFIG_PCMCIA_SMC91C92=y +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_IDEDISK is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=9600 +# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set + +# +# Other L3 adapters +# +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_SERIO is not set + +# +# Joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +CONFIG_SA1100_WATCHDOG=y +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_FREEVXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# 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_SA1100=y +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set + +# +# Multimedia Capabilities Port drivers +# +CONFIG_MCP=y +CONFIG_MCP_SA1100=y +CONFIG_MCP_UCB1200=y +CONFIG_MCP_UCB1200_AUDIO=y +CONFIG_MCP_UCB1200_TS=y + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# + +# +# USB Device Class drivers +# + +# +# USB Human Interface Devices (HID) +# + +# +# USB Imaging devices +# + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# USB port drivers +# + +# +# USB Serial Converter support +# + +# +# USB Miscellaneous drivers +# + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_LL=y diff -urN linux-2.4.18/arch/arm/def-configs/system3 linux-2.4.19-pre5/arch/arm/def-configs/system3 --- linux-2.4.18/arch/arm/def-configs/system3 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/def-configs/system3 Sat Mar 30 22:55:37 2002 @@ -0,0 +1,977 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1100_PT_SYSTEM3=y +CONFIG_SA1111=y +CONFIG_FORCE_MAX_ZONEORDER=9 +CONFIG_SA1100_USB=m +CONFIG_SA1100_USB_NETLINK=m +CONFIG_SA1100_USB_CHAR=m + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_PM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="noinitrd root=/dev/mtdblock3" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_BOOTLDR_PARTS=m +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +CONFIG_SMC9194=m +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=m +# CONFIG_PCMCIA_NMCLAN is not set +CONFIG_PCMCIA_SMC91C92=m +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +# CONFIG_IRNET is not set +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set +# CONFIG_IRDA_OPTIONS is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=m + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=38400 +CONFIG_SERIAL_8250=m +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_SA1100_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +CONFIG_USB_OHCI_SA1111=m + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN linux-2.4.18/arch/arm/kernel/Makefile linux-2.4.19-pre5/arch/arm/kernel/Makefile --- linux-2.4.18/arch/arm/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/Makefile Sat Mar 30 22:55:37 2002 @@ -42,7 +42,8 @@ no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ - $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) + $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \ + $(CONFIG_ARCH_MX1ADS) ifneq ($(findstring y,$(no-irq-arch)),y) obj-y += irq-arch.o diff -urN linux-2.4.18/arch/arm/kernel/armksyms.c linux-2.4.19-pre5/arch/arm/kernel/armksyms.c --- linux-2.4.18/arch/arm/kernel/armksyms.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/armksyms.c Sat Mar 30 22:55:37 2002 @@ -77,12 +77,12 @@ extern void __do_softirq(void); #define EXPORT_SYMBOL_ALIAS(sym,orig) \ - const char __kstrtab_##sym##[] \ + const char __kstrtab_##sym[] \ __attribute__((section(".kstrtab"))) = \ __MODULE_STRING(sym); \ const struct module_symbol __ksymtab_##sym \ __attribute__((section("__ksymtab"))) = \ - { (unsigned long)&##orig, __kstrtab_##sym }; + { (unsigned long)&orig, __kstrtab_##sym }; /* * floating point math emulator support. @@ -115,7 +115,9 @@ EXPORT_SYMBOL(system_rev); EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); +#ifdef CONFIG_DEBUG_BUGVERBOSE EXPORT_SYMBOL(__bug); +#endif EXPORT_SYMBOL(__bad_xchg); EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); @@ -229,6 +231,7 @@ EXPORT_SYMBOL_NOVERS(__udivmoddi4); EXPORT_SYMBOL_NOVERS(__udivsi3); EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL_NOVERS(abort); /* bitops */ EXPORT_SYMBOL(set_bit); diff -urN linux-2.4.18/arch/arm/kernel/bios32.c linux-2.4.19-pre5/arch/arm/kernel/bios32.c --- linux-2.4.18/arch/arm/kernel/bios32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/bios32.c Sat Mar 30 22:55:37 2002 @@ -153,8 +153,7 @@ } /* - * PCI IDE controllers use non-standard I/O port - * decoding, respect it. + * PCI IDE controllers use non-standard I/O port decoding, respect it. */ static void __init pci_fixup_ide_bases(struct pci_dev *dev) { @@ -181,9 +180,82 @@ pci_write_config_dword(dev, 0x40, 0x80000000); } +/* + * The CY82C693 needs some rather major fixups to ensure that it does + * the right thing. Idea from the Alpha people, with a few additions. + * + * We ensure that the IDE base registers are set to 1f0/3f4 for the + * primary bus, and 170/374 for the secondary bus. Also, hide them + * from the PCI subsystem view as well so we won't try to perform + * our own auto-configuration on them. + * + * In addition, we ensure that the PCI IDE interrupts are routed to + * IRQ 14 and IRQ 15 respectively. + * + * The above gets us to a point where the IDE on this device is + * functional. However, The CY82C693U _does not work_ in bus + * master mode without locking the PCI bus solid. + */ +static void __init pci_fixup_cy82c693(struct pci_dev *dev) +{ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u32 base0, base1; + + if (dev->class & 0x80) { /* primary */ + base0 = 0x1f0; + base1 = 0x3f4; + } else { /* secondary */ + base0 = 0x170; + base1 = 0x374; + } + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + base0 | PCI_BASE_ADDRESS_SPACE_IO); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, + base1 | PCI_BASE_ADDRESS_SPACE_IO); + + dev->resource[0].start = 0; + dev->resource[0].end = 0; + dev->resource[0].flags = 0; + + dev->resource[1].start = 0; + dev->resource[1].end = 0; + dev->resource[1].flags = 0; + } else if (PCI_FUNC(dev->devfn) == 0) { + /* + * Setup IDE IRQ routing. + */ + pci_write_config_byte(dev, 0x4b, 14); + pci_write_config_byte(dev, 0x4c, 15); + + /* + * Disable FREQACK handshake, enable USB. + */ + pci_write_config_byte(dev, 0x4d, 0x41); + + /* + * Enable PCI retry, and PCI post-write buffer. + */ + pci_write_config_byte(dev, 0x44, 0x17); + + /* + * Enable ISA master and DMA post write buffering. + */ + pci_write_config_byte(dev, 0x45, 0x03); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, + PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, + pci_fixup_cy82c693 + }, { + PCI_FIXUP_HEADER, + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + pci_fixup_dec21142 + }, { + PCI_FIXUP_HEADER, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_dec21285 }, { @@ -198,10 +270,6 @@ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases - }, { - PCI_FIXUP_HEADER, - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - pci_fixup_dec21142 }, { 0 } }; diff -urN linux-2.4.18/arch/arm/kernel/calls.S linux-2.4.19-pre5/arch/arm/kernel/calls.S --- linux-2.4.18/arch/arm/kernel/calls.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/calls.S Sat Mar 30 22:55:37 2002 @@ -236,6 +236,27 @@ .long SYMBOL_NAME(sys_mincore) /* 220 */ .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* Security */ + .long SYMBOL_NAME(sys_gettid) +/* 225 */ .long SYMBOL_NAME(sys_readahead) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_setxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_lsetxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_fsetxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_getxattr */ +/* 230 */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_lgetxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_fgetxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_listxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_llistxattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_flistxattr */ +/* 235 */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_removexattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_lremovexattr */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_fremovexattr */ + .long SYMBOL_NAME(sys_tkill) + /* + * Please check 2.5 _before_ adding calls here, + * and copy changes to rmk@arm.linux.org.uk. Thanks. + */ __syscall_end: .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 diff -urN linux-2.4.18/arch/arm/kernel/compat.c linux-2.4.19-pre5/arch/arm/kernel/compat.c --- linux-2.4.18/arch/arm/kernel/compat.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/compat.c Sat Mar 30 22:55:37 2002 @@ -89,10 +89,12 @@ } #ifdef CONFIG_FOOTBRIDGE - tag = tag_next(tag); - tag->hdr.tag = ATAG_MEMCLK; - tag->hdr.size = tag_size(tag_memclk); - tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285; + if (params->u1.s.mem_fclk_21285) { + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEMCLK; + tag->hdr.size = tag_size(tag_memclk); + tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285; + } #endif #ifdef CONFIG_ARCH_ACORN diff -urN linux-2.4.18/arch/arm/kernel/debug-armv.S linux-2.4.19-pre5/arch/arm/kernel/debug-armv.S --- linux-2.4.18/arch/arm/kernel/debug-armv.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/debug-armv.S Sat Mar 30 22:55:37 2002 @@ -164,28 +164,49 @@ .endm #elif defined(CONFIG_ARCH_SA1100) + .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x80000000 @ physical base address movne \rx, #0xf8000000 @ virtual address - @add \rx, \rx, #0x00050000 @ Ser3 - add \rx, \rx, #0x00010000 @ Ser1 + + @ We probe for the active serial port here, coherently with + @ the comment in include/asm-arm/arch-sa1100/uncompress.h. + @ We assume r1 can be clobbered. + + @ see if Ser3 is active + add \rx, \rx, #0x00050000 + ldr r1, [\rx, #UTCR3] + tst r1, #UTCR3_TXE + + @ if Ser3 is inactive, then try Ser1 + addeq \rx, \rx, #(0x00010000 - 0x00050000) + ldreq r1, [\rx, #UTCR3] + tsteq r1, #UTCR3_TXE + + @ if Ser1 is inactive, then try Ser2 + addeq \rx, \rx, #(0x00030000 - 0x00010000) + ldreq r1, [\rx, #UTCR3] + tsteq r1, #UTCR3_TXE + + @ if all ports are inactive, then there is nothing we can do + moveq pc, lr .endm .macro senduart,rd,rx - str \rd, [\rx, #0x14] @ UTDR + str \rd, [\rx, #UTDR] .endm .macro waituart,rd,rx -1001: ldr \rd, [\rx, #0x20] @ UTSR1 - tst \rd, #1 << 2 @ UTSR1_TNF +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TNF beq 1001b .endm .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x20] @ UTSR1 - tst \rd, #1 << 0 @ UTSR1_TBY +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TBY bne 1001b .endm diff -urN linux-2.4.18/arch/arm/kernel/dma-arc.c linux-2.4.19-pre5/arch/arm/kernel/dma-arc.c --- linux-2.4.18/arch/arm/kernel/dma-arc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/dma-arc.c Sat Mar 30 22:55:37 2002 @@ -96,7 +96,7 @@ /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ extern unsigned int fdc1772_fdc_int_done; - * Explicit! If the int done is 0 then 1 int to go */ + /* Explicit! If the int done is 0 then 1 int to go */ return (fdc1772_fdc_int_done==0)?1:0; } diff -urN linux-2.4.18/arch/arm/kernel/dma.c linux-2.4.19-pre5/arch/arm/kernel/dma.c --- linux-2.4.18/arch/arm/kernel/dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/dma.c Sat Mar 30 22:55:37 2002 @@ -275,6 +275,8 @@ #endif +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); EXPORT_SYMBOL(enable_dma); EXPORT_SYMBOL(disable_dma); EXPORT_SYMBOL(set_dma_addr); diff -urN linux-2.4.18/arch/arm/kernel/entry-armv.S linux-2.4.19-pre5/arch/arm/kernel/entry-armv.S --- linux-2.4.18/arch/arm/kernel/entry-armv.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/entry-armv.S Sat Mar 30 22:55:37 2002 @@ -454,6 +454,31 @@ .macro irq_prio_table .endm +#elif defined(CONFIG_ARCH_MX1ADS) + + .macro disable_fiq + .endm +#define AITC_NIVECSR 0x40 + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =IO_ADDRESS(MX1ADS_AITC_BASE) + @ Load offset & priority of the highest priority + @ interrupt pending. + ldr \irqnr, [\irqstat, #AITC_NIVECSR] + @ Shift off the priority leaving the offset or + @ "interrupt number" + mov \irqnr, \irqnr, lsr #16 + ldr \irqstat, =1 @ dummy compare + ldr \base, =0xFFFF // invalid interrupt + cmp \irqnr, \base + bne 1001f + ldr \irqstat, =0 +1001: + tst \irqstat, #1 @ to make the condition code = TRUE + .endm + + .macro irq_prio_table + .endm + #elif defined(CONFIG_ARCH_CLPS711X) #include @@ -643,14 +668,14 @@ mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT biceq r9, r9, #I_BIT @ previously - mov r0, r2 + mov r0, r2 @ *** remove once everyones in sync /* * This routine must not corrupt r9 */ #ifdef MULTI_CPU - ldr r2, .LCprocfns @ pass r0, r3 to + ldr r4, .LCprocfns @ pass r0, r3 to mov lr, pc @ processor code - ldr pc, [r2] @ call processor specific code + ldr pc, [r4] @ call processor specific code #else bl cpu_data_abort #endif @@ -747,15 +772,16 @@ stmia sp, {r0 - r12} @ save r0 - r12 ldr r7, .LCabt add r5, sp, #S_PC - ldmia r7, {r0, r3, r4} @ Get USR pc, cpsr - stmia r5, {r0, r3, r4} @ Save USR pc, cpsr, old_r0 + ldmia r7, {r2 - r4} @ Get USR pc, cpsr + stmia r5, {r2 - r4} @ Save USR pc, cpsr, old_r0 stmdb r5, {sp, lr}^ alignment_trap r7, r7, __temp_abt zero_fp + mov r0, r2 @ remove once everyones in sync #ifdef MULTI_CPU - ldr r2, .LCprocfns @ pass r0, r3 to + ldr r4, .LCprocfns @ pass r0, r3 to mov lr, pc @ processor code - ldr pc, [r2] @ call processor specific code + ldr pc, [r4] @ call processor specific code #else bl cpu_data_abort #endif diff -urN linux-2.4.18/arch/arm/kernel/init_task.c linux-2.4.19-pre5/arch/arm/kernel/init_task.c --- linux-2.4.18/arch/arm/kernel/init_task.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/init_task.c Sat Mar 30 22:55:37 2002 @@ -9,7 +9,6 @@ #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; diff -urN linux-2.4.18/arch/arm/kernel/process.c linux-2.4.19-pre5/arch/arm/kernel/process.c --- linux-2.4.18/arch/arm/kernel/process.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/process.c Sat Mar 30 22:55:37 2002 @@ -24,9 +24,8 @@ #include #include -#include -#include #include +#include #include /* diff -urN linux-2.4.18/arch/arm/kernel/semaphore.c linux-2.4.19-pre5/arch/arm/kernel/semaphore.c --- linux-2.4.18/arch/arm/kernel/semaphore.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/arm/kernel/semaphore.c Sat Mar 30 22:55:37 2002 @@ -210,7 +210,6 @@ mov r0, ip bl __up ldmfd sp!, {r0 - r3, pc}^ - "); #else @@ -248,7 +247,6 @@ mov r0, ip bl __up ldmfd sp!, {r0 - r3, pc} - "); #endif diff -urN linux-2.4.18/arch/arm/kernel/signal.c linux-2.4.19-pre5/arch/arm/kernel/signal.c --- linux-2.4.18/arch/arm/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/signal.c Sat Mar 30 22:55:37 2002 @@ -344,7 +344,7 @@ /* * This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp)) + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) sp = current->sas_ss_sp + current->sas_ss_size; /* diff -urN linux-2.4.18/arch/arm/kernel/traps.c linux-2.4.19-pre5/arch/arm/kernel/traps.c --- linux-2.4.18/arch/arm/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/kernel/traps.c Sat Mar 30 22:55:37 2002 @@ -25,8 +25,6 @@ #include #include -#include -#include #include #include #include @@ -53,7 +51,7 @@ */ static int verify_stack(unsigned long sp) { - if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory) + if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0)) return -EFAULT; return 0; @@ -62,13 +60,15 @@ /* * Dump out the contents of some memory nicely... */ -void dump_mem(unsigned long bottom, unsigned long top) +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) { unsigned long p = bottom & ~31; int i; + printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); + for (p = bottom & ~31; p < top;) { - printk("%08lx: ", p); + printk("%04lx: ", p & 0xffff); for (i = 0; i < 8; i++, p += 4) { unsigned int val; @@ -79,21 +79,11 @@ __get_user(val, (unsigned long *)p); printk("%08x ", val); } - if (i == 3) - printk(" "); } printk ("\n"); } } -/* - * 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. - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define MODULE_RANGE (8*1024*1024) - static void dump_instr(struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); @@ -102,7 +92,7 @@ int i; printk("Code: "); - for (i = -2; i < 3; i++) { + for (i = -4; i < 1; i++) { unsigned int val, bad; if (thumb) @@ -122,8 +112,7 @@ static void dump_stack(struct task_struct *tsk, unsigned long sp) { - printk("Stack:\n"); - dump_mem(sp - 16, 8192+(unsigned long)tsk); + dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk); } static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) @@ -289,10 +278,9 @@ handler[reason], processor_modes[proc_mode]); /* - * We need to switch to kernel mode so that we can - * use __get_user to safely read from kernel space. - * Note that we now dump the code first, just in case - * the backtrace kills us. + * We need to switch to kernel mode so that we can use __get_user + * to safely read from kernel space. Note that we now dump the + * code first, just in case the backtrace kills us. */ fs = get_fs(); set_fs(KERNEL_DS); @@ -301,10 +289,8 @@ * Dump out the vectors and stub routines. Maybe a better solution * would be to dump them out only if we detect that they are corrupted. */ - printk(KERN_CRIT "Vectors:\n"); - dump_mem(vectors, 0x40); - printk(KERN_CRIT "Stubs:\n"); - dump_mem(vectors + 0x200, 0x4b8); + dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40); + dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8); set_fs(fs); @@ -528,11 +514,6 @@ void abort(void) { - void *lr = __builtin_return_address(0); - - printk(KERN_CRIT "abort() called from %p! (Please " - "report to rmk@arm.linux.org.uk)\n", lr); - BUG(); /* if that doesn't kill us, halt */ diff -urN linux-2.4.18/arch/arm/lib/ecard.S linux-2.4.19-pre5/arch/arm/lib/ecard.S --- linux-2.4.18/arch/arm/lib/ecard.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/lib/ecard.S Sat Mar 30 22:55:37 2002 @@ -12,7 +12,7 @@ #include #include -#if defined(CONFIG_CPU_26) +#ifdef CONFIG_CPU_26 #define CPSR2SPSR(rt) #else #define CPSR2SPSR(rt) \ diff -urN linux-2.4.18/arch/arm/lib/getuser.S linux-2.4.19-pre5/arch/arm/lib/getuser.S --- linux-2.4.18/arch/arm/lib/getuser.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/lib/getuser.S Sat Mar 30 22:55:37 2002 @@ -80,8 +80,9 @@ /* fall through */ -__get_user_bad: +__get_user_bad_8: mov r2, #0 +__get_user_bad: mov r1, #0 mov r0, #-14 mov pc, lr @@ -91,6 +92,6 @@ .long 2b, __get_user_bad .long 3b, __get_user_bad .long 4b, __get_user_bad - .long 5b, __get_user_bad - .long 6b, __get_user_bad + .long 5b, __get_user_bad_8 + .long 6b, __get_user_bad_8 .previous diff -urN linux-2.4.18/arch/arm/lib/io-acorn.S linux-2.4.19-pre5/arch/arm/lib/io-acorn.S --- linux-2.4.18/arch/arm/lib/io-acorn.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/lib/io-acorn.S Sat Mar 30 22:55:37 2002 @@ -58,7 +58,7 @@ @ Proto : void memc_write(int register, int value); @ Returns: nothing -#if defined(CONFIG_CPU_26) +#ifdef CONFIG_CPU_26 ENTRY(memc_write) cmp r0, #7 RETINSTR(movgt,pc,lr) diff -urN linux-2.4.18/arch/arm/lib/io-shark.c linux-2.4.19-pre5/arch/arm/lib/io-shark.c --- linux-2.4.18/arch/arm/lib/io-shark.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/lib/io-shark.c Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/io-shark.c * - * by Alexander Schulz + * by Alexander Schulz * * derived from: * linux/arch/arm/lib/io-ebsa.S diff -urN linux-2.4.18/arch/arm/lib/strrchr.S linux-2.4.19-pre5/arch/arm/lib/strrchr.S --- linux-2.4.18/arch/arm/lib/strrchr.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/lib/strrchr.S Sat Mar 30 22:55:37 2002 @@ -18,7 +18,7 @@ mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 - moveq r3, r0 + subeq r3, r0, #1 teq r2, #0 bne 1b mov r0, r3 diff -urN linux-2.4.18/arch/arm/mach-clps711x/Makefile linux-2.4.19-pre5/arch/arm/mach-clps711x/Makefile --- linux-2.4.18/arch/arm/mach-clps711x/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/Makefile Sat Mar 30 22:55:37 2002 @@ -0,0 +1,30 @@ +# +# 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). + +USE_STANDARD_AS_RULE := true + +O_TARGET := clps711x.o + +# Object file lists. + +obj-y := irq.o mm.o time.o +obj-m := +obj-n := +obj- := + +export-objs := leds-p720t.o + +obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o +obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o +obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o +obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o +obj-$(CONFIG_ARCH_P720T) += p720t.o +obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o +leds-$(CONFIG_ARCH_P720T) += p720t-leds.o +obj-$(CONFIG_LEDS) += $(leds-y) + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/arm/mach-clps711x/autcpu12.c linux-2.4.19-pre5/arch/arm/mach-clps711x/autcpu12.c --- linux-2.4.18/arch/arm/mach-clps711x/autcpu12.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/autcpu12.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,72 @@ +/* + * linux/arch/arm/mach-clps711x/autcpu12.c + * + * (c) 2001 Thomas Gleixner, autronix automation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern void clps711x_map_io(void); +extern void clps711x_init_irq(void); + +/* + * The on-chip registers are given a size of 1MB so that a section can + * be used to map them; this saves a page table. This is the place to + * add mappings for ROM, expansion memory, PCMCIA, etc. (if static + * mappings are chosen for those areas). + * +*/ + +static struct map_desc autcpu12_io_desc[] __initdata = { + /* virtual, physical, length, domain, r, w, c, b */ + /* memory-mapped extra io and CS8900A Ethernet chip */ + /* ethernet chip */ + { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 1, 1, 0, 0 }, + + LAST_DESC +}; + +void __init autcpu12_map_io(void) +{ + clps711x_map_io(); + iotable_init(autcpu12_io_desc); +} + +MACHINE_START(AUTCPU12, "autronix autcpu12") + MAINTAINER("Thomas Gleixner") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0020000) + MAPIO(autcpu12_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + diff -urN linux-2.4.18/arch/arm/mach-clps711x/cdb89712.c linux-2.4.19-pre5/arch/arm/mach-clps711x/cdb89712.c --- linux-2.4.18/arch/arm/mach-clps711x/cdb89712.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/cdb89712.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,74 @@ +/* + * linux/arch/arm/mach-clps711x/cdb89712.c + * + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +/* + * Map the CS89712 Ethernet port. That should be moved to the + * ethernet driver, perhaps. + */ +static struct map_desc cdb89712_io_desc[] __initdata = { + { ETHER_BASE, ETHER_START, ETHER_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static void __init +fixup_cdb89712(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +} + +static void __init cdb89712_map_io(void) +{ + clps711x_map_io(); + iotable_init(cdb89712_io_desc); +} + +MACHINE_START(CDB89712, "Cirrus-CDB89712") + MAINTAINER("Ray Lehtiniemi") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_cdb89712) + MAPIO(cdb89712_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + +static int cdb89712_hw_init(void) +{ + return 0; +} + +__initcall(cdb89712_hw_init); + diff -urN linux-2.4.18/arch/arm/mach-clps711x/clep7312.c linux-2.4.19-pre5/arch/arm/mach-clps711x/clep7312.c --- linux-2.4.18/arch/arm/mach-clps711x/clep7312.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/clep7312.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/mach-clps711x/clep7312.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +static void __init +fixup_clep7312(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->end = 0xc0FFFFFF; + mi->bank[0].start = 0xc0000000; + mi->bank[0].size = 0x01000000; + mi->bank[0].node = 0; +} + + +MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312") + MAINTAINER("Nobody") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_clep7312) + MAPIO(clps711x_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + diff -urN linux-2.4.18/arch/arm/mach-clps711x/dma.c linux-2.4.19-pre5/arch/arm/mach-clps711x/dma.c --- linux-2.4.18/arch/arm/mach-clps711x/dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/dma.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mach-clps711x/dma.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +void __init arch_dma_init(dma_t *dma) +{ +} diff -urN linux-2.4.18/arch/arm/mach-clps711x/edb7211-arch.c linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-arch.c --- linux-2.4.18/arch/arm/mach-clps711x/edb7211-arch.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-arch.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,59 @@ +/* + * linux/arch/arm/mach-clps711x/arch-edb7211.c + * + * Copyright (C) 2000, 2001 Blue Mug, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include + +extern void clps711x_init_irq(void); +extern void edb7211_map_io(void); + +static void __init +fixup_edb7211(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + /* + * Bank start addresses are not present in the information + * passed in from the boot loader. We could potentially + * detect them, but instead we hard-code them. + * + * Banks sizes _are_ present in the param block, but we're + * not using that information yet. + */ + mi->bank[0].start = 0xc0000000; + mi->bank[0].size = 8*1024*1024; + mi->bank[0].node = 0; + mi->bank[1].start = 0xc1000000; + mi->bank[1].size = 8*1024*1024; + mi->bank[1].node = 1; + mi->nr_banks = 2; +} + +MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)") + MAINTAINER("Jon McClintock") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0020100) /* 0xc0000000 - 0xc001ffff can be video RAM */ + FIXUP(fixup_edb7211) + MAPIO(edb7211_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END diff -urN linux-2.4.18/arch/arm/mach-clps711x/edb7211-mm.c linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-mm.c --- linux-2.4.18/arch/arm/mach-clps711x/edb7211-mm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-mm.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,74 @@ +/* + * linux/arch/arm/mach-clps711x/mm.c + * + * Extra MM routines for the EDB7211 board + * + * Copyright (C) 2000, 2001 Blue Mug, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include + +#include + +#define MB1 1048576 /* one megabyte == size of an MMU section */ + +extern void clps711x_map_io(void); + +/* + * The on-chip registers are given a size of 1MB so that a section can + * be used to map them; this saves a page table. This is the place to + * add mappings for ROM, expansion memory, PCMCIA, etc. (if static + * mappings are chosen for those areas). + * + * Here is a physical memory map (to be fleshed out later): + * + * Physical Address Size Description + * ----------------- ----- --------------------------------- + * c0000000-c001ffff 128KB reserved for video RAM [1] + * c0020000-c0023fff 16KB parameters (see Documentation/arm/Setup) + * c0024000-c0027fff 16KB swapper_pg_dir (task 0 page directory) + * c0028000-... kernel image (TEXTADDR) + * + * [1] Unused pages should be given back to the VM; they are not yet. + * The parameter block should also be released (not sure if this + * happens). + */ +static struct map_desc edb7211_io_desc[] __initdata = { + /* virtual, physical, length, domain, r, w, c, b */ + + /* memory-mapped extra keyboard row and CS8900A Ethernet chip */ + { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 1, 1, 0, 0 }, + { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 1, 1, 0, 0 }, + + /* flash banks */ + { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, + { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, + + LAST_DESC +}; + +void __init edb7211_map_io(void) +{ + clps711x_map_io(); + iotable_init(edb7211_io_desc); +} + diff -urN linux-2.4.18/arch/arm/mach-clps711x/fortunet.c linux-2.4.19-pre5/arch/arm/mach-clps711x/fortunet.c --- linux-2.4.18/arch/arm/mach-clps711x/fortunet.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/fortunet.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,81 @@ +/* + * linux/arch/arm/mach-clps711x/fortunet.c + * + * Derived from linux/arch/arm/mach-integrator/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void clps711x_map_io(void); +extern void clps711x_init_irq(void); + +struct meminfo memmap = { 1, 0xC1000000, {{0xC0000000,0x01000000,0}}}; + +typedef struct tag_IMAGE_PARAMS +{ + int ramdisk_ok; + int ramdisk_address; + int ramdisk_size; + int ram_size; + int extra_param_type; + int extra_param_ptr; + int command_line; +} IMAGE_PARAMS; + +#define IMAGE_PARAMS_PHYS 0xC01F0000 + +static void __init +fortunet_fixup(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + IMAGE_PARAMS *ip; + ip = (IMAGE_PARAMS *)__phys_to_virt(IMAGE_PARAMS_PHYS); + *cmdline = (char *)__phys_to_virt(ip->command_line); +#ifdef CONFIG_BLK_DEV_INITRD + if(ip->ramdisk_ok) + { + initrd_start = __phys_to_virt(ip->ramdisk_address); + initrd_end = initrd_start + ip->ramdisk_size; + } +#endif + memmap.bank[0].size = ip->ram_size; + memmap.end = ip->ram_size+0xC0000000; + *mi = memmap; +} + +MACHINE_START(FORTUNET, "ARM-FortuNet") + MAINTAINER("FortuNet Inc.") + BOOT_MEM(0xc0000000, 0x80000000, 0xf0000000) + BOOT_PARAMS(0x00000000) + FIXUP(fortunet_fixup) + MAPIO(clps711x_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END diff -urN linux-2.4.18/arch/arm/mach-clps711x/irq.c linux-2.4.19-pre5/arch/arm/mach-clps711x/irq.c --- linux-2.4.18/arch/arm/mach-clps711x/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/irq.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,138 @@ +/* + * linux/arch/arm/mach-clps711x/irq.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include +#include +#include +#include + +#include + +static void mask_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 &= ~(1 << irq); + clps_writel(intmr1, INTMR1); +} + +static void mask_ack_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 &= ~(1 << irq); + clps_writel(intmr1, INTMR1); + + switch (irq) { + case IRQ_CSINT: clps_writel(0, COEOI); break; + case IRQ_TC1OI: clps_writel(0, TC1EOI); break; + case IRQ_TC2OI: clps_writel(0, TC2EOI); break; + case IRQ_RTCMI: clps_writel(0, RTCEOI); break; + case IRQ_TINT: clps_writel(0, TEOI); break; + case IRQ_UMSINT: clps_writel(0, UMSEOI); break; + } +} + +static void unmask_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 |= 1 << irq; + clps_writel(intmr1, INTMR1); +} + +static void mask_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 &= ~(1 << (irq - 16)); + clps_writel(intmr2, INTMR2); +} + +static void mask_ack_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 &= ~(1 << (irq - 16)); + clps_writel(intmr2, INTMR2); + + switch (irq) { + case IRQ_KBDINT: clps_writel(0, KBDEOI); break; + } +} + +static void unmask_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 |= 1 << (irq - 16); + clps_writel(intmr2, INTMR2); +} + +void __init clps711x_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + if (INT1_IRQS & (1 << i)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = (INT1_ACK_IRQS & (1 << i)) ? + mask_ack_irq_int1 : + mask_irq_int1; + irq_desc[i].mask = mask_irq_int1; + irq_desc[i].unmask = unmask_irq_int1; + } + if (INT2_IRQS & (1 << i)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = (INT2_ACK_IRQS & (1 << i)) ? + mask_ack_irq_int2 : + mask_irq_int2; + irq_desc[i].mask = mask_irq_int2; + irq_desc[i].unmask = unmask_irq_int2; + } + } + + /* + * Disable interrupts + */ + clps_writel(0, INTMR1); + clps_writel(0, INTMR2); + + /* + * Clear down any pending interrupts + */ + clps_writel(0, COEOI); + clps_writel(0, TC1EOI); + clps_writel(0, TC2EOI); + clps_writel(0, RTCEOI); + clps_writel(0, TEOI); + clps_writel(0, UMSEOI); + clps_writel(0, SYNCIO); + clps_writel(0, KBDEOI); +} diff -urN linux-2.4.18/arch/arm/mach-clps711x/mm.c linux-2.4.19-pre5/arch/arm/mach-clps711x/mm.c --- linux-2.4.18/arch/arm/mach-clps711x/mm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/mm.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,70 @@ +/* + * linux/arch/arm/mach-clps711x/mm.c + * + * Generic MM setup for the CLPS711x-based machines. + * + * Copyright (C) 2001 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if 0 //def CONFIG_DISCONTIGMEM + +/* + * The assumption of maximum 4 discontiguous memory banks is present + * in several places in the ARM kernel, including the parameter block + * (this affects boot loaders, too). Banks do not necessarily + * correspond 1:1 with NUMA nodes, although they usually will, + * especially if they are widely discontiguous. + * + * - note that the parameter block is depreciated for new implementations + * - also note that discontig_node_data is actually used + * -- rmk + */ + +static bootmem_data_t node_bootmem_data[4]; + +pg_data_t clps711x_node_data[4] = { + { bdata: &node_bootmem_data[0] }, + { bdata: &node_bootmem_data[1] }, + { bdata: &node_bootmem_data[2] }, + { bdata: &node_bootmem_data[3] }, +}; + +#endif + +/* + * This maps the generic CLPS711x registers + */ +static struct map_desc clps711x_io_desc[] __initdata = { + { CLPS7111_VIRT_BASE, CLPS7111_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 }, + LAST_DESC +}; + +void __init clps711x_map_io(void) +{ + iotable_init(clps711x_io_desc); +} diff -urN linux-2.4.18/arch/arm/mach-clps711x/p720t-leds.c linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t-leds.c --- linux-2.4.18/arch/arm/mach-clps711x/p720t-leds.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t-leds.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/mach-clps711x/leds.c + * + * Integrator LED control routines + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +static void p720t_leds_event(led_event_t ledevt) +{ + unsigned long flags; + u32 pddr; + + local_irq_save(flags); + switch(ledevt) { + case led_idle_start: + break; + + case led_idle_end: + break; + + case led_timer: + pddr = clps_readb(PDDR); + clps_writeb(pddr ^ 1, PDDR); + break; + + default: + break; + } + + local_irq_restore(flags); +} + +static int __init leds_init(void) +{ + if (machine_is_p720t()) + leds_event = p720t_leds_event; + + return 0; +} + +__initcall(leds_init); diff -urN linux-2.4.18/arch/arm/mach-clps711x/p720t.c linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t.c --- linux-2.4.18/arch/arm/mach-clps711x/p720t.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,118 @@ +/* + * linux/arch/arm/mach-clps711x/p720t.c + * + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +/* + * Map the P720T system PLD. It occupies two address spaces: + * SYSPLD_PHYS_BASE and SYSPLD_PHYS_BASE + 0x00400000 + * We map both here. + */ +static struct map_desc p720t_io_desc[] __initdata = { + { SYSPLD_VIRT_BASE, SYSPLD_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 }, + { 0xfe400000, 0x10400000, 1048576, DOMAIN_IO, 0, 1 }, + LAST_DESC +}; + +static void __init +fixup_p720t(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + struct tag *tag = (struct tag *)params; + + /* + * Our bootloader doesn't setup any tags (yet). + */ + if (tag->hdr.tag != ATAG_CORE) { + tag->hdr.tag = ATAG_CORE; + tag->hdr.size = tag_size(tag_core); + tag->u.core.flags = 0; + tag->u.core.pagesize = PAGE_SIZE; + tag->u.core.rootdev = 0x0100; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEM; + tag->hdr.size = tag_size(tag_mem32); + tag->u.mem.size = 4096; + tag->u.mem.start = PHYS_OFFSET; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_NONE; + tag->hdr.size = 0; + } +} + +static void __init p720t_map_io(void) +{ + clps711x_map_io(); + iotable_init(p720t_io_desc); +} + +MACHINE_START(P720T, "ARM-Prospector720T") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_p720t) + MAPIO(p720t_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + +static int p720t_hw_init(void) +{ + /* + * Power down as much as possible in case we don't + * have the drivers loaded. + */ + PLD_LCDEN = 0; + PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); + + PLD_KBD = 0; + PLD_IO = 0; + PLD_IRDA = 0; + PLD_CODEC = 0; + PLD_TCH = 0; + PLD_SPI = 0; +#ifndef CONFIG_DEBUG_LL + PLD_COM2 = 0; + PLD_COM1 = 0; +#endif + + return 0; +} + +__initcall(p720t_hw_init); + diff -urN linux-2.4.18/arch/arm/mach-clps711x/time.c linux-2.4.19-pre5/arch/arm/mach-clps711x/time.c --- linux-2.4.18/arch/arm/mach-clps711x/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-clps711x/time.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,54 @@ +/* + * linux/arch/arm/mach-clps711x/time.c + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include +#include +#include + +extern unsigned long (*gettimeoffset)(void); + +/* + * gettimeoffset() returns time since last timer tick, in usecs. + * + * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. + * 'tick' is usecs per jiffy. + */ +static unsigned long clps711x_gettimeoffset(void) +{ + unsigned long hwticks; + hwticks = LATCH - (clps_readl(TC2D) & 0xffff); /* since last underflow */ + return (hwticks * tick) / LATCH; +} + +void __init clps711x_setup_timer(void) +{ + unsigned int syscon; + + gettimeoffset = clps711x_gettimeoffset; + + syscon = clps_readl(SYSCON1); + syscon |= SYSCON1_TC2S | SYSCON1_TC2M; + clps_writel(syscon, SYSCON1); + + clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */ + + xtime.tv_sec = clps_readl(RTCDR); +} diff -urN linux-2.4.18/arch/arm/mach-ebsa110/io.c linux-2.4.19-pre5/arch/arm/mach-ebsa110/io.c --- linux-2.4.18/arch/arm/mach-ebsa110/io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-ebsa110/io.c Sat Mar 30 22:55:37 2002 @@ -139,7 +139,11 @@ ((p) >> 3) == (0x2f8 >> 3) || \ ((p) >> 3) == (0x378 >> 3)) -u8 __inb(int port) +/* + * We're addressing an 8 or 16-bit peripheral which tranfers + * odd addresses on the low ISA byte lane. + */ +u8 __inb8(unsigned int port) { u32 ret; @@ -162,7 +166,11 @@ return ret; } -u16 __inw(int port) +/* + * We're addressing a 16-bit peripheral which transfers odd + * addresses on the high ISA byte lane. + */ +u8 __inb16(unsigned int port) { u32 ret; @@ -170,13 +178,33 @@ * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - ret = __arch_getw(ISAIO_BASE + (port << 2)); + ret = __arch_getb(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); /* * Shame nothing else does */ + ret = __arch_getb(a + (port & 1)); + } + return ret; +} + +u16 __inw(unsigned int port) +{ + u32 ret; + + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port) || port & 1) + ret = __arch_getw(ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + (port << 1); + + /* + * Shame nothing else does + */ if (port & 1) BUG(); @@ -185,17 +213,27 @@ return ret; } -u32 __inl(int port) +/* + * Fake a 32-bit read with two 16-bit reads. Needed for 3c589. + */ +u32 __inl(unsigned int port) { - BUG(); - return 0; + u32 a; + + if (SUPERIO_PORT(port) || port & 3) + BUG(); + + a = ISAIO_BASE + (port << 1); + + return __arch_getw(a) | __arch_getw(a + 4) << 16; } -EXPORT_SYMBOL(__inb); +EXPORT_SYMBOL(__inb8); +EXPORT_SYMBOL(__inb16); EXPORT_SYMBOL(__inw); EXPORT_SYMBOL(__inl); -void __outb(u8 val, int port) +void __outb8(u8 val, unsigned int port) { /* * The SuperIO registers use sane addressing techniques... @@ -215,7 +253,24 @@ } } -void __outw(u16 val, int port) +void __outb16(u8 val, unsigned int port) +{ + /* + * The SuperIO registers use sane addressing techniques... + */ + if (SUPERIO_PORT(port)) + __arch_putb(val, ISAIO_BASE + (port << 2)); + else { + u32 a = ISAIO_BASE + ((port & ~1) << 1); + + /* + * Shame nothing else does + */ + __arch_putb(val, a + (port & 1)); + } +} + +void __outw(u16 val, unsigned int port) { u32 off; @@ -225,7 +280,7 @@ if (SUPERIO_PORT(port)) off = port << 2; else { - off = (port & ~1) << 1; + off = port << 1; if (port & 1) BUG(); @@ -233,12 +288,13 @@ __arch_putw(val, ISAIO_BASE + off); } -void __outl(u32 val, int port) +void __outl(u32 val, unsigned int port) { BUG(); } -EXPORT_SYMBOL(__outb); +EXPORT_SYMBOL(__outb8); +EXPORT_SYMBOL(__outb16); EXPORT_SYMBOL(__outw); EXPORT_SYMBOL(__outl); @@ -315,12 +371,29 @@ EXPORT_SYMBOL(outsw); EXPORT_SYMBOL(insw); +/* + * We implement these as 16-bit insw/outsw, mainly for + * 3c589 cards. + */ void outsl(unsigned int port, const void *from, int len) { - panic("outsl not supported on this architecture"); + u32 off = port << 1; + + if (SUPERIO_PORT(port) || port & 3) + BUG(); + + __raw_writesw(ISAIO_BASE + off, from, len << 1); } void insl(unsigned int port, void *from, int len) { - panic("insl not supported on this architecture"); + u32 off = port << 1; + + if (SUPERIO_PORT(port) || port & 3) + BUG(); + + __raw_readsw(ISAIO_BASE + off, from, len << 1); } + +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insl); diff -urN linux-2.4.18/arch/arm/mach-epxa10db/arch.c linux-2.4.19-pre5/arch/arm/mach-epxa10db/arch.c --- linux-2.4.18/arch/arm/mach-epxa10db/arch.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-epxa10db/arch.c Sat Mar 30 22:55:37 2002 @@ -18,7 +18,6 @@ * 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 diff -urN linux-2.4.18/arch/arm/mach-epxa10db/mm.c linux-2.4.19-pre5/arch/arm/mach-epxa10db/mm.c --- linux-2.4.18/arch/arm/mach-epxa10db/mm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-epxa10db/mm.c Sat Mar 30 22:55:37 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include diff -urN linux-2.4.18/arch/arm/mach-integrator/pci_v3.c linux-2.4.19-pre5/arch/arm/mach-integrator/pci_v3.c --- linux-2.4.18/arch/arm/mach-integrator/pci_v3.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-integrator/pci_v3.c Sat Mar 30 22:55:37 2002 @@ -20,6 +20,7 @@ * 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 @@ -411,12 +412,19 @@ flags: IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -void __init pci_v3_setup_resources(struct resource **resource) +int __init pci_v3_setup_resources(struct resource **resource) { - if (request_resource(&iomem_resource, &non_mem)) - printk("PCI: unable to allocate non-prefetchable memory region\n"); - if (request_resource(&iomem_resource, &pre_mem)) - printk("PCI: unable to allocate prefetchable memory region\n"); + if (request_resource(&iomem_resource, &non_mem)) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region\n"); + return -EBUSY; + } + if (request_resource(&iomem_resource, &pre_mem)) { + release_resource(&non_mem); + printk(KERN_ERR "PCI: unable to allocate prefetchable " + "memory region\n"); + return -EBUSY; + } /* * bus->resource[0] is the IO resource for this bus @@ -426,6 +434,8 @@ resource[0] = &ioport_resource; resource[1] = &non_mem; resource[2] = &pre_mem; + + return 1; } /* @@ -433,18 +443,23 @@ * means I can't get additional information on the reason for the pm2fb * problems. I suppose I'll just have to mind-meld with the machine. ;) */ -#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_PCIENABLE)) -#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE+0x20)) -#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE+0x24)) +#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20) +#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24) static int v3_fault(unsigned long addr, struct pt_regs *regs) { unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; +#if 0 + char buf[128]; - printk("V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", + sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, v3_readb(V3_LB_ISTAT)); + printk(KERN_DEBUG "%s", buf); + printascii(buf); +#endif v3_writeb(V3_LB_ISTAT, 0); __raw_writel(3, SC_PCI); @@ -467,11 +482,20 @@ return 0; } + if ((instr & 0x0e100090) == 0x00100090) { + int reg = (instr >> 12) & 15; + + regs->uregs[reg] = -1; + regs->ARM_pc += 4; + return 0; + } + return 1; } static void v3_irq(int irq, void *devid, struct pt_regs *regs) { +#ifdef CONFIG_DEBUG_LL unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; char buf[128]; @@ -480,10 +504,13 @@ pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, v3_readb(V3_LB_ISTAT)); printascii(buf); +#endif + v3_writew(V3_PCI_STAT, 0xf000); v3_writeb(V3_LB_ISTAT, 0); __raw_writel(3, SC_PCI); +#ifdef CONFIG_DEBUG_LL /* * If the instruction being executed was a read, * make it look like it read all-ones. @@ -493,17 +520,9 @@ sprintf(buf, " reg%d = %08lx\n", reg, regs->uregs[reg]); printascii(buf); } +#endif } -static struct irqaction v3_int = { - name: "V3", - handler: v3_irq, -}; -static struct irqaction v3_int2 = { - name: "V3TM", - handler: v3_irq, -}; - extern int (*external_fault)(unsigned long addr, struct pt_regs *regs); /* @@ -514,6 +533,8 @@ { unsigned int pci_cmd; unsigned long flags; + unsigned int temp; + int ret; /* * Hook in our fault handler for PCI errors @@ -523,6 +544,12 @@ spin_lock_irqsave(&v3_lock, flags); /* + * Unlock V3 registers, but only if they were previously locked. + */ + if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK) + v3_writew(V3_SYSTEM, 0xa05f); + + /* * Setup window 0 - PCI non-prefetchable memory * Local: 0x40000000 Bus: 0x00000000 Size: 256MB */ @@ -548,6 +575,45 @@ V3_LB_BASE_ENABLE); v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); + /* + * Disable PCI to host IO cycles + */ + temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN; + temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS; + v3_writew(V3_PCI_CFG, temp); + + printk(KERN_DEBUG "FIFO_CFG: %04x FIFO_PRIO: %04x\n", + v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY)); + + /* + * Set the V3 FIFO such that writes have higher priority than + * reads, and local bus write causes local bus read fifo flush. + * Same for PCI. + */ + v3_writew(V3_FIFO_PRIORITY, 0x0a0a); + + /* + * Re-lock the system register. + */ + temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK; + v3_writew(V3_SYSTEM, temp); + + /* + * Clear any error conditions, and enable write errors. + */ + v3_writeb(V3_LB_ISTAT, 0); + v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); + v3_writeb(V3_LB_IMASK, 0x28); + __raw_writel(3, SC_PCI); + + /* + * Grab the PCI error interrupt. + */ + ret = request_irq(IRQ_V3INT, v3_irq, 0, "V3 error", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab PCI error " + "interrupt: %d\n", ret); + spin_unlock_irqrestore(&v3_lock, flags); pci_scan_bus(0, &pci_v3_ops, sysdata); @@ -557,18 +623,13 @@ v3_writew(V3_PCI_CMD, pci_cmd); - /* - * Clear any error conditions. - */ - __raw_writel(3, SC_PCI); - v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); - v3_writeb(V3_LB_ISTAT, 0); + v3_writeb(V3_LB_ISTAT, ~0x40); v3_writeb(V3_LB_IMASK, 0x68); - printk("LB_CFG: %04x LB_ISTAT: %02x LB_IMASK: %02x\n", - v3_readw(V3_LB_CFG), - v3_readb(V3_LB_ISTAT), - v3_readb(V3_LB_IMASK)); - setup_arm_irq(IRQ_V3INT, &v3_int); -// setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2); +#if 0 + ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab local bus timeout ". + "interrupt: %d\n", ret); +#endif } diff -urN linux-2.4.18/arch/arm/mach-mx1ads/Makefile linux-2.4.19-pre5/arch/arm/mach-mx1ads/Makefile --- linux-2.4.18/arch/arm/mach-mx1ads/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/Makefile Sat Mar 30 22:55:37 2002 @@ -0,0 +1,20 @@ +# +# 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). + +USE_STANDARD_AS_RULE := true + +O_TARGET := mx1ads.o + +# Object file lists. + +obj-y := arch.o cpu.o irq.o mm.o time.o +obj-m := +obj-n := +obj- := + + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/arm/mach-mx1ads/arch.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/arch.c --- linux-2.4.18/arch/arm/mach-mx1ads/arch.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/arch.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,59 @@ +/* + * linux/arch/arm/mach-mx1ads/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void mx1ads_map_io(void); +extern void mx1ads_init_irq(void); + + +static void __init +mx1ads_fixup(struct machine_desc *desc, struct param_struct *unused, + char **cmdline, struct meminfo *mi) +{ +} + +MACHINE_START(MX1ADS, "Motorola MX1ADS") + MAINTAINER("Shane Nay") +#ifdef CONFIG_ARCH_MX1ADS_SRAM + BOOT_MEM(0x12000000, 0x00200000, 0xf0200000) +#else + BOOT_MEM(0x08000000, 0x00200000, 0xf0200000) +#endif + FIXUP(mx1ads_fixup) + MAPIO(mx1ads_map_io) + INITIRQ(mx1ads_init_irq) +MACHINE_END + +#if 0 + +#endif diff -urN linux-2.4.18/arch/arm/mach-mx1ads/cpu.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/cpu.c --- linux-2.4.18/arch/arm/mach-mx1ads/cpu.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/cpu.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/mach-mx1ads/cpu.c + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * + * $Id: cpu.c,v 1.2 2001/09/22 12:11:17 rmk Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * CPU support functions + */ + +/* FIXME- + * Add support for clock change on the fly. (Power) + * + */ +#include +#include +#include +#include +#include + +#include +#include + + +static int __init cpu_init(void) +{ + return 0; +} + +__initcall(cpu_init); diff -urN linux-2.4.18/arch/arm/mach-mx1ads/irq.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/irq.c --- linux-2.4.18/arch/arm/mach-mx1ads/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/irq.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,73 @@ +/* + * linux/arch/arm/mach-mx1ads/irq.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include +#include +#include + +#include + +/* + * + * We simply use the ENABLE DISABLE registers inside of the MX1 + * to turn on/off specific interrupts. FIXME- We should + * also add support for the accelerated interrupt controller + * by putting offets to irq jump code in the appropriate + * places. + * + */ + +#define INTENNUM_OFF 0x8 +#define INTDISNUM_OFF 0xC + +#define VA_AITC_BASE IO_ADDRESS(MX1ADS_AITC_BASE) +#define MX1ADS_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF) +#define MX1ADS_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF) + +static void +mx1ads_mask_irq(unsigned int irq) +{ + __raw_writel(irq, MX1ADS_AITC_INTDISNUM); +} + +static void +mx1ads_unmask_irq(unsigned int irq) +{ + __raw_writel(irq, MX1ADS_AITC_INTENNUM); +} + +void __init +mx1ads_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = mx1ads_mask_irq; + irq_desc[i].mask = mx1ads_mask_irq; + irq_desc[i].unmask = mx1ads_unmask_irq; + } + + /* Disable all interrupts initially. */ + /* In MX1 this is done in the bootloader. */ +} diff -urN linux-2.4.18/arch/arm/mach-mx1ads/mm.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/mm.c --- linux-2.4.18/arch/arm/mach-mx1ads/mm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/mm.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/mach-mx1ads/mm.c + * + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + + + +static struct map_desc mx1ads_io_desc[] __initdata = { + + { IO_ADDRESS(MX1ADS_SRAM_BASE), MX1ADS_SRAM_BASE, SZ_128K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(MX1ADS_IO_BASE), MX1ADS_IO_BASE, SZ_256K , DOMAIN_IO, 0, 1}, + LAST_DESC +}; + +void __init mx1ads_map_io(void) +{ + iotable_init(mx1ads_io_desc); +} diff -urN linux-2.4.18/arch/arm/mach-mx1ads/time.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/time.c --- linux-2.4.18/arch/arm/mach-mx1ads/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/time.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/mach-mx1ads/time.c + * + * Copyright (C) 2000-2001 Deep Blue Solutions + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include + + +extern int (*set_rtc)(void); + +/* FIXME- + * When we have an external RTC part, + * put the mapping in for that part. + * + * The internal RTC within the MX1 is not sufficient + * for tracking time other than time of day, or + * date over very short periods of time. + * + */ + +static int mx1ads_set_rtc(void) +{ + return 0; +} + +static int mx1ads_rtc_init(void) +{ + xtime.tv_sec = 0; + + set_rtc = mx1ads_set_rtc; + + return 0; +} + +__initcall(mx1ads_rtc_init); diff -urN linux-2.4.18/arch/arm/mach-sa1100/Makefile linux-2.4.19-pre5/arch/arm/mach-sa1100/Makefile --- linux-2.4.18/arch/arm/mach-sa1100/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/Makefile Sat Mar 30 22:55:37 2002 @@ -9,20 +9,19 @@ O_TARGET := sa1100.o -obj-y := +# Common support (must be linked before board specific support) +obj-y := generic.o irq.o dma-sa1100.o obj-m := obj-n := obj- := -export-objs := assabet.o dma-sa1100.o dma-sa1111.o freebird.o generic.o \ - h3600.o huw_webpanel.o irq.o pcipool.o sa1111-pcibuf.o \ - yopy.o +export-objs := assabet.o dma-sa1100.o dma-sa1111.o \ + flexanet.o freebird.o generic.o h3600.o \ + huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \ + system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o # These aren't present yet, and prevents a plain -ac kernel building. -# hwtimer.o usb_ctl.o usb_recv.o usb_send.o - -# Common support (must be linked before board specific support) -obj-y += generic.o irq.o dma-sa1100.o +# hwtimer.o # This needs to be cleaned up. We probably need to have SA1100 # and SA1110 config symbols. @@ -31,6 +30,7 @@ ifeq ($(CONFIG_CPU_FREQ),y) obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o +obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o endif @@ -42,11 +42,13 @@ obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o obj-$(CONFIG_SA1100_ASSABET) += assabet.o obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o +obj-$(CONFIG_SA1100_BADGE4) += badge4.o obj-$(CONFIG_SA1100_BRUTUS) += brutus.o obj-$(CONFIG_SA1100_CERF) += cerf.o obj-$(CONFIG_SA1100_EMPEG) += empeg.o obj-$(CONFIG_SA1100_FLEXANET) += flexanet.o obj-$(CONFIG_SA1100_FREEBIRD) += freebird.o +obj-$(CONFIG_SA1100_FRODO) += frodo.o obj-$(CONFIG_SA1100_GRAPHICSCLIENT) += graphicsclient.o obj-$(CONFIG_SA1100_GRAPHICSMASTER) += graphicsmaster.o obj-$(CONFIG_SA1100_H3600) += h3600.o @@ -59,6 +61,8 @@ obj-$(CONFIG_SA1100_PANGOLIN) += pangolin.o obj-$(CONFIG_SA1100_PFS168) += pfs168.o obj-$(CONFIG_SA1100_PLEB) += pleb.o +obj-$(CONFIG_SA1100_PT_SYSTEM3) += system3.o +obj-$(CONFIG_SA1100_SHANNON) += shannon.o obj-$(CONFIG_SA1100_SHERMAN) += sherman.o obj-$(CONFIG_SA1100_SIMPAD) += simpad.o obj-$(CONFIG_SA1100_VICTOR) += victor.o @@ -72,14 +76,27 @@ leds-$(CONFIG_SA1100_BRUTUS) += leds-brutus.o leds-$(CONFIG_SA1100_CERF) += leds-cerf.o leds-$(CONFIG_SA1100_FLEXANET) += leds-flexanet.o +leds-$(CONFIG_SA1100_FRODO) += leds-frodo.o leds-$(CONFIG_SA1100_GRAPHICSCLIENT) += leds-graphicsclient.o leds-$(CONFIG_SA1100_GRAPHICSMASTER) += leds-graphicsmaster.o leds-$(CONFIG_SA1100_LART) += leds-lart.o leds-$(CONFIG_SA1100_PFS168) += leds-pfs168.o leds-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o +leds-$(CONFIG_SA1100_PT_SYSTEM3) += leds-system3.o obj-$(CONFIG_LEDS) += $(leds-y) +# SA1110 USB client support +list-multi += sa1100usb_core.o +sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o +obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o +obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o +obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o + # Miscelaneous functions obj-$(CONFIG_PM) += pm.o sleep.o include $(TOPDIR)/Rules.make + +sa1100usb_core.o: $(sa1100usb_core-objs) + $(LD) -r -o $@ $(sa1100usb_core-objs) + diff -urN linux-2.4.18/arch/arm/mach-sa1100/adsbitsy.c linux-2.4.19-pre5/arch/arm/mach-sa1100/adsbitsy.c --- linux-2.4.18/arch/arm/mach-sa1100/adsbitsy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/adsbitsy.c Sat Mar 30 22:55:37 2002 @@ -53,7 +53,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(ADSBITSY_SA1111_BASE); if (ret < 0) return ret; @@ -94,7 +94,7 @@ sa1110_mb_enable(); set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE); - sa1111_init_irq(SA1100_GPIO_TO_IRQ(0)); + sa1111_init_irq(IRQ_GPIO0); return 0; } @@ -126,8 +126,8 @@ static struct map_desc adsbitsy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */ + { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */ + { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ LAST_DESC }; @@ -135,24 +135,15 @@ { if (port->mapbase == _Ser1UTCR0) { Ser1SDCR0 |= SDCR0_UART; - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO15; - GPCR |= GPIO_GPIO15; - // Set CTS Input - GPDR &= ~GPIO_GPIO14; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO15; } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO17; - GPCR |= GPIO_GPIO17; - // Set CTS Input - GPDR &= ~GPIO_GPIO16; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO17; } else if (port->mapbase == _Ser2UTCR0) { - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO19; - GPCR |= GPIO_GPIO19; - // Set CTS Input - GPDR &= ~GPIO_GPIO18; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO19; } return 0; } @@ -166,10 +157,12 @@ sa1100_map_io(); iotable_init(adsbitsy_io_desc); - sa1110_register_uart_fns(&adsbitsy_port_fns); + sa1100_register_uart_fns(&adsbitsy_port_fns); sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19; + GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18); } MACHINE_START(ADSBITSY, "ADS Bitsy") diff -urN linux-2.4.18/arch/arm/mach-sa1100/assabet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/assabet.c --- linux-2.4.18/arch/arm/mach-sa1100/assabet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/assabet.c Sat Mar 30 22:55:37 2002 @@ -31,16 +31,48 @@ #include "generic.h" +#define ASSABET_BCR_DB1110 \ + (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ + ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ + ASSABET_BCR_IRDA_MD0) + +#define ASSABET_BCR_DB1111 \ + (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ + ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ + ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \ + ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST) -unsigned long BCR_value = ASSABET_BCR_DB1110; unsigned long SCR_value = ASSABET_SCR_INIT; -EXPORT_SYMBOL(BCR_value); EXPORT_SYMBOL(SCR_value); +static unsigned long BCR_value = ASSABET_BCR_DB1110; + +void ASSABET_BCR_frob(unsigned int mask, unsigned int val) +{ + unsigned long flags; + + local_irq_save(flags); + BCR_value = (BCR_value & ~mask) | val; + ASSABET_BCR = BCR_value; + local_irq_restore(flags); +} + +EXPORT_SYMBOL(ASSABET_BCR_frob); + static int __init assabet_init(void) { - if (machine_is_assabet() && machine_has_neponset()) { + if (!machine_is_assabet()) + return -EINVAL; + + /* + * Set the IRQ edges + */ + set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE); /* UCB1300 */ + + if (machine_has_neponset()) { /* * Angel sets this, but other bootloaders may not. * @@ -55,6 +87,7 @@ "hasn't been configured in the kernel\n" ); #endif } + return 0; } @@ -87,18 +120,18 @@ * repeat it here because the kernel may not be loaded as a zImage, and * also because it's a hassle to communicate the SCR value to the kernel * from the decompressor. + * + * Note that IRQs are guaranteed to be disabled. */ static void __init get_assabet_scr(void) { - unsigned long flags, scr, i; + unsigned long scr, i; - local_irq_save(flags); GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */ GPDR |= 0x3fc; /* restore correct pin direction */ - local_irq_restore(flags); scr &= 0x3fc; /* save as system configuration byte. */ SCR_value = scr; } @@ -174,9 +207,9 @@ static struct map_desc assabet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ /* f3000000 - neponset system registers */ /* f4000000 - neponset SA1111 registers */ LAST_DESC @@ -186,19 +219,18 @@ { if (port->mapbase == _Ser1UTCR0) { if (state) - ASSABET_BCR_clear(ASSABET_BCR_RS232EN); + ASSABET_BCR_clear(ASSABET_BCR_RS232EN | + ASSABET_BCR_COM_RTS | + ASSABET_BCR_COM_DTR); else - ASSABET_BCR_set(ASSABET_BCR_RS232EN); + ASSABET_BCR_set(ASSABET_BCR_RS232EN | + ASSABET_BCR_COM_RTS | + ASSABET_BCR_COM_DTR); } } /* - * Note! this can be called from IRQ context. - * FIXME: You _need_ to handle ASSABET_BCR carefully, which doesn't - * happen at the moment. Suggest putting interrupt save/restore - * in ASSABET_BCR_set/clear. - * - * NB: Assabet uses COM_RTS and COM_DTR for both UART1 (com port) + * Assabet uses COM_RTS and COM_DTR for both UART1 (com port) * and UART3 (radio module). We only handle them for UART1 here. */ static void assabet_set_mctrl(struct uart_port *port, u_int mctrl) @@ -207,21 +239,21 @@ u_int set = 0, clear = 0; if (mctrl & TIOCM_RTS) - set |= ASSABET_BCR_COM_RTS; - else clear |= ASSABET_BCR_COM_RTS; + else + set |= ASSABET_BCR_COM_RTS; if (mctrl & TIOCM_DTR) - set |= ASSABET_BCR_COM_DTR; - else clear |= ASSABET_BCR_COM_DTR; + else + set |= ASSABET_BCR_COM_DTR; ASSABET_BCR_clear(clear); ASSABET_BCR_set(set); } } -static int assabet_get_mctrl(struct uart_port *port) +static u_int assabet_get_mctrl(struct uart_port *port) { u_int ret = 0; u_int bsr = ASSABET_BSR; @@ -312,11 +344,7 @@ PWER = PWER_GPIO0; PGSR = 0; PCFR = 0; - - /* - * Clear all possible wakeup reasons. - */ - RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; + PSDR = 0; } diff -urN linux-2.4.18/arch/arm/mach-sa1100/badge4.c linux-2.4.19-pre5/arch/arm/mach-sa1100/badge4.c --- linux-2.4.18/arch/arm/mach-sa1100/badge4.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/badge4.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,213 @@ +/* + * linux/arch/arm/mach-sa1100/badge4.c + * + * BadgePAD 4 specific initialization + * + * Tim Connors + * Christopher Hoover + * + * Copyright (C) 2002 Hewlett-Packard Company + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "generic.h" +#include "sa1111.h" + +static int __init badge4_sa1111_init(void) +{ + int ret; + + /* + * Ensure that the memory bus request/grant signals are setup, + * and the grant is held in its inactive state + */ + sa1110_mb_disable(); + + /* + * Probe for SA1111. + */ + ret = sa1111_probe(BADGE4_SA1111_BASE); + if (ret < 0) + return ret; + + /* + * We found it. Wake the chip up. + */ + sa1111_wake(); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + */ + SKPCR |= SKPCR_DCLKEN; + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + set_GPIO_IRQ_edge(BADGE4_GPIO_INT_1111, GPIO_RISING_EDGE); + sa1111_init_irq(BADGE4_IRQ_GPIO_SA1111); + + return 0; +} + +static int __init badge4_init(void) +{ + int ret; + + if (!machine_is_badge4()) + return -ENODEV; + + ret = badge4_sa1111_init(); + if (ret < 0) + printk(KERN_ERR __FUNCTION__ + ": SA-1111 initialization failed (%d)\n", ret); + + /* N.B, according to rmk this is the singular place that GPDR + should be set */ + + /* Video expansion */ + GPCR = (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | + BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | + BADGE4_GPIO_GPC_VID); + GPDR |= (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | + BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | + BADGE4_GPIO_GPC_VID); + + /* SDRAM SPD i2c */ + GPCR = (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL); + GPDR |= (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL); + + /* uart */ + GPCR = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); + GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); + + /* drives CPLD muxsel0 input */ + GPCR = BADGE4_GPIO_MUXSEL0; + GPDR |= BADGE4_GPIO_MUXSEL0; + + /* test points */ + GPCR = (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | + BADGE4_GPIO_TESTPT_J5); + GPDR |= (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | + BADGE4_GPIO_TESTPT_J5); + + /* drives CPLD sdram type inputs; this shouldn't be needed; + bootloader left it this way. */ + GPDR |= (BADGE4_GPIO_SDTYP0 | BADGE4_GPIO_SDTYP1); + + /* 5V supply rail. */ + GPCR = BADGE4_GPIO_PCMEN5V; /* initially off */ + GPDR |= BADGE4_GPIO_PCMEN5V; + + /* drives SA1111 reset pin; this shouldn't be needed; + bootloader left it this way. */ + GPSR = BADGE4_GPIO_SA1111_NRST; + GPDR |= BADGE4_GPIO_SA1111_NRST; + + return 0; +} + +__initcall(badge4_init); + + +static unsigned badge4_5V_bitmap = 0; + +void badge4_set_5V(unsigned subsystem, int on) +{ + unsigned long flags; + unsigned old_5V_bitmap; + + local_irq_save(flags); + + old_5V_bitmap = badge4_5V_bitmap; + + if (on) { + badge4_5V_bitmap |= subsystem; + } else { + badge4_5V_bitmap &= ~subsystem; + } + + /* detect on->off and off->on transitions */ + if ((!old_5V_bitmap) && (badge4_5V_bitmap)) { + /* was off, now on */ + printk(KERN_INFO __FUNCTION__ ": enabling 5V supply rail\n"); + GPSR = BADGE4_GPIO_PCMEN5V; + } else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) { + /* was on, now off */ + printk(KERN_INFO __FUNCTION__ ": disabling 5V supply rail\n"); + GPCR = BADGE4_GPIO_PCMEN5V; + } + + local_irq_restore(flags); +} +EXPORT_SYMBOL(badge4_set_5V); + + +static void __init +fixup_badge4(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + /* nothing needed here */ +} + +static struct map_desc badge4_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + {0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0,1,0,0},/* Flash bank 0 */ + {0xf1000000, 0x08000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM bank 1 */ + {0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM bank 2 */ + {0xf4000000, 0x48000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SA-1111 */ + LAST_DESC +}; + +static void __init badge4_map_io(void) +{ + sa1100_map_io(); + iotable_init(badge4_io_desc); + + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); +} + +MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_badge4) + MAPIO(badge4_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN linux-2.4.18/arch/arm/mach-sa1100/cerf.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cerf.c --- linux-2.4.18/arch/arm/mach-sa1100/cerf.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cerf.c Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/cerf.c */ - +#include #include #include #include @@ -16,20 +16,22 @@ #include "generic.h" -static void __init cerf_init_irq (void) +static void __init cerf_init_irq(void) { - sa1100_init_irq(); + sa1100_init_irq(); - /* Need to register these as rising edge interrupts - * For standard 16550 serial driver support - * Basically - I copied it from pfs168.c :) - */ + /* Need to register these as rising edge interrupts + * For standard 16550 serial driver support + * Basically - I copied it from pfs168.c :) + */ #ifdef CONFIG_SA1100_CERF_CPLD - set_GPIO_IRQ_edge(GPIO_GPIO(3), GPIO_RISING_EDGE); /* PDA Full serial port */ - set_GPIO_IRQ_edge(GPIO_GPIO(2), GPIO_RISING_EDGE); /* PDA Bluetooth */ - GPDR &= ~(GPIO_GPIO(3)); /* Set the direction of serial port GPIO pin to in */ - GPDR &= ~(GPIO_GPIO(2)); /* Set the direction of bluetooth GPIO pin to in */ + /* PDA Full serial port */ + set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE); + /* PDA Bluetooth */ + set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE); #endif /* CONFIG_SA1100_CERF_CPLD */ + + set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); } static void __init @@ -37,22 +39,20 @@ char **cmdline, struct meminfo *mi) { #if defined(CONFIG_SA1100_CERF_64MB) - // 64MB RAM - SET_BANK( 0, 0xc0000000, 64*1024*1024 ); - mi->nr_banks = 1; -#elif defined(CONFIG_SA1100_CERF_32MB) // 32MB RAM + SET_BANK( 0, 0xc0000000, 64*1024*1024 ); + mi->nr_banks = 1; +#elif defined(CONFIG_SA1100_CERF_32MB) SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; -#elif defined(CONFIG_SA1100_CERF_16MB) // 16Meg Ram. +#elif defined(CONFIG_SA1100_CERF_16MB) SET_BANK( 0, 0xc0000000, 8*1024*1024 ); SET_BANK( 1, 0xc8000000, 8*1024*1024 ); mi->nr_banks = 2; #elif defined(CONFIG_SA1100_CERF_8MB) - // 8Meg Ram. - SET_BANK( 0, 0xc0000000, 8*1024*1024 ); - mi->nr_banks = 1; + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + mi->nr_banks = 1; #else - #error "Undefined memory size for Cerfboard." +#error "Undefined memory size for Cerfboard." #endif // ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); @@ -62,13 +62,13 @@ } static struct map_desc cerf_io_desc[] __initdata = { - /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Ethernet Chip */ + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Crystal Ethernet Chip */ #ifdef CONFIG_SA1100_CERF_CPLD - { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD Chip */ - { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Bluetooth */ - { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Serial */ + { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Chip */ + { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Bluetooth */ + { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Serial */ #endif LAST_DESC }; @@ -78,12 +78,18 @@ sa1100_map_io(); iotable_init(cerf_io_desc); - sa1100_register_uart(0, 3); + sa1100_register_uart(0, 3); #ifdef CONFIG_SA1100_CERF_IRDA_ENABLED sa1100_register_uart(1, 1); #else sa1100_register_uart(1, 2); sa1100_register_uart(2, 1); +#endif + + /* set some GPDR bits here while it's safe */ + GPDR |= GPIO_CF_RESET; +#ifdef CONFIG_SA1100_CERF_CPLD + GPDR |= GPIO_PWR_SHUTDOWN; #endif } diff -urN linux-2.4.18/arch/arm/mach-sa1100/cpu-sa1100.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1100.c --- linux-2.4.18/arch/arm/mach-sa1100/cpu-sa1100.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1100.c Sat Mar 30 22:55:37 2002 @@ -90,7 +90,8 @@ #include - +extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); +extern unsigned int sa11x0_validatespeed(unsigned int khz); typedef struct { @@ -219,14 +220,22 @@ }; - +static void sa1100_setspeed(unsigned int khz) +{ + PPCR = sa11x0_freq_to_ppcr(khz); +} static int __init sa1100_dram_init(void) { - return cpufreq_register_notifier(&sa1100_dram_block); -} + int ret = -ENODEV; + if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) { + ret = cpufreq_register_notifier(&sa1100_dram_block); + cpufreq_setfunctions(sa11x0_validatespeed, sa1100_setspeed); + } + return ret; +} __initcall(sa1100_dram_init); diff -urN linux-2.4.18/arch/arm/mach-sa1100/cpu-sa1110.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1110.c --- linux-2.4.18/arch/arm/mach-sa1100/cpu-sa1110.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1110.c Sat Mar 30 22:55:37 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 2001 Russell King * - * $Id: cpu-sa1110.c,v 1.5 2001/09/10 13:25:58 rmk Exp $ + * $Id: cpu-sa1110.c,v 1.6 2001/10/22 11:53:47 rmk Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -29,14 +29,8 @@ #undef DEBUG -extern u_int processor_id; - -#define CPU_REVISION (processor_id & 15) -#define CPU_SA1110_A0 (0) -#define CPU_SA1110_B0 (4) -#define CPU_SA1110_B1 (5) -#define CPU_SA1110_B2 (6) -#define CPU_SA1110_B4 (8) +extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); +extern unsigned int sa11x0_validatespeed(unsigned int khz); struct sdram_params { u_char rows; /* bits */ @@ -48,6 +42,12 @@ u_short refresh; /* refresh time for array (us) */ }; +struct sdram_info { + u_int mdcnfg; + u_int mdrefr; + u_int mdcas[3]; +}; + static struct sdram_params tc59sm716_cl2_params __initdata = { rows: 12, tck: 10, @@ -68,6 +68,16 @@ cas_latency: 3, }; +static struct sdram_params samsung_k4s641632d_tc75 __initdata = { + rows: 14, + tck: 9, + trcd: 27, + trp: 20, + twr: 9, + refresh: 64000, + cas_latency: 3, +}; + static struct sdram_params sdram_params; /* @@ -95,10 +105,11 @@ mdcas[1] = mdcas[2] = 0x55555555 << (shift & 1); } -static void sdram_update_timing(u_int cpu_khz, struct sdram_params *sdram) +static void +sdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz, + struct sdram_params *sdram) { - u_int mdcnfg, mdrefr, mdcas[3], mem_khz, sd_khz, trp, twr; - unsigned long flags; + u_int mem_khz, sd_khz, trp, twr; mem_khz = cpu_khz / 2; sd_khz = mem_khz; @@ -114,7 +125,7 @@ (CPU_REVISION < CPU_SA1110_B2 && sd_khz < 62000)) sd_khz /= 2; - mdcnfg = MDCNFG & 0x007f007f; + sd->mdcnfg = MDCNFG & 0x007f007f; twr = ns_to_cycles(sdram->twr, mem_khz); @@ -123,53 +134,26 @@ if (trp < 1) trp = 1; - mdcnfg |= trp << 8; - mdcnfg |= trp << 24; - mdcnfg |= sdram->cas_latency << 12; - mdcnfg |= sdram->cas_latency << 28; - mdcnfg |= twr << 14; - mdcnfg |= twr << 30; + sd->mdcnfg |= trp << 8; + sd->mdcnfg |= trp << 24; + sd->mdcnfg |= sdram->cas_latency << 12; + sd->mdcnfg |= sdram->cas_latency << 28; + sd->mdcnfg |= twr << 14; + sd->mdcnfg |= twr << 30; - mdrefr = MDREFR & 0xffbffff0; - mdrefr |= 7; + sd->mdrefr = MDREFR & 0xffbffff0; + sd->mdrefr |= 7; if (sd_khz != mem_khz) - mdrefr |= MDREFR_K1DB2; + sd->mdrefr |= MDREFR_K1DB2; /* initial number of '1's in MDCAS + 1 */ - set_mdcas(mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz)); + set_mdcas(sd->mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz)); #ifdef DEBUG - mdelay(250); printk("MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n", - mdcnfg, mdrefr, mdcas[0], mdcas[1], mdcas[2]); + sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1], sd->mdcas[2]); #endif - - /* - * Reprogram the DRAM timings with interrupts disabled, and - * ensure that we are doing this within a complete cache line. - * This means that we won't access SDRAM for the duration of - * the programming. - */ - local_irq_save(flags); - asm("mcr p15, 0, %0, c10, c4" : : "r" (0)); - udelay(10); - __asm__(" - b 1f - .align 5 -1: str %3, [%1, #28] @ MDREFR - str %4, [%1, #4] @ MDCAS0 - str %5, [%1, #8] @ MDCAS1 - str %6, [%1, #12] @ MDCAS2 - str %2, [%1, #0] @ MDCNFG - ldr %0, [%1, #0] - nop - nop" - : "=&r" (mdcnfg) - : "r" (io_p2v(_MDCNFG)), - "0" (mdcnfg), "r" (mdrefr), - "r" (mdcas[0]), "r" (mdcas[1]), "r" (mdcas[2])); - local_irq_restore(flags); } /* @@ -203,65 +187,92 @@ sdram_set_refresh(dri); } -static int -sdram_notifier(struct notifier_block *nb, unsigned long val, void *data) +/* + * Ok, set the CPU frequency. Since we've done the validation + * above, we can match for an exact frequency. If we don't find + * an exact match, we will to set the lowest frequency to be safe. + */ +static void sa1110_setspeed(unsigned int khz) { - struct cpufreq_info *ci = data; struct sdram_params *sdram = &sdram_params; + struct sdram_info sd; + unsigned long flags; + unsigned int ppcr, unused; - /* were we initialised? */ - if (sdram->cas_latency == 0) { - struct cpufreq_minmax *m = data; - m->min_freq = m->max_freq = m->cur_freq; - return 0; - } + ppcr = sa11x0_freq_to_ppcr(khz); + sdram_calculate_timing(&sd, khz, sdram); - switch (val) { - case CPUFREQ_MINMAX: - /* - * until we work out why the assabet - * crashes below 147.5MHz... - */ - cpufreq_updateminmax(data, 147500, -1); - break; - - case CPUFREQ_PRECHANGE: - /* - * The clock could be going away for some time. - * Set the SDRAMs to refresh rapidly (every 64 - * memory clock cycles). To get through the - * whole array, we need to wait 262144 mclk cycles. - * We wait 20ms to be safe. - */ - sdram_set_refresh(2); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(20 * HZ / 1000); - - if (ci->old_freq < ci->new_freq) - sdram_update_timing(ci->new_freq, sdram); - break; - - case CPUFREQ_POSTCHANGE: - if (ci->old_freq > ci->new_freq) - sdram_update_timing(ci->new_freq, sdram); - sdram_update_refresh(ci->new_freq, sdram); - break; +#if 0 + /* + * These values are wrong according to the SA1110 documentation + * and errata, but they seem to work. Need to get a storage + * scope on to the SDRAM signals to work out why. + */ + if (khz < 147500) { + sd.mdrefr |= MDREFR_K1DB2; + sd.mdcas[0] = 0xaaaaaa7f; + } else { + sd.mdrefr &= ~MDREFR_K1DB2; + sd.mdcas[0] = 0xaaaaaa9f; } - return 0; -} + sd.mdcas[1] = 0xaaaaaaaa; + sd.mdcas[2] = 0xaaaaaaaa; +#endif + /* + * The clock could be going away for some time. Set the SDRAMs + * to refresh rapidly (every 64 memory clock cycles). To get + * through the whole array, we need to wait 262144 mclk cycles. + * We wait 20ms to be safe. + */ + sdram_set_refresh(2); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(20 * HZ / 1000); -static struct notifier_block sa1110_clkchg_block = { - notifier_call: sdram_notifier, -}; + /* + * Reprogram the DRAM timings with interrupts disabled, and + * ensure that we are doing this within a complete cache line. + * This means that we won't access SDRAM for the duration of + * the programming. + */ + local_irq_save(flags); + asm("mcr p15, 0, %0, c10, c4" : : "r" (0)); + udelay(10); + __asm__ __volatile__(" + b 2f + .align 5 +1: str %3, [%1, #0] @ MDCNFG + str %4, [%1, #28] @ MDREFR + str %5, [%1, #4] @ MDCAS0 + str %6, [%1, #8] @ MDCAS1 + str %7, [%1, #12] @ MDCAS2 + str %8, [%2, #0] @ PPCR + ldr %0, [%1, #0] + b 3f +2: b 1b +3: nop + nop" + : "=&r" (unused) + : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg), + "r" (sd.mdrefr), "r" (sd.mdcas[0]), + "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr)); + local_irq_restore(flags); -static int __init sa1110_sdram_init(void) + /* + * Now, return the SDRAM refresh back to normal. + */ + sdram_update_refresh(khz, sdram); +} + +static int __init sa1110_clk_init(void) { struct sdram_params *sdram = NULL; - unsigned int cur_freq = cpufreq_get(smp_processor_id()); if (machine_is_assabet()) sdram = &tc59sm716_cl3_params; + if (machine_is_pt_system3()) + sdram = &samsung_k4s641632d_tc75; + if (sdram) { printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d" " twr: %d refresh: %d cas_latency: %d\n", @@ -270,11 +281,11 @@ memcpy(&sdram_params, sdram, sizeof(sdram_params)); - sdram_update_timing(cur_freq, &sdram_params); - sdram_update_refresh(cur_freq, &sdram_params); + sa1110_setspeed(cpufreq_get(0)); + cpufreq_setfunctions(sa11x0_validatespeed, sa1110_setspeed); } - return cpufreq_register_notifier(&sa1110_clkchg_block); + return 0; } -__initcall(sa1110_sdram_init); +__initcall(sa1110_clk_init); diff -urN linux-2.4.18/arch/arm/mach-sa1100/dma-sa1100.c linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1100.c --- linux-2.4.18/arch/arm/mach-sa1100/dma-sa1100.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1100.c Sat Mar 30 22:55:37 2002 @@ -147,6 +147,19 @@ } /* + * This improves latency if there are some active spinning + * buffers. We kill them altogether. + */ + if (dma->spin_ref > 0) { + if (channel_is_sa1111_sac(dma - dma_chan)) + sa1111_reset_sac_dma(dma - dma_chan); + else + dma->regs->ClrDCSR = + DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB; + dma->spin_ref = 0; + } + + /* * Let's try to start DMA on the current buffer. * If DMA is busy then we break here. */ @@ -188,8 +201,7 @@ */ DPRINTK("IRQ: buf done\n"); dma->curr = buf->next; - if (dma->curr == NULL) - dma->spin_ref = -dma->spin_ref; + dma->spin_ref = -dma->spin_ref; if (dma->head == buf) dma->head = NULL; if (dma->callback) { @@ -468,7 +480,6 @@ int flags; save_flags_cli(flags); dma->stopped = 0; - dma->spin_ref = 0; process_dma(dma); restore_flags(flags); } diff -urN linux-2.4.18/arch/arm/mach-sa1100/dma-sa1111.c linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1111.c --- linux-2.4.18/arch/arm/mach-sa1100/dma-sa1111.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1111.c Sat Mar 30 22:55:37 2002 @@ -22,6 +22,7 @@ #include #include #include +#include // #define DEBUG #ifdef DEBUG diff -urN linux-2.4.18/arch/arm/mach-sa1100/empeg.c linux-2.4.19-pre5/arch/arm/mach-sa1100/empeg.c --- linux-2.4.18/arch/arm/mach-sa1100/empeg.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/empeg.c Sat Mar 30 22:55:37 2002 @@ -31,7 +31,7 @@ static struct map_desc empeg_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/flexanet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/flexanet.c --- linux-2.4.18/arch/arm/mach-sa1100/flexanet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/flexanet.c Sat Mar 30 22:55:37 2002 @@ -9,8 +9,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include @@ -27,22 +25,140 @@ #include #include #include +#include #include "generic.h" -unsigned long BCR_value = BCR_POWERUP; -unsigned long flexanet_GUI_type = 0x0000000F; +unsigned long flexanet_BCR = FHH_BCR_POWERUP; + +EXPORT_SYMBOL(flexanet_BCR); + +/* physical addresses */ +#define _RCNR 0x90010004 +#define _GPLR 0x90040000 +#define _Ser4SSCR0 0x80070060 + +/* + * Get the modem-control register of the UARTs + * + */ +static int flexanet_get_mctrl(struct uart_port *port) +{ + int stat = 0; + unsigned long bsr; + + /* only DSR and CTS are implemented in UART1 & 3 */ + if (port->membase == (void *)&Ser1UTCR0) + { + bsr = FHH_BSR; + + if ((bsr & FHH_BSR_DSR1) != 0) + stat |= TIOCM_DSR; + if ((bsr & FHH_BSR_CTS1) != 0) + stat |= TIOCM_CTS; + } + else if (port->membase == (void *)&Ser3UTCR0) + { + bsr = FHH_BSR; + + if ((bsr & FHH_BSR_DSR3) != 0) + stat |= TIOCM_DSR; + if ((bsr & FHH_BSR_CTS3) != 0) + stat |= TIOCM_CTS; + } + + return stat; +} + +/* + * Set the modem-control register of the UARTs + * + */ +static void flexanet_set_mctrl(struct uart_port *port, u_int mctrl) +{ + unsigned long flags; -EXPORT_SYMBOL(BCR_value); -EXPORT_SYMBOL(flexanet_GUI_type); + /* only the RTS signal is implemented in UART1 & 3 */ + if (port->membase == (void *)&Ser1UTCR0) + { + local_irq_save(flags); + + if (mctrl & TIOCM_RTS) + flexanet_BCR |= FHH_BCR_RTS1; + else + flexanet_BCR &= ~FHH_BCR_RTS1; + + FHH_BCR = flexanet_BCR; + local_irq_restore(flags); + } + else if (port->membase == (void *)&Ser3UTCR0) + { + local_irq_save(flags); + + if (mctrl & TIOCM_RTS) + flexanet_BCR |= FHH_BCR_RTS3; + else + flexanet_BCR &= ~FHH_BCR_RTS3; + + FHH_BCR = flexanet_BCR; + local_irq_restore(flags); + } +} + +/* + * machine-specific serial port functions + * + * get_mctrl : set state of modem control lines + * set_mctrl : set the modem control lines + * pm : power-management. Turn device on/off. + * + */ +static struct sa1100_port_fns flexanet_port_fns __initdata = +{ + set_mctrl : flexanet_set_mctrl, + get_mctrl : flexanet_get_mctrl, + pm : NULL, +}; + + +/* + * Initialization and serial port mapping + * + */ + +static int flexanet_serial_init(void) +{ + /* register low-level functions */ + sa1100_register_uart_fns(&flexanet_port_fns); + + /* UART port number mapping */ + sa1100_register_uart(0, 1); /* RS232 */ + sa1100_register_uart(1, 3); /* Radio */ + + /* Select UART function in Serial port 1 */ + Ser1SDCR0 |= SDCR0_UART; + + return 0; +} + + +static int __init flexanet_init(void) +{ + return 0; +} + +__initcall(flexanet_init); -static unsigned long probe_gui_board (void); static void __init fixup_flexanet(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { + int status; + unsigned long now; + + /* fixed RAM size, by now (64MB) */ SET_BANK( 0, 0xc0000000, 64*1024*1024 ); mi->nr_banks = 1; @@ -56,8 +172,11 @@ static struct map_desc flexanet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Ethernet controller */ + { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Instrument boards */ + { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* External peripherals */ LAST_DESC }; @@ -65,9 +184,27 @@ { sa1100_map_io(); iotable_init(flexanet_io_desc); + flexanet_serial_init(); - sa1100_register_uart(0, 1); - Ser1SDCR0 |= SDCR0_UART; + /* wakeup source is GPIO-0 only */ + PWER = PWER_GPIO0; + + /* GPIOs set to zero during sleep */ + PGSR = 0; + + /* + * stop the 3.68 MHz oscillator and float control busses + * during sleep, since peripherals are powered off. + */ + PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS; + + /* deassert the GUI reset */ + FLEXANET_BCR_set(FHH_BCR_GUI_NRST); + + /* + * Set IRQ edges + */ + set_GPIO_IRQ_edge(GPIO_GUI_IRQ, GPIO_RISING_EDGE); } @@ -78,3 +215,4 @@ MAPIO(flexanet_map_io) INITIRQ(sa1100_init_irq) MACHINE_END + diff -urN linux-2.4.18/arch/arm/mach-sa1100/freebird.c linux-2.4.19-pre5/arch/arm/mach-sa1100/freebird.c --- linux-2.4.18/arch/arm/mach-sa1100/freebird.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/freebird.c Sat Mar 30 22:55:37 2002 @@ -37,9 +37,9 @@ static struct map_desc freebird_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0}, + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */ + { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0}, LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/frodo.c linux-2.4.19-pre5/arch/arm/mach-sa1100/frodo.c --- linux-2.4.18/arch/arm/mach-sa1100/frodo.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/frodo.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,61 @@ + +/* + * linux/arch/arm/mach-sa1100/frodo.c + * + * Author: Abraham van der Merwe + * + * This file contains the 2d3D, Inc. SA-1110 Development Board tweaks. + * + * This source code is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * History: + * + * 2002/01/31 Initial version + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "generic.h" + +static struct map_desc frodo_io_desc[] __initdata = +{ + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* flash memory */ + { 0xf0000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16-bit on-board devices (including CPLDs) */ + { 0xf1000000, 0x18000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* 32-bit daughter card */ + LAST_DESC +}; + +static void __init frodo_map_io (void) +{ + sa1100_map_io (); + iotable_init (frodo_io_desc); + + sa1100_register_uart (0,2); /* UART2 (serial console) */ + sa1100_register_uart (1,1); /* UART1 (big kahuna flow control serial port) */ + + /* + * Set SUS bit in SDCR0 so serial port 1 acts as a UART. + * See Intel SA-1110 Developers Manual Section 11.9.2.1 (GPCLK/UART Select) + */ + Ser1SDCR0 |= SDCR0_SUS; +} + +MACHINE_START (FRODO,"2d3D, Inc. SA-1110 Development Board") + BOOT_MEM (0xc0000000,0x80000000,0xf8000000) + BOOT_PARAMS (0xc0000100) + MAPIO (frodo_map_io) + INITIRQ (sa1100_init_irq) +MACHINE_END + diff -urN linux-2.4.18/arch/arm/mach-sa1100/generic.c linux-2.4.19-pre5/arch/arm/mach-sa1100/generic.c --- linux-2.4.18/arch/arm/mach-sa1100/generic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/generic.c Sat Mar 30 22:55:37 2002 @@ -56,20 +56,13 @@ /* * Return the current CPU clock frequency in units of 100kHz */ -unsigned short get_cclk_frequency(void) +static inline unsigned short get_cclk_frequency(void) { return cclk_frequency_100khz[PPCR & 0xf]; } -EXPORT_SYMBOL(get_cclk_frequency); - #ifdef CONFIG_CPU_FREQ - -/* - * Validate the speed in khz. If we can't generate the precise - * frequency requested, round it down (to be on the safe side). - */ -unsigned int sa1100_validatespeed(unsigned int khz) +unsigned int sa11x0_freq_to_ppcr(unsigned int khz) { int i; @@ -79,35 +72,34 @@ if (cclk_frequency_100khz[i] <= khz) break; - return cclk_frequency_100khz[i] * 100; + return i; } /* - * Ok, set the CPU frequency. Since we've done the validation - * above, we can match for an exact frequency. If we don't find - * an exact match, we will to set the lowest frequency to be safe. + * Validate the speed in khz. If we can't generate the precise + * frequency requested, round it down (to be on the safe side). */ -void sa1100_setspeed(unsigned int khz) +unsigned int sa11x0_validatespeed(unsigned int khz) { - int i; - - khz /= 100; - - for (i = NR_FREQS - 1; i > 0; i--) - if (cclk_frequency_100khz[i] == khz) - break; -//printk("setting ppcr to %d\n", i); - PPCR = i; + return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100; } -static int __init sa1100_init_clock(void) +static int __init sa11x0_init_clock(void) { - cpufreq_init(get_cclk_frequency() * 100); - cpufreq_setfunctions(sa1100_validatespeed, sa1100_setspeed); + cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100); return 0; } -__initcall(sa1100_init_clock); +__initcall(sa11x0_init_clock); +#else +/* + * We still need to provide this so building without cpufreq works. + */ +unsigned int cpufreq_get(int cpu) +{ + return cclk_frequency_100khz[PPCR & 0xf] * 100; +} +EXPORT_SYMBOL(cpufreq_get); #endif /* @@ -130,13 +122,13 @@ PMCR = PMCR_SF; } -static int __init sa1100_set_poweroff(void) +static int __init sa1100_init(void) { pm_power_off = sa1100_power_off; return 0; } -__initcall(sa1100_set_poweroff); +__initcall(sa1100_init); /* @@ -149,7 +141,8 @@ * 0xf0000000-0xf3ffffff: miscellaneous stuff (CPLDs, etc.) * 0xf4000000-0xf4ffffff: SA-1111 * 0xf5000000-0xf5ffffff: reserved (used by cache flushing area) - * 0xf6000000-0xffffffff: reserved (internal SA1100 IO defined above) + * 0xf6000000-0xfffeffff: reserved (internal SA1100 IO defined above) + * 0xffff0000-0xffff0fff: SA1100 exception vectors * * Below 0xe8000000 is reserved for vm allocation. * @@ -159,8 +152,8 @@ static struct map_desc standard_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */ - { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */ + { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ + { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ diff -urN linux-2.4.18/arch/arm/mach-sa1100/graphicsclient.c linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsclient.c --- linux-2.4.18/arch/arm/mach-sa1100/graphicsclient.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsclient.c Sat Mar 30 22:55:37 2002 @@ -113,7 +113,6 @@ irq_desc[irq].mask = ADS_mask_irq1; irq_desc[irq].unmask = ADS_unmask_irq1; } - GPDR &= ~GPIO_GPIO0; set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); } @@ -138,7 +137,7 @@ static struct map_desc graphicsclient_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */ { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ { 0xf1000000, 0x18000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */ LAST_DESC @@ -193,12 +192,8 @@ if (port->mapbase == _Ser1UTCR0) { Ser1SDCR0 |= SDCR0_UART; /* Set RTS Output */ - GPDR |= GPIO_GC_UART0_RTS; GPSR = GPIO_GC_UART0_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART0_CTS; - gc_uart_ctrl_data[0].cts_prev_state = 0; gc_uart_ctrl_data[0].info = info; gc_uart_ctrl_data[0].port = port; @@ -210,12 +205,8 @@ } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; /* Set RTS Output */ - GPDR |= GPIO_GC_UART1_RTS; GPSR = GPIO_GC_UART1_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART1_RTS; - gc_uart_ctrl_data[1].cts_prev_state = 0; gc_uart_ctrl_data[1].info = info; gc_uart_ctrl_data[1].port = port; @@ -226,12 +217,8 @@ &gc_uart_ctrl_data[1]); } else if (port->mapbase == _Ser3UTCR0) { /* Set RTS Output */ - GPDR |= GPIO_GC_UART2_RTS; GPSR = GPIO_GC_UART2_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART2_RTS; - gc_uart_ctrl_data[2].cts_prev_state = 0; gc_uart_ctrl_data[2].info = info; gc_uart_ctrl_data[2].port = port; @@ -258,9 +245,9 @@ return 0; } -static int graphicsclient_get_mctrl(struct uart_port *port) +static u_int graphicsclient_get_mctrl(struct uart_port *port) { - int result = TIOCM_CD | TIOCM_DSR; + u_int result = TIOCM_CD | TIOCM_DSR; if (port->mapbase == _Ser1UTCR0) { if (!(GPLR & GPIO_GC_UART0_CTS)) @@ -326,6 +313,8 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + GPDR |= GPIO_GC_UART0_RTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS; + GPDR &= ~(GPIO_GC_UART0_CTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS); } MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") diff -urN linux-2.4.18/arch/arm/mach-sa1100/graphicsmaster.c linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsmaster.c --- linux-2.4.18/arch/arm/mach-sa1100/graphicsmaster.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsmaster.c Sat Mar 30 22:55:37 2002 @@ -43,7 +43,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(ADS_SA1111_BASE); if (ret < 0) return ret; @@ -174,7 +174,6 @@ irq_desc[irq].mask = ADS_mask_irq1; irq_desc[irq].unmask = ADS_unmask_irq1; } - GPDR &= ~GPIO_GPIO0; set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); } @@ -200,10 +199,10 @@ static struct map_desc graphicsmaster_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */ - { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */ - { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */ + { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ + { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */ + { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; @@ -215,31 +214,22 @@ Ser1SDCR0 |= SDCR0_UART; /* Set RTS Output */ GPSR = GPIO_GPIO15; - GPDR |= GPIO_GPIO15; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO14; } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; /* Set RTS Output */ GPSR = GPIO_GPIO17; - GPDR |= GPIO_GPIO17; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO16; } else if (port->mapbase == _Ser3UTCR0) { /* Set RTS Output */ GPSR = GPIO_GPIO19; - GPDR |= GPIO_GPIO19; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO18; } return ret; } -static int graphicsmaster_get_mctrl(struct uart_port *port) +static u_int graphicsmaster_get_mctrl(struct uart_port *port) { - int result = TIOCM_CD | TIOCM_DSR; + u_int result = TIOCM_CD | TIOCM_DSR; if (port->mapbase == _Ser1UTCR0) { if (!(GPLR & GPIO_GPIO14)) @@ -304,6 +294,10 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + + /* set GPDR now */ + GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19; + GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18); } MACHINE_START(GRAPHICSMASTER, "ADS GraphicsMaster") diff -urN linux-2.4.18/arch/arm/mach-sa1100/h3600.c linux-2.4.19-pre5/arch/arm/mach-sa1100/h3600.c --- linux-2.4.18/arch/arm/mach-sa1100/h3600.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/h3600.c Sat Mar 30 22:55:37 2002 @@ -1,8 +1,24 @@ /* - * linux/arch/arm/mach-sa1100/h3600.c + * Hardware definitions for Compaq iPAQ H3xxx Handheld Computers + * + * Copyright 2000,1 Compaq Computer Corporation. + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Author: Jamey Hicks. + * + * History: + * + * 2001-10-?? Andrew Christian Added support for iPAQ H3800 + * and abstracted EGPIO interface. + * */ - -#include #include #include #include @@ -17,84 +33,338 @@ #include #include #include +#include #include "generic.h" - /* - * Bitsy has extended, write-only memory-mapped GPIO's + * H3600 has extended, write-only memory-mapped GPIO's + * H3100 has 1/2 extended, write-only GPIO and 1/2 on + * regular GPIO lines. + * H3800 has memory-mapped GPIO through ASIC1 & 2 */ -static int h3600_egpio = EGPIO_H3600_RS232_ON; +#define H3600_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT) + +static unsigned int h3600_egpio; + +/************************* H3100 *************************/ + +#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON \ + | GPIO_H3100_GPIO3 \ + | GPIO_H3100_QMUTE \ + | GPIO_H3100_LCD_3V_ON \ + | GPIO_H3100_AUD_ON \ + | GPIO_H3100_AUD_PWR_ON \ + | GPIO_H3100_IR_ON \ + | GPIO_H3100_IR_FSEL) + +static void h3100_init_egpio( void ) +{ + GPDR |= H3100_DIRECT_EGPIO; + GPCR = H3100_DIRECT_EGPIO; /* Initially all off */ + + /* Older bootldrs put GPIO2-9 in alternate mode on the + assumption that they are used for video */ + GAFR &= ~H3100_DIRECT_EGPIO; + + h3600_egpio = EGPIO_H3600_RS232_ON; + H3600_EGPIO = h3600_egpio; +} + +static void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) +{ + unsigned int egpio = 0; + long gpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + egpio |= EGPIO_H3600_LCD_ON; + gpio |= GPIO_H3100_LCD_3V_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + egpio |= EGPIO_H3600_CODEC_NRESET; + break; + case IPAQ_EGPIO_AUDIO_ON: + gpio |= GPIO_H3100_AUD_PWR_ON + | GPIO_H3100_AUD_ON; + break; + case IPAQ_EGPIO_QMUTE: + gpio |= GPIO_H3100_QMUTE; + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + egpio |= EGPIO_H3600_OPT_NVRAM_ON; + break; + case IPAQ_EGPIO_OPT_ON: + egpio |= EGPIO_H3600_OPT_ON; + break; + case IPAQ_EGPIO_CARD_RESET: + egpio |= EGPIO_H3600_CARD_RESET; + break; + case IPAQ_EGPIO_OPT_RESET: + egpio |= EGPIO_H3600_OPT_RESET; + break; + case IPAQ_EGPIO_IR_ON: + gpio |= GPIO_H3100_IR_ON; + break; + case IPAQ_EGPIO_IR_FSEL: + gpio |= GPIO_H3100_IR_FSEL; + break; + case IPAQ_EGPIO_RS232_ON: + egpio |= EGPIO_H3600_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + egpio |= EGPIO_H3600_VPP_ON; + break; + } + + local_irq_save(flags); + if ( setp ) { + h3600_egpio |= egpio; + GPSR = gpio; + } else { + h3600_egpio &= ~egpio; + GPCR = gpio; + } + H3600_EGPIO = h3600_egpio; + local_irq_restore(flags); -void init_h3600_egpio(void) + /* + if ( x != IPAQ_EGPIO_VPP_ON ) { + printk(__FUNCTION__ " : type=%d (%s) gpio=0x%x (0x%x) egpio=0x%x (0x%x) setp=%d\n", + x, egpio_names[x], GPLR, gpio, h3600_egpio, egpio, setp ); + } + */ +} + +static unsigned long h3100_read_egpio( void ) { -#ifdef CONFIG_IPAQ_H3100 - int h3100_controls = (GPIO_H3100_BT_ON - | GPIO_H3100_QMUTE - | GPIO_H3100_LCD_3V_ON - | GPIO_H3100_AUD_ON - | GPIO_H3100_AUD_PWR_ON - | GPIO_H3100_IR_ON - | GPIO_H3100_IR_FSEL); - GPDR |= h3100_controls; - GPCR = h3100_controls; - GAFR = GPIO_SSP_CLK; -#endif -} - -void clr_h3600_egpio(unsigned long x) -{ -#ifdef CONFIG_IPAQ_H3100 - unsigned long gpcr = 0; - if (x&EGPIO_H3600_QMUTE) - gpcr |= GPIO_H3100_QMUTE; - if (x&EGPIO_H3600_LCD_ON) - gpcr |= GPIO_H3100_LCD_3V_ON; - if (x&EGPIO_H3600_AUD_AMP_ON) - gpcr |= GPIO_H3100_AUD_ON; - if (x&EGPIO_H3600_AUD_PWR_ON) - gpcr |= GPIO_H3100_AUD_PWR_ON; - if (x&EGPIO_H3600_IR_ON) - gpcr |= GPIO_H3100_IR_ON; - if (x&EGPIO_H3600_IR_FSEL) - gpcr |= GPIO_H3100_IR_FSEL; - GPCR = gpcr; -#endif - h3600_egpio &= ~x; + return h3600_egpio; +} + +static struct ipaq_model_ops h3100_model_ops __initdata = { + model : IPAQ_H3100, + generic_name : "3100", + initialize : h3100_init_egpio, + control : h3100_control_egpio, + read : h3100_read_egpio +}; + + +/************************* H3600 *************************/ + +static void h3600_init_egpio( void ) +{ + h3600_egpio = EGPIO_H3600_RS232_ON; H3600_EGPIO = h3600_egpio; } -void set_h3600_egpio(unsigned long x) +static void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) { -#ifdef CONFIG_IPAQ_H3100 - unsigned long gpsr = 0; - if (x&EGPIO_H3600_QMUTE) - gpsr |= GPIO_H3100_QMUTE; - if (x&EGPIO_H3600_LCD_ON) - gpsr |= GPIO_H3100_LCD_3V_ON; - if (x&EGPIO_H3600_AUD_AMP_ON) - gpsr |= GPIO_H3100_AUD_ON; - if (x&EGPIO_H3600_AUD_PWR_ON) - gpsr |= GPIO_H3100_AUD_PWR_ON; - if (x&EGPIO_H3600_IR_ON) - gpsr |= GPIO_H3100_IR_ON; - if (x&EGPIO_H3600_IR_FSEL) - gpsr |= GPIO_H3100_IR_FSEL; - GPSR = gpsr; -#endif - h3600_egpio |= x; + unsigned int egpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + egpio |= EGPIO_H3600_LCD_ON | + EGPIO_H3600_LCD_PCI | + EGPIO_H3600_LCD_5V_ON | + EGPIO_H3600_LVDD_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + egpio |= EGPIO_H3600_CODEC_NRESET; + break; + case IPAQ_EGPIO_AUDIO_ON: + egpio |= EGPIO_H3600_AUD_AMP_ON | + EGPIO_H3600_AUD_PWR_ON; + break; + case IPAQ_EGPIO_QMUTE: + egpio |= EGPIO_H3600_QMUTE; + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + egpio |= EGPIO_H3600_OPT_NVRAM_ON; + break; + case IPAQ_EGPIO_OPT_ON: + egpio |= EGPIO_H3600_OPT_ON; + break; + case IPAQ_EGPIO_CARD_RESET: + egpio |= EGPIO_H3600_CARD_RESET; + break; + case IPAQ_EGPIO_OPT_RESET: + egpio |= EGPIO_H3600_OPT_RESET; + break; + case IPAQ_EGPIO_IR_ON: + egpio |= EGPIO_H3600_IR_ON; + break; + case IPAQ_EGPIO_IR_FSEL: + egpio |= EGPIO_H3600_IR_FSEL; + break; + case IPAQ_EGPIO_RS232_ON: + egpio |= EGPIO_H3600_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + egpio |= EGPIO_H3600_VPP_ON; + break; + } + + local_irq_save(flags); + if ( setp ) + h3600_egpio |= egpio; + else + h3600_egpio &= ~egpio; H3600_EGPIO = h3600_egpio; + local_irq_restore(flags); +} + +static unsigned long h3600_read_egpio( void ) +{ + return h3600_egpio; +} + +static struct ipaq_model_ops h3600_model_ops __initdata = { + model : IPAQ_H3600, + generic_name : "3600", + initialize : h3600_init_egpio, + control : h3600_control_egpio, + read : h3600_read_egpio +}; + +/************************* H3800 *************************/ + +#define ASIC1_OUTPUTS 0x7fff /* First 15 bits are used */ + +static unsigned int h3800_asic1_gpio; +static unsigned int h3800_asic2_gpio; + +static void h3800_init_egpio(void) +{ + /* Set up ASIC #1 */ + H3800_ASIC1_GPIO_Direction = ASIC1_OUTPUTS; /* All outputs */ + H3800_ASIC1_GPIO_Mask = ASIC1_OUTPUTS; /* No interrupts */ + H3800_ASIC1_GPIO_SleepMask = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_SleepDir = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_SleepOut = GPIO_H3800_ASIC1_EAR_ON_N; + H3800_ASIC1_GPIO_BattFaultDir = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_BattFaultOut = GPIO_H3800_ASIC1_EAR_ON_N; + + h3800_asic1_gpio = GPIO_H3800_ASIC1_IR_ON_N /* TODO: Check IR level */ + | GPIO_H3800_ASIC1_RS232_ON + | GPIO_H3800_ASIC1_EAR_ON_N; + + H3800_ASIC1_GPIO_Out = h3800_asic1_gpio; + + /* Set up ASIC #2 */ + H3800_ASIC2_GPIO_Direction = GPIO_H3800_ASIC2_PEN_IRQ + | GPIO_H3800_ASIC2_SD_DETECT + | GPIO_H3800_ASIC2_EAR_IN_N + | GPIO_H3800_ASIC2_USB_DETECT_N + | GPIO_H3800_ASIC2_SD_CON_SLT; + + h3800_asic2_gpio = GPIO_H3800_ASIC2_IN_Y1_N | GPIO_H3800_ASIC2_IN_X1_N; + H3800_ASIC2_GPIO_Data = h3800_asic2_gpio; + H3800_ASIC2_GPIO_BattFaultOut = h3800_asic2_gpio; + + /* TODO : Set sleep states & battery fault states */ + + /* Clear VPP Enable */ + H3800_ASIC1_FlashWP_VPP_ON = 0; +} + +static void h3800_control_egpio( enum ipaq_egpio_type x, int setp ) +{ + unsigned int set_asic1_egpio = 0; + unsigned int clear_asic1_egpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + set_asic1_egpio |= GPIO_H3800_ASIC1_LCD_5V_ON + | GPIO_H3800_ASIC1_LCD_ON + | GPIO_H3800_ASIC1_LCD_PCI + | GPIO_H3800_ASIC1_VGH_ON + | GPIO_H3800_ASIC1_VGL_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + break; + case IPAQ_EGPIO_AUDIO_ON: + break; + case IPAQ_EGPIO_QMUTE: + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + break; + case IPAQ_EGPIO_OPT_ON: + break; + case IPAQ_EGPIO_CARD_RESET: + break; + case IPAQ_EGPIO_OPT_RESET: + break; + case IPAQ_EGPIO_IR_ON: + clear_asic1_egpio |= GPIO_H3800_ASIC1_IR_ON_N; /* TODO : This is backwards? */ + break; + case IPAQ_EGPIO_IR_FSEL: + break; + case IPAQ_EGPIO_RS232_ON: + set_asic1_egpio |= GPIO_H3800_ASIC1_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + H3800_ASIC1_FlashWP_VPP_ON = setp; + break; + } + + local_irq_save(flags); + if ( setp ) { + h3800_asic1_gpio |= set_asic1_egpio; + h3800_asic1_gpio &= ~clear_asic1_egpio; + } + else { + h3800_asic1_gpio &= ~set_asic1_egpio; + h3800_asic1_gpio |= clear_asic1_egpio; + } + H3800_ASIC1_GPIO_Out = h3800_asic1_gpio; + local_irq_restore(flags); } -EXPORT_SYMBOL(clr_h3600_egpio); -EXPORT_SYMBOL(set_h3600_egpio); +static unsigned long h3800_read_egpio( void ) +{ + return h3800_asic1_gpio | (h3800_asic2_gpio << 16); +} + +static struct ipaq_model_ops h3800_model_ops __initdata = { + model : IPAQ_H3800, + generic_name : "3800", + initialize : h3800_init_egpio, + control : h3800_control_egpio, + read : h3800_read_egpio +}; /* - * Low-level UART features. - * - * Note that RTS, CTS and DCD are all active low. + * Use command line argument to choose between ipaq handheld model numbers + */ + +struct ipaq_model_ops ipaq_model_ops; +EXPORT_SYMBOL(ipaq_model_ops); + +static int __init h3600_init_model_ops(void) +{ + if (machine_is_h3xxx()) { + if (machine_is_h3100()) { + ipaq_model_ops = h3100_model_ops; + } else if (machine_is_h3600()) { + ipaq_model_ops = h3600_model_ops; + } else if (machine_is_h3800()) { + ipaq_model_ops = h3800_model_ops; + } + init_h3600_egpio(); + } + return 0; +} + +__initcall(h3600_init_model_ops); + +/* + * low-level UART features */ static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl) @@ -107,9 +377,9 @@ } } -static int h3600_uart_get_mctrl(struct uart_port *port) +static u_int h3600_uart_get_mctrl(struct uart_port *port) { - int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; + u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; if (port->mapbase == _Ser3UTCR0) { int gplr = GPLR; @@ -139,20 +409,30 @@ static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate) { if (port->mapbase == _Ser2UTCR0) { - if (state == 0) { - set_h3600_egpio(EGPIO_H3600_IR_ON); - } else { - clr_h3600_egpio(EGPIO_H3600_IR_ON); - } + assign_h3600_egpio( IPAQ_EGPIO_IR_ON, !state ); } else if (port->mapbase == _Ser3UTCR0) { - if (state == 0) { - set_h3600_egpio(EGPIO_H3600_RS232_ON); - } else { - clr_h3600_egpio(EGPIO_H3600_RS232_ON); - } + assign_h3600_egpio( IPAQ_EGPIO_RS232_ON, !state ); } } +/* + * Enable/Disable wake up events for this serial port. + * Obviously, we only support this on the normal COM port. + */ +static int h3600_uart_set_wake(struct uart_port *port, u_int enable) +{ + int err = -EINVAL; + + if (port->mapbase == _Ser3UTCR0) { + if (enable) + PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */ + else + PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */ + err = 0; + } + return err; +} + static int h3600_uart_open(struct uart_port *port, struct uart_info *info) { int ret = 0; @@ -163,8 +443,6 @@ Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR | HSSR0_RAB | HSSR0_FRE; } else if (port->mapbase == _Ser3UTCR0) { - GPDR &= ~(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS); - GPDR |= GPIO_H3600_COM_RTS; set_GPIO_IRQ_edge(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS, GPIO_BOTH_EDGES); @@ -193,16 +471,17 @@ set_mctrl: h3600_uart_set_mctrl, get_mctrl: h3600_uart_get_mctrl, pm: h3600_uart_pm, + set_wake: h3600_uart_set_wake, open: h3600_uart_open, close: h3600_uart_close, }; static struct map_desc h3600_io_desc[] __initdata = { - /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */ - { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */ - { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */ + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 CS#0 */ + { H3600_EGPIO_VIRT, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 CS#5 */ + { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2 CS#2 */ + { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4 CS#4 */ LAST_DESC }; @@ -214,13 +493,19 @@ sa1100_register_uart_fns(&h3600_port_fns); sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */ - init_h3600_egpio(); /* - * Default GPIO settings. + * Default GPIO settings. Should be set by machine */ GPCR = 0x0fffffff; - GPDR = 0x0401f3fc; +// GPDR = 0x0401f3fc; + GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK | + GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA | + GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 | + GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | + GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; + + init_h3600_egpio(); /* * Ensure those pins are outputs and driving low. @@ -230,11 +515,24 @@ /* Configure suspend conditions */ PGSR = 0; - PWER = 0x1 | (1 << 31); - PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS; -} - -MACHINE_START(H3600, "Compaq iPAQ") + PWER = PWER_GPIO0 | PWER_RTC; + PCFR = PCFR_OPDE; + PSDR = 0; +} + +MACHINE_START(H3600, "Compaq iPAQ H3600") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(h3600_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END +MACHINE_START(H3100, "Compaq iPAQ H3100") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(h3600_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END +MACHINE_START(H3800, "Compaq iPAQ H3800") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) BOOT_PARAMS(0xc0000100) MAPIO(h3600_map_io) diff -urN linux-2.4.18/arch/arm/mach-sa1100/huw_webpanel.c linux-2.4.19-pre5/arch/arm/mach-sa1100/huw_webpanel.c --- linux-2.4.18/arch/arm/mach-sa1100/huw_webpanel.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/huw_webpanel.c Sat Mar 30 22:55:37 2002 @@ -2,8 +2,6 @@ * linux/arch/arm/mach-sa1100/huw_webpanel.c * */ - -#include #include #include #include @@ -55,8 +53,8 @@ **/ static struct map_desc huw_webpanel_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0, neccessary for mtd */ - { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 1, 1, 0, 0 }, /* Parameter */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0, neccessary for mtd */ + { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 0, 1, 0, 0 }, /* Parameter */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/irq.c linux-2.4.19-pre5/arch/arm/mach-sa1100/irq.c --- linux-2.4.18/arch/arm/mach-sa1100/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/irq.c Sat Mar 30 22:55:37 2002 @@ -9,12 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include #include +#include #include #include @@ -35,8 +34,13 @@ static int GPIO_IRQ_rising_edge; static int GPIO_IRQ_falling_edge; -void set_GPIO_IRQ_edge( int gpio_mask, int edge ) +void set_GPIO_IRQ_edge(int gpio_mask, int edge) { + long flags; + int irq = 0; + + gpio_mask &= 0x0fffffff; + local_irq_save(flags); if (edge & GPIO_FALLING_EDGE) GPIO_IRQ_falling_edge |= gpio_mask; else @@ -45,6 +49,17 @@ GPIO_IRQ_rising_edge |= gpio_mask; else GPIO_IRQ_rising_edge &= ~gpio_mask; + GPDR &= ~gpio_mask; + GAFR &= ~gpio_mask; + while (gpio_mask) { + if (irq == 11) + irq = IRQ_GPIO11; + if (gpio_mask & 1) + irq_desc[irq].valid = 1; + irq++; + gpio_mask >>= 1; + } + local_irq_restore(flags); } EXPORT_SYMBOL(set_GPIO_IRQ_edge); @@ -121,7 +136,7 @@ for (i = 11; i <= 27; ++i) { if (irq & (1< + * + * This file contains the 2d3D, Inc. SA-1110 Development Board LED + * event handler. + * + * Frodo LEDs + * + * - led6 - toggles state every 50 timer interrupts (Heartbeat) + * - led7 - on if system is not idle (CPU load) + */ + +#include +#include + +#include +#include +#include + +#include "leds.h" + +#define led6_on() FRODO_CPLD_GENERAL |= FRODO_LED2 +#define led6_off() FRODO_CPLD_GENERAL &= ~FRODO_LED2 +#define led6_invert() do { \ + if ((FRODO_CPLD_GENERAL & FRODO_LED2)) \ + led6_off (); \ + else \ + led6_on (); \ + } while (0) + +#define led7_on() FRODO_CPLD_GENERAL |= FRODO_LED1 +#define led7_off() FRODO_CPLD_GENERAL &= ~FRODO_LED1 +#define led7_invert() do { \ + if ((FRODO_CPLD_GENERAL & FRODO_LED1)) \ + led7_off (); \ + else \ + led7_on (); \ + } while (0) + +static int claimed; + +void frodo_leds_event (led_event_t evt) +{ + unsigned long flags; + + local_irq_save (flags); + + switch (evt) + { +#ifdef CONFIG_LEDS_CPU + /* turn off CPU load LED */ + case led_idle_start: + if (!claimed) led7_off (); + break; + + /* turn on CPU load LED */ + case led_idle_end: + if (!claimed) led7_on (); + break; +#endif + +#ifdef CONFIG_LEDS_TIMER + /* toggle heartbeat LED */ + case led_timer: + if (!claimed) led6_invert (); + break; +#endif + + /* start: turn on LEDs and set claimed to 0 */ + case led_start: + led6_on (); + led7_on (); + claimed = 0; + break; + + /* stop: turn off LEDs */ + case led_stop: + led6_off (); + led7_off (); + break; + + /* override CPU load & timer LEDs */ + case led_claim: + claimed = 1; + break; + + /* restore CPU load & timer LEDs */ + case led_release: + claimed = 0; + break; + + /* direct LED access (must be previously claimed) */ + + /* led7 */ + case led_green_on: + if (claimed) led7_on (); + break; + + case led_green_off: + if (claimed) led7_off (); + break; + + /* led6 -- at the moment this is actually also green */ + case led_red_on: + if (claimed) led6_on (); + break; + + case led_red_off: + if (claimed) led6_off (); + break; + + default: + break; + } + + local_irq_restore (flags); +} + diff -urN linux-2.4.18/arch/arm/mach-sa1100/leds-system3.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-system3.c --- linux-2.4.18/arch/arm/mach-sa1100/leds-system3.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-system3.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,47 @@ +/* + * linux/arch/arm/mach-sa1100/leds-system3.c + * + * Copyright (C) 2001 Stefan Eletzhofer + * + * Original (leds-footbridge.c) by Russell King + * + * $Id: leds-system3.c,v 1.1.6.1 2001/12/04 15:19:26 seletz Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Log: leds-system3.c,v $ + * Revision 1.1.6.1 2001/12/04 15:19:26 seletz + * - merged from linux_2_4_13_ac5_rmk2 + * + * Revision 1.1.4.2 2001/11/19 17:58:53 seletz + * - cleanup + * + * Revision 1.1.4.1 2001/11/16 13:49:54 seletz + * - dummy LED support for PT Digital Board + * + * Revision 1.1.2.1 2001/10/15 16:03:39 seletz + * - dummy function + * + * + */ +#include + +#include +#include +#include + +#include "leds.h" + + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +static unsigned int led_state; +static unsigned int hw_led_state; + +void system3_leds_event(led_event_t evt) +{ + /* TODO: support LEDs */ +} diff -urN linux-2.4.18/arch/arm/mach-sa1100/leds.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.c --- linux-2.4.18/arch/arm/mach-sa1100/leds.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.c Sat Mar 30 22:55:37 2002 @@ -5,7 +5,6 @@ * * Copyright (C) 2001 Nicolas Pitre */ -#include #include #include @@ -16,24 +15,30 @@ static int __init sa1100_leds_init(void) { + if (machine_is_adsbitsy()) + leds_event = adsbitsy_leds_event; if (machine_is_assabet()) leds_event = assabet_leds_event; + if (machine_is_consus()) + leds_event = consus_leds_event; if (machine_is_brutus()) leds_event = brutus_leds_event; if (machine_is_cerf()) leds_event = cerf_leds_event; if (machine_is_flexanet()) leds_event = flexanet_leds_event; + if (machine_is_frodo()) + leds_event = frodo_leds_event; if (machine_is_graphicsclient()) leds_event = graphicsclient_leds_event; + if (machine_is_graphicsmaster()) + leds_event = graphicsmaster_leds_event; if (machine_is_lart()) leds_event = lart_leds_event; if (machine_is_pfs168()) leds_event = pfs168_leds_event; - if (machine_is_graphicsmaster()) - leds_event = graphicsmaster_leds_event; - if (machine_is_adsbitsy()) - leds_event = adsbitsy_leds_event; + if (machine_is_pt_system3()) + leds_event = system3_leds_event; leds_event(led_start); return 0; diff -urN linux-2.4.18/arch/arm/mach-sa1100/leds.h linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.h --- linux-2.4.18/arch/arm/mach-sa1100/leds.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.h Sat Mar 30 22:55:37 2002 @@ -1,4 +1,5 @@ extern void assabet_leds_event(led_event_t evt); +extern void consus_leds_event(led_event_t evt); extern void brutus_leds_event(led_event_t evt); extern void cerf_leds_event(led_event_t evt); extern void flexanet_leds_event(led_event_t evt); @@ -7,3 +8,5 @@ extern void pfs168_leds_event(led_event_t evt); extern void graphicsmaster_leds_event(led_event_t evt); extern void adsbitsy_leds_event(led_event_t evt); +extern void system3_leds_event(led_event_t evt); +extern void frodo_leds_event(led_event_t evt); diff -urN linux-2.4.18/arch/arm/mach-sa1100/nanoengine.c linux-2.4.19-pre5/arch/arm/mach-sa1100/nanoengine.c --- linux-2.4.18/arch/arm/mach-sa1100/nanoengine.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/nanoengine.c Sat Mar 30 22:55:37 2002 @@ -34,9 +34,9 @@ static struct map_desc nanoengine_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Internal PCI Config Space */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/neponset.c linux-2.4.19-pre5/arch/arm/mach-sa1100/neponset.c --- linux-2.4.18/arch/arm/mach-sa1100/neponset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/neponset.c Sat Mar 30 22:55:37 2002 @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -16,6 +18,7 @@ #include #include #include +#include #include "sa1111.h" @@ -40,10 +43,10 @@ if (!irr) break; if( irr & IRR_ETHERNET ) - do_IRQ(NEPONSET_ETHERNET_IRQ, regs); + do_IRQ(IRQ_NEPONSET_SMC9196, regs); if( irr & IRR_USAR ) - do_IRQ(NEPONSET_USAR_IRQ, regs); + do_IRQ(IRQ_NEPONSET_USAR, regs); if( irr & IRR_SA1111 ) sa1111_IRQ_demux(irq, dev_id, regs); @@ -58,19 +61,16 @@ static void __init neponset_init_irq(void) { - int irq; - sa1111_init_irq(-1); /* SA1111 IRQ not routed to a GPIO */ /* setup extra Neponset IRQs */ - irq = NEPONSET_ETHERNET_IRQ; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq = NEPONSET_USAR_IRQ; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - set_GPIO_IRQ_edge(ASSABET_GPIO_NEP_IRQ, GPIO_RISING_EDGE); - setup_arm_irq(ASSABET_IRQ_GPIO_NEP_IRQ, &neponset_irq); + irq_desc[IRQ_NEPONSET_SMC9196].valid = 1; + irq_desc[IRQ_NEPONSET_SMC9196].probe_ok = 1; + irq_desc[IRQ_NEPONSET_USAR].valid = 1; + irq_desc[IRQ_NEPONSET_USAR].probe_ok = 1; + + set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE); + setup_arm_irq(IRQ_GPIO25, &neponset_irq); } static int __init neponset_init(void) @@ -102,6 +102,11 @@ } /* + * Disable GPIO 0/1 drivers so the buttons work on the module. + */ + NCR_0 |= NCR_GP01_OFF; + + /* * Neponset has SA1111 connected to CS4. We know that after * reset the chip will be configured for variable latency IO. */ @@ -110,7 +115,7 @@ /* * Probe for a SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(NEPONSET_SA1111_BASE); if (ret < 0) return ret; @@ -150,8 +155,8 @@ static struct map_desc neponset_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; @@ -184,7 +189,7 @@ MDM_CTL_0 = mdm_ctl0; } -static int neponset_get_mctrl(struct uart_port *port) +static u_int neponset_get_mctrl(struct uart_port *port) { u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; u_int mdm_ctl1 = MDM_CTL_1; diff -urN linux-2.4.18/arch/arm/mach-sa1100/omnimeter.c linux-2.4.19-pre5/arch/arm/mach-sa1100/omnimeter.c --- linux-2.4.18/arch/arm/mach-sa1100/omnimeter.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/omnimeter.c Sat Mar 30 22:55:37 2002 @@ -30,7 +30,7 @@ static struct map_desc omnimeter_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* TS */ + { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* TS */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/pangolin.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pangolin.c --- linux-2.4.18/arch/arm/mach-sa1100/pangolin.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pangolin.c Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pangolin.c */ - +#include #include #include #include @@ -30,8 +30,8 @@ static struct map_desc pangolin_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ LAST_DESC }; @@ -43,6 +43,12 @@ sa1100_register_uart(0, 1); sa1100_register_uart(1, 3); Ser1SDCR0 |= SDCR0_UART; + + /* set some GPDR bits while it's safe */ + GPDR |= GPIO_PCMCIA_RESET; +#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE + GPDR |= GPIO_PCMCIA_BUS_ON; +#endif } MACHINE_START(PANGOLIN, "Dialogue-Pangolin") diff -urN linux-2.4.18/arch/arm/mach-sa1100/pfs168.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pfs168.c --- linux-2.4.18/arch/arm/mach-sa1100/pfs168.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pfs168.c Sat Mar 30 22:55:37 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pfs168.c */ - +#include #include #include #include @@ -34,7 +34,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(PFS168_SA1111_BASE); if (ret < 0) return ret; @@ -65,8 +65,7 @@ */ sa1110_mb_enable(); - set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE); - sa1111_init_irq(SA1100_GPIO_TO_IRQ(25)); /* SA1111 IRQ on GPIO 25 */ + sa1111_init_irq(IRQ_GPIO25); /* SA1111 IRQ on GPIO 25 */ return 0; } @@ -84,6 +83,8 @@ */ set_GPIO_IRQ_edge(GPIO_GPIO(19), GPIO_RISING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO(20), GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE); } @@ -101,20 +102,20 @@ static struct map_desc pfs168_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */ - { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */ - { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */ - { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Status LED control (SYSLED) */ - { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */ - { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */ - { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */ - { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */ - { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register A (SYSCTLA) */ - { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register B (SYSCTLB) */ - { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* SMC91C96 */ - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ - { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */ + { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */ + { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */ + { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Status LED control (SYSLED) */ + { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */ + { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */ + { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */ + { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */ + { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register A (SYSCTLA) */ + { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register B (SYSCTLB) */ + { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* SMC91C96 */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/pleb.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pleb.c --- linux-2.4.18/arch/arm/mach-sa1100/pleb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pleb.c Sat Mar 30 22:55:37 2002 @@ -35,8 +35,8 @@ static struct map_desc pleb_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ - { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ + { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */ + { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/pm.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pm.c --- linux-2.4.18/arch/arm/mach-sa1100/pm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pm.c Sat Mar 30 22:55:37 2002 @@ -19,30 +19,27 @@ * Cleaned up, pushed platform dependent stuff * in the platform specific files. */ - -/* - * Debug macros - */ -#define DEBUG 1 -#ifdef DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - - +#include #include #include #include +#include +#include #include -#include +#include #include #include #include +#include #include "sleep.h" +/* + * Debug macros + */ +#undef DEBUG + extern void sa1100_cpu_suspend(void); extern void sa1100_cpu_resume(void); @@ -54,22 +51,17 @@ int pm_do_suspend(void) { - int retval; - /* set up pointer to sleep parameters */ - sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); + sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); if (!sleep_save) return -ENOMEM; - sleep_save_p = virt_to_phys(sleep_save); - retval = pm_send_all(PM_SUSPEND, (void *)2); - if (retval) { - kfree(sleep_save); - return retval; - } + sleep_save_p = virt_to_phys(sleep_save); cli(); + leds_event(led_stop); + /* preserve current time */ RCNR = xtime.tv_sec; @@ -112,7 +104,9 @@ /* ensure not to come back here if it wasn't intended */ PSPR = 0; - DPRINTK("*** made it back from resume\n"); +#ifdef DEBUG + printk(KERN_DEBUG "*** made it back from resume\n"); +#endif /* restore registers */ RESTORE(GPDR); @@ -146,21 +140,55 @@ /* restore current time */ xtime.tv_sec = RCNR; + leds_event(led_start); + sti(); kfree (sleep_save); - retval = pm_send_all(PM_RESUME, (void *)0); - if (retval) - return retval; + /* + * Restore the CPU frequency settings. + */ +#ifdef CONFIG_CPU_FREQ + cpufreq_restore(); +#endif return 0; } +#ifdef CONFIG_SYSCTL +/* + * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than + * linux/sysctl.h. + * + * This means our interface here won't survive long - it needs a new + * interface. Quick hack to get this working - use sysctl id 9999. + */ +#warning ACPI broke the kernel, this interface needs to be fixed up. +#define CTL_ACPI 9999 +#define ACPI_S1_SLP_TYP 19 + +/* + * Send us to sleep. + */ +static int sysctl_pm_do_suspend(void) +{ + int retval; + + retval = pm_send_all(PM_SUSPEND, (void *)3); + + if (retval == 0) { + retval = pm_do_suspend(); + + pm_send_all(PM_RESUME, (void *)0); + } + + return retval; +} static struct ctl_table pm_table[] = { - {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&pm_do_suspend}, + {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend}, {0} }; @@ -181,3 +209,4 @@ __initcall(pm_init); +#endif diff -urN linux-2.4.18/arch/arm/mach-sa1100/sa1111-pcibuf.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111-pcibuf.c --- linux-2.4.18/arch/arm/mach-sa1100/sa1111-pcibuf.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111-pcibuf.c Sat Mar 30 22:55:37 2002 @@ -13,7 +13,6 @@ * * 06/13/2001 - created. */ -#include #include #include #include diff -urN linux-2.4.18/arch/arm/mach-sa1100/sa1111.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.c --- linux-2.4.18/arch/arm/mach-sa1100/sa1111.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.c Sat Mar 30 22:55:37 2002 @@ -15,6 +15,7 @@ * All initialization functions provided here are intended to be called * from machine specific code with proper arguments when required. */ +#include #include #include #include @@ -22,57 +23,80 @@ #include #include #include +#include #include #include #include #include +#include + #include "sa1111.h" +struct resource sa1111_resource = { + name: "SA1111", +}; + +EXPORT_SYMBOL(sa1111_resource); + /* - * SA1111 Interrupt support + * SA1111 interrupt support */ - -void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs) { - int i; unsigned long stat0, stat1; - for(;;) { - stat0 = INTSTATCLR0, stat1 = INTSTATCLR1; - if( !stat0 && !stat1 ) break; - if( stat0 ) - for( i = 0; i < 32; i++ ) - if( stat0 & (1<>= 1) + if (stat0 & 1) + do_IRQ(i, regs); + + for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) + if (stat1 & 1) + do_IRQ(i, regs); } } -static struct irqaction sa1111_irq = { - name: "SA1111", - handler: sa1111_IRQ_demux, - flags: SA_INTERRUPT -}; +#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) +#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) +/* + * A note about masking IRQs: + * + * The GPIO IRQ edge detection only functions while the IRQ itself is + * enabled; edges are not detected while the IRQ is disabled. + * + * This is especially important for the PCMCIA signals, where we must + * pick up every transition. We therefore do not disable the IRQs + * while processing them. + * + * However, since we are changed to a GPIO on the host processor, + * all SA1111 IRQs will be disabled while we're processing any SA1111 + * IRQ. + * + * Note also that changing INTPOL while an IRQ is enabled will itself + * trigger an IRQ. + */ static void sa1111_mask_and_ack_lowirq(unsigned int irq) { - unsigned int mask = 1 << (irq - SA1111_IRQ(0)); + unsigned int mask = SA1111_IRQMASK_LO(irq); - // broken hardware: interrupt events are lost if they occur - // while the interrupts are disabled. //INTEN0 &= ~mask; INTSTATCLR0 = mask; } static void sa1111_mask_and_ack_highirq(unsigned int irq) { - unsigned int mask = 1 << (irq - SA1111_IRQ(32)); + unsigned int mask = SA1111_IRQMASK_HI(irq); //INTEN1 &= ~mask; INTSTATCLR1 = mask; @@ -80,27 +104,29 @@ static void sa1111_mask_lowirq(unsigned int irq) { - //INTEN0 &= ~(1 << (irq - SA1111_IRQ(0))); + INTEN0 &= ~SA1111_IRQMASK_LO(irq); } static void sa1111_mask_highirq(unsigned int irq) { - //INTEN1 &= ~(1 << (irq - SA1111_IRQ(32))); + INTEN1 &= ~SA1111_IRQMASK_HI(irq); } static void sa1111_unmask_lowirq(unsigned int irq) { - INTEN0 |= 1 << (irq - SA1111_IRQ(0)); + INTEN0 |= SA1111_IRQMASK_LO(irq); } static void sa1111_unmask_highirq(unsigned int irq) { - INTEN1 |= 1 << ((irq - SA1111_IRQ(32))); + INTEN1 |= SA1111_IRQMASK_HI(irq); } void __init sa1111_init_irq(int irq_nr) { - int irq; + int irq, ret; + + request_mem_region(_INTTEST0, 512, "irqs"); /* disable all IRQs */ INTEN0 = 0; @@ -111,21 +137,21 @@ * specifies that S0ReadyInt and S1ReadyInt should be '1'. */ INTPOL0 = 0; - INTPOL1 = 1 << (S0_READY_NINT - SA1111_IRQ(32)) | - 1 << (S1_READY_NINT - SA1111_IRQ(32)); + INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) | + SA1111_IRQMASK_HI(S1_READY_NINT); /* clear all IRQs */ INTSTATCLR0 = -1; INTSTATCLR1 = -1; - for (irq = SA1111_IRQ(0); irq <= SA1111_IRQ(26); irq++) { + for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 0; irq_desc[irq].mask_ack = sa1111_mask_and_ack_lowirq; irq_desc[irq].mask = sa1111_mask_lowirq; irq_desc[irq].unmask = sa1111_unmask_lowirq; } - for (irq = SA1111_IRQ(32); irq <= SA1111_IRQ(54); irq++) { + for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 0; irq_desc[irq].mask_ack = sa1111_mask_and_ack_highirq; @@ -134,28 +160,60 @@ } /* Register SA1111 interrupt */ - if (irq_nr >= 0) - setup_arm_irq(irq_nr, &sa1111_irq); + if (irq_nr < 0) + return; + + ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT, + "SA1111", NULL); + if (ret < 0) + printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n", + irq_nr, ret); } -/* - * Probe for a SA1111 chip. +/** + * sa1111_probe - probe for a single SA1111 chip. + * @phys_addr: physical address of device. + * + * Probe for a SA1111 chip. This must be called + * before any other SA1111-specific code. + * + * Returns: + * %-ENODEV device not found. + * %-EBUSY physical address already marked in-use. + * %0 successful. */ - -int __init sa1111_probe(void) +int __init sa1111_probe(unsigned long phys_addr) { - unsigned long id = SBI_SKID; + unsigned long id; int ret = -ENODEV; - if ((id & SKID_ID_MASK) == SKID_SA1111_ID) { - printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " - "silicon revision %lx, metal revision %lx\n", - (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); - ret = 0; - } else { - printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id); + sa1111_resource.start = phys_addr; + sa1111_resource.end = phys_addr + 0x2000; + + if (request_resource(&iomem_resource, &sa1111_resource)) { + ret = -EBUSY; + goto out; + } + + /* + * Probe for the chip. Only touch the SBI registers. + */ + id = SBI_SKID; + if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { + printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); + ret = -ENODEV; + goto release; } + printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " + "silicon revision %lx, metal revision %lx\n", + (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + + return 0; + + release: + release_resource(&sa1111_resource); + out: return ret; } @@ -175,6 +233,10 @@ */ void sa1111_wake(void) { + unsigned long flags; + + local_irq_save(flags); + /* * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: * (SA-1110 Developer's Manual, section 9.1.2.1) @@ -210,6 +272,8 @@ * Ensure all clocks are initially off. */ SKPCR = 0; + + local_irq_restore(flags); } void sa1111_doze(void) @@ -242,12 +306,17 @@ */ void __init sa1110_mb_disable(void) { + unsigned long flags; + + local_irq_save(flags); + PGSR &= ~GPIO_MBGNT; GPCR = GPIO_MBGNT; GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT; GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ); + local_irq_restore(flags); } /* @@ -256,10 +325,19 @@ */ void __init sa1110_mb_enable(void) { + unsigned long flags; + + local_irq_save(flags); + PGSR &= ~GPIO_MBGNT; GPCR = GPIO_MBGNT; GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT; GAFR |= (GPIO_MBGNT | GPIO_MBREQ); TUCR |= TUCR_MR; + + local_irq_restore(flags); } + +EXPORT_SYMBOL(sa1111_wake); +EXPORT_SYMBOL(sa1111_doze); diff -urN linux-2.4.18/arch/arm/mach-sa1100/sa1111.h linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.h --- linux-2.4.18/arch/arm/mach-sa1100/sa1111.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.h Sat Mar 30 22:55:37 2002 @@ -11,7 +11,7 @@ /* * Probe for a SA1111 chip. */ -extern int sa1111_probe(void); +extern int sa1111_probe(unsigned long phys); /* * Wake up a SA1111 chip. @@ -30,5 +30,5 @@ extern void sa1111_init_irq(int irq_nr); -extern void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ); +extern void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs); diff -urN linux-2.4.18/arch/arm/mach-sa1100/shannon.c linux-2.4.19-pre5/arch/arm/mach-sa1100/shannon.c --- linux-2.4.18/arch/arm/mach-sa1100/shannon.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/shannon.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,47 @@ +/* + * linux/arch/arm/mach-sa1100/shannon.c + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "generic.h" + + +static struct map_desc shannon_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */ + LAST_DESC +}; + +static void __init shannon_map_io(void) +{ + sa1100_map_io(); + iotable_init(shannon_io_desc); + + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); + Ser1SDCR0 |= SDCR0_SUS; + GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD); + GPDR |= GPIO_UART_TXD; + GPDR &= ~GPIO_UART_RXD; + PPAR |= PPAR_UPR; + + set_GPIO_IRQ_edge(SHANNON_GPIO_IRQ_CODEC); +} + +MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(shannon_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN linux-2.4.18/arch/arm/mach-sa1100/sherman.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sherman.c --- linux-2.4.18/arch/arm/mach-sa1100/sherman.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sherman.c Sat Mar 30 22:55:37 2002 @@ -31,7 +31,7 @@ static struct map_desc sherman_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash*/ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/simpad.c linux-2.4.19-pre5/arch/arm/mach-sa1100/simpad.c --- linux-2.4.18/arch/arm/mach-sa1100/simpad.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/simpad.c Sat Mar 30 22:55:37 2002 @@ -23,18 +23,6 @@ long cs3_shadow; -static int __init simpad_init(void) -{ - PSPR = 0xc0008000; - GPDR &= ~GPIO_GPIO0; - cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | - ENABLE_5V | RESET_SIMCARD); - *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow; - return 0; -} - -__initcall(simpad_init); - long get_cs3_shadow() { return cs3_shadow; @@ -70,8 +58,8 @@ static struct map_desc simpad_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, - { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC }; @@ -96,11 +84,17 @@ sa1100_map_io(); iotable_init(simpad_io_desc); -#ifndef CONFIG_SERIAL_SA1100_OLD + PSPR = 0xc0008000; + GPDR &= ~GPIO_GPIO0; + cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | + ENABLE_5V | RESET_SIMCARD); + *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow; + //It is only possible to register 3 UART in serial_sa1100.c sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); -#endif + + set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE); } #ifdef CONFIG_PROC_FS diff -urN linux-2.4.18/arch/arm/mach-sa1100/system3.c linux-2.4.19-pre5/arch/arm/mach-sa1100/system3.c --- linux-2.4.18/arch/arm/mach-sa1100/system3.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/system3.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,379 @@ +/* + * linux/arch/arm/mach-sa1100/system3.c + * + * Copyright (C) 2001 Stefan Eletzhofer + * + * $Id: system3.c,v 1.1.6.1 2001/12/04 17:28:06 seletz Exp $ + * + * This file contains all PT Sytsem 3 tweaks. Based on original work from + * Nicolas Pitre's assabet fixes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Log: system3.c,v $ + * Revision 1.1.6.1 2001/12/04 17:28:06 seletz + * - merged from previous branch + * + * Revision 1.1.4.3 2001/12/04 15:16:31 seletz + * - merged from linux_2_4_13_ac5_rmk2 + * + * Revision 1.1.4.2 2001/11/19 17:18:57 seletz + * - more code cleanups + * + * Revision 1.1.4.1 2001/11/16 13:52:05 seletz + * - PT Digital Board Support Code + * + * Revision 1.1.2.2 2001/11/05 16:46:18 seletz + * - cleanups + * + * Revision 1.1.2.1 2001/10/15 16:00:43 seletz + * - first revision working with new board + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "generic.h" +#include "sa1111.h" + +#define DEBUG 1 + +#ifdef DEBUG +# define DPRINTK( x, args... ) printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args ); +#else +# define DPRINTK( x, args... ) /* nix */ +#endif + +/********************************************************************** + * prototypes + */ + +/* init funcs */ +static void __init fixup_system3(struct machine_desc *desc, + struct param_struct *params, char **cmdline, struct meminfo *mi); +static void __init get_system3_scr(void); +static int __init system3_init(void); +static void __init system3_init_irq(void); +static void __init system3_map_io(void); + +static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ); +static int system3_get_mctrl(struct uart_port *port); +static void system3_set_mctrl(struct uart_port *port, u_int mctrl); +static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate); +static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data); + +extern void convert_to_tag_list(struct param_struct *params, int mem_init); + + +/********************************************************************** + * global data + */ + +/********************************************************************** + * static data + */ + +static struct map_desc system3_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ + LAST_DESC +}; + +static struct sa1100_port_fns system3_port_fns __initdata = { + set_mctrl: system3_set_mctrl, + get_mctrl: system3_get_mctrl, + pm: system3_uart_pm, +}; + +static struct irqaction system3_irq = { + name: "PT Digital Board SA1111 IRQ", + handler: system3_IRQ_demux, + flags: SA_INTERRUPT +}; + +static struct notifier_block system3_clkchg_block = { + notifier_call: sdram_notifier, +}; + +/********************************************************************** + * Static functions + */ + +static void __init system3_map_io(void) +{ + DPRINTK( "%s\n", "START" ); + sa1100_map_io(); + iotable_init(system3_io_desc); + + sa1100_register_uart_fns(&system3_port_fns); + sa1100_register_uart(0, 1); /* com port */ + sa1100_register_uart(1, 2); + sa1100_register_uart(2, 3); /* radio module */ + + Ser1SDCR0 |= SDCR0_SUS; +} + + +/********************************************************************* + * Install IRQ handler + */ +static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +{ + u_char irr; + + for(;;){ + //irr = PTCPLD_REG_IRQSR & (PT_IRQ_LAN | PT_IRQ_USAR | PT_IRQ_SA1111); + irr = PT_IRQSR & (PT_IRQ_LAN | PT_IRQ_SA1111); + + irr ^= (PT_IRQ_LAN); + if (!irr) break; + + if( irr & PT_IRQ_LAN ) + do_IRQ(IRQ_SYSTEM3_SMC9196, regs); + +#if 0 + /* Highspeed Serial Bus not yet used */ + if( irr & PT_IRQ_USAR ) + do_IRQ(PT_USAR_IRQ, regs); +#endif + + if( irr & PT_IRQ_SA1111 ) + sa1111_IRQ_demux(irq, dev_id, regs); + } +} + + +static void __init system3_init_irq(void) +{ + int irq; + + DPRINTK( "%s\n", "START" ); + + /* SA1111 IRQ not routed to a GPIO. */ + sa1111_init_irq(-1); + + /* setup extra IRQs */ + irq = IRQ_SYSTEM3_SMC9196; + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + +#if 0 + /* Highspeed Serial Bus not yet used */ + irq = PT_USAR_IRQ; + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; +#endif + + /* IRQ by CPLD */ + set_GPIO_IRQ_edge( GPIO_GPIO(25), GPIO_RISING_EDGE ); + setup_arm_irq( IRQ_GPIO25, &system3_irq ); +} + +/********************************************************************** + * On system 3 limit cpu frequency to 206 Mhz + */ +static int sdram_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + switch (event) { + case CPUFREQ_MINMAX: + cpufreq_updateminmax(data, 147500, 206000); + break; + + } + return 0; +} + +/** + * fixup_system3 - fixup function for system 3 board + * @desc: machine description + * @param: kernel params + * @cmdline: kernel cmdline + * @mi: memory info struct + * + */ +static void __init fixup_system3(struct machine_desc *desc, + struct param_struct *params, char **cmdline, struct meminfo *mi) +{ + DPRINTK( "%s\n", "START" ); + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( 0xc0800000, 8*1024*1024 ); +} + + +/** + * system3_uart_pm - powermgmt callback function for system 3 UART + * @port: uart port structure + * @state: pm state + * @oldstate: old pm state + * + */ +static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate) +{ + /* TODO: switch on/off uart in powersave mode */ +} + +/* + * Note! this can be called from IRQ context. + * FIXME: Handle PT Digital Board CTRL regs irq-safe. + * + * NB: system3 uses COM_RTS and COM_DTR for both UART1 (com port) + * and UART3 (radio module). We only handle them for UART1 here. + */ +static void system3_set_mctrl(struct uart_port *port, u_int mctrl) +{ + if (port->mapbase == _Ser1UTCR0) { + u_int set = 0, clear = 0; + + if (mctrl & TIOCM_RTS) + set |= PT_CTRL2_RS1_RTS; + else + clear |= PT_CTRL2_RS1_RTS; + + if (mctrl & TIOCM_DTR) + set |= PT_CTRL2_RS1_DTR; + else + clear |= PT_CTRL2_RS1_DTR; + + PTCTRL2_clear(clear); + PTCTRL2_set(set); + } +} + +static int system3_get_mctrl(struct uart_port *port) +{ + u_int ret = 0; + u_int irqsr = PT_IRQSR; + + /* need 2 reads to read current value */ + irqsr = PT_IRQSR; + + /* TODO: check IRQ source register for modem/com + status lines and set them correctly. */ + + ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; + + return ret; +} + +static int __init system3_init(void) +{ + int ret = 0; + DPRINTK( "%s\n", "START" ); + + if ( !machine_is_pt_system3() ) { + ret = -EINVAL; + goto DONE; + } + + /* init control register */ + PT_CTRL0 = PT_CTRL0_INIT; + PT_CTRL1 = 0x02; + PT_CTRL2 = 0x00; + DPRINTK( "CTRL[0]=0x%02x\n", PT_CTRL0 ); + DPRINTK( "CTRL[1]=0x%02x\n", PT_CTRL1 ); + DPRINTK( "CTRL[2]=0x%02x\n", PT_CTRL2 ); + + /* + * Ensure that the memory bus request/grant signals are setup, + * and the grant is held in its inactive state. + */ + sa1110_mb_disable(); + + /* + * Probe for a SA1111. + */ + ret = sa1111_probe(PT_SA1111_BASE); + if (ret < 0) { + printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); + goto DONE; + } + + /* + * We found it. Wake the chip up. + */ + sa1111_wake(); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + */ + SKPCR |= SKPCR_DCLKEN; + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + system3_init_irq(); + +#if defined( CONFIG_CPU_FREQ ) + ret = cpufreq_register_notifier(&system3_clkchg_block); + if ( ret != 0 ) { + printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" ); + goto DONE; + } +#endif + + ret = 0; +DONE: + DPRINTK( "ret=%d\n", ret ); + return ret; +} + +/********************************************************************** + * Exported Functions + */ + +/********************************************************************** + * kernel magic macros + */ +__initcall(system3_init); + +MACHINE_START(PT_SYSTEM3, "PT System 3") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_system3) + MAPIO(system3_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN linux-2.4.18/arch/arm/mach-sa1100/victor.c linux-2.4.19-pre5/arch/arm/mach-sa1100/victor.c --- linux-2.4.18/arch/arm/mach-sa1100/victor.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/victor.c Sat Mar 30 22:55:37 2002 @@ -60,7 +60,7 @@ static struct map_desc victor_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/xp860.c linux-2.4.19-pre5/arch/arm/mach-sa1100/xp860.c --- linux-2.4.18/arch/arm/mach-sa1100/xp860.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/xp860.c Sat Mar 30 22:55:37 2002 @@ -21,6 +21,7 @@ static void xp860_power_off(void) { + cli(); GPDR |= GPIO_GPIO20; GPSR = GPIO_GPIO20; mdelay(1000); @@ -40,7 +41,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x40000000); if (ret < 0) return ret; @@ -65,9 +66,9 @@ static struct map_desc xp860_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ - { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ - { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCSI */ + { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN */ + { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */ LAST_DESC }; diff -urN linux-2.4.18/arch/arm/mach-sa1100/yopy.c linux-2.4.19-pre5/arch/arm/mach-sa1100/yopy.c --- linux-2.4.18/arch/arm/mach-sa1100/yopy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mach-sa1100/yopy.c Sat Mar 30 22:55:37 2002 @@ -1,8 +1,6 @@ /* * linux/arch/arm/mach-sa1100/yopy.c */ - -#include #include #include #include @@ -52,14 +50,16 @@ static int __init yopy_hw_init(void) { - YOPY_EGPIO = yopy_egpio; + if (machine_is_yopy()) { + YOPY_EGPIO = yopy_egpio; - /* Enable Output */ - PPDR |= PPC_L_BIAS; - PSDR &= ~PPC_L_BIAS; - PPSR |= PPC_L_BIAS; + /* Enable Output */ + PPDR |= PPC_L_BIAS; + PSDR &= ~PPC_L_BIAS; + PPSR |= PPC_L_BIAS; - YOPY_EGPIO = yopy_egpio; + YOPY_EGPIO = yopy_egpio; + } return 0; } @@ -69,9 +69,9 @@ static struct map_desc yopy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 0 */ - { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 1 */ - { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD */ + { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 0 */ + { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 1 */ + { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */ { 0xf1000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO */ LAST_DESC }; @@ -82,6 +82,8 @@ iotable_init(yopy_io_desc); sa1100_register_uart(0, 3); + + set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); } diff -urN linux-2.4.18/arch/arm/mm/Makefile linux-2.4.19-pre5/arch/arm/mm/Makefile --- linux-2.4.18/arch/arm/mm/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/Makefile Sat Mar 30 22:55:37 2002 @@ -13,19 +13,20 @@ # Object file lists. -obj-y := init.o +obj-y := init.o extable.o fault-common.o obj-m := obj-n := obj- := export-objs := proc-syms.o discontig.o -cpu32-y := consistent.o fault-armv.o ioremap.o mm-armv.o -cpu32-$(CONFIG_MODULES) += proc-syms.o +ifeq ($(CONFIG_CPU_32),y) +obj-y += consistent.o fault-armv.o ioremap.o mm-armv.o +obj-$(CONFIG_MODULES) += proc-syms.o +endif -obj-y += extable.o fault-common.o obj-$(CONFIG_CPU_26) += fault-armo.o mm-armo.o small_page.o -obj-$(CONFIG_CPU_32) += $(cpu32-y) +obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o # Select the processor-specific files @@ -34,6 +35,7 @@ p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o p-$(CONFIG_CPU_ARM720T) += proc-arm720.o p-$(CONFIG_CPU_ARM920T) += proc-arm920.o +p-$(CONFIG_CPU_ARM922T) += proc-arm922.o p-$(CONFIG_CPU_ARM926T) += proc-arm926.o p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o p-$(CONFIG_CPU_SA110) += proc-sa110.o diff -urN linux-2.4.18/arch/arm/mm/alignment.c linux-2.4.19-pre5/arch/arm/mm/alignment.c --- linux-2.4.18/arch/arm/mm/alignment.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mm/alignment.c Sat Mar 30 22:55:37 2002 @@ -0,0 +1,609 @@ +/* + * linux/arch/arm/mm/alignment.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void +do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, + int error_code, struct pt_regs *regs); + +/* + * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 + * /proc/sys/debug/alignment, modified and integrated into + * Linux 2.1 by Russell King + * + * Speed optimisations and better fault handling by Russell King. + * + * *** NOTE *** + * This code is not portable to processors with late data abort handling. + */ +#define CODING_BITS(i) (i & 0x0e000000) + +#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ +#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ +#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ +#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ +#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ + +#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0) + +#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ +#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ + +#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ +#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ +#define RM_BITS(i) (i & 15) /* Rm */ + +#define REGMASK_BITS(i) (i & 0xffff) +#define OFFSET_BITS(i) (i & 0x0fff) + +#define IS_SHIFT(i) (i & 0x0ff0) +#define SHIFT_BITS(i) ((i >> 7) & 0x1f) +#define SHIFT_TYPE(i) (i & 0x60) +#define SHIFT_LSL 0x00 +#define SHIFT_LSR 0x20 +#define SHIFT_ASR 0x40 +#define SHIFT_RORRRX 0x60 + +static unsigned long ai_user; +static unsigned long ai_sys; +static unsigned long ai_skipped; +static unsigned long ai_half; +static unsigned long ai_word; +static unsigned long ai_multi; +static int ai_usermode; + +#ifdef CONFIG_PROC_FS +static const char *usermode_action[] = { + "ignored", + "warn", + "fixup", + "fixup+warn", + "signal", + "signal+warn" +}; + +static int +proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + char *p = page; + int len; + + p += sprintf(p, "User:\t\t%lu\n", ai_user); + p += sprintf(p, "System:\t\t%lu\n", ai_sys); + p += sprintf(p, "Skipped:\t%lu\n", ai_skipped); + p += sprintf(p, "Half:\t\t%lu\n", ai_half); + p += sprintf(p, "Word:\t\t%lu\n", ai_word); + p += sprintf(p, "Multi:\t\t%lu\n", ai_multi); + p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode, + usermode_action[ai_usermode]); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +static int proc_alignment_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int mode; + + if (count > 0) { + if (get_user(mode, buffer)) + return -EFAULT; + if (mode >= '0' && mode <= '5') + ai_usermode = mode - '0'; + } + return count; +} + +/* + * This needs to be done after sysctl_init, otherwise sys/ will be + * overwritten. Actually, this shouldn't be in sys/ at all since + * it isn't a sysctl, and it doesn't contain sysctl information. + * We now locate it in /proc/cpu/alignment instead. + */ +static int __init alignment_init(void) +{ + struct proc_dir_entry *res; + + res = proc_mkdir("cpu", NULL); + if (!res) + return -ENOMEM; + + res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res); + if (!res) + return -ENOMEM; + + res->read_proc = proc_alignment_read; + res->write_proc = proc_alignment_write; + + return 0; +} + +__initcall(alignment_init); +#endif /* CONFIG_PROC_FS */ + +union offset_union { + unsigned long un; + signed long sn; +}; + +#define TYPE_ERROR 0 +#define TYPE_FAULT 1 +#define TYPE_LDST 2 +#define TYPE_DONE 3 + +#define __get8_unaligned_check(ins,val,addr,err) \ + __asm__( \ + "1: "ins" %1, [%2], #1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, #1\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (val), "=r" (addr) \ + : "0" (err), "2" (addr)) + +#define __get16_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 8; \ + if (err) \ + goto fault; \ + } while (0) + +#define get16_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrb",val,addr) + +#define get16t_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrbt",val,addr) + +#define __get32_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 8; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 16; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 24; \ + if (err) \ + goto fault; \ + } while (0) + +#define get32_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrb",val,addr) + +#define get32t_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrbt",val,addr) + +#define __put16_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: "ins" %1, [%2]\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "4: mov %0, #1\n" \ + " b 3b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 4b\n" \ + " .long 2b, 4b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define put16_unaligned_check(val,addr) \ + __put16_unaligned_check("strb",val,addr) + +#define put16t_unaligned_check(val,addr) \ + __put16_unaligned_check("strbt",val,addr) + +#define __put32_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v = val, a = addr; \ + __asm__( \ + "1: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "2: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "3: "ins" %1, [%2], #1\n" \ + " mov %1, %1, lsr #8\n" \ + "4: "ins" %1, [%2]\n" \ + "5:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "6: mov %0, #1\n" \ + " b 5b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 1b, 6b\n" \ + " .long 2b, 6b\n" \ + " .long 3b, 6b\n" \ + " .long 4b, 6b\n" \ + " .previous\n" \ + : "=r" (err), "=&r" (v), "=&r" (a) \ + : "0" (err), "1" (v), "2" (a)); \ + if (err) \ + goto fault; \ + } while (0) + +#define put32_unaligned_check(val,addr) \ + __put32_unaligned_check("strb", val, addr) + +#define put32t_unaligned_check(val,addr) \ + __put32_unaligned_check("strbt", val, addr) + +static void +do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset) +{ + if (!LDST_U_BIT(instr)) + offset.un = -offset.un; + + if (!LDST_P_BIT(instr)) + addr += offset.un; + + if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) + regs->uregs[RN_BITS(instr)] = addr; +} + +static int +do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd = RD_BITS(instr); + + if ((instr & 0x01f00ff0) == 0x01000090) + goto swp; + + if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0) + goto bad; + + ai_half += 1; + + if (user_mode(regs)) + goto user; + + if (LDST_L_BIT(instr)) { + unsigned long val; + get16_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + + user: + if (LDST_L_BIT(instr)) { + unsigned long val; + get16t_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16t_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + + swp: + printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); + bad: + return TYPE_ERROR; + + fault: + return TYPE_FAULT; +} + +static int +do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd = RD_BITS(instr); + + ai_word += 1; + + if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs)) + goto trans; + + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else + put32_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + + trans: + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else + put32t_unaligned_check(regs->uregs[rd], addr); + return TYPE_LDST; + + fault: + return TYPE_FAULT; +} + +/* + * LDM/STM alignment handler. + * + * There are 4 variants of this instruction: + * + * B = rn pointer before instruction, A = rn pointer after instruction + * ------ increasing address -----> + * | | r0 | r1 | ... | rx | | + * PU = 01 B A + * PU = 11 B A + * PU = 00 A B + * PU = 10 A B + */ +static int +do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd, rn, correction, nr_regs, regbits; + unsigned long eaddr, newaddr; + + if (LDM_S_BIT(instr)) + goto bad; + + correction = 4; /* processor implementation defined */ + regs->ARM_pc += correction; + + ai_multi += 1; + + /* count the number of registers in the mask to be transferred */ + nr_regs = hweight16(REGMASK_BITS(instr)) * 4; + + rn = RN_BITS(instr); + newaddr = eaddr = regs->uregs[rn]; + + if (!LDST_U_BIT(instr)) + nr_regs = -nr_regs; + newaddr += nr_regs; + if (!LDST_U_BIT(instr)) + eaddr = newaddr; + + if (LDST_P_EQ_U(instr)) /* U = P */ + eaddr += 4; + + /* + * For alignment faults on the ARM922T the MMU makes + * the FSR (and hence addr) equal to the updated base address + * of the multiple access rather than the restored value. + * Switch this messsage off if we've got a ARM922, otherwise + * [ls]dm alignment faults are noisy! + */ +#if !(defined CONFIG_CPU_ARM922T) + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) { + printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + show_regs(regs); + } +#endif + + if (user_mode(regs)) { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32t_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } else { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } + + if (LDST_W_BIT(instr)) + regs->uregs[rn] = newaddr; + if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15))) + regs->ARM_pc -= correction; + return TYPE_DONE; + +fault: + regs->ARM_pc -= correction; + return TYPE_FAULT; + +bad: + printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); + return TYPE_ERROR; +} + +int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) +{ + union offset_union offset; + unsigned long instr, instrptr; + int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); + unsigned int type; + + instrptr = instruction_pointer(regs); + instr = *(unsigned long *)instrptr; + + if (user_mode(regs)) + goto user; + + ai_sys += 1; + + fixup: + + regs->ARM_pc += 4; + + switch (CODING_BITS(instr)) { + case 0x00000000: /* ldrh or strh */ + if (LDSTH_I_BIT(instr)) + offset.un = (instr & 0xf00) >> 4 | (instr & 15); + else + offset.un = regs->uregs[RM_BITS(instr)]; + handler = do_alignment_ldrhstrh; + break; + + case 0x04000000: /* ldr or str immediate */ + offset.un = OFFSET_BITS(instr); + handler = do_alignment_ldrstr; + break; + + case 0x06000000: /* ldr or str register */ + offset.un = regs->uregs[RM_BITS(instr)]; + + if (IS_SHIFT(instr)) { + unsigned int shiftval = SHIFT_BITS(instr); + + switch(SHIFT_TYPE(instr)) { + case SHIFT_LSL: + offset.un <<= shiftval; + break; + + case SHIFT_LSR: + offset.un >>= shiftval; + break; + + case SHIFT_ASR: + offset.sn >>= shiftval; + break; + + case SHIFT_RORRRX: + if (shiftval == 0) { + offset.un >>= 1; + if (regs->ARM_cpsr & CC_C_BIT) + offset.un |= 1 << 31; + } else + offset.un = offset.un >> shiftval | + offset.un << (32 - shiftval); + break; + } + } + handler = do_alignment_ldrstr; + break; + + case 0x08000000: /* ldm or stm */ + handler = do_alignment_ldmstm; + break; + + default: + goto bad; + } + + type = handler(addr, instr, regs); + + if (type == TYPE_ERROR || type == TYPE_FAULT) + goto bad_or_fault; + + if (type == TYPE_LDST) + do_alignment_finish_ldst(addr, instr, regs, offset); + + return 0; + + bad_or_fault: + if (type == TYPE_ERROR) + goto bad; + regs->ARM_pc -= 4; + /* + * We got a fault - fix it up, or die. + */ + do_bad_area(current, current->mm, addr, error_code, regs); + return 0; + + bad: + /* + * Oops, we didn't handle the instruction. + */ + printk(KERN_ERR "Alignment trap: not handling instruction " + "%08lx at [<%08lx>]\n", instr, instrptr); + ai_skipped += 1; + return 1; + + user: + ai_user += 1; + + if (ai_usermode & 1) + printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx " + "Address=0x%08lx Code 0x%02x\n", current->comm, + current->pid, instrptr, instr, addr, error_code); + + if (ai_usermode & 2) + goto fixup; + + if (ai_usermode & 4) + force_sig(SIGBUS, current); + else + set_cr(cr_no_alignment); + + return 0; +} diff -urN linux-2.4.18/arch/arm/mm/fault-armv.c linux-2.4.19-pre5/arch/arm/mm/fault-armv.c --- linux-2.4.18/arch/arm/mm/fault-armv.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/fault-armv.c Sat Mar 30 22:55:37 2002 @@ -27,7 +27,6 @@ #include #include #include -#include extern void die_if_kernel(const char *str, struct pt_regs *regs, int err); extern void show_pte(struct mm_struct *mm, unsigned long addr); @@ -40,499 +39,15 @@ struct pt_regs *regs); #ifdef CONFIG_ALIGNMENT_TRAP -/* - * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 - * /proc/sys/debug/alignment, modified and integrated into - * Linux 2.1 by Russell King - * - * Speed optimisations and better fault handling by Russell King. - * - * *** NOTE *** - * This code is not portable to processors with late data abort handling. - */ -#define CODING_BITS(i) (i & 0x0e000000) - -#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ -#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ -#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ -#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ -#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ - -#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0) - -#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ -#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ - -#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ -#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ -#define RM_BITS(i) (i & 15) /* Rm */ - -#define REGMASK_BITS(i) (i & 0xffff) -#define OFFSET_BITS(i) (i & 0x0fff) - -#define IS_SHIFT(i) (i & 0x0ff0) -#define SHIFT_BITS(i) ((i >> 7) & 0x1f) -#define SHIFT_TYPE(i) (i & 0x60) -#define SHIFT_LSL 0x00 -#define SHIFT_LSR 0x20 -#define SHIFT_ASR 0x40 -#define SHIFT_RORRRX 0x60 - -static unsigned long ai_user; -static unsigned long ai_sys; -static unsigned long ai_skipped; -static unsigned long ai_half; -static unsigned long ai_word; -static unsigned long ai_multi; - -#ifdef CONFIG_SYSCTL -static int proc_alignment_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *p = page; - int len; - - p += sprintf(p, "User:\t\t%li\n", ai_user); - p += sprintf(p, "System:\t\t%li\n", ai_sys); - p += sprintf(p, "Skipped:\t%li\n", ai_skipped); - p += sprintf(p, "Half:\t\t%li\n", ai_half); - p += sprintf(p, "Word:\t\t%li\n", ai_word); - p += sprintf(p, "Multi:\t\t%li\n", ai_multi); - - len = (p - page) - off; - if (len < 0) - len = 0; - - *eof = (len <= count) ? 1 : 0; - *start = page + off; - - return len; -} - -/* - * This needs to be done after sysctl_init, otherwise sys/ - * will be overwritten. - */ -static int __init alignment_init(void) -{ - create_proc_read_entry("sys/debug/alignment", 0, NULL, - proc_alignment_read, NULL); - return 0; -} - -__initcall(alignment_init); -#endif /* CONFIG_SYSCTL */ - -union offset_union { - unsigned long un; - signed long sn; -}; - -#define TYPE_ERROR 0 -#define TYPE_FAULT 1 -#define TYPE_LDST 2 -#define TYPE_DONE 3 - -#define get8_unaligned_check(val,addr,err) \ - __asm__( \ - "1: ldrb %1, [%2], #1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) - -#define get8t_unaligned_check(val,addr,err) \ - __asm__( \ - "1: ldrbt %1, [%2], #1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) - -#define get16_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ - val |= v << 8; \ - if (err) \ - goto fault; \ - } while (0) - -#define put16_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v = val, a = addr; \ - __asm__( \ - "1: strb %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ - "2: strb %1, [%2]\n" \ - "3:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: mov %0, #1\n" \ - " b 3b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (v), "=&r" (a) \ - : "0" (err), "1" (v), "2" (a)); \ - if (err) \ - goto fault; \ - } while (0) - -#define __put32_unaligned_check(ins,val,addr) \ - do { \ - unsigned int err = 0, v = val, a = addr; \ - __asm__( \ - "1: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ - "2: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ - "3: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ - "4: "ins" %1, [%2]\n" \ - "5:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "6: mov %0, #1\n" \ - " b 5b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 6b\n" \ - " .long 2b, 6b\n" \ - " .long 3b, 6b\n" \ - " .long 4b, 6b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (v), "=&r" (a) \ - : "0" (err), "1" (v), "2" (a)); \ - if (err) \ - goto fault; \ - } while (0) - -#define get32_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - -#define put32_unaligned_check(val,addr) \ - __put32_unaligned_check("strb", val, addr) - -#define get32t_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8t_unaligned_check(val,a,err); \ - get8t_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - -#define put32t_unaligned_check(val,addr) \ - __put32_unaligned_check("strbt", val, addr) - -static void -do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset) -{ - if (!LDST_U_BIT(instr)) - offset.un = -offset.un; - - if (!LDST_P_BIT(instr)) - addr += offset.un; - - if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) - regs->uregs[RN_BITS(instr)] = addr; -} - -static int -do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) -{ - unsigned int rd = RD_BITS(instr); - - if ((instr & 0x01f00ff0) == 0x01000090) - goto swp; - - if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0) - goto bad; - - ai_half += 1; - - if (LDST_L_BIT(instr)) { - unsigned long val; - get16_unaligned_check(val, addr); - - /* signed half-word? */ - if (instr & 0x40) - val = (signed long)((signed short) val); - - regs->uregs[rd] = val; - } else - put16_unaligned_check(regs->uregs[rd], addr); - - return TYPE_LDST; - -swp: - printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); -bad: - return TYPE_ERROR; - -fault: - return TYPE_FAULT; -} - -static int -do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) -{ - unsigned int rd = RD_BITS(instr); - - ai_word += 1; - - if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) - goto trans; - - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], addr); - else - put32_unaligned_check(regs->uregs[rd], addr); - return TYPE_LDST; - -trans: - if (LDST_L_BIT(instr)) - get32t_unaligned_check(regs->uregs[rd], addr); - else - put32t_unaligned_check(regs->uregs[rd], addr); - return TYPE_LDST; - -fault: - return TYPE_FAULT; -} - -/* - * LDM/STM alignment handler. - * - * There are 4 variants of this instruction: - * - * B = rn pointer before instruction, A = rn pointer after instruction - * ------ increasing address -----> - * | | r0 | r1 | ... | rx | | - * PU = 01 B A - * PU = 11 B A - * PU = 00 A B - * PU = 10 A B - */ -static int -do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs) -{ - unsigned int rd, rn, correction, nr_regs, regbits; - unsigned long eaddr, newaddr; - - if (LDM_S_BIT(instr)) - goto bad; - - correction = 4; /* processor implementation defined */ - regs->ARM_pc += correction; - - ai_multi += 1; - - /* count the number of registers in the mask to be transferred */ - nr_regs = hweight16(REGMASK_BITS(instr)) * 4; - - rn = RN_BITS(instr); - newaddr = eaddr = regs->uregs[rn]; - - if (!LDST_U_BIT(instr)) - nr_regs = -nr_regs; - newaddr += nr_regs; - if (!LDST_U_BIT(instr)) - eaddr = newaddr; - - if (LDST_P_EQ_U(instr)) /* U = P */ - eaddr += 4; - - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) { - printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - show_regs(regs); - } - - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], eaddr); - else - put32_unaligned_check(regs->uregs[rd], eaddr); - eaddr += 4; - } - - if (LDST_W_BIT(instr)) - regs->uregs[rn] = newaddr; - if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15))) - regs->ARM_pc -= correction; - return TYPE_DONE; - -fault: - regs->ARM_pc -= correction; - return TYPE_FAULT; - -bad: - printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); - return TYPE_ERROR; -} - -static int -do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) -{ - union offset_union offset; - unsigned long instr, instrptr; - int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); - unsigned int type; - - if (user_mode(regs)) - goto user; - - ai_sys += 1; - - instrptr = instruction_pointer(regs); - instr = *(unsigned long *)instrptr; - - regs->ARM_pc += 4; - - switch (CODING_BITS(instr)) { - case 0x00000000: /* ldrh or strh */ - if (LDSTH_I_BIT(instr)) - offset.un = (instr & 0xf00) >> 4 | (instr & 15); - else - offset.un = regs->uregs[RM_BITS(instr)]; - handler = do_alignment_ldrhstrh; - break; - - case 0x04000000: /* ldr or str immediate */ - offset.un = OFFSET_BITS(instr); - handler = do_alignment_ldrstr; - break; - - case 0x06000000: /* ldr or str register */ - offset.un = regs->uregs[RM_BITS(instr)]; - - if (IS_SHIFT(instr)) { - unsigned int shiftval = SHIFT_BITS(instr); - - switch(SHIFT_TYPE(instr)) { - case SHIFT_LSL: - offset.un <<= shiftval; - break; - - case SHIFT_LSR: - offset.un >>= shiftval; - break; - - case SHIFT_ASR: - offset.sn >>= shiftval; - break; - - case SHIFT_RORRRX: - if (shiftval == 0) { - offset.un >>= 1; - if (regs->ARM_cpsr & CC_C_BIT) - offset.un |= 1 << 31; - } else - offset.un = offset.un >> shiftval | - offset.un << (32 - shiftval); - break; - } - } - handler = do_alignment_ldrstr; - break; - - case 0x08000000: /* ldm or stm */ - handler = do_alignment_ldmstm; - break; - - default: - goto bad; - } - - type = handler(addr, instr, regs); - - if (type == TYPE_ERROR || type == TYPE_FAULT) - goto bad_or_fault; - - if (type == TYPE_LDST) - do_alignment_finish_ldst(addr, instr, regs, offset); - - return 0; - -bad_or_fault: - if (type == TYPE_ERROR) - goto bad; - regs->ARM_pc -= 4; - /* - * We got a fault - fix it up, or die. - */ - do_bad_area(current, current->mm, addr, error_code, regs); - return 0; - -bad: - /* - * Oops, we didn't handle the instruction. - */ - printk(KERN_ERR "Alignment trap: not handling instruction " - "%08lx at [<%08lx>]\n", instr, instrptr); - ai_skipped += 1; - return 1; - -user: - set_cr(cr_no_alignment); - ai_user += 1; - return 0; -} - +extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs); #else - -#define do_alignment NULL - +#define do_alignment do_bad #endif + /* - * Some section permission faults need to be handled gracefully, for - * instance, when they happen due to a __{get,put}_user during an oops). + * Some section permission faults need to be handled gracefully. + * They can happen due to a __{get,put}_user during an oops. */ static int do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) @@ -557,73 +72,54 @@ return 1; } +/* + * This abort handler always returns "fault". + */ +static int +do_bad(unsigned long addr, int error_code, struct pt_regs *regs) +{ + return 1; +} + static const struct fsr_info { int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); int sig; - char *name; + const char *name; } fsr_info[] = { - { NULL, SIGSEGV, "vector exception" }, + { do_bad, SIGSEGV, "vector exception" }, { do_alignment, SIGILL, "alignment exception" }, - { NULL, SIGKILL, "terminal exception" }, + { do_bad, SIGKILL, "terminal exception" }, { do_alignment, SIGILL, "alignment exception" }, { do_external_fault, SIGBUS, "external abort on linefetch" }, { do_translation_fault, SIGSEGV, "section translation fault" }, { do_external_fault, SIGBUS, "external abort on linefetch" }, { do_page_fault, SIGSEGV, "page translation fault" }, { do_external_fault, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "section domain fault" }, + { do_bad, SIGSEGV, "section domain fault" }, { do_external_fault, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "page domain fault" }, - { NULL, SIGBUS, "external abort on translation" }, + { do_bad, SIGSEGV, "page domain fault" }, + { do_bad, SIGBUS, "external abort on translation" }, { do_sect_fault, SIGSEGV, "section permission fault" }, - { NULL, SIGBUS, "external abort on translation" }, + { do_bad, SIGBUS, "external abort on translation" }, { do_page_fault, SIGSEGV, "page permission fault" } }; /* - * Currently dropped down to debug level + * Dispatch a data abort to the relevant handler. */ asmlinkage void do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr) { const struct fsr_info *inf = fsr_info + (fsr & 15); -#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS) - if (addr == regs->ARM_pc) - goto sa1_weirdness; -#endif - - if (!inf->fn) - goto bad; - if (!inf->fn(addr, error_code, regs)) return; -bad: - printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", + + printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); - show_pte(current->mm, addr); force_sig(inf->sig, current); + show_pte(current->mm, addr); die_if_kernel("Oops", regs, 0); - return; - -#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS) -sa1_weirdness: - if (user_mode(regs)) { - static int first = 1; - if (first) { - printk(KERN_DEBUG "Fixing up bad data abort at %08lx\n", addr); -#ifdef CONFIG_DEBUG_ERRORS - show_pte(current->mm, addr); -#endif - } - first = 0; - return; - } - - if (!inf->fn || inf->fn(addr, error_code, regs)) - goto bad; - return; -#endif } asmlinkage void @@ -680,38 +176,13 @@ return; } -/* - * Take care of architecture specific things when placing a new PTE into - * a page table, or changing an existing PTE. Basically, there are two - * things that we need to take care of: - * - * 1. If PG_dcache_dirty is set for the page, we need to ensure - * that any cache entries for the kernels virtual memory - * range are written back to the page. - * 2. If we have multiple shared mappings of the same space in - * an object, we need to deal with the cache aliasing issues. - * - * Note that the page_table_lock will be held. - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +static void +make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page) { - struct page *page = pte_page(pte); struct vm_area_struct *mpnt; - struct mm_struct *mm; - unsigned long pgoff; - int aliases; - - if (!VALID_PAGE(page) || !page->mapping) - return; - - if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) { - unsigned long kvirt = (unsigned long)page_address(page); - cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0); - } - - mm = vma->vm_mm; - pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; - aliases = 0; + struct mm_struct *mm = vma->vm_mm; + unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; + int aliases = 0; /* * If we have any shared mappings that are in the same mm @@ -727,7 +198,7 @@ * Note that we intentionally don't mask out the VMA * that we are fixing up. */ - if (mpnt->vm_mm != mm && mpnt != vma) + if (mpnt->vm_mm != mm || mpnt == vma) continue; /* @@ -748,4 +219,31 @@ } if (aliases) adjust_pte(vma, addr); +} + +/* + * Take care of architecture specific things when placing a new PTE into + * a page table, or changing an existing PTE. Basically, there are two + * things that we need to take care of: + * + * 1. If PG_dcache_dirty is set for the page, we need to ensure + * that any cache entries for the kernels virtual memory + * range are written back to the page. + * 2. If we have multiple shared mappings of the same space in + * an object, we need to deal with the cache aliasing issues. + * + * Note that the page_table_lock will be held. + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + struct page *page = pte_page(pte); + + if (VALID_PAGE(page) && page->mapping) { + if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) { + unsigned long kvirt = (unsigned long)page_address(page); + cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0); + } + + make_coherent(vma, addr, page); + } } diff -urN linux-2.4.18/arch/arm/mm/fault-common.c linux-2.4.19-pre5/arch/arm/mm/fault-common.c --- linux-2.4.18/arch/arm/mm/fault-common.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/fault-common.c Sat Mar 30 22:55:37 2002 @@ -141,6 +141,7 @@ printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " "lr=0x%08lx (bad address=0x%08lx, code %d)\n", tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code); + show_regs(regs); #endif tsk->thread.address = addr; diff -urN linux-2.4.18/arch/arm/mm/mm-armv.c linux-2.4.19-pre5/arch/arm/mm/mm-armv.c --- linux-2.4.18/arch/arm/mm/mm-armv.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/mm-armv.c Sat Mar 30 22:55:37 2002 @@ -14,10 +14,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -224,6 +224,19 @@ unsigned long virt, length; int prot_sect, prot_pte; long off; + + if (md->prot_read && md->prot_write && + !md->cacheable && !md->bufferable) { + printk(KERN_WARNING "Security risk: creating user " + "accessible mapping for 0x%08lx at 0x%08lx\n", + md->physical, md->virtual); + } + + if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) { + printk(KERN_WARNING "MM: not creating mapping for " + "0x%08lx at 0x%08lx in user region\n", + md->physical, md->virtual); + } prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | (md->prot_read ? L_PTE_USER : 0) | diff -urN linux-2.4.18/arch/arm/mm/proc-arm1020.S linux-2.4.19-pre5/arch/arm/mm/proc-arm1020.S --- linux-2.4.18/arch/arm/mm/proc-arm1020.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/proc-arm1020.S Sat Mar 30 22:55:37 2002 @@ -56,22 +56,27 @@ * cpu_arm1020_data_abort() * * obtain information about current aborted instruction + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * - * r0 = address of aborted instruction + * r2 = address of aborted instruction + * r3 = cpsr * * Returns: * r0 = address of abort * r1 != 0 if writing * r3 = FSR + * r4 = corrupted */ .align 5 ENTRY(cpu_arm1020_data_abort) - ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r3, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r1, [r2] @ read aborted instruction + and r3, r3, #255 tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 mov pc, lr /* diff -urN linux-2.4.18/arch/arm/mm/proc-arm720.S linux-2.4.19-pre5/arch/arm/mm/proc-arm720.S --- linux-2.4.18/arch/arm/mm/proc-arm720.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/proc-arm720.S Sat Mar 30 22:55:38 2002 @@ -111,6 +111,9 @@ * : r3 = saved SPSR * * Purpose : obtain information about current aborted instruction + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * * Returns : r0 = address of abort * : r1 != 0 if writing diff -urN linux-2.4.18/arch/arm/mm/proc-arm920.S linux-2.4.19-pre5/arch/arm/mm/proc-arm920.S --- linux-2.4.18/arch/arm/mm/proc-arm920.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/proc-arm920.S Sat Mar 30 22:55:38 2002 @@ -56,22 +56,27 @@ * cpu_arm920_data_abort() * * obtain information about current aborted instruction + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * - * r0 = address of aborted instruction + * r2 = address of aborted instruction + * r3 = cpsr * * Returns: * r0 = address of abort * r1 != 0 if writing * r3 = FSR + * r4 = corrupted */ .align 5 ENTRY(cpu_arm920_data_abort) - ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r3, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r1, [r2] @ read aborted instruction + and r3, r3, #255 tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 mov pc, lr /* diff -urN linux-2.4.18/arch/arm/mm/proc-arm922.S linux-2.4.19-pre5/arch/arm/mm/proc-arm922.S --- linux-2.4.18/arch/arm/mm/proc-arm922.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/arm/mm/proc-arm922.S Sat Mar 30 22:55:38 2002 @@ -0,0 +1,657 @@ +/* + * linux/arch/arm/mm/arm922.S: MMU functions for ARM922 + * + * Copyright (C) 1999,2000 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2001 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm922. + */ +#include +#include +#include +#include +#include +#include + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 8192 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm922_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm922_data_abort) + ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r1, r1, lsr #21 @ C = bit 20 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + sbc r1, r1, r1 @ r1 = C - 1 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm922_check_bugs() + */ +ENTRY(cpu_arm922_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm922_proc_init() + */ +ENTRY(cpu_arm922_proc_init) + mov pc, lr + +/* + * cpu_arm922_proc_fin() + */ +ENTRY(cpu_arm922_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm922_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm922_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm922_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm922_do_idle() + */ + .align 5 +ENTRY(cpu_arm922_do_idle) +#if defined(CONFIG_CPU_ARM922_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm922_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm922_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm922_cache_clean_invalidate_all_r2: + mov ip, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +/* + * 'Clean & Invalidate whole DCache' + * Re-written to use Index Ops. + * Uses registers r1, r3 and ip + */ + mov r1, #3 << 5 @ 4 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm922_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM + bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm922_cache_clean_invalidate_all_r2 +1: teq r2, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#endif + cmp r0, r1 + blt 1b + + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm922_flush_ram_page) + mov r1, #PAGESIZE +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE +#else +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm922_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm922_dcache_invalidate_range) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + tst r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry +#endif @ clean D entry + bic r0, r0, #DCACHELINESIZE - 1 + bic r1, r1, #DCACHELINESIZE - 1 +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm922_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_range) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_arm922_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE -1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bpl 1b +#endif + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_page) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b +#endif + mov pc, lr + +/* + * cpu_arm922_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_entry) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm922_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * This is a little misleading, it is not intended to clean out + * the i-cache but to make sure that any data written to the + * range is made consistant. This means that when we execute code + * in that region, everything works as we expect. + * + * This generally means writing back data in the Dcache and + * write buffer and flushing the Icache over that region + * + * start: virtual start address + * end: virtual end address + * + * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to + * loop twice, once for i-cache, once for d-cache) + */ + .align 5 +ENTRY(cpu_arm922_icache_invalidate_range) + bic r0, r0, #ICACHELINESIZE - 1 @ Safety check + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + bgt cpu_arm922_cache_clean_invalidate_all_r2 + + bic r1, r1, #ICACHELINESIZE - 1 + add r1, r1, #ICACHELINESIZE + +1: mcr p15, 0, r0, c7, c5, 1 @ Clean I entry + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + add r0, r0, #ICACHELINESIZE + subs r1, r1, #ICACHELINESIZE + bne 1b + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(cpu_arm922_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_arm922_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm922_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + + mov r3, #PAGESIZE + sub r3, r3, #1 + bic r0, r0, r3 + bic r1, r1, r3 + +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm922_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm922_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm922_set_pgd) + mov ip, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +@ && 'Clean & Invalidate whole DCache' +@ && Re-written to use Index Ops. +@ && Uses registers r1, r3 and ip + + mov r1, #3 << 5 @ 4 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm922_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm922_set_pmd) +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm922_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + eor r3, r2, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "ARM/ALTERA" +ENTRY(cpu_arm922_name) + .ascii "Arm922T" +#if defined(CONFIG_CPU_ARM922_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM922_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM922_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM922_WRITETHROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm922_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + @ VI ZFRS BLDP WCAM + bic r0, r0, #0x0e00 + bic r0, r0, #0x0002 + bic r0, r0, #0x000c + bic r0, r0, #0x1000 @ ...0 000. .... 000. +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 + orr r0, r0, #0x2100 @ ..1. ...1 ..11 ...1 + +#ifdef CONFIG_CPU_ARM922_D_CACHE_ON + orr r0, r0, #0x0004 @ .... .... .... .1.. +#endif +#ifdef CONFIG_CPU_ARM922_I_CACHE_ON + orr r0, r0, #0x1000 @ ...1 .... .... .... +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm922_processor_functions, #object +arm922_processor_functions: + .word cpu_arm922_data_abort + .word cpu_arm922_check_bugs + .word cpu_arm922_proc_init + .word cpu_arm922_proc_fin + .word cpu_arm922_reset + .word cpu_arm922_do_idle + + /* cache */ + .word cpu_arm922_cache_clean_invalidate_all + .word cpu_arm922_cache_clean_invalidate_range + .word cpu_arm922_flush_ram_page + + /* dcache */ + .word cpu_arm922_dcache_invalidate_range + .word cpu_arm922_dcache_clean_range + .word cpu_arm922_dcache_clean_page + .word cpu_arm922_dcache_clean_entry + + /* icache */ + .word cpu_arm922_icache_invalidate_range + .word cpu_arm922_icache_invalidate_page + + /* tlb */ + .word cpu_arm922_tlb_invalidate_all + .word cpu_arm922_tlb_invalidate_range + .word cpu_arm922_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm922_set_pgd + .word cpu_arm922_set_pmd + .word cpu_arm922_set_pte + .size arm922_processor_functions, . - arm922_processor_functions + + .type cpu_arm922_info, #object +cpu_arm922_info: + .long cpu_manu_name + .long cpu_arm922_name + .size cpu_arm922_info, . - cpu_arm922_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm922_proc_info,#object +__arm922_proc_info: + .long 0x41009220 + .long 0xff00fff0 + .long 0x00000c1e @ mmuflags + b __arm922_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm922_info + .long arm922_processor_functions + .size __arm922_proc_info, . - __arm922_proc_info diff -urN linux-2.4.18/arch/arm/mm/proc-arm926.S linux-2.4.19-pre5/arch/arm/mm/proc-arm926.S --- linux-2.4.18/arch/arm/mm/proc-arm926.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/proc-arm926.S Sat Mar 30 22:55:38 2002 @@ -56,35 +56,39 @@ * cpu_arm926_data_abort() * * obtain information about current aborted instruction + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * * Inputs: - * r0 = address of abort - * r1 = cpsr of abort + * r2 = address of abort + * r3 = cpsr of abort * * Returns: * r0 = address of abort * r1 != 0 if writing * r3 = FSR + * r4 = corrupted */ .align 5 ENTRY(cpu_arm926_data_abort) - tst r1, #1<<24 @ Check for Jbit (NE -> found) - movne r1, #-1 @ Mark as writing + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r4, c5, c0, 0 @ get FSR + + tst r3, #1<<24 @ Check for Jbit (NE -> found) + movne r3, #-1 @ Mark as writing bne 2f - tst r1, #1<<5 @ Check for Thumb-bit (NE -> found) - ldrneh r1, [r0] @ Read aborted Thumb instruction + tst r3, #1<<5 @ Check for Thumb-bit (NE -> found) + ldrneh r1, [r2] @ Read aborted Thumb instruction tstne r1, r1, lsr #12 @ C = bit 11 - ldreq r1, [r0] @ Read aborted ARM instruction + ldreq r1, [r2] @ Read aborted ARM instruction tsteq r1, r1, lsr #21 @ C = bit 20 sbc r1, r1, r1 @ r1 = C - 1 2: - mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r3, r3, #255 - mrc p15, 0, r0, c6, c0, 0 @ get FAR - + and r3, r4, #255 mov pc, lr /* @@ -193,10 +197,9 @@ .align 5 ENTRY(cpu_arm926_cache_clean_invalidate_range) bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM - bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM sub r3, r1, r0 cmp r3, #MAX_AREA_SIZE - bgt cpu_arm926_cache_clean_invalidate_all_r2 + bhi cpu_arm926_cache_clean_invalidate_all_r2 1: teq r2, #0 #ifdef CONFIG_CPU_ARM926_WRITETHROUGH @@ -216,7 +219,7 @@ #endif cmp r0, r1 - blt 1b + blo 1b mcr p15, 0, r1, c7, c10, 4 @ drain WB @@ -267,14 +270,13 @@ tst r0, #DCACHELINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry tst r1, #DCACHELINESIZE - 1 - mcrne p15, 0, r1, c7, c10, 1 -#endif @ clean D entry + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry +#endif bic r0, r0, #DCACHELINESIZE - 1 - bic r1, r1, #DCACHELINESIZE - 1 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry add r0, r0, #DCACHELINESIZE cmp r0, r1 - blt 1b + blo 1b mov pc, lr /* @@ -291,18 +293,15 @@ ENTRY(cpu_arm926_dcache_clean_range) #ifndef CONFIG_CPU_ARM926_WRITETHROUGH bic r0, r0, #DCACHELINESIZE - 1 - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE mov r2, #0 - bgt cpu_arm926_cache_clean_invalidate_all_r2 - - bic r1, r1, #DCACHELINESIZE -1 - add r1, r1, #DCACHELINESIZE + bhi cpu_arm926_cache_clean_invalidate_all_r2 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #DCACHELINESIZE - subs r1, r1, #DCACHELINESIZE - bpl 1b + cmp r0, r1 + blo 1b #endif mcr p15, 0, r2, c7, c10, 4 @ drain WB mov pc, lr @@ -354,7 +353,12 @@ /* * cpu_arm926_icache_invalidate_range(start, end) * - * invalidate a range of virtual addresses from the Icache + * This *is not* just icache. It is to make data written to memory + * consistent such that instructions fetched from the region are what + * we expect. + * + * This is typically used after we have copied a module into kernel space, + * and we're about to start executing code from that module. * * start: virtual start address * end: virtual end address @@ -362,17 +366,14 @@ .align 5 ENTRY(cpu_arm926_icache_invalidate_range) bic r0, r0, #DCACHELINESIZE - 1 @ Safety check - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE - bgt cpu_arm926_cache_clean_invalidate_all_r2 - - bic r1, r1, #DCACHELINESIZE - 1 - add r1, r1, #DCACHELINESIZE + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bhi cpu_arm926_cache_clean_invalidate_all_r2 1: mcr p15, 0, r0, c7, c5, 1 @ clean I entries add r0, r0, #DCACHELINESIZE - subs r1, r1, #DCACHELINESIZE - bne 1b + cmp r0, r1 + blo 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB @@ -410,16 +411,14 @@ mov r3, #0 mcr p15, 0, r3, c7, c10, 4 @ drain WB - mov r3, #PAGESIZE - sub r3, r3, #1 - bic r0, r0, r3 - bic r1, r1, r3 + bic r0, r0, #(PAGESIZE - 1) & 0x00ff + bic r0, r0, #(PAGESIZE - 1) & 0xff00 1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry add r0, r0, #PAGESIZE cmp r0, r1 - blt 1b + blo 1b mov pc, lr /* diff -urN linux-2.4.18/arch/arm/mm/proc-sa110.S linux-2.4.19-pre5/arch/arm/mm/proc-sa110.S --- linux-2.4.18/arch/arm/mm/proc-sa110.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/mm/proc-sa110.S Sat Mar 30 22:55:38 2002 @@ -69,24 +69,29 @@ /* * cpu_sa110_data_abort() * - * obtain information about current aborted instruction + * obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * - * r0 = address of aborted instruction + * r2 = address of aborted instruction + * r3 = cpsr * * Returns: * r0 = address of abort * r1 != 0 if writing * r3 = FSR + * r4 = corrupted */ .align 5 ENTRY(cpu_sa110_data_abort) ENTRY(cpu_sa1100_data_abort) - ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r3, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r1, [r2] @ read aborted instruction + and r3, r3, #255 tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 mov pc, lr /* diff -urN linux-2.4.18/arch/arm/nwfpe/ARM-gcc.h linux-2.4.19-pre5/arch/arm/nwfpe/ARM-gcc.h --- linux-2.4.18/arch/arm/nwfpe/ARM-gcc.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/ARM-gcc.h Sat Mar 30 22:55:38 2002 @@ -1,11 +1,3 @@ - -/* -------------------------------------------------------------------------------- -One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. -------------------------------------------------------------------------------- -*/ -#define LITTLEENDIAN - /* ------------------------------------------------------------------------------- The macro `BITS64' can be defined to indicate that 64-bit integer types are diff -urN linux-2.4.18/arch/arm/nwfpe/ChangeLog linux-2.4.19-pre5/arch/arm/nwfpe/ChangeLog --- linux-2.4.18/arch/arm/nwfpe/ChangeLog Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/ChangeLog Sat Mar 30 22:55:38 2002 @@ -1,3 +1,26 @@ +2002-01-19 Russell King + + * fpa11.h - Add documentation + - remove userRegisters pointer from this structure. + - add new method to obtain integer register values. + * softfloat.c - Remove float128 + * softfloat.h - Remove float128 + * softfloat-specialize - Remove float128 + + * The FPA11 structure is not a kernel-specific data structure. + It is used by users of ptrace to examine the values of the + floating point registers. Therefore, any changes to the + FPA11 structure (size or position of elements contained + within) have to be well thought out. + + * Since 128-bit float requires the FPA11 structure to change + size, it has been removed. 128-bit float is currently unused, + and needs various things to be re-worked so that we won't + overflow the available space in the task structure. + + * The changes are designed to break any patch that goes on top + of this code, so that the authors properly review their changes. + 1999-08-19 Scott Bambrough * fpmodule.c - Changed version number to 0.95 diff -urN linux-2.4.18/arch/arm/nwfpe/double_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/double_cpdo.c --- linux-2.4.18/arch/arm/nwfpe/double_cpdo.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/double_cpdo.c Sat Mar 30 22:55:38 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" float64 float64_exp(float64 Fm); float64 float64_ln(float64 Fm); @@ -165,8 +165,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fDouble = - int32_to_float64(float64_to_int32(rFm)); + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); break; case SQT_CODE: diff -urN linux-2.4.18/arch/arm/nwfpe/entry.S linux-2.4.19-pre5/arch/arm/nwfpe/entry.S --- linux-2.4.18/arch/arm/nwfpe/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/entry.S Sat Mar 30 22:55:38 2002 @@ -50,11 +50,8 @@ This routine does three things: -1) It saves SP into a variable called userRegisters. The kernel has -created a struct pt_regs on the stack and saved the user registers -into it. See /usr/include/asm/proc/ptrace.h for details. The -emulator code uses userRegisters as the base of an array of words from -which the contents of the registers can be extracted. +1) The kernel has created a struct pt_regs on the stack and saved the +user registers into it. See inclue/asm-arm/proc/ptrace.h for details. 2) It calls EmulateAll to emulate a floating point instruction. EmulateAll returns 1 if the emulation was successful, or 0 if not. @@ -73,21 +70,16 @@ .globl nwfpe_enter nwfpe_enter: - /* ?? Could put userRegisters and fpa11 into fixed regs during - emulation. This would reduce load/store overhead at the expense - of stealing two regs from the register allocator. Not sure if - it's worth it. */ - str sp, [r10] @ Store the user registers pointer in the fpa11 structure. - mov r4, sp @ use r4 for local pointer - mov r10, lr @ save the failure-return addresses + mov r4, lr @ save the failure-return addresses + mov sl, sp @ we access the registers via 'sl' - ldr r5, [r4, #60] @ get contents of PC; + ldr r5, [sp, #60] @ get contents of PC; sub r8, r5, #4 .Lx2: ldrt r0, [r8] @ get actual instruction into r0 emulate: bl EmulateAll @ emulate the instruction cmp r0, #0 @ was emulation successful - moveq pc, r10 @ no, return failure + moveq pc, r4 @ no, return failure next: .Lx1: ldrt r6, [r5], #4 @ get the next instruction and @@ -99,10 +91,10 @@ teqne r2, #0x0E000000 movne pc, r9 @ return ok if not a fp insn - str r5, [r4, #60] @ update PC copy in regs + str r5, [sp, #60] @ update PC copy in regs mov r0, r6 @ save a copy - ldr r1, [r4, #64] @ fetch the condition codes + ldr r1, [sp, #64] @ fetch the condition codes bl checkCondition @ check the condition cmp r0, #0 @ r0 = 0 ==> condition failed diff -urN linux-2.4.18/arch/arm/nwfpe/entry26.S linux-2.4.19-pre5/arch/arm/nwfpe/entry26.S --- linux-2.4.18/arch/arm/nwfpe/entry26.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/entry26.S Sat Mar 30 22:55:38 2002 @@ -65,18 +65,8 @@ .globl nwfpe_enter nwfpe_enter: - ldr r4, =userRegisters - str sp, [r4] @ save pointer to user regs - - mov r10, sp, lsr #13 @ find workspace - mov r10, r10, lsl #13 - add r10, r10, #TSS_FPESAVE - - ldr r4, =fpa11 - str r10, [r4] @ store pointer to our state - mov r4, sp @ use r4 for local pointer - - ldr r5, [r4, #60] @ get contents of PC + mov sl, sp + ldr r5, [sp, #60] @ get contents of PC bic r5, r5, #0xfc000003 ldr r0, [r5, #-4] @ get actual instruction into r0 bl EmulateAll @ emulate the instruction @@ -93,10 +83,10 @@ teqne r2, #0x0E000000 bne ret_from_exception @ return ok if not a fp insn - ldr r9, [r4, #60] @ get new condition codes + ldr r9, [sp, #60] @ get new condition codes and r9, r9, #0xfc000003 orr r7, r5, r9 - str r7, [r4, #60] @ update PC copy in regs + str r7, [sp, #60] @ update PC copy in regs mov r0, r6 @ save a copy mov r1, r9 @ fetch the condition codes diff -urN linux-2.4.18/arch/arm/nwfpe/extended_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/extended_cpdo.c --- linux-2.4.18/arch/arm/nwfpe/extended_cpdo.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/extended_cpdo.c Sat Mar 30 22:55:38 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" floatx80 floatx80_exp(floatx80 Fm); floatx80 floatx80_ln(floatx80 Fm); @@ -157,8 +157,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fExtended = - int32_to_floatx80(floatx80_to_int32(rFm)); + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); break; case SQT_CODE: diff -urN linux-2.4.18/arch/arm/nwfpe/fpa11.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.c --- linux-2.4.18/arch/arm/nwfpe/fpa11.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.c Sat Mar 30 22:55:38 2002 @@ -19,14 +19,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include - #include "fpa11.h" + #include "fpopcode.h" #include "fpmodule.h" #include "fpmodule.inl" +#include + /* forward declarations */ unsigned int EmulateCPDO(const unsigned int); unsigned int EmulateCPDT(const unsigned int); @@ -56,6 +57,7 @@ void SetRoundingMode(const unsigned int opcode) { #if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); fpa11->fpcr &= ~MASK_ROUNDING_MODE; #endif switch (opcode & MASK_ROUNDING_MODE) @@ -94,6 +96,7 @@ void SetRoundingPrecision(const unsigned int opcode) { #if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; #endif switch (opcode & MASK_ROUNDING_PRECISION) diff -urN linux-2.4.18/arch/arm/nwfpe/fpa11.h linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.h --- linux-2.4.18/arch/arm/nwfpe/fpa11.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.h Sat Mar 30 22:55:38 2002 @@ -22,45 +22,67 @@ #ifndef __FPA11_H__ #define __FPA11_H__ -/* includes */ -#include "fpsr.h" /* FP control and status register definitions */ -#include "softfloat.h" +#define GET_FPA11() ((FPA11 *)(¤t->thread.fpstate)) + +/* + * The processes registers are always at the very top of the 8K + * stack+task struct. Use the same method as 'current' uses to + * reach them. + */ +register unsigned int *user_registers asm("sl"); + +#define GET_USERREG() (user_registers) /* Need task_struct */ #include +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + #define typeNone 0x00 #define typeSingle 0x01 #define typeDouble 0x02 #define typeExtended 0x03 +/* + * This must be no more and no less than 12 bytes. + */ typedef union tagFPREG { - float32 fSingle; - float64 fDouble; floatx80 fExtended; + float64 fDouble; + float32 fSingle; } FPREG; -/* FPA11 device model */ +/* + * FPA11 device model. + * + * This structure is exported to user space. Do not re-order. + * Only add new stuff to the end, and do not change the size of + * any element. Elements of this structure are used by user + * space, and must match struct user_fp in include/asm-arm/user.h. + * We include the byte offsets below for documentation purposes. + * + * The size of this structure and FPREG are checked by fpmodule.c + * on initialisation. If the rules have been broken, NWFPE will + * not initialise. + */ typedef struct tagFPA11 { - unsigned int *userRegisters; - FPREG fpreg[8]; /* 8 floating point registers */ - FPSR fpsr; /* floating point status register */ - FPCR fpcr; /* floating point control register */ - unsigned char fType[8]; /* type of floating point value held in - floating point registers. One of none - single, double or extended. */ - int initflag; /* this is special. The kernel guarantees - to set it to 0 when a thread is launched, - so we can use it to detect whether this - instance of the emulator needs to be - initialised. */ +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ } FPA11; extern void resetFPA11(void); extern void SetRoundingMode(const unsigned int); extern void SetRoundingPrecision(const unsigned int); - -#define GET_FPA11() ((FPA11 *)(¤t->thread.fpstate)) -#define GET_USERREG() (GET_FPA11()->userRegisters) #endif diff -urN linux-2.4.18/arch/arm/nwfpe/fpa11_cpdt.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cpdt.c --- linux-2.4.18/arch/arm/nwfpe/fpa11_cpdt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cpdt.c Sat Mar 30 22:55:38 2002 @@ -20,9 +20,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" #include "fpmodule.h" #include "fpmodule.inl" diff -urN linux-2.4.18/arch/arm/nwfpe/fpa11_cprt.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cprt.c --- linux-2.4.18/arch/arm/nwfpe/fpa11_cprt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cprt.c Sat Mar 30 22:55:38 2002 @@ -20,10 +20,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "milieu.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" #include "fpa11.inl" #include "fpmodule.h" #include "fpmodule.inl" @@ -82,8 +82,7 @@ unsigned int nRc = 1; SetRoundingMode(opcode); - SetRoundingPrecision(opcode); - + switch (opcode & MASK_ROUNDING_PRECISION) { case ROUND_SINGLE: diff -urN linux-2.4.18/arch/arm/nwfpe/fpmodule.c linux-2.4.19-pre5/arch/arm/nwfpe/fpmodule.c --- linux-2.4.18/arch/arm/nwfpe/fpmodule.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpmodule.c Sat Mar 30 22:55:38 2002 @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" + #include #include #include @@ -36,7 +38,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpmodule.h" -#include "fpa11.h" #include "fpa11.inl" /* kernel symbols required for signal handling */ @@ -83,6 +84,11 @@ { if (sizeof(FPA11) > sizeof(union fp_state)) { printk(KERN_ERR "nwfpe: bad structure size\n"); + return -EINVAL; + } + + if (sizeof(FPREG) != 12) { + printk(KERN_ERR "nwfpe: bad register size\n"); return -EINVAL; } diff -urN linux-2.4.18/arch/arm/nwfpe/fpopcode.c linux-2.4.19-pre5/arch/arm/nwfpe/fpopcode.c --- linux-2.4.18/arch/arm/nwfpe/fpopcode.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/fpopcode.c Sat Mar 30 22:55:38 2002 @@ -19,10 +19,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" #include "fpsr.h" -#include "fpa11.h" #include "fpmodule.h" #include "fpmodule.inl" diff -urN linux-2.4.18/arch/arm/nwfpe/single_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/single_cpdo.c --- linux-2.4.18/arch/arm/nwfpe/single_cpdo.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/single_cpdo.c Sat Mar 30 22:55:38 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" float32 float32_exp(float32 Fm); float32 float32_ln(float32 Fm); @@ -139,8 +139,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fSingle = - int32_to_float32(float32_to_int32(rFm)); + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); break; case SQT_CODE: diff -urN linux-2.4.18/arch/arm/nwfpe/softfloat-specialize linux-2.4.19-pre5/arch/arm/nwfpe/softfloat-specialize --- linux-2.4.18/arch/arm/nwfpe/softfloat-specialize Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat-specialize Sat Mar 30 22:55:38 2002 @@ -364,108 +364,3 @@ } #endif - -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -The pattern for a default generated quadruple-precision NaN. The `high' and -`low' values hold the most- and least-significant bits, respectively. -------------------------------------------------------------------------------- -*/ -#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF ) -#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is a NaN; -otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float128_is_nan( float128 a ) -{ - - return - ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) - && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is a -signaling NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float128_is_signaling_nan( float128 a ) -{ - - return - ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) - && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the quadruple-precision floating-point NaN -`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid -exception is raised. -------------------------------------------------------------------------------- -*/ -static commonNaNT float128ToCommonNaN( float128 a ) -{ - commonNaNT z; - - if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); - z.sign = a.high>>63; - shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the canonical NaN `a' to the quadruple- -precision floating-point format. -------------------------------------------------------------------------------- -*/ -static float128 commonNaNToFloat128( commonNaNT a ) -{ - float128 z; - - shift128Right( a.high, a.low, 16, &z.high, &z.low ); - z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); - return z; - -} - -/* -------------------------------------------------------------------------------- -Takes two quadruple-precision floating-point values `a' and `b', one of -which is a NaN, and returns the appropriate NaN result. If either `a' or -`b' is a signaling NaN, the invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static float128 propagateFloat128NaN( float128 a, float128 b ) -{ - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - - aIsNaN = float128_is_nan( a ); - aIsSignalingNaN = float128_is_signaling_nan( a ); - bIsNaN = float128_is_nan( b ); - bIsSignalingNaN = float128_is_signaling_nan( b ); - a.high |= LIT64( 0x0000800000000000 ); - b.high |= LIT64( 0x0000800000000000 ); - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); - if ( aIsNaN ) { - return ( aIsSignalingNaN & bIsNaN ) ? b : a; - } - else { - return b; - } - -} - -#endif - diff -urN linux-2.4.18/arch/arm/nwfpe/softfloat.c linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.c --- linux-2.4.18/arch/arm/nwfpe/softfloat.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.c Sat Mar 30 22:55:39 2002 @@ -28,6 +28,7 @@ =============================================================================== */ +#include "fpa11.h" #include "milieu.h" #include "softfloat.h" @@ -753,277 +754,6 @@ #endif -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -Returns the least-significant 64 fraction bits of the quadruple-precision -floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE bits64 extractFloat128Frac1( float128 a ) -{ - - return a.low; - -} - -/* -------------------------------------------------------------------------------- -Returns the most-significant 48 fraction bits of the quadruple-precision -floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE bits64 extractFloat128Frac0( float128 a ) -{ - - return a.high & LIT64( 0x0000FFFFFFFFFFFF ); - -} - -/* -------------------------------------------------------------------------------- -Returns the exponent bits of the quadruple-precision floating-point value -`a'. -------------------------------------------------------------------------------- -*/ -INLINE int32 extractFloat128Exp( float128 a ) -{ - - return ( a.high>>48 ) & 0x7FFF; - -} - -/* -------------------------------------------------------------------------------- -Returns the sign bit of the quadruple-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE flag extractFloat128Sign( float128 a ) -{ - - return a.high>>63; - -} - -/* -------------------------------------------------------------------------------- -Normalizes the subnormal quadruple-precision floating-point value -represented by the denormalized significand formed by the concatenation of -`aSig0' and `aSig1'. The normalized exponent is stored at the location -pointed to by `zExpPtr'. The most significant 49 bits of the normalized -significand are stored at the location pointed to by `zSig0Ptr', and the -least significant 64 bits of the normalized significand are stored at the -location pointed to by `zSig1Ptr'. -------------------------------------------------------------------------------- -*/ -static void - normalizeFloat128Subnormal( - bits64 aSig0, - bits64 aSig1, - int32 *zExpPtr, - bits64 *zSig0Ptr, - bits64 *zSig1Ptr - ) -{ - int8 shiftCount; - - if ( aSig0 == 0 ) { - shiftCount = countLeadingZeros64( aSig1 ) - 15; - if ( shiftCount < 0 ) { - *zSig0Ptr = aSig1>>( - shiftCount ); - *zSig1Ptr = aSig1<<( shiftCount & 63 ); - } - else { - *zSig0Ptr = aSig1<>= shiftCount; - z = aSig0; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_exception_flags |= float_flag_invalid; - return aSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( ( aSig0<>1, &z.high, &z.low ); - if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; - } - else { - if ( (sbits64) z.low < 0 ) { - ++z.high; - if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; - } - } - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat128Sign( z ) - ^ ( roundingMode == float_round_up ) ) { - add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); - } - } - z.low &= ~ roundBitsMask; - } - else { - if ( aExp <= 0x3FFE ) { - if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; - float_exception_flags |= float_flag_inexact; - aSign = extractFloat128Sign( a ); - switch ( float_rounding_mode ) { - case float_round_nearest_even: - if ( ( aExp == 0x3FFE ) - && ( extractFloat128Frac0( a ) - | extractFloat128Frac1( a ) ) - ) { - return packFloat128( aSign, 0x3FFF, 0, 0 ); - } - break; - case float_round_down: - return - aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) - : packFloat128( 0, 0, 0, 0 ); - case float_round_up: - return - aSign ? packFloat128( 1, 0, 0, 0 ) - : packFloat128( 0, 0x3FFF, 0, 0 ); - } - return packFloat128( aSign, 0, 0, 0 ); - } - lastBitMask = 1; - lastBitMask <<= 0x402F - aExp; - roundBitsMask = lastBitMask - 1; - z.low = 0; - z.high = a.high; - roundingMode = float_rounding_mode; - if ( roundingMode == float_round_nearest_even ) { - z.high += lastBitMask>>1; - if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { - z.high &= ~ lastBitMask; - } - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat128Sign( z ) - ^ ( roundingMode == float_round_up ) ) { - z.high |= ( a.low != 0 ); - z.high += roundBitsMask; - } - } - z.high &= ~ roundBitsMask; - } - if ( ( z.low != a.low ) || ( z.high != a.high ) ) { - float_exception_flags |= float_flag_inexact; - } - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the absolute values of the quadruple-precision -floating-point values `a' and `b'. If `zSign' is true, the sum is negated -before being returned. `zSign' is ignored if the result is a NaN. The -addition is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float128 addFloat128Sigs( float128 a, float128 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - int32 expDiff; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - if ( 0 < expDiff ) { - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= LIT64( 0x0001000000000000 ); - } - shift128ExtraRightJamming( - bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= LIT64( 0x0001000000000000 ); - } - shift128ExtraRightJamming( - aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); - zExp = bExp; - } - else { - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN( a, b ); - } - return a; - } - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); - zSig2 = 0; - zSig0 |= LIT64( 0x0002000000000000 ); - zExp = aExp; - goto shiftRight1; - } - aSig0 |= LIT64( 0x0001000000000000 ); - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - --zExp; - if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; - ++zExp; - shiftRight1: - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - roundAndPack: - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the absolute values of the quadruple- -precision floating-point values `a' and `b'. If `zSign' is true, the -difference is negated before being returned. `zSign' is ignored if the -result is a NaN. The subtraction is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float128 subFloat128Sigs( float128 a, float128 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; - int32 expDiff; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); - shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN( a, b ); - } - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - if ( bSig0 < aSig0 ) goto aBigger; - if ( aSig0 < bSig0 ) goto bBigger; - if ( bSig1 < aSig1 ) goto aBigger; - if ( aSig1 < bSig1 ) goto bBigger; - return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 ); - bExpBigger: - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= LIT64( 0x4000000000000000 ); - } - shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - bSig0 |= LIT64( 0x4000000000000000 ); - bBigger: - sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= LIT64( 0x4000000000000000 ); - } - shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); - aSig0 |= LIT64( 0x4000000000000000 ); - aBigger: - sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - zExp = aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the quadruple-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_add( float128 a, float128 b ) -{ - flag aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return addFloat128Sigs( a, b, aSign ); - } - else { - return subFloat128Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the quadruple-precision floating-point -values `a' and `b'. The operation is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_sub( float128 a, float128 b ) -{ - flag aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return subFloat128Sigs( a, b, aSign ); - } - else { - return addFloat128Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of multiplying the quadruple-precision floating-point -values `a' and `b'. The operation is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_mul( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( ( aSig0 | aSig1 ) - || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { - return propagateFloat128NaN( a, b ); - } - if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - zExp = aExp + bExp - 0x4000; - aSig0 |= LIT64( 0x0001000000000000 ); - shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); - mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); - add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zSig2 |= ( zSig3 != 0 ); - if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - ++zExp; - } - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of dividing the quadruple-precision floating-point value -`a' by the corresponding value `b'. The operation is performed according to -the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_div( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - goto invalid; - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign, 0, 0, 0 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) { - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - float_raise( float_flag_divbyzero ); - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - zExp = aExp - bExp + 0x3FFD; - shortShift128Left( - aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); - shortShift128Left( - bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); - if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { - shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); - ++zExp; - } - zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); - mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); - sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); - } - zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); - if ( ( zSig1 & 0x3FFF ) <= 4 ) { - mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); - sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the remainder of the quadruple-precision floating-point value `a' -with respect to the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_rem( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, expDiff; - bits64 aSig0, aSig1, bSig0, bSig1; - bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1; - bits64 sigMean1; - sbits64 sigMean0; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - if ( aExp == 0x7FFF ) { - if ( ( aSig0 | aSig1 ) - || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { - return propagateFloat128NaN( a, b ); - } - goto invalid; - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return a; - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - expDiff = aExp - bExp; - if ( expDiff < -1 ) return a; - shortShift128Left( - aSig0 | LIT64( 0x0001000000000000 ), - aSig1, - 15 - ( expDiff < 0 ), - &aSig0, - &aSig1 - ); - shortShift128Left( - bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); - q = le128( bSig0, bSig1, aSig0, aSig1 ); - if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); - expDiff -= 64; - while ( 0 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig0 ); - q = ( 4 < q ) ? q - 4 : 0; - mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); - shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); - shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); - sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); - expDiff -= 61; - } - if ( -64 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig0 ); - q = ( 4 < q ) ? q - 4 : 0; - q >>= - expDiff; - shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); - expDiff += 52; - if ( expDiff < 0 ) { - shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - } - else { - shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); - } - mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); - sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); - } - else { - shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); - shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); - } - do { - alternateASig0 = aSig0; - alternateASig1 = aSig1; - ++q; - sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); - } while ( 0 <= (sbits64) aSig0 ); - add128( - aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); - if ( ( sigMean0 < 0 ) - || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { - aSig0 = alternateASig0; - aSig1 = alternateASig1; - } - zSign = ( (sbits64) aSig0 < 0 ); - if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); - return - normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the square root of the quadruple-precision floating-point value `a'. -The operation is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_sqrt( float128 a ) -{ - flag aSign; - int32 aExp, zExp; - bits64 aSig0, aSig1, zSig0, zSig1, zSig2; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; - bits64 shiftedRem0, shiftedRem1; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a ); - if ( ! aSign ) return a; - goto invalid; - } - if ( aSign ) { - if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; - aSig0 |= LIT64( 0x0001000000000000 ); - zSig0 = estimateSqrt32( aExp, aSig0>>17 ); - zSig0 <<= 31; - shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); - zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; - if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); - shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); - mul64To128( zSig0, zSig0, &term0, &term1 ); - sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - shortShift128Left( 0, zSig0, 1, &term0, &term1 ); - term1 |= 1; - add128( rem0, rem1, term0, term1, &rem0, &rem1 ); - } - shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); - zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); - if ( ( zSig1 & 0x3FFF ) <= 5 ) { - if ( zSig1 == 0 ) zSig1 = 1; - mul64To128( zSig0, zSig1, &term1, &term2 ); - shortShift128Left( term1, term2, 1, &term1, &term2 ); - sub128( rem1, 0, term1, term2, &rem1, &rem2 ); - mul64To128( zSig1, zSig1, &term2, &term3 ); - sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); - term3 |= 1; - add192( - rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); - return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is equal to -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_eq( float128 a, float128 b ) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -or equal to the corresponding value `b', and 0 otherwise. The comparison -is performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_le( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_lt( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is equal to -the corresponding value `b', and 0 otherwise. The invalid exception is -raised if either operand is a NaN. Otherwise, the comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_eq_signaling( float128 a, float128 b ) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -cause an exception. Otherwise, the comparison is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_le_quiet( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -exception. Otherwise, the comparison is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_lt_quiet( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return diff -urN linux-2.4.18/arch/arm/nwfpe/softfloat.h linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.h --- linux-2.4.18/arch/arm/nwfpe/softfloat.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.h Sat Mar 30 22:55:39 2002 @@ -37,12 +37,10 @@ The macro `FLOATX80' must be defined to enable the extended double-precision floating-point format `floatx80'. If this macro is not defined, the `floatx80' type will not be defined, and none of the functions that either -input or output the `floatx80' type will be defined. The same applies to -the `FLOAT128' macro and the quadruple-precision format `float128'. +input or output the `floatx80' type will be defined. ------------------------------------------------------------------------------- */ #define FLOATX80 -/* #define FLOAT128 */ /* ------------------------------------------------------------------------------- @@ -51,17 +49,10 @@ */ typedef unsigned long int float32; typedef unsigned long long float64; -#ifdef FLOATX80 typedef struct { unsigned short high; unsigned long long low; } floatx80; -#endif -#ifdef FLOAT128 -typedef struct { - unsigned long long high, low; -} float128; -#endif /* ------------------------------------------------------------------------------- @@ -131,9 +122,6 @@ #ifdef FLOATX80 floatx80 int32_to_floatx80( signed int ); #endif -#ifdef FLOAT128 -float128 int32_to_float128( signed int ); -#endif /* ------------------------------------------------------------------------------- @@ -146,9 +134,6 @@ #ifdef FLOATX80 floatx80 float32_to_floatx80( float32 ); #endif -#ifdef FLOAT128 -float128 float32_to_float128( float32 ); -#endif /* ------------------------------------------------------------------------------- @@ -181,9 +166,6 @@ #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 ); #endif -#ifdef FLOAT128 -float128 float64_to_float128( float64 ); -#endif /* ------------------------------------------------------------------------------- @@ -216,9 +198,6 @@ signed int floatx80_to_int32_round_to_zero( floatx80 ); float32 floatx80_to_float32( floatx80 ); float64 floatx80_to_float64( floatx80 ); -#ifdef FLOAT128 -float128 floatx80_to_float128( floatx80 ); -#endif /* ------------------------------------------------------------------------------- @@ -247,43 +226,6 @@ char floatx80_le_quiet( floatx80, floatx80 ); char floatx80_lt_quiet( floatx80, floatx80 ); char floatx80_is_signaling_nan( floatx80 ); - -#endif - -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE quadruple-precision conversion routines. -------------------------------------------------------------------------------- -*/ -signed int float128_to_int32( float128 ); -signed int float128_to_int32_round_to_zero( float128 ); -float32 float128_to_float32( float128 ); -float64 float128_to_float64( float128 ); -#ifdef FLOATX80 -floatx80 float128_to_floatx80( float128 ); -#endif - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE quadruple-precision operations. -------------------------------------------------------------------------------- -*/ -float128 float128_round_to_int( float128 ); -float128 float128_add( float128, float128 ); -float128 float128_sub( float128, float128 ); -float128 float128_mul( float128, float128 ); -float128 float128_div( float128, float128 ); -float128 float128_rem( float128, float128 ); -float128 float128_sqrt( float128 ); -char float128_eq( float128, float128 ); -char float128_le( float128, float128 ); -char float128_lt( float128, float128 ); -char float128_eq_signaling( float128, float128 ); -char float128_le_quiet( float128, float128 ); -char float128_lt_quiet( float128, float128 ); -char float128_is_signaling_nan( float128 ); #endif diff -urN linux-2.4.18/arch/arm/tools/Makefile linux-2.4.19-pre5/arch/arm/tools/Makefile --- linux-2.4.18/arch/arm/tools/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/tools/Makefile Sat Mar 30 22:55:39 2002 @@ -15,13 +15,17 @@ # what we want. We do this in several stages so make picks up on # any errors that occur along the way. -$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c - $(CC) $(CFLAGS) -S -o - getconstants.c > $@.tmp.1 +constants.h: constants-hdr getconstants.c + $(CC) $(CFLAGS) -S -o $@.tmp.1 getconstants.c sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' $@.tmp.1 > $@.tmp.2 - cat constants-hdr $@.tmp.2 > $@.tmp - cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@ + cat constants-hdr $@.tmp.2 > $@ $(RM) $@.tmp* +# Only update include/asm-arm/constants.h when it has actually changed. + +$(TOPDIR)/include/asm-arm/constants.h: constants.h + cmp constants.h $@ >/dev/null 2>&1 || cp -p constants.h $@ + # Build our dependencies, and then generate the constants and # mach-types header files. If we do it now, mkdep will pick # the dependencies up later on when it runs through the other @@ -29,7 +33,7 @@ dep: $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- getconstants.c |\ - sed s,getconstants.o,$(TOPDIR)/include/asm-arm/constants.h, > .depend + sed s,getconstants.o,constants.h, > .depend $(MAKE) all .PHONY: all dep diff -urN linux-2.4.18/arch/arm/tools/mach-types linux-2.4.19-pre5/arch/arm/tools/mach-types --- linux-2.4.18/arch/arm/tools/mach-types Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/arm/tools/mach-types Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Oct 26 17:37:13 2001 +# Last update: Sat Mar 16 15:56:27 2002 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -118,10 +118,10 @@ cdb89712 ARCH_CDB89712 CDB89712 107 graphicsmaster SA1100_GRAPHICSMASTER GRAPHICSMASTER 108 adsbitsy SA1100_ADSBITSY ADSBITSY 109 -cotulla_idp ARCH_COTULLA_IDP COTULLA_IDP 110 +pxa_idp ARCH_PXA_IDP PXA_IDP 110 plce ARCH_PLCE PLCE 111 pt_system3 SA1100_PT_SYSTEM3 PT_SYSTEM3 112 -medalb ARCH_MEDALB MEDALB 113 +murphy ARCH_MEDALB MEDALB 113 eagle ARCH_EAGLE EAGLE 114 dsc21 ARCH_DSC21 DSC21 115 dsc24 ARCH_DSC24 DSC24 116 @@ -137,3 +137,44 @@ elroy SA1100_ELROY ELROY 126 gms720 ARCH_GMS720 GMS720 127 s24x ARCH_S24X S24X 128 +jtel_clep7312 ARCH_JTEL_CLEP7312 JTEL_CLEP7312 129 +cx821xx ARCH_CX821XX CX821XX 130 +edb7312 ARCH_EDB7312 EDB7312 131 +bsa1110 SA1100_BSA1110 BSA1110 132 +powerpin ARCH_POWERPIN POWERPIN 133 +openarm ARCH_OPENARM OPENARM 134 +whitechapel SA1100_WHITECHAPEL WHITECHAPEL 135 +h3100 SA1100_H3100 H3100 136 +h3800 SA1100_H3800 H3800 137 +blue_v1 ARCH_BLUE_V1 BLUE_V1 138 +pxa_cerf ARCH_PXA_CERF PXA_CERF 139 +arm7tevb ARCH_ARM7TEVB ARM7TEVB 140 +d7400 ARCH_D7400 D7400 141 +piranha ARCH_PIRANHA PIRANHA 142 +sbcamelot SA1100_SBCAMELOT SBCAMELOT 143 +kings SA1100_KINGS KINGS 144 +smdk2400 ARCH_SMDK2400 SMDK2400 145 +collie ARCH_COLLIE COLLIE 146 +idr ARCH_IDR IDR 147 +badge4 SA1100_BADGE4 BADGE4 148 +webnet ARCH_WEBNET WEBNET 149 +d7300 SA1100_D7300 D7300 150 +cep SA1100_CEP CEP 151 +fortunet ARCH_FORTUNET FORTUNET 152 +vc547x ARCH_VC547X VC547X 153 +filewalker SA1100_FILEWALKER FILEWALKER 154 +netgateway SA1100_NETGATEWAY NETGATEWAY 155 +symbol2800 SA1100_SYMBOL2800 SYMBOL2800 156 +suns SA1100_SUNS SUNS 157 +frodo SA1100_FRODO FRODO 158 +ms301 SA1100_MACH_TYTE_MS301 MACH_TYTE_MS301 159 +mx1ads ARCH_MX1ADS MX1ADS 160 +h7201 ARCH_H7201 H7201 161 +h7202 ARCH_H7202 H7202 162 +amico ARCH_AMICO AMICO 163 +iam SA1100_IAM IAM 164 +tt530 SA1100_TT530 TT530 165 +sam2400 ARCH_SAM2400 SAM2400 166 +jornada56x ARCH_JORNADA56X JORNADA56X 167 +active SA1100_ACTIVE ACTIVE 168 +iq80321 ARCH_IQ80321 IQ80321 169 diff -urN linux-2.4.18/arch/cris/drivers/ethernet.c linux-2.4.19-pre5/arch/cris/drivers/ethernet.c --- linux-2.4.18/arch/cris/drivers/ethernet.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/cris/drivers/ethernet.c Sat Mar 30 22:55:33 2002 @@ -1005,7 +1005,7 @@ int i; #endif - if (!led_active && jiffies > led_next_time) { + if (!led_active && time_after(jiffies, led_next_time)) { /* light the network leds depending on the current speed. */ e100_set_network_leds(NETWORK_ACTIVITY); @@ -1297,7 +1297,7 @@ { D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); - if (!led_active && jiffies > led_next_time) { + if (!led_active && time_after(jiffies, led_next_time)) { /* light the network leds depending on the current speed. */ e100_set_network_leds(NETWORK_ACTIVITY); @@ -1322,7 +1322,7 @@ static void e100_clear_network_leds(unsigned long dummy) { - if (led_active && jiffies > led_next_time) { + if (led_active && jiffies > time_after(jiffies, led_next_time)) { e100_set_network_leds(NO_NETWORK_ACTIVITY); /* Set the earliest time we may set the LED */ diff -urN linux-2.4.18/arch/cris/drivers/ide.c linux-2.4.19-pre5/arch/cris/drivers/ide.c --- linux-2.4.18/arch/cris/drivers/ide.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/cris/drivers/ide.c Sat Mar 30 22:55:33 2002 @@ -354,7 +354,7 @@ printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY); h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ); - while(jiffies < h) ; + while(time_before(jiffies, h)) ; /* reset the dma channels we will use */ diff -urN linux-2.4.18/arch/cris/drivers/lpslave/e100lpslavenet.c linux-2.4.19-pre5/arch/cris/drivers/lpslave/e100lpslavenet.c --- linux-2.4.18/arch/cris/drivers/lpslave/e100lpslavenet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/cris/drivers/lpslave/e100lpslavenet.c Sat Mar 30 22:55:33 2002 @@ -310,7 +310,7 @@ IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | /* Not used in reverse direction, don't care */ IO_STATE(R_PAR0_CONFIG, istrb, noninv) | - /* Not connected, don't care / + /* Not connected, don't care */ IO_STATE(R_PAR0_CONFIG, iinit, noninv) | /* perror is GND and reverse wants 0, noninv */ IO_STATE(R_PAR0_CONFIG, iperr, noninv) | diff -urN linux-2.4.18/arch/cris/kernel/entry.S linux-2.4.19-pre5/arch/cris/kernel/entry.S --- linux-2.4.18/arch/cris/kernel/entry.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/cris/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -1013,6 +1013,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */ .long SYMBOL_NAME(sys_gettid) .long SYMBOL_NAME(sys_readahead) /* 225 */ + .long SYMBOL_NAME(sys_tkill) /* * NOTE!! This doesn't have to be exact - we just have diff -urN linux-2.4.18/arch/cris/kernel/signal.c linux-2.4.19-pre5/arch/cris/kernel/signal.c --- linux-2.4.18/arch/cris/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/cris/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -679,10 +679,7 @@ default: lock_kernel(); - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/cris/mm/init.c linux-2.4.19-pre5/arch/cris/mm/init.c --- linux-2.4.18/arch/cris/mm/init.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/cris/mm/init.c Sat Mar 30 22:55:39 2002 @@ -465,7 +465,7 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %luk freed\n", + printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10); } diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.19-pre5/arch/i386/config.in --- linux-2.4.18/arch/i386/config.in Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/config.in Sat Mar 30 22:55:39 2002 @@ -163,6 +163,9 @@ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y define_bool CONFIG_X86_OOSTORE y fi + +bool 'Machine Check Exception' CONFIG_X86_MCE + tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K @@ -421,7 +424,6 @@ bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK - bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE fi endmenu diff -urN linux-2.4.18/arch/i386/defconfig linux-2.4.19-pre5/arch/i386/defconfig --- linux-2.4.18/arch/i386/defconfig Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/defconfig Sat Mar 30 22:55:25 2002 @@ -49,6 +49,7 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_MCE=y # CONFIG_TOSHIBA is not set # CONFIG_I8K is not set # CONFIG_MICROCODE is not set diff -urN linux-2.4.18/arch/i386/kernel/acpitable.c linux-2.4.19-pre5/arch/i386/kernel/acpitable.c --- linux-2.4.18/arch/i386/kernel/acpitable.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/acpitable.c Sat Mar 30 22:55:33 2002 @@ -172,40 +172,41 @@ /* - * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0, + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, * to map the target physical address. The problem is that set_fixmap() * provides a single page, and it is possible that the page is not * sufficient. * By using this area, we can map up to MAX_IO_APICS pages temporarily, * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. */ -static __inline__ char * +static __init char * __va_range(unsigned long phys, unsigned long size) { - unsigned long base, offset, mapped_size, mapped_phys = phys; - int idx = FIX_IO_APIC_BASE_0; + unsigned long base, offset, mapped_size; + int idx; offset = phys & (PAGE_SIZE - 1); mapped_size = PAGE_SIZE - offset; - set_fixmap(idx, mapped_phys); - base = fix_to_virt(FIX_IO_APIC_BASE_0); + set_fixmap(FIX_IO_APIC_BASE_END, phys); + base = fix_to_virt(FIX_IO_APIC_BASE_END); + dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size, + FIX_IO_APIC_BASE_END, base); /* * Most cases can be covered by the below. */ - if (mapped_size >= size) - return ((unsigned char *) base + offset); - - dprintk("__va_range: mapping more than a single page, size = 0x%lx\n", - size); - - do { - if (idx++ == FIX_IO_APIC_BASE_END) + idx = FIX_IO_APIC_BASE_END; + while (mapped_size < size) { + if (--idx < FIX_IO_APIC_BASE_0) return 0; /* cannot handle this */ - mapped_phys = mapped_phys + PAGE_SIZE; - set_fixmap(idx, mapped_phys); - mapped_size = mapped_size + PAGE_SIZE; - } while (mapped_size < size); + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } return ((unsigned char *) base + offset); } @@ -267,11 +268,14 @@ } for (i = 0; i < tables; i++) { - + /* Map in header, then map in full table length. */ header = (acpi_table_header *) __va_range(saved_rsdt.entry[i], sizeof(acpi_table_header)); - + if (!header) + break; + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], header->length); if (!header) break; diff -urN linux-2.4.18/arch/i386/kernel/apm.c linux-2.4.19-pre5/arch/i386/kernel/apm.c --- linux-2.4.18/arch/i386/kernel/apm.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/apm.c Sat Mar 30 22:55:39 2002 @@ -275,10 +275,11 @@ */ /* - * Define to always call the APM BIOS busy routine even if the clock was - * not slowed by the idle routine. + * Define as 1 to make the driver always call the APM BIOS busy + * routine even if the clock was not reported as slowed by the + * idle routine. Otherwise, define as 0. */ -#define ALWAYS_CALL_BUSY +#define ALWAYS_CALL_BUSY 1 /* * Define to make the APM BIOS calls zero all data segment registers (so @@ -380,7 +381,7 @@ static int set_pm_idle; static int suspends_pending; static int standbys_pending; -static int waiting_for_resume; +static int ignore_sys_suspend; static int ignore_normal_resume; static int bounce_interval = DEFAULT_BOUNCE_INTERVAL; @@ -470,6 +471,28 @@ }; #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) +/** + * apm_error - display an APM error + * @str: information string + * @err: APM BIOS return code + * + * Write a meaningful log entry to the kernel log in the event of + * an APM error. + */ + +static void apm_error(char *str, int err) +{ + int i; + + for (i = 0; i < ERROR_COUNT; i++) + if (error_table[i].key == err) break; + if (i < ERROR_COUNT) + printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg); + else + printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n", + str, err); +} + /* * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and * apm_info.allow_ints, we are being really paranoid here! Not only @@ -701,13 +724,13 @@ } /** - * apm_set_power_state - set system wide power state + * set_system_power_state - set system wide power state * @state: which state to enter * * Transition the entire system into a new APM power state. */ -static int apm_set_power_state(u_short state) +static int set_system_power_state(u_short state) { return set_power_state(APM_DEVICE_ALL, state); } @@ -724,7 +747,6 @@ static int apm_do_idle(void) { u32 eax; - int slowed; if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) { static unsigned long t; @@ -736,13 +758,8 @@ } return -1; } - slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0; -#ifdef ALWAYS_CALL_BUSY - clock_slowed = 1; -#else - clock_slowed = slowed; -#endif - return slowed; + clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0; + return clock_slowed; } /** @@ -755,7 +772,7 @@ { u32 dummy; - if (clock_slowed) { + if (clock_slowed || ALWAYS_CALL_BUSY) { (void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy); clock_slowed = 0; } @@ -770,7 +787,7 @@ #define IDLE_CALC_LIMIT (HZ * 100) #define IDLE_LEAKY_MAX 16 -static void (*sys_idle)(void); +static void (*original_pm_idle)(void); extern void default_idle(void); @@ -784,14 +801,13 @@ static void apm_cpu_idle(void) { - static int use_apm_idle = 0; - static unsigned int last_jiffies = 0; - static unsigned int last_stime = 0; + static int use_apm_idle; /* = 0 */ + static unsigned int last_jiffies; /* = 0 */ + static unsigned int last_stime; /* = 0 */ - int apm_is_idle = 0; + int apm_idle_done = 0; unsigned int jiffies_since_last_check = jiffies - last_jiffies; - unsigned int t1; - + unsigned int bucket; recalc: if (jiffies_since_last_check > IDLE_CALC_LIMIT) { @@ -809,7 +825,7 @@ last_stime = current->times.tms_stime; } - t1 = IDLE_LEAKY_MAX; + bucket = IDLE_LEAKY_MAX; while (!current->need_resched) { if (use_apm_idle) { @@ -817,23 +833,24 @@ t = jiffies; switch (apm_do_idle()) { - case 0: apm_is_idle = 1; + case 0: apm_idle_done = 1; if (t != jiffies) { - if (t1) { - t1 = IDLE_LEAKY_MAX; + if (bucket) { + bucket = IDLE_LEAKY_MAX; continue; } - } else if (t1) { - t1--; + } else if (bucket) { + bucket--; continue; } break; - case 1: apm_is_idle = 1; + case 1: apm_idle_done = 1; break; + default: /* BIOS refused */ } } - if (sys_idle) - sys_idle(); + if (original_pm_idle) + original_pm_idle(); else default_idle(); jiffies_since_last_check = jiffies - last_jiffies; @@ -841,7 +858,7 @@ goto recalc; } - if (apm_is_idle) + if (apm_idle_done) apm_do_busy(); } @@ -889,7 +906,7 @@ if (apm_info.realmode_power_off) machine_real_restart(po_bios_call, sizeof(po_bios_call)); else - (void) apm_set_power_state(APM_STATE_OFF); + (void) set_system_power_state(APM_STATE_OFF); } /** @@ -1034,28 +1051,6 @@ return APM_SUCCESS; } -/** - * apm_error - display an APM error - * @str: information string - * @err: APM BIOS return code - * - * Write a meaningful log entry to the kernel log in the event of - * an APM error. - */ - -static void apm_error(char *str, int err) -{ - int i; - - for (i = 0; i < ERROR_COUNT; i++) - if (error_table[i].key == err) break; - if (i < ERROR_COUNT) - printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg); - else - printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n", - str, err); -} - #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) /** @@ -1194,9 +1189,9 @@ /* Vetoed */ if (vetoable) { if (apm_info.connection_version > 0x100) - apm_set_power_state(APM_STATE_REJECT); + set_system_power_state(APM_STATE_REJECT); err = -EBUSY; - waiting_for_resume = 0; + ignore_sys_suspend = 0; printk(KERN_WARNING "apm: suspend was vetoed.\n"); goto out; } @@ -1204,9 +1199,10 @@ } get_time_diff(); cli(); - err = apm_set_power_state(APM_STATE_SUSPEND); + err = set_system_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); + ignore_normal_resume = 1; sti(); if (err == APM_NO_ERROR) err = APM_SUCCESS; @@ -1215,7 +1211,6 @@ err = (err == APM_SUCCESS) ? 0 : -EIO; pm_send_all(PM_RESUME, (void *)0); queue_event(APM_NORMAL_RESUME, NULL); - ignore_normal_resume = 1; out: for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; @@ -1231,7 +1226,7 @@ /* If needed, notify drivers here */ get_time_diff(); - err = apm_set_power_state(APM_STATE_STANDBY); + err = set_system_power_state(APM_STATE_STANDBY); if ((err != APM_SUCCESS) && (err != APM_NO_ERROR)) apm_error("standby", err); } @@ -1285,13 +1280,13 @@ case APM_USER_SUSPEND: #ifdef CONFIG_APM_IGNORE_USER_SUSPEND if (apm_info.connection_version > 0x100) - apm_set_power_state(APM_STATE_REJECT); + set_system_power_state(APM_STATE_REJECT); break; #endif case APM_SYS_SUSPEND: if (ignore_bounce) { if (apm_info.connection_version > 0x100) - apm_set_power_state(APM_STATE_REJECT); + set_system_power_state(APM_STATE_REJECT); break; } /* @@ -1302,9 +1297,9 @@ * sending a SUSPEND event until something else * happens! */ - if (waiting_for_resume) + if (ignore_sys_suspend) return; - waiting_for_resume = 1; + ignore_sys_suspend = 1; queue_event(event, NULL); if (suspends_pending <= 0) (void) suspend(1); @@ -1313,7 +1308,7 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: - waiting_for_resume = 0; + ignore_sys_suspend = 0; last_resume = jiffies; ignore_bounce = 1; if ((event != APM_NORMAL_RESUME) @@ -1357,7 +1352,7 @@ pending_count = 4; if (debug) printk(KERN_DEBUG "apm: setting state busy\n"); - err = apm_set_power_state(APM_STATE_BUSY); + err = set_system_power_state(APM_STATE_BUSY); if (err) apm_error("busy", err); } @@ -1964,7 +1959,7 @@ if (HZ != 100) idle_period = (idle_period * HZ) / 100; if (idle_threshold < 100) { - sys_idle = pm_idle; + original_pm_idle = pm_idle; pm_idle = apm_cpu_idle; set_pm_idle = 1; } @@ -1977,7 +1972,7 @@ int error; if (set_pm_idle) - pm_idle = sys_idle; + pm_idle = original_pm_idle; if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0) && (apm_info.connection_version > 0x0100)) { error = apm_engage_power_management(APM_DEVICE_ALL, 0); diff -urN linux-2.4.18/arch/i386/kernel/bluesmoke.c linux-2.4.19-pre5/arch/i386/kernel/bluesmoke.c --- linux-2.4.18/arch/i386/kernel/bluesmoke.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/bluesmoke.c Sat Mar 30 22:55:25 2002 @@ -3,9 +3,12 @@ #include #include #include +#include #include #include +#ifdef CONFIG_X86_MCE + static int mce_disabled __initdata = 0; /* @@ -41,13 +44,12 @@ if(high&(1<<27)) { rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); - printk("[%08x%08x]", alow, ahigh); + printk("[%08x%08x]", ahigh, alow); } if(high&(1<<26)) { rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); - printk(" at %08x%08x", - high, low); + printk(" at %08x%08x", ahigh, alow); } printk("\n"); /* Clear it */ @@ -247,3 +249,8 @@ __setup("nomce", mcheck_disable); __setup("mce", mcheck_enable); + +#else +asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {} +void __init mcheck_init(struct cpuinfo_x86 *c) {} +#endif diff -urN linux-2.4.18/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre5/arch/i386/kernel/dmi_scan.c --- linux-2.4.18/arch/i386/kernel/dmi_scan.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/dmi_scan.c Sat Mar 30 22:55:39 2002 @@ -9,6 +9,7 @@ #include #include #include +#include unsigned long dmi_broken; int is_sony_vaio_laptop; @@ -51,7 +52,7 @@ u8 *data; int i=1; - buf = ioremap(base, len); + buf = bt_ioremap(base, len); if(buf==NULL) return -1; @@ -83,7 +84,7 @@ data+=2; i++; } - iounmap(buf); + bt_iounmap(buf, len); return 0; } @@ -155,7 +156,7 @@ return; if (dmi_ident[slot]) return; - dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + dmi_ident[slot] = alloc_bootmem(strlen(p)+1); if(dmi_ident[slot]) strcpy(dmi_ident[slot], p); else @@ -452,6 +453,11 @@ MATCH(DMI_BIOS_VERSION, "A04"), MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH } }, + { broken_apm_power, "Dell Inspiron 2500", { /* Handle problems with APM on Inspiron 2500 */ + MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION, "A12"), + MATCH(DMI_BIOS_DATE, "02/04/2002"), NO_MATCH + } }, { set_realmode_power_off, "Award Software v4.60 PGMA", { /* broken PM poweroff bios */ MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."), MATCH(DMI_BIOS_VERSION, "4.60 PGMA"), @@ -493,12 +499,23 @@ MATCH(DMI_PRODUCT_NAME, "Delhi3"), NO_MATCH, NO_MATCH, } }, + { apm_is_horked, "Fujitsu-Siemens", { /* APM crashes */ + MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"), + MATCH(DMI_BIOS_VERSION, "Version1.01"), + NO_MATCH, NO_MATCH, + } }, { apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */ MATCH(DMI_SYS_VENDOR, "SHARP"), MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"), MATCH(DMI_BIOS_VENDOR,"SystemSoft"), MATCH(DMI_BIOS_VERSION,"Version R2.08") } }, + { apm_is_horked, "Dell Inspiron 2500", { /* APM crashes */ + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"), + MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION,"A11") + } }, { sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */ MATCH(DMI_SYS_VENDOR, "Sony Corporation"), MATCH(DMI_PRODUCT_NAME, "PCG-"), @@ -731,12 +748,9 @@ } } -static int __init dmi_scan_machine(void) +void __init dmi_scan_machine(void) { int err = dmi_iterate(dmi_decode); if(err == 0) dmi_check_blacklist(); - return err; } - -module_init(dmi_scan_machine); diff -urN linux-2.4.18/arch/i386/kernel/entry.S linux-2.4.19-pre5/arch/i386/kernel/entry.S --- linux-2.4.18/arch/i386/kernel/entry.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -634,6 +634,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* 235 reserved for removexattr */ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lremovexattr */ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fremovexattr */ + .long SYMBOL_NAME(sys_tkill) .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) diff -urN linux-2.4.18/arch/i386/kernel/head.S linux-2.4.19-pre5/arch/i386/kernel/head.S --- linux-2.4.18/arch/i386/kernel/head.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/head.S Sat Mar 30 22:55:33 2002 @@ -178,7 +178,7 @@ * we don't need to preserve eflags. */ - movl $3,X86 # at least 386 + movb $3,X86 # at least 386 pushfl # push EFLAGS popl %eax # get EFLAGS movl %eax,%ecx # save original EFLAGS @@ -191,7 +191,7 @@ andl $0x40000,%eax # check if AC bit changed je is386 - movl $4,X86 # at least 486 + movb $4,X86 # at least 486 movl %ecx,%eax xorl $0x200000,%eax # check ID flag pushl %eax diff -urN linux-2.4.18/arch/i386/kernel/i386_ksyms.c linux-2.4.19-pre5/arch/i386/kernel/i386_ksyms.c --- linux-2.4.18/arch/i386/kernel/i386_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/i386_ksyms.c Sat Mar 30 22:55:39 2002 @@ -73,6 +73,7 @@ EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +EXPORT_SYMBOL(empty_zero_page); #ifdef CONFIG_DEBUG_IOVIRT EXPORT_SYMBOL(__io_virt_debug); @@ -145,6 +146,10 @@ EXPORT_SYMBOL(flush_tlb_page); #endif +#ifdef CONFIG_X86_IO_APIC +EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); +#endif + #ifdef CONFIG_MCA EXPORT_SYMBOL(machine_id); #endif @@ -166,10 +171,6 @@ #ifdef CONFIG_HAVE_DEC_LOCK EXPORT_SYMBOL(atomic_dec_and_lock); -#endif - -#ifdef CONFIG_DEBUG_BUGVERBOSE -EXPORT_SYMBOL(do_BUG); #endif extern int is_sony_vaio_laptop; diff -urN linux-2.4.18/arch/i386/kernel/io_apic.c linux-2.4.19-pre5/arch/i386/kernel/io_apic.c --- linux-2.4.18/arch/i386/kernel/io_apic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/io_apic.c Sat Mar 30 22:55:33 2002 @@ -67,7 +67,7 @@ * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq(unsigned int irq, int apic, int pin) +static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -85,6 +85,26 @@ entry->pin = pin; } +/* + * Reroute an IRQ to a different pin. + */ +static void __init replace_pin_at_irq(unsigned int irq, + int oldapic, int oldpin, + int newapic, int newpin) +{ + struct irq_pin_list *entry = irq_2_pin + irq; + + while (1) { + if (entry->apic == oldapic && entry->pin == oldpin) { + entry->apic = newapic; + entry->pin = newpin; + } + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } +} + #define __DO_ACTION(R, ACTION, FINAL) \ \ { \ @@ -1533,6 +1553,10 @@ setup_ExtINT_IRQ0_pin(pin2, vector); if (timer_irq_works()) { printk("works.\n"); + if (pin1 != -1) + replace_pin_at_irq(0, 0, pin1, 0, pin2); + else + add_pin_to_irq(0, 0, pin2); if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); check_nmi_watchdog(); diff -urN linux-2.4.18/arch/i386/kernel/microcode.c linux-2.4.19-pre5/arch/i386/kernel/microcode.c --- linux-2.4.18/arch/i386/kernel/microcode.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/microcode.c Sat Mar 30 22:55:39 2002 @@ -51,6 +51,12 @@ * Bugfix for HT (Hyper-Threading) enabled processors * whereby processor resources are shared by all logical processors * in a single CPU package. + * 1.10 28 Feb 2002 Asit K Mallick and + * Tigran Aivazian , + * Serialize updates as required on HT processors due to speculative + * nature of implementation. + * 1.11 22 Mar 2001 Tigran Aivazian + * Fix the panic when writing zero-length microcode chunk. */ #include @@ -60,12 +66,16 @@ #include #include #include +#include #include #include #include -#define MICROCODE_VERSION "1.09" + +static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED; + +#define MICROCODE_VERSION "1.11" MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -195,7 +205,8 @@ struct cpuinfo_x86 *c = cpu_data + cpu_num; struct update_req *req = update_req + cpu_num; unsigned int pf = 0, val[2], rev, sig; - int i,found=0; + unsigned long flags; + int i; req->err = 1; /* assume update will fail on this cpu */ @@ -216,8 +227,9 @@ for (i=0; islot = i; + + /* serialize access to update decision */ + spin_lock_irqsave(µcode_update_lock, flags); + /* trick, to work even if there was no prior update by the BIOS */ wrmsr(MSR_IA32_UCODE_REV, 0, 0); __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); /* get current (on-cpu) revision into rev (ignore val[0]) */ rdmsr(MSR_IA32_UCODE_REV, val[0], rev); + if (microcode[i].rev < rev) { + spin_unlock_irqrestore(µcode_update_lock, flags); printk(KERN_ERR - "microcode: CPU%d not 'upgrading' to earlier revision" + "microcode: CPU%d not 'upgrading' to earlier revision" + " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); + return; + } else if (microcode[i].rev == rev) { + /* notify the caller of success on this cpu */ + req->err = 0; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_ERR + "microcode: CPU%d already at revision" " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); - } else { - int sum = 0; - struct microcode *m = µcode[i]; - unsigned int *sump = (unsigned int *)(m+1); - - while (--sump >= (unsigned int *)m) - sum += *sump; - if (sum != 0) { - printk(KERN_ERR "microcode: CPU%d aborting, " - "bad checksum\n", cpu_num); - break; - } - - /* write microcode via MSR 0x79 */ - wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); + return; + } - /* serialize */ - __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); + /* Verify the checksum */ + while (--sump >= (unsigned int *)m) + sum += *sump; + if (sum != 0) { + req->err = 1; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_ERR "microcode: CPU%d aborting, " + "bad checksum\n", cpu_num); + return; + } + + /* write microcode via MSR 0x79 */ + wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); - /* get the current revision from MSR 0x8B */ - rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + /* serialize */ + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); - /* notify the caller of success on this cpu */ - req->err = 0; - req->slot = i; + /* get the current revision from MSR 0x8B */ + rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); - printk(KERN_INFO "microcode: CPU%d updated from revision " - "%d to %d, date=%08x\n", - cpu_num, rev, val[1], m->date); - } - break; + /* notify the caller of success on this cpu */ + req->err = 0; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_INFO "microcode: CPU%d updated from revision " + "%d to %d, date=%08x\n", + cpu_num, rev, val[1], microcode[i].date); + return; } - - if(!found) - printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", - cpu_num, sig, pf); + + printk(KERN_ERR + "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", + cpu_num, sig, pf); } + static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) { ssize_t ret = 0; @@ -305,9 +332,13 @@ { ssize_t ret; - if (len % sizeof(struct microcode) != 0) { + if (!len || len % sizeof(struct microcode) != 0) { printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", sizeof(struct microcode)); + return -EINVAL; + } + if ((len >> PAGE_SHIFT) > num_physpages) { + printk(KERN_ERR "microcode: too much data (max %d pages)\n", num_physpages); return -EINVAL; } down_write(µcode_rwsem); diff -urN linux-2.4.18/arch/i386/kernel/mpparse.c linux-2.4.19-pre5/arch/i386/kernel/mpparse.c --- linux-2.4.18/arch/i386/kernel/mpparse.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/mpparse.c Sat Mar 30 22:55:25 2002 @@ -37,6 +37,8 @@ int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES]; int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_local [MAX_MP_BUSSES]; +int quad_local_to_mp_bus_id [NR_CPUS/4][4]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; @@ -241,13 +243,17 @@ static void __init MP_bus_info (struct mpc_config_bus *m) { char str[7]; + int quad; memcpy(str, m->mpc_bustype, 6); str[6] = 0; if (clustered_apic_mode) { - mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad; - printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]); + quad = translation_table[mpc_record]->trans_quad; + mp_bus_id_to_node[m->mpc_busid] = quad; + mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local; + quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid; + printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad); } else { Dprintk("Bus #%d is %s\n", m->mpc_busid, str); } @@ -324,13 +330,14 @@ static void __init MP_translation_info (struct mpc_config_translation *m) { - printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, - m->trans_quad, m->trans_global, m->trans_local); + printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); if (mpc_record >= MAX_MPC_ENTRY) printk("MAX_MPC_ENTRY exceeded!\n"); else translation_table[mpc_record] = m; /* stash this for later */ + if (m->trans_quad+1 > numnodes) + numnodes = m->trans_quad+1; } /* @@ -494,10 +501,6 @@ } } ++mpc_record; - } - if (clustered_apic_mode && nr_ioapics > 2) { - /* don't initialise IO apics on secondary quads */ - nr_ioapics = 2; } if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); diff -urN linux-2.4.18/arch/i386/kernel/mtrr.c linux-2.4.19-pre5/arch/i386/kernel/mtrr.c --- linux-2.4.18/arch/i386/kernel/mtrr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/mtrr.c Sat Mar 30 22:55:25 2002 @@ -378,10 +378,8 @@ static int arr3_protected; /* Put the processor into a state where MTRRs can be safely set */ -static void set_mtrr_prepare (struct set_mtrr_context *ctxt) +static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt) { - unsigned long tmp; - /* Disable interrupts locally */ __save_flags (ctxt->flags); __cli (); @@ -404,16 +402,27 @@ } if ( mtrr_if == MTRR_IF_INTEL ) { - /* Disable MTRRs, and set the default type to uncached */ + /* Save MTRR state */ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + } else { + /* Cyrix ARRs - everything else were excluded at the top */ + ctxt->ccr3 = getCx86 (CX86_CCR3); + } +} /* End Function set_mtrr_prepare_save */ + +static void set_mtrr_disable (struct set_mtrr_context *ctxt) +{ + if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) + return; + + if ( mtrr_if == MTRR_IF_INTEL ) { + /* Disable MTRRs, and set the default type to uncached */ wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); } else { /* Cyrix ARRs - everything else were excluded at the top */ - tmp = getCx86 (CX86_CCR3); - setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10); - ctxt->ccr3 = tmp; + setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); } -} /* End Function set_mtrr_prepare */ +} /* End Function set_mtrr_disable */ /* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) @@ -674,7 +683,10 @@ { struct set_mtrr_context ctxt; - if (do_safe) set_mtrr_prepare (&ctxt); + if (do_safe) { + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); + } if (size == 0) { /* The invalid bit is kept in the mask, so we simply clear the @@ -726,7 +738,10 @@ } } - if (do_safe) set_mtrr_prepare (&ctxt); + if (do_safe) { + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); + } base <<= PAGE_SHIFT; setCx86(arr, ((unsigned char *) &base)[3]); setCx86(arr+1, ((unsigned char *) &base)[2]); @@ -750,7 +765,10 @@ u32 regs[2]; struct set_mtrr_context ctxt; - if (do_safe) set_mtrr_prepare (&ctxt); + if (do_safe) { + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); + } /* * Low is MTRR0 , High MTRR 1 */ @@ -788,7 +806,10 @@ struct set_mtrr_context ctxt; unsigned long low, high; - if (do_safe) set_mtrr_prepare( &ctxt ); + if (do_safe) { + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); + } if (size == 0) { /* Disable */ @@ -985,6 +1006,7 @@ static atomic_t undone_count; +static volatile int wait_barrier_mtrr_disable = FALSE; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; @@ -1003,18 +1025,21 @@ { struct set_mtrr_data *data = info; struct set_mtrr_context ctxt; - - set_mtrr_prepare (&ctxt); + set_mtrr_prepare_save (&ctxt); /* Notify master that I've flushed and disabled my cache */ atomic_dec (&undone_count); - while (wait_barrier_execute) barrier (); + while (wait_barrier_mtrr_disable) { rep_nop(); barrier(); } + set_mtrr_disable (&ctxt); + /* Notify master that I've flushed and disabled my cache */ + atomic_dec (&undone_count); + while (wait_barrier_execute) { rep_nop(); barrier(); } /* The master has cleared me to execute */ (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size, data->smp_type, FALSE); /* Notify master CPU that I've executed the function */ atomic_dec (&undone_count); /* Wait for master to clear me to enable cache and return */ - while (wait_barrier_cache_enable) barrier (); + while (wait_barrier_cache_enable) { rep_nop(); barrier(); } set_mtrr_done (&ctxt); } /* End Function ipi_handler */ @@ -1028,6 +1053,7 @@ data.smp_base = base; data.smp_size = size; data.smp_type = type; + wait_barrier_mtrr_disable = TRUE; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; atomic_set (&undone_count, smp_num_cpus - 1); @@ -1035,15 +1061,22 @@ if (smp_call_function (ipi_handler, &data, 1, 0) != 0) panic ("mtrr: timed out waiting for other CPUs\n"); /* Flush and disable the local CPU's cache */ - set_mtrr_prepare (&ctxt); + set_mtrr_prepare_save (&ctxt); + /* Wait for all other CPUs to flush and disable their caches */ + while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } + /* Set up for completion wait and then release other CPUs to change MTRRs*/ + atomic_set (&undone_count, smp_num_cpus - 1); + wait_barrier_mtrr_disable = FALSE; + set_mtrr_disable (&ctxt); + /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) barrier (); + while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } /* Set up for completion wait and then release other CPUs to change MTRRs*/ atomic_set (&undone_count, smp_num_cpus - 1); wait_barrier_execute = FALSE; (*set_mtrr_up) (reg, base, size, type, FALSE); /* Now wait for other CPUs to complete the function */ - while (atomic_read (&undone_count) > 0) barrier (); + while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } /* Now all CPUs should have finished the function. Release the barrier to allow them to re-enable their caches and return from their interrupt, then enable the local cache and return */ @@ -1889,7 +1922,9 @@ struct set_mtrr_context ctxt; int i; - set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ + /* flush cache and enable MAPEN */ + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); /* the CCRs are not contiguous */ for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]); @@ -1926,7 +1961,9 @@ int i; #endif - set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ + /* flush cache and enable MAPEN */ + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); /* Save all CCRs locally */ ccr[0] = getCx86 (CX86_CCR0); @@ -2075,7 +2112,8 @@ { struct set_mtrr_context ctxt; - set_mtrr_prepare (&ctxt); + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); if(boot_cpu_data.x86_model==4) centaur_mcr0_init(); @@ -2192,7 +2230,8 @@ /* Note that this is not ideal, since the cache is only flushed/disabled for this CPU while the MTRRs are changed, but changing this requires more invasive changes to the way the kernel boots */ - set_mtrr_prepare (&ctxt); + set_mtrr_prepare_save (&ctxt); + set_mtrr_disable (&ctxt); mask = set_mtrr_state (&smp_mtrr_state, &ctxt); set_mtrr_done (&ctxt); /* Use the atomic bitops to update the global mask */ diff -urN linux-2.4.18/arch/i386/kernel/nmi.c linux-2.4.19-pre5/arch/i386/kernel/nmi.c --- linux-2.4.18/arch/i386/kernel/nmi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/nmi.c Sat Mar 30 22:55:33 2002 @@ -8,6 +8,7 @@ * Fixes: * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. + * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog. */ #include @@ -43,6 +44,32 @@ #define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 #define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED +#define MSR_P4_MISC_ENABLE 0x1A0 +#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) +#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12) +#define MSR_P4_PERFCTR0 0x300 +#define MSR_P4_CCCR0 0x360 +#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) +#define P4_ESCR_OS (1<<3) +#define P4_ESCR_USR (1<<2) +#define P4_CCCR_OVF_PMI (1<<26) +#define P4_CCCR_THRESHOLD(N) ((N)<<20) +#define P4_CCCR_COMPLEMENT (1<<19) +#define P4_CCCR_COMPARE (1<<18) +#define P4_CCCR_REQUIRED (3<<16) +#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) +#define P4_CCCR_ENABLE (1<<12) +/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter + CRU_ESCR0 (with any non-null event selector) through a complemented + max threshold. [IA32-Vol3, Section 14.9.9] */ +#define MSR_P4_IQ_COUNTER0 0x30C +#define MSR_P4_IQ_CCCR0 0x36C +#define MSR_P4_CRU_ESCR0 0x3B8 +#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR) +#define P4_NMI_IQ_CCCR0 \ + (P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ + P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) + int __init check_nmi_watchdog (void) { irq_cpustat_t tmp[NR_CPUS]; @@ -84,11 +111,11 @@ /* * If any other x86 CPU has a local APIC, then * please test the NMI stuff there and send me the - * missing bits. Right now Intel P6 and AMD K7 only. + * missing bits. Right now Intel P6/P4 and AMD K7 only. */ if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && - (boot_cpu_data.x86 == 6)) + (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15)) nmi_watchdog = nmi; if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && @@ -118,7 +145,15 @@ wrmsr(MSR_K7_EVNTSEL0, 0, 0); break; case X86_VENDOR_INTEL: - wrmsr(MSR_IA32_EVNTSEL0, 0, 0); + switch (boot_cpu_data.x86) { + case 6: + wrmsr(MSR_P6_EVNTSEL0, 0, 0); + break; + case 15: + wrmsr(MSR_P4_IQ_CCCR0, 0, 0); + wrmsr(MSR_P4_CRU_ESCR0, 0, 0); + break; + } break; } } @@ -157,17 +192,22 @@ * Original code written by Keith Owens. */ +static void __pminit clear_msr_range(unsigned int base, unsigned int n) +{ + unsigned int i; + + for(i = 0; i < n; ++i) + wrmsr(base+i, 0, 0); +} + static void __pminit setup_k7_watchdog(void) { - int i; unsigned int evntsel; nmi_perfctr_msr = MSR_K7_PERFCTR0; - for(i = 0; i < 4; ++i) { - wrmsr(MSR_K7_EVNTSEL0+i, 0, 0); - wrmsr(MSR_K7_PERFCTR0+i, 0, 0); - } + clear_msr_range(MSR_K7_EVNTSEL0, 4); + clear_msr_range(MSR_K7_PERFCTR0, 4); evntsel = K7_EVNTSEL_INT | K7_EVNTSEL_OS @@ -184,27 +224,54 @@ static void __pminit setup_p6_watchdog(void) { - int i; unsigned int evntsel; - nmi_perfctr_msr = MSR_IA32_PERFCTR0; + nmi_perfctr_msr = MSR_P6_PERFCTR0; - for(i = 0; i < 2; ++i) { - wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0); - wrmsr(MSR_IA32_PERFCTR0+i, 0, 0); - } + clear_msr_range(MSR_P6_EVNTSEL0, 2); + clear_msr_range(MSR_P6_PERFCTR0, 2); evntsel = P6_EVNTSEL_INT | P6_EVNTSEL_OS | P6_EVNTSEL_USR | P6_NMI_EVENT; - wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); - Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); + wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); + Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= P6_EVNTSEL0_ENABLE; - wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); + wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); +} + +static int __pminit setup_p4_watchdog(void) +{ + unsigned int misc_enable, dummy; + + rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy); + if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) + return 0; + + nmi_perfctr_msr = MSR_P4_IQ_COUNTER0; + + if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL)) + clear_msr_range(0x3F1, 2); + /* MSR 0x3F0 seems to have a default value of 0xFC00, but current + docs doesn't fully define it, so leave it alone for now. */ + clear_msr_range(0x3A0, 31); + clear_msr_range(0x3C0, 6); + clear_msr_range(0x3C8, 6); + clear_msr_range(0x3E0, 2); + clear_msr_range(MSR_P4_CCCR0, 18); + clear_msr_range(MSR_P4_PERFCTR0, 18); + + wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); + Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1); + apic_write(APIC_LVTPC, APIC_DM_NMI); + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0); + return 1; } void __pminit setup_apic_nmi_watchdog (void) @@ -216,9 +283,17 @@ setup_k7_watchdog(); break; case X86_VENDOR_INTEL: - if (boot_cpu_data.x86 != 6) + switch (boot_cpu_data.x86) { + case 6: + setup_p6_watchdog(); + break; + case 15: + if (!setup_p4_watchdog()) + return; + break; + default: return; - setup_p6_watchdog(); + } break; default: return; @@ -283,7 +358,7 @@ * to get a message out. */ bust_spinlocks(1); - printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); + printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); show_registers(regs); printk("console shuts up ...\n"); console_silent(); @@ -295,6 +370,18 @@ last_irq_sums[cpu] = sum; alert_counter[cpu] = 0; } - if (nmi_perfctr_msr) + if (nmi_perfctr_msr) { + if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) { + /* + * P4 quirks: + * - An overflown perfctr will assert its interrupt + * until the OVF flag in its CCCR is cleared. + * - LVTPC is masked on interrupt and must be + * unmasked by the LVTPC handler. + */ + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0); + apic_write(APIC_LVTPC, APIC_DM_NMI); + } wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); + } } diff -urN linux-2.4.18/arch/i386/kernel/pci-irq.c linux-2.4.19-pre5/arch/i386/kernel/pci-irq.c --- linux-2.4.18/arch/i386/kernel/pci-irq.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/pci-irq.c Sat Mar 30 22:55:39 2002 @@ -206,6 +206,24 @@ } /* + * ITE 8330G pirq rules are nibble-based + * FIXME: pirqmap may be { 1, 0, 3, 2 }, + * 2+3 are both mapped to irq 9 on my system + */ +static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; + return read_config_nybble(router,0x43, pirqmap[pirq-1]); +} + +static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; + write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); + return 1; +} + +/* * OPTI: high four bits are nibble pointer.. * I wonder what the low bits do? */ @@ -446,6 +464,8 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, + + { "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set }, { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set }, { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set }, diff -urN linux-2.4.18/arch/i386/kernel/pci-pc.c linux-2.4.19-pre5/arch/i386/kernel/pci-pc.c --- linux-2.4.18/arch/i386/kernel/pci-pc.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/pci-pc.c Sat Mar 30 22:55:39 2002 @@ -14,6 +14,7 @@ #include #include +#include #include "pci-i386.h" @@ -26,6 +27,16 @@ int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; +#ifdef CONFIG_MULTIQUAD +#define BUS2QUAD(global) (mp_bus_id_to_node[global]) +#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) +#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) +#else +#define BUS2QUAD(global) (0) +#define BUS2LOCAL(global) (global) +#define QUADLOCAL2BUS(quad,local) (local) +#endif + /* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. @@ -39,10 +50,71 @@ #ifdef CONFIG_PCI_DIRECT +#ifdef CONFIG_MULTIQUAD +#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ + (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) + +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */ +{ + unsigned long flags; + + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + *value = inl_quad(0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */ +{ + unsigned long flags; + + if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + outl_quad((u32)value, 0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#else /* !CONFIG_MULTIQUAD */ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */ { unsigned long flags; @@ -70,7 +142,7 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */ { unsigned long flags; @@ -98,6 +170,8 @@ return 0; } +#endif /* CONFIG_MULTIQUAD */ + #undef PCI_CONF1_ADDRESS static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) @@ -347,7 +421,7 @@ pci_sanity_check(&pci_direct_conf1)) { outl (tmp, 0xCF8); __restore_flags(flags); - printk("PCI: Using configuration type 1\n"); + printk(KERN_INFO "PCI: Using configuration type 1\n"); request_region(0xCF8, 8, "PCI conf1"); return &pci_direct_conf1; } @@ -364,7 +438,7 @@ if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 && pci_sanity_check(&pci_direct_conf2)) { __restore_flags(flags); - printk("PCI: Using configuration type 2\n"); + printk(KERN_INFO "PCI: Using configuration type 2\n"); request_region(0xCF8, 4, "PCI conf2"); return &pci_direct_conf2; } @@ -472,10 +546,10 @@ case 0: return address + entry; case 0x80: /* Not present */ - printk("bios32_service(0x%lx): not present\n", service); + printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); return 0; default: /* Shouldn't happen */ - printk("bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", + printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", service, return_code); return 0; } @@ -525,7 +599,7 @@ status, signature); return 0; } - printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n", + printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n", major_ver, minor_ver, pcibios_entry, pcibios_last_bus); #ifdef CONFIG_PCI_DIRECT if (!(hw_mech & PCIBIOS_HW_TYPE1)) @@ -827,7 +901,7 @@ } } if (ln == &pci_devices) { - printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); + printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); /* * We must not continue scanning as several buggy BIOSes * return garbage after the last device. Grr. @@ -836,7 +910,7 @@ } } if (!found) { - printk("PCI: Device %02x:%02x not found by BIOS\n", + printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n", dev->bus->number, dev->devfn); list_del(&dev->global_list); list_add_tail(&dev->global_list, &sorted_devices); @@ -896,7 +970,7 @@ rt->size = opt.size + sizeof(struct irq_routing_table); rt->exclusive_irqs = map; memcpy(rt->slots, (void *) page, opt.size); - printk("PCI: Using BIOS Interrupt Routing Table\n"); + printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n"); } } free_page(page); @@ -961,7 +1035,7 @@ } if (!seen_host_bridge) return; - printk("PCI: Ignoring ghost devices on bus %02x\n", b->number); + printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number); ln = &b->devices; while (ln->next != &b->devices) { @@ -999,7 +1073,7 @@ if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l); - printk("PCI: Discovered peer bus %02x\n", n); + printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); pci_scan_bus(n, pci_root_ops, NULL); break; } @@ -1017,6 +1091,8 @@ */ int pxb, reg; u8 busno, suba, subb; + int quad = BUS2QUAD(d->bus->number); + printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name); reg = 0xd0; for(pxb=0; pxb<2; pxb++) { @@ -1025,9 +1101,9 @@ pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -1040,7 +1116,7 @@ */ u8 busno; pci_read_config_byte(d, 0x4a, &busno); - printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno); + printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno); pci_scan_bus(busno, pci_root_ops, NULL); pcibios_last_bus = -1; } @@ -1053,7 +1129,7 @@ */ int i; - printk("PCI: Fixing base address flags for device %s\n", d->slot_name); + printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name); for(i=0; i<4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } @@ -1199,15 +1275,25 @@ void __init pcibios_init(void) { + int quad; + if (!pci_root_ops) pcibios_config_init(); if (!pci_root_ops) { - printk("PCI: System does not support PCI\n"); + printk(KERN_WARNING "PCI: System does not support PCI\n"); return; } - printk("PCI: Probing PCI hardware\n"); + printk(KERN_INFO "PCI: Probing PCI hardware\n"); pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); + if (clustered_apic_mode && (numnodes > 1)) { + for (quad = 1; quad < numnodes; ++quad) { + printk("Scanning PCI bus %d for quad %d\n", + QUADLOCAL2BUS(quad,0), quad); + pci_scan_bus(QUADLOCAL2BUS(quad,0), + pci_root_ops, NULL); + } + } pcibios_irq_init(); pcibios_fixup_peer_bridges(); diff -urN linux-2.4.18/arch/i386/kernel/setup.c linux-2.4.19-pre5/arch/i386/kernel/setup.c --- linux-2.4.18/arch/i386/kernel/setup.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/setup.c Sat Mar 30 22:55:33 2002 @@ -98,6 +98,8 @@ #endif #include #include +#include +#include #include #include #include @@ -155,6 +157,7 @@ unsigned char aux_device_present; extern void mcheck_init(struct cpuinfo_x86 *c); +extern void dmi_scan_machine(void); extern int root_mountflags; extern char _text, _etext, _edata, _end; @@ -1042,6 +1045,7 @@ conswitchp = &dummy_con; #endif #endif + dmi_scan_machine(); } static int cachesize_override __initdata = -1; @@ -1306,7 +1310,7 @@ } /* - * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU + * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) { @@ -1468,11 +1472,6 @@ break; case 4: /* MediaGX/GXm */ - /* - * Life sometimes gets weiiiiiiiird if we use this - * on the MediaGX. So we turn it off for now. - */ - #ifdef CONFIG_PCI /* It isnt really a PCI quirk directly, but the cure is the same. The MediaGX has deep magic SMM stuff that handles the @@ -1494,14 +1493,22 @@ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { get_model_name(c); /* get CPU marketing name */ - clear_bit(X86_FEATURE_TSC, c->x86_capability); + /* + * The 5510/5520 companion chips have a funky PIT + * that breaks the TSC synchronizing, so turn it off + */ + if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) || + pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL)) + clear_bit(X86_FEATURE_TSC, c->x86_capability); return; } else { /* MediaGX */ Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; p = Cx86_cb+2; c->x86_model = (dir1 & 0x20) ? 1 : 2; - clear_bit(X86_FEATURE_TSC, &c->x86_capability); + if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) || + pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL)) + clear_bit(X86_FEATURE_TSC, &c->x86_capability); } break; @@ -2270,6 +2277,8 @@ c->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(v, "CyrixInstead")) c->x86_vendor = X86_VENDOR_CYRIX; + else if (!strcmp(v, "Geode by NSC")) + c->x86_vendor = X86_VENDOR_NSC; else if (!strcmp(v, "UMC UMC UMC ")) c->x86_vendor = X86_VENDOR_UMC; else if (!strcmp(v, "CentaurHauls")) @@ -2613,6 +2622,10 @@ init_cyrix(c); break; + case X86_VENDOR_NSC: + init_cyrix(c); + break; + case X86_VENDOR_AMD: init_amd(c); break; @@ -2713,14 +2726,17 @@ { get_cpu_vendor(&boot_cpu_data); - if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) + if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX || + boot_cpu_data.x86_vendor == X86_VENDOR_NSC ) init_cyrix(&boot_cpu_data); } /* These need to match */ static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; + "Intel", "Cyrix", "AMD", "UMC", "NexGen", + "Centaur", "Rise", "Transmeta", "NSC" +}; void __init print_cpu_info(struct cpuinfo_x86 *c) diff -urN linux-2.4.18/arch/i386/kernel/signal.c linux-2.4.19-pre5/arch/i386/kernel/signal.c --- linux-2.4.18/arch/i386/kernel/signal.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -685,10 +685,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/i386/kernel/smpboot.c linux-2.4.19-pre5/arch/i386/kernel/smpboot.c --- linux-2.4.18/arch/i386/kernel/smpboot.c Sun Dec 23 16:23:35 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/smpboot.c Sat Mar 30 22:55:25 2002 @@ -213,7 +213,7 @@ * ^---- (this multiplication can overflow) */ -static unsigned long long div64 (unsigned long long a, unsigned long b0) +static unsigned long long __init div64 (unsigned long long a, unsigned long b0) { unsigned int a1, a2; unsigned long long res; @@ -981,11 +981,14 @@ { int apicid, cpu, bit; - if (clustered_apic_mode) { - /* remap the 1st quad's 256k range for cross-quad I/O */ - xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN); - printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n", - (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN); + if (clustered_apic_mode && (numnodes > 1)) { + printk("Remapping cross-quad port I/O for %d quads\n", + numnodes); + printk("xquad_portio vaddr 0x%08lx, len %08lx\n", + (u_long) xquad_portio, + (u_long) numnodes * XQUAD_PORTIO_LEN); + xquad_portio = ioremap (XQUAD_PORTIO_BASE, + numnodes * XQUAD_PORTIO_LEN); } #ifdef CONFIG_MTRR diff -urN linux-2.4.18/arch/i386/kernel/traps.c linux-2.4.19-pre5/arch/i386/kernel/traps.c --- linux-2.4.18/arch/i386/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/kernel/traps.c Sat Mar 30 22:55:39 2002 @@ -237,6 +237,41 @@ printk("\n"); } +static void handle_BUG(struct pt_regs *regs) +{ + unsigned short ud2; + unsigned short line; + char *file; + char c; + unsigned long eip; + + if (regs->xcs & 3) + goto no_bug; /* Not in kernel */ + + eip = regs->eip; + + if (eip < PAGE_OFFSET) + goto no_bug; + if (__get_user(ud2, (unsigned short *)eip)) + goto no_bug; + if (ud2 != 0x0b0f) + goto no_bug; + if (__get_user(line, (unsigned short *)(eip + 2))) + goto bug; + if (__get_user(file, (char **)(eip + 4)) || + (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + file = ""; + + printk("kernel BUG at %s:%d!\n", file, line); + +no_bug: + return; + + /* Here we know it was a BUG but file-n-line is unavailable */ +bug: + printk("Kernel BUG\n"); +} + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) @@ -244,6 +279,7 @@ console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); + handle_BUG(regs); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); bust_spinlocks(0); @@ -505,6 +541,8 @@ * allowing programs to debug themselves without the ptrace() * interface. */ + if ((regs->xcs & 3) == 0) + goto clear_TF; if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } diff -urN linux-2.4.18/arch/i386/math-emu/reg_add_sub.c linux-2.4.19-pre5/arch/i386/math-emu/reg_add_sub.c --- linux-2.4.18/arch/i386/math-emu/reg_add_sub.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/math-emu/reg_add_sub.c Sat Mar 30 22:55:25 2002 @@ -140,7 +140,7 @@ FPU_REG const *a, *b; FPU_REG *dest; u_char taga, tagb, signa, signb, saved_sign, sign; - int diff, tag, expa, expb, deststnr; + int diff, tag = 0, expa, expb, deststnr; a = &st(0); taga = FPU_gettag0(); diff -urN linux-2.4.18/arch/i386/math-emu/reg_compare.c linux-2.4.19-pre5/arch/i386/math-emu/reg_compare.c --- linux-2.4.18/arch/i386/math-emu/reg_compare.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/math-emu/reg_compare.c Sat Mar 30 22:55:25 2002 @@ -174,7 +174,7 @@ /* This function requires that st(0) is not empty */ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { - int f, c; + int f = 0, c; c = compare(loaded_data, loaded_tag); @@ -216,7 +216,7 @@ static int compare_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) @@ -268,7 +268,7 @@ static int compare_u_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) diff -urN linux-2.4.18/arch/i386/math-emu/reg_divide.c linux-2.4.19-pre5/arch/i386/math-emu/reg_divide.c --- linux-2.4.18/arch/i386/math-emu/reg_divide.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/math-emu/reg_divide.c Sat Mar 30 22:55:25 2002 @@ -203,4 +203,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN linux-2.4.18/arch/i386/math-emu/reg_ld_str.c linux-2.4.19-pre5/arch/i386/math-emu/reg_ld_str.c --- linux-2.4.18/arch/i386/math-emu/reg_ld_str.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/math-emu/reg_ld_str.c Sat Mar 30 22:55:25 2002 @@ -632,7 +632,7 @@ /* Put a float into user memory */ int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single) { - long templ; + long templ = 0; unsigned long increment = 0; /* avoid gcc warnings */ int precision_loss; int exp; diff -urN linux-2.4.18/arch/i386/math-emu/reg_mul.c linux-2.4.19-pre5/arch/i386/math-emu/reg_mul.c --- linux-2.4.18/arch/i386/math-emu/reg_mul.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/math-emu/reg_mul.c Sat Mar 30 22:55:25 2002 @@ -128,4 +128,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN linux-2.4.18/arch/i386/mm/fault.c linux-2.4.19-pre5/arch/i386/mm/fault.c --- linux-2.4.18/arch/i386/mm/fault.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/i386/mm/fault.c Sat Mar 30 22:55:39 2002 @@ -125,12 +125,6 @@ } } -void do_BUG(const char *file, int line) -{ - bust_spinlocks(1); - printk("kernel BUG at %s:%d!\n", file, line); -} - asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); extern unsigned long idt; diff -urN linux-2.4.18/arch/i386/mm/init.c linux-2.4.19-pre5/arch/i386/mm/init.c --- linux-2.4.18/arch/i386/mm/init.c Sun Dec 23 16:23:35 2001 +++ linux-2.4.19-pre5/arch/i386/mm/init.c Sat Mar 30 22:55:39 2002 @@ -128,7 +128,6 @@ static inline void set_pte_phys (unsigned long vaddr, unsigned long phys, pgprot_t flags) { - pgprot_t prot; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -144,10 +143,8 @@ return; } pte = pte_offset(pmd, vaddr); - if (pte_val(*pte)) - pte_ERROR(*pte); - pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); - set_pte(pte, mk_pte_phys(phys, prot)); + /* stored as-is, to permit clearing entries */ + set_pte(pte, mk_pte_phys(phys, flags)); /* * It's enough to flush this one mapping. @@ -462,8 +459,9 @@ #ifdef CONFIG_HIGHMEM highmem_start_page = mem_map + highstart_pfn; max_mapnr = num_physpages = highend_pfn; + num_mappedpages = max_low_pfn; #else - max_mapnr = num_physpages = max_low_pfn; + max_mapnr = num_mappedpages = num_physpages = max_low_pfn; #endif high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); @@ -505,7 +503,7 @@ datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codesize >> 10, @@ -569,14 +567,14 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); diff -urN linux-2.4.18/arch/i386/mm/ioremap.c linux-2.4.19-pre5/arch/i386/mm/ioremap.c --- linux-2.4.18/arch/i386/mm/ioremap.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/i386/mm/ioremap.c Sat Mar 30 22:55:33 2002 @@ -161,3 +161,68 @@ if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long) addr)); } + +void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) +{ + unsigned long offset, last_addr; + unsigned int nrpages; + enum fixed_addresses idx; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && last_addr < 0x100000) + return phys_to_virt(phys_addr); + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Mappings have to fit in the FIX_BTMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > NR_FIX_BTMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + set_fixmap(idx, phys_addr); + phys_addr += PAGE_SIZE; + --idx; + --nrpages; + } + return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); +} + +void __init bt_iounmap(void *addr, unsigned long size) +{ + unsigned long virt_addr; + unsigned long offset; + unsigned int nrpages; + enum fixed_addresses idx; + + virt_addr = (unsigned long)addr; + if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) + return; + offset = virt_addr & ~PAGE_MASK; + nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; + + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + __set_fixmap(idx, 0, __pgprot(0)); + --idx; + --nrpages; + } +} diff -urN linux-2.4.18/arch/ia64/Makefile linux-2.4.19-pre5/arch/ia64/Makefile --- linux-2.4.18/arch/ia64/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/Makefile Sat Mar 30 22:55:25 2002 @@ -25,7 +25,7 @@ GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') ifneq ($(GCC_VERSION),2) - CFLAGS += -frename-registers --param max-inline-insns=400 + CFLAGS += -frename-registers --param max-inline-insns=2000 endif ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) @@ -58,7 +58,7 @@ CFLAGS += -DBRINGUP SUBDIRS := arch/$(ARCH)/sn/kernel \ arch/$(ARCH)/sn/io \ - arch/$(ARCH)/sn/fprom \ + arch/$(ARCH)/sn/fakeprom \ $(SUBDIRS) CORE_FILES := arch/$(ARCH)/sn/kernel/sn.o \ arch/$(ARCH)/sn/io/sgiio.o \ diff -urN linux-2.4.18/arch/ia64/config.in linux-2.4.19-pre5/arch/ia64/config.in --- linux-2.4.18/arch/ia64/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/config.in Sat Mar 30 22:55:25 2002 @@ -135,6 +135,7 @@ source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in +source drivers/ieee1394/Config.in source drivers/message/i2o/Config.in source drivers/md/Config.in @@ -244,7 +245,7 @@ mainmenu_option next_comment comment 'Simulated drivers' - tristate 'Simulated Ethernet ' CONFIG_SIMETH + bool 'Simulated Ethernet ' CONFIG_SIMETH bool 'Simulated serial driver support' CONFIG_SIM_SERIAL if [ "$CONFIG_SCSI" != "n" ]; then bool 'Simulated SCSI disk' CONFIG_SCSI_SIM @@ -266,9 +267,7 @@ bool ' Disable VHPT' CONFIG_DISABLE_VHPT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ -# early printk is currently broken for SMP: the secondary processors get stuck... -# bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK - + bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG diff -urN linux-2.4.18/arch/ia64/defconfig linux-2.4.19-pre5/arch/ia64/defconfig --- linux-2.4.18/arch/ia64/defconfig Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/defconfig Sat Mar 30 22:55:25 2002 @@ -299,6 +299,7 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -373,6 +374,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -554,6 +556,9 @@ # CONFIG_TUNER_3036 is not set # CONFIG_VIDEO_STRADIS is not set # CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set # CONFIG_VIDEO_ZR36120 is not set # CONFIG_VIDEO_MEYE is not set @@ -584,11 +589,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set @@ -626,6 +635,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_ROOT_NFS is not set @@ -874,6 +884,7 @@ CONFIG_IA64_PRINT_HAZARDS=y # CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set diff -urN linux-2.4.18/arch/ia64/ia32/binfmt_elf32.c linux-2.4.19-pre5/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.18/arch/ia64/ia32/binfmt_elf32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/binfmt_elf32.c Sat Mar 30 22:55:25 2002 @@ -142,10 +142,11 @@ /* * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 - * architecture manual. + * architecture manual. Also note that the only fields that are not ignored are + * `base', `limit', 'G', `P' (must be 1) and `S' (must be 0). */ - regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, - 0, 0, 0, 0, 0, 0)); + regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, + 0, 0, 0, 1, 0, 0, 0)); /* Setup the segment selectors */ regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ @@ -206,6 +207,7 @@ set_personality(PER_LINUX32); current->thread.map_base = IA32_PAGE_OFFSET/3; current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ + current->thread.flags |= IA64_THREAD_XSTACK; /* data must be executable */ set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ } diff -urN linux-2.4.18/arch/ia64/ia32/ia32_entry.S linux-2.4.19-pre5/arch/ia64/ia32/ia32_entry.S --- linux-2.4.18/arch/ia64/ia32/ia32_entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/ia32_entry.S Sat Mar 30 22:55:25 2002 @@ -37,7 +37,7 @@ mov loc1=r16 // save ar.pfs across do_fork .body zxt4 out1=in1 // newsp - mov out3=0 // stacksize + mov out3=16 // stacksize (compensates for 16-byte scratch area) adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s zxt4 out0=in0 // out0 = clone_flags br.call.sptk.many rp=do_fork @@ -220,7 +220,7 @@ data8 sys32_pipe data8 sys32_times data8 sys32_ni_syscall /* old prof syscall holder */ - data8 sys_brk /* 45 */ + data8 sys32_brk /* 45 */ data8 sys_setgid /* 16-bit version */ data8 sys_getgid /* 16-bit version */ data8 sys32_signal diff -urN linux-2.4.18/arch/ia64/ia32/ia32_ioctl.c linux-2.4.19-pre5/arch/ia64/ia32/ia32_ioctl.c --- linux-2.4.18/arch/ia64/ia32/ia32_ioctl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/ia32_ioctl.c Sat Mar 30 22:55:25 2002 @@ -79,6 +79,38 @@ return ret; } + case IOCTL_NR(SIOCGIFCONF): + { + struct ifconf32 { + int ifc_len; + unsigned int ifc_ptr; + } ifconf32; + struct ifconf ifconf; + int i, n; + char *p32, *p64; + char buf[32]; /* sizeof IA32 ifreq structure */ + + if (copy_from_user(&ifconf32, P(arg), sizeof(ifconf32))) + return -EFAULT; + ifconf.ifc_len = ifconf32.ifc_len; + ifconf.ifc_req = P(ifconf32.ifc_ptr); + ret = DO_IOCTL(fd, SIOCGIFCONF, &ifconf); + ifconf32.ifc_len = ifconf.ifc_len; + if (copy_to_user(P(arg), &ifconf32, sizeof(ifconf32))) + return -EFAULT; + n = ifconf.ifc_len / sizeof(struct ifreq); + p32 = P(ifconf32.ifc_ptr); + p64 = P(ifconf32.ifc_ptr); + for (i = 0; i < n; i++) { + if (copy_from_user(buf, p64, sizeof(struct ifreq))) + return -EFAULT; + if (copy_to_user(p32, buf, sizeof(buf))) + return -EFAULT; + p32 += sizeof(buf); + p64 += sizeof(struct ifreq); + } + return ret; + } case IOCTL_NR(DRM_IOCTL_VERSION): { diff -urN linux-2.4.18/arch/ia64/ia32/ia32_signal.c linux-2.4.19-pre5/arch/ia64/ia32/ia32_signal.c --- linux-2.4.18/arch/ia64/ia32/ia32_signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/ia32_signal.c Sat Mar 30 22:55:25 2002 @@ -522,6 +522,7 @@ static int setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { + struct exec_domain *ed = current->exec_domain; struct sigframe_ia32 *frame; int err = 0; @@ -530,12 +531,8 @@ 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 |= __put_user((ed && ed->signal_invmap + && sig < 32 ? (int)(ed->signal_invmap[sig]) : sig), &frame->sig); err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); @@ -590,6 +587,7 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { + struct exec_domain *ed = current->exec_domain; struct rt_sigframe_ia32 *frame; int err = 0; @@ -598,11 +596,8 @@ 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), + err |= __put_user((ed && ed->signal_invmap + && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig); err |= __put_user((long)&frame->info, &frame->pinfo); err |= __put_user((long)&frame->uc, &frame->puc); diff -urN linux-2.4.18/arch/ia64/ia32/ia32_support.c linux-2.4.19-pre5/arch/ia64/ia32/ia32_support.c --- linux-2.4.18/arch/ia64/ia32/ia32_support.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/ia32_support.c Sat Mar 30 22:55:25 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 1999 Arun Sharma * Copyright (C) 2000 Asit K. Mallick - * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001-2002 Hewlett-Packard Co * David Mosberger-Tang * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context @@ -153,10 +153,12 @@ /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */ ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); for (nr = 0; nr < NR_CPUS; ++nr) { - ia32_gdt[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, - 0xb, 0, 3, 1, 1, 1, 0); - ia32_gdt[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, - 0x2, 0, 3, 1, 1, 1, 0); + ia32_gdt[_TSS(nr) >> IA32_SEGSEL_INDEX_SHIFT] + = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, + 0xb, 0, 3, 1, 1, 1, 0); + ia32_gdt[_LDT(nr) >> IA32_SEGSEL_INDEX_SHIFT] + = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, + 0x2, 0, 3, 1, 1, 1, 0); } } @@ -172,6 +174,10 @@ siginfo.si_signo = SIGTRAP; siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_addr = 0; + siginfo.si_imm = 0; siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); } diff -urN linux-2.4.18/arch/ia64/ia32/ia32_traps.c linux-2.4.19-pre5/arch/ia64/ia32/ia32_traps.c --- linux-2.4.18/arch/ia64/ia32/ia32_traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/ia32_traps.c Sat Mar 30 22:55:25 2002 @@ -2,7 +2,7 @@ * IA-32 exception handlers * * Copyright (C) 2000 Asit K. Mallick - * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001-2002 Hewlett-Packard Co * David Mosberger-Tang * * 06/16/00 A. Mallick added siginfo for most cases (close to IA32) @@ -40,7 +40,11 @@ { struct siginfo siginfo; + /* initialize these fields to avoid leaking kernel bits to user space: */ siginfo.si_errno = 0; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_imm = 0; switch ((isr >> 16) & 0xff) { case 1: case 2: @@ -103,6 +107,8 @@ * and it will suffer the consequences since we won't be able to * fully reproduce the context of the exception */ + siginfo.si_isr = isr; + siginfo.si_flags = __ISR_VALID; switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) { case 0x000: default: diff -urN linux-2.4.18/arch/ia64/ia32/sys_ia32.c linux-2.4.19-pre5/arch/ia64/ia32/sys_ia32.c --- linux-2.4.18/arch/ia64/ia32/sys_ia32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/ia32/sys_ia32.c Sat Mar 30 22:55:25 2002 @@ -6,7 +6,7 @@ * 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) - * Copyright (C) 2000-2001 Hewlett-Packard Co + * Copyright (C) 2000-2002 Hewlett-Packard Co * David Mosberger-Tang * * These routines maintain argument size conversion between 32bit and 64bit @@ -82,6 +82,7 @@ /* forward declaration: */ asmlinkage long sys32_mprotect (unsigned int, unsigned int, int); +asmlinkage unsigned long sys_brk(unsigned long); /* * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore @@ -412,7 +413,7 @@ return -EINVAL; } if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0) - return EINVAL; + return -EINVAL; } return start; } @@ -2590,6 +2591,7 @@ default: return -EINVAL; } + return -EINVAL; } /* @@ -3807,6 +3809,19 @@ ret = sys_personality(personality); if (ret == PER_LINUX32) ret = PER_LINUX; + return ret; +} + +asmlinkage unsigned long +sys32_brk (unsigned int brk) +{ + unsigned long ret, obrk; + struct mm_struct *mm = current->mm; + + obrk = mm->brk; + ret = sys_brk(brk); + if (ret < obrk) + clear_user((void *) ret, PAGE_ALIGN(ret) - ret); return ret; } diff -urN linux-2.4.18/arch/ia64/kernel/Makefile linux-2.4.19-pre5/arch/ia64/kernel/Makefile --- linux-2.4.18/arch/ia64/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/Makefile Sat Mar 30 22:55:25 2002 @@ -14,7 +14,7 @@ export-objs := ia64_ksyms.o obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \ - machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ + machvec.o pal.o process.o perfmon.o ptrace.o sal.o salinfo.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o diff -urN linux-2.4.18/arch/ia64/kernel/acpi.c linux-2.4.19-pre5/arch/ia64/kernel/acpi.c --- linux-2.4.18/arch/ia64/kernel/acpi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/acpi.c Sat Mar 30 22:55:25 2002 @@ -401,7 +401,7 @@ # ifdef CONFIG_ACPI acpi_xsdt_t *xsdt; acpi_desc_table_hdr_t *hdrp; - acpi_madt_t *madt; + acpi_madt_t *madt = NULL; int tables, i; if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { diff -urN linux-2.4.18/arch/ia64/kernel/brl_emu.c linux-2.4.19-pre5/arch/ia64/kernel/brl_emu.c --- linux-2.4.18/arch/ia64/kernel/brl_emu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/brl_emu.c Sat Mar 30 22:55:25 2002 @@ -2,6 +2,9 @@ * Emulation of the "brl" instruction for IA64 processors that * don't support it in hardware. * Author: Stephan Zeisset, Intel Corp. + * + * 02/22/02 D. Mosberger Clear si_flgs, si_isr, and si_imm to avoid + * leaking kernel bits. */ #include @@ -195,6 +198,9 @@ printk("Woah! Unimplemented Instruction Address Trap!\n"); siginfo.si_signo = SIGILL; siginfo.si_errno = 0; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_imm = 0; siginfo.si_code = ILL_BADIADDR; force_sig_info(SIGILL, &siginfo, current); } else if (ia64_psr(regs)->tb) { @@ -205,6 +211,10 @@ siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; siginfo.si_code = TRAP_BRANCH; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_addr = 0; + siginfo.si_imm = 0; force_sig_info(SIGTRAP, &siginfo, current); } else if (ia64_psr(regs)->ss) { /* @@ -214,6 +224,10 @@ siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; siginfo.si_code = TRAP_TRACE; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_addr = 0; + siginfo.si_imm = 0; force_sig_info(SIGTRAP, &siginfo, current); } return rv; diff -urN linux-2.4.18/arch/ia64/kernel/efivars.c linux-2.4.19-pre5/arch/ia64/kernel/efivars.c --- linux-2.4.18/arch/ia64/kernel/efivars.c Sun Dec 23 16:23:35 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/efivars.c Sat Mar 30 22:55:25 2002 @@ -29,6 +29,11 @@ * * Changelog: * + * 12 Feb 2002 - Matt Domsch + * use list_for_each_safe when deleting vars. + * remove ifdef CONFIG_SMP around include + * v0.04 release to linux-ia64@linuxia64.org + * * 20 April 2001 - Matt Domsch * Moved vars from /proc/efi to /proc/efi/vars, and made * efi.c own the /proc/efi directory. @@ -56,18 +61,16 @@ #include /* for capable() */ #include #include +#include #include #include -#ifdef CONFIG_SMP -#include -#endif MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("/proc interface to EFI Variables"); MODULE_LICENSE("GPL"); -#define EFIVARS_VERSION "0.03 2001-Apr-20" +#define EFIVARS_VERSION "0.04 2002-Feb-12" static int efivar_read(char *page, char **start, off_t off, @@ -265,7 +268,7 @@ { unsigned long strsize1, strsize2; int found=0; - struct list_head *pos; + struct list_head *pos, *n; unsigned long size = sizeof(efi_variable_t); efi_status_t status; efivar_entry_t *efivar = data, *search_efivar = NULL; @@ -297,7 +300,7 @@ This allows any properly formatted data structure to be written to any of the files in /proc/efi/vars and it will work. */ - list_for_each(pos, &efivar_list) { + list_for_each_safe(pos, n, &efivar_list) { search_efivar = efivar_entry(pos); strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); strsize2 = utf8_strsize(var_data->VariableName, 1024); @@ -413,12 +416,12 @@ static void __exit efivars_exit(void) { - struct list_head *pos; + struct list_head *pos, *n; efivar_entry_t *efivar; spin_lock(&efivars_lock); - list_for_each(pos, &efivar_list) { + list_for_each_safe(pos, n, &efivar_list) { efivar = efivar_entry(pos); remove_proc_entry(efivar->entry->name, efi_vars_dir); list_del(&efivar->list); diff -urN linux-2.4.18/arch/ia64/kernel/entry.S linux-2.4.19-pre5/arch/ia64/kernel/entry.S --- linux-2.4.18/arch/ia64/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -115,7 +115,7 @@ mov loc1=r16 // save ar.pfs across do_fork .body mov out1=in1 - mov out3=0 + mov out3=16 // stacksize (compensates for 16-byte scratch area) adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags br.call.sptk.many rp=do_fork @@ -521,35 +521,38 @@ ;; mov.ret.sptk rp=r14,.restart .restart: + // need_resched and signals atomic test +(pUser) rsm psr.i adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 adds r18=IA64_TASK_SIGPENDING_OFFSET,r13 #ifdef CONFIG_PERFMON - adds r19=IA64_TASK_PFM_MUST_BLOCK_OFFSET,r13 + adds r19=IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET,r13 #endif ;; #ifdef CONFIG_PERFMON -(pUser) ld8 r19=[r19] // load current->thread.pfm_must_block +(pUser) ld8 r19=[r19] // load current->thread.pfm_ovfl_block_reset #endif (pUser) ld8 r17=[r17] // load current->need_resched (pUser) ld4 r18=[r18] // load current->sigpending ;; #ifdef CONFIG_PERFMON -(pUser) cmp.ne.unc p9,p0=r19,r0 // current->thread.pfm_must_block != 0? +(pUser) cmp.ne.unc p9,p0=r19,r0 // current->thread.pfm_ovfl_block_reset != 0? #endif (pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? (pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? ;; - adds r2=PT(R8)+16,r12 - adds r3=PT(R9)+16,r12 #ifdef CONFIG_PERFMON -(p9) br.call.spnt.many b7=pfm_block_on_overflow +(p9) br.call.spnt.many b7=pfm_ovfl_block_reset #endif #if __GNUC__ < 3 (p7) br.call.spnt.many b7=invoke_schedule #else (p7) br.call.spnt.many b7=schedule #endif -(p8) br.call.spnt.many b7=handle_signal_delivery // check & deliver pending signals +(p8) br.call.spnt.many rp=handle_signal_delivery // check & deliver pending signals (once) + ;; +.ret9: adds r2=PT(R8)+16,r12 + adds r3=PT(R9)+16,r12 ;; // start restoring the state saved on the kernel stack (struct pt_regs): ld8.fill r8=[r2],16 @@ -582,7 +585,7 @@ ld8.fill r30=[r2],16 ld8.fill r31=[r3],16 ;; - rsm psr.i | psr.ic // initiate turning off of interrupts & interruption collection + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection invala // invalidate ALAT ;; ld8 r1=[r2],16 // ar.ccv @@ -601,7 +604,7 @@ mov ar.fpsr=r13 mov b0=r14 ;; - srlz.i // ensure interrupts & interruption collection are off + srlz.i // ensure interruption collection is off mov b7=r15 ;; bsw.0 // switch back to bank 0 @@ -1142,7 +1145,7 @@ data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_tkill data8 ia64_ni_syscall // 1230 data8 ia64_ni_syscall data8 ia64_ni_syscall diff -urN linux-2.4.18/arch/ia64/kernel/gate.S linux-2.4.19-pre5/arch/ia64/kernel/gate.S --- linux-2.4.18/arch/ia64/kernel/gate.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/gate.S Sat Mar 30 22:55:25 2002 @@ -90,7 +90,7 @@ (p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16) back_from_setup_rbs: - .save ar.pfs, r8 + .spillreg ar.pfs, r8 alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 ld8 out0=[base0],16 // load arg0 (signum) adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 diff -urN linux-2.4.18/arch/ia64/kernel/head.S linux-2.4.19-pre5/arch/ia64/kernel/head.S --- linux-2.4.18/arch/ia64/kernel/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/head.S Sat Mar 30 22:55:25 2002 @@ -180,10 +180,12 @@ .rodata alive_msg: stringz "I'm alive and well\n" +alive_msg_end: .previous alloc r2=ar.pfs,0,0,2,0 movl out0=alive_msg + movl out1=alive_msg_end-alive_msg-1 ;; br.call.sptk.many rp=early_printk 1: // force new bundle diff -urN linux-2.4.18/arch/ia64/kernel/ia64_ksyms.c linux-2.4.19-pre5/arch/ia64/kernel/ia64_ksyms.c --- linux-2.4.18/arch/ia64/kernel/ia64_ksyms.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/ia64_ksyms.c Sat Mar 30 22:55:25 2002 @@ -24,6 +24,7 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); #include EXPORT_SYMBOL(isa_irq_to_vector_map); diff -urN linux-2.4.18/arch/ia64/kernel/iosapic.c linux-2.4.19-pre5/arch/ia64/kernel/iosapic.c --- linux-2.4.18/arch/ia64/kernel/iosapic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/iosapic.c Sat Mar 30 22:55:25 2002 @@ -3,8 +3,9 @@ * * 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) 2000-2002 J.I. Lee + * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co. + * David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond * @@ -15,6 +16,12 @@ * PCI to vector mapping, shared PCI interrupts. * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. * Clean up much of the old IOSAPIC cruft. + * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for + * ACPI S5(SoftOff) support. + * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT + * 02/01/07 E. Focht Redirectable interrupt vectors in + * iosapic_set_affinity(), initializations for + * /proc/irq/#/smp_affinity */ /* * Here is what the interrupt logic between a PCI device and the CPU looks like: @@ -63,6 +70,7 @@ #undef DEBUG_IRQ_ROUTING +#undef OVERRIDE_DEBUG static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; @@ -88,7 +96,7 @@ * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no * entry exists, return -1. */ -static int +int iosapic_irq_to_vector (int irq) { int vector; @@ -121,6 +129,7 @@ u32 low32, high32; char *addr; int pin; + char redir; pin = iosapic_irq[vector].pin; if (pin < 0) @@ -131,6 +140,11 @@ trigger = iosapic_irq[vector].trigger; dmode = iosapic_irq[vector].dmode; + redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; +#ifdef CONFIG_SMP + set_irq_affinity_info(vector, (int)(dest & 0xffff), redir); +#endif + low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | (trigger << IOSAPIC_TRIGGER_SHIFT) | (dmode << IOSAPIC_DELIVERY_SHIFT) | @@ -211,6 +225,7 @@ u32 high32, low32; int dest, pin; char *addr; + int redir = (irq & (1<<31)) ? 1 : 0; mask &= (1UL << smp_num_cpus) - 1; @@ -225,6 +240,8 @@ if (pin < 0) return; /* not an IOSAPIC interrupt */ + set_irq_affinity_info(irq,dest,redir); + /* dest contains both id and eid */ high32 = dest << IOSAPIC_DEST_SHIFT; @@ -234,9 +251,13 @@ writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); - /* change delivery mode to fixed */ low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT); - low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); + if (redir) + /* change delivery mode to lowest priority */ + low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); + else + /* change delivery mode to fixed */ + low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); @@ -343,29 +364,64 @@ } /* - * ACPI can describe IOSAPIC interrupts via static tables and namespace - * methods. This provides an interface to register those interrupts and - * program the IOSAPIC RTE. + * if the given vector is already owned by other, + * assign a new vector for the other and make the vector available */ -int -iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long - edge_triggered, u32 base_irq, char *iosapic_address) +static void +iosapic_reassign_vector (int vector) +{ + int new_vector; + + if (iosapic_irq[vector].pin >= 0 || iosapic_irq[vector].addr + || iosapic_irq[vector].base_irq || iosapic_irq[vector].dmode + || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger) + { + new_vector = ia64_alloc_irq(); + printk("Reassigning Vector 0x%x to 0x%x\n", vector, new_vector); + memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector], + sizeof(struct iosapic_irq)); + memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq)); + iosapic_irq[vector].pin = -1; + } +} + +static void +register_irq (u32 global_vector, int vector, int pin, unsigned char delivery, + unsigned long polarity, unsigned long edge_triggered, + u32 base_irq, char *iosapic_address) { irq_desc_t *idesc; struct hw_interrupt_type *irq_type; - int vector; - vector = iosapic_irq_to_vector(global_vector); - if (vector < 0) - vector = ia64_alloc_irq(); - - /* fill in information from this vector's IOSAPIC */ - iosapic_irq[vector].addr = iosapic_address; - iosapic_irq[vector].base_irq = base_irq; - iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; + iosapic_irq[vector].pin = pin; iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; - iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + iosapic_irq[vector].dmode = delivery; + /* + * In override, it does not provide addr/base_irq. global_vector is enough to + * locate iosapic addr, base_irq and pin by examining base_irq and max_pin of + * registered iosapics (tbd) + */ +#ifndef OVERRIDE_DEBUG + if (iosapic_address) { + iosapic_irq[vector].addr = iosapic_address; + iosapic_irq[vector].base_irq = base_irq; + } +#else + if (iosapic_address) { + if (iosapic_irq[vector].addr && (iosapic_irq[vector].addr != iosapic_address)) + printk("WARN: register_irq: diff IOSAPIC ADDRESS for gv %x, v %x\n", + global_vector, vector); + iosapic_irq[vector].addr = iosapic_address; + if (iosapic_irq[vector].base_irq && (iosapic_irq[vector].base_irq != base_irq)) { + printk("WARN: register_irq: diff BASE IRQ %x for gv %x, v %x\n", + base_irq, global_vector, vector); + } + iosapic_irq[vector].base_irq = base_irq; + } else if (!iosapic_irq[vector].addr) + printk("WARN: register_irq: invalid override for gv %x, v %x\n", + global_vector, vector); +#endif if (edge_triggered) { iosapic_irq[vector].trigger = IOSAPIC_EDGE; irq_type = &irq_type_iosapic_edge; @@ -377,12 +433,32 @@ idesc = irq_desc(vector); if (idesc->handler != irq_type) { if (idesc->handler != &no_irq_type) - printk("iosapic_register_irq(): changing vector 0x%02x from" + printk("register_irq(): changing vector 0x%02x from " "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); idesc->handler = irq_type; } +} + +/* + * ACPI can describe IOSAPIC interrupts via static tables and namespace + * methods. This provides an interface to register those interrupts and + * program the IOSAPIC RTE. + */ +int +iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long + edge_triggered, u32 base_irq, char *iosapic_address) +{ + int vector; - printk("IOSAPIC %x(%s,%s) -> Vector %x\n", global_vector, + vector = iosapic_irq_to_vector(global_vector); + if (vector < 0) + vector = ia64_alloc_irq(); + + register_irq (global_vector, vector, global_vector - base_irq, + IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, + base_irq, iosapic_address); + + printk("IOSAPIC 0x%x(%s,%s) -> Vector 0x%x\n", global_vector, (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector); /* program the IOSAPIC routing table */ @@ -395,51 +471,40 @@ * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */ int -iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, - u16 eid, u16 id, unsigned long polarity, +iosapic_register_platform_irq (u32 int_type, u32 global_vector, + u32 iosapic_vector, u16 eid, u16 id, unsigned long polarity, unsigned long edge_triggered, u32 base_irq, char *iosapic_address) { - struct hw_interrupt_type *irq_type; - irq_desc_t *idesc; + unsigned char delivery; int vector; switch (int_type) { - case ACPI20_ENTRY_PIS_CPEI: + case ACPI20_ENTRY_PIS_PMI: + vector = iosapic_vector; + /* + * since PMI vector is alloc'd by FW(ACPI) not by kernel, + * we need to make sure the vector is available + */ + iosapic_reassign_vector(vector); + delivery = IOSAPIC_PMI; + break; + case ACPI20_ENTRY_PIS_CPEI: vector = IA64_PCE_VECTOR; - iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + delivery = IOSAPIC_LOWEST_PRIORITY; break; - case ACPI20_ENTRY_PIS_INIT: + case ACPI20_ENTRY_PIS_INIT: vector = ia64_alloc_irq(); - iosapic_irq[vector].dmode = IOSAPIC_INIT; + delivery = IOSAPIC_INIT; break; - default: + default: printk("iosapic_register_platform_irq(): invalid int type\n"); return -1; } - /* fill in information from this vector's IOSAPIC */ - iosapic_irq[vector].addr = iosapic_address; - iosapic_irq[vector].base_irq = base_irq; - iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; - iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; - - if (edge_triggered) { - iosapic_irq[vector].trigger = IOSAPIC_EDGE; - irq_type = &irq_type_iosapic_edge; - } else { - iosapic_irq[vector].trigger = IOSAPIC_LEVEL; - irq_type = &irq_type_iosapic_level; - } - - idesc = irq_desc(vector); - if (idesc->handler != irq_type) { - if (idesc->handler != &no_irq_type) - printk("iosapic_register_platform_irq(): changing vector 0x%02x from" - "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); - idesc->handler = irq_type; - } + register_irq(global_vector, vector, global_vector - base_irq, delivery, polarity, + edge_triggered, base_irq, iosapic_address); - printk("PLATFORM int %x: IOSAPIC %x(%s,%s) -> Vector %x CPU %.02u:%.02u\n", + printk("PLATFORM int 0x%x: IOSAPIC 0x%x(%s,%s) -> Vector 0x%x CPU %.02u:%.02u\n", int_type, global_vector, (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector, eid, id); @@ -450,15 +515,18 @@ /* - * ACPI calls this when it finds an entry for a legacy ISA interrupt. Note that the - * irq_base and IOSAPIC address must be set in iosapic_init(). + * ACPI calls this when it finds an entry for a legacy ISA interrupt. + * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */ void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin, unsigned long polarity, unsigned long edge_triggered) { - unsigned int vector = isa_irq_to_vector(irq); + int vector = isa_irq_to_vector(irq); + + register_irq(irq, vector, (int)pin, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, + 0, NULL); /* ignored for override */ #ifdef DEBUG_IRQ_ROUTING printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n", @@ -467,18 +535,14 @@ vector); #endif - iosapic_irq[vector].pin = pin; - iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; - iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; - iosapic_irq[vector].trigger = edge_triggered ? IOSAPIC_EDGE : IOSAPIC_LEVEL; + /* program the IOSAPIC routing table */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } void __init iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat) { - struct hw_interrupt_type *irq_type; - int i, irq, max_pin, vector; - irq_desc_t *idesc; + int i, irq, max_pin, vector, pin; unsigned int ver; char *addr; static int first_time = 1; @@ -496,7 +560,6 @@ } addr = ioremap(phys_addr, 0); - ver = iosapic_version(addr); max_pin = (ver >> 16) & 0xff; @@ -511,27 +574,18 @@ */ for (irq = 0; irq < 16; ++irq) { vector = isa_irq_to_vector(irq); - iosapic_irq[vector].addr = addr; - iosapic_irq[vector].base_irq = 0; - if (iosapic_irq[vector].pin == -1) - iosapic_irq[vector].pin = irq; - iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; - iosapic_irq[vector].trigger = IOSAPIC_EDGE; - iosapic_irq[vector].polarity = IOSAPIC_POL_HIGH; + if ((pin = iosapic_irq[vector].pin) == -1) + pin = irq; + + register_irq(irq, vector, pin, + /* IOSAPIC_POL_HIGH, IOSAPIC_EDGE */ + IOSAPIC_LOWEST_PRIORITY, 1, 1, base_irq, addr); + #ifdef DEBUG_IRQ_ROUTING printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n", irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); #endif - irq_type = &irq_type_iosapic_edge; - idesc = irq_desc(vector); - if (idesc->handler != irq_type) { - if (idesc->handler != &no_irq_type) - printk("iosapic_init: changing vector 0x%02x from %s to " - "%s\n", irq, idesc->handler->typename, - irq_type->typename); - idesc->handler = irq_type; - } /* program the IOSAPIC routing table: */ set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); @@ -540,7 +594,7 @@ for (i = 0; i < pci_irq.num_routes; i++) { irq = pci_irq.route[i].irq; - if ((unsigned) (irq - base_irq) > max_pin) + if ((irq < (int)base_irq) || (irq > (int)(base_irq + max_pin))) /* the interrupt route is for another controller... */ continue; @@ -553,29 +607,18 @@ vector = ia64_alloc_irq(); } - iosapic_irq[vector].addr = addr; - iosapic_irq[vector].base_irq = base_irq; - iosapic_irq[vector].pin = (irq - base_irq); - iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; - iosapic_irq[vector].trigger = IOSAPIC_LEVEL; - iosapic_irq[vector].polarity = IOSAPIC_POL_LOW; + register_irq(irq, vector, irq - base_irq, + /* IOSAPIC_POL_LOW, IOSAPIC_LEVEL */ + IOSAPIC_LOWEST_PRIORITY, 0, 0, base_irq, addr); # ifdef DEBUG_IRQ_ROUTING printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n", pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); # endif - irq_type = &irq_type_iosapic_level; - idesc = irq_desc(vector); - if (idesc->handler != irq_type){ - if (idesc->handler != &no_irq_type) - printk("iosapic_init: changing vector 0x%02x from %s to %s\n", - vector, idesc->handler->typename, irq_type->typename); - idesc->handler = irq_type; - } - /* program the IOSAPIC routing table: */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + /* program the IOSAPIC routing table: */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } } @@ -585,6 +628,8 @@ struct pci_dev *dev; unsigned char pin; int vector; + struct hw_interrupt_type *irq_type; + irq_desc_t *idesc; if (phase != 1) return; @@ -611,19 +656,28 @@ if (vector >= 0) printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n", - bridge->bus->number, PCI_SLOT(bridge->devfn), + dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); else printk(KERN_WARNING - "PCI: Couldn't map irq for (B%d,I%d,P%d)o\n", - bridge->bus->number, PCI_SLOT(bridge->devfn), - pin); + "PCI: Couldn't map irq for (B%d,I%d,P%d)\n", + dev->bus->number, PCI_SLOT(dev->devfn), pin); } if (vector >= 0) { printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); dev->irq = vector; + irq_type = &irq_type_iosapic_level; + idesc = irq_desc(vector); + if (idesc->handler != irq_type){ + if (idesc->handler != &no_irq_type) + printk("iosapic_pci_fixup: changing vector 0x%02x " + "from %s to %s\n", vector, + idesc->handler->typename, + irq_type->typename); + idesc->handler = irq_type; + } #ifdef CONFIG_SMP /* * For platforms that do not support interrupt redirect @@ -638,7 +692,16 @@ cpu_index++; if (cpu_index >= smp_num_cpus) cpu_index = 0; + } else { + /* + * Direct the interrupt vector to the current cpu, + * platform redirection will distribute them. + */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); } +#else + /* direct the interrupt vector to the running cpu id */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); #endif } } diff -urN linux-2.4.18/arch/ia64/kernel/irq.c linux-2.4.19-pre5/arch/ia64/kernel/irq.c --- linux-2.4.18/arch/ia64/kernel/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/irq.c Sat Mar 30 22:55:25 2002 @@ -287,10 +287,11 @@ * already executing in one.. */ if (!irqs_running()) - if (local_bh_count() || !spin_is_locked(&global_bh_lock)) + if (really_local_bh_count() || !spin_is_locked(&global_bh_lock)) break; /* Duh, we have to loop. Release the lock to avoid deadlocks */ + smp_mb__before_clear_bit(); /* need barrier before releasing lock... */ clear_bit(0,&global_irq_lock); for (;;) { @@ -305,7 +306,7 @@ continue; if (global_irq_lock) continue; - if (!local_bh_count() && spin_is_locked(&global_bh_lock)) + if (!really_local_bh_count() && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -378,14 +379,14 @@ __save_flags(flags); if (flags & IA64_PSR_I) { __cli(); - if (!local_irq_count()) + if (!really_local_irq_count()) get_irqlock(); } #else __save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { __cli(); - if (!local_irq_count()) + if (!really_local_irq_count()) get_irqlock(); } #endif @@ -393,7 +394,7 @@ void __global_sti(void) { - if (!local_irq_count()) + if (!really_local_irq_count()) release_irqlock(smp_processor_id()); __sti(); } @@ -422,7 +423,7 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count()) { + if (!really_local_irq_count()) { if (local_enabled) retval = 1; if (global_irq_holder == cpu) @@ -529,7 +530,7 @@ disable_irq_nosync(irq); #ifdef CONFIG_SMP - if (!local_irq_count()) { + if (!really_local_irq_count()) { do { barrier(); } while (irq_desc(irq)->status & IRQ_INPROGRESS); @@ -1009,6 +1010,11 @@ rand_initialize_irq(irq); } + if (new->flags & SA_PERCPU_IRQ) { + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_ia64_lsapic; + } + /* * The following block of code has to be executed atomically */ @@ -1089,13 +1095,25 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; + +void set_irq_affinity_info(int irq, int hwid, int redir) +{ + unsigned long mask = 1UL<= 0 && irq < NR_IRQS) { + irq_affinity[irq] = mask; + irq_redir[irq] = (char) (redir & 0xff); + } +} static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { - if (count < HEX_DIGITS+1) + if (count < HEX_DIGITS+3) return -EINVAL; - return sprintf (page, "%08lx\n", irq_affinity[(long)data]); + return sprintf (page, "%s%08lx\n", irq_redir[(long)data] ? "r " : "", + irq_affinity[(long)data]); } static int irq_affinity_write_proc (struct file *file, const char *buffer, @@ -1103,11 +1121,20 @@ { int irq = (long) data, full_count = count, err; unsigned long new_value; + const char *buf = buffer; + int redir; if (!irq_desc(irq)->handler->set_affinity) return -EIO; - err = parse_hex_value(buffer, count, &new_value); + if (buf[0] == 'r' || buf[0] == 'R') { + ++buf; + while (*buf == ' ') ++buf; + redir = 1; + } else + redir = 0; + + err = parse_hex_value(buf, count, &new_value); /* * Do not allow disabling IRQs completely - it's a too easy @@ -1117,8 +1144,7 @@ if (!(new_value & cpu_online_map)) return -EINVAL; - irq_affinity[irq] = new_value; - irq_desc(irq)->handler->set_affinity(irq, new_value); + irq_desc(irq)->handler->set_affinity(irq | (redir?(1<<31):0), new_value); return full_count; } diff -urN linux-2.4.18/arch/ia64/kernel/ivt.S linux-2.4.19-pre5/arch/ia64/kernel/ivt.S --- linux-2.4.18/arch/ia64/kernel/ivt.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/ivt.S Sat Mar 30 22:55:25 2002 @@ -275,6 +275,7 @@ mov r16=cr.ifa // get address that caused the TLB miss movl r17=PAGE_KERNEL mov r21=cr.ipsr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) mov r31=pr ;; #ifdef CONFIG_DISABLE_VHPT @@ -289,12 +290,12 @@ (p8) br.cond.dptk itlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r19=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) cmp.ne p8,p0=r0,r23 // psr.cpl != 0? - dep r19=r17,r19,0,12 // insert PTE control bits into r19 + or r19=r17,r19 // insert PTE control bits into r19 ;; or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 (p8) br.cond.spnt page_fault @@ -312,6 +313,7 @@ mov r16=cr.ifa // get address that caused the TLB miss movl r17=PAGE_KERNEL mov r20=cr.isr + movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) mov r21=cr.ipsr mov r31=pr ;; @@ -328,15 +330,15 @@ #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? + and r19=r19,r16 // clear ed, reserved bits, and PTE control bits shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r19=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) cmp.ne p8,p0=r0,r23 (p8) br.cond.spnt page_fault dep r21=-1,r21,IA64_PSR_ED_BIT,1 - dep r19=r17,r19,0,12 // insert PTE control bits into r19 + or r19=r19,r17 // insert PTE control bits into r19 ;; or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 (p6) mov cr.ipsr=r21 diff -urN linux-2.4.18/arch/ia64/kernel/mca.c linux-2.4.19-pre5/arch/ia64/kernel/mca.c --- linux-2.4.18/arch/ia64/kernel/mca.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/mca.c Sat Mar 30 22:55:25 2002 @@ -3,6 +3,9 @@ * Purpose: Generic MCA handling layer * * Updated for latest kernel + * Copyright (C) 2002 Intel + * Copyright (C) Jenna Hall (jenna.s.hall@intel.com) + * * Copyright (C) 2001 Intel * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com) * @@ -12,6 +15,11 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * + * 02/01/04 J. Hall Aligned MCA stack to 16 bytes, added platform vs. CPU + * error flag, set SAL default return values, changed + * error record structure to linked list, added init call + * to sal_get_state_info_size(). + * * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected * platform errors, completed code for logging of * corrected & uncorrected machine check errors, and @@ -27,6 +35,7 @@ #include #include #include +#include #include #include @@ -50,18 +59,22 @@ 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[512]; -u64 ia64_mca_stack[1024]; +u64 ia64_mca_stack[1024] __attribute__((aligned(16))); u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); +u64 ia64_mca_sal_data_area[1356]; +u64 ia64_mca_min_state_save_info; +u64 ia64_tlb_functional; +u64 ia64_os_mca_recovery_successful; 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); -extern void ia64_monarch_init_handler (void); -extern void ia64_slave_init_handler (void); -extern struct hw_interrupt_type irq_type_iosapic_level; +extern void ia64_monarch_init_handler (void); +extern void ia64_slave_init_handler (void); +extern struct hw_interrupt_type irq_type_iosapic_level; static struct irqaction cmci_irqaction = { handler: ia64_mca_cmc_int_handler, @@ -95,25 +108,31 @@ * memory. * * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) - * Outputs : None + * Outputs : platform error status */ -void +int ia64_mca_log_sal_error_record(int sal_info_type) { + int platform_err = 0; + /* Get the MCA error record */ if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) - return; // no record retrieved + return platform_err; // no record retrieved - /* Log the error record */ - ia64_log_print(sal_info_type, (prfunc_t)printk); + /* TODO: + * 1. analyze error logs to determine recoverability + * 2. perform error recovery procedures, if applicable + * 3. set ia64_os_mca_recovery_successful flag, if applicable + */ - /* Clear the CMC SAL logs now that they have been logged */ + platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk); ia64_sal_clear_state_info(sal_info_type); + + return platform_err; } /* - * hack for now, add platform dependent handlers - * here + * platform dependent error handling */ #ifndef PLATFORM_MCA_HANDLERS void @@ -275,8 +294,8 @@ cmcv_reg_t cmcv; cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ - cmcv.cmcv_vector = IA64_CMC_VECTOR; + cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ + cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " @@ -374,6 +393,9 @@ IA64_MCA_DEBUG("ia64_mca_init: begin\n"); + /* initialize recovery success indicator */ + ia64_os_mca_recovery_successful = 0; + /* Clear the Rendez checkin flag for all cpus */ for(i = 0 ; i < NR_CPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; @@ -459,7 +481,7 @@ /* * Configure the CMCI vector and handler. Interrupts for CMC are - * per-processor, so AP CMC interrupts are setup in smp_callin() (smp.c). + * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). */ register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ @@ -498,6 +520,9 @@ ia64_log_init(SAL_INFO_TYPE_CMC); ia64_log_init(SAL_INFO_TYPE_CPE); + /* Zero the min state save info */ + ia64_mca_min_state_save_info = 0; + #if defined(MCA_TEST) mca_test(); #endif /* #if defined(MCA_TEST) */ @@ -576,7 +601,7 @@ int cpu; /* Clear the Rendez checkin flag for all cpus */ - for(cpu = 0 ; cpu < smp_num_cpus; cpu++) + for(cpu = 0; cpu < smp_num_cpus; cpu++) if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) ia64_mca_wakeup(cpu); @@ -668,6 +693,13 @@ /* Cold Boot for uncorrectable MCA */ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; + + /* Default = tell SAL to return to same context */ + ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; + + /* Register pointer to new min state values */ + /* NOTE: need to do something with this during recovery phase */ + ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info; } /* @@ -678,10 +710,10 @@ * 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 + * 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 rendezvous spinloop. + * slave processors out of rendezvous spinloop. * * Inputs : None * Outputs : None @@ -689,20 +721,16 @@ void ia64_mca_ucmc_handler(void) { -#if 0 /* stubbed out @FVL */ - /* - * Attempting to log a DBE error Causes "reserved register/field panic" - * in printk. - */ + int platform_err = 0; /* Get the MCA error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); -#endif /* stubbed out @FVL */ + platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); /* * Do Platform-specific mca error handling if required. */ - mca_handler_platform() ; + if (platform_err) + mca_handler_platform(); /* * Wakeup all the processors which are spinning in the rendezvous @@ -749,13 +777,16 @@ { spinlock_t isl_lock; int isl_index; - ia64_err_rec_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ + ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ } ia64_state_log_t; static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; -/* Note: Some of these macros assume IA64_MAX_LOGS is always 2. Should be */ -/* fixed. @FVL */ +#define IA64_LOG_ALLOCATE(it, size) \ + {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size); \ + ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size);} #define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) #define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) #define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) @@ -765,13 +796,13 @@ ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index #define IA64_LOG_INDEX_DEC(it) \ ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index -#define IA64_LOG_NEXT_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) -#define IA64_LOG_CURR_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) +#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) +#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) /* * C portion of the OS INIT handler * - * Called from ia64__init_handler + * Called from ia64_monarch_init_handler * * Inputs: pointer to pt_regs where processor info was saved. * @@ -885,10 +916,18 @@ void ia64_log_init(int sal_info_type) { - IA64_LOG_LOCK_INIT(sal_info_type); + u64 max_size = 0; + IA64_LOG_NEXT_INDEX(sal_info_type) = 0; - memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, - sizeof(ia64_err_rec_t) * IA64_MAX_LOGS); + IA64_LOG_LOCK_INIT(sal_info_type); + + // SAL will tell us the maximum size of any error record of this type + max_size = ia64_sal_get_state_info_size(sal_info_type); + + // set up OS data structures to hold error info + IA64_LOG_ALLOCATE(sal_info_type, max_size); + memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); + memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); } /* @@ -923,8 +962,7 @@ return total_len; } else { IA64_LOG_UNLOCK(sal_info_type); - prfunc("ia64_log_get: Failed to retrieve SAL error record type %d\n", - sal_info_type); + prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type); return 0; } } @@ -1268,7 +1306,7 @@ } if (mdei->valid.oem_data) { - ia64_log_prt_oem_data((int)mdei->header.len, + platform_mem_dev_err_print((int)mdei->header.len, (int)sizeof(sal_log_mem_dev_err_info_t) - 1, &(mdei->oem_data[0]), prfunc); } @@ -1357,7 +1395,7 @@ prfunc("\n"); if (pbei->valid.oem_data) { - ia64_log_prt_oem_data((int)pbei->header.len, + platform_pci_bus_err_print((int)pbei->header.len, (int)sizeof(sal_log_pci_bus_err_info_t) - 1, &(pbei->oem_data[0]), prfunc); } @@ -1456,7 +1494,7 @@ } } if (pcei->valid.oem_data) { - ia64_log_prt_oem_data((int)pcei->header.len, n_pci_data, + platform_pci_comp_err_print((int)pcei->header.len, n_pci_data, p_oem_data, prfunc); prfunc("\n"); } @@ -1485,7 +1523,7 @@ ia64_log_prt_guid(&psei->guid, prfunc); } if (psei->valid.oem_data) { - ia64_log_prt_oem_data((int)psei->header.len, + platform_plat_specific_err_print((int)psei->header.len, (int)sizeof(sal_log_plat_specific_err_info_t) - 1, &(psei->oem_data[0]), prfunc); } @@ -1519,7 +1557,7 @@ if (hcei->valid.bus_spec_data) prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data); if (hcei->valid.oem_data) { - ia64_log_prt_oem_data((int)hcei->header.len, + platform_host_ctlr_err_print((int)hcei->header.len, (int)sizeof(sal_log_host_ctlr_err_info_t) - 1, &(hcei->oem_data[0]), prfunc); } @@ -1553,7 +1591,7 @@ if (pbei->valid.bus_spec_data) prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data); if (pbei->valid.oem_data) { - ia64_log_prt_oem_data((int)pbei->header.len, + platform_plat_bus_err_print((int)pbei->header.len, (int)sizeof(sal_log_plat_bus_err_info_t) - 1, &(pbei->oem_data[0]), prfunc); } @@ -1745,17 +1783,18 @@ * Inputs : lh (Pointer to the sal error record header with format * specified by the SAL spec). * prfunc (fn ptr of log output function to use) - * Outputs : None + * Outputs : platform error status */ -void +int ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) { - sal_log_section_hdr_t *slsh; - int n_sects; - int ercd_pos; + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; + int platform_err = 0; if (!lh) - return; + return platform_err; #ifdef MCA_PRT_XTRA_DATA // for test only @FVL ia64_log_prt_record_header(lh, prfunc); @@ -1765,7 +1804,7 @@ IA64_MCA_DEBUG("ia64_mca_log_print: " "truncated SAL error record. len = %d\n", lh->len); - return; + return platform_err; } /* Print record header info */ @@ -1796,35 +1835,43 @@ ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform Memory Device Error Info Section\n"); ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform SEL Device Error Info Section\n"); ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform PCI Bus Error Info Section\n"); ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform SMBIOS Device Error Info Section\n"); ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform PCI Component Error Info Section\n"); ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform Specific Error Info Section\n"); ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *) slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform Host Controller Error Info Section\n"); ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh, prfunc); } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) { + platform_err = 1; prfunc("+Platform Bus Error Info Section\n"); ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh, prfunc); @@ -1838,8 +1885,9 @@ n_sects, lh->len); if (!n_sects) { prfunc("No Platform Error Info Sections found\n"); - return; + return platform_err; } + return platform_err; } /* @@ -1849,15 +1897,17 @@ * * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) * prfunc (fn ptr of log output function to use) - * Outputs : None + * Outputs : platform error status */ -void +int ia64_log_print(int sal_info_type, prfunc_t prfunc) { + int platform_err = 0; + switch(sal_info_type) { case SAL_INFO_TYPE_MCA: prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n"); - ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); prfunc("+END HARDWARE ERROR STATE AT MCA\n"); break; case SAL_INFO_TYPE_INIT: @@ -1877,4 +1927,5 @@ prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n"); break; } + return platform_err; } diff -urN linux-2.4.18/arch/ia64/kernel/mca_asm.S linux-2.4.19-pre5/arch/ia64/kernel/mca_asm.S --- linux-2.4.18/arch/ia64/kernel/mca_asm.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/mca_asm.S Sat Mar 30 22:55:25 2002 @@ -7,6 +7,12 @@ // 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp // kstack, switch modes, jump to C INIT handler // +// 02/01/04 J.Hall +// Before entering virtual mode code: +// 1. Check for TLB CPU error +// 2. Restore current thread pointer to kr6 +// 3. Move stack ptr 16 bytes to conform to C calling convention +// #include #include @@ -21,10 +27,21 @@ */ #define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ +/* + * Needed for ia64_sal call + */ +#define SAL_GET_STATE_INFO 0x01000001 + +/* + * Needed for return context to SAL + */ +#define IA64_MCA_SAME_CONTEXT 0x0 +#define IA64_MCA_COLD_BOOT -2 + #include "minstate.h" /* - * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec) + * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec) * 1. GR1 = OS GP * 2. GR8 = PAL_PROC physical address * 3. GR9 = SAL_PROC physical address @@ -40,26 +57,34 @@ st8 [_tmp]=r9,0x08;; \ st8 [_tmp]=r10,0x08;; \ st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08;; + st8 [_tmp]=r12,0x08 /* - * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) - * 1. GR8 = OS_MCA return status + * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) + * (p6) is executed if we never entered virtual mode (TLB error) + * (p7) is executed if we entered virtual mode as expected (normal case) + * 1. GR8 = OS_MCA return status * 2. GR9 = SAL GP (physical) - * 3. GR10 = 0/1 returning same/new context - * 4. GR22 = New min state save area pointer - * returns ptr to SAL rtn save loc in _tmp + * 3. GR10 = 0/1 returning same/new context + * 4. GR22 = New min state save area pointer + * returns ptr to SAL rtn save loc in _tmp */ -#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 r10=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ - add _tmp=0x28,_tmp;; // point to SAL rtn save location +#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ +(p6) movl _tmp=ia64_sal_to_os_handoff_state;; \ +(p7) movl _tmp=ia64_os_to_sal_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ +(p6) movl r8=IA64_MCA_COLD_BOOT; \ +(p6) movl r10=IA64_MCA_SAME_CONTEXT; \ +(p6) add _tmp=0x18,_tmp;; \ +(p6) ld8 r9=[_tmp],0x10; \ +(p6) movl r22=ia64_mca_min_state_save_info;; \ +(p7) ld8 r8=[_tmp],0x08;; \ +(p7) ld8 r9=[_tmp],0x08;; \ +(p7) ld8 r10=[_tmp],0x08;; \ +(p7) ld8 r22=[_tmp],0x08;; \ + DATA_VA_TO_PA(r22) + // now _tmp is pointing to SAL rtn save location + .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end @@ -70,6 +95,9 @@ .global ia64_mca_stackframe .global ia64_mca_bspstore .global ia64_init_stack + .global ia64_mca_sal_data_area + .global ia64_tlb_functional + .global ia64_mca_min_state_save_info .text .align 16 @@ -90,26 +118,34 @@ // 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: br ia64_os_mca_proc_state_dump;; 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 r2=ia64_mca_bspstore;; // local bspstore area location in r2 DATA_VA_TO_PA(r2);; - movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 + movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 DATA_VA_TO_PA(r3);; - rse_switch_context(r6,r3,r2);; // RSC management in this new context - movl r12=ia64_mca_stack;; - mov r2=8*1024;; // stack size must be same as c array - add r12=r2,r12;; // stack base @ bottom of array + rse_switch_context(r6,r3,r2);; // RSC management in this new context + movl r12=ia64_mca_stack + mov r2=8*1024;; // stack size must be same as C array + add r12=r2,r12;; // stack base @ bottom of array + adds r12=-16,r12;; // allow 16 bytes of scratch + // (C calling convention) DATA_VA_TO_PA(r12);; - // Enter virtual mode from physical mode + // Check to see if the MCA resulted from a TLB error +begin_tlb_error_check: + br ia64_os_mca_tlb_error_check;; + +done_tlb_error_check: + + // If TLB is functional, enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) ia64_os_mca_virtual_begin: @@ -130,25 +166,28 @@ #endif /* #if defined(MCA_TEST) */ // restore the original stack frame here - movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 + 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 + 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 + mov r8=gp ;; begin_os_mca_restore: br ia64_os_mca_proc_state_restore;; ia64_os_mca_done_restore: - ;; + movl r3=ia64_tlb_functional;; + DATA_VA_TO_PA(r3);; + ld8 r3=[r3];; + cmp.eq p6,p7=r0,r3;; + OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);; // branch back to SALE_CHECK - OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) ld8 r3=[r2];; - mov b0=r3;; // SAL_CHECK return address + mov b0=r3;; // SAL_CHECK return address br b0 ;; ia64_os_mca_dispatch_end: @@ -405,7 +444,7 @@ 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 @@ -621,6 +660,80 @@ //EndStub////////////////////////////////////////////////////////////////////// +//++ +// Name: +// ia64_os_mca_tlb_error_check() +// +// Stub Description: +// +// This stub checks to see if the MCA resulted from a TLB error +// +//-- + +ia64_os_mca_tlb_error_check: + + // Retrieve sal data structure for uncorrected MCA + + // Make the ia64_sal_get_state_info() call + movl r4=ia64_mca_sal_data_area;; + movl r7=ia64_sal;; + mov r6=r1 // save gp + DATA_VA_TO_PA(r4) // convert to physical address + DATA_VA_TO_PA(r7);; // convert to physical address + ld8 r7=[r7] // get addr of pdesc from ia64_sal + movl r3=SAL_GET_STATE_INFO;; + DATA_VA_TO_PA(r7);; // convert to physical address + ld8 r8=[r7],8;; // get pdesc function pointer + DATA_VA_TO_PA(r8) // convert to physical address + ld8 r1=[r7];; // set new (ia64_sal) gp + DATA_VA_TO_PA(r1) // convert to physical address + mov b6=r8 + + alloc r5=ar.pfs,8,0,8,0;; // allocate stack frame for SAL call + mov out0=r3 // which SAL proc to call + mov out1=r0 // error type == MCA + mov out2=r0 // null arg + mov out3=r4 // data copy area + mov out4=r0 // null arg + mov out5=r0 // null arg + mov out6=r0 // null arg + mov out7=r0;; // null arg + + br.call.sptk.few b0=b6;; + + mov r1=r6 // restore gp + mov ar.pfs=r5;; // restore ar.pfs + + movl r6=ia64_tlb_functional;; + DATA_VA_TO_PA(r6) // needed later + + cmp.eq p6,p7=r0,r8;; // check SAL call return address +(p7) st8 [r6]=r0 // clear tlb_functional flag +(p7) br tlb_failure // error; return to SAL + + // examine processor error log for type of error + add r4=40+24,r4;; // parse past record header (length=40) + // and section header (length=24) + ld4 r4=[r4] // get valid field of processor log + mov r5=0xf00;; + and r5=r4,r5;; // read bits 8-11 of valid field + // to determine if we have a TLB error + movl r3=0x1 + cmp.eq p6,p7=r0,r5;; + // if no TLB failure, set tlb_functional flag +(p6) st8 [r6]=r3 + // else clear flag +(p7) st8 [r6]=r0 + + // if no TLB failure, continue with normal virtual mode logging +(p6) br done_tlb_error_check + // else no point in entering virtual mode for logging +tlb_failure: + br ia64_os_mca_virtual_end + +//EndStub////////////////////////////////////////////////////////////////////// + + // ok, the issue here is that we need to save state information so // it can be useable by the kernel debugger and show regs routines. // In order to do this, our best bet is save the current state (plus @@ -633,7 +746,7 @@ // This has been defined for registration purposes with SAL // as a part of ia64_mca_init. // -// When we get here, the follow registers have been +// When we get here, the following registers have been // set by the SAL for our use // // 1. GR1 = OS INIT GP @@ -649,42 +762,10 @@ GLOBAL_ENTRY(ia64_monarch_init_handler) -#if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) - // - // work around SAL bug that sends all processors to monarch entry - // - mov r17=cr.lid - // XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid - movl r18=ia64_cpu_to_sapicid - ;; - dep r18=0,r18,61,3 // convert to physical address - ;; - shr.u r17=r17,16 - ld4 r18=[r18] // get the BSP ID - ;; - dep r17=0,r17,16,48 - ;; - cmp4.ne p6,p0=r17,r18 // Am I the BSP ? -(p6) br.cond.spnt slave_init_spin_me - ;; -#endif - -// -// ok, the first thing we do is stash the information -// the SAL passed to os -// -_tmp = r2 - movl _tmp=ia64_sal_to_os_handoff_state - ;; - dep _tmp=0,_tmp, 61, 3 // get physical address + // stash the information the SAL passed to os + SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) ;; - st8 [_tmp]=r1,0x08;; - st8 [_tmp]=r8,0x08;; - st8 [_tmp]=r9,0x08;; - st8 [_tmp]=r10,0x08;; - st8 [_tmp]=r11,0x08;; - st8 [_tmp]=r12,0x08;; // now we want to save information so we can dump registers SAVE_MIN_WITH_COVER @@ -695,12 +776,10 @@ ;; SAVE_REST -// ok, enough should be saved at this point to be dangerous, and supply +// ok, enough should be saved at this point to be dangerous, and supply // information for a dump // We need to switch to Virtual mode before hitting the C functions. -// -// -// + movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN mov r3=psr // get the current psr, minimum enabled at this point ;; @@ -708,8 +787,8 @@ ;; movl r3=IVirtual_Switch ;; - mov cr.iip=r3 // short return to set the appropriate bits - mov cr.ipsr=r2 // need to do an rfi to set appropriate bits + mov cr.iip=r3 // short return to set the appropriate bits + mov cr.ipsr=r2 // need to do an rfi to set appropriate bits ;; rfi ;; @@ -717,7 +796,7 @@ // // We should now be running virtual // - // Lets call the C handler to get the rest of the state info + // Let's call the C handler to get the rest of the state info // alloc r14=ar.pfs,0,0,1,0 // now it's safe (must be first in insn group!) ;; // diff -urN linux-2.4.18/arch/ia64/kernel/palinfo.c linux-2.4.19-pre5/arch/ia64/kernel/palinfo.c --- linux-2.4.18/arch/ia64/kernel/palinfo.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/palinfo.c Sat Mar 30 22:55:25 2002 @@ -724,7 +724,7 @@ status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); if (status != 0) { - printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status); + printk("palinfo: pal call failed on tr[%d:%d]=%ld\n", i, j, status); continue; } @@ -842,9 +842,8 @@ palinfo_smp_call(void *info) { palinfo_smp_data_t *data = (palinfo_smp_data_t *)info; - /* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/ if (data == NULL) { - printk(KERN_ERR __FUNCTION__" data pointer is NULL\n"); + printk("%s palinfo: data pointer is NULL\n", KERN_ERR); data->ret = 0; /* no output */ return; } @@ -868,11 +867,10 @@ ptr.page = page; ptr.ret = 0; /* just in case */ - /*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/ /* will send IPI to other CPU and wait for completion of remote call */ if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) { - printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); + printk("palinfo: remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); return 0; } return ptr.ret; @@ -881,7 +879,7 @@ static int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) { - printk(__FUNCTION__" should not be called with non SMP kernel\n"); + printk("palinfo: should not be called with non SMP kernel\n"); return 0; } #endif /* CONFIG_SMP */ diff -urN linux-2.4.18/arch/ia64/kernel/perfmon.c linux-2.4.19-pre5/arch/ia64/kernel/perfmon.c --- linux-2.4.18/arch/ia64/kernel/perfmon.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/perfmon.c Sat Mar 30 22:55:25 2002 @@ -1,13 +1,16 @@ /* - * This file contains the code to configure and read/write the ia64 performance - * monitoring stuff. + * This file implements the perfmon subsystem which is used + * to program the IA-64 Performance Monitoring Unit (PMU). * * Originaly Written by Ganesh Venkitachalam, IBM Corp. - * Modifications by David Mosberger-Tang, Hewlett-Packard Co. - * Modifications by Stephane Eranian, Hewlett-Packard Co. * Copyright (C) 1999 Ganesh Venkitachalam - * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 2000-2001 Stephane Eranian + * + * Modifications by Stephane Eranian, Hewlett-Packard Co. + * Modifications by David Mosberger-Tang, Hewlett-Packard Co. + * + * Copyright (C) 1999-2002 Hewlett Packard Co + * Stephane Eranian + * David Mosberger-Tang */ #include @@ -22,151 +25,137 @@ #include #include -#include #include -#include #include #include #include -#include #include #include #include -#include #include #include /* for ia64_get_itc() */ #ifdef CONFIG_PERFMON -#define PFM_VERSION "0.3" -#define PFM_SMPL_HDR_VERSION 1 - -#define PMU_FIRST_COUNTER 4 /* first generic counter */ - -#define PFM_WRITE_PMCS 0xa0 -#define PFM_WRITE_PMDS 0xa1 -#define PFM_READ_PMDS 0xa2 -#define PFM_STOP 0xa3 -#define PFM_START 0xa4 -#define PFM_ENABLE 0xa5 /* unfreeze only */ -#define PFM_DISABLE 0xa6 /* freeze only */ -#define PFM_RESTART 0xcf -#define PFM_CREATE_CONTEXT 0xa7 -#define PFM_DESTROY_CONTEXT 0xa8 /* - * Those 2 are just meant for debugging. I considered using sysctl() for - * that but it is a little bit too pervasive. This solution is at least - * self-contained. + * For PMUs which rely on the debug registers for some features, you must + * you must enable the following flag to activate the support for + * accessing the registers via the perfmonctl() interface. */ -#define PFM_DEBUG_ON 0xe0 -#define PFM_DEBUG_OFF 0xe1 - -#define PFM_DEBUG_BASE PFM_DEBUG_ON - +#ifdef CONFIG_ITANIUM +#define PFM_PMU_USES_DBR 1 +#endif /* - * perfmon API flags + * perfmon context states */ -#define PFM_FL_INHERIT_NONE 0x00 /* never inherit a context across fork (default) */ -#define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ -#define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ -#define PFM_FL_SMPL_OVFL_NOBLOCK 0x04 /* do not block on sampling buffer overflow */ -#define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ -#define PFM_FL_EXCL_INTR 0x10 /* exclude interrupt from system wide monitoring */ +#define PFM_CTX_DISABLED 0 +#define PFM_CTX_ENABLED 1 /* - * PMC API flags + * Reset register flags */ -#define PFM_REGFL_OVFL_NOTIFY 1 /* send notification on overflow */ +#define PFM_RELOAD_LONG_RESET 1 +#define PFM_RELOAD_SHORT_RESET 2 /* - * Private flags and masks + * Misc macros and definitions */ +#define PMU_FIRST_COUNTER 4 + +#define PFM_IS_DISABLED() pmu_conf.pfm_is_disabled + +#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_soft_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) #define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) -#ifdef CONFIG_SMP -#define cpu_is_online(i) (cpu_online_map & (1UL << i)) -#else -#define cpu_is_online(i) 1 -#endif +#define PMC_IS_IMPL(i) (i>6] & (1UL<< (i) %64)) +#define PMD_IS_IMPL(i) (i>6)] & (1UL<<(i) % 64)) + +#define PMD_IS_COUNTING(i) (i >=0 && i < 256 && pmu_conf.counter_pmds[i>>6] & (1UL <<(i) % 64)) +#define PMC_IS_COUNTING(i) PMD_IS_COUNTING(i) + +#define IBR_IS_IMPL(k) (kpmc_es == PMU_BTB_EVENT) + +#define LSHIFT(x) (1UL<<(x)) +#define PMM(x) LSHIFT(x) +#define PMC_IS_MONITOR(c) ((pmu_conf.monitor_pmcs[0] & PMM((c))) != 0) + +#define CTX_IS_ENABLED(c) ((c)->ctx_flags.state == PFM_CTX_ENABLED) +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) +#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) +#define CTX_HAS_SMPL(c) ((c)->ctx_psb != NULL) +#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1UL<< ((n) % 64) + +#define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) + +#define LOCK_CTX(ctx) spin_lock(&(ctx)->ctx_lock) +#define UNLOCK_CTX(ctx) spin_unlock(&(ctx)->ctx_lock) + +#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0) +#define PMU_OWNER() pmu_owners[smp_processor_id()].owner + +#define LOCK_PFS() spin_lock(&pfm_sessions.pfs_lock) +#define UNLOCK_PFS() spin_unlock(&pfm_sessions.pfs_lock) + +#define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) + +/* + * debugging + */ +#define DBprintk(a) \ + do { \ + if (pfm_debug_mode >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) -#define PMC_IS_IMPL(i) (i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) -#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) -#define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) -#define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) -/* This is the Itanium-specific PMC layout for counter config */ +/* + * These are some helpful architected PMC and IBR/DBR register layouts + */ typedef struct { unsigned long pmc_plm:4; /* privilege level mask */ unsigned long pmc_ev:1; /* external visibility */ unsigned long pmc_oi:1; /* overflow interrupt */ unsigned long pmc_pm:1; /* privileged monitor */ unsigned long pmc_ig1:1; /* reserved */ - unsigned long pmc_es:7; /* event select */ - unsigned long pmc_ig2:1; /* reserved */ - unsigned long pmc_umask:4; /* unit mask */ - unsigned long pmc_thres:3; /* threshold */ - unsigned long pmc_ig3:1; /* reserved (missing from table on p6-17) */ - unsigned long pmc_ism:2; /* instruction set mask */ - unsigned long pmc_ig4:38; /* reserved */ -} pmc_counter_reg_t; - -/* test for EAR/BTB configuration */ -#define PMU_DEAR_EVENT 0x67 -#define PMU_IEAR_EVENT 0x23 -#define PMU_BTB_EVENT 0x11 - -#define PMC_IS_DEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_DEAR_EVENT) -#define PMC_IS_IEAR(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_IEAR_EVENT) -#define PMC_IS_BTB(a) (((pmc_counter_reg_t *)(a))->pmc_es == PMU_BTB_EVENT) - -/* - * This header is at the beginning of the sampling buffer returned to the user. - * It is exported as Read-Only at this point. It is directly followed with the - * first record. - */ -typedef struct { - int hdr_version; /* could be used to differentiate formats */ - int hdr_reserved; - unsigned long hdr_entry_size; /* size of one entry in bytes */ - unsigned long hdr_count; /* how many valid entries */ - unsigned long hdr_pmds; /* which pmds are recorded */ -} perfmon_smpl_hdr_t; - -/* - * Header entry in the buffer as a header as follows. - * The header is directly followed with the PMDS to saved in increasing index order: - * PMD4, PMD5, .... How many PMDs are present is determined by the tool which must - * keep track of it when generating the final trace file. - */ -typedef struct { - int pid; /* identification of process */ - int cpu; /* which cpu was used */ - unsigned long rate; /* initial value of this counter */ - unsigned long stamp; /* timestamp */ - unsigned long ip; /* where did the overflow interrupt happened */ - unsigned long regs; /* which registers overflowed (up to 64)*/ -} perfmon_smpl_entry_t; + unsigned long pmc_es:8; /* event select */ + unsigned long pmc_ig2:48; /* reserved */ +} pfm_monitor_t; /* * There is one such data structure per perfmon context. It is used to describe the - * sampling buffer. It is to be shared among siblings whereas the pfm_context isn't. + * sampling buffer. It is to be shared among siblings whereas the pfm_context + * is not. * Therefore we maintain a refcnt which is incremented on fork(). - * This buffer is private to the kernel only the actual sampling buffer including its - * header are exposed to the user. This construct allows us to export the buffer read-write, - * if needed, without worrying about security problems. - */ -typedef struct { - atomic_t psb_refcnt; /* how many users for the buffer */ - int reserved; + * This buffer is private to the kernel only the actual sampling buffer + * including its header are exposed to the user. This construct allows us to + * export the buffer read-write, if needed, without worrying about security + * problems. + */ +typedef struct _pfm_smpl_buffer_desc { + spinlock_t psb_lock; /* protection lock */ + unsigned long psb_refcnt; /* how many users for the buffer */ + int psb_flags; /* bitvector of flags */ + void *psb_addr; /* points to location of first entry */ unsigned long psb_entries; /* maximum number of entries */ unsigned long psb_size; /* aligned size of buffer */ - unsigned long psb_index; /* next free entry slot */ + unsigned long psb_index; /* next free entry slot XXX: must use the one in buffer */ unsigned long psb_entry_size; /* size of each entry including entry header */ perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ + + struct _pfm_smpl_buffer_desc *psb_next; /* next psb, used for rvfreeing of psb_hdr */ + } pfm_smpl_buffer_desc_t; +#define LOCK_PSB(p) spin_lock(&(p)->psb_lock) +#define UNLOCK_PSB(p) spin_unlock(&(p)->psb_lock) + +#define PFM_PSB_VMA 0x1 /* a VMA is describing the buffer */ /* * This structure is initialized at boot time and contains @@ -180,126 +169,192 @@ unsigned long num_pmcs ; /* highest PMC implemented (may have holes) */ unsigned long num_pmds; /* highest PMD implemented (may have holes) */ unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ + unsigned long num_ibrs; /* number of instruction debug registers */ + unsigned long num_dbrs; /* number of data debug registers */ + unsigned long monitor_pmcs[4]; /* which pmc are controlling monitors */ + unsigned long counter_pmds[4]; /* which pmd are used as counters */ } pmu_config_t; -#define PERFMON_IS_DISABLED() pmu_conf.pfm_is_disabled - +/* + * 64-bit software counter structure + */ typedef struct { - __u64 val; /* virtual 64bit counter value */ - __u64 ival; /* initial value from user */ - __u64 smpl_rval; /* reset value on sampling overflow */ - __u64 ovfl_rval; /* reset value on overflow */ - int flags; /* notify/do not notify */ + u64 val; /* virtual 64bit counter value */ + u64 ival; /* initial value from user */ + u64 long_reset; /* reset value on sampling overflow */ + u64 short_reset;/* reset value on overflow */ + u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */ + int flags; /* notify/do not notify */ } pfm_counter_t; -#define PMD_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) /* - * perfmon context. One per process, is cloned on fork() depending on inheritance flags + * perfmon context. One per process, is cloned on fork() depending on + * inheritance flags */ typedef struct { - unsigned int inherit:2; /* inherit mode */ - unsigned int noblock:1; /* block/don't block on overflow with notification */ - unsigned int system:1; /* do system wide monitoring */ - unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ - unsigned int exclintr:1;/* exlcude interrupts from system wide monitoring */ - unsigned int reserved:26; + unsigned int state:1; /* 0=disabled, 1=enabled */ + unsigned int inherit:2; /* inherit mode */ + unsigned int block:1; /* when 1, task will blocked on user notifications */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ + unsigned int protected:1; /* allow access to creator of context only */ + unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ + unsigned int reserved:24; } pfm_context_flags_t; +/* + * perfmon context: encapsulates all the state of a monitoring session + * XXX: probably need to change layout + */ typedef struct pfm_context { + pfm_smpl_buffer_desc_t *ctx_psb; /* sampling buffer, if any */ + unsigned long ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ - pfm_smpl_buffer_desc_t *ctx_smpl_buf; /* sampling buffer descriptor, if any */ - unsigned long ctx_dear_counter; /* which PMD holds D-EAR */ - unsigned long ctx_iear_counter; /* which PMD holds I-EAR */ - unsigned long ctx_btb_counter; /* which PMD holds BTB */ - - spinlock_t ctx_notify_lock; + spinlock_t ctx_lock; pfm_context_flags_t ctx_flags; /* block/noblock */ - int ctx_notify_sig; /* XXX: SIGPROF or other */ + struct task_struct *ctx_notify_task; /* who to notify on overflow */ - struct task_struct *ctx_creator; /* pid of creator (debug) */ + struct task_struct *ctx_owner; /* pid of creator (debug) */ + + unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ + unsigned long ctx_smpl_regs[4]; /* which registers to record on overflow */ - unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ - unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ - struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + unsigned long ctx_used_pmds[4]; /* bitmask of used PMD (speedup ctxsw) */ + unsigned long ctx_saved_pmcs[4]; /* bitmask of PMC to save on ctxsw */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of PMC to reload on ctxsw (SMP) */ - unsigned long ctx_used_pmds[4]; /* bitmask of used PMD (speedup ctxsw) */ - unsigned long ctx_used_pmcs[4]; /* bitmask of used PMC (speedup ctxsw) */ + unsigned long ctx_used_ibrs[4]; /* bitmask of used IBR (speedup ctxsw) */ + unsigned long ctx_used_dbrs[4]; /* bitmask of used DBR (speedup ctxsw) */ - pfm_counter_t ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */ + pfm_counter_t ctx_soft_pmds[IA64_NUM_PMD_REGS]; /* XXX: size should be dynamic */ + u64 ctx_saved_psr; /* copy of psr used for lazy ctxsw */ + unsigned long ctx_saved_cpus_allowed; /* copy of the task cpus_allowed (system wide) */ + unsigned long ctx_cpu; /* cpu to which perfmon is applied (system wide) */ + + atomic_t ctx_saving_in_progress; /* flag indicating actual save in progress */ + atomic_t ctx_last_cpu; /* CPU id of current or last CPU used */ } pfm_context_t; -#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1<< ((n) % 64) -#define CTX_USED_PMC(ctx,n) (ctx)->ctx_used_pmcs[(n)>>6] |= 1<< ((n) % 64) +#define ctx_fl_inherit ctx_flags.inherit +#define ctx_fl_block ctx_flags.block +#define ctx_fl_system ctx_flags.system +#define ctx_fl_frozen ctx_flags.frozen +#define ctx_fl_protected ctx_flags.protected +#define ctx_fl_using_dbreg ctx_flags.using_dbreg + +/* + * global information about all sessions + * mostly used to synchronize between system wide and per-process + */ +typedef struct { + spinlock_t pfs_lock; /* lock the structure */ -#define ctx_fl_inherit ctx_flags.inherit -#define ctx_fl_noblock ctx_flags.noblock -#define ctx_fl_system ctx_flags.system -#define ctx_fl_frozen ctx_flags.frozen -#define ctx_fl_exclintr ctx_flags.exclintr + unsigned long pfs_task_sessions; /* number of per task sessions */ + unsigned long pfs_sys_sessions; /* number of per system wide sessions */ + unsigned long pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ + unsigned long pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ + struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ +} pfm_session_t; -#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_noblock == 1) -#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) -#define CTX_HAS_SMPL(c) ((c)->ctx_smpl_buf != NULL) +/* + * structure used to pass argument to/from remote CPU + * using IPI to check and possibly save the PMU context on SMP systems. + * + * not used in UP kernels + */ +typedef struct { + struct task_struct *task; /* which task we are interested in */ + int retval; /* return value of the call: 0=you can proceed, 1=need to wait for completion */ +} pfm_smp_ipi_arg_t; -static pmu_config_t pmu_conf; +/* + * perfmon command descriptions + */ +typedef struct { + int (*cmd_func)(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + int cmd_flags; + unsigned int cmd_narg; + size_t cmd_argsize; +} pfm_cmd_desc_t; -/* for debug only */ -static int pfm_debug=0; /* 0= nodebug, >0= debug output on */ +#define PFM_CMD_PID 0x1 /* command requires pid argument */ +#define PFM_CMD_ARG_READ 0x2 /* command must read argument(s) */ +#define PFM_CMD_ARG_WRITE 0x4 /* command must write argument(s) */ +#define PFM_CMD_CTX 0x8 /* command needs a perfmon context */ +#define PFM_CMD_NOCHK 0x10 /* command does not need to check task's state */ -#define DBprintk(a) \ - do { \ - if (pfm_debug >0) { printk(__FUNCTION__" %d: ", __LINE__); printk a; } \ - } while (0); +#define PFM_CMD_IDX(cmd) (cmd) + +#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \ + && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) + +#define PFM_CMD_USE_PID(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0) +#define PFM_CMD_READ_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0) +#define PFM_CMD_WRITE_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_WRITE) != 0) +#define PFM_CMD_USE_CTX(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0) +#define PFM_CMD_CHK(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0) + +#define PFM_CMD_ARG_MANY -1 /* cannot be zero */ +#define PFM_CMD_NARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg) +#define PFM_CMD_ARG_SIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize) -static void ia64_reset_pmu(void); /* - * structure used to pass information between the interrupt handler - * and the tasklet. + * perfmon internal variables */ -typedef struct { - pid_t to_pid; /* which process to notify */ - pid_t from_pid; /* which process is source of overflow */ - int sig; /* with which signal */ - unsigned long bitvect; /* which counters have overflowed */ -} notification_info_t; +static pmu_config_t pmu_conf; /* PMU configuration */ +static int pfm_debug_mode; /* 0= nodebug, >0= debug output on */ +static pfm_session_t pfm_sessions; /* global sessions information */ +static struct proc_dir_entry *perfmon_dir; /* for debug only */ +static unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ +static unsigned long pfm_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ +static unsigned long pfm_recorded_samples_count; -typedef struct { - unsigned long pfs_proc_sessions; - unsigned long pfs_sys_session; /* can only be 0/1 */ - unsigned long pfs_dfl_dcr; /* XXX: hack */ - unsigned int pfs_pp; -} pfm_session_t; +static unsigned long reset_pmcs[IA64_NUM_PMC_REGS]; /* contains PAL reset values for PMCS */ + +static void pfm_vm_close(struct vm_area_struct * area); +static struct vm_operations_struct pfm_vm_ops={ + close: pfm_vm_close +}; -struct { +/* + * keep track of task owning the PMU per CPU. + */ +static struct { struct task_struct *owner; } ____cacheline_aligned pmu_owners[NR_CPUS]; -/* - * helper macros - */ -#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); -#define PMU_OWNER() pmu_owners[smp_processor_id()].owner +/* + * forward declarations + */ +static void ia64_reset_pmu(struct task_struct *); #ifdef CONFIG_SMP -#define PFM_CAN_DO_LAZY() (smp_num_cpus==1 && pfs_info.pfs_sys_session==0) -#else -#define PFM_CAN_DO_LAZY() (pfs_info.pfs_sys_session==0) +static void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx); #endif - static void pfm_lazy_save_regs (struct task_struct *ta); -/* for debug only */ -static struct proc_dir_entry *perfmon_dir; +static inline unsigned long +pfm_read_soft_counter(pfm_context_t *ctx, int i) +{ + return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.perf_ovfl_val); +} -/* - * XXX: hack to indicate that a system wide monitoring session is active - */ -static pfm_session_t pfs_info; +static inline void +pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) +{ + ctx->ctx_soft_pmds[i].val = val & ~pmu_conf.perf_ovfl_val; + /* + * writing to unimplemented part is ignore, so we do not need to + * mask off top part + */ + ia64_set_pmd(i, val); +} /* * finds the number of PM(C|D) registers given @@ -324,10 +379,10 @@ * Generates a unique (per CPU) timestamp */ static inline unsigned long -perfmon_get_stamp(void) +pfm_get_stamp(void) { /* - * XXX: maybe find something more efficient + * XXX: must find something more efficient */ return ia64_get_itc(); } @@ -353,80 +408,185 @@ } } } - DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret)); + DBprintk(("[%d] uv2kva(%lx-->%lx)\n", current->pid, adr, ret)); return ret; } - /* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */ static inline unsigned long -kvirt_to_pa(unsigned long adr) +pfm_kvirt_to_pa(unsigned long adr) { __u64 pa = ia64_tpa(adr); - DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); + //DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); return pa; } + static void * -rvmalloc(unsigned long size) +pfm_rvmalloc(unsigned long size) { void *mem; unsigned long adr, page; - /* XXX: may have to revisit this part because - * vmalloc() does not necessarily return a page-aligned buffer. - * This maybe a security problem when mapped at user level - */ mem=vmalloc(size); if (mem) { + //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); + page = pfm_kvirt_to_pa(adr); mem_map_reserve(virt_to_page(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; + adr += PAGE_SIZE; + size -= PAGE_SIZE; } } return mem; } static void -rvfree(void *mem, unsigned long size) +pfm_rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr, page = 0; if (mem) { adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); + page = pfm_kvirt_to_pa(adr); mem_map_unreserve(virt_to_page(__va(page))); adr+=PAGE_SIZE; size-=PAGE_SIZE; } vfree(mem); } + return; +} + +/* + * This function gets called from mm/mmap.c:exit_mmap() only when there is a sampling buffer + * attached to the context AND the current task has a mapping for it, i.e., it is the original + * creator of the context. + * + * This function is used to remember the fact that the vma describing the sampling buffer + * has now been removed. It can only be called when no other tasks share the same mm context. + * + */ +static void +pfm_vm_close(struct vm_area_struct *vma) +{ + pfm_smpl_buffer_desc_t *psb = (pfm_smpl_buffer_desc_t *)vma->vm_private_data; + + if (psb == NULL) { + printk("perfmon: psb is null in [%d]\n", current->pid); + return; + } + /* + * Add PSB to list of buffers to free on release_thread() when no more users + * + * This call is safe because, once the count is zero is cannot be modified anymore. + * This is not because there is no more user of the mm context, that the sampling + * buffer is not being used anymore outside of this task. In fact, it can still + * be accessed from within the kernel by another task (such as the monitored task). + * + * Therefore, we only move the psb into the list of buffers to free when we know + * nobody else is using it. + * The linked list if independent of the perfmon context, because in the case of + * multi-threaded processes, the last thread may not have been involved with + * monitoring however it will be the one removing the vma and it should therefore + * also remove the sampling buffer. This buffer cannot be removed until the vma + * is removed. + * + * This function cannot remove the buffer from here, because exit_mmap() must first + * complete. Given that there is no other vma related callback in the generic code, + * we have created on own with the linked list of sampling buffer to free which + * is part of the thread structure. In release_thread() we check if the list is + * empty. If not we call into perfmon to free the buffer and psb. That is the only + * way to ensure a safe deallocation of the sampling buffer which works when + * the buffer is shared between distinct processes or with multi-threaded programs. + * + * We need to lock the psb because the refcnt test and flag manipulation must + * looked like an atomic operation vis a vis pfm_context_exit() + */ + LOCK_PSB(psb); + + if (psb->psb_refcnt == 0) { + + psb->psb_next = current->thread.pfm_smpl_buf_list; + current->thread.pfm_smpl_buf_list = psb; + + DBprintk(("psb for [%d] smpl @%p size %ld inserted into list\n", + current->pid, psb->psb_hdr, psb->psb_size)); + } + DBprintk(("psb vma flag cleared for [%d] smpl @%p size %ld inserted into list\n", + current->pid, psb->psb_hdr, psb->psb_size)); + + /* + * indicate to pfm_context_exit() that the vma has been removed. + */ + psb->psb_flags &= ~PFM_PSB_VMA; + + UNLOCK_PSB(psb); +} + +/* + * This function is called from pfm_destroy_context() and also from pfm_inherit() + * to explicitely remove the sampling buffer mapping from the user level address space. + */ +static int +pfm_remove_smpl_mapping(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + pfm_smpl_buffer_desc_t *psb; + int r; + + /* + * some sanity checks first + */ + if (ctx == NULL || task->mm == NULL || ctx->ctx_smpl_vaddr == 0 || ctx->ctx_psb == NULL) { + printk("perfmon: invalid context mm=%p\n", task->mm); + return -1; + } + psb = ctx->ctx_psb; + + down_write(&task->mm->mmap_sem); + + r = do_munmap(task->mm, ctx->ctx_smpl_vaddr, psb->psb_size); + + up_write(&task->mm->mmap_sem); + if (r !=0) { + printk("perfmon: pid %d unable to unmap sampling buffer @0x%lx size=%ld\n", + task->pid, ctx->ctx_smpl_vaddr, psb->psb_size); + } + DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d\n", + task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r)); + + /* + * make sure we suppress all traces of this buffer + * (important for pfm_inherit) + */ + ctx->ctx_smpl_vaddr = 0; + + return 0; } static pfm_context_t * pfm_context_alloc(void) { - pfm_context_t *pfc; + pfm_context_t *ctx; /* allocate context descriptor */ - pfc = vmalloc(sizeof(*pfc)); - if (pfc) memset(pfc, 0, sizeof(*pfc)); - - return pfc; + ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); + if (ctx) memset(ctx, 0, sizeof(pfm_context_t)); + + return ctx; } static void -pfm_context_free(pfm_context_t *pfc) +pfm_context_free(pfm_context_t *ctx) { - if (pfc) vfree(pfc); + if (ctx) kfree(ctx); } static int @@ -434,11 +594,13 @@ { unsigned long page; + DBprintk(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); + while (size > 0) { - page = kvirt_to_pa(buf); + page = pfm_kvirt_to_pa(buf); if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM; - + addr += PAGE_SIZE; buf += PAGE_SIZE; size -= PAGE_SIZE; @@ -458,7 +620,7 @@ for (i=0; i < size; i++, which++) res += hweight64(*which); - DBprintk((" res=%ld\n", res)); + DBprintk(("weight=%ld\n", res)); return res; } @@ -467,15 +629,16 @@ * Allocates the sampling buffer and remaps it into caller's address space */ static int -pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long which_pmds, unsigned long entries, void **user_addr) +pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long *which_pmds, unsigned long entries, + void **user_vaddr) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long addr, size, regcount; + struct vm_area_struct *vma = NULL; + unsigned long size, regcount; void *smpl_buf; pfm_smpl_buffer_desc_t *psb; - regcount = pfm_smpl_entry_size(&which_pmds, 1); + regcount = pfm_smpl_entry_size(which_pmds, 1); /* note that regcount might be 0, in this case only the header for each * entry will be recorded. @@ -488,133 +651,207 @@ + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); /* * check requested size to avoid Denial-of-service attacks - * XXX: may have to refine this test + * XXX: may have to refine this test + * Check against address space limit. + * + * if ((mm->total_vm << PAGE_SHIFT) + len> current->rlim[RLIMIT_AS].rlim_cur) + * return -ENOMEM; */ if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; - /* find some free area in address space */ - addr = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE); - if (!addr) goto no_addr; + /* + * We do the easy to undo allocations first. + * + * pfm_rvmalloc(), clears the buffer, so there is no leak + */ + smpl_buf = pfm_rvmalloc(size); + if (smpl_buf == NULL) { + DBprintk(("Can't allocate sampling buffer\n")); + return -ENOMEM; + } + + DBprintk(("smpl_buf @%p\n", smpl_buf)); - DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr)); + /* allocate sampling buffer descriptor now */ + psb = kmalloc(sizeof(*psb), GFP_KERNEL); + if (psb == NULL) { + DBprintk(("Can't allocate sampling buffer descriptor\n")); + pfm_rvfree(smpl_buf, size); + return -ENOMEM; + } /* allocate vma */ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!vma) goto no_vma; - - /* XXX: see rvmalloc() for page alignment problem */ - smpl_buf = rvmalloc(size); - if (smpl_buf == NULL) goto no_buffer; - - DBprintk((" smpl_buf @%p\n", smpl_buf)); - - if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap; - - /* allocate sampling buffer descriptor now */ - psb = vmalloc(sizeof(*psb)); - if (psb == NULL) goto no_buffer_desc; + if (!vma) { + DBprintk(("Cannot allocate vma\n")); + goto error; + } + /* + * partially initialize the vma for the sampling buffer + */ + vma->vm_mm = mm; + vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + vma->vm_ops = &pfm_vm_ops; /* necesarry to get the close() callback */ + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_raend = 0; + vma->vm_private_data = psb; /* information needed by the pfm_vm_close() function */ - /* start with something clean */ - memset(smpl_buf, 0x0, size); + /* + * Now we have everything we need and we can initialize + * and connect all the data structures + */ psb->psb_hdr = smpl_buf; - psb->psb_addr = (char *)smpl_buf+sizeof(perfmon_smpl_hdr_t); /* first entry */ + psb->psb_addr = ((char *)smpl_buf)+sizeof(perfmon_smpl_hdr_t); /* first entry */ psb->psb_size = size; /* aligned size */ psb->psb_index = 0; psb->psb_entries = entries; + psb->psb_flags = PFM_PSB_VMA; /* remember that there is a vma describing the buffer */ + psb->psb_refcnt = 1; - atomic_set(&psb->psb_refcnt, 1); + spin_lock_init(&psb->psb_lock); + /* + * XXX: will need to do cacheline alignment to avoid false sharing in SMP mode and + * multitask monitoring. + */ psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); - DBprintk((" psb @%p entry_size=%ld hdr=%p addr=%p\n", (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, (void *)psb->psb_addr)); - - /* initialize some of the fields of header */ - psb->psb_hdr->hdr_version = PFM_SMPL_HDR_VERSION; - psb->psb_hdr->hdr_entry_size = sizeof(perfmon_smpl_entry_t)+regcount*sizeof(u64); - psb->psb_hdr->hdr_pmds = which_pmds; - - /* store which PMDS to record */ - ctx->ctx_smpl_regs = which_pmds; + DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p\n", + (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, + (void *)psb->psb_addr)); - /* link to perfmon context */ - ctx->ctx_smpl_buf = psb; + /* initialize some of the fields of user visible buffer header */ + psb->psb_hdr->hdr_version = PFM_SMPL_VERSION; + psb->psb_hdr->hdr_entry_size = psb->psb_entry_size; + psb->psb_hdr->hdr_pmds[0] = which_pmds[0]; /* - * initialize the vma for the sampling buffer + * Let's do the difficult operations next. + * + * now we atomically find some area in the address space and + * remap the buffer in it. */ - vma->vm_mm = mm; - vma->vm_start = addr; - vma->vm_end = addr + size; - vma->vm_flags = VM_READ|VM_MAYREAD; - vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ - vma->vm_ops = NULL; - vma->vm_pgoff = 0; - vma->vm_file = NULL; - vma->vm_raend = 0; + down_write(¤t->mm->mmap_sem); + - vma->vm_private_data = ctx; /* link to pfm_context(not yet used) */ + /* find some free area in address space, must have mmap sem held */ + vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS); + if (vma->vm_start == 0UL) { + DBprintk(("Cannot find unmapped area for size %ld\n", size)); + up_write(¤t->mm->mmap_sem); + goto error; + } + vma->vm_end = vma->vm_start + size; + + DBprintk(("entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, vma->vm_start)); + + /* can only be applied to current, need to have the mm semaphore held when called */ + if (pfm_remap_buffer((unsigned long)smpl_buf, vma->vm_start, size)) { + DBprintk(("Can't remap buffer\n")); + up_write(¤t->mm->mmap_sem); + goto error; + } /* - * now insert the vma in the vm list for the process + * now insert the vma in the vm list for the process, must be + * done with mmap lock held */ insert_vm_struct(mm, vma); mm->total_vm += size >> PAGE_SHIFT; + up_write(¤t->mm->mmap_sem); + + /* store which PMDS to record */ + ctx->ctx_smpl_regs[0] = which_pmds[0]; + + + /* link to perfmon context */ + ctx->ctx_psb = psb; + /* - * that's the address returned to the user + * keep track of user level virtual address */ - *user_addr = (void *)addr; + ctx->ctx_smpl_vaddr = *(unsigned long *)user_vaddr = vma->vm_start; return 0; - /* outlined error handling */ -no_addr: - DBprintk(("Cannot find unmapped area for size %ld\n", size)); - return -ENOMEM; -no_vma: - DBprintk(("Cannot allocate vma\n")); - return -ENOMEM; -cant_remap: - DBprintk(("Can't remap buffer\n")); - rvfree(smpl_buf, size); -no_buffer: - DBprintk(("Can't allocate sampling buffer\n")); - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; -no_buffer_desc: - DBprintk(("Can't allocate sampling buffer descriptor\n")); - kmem_cache_free(vm_area_cachep, vma); - rvfree(smpl_buf, size); +error: + pfm_rvfree(smpl_buf, size); + kfree(psb); return -ENOMEM; } +/* + * XXX: do something better here + */ +static int +pfm_bad_permissions(struct task_struct *task) +{ + /* stolen from bad_signal() */ + return (current->session != task->session) + && (current->euid ^ task->suid) && (current->euid ^ task->uid) + && (current->uid ^ task->suid) && (current->uid ^ task->uid); +} + + static int -pfx_is_sane(pfreq_context_t *pfx) +pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx) { int ctx_flags; + int cpu; /* valid signal */ - //if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return -EINVAL; - if (pfx->notify_sig !=0 && pfx->notify_sig != SIGPROF) return -EINVAL; /* cannot send to process 1, 0 means do not notify */ - if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return -EINVAL; - - ctx_flags = pfx->flags; + if (pfx->ctx_notify_pid == 1) { + DBprintk(("invalid notify_pid %d\n", pfx->ctx_notify_pid)); + return -EINVAL; + } + ctx_flags = pfx->ctx_flags; if (ctx_flags & PFM_FL_SYSTEM_WIDE) { -#ifdef CONFIG_SMP - if (smp_num_cpus > 1) { - printk("perfmon: system wide monitoring on SMP not yet supported\n"); + DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask)); + /* + * cannot block in this mode + */ + if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { + DBprintk(("cannot use blocking mode when in system wide monitoring\n")); return -EINVAL; } -#endif - if ((ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) == 0) { - printk("perfmon: system wide monitoring cannot use blocking notification mode\n"); + /* + * must only have one bit set in the CPU mask + */ + if (hweight64(pfx->ctx_cpu_mask) != 1UL) { + DBprintk(("invalid CPU mask specified\n")); + return -EINVAL; + } + /* + * and it must be a valid CPU + */ + cpu = ffs(pfx->ctx_cpu_mask); + if (cpu > smp_num_cpus) { + DBprintk(("CPU%d is not online\n", cpu)); + return -EINVAL; + } + /* + * check for pre-existing pinning, if conflicting reject + */ + if (task->cpus_allowed != ~0UL && (task->cpus_allowed & (1UL<pid, + task->cpus_allowed, cpu)); return -EINVAL; } + + } else { + /* + * must provide a target for the signal in blocking mode even when + * no counter is configured with PFM_FL_REG_OVFL_NOTIFY + */ + if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) return -EINVAL; } /* probably more to add here */ @@ -622,68 +859,97 @@ } static int -pfm_context_create(int flags, perfmon_req_t *req) +pfm_create_context(struct task_struct *task, pfm_context_t *ctx, void *req, int count, + struct pt_regs *regs) { - pfm_context_t *ctx; - struct task_struct *task = NULL; - perfmon_req_t tmp; + pfarg_context_t tmp; void *uaddr = NULL; - int ret; + int ret, cpu = 0; int ctx_flags; - pid_t pid; + pid_t notify_pid; - /* to go away */ - if (flags) { - printk("perfmon: use context flags instead of perfmon() flags. Obsoleted API\n"); - } + /* a context has already been defined */ + if (ctx) return -EBUSY; + + /* + * not yet supported + */ + if (task != current) return -EINVAL; if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - ret = pfx_is_sane(&tmp.pfr_ctx); + ret = pfx_is_sane(task, &tmp); if (ret < 0) return ret; - ctx_flags = tmp.pfr_ctx.flags; + ctx_flags = tmp.ctx_flags; + + ret = -EBUSY; + + LOCK_PFS(); if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + + /* at this point, we know there is at least one bit set */ + cpu = ffs(tmp.ctx_cpu_mask) - 1; + + DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id())); + + if (pfm_sessions.pfs_task_sessions > 0) { + DBprintk(("system wide not possible, task_sessions=%ld\n", pfm_sessions.pfs_task_sessions)); + goto abort; + } + + if (pfm_sessions.pfs_sys_session[cpu]) { + DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",pfm_sessions.pfs_sys_session[cpu]->pid, cpu)); + goto abort; + } + pfm_sessions.pfs_sys_session[cpu] = task; /* - * XXX: This is not AT ALL SMP safe + * count the number of system wide sessions */ - if (pfs_info.pfs_proc_sessions > 0) return -EBUSY; - if (pfs_info.pfs_sys_session > 0) return -EBUSY; + pfm_sessions.pfs_sys_sessions++; - pfs_info.pfs_sys_session = 1; - - } else if (pfs_info.pfs_sys_session >0) { + } else if (pfm_sessions.pfs_sys_sessions == 0) { + pfm_sessions.pfs_task_sessions++; + } else { /* no per-process monitoring while there is a system wide session */ - return -EBUSY; - } else - pfs_info.pfs_proc_sessions++; + goto abort; + } + + UNLOCK_PFS(); + + ret = -ENOMEM; ctx = pfm_context_alloc(); if (!ctx) goto error; - /* record the creator (debug only) */ - ctx->ctx_creator = current; + /* record the creator (important for inheritance) */ + ctx->ctx_owner = current; + + notify_pid = tmp.ctx_notify_pid; - pid = tmp.pfr_ctx.notify_pid; + spin_lock_init(&ctx->ctx_lock); - spin_lock_init(&ctx->ctx_notify_lock); + if (notify_pid == current->pid) { - if (pid == current->pid) { ctx->ctx_notify_task = task = current; current->thread.pfm_context = ctx; - atomic_set(¤t->thread.pfm_notifiers_check, 1); + } else if (notify_pid!=0) { + struct task_struct *notify_task; - } else if (pid!=0) { read_lock(&tasklist_lock); - task = find_task_by_pid(pid); - if (task) { + notify_task = find_task_by_pid(notify_pid); + + if (notify_task) { + + ret = -EPERM; + /* - * record who to notify - */ - ctx->ctx_notify_task = task; + * check if we can send this task a signal + */ + if (pfm_bad_permissions(notify_task)) goto buffer_error; /* * make visible @@ -702,7 +968,9 @@ * task has been detached from the tasklist otherwise you are * exposed to race conditions. */ - atomic_add(1, &task->thread.pfm_notifiers_check); + atomic_add(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); + + ctx->ctx_notify_task = notify_task; } read_unlock(&tasklist_lock); } @@ -710,37 +978,48 @@ /* * notification process does not exist */ - if (pid != 0 && task == NULL) { + if (notify_pid != 0 && ctx->ctx_notify_task == NULL) { ret = -EINVAL; goto buffer_error; } - ctx->ctx_notify_sig = SIGPROF; /* siginfo imposes a fixed signal */ + if (tmp.ctx_smpl_entries) { + DBprintk(("sampling entries=%ld\n",tmp.ctx_smpl_entries)); - if (tmp.pfr_ctx.smpl_entries) { - DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries)); - - ret = pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, - tmp.pfr_ctx.smpl_entries, &uaddr); + ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, + tmp.ctx_smpl_entries, &uaddr); if (ret<0) goto buffer_error; - tmp.pfr_ctx.smpl_vaddr = uaddr; + tmp.ctx_smpl_vaddr = uaddr; } /* initialization of context's flags */ - ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; - ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; - ctx->ctx_fl_exclintr = (ctx_flags & PFM_FL_EXCL_INTR) ? 1: 0; - ctx->ctx_fl_frozen = 0; + ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_frozen = 0; + /* + * setting this flag to 0 here means, that the creator or the task that the + * context is being attached are granted access. Given that a context can only + * be created for the calling process this, in effect only allows the creator + * to access the context. See pfm_protect() for more. + */ + ctx->ctx_fl_protected = 0; + + /* for system wide mode only (only 1 bit set) */ + ctx->ctx_cpu = cpu; + + atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */ /* * Keep track of the pmds we want to sample * XXX: may be we don't need to save/restore the DEAR/IEAR pmds * but we do need the BTB for sure. This is because of a hardware * buffer of 1 only for non-BTB pmds. + * + * We ignore the unimplemented pmds specified by the user */ - ctx->ctx_used_pmds[0] = tmp.pfr_ctx.smpl_regs; - ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ + ctx->ctx_used_pmds[0] = tmp.ctx_smpl_regs[0] & pmu_conf.impl_regs[4]; + ctx->ctx_saved_pmcs[0] = 1; /* always save/restore PMC[0] */ sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ @@ -750,31 +1029,28 @@ goto buffer_error; } - DBprintk((" context=%p, pid=%d notify_sig %d notify_task=%p\n",(void *)ctx, current->pid, ctx->ctx_notify_sig, ctx->ctx_notify_task)); - DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, current->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + DBprintk(("context=%p, pid=%d notify_task=%p\n", + (void *)ctx, task->pid, ctx->ctx_notify_task)); + + DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d\n", + (void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, + ctx->ctx_fl_block, ctx->ctx_fl_system)); /* * when no notification is required, we can make this visible at the last moment */ - if (pid == 0) current->thread.pfm_context = ctx; - + if (notify_pid == 0) task->thread.pfm_context = ctx; /* - * by default, we always include interrupts for system wide - * DCR.pp is set by default to zero by kernel in cpu_init() + * pin task to CPU and force reschedule on exit to ensure + * that when back to user level the task runs on the designated + * CPU. */ if (ctx->ctx_fl_system) { - if (ctx->ctx_fl_exclintr == 0) { - unsigned long dcr = ia64_get_dcr(); - - ia64_set_dcr(dcr|IA64_DCR_PP); - /* - * keep track of the kernel default value - */ - pfs_info.pfs_dfl_dcr = dcr; - - DBprintk((" dcr.pp is set\n")); - } - } + ctx->ctx_saved_cpus_allowed = task->cpus_allowed; + task->cpus_allowed = 1UL << cpu; + task->need_resched = 1; + DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid,task->cpus_allowed)); + } return 0; @@ -784,225 +1060,492 @@ /* * undo session reservation */ + LOCK_PFS(); + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { - pfs_info.pfs_sys_session = 0; + pfm_sessions.pfs_sys_session[cpu] = NULL; + pfm_sessions.pfs_sys_sessions--; } else { - pfs_info.pfs_proc_sessions--; + pfm_sessions.pfs_task_sessions--; } +abort: + UNLOCK_PFS(); + return ret; } static void -pfm_reset_regs(pfm_context_t *ctx) +pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) { - unsigned long mask = ctx->ctx_ovfl_regs; - int i, cnum; + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i; + + DBprintk(("masks=0x%lx\n", mask)); - DBprintk((" ovfl_regs=0x%lx\n", mask)); /* * now restore reset value on sampling overflowed counters */ - for(i=0, cnum=PMU_FIRST_COUNTER; i < pmu_conf.max_counters; i++, cnum++, mask >>= 1) { + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { if (mask & 0x1) { - DBprintk((" reseting PMD[%d]=%lx\n", cnum, ctx->ctx_pmds[i].smpl_rval & pmu_conf.perf_ovfl_val)); + val = flag == PFM_RELOAD_LONG_RESET ? + ctx->ctx_soft_pmds[i].long_reset: + ctx->ctx_soft_pmds[i].short_reset; + + reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0]; + + DBprintk(("[%d] %s reset soft_pmd[%d]=%lx\n", + current->pid, + flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val)); /* upper part is ignored on rval */ - ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + pfm_write_soft_counter(ctx, i, val); + } + } - /* - * we must reset BTB index (clears pmd16.full to make - * sure we do not report the same branches twice. - * The non-blocking case in handled in update_counters() - */ - if (cnum == ctx->ctx_btb_counter) { - DBprintk(("reseting PMD16\n")); - ia64_set_pmd(16, 0); - } + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + val = flag == PFM_RELOAD_LONG_RESET ? + ctx->ctx_soft_pmds[i].long_reset: + ctx->ctx_soft_pmds[i].short_reset; + + if (PMD_IS_COUNTING(i)) { + pfm_write_soft_counter(ctx, i, val); + } else { + ia64_set_pmd(i, val); } + + DBprintk(("[%d] %s reset_others pmd[%d]=%lx\n", + current->pid, + flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val)); } /* just in case ! */ - ctx->ctx_ovfl_regs = 0; + ctx->ctx_ovfl_regs[0] = 0UL; } static int -pfm_write_pmcs(struct task_struct *ta, perfmon_req_t *req, int count) +pfm_write_pmcs(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { struct thread_struct *th = &ta->thread; - pfm_context_t *ctx = th->pfm_context; - perfmon_req_t tmp; - unsigned long cnum; + pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; + unsigned int cnum; int i; + int ret = 0, reg_retval = 0; + + /* we don't quite support this right now */ + if (ta != current) return -EINVAL; + + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; /* XXX: ctx locking may be required here */ for (i = 0; i < count; i++, req++) { + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - cnum = tmp.pfr_reg.reg_num; + cnum = tmp.reg_num; - /* XXX needs to check validity of the data maybe */ - if (!PMC_IS_IMPL(cnum)) { - DBprintk((" invalid pmc[%ld]\n", cnum)); - return -EINVAL; + /* + * we reject all non implemented PMC as well + * as attempts to modify PMC[0-3] which are used + * as status registers by the PMU + */ + if (!PMC_IS_IMPL(cnum) || cnum < 4) { + DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum)); + ret = -EINVAL; + goto abort_mission; } + /* + * A PMC used to configure monitors must be: + * - system-wide session: privileged monitor + * - per-task : user monitor + * any other configuration is rejected. + */ + if (PMC_IS_MONITOR(cnum)) { + pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value; - if (PMC_IS_COUNTER(cnum)) { + DBprintk(("pmc[%u].pm = %d\n", cnum, p->pmc_pm)); + if (ctx->ctx_fl_system ^ p->pmc_pm) { + //if ((ctx->ctx_fl_system == 1 && p->pmc_pm == 0) + // ||(ctx->ctx_fl_system == 0 && p->pmc_pm == 1)) { + ret = -EINVAL; + goto abort_mission; + } /* - * we keep track of EARS/BTB to speed up sampling later + * enforce generation of overflow interrupt. Necessary on all + * CPUs which do not implement 64-bit hardware counters. */ - if (PMC_IS_DEAR(&tmp.pfr_reg.reg_value)) { - ctx->ctx_dear_counter = cnum; - } else if (PMC_IS_IEAR(&tmp.pfr_reg.reg_value)) { - ctx->ctx_iear_counter = cnum; - } else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) { - ctx->ctx_btb_counter = cnum; + p->pmc_oi = 1; + } + + if (PMC_IS_COUNTING(cnum)) { + if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) { + /* + * must have a target for the signal + */ + if (ctx->ctx_notify_task == NULL) { + ret = -EINVAL; + goto abort_mission; + } + + ctx->ctx_soft_pmds[cnum].flags |= PFM_REGFL_OVFL_NOTIFY; } -#if 0 - if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) - ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; -#endif + /* + * copy reset vector + */ + ctx->ctx_soft_pmds[cnum].reset_pmds[0] = tmp.reg_reset_pmds[0]; + ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1]; + ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2]; + ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3]; + + /* + * needed in case the user does not initialize the equivalent + * PMD. Clearing is done in reset_pmu() so there is no possible + * leak here. + */ + CTX_USED_PMD(ctx, cnum); } - /* keep track of what we use */ - CTX_USED_PMC(ctx, cnum); - ia64_set_pmc(cnum, tmp.pfr_reg.reg_value); +abort_mission: + if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL; - DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x used_pmcs=0%lx\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags, ctx->ctx_used_pmcs[0])); + PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval); - } - /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out - */ - if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; + /* + * update register return value, abort all if problem during copy. + */ + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; - return 0; + /* + * if there was something wrong on this register, don't touch + * the hardware at all and abort write request for others. + * + * On error, the user mut sequentially scan the table and the first + * entry which has a return flag set is the one that caused the error. + */ + if (ret != 0) { + DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", + ta->pid, cnum, tmp.reg_value, reg_retval)); + break; + } + + /* + * We can proceed with this register! + */ + + /* + * keep copy the pmc, used for register reload + */ + th->pmc[cnum] = tmp.reg_value; + + ia64_set_pmc(cnum, tmp.reg_value); + + DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x save_pmcs=0%lx reload_pmcs=0x%lx\n", + ta->pid, cnum, tmp.reg_value, + ctx->ctx_soft_pmds[cnum].flags, + ctx->ctx_saved_pmcs[0], ctx->ctx_reload_pmcs[0])); + + } + return ret; } static int -pfm_write_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +pfm_write_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *th = &ta->thread; - pfm_context_t *ctx = th->pfm_context; - perfmon_req_t tmp; - unsigned long cnum; + pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; + unsigned int cnum; int i; + int ret = 0, reg_retval = 0; + + /* we don't quite support this right now */ + if (ta != current) return -EINVAL; + + /* + * Cannot do anything before PMU is enabled + */ + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + /* XXX: ctx locking may be required here */ for (i = 0; i < count; i++, req++) { - int k; if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - cnum = tmp.pfr_reg.reg_num; - - k = cnum - PMU_FIRST_COUNTER; + cnum = tmp.reg_num; - if (!PMD_IS_IMPL(cnum)) return -EINVAL; + if (!PMD_IS_IMPL(cnum)) { + ret = -EINVAL; + goto abort_mission; + } /* update virtualized (64bits) counter */ - if (PMD_IS_COUNTER(cnum)) { - ctx->ctx_pmds[k].ival = tmp.pfr_reg.reg_value; - ctx->ctx_pmds[k].val = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val; - ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset; - ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset; + if (PMD_IS_COUNTING(cnum)) { + ctx->ctx_soft_pmds[cnum].ival = tmp.reg_value; + ctx->ctx_soft_pmds[cnum].val = tmp.reg_value & ~pmu_conf.perf_ovfl_val; + ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset; + ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset; + + } +abort_mission: + if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL; + + PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval); - if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) - ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; + + /* + * if there was something wrong on this register, don't touch + * the hardware at all and abort write request for others. + * + * On error, the user mut sequentially scan the table and the first + * entry which has a return flag set is the one that caused the error. + */ + if (ret != 0) { + DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", + ta->pid, cnum, tmp.reg_value, reg_retval)); + break; } + /* keep track of what we use */ CTX_USED_PMD(ctx, cnum); /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(cnum, tmp.pfr_reg.reg_value); + ia64_set_pmd(cnum, tmp.reg_value); /* to go away */ ia64_srlz_d(); - DBprintk((" setting PMD[%ld]: ovfl_notify=%d pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx used_pmds=0%lx\n", - cnum, - PMD_OVFL_NOTIFY(ctx, cnum - PMU_FIRST_COUNTER), - ctx->ctx_pmds[k].val, - ctx->ctx_pmds[k].ovfl_rval, - ctx->ctx_pmds[k].smpl_rval, - ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val, - ctx->ctx_used_pmds[0])); + DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx short_reset=0x%lx " + "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n", + ta->pid, cnum, + ctx->ctx_soft_pmds[cnum].val, + ctx->ctx_soft_pmds[cnum].short_reset, + ctx->ctx_soft_pmds[cnum].long_reset, + ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val, + PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', + ctx->ctx_used_pmds[0], + ctx->ctx_soft_pmds[cnum].reset_pmds[0])); } - /* - * we have to set this here event hough we haven't necessarily started monitoring - * because we may be context switched out - */ - if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; - - return 0; + return ret; } static int -pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count) +pfm_read_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { struct thread_struct *th = &ta->thread; - pfm_context_t *ctx = th->pfm_context; unsigned long val=0; - perfmon_req_t tmp; + pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; int i; + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + /* * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING - * This is required when the monitoring has been stoppped by user of kernel. - * If ity is still going on, then that's fine because we a re not gauranteed - * to return an accurate value in this case + * This is required when the monitoring has been stoppped by user or kernel. + * If it is still going on, then that's fine because we a re not guaranteed + * to return an accurate value in this case. */ /* XXX: ctx locking may be required here */ + DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), ta->pid)); + for (i = 0; i < count; i++, req++) { - unsigned long reg_val = ~0, ctx_val = ~0; + unsigned long reg_val = ~0UL, ctx_val = ~0UL; if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; + if (!PMD_IS_IMPL(tmp.reg_num)) goto abort_mission; - if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) { - if (ta == current){ - val = ia64_get_pmd(tmp.pfr_reg.reg_num); - } else { - val = reg_val = th->pmd[tmp.pfr_reg.reg_num]; + /* + * If the task is not the current one, then we check if the + * PMU state is still in the local live register due to lazy ctxsw. + * If true, then we read directly from the registers. + */ + if (atomic_read(&ctx->ctx_last_cpu) == smp_processor_id()){ + ia64_srlz_d(); + val = reg_val = ia64_get_pmd(tmp.reg_num); + DBprintk(("reading pmd[%u]=0x%lx from hw\n", tmp.reg_num, val)); + } else { +#ifdef CONFIG_SMP + int cpu; + /* + * for SMP system, the context may still be live on another + * CPU so we need to fetch it before proceeding with the read + * This call we only be made once for the whole loop because + * of ctx_last_cpu becoming == -1. + * + * We cannot reuse ctx_last_cpu as it may change before we get to the + * actual IPI call. In this case, we will do the call for nothing but + * there is no way around it. The receiving side will simply do nothing. + */ + cpu = atomic_read(&ctx->ctx_last_cpu); + if (cpu != -1) { + DBprintk(("must fetch on CPU%d for [%d]\n", cpu, ta->pid)); + pfm_fetch_regs(cpu, ta, ctx); } - val &= pmu_conf.perf_ovfl_val; +#endif + /* context has been saved */ + val = reg_val = th->pmd[tmp.reg_num]; + } + if (PMD_IS_COUNTING(tmp.reg_num)) { /* - * lower part of .val may not be zero, so we must be an addition because of - * residual count (see update_counters). + * XXX: need to check for overflow */ - val += ctx_val = ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; + + val &= pmu_conf.perf_ovfl_val; + val += ctx_val = ctx->ctx_soft_pmds[tmp.reg_num].val; } else { - /* for now */ - if (ta != current) return -EINVAL; - ia64_srlz_d(); - val = ia64_get_pmd(tmp.pfr_reg.reg_num); + val = reg_val = ia64_get_pmd(tmp.reg_num); } - tmp.pfr_reg.reg_value = val; + PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); + tmp.reg_value = val; - DBprintk((" reading PMD[%ld]=0x%lx reg=0x%lx ctx_val=0x%lx pmc=0x%lx\n", - tmp.pfr_reg.reg_num, val, reg_val, ctx_val, ia64_get_pmc(tmp.pfr_reg.reg_num))); + DBprintk(("read pmd[%u] soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", + tmp.reg_num, ctx_val, reg_val, + ia64_get_pmc(tmp.reg_num))); if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; } return 0; +abort_mission: + PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); + /* + * XXX: if this fails, we stick we the original failure, flag not updated! + */ + copy_to_user(req, &tmp, sizeof(tmp)); + return -EINVAL; + +} + +#ifdef PFM_PMU_USES_DBR +/* + * Only call this function when a process it trying to + * write the debug registers (reading is always allowed) + */ +int +pfm_use_debug_registers(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + int ret = 0; + + DBprintk(("called for [%d]\n", task->pid)); + + /* + * do it only once + */ + if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0; + + /* + * Even on SMP, we do not need to use an atomic here because + * the only way in is via ptrace() and this is possible only when the + * process is stopped. Even in the case where the ctxsw out is not totally + * completed by the time we come here, there is no way the 'stopped' process + * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine. + * So this is always safe. + */ + if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; + + /* + * XXX: not pretty + */ + LOCK_PFS(); + + /* + * We only allow the use of debug registers when there is no system + * wide monitoring + * XXX: we could relax this by + */ + if (pfm_sessions.pfs_sys_use_dbregs> 0) + ret = -1; + else + pfm_sessions.pfs_ptrace_use_dbregs++; + + DBprintk(("ptrace_use_dbregs=%lu sys_use_dbregs=%lu by [%d] ret = %d\n", + pfm_sessions.pfs_ptrace_use_dbregs, + pfm_sessions.pfs_sys_use_dbregs, + task->pid, ret)); + + UNLOCK_PFS(); + + return ret; +} + +/* + * This function is called for every task that exits with the + * IA64_THREAD_DBG_VALID set. This indicates a task which was + * able to use the debug registers for debugging purposes via + * ptrace(). Therefore we know it was not using them for + * perfmormance monitoring, so we only decrement the number + * of "ptraced" debug register users to keep the count up to date + */ +int +pfm_release_debug_registers(struct task_struct *task) +{ + int ret; + + LOCK_PFS(); + if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { + printk("perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task->pid); + ret = -1; + } else { + pfm_sessions.pfs_ptrace_use_dbregs--; + ret = 0; + } + UNLOCK_PFS(); + + return ret; +} +#else /* PFM_PMU_USES_DBR is true */ +/* + * in case, the PMU does not use the debug registers, these two functions are nops. + * The first function is called from arch/ia64/kernel/ptrace.c. + * The second function is called from arch/ia64/kernel/process.c. + */ +int +pfm_use_debug_registers(struct task_struct *task) +{ + return 0; +} +int +pfm_release_debug_registers(struct task_struct *task) +{ + return 0; } +#endif /* PFM_PMU_USES_DBR */ static int -pfm_do_restart(struct task_struct *task) +pfm_restart(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) { - struct thread_struct *th = &task->thread; - pfm_context_t *ctx = th->pfm_context; void *sem = &ctx->ctx_restart_sem; + /* + * Cannot do anything before PMU is enabled + */ + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + + + if (ctx->ctx_fl_frozen==0) { + printk("task %d without pmu_frozen set\n", task->pid); + return -EINVAL; + } + if (task == current) { - DBprintk((" restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET); - pfm_reset_regs(ctx); + ctx->ctx_ovfl_regs[0] = 0UL; /* * We ignore block/don't block because we never block @@ -1011,26 +1554,36 @@ ctx->ctx_fl_frozen = 0; if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; - ctx->ctx_smpl_buf->psb_index = 0; + ctx->ctx_psb->psb_hdr->hdr_count = 0; + ctx->ctx_psb->psb_index = 0; } - /* pfm_reset_smpl_buffers(ctx,th->pfm_ovfl_regs);*/ - /* simply unfreeze */ ia64_set_pmc(0, 0); ia64_srlz_d(); return 0; - } + } + /* restart on another task */ - /* check if blocking */ + /* + * if blocking, then post the semaphore. + * if non-blocking, then we ensure that the task will go into + * pfm_overflow_must_block() before returning to user mode. + * We cannot explicitely reset another task, it MUST always + * be done by the task itself. This works for system wide because + * the tool that is controlling the session is doing "self-monitoring". + * + * XXX: what if the task never goes back to user? + * + */ if (CTX_OVFL_NOBLOCK(ctx) == 0) { - DBprintk((" unblocking %d \n", task->pid)); + DBprintk(("unblocking %d \n", task->pid)); up(sem); - return 0; + } else { + task->thread.pfm_ovfl_block_reset = 1; } - +#if 0 /* * in case of non blocking mode, then it's just a matter of * of reseting the sampling buffer (if any) index. The PMU @@ -1041,281 +1594,719 @@ * must reset the header count first */ if (CTX_HAS_SMPL(ctx)) { - DBprintk((" resetting sampling indexes for %d \n", task->pid)); - ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; - ctx->ctx_smpl_buf->psb_index = 0; + DBprintk(("resetting sampling indexes for %d \n", task->pid)); + ctx->ctx_psb->psb_hdr->hdr_count = 0; + ctx->ctx_psb->psb_index = 0; } - +#endif return 0; } +#ifndef CONFIG_SMP /* - * system-wide mode: propagate activation/desactivation throughout the tasklist - * - * XXX: does not work for SMP, of course + * On UP kernels, we do not need to constantly set the psr.pp bit + * when a task is scheduled. The psr.pp bit can only be changed in + * the kernel because of a user request. Given we are on a UP non preeemptive + * kernel we know that no other task is running, so we cna simply update their + * psr.pp from their saved state. There is this no impact on the context switch + * code compared to the SMP case. */ static void -pfm_process_tasklist(int cmd) +pfm_tasklist_toggle_pp(unsigned int val) { struct task_struct *p; struct pt_regs *regs; + DBprintk(("invoked by [%d] pp=%u\n", current->pid, val)); + + read_lock(&tasklist_lock); + for_each_task(p) { - regs = (struct pt_regs *)((unsigned long)p + IA64_STK_OFFSET); + regs = (struct pt_regs *)((unsigned long) p + IA64_STK_OFFSET); + + /* + * position on pt_regs saved on stack on 1st entry into the kernel + */ regs--; - ia64_psr(regs)->pp = cmd; + + /* + * update psr.pp + */ + ia64_psr(regs)->pp = val; } + read_unlock(&tasklist_lock); } +#endif + + static int -do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) +pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) { - perfmon_req_t tmp; - struct thread_struct *th = &task->thread; - pfm_context_t *ctx = th->pfm_context; - - memset(&tmp, 0, sizeof(tmp)); + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - if (ctx == NULL && cmd != PFM_CREATE_CONTEXT && cmd < PFM_DEBUG_BASE) { - DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); - return -EINVAL; - } + /* + * Cannot do anything before PMU is enabled + */ + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - switch (cmd) { - case PFM_CREATE_CONTEXT: - /* a context has already been defined */ - if (ctx) return -EBUSY; + DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", + current->pid, + ctx->ctx_fl_system, PMU_OWNER(), + current)); + /* simply stop monitoring but not the PMU */ + if (ctx->ctx_fl_system) { - /* - * cannot directly create a context in another process - */ - if (task != current) return -EINVAL; + __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); - if (req == NULL || count != 1) return -EINVAL; + /* disable dcr pp */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; +#ifdef CONFIG_SMP + local_cpu_data->pfm_dcr_pp = 0; +#else + pfm_tasklist_toggle_pp(0); +#endif - return pfm_context_create(flags, req); + ia64_psr(regs)->pp = 0; - case PFM_WRITE_PMCS: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + } else { + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + ia64_psr(regs)->up = 0; + } + return 0; +} - return pfm_write_pmcs(task, req, count); +static int +pfm_disable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - case PFM_WRITE_PMDS: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; + /* + * stop monitoring, freeze PMU, and save state in context + * this call will clear IA64_THREAD_PM_VALID for per-task sessions. + */ + pfm_flush_regs(task); - return pfm_write_pmds(task, req, count); + if (ctx->ctx_fl_system) { + ia64_psr(regs)->pp = 0; + } else { + ia64_psr(regs)->up = 0; + } + /* + * goes back to default behavior + * no need to change live psr.sp because useless at the kernel level + */ + ia64_psr(regs)->sp = 1; - case PFM_START: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + DBprintk(("enabling psr.sp for [%d]\n", current->pid)); - if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); + ctx->ctx_flags.state = PFM_CTX_DISABLED; - SET_PMU_OWNER(current); + return 0; +} - /* will start monitoring right after rfi */ - ia64_psr(regs)->up = 1; - ia64_psr(regs)->pp = 1; - if (ctx->ctx_fl_system) { - pfm_process_tasklist(1); - pfs_info.pfs_pp = 1; - } - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; +static int +pfm_destroy_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; - ia64_set_pmc(0, 0); - ia64_srlz_d(); + /* + * if context was never enabled, then there is not much + * to do + */ + if (!CTX_IS_ENABLED(ctx)) goto skipped_stop; - break; + /* + * Disable context: stop monitoring, flush regs to software state (useless here), + * and freeze PMU + * + * The IA64_THREAD_PM_VALID is cleared by pfm_flush_regs() called from pfm_disable() + */ + pfm_disable(task, ctx, arg, count, regs); - case PFM_ENABLE: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + if (ctx->ctx_fl_system) { + ia64_psr(regs)->pp = 0; + } else { + ia64_psr(regs)->up = 0; + } - if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); + /* restore security level */ + ia64_psr(regs)->sp = 1; - /* reset all registers to stable quiet state */ - ia64_reset_pmu(); +skipped_stop: + /* + * remove sampling buffer mapping, if any + */ + if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task); - /* make sure nothing starts */ - ia64_psr(regs)->up = 0; - ia64_psr(regs)->pp = 0; + /* now free context and related state */ + pfm_context_exit(task); - /* do it on the live register as well */ - __asm__ __volatile__ ("rsm psr.pp|psr.pp;;"::: "memory"); + return 0; +} - SET_PMU_OWNER(current); +/* + * does nothing at the moment + */ +static int +pfm_unprotect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + return 0; +} - /* - * mark the state as valid. - * this will trigger save/restore at context switch - */ - if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; +static int +pfm_protect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + DBprintk(("context from [%d] is protected\n", task->pid)); + /* + * from now on, only the creator of the context has access to it + */ + ctx->ctx_fl_protected = 1; - /* simply unfreeze */ - ia64_set_pmc(0, 0); - ia64_srlz_d(); - break; + /* + * reinforce secure monitoring: cannot toggle psr.up + */ + ia64_psr(regs)->sp = 1; - case PFM_DISABLE: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + return 0; +} - /* simply freeze */ - ia64_set_pmc(0, 1); - ia64_srlz_d(); - /* - * XXX: cannot really toggle IA64_THREAD_PM_VALID - * but context is still considered valid, so any - * read request would return something valid. Same - * thing when this task terminates (pfm_flush_regs()). - */ - break; +static int +pfm_debug(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + unsigned int mode = *(unsigned int *)arg; - case PFM_READ_PMDS: - if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - - return pfm_read_pmds(task, req, count); - - case PFM_STOP: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* simply stop monitors, not PMU */ - ia64_psr(regs)->up = 0; - ia64_psr(regs)->pp = 0; - - if (ctx->ctx_fl_system) { - pfm_process_tasklist(0); - pfs_info.pfs_pp = 0; - } + pfm_debug_mode = mode == 0 ? 0 : 1; - break; + printk("perfmon debugging %s\n", pfm_debug_mode ? "on" : "off"); + + return 0; +} + +#ifdef PFM_PMU_USES_DBR + +typedef struct { + unsigned long ibr_mask:56; + unsigned long ibr_plm:4; + unsigned long ibr_ig:3; + unsigned long ibr_x:1; +} ibr_mask_reg_t; + +typedef struct { + unsigned long dbr_mask:56; + unsigned long dbr_plm:4; + unsigned long dbr_ig:2; + unsigned long dbr_w:1; + unsigned long dbr_r:1; +} dbr_mask_reg_t; + +typedef union { + unsigned long val; + ibr_mask_reg_t ibr; + dbr_mask_reg_t dbr; +} dbreg_t; + + +static int +pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = &task->thread; + pfm_context_t *ctx = task->thread.pfm_context; + pfarg_dbreg_t tmp, *req = (pfarg_dbreg_t *)arg; + dbreg_t dbreg; + unsigned int rnum; + int first_time; + int i, ret = 0; + + /* + * for range restriction: psr.db must be cleared or the + * the PMU will ignore the debug registers. + * + * XXX: may need more in system wide mode, + * no task can have this bit set? + */ + if (ia64_psr(regs)->db == 1) return -EINVAL; + + + first_time = ctx->ctx_fl_using_dbreg == 0; + + /* + * check for debug registers in system wide mode + * + */ + LOCK_PFS(); + if (ctx->ctx_fl_system && first_time) { + if (pfm_sessions.pfs_ptrace_use_dbregs) + ret = -EBUSY; + else + pfm_sessions.pfs_sys_use_dbregs++; + } + UNLOCK_PFS(); - case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */ + if (ret != 0) return ret; - if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system==0) { - printk(" PFM_RESTART not monitoring\n"); - return -EINVAL; + if (ctx->ctx_fl_system) { + /* we mark ourselves as owner of the debug registers */ + ctx->ctx_fl_using_dbreg = 1; + } else { + if (ctx->ctx_fl_using_dbreg == 0) { + ret= -EBUSY; + if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) { + DBprintk(("debug registers already in use for [%d]\n", task->pid)); + goto abort_mission; + } + /* we mark ourselves as owner of the debug registers */ + ctx->ctx_fl_using_dbreg = 1; + + /* + * Given debug registers cannot be used for both debugging + * and performance monitoring at the same time, we reuse + * the storage area to save and restore the registers on ctxsw. + */ + memset(task->thread.dbr, 0, sizeof(task->thread.dbr)); + memset(task->thread.ibr, 0, sizeof(task->thread.ibr)); + + /* + * clear hardware registers to make sure we don't leak + * information and pick up stale state + */ + for (i=0; i < pmu_conf.num_ibrs; i++) { + ia64_set_ibr(i, 0UL); } - if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) { - printk("task %d without pmu_frozen set\n", task->pid); - return -EINVAL; + for (i=0; i < pmu_conf.num_dbrs; i++) { + ia64_set_dbr(i, 0UL); } + } + } - return pfm_do_restart(task); /* we only look at first entry */ + ret = -EFAULT; - case PFM_DESTROY_CONTEXT: - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* first stop monitors */ - ia64_psr(regs)->up = 0; - ia64_psr(regs)->pp = 0; + /* + * Now install the values into the registers + */ + for (i = 0; i < count; i++, req++) { - /* then freeze PMU */ - ia64_set_pmc(0, 1); - ia64_srlz_d(); + + if (copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission; + + rnum = tmp.dbreg_num; + dbreg.val = tmp.dbreg_value; + + ret = -EINVAL; - /* don't save/restore on context switch */ - if (ctx->ctx_fl_system ==0) task->thread.flags &= ~IA64_THREAD_PM_VALID; + if ((mode == 0 && !IBR_IS_IMPL(rnum)) || ((mode == 1) && !DBR_IS_IMPL(rnum))) { + DBprintk(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", + rnum, dbreg.val, mode, i, count)); - SET_PMU_OWNER(NULL); + goto abort_mission; + } - /* now free context and related state */ - pfm_context_exit(task); - break; + /* + * make sure we do not install enabled breakpoint + */ + if (rnum & 0x1) { + if (mode == 0) + dbreg.ibr.ibr_x = 0; + else + dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; + } - case PFM_DEBUG_ON: - printk("perfmon debugging on\n"); - pfm_debug = 1; - break; + /* + * clear return flags and copy back to user + * + * XXX: fix once EAGAIN is implemented + */ + ret = -EFAULT; - case PFM_DEBUG_OFF: - printk("perfmon debugging off\n"); - pfm_debug = 0; - break; + PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0); + + if (copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission; + + /* + * Debug registers, just like PMC, can only be modified + * by a kernel call. Moreover, perfmon() access to those + * registers are centralized in this routine. The hardware + * does not modify the value of these registers, therefore, + * if we save them as they are written, we can avoid having + * to save them on context switch out. This is made possible + * by the fact that when perfmon uses debug registers, ptrace() + * won't be able to modify them concurrently. + */ + if (mode == 0) { + CTX_USED_IBR(ctx, rnum); + + ia64_set_ibr(rnum, dbreg.val); - default: - DBprintk((" UNknown command 0x%x\n", cmd)); + thread->ibr[rnum] = dbreg.val; + + DBprintk(("write ibr%u=0x%lx used_ibrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_ibrs[0])); + } else { + CTX_USED_DBR(ctx, rnum); + + ia64_set_dbr(rnum, dbreg.val); + + thread->dbr[rnum] = dbreg.val; + + DBprintk(("write dbr%u=0x%lx used_dbrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_dbrs[0])); + } + } + + return 0; + +abort_mission: + /* + * in case it was our first attempt, we undo the global modifications + */ + if (first_time) { + LOCK_PFS(); + if (ctx->ctx_fl_system) { + pfm_sessions.pfs_sys_use_dbregs--; + } + UNLOCK_PFS(); + ctx->ctx_fl_using_dbreg = 0; + } + /* + * install error return flag + */ + if (ret != -EFAULT) { + /* + * XXX: for now we can only come here on EINVAL + */ + PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL); + copy_to_user(req, &tmp, sizeof(tmp)); + } + return ret; +} + +static int +pfm_write_ibrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + + return pfm_write_ibr_dbr(0, task, arg, count, regs); +} + +static int +pfm_write_dbrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + + return pfm_write_ibr_dbr(1, task, arg, count, regs); +} + +#endif /* PFM_PMU_USES_DBR */ + +static int +pfm_get_features(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_features_t tmp; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.ft_version = PFM_VERSION; + tmp.ft_smpl_version = PFM_SMPL_VERSION; + + if (copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT; + + return 0; +} + +static int +pfm_start(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + /* + * Cannot do anything before PMU is enabled + */ + if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + + DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", + current->pid, + ctx->ctx_fl_system, PMU_OWNER(), + current)); + + if (PMU_OWNER() != task) { + printk("perfmon: pfm_start task [%d] not pmu owner\n", task->pid); + return -EINVAL; + } + + if (ctx->ctx_fl_system) { + + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); + +#ifdef CONFIG_SMP + local_cpu_data->pfm_dcr_pp = 1; +#else + pfm_tasklist_toggle_pp(1); +#endif + ia64_psr(regs)->pp = 1; + + __asm__ __volatile__ ("ssm psr.pp;;"::: "memory"); + + } else { + if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) { + printk("perfmon: pfm_start task flag not set for [%d]\n", task->pid); return -EINVAL; + } + ia64_psr(regs)->up = 1; + __asm__ __volatile__ ("sum psr.up;;"::: "memory"); + } + ia64_srlz_d(); + + return 0; +} + +static int +pfm_enable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + if (ctx->ctx_fl_system == 0 && PMU_OWNER() && PMU_OWNER() != current) + pfm_lazy_save_regs(PMU_OWNER()); + + /* reset all registers to stable quiet state */ + ia64_reset_pmu(task); + + /* make sure nothing starts */ + if (ctx->ctx_fl_system) { + ia64_psr(regs)->pp = 0; + ia64_psr(regs)->up = 0; /* just to make sure! */ + + __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); + +#ifdef CONFIG_SMP + local_cpu_data->pfm_syst_wide = 1; + local_cpu_data->pfm_dcr_pp = 0; +#endif + } else { + /* + * needed in case the task was a passive task during + * a system wide session and now wants to have its own + * session + */ + ia64_psr(regs)->pp = 0; /* just to make sure! */ + ia64_psr(regs)->up = 0; + + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + /* + * allow user control (user monitors only) + if (task == ctx->ctx_owner) { + */ + { + DBprintk(("clearing psr.sp for [%d]\n", current->pid)); + ia64_psr(regs)->sp = 0; + } + task->thread.flags |= IA64_THREAD_PM_VALID; } + + SET_PMU_OWNER(task); + + + ctx->ctx_flags.state = PFM_CTX_ENABLED; + atomic_set(&ctx->ctx_last_cpu, smp_processor_id()); + + /* simply unfreeze */ + ia64_set_pmc(0, 0); + ia64_srlz_d(); + return 0; } /* - * XXX: do something better here + * functions MUST be listed in the increasing order of their index (see permfon.h) */ +static pfm_cmd_desc_t pfm_cmd_tab[]={ +/* 0 */{ NULL, 0, 0, 0}, /* not used */ +/* 1 */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, +/* 2 */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, +/* 3 */{ pfm_read_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, +/* 4 */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 5 */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 6 */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 7 */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 8 */{ pfm_create_context, PFM_CMD_ARG_READ, 1, sizeof(pfarg_context_t)}, +/* 9 */{ pfm_destroy_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0}, +/* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0}, +/* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)}, +/* 14 */{ pfm_unprotect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 15 */{ NULL, 0, 0, 0}, /* not used */ +/* 16 */{ NULL, 0, 0, 0}, /* not used */ +/* 17 */{ NULL, 0, 0, 0}, /* not used */ +/* 18 */{ NULL, 0, 0, 0}, /* not used */ +/* 19 */{ NULL, 0, 0, 0}, /* not used */ +/* 20 */{ NULL, 0, 0, 0}, /* not used */ +/* 21 */{ NULL, 0, 0, 0}, /* not used */ +/* 22 */{ NULL, 0, 0, 0}, /* not used */ +/* 23 */{ NULL, 0, 0, 0}, /* not used */ +/* 24 */{ NULL, 0, 0, 0}, /* not used */ +/* 25 */{ NULL, 0, 0, 0}, /* not used */ +/* 26 */{ NULL, 0, 0, 0}, /* not used */ +/* 27 */{ NULL, 0, 0, 0}, /* not used */ +/* 28 */{ NULL, 0, 0, 0}, /* not used */ +/* 29 */{ NULL, 0, 0, 0}, /* not used */ +/* 30 */{ NULL, 0, 0, 0}, /* not used */ +/* 31 */{ NULL, 0, 0, 0}, /* not used */ +#ifdef PFM_PMU_USES_DBR +/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}, +/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)} +#endif +}; +#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) + static int -perfmon_bad_permissions(struct task_struct *task) +check_task_state(struct task_struct *task) { - /* stolen from bad_signal() */ - return (current->session != task->session) - && (current->euid ^ task->suid) && (current->euid ^ task->uid) - && (current->uid ^ task->suid) && (current->uid ^ task->uid); + int ret = 0; +#ifdef CONFIG_SMP + /* We must wait until the state has been completely + * saved. There can be situations where the reader arrives before + * after the task is marked as STOPPED but before pfm_save_regs() + * is completed. + */ + for (;;) { + + task_lock(task); + if (!task_has_cpu(task)) break; + task_unlock(task); + + do { + if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY; + barrier(); + cpu_relax(); + } while (task_has_cpu(task)); + } + task_unlock(task); +#else + if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) { + DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state)); + ret = -EBUSY; + } +#endif + return ret; } asmlinkage int -sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack) +sys_perfmonctl (pid_t pid, int cmd, void *arg, int count, long arg5, long arg6, long arg7, + long arg8, long stack) { - struct pt_regs *regs = (struct pt_regs *) &stack; - struct task_struct *child = current; - int ret = -ESRCH; + struct pt_regs *regs = (struct pt_regs *)&stack; + struct task_struct *task = current; + pfm_context_t *ctx = task->thread.pfm_context; + size_t sz; + int ret = -ESRCH, narg; - /* sanity check: - * - * ensures that we don't do bad things in case the OS - * does not have enough storage to save/restore PMC/PMD + /* + * reject any call if perfmon was disabled at initialization time */ - if (PERFMON_IS_DISABLED()) return -ENOSYS; + if (PFM_IS_DISABLED()) return -ENOSYS; - /* XXX: pid interface is going away in favor of pfm context */ - if (pid != current->pid) { - read_lock(&tasklist_lock); + DBprintk(("cmd=%d idx=%d valid=%d narg=0x%x\n", cmd, PFM_CMD_IDX(cmd), + PFM_CMD_IS_VALID(cmd), PFM_CMD_NARG(cmd))); - child = find_task_by_pid(pid); + if (PFM_CMD_IS_VALID(cmd) == 0) return -EINVAL; - if (!child) goto abort_call; + /* ingore arguments when command has none */ + narg = PFM_CMD_NARG(cmd); + if ((narg == PFM_CMD_ARG_MANY && count == 0) || (narg > 0 && narg != count)) return -EINVAL; - ret = -EPERM; + sz = PFM_CMD_ARG_SIZE(cmd); - if (perfmon_bad_permissions(child)) goto abort_call; + if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT; - /* - * XXX: need to do more checking here + if (PFM_CMD_WRITE_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT; + + if (PFM_CMD_USE_PID(cmd)) { + /* + * XXX: may need to fine tune this one */ - if (child->state != TASK_ZOMBIE && child->state != TASK_STOPPED) { - DBprintk((" warning process %d not in stable state %ld\n", pid, child->state)); + if (pid < 2) return -EPERM; + + if (pid != current->pid) { + + read_lock(&tasklist_lock); + + task = find_task_by_pid(pid); + + if (!task) goto abort_call; + + ret = -EPERM; + + if (pfm_bad_permissions(task)) goto abort_call; + + if (PFM_CMD_CHK(cmd)) { + ret = check_task_state(task); + if (ret != 0) goto abort_call; + } + ctx = task->thread.pfm_context; } + } + + if (PFM_CMD_USE_CTX(cmd)) { + ret = -EINVAL; + if (ctx == NULL) { + DBprintk(("no context for task %d\n", task->pid)); + goto abort_call; + } + ret = -EPERM; + /* + * we only grant access to the context if: + * - the caller is the creator of the context (ctx_owner) + * OR - the context is attached to the caller AND The context IS NOT + * in protected mode + */ + if (ctx->ctx_owner != current && (ctx->ctx_fl_protected || task != current)) { + DBprintk(("context protected, no access for [%d]\n", task->pid)); + goto abort_call; + } } - ret = do_perfmonctl(child, cmd, flags, req, count, regs); + + ret = (*pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func)(task, ctx, arg, count, regs); abort_call: - if (child != current) read_unlock(&tasklist_lock); + if (task != current) read_unlock(&tasklist_lock); return ret; } #if __GNUC__ >= 3 void asmlinkage -pfm_block_on_overflow(void) +pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, + u64 arg6, u64 arg7, long info) #else void asmlinkage -pfm_block_on_overflow(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, + u64 arg6, u64 arg7, long info) #endif { struct thread_struct *th = ¤t->thread; @@ -1323,32 +2314,22 @@ int ret; /* - * NO matter what notify_pid is, - * we clear overflow, won't notify again + * clear the flag, to make sure we won't get here + * again */ - th->pfm_must_block = 0; + th->pfm_ovfl_block_reset = 0; /* * do some sanity checks first */ if (!ctx) { - printk("perfmon: process %d has no PFM context\n", current->pid); - return; - } - if (ctx->ctx_notify_task == 0) { - printk("perfmon: process %d has no task to notify\n", current->pid); + printk("perfmon: [%d] has no PFM context\n", current->pid); return; } - DBprintk((" current=%d task=%d\n", current->pid, ctx->ctx_notify_task->pid)); - - /* should not happen */ - if (CTX_OVFL_NOBLOCK(ctx)) { - printk("perfmon: process %d non-blocking ctx should not be here\n", current->pid); - return; - } + if (CTX_OVFL_NOBLOCK(ctx)) goto non_blocking; - DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid)); + DBprintk(("[%d] before sleeping\n", current->pid)); /* * may go through without blocking on SMP systems @@ -1356,12 +2337,14 @@ */ ret = down_interruptible(&ctx->ctx_restart_sem); - DBprintk((" CPU%d %d after sleep ret=%d\n", smp_processor_id(), current->pid, ret)); + DBprintk(("[%d] after sleeping ret=%d\n", current->pid, ret)); /* * in case of interruption of down() we don't restart anything */ if (ret >= 0) { + +non_blocking: /* we reactivate on context switch */ ctx->ctx_fl_frozen = 0; /* @@ -1369,19 +2352,19 @@ * use the local reference */ - pfm_reset_regs(ctx); + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET); + + ctx->ctx_ovfl_regs[0] = 0UL; /* * Unlock sampling buffer and reset index atomically * XXX: not really needed when blocking */ if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_smpl_buf->psb_hdr->hdr_count = 0; - ctx->ctx_smpl_buf->psb_index = 0; + ctx->ctx_psb->psb_hdr->hdr_count = 0; + ctx->ctx_psb->psb_index = 0; } - DBprintk((" CPU%d %d unfreeze PMU\n", smp_processor_id(), current->pid)); - ia64_set_pmc(0, 0); ia64_srlz_d(); @@ -1390,23 +2373,111 @@ } /* + * This function will record an entry in the sampling if it is not full already. + * Return: + * 0 : buffer is not full (did not BECOME full: still space or was already full) + * 1 : buffer is full (recorded the last entry) + */ +static int +pfm_record_sample(struct task_struct *task, pfm_context_t *ctx, unsigned long ovfl_mask, struct pt_regs *regs) +{ + pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; + unsigned long *e, m, idx; + perfmon_smpl_entry_t *h; + int j; + + +pfm_recorded_samples_count++; + idx = ia64_fetch_and_add(1, &psb->psb_index); + DBprintk(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries)); + + /* + * XXX: there is a small chance that we could run out on index before resetting + * but index is unsigned long, so it will take some time..... + * We use > instead of == because fetch_and_add() is off by one (see below) + * + * This case can happen in non-blocking mode or with multiple processes. + * For non-blocking, we need to reload and continue. + */ + if (idx > psb->psb_entries) return 0; + + /* first entry is really entry 0, not 1 caused by fetch_and_add */ + idx--; + + h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); + + /* + * initialize entry header + */ + h->pid = task->pid; + h->cpu = smp_processor_id(); + h->rate = 0; /* XXX: add the sampling rate used here */ + h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ + h->regs = ovfl_mask; /* which registers overflowed */ + + /* guaranteed to monotonically increase on each cpu */ + h->stamp = pfm_get_stamp(); + h->period = 0UL; /* not yet used */ + + /* position for first pmd */ + e = (unsigned long *)(h+1); + + /* + * selectively store PMDs in increasing index number + */ + m = ctx->ctx_smpl_regs[0]; + for (j=0; m; m >>=1, j++) { + + if ((m & 0x1) == 0) continue; + + if (PMD_IS_COUNTING(j)) { + *e = pfm_read_soft_counter(ctx, j); + /* check if this pmd overflowed as well */ + *e += ovfl_mask & (1UL<psb_hdr->hdr_count); + + DBprintk(("index=%ld entries=%ld hdr_count=%ld\n", + idx, psb->psb_entries, psb->psb_hdr->hdr_count)); + /* + * sampling buffer full ? + */ + if (idx == (psb->psb_entries-1)) { + DBprintk(("sampling buffer full\n")); + /* + * XXX: must reset buffer in blocking mode and lost notified + */ + return 1; + } + return 0; +} + +/* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code * Return: * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ -unsigned long -update_counters (struct task_struct *task, u64 pmc0, struct pt_regs *regs) +static unsigned long +pfm_overflow_handler(struct task_struct *task, u64 pmc0, struct pt_regs *regs) { - unsigned long mask, i, cnum; - struct thread_struct *th; + unsigned long mask; + struct thread_struct *t; pfm_context_t *ctx; - unsigned long bv = 0; + unsigned long old_val; + unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; + int i; int my_cpu = smp_processor_id(); - int ret = 1, buffer_is_full = 0; - int ovfl_has_long_recovery, can_notify, need_reset_pmd16=0; + int ret = 1; struct siginfo si; - /* * It is never safe to access the task for which the overflow interrupt is destinated * using the current variable as the interrupt may occur in the middle of a context switch @@ -1421,233 +2492,151 @@ */ if (task == NULL) { - DBprintk((" owners[%d]=NULL\n", my_cpu)); + DBprintk(("owners[%d]=NULL\n", my_cpu)); return 0x1; } - th = &task->thread; - ctx = th->pfm_context; + t = &task->thread; + ctx = task->thread.pfm_context; + + if (!ctx) { + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", + task->pid); + return 0; + } /* * XXX: debug test * Don't think this could happen given upfront tests */ - if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { - printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", task->pid); + if ((t->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { + printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", + task->pid); return 0x1; } - if (!ctx) { - printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", task->pid); - return 0; - } - /* * sanity test. Should never happen */ - if ((pmc0 & 0x1 )== 0) { - printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", task->pid, pmc0); + if ((pmc0 & 0x1) == 0) { + printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", + task->pid, pmc0); return 0x0; } mask = pmc0 >> PMU_FIRST_COUNTER; - DBprintk(("pmc0=0x%lx pid=%d owner=%d iip=0x%lx, ctx is in %s mode used_pmds=0x%lx used_pmcs=0x%lx\n", - pmc0, task->pid, PMU_OWNER()->pid, regs->cr_iip, - CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK", - ctx->ctx_used_pmds[0], - ctx->ctx_used_pmcs[0])); + DBprintk(("pmc0=0x%lx pid=%d iip=0x%lx, %s" + " mode used_pmds=0x%lx save_pmcs=0x%lx reload_pmcs=0x%lx\n", + pmc0, task->pid, (regs ? regs->cr_iip : 0), + CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", + ctx->ctx_used_pmds[0], + ctx->ctx_saved_pmcs[0], + ctx->ctx_reload_pmcs[0])); /* - * XXX: need to record sample only when an EAR/BTB has overflowed + * First we update the virtual counters */ - if (CTX_HAS_SMPL(ctx)) { - pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; - unsigned long *e, m, idx=0; - perfmon_smpl_entry_t *h; - int j; - - idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk((" recording index=%ld entries=%ld\n", idx, psb->psb_entries)); + for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { + + /* skip pmd which did not overflow */ + if ((mask & 0x1) == 0) continue; + + DBprintk(("PMD[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", + i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val)); /* - * XXX: there is a small chance that we could run out on index before resetting - * but index is unsigned long, so it will take some time..... - * We use > instead of == because fetch_and_add() is off by one (see below) - * - * This case can happen in non-blocking mode or with multiple processes. - * For non-blocking, we need to reload and continue. + * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use + * val to count the number of times we overflowed. Otherwise we would loose the + * current value in the PMD (which can be >0). So to make sure we don't loose + * the residual counts we set val to contain full 64bits value of the counter. */ - if (idx > psb->psb_entries) { - buffer_is_full = 1; - goto reload_pmds; - } - - /* first entry is really entry 0, not 1 caused by fetch_and_add */ - idx--; + old_val = ctx->ctx_soft_pmds[i].val; + ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i); - h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); - h->pid = task->pid; - h->cpu = my_cpu; - h->rate = 0; - h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ - h->regs = mask; /* which registers overflowed */ + DBprintk(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", + i, ctx->ctx_soft_pmds[i].val, old_val, + ia64_get_pmd(i) & pmu_conf.perf_ovfl_val)); - /* guaranteed to monotonically increase on each cpu */ - h->stamp = perfmon_get_stamp(); - - e = (unsigned long *)(h+1); - - /* - * selectively store PMDs in increasing index number - */ - for (j=0, m = ctx->ctx_smpl_regs; m; m >>=1, j++) { - if (m & 0x1) { - if (PMD_IS_COUNTER(j)) - *e = ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val - + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val); - else { - *e = ia64_get_pmd(j); /* slow */ - } - DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); - e++; - } - } /* - * make the new entry visible to user, needs to be atomic + * now that we have extracted the hardware counter, we can clear it to ensure + * that a subsequent PFM_READ_PMDS will not include it again. */ - ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); + ia64_set_pmd(i, 0UL); - DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); - /* - * sampling buffer full ? + /* + * check for overflow condition */ - if (idx == (psb->psb_entries-1)) { - /* - * will cause notification, cannot be 0 - */ - bv = mask << PMU_FIRST_COUNTER; + if (old_val > ctx->ctx_soft_pmds[i].val) { - buffer_is_full = 1; + ovfl_pmds |= 1UL << i; - DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv)); + DBprintk(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds)); - /* - * we do not reload here, when context is blocking - */ - if (!CTX_OVFL_NOBLOCK(ctx)) goto no_reload; - - /* - * here, we have a full buffer but we are in non-blocking mode - * so we need to reload overflowed PMDs with sampling reset values - * and restart right away. - */ + if (PMC_OVFL_NOTIFY(ctx, i)) { + ovfl_notify |= 1UL << i; + } } - /* FALL THROUGH */ } -reload_pmds: - - /* - * in the case of a non-blocking context, we reload - * with the ovfl_rval when no user notification is taking place (short recovery) - * otherwise when the buffer is full which requires user interaction) then we use - * smpl_rval which is the long_recovery path (disturbance introduce by user execution). - * - * XXX: implies that when buffer is full then there is always notification. - */ - ovfl_has_long_recovery = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; /* - * XXX: CTX_HAS_SMPL() should really be something like CTX_HAS_SMPL() and is activated,i.e., - * one of the PMC is configured for EAR/BTB. + * check for sampling buffer * - * When sampling, we can only notify when the sampling buffer is full. + * if present, record sample. We propagate notification ONLY when buffer + * becomes full. */ - can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_task; - - DBprintk((" ovfl_has_long_recovery=%d can_notify=%d\n", ovfl_has_long_recovery, can_notify)); - - for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) { - - if ((mask & 0x1) == 0) continue; - - DBprintk((" PMD[%ld] overflowed pmd=0x%lx pmod.val=0x%lx\n", cnum, ia64_get_pmd(cnum), ctx->ctx_pmds[i].val)); - - /* - * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use - * val to count the number of times we overflowed. Otherwise we would loose the current value - * in the PMD (which can be >0). So to make sure we don't loose - * the residual counts we set val to contain full 64bits value of the counter. - * - * XXX: is this needed for EARS/BTB ? - */ - ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val - + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val); /* slow */ - - DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); - - if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) { - DBprintk((" CPU%d should notify task %p with signal %d\n", my_cpu, ctx->ctx_notify_task, ctx->ctx_notify_sig)); - bv |= 1 << i; - } else { - DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum)); + if(CTX_HAS_SMPL(ctx)) { + ret = pfm_record_sample(task, ctx, ovfl_pmds, regs); + if (ret == 1) { /* - * In case no notification is requested, we reload the reset value right away - * otherwise we wait until the notify_pid process has been called and has - * has finished processing data. Check out pfm_overflow_notify() + * Sampling buffer became full + * If no notication was requested, then we reset buffer index + * and reset registers (done below) and resume. + * If notification requested, then defer reset until pfm_restart() */ - - /* writes to upper part are ignored, so this is safe */ - if (ovfl_has_long_recovery) { - DBprintk((" CPU%d PMD[%ld] reload with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); - ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); - } else { - DBprintk((" CPU%d PMD[%ld] reload with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); - ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval); + if (ovfl_notify == 0UL) { + ctx->ctx_psb->psb_hdr->hdr_count = 0UL; + ctx->ctx_psb->psb_index = 0UL; } + } else { + /* + * sample recorded in buffer, no need to notify user + */ + ovfl_notify = 0UL; } - if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1; } - /* - * In case of BTB overflow we need to reset the BTB index. - */ - if (need_reset_pmd16) { - DBprintk(("reset PMD16\n")); - ia64_set_pmd(16, 0); - } - -no_reload: /* - * some counters overflowed, but they did not require - * user notification, so after having reloaded them above - * we simply restart + * No overflow requiring a user level notification */ - if (!bv) return 0x0; + if (ovfl_notify == 0UL) { + pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET); + return 0x0; + } - ctx->ctx_ovfl_regs = bv; /* keep track of what to reset when unblocking */ - /* - * Now we know that: - * - we have some counters which overflowed (contains in bv) - * - someone has asked to be notified on overflow. + /* + * keep track of what to reset when unblocking */ + ctx->ctx_ovfl_regs[0] = ovfl_pmds; - /* - * If the notification task is still present, then notify_task is non - * null. It is clean by that task if it ever exits before we do. + * we have come to this point because there was an overflow and that notification + * was requested. The notify_task may have disappeared, in which case notify_task + * is NULL. */ - if (ctx->ctx_notify_task) { si.si_errno = 0; si.si_addr = NULL; si.si_pid = task->pid; /* who is sending */ - si.si_signo = ctx->ctx_notify_sig; /* is SIGPROF */ - si.si_code = PROF_OVFL; /* goes to user */ - si.si_pfm_ovfl = bv; - - + si.si_signo = SIGPROF; + si.si_code = PROF_OVFL; /* indicates a perfmon SIGPROF signal */ + /* + * Shift the bitvector such that the user sees bit 4 for PMD4 and so on. + * We only use smpl_ovfl[0] for now. It should be fine for quite a while + * until we have more than 61 PMD available. + */ + si.si_pfm_ovfl[0] = ovfl_notify; /* * when the target of the signal is not ourself, we have to be more @@ -1659,15 +2648,29 @@ if (ctx->ctx_notify_task != current) { /* * grab the notification lock for this task + * This guarantees that the sequence: test + send_signal + * is atomic with regards to the ctx_notify_task field. + * + * We need a spinlock and not just an atomic variable for this. + * */ - spin_lock(&ctx->ctx_notify_lock); + spin_lock(&ctx->ctx_lock); /* * now notify_task cannot be modified until we're done * if NULL, they it got modified while we were in the handler */ if (ctx->ctx_notify_task == NULL) { - spin_unlock(&ctx->ctx_notify_lock); + + spin_unlock(&ctx->ctx_lock); + + /* + * If we've lost the notified task, then we will run + * to completion wbut keep the PMU frozen. Results + * will be incorrect anyway. We do not kill task + * to leave it possible to attach perfmon context + * to already running task. + */ goto lost_notify; } /* @@ -1681,20 +2684,23 @@ * necessarily go to the signal handler (if any) when it goes back to * user mode. */ - DBprintk((" %d sending %d notification to %d\n", task->pid, si.si_signo, ctx->ctx_notify_task->pid)); + DBprintk(("[%d] sending notification to [%d]\n", + task->pid, ctx->ctx_notify_task->pid)); /* * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock */ - ret = send_sig_info(ctx->ctx_notify_sig, &si, ctx->ctx_notify_task); - if (ret != 0) printk(" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_task->pid, ret); + ret = send_sig_info(SIGPROF, &si, ctx->ctx_notify_task); + if (ret != 0) + printk("send_sig_info(process %d, SIGPROF)=%d\n", + ctx->ctx_notify_task->pid, ret); /* * now undo the protections in order */ if (ctx->ctx_notify_task != current) { read_unlock(&tasklist_lock); - spin_unlock(&ctx->ctx_notify_lock); + spin_unlock(&ctx->ctx_lock); } /* @@ -1711,35 +2717,41 @@ * before, changing it to NULL will still maintain this invariant. * Of course, when it is equal to current it cannot change at this point. */ - if (!CTX_OVFL_NOBLOCK(ctx) && ctx->ctx_notify_task != current) { - th->pfm_must_block = 1; /* will cause blocking */ + DBprintk(("block=%d notify [%d] current [%d]\n", + ctx->ctx_fl_block, + ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, + current->pid )); + + if (!CTX_OVFL_NOBLOCK(ctx) && ctx->ctx_notify_task != task) { + t->pfm_ovfl_block_reset = 1; /* will cause blocking */ } } else { -lost_notify: - DBprintk((" notification task has disappeared !\n")); +lost_notify: /* XXX: more to do here, to convert to non-blocking (reset values) */ + + DBprintk(("notification task has disappeared !\n")); /* - * for a non-blocking context, we make sure we do not fall into the pfm_overflow_notify() - * trap. Also in the case of a blocking context with lost notify process, then we do not - * want to block either (even though it is interruptible). In this case, the PMU will be kept - * frozen and the process will run to completion without monitoring enabled. + * for a non-blocking context, we make sure we do not fall into the + * pfm_overflow_notify() trap. Also in the case of a blocking context with lost + * notify process, then we do not want to block either (even though it is + * interruptible). In this case, the PMU will be kept frozen and the process will + * run to completion without monitoring enabled. * * Of course, we cannot loose notify process when self-monitoring. */ - th->pfm_must_block = 0; + t->pfm_ovfl_block_reset = 0; } /* - * if we block, we keep the PMU frozen. If non-blocking we restart. - * in the case of non-blocking were the notify process is lost, we also - * restart. + * If notification was successful, then we rely on the pfm_restart() + * call to unfreeze and reset (in both blocking or non-blocking mode). + * + * If notification failed, then we will keep the PMU frozen and run + * the task to completion */ - if (!CTX_OVFL_NOBLOCK(ctx)) - ctx->ctx_fl_frozen = 1; - else - ctx->ctx_fl_frozen = 0; + ctx->ctx_fl_frozen = 1; - DBprintk((" reload pmc0=0x%x must_block=%ld\n", - ctx->ctx_fl_frozen ? 0x1 : 0x0, th->pfm_must_block)); + DBprintk(("reload pmc0=0x%x must_block=%ld\n", + ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset)); return ctx->ctx_fl_frozen ? 0x1 : 0x0; } @@ -1748,29 +2760,40 @@ perfmon_interrupt (int irq, void *arg, struct pt_regs *regs) { u64 pmc0; - struct task_struct *ta; + struct task_struct *task; - pmc0 = ia64_get_pmc(0); /* slow */ + pfm_ovfl_intr_count++; + + /* + * srlz.d done before arriving here + * + * This is slow + */ + pmc0 = ia64_get_pmc(0); /* * if we have some pending bits set * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 */ - if ((pmc0 & ~0x1) && (ta=PMU_OWNER())) { + if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) { - /* assumes, PMC[0].fr = 1 at this point */ - pmc0 = update_counters(ta, pmc0, regs); - - /* - * if pmu_frozen = 0 - * pmc0 = 0 and we resume monitoring right away - * else - * pmc0 = 0x1 frozen but all pending bits are cleared + /* + * assumes, PMC[0].fr = 1 at this point + * + * XXX: change protype to pass &pmc0 */ - ia64_set_pmc(0, pmc0); - ia64_srlz_d(); + pmc0 = pfm_overflow_handler(task, pmc0, regs); + + /* we never explicitely freeze PMU here */ + if (pmc0 == 0) { + ia64_set_pmc(0, 0); + ia64_srlz_d(); + } } else { - printk("perfmon: Spurious PMU overflow interrupt: pmc0=0x%lx owner=%p\n", pmc0, (void *)PMU_OWNER()); + pfm_spurious_ovfl_intr_count++; + + DBprintk(("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", + smp_processor_id(), pmc0, (void *)PMU_OWNER())); } } @@ -1778,14 +2801,39 @@ static int perfmon_proc_info(char *page) { +#ifdef CONFIG_SMP +#define cpu_is_online(i) (cpu_online_map & (1UL << i)) +#else +#define cpu_is_online(i) 1 +#endif char *p = page; u64 pmc0 = ia64_get_pmc(0); int i; - p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", smp_processor_id(), pmc0, pfm_debug ? "On" : "Off"); - p += sprintf(p, "proc_sessions=%lu sys_sessions=%lu\n", - pfs_info.pfs_proc_sessions, - pfs_info.pfs_sys_session); + p += sprintf(p, "perfmon enabled: %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes"); + + p += sprintf(p, "monitors_pmcs0]=0x%lx\n", pmu_conf.monitor_pmcs[0]); + p += sprintf(p, "counter_pmcds[0]=0x%lx\n", pmu_conf.counter_pmds[0]); + p += sprintf(p, "overflow interrupts=%lu\n", pfm_ovfl_intr_count); + p += sprintf(p, "spurious overflow interrupts=%lu\n", pfm_spurious_ovfl_intr_count); + p += sprintf(p, "recorded samples=%lu\n", pfm_recorded_samples_count); + + p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", + smp_processor_id(), pmc0, pfm_debug_mode ? "On" : "Off"); + +#ifdef CONFIG_SMP + p += sprintf(p, "CPU%d cpu_data.pfm_syst_wide=%d cpu_data.dcr_pp=%d\n", + smp_processor_id(), local_cpu_data->pfm_syst_wide, local_cpu_data->pfm_dcr_pp); +#endif + + LOCK_PFS(); + p += sprintf(p, "proc_sessions=%lu\nsys_sessions=%lu\nsys_use_dbregs=%lu\nptrace_use_dbregs=%lu\n", + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_sys_use_dbregs, + pfm_sessions.pfs_ptrace_use_dbregs); + + UNLOCK_PFS(); for(i=0; i < NR_CPUS; i++) { if (cpu_is_online(i)) { @@ -1794,10 +2842,11 @@ pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); } } + return p - page; } -/* for debug only */ +/* /proc interface, for debug only */ static int perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1814,153 +2863,90 @@ return len; } -static struct irqaction perfmon_irqaction = { - handler: perfmon_interrupt, - flags: SA_INTERRUPT, - name: "perfmon" -}; - -void __init -perfmon_init (void) +#ifdef CONFIG_SMP +void +pfm_syst_wide_update_task(struct task_struct *task, int mode) { - pal_perf_mon_info_u_t pm_info; - s64 status; + struct pt_regs *regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET); - register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + regs--; - ia64_set_pmv(IA64_PERFMON_VECTOR); - ia64_srlz_d(); - - pmu_conf.pfm_is_disabled = 1; + /* + * propagate the value of the dcr_pp bit to the psr + */ + ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0; +} +#endif - printk("perfmon: version %s (sampling format v%d)\n", PFM_VERSION, PFM_SMPL_HDR_VERSION); - printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR); - if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) { - printk("perfmon: PAL call failed (%ld)\n", status); - return; - } - pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; - pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; - pmu_conf.num_pmcs = find_num_pm_regs(pmu_conf.impl_regs); - pmu_conf.num_pmds = find_num_pm_regs(&pmu_conf.impl_regs[4]); +void +pfm_save_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + u64 psr; - printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val); - printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds); + ctx = task->thread.pfm_context; - /* sanity check */ - if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { - printk(KERN_ERR "perfmon: ERROR not enough PMC/PMD storage in kernel, perfmon is DISABLED\n"); - return; /* no need to continue anyway */ - } - /* we are all set */ - pmu_conf.pfm_is_disabled = 0; /* - * Insert the tasklet in the list. - * It is still disabled at this point, so it won't run - printk(__FUNCTION__" tasklet is %p state=%d, count=%d\n", &perfmon_tasklet, perfmon_tasklet.state, perfmon_tasklet.count); + * save current PSR: needed because we modify it */ + __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); /* - * for now here for debug purposes + * stop monitoring: + * This is the last instruction which can generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level */ - perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); -} + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + + ctx->ctx_saved_psr = psr; + + //ctx->ctx_last_cpu = smp_processor_id(); -void -perfmon_init_percpu (void) -{ - ia64_set_pmv(IA64_PERFMON_VECTOR); - ia64_srlz_d(); } -void -pfm_save_regs (struct task_struct *ta) +static void +pfm_lazy_save_regs (struct task_struct *task) { - struct task_struct *owner; pfm_context_t *ctx; struct thread_struct *t; - u64 pmc0, psr; unsigned long mask; int i; - t = &ta->thread; - ctx = ta->thread.pfm_context; + DBprintk(("on [%d] by [%d]\n", task->pid, current->pid)); - /* - * We must make sure that we don't loose any potential overflow - * interrupt while saving PMU context. In this code, external - * interrupts are always enabled. - */ + t = &task->thread; + ctx = task->thread.pfm_context; - /* - * save current PSR: needed because we modify it +#ifdef CONFIG_SMP + /* + * announce we are saving this PMU state + * This will cause other CPU, to wait until we're done + * before using the context.h + * + * must be an atomic operation */ - __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); + atomic_set(&ctx->ctx_saving_in_progress, 1); - /* - * stop monitoring: - * This is the only way to stop monitoring without destroying overflow - * information in PMC[0]. - * This is the last instruction which can cause overflow when monitoring - * in kernel. - * By now, we could still have an overflow interrupt in-flight. - */ - __asm__ __volatile__ ("rsm psr.up|psr.pp;;"::: "memory"); + /* + * if owner is NULL, it means that the other CPU won the race + * and the IPI has caused the context to be saved in pfm_handle_fectch_regs() + * instead of here. We have nothing to do + * + * note that this is safe, because the other CPU NEVER modifies saving_in_progress. + */ + if (PMU_OWNER() == NULL) goto do_nothing; +#endif /* - * Mark the PMU as not owned - * This will cause the interrupt handler to do nothing in case an overflow - * interrupt was in-flight - * This also guarantees that pmc0 will contain the final state - * It virtually gives us full control over overflow processing from that point - * on. - * It must be an atomic operation. + * do not own the PMU */ - owner = PMU_OWNER(); SET_PMU_OWNER(NULL); - /* - * read current overflow status: - * - * we are guaranteed to read the final stable state - */ ia64_srlz_d(); - pmc0 = ia64_get_pmc(0); /* slow */ - - /* - * freeze PMU: - * - * This destroys the overflow information. This is required to make sure - * next process does not start with monitoring on if not requested - */ - ia64_set_pmc(0, 1); - - /* - * Check for overflow bits and proceed manually if needed - * - * It is safe to call the interrupt handler now because it does - * not try to block the task right away. Instead it will set a - * flag and let the task proceed. The blocking will only occur - * next time the task exits from the kernel. - */ - if (pmc0 & ~0x1) { - update_counters(owner, pmc0, NULL); - /* we will save the updated version of pmc0 */ - } - /* - * restore PSR for context switch to save - */ - __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); - - /* - * we do not save registers if we can do lazy - */ - if (PFM_CAN_DO_LAZY()) { - SET_PMU_OWNER(owner); - return; - } /* * XXX needs further optimization. @@ -1970,30 +2956,75 @@ for (i=0; mask; i++, mask>>=1) { if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } - - /* skip PMC[0], we handle it separately */ - mask = ctx->ctx_used_pmcs[0]>>1; - for (i=1; mask; i++, mask>>=1) { + /* + * XXX: simplify to pmc0 only + */ + mask = ctx->ctx_saved_pmcs[0]; + for (i=0; mask; i++, mask>>=1) { if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } + + /* not owned by this CPU */ + atomic_set(&ctx->ctx_last_cpu, -1); + +#ifdef CONFIG_SMP +do_nothing: +#endif /* - * Throughout this code we could have gotten an overflow interrupt. It is transformed - * into a spurious interrupt as soon as we give up pmu ownership. + * declare we are done saving this context + * + * must be an atomic operation */ + atomic_set(&ctx->ctx_saving_in_progress,0); + } -static void -pfm_lazy_save_regs (struct task_struct *ta) +#ifdef CONFIG_SMP +/* + * Handles request coming from other CPUs + */ +static void +pfm_handle_fetch_regs(void *info) { - pfm_context_t *ctx; + pfm_smp_ipi_arg_t *arg = info; struct thread_struct *t; + pfm_context_t *ctx; unsigned long mask; int i; - DBprintk((" on [%d] by [%d]\n", ta->pid, current->pid)); + ctx = arg->task->thread.pfm_context; + t = &arg->task->thread; + + DBprintk(("task=%d owner=%d saving=%d\n", + arg->task->pid, + PMU_OWNER() ? PMU_OWNER()->pid: -1, + atomic_read(&ctx->ctx_saving_in_progress))); + + /* must wait if saving was interrupted */ + if (atomic_read(&ctx->ctx_saving_in_progress)) { + arg->retval = 1; + return; + } + + /* can proceed, done with context */ + if (PMU_OWNER() != arg->task) { + arg->retval = 0; + return; + } + + DBprintk(("saving state for [%d] save_pmcs=0x%lx all_pmcs=0x%lx used_pmds=0x%lx\n", + arg->task->pid, + ctx->ctx_saved_pmcs[0], + ctx->ctx_reload_pmcs[0], + ctx->ctx_used_pmds[0])); + + /* + * XXX: will be replaced with pure assembly call + */ + SET_PMU_OWNER(NULL); + + ia64_srlz_d(); - t = &ta->thread; - ctx = ta->thread.pfm_context; /* * XXX needs further optimization. * Also must take holes into account @@ -2003,84 +3034,295 @@ if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } - /* skip PMC[0], we handle it separately */ - mask = ctx->ctx_used_pmcs[0]>>1; - for (i=1; mask; i++, mask>>=1) { + mask = ctx->ctx_saved_pmcs[0]; + for (i=0; mask; i++, mask>>=1) { if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } - SET_PMU_OWNER(NULL); + /* not owned by this CPU */ + atomic_set(&ctx->ctx_last_cpu, -1); + + /* can proceed */ + arg->retval = 0; +} + +/* + * Function call to fetch PMU state from another CPU identified by 'cpu'. + * If the context is being saved on the remote CPU, then we busy wait until + * the saving is done and then we return. In this case, non IPI is sent. + * Otherwise, we send an IPI to the remote CPU, potentially interrupting + * pfm_lazy_save_regs() over there. + * + * If the retval==1, then it means that we interrupted remote save and that we must + * wait until the saving is over before proceeding. + * Otherwise, we did the saving on the remote CPU, and it was done by the time we got there. + * in either case, we can proceed. + */ +static void +pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx) +{ + pfm_smp_ipi_arg_t arg; + int ret; + + arg.task = task; + arg.retval = -1; + + if (atomic_read(&ctx->ctx_saving_in_progress)) { + DBprintk(("no IPI, must wait for [%d] to be saved on [%d]\n", task->pid, cpu)); + + /* busy wait */ + while (atomic_read(&ctx->ctx_saving_in_progress)); + return; + } + DBprintk(("calling CPU %d from CPU %d\n", cpu, smp_processor_id())); + + if (cpu == -1) { + printk("refusing to use -1 for [%d]\n", task->pid); + return; + } + + /* will send IPI to other CPU and wait for completion of remote call */ + if ((ret=smp_call_function_single(cpu, pfm_handle_fetch_regs, &arg, 0, 1))) { + printk("perfmon: remote CPU call from %d to %d error %d\n", smp_processor_id(), cpu, ret); + return; + } + /* + * we must wait until saving is over on the other CPU + * This is the case, where we interrupted the saving which started just at the time we sent the + * IPI. + */ + if (arg.retval == 1) { + DBprintk(("must wait for [%d] to be saved on [%d]\n", task->pid, cpu)); + while (atomic_read(&ctx->ctx_saving_in_progress)); + DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu)); + } } +#endif /* CONFIG_SMP */ void -pfm_load_regs (struct task_struct *ta) +pfm_load_regs (struct task_struct *task) { - struct thread_struct *t = &ta->thread; - pfm_context_t *ctx = ta->thread.pfm_context; + struct thread_struct *t; + pfm_context_t *ctx; struct task_struct *owner; unsigned long mask; + u64 psr; int i; +#ifdef CONFIG_SMP + int cpu; +#endif owner = PMU_OWNER(); - if (owner == ta) goto skip_restore; + ctx = task->thread.pfm_context; + + /* + * if we were the last user, then nothing to do except restore psr + */ + if (owner == task) { + if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) + DBprintk(("invalid last_cpu=%d for [%d]\n", + atomic_read(&ctx->ctx_last_cpu), task->pid)); + + psr = ctx->ctx_saved_psr; + __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + + return; + } + DBprintk(("load_regs: must reload for [%d] owner=%d\n", + task->pid, owner ? owner->pid : -1 )); + /* + * someone else is still using the PMU, first push it out and + * then we'll be able to install our stuff ! + */ if (owner) pfm_lazy_save_regs(owner); - SET_PMU_OWNER(ta); +#ifdef CONFIG_SMP + /* + * check if context on another CPU (-1 means saved) + * We MUST use the variable, as last_cpu may change behind our + * back. If it changes to -1 (not on a CPU anymore), then in cpu + * we have the last CPU the context was on. We may be sending the + * IPI for nothing, but we have no way of verifying this. + */ + cpu = atomic_read(&ctx->ctx_last_cpu); + if (cpu != -1) { + pfm_fetch_regs(cpu, task, ctx); + } +#endif + t = &task->thread; + /* + * XXX: will be replaced by assembly routine + * We clear all unused PMDs to avoid leaking information + */ mask = ctx->ctx_used_pmds[0]; for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmd(i, t->pmd[i]); + if (mask & 0x1) + ia64_set_pmd(i, t->pmd[i]); + else + ia64_set_pmd(i, 0UL); } + /* XXX: will need to clear all unused pmd, for security */ - /* skip PMC[0] to avoid side effects */ - mask = ctx->ctx_used_pmcs[0]>>1; + /* + * skip pmc[0] to avoid side-effects, + * all PMCs are systematically reloaded, unsued get default value + * to avoid picking up stale configuration + */ + mask = ctx->ctx_reload_pmcs[0]>>1; for (i=1; mask; i++, mask>>=1) { if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); } -skip_restore: + + /* + * restore debug registers when used for range restrictions. + * We must restore the unused registers to avoid picking up + * stale information. + */ + mask = ctx->ctx_used_ibrs[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) + ia64_set_ibr(i, t->ibr[i]); + else + ia64_set_ibr(i, 0UL); + } + + mask = ctx->ctx_used_dbrs[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) + ia64_set_dbr(i, t->dbr[i]); + else + ia64_set_dbr(i, 0UL); + } + + if (t->pmc[0] & ~0x1) { + ia64_srlz_d(); + pfm_overflow_handler(task, t->pmc[0], NULL); + } + + /* + * fl_frozen==1 when we are in blocking mode waiting for restart + */ + if (ctx->ctx_fl_frozen == 0) { + ia64_set_pmc(0, 0); + ia64_srlz_d(); + } + atomic_set(&ctx->ctx_last_cpu, smp_processor_id()); + + SET_PMU_OWNER(task); + + /* + * restore the psr we changed in pfm_save_regs() + */ + psr = ctx->ctx_saved_psr; + __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + +} + +/* + * XXX: make this routine able to work with non current context + */ +static void +ia64_reset_pmu(struct task_struct *task) +{ + struct thread_struct *t = &task->thread; + pfm_context_t *ctx = t->pfm_context; + unsigned long mask; + int i; + + if (task != current) { + printk("perfmon: invalid task in ia64_reset_pmu()\n"); + return; + } + + /* Let's make sure the PMU is frozen */ + ia64_set_pmc(0,1); + + /* + * install reset values for PMC. We skip PMC0 (done above) + * XX: good up to 64 PMCS + */ + mask = pmu_conf.impl_regs[0] >> 1; + for(i=1; mask; mask>>=1, i++) { + if (mask & 0x1) { + ia64_set_pmc(i, reset_pmcs[i]); + /* + * When restoring context, we must restore ALL pmcs, even the ones + * that the task does not use to avoid leaks and possibly corruption + * of the sesion because of configuration conflicts. So here, we + * initializaed the table used in the context switch restore routine. + */ + t->pmc[i] = reset_pmcs[i]; + DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i])); + + } + } + /* + * clear reset values for PMD. + * XX: good up to 64 PMDS. Suppose that zero is a valid value. + */ + mask = pmu_conf.impl_regs[4]; + for(i=0; mask; mask>>=1, i++) { + if (mask & 0x1) ia64_set_pmd(i, 0UL); + } + /* - * unfreeze only when possible + * On context switched restore, we must restore ALL pmc even + * when they are not actively used by the task. In UP, the incoming process + * may otherwise pick up left over PMC state from the previous process. + * As opposed to PMD, stale PMC can cause harm to the incoming + * process because they may change what is being measured. + * Therefore, we must systematically reinstall the entire + * PMC state. In SMP, the same thing is possible on the + * same CPU but also on between 2 CPUs. + * + * There is unfortunately no easy way to avoid this problem + * on either UP or SMP. This definitively slows down the + * pfm_load_regs(). */ - if (ctx->ctx_fl_frozen == 0) { - ia64_set_pmc(0, 0); - ia64_srlz_d(); - /* place where we potentially (kernel level) start monitoring again */ - } -} + + /* + * We must include all the PMC in this mask to make sure we don't + * see any side effect of the stale state, such as opcode matching + * or range restrictions, for instance. + */ + ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0]; + /* + * useful in case of re-enable after disable + */ + ctx->ctx_used_pmds[0] = 0UL; + ctx->ctx_used_ibrs[0] = 0UL; + ctx->ctx_used_dbrs[0] = 0UL; + + ia64_srlz_d(); +} /* * This function is called when a thread exits (from exit_thread()). * This is a simplified pfm_save_regs() that simply flushes the current * register state into the save area taking into account any pending - * overflow. This time no notification is sent because the taks is dying + * overflow. This time no notification is sent because the task is dying * anyway. The inline processing of overflows avoids loosing some counts. * The PMU is frozen on exit from this call and is to never be reenabled * again for this task. + * */ void -pfm_flush_regs (struct task_struct *ta) +pfm_flush_regs (struct task_struct *task) { pfm_context_t *ctx; - u64 pmc0, psr, mask; - int i,j; + u64 pmc0; + unsigned long mask, mask2, val; + int i; - if (ta == NULL) { - panic(__FUNCTION__" task is NULL\n"); - } - ctx = ta->thread.pfm_context; - if (ctx == NULL) { - panic(__FUNCTION__" no PFM ctx is NULL\n"); - } - /* - * We must make sure that we don't loose any potential overflow - * interrupt while saving PMU context. In this code, external - * interrupts are always enabled. - */ + ctx = task->thread.pfm_context; - /* - * save current PSR: needed because we modify it + if (ctx == NULL) return; + + /* + * that's it if context already disabled */ - __asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory"); + if (ctx->ctx_flags.state == PFM_CTX_DISABLED) return; /* * stop monitoring: @@ -2090,7 +3332,27 @@ * in kernel. * By now, we could still have an overflow interrupt in-flight. */ - __asm__ __volatile__ ("rsm psr.up;;"::: "memory"); + if (ctx->ctx_fl_system) { + + __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); + + /* disable dcr pp */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + +#ifdef CONFIG_SMP + local_cpu_data->pfm_syst_wide = 0; + local_cpu_data->pfm_dcr_pp = 0; +#else + pfm_tasklist_toggle_pp(0); +#endif + + } else { + + __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + + /* no more save/restore on ctxsw */ + current->thread.flags &= ~IA64_THREAD_PM_VALID; + } /* * Mark the PMU as not owned @@ -2121,85 +3383,68 @@ ia64_srlz_d(); /* - * restore PSR for context switch to save + * We don't need to restore psr, because we are on our way out anyway */ - __asm__ __volatile__ ("mov psr.l=%0;;srlz.i;"::"r"(psr): "memory"); /* * This loop flushes the PMD into the PFM context. - * IT also processes overflow inline. + * It also processes overflow inline. * * IMPORTANT: No notification is sent at this point as the process is dying. * The implicit notification will come from a SIGCHILD or a return from a * waitpid(). * - * XXX: must take holes into account */ - mask = pmc0 >> PMU_FIRST_COUNTER; - for (i=0,j=PMU_FIRST_COUNTER; i< pmu_conf.max_counters; i++,j++) { - - /* collect latest results */ - ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val; - - /* - * now everything is in ctx_pmds[] and we need - * to clear the saved context from save_regs() such that - * pfm_read_pmds() gets the correct value - */ - ta->thread.pmd[j] = 0; - /* take care of overflow inline */ - if (mask & 0x1) { - ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; - DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n", - j, ia64_get_pmd(j), ctx->ctx_pmds[i].val)); - } - mask >>=1; - } -} + if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) + printk("perfmon: [%d] last_cpu=%d\n", task->pid, atomic_read(&ctx->ctx_last_cpu)); -/* - * XXX: this routine is not very portable for PMCs - * XXX: make this routine able to work with non current context - */ -static void -ia64_reset_pmu(void) -{ - int i; + mask = pmc0 >> PMU_FIRST_COUNTER; + mask2 = ctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER; - /* PMU is frozen, no pending overflow bits */ - ia64_set_pmc(0,1); + for (i = PMU_FIRST_COUNTER; mask2; i++, mask>>=1, mask2>>=1) { - /* extra overflow bits + counter configs cleared */ - for(i=1; i< PMU_FIRST_COUNTER + pmu_conf.max_counters ; i++) { - ia64_set_pmc(i,0); - } + /* skip non used pmds */ + if ((mask2 & 0x1) == 0) continue; - /* opcode matcher set to all 1s */ - ia64_set_pmc(8,~0); - ia64_set_pmc(9,~0); + val = ia64_get_pmd(i); - /* I-EAR config cleared, plm=0 */ - ia64_set_pmc(10,0); + if (PMD_IS_COUNTING(i)) { - /* D-EAR config cleared, PMC[11].pt must be 1 */ - ia64_set_pmc(11,1 << 28); + DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val)); - /* BTB config. plm=0 */ - ia64_set_pmc(12,0); + /* collect latest results */ + ctx->ctx_soft_pmds[i].val += val & pmu_conf.perf_ovfl_val; - /* Instruction address range, PMC[13].ta must be 1 */ - ia64_set_pmc(13,1); + /* + * now everything is in ctx_soft_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + task->thread.pmd[i] = 0; - /* clears all PMD registers */ - for(i=0;i< pmu_conf.num_pmds; i++) { - if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); + /* take care of overflow inline */ + if (mask & 0x1) { + ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; + DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n", + task->pid, i, ctx->ctx_soft_pmds[i].val)); + } + } else { + DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val)); + /* not a counter, just save value as is */ + task->thread.pmd[i] = val; + } } - ia64_srlz_d(); + /* + * indicates that context has been saved + */ + atomic_set(&ctx->ctx_last_cpu, -1); + } + /* - * task is the newly created task + * task is the newly created task, pt_regs for new child */ int pfm_inherit(struct task_struct *task, struct pt_regs *regs) @@ -2207,25 +3452,29 @@ pfm_context_t *ctx = current->thread.pfm_context; pfm_context_t *nctx; struct thread_struct *th = &task->thread; - int i, cnum; + unsigned long m; + int i; /* - * bypass completely for system wide + * make sure child cannot mess up the monitoring session */ - if (pfs_info.pfs_sys_session) { - DBprintk((" enabling psr.pp for %d\n", task->pid)); - ia64_psr(regs)->pp = pfs_info.pfs_pp; - return 0; - } + ia64_psr(regs)->sp = 1; + DBprintk(("enabling psr.sp for [%d]\n", task->pid)); + + /* + * remove any sampling buffer mapping from child user + * address space. Must be done for all cases of inheritance. + */ + if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task); /* * takes care of easiest case first */ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { - DBprintk((" removing PFM context for %d\n", task->pid)); + DBprintk(("removing PFM context for [%d]\n", task->pid)); task->thread.pfm_context = NULL; - task->thread.pfm_must_block = 0; - atomic_set(&task->thread.pfm_notifiers_check, 0); + task->thread.pfm_ovfl_block_reset = 0; + /* copy_thread() clears IA64_THREAD_PM_VALID */ return 0; } @@ -2235,45 +3484,81 @@ /* copy content */ *nctx = *ctx; + if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; - atomic_set(&task->thread.pfm_notifiers_check, 0); - DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid)); - pfs_info.pfs_proc_sessions++; + atomic_set(&nctx->ctx_last_cpu, -1); + + /* + * task is not yet visible in the tasklist, so we do + * not need to lock the newly created context. + * However, we must grab the tasklist_lock to ensure + * that the ctx_owner or ctx_notify_task do not disappear + * while we increment their check counters. + */ + read_lock(&tasklist_lock); + + if (nctx->ctx_notify_task) + atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check); + + if (nctx->ctx_owner) + atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check); + + read_unlock(&tasklist_lock); + + DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid)); + + LOCK_PFS(); + pfm_sessions.pfs_task_sessions++; + UNLOCK_PFS(); } /* initialize counters in new context */ - for(i=0, cnum= PMU_FIRST_COUNTER; i < pmu_conf.max_counters; cnum++, i++) { - nctx->ctx_pmds[i].val = nctx->ctx_pmds[i].ival & ~pmu_conf.perf_ovfl_val; - th->pmd[cnum] = nctx->ctx_pmds[i].ival & pmu_conf.perf_ovfl_val; + m = pmu_conf.counter_pmds[0] >> PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) { + if (m & 0x1) { + nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val; + th->pmd[i] = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val; + } } /* clear BTB index register */ th->pmd[16] = 0; /* if sampling then increment number of users of buffer */ - if (nctx->ctx_smpl_buf) { - atomic_inc(&nctx->ctx_smpl_buf->psb_refcnt); + if (nctx->ctx_psb) { + + /* + * XXX: nopt very pretty! + */ + LOCK_PSB(nctx->ctx_psb); + nctx->ctx_psb->psb_refcnt++; + UNLOCK_PSB(nctx->ctx_psb); + /* + * remove any pointer to sampling buffer mapping + */ + nctx->ctx_smpl_vaddr = 0; } nctx->ctx_fl_frozen = 0; - nctx->ctx_ovfl_regs = 0; + nctx->ctx_ovfl_regs[0] = 0UL; + sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ /* clear pending notification */ - th->pfm_must_block = 0; + th->pfm_ovfl_block_reset = 0; /* link with new task */ - th->pfm_context = nctx; + th->pfm_context = nctx; - DBprintk((" nctx=%p for process %d\n", (void *)nctx, task->pid)); + DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid)); /* * the copy_thread routine automatically clears * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller */ if (current->thread.flags & IA64_THREAD_PM_VALID) { - DBprintk((" setting PM_VALID for %d\n", task->pid)); + DBprintk(("setting PM_VALID for [%d]\n", task->pid)); th->flags |= IA64_THREAD_PM_VALID; } @@ -2281,100 +3566,249 @@ } /* - * called from release_thread(), at this point this task is not in the - * tasklist anymore + * + * We cannot touch any of the PMU registers at this point as we may + * not be running on the same CPU the task was last run on. Therefore + * it is assumed that the PMU has been stopped appropriately in + * pfm_flush_regs() called from exit_thread(). + * + * The function is called in the context of the parent via a release_thread() + * and wait4(). The task is not in the tasklist anymore. */ void pfm_context_exit(struct task_struct *task) { pfm_context_t *ctx = task->thread.pfm_context; - if (!ctx) { - DBprintk((" invalid context for %d\n", task->pid)); - return; - } + /* + * check sampling buffer + */ + if (ctx->ctx_psb) { + pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; + + LOCK_PSB(psb); + + DBprintk(("sampling buffer from [%d] @%p size %ld vma_flag=0x%x\n", + task->pid, + psb->psb_hdr, psb->psb_size, psb->psb_flags)); + + /* + * in the case where we are the last user, we may be able to free + * the buffer + */ + psb->psb_refcnt--; + + if (psb->psb_refcnt == 0) { + + /* + * The flag is cleared in pfm_vm_close(). which gets + * called from do_exit() via exit_mm(). + * By the time we come here, the task has no more mm context. + * + * We can only free the psb and buffer here after the vm area + * describing the buffer has been removed. This normally happens + * as part of do_exit() but the entire mm context is ONLY removed + * once its reference counts goes to zero. This is typically + * the case except for multi-threaded (several tasks) processes. + * + * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details. + */ + if ((psb->psb_flags & PFM_PSB_VMA) == 0) { + + DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n", + task->pid, + psb->psb_hdr, psb->psb_size)); + + /* + * free the buffer and psb + */ + pfm_rvfree(psb->psb_hdr, psb->psb_size); + kfree(psb); + psb = NULL; + } + } + /* psb may have been deleted */ + if (psb) UNLOCK_PSB(psb); + } + + DBprintk(("cleaning [%d] pfm_context @%p notify_task=%p check=%d mm=%p\n", + task->pid, ctx, + ctx->ctx_notify_task, + atomic_read(&task->thread.pfm_notifiers_check), task->mm)); - /* check is we have a sampling buffer attached */ - if (ctx->ctx_smpl_buf) { - pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; - - /* if only user left, then remove */ - DBprintk((" [%d] [%d] psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); - - if (atomic_dec_and_test(&psb->psb_refcnt) ) { - rvfree(psb->psb_hdr, psb->psb_size); - vfree(psb); - DBprintk((" [%d] cleaning [%d] sampling buffer\n", current->pid, task->pid )); - } - } - DBprintk((" [%d] cleaning [%d] pfm_context @%p\n", current->pid, task->pid, (void *)ctx)); - - /* - * To avoid getting the notified task scan the entire process list - * when it exits because it would have pfm_notifiers_check set, we - * decrease it by 1 to inform the task, that one less task is going - * to send it notification. each new notifer increases this field by - * 1 in pfm_context_create(). Of course, there is race condition between - * decreasing the value and the notified task exiting. The danger comes - * from the fact that we have a direct pointer to its task structure - * thereby bypassing the tasklist. We must make sure that if we have - * notify_task!= NULL, the target task is still somewhat present. It may - * already be detached from the tasklist but that's okay. Note that it is - * okay if we 'miss the deadline' and the task scans the list for nothing, - * it will affect performance but not correctness. The correctness is ensured - * by using the notify_lock whic prevents the notify_task from changing on us. - * Once holdhing this lock, if we see notify_task!= NULL, then it will stay like + /* + * To avoid getting the notified task or owner task scan the entire process + * list when they exit, we decrement notifiers_check and owners_check respectively. + * + * Of course, there is race condition between decreasing the value and the + * task exiting. The danger comes from the fact that, in both cases, we have a + * direct pointer to a task structure thereby bypassing the tasklist. + * We must make sure that, if we have task!= NULL, the target task is still + * present and is identical to the initial task specified + * during pfm_create_context(). It may already be detached from the tasklist but + * that's okay. Note that it is okay if we miss the deadline and the task scans + * the list for nothing, it will affect performance but not correctness. + * The correctness is ensured by using the ctx_lock which prevents the + * notify_task from changing the fields in our context. + * Once holdhing this lock, if we see task!= NULL, then it will stay like * that until we release the lock. If it is NULL already then we came too late. */ - spin_lock(&ctx->ctx_notify_lock); + LOCK_CTX(ctx); - if (ctx->ctx_notify_task) { - DBprintk((" [%d] [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, task->pid, - ctx->ctx_notify_task->pid, - atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); + if (ctx->ctx_notify_task != NULL) { + DBprintk(("[%d], [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, + task->pid, + ctx->ctx_notify_task->pid, + atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); + + atomic_dec(&ctx->ctx_notify_task->thread.pfm_notifiers_check); + } + + if (ctx->ctx_owner != NULL) { + DBprintk(("[%d], [%d] atomic_sub on [%d] owners=%u\n", + current->pid, + task->pid, + ctx->ctx_owner->pid, + atomic_read(&ctx->ctx_owner->thread.pfm_owners_check))); - atomic_sub(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); + atomic_dec(&ctx->ctx_owner->thread.pfm_owners_check); } - spin_unlock(&ctx->ctx_notify_lock); + UNLOCK_CTX(ctx); + + LOCK_PFS(); if (ctx->ctx_fl_system) { - /* - * if included interrupts (true by default), then reset - * to get default value - */ - if (ctx->ctx_fl_exclintr == 0) { - /* - * reload kernel default DCR value - */ - ia64_set_dcr(pfs_info.pfs_dfl_dcr); - DBprintk((" restored dcr to 0x%lx\n", pfs_info.pfs_dfl_dcr)); + + pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL; + pfm_sessions.pfs_sys_sessions--; + DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu)); + /* update perfmon debug register counter */ + if (ctx->ctx_fl_using_dbreg) { + if (pfm_sessions.pfs_sys_use_dbregs == 0) { + printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid); + } else + pfm_sessions.pfs_sys_use_dbregs--; } - /* - * free system wide session slot - */ - pfs_info.pfs_sys_session = 0; + + /* + * remove any CPU pinning + */ + task->cpus_allowed = ctx->ctx_saved_cpus_allowed; + task->need_resched = 1; } else { - pfs_info.pfs_proc_sessions--; + pfm_sessions.pfs_task_sessions--; } + UNLOCK_PFS(); pfm_context_free(ctx); /* * clean pfm state in thread structure, */ - task->thread.pfm_context = NULL; - task->thread.pfm_must_block = 0; + task->thread.pfm_context = NULL; + task->thread.pfm_ovfl_block_reset = 0; + /* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */ +} + +/* + * function invoked from release_thread when pfm_smpl_buf_list is not NULL + */ +int +pfm_cleanup_smpl_buf(struct task_struct *task) +{ + pfm_smpl_buffer_desc_t *tmp, *psb = task->thread.pfm_smpl_buf_list; + if (psb == NULL) { + printk("perfmon: psb is null in [%d]\n", current->pid); + return -1; + } + /* + * Walk through the list and free the sampling buffer and psb + */ + while (psb) { + DBprintk(("[%d] freeing smpl @%p size %ld\n", current->pid, psb->psb_hdr, psb->psb_size)); + + pfm_rvfree(psb->psb_hdr, psb->psb_size); + tmp = psb->psb_next; + kfree(psb); + psb = tmp; + } + + /* just in case */ + task->thread.pfm_smpl_buf_list = NULL; + + return 0; +} + +/* + * function invoked from release_thread to make sure that the ctx_owner field does not + * point to an unexisting task. + */ +void +pfm_cleanup_owners(struct task_struct *task) +{ + struct task_struct *p; + pfm_context_t *ctx; + + DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); + + read_lock(&tasklist_lock); + + for_each_task(p) { + /* + * It is safe to do the 2-step test here, because thread.ctx + * is cleaned up only in release_thread() and at that point + * the task has been detached from the tasklist which is an + * operation which uses the write_lock() on the tasklist_lock + * so it cannot run concurrently to this loop. So we have the + * guarantee that if we find p and it has a perfmon ctx then + * it is going to stay like this for the entire execution of this + * loop. + */ + ctx = p->thread.pfm_context; + + //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); + + if (ctx && ctx->ctx_owner == task) { + DBprintk(("trying for owner [%d] in [%d]\n", task->pid, p->pid)); + /* + * the spinlock is required to take care of a race condition + * with the send_sig_info() call. We must make sure that + * either the send_sig_info() completes using a valid task, + * or the notify_task is cleared before the send_sig_info() + * can pick up a stale value. Note that by the time this + * function is executed the 'task' is already detached from the + * tasklist. The problem is that the notifiers have a direct + * pointer to it. It is okay to send a signal to a task in this + * stage, it simply will have no effect. But it is better than sending + * to a completely destroyed task or worse to a new task using the same + * task_struct address. + */ + LOCK_CTX(ctx); + + ctx->ctx_owner = NULL; + + UNLOCK_CTX(ctx); + + DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); + } + } + read_unlock(&tasklist_lock); } + +/* + * function called from release_thread to make sure that the ctx_notify_task is not pointing + * to an unexisting task + */ void pfm_cleanup_notifiers(struct task_struct *task) { struct task_struct *p; pfm_context_t *ctx; - DBprintk((" [%d] called\n", task->pid)); + DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); read_lock(&tasklist_lock); @@ -2391,10 +3825,10 @@ */ ctx = p->thread.pfm_context; - DBprintk((" [%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); + //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); if (ctx && ctx->ctx_notify_task == task) { - DBprintk((" trying for notifier %d in %d\n", task->pid, p->pid)); + DBprintk(("trying for notifier [%d] in [%d]\n", task->pid, p->pid)); /* * the spinlock is required to take care of a race condition * with the send_sig_info() call. We must make sure that @@ -2408,23 +3842,146 @@ * to a completely destroyed task or worse to a new task using the same * task_struct address. */ - spin_lock(&ctx->ctx_notify_lock); + LOCK_CTX(ctx); ctx->ctx_notify_task = NULL; - spin_unlock(&ctx->ctx_notify_lock); + UNLOCK_CTX(ctx); - DBprintk((" done for notifier %d in %d\n", task->pid, p->pid)); + DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); } } read_unlock(&tasklist_lock); +} + +static struct irqaction perfmon_irqaction = { + handler: perfmon_interrupt, + flags: SA_INTERRUPT, + name: "perfmon" +}; + +static void +pfm_pmu_snapshot(void) +{ + int i; + + for (i=0; i < IA64_NUM_PMC_REGS; i++) { + if (i >= pmu_conf.num_pmcs) break; + if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i); + } +} + +/* + * perfmon initialization routine, called from the initcall() table + */ +int __init +perfmon_init (void) +{ + pal_perf_mon_info_u_t pm_info; + s64 status; + + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_set_pmv(IA64_PERFMON_VECTOR); + ia64_srlz_d(); + + pmu_conf.pfm_is_disabled = 1; + + printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", + PFM_VERSION_MAJ, + PFM_VERSION_MIN, + PFM_SMPL_VERSION_MAJ, + PFM_SMPL_VERSION_MIN, + IA64_PERFMON_VECTOR); + + if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) { + printk("perfmon: PAL call failed (%ld), perfmon disabled\n", status); + return -1; + } + + pmu_conf.perf_ovfl_val = (1UL << pm_info.pal_perf_mon_info_s.width) - 1; + pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; + pmu_conf.num_pmcs = find_num_pm_regs(pmu_conf.impl_regs); + pmu_conf.num_pmds = find_num_pm_regs(&pmu_conf.impl_regs[4]); + + printk("perfmon: %u bits counters\n", pm_info.pal_perf_mon_info_s.width); + + printk("perfmon: %lu PMC/PMD pairs, %lu PMCs, %lu PMDs\n", + pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds); + + /* sanity check */ + if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon is DISABLED\n"); + return -1; /* no need to continue anyway */ + } + + if (ia64_pal_debug_info(&pmu_conf.num_ibrs, &pmu_conf.num_dbrs)) { + printk(KERN_WARNING "perfmon: unable to get number of debug registers\n"); + pmu_conf.num_ibrs = pmu_conf.num_dbrs = 0; + } + /* PAL reports the number of pairs */ + pmu_conf.num_ibrs <<=1; + pmu_conf.num_dbrs <<=1; + + /* + * take a snapshot of all PMU registers. PAL is supposed + * to configure them with stable/safe values, i.e., not + * capturing anything. + * We take a snapshot now, before we make any modifications. This + * will become our master copy. Then we will reuse the snapshot + * to reset the PMU in pfm_enable(). Using this technique, perfmon + * does NOT have to know about the specific values to program for + * the PMC/PMD. The safe values may be different from one CPU model to + * the other. + */ + pfm_pmu_snapshot(); + + /* + * list the pmc registers used to control monitors + * XXX: unfortunately this information is not provided by PAL + * + * We start with the architected minimum and then refine for each CPU model + */ + pmu_conf.monitor_pmcs[0] = PMM(4)|PMM(5)|PMM(6)|PMM(7); + + /* + * architected counters + */ + pmu_conf.counter_pmds[0] |= PMM(4)|PMM(5)|PMM(6)|PMM(7); + +#ifdef CONFIG_ITANIUM + pmu_conf.monitor_pmcs[0] |= PMM(10)|PMM(11)|PMM(12); + /* Itanium does not add more counters */ +#endif + /* we are all set */ + pmu_conf.pfm_is_disabled = 0; + + /* + * for now here for debug purposes + */ + perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); + + spin_lock_init(&pfm_sessions.pfs_lock); + + return 0; +} + +__initcall(perfmon_init); + +void +perfmon_init_percpu (void) +{ + ia64_set_pmv(IA64_PERFMON_VECTOR); + ia64_srlz_d(); } + #else /* !CONFIG_PERFMON */ asmlinkage int -sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long arg6, long arg7, long arg8, long stack) +sys_perfmonctl (int pid, int cmd, void *req, int count, long arg5, long arg6, + long arg7, long arg8, long stack) { return -ENOSYS; } diff -urN linux-2.4.18/arch/ia64/kernel/process.c linux-2.4.19-pre5/arch/ia64/kernel/process.c --- linux-2.4.18/arch/ia64/kernel/process.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/process.c Sat Mar 30 22:55:25 2002 @@ -1,8 +1,8 @@ /* * Architecture-specific setup. * - * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang + * Copyright (C) 1998-2002 Hewlett-Packard Co + * David Mosberger-Tang */ #define __KERNEL_SYSCALLS__ /* see */ #include @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,10 @@ #include #include +#ifdef CONFIG_IA64_SGI_SN +#include +#endif + static void do_show_stack (struct unw_frame_info *info, void *arg) { @@ -46,6 +51,15 @@ } void +show_trace_task (struct task_struct *task) +{ + struct unw_frame_info info; + + unw_init_from_blocked_task(&info, task); + do_show_stack(&info, 0); +} + +void show_stack (struct task_struct *task) { if (!task) @@ -90,8 +104,8 @@ 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) { + if (user_mode(regs)) { + /* print the stacked registers */ unsigned long val, sof, *bsp, ndirty; int i, is_nat = 0; @@ -122,8 +136,18 @@ if (!current->need_resched) min_xtp(); #endif - while (!current->need_resched) + + while (!current->need_resched) { +#ifdef CONFIG_IA64_SGI_SN + snidle(); +#endif continue; + } + +#ifdef CONFIG_IA64_SGI_SN + snidleoff(); +#endif + #ifdef CONFIG_SMP normal_xtp(); #endif @@ -139,10 +163,17 @@ { if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) ia64_save_debug_regs(&task->thread.dbr[0]); + #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) pfm_save_regs(task); + +# ifdef CONFIG_SMP + if (local_cpu_data->pfm_syst_wide) + pfm_syst_wide_update_task(task, 0); +# endif #endif + if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(task); } @@ -152,10 +183,17 @@ { if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) ia64_load_debug_regs(&task->thread.dbr[0]); + #ifdef CONFIG_PERFMON if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) pfm_load_regs(task); + +# ifdef CONFIG_SMP + if (local_cpu_data->pfm_syst_wide) + pfm_syst_wide_update_task(task, 1); +# endif #endif + if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(task); } @@ -235,7 +273,7 @@ if (user_mode(child_ptregs)) { if (user_stack_base) { - child_ptregs->r12 = user_stack_base + user_stack_size; + child_ptregs->r12 = user_stack_base + user_stack_size - 16; child_ptregs->ar_bspstore = user_stack_base; child_ptregs->ar_rnat = 0; child_ptregs->loadrs = 0; @@ -288,9 +326,15 @@ if (IS_IA32_PROCESS(ia64_task_regs(current))) ia32_save_state(p); #endif + #ifdef CONFIG_PERFMON - if (p->thread.pfm_context) - retval = pfm_inherit(p, child_ptregs); + /* + * reset notifiers and owner check (may not have a perfmon context) + */ + atomic_set(&p->thread.pfm_notifiers_check, 0); + atomic_set(&p->thread.pfm_owners_check, 0); + + if (current->thread.pfm_context) retval = pfm_inherit(p, child_ptregs); #endif return retval; } @@ -414,6 +458,16 @@ return error; } +void +ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter) +{ + set_personality(PER_LINUX); + if (elf_ex->e_flags & EF_IA_64_LINUX_EXECUTABLE_STACK) + current->thread.flags |= IA64_THREAD_XSTACK; + else + current->thread.flags &= ~IA64_THREAD_XSTACK; +} + pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { @@ -445,15 +499,15 @@ #ifdef CONFIG_PERFMON /* - * By the time we get here, the task is detached from the tasklist. This is important - * because it means that no other tasks can ever find it as a notifiied task, therfore - * there is no race condition between this code and let's say a pfm_context_create(). - * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if - * this other task is in the middle of its own pfm_context_exit() because it would alreayd - * be out of the task list. Note that this case is very unlikely between a direct child - * and its parents (if it is the notified process) because of the way the exit is notified - * via SIGCHLD. + * by the time we get here, the task is detached from the tasklist. This is important + * because it means that no other tasks can ever find it as a notified task, therfore there + * is no race condition between this code and let's say a pfm_context_create(). + * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if this + * other task is in the middle of its own pfm_context_exit() because it would already be out of + * the task list. Note that this case is very unlikely between a direct child and its parents + * (if it is the notified process) because of the way the exit is notified via SIGCHLD. */ + void release_thread (struct task_struct *task) { @@ -462,6 +516,12 @@ if (atomic_read(&task->thread.pfm_notifiers_check) > 0) pfm_cleanup_notifiers(task); + + if (atomic_read(&task->thread.pfm_owners_check) > 0) + pfm_cleanup_owners(task); + + if (task->thread.pfm_smpl_buf_list) + pfm_cleanup_smpl_buf(task); } #endif @@ -477,21 +537,13 @@ ia64_set_fpu_owner(0); #endif #ifdef CONFIG_PERFMON - /* stop monitoring */ - if ((current->thread.flags & IA64_THREAD_PM_VALID) != 0) { - /* - * we cannot rely on switch_to() to save the PMU - * context for the last time. There is a possible race - * condition in SMP mode between the child and the - * parent. by explicitly saving the PMU context here - * we garantee no race. this call we also stop - * monitoring - */ + /* if needed, stop monitoring and flush state to perfmon context */ + if (current->thread.pfm_context) pfm_flush_regs(current); - /* - * make sure that switch_to() will not save context again - */ - current->thread.flags &= ~IA64_THREAD_PM_VALID; + + /* free debug register resources */ + if ((current->thread.flags & IA64_THREAD_DBG_VALID) != 0) { + pfm_release_debug_registers(current); } #endif } diff -urN linux-2.4.18/arch/ia64/kernel/ptrace.c linux-2.4.19-pre5/arch/ia64/kernel/ptrace.c --- linux-2.4.18/arch/ia64/kernel/ptrace.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/ptrace.c Sat Mar 30 22:55:25 2002 @@ -1,7 +1,7 @@ /* * Kernel support for the ptrace() and syscall tracing interfaces. * - * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2002 Hewlett-Packard Co * David Mosberger-Tang * * Derived from the x86 and Alpha versions. Most of the code in here @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_PERFMON +# include +#endif /* * Bits in the PSR that we allow ptrace() to change: @@ -755,11 +758,6 @@ } else { /* access debug registers */ - if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { - child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(child->thread.dbr, 0, sizeof(child->thread.dbr)); - memset(child->thread.ibr, 0, sizeof(child->thread.ibr)); - } if (addr >= PT_IBR) { regnum = (addr - PT_IBR) >> 3; ptr = &child->thread.ibr[0]; @@ -772,6 +770,30 @@ dprintk("ptrace: rejecting access to register address 0x%lx\n", addr); return -1; } +#ifdef CONFIG_PERFMON + /* + * Check if debug registers are used by perfmon. This test must be done + * once we know that we can do the operation, i.e. the arguments are all + * valid, but before we start modifying the state. + * + * Perfmon needs to keep a count of how many processes are trying to + * modify the debug registers for system wide monitoring sessions. + * + * We also include read access here, because they may cause the + * PMU-installed debug register state (dbr[], ibr[]) to be reset. The two + * arrays are also used by perfmon, but we do not use + * IA64_THREAD_DBG_VALID. The registers are restored by the PMU context + * switch code. + */ + if (pfm_use_debug_registers(child)) + return -1; +#endif + + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(child->thread.dbr, 0, sizeof(child->thread.dbr)); + memset(child->thread.ibr, 0, sizeof(child->thread.ibr)); + } ptr += regnum; @@ -789,6 +811,260 @@ return 0; } +static long +ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) +{ + struct switch_stack *sw; + struct pt_regs *pt; + long ret, retval; + struct unw_frame_info info; + char nat = 0; + int i; + + retval = verify_area(VERIFY_WRITE, ppr, sizeof(struct pt_all_user_regs)); + if (retval != 0) { + return -EIO; + } + + pt = ia64_task_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) { + return -EIO; + } + + if (((unsigned long) ppr & 0x7) != 0) { + dprintk("ptrace:unaligned register address %p\n", ppr); + return -EIO; + } + + retval = 0; + + /* control regs */ + + retval |= __put_user(pt->cr_iip, &ppr->cr_iip); + retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 0); + + /* app regs */ + + retval |= __put_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); + retval |= __put_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); + retval |= __put_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); + retval |= __put_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); + retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); + retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); + + retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 0); + retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 0); + retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 0); + retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 0); + retval |= access_uarea(child, PT_CFM, &ppr->cfm, 0); + + /* gr1-gr3 */ + + retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long) * 3); + + /* gr4-gr7 */ + + for (i = 4; i < 8; i++) { + retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 0); + } + + /* gr8-gr11 */ + + retval |= __copy_to_user(&ppr->gr[8], &pt->r8, sizeof(long) * 4); + + /* gr12-gr15 */ + + retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 4); + + /* gr16-gr31 */ + + retval |= __copy_to_user(&ppr->gr[16], &pt->r16, sizeof(long) * 16); + + /* b0 */ + + retval |= __put_user(pt->b0, &ppr->br[0]); + + /* b1-b5 */ + + for (i = 1; i < 6; i++) { + retval |= unw_access_br(&info, i, &ppr->br[i], 0); + } + + /* b6-b7 */ + + retval |= __put_user(pt->b6, &ppr->br[6]); + retval |= __put_user(pt->b7, &ppr->br[7]); + + /* fr2-fr5 */ + + for (i = 2; i < 6; i++) { + retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); + retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + } + + /* fr6-fr9 */ + + retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 4); + + /* fp scratch regs(10-15) */ + + retval |= __copy_to_user(&ppr->fr[10], &sw->f10, sizeof(struct ia64_fpreg) * 6); + + /* fr16-fr31 */ + + for (i = 16; i < 32; i++) { + retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0); + retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); + } + + /* fph */ + + ia64_flush_fph(child); + retval |= __copy_to_user(&ppr->fr[32], &child->thread.fph, sizeof(ppr->fr[32]) * 96); + + /* preds */ + + retval |= __put_user(pt->pr, &ppr->pr); + + /* nat bits */ + + retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 0); + + ret = retval ? -EIO : 0; + return ret; +} + +static long +ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) +{ + struct switch_stack *sw; + struct pt_regs *pt; + long ret, retval; + struct unw_frame_info info; + char nat = 0; + int i; + + retval = verify_area(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs)); + if (retval != 0) { + return -EIO; + } + + pt = ia64_task_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) { + return -EIO; + } + + if (((unsigned long) ppr & 0x7) != 0) { + dprintk("ptrace:unaligned register address %p\n", ppr); + return -EIO; + } + + retval = 0; + + /* control regs */ + + retval |= __get_user(pt->cr_iip, &ppr->cr_iip); + retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 1); + + /* app regs */ + + retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); + retval |= __get_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); + retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); + retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); + retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); + retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); + + retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 1); + retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 1); + retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 1); + retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 1); + retval |= access_uarea(child, PT_CFM, &ppr->cfm, 1); + + /* gr1-gr3 */ + + retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long) * 3); + + /* gr4-gr7 */ + + for (i = 4; i < 8; i++) { + long ret = unw_get_gr(&info, i, &ppr->gr[i], &nat); + if (ret < 0) { + return ret; + } + retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 1); + } + + /* gr8-gr11 */ + + retval |= __copy_from_user(&pt->r8, &ppr->gr[8], sizeof(long) * 4); + + /* gr12-gr15 */ + + retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 4); + + /* gr16-gr31 */ + + retval |= __copy_from_user(&pt->r16, &ppr->gr[16], sizeof(long) * 16); + + /* b0 */ + + retval |= __get_user(pt->b0, &ppr->br[0]); + + /* b1-b5 */ + + for (i = 1; i < 6; i++) { + retval |= unw_access_br(&info, i, &ppr->br[i], 1); + } + + /* b6-b7 */ + + retval |= __get_user(pt->b6, &ppr->br[6]); + retval |= __get_user(pt->b7, &ppr->br[7]); + + /* fr2-fr5 */ + + for (i = 2; i < 6; i++) { + retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); + retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + } + + /* fr6-fr9 */ + + retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 4); + + /* fp scratch regs(10-15) */ + + retval |= __copy_from_user(&sw->f10, &ppr->fr[10], sizeof(ppr->fr[10]) * 6); + + /* fr16-fr31 */ + + for (i = 16; i < 32; i++) { + retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1); + retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); + } + + /* fph */ + + ia64_sync_fph(child); + retval |= __copy_from_user(&child->thread.fph, &ppr->fr[32], sizeof(ppr->fr[32]) * 96); + + /* preds */ + + retval |= __get_user(pt->pr, &ppr->pr); + + /* nat bits */ + + retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 1); + + ret = retval ? -EIO : 0; + return ret; +} + /* * Called by kernel/ptrace.c when detaching.. * @@ -977,6 +1253,14 @@ case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); + goto out_tsk; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (struct pt_all_user_regs*) data); + goto out_tsk; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (struct pt_all_user_regs*) data); goto out_tsk; default: diff -urN linux-2.4.18/arch/ia64/kernel/sal.c linux-2.4.19-pre5/arch/ia64/kernel/sal.c --- linux-2.4.18/arch/ia64/kernel/sal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/sal.c Sat Mar 30 22:55:25 2002 @@ -18,7 +18,8 @@ #include #include -spinlock_t sal_lock = SPIN_LOCK_UNLOCKED; +spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; +unsigned long sal_platform_features; static struct { void *addr; /* function entry point */ @@ -76,7 +77,7 @@ return str; } -static void __init +static void __init ia64_sal_handler_init (void *entry_point, void *gpval) { /* fill in the SAL procedure descriptor and point ia64_sal to it: */ @@ -102,7 +103,7 @@ if (strncmp(systab->signature, "SST_", 4) != 0) printk("bad signature in system table!"); - /* + /* * revisions are coded in BCD, so %x does the job for us */ printk("SAL v%x.%02x: oem=%.32s, product=%.32s\n", @@ -152,12 +153,12 @@ case SAL_DESC_PLATFORM_FEATURE: { struct ia64_sal_desc_platform_feature *pf = (void *) p; + sal_platform_features = pf->feature_mask; printk("SAL: Platform features "); - if (pf->feature_mask & (1 << 0)) + if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK) printk("BusLock "); - - if (pf->feature_mask & (1 << 1)) { + if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) { printk("IRQ_Redirection "); #ifdef CONFIG_SMP if (no_int_routing) @@ -166,15 +167,17 @@ smp_int_redirect |= SMP_IRQ_REDIRECTION; #endif } - if (pf->feature_mask & (1 << 2)) { + if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) { printk("IPI_Redirection "); #ifdef CONFIG_SMP - if (no_int_routing) + if (no_int_routing) smp_int_redirect &= ~SMP_IPI_REDIRECTION; else smp_int_redirect |= SMP_IPI_REDIRECTION; #endif } + if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT) + printk("ITC_Drift "); printk("\n"); break; } diff -urN linux-2.4.18/arch/ia64/kernel/setup.c linux-2.4.19-pre5/arch/ia64/kernel/setup.c --- linux-2.4.18/arch/ia64/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/setup.c Sat Mar 30 22:55:25 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Hewlett-Packard Co * David Mosberger-Tang - * Copyright (C) 1998, 1999, 2001 Stephane Eranian + * Stephane Eranian * Copyright (C) 2000, Rohit Seth * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond @@ -147,6 +147,10 @@ } +/* + * Find a place to put the bootmap and return its starting address in bootmap_start. + * This address must be page-aligned. + */ static int find_bootmap_location (unsigned long start, unsigned long end, void *arg) { @@ -165,7 +169,7 @@ for (i = 0; i < num_rsvd_regions; i++) { range_start = MAX(start, free_start); - range_end = MIN(end, rsvd_region[i].start); + range_end = MIN(end, rsvd_region[i].start & PAGE_MASK); if (range_end <= range_start) continue; /* skip over empty range */ @@ -177,7 +181,7 @@ /* nothing more available in this segment */ if (range_end == end) return 0; - free_start = rsvd_region[i].end; + free_start = PAGE_ALIGN(rsvd_region[i].end); } return 0; } @@ -306,6 +310,10 @@ /* process SAL system table: */ ia64_sal_init(efi.sal_systab); +#ifdef CONFIG_IA64_GENERIC + machvec_init(acpi_get_sysname()); +#endif + /* * Set `iobase' to the appropriate address in region 6 * (uncached access range) @@ -332,10 +340,6 @@ cpu_init(); /* initialize the bootstrap CPU */ -#ifdef CONFIG_IA64_GENERIC - machvec_init(acpi_get_sysname()); -#endif - if (efi.acpi20) { /* Parse the ACPI 2.0 tables */ acpi20_parse(efi.acpi20); @@ -371,17 +375,14 @@ { #ifdef CONFIG_SMP # define lpj c->loops_per_jiffy +# define cpu c->processor #else # define lpj loops_per_jiffy +# define cpu 0 #endif char family[32], features[128], *cp; struct cpuinfo_ia64 *c = v; - unsigned long mask, cpu = c - cpu_data(0); - -#ifdef CONFIG_SMP - if (!(cpu_online_map & (1 << cpu))) - return 0; -#endif + unsigned long mask; mask = c->features; @@ -403,7 +404,7 @@ sprintf(cp, " 0x%lx", mask); seq_printf(m, - "processor : %lu\n" + "processor : %d\n" "vendor : %s\n" "arch : IA-64\n" "family : %s\n" @@ -427,6 +428,10 @@ static void * c_start (struct seq_file *m, loff_t *pos) { +#ifdef CONFIG_SMP + while (*pos < NR_CPUS && !(cpu_online_map & (1 << *pos))) + ++*pos; +#endif return *pos < NR_CPUS ? cpu_data(*pos) : NULL; } @@ -483,6 +488,9 @@ cpuid.bits[i] = ia64_get_cpuid(i); memcpy(c->vendor, cpuid.field.vendor, 16); +#ifdef CONFIG_SMP + c->processor = smp_processor_id(); +#endif c->ppn = cpuid.field.ppn; c->number = cpuid.field.number; c->revision = cpuid.field.revision; @@ -534,7 +542,7 @@ = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), sizeof(struct cpuinfo_ia64)); for (cpu = 1; cpu < NR_CPUS; ++cpu) - memcpy(my_cpu_data->cpu_data[cpu]->cpu_data_ptrs, + memcpy(my_cpu_data->cpu_data[cpu]->cpu_data, my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data)); } else { order = get_order(sizeof(struct cpuinfo_ia64)); @@ -616,4 +624,6 @@ num_phys_stacked = 96; } local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8; + + platform_cpu_init(); } diff -urN linux-2.4.18/arch/ia64/kernel/signal.c linux-2.4.19-pre5/arch/ia64/kernel/signal.c --- linux-2.4.18/arch/ia64/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -1,7 +1,7 @@ /* * Architecture-specific signal handling support. * - * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2002 Hewlett-Packard Co * David Mosberger-Tang * * Derived from i386 and Alpha versions. @@ -160,6 +160,7 @@ err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { case __SI_FAULT >> 16: + err |= __put_user(from->si_flags, &to->si_flags); err |= __put_user(from->si_isr, &to->si_isr); case __SI_POLL >> 16: err |= __put_user(from->si_addr, &to->si_addr); @@ -172,7 +173,12 @@ case __SI_PROF >> 16: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_pfm_ovfl, &to->si_pfm_ovfl); + if (from->si_code == PROF_OVFL) { + err |= __put_user(from->si_pfm_ovfl[0], &to->si_pfm_ovfl[0]); + err |= __put_user(from->si_pfm_ovfl[1], &to->si_pfm_ovfl[1]); + err |= __put_user(from->si_pfm_ovfl[2], &to->si_pfm_ovfl[2]); + err |= __put_user(from->si_pfm_ovfl[3], &to->si_pfm_ovfl[3]); + } break; default: err |= __put_user(from->si_uid, &to->si_uid); @@ -578,10 +584,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/ia64/kernel/smpboot.c linux-2.4.19-pre5/arch/ia64/kernel/smpboot.c --- linux-2.4.18/arch/ia64/kernel/smpboot.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/smpboot.c Sat Mar 30 22:55:25 2002 @@ -416,9 +416,9 @@ if (!idle) panic("No idle process for CPU %d", cpu); - idle->processor = cpu; + task_set_cpu(idle, cpu); /* we schedule the first task manually */ + ia64_cpu_to_sapicid[cpu] = sapicid; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ del_from_runqueue(idle); unhash_process(idle); diff -urN linux-2.4.18/arch/ia64/kernel/traps.c linux-2.4.19-pre5/arch/ia64/kernel/traps.c --- linux-2.4.18/arch/ia64/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/traps.c Sat Mar 30 22:55:25 2002 @@ -1,7 +1,7 @@ /* * Architecture-specific trap handling. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2002 Hewlett-Packard Co * David Mosberger-Tang * * 05/12/00 grao : added isr in siginfo for SIGFPE @@ -133,6 +133,8 @@ /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num; + siginfo.si_flags = 0; /* clear __ISR_VALID */ + siginfo.si_isr = 0; switch (break_num) { case 0: /* unknown error */ @@ -352,6 +354,8 @@ siginfo.si_code = FPE_FLTDIV; } siginfo.si_isr = isr; + siginfo.si_flags = __ISR_VALID; + siginfo.si_imm = 0; force_sig_info(SIGFPE, &siginfo, current); } } else { @@ -372,6 +376,8 @@ siginfo.si_code = FPE_FLTRES; } siginfo.si_isr = isr; + siginfo.si_flags = __ISR_VALID; + siginfo.si_imm = 0; force_sig_info(SIGFPE, &siginfo, current); } } @@ -490,6 +496,8 @@ siginfo.si_errno = 0; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = vector; + siginfo.si_flags = __ISR_VALID; + siginfo.si_isr = isr; force_sig_info(SIGILL, &siginfo, current); return; } @@ -517,6 +525,10 @@ } siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_addr = 0; + siginfo.si_imm = 0; force_sig_info(SIGTRAP, &siginfo, current); return; @@ -528,6 +540,9 @@ siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_flags = __ISR_VALID; + siginfo.si_isr = isr; + siginfo.si_imm = 0; force_sig_info(SIGFPE, &siginfo, current); } return; @@ -537,6 +552,9 @@ siginfo.si_signo = SIGILL; siginfo.si_code = ILL_BADIADDR; siginfo.si_errno = 0; + siginfo.si_flags = 0; + siginfo.si_isr = 0; + siginfo.si_imm = 0; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); force_sig_info(SIGILL, &siginfo, current); return; diff -urN linux-2.4.18/arch/ia64/kernel/unaligned.c linux-2.4.19-pre5/arch/ia64/kernel/unaligned.c --- linux-2.4.18/arch/ia64/kernel/unaligned.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/unaligned.c Sat Mar 30 22:55:25 2002 @@ -1,9 +1,9 @@ /* * Architecture-specific unaligned trap handling. * - * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2000 Stephane Eranian - * Copyright (C) 2001 David Mosberger-Tang + * Copyright (C) 1999-2002 Hewlett-Packard Co + * Stephane Eranian + * David Mosberger-Tang * * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. @@ -23,7 +23,7 @@ #undef DEBUG_UNALIGNED_TRAP #ifdef DEBUG_UNALIGNED_TRAP -# define DPRINT(a...) do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0) +# define DPRINT(a...) do { printk("%s %u: ", __FUNCTION__, __LINE__); printk (a); } while (0) # define DDUMP(str,vp,len) dump(str, vp, len) static void @@ -650,7 +650,7 @@ * just in case. */ if (ld.x6_op == 1 || ld.x6_op == 3) { - printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); + printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__); die_if_kernel("unaligned reference on specualtive load with register update\n", regs, 30); } @@ -1080,8 +1080,8 @@ * For this reason we keep this sanity check */ if (ld.x6_op == 1 || ld.x6_op == 3) - printk(KERN_ERR __FUNCTION__": register update on speculative load pair, " - "error\n"); + printk("%s %s: register update on speculative load pair, " + "error\n",KERN_ERR, __FUNCTION__); setreg(ld.r3, ifa, 0, regs); } @@ -1488,6 +1488,9 @@ si.si_errno = 0; si.si_code = BUS_ADRALN; si.si_addr = (void *) ifa; + si.si_flags = 0; + si.si_isr = 0; + si.si_imm = 0; force_sig_info(SIGBUS, &si, current); goto done; } diff -urN linux-2.4.18/arch/ia64/kernel/unwind.c linux-2.4.19-pre5/arch/ia64/kernel/unwind.c --- linux-2.4.18/arch/ia64/kernel/unwind.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/unwind.c Sat Mar 30 22:55:25 2002 @@ -1,6 +1,6 @@ /* - * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang + * Copyright (C) 1999-2002 Hewlett-Packard Co + * David Mosberger-Tang */ /* * This file implements call frame unwind support for the Linux @@ -72,6 +72,8 @@ #define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) +#define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) +#define free_labeled_state(usr) kfree(usr) typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; @@ -521,7 +523,7 @@ } -/* Unwind decoder routines */ +/* Routines to manipulate the state stack. */ static inline void push (struct unw_state_record *sr) @@ -534,24 +536,60 @@ return; } memcpy(rs, &sr->curr, sizeof(*rs)); - rs->next = sr->stack; - sr->stack = rs; + sr->curr.next = rs; } static void pop (struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_reg_state *rs = sr->curr.next; - if (!sr->stack) { - printk ("unwind: stack underflow!\n"); + if (!rs) { + printk("unwind: stack underflow!\n"); return; } - rs = sr->stack; - sr->stack = rs->next; + memcpy(&sr->curr, rs, sizeof(*rs)); free_reg_state(rs); } +/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */ +static struct unw_reg_state * +dup_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *copy, *prev = NULL, *first = NULL; + + while (rs) { + copy = alloc_reg_state(); + if (!copy) { + printk ("unwind.dup_state_stack: out of memory\n"); + return NULL; + } + memcpy(copy, rs, sizeof(*copy)); + if (first) + prev->next = copy; + else + first = copy; + rs = rs->next; + prev = copy; + } + return first; +} + +/* Free all stacked register states (but not RS itself). */ +static void +free_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *p, *next; + + for (p = rs->next; p != NULL; p = next) { + next = p->next; + free_reg_state(p); + } + rs->next = NULL; +} + +/* Unwind decoder routines */ + static enum unw_register_index __attribute__((const)) decode_abreg (unsigned char abreg, int memory) { @@ -689,7 +727,7 @@ sr->first_region = 0; /* check if we're done: */ - if (body && sr->when_target < sr->region_start + sr->region_len) { + if (sr->when_target < sr->region_start + sr->region_len) { sr->done = 1; return; } @@ -902,31 +940,36 @@ static inline void desc_copy_state (unw_word label, struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_labeled_state *ls; - for (rs = sr->reg_state_list; rs; rs = rs->next) { - if (rs->label == label) { - memcpy (&sr->curr, rs, sizeof(sr->curr)); + for (ls = sr->labeled_states; ls; ls = ls->next) { + if (ls->label == label) { + free_state_stack(&sr->curr); + memcpy(&sr->curr, &ls->saved_state, sizeof(sr->curr)); + sr->curr.next = dup_state_stack(ls->saved_state.next); return; } } - printk("unwind: failed to find state labelled 0x%lx\n", label); + printk("unwind: failed to find state labeled 0x%lx\n", label); } static inline void desc_label_state (unw_word label, struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_labeled_state *ls; - rs = alloc_reg_state(); - if (!rs) { - printk("unwind: cannot stack!\n"); + ls = alloc_labeled_state(); + if (!ls) { + printk("unwind.desc_label_state(): out of memory\n"); return; } - memcpy(rs, &sr->curr, sizeof(*rs)); - rs->label = label; - rs->next = sr->reg_state_list; - sr->reg_state_list = rs; + ls->label = label; + memcpy(&ls->saved_state, &sr->curr, sizeof(ls->saved_state)); + ls->saved_state.next = dup_state_stack(sr->curr.next); + + /* insert into list of labeled states: */ + ls->next = sr->labeled_states; + sr->labeled_states = ls; } /* @@ -1378,6 +1421,8 @@ else break; } + if (rel_ip < e->start_offset || rel_ip >= e->end_offset) + return NULL; return e; } @@ -1388,9 +1433,9 @@ static inline struct unw_script * build_script (struct unw_frame_info *info) { - struct unw_reg_state *rs, *next; const struct unw_table_entry *e = 0; struct unw_script *script = 0; + struct unw_labeled_state *ls, *next; unsigned long ip = info->ip; struct unw_state_record sr; struct unw_table *table; @@ -1535,15 +1580,15 @@ for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i) compile_reg(&sr, i, script); - /* free labelled register states & stack: */ + /* free labeled register states & stack: */ STAT(parse_start = ia64_get_itc()); - for (rs = sr.reg_state_list; rs; rs = next) { - next = rs->next; - free_reg_state(rs); + for (ls = sr.labeled_states; ls; ls = next) { + next = ls->next; + free_state_stack(&ls->saved_state); + free_labeled_state(ls); } - while (sr.stack) - pop(&sr); + free_state_stack(&sr.curr); STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start); script_finalize(script, &sr); diff -urN linux-2.4.18/arch/ia64/kernel/unwind_i.h linux-2.4.19-pre5/arch/ia64/kernel/unwind_i.h --- linux-2.4.18/arch/ia64/kernel/unwind_i.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/kernel/unwind_i.h Sat Mar 30 22:55:25 2002 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang + * Copyright (C) 2000, 2002 Hewlett-Packard Co + * David Mosberger-Tang * * Kernel unwind support. */ @@ -85,6 +85,17 @@ int when; /* when the register gets saved */ }; +struct unw_reg_state { + struct unw_reg_state *next; /* next (outer) element on state stack */ + struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */ +}; + +struct unw_labeled_state { + struct unw_labeled_state *next; /* next labeled state (or NULL) */ + unsigned long label; /* label for this state */ + struct unw_reg_state saved_state; +}; + struct unw_state_record { unsigned int first_region : 1; /* is this the first region? */ unsigned int done : 1; /* are we done scanning descriptors? */ @@ -105,11 +116,8 @@ u8 gr_save_loc; /* next general register to use for saving a register */ u8 return_link_reg; /* branch register in which the return link is passed */ - struct unw_reg_state { - struct unw_reg_state *next; - unsigned long label; /* label of this state record */ - struct unw_reg_info reg[UNW_NUM_REGS]; - } curr, *stack, *reg_state_list; + struct unw_labeled_state *labeled_states; /* list of all labeled states */ + struct unw_reg_state curr; /* current state */ }; enum unw_nat_type { diff -urN linux-2.4.18/arch/ia64/lib/swiotlb.c linux-2.4.19-pre5/arch/ia64/lib/swiotlb.c --- linux-2.4.18/arch/ia64/lib/swiotlb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/lib/swiotlb.c Sat Mar 30 22:55:25 2002 @@ -27,11 +27,21 @@ #define ALIGN(val, align) ((unsigned long) \ (((unsigned long) (val) + ((align) - 1)) & ~((align) - 1))) +#define OFFSET(val,align) ((unsigned long) \ + ( (val) & ( (align) - 1))) + #define SG_ENT_VIRT_ADDRESS(sg) ((sg)->address ? (sg)->address \ : page_address((sg)->page) + (sg)->offset) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) /* + * Maximum allowable number of contiguous slabs to map, + * must be a power of 2. What is the appropriate value ? + * The complexity of {map,unmap}_single is linearly dependent on this value. + */ +#define IO_TLB_SEGSIZE 128 + +/* * log of the size of each IO TLB slab. The number of slabs is command line controllable. */ #define IO_TLB_SHIFT 11 @@ -69,10 +79,15 @@ setup_io_tlb_npages (char *str) { io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); + + /* avoid tail segment of size < IO_TLB_SEGSIZE */ + io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); + return 1; } __setup("swiotlb=", setup_io_tlb_npages); + /* * Statically reserve bounce buffer space and initialize bounce buffer data structures for * the software IO TLB used to implement the PCI DMA API. @@ -92,12 +107,12 @@ /* * Allocate and initialize the free list array. This array is used - * to find contiguous free memory regions of size 2^IO_TLB_SHIFT between - * io_tlb_start and io_tlb_end. + * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE + * between io_tlb_start and io_tlb_end. */ io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); for (i = 0; i < io_tlb_nslabs; i++) - io_tlb_list[i] = io_tlb_nslabs - i; + io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); io_tlb_index = 0; io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); @@ -124,7 +139,7 @@ if (size > (1 << PAGE_SHIFT)) stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT)); else - stride = nslots; + stride = 1; if (!nslots) BUG(); @@ -151,7 +166,8 @@ for (i = index; i < index + nslots; i++) io_tlb_list[i] = 0; - for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--) + for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) + && io_tlb_list[i]; i--) io_tlb_list[i] = ++count; dma_addr = io_tlb_start + (index << IO_TLB_SHIFT); @@ -217,7 +233,8 @@ */ spin_lock_irqsave(&io_tlb_lock, flags); { - int count = ((index + nslots) < io_tlb_nslabs ? io_tlb_list[index + nslots] : 0); + int count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ? + io_tlb_list[index + nslots] : 0); /* * Step 1: return the slots to the free list, merging the slots with * superceeding slots @@ -228,7 +245,8 @@ * Step 2: merge the returned slots with the preceeding slots, if * available (non zero) */ - for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--) + for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && + io_tlb_list[i]; i--) io_tlb_list[i] = ++count; } spin_unlock_irqrestore(&io_tlb_lock, flags); @@ -405,11 +423,13 @@ for (i = 0; i < nelems; i++, sg++) { sg->orig_address = SG_ENT_VIRT_ADDRESS(sg); if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) { - addr = map_single(hwdev, sg->address, sg->length, direction); + addr = map_single(hwdev, sg->orig_address, sg->length, direction); if (sg->address) sg->address = addr; - else + else { sg->page = virt_to_page(addr); + sg->offset = (u64) addr & ~PAGE_MASK; + } } } return nelems; @@ -432,10 +452,12 @@ unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction); if (sg->address) sg->address = sg->orig_address; - else + else { sg->page = virt_to_page(sg->orig_address); + sg->offset = (u64) sg->orig_address & ~PAGE_MASK; + } } else if (direction == PCI_DMA_FROMDEVICE) - mark_clean(sg->address, sg->length); + mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length); } /* diff -urN linux-2.4.18/arch/ia64/mm/extable.c linux-2.4.19-pre5/arch/ia64/mm/extable.c --- linux-2.4.18/arch/ia64/mm/extable.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/mm/extable.c Sat Mar 30 22:55:25 2002 @@ -1,8 +1,8 @@ /* * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2001-2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include @@ -55,10 +55,12 @@ struct module *mp; /* The kernel is the last "module" -- no need to treat it special. */ - for (mp = module_list; mp ; mp = mp->next) { + for (mp = module_list; mp; mp = mp->next) { if (!mp->ex_table_start) continue; archdata = (struct archdata *) mp->archdata_start; + if (!archdata) + continue; entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr, (unsigned long) archdata->gp); if (entry) { diff -urN linux-2.4.18/arch/ia64/mm/fault.c linux-2.4.19-pre5/arch/ia64/mm/fault.c --- linux-2.4.18/arch/ia64/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/mm/fault.c Sat Mar 30 22:55:25 2002 @@ -1,7 +1,7 @@ /* * MMU fault handling support. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2002 Hewlett-Packard Co * David Mosberger-Tang */ #include @@ -96,7 +96,7 @@ * sure we exit gracefully rather than endlessly redo the * fault. */ - switch (handle_mm_fault(mm, vma, address, mask)) { + switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) { case 1: ++current->min_flt; break; @@ -151,6 +151,8 @@ si.si_errno = 0; si.si_code = code; si.si_addr = (void *) address; + si.si_isr = isr; + si.si_flags = __ISR_VALID; force_sig_info(signal, &si, current); return; } diff -urN linux-2.4.18/arch/ia64/sn/Makefile linux-2.4.19-pre5/arch/ia64/sn/Makefile --- linux-2.4.18/arch/ia64/sn/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/Makefile Thu Jan 1 01:00:00 1970 @@ -1,19 +0,0 @@ -# -# ia64/sn/Makefile -# -# Copyright (C) 1999 Silicon Graphics, Inc. -# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) -# - -EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ - -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ - -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS -all: sn.a - -O_TARGET = sn.a -obj-y = sn1/sn1.a - -clean:: - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,777 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,772 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-dig-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-dig-mp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-dig-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-dig-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,459 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-dig-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-dig-sp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-dig-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-dig-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,459 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-generic-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-generic-mp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-generic-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-generic-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,460 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +CONFIG_IA64_GENERIC=y +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Simulated drivers +# +# CONFIG_SIMETH is not set +# CONFIG_SIM_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-generic-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-generic-sp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-generic-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-generic-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,460 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +CONFIG_IA64_GENERIC=y +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +# CONFIG_IA32_SUPPORT is not set +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Simulated drivers +# +# CONFIG_SIMETH is not set +# CONFIG_SIM_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-hp-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-hp-sp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-hp-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-hp-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,334 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +CONFIG_IA64_HP_SIM=y +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Simulated drivers +# +CONFIG_SIMETH=y +CONFIG_SIM_SERIAL=y +CONFIG_SCSI_SIM=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-prom-medusa linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-prom-medusa --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Sat Mar 30 22:55:25 2002 @@ -0,0 +1,529 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,736 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Sat Mar 30 22:55:25 2002 @@ -0,0 +1,738 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Sat Mar 30 22:55:25 2002 @@ -0,0 +1,736 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-sp --- linux-2.4.18/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,736 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-dig-numa linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-dig-numa --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-dig-numa Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-dig-numa Sat Mar 30 22:55:25 2002 @@ -0,0 +1,460 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_NUMA=y +CONFIG_DISCONTIGMEM=y +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,459 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,459 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +# CONFIG_IA64_MCA is not set +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +# CONFIG_IA32_SUPPORT is not set +# CONFIG_PERFMON is not set +# CONFIG_IA64_PALINFO is not set +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +# CONFIG_SCSI 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_SUPPORT is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-mp linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-mp --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,730 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +CONFIG_IA64_SGI_SN2=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_MCKINLEY_ASTEP_SPECIFIC=y +CONFIG_MCKINLEY_A0_SPECIFIC=y +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Sat Mar 30 22:55:25 2002 @@ -0,0 +1,732 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +CONFIG_IA64_SGI_SN2=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_MCKINLEY_ASTEP_SPECIFIC=y +CONFIG_MCKINLEY_A0_SPECIFIC=y +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +# CONFIG_SERIAL_SGI_L1_PROTOCOL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Sat Mar 30 22:55:25 2002 @@ -0,0 +1,537 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +CONFIG_IA64_SGI_SN2=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_MCKINLEY_ASTEP_SPECIFIC=y +CONFIG_MCKINLEY_A0_SPECIFIC=y +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +# CONFIG_IA32_SUPPORT is not set +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y +# CONFIG_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# Networking support is needed for USB Networking device support +# + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -urN linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-sp linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-sp --- linux-2.4.18/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Sat Mar 30 22:55:25 2002 @@ -0,0 +1,730 @@ +# +# 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=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +CONFIG_IA64_SGI_SN2=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_MCKINLEY_ASTEP_SPECIFIC=y +CONFIG_MCKINLEY_A0_SPECIFIC=y +CONFIG_IA64_SGI_SN=y +CONFIG_IA64_SGI_SN_DEBUG=y +CONFIG_IA64_SGI_SN_SIM=y +CONFIG_IA64_SGI_AUTOTEST=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_SERIAL_SGI_L1_PROTOCOL=y +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_PERCPU_IRQ=y +CONFIG_PCIBA=y +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate 1394 support +# +# CONFIG_X1394 is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_SBP2 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# 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 + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_SUPPORT=y + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="n" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +CONFIG_KALLSYMS=y diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/Makefile linux-2.4.19-pre5/arch/ia64/sn/fakeprom/Makefile --- linux-2.4.18/arch/ia64/sn/fakeprom/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/Makefile Sat Mar 30 22:55:25 2002 @@ -0,0 +1,30 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved. +# + +TOPDIR=../../../.. +HPATH = $(TOPDIR)/include + +LIB = ../../lib/lib.a + +OBJ=fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o +obj-y=fprom + +fprom: $(OBJ) + $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -c -o $*.o $< + +clean: + rm -f *.o fprom + + +include $(TOPDIR)/Rules.make + diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/README linux-2.4.19-pre5/arch/ia64/sn/fakeprom/README --- linux-2.4.18/arch/ia64/sn/fakeprom/README Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/README Sat Mar 30 22:55:25 2002 @@ -0,0 +1,85 @@ +This directory contains the files required to build +the fake PROM image that is currently being used to +boot IA64 kernels running under the SGI Medusa kernel. + +The FPROM currently provides the following functions: + + - PAL emulation for all PAL calls we've made so far. + - SAL emulation for all SAL calls we've made so far. + - EFI emulation for all EFI calls we've made so far. + - builds the "ia64_bootparam" structure that is + passed to the kernel from SAL. This structure + shows the cpu & memory configurations. + - supports medusa boottime options for changing + the number of cpus present + - supports medusa boottime options for changing + the memory configuration. + + + +At some point, this fake PROM will be replaced by the +real PROM. + + + + +To build a fake PROM, cd to this directory & type: + + make + +This will (or should) build a fake PROM named "fprom". + + + + +Use this fprom image when booting the Medusa simulator. The +control file used to boot Medusa should include the +following lines: + + load fprom + load vmlinux + sr pc 0x100000 + sr g 9
#(currently 0xe000000000520000) + +NOTE: There is a script "runsim" in this directory that can be used to +simplify setting up an environment for running under Medusa. + + + + +The following parameters may be passed to the fake PROM to +control the PAL/SAL/EFI parameters passed to the kernel: + + GR[8] = # of cpus + GR[9] = address of primary entry point into the kernel + GR[20] = memory configuration for node 0 + GR[21] = memory configuration for node 1 + GR[22] = memory configuration for node 2 + GR[23] = memory configuration for node 3 + + +Registers GR[20] - GR[23] contain information to specify the +amount of memory present on nodes 0-3. + + - if nothing is specified (all registers are 0), the configuration + defaults to 8 MB on node 0. + + - a mem config entry for node N is passed in GR[20+N] + + - a mem config entry consists of 8 hex digits. Each digit gives the + amount of physical memory available on the node starting at + 1GB*, where dn is the digit number. The amount of memory + is 8MB*2**. (If = 0, the memory size is 0). + + SN1 doesnt support dimms this small but small memory systems + boot faster on Medusa. + + + +An example helps a lot. The following specifies that node 0 has +physical memory 0 to 8MB and 1GB to 1GB+32MB, and that node 1 has +64MB starting at address 0 of the node which is 8GB. + + gr[20] = 0x21 # 0 to 8MB, 1GB to 1GB+32MB + gr[21] = 0x4 # 8GB to 8GB+64MB + diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/fpmem.c linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fpmem.c --- linux-2.4.18/arch/ia64/sn/fakeprom/fpmem.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fpmem.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,266 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + + + +/* + * FPROM EFI memory descriptor build routines + * + * - Routines to build the EFI memory descriptor map + * - Should also be usable by the SGI SN1 prom to convert + * klconfig to efi_memmap + */ + +#include +#include +#include "fpmem.h" + +/* + * args points to a layout in memory like this + * + * 32 bit 32 bit + * + * numnodes numcpus + * + * 16 bit 16 bit 32 bit + * nasid0 cpuconf membankdesc0 + * nasid1 cpuconf membankdesc1 + * . + * . + * . + * . + * . + */ + +sn_memmap_t *sn_memmap ; +sn_config_t *sn_config ; + +/* + * There is a hole in the node 0 address space. Dont put it + * in the memory map + */ +#define NODE0_HOLE_SIZE (20*MB) +#define NODE0_HOLE_END (4UL*GB) + +#define MB (1024*1024) +#define GB (1024*MB) +#define KERNEL_SIZE (4*MB) +#define PROMRESERVED_SIZE (1*MB) + +#ifdef CONFIG_IA64_SGI_SN1 +#define PHYS_ADDRESS(_n, _x) (((long)_n<<33L) | (long)_x) +#define MD_BANK_SHFT 30 +#else +#define PHYS_ADDRESS(_n, _x) (((long)_n<<38L) | (long)_x | 0x3000000000UL) +#define MD_BANK_SHFT 34 +#endif + +/* + * For SN, this may not take an arg and gets the numnodes from + * the prom variable or by traversing klcfg or promcfg + */ +int +GetNumNodes(void) +{ + return sn_config->nodes; +} + +int +GetNumCpus(void) +{ + return sn_config->cpus; +} + +/* For SN1, get the index th nasid */ + +int +GetNasid(int index) +{ + return sn_memmap[index].nasid ; +} + +node_memmap_t +GetMemBankInfo(int index) +{ + return sn_memmap[index].node_memmap ; +} + +int +IsCpuPresent(int cnode, int cpu) +{ + return sn_memmap[cnode].cpuconfig & (1<type = type; + md->phys_addr = paddr; + md->virt_addr = 0; + md->num_pages = numbytes >> 12; + md->attribute = EFI_MEMORY_WB; +} + +int +build_efi_memmap(void *md, int mdsize) +{ + int numnodes = GetNumNodes() ; + int cnode,bank ; + int nasid ; + node_memmap_t membank_info ; + int bsize; + int count = 0 ; + long paddr, hole, numbytes; + + + for (cnode=0;cnode + +/* + * Structure of the mem config of the node as a SN1 MI reg + * Medusa supports this reg config. + * + * BankSize nibble to bank size mapping + * + * 1 - 64 MB + * 2 - 128 MB + * 3 - 256 MB + * 4 - 512 MB + * 5 - 1024 MB (1GB) + */ + +#define MBSHIFT 20 + +#ifdef CONFIG_IA64_SGI_SN1 +typedef struct node_memmap_s +{ + unsigned int b0 :1, /* 0 bank 0 present */ + b1 :1, /* 1 bank 1 present */ + r01 :2, /* 2-3 reserved */ + b01size :4, /* 4-7 Size of bank 0 and 1 */ + b2 :1, /* 8 bank 2 present */ + b3 :1, /* 9 bank 3 present */ + r23 :2, /* 10-11 reserved */ + b23size :4, /* 12-15 Size of bank 2 and 3 */ + b4 :1, /* 16 bank 4 present */ + b5 :1, /* 17 bank 5 present */ + r45 :2, /* 18-19 reserved */ + b45size :4, /* 20-23 Size of bank 4 and 5 */ + b6 :1, /* 24 bank 6 present */ + b7 :1, /* 25 bank 7 present */ + r67 :2, /* 26-27 reserved */ + b67size :4; /* 28-31 Size of bank 6 and 7 */ +} node_memmap_t ; + +/* Support the medusa hack for 8M/16M/32M nodes */ +#define SN1_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ +#define BankSizeBytes(bsize) ((bsize<6) ? (1<<((bsize-1)+SN1_BANK_SIZE_SHIFT)) :\ + (1<<((bsize-9)+MBSHIFT))) +#else +typedef struct node_memmap_s +{ + unsigned int b0size :3, /* 0-2 bank 0 size */ + b0dou :1, /* 3 bank 0 is 2-sided */ + ena0 :1, /* 4 bank 0 enabled */ + r0 :3, /* 5-7 reserved */ + b1size :3, /* 8-10 bank 1 size */ + b1dou :1, /* 11 bank 1 is 2-sided */ + ena1 :1, /* 12 bank 1 enabled */ + r1 :3, /* 13-15 reserved */ + b2size :3, /* 16-18 bank 2 size */ + b2dou :1, /* 19 bank 1 is 2-sided */ + ena2 :1, /* 20 bank 2 enabled */ + r2 :3, /* 21-23 reserved */ + b3size :3, /* 24-26 bank 3 size */ + b3dou :1, /* 27 bank 3 is 2-sided */ + ena3 :1, /* 28 bank 3 enabled */ + r3 :3; /* 29-31 reserved */ +} node_memmap_t ; + +#define SN2_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ +#define BankPresent(bsize) (bsize<6) +#define BankSizeBytes(bsize) (BankPresent(bsize) ? 1UL<<((bsize)+SN2_BANK_SIZE_SHIFT) : 0) +#endif + +typedef struct sn_memmap_s +{ + short nasid ; + short cpuconfig; + node_memmap_t node_memmap ; +} sn_memmap_t ; + +typedef struct sn_config_s +{ + int cpus; + int nodes; + sn_memmap_t memmap[1]; /* start of array */ +} sn_config_t; + + + +extern void build_init(unsigned long); +extern int build_efi_memmap(void *, int); +extern int GetNumNodes(void); +extern int GetNumCpus(void); +extern int IsCpuPresent(int, int); +extern int GetNasid(int); diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/fprom.lds linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fprom.lds --- linux-2.4.18/arch/ia64/sn/fakeprom/fprom.lds Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fprom.lds Sat Mar 30 22:55:25 2002 @@ -0,0 +1,96 @@ + +OUTPUT_FORMAT("elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +SECTIONS +{ + v = 0x0000000000000000 ; /* this symbol is here to make debugging with kdb easier... */ + + . = (0x000000000000000 + 0x100000) ; + + _text = .; + .text : AT(ADDR(.text) - 0x0000000000000000 ) + { + *(__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) + } + + /* Global data */ + _data = .; + + .rodata : AT(ADDR(.rodata) - 0x0000000000000000 ) + { *(.rodata) *(.rodata.*) } + .opd : AT(ADDR(.opd) - 0x0000000000000000 ) + { *(.opd) } + .data : AT(ADDR(.data) - 0x0000000000000000 ) + { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } + + __gp = ALIGN (8) + 0x200000; + + .got : AT(ADDR(.got) - 0x0000000000000000 ) + { *(.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) - 0x0000000000000000 ) + { *(.sdata) } + _edata = .; + _bss = .; + .sbss : AT(ADDR(.sbss) - 0x0000000000000000 ) + { *(.sbss) *(.scommon) } + .bss : AT(ADDR(.bss) - 0x0000000000000000 ) + { *(.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 -urN linux-2.4.18/arch/ia64/sn/fakeprom/fpromasm.S linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fpromasm.S --- linux-2.4.18/arch/ia64/sn/fakeprom/fpromasm.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fpromasm.S Sat Mar 30 22:55:25 2002 @@ -0,0 +1,403 @@ +/* + * + * 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. + * + * (Code copied from or=ther files) + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + + + +#define __ASSEMBLY__ 1 +#include +#include +#include +#include + +/* + * This file contains additional set up code that is needed to get going on + * Medusa. This code should disappear once real hw is available. + * + * On entry to this routine, the following register values are assumed: + * + * gr[8] - BSP cpu + * pr[9] - kernel entry address + * pr[10] - cpu number on the node + * + * NOTE: + * This FPROM may be loaded/executed at an address different from the + * address that it was linked at. The FPROM is linked to run on node 0 + * at address 0x100000. If the code in loaded into another node, it + * must be loaded at offset 0x100000 of the node. In addition, the + * FPROM does the following things: + * - determine the base address of the node it is loaded on + * - add the node base to _gp. + * - add the node base to all addresses derived from "movl" + * instructions. (I couldnt get GPREL addressing to work) + * (maybe newer versions of the tools will support this) + * - scan the .got section and add the node base to all + * pointers in this section. + * - add the node base to all physical addresses in the + * SAL/PAL/EFI table built by the C code. (This is done + * in the C code - not here) + * - add the node base to the TLB entries for vmlinux + */ + +#define KERNEL_BASE 0xe000000000000000 +#define BOOT_PARAM_ADDR 0x40000 + + +/* + * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should + * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) + * IOSPEC_BASE value + */ +#ifdef CONFIG_IA64_SGI_SN1 +#define IOPB_PA 0xc0000FFFFC000000 +#else +#define IOPB_PA 0xc000000fcc000000 +#endif + +#define RR_RID 8 + + + +// ==================================================================================== + .text + .align 16 + .global _start + .proc _start +_start: + +// Setup psr and rse for system init + mov psr.l = r0;; + srlz.d;; + invala + mov ar.rsc = r0;; + loadrs + ;; + +// Isolate node number we are running on. + mov r6 = ip;; +#ifdef CONFIG_IA64_SGI_SN1 + shr r5 = r6,33;; // r5 = node number + shl r6 = r5,33 // r6 = base memory address of node +#else + shr r5 = r6,38 // r5 = node number + dep r6 = 0,r6,0,36 // r6 = base memory address of node + +#endif + + +// Set & relocate gp. + movl r1= __gp;; // Add base memory address + or r1 = r1,r6 // Relocate to boot node + +// Lets figure out who we are & put it in the LID register. +#ifdef CONFIG_IA64_SGI_SN2 +// On SN2, we (currently) pass the cpu number in r10 at boot + and r25=3,r10;; + movl r16=0x8000008110000400 // Allow IPIs + mov r17=-1;; + st8 [r16]=r17 + movl r16=0x8000008110060580;; // SHUB_ID + ld8 r27=[r16];; + extr.u r27=r27,32,11;; + shl r26=r25,28;; // Align local cpu# to lid.eid + shl r27=r27,16;; // Align NASID to lid.id + or r26=r26,r27;; // build the LID +#else +// The BR_PI_SELF_CPU_NUM register gives us a value of 0-3. +// This identifies the cpu on the node. +// Merge the cpu number with the NASID to generate the LID. + movl r24=0x80000a0001000020;; // BR_PI_SELF_CPU_NUM + ld8 r25=[r24] // Fetch PI_SELF + movl r27=0x80000a0001600000;; // Fetch REVID to get local NASID + ld8 r27=[r27];; + extr.u r27=r27,32,8;; + shl r26=r25,16;; // Align local cpu# to lid.eid + shl r27=r27,24;; // Align NASID to lid.id + or r26=r26,r27;; // build the LID +#endif + mov cr.lid=r26 // Now put in in the LID register + + movl r2=FPSR_DEFAULT;; + mov ar.fpsr=r2 + movl sp = bootstacke-16;; + or sp = sp,r6 // Relocate to boot node + +// Save the NASID that we are loaded on. + movl r2=base_nasid;; // Save base_nasid for C code + or r2 = r2,r6;; // Relocate to boot node + st8 [r2]=r5 // Uncond st8 - same on all cpus + +// Save the kernel entry address. It is passed in r9 on one of +// the cpus. + movl r2=bsp_entry_pc + cmp.ne p6,p0=r9,r0;; + or r2 = r2,r6;; // Relocate to boot node +(p6) st8 [r2]=r9 // Uncond st8 - same on all cpus + + +// The following can ONLY be done by 1 cpu. Lets set a lock - the +// cpu that gets it does the initilization. The rest just spin waiting +// til initilization is complete. + movl r22 = initlock;; + or r22 = r22,r6 // Relocate to boot node + mov r23 = 1;; + xchg8 r23 = [r22],r23;; + cmp.eq p6,p0 = 0,r23 +(p6) br.cond.spnt.few init +1: ld4 r23 = [r22];; + cmp.eq p6,p0 = 1,r23 +(p6) br.cond.sptk 1b + br initx + +// Add base address of node memory to each pointer in the .got section. +init: movl r16 = _GLOBAL_OFFSET_TABLE_;; + or r16 = r16,r6;; // Relocate to boot node +1: ld8 r17 = [r16];; + cmp.eq p6,p7=0,r17 +(p6) br.cond.sptk.few.clr 2f;; + or r17 = r17,r6;; // Relocate to boot node + st8 [r16] = r17,8 + br 1b +2: + mov r23 = 2;; // All done, release the spinning cpus + st4 [r22] = r23 +initx: + +// +// I/O-port space base address: +// + movl r2 = IOPB_PA;; + mov ar.k0 = r2 + + +// Now call main & pass it the current LID value. + alloc r0=ar.pfs,0,0,2,0 + mov r32=r26 + mov r33=r8;; + br.call.sptk.few rp=fmain + +// Initialize Region Registers +// + mov r10 = r0 + mov r2 = (13<<2) + mov r3 = r0;; +1: cmp4.gtu p6,p7 = 7, r3 + dep r10 = r3, r10, 61, 3 + dep r2 = r3, r2, RR_RID, 4;; +(p7) dep r2 = 0, r2, 0, 1;; +(p6) dep r2 = -1, r2, 0, 1;; + mov rr[r10] = r2 + add r3 = 1, r3;; + srlz.d;; + cmp4.gtu p6,p0 = 8, r3 +(p6) br.cond.sptk.few.clr 1b + +// +// Return value indicates if we are the BSP or AP. +// 1 = BSP, 0 = AP + mov cr.tpr=r0;; + cmp.eq p6,p0=r8,r0 +(p6) br.cond.spnt slave + +// +// Go to kernel C startup routines +// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. +// This is the only way to set them. + + movl r28=BOOT_PARAM_ADDR + movl r2=bsp_entry_pc;; + or r28 = r28,r6;; // Relocate to boot node + or r2 = r2,r6;; // Relocate to boot node + ld8 r2=[r2];; + or r2=r2,r6;; + dep r2=0,r2,61,3;; // convert to phys mode + +// +// Turn on address translation, interrupt collection, psr.ed, protection key. +// Interrupts (PSR.i) are still off here. +// + + movl r3 = ( IA64_PSR_BN | \ + IA64_PSR_AC | \ + IA64_PSR_DB | \ + IA64_PSR_DA | \ + IA64_PSR_IC \ + ) + ;; + mov cr.ipsr = r3 + +// +// Go to kernel C startup routines +// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. +// This is the only way to set them. + + mov r8=r28;; + bsw.1 ;; + mov r28=r8;; + bsw.0 ;; + mov cr.iip = r2 + srlz.d;; + rfi;; + + .endp _start + + + +// Slave processors come here to spin til they get an interrupt. Then they launch themselves to +// the place ap_entry points. No initialization is necessary - the kernel makes no +// assumptions about state on this entry. +// Note: should verify that the interrupt we got was really the ap_wakeup +// interrupt but this should not be an issue on medusa +slave: + nop.i 0x8beef // Medusa - put cpu to sleep til interrupt occurs + mov r8=cr.irr0;; // Check for interrupt pending. + cmp.eq p6,p0=r8,r0 +(p6) br.cond.sptk slave;; + + mov r8=cr.ivr;; // Got one. Must read ivr to accept it + srlz.d;; + mov cr.eoi=r0;; // must write eoi to clear + movl r8=ap_entry;; // now jump to kernel entry + or r8 = r8,r6;; // Relocate to boot node + ld8 r9=[r8],8;; + ld8 r1=[r8] + mov b0=r9;; + br b0 + +// Here is the kernel stack used for the fake PROM + .bss + .align 16384 +bootstack: + .skip 16384 +bootstacke: +initlock: + data4 + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// This code emulates the PAL. Only essential interfaces are emulated. + + + .text + .global pal_emulator + .proc pal_emulator +pal_emulator: + mov r8=-1 + + mov r9=256 + ;; + cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ +(p6) br.cond.sptk.few static + ;; + mov r9=512 + ;; + cmp.gtu p6,p7=r9,r28 +(p6) br.cond.sptk.few stacked + ;; + +static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ +(p7) br.cond.sptk.few 1f + movl r8=0 /* status = 0 */ + movl r9=0x100000000 /* tc.base */ + movl r10=0x0000000200000003 /* count[0], count[1] */ + movl r11=0x1000000000002000 /* stride[0], stride[1] */ + ;; + +1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ +(p7) br.cond.sptk.few 1f + movl r8=0 /* status = 0 */ + movl r9 =0x100000064 /* proc_ratio (1/100) */ + movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ + movl r11=0x10000000a /* itc_ratio<<32 (1/100) */ + ;; + +1: cmp.eq p6,p7=8,r28 /* PAL_VM_SUMMARY */ +(p7) br.cond.sptk.few 1f + movl r8=0 +#ifdef CONFIG_IA64_SGI_SN1 + movl r9=0x0203083001151059 + movl r10=0x1232 +#else + movl r9=0x0203083001151065 + movl r10=0x183f +#endif + movl r11=0 + ;; + +1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ +(p7) br.cond.sptk.few 1f + movl r8=0 + movl r9=0x60 + movl r10=0x0 + movl r11=0 + ;; + +1: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */ +(p7) br.cond.sptk.few 1f + movl r8=0 + movl r9=0x08122004 + movl r10=0x0 + movl r11=0 + mov r2=ar.lc + mov r3=16;; + mov ar.lc=r3 + mov r3=r29;; +5: st8 [r3]=r0,8 + br.cloop.sptk.few 5b;; + mov ar.lc=r2 + mov r3=r29 + movl r2=0x1fff;; /* PMC regs */ + st8 [r3]=r2 + add r3=32,r3 + movl r2=0x3ffff;; /* PMD regs */ + st8 [r3]=r2 + add r3=32,r3 + movl r2=0xf0;; /* cycle regs */ + st8 [r3]=r2 + add r3=32,r3 + movl r2=0x10;; /* retired regs */ + st8 [r3]=r2 + ;; + +1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ +(p7) br.cond.sptk.few 1f + movl r8=0 /* status = 0 */ + movl r9=96 /* num phys stacked */ + movl r10=0 /* hints */ + movl r11=0 + ;; + +1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ +(p7) br.cond.sptk.few 1f + mov r9=ar.lc + movl r8=524288 /* flush 512k million cache lines (16MB) */ + ;; + mov ar.lc=r8 + movl r8=0xe000000000000000 + ;; +.loop: fc r8 + add r8=32,r8 + br.cloop.sptk.few .loop + sync.i + ;; + srlz.i + ;; + mov ar.lc=r9 + mov r8=r0 +1: br.cond.sptk.few rp + +stacked: + br.ret.sptk.few rp + + .endp pal_emulator + diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/fw-emu.c linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fw-emu.c --- linux-2.4.18/arch/ia64/sn/fakeprom/fw-emu.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/fw-emu.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,836 @@ +/* + * PAL & SAL emulation. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_IA64_SGI_SN2 +#include +#include +#endif +#include +#include "fpmem.h" + +#define zzACPI_1_0 1 /* Include ACPI 1.0 tables */ + +#define OEMID "SGI" +#ifdef CONFIG_IA64_SGI_SN1 +#define PRODUCT "SN1" +#define PROXIMITY_DOMAIN(nasid) (nasid) +#else +#define PRODUCT "SN2" +#define PROXIMITY_DOMAIN(nasid) (((nasid)>>1) & 255) +#endif + +#define MB (1024*1024UL) +#define GB (MB*1024UL) +#define BOOT_PARAM_ADDR 0x40000 +#define MAX(i,j) ((i) > (j) ? (i) : (j)) +#define MIN(i,j) ((i) < (j) ? (i) : (j)) +#define ABS(i) ((i) > 0 ? (i) : -(i)) +#define ALIGN8(p) (((long)(p) +7) & ~7) + +#define FPROM_BUG() do {while (1);} while (0) +#define MAX_SN_NODES 128 +#define MAX_LSAPICS 512 +#define MAX_CPUS 512 +#define MAX_CPUS_NODE 4 +#define CPUS_PER_NODE 4 +#define CPUS_PER_FSB 2 +#define CPUS_PER_FSB_MASK (CPUS_PER_FSB-1) + +#ifdef ACPI_1_0 +#define NUM_EFI_DESCS 3 +#else +#define NUM_EFI_DESCS 2 +#endif + +#define RSDP_CHECKSUM_LENGTH 20 + +typedef union ia64_nasid_va { + struct { +#if defined(CONFIG_IA64_SGI_SN1) + unsigned long off : 33; /* intra-region offset */ + unsigned long nasid : 7; /* NASID */ + unsigned long off2 : 21; /* fill */ + unsigned long reg : 3; /* region number */ +#elif defined(CONFIG_IA64_SGI_SN2) + unsigned long off : 36; /* intra-region offset */ + unsigned long attr : 2; + unsigned long nasid : 11; /* NASID */ + unsigned long off2 : 12; /* fill */ + unsigned long reg : 3; /* region number */ +#endif + } f; + unsigned long l; + void *p; +} ia64_nasid_va; + +typedef struct { + unsigned long pc; + unsigned long gp; +} func_ptr_t; + +#define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;}) +#define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p))) + +#if defined(CONFIG_IA64_SGI_SN1) +#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.l;}) +#elif defined(CONFIG_IA64_SGI_SN2) +#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.f.attr = 3; _v.l;}) +#endif + +/* + * The following variables are passed thru registersfrom the configuration file and + * are set via the _start function. + */ +long base_nasid; +long num_cpus; +long bsp_entry_pc=0; +long num_nodes; +long app_entry_pc; +int bsp_lid; +func_ptr_t ap_entry; + + +extern void pal_emulator(void); +static efi_runtime_services_t *efi_runtime_p; +static char fw_mem[( sizeof(efi_system_table_t) + + sizeof(efi_runtime_services_t) + + NUM_EFI_DESCS*sizeof(efi_config_table_t) + + sizeof(struct ia64_sal_systab) + + sizeof(struct ia64_sal_desc_entry_point) + + sizeof(struct ia64_sal_desc_ap_wakeup) +#ifdef ACPI_1_0 + + sizeof(acpi_rsdp_t) + + sizeof(acpi_rsdt_t) + + sizeof(acpi_sapic_t) + + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t)) +#endif + + sizeof(acpi20_rsdp_t) + + sizeof(acpi_xsdt_t) + + sizeof(acpi_slit_t) + + MAX_SN_NODES*MAX_SN_NODES+8 + + sizeof(acpi_madt_t) + + 16*MAX_CPUS + + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t)) + + sizeof(acpi_srat_t) + + MAX_CPUS*sizeof(srat_cpu_affinity_t) + + MAX_SN_NODES*sizeof(srat_memory_affinity_t) + + sizeof(ia64_sal_desc_ptc_t) + + + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) + + + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) + + + 1024)] __attribute__ ((aligned (8))); + + +static efi_status_t +efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) +{ + if (tm) { + memset(tm, 0, sizeof(*tm)); + tm->year = 2000; + tm->month = 2; + tm->day = 13; + tm->hour = 10; + tm->minute = 11; + tm->second = 12; + } + + if (tc) { + tc->resolution = 10; + tc->accuracy = 12; + tc->sets_to_zero = 1; + } + + return EFI_SUCCESS; +} + +static void +efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) +{ + while(1); /* Is there a pseudo-op to stop medusa */ +} + +static efi_status_t +efi_success (void) +{ + return EFI_SUCCESS; +} + +static efi_status_t +efi_unimplemented (void) +{ + return EFI_UNSUPPORTED; +} + +#ifdef CONFIG_IA64_SGI_SN2 + +#undef cpu_physical_id +#define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) + +void +fprom_send_cpei(void) { + long *p, val; + long physid; + long nasid, slice; + + physid = cpu_physical_id(0); + nasid = cpu_physical_id_to_nasid(physid); + slice = cpu_physical_id_to_slice(physid); + + p = (long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT); + val = (1UL<pc = in2; + fp->gp = in3; + } else if (in1 == SAL_VECTOR_OS_MCA || in1 == SAL_VECTOR_OS_INIT) { + } else { + status = -1; + } + ; + } 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) { + ; + } else if (index == SAL_UPDATE_PAL) { + ; +#ifdef CONFIG_IA64_SGI_SN2 + } else if (index == SN_SAL_LOG_CE) { +#ifdef ajmtestcpei + fprom_send_cpei(); +#else /* ajmtestcpei */ + ; +#endif /* ajmtestcpei */ +#endif + } else if (index == SN_SAL_PROBE) { + r9 = 0UL; + if (in2 == 4) { + r9 = *(unsigned *)in1; + if (r9 == -1) { + status = 1; + } + } else if (in2 == 2) { + r9 = *(unsigned short *)in1; + if (r9 == -1) { + status = 1; + } + } else if (in2 == 1) { + r9 = *(unsigned char *)in1; + if (r9 == -1) { + status = 1; + } + } else if (in2 == 8) { + r9 = *(unsigned long *)in1; + if (r9 == -1) { + status = 1; + } + } else { + status = 2; + } + } else if (index == SN_SAL_GET_KLCONFIG_ADDR) { + r9 = 0x30000; + } else if (index == SN_SAL_CONSOLE_PUTC) { + status = -1; + } else if (index == SN_SAL_CONSOLE_GETC) { + status = -1; + } else if (index == SN_SAL_CONSOLE_POLL) { + status = -1; + } 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; +} + + +/* + * Fix the addresses in a function pointer by adding base node address + * to pc & gp. + */ +void +fix_function_pointer(void *fp) +{ + func_ptr_t *_fp; + + _fp = fp; + _fp->pc = __fwtab_pa(base_nasid, _fp->pc); + _fp->gp = __fwtab_pa(base_nasid, _fp->gp); +} + +void +fix_virt_function_pointer(void **fptr) +{ + func_ptr_t *fp; + long *p; + + p = (long*)fptr; + fp = *fptr; + fp->pc = fp->pc | PAGE_OFFSET; + fp->gp = fp->gp | PAGE_OFFSET; + *p |= PAGE_OFFSET; +} + + +int +efi_set_virtual_address_map(void) +{ + efi_runtime_services_t *runtime; + + runtime = efi_runtime_p; + fix_virt_function_pointer((void**)&runtime->get_time); + fix_virt_function_pointer((void**)&runtime->set_time); + fix_virt_function_pointer((void**)&runtime->get_wakeup_time); + fix_virt_function_pointer((void**)&runtime->set_wakeup_time); + fix_virt_function_pointer((void**)&runtime->set_virtual_address_map); + fix_virt_function_pointer((void**)&runtime->get_variable); + fix_virt_function_pointer((void**)&runtime->get_next_variable); + fix_virt_function_pointer((void**)&runtime->set_variable); + fix_virt_function_pointer((void**)&runtime->get_next_high_mono_count); + fix_virt_function_pointer((void**)&runtime->reset_system); + return EFI_SUCCESS;; +} + +void +acpi_table_init(acpi_desc_table_hdr_t *p, char *sig, int siglen, int revision, int oem_revision) +{ + memcpy(p->signature, sig, siglen); + memcpy(p->oem_id, OEMID, 6); + memcpy(p->oem_table_id, sig, 4); + memcpy(p->oem_table_id+4, PRODUCT, 4); + p->revision = revision; + p->oem_revision = (revision<<16) + oem_revision; + p->creator_id = 1; + p->creator_revision = 1; +} + +void +acpi_checksum(acpi_desc_table_hdr_t *p, int length) +{ + u8 *cp, *cpe, checksum; + + p->checksum = 0; + p->length = length; + checksum = 0; + for (cp=(u8*)p, cpe=cp+p->length; cpchecksum = -checksum; +} + +void +acpi_checksum_rsdp20(acpi20_rsdp_t *p, int length) +{ + u8 *cp, *cpe, checksum; + + p->checksum = 0; + p->length = length; + checksum = 0; + for (cp=(u8*)p, cpe=cp+RSDP_CHECKSUM_LENGTH; cpchecksum = -checksum; +} + +int +nasid_present(int nasid) +{ + int cnode; + for (cnode=0; cnode= 1024) + arglen = 1023; + memcpy(cmd_line, args, arglen); + } else { + arglen = 0; + } + cmd_line[arglen] = '\0'; + /* + * For now, just bring up bash. + * If you want to execute all the startup scripts, delete the "init=..". + * You can also edit this line to pass other arguments to the kernel. + * Note: disable kernel text replication. + */ + strcpy(cmd_line, "init=/bin/bash ktreplicate=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 = __fwtab_pa(base_nasid, vendor); + efi_systab->fw_revision = 1; + efi_systab->runtime = __fwtab_pa(base_nasid, efi_runtime); + efi_systab->nr_tables = 2; + efi_systab->tables = __fwtab_pa(base_nasid, efi_tables); + memcpy(vendor, "S\0i\0l\0i\0c\0o\0n\0-\0G\0r\0a\0p\0h\0i\0c\0s\0\0", 40); + + 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 = __fwtab_pa(base_nasid, &efi_get_time); + efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map); + efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->get_next_high_mono_count = __fwtab_pa(base_nasid, &efi_unimplemented); + efi_runtime->reset_system = __fwtab_pa(base_nasid, &efi_reset_system); + + efi_tables->guid = SAL_SYSTEM_TABLE_GUID; + efi_tables->table = __fwtab_pa(base_nasid, sal_systab); + efi_tables++; +#ifdef ACPI_1_0 + efi_tables->guid = ACPI_TABLE_GUID; + efi_tables->table = __fwtab_pa(base_nasid, acpi_rsdp); + efi_tables++; +#endif + efi_tables->guid = ACPI_20_TABLE_GUID; + efi_tables->table = __fwtab_pa(base_nasid, acpi20_rsdp); + efi_tables++; + + fix_function_pointer(&efi_unimplemented); + fix_function_pointer(&efi_get_time); + fix_function_pointer(&efi_success); + fix_function_pointer(&efi_reset_system); + fix_function_pointer(&efi_set_virtual_address_map); + +#ifdef ACPI_1_0 + /* fill in the ACPI system table - has a pointer to the ACPI table header */ + memcpy(acpi_rsdp->signature, "RSD PTR ", 8); + acpi_rsdp->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt); + + acpi_table_init(&acpi_rsdt->header, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN, 1, 1); + acpi_rsdt->header.length = sizeof(acpi_rsdt_t); + acpi_rsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_sapic); + + memcpy(acpi_sapic->header.signature, "SPIC ", 4); + acpi_sapic->header.length = sizeof(acpi_sapic_t)+num_cpus*sizeof(acpi_entry_lsapic_t); + + for (cnode=0; cnodetype = ACPI_ENTRY_LOCAL_SAPIC; + acpi_lsapic->length = sizeof(acpi_entry_lsapic_t); + acpi_lsapic->acpi_processor_id = cnode*4+cpu; + acpi_lsapic->flags = LSAPIC_ENABLED|LSAPIC_PRESENT; +#if defined(CONFIG_IA64_SGI_SN1) + acpi_lsapic->eid = cpu; + acpi_lsapic->id = nasid; +#else + acpi_lsapic->eid = nasid&0xffff; + acpi_lsapic->id = (cpu<<4) | (nasid>>16); +#endif + acpi_lsapic++; + } + } +#endif + + + /* fill in the ACPI20 system table - has a pointer to the ACPI table header */ + memcpy(acpi20_rsdp->signature, "RSD PTR ", 8); + acpi20_rsdp->xsdt = (struct acpi_xsdt*)__fwtab_pa(base_nasid, acpi_xsdt); + acpi20_rsdp->revision = 2; + acpi_checksum_rsdp20(acpi20_rsdp, sizeof(acpi20_rsdp_t)); + + /* Set up the XSDT table - contains pointers to the other ACPI tables */ + acpi_table_init(&acpi_xsdt->header, ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN, 1, 1); + acpi_xsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_madt); + acpi_xsdt->entry_ptrs[1] = __fwtab_pa(base_nasid, acpi_slit); + acpi_xsdt->entry_ptrs[2] = __fwtab_pa(base_nasid, acpi_srat); + acpi_checksum(&acpi_xsdt->header, sizeof(acpi_xsdt_t) + 16); + + /* Set up the MADT table */ + acpi_table_init(&acpi_madt->header, ACPI_MADT_SIG, ACPI_MADT_SIG_LEN, 1, 1); + lsapic20 = (acpi20_entry_lsapic_t*) (acpi_madt + 1); + for (cnode=0; cnodetype = ACPI20_ENTRY_LOCAL_SAPIC; + lsapic20->length = sizeof(acpi_entry_lsapic_t); + lsapic20->acpi_processor_id = cnode*4+cpu; + lsapic20->flags = LSAPIC_ENABLED|LSAPIC_PRESENT; +#if defined(CONFIG_IA64_SGI_SN1) + lsapic20->eid = cpu; + lsapic20->id = nasid; +#else + lsapic20->eid = nasid&0xffff; + lsapic20->id = (cpu<<4) | (nasid>>16); +#endif + lsapic20 = (acpi20_entry_lsapic_t*) ((long)lsapic20+sizeof(acpi_entry_lsapic_t)); + } + } + acpi_checksum(&acpi_madt->header, (char*)lsapic20 - (char*)acpi_madt); + + /* Set up the SRAT table */ + acpi_table_init(&acpi_srat->header, ACPI_SRAT_SIG, ACPI_SRAT_SIG_LEN, ACPI_SRAT_REVISION, 1); + ptr = acpi_srat+1; + for (cnode=0; cnodetype = SRAT_MEMORY_STRUCTURE; + srat_memory_affinity->length = sizeof(srat_memory_affinity_t); + srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); + srat_memory_affinity->base_addr_lo = 0; + srat_memory_affinity->length_lo = 0; +#if defined(CONFIG_IA64_SGI_SN1) + srat_memory_affinity->base_addr_hi = nasid<<1; + srat_memory_affinity->length_hi = SN1_NODE_SIZE>>32; +#else + srat_memory_affinity->base_addr_hi = (nasid<<6) | (3<<4); + srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32; +#endif + srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY; + srat_memory_affinity->flags = SRAT_MEMORY_FLAGS_ENABLED; + } + + for (cnode=0; cnodetype = SRAT_CPU_STRUCTURE; + srat_cpu_affinity->length = sizeof(srat_cpu_affinity_t); + srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); + srat_cpu_affinity->flags = SRAT_CPU_FLAGS_ENABLED; +#if defined(CONFIG_IA64_SGI_SN1) + srat_cpu_affinity->apic_id = nasid; + srat_cpu_affinity->local_sapic_eid = cpu; +#else + srat_cpu_affinity->local_sapic_eid = nasid&0xffff; + srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16); +#endif + } + } + acpi_checksum(&acpi_srat->header, (char*)ptr - (char*)acpi_srat); + + + /* Set up the SLIT table */ + acpi_table_init(&acpi_slit->header, ACPI_SLIT_SIG, ACPI_SLIT_SIG_LEN, ACPI_SLIT_REVISION, 1); + acpi_slit->localities = PROXIMITY_DOMAIN(max_nasid)+1; + cp=acpi_slit->entries; + memset(cp, 255, acpi_slit->localities*acpi_slit->localities); + + for (i=0; i<=max_nasid; i++) + for (j=0; j<=max_nasid; j++) + if (nasid_present(i) && nasid_present(j)) + *(cp+PROXIMITY_DOMAIN(i)*acpi_slit->localities+PROXIMITY_DOMAIN(j)) = 10 + MIN(254, 5*ABS(i-j)); + + cp = acpi_slit->entries + acpi_slit->localities*acpi_slit->localities; + acpi_checksum(&acpi_slit->header, cp - (char*)acpi_slit); + + + /* 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 = 3; + + strcpy(sal_systab->oem_id, "SGI"); + strcpy(sal_systab->product_id, "SN1"); + + /* fill in an entry point: */ + sal_ed->type = SAL_DESC_ENTRY_POINT; + sal_ed->pal_proc = __fwtab_pa(base_nasid, pal_desc[0]); + sal_ed->sal_proc = __fwtab_pa(base_nasid, sal_desc[0]); + sal_ed->gp = __fwtab_pa(base_nasid, sal_desc[1]); + + /* kludge the PTC domain info */ + sal_ptc->type = SAL_DESC_PTC; + sal_ptc->num_domains = 0; + sal_ptc->domain_info = __fwtab_pa(base_nasid, sal_ptcdi); + cpus_found = 0; + last_domain = -1; + sal_ptcdi--; + for (cnode=0; cnodenum_domains++; + sal_ptcdi++; + sal_ptcdi->proc_count = 0; + sal_ptcdi->proc_list = __fwtab_pa(base_nasid, sal_ptclid); + last_domain = domain; + } + sal_ptcdi->proc_count++; + sal_ptclid->id = nasid; + sal_ptclid->eid = cpu; + sal_ptclid++; + cpus_found++; + } + } + } + + if (cpus_found != num_cpus) + FPROM_BUG(); + + /* Make the AP WAKEUP entry */ + sal_apwake->type = SAL_DESC_AP_WAKEUP; + sal_apwake->mechanism = IA64_SAL_AP_EXTERNAL_INT; + sal_apwake->vector = 18; + + for (checksum=0, cp=(char*)sal_systab; cp < (char *)efi_memmap; ++cp) + checksum += *cp; + sal_systab->checksum = -checksum; + + /* If the checksum is correct, the kernel tries to use the + * table. We dont build enough table & the kernel aborts. + * Note that the PROM hasd thhhe same problem!! + */ +#ifdef DOESNT_WORK + for (checksum=0, cp=(char*)acpi_rsdp, cpe=cp+RSDP_CHECKSUM_LENGTH; cpchecksum = -checksum; +#endif + + md = &efi_memmap[0]; + num_memmd = build_efi_memmap((void *)md, mdsize) ; + + bp = (struct ia64_boot_param*) __fwtab_pa(base_nasid, BOOT_PARAM_ADDR); + bp->efi_systab = __fwtab_pa(base_nasid, &fw_mem); + bp->efi_memmap = __fwtab_pa(base_nasid, efi_memmap); + bp->efi_memmap_size = num_memmd*mdsize; + bp->efi_memdesc_size = mdsize; + bp->efi_memdesc_version = 0x101; + bp->command_line = __fwtab_pa(base_nasid, 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->fpswa = 0; + + /* + * Now pick the BSP & store it LID value in + * a global variable. Note if BSP is greater than last cpu, + * pick the last cpu. + */ + for (cnode=0; cnode 0) + continue; + return; + } + } +} diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/klgraph_init.c linux-2.4.19-pre5/arch/ia64/sn/fakeprom/klgraph_init.c --- linux-2.4.18/arch/ia64/sn/fakeprom/klgraph_init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/klgraph_init.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,287 @@ +/* $Id: klgraph_init.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * This is a temporary file that statically initializes the expected + * initial klgraph information that is normally provided by prom. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) +#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) +#define HUBREG ((char *)0xc0000a0001e00000) +#define WIDGET0 ((char *)0xc0000a0000000000) +#define WIDGET4 ((char *)0xc0000a0000000004) + +#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) +#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) +#define HUBREG ((char *)0xc0000a0001e00000) +#define WIDGET0 ((char *)0xc0000a0000000000) + +#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c +void +klgraph_init(void) +{ + + u64 *temp; + + /* + * Initialize some hub/xbow registers that allows access to + * Xbridge etc. These are normally done in PROM. + */ + + /* Write IOERR clear to clear the CRAZY bit in the status */ +#ifdef CONFIG_IA64_SGI_SN1 + *(volatile uint64_t *)0xc0000a0001c001f8 = (uint64_t)0xffffffff; + + /* set widget control register...setting bedrock widget id to b */ + *(volatile uint64_t *)0xc0000a0001c00020 = (uint64_t)0x801b; + + /* set io outbound widget access...allow all */ + *(volatile uint64_t *)0xc0000a0001c00110 = (uint64_t)0xff01; + + /* set io inbound widget access...allow all */ + *(volatile uint64_t *)0xc0000a0001c00118 = (uint64_t)0xff01; + + /* set io crb timeout to max */ + *(volatile uint64_t *)0xc0000a0001c003c0 = (uint64_t)0xffffff; + *(volatile uint64_t *)0xc0000a0001c003c0 = (uint64_t)0xffffff; + + /* set local block io permission...allow all */ + *(volatile uint64_t *)0xc0000a0001e04010 = (uint64_t)0xfffffffffffffff; + + /* clear any errors */ + /* clear_ii_error(); medusa should have cleared these */ + + /* set default read response buffers in bridge */ + *(volatile u32 *)0xc0000a000f000280L = 0xba98; + *(volatile u32 *)0xc0000a000f000288L = 0xba98; +#elif CONFIG_IA64_SGI_SN2 + *(volatile uint64_t *)0xc000000801c001f8 = (uint64_t)0xffffffff; + + /* set widget control register...setting bedrock widget id to a */ + *(volatile uint64_t *)0xc000000801c00020 = (uint64_t)0x801a; + + /* set io outbound widget access...allow all */ + *(volatile uint64_t *)0xc000000801c00110 = (uint64_t)0xff01; + + /* set io inbound widget access...allow all */ + *(volatile uint64_t *)0xc000000801c00118 = (uint64_t)0xff01; + + /* set io crb timeout to max */ + *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; + *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; + + /* set local block io permission...allow all */ +// [LB] *(volatile uint64_t *)0xc000000801e04010 = (uint64_t)0xfffffffffffffff; + + /* clear any errors */ + /* clear_ii_error(); medusa should have cleared these */ + + /* set default read response buffers in bridge */ +// [PI] *(volatile u32 *)0xc00000080f000280L = 0xba98; +// [PI] *(volatile u32 *)0xc00000080f000288L = 0xba98; +#endif /* CONFIG_IA64_SGI_SN1 */ + + /* + * kldir entries initialization - mankato + */ + convert(0x8000000000002000, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002010, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002020, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002030, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002040, 0x434d5f53505f5357, 0x0000000000030000); + convert(0x8000000000002050, 0x0000000000000000, 0x0000000000010000); + convert(0x8000000000002060, 0x0000000000000001, 0x0000000000000000); + convert(0x8000000000002070, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002080, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002090, 0x0000000000000000, 0x0000000000000000); + convert(0x80000000000020a0, 0x0000000000000000, 0x0000000000000000); + convert(0x80000000000020b0, 0x0000000000000000, 0x0000000000000000); + convert(0x80000000000020c0, 0x434d5f53505f5357, 0x0000000000000000); + convert(0x80000000000020d0, 0x0000000000002400, 0x0000000000000400); + convert(0x80000000000020e0, 0x0000000000000001, 0x0000000000000000); + convert(0x80000000000020f0, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002100, 0x434d5f53505f5357, 0x0000000000040000); + convert(0x8000000000002110, 0x0000000000000000, 0xffffffffffffffff); + convert(0x8000000000002120, 0x0000000000000001, 0x0000000000000000); + convert(0x8000000000002130, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002140, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002150, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002160, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002170, 0x0000000000000000, 0x0000000000000000); + convert(0x8000000000002180, 0x434d5f53505f5357, 0x0000000000020000); + convert(0x8000000000002190, 0x0000000000000000, 0x0000000000010000); + convert(0x80000000000021a0, 0x0000000000000001, 0x0000000000000000); + + /* + * klconfig entries initialization - mankato + */ + convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000); + convert(0x0000000000030010, 0x0003007000000018, 0x800002000f820178); + convert(0x0000000000030020, 0x80000a000f024000, 0x800002000f800000); + convert(0x0000000000030030, 0x0300fafa00012580, 0x00000000040f0000); + convert(0x0000000000030040, 0x0000000000000000, 0x0003097000030070); + convert(0x0000000000030050, 0x00030970000303b0, 0x0003181000033f70); + convert(0x0000000000030060, 0x0003d51000037570, 0x0000000000038330); + convert(0x0000000000030070, 0x0203110100030140, 0x0001000000000101); + convert(0x0000000000030080, 0x0900000000000000, 0x000000004e465e67); + convert(0x0000000000030090, 0x0003097000000000, 0x00030b1000030a40); + convert(0x00000000000300a0, 0x00030cb000030be0, 0x000315a0000314d0); + convert(0x00000000000300b0, 0x0003174000031670, 0x0000000000000000); + convert(0x0000000000030100, 0x000000000000001a, 0x3350490000000000); + convert(0x0000000000030110, 0x0000000000000037, 0x0000000000000000); + convert(0x0000000000030140, 0x0002420100030210, 0x0001000000000101); + convert(0x0000000000030150, 0x0100000000000000, 0xffffffffffffffff); + convert(0x0000000000030160, 0x00030d8000000000, 0x0000000000030e50); + convert(0x00000000000301c0, 0x0000000000000000, 0x0000000000030070); + convert(0x00000000000301d0, 0x0000000000000025, 0x424f490000000000); + convert(0x00000000000301e0, 0x000000004b434952, 0x0000000000000000); + convert(0x0000000000030210, 0x00027101000302e0, 0x00010000000e4101); + convert(0x0000000000030220, 0x0200000000000000, 0xffffffffffffffff); + convert(0x0000000000030230, 0x00030f2000000000, 0x0000000000030ff0); + convert(0x0000000000030290, 0x0000000000000000, 0x0000000000030140); + convert(0x00000000000302a0, 0x0000000000000026, 0x7262490000000000); + convert(0x00000000000302b0, 0x00000000006b6369, 0x0000000000000000); + convert(0x00000000000302e0, 0x0002710100000000, 0x00010000000f3101); + convert(0x00000000000302f0, 0x0500000000000000, 0xffffffffffffffff); + convert(0x0000000000030300, 0x000310c000000000, 0x0003126000031190); + convert(0x0000000000030310, 0x0003140000031330, 0x0000000000000000); + convert(0x0000000000030360, 0x0000000000000000, 0x0000000000030140); + convert(0x0000000000030370, 0x0000000000000029, 0x7262490000000000); + convert(0x0000000000030380, 0x00000000006b6369, 0x0000000000000000); + convert(0x0000000000030970, 0x0000000002010102, 0x0000000000000000); + convert(0x0000000000030980, 0x000000004e465e67, 0xffffffff00000000); + /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ + convert(0x00000000000309a0, 0x0000000000037570, 0xffffffff00000000); + convert(0x00000000000309b0, 0x0000000000030070, 0x0000000000000000); + convert(0x00000000000309c0, 0x000000000003f420, 0x0000000000000000); + convert(0x0000000000030a40, 0x0000000002010125, 0x0000000000000000); + convert(0x0000000000030a50, 0xffffffffffffffff, 0xffffffff00000000); + convert(0x0000000000030a70, 0x0000000000037b78, 0x0000000000000000); + convert(0x0000000000030b10, 0x0000000002010125, 0x0000000000000000); + convert(0x0000000000030b20, 0xffffffffffffffff, 0xffffffff00000000); + convert(0x0000000000030b40, 0x0000000000037d30, 0x0000000000000001); + convert(0x0000000000030be0, 0x00000000ff010203, 0x0000000000000000); + convert(0x0000000000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); + convert(0x0000000000030c10, 0x0000000000037ee8, 0x0100010000000200); + convert(0x0000000000030cb0, 0x00000000ff310111, 0x0000000000000000); + convert(0x0000000000030cc0, 0xffffffffffffffff, 0x0000000000000000); + convert(0x0000000000030d80, 0x0000000002010104, 0x0000000000000000); + convert(0x0000000000030d90, 0xffffffffffffffff, 0x00000000000000ff); + convert(0x0000000000030db0, 0x0000000000037f18, 0x0000000000000000); + convert(0x0000000000030dc0, 0x0000000000000000, 0x0003007000060000); + convert(0x0000000000030de0, 0x0000000000000000, 0x0003021000050000); + convert(0x0000000000030df0, 0x000302e000050000, 0x0000000000000000); + convert(0x0000000000030e30, 0x0000000000000000, 0x000000000000000a); + convert(0x0000000000030e50, 0x00000000ff00011a, 0x0000000000000000); + convert(0x0000000000030e60, 0xffffffffffffffff, 0x0000000000000000); + convert(0x0000000000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); + convert(0x0000000000030e90, 0x000000000000bc6e, 0x0000000000000000); + convert(0x0000000000030f20, 0x0000000002010205, 0x00000000d0020000); + convert(0x0000000000030f30, 0xffffffffffffffff, 0x0000000e0000000e); + convert(0x0000000000030f40, 0x000000000000000e, 0x0000000000000000); + convert(0x0000000000030f50, 0x0000000000038010, 0x00000000000007ff); + convert(0x0000000000030f70, 0x0000000000000000, 0x0000000022001077); + convert(0x0000000000030fa0, 0x0000000000000000, 0x000000000003f4a8); + convert(0x0000000000030ff0, 0x0000000000310120, 0x0000000000000000); + convert(0x0000000000031000, 0xffffffffffffffff, 0xffffffff00000002); + convert(0x0000000000031010, 0x000000000000000e, 0x0000000000000000); + convert(0x0000000000031020, 0x0000000000038088, 0x0000000000000000); + convert(0x00000000000310c0, 0x0000000002010205, 0x00000000d0020000); + convert(0x00000000000310d0, 0xffffffffffffffff, 0x0000000f0000000f); + convert(0x00000000000310e0, 0x000000000000000f, 0x0000000000000000); + convert(0x00000000000310f0, 0x00000000000380b8, 0x00000000000007ff); + convert(0x0000000000031120, 0x0000000022001077, 0x00000000000310a9); + convert(0x0000000000031130, 0x00000000580211c1, 0x000000008009104c); + convert(0x0000000000031140, 0x0000000000000000, 0x000000000003f4c0); + convert(0x0000000000031190, 0x0000000000310120, 0x0000000000000000); + convert(0x00000000000311a0, 0xffffffffffffffff, 0xffffffff00000003); + convert(0x00000000000311b0, 0x000000000000000f, 0x0000000000000000); + convert(0x00000000000311c0, 0x0000000000038130, 0x0000000000000000); + convert(0x0000000000031260, 0x0000000000110106, 0x0000000000000000); + convert(0x0000000000031270, 0xffffffffffffffff, 0xffffffff00000004); + convert(0x0000000000031280, 0x000000000000000f, 0x0000000000000000); + convert(0x00000000000312a0, 0x00000000ff110013, 0x0000000000000000); + convert(0x00000000000312b0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0x00000000000312c0, 0x000000000000000f, 0x0000000000000000); + convert(0x00000000000312e0, 0x0000000000110012, 0x0000000000000000); + convert(0x00000000000312f0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0x0000000000031300, 0x000000000000000f, 0x0000000000000000); + convert(0x0000000000031310, 0x0000000000038160, 0x0000000000000000); + convert(0x0000000000031330, 0x00000000ff310122, 0x0000000000000000); + convert(0x0000000000031340, 0xffffffffffffffff, 0xffffffff00000005); + convert(0x0000000000031350, 0x000000000000000f, 0x0000000000000000); + convert(0x0000000000031360, 0x0000000000038190, 0x0000000000000000); + convert(0x0000000000031400, 0x0000000000310121, 0x0000000000000000); + convert(0x0000000000031400, 0x0000000000310121, 0x0000000000000000); + convert(0x0000000000031410, 0xffffffffffffffff, 0xffffffff00000006); + convert(0x0000000000031420, 0x000000000000000f, 0x0000000000000000); + convert(0x0000000000031430, 0x00000000000381c0, 0x0000000000000000); + convert(0x00000000000314d0, 0x00000000ff010201, 0x0000000000000000); + convert(0x00000000000314e0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0x0000000000031500, 0x00000000000381f0, 0x000030430000ffff); + convert(0x0000000000031510, 0x000000000000ffff, 0x0000000000000000); + convert(0x00000000000315a0, 0x00000020ff000201, 0x0000000000000000); + convert(0x00000000000315b0, 0xffffffffffffffff, 0xffffffff00000001); + convert(0x00000000000315d0, 0x0000000000038240, 0x00003f3f0000ffff); + convert(0x00000000000315e0, 0x000000000000ffff, 0x0000000000000000); + convert(0x0000000000031670, 0x00000000ff010201, 0x0000000000000000); + convert(0x0000000000031680, 0xffffffffffffffff, 0x0000000100000002); + convert(0x00000000000316a0, 0x0000000000038290, 0x000030430000ffff); + convert(0x00000000000316b0, 0x000000000000ffff, 0x0000000000000000); + convert(0x0000000000031740, 0x00000020ff000201, 0x0000000000000000); + convert(0x0000000000031750, 0xffffffffffffffff, 0x0000000500000003); + convert(0x0000000000031770, 0x00000000000382e0, 0x00003f3f0000ffff); + convert(0x0000000000031780, 0x000000000000ffff, 0x0000000000000000); + + /* + * GDA initialization - mankato + */ + convert(0x8000000000002400, 0x0000000258464552, 0x000000000ead0000); + convert(0x8000000000002480, 0xffffffff00010000, 0xffffffffffffffff); + convert(0x8000000000002490, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024a0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024b0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024c0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024d0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024e0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x80000000000024f0, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002500, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002510, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002520, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002530, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002540, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002550, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002560, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002570, 0xffffffffffffffff, 0xffffffffffffffff); + convert(0x8000000000002580, 0x000000000000ffff, 0x0000000000000000); + +} + diff -urN linux-2.4.18/arch/ia64/sn/fakeprom/main.c linux-2.4.19-pre5/arch/ia64/sn/fakeprom/main.c --- linux-2.4.18/arch/ia64/sn/fakeprom/main.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/fakeprom/main.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,125 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + */ + + + +#include +#include +#include + +extern void klgraph_init(void); +void bedrock_init(int); +void synergy_init(int, int); +void sys_fw_init (const char *args, int arglen, int bsp); + +volatile int bootmaster=0; /* Used to pick bootmaster */ +volatile int nasidmaster[128]={0}; /* Used to pick node/synergy masters */ +int init_done=0; +extern int bsp_lid; + +#define get_bit(b,p) (((*p)>>(b))&1) + +int +fmain(int lid, int bsp) { + int syn, nasid, cpu; + + /* + * First lets figure out who we are. This is done from the + * LID passed to us. + */ + +#ifdef CONFIG_IA64_SGI_SN1 + nasid = (lid>>24); + syn = (lid>>17)&1; + cpu = (lid>>16)&1; + + /* + * Now pick a synergy master to initialize synergy registers. + */ + if (test_and_set_bit(syn, &nasidmaster[nasid]) == 0) { + synergy_init(nasid, syn); + test_and_set_bit(syn+2, &nasidmaster[nasid]); + } else + while (get_bit(syn+2, &nasidmaster[nasid]) == 0); +#else + nasid = (lid>>16)&0xfff; + cpu = (lid>>28)&3; + syn = 0; +#endif + + /* + * Now pick a nasid master to initialize Bedrock registers. + */ + if (test_and_set_bit(8, &nasidmaster[nasid]) == 0) { + bedrock_init(nasid); + test_and_set_bit(9, &nasidmaster[nasid]); + } else + while (get_bit(9, &nasidmaster[nasid]) == 0); + + + /* + * Now pick a BSP & finish init. + */ + if (test_and_set_bit(0, &bootmaster) == 0) { + sys_fw_init(0, 0, bsp); + test_and_set_bit(1, &bootmaster); + } else + while (get_bit(1, &bootmaster) == 0); + + return (lid == bsp_lid); +} + + +void +bedrock_init(int nasid) +{ + nasid = nasid; /* to quiet gcc */ +#if 0 + /* + * Undef if you need fprom to generate a 1 node klgraph + * information .. only works for 1 node for nasid 0. + */ + klgraph_init(); +#endif +} + + +void +synergy_init(int nasid, int syn) +{ + long *base; + long off; + + /* + * Enable all FSB flashed interrupts. + * ZZZ - I'd really like defines for this...... + */ + base = (long*)0x80000e0000000000LL; /* base of synergy regs */ + for (off = 0x2a0; off < 0x2e0; off+=8) /* offset for VEC_MASK_{0-3}_A/B */ + *(base+off/8) = -1LL; + + /* + * Set the NASID in the FSB_CONFIG register. + */ + base = (long*)0x80000e0000000450LL; + *base = (long)((nasid<<16)|(syn<<9)); +} + + +/* Why isnt there a bcopy/memcpy in lib64.a */ + +void* +memcpy(void * dest, const void *src, size_t count) +{ + char *s, *se, *d; + + for(d=dest, s=(char*)src, se=s+count; s] <-p> | <-k> [] + -p Create PROM control file & links + -k Create LINUX control file & links + -c Control file name [Default: cf] + Path to directory that contains the linux or PROM files. + The directory can be any of the following: + (linux simulations) + worktree + worktree/linux + any directory with vmlinux, vmlinux.sym & fprom files + (prom simulations) + worktree + worktree/stand/arcs/IP37prom/dev + any directory with fw.bin & fw.sim files + + Simulations: + sim [-X ] [-o ] [-M] [] + -c Control file name [Default: cf] + -M Pipe output thru fmtmedusa + -o Output filename (copy of all commands/output) [Default: simout] + -X Specifies number of instructions to execute [Default: 0] + (Used only in auto test mode - not described here) + +Examples: + sim -p # create control file (cf) & links for prom simulations + sim -k # create control file (cf) & links for linux simulations + sim -p -c cfprom # create a prom control file (cfprom) only. No links are made. + + sim # run medusa using previously created links & + # control file (cf). +END +exit 1 +} + +# ----------------------- create control file header -------------------- +create_cf_header() { +cat <>$CF +# +# Template for a control file for running linux kernels under medusa. +# You probably want to make mods here but this is a good starting point. +# + +# Preferences +setenv cpu_stepping A +setenv exceptionPrint off +setenv interrupt_messages off +setenv lastPCsize 100000 +setenv low_power_mode on +setenv partialIntelChipSet on +setenv printIntelMessages off +setenv prom_write_action halt +setenv prom_write_messages on +setenv step_quantum 100 +setenv swizzling on +setenv tsconsole on +setenv uart_echo on +symbols on + +# IDE disk params +setenv diskCylinders 611 +setenv bootDrive C +setenv diskHeads 16 +setenv diskPath idedisk +setenv diskPresent 1 +setenv diskSpt 63 + +# Hardware config +setenv coherency_type nasid +setenv cpu_cache_type default +setenv synergy_cache_type syn_cac_64m_8w +setenv l4_uc_snoop off + +# Numalink config +setenv route_enable on +setenv network_type router # Select [xbar|router] +setenv network_warning 0xff + +END +} + + +# ------------------ create control file entries for linux simulations ------------- +create_cf_linux() { +cat <>$CF +# Kernel specific options +setenv calias_size 0 +setenv mca_on_memory_failure off +setenv LOADPC 0x00100000 # FPROM load address/entry point (8 digits!) +setenv symbol_table vmlinux.sym +load fprom +load vmlinux + +# Useful breakpoints to always have set. Add more if desired. +break 0xe000000000505e00 all # dispatch_to_fault_handler +break panic all # stop on panic +break die_if_kernel all # may as well stop + +END +} + +# ------------------ create control file entries for prom simulations --------------- +create_cf_prom() { + SYM2="" + ADDR="0x80000000ff800000" + [ "$EMBEDDED_LINUX" != "0" ] || SYM2="setenv symbol_table2 vmlinux.sym" + [ "$SIZE" = "8MB" ] || ADDR="0x80000000ffc00000" + cat <>$CF +# PROM specific options +setenv mca_on_memory_failure on +setenv LOADPC 0x80000000ffffffb0 +setenv promFile fw.bin +setenv promAddr $ADDR +setenv symbol_table fw.sym +$SYM2 + +# Useful breakpoints to always have set. Add more if desired. +break ivt_gexx all +break ivt_brk all +break PROM_Panic_Spin all +break PROM_Panic all +break PROM_C_Panic all +break fled_die all +break ResetNow all +break zzzbkpt all + +END +} + + +# ------------------ create control file entries for memory configuration ------------- +create_cf_memory() { +cat <>$CF +# CPU/Memory map format: +# setenv nodeN_memory_config 0xBSBSBSBS +# B=banksize (0=unused, 1=64M, 2=128M, .., 5-1G, c=8M, d=16M, e=32M) +# S=bank enable (0=both disable, 3=both enable, 2=bank1 enable, 1=bank0 enable) +# rightmost digits are for bank 0, the lowest address. +# setenv nodeN_nasid +# specifies the NASID for the node. This is used ONLY if booting the kernel. +# On PROM configurations, set to 0 - PROM will change it later. +# setenv nodeN_cpu_config +# Set bit number N to 1 to enable cpu N. Ex., a value of 5 enables cpu 0 & 2. +# +# Repeat the above 3 commands for each node. +# +# For kernel, default to 32MB. Although this is not a valid hardware configuration, +# it runs faster on medusa. For PROM, 64MB is smallest allowed value. + +setenv node0_cpu_config 0x1 # Enable only cpu 0 on the node +END + +if [ $LINUX -eq 1 ] ; then +cat <>$CF +setenv node0_nasid 0 # cnode 0 has NASID 0 +setenv node0_memory_config 0xe1 # 32MB +END +else +cat <>$CF +setenv node0_memory_config 0x31 # 256MB +END +fi +} + +# -------------------- set links to linux files ------------------------- +set_linux_links() { + if [ -d $D/linux/arch ] ; then + D=$D/linux + elif [ -d $D/arch -o -e vmlinux.sym -o -e $D/vmlinux ] ; then + D=$D + else + err "cant determine directory for linux binaries" + fi + rm -rf vmlinux vmlinux.sym fprom + ln -s $D/vmlinux vmlinux + if [ -f $D/vmlinux.sym ] ; then + ln -s $D/vmlinux.sym vmlinux.sym + elif [ -f $D/System.map ] ; then + ln -s $D/System.map vmlinux.sym + fi + if [ -d $D/arch ] ; then + ln -s $D/arch/ia64/sn/fprom/fprom fprom + else + ln -s $D/fprom fprom + fi + echo " .. Created links to linux files" +} + +# -------------------- set links to prom files ------------------------- +set_prom_links() { + if [ -d $D/stand ] ; then + D=$D/stand/arcs/IP37prom/dev + elif [ -d $D/sal ] ; then + D=$D + else + err "cant determine directory for PROM binaries" + fi + SETUP="/tmp/tmp.$$" + rm -r -f $SETUP + sed 's/export/setenv/' < $D/../../../../.setup | sed 's/=/ /' >$SETUP + egrep -q '^ *setenv *PROMSIZE *8MB|^ *export' $SETUP + if [ $? -eq 0 ] ; then + SIZE="8MB" + else + SIZE="4MB" + fi + grep -q '^ *setenv *LAUNCH_VMLINUX' $SETUP + EMBEDDED_LINUX=$? + PRODUCT=`grep '^ *setenv *PRODUCT' $SETUP | cut -d" " -f3` + rm -f fw.bin fw.map fw.sym vmlinux vmlinux.sym fprom $SETUP + SDIR="${PRODUCT}${SIZE}.O" + BIN="${PRODUCT}ip37prom${SIZE}" + ln -s $D/$SDIR/$BIN.bin fw.bin + ln -s $D/$SDIR/$BIN.map fw.map + ln -s $D/$SDIR/$BIN.sym fw.sym + echo " .. Created links to $SIZE prom files" + if [ $EMBEDDED_LINUX -eq 0 ] ; then + ln -s $D/linux/vmlinux vmlinux + ln -s $D/linux/vmlinux.sym vmlinux.sym + if [ -d linux/arch ] ; then + ln -s $D/linux/arch/ia64/sn/fprom/fprom fprom + else + ln -s $D/linux/fprom fprom + fi + echo " .. Created links to embedded linux files in prom tree" + fi +} + +# --------------- start of shell script -------------------------------- +OUT="simout" +FMTMED=0 +STEPCNT=0 +PROM=0 +LINUX=0 +NCF="cf" +while getopts "HMX:c:o:pk" c ; do + case ${c} in + H) help;; + M) FMTMED=1;; + X) STEPCNT=${OPTARG};; + c) NCF=${OPTARG};; + k) PROM=0;LINUX=1;; + p) PROM=1;LINUX=0;; + o) OUT=${OPTARG};; + \?) exit 1;; + esac +done +shift `expr ${OPTIND} - 1` + +# Check if command is for creating control file and/or links to images. +if [ $PROM -eq 1 -o $LINUX -eq 1 ] ; then + CF=$NCF + [ ! -f $CF ] || err "wont overwrite an existing control file ($CF)" + if [ $# -gt 0 ] ; then + D=$1 + [ -d $D ] || err "cannot find directory $D" + [ $PROM -eq 0 ] || set_prom_links + [ $LINUX -eq 0 ] || set_linux_links + fi + create_cf_header + [ $PROM -eq 0 ] || create_cf_prom + [ $LINUX -eq 0 ] || create_cf_linux + [ ! -f ../idedisk ] || ln -s ../idedisk . + create_cf_memory + echo " .. Basic control file created (in $CF). You might want to edit" + echo " this file (at least, look at it)." + exit 0 +fi + +# Verify that the control file exists +CF=${1:-$NCF} +[ -f $CF ] || err "No control file exists. For help, type: $0 -H" + +# Build the .cf files from the user control file. The .cf file is +# identical except that the actual start & load addresses are inserted +# into the file. In addition, the FPROM commands for configuring memory +# and LIDs are generated. + +rm -f .cf .cf1 .cf2 +awk ' +function strtonum(n) { + if (substr(n,1,2) != "0x") + return int(n) + n = substr(n,3) + r=0 + while (length(n) > 0) { + r = r*16+(index("0123456789abcdef", substr(n,1,1))-1) + n = substr(n,2) + } + return r + } +/^#/ {next} +/^$/ {next} +/^setenv *LOADPC/ {loadpc = $3; next} +/^setenv *node.._cpu_config/ {n=int(substr($2,5,2)); cpuconf[n] = strtonum($3); print; next} +/^setenv *node.._memory_config/ {n=int(substr($2,5,2)); memconf[n] = strtonum($3); print; next} +/^setenv *node.._nasid/ {n=int(substr($2,5,2)); nasid[n] = strtonum($3); print; next} +/^setenv *node._cpu_config/ {n=int(substr($2,5,1)); cpuconf[n] = strtonum($3); print; next} +/^setenv *node._memory_config/ {n=int(substr($2,5,1)); memconf[n] = strtonum($3); print; next} +/^setenv *node._nasid/ {n=int(substr($2,5,1)); nasid[n] = strtonum($3); print; next} + {print} +END { + # Generate the memmap info that starts at the beginning of + # the node the kernel was loaded on. + loadnasid = nasid[0] + cnode = 0 + for (i=0; i<128; i++) { + if (memconf[i] != "") { + printf "sm 0x%x%08x 0x%x%04x%04x\n", + 2*loadnasid, 8*cnodes+8, memconf[i], cpuconf[i], nasid[i] + cnodes++ + cpus += substr("0112122312232334", cpuconf[i]+1,1) + } + } + printf "sm 0x%x00000000 0x%x%08x\n", 2*loadnasid, cnodes, cpus + printf "setenv number_of_nodes %d\n", cnodes + + # Now set the starting PC for each cpu. + cnode = 0 + lowcpu=-1 + for (i=0; i<128; i++) { + if (memconf[i] != "") { + printf "setnode %d\n", cnode + conf = cpuconf[i] + for (j=0; j<4; j++) { + if (conf != int(conf/2)*2) { + printf "setcpu %d\n", j + if (length(loadpc) == 18) + printf "sr pc %s\n", loadpc + else + printf "sr pc 0x%x%s\n", 2*loadnasid, substr(loadpc,3) + if (lowcpu == -1) + lowcpu = j + } + conf = int(conf/2) + } + cnode++ + } + } + printf "setnode 0\n" + printf "setcpu %d\n", lowcpu + } +' <$CF >.cf + +# Now build the .cf1 & .cf2 control files. +CF2_LINES="^sm |^break |^run |^si |^quit |^symbols " +egrep "$CF2_LINES" .cf >.cf2 +egrep -v "$CF2_LINES" .cf >.cf1 +if [ $STEPCNT -ne 0 ] ; then + echo "s $STEPCNT" >>.cf2 + echo "lastpc 1000" >>.cf2 + echo "q" >>.cf2 +fi +if [ -f vmlinux.sym ] ; then + awk '/ _start$/ {print "sr g 9 0x" $3}' < vmlinux.sym >> .cf2 +fi +echo "script-on $OUT" >>.cf2 + +# Now start medusa.... +if [ $FMTMED -ne 0 ] ; then + $MEDUSA -system mpsn1 -c .cf1 -i .cf2 | fmtmedusa +elif [ $STEPCNT -eq 0 ] ; then + $MEDUSA -system mpsn1 -c .cf1 -i .cf2 +else + $MEDUSA -system mpsn1 -c .cf1 -i .cf2 2>&1 +fi diff -urN linux-2.4.18/arch/ia64/sn/fprom/Makefile linux-2.4.19-pre5/arch/ia64/sn/fprom/Makefile --- linux-2.4.18/arch/ia64/sn/fprom/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/Makefile Thu Jan 1 01:00:00 1970 @@ -1,33 +0,0 @@ -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# Copyright (C) 2000 Silicon Graphics, Inc. -# Copyright (C) Jack Steiner (steiner@sgi.com) -# - -TOPDIR=../../../.. -HPATH = $(TOPDIR)/include - -LIB = ../../lib/lib.a - -OBJ=fpromasm.o main.o fw-emu.o fpmem.o -obj-y=fprom - -fprom: $(OBJ) - $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) - -comma := , - -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_KERNEL) -c -o $*.o $< - -clean: - rm -f *.o fprom - - -include $(TOPDIR)/Rules.make - diff -urN linux-2.4.18/arch/ia64/sn/fprom/README linux-2.4.19-pre5/arch/ia64/sn/fprom/README --- linux-2.4.18/arch/ia64/sn/fprom/README Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/README Thu Jan 1 01:00:00 1970 @@ -1,85 +0,0 @@ -This directory contains the files required to build -the fake PROM image that is currently being used to -boot IA64 kernels running under the SGI Medusa kernel. - -The FPROM currently provides the following functions: - - - PAL emulation for all PAL calls we've made so far. - - SAL emulation for all SAL calls we've made so far. - - EFI emulation for all EFI calls we've made so far. - - builds the "ia64_bootparam" structure that is - passed to the kernel from SAL. This structure - shows the cpu & memory configurations. - - supports medusa boottime options for changing - the number of cpus present - - supports medusa boottime options for changing - the memory configuration. - - - -At some point, this fake PROM will be replaced by the -real PROM. - - - - -To build a fake PROM, cd to this directory & type: - - make - -This will (or should) build a fake PROM named "fprom". - - - - -Use this fprom image when booting the Medusa simulator. The -control file used to boot Medusa should include the -following lines: - - load fprom - load vmlinux - sr pc 0x100000 - sr g 9
#(currently 0xe000000000520000) - -NOTE: There is a script "runsim" in this directory that can be used to -simplify setting up an environment for running under Medusa. - - - - -The following parameters may be passed to the fake PROM to -control the PAL/SAL/EFI parameters passed to the kernel: - - GR[8] = # of cpus - GR[9] = address of primary entry point into the kernel - GR[20] = memory configuration for node 0 - GR[21] = memory configuration for node 1 - GR[22] = memory configuration for node 2 - GR[23] = memory configuration for node 3 - - -Registers GR[20] - GR[23] contain information to specify the -amount of memory present on nodes 0-3. - - - if nothing is specified (all registers are 0), the configuration - defaults to 8 MB on node 0. - - - a mem config entry for node N is passed in GR[20+N] - - - a mem config entry consists of 8 hex digits. Each digit gives the - amount of physical memory available on the node starting at - 1GB*, where dn is the digit number. The amount of memory - is 8MB*2**. (If = 0, the memory size is 0). - - SN1 doesnt support dimms this small but small memory systems - boot faster on Medusa. - - - -An example helps a lot. The following specifies that node 0 has -physical memory 0 to 8MB and 1GB to 1GB+32MB, and that node 1 has -64MB starting at address 0 of the node which is 8GB. - - gr[20] = 0x21 # 0 to 8MB, 1GB to 1GB+32MB - gr[21] = 0x4 # 8GB to 8GB+64MB - diff -urN linux-2.4.18/arch/ia64/sn/fprom/fpmem.c linux-2.4.19-pre5/arch/ia64/sn/fprom/fpmem.c --- linux-2.4.18/arch/ia64/sn/fprom/fpmem.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/fpmem.c Thu Jan 1 01:00:00 1970 @@ -1,200 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) - */ - - -/* - * FPROM EFI memory descriptor build routines - * - * - Routines to build the EFI memory descriptor map - * - Should also be usable by the SGI SN1 prom to convert - * klconfig to efi_memmap - */ - -#include -#include "fpmem.h" - -/* - * args points to a layout in memory like this - * - * 32 bit 32 bit - * - * numnodes numcpus - * - * 16 bit 16 bit 32 bit - * nasid0 cpuconf membankdesc0 - * nasid1 cpuconf membankdesc1 - * . - * . - * . - * . - * . - */ - -sn_memmap_t *sn_memmap ; -sn_config_t *sn_config ; - -/* - * There is a hole in the node 0 address space. Dont put it - * in the memory map - */ -#define NODE0_HOLE_SIZE (20*MB) -#define NODE0_HOLE_END (4UL*GB) - -#define MB (1024*1024) -#define GB (1024*MB) -#define KERNEL_SIZE (4*MB) -#define PROMRESERVED_SIZE (1*MB) -#define MD_BANK_SHFT 30 - -#define TO_NODE(_n, _x) (((long)_n<<33L) | (long)_x) - -/* - * For SN, this may not take an arg and gets the numnodes from - * the prom variable or by traversing klcfg or promcfg - */ -int -GetNumNodes(void) -{ - return sn_config->nodes; -} - -int -GetNumCpus(void) -{ - return sn_config->cpus; -} - -/* For SN1, get the index th nasid */ - -int -GetNasid(int index) -{ - return sn_memmap[index].nasid ; -} - -node_memmap_t -GetMemBankInfo(int index) -{ - return sn_memmap[index].node_memmap ; -} - -int -IsCpuPresent(int cnode, int cpu) -{ - return sn_memmap[cnode].cpuconfig & (1<type = type; - md->phys_addr = paddr; - md->virt_addr = 0; - md->num_pages = numbytes >> 12; - md->attribute = EFI_MEMORY_WB; -} - -int -build_efi_memmap(void *md, int mdsize) -{ - int numnodes = GetNumNodes() ; - int cnode,bank ; - int nasid ; - node_memmap_t membank_info ; - int bsize; - int count = 0 ; - long paddr, hole, numbytes; - - - for (cnode=0;cnode - -typedef struct sn_memmap_s -{ - short nasid ; - short cpuconfig; - node_memmap_t node_memmap ; -} sn_memmap_t ; - -typedef struct sn_config_s -{ - int cpus; - int nodes; - sn_memmap_t memmap[1]; /* start of array */ -} sn_config_t; - - -extern void build_init(unsigned long); -extern int build_efi_memmap(void *, int); -extern int GetNumNodes(void); -extern int GetNumCpus(void); -extern int IsCpuPresent(int, int); -extern int GetNasid(int); diff -urN linux-2.4.18/arch/ia64/sn/fprom/fprom.lds linux-2.4.19-pre5/arch/ia64/sn/fprom/fprom.lds --- linux-2.4.18/arch/ia64/sn/fprom/fprom.lds Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/fprom.lds Thu Jan 1 01:00:00 1970 @@ -1,96 +0,0 @@ - -OUTPUT_FORMAT("elf64-ia64-little") -OUTPUT_ARCH(ia64) -ENTRY(_start) -SECTIONS -{ - v = 0x0000000000000000 ; /* this symbol is here to make debugging with kdb easier... */ - - . = (0x000000000000000 + 0x100000) ; - - _text = .; - .text : AT(ADDR(.text) - 0x0000000000000000 ) - { - *(__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) - } - - /* Global data */ - _data = .; - - .rodata : AT(ADDR(.rodata) - 0x0000000000000000 ) - { *(.rodata) *(.rodata.*) } - .opd : AT(ADDR(.opd) - 0x0000000000000000 ) - { *(.opd) } - .data : AT(ADDR(.data) - 0x0000000000000000 ) - { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } - - __gp = ALIGN (8) + 0x200000; - - .got : AT(ADDR(.got) - 0x0000000000000000 ) - { *(.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) - 0x0000000000000000 ) - { *(.sdata) } - _edata = .; - _bss = .; - .sbss : AT(ADDR(.sbss) - 0x0000000000000000 ) - { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - 0x0000000000000000 ) - { *(.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 -urN linux-2.4.18/arch/ia64/sn/fprom/fpromasm.S linux-2.4.19-pre5/arch/ia64/sn/fprom/fpromasm.S --- linux-2.4.18/arch/ia64/sn/fprom/fpromasm.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/fpromasm.S Thu Jan 1 01:00:00 1970 @@ -1,314 +0,0 @@ -/* - * - * 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. - * - * (Code copied from or=ther files) - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) - */ - - - -#define __ASSEMBLY__ 1 -#include "asm/processor.h" - -/* - * This file contains additional set up code that is needed to get going on - * Medusa. This code should disappear once real hw is available. - * - * On entry to this routine, the following register values are assumed: - * - * gr[8] - BSP cpu - * pr[9] - kernel entry address - * - * NOTE: - * This FPROM may be loaded/executed at an address different from the - * address that it was linked at. The FPROM is linked to run on node 0 - * at address 0x100000. If the code in loaded into another node, it - * must be loaded at offset 0x100000 of the node. In addition, the - * FPROM does the following things: - * - determine the base address of the node it is loaded on - * - add the node base to _gp. - * - add the node base to all addresses derived from "movl" - * instructions. (I couldnt get GPREL addressing to work) - * (maybe newer versions of the tools will support this) - * - scan the .got section and add the node base to all - * pointers in this section. - * - add the node base to all physical addresses in the - * SAL/PAL/EFI table built by the C code. (This is done - * in the C code - not here) - * - add the node base to the TLB entries for vmlinux - */ - -#define KERNEL_BASE 0xe000000000000000 -#define PAGESIZE_256M 28 - -/* - * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should - * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) - * IOSPEC_BASE value - */ -#define IOPB_PA 0x00000a0000000000 /* inv swizzle IOSPEC_BASE */ - -#define RR_RID 8 - - - -// ==================================================================================== - .text - .align 16 - .global _start - .proc _start -_start: - -// Setup psr and rse for system init - mov psr.l = r0;; - srlz.d;; - invala - mov ar.rsc = r0;; - loadrs - ;; - -// Set CALIAS size to zero. We dont use it. - movl r24=0x80000a0001000028;; // BR_PI_CALIAS_SIZE - st8 [r24]=r0 - -// Isolate node number we are running on. - mov r6 = ip;; - shr r5 = r6,33;; // r5 = node number - shl r6 = r5,33 // r6 = base memory address of node - -// Set & relocate gp. - movl r1= __gp;; // Add base memory address - add r1 = r1,r6 // Relocate to boot node - -// Lets figure out who we are & put it in the LID register. -// The BR_PI_SELF_CPU_NUM register gives us a value of 0-3. -// This identifies the cpu on the node. -// Merge the cpu number with the NASID to generate the LID. - movl r24=0x80000a0001000020;; // BR_PI_SELF_CPU_NUM - ld8 r25=[r24] // Fetch PI_SELF - movl r27=0x80000a0001600000;; // Fetch REVID to get local NASID - ld8 r27=[r27];; - extr.u r27=r27,32,8 - shl r26=r25,16;; // Align local cpu# to lid.eid - shl r27=r27,24;; // Align NASID to lid.id - or r26=r26,r27;; // build the LID - mov cr.lid=r26 // Now put in in the LID register - - movl r2=FPSR_DEFAULT;; - mov ar.fpsr=r2 - movl sp = bootstacke-16;; - add sp = sp,r6 // Relocate to boot node - -// Save the NASID that we are loaded on. - movl r2=base_nasid;; // Save base_nasid for C code - add r2 = r2,r6;; // Relocate to boot node - st8 [r2]=r5 // Uncond st8 - same on all cpus - -// Save the kernel entry address. It is passed in r9 on one of -// the cpus. - movl r2=bsp_entry_pc - cmp.ne p6,p0=r9,r0;; - add r2 = r2,r6;; // Relocate to boot node -(p6) st8 [r2]=r9 // Uncond st8 - same on all cpus - - -// The following can ONLY be done by 1 cpu. Lets set a lock - the -// cpu that gets it does the initilization. The rest just spin waiting -// til initilization is complete. - movl r22 = initlock;; - add r22 = r22,r6 // Relocate to boot node - mov r23 = 1;; - xchg8 r23 = [r22],r23;; - cmp.eq p6,p0 = 0,r23 -(p6) br.cond.spnt.few init -1: ld4 r23 = [r22];; - cmp.eq p6,p0 = 1,r23 -(p6) br.cond.sptk 1b - br initx - -// Add base address of node memory to each pointer in the .got section. -init: movl r16 = _GLOBAL_OFFSET_TABLE_;; - add r16 = r16,r6;; // Relocate to boot node -1: ld8 r17 = [r16];; - cmp.eq p6,p7=0,r17 -(p6) br.cond.sptk.few.clr 2f;; - add r17 = r17,r6;; // Relocate to boot node - st8 [r16] = r17,8 - br 1b -2: - mov r23 = 2;; // All done, release the spinning cpus - st4 [r22] = r23 -initx: - -// -// I/O-port space base address: -// - movl r2 = IOPB_PA;; - mov ar.k0 = r2 - - -// Now call main & pass it the current LID value. - alloc r0=ar.pfs,0,0,2,0 - mov r32=r26 - mov r33=r8;; - br.call.sptk.few rp=fmain - -// Initialize Region Registers -// - mov r10 = r0 - mov r2 = (13<<2) - mov r3 = r0;; -1: cmp4.gtu p6,p7 = 7, r3 - dep r10 = r3, r10, 61, 3 - dep r2 = r3, r2, RR_RID, 4;; -(p7) dep r2 = 0, r2, 0, 1;; -(p6) dep r2 = -1, r2, 0, 1;; - mov rr[r10] = r2 - add r3 = 1, r3;; - srlz.d;; - cmp4.gtu p6,p0 = 8, r3 -(p6) br.cond.sptk.few.clr 1b - -// -// Return value indicates if we are the BSP or AP. -// 1 = BSP, 0 = AP - mov cr.tpr=r0;; - cmp.eq p6,p0=r8,r0 -(p6) br.cond.spnt slave - -// -// Initialize the protection key registers with only pkr[0] = valid. -// -// Should be initialized in accordance with the OS. -// - mov r2 = 1 - mov r3 = r0;; - mov pkr[r3] = r2;; - srlz.d;; - mov r2 = r0 - -1: add r3 = r3, r0, 1;; // increment PKR - cmp.gtu p6, p0 = 16, r3;; -(p6) mov pkr[r3] = r2 -(p6) br.cond.sptk.few.clr 1b - - mov ar.rnat = r0 // clear RNAT register - -// -// Setup system address translation for kernel -// -// Note: The setup of Kernel Virtual address space can be done by the -// C code of the boot loader. -// -// - -#define LINUX_PAGE_OFFSET 0xe000000000000000 -#define ITIR(key, ps) ((key<<8) | (ps<<2)) -#define ITRGR(ed,ar,ma) ((ed<<52) | (ar<<9) | (ma<<2) | 0x61) - -#define AR_RX 1 // RX permission -#define AR_RW 4 // RW permission -#define MA_WB 0 // WRITEBACK memory attribute - -#define TLB_PAGESIZE 28 // Use 256MB pages for now. - mov r16=r5 - -// -// text section -// - movl r2 = LINUX_PAGE_OFFSET;; // Set up IFA with VPN of linux - mov cr.ifa = r2 - movl r3 = ITIR(0,TLB_PAGESIZE);; // Set ITIR to default pagesize - mov cr.itir = r3 - - shl r4 = r16,33;; // physical addr of start of node - movl r5 = ITRGR(1,AR_RX,MA_WB);; // TLB attributes - or r10=r4,r5;; - - itr.i itr[r0] = r10;; // Dropin ITR entry - srlz.i;; - -// -// data section -// - movl r2 = LINUX_PAGE_OFFSET;; // Set up IFA with VPN of linux - mov cr.ifa = r2 - movl r3 = ITIR(0,TLB_PAGESIZE);; // Set ITIR to default pagesize - mov cr.itir = r3 - - shl r4 = r16,33;; // physical addr of start of node - movl r5 = ITRGR(1,AR_RW,MA_WB);; // TLB attributes - or r10=r4,r5;; - - itr.d dtr[r0] = r10;; // Dropin DTR entry - srlz.d;; - - - - -// -// Turn on address translation, interrupt collection, psr.ed, protection key. -// Interrupts (PSR.i) are still off here. -// - - movl r3 = ( IA64_PSR_BN | \ - IA64_PSR_AC | \ - IA64_PSR_IT | \ - IA64_PSR_DB | \ - IA64_PSR_DA | \ - IA64_PSR_RT | \ - IA64_PSR_DT | \ - IA64_PSR_IC \ - ) - ;; - mov cr.ipsr = r3 - -// -// Go to kernel C startup routines -// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. -// This is the only way to set them. - - movl r2=bsp_entry_pc;; - add r2 = r2,r6;; // Relocate to boot node - ld8 r2=[r2];; - mov cr.iip = r2 - srlz.d;; - rfi;; - .endp _start - -// Slave processors come here to spin til they get an interrupt. Then they launch themselves to -// the place ap_entry points. No initialization is necessary - the kernel makes no -// assumptions about state on this entry. -// Note: should verify that the interrupt we got was really the ap_wakeup -// interrupt but this should not be an issue on medusa -slave: - nop.i 0x8beef // Medusa - put cpu to sleep til interrupt occurs - mov r8=cr.irr0;; // Check for interrupt pending. - cmp.eq p6,p0=r8,r0 -(p6) br.cond.sptk slave;; - - mov r8=cr.ivr;; // Got one. Must read ivr to accept it - srlz.d;; - mov cr.eoi=r0;; // must write eoi to clear - movl r8=ap_entry;; // now jump to kernel entry - add r8 = r8,r6;; // Relocate to boot node - ld8 r9=[r8],8;; - ld8 r1=[r8] - mov b0=r9;; - br b0 - -// Here is the kernel stack used for the fake PROM - .bss - .align 16384 -bootstack: - .skip 16384 -bootstacke: -initlock: - data4 diff -urN linux-2.4.18/arch/ia64/sn/fprom/fw-emu.c linux-2.4.19-pre5/arch/ia64/sn/fprom/fw-emu.c --- linux-2.4.18/arch/ia64/sn/fprom/fw-emu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/fw-emu.c Thu Jan 1 01:00:00 1970 @@ -1,524 +0,0 @@ -/* - * PAL & SAL emulation. - * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang - * - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) - */ -#include -#include -#include -#include -#include -#include "fpmem.h" - -#define MB (1024*1024UL) -#define GB (MB*1024UL) - -#define FPROM_BUG() do {while (1);} while (0) -#define MAX_NODES 128 -#define MAX_LSAPICS 512 -#define MAX_CPUS 512 -#define MAX_CPUS_NODE 4 -#define CPUS_PER_NODE 4 -#define CPUS_PER_FSB 2 -#define CPUS_PER_FSB_MASK (CPUS_PER_FSB-1) - -#define NUM_EFI_DESCS 2 - -typedef union ia64_nasid_va { - struct { - unsigned long off : 33; /* intra-region offset */ - unsigned long nasid : 7; /* NASID */ - unsigned long off2 : 21; /* fill */ - unsigned long reg : 3; /* region number */ - } f; - unsigned long l; - void *p; -} ia64_nasid_va; - -typedef struct { - unsigned long pc; - unsigned long gp; -} func_ptr_t; - -#define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;}) -#define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p))) -#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.l;}) - -/* - * The following variables are passed thru registersfrom the configuration file and - * are set via the _start function. - */ -long base_nasid; -long num_cpus; -long bsp_entry_pc=0; -long num_nodes; -long app_entry_pc; -int bsp_lid; -func_ptr_t ap_entry; - - -static efi_runtime_services_t *efi_runtime_p; -static char fw_mem[( sizeof(efi_system_table_t) - + sizeof(efi_runtime_services_t) - + NUM_EFI_DESCS*sizeof(efi_config_table_t) - + sizeof(struct ia64_sal_systab) - + sizeof(struct ia64_sal_desc_entry_point) - + sizeof(struct ia64_sal_desc_ap_wakeup) - + sizeof(acpi_rsdp_t) - + sizeof(acpi_rsdt_t) - + sizeof(acpi_sapic_t) - + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t)) - + (1+8*MAX_NODES)*(sizeof(efi_memory_desc_t)) - + sizeof(ia64_sal_desc_ptc_t) + - + MAX_NODES*sizeof(ia64_sal_ptc_domain_info_t) + - + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) + - + 1024)] __attribute__ ((aligned (8))); - -/* - * 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 (" - .text - .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=0x500000000 /* 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=0x10000000a /* itc_ratio<<32 (1/100) */ - -1: cmp.eq p6,p7=22,r28;; /* PAL_MC_DRAIN */ -(p7) br.cond.sptk.few 1f;; - mov r8=0 - br.cond.sptk.few rp - -1: cmp.eq p6,p7=23,r28;; /* PAL_MC_EXPECTED */ -(p7) br.cond.sptk.few 1f;; - mov r8=0 - br.cond.sptk.few rp - -1: br.cond.sptk.few rp - .endp pal_emulator_static\n"); - - -static efi_status_t -efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) -{ - if (tm) { - memset(tm, 0, sizeof(*tm)); - tm->year = 2000; - tm->month = 2; - tm->day = 13; - tm->hour = 10; - tm->minute = 11; - tm->second = 12; - } - - if (tc) { - tc->resolution = 10; - tc->accuracy = 12; - tc->sets_to_zero = 1; - } - - return EFI_SUCCESS; -} - -static void -efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) -{ - while(1); /* Is there a pseudo-op to stop medusa */ -} - -static efi_status_t -efi_success (void) -{ - return EFI_SUCCESS; -} - -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 = 500000000; - 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... - */ - r9 = 700000000; - break; - - case SAL_FREQ_BASE_REALTIME_CLOCK: - r9 = 1; - break; - - default: - status = -1; - break; - } - } else if (index == SAL_SET_VECTORS) { - if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { - func_ptr_t *fp; - fp = ADDR_OF(&ap_entry); - fp->pc = in2; - fp->gp = in3; - } else { - status = -1; - } - ; - } 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) { - ; - } 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; -} - - -/* - * Fix the addresses in a function pointer by adding base node address - * to pc & gp. - */ -void -fix_function_pointer(void *fp) -{ - func_ptr_t *_fp; - - _fp = fp; - _fp->pc = __fwtab_pa(base_nasid, _fp->pc); - _fp->gp = __fwtab_pa(base_nasid, _fp->gp); -} - -void -fix_virt_function_pointer(void *fptr) -{ - func_ptr_t *fp; - - fp = fptr; - fp->pc = fp->pc | PAGE_OFFSET; - fp->gp = fp->gp | PAGE_OFFSET; -} - - -int -efi_set_virtual_address_map(void) -{ - efi_runtime_services_t *runtime; - - runtime = efi_runtime_p; - fix_virt_function_pointer((void*)runtime->get_time); - fix_virt_function_pointer((void*)runtime->set_time); - fix_virt_function_pointer((void*)runtime->get_wakeup_time); - fix_virt_function_pointer((void*)runtime->set_wakeup_time); - fix_virt_function_pointer((void*)runtime->set_virtual_address_map); - fix_virt_function_pointer((void*)runtime->get_variable); - fix_virt_function_pointer((void*)runtime->get_next_variable); - fix_virt_function_pointer((void*)runtime->set_variable); - fix_virt_function_pointer((void*)runtime->get_next_high_mono_count); - fix_virt_function_pointer((void*)runtime->reset_system); - return EFI_SUCCESS;; -} - - -void -sys_fw_init (const char *args, int arglen, int bsp) -{ - /* - * Use static variables to keep from overflowing the RSE stack - */ - static efi_system_table_t *efi_systab; - static efi_runtime_services_t *efi_runtime; - static efi_config_table_t *efi_tables; - static ia64_sal_desc_ptc_t *sal_ptc; - static ia64_sal_ptc_domain_info_t *sal_ptcdi; - static ia64_sal_ptc_domain_proc_entry_t *sal_ptclid; - static acpi_rsdp_t *acpi_systab; - static acpi_rsdt_t *acpi_rsdt; - static acpi_sapic_t *acpi_sapic; - static acpi_entry_lsapic_t *acpi_lsapic; - static struct ia64_sal_systab *sal_systab; - static efi_memory_desc_t *efi_memmap, *md; - static unsigned long *pal_desc, *sal_desc; - static struct ia64_sal_desc_entry_point *sal_ed; - static struct ia64_boot_param *bp; - static struct ia64_sal_desc_ap_wakeup *sal_apwake; - static unsigned char checksum = 0; - static char *cp, *cmd_line, *vendor; - static int mdsize, domain, last_domain ; - static int cnode, nasid, cpu, num_memmd, cpus_found; - - /* - * Pass the parameter base address to the build_efi_xxx routines. - */ - build_init(8LL*GB*base_nasid); - - num_nodes = GetNumNodes(); - num_cpus = GetNumCpus(); - - - memset(fw_mem, 0, sizeof(fw_mem)); - - pal_desc = (unsigned long *) &pal_emulator_static; - sal_desc = (unsigned long *) &sal_emulator; - fix_function_pointer(&pal_emulator_static); - fix_function_pointer(&sal_emulator); - - /* Align this to 16 bytes, probably EFI does this */ - mdsize = (sizeof(efi_memory_desc_t) + 15) & ~15 ; - - cp = fw_mem; - efi_systab = (void *) cp; cp += sizeof(*efi_systab); - efi_runtime_p = efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); - efi_tables = (void *) cp; cp += NUM_EFI_DESCS*sizeof(*efi_tables); - sal_systab = (void *) cp; cp += sizeof(*sal_systab); - sal_ed = (void *) cp; cp += sizeof(*sal_ed); - sal_ptc = (void *) cp; cp += sizeof(*sal_ptc); - sal_apwake = (void *) cp; cp += sizeof(*sal_apwake); - acpi_systab = (void *) cp; cp += sizeof(*acpi_systab); - acpi_rsdt = (void *) cp; cp += sizeof(*acpi_rsdt); - acpi_sapic = (void *) cp; cp += sizeof(*acpi_sapic); - acpi_lsapic = (void *) cp; cp += num_cpus*sizeof(*acpi_lsapic); - vendor = (char *) cp; cp += 32; - efi_memmap = (void *) cp; cp += 8*32*sizeof(*efi_memmap); - sal_ptcdi = (void *) cp; cp += CPUS_PER_FSB*(1+num_nodes)*sizeof(*sal_ptcdi); - sal_ptclid = (void *) cp; cp += ((3+num_cpus)*sizeof(*sal_ptclid)+7)/8*8; - cmd_line = (void *) cp; - - if (args) { - if (arglen >= 1024) - arglen = 1023; - memcpy(cmd_line, args, arglen); - } else { - arglen = 0; - } - cmd_line[arglen] = '\0'; -#ifdef BRINGUP - /* for now, just bring up bash */ - strcpy(cmd_line, "init=/bin/bash"); -#else - strcpy(cmd_line, ""); -#endif - - 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 = __fwtab_pa(base_nasid, vendor); - efi_systab->fw_revision = 1; - efi_systab->runtime = __fwtab_pa(base_nasid, efi_runtime); - efi_systab->nr_tables = 2; - efi_systab->tables = __fwtab_pa(base_nasid, efi_tables); - memcpy(vendor, "S\0i\0l\0i\0c\0o\0n\0-\0G\0r\0a\0p\0h\0i\0c\0s\0\0", 32); - - 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 = __fwtab_pa(base_nasid, &efi_get_time); - efi_runtime->set_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_wakeup_time = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_virtual_address_map = __fwtab_pa(base_nasid, &efi_set_virtual_address_map); - efi_runtime->get_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_next_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->set_variable = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->get_next_high_mono_count = __fwtab_pa(base_nasid, &efi_unimplemented); - efi_runtime->reset_system = __fwtab_pa(base_nasid, &efi_reset_system); - - efi_tables->guid = SAL_SYSTEM_TABLE_GUID; - efi_tables->table = __fwtab_pa(base_nasid, sal_systab); - efi_tables++; - efi_tables->guid = ACPI_TABLE_GUID; - efi_tables->table = __fwtab_pa(base_nasid, acpi_systab); - fix_function_pointer(&efi_unimplemented); - fix_function_pointer(&efi_get_time); - fix_function_pointer(&efi_success); - fix_function_pointer(&efi_reset_system); - fix_function_pointer(&efi_set_virtual_address_map); - - /* fill in the ACPI system table: */ - memcpy(acpi_systab->signature, "RSD PTR ", 8); - acpi_systab->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt); - - memcpy(acpi_rsdt->header.signature, "RSDT",4); - acpi_rsdt->header.length = sizeof(acpi_rsdt_t); - memcpy(acpi_rsdt->header.oem_id, "SGI", 3); - memcpy(acpi_rsdt->header.oem_table_id, "SN1", 3); - acpi_rsdt->header.oem_revision = 0x00010001; - acpi_rsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_sapic); - - memcpy(acpi_sapic->header.signature, "SPIC ", 4); - acpi_sapic->header.length = sizeof(acpi_sapic_t)+num_cpus*sizeof(acpi_entry_lsapic_t); - for (cnode=0; cnodetype = ACPI_ENTRY_LOCAL_SAPIC; - acpi_lsapic->length = sizeof(acpi_entry_lsapic_t); - acpi_lsapic->acpi_processor_id = cnode*4+cpu; - acpi_lsapic->flags = LSAPIC_ENABLED|LSAPIC_PRESENT; - acpi_lsapic->eid = cpu; - acpi_lsapic->id = nasid; - acpi_lsapic++; - } - } - - - /* 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 = 3; - - strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN1"); - - /* fill in an entry point: */ - sal_ed->type = SAL_DESC_ENTRY_POINT; - sal_ed->pal_proc = __fwtab_pa(base_nasid, pal_desc[0]); - sal_ed->sal_proc = __fwtab_pa(base_nasid, sal_desc[0]); - sal_ed->gp = __fwtab_pa(base_nasid, sal_desc[1]); - - /* kludge the PTC domain info */ - sal_ptc->type = SAL_DESC_PTC; - sal_ptc->num_domains = 0; - sal_ptc->domain_info = __fwtab_pa(base_nasid, sal_ptcdi); - cpus_found = 0; - last_domain = -1; - sal_ptcdi--; - for (cnode=0; cnodenum_domains++; - sal_ptcdi++; - sal_ptcdi->proc_count = 0; - sal_ptcdi->proc_list = __fwtab_pa(base_nasid, sal_ptclid); - last_domain = domain; - } - sal_ptcdi->proc_count++; - sal_ptclid->id = nasid; - sal_ptclid->eid = cpu; - sal_ptclid++; - cpus_found++; - } - } - } - - if (cpus_found != num_cpus) - FPROM_BUG(); - - /* Make the AP WAKEUP entry */ - sal_apwake->type = SAL_DESC_AP_WAKEUP; - sal_apwake->mechanism = IA64_SAL_AP_EXTERNAL_INT; - sal_apwake->vector = 18; - - for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) - checksum += *cp; - - sal_systab->checksum = -checksum; - - md = &efi_memmap[0]; - num_memmd = build_efi_memmap((void *)md, mdsize) ; - - bp = id(ZERO_PAGE_ADDR + (((long)base_nasid)<<33)); - bp->efi_systab = __fwtab_pa(base_nasid, &fw_mem); - bp->efi_memmap = __fwtab_pa(base_nasid, efi_memmap); - bp->efi_memmap_size = num_memmd*mdsize; - bp->efi_memdesc_size = mdsize; - bp->efi_memdesc_version = 0x101; - bp->command_line = __fwtab_pa(base_nasid, 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; - - /* - * Now pick the BSP & store it LID value in - * a global variable. Note if BSP is greater than last cpu, - * pick the last cpu. - */ - for (cnode=0; cnode 0) - continue; - return; - } - } -} diff -urN linux-2.4.18/arch/ia64/sn/fprom/main.c linux-2.4.19-pre5/arch/ia64/sn/fprom/main.c --- linux-2.4.18/arch/ia64/sn/fprom/main.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/fprom/main.c Thu Jan 1 01:00:00 1970 @@ -1,110 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) - */ - - - -#include -#include - -void bedrock_init(int); -void synergy_init(int, int); -void sys_fw_init (const char *args, int arglen, int bsp); - -volatile int bootmaster=0; /* Used to pick bootmaster */ -volatile int nasidmaster[128]={0}; /* Used to pick node/synergy masters */ -int init_done=0; -extern int bsp_lid; - -#define get_bit(b,p) (((*p)>>(b))&1) - -int -fmain(int lid, int bsp) { - int syn, nasid, cpu; - - /* - * First lets figure out who we are. This is done from the - * LID passed to us. - */ - nasid = (lid>>24); - syn = (lid>>17)&1; - cpu = (lid>>16)&1; - - /* - * Now pick a synergy master to initialize synergy registers. - */ - if (test_and_set_bit(syn, &nasidmaster[nasid]) == 0) { - synergy_init(nasid, syn); - test_and_set_bit(syn+2, &nasidmaster[nasid]); - } else - while (get_bit(syn+2, &nasidmaster[nasid]) == 0); - - /* - * Now pick a nasid master to initialize Bedrock registers. - */ - if (test_and_set_bit(8, &nasidmaster[nasid]) == 0) { - bedrock_init(nasid); - test_and_set_bit(9, &nasidmaster[nasid]); - } else - while (get_bit(9, &nasidmaster[nasid]) == 0); - - - /* - * Now pick a BSP & finish init. - */ - if (test_and_set_bit(0, &bootmaster) == 0) { - sys_fw_init(0, 0, bsp); - test_and_set_bit(1, &bootmaster); - } else - while (get_bit(1, &bootmaster) == 0); - - return (lid == bsp_lid); -} - - -void -bedrock_init(int nasid) -{ - nasid = nasid; /* to quiet gcc */ -} - - -void -synergy_init(int nasid, int syn) -{ - long *base; - long off; - - /* - * Enable all FSB flashed interrupts. - * ZZZ - I'd really like defines for this...... - */ - base = (long*)0x80000e0000000000LL; /* base of synergy regs */ - for (off = 0x2a0; off < 0x2e0; off+=8) /* offset for VEC_MASK_{0-3}_A/B */ - *(base+off/8) = -1LL; - - /* - * Set the NASID in the FSB_CONFIG register. - */ - base = (long*)0x80000e0000000450LL; - *base = (long)((nasid<<16)|(syn<<9)); -} - - -/* Why isnt there a bcopy/memcpy in lib64.a */ - -void* -memcpy(void * dest, const void *src, size_t count) -{ - char *s, *se, *d; - - for(d=dest, s=(char*)src, se=s+count; s] <-p> | <-k> [] - -p Create PROM control file & links - -k Create LINUX control file & links - -c Control file name [Default: cf] - Path to directory that contains the linux or PROM files. - The directory can be any of the following: - (linux simulations) - worktree - worktree/linux - any directory with vmlinux, vmlinux.sym & fprom files - (prom simulations) - worktree - worktree/stand/arcs/IP37prom/dev - any directory with fw.bin & fw.sim files - - Simulations: - sim [-X ] [-o ] [-M] [] - -c Control file name [Default: cf] - -M Pipe output thru fmtmedusa - -o Output filename (copy of all commands/output) [Default: simout] - -X Specifies number of instructions to execute [Default: 0] - (Used only in auto test mode - not described here) - -Examples: - sim -p # create control file (cf) & links for prom simulations - sim -k # create control file (cf) & links for linux simulations - sim -p -c cfprom # create a prom control file (cfprom) only. No links are made. - - sim # run medusa using previously created links & - # control file (cf). -END -exit 1 -} - -# ----------------------- create control file header -------------------- -create_cf_header() { -cat <>$CF -# -# Template for a control file for running linux kernels under medusa. -# You probably want to make mods here but this is a good starting point. -# - -# Preferences -setenv cpu_stepping A -setenv exceptionPrint off -setenv interrupt_messages off -setenv lastPCsize 100000 -setenv low_power_mode on -setenv partialIntelChipSet on -setenv printIntelMessages off -setenv prom_write_action halt -setenv prom_write_messages on -setenv step_quantum 100 -setenv swizzling on -setenv tsconsole on -setenv uart_echo on -symbols on - -# IDE disk params -setenv diskCylinders 611 -setenv bootDrive C -setenv diskHeads 16 -setenv diskPath idedisk -setenv diskPresent 1 -setenv diskSpt 63 - -# Hardware config -setenv coherency_type nasid -setenv cpu_cache_type default -setenv synergy_cache_type syn_cac_64m_8w - -# Numalink config -setenv route_enable on -setenv network_type xbar # Select [xbar|router] -setenv network_warning 0xff - -END -} - - -# ------------------ create control file entries for linux simulations ------------- -create_cf_linux() { -cat <>$CF -# Kernel specific options -setenv mca_on_memory_failure off -setenv LOADPC 0x00100000 # FPROM load address/entry point (8 digits!) -sr g 9 0xe000000000520000 # Kernel entry point -setenv symbol_table vmlinux.sym -load fprom -load vmlinux - -# Useful breakpoints to always have set. Add more if desired. -break 0xe000000000505e00 all # dispatch_to_fault_handler -break panic all # stop on panic -break die_if_kernel all # may as well stop - -END -} - -# ------------------ create control file entries for prom simulations --------------- -create_cf_prom() { - SYM2="" - ADDR="0x80000000ff800000" - [ "$EMBEDDED_LINUX" != "0" ] || SYM2="setenv symbol_table2 vmlinux.sym" - [ "$SIZE" = "8MB" ] || ADDR="0x80000000ffc00000" - cat <>$CF -# PROM specific options -setenv mca_on_memory_failure on -setenv LOADPC 0x80000000ffffffb0 -setenv promFile fw.bin -setenv promAddr $ADDR -setenv symbol_table fw.sym -$SYM2 - -# Useful breakpoints to always have set. Add more if desired. -break Pr_ivt_gexx all -break Pr_ivt_brk all -break Pr_PROM_Panic_Spin all -break Pr_PROM_Panic all -break Pr_PROM_C_Panic all -break Pr_fled_die all -break Pr_ResetNow all -break Pr_zzzbkpt all - -END -} - - -# ------------------ create control file entries for memory configuration ------------- -create_cf_memory() { -cat <>$CF -# CPU/Memory map format: -# setenv nodeN_memory_config 0xBSBSBSBS -# B=banksize (0=unused, 1=64M, 2=128M, .., 5-1G, c=8M, d=16M, e=32M) -# S=bank enable (0=both disable, 3=both enable, 2=bank1 enable, 1=bank0 enable) -# rightmost digits are for bank 0, the lowest address. -# setenv nodeN_nasid -# specifies the NASID for the node. This is used ONLY if booting the kernel. -# On PROM configurations, set to 0 - PROM will change it later. -# setenv nodeN_cpu_config -# Set bit number N to 1 to enable cpu N. Ex., a value of 5 enables cpu 0 & 2. -# -# Repeat the above 3 commands for each node. -# -# For kernel, default to 32MB. Although this is not a valid hardware configuration, -# it runs faster on medusa. For PROM, 64MB is smallest allowed value. - -setenv node0_cpu_config 0x1 # Enable only cpu 0 on the node -END - -if [ $LINUX -eq 1 ] ; then -cat <>$CF -setenv node0_nasid 0 # cnode 0 has NASID 0 -setenv node0_memory_config 0xe1 # 32MB -END -else -cat <>$CF -setenv node0_memory_config 0x11 # 64MB -END -fi -} - -# -------------------- set links to linux files ------------------------- -set_linux_links() { - if [ -d $D/linux/arch ] ; then - D=$D/linux - elif [ -d $D/arch -o -e vmlinux.sym ] ; then - D=$D - else - err "cant determine directory for linux binaries" - fi - rm -rf vmlinux vmlinux.sym fprom - ln -s $D/vmlinux vmlinux - ln -s $D/vmlinux.sym vmlinux.sym - if [ -d $D/arch ] ; then - ln -s $D/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/fprom fprom - fi - echo " .. Created links to linux files" -} - -# -------------------- set links to prom files ------------------------- -set_prom_links() { - if [ -d $D/stand ] ; then - D=$D/stand/arcs/IP37prom/dev - elif [ -d $D/sal ] ; then - D=$D - else - err "cant determine directory for PROM binaries" - fi - SETUP="$D/../../../../.setup" - grep -q '^ *setenv *PROMSIZE *8MB' $SETUP - if [ $? -eq 0 ] ; then - SIZE="8MB" - else - SIZE="4MB" - fi - grep -q '^ *setenv *LAUNCH_VMLINUX' $SETUP - EMBEDDED_LINUX=$? - rm -f fw.bin fw.map fw.sym vmlinux vmlinux.sym fprom - SDIR="SN1IA${SIZE}.O" - BIN="SN1IAip37prom${SIZE}" - ln -s $D/$SDIR/$BIN.bin fw.bin - ln -s $D/$SDIR/$BIN.map fw.map - ln -s $D/$SDIR/$BIN.sym fw.sym - echo " .. Created links to $SIZE prom files" - if [ $EMBEDDED_LINUX -eq 0 ] ; then - ln -s $D/linux/vmlinux vmlinux - ln -s $D/linux/vmlinux.sym vmlinux.sym - if [ -d linux/arch ] ; then - ln -s $D/linux/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/linux/fprom fprom - fi - echo " .. Created links to embedded linux files in prom tree" - fi -} - -# --------------- start of shell script -------------------------------- -OUT="simout" -FMTMED=0 -STEPCNT=0 -PROM=0 -LINUX=0 -NCF="cf" -while getopts "HMX:c:o:pk" c ; do - case ${c} in - H) help;; - M) FMTMED=1;; - X) STEPCNT=${OPTARG};; - c) NCF=${OPTARG};; - k) PROM=0;LINUX=1;; - p) PROM=1;LINUX=0;; - o) OUT=${OPTARG};; - \?) exit 1;; - esac -done -shift `expr ${OPTIND} - 1` - -# Check if command is for creating control file and/or links to images. -if [ $PROM -eq 1 -o $LINUX -eq 1 ] ; then - CF=$NCF - [ ! -f $CF ] || err "wont overwrite an existing control file ($CF)" - if [ $# -gt 0 ] ; then - D=$1 - [ -d $D ] || err "cannot find directory $D" - [ $PROM -eq 0 ] || set_prom_links - [ $LINUX -eq 0 ] || set_linux_links - fi - create_cf_header - [ $PROM -eq 0 ] || create_cf_prom - [ $LINUX -eq 0 ] || create_cf_linux - create_cf_memory - echo " .. Basic control file created (in $CF). You might want to edit" - echo " this file (at least, look at it)." - exit 0 -fi - -# Verify that the control file exists -CF=${1:-$NCF} -[ -f $CF ] || err "No control file exists. For help, type: $0 -H" - -# Build the .cf files from the user control file. The .cf file is -# identical except that the actual start & load addresses are inserted -# into the file. In addition, the FPROM commands for configuring memory -# and LIDs are generated. - -rm -f .cf .cf1 .cf2 -awk ' -function strtonum(n) { - if (substr(n,1,2) != "0x") - return int(n) - n = substr(n,3) - r=0 - while (length(n) > 0) { - r = r*16+(index("0123456789abcdef", substr(n,1,1))-1) - n = substr(n,2) - } - return r - } -/^#/ {next} -/^$/ {next} -/^setenv *LOADPC/ {loadpc = $3; next} -/^setenv *node._cpu_config/ {n=int(substr($2,5,1)); cpuconf[n] = strtonum($3); print; next} -/^setenv *node._memory_config/ {n=int(substr($2,5,1)); memconf[n] = strtonum($3); print; next} -/^setenv *node._nasid/ {n=int(substr($2,5,1)); nasid[n] = strtonum($3); print; next} - {print} -END { - # Generate the memmap info that starts at the beginning of - # the node the kernel was loaded on. - loadnasid = nasid[0] - cnode = 0 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "sm 0x%x%08x 0x%x%04x%04x\n", - 2*loadnasid, 8*cnodes+8, memconf[i], cpuconf[i], nasid[i] - cnodes++ - cpus += substr("0112122312232334", cpuconf[i]+1,1) - } - } - printf "sm 0x%x00000000 0x%x%08x\n", 2*loadnasid, cnodes, cpus - printf "setenv number_of_nodes %d\n", cnodes - - # Now set the starting PC for each cpu. - cnode = 0 - lowcpu=-1 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "setnode %d\n", cnode - conf = cpuconf[i] - for (j=0; j<4; j++) { - if (conf != int(conf/2)*2) { - printf "setcpu %d\n", j - if (length(loadpc) == 18) - printf "sr pc %s\n", loadpc - else - printf "sr pc 0x%x%s\n", 2*loadnasid, substr(loadpc,3) - if (lowcpu == -1) - lowcpu = j - } - conf = int(conf/2) - } - cnode++ - } - } - printf "setnode 0\n" - printf "setcpu %d\n", lowcpu - } -' <$CF >.cf - -# Now build the .cf1 & .cf2 control files. -CF2_LINES="^sm |^break |^run |^si |^quit |^symbols " -egrep "$CF2_LINES" .cf >.cf2 -egrep -v "$CF2_LINES" .cf >.cf1 -if [ $STEPCNT -ne 0 ] ; then - echo "s $STEPCNT" >>.cf2 - echo "lastpc 1000" >>.cf2 - echo "q" >>.cf2 -fi -echo "script-on $OUT" >>.cf2 - -# Now start medusa.... -if [ $FMTMED -ne 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 | fmtmedusa -elif [ $STEPCNT -eq 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 -else - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 2>&1 -fi diff -urN linux-2.4.18/arch/ia64/sn/io/Makefile linux-2.4.19-pre5/arch/ia64/sn/io/Makefile --- linux-2.4.18/arch/ia64/sn/io/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/Makefile Sat Mar 30 22:55:25 2002 @@ -3,8 +3,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 2000 Silicon Graphics, Inc. -# Copyright (C) Jack Steiner (steiner@sgi.com) +# Copyright (C) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. # # # Makefile for the linux kernel. @@ -13,20 +12,34 @@ # 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... -EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ - -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ - -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS +EXTRA_CFLAGS := -DLITTLE_ENDIAN + O_TARGET := sgiio.o -obj-y := stubs.o sgi_if.o pciio.o pcibr.o xtalk.o xbow.o xswitch.o hubspc.o \ - klgraph_hack.o io.o hubdev.o huberror.o \ + +ifeq ($(CONFIG_MODULES),y) +export-objs = pciio.o hcl.o +endif + +obj-y := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \ hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \ module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \ - ml_SN_intr.o ip37.o pciba.o \ - ml_iograph.o hcl_util.o cdl.o \ - mem_refcnt.o devsupport.o alenlist.o pci_bus_cvlink.o \ - eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o + ml_iograph.o hcl_util.o cdl.o hubdev.o hubspc.o \ + alenlist.o pci_bus_cvlink.o \ + eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o \ + ifconfig_net.o efi-rtc.o io.o + +obj-$(CONFIG_IA64_SGI_SN1) += sn1/ml_SN_intr.o sn1/mem_refcnt.o sn1/hubcounters.o \ + sn1/ip37.o sn1/huberror.o sn1/hub_intr.o sn1/pcibr.o + +obj-$(CONFIG_IA64_SGI_SN2) += sn2/ml_SN_intr.o sn2/shub_intr.o sn2/shuberror.o \ + sn2/bte_error.o \ + sn2/pcibr/pcibr_dvr.o sn2/pcibr/pcibr_ate.o \ + sn2/pcibr/pcibr_config.o sn2/pcibr/pcibr_dvr.o \ + sn2/pcibr/pcibr_hints.o \ + sn2/pcibr/pcibr_idbg.o sn2/pcibr/pcibr_intr.o \ + sn2/pcibr/pcibr_rrb.o sn2/pcibr/pcibr_slot.o + +obj-$(CONFIG_PCIBA) += pciba.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/io/alenlist.c linux-2.4.19-pre5/arch/ia64/sn/io/alenlist.c --- linux-2.4.18/arch/ia64/sn/io/alenlist.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/alenlist.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ /* Implementation of Address/Length Lists. */ @@ -13,9 +12,9 @@ #include #include +#include #include #include -#include /* * Logically, an Address/Length List is a list of Pairs, where each pair @@ -218,9 +217,9 @@ void alenlist_init(void) { - alenlist_zone = kmem_zone_init(sizeof(struct alenlist_s), "alenlist"); - alenlist_chunk_zone = kmem_zone_init(sizeof(struct alenlist_chunk_s), "alchunk"); - alenlist_cursor_zone = kmem_zone_init(sizeof(struct alenlist_cursor_s), "alcursor"); + alenlist_zone = snia_kmem_zone_init(sizeof(struct alenlist_s), "alenlist"); + alenlist_chunk_zone = snia_kmem_zone_init(sizeof(struct alenlist_chunk_s), "alchunk"); + alenlist_cursor_zone = snia_kmem_zone_init(sizeof(struct alenlist_cursor_s), "alcursor"); #if DEBUG idbg_addfunc("alenshow", alenlist_show); #endif /* DEBUG */ @@ -250,7 +249,7 @@ { alenlist_t alenlist; - alenlist = kmem_zone_alloc(alenlist_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); + alenlist = snia_kmem_zone_alloc(alenlist_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); if (alenlist) { INCR_COUNT(&alenlist_count); @@ -334,7 +333,7 @@ while (chunk) { freechunk = chunk; chunk = chunk->alc_next; - kmem_zone_free(alenlist_chunk_zone, freechunk); + snia_kmem_zone_free(alenlist_chunk_zone, freechunk); DECR_COUNT(&alenlist_chunk_count); } alenlist->al_actual_size = ALEN_CHUNK_SZ; @@ -407,7 +406,7 @@ alenlist_clear(alenlist); /* Now, free the alenlist itself */ - kmem_zone_free(alenlist_zone, alenlist); + snia_kmem_zone_free(alenlist_zone, alenlist); DECR_COUNT(&alenlist_count); } @@ -473,7 +472,7 @@ } else { alenlist_chunk_t new_chunk; - new_chunk = kmem_zone_alloc(alenlist_chunk_zone, + new_chunk = snia_kmem_zone_alloc(alenlist_chunk_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); if (new_chunk == NULL) @@ -656,7 +655,7 @@ alenlist_cursor_t cursorp; ASSERT(alenlist != NULL); - cursorp = kmem_zone_alloc(alenlist_cursor_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); + cursorp = snia_kmem_zone_alloc(alenlist_cursor_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); if (cursorp) { INCR_COUNT(&alenlist_cursor_count); alenlist_cursor_init(alenlist, 0, cursorp); @@ -671,7 +670,7 @@ alenlist_cursor_destroy(alenlist_cursor_t cursorp) { DECR_COUNT(&alenlist_cursor_count); - kmem_zone_free(alenlist_cursor_zone, cursorp); + snia_kmem_zone_free(alenlist_cursor_zone, cursorp); } @@ -752,7 +751,7 @@ maxlength -= ((alenp->al_addr + cursorp->al_bcount) & maxlen1); - length = MIN(maxlength, length); + length = min(maxlength, length); } /* Update the cursor, if desired. */ @@ -842,7 +841,7 @@ offset = poff(kvaddr); /* Handle first page */ - piece_length = MIN(NBPP - offset, length); + piece_length = min((size_t)(NBPP - offset), length); if (alenlist_append(alenlist, paddr, piece_length, flags) == ALENLIST_FAILURE) goto failure; length -= piece_length; diff -urN linux-2.4.18/arch/ia64/sn/io/ate_utils.c linux-2.4.19-pre5/arch/ia64/sn/io/ate_utils.c --- linux-2.4.18/arch/ia64/sn/io/ate_utils.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ate_utils.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,205 @@ +/* $Id: ate_utils.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Allocate the map needed to allocate the ATE entries. + */ +struct map * +atemapalloc(ulong_t mapsiz) +{ + struct map *mp; + ulong_t size; + struct a { + spinlock_t lock; + sv_t sema; + } *sync; + + if (mapsiz == 0) + return(NULL); + size = sizeof(struct map) * (mapsiz + 2); + if ((mp = (struct map *) kmalloc(size, GFP_KERNEL)) == NULL) + return(NULL); + memset(mp, 0x0, size); + + sync = kmalloc(sizeof(struct a), GFP_KERNEL); + if (sync == NULL) { + kfree(mp); + return(NULL); + } + memset(sync, 0x0, sizeof(struct a)); + + mutex_spinlock_init(&sync->lock); + sv_init( &(sync->sema), &(sync->lock), SV_MON_SPIN | SV_ORDER_FIFO /*| SV_INTS*/); + mp[1].m_size = (unsigned long) &sync->lock; + mp[1].m_addr = (unsigned long) &sync->sema; + mapsize(mp) = mapsiz - 1; + return(mp); +} + +/* + * free a map structure previously allocated via rmallocmap(). + */ +void +atemapfree(struct map *mp) +{ + struct a { + spinlock_t lock; + sv_t sema; + }; + /* ASSERT(sv_waitq(mapout(mp)) == 0); */ + /* sv_destroy(mapout(mp)); */ + spin_lock_destroy(maplock(mp)); + kfree((void *)mp[1].m_size); + kfree(mp); +} + +/* + * Allocate 'size' units from the given map. + * Return the base of the allocated space. + * In a map, the addresses are increasing and the + * list is terminated by a 0 size. + * Algorithm is first-fit. + */ + +ulong_t +atealloc( + struct map *mp, + size_t size) +{ + register unsigned int a; + register struct map *bp; + register unsigned long s; + + ASSERT(size >= 0); + + if (size == 0) + return((ulong_t) NULL); + + s = mutex_spinlock(maplock(mp)); + + for (bp = mapstart(mp); bp->m_size; bp++) { + if (bp->m_size >= size) { + a = bp->m_addr; + bp->m_addr += size; + if ((bp->m_size -= size) == 0) { + do { + bp++; + (bp-1)->m_addr = bp->m_addr; + } while ((((bp-1)->m_size) = (bp->m_size))); + mapsize(mp)++; + } + + ASSERT(bp->m_size < 0x80000000); + mutex_spinunlock(maplock(mp), s); + return(a); + } + } + + /* + * We did not get what we need .. we cannot sleep .. + */ + mutex_spinunlock(maplock(mp), s); + return(0); +} + +/* + * Free the previously allocated space a of size units into the specified map. + * Sort ``a'' into map and combine on one or both ends if possible. + * Returns 0 on success, 1 on failure. + */ +void +atefree(struct map *mp, size_t size, ulong_t a) +{ + register struct map *bp; + register unsigned int t; + register unsigned long s; + + ASSERT(size >= 0); + + if (size == 0) + return; + + bp = mapstart(mp); + s = mutex_spinlock(maplock(mp)); + + for ( ; bp->m_addr<=a && bp->m_size!=0; bp++) + ; + if (bp>mapstart(mp) && (bp-1)->m_addr+(bp-1)->m_size == a) { + (bp-1)->m_size += size; + if (bp->m_addr) { + /* m_addr==0 end of map table */ + ASSERT(a+size <= bp->m_addr); + if (a+size == bp->m_addr) { + + /* compress adjacent map addr entries */ + (bp-1)->m_size += bp->m_size; + while (bp->m_size) { + bp++; + (bp-1)->m_addr = bp->m_addr; + (bp-1)->m_size = bp->m_size; + } + mapsize(mp)++; + } + } + } else { + if (a+size == bp->m_addr && bp->m_size) { + bp->m_addr -= size; + bp->m_size += size; + } else { + ASSERT(size); + if (mapsize(mp) == 0) { + mutex_spinunlock(maplock(mp), s); + printk("atefree : map overflow 0x%p Lost 0x%lx items at 0x%lx", + (void *)mp, size, a) ; + return ; + } + do { + t = bp->m_addr; + bp->m_addr = a; + a = t; + t = bp->m_size; + bp->m_size = size; + bp++; + } while ((size = t)); + mapsize(mp)--; + } + } + mutex_spinunlock(maplock(mp), s); + /* + * wake up everyone waiting for space + */ + if (mapout(mp)) + ; + /* sv_broadcast(mapout(mp)); */ +} diff -urN linux-2.4.18/arch/ia64/sn/io/cdl.c linux-2.4.19-pre5/arch/ia64/sn/io/cdl.c --- linux-2.4.18/arch/ia64/sn/io/cdl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/cdl.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include @@ -17,11 +16,9 @@ #include "asm/sn/ioerror_handling.h" #include -#ifdef BRINGUP /* these get called directly in cdl_add_connpt in fops bypass hack */ extern int pcibr_attach(devfs_handle_t); extern int xbow_attach(devfs_handle_t); -#endif /* BRINGUP */ /* * cdl: Connection and Driver List @@ -37,8 +34,6 @@ int mfg_num; int (*attach) (devfs_handle_t); } dummy_reg; - -typedef struct cdl *cdl_p; #define MAX_SGI_IO_INFRA_DRVR 4 struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = diff -urN linux-2.4.18/arch/ia64/sn/io/devsupport.c linux-2.4.19-pre5/arch/ia64/sn/io/devsupport.c --- linux-2.4.18/arch/ia64/sn/io/devsupport.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/devsupport.c Thu Jan 1 01:00:00 1970 @@ -1,1289 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Interfaces in this file are all platform-independent AND IObus-independent. - * Be aware that there may be macro equivalents to each of these hiding in - * header files which supercede these functions. - */ - -/* =====Generic iobus support===== */ - -/* String table to hold names of interrupts. */ -#ifdef LATER -static struct string_table device_desc_string_table; -#endif - -/* One time initialization for device descriptor support. */ -static void -device_desc_init(void) -{ -#ifdef LATER - string_table_init(&device_desc_string_table); -#endif - FIXME("device_desc_init"); -} - - -/* Drivers use these interfaces to manage device descriptors */ -static device_desc_t -device_desc_alloc(void) -{ -#ifdef LATER - device_desc_t device_desc; - - device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0); - device_desc->intr_target = GRAPH_VERTEX_NONE; - - ASSERT(device_desc->intr_policy == 0); - device_desc->intr_swlevel = -1; - ASSERT(device_desc->intr_name == NULL); - ASSERT(device_desc->flags == 0); - - ASSERT(!(device_desc->flags & D_IS_ASSOC)); - return(device_desc); -#else - FIXME("device_desc_alloc"); - return((device_desc_t)0); -#endif -} - -void -device_desc_free(device_desc_t device_desc) -{ -#ifdef LATER - if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */ - kfree(device_desc); -#endif - FIXME("device_desc_free"); -} - -device_desc_t -device_desc_dup(devfs_handle_t dev) -{ -#ifdef LATER - device_desc_t orig_device_desc, new_device_desc; - - - new_device_desc = device_desc_alloc(); - orig_device_desc = device_desc_default_get(dev); - if (orig_device_desc) - *new_device_desc = *orig_device_desc;/* small structure copy */ - else { - device_driver_t driver; - ilvl_t pri; - /* - * Use the driver's thread priority in - * case the device thread priority has not - * been given. - */ - if (driver = device_driver_getbydev(dev)) { - pri = device_driver_thread_pri_get(driver); - device_desc_intr_swlevel_set(new_device_desc,pri); - } - } - new_device_desc->flags &= ~D_IS_ASSOC; - return(new_device_desc); -#else - FIXME("device_desc_dup"); - return((device_desc_t)0); -#endif -} - -device_desc_t -device_desc_default_get(devfs_handle_t dev) -{ -#ifdef LATER - graph_error_t rc; - device_desc_t device_desc; - - rc = hwgraph_info_get_LBL(dev, INFO_LBL_DEVICE_DESC, (arbitrary_info_t *)&device_desc); - - if (rc == GRAPH_SUCCESS) - return(device_desc); - else - return(NULL); -#else - FIXME("device_desc_default_get"); - return((device_desc_t)0); -#endif -} - -void -device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc) -{ -#ifdef LATER - graph_error_t rc; - device_desc_t old_device_desc = NULL; - - if (new_device_desc) { - new_device_desc->flags |= D_IS_ASSOC; - rc = hwgraph_info_add_LBL(dev, INFO_LBL_DEVICE_DESC, - (arbitrary_info_t)new_device_desc); - if (rc == GRAPH_DUP) { - rc = hwgraph_info_replace_LBL(dev, INFO_LBL_DEVICE_DESC, - (arbitrary_info_t)new_device_desc, - (arbitrary_info_t *)&old_device_desc); - - ASSERT(rc == GRAPH_SUCCESS); - } - hwgraph_info_export_LBL(dev, INFO_LBL_DEVICE_DESC, - sizeof(struct device_desc_s)); - } else { - rc = hwgraph_info_remove_LBL(dev, INFO_LBL_DEVICE_DESC, - (arbitrary_info_t *)&old_device_desc); - } - - if (old_device_desc) { - ASSERT(old_device_desc->flags & D_IS_ASSOC); - old_device_desc->flags &= ~D_IS_ASSOC; - device_desc_free(old_device_desc); - } -#endif - FIXME("device_desc_default_set"); -} - -devfs_handle_t -device_desc_intr_target_get(device_desc_t device_desc) -{ -#ifdef LATER - return(device_desc->intr_target); -#else - FIXME("device_desc_intr_target_get"); - return((devfs_handle_t)0); -#endif -} - -int -device_desc_intr_policy_get(device_desc_t device_desc) -{ -#ifdef LATER - return(device_desc->intr_policy); -#else - FIXME("device_desc_intr_policy_get"); - return(0); -#endif -} - -ilvl_t -device_desc_intr_swlevel_get(device_desc_t device_desc) -{ -#ifdef LATER - return(device_desc->intr_swlevel); -#else - FIXME("device_desc_intr_swlevel_get"); - return((ilvl_t)0); -#endif -} - -char * -device_desc_intr_name_get(device_desc_t device_desc) -{ -#ifdef LATER - return(device_desc->intr_name); -#else - FIXME("device_desc_intr_name_get"); - return(NULL); -#endif -} - -int -device_desc_flags_get(device_desc_t device_desc) -{ -#ifdef LATER - return(device_desc->flags); -#else - FIXME("device_desc_flags_get"); - return(0); -#endif -} - -void -device_desc_intr_target_set(device_desc_t device_desc, devfs_handle_t target) -{ - if ( device_desc != (device_desc_t)0 ) - device_desc->intr_target = target; -} - -void -device_desc_intr_policy_set(device_desc_t device_desc, int policy) -{ - if ( device_desc != (device_desc_t)0 ) - device_desc->intr_policy = policy; -} - -void -device_desc_intr_swlevel_set(device_desc_t device_desc, ilvl_t swlevel) -{ - if ( device_desc != (device_desc_t)0 ) - device_desc->intr_swlevel = swlevel; -} - -void -device_desc_intr_name_set(device_desc_t device_desc, char *name) -{ -#ifdef LATER - if ( device_desc != (device_desc_t)0 ) - device_desc->intr_name = string_table_insert(&device_desc_string_table, name); -#else - FIXME("device_desc_intr_name_set"); -#endif -} - -void -device_desc_flags_set(device_desc_t device_desc, int flags) -{ - if ( device_desc != (device_desc_t)0 ) - device_desc->flags = flags; -} - - - -/*============= device admin registry routines ===================== */ - -/* Linked list of pairs */ -typedef struct dev_admin_list_s { - struct dev_admin_list_s *admin_next; /* next entry in the - * list - */ - char *admin_name; /* info label */ - char *admin_val; /* actual info */ -} dev_admin_list_t; - -/* Device/Driver administration registry */ -typedef struct dev_admin_registry_s { - mrlock_t reg_lock; /* To allow - * exclusive - * access - */ - dev_admin_list_t *reg_first; /* first entry in - * the list - */ - dev_admin_list_t **reg_last; /* pointer to the - * next to last entry - * in the last which - * is also the place - * where the new - * entry gets - * inserted - */ -} dev_admin_registry_t; - -/* -** device_driver_s associates a device driver prefix with device switch entries. -*/ -struct device_driver_s { - struct device_driver_s *dd_next; /* next element on hash chain */ - struct device_driver_s *dd_prev; /* previous element on hash chain */ - char *dd_prefix; /* driver prefix string */ - struct bdevsw *dd_bdevsw; /* driver's bdevsw */ - struct cdevsw *dd_cdevsw; /* driver's cdevsw */ - - /* driver administration specific data structures need to - * maintain the list of pairs - */ - dev_admin_registry_t dd_dev_admin_registry; - ilvl_t dd_thread_pri; /* default thread priority for - * all this driver's - * threads. - */ - -}; - -#define NEW(_p) (_p = kmalloc(sizeof(*_p), GFP_KERNEL)) -#define FREE(_p) (kmem_free(_p)) - -/* - * helpful lock macros - */ - -#define DEV_ADMIN_REGISTRY_INITLOCK(lockp,name) mrinit(lockp,name) -#define DEV_ADMIN_REGISTRY_RDLOCK(lockp) mraccess(lockp) -#define DEV_ADMIN_REGISTRY_WRLOCK(lockp) mrupdate(lockp) -#define DEV_ADMIN_REGISTRY_UNLOCK(lockp) mrunlock(lockp) - -/* Initialize the registry - */ -static void -dev_admin_registry_init(dev_admin_registry_t *registry) -{ -#ifdef LATER - if ( registry != (dev_admin_registry_t *)0 ) - DEV_ADMIN_REGISTRY_INITLOCK(®istry->reg_lock, - "dev_admin_registry_lock"); - registry->reg_first = NULL; - registry->reg_last = ®istry->reg_first; - } -#else - FIXME("dev_admin_registry_init"); -#endif -} - -/* - * add an entry to the dev admin registry. - * if the name already exists in the registry then change the - * value iff the new value differs from the old value. - * if the name doesn't exist a new list entry is created and put - * at the end. - */ -static void -dev_admin_registry_add(dev_admin_registry_t *registry, - char *name, - char *val) -{ -#ifdef LATER - dev_admin_list_t *reg_entry; - dev_admin_list_t *scan = 0; - - DEV_ADMIN_REGISTRY_WRLOCK(®istry->reg_lock); - - /* check if the name already exists in the registry */ - scan = registry->reg_first; - - while (scan) { - if (strcmp(scan->admin_name,name) == 0) { - /* name is there in the registry */ - if (strcmp(scan->admin_val,val)) { - /* old value != new value - * reallocate memory and copy the new value - */ - FREE(scan->admin_val); - scan->admin_val = - (char *)kern_calloc(1,strlen(val)+1); - strcpy(scan->admin_val,val); - goto out; - } - goto out; /* old value == new value */ - } - scan = scan->admin_next; - } - - /* name is not there in the registry. - * allocate memory for the new registry entry - */ - NEW(reg_entry); - - reg_entry->admin_next = 0; - reg_entry->admin_name = (char *)kern_calloc(1,strlen(name)+1); - strcpy(reg_entry->admin_name,name); - reg_entry->admin_val = (char *)kern_calloc(1,strlen(val)+1); - strcpy(reg_entry->admin_val,val); - - /* add the entry at the end of the registry */ - - *(registry->reg_last) = reg_entry; - registry->reg_last = ®_entry->admin_next; - -out: DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock); -#endif - FIXME("dev_admin_registry_add"); -} -/* - * check if there is an info corr. to a particular - * name starting from the cursor position in the - * registry - */ -static char * -dev_admin_registry_find(dev_admin_registry_t *registry,char *name) -{ -#ifdef LATER - dev_admin_list_t *scan = 0; - - DEV_ADMIN_REGISTRY_RDLOCK(®istry->reg_lock); - scan = registry->reg_first; - - while (scan) { - if (strcmp(scan->admin_name,name) == 0) { - DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock); - return scan->admin_val; - } - scan = scan->admin_next; - } - DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock); - return 0; -#else - FIXME("dev_admin_registry_find"); - return(NULL); -#endif -} -/*============= MAIN DEVICE/ DRIVER ADMINISTRATION INTERFACE================ */ -/* - * return any labelled info associated with a device. - * called by any kernel code including device drivers. - */ -char * -device_admin_info_get(devfs_handle_t dev_vhdl, - char *info_lbl) -{ -#ifdef LATER - char *info = 0; - - /* return value need not be GRAPH_SUCCESS as the labelled - * info may not be present - */ - (void)hwgraph_info_get_LBL(dev_vhdl,info_lbl, - (arbitrary_info_t *)&info); - - - return info; -#else - FIXME("device_admin_info_get"); - return(NULL); -#endif -} - -/* - * set labelled info associated with a device. - * called by hwgraph infrastructure . may also be called - * by device drivers etc. - */ -int -device_admin_info_set(devfs_handle_t dev_vhdl, - char *dev_info_lbl, - char *dev_info_val) -{ -#ifdef LATER - graph_error_t rv; - arbitrary_info_t old_info; - - /* Handle the labelled info - * intr_target - * sw_level - * in a special way. These are part of device_desc_t - * Right now this is the only case where we have - * a set of related device_admin attributes which - * are grouped together. - * In case there is a need for another set we need to - * take a more generic approach to solving this. - * Basically a registry should be implemented. This - * registry is initialized with the callbacks for the - * attributes which need to handled in a special way - * For example: - * Consider - * device_desc - * intr_target - * intr_swlevel - * register "do_intr_target" for intr_target - * register "do_intr_swlevel" for intr_swlevel. - * When the device_admin interface layer gets an pair - * it looks in the registry to see if there is a function registered to - * handle "attr. If not follow the default path of setting the - * as labelled information hanging off the vertex. - * In the above example: - * "do_intr_target" does what is being done below for the ADMIN_LBL_INTR_TARGET - * case - */ - if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET) || - !strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) { - - device_desc_t device_desc; - - /* Check if there is a default device descriptor - * information for this vertex. If not dup one . - */ - if (!(device_desc = device_desc_default_get(dev_vhdl))) { - device_desc = device_desc_dup(dev_vhdl); - device_desc_default_set(dev_vhdl,device_desc); - - } - if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET)) { - /* Check if a target cpu has been specified - * for this device by a device administration - * directive - */ -#ifdef DEBUG - printf(ADMIN_LBL_INTR_TARGET - " dev = 0x%x " - "dev_admin_info = %s" - " target = 0x%x\n", - dev_vhdl, - dev_info_lbl, - hwgraph_path_to_vertex(dev_info_val)); -#endif - - device_desc->intr_target = - hwgraph_path_to_vertex(dev_info_val); - } else if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) { - /* Check if the ithread priority level has been - * specified for this device by a device administration - * directive - */ -#ifdef DEBUG - printf(ADMIN_LBL_INTR_SWLEVEL - " dev = 0x%x " - "dev_admin_info = %s" - " sw level = 0x%x\n", - dev_vhdl, - dev_info_lbl, - atoi(dev_info_val)); -#endif - device_desc->intr_swlevel = atoi(dev_info_val); - } - - } - if (!dev_info_val) - rv = hwgraph_info_remove_LBL(dev_vhdl, - dev_info_lbl, - &old_info); - else { - - rv = hwgraph_info_add_LBL(dev_vhdl, - dev_info_lbl, - (arbitrary_info_t)dev_info_val); - - if (rv == GRAPH_DUP) { - rv = hwgraph_info_replace_LBL(dev_vhdl, - dev_info_lbl, - (arbitrary_info_t)dev_info_val, - &old_info); - } - } - ASSERT(rv == GRAPH_SUCCESS); -#endif - FIXME("device_admin_info_set"); - return 0; -} - -/* - * return labelled info associated with a device driver - * called by kernel code including device drivers - */ -char * -device_driver_admin_info_get(char *driver_prefix, - char *driver_info_lbl) -{ -#ifdef LATER - device_driver_t driver; - - driver = device_driver_get(driver_prefix); - return (dev_admin_registry_find(&driver->dd_dev_admin_registry, - driver_info_lbl)); -#else - FIXME("device_driver_admin_info_get"); - return(NULL); -#endif -} - -/* - * set labelled info associated with a device driver. - * called by hwgraph infrastructure . may also be called - * from drivers etc. - */ -int -device_driver_admin_info_set(char *driver_prefix, - char *driver_info_lbl, - char *driver_info_val) -{ -#ifdef LATER - device_driver_t driver; - - driver = device_driver_get(driver_prefix); - dev_admin_registry_add(&driver->dd_dev_admin_registry, - driver_info_lbl, - driver_info_val); -#endif - FIXME("device_driver_admin_info_set"); - return 0; -} -/*================== device / driver admin support routines================*/ - -/* static tables created by lboot */ -extern dev_admin_info_t dev_admin_table[]; -extern dev_admin_info_t drv_admin_table[]; -extern int dev_admin_table_size; -extern int drv_admin_table_size; - -/* Extend the device admin table to allow the kernel startup code to - * provide some device specific administrative hints - */ -#define ADMIN_TABLE_CHUNK 100 -static dev_admin_info_t extended_dev_admin_table[ADMIN_TABLE_CHUNK]; -static int extended_dev_admin_table_size = 0; -static mrlock_t extended_dev_admin_table_lock; - -/* Initialize the extended device admin table */ -void -device_admin_table_init(void) -{ -#ifdef LATER - extended_dev_admin_table_size = 0; - mrinit(&extended_dev_admin_table_lock, - "extended_dev_admin_table_lock"); -#endif - FIXME("device_admin_table_init"); -} -/* Add triple to - * the extended device administration info table. This is helpful - * for kernel startup code to put some hints before the hwgraph - * is setup - */ -void -device_admin_table_update(char *name,char *label,char *value) -{ -#ifdef LATER - dev_admin_info_t *p; - - mrupdate(&extended_dev_admin_table_lock); - - /* Safety check that we haven't exceeded array limits */ - ASSERT(extended_dev_admin_table_size < ADMIN_TABLE_CHUNK); - - if (extended_dev_admin_table_size == ADMIN_TABLE_CHUNK) - goto out; - - /* Get the pointer to the entry in the table where we are - * going to put the new information - */ - p = &extended_dev_admin_table[extended_dev_admin_table_size++]; - - /* Allocate memory for the strings and copy them in */ - p->dai_name = (char *)kern_calloc(1,strlen(name)+1); - strcpy(p->dai_name,name); - p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1); - strcpy(p->dai_param_name,label); - p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1); - strcpy(p->dai_param_val,value); - -out: mrunlock(&extended_dev_admin_table_lock); -#endif - FIXME("device_admin_table_update"); -} -/* Extend the device driver admin table to allow the kernel startup code to - * provide some device driver specific administrative hints - */ - -static dev_admin_info_t extended_drv_admin_table[ADMIN_TABLE_CHUNK]; -static int extended_drv_admin_table_size = 0; -mrlock_t extended_drv_admin_table_lock; - -/* Initialize the extended device driver admin table */ -void -device_driver_admin_table_init(void) -{ -#ifdef LATER - extended_drv_admin_table_size = 0; - mrinit(&extended_drv_admin_table_lock, - "extended_drv_admin_table_lock"); -#endif - FIXME("device_driver_admin_table_init"); -} -/* Add triple to - * the extended device administration info table. This is helpful - * for kernel startup code to put some hints before the hwgraph - * is setup - */ -void -device_driver_admin_table_update(char *name,char *label,char *value) -{ -#ifdef LATER - dev_admin_info_t *p; - - mrupdate(&extended_dev_admin_table_lock); - - /* Safety check that we haven't exceeded array limits */ - ASSERT(extended_drv_admin_table_size < ADMIN_TABLE_CHUNK); - - if (extended_drv_admin_table_size == ADMIN_TABLE_CHUNK) - goto out; - - /* Get the pointer to the entry in the table where we are - * going to put the new information - */ - p = &extended_drv_admin_table[extended_drv_admin_table_size++]; - - /* Allocate memory for the strings and copy them in */ - p->dai_name = (char *)kern_calloc(1,strlen(name)+1); - strcpy(p->dai_name,name); - p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1); - strcpy(p->dai_param_name,label); - p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1); - strcpy(p->dai_param_val,value); - -out: mrunlock(&extended_drv_admin_table_lock); -#endif - FIXME("device_driver_admin_table_update"); -} -/* - * keeps on adding the labelled info for each new (lbl,value) pair - * that it finds in the static dev admin table ( created by lboot) - * and the extended dev admin table ( created if at all by the kernel startup - * code) corresponding to a device in the hardware graph. - */ -void -device_admin_info_update(devfs_handle_t dev_vhdl) -{ -#ifdef LATER - int i = 0; - dev_admin_info_t *scan; - devfs_handle_t scan_vhdl; - - /* Check the static device administration info table */ - scan = dev_admin_table; - while (i < dev_admin_table_size) { - - scan_vhdl = hwgraph_path_to_dev(scan->dai_name); - if (scan_vhdl == dev_vhdl) { - device_admin_info_set(dev_vhdl, - scan->dai_param_name, - scan->dai_param_val); - } - if (scan_vhdl != NODEV) - hwgraph_vertex_unref(scan_vhdl); - scan++;i++; - - } - i = 0; - /* Check the extended device administration info table */ - scan = extended_dev_admin_table; - while (i < extended_dev_admin_table_size) { - scan_vhdl = hwgraph_path_to_dev(scan->dai_name); - if (scan_vhdl == dev_vhdl) { - device_admin_info_set(dev_vhdl, - scan->dai_param_name, - scan->dai_param_val); - } - if (scan_vhdl != NODEV) - hwgraph_vertex_unref(scan_vhdl); - scan++;i++; - - } - - -#endif - FIXME("device_admin_info_update"); -} - -/* looks up the static drv admin table ( created by the lboot) and the extended - * drv admin table (created if at all by the kernel startup code) - * for this driver specific administration info and adds it to the admin info - * associated with this device driver's object - */ -void -device_driver_admin_info_update(device_driver_t driver) -{ -#ifdef LATER - int i = 0; - dev_admin_info_t *scan; - - /* Check the static device driver administration info table */ - scan = drv_admin_table; - while (i < drv_admin_table_size) { - - if (strcmp(scan->dai_name,driver->dd_prefix) == 0) { - dev_admin_registry_add(&driver->dd_dev_admin_registry, - scan->dai_param_name, - scan->dai_param_val); - } - scan++;i++; - } - i = 0; - /* Check the extended device driver administration info table */ - scan = extended_drv_admin_table; - while (i < extended_drv_admin_table_size) { - - if (strcmp(scan->dai_name,driver->dd_prefix) == 0) { - dev_admin_registry_add(&driver->dd_dev_admin_registry, - scan->dai_param_name, - scan->dai_param_val); - } - scan++;i++; - } -#endif - FIXME("device_driver_admin_info_update"); -} - -/* =====Device Driver Support===== */ - - - -/* -** Generic device driver support routines for use by kernel modules that -** deal with device drivers (but NOT for use by the drivers themselves). -** EVERY registered driver currently in the system -- static or loadable -- -** has an entry in the device_driver_hash table. A pointer to such an entry -** serves as a generic device driver handle. -*/ - -#define DEVICE_DRIVER_HASH_SIZE 32 -#ifdef LATER -lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE]; -device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE]; -static struct string_table driver_prefix_string_table; -#endif - -/* -** Initialize device driver infrastructure. -*/ -void -device_driver_init(void) -{ -#ifdef LATER - int i; - extern void alenlist_init(void); - extern void hwgraph_init(void); - extern void device_desc_init(void); - - ASSERT(DEVICE_DRIVER_NONE == NULL); - alenlist_init(); - hwgraph_init(); - device_desc_init(); - - string_table_init(&driver_prefix_string_table); - - for (i=0; isdd_prefix); - if (!driver) - driver = device_driver_alloc(desc->sdd_prefix); - pri = device_driver_sysgen_thread_pri_get(desc->sdd_prefix); - device_driver_thread_pri_set(driver, pri); - device_driver_devsw_put(driver, desc->sdd_bdevsw, desc->sdd_cdevsw); - } -#endif - FIXME("device_driver_init"); -} - -/* -** Hash a prefix string into a hash table chain. -*/ -static int -driver_prefix_hash(char *prefix) -{ -#ifdef LATER - int accum = 0; - char nextchar; - - while (nextchar = *prefix++) - accum = accum ^ nextchar; - - return(accum % DEVICE_DRIVER_HASH_SIZE); -#else - FIXME("driver_prefix_hash"); - return(0); -#endif -} - - -/* -** Allocate a driver handle. -** Returns the driver handle, or NULL if the driver prefix -** already has a handle. -** -** Upper layers prevent races among device_driver_alloc, -** device_driver_free, and device_driver_get*. -*/ -device_driver_t -device_driver_alloc(char *prefix) -{ -#ifdef LATER - int which_hash; - device_driver_t new_driver; - unsigned long s; - - which_hash = driver_prefix_hash(prefix); - - new_driver = kern_calloc(1, sizeof(*new_driver)); - ASSERT(new_driver != NULL); - new_driver->dd_prev = NULL; - new_driver->dd_prefix = string_table_insert(&driver_prefix_string_table, prefix); - new_driver->dd_bdevsw = NULL; - new_driver->dd_cdevsw = NULL; - - dev_admin_registry_init(&new_driver->dd_dev_admin_registry); - device_driver_admin_info_update(new_driver); - - s = mutex_spinlock(&device_driver_lock[which_hash]); - -#if DEBUG - { - device_driver_t drvscan; - - /* Make sure we haven't already added a driver with this prefix */ - drvscan = device_driver_hash[which_hash]; - while (drvscan && - strcmp(drvscan->dd_prefix, prefix)) { - drvscan = drvscan->dd_next; - } - - ASSERT(!drvscan); - } -#endif /* DEBUG */ - - - /* Add new_driver to front of hash chain. */ - new_driver->dd_next = device_driver_hash[which_hash]; - if (new_driver->dd_next) - new_driver->dd_next->dd_prev = new_driver; - device_driver_hash[which_hash] = new_driver; - - mutex_spinunlock(&device_driver_lock[which_hash], s); - - return(new_driver); -#else - FIXME("device_driver_alloc"); - return((device_driver_t)0); -#endif -} - -/* -** Free a driver handle. -** -** Statically loaded drivers should never device_driver_free. -** Dynamically loaded drivers device_driver_free when either an -** unloaded driver is unregistered, or when an unregistered driver -** is unloaded. -*/ -void -device_driver_free(device_driver_t driver) -{ -#ifdef LATER - int which_hash; - unsigned long s; - - if (!driver) - return; - - which_hash = driver_prefix_hash(driver->dd_prefix); - - s = mutex_spinlock(&device_driver_lock[which_hash]); - -#if DEBUG - { - device_driver_t drvscan; - - /* Make sure we're dealing with the right list */ - drvscan = device_driver_hash[which_hash]; - while (drvscan && (drvscan != driver)) - drvscan = drvscan->dd_next; - - ASSERT(drvscan); - } -#endif /* DEBUG */ - - if (driver->dd_next) - driver->dd_next->dd_prev = driver->dd_prev; - - if (driver->dd_prev) - driver->dd_prev->dd_next = driver->dd_next; - else - device_driver_hash[which_hash] = driver->dd_next; - - mutex_spinunlock(&device_driver_lock[which_hash], s); - - driver->dd_next = NULL; /* sanity */ - driver->dd_prev = NULL; /* sanity */ - driver->dd_prefix = NULL; /* sanity */ - - if (driver->dd_bdevsw) { - driver->dd_bdevsw->d_driver = NULL; - driver->dd_bdevsw = NULL; - } - - if (driver->dd_cdevsw) { - if (driver->dd_cdevsw->d_str) { - str_free_mux_node(driver); - } - driver->dd_cdevsw->d_driver = NULL; - driver->dd_cdevsw = NULL; - } - - kern_free(driver); -#endif - FIXME("device_driver_free"); -} - - -/* -** Given a device driver prefix, return a handle to the caller. -*/ -device_driver_t -device_driver_get(char *prefix) -{ -#ifdef LATER - int which_hash; - device_driver_t drvscan; - unsigned long s; - - if (prefix == NULL) - return(NULL); - - which_hash = driver_prefix_hash(prefix); - - s = mutex_spinlock(&device_driver_lock[which_hash]); - - drvscan = device_driver_hash[which_hash]; - while (drvscan && strcmp(drvscan->dd_prefix, prefix)) - drvscan = drvscan->dd_next; - - mutex_spinunlock(&device_driver_lock[which_hash], s); - - return(drvscan); -#else - FIXME("device_driver_get"); - return((device_driver_t)0); -#endif -} - - -/* -** Given a block or char special file devfs_handle_t, find the -** device driver that controls it. -*/ -device_driver_t -device_driver_getbydev(devfs_handle_t device) -{ -#ifdef LATER - struct bdevsw *my_bdevsw; - struct cdevsw *my_cdevsw; - - my_cdevsw = get_cdevsw(device); - if (my_cdevsw != NULL) - return(my_cdevsw->d_driver); - - my_bdevsw = get_bdevsw(device); - if (my_bdevsw != NULL) - return(my_bdevsw->d_driver); - -#endif - FIXME("device_driver_getbydev"); - return((device_driver_t)0); -} - - -/* -** Associate a driver with bdevsw/cdevsw pointers. -** -** Statically loaded drivers are permanently and automatically associated -** with the proper bdevsw/cdevsw. Dynamically loaded drivers associate -** themselves when the driver is registered, and disassociate when the -** driver unregisters. -** -** Returns 0 on success, -1 on failure (devsw already associated with driver) -*/ -int -device_driver_devsw_put(device_driver_t driver, - struct bdevsw *my_bdevsw, - struct cdevsw *my_cdevsw) -{ -#ifdef LATER - int i; - - if (!driver) - return(-1); - - /* Trying to re-register data? */ - if (((my_bdevsw != NULL) && (driver->dd_bdevsw != NULL)) || - ((my_cdevsw != NULL) && (driver->dd_cdevsw != NULL))) - return(-1); - - if (my_bdevsw != NULL) { - driver->dd_bdevsw = my_bdevsw; - my_bdevsw->d_driver = driver; - for (i = 0; i < bdevmax; i++) { - if (driver->dd_bdevsw->d_flags == bdevsw[i].d_flags) { - bdevsw[i].d_driver = driver; - break; - } - } - } - - if (my_cdevsw != NULL) { - driver->dd_cdevsw = my_cdevsw; - my_cdevsw->d_driver = driver; - for (i = 0; i < cdevmax; i++) { - if (driver->dd_cdevsw->d_flags == cdevsw[i].d_flags) { - cdevsw[i].d_driver = driver; - break; - } - } - } -#endif - FIXME("device_driver_devsw_put"); - return(0); -} - - -/* -** Given a driver, return the corresponding bdevsw and cdevsw pointers. -*/ -void -device_driver_devsw_get( device_driver_t driver, - struct bdevsw **bdevswp, - struct cdevsw **cdevswp) -{ - if (!driver) { - *bdevswp = NULL; - *cdevswp = NULL; - } else { - *bdevswp = driver->dd_bdevsw; - *cdevswp = driver->dd_cdevsw; - } -} - -/* - * device_driver_thread_pri_set - * Given a driver try to set its thread priority. - * Returns 0 on success , -1 on failure. - */ -int -device_driver_thread_pri_set(device_driver_t driver,ilvl_t pri) -{ - if (!driver) - return(-1); - driver->dd_thread_pri = pri; - return(0); -} -/* - * device_driver_thread_pri_get - * Given a driver return the driver thread priority. - * If the driver is NULL return invalid driver thread - * priority. - */ -ilvl_t -device_driver_thread_pri_get(device_driver_t driver) -{ - if (driver) - return(driver->dd_thread_pri); - else - return(DRIVER_THREAD_PRI_INVALID); -} -/* -** Given a device driver, return it's handle (prefix). -*/ -void -device_driver_name_get(device_driver_t driver, char *buffer, int length) -{ - if (driver == NULL) - return; - - strncpy(buffer, driver->dd_prefix, length); -} - - -/* -** Associate a pointer-sized piece of information with a device. -*/ -void -device_info_set(devfs_handle_t device, void *info) -{ -#ifdef LATER - hwgraph_fastinfo_set(device, (arbitrary_info_t)info); -#endif - FIXME("device_info_set"); -} - - -/* -** Retrieve a pointer-sized piece of information associated with a device. -*/ -void * -device_info_get(devfs_handle_t device) -{ -#ifdef LATER - return((void *)hwgraph_fastinfo_get(device)); -#else - FIXME("device_info_get"); - return(NULL); -#endif -} - -/* - * Find the thread priority for a device, from the various - * sysgen files. - */ -int -device_driver_sysgen_thread_pri_get(char *dev_prefix) -{ -#ifdef LATER - int pri; - char *pri_s; - char *class; - - extern default_intr_pri; - extern disk_intr_pri; - extern serial_intr_pri; - extern parallel_intr_pri; - extern tape_intr_pri; - extern graphics_intr_pri; - extern network_intr_pri; - extern scsi_intr_pri; - extern audio_intr_pri; - extern video_intr_pri; - extern external_intr_pri; - extern tserialio_intr_pri; - - /* Check if there is a thread priority specified for - * this driver's thread thru admin hints. If so - * use that value. Otherwise set it to its default - * class value, otherwise set it to the default - * value. - */ - - if (pri_s = device_driver_admin_info_get(dev_prefix, - ADMIN_LBL_THREAD_PRI)) { - pri = atoi(pri_s); - } else if (class = device_driver_admin_info_get(dev_prefix, - ADMIN_LBL_THREAD_CLASS)) { - if (strcmp(class, "disk") == 0) - pri = disk_intr_pri; - else if (strcmp(class, "serial") == 0) - pri = serial_intr_pri; - else if (strcmp(class, "parallel") == 0) - pri = parallel_intr_pri; - else if (strcmp(class, "tape") == 0) - pri = tape_intr_pri; - else if (strcmp(class, "graphics") == 0) - pri = graphics_intr_pri; - else if (strcmp(class, "network") == 0) - pri = network_intr_pri; - else if (strcmp(class, "scsi") == 0) - pri = scsi_intr_pri; - else if (strcmp(class, "audio") == 0) - pri = audio_intr_pri; - else if (strcmp(class, "video") == 0) - pri = video_intr_pri; - else if (strcmp(class, "external") == 0) - pri = external_intr_pri; - else if (strcmp(class, "tserialio") == 0) - pri = tserialio_intr_pri; - else - pri = default_intr_pri; - } else - pri = default_intr_pri; - - if (pri > 255) - pri = 255; - else if (pri < 0) - pri = 0; - return pri; -#else - FIXME("device_driver_sysgen_thread_pri_get"); - return(-1); -#endif -} diff -urN linux-2.4.18/arch/ia64/sn/io/eeprom.c linux-2.4.19-pre5/arch/ia64/sn/io/eeprom.c --- linux-2.4.18/arch/ia64/sn/io/eeprom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/eeprom.c Sat Mar 30 22:55:25 2002 @@ -1,14 +1,11 @@ /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) + * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved. */ - /* * WARNING: There is more than one copy of this file in different isms. * All copies must be kept exactly in sync. @@ -28,37 +25,24 @@ * */ -/************************************************************************** - * * - * Copyright (C) 1999 Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - ************************************************************************** - */ - - #include #include #include #include +#include #include #include #include #include #include #include -#include -/* #include */ #include #include #include #include #include +#include +#include #if defined(EEPROM_DEBUG) #define db_printf(x) printk x @@ -384,9 +368,6 @@ int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else char uid_str[32]; char msg[BRL1_QSIZE]; int subch, len; @@ -421,7 +402,7 @@ } else { scp = ≻ - sc_init( &sc, nasid, BRL1_LOCALUART ); + sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); } /* fill in msg with the opcode & params */ @@ -455,15 +436,11 @@ *uid = generate_unique_id( uid_str, strlen( uid_str ) ); return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else char uid_str[32]; char msg[BRL1_QSIZE]; int subch, len; @@ -472,14 +449,12 @@ if ( IS_RUNNING_ON_SIMULATOR() ) return EEP_L1; -#ifdef BRINGUP #define FAIL \ { \ *uid = rtc_time(); \ printk( "rbrick_uid_get failed; using current time as uid\n" ); \ return EEP_OK; \ } -#endif /* BRINGUP */ ROUTER_LOCK(path); sc_init( &sc, nasid, path ); @@ -520,7 +495,6 @@ *uid = generate_unique_id( uid_str, strlen( uid_str ) ); return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) @@ -593,12 +567,10 @@ extern char *nic_vertex_info_get( devfs_handle_t ); extern void nic_vmc_check( devfs_handle_t, char * ); -#ifdef BRINGUP /* the following were lifted from nic.c - change later? */ #define MAX_INFO 2048 #define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) #define DEL(ptr) (kern_free((ptr))) -#endif /* BRINGUP */ char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, net_vec_t path ) @@ -884,9 +856,6 @@ int read_ia( l1sc_t *sc, int subch, int l1_compt, int ia_code, char *eep_record ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else char msg[BRL1_QSIZE]; /* message buffer */ int len; /* number of bytes used in message buffer */ int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ @@ -936,16 +905,12 @@ } return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int read_spd( l1sc_t *sc, int subch, int l1_compt, eeprom_spd_u *spd ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else char msg[BRL1_QSIZE]; /* message buffer */ int len; /* number of bytes used in message buffer */ int resp; /* l1 response code */ @@ -1010,7 +975,6 @@ offset += EEPROM_CHUNKSIZE; } return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } @@ -1068,7 +1032,7 @@ if( (checksum & 0xff) != 0 ) { db_printf(( "read_chassis_ia: bad checksum\n" )); - db_printf(( "read_chassis_ia: target 0x%x uart 0x%x\n", + db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", sc->subch[subch].target, sc->uart )); return EEP_BAD_CHECKSUM; } @@ -1199,7 +1163,7 @@ if( (checksum & 0xff) != 0 ) { db_printf(( "read_board_ia: bad checksum\n" )); - db_printf(( "read_board_ia: target 0x%x uart 0x%x\n", + db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", sc->subch[subch].target, sc->uart )); return EEP_BAD_CHECKSUM; } @@ -1211,9 +1175,6 @@ int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, int component ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else int r; uint64_t uid = 0; #ifdef LOG_GETENV @@ -1290,16 +1251,12 @@ return fake_an_eeprom_record( buf, component, uid ); } return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, int component ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else l1sc_t *scp; int local = (nasid == get_nasid()); @@ -1318,16 +1275,12 @@ } return _cbrick_eeprom_read( buf, scp, component ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, int component ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else int r; int l1_compt, subch; l1sc_t *scp; @@ -1391,16 +1344,12 @@ return r; } return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, net_vec_t path, int component ) { -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else int r; uint64_t uid = 0; int l1_compt, subch; @@ -1470,5 +1419,4 @@ /* unsupported brick type */ return EEP_PARAM; } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } diff -urN linux-2.4.18/arch/ia64/sn/io/efi-rtc.c linux-2.4.19-pre5/arch/ia64/sn/io/efi-rtc.c --- linux-2.4.18/arch/ia64/sn/io/efi-rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/efi-rtc.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,185 @@ +/* + * 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) 2001 Silicon Graphics, Inc. + * Copyright (C) 2001 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No locking necessary when this is called from efirtc which protects us + * from racing by efi_rtc_lock. + */ +#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) +#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) +#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) + +#define TOD_SGS_M48T35 1 +#define TOD_DALLAS_DS1386 2 + +static unsigned long nvram_base = 0; +static int tod_chip_type; + +static int +get_tod_chip_type(void) +{ + unsigned char testval; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_DAY_ADDR, 0xff); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + + testval = read_io_port(RTC_DAL_DAY_ADDR); + if (testval == 0xff) + return TOD_SGS_M48T35; + + return TOD_DALLAS_DS1386; +} + +efi_status_t +ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + memset(time, 0, sizeof(*time)); + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); + + time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; + time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); + time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); + time->nanosecond = 0; + + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + + time->nanosecond = 0; + time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); + time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); + time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + if (caps) { + caps->resolution = 50000000; /* 50PPM */ + caps->accuracy = 1000; /* 1ms */ + caps->sets_to_zero = 0; + } + + return EFI_SUCCESS; +} + +static efi_status_t ioc3_set_time (efi_time_t *t) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); + write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/* The following two are not supported atm. */ +static efi_status_t +ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t +ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +/* + * It looks like the master IOC3 is usually on bus 0, device 4. Hope + * that's right + */ +static __init int efi_ioc3_time_init(void) +{ + struct pci_dev *dev; + static struct ioc3 *ioc3; + + dev = pci_find_slot(0, PCI_DEVFN(4, 0)); + if (!dev) { + printk(KERN_CRIT "Couldn't find master IOC3\n"); + + return -ENODEV; + } + + ioc3 = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + nvram_base = (unsigned long) ioc3 + IOC3_BYTEBUS_DEV0; + + tod_chip_type = get_tod_chip_type(); + if (tod_chip_type == 1) + printk(KERN_NOTICE "TOD type is SGS M48T35\n"); + else if (tod_chip_type == 2) + printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); + else + printk(KERN_CRIT "No or unknown TOD\n"); + + efi.get_time = ioc3_get_time; + efi.set_time = ioc3_set_time; + efi.get_wakeup_time = ioc3_get_wakeup_time; + efi.set_wakeup_time = ioc3_set_wakeup_time; + + return 0; +} + +module_init(efi_ioc3_time_init); diff -urN linux-2.4.18/arch/ia64/sn/io/hcl.c linux-2.4.19-pre5/arch/ia64/sn/io/hcl.c --- linux-2.4.18/arch/ia64/sn/io/hcl.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/hcl.c Sat Mar 30 22:55:25 2002 @@ -6,8 +6,7 @@ * * hcl - SGI's Hardware Graph compatibility layer. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include @@ -49,7 +48,6 @@ /* * Some Global definitions. */ -spinlock_t hcl_spinlock; devfs_handle_t hcl_handle = NULL; invplace_t invplace_none = { @@ -142,6 +140,7 @@ { extern void string_table_init(struct string_table *); extern struct string_table label_string_table; + extern int init_ifconfig_net(void); int rv = 0; #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) @@ -153,8 +152,6 @@ printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options); #endif - spin_lock_init(&hcl_spinlock); - /* * Create the hwgraph_root on devfs. */ @@ -192,6 +189,12 @@ return(0); } + /* + * Initialize the ifconfgi_net driver that does network devices + * Persistent Naming. + */ + init_ifconfig_net(); + return(0); } @@ -238,8 +241,7 @@ { if (hcl_debug) { - printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", - de, fastinfo); + printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", (void *)de, fastinfo); } labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL); @@ -466,7 +468,7 @@ * We need to clean up! */ printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%p\n", - new_devfs_handle); + (void *)new_devfs_handle); } /* @@ -1044,30 +1046,6 @@ } /* - * hwgraph_cdevsw_get - returns the fops of the given devfs entry. - */ -struct file_operations * -hwgraph_cdevsw_get(devfs_handle_t de) -{ - struct file_operations *fops = devfs_get_ops(de); - - devfs_put_ops(de); /* FIXME: this may need to be moved to callers */ - return(fops); -} - -/* - * hwgraph_bdevsw_get - returns the fops of the given devfs entry. -*/ -struct file_operations * /* FIXME: shouldn't this be a blkdev? */ -hwgraph_bdevsw_get(devfs_handle_t de) -{ - struct file_operations *fops = devfs_get_ops(de); - - devfs_put_ops(de); /* FIXME: this may need to be moved to callers */ - return(fops); -} - -/* ** Inventory is now associated with a vertex in the graph. For items that ** belong in the inventory but have no vertex ** (e.g. old non-graph-aware drivers), we create a bogus vertex under the @@ -1550,6 +1528,4 @@ EXPORT_SYMBOL(hwgraph_path_to_dev); EXPORT_SYMBOL(hwgraph_block_device_get); EXPORT_SYMBOL(hwgraph_char_device_get); -EXPORT_SYMBOL(hwgraph_cdevsw_get); -EXPORT_SYMBOL(hwgraph_bdevsw_get); EXPORT_SYMBOL(hwgraph_vertex_name_get); diff -urN linux-2.4.18/arch/ia64/sn/io/hcl_util.c linux-2.4.19-pre5/arch/ia64/sn/io/hcl_util.c --- linux-2.4.18/arch/ia64/sn/io/hcl_util.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/hcl_util.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include @@ -14,6 +13,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.4.18/arch/ia64/sn/io/hubdev.c linux-2.4.19-pre5/arch/ia64/sn/io/hubdev.c --- linux-2.4.18/arch/ia64/sn/io/hubdev.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/hubdev.c Sat Mar 30 22:55:25 2002 @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ +#include #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ ASSERT(attach_method); - callout = (hubdev_callout_t *)kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); + callout = (hubdev_callout_t *)snia_kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); ASSERT(callout); mutex_lock(&hubdev_callout_mutex); @@ -104,6 +105,9 @@ * Given a hub vertex, return the base address of the Hspec space * for that hub. */ + +#if defined(CONFIG_IA64_SGI_SN1) + caddr_t hubdev_prombase_get(devfs_handle_t hub) { @@ -124,3 +128,5 @@ return hinfo->h_cnodeid; } + +#endif /* CONFIG_IA64_SGI_SN1 */ diff -urN linux-2.4.18/arch/ia64/sn/io/huberror.c linux-2.4.19-pre5/arch/ia64/sn/io/huberror.c --- linux-2.4.18/arch/ia64/sn/io/huberror.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/huberror.c Thu Jan 1 01:00:00 1970 @@ -1,475 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Alan Mayer - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_eint_init(cnodeid_t cnode); -extern void hubii_eint_init(cnodeid_t cnode); -extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - -extern int maxcpus; - -#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ - - -void -hub_error_clear(nasid_t nasid) -{ - int i; - hubreg_t idsr; - int sn; - - for(sn=0; snel_spool_cur_addr[0] = - SN0_ERROR_LOG(cnode)->el_spool_last_addr[0] = - REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); - } - - if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { - SN0_ERROR_LOG(cnode)->el_spool_cur_addr[1] = - SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = - REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); - } - } - - - PI_SPOOL_SIZE_BYTES = - ERR_STACK_SIZE_BYTES(REMOTE_HUB_L(nasid, PI_ERR_STACK_SIZE)); - -#ifdef BRINGUP -/* BRINGUP: The following code looks like a check to make sure -the prom set up the error spool correctly for 2 processors. I -don't think it is needed. */ - for(sn=0; snel_spool_cur_addr[1] = - SN0_ERROR_LOG(cnode)->el_spool_last_addr[1] = - REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); - - } - } - } -#endif /* BRINGUP */ - - /* programming our own hub. Enable error_int_pend intr. - * If both present, CPU A takes CPU b's error interrupts and any - * generic ones. CPU B takes CPU A error ints. - */ - if (cause_intr_connect (SRB_ERR_IDX, - (intr_func_t)(hubpi_eint_handler), - SR_ALL_MASK|SR_IE)) { - cmn_err(ERR_WARN, - "hub_error_init: cause_intr_connect failed on %d", cnode); - } - } - else { - /* programming remote hub. The only valid reason that this - * is called will be on headless hubs. No interrupts - */ - for(sn=0; snhuberror_ticks = HUB_ERROR_PERIOD; - return; -} - -/* - * Function : hubii_eint_init - * Parameters : cnode - * Purpose : to initialize the hub iio error interrupt. - * Assumptions : Called once per hub, by the cpu which will ultimately - * handle this interrupt. - * Returns : None. - */ - - -void -hubii_eint_init(cnodeid_t cnode) -{ - int bit, rv; - ii_iidsr_u_t hubio_eint; - hubinfo_t hinfo; - cpuid_t intr_cpu; - devfs_handle_t hub_v; - ii_ilcsr_u_t ilcsr; - - hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); - ASSERT_ALWAYS(hub_v); - hubinfo_get(hub_v, &hinfo); - - ASSERT(hinfo); - ASSERT(hinfo->h_cnodeid == cnode); - - ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); - - if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { - /* - * HUB II link is not up. - * Just disable LLP, and don't connect any interrupts. - */ - ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); - return; - } - /* Select a possible interrupt target where there is a free interrupt - * bit and also reserve the interrupt bit for this IO error interrupt - */ - intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, - "HUB IO error interrupt",&bit); - if (intr_cpu == CPU_NONE) { - printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); - return; - } - - rv = intr_connect_level(intr_cpu, bit, 0,(intr_func_t)(NULL), - (void *)(long)hub_v, NULL); - synergy_intr_connect(bit, intr_cpu); - request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, NULL, (void *)hub_v); - ASSERT_ALWAYS(rv >= 0); - hubio_eint.ii_iidsr_regval = 0; - hubio_eint.ii_iidsr_fld_s.i_enable = 1; - hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ - hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); - hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); - -} - -void -hubni_eint_init(cnodeid_t cnode) -{ - int intr_bit; - cpuid_t targ; - - - if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) - return; - - /* The prom chooses which cpu gets these interrupts, but we - * don't know which one it chose. We will register all of the - * cpus to be sure. This only costs us an irqaction per cpu. - */ - for (; targ < CPUS_PER_NODE; targ++) { - if (!cpu_enabled(targ) ) continue; - /* connect the INTEND1 bits. */ - for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { - intr_connect_level(targ, intr_bit, II_ERRORINT, NULL, NULL, NULL); - } - request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, NULL, NULL); - /* synergy masks are initialized in the prom to enable all interrupts. */ - /* We'll just leave them that way, here, for these interrupts. */ - } -} - - -/*ARGSUSED*/ -void -hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) -{ - devfs_handle_t hub_v; - hubinfo_t hinfo; - ii_wstat_u_t wstat; - hubreg_t idsr; - - panic("Hubii interrupt\n"); -#ifdef ajm - /* - * If the NI has a problem, everyone has a problem. We shouldn't - * even attempt to handle other errors when an NI error is present. - */ - if (check_ni_errors()) { - hubni_error_handler("II interrupt", 1); - /* NOTREACHED */ - } - - /* two levels of casting avoids compiler warning.!! */ - hub_v = (devfs_handle_t)(long)(arg); - ASSERT(hub_v); - - hubinfo_get(hub_v, &hinfo); - - /* - * Identify the reason for error. - */ - wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); - - if (wstat.ii_wstat_fld_s.w_crazy) { - char *reason; - /* - * We can do a couple of things here. - * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check - * which of these caused the CRAZY bit to be set. - * You may be able to check if the Link is up really. - */ - if (wstat.ii_wstat_fld_s.w_tx_mx_rty) - reason = "Micro Packet Retry Timeout"; - else if (wstat.ii_wstat_fld_s.w_xt_tail_to) - reason = "Crosstalk Tail Timeout"; - else if (wstat.ii_wstat_fld_s.w_xt_crd_to) - reason = "Crosstalk Credit Timeout"; - else { - hubreg_t hubii_imem; - /* - * Check if widget 0 has been marked as shutdown, or - * if BTE 0/1 has been marked. - */ - hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); - if (hubii_imem & IIO_IMEM_W0ESD) - reason = "Hub Widget 0 has been Shutdown"; - else if (hubii_imem & IIO_IMEM_B0ESD) - reason = "BTE 0 has been shutdown"; - else if (hubii_imem & IIO_IMEM_B1ESD) - reason = "BTE 1 has been shutdown"; - else reason = "Unknown"; - - } - /* - * Note: we may never be able to print this, if the II talking - * to Xbow which hosts the console is dead. - */ - printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", - hinfo->h_cnodeid, reason); - } - - /* - * It's a toss as to which one among PRB/CRB to check first. - * Current decision is based on the severity of the errors. - * IO CRB errors tend to be more severe than PRB errors. - * - * It is possible for BTE errors to have been handled already, so we - * may not see any errors handled here. - */ - (void)hubiio_crb_error_handler(hub_v, hinfo); - (void)hubiio_prb_error_handler(hub_v, hinfo); - /* - * If we reach here, it indicates crb/prb handlers successfully - * handled the error. So, re-enable II to send more interrupt - * and return. - */ - REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); - idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); -#endif /* ajm */ -} diff -urN linux-2.4.18/arch/ia64/sn/io/hubspc.c linux-2.4.19-pre5/arch/ia64/sn/io/hubspc.c --- linux-2.4.18/arch/ia64/sn/io/hubspc.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/hubspc.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ /* @@ -19,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,18 +27,12 @@ #include #include #include -#include -#include +#include #include - - -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include -#include +#include +#include #include -#endif - -#include +#include /* Uncomment the following line for tracing */ @@ -45,10 +40,6 @@ int hubspc_devflag = D_MP; -extern void *device_info_get(devfs_handle_t device); -extern void device_info_set(devfs_handle_t device, void *info); - - /***********************************************************************/ /* CPU Prom Space */ @@ -127,9 +118,8 @@ return 0; } -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) +#if defined(CONFIG_IA64_SGI_SN1) #define SN_PROMVERSION INV_IP35PROM -#endif /* Add "detailed" labelled inventory information to the * prom vertex @@ -159,7 +149,6 @@ cpuprom_inventory_info->im_rev = IP27CONFIG.pvers_rev; cpuprom_inventory_info->im_version = IP27CONFIG.pvers_vers; - /* Store this info as labelled information hanging off the * prom device vertex */ @@ -172,41 +161,17 @@ sizeof(invent_miscinfo_t)); } -int -cpuprom_attach(devfs_handle_t node) -{ - devfs_handle_t prom_dev; - - hwgraph_char_device_add(node, EDGE_LBL_PROM, "hubspc_", &prom_dev); -#ifdef HUBSPC_DEBUG - printf("hubspc: prom_attach hub: 0x%x prom: 0x%x\n", node, prom_dev); -#endif /* HUBSPC_DEBUG */ - device_inventory_add(prom_dev, INV_PROM, SN_PROMVERSION, - (major_t)0, (minor_t)0, 0); - - /* Add additional inventory info about the cpu prom like - * revision & version numbers etc. - */ - cpuprom_detailed_inventory_info_add(prom_dev,node); - device_info_set(prom_dev, (void*)(ulong)HUBSPC_PROM); - prominfo_add(node, prom_dev); - - return (0); -} - -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #define FPROM_CONFIG_ADDR MD_JUNK_BUS_TIMING #define FPROM_ENABLE_MASK MJT_FPROM_ENABLE_MASK #define FPROM_ENABLE_SHFT MJT_FPROM_ENABLE_SHFT #define FPROM_SETUP_MASK MJT_FPROM_SETUP_MASK #define FPROM_SETUP_SHFT MJT_FPROM_SETUP_SHFT -#endif /*ARGSUSED*/ int cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len) { - int errcode; + int errcode = 0; caddr_t kvaddr; devfs_handle_t node; cnodeid_t cnode; @@ -220,7 +185,7 @@ kvaddr = hubdev_prombase_get(node); cnode = hubdev_cnodeid_get(node); #ifdef HUBSPC_DEBUG - printf("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr); + printk("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr); #endif if (len > RBOOT_SIZE) @@ -251,6 +216,7 @@ } return (errcode); } +#endif /* CONFIG_IA64_SGI_SN1 */ /*ARGSUSED*/ int @@ -263,8 +229,6 @@ /* Base Hub Space Driver */ /***********************************************************************/ -// extern int l1_attach( devfs_handle_t ); - /* * hubspc_init * Registration of the hubspc devices with the hub manager @@ -277,24 +241,19 @@ */ /* The reference counters */ +#if defined(CONFIG_IA64_SGI_SN1) hubdev_register(mem_refcnt_attach); +#endif - /* Prom space */ - hubdev_register(cpuprom_attach); - -#if defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) /* L1 system controller link */ if ( !IS_RUNNING_ON_SIMULATOR() ) { /* initialize the L1 link */ - void l1_cons_init( l1sc_t *sc ); - elsc_t *get_elsc(void); - - l1_cons_init((l1sc_t *)get_elsc()); + extern void l1_init(void); + l1_init(); } -#endif #ifdef HUBSPC_DEBUG - printf("hubspc_init: Completed\n"); + printk("hubspc_init: Completed\n"); #endif /* HUBSPC_DEBUG */ /* Initialize spinlocks */ mutex_spinlock_init(&cpuprom_spinlock); @@ -304,26 +263,7 @@ int hubspc_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) { - int errcode = 0; - - switch ((hubspc_subdevice_t)(ulong)device_info_get(*devp)) { - case HUBSPC_REFCOUNTERS: - errcode = mem_refcnt_open(devp, oflag, otyp, crp); - break; - - case HUBSPC_PROM: - break; - - default: - errcode = ENODEV; - } - -#ifdef HUBSPC_DEBUG - printf("hubspc_open: Completed open for type %d\n", - (hubspc_subdevice_t)(ulong)device_info_get(*devp)); -#endif /* HUBSPC_DEBUG */ - - return (errcode); + return (0); } @@ -331,25 +271,7 @@ int hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) { - int errcode = 0; - - switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) { - case HUBSPC_REFCOUNTERS: - errcode = mem_refcnt_close(dev, oflag, otyp, crp); - break; - - case HUBSPC_PROM: - break; - default: - errcode = ENODEV; - } - -#ifdef HUBSPC_DEBUG - printf("hubspc_close: Completed close for type %d\n", - (hubspc_subdevice_t)(ulong)device_info_get(dev)); -#endif /* HUBSPC_DEBUG */ - - return (errcode); + return (0); } /* ARGSUSED */ @@ -357,7 +279,6 @@ hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) { /*REFERENCED*/ - hubspc_subdevice_t subdevice; int errcode = 0; /* check validity of request */ @@ -365,30 +286,6 @@ return ENXIO; } - subdevice = (hubspc_subdevice_t)(ulong)device_info_get(dev); - -#ifdef HUBSPC_DEBUG - printf("hubspc_map: subdevice: %d vaddr: 0x%x phyaddr: 0x%x len: 0x%x\n", - subdevice, v_getaddr(vt), off, len); -#endif /* HUBSPC_DEBUG */ - - switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) { - case HUBSPC_REFCOUNTERS: - errcode = mem_refcnt_mmap(dev, vt, off, len, prot); - break; - - case HUBSPC_PROM: - errcode = cpuprom_map(dev, vt, off, len); - break; - default: - errcode = ENODEV; - } - -#ifdef HUBSPC_DEBUG - printf("hubspc_map finished: spctype: %d vaddr: 0x%x len: 0x%x\n", - (hubspc_subdevice_t)(ulong)device_info_get(dev), v_getaddr(vt), len); -#endif /* HUBSPC_DEBUG */ - return errcode; } @@ -396,21 +293,7 @@ int hubspc_unmap(devfs_handle_t dev, vhandl_t *vt) { - int errcode = 0; - - switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) { - case HUBSPC_REFCOUNTERS: - errcode = mem_refcnt_unmap(dev, vt); - break; - - case HUBSPC_PROM: - errcode = cpuprom_unmap(dev, vt); - break; - - default: - errcode = ENODEV; - } - return errcode; + return (0); } @@ -423,19 +306,6 @@ cred_t *cred_p, int *rvalp) { - int errcode = 0; - - switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) { - case HUBSPC_REFCOUNTERS: - errcode = mem_refcnt_ioctl(dev, cmd, arg, mode, cred_p, rvalp); - break; - - case HUBSPC_PROM: - break; - - default: - errcode = ENODEV; - } - return errcode; + return (0); } diff -urN linux-2.4.18/arch/ia64/sn/io/ifconfig_net.c linux-2.4.19-pre5/arch/ia64/sn/io/ifconfig_net.c --- linux-2.4.18/arch/ia64/sn/io/ifconfig_net.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ifconfig_net.c Sat Mar 30 22:55:25 2002 @@ -0,0 +1,298 @@ +/* $Id: ifconfig_net.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ifconfig_net - SGI's Persistent Network Device names. + * + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGI_IFCONFIG_NET "SGI-PERSISTENT NETWORK DEVICE NAME DRIVER" +#define SGI_IFCONFIG_NET_VERSION "1.0" + +/* + * Some Global definitions. + */ +devfs_handle_t ifconfig_net_handle = NULL; +unsigned long ifconfig_net_debug = 0; + +/* + * ifconfig_net_open - Opens the special device node "/devhw/.ifconfig_net". + */ +static int ifconfig_net_open(struct inode * inode, struct file * filp) +{ + if (ifconfig_net_debug) { + printk("ifconfig_net_open called.\n"); + } + + return(0); + +} + +/* + * ifconfig_net_close - Closes the special device node "/devhw/.ifconfig_net". + */ +static int ifconfig_net_close(struct inode * inode, struct file * filp) +{ + + if (ifconfig_net_debug) { + printk("ifconfig_net_close called.\n"); + } + + return(0); +} + +/* + * assign_ifname - Assign the next available interface name from the persistent list. + */ +void +assign_ifname(struct net_device *dev, + struct ifname_num *ifname_num) + +{ + + /* + * Handle eth devices. + */ + if ( (memcmp(dev->name, "eth", 3) == 0) ) { + if (ifname_num->next_eth != -1) { + /* + * Assign it the next available eth interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "eth%d", (int)ifname_num->next_eth); + ifname_num->next_eth++; + } + + return; + } + + /* + * Handle fddi devices. + */ + if ( (memcmp(dev->name, "fddi", 4) == 0) ) { + if (ifname_num->next_fddi != -1) { + /* + * Assign it the next available fddi interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "fddi%d", (int)ifname_num->next_fddi); + ifname_num->next_fddi++; + } + + return; + } + + /* + * Handle hip devices. + */ + if ( (memcmp(dev->name, "hip", 3) == 0) ) { + if (ifname_num->next_hip != -1) { + /* + * Assign it the next available hip interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "hip%d", (int)ifname_num->next_hip); + ifname_num->next_hip++; + } + + return; + } + + /* + * Handle tr devices. + */ + if ( (memcmp(dev->name, "tr", 2) == 0) ) { + if (ifname_num->next_tr != -1) { + /* + * Assign it the next available tr interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "tr%d", (int)ifname_num->next_tr); + ifname_num->next_tr++; + } + + return; + } + + /* + * Handle fc devices. + */ + if ( (memcmp(dev->name, "fc", 2) == 0) ) { + if (ifname_num->next_fc != -1) { + /* + * Assign it the next available fc interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "fc%d", (int)ifname_num->next_fc); + ifname_num->next_fc++; + } + + return; + } +} + +/* + * find_persistent_ifname: Returns the entry that was seen in previous boot. + */ +struct ifname_MAC * +find_persistent_ifname(struct net_device *dev, + struct ifname_MAC *ifname_MAC) + +{ + + while (ifname_MAC->addr_len) { + if (memcmp(dev->dev_addr, ifname_MAC->dev_addr, dev->addr_len) == 0) + return(ifname_MAC); + + ifname_MAC++; + } + + return(NULL); +} + +/* + * ifconfig_net_ioctl: ifconfig_net driver ioctl interface. + */ +static int ifconfig_net_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + extern struct net_device *__dev_get_by_name(const char *); +#ifdef CONFIG_NET + struct net_device *dev; + struct ifname_MAC *found; + char temp[64]; +#endif + struct ifname_MAC *ifname_MAC; + struct ifname_MAC *new_devices, *temp_new_devices; + struct ifname_num *ifname_num; + unsigned long size; + + + if (ifconfig_net_debug) { + printk("HCL: hcl_ioctl called.\n"); + } + + /* + * Read in the header and see how big of a buffer we really need to + * allocate. + */ + ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), + GFP_KERNEL); + copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num)); + size = ifname_num->size; + kfree(ifname_num); + ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL); + ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) ); + + copy_from_user( ifname_num, (char *) arg, size); + new_devices = kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL); + temp_new_devices = new_devices; + + memset(new_devices, 0, size - sizeof(struct ifname_num)); + +#ifdef CONFIG_NET + /* + * Go through the net device entries and make them persistent! + */ + for (dev = dev_base; dev != NULL; dev = dev->next) { + /* + * Skip NULL entries or "lo" + */ + if ( (dev->addr_len == 0) || ( !strncmp(dev->name, "lo", strlen(dev->name))) ){ + continue; + } + + /* + * See if we have a persistent interface name for this device. + */ + found = NULL; + found = find_persistent_ifname(dev, ifname_MAC); + if (found) { + strcpy(dev->name, found->name); + } else { + /* Never seen this before .. */ + assign_ifname(dev, ifname_num); + + /* + * Save the information for the next boot. + */ + sprintf(temp,"%s %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + strcpy(temp_new_devices->name, dev->name); + temp_new_devices->addr_len = dev->addr_len; + memcpy(temp_new_devices->dev_addr, dev->dev_addr, dev->addr_len); + temp_new_devices++; + } + + } +#endif + + /* + * Copy back to the User Buffer area any new devices encountered. + */ + copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, + size - sizeof(struct ifname_num)); + + return(0); + +} + +struct file_operations ifconfig_net_fops = { + ioctl:ifconfig_net_ioctl, /* ioctl */ + open:ifconfig_net_open, /* open */ + release:ifconfig_net_close /* release */ +}; + + +/* + * init_ifconfig_net() - Boot time initialization. Ensure that it is called + * after devfs has been initialized. + * + */ +#ifdef MODULE +int init_module (void) +#else +int __init init_ifconfig_net(void) +#endif +{ + ifconfig_net_handle = NULL; + ifconfig_net_handle = hwgraph_register(hwgraph_root, ".ifconfig_net", + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &ifconfig_net_fops, NULL); + + if (ifconfig_net_handle == NULL) { + panic("Unable to create SGI PERSISTENT NETWORK DEVICE Name Driver.\n"); + } + + return(0); + +} diff -urN linux-2.4.18/arch/ia64/sn/io/invent.c linux-2.4.19-pre5/arch/ia64/sn/io/invent.c --- linux-2.4.18/arch/ia64/sn/io/invent.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/invent.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ /* diff -urN linux-2.4.18/arch/ia64/sn/io/io.c linux-2.4.19-pre5/arch/ia64/sn/io/io.c --- linux-2.4.18/arch/ia64/sn/io/io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/io.c Sat Mar 30 22:55:25 2002 @@ -1,36 +1,50 @@ -/* $Id$ +/* $Id: io.c,v 1.2 2001/06/26 14:02:43 pfg Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. */ #include -#include #include #include #include -#include +#include #include #include #include #include +#include #include #include #include #include #include -#include #include #include #include -#include #include extern xtalk_provider_t hub_provider; +extern void hub_intr_init(devfs_handle_t hubv); + + +/* + * hub_device_desc_update + * Update the passed in device descriptor with the actual the + * target cpu number and interrupt priority level. + * NOTE : These might be the same as the ones passed in thru + * the descriptor. + */ +void +hub_device_desc_update(device_desc_t dev_desc, + ilvl_t intr_swlevel, + cpuid_t cpu) +{ +} + /* * Perform any initializations needed to support hub-based I/O. @@ -63,7 +77,7 @@ /* * Setup pio structures needed for a particular hub. */ -static void +void hub_pio_init(devfs_handle_t hubv) { xwidgetnum_t widget; @@ -386,7 +400,7 @@ /* ARGSUSED */ -static void +void hub_dma_init(devfs_handle_t hubv) { } @@ -411,7 +425,7 @@ xwidgetnum_t widget = xwidget_info_id_get(widget_info); devfs_handle_t hubv = xwidget_info_master_get(widget_info); - dmamap = kern_malloc(sizeof(struct hub_dmamap_s)); + dmamap = kmalloc(sizeof(struct hub_dmamap_s), GFP_ATOMIC); dmamap->hdma_xtalk_info.xd_dev = dev; dmamap->hdma_xtalk_info.xd_target = widget; dmamap->hdma_hub = hubv; @@ -454,9 +468,9 @@ if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); + printk(KERN_WARNING "%v: hub_dmamap_addr re-uses dmamap.\n",vhdl); #else - PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl); + printk(KERN_WARNING "%p: hub_dmamap_addr re-uses dmamap.\n", (void *)vhdl); #endif } } else { @@ -487,9 +501,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl); + printk(KERN_WARNING "%v: hub_dmamap_list re-uses dmamap\n",vhdl); #else - PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl); + printk(KERN_WARNING "%p: hub_dmamap_list re-uses dmamap\n", (void *)vhdl); #endif } } else { @@ -516,9 +530,9 @@ if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl); + printk(KERN_WARNING "%v: hub_dmamap_done already done with dmamap\n",vhdl); #else - PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl); + printk(KERN_WARNING "%p: hub_dmamap_done already done with dmamap\n", (void *)vhdl); #endif } } @@ -581,329 +595,6 @@ -/* INTERRUPT MANAGEMENT */ - -/* ARGSUSED */ -static void -hub_intr_init(devfs_handle_t hubv) -{ -} - -/* - * hub_device_desc_update - * Update the passed in device descriptor with the actual the - * target cpu number and interrupt priority level. - * NOTE : These might be the same as the ones passed in thru - * the descriptor. - */ -static void -hub_device_desc_update(device_desc_t dev_desc, - ilvl_t intr_swlevel, - cpuid_t cpu) -{ - char cpuname[40]; - - /* Store the interrupt priority level in the device descriptor */ - device_desc_intr_swlevel_set(dev_desc, intr_swlevel); - - /* Convert the cpuid to the vertex handle in the hwgraph and - * save it in the device descriptor. - */ - sprintf(cpuname,"/hw/cpunum/%ld",cpu); - device_desc_intr_target_set(dev_desc, - hwgraph_path_to_dev(cpuname)); -} - -int allocate_my_bit = INTRCONNECT_ANYBIT; - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -static hub_intr_t -do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev, /* owner of this interrupt, if known */ - int uncond_nothread) /* unconditionally non-threaded */ -{ - cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ - int cpupicked = 0; - int bit; /* interrupt vector */ - /*REFERENCED*/ - int intr_resflags = 0; - hub_intr_t intr_hdl; - cnodeid_t nodeid; /* node to receive interrupt */ - /*REFERENCED*/ - nasid_t nasid; /* nasid to receive interrupt */ - struct xtalk_intr_s *xtalk_info; - iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */ - xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */ - char *intr_name = NULL; - ilvl_t intr_swlevel; - extern int default_intr_pri; -#ifdef CONFIG_IA64_SGI_SN1 - extern void synergy_intr_alloc(int, int); -#endif - - /* - * If caller didn't explicily specify a device descriptor, see if there's - * a default descriptor associated with the device. - */ - if (!dev_desc) - dev_desc = device_desc_default_get(dev); - - if (dev_desc) { - intr_name = device_desc_intr_name_get(dev_desc); - intr_swlevel = device_desc_intr_swlevel_get(dev_desc); - if (dev_desc->flags & D_INTR_ISERR) { - intr_resflags = II_ERRORINT; - } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { - intr_resflags = II_THREADED; - } else { - /* Neither an error nor a thread. */ - intr_resflags = 0; - } - } else { - intr_swlevel = default_intr_pri; - if (!uncond_nothread) - intr_resflags = II_THREADED; - } - - /* XXX - Need to determine if the interrupt should be threaded. */ - - /* If the cpu has not been picked already then choose a candidate - * interrupt target and reserve the interrupt bit - */ -#if defined(NEW_INTERRUPTS) - if (!cpupicked) { - cpu = intr_heuristic(dev,dev_desc,allocate_my_bit, - intr_resflags,owner_dev, - intr_name,&bit); - } -#endif - - /* At this point we SHOULD have a valid cpu */ - if (cpu == CPU_NONE) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n", - owner_dev); -#else - PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n", - owner_dev); -#endif - return(0); - - } - - /* If the cpu has been picked already (due to the bridge data - * corruption bug) then try to reserve an interrupt bit . - */ -#if defined(NEW_INTERRUPTS) - if (cpupicked) { - bit = intr_reserve_level(cpu, allocate_my_bit, - intr_resflags, - owner_dev, intr_name); - if (bit < 0) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("Could not reserve an interrupt bit for cpu " - " %d and dev %v\n", - cpu,owner_dev); -#else - PRINT_WARNING("Could not reserve an interrupt bit for cpu " - " %d and dev 0x%x\n", - cpu, owner_dev); -#endif - - return(0); - } - } -#endif /* NEW_INTERRUPTS */ - - nodeid = cpuid_to_cnodeid(cpu); - nasid = cpuid_to_nasid(cpu); - xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu))); - - /* - * Allocate an interrupt handle, and fill it in. There are two - * pieces to an interrupt handle: the piece needed by generic - * xtalk code which is used by crosstalk device drivers, and - * the piece needed by low-level IP27 hardware code. - */ - intr_hdl = kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid); - ASSERT_ALWAYS(intr_hdl); - - /* - * Fill in xtalk information for generic xtalk interfaces that - * operate on xtalk_intr_hdl's. - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = dev; - xtalk_info->xi_vector = bit; - xtalk_info->xi_addr = xtalk_addr; - - /* - * Regardless of which CPU we ultimately interrupt, a given crosstalk - * widget always handles interrupts (and PIO and DMA) through its - * designated "master" crosstalk provider. - */ - xwidget_info = xwidget_info_get(dev); - if (xwidget_info) - xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); - - /* Fill in low level hub information for hub_* interrupt interface */ - intr_hdl->i_swlevel = intr_swlevel; - intr_hdl->i_cpuid = cpu; - intr_hdl->i_bit = bit; - intr_hdl->i_flags = HUB_INTR_IS_ALLOCED; - - /* Store the actual interrupt priority level & interrupt target - * cpu back in the device descriptor. - */ - hub_device_desc_update(dev_desc, intr_swlevel, cpu); -#ifdef CONFIG_IA64_SGI_SN1 - synergy_intr_alloc((int)bit, (int)cpu); -#endif - return(intr_hdl); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Uncondtionally request non-threaded, regardless of what the device - * descriptor might say. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -hub_intr_free(hub_intr_t intr_hdl) -{ - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_t xtalk_info; - - if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { - /* Setting the following fields in the xtalk interrupt info - * clears the interrupt target register in the xtalk user - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = NODEV; - xtalk_info->xi_vector = 0; - xtalk_info->xi_addr = 0; - hub_intr_disconnect(intr_hdl); - } - - if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) - kfree(intr_hdl); - -#if defined(NEW_INTERRUPTS) - intr_unreserve_level(cpu, bit); -#endif -} - - -/* - * Associate resources allocated with a previous hub_intr_alloc call with the - * described handler, arg, name, etc. - */ -/*ARGSUSED*/ -int -hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */ - intr_func_t intr_func, /* xtalk intr handler */ - void *intr_arg, /* arg to intr handler */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg, /* arg to setfunc */ - void *thread) /* intr thread to use */ -{ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; -#ifdef CONFIG_IA64_SGI_SN1 - extern int synergy_intr_connect(int, int); -#endif - - ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); - -#if defined(NEW_INTERRUPTS) - rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, - intr_func, intr_arg, NULL); - if (rv < 0) - return(rv); - -#endif - intr_hdl->i_xtalk_info.xi_setfunc = setfunc; - intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; - - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; -#ifdef CONFIG_IA64_SGI_SN1 - return(synergy_intr_connect((int)bit, (int)cpu)); -#endif -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -hub_intr_disconnect(hub_intr_t intr_hdl) -{ - /*REFERENCED*/ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_setfunc_t setfunc; - - setfunc = intr_hdl->i_xtalk_info.xi_setfunc; - - /* TBD: send disconnected interrupts somewhere harmless */ - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - -#if defined(NEW_INTERRUPTS) - rv = intr_disconnect_level(cpu, bit); - ASSERT(rv == 0); -#endif - - intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl) -{ - cpuid_t cpuid = intr_hdl->i_cpuid; - ASSERT(cpuid != CPU_NONE); - - return(cpuid_to_vertex(cpuid)); -} - - - /* CONFIGURATION MANAGEMENT */ /* @@ -912,6 +603,9 @@ void hub_provider_startup(devfs_handle_t hubv) { + extern void hub_dma_init(devfs_handle_t hubv); + extern void hub_pio_init(devfs_handle_t hubv); + hub_pio_init(hubv); hub_dma_init(hubv); hub_intr_init(hubv); @@ -1170,58 +864,6 @@ return rv; } -#if ((defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP)) -/* BRINGUP: This ought to be useful for IP27 too but, for now, - * make it SN1 only because `ii_ixtt_u_t' is not in IP27/hubio.h - * (or anywhere else :-). - */ -int -hubii_ixtt_set(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt) -{ - xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); - devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); - hubinfo_t hub_info = 0; - nasid_t nasid; - unsigned long s; - - /* Use the nasid from the hub info hanging off the hub vertex - * and widget number from the widget vertex - */ - hubinfo_get(hub_vhdl, &hub_info); - /* Being over cautious by grabbing a lock */ - s = mutex_spinlock(&hub_info->h_bwlock); - nasid = hub_info->h_nasid; - - REMOTE_HUB_S(nasid, IIO_IXTT, ixtt->ii_ixtt_regval); - - mutex_spinunlock(&hub_info->h_bwlock, s); - return 0; -} - -int -hubii_ixtt_get(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt) -{ - xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); - devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); - hubinfo_t hub_info = 0; - nasid_t nasid; - unsigned long s; - - /* Use the nasid from the hub info hanging off the hub vertex - * and widget number from the widget vertex - */ - hubinfo_get(hub_vhdl, &hub_info); - /* Being over cautious by grabbing a lock */ - s = mutex_spinlock(&hub_info->h_bwlock); - nasid = hub_info->h_nasid; - - ixtt->ii_ixtt_regval = REMOTE_HUB_L(nasid, IIO_IXTT); - - mutex_spinunlock(&hub_info->h_bwlock, s); - return 0; -} -#endif /* CONFIG_IA64_SGI_SN1 */ - /* * hub_device_inquiry * Find out the xtalk widget related information stored in this @@ -1259,7 +901,7 @@ #if defined(SUPPORT_PRINTING_V_FORMAT) printk("Inquiry Info for %v\n", xconn); #else - printk("Inquiry Info for 0x%x\n", xconn); + printk("Inquiry Info for %p\n", (void *)xconn); #endif printk("\tDevices shutdown [ "); diff -urN linux-2.4.18/arch/ia64/sn/io/ip37.c linux-2.4.19-pre5/arch/ia64/sn/io/ip37.c --- linux-2.4.18/arch/ia64/sn/io/ip37.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ip37.c Thu Jan 1 01:00:00 1970 @@ -1,121 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ - -/* - * ip37.c - * Support for IP35/IP37 machines - */ - -#include -#include - -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include -#include -#include -#include /* for bridge_t */ - - -xwidgetnum_t -hub_widget_id(nasid_t nasid) -{ - hubii_wcr_t ii_wcr; /* the control status register */ - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - - return ii_wcr.wcr_fields_s.wcr_widget_id; -} - -/* - * get_nasid() returns the physical node id number of the caller. - */ -nasid_t -get_nasid(void) -{ - return (nasid_t)((LOCAL_HUB_L(LB_REV_ID) & LRI_NODEID_MASK) >> LRI_NODEID_SHFT); -} - -int -get_slice(void) -{ - return LOCAL_HUB_L(PI_CPU_NUM); -} - -int -is_fine_dirmode(void) -{ - return (((LOCAL_HUB_L(LB_REV_ID) & LRI_SYSTEM_SIZE_MASK) - >> LRI_SYSTEM_SIZE_SHFT) == SYSTEM_SIZE_SMALL); - -} - -hubreg_t -get_hub_chiprev(nasid_t nasid) -{ - - return ((REMOTE_HUB_L(nasid, LB_REV_ID) & LRI_REV_MASK) - >> LRI_REV_SHFT); -} - -int -verify_snchip_rev(void) -{ - int hub_chip_rev; - int i; - static int min_hub_rev = 0; - nasid_t nasid; - static int first_time = 1; - extern int maxnodes; - - - if (first_time) { - for (i = 0; i < maxnodes; i++) { - nasid = COMPACT_TO_NASID_NODEID(i); - hub_chip_rev = get_hub_chiprev(nasid); - - if ((hub_chip_rev < min_hub_rev) || (i == 0)) - min_hub_rev = hub_chip_rev; - } - - - first_time = 0; - } - - return min_hub_rev; - -} - -#ifdef SN1_USE_POISON_BITS -int -hub_bte_poison_ok(void) -{ - /* - * For now, assume poisoning is ok. If it turns out there are chip - * bugs that prevent its use in early revs, there is some neat code - * to steal from the IP27 equivalent of this code. - */ - -#ifdef BRINGUP /* temp disable BTE poisoning - might be sw bugs in this area */ - return 0; -#else - return 1; -#endif -} -#endif /* SN1_USE_POISON_BITS */ - - -void -ni_reset_port(void) -{ - LOCAL_HUB_S(NI_RESET_ENABLE, NRE_RESETOK); - LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); -} - -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ diff -urN linux-2.4.18/arch/ia64/sn/io/klconflib.c linux-2.4.19-pre5/arch/ia64/sn/io/klconflib.c --- linux-2.4.18/arch/ia64/sn/io/klconflib.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/klconflib.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ @@ -13,12 +12,13 @@ #include #include #include +#include +#include +#include #include #include #include #include - -#include #include #include #include @@ -40,6 +40,9 @@ static void sort_nic_names(lboard_t *) ; +u64 klgraph_addr[MAX_COMPACT_NODES]; +int module_number = 0; + lboard_t * find_lboard(lboard_t *start, unsigned char brd_type) { @@ -213,14 +216,13 @@ { lboard_t *board; -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC -/* BRINGUP: If this works then look for callers of is_master_baseio() +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) +/* If this works then look for callers of is_master_baseio() * (e.g. iograph.c) and let them pass in a slot if they want */ board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module); #else - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - module, slot); + board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), module, slot); #endif #ifndef _STANDALONE @@ -228,7 +230,7 @@ cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) board = find_lboard_module((lboard_t *) KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), module); @@ -300,16 +302,6 @@ return(brd); } -int -get_cpu_slice(cpuid_t cpu) -{ - klcpu_t *acpu; - if ((acpu = get_cpuinfo(cpu)) == NULL) - return -1; - return acpu->cpu_info.physid; -} - - /* * get_actual_nasid * @@ -366,10 +358,6 @@ { moduleid_t modnum; char *board_name; -#if !defined(CONFIG_SGI_IP35) && !defined(CONFIG_IA64_SGI_SN1) && !defined(CONFIG_IA64_GENERIC) - slotid_t slot; - char slot_name[SLOTNUM_MAXLENGTH]; -#endif ASSERT(brd); @@ -410,7 +398,10 @@ modnum = brd->brd_module; - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); + /* ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); */ +if ((modnum == MODULE_UNKNOWN) || (modnum == INVALID_MODULE)) { + modnum = ++module_number; +} #ifdef __ia64 { char buffer[16]; @@ -431,7 +422,7 @@ { lboard_t *brd; - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); if (!brd) return INVALID_MODULE; @@ -569,8 +560,8 @@ if (component_serial_number_get(board, hub->hub_mfg_nic, serial_number, -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - "IP35")) +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) + "IP37")) #else "IP27")) /* Try with IP31 key if IP27 key fails */ @@ -578,7 +569,7 @@ hub->hub_mfg_nic, serial_number, "IP31")) -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_SGI_SN1 */ return(1); break; } @@ -875,10 +866,11 @@ } -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) char brick_types[MAX_BRICK_TYPES + 1] = "crikxdp789012345"; +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) + /* * Format a module id for printing. */ @@ -1009,7 +1001,7 @@ return (int)(unsigned short)m; } -#else /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ +#else /* CONFIG_IA64_SGI_SN1 */ /* * Format a module id for printing. @@ -1038,8 +1030,8 @@ if (strstr(buffer, EDGE_LBL_MODULE "/") == buffer) buffer += strlen(EDGE_LBL_MODULE "/"); - m = 0; - while(c = *buffer++) { + for (m = 0; *buffer; buffer++) { + c = *buffer; if (!isdigit(c)) return -1; m = 10 * m + (c - '0'); @@ -1049,6 +1041,6 @@ return (int)(unsigned short)m; } -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_SGI_SN1 */ diff -urN linux-2.4.18/arch/ia64/sn/io/klgraph.c linux-2.4.19-pre5/arch/ia64/sn/io/klgraph.c --- linux-2.4.18/arch/ia64/sn/io/klgraph.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/klgraph.c Sat Mar 30 22:55:25 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ /* @@ -18,12 +17,12 @@ #include #include #include +#include +#include #include #include #include #include - -#include #include #include #include @@ -43,8 +42,7 @@ #include extern char arg_maxnodes[]; -extern int maxnodes; - +extern u64 klgraph_addr[]; /* * Support for verbose inventory via hardware graph. @@ -139,193 +137,63 @@ void klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) { +#if defined(CONFIG_IA64_SGI_SN1) devfs_handle_t myhubv; + devfs_handle_t hub_mon; + devfs_handle_t synergy; + devfs_handle_t fsb0; + devfs_handle_t fsb1; int rc; + extern struct file_operations hub_mon_fops; GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); rc = device_master_set(myhubv, node_vertex); -#ifdef LATER /* - * Activate when we support hub stats. + * hub perf stats. */ rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO, (arbitrary_info_t)(&NODEPDA(cnode)->hubstats)); -#endif if (rc != GRAPH_SUCCESS) { - PRINT_WARNING("klhwg_add_hub: Can't add hub info label 0x%p, code %d", - myhubv, rc); + printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d", + (void *)myhubv, rc); } klhwg_hub_invent_info(myhubv, cnode, hub); -#ifndef BRINGUP + hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &hub_mon_fops, + (void *)(long)cnode); + init_hub_stats(cnode, NODEPDA(cnode)); - sndrv_attach(myhubv); -#else + /* - * Need to call our driver to do the attach? + * synergy perf */ - FIXME("klhwg_add_hub: Need to add code to do the attach.\n"); -#endif -} - -#ifndef BRINGUP - -void -klhwg_add_rps(devfs_handle_t node_vertex, cnodeid_t cnode, int flag) -{ - devfs_handle_t myrpsv; - invent_rpsinfo_t *rps_invent; - int rc; - - if(cnode == CNODEID_NONE) - return; - - GRPRINTF(("klhwg_add_rps: adding %s to vertex 0x%x\n", EDGE_LBL_RPS, - node_vertex)); - - rc = hwgraph_path_add(node_vertex, EDGE_LBL_RPS, &myrpsv); - if (rc != GRAPH_SUCCESS) - return; - - device_master_set(myrpsv, node_vertex); - - rps_invent = (invent_rpsinfo_t *) - klhwg_invent_alloc(cnode, INV_RPS, sizeof(invent_rpsinfo_t)); - - if (!rps_invent) - return; - - rps_invent->ir_xbox = 0; /* not an xbox RPS */ - - if (flag) - rps_invent->ir_gen.ig_flag = INVENT_ENABLED; - else - rps_invent->ir_gen.ig_flag = 0x0; - - hwgraph_info_add_LBL(myrpsv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) rps_invent); - hwgraph_info_export_LBL(myrpsv, INFO_LBL_DETAIL_INVENT, - sizeof(invent_rpsinfo_t)); - -} - -/* - * klhwg_update_rps gets invoked when the system controller sends an - * interrupt indicating the power supply has lost/regained the redundancy. - * It's responsible for updating the Hardware graph information. - * rps_state = 0 -> if the rps lost the redundancy - * = 1 -> If it is redundant. - */ -void -klhwg_update_rps(cnodeid_t cnode, int rps_state) -{ - devfs_handle_t node_vertex; - devfs_handle_t rpsv; - invent_rpsinfo_t *rps_invent; - int rc; - if(cnode == CNODEID_NONE) - return; - - node_vertex = cnodeid_to_vertex(cnode); - rc = hwgraph_edge_get(node_vertex, EDGE_LBL_RPS, &rpsv); - if (rc != GRAPH_SUCCESS) { - return; - } - - rc = hwgraph_info_get_LBL(rpsv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t *)&rps_invent); - if (rc != GRAPH_SUCCESS) { - return; - } - - if (rps_state == 0 ) - rps_invent->ir_gen.ig_flag = 0; - else - rps_invent->ir_gen.ig_flag = INVENT_ENABLED; -} - -void -klhwg_add_xbox_rps(devfs_handle_t node_vertex, cnodeid_t cnode, int flag) -{ - devfs_handle_t myrpsv; - invent_rpsinfo_t *rps_invent; - int rc; - - if(cnode == CNODEID_NONE) - return; - - GRPRINTF(("klhwg_add_rps: adding %s to vertex 0x%x\n", - EDGE_LBL_XBOX_RPS, node_vertex)); - - rc = hwgraph_path_add(node_vertex, EDGE_LBL_XBOX_RPS, &myrpsv); - if (rc != GRAPH_SUCCESS) - return; - - device_master_set(myrpsv, node_vertex); - - rps_invent = (invent_rpsinfo_t *) - klhwg_invent_alloc(cnode, INV_RPS, sizeof(invent_rpsinfo_t)); - - if (!rps_invent) - return; - - rps_invent->ir_xbox = 1; /* xbox RPS */ - - if (flag) - rps_invent->ir_gen.ig_flag = INVENT_ENABLED; - else - rps_invent->ir_gen.ig_flag = 0x0; - - hwgraph_info_add_LBL(myrpsv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) rps_invent); - hwgraph_info_export_LBL(myrpsv, INFO_LBL_DETAIL_INVENT, - sizeof(invent_rpsinfo_t)); - -} - -/* - * klhwg_update_xbox_rps gets invoked when the xbox system controller - * polls the status register and discovers that the power supply has - * lost/regained the redundancy. - * It's responsible for updating the Hardware graph information. - * rps_state = 0 -> if the rps lost the redundancy - * = 1 -> If it is redundant. - */ -void -klhwg_update_xbox_rps(cnodeid_t cnode, int rps_state) -{ - devfs_handle_t node_vertex; - devfs_handle_t rpsv; - invent_rpsinfo_t *rps_invent; - int rc; - if(cnode == CNODEID_NONE) - return; - - node_vertex = cnodeid_to_vertex(cnode); - rc = hwgraph_edge_get(node_vertex, EDGE_LBL_XBOX_RPS, &rpsv); - if (rc != GRAPH_SUCCESS) { - return; - } - - rc = hwgraph_info_get_LBL(rpsv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t *)&rps_invent); - if (rc != GRAPH_SUCCESS) { - return; - } - - if (rps_state == 0 ) - rps_invent->ir_gen.ig_flag = 0; - else - rps_invent->ir_gen.ig_flag = INVENT_ENABLED; + (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy); + (void) hwgraph_path_add(synergy, "0", &fsb0); + (void) hwgraph_path_add(synergy, "1", &fsb1); + + fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0)); + + fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1)); +#endif /* CONFIG_IA64_SGI_SN1 */ } -#endif /* BRINGUP */ - void klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) { @@ -338,11 +206,8 @@ /*REFERENCED*/ graph_error_t err; -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC) - if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_IOBRICK_XBOW)) == NULL) + if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) return; -#endif if (KL_CONFIG_DUPLICATE_BOARD(brd)) return; @@ -372,7 +237,7 @@ hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); if (hub_nasid == INVALID_NASID) { - PRINT_WARNING("hub widget %d, skipping xbow graph\n", widgetnum); + printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); continue; } @@ -387,13 +252,13 @@ err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - PRINT_WARNING("klhwg_add_xbow: Check for " + printk(KERN_WARNING "klhwg_add_xbow: Check for " "working routers and router links!"); PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p)," + "edge: vertex 0x%p to vertex 0x%p," "error %d\n", - hubv, hubv, xbow_v, xbow_v, err); + (void *)hubv, (void *)xbow_v, err); } xswitch_vertex_init(xbow_v); @@ -416,7 +281,7 @@ err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); if (err != GRAPH_SUCCESS) { if (err == GRAPH_DUP) - PRINT_WARNING("klhwg_add_xbow: Check for " + printk(KERN_WARNING "klhwg_add_xbow: Check for " "working routers and router links!"); PRINT_PANIC("klhwg_add_xbow: Failed to add " @@ -443,7 +308,7 @@ int board_disabled = 0; nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", cnode, nasid, brd)); ASSERT(brd); @@ -495,7 +360,7 @@ brd = KLCF_NEXT(brd); if (brd) - brd = find_lboard(brd, KLTYPE_IP27); + brd = find_lboard(brd, KLTYPE_SNIA); else break; } while(brd); @@ -513,7 +378,7 @@ char path_buffer[100]; int rv; - for (cnode = 0; cnode < maxnodes; cnode++) { + for (cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", @@ -594,7 +459,7 @@ return; if (rc != GRAPH_SUCCESS) - PRINT_WARNING("Can't find router: %s", path_buffer); + printk(KERN_WARNING "Can't find router: %s", path_buffer); /* We don't know what to do with multiple router components */ if (brd->brd_numcompts != 1) { @@ -650,7 +515,7 @@ if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", - path_buffer, dest_path, dest_hndl, rc); + path_buffer, dest_path, (void *)dest_hndl, rc); } } @@ -663,7 +528,7 @@ cnodeid_t cnode; lboard_t *brd; - for (cnode = 0; cnode < maxnodes; cnode++) { + for (cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", @@ -703,14 +568,13 @@ char dest_path[50]; graph_error_t rc; - for (cnode = 0; cnode < maxnodes; cnode++) { + for (cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", cnode)); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_IP27); + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); ASSERT(brd); hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); @@ -732,7 +596,7 @@ rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); if (rc != GRAPH_SUCCESS) - PRINT_WARNING("Can't find hub: %s", path_buffer); + printk(KERN_WARNING "Can't find hub: %s", path_buffer); dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( hub->hub_port.port_nasid, @@ -757,7 +621,7 @@ if (rc != GRAPH_SUCCESS) PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", - path_buffer, dest_path, dest_hndl, rc); + path_buffer, dest_path, (void *)dest_hndl, rc); } } @@ -896,23 +760,14 @@ void klhwg_add_all_nodes(devfs_handle_t hwgraph_root) { - //gda_t *gdap = GDA; - gda_t *gdap; cnodeid_t cnode; - gdap = (gda_t *)0xe000000000002400; - - FIXME("klhwg_add_all_nodes: FIX GDA\n"); - for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - klhwg_add_node(hwgraph_root, cnode, gdap); + klhwg_add_node(hwgraph_root, cnode, NULL); } for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - - klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]); + klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode)); } /* diff -urN linux-2.4.18/arch/ia64/sn/io/klgraph_hack.c linux-2.4.19-pre5/arch/ia64/sn/io/klgraph_hack.c --- linux-2.4.18/arch/ia64/sn/io/klgraph_hack.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/klgraph_hack.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ @@ -18,6 +17,7 @@ #include #include #include +#include #include void * real_port; @@ -28,11 +28,11 @@ kl_config_hdr_t *linux_klcfg; -#ifdef BRINGUP +#ifdef DEFINE_DUMP_RTNS /* forward declarations */ -extern void dump_ii(void), dump_lb(void), dump_crossbow(void); -extern void clear_ii_error(void); -#endif /* BRINGUP */ +static void dump_ii(void), dump_crossbow(void); +static void clear_ii_error(void); +#endif /* DEFINE_DUMP_RTNS */ #define SYNERGY_WIDGET ((char *)0xc0000e0000000000) #define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) @@ -45,115 +45,10 @@ #define HUBREG ((char *)0xc0000a0001e00000) #define WIDGET0 ((char *)0xc0000a0000000000) -int test = 0; - -/* - * Hack to loop for test. - */ -void -test_io_regs(void) -{ - - uint32_t reg_32bits; - uint64_t reg_64bits; - - while (test) { - - reg_32bits = (uint32_t)(*(volatile uint32_t *) SYNERGY_WIDGET); - reg_64bits = (uint64_t) (*(volatile uint64_t *) SYNERGY_WIDGET); - - } - - printk("Synergy Widget Address = 0x%p, Value = 0x%lx\n", SYNERGY_WIDGET, (uint64_t)*(SYNERGY_WIDGET)); - - printk("Synergy swizzle Address = 0x%p, Value = 0x%lx\n", SYNERGY_SWIZZLE, (uint64_t)*(SYNERGY_SWIZZLE)); - printk("HUBREG Address = 0x%p, Value = 0x%lx\n", HUBREG, (uint64_t)*(HUBREG)); - printk("WIDGET0 Address = 0x%p, Value = 0x%lx\n", WIDGET0, (uint64_t)*(WIDGET0)); - printk("WIDGET4 Address = 0x%p, Value = 0x%x\n", WIDGET4, (uint32_t)*(WIDGET4)); - -} - void klgraph_hack_init(void) { - kl_config_hdr_t *kl_hdr_ptr; - lboard_t *lb_ptr; - lboard_t *temp_ptr; - klhub_t *klhub_ptr; - klioc3_t *klioc3_ptr; - klbri_t *klbri_ptr; - klxbow_t *klxbow_ptr; - klinfo_t *klinfo_ptr; - klcomp_t *klcomp_ptr; -#if 0 - uint64_t *tmp; - volatile u32 *tmp32; - - /* Preset some values */ - /* Write IOERR clear to clear the CRAZY bit in the status */ - tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff; - /* set widget control register...setting bedrock widget id to b */ - /* tmp = (uint64_t *)0xc0000a0001c00020; *tmp = (uint64_t)0x801b; */ - /* set io outbound widget access...allow all */ - tmp = (uint64_t *)0xc0000a0001c00110; *tmp = (uint64_t)0xff01; - /* set io inbound widget access...allow all */ - tmp = (uint64_t *)0xc0000a0001c00118; *tmp = (uint64_t)0xff01; - /* set io crb timeout to max */ - tmp = (uint64_t *)0xc0000a0001c003c0; *tmp = (uint64_t)0xffffff; - tmp = (uint64_t *)0xc0000a0001c003c0; *tmp = (uint64_t)0xffffff; - - /* set local block io permission...allow all */ - tmp = (uint64_t *)0xc0000a0001e04010; *tmp = (uint64_t)0xfffffffffffffff; - - /* clear any errors */ - clear_ii_error(); - - /* set default read response buffers in bridge */ - tmp32 = (volatile u32 *)0xc0000a000f000280L; - *tmp32 = 0xba98; - tmp32 = (volatile u32 *)0xc0000a000f000288L; - *tmp32 = 0xba98; - -printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001e00000, *( (volatile uint64_t *)0xc0000a0001e00000) ); - -printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001c00000, *( (volatile uint64_t *)0xc0000a0001c00000) ); - -printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc000020001e00000, *( (volatile uint64_t *)0xc000020001e00000) ); - - -printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc000020001c00000, *( (volatile uint64_t *)0xc000020001c00000) ); - -printk("Widget ID Address 0x%p Value 0x%lx\n", (uint64_t *)0xc0000a0001e00000, *( (volatile uint64_t *)0xc0000a0001e00000) ); - -printk("Xbow ID Address 0x%p Value 0x%x\n", (uint64_t *)0xc0000a0000000000, *( (volatile uint32_t *)0xc0000a0000000000) ); - -printk("Xbow ID Address 0x%p Value 0x%x\n", (uint64_t *)0xc000020000000004, *( (volatile uint32_t *)0xc000020000000004) ); - -#endif - - if ( test ) - test_io_regs(); - /* - * Klconfig header. - */ - kl_hdr_ptr = kmalloc(sizeof(kl_config_hdr_t), GFP_KERNEL); - kl_hdr_ptr->ch_magic = 0xbeedbabe; - kl_hdr_ptr->ch_version = 0x0; - kl_hdr_ptr->ch_malloc_hdr_off = 0x48; - kl_hdr_ptr->ch_cons_off = 0x18; - kl_hdr_ptr->ch_board_info = 0x0; - kl_hdr_ptr->ch_cons_info.uart_base = 0x920000000f820178; - kl_hdr_ptr->ch_cons_info.config_base = 0x920000000f024000; - kl_hdr_ptr->ch_cons_info.memory_base = 0x920000000f800000; - kl_hdr_ptr->ch_cons_info.baud = 0x2580; - kl_hdr_ptr->ch_cons_info.flag = 0x1; - kl_hdr_ptr->ch_cons_info.type = 0x300fafa; - kl_hdr_ptr->ch_cons_info.nasid = 0x0; - kl_hdr_ptr->ch_cons_info.wid = 0xf; - kl_hdr_ptr->ch_cons_info.npci = 0x4; - kl_hdr_ptr->ch_cons_info.baseio_nic = 0x0; - /* * We need to know whether we are booting from PROM or * boot from disk. @@ -162,520 +57,44 @@ if (linux_klcfg->ch_magic == 0xbeedbabe) { return; } else { - linux_klcfg = kl_hdr_ptr; + panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n"); } - /* - * lboard KLTYPE_IP35 - */ - lb_ptr = kmalloc(sizeof(lboard_t), GFP_KERNEL); - kl_hdr_ptr->ch_board_info = (klconf_off_t) lb_ptr; - temp_ptr = lb_ptr; - printk("First Lboard = %p\n", temp_ptr); - - lb_ptr->brd_next = 0; - lb_ptr->struct_type = 0x1; - lb_ptr->brd_type = 0x11; - lb_ptr->brd_sversion = 0x3; - lb_ptr->brd_brevision = 0x1; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_slot = 0x0; - lb_ptr->brd_debugsw = 0x0; - lb_ptr->brd_module = 0x145; - lb_ptr->brd_partition = 0x0; - lb_ptr->brd_diagval = 0x0; - lb_ptr->brd_diagparm = 0x0; - lb_ptr->brd_inventory = 0x0; - lb_ptr->brd_numcompts = 0x5; - lb_ptr->brd_nic = 0x2a0aed35; - lb_ptr->brd_nasid = 0x0; - lb_ptr->brd_errinfo = 0x0; - lb_ptr->brd_parent = 0x0; - lb_ptr->brd_graph_link = (devfs_handle_t)0x26; - lb_ptr->brd_owner = 0x0; - lb_ptr->brd_nic_flags = 0x0; - memcpy(&lb_ptr->brd_name[0], "IP35", 4); - - /* - * Hub Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klhub_ptr = (klhub_t *)klcomp_ptr; - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[0] = (klconf_off_t)klcomp_ptr; - printk("hub info = %p lboard = %p\n", klhub_ptr, lb_ptr); - - klinfo_ptr = (klinfo_t *)klhub_ptr; - klinfo_ptr->struct_type = 0x2; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0x1; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0x2a0aed35; - klinfo_ptr->physid = 0x0; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - klhub_ptr->hub_flags = 0x0; - klhub_ptr->hub_port.port_nasid = (nasid_t)0x0ffffffff; - klhub_ptr->hub_port.port_flag = 0x0; - klhub_ptr->hub_port.port_offset = 0x0; - klhub_ptr->hub_box_nic = 0x0; - klhub_ptr->hub_mfg_nic = 0x3f420; - klhub_ptr->hub_speed = 0xbebc200; - - /* - * Memory Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[1] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x3; - klinfo_ptr->struct_version = 0x2; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0xff; - klinfo_ptr->virtid = 0xffffffff; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_HUB_UART Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[2] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x11; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x0; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_CPU Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[3] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x1; - klinfo_ptr->struct_version = 0x2; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x0; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_CPU Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[4] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x1; - klinfo_ptr->struct_version = 0x2; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x1; - klinfo_ptr->virtid = 0x1; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - lb_ptr->brd_compts[5] = 0; /* Set the next one to 0 .. end */ - lb_ptr->brd_numcompts = 5; /* 0 to 4 */ - - /* - * lboard(0x42) KLTYPE_PBRICK_XBOW - */ - lb_ptr = kmalloc(sizeof(lboard_t), GFP_KERNEL); - temp_ptr->brd_next = (klconf_off_t)lb_ptr; /* Let the previous point at the new .. */ - temp_ptr = lb_ptr; - printk("Second Lboard = %p\n", temp_ptr); - - lb_ptr->brd_next = 0; - lb_ptr->struct_type = 0x1; - lb_ptr->brd_type = 0x42; - lb_ptr->brd_sversion = 0x2; - lb_ptr->brd_brevision = 0x0; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_slot = 0x0; - lb_ptr->brd_debugsw = 0x0; - lb_ptr->brd_module = 0x145; - lb_ptr->brd_partition = 0x1; - lb_ptr->brd_diagval = 0x0; - lb_ptr->brd_diagparm = 0x0; - lb_ptr->brd_inventory = 0x0; - lb_ptr->brd_numcompts = 0x1; - lb_ptr->brd_nic = 0xffffffffffffffff; - lb_ptr->brd_nasid = 0x0; - lb_ptr->brd_errinfo = 0x0; - lb_ptr->brd_parent = (struct lboard_s *)0x9600000000030070; - lb_ptr->brd_graph_link = (devfs_handle_t)0xffffffff; - lb_ptr->brd_owner = 0x0; - lb_ptr->brd_nic_flags = 0x0; - memcpy(&lb_ptr->brd_name[0], "IOBRICK", 7); - - /* - * KLSTRUCT_XBOW Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - memset(klcomp_ptr, 0, sizeof(klcomp_t)); - klxbow_ptr = (klxbow_t *)klcomp_ptr; - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[0] = (klconf_off_t)klcomp_ptr; - printk("xbow_p 0x%p\n", klcomp_ptr); - - klinfo_ptr->struct_type = 0x4; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0x2; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0xff; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0x0; - klinfo_ptr->nasid = 0x0; - - klxbow_ptr->xbow_master_hub_link = 0xb; - klxbow_ptr->xbow_port_info[0].port_nasid = 0x0; - klxbow_ptr->xbow_port_info[0].port_flag = 0x0; - klxbow_ptr->xbow_port_info[0].port_offset = 0x0; - - klxbow_ptr->xbow_port_info[1].port_nasid = 0x401; - klxbow_ptr->xbow_port_info[1].port_flag = 0x0; - klxbow_ptr->xbow_port_info[1].port_offset = 0x0; - - klxbow_ptr->xbow_port_info[2].port_nasid = 0x0; - klxbow_ptr->xbow_port_info[2].port_flag = 0x0; - klxbow_ptr->xbow_port_info[2].port_offset = 0x0; - - klxbow_ptr->xbow_port_info[3].port_nasid = 0x0; /* ffffffff */ - klxbow_ptr->xbow_port_info[3].port_flag = 0x6; - klxbow_ptr->xbow_port_info[3].port_offset = 0x30070; - - klxbow_ptr->xbow_port_info[4].port_nasid = 0x0; /* ffffff00; */ - klxbow_ptr->xbow_port_info[4].port_flag = 0x0; - klxbow_ptr->xbow_port_info[4].port_offset = 0x0; - - klxbow_ptr->xbow_port_info[5].port_nasid = 0x0; - klxbow_ptr->xbow_port_info[5].port_flag = 0x0; - klxbow_ptr->xbow_port_info[5].port_offset = 0x0; - klxbow_ptr->xbow_port_info[6].port_nasid = 0x0; - klxbow_ptr->xbow_port_info[6].port_flag = 0x5; - klxbow_ptr->xbow_port_info[6].port_offset = 0x30210; - klxbow_ptr->xbow_port_info[7].port_nasid = 0x3; - klxbow_ptr->xbow_port_info[7].port_flag = 0x5; - klxbow_ptr->xbow_port_info[7].port_offset = 0x302e0; - - lb_ptr->brd_compts[1] = 0; - lb_ptr->brd_numcompts = 1; - - - /* - * lboard KLTYPE_PBRICK - */ - lb_ptr = kmalloc(sizeof(lboard_t), GFP_KERNEL); - temp_ptr->brd_next = (klconf_off_t)lb_ptr; /* Let the previous point at the new .. */ - temp_ptr = lb_ptr; - printk("Third Lboard %p\n", lb_ptr); - - lb_ptr->brd_next = 0; - lb_ptr->struct_type = 0x1; - lb_ptr->brd_type = 0x72; - lb_ptr->brd_sversion = 0x2; - lb_ptr->brd_brevision = 0x0; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_promver = 0x41; - lb_ptr->brd_slot = 0xe; - lb_ptr->brd_debugsw = 0x0; - lb_ptr->brd_module = 0x145; - lb_ptr->brd_partition = 0x1; - lb_ptr->brd_diagval = 0x0; - lb_ptr->brd_diagparm = 0x0; - lb_ptr->brd_inventory = 0x0; - lb_ptr->brd_numcompts = 0x1; - lb_ptr->brd_nic = 0x30e3fd; - lb_ptr->brd_nasid = 0x0; - lb_ptr->brd_errinfo = 0x0; - lb_ptr->brd_parent = (struct lboard_s *)0x9600000000030140; - lb_ptr->brd_graph_link = (devfs_handle_t)0xffffffff; - lb_ptr->brd_owner = 0x0; - lb_ptr->brd_nic_flags = 0x0; - memcpy(&lb_ptr->brd_name[0], "IP35", 4); - - /* - * KLSTRUCT_BRI Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klbri_ptr = (klbri_t *)klcomp_ptr; - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[0] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x5; - klinfo_ptr->struct_version = 0x2; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0x2; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0xd002; - klinfo_ptr->nic = 0x30e3fd; - klinfo_ptr->physid = 0xe; - klinfo_ptr->virtid = 0xe; - klinfo_ptr->widid = 0xe; - klinfo_ptr->nasid = 0x0; - - klbri_ptr->bri_eprominfo = 0xff; - klbri_ptr->bri_bustype = 0x7; - klbri_ptr->bri_mfg_nic = 0x3f4a8; - - lb_ptr->brd_compts[1] = 0; - lb_ptr->brd_numcompts = 1; - - /* - * lboard KLTYPE_PBRICK - */ - lb_ptr = kmalloc(sizeof(lboard_t), GFP_KERNEL); - temp_ptr->brd_next = (klconf_off_t)lb_ptr; /* Let the previous point at the new .. */ - temp_ptr = lb_ptr; - printk("Fourth Lboard %p\n", lb_ptr); - - lb_ptr->brd_next = 0x0; - lb_ptr->struct_type = 0x1; - lb_ptr->brd_type = 0x72; - lb_ptr->brd_sversion = 0x2; - lb_ptr->brd_brevision = 0x0; - lb_ptr->brd_promver = 0x1; - lb_ptr->brd_promver = 0x31; - lb_ptr->brd_slot = 0xf; - lb_ptr->brd_debugsw = 0x0; - lb_ptr->brd_module = 0x145; - lb_ptr->brd_partition = 0x1; - lb_ptr->brd_diagval = 0x0; - lb_ptr->brd_diagparm = 0x0; - lb_ptr->brd_inventory = 0x0; - lb_ptr->brd_numcompts = 0x6; - lb_ptr->brd_nic = 0x30e3fd; - lb_ptr->brd_nasid = 0x0; - lb_ptr->brd_errinfo = 0x0; - lb_ptr->brd_parent = (struct lboard_s *)0x9600000000030140; - lb_ptr->brd_graph_link = (devfs_handle_t)0xffffffff; - lb_ptr->brd_owner = 0x0; - lb_ptr->brd_nic_flags = 0x0; - memcpy(&lb_ptr->brd_name[0], "IP35", 4); - - - /* - * KLSTRUCT_BRI Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klbri_ptr = (klbri_t *)klcomp_ptr; - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[0] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x5; - klinfo_ptr->struct_version = 0x2; - klinfo_ptr->flags = 0x1; - klinfo_ptr->revision = 0x2; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0xd002; - klinfo_ptr->nic = 0x30e3fd; - klinfo_ptr->physid = 0xf; - klinfo_ptr->virtid = 0xf; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - klbri_ptr->bri_eprominfo = 0xff; - klbri_ptr->bri_bustype = 0x7; - klbri_ptr->bri_mfg_nic = 0x3f528; - - /* - * KLSTRUCT_SCSI component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[1] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0xb; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0x5; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x1; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_IOC3 Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klioc3_ptr = (klioc3_t *)klcomp_ptr; - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[2] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x6; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0x1; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x4; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - klioc3_ptr->ioc3_ssram = 0x0; - klioc3_ptr->ioc3_nvram = 0x0; - - /* - * KLSTRUCT_UNKNOWN Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[3] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x0; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x5; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_SCSI Component - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[4] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0xb; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0x1; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x6; - klinfo_ptr->virtid = 0x5; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - /* - * KLSTRUCT_UNKNOWN - */ - klcomp_ptr = kmalloc(sizeof(klcomp_t), GFP_KERNEL); - klinfo_ptr = (klinfo_t *)klcomp_ptr; - lb_ptr->brd_compts[5] = (klconf_off_t)klcomp_ptr; - - klinfo_ptr->struct_type = 0x0; - klinfo_ptr->struct_version = 0x1; - klinfo_ptr->flags = 0x31; - klinfo_ptr->revision = 0xff; - klinfo_ptr->diagval = 0x0; - klinfo_ptr->diagparm = 0x0; - klinfo_ptr->inventory = 0x0; - klinfo_ptr->partid = 0x0; - klinfo_ptr->nic = 0xffffffffffffffff; - klinfo_ptr->physid = 0x7; - klinfo_ptr->virtid = 0x0; - klinfo_ptr->widid = 0xf; - klinfo_ptr->nasid = 0x0; - - lb_ptr->brd_compts[6] = 0; - lb_ptr->brd_numcompts = 6; - } -#ifdef BRINGUP +#ifdef DEFINE_DUMP_RTNS /* * these were useful for printing out registers etc * during bringup */ -void +static void xdump(long long *addr, int count) { int ii; volatile long long *xx = addr; for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%p\n", xx, *xx); + printk("0x%p : 0x%p\n", (void *)xx, (void *)*xx); } } -void +static void xdump32(unsigned int *addr, int count) { int ii; volatile unsigned int *xx = addr; for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%0x\n", xx, *xx); + printk("0x%p : 0x%0x\n", (void *)xx, (int)*xx); } } - - -void +static void clear_ii_error(void) { volatile long long *tmp; @@ -716,8 +135,8 @@ } -void -dump_ii() +static void +dump_ii(void) { printk("===== Dump the II regs =====\n"); xdump((long long *)0xc0000a0001c00000, 2); @@ -746,23 +165,8 @@ xdump((long long *)0xc0000a000f000000, 1); } -void -dump_lb() -{ - printk("===== Dump the LB regs =====\n"); - xdump((long long *)0xc0000a0001e00000, 1); - xdump((long long *)0xc0000a0001e04000, 13); - xdump((long long *)0xc0000a0001e04100, 2); - xdump((long long *)0xc0000a0001e04200, 2); - xdump((long long *)0xc0000a0001e08000, 5); - xdump((long long *)0xc0000a0001e08040, 2); - xdump((long long *)0xc0000a0001e08050, 3); - xdump((long long *)0xc0000a0001e0c000, 3); - xdump((long long *)0xc0000a0001e0c020, 4); -} - -void -dump_crossbow() +static void +dump_crossbow(void) { printk("===== Dump the Crossbow regs =====\n"); clear_ii_error(); @@ -793,4 +197,4 @@ } -#endif /* BRINGUP */ +#endif /* DEFINE_DUMP_RTNS */ diff -urN linux-2.4.18/arch/ia64/sn/io/l1.c linux-2.4.19-pre5/arch/ia64/sn/io/l1.c --- linux-2.4.18/arch/ia64/sn/io/l1.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/l1.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ /* In general, this file is organized in a hierarchy from lower-level @@ -16,18 +15,12 @@ * System controller "message" interface (allows multiplexing * of various kinds of requests and responses with * console I/O) - * Console interfaces (there are two): - * (1) "elscuart", used in the IP35prom and (maybe) some - * debugging situations elsewhere, and - * (2) "l1_cons", the glue that allows the L1 to act + * Console interface: + * "l1_cons", the glue that allows the L1 to act * as the system console for the stdio libraries * * Routines making use of the system controller "message"-style interface - * can be found in l1_command.c. Their names are leftover from early SN0, - * when the "module system controller" (msc) was known as the "entry level - * system controller" (elsc). The names and signatures of those functions - * remain unchanged in order to keep the SN0 -> SN1 system controller - * changes fairly localized. + * can be found in l1_command.c. */ @@ -35,45 +28,32 @@ #include #include #include +#include #include +#include #include #include #include #include #include #include -#include #include #include #include #include #include +#include +#include +#include +#include -#include - -/* - * Delete this when atomic_clear is part of atomic.h. - */ -static __inline__ int -atomic_clear (int i, atomic_t *v) -{ - __s32 old, new; - - do { - old = atomic_read(v); - new = old & ~i; - } while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old); - return new; -} - -#if defined(EEPROM_DEBUG) -#define db_printf(x) printk x -#else -#define db_printf(x) +#if defined(CONFIG_IA64_SGI_SN2) +#define USE_SAL_CONSOLE_IO 1 /* DON'T un-def this for the simulator... */ #endif -// From irix/kern/sys/SN/SN1/bdrkhspecregs.h -#define HSPEC_UART_0 0x00000080 /* UART Registers */ +/* Make all console writes atomic */ +#define SYNC_CONSOLE_WRITE 1 + /********************************************************************* * Hardware-level (UART) driver routines. @@ -81,28 +61,33 @@ /* macros for reading/writing registers */ -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) +#define LD(x) (*(volatile uint64_t *)(x)) +#define SD(x, v) (LD(x) = (uint64_t) (v)) /* location of uart receive/xmit data register */ -#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), HSPEC_UART_0)) -#define LOCAL_HUB LOCAL_HUB_ADDR -#define LOCK_HUB REMOTE_HUB_ADDR - -#define ADDR_L1_REG(n, r) \ - (L1_UART_BASE(n) | ( (r) << 3 )) +#if defined(CONFIG_IA64_SGI_SN1) +#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080)) +#define LOCK_HUB REMOTE_HUB_ADDR +#elif defined(CONFIG_IA64_SGI_SN2) +#define L1_UART_BASE(n) ((ulong)REMOTE_HUB((n), SH_JUNK_BUS_UART0)) +#define LOCK_HUB REMOTE_HUB +typedef u64 rtc_time_t; +#endif -#define READ_L1_UART_REG(n, r) \ - ( LD(ADDR_L1_REG((n), (r))) ) -#define WRITE_L1_UART_REG(n, r, v) \ - ( SD(ADDR_L1_REG((n), (r)), (v)) ) +#define ADDR_L1_REG(n, r) ( L1_UART_BASE(n) | ( (r) << 3 ) ) +#define READ_L1_UART_REG(n, r) ( LD(ADDR_L1_REG((n), (r))) ) +#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) ) + +/* upper layer interface calling methods */ +#define SERIAL_INTERRUPT_MODE 0 +#define SERIAL_POLLED_MODE 1 /* UART-related #defines */ #define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 0xf0 +#define UART_FIFO_DEPTH 16 #define UART_DELAY_SPAN 10 #define UART_PUTC_TIMEOUT 50000 #define UART_INIT_TIMEOUT 100000 @@ -114,17 +99,32 @@ #define UART_NO_CHAR (-3) #define UART_VECTOR (-4) -#ifdef BRINGUP -#define UART_DELAY(x) { int i; i = x * 1000; while (--i); } -#else -#define UART_DELAY(x) us_delay(x) -#endif +#define UART_DELAY(x) udelay(x) + +/* Some debug counters */ +#define L1C_INTERRUPTS 0 +#define L1C_OUR_R_INTERRUPTS 1 +#define L1C_OUR_X_INTERRUPTS 2 +#define L1C_SEND_CALLUPS 3 +#define L1C_RECEIVE_CALLUPS 4 +#define L1C_SET_BAUD 5 +#define L1C_ALREADY_LOCKED L1C_SET_BAUD +#define L1C_R_IRQ 6 +#define L1C_R_IRQ_RET 7 +#define L1C_LOCK_TIMEOUTS 8 +#define L1C_LOCK_COUNTER 9 +#define L1C_UNLOCK_COUNTER 10 +#define L1C_REC_STALLS 11 +#define L1C_CONNECT_CALLS 12 +#define L1C_SIZE L1C_CONNECT_CALLS /* Set to the last one */ + +uint64_t L1_collectibles[L1C_SIZE + 1]; + /* * Some macros for handling Endian-ness */ -#ifdef LITTLE_ENDIAN #define COPY_INT_TO_BUFFER(_b, _i, _n) \ { \ _b[_i++] = (_n >> 24) & 0xff; \ @@ -149,42 +149,64 @@ _xyz[1] = _b[_i++]; \ _xyz[0] = _b[_i++]; \ } -#else /* BIG_ENDIAN */ - -extern char *bcopy(const char * src, char * dest, int count); -#define COPY_INT_TO_BUFFER(_b, _i, _n) \ - { \ - bcopy((char *)&_n, _b, sizeof(_n)); \ - _i += sizeof(_n); \ - } +void snia_kmem_free(void *where, int size); -#define COPY_BUFFER_TO_INT(_b, _i, _n) \ - { \ - bcopy(&_b[_i], &_n, sizeof(_n)); \ - _i += sizeof(_n); \ - } +#define ALREADY_LOCKED 1 +#define NOT_LOCKED 0 +static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ ); -#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn) \ - { \ - bcopy(&(_b[_i]), _bn, sizeof(int)); \ - _i += sizeof(int); \ - } -#endif /* LITTLE_ENDIAN */ +#define BCOPY(x,y,z) memcpy(y,x,z) -void kmem_free(void *where, int size); +uint8_t L1_interrupts_connected; /* Non-zero when we are in interrupt mode */ -#define BCOPY(x,y,z) memcpy(y,x,z) /* * Console locking defines and functions. * */ -#ifdef BRINGUP -#define FORCE_CONSOLE_NASID +uint8_t L1_cons_is_inited = 0; /* non-zero when console is init'd */ +nasid_t Master_console_nasid = (nasid_t)-1; +extern nasid_t console_nasid; + +#if defined(CONFIG_IA64_SGI_SN1) +u64 ia64_sn_get_console_nasid(void); #endif +inline nasid_t +get_master_nasid(void) +{ +#if defined(CONFIG_IA64_SGI_SN1) + nasid_t nasid = Master_console_nasid; + + if ( nasid == (nasid_t)-1 ) { + nasid = (nasid_t)ia64_sn_get_console_nasid(); + if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) { + /* Out of bounds, use local */ + console_nasid = nasid = get_nasid(); + } + else { + /* Got a valid nasid, set the console_nasid */ + char xx[100]; +/* zzzzzz - force nasid to 0 for now */ + sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid); +nasid = 0; +/* end zzzzzz */ + xx[99] = (char)0; + early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED); + Master_console_nasid = console_nasid = nasid; + } + } + return(nasid); +#else + return((nasid_t)0); +#endif /* CONFIG_IA64_SGI_SN1 */ +} + + +#if defined(CONFIG_IA64_SGI_SN1) + #define HUB_LOCK 16 #define PRIMARY_LOCK_TIMEOUT 10000000 @@ -199,7 +221,6 @@ #define RTC_TIME_MAX ((rtc_time_t) ~0ULL) - /* * primary_lock * @@ -295,26 +316,37 @@ #define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ -inline void +void lock_console(nasid_t nasid) { int ret; + /* If we already have it locked, just return */ + L1_collectibles[L1C_LOCK_COUNTER]++; + ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); if ( ret != 0 ) { + L1_collectibles[L1C_LOCK_TIMEOUTS]++; /* timeout */ hub_unlock(nasid, HUB_LOCK); /* If the 2nd lock fails, just pile ahead.... */ hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + L1_collectibles[L1C_LOCK_TIMEOUTS]++; } } inline void unlock_console(nasid_t nasid) { + L1_collectibles[L1C_UNLOCK_COUNTER]++; hub_unlock(nasid, HUB_LOCK); } +#else /* SN2 */ +inline void lock_console(nasid_t n) {} +inline void unlock_console(nasid_t n) {} + +#endif /* CONFIG_IA64_SGI_SN1 */ int get_L1_baud(void) @@ -325,27 +357,18 @@ /* uart driver functions */ -static void +static inline void uart_delay( rtc_time_t delay_span ) { UART_DELAY( delay_span ); } -#define UART_PUTC_READY(n) ( (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) && (READ_L1_UART_REG((n), REG_MSR) & MSR_CTS) ) +#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) static int uart_putc( l1sc_t *sc ) { -#ifdef BRINGUP - /* need a delay to avoid dropping chars */ - UART_DELAY(57); -#endif -#ifdef FORCE_CONSOLE_NASID - /* We need this for the console write path _elscuart_flush() -> brl1_send() */ - sc->nasid = 0; -#endif - WRITE_L1_UART_REG( sc->nasid, REG_DAT, - sc->send[sc->sent] ); + WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); return UART_SUCCESS; } @@ -356,10 +379,6 @@ u_char lsr_reg = 0; nasid_t nasid = sc->nasid; -#ifdef FORCE_CONSOLE_NASID - nasid = sc->nasid = 0; -#endif - if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -396,9 +415,10 @@ } } - if ( sc->uart == BRL1_LOCALUART ) + if ( sc->uart == BRL1_LOCALHUB_UART ) lock_console(nasid); + /* Setup for the proper baud rate */ WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); uart_delay( UART_DELAY_SPAN ); WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff ); @@ -407,6 +427,8 @@ uart_delay( UART_DELAY_SPAN ); /* set operating parameters and set DLAB to 0 */ + + /* 8bit, one stop, clear request to send, auto flow control */ WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); uart_delay( UART_DELAY_SPAN ); WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE ); @@ -416,23 +438,28 @@ WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 ); uart_delay( UART_DELAY_SPAN ); - /* enable FIFO mode and reset both FIFOs */ + /* enable FIFO mode and reset both FIFOs, trigger on 1 */ WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN ); uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_FCR, - FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); + WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0); - if ( sc->uart == BRL1_LOCALUART ) + if ( sc->uart == BRL1_LOCALHUB_UART ) unlock_console(nasid); } /* This requires the console lock */ + +#if defined(CONFIG_IA64_SGI_SN1) + static void uart_intr_enable( l1sc_t *sc, u_char mask ) { u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(nasid); + /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -444,6 +471,9 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg |= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(nasid); } /* This requires the console lock */ @@ -453,6 +483,9 @@ u_char lcr_reg, icr_reg; nasid_t nasid = sc->nasid; + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(nasid); + /* make sure that the DLAB bit in the LCR register is 0 */ lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); @@ -464,7 +497,11 @@ icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); icr_reg &= mask; WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(nasid); } +#endif /* CONFIG_IA64_SGI_SN1 */ #define uart_enable_xmit_intr(sc) \ uart_intr_enable((sc), ICR_TIEN) @@ -511,10 +548,6 @@ net_vec_t path = sc->uart; rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; -#ifdef FORCE_CONSOLE_NASID - /* We need this for the console write path _elscuart_flush() -> brl1_send() */ - nasid = sc->nasid = 0; -#endif c = (sc->send[sc->sent] & 0xffULL); while( 1 ) @@ -543,10 +576,6 @@ nasid_t nasid = sc->nasid; net_vec_t path = sc->uart; -#ifdef FORCE_CONSOLE_NASID - nasid = sc->nasid = 0; -#endif - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) { @@ -617,6 +646,15 @@ return 0; } +/********************************************************************* + * locking macros + */ + +#define L1SC_SEND_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); } +#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); } +#define L1SC_RECV_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } +#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); } + /********************************************************************* * subchannel manipulation @@ -626,31 +664,43 @@ * associated with particular subchannels (e.g., receive queues). * */ - -#ifdef SPINLOCKS_WORK -#define SUBCH_LOCK(sc) spin_lock_irq( &((sc)->subch_lock) ) -#define SUBCH_UNLOCK(sc) spin_unlock_irq( &((sc)->subch_lock) ) -#define SUBCH_DATA_LOCK(sbch) spin_lock_irq( &((sbch)->data_lock) ) -#define SUBCH_DATA_UNLOCK(sbch) spin_unlock_irq( &((sbch)->data_lock) ) -#else -#define SUBCH_LOCK(sc) -#define SUBCH_UNLOCK(sc) -#define SUBCH_DATA_LOCK(sbch) -#define SUBCH_DATA_UNLOCK(sbch) -#endif +#define SUBCH_LOCK(sc, p) spin_lock_irqsave( &((sc)->subch_lock), p ) +#define SUBCH_UNLOCK(sc, p) spin_unlock_irqrestore( &((sc)->subch_lock), p ) +#define SUBCH_DATA_LOCK(sbch, p) spin_lock_irqsave( &((sbch)->data_lock), p ) +#define SUBCH_DATA_UNLOCK(sbch, p) spin_unlock_irqrestore( &((sbch)->data_lock), p ) -/* get_myid is an internal function that reads the PI_CPU_NUM - * register of the local bedrock to determine which of the - * four possible CPU's "this" one is +/* + * set a function to be called for subchannel ch in the event of + * a transmission low-water interrupt from the uart */ -static int -get_myid( void ) +void +subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) { - return( LD(LOCAL_HUB(PI_CPU_NUM)) ); + unsigned long pl = 0; + + L1SC_SEND_LOCK( sc, pl ); +#if !defined(SYNC_CONSOLE_WRITE) + if ( func && !sc->send_in_use ) + uart_enable_xmit_intr( sc ); +#endif + sc->subch[ch].tx_notify = func; + L1SC_SEND_UNLOCK(sc, pl ); } +/* + * set a function to be called for subchannel ch when data is received + */ +void +subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) +{ + unsigned long pl = 0; + brl1_sch_t *subch = &(sc->subch[ch]); + SUBCH_DATA_LOCK( subch, pl ); + sc->subch[ch].rx_notify = func; + SUBCH_DATA_UNLOCK( subch, pl ); +} /********************************************************************* * Queue manipulation macros @@ -767,14 +817,16 @@ * brl1_discard_packet is a dummy "receive callback" used to get rid * of packets we don't want */ -void brl1_discard_packet( l1sc_t *sc, int ch ) +void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) { + unsigned long pl = 0; brl1_sch_t *subch = &sc->subch[ch]; + sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch ); + SUBCH_DATA_LOCK( subch, pl ); q->opos = q->ipos; - atomic_clear( &(subch->packet_arrived), ~((unsigned)0) ); - SUBCH_DATA_UNLOCK( subch ); + atomic_set(&(subch->packet_arrived), 0); + SUBCH_DATA_UNLOCK( subch, pl ); } @@ -789,17 +841,15 @@ static int brl1_send_chars( l1sc_t *sc ) { - /* In the kernel, we track the depth of the C brick's UART's + /* We track the depth of the C brick's UART's * fifo in software, and only check if the UART is accepting * characters when our count indicates that the fifo should * be full. * - * For remote (router) UARTs, and also for the local (C brick) - * UART in the prom, we check with the UART before sending every + * For remote (router) UARTs, we check with the UART before sending every * character. */ - if( sc->uart == BRL1_LOCALUART ) - { + if( sc->uart == BRL1_LOCALHUB_UART ) { if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) sc->fifo_space = UART_FIFO_DEPTH; @@ -809,16 +859,10 @@ sc->sent++; } } + else { - else - - /* The following applies to all UARTs in the prom, and to remote - * (router) UARTs in the kernel... - */ - -#define TIMEOUT_RETRIES 30 + /* remote (router) UARTs */ - { int result; int tries = 0; @@ -831,7 +875,7 @@ if( result == UART_TIMEOUT ) { tries++; /* send this character in TIMEOUT_RETRIES... */ - if( tries < TIMEOUT_RETRIES ) { + if( tries < 30 /* TIMEOUT_RETRIES */ ) { continue; } /* ...or else... */ @@ -864,33 +908,39 @@ static int brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) { + unsigned long pl = 0; int index; int pkt_len = 0; unsigned short crc = INIT_CRC; char *send_ptr = sc->send; -#ifdef BRINGUP - /* We want to be sure that we are sending the entire packet before returning */ - wait = 1; -#endif - if ( sc->uart == BRL1_LOCALUART ) - lock_console(sc->nasid); - if( sc->send_in_use ) { - if( !wait ) { - if ( sc->uart == BRL1_LOCALUART ) - unlock_console(sc->nasid); - return 0; /* couldn't send anything; wait for buffer to drain */ - } - else { - /* buffer's in use, but we're synchronous I/O, so we're going - * to send whatever's in there right now and take the buffer - */ - while( sc->sent < sc->send_len ) + if( sc->send_in_use && !(wait) ) { + /* We are in the middle of sending, but can wait until done */ + return 0; + } + else if( sc->send_in_use ) { + /* buffer's in use, but we're synchronous I/O, so we're going + * to send whatever's in there right now and take the buffer + */ + int counter = 0; + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); + while( sc->sent < sc->send_len ) { brl1_send_chars( sc ); + if ( counter++ > 0xfffff ) { + char *str = "Looping waiting for uart to clear (1)\n"; + early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); + break; + } } } else { + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); sc->send_in_use = 1; } *send_ptr++ = BRL1_FLAG_CH; @@ -948,23 +998,100 @@ sc->send_len = pkt_len; sc->sent = 0; - do { - brl1_send_chars( sc ); - } while( (sc->sent < sc->send_len) && wait ); + { + int counter = 0; + do { + brl1_send_chars( sc ); + if ( counter++ > 0xfffff ) { + char *str = "Looping waiting for uart to clear (2)\n"; + early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); + break; + } + } while( (sc->sent < sc->send_len) && wait ); + } + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(sc->nasid); if( sc->sent == sc->send_len ) { - /* success! release the send buffer */ + /* success! release the send buffer and call the callup */ +#if !defined(SYNC_CONSOLE_WRITE) + brl1_notif_t callup; +#endif + sc->send_in_use = 0; + /* call any upper layer that's asked for notification */ +#if defined(XX_SYNC_CONSOLE_WRITE) + /* + * This is probably not a good idea - since the l1_ write func can be called multiple + * time within the callup function. + */ + callup = subch->tx_notify; + if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) { + L1_collectibles[L1C_SEND_CALLUPS]++; + (*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq, + sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id, + sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch)); + } +#endif /* SYNC_CONSOLE_WRITE */ } - else if( !wait ) { +#if !defined(SYNC_CONSOLE_WRITE) + else if ( !wait ) { /* enable low-water interrupts so buffer will be drained */ uart_enable_xmit_intr(sc); } - if ( sc->uart == BRL1_LOCALUART ) - unlock_console(sc->nasid); +#endif + + L1SC_SEND_UNLOCK(sc, pl); + return len; } +/* brl1_send_cont is intended to be called as an interrupt service + * routine. It sends until the UART won't accept any more characters, + * or until an error is encountered (in which case we surrender the + * send buffer and give up trying to send the packet). Once the + * last character in the packet has been sent, this routine releases + * the send buffer and calls any previously-registered "low-water" + * output routines. + */ + +#if !defined(SYNC_CONSOLE_WRITE) + +int +brl1_send_cont( l1sc_t *sc ) +{ + unsigned long pl = 0; + int done = 0; + brl1_notif_t callups[BRL1_NUM_SUBCHANS]; + brl1_notif_t *callup; + brl1_sch_t *subch; + int index; + + /* + * I'm not sure how I think this is to be handled - whether the lock is held + * over the interrupt - but it seems like it is a bad idea.... + */ + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); + brl1_send_chars( sc ); + done = (sc->sent == sc->send_len); + if( done ) { + sc->send_in_use = 0; +#if !defined(SYNC_CONSOLE_WRITE) + uart_disable_xmit_intr(sc); +#endif + } + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(sc->nasid); + /* Release the lock */ + L1SC_SEND_UNLOCK(sc, pl); + + return 0; +} +#endif /* SYNC_CONSOLE_WRITE */ /* internal function -- used by brl1_receive to read a character * from the uart and check whether errors occurred in the process. @@ -1046,40 +1173,33 @@ * error (parity error, bad header, bad CRC, etc.). */ -#define STATE_SET(l,s) ((l)->brl1_state = (s)) -#define STATE_GET(l) ((l)->brl1_state) +#define STATE_SET(l,s) ((l)->brl1_state = (s)) +#define STATE_GET(l) ((l)->brl1_state) #define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h)) #define LAST_HDR_GET(l) ((l)->brl1_last_hdr) -#define SEQSTAMP_INCR(l) -#define SEQSTAMP_GET(l) - #define VALID_HDR(c) \ ( SUBCH((c)) <= SC_CONS_SYSTEM \ ? PKT_TYPE((c)) == BRL1_REQUEST \ : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ PKT_TYPE((c)) == BRL1_EVENT ) ) -#define IS_TTY_PKT(l) \ - ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) +#define IS_TTY_PKT(l) ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) int -brl1_receive( l1sc_t *sc ) +brl1_receive( l1sc_t *sc, int mode ) { int result; /* value to be returned by brl1_receive */ int c; /* most-recently-read character */ int done; /* set done to break out of recv loop */ + unsigned long pl = 0, cpl = 0; sc_cq_t *q; /* pointer to queue we're working with */ result = BRL1_NO_MESSAGE; -#ifdef FORCE_CONSOLE_NASID - sc->nasid = 0; -#endif - if ( sc->uart == BRL1_LOCALUART ) - lock_console(sc->nasid); + L1SC_RECV_LOCK(sc, cpl); done = 0; while( !done ) @@ -1210,8 +1330,7 @@ * starting a new packet */ STATE_SET( sc, BRL1_FLAG ); - SEQSTAMP_INCR(sc); /* bump the packet sequence counter */ - + /* if the packet body has less than 2 characters, * it can't be a well-formed packet. Discard it. */ @@ -1258,7 +1377,7 @@ /* get the subchannel and lock it */ subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch ); + SUBCH_DATA_LOCK( subch, pl ); /* if this isn't a console packet, we need to record * a length byte @@ -1276,14 +1395,16 @@ */ atomic_inc(&(subch->packet_arrived)); callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); - if( callup ) { - if ( sc->uart == BRL1_LOCALUART ) - unlock_console(sc->nasid); - (*callup)( sc, SUBCH(LAST_HDR_GET(sc)) ); - if ( sc->uart == BRL1_LOCALUART ) - lock_console(sc->nasid); + if( callup && (mode == SERIAL_INTERRUPT_MODE) ) { + L1SC_RECV_UNLOCK( sc, cpl ); + L1_collectibles[L1C_RECEIVE_CALLUPS]++; + (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq, + sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id, + sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs, + sc, SUBCH(LAST_HDR_GET(sc)) ); + L1SC_RECV_LOCK( sc, cpl ); } continue; /* go back for more! */ } @@ -1351,9 +1472,8 @@ } /* end of switch( STATE_GET(sc) ) */ } /* end of while(!done) */ - - if ( sc->uart == BRL1_LOCALUART ) - unlock_console(sc->nasid); + + L1SC_RECV_UNLOCK( sc, cpl ); return result; } @@ -1370,13 +1490,10 @@ brl1_sch_t *subch; bzero( sc, sizeof( *sc ) ); -#ifdef FORCE_CONSOLE_NASID - nasid = (nasid_t)0; -#endif sc->nasid = nasid; sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALUART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALUART ? uart_putc : rtr_uart_putc); + sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); + sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); sc->sol = 1; subch = sc->subch; @@ -1403,9 +1520,8 @@ spin_lock_init( &(subch->data_lock) ); sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); subch->tx_notify = NULL; - if( sc->uart == BRL1_LOCALUART ) { - subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(nasid) ); + if( sc->uart == BRL1_LOCALHUB_UART ) { + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); ASSERT( subch->iqp ); cq_init( subch->iqp ); subch->rx_notify = NULL; @@ -1440,8 +1556,10 @@ /* initialize synchronization structures */ spin_lock_init( &(sc->subch_lock) ); + spin_lock_init( &(sc->send_lock) ); + spin_lock_init( &(sc->recv_lock) ); - if( sc->uart == BRL1_LOCALUART ) { + if( sc->uart == BRL1_LOCALHUB_UART ) { uart_init( sc, UART_BAUD_RATE ); } else { @@ -1461,93 +1579,574 @@ } } +/********************************************************************* + * These are interrupt-related functions used in the kernel to service + * the L1. + */ + +/* + * brl1_intrd is the function which is called on a console interrupt. + */ -/* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. These are external - * interfaces into the protocol driver. +#if defined(CONFIG_IA64_SGI_SN1) + +static void +brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff) +{ + u_char isr_reg; + l1sc_t *sc = get_elsc(); + int ret; + + L1_collectibles[L1C_INTERRUPTS]++; + isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); + + /* Save for callup args in console */ + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq; + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id; + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff; + +#if defined(SYNC_CONSOLE_WRITE) + while( isr_reg & ISR_RxRDY ) +#else + while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) +#endif + { + if( isr_reg & ISR_RxRDY ) { + L1_collectibles[L1C_OUR_R_INTERRUPTS]++; + ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE); + if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) + L1_collectibles[L1C_REC_STALLS] = ret; + } +#if !defined(SYNC_CONSOLE_WRITE) + if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) { + L1_collectibles[L1C_OUR_X_INTERRUPTS]++; + brl1_send_cont(sc); + } +#endif /* SYNC_CONSOLE_WRITE */ + isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); + } +} +#endif /* CONFIG_IA64_SGI_SN1 */ + + +/* + * Install a callback function for the system console subchannel + * to allow an upper layer to be notified when the send buffer + * has been emptied. + */ +static inline void +l1_tx_notif( brl1_notif_t func ) +{ + subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, + SC_CONS_SYSTEM, func ); +} + + +/* + * Install a callback function for the system console subchannel + * to allow an upper layer to be notified when a packet has been + * received. + */ +static inline void +l1_rx_notif( brl1_notif_t func ) +{ + subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, + SC_CONS_SYSTEM, func ); +} + + +/* brl1_intr is called directly from the uart interrupt; after it runs, the + * interrupt "daemon" xthread is signalled to continue. */ void -l1_control_out(int offset, int value) +brl1_intr( void ) { - nasid_t nasid = 0; //(get_elsc())->nasid; - WRITE_L1_UART_REG(nasid, offset, value); } +#define BRL1_INTERRUPT_LEVEL 65 /* linux request_irq() value */ + +/* Return the current interrupt level */ + +//#define CONSOLE_POLLING_ALSO + int -l1_control_in(int offset) +l1_get_intr_value( void ) { - nasid_t nasid = 0; //(get_elsc())->nasid; - return(READ_L1_UART_REG(nasid, offset)); +#if defined(USE_SAL_CONSOLE_IO) + return(0); +#else +#if defined(CONSOLE_POLLING_ALSO) + return(0); +#else + return(BRL1_INTERRUPT_LEVEL); +#endif /* CONSOLE_POLLING_ALSO */ +#endif /* USE_SAL_CONSOLE_IO */ } -#define PUTCHAR(ch) \ - { \ - while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ - (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ - WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ - } +/* Disconnect the callup functions - throw away interrupts */ -int -l1_serial_out( char *str, int len ) +void +l1_unconnect_intr(void) { - int sent = len; - char crc_char; - unsigned short crc = INIT_CRC; - nasid_t nasid = 0; //(get_elsc())->nasid; +#if !defined(USE_SAL_CONSOLE_IO) + /* UnRegister the upper-level callup functions */ + l1_rx_notif((brl1_notif_t)NULL); + l1_tx_notif((brl1_notif_t)NULL); + /* We do NOT unregister the interrupts */ +#endif /* !USE_SAL_CONSOLE_IO */ +} - lock_console(nasid); +/* Set up uart interrupt handling for this node's uart */ - PUTCHAR( BRL1_FLAG_CH ); - PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); - crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); +void +l1_connect_intr(void *rx_notify, void *tx_notify) +{ +#if defined(USE_SAL_CONSOLE_IO) +#if 0 + // Will need code here for sn2 - something like this + console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); + intr_connect_level(console_nodepda->node_first_cpu, + SGI_UART_VECTOR, INTPEND0_MAXMASK, + dummy_intr_func); + request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), + intr_func, SA_INTERRUPT | SA_SHIRQ, + "l1_protocol_driver", (void *)sc); +#endif +#else + l1sc_t *sc; + nasid_t nasid; +#if defined(CONFIG_IA64_SGI_SN1) + int tmp; +#endif + nodepda_t *console_nodepda; + int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); - while( len ) { + if ( L1_interrupts_connected ) { + /* Interrupts are connected, so just register the callups */ + l1_rx_notif((brl1_notif_t)rx_notify); + l1_tx_notif((brl1_notif_t)tx_notify); - if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { - PUTCHAR( BRL1_ESC_CH ); - PUTCHAR( (*str) ^ BRL1_XOR_CH ); + L1_collectibles[L1C_CONNECT_CALLS]++; + return; + } + else + L1_interrupts_connected = 1; + + nasid = get_master_nasid(); + console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid)); + sc = &console_nodepda->module->elsc; + sc->intr_cpu = console_nodepda->node_first_cpu; + +#if defined(CONFIG_IA64_SGI_SN1) + if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) { + L1_interrupts_connected = 0; /* FAILS !! */ } else { - PUTCHAR( *str ); + void synergy_intr_connect(int, int); + + synergy_intr_connect(UART_INTR, sc->intr_cpu); + L1_collectibles[L1C_R_IRQ]++; + tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc); + L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp; + if ( tmp ) { + L1_interrupts_connected = 0; /* FAILS !! */ + } + else { + /* Register the upper-level callup functions */ + l1_rx_notif((brl1_notif_t)rx_notify); + l1_tx_notif((brl1_notif_t)tx_notify); + + /* Set the uarts the way we like it */ + uart_enable_recv_intr( sc ); + uart_disable_xmit_intr( sc ); + } } - - crc = crc16_calc( crc, *str ); +#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* USE_SAL_CONSOLE_IO */ +} - str++; len--; - } - - crc ^= 0xffff; - crc_char = crc & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - crc_char = (crc >> 8) & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - PUTCHAR( BRL1_FLAG_CH ); - unlock_console(nasid); - return sent - len; +/* These are functions to use from serial_in/out when in protocol + * mode to send and receive uart control regs. These are external + * interfaces into the protocol driver. + */ + +void +l1_control_out(int offset, int value) +{ +#if defined(USE_SAL_CONSOLE_IO) + /* quietly ignore unless simulator */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + if ( master_node_bedrock_address != (u64)0 ) { + writeb(value, (unsigned long)master_node_bedrock_address + + (offset<< 3)); + } + return; + } +#else + nasid_t nasid = get_master_nasid(); + WRITE_L1_UART_REG(nasid, offset, value); +#endif } +/* Console input exported interface. Return a register value. */ + int -l1_serial_in(void) +l1_control_in_polled(int offset) { - static int l1_cons_getc( l1sc_t *sc ); + static int l1_control_in_local(int, int); - return(l1_cons_getc(get_elsc())); + return(l1_control_in_local(offset, SERIAL_POLLED_MODE)); } +int +l1_control_in(int offset) +{ + static int l1_control_in_local(int, int); -/********************************************************************* - * l1_cons functions - * - * These allow the L1 to act as the system console. They're intended + return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE)); +} + +static int +l1_control_in_local(int offset, int mode) +{ +#if defined(USE_SAL_CONSOLE_IO) + int sal_call_status = 0, input; + int ret = 0; + + if ( offset == REG_LSR ) { + ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ + sal_call_status = ia64_sn_console_check(&input); + if ( !sal_call_status && input ) { + /* input pending */ + ret |= LSR_RCA; + } + } + + /* If the sal call failed, do it the old-fashioned way */ + if ( sal_call_status ) { + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + ret = readb((unsigned long)master_node_bedrock_address + + (offset<< 3)); + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid; + int ret, input; + static int l1_poll(l1sc_t *, int); + + nasid = get_master_nasid(); + ret = READ_L1_UART_REG(nasid, offset); + + if ( offset == REG_LSR ) { + ret |= (LSR_XHRE | LSR_XSRE); /* can send anytime */ + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { + input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode); + if ( input ) { + ret |= LSR_RCA; + } + } + } + } +#if defined(USE_SAL_CONSOLE_IO) + } + } +#endif + return(ret); +} + +/* + * Console input exported interface. Return a character (if one is available) + */ + +int +l1_serial_in_polled(void) +{ + static int l1_serial_in_local(int mode); + + return(l1_serial_in_local(SERIAL_POLLED_MODE)); +} + +int +l1_serial_in(void) +{ + static int l1_serial_in_local(int mode); + + return(l1_serial_in_local(SERIAL_INTERRUPT_MODE)); +} + +static int +l1_serial_in_local(int mode) +{ +#if defined(USE_SAL_CONSOLE_IO) + int sal_call_status; + int ch; + + sal_call_status = ia64_sn_console_getc(&ch); + if ( !sal_call_status ) { + return(ch); + } + else { + /* If the sal called failed - do it the old-fashioned way */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid; + l1sc_t *sc; + int value; + static int l1_getc( l1sc_t *, int ); + static inline l1sc_t *early_sc_init(nasid_t); + + nasid = get_master_nasid(); + sc = early_sc_init(nasid); + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { + sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc; + } + } + value = l1_getc(sc, mode); + return(value); +#if defined(USE_SAL_CONSOLE_IO) + } + } +#endif +} + +/* Console output exported interface. Write message to the console. */ + +int +l1_serial_out( char *str, int len ) +{ +#if defined(USE_SAL_CONSOLE_IO) + int sal_call_status = 0; + int counter = len; + + /* Attempt to write things out thru the sal */ + while ( counter > 0 ) { + if ( (sal_call_status = ia64_sn_console_putc(*str)) ) { + break; + } + counter--; + str++; + } + if ( sal_call_status ) { + /* If the sal called failed - do it the old-fashioned way */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + if (!master_node_bedrock_address) + early_sn_setup(); + if ( master_node_bedrock_address != (u64)0 ) { +#ifdef FLAG_DIRECT_CONSOLE_WRITES + /* This is an easy way to pre-pend the output to know whether the output + * was done via sal or directly */ + writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); +#endif /* FLAG_DIRECT_CONSOLE_WRITES */ + while ( counter > 0 ) { + writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + counter--; + str++; + } + } + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid = get_master_nasid(); + int l1_write(l1sc_t *, char *, int, int); + + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) + return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len, +#if defined(SYNC_CONSOLE_WRITE) + 1 +#else + !L1_interrupts_connected +#endif + )); + } + return(early_l1_serial_out(nasid, str, len, NOT_LOCKED)); +#if defined(USE_SAL_CONSOLE_IO) + } + } + return((counter <= 0) ? 0 : (len - counter)); +#endif +} + + +/* + * These are the 'early' functions - when we need to do things before we have + * all the structs setup. + */ + + +static l1sc_t Early_console; /* fake l1sc_t */ +static int Early_console_inited = 0; + +static void +early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) +{ + int i; + brl1_sch_t *subch; + + bzero( sc, sizeof( *sc ) ); + sc->nasid = nasid; + sc->uart = uart; + sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); + sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); + sc->sol = 1; + subch = sc->subch; + + /* initialize L1 subchannels + */ + + /* assign processor TTY channels */ + for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } + + /* assign system TTY channel (first free subchannel after each + * processor's individual TTY channel has been assigned) + */ + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + if( sc->uart == BRL1_LOCALHUB_UART ) { + static sc_cq_t x_iqp; + + subch->iqp = &x_iqp; + ASSERT( subch->iqp ); + cq_init( subch->iqp ); + } + else { + /* we shouldn't be getting console input from remote UARTs */ + subch->iqp = &sc->garbage_q; + } + subch++; i++; + + /* "reserved" subchannels (0x05-0x0F); for now, throw away + * incoming packets + */ + for( ; i < 0x10; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } + + /* remaining subchannels are free */ + for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } +} + +static inline l1sc_t * +early_sc_init(nasid_t nasid) +{ + /* This is for early I/O */ + if ( Early_console_inited == 0 ) { + early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); + Early_console_inited = 1; + } + return(&Early_console); +} + +#define PUTCHAR(ch) \ + { \ + while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ + (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ + WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ + } + +static int +early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ) +{ + int ret, sent = 0; + char *msg = str; + static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); + + while ( sent < len ) { + ret = early_l1_send(nasid, msg, len - sent, lock_state); + sent += ret; + msg += ret; + } + return(len); +} + +static inline int +early_l1_send( nasid_t nasid, char *str, int len, int lock_state ) +{ + int sent; + char crc_char; + unsigned short crc = INIT_CRC; + + if( len > (BRL1_QSIZE - 1) ) + len = (BRL1_QSIZE - 1); + + sent = len; + if ( lock_state == NOT_LOCKED ) + lock_console(nasid); + + PUTCHAR( BRL1_FLAG_CH ); + PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); + crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); + + while( len ) { + + if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { + PUTCHAR( BRL1_ESC_CH ); + PUTCHAR( (*str) ^ BRL1_XOR_CH ); + } + else { + PUTCHAR( *str ); + } + + crc = crc16_calc( crc, *str ); + + str++; len--; + } + + crc ^= 0xffff; + crc_char = crc & 0xff; + if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { + crc_char ^= BRL1_XOR_CH; + PUTCHAR( BRL1_ESC_CH ); + } + PUTCHAR( crc_char ); + crc_char = (crc >> 8) & 0xff; + if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { + crc_char ^= BRL1_XOR_CH; + PUTCHAR( BRL1_ESC_CH ); + } + PUTCHAR( crc_char ); + PUTCHAR( BRL1_FLAG_CH ); + + if ( lock_state == NOT_LOCKED ) + unlock_console(nasid); + return sent; +} + +/********************************************************************* + * l1_cons functions + * + * These allow the L1 to act as the system console. They're intended * to abstract away most of the br/l1 internal details from the * _L1_cons_* functions (in the prom-- see "l1_console.c") and * l1_* functions (in the kernel-- see "sio_l1.c") that they support. @@ -1555,12 +2154,16 @@ */ static int -l1_cons_poll( l1sc_t *sc ) +l1_poll( l1sc_t *sc, int mode ) { + int ret; + /* in case this gets called before the l1sc_t structure for the module_t * struct for this node is initialized (i.e., if we're called with a * zero l1sc_t pointer)... */ + + if( !sc ) { return 0; } @@ -1569,7 +2172,9 @@ return 1; } - brl1_receive( sc ); + ret = brl1_receive( sc, mode ); + if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) + L1_collectibles[L1C_REC_STALLS] = ret; if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { return 1; @@ -1581,43 +2186,65 @@ /* pull a character off of the system console queue (if one is available) */ static int -l1_cons_getc( l1sc_t *sc ) +l1_getc( l1sc_t *sc, int mode ) { + unsigned long pl = 0; int c; brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); sc_cq_t *q = subch->iqp; - if( !l1_cons_poll( sc ) ) { + if( !l1_poll( sc, mode ) ) { return 0; } - SUBCH_DATA_LOCK( subch ); + SUBCH_DATA_LOCK( subch, pl ); if( cq_empty( q ) ) { atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); return 0; } cq_rem( q, c ); if( cq_empty( q ) ) atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); return c; } +/* + * Write a message to the L1 on the system console subchannel. + * + * Danger: don't use a non-zero value for the wait parameter unless you're + * someone important (like a kernel error message). + */ + +int +l1_write( l1sc_t *sc, char *msg, int len, int wait ) +{ + int sent = 0, ret = 0; + + if ( wait ) { + while ( sent < len ) { + ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); + sent += ret; + msg += ret; + } + ret = len; + } + else { + ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); + } + return(ret); +} /* initialize the system console subchannel */ void -l1_cons_init( l1sc_t *sc ) +l1_init(void) { - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - - SUBCH_DATA_LOCK( subch ); - atomic_set(&subch->packet_arrived, 0); - cq_init( subch->iqp ); - SUBCH_DATA_UNLOCK( subch ); + /* All we do now is remember that we have been called */ + L1_cons_is_inited = 1; } @@ -1637,16 +2264,18 @@ #define L1_DBG_PRF(x) #endif -/* sc_data_ready is called to signal threads that are blocked on - * l1 input. +/* + * sc_data_ready is called to signal threads that are blocked on l1 input. */ void -sc_data_ready( l1sc_t *sc, int ch ) +sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) { + unsigned long pl = 0; + brl1_sch_t *subch = &(sc->subch[ch]); - SUBCH_DATA_LOCK( subch ); + SUBCH_DATA_LOCK( subch, pl ); sv_signal( &(subch->arrive_sv) ); - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); } /* sc_open reserves a subchannel to send a request to the L1 (the @@ -1661,9 +2290,10 @@ * subchannel assignment. */ int ch; + unsigned long pl = 0; brl1_sch_t *subch; - SUBCH_LOCK( sc ); + SUBCH_LOCK( sc, pl ); /* Look for a free subchannel. Subchannels 0-15 are reserved * for other purposes. @@ -1676,12 +2306,12 @@ if( ch == BRL1_NUM_SUBCHANS ) { /* there were no subchannels available! */ - SUBCH_UNLOCK( sc ); + SUBCH_UNLOCK( sc, pl ); return SC_NSUBCH; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc ); + SUBCH_UNLOCK( sc, pl ); atomic_set(&subch->packet_arrived, 0); subch->target = target; @@ -1689,7 +2319,7 @@ sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; - subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(sc->nasid) ); ASSERT( subch->iqp ); cq_init( subch->iqp ); @@ -1703,29 +2333,31 @@ int sc_close( l1sc_t *sc, int ch ) { + unsigned long pl = 0; brl1_sch_t *subch; - SUBCH_LOCK( sc ); + SUBCH_LOCK( sc, pl ); subch = &(sc->subch[ch]); if( subch->use != BRL1_SUBCH_RSVD ) { /* we're trying to close a subchannel that's not open */ + SUBCH_UNLOCK( sc, pl ); return SC_NOPEN; } atomic_set(&subch->packet_arrived, 0); subch->use = BRL1_SUBCH_FREE; - SUBCH_DATA_LOCK( subch ); sv_broadcast( &(subch->arrive_sv) ); sv_destroy( &(subch->arrive_sv) ); - SUBCH_DATA_UNLOCK( subch ); spin_lock_destroy( &(subch->data_lock) ); ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); - kmem_free( subch->iqp, sizeof(sc_cq_t) ); + snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); subch->iqp = &sc->garbage_q; + subch->tx_notify = NULL; + subch->rx_notify = brl1_discard_packet; - SUBCH_UNLOCK( sc ); + SUBCH_UNLOCK( sc, pl ); return SC_SUCCESS; } @@ -2003,9 +2635,6 @@ return 0; } - - - /* sc_send takes as arguments a system controller struct, a * buffer which contains a Bedrock<->L1 "request" message, * the message length, and the subchannel (presumably obtained @@ -2033,11 +2662,10 @@ /* Verify that this is an open subchannel */ - if( sc->subch[ch].use == BRL1_SUBCH_FREE ) - { + if( sc->subch[ch].use == BRL1_SUBCH_FREE ) { return SC_NOPEN; } - + type_and_subch = (BRL1_REQUEST | ((u_char)ch)); result = brl1_send( sc, msg, len, type_and_subch, wait ); @@ -2058,8 +2686,6 @@ return( result ); } - - /* subch_pull_msg pulls a message off the receive queue for subch * and places it the buffer pointed to by msg. This routine should only * be called when the caller already knows a message is available on the @@ -2115,6 +2741,7 @@ sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { int is_msg = 0; + unsigned long pl = 0; brl1_sch_t *subch = &(sc->subch[ch]); rtc_time_t exp_time = rtc_time() + block; @@ -2127,7 +2754,7 @@ /* kick the next lower layer and see if it pulls anything in */ - brl1_receive( sc ); + brl1_receive( sc, SERIAL_POLLED_MODE ); is_msg = atomic_read(&subch->packet_arrived); } while( block && !is_msg && (rtc_time() < exp_time) ); @@ -2137,9 +2764,9 @@ return( SC_NMSG ); } - SUBCH_DATA_LOCK( subch ); + SUBCH_DATA_LOCK( subch, pl ); subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); return( SC_SUCCESS ); } @@ -2156,10 +2783,11 @@ sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) { int is_msg = 0; + unsigned long pl = 0; brl1_sch_t *subch = &(sc->subch[ch]); do { - SUBCH_DATA_LOCK(subch); + SUBCH_DATA_LOCK(subch, pl); is_msg = atomic_read(&subch->packet_arrived); if( !is_msg && block ) { /* wake me when you've got something */ @@ -2178,12 +2806,12 @@ if( !is_msg ) { /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); return( SC_NMSG ); } subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch ); + SUBCH_DATA_UNLOCK( subch, pl ); return( SC_SUCCESS ); } @@ -2206,16 +2834,13 @@ * rewriting of the L1 command interface anyway.) */ #define __RETRIES 50 -#define __WAIT_SEND ( sc->uart != BRL1_LOCALUART ) +#define __WAIT_SEND 1 // ( sc->uart != BRL1_LOCALHUB_UART ) #define __WAIT_RECV 10000000 int sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) { -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else int result; int retries; @@ -2237,16 +2862,12 @@ } /* block on sc_recv_* */ -#ifdef LATER - if( sc->uart == BRL1_LOCALUART ) { + if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) { return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); } - else -#endif /* LATER */ - { + else { return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } /* sc_command_kern is a knuckle-dragging, no-patience version of sc_command @@ -2254,12 +2875,10 @@ * delayed until the send buffer clears. sc_command should be used instead * under most circumstances. */ + int sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) { -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else int result; if ( IS_RUNNING_ON_SIMULATOR() ) @@ -2270,7 +2889,6 @@ } return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ } @@ -2282,6 +2900,7 @@ * Returns 1 if input is available on the given queue, * 0 otherwise. */ + int sc_poll( l1sc_t *sc, int ch ) { @@ -2290,7 +2909,7 @@ if( atomic_read(&subch->packet_arrived) ) return 1; - brl1_receive( sc ); + brl1_receive( sc, SERIAL_POLLED_MODE ); if( atomic_read(&subch->packet_arrived) ) return 1; @@ -2298,8 +2917,8 @@ return 0; } -/* for now, sc_init just calls brl1_init - */ +/* for now, sc_init just calls brl1_init */ + void sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) { @@ -2311,7 +2930,7 @@ * network's environmental monitor tasks. */ -#ifdef LINUX_KERNEL_THREADS +#if defined(LINUX_KERNEL_THREADS) static void sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) @@ -2366,14 +2985,12 @@ i++ ); } } -#endif /* LINUX_KERNEL_THREADS */ /* sc_event waits for events to arrive from the system controller, and * prints appropriate messages to the syslog. */ -#ifdef LINUX_KERNEL_THREADS static void sc_event( l1sc_t *sc, int ch ) { @@ -2394,7 +3011,7 @@ */ result = sc_recv_intr( sc, ch, event, &event_len, 1 ); if( result != SC_SUCCESS ) { - PRINT_WARNING("Error receiving sysctl event on nasid %d\n", + printk(KERN_WARNING "Error receiving sysctl event on nasid %d\n", sc->nasid ); } else { @@ -2438,53 +3055,50 @@ } } -#endif /* LINUX_KERNEL_THREADS */ /* sc_listen sets up a service thread to listen for incoming events. */ + void sc_listen( l1sc_t *sc ) { int result; + unsigned long pl = 0; brl1_sch_t *subch; char msg[BRL1_QSIZE]; int len; /* length of message being sent */ int ch; /* system controller subchannel used */ -#ifdef LINUX_KERNEL_THREADS extern int msc_shutdown_pri; -#endif /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc ); + SUBCH_LOCK( sc, pl ); subch = &(sc->subch[BRL1_EVENT_SUBCH]); if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc ); - PRINT_WARNING("sysctl event subchannel in use! " + SUBCH_UNLOCK( sc, pl ); + printk(KERN_WARNING "sysctl event subchannel in use! " "Not monitoring sysctl events.\n" ); return; } subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc ); + SUBCH_UNLOCK( sc, pl ); atomic_set(&subch->packet_arrived, 0); - subch->target = BRL1_LOCALUART; + subch->target = BRL1_LOCALHUB_UART; spin_lock_init( &(subch->data_lock) ); sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); subch->tx_notify = NULL; subch->rx_notify = sc_data_ready; - subch->iqp = kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(sc->nasid) ); ASSERT( subch->iqp ); cq_init( subch->iqp ); -#ifdef LINUX_KERNEL_THREADS /* set up a thread to listen for events */ sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri, KT_PS, (st_func_t *) sc_event, (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 ); -#endif /* signal the L1 to begin sending events */ bzero( msg, BRL1_QSIZE ); @@ -2522,276 +3136,8 @@ err_return: /* there was a problem; complain */ - PRINT_WARNING("failed to set sysctl event-monitoring subchannel. " + printk(KERN_WARNING "failed to set sysctl event-monitoring subchannel. " "Sysctl events will not be monitored.\n" ); } - -/********************************************************************* - * elscuart functions. These provide a uart-like interface to the - * bedrock/l1 protocol console channels. They are similar in form - * and intent to the elscuart_* functions defined for SN0 in elsc.c. - * - */ - -int _elscuart_flush( l1sc_t *sc ); - -/* Leave room in queue for CR/LF */ -#define ELSCUART_LINE_MAX (BRL1_QSIZE - 2) - - -/* - * _elscuart_putc provides an entry point to the L1 interface driver; - * writes a single character to the output queue. Flushes at the - * end of each line, and translates newlines into CR/LF. - * - * The kernel should generally use l1_cons_write instead, since it assumes - * buffering, translation, prefixing, etc. are done at a higher - * level. - * - */ -int -_elscuart_putc( l1sc_t *sc, int c ) -{ - sc_cq_t *q; - - q = &(sc->oq[ MAP_OQ(L1_ELSCUART_SUBCH(get_myid())) ]); - - if( c != '\n' && c != '\r' && cq_used(q) >= ELSCUART_LINE_MAX ) { - cq_add( q, '\r' ); - cq_add( q, '\n' ); - _elscuart_flush( sc ); - sc->sol = 1; - } - - if( sc->sol && c != '\r' ) { - char prefix[16], *s; - - if( cq_room( q ) < 8 && _elscuart_flush(sc) < 0 ) - { - return -1; - } - - if( sc->verbose ) - { -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf( prefix, - "%c %d%d%d %M:", - 'A' + get_myid(), - sc->nasid / 100, - (sc->nasid / 10) % 10, - sc->nasid / 10, - sc->modid ); -#else - sprintf( prefix, - "%c %d%d%d 0x%x:", - 'A' + get_myid(), - sc->nasid / 100, - (sc->nasid / 10) % 10, - sc->nasid / 10, - sc->modid ); -#endif - - for( s = prefix; *s; s++ ) - cq_add( q, *s ); - } - sc->sol = 0; - - } - - if( cq_room( q ) < 2 && _elscuart_flush(sc) < 0 ) - { - return -1; - } - - if( c == '\n' ) { - cq_add( q, '\r' ); - sc->sol = 1; - } - - cq_add( q, (u_char) c ); - - if( c == '\n' ) { - /* flush buffered line */ - if( _elscuart_flush( sc ) < 0 ) - { - return -1; - } - } - - if( c== '\r' ) - { - sc->sol = 1; - } - - return 0; -} - - -/* - * _elscuart_getc reads a character from the input queue. This - * routine blocks. - */ -int -_elscuart_getc( l1sc_t *sc ) -{ - int r; - - while( (r = _elscuart_poll( sc )) == 0 ); - - if( r < 0 ) { - /* some error occurred */ - return r; - } - - return _elscuart_readc( sc ); -} - - - -/* - * _elscuart_poll returns 1 if characters are ready for the - * calling processor, 0 if they are not - */ -int -_elscuart_poll( l1sc_t *sc ) -{ - int result; - - if( sc->cons_listen ) { - result = l1_cons_poll( sc ); - if( result ) - return result; - } - - return sc_poll( sc, L1_ELSCUART_SUBCH(get_myid()) ); -} - - - -/* _elscuart_readc is to be used only when _elscuart_poll has - * indicated that a character is waiting. Pulls a character - * of this processor's console queue and returns it. - * - */ -int -_elscuart_readc( l1sc_t *sc ) -{ - int c; - sc_cq_t *q; - brl1_sch_t *subch; - - if( sc->cons_listen ) { - subch = &(sc->subch[ SC_CONS_SYSTEM ]); - q = subch->iqp; - - SUBCH_DATA_LOCK( subch ); - if( !cq_empty( q ) ) { - cq_rem( q, c ); - if( cq_empty( q ) ) { - atomic_set(&subch->packet_arrived, 0); - } - SUBCH_DATA_UNLOCK( subch ); - return c; - } - SUBCH_DATA_UNLOCK( subch ); - } - - subch = &(sc->subch[ L1_ELSCUART_SUBCH(get_myid()) ]); - q = subch->iqp; - - SUBCH_DATA_LOCK( subch ); - if( cq_empty( q ) ) { - SUBCH_DATA_UNLOCK( subch ); - return -1; - } - - cq_rem( q, c ); - if( cq_empty ( q ) ) { - atomic_set(&subch->packet_arrived, 0); - } - SUBCH_DATA_UNLOCK( subch ); - - return c; -} - - -/* - * _elscuart_flush flushes queued output to the L1. - * This routine blocks until the queue is flushed. - */ -int -_elscuart_flush( l1sc_t *sc ) -{ - int r, n; - char buf[BRL1_QSIZE]; - sc_cq_t *q = &(sc->oq[ MAP_OQ(L1_ELSCUART_SUBCH(get_myid())) ]); - - while( (n = cq_used(q)) ) { - - /* buffer queue contents */ - r = BRL1_QSIZE - q->opos; - - if( n > r ) { - BCOPY( q->buf + q->opos, buf, r ); - BCOPY( q->buf, buf + r, n - r ); - } else { - BCOPY( q->buf + q->opos, buf, n ); - } - - /* attempt to send buffer contents */ - r = brl1_send( sc, buf, cq_used( q ), - (BRL1_EVENT | L1_ELSCUART_SUBCH(get_myid())), 1 ); - - /* if no error, dequeue the sent characters; otherwise, - * return the error - */ - if( r >= SC_SUCCESS ) { - q->opos = (q->opos + r) % BRL1_QSIZE; - } - else { - return r; - } - } - - return 0; -} - - - -/* _elscuart_probe returns non-zero if the L1 (and - * consequently the elscuart) can be accessed - */ -int -_elscuart_probe( l1sc_t *sc ) -{ -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return 0; -#else - char ver[BRL1_QSIZE]; - extern int elsc_version( l1sc_t *, char * ); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return 0; - return( elsc_version(sc, ver) >= 0 ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - - -/* _elscuart_init zeroes out the l1sc_t console - * queues for this processor's console subchannel. - */ -void -_elscuart_init( l1sc_t *sc ) -{ - brl1_sch_t *subch = &sc->subch[L1_ELSCUART_SUBCH(get_myid())]; - - SUBCH_DATA_LOCK(subch); - - atomic_set(&subch->packet_arrived, 0); - cq_init( subch->iqp ); - cq_init( &sc->oq[MAP_OQ(L1_ELSCUART_SUBCH(get_myid()))] ); - - SUBCH_DATA_UNLOCK(subch); -} +#endif /* LINUX_KERNEL_THREADS */ diff -urN linux-2.4.18/arch/ia64/sn/io/l1_command.c linux-2.4.19-pre5/arch/ia64/sn/io/l1_command.c --- linux-2.4.18/arch/ia64/sn/io/l1_command.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/l1_command.c Sat Mar 30 22:55:26 2002 @@ -4,20 +4,20 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. + * All rights reserved. */ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -27,7 +27,6 @@ #define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ #define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ -#define LOCAL_HUB LOCAL_HUB_ADDR #define LD(x) (*(volatile uint64_t *)(x)) #define SD(x, v) (LD(x) = (uint64_t) (v)) @@ -75,7 +74,7 @@ void elsc_init(elsc_t *e, nasid_t nasid) { - sc_init((l1sc_t *)e, nasid, BRL1_LOCALUART); + sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART); } @@ -1376,85 +1375,4 @@ sprintf( result, "%d.%d.%d", major, minor, bugfix ); return 0; -} - - - -/* elscuart routines - * - * Most of the elscuart functionality is implemented in l1.c. The following - * is directly "recycled" from elsc.c. - */ - - -/* - * _elscuart_puts - */ - -int _elscuart_puts(elsc_t *e, char *s) -{ - int c; - - if (s == 0) - s = ""; - - while ((c = LBYTE(s)) != 0) { - if (_elscuart_putc(e, c) < 0) - return -1; - s++; - } - - return 0; -} - - -/* - * elscuart wrapper routines - * - * The following routines are similar to their counterparts in l1.c, - * except instead of taking an elsc_t pointer directly, they call - * a global routine "get_elsc" to obtain the pointer. - * This is useful when the elsc is employed for stdio. - */ - -int elscuart_probe(void) -{ - return _elscuart_probe(get_elsc()); -} - -void elscuart_init(void *init_data) -{ - _elscuart_init(get_elsc()); - /* dummy variable included for driver compatability */ - init_data = init_data; -} - -int elscuart_poll(void) -{ - return _elscuart_poll(get_elsc()); -} - -int elscuart_readc(void) -{ - return _elscuart_readc(get_elsc()); -} - -int elscuart_getc(void) -{ - return _elscuart_getc(get_elsc()); -} - -int elscuart_puts(char *s) -{ - return _elscuart_puts(get_elsc(), s); -} - -int elscuart_putc(int c) -{ - return _elscuart_putc(get_elsc(), c); -} - -int elscuart_flush(void) -{ - return _elscuart_flush(get_elsc()); } diff -urN linux-2.4.18/arch/ia64/sn/io/labelcl.c linux-2.4.19-pre5/arch/ia64/sn/io/labelcl.c --- linux-2.4.18/arch/ia64/sn/io/labelcl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/labelcl.c Sat Mar 30 22:55:26 2002 @@ -1,21 +1,10 @@ /* labelcl - SGI's Hwgraph Compatibility Layer. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Colin Ngam may be reached by email at cngam@sgi.com - + * + * 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) 2001 Silicon Graphics, Inc. All rights reserved. */ #include @@ -286,7 +275,7 @@ if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); - printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); + printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, (void *)de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ diff -urN linux-2.4.18/arch/ia64/sn/io/mem_refcnt.c linux-2.4.19-pre5/arch/ia64/sn/io/mem_refcnt.c --- linux-2.4.18/arch/ia64/sn/io/mem_refcnt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/mem_refcnt.c Thu Jan 1 01:00:00 1970 @@ -1,222 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// From numa_hw.h - -#define MIGR_COUNTER_MAX_GET(nodeid) \ - (NODEPDA_MCD((nodeid))->migr_system_kparms.migr_threshold_reference) -/* - * Get the Absolute Theshold - */ -#define MIGR_THRESHOLD_ABS_GET(nodeid) ( \ - MD_MIG_VALUE_THRESH_GET(COMPACT_TO_NASID_NODEID(nodeid))) -/* - * Get the current Differential Threshold - */ -#define MIGR_THRESHOLD_DIFF_GET(nodeid) \ - (NODEPDA_MCD(nodeid)->migr_as_kparms.migr_base_threshold) - -#define NUM_OF_HW_PAGES_PER_SW_PAGE() (NBPP / MD_PAGE_SIZE) - -// #include "migr_control.h" - -int -mem_refcnt_attach(devfs_handle_t hub) -{ - devfs_handle_t refcnt_dev; - - hwgraph_char_device_add(hub, - "refcnt", - "hubspc_", - &refcnt_dev); - device_info_set(refcnt_dev, (void*)(ulong)HUBSPC_REFCOUNTERS); - - return (0); -} - - -/*ARGSUSED*/ -int -mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) -{ - cnodeid_t node; - - ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(*devp) == HUBSPC_REFCOUNTERS ); - - node = master_node_get(*devp); - - ASSERT( (node >= 0) && (node < numnodes) ); - - if (NODEPDA(node)->migr_refcnt_counterbuffer == NULL) { - return (ENODEV); - } - - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != (size_t)0 ); - - return (0); -} - -/*ARGSUSED*/ -int -mem_refcnt_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED*/ -int -mem_refcnt_mmap(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - cnodeid_t node; - int errcode; - char* buffer; - size_t blen; - - ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(dev) == HUBSPC_REFCOUNTERS ); - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - /* - * XXXX deal with prot's somewhere around here.... - */ - - buffer = NODEPDA(node)->migr_refcnt_counterbuffer; - blen = NODEPDA(node)->migr_refcnt_cbsize; - - /* - * Force offset to be a multiple of sizeof(refcnt_t) - * We round up. - */ - - off = (((off - 1)/sizeof(refcnt_t)) + 1) * sizeof(refcnt_t); - - if ( ((buffer + blen) - (buffer + off + len)) < 0 ) { - return (EPERM); - } - - errcode = v_mapphys(vt, - buffer + off, - len); - - return errcode; -} - -/*ARGSUSED*/ -int -mem_refcnt_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* ARGSUSED */ -int -mem_refcnt_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int mode, - cred_t *cred_p, - int *rvalp) -{ - cnodeid_t node; - int errcode; - extern int numnodes; - - ASSERT( (hubspc_subdevice_t)(ulong)device_info_get(dev) == HUBSPC_REFCOUNTERS ); - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - errcode = 0; - - switch (cmd) { - case RCB_INFO_GET: - { - rcb_info_t rcb; - - rcb.rcb_len = NODEPDA(node)->migr_refcnt_cbsize; - - rcb.rcb_sw_sets = NODEPDA(node)->migr_refcnt_numsets; - rcb.rcb_sw_counters_per_set = numnodes; - rcb.rcb_sw_counter_size = sizeof(refcnt_t); - - rcb.rcb_base_pages = NODEPDA(node)->migr_refcnt_numsets / - NUM_OF_HW_PAGES_PER_SW_PAGE(); - rcb.rcb_base_page_size = NBPP; - rcb.rcb_base_paddr = ctob(slot_getbasepfn(node, 0)); - - rcb.rcb_cnodeid = node; - rcb.rcb_granularity = MD_PAGE_SIZE; -#ifdef LATER - rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); - rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); -#endif - rcb.rcb_abs_threshold = MIGR_THRESHOLD_ABS_GET(node); - rcb.rcb_num_slots = node_getnumslots(node); - - if (COPYOUT(&rcb, arg, sizeof(rcb_info_t))) { - errcode = EFAULT; - } - - break; - } - case RCB_SLOT_GET: - { - rcb_slot_t slot[MAX_MEM_SLOTS]; - int s; - int nslots; - - nslots = node_getnumslots(node); - ASSERT(nslots <= MAX_MEM_SLOTS); - for (s = 0; s < nslots; s++) { - slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); -#ifdef LATER - slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); -#else - slot[s].size = (uint64_t)1; -#endif - } - if (COPYOUT(&slot[0], arg, nslots * sizeof(rcb_slot_t))) { - errcode = EFAULT; - } - - *rvalp = nslots; - break; - } - - default: - errcode = EINVAL; - break; - - } - - return errcode; -} diff -urN linux-2.4.18/arch/ia64/sn/io/ml_SN_init.c linux-2.4.19-pre5/arch/ia64/sn/io/ml_SN_init.c --- linux-2.4.18/arch/ia64/sn/io/ml_SN_init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ml_SN_init.c Sat Mar 30 22:55:26 2002 @@ -4,37 +4,30 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include +#include #include #include #include #include -#include #include #include #include -#include - - -#if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include -#include -#include -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ - +#include extern int numcpus; extern char arg_maxnodes[]; extern cpuid_t master_procid; -extern void * kmem_alloc_node(register size_t, register int , cnodeid_t); +#if defined(CONFIG_IA64_SGI_SN1) extern synergy_da_t *Synergy_da_indr[]; +#endif extern int hasmetarouter; @@ -45,18 +38,8 @@ extern xwidgetnum_t hub_widget_id(nasid_t); -static int fine_mode = 0; - -static cnodemask_t hub_init_mask; /* Mask of cpu in a node doing init */ -static volatile cnodemask_t hub_init_done_mask; - /* Node mask where we wait for - * per hub initialization - */ -spinlock_t hub_mask_lock; /* Lock for hub_init_mask above. */ - extern int valid_icache_reasons; /* Reasons to flush the icache */ extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern int numnodes; extern u_char miniroot; extern volatile int need_utlbmiss_patch; extern void iograph_early_init(void); @@ -83,20 +66,6 @@ */ master_nasid = get_nasid(); set_master_bridge_base(); - FIXME("mlreset: Enable when we support ioc3 .."); -#ifdef LATER - if (get_console_nasid() == master_nasid) - /* Set up the IOC3 */ - ioc3_mlreset((ioc3_cfg_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->config_base, - (ioc3_mem_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base); - - /* - * Initialize Master nvram base. - */ - nvram_baseinit(); - - fine_mode = is_fine_dirmode(); -#endif /* LATER */ /* We're the master processor */ master_procid = smp_processor_id(); @@ -108,75 +77,12 @@ */ ASSERT_ALWAYS(master_nasid == get_nasid()); -#ifdef LATER - - /* - * Activate when calias is implemented. - */ - /* Set all nodes' calias sizes to 8k */ - for (i = 0; i < maxnodes; i++) { - nasid_t nasid; - int sn; - - nasid = COMPACT_TO_NASID_NODEID(i); - - /* - * Always have node 0 in the region mask, otherwise CALIAS accesses - * get exceptions since the hub thinks it is a node 0 address. - */ - for (sn=0; snpdinfo = (void *)hubinfo; hubinfo->h_nodepda = npda; hubinfo->h_cnodeid = node; @@ -230,92 +119,37 @@ hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); npda->xbow_peer = INVALID_NASID; - /* Initialize the linked list of + + /* + * Initialize the linked list of * router info pointers to the dependent routers */ npda->npda_rip_first = NULL; - /* npda_rip_last always points to the place + + /* + * npda_rip_last always points to the place * where the next element is to be inserted * into the list */ npda->npda_rip_last = &npda->npda_rip_first; - npda->dependent_routers = 0; npda->module_id = INVALID_MODULE; +#ifdef CONFIG_IA64_SGI_SN1 /* - * Initialize the subnodePDA. - */ + * Initialize the interrupts. + * On sn2, this is done at pci init time, + * because sn2 needs the cpus checked in + * when it initializes interrupts. This is + * so we don't see all the nodes as headless. + */ for (sn=0; snprof_count = 0; - SNPDA(npda,sn)->next_prof_timeout = 0; intr_init_vecblk(npda, node, sn); } +#endif /* CONFIG_IA64_SGI_SN1 */ - npda->vector_unit_busy = 0; - - spin_lock_init(&npda->vector_lock); mutex_init_locked(&npda->xbow_sema); /* init it locked? */ - spin_lock_init(&npda->fprom_lock); - spin_lock_init(&npda->node_utlbswitchlock); - npda->ni_error_print = 0; #ifdef LATER - if (need_utlbmiss_patch) { - npda->node_need_utlbmiss_patch = 1; - npda->node_utlbmiss_patched = 1; - } -#endif - - /* - * Clear out the nasid mask. - */ - for (i = 0; i < NASID_MASK_BYTES; i++) - npda->nasid_mask[i] = 0; - - for (i = 0; i < numnodes; i++) { - nasid_t nasid = COMPACT_TO_NASID_NODEID(i); - - /* Set my mask bit */ - npda->nasid_mask[nasid / 8] |= (1 << nasid % 8); - } - -#ifdef LATER - npda->node_first_cpu = get_cnode_cpu(node); -#endif - - if (npda->node_first_cpu != CPU_NONE) { - /* - * Count number of cpus only if first CPU is valid. - */ - numcpus_p = &npda->node_num_cpus; - *numcpus_p = 0; - for (i = npda->node_first_cpu; i < MAXCPUS; i++) { - if (CPUID_TO_COMPACT_NODEID(i) != node) - break; - else - (*numcpus_p)++; - } - } else { - npda->node_num_cpus = 0; - } - - /* Allocate memory for the dump stack on each node - * This is useful during nmi handling since we - * may not be guaranteed shared memory at that time - * which precludes depending on a global dump stack - */ -#ifdef LATER - npda->dump_stack = (uint64_t *)kmem_zalloc_node(DUMP_STACK_SIZE,VM_NOSLEEP, - node); - ASSERT_ALWAYS(npda->dump_stack); - ASSERT(npda->dump_stack); -#endif - /* Initialize the counter which prevents - * both the cpus on a node to proceed with nmi - * handling. - */ -#ifdef LATER - npda->dump_count = 0; /* Setup the (module,slot) --> nic mapping for all the routers * in the system. This is useful during error handling when @@ -325,17 +159,9 @@ /* Allocate memory for the per-node router traversal queue */ router_queue_init(npda,node); - npda->sbe_info = kmem_zalloc_node_hint(sizeof (sbe_info_t), 0, node); + npda->sbe_info = alloc_bootmem_node(NODE_DATA(node), sizeof (sbe_info_t)); ASSERT(npda->sbe_info); -#ifdef CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC - /* - * Initialize bte info pointers to NULL - */ - for (i = 0; i < BTES_PER_NODE; i++) { - npda->node_bte_info[i] = (bteinfo_t *)NULL; - } -#endif #endif /* LATER */ } @@ -345,260 +171,44 @@ * Must be done _after_ init_platform_nodepda(). * If we need a lock here, something else is wrong! */ -// void init_platform_pda(pda_t *ppda, cpuid_t cpu) void init_platform_pda(cpuid_t cpu) { +#if defined(CONFIG_IA64_SGI_SN1) hub_intmasks_t *intmasks; -#ifdef LATER - cpuinfo_t cpuinfo; -#endif - int i; + int i, subnode; cnodeid_t cnode; synergy_da_t *sda; int which_synergy; -#ifdef LATER - /* Allocate per-cpu platform-dependent data */ - cpuinfo = (cpuinfo_t)kmem_alloc_node(sizeof(struct cpuinfo_s), GFP_ATOMIC, cputocnode(cpu)); - ASSERT_ALWAYS(cpuinfo); - ppda->pdinfo = (void *)cpuinfo; - cpuinfo->ci_cpupda = ppda; - cpuinfo->ci_cpuid = cpu; -#endif cnode = cpuid_to_cnodeid(cpu); which_synergy = cpuid_to_synergy(cpu); + sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - // intmasks = &ppda->p_intmasks; intmasks = &sda->s_intmasks; -#ifdef LATER - ASSERT_ALWAYS(&ppda->p_nodepda); -#endif - /* Clear INT_PEND0 masks. */ for (i = 0; i < N_INTPEND0_MASKS; i++) intmasks->intpend0_masks[i] = 0; /* Set up pointer to the vector block in the nodepda. */ /* (Cant use SUBNODEPDA - not working yet) */ - intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; + subnode = cpuid_to_subnode(cpu); + intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; + intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; + if (intmasks->dispatch0 != &SUBNODEPDA(cnode, subnode)->intr_dispatch0 || + intmasks->dispatch1 != &SUBNODEPDA(cnode, subnode)->intr_dispatch1) + panic("xxx"); + intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0; + intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1; /* Clear INT_PEND1 masks. */ for (i = 0; i < N_INTPEND1_MASKS; i++) intmasks->intpend1_masks[i] = 0; - - -#ifdef LATER - /* Don't read the routers unless we're the master. */ - ppda->p_routertick = 0; -#endif - +#endif /* CONFIG_IA64_SGI_SN1 */ } -#if (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && !defined(BRINGUP) /* protect low mem for IP35/7 */ -#error "need protect_hub_calias, protect_nmi_handler_data" -#endif - -#ifdef LATER -/* - * For now, just protect the first page (exception handlers). We - * may want to protect more stuff later. - */ void -protect_hub_calias(nasid_t nasid) -{ - paddr_t pa = NODE_OFFSET(nasid) + 0; /* page 0 on node nasid */ - int i; - - for (i = 0; i < MAX_REGIONS; i++) { - if (i == nasid_to_region(nasid)) - continue; - } -} - -/* - * Protect the page of low memory used to communicate with the NMI handler. - */ -void -protect_nmi_handler_data(nasid_t nasid, int slice) -{ - paddr_t pa = NODE_OFFSET(nasid) + NMI_OFFSET(nasid, slice); - int i; - - for (i = 0; i < MAX_REGIONS; i++) { - if (i == nasid_to_region(nasid)) - continue; - } -} -#endif /* LATER */ - - -#ifdef LATER -/* - * Protect areas of memory that we access uncached by marking them as - * poisoned so the T5 can't read them speculatively and erroneously - * mark them dirty in its cache only to write them back with old data - * later. - */ -static void -protect_low_memory(nasid_t nasid) -{ - /* Protect low memory directory */ - poison_state_alter_range(KLDIR_ADDR(nasid), KLDIR_SIZE, 1); - - /* Protect klconfig area */ - poison_state_alter_range(KLCONFIG_ADDR(nasid), KLCONFIG_SIZE(nasid), 1); - - /* Protect the PI error spool area. */ - poison_state_alter_range(PI_ERROR_ADDR(nasid), PI_ERROR_SIZE(nasid), 1); - - /* Protect CPU A's cache error eframe area. */ - poison_state_alter_range(TO_NODE_UNCAC(nasid, CACHE_ERR_EFRAME), - CACHE_ERR_AREA_SIZE, 1); - - /* Protect CPU B's area */ - poison_state_alter_range(TO_NODE_UNCAC(nasid, CACHE_ERR_EFRAME) - ^ UALIAS_FLIP_BIT, - CACHE_ERR_AREA_SIZE, 1); -#error "SN1 not handled correctly" -} -#endif /* LATER */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -void -per_hub_init(cnodeid_t cnode) -{ - uint64_t done; - nasid_t nasid; - nodepda_t *npdap; -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */ - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; -#endif -#ifdef LATER - int i; -#endif - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - /* Grab the hub_mask lock. */ - spin_lock(&hub_mask_lock); - - /* Test our bit. */ - if (!(done = CNODEMASK_TSTB(hub_init_mask, cnode))) { - - /* Turn our bit on in the mask. */ - CNODEMASK_SETB(hub_init_mask, cnode); - } - -#if defined(SN0_HWDEBUG) - hub_config_setup(); -#endif - /* Release the hub_mask lock. */ - spin_unlock(&hub_mask_lock); - - /* - * Do the actual initialization if it hasn't been done yet. - * We don't need to hold a lock for this work. - */ - if (!done) { - npdap = NODEPDA(cnode); - -#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) - /* initialize per-node synergy perf instrumentation */ - npdap->synergy_perf_enabled = 0; /* off by default */ - npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; - npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; - npdap->synergy_inactive_intervals = 0; - npdap->synergy_active_intervals = 0; - npdap->synergy_perf_data = NULL; - npdap->synergy_perf_first = NULL; -#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ - - npdap->hub_chip_rev = get_hub_chiprev(nasid); - -#ifdef LATER - for (i = 0; i < CPUS_PER_NODE; i++) { - cpu = cnode_slice_to_cpuid(cnode, i); - if (!cpu_enabled(cpu)) - SET_CPU_LEDS(nasid, i, 0xf); - } -#endif /* LATER */ - -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */ - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - -#endif /* SN0_HWDEBUG */ - - - - /* Reserve all of the hardwired interrupt levels. */ - intr_reserve_hardwired(cnode); - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); - -#ifdef LATER - /* Set up correctable memory/directory ECC error interrupt. */ - install_eccintr(cnode); - - /* Protect our exception vectors from accidental corruption. */ - protect_hub_calias(nasid); - - /* Enable RT clock interrupts */ - hub_rtc_init(cnode); - hub_migrintr_init(cnode); /* Enable migration interrupt */ -#endif /* LATER */ - - spin_lock(&hub_mask_lock); - CNODEMASK_SETB(hub_init_done_mask, cnode); - spin_unlock(&hub_mask_lock); - - } else { - /* - * Wait for the other CPU to complete the initialization. - */ - while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) { - /* - * On SNIA64 we should never get here .. - */ - printk("WARNING: per_hub_init: Should NEVER get here!\n"); - /* LOOP */ - ; - } - } -} - -extern void update_node_information(cnodeid_t cnodeid) { nodepda_t *npda = NODEPDA(cnodeid); @@ -623,22 +233,3 @@ npda_rip = npda_rip->router_next; } } - -hubreg_t -get_region(cnodeid_t cnode) -{ - if (fine_mode) - return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT; - else - return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT; -} - -hubreg_t -nasid_to_region(nasid_t nasid) -{ - if (fine_mode) - return nasid >> NASID_TO_FINEREG_SHFT; - else - return nasid >> NASID_TO_COARSEREG_SHFT; -} - diff -urN linux-2.4.18/arch/ia64/sn/io/ml_SN_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/ml_SN_intr.c --- linux-2.4.18/arch/ia64/sn/io/ml_SN_intr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ml_SN_intr.c Thu Jan 1 01:00:00 1970 @@ -1,1728 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Alan Mayer - */ - -/* - * intr.c- - * This file contains all of the routines necessary to set up and - * handle interrupts on an IP27 board. - */ - -#ident "$Revision: 1.167 $" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DEBUG_INTR_TSTAMP_DEBUG -#include -#include -#include -void do_splx_log(int, int); -void spldebug_log_event(int); -#endif - -// FIXME - BRINGUP -#ifdef CONFIG_SMP -extern unsigned long cpu_online_map; -#endif -#define cpu_allows_intr(cpu) (1) -// If I understand what's going on with this, 32 should work. -// physmem_maxradius seems to be the maximum number of router -// hops to get from one end of the system to the other. With -// a maximally configured machine, with the dumbest possible -// topology, we would make 32 router hops. For what we're using -// it for, the dumbest possible should suffice. -#define physmem_maxradius() 32 - -#define SUBNODE_ANY -1 - -extern int nmied; -extern int hub_intr_wakeup_cnt; -extern synergy_da_t *Synergy_da_indr[]; -extern cpuid_t master_procid; - -extern cnodeid_t master_node_get(devfs_handle_t vhdl); - -extern snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - - -#define INTR_LOCK(vecblk) \ - (s = mutex_spinlock(&(vecblk)->vector_lock)) -#define INTR_UNLOCK(vecblk) \ - mutex_spinunlock(&(vecblk)->vector_lock, s) - -/* - * REACT/Pro - */ - - - -/* - * Find first bit set - * Used outside this file also - */ -int ms1bit(unsigned long x) -{ - int b; - - if (x >> 32) b = 32, x >>= 32; - else b = 0; - if (x >> 16) b += 16, x >>= 16; - if (x >> 8) b += 8, x >>= 8; - if (x >> 4) b += 4, x >>= 4; - if (x >> 2) b += 2, x >>= 2; - - return b + (int) (x >> 1); -} - -/* ARGSUSED */ -void -intr_stray(void *lvl) -{ - PRINT_WARNING("Stray Interrupt - level %ld to cpu %d", (long)lvl, cpuid()); -} - -#if defined(DEBUG) - -/* Infrastructure to gather the device - target cpu mapping info */ -#define MAX_DEVICES 1000 /* Reasonable large number . Need not be - * the exact maximum # devices possible. - */ -#define MAX_NAME 100 -typedef struct { - dev_t dev; /* device */ - cpuid_t cpuid; /* target cpu */ - cnodeid_t cnodeid;/* node on which the target cpu is present */ - int bit; /* intr bit reserved */ - char intr_name[MAX_NAME]; /* name of the interrupt */ -} intr_dev_targ_map_t; - -intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; -uint64_t intr_dev_targ_map_size; -spinlock_t intr_dev_targ_map_lock; - -/* Print out the device - target cpu mapping. - * This routine is used only in the idbg command - * "intrmap" - */ -void -intr_dev_targ_map_print(cnodeid_t cnodeid) -{ - int i,j,size = 0; - int print_flag = 0,verbose = 0; - char node_name[10]; - - if (cnodeid != CNODEID_NONE) { - nodepda_t *npda; - - npda = NODEPDA(cnodeid); - for (j=0; jintr_dispatch0.info[i].ii_flags); - qprintf("\n INT_PEND1: "); - for(i = 0 ; i < N_INTPEND_BITS ; i++) - qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags); - } - verbose = 1; - } - qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n", - (verbose ? "All" : "Non-hardwired"), - (cnodeid == CNODEID_NONE) ? "s: All" : node_name); - - qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n"); - for (i = 0 ; i < intr_dev_targ_map_size ; i++) { - - print_flag = 0; - if (verbose) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } else { - if (intr_dev_targ_map[i].dev != 0) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == - intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } - } - if (print_flag) { - size++; - qprintf("%d\t%d\t%d\t%d\t%s\n", - intr_dev_targ_map[i].dev, - intr_dev_targ_map[i].cpuid, - intr_dev_targ_map[i].cnodeid, - intr_dev_targ_map[i].bit, - intr_dev_targ_map[i].intr_name); - } - - } - qprintf("\nTotal : %d\n",size); -} -#endif /* DEBUG */ - -/* - * The spinlocks have already been initialized. Now initialize the interrupt - * vectors. One processor on each hub does the work. - */ -void -intr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn) -{ - int i, ip=0; - intr_vecblk_t *vecblk; - subnode_pda_t *snpda; - - - snpda = SNPDA(npda,sn); - do { - if (ip == 0) { - vecblk = &snpda->intr_dispatch0; - } else { - vecblk = &snpda->intr_dispatch1; - } - - /* Initialize this vector. */ - for (i = 0; i < N_INTPEND_BITS; i++) { - vecblk->vectors[i].iv_func = intr_stray; - vecblk->vectors[i].iv_prefunc = NULL; - vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i); - - vecblk->info[i].ii_owner_dev = 0; - strcpy(vecblk->info[i].ii_name, "Unused"); - vecblk->info[i].ii_flags = 0; /* No flags */ - vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */ - - } - - mutex_spinlock_init(&vecblk->vector_lock); - - vecblk->vector_count = 0; - for (i = 0; i < CPUS_PER_SUBNODE; i++) - vecblk->cpu_count[i] = 0; - - vecblk->vector_state = VECTOR_UNINITED; - - } while (++ip < 2); - -} - - -/* - * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - * devfs_handle_t owner_dev, char *name) - * Internal work routine to reserve or unreserve an interrupt level. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to reserve. -1 means any level - * resflags should include II_ERRORINT if this is an - * error interrupt, II_THREADED if the interrupt handler - * will be threaded, or 0 otherwise. - * reserve should be set to II_RESERVE or II_UNRESERVE - * to get or clear a reservation. - * owner_dev is the device that "owns" this interrupt, if supplied - * name is a human-readable name for this interrupt, if supplied - * intr_reserve_level returns the bit reserved or -1 to indicate an error - */ -static int -do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - devfs_handle_t owner_dev, char *name) -{ - intr_vecblk_t *vecblk; - hub_intmasks_t *hub_intmasks; - unsigned long s; - int rv = 0; - int ip; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - // if (pdaindr[cpu].pda == NULL) return -1; - if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) { - vecblk = hub_intmasks->dispatch0; - ip = 0; - } else { - ASSERT((bit >= N_INTPEND_BITS) || (bit == -1)); - bit -= N_INTPEND_BITS; /* Get position relative to INT_PEND1 reg. */ - vecblk = hub_intmasks->dispatch1; - ip = 1; - } - - INTR_LOCK(vecblk); - - if (bit <= -1) { - bit = 0; - ASSERT(reserve == II_RESERVE); - /* Choose any available level */ - for (; bit < N_INTPEND_BITS; bit++) { - if (!(vecblk->info[bit].ii_flags & II_RESERVE)) { - rv = bit; - break; - } - } - - /* Return -1 if all interrupt levels int this register are taken. */ - if (bit == N_INTPEND_BITS) - rv = -1; - - } else { - /* Reserve a particular level if it's available. */ - if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) { - /* Can't (un)reserve a level that's already (un)reserved. */ - rv = -1; - } else { - rv = bit; - } - } - - /* Reserve the level and bump the count. */ - if (rv != -1) { - if (reserve) { - int maxlen = sizeof(vecblk->info[bit].ii_name) - 1; - int namelen; - vecblk->info[bit].ii_flags |= (II_RESERVE | resflags); - vecblk->info[bit].ii_owner_dev = owner_dev; - /* Copy in the name. */ - namelen = name ? strlen(name) : 0; - strncpy(vecblk->info[bit].ii_name, name, MIN(namelen, maxlen)); - vecblk->info[bit].ii_name[maxlen] = '\0'; - vecblk->vector_count++; - } else { - vecblk->info[bit].ii_flags = 0; /* Clear all the flags */ - vecblk->info[bit].ii_owner_dev = 0; - /* Clear the name. */ - vecblk->info[bit].ii_name[0] = '\0'; - vecblk->vector_count--; - } - } - - INTR_UNLOCK(vecblk); - -#if defined(DEBUG) - if (rv >= 0) { - int namelen = name ? strlen(name) : 0; - /* Gather this device - target cpu mapping information - * in a table which can be used later by the idbg "intrmap" - * command - */ - s = mutex_spinlock(&intr_dev_targ_map_lock); - if (intr_dev_targ_map_size < MAX_DEVICES) { - intr_dev_targ_map_t *p; - - p = &intr_dev_targ_map[intr_dev_targ_map_size]; - p->dev = owner_dev; - p->cpuid = cpu; - p->cnodeid = cputocnode(cpu); - p->bit = ip * N_INTPEND_BITS + rv; - strncpy(p->intr_name, - name, - MIN(MAX_NAME,namelen)); - intr_dev_targ_map_size++; - } - mutex_spinunlock(&intr_dev_targ_map_lock,s); - } -#endif /* DEBUG */ - - return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ; -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Reserve an interrupt level. - */ -int -intr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name) -{ - return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name)); -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Unreserve an interrupt level. - */ -void -intr_unreserve_level(cpuid_t cpu, int bit) -{ - (void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL); -} - -/* - * Get values that vary depending on which CPU and bit we're operating on - */ -static hub_intmasks_t * -intr_get_ptrs(cpuid_t cpu, int bit, - int *new_bit, /* Bit relative to the register */ - hubreg_t **intpend_masks, /* Masks for this register */ - intr_vecblk_t **vecblk, /* Vecblock for this interrupt */ - int *ip) /* Which intpend register */ -{ - hub_intmasks_t *hub_intmasks; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - if (bit < N_INTPEND_BITS) { - *intpend_masks = hub_intmasks->intpend0_masks; - *vecblk = hub_intmasks->dispatch0; - *ip = 0; - *new_bit = bit; - } else { - *intpend_masks = hub_intmasks->intpend1_masks; - *vecblk = hub_intmasks->dispatch1; - *ip = 1; - *new_bit = bit - N_INTPEND_BITS; - } - - return hub_intmasks; -} - - -/* - * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, - * intr_func_t intr_func, void *intr_arg); - * This is the lowest-level interface to the interrupt code. It shouldn't - * be called from outside the ml/SN directory. - * intr_connect_level hooks up an interrupt to a particular bit in - * the INT_PEND0/1 masks. Returns 0 on success. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to connect to - * intr_swlevel tells which software level to use - * intr_func is the interrupt handler - * intr_arg is an arbitrary argument interpreted by the handler - * intr_prefunc is a prologue function, to be called - * with interrupts disabled, to disable - * the interrupt at source. It is called - * with the same argument. Should be NULL for - * typical interrupts, which can be masked - * by the infrastructure at the level bit. - * intr_connect_level returns 0 on success or nonzero on an error - */ -/* ARGSUSED */ -int -intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, - intr_func_t intr_func, void *intr_arg, - intr_func_t intr_prefunc) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - int rv = 0; - int ip; - unsigned long s; - - ASSERT(bit < N_INTPEND_BITS * 2); - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & II_INUSE) || - (!(vecblk->info[bit].ii_flags & II_RESERVE))) { - /* Can't assign to a level that's in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_func = intr_func; - vecblk->vectors[bit].iv_prefunc = intr_prefunc; - vecblk->vectors[bit].iv_arg = intr_arg; - vecblk->info[bit].ii_flags |= II_INUSE; - } - - /* Now stuff the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - // nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu)); - nasid_t nasid = cpuid_to_nasid(cpu); - int subnode = cpuid_to_subnode(cpu); - - /* Make sure it's not already pending when we connect it. */ - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS); - - intpend_masks[0] |= (1ULL << (uint64_t)bit); - - lslice = cputolocalslice(cpu); - vecblk->cpu_count[lslice]++; -#if SN1 - /* - * On SN1, there are 8 interrupt mask registers per node: - * PI_0 MASK_0 A - * PI_0 MASK_1 A - * PI_0 MASK_0 B - * PI_0 MASK_1 B - * PI_1 MASK_0 A - * PI_1 MASK_1 A - * PI_1 MASK_0 B - * PI_1 MASK_1 B - */ -#endif - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice); - } - - HUB_S(mask_reg, intpend_masks[0]); - } - - INTR_UNLOCK(vecblk); - - return rv; -} - - -/* - * intr_disconnect_level(cpuid_t cpu, int bit) - * - * This is the lowest-level interface to the interrupt code. It should - * not be called from outside the ml/SN directory. - * intr_disconnect_level removes a particular bit from an interrupt in - * the INT_PEND0/1 masks. Returns 0 on success or nonzero on failure. - */ -int -intr_disconnect_level(cpuid_t cpu, int bit) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - unsigned long s; - int rv = 0; - int ip; - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) != - ((II_RESERVE | II_INUSE))) { - /* Can't remove a level that's not in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_func = (intr_func_t)NULL; - vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL; - vecblk->vectors[bit].iv_arg = 0; - vecblk->info[bit].ii_flags &= ~II_INUSE; -#ifdef BASE_ITHRTEAD - vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */ -#endif - } - - /* Now clear the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - lslice = cputolocalslice(cpu); - vecblk->cpu_count[lslice]--; - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cputocnode(cpu)), - cpuid_to_subnode(cpu), - ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A); - mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg + - (PI_INT_MASK_OFFSET * lslice)); - *mask_reg = intpend_masks[0]; - } - - INTR_UNLOCK(vecblk); - - return rv; -} - -/* - * Actually block or unblock an interrupt - */ -void -do_intr_block_bit(cpuid_t cpu, int bit, int block) -{ - intr_vecblk_t *vecblk; - int ip; - unsigned long s; - hubreg_t *intpend_masks; - volatile hubreg_t mask_value; - volatile hubreg_t *mask_reg; - - intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip); - - INTR_LOCK(vecblk); - - if (block) - /* Block */ - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - else - /* Unblock */ - intpend_masks[0] |= (1ULL << (uint64_t)bit); - - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cputocnode(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK0_A); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cputocnode(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK1_A); - } - - HUB_S(mask_reg, intpend_masks[0]); - - /* - * Wait for it to take effect. (One read should suffice.) - * This is only necessary when blocking an interrupt - */ - if (block) - while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0]) - ; - - INTR_UNLOCK(vecblk); -} - - -/* - * Block a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_block_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 1); -} - - -/* - * Unblock a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_unblock_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 0); -} - - -/* verifies that the specified CPUID is on the specified SUBNODE (if any) */ -#define cpu_on_subnode(cpuid, which_subnode) \ - (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode))) - - -/* - * Choose one of the CPUs on a specified node or subnode to receive - * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu. - * - * Among all acceptable CPUs, the CPU that has the fewest total number - * of interrupts targetted towards it is chosen. Note that we never - * consider how frequent each of these interrupts might occur, so a rare - * hardware error interrupt is weighted equally with a disk interrupt. - */ -static cpuid_t -do_intr_cpu_choose(cnodeid_t cnode, int which_subnode) -{ - cpuid_t cpu, best_cpu = CPU_NONE; - int slice, min_count=1000; - - min_count = 1000; - for (slice=0; slice < CPUS_PER_NODE; slice++) { - intr_vecblk_t *vecblk0, *vecblk1; - int total_intrs_to_slice; - subnode_pda_t *snpda; - int local_cpu_num; - - cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) - continue; - - /* If this cpu isn't enabled for interrupts, skip it */ - if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu)) - continue; - - /* If this isn't the right subnode, skip it */ - if (!cpu_on_subnode(cpu, which_subnode)) - continue; - - /* OK, this one's a potential CPU for interrupts */ - snpda = SUBNODEPDA(cnode,SUBNODE(slice)); - vecblk0 = &snpda->intr_dispatch0; - vecblk1 = &snpda->intr_dispatch1; - local_cpu_num = LOCALCPU(slice); - total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] + - vecblk1->cpu_count[local_cpu_num]; - - if (min_count > total_intrs_to_slice) { - min_count = total_intrs_to_slice; - best_cpu = cpu; - } - } - return best_cpu; -} - -/* - * Choose an appropriate interrupt target CPU on a specified node. - * If which_subnode is SUBNODE_ANY, then subnode is not considered. - * Otherwise, the chosen CPU must be on the specified subnode. - */ -static cpuid_t -intr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode) -{ - return(do_intr_cpu_choose(cnode, which_subnode)); -} - - -#ifdef LATER -/* - * Convert a subnode vertex into a (cnodeid, which_subnode) pair. - * Return 0 on success, non-zero on failure. - */ -static int -subnodevertex_to_subnode(devfs_handle_t vhdl, cnodeid_t *cnodeidp, int *which_subnodep) -{ - arbitrary_info_t which_subnode; - cnodeid_t cnodeid; - - /* Try to grab subnode information */ - if (hwgraph_info_get_LBL(vhdl, INFO_LBL_CPUBUS, &which_subnode) != GRAPH_SUCCESS) - return(-1); - - /* On which node? */ - cnodeid = master_node_get(vhdl); - if (cnodeid == CNODEID_NONE) - return(-1); - - *which_subnodep = (int)which_subnode; - *cnodeidp = cnodeid; - return(0); /* success */ -} - -#endif /* LATER */ - -/* Make it easy to identify subnode vertices in the hwgraph */ -void -mark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode) -{ - graph_error_t rv; - - ASSERT(0 <= which_subnode); - ASSERT(which_subnode < NUM_SUBNODES); - - rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); - - rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t)); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); -} - - -/* - * Given a device descriptor, extract interrupt target information and - * choose an appropriate CPU. Return CPU_NONE if we can't make sense - * out of the target information. - * TBD: Should this be considered platform-independent code? - */ - -#ifdef LATER -static cpuid_t -intr_target_from_desc(device_desc_t dev_desc, int favor_subnode) -{ - cpuid_t cpuid = CPU_NONE; - cnodeid_t cnodeid; - int which_subnode; - devfs_handle_t intr_target_dev; - - if ((intr_target_dev = device_desc_intr_target_get(dev_desc)) != GRAPH_VERTEX_NONE) { - /* - * A valid device was specified. If it's a particular - * CPU, then use that CPU as target. - */ - cpuid = cpuvertex_to_cpuid(intr_target_dev); - if (cpuid != CPU_NONE) - goto cpuchosen; - - /* If a subnode vertex was specified, pick a CPU on that subnode. */ - if (subnodevertex_to_subnode(intr_target_dev, &cnodeid, &which_subnode) == 0) { - cpuid = intr_cpu_choose_from_node(cnodeid, which_subnode); - goto cpuchosen; - } - - /* - * Otherwise, pick a CPU on the node that owns the - * specified target. Favor "favor_subnode", if specified. - */ - cnodeid = master_node_get(intr_target_dev); - if (cnodeid != CNODEID_NONE) { - cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode); - goto cpuchosen; - } - } - -cpuchosen: - return(cpuid); -} -#endif /* LATER */ - - -#ifdef LATER -/* - * Check if we had already visited this candidate cnode - */ -static void * -intr_cnode_seen(cnodeid_t candidate, - void *arg1, - void *arg2) -{ - int i; - cnodeid_t *visited_cnodes = (cnodeid_t *)arg1; - int *num_visited_cnodes = (int *)arg2; - - ASSERT(visited_cnodes); - ASSERT(*num_visited_cnodes <= numnodes); - for(i = 0 ; i < *num_visited_cnodes; i++) { - if (candidate == visited_cnodes[i]) - return(NULL); - } - return(visited_cnodes); -} - -#endif /* LATER */ - - - -/* - * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags, - * owner_dev,intr_name,*resp_bit) - * Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but - * not both. - * 1. If cpuid is specified, this routine tests if this cpu can be a valid - * interrupt target candidate. - * 2. If cnodeid is specified, this routine tests if there is a cpu on - * this node which can be a valid interrupt target candidate. - * 3. If a valid interrupt target cpu candidate is found then an attempt at - * reserving an interrupt bit on the corresponding cnode is made. - * - * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid - * interrupt target cpu then routine returns CPU_NONE (failure) - * Otherwise routine returns cpuid of interrupt target (success) - */ -static cpuid_t -intr_bit_reserve_test(cpuid_t cpuid, - int favor_subnode, - cnodeid_t cnodeid, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - - ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE)); - - if (cnodeid != CNODEID_NONE) { - /* Try to choose a interrupt cpu candidate */ - cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode); - } - - if (cpuid != CPU_NONE) { - /* Try to reserve an interrupt bit on the hub - * corresponding to the canidate cnode. If we - * are successful then we got a cpu which can - * act as an interrupt target for the io device. - * Otherwise we need to continue the search - * further. - */ - *resp_bit = do_intr_reserve_level(cpuid, - req_bit, - intr_resflags, - II_RESERVE, - owner_dev, - intr_name); - - if (*resp_bit >= 0) - /* The interrupt target specified was fine */ - return(cpuid); - } - return(CPU_NONE); -} -/* - * intr_heuristic(dev_t dev,device_desc_t dev_desc, - * int req_bit,int intr_resflags,dev_t owner_dev, - * char *intr_name,int *resp_bit) - * - * Choose an interrupt destination for an interrupt. - * dev is the device for which the interrupt is being set up - * dev_desc is a description of hardware and policy that could - * help determine where this interrupt should go - * req_bit is the interrupt bit requested - * (can be INTRCONNECT_ANY_BIT in which the first available - * interrupt bit is used) - * intr_resflags indicates whether we want to (un)reserve bit - * owner_dev is the owner device - * intr_name is the readable interrupt name - * resp_bit indicates whether we succeeded in getting the required - * action { (un)reservation} done - * negative value indicates failure - * - */ -/* ARGSUSED */ -cpuid_t -intr_heuristic(devfs_handle_t dev, - device_desc_t dev_desc, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - cpuid_t cpuid; /* possible intr targ*/ - cnodeid_t candidate; /* possible canidate */ -#ifdef LATER - cnodeid_t visited_cnodes[MAX_NASIDS], /* nodes seen so far */ - center, /* node we are on */ - candidate; /* possible canidate */ - int num_visited_cnodes = 0; /* # nodes seen */ - - int radius = 1, /* start looking at the - * current node - */ - maxradius = physmem_maxradius(); - void *rv; -#endif /* LATER */ - int which_subnode = SUBNODE_ANY; - -/* SN1 + pcibr Addressing Limitation */ - { - devfs_handle_t pconn_vhdl; - pcibr_soft_t pcibr_soft; - - /* - * This combination of SN1 and Bridge hardware has an odd "limitation". - * Due to the choice of addresses for PI0 and PI1 registers on SN1 - * and historical limitations in Bridge, Bridge is unable to - * send interrupts to both PI0 CPUs and PI1 CPUs -- we have - * to choose one set or the other. That choice is implicitly - * made when Bridge first attaches its error interrupt. After - * that point, all subsequent interrupts are restricted to the - * same PI number (though it's possible to send interrupts to - * the same PI number on a different node). - * - * Since neither SN1 nor Bridge designers are willing to admit a - * bug, we can't really call this a "workaround". It's a permanent - * solution for an SN1-specific and Bridge-specific hardware - * limitation that won't ever be lifted. - */ - if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && - ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) { - /* - * We "know" that the error interrupt is the first - * interrupt set up by pcibr_attach. Send all interrupts - * on this bridge to the same subnode number. - */ - if (pcibr_soft->bsi_err_intr) { - which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid); - } - } - } - -#ifdef LATER - /* - * If an interrupt target was specified for this - * interrupt allocation, try to use it. - */ - if (dev_desc) { - - /* Try to see if the interrupt target specified in the - * device descriptor is a legal candidate. - */ - cpuid = intr_bit_reserve_test(intr_target_from_desc(dev_desc, which_subnode), - which_subnode, - CNODEID_NONE, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); /* got a valid interrupt target */ - - printk("Override explicit interrupt targetting: %v (0x%x)\n", - owner_dev, owner_dev); - - intr_unreserve_level(cpuid, *resp_bit); - } - - /* Fall through on to the next step in the search for - * the interrupt candidate. - */ - - } -#endif /* LATER */ - - /* Check if we can find a valid interrupt target candidate on - * the master node for the device. - */ - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - master_node_get(dev), - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); /* got a valid interrupt target */ - else - intr_unreserve_level(cpuid, *resp_bit); - } - - PRINT_WARNING("Cannot target interrupts to closest node(%d): %ld (0x%lx)\n", - master_node_get(dev),(long) owner_dev, (unsigned long)owner_dev); - - /* Fall through into the default algorithm - * (exhaustive-search-for-the-nearest-possible-interrupt-target) - * for finding the interrupt target - */ - -#ifndef BRINGUP - // Use of this algorithm is deferred until the supporting - // code has been implemented. - /* - * No valid interrupt specification exists. - * Try to find a node which is closest to the current node - * which can process interrupts from a device - */ - - center = cpuid_to_cnodeid(smp_processor_id()); - while (radius <= maxradius) { - - /* Try to find a node at the given radius and which - * we haven't seen already. - */ - rv = physmem_select_neighbor_node(center,radius,&candidate, - intr_cnode_seen, - (void *)visited_cnodes, - (void *)&num_visited_cnodes); - if (!rv) { - /* We have seen all the nodes at this particular radius - * Go on to the next radius level. - */ - radius++; - continue; - } - /* We are seeing this candidate cnode for the first time - */ - visited_cnodes[num_visited_cnodes++] = candidate; - - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - candidate, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); /* got a valid interrupt target */ - else - intr_unreserve_level(cpuid, *resp_bit); - } - } -#else /* BRINGUP */ - { - // Do a stupid round-robin assignment of the node. - static cnodeid_t last_node = -1; - - if (last_node >= numnodes) last_node = 0; - for (candidate = last_node + 1; candidate != last_node; candidate++) { - if (candidate == numnodes) candidate = 0; - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - candidate, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) { - last_node = candidate; - return(cpuid); /* got a valid interrupt target */ - } - else - intr_unreserve_level(cpuid, *resp_bit); - } - } - last_node = candidate; - } -#endif - - PRINT_WARNING("Cannot target interrupts to any close node: %ld (0x%lx)\n", - (long)owner_dev, (unsigned long)owner_dev); - - /* In the worst case try to allocate interrupt bits on the - * master processor's node. We may get here during error interrupt - * allocation phase when the topology matrix is not yet setup - * and hence cannot do an exhaustive search. - */ - ASSERT(cpu_allows_intr(master_procid)); - cpuid = intr_bit_reserve_test(master_procid, - which_subnode, - CNODEID_NONE, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); - else - intr_unreserve_level(cpuid, *resp_bit); - } - - PRINT_WARNING("Cannot target interrupts: %ld (0x%lx)\n", - (long)owner_dev, (unsigned long)owner_dev); - - return(CPU_NONE); /* Should never get here */ -} - - - - -#ifndef BRINGUP -/* - * Should never receive an exception while running on the idle - * stack. It IS possible to handle *interrupts* while on the - * idle stack, but a non-interrupt *exception* is a problem. - */ -void -idle_err(inst_t *epc, uint cause, void *fep, void *sp) -{ - eframe_t *ep = (eframe_t *)fep; - - if ((cause & CAUSE_EXCMASK) == EXC_IBE || - (cause & CAUSE_EXCMASK) == EXC_DBE) { - (void)dobuserre((eframe_t *)ep, epc, 0); - } - - /* XXX - This will have to change to deal with various SN errors. */ - panic( "exception on IDLE stack " - "ep:0x%x epc:0x%x cause:0x%w32x sp:0x%x badvaddr:0x%x", - ep, epc, cause, sp, getbadvaddr()); - /* NOTREACHED */ -} - - -/* - * earlynofault - handle very early global faults - usually just while - * sizing memory - * Returns: 1 if should do nofault - * 0 if not - */ -/* ARGSUSED */ -int -earlynofault(eframe_t *ep, uint code) -{ - switch(code) { - case EXC_DBE: - return(1); - default: - return(0); - } -} - - - -/* ARGSUSED */ -static void -cpuintr(void *arg1, void *arg2) -{ -#if RTE - static int rte_intrdebug = 1; -#endif - /* - * Frame Scheduler - */ - LOG_TSTAMP_EVENT(RTMON_INTR, TSTAMP_EV_CPUINTR, NULL, NULL, - NULL, NULL); - - /* - * Hardware clears the IO interrupts, but we need to clear software- - * generated interrupts. - */ - LOCAL_HUB_CLR_INTR(CPU_ACTION_A + cputolocalslice(cpuid())); - -#if 0 - /* XXX - Handle error interrupts. */ - if (error_intr_reason) - error_intr(); -#endif /* 0 */ - - /* - * If we're headed for panicspin and it is due to a NMI, save the - * eframe in the NMI area - */ - if (private.p_va_panicspin && nmied) { - caddr_t nmi_save_area; - - nmi_save_area = (caddr_t) (TO_UNCAC(TO_NODE( - cputonasid(cpuid()), IP27_NMI_EFRAME_OFFSET)) + - cputoslice(cpuid()) * IP27_NMI_EFRAME_SIZE); - bcopy((caddr_t) arg2, nmi_save_area, sizeof(eframe_t)); - } - - doacvec(); -#if RTE - if (private.p_flags & PDAF_ISOLATED && !rte_intrdebug) - goto end_cpuintr; -#endif - doactions(); -#if RTE -end_cpuintr: -#endif - LOG_TSTAMP_EVENT(RTMON_INTR, TSTAMP_EV_INTREXIT, TSTAMP_EV_CPUINTR, NULL, NULL, NULL); -} - -void -install_cpuintr(cpuid_t cpu) -{ - int intr_bit = CPU_ACTION_A + cputolocalslice(cpu); - - if (intr_connect_level(cpu, intr_bit, INTPEND0_MAXMASK, - (intr_func_t) cpuintr, NULL, NULL)) - panic("install_cpuintr: Can't connect interrupt."); -} -#endif /* BRINGUP */ - -#ifdef DEBUG_INTR_TSTAMP -/* We allocate an array, but only use element number 64. This guarantees that - * the entry is in a cacheline by itself. - */ -#define DINTR_CNTIDX 32 -#define DINTR_TSTAMP1 48 -#define DINTR_TSTAMP2 64 -volatile long long dintr_tstamp_cnt[128]; -int dintr_debug_output=0; -extern void idbg_tstamp_debug(void); -#ifdef SPLDEBUG -extern void idbg_splx_log(int); -#endif -#if DEBUG_INTR_TSTAMP_DEBUG -int dintr_enter_symmon=1000; /* 1000 microseconds is 1 millisecond */ -#endif - -#ifndef BRINGUP -/* ARGSUSED */ -static void -cpulatintr(void *arg) -{ - /* - * Hardware only clears IO interrupts so we have to clear our level - * here. - */ - LOCAL_HUB_CLR_INTR(CPU_INTRLAT_A + cputolocalslice(cpuid())); - -#if DEBUG_INTR_TSTAMP_DEBUG - dintr_tstamp_cnt[DINTR_TSTAMP2] = GET_LOCAL_RTC; - if ((dintr_tstamp_cnt[DINTR_TSTAMP2] - dintr_tstamp_cnt[DINTR_TSTAMP1]) - > dintr_enter_symmon) { -#ifdef SPLDEBUG - extern int spldebug_log_off; - - spldebug_log_off = 1; -#endif /* SPLDEBUG */ - debug("ring"); -#ifdef SPLDEBUG - spldebug_log_off = 0; -#endif /* SPLDEBUG */ - } -#endif - dintr_tstamp_cnt[DINTR_CNTIDX]++; - - return; -} - -static int install_cpulat_first=0; - -void -install_cpulatintr(cpuid_t cpu) -{ - int intr_bit; - devfs_handle_t cpuv = cpuid_to_vertex(cpu); - - intr_bit = CPU_INTRLAT_A + cputolocalslice(cpu); - if (intr_bit != intr_reserve_level(cpu, intr_bit, II_THREADED, - cpuv, "intrlat")) - panic( "install_cpulatintr: Can't reserve interrupt."); - - if (intr_connect_level(cpu, intr_bit, INTPEND0_MAXMASK, - cpulatintr, NULL, NULL)) - panic( "install_cpulatintr: Can't connect interrupt."); - - if (!install_cpulat_first) { - install_cpulat_first++; - idbg_addfunc("tstamp_debug", (void (*)())idbg_tstamp_debug); -#if defined(SPLDEBUG) || defined(SPLDEBUG_CPU_EVENTS) - idbg_addfunc("splx_log", (void (*)())idbg_splx_log); -#endif /* SPLDEBUG || SPLDEBUG_CPU_EVENTS */ - } -} -#endif /* BRINGUP */ - -#endif /* DEBUG_INTR_TSTAMP */ - -#ifndef BRINGUP -/* ARGSUSED */ -static void -dbgintr(void *arg) -{ - /* - * Hardware only clears IO interrupts so we have to clear our level - * here. - */ - LOCAL_HUB_CLR_INTR(N_INTPEND_BITS + DEBUG_INTR_A + cputolocalslice(cpuid())); - - debug("zing"); - return; -} - - -void -install_dbgintr(cpuid_t cpu) -{ - int intr_bit; - devfs_handle_t cpuv = cpuid_to_vertex(cpu); - - intr_bit = N_INTPEND_BITS + DEBUG_INTR_A + cputolocalslice(cpu); - if (intr_bit != intr_reserve_level(cpu, intr_bit, 1, cpuv, "DEBUG")) - panic("install_dbgintr: Can't reserve interrupt. " - " intr_bit %d" ,intr_bit); - - if (intr_connect_level(cpu, intr_bit, INTPEND1_MAXMASK, - dbgintr, NULL, NULL)) - panic("install_dbgintr: Can't connect interrupt."); - -#ifdef DEBUG_INTR_TSTAMP - /* Set up my interrupt latency test interrupt */ - install_cpulatintr(cpu); -#endif -} - -/* ARGSUSED */ -static void -tlbintr(void *arg) -{ - extern void tlbflush_rand(void); - - /* - * Hardware only clears IO interrupts so we have to clear our level - * here. - */ - LOCAL_HUB_CLR_INTR(N_INTPEND_BITS + TLB_INTR_A + cputolocalslice(cpuid())); - - tlbflush_rand(); - return; -} - - -void -install_tlbintr(cpuid_t cpu) -{ - int intr_bit; - devfs_handle_t cpuv = cpuid_to_vertex(cpu); - - intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputolocalslice(cpu); - if (intr_bit != intr_reserve_level(cpu, intr_bit, 1, cpuv, "DEBUG")) - panic("install_tlbintr: Can't reserve interrupt. " - " intr_bit %d" ,intr_bit); - - if (intr_connect_level(cpu, intr_bit, INTPEND1_MAXMASK, - tlbintr, NULL, NULL)) - panic("install_tlbintr: Can't connect interrupt."); - -} - - -/* - * Send an interrupt to all nodes. Don't panic if we get an error. - * Returns 1 if any exceptions occurred. - */ -int -protected_broadcast(hubreg_t intrbit) -{ - nodepda_t *npdap = private.p_nodepda; - int byte, bit, sn; - int error = 0; - - extern int _wbadaddr_val(volatile void *, int, volatile int *); - - /* Send rather than clear an interrupt. */ - intrbit |= 0x100; - - for (byte = 0; byte < NASID_MASK_BYTES; byte++) { - for (bit = 0; bit < 8; bit++) { - if (npdap->nasid_mask[byte] & (1 << bit)) { - nasid_t nasid = byte * 8 + bit; - for (sn=0; snii_name, - vector->iv_func, vector->iv_arg, vector->iv_prefunc); - pf(" vertex 0x%x %s%s", - info->ii_owner_dev, - ((info->ii_flags) & II_RESERVE) ? "R" : "U", - ((info->ii_flags) & II_INUSE) ? "C" : "-"); - pf("%s%s%s%s", - ip & value ? "P" : "-", - ima & value ? "A" : "-", - imb & value ? "B" : "-", - ((info->ii_flags) & II_ERRORINT) ? "E" : "-"); - pf("\n"); -} - - -/* - * Dump information about interrupt vector assignment. - */ -void -intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)) -{ - nodepda_t *npda; - int ip, sn, bit; - intr_vecblk_t *dispatch; - hubreg_t ipr, ima, imb; - nasid_t nasid; - - if ((cnode < 0) || (cnode >= numnodes)) { - pf("intr_dumpvec: cnodeid out of range: %d\n", cnode); - return ; - } - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - if (nasid == INVALID_NASID) { - pf("intr_dumpvec: Bad cnodeid: %d\n", cnode); - return ; - } - - - npda = NODEPDA(cnode); - - for (sn = 0; sn < NUM_SUBNODES; sn++) { - for (ip = 0; ip < 2; ip++) { - dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0); - ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0); - ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A); - imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B); - - pf("Node %d INT_PEND%d:\n", cnode, ip); - - if (dispatch->ithreads_enabled) - pf(" Ithreads enabled\n"); - else - pf(" Ithreads disabled\n"); - pf(" vector_count = %d, vector_state = %d\n", - dispatch->vector_count, - dispatch->vector_state); - pf(" CPU A count %d, CPU B count %d\n", - dispatch->cpu_count[0], - dispatch->cpu_count[1]); - pf(" &vector_lock = 0x%x\n", - &(dispatch->vector_lock)); - for (bit = 0; bit < N_INTPEND_BITS; bit++) { - if ((dispatch->info[bit].ii_flags & II_RESERVE) || - (ipr & (1L << bit))) { - dump_vector(&(dispatch->info[bit]), - &(dispatch->vectors[bit]), - bit, ipr, ima, imb, pf); - } - } - pf("\n"); - } - } -} - diff -urN linux-2.4.18/arch/ia64/sn/io/ml_iograph.c linux-2.4.19-pre5/arch/ia64/sn/io/ml_iograph.c --- linux-2.4.18/arch/ia64/sn/io/ml_iograph.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/ml_iograph.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include @@ -13,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -30,8 +32,6 @@ #include #include -extern int maxnodes; - /* #define IOGRAPH_DEBUG */ #ifdef IOGRAPH_DEBUG #define DBG(x...) printk(x) @@ -107,10 +107,10 @@ #ifdef LATER if (!is_headless_node_vertex(master)) { #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("volunteer for widgets: vertex %v has no info label", + printk(KERN_WARNING "volunteer for widgets: vertex %v has no info label", xswitch); #else - PRINT_WARNING("volunteer for widgets: vertex 0x%x has no info label", + printk(KERN_WARNING "volunteer for widgets: vertex 0x%x has no info label", xswitch); #endif } @@ -155,11 +155,11 @@ #ifdef LATER if (!is_headless_node_vertex(hubv)) { #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("assign_widgets_to_volunteers:vertex %v has " + printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has " " no info label", xswitch); #else - PRINT_WARNING("assign_widgets_to_volunteers:vertex 0x%x has " + printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has " " no info label", xswitch); #endif @@ -184,9 +184,6 @@ */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { -#ifndef BRINGUP - int i; -#endif /* * Ignore disabled/empty ports. */ @@ -244,7 +241,7 @@ cnodeid_t cnode; nasid_t nasid; lboard_t *board; - + /* * Init. the board-to-hwgraph link early, so FRU analyzer * doesn't trip on leftover values if we panic early on. @@ -267,55 +264,6 @@ hubio_init(); } -#ifdef LATER -/* There is an identical definition of this in os/scheduler/runq.c */ -#define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE -/* - * These functions absolutely doesn't belong here. It's here, though, - * until the scheduler provides a platform-independent version - * that works the way it should. The interface will definitely change, - * too. Currently used only in this file and by io/cdl.c in order to - * bind various I/O threads to a CPU on the proper node. - */ -cpu_cookie_t -setnoderun(cnodeid_t cnodeid) -{ - int i; - cpuid_t cpunum; - cpu_cookie_t cookie; - - INIT_COOKIE(cookie); - if (cnodeid == CNODEID_NONE) - return(cookie); - - /* - * Do a setmustrun to one of the CPUs on the specified - * node. - */ - if ((cpunum = CNODE_TO_CPU_BASE(cnodeid)) == CPU_NONE) { - return(cookie); - } - - cpunum += CNODE_NUM_CPUS(cnodeid) - 1; - - for (i = 0; i < CNODE_NUM_CPUS(cnodeid); i++, cpunum--) { - - if (cpu_enabled(cpunum)) { - cookie = setmustrun(cpunum); - break; - } - } - - return(cookie); -} - -void -restorenoderun(cpu_cookie_t cookie) -{ - restoremustrun(cookie); -} -#endif /* LATER */ - #ifdef LINUX_KERNEL_THREADS static struct semaphore io_init_sema; #endif @@ -445,6 +393,7 @@ slotid_t slot; lboard_t *board = NULL; char buffer[16]; + slotid_t get_widget_slotnum(int xbow, int widget); DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* @@ -507,6 +456,7 @@ { lboard_t dummy; + if (board) { DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); } else { @@ -517,7 +467,6 @@ } /* - * BRINGUP * Make sure we really want to say xbrick, pbrick, * etc. rather than XIO, graphics, etc. */ @@ -534,14 +483,10 @@ "%cbrick" "/%s/%d", buffer, #endif -#ifdef BRINGUP (board->brd_type == KLTYPE_IBRICK) ? 'I' : (board->brd_type == KLTYPE_PBRICK) ? 'P' : (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', -#else - toupper(MODULE_GET_BTCHAR(NODEPDA(cnode)->module_id)), -#endif /* BRINGUP */ EDGE_LBL_XTALK, widgetnum); } @@ -563,11 +508,7 @@ */ if (is_master_baseio(nasid, NODEPDA(cnode)->module_id, -#ifdef BRINGUP get_widget_slotnum(0,widgetnum))) { -#else - <<< BOMB! >>> Need a new way to get slot numbers on IP35/IP37 -#endif extern void klhwg_baseio_inventory_add(devfs_handle_t, cnodeid_t); module = NODEPDA(cnode)->module_id; @@ -582,7 +523,6 @@ (lboard_t *)KL_CONFIG_INFO(nasid), module); /* - * BRINGUP * Change iobrick to correct i/o brick */ #ifdef SUPPORT_PRINTING_M_FORMAT @@ -594,11 +534,7 @@ NODEPDA(cnode)->module_id, EDGE_LBL_XTALK, widgetnum); } else { -#ifdef BRINGUP slot = get_widget_slotnum(0, widgetnum); -#else - <<< BOMB! Need a new way to get slot numbers on IP35/IP37 -#endif board = get_board_name(nasid, module, slot, new_name); /* @@ -729,41 +665,25 @@ GRAPH_SUCCESS) continue; -#if defined (CONFIG_SGI_IP35) || defined (CONFIG_IA64_SGI_SN1) || defined (CONFIG_IA64_GENERIC) board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), NODEPDA(cnodeid)->module_id); -#else - { - slotid_t slot; - slot = get_widget_slotnum(xbow_num, widgetnum); - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - NODEPDA(cnodeid)->module_id, slot); - } -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ if (board == NULL && peer_nasid != INVALID_NASID) { /* * Try to find the board on our peer */ -#if defined (CONFIG_SGI_IP35) || defined (CONFIG_IA64_SGI_SN1) || defined (CONFIG_IA64_GENERIC) board = find_lboard_module( (lboard_t *)KL_CONFIG_INFO(peer_nasid), NODEPDA(cnodeid)->module_id); - -#else - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(peer_nasid), - NODEPDA(cnodeid)->module_id, slot); - -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ } if (board == NULL) { #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("Could not find PROM info for vertex %v, " + printk(KERN_WARNING "Could not find PROM info for vertex %v, " "FRU analyzer may fail", vhdl); #else - PRINT_WARNING("Could not find PROM info for vertex 0x%x, " + printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " "FRU analyzer may fail", - vhdl); + (void *)vhdl); #endif return; } @@ -918,7 +838,6 @@ DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); npdap->basew_id = 0; -#if defined(BRINGUP) } else if (widget_partnum == XG_WIDGET_PART_NUM) { /* * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock??? @@ -926,11 +845,10 @@ */ npdap->basew_id = 0; npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); -#endif } else { npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, hubv); + panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); /*NOTREACHED*/ } @@ -1037,7 +955,7 @@ #define __DEVSTR3 "/lun/0/disk/partition/" #define __DEVSTR4 "/../ef" -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC +#if defined(CONFIG_IA64_SGI_SN1) /* * Currently, we need to allow for 5 IBrick slots with 1 FC each * plus an internal 1394. @@ -1045,6 +963,8 @@ * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. */ #define NUM_BASE_IO_SCSI_CTLR 6 +#else +#define NUM_BASE_IO_SCSI_CTLR 6 #endif /* * This tells ioconfig where it can start numbering scsi controllers. @@ -1072,7 +992,6 @@ for (i=0; i -extern devfs_handle_t ioc3_console_vhdl_get(void); devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; /* Define the system critical vertices and connect them through @@ -1251,6 +1166,7 @@ { char name[MAXDEVNAME]; devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; + devfs_handle_t ioc3_console_vhdl_get(void); DBG("baseio_ctlr_num_set; FIXME\n"); @@ -1335,7 +1251,7 @@ rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); } if (rtn_val) - PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); + printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { @@ -1355,7 +1271,7 @@ rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); } if (rtn_val) - PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); + printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); } @@ -1379,7 +1295,7 @@ #endif active = 0; - for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) { + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { #ifdef LINUX_KERNEL_THREADS char thread_name[16]; extern int io_init_pri; @@ -1428,7 +1344,7 @@ #endif /* LINUX_KERNEL_THREADS */ - for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) /* * Update information generated by IO init. */ diff -urN linux-2.4.18/arch/ia64/sn/io/module.c linux-2.4.19-pre5/arch/ia64/sn/io/module.c --- linux-2.4.18/arch/ia64/sn/io/module.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/module.c Sat Mar 30 22:55:26 2002 @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include +#include #include #include #include @@ -25,7 +26,7 @@ #include -/* #define LDEBUG 1 */ +/* #define LDEBUG 1 */ #ifdef LDEBUG #define DPRINTF printk @@ -173,9 +174,35 @@ lboard_t *board; klmod_serial_num_t *comp; char * bcopy(const char * src, char * dest, int count); + char serial_number[16]; + + /* + * record brick serial number + */ + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + + if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) + { +#if LDEBUG + printf ("module_probe_snum: no IP35 board found!\n"); +#endif + return 0; + } + + board_serial_number_get( board, serial_number ); + if( serial_number[0] != '\0' ) { + encode_str_serial( serial_number, m->snum.snum_str ); + m->snum_valid = 1; + } +#if LDEBUG + else { + printf("module_probe_snum: brick serial number is null!\n"); + } + printf("module_probe_snum: brick serial number == %s\n", serial_number); +#endif /* DEBUG */ board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_MIDPLANE8); + KLTYPE_IOBRICK_XBOW); if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) return 0; @@ -196,13 +223,13 @@ if (comp->snum.snum_str[0] != '\0') { bcopy(comp->snum.snum_str, - m->snum.snum_str, + m->sys_snum, MAX_SERIAL_NUM_SIZE); - m->snum_valid = 1; + m->sys_snum_valid = 1; } } - if (m->snum_valid) + if (m->sys_snum_valid) return 1; else { DPRINTF("Invalid serial number for module %d, " @@ -227,8 +254,7 @@ for (node = 0; node < numnodes; node++) { nasid = COMPACT_TO_NASID_NODEID(node); - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_IP27); + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); ASSERT(board); m = module_add_node(board->brd_module, node); @@ -241,7 +267,7 @@ nserial); if (nserial == 0) - PRINT_WARNING("io_module_init: No serial number found.\n"); + printk(KERN_WARNING "io_module_init: No serial number found.\n"); } elsc_t *get_elsc(void) diff -urN linux-2.4.18/arch/ia64/sn/io/pci.c linux-2.4.19-pre5/arch/ia64/sn/io/pci.c --- linux-2.4.18/arch/ia64/sn/io/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pci.c Sat Mar 30 22:55:26 2002 @@ -1,12 +1,12 @@ /* * + * SNI64 specific PCI support for SNI IO. + * * 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. * - * SNI64 specific PCI support for SNI IO. - * - * Copyright (C) 1997, 1998, 2000 Colin Ngam + * Copyright (c) 1997, 1998, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include #include @@ -14,7 +14,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -227,7 +228,7 @@ * snia64_pci_find_bios - SNIA64 pci_find_bios() platform specific code. */ void __init -sn1_pci_find_bios(void) +sn_pci_find_bios(void) { extern struct pci_ops pci_conf; /* @@ -237,11 +238,7 @@ sgi_master_io_infr_init(); -#ifdef BRINGUP - if ( IS_RUNNING_ON_SIMULATOR() ) - return; -#endif - /* sn1_io_infrastructure_init(); */ + /* sn_io_infrastructure_init(); */ pci_conf = snia64_pci_ops; } @@ -251,8 +248,6 @@ int i; unsigned int size; - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(d->bus->number); - /* IOC3 only decodes 0x20 bytes of the config space, reading * beyond that is relatively benign but writing beyond that * (especially the base address registers) will shut down the @@ -294,5 +289,12 @@ d->subsystem_device = 0; } + +#else +void sn_pci_find_bios(void) {} +void pci_fixup_ioc3(struct pci_dev *d) {} +struct list_head pci_root_buses; +struct list_head pci_root_buses; +struct list_head pci_devices; #endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/ia64/sn/io/pci_bus_cvlink.c linux-2.4.19-pre5/arch/ia64/sn/io/pci_bus_cvlink.c --- linux-2.4.18/arch/ia64/sn/io/pci_bus_cvlink.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pci_bus_cvlink.c Sat Mar 30 22:55:26 2002 @@ -4,19 +4,21 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ +#include #include #include #include +#include #include #include #include #include #include -#include +#include +#include #include #include #include @@ -26,20 +28,19 @@ #include #include #include -#include #include #include #include -#include - +#include #include -// #include #include #include -extern int bridge_rev_b_data_check_disable; #include +#include +#include + +extern int bridge_rev_b_data_check_disable; -#define MAX_PCI_XWIDGET 256 devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; @@ -49,11 +50,13 @@ static int pci_bus_map_create(devfs_handle_t xtalk); devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); -#define SN1_IOPORTS_UNIT 256 +#define SN_IOPORTS_UNIT 256 #define MAX_IOPORTS 0xffff -#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT) +#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN_IOPORTS_UNIT) struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; -unsigned long sn1_allocate_ioports(unsigned long pci_address); +unsigned long sn_allocate_ioports(unsigned long pci_address); + +extern void sn_init_irq_desc(void); @@ -104,7 +107,7 @@ int func = 0; char name[16]; devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = NULL; + devfs_handle_t device_vertex = (devfs_handle_t)NULL; /* * Go get the pci bus vertex. @@ -112,9 +115,9 @@ pci_bus = pci_bus_to_vertex(busnum); if (!pci_bus) { /* - * During probing, the Linux pci code invents non existant + * During probing, the Linux pci code invents non-existent * bus numbers and pci_dev structures and tries to access - * them to determine existance. Don't crib during probing. + * them to determine existence. Don't crib during probing. */ if (done_probing) printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); @@ -129,11 +132,25 @@ slot = PCI_SLOT(devfn); func = PCI_FUNC(devfn); - if (func == 0) + /* + * For a NON Multi-function card the name of the device looks like: + * ../pci/1, ../pci/2 .. + */ + if (func == 0) { sprintf(name, "%d", slot); - else - sprintf(name, "%d%c", slot, 'a'+func); - + if (hwgraph_traverse(pci_bus, name, &device_vertex) == + GRAPH_SUCCESS) { + if (device_vertex) { + return(device_vertex); + } + } + } + + /* + * This maybe a multifunction card. It's names look like: + * ../pci/1a, ../pci/1b, etc. + */ + sprintf(name, "%d%c", slot, 'a'+func); if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { if (!device_vertex) { return(NULL); @@ -144,12 +161,42 @@ } /* + * For the given device, initialize the addresses for both the Device(x) Flush + * Write Buffer register and the Xbow Flush Register for the port the PCI bus + * is connected. + */ +static void +set_flush_addresses(struct pci_dev *device_dev, + struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + + device_sysdata->dma_buf_sync = (volatile unsigned int *) + &(bridge->b_wr_req_buf[pciio_slot].reg); + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), + pcibr_soft->bs_xid); +#ifdef DEBUG + + printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", + device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); + + while((volatile unsigned int )*device_sysdata->dma_buf_sync); + while((volatile unsigned int )*device_sysdata->xbow_buf_sync); +#endif + +} + +/* * Most drivers currently do not properly tell the arch specific pci dma * interfaces whether they can handle A64. Here is where we privately * keep track of this. */ static void __init -set_sn1_pci64(struct pci_dev *dev) +set_sn_pci64(struct pci_dev *dev) { unsigned short vendor = dev->vendor; unsigned short device = dev->device; @@ -172,7 +219,7 @@ } /* - * sn1_allocate_ioports() - This routine provides the allocation and + * sn_allocate_ioports() - This routine provides the allocation and * mappings between Linux style IOPORTs management. * * For simplicity sake, SN1 will allocate IOPORTs in chunks of @@ -189,9 +236,9 @@ * Address. This address via the tlb entries generates the PCI Address * allocated by the SN1 IO Infrastructure Layer. */ -static unsigned long sn1_ioport_num = 0x100; /* Reserve room for Legacy stuff */ +static unsigned long sn_ioport_num = 0x1000; /* Reserve room for Legacy stuff */ unsigned long -sn1_allocate_ioports(unsigned long pci_address) +sn_allocate_ioports(unsigned long pci_address) { unsigned long ioport_index; @@ -199,8 +246,8 @@ /* * Just some idiot checking .. */ - if ( sn1_ioport_num > 0xffff ) { - printk("sn1_allocate_ioports: No more IO PORTS available\n"); + if ( sn_ioport_num > 0xffff ) { + printk("sn_allocate_ioports: No more IO PORTS available\n"); return(-1); } @@ -208,51 +255,64 @@ * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's * Manual for details. */ - ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT; - ioports_to_tlbs[ioport_index].ppn = pci_address; + ioport_index = sn_ioport_num / SN_IOPORTS_UNIT; + ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ - ioports_to_tlbs[ioport_index].ma = 5; /* Memory Attributes */ - ioports_to_tlbs[ioport_index].a = 0; /* Set Data Access Bit Fault */ - ioports_to_tlbs[ioport_index].d = 0; /* Dirty Bit */ - ioports_to_tlbs[ioport_index].pl = 3;/* Privilege Level - All levels can R/W*/ - ioports_to_tlbs[ioport_index].ar = 2; /* Access Rights - R/W only*/ + ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */ + ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/ + ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/ + ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */ + ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/ + ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/ + ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */ ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ - printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index].ppn); + /* printk("sn_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */ - sn1_ioport_num += SN1_IOPORTS_UNIT; + sn_ioport_num += SN_IOPORTS_UNIT; - return(sn1_ioport_num - SN1_IOPORTS_UNIT); + return(sn_ioport_num - SN_IOPORTS_UNIT); } /* - * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is + * sn_pci_fixup() - This routine is called when platform_pci_fixup() is * invoked at the end of pcibios_init() to link the Linux pci * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c * * Other platform specific fixup can also be done here. */ void -sn1_pci_fixup(int arg) +sn_pci_fixup(int arg) { struct list_head *ln; struct pci_bus *pci_bus = NULL; struct pci_dev *device_dev = NULL; - struct sn1_widget_sysdata *widget_sysdata; - struct sn1_device_sysdata *device_sysdata; + struct sn_widget_sysdata *widget_sysdata; + struct sn_device_sysdata *device_sysdata; +#ifdef SN_IOPORTS unsigned long ioport; +#endif pciio_intr_t intr_handle; int cpuid, bit; - devfs_handle_t *device_vertex; + devfs_handle_t device_vertex; pciio_intr_line_t lines; - extern void sn1_pci_find_bios(void); - + extern void sn_pci_find_bios(void); +#ifdef CONFIG_IA64_SGI_SN2 + extern int numnodes; + int cnode; +#endif /* CONFIG_IA64_SGI_SN2 */ -unsigned long res; if (arg == 0) { - sn1_pci_find_bios(); + sn_init_irq_desc(); + sn_pci_find_bios(); +#ifdef CONFIG_IA64_SGI_SN2 + for (cnode = 0; cnode < numnodes; cnode++) { + extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); + intr_init_vecblk(NODEPDA(cnode), cnode, 0); + } +#endif /* CONFIG_IA64_SGI_SN2 */ return; } @@ -274,19 +334,12 @@ #endif done_probing = 1; - if ( IS_RUNNING_ON_SIMULATOR() ) { - printk("sn1_pci_fixup not supported on simulator.\n"); - return; - } - -#ifdef REAL_HARDWARE - /* * Initialize the pci bus vertex in the pci_bus struct. */ for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { pci_bus = pci_bus_b(ln); - widget_sysdata = kmalloc(sizeof(struct sn1_widget_sysdata), + widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), GFP_KERNEL); widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); pci_bus->sysdata = (void *)widget_sysdata; @@ -296,8 +349,35 @@ * set the root start and end so that drivers calling check_region() * won't see a conflict */ - ioport_resource.start |= IO_SWIZ_BASE; - ioport_resource.end |= (HSPEC_SWIZ_BASE-1); +#ifdef SN_IOPORTS + ioport_resource.start = sn_ioport_num; + ioport_resource.end = 0xffff; +#else +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + /* + * IDE legacy IO PORTs are supported in Medusa. + * Just open up IO PORTs from 0 .. ioport_resource.end. + */ + ioport_resource.start = 0; + } else { + /* + * We do not support Legacy IO PORT numbers. + */ + ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET; + } + ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET; +#else + // Need something here for sn2.... ZXZXZX +#endif +#endif + + /* + * Set the root start and end for Mem Resource. + */ + iomem_resource.start = 0; + iomem_resource.end = 0xffffffffffffffff; + /* * Initialize the device vertex in the pci_dev struct. */ @@ -307,6 +387,7 @@ u16 cmd; devfs_handle_t vhdl; unsigned long size; + extern int bit_pos_to_irq(int); if (device_dev->vendor == PCI_VENDOR_ID_SGI && device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { @@ -316,12 +397,18 @@ /* Set the device vertex */ - device_sysdata = kmalloc(sizeof(struct sn1_device_sysdata), + device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), GFP_KERNEL); device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); device_sysdata->isa64 = 0; + /* + * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush + * register addresses. + */ + (void) set_flush_addresses(device_dev, device_sysdata); + device_dev->sysdata = (void *) device_sysdata; - set_sn1_pci64(device_dev); + set_sn_pci64(device_dev); pci_read_config_word(device_dev, PCI_COMMAND, &cmd); /* @@ -336,11 +423,8 @@ size = device_dev->resource[idx].end - device_dev->resource[idx].start; if (size) { - res = 0; - res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); - -/* printk("sn1_pci_fixup: Mapped Address = 0x%p size = 0x%x\n", device_dev->resource[idx].start, size); */ + device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; } else continue; @@ -348,6 +432,7 @@ device_dev->resource[idx].end = device_dev->resource[idx].start + size; +#ifdef CONFIG_IA64_SGI_SN1 /* * Adjust the addresses to go to the SWIZZLE .. */ @@ -355,15 +440,25 @@ device_dev->resource[idx].start & 0xfffff7ffffffffff; device_dev->resource[idx].end = device_dev->resource[idx].end & 0xfffff7ffffffffff; - res = 0; - res = pciio_config_get(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + idx, 4); +#endif + if (device_dev->resource[idx].flags & IORESOURCE_IO) { cmd |= PCI_COMMAND_IO; - ioport = sn1_allocate_ioports(device_dev->resource[idx].start); - /* device_dev->resource[idx].start = ioport; */ - /* device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT */ +#ifdef SN_IOPORTS + ioport = sn_allocate_ioports(device_dev->resource[idx].start); + if (ioport < 0) { + printk("sn_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number); + continue; + } + pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff))); + +printk("sn_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff))); + + device_dev->resource[idx].start = ioport; + device_dev->resource[idx].end = ioport + SN_IOPORTS_UNIT; +#endif } - else if (device_dev->resource[idx].flags & IORESOURCE_MEM) + if (device_dev->resource[idx].flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } /* @@ -371,17 +466,24 @@ */ size = device_dev->resource[PCI_ROM_RESOURCE].end - device_dev->resource[PCI_ROM_RESOURCE].start; - device_dev->resource[PCI_ROM_RESOURCE].start = + + if (size) { + device_dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[PCI_ROM_RESOURCE].end = + device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; + device_dev->resource[PCI_ROM_RESOURCE].end = device_dev->resource[PCI_ROM_RESOURCE].start + size; - /* - * go through synergy swizzled space - */ - device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; - device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; +#ifdef CONFIG_IA64_SGI_SN1 + /* + * go through synergy swizzled space + */ + device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; + device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; +#endif + + } /* * Update the Command Word on the Card. @@ -390,29 +492,46 @@ /* bit gets dropped .. no harm */ pci_write_config_word(device_dev, PCI_COMMAND, cmd); - pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, &lines); -#ifdef BRINGUP + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); if (device_dev->vendor == PCI_VENDOR_ID_SGI && device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { lines = 1; } - -#endif - device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata; + device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; device_vertex = device_sysdata->vhdl; intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); bit = intr_handle->pi_irq; cpuid = intr_handle->pi_cpu; +#ifdef CONFIG_IA64_SGI_SN1 irq = bit_pos_to_irq(bit); +#else /* SN2 */ + irq = bit; +#endif irq = irq + (cpuid << 8); - pciio_intr_connect(intr_handle, NULL, NULL, NULL); + pciio_intr_connect(intr_handle); device_dev->irq = irq; +#ifdef ajmtestintr + { + int slot = PCI_SLOT(device_dev->devfn); + static int timer_set = 0; + pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + extern void intr_test_handle_intr(int, void*, struct pt_regs *); + + if (!timer_set) { + intr_test_set_timer(); + timer_set = 1; + } + intr_test_register_irq(irq, pcibr_soft, slot); + request_irq(irq, intr_test_handle_intr,0,NULL, NULL); + } +#endif } -#endif /* REAL_HARDWARE */ + #if 0 { @@ -430,6 +549,10 @@ printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); } + +printk("testing Big Window: 0xC0000200c0000000 %p\n", *( (volatile uint64_t *)0xc0000200a0000000)); +printk("testing Big Window: 0xC0000200c0000008 %p\n", *( (volatile uint64_t *)0xc0000200a0000008)); + #endif } @@ -472,12 +595,14 @@ * Loop throught this vertex and get the Xwidgets .. */ for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { +#if 0 { int pos; char dname[256]; pos = devfs_generate_path(xtalk, dname, 256); printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); } +#endif sprintf(pathname, "%d", widgetnum); xwidget = NULL; @@ -512,12 +637,12 @@ */ master_node_vertex = device_master_get(xwidget); if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", xwidget); + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); } hubinfo_get(master_node_vertex, &hubinfo); if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", master_node_vertex); + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); return(1); } else { busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; @@ -527,12 +652,12 @@ * Pre assign DMA maps needed for 32 Bits Page Map DMA. */ busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct sn1_dma_maps_s) * 512, GFP_KERNEL); + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, xwidget); + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct sn1_dma_maps_s) * 512); + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); } @@ -552,14 +677,10 @@ { devfs_handle_t devfs_hdl = NULL; - devfs_handle_t module_comp = NULL; - devfs_handle_t node = NULL; devfs_handle_t xtalk = NULL; - graph_vertex_place_t placeptr = EDGE_PLACE_WANT_REAL_EDGES; int rv = 0; char name[256]; int master_iobrick; - moduleid_t iobrick_id; int i; /* @@ -619,66 +740,4 @@ } return(0); -} - -/* - * sgi_pci_intr_support - - */ -int -sgi_pci_intr_support (unsigned int requested_irq, device_desc_t *dev_desc, - devfs_handle_t *bus_vertex, pciio_intr_line_t *lines, - devfs_handle_t *device_vertex) - -{ - - unsigned int bus; - unsigned int devfn; - struct pci_dev *pci_dev; - unsigned char intr_pin = 0; - struct sn1_widget_sysdata *widget_sysdata; - struct sn1_device_sysdata *device_sysdata; - - if (!dev_desc || !bus_vertex || !device_vertex) { - printk("WARNING: sgi_pci_intr_support: Invalid parameter dev_desc 0x%p, bus_vertex 0x%p, device_vertex 0x%p\n", dev_desc, bus_vertex, device_vertex); - return(-1); - } - - devfn = (requested_irq >> 8) & 0xff; - bus = (requested_irq >> 16) & 0xffff; - pci_dev = pci_find_slot(bus, devfn); - widget_sysdata = (struct sn1_widget_sysdata *)pci_dev->bus->sysdata; - *bus_vertex = widget_sysdata->vhdl; - device_sysdata = (struct sn1_device_sysdata *)pci_dev->sysdata; - *device_vertex = device_sysdata->vhdl; -#if 0 - { - int pos; - char dname[256]; - pos = devfs_generate_path(*device_vertex, dname, 256); - printk("%s : path= %s pos %d\n", __FUNCTION__, &dname[pos], pos); - } -#endif /* BRINGUP */ - - - /* - * Get the Interrupt PIN. - */ - pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intr_pin); - *lines = (pciio_intr_line_t)intr_pin; - -#ifdef BRINGUP - /* - * ioc3 can't decode the PCI_INTERRUPT_PIN field of its config - * space so we have to set it here - */ - if (pci_dev->vendor == PCI_VENDOR_ID_SGI && - pci_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { - *lines = 1; - } -#endif /* BRINGUP */ - - /* Not supported currently */ - *dev_desc = NULL; - return(0); - } diff -urN linux-2.4.18/arch/ia64/sn/io/pci_dma.c linux-2.4.19-pre5/arch/ia64/sn/io/pci_dma.c --- linux-2.4.18/arch/ia64/sn/io/pci_dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pci_dma.c Sat Mar 30 22:55:26 2002 @@ -3,11 +3,9 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Leo Dagum + * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved. */ -#include #include #include #include @@ -15,37 +13,23 @@ #include #include -#ifndef LANGUAGE_C -#define LANGUAGE_C 99 -#endif -#ifndef _LANGUAGE_C -#define _LANGUAGE_C 99 -#endif - +#include #include #include +#include #include #include #include #include -#include +#include #include #include #include - -/* - * this is REALLY ugly, blame it on gcc's lame inlining that we - * have to put procedures in header files - */ -#if LANGUAGE_C == 99 -#undef LANGUAGE_C -#endif -#if CONFIG_IA64_SGI_IO == 99 -#undef CONFIG_IA64_SGI_IO -#endif +#include pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); -struct sn1_dma_maps_s *find_sn1_dma_map(dma_addr_t, unsigned char); +void free_pciio_dmamap(pcibr_dmamap_t); +struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); extern devfs_handle_t busnum_to_pcibr_vhdl[]; extern nasid_t busnum_to_nid[]; extern void * busnum_to_atedmamaps[]; @@ -57,48 +41,92 @@ get_free_pciio_dmamap(devfs_handle_t pci_bus) { int i; - struct sn1_dma_maps_s *sn1_dma_map = NULL; + struct sn_dma_maps_s *sn_dma_map = NULL; /* * Darn, we need to get the maps allocated for this bus. */ - for (i=0; i<512; i++) { + for (i=0; idma_addr) { - sn1_dma_map->dma_addr = -1; - return( (pciio_dmamap_t) sn1_dma_map ); + for (i=0; idma_addr) { + sn_dma_map->dma_addr = -1; + return( (pciio_dmamap_t) sn_dma_map ); } } -printk("get_pciio_dmamap: Unable to find a free dmamap\n"); return(NULL); } -struct sn1_dma_maps_s * -find_sn1_dma_map(dma_addr_t dma_addr, unsigned char busnum) +/* + * Free pciio_dmamap_t entry. + */ +void +free_pciio_dmamap(pcibr_dmamap_t dma_map) +{ + struct sn_dma_maps_s *sn_dma_map; + + sn_dma_map = (struct sn_dma_maps_s *) dma_map; + sn_dma_map->dma_addr = 0; + +} + +/* + * sn_dma_sync: This routine flushes all DMA buffers for the device into the II. + * This does not mean that the data is in the "Coherence Domain". But it + * is very close. + */ +void +sn_dma_sync( struct pci_dev *hwdev ) +{ + + struct sn_device_sysdata *device_sysdata; + volatile unsigned long dummy; + + /* + * It is expected that on IA64 platform, a DMA sync ensures that all + * the DMA (dma_handle) are complete and coherent. + * 1. Flush Write Buffers from Bridge. + * 2. Flush Xbow Port. + */ + device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; + dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync; + + /* + * For the Xbow Port flush, we maybe denied the request because + * someone else may be flushing the Port .. try again. + */ + while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) { + udelay(2); + } +} + + +struct sn_dma_maps_s * +find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) { - struct sn1_dma_maps_s *sn1_dma_map = NULL; + struct sn_dma_maps_s *sn_dma_map = NULL; int i; - sn1_dma_map = busnum_to_atedmamaps[busnum]; + sn_dma_map = busnum_to_atedmamaps[busnum]; - for (i=0; i<512; i++, sn1_dma_map++) { - if (sn1_dma_map->dma_addr == dma_addr) { - return( sn1_dma_map ); + for (i=0; idma_addr == dma_addr) { + return( sn_dma_map ); } } printk("find_pciio_dmamap: Unable find the corresponding dma map\n"); + return(NULL); } @@ -111,12 +139,12 @@ * write gathering turned on, hence the PCIIO_DMA_CMD flag */ void * -sn1_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +sn_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *ret; int gfp = GFP_ATOMIC; devfs_handle_t vhdl; - struct sn1_device_sysdata *device_sysdata; + struct sn_device_sysdata *device_sysdata; paddr_t temp_ptr; *dma_handle = (dma_addr_t) NULL; @@ -124,7 +152,7 @@ /* * get vertex for the device */ - device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; + device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) { @@ -139,9 +167,15 @@ /* * This device supports 64bits DMA addresses. */ +#ifdef CONFIG_IA64_SGI_SN1 *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); +#else /* SN2 */ + *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, + PCIBR_BARRIER | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); +#endif + return (ret); } @@ -152,15 +186,21 @@ * First try to get 32 Bit Direct Map Support. */ if (IS_PCI32G(hwdev)) { +#ifdef CONFIG_IA64_SGI_SN1 *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); +#else /* SN2 */ + *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, + PCIBR_BARRIER | PCIIO_DMA_CMD); +#endif + if (dma_handle) { return (ret); } else { /* * We need to map this request by using ATEs. */ - printk("sn1_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!"); + printk("sn_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!"); BUG(); } } @@ -176,17 +216,17 @@ } void -sn1_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +sn_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)); } /* - * On sn1 we use the orig_address entry of the scatterlist to store + * On sn1 we use the page entry of the scatterlist to store * the physical address corresponding to the given virtual address */ int -sn1_pci_map_sg (struct pci_dev *hwdev, +sn_pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { @@ -194,7 +234,7 @@ devfs_handle_t vhdl; dma_addr_t dma_addr; paddr_t temp_ptr; - struct sn1_device_sysdata *device_sysdata; + struct sn_device_sysdata *device_sysdata; pciio_dmamap_t dma_map; @@ -205,21 +245,51 @@ /* * Handle 64 bit cards. */ - device_sysdata = (struct sn1_device_sysdata *) hwdev->sysdata; + device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; for (i = 0; i < nents; i++, sg++) { - sg->orig_address = (char *)NULL; + /* this catches incorrectly written drivers that + attempt to map scatterlists that they have + previously mapped. we print a warning and + continue, but the driver should be fixed */ + switch (((u64)sg->address) >> 60) { + case 0xa: + case 0xb: +#ifdef DEBUG +/* This needs to be cleaned up at some point. */ + NAG("A PCI driver (for device at%8s) has attempted to " + "map a scatterlist that was previously mapped at " + "%p - this is currently being worked around.\n", + hwdev->slot_name, (void *)sg->address); +#endif + temp_ptr = (u64)sg->address & TO_PHYS_MASK; + break; + case 0xe: /* a good address, we now map it. */ + temp_ptr = (paddr_t) __pa(sg->address); + break; + default: + printk(KERN_ERR + "Very bad address (%p) passed to sn_pci_map_sg\n", + (void *)sg->address); + BUG(); + } + sg->page = (char *)NULL; dma_addr = 0; - temp_ptr = (paddr_t) __pa(sg->address); /* * Handle the most common case 64Bit cards. */ if (IS_PCIA64(hwdev)) { +#ifdef CONFIG_IA64_SGI_SN1 dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, temp_ptr, sg->length, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD | PCIIO_DMA_A64 ); + PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | + PCIIO_DMA_A64 ); +#else + dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, + temp_ptr, sg->length, + PCIIO_DMA_DATA | PCIIO_DMA_A64 ); +#endif sg->address = (char *)dma_addr; continue; } @@ -228,10 +298,14 @@ * Handle 32Bits and greater cards. */ if (IS_PCI32G(hwdev)) { +#ifdef CONFIG_IA64_SGI_SN1 dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, temp_ptr, sg->length, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); + PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); +#else + dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, + temp_ptr, sg->length, PCIIO_DMA_DATA); +#endif if (dma_addr) { sg->address = (char *)dma_addr; continue; @@ -244,9 +318,12 @@ * Let's 32Bit Page map the request. */ dma_map = NULL; +#ifdef CONFIG_IA64_SGI_SN1 dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); + PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); +#else + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, PCIIO_DMA_DATA); +#endif if (!dma_map) { printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n"); BUG(); @@ -254,7 +331,7 @@ dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length); /* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */ sg->address = (char *)dma_addr; - sg->orig_address = (char *)dma_map; + sg->page = (char *)dma_map; } @@ -268,30 +345,31 @@ * pci_unmap_single() above. */ void -sn1_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +sn_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { int i; - struct sn1_dma_maps_s *sn1_dma_map; + struct sn_dma_maps_s *sn_dma_map; if (direction == PCI_DMA_NONE) BUG(); for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address) { + if (sg->page) { /* - * We maintain the DMA Map pointer in sg->orig_address if + * We maintain the DMA Map pointer in sg->page if * it is ever allocated. */ /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */ - /* sg->address = sg->orig_address; */ + /* sg->address = sg->page; */ sg->address = (char *)-1; - sn1_dma_map = (struct sn1_dma_maps_s *)sg->orig_address; - pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); - sn1_dma_map->dma_addr = 0; - sg->orig_address = 0; + sn_dma_map = (struct sn_dma_maps_s *)sg->page; + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = 0; + sg->page = 0; } + } /* @@ -304,15 +382,15 @@ * get rid of dev_desc and vhdl (seems redundant given a pci_dev); * figure out how to save dmamap handle so can use two step. */ -dma_addr_t sn1_pci_map_single (struct pci_dev *hwdev, +dma_addr_t sn_pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) { devfs_handle_t vhdl; dma_addr_t dma_addr; paddr_t temp_ptr; - struct sn1_device_sysdata *device_sysdata; + struct sn_device_sysdata *device_sysdata; pciio_dmamap_t dma_map = NULL; - struct sn1_dma_maps_s *sn1_dma_map; + struct sn_dma_maps_s *sn_dma_map; if (direction == PCI_DMA_NONE) @@ -322,7 +400,7 @@ /* * find vertex for the device */ - device_sysdata = (struct sn1_device_sysdata *)hwdev->sysdata; + device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; vhdl = device_sysdata->vhdl; /* @@ -335,10 +413,14 @@ /* * This device supports 64bits DMA addresses. */ +#ifdef CONFIG_IA64_SGI_SN1 dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD - | PCIIO_DMA_A64 ); + PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | PCIIO_DMA_A64 ); +#else + dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, + temp_ptr, size, PCIIO_DMA_DATA | PCIIO_DMA_A64 ); +#endif return (dma_addr); } @@ -349,9 +431,14 @@ * First try to get 32 Bit Direct Map Support. */ if (IS_PCI32G(hwdev)) { +#ifdef CONFIG_IA64_SGI_SN1 dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); + PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); +#else + dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, + temp_ptr, size, PCIIO_DMA_DATA); +#endif if (dma_addr) { return (dma_addr); } @@ -369,64 +456,72 @@ * Let's 32Bit Page map the request. */ dma_map = NULL; - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIBR_BARRIER | - PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); +#ifdef CONFIG_IA64_SGI_SN1 + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | + PCIIO_DMA_DATA); +#else + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA); +#endif if (!dma_map) { printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n"); BUG(); } dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size); - /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, + /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */ - sn1_dma_map = (struct sn1_dma_maps_s *)dma_map; - sn1_dma_map->dma_addr = dma_addr; + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = dma_addr; return ((dma_addr_t)dma_addr); } void -sn1_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +sn_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { - struct sn1_dma_maps_s *sn1_dma_map = NULL; + struct sn_dma_maps_s *sn_dma_map = NULL; if (direction == PCI_DMA_NONE) BUG(); /* - * Get the sn1_dma_map entry. + * Get the sn_dma_map entry. */ if (IS_PCI32_MAPPED(dma_addr)) - sn1_dma_map = find_sn1_dma_map(dma_addr, hwdev->bus->number); + sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number); - if (sn1_dma_map) { - pciio_dmamap_done((pciio_dmamap_t)sn1_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn1_dma_map); - sn1_dma_map->dma_addr = (dma_addr_t)NULL; + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; } } void -sn1_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +sn_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + + sn_dma_sync(hwdev); + } void -sn1_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +sn_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + + sn_dma_sync(hwdev); + } unsigned long -sn1_dma_address (struct scatterlist *sg) +sn_dma_address (struct scatterlist *sg) { return ((unsigned long)sg->address); } diff -urN linux-2.4.18/arch/ia64/sn/io/pciba.c linux-2.4.19-pre5/arch/ia64/sn/io/pciba.c --- linux-2.4.18/arch/ia64/sn/io/pciba.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pciba.c Sat Mar 30 22:55:26 2002 @@ -1,1716 +1,958 @@ -/* $Id$ +/* + * arch/ia64/sn/io/pciba.c * - * 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. + * IRIX PCIBA-inspired user mode PCI interface * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * requires: devfs + * + * device nodes show up in /dev/pci/BB/SS.F (where BB is the bus the + * device is on, SS is the slot the device is in, and F is the + * device's function on a multi-function card). + * + * when compiled into the kernel, it will only be initialized by the + * sgi sn1 specific initialization code. in this case, device nodes + * are under /dev/hw/..../ + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * + * 03262001 - Initial version by Chad Talbott */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include -#include -#endif -#define copyin(_a, _b, _c) copy_from_user(_b, _a, _c) +/* jesse's beefs: + + register_pci_device should be documented + + grossness with do_swap should be documented + + big, gross union'ized node_data should be replaced with independent + structures + + replace global list of nodes with global lists of resources. could + use object oriented approach of allocating and cleaning up + resources. + +*/ + -#ifndef DEBUG_PCIBA -#define DEBUG_PCIBA 0 +#include +#ifndef CONFIG_DEVFS_FS +# error PCIBA requires devfs #endif -/* v_mapphys does not percolate page offset back. */ -#define PCIBA_ALIGN_CHECK 1 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include #include -/* grab an unused space code for "User DMA" space */ -#ifndef PCIBA_SPACE_UDMA -#define PCIBA_SPACE_UDMA (14) + +MODULE_DESCRIPTION("User mode PCI interface"); +MODULE_AUTHOR("Chad Talbott"); + + +#undef DEBUG_PCIBA +/* #define DEBUG_PCIBA */ + +#undef TRACE_PCIBA +/* #define TRACE_PCIBA */ + +#if defined(DEBUG_PCIBA) +# define DPRINTF(x...) printk(KERN_DEBUG x) +#else +# define DPRINTF(x...) #endif -#if DEBUG_REFCT -extern int hwgraph_vertex_refct(vertex_hdl_t); +#if defined(TRACE_PCIBA) +# if defined(__GNUC__) +# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ + __FILE__, __LINE__, __FUNCTION__) +# else +# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) +# endif +#else +# define TRACE() #endif -extern int pci_user_dma_max_pages; -#define NEW(ptr) (ptr = kmem_zalloc(sizeof (*(ptr)), KM_SLEEP)) -#define DEL(ptr) (kfree(ptr)) -/* Oops -- no standard "pci address" type! */ -typedef uint64_t pciaddr_t; +typedef enum { failure, success } status; +typedef enum { false, true } boolean; -/* ================================================================ - * driver types - */ -typedef struct pciba_slot_s *pciba_slot_t; -typedef struct pciba_comm_s *pciba_comm_t; -typedef struct pciba_soft_s *pciba_soft_t; -typedef struct pciba_map_s *pciba_map_t, **pciba_map_h; -typedef struct pciba_dma_s *pciba_dma_t, **pciba_dma_h; -typedef struct pciba_bus_s *pciba_bus_t; - -#define TRACKED_SPACES 16 -struct pciba_comm_s { - devfs_handle_t conn; - pciba_bus_t bus; - int refct; - pciba_soft_t soft[TRACKED_SPACES][2]; - struct semaphore lock; - pciba_dma_t dmap; + +/* major data structures: + + struct node_data - + + one for each file registered with devfs. contains everything + that any file's fops would need to know about. + + struct dma_allocation - + + a single DMA allocation. only the 'dma' nodes care about + these. they are there primarily to allow the driver to look + up the kernel virtual address of dma buffers allocated by + pci_alloc_consistent, as the application is only given the + physical address (to program the device's dma, presumably) and + cannot supply the kernel virtual address when freeing the + buffer. + + it's also useful to maintain a list of buffers allocated + through a specific node to allow some sanity checking by this + driver. this prevents (for example) a broken application from + freeing buffers that it didn't allocate, or buffers allocated + on another node. + + global_node_list - + + a list of all nodes allocated. this allows the driver to free + all the memory it has 'kmalloc'd in case of an error, or on + module removal. + + global_dma_list - + + a list of all dma buffers allocated by this driver. this + allows the driver to 'pci_free_consistent' all buffers on + module removal or error. + +*/ + + +struct node_data { + /* flat list of all the device nodes. makes it easy to free + them all when we're unregistered */ + struct list_head global_node_list; + devfs_handle_t devfs_handle; + + void (* cleanup)(struct node_data *); + + union { + struct { + struct pci_dev * dev; + struct list_head dma_allocs; + boolean mmapped; + } dma; + struct { + struct pci_dev * dev; + u32 saved_rom_base_reg; + boolean mmapped; + } rom; + struct { + struct resource * res; + } base; + struct { + struct pci_dev * dev; + } config; + } u; }; -/* pciba_soft: device_info() for all openables */ -struct pciba_soft_s { - pciba_comm_t comm; - devfs_handle_t vhdl; - int refct; - pciio_space_t space; - size_t size; - pciio_space_t iomem; - pciaddr_t base; - unsigned flags; +struct dma_allocation { + struct list_head list; + + dma_addr_t handle; + void * va; + size_t size; }; -#define pciba_soft_get(v) (pciba_soft_t)hwgraph_fastinfo_get(v) -#define pciba_soft_set(v,i) hwgraph_fastinfo_set(v,(arbitrary_info_t)(i)) -#define pciba_soft_lock(soft) down(&soft->comm->lock) -#define pciba_soft_unlock(soft) up(&soft->comm->lock) +static LIST_HEAD(global_node_list); +static LIST_HEAD(global_dma_list); -/* pciba_map: data describing a mapping. - * (ie. a user mmap request) - */ -struct pciba_map_s { - pciba_map_t next; -#ifdef LATER - uthread_t *uthread; -#endif - __psunsigned_t handle; - uvaddr_t uvaddr; - size_t size; - pciio_piomap_t map; - pciio_space_t space; - pciaddr_t base; - unsigned flags; -}; -/* pciba_dma: data describing a DMA mapping. - */ -struct pciba_dma_s { - pciba_dma_t next; - iopaddr_t paddr; /* starting phys addr */ - caddr_t kaddr; /* starting kern addr */ - pciio_dmamap_t map; /* mapping resources (ugh!) */ - pciaddr_t daddr; /* starting pci addr */ - size_t pages; /* size of block in pages */ - size_t bytes; /* size of block in bytes */ - __psunsigned_t handle; /* mapping handle */ +/* module entry points */ +int __init pciba_init(void); +void __exit pciba_exit(void); + +static status __init register_with_devfs(void); +static void __exit unregister_with_devfs(void); + +static status __init register_pci_device(devfs_handle_t device_dir_handle, + struct pci_dev * dev); + +/* file operations */ +static int generic_open(struct inode * inode, struct file * file); +static int rom_mmap(struct file * file, struct vm_area_struct * vma); +static int rom_release(struct inode * inode, struct file * file); +static int base_mmap(struct file * file, struct vm_area_struct * vma); +static int config_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, + unsigned long arg); +static int dma_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, + unsigned long arg); +static int dma_mmap(struct file * file, struct vm_area_struct * vma); + +/* support routines */ +static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va); +static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va); + +#ifdef DEBUG_PCIBA +static void dump_nodes(struct list_head * nodes); +static void dump_allocations(struct list_head * dalp); +#endif + +/* file operations for each type of node */ +static struct file_operations rom_fops = { + owner: THIS_MODULE, + mmap: rom_mmap, + open: generic_open, + release: rom_release }; + -/* pciba_bus: common bus info for all openables - * descended from the same master vertex. - */ -struct pciba_bus_s { - struct semaphore lock; - pciba_map_t maps; /* stack of mappings */ - int refct; +static struct file_operations base_fops = { + owner: THIS_MODULE, + mmap: base_mmap, + open: generic_open }; -#define pciba_bus_lock(bus) down(&bus->lock) -#define pciba_bus_unlock(bus) up(&bus->lock) -typedef union ioctl_arg_buffer_u { - char data[IOCPARM_MASK + 1]; - uint8_t uc; - uint16_t us; - uint32_t ui; - uint64_t ud; - caddr_t ca; -#if ULI - struct uliargs uli; - struct uliargs32 uli32; -#endif -} ioctl_arg_buffer_t; +static struct file_operations config_fops = { + owner: THIS_MODULE, + ioctl: config_ioctl, + open: generic_open +}; -/* ================================================================ - * driver variables - */ -char *pciba_mversion = "mload version 7.0"; -int pciba_devflag = 0x1 | - 0x200 | - 0x400; +static struct file_operations dma_fops = { + owner: THIS_MODULE, + ioctl: dma_ioctl, + mmap: dma_mmap, + open: generic_open +}; -/* this counts the reasons why we can not - * currently unload this driver. - */ -atomic_t pciba_prevent_unload = ATOMIC_INIT(0); -#if DEBUG_PCIBA -static struct reg_values space_v[] = -{ - {PCIIO_SPACE_NONE, "none"}, - {PCIIO_SPACE_ROM, "ROM"}, - {PCIIO_SPACE_IO, "I/O"}, - {PCIIO_SPACE_MEM, "MEM"}, - {PCIIO_SPACE_MEM32, "MEM(32)"}, - {PCIIO_SPACE_MEM64, "MEM(64)"}, - {PCIIO_SPACE_CFG, "CFG"}, - {PCIIO_SPACE_WIN(0), "WIN(0)"}, - {PCIIO_SPACE_WIN(1), "WIN(1)"}, - {PCIIO_SPACE_WIN(2), "WIN(2)"}, - {PCIIO_SPACE_WIN(3), "WIN(3)"}, - {PCIIO_SPACE_WIN(4), "WIN(4)"}, - {PCIIO_SPACE_WIN(5), "WIN(5)"}, - {PCIBA_SPACE_UDMA, "UDMA"}, - {PCIIO_SPACE_BAD, "BAD"}, - {0} -}; +module_init(pciba_init); +module_exit(pciba_exit); + -static struct reg_desc space_desc[] = +int __init +pciba_init(void) { - {0xFF, 0, "space", 0, space_v}, - {0} -}; -#endif + TRACE(); -char pciba_edge_lbl_base[] = "base"; -char pciba_edge_lbl_cfg[] = "config"; -char pciba_edge_lbl_dma[] = "dma"; -char pciba_edge_lbl_intr[] = "intr"; -char pciba_edge_lbl_io[] = "io"; -char pciba_edge_lbl_mem[] = "mem"; -char pciba_edge_lbl_rom[] = "rom"; -char *pciba_edge_lbl_win[6] = -{"0", "1", "2", "3", "4", "5"}; - -#define PCIBA_EDGE_LBL_BASE pciba_edge_lbl_base -#define PCIBA_EDGE_LBL_CFG pciba_edge_lbl_cfg -#define PCIBA_EDGE_LBL_DMA pciba_edge_lbl_dma -#define PCIBA_EDGE_LBL_INTR pciba_edge_lbl_intr -#define PCIBA_EDGE_LBL_IO pciba_edge_lbl_io -#define PCIBA_EDGE_LBL_MEM pciba_edge_lbl_mem -#define PCIBA_EDGE_LBL_ROM pciba_edge_lbl_rom -#define PCIBA_EDGE_LBL_WIN(n) pciba_edge_lbl_win[n] - -#define PCIBA_EDGE_LBL_FLIP pciba_edge_lbl_flip - -static char pciba_info_lbl_bus[] = "pciba_bus"; - -#define PCIBA_INFO_LBL_BUS pciba_info_lbl_bus - -struct file_operations pciba_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - -/* ================================================================ - * function table of contents - */ + if (register_with_devfs() == failure) + return 1; /* failure */ -void pciba_init(void); -int pciba_attach(devfs_handle_t); + printk("PCIBA (a user mode PCI interface) initialized.\n"); -static void pciba_sub_attach(pciba_comm_t, - pciio_space_t, pciio_space_t, pciaddr_t, - devfs_handle_t, devfs_handle_t, char *); - -static pciba_bus_t pciba_find_bus(devfs_handle_t, int); -#ifdef LATER -static void pciba_map_push(pciba_bus_t, pciba_map_t); -static pciba_map_t pciba_map_pop_hdl(pciba_bus_t, __psunsigned_t); -static void pciba_sub_detach(devfs_handle_t, char *); -static pciio_iter_f pciba_unload_me; -#endif + return 0; /* success */ +} -int pciba_unload(void); -int pciba_unreg(void); -int pciba_detach(devfs_handle_t); - -int pciba_open(dev_t *, int, int, struct cred *); -int pciba_close(dev_t); -int pciba_read(dev_t, cred_t *); -int pciba_write(dev_t, cred_t *); -int pciba_ioctl(dev_t, int, void *, int, cred_t *, int *); - -int pciba_map(dev_t, vhandl_t *, off_t, size_t, uint32_t); -int pciba_unmap(dev_t, vhandl_t *); - -#if ULI -void pciba_clearuli(struct uli *); -static intr_func_f pciba_intr; -#endif /* Undef as it gets implemented */ -/* ================================================================ - * driver load, register, and setup - */ -void -pciba_init(void) +void __exit +pciba_exit(void) { + TRACE(); - /* - * What do we need to do here? - */ -#if DEBUG_PCIBA - printk("pciba_init()\n"); -#endif + /* FIXME: should also free all that memory that we allocated + ;) */ + unregister_with_devfs(); } -#ifdef LATER -#if HWG_PERF_CHECK && IP30 && !DEBUG -void -pciba_timeout(void *arg1, void *arg2) -{ - struct semaphore *semap = (sema_t *) arg1; - unsigned long *cvalp = (unsigned long *) arg2; - - if (cvalp) - cvalp[0] = RAW_COUNT(); - if (semap) - up(semap); -} - -volatile unsigned long cNval[1]; -struct semaphore tsema; - -void -pciba_timeout_test(void) -{ - unsigned long c0val, cval; - toid_t tid; - - extern void hwg_hprint(unsigned long, char *); - - sema_init(&tsema, 0); - - cNval[0] = 0; - c0val = RAW_COUNT(); - tid = timeout((void (*)()) pciba_timeout, (void *) 0, 1, (void *) cNval); - DELAY(1000000); - cval = cNval[0]; - if (cval == 0) { - untimeout(tid); - PRINT_ALERT("pciba: one-tick timeout did not happen in a second\n"); - return; - } - cval = cval - c0val; - hwg_hprint(cval, "timeout(1)"); - - cNval[0] = 0; - c0val = RAW_COUNT(); - tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, 2, (void *) cNval); - - /* FIXME : this probably needs to be down_interruptible() */ - - if (down(&tsema) < 0) { /* wait for the pciba_timeout */ - untimeout(tid); - PRINT_WARNING("pciba: timeout(2) time check aborted\n"); - return; - } - cval = cNval[0]; - if (cval == 0) { - untimeout(tid); - PRINT_WARNING("pciba: timeout(2) time not logged\n"); - return; - } - cval = cval - c0val; - hwg_hprint(cval, "timeout(2)"); - - cNval[0] = 0; - c0val = RAW_COUNT(); - tid = timeout((void (*)()) pciba_timeout, (void *) &tsema, HZ, (void *) cNval); - - /* FIXME : this probably needs to be down_interruptible() */ - - if (down(&tsema) < 0) { /* wait for the pciba_timeout */ - untimeout(tid); - PRINT_WARNING("pciba: timeout(HZ) time check aborted\n"); - return; - } - cval = cNval[0]; - if (cval == 0) { - untimeout(tid); - PRINT_WARNING("pciba: timeout(HZ) time not logged\n"); - return; - } - cval = cval - c0val; - hwg_hprint(cval, "timeout(HZ)"); - - printk("verifying untimeout() cancells ...\n"); - cNval[0] = 0; - tid = timeout((void (*)()) pciba_timeout, (void *) 0, 2, (void *) cNval); - untimeout(tid); - DELAY(1000000); - cval = cNval[0]; - if (cval != 0) { - PRINT_ALERT("pciba: unable to cancel two-tick timeout\n"); - cval -= c0val; - hwg_hprint(cval, "CANCELLED timeout(2)"); - } -} -#endif -int -pciba_reg(void) +# if 0 +static void __exit +free_nodes(void) { -#if DEBUG_PCIBA - printk("pciba_reg()\n"); -#endif - pciio_driver_register(-1, -1, "pciba_", 0); - -#if HWG_PERF_CHECK && IP30 && !DEBUG - printk("%s %d\n", __FUNCTION__, __LINE__); -pciba_timeout_test(); -#endif + struct node_data * nd; + + TRACE(); -#if DEBUG_REFCT - { - char *cname = "pciba"; - char *dname = "ptv"; - char *cpath0 = "node/xtalk/15"; - char *uname0 = "0"; - char *cpath1 = "node/xtalk/13"; - char *uname1 = "1"; - devfs_handle_t conn; - devfs_handle_t conv; - devfs_handle_t vhdl; - int ret; - - printk("pciba refct tests:\n"); - -#define SHOWREF(vhdl,func) printk("ref=%d\t%s\t(%d) %v\n", hwgraph_vertex_refct(vhdl), #func, vhdl, vhdl); - - if (GRAPH_SUCCESS != (ret = hwgraph_path_add(hwgraph_root, cname, &conv))) - printk("\tunable to create conv (ret=%d)\n", ret); - else { SHOWREF(conv, hwgraph_path_add); - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) - printk("\tunable to find %s (ret=%d)\n", cpath0, ret); - else { SHOWREF(conn, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) - printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); - else { SHOWREF(vhdl, hwgraph_char_device_add); - hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname0))) - printk("unable to create %v/%s (ret=%d)\n", conn, uname0, vhdl, ret); - else SHOWREF(vhdl, hwgraph_edge_add); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) - printk("unable to unref %v\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_unref); - } - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) - printk("unable to unref %v\n", conn); - else SHOWREF(conn, hwgraph_vertex_unref); - } - - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) - printk("\tunable to find %s (ret=%d)\n", cpath1, ret); - else { SHOWREF(conn, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_char_device_add(conn, dname, "pciba_", &vhdl))) - printk("unable to create %v/%s (ret=%d)\n", conn, dname, ret); - else { SHOWREF(vhdl, hwgraph_char_device_add); - hwgraph_chmod(vhdl, 0666); SHOWREF(vhdl, hwgraph_chmod); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_add(conv, vhdl, uname1))) - printk("unable to create %v/%s (ret=%d)\n", conn, uname1, vhdl, ret); - else SHOWREF(vhdl, hwgraph_edge_add); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) - printk("unable to unref %v\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_unref); - } - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) - printk("unable to unref %v\n", conn); - else SHOWREF(conn, hwgraph_vertex_unref); - } - - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath0, &conn))) - printk("\tunable to find %s (ret=%d)\n", cpath0, ret); - else { SHOWREF(conn, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) - printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); - else { SHOWREF(vhdl, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname0, NULL))) - printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname0, ret); - else SHOWREF(vhdl, hwgraph_edge_remove); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) - printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); - else SHOWREF(vhdl, hwgraph_edge_remove); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) - printk("unable to unref %v\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_unref); - if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) - printk("\tvertex %d destroyed OK\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_destroy); - } - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) - printk("unable to unref %v\n", conn); - else SHOWREF(conn, hwgraph_vertex_unref); - } - - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(hwgraph_root, cpath1, &conn))) - printk("\tunable to find %s (ret=%d)\n", cpath1, ret); - else { SHOWREF(conn, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_traverse(conn, dname, &vhdl))) - printk("\tunable to find %v/%s (ret=%d)\n", conn, dname, ret); - else { SHOWREF(vhdl, hwgraph_traverse); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conv, uname1, NULL))) - printk("\tunable to remove edge %v/%s (ret=%d)\n", conv, uname1, ret); - else SHOWREF(vhdl, hwgraph_edge_remove); - if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(conn, dname, NULL))) - printk("\tunable to remove edge %v/%s (ret=%d)\n", conn, dname, ret); - else SHOWREF(vhdl, hwgraph_edge_remove); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(vhdl))) - printk("unable to unref %v\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_unref); - if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(vhdl))) - printk("\tvertex %d destroyed OK\n", vhdl); - else SHOWREF(vhdl, hwgraph_vertex_destroy); - } - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conn))) - printk("unable to unref %v\n", conn); - else SHOWREF(conn, hwgraph_vertex_unref); - } - - if (GRAPH_SUCCESS != (ret = hwgraph_edge_remove(hwgraph_root, cname, NULL))) - printk("\tunable to remove edge %v/%s (ret=%d)\n", hwgraph_root, cname, ret); - else SHOWREF(conv, hwgraph_edge_remove); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_unref(conv))) - printk("unable to unref %v\n", conv); - else SHOWREF(conv, hwgraph_vertex_unref); - if (GRAPH_SUCCESS == (ret = hwgraph_vertex_destroy(conv))) - printk("\tvertex %d destroyed OK\n", conv); - else SHOWREF(conv, hwgraph_vertex_destroy); + list_for_each(nd, &node_list) { + kfree(list_entry(nd, struct nd, node_list)); } - } -#endif - - return 0; } - -#endif -int -pciba_attach(devfs_handle_t hconn) -{ -#if defined(PCIIO_SLOT_NONE) - pciio_info_t info = pciio_info_get(hconn); - pciio_slot_t slot = pciio_info_slot_get(info); #endif - pciba_comm_t comm; - pciba_bus_t bus; - int ht; - devfs_handle_t hbase; - devfs_handle_t gconn; - devfs_handle_t gbase; - int win; - int wins; - pciio_space_t space; - pciaddr_t base; - int iwins; - int mwins; -#if DEBUG_PCIBA - printk("pciba_attach(%p)\n", hconn); -#endif +static devfs_handle_t pciba_devfs_handle; - /* Pick up "dualslot guest" vertex, - * which gets all functionality except - * config space access. - */ - if ((GRAPH_SUCCESS != - hwgraph_traverse(hconn, ".guest", &gconn)) || - (hconn == gconn)) - gconn = GRAPH_VERTEX_NONE; - - bus = pciba_find_bus(hconn, 1); - bus->refct ++; - - /* set up data common to all pciba openables - * on this connection point. - */ - NEW(comm); - comm->conn = hconn; - comm->bus = bus; - comm->refct = 0; - sema_init(&comm->lock, 1); -#if !defined(PCIIO_SLOT_NONE) - if (bus->refct == 1) -#else - if (slot == PCIIO_SLOT_NONE) -#endif - { - pciio_info_t pciio_info; - devfs_handle_t master; - - pciio_info = pciio_info_get(hconn); - master = pciio_info_master_get(pciio_info); - - pciba_sub_attach(comm, PCIIO_SPACE_IO, PCIIO_SPACE_IO, 0, master, master, PCIBA_EDGE_LBL_IO); - pciba_sub_attach(comm, PCIIO_SPACE_MEM, PCIIO_SPACE_MEM, 0, master, master, PCIBA_EDGE_LBL_MEM); -#if defined(PCIIO_SLOT_NONE) - return 0; -#endif - } +#if !defined(CONFIG_IA64_SGI_SN1) - ht = 0x7F & pciio_config_get(hconn, PCI_CFG_HEADER_TYPE, 1); +static status __init +register_with_devfs(void) +{ + struct pci_dev * dev; + devfs_handle_t device_dir_handle; + char devfs_path[40]; - wins = ((ht == 0x00) ? 6 : - (ht == 0x01) ? 2 : - 0); - - mwins = iwins = 0; - - hbase = GRAPH_VERTEX_NONE; - gbase = GRAPH_VERTEX_NONE; - - for (win = 0; win < wins; win++) { - - base = pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win), 4); - if (base & 1) { - space = PCIIO_SPACE_IO; - base &= 0xFFFFFFFC; - } else if ((base & 7) == 4) { - space = PCIIO_SPACE_MEM; - base &= 0xFFFFFFF0; - base |= ((pciaddr_t) pciio_config_get(hconn, PCI_CFG_BASE_ADDR(win + 1), 4)) << 32; - } else { - space = PCIIO_SPACE_MEM; - base &= 0xFFFFFFF0; - } + TRACE(); - if (!base) - break; + pciba_devfs_handle = devfs_mk_dir(NULL, "pci", NULL); + if (pciba_devfs_handle == NULL) + return failure; -#if PCIBA_ALIGN_CHECK - if (base & (_PAGESZ - 1)) { -#if DEBUG_PCIBA - PRINT_WARNING("%p pciba: BASE%d not page aligned!\n" - "\tmmap this window at offset 0x%x via \".../pci/%s\"\n", - hconn, win, base, - (space == PCIIO_SPACE_IO) ? "io" : "mem"); -#endif - continue; /* next window */ - } -#endif + /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ + + pci_for_each_dev(dev) { + sprintf(devfs_path, "%02x/%02x.%x", + dev->bus->number, + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + device_dir_handle = + devfs_mk_dir(pciba_devfs_handle, devfs_path, NULL); + if (device_dir_handle == NULL) + return failure; - if ((hbase == GRAPH_VERTEX_NONE) && - ((GRAPH_SUCCESS != - hwgraph_path_add(hconn, PCIBA_EDGE_LBL_BASE, &hbase)) || - (hbase == GRAPH_VERTEX_NONE))) - break; /* no base vertex, no more windows. */ - - if ((gconn != GRAPH_VERTEX_NONE) && - (gbase == GRAPH_VERTEX_NONE) && - ((GRAPH_SUCCESS != - hwgraph_path_add(gconn, PCIBA_EDGE_LBL_BASE, &gbase)) || - (gbase == GRAPH_VERTEX_NONE))) - break; /* no base vertex, no more windows. */ - - pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hbase, gbase, PCIBA_EDGE_LBL_WIN(win)); - - if (space == PCIIO_SPACE_IO) { - if (!iwins++) { - pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_IO); - } - } else { - if (!mwins++) { - pciba_sub_attach(comm, PCIIO_SPACE_WIN(win), space, base, hconn, gconn, PCIBA_EDGE_LBL_MEM); - } + if (register_pci_device(device_dir_handle, dev) == failure) { + devfs_unregister(pciba_devfs_handle); + return failure; + } } - if ((base & 7) == 4) - win++; - } - - pciba_sub_attach(comm, PCIIO_SPACE_CFG, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_CFG); - pciba_sub_attach(comm, PCIBA_SPACE_UDMA, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_DMA); -#if ULI - pciba_sub_attach(comm, PCIIO_SPACE_NONE, PCIIO_SPACE_NONE, 0, hconn, gconn, PCIBA_EDGE_LBL_INTR); -#endif + return success; +} - /* XXX should ignore if device is an IOC3 */ - if (ht == 0x01) - base = pciio_config_get(hconn, PCI_EXPANSION_ROM+8, 4); - else - base = pciio_config_get(hconn, PCI_EXPANSION_ROM, 4); - - base &= 0xFFFFF000; - - if (base) { - if (base & (_PAGESZ - 1)) -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v pciba: ROM is 0x%x\n" - "\tnot page aligned, mmap will be difficult\n", - hconn, base); #else - PRINT_WARNING("0x%x pciba: ROM is 0x%x\n" - "\tnot page aligned, mmap will be difficult\n", - hconn, base); -#endif - pciba_sub_attach(comm, PCIIO_SPACE_ROM, PCIIO_SPACE_MEM, base, hconn, gconn, PCIBA_EDGE_LBL_ROM); - } -#if !FICUS /* FICUS shorts the refct by one on path_add */ - if (hbase != GRAPH_VERTEX_NONE) - hwgraph_vertex_unref(hbase); +extern devfs_handle_t +devfn_to_vertex(unsigned char busnum, unsigned int devfn); - if (gbase != GRAPH_VERTEX_NONE) - hwgraph_vertex_unref(gbase); -#endif +static status __init +register_with_devfs(void) +{ + struct pci_dev * dev; + devfs_handle_t device_dir_handle; - return 0; -} + TRACE(); -static void -pciba_sub_attach2(pciba_comm_t comm, - pciio_space_t space, - pciio_space_t iomem, - pciaddr_t base, - devfs_handle_t from, - char *name, - char *suf, - unsigned bigend) -{ - char nbuf[128]; - pciba_soft_t soft; - devfs_handle_t handle = NULL; - - if (suf && *suf) { - strcpy(nbuf, name); - name = nbuf; - strcat(name, suf); - } - -#if DEBUG_PCIBA - printk("pciba_sub_attach2 %p/%s %p at %p[%x]\n", - from, name, space, space_desc, iomem, space_desc, base, from, name); -#endif + /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */ - if (space < TRACKED_SPACES) - if ((soft = comm->soft[space][bigend]) != NULL) { - soft->refct ++; - hwgraph_edge_add(from, soft->vhdl, name); - return; + pci_for_each_dev(dev) { + device_dir_handle = devfn_to_vertex(dev->bus->number, + dev->devfn); + if (device_dir_handle == NULL) + return failure; + + if (register_pci_device(device_dir_handle, dev) == failure) { + devfs_unregister(pciba_devfs_handle); + return failure; + } } - NEW(soft); - if (!soft) - return; - - soft->comm = comm; - soft->space = space; - soft->size = 0; - soft->iomem = iomem; - soft->base = base; - soft->refct = 1; - - if (space == PCIIO_SPACE_NONE) - soft->flags = 0; - else if (bigend) - soft->flags = PCIIO_BYTE_STREAM; - else - soft->flags = PCIIO_WORD_VALUES; - - handle = hwgraph_register(from, name, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pciba_fops, NULL); - soft->vhdl = handle; - pciba_soft_set(soft->vhdl, soft); - if (space < TRACKED_SPACES) - comm->soft[space][bigend] = soft; - comm->refct ++; + return success; } -static void -pciba_sub_attach1(pciba_comm_t comm, - pciio_space_t space, - pciio_space_t iomem, - pciaddr_t base, - devfs_handle_t hfrom, - devfs_handle_t gfrom, - char *name, - char *suf, - unsigned bigend) -{ - pciba_sub_attach2(comm, space, iomem, base, hfrom, name, suf, bigend); - if ((gfrom != GRAPH_VERTEX_NONE) && (gfrom != hfrom)) - pciba_sub_attach2(comm, space, iomem, base, gfrom, name, suf, bigend); -} +#endif /* CONFIG_IA64_SGI_SN1 */ + + +static void __exit +unregister_with_devfs(void) +{ + struct list_head * lhp; + struct node_data * nd; + + TRACE(); + + list_for_each(lhp, &global_node_list) { + nd = list_entry(lhp, struct node_data, global_node_list); + devfs_unregister(nd->devfs_handle); + } -static void -pciba_sub_attach(pciba_comm_t comm, - pciio_space_t space, - pciio_space_t iomem, - pciaddr_t base, - devfs_handle_t hfrom, - devfs_handle_t gfrom, - char *name) -{ - pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, NULL, 0); - if (iomem != PCIIO_SPACE_NONE) { - pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_le", 0); - pciba_sub_attach1(comm, space, iomem, base, hfrom, gfrom, name, "_be", 1); - } } -#ifdef LATER -static void -pciba_reload_me(devfs_handle_t pconn_vhdl) + +struct node_data * new_node(void) { - devfs_handle_t vhdl; + struct node_data * node; + + TRACE(); + + node = kmalloc(sizeof(struct node_data), GFP_KERNEL); + if (node == NULL) + return NULL; + list_add(&node->global_node_list, &global_node_list); + return node; +} -#if DEBUG_PCIBA - printf("pciba_reload_me(%v)\n", pconn_vhdl); -#endif - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &vhdl)) - return; +void dma_cleanup(struct node_data * dma_node) +{ + TRACE(); - hwgraph_vertex_unref(vhdl); + /* FIXME: should free these allocations */ +#ifdef DEBUG_PCIBA + dump_allocations(&dma_node->u.dma.dma_allocs); +#endif + devfs_unregister(dma_node->devfs_handle); } -#endif /* LATER */ -static pciba_bus_t -pciba_find_bus(devfs_handle_t pconn, int cflag) + +void init_dma_node(struct node_data * node, + struct pci_dev * dev, devfs_handle_t dh) { - pciio_info_t pciio_info; - devfs_handle_t master; - arbitrary_info_t ainfo; - pciba_bus_t bus; + TRACE(); - pciio_info = pciio_info_get(pconn); - master = pciio_info_master_get(pciio_info); + node->devfs_handle = dh; + node->u.dma.dev = dev; + node->cleanup = dma_cleanup; + INIT_LIST_HEAD(&node->u.dma.dma_allocs); +} - if (GRAPH_SUCCESS == - hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo)) - return (pciba_bus_t) ainfo; - if (!cflag) - return 0; +void rom_cleanup(struct node_data * rom_node) +{ + TRACE(); - NEW(bus); - if (!bus) - return 0; + if (rom_node->u.rom.mmapped) + pci_write_config_dword(rom_node->u.rom.dev, + PCI_ROM_ADDRESS, + rom_node->u.rom.saved_rom_base_reg); + devfs_unregister(rom_node->devfs_handle); +} - sema_init(&bus->lock, 1); - ainfo = (arbitrary_info_t) bus; - hwgraph_info_add_LBL(master, PCIBA_INFO_LBL_BUS, ainfo); - hwgraph_info_get_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); - if ((pciba_bus_t) ainfo != bus) - DEL(bus); -#if DEBUG_PCIBA - else - printk("pcbia_find_bus: new bus at %p\n", master); -#endif +void init_rom_node(struct node_data * node, + struct pci_dev * dev, devfs_handle_t dh) +{ + TRACE(); - return (pciba_bus_t) ainfo; + node->devfs_handle = dh; + node->u.rom.dev = dev; + node->cleanup = rom_cleanup; + node->u.rom.mmapped = false; } -#ifdef LATER -static void -pciba_map_push(pciba_bus_t bus, pciba_map_t map) + +static status __init +register_pci_device(devfs_handle_t device_dir_handle, struct pci_dev * dev) { -#if DEBUG_PCIBA - printk("pciba_map_push(bus=0x%x, map=0x%x, hdl=0x%x\n", - bus, map, map->handle); -#endif - pciba_bus_lock(bus); - map->next = bus->maps; - bus->maps = map; - pciba_bus_unlock(bus); -} - -static pciba_map_t -pciba_map_pop_hdl(pciba_bus_t bus, __psunsigned_t handle) -{ - pciba_map_h hdl; - pciba_map_t map; - - pciba_bus_lock(bus); - for (hdl = &bus->maps; map = *hdl; hdl = &map->next) - if (map->handle == handle) { - *hdl = map->next; - break; + struct node_data * nd; + char devfs_path[20]; + devfs_handle_t node_devfs_handle; + int ri; + + TRACE(); + + + /* register nodes for all the device's base address registers */ + for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { + if (pci_resource_len(dev, ri) != 0) { + sprintf(devfs_path, "base/%d", ri); + if (devfs_register(device_dir_handle, devfs_path, + DEVFS_FL_NONE, + 0, 0, + S_IFREG | S_IRUSR | S_IWUSR, + &base_fops, + &dev->resource[ri]) == NULL) + return failure; + } } - pciba_bus_unlock(bus); -#if DEBUG_PCIBA - printk("pciba_map_pop_va(bus=0x%x, handle=0x%x) returns map=0x%x\n", - bus, handle, map); + + /* register a node corresponding to the first MEM resource on + the device */ + for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { + if (dev->resource[ri].flags & IORESOURCE_MEM && + pci_resource_len(dev, ri) != 0) { + if (devfs_register(device_dir_handle, "mem", + DEVFS_FL_NONE, 0, 0, + S_IFREG | S_IRUSR | S_IWUSR, + &base_fops, + &dev->resource[ri]) == NULL) + return failure; + break; + } + } + + /* also register a node corresponding to the first IO resource + on the device */ + for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { + if (dev->resource[ri].flags & IORESOURCE_IO && + pci_resource_len(dev, ri) != 0) { + if (devfs_register(device_dir_handle, "io", + DEVFS_FL_NONE, 0, 0, + S_IFREG | S_IRUSR | S_IWUSR, + &base_fops, + &dev->resource[ri]) == NULL) + return failure; + break; + } + } + + /* register a node corresponding to the device's ROM resource, + if present */ + if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) { + nd = new_node(); + if (nd == NULL) + return failure; + node_devfs_handle = devfs_register(device_dir_handle, "rom", + DEVFS_FL_NONE, 0, 0, + S_IFREG | S_IRUSR, + &rom_fops, nd); + if (node_devfs_handle == NULL) + return failure; + init_rom_node(nd, dev, node_devfs_handle); + } + + /* register a node that allows ioctl's to read and write to + the device's config space */ + if (devfs_register(device_dir_handle, "config", DEVFS_FL_NONE, + 0, 0, S_IFREG | S_IRUSR | S_IWUSR, + &config_fops, dev) == NULL) + return failure; + + + /* finally, register a node that allows ioctl's to allocate + and free DMA buffers, as well as memory map those + buffers. */ + nd = new_node(); + if (nd == NULL) + return failure; + node_devfs_handle = + devfs_register(device_dir_handle, "dma", DEVFS_FL_NONE, + 0, 0, S_IFREG | S_IRUSR | S_IWUSR, + &dma_fops, nd); + if (node_devfs_handle == NULL) + return failure; + init_dma_node(nd, dev, node_devfs_handle); + +#ifdef DEBUG_PCIBA + dump_nodes(&global_node_list); #endif - return map; + + return success; } -/* ================================================================ - * driver teardown, unregister and unload - */ -int -pciba_unload(void) -{ -#if DEBUG_PCIBA - printk("pciba_unload()\n"); -#endif - if (atomic_read(&pciba_prevent_unload)) - return -1; +static int +generic_open(struct inode * inode, struct file * file) +{ + TRACE(); - pciio_iterate("pciba_", pciba_unload_me); + /* FIXME: should check that they're not trying to open the ROM + writable */ - return 0; + return 0; /* success */ } -int -pciba_unreg(void) + +static int +rom_mmap(struct file * file, struct vm_area_struct * vma) { + unsigned long pci_pa; + struct node_data * nd; -#if DEBUG_PCIBA - printf("pciba_unreg()\n"); -#endif + TRACE(); - if (atomic_read(&pciba_prevent_unload)) - return -1; + nd = (struct node_data * )file->private_data; - pciio_driver_unregister("pciba_"); - return 0; + pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE); + + if (!nd->u.rom.mmapped) { + nd->u.rom.mmapped = true; + DPRINTF("Enabling ROM address decoder.\n"); + DPRINTF( +"rom_mmap: FIXME: some cards do not allow both ROM and memory addresses to\n" +"rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.\n"); + pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, + &nd->u.rom.saved_rom_base_reg); + DPRINTF("ROM base address contains %x\n", + nd->u.rom.saved_rom_base_reg); + pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, + nd->u.rom.saved_rom_base_reg | + PCI_ROM_ADDRESS_ENABLE); + } + + return mmap_pci_address(vma, pci_pa); } -int -pciba_detach(devfs_handle_t conn) + +static int +rom_release(struct inode * inode, struct file * file) { - devfs_handle_t base; - pciba_bus_t bus; - devfs_handle_t gconn; - devfs_handle_t gbase; + struct node_data * nd; - pciio_info_t pciio_info; - devfs_handle_t master; - arbitrary_info_t ainfo; - int ret; + TRACE(); -#if DEBUG_PCIBA - printf("pciba_detach(%v)\n", conn); -#endif + nd = (struct node_data * )file->private_data; - if ((GRAPH_SUCCESS != - hwgraph_traverse(conn, ".guest", &gconn)) || - (conn == gconn)) - gconn = GRAPH_VERTEX_NONE; - - if (gconn != GRAPH_VERTEX_NONE) { - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_CFG); - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_DMA); - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_ROM); -#if ULI - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_INTR); -#endif - if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &gbase)) { - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_MEM); - pciba_sub_detach(gconn, PCIBA_EDGE_LBL_IO); - pciba_sub_detach(gbase, "0"); - pciba_sub_detach(gbase, "1"); - pciba_sub_detach(gbase, "2"); - pciba_sub_detach(gbase, "3"); - pciba_sub_detach(gbase, "4"); - pciba_sub_detach(gbase, "5"); - hwgraph_vertex_unref(gbase); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(gbase))) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", - conn, ret); -#else - PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", - conn, ret); -#endif -#if DEBUG_REFCT - printk("\tretained refct %d\n", hwgraph_vertex_refct(gbase)); -#endif - } + if (nd->u.rom.mmapped) { + nd->u.rom.mmapped = false; + DPRINTF("Disabling ROM address decoder.\n"); + pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, + nd->u.rom.saved_rom_base_reg); } - } + return 0; /* indicate success */ +} - pciba_sub_detach(conn, PCIBA_EDGE_LBL_CFG); - pciba_sub_detach(conn, PCIBA_EDGE_LBL_DMA); - pciba_sub_detach(conn, PCIBA_EDGE_LBL_ROM); -#if ULI - pciba_sub_detach(conn, PCIBA_EDGE_LBL_INTR); -#endif - if (GRAPH_SUCCESS == hwgraph_edge_remove(conn, PCIBA_EDGE_LBL_BASE, &base)) { - pciba_sub_detach(conn, PCIBA_EDGE_LBL_MEM); - pciba_sub_detach(conn, PCIBA_EDGE_LBL_IO); - pciba_sub_detach(base, "0"); - pciba_sub_detach(base, "1"); - pciba_sub_detach(base, "2"); - pciba_sub_detach(base, "3"); - pciba_sub_detach(base, "4"); - pciba_sub_detach(base, "5"); - hwgraph_vertex_unref(base); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(base))) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(%v/base) failed (%d)", - conn, ret); -#else - PRINT_WARNING(CE_WARN, "pciba: hwgraph_vertex_destroy(0x%x/base) failed (%d)", - conn, ret); -#endif -#if DEBUG_REFCT - printk("\tretained refct %d\n", hwgraph_vertex_refct(base)); -#endif - } - } +static int +base_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct resource * resource; - bus = pciba_find_bus(conn, 0); - if (bus && !--(bus->refct)) { + TRACE(); - pciio_info = pciio_info_get(conn); + resource = (struct resource *)file->private_data; - master = pciio_info_master_get(pciio_info); + return mmap_pci_address(vma, resource->start); +} - pciba_sub_detach(master, PCIBA_EDGE_LBL_IO); - pciba_sub_detach(master, PCIBA_EDGE_LBL_MEM); - pciba_sub_detach(master, PCIBA_EDGE_LBL_CFG); - hwgraph_info_remove_LBL(master, PCIBA_INFO_LBL_BUS, &ainfo); -#if DEBUG_PCIBA - printf("pcbia_detach: DEL(bus) at %v\n", master); -#endif - DEL(bus); - } +static int +config_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, + unsigned long arg) +{ + struct pci_dev * dev; - return 0; -} + union cfg_data { + uint8_t byte; + uint16_t word; + uint32_t dword; + } read_data, write_data; -static void -pciba_sub_detach1(devfs_handle_t conn, - char *name, - char *suf) -{ - devfs_handle_t vhdl; - pciba_soft_t soft; - pciba_comm_t comm; - int ret; - char nbuf[128]; - - if (suf && *suf) { - strcpy(nbuf, name); - name = nbuf; - strcat(name, suf); - } - - if ((GRAPH_SUCCESS == hwgraph_edge_remove(conn, name, &vhdl)) && - ((soft = pciba_soft_get(vhdl)) != NULL)) { -#if DEBUG_PCIBA -#if defined(SUPPORT_PRINTING_V_FORMAT) - prink("pciba_sub_detach(%v,%s)\n", conn, name); -#else - prink("pciba_sub_detach(0x%x,%s)\n", conn, name); -#endif -#endif + int dir, size, offset; - hwgraph_vertex_unref(soft->vhdl); -#if DEBUG_REFCT - printk("\tadjusted refct %d (soft ref: %d)\n", - hwgraph_vertex_refct(vhdl), - soft->refct); -#endif - if (!--(soft->refct)) { - comm = soft->comm; - if (!--(comm->refct)) { - DEL(comm); - } - pciba_soft_set(vhdl, 0); - DEL(soft); - - hwgraph_vertex_unref(vhdl); - if (GRAPH_SUCCESS != (ret = hwgraph_vertex_destroy(vhdl))) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("pciba: hwgraph_vertex_destroy(0x%x/%s) failed (%d)", - conn, name, ret); -#else - PRINT_WARNING("pciba: hwgraph_vertex_destroy(%v/%s) failed (%d)", - conn, name, ret); -#endif -#if DEBUG_REFCT - printk("\tretained refct %d\n", hwgraph_vertex_refct(vhdl)); -#endif - } - } - } -} + TRACE(); -static void -pciba_sub_detach(devfs_handle_t conn, - char *name) -{ - pciba_sub_detach1(conn, name, ""); - pciba_sub_detach1(conn, name, "_le"); - pciba_sub_detach1(conn, name, "_be"); -} + DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)\n", + cmd, + _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); + DPRINTF("arg = %lx\n", arg); -static void -pciba_unload_me(devfs_handle_t pconn_vhdl) -{ - devfs_handle_t c_vhdl; + dev = (struct pci_dev *)file->private_data; -#if DEBUG_PCIBA - printf("pciba_unload_me(%v)\n", pconn_vhdl); -#endif + /* PCIIOCCFG{RD,WR}: read and/or write PCI configuration + space. If both, the read happens first (this becomes a swap + operation, atomic with respect to other updates through + this path). */ - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, PCIBA_EDGE_LBL_CFG, &c_vhdl)) - return; + dir = _IOC_DIR(cmd); - hwgraph_vertex_unref(c_vhdl); -} +#define do_swap(suffix, type) \ + do { \ + if (dir & _IOC_READ) { \ + pci_read_config_##suffix(dev, _IOC_NR(cmd), \ + &read_data.suffix); \ + } \ + if (dir & _IOC_WRITE) { \ + get_user(write_data.suffix, (type)arg); \ + pci_write_config_##suffix(dev, _IOC_NR(cmd), \ + write_data.suffix); \ + } \ + if (dir & _IOC_READ) { \ + put_user(read_data.suffix, (type)arg); \ + } \ + } while (0) -/* ================================================================ - * standard unix entry points - */ + size = _IOC_SIZE(cmd); + offset = _IOC_NR(cmd); -/*ARGSUSED */ -int -pciba_open(dev_t *devp, int flag, int otyp, struct cred *crp) -{ + DPRINTF("sanity check\n"); + if (((size > 0) || (size <= 4)) && + ((offset + size) <= 256) && + (dir & (_IOC_READ | _IOC_WRITE))) { -#if DEBUG_PCIBA - printf("pciba_open(%V)\n", *devp); -#endif - return 0; + switch (size) + { + case 1: + do_swap(byte, uint8_t *); + break; + case 2: + do_swap(word, uint16_t *); + break; + case 4: + do_swap(dword, uint32_t *); + break; + default: + DPRINTF("invalid ioctl\n"); + return -EINVAL; + } + } else + return -EINVAL; + + return 0; } -/*ARGSUSED */ -int -pciba_close(dev_t dev) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - pciba_soft_t soft = pciba_soft_get(vhdl); - -#if DEBUG_PCIBA - printf("pciba_close(%V)\n", dev); -#endif - /* if there is pending DMA for this device, hit the - * device over the head with a baseball bat and - * release the system memory resources. - */ - if (soft && soft->comm->dmap) { - pciba_dma_t next; - pciba_dma_t dmap; - - pciba_soft_lock(soft); - if (dmap = soft->comm->dmap) { - soft->comm->dmap = 0; - - pciio_reset(soft->comm->conn); - - do { - if (!dmap->kaddr) - break; - if (!dmap->paddr) - break; - if (dmap->bytes < NBPP) - break; - next = dmap->next; - kvpfree(dmap->kaddr, dmap->bytes / NBPP); - dmap->paddr = 0; - dmap->bytes = 0; - DEL(dmap); - } while (dmap = next); +#ifdef DEBUG_PCIBA +static void +dump_allocations(struct list_head * dalp) +{ + struct dma_allocation * dap; + struct list_head * p; + + printk("{\n"); + list_for_each(p, dalp) { + dap = list_entry(p, struct dma_allocation, + list); + printk(" handle = %lx, va = %p\n", + dap->handle, dap->va); } - pciba_soft_unlock(soft); - } - return 0; + printk("}\n"); } -/* ARGSUSED */ -int -pciba_read(dev_t dev, cred_t *crp) +static void +dump_nodes(struct list_head * nodes) { -#if DEBUG_PCIBA - printf("pciba_read(%V)\n", dev); -#endif - - return EINVAL; + struct node_data * ndp; + struct list_head * p; + + printk("{\n"); + list_for_each(p, nodes) { + ndp = list_entry(p, struct node_data, + global_node_list); + printk(" %p\n", (void *)ndp); + } + printk("}\n"); } -/* ARGSUSED */ -int -pciba_write(dev_t dev, cred_t *crp) + +#if 0 +#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) + +static void +test_list(void) { -#if DEBUG_PCIBA - printf("pciba_write(%V)\n", dev); -#endif + u64 i; + LIST_HEAD(the_list); - return EINVAL; + for (i = 0; i < 5; i++) { + struct dma_allocation * new_alloc; + NEW(new_alloc); + new_alloc->va = (void *)i; + new_alloc->handle = 5*i; + printk("%d - the_list->next = %lx\n", i, the_list.next); + list_add(&new_alloc->list, &the_list); + } + dump_allocations(&the_list); } - -/*ARGSUSED */ -int -pciba_ioctl(dev_t dev, int cmd, void *uarg, int mode, cred_t *crp, int *rvalp) -{ - devfs_handle_t vhdl; - pciba_soft_t soft; - pciio_space_t space; - ioctl_arg_buffer_t arg; - int psize; - int err = 0; - -#if ULI - char abi = get_current_abi(); - pciio_intr_t intr=0; - device_desc_t desc; - cpuid_t intrcpu; - unsigned lines; - struct uli *uli = 0; #endif - unsigned flags; - void *kaddr = 0; - iopaddr_t paddr; - pciba_dma_h dmah; - pciba_dma_t dmap = 0; - pciio_dmamap_t dmamap = 0; - size_t bytes; - int pages; - pciaddr_t daddr; - -#if DEBUG_PCIBA - printf("pciba_ioctl(%V,0x%x)\n", dev, cmd); #endif - psize = (cmd >> 16) & IOCPARM_MASK; - -#if ULI - ASSERT(sizeof(struct uliargs) > 8); /* prevent CFG access conflict */ - ASSERT(sizeof(struct uliargs) <= IOCPARM_MASK); -#endif - arg.ca = uarg; +static LIST_HEAD(dma_buffer_list); - if ((psize > 0) && (cmd & (IOC_OUT | IOC_IN))) { - if (psize > sizeof(arg)) - err = EINVAL; /* "bad parameter size */ - else { - if (cmd & IOC_OUT) - bzero(arg.data, psize); - if ((cmd & IOC_IN) && - (copyin(uarg, arg.data, psize) < 0)) - err = EFAULT; /* "parameter copyin failed" */ - } - } - vhdl = dev_to_vhdl(dev); - soft = pciba_soft_get(vhdl); - space = soft->space; - - if (err == 0) { - err = EINVAL; /* "invalid ioctl for this vertex" */ - switch (space) { -#if ULI - case PCIIO_SPACE_NONE: /* the "intr" vertex */ - /* PCIIOCSETULI: set up user interrupts. - */ - lines = cmd & 15; - if (ABI_IS_64BIT(abi)) { - if (cmd != PCIIOCSETULI(lines)) { - err = EINVAL; /* "invalid ioctl for this vertex" */ - break; - } - } - else { - struct uliargs uliargs; - - if (cmd != PCIIOCSETULI32(lines)) { - err = EINVAL; /* "invalid ioctl for this vertex" */ - break; - } - - uliargs32_to_uliargs(&arg.uli32, &uliargs); - arg.uli = uliargs; - } - desc = device_desc_dup(soft->comm->conn); - device_desc_flags_set(desc, (device_desc_flags_get(desc) | - D_INTR_NOTHREAD)); - device_desc_intr_swlevel_set(desc, INTR_SWLEVEL_NOTHREAD_DEFAULT); - device_desc_intr_name_set(desc, "PCIBA"); - device_desc_default_set(soft->comm->conn, desc); - - /* When designating interrupts, the slot number - * is taken from the connection point. - * Bits 0..3 are used to select INTA..INTD; more - * than one bit can be specified. These should - * be constructed using PCIIO_INTR_LINE_[ABCD]. - */ - intr = pciio_intr_alloc - (soft->comm->conn, desc, lines, soft->vhdl); - if (intr == 0) { - err = ENOMEM; /* "insufficient resources" */ - break; - } - intrcpu = cpuvertex_to_cpuid(pciio_intr_cpu_get(intr)); - if (err = new_uli(&arg.uli, &uli, intrcpu)) { - break; /* "unable to set up ULI" */ - } - atomic_inc(&pciba_prevent_unload); - - pciio_intr_connect(intr, pciba_intr, uli, (void *) 0); - - /* NOTE: don't set the teardown function - * until the interrupt is connected. - */ - uli->teardownarg1 = (__psint_t) intr; - uli->teardown = pciba_clearuli; - - arg.uli.id = uli->index; - - if (!ABI_IS_64BIT(abi)) { - struct uliargs32 uliargs32; - uliargs_to_uliargs32(&arg.uli, &uliargs32); - arg.uli32 = uliargs32; - } +static int +dma_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, + unsigned long arg) +{ + struct node_data * nd; + uint64_t argv; + int result; + struct dma_allocation * dma_alloc; + struct list_head * iterp; - err = 0; - break; -#endif + TRACE(); - case PCIBA_SPACE_UDMA: /* the "dma" vertex */ + DPRINTF("cmd = %x\n", cmd); + DPRINTF("arg = %lx\n", arg); - switch (cmd) { + nd = (struct node_data *)file->private_data; - case PCIIOCDMAALLOC: - /* PCIIOCDMAALLOC: allocate a chunk of physical - * memory and set it up for DMA. Return the - * PCI address that gets to it. - * NOTE: this allocates memory local to the - * CPU doing the ioctl, not local to the - * device that will be doing the DMA. - */ - - if (!_CAP_ABLE(CAP_DEVICE_MGT)) { - err = EPERM; - break; - } - /* separate the halves of the incoming parameter */ - flags = arg.ud >> 32; - bytes = arg.ud & 0xFFFFFFFF; - -#if DEBUG_PCIBA - printf("pciba: user wants 0x%x bytes of DMA, flags 0x%x\n", - bytes, flags); +#ifdef DEBUG_PCIBA + DPRINTF("at dma_ioctl entry\n"); + dump_allocations(&nd->u.dma.dma_allocs); #endif - /* round up the requested size to the next highest page */ - pages = (bytes + NBPP - 1) / NBPP; - - /* make sure the requested size is something reasonable */ - if (pages > pci_user_dma_max_pages) { -#if DEBUG_PCIBA - printf("pciba: request for too much buffer space\n"); + switch (cmd) { + case PCIIOCDMAALLOC: + /* PCIIOCDMAALLOC: allocate a chunk of physical memory + and set it up for DMA. Return the PCI address that + gets to it. */ + DPRINTF("case PCIIOCDMAALLOC (%lx)\n", PCIIOCDMAALLOC); + + if ( (result = get_user(argv, (uint64_t *)arg)) ) + return result; + DPRINTF("argv (size of buffer) = %lx\n", argv); + + dma_alloc = (struct dma_allocation *) + kmalloc(sizeof(struct dma_allocation), GFP_KERNEL); + if (dma_alloc == NULL) + return -ENOMEM; + + dma_alloc->size = (size_t)argv; + dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev, + dma_alloc->size, + &dma_alloc->handle); + DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lx\n", + dma_alloc->va, dma_alloc->handle); + if (dma_alloc->va == NULL) { + kfree(dma_alloc); + return -ENOMEM; + } + + list_add(&dma_alloc->list, &nd->u.dma.dma_allocs); + if ( (result = put_user((uint64_t)dma_alloc->handle, + (uint64_t *)arg)) ) { + DPRINTF("put_user failed\n"); + pci_free_consistent(nd->u.dma.dev, (size_t)argv, + dma_alloc->va, dma_alloc->handle); + kfree(dma_alloc); + return result; + } + +#ifdef DEBUG_PCIBA + DPRINTF("after insertion\n"); + dump_allocations(&nd->u.dma.dma_allocs); #endif - err = EINVAL; - break; /* "request for too much buffer space" */ - } - /* "correct" number of bytes */ - bytes = pages * NBPP; + break; - /* allocate the space */ - /* XXX- force to same node as the device? */ - /* XXX- someday, we want to handle user buffers, - * and noncontiguous pages, but this will - * require either fancy mapping or handing - * a list of blocks back to the user. For - * now, just tell users to allocate a lot of - * individual single-pages and manage their - * scatter-gather manually. - */ - kaddr = kvpalloc(pages, VM_DIRECT | KM_NOSLEEP, 0); - if (kaddr == 0) { -#if DEBUG_PCIBA - printf("pciba: unable to get %d contiguous pages\n", pages); -#endif - err = EAGAIN; /* "insufficient resources, try again later" */ - break; - } -#if DEBUG_PCIBA - printf("pciba: kaddr is 0x%x\n", kaddr); -#endif - paddr = kvtophys(kaddr); + case PCIIOCDMAFREE: + DPRINTF("case PCIIOCDMAFREE (%lx)\n", PCIIOCDMAFREE); - daddr = pciio_dmatrans_addr - (soft->comm->conn, 0, paddr, bytes, flags); - if (daddr == 0) { /* "no direct path available" */ -#if DEBUG_PCIBA - printf("pciba: dmatrans failed, trying dmamap\n"); -#endif - dmamap = pciio_dmamap_alloc - (soft->comm->conn, 0, bytes, flags); - if (dmamap == 0) { -#if DEBUG_PCIBA - printf("pciba: unable to allocate dmamap\n"); -#endif - err = ENOMEM; - break; /* "out of mapping resources" */ - } - daddr = pciio_dmamap_addr - (dmamap, paddr, bytes); - if (daddr == 0) { -#if DEBUG_PCIBA - printf("pciba: dmamap_addr failed\n"); -#endif - err = EINVAL; - break; /* "can't get there from here" */ - } - } -#if DEBUG_PCIBA - printf("pciba: daddr is 0x%x\n", daddr); + if ( (result = get_user(argv, (uint64_t *)arg)) ) { + DPRINTF("get_user failed\n"); + return result; + } + + DPRINTF("argv (physical address of DMA buffer) = %lx\n", argv); + list_for_each(iterp, &nd->u.dma.dma_allocs) { + struct dma_allocation * da = + list_entry(iterp, struct dma_allocation, list); + if (da->handle == argv) { + pci_free_consistent(nd->u.dma.dev, da->size, + da->va, da->handle); + list_del(&da->list); + kfree(da); +#ifdef DEBUG_PCIBA + DPRINTF("after deletion\n"); + dump_allocations(&nd->u.dma.dma_allocs); #endif - NEW(dmap); - if (!dmap) { - err = ENOMEM; - break; /* "no memory available" */ + return 0; /* success */ + } } - dmap->bytes = bytes; - dmap->pages = pages; - dmap->paddr = paddr; - dmap->kaddr = kaddr; - dmap->map = dmamap; - dmap->daddr = daddr; - dmap->handle = 0; - -#if DEBUG_PCIBA - printf("pciba: dmap 0x%x contains va 0x%x bytes 0x%x pa 0x%x pages 0x%x daddr 0x%x\n", - dmap, kaddr, bytes, paddr, pages, daddr); -#endif + /* previously allocated dma buffer wasn't found */ + DPRINTF("attempt to free invalid dma handle\n"); + return -EINVAL; - arg.ud = dmap->daddr; + default: + DPRINTF("undefined ioctl\n"); + return -EINVAL; + } - err = 0; - break; + DPRINTF("success\n"); + return 0; +} + - case PCIIOCDMAFREE: - /* PCIIOCDMAFREE: Find the chunk of - * User DMA memory, and release its - * resources back to the system. - */ - - if (!_CAP_ABLE(CAP_DEVICE_MGT)) { - err = EPERM; /* "you can't do that" */ - break; - } - if (soft->comm->dmap == NULL) { - err = EINVAL; /* "no User DMA to free" */ - break; - } - /* find the request. */ - daddr = arg.ud; - err = EINVAL; /* "block not found" */ - pciba_soft_lock(soft); - for (dmah = &soft->comm->dmap; dmap = *dmah; dmah = &dmap->next) { - if (dmap->daddr == daddr) { - if (dmap->handle != 0) { - dmap = 0; /* don't DEL this dmap! */ - err = EINVAL; /* "please unmap first" */ - break; /* break outa for loop. */ - } - *dmah = dmap->next; +static int +dma_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct node_data * nd; + struct list_head * iterp; + int result; + + TRACE(); - if (dmamap = dmap->map) { - pciio_dmamap_free(dmamap); - dmamap = 0; /* don't free it twice! */ + nd = (struct node_data *)file->private_data; + + DPRINTF("vma->vm_start is %lx\n", vma->vm_start); + DPRINTF("vma->vm_end is %lx\n", vma->vm_end); + DPRINTF("offset = %lx\n", vma->vm_pgoff); + + /* get kernel virtual address for the dma buffer (necessary + * for the mmap). */ + list_for_each(iterp, &nd->u.dma.dma_allocs) { + struct dma_allocation * da = + list_entry(iterp, struct dma_allocation, list); + /* why does mmap shift its offset argument? */ + if (da->handle == vma->vm_pgoff << PAGE_SHIFT) { + DPRINTF("found dma handle\n"); + if ( (result = mmap_kernel_address(vma, + da->va)) ) { + return result; /* failure */ + } else { + /* it seems like at least one of these + should show up in user land.... + I'm missing something */ + *(char *)da->va = 0xaa; + strncpy(da->va, " Toastie!", da->size); + if (put_user(0x18badbeeful, + (u64 *)vma->vm_start)) + DPRINTF("put_user failed?!\n"); + return 0; /* success */ } - kvpfree(dmap->kaddr, dmap->bytes / NBPP); - DEL(dmap); - dmap = 0; /* don't link this back into the list! */ - err = 0; /* "all done" */ - break; /* break outa for loop. */ - } - } - pciba_soft_unlock(soft); - break; /* break outa case PCIIOCDMAFREE: */ - } - break; /* break outa case PCIBA_SPACE_UDMA: */ - - case PCIIO_SPACE_CFG: - - /* PCIIOCCFG{RD,WR}: read and/or write - * PCI configuration space. If both, - * the read happens first (this becomes - * a swap operation, atomic with respect - * to other updates through this path). - * - * Should be *last* IOCTl command checked, - * so other patterns can nip useless codes - * out of the space this decodes. - */ - err = EINVAL; - if ((psize > 0) || (psize <= 8) && - (((cmd & 0xFF) + psize) <= 256) && - (cmd & (IOC_IN | IOC_OUT))) { - - uint64_t rdata; - uint64_t wdata; - int shft; - - shft = 64 - (8 * psize); - - wdata = arg.ud >> shft; - - pciba_soft_lock(soft); - - if (cmd & IOC_OUT) - rdata = pciio_config_get(soft->comm->conn, cmd & 0xFFFF, psize); - if (cmd & IOC_IN) - pciio_config_set(soft->comm->conn, cmd & 0xFFFF, psize, wdata); - - pciba_soft_unlock(soft); - arg.ud = rdata << shft; - err = 0; - break; - } - break; - } - } - /* done: come here if all went OK. - */ - if ((err == 0) && - ((cmd & IOC_OUT) && (psize > 0)) && - copyout(arg.data, uarg, psize)) - err = EFAULT; - - /* This gets delayed until after the copyout so we - * do not free the dmap on a copyout error, or - * alternately end up with a dangling allocated - * buffer that the user never got back. - */ - if ((err == 0) && dmap) { - pciba_soft_lock(soft); - dmap->next = soft->comm->dmap; - soft->comm->dmap = dmap; - pciba_soft_unlock(soft); - } - if (err) { - /* Things went badly. Clean up. - */ -#if ULI - if (intr) { - pciio_intr_disconnect(intr); - pciio_intr_free(intr); - } - if (uli) - free_uli(uli); -#endif - if (dmap) { - if (dmap->map && (dmap->map != dmamap)) - pciio_dmamap_free(dmap->map); - DEL(dmap); + } } - if (dmamap) - pciio_dmamap_free(dmamap); - if (kaddr) - kvpfree(kaddr, pages); - } - return *rvalp = err; + DPRINTF("attempt to mmap an invalid dma handle\n"); + return -EINVAL; } -/* ================================================================ - * mapping support - */ - -/*ARGSUSED */ -int -pciba_map(dev_t dev, vhandl_t *vt, - off_t off, size_t len, uint32_t prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - pciba_soft_t soft = pciba_soft_get(vhdl); - devfs_handle_t conn = soft->comm->conn; - pciio_space_t space = soft->space; - size_t pages = (len + NBPP - 1) / NBPP; - pciio_piomap_t pciio_piomap = 0; - caddr_t kaddr; - pciba_map_t map; - pciba_dma_t dmap; -#if DEBUG_PCIBA - printf("pciba_map(%V,vt=0x%x)\n", dev, vt); -#endif +static int +mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va) +{ + unsigned long pci_pa; - if (space == PCIBA_SPACE_UDMA) { - pciba_soft_lock(soft); + TRACE(); - for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) { - if (off == dmap->daddr) { - if (pages != dmap->pages) { - pciba_soft_unlock(soft); - return EINVAL; /* "size mismatch" */ - } - v_mapphys(vt, dmap->kaddr, dmap->bytes); - dmap->handle = v_gethandle(vt); - pciba_soft_unlock(soft); -#if DEBUG_PCIBA - printf("pciba: mapped dma at kaddr 0x%x via handle 0x%x\n", - dmap->kaddr, dmap->handle); -#endif - return 0; - } - } - pciba_soft_unlock(soft); - return EINVAL; /* "block not found" */ - } - if (soft->iomem == PCIIO_SPACE_NONE) - return EINVAL; /* "mmap not supported" */ - - kaddr = (caddr_t) pciio_pio_addr - (conn, 0, space, off, len, &pciio_piomap, soft->flags | PCIIO_FIXED ); - -#if DEBUG_PCIBA - printf("pciba: mapped %R[0x%x..0x%x] via map 0x%x to kaddr 0x%x\n", - space, space_desc, off, off + len - 1, pciio_piomap, kaddr); -#endif + DPRINTF("vma->vm_start is %lx\n", vma->vm_start); + DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - if (kaddr == NULL) - return EINVAL; /* "you can't get there from here" */ + /* the size of the vma doesn't necessarily correspond to the + size specified in the mmap call. So we can't really do any + kind of sanity check here. This is a dangerous driver, and + it's very easy for a user process to kill the machine. */ - NEW(map); - if (map == NULL) { - if (pciio_piomap) - pciio_piomap_free(pciio_piomap); - return ENOMEM; /* "unable to get memory resources */ - } -#ifdef LATER - map->uthread = curuthread; -#endif - map->handle = v_gethandle(vt); - map->uvaddr = v_getaddr(vt); - map->map = pciio_piomap; - map->space = soft->iomem; - map->base = soft->base + off; - map->size = len; - pciba_map_push(soft->comm->bus, map); - - /* Inform the system of the correct - * kvaddr corresponding to the thing - * that is being mapped. - */ - v_mapphys(vt, kaddr, len); - - return 0; -} - -/*ARGSUSED */ -int -pciba_unmap(dev_t dev, vhandl_t *vt) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - pciba_soft_t soft = pciba_soft_get(vhdl); - pciba_bus_t bus = soft->comm->bus; - pciba_map_t map; - __psunsigned_t handle = v_gethandle(vt); + DPRINTF("PCI base at virtual address %lx\n", pci_va); + /* the __pa macro is intended for region 7 on IA64, so it + doesn't work for region 6 */ + /* pci_pa = __pa(pci_va); */ + /* should be replaced by __tpa or equivalent (preferably a + generic equivalent) */ + pci_pa = pci_va & ~0xe000000000000000ul; + DPRINTF("PCI base at physical address %lx\n", pci_pa); -#if DEBUG_PCIBA - printf("pciba_unmap(%V,vt=%x)\n", dev, vt); -#endif + /* there are various arch-specific versions of this function + defined in linux/drivers/char/mem.c, but it would be nice + if all architectures put it in pgtable.h. it's defined + there for ia64.... */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - /* If this is a userDMA buffer, - * make a note that it has been unmapped - * so it can be released. - */ - if (soft->comm->dmap) { - pciba_dma_t dmap; - - pciba_soft_lock(soft); - for (dmap = soft->comm->dmap; dmap != NULL; dmap = dmap->next) - if (handle == dmap->handle) { - dmap->handle = 0; - pciba_soft_unlock(soft); -#if DEBUG_PCIBA - printf("pciba: unmapped dma at kaddr 0x%x via handle 0x%x\n", - dmap->kaddr, handle); -#endif - return 0; /* found userPCI */ - } - pciba_soft_unlock(soft); - } - map = pciba_map_pop_hdl(bus, handle); - if (map == NULL) - return EINVAL; /* no match */ + vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - if (map->map) - pciio_piomap_free(map->map); - DEL(map); - - return (0); /* all done OK */ + return io_remap_page_range(vma->vm_start, pci_pa, + vma->vm_end-vma->vm_start, + vma->vm_page_prot); } -#if ULI -void -pciba_clearuli(struct uli *uli) + +static int +mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va) { - pciio_intr_t intr = (pciio_intr_t) uli->teardownarg1; + unsigned long kernel_pa; -#if DEBUG_PCIBA - printf("pciba_clearuli(0x%x)\n", uli); -#endif + TRACE(); - pciio_intr_disconnect(intr); - pciio_intr_free(intr); - atomic_dec(&pciba_prevent_unload); -} + DPRINTF("vma->vm_start is %lx\n", vma->vm_start); + DPRINTF("vma->vm_end is %lx\n", vma->vm_end); -void -pciba_intr(intr_arg_t arg) -{ - struct uli *uli = (struct uli *) arg; - int ulinum = uli->index; + /* the size of the vma doesn't necessarily correspond to the + size specified in the mmap call. So we can't really do any + kind of sanity check here. This is a dangerous driver, and + it's very easy for a user process to kill the machine. */ - extern void frs_handle_uli(void); + DPRINTF("mapping virtual address %p\n", kernel_va); + kernel_pa = __pa(kernel_va); + DPRINTF("mapping physical address %lx\n", kernel_pa); - if (ulinum >= 0 && ulinum < MAX_ULIS) { - uli_callup(ulinum); + vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - if (private.p_frs_flags) - frs_handle_uli(); - } -} -#endif -#endif /* LATER - undef as we implement each routine */ + return remap_page_range(vma->vm_start, kernel_pa, + vma->vm_end-vma->vm_start, + vma->vm_page_prot); +} diff -urN linux-2.4.18/arch/ia64/sn/io/pcibr.c linux-2.4.19-pre5/arch/ia64/sn/io/pcibr.c --- linux-2.4.18/arch/ia64/sn/io/pcibr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pcibr.c Thu Jan 1 01:00:00 1970 @@ -1,9824 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam - */ - -#ifdef BRINGUP -int NeedXbridgeSwap = 0; -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include -#include -#endif - -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - -#undef PCIBR_ATE_DEBUG -#if defined(BRINGUP) -#if 0 -#define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ -#endif -#define PCI_DEBUG 1 -#define ATTACH_DEBUG 1 -#define PCIBR_SOFT_LIST 1 -#endif - -#ifndef LOCAL -#define LOCAL static -#endif - -/* - * Macros related to the Lucent USS 302/312 usb timeout workaround. It - * appears that if the lucent part can get into a retry loop if it sees a - * DAC on the bus during a pio read retry. The loop is broken after about - * 1ms, so we need to set up bridges holding this part to allow at least - * 1ms for pio. - */ - -#define USS302_TIMEOUT_WAR - -#ifdef USS302_TIMEOUT_WAR -#include -#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 -#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 -#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 -#define USS302_BRIDGE_TIMEOUT_HLD 4 -#endif - -#define PCIBR_LLP_CONTROL_WAR -#if defined (PCIBR_LLP_CONTROL_WAR) -int pcibr_llp_control_war_cnt; -#endif /* PCIBR_LLP_CONTROL_WAR */ - -#define NEWAf(ptr,n,f) (ptr = kmem_zalloc((n)*sizeof (*(ptr)), (f&PCIIO_NOSLEEP)?KM_NOSLEEP:KM_SLEEP)) -#define NEWA(ptr,n) (ptr = kmem_zalloc((n)*sizeof (*(ptr)), KM_SLEEP)) -#define DELA(ptr,n) (kfree(ptr)) - -#define NEWf(ptr,f) NEWAf(ptr,1,f) -#define NEW(ptr) NEWA(ptr,1) -#define DEL(ptr) DELA(ptr,1) - -int pcibr_devflag = D_MP; - -#ifdef LATER -#define F(s,n) { 1l<<(s),-(s), n } - -struct reg_desc bridge_int_status_desc[] = -{ - F(31, "MULTI_ERR"), - F(30, "PMU_ESIZE_EFAULT"), - F(29, "UNEXPECTED_RESP"), - F(28, "BAD_XRESP_PACKET"), - F(27, "BAD_XREQ_PACKET"), - F(26, "RESP_XTALK_ERROR"), - F(25, "REQ_XTALK_ERROR"), - F(24, "INVALID_ADDRESS"), - F(23, "UNSUPPORTED_XOP"), - F(22, "XREQ_FIFO_OFLOW"), - F(21, "LLP_REC_SNERROR"), - F(20, "LLP_REC_CBERROR"), - F(19, "LLP_RCTY"), - F(18, "LLP_TX_RETRY"), - F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), - F(15, "PCI_ABORT"), - F(14, "PCI_PARITY"), - F(13, "PCI_SERR"), - F(12, "PCI_PERR"), - F(11, "PCI_MASTER_TOUT"), - F(10, "PCI_RETRY_CNT"), - F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), - F(7, "INT7"), - F(6, "INT6"), - F(5, "INT5"), - F(4, "INT4"), - F(3, "INT3"), - F(2, "INT2"), - F(1, "INT1"), - F(0, "INT0"), - {0} -}; - -struct reg_values space_v[] = -{ - {PCIIO_SPACE_NONE, "none"}, - {PCIIO_SPACE_ROM, "ROM"}, - {PCIIO_SPACE_IO, "I/O"}, - {PCIIO_SPACE_MEM, "MEM"}, - {PCIIO_SPACE_MEM32, "MEM(32)"}, - {PCIIO_SPACE_MEM64, "MEM(64)"}, - {PCIIO_SPACE_CFG, "CFG"}, - {PCIIO_SPACE_WIN(0), "WIN(0)"}, - {PCIIO_SPACE_WIN(1), "WIN(1)"}, - {PCIIO_SPACE_WIN(2), "WIN(2)"}, - {PCIIO_SPACE_WIN(3), "WIN(3)"}, - {PCIIO_SPACE_WIN(4), "WIN(4)"}, - {PCIIO_SPACE_WIN(5), "WIN(5)"}, - {PCIIO_SPACE_BAD, "BAD"}, - {0} -}; - -struct reg_desc space_desc[] = -{ - {0xFF, 0, "space", 0, space_v}, - {0} -}; - -#if DEBUG -#define device_desc device_bits -LOCAL struct reg_desc device_bits[] = -{ - {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, - {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, - {BRIDGE_DEV_FORCE_PCI_PAR, 0, "FORCE_PCI_PAR"}, - {BRIDGE_DEV_VIRTUAL_EN, 0, "VIRTUAL_EN"}, - {BRIDGE_DEV_PMU_WRGA_EN, 0, "PMU_WRGA_EN"}, - {BRIDGE_DEV_DIR_WRGA_EN, 0, "DIR_WRGA_EN"}, - {BRIDGE_DEV_DEV_SIZE, 0, "DEV_SIZE"}, - {BRIDGE_DEV_RT, 0, "RT"}, - {BRIDGE_DEV_SWAP_PMU, 0, "SWAP_PMU"}, - {BRIDGE_DEV_SWAP_DIR, 0, "SWAP_DIR"}, - {BRIDGE_DEV_PREF, 0, "PREF"}, - {BRIDGE_DEV_PRECISE, 0, "PRECISE"}, - {BRIDGE_DEV_COH, 0, "COH"}, - {BRIDGE_DEV_BARRIER, 0, "BARRIER"}, - {BRIDGE_DEV_GBR, 0, "GBR"}, - {BRIDGE_DEV_DEV_SWAP, 0, "DEV_SWAP"}, - {BRIDGE_DEV_DEV_IO_MEM, 0, "DEV_IO_MEM"}, - {BRIDGE_DEV_OFF_MASK, BRIDGE_DEV_OFF_ADDR_SHFT, "DEV_OFF", "%x"}, - {0} -}; -#endif /* DEBUG */ - -#ifdef SUPPORT_PRINTING_R_FORMAT -LOCAL struct reg_values xio_cmd_pactyp[] = -{ - {0x0, "RdReq"}, - {0x1, "RdResp"}, - {0x2, "WrReqWithResp"}, - {0x3, "WrResp"}, - {0x4, "WrReqNoResp"}, - {0x5, "Reserved(5)"}, - {0x6, "FetchAndOp"}, - {0x7, "Reserved(7)"}, - {0x8, "StoreAndOp"}, - {0x9, "Reserved(9)"}, - {0xa, "Reserved(a)"}, - {0xb, "Reserved(b)"}, - {0xc, "Reserved(c)"}, - {0xd, "Reserved(d)"}, - {0xe, "SpecialReq"}, - {0xf, "SpecialResp"}, - {0} -}; - -LOCAL struct reg_desc xio_cmd_bits[] = -{ - {WIDGET_DIDN, -28, "DIDN", "%x"}, - {WIDGET_SIDN, -24, "SIDN", "%x"}, - {WIDGET_PACTYP, -20, "PACTYP", 0, xio_cmd_pactyp}, - {WIDGET_TNUM, -15, "TNUM", "%x"}, - {WIDGET_COHERENT, 0, "COHERENT"}, - {WIDGET_DS, 0, "DS"}, - {WIDGET_GBR, 0, "GBR"}, - {WIDGET_VBPM, 0, "VBPM"}, - {WIDGET_ERROR, 0, "ERROR"}, - {WIDGET_BARRIER, 0, "BARRIER"}, - {0} -}; -#endif /* SUPPORT_PRINTING_R_FORMAT */ - -#if PCIBR_FREEZE_TIME || PCIBR_ATE_DEBUG -LOCAL struct reg_desc ate_bits[] = -{ - {0xFFFF000000000000ull, -48, "RMF", "%x"}, - {~(IOPGSIZE - 1) & /* may trim off some low bits */ - 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, - {0x0000000000000F00ull, -8, "port", "%x"}, - {0x0000000000000010ull, 0, "Barrier"}, - {0x0000000000000008ull, 0, "Prefetch"}, - {0x0000000000000004ull, 0, "Precise"}, - {0x0000000000000002ull, 0, "Coherent"}, - {0x0000000000000001ull, 0, "Valid"}, - {0} -}; -#endif - -#if PCIBR_ATE_DEBUG -LOCAL struct reg_values ssram_sizes[] = -{ - {BRIDGE_CTRL_SSRAM_512K, "512k"}, - {BRIDGE_CTRL_SSRAM_128K, "128k"}, - {BRIDGE_CTRL_SSRAM_64K, "64k"}, - {BRIDGE_CTRL_SSRAM_1K, "1k"}, - {0} -}; - -LOCAL struct reg_desc control_bits[] = -{ - {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, - {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, - {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, - {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, - {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, - {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, - {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, - {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, - {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, - {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, - {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, - {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, - {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, - {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, - {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, - {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, - {BRIDGE_CTRL_MAX_TRANS_MASK, -4, "MAX_TRANS", "%d"}, - {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, - {0} -}; -#endif -#endif /* LATER */ - -/* kbrick widgetnum-to-bus layout */ -int p_busnum[MAX_PORT_NUM] = { /* widget# */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 2, /* 0x8 */ - 1, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 5, /* 0xc */ - 6, /* 0xd */ - 4, /* 0xe */ - 3, /* 0xf */ -}; - -/* - * Additional PIO spaces per slot are - * recorded in this structure. - */ -struct pciio_piospace_s { - pciio_piospace_t next; /* another space for this device */ - char free; /* 1 if free, 0 if in use */ - pciio_space_t space; /* Which space is in use */ - iopaddr_t start; /* Starting address of the PIO space */ - size_t count; /* size of PIO space */ -}; - -/* Use io spin locks. This ensures that all the PIO writes from a particular - * CPU to a particular IO device are synched before the start of the next - * set of PIO operations to the same device. - */ -#define pcibr_lock(pcibr_soft) io_splock(&pcibr_soft->bs_lock) -#define pcibr_unlock(pcibr_soft,s) io_spunlock(&pcibr_soft->bs_lock,s) - -#if PCIBR_SOFT_LIST -typedef struct pcibr_list_s *pcibr_list_p; -struct pcibr_list_s { - pcibr_list_p bl_next; - pcibr_soft_t bl_soft; - devfs_handle_t bl_vhdl; -}; -pcibr_list_p pcibr_list = 0; -#endif - -typedef volatile unsigned *cfg_p; -typedef volatile bridgereg_t *reg_p; - -#define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" - -#define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) -#define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) - -#define PCIBR_VALID_SLOT(s) (s < 8) - -#ifdef SN_XXX -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); -#endif -extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - -extern devfs_handle_t hwgraph_root; -extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); -extern int cap_able(uint64_t x); -extern uint64_t rmalloc(struct map *mp, size_t size); -extern void rmfree(struct map *mp, size_t size, uint64_t a); -extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); -extern long atoi(register char *p); -extern void *swap_ptr(void **loc, void *new); -extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr); -extern struct map *rmallocmap(uint64_t mapsiz); -extern void rmfreemap(struct map *mp); -extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); -extern int io_path_map_widget(devfs_handle_t vertex); - - - -/* ===================================================================== - * Function Table of Contents - * - * The order of functions in this file has stopped - * making much sense. We might want to take a look - * at it some time and bring back some sanity, or - * perhaps bust this file into smaller chunks. - */ - -LOCAL void do_pcibr_rrb_clear(bridge_t *, int); -LOCAL void do_pcibr_rrb_flush(bridge_t *, int); -LOCAL int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); -LOCAL int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); - -LOCAL void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); - -int pcibr_wrb_flush(devfs_handle_t); -int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); -void pcibr_rrb_flush(devfs_handle_t); - -LOCAL int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); -void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); - -LOCAL void pcibr_clearwidint(bridge_t *); -LOCAL void pcibr_setwidint(xtalk_intr_t); -LOCAL int pcibr_probe_slot(bridge_t *, cfg_p, unsigned *); - -void pcibr_init(void); -int pcibr_attach(devfs_handle_t); -int pcibr_detach(devfs_handle_t); -int pcibr_open(devfs_handle_t *, int, int, cred_t *); -int pcibr_close(devfs_handle_t, int, int, cred_t *); -int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int pcibr_unmap(devfs_handle_t, vhandl_t *); -int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); - -LOCAL int pcibr_init_ext_ate_ram(bridge_t *); -LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); -LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); - -LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); -LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); - -pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pcibr_piomap_free(pcibr_piomap_t); -caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); -void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -LOCAL iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); -LOCAL bridge_ate_t pcibr_flags_to_ate(unsigned); - -pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pcibr_dmamap_free(pcibr_dmamap_t); -LOCAL bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -LOCAL iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); -iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); -void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); -iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); - -static unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); -pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pcibr_intr_free(pcibr_intr_t); -LOCAL void pcibr_setpciint(xtalk_intr_t); -int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t, void *); -void pcibr_intr_disconnect(pcibr_intr_t); - -devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); -void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_func(intr_arg_t); - -LOCAL void print_bridge_errcmd(uint32_t, char *); - -void pcibr_error_dump(pcibr_soft_t); -uint32_t pcibr_errintr_group(uint32_t); -LOCAL void pcibr_pioerr_check(pcibr_soft_t); -LOCAL void pcibr_error_intr_handler(intr_arg_t); - -LOCAL int pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *); -LOCAL void pcibr_error_cleanup(pcibr_soft_t, int); -void pcibr_device_disable(pcibr_soft_t, int); -LOCAL int pcibr_pioerror(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -LOCAL int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); -int pcibr_error_devenable(devfs_handle_t, int); - -void pcibr_provider_startup(devfs_handle_t); -void pcibr_provider_shutdown(devfs_handle_t); - -int pcibr_reset(devfs_handle_t); -pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); -int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); - -LOCAL cfg_p pcibr_config_addr(devfs_handle_t, unsigned); -uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -LOCAL uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); -void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -LOCAL void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); - -LOCAL pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -void pcibr_hints_fix_rrbs(devfs_handle_t); -void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); - -LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); - -#ifdef LATER -LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, - pcibr_slot_info_resp_t); -LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, - pcibr_slot_func_info_resp_t); -#endif /* LATER */ - -LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); -LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, - pciio_slot_t, int); -LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, - pciio_slot_t, int); - -LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); -LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); -#ifdef LATER -LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); -#endif - -/* ===================================================================== - * RRB management - */ - -#define LSBIT(word) ((word) &~ ((word)-1)) - -#define PCIBR_RRB_SLOT_VIRTUAL 8 - -LOCAL void -do_pcibr_rrb_clear(bridge_t *bridge, int rrb) -{ - bridgereg_t status; - - /* bridge_lock must be held; - * this RRB must be disabled. - */ - - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } -} - -LOCAL void -do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) -{ - reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; - bridgereg_t rrbv; - int shft = 4 * (rrbn >> 1); - unsigned ebit = BRIDGE_RRB_EN << shft; - - rrbv = *rrbp; - if (rrbv & ebit) - *rrbp = rrbv & ~ebit; - - do_pcibr_rrb_clear(bridge, rrbn); - - if (rrbv & ebit) - *rrbp = rrbv; -} - -/* - * pcibr_rrb_count_valid: count how many RRBs are - * marked valid for the specified PCI slot on this - * bridge. - * - * NOTE: The "slot" parameter for all pcibr_rrb - * management routines must include the "virtual" - * bit; when manageing both the normal and the - * virtual channel, separate calls to these - * routines must be made. To denote the virtual - * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot - * number. - * - * IMPL NOTE: The obvious algorithm is to iterate - * through the RRB fields, incrementing a count if - * the RRB is valid and matches the slot. However, - * it is much simpler to use an algorithm derived - * from the "partitioned add" idea. First, XOR in a - * pattern such that the fields that match this - * slot come up "all ones" and all other fields - * have zeros in the mismatching bits. Then AND - * together the bits in the field, so we end up - * with one bit turned on for each field that - * matched. Now we need to count these bits. This - * can be done either with a series of shift/add - * instructions or by using "tmp % 15"; I expect - * that the cascaded shift/add will be faster. - */ - -LOCAL int -do_pcibr_rrb_count_valid(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp ^= 0x11111111 * (7 - slot / 2); - tmp &= (0xCCCCCCCC & tmp) >> 2; - tmp &= (0x22222222 & tmp) >> 1; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_count_avail: count how many RRBs are - * available to be allocated for the specified slot. - * - * IMPL NOTE: similar to the above, except we are - * just counting how many fields have the valid bit - * turned off. - */ -LOCAL int -do_pcibr_rrb_count_avail(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~tmp) >> 3; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_alloc: allocate some additional RRBs - * for the specified slot. Returns -1 if there were - * insufficient free RRBs to satisfy the request, - * or 0 if the request was fulfilled. - * - * Note that if a request can be partially filled, - * it will be, even if we return failure. - * - * IMPL NOTE: again we avoid iterating across all - * the RRBs; instead, we form up a word containing - * one bit for each free RRB, then peel the bits - * off from the low end. - */ -LOCAL int -do_pcibr_rrb_alloc(bridge_t *bridge, - pciio_slot_t slot, - int more) -{ - int rv = 0; - bridgereg_t reg, tmp, bit; - - reg = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~reg) >> 3; - while (more-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); - } - bridge->b_rrb_map[slot & 1].reg = reg; - return rv; -} - -/* - * do_pcibr_rrb_free: release some of the RRBs that - * have been allocated for the specified - * slot. Returns zero for success, or negative if - * it was unable to free that many RRBs. - * - * IMPL NOTE: We form up a bit for each RRB - * allocated to the slot, aligned with the VALID - * bitfield this time; then we peel bits off one at - * a time, releasing the corresponding RRB. - */ -LOCAL int -do_pcibr_rrb_free(bridge_t *bridge, - pciio_slot_t slot, - int less) -{ - int rv = 0; - bridgereg_t reg, tmp, clr, bit; - int i; - - clr = 0; - reg = bridge->b_rrb_map[slot & 1].reg; - - /* This needs to be done otherwise the rrb's on the virtual channel - * for this slot won't be freed !! - */ - tmp = reg & 0xbbbbbbbb; - - tmp ^= (0x11111111 * (7 - slot / 2)); - tmp &= (0x33333333 & tmp) << 2; - tmp &= (0x44444444 & tmp) << 1; - while (less-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg &= ~bit; - clr |= bit; - } - bridge->b_rrb_map[slot & 1].reg = reg; - - for (i = 0; i < 8; i++) - if (clr & (8 << (4 * i))) - do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); - - return rv; -} - -LOCAL void -do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, - int slot, - int more_rrbs) -{ - bridge_t *bridge = pcibr_soft->bs_base; - int got; - - for (got = 0; got < more_rrbs; ++got) { - if (pcibr_soft->bs_rrb_res[slot & 7] > 0) - pcibr_soft->bs_rrb_res[slot & 7]--; - else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) - pcibr_soft->bs_rrb_avail[slot & 1]--; - else - break; - if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) - break; -#if PCIBR_RRB_DEBUG - printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n", - slot & 7, slot & 8 ? "v" : ""); -#endif - pcibr_soft->bs_rrb_valid[slot]++; - } -#if PCIBR_RRB_DEBUG - printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (slot = 0; slot < 8; ++slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif -} - -/* - * Device driver interface to flush the write buffers for a specified - * device hanging off the bridge. - */ -int -pcibr_wrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - volatile bridgereg_t *wrb_flush; - - wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); - while (*wrb_flush); - - return(0); -} -/* - * Device driver interface to request RRBs for a specified device - * hanging off a Bridge. The driver requests the total number of - * RRBs it would like for the normal channel (vchan0) and for the - * "virtual channel" (vchan1). The actual number allocated to each - * channel is returned. - * - * If we cannot allocate at least one RRB to a channel that needs - * at least one, return -1 (failure). Otherwise, satisfy the request - * as best we can and return 0. - */ -int -pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - int desired_vchan0; - int desired_vchan1; - int orig_vchan0; - int orig_vchan1; - int delta_vchan0; - int delta_vchan1; - int final_vchan0; - int final_vchan1; - int avail_rrbs; - unsigned long s; - int error; - - /* - * TBD: temper request with admin info about RRB allocation, - * and according to demand from other devices on this Bridge. - * - * One way of doing this would be to allocate two RRBs - * for each device on the bus, before any drivers start - * asking for extras. This has the weakness that one - * driver might not give back an "extra" RRB until after - * another driver has already failed to get one that - * it wanted. - */ - - s = pcibr_lock(pcibr_soft); - - /* How many RRBs do we own? */ - orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; - orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - /* How many RRBs do we want? */ - desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; - desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; - - /* How many RRBs are free? */ - avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot]; - - /* Figure desired deltas */ - delta_vchan0 = desired_vchan0 - orig_vchan0; - delta_vchan1 = desired_vchan1 - orig_vchan1; - - /* Trim back deltas to something - * that we can actually meet, by - * decreasing the ending allocation - * for whichever channel wants - * more RRBs. If both want the same - * number, cut the second channel. - * NOTE: do not change the allocation for - * a channel that was passed as NULL. - */ - while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { - if (count_vchan0 && - (!count_vchan1 || - ((orig_vchan0 + delta_vchan0) > - (orig_vchan1 + delta_vchan1)))) - delta_vchan0--; - else - delta_vchan1--; - } - - /* Figure final RRB allocations - */ - final_vchan0 = orig_vchan0 + delta_vchan0; - final_vchan1 = orig_vchan1 + delta_vchan1; - - /* If either channel wants RRBs but our actions - * would leave it with none, declare an error, - * but DO NOT change any RRB allocations. - */ - if ((desired_vchan0 && !final_vchan0) || - (desired_vchan1 && !final_vchan1)) { - - error = -1; - - } else { - - /* Commit the allocations: free, then alloc. - */ - if (delta_vchan0 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); - if (delta_vchan1 < 0) - (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); - - if (delta_vchan0 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); - if (delta_vchan1 > 0) - (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); - - /* Return final values to caller. - */ - if (count_vchan0) - *count_vchan0 = final_vchan0; - if (count_vchan1) - *count_vchan1 = final_vchan1; - - /* prevent automatic changes to this slot's RRBs - */ - pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; - - /* Track the actual allocations, release - * any further reservations, and update the - * number of available RRBs. - */ - - pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot] - - delta_vchan0 - - delta_vchan1; - pcibr_soft->bs_rrb_res[pciio_slot] = 0; - -#if PCIBR_RRB_DEBUG - printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", - pciio_slot, final_vchan0, final_vchan1, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[pciio_slot]); - printk("\n"); -#endif - - error = 0; - } - - pcibr_unlock(pcibr_soft, s); - return error; -} - -/* - * Device driver interface to check the current state - * of the RRB allocations. - * - * pconn_vhdl is your PCI connection point (specifies which - * PCI bus and which slot). - * - * count_vchan0 points to where to return the number of RRBs - * assigned to the primary DMA channel, used by all DMA - * that does not explicitly ask for the alternate virtual - * channel. - * - * count_vchan1 points to where to return the number of RRBs - * assigned to the secondary DMA channel, used when - * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. - * - * count_reserved points to where to return the number of RRBs - * that have been automatically reserved for your device at - * startup, but which have not been assigned to a - * channel. RRBs must be assigned to a channel to be used; - * this can be done either with an explicit pcibr_rrb_alloc - * call, or automatically by the infrastructure when a DMA - * translation is constructed. Any call to pcibr_rrb_alloc - * will release any unassigned reserved RRBs back to the - * free pool. - * - * count_pool points to where to return the number of RRBs - * that are currently unassigned and unreserved. This - * number can (and will) change as other drivers make calls - * to pcibr_rrb_alloc, or automatically allocate RRBs for - * DMA beyond their initial reservation. - * - * NULL may be passed for any of the return value pointers - * the caller is not interested in. - * - * The return value is "0" if all went well, or "-1" if - * there is a problem. Additionally, if the wrong vertex - * is passed in, one of the subsidiary support functions - * could panic with a "bad pciio fingerprint." - */ - -int -pcibr_rrb_check(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1, - int *count_reserved, - int *count_pool) -{ - pciio_info_t pciio_info; - pciio_slot_t pciio_slot; - pcibr_soft_t pcibr_soft; - unsigned long s; - int error = -1; - - if ((pciio_info = pciio_info_get(pconn_vhdl)) && - (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && - ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { - - s = pcibr_lock(pcibr_soft); - - if (count_vchan0) - *count_vchan0 = - pcibr_soft->bs_rrb_valid[pciio_slot]; - - if (count_vchan1) - *count_vchan1 = - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - if (count_reserved) - *count_reserved = - pcibr_soft->bs_rrb_res[pciio_slot]; - - if (count_pool) - *count_pool = - pcibr_soft->bs_rrb_avail[pciio_slot & 1]; - - error = 0; - - pcibr_unlock(pcibr_soft, s); - } - return error; -} - -/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities - * requested for each of the devies. The evn_odd argument indicates whether - * allcoation for the odd or even rrbs is requested and next group of four pairse - * are the amount to assign to each device (they should sum to <= 8) and - * whether to set the viritual bit for that device (1 indictaes yes, 0 indicates no) - * the devices in order are either 0, 2, 4, 6 or 1, 3, 5, 7 - * if even_odd is even we alloc even rrbs else we allocate odd rrbs - * returns 0 if no errors else returns -1 - */ - -int -pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, - int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, - int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) -{ - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft = NULL; - bridge_t *bridge = NULL; - - uint32_t rrb_setting = 0; - int rrb_shift = 7; - uint32_t cur_rrb; - int dev_rrbs[4]; - int virt[4]; - int i, j; - unsigned long s; - - if (GRAPH_SUCCESS == - hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) - bridge = pcibr_soft->bs_base; - hwgraph_vertex_unref(pcibr_vhdl); - } - if (bridge == NULL) - bridge = (bridge_t *) xtalk_piotrans_addr - (vhdl, NULL, 0, sizeof(bridge_t), 0); - - even_odd &= 1; - - dev_rrbs[0] = dev_1_rrbs; - dev_rrbs[1] = dev_2_rrbs; - dev_rrbs[2] = dev_3_rrbs; - dev_rrbs[3] = dev_4_rrbs; - - virt[0] = virt1; - virt[1] = virt2; - virt[2] = virt3; - virt[3] = virt4; - - if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { - return -1; - } - if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { - return -1; - } - /* walk through rrbs */ - for (i = 0; i < 4; i++) { - if (virt[i]) { - cur_rrb = i | 0xc; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - dev_rrbs[i] = dev_rrbs[i] - 1; - } - for (j = 0; j < dev_rrbs[i]; j++) { - cur_rrb = i | 0x8; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - } - } - - if (pcibr_soft) - s = pcibr_lock(pcibr_soft); - - bridge->b_rrb_map[even_odd].reg = rrb_setting; - - if (pcibr_soft) { - - pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; - - /* since we've "FIXED" the allocations - * for these slots, we probably can dispense - * with tracking avail/res/valid data, but - * keeping it up to date helps debugging. - */ - - pcibr_soft->bs_rrb_avail[even_odd] = - 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); - - pcibr_soft->bs_rrb_res[even_odd + 0] = 0; - pcibr_soft->bs_rrb_res[even_odd + 2] = 0; - pcibr_soft->bs_rrb_res[even_odd + 4] = 0; - pcibr_soft->bs_rrb_res[even_odd + 6] = 0; - - pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; - - pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; - - pcibr_unlock(pcibr_soft, s); - } - return 0; -} - -/* - * pcibr_rrb_flush: chase down all the RRBs assigned - * to the specified connection point, and flush - * them. - */ -void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - unsigned long s; - reg_p rrbp; - unsigned rrbm; - int i; - int rrbn; - unsigned sval; - unsigned mask; - - sval = BRIDGE_RRB_EN | (pciio_slot >> 1); - mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; - rrbn = pciio_slot & 1; - rrbp = &bridge->b_rrb_map[rrbn].reg; - - s = pcibr_lock(pcibr_soft); - rrbm = *rrbp; - for (i = 0; i < 8; ++i) { - if ((rrbm & mask) == sval) - do_pcibr_rrb_flush(bridge, rrbn); - rrbm >>= 4; - rrbn += 2; - } - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Device(x) register management - */ - -/* pcibr_try_set_device: attempt to modify Device(x) - * for the specified slot on the specified bridge - * as requested in flags, limited to the specified - * bits. Returns which BRIDGE bits were in conflict, - * or ZERO if everything went OK. - * - * Caller MUST hold pcibr_lock when calling this function. - */ -LOCAL int -pcibr_try_set_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - unsigned flags, - bridgereg_t mask) -{ - bridge_t *bridge; - pcibr_soft_slot_t slotp; - bridgereg_t old; - bridgereg_t new; - bridgereg_t chg; - bridgereg_t bad; - bridgereg_t badpmu; - bridgereg_t badd32; - bridgereg_t badd64; - bridgereg_t fix; - unsigned long s; - bridgereg_t xmask; - - xmask = mask; - if (pcibr_soft->bs_xbridge) { - if (mask == BRIDGE_DEV_PMU_BITS) - xmask = XBRIDGE_DEV_PMU_BITS; - if (mask == BRIDGE_DEV_D64_BITS) - xmask = XBRIDGE_DEV_D64_BITS; - } - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - bridge = pcibr_soft->bs_base; - - old = slotp->bss_device; - - /* figure out what the desired - * Device(x) bits are based on - * the flags specified. - */ - - new = old; - - /* Currently, we inherit anything that - * the new caller has not specified in - * one way or another, unless we take - * action here to not inherit. - * - * This is needed for the "swap" stuff, - * since it could have been set via - * pcibr_endian_set -- altho note that - * any explicit PCIBR_BYTE_STREAM or - * PCIBR_WORD_VALUES will freely override - * the effect of that call (and vice - * versa, no protection either way). - * - * I want to get rid of pcibr_endian_set - * in favor of tracking DMA endianness - * using the flags specified when DMA - * channels are created. - */ - -#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) -#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) - - /* Do not use Barrier, Write Gather, - * or Prefetch unless asked. - * Leave everything else as it - * was from the last time. - */ - new = new - & ~BRIDGE_DEV_BARRIER - & ~BRIDGE_DEV_WRGA_BITS - & ~BRIDGE_DEV_PREF - ; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { - new = (new - & ~BRIDGE_DEV_BARRIER) /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ - - } - if (flags & PCIIO_DMA_CMD) { - new = ((new - & ~BRIDGE_DEV_PREF) /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ - } - /* Generic detail flags - */ - if (flags & PCIIO_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIIO_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIIO_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIBR_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_BYTE_STREAM) - new |= (pcibr_soft->bs_xbridge) ? - BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; - if (flags & PCIIO_WORD_VALUES) - new &= (pcibr_soft->bs_xbridge) ? - ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; - - /* Provider-specific flags - */ - if (flags & PCIBR_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - new |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - new &= ~BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - new |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - new &= ~BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - new |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - new &= ~BRIDGE_DEV_DEV_SIZE; - - chg = old ^ new; /* what are we changing, */ - chg &= xmask; /* of the interesting bits */ - - if (chg) { - - badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; - if (pcibr_soft->bs_xbridge) { - badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; - } else { - badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; - } - bad = badpmu | badd32 | badd64; - - if (bad) { - - /* some conflicts can be resolved by - * forcing the bit on. this may cause - * some performance degredation in - * the stream(s) that want the bit off, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) ){ - bad &= ~fix; - /* don't change these bits if - * they are already set in "old" - */ - chg &= ~(fix & old); - } - /* some conflicts can be resolved by - * forcing the bit off. this may cause - * some performance degredation in - * the stream(s) that want the bit on, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ) { - bad &= ~fix; - /* don't change these bits if - * we wanted to turn them on. - */ - chg &= ~(fix & new); - } - /* conflicts in other bits mean - * we can not establish this DMA - * channel while the other(s) are - * still present. - */ - if (bad) { - pcibr_unlock(pcibr_soft, s); -#if (DEBUG && PCIBR_DEV_DEBUG) - printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); -#endif - return bad; - } - } - } - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr++; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr++; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr++; - - /* the value we want to write is the - * original value, with the bits for - * our selected changes flipped, and - * with any disabled features turned off. - */ - new = old ^ chg; /* only change what we want to change */ - - if (slotp->bss_device == new) { - pcibr_unlock(pcibr_soft, s); - return 0; - } - bridge->b_device[slot].reg = new; - slotp->bss_device = new; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); -#endif - - return 0; -} - -void -pcibr_release_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - bridgereg_t mask) -{ - pcibr_soft_slot_t slotp; - unsigned long s; - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr--; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr--; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr--; - - pcibr_unlock(pcibr_soft, s); -} - -/* - * flush write gather buffer for slot - */ -LOCAL void -pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - bridge_t *bridge; - unsigned long s; - volatile uint32_t wrf; - s = pcibr_lock(pcibr_soft); - bridge = pcibr_soft->bs_base; - wrf = bridge->b_wr_req_buf[slot].reg; - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Bridge (pcibr) "Device Driver" entry points - */ - -/* - * pcibr_probe_slot: read a config space word - * while trapping any errors; reutrn zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -LOCAL int -pcibr_probe_slot(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) -{ - int rv; - bridgereg_t old_enable, new_enable; - int badaddr_val(volatile void *, int, volatile void *); - - - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - - bridge->b_int_enable = new_enable; - - /* - * The xbridge doesn't clear b_err_int_view unless - * multi-err is cleared... - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) cfg, 4, valp); - - /* - * The xbridge doesn't set master timeout in b_int_status - * here. Fortunately it's in error_interrupt_view. - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ - } - - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - return rv; -} - -/* - * pcibr_init: called once during system startup or - * when a loadable driver is loaded. - * - * The driver_register function should normally - * be in _reg, not _init. But the pcibr driver is - * required by devinit before the _reg routines - * are called, so this is an exception. - */ -void -pcibr_init(void) -{ -#if DEBUG && ATTACH_DEBUG - printk("pcibr_init\n"); -#endif - - xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, - XBRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); - xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, - BRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); -} - -/* - * open/close mmap/munmap interface would be used by processes - * that plan to map the PCI bridge, and muck around with the - * registers. This is dangerous to do, and will be allowed - * to a select brand of programs. Typically these are - * diagnostics programs, or some user level commands we may - * write to do some weird things. - * To start with expect them to have root priveleges. - * We will ask for more later. - */ -/* ARGSUSED */ -int -pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - int error; - devfs_handle_t vhdl = dev_to_vhdl(dev); - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - ASSERT(pcibr_soft); - len = ctob(btoc(len)); /* Make len page aligned */ - error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); - - /* - * If the offset being mapped corresponds to the flash prom - * base, and if the mapping succeeds, and if the user - * has requested the protections to be WRITE, enable the - * flash prom to be written. - * - * XXX- deprecate this in favor of using the - * real flash driver ... - */ - if (!error && - ((off == BRIDGE_EXTERNAL_FLASH) || - (len > BRIDGE_EXTERNAL_FLASH))) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return error; -} - -/*ARGSUSED */ -int -pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return 0; -} - -/* This is special case code used by grio. There are plans to make - * this a bit more general in the future, but till then this should - * be sufficient. - */ -pciio_slot_t -pcibr_device_slot_get(devfs_handle_t dev_vhdl) -{ - char devname[MAXDEVNAME]; - devfs_handle_t tdev; - pciio_info_t pciio_info; - pciio_slot_t slot = PCIIO_SLOT_NONE; - - vertex_to_name(dev_vhdl, devname, MAXDEVNAME); - - /* run back along the canonical path - * until we find a PCI connection point. - */ - tdev = hwgraph_connectpt_get(dev_vhdl); - while (tdev != GRAPH_VERTEX_NONE) { - pciio_info = pciio_info_chk(tdev); - if (pciio_info) { - slot = pciio_info_slot_get(pciio_info); - break; - } - hwgraph_vertex_unref(tdev); - tdev = hwgraph_connectpt_get(tdev); - } - hwgraph_vertex_unref(tdev); - - return slot; -} - -/*========================================================================== - * BRIDGE PCI SLOT RELATED IOCTLs - */ -char *pci_space_name[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - - -#ifdef LATER - -void -pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, - int func, - pcibr_slot_func_info_resp_t funcp) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - int win; - - funcp->resp_f_status = 0; - - if (!pcibr_info) { - return; - } - - funcp->resp_f_status |= FUNC_IS_VALID; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); -#else - sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex); -#endif - - if(is_sys_critical_vertex(pcibr_info->f_vertex)) { - funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; - } - - funcp->resp_f_bus = pcibr_info->f_bus; - funcp->resp_f_slot = pcibr_info->f_slot; - funcp->resp_f_func = pcibr_info->f_func; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); -#else - sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master); -#endif - funcp->resp_f_pops = pcibr_info->f_pops; - funcp->resp_f_efunc = pcibr_info->f_efunc; - funcp->resp_f_einfo = pcibr_info->f_einfo; - - funcp->resp_f_vendor = pcibr_info->f_vendor; - funcp->resp_f_device = pcibr_info->f_device; - - for(win = 0 ; win < 6 ; win++) { - funcp->resp_f_window[win].resp_w_base = - pcibr_info->f_window[win].w_base; - funcp->resp_f_window[win].resp_w_size = - pcibr_info->f_window[win].w_size; - sprintf(funcp->resp_f_window[win].resp_w_space, - "%s", - pci_space_name[pcibr_info->f_window[win].w_space]); - } - - funcp->resp_f_rbase = pcibr_info->f_rbase; - funcp->resp_f_rsize = pcibr_info->f_rsize; - - for (win = 0 ; win < 4; win++) { - funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; - } - - funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; - -} - -int -pcibr_slot_info_return(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pcibr_slot_info_resp_t respp) -{ - pcibr_soft_slot_t pss; - int func; - bridge_t *bridge = pcibr_soft->bs_base; - reg_p b_respp; - pcibr_slot_info_resp_t slotp; - pcibr_slot_func_info_resp_t funcp; - - slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP); - if (slotp == NULL) { - return(ENOMEM); - } - - pss = &pcibr_soft->bs_slot[slot]; - - printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot); - - slotp->resp_has_host = pss->has_host; - slotp->resp_host_slot = pss->host_slot; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); -#else - sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn); -#endif - slotp->resp_slot_status = pss->slot_status; - slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); - - if (is_sys_critical_vertex(pss->slot_conn)) { - slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; - } - - slotp->resp_bss_ninfo = pss->bss_ninfo; - - for (func = 0; func < pss->bss_ninfo; func++) { - funcp = &(slotp->resp_func[func]); - pcibr_slot_func_info_return(pss->bss_infos, func, funcp); - } - - sprintf(slotp->resp_bss_devio_bssd_space, "%s", - pci_space_name[pss->bss_devio.bssd_space]); - slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; - slotp->resp_bss_device = pss->bss_device; - - slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; - slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; - slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; - - slotp->resp_bss_d64_base = pss->bss_d64_base; - slotp->resp_bss_d64_flags = pss->bss_d64_flags; - slotp->resp_bss_d32_base = pss->bss_d32_base; - slotp->resp_bss_d32_flags = pss->bss_d32_flags; - - slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active); - - slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; - slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; - - slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; - slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]; - slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; - - if (slot & 1) { - b_respp = &bridge->b_odd_resp; - } else { - b_respp = &bridge->b_even_resp; - } - - slotp->resp_b_resp = *b_respp; - - slotp->resp_b_int_device = bridge->b_int_device; - slotp->resp_b_int_enable = bridge->b_int_enable; - slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; - - if (COPYOUT(slotp, respp, sizeof(*respp))) { - return(EFAULT); - } - - kmem_free(slotp, sizeof(*slotp)); - - return(0); -} - -/* - * pcibr_slot_query - * Return information about the PCI slot maintained by the infrastructure. - * Information is requested in the request structure. - * - * Information returned in the response structure: - * Slot hwgraph name - * Vendor/Device info - * Base register info - * Interrupt mapping from device pins to the bridge pins - * Devio register - * Software RRB info - * RRB register info - * Host/Gues info - * PCI Bus #,slot #, function # - * Slot provider hwgraph name - * Provider Functions - * Error handler - * DMA mapping usage counters - * DMA direct translation info - * External SSRAM workaround info - */ -int -pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = reqp->req_slot; - pciio_slot_t tmp_slot; - pcibr_slot_info_resp_t respp = (pcibr_slot_info_resp_t) reqp->req_respp; - int size = reqp->req_size; - int error; - - /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) { - return(EINVAL); - } - - /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ - if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { - return(EINVAL); - } - -#ifdef LATER - /* Do not allow a query of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(EPERM); - } -#endif - - /* Return information for the requested PCI slot */ - if (slot != PCIIO_SLOT_NONE) { - if (size < sizeof(*respp)) { - return(EINVAL); - } - - /* Acquire read access to the slot */ - mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO); - - error = pcibr_slot_info_return(pcibr_soft, slot, respp); - - /* Release the slot lock */ - mrunlock(pcibr_soft->bs_slot[slot].slot_lock); - - return(error); - } - - /* Return information for all the slots */ - for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { - - if (size < sizeof(*respp)) { - return(EINVAL); - } - - /* Acquire read access to the slot */ - mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO); - - error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); - - /* Release the slot lock */ - mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock); - - if (error) { - return(error); - } - - ++respp; - size -= sizeof(*respp); - } - - return(error); -} -#endif /* LATER */ - - -/*ARGSUSED */ -int -pcibr_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef LATER - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); -#endif - int error = 0; - - hwgraph_vertex_unref(pcibr_vhdl); - - switch (cmd) { -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); - break; - } - - case PCIBR_SLOT_POWERUP: - { - pciio_slot_t slot; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_SHUTDOWN: - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_QUERY: - { - struct pcibr_slot_info_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_query(pcibr_vhdl, &req); - break; - } -#endif /* LATER */ - default: - break; - - } - - return error; -} - -void -pcibr_freeblock_sub(iopaddr_t *free_basep, - iopaddr_t *free_lastp, - iopaddr_t base, - size_t size) -{ - iopaddr_t free_base = *free_basep; - iopaddr_t free_last = *free_lastp; - iopaddr_t last = base + size - 1; - - if ((last < free_base) || (base > free_last)); /* free block outside arena */ - - else if ((base <= free_base) && (last >= free_last)) - /* free block contains entire arena */ - *free_basep = *free_lastp = 0; - - else if (base <= free_base) - /* free block is head of arena */ - *free_basep = last + 1; - - else if (last >= free_last) - /* free block is tail of arena */ - *free_lastp = base - 1; - - /* - * We are left with two regions: the free area - * in the arena "below" the block, and the free - * area in the arena "above" the block. Keep - * the one that is bigger. - */ - - else if ((base - free_base) > (free_last - last)) - *free_lastp = base - 1; /* keep lower chunk */ - else - *free_basep = last + 1; /* keep upper chunk */ -} - -/* Convert from ssram_bits in control register to number of SSRAM entries */ -#define ATE_NUM_ENTRIES(n) _ate_info[n] - -/* Possible choices for number of ATE entries in Bridge's SSRAM */ -LOCAL int _ate_info[] = -{ - 0, /* 0 entries */ - 8 * 1024, /* 8K entries */ - 16 * 1024, /* 16K entries */ - 64 * 1024 /* 64K entries */ -}; - -#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) -#define ATE_PROBE_VALUE 0x0123456789abcdefULL - -/* - * Determine the size of this bridge's external mapping SSRAM, and set - * the control register appropriately to reflect this size, and initialize - * the external SSRAM. - */ -LOCAL int -pcibr_init_ext_ate_ram(bridge_t *bridge) -{ - int largest_working_size = 0; - int num_entries, entry; - int i, j; - bridgereg_t old_enable, new_enable; - int s; - - /* Probe SSRAM to determine its size. */ - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - - for (i = 1; i < ATE_NUM_SIZES; i++) { - /* Try writing a value */ - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - - /* Guard against wrap */ - for (j = 1; j < i; j++) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; - - /* See if value was written */ - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - - s = splhi(); - bridge->b_wid_control = (bridge->b_wid_control - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - - num_entries = ATE_NUM_ENTRIES(largest_working_size); - -#if PCIBR_ATE_DEBUG - if (num_entries) - printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); - else - printk("bridge at 0x%x: no externa9422l ATE RAM found\n", bridge); -#endif - - /* Initialize external mapping entries */ - for (entry = 0; entry < num_entries; entry++) - bridge->b_ext_ate_ram[entry] = 0; - - return (num_entries); -} - -/* - * Allocate "count" contiguous Bridge Address Translation Entries - * on the specified bridge to be used for PCI to XTALK mappings. - * Indices in rm map range from 1..num_entries. Indicies returned - * to caller range from 0..num_entries-1. - * - * Return the start index on success, -1 on failure. - */ -LOCAL int -pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) -{ - int index = 0; - - index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); -/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ - - if (!index && pcibr_soft->bs_ext_ate_map) - index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); - - /* rmalloc manages resources in the 1..n - * range, with 0 being failure. - * pcibr_ate_alloc manages resources - * in the 0..n-1 range, with -1 being failure. - */ - return index - 1; -} - -LOCAL void -pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) -/* Who says there's no such thing as a free meal? :-) */ -{ - /* note the "+1" since rmalloc handles 1..n but - * we start counting ATEs at zero. - */ -/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ - - rmfree((index < pcibr_soft->bs_int_ate_size) - ? pcibr_soft->bs_int_ate_map - : pcibr_soft->bs_ext_ate_map, - count, index + 1); -} - -LOCAL pcibr_info_t -pcibr_info_get(devfs_handle_t vhdl) -{ - return (pcibr_info_t) pciio_info_get(vhdl); -} - -pcibr_info_t -pcibr_device_info_new( - pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pciio_function_t rfunc, - pciio_vendor_id_t vendor, - pciio_device_id_t device) -{ - pcibr_info_t pcibr_info; - pciio_function_t func; - int ibit; - - func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; - - NEW(pcibr_info); - pciio_device_info_new(&pcibr_info->f_c, - pcibr_soft->bs_vhdl, - slot, rfunc, - vendor, device); - - if (slot != PCIIO_SLOT_NONE) { - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - * - * XXX- allow pcibr_hints to override default - * XXX- allow ADMIN to override pcibr_hints - */ - for (ibit = 0; ibit < 4; ++ibit) - pcibr_info->f_ibit[ibit] = - (slot + 4 * ibit) & 7; - - /* - * Record the info in the sparse func info space. - */ - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) - pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; - } - return pcibr_info; -} - -void -pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info_t pcibr_info; - pciio_function_t func; - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; - int nfunc = slotp->bss_ninfo; - - - for (func = 0; func < nfunc; func++) { - pcibr_info = slotp->bss_infos[func]; - - if (!pcibr_info) - continue; - - slotp->bss_infos[func] = 0; - pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); - pciio_device_info_free(&pcibr_info->f_c); - DEL(pcibr_info); - } - - /* Clear the DEVIO(x) for this slot */ - slotp->bss_devio.bssd_space = PCIIO_SPACE_NONE; - slotp->bss_devio.bssd_base = PCIBR_D32_BASE_UNSET; - slotp->bss_device = 0; - - - /* Reset the mapping usage counters */ - slotp->bss_pmu_uctr = 0; - slotp->bss_d32_uctr = 0; - slotp->bss_d64_uctr = 0; - - /* Clear the Direct translation info */ - slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; - slotp->bss_d64_flags = 0; - slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; - slotp->bss_d32_flags = 0; - - /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = ATOMIC_INIT(0); - slotp->bss_cmd_pointer = 0; - slotp->bss_cmd_shadow = 0; - -} - -/* - * PCI_ADDR_SPACE_LIMITS_LOAD - * Gets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_LOAD() \ - pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ - pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ - pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ - pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ - pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ - pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; -/* - * PCI_ADDR_SPACE_LIMITS_STORE - * Sets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_STORE() \ - pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ - pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ - pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ - pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ - pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ - pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; - -#define PCI_ADDR_SPACE_LIMITS_PRINT() \ - printf("+++++++++++++++++++++++\n" \ - "IO base 0x%x last 0x%x\n" \ - "SWIN base 0x%x last 0x%x\n" \ - "MEM base 0x%x last 0x%x\n" \ - "+++++++++++++++++++++++\n", \ - pcibr_soft->bs_spinfo.pci_io_base, \ - pcibr_soft->bs_spinfo.pci_io_last, \ - pcibr_soft->bs_spinfo.pci_swin_base, \ - pcibr_soft->bs_spinfo.pci_swin_last, \ - pcibr_soft->bs_spinfo.pci_mem_base, \ - pcibr_soft->bs_spinfo.pci_mem_last); - -/* - * pcibr_slot_info_init - * Probe for this slot and see if it is populated. - * If it is populated initialize the generic PCI infrastructural - * information associated with this particular PCI device. - */ -int -pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - cfg_p cfgw; - unsigned idword; - unsigned pfail; - unsigned idwords[8]; - pciio_vendor_id_t vendor; - pciio_device_id_t device; - unsigned htype; -#if !defined(CONFIG_IA64_SGI_SN1) - int nbars; -#endif - cfg_p wptr; - int win; - pciio_space_t space; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - int nfunc; - pciio_function_t rfunc; - int func; - devfs_handle_t conn_vhdl; - pcibr_soft_slot_t slotp; - - /* Get the basic software information required to proceed */ - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization - * is done by the host slot then we are done. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - /* Check for a slot with any system critical functions */ - if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - /* Load the current values of allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - /* Try to read the device-id/vendor-id from the config space */ - cfgw = bridge->b_type0_cfg_dev[slot].l; - - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(ENODEV); - - slotp = &pcibr_soft->bs_slot[slot]; - slotp->slot_status |= SLOT_POWER_UP; - - vendor = 0xFFFF & idword; - /* If the vendor id is not valid then the slot is not populated - * and we are done. - */ - if (vendor == 0xFFFF) - return(ENODEV); - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - - nfunc = 1; - rfunc = PCIIO_FUNC_NONE; - pfail = 0; - - /* NOTE: if a card claims to be multifunction - * but only responds to config space 0, treat - * it as a unifunction card. - */ - - if (htype & 0x80) { /* MULTIFUNCTION */ - for (func = 1; func < 8; ++func) { - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { - pfail |= 1 << func; - continue; - } - vendor = 0xFFFF & idwords[func]; - if (vendor == 0xFFFF) { - pfail |= 1 << func; - continue; - } - nfunc = func + 1; - rfunc = 0; - } - cfgw = bridge->b_type0_cfg_dev[slot].l; - } - NEWA(pcibr_infoh, nfunc); - - pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - for (func = 0; func < nfunc; ++func) { - unsigned cmd_reg; - - if (func) { - if (pfail & (1 << func)) - continue; - - idword = idwords[func]; - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - rfunc = func; - } - htype &= 0x7f; - if (htype != 0x00) { - PRINT_WARNING("%s pcibr: pci slot %d func %d has strange header type 0x%x\n", - pcibr_soft->bs_name, slot, func, htype); -#if defined(CONFIG_IA64_SGI_SN1) - continue; -#else - nbars = 2; - } else { - nbars = PCI_CFG_BASE_ADDRS; -#endif - } -#if DEBUG && ATTACH_DEBUG - PRINT_NOTICE( - "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", - pcibr_soft->bs_name, slot, func, vendor, device); -#endif - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, rfunc, vendor, device); - conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); - if (func == 0) - slotp->slot_conn = conn_vhdl; - - cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; - - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - -#if defined(CONFIG_IA64_SGI_SN1) - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) -#else - for (win = 0; win < nbars; ++win) -#endif - { - iopaddr_t base, mask, code; - size_t size; - - /* - * GET THE BASE & SIZE OF THIS WINDOW: - * - * The low two or four bits of the BASE register - * determines which address space we are in; the - * rest is a base address. BASE registers - * determine windows that are power-of-two sized - * and naturally aligned, so we can get the size - * of a window by writing all-ones to the - * register, reading it back, and seeing which - * bits are used for decode; the least - * significant nonzero bit is also the size of - * the window. - * - * WARNING: someone may already have allocated - * some PCI space to this window, and in fact - * PIO may be in process at this very moment - * from another processor (or even from this - * one, if we get interrupted)! So, if the BASE - * already has a nonzero address, be generous - * and use the LSBit of that address as the - * size; this could overstate the window size. - * Usually, when one card is set up, all are set - * up; so, since we don't bitch about - * overlapping windows, we are ok. - * - * UNFORTUNATELY, some cards do not clear their - * BASE registers on reset. I have two heuristics - * that can detect such cards: first, if the - * decode enable is turned off for the space - * that the window uses, we can disregard the - * initial value. second, if the address is - * outside the range that we use, we can disregard - * it as well. - * - * This is looking very PCI generic. Except for - * knowing how many slots and where their config - * spaces are, this window loop and the next one - * could probably be shared with other PCI host - * adapters. It would be interesting to see if - * this could be pushed up into pciio, when we - * start supporting more PCI providers. - */ -#ifdef LITTLE_ENDIAN - base = wptr[((win*4)^4)/4]; -#else - base = wptr[win]; -#endif - - if (base & PCI_BA_IO_SPACE) { - /* BASE is in I/O space. */ - space = PCIIO_SPACE_IO; - mask = -4; - code = base & 3; - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { - base = 0; /* decode not enabled */ - } - } else { - /* BASE is in MEM space. */ - space = PCIIO_SPACE_MEM; - mask = -16; - code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { - base = 0; /* decode not enabled */ - } else if (base & 0xC0000000) { - base = 0; /* outside permissable range */ - } else if ((code == PCI_BA_MEM_64BIT) && -#ifdef LITTLE_ENDIAN - (wptr[(((win + 1)*4)^4)/4] != 0)) { -#else - (wptr[win + 1] != 0)) { -#endif /* LITTLE_ENDIAN */ - base = 0; /* outside permissable range */ - } - } - - if (base != 0) { /* estimate size */ - size = base & -base; - } else { /* calculate size */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ - size = wptr[((win*4)^4)/4]; /* get stored bits */ -#else - wptr[win] = ~0; /* turn on all bits */ - size = wptr[win]; /* get stored bits */ -#endif /* LITTLE_ENDIAN */ - size &= mask; /* keep addr */ - size &= -size; /* keep lsbit */ - if (size == 0) - continue; - } - - pcibr_info->f_window[win].w_space = space; - pcibr_info->f_window[win].w_base = base; - pcibr_info->f_window[win].w_size = size; - - /* - * If this window already has PCI space - * allocated for it, "subtract" that space from - * our running freeblocks. Don't worry about - * overlaps in existing allocated windows; we - * may be overstating their sizes anyway. - */ - - if (base && size) { - if (space == PCIIO_SPACE_IO) { - pcibr_freeblock_sub(&pci_io_fb, - &pci_io_fl, - base, size); - } else { - pcibr_freeblock_sub(&pci_lo_fb, - &pci_lo_fl, - base, size); - pcibr_freeblock_sub(&pci_hi_fb, - &pci_hi_fl, - base, size); - } - } -#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) - /* - * IOC3 BASE_ADDR* BUG WORKAROUND - * - - * If we write to BASE1 on the IOC3, the - * data in BASE0 is replaced. The - * original workaround was to remember - * the value of BASE0 and restore it - * when we ran off the end of the BASE - * registers; however, a later - * workaround was added (I think it was - * rev 1.44) to avoid setting up - * anything but BASE0, with the comment - * that writing all ones to BASE1 set - * the enable-parity-error test feature - * in IOC3's SCR bit 14. - * - * So, unless we defer doing any PCI - * space allocation until drivers - * attach, and set up a way for drivers - * (the IOC3 in paricular) to tell us - * generically to keep our hands off - * BASE registers, we gotta "know" about - * the IOC3 here. - * - * Too bad the PCI folks didn't reserve the - * all-zero value for 'no BASE here' (it is a - * valid code for an uninitialized BASE in - * 32-bit PCI memory space). - */ - - if ((vendor == IOC3_VENDOR_ID_NUM) && - (device == IOC3_DEVICE_ID_NUM)) - break; -#endif - if (code == PCI_BA_MEM_64BIT) { - win++; /* skip upper half */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = 0; /* which must be zero */ -#else - wptr[win] = 0; /* which must be zero */ -#endif /* LITTLE_ENDIAN */ - } - } /* next win */ - } /* next func */ - - /* Store back the values for allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_info_free - * Remove all the PCI infrastructural information associated - * with a particular PCI device. - */ -int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - int nfunc; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - -#if !defined(CONFIG_IA64_SGI_SN1) - /* Clean out all the base registers */ - bridge = pcibr_soft->bs_base; - cfgw = bridge->b_type0_cfg_dev[slot].l; - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = 0; -#else - wptr[win] = 0; -#endif /* LITTLE_ENDIAN */ -#endif /* !CONFIG_IA64_SGI_SN1 */ - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - - pcibr_device_info_free(pcibr_vhdl, slot); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - DELA(pcibr_infoh,nfunc); - pcibr_soft->bs_slot[slot].bss_ninfo = 0; - - return(0); -} - -int as_debug = 0; -/* - * pcibr_slot_addr_space_init - * Reserve chunks of PCI address space as required by - * the base registers in the card. - */ -int -pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - size_t align; - iopaddr_t mask; - int nbars; - int nfunc; - int func; - int win; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* Get the current values for the allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - if (as_debug) -#ifdef LATER - PCI_ADDR_SPACE_LIMITS_PRINT(); -#endif - /* allocate address space, - * for windows that have not been - * previously assigned. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - if (nfunc < 1) - return(EINVAL); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - if (!pcibr_infoh) - return(EINVAL); - - /* - * Try to make the DevIO windows not - * overlap by pushing the "io" and "hi" - * allocation areas up to the next one - * or two megabyte bound. This also - * keeps them from being zero. - * - * DO NOT do this with "pci_lo" since - * the entire "lo" area is only a - * megabyte, total ... - */ - align = (slot < 2) ? 0x200000 : 0x100000; - mask = -align; - pci_io_fb = (pci_io_fb + align - 1) & mask; - pci_hi_fb = (pci_hi_fb + align - 1) & mask; - - for (func = 0; func < nfunc; ++func) { - cfg_p cfgw; - cfg_p wptr; - pciio_space_t space; - iopaddr_t base; - size_t size; - cfg_p pci_cfg_cmd_reg_p; - unsigned pci_cfg_cmd_reg; - unsigned pci_cfg_cmd_reg_add = 0; - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - -#if defined(CONFIG_IA64_SGI_SN1) - nbars = PCI_CFG_BASE_ADDRS; -#else - if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) - nbars = 2; - else - nbars = PCI_CFG_BASE_ADDRS; -#endif - - for (win = 0; win < nbars; ++win) { - - space = pcibr_info->f_window[win].w_space; - base = pcibr_info->f_window[win].w_base; - size = pcibr_info->f_window[win].w_size; - - if (size < 1) - continue; - - if (base >= size) { -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", - slot, func, win, space, base, base + size - 1); -#endif - continue; /* already allocated */ - } - align = size; /* ie. 0x00001000 */ - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ - mask = -align; /* ie. 0xFFFFC000 */ - - switch (space) { - case PCIIO_SPACE_IO: - base = (pci_io_fb + align - 1) & mask; - if ((base + size) > pci_io_fl) { - base = 0; - break; - } - pci_io_fb = base + size; - break; - - case PCIIO_SPACE_MEM: -#ifdef LITTLE_ENDIAN - if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == -#else - if ((wptr[win] & PCI_BA_MEM_LOCATION) == -#endif /* LITTLE_ENDIAN */ - PCI_BA_MEM_1MEG) { - /* allocate from 20-bit PCI space */ - base = (pci_lo_fb + align - 1) & mask; - if ((base + size) > pci_lo_fl) { - base = 0; - break; - } - pci_lo_fb = base + size; - } else { - /* allocate from 32-bit or 64-bit PCI space */ - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) { - base = 0; - break; - } - pci_hi_fb = base + size; - } - break; - - default: - base = 0; -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d window %d had bad space code %d\n", - slot, win, space); -#endif - } - pcibr_info->f_window[win].w_base = base; -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = base; -#if DEBUG && PCI_DEBUG - printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); -#endif -#else - wptr[win] = base; -#endif /* LITTLE_ENDIAN */ - -#if DEBUG && PCI_DEBUG - if (base >= size) - printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", - slot, func, win, space, base, base + size - 1); - else - printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", - slot, func, win, size, space); -#endif - } /* next base */ - - /* - * Allocate space for the EXPANSION ROM - * NOTE: DO NOT DO THIS ON AN IOC3, - * as it blows the system away. - */ - base = size = 0; - if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || - (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { - - wptr = cfgw + PCI_EXPANSION_ROM / 4; -#ifdef LITTLE_ENDIAN - wptr[1] = 0xFFFFF000; - mask = wptr[1]; -#else - *wptr = 0xFFFFF000; - mask = *wptr; -#endif /* LITTLE_ENDIAN */ - if (mask & 0xFFFFF000) { - size = mask & -mask; - align = size; - if (align < _PAGESZ) - align = _PAGESZ; - mask = -align; - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) - base = size = 0; - else { - pci_hi_fb = base + size; -#ifdef LITTLE_ENDIAN - wptr[1] = base; -#else - *wptr = base; -#endif /* LITTLE_ENDIAN */ -#if DEBUG && PCI_DEBUG - printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", - pcibr_soft->bs_name, slot, - base, base + size - 1); -#endif - } - } - } - pcibr_info->f_rbase = base; - pcibr_info->f_rsize = size; - - /* - * if necessary, update the board's - * command register to enable decoding - * in the windows we added. - * - * There are some bits we always want to - * be sure are set. - */ - pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - - /* - * The Adaptec 1160 FC Controller WAR #767995: - * The part incorrectly ignores the upper 32 bits of a 64 bit - * address when decoding references to it's registers so to - * keep it from responding to a bus cycle that it shouldn't - * we only use I/O space to get at it's registers. Don't - * enable memory space accesses on that PCI device. - */ - #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ - #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ - - if ((pcibr_info->f_vendor != FCADP_VENDID) || - (pcibr_info->f_device != FCADP_DEVID)) - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; - - pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - - pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; - pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; -#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ - if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) - fast_back_to_back_enable = 0; -#endif - pci_cfg_cmd_reg &= 0xFFFF; - if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; - - } /* next func */ - - /* Now that we have allocated new chunks of PCI address spaces to this - * card we need to update the bookkeeping values which indicate - * the current PCI address space allocations. - */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_device_init - * Setup the device register in the bridge for this PCI slot. - */ -int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - bridgereg_t devreg; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* - * Adjustments to Device(x) - * and init of bss_device shadow - */ - devreg = bridge->b_device[slot].reg; - devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; - devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; -#ifdef LITTLE_ENDIAN - devreg |= BRIDGE_DEV_DEV_SWAP; -#endif - pcibr_soft->bs_slot[slot].bss_device = devreg; - bridge->b_device[slot].reg = devreg; - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); -#endif - -#if DEBUG && PCI_DEBUG - printk("pcibr: PCI space allocation done.\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_guest_info_init - * Setup the host/guest relations for a PCI slot. - */ -int -pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - pcibr_soft_slot_t slotp; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - slotp = &pcibr_soft->bs_slot[slot]; - - /* create info and verticies for guest slots; - * for compatibilitiy macros, create info - * for even unpopulated slots (but do not - * build verticies for them). - */ - if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { - NEWA(pcibr_infoh, 1); - pcibr_soft->bs_slot[slot].bss_ninfo = 1; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - - if (pcibr_soft->bs_slot[slot].has_host) { - slotp->slot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - } - } - - /* generate host/guest relations - */ - if (pcibr_soft->bs_slot[slot].has_host) { - int host = pcibr_soft->bs_slot[slot].host_slot; - pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; - - hwgraph_edge_add(slotp->slot_conn, - host_slotp->slot_conn, - EDGE_LBL_HOST); - - /* XXX- only gives us one guest edge per - * host. If/when we have a host with more than - * one guest, we will need to figure out how - * the host finds all its guests, and sorts - * out which one is which. - */ - hwgraph_edge_add(host_slotp->slot_conn, - slotp->slot_conn, - EDGE_LBL_GUEST); - } - - return(0); -} - -/* - * pcibr_slot_initial_rrb_alloc - * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation - * strategy routine defined per platform. - */ - -int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - int c0, c1; - int r; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* How may RRBs are on this slot? - */ - c0 = do_pcibr_rrb_count_valid(bridge, slot); - c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); - -#if PCIBR_RRB_DEBUG - printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); -#endif - - /* Do we really need any? - */ - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - pcibr_info = pcibr_infoh[0]; - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - if (c0 > 0) - do_pcibr_rrb_free(bridge, slot, c0); - if (c1 > 0) - do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); - pcibr_soft->bs_rrb_valid[slot] = 0x1000; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(ENODEV); - } - - pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; - pcibr_soft->bs_rrb_valid[slot] = c0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; - - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); - - r = 3 - (c0 + c1); - - if (r > 0) { - pcibr_soft->bs_rrb_res[slot] = r; - pcibr_soft->bs_rrb_avail[slot & 1] -= r; - } - -#if PCIBR_RRB_DEBUG - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - async_attach_t aa = NULL; - int func; - devfs_handle_t xconn_vhdl,conn_vhdl; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - - if (pcibr_soft->bs_slot[slot].has_host) { - return(EPERM); - } - - xconn_vhdl = pcibr_soft->bs_conn; - aa = async_attach_get_info(xconn_vhdl); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - - /* If the PCI device has been disabled in the prom, - * do not set it up for driver attach. NOTE: usrpci - * and pciba will not "see" this connection point! - */ - if (device_admin_info_get(conn_vhdl, ADMIN_LBL_DISABLED)) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING("pcibr_slot_call_device_attach: %v disabled\n", - conn_vhdl); -#endif - continue; - } -#ifdef LATER - /* - * Activate if and when we support cdl. - */ - if (aa) - async_attach_add_info(conn_vhdl, aa); -#endif /* LATER */ - - error_func = pciio_device_attach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; - } else { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int func; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_soft->bs_slot[slot].has_host) - return(EPERM); - - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - - error_func = pciio_device_detach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; - } else { - if (conn_vhdl != GRAPH_VERTEX_NONE) - pcibr_device_unregister(conn_vhdl); - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. - */ -int -pcibr_slot_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - int error; - - /* Call the device detach function */ - error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); - return (error); - -} - -/* - * pcibr_is_slot_sys_critical - * Check slot for any functions that are system critical. - * Return 1 if any are system critical or 0 otherwise. - * - * This function will always return 0 when called by - * pcibr_attach() because the system critical vertices - * have not yet been set in the hwgraph. - */ -int -pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int func; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(0); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - if (is_sys_critical_vertex(conn_vhdl)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("%v is a system critical device vertex\n", conn_vhdl); -#else - PRINT_WARNING("%p is a system critical device vertex\n", conn_vhdl); -#endif - return(1); - } - - } - - return(0); -} - -/* - * pcibr_device_unregister - * This frees up any hardware resources reserved for this PCI device - * and removes any PCI infrastructural information setup for it. - * This is usually used at the time of shutting down of the PCI card. - */ -int -pcibr_device_unregister(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - int error_call; - int error = 0; - - pciio_info = pciio_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Clear all the hardware xtalk resources for this device */ - xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); - - /* Flush all the rrbs */ - pcibr_rrb_flush(pconn_vhdl); - - /* Free the rrbs allocated to this slot */ - error_call = do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]); - - if (error_call) - error = ERANGE; - - pcibr_soft->bs_rrb_valid[slot] = 0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; - pcibr_soft->bs_rrb_res[slot] = 0; - - /* Flush the write buffers !! */ - error_call = pcibr_wrb_flush(pconn_vhdl); - - if (error_call) - error = error_call; - - /* Clear the information specific to the slot */ - error_call = pcibr_slot_info_free(pcibr_vhdl, slot); - - if (error_call) - error = error_call; - - return(error); - -} - -/* - * build a convenience link path in the - * form of "...//bus/" - * - * returns 1 on success, 0 otherwise - * - * depends on hwgraph separator == '/' - */ -int -pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) -{ - char dst[MAXDEVNAME]; - char *dp = dst; - char *cp, *xp; - int widgetnum; - char pcibus[8]; - devfs_handle_t nvtx, svtx; - int rv; - -#if DEBUG - printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", - slot, f_c); - { - int pos; - char dname[256]; - pos = devfs_generate_path(f_c, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) - return 0; - - /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ - - /* find the widget number */ - xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); - if (xp == NULL) - return 0; - widgetnum = atoi(xp+7); - if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) - return 0; - - /* remove "/pci/direct" from path */ - cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); - if (cp == NULL) - return 0; - *cp = (char)NULL; - - /* get the vertex for the widget */ - if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) - return 0; - - *xp = (char)NULL; /* remove "/xtalk/..." from path */ - - /* dst example now == /hw/module/001c02/Pbrick */ - - /* get the bus number */ - strcat(dst, "/bus"); - sprintf(pcibus, "%d", p_busnum[widgetnum]); - - /* link to bus to widget */ - rv = hwgraph_path_add(NULL, dp, &nvtx); - if (GRAPH_SUCCESS == rv) - rv = hwgraph_edge_add(nvtx, svtx, pcibus); - - return (rv == GRAPH_SUCCESS); -} - - -/* - * pcibr_attach: called every time the crosstalk - * infrastructure is asked to initialize a widget - * that matches the part number we handed to the - * registration routine above. - */ -/*ARGSUSED */ -int -pcibr_attach(devfs_handle_t xconn_vhdl) -{ - /* REFERENCED */ - graph_error_t rc; - devfs_handle_t pcibr_vhdl; - devfs_handle_t ctlr_vhdl; - bridge_t *bridge = NULL; - bridgereg_t id; - int rev; - pcibr_soft_t pcibr_soft; - pcibr_info_t pcibr_info; - xwidget_info_t info; - xtalk_intr_t xtalk_intr; - device_desc_t dev_desc; - int slot; - int ibit; - devfs_handle_t noslot_conn; - char devnm[MAXDEVNAME], *s; - pcibr_hints_t pcibr_hints; - bridgereg_t b_int_enable; - unsigned rrb_fixed = 0; - - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - - int spl_level; -#ifdef LATER - char *nicinfo = (char *)0; -#endif - -#if PCI_FBBE - int fast_back_to_back_enable; -#endif - l1sc_t *scp; - nasid_t nasid; - - async_attach_t aa = NULL; - - aa = async_attach_get_info(xconn_vhdl); - -#if DEBUG && ATTACH_DEBUG - printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); - { - int pos; - char dname[256]; - pos = devfs_generate_path(xconn_vhdl, dname, 256); - printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif - - /* Setup the PRB for the bridge in CONVEYOR BELT - * mode. PRBs are setup in default FIRE-AND-FORGET - * mode during the initialization. - */ - hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); - - bridge = (bridge_t *) - xtalk_piotrans_addr(xconn_vhdl, NULL, - 0, sizeof(bridge_t), 0); - -#ifndef MEDUSA_HACK - if ((bridge->b_wid_stat & BRIDGE_STAT_PCI_GIO_N) == 0) - return -1; /* someone else handles GIO bridges. */ -#endif - -#ifdef BRINGUP - if (XWIDGET_PART_REV_NUM(bridge->b_wid_id) == XBRIDGE_PART_REV_A) - NeedXbridgeSwap = 1; -#endif - - /* - * Create the vertex for the PCI bus, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); - - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - - ASSERT(ctlr_vhdl != NULL); - - /* - * decode the nic, and hang its stuff off our - * connection point where other drivers can get - * at it. - */ -#ifdef LATER - nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); -#endif - - /* - * Get the hint structure; if some NIC callback - * marked this vertex as "hands-off" then we - * just return here, before doing anything else. - */ - pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); - - if (pcibr_hints && pcibr_hints->ph_hands_off) - return -1; /* generic operations disabled */ - - id = bridge->b_wid_id; - rev = XWIDGET_PART_REV_NUM(id); - - hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); - - /* - * allocate soft state structure, fill in some - * fields, and hook it up to our vertex. - */ - NEW(pcibr_soft); - BZERO(pcibr_soft, sizeof *pcibr_soft); - pcibr_soft_set(pcibr_vhdl, pcibr_soft); - - pcibr_soft->bs_conn = xconn_vhdl; - pcibr_soft->bs_vhdl = pcibr_vhdl; - pcibr_soft->bs_base = bridge; - pcibr_soft->bs_rev_num = rev; - pcibr_soft->bs_intr_bits = pcibr_intr_bits; - if (is_xbridge(bridge)) { - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 1; - } else { - pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 0; - } - - nasid = NASID_GET(bridge); - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - pcibr_soft->bs_l1sc = scp; - pcibr_soft->bs_moduleid = iobrick_module_get(scp); - pcibr_soft->bsi_err_intr = 0; - - /* Bridges up through REV C - * are unable to set the direct - * byteswappers to BYTE_STREAM. - */ - if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { - pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; - pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; - } -#if PCIBR_SOFT_LIST - { - pcibr_list_p self; - - NEW(self); - self->bl_soft = pcibr_soft; - self->bl_vhdl = pcibr_vhdl; - self->bl_next = pcibr_list; - self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); - } -#endif - - /* - * get the name of this bridge vertex and keep the info. Use this - * only where it is really needed now: like error interrupts. - */ - s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); - pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(pcibr_soft->bs_name, s); - -#if SHOW_REVS || DEBUG -#if !DEBUG - if (kdebug) -#endif - printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", - is_xbridge(bridge) ? "X" : "", - (rev == BRIDGE_PART_REV_A) ? "A" : - (rev == BRIDGE_PART_REV_B) ? "B" : - (rev == BRIDGE_PART_REV_C) ? "C" : - (rev == BRIDGE_PART_REV_D) ? "D" : - (rev == XBRIDGE_PART_REV_A) ? "A" : - (rev == XBRIDGE_PART_REV_B) ? "B" : - "unknown", - rev, pcibr_soft->bs_name); -#endif - - info = xwidget_info_get(xconn_vhdl); - pcibr_soft->bs_xid = xwidget_info_id_get(info); - pcibr_soft->bs_master = xwidget_info_master_get(info); - pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); - - /* - * Init bridge lock. - */ - spin_lock_init(&pcibr_soft->bs_lock); - - /* - * If we have one, process the hints structure. - */ - if (pcibr_hints) { - rrb_fixed = pcibr_hints->ph_rrb_fixed; - - pcibr_soft->bs_rrb_fixed = rrb_fixed; - - if (pcibr_hints->ph_intr_bits) - pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; - - for (slot = 0; slot < 8; ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; - - if (hslot < 0) { - pcibr_soft->bs_slot[slot].host_slot = slot; - } else { - pcibr_soft->bs_slot[slot].has_host = 1; - pcibr_soft->bs_slot[slot].host_slot = hslot; - } - } - } - /* - * set up initial values for state fields - */ - for (slot = 0; slot < 8; ++slot) { - pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); - } - - for (ibit = 0; ibit < 8; ++ibit) { - pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = - &(bridge->b_int_status); - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; - } - - /* - * connect up our error handler - */ - xwidget_error_register(xconn_vhdl, pcibr_error_handler, pcibr_soft); - - /* - * Initialize various Bridge registers. - */ - - /* - * On pre-Rev.D bridges, set the PCI_RETRY_CNT - * to zero to avoid dropping stores. (#475347) - */ - if (rev < BRIDGE_PART_REV_D) - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; - - /* - * Clear all pending interrupts. - */ - bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); - - /* - * Until otherwise set up, - * assume all interrupts are - * from slot 7. - */ - bridge->b_int_device = (uint32_t) 0xffffffff; - - { - bridgereg_t dirmap; - paddr_t paddr; - iopaddr_t xbase; - xwidgetnum_t xport; - iopaddr_t offset; - int num_entries = 0; - int entry; - cnodeid_t cnodeid; - nasid_t nasid; - char *node_val; - devfs_handle_t node_vhdl; - char vname[MAXDEVNAME]; - - /* Set the Bridge's 32-bit PCI to XTalk - * Direct Map register to the most useful - * value we can determine. Note that we - * must use a single xid for all of: - * direct-mapped 32-bit DMA accesses - * direct-mapped 64-bit DMA accesses - * DMA accesses through the PMU - * interrupts - * This is the only way to guarantee that - * completion interrupts will reach a CPU - * after all DMA data has reached memory. - * (Of course, there may be a few special - * drivers/controllers that explicitly manage - * this ordering problem.) - */ - - cnodeid = 0; /* default node id */ - /* - * Determine the base address node id to be used for all 32-bit - * Direct Mapping I/O. The default is node 0, but this can be changed - * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE - * attribute in the irix.sm config file. A device driver can obtain - * this node value via a call to pcibr_get_dmatrans_node(). - */ - node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE); - if (node_val != NULL) { - node_vhdl = hwgraph_path_to_vertex(node_val); - if (node_vhdl != GRAPH_VERTEX_NONE) { - cnodeid = nodevertex_to_cnodeid(node_vhdl); - } - if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) { - cnodeid = 0; - vertex_to_name(pcibr_vhdl, vname, sizeof(vname)); - PRINT_WARNING( "Invalid hwgraph node path specified:\n DEVICE_ADMIN: %s %s=%s\n", - vname, ADMIN_LBL_DMATRANS_NODE, node_val); - } - } - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - paddr = NODE_OFFSET(nasid) + 0; - - /* currently, we just assume that if we ask - * for a DMA mapping to "zero" the XIO - * host will transmute this into a request - * for the lowest hunk of memory. - */ - xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, - paddr, _PAGESZ, 0); - - if (xbase != XIO_NOWHERE) { - if (XIO_PACKED(xbase)) { - xport = XIO_PORT(xbase); - xbase = XIO_ADDR(xbase); - } else - xport = pcibr_soft->bs_mxid; - - offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); - xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; - - dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; - - if (xbase) - dirmap |= BRIDGE_DIRMAP_OFF & xbase; - else if (offset >= (512 << 20)) - dirmap |= BRIDGE_DIRMAP_ADD512; - - bridge->b_dir_map = dirmap; - } - /* - * Set bridge's idea of page size according to the system's - * idea of "IO page size". TBD: The idea of IO page size - * should really go away. - */ - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - spl_level = splhi(); -#if IOPGSIZE == 4096 - bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; -#elif IOPGSIZE == 16384 - bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; -#else - <<>>; -#endif - bridge->b_wid_control; /* inval addr bug war */ - splx(spl_level); - - /* Initialize internal mapping entries */ - for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) - bridge->b_int_ate_ram[entry].wr = 0; - - /* - * Determine if there's external mapping SSRAM on this - * bridge. Set up Bridge control register appropriately, - * inititlize SSRAM, and set software up to manage RAM - * entries as an allocatable resource. - * - * Currently, we just use the rm* routines to manage ATE - * allocation. We should probably replace this with a - * Best Fit allocator. - * - * For now, if we have external SSRAM, avoid using - * the internal ssram: we can't turn PREFETCH on - * when we use the internal SSRAM; and besides, - * this also guarantees that no allocation will - * straddle the internal/external line, so we - * can increment ATE write addresses rather than - * recomparing against BRIDGE_INTERNAL_ATES every - * time. - */ - if (is_xbridge(bridge)) - num_entries = 0; - else - num_entries = pcibr_init_ext_ate_ram(bridge); - - /* we always have 128 ATEs (512 for Xbridge) inside the chip - * even if disabled for debugging. - */ - pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); - pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); -#endif - - if (num_entries > pcibr_soft->bs_int_ate_size) { -#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ - printk("pcibr_attach: disabling internal ATEs.\n"); - pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); -#endif - pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); - pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, - num_entries - pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d EXTERNAL ATEs\n", - num_entries - pcibr_soft->bs_int_ate_size); -#endif - } - } - - { - bridgereg_t dirmap; - iopaddr_t xbase; - - /* - * now figure the *real* xtalk base address - * that dirmap sends us to. - */ - dirmap = bridge->b_dir_map; - if (dirmap & BRIDGE_DIRMAP_OFF) - xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) - << BRIDGE_DIRMAP_OFF_ADDRSHFT; - else if (dirmap & BRIDGE_DIRMAP_ADD512) - xbase = 512 << 20; - else - xbase = 0; - - pcibr_soft->bs_dir_xbase = xbase; - - /* it is entirely possible that we may, at this - * point, have our dirmap pointing somewhere - * other than our "master" port. - */ - pcibr_soft->bs_dir_xport = - (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; - } - - /* pcibr sources an error interrupt; - * figure out where to send it. - * - * If any interrupts are enabled in bridge, - * then the prom set us up and our interrupt - * has already been reconnected in mlreset - * above. - * - * Need to set the D_INTR_ISERR flag - * in the dev_desc used for allocating the - * error interrupt, so our interrupt will - * be properly routed and prioritized. - * - * If our crosstalk provider wants to - * fix widget error interrupts to specific - * destinations, D_INTR_ISERR is how it - * knows to do this. - */ - - dev_desc = device_desc_dup(pcibr_vhdl); - device_desc_flags_set(dev_desc, - device_desc_flags_get(dev_desc) | D_INTR_ISERR); - device_desc_intr_name_set(dev_desc, "Bridge error"); - - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); - ASSERT(xtalk_intr != NULL); - - device_desc_free(dev_desc); - - pcibr_soft->bsi_err_intr = xtalk_intr; - - /* - * On IP35 with XBridge, we do some extra checks in pcibr_setwidint - * in order to work around some addressing limitations. In order - * for that fire wall to work properly, we need to make sure we - * start from a known clean state. - */ - pcibr_clearwidint(bridge); - - xtalk_intr_connect(xtalk_intr, - (intr_func_t) pcibr_error_intr_handler, - (intr_arg_t) pcibr_soft, - (xtalk_intr_setfunc_t) pcibr_setwidint, - (void *) bridge, - (void *) 0); - - /* - * now we can start handling error interrupts; - * enable all of them. - * NOTE: some PCI ints may already be enabled. - */ - b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; - - - bridge->b_int_enable = b_int_enable; - bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ - - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * Depending on the rev of bridge, disable certain features. - * Easiest way seems to be to force the PCIBR_NOwhatever - * flag to be on for all DMA calls, which overrides any - * PCIBR_whatever flag or even the setting of whatever - * from the PCIIO_DMA_class flags (or even from the other - * PCIBR flags, since NO overrides YES). - */ - pcibr_soft->bs_dma_flags = 0; - - /* PREFETCH: - * Always completely disabled for REV.A; - * at "pcibr_prefetch_enable_rev", anyone - * asking for PCIIO_PREFETCH gets it. - * Between these two points, you have to ask - * for PCIBR_PREFETCH, which promises that - * your driver knows about known Bridge WARs. - */ - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) - pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; - else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - - /* WRITE_GATHER: - * Disabled up to but not including the - * rev number in pcibr_wg_enable_rev. There - * is no "WAR range" as with prefetch. - */ - if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; - - pciio_provider_register(pcibr_vhdl, &pcibr_provider); - pciio_provider_startup(pcibr_vhdl); - - pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ - pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ - - pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ - pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ - - pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ - pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ - - - PCI_ADDR_SPACE_LIMITS_STORE(); - - /* build "no-slot" connection point - */ - pcibr_info = pcibr_device_info_new - (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - noslot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - - /* Remember the no slot connection point info for tearing it - * down during detach. - */ - pcibr_soft->bs_noslot_conn = noslot_conn; - pcibr_soft->bs_noslot_info = pcibr_info; -#if PCI_FBBE - fast_back_to_back_enable = 1; -#endif - -#if PCI_FBBE - if (fast_back_to_back_enable) { - /* - * All devices on the bus are capable of fast back to back, so - * we need to set the fast back to back bit in all devices on - * the bus that are capable of doing such accesses. - */ - } -#endif - -#ifdef LATER - /* If the bridge has been reset then there is no need to reset - * the individual PCI slots. - */ - for (slot = 0; slot < 8; ++slot) - /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl, slot); -#endif - - for (slot = 0; slot < 8; ++slot) - /* Find out what is out there */ - (void)pcibr_slot_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Set up the address space for this slot in the pci land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - -#ifndef __ia64 -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - for (slot = 0; slot < 8; ++slot) - /* Set up convenience links */ - if (is_xbridge(bridge)) - if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ - pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); -#endif -#endif - - for (slot = 0; slot < 8; ++slot) - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Initial RRB management */ - (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); - - /* driver attach routines should be called out from generic linux code */ - for (slot = 0; slot < 8; ++slot) - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); - - /* - * Each Pbrick PCI bus only has slots 1 and 2. Similarly for - * widget 0xe on Ibricks. Allocate RRB's accordingly. - */ - if (pcibr_soft->bs_moduleid > 0) { - switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { - case 'p': /* Pbrick */ - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - break; - case 'i': /* Ibrick */ - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); - } - break; - } /* switch */ - } - -#ifdef LATER - if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); -#if PCIBR_RRB_DEBUG - printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); - - printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", - pcibr_vhdl, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - - for (slot = 0; slot < 8; ++slot) - printf("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - - printf("\n"); -#endif - } -#else - FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif - - if (aa) - async_attach_add_info(noslot_conn, aa); - - pciio_device_attach(noslot_conn, 0); - - - /* - * Tear down pointer to async attach info -- async threads for - * bridge's descendants may be running but the bridge's work is done. - */ - if (aa) - async_attach_del_info(xconn_vhdl); - - return 0; -} -/* - * pcibr_detach: - * Detach the bridge device from the hwgraph after cleaning out all the - * underlying vertices. - */ -int -pcibr_detach(devfs_handle_t xconn) -{ - pciio_slot_t slot; - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - - /* Get the bridge vertex from its xtalk connection point */ - if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) - return(1); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Disable the interrupts from the bridge */ - bridge->b_int_enable = 0; - - /* Detach all the PCI devices talking to this bridge */ - for(slot = 0; slot < 8; slot++) { -#ifdef DEBUG - printk("pcibr_device_detach called for %p/%d\n", - pcibr_vhdl,slot); -#endif - pcibr_slot_detach(pcibr_vhdl, slot, 0); - } - - /* Unregister the no-slot connection point */ - pciio_device_info_unregister(pcibr_vhdl, - &(pcibr_soft->bs_noslot_info->f_c)); - - spin_lock_destroy(&pcibr_soft->bs_lock); - kfree(pcibr_soft->bs_name); - - /* Error handler gets unregistered when the widget info is - * cleaned - */ - /* Free the soft ATE maps */ - if (pcibr_soft->bs_int_ate_map) - rmfreemap(pcibr_soft->bs_int_ate_map); - if (pcibr_soft->bs_ext_ate_map) - rmfreemap(pcibr_soft->bs_ext_ate_map); - - /* Disconnect the error interrupt and free the xtalk resources - * associated with it. - */ - xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); - xtalk_intr_free(pcibr_soft->bsi_err_intr); - - /* Clear the software state maintained by the bridge driver for this - * bridge. - */ - DEL(pcibr_soft); - /* Remove the Bridge revision labelled info */ - (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); - /* Remove the character device associated with this bridge */ - (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); - /* Remove the PCI bridge vertex */ - (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); - - return(0); -} - -int -pcibr_asic_rev(devfs_handle_t pconn_vhdl) -{ - devfs_handle_t pcibr_vhdl; - arbitrary_info_t ainfo; - - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) - return -1; - - if (GRAPH_SUCCESS != - hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) - return -1; - - return (int) ainfo; -} - -int -pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t slot; - slot = pciio_info_slot_get(pciio_info); - pcibr_device_write_gather_flush(pcibr_soft, slot); - return 0; -} - -/* ===================================================================== - * PIO MANAGEMENT - */ - -LOCAL iopaddr_t -pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, - pciio_slot_t slot, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - unsigned bar; /* which BASE reg on device is decoding */ - iopaddr_t xio_addr = XIO_NOWHERE; - - pciio_space_t wspace; /* which space device is decoding */ - iopaddr_t wbase; /* base of device decode on PCI */ - size_t wsize; /* size of device decode on PCI */ - - int try; /* DevIO(x) window scanning order control */ - int win; /* which DevIO(x) window is being used */ - pciio_space_t mspace; /* target space for devio(x) register */ - iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ - size_t msize; /* size of devio(x) mapped area on PCI */ - size_t mmask; /* addr bits stored in Device(x) */ - - unsigned long s; - - s = pcibr_lock(pcibr_soft); - - if (pcibr_soft->bs_slot[slot].has_host) { - slot = pcibr_soft->bs_slot[slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; - } - if (space == PCIIO_SPACE_NONE) - goto done; - - if (space == PCIIO_SPACE_CFG) { - /* - * Usually, the first mapping - * established to a PCI device - * is to its config space. - * - * In any case, we definitely - * do NOT need to worry about - * PCI BASE registers, and - * MUST NOT attempt to point - * the DevIO(x) window at - * this access ... - */ - if (((flags & PCIIO_BYTE_STREAM) == 0) && - ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) - xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); - - goto done; - } - if (space == PCIIO_SPACE_ROM) { - /* PIO to the Expansion Rom. - * Driver is responsible for - * enabling and disabling - * decodes properly. - */ - wbase = pcibr_info->f_rbase; - wsize = pcibr_info->f_rsize; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - pci_addr += wbase; - space = PCIIO_SPACE_MEM; - } - /* - * reduce window mappings to raw - * space mappings (maybe allocating - * windows), and try for DevIO(x) - * usage (setting it if it is available). - */ - bar = space - PCIIO_SPACE_WIN0; - if (bar < 6) { - wspace = pcibr_info->f_window[bar].w_space; - if (wspace == PCIIO_SPACE_NONE) - goto done; - - /* get PCI base and size */ - wbase = pcibr_info->f_window[bar].w_base; - wsize = pcibr_info->f_window[bar].w_size; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - /* shift from window relative to - * decoded space relative. - */ - pci_addr += wbase; - space = wspace; - } else - bar = -1; - - /* Scan all the DevIO(x) windows twice looking for one - * that can satisfy our request. The first time through, - * only look at assigned windows; the second time, also - * look at PCIIO_SPACE_NONE windows. Arrange the order - * so we always look at our own window first. - * - * We will not attempt to satisfy a single request - * by concatinating multiple windows. - */ - for (try = 0; try < 16; ++try) { - bridgereg_t devreg; - unsigned offset; - - win = (try + slot) % 8; - - /* If this DevIO(x) mapping area can provide - * a mapping to this address, use it. - */ - msize = (win < 2) ? 0x200000 : 0x100000; - mmask = -msize; - if (space != PCIIO_SPACE_IO) - mmask &= 0x3FFFFFFF; - - offset = pci_addr & (msize - 1); - - /* If this window can't possibly handle that request, - * go on to the next window. - */ - if (((pci_addr & (msize - 1)) + req_size) > msize) - continue; - - devreg = pcibr_soft->bs_slot[win].bss_device; - - /* Is this window "nailed down"? - * If not, maybe we can use it. - * (only check this the second time through) - */ - mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; - if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { - - /* If this is the primary DevIO(x) window - * for some other device, skip it. - */ - if ((win != slot) && - (PCIIO_VENDOR_ID_NONE != - pcibr_soft->bs_slot[win].bss_vendor_id)) - continue; - - /* It's a free window, and we fit in it. - * Set up Device(win) to our taste. - */ - mbase = pci_addr & mmask; - - /* check that we would really get from - * here to there. - */ - if ((mbase | offset) != pci_addr) - continue; - - devreg &= ~BRIDGE_DEV_OFF_MASK; - if (space != PCIIO_SPACE_IO) - devreg |= BRIDGE_DEV_DEV_IO_MEM; - else - devreg &= ~BRIDGE_DEV_DEV_IO_MEM; - devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; - - /* default is WORD_VALUES. - * if you specify both, - * operation is undefined. - */ - if (flags & PCIIO_BYTE_STREAM) - devreg |= BRIDGE_DEV_DEV_SWAP; - else - devreg &= ~BRIDGE_DEV_DEV_SWAP; - - if (pcibr_soft->bs_slot[win].bss_device != devreg) { - bridge->b_device[win].reg = devreg; - pcibr_soft->bs_slot[win].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); -#endif - } - pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; - pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", - __FUNCTION__, __LINE__, space, space_desc, - pci_addr, pci_addr + req_size - 1, - slot, win, devreg); -#endif - - goto done; - } /* endif DevIO(x) not pointed */ - mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; - - /* Now check for request incompat with DevIO(x) - */ - if ((mspace != space) || - (pci_addr < mbase) || - ((pci_addr + req_size) > (mbase + msize)) || - ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || - (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) - continue; - - /* DevIO(x) window is pointed at PCI space - * that includes our target. Calculate the - * final XIO address, release the lock and - * return. - */ - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", - __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); -#endif - goto done; - } - - switch (space) { - /* - * Accesses to device decode - * areas that do a not fit - * within the DevIO(x) space are - * modified to be accesses via - * the direct mapping areas. - * - * If necessary, drivers can - * explicitly ask for mappings - * into these address spaces, - * but this should never be needed. - */ - case PCIIO_SPACE_MEM: /* "mem space" */ - case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; - break; - - case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; - break; - - case PCIIO_SPACE_IO: /* "i/o space" */ - /* Bridge Hardware Bug WAR #482741: - * The 4G area that maps directly from - * XIO space to PCI I/O space is busted - * until Bridge Rev D. - */ - if ((pcibr_soft->bs_rev_num > BRIDGE_PART_REV_C) && - ((pci_addr + BRIDGE_PCI_IO_BASE + req_size - 1) <= - BRIDGE_PCI_IO_LIMIT)) - xio_addr = pci_addr + BRIDGE_PCI_IO_BASE; - break; - } - - /* Check that "Direct PIO" byteswapping matches, - * try to change it if it does not. - */ - if (xio_addr != XIO_NOWHERE) { - unsigned bst; /* nonzero to set bytestream */ - unsigned *bfp; /* addr of record of how swapper is set */ - unsigned swb; /* which control bit to mung */ - unsigned bfo; /* current swapper setting */ - unsigned bfn; /* desired swapper setting */ - - bfp = ((space == PCIIO_SPACE_IO) - ? (&pcibr_soft->bs_pio_end_io) - : (&pcibr_soft->bs_pio_end_mem)); - - bfo = *bfp; - - bst = flags & PCIIO_BYTE_STREAM; - - bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; - - if (bfn == bfo) { /* we already match. */ - ; - } else if (bfo != 0) { /* we have a conflict. */ -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", - space, - bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - xio_addr = XIO_NOWHERE; - } else { /* OK to make the change. */ - bridgereg_t octl, nctl; - - swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; - octl = bridge->b_wid_control; - nctl = bst ? octl | swb : octl & ~swb; - - if (octl != nctl) /* make the change if any */ - bridge->b_wid_control = nctl; - - *bfp = bfn; /* record the assignment */ - -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", - space, - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - } - } - done: - pcibr_unlock(pcibr_soft, s); - return xio_addr; -} - -/*ARGSUSED6 */ -pcibr_piomap_t -pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - size_t req_size_max, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - pcibr_piomap_t *mapptr; - pcibr_piomap_t maplist; - pcibr_piomap_t pcibr_piomap; - iopaddr_t xio_addr; - xtalk_piomap_t xtalk_piomap; - unsigned long s; - - /* Make sure that the req sizes are non-zero */ - if ((req_size < 1) || (req_size_max < 1)) - return NULL; - - /* - * Code to translate slot/space/addr - * into xio_addr is common between - * this routine and pcibr_piotrans_addr. - */ - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - /* Check the piomap list to see if there is already an allocated - * piomap entry but not in use. If so use that one. Otherwise - * allocate a new piomap entry and add it to the piomap list - */ - mapptr = &(pcibr_info->f_piomap); - - s = pcibr_lock(pcibr_soft); - for (pcibr_piomap = *mapptr; - pcibr_piomap != NULL; - pcibr_piomap = pcibr_piomap->bp_next) { - if (pcibr_piomap->bp_mapsz == 0) - break; - } - - if (pcibr_piomap) - mapptr = NULL; - else { - pcibr_unlock(pcibr_soft, s); - NEW(pcibr_piomap); - } - - pcibr_piomap->bp_dev = pconn_vhdl; - pcibr_piomap->bp_slot = pciio_slot; - pcibr_piomap->bp_flags = flags; - pcibr_piomap->bp_space = space; - pcibr_piomap->bp_pciaddr = pci_addr; - pcibr_piomap->bp_mapsz = req_size; - pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); - - if (mapptr) { - s = pcibr_lock(pcibr_soft); - maplist = *mapptr; - pcibr_piomap->bp_next = maplist; - *mapptr = pcibr_piomap; - } - pcibr_unlock(pcibr_soft, s); - - - if (pcibr_piomap) { - xtalk_piomap = - xtalk_piomap_alloc(xconn_vhdl, 0, - xio_addr, - req_size, req_size_max, - flags & PIOMAP_FLAGS); - if (xtalk_piomap) { - pcibr_piomap->bp_xtalk_addr = xio_addr; - pcibr_piomap->bp_xtalk_pio = xtalk_piomap; - } else { - pcibr_piomap->bp_mapsz = 0; - pcibr_piomap = 0; - } - } - return pcibr_piomap; -} - -/*ARGSUSED */ -void -pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); - pcibr_piomap->bp_xtalk_pio = 0; - pcibr_piomap->bp_mapsz = 0; -} - -/*ARGSUSED */ -caddr_t -pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, - iopaddr_t pci_addr, - size_t req_size) -{ - return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, - pcibr_piomap->bp_xtalk_addr + - pci_addr - pcibr_piomap->bp_pciaddr, - req_size); -} - -/*ARGSUSED */ -void -pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); -} - -/*ARGSUSED */ -caddr_t -pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - iopaddr_t xio_addr; - - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); -} - -/* - * PIO Space allocation and management. - * Allocate and Manage the PCI PIO space (mem and io space) - * This routine is pretty simplistic at this time, and - * does pretty trivial management of allocation and freeing.. - * The current scheme is prone for fragmentation.. - * Change the scheme to use bitmaps. - */ - -/*ARGSUSED */ -iopaddr_t -pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - size_t req_size, - size_t alignment) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - pciio_piospace_t piosp; - unsigned long s; - - iopaddr_t *pciaddr, *pcilast; - iopaddr_t start_addr; - size_t align_mask; - - /* - * Check for proper alignment - */ - ASSERT(alignment >= NBPP); - ASSERT((alignment & (alignment - 1)) == 0); - - align_mask = alignment - 1; - s = pcibr_lock(pcibr_soft); - - /* - * First look if a previously allocated chunk exists. - */ - if ((piosp = pcibr_info->f_piospace)) { - /* - * Look through the list for a right sized free chunk. - */ - do { - if (piosp->free && - (piosp->space == space) && - (piosp->count >= req_size) && - !(piosp->start & align_mask)) { - piosp->free = 0; - pcibr_unlock(pcibr_soft, s); - return piosp->start; - } - piosp = piosp->next; - } while (piosp); - } - ASSERT(!piosp); - - switch (space) { - case PCIIO_SPACE_IO: - pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; - pcilast = &pcibr_soft->bs_spinfo.pci_io_last; - break; - case PCIIO_SPACE_MEM: - case PCIIO_SPACE_MEM32: - pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; - pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; - break; - default: - ASSERT(0); - pcibr_unlock(pcibr_soft, s); - return 0; - } - - start_addr = *pciaddr; - - /* - * Align start_addr. - */ - if (start_addr & align_mask) - start_addr = (start_addr + align_mask) & ~align_mask; - - if ((start_addr + req_size) > *pcilast) { - /* - * If too big a request, reject it. - */ - pcibr_unlock(pcibr_soft, s); - return 0; - } - *pciaddr = (start_addr + req_size); - - NEW(piosp); - piosp->free = 0; - piosp->space = space; - piosp->start = start_addr; - piosp->count = req_size; - piosp->next = pcibr_info->f_piospace; - pcibr_info->f_piospace = piosp; - - pcibr_unlock(pcibr_soft, s); - return start_addr; -} - -/*ARGSUSED */ -void -pcibr_piospace_free(devfs_handle_t pconn_vhdl, - pciio_space_t space, - iopaddr_t pciaddr, - size_t req_size) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - pciio_piospace_t piosp; - unsigned long s; - char name[1024]; - - /* - * Look through the bridge data structures for the pciio_piospace_t - * structure corresponding to 'pciaddr' - */ - s = pcibr_lock(pcibr_soft); - piosp = pcibr_info->f_piospace; - while (piosp) { - /* - * Piospace free can only be for the complete - * chunk and not parts of it.. - */ - if (piosp->start == pciaddr) { - if (piosp->count == req_size) - break; - /* - * Improper size passed for freeing.. - * Print a message and break; - */ - hwgraph_vertex_name_get(pconn_vhdl, name, 1024); - PRINT_WARNING("pcibr_piospace_free: error"); - PRINT_WARNING("Device %s freeing size (0x%lx) different than allocated (0x%lx)", - name, req_size, piosp->count); - PRINT_WARNING("Freeing 0x%lx instead", piosp->count); - break; - } - piosp = piosp->next; - } - - if (!piosp) { - PRINT_WARNING( - "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", - pciaddr, req_size); - pcibr_unlock(pcibr_soft, s); - return; - } - piosp->free = 1; - pcibr_unlock(pcibr_soft, s); - return; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * The Bridge ASIC provides three methods of doing - * DMA: via a "direct map" register available in - * 32-bit PCI space (which selects a contiguous 2G - * address space on some other widget), via - * "direct" addressing via 64-bit PCI space (all - * destination information comes from the PCI - * address, including transfer attributes), and via - * a "mapped" region that allows a bunch of - * different small mappings to be established with - * the PMU. - * - * For efficiency, we most prefer to use the 32-bit - * direct mapping facility, since it requires no - * resource allocations. The advantage of using the - * PMU over the 64-bit direct is that single-cycle - * PCI addressing can be used; the advantage of - * using 64-bit direct over PMU addressing is that - * we do not have to allocate entries in the PMU. - */ - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Direct Map attribute bits. - */ -LOCAL iopaddr_t -pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) -{ - iopaddr_t attributes = 0; - - /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef LATER - ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); -#endif - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ - attributes |= PCI64_ATTR_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= PCI64_ATTR_BAR; /* barrier bit on */ - attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - /* the swap bit is in the address attributes for xbridge */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - attributes |= PCI64_ATTR_SWAP; - if (flags & PCIIO_WORD_VALUES) - attributes &= ~PCI64_ATTR_SWAP; - } - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= PCI64_ATTR_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~PCI64_ATTR_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= PCI64_ATTR_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~PCI64_ATTR_PREC; - - if (flags & PCIBR_VCHAN1) - attributes |= PCI64_ATTR_VIRTUAL; - if (flags & PCIBR_VCHAN0) - attributes &= ~PCI64_ATTR_VIRTUAL; - - return (attributes); -} - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Address Translation Entry attribute bits. - */ -LOCAL bridge_ate_t -pcibr_flags_to_ate(unsigned flags) -{ - bridge_ate_t attributes; - - /* default if nothing specified: - * NOBARRIER - * NOPREFETCH - * NOPRECISE - * COHERENT - * Plus the valid bit - */ - attributes = ATE_CO | ATE_V; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~ATE_BAR; /* no barrier */ - attributes |= ATE_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= ATE_BAR; /* barrier bit on */ - attributes &= ~ATE_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~ATE_PREF; - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= ATE_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~ATE_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~ATE_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= ATE_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~ATE_PREC; - - return (attributes); -} - -/*ARGSUSED */ -pcibr_dmamap_t -pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - size_t req_size_max, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t slot; - xwidgetnum_t xio_port; - - xtalk_dmamap_t xtalk_dmamap; - pcibr_dmamap_t pcibr_dmamap; - int ate_count; - int ate_index; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - -#ifdef IRIX - NEWf(pcibr_dmamap, flags); -#else - /* - * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() - * can be called within an interrupt thread. - */ - pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); -#endif - - if (!pcibr_dmamap) - return 0; - - xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, - flags & DMAMAP_FLAGS); - if (!xtalk_dmamap) { -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); -#endif - DEL(pcibr_dmamap); - return 0; - } - xio_port = pcibr_soft->bs_mxid; - slot = pciio_info_slot_get(pciio_info); - - pcibr_dmamap->bd_dev = pconn_vhdl; - pcibr_dmamap->bd_slot = slot; - pcibr_dmamap->bd_soft = pcibr_soft; - pcibr_dmamap->bd_xtalk = xtalk_dmamap; - pcibr_dmamap->bd_max_size = req_size_max; - pcibr_dmamap->bd_xio_port = xio_port; - - if (flags & PCIIO_DMA_A64) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { - iopaddr_t pci_addr; - int have_rrbs; - int min_rrbs; - - /* Device is capable of A64 operations, - * and the attributes of the DMA are - * consistant with any previous DMA - * mappings using shared resources. - */ - - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_pci_addr = pci_addr; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - if (flags & PCIBR_VCHAN1) - slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct64\n"); -#endif - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct64\n"); -#endif - flags &= ~PCIIO_DMA_A64; - } - if (flags & PCIIO_FIXED) { - /* warning: mappings may fail later, - * if direct32 can't get to the address. - */ - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { - /* User desires DIRECT A32 operations, - * and the attributes of the DMA are - * consistant with any previous DMA - * mappings using shared resources. - * Mapping calls may fail if target - * is outside the direct32 range. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct32\n"); -#endif - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; - pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct32\n"); -#endif - /* If the user demands FIXED and we can't - * give it to him, fail. - */ - xtalk_dmamap_free(xtalk_dmamap); - DEL(pcibr_dmamap); - return 0; - } - /* - * Allocate Address Translation Entries from the mapping RAM. - * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, - * the maximum number of ATEs is based on the worst-case - * scenario, where the requested target is in the - * last byte of an ATE; thus, mapping IOPGSIZE+2 - * does end up requiring three ATEs. - */ - if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { - ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ - +req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } else { /* assume requested target is page aligned */ - ate_count = IOPG(req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } - - ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); - - if (ate_index != -1) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { - bridge_ate_t ate_proto; - int have_rrbs; - int min_rrbs; - -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using PMU\n"); -#endif - - ate_proto = pcibr_flags_to_ate(flags); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_pci_addr = - PCI32_MAPPED_BASE + IOPGSIZE * ate_index; - /* - * for xbridge the byte-swap bit == bit 29 of PCI address - */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - /* - * If swap was set in bss_device in pcibr_endian_set() - * we need to change the address bit. - */ - if (pcibr_soft->bs_slot[slot].bss_device & - BRIDGE_DEV_SWAP_PMU) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - if (flags & PCIIO_WORD_VALUES) - ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); - } - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); - pcibr_dmamap->bd_ate_index = ate_index; - pcibr_dmamap->bd_ate_count = ate_count; - pcibr_dmamap->bd_ate_proto = ate_proto; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (ate_proto & ATE_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } - if (ate_index >= pcibr_soft->bs_int_ate_size && - !pcibr_soft->bs_xbridge) { - bridge_t *bridge = pcibr_soft->bs_base; - volatile unsigned *cmd_regp; - unsigned cmd_reg; - unsigned long s; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; - - s = pcibr_lock(pcibr_soft); - cmd_regp = &(bridge-> - b_type0_cfg_dev[slot]. - l[PCI_CFG_COMMAND / 4]); - cmd_reg = *cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; - pcibr_unlock(pcibr_soft, s); - } - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use PMU\n"); -#endif - pcibr_ate_free(pcibr_soft, ate_index, ate_count); - } - /* total failure: sorry, you just can't - * get from here to there that way. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: complete failure.\n"); -#endif - xtalk_dmamap_free(xtalk_dmamap); - DEL(pcibr_dmamap); - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - pciio_slot_t slot = pcibr_dmamap->bd_slot; - - unsigned flags = pcibr_dmamap->bd_flags; - - /* Make sure that bss_ext_ates_active - * is properly kept up to date. - */ - - if (PCIBR_DMAMAP_BUSY & flags) - if (PCIBR_DMAMAP_SSRAM & flags) - atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); - - xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); - - if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); - } - if (pcibr_dmamap->bd_ate_count) { - pcibr_ate_free(pcibr_dmamap->bd_soft, - pcibr_dmamap->bd_ate_index, - pcibr_dmamap->bd_ate_count); - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); - } -#ifdef IRIX - DEL(pcibr_dmamap); -#endif -} - -/* - * Setup an Address Translation Entry as specified. Use either the Bridge - * internal maps or the external map RAM, as appropriate. - */ -LOCAL bridge_ate_p -pcibr_ate_addr(pcibr_soft_t pcibr_soft, - int ate_index) -{ - bridge_t *bridge = pcibr_soft->bs_base; - - return (ate_index < pcibr_soft->bs_int_ate_size) - ? &(bridge->b_int_ate_ram[ate_index].wr) - : &(bridge->b_ext_ate_ram[ate_index]); -} - -/* - * pcibr_addr_xio_to_pci: given a PIO range, hand - * back the corresponding base PCI MEM address; - * this is used to short-circuit DMA requests that - * loop back onto this PCI bus. - */ -LOCAL iopaddr_t -pcibr_addr_xio_to_pci(pcibr_soft_t soft, - iopaddr_t xio_addr, - size_t req_size) -{ - iopaddr_t xio_lim = xio_addr + req_size - 1; - iopaddr_t pci_addr; - pciio_slot_t slot; - - if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && - (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; - return pci_addr; - } - if ((xio_addr >= BRIDGE_PCI_MEM64_BASE) && - (xio_lim <= BRIDGE_PCI_MEM64_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; - return pci_addr; - } - for (slot = 0; slot < 8; ++slot) - if ((xio_addr >= BRIDGE_DEVIO(slot)) && - (xio_lim < BRIDGE_DEVIO(slot + 1))) { - bridgereg_t dev; - - dev = soft->bs_slot[slot].bss_device; - pci_addr = dev & BRIDGE_DEV_OFF_MASK; - pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; - pci_addr += xio_addr - BRIDGE_DEVIO(slot); - return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; - } - return 0; -} - -/* We are starting to get more complexity - * surrounding writing ATEs, so pull - * the writing code into this new function. - */ - -#if PCIBR_FREEZE_TIME -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) -#else -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) -#endif - -LOCAL unsigned -ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef LATER - int dma_slot = pcibr_dmamap->bd_slot; -#endif - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - int slot; - - unsigned long s; - unsigned cmd_reg; - volatile unsigned *cmd_lwa; - unsigned cmd_lwd; - - if (!ext_ates) - return 0; - - /* Bridge Hardware Bug WAR #484930: - * Bridge can't handle updating External ATEs - * while DMA is occuring that uses External ATEs, - * even if the particular ATEs involved are disjoint. - */ - - /* need to prevent anyone else from - * unfreezing the grant while we - * are working; also need to prevent - * this thread from being interrupted - * to keep PCI grant freeze time - * at an absolute minimum. - */ - s = pcibr_lock(pcibr_soft); - -#ifdef LATER - /* just in case pcibr_dmamap_done was not called */ - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); - } -#endif /* LATER */ -#if PCIBR_FREEZE_TIME - *freeze_time_ptr = get_timestamp(); -#endif - - cmd_lwa = 0; - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - cmd_reg = pcibr_soft-> - bs_slot[slot]. - bss_cmd_shadow; - if (cmd_reg & PCI_CMD_BUS_MASTER) { - cmd_lwa = pcibr_soft-> - bs_slot[slot]. - bss_cmd_pointer; - cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; - cmd_lwa[0] = cmd_lwd; - } - cmd_regs[slot] = cmd_reg; - } else - cmd_regs[slot] = 0; - - if (cmd_lwa) { - bridge_t *bridge = pcibr_soft->bs_base; - - /* Read the last master bit that has been cleared. This PIO read - * on the PCI bus is to ensure the completion of any DMAs that - * are due to bus requests issued by PCI devices before the - * clearing of master bits. - */ - cmd_lwa[0]; - - /* Flush all the write buffers in the bridge */ - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - /* Flush the write buffer associated with this - * PCI device which might be using dma map RAM. - */ - bridge->b_wr_req_buf[slot].reg; - } - } - return s; -} - -#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) - -LOCAL void -ate_write(bridge_ate_p ate_ptr, - int ate_count, - bridge_ate_t ate) -{ - while (ate_count-- > 0) { - *ate_ptr++ = ate; - ate += IOPGSIZE; - } -} - - -#if PCIBR_FREEZE_TIME -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) -#else -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) -#endif - -LOCAL void -ate_thaw(pcibr_dmamap_t pcibr_dmamap, - int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - int dma_slot = pcibr_dmamap->bd_slot; - int slot; - bridge_t *bridge = pcibr_soft->bs_base; - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - - unsigned cmd_reg; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; - static unsigned max_freeze_time = 0; - static unsigned max_ate_total; -#endif - - if (!ext_ates) - return; - - /* restore cmd regs */ - for (slot = 0; slot < 8; ++slot) - if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) - bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; - atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - -#if PCIBR_FREEZE_TIME - freeze_time = get_timestamp() - freeze_time_start; - - if ((max_freeze_time < freeze_time) || - (max_ate_total < ate_total)) { - if (max_freeze_time < freeze_time) - max_freeze_time = freeze_time; - if (max_ate_total < ate_total) - max_ate_total = ate_total; - pcibr_unlock(pcibr_soft, s); - printk("%s: pci freeze time %d usec for %d ATEs\n" - "\tfirst ate: %R\n", - pcibr_soft->bs_name, - freeze_time * 1000 / 1250, - ate_total, - ate, ate_bits); - } else -#endif - pcibr_unlock(pcibr_soft, s); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, - paddr_t paddr, - size_t req_size) -{ - pcibr_soft_t pcibr_soft; - iopaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - unsigned flags; - - ASSERT(pcibr_dmamap != NULL); - ASSERT(req_size > 0); - ASSERT(req_size <= pcibr_dmamap->bd_max_size); - - pcibr_soft = pcibr_dmamap->bd_soft; - - flags = pcibr_dmamap->bd_flags; - - xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - /* If this DMA is to an address that - * refers back to this Bridge chip, - * reduce it back to the correct - * PCI MEM address. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - } else if (flags & PCIIO_DMA_A64) { - /* A64 DMA: - * always use 64-bit direct mapping, - * which always works. - * Device(x) was set up during - * dmamap allocation. - */ - - /* attributes are already bundled up into bd_pci_addr. - */ - pci_addr = pcibr_dmamap->bd_pci_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) - | xio_addr; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - pci_addr &= ~PCI64_ATTR_PREF; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct64):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else if (flags & PCIIO_FIXED) { - /* A32 direct DMA: - * always use 32-bit direct mapping, - * which may fail. - * Device(x) was set up during - * dmamap allocation. - */ - - if (xio_port != pcibr_soft->bs_dir_xport) - pci_addr = 0; /* wrong DIDN */ - else if (xio_addr < pcibr_dmamap->bd_xio_addr) - pci_addr = 0; /* out of range */ - else if ((xio_addr + req_size) > - (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) - pci_addr = 0; /* out of range */ - else - pci_addr = pcibr_dmamap->bd_pci_addr + - xio_addr - pcibr_dmamap->bd_xio_addr; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct32):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else { - bridge_t *bridge = pcibr_soft->bs_base; - iopaddr_t offset = IOPGOFF(xio_addr); - bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; - int ate_count = IOPG(offset + req_size - 1) + 1; - - int ate_index = pcibr_dmamap->bd_ate_index; - unsigned cmd_regs[8]; - unsigned s; - -#if PCIBR_FREEZE_TIME - int ate_total = ate_count; - unsigned freeze_time; -#endif - -#if PCIBR_ATE_DEBUG - bridge_ate_t ate_cmp; - bridge_ate_p ate_cptr; - unsigned ate_lo, ate_hi; - int ate_bad = 0; - int ate_rbc = 0; -#endif - bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; - bridge_ate_t ate; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - ate_proto &= ~ATE_PREF; - - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - - pci_addr = pcibr_dmamap->bd_pci_addr + offset; - - /* Fill in our mapping registers - * with the appropriate xtalk data, - * and hand back the PCI address. - */ - - ASSERT(ate_count > 0); - if (ate_count <= pcibr_dmamap->bd_ate_count) { - ATE_FREEZE(); - ATE_WRITE(); - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } else { - /* The number of ATE's required is greater than the number - * allocated for this map. One way this can happen is if - * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP - * flag, and then when that map is used (right now), the - * target address tells us we really did need to roundup. - * The other possibility is that the map is just plain too - * small to handle the requested target area. - */ -#if PCIBR_ATE_DEBUG - PRINT_WARNING( "pcibr_dmamap_addr :\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tate_count 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - paddr, paddr + req_size - 1, - ate_count, pcibr_dmamap->bd_ate_count); -#endif - pci_addr = 0; - } - - } - return pci_addr; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, - alenlist_t palenlist, - unsigned flags) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge=NULL; - - unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - int inplace = flags & PCIIO_INPLACE; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist; - size_t length; - iopaddr_t offset; - unsigned direct64; - int ate_index = 0; - int ate_count = 0; - int ate_total = 0; - bridge_ate_p ate_ptr = (bridge_ate_p)0; - bridge_ate_t ate_proto = (bridge_ate_t)0; - bridge_ate_t ate_prev; - bridge_ate_t ate; - alenaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - alenaddr_t new_addr; - - unsigned cmd_regs[8]; - unsigned s = 0; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; -#endif - int ate_freeze_done = 0; /* To pair ATE_THAW - * with an ATE_FREEZE - */ - - pcibr_soft = pcibr_dmamap->bd_soft; - - xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; - if (!direct64) { - bridge = pcibr_soft->bs_base; - ate_ptr = pcibr_dmamap->bd_ate_ptr; - ate_index = pcibr_dmamap->bd_ate_index; - ate_proto = pcibr_dmamap->bd_ate_proto; - ATE_FREEZE(); - ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ - } - pci_addr = pcibr_dmamap->bd_pci_addr; - - ate_prev = 0; /* matches no valid ATEs */ - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &length, al_flags)) { - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - if (xio_port == pcibr_soft->bs_xid) { - new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) - goto fail; - } else if (direct64) { - new_addr = pci_addr | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - new_addr &= ~PCI64_ATTR_PREF; - - } else { - /* calculate the ate value for - * the first address. If it - * matches the previous - * ATE written (ie. we had - * multiple blocks in the - * same IOPG), then back up - * and reuse that ATE. - * - * We are NOT going to - * aggressively try to - * reuse any other ATEs. - */ - offset = IOPGOFF(xio_addr); - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - if (ate == ate_prev) { -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_list: ATE share\n"); -#endif - ate_ptr--; - ate_index--; - pci_addr -= IOPGSIZE; - } - new_addr = pci_addr + offset; - - /* Fill in the hardware ATEs - * that contain this block. - */ - ate_count = IOPG(offset + length - 1) + 1; - ate_total += ate_count; - - /* Ensure that this map contains enough ATE's */ - if (ate_total > pcibr_dmamap->bd_ate_count) { -#if PCIBR_ATE_DEBUG - PRINT_WARNING( "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count); -#endif - goto fail; - } - - ATE_WRITE(); - - ate_index += ate_count; - ate_ptr += ate_count; - - ate_count <<= IOPFNSHIFT; - ate += ate_count; - pci_addr += ate_count; - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) - goto fail; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - - /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the - * changes that ATE_FREEZE has done to implement the external SSRAM - * bug workaround. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - return pciio_alenlist; - - fail: - /* There are various points of failure after doing an ATE_FREEZE - * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. - * The decision to do an ATE_THAW needs to be based on whether a - * an ATE_FREEZE was done before. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; - } - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) -{ - /* - * We could go through and invalidate ATEs here; - * for performance reasons, we don't. - * We also don't enforce the strict alternation - * between _addr/_list and _done, but Hub does. - */ - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); - } - - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); -} - - -/* - * For each bridge, the DIR_OFF value in the Direct Mapping Register - * determines the PCI to Crosstalk memory mapping to be used for all - * 32-bit Direct Mapping memory accesses. This mapping can be to any - * node in the system. This function will return that compact node id. - */ - -/*ARGSUSED */ -cnodeid_t -pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) -{ - - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - paddr_t paddr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - - xwidgetnum_t xio_port; - iopaddr_t xio_addr; - iopaddr_t pci_addr; - - int have_rrbs; - int min_rrbs; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, - flags & DMAMAP_FLAGS); - - if (!xio_addr) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - return pci_addr; - } - /* If the caller can use A64, try to - * satisfy the request with the 64-bit - * direct map. This can fail if the - * configuration bits in Device(x) - * conflict with our flags. - */ - - if (flags & PCIIO_DMA_A64) { - pci_addr = slotp->bss_d64_base; - if (!(flags & PCIBR_VCHAN1)) - flags |= PCIBR_VCHAN0; - if ((pci_addr != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - -#if DEBUG && PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_addr; - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - if (flags & PCIBR_VCHAN1) - pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ - flags = flags - & ~PCIIO_DMA_A64 - & ~PCIBR_VCHAN0 - ; - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-64\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - /* Try to satisfy the request with the 32-bit direct - * map. This can fail if the configuration bits in - * Device(x) conflict with our flags, or if the - * target address is outside where DIR_OFF points. - */ - { - size_t map_size = 1ULL << 31; - iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = req_size + offset; - - if ((req_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\txio region outside direct32 target\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } else { - pci_addr = slotp->bss_d32_base; - if ((pci_addr != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - - pci_addr |= offset; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { - - pci_addr = PCI32_DIRECT_BASE; - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_addr; - pci_addr |= offset; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (slotp->bss_device & BRIDGE_DEV_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-32\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - } - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tno acceptable PCI address found or constructable\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - - return 0; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - alenlist_t palenlist, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - xwidgetnum_t xio_port; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist = 0; - - int inplace; - unsigned direct64; - unsigned al_flags; - - iopaddr_t xio_base; - alenaddr_t xio_addr; - size_t xio_size; - - size_t map_size; - iopaddr_t pci_base; - alenaddr_t pci_addr; - - unsigned relbits = 0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - inplace = flags & PCIIO_INPLACE; - direct64 = flags & PCIIO_DMA_A64; - al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - - if (direct64) { - map_size = 1ull << 48; - xio_base = 0; - pci_base = slotp->bss_d64_base; - if ((pci_base != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D64_BITS; - pci_base = - pcibr_flags_to_d64(flags, pcibr_soft); - } - } else { - xio_base = pcibr_soft->bs_dir_xbase; - map_size = 1ull << 31; - pci_base = slotp->bss_d32_base; - if ((pci_base != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D32_BITS; - pci_base = PCI32_DIRECT_BASE; - } - } - - xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &xio_size, al_flags)) { - - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if ( (pci_addr == (alenaddr_t)NULL) ) - goto fail; - } else if (direct64) { - ASSERT(xio_port != 0); - pci_addr = pci_base | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - } else { - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = xio_size + offset; - - if ((xio_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) - goto fail; - - pci_addr = pci_base + (xio_addr - xio_base); - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) - goto fail; - } - } - - if (relbits) { - if (direct64) { - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_base; - } else { - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_base; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - return pciio_alenlist; - - fail: - if (relbits) - pcibr_release_device(pcibr_soft, pciio_slot, relbits); - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -void -pcibr_dmamap_drain(pcibr_dmamap_t map) -{ - xtalk_dmamap_drain(map->bd_xtalk); -} - -void -pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, - paddr_t paddr, - size_t bytes) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); -} - -void -pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, - alenlist_t list) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmalist_drain(xconn_vhdl, list); -} - -/* - * Get the starting PCIbus address out of the given DMA map. - * This function is supposed to be used by a close friend of PCI bridge - * since it relies on the fact that the starting address of the map is fixed at - * the allocation time in the current implementation of PCI bridge. - */ -iopaddr_t -pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) -{ - return (pcibr_dmamap->bd_pci_addr); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - */ - -static unsigned -pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines) -{ - pciio_slot_t slot = pciio_info_slot_get(info); - unsigned bbits = 0; - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - */ - - if (slot < 8) { - if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) - bbits |= 1 << slot; - if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) - bbits |= 1 << (slot ^ 4); - } - return bbits; -} - - -/* - * Get the next wrapper pointer queued in the interrupt circular buffer. - */ -#ifdef KERNEL_THREADS -pcibr_intr_wrap_t -pcibr_wrap_get(pcibr_intr_cbuf_t cbuf) -{ - pcibr_intr_wrap_t wrap; - - if (cbuf->ib_in == cbuf->ib_out) - PRINT_PANIC("pcibr intr circular buffer empty, cbuf=0x%x, ib_in=ib_out=%d\n", - cbuf, cbuf->ib_out); - - wrap = cbuf->ib_cbuf[cbuf->ib_out++]; - cbuf->ib_out = cbuf->ib_out % IBUFSIZE; - return(wrap); -} - -/* - * Queue a wrapper pointer in the interrupt circular buffer. - */ -void -pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) -{ - int in; - unsigned long s; - - /* - * Multiple CPUs could be executing this code simultaneously - * if a handler has registered multiple interrupt lines and - * the interrupts are directed to different CPUs. - */ - s = mutex_spinlock(&cbuf->ib_lock); - in = (cbuf->ib_in + 1) % IBUFSIZE; - if (in == cbuf->ib_out) - PRINT_PANIC("pcibr intr circular buffer full, cbuf=0x%x, ib_in=%d\n", - cbuf, cbuf->ib_in); - - cbuf->ib_cbuf[cbuf->ib_in] = wrap; - cbuf->ib_in = in; - mutex_spinunlock(&cbuf->ib_lock, s); - return; -} -#endif /* KERNEL_THREADS */ - -/* - * There are end cases where a deadlock can occur if interrupt - * processing completes and the Bridge b_int_status bit is still set. - * - * One scenerio is if a second PCI interrupt occurs within 60ns of - * the previous interrupt being cleared. In this case the Bridge - * does not detect the transition, the Bridge b_int_status bit - * remains set, and because no transition was detected no interrupt - * packet is sent to the Hub/Heart. - * - * A second scenerio is possible when a b_int_status bit is being - * shared by multiple devices: - * Device #1 generates interrupt - * Bridge b_int_status bit set - * Device #2 generates interrupt - * interrupt processing begins - * ISR for device #1 runs and - * clears interrupt - * Device #1 generates interrupt - * ISR for device #2 runs and - * clears interrupt - * (b_int_status bit still set) - * interrupt processing completes - * - * Interrupt processing is now complete, but an interrupt is still - * outstanding for Device #1. But because there was no transition of - * the b_int_status bit, no interrupt packet will be generated and - * a deadlock will occur. - * - * To avoid these deadlock situations, this function is used - * to check if a specific Bridge b_int_status bit is set, and if so, - * cause the setting of the corresponding interrupt bit. - * - * On a XBridge (IP35), we do this by writing the appropriate Bridge Force - * Interrupt register. - */ -void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) -{ - unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); - - bit = wrap->iw_intr; - - if (pcibr_soft->bs_xbridge) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - REMOTE_CPU_SEND_INTR(cpu, intr_bit); - } -} - -/* Wrapper for pcibr interrupt threads. */ -#ifdef KERNEL_THREADS -static void -pcibr_intrd(pcibr_intr_t intr) -{ - pcibr_intr_wrap_t wrap; - - /* Called on each restart */ - ASSERT(cpuid() == intr->bi_mustruncpu); - -#ifdef ITHREAD_LATENCY - xthread_update_latstats(intr->bi_tinfo.thd_latstats); -#endif /* ITHREAD_LATENCY */ - - ASSERT(intr->bi_func != NULL); - intr->bi_func(intr->bi_arg); /* Invoke the interrupt handler */ - - /* - * The pcibr_intrd thread needs access to the wrapper struct - * specific to the current interrupt it is processing. Because - * multiple calls/wakeups to the thread could be queued, each - * potentially from a different interrupt line (PCIIO_INTR_LINE_A, - * etc), multiple wrapper struct pointers need to be queued. This - * is done via a circular buffer of wrapper struct pointers. - */ - wrap = pcibr_wrap_get(&intr->bi_ibuf); - - /* - * The interrupt handler has completed. Now decrement the running - * count tracking the number of handlers still running for this line. - * If this was the last handler to complete (i.e., iw_hdlrcnt == 0), - * avoid a potential deadlock condition and ensure that another - * interrupt will occur if the Bridge b_int_status bit is still - * set. - */ - atomicAddInt(&(wrap->iw_hdlrcnt), -1); - if (wrap->iw_hdlrcnt == 0) - pcibr_force_interrupt(wrap); - - ipsema(&intr->bi_tinfo.thd_isync); /* Sleep 'till next interrupt */ - /* NOTREACHED */ -} - -static void -pcibr_intrd_start(pcibr_intr_t intr) -{ - ASSERT(intr->bi_mustruncpu >= 0); - setmustrun(intr->bi_mustruncpu); - - xthread_set_func(KT_TO_XT(curthreadp), (xt_func_t *)pcibr_intrd, (void *)intr); - atomicSetInt(&intr->bi_tinfo.thd_flags, THD_INIT); - ipsema(&intr->bi_tinfo.thd_isync); /* Comes out in pcibr_intrd */ - /* NOTREACHED */ -} - - -static void -pcibr_thread_setup(pcibr_intr_t intr, int bridge_levels, ilvl_t intr_swlevel) -{ - char thread_name[32]; - - sprintf(thread_name, "pcibr_intrd[0x%x]", bridge_levels); - thread_name[IT_NAMELEN-1] = '\0'; - - /* XXX need to adjust priority whenever an interrupt is connected */ - intr->bi_tinfo.thd_pri = intr_swlevel; - atomicSetInt(&intr->bi_tinfo.thd_flags, THD_ISTHREAD | THD_REG); - xthread_setup(thread_name, intr_swlevel, &intr->bi_tinfo, - (xt_func_t *)pcibr_intrd_start, - (void *)intr); -} -#endif /* KERNEL_THREADS */ - - - -/*ARGSUSED */ -pcibr_intr_t -pcibr_intr_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_intr_line_t lines, - devfs_handle_t owner_dev) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pcibr_info->f_slot; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; - int is_threaded = 0; -#ifdef KERNEL_THREADS - cpuid_t mustruncpu = CPU_NONE; - cpuid_t old_intrcpu = CPU_NONE; -#endif - int thread_swlevel; - - xtalk_intr_t *xtalk_intr_p; - pcibr_intr_t *pcibr_intr_p; - pcibr_intr_list_t *intr_list_p; - - unsigned pcibr_int_bits; - unsigned pcibr_int_bit; - xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; - hub_intr_t hub_intr; - pcibr_intr_t pcibr_intr; - pcibr_intr_list_t intr_entry; - pcibr_intr_list_t intr_list; - bridgereg_t int_dev; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_alloc\n" - "%v:%s%s%s%s%s\n", - owner_dev, pconn_vhdl, - !(lines & 15) ? " No INTs?" : "", - lines & 1 ? " INTA" : "", - lines & 2 ? " INTB" : "", - lines & 4 ? " INTC" : "", - lines & 8 ? " INTD" : ""); -#endif - - NEW(pcibr_intr); - if (!pcibr_intr) - return NULL; - - if (dev_desc) { - cpuid_t intr_target_from_desc(device_desc_t, int); - -#ifdef KERNEL_THREADS - is_threaded = !(device_desc_flags_get(dev_desc) & D_INTR_NOTHREAD); - if (is_threaded) { - /* - * If the device descriptor contains interrupt target info, - * save the CPU requested. This is the CPU the pcibr_intrd - * thread will be set to run on. - * - * We need to get the interrupt target info at this time, because - * the original intr_target value can be overwritten, as part of - * the xtalk_intr_alloc_nothd() call, with the actual interrupt CPU. - * This can be different than the requested CPU if the lower layers - * could not direct the hardware interrupt to the requested CPU. - * Regardless of which CPU processes the hardware interrupt, the - * ISR thread will still be setup to run on the CPU originally - * requested. - */ - mustruncpu = intr_target_from_desc(dev_desc, SUBNODE_ANY); - thread_swlevel = device_desc_intr_swlevel_get(dev_desc); - } -#endif /* KERNEL_THREADS */ - } else { - extern int default_intr_pri; - - is_threaded = 1; /* PCI interrupts are threaded, by default */ - thread_swlevel = default_intr_pri; - } - - pcibr_intr->bi_dev = pconn_vhdl; - pcibr_intr->bi_lines = lines; - pcibr_intr->bi_soft = pcibr_soft; - pcibr_intr->bi_ibits = 0; /* bits will be added below */ - pcibr_intr->bi_func = 0; /* unset until connect */ - pcibr_intr->bi_arg = 0; /* unset until connect */ - pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; - pcibr_intr->bi_mustruncpu = CPU_NONE; -#ifdef KERNEL_THREADS - pcibr_intr->bi_ibuf.ib_in = 0; - pcibr_intr->bi_ibuf.ib_out = 0; -#endif - mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); - - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); - - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ -#if DEBUG && INTR_DEBUG - printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); -#endif - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - xtalk_intr = *xtalk_intr_p; - - if (xtalk_intr == NULL) { - /* - * This xtalk_intr_alloc is constrained for two reasons: - * 1) Normal interrupts and error interrupts need to be delivered - * through a single xtalk target widget so that there aren't any - * ordering problems with DMA, completion interrupts, and error - * interrupts. (Use of xconn_vhdl forces this.) - * - * 2) On IP35, addressing constraints on IP35 and Bridge force - * us to use a single PI number for all interrupts from a - * single Bridge. (IP35-specific code forces this, and we - * verify in pcibr_setwidint.) - */ - - /* - * All code dealing with threaded PCI interrupt handlers - * is located at the pcibr level. Because of this, - * we always want the lower layers (hub/heart_intr_alloc, - * intr_level_connect) to treat us as non-threaded so we - * don't set up a duplicate threaded environment. We make - * this happen by calling a special xtalk interface. - */ - xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, - owner_dev); -#if DEBUG && INTR_DEBUG - printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); -#endif - - /* both an assert and a runtime check on this: - * we need to check in non-DEBUG kernels, and - * the ASSERT gets us more information when - * we use DEBUG kernels. - */ - ASSERT(xtalk_intr != NULL); - if (xtalk_intr == NULL) { - /* it is quite possible that our - * xtalk_intr_alloc failed because - * someone else got there first, - * and we can find their results - * in xtalk_intr_p. - */ - if (!*xtalk_intr_p) { -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_ALERT( - "pcibr_intr_alloc %v: unable to get xtalk interrupt resources", - xconn_vhdl); -#endif - /* yes, we leak resources here. */ - return 0; - } - } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { - /* - * now tell the bridge which slot is - * using this interrupt line. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); - bridge->b_int_device = int_dev; /* XXXMP */ - -#if DEBUG && INTR_DEBUG - printk("%v: bridge intr bit %d clears my wrb\n", - pconn_vhdl, pcibr_int_bit); -#endif - } else { - /* someone else got one allocated first; - * free the one we just created, and - * retrieve the one they allocated. - */ - xtalk_intr_free(xtalk_intr); - xtalk_intr = *xtalk_intr_p; -#if PARANOID - /* once xtalk_intr is set, we never clear it, - * so if the CAS fails above, this condition - * can "never happen" ... - */ - if (!xtalk_intr) { - PRINT_ALERT( - "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", - xconn_vhdl); - /* yes, we leak resources here. */ - return 0; - } -#endif - } - } - -#ifdef KERNEL_THREADS - if (is_threaded) { - cpuid_t intrcpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - - /* - * It is possible that 2 (or more) interrupts originating on a - * single Bridge and used by a single device were assigned to - * different CPUs. If this occurs issue a warning message for - * this sub-optimal configuration. There are two ways this - * could happen: - * - * - There were insufficient xtalk interrupt resources to - * allow all interrupts to be assigned to the same CPU. - * This is an unlikely case, but could happen if someone - * tries to target a lot of interrupts to a single CPU. - * - * - If there is no device descriptor associated with this - * device, the xtalk/hub/heart layers will not know to - * assign the same CPU to any additional interrupts this - * driver has specified, and will perform the normal load - * leveling of interrupts across CPUs. - * (The lower layers store the CPU assigned to the first - * interrupt in the device desc, if present, and then when - * called again for additional interrupts for the same device, - * use this information to assign the same CPU to these - * interrupts.) - */ - if ((old_intrcpu != CPU_NONE) && (old_intrcpu != intrcpu)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_WARNING("Conflict on where to schedule interrupts for %v\n", pconn_vhdl); -#else - PRINT_WARNING("Conflict on where to schedule interrupts for 0x%x\n", pconn_vhdl); -#endif - PRINT_WARNING("(on cpu %d or on cpu %d), cpu %d used\n", old_intrcpu, intrcpu, intrcpu); - } - if (old_intrcpu == CPU_NONE) - old_intrcpu = intrcpu; - /* - * For threaded drivers, set the interrupt thread to run wherever - * the interrupt is targeted, or where requested in the dev_desc. - */ - if (mustruncpu != CPU_NONE) { - pcibr_intr->bi_mustruncpu = mustruncpu; - if (mustruncpu != intrcpu) { - PRINT_WARNING("Request to target PCI interrupts to CPU %d could not\n" - " be satisfied, CPU %d used. However, interrupt thread\n" - " pcibr_intrd will run on CPU %d as requested.\n" - " %v (0x%x)\n", - mustruncpu, intrcpu, mustruncpu, owner_dev, - owner_dev); - } - } else { - pcibr_intr->bi_mustruncpu = intrcpu; - } - ASSERT(pcibr_intr->bi_mustruncpu >= 0); - - } -#endif /* KERNEL_THREADS */ - - pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; - - NEW(intr_entry); - intr_entry->il_next = NULL; - intr_entry->il_intr = pcibr_intr; - intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); - intr_list_p = - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; -#if DEBUG && INTR_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("0x%x: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#else - printk("%v: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#endif -#endif - - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the first interrupt on this bridge bit. - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list = *intr_list_p; - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* first entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the new second interrupt on this bit. - */ - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - while (1) { - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* an entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* entry appended to share list - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - /* step to next record in chain - */ - intr_list = *intr_list_p; - } - } - } - -#ifdef KERNEL_THREADS - if (is_threaded) { - /* Set pcibr_intr->bi_tinfo */ - pcibr_thread_setup(pcibr_intr, pcibr_int_bits, thread_swlevel); - ASSERT(!(pcibr_intr->bi_flags & PCIIO_INTR_CONNECTED)); - } -#endif /* KERNEL_THREADS */ - -#if DEBUG && INTR_DEBUG - printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); -#endif - hub_intr = (hub_intr_t)xtalk_intr; - pcibr_intr->bi_irq = hub_intr->i_bit; - pcibr_intr->bi_cpu = hub_intr->i_cpuid; - return pcibr_intr; -} - -/*ARGSUSED */ -void -pcibr_intr_free(pcibr_intr_t pcibr_intr) -{ - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bit; - pcibr_intr_list_t intr_list; - int intr_shared; - xtalk_intr_t *xtalk_intrp; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; - intr_list != NULL; - intr_list = intr_list->il_next) - if (compare_and_swap_ptr((void **) &intr_list->il_intr, - pcibr_intr, - NULL)) { -#if DEBUG && INTR_DEBUG - printk("%s: cleared a handler from bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - } - /* If this interrupt line is not being shared between multiple - * devices release the xtalk interrupt resources. - */ - intr_shared = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; - xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - if ((!intr_shared) && (*xtalk_intrp)) { - - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_dev; - - xtalk_intr_free(*xtalk_intrp); - *xtalk_intrp = 0; - - /* Clear the PCI device interrupt to bridge interrupt pin - * mapping. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - bridge->b_int_device = int_dev; - - } - } - } - DEL(pcibr_intr); -} - -LOCAL void -pcibr_setpciint(xtalk_intr_t xtalk_intr) -{ - iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); - bridgereg_t *int_addr = (bridgereg_t *) - xtalk_intr_sfarg_get(xtalk_intr); - - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); -} - -/*ARGSUSED */ -int -pcibr_intr_connect(pcibr_intr_t pcibr_intr, - intr_func_t intr_func, - intr_arg_t intr_arg, - void *thread) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - bridgereg_t b_int_enable; - unsigned long s; - - if (pcibr_intr == NULL) - return -1; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_connect 0x%X(0x%X)\n", - pcibr_intr->bi_dev, intr_func, intr_arg); -#endif - - pcibr_intr->bi_func = intr_func; - pcibr_intr->bi_arg = intr_arg; - *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - pcibr_intr_wrap_t intr_wrap; - xtalk_intr_t xtalk_intr; - - xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - /* - * If this interrupt line is being shared and the connect has - * already been done, no need to do it again. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) - continue; - - - /* - * Use the pcibr wrapper function to handle all Bridge interrupts - * regardless of whether the interrupt line is shared or not. - */ - xtalk_intr_connect(xtalk_intr, - pcibr_intr_func, - (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), - 0); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; - -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d wrapper connected\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif - } - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable |= pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - return 0; -} - -/*ARGSUSED */ -void -pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - pcibr_intr_wrap_t intr_wrap; - bridgereg_t b_int_enable; - unsigned long s; - - /* Stop calling the function. Now. - */ - *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; - pcibr_intr->bi_func = 0; - pcibr_intr->bi_arg = 0; - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and disconnect the interrupt. - */ - - /* don't disable interrupts for lines that - * are shared between devices. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) - pcibr_int_bits &= ~(1 << pcibr_int_bit); - if (!pcibr_int_bits) - return; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - /* if the interrupt line is now shared, - * do not disconnect it. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; - -#if DEBUG && INTR_DEBUG - printk("%s: xtalk disconnect done for Bridge bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - - /* if we are sharing the interrupt line, - * connect us up; this closes the hole - * where the another pcibr_intr_alloc() - * was in progress as we disconnected. - */ - intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - - xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - pcibr_intr_func, - (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr), - 0); - } -} - -/*ARGSUSED */ -devfs_handle_t -pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) - return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - return 0; -} - -/* ===================================================================== - * INTERRUPT HANDLING - */ -LOCAL void -pcibr_clearwidint(bridge_t *bridge) -{ - bridge->b_wid_int_upper = 0; - bridge->b_wid_int_lower = 0; -} - - -LOCAL void -pcibr_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; - widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; - - bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); - - NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - - OLD_b_wid_int_upper = bridge->b_wid_int_upper; - OLD_b_wid_int_lower = bridge->b_wid_int_lower; - -#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - /* Verify that all interrupts from this Bridge are using a single PI */ - if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { - /* - * Once set, these registers shouldn't change; they should - * be set multiple times with the same values. - * - * If we're attempting to change these registers, it means - * that our heuristics for allocating interrupts in a way - * appropriate for IP35 have failed, and the admin needs to - * explicitly direct some interrupts (or we need to make the - * heuristics more clever). - * - * In practice, we hope this doesn't happen very often, if - * at all. - */ - if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || - (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { - PRINT_WARNING("Interrupt allocation is too complex.\n"); - PRINT_WARNING("Use explicit administrative interrupt targetting.\n"); - PRINT_WARNING("bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); - PRINT_WARNING("NEW=0x%x/0x%x OLD=0x%x/0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, - OLD_b_wid_int_upper, OLD_b_wid_int_lower); - PRINT_PANIC("PCI Bridge interrupt targetting error\n"); - } - } -#endif /* CONFIG_SGI_IP35 */ - - bridge->b_wid_int_upper = NEW_b_wid_int_upper; - bridge->b_wid_int_lower = NEW_b_wid_int_lower; - bridge->b_int_host_err = vect; -} - -/* - * pcibr_intr_preset: called during mlreset time - * if the platform specific code needs to route - * one of the Bridge's xtalk interrupts before the - * xtalk infrastructure is available. - */ -void -pcibr_xintr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - bridge_t *bridge = (bridge_t *) which_widget; - - if (which_widget_intr == -1) { - /* bridge widget error interrupt */ - bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - bridge->b_int_host_err = vect; - - /* turn on all interrupts except - * the PCI interrupt requests, - * at least at heart. - */ - bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; - - } else { - /* routing a PCI device interrupt. - * targ and low 38 bits of addr must - * be the same as the already set - * value for the widget error interrupt. - */ - bridge->b_int_addr[which_widget_intr].addr = - ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - /* - * now bridge can let it through; - * NB: still should be blocked at - * xtalk provider end, until the service - * function is set. - */ - bridge->b_int_enable |= 1 << vect; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ -} - - -/* - * pcibr_intr_func() - * - * This is the pcibr interrupt "wrapper" function that is called, - * in interrupt context, to initiate the interrupt handler(s) registered - * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded - * handlers will be called directly, and threaded handlers will have their - * thread woken up. - */ -void -pcibr_intr_func(intr_arg_t arg) -{ - pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p wrbf; - intr_func_t func; - pcibr_intr_t intr; - pcibr_intr_list_t list; - int clearit; -#ifdef KERNEL_THREADS - int do_nonthreaded = 0; - int do_threaded = 1; - int is_threaded = 0; -#else - int do_nonthreaded = 1; - int do_threaded = 0; - int is_threaded = 0; -#endif - int nonthreaded_count = 0; - int x = 0; - - /* - * If any handler is still running from a previous interrupt - * just return. If there's a need to call the handler(s) again, - * another interrupt will be generated either by the device or by - * pcibr_force_interrupt(). - */ - - if (wrap->iw_hdlrcnt) { - return; - } - - /* - * Call all interrupt handlers registered. - * First, the pcibr_intrd threads for any threaded handlers will be - * awoken, then any non-threaded handlers will be called sequentially. - */ - - clearit = 1; - while (do_threaded || do_nonthreaded) { - for (list = wrap->iw_list; list != NULL; list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - - ASSERT(intr->bi_func); - - /* - * This device may have initiated write - * requests since the bridge last saw - * an edge on this interrupt input; flushing - * the buffer prior to invoking the handler - * should help but may not be sufficient if we - * get more requests after the flush, followed - * by the card deciding it wants service, before - * the interrupt handler checks to see if things need - * to be done. - * - * There is a similar race condition if - * an interrupt handler loops around and - * notices further service is requred. - * Perhaps we need to have an explicit - * call that interrupt handlers need to - * do between noticing that DMA to memory - * has completed, but before observing the - * contents of memory? - */ - -#ifdef KERNEL_THREADS - is_threaded = !(intr->bi_flags & PCIIO_INTR_NOTHREAD); - if (!is_threaded) { - nonthreaded_count++; - } - - if ((do_threaded) && (is_threaded)) { - /* Only need to flush write buffers if sharing */ - - if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { - if (x = *wrbf) /* write request buffer flush */ -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_ALERT("pcibr_intr_func %v: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#else - PRINT_ALERT("pcibr_intr_func 0x%x: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#endif - } - - /* - * Keep a running count of the number of interrupt - * handlers that have yet to complete. - */ - atomicAddInt(&(wrap->iw_hdlrcnt), 1); - - /* - * Prior to waking up pcibr_intrd, a pointer to the - * wrapper struct corresponding to the interrupt taken - * needs to be queued in the interrupt circular buffer. - * The pcibr_intrd thread needs the wrapper pointer in - * order to decrement the handler count (iw_hdlrcnt). - */ - pcibr_wrap_put(wrap, &intr->bi_ibuf); -#ifdef ITHREAD_LATENCY - xthread_set_istamp(intr->bi_tinfo.thd_latstats); -#endif /* ITHREAD_LATENCY */ - up(&intr->bi_tinfo.thd_isync); - } else -#endif /* KERNEL_THREADS */ - if ((do_nonthreaded) && (!is_threaded)) { - /* Non-threaded. - * Call the interrupt handler at interrupt level - */ - - /* Only need to flush write buffers if sharing */ - - if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { - if ((x = *wrbf)) /* write request buffer flush */ -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_ALERT("pcibr_intr_func %v: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#else - PRINT_ALERT("pcibr_intr_func %p: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#endif - } - - func = intr->bi_func; - func(intr->bi_arg); - } - - clearit = 0; - } - } - - if (do_threaded) { - /* - * All threaded handlers have been called; - * next do non-threaded, if any. - */ - do_threaded = 0; - - if (nonthreaded_count) - do_nonthreaded = 1; - } else { - do_nonthreaded = 0; - /* - * If the non-threaded handler was the last to complete, - * (i.e., no threaded handlers still running) force an - * interrupt to avoid a potential deadlock situation. - */ - if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); - } - } - } - - /* If there were no handlers, - * disable the interrupt and return. - * It will get enabled again after - * a handler is connected. - * If we don't do this, we would - * sit here and spin through the - * list forever. - */ - if (clearit) { - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_int_enable; - bridgereg_t mask = 1 << wrap->iw_intr; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~mask; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - return; - } -} - -/* ===================================================================== - * ERROR HANDLING - */ - -#ifdef DEBUG -#ifdef ERROR_DEBUG -#define BRIDGE_PIOERR_TIMEOUT 100 /* Timeout with ERROR_DEBUG defined */ -#else -#define BRIDGE_PIOERR_TIMEOUT 40 /* Timeout in debug mode */ -#endif -#else -#define BRIDGE_PIOERR_TIMEOUT 1 /* Timeout in non-debug mode */ -#endif - -LOCAL void -print_bridge_errcmd(uint32_t cmdword, char *errtype) -{ -#ifdef SUPPORT_PRINTING_R_FORMAT - PRINT_WARNING( - " Bridge %s error command word register %R", - errtype, cmdword, xio_cmd_bits); -#else - PRINT_WARNING( - " Bridge %s error command word register 0x%x", - errtype, cmdword); -#endif -} - -LOCAL char *pcibr_isr_errs[] = -{ - "", "", "", "", "", "", "", "", - "08: GIO non-contiguous byte enable in crosstalk packet", - "09: PCI to Crosstalk read request timeout", - "10: PCI retry operation count exhausted.", - "11: PCI bus device select timeout", - "12: PCI device reported parity error", - "13: PCI Address/Cmd parity error ", - "14: PCI Bridge detected parity error", - "15: PCI abort condition", - "16: SSRAM parity error", - "17: LLP Transmitter Retry count wrapped", - "18: LLP Transmitter side required Retry", - "19: LLP Receiver retry count wrapped", - "20: LLP Receiver check bit error", - "21: LLP Receiver sequence number error", - "22: Request packet overflow", - "23: Request operation not supported by bridge", - "24: Request packet has invalid address for bridge widget", - "25: Incoming request xtalk command word error bit set or invalid sideband", - "26: Incoming response xtalk command word error bit set or invalid sideband", - "27: Framing error, request cmd data size does not match actual", - "28: Framing error, response cmd data size does not match actual", - "29: Unexpected response arrived", - "30: Access to SSRAM beyond device limits", - "31: Multiple errors occurred", -}; - -/* - * PCI Bridge Error interrupt handling. - * This routine gets invoked from system interrupt dispatcher - * and is responsible for invoking appropriate error handler, - * depending on the type of error. - * This IS a duplicate of bridge_errintr defined specfic to IP30. - * There are some minor differences in terms of the return value and - * parameters passed. One of these two should be removed at some point - * of time. - */ -/*ARGSUSED */ -void -pcibr_error_dump(pcibr_soft_t pcibr_soft) -{ - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_status; - int i; - - int_status = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); - - PRINT_ALERT( "%s PCI BRIDGE ERROR: int_status is 0x%X", - pcibr_soft->bs_name, int_status); - - for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) { - if (int_status & (1 << i)) { - PRINT_WARNING( "%s", pcibr_isr_errs[i]); - } - } - - if (int_status & BRIDGE_ISR_XTALK_ERROR) { - print_bridge_errcmd(bridge->b_wid_err_cmdword, ""); - - PRINT_WARNING(" Bridge error address 0x%lx", - (((uint64_t) bridge->b_wid_err_upper << 32) | - bridge->b_wid_err_lower)); - - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux"); - - if (int_status & (BRIDGE_ISR_BAD_XRESP_PKT | BRIDGE_ISR_RESP_XTLK_ERR)) { - PRINT_WARNING(" Bridge response buffer: dev-num %d buff-num %d addr 0x%lx\n", - ((bridge->b_wid_resp_upper >> 20) & 0x3), - ((bridge->b_wid_resp_upper >> 16) & 0xF), - (((uint64_t) (bridge->b_wid_resp_upper & 0xFFFF) << 32) | - bridge->b_wid_resp_lower)); - } - } - if (int_status & BRIDGE_ISR_SSRAM_PERR) - PRINT_WARNING(" Bridge SSRAM parity error register 0x%x", - bridge->b_ram_perr); - - if (int_status & BRIDGE_ISR_PCIBUS_ERROR) { - PRINT_WARNING(" PCI/GIO error upper address register 0x%x", - bridge->b_pci_err_upper); - - PRINT_WARNING(" PCI/GIO error lower address register 0x%x", - bridge->b_pci_err_lower); - } - if (int_status & BRIDGE_ISR_ERROR_FATAL) { - PRINT_PANIC("PCI Bridge Error interrupt killed the system"); - /*NOTREACHED */ - } else { - PRINT_ALERT( "Non-fatal Error in Bridge.."); - } -} - -#define PCIBR_ERRINTR_GROUP(error) \ - (( error & (BRIDGE_IRR_PCI_GRP|BRIDGE_IRR_GIO_GRP) - -uint32_t -pcibr_errintr_group(uint32_t error) -{ - uint32_t group = BRIDGE_IRR_MULTI_CLR; - - if (error & BRIDGE_IRR_PCI_GRP) - group |= BRIDGE_IRR_PCI_GRP_CLR; - if (error & BRIDGE_IRR_SSRAM_GRP) - group |= BRIDGE_IRR_SSRAM_GRP_CLR; - if (error & BRIDGE_IRR_LLP_GRP) - group |= BRIDGE_IRR_LLP_GRP_CLR; - if (error & BRIDGE_IRR_REQ_DSP_GRP) - group |= BRIDGE_IRR_REQ_DSP_GRP_CLR; - if (error & BRIDGE_IRR_RESP_BUF_GRP) - group |= BRIDGE_IRR_RESP_BUF_GRP_CLR; - if (error & BRIDGE_IRR_CRP_GRP) - group |= BRIDGE_IRR_CRP_GRP_CLR; - - return group; - -} - - -/* pcibr_pioerr_check(): - * Check to see if this pcibr has a PCI PIO - * TIMEOUT error; if so, clear it and bump - * the timeout-count on any piomaps that - * could cover the address. - */ -static void -pcibr_pioerr_check(pcibr_soft_t soft) -{ - bridge_t *bridge; - bridgereg_t b_int_status; - bridgereg_t b_pci_err_lower; - bridgereg_t b_pci_err_upper; - iopaddr_t pci_addr; - pciio_slot_t slot; - pcibr_piomap_t map; - iopaddr_t base; - size_t size; - unsigned win; - int func; - - bridge = soft->bs_base; - b_int_status = bridge->b_int_status; - if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - b_pci_err_lower = bridge->b_pci_err_lower; - b_pci_err_upper = bridge->b_pci_err_upper; - b_int_status = bridge->b_int_status; - if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - bridge->b_int_rst_stat = (BRIDGE_IRR_PCI_GRP_CLR| - BRIDGE_IRR_MULTI_CLR); - - pci_addr = b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK; - pci_addr = (pci_addr << 32) | b_pci_err_lower; - - slot = 8; - while (slot-- > 0) { - int nfunc = soft->bs_slot[slot].bss_ninfo; - pcibr_info_h pcibr_infoh = soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; func++) { - pcibr_info_t pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - for (map = pcibr_info->f_piomap; - map != NULL; map = map->bp_next) { - base = map->bp_pciaddr; - size = map->bp_mapsz; - win = map->bp_space - PCIIO_SPACE_WIN(0); - if (win < 6) - base += - soft->bs_slot[slot].bss_window[win].bssw_base; - else if (map->bp_space == PCIIO_SPACE_ROM) - base += pcibr_info->f_rbase; - if ((pci_addr >= base) && (pci_addr < (base + size))) - atomic_inc(map->bp_toc); - } - } - } - } - } -} - -/* - * PCI Bridge Error interrupt handler. - * This gets invoked, whenever a PCI bridge sends an error interrupt. - * Primarily this servers two purposes. - * - If an error can be handled (typically a PIO read/write - * error, we try to do it silently. - * - If an error cannot be handled, we die violently. - * Interrupt due to PIO errors: - * - Bridge sends an interrupt, whenever a PCI operation - * done by the bridge as the master fails. Operations could - * be either a PIO read or a PIO write. - * PIO Read operation also triggers a bus error, and it's - * We primarily ignore this interrupt in that context.. - * For PIO write errors, this is the only indication. - * and we have to handle with the info from here. - * - * So, there is no way to distinguish if an interrupt is - * due to read or write error!. - */ - - -LOCAL void -pcibr_error_intr_handler(intr_arg_t arg) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - bridgereg_t int_status; - bridgereg_t err_status; - int i; - - /* REFERENCED */ - bridgereg_t disable_errintr_mask = 0; - -#if PCIBR_SOFT_LIST - /* IP27 seems to be handing us junk. - */ - { - pcibr_list_p entry; - - entry = pcibr_list; - while (1) { - if (entry == NULL) { - printk("pcibr_error_intr_handler:\n" - "\tparameter (0x%p) is not a pcibr_soft!", - arg); - PRINT_PANIC("Invalid parameter to pcibr_error_intr_handler"); - } - if ((intr_arg_t) entry->bl_soft == arg) - break; - entry = entry->bl_next; - } - } -#endif - pcibr_soft = (pcibr_soft_t) arg; - bridge = pcibr_soft->bs_base; - - /* - * pcibr_error_intr_handler gets invoked whenever bridge encounters - * an error situation, and the interrupt for that error is enabled. - * This routine decides if the error is fatal or not, and takes - * action accordingly. - * - * In one case there is a need for special action. - * In case of PIO read/write timeouts due to user level, we do - * get an error interrupt. In this case, way to handle would - * be to start a timeout. If the error was due to "read", bus - * error handling code takes care of it. If error is due to write, - * it's handled at timeout - */ - - /* int_status is which bits we have to clear; - * err_status is the bits we haven't handled yet. - */ - - int_status = bridge->b_int_status & ~BRIDGE_ISR_INT_MSK; - err_status = int_status & ~BRIDGE_ISR_MULTI_ERR; - - if (!(int_status & ~BRIDGE_ISR_INT_MSK)) { - /* - * No error bit set!!. - */ - return; - } - /* If we have a PCIBUS_PIOERR, - * hand it to the logger but otherwise - * ignore the event. - */ - if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - pcibr_pioerr_check(pcibr_soft); - err_status &= ~BRIDGE_ISR_PCIBUS_PIOERR; - int_status &= ~BRIDGE_ISR_PCIBUS_PIOERR; - } - - - if (err_status) { - struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; - - for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++, bs_estat++) { - if (err_status & (1 << i)) { - uint32_t errrate = 0; - uint32_t errcount = 0; - uint32_t errinterval = 0, current_tick = 0; - int panic_on_llp_tx_retry = 0; - int is_llp_tx_retry_intr = 0; - - bs_estat->bs_errcount_total++; - -#ifdef LATER - current_tick = lbolt; -#else - current_tick = 0; -#endif - errinterval = (current_tick - bs_estat->bs_lasterr_timestamp); - errcount = (bs_estat->bs_errcount_total - - bs_estat->bs_lasterr_snapshot); - - is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY == (1 << i)); - - /* On a non-zero error rate (which is equivalent to - * to 100 errors /sec at least) for the LLP transmitter - * retry interrupt we need to panic the system - * to prevent potential data corruption . - * NOTE : errcount is being compared to PCIBR_ERRTIME_THRESHOLD - * to make sure that we are not seing cases like x error - * interrupts per y ticks for very low x ,y (x > y ) which - * makes error rate be > 100 /sec. - */ - - /* Check for the divide by zero condition while - * calculating the error rates. - */ - - if (errinterval) { - errrate = errcount / errinterval; - /* If able to calculate error rate - * on a LLP transmitter retry interrupt check - * if the error rate is nonzero and we have seen - * a certain minimum number of errors. - */ - if (is_llp_tx_retry_intr && - errrate && - (errcount >= PCIBR_ERRTIME_THRESHOLD)) { - panic_on_llp_tx_retry = 1; - } - } else { - errrate = 0; - /* Since we are not able to calculate the - * error rate check if we exceeded a certain - * minimum number of errors for LLP transmitter - * retries. Note that this can only happen - * within the first tick after the last snapshot. - */ - if (is_llp_tx_retry_intr && - (errcount >= PCIBR_ERRINTR_DISABLE_LEVEL)) { - panic_on_llp_tx_retry = 1; - } - } - if (panic_on_llp_tx_retry) { - static uint32_t last_printed_rate; - - if (errrate > last_printed_rate) { - last_printed_rate = errrate; - /* Print the warning only if the error rate - * for the transmitter retry interrupt - * exceeded the previously printed rate. - */ - PRINT_WARNING( - "%s: %s, Excessive error interrupts : %d/tick\n", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - errrate); - - } - /* - * Update snapshot, and time - */ - bs_estat->bs_lasterr_timestamp = current_tick; - bs_estat->bs_lasterr_snapshot = - bs_estat->bs_errcount_total; - - } - /* - * If the error rate is high enough, print the error rate. - */ - if (errinterval > PCIBR_ERRTIME_THRESHOLD) { - - if (errrate > PCIBR_ERRRATE_THRESHOLD) { - PRINT_NOTICE( "%s: %s, Error rate %d/tick", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - errrate); - /* - * Update snapshot, and time - */ - bs_estat->bs_lasterr_timestamp = current_tick; - bs_estat->bs_lasterr_snapshot = - bs_estat->bs_errcount_total; - } - } - if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) { - /* - * We have seen a fairly large number of errors of - * this type. Let's disable the interrupt. But flash - * a message about the interrupt being disabled. - */ - PRINT_NOTICE( - "%s Disabling error interrupt type %s. Error count %d", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - bs_estat->bs_errcount_total); - disable_errintr_mask |= (1 << i); - } - } - } - } - - if (disable_errintr_mask) { - /* - * Disable some high frequency errors as they - * could eat up too much cpu time. - */ - bridge->b_int_enable &= ~disable_errintr_mask; - } - /* - * If we leave the PROM cacheable, T5 might - * try to do a cache line sized writeback to it, - * which will cause a BRIDGE_ISR_INVLD_ADDR. - */ - if ((err_status & BRIDGE_ISR_INVLD_ADDR) && - (0x00000000 == bridge->b_wid_err_upper) && - (0x00C00000 == (0xFFC00000 & bridge->b_wid_err_lower)) && - (0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) { - err_status &= ~BRIDGE_ISR_INVLD_ADDR; - } -#if defined (PCIBR_LLP_CONTROL_WAR) - /* - * The bridge bug, where the llp_config or control registers - * need to be read back after being written, affects an MP - * system since there could be small windows between writing - * the register and reading it back on one cpu while another - * cpu is fielding an interrupt. If we run into this scenario, - * workaround the problem by ignoring the error. (bug 454474) - * pcibr_llp_control_war_cnt keeps an approximate number of - * times we saw this problem on a system. - */ - - if ((err_status & BRIDGE_ISR_INVLD_ADDR) && - ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) - == (BRIDGE_INT_RST_STAT & 0xff0))) { -#ifdef LATER - if (kdebug) - PRINT_NOTICE( "%s bridge: ignoring llp/control address interrupt", - pcibr_soft->bs_name); -#endif - pcibr_llp_control_war_cnt++; - err_status &= ~BRIDGE_ISR_INVLD_ADDR; - } -#endif /* PCIBR_LLP_CONTROL_WAR */ - -#ifdef DEBUG - if (err_status & BRIDGE_ISR_ERROR_DUMP) - pcibr_error_dump(pcibr_soft); -#else - if (err_status & BRIDGE_ISR_ERROR_FATAL) { - printk("BRIDGE ERR STATUS 0x%x\n", err_status); - pcibr_error_dump(pcibr_soft); - } -#endif - - /* - * We can't return without re-enabling the interrupt, since - * it would cause problems for devices like IOC3 (Lost - * interrupts ?.). So, just cleanup the interrupt, and - * use saved values later.. - */ - bridge->b_int_rst_stat = pcibr_errintr_group(int_status); -} - -/* - * pcibr_addr_toslot - * Given the 'pciaddr' find out which slot this address is - * allocated to, and return the slot number. - * While we have the info handy, construct the - * function number, space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - */ -LOCAL int -pcibr_addr_toslot(pcibr_soft_t pcibr_soft, - iopaddr_t pciaddr, - pciio_space_t *spacep, - iopaddr_t *offsetp, - pciio_function_t *funcp) -{ - int s, f=0, w; - iopaddr_t base; - size_t size; - pciio_piospace_t piosp; - - /* - * Check if the address is in config space - */ - - if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { - - if (pciaddr >= BRIDGE_CONFIG1_BASE) - pciaddr -= BRIDGE_CONFIG1_BASE; - else - pciaddr -= BRIDGE_CONFIG_BASE; - - s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; - pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; - - if (funcp) { - f = pciaddr / 0x100; - pciaddr %= 0x100; - } - if (spacep) - *spacep = PCIIO_SPACE_CFG; - if (offsetp) - *offsetp = pciaddr; - if (funcp) - *funcp = f; - - return s; - } - for (s = 0; s < 8; s++) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - for (w = 0; w < 6; w++) { - if (pcibr_info->f_window[w].w_space - == PCIIO_SPACE_NONE) { - continue; - } - base = pcibr_info->f_window[w].w_base; - size = pcibr_info->f_window[w].w_size; - - if ((pciaddr >= base) && (pciaddr < (base + size))) { - if (spacep) - *spacep = PCIIO_SPACE_WIN(w); - if (offsetp) - *offsetp = pciaddr - base; - if (funcp) - *funcp = f; - return s; - } /* endif match */ - } /* next window */ - } /* next func */ - } /* next slot */ - - /* - * Check if the address was allocated as part of the - * pcibr_piospace_alloc calls. - */ - for (s = 0; s < 8; s++) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - piosp = pcibr_info->f_piospace; - while (piosp) { - if ((piosp->start <= pciaddr) && - ((piosp->count + piosp->start) > pciaddr)) { - if (spacep) - *spacep = piosp->space; - if (offsetp) - *offsetp = pciaddr - piosp->start; - return s; - } /* endif match */ - piosp = piosp->next; - } /* next piosp */ - } /* next func */ - } /* next slot */ - - /* - * Some other random address on the PCI bus ... - * we have no way of knowing whether this was - * a MEM or I/O access; so, for now, we just - * assume that the low 1G is MEM, the next - * 3G is I/O, and anything above the 4G limit - * is obviously MEM. - */ - - if (spacep) - *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : - (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : - PCIIO_SPACE_MEM); - if (offsetp) - *offsetp = pciaddr; - - return PCIIO_SLOT_NONE; - -} - -LOCAL void -pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) -{ - bridge_t *bridge = pcibr_soft->bs_base; - - ASSERT(error_code & IOECODE_PIO); - error_code = error_code; - - bridge->b_int_rst_stat = - (BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR); - (void) bridge->b_wid_tflush; /* flushbus */ -} - -/* - * pcibr_error_extract - * Given the 'pcibr vertex handle' find out which slot - * the bridge status error address (from pcibr_soft info - * hanging off the vertex) - * allocated to, and return the slot number. - * While we have the info handy, construct the - * space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - * - * XXX- this interface has no way to return the function - * number on a multifunction card, even though that data - * is available. - */ - -pciio_slot_t -pcibr_error_extract(devfs_handle_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *offsetp) -{ - pcibr_soft_t pcibr_soft = 0; - iopaddr_t bserr_addr; - bridge_t *bridge; - pciio_slot_t slot = PCIIO_SLOT_NONE; - arbitrary_info_t rev; - - /* Do a sanity check as to whether we really got a - * bridge vertex handle. - */ - if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != - GRAPH_SUCCESS) - return(slot); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) { - bridge = pcibr_soft->bs_base; - bserr_addr = - bridge->b_pci_err_lower | - ((uint64_t) (bridge->b_pci_err_upper & - BRIDGE_ERRUPPR_ADDRMASK) << 32); - - slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, - spacep, offsetp, NULL); - } - return slot; -} - -/*ARGSUSED */ -void -pcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum) -{ - /* - * XXX - * Device failed to handle error. Take steps to - * disable this device ? HOW TO DO IT ? - * - * If there are any Read response buffers associated - * with this device, it's time to get them back!! - * - * We can disassociate any interrupt level associated - * with this device, and disable that interrupt level - * - * For now it's just a place holder - */ -} - -/* - * pcibr_pioerror - * Handle PIO error that happened at the bridge pointed by pcibr_soft. - * - * Queries the Bus interface attached to see if the device driver - * mapping the device-number that caused error can handle the - * situation. If so, it will clean up any error, and return - * indicating the error was handled. If the device driver is unable - * to handle the error, it expects the bus-interface to disable that - * device, and takes any steps needed here to take away any resources - * associated with this device. - */ - -#define BEM_ADD_STR(s) printk("%s", (s)) -#ifdef SUPPORT_SGI_CMN_ERR_STUFF -#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v)) -#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc) - -#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc) -#else -#define BEM_ADD_VAR(v) -#define BEM_ADD_REG(r) -#define BEM_ADD_NSPC(n,s) -#endif -#define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s) - -/* BEM_ADD_IOE doesn't dump the whole ioerror, it just - * decodes the PCI specific portions -- we count on our - * callers to dump the raw IOE data. - */ -#ifdef LATER -#define BEM_ADD_IOE(ioe) \ - do { \ - if (IOERROR_FIELDVALID(ioe, busspace)) { \ - unsigned spc; \ - unsigned win; \ - \ - spc = IOERROR_GETVALUE(ioe, busspace); \ - win = spc - PCIIO_SPACE_WIN(0); \ - \ - switch (spc) { \ - case PCIIO_SPACE_CFG: \ - printk("\tPCI Slot %d Func %d CFG space Offset 0x%x\n", \ - pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - IOERROR_GETVALUE(ioe, busaddr)); \ - break; \ - case PCIIO_SPACE_IO: \ - printk("\tPCI I/O space Offset 0x%x\n", \ - IOERROR_GETVALUE(ioe, busaddr)); \ - break; \ - case PCIIO_SPACE_MEM: \ - case PCIIO_SPACE_MEM32: \ - case PCIIO_SPACE_MEM64: \ - printk("\tPCI MEM space Offset 0x%x\n", \ - IOERROR_GETVALUE(ioe, busaddr)); \ - break; \ - default: \ - if (win < 6) { \ - printk("\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\ - pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - win, \ - IOERROR_GETVALUE(ioe, busaddr)); \ - } \ - break; \ - } \ - } \ - } while (0) -#else -#define BEM_ADD_IOE(ioe) -#endif - -/*ARGSUSED */ -LOCAL int -pcibr_pioerror( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - int retval = IOERROR_HANDLED; - - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; - bridge_t *bridge = pcibr_soft->bs_base; - - bridgereg_t bridge_int_status; - bridgereg_t bridge_pci_err_lower; - bridgereg_t bridge_pci_err_upper; - bridgereg_t bridge_pci_err_addr; - - iopaddr_t bad_xaddr; - - pciio_space_t raw_space; /* raw PCI space */ - iopaddr_t raw_paddr; /* raw PCI address */ - - pciio_space_t space; /* final PCI space */ - pciio_slot_t slot; /* final PCI slot, if appropriate */ - pciio_function_t func; /* final PCI func, if appropriate */ - iopaddr_t offset; /* final PCI offset */ - - int cs, cw, cf; - pciio_space_t wx; - iopaddr_t wb; - size_t ws; - iopaddr_t wl; - - - /* - * We expect to have an "xtalkaddr" coming in, - * and need to construct the slot/space/offset. - */ - -#ifdef LATER - bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); -#else - bad_xaddr = -1; -#endif - - slot = PCIIO_SLOT_NONE; - func = PCIIO_FUNC_NONE; - raw_space = PCIIO_SPACE_NONE; - raw_paddr = 0; - - if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) && - (bad_xaddr < BRIDGE_TYPE1_CFG)) { - raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0; - slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF; - raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF; - raw_space = PCIIO_SPACE_CFG; - } - if ((bad_xaddr >= BRIDGE_TYPE1_CFG) && - (bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) { - /* Type 1 config space: - * slot and function numbers not known. - * Perhaps we can read them back? - */ - raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG; - raw_space = PCIIO_SPACE_CFG; - } - if ((bad_xaddr >= BRIDGE_DEVIO0) && - (bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) { - int x; - - raw_paddr = bad_xaddr - BRIDGE_DEVIO0; - x = raw_paddr / BRIDGE_DEVIO_OFF; - raw_paddr %= BRIDGE_DEVIO_OFF; - /* first two devio windows are double-sized */ - if ((x == 1) || (x == 3)) - raw_paddr += BRIDGE_DEVIO_OFF; - if (x > 0) - x--; - if (x > 1) - x--; - /* x is which devio reg; no guarantee - * PCI slot x will be responding. - * still need to figure out who decodes - * space/offset on the bus. - */ - raw_space = pcibr_soft->bs_slot[x].bss_devio.bssd_space; - if (raw_space == PCIIO_SPACE_NONE) { - /* Someone got an error because they - * accessed the PCI bus via a DevIO(x) - * window that pcibr has not yet assigned - * to any specific PCI address. It is - * quite possible that the Device(x) - * register has been changed since they - * made their access, but we will give it - * our best decode shot. - */ - raw_space = pcibr_soft->bs_slot[x].bss_device - & BRIDGE_DEV_DEV_IO_MEM - ? PCIIO_SPACE_MEM - : PCIIO_SPACE_IO; - raw_paddr += - (pcibr_soft->bs_slot[x].bss_device & - BRIDGE_DEV_OFF_MASK) << - BRIDGE_DEV_OFF_ADDR_SHFT; - } else - raw_paddr += pcibr_soft->bs_slot[x].bss_devio.bssd_base; - } - if ((bad_xaddr >= BRIDGE_PCI_MEM32_BASE) && - (bad_xaddr <= BRIDGE_PCI_MEM32_LIMIT)) { - raw_space = PCIIO_SPACE_MEM32; - raw_paddr = bad_xaddr - BRIDGE_PCI_MEM32_BASE; - } - if ((bad_xaddr >= BRIDGE_PCI_MEM64_BASE) && - (bad_xaddr <= BRIDGE_PCI_MEM64_LIMIT)) { - raw_space = PCIIO_SPACE_MEM64; - raw_paddr = bad_xaddr - BRIDGE_PCI_MEM64_BASE; - } - if ((bad_xaddr >= BRIDGE_PCI_IO_BASE) && - (bad_xaddr <= BRIDGE_PCI_IO_LIMIT)) { - raw_space = PCIIO_SPACE_IO; - raw_paddr = bad_xaddr - BRIDGE_PCI_IO_BASE; - } - space = raw_space; - offset = raw_paddr; - - if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { - /* we've got a space/offset but not which - * PCI slot decodes it. Check through our - * notions of which devices decode where. - * - * Yes, this "duplicates" some logic in - * pcibr_addr_toslot; the difference is, - * this code knows which space we are in, - * and can really really tell what is - * going on (no guessing). - */ - - for (cs = 0; (cs < 8) && (slot == PCIIO_SLOT_NONE); cs++) { - int nf = pcibr_soft->bs_slot[cs].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; - - for (cf = 0; (cf < nf) && (slot == PCIIO_SLOT_NONE); cf++) { - pcibr_info_t pcibr_info = pcibr_infoh[cf]; - - if (!pcibr_info) - continue; - for (cw = 0; (cw < 6) && (slot == PCIIO_SLOT_NONE); ++cw) { - if (((wx = pcibr_info->f_window[cw].w_space) != PCIIO_SPACE_NONE) && - ((wb = pcibr_info->f_window[cw].w_base) != 0) && - ((ws = pcibr_info->f_window[cw].w_size) != 0) && - ((wl = wb + ws) > wb) && - ((wb <= offset) && (wl > offset))) { - /* MEM, MEM32 and MEM64 need to - * compare as equal ... - */ - if ((wx == space) || - (((wx == PCIIO_SPACE_MEM) || - (wx == PCIIO_SPACE_MEM32) || - (wx == PCIIO_SPACE_MEM64)) && - ((space == PCIIO_SPACE_MEM) || - (space == PCIIO_SPACE_MEM32) || - (space == PCIIO_SPACE_MEM64)))) { - slot = cs; - func = cf; - space = PCIIO_SPACE_WIN(cw); - offset -= wb; - } /* endif window space match */ - } /* endif window valid and addr match */ - } /* next window unless slot set */ - } /* next func unless slot set */ - } /* next slot unless slot set */ - /* XXX- if slot is still -1, no PCI devices are - * decoding here using their standard PCI BASE - * registers. This would be a really good place - * to cross-coordinate with the pciio PCI - * address space allocation routines, to find - * out if this address is "allocated" by any of - * our subsidiary devices. - */ - } - /* Scan all piomap records on this PCI bus to update - * the TimeOut Counters on all matching maps. If we - * don't already know the slot number, take it from - * the first matching piomap. Note that we have to - * compare maps against raw_space and raw_paddr - * since space and offset could already be - * window-relative. - * - * There is a chance that one CPU could update - * through this path, and another CPU could also - * update due to an interrupt. Closing this hole - * would only result in the possibility of some - * errors never getting logged at all, and since the - * use for bp_toc is as a logical test rather than a - * strict count, the excess counts are not a - * problem. - */ - for (cs = 0; cs < 8; ++cs) { - int nf = pcibr_soft->bs_slot[cs].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; - - for (cf = 0; cf < nf; cf++) { - pcibr_info_t pcibr_info = pcibr_infoh[cf]; - pcibr_piomap_t map; - - if (!pcibr_info) - continue; - - for (map = pcibr_info->f_piomap; - map != NULL; map = map->bp_next) { - wx = map->bp_space; - wb = map->bp_pciaddr; - ws = map->bp_mapsz; - cw = wx - PCIIO_SPACE_WIN(0); - if (cw < 6) { - wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; - wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space; - } - if (wx == PCIIO_SPACE_ROM) { - wb += pcibr_info->f_rbase; - wx = PCIIO_SPACE_MEM; - } - if ((wx == PCIIO_SPACE_MEM32) || - (wx == PCIIO_SPACE_MEM64)) - wx = PCIIO_SPACE_MEM; - wl = wb + ws; - if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { - atomic_inc(map->bp_toc); - if (slot == PCIIO_SLOT_NONE) { - slot = cs; - space = map->bp_space; - if (cw < 6) - offset -= pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; - } - } - } - } - } - - if (space != PCIIO_SPACE_NONE) { - if (slot != PCIIO_SLOT_NONE) { -#ifdef LATER - if (func != PCIIO_FUNC_NONE) - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,func)); - else - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,0)); -#else - if (func != PCIIO_FUNC_NONE) { - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,func)); - } else { - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,0)); - } -#endif - } - - IOERROR_SETVALUE(ioe, busspace, space); - IOERROR_SETVALUE(ioe, busaddr, offset); - } - if (mode == MODE_DEVPROBE) { - /* - * During probing, we don't really care what the - * error is. Clean up the error in Bridge, notify - * subsidiary devices, and return success. - */ - pcibr_error_cleanup(pcibr_soft, error_code); - - /* if appropriate, give the error handler for this slot - * a shot at this probe access as well. - */ - return (slot == PCIIO_SLOT_NONE) ? IOERROR_HANDLED : - pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - } - /* - * If we don't know what "PCI SPACE" the access - * was targeting, we may have problems at the - * Bridge itself. Don't touch any bridge registers, - * and do complain loudly. - */ - - if (space == PCIIO_SPACE_NONE) { - printk("XIO Bus Error at %s\n" - "\taccess to XIO bus offset 0x%lx\n" - "\tdoes not correspond to any PCI address\n", - pcibr_soft->bs_name, bad_xaddr); - - /* caller will dump contents of ioe struct */ - return IOERROR_XTALKLEVEL; - } - /* - * Read the PCI Bridge error log registers. - */ - bridge_int_status = bridge->b_int_status; - bridge_pci_err_upper = bridge->b_pci_err_upper; - bridge_pci_err_lower = bridge->b_pci_err_lower; - - bridge_pci_err_addr = - bridge_pci_err_lower - | (((iopaddr_t) bridge_pci_err_upper - & BRIDGE_ERRUPPR_ADDRMASK) << 32); - - /* - * Actual PCI Error handling situation. - * Typically happens when a user level process accesses - * PCI space, and it causes some error. - * - * Due to PCI Bridge implementation, we get two indication - * for a read error: an interrupt and a Bus error. - * We like to handle read error in the bus error context. - * But the interrupt comes and goes before bus error - * could make much progress. (NOTE: interrupd does - * come in _after_ bus error processing starts. But it's - * completed by the time bus error code reaches PCI PIO - * error handling. - * Similarly write error results in just an interrupt, - * and error handling has to be done at interrupt level. - * There is no way to distinguish at interrupt time, if an - * error interrupt is due to read/write error.. - */ - - /* We know the xtalk addr, the raw PCI bus space, - * the raw PCI bus address, the decoded PCI bus - * space, the offset within that space, and the - * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot - * is known to be involved). - */ - - /* - * Hand the error off to the handler registered - * for the slot that should have decoded the error, - * or to generic PCI handling (if pciio decides that - * such is appropriate). - */ - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - - if (retval != IOERROR_HANDLED) { - - /* Generate a generic message for IOERROR_UNHANDLED - * since the subsidiary handlers were silent, and - * did no recovery. - */ - if (retval == IOERROR_UNHANDLED) { - retval = IOERROR_PANIC; - - /* we may or may not want to print some of this, - * depending on debug level and which error code. - */ - - PRINT_ALERT( - "PIO Error on PCI Bus %s", - pcibr_soft->bs_name); - /* this decodes part of the ioe; our caller - * will dump the raw details in DEBUG and - * kdebug kernels. - */ - BEM_ADD_IOE(ioe); - } -#if defined(FORCE_ERRORS) - if (0) { -#elif !DEBUG - if (kdebug) { -#endif - /* - * dump raw data from bridge - */ - - BEM_ADD_STR("DEBUG DATA -- raw info from Bridge ASIC:\n"); - BEM_ADD_REG(bridge_int_status); - BEM_ADD_VAR(bridge_pci_err_upper); - BEM_ADD_VAR(bridge_pci_err_lower); - BEM_ADD_VAR(bridge_pci_err_addr); - BEM_ADD_SPC(raw_space); - BEM_ADD_VAR(raw_paddr); - if (IOERROR_FIELDVALID(ioe, widgetdev)) { - -#ifdef LATER - slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, - widgetdev)); - func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, - widgetdev)); -#else - slot = -1; - func = -1; -#endif - if (slot < 8) { -#ifdef SUPPORT_SGI_CMN_ERR_STUFF - bridgereg_t device = bridge->b_device[slot].reg; -#endif - - BEM_ADD_VAR(slot); - BEM_ADD_VAR(func); - BEM_ADD_REG(device); - } - } -#if !DEBUG || defined(FORCE_ERRORS) - } -#endif - - /* - * Since error could not be handled at lower level, - * error data logged has not been cleared. - * Clean up errors, and - * re-enable bridge to interrupt on error conditions. - * NOTE: Wheather we get the interrupt on PCI_ABORT or not is - * dependent on INT_ENABLE register. This write just makes sure - * that if the interrupt was enabled, we do get the interrupt. - * - * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges - * a group of interrupts. If while handling this error, - * some other error has occurred, that would be - * implicitly cleared by this write. - * Need a way to ensure we don't inadvertently clear some - * other errors. - */ -#ifdef LATER - if (IOERROR_FIELDVALID(ioe, widgetdev)) - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe, widgetdev))); -#endif - - if (mode == MODE_DEVUSERERROR) - pcibr_error_cleanup(pcibr_soft, error_code); - } - return retval; -} - -/* - * bridge_dmaerror - * Some error was identified in a DMA transaction. - * This routine will identify the that caused the error, - * and try to invoke the appropriate bus service to handle this. - */ - -#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT) - -int -pcibr_dmard_error( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t bus_lowaddr, bus_uppraddr; - int retval = 0; - int bufnum; - - /* - * In case of DMA errors, bridge should have logged the - * address that caused the error. - * Look up the address, in the bridge error registers, and - * take appropriate action - */ -#ifdef LATER - ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid); - ASSERT(bridge); -#endif - - /* - * read error log registers - */ - bus_lowaddr = bridge->b_wid_resp_lower; - bus_uppraddr = bridge->b_wid_resp_upper; - - bufnum = BRIDGE_RESP_ERRUPPR_BUFNUM(bus_uppraddr); - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create( - BRIDGE_RESP_ERRUPPR_DEVICE(bus_uppraddr), - 0)); - IOERROR_SETVALUE(ioe, busaddr, - (bus_lowaddr | - ((iopaddr_t) - (bus_uppraddr & - BRIDGE_ERRUPPR_ADDRMASK) << 32))); - - /* - * need to ensure that the xtalk address in ioe - * maps to PCI error address read from bridge. - * How to convert PCI address back to Xtalk address ? - * (better idea: convert XTalk address to PCI address - * and then do the compare!) - */ - - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - if (retval != IOERROR_HANDLED) -#ifdef LATER - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe,widgetdev))); -#else - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get(-1)); -#endif - - /* - * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR - * NOTE: Wheather we get the interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR or - * not is dependent on INT_ENABLE register. This write just makes sure - * that if the interrupt was enabled, we do get the interrupt. - */ - bridge->b_int_rst_stat = BRIDGE_IRR_RESP_BUF_GRP_CLR; - - /* - * Also, release the "bufnum" back to buffer pool that could be re-used. - * This is done by "disabling" the buffer for a moment, then restoring - * the original assignment. - */ - - { - reg_p regp; - bridgereg_t regv; - bridgereg_t mask; - - regp = (bufnum & 1) - ? &bridge->b_odd_resp - : &bridge->b_even_resp; - - mask = 0xF << ((bufnum >> 1) * 4); - - regv = *regp; - *regp = regv & ~mask; - *regp = regv; - } - - return retval; -} - -/* - * pcibr_dmawr_error: - * Handle a dma write error caused by a device attached to this bridge. - * - * ioe has the widgetnum, widgetdev, and memaddr fields updated - * But we don't know the PCI address that corresponds to "memaddr" - * nor do we know which device driver is generating this address. - * - * There is no easy way to find out the PCI address(es) that map - * to a specific system memory address. Bus handling code is also - * of not much help, since they don't keep track of the DMA mapping - * that have been handed out. - * So it's a dead-end at this time. - * - * If translation is available, we could invoke the error handling - * interface of the device driver. - */ -/*ARGSUSED */ -int -pcibr_dmawr_error( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; - int retval; - - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - -#ifdef LATER - if (retval != IOERROR_HANDLED) { - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe, widgetdev))); - - } -#endif - return retval; -} - -/* - * Bridge error handler. - * Interface to handle all errors that involve bridge in some way. - * - * This normally gets called from xtalk error handler. - * ioe has different set of fields set depending on the error that - * was encountered. So, we have a bit field indicating which of the - * fields are valid. - * - * NOTE: This routine could be operating in interrupt context. So, - * don't try to sleep here (till interrupt threads work!!) - */ -LOCAL int -pcibr_error_handler( - error_handler_arg_t einfo, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - pcibr_soft_t pcibr_soft; - int retval = IOERROR_BADERRORCODE; - - pcibr_soft = (pcibr_soft_t) einfo; - - /* If we are in the action handling phase clean out the error state - * on the xswitch. - */ -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(xconn_vhdl, ERROR_STATE_NONE); -#endif - -#if DEBUG && ERROR_DEBUG - printk("%s: pcibr_error_handler\n", pcibr_soft->bs_name); -#endif - - ASSERT(pcibr_soft != NULL); - - if (error_code & IOECODE_PIO) - retval = pcibr_pioerror(pcibr_soft, error_code, mode, ioe); - - if (error_code & IOECODE_DMA) { - if (error_code & IOECODE_READ) { - /* - * DMA read error occurs when a device attached to the bridge - * tries to read some data from system memory, and this - * either results in a timeout or access error. - * First case is indicated by the bit "XREAD_REQ_TOUT" - * and second case by "RESP_XTALK_ERROR" bit in bridge error - * interrupt status register. - * - * pcibr_error_intr_handler would get invoked first, and it has - * the responsibility of calling pcibr_error_handler with - * suitable parameters. - */ - - retval = pcibr_dmard_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); - } - if (error_code & IOECODE_WRITE) { - /* - * A device attached to this bridge has been generating - * bad DMA writes. Find out the device attached, and - * slap on it's wrist. - */ - - retval = pcibr_dmawr_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); - } - } - return retval; - -} - -/* - * Reenable a device after handling the error. - * This is called by the lower layers when they wish to be reenabled - * after an error. - * Note that each layer would be calling the previous layer to reenable - * first, before going ahead with their own re-enabling. - */ - -int -pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - ASSERT(error_code & IOECODE_PIO); - - /* If the error is not known to be a write, - * we have to call devenable. - * write errors are isolated to the bridge. - */ - if (!(error_code & IOECODE_WRITE)) { - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - int rc; - - rc = xtalk_error_devenable(xconn_vhdl, pciio_slot, error_code); - if (rc != IOERROR_HANDLED) - return rc; - } - pcibr_error_cleanup(pcibr_soft, error_code); - return IOERROR_HANDLED; -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ -/*ARGSUSED */ -void -pcibr_provider_startup(devfs_handle_t pcibr) -{ -} - -/*ARGSUSED */ -void -pcibr_provider_shutdown(devfs_handle_t pcibr) -{ -} - -int -pcibr_reset(devfs_handle_t conn) -{ - pciio_info_t pciio_info = pciio_info_get(conn); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t ctlreg; - unsigned cfgctl[8]; - unsigned long s; - int f, nf; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int win; - - if (pcibr_soft->bs_slot[pciio_slot].has_host) { - pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; - } - if (pciio_slot < 4) { - s = pcibr_lock(pcibr_soft); - nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; - - ctlreg = bridge->b_wid_control; - bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); - /* XXX delay? */ - bridge->b_wid_control = ctlreg; - /* XXX delay? */ - - for (f = 0; f < nf; ++f) - if ((pcibr_info = pcibr_infoh[f])) - for (win = 0; win < 6; ++win) - if (pcibr_info->f_window[win].w_base != 0) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = - pcibr_info->f_window[win].w_base; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; - pcibr_unlock(pcibr_soft, s); - - return 0; - } -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING( "%v: pcibr_reset unimplemented for slot %d\n", - conn, pciio_slot); -#endif - return -1; -} - -pciio_endian_t -pcibr_endian_set(devfs_handle_t pconn_vhdl, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t devreg; - unsigned long s; - - /* - * Bridge supports hardware swapping; so we can always - * arrange for the caller's desired endianness. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_end != desired_end) - devreg |= BRIDGE_DEV_SWAP_BITS; - else - devreg &= ~BRIDGE_DEV_SWAP_BITS; - - /* NOTE- if we ever put SWAP bits - * onto the disabled list, we will - * have to change the logic here. - */ - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); -#endif - - return desired_end; -} - -/* This (re)sets the GBR and REALTIME bits and also keeps track of how - * many sets are outstanding. Reset succeeds only if the number of outstanding - * sets == 1. - */ -int -pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, - pciio_slot_t pciio_slot, - pciio_priority_t device_prio) -{ - unsigned long s; - int *counter; - bridgereg_t rtbits = 0; - bridgereg_t devreg; - int rc = PRIO_SUCCESS; - - /* in dual-slot configurations, the host and the - * guest have separate DMA resources, so they - * have separate requirements for priority bits. - */ - - counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); - - /* - * Bridge supports PCI notions of LOW and HIGH priority - * arbitration rings via a "REAL_TIME" bit in the per-device - * Bridge register. The "GBR" bit controls access to the GBR - * ring on the xbow. These two bits are (re)set together. - * - * XXX- Bug in Rev B Bridge Si: - * Symptom: Prefetcher starts operating incorrectly. This happens - * due to corruption of the address storage ram in the prefetcher - * when a non-real time PCI request is pulled and a real-time one is - * put in it's place. Workaround: Use only a single arbitration ring - * on PCI bus. GBR and RR can still be uniquely used per - * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. - */ - - if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) - rtbits |= BRIDGE_DEV_RT; - - /* NOTE- if we ever put DEV_RT or DEV_GBR on - * the disabled list, we will have to take - * it into account here. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_prio == PCI_PRIO_HIGH) { - if ((++*counter == 1)) { - if (rtbits) - devreg |= rtbits; - else - rc = PRIO_FAIL; - } - } else if (device_prio == PCI_PRIO_LOW) { - if (*counter <= 0) - rc = PRIO_FAIL; - else if (--*counter == 0) - if (rtbits) - devreg &= ~rtbits; - } - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - - return rc; -} - -pciio_priority_t -pcibr_priority_set(devfs_handle_t pconn_vhdl, - pciio_priority_t device_prio) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); - - return device_prio; -} - -/* - * Interfaces to allow special (e.g. SGI) drivers to set/clear - * Bridge-specific device flags. Many flags are modified through - * PCI-generic interfaces; we don't allow them to be directly - * manipulated here. Only flags that at this point seem pretty - * Bridge-specific can be set through these special interfaces. - * We may add more flags as the need arises, or remove flags and - * create PCI-generic interfaces as the need arises. - * - * Returns 0 on failure, 1 on success - */ -int -pcibr_device_flags_set(devfs_handle_t pconn_vhdl, - pcibr_device_flags_t flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t set = 0; - bridgereg_t clr = 0; - - ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_PMU_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_PMU_WRGA_EN; - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_DIR_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_DIR_WRGA_EN; - - if (flags & PCIBR_PREFETCH) - set |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - clr |= BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - set |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - clr |= BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - set |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - clr |= BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - set |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - clr |= BRIDGE_DEV_DEV_SIZE; - - if (set || clr) { - bridgereg_t devreg; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - devreg = (devreg & ~clr) | set; - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); -#endif - } - return (1); -} - -#ifdef LITTLE_ENDIAN -/* - * on sn-ia we need to twiddle the addresses going out - * the pci bus because we use the unswizzled synergy space - * (the alternative is to use the swizzled synergy space - * and byte swap the data) - */ -#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) -#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) -#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#else -#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) -#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) -#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) -#endif /* LITTLE_ENDIAN */ - - -LOCAL cfg_p -pcibr_config_addr(devfs_handle_t conn, - unsigned reg) -{ - pcibr_info_t pcibr_info; - pciio_slot_t pciio_slot; - pciio_function_t pciio_func; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - cfg_p cfgbase = (cfg_p)0; - - pcibr_info = pcibr_info_get(conn); - - pciio_slot = pcibr_info->f_slot; - if (pciio_slot == PCIIO_SLOT_NONE) - pciio_slot = PCI_TYPE1_SLOT(reg); - - pciio_func = pcibr_info->f_func; - if (pciio_func == PCIIO_FUNC_NONE) - pciio_func = PCI_TYPE1_FUNC(reg); - - pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - bridge = pcibr_soft->bs_base; - - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; - - return cfgbase; -} - -uint64_t -pcibr_config_get(devfs_handle_t conn, - unsigned reg, - unsigned size) -{ - return do_pcibr_config_get(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); -} - -LOCAL uint64_t -do_pcibr_config_get( - cfg_p cfgbase, - unsigned reg, - unsigned size) -{ - unsigned value; - - - value = CW(cfgbase, reg); - - if (reg & 3) - value >>= 8 * (reg & 3); - if (size < 4) - value &= (1 << (8 * size)) - 1; - - return value; -} - -void -pcibr_config_set(devfs_handle_t conn, - unsigned reg, - unsigned size, - uint64_t value) -{ - do_pcibr_config_set(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); -} - -LOCAL void -do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - switch (size) { - case 1: - CB(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; - - case 4: - CW(cfgbase, reg) = value; - break; - } -} - -pciio_provider_t pcibr_provider = -{ - (pciio_piomap_alloc_f *) pcibr_piomap_alloc, - (pciio_piomap_free_f *) pcibr_piomap_free, - (pciio_piomap_addr_f *) pcibr_piomap_addr, - (pciio_piomap_done_f *) pcibr_piomap_done, - (pciio_piotrans_addr_f *) pcibr_piotrans_addr, - (pciio_piospace_alloc_f *) pcibr_piospace_alloc, - (pciio_piospace_free_f *) pcibr_piospace_free, - - (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, - (pciio_dmamap_free_f *) pcibr_dmamap_free, - (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, - (pciio_dmamap_done_f *) pcibr_dmamap_done, - (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, - (pciio_dmamap_drain_f *) pcibr_dmamap_drain, - (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - (pciio_dmalist_drain_f *) pcibr_dmalist_drain, - - (pciio_intr_alloc_f *) pcibr_intr_alloc, - (pciio_intr_free_f *) pcibr_intr_free, - (pciio_intr_connect_f *) pcibr_intr_connect, - (pciio_intr_disconnect_f *) pcibr_intr_disconnect, - (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, - - (pciio_provider_startup_f *) pcibr_provider_startup, - (pciio_provider_shutdown_f *) pcibr_provider_shutdown, - (pciio_reset_f *) pcibr_reset, - (pciio_write_gather_flush_f *) pcibr_write_gather_flush, - (pciio_endian_set_f *) pcibr_endian_set, - (pciio_priority_set_f *) pcibr_priority_set, - (pciio_config_get_f *) pcibr_config_get, - (pciio_config_set_f *) pcibr_config_set, - - (pciio_error_devenable_f *) pcibr_error_devenable, - (pciio_error_extract_f *) pcibr_error_extract, - -#ifdef LATER - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, -#else - (pciio_driver_reg_callback_f *) 0, - (pciio_driver_unreg_callback_f *) 0, -#endif - (pciio_device_unregister_f *) pcibr_device_unregister, - (pciio_dma_enabled_f *) pcibr_dma_enabled, -}; - -LOCAL pcibr_hints_t -pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) -{ - arbitrary_info_t ainfo = 0; - graph_error_t rv; - pcibr_hints_t hint; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (alloc && (rv != GRAPH_SUCCESS)) { - - NEW(hint); - hint->rrb_alloc_funct = NULL; - hint->ph_intr_bits = NULL; - rv = hwgraph_info_add_LBL(xconn_vhdl, - INFO_LBL_PCIBR_HINTS, - (arbitrary_info_t) hint); - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - if (ainfo != (arbitrary_info_t) hint) - goto abnormal_exit; - } - return (pcibr_hints_t) ainfo; - -abnormal_exit: -#ifdef LATER - printf("SHOULD NOT BE HERE\n"); -#endif - DEL(hint); - return(NULL); - -} - -void -pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_rrb_fixed = mask; -#if DEBUG - else - printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); -} - -void -pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, - pciio_slot_t host, - pciio_slot_t guest) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_host_slot[guest] = host + 1; -#if DEBUG - else - printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, - pcibr_intr_bits_f *xxx_intr_bits) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_intr_bits = xxx_intr_bits; -#if DEBUG - else - printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->rrb_alloc_funct = rrb_alloc_funct; -} - -void -pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_hands_off = 1; -#if DEBUG - else - printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, - pciio_slot_t slot, - uint64_t subdevs) -{ - arbitrary_info_t ainfo = 0; - char sdname[16]; - devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; - - sprintf(sdname, "pci/%d", slot); - (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); - if (pconn_vhdl == GRAPH_VERTEX_NONE) { -#if DEBUG - printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" - "\t%p (seeking %s)\n", xconn_vhdl, sdname); -#endif - return; - } - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == 0) { - uint64_t *subdevp; - - NEW(subdevp); - if (!subdevp) { -#if DEBUG - printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } - *subdevp = subdevs; - hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == (arbitrary_info_t) subdevp) - return; - DEL(subdevp); - if (ainfo == (arbitrary_info_t) NULL) { -#if DEBUG - printk("pcibr_hints_subdevs: null subdevs ptr at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } -#if DEBUG - printk("pcibr_subdevs_get: dup subdev add_LBL at\n" - "\t%p\n", pconn_vhdl); -#endif - } - *(uint64_t *) ainfo = subdevs; -} - - -#ifdef LATER - -#include -#include - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); -#endif - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_master); -#endif - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} - -#endif /* LATER */ - -int -pcibr_dma_enabled(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - - return xtalk_dma_enabled(pcibr_soft->bs_conn); -} diff -urN linux-2.4.18/arch/ia64/sn/io/pciio.c linux-2.4.19-pre5/arch/ia64/sn/io/pciio.c --- linux-2.4.18/arch/ia64/sn/io/pciio.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/pciio.c Sat Mar 30 22:55:26 2002 @@ -4,14 +4,18 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #define USRPCI 0 +#include #include #include +#include +#include +#include +#include #include #include #include /* Must be before iograph.h to get MAX_PORT_NUM */ @@ -25,13 +29,16 @@ #include #include #include +#include +#include +#include #define DEBUG_PCIIO #undef DEBUG_PCIIO /* turn this on for yet more console output */ -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) +#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DO_DEL(ptr) (kfree(ptr)) char pciio_info_fingerprint[] = "pciio_info"; @@ -45,7 +52,11 @@ switch (len) { case 4: +#ifdef CONFIG_IA64_SGI_SN1 new_addr = (void *)(((u64) addr)^4); +#else + new_addr = (void *) addr; +#endif ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); break; default: @@ -63,6 +74,14 @@ get_console_nasid(void) { extern nasid_t console_nasid; + if (console_nasid < 0) { + console_nasid = ia64_sn_get_console_nasid(); + if (console_nasid < 0) { +// ZZZ What do we do if we don't get a console nasid on the hardware???? + if (IS_RUNNING_ON_SIMULATOR() ) + console_nasid = master_nasid; + } + } return console_nasid; } @@ -105,7 +124,7 @@ * completely disappear. */ -#if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC +#if defined(CONFIG_IA64_SGI_SN1) /* * For the moment, we will assume that IP27 * only use Bridge ASICs to provide PCI support. @@ -115,7 +134,7 @@ #define CAST_PIOMAP(x) ((pcibr_piomap_t)(x)) #define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x)) #define CAST_INTR(x) ((pcibr_intr_t)(x)) -#endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_SGI_SN1 */ /* ===================================================================== * Function Table of Contents @@ -150,14 +169,11 @@ pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); void pciio_intr_free(pciio_intr_t); -int pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t, void *thread); +int pciio_intr_connect(pciio_intr_t); void pciio_intr_disconnect(pciio_intr_t); devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); -static pciio_info_t pciio_cardinfo_get(devfs_handle_t, pciio_slot_t); -int pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int pciio_error_devenable(devfs_handle_t, int); void pciio_provider_startup(devfs_handle_t); void pciio_provider_shutdown(devfs_handle_t); @@ -257,7 +273,7 @@ #if defined(SUPPORT_PRINTING_V_FORMAT) PRINT_PANIC("%v: provider_fns == NULL", dev); #else - PRINT_PANIC("0x%x: provider_fns == NULL", dev); + PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); #endif return provider_fns; @@ -575,13 +591,10 @@ * Returns 0 on success, returns <0 on failure. */ int -pciio_intr_connect(pciio_intr_t intr_hdl, /* pciio intr resource handle */ - intr_func_t intr_func, /* pciio intr handler */ - intr_arg_t intr_arg, /* arg to intr handler */ - void *thread) -{ /* intr thread to use */ +pciio_intr_connect(pciio_intr_t intr_hdl) /* pciio intr resource handle */ +{ return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), intr_func, intr_arg, thread); + (CAST_INTR(intr_hdl)); } /* @@ -605,10 +618,6 @@ (CAST_INTR(intr_hdl)); } -/* ===================================================================== - * ERROR MANAGEMENT - */ - void pciio_slot_func_to_name(char *name, pciio_slot_t slot, @@ -630,193 +639,6 @@ sprintf(name, "%d%c", slot, 'a'+func); } -/* - * pciio_cardinfo_get - * - * Get the pciio info structure corresponding to the - * specified PCI "slot" (we like it when the same index - * number is used for the PCI IDSEL, the REQ/GNT pair, - * and the interrupt line being used for INTA. We like - * it so much we call it the slot number). - */ -static pciio_info_t -pciio_cardinfo_get( - devfs_handle_t pciio_vhdl, - pciio_slot_t pci_slot) -{ - char namebuf[16]; - pciio_info_t info = 0; - devfs_handle_t conn; - - pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE); - if (GRAPH_SUCCESS == - hwgraph_traverse(pciio_vhdl, namebuf, &conn)) { - info = pciio_info_chk(conn); - hwgraph_vertex_unref(conn); - } - - return info; -} - -/* - * pciio_error_handler: - * dispatch an error to the appropriate - * pciio connection point, or process - * it as a generic pci error. - * Yes, the first parameter is the - * provider vertex at the middle of - * the bus; we get to the pciio connect - * point using the ioerror widgetdev field. - * - * This function is called by the - * specific PCI provider, after it has figured - * out where on the PCI bus (including which slot, - * if it can tell) the error came from. - */ -/*ARGSUSED */ -int -pciio_error_handler( - devfs_handle_t pciio_vhdl, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - pciio_info_t pciio_info; - devfs_handle_t pconn_vhdl; -#if USRPCI - devfs_handle_t usrpci_v; -#endif - pciio_slot_t slot; - - int retval; -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - error_state_t e_state; -#endif - -#if DEBUG && ERROR_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("%v: pciio_error_handler\n", pciio_vhdl); -#else - printk("0x%x: pciio_error_handler\n", pciio_vhdl); -#endif -#endif - -#if defined(SUPPORT_PRINTING_V_FORMAT) - IOERR_PRINTF(printk("%v: PCI Bus Error: Error code: %d Error mode: %d\n", - pciio_vhdl, error_code, mode)); -#else - IOERR_PRINTF(printk("0x%x: PCI Bus Error: Error code: %d Error mode: %d\n", - pciio_vhdl, error_code, mode)); -#endif - - /* If there is an error handler sitting on - * the "no-slot" connection point, give it - * first crack at the error. NOTE: it is - * quite possible that this function may - * do further refining of the ioerror. - */ - pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE); - if (pciio_info && pciio_info->c_efunc) { - pconn_vhdl = pciio_info_dev_get(pciio_info); -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - e_state = error_state_get(pciio_vhdl); - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - if (error_state_set(pconn_vhdl,e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif - retval = pciio_info->c_efunc - (pciio_info->c_einfo, error_code, mode, ioerror); - if (retval != IOERROR_UNHANDLED) - return retval; - } - - /* Is the error associated with a particular slot? - */ - if (IOERROR_FIELDVALID(ioerror, widgetdev)) { - /* - * NOTE : - * widgetdev is a 4byte value encoded as slot in the higher order - * 2 bytes and function in the lower order 2 bytes. - */ -#ifdef LATER - slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioerror, widgetdev)); -#else - slot = 0; -#endif - - /* If this slot has an error handler, - * deliver the error to it. - */ - pciio_info = pciio_cardinfo_get(pciio_vhdl, slot); - if (pciio_info != NULL) { - if (pciio_info->c_efunc != NULL) { - - pconn_vhdl = pciio_info_dev_get(pciio_info); -#if defined(CONFIG_SGI_IO_ERROR_HANDLING) - e_state = error_state_get(pciio_vhdl); - - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - - - if (error_state_set(pconn_vhdl,e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif - retval = pciio_info->c_efunc - (pciio_info->c_einfo, error_code, mode, ioerror); - if (retval != IOERROR_UNHANDLED) - return retval; - } - -#if USRPCI - /* If the USRPCI driver is available and - * knows about this connection point, - * deliver the error to it. - * - * OK to use pconn_vhdl here, even though we - * have already UNREF'd it, since we know that - * it is not going away. - */ - pconn_vhdl = pciio_info_dev_get(pciio_info); - if (GRAPH_SUCCESS == - hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) { - retval = usrpci_error_handler - (usrpci_v, error_code, IOERROR_GETVALUE(ioerror, busaddr)); - hwgraph_vertex_unref(usrpci_v); - if (retval != IOERROR_UNHANDLED) { - /* - * This unref is not needed. If this code is called often enough, - * the system will crash, due to vertex reference count reaching 0, - * causing vertex to be unallocated. -jeremy - * hwgraph_vertex_unref(pconn_vhdl); - */ - return retval; - } - } -#endif - } - } - - return (mode == MODE_DEVPROBE) - ? IOERROR_HANDLED /* probes are OK */ - : IOERROR_UNHANDLED; /* otherwise, foo! */ -} - -int -pciio_error_devenable(devfs_handle_t pconn_vhdl, int error_code) -{ - return DEV_FUNC(pconn_vhdl, error_devenable) - (pconn_vhdl, error_code); - /* no cleanup specific to this layer. */ -} - /* ===================================================================== * CONFIGURATION MANAGEMENT */ @@ -856,12 +678,12 @@ #if DEBUG #if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_ALERT("%v: pciio_endian_set is going away.\n" + printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev); #else - PRINT_ALERT("0x%x: pciio_endian_set is going away.\n" + printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", dev); @@ -944,14 +766,6 @@ /* ===================================================================== * GENERIC PCI SUPPORT FUNCTIONS */ -pciio_slot_t -pciio_error_extract(devfs_handle_t dev, - pciio_space_t *space, - iopaddr_t *offset) -{ - ASSERT(dev != NODEV); - return DEV_FUNC(dev,error_extract)(dev,space,offset); -} /* * Issue a hardware reset to a card. @@ -1054,14 +868,9 @@ } #endif /* DEBUG_PCIIO */ -#ifdef BRINGUP if ((pciio_info != NULL) && (pciio_info->c_fingerprint != pciio_info_fingerprint) && (pciio_info->c_fingerprint != NULL)) { -#else - if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint)) { -#endif /* BRINGUP */ return((pciio_info_t)-1); /* Should panic .. */ } @@ -1388,7 +1197,7 @@ pciio_device_id_t device_id) { if (!pciio_info) - NEW(pciio_info); + GET_NEW(pciio_info); ASSERT(pciio_info != NULL); pciio_info->c_slot = slot; @@ -1420,6 +1229,7 @@ { char name[32]; devfs_handle_t pconn; + int device_master_set(devfs_handle_t, devfs_handle_t); pciio_slot_func_to_name(name, pciio_info->c_slot, @@ -1431,16 +1241,14 @@ pciio_info->c_vertex = pconn; pciio_info_set(pconn, pciio_info); -#ifdef BRINGUP +#ifdef DEBUG_PCIIO { int pos; char dname[256]; pos = devfs_generate_path(pconn, dname, 256); -#ifdef DEBUG_PCIIO printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); -#endif } -#endif /* BRINGUP */ +#endif /* DEBUG_PCIIO */ /* * create link to our pci provider @@ -1520,7 +1328,6 @@ pciio_info_t pciio_info; pciio_vendor_id_t vendor_id; pciio_device_id_t device_id; - int pciba_attach(devfs_handle_t); pciio_device_inventory_add(pconn); @@ -1536,11 +1343,6 @@ */ ASSERT(pciio_registry != NULL); - /* - * Since pciba is not called from cdl routines .. call it here. - */ - pciba_attach(pconn); - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); } @@ -1625,3 +1427,85 @@ { return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); } + +/* + * These are complementary Linux interfaces that takes in a pci_dev * as the + * first arguement instead of devfs_handle_t. + */ +iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); +pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); +void snia_pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +void snia_pciio_dmamap_done(pciio_dmamap_t); +pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, + pciio_endian_t desired_end); + +#include +EXPORT_SYMBOL(snia_pciio_dmatrans_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_alloc); +EXPORT_SYMBOL(snia_pciio_dmamap_free); +EXPORT_SYMBOL(snia_pciio_dmamap_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_done); +EXPORT_SYMBOL(snia_pciio_endian_set); + +pciio_endian_t +snia_pciio_endian_set(struct pci_dev *pci_dev, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return DEV_FUNC(dev, endian_set) + (dev, device_end, desired_end); +} + +iopaddr_t +snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + +pciio_dmamap_t +snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + +void +snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_free) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) + (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); +} + +void +snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_done) + (CAST_DMAMAP(pciio_dmamap)); +} + diff -urN linux-2.4.18/arch/ia64/sn/io/sgi_if.c linux-2.4.19-pre5/arch/ia64/sn/io/sgi_if.c --- linux-2.4.18/arch/ia64/sn/io/sgi_if.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sgi_if.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include @@ -22,7 +21,7 @@ #include void * -kmem_zalloc(size_t size, int flag) +snia_kmem_zalloc(size_t size, int flag) { void *ptr = kmalloc(size, GFP_KERNEL); BZERO(ptr, size); diff -urN linux-2.4.18/arch/ia64/sn/io/sgi_io_init.c linux-2.4.19-pre5/arch/ia64/sn/io/sgi_io_init.c --- linux-2.4.18/arch/ia64/sn/io/sgi_io_init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sgi_io_init.c Sat Mar 30 22:55:26 2002 @@ -4,26 +4,24 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include #include #include #include -#include +#include +#include #include #include -#include +#include #include extern void mlreset(int ); extern int init_hcl(void); extern void klgraph_hack_init(void); -extern void per_hub_init(cnodeid_t); extern void hubspc_init(void); -extern void pciba_init(void); extern void pciio_init(void); extern void pcibr_init(void); extern void xtalk_init(void); @@ -33,23 +31,21 @@ extern void usrpci_init(void); extern void ioc3_init(void); extern void initialize_io(void); -extern void init_platform_nodepda(nodepda_t *, cnodeid_t ); +#if defined(CONFIG_IA64_SGI_SN1) extern void intr_clear_all(nasid_t); +#endif extern void klhwg_add_all_modules(devfs_handle_t); extern void klhwg_add_all_nodes(devfs_handle_t); void sn_mp_setup(void); extern devfs_handle_t hwgraph_root; extern void io_module_init(void); -extern cnodeid_t nasid_to_compact_node[]; extern void pci_bus_cvlink_init(void); extern void temp_hack(void); -extern void init_platform_pda(cpuid_t cpu); extern int pci_bus_to_hcl_cvlink(void); -extern synergy_da_t *Synergy_da_indr[]; -#define DEBUG_IO_INIT +/* #define DEBUG_IO_INIT 1 */ #ifdef DEBUG_IO_INIT #define DBG(x...) printk(x) #else @@ -57,20 +53,73 @@ #endif /* DEBUG_IO_INIT */ /* - * kern/ml/csu.s calls mlsetup - * mlsetup calls mlreset(master) - kern/os/startup.c - * j main - * - - * SN/slave.s start_slave_loop calls slave_entry - * SN/slave.s slave_entry calls slave_loop - * SN/slave.s slave_loop calls bootstrap - * bootstrap in SN1/SN1asm.s calls cboot - * cboot calls mlreset(slave) - ml/SN/mp.c + * per_hub_init * - * sgi_io_infrastructure_init() gets called right before pci_init() - * in Linux mainline. This routine actually mirrors the IO Infrastructure - * call sequence in IRIX, ofcourse, nicely modified for Linux. + * This code is executed once for each Hub chip. + */ +static void +per_hub_init(cnodeid_t cnode) +{ + nasid_t nasid; + nodepda_t *npdap; + ii_icmr_u_t ii_icmr; + ii_ibcr_u_t ii_ibcr; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + ASSERT(nasid != INVALID_NASID); + ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); + + npdap = NODEPDA(cnode); + +#if defined(CONFIG_IA64_SGI_SN1) + /* initialize per-node synergy perf instrumentation */ + npdap->synergy_perf_enabled = 0; /* off by default */ + npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; + npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; + npdap->synergy_inactive_intervals = 0; + npdap->synergy_active_intervals = 0; + npdap->synergy_perf_data = NULL; + npdap->synergy_perf_first = NULL; +#endif /* CONFIG_IA64_SGI_SN1 */ + + + /* + * Set the total number of CRBs that can be used. + */ + ii_icmr.ii_icmr_regval= 0x0; + ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; + REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); + + /* + * Set the number of CRBs that both of the BTEs combined + * can use minus 1. + */ + ii_ibcr.ii_ibcr_regval= 0x0; + ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; + REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); + + /* + * Set CRB timeout to be 10ms. + */ + REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); + REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); + + +#if defined(CONFIG_IA64_SGI_SN1) + /* Reserve all of the hardwired interrupt levels. */ + intr_reserve_hardwired(cnode); +#endif + + /* Initialize error interrupts for this hub. */ + hub_error_init(cnode); +} + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). * * It is very IMPORTANT that this call is only made by the Master CPU! * @@ -80,7 +129,6 @@ sgi_master_io_infr_init(void) { int cnode; - extern int maxnodes; /* * Do any early init stuff .. einit_tbl[] etc. @@ -88,17 +136,49 @@ DBG("--> sgi_master_io_infr_init: calling init_hcl().\n"); init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ +#ifdef Colin + +printk("Testing out Xbridge Access .. if it hangs Xbridge is not init yet.\n"); +printk(" Reading Xbridge WID at address 0xc00000080f000000 0x%p\n", (* (volatile uint32_t *)(0xc00000080f000000))); + +printk("Testing out PCI Address Space Accesses\n"); +printk(" Testing PCI Config Read Byte: address 0xc00000080f020000 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020000))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020001 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020001))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020002 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020002))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020003 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020003))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020004))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020005 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020005))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020006 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020006))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020007 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020007))); + +printk(" Testing PCI Config Word: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020004))); + +printk(" Testing PCI Config Word: address 0xc00000080f020008 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020008))); + +#endif + /* * initialize the Linux PCI to xwidget vertexes .. */ DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n"); pci_bus_cvlink_init(); +#ifdef BRINGUP +#ifdef CONFIG_IA64_SGI_SN1 /* * Hack to provide statically initialzed klgraph entries. */ DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); klgraph_hack_init(); +#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* BRINGUP */ /* * This is the Master CPU. Emulate mlsetup and main.c in Irix. @@ -117,7 +197,7 @@ sn_mp_setup(); DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - for (cnode = 0; cnode < maxnodes; cnode++) { + for (cnode = 0; cnode < numnodes; cnode++) { per_hub_init(cnode); } @@ -133,9 +213,6 @@ DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n"); hubspc_init(); - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); - pciba_init(); - DBG("--> sgi_master_io_infr_init: calling pciio_init()\n"); pciio_init(); @@ -172,6 +249,11 @@ DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n"); pci_bus_to_hcl_cvlink(); +#ifdef CONFIG_PCIBA + DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); + pciba_init(); +#endif + DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n"); } @@ -199,76 +281,15 @@ sn_mp_setup(void) { cnodeid_t cnode; - extern int maxnodes; cpuid_t cpu; - DBG("sn_mp_setup: Entered.\n"); - /* - * NODEPDA(x) Macro depends on nodepda - * subnodepda is also statically set to calias space which we - * do not currently support yet .. just a hack for now. - */ -#ifdef NUMA_BASE - maxnodes = numnodes; - DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); - printk("sn_mp_setup(): Allocating backing store for *Nodepdaindr[%2d] \n", - maxnodes); - - /* - * Initialize Nodpdaindr and per-node nodepdaindr array - */ - *Nodepdaindr = (nodepda_t *) kmalloc(sizeof(nodepda_t *)*numnodes, GFP_KERNEL); - for (cnode=0; cnodepernode_pdaindr = Nodepdaindr; - subnodepda = &Nodepdaindr[cnode]->snpda[cnode]; - } - nodepda = Nodepdaindr[0]; -#else - Nodepdaindr = (nodepda_t *) kmalloc(sizeof(struct nodepda_s), GFP_KERNEL); - nodepda = Nodepdaindr[0]; - subnodepda = &Nodepdaindr[0]->snpda[0]; - -#endif /* NUMA_BASE */ - - /* - * Before we let the other processors run, set up the platform specific - * stuff in the nodepda. - * - * ???? maxnodes set in mlreset .. who sets it now ???? - * ???? cpu_node_probe() called in mlreset to set up the following: - * compact_to_nasid_node[] - cnode id gives nasid - * nasid_to_compact_node[] - nasid gives cnode id - * - * do_cpumask() sets the following: - * cpuid_to_compact_node[] - cpuid gives cnode id - * - * nasid comes from gdap->g_nasidtable[] - * ml/SN/promif.c - */ - -#ifdef CONFIG_IA64_SGI_SN1 for (cpu = 0; cpu < smp_num_cpus; cpu++) { /* Skip holes in CPU space */ if (cpu_enabled(cpu)) { init_platform_pda(cpu); } } -#endif - for (cnode = 0; cnode < maxnodes; cnode++) { - /* - * Set up platform-dependent nodepda fields. - * The following routine actually sets up the hubinfo struct - * in nodepda. - */ - DBG("sn_mp_io_setup: calling init_platform_nodepda(%2d)\n",cnode); - init_platform_nodepda(Nodepdaindr[cnode], cnode); - } + /* * Initialize platform-dependent vertices in the hwgraph: * module @@ -290,24 +311,26 @@ klhwg_add_all_nodes(hwgraph_root); - for (cnode = 0; cnode < maxnodes; cnode++) { + for (cnode = 0; cnode < numnodes; cnode++) { /* * This routine clears the Hub's Interrupt registers. */ -#ifdef CONFIG_IA64_SGI_SN1 /* * We need to move this intr_clear_all() routine * from SN/intr.c to a more appropriate file. * Talk to Al Mayer. */ +#if defined(CONFIG_IA64_SGI_SN1) intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); +#endif /* now init the hub */ // per_hub_init(cnode); -#endif + } -#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) +#if defined(CONFIG_IA64_SGI_SN1) synergy_perf_init(); -#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ +#endif + } diff -urN linux-2.4.18/arch/ia64/sn/io/sgi_io_sim.c linux-2.4.19-pre5/arch/ia64/sn/io/sgi_io_sim.c --- linux-2.4.18/arch/ia64/sn/io/sgi_io_sim.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sgi_io_sim.c Sat Mar 30 22:55:26 2002 @@ -4,31 +4,28 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ +#include #include #include -#include +#include +#include +#include #include #include #include #include -#include cpuid_t master_procid = 0; -int maxnodes; char arg_maxnodes[4]; -nodepda_t *Nodepdaindr[MAX_COMPACT_NODES]; -nodepda_t *nodepda; -subnode_pda_t *subnodepda; - -synergy_da_t *Synergy_da_indr[MAX_COMPACT_NODES * 2]; - extern void init_all_devices(void); +#if defined(CONFIG_IA64_SGI_SN1) +synergy_da_t *Synergy_da_indr[MAX_COMPACT_NODES * 2]; +#endif /* * Return non-zero if the given variable was specified @@ -73,27 +70,23 @@ * Routines provided by ml/SN/promif.c. */ static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; -nasid_t console_nasid; +nasid_t console_nasid = (nasid_t)-1; static char console_wid; static char console_pcislot; void set_master_bridge_base(void) { - - console_nasid = KL_CONFIG_CH_CONS_INFO(master_nasid)->nasid; console_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base); console_pcislot = KL_CONFIG_CH_CONS_INFO(master_nasid)->npci; - master_bridge_base = (__psunsigned_t)NODE_SWIN_BASE(console_nasid, - console_wid); - FIXME("WARNING: set_master_bridge_base: NON NASID 0 DOES NOT WORK\n"); + master_bridge_base = (__psunsigned_t)NODE_SWIN_BASE(console_nasid, console_wid); + // FIXME("WARNING: set_master_bridge_base: NON NASID 0 DOES NOT WORK\n"); } int check_nasid_equiv(nasid_t nasida, nasid_t nasidb) { - if ((nasida == nasidb) || - (nasida == NODEPDA(NASID_TO_COMPACT_NODEID(nasidb))->xbow_peer)) + if ((nasida == nasidb) || (nasida == NODEPDA(NASID_TO_COMPACT_NODEID(nasidb))->xbow_peer)) return 1; else return 0; diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/hub_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/hub_intr.c --- linux-2.4.18/arch/ia64/sn/io/sn1/hub_intr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/hub_intr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,307 @@ +/* $Id: hub_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern xtalk_provider_t hub_provider; + +/* ARGSUSED */ +void +hub_intr_init(devfs_handle_t hubv) +{ +} + +/* + * hub_device_desc_update + * Update the passed in device descriptor with the actual the + * target cpu number and interrupt priority level. + * NOTE : These might be the same as the ones passed in thru + * the descriptor. + */ +static void +hub_device_desc_update(device_desc_t dev_desc, + ilvl_t intr_swlevel, + cpuid_t cpu) +{ +} + +int allocate_my_bit = INTRCONNECT_ANYBIT; + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +static hub_intr_t +do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev, /* owner of this interrupt, if known */ + int uncond_nothread) /* unconditionally non-threaded */ +{ + cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ + int cpupicked = 0; + int bit; /* interrupt vector */ + /*REFERENCED*/ + int intr_resflags = 0; + hub_intr_t intr_hdl; + cnodeid_t nodeid; /* node to receive interrupt */ + /*REFERENCED*/ + nasid_t nasid; /* nasid to receive interrupt */ + struct xtalk_intr_s *xtalk_info; + iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */ + xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */ + char *intr_name = NULL; + ilvl_t intr_swlevel = (ilvl_t)0; + extern int default_intr_pri; + extern void synergy_intr_alloc(int, int); + + + if (dev_desc) { + if (dev_desc->flags & D_INTR_ISERR) { + intr_resflags = II_ERRORINT; + } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { + intr_resflags = II_THREADED; + } else { + /* Neither an error nor a thread. */ + intr_resflags = 0; + } + } else { + intr_swlevel = default_intr_pri; + if (!uncond_nothread) + intr_resflags = II_THREADED; + } + + /* XXX - Need to determine if the interrupt should be threaded. */ + + /* If the cpu has not been picked already then choose a candidate + * interrupt target and reserve the interrupt bit + */ + if (!cpupicked) { + cpu = intr_heuristic(dev,dev_desc,allocate_my_bit, + intr_resflags,owner_dev, + intr_name,&bit); + } + + /* At this point we SHOULD have a valid cpu */ + if (cpu == CPU_NONE) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "%v hub_intr_alloc could not allocate interrupt\n", + owner_dev); +#else + printk(KERN_WARNING "%p hub_intr_alloc could not allocate interrupt\n", + (void *)owner_dev); +#endif + return(0); + + } + + /* If the cpu has been picked already (due to the bridge data + * corruption bug) then try to reserve an interrupt bit . + */ + if (cpupicked) { + bit = intr_reserve_level(cpu, allocate_my_bit, + intr_resflags, + owner_dev, intr_name); + if (bit < 0) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " + " %d and dev %v\n", + cpu,owner_dev); +#else + printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " + " %d and dev %p\n", + (int)cpu, (void *)owner_dev); +#endif + + return(0); + } + } + + nodeid = cpuid_to_cnodeid(cpu); + nasid = cpuid_to_nasid(cpu); + xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu))); + + /* + * Allocate an interrupt handle, and fill it in. There are two + * pieces to an interrupt handle: the piece needed by generic + * xtalk code which is used by crosstalk device drivers, and + * the piece needed by low-level IP27 hardware code. + */ + intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid); + ASSERT_ALWAYS(intr_hdl); + + /* + * Fill in xtalk information for generic xtalk interfaces that + * operate on xtalk_intr_hdl's. + */ + xtalk_info = &intr_hdl->i_xtalk_info; + xtalk_info->xi_dev = dev; + xtalk_info->xi_vector = bit; + xtalk_info->xi_addr = xtalk_addr; + + /* + * Regardless of which CPU we ultimately interrupt, a given crosstalk + * widget always handles interrupts (and PIO and DMA) through its + * designated "master" crosstalk provider. + */ + xwidget_info = xwidget_info_get(dev); + if (xwidget_info) + xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); + + /* Fill in low level hub information for hub_* interrupt interface */ + intr_hdl->i_swlevel = intr_swlevel; + intr_hdl->i_cpuid = cpu; + intr_hdl->i_bit = bit; + intr_hdl->i_flags = HUB_INTR_IS_ALLOCED; + + /* Store the actual interrupt priority level & interrupt target + * cpu back in the device descriptor. + */ + hub_device_desc_update(dev_desc, intr_swlevel, cpu); + synergy_intr_alloc((int)bit, (int)cpu); + return(intr_hdl); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Uncondtionally request non-threaded, regardless of what the device + * descriptor might say. + * Returns a hub interrupt handle on success, or 0 on failure. + */ +hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt, if known */ +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); +} + +/* + * Free resources consumed by intr_alloc. + */ +void +hub_intr_free(hub_intr_t intr_hdl) +{ + cpuid_t cpu = intr_hdl->i_cpuid; + int bit = intr_hdl->i_bit; + xtalk_intr_t xtalk_info; + + if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { + /* Setting the following fields in the xtalk interrupt info + * clears the interrupt target register in the xtalk user + */ + xtalk_info = &intr_hdl->i_xtalk_info; + xtalk_info->xi_dev = NODEV; + xtalk_info->xi_vector = 0; + xtalk_info->xi_addr = 0; + hub_intr_disconnect(intr_hdl); + } + + if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) + kfree(intr_hdl); + + intr_unreserve_level(cpu, bit); +} + + +/* + * Associate resources allocated with a previous hub_intr_alloc call with the + * described handler, arg, name, etc. + */ +/*ARGSUSED*/ +int +hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */ + xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ + void *setfunc_arg) /* arg to setfunc */ +{ + int rv; + cpuid_t cpu = intr_hdl->i_cpuid; + int bit = intr_hdl->i_bit; + extern int synergy_intr_connect(int, int); + + ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); + + rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, NULL); + if (rv < 0) + return(rv); + + intr_hdl->i_xtalk_info.xi_setfunc = setfunc; + intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; + + if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); + + intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; + return(synergy_intr_connect((int)bit, (int)cpu)); +} + + +/* + * Disassociate handler with the specified interrupt. + */ +void +hub_intr_disconnect(hub_intr_t intr_hdl) +{ + /*REFERENCED*/ + int rv; + cpuid_t cpu = intr_hdl->i_cpuid; + int bit = intr_hdl->i_bit; + xtalk_intr_setfunc_t setfunc; + + setfunc = intr_hdl->i_xtalk_info.xi_setfunc; + + /* TBD: send disconnected interrupts somewhere harmless */ + if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); + + rv = intr_disconnect_level(cpu, bit); + ASSERT(rv == 0); + intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; +} + + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +hub_intr_cpu_get(hub_intr_t intr_hdl) +{ + cpuid_t cpuid = intr_hdl->i_cpuid; + ASSERT(cpuid != CPU_NONE); + + return(cpuid_to_vertex(cpuid)); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/hubcounters.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/hubcounters.c --- linux-2.4.18/arch/ia64/sn/io/sn1/hubcounters.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/hubcounters.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,283 @@ +/* $Id: hubcounters.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. + * All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void hubni_error_handler(char *, int); /* huberror.c */ + +static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +struct file_operations hub_mon_fops = { + ioctl: hubstats_ioctl, +}; + +#define HUB_CAPTURE_TICKS (2 * HZ) + +#define HUB_ERR_THRESH 500 +#define USEC_PER_SEC 1000000 +#define NSEC_PER_SEC USEC_PER_SEC*1000 + +volatile int hub_print_usecs = 600 * USEC_PER_SEC; + +/* Return success if the hub's crosstalk link is working */ +int +hub_xtalk_link_up(nasid_t nasid) +{ + hubreg_t llp_csr_reg; + + /* Read the IO LLP control status register */ + llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); + + /* Check if the xtalk link is working */ + if (llp_csr_reg & IIO_LLP_CSR_IS_UP) + return(1); + + return(0); + + +} + +static char *error_flag_to_type(unsigned char error_flag) +{ + switch(error_flag) { + case 0x1: return ("NI retries"); + case 0x2: return ("NI SN errors"); + case 0x4: return ("NI CB errors"); + case 0x8: return ("II CB errors"); + case 0x10: return ("II SN errors"); + default: return ("Errors"); + } +} + +int +print_hub_error(hubstat_t *hsp, hubreg_t reg, + int64_t delta, unsigned char error_flag) +{ + int64_t rate; + + reg *= hsp->hs_per_minute; /* Convert to minutes */ + rate = reg / delta; + + if (rate > HUB_ERR_THRESH) { + + if(hsp->hs_maint & error_flag) + { + printk( "Excessive %s (%ld/min) on %s", + error_flag_to_type(error_flag), rate, hsp->hs_name); + } + else + { + hsp->hs_maint |= error_flag; + printk( "Excessive %s (%ld/min) on %s", + error_flag_to_type(error_flag), rate, hsp->hs_name); + } + return 1; + } else { + return 0; + } +} + + +int +check_hub_error_rates(hubstat_t *hsp) +{ + int64_t delta = hsp->hs_timestamp - hsp->hs_timebase; + int printed = 0; + + printed += print_hub_error(hsp, hsp->hs_ni_retry_errors, + delta, 0x1); + +#if 0 + printed += print_hub_error(hsp, hsp->hs_ni_sn_errors, + delta, 0x2); +#endif + + printed += print_hub_error(hsp, hsp->hs_ni_cb_errors, + delta, 0x4); + + + /* If the hub's xtalk link is not working there is + * no need to print the "Excessive..." warning + * messages + */ + if (!hub_xtalk_link_up(hsp->hs_nasid)) + return(printed); + + + printed += print_hub_error(hsp, hsp->hs_ii_cb_errors, + delta, 0x8); + + printed += print_hub_error(hsp, hsp->hs_ii_sn_errors, + delta, 0x10); + + return printed; +} + + +void +capture_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) +{ + nasid_t nasid; + hubstat_t *hsp = &(npda->hubstats); + hubreg_t port_error; + ii_illr_u_t illr; + int count; + int overflow = 0; + + /* + * If our link wasn't up at boot time, don't worry about error rates. + */ + if (!(hsp->hs_ni_port_status & NPS_LINKUP_MASK)) { + printk("capture_hub_stats: cnode=%d hs_ni_port_status=0x%016lx : link is not up\n", + cnodeid, hsp->hs_ni_port_status); + return; + } + + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + + hsp->hs_timestamp = GET_RTC_COUNTER(); + + port_error = REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); + count = ((port_error & NPE_RETRYCOUNT_MASK) >> NPE_RETRYCOUNT_SHFT); + hsp->hs_ni_retry_errors += count; + if (count == NPE_COUNT_MAX) + overflow = 1; + count = ((port_error & NPE_SNERRCOUNT_MASK) >> NPE_SNERRCOUNT_SHFT); + hsp->hs_ni_sn_errors += count; + if (count == NPE_COUNT_MAX) + overflow = 1; + count = ((port_error & NPE_CBERRCOUNT_MASK) >> NPE_CBERRCOUNT_SHFT); + hsp->hs_ni_cb_errors += count; + if (overflow || count == NPE_COUNT_MAX) + hsp->hs_ni_overflows++; + + if (port_error & NPE_FATAL_ERRORS) { +#ifdef ajm + hubni_error_handler("capture_hub_stats", 1); +#else + printk("Error: hubni_error_handler in capture_hub_stats"); +#endif + } + + illr.ii_illr_regval = REMOTE_HUB_L(nasid, IIO_LLP_LOG); + REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); + + hsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt; + hsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt; + if ((illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) || + (illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX)) + hsp->hs_ii_overflows++; + + if (hsp->hs_print) { + if (check_hub_error_rates(hsp)) { + hsp->hs_last_print = GET_RTC_COUNTER(); + hsp->hs_print = 0; + } + } else { + if ((GET_RTC_COUNTER() - + hsp->hs_last_print) > hub_print_usecs) + hsp->hs_print = 1; + } + + npda->hubticks = HUB_CAPTURE_TICKS; +} + + +void +init_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) +{ + hubstat_t *hsp = &(npda->hubstats); + nasid_t nasid = cnodeid_to_nasid(cnodeid); + bzero(&(npda->hubstats), sizeof(hubstat_t)); + + hsp->hs_version = HUBSTAT_VERSION; + hsp->hs_cnode = cnodeid; + hsp->hs_nasid = nasid; + hsp->hs_timebase = GET_RTC_COUNTER(); + hsp->hs_ni_port_status = REMOTE_HUB_L(nasid, NI_PORT_STATUS); + + /* Clear the II error counts. */ + REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); + + /* Clear the NI counts. */ + REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); + + hsp->hs_per_minute = (long long)RTC_CYCLES_PER_SEC * 60LL; + + npda->hubticks = HUB_CAPTURE_TICKS; + + /* XX should use kmem_alloc_node */ + hsp->hs_name = (char *)kmalloc(MAX_HUB_PATH, GFP_KERNEL); + ASSERT_ALWAYS(hsp->hs_name); + + sprintf(hsp->hs_name, "/dev/hw/" EDGE_LBL_MODULE "/%03d/" + EDGE_LBL_NODE "/" EDGE_LBL_HUB, + npda->module_id); + + hsp->hs_last_print = 0; + hsp->hs_print = 1; + + hub_print_usecs = hub_print_usecs; + +#if 0 + printk("init_hub_stats: cnode=%d nasid=%d hs_version=%d hs_ni_port_status=0x%016lx\n", + cnodeid, nasid, hsp->hs_version, hsp->hs_ni_port_status); +#endif +} + +static int +hubstats_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + cnodeid_t cnode; + nodepda_t *npdap; + uint64_t longarg; + devfs_handle_t d; + + if ((d = devfs_get_handle_from_inode(inode)) == NULL) + return -ENODEV; + cnode = (cnodeid_t)hwgraph_fastinfo_get(d); + npdap = NODEPDA(cnode); + + if (npdap->hubstats.hs_version != HUBSTAT_VERSION) { + init_hub_stats(cnode, npdap); + } + + switch (cmd) { + case SNDRV_GET_INFOSIZE: + longarg = sizeof(hubstat_t); + if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { + return -EFAULT; + } + break; + + case SNDRV_GET_HUBINFO: + /* refresh npda->hubstats */ + capture_hub_stats(cnode, npdap); + if (copy_to_user((void *)arg, &npdap->hubstats, sizeof(hubstat_t))) { + return -EFAULT; + } + break; + + default: + return -EINVAL; + } + + return 0; +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/huberror.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/huberror.c --- linux-2.4.18/arch/ia64/sn/io/sn1/huberror.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/huberror.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,228 @@ +/* $Id: huberror.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void hubni_eint_init(cnodeid_t cnode); +extern void hubii_eint_init(cnodeid_t cnode); +extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + +extern int maxcpus; + +#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ + + +void +hub_error_clear(nasid_t nasid) +{ + int i; + hubreg_t idsr; + int sn; + + for(sn=0; snh_cnodeid == cnode); + + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. + * Just disable LLP, and don't connect any interrupts. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + return; + } + /* Select a possible interrupt target where there is a free interrupt + * bit and also reserve the interrupt bit for this IO error interrupt + */ + intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, + "HUB IO error interrupt",&bit); + if (intr_cpu == CPU_NONE) { + printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); + return; + } + + rv = intr_connect_level(intr_cpu, bit, 0, NULL); + synergy_intr_connect(bit, intr_cpu); + request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); + ASSERT_ALWAYS(rv >= 0); + hubio_eint.ii_iidsr_regval = 0; + hubio_eint.ii_iidsr_fld_s.i_enable = 1; + hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ + hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); + hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); + +} + +void +hubni_eint_init(cnodeid_t cnode) +{ + int intr_bit; + cpuid_t targ; + + + if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) + return; + + /* The prom chooses which cpu gets these interrupts, but we + * don't know which one it chose. We will register all of the + * cpus to be sure. This only costs us an irqaction per cpu. + */ + for (; targ < CPUS_PER_NODE; targ++) { + if (!cpu_enabled(targ) ) continue; + /* connect the INTEND1 bits. */ + for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { + intr_connect_level(targ, intr_bit, II_ERRORINT, NULL); + } + request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, "SN hub error", NULL); + /* synergy masks are initialized in the prom to enable all interrupts. */ + /* We'll just leave them that way, here, for these interrupts. */ + } +} + + +/*ARGSUSED*/ +void +hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) +{ + + panic("Hubii interrupt\n"); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/ip37.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/ip37.c --- linux-2.4.18/arch/ia64/sn/io/sn1/ip37.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/ip37.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,47 @@ +/* + * + * 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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * ip37.c + * Support for IP35/IP37 machines + */ + +#include + +#include +#include +#include +#include /* for bridge_t */ + + +xwidgetnum_t +hub_widget_id(nasid_t nasid) +{ + hubii_wcr_t ii_wcr; /* the control status register */ + + ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); + + return ii_wcr.wcr_fields_s.wcr_widget_id; +} + +int +is_fine_dirmode(void) +{ + return (((LOCAL_HUB_L(LB_REV_ID) & LRI_SYSTEM_SIZE_MASK) + >> LRI_SYSTEM_SIZE_SHFT) == SYSTEM_SIZE_SMALL); + +} + + +void +ni_reset_port(void) +{ + LOCAL_HUB_S(NI_RESET_ENABLE, NRE_RESETOK); + LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/mem_refcnt.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/mem_refcnt.c --- linux-2.4.18/arch/ia64/sn/io/sn1/mem_refcnt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/mem_refcnt.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,221 @@ +/* $Id: mem_refcnt.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// From numa_hw.h + +#define MIGR_COUNTER_MAX_GET(nodeid) \ + (NODEPDA_MCD((nodeid))->migr_system_kparms.migr_threshold_reference) +/* + * Get the Absolute Theshold + */ +#define MIGR_THRESHOLD_ABS_GET(nodeid) ( \ + MD_MIG_VALUE_THRESH_GET(COMPACT_TO_NASID_NODEID(nodeid))) +/* + * Get the current Differential Threshold + */ +#define MIGR_THRESHOLD_DIFF_GET(nodeid) \ + (NODEPDA_MCD(nodeid)->migr_as_kparms.migr_base_threshold) + +#define NUM_OF_HW_PAGES_PER_SW_PAGE() (NBPP / MD_PAGE_SIZE) + +// #include "migr_control.h" + +int +mem_refcnt_attach(devfs_handle_t hub) +{ +#ifndef CONFIG_IA64_SGI_SN + devfs_handle_t refcnt_dev; + + hwgraph_char_device_add(hub, + "refcnt", + "hubspc_", + &refcnt_dev); + device_info_set(refcnt_dev, (void*)(ulong)HUBSPC_REFCOUNTERS); +#endif + + return (0); +} + + +/*ARGSUSED*/ +int +mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) +{ + cnodeid_t node; + + node = master_node_get(*devp); + + ASSERT( (node >= 0) && (node < numnodes) ); + + if (NODEPDA(node)->migr_refcnt_counterbuffer == NULL) { + return (ENODEV); + } + + ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); + ASSERT( NODEPDA(node)->migr_refcnt_cbsize != (size_t)0 ); + + return (0); +} + +/*ARGSUSED*/ +int +mem_refcnt_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) +{ + return 0; +} + +/*ARGSUSED*/ +int +mem_refcnt_mmap(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) +{ + cnodeid_t node; + int errcode; + char* buffer; + size_t blen; + + node = master_node_get(dev); + + ASSERT( (node >= 0) && (node < numnodes) ); + + ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); + ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); + ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); + + /* + * XXXX deal with prot's somewhere around here.... + */ + + buffer = NODEPDA(node)->migr_refcnt_counterbuffer; + blen = NODEPDA(node)->migr_refcnt_cbsize; + + /* + * Force offset to be a multiple of sizeof(refcnt_t) + * We round up. + */ + + off = (((off - 1)/sizeof(refcnt_t)) + 1) * sizeof(refcnt_t); + + if ( ((buffer + blen) - (buffer + off + len)) < 0 ) { + return (EPERM); + } + + errcode = v_mapphys(vt, + buffer + off, + len); + + return errcode; +} + +/*ARGSUSED*/ +int +mem_refcnt_unmap(devfs_handle_t dev, vhandl_t *vt) +{ + return 0; +} + +/* ARGSUSED */ +int +mem_refcnt_ioctl(devfs_handle_t dev, + int cmd, + void *arg, + int mode, + cred_t *cred_p, + int *rvalp) +{ + cnodeid_t node; + int errcode; + extern int numnodes; + + node = master_node_get(dev); + + ASSERT( (node >= 0) && (node < numnodes) ); + + ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); + ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); + ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); + + errcode = 0; + + switch (cmd) { + case RCB_INFO_GET: + { + rcb_info_t rcb; + + rcb.rcb_len = NODEPDA(node)->migr_refcnt_cbsize; + + rcb.rcb_sw_sets = NODEPDA(node)->migr_refcnt_numsets; + rcb.rcb_sw_counters_per_set = numnodes; + rcb.rcb_sw_counter_size = sizeof(refcnt_t); + + rcb.rcb_base_pages = NODEPDA(node)->migr_refcnt_numsets / + NUM_OF_HW_PAGES_PER_SW_PAGE(); + rcb.rcb_base_page_size = NBPP; + rcb.rcb_base_paddr = ctob(slot_getbasepfn(node, 0)); + + rcb.rcb_cnodeid = node; + rcb.rcb_granularity = MD_PAGE_SIZE; +#ifdef LATER + rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); + rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); +#endif + rcb.rcb_abs_threshold = MIGR_THRESHOLD_ABS_GET(node); + rcb.rcb_num_slots = MAX_MEM_SLOTS; + + if (COPYOUT(&rcb, arg, sizeof(rcb_info_t))) { + errcode = EFAULT; + } + + break; + } + case RCB_SLOT_GET: + { + rcb_slot_t slot[MAX_MEM_SLOTS]; + int s; + int nslots; + + nslots = MAX_MEM_SLOTS; + ASSERT(nslots <= MAX_MEM_SLOTS); + for (s = 0; s < nslots; s++) { + slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); +#ifdef LATER + slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); +#else + slot[s].size = (uint64_t)1; +#endif + } + if (COPYOUT(&slot[0], arg, nslots * sizeof(rcb_slot_t))) { + errcode = EFAULT; + } + + *rvalp = nslots; + break; + } + + default: + errcode = EINVAL; + break; + + } + + return errcode; +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/ml_SN_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/ml_SN_intr.c --- linux-2.4.18/arch/ia64/sn/io/sn1/ml_SN_intr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/ml_SN_intr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1154 @@ +/* $Id: ml_SN_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * intr.c- + * This file contains all of the routines necessary to set up and + * handle interrupts on an IP27 board. + */ + +#ident "$Revision: 1.1 $" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if DEBUG_INTR_TSTAMP_DEBUG +#include +#include +#include +void do_splx_log(int, int); +void spldebug_log_event(int); +#endif + +#ifdef CONFIG_SMP +extern unsigned long cpu_online_map; +#endif +#define cpu_allows_intr(cpu) (1) +// If I understand what's going on with this, 32 should work. +// physmem_maxradius seems to be the maximum number of router +// hops to get from one end of the system to the other. With +// a maximally configured machine, with the dumbest possible +// topology, we would make 32 router hops. For what we're using +// it for, the dumbest possible should suffice. +#define physmem_maxradius() 32 + +#define SUBNODE_ANY (-1) + +extern int nmied; +extern int hub_intr_wakeup_cnt; +extern synergy_da_t *Synergy_da_indr[]; +extern cpuid_t master_procid; + +extern cnodeid_t master_node_get(devfs_handle_t vhdl); + +extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); + + +#define INTR_LOCK(vecblk) \ + (s = mutex_spinlock(&(vecblk)->vector_lock)) +#define INTR_UNLOCK(vecblk) \ + mutex_spinunlock(&(vecblk)->vector_lock, s) + +/* + * REACT/Pro + */ + + + +/* + * Find first bit set + * Used outside this file also + */ +int ms1bit(unsigned long x) +{ + int b; + + if (x >> 32) b = 32, x >>= 32; + else b = 0; + if (x >> 16) b += 16, x >>= 16; + if (x >> 8) b += 8, x >>= 8; + if (x >> 4) b += 4, x >>= 4; + if (x >> 2) b += 2, x >>= 2; + + return b + (int) (x >> 1); +} + +/* ARGSUSED */ +void +intr_stray(void *lvl) +{ + printk(KERN_WARNING "Stray Interrupt - level %ld to cpu %d", (long)lvl, smp_processor_id()); +} + +#if defined(DEBUG) + +/* Infrastructure to gather the device - target cpu mapping info */ +#define MAX_DEVICES 1000 /* Reasonable large number . Need not be + * the exact maximum # devices possible. + */ +#define MAX_NAME 100 +typedef struct { + dev_t dev; /* device */ + cpuid_t cpuid; /* target cpu */ + cnodeid_t cnodeid;/* node on which the target cpu is present */ + int bit; /* intr bit reserved */ + char intr_name[MAX_NAME]; /* name of the interrupt */ +} intr_dev_targ_map_t; + +intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; +uint64_t intr_dev_targ_map_size; +spinlock_t intr_dev_targ_map_lock; + +/* Print out the device - target cpu mapping. + * This routine is used only in the idbg command + * "intrmap" + */ +void +intr_dev_targ_map_print(cnodeid_t cnodeid) +{ + int i,j,size = 0; + int print_flag = 0,verbose = 0; + char node_name[10]; + + if (cnodeid != CNODEID_NONE) { + nodepda_t *npda; + + npda = NODEPDA(cnodeid); + for (j=0; jintr_dispatch0.info[i].ii_flags); + qprintf("\n INT_PEND1: "); + for(i = 0 ; i < N_INTPEND_BITS ; i++) + qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags); + } + verbose = 1; + } + qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n", + (verbose ? "All" : "Non-hardwired"), + (cnodeid == CNODEID_NONE) ? "s: All" : node_name); + + qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n"); + for (i = 0 ; i < intr_dev_targ_map_size ; i++) { + + print_flag = 0; + if (verbose) { + if (cnodeid != CNODEID_NONE) { + if (cnodeid == intr_dev_targ_map[i].cnodeid) + print_flag = 1; + } else { + print_flag = 1; + } + } else { + if (intr_dev_targ_map[i].dev != 0) { + if (cnodeid != CNODEID_NONE) { + if (cnodeid == + intr_dev_targ_map[i].cnodeid) + print_flag = 1; + } else { + print_flag = 1; + } + } + } + if (print_flag) { + size++; + qprintf("%d\t%d\t%d\t%d\t%s\n", + intr_dev_targ_map[i].dev, + intr_dev_targ_map[i].cpuid, + intr_dev_targ_map[i].cnodeid, + intr_dev_targ_map[i].bit, + intr_dev_targ_map[i].intr_name); + } + + } + qprintf("\nTotal : %d\n",size); +} +#endif /* DEBUG */ + +/* + * The spinlocks have already been initialized. Now initialize the interrupt + * vectors. One processor on each hub does the work. + */ +void +intr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn) +{ + int i, ip=0; + intr_vecblk_t *vecblk; + subnode_pda_t *snpda; + + + snpda = SNPDA(npda,sn); + do { + if (ip == 0) { + vecblk = &snpda->intr_dispatch0; + } else { + vecblk = &snpda->intr_dispatch1; + } + + /* Initialize this vector. */ + for (i = 0; i < N_INTPEND_BITS; i++) { + vecblk->vectors[i].iv_func = intr_stray; + vecblk->vectors[i].iv_prefunc = NULL; + vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i); + + vecblk->info[i].ii_owner_dev = 0; + strcpy(vecblk->info[i].ii_name, "Unused"); + vecblk->info[i].ii_flags = 0; /* No flags */ + vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */ + + } + + mutex_spinlock_init(&vecblk->vector_lock); + + vecblk->vector_count = 0; + for (i = 0; i < CPUS_PER_SUBNODE; i++) + vecblk->cpu_count[i] = 0; + + vecblk->vector_state = VECTOR_UNINITED; + + } while (++ip < 2); + +} + + +/* + * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, + * devfs_handle_t owner_dev, char *name) + * Internal work routine to reserve or unreserve an interrupt level. + * cpu is the CPU to which the interrupt will be sent. + * bit is the level bit to reserve. -1 means any level + * resflags should include II_ERRORINT if this is an + * error interrupt, II_THREADED if the interrupt handler + * will be threaded, or 0 otherwise. + * reserve should be set to II_RESERVE or II_UNRESERVE + * to get or clear a reservation. + * owner_dev is the device that "owns" this interrupt, if supplied + * name is a human-readable name for this interrupt, if supplied + * intr_reserve_level returns the bit reserved or -1 to indicate an error + */ +static int +do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, + devfs_handle_t owner_dev, char *name) +{ + intr_vecblk_t *vecblk; + hub_intmasks_t *hub_intmasks; + unsigned long s; + int rv = 0; + int ip; + synergy_da_t *sda; + int which_synergy; + cnodeid_t cnode; + + ASSERT(bit < N_INTPEND_BITS * 2); + + cnode = cpuid_to_cnodeid(cpu); + which_synergy = cpuid_to_synergy(cpu); + sda = Synergy_da_indr[(cnode * 2) + which_synergy]; + hub_intmasks = &sda->s_intmasks; + // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; + + // if (pdaindr[cpu].pda == NULL) return -1; + if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) { + vecblk = hub_intmasks->dispatch0; + ip = 0; + } else { + ASSERT((bit >= N_INTPEND_BITS) || (bit == -1)); + bit -= N_INTPEND_BITS; /* Get position relative to INT_PEND1 reg. */ + vecblk = hub_intmasks->dispatch1; + ip = 1; + } + + INTR_LOCK(vecblk); + + if (bit <= -1) { + bit = 0; + ASSERT(reserve == II_RESERVE); + /* Choose any available level */ + for (; bit < N_INTPEND_BITS; bit++) { + if (!(vecblk->info[bit].ii_flags & II_RESERVE)) { + rv = bit; + break; + } + } + + /* Return -1 if all interrupt levels int this register are taken. */ + if (bit == N_INTPEND_BITS) + rv = -1; + + } else { + /* Reserve a particular level if it's available. */ + if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) { + /* Can't (un)reserve a level that's already (un)reserved. */ + rv = -1; + } else { + rv = bit; + } + } + + /* Reserve the level and bump the count. */ + if (rv != -1) { + if (reserve) { + int maxlen = sizeof(vecblk->info[bit].ii_name) - 1; + int namelen; + vecblk->info[bit].ii_flags |= (II_RESERVE | resflags); + vecblk->info[bit].ii_owner_dev = owner_dev; + /* Copy in the name. */ + namelen = name ? strlen(name) : 0; + strncpy(vecblk->info[bit].ii_name, name, min(namelen, maxlen)); + vecblk->info[bit].ii_name[maxlen] = '\0'; + vecblk->vector_count++; + } else { + vecblk->info[bit].ii_flags = 0; /* Clear all the flags */ + vecblk->info[bit].ii_owner_dev = 0; + /* Clear the name. */ + vecblk->info[bit].ii_name[0] = '\0'; + vecblk->vector_count--; + } + } + + INTR_UNLOCK(vecblk); + +#if defined(DEBUG) + if (rv >= 0) { + int namelen = name ? strlen(name) : 0; + /* Gather this device - target cpu mapping information + * in a table which can be used later by the idbg "intrmap" + * command + */ + s = mutex_spinlock(&intr_dev_targ_map_lock); + if (intr_dev_targ_map_size < MAX_DEVICES) { + intr_dev_targ_map_t *p; + + p = &intr_dev_targ_map[intr_dev_targ_map_size]; + p->dev = owner_dev; + p->cpuid = cpu; + p->cnodeid = cpuid_to_cnodeid(cpu); + p->bit = ip * N_INTPEND_BITS + rv; + strncpy(p->intr_name, + name, + min(MAX_NAME,namelen)); + intr_dev_targ_map_size++; + } + mutex_spinunlock(&intr_dev_targ_map_lock,s); + } +#endif /* DEBUG */ + + return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ; +} + + +/* + * WARNING: This routine should only be called from within ml/SN. + * Reserve an interrupt level. + */ +int +intr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name) +{ + return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name)); +} + + +/* + * WARNING: This routine should only be called from within ml/SN. + * Unreserve an interrupt level. + */ +void +intr_unreserve_level(cpuid_t cpu, int bit) +{ + (void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL); +} + +/* + * Get values that vary depending on which CPU and bit we're operating on + */ +static hub_intmasks_t * +intr_get_ptrs(cpuid_t cpu, int bit, + int *new_bit, /* Bit relative to the register */ + hubreg_t **intpend_masks, /* Masks for this register */ + intr_vecblk_t **vecblk, /* Vecblock for this interrupt */ + int *ip) /* Which intpend register */ +{ + hub_intmasks_t *hub_intmasks; + synergy_da_t *sda; + int which_synergy; + cnodeid_t cnode; + + ASSERT(bit < N_INTPEND_BITS * 2); + + cnode = cpuid_to_cnodeid(cpu); + which_synergy = cpuid_to_synergy(cpu); + sda = Synergy_da_indr[(cnode * 2) + which_synergy]; + hub_intmasks = &sda->s_intmasks; + + // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; + + if (bit < N_INTPEND_BITS) { + *intpend_masks = hub_intmasks->intpend0_masks; + *vecblk = hub_intmasks->dispatch0; + *ip = 0; + *new_bit = bit; + } else { + *intpend_masks = hub_intmasks->intpend1_masks; + *vecblk = hub_intmasks->dispatch1; + *ip = 1; + *new_bit = bit - N_INTPEND_BITS; + } + + return hub_intmasks; +} + + +/* + * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, + * intr_func_t intr_func, void *intr_arg); + * This is the lowest-level interface to the interrupt code. It shouldn't + * be called from outside the ml/SN directory. + * intr_connect_level hooks up an interrupt to a particular bit in + * the INT_PEND0/1 masks. Returns 0 on success. + * cpu is the CPU to which the interrupt will be sent. + * bit is the level bit to connect to + * intr_swlevel tells which software level to use + * intr_func is the interrupt handler + * intr_arg is an arbitrary argument interpreted by the handler + * intr_prefunc is a prologue function, to be called + * with interrupts disabled, to disable + * the interrupt at source. It is called + * with the same argument. Should be NULL for + * typical interrupts, which can be masked + * by the infrastructure at the level bit. + * intr_connect_level returns 0 on success or nonzero on an error + */ +/* ARGSUSED */ +int +intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, intr_func_t intr_prefunc) +{ + intr_vecblk_t *vecblk; + hubreg_t *intpend_masks; + int rv = 0; + int ip; + unsigned long s; + + ASSERT(bit < N_INTPEND_BITS * 2); + + (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, + &vecblk, &ip); + + INTR_LOCK(vecblk); + + if ((vecblk->info[bit].ii_flags & II_INUSE) || + (!(vecblk->info[bit].ii_flags & II_RESERVE))) { + /* Can't assign to a level that's in use or isn't reserved. */ + rv = -1; + } else { + /* Stuff parameters into vector and info */ + vecblk->vectors[bit].iv_prefunc = intr_prefunc; + vecblk->info[bit].ii_flags |= II_INUSE; + } + + /* Now stuff the masks if everything's okay. */ + if (!rv) { + int lslice; + volatile hubreg_t *mask_reg; + // nasid_t nasid = COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)); + nasid_t nasid = cpuid_to_nasid(cpu); + int subnode = cpuid_to_subnode(cpu); + + /* Make sure it's not already pending when we connect it. */ + REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS); + + if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { + intpend_masks[0] |= (1ULL << (uint64_t)bit); + } + + lslice = cpuid_to_localslice(cpu); + vecblk->cpu_count[lslice]++; +#if SN1 + /* + * On SN1, there are 8 interrupt mask registers per node: + * PI_0 MASK_0 A + * PI_0 MASK_1 A + * PI_0 MASK_0 B + * PI_0 MASK_1 B + * PI_1 MASK_0 A + * PI_1 MASK_1 A + * PI_1 MASK_0 B + * PI_1 MASK_1 B + */ +#endif + if (ip == 0) { + mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, + PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice); + } else { + mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, + PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice); + } + + HUB_S(mask_reg, intpend_masks[0]); + } + + INTR_UNLOCK(vecblk); + + return rv; +} + + +/* + * intr_disconnect_level(cpuid_t cpu, int bit) + * + * This is the lowest-level interface to the interrupt code. It should + * not be called from outside the ml/SN directory. + * intr_disconnect_level removes a particular bit from an interrupt in + * the INT_PEND0/1 masks. Returns 0 on success or nonzero on failure. + */ +int +intr_disconnect_level(cpuid_t cpu, int bit) +{ + intr_vecblk_t *vecblk; + hubreg_t *intpend_masks; + unsigned long s; + int rv = 0; + int ip; + + (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, + &vecblk, &ip); + + INTR_LOCK(vecblk); + + if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) != + ((II_RESERVE | II_INUSE))) { + /* Can't remove a level that's not in use or isn't reserved. */ + rv = -1; + } else { + /* Stuff parameters into vector and info */ + vecblk->vectors[bit].iv_func = (intr_func_t)NULL; + vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL; + vecblk->vectors[bit].iv_arg = 0; + vecblk->info[bit].ii_flags &= ~II_INUSE; +#ifdef BASE_ITHRTEAD + vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */ +#endif + } + + /* Now clear the masks if everything's okay. */ + if (!rv) { + int lslice; + volatile hubreg_t *mask_reg; + + intpend_masks[0] &= ~(1ULL << (uint64_t)bit); + lslice = cpuid_to_localslice(cpu); + vecblk->cpu_count[lslice]--; + mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), + cpuid_to_subnode(cpu), + ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A); + mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg + + (PI_INT_MASK_OFFSET * lslice)); + *mask_reg = intpend_masks[0]; + } + + INTR_UNLOCK(vecblk); + + return rv; +} + +/* + * Actually block or unblock an interrupt + */ +void +do_intr_block_bit(cpuid_t cpu, int bit, int block) +{ + intr_vecblk_t *vecblk; + int ip; + unsigned long s; + hubreg_t *intpend_masks; + volatile hubreg_t mask_value; + volatile hubreg_t *mask_reg; + + intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip); + + INTR_LOCK(vecblk); + + if (block) + /* Block */ + intpend_masks[0] &= ~(1ULL << (uint64_t)bit); + else + /* Unblock */ + intpend_masks[0] |= (1ULL << (uint64_t)bit); + + if (ip == 0) { + mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), + cpuid_to_subnode(cpu), PI_INT_MASK0_A); + } else { + mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), + cpuid_to_subnode(cpu), PI_INT_MASK1_A); + } + + HUB_S(mask_reg, intpend_masks[0]); + + /* + * Wait for it to take effect. (One read should suffice.) + * This is only necessary when blocking an interrupt + */ + if (block) + while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0]) + ; + + INTR_UNLOCK(vecblk); +} + + +/* + * Block a particular interrupt (cpu/bit pair). + */ +/* ARGSUSED */ +void +intr_block_bit(cpuid_t cpu, int bit) +{ + do_intr_block_bit(cpu, bit, 1); +} + + +/* + * Unblock a particular interrupt (cpu/bit pair). + */ +/* ARGSUSED */ +void +intr_unblock_bit(cpuid_t cpu, int bit) +{ + do_intr_block_bit(cpu, bit, 0); +} + + +/* verifies that the specified CPUID is on the specified SUBNODE (if any) */ +#define cpu_on_subnode(cpuid, which_subnode) \ + (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode))) + + +/* + * Choose one of the CPUs on a specified node or subnode to receive + * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu. + * + * Among all acceptable CPUs, the CPU that has the fewest total number + * of interrupts targetted towards it is chosen. Note that we never + * consider how frequent each of these interrupts might occur, so a rare + * hardware error interrupt is weighted equally with a disk interrupt. + */ +static cpuid_t +do_intr_cpu_choose(cnodeid_t cnode, int which_subnode) +{ + cpuid_t cpu, best_cpu = CPU_NONE; + int slice, min_count=1000; + + min_count = 1000; + for (slice=0; slice < CPUS_PER_NODE; slice++) { + intr_vecblk_t *vecblk0, *vecblk1; + int total_intrs_to_slice; + subnode_pda_t *snpda; + int local_cpu_num; + + cpu = cnode_slice_to_cpuid(cnode, slice); + if (cpu == CPU_NONE) + continue; + + /* If this cpu isn't enabled for interrupts, skip it */ + if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu)) + continue; + + /* If this isn't the right subnode, skip it */ + if (!cpu_on_subnode(cpu, which_subnode)) + continue; + + /* OK, this one's a potential CPU for interrupts */ + snpda = SUBNODEPDA(cnode,SUBNODE(slice)); + vecblk0 = &snpda->intr_dispatch0; + vecblk1 = &snpda->intr_dispatch1; + local_cpu_num = LOCALCPU(slice); + total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] + + vecblk1->cpu_count[local_cpu_num]; + + if (min_count > total_intrs_to_slice) { + min_count = total_intrs_to_slice; + best_cpu = cpu; + } + } + return best_cpu; +} + +/* + * Choose an appropriate interrupt target CPU on a specified node. + * If which_subnode is SUBNODE_ANY, then subnode is not considered. + * Otherwise, the chosen CPU must be on the specified subnode. + */ +static cpuid_t +intr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode) +{ + return(do_intr_cpu_choose(cnode, which_subnode)); +} + + +/* Make it easy to identify subnode vertices in the hwgraph */ +void +mark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode) +{ + graph_error_t rv; + + ASSERT(0 <= which_subnode); + ASSERT(which_subnode < NUM_SUBNODES); + + rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode); + ASSERT_ALWAYS(rv == GRAPH_SUCCESS); + + rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t)); + ASSERT_ALWAYS(rv == GRAPH_SUCCESS); +} + + +/* + * Given a device descriptor, extract interrupt target information and + * choose an appropriate CPU. Return CPU_NONE if we can't make sense + * out of the target information. + * TBD: Should this be considered platform-independent code? + */ + + +/* + * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags, + * owner_dev,intr_name,*resp_bit) + * Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but + * not both. + * 1. If cpuid is specified, this routine tests if this cpu can be a valid + * interrupt target candidate. + * 2. If cnodeid is specified, this routine tests if there is a cpu on + * this node which can be a valid interrupt target candidate. + * 3. If a valid interrupt target cpu candidate is found then an attempt at + * reserving an interrupt bit on the corresponding cnode is made. + * + * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid + * interrupt target cpu then routine returns CPU_NONE (failure) + * Otherwise routine returns cpuid of interrupt target (success) + */ +static cpuid_t +intr_bit_reserve_test(cpuid_t cpuid, + int favor_subnode, + cnodeid_t cnodeid, + int req_bit, + int intr_resflags, + devfs_handle_t owner_dev, + char *intr_name, + int *resp_bit) +{ + + ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE)); + + if (cnodeid != CNODEID_NONE) { + /* Try to choose a interrupt cpu candidate */ + cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode); + } + + if (cpuid != CPU_NONE) { + /* Try to reserve an interrupt bit on the hub + * corresponding to the canidate cnode. If we + * are successful then we got a cpu which can + * act as an interrupt target for the io device. + * Otherwise we need to continue the search + * further. + */ + *resp_bit = do_intr_reserve_level(cpuid, + req_bit, + intr_resflags, + II_RESERVE, + owner_dev, + intr_name); + + if (*resp_bit >= 0) + /* The interrupt target specified was fine */ + return(cpuid); + } + return(CPU_NONE); +} +/* + * intr_heuristic(dev_t dev,device_desc_t dev_desc, + * int req_bit,int intr_resflags,dev_t owner_dev, + * char *intr_name,int *resp_bit) + * + * Choose an interrupt destination for an interrupt. + * dev is the device for which the interrupt is being set up + * dev_desc is a description of hardware and policy that could + * help determine where this interrupt should go + * req_bit is the interrupt bit requested + * (can be INTRCONNECT_ANY_BIT in which the first available + * interrupt bit is used) + * intr_resflags indicates whether we want to (un)reserve bit + * owner_dev is the owner device + * intr_name is the readable interrupt name + * resp_bit indicates whether we succeeded in getting the required + * action { (un)reservation} done + * negative value indicates failure + * + */ +/* ARGSUSED */ +cpuid_t +intr_heuristic(devfs_handle_t dev, + device_desc_t dev_desc, + int req_bit, + int intr_resflags, + devfs_handle_t owner_dev, + char *intr_name, + int *resp_bit) +{ + cpuid_t cpuid; /* possible intr targ*/ + cnodeid_t candidate; /* possible canidate */ + int which_subnode = SUBNODE_ANY; + +/* SN1 + pcibr Addressing Limitation */ + { + devfs_handle_t pconn_vhdl; + pcibr_soft_t pcibr_soft; + + /* + * This combination of SN1 and Bridge hardware has an odd "limitation". + * Due to the choice of addresses for PI0 and PI1 registers on SN1 + * and historical limitations in Bridge, Bridge is unable to + * send interrupts to both PI0 CPUs and PI1 CPUs -- we have + * to choose one set or the other. That choice is implicitly + * made when Bridge first attaches its error interrupt. After + * that point, all subsequent interrupts are restricted to the + * same PI number (though it's possible to send interrupts to + * the same PI number on a different node). + * + * Since neither SN1 nor Bridge designers are willing to admit a + * bug, we can't really call this a "workaround". It's a permanent + * solution for an SN1-specific and Bridge-specific hardware + * limitation that won't ever be lifted. + */ + if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && + ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) { + /* + * We "know" that the error interrupt is the first + * interrupt set up by pcibr_attach. Send all interrupts + * on this bridge to the same subnode number. + */ + if (pcibr_soft->bsi_err_intr) { + which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid); + } + } + } + + /* Check if we can find a valid interrupt target candidate on + * the master node for the device. + */ + cpuid = intr_bit_reserve_test(CPU_NONE, + which_subnode, + master_node_get(dev), + req_bit, + intr_resflags, + owner_dev, + intr_name, + resp_bit); + + if (cpuid != CPU_NONE) { + if (cpu_on_subnode(cpuid, which_subnode)) + return(cpuid); /* got a valid interrupt target */ + else + intr_unreserve_level(cpuid, *resp_bit); + } + + printk(KERN_WARNING "Cannot target interrupts to closest node(%d): (0x%lx)\n", + master_node_get(dev),(unsigned long)owner_dev); + + /* Fall through into the default algorithm + * (exhaustive-search-for-the-nearest-possible-interrupt-target) + * for finding the interrupt target + */ + + { + /* + * Do a stupid round-robin assignment of the node. + * (Should do a "nearest neighbor" but not for SN1. + */ + static cnodeid_t last_node = -1; + + if (last_node >= numnodes) last_node = 0; + for (candidate = last_node + 1; candidate != last_node; candidate++) { + if (candidate == numnodes) candidate = 0; + cpuid = intr_bit_reserve_test(CPU_NONE, + which_subnode, + candidate, + req_bit, + intr_resflags, + owner_dev, + intr_name, + resp_bit); + + if (cpuid != CPU_NONE) { + if (cpu_on_subnode(cpuid, which_subnode)) { + last_node = candidate; + return(cpuid); /* got a valid interrupt target */ + } + else + intr_unreserve_level(cpuid, *resp_bit); + } + } + last_node = candidate; + } + + printk(KERN_WARNING "Cannot target interrupts to any close node: %ld (0x%lx)\n", + (long)owner_dev, (unsigned long)owner_dev); + + /* In the worst case try to allocate interrupt bits on the + * master processor's node. We may get here during error interrupt + * allocation phase when the topology matrix is not yet setup + * and hence cannot do an exhaustive search. + */ + ASSERT(cpu_allows_intr(master_procid)); + cpuid = intr_bit_reserve_test(master_procid, + which_subnode, + CNODEID_NONE, + req_bit, + intr_resflags, + owner_dev, + intr_name, + resp_bit); + + if (cpuid != CPU_NONE) { + if (cpu_on_subnode(cpuid, which_subnode)) + return(cpuid); + else + intr_unreserve_level(cpuid, *resp_bit); + } + + printk(KERN_WARNING "Cannot target interrupts: (0x%lx)\n", + (unsigned long)owner_dev); + + return(CPU_NONE); /* Should never get here */ +} + +struct hardwired_intr_s { + signed char level; + int flags; + char *name; +} const hardwired_intr[] = { + { INT_PEND0_BASELVL + RESERVED_INTR, 0, "Reserved" }, + { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, + { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, + { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, + { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, + { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, + { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, + { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, + { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, + { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, + { INT_PEND1_BASELVL + MD_COR_ERR_INTR, II_ERRORINT, "MD Correct. Error" }, + { INT_PEND1_BASELVL + NI_ERROR_INTR, II_ERRORINT, "NI Error" }, + { INT_PEND1_BASELVL + NI_BRDCAST_ERR_A, II_ERRORINT, "Remote NI Error"}, + { INT_PEND1_BASELVL + NI_BRDCAST_ERR_B, II_ERRORINT, "Remote NI Error"}, + { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, + { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, + { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, + { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, + { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, + { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, + { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, + { -1, 0, (char *)NULL}, +}; + +/* + * Reserve all of the hardwired interrupt levels so they're not used as + * general purpose bits later. + */ +void +intr_reserve_hardwired(cnodeid_t cnode) +{ + cpuid_t cpu; + int level; + int i; + char subnode_done[NUM_SUBNODES]; + + // cpu = cnodetocpu(cnode); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (cpuid_to_cnodeid(cpu) == cnode) { + break; + } + } + if (cpu == smp_num_cpus) cpu = CPU_NONE; + if (cpu == CPU_NONE) { + printk("Node %d has no CPUs", cnode); + return; + } + + for (i=0; iii_name, + vector->iv_func, vector->iv_arg, vector->iv_prefunc); + pf(" vertex 0x%x %s%s", + info->ii_owner_dev, + ((info->ii_flags) & II_RESERVE) ? "R" : "U", + ((info->ii_flags) & II_INUSE) ? "C" : "-"); + pf("%s%s%s%s", + ip & value ? "P" : "-", + ima & value ? "A" : "-", + imb & value ? "B" : "-", + ((info->ii_flags) & II_ERRORINT) ? "E" : "-"); + pf("\n"); +} + + +/* + * Dump information about interrupt vector assignment. + */ +void +intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)) +{ + nodepda_t *npda; + int ip, sn, bit; + intr_vecblk_t *dispatch; + hubreg_t ipr, ima, imb; + nasid_t nasid; + + if ((cnode < 0) || (cnode >= numnodes)) { + pf("intr_dumpvec: cnodeid out of range: %d\n", cnode); + return ; + } + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + if (nasid == INVALID_NASID) { + pf("intr_dumpvec: Bad cnodeid: %d\n", cnode); + return ; + } + + + npda = NODEPDA(cnode); + + for (sn = 0; sn < NUM_SUBNODES; sn++) { + for (ip = 0; ip < 2; ip++) { + dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0); + ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0); + ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A); + imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B); + + pf("Node %d INT_PEND%d:\n", cnode, ip); + + if (dispatch->ithreads_enabled) + pf(" Ithreads enabled\n"); + else + pf(" Ithreads disabled\n"); + pf(" vector_count = %d, vector_state = %d\n", + dispatch->vector_count, + dispatch->vector_state); + pf(" CPU A count %d, CPU B count %d\n", + dispatch->cpu_count[0], + dispatch->cpu_count[1]); + pf(" &vector_lock = 0x%x\n", + &(dispatch->vector_lock)); + for (bit = 0; bit < N_INTPEND_BITS; bit++) { + if ((dispatch->info[bit].ii_flags & II_RESERVE) || + (ipr & (1L << bit))) { + dump_vector(&(dispatch->info[bit]), + &(dispatch->vectors[bit]), + bit, ipr, ima, imb, pf); + } + } + pf("\n"); + } + } +} + diff -urN linux-2.4.18/arch/ia64/sn/io/sn1/pcibr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn1/pcibr.c --- linux-2.4.18/arch/ia64/sn/io/sn1/pcibr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn1/pcibr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,7950 @@ +/* + * 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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +int NeedXbridgeSwap = 0; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +extern boolean_t is_sys_critical_vertex(devfs_handle_t); + +#undef PCIBR_ATE_DEBUG + +#if 0 +#define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ +#endif +#define PCI_DEBUG 1 +#define ATTACH_DEBUG 1 +#define PCIBR_SOFT_LIST 1 + +#ifndef LOCAL +#define LOCAL static +#endif + +/* + * Macros related to the Lucent USS 302/312 usb timeout workaround. It + * appears that if the lucent part can get into a retry loop if it sees a + * DAC on the bus during a pio read retry. The loop is broken after about + * 1ms, so we need to set up bridges holding this part to allow at least + * 1ms for pio. + */ + +#define USS302_TIMEOUT_WAR + +#ifdef USS302_TIMEOUT_WAR +#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 +#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 +#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 +#define USS302_BRIDGE_TIMEOUT_HLD 4 +#endif + +#define PCIBR_LLP_CONTROL_WAR +#if defined (PCIBR_LLP_CONTROL_WAR) +int pcibr_llp_control_war_cnt; +#endif /* PCIBR_LLP_CONTROL_WAR */ + +int pcibr_devflag = D_MP; + +#ifdef LATER +#define F(s,n) { 1l<<(s),-(s), n } + +struct reg_desc bridge_int_status_desc[] = +{ + F(31, "MULTI_ERR"), + F(30, "PMU_ESIZE_EFAULT"), + F(29, "UNEXPECTED_RESP"), + F(28, "BAD_XRESP_PACKET"), + F(27, "BAD_XREQ_PACKET"), + F(26, "RESP_XTALK_ERROR"), + F(25, "REQ_XTALK_ERROR"), + F(24, "INVALID_ADDRESS"), + F(23, "UNSUPPORTED_XOP"), + F(22, "XREQ_FIFO_OFLOW"), + F(21, "LLP_REC_SNERROR"), + F(20, "LLP_REC_CBERROR"), + F(19, "LLP_RCTY"), + F(18, "LLP_TX_RETRY"), + F(17, "LLP_TCTY"), + F(16, "SSRAM_PERR"), + F(15, "PCI_ABORT"), + F(14, "PCI_PARITY"), + F(13, "PCI_SERR"), + F(12, "PCI_PERR"), + F(11, "PCI_MASTER_TOUT"), + F(10, "PCI_RETRY_CNT"), + F(9, "XREAD_REQ_TOUT"), + F(8, "GIO_BENABLE_ERR"), + F(7, "INT7"), + F(6, "INT6"), + F(5, "INT5"), + F(4, "INT4"), + F(3, "INT3"), + F(2, "INT2"), + F(1, "INT1"), + F(0, "INT0"), + {0} +}; + +struct reg_values space_v[] = +{ + {PCIIO_SPACE_NONE, "none"}, + {PCIIO_SPACE_ROM, "ROM"}, + {PCIIO_SPACE_IO, "I/O"}, + {PCIIO_SPACE_MEM, "MEM"}, + {PCIIO_SPACE_MEM32, "MEM(32)"}, + {PCIIO_SPACE_MEM64, "MEM(64)"}, + {PCIIO_SPACE_CFG, "CFG"}, + {PCIIO_SPACE_WIN(0), "WIN(0)"}, + {PCIIO_SPACE_WIN(1), "WIN(1)"}, + {PCIIO_SPACE_WIN(2), "WIN(2)"}, + {PCIIO_SPACE_WIN(3), "WIN(3)"}, + {PCIIO_SPACE_WIN(4), "WIN(4)"}, + {PCIIO_SPACE_WIN(5), "WIN(5)"}, + {PCIIO_SPACE_BAD, "BAD"}, + {0} +}; + +struct reg_desc space_desc[] = +{ + {0xFF, 0, "space", 0, space_v}, + {0} +}; + +#if DEBUG +#define device_desc device_bits +LOCAL struct reg_desc device_bits[] = +{ + {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, + {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, + {BRIDGE_DEV_FORCE_PCI_PAR, 0, "FORCE_PCI_PAR"}, + {BRIDGE_DEV_VIRTUAL_EN, 0, "VIRTUAL_EN"}, + {BRIDGE_DEV_PMU_WRGA_EN, 0, "PMU_WRGA_EN"}, + {BRIDGE_DEV_DIR_WRGA_EN, 0, "DIR_WRGA_EN"}, + {BRIDGE_DEV_DEV_SIZE, 0, "DEV_SIZE"}, + {BRIDGE_DEV_RT, 0, "RT"}, + {BRIDGE_DEV_SWAP_PMU, 0, "SWAP_PMU"}, + {BRIDGE_DEV_SWAP_DIR, 0, "SWAP_DIR"}, + {BRIDGE_DEV_PREF, 0, "PREF"}, + {BRIDGE_DEV_PRECISE, 0, "PRECISE"}, + {BRIDGE_DEV_COH, 0, "COH"}, + {BRIDGE_DEV_BARRIER, 0, "BARRIER"}, + {BRIDGE_DEV_GBR, 0, "GBR"}, + {BRIDGE_DEV_DEV_SWAP, 0, "DEV_SWAP"}, + {BRIDGE_DEV_DEV_IO_MEM, 0, "DEV_IO_MEM"}, + {BRIDGE_DEV_OFF_MASK, BRIDGE_DEV_OFF_ADDR_SHFT, "DEV_OFF", "%x"}, + {0} +}; +#endif /* DEBUG */ + +#ifdef SUPPORT_PRINTING_R_FORMAT +LOCAL struct reg_values xio_cmd_pactyp[] = +{ + {0x0, "RdReq"}, + {0x1, "RdResp"}, + {0x2, "WrReqWithResp"}, + {0x3, "WrResp"}, + {0x4, "WrReqNoResp"}, + {0x5, "Reserved(5)"}, + {0x6, "FetchAndOp"}, + {0x7, "Reserved(7)"}, + {0x8, "StoreAndOp"}, + {0x9, "Reserved(9)"}, + {0xa, "Reserved(a)"}, + {0xb, "Reserved(b)"}, + {0xc, "Reserved(c)"}, + {0xd, "Reserved(d)"}, + {0xe, "SpecialReq"}, + {0xf, "SpecialResp"}, + {0} +}; + +LOCAL struct reg_desc xio_cmd_bits[] = +{ + {WIDGET_DIDN, -28, "DIDN", "%x"}, + {WIDGET_SIDN, -24, "SIDN", "%x"}, + {WIDGET_PACTYP, -20, "PACTYP", 0, xio_cmd_pactyp}, + {WIDGET_TNUM, -15, "TNUM", "%x"}, + {WIDGET_COHERENT, 0, "COHERENT"}, + {WIDGET_DS, 0, "DS"}, + {WIDGET_GBR, 0, "GBR"}, + {WIDGET_VBPM, 0, "VBPM"}, + {WIDGET_ERROR, 0, "ERROR"}, + {WIDGET_BARRIER, 0, "BARRIER"}, + {0} +}; +#endif /* SUPPORT_PRINTING_R_FORMAT */ + +#if PCIBR_FREEZE_TIME || PCIBR_ATE_DEBUG +LOCAL struct reg_desc ate_bits[] = +{ + {0xFFFF000000000000ull, -48, "RMF", "%x"}, + {~(IOPGSIZE - 1) & /* may trim off some low bits */ + 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, + {0x0000000000000F00ull, -8, "port", "%x"}, + {0x0000000000000010ull, 0, "Barrier"}, + {0x0000000000000008ull, 0, "Prefetch"}, + {0x0000000000000004ull, 0, "Precise"}, + {0x0000000000000002ull, 0, "Coherent"}, + {0x0000000000000001ull, 0, "Valid"}, + {0} +}; +#endif + +#if PCIBR_ATE_DEBUG +LOCAL struct reg_values ssram_sizes[] = +{ + {BRIDGE_CTRL_SSRAM_512K, "512k"}, + {BRIDGE_CTRL_SSRAM_128K, "128k"}, + {BRIDGE_CTRL_SSRAM_64K, "64k"}, + {BRIDGE_CTRL_SSRAM_1K, "1k"}, + {0} +}; + +LOCAL struct reg_desc control_bits[] = +{ + {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, + {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, + {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, + {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, + {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, + {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, + {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, + {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, + {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, + {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, + {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, + {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, + {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, + {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, + {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, + {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, + {BRIDGE_CTRL_MAX_TRANS_MASK, -4, "MAX_TRANS", "%d"}, + {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, + {0} +}; +#endif +#endif /* LATER */ + +/* kbrick widgetnum-to-bus layout */ +int p_busnum[MAX_PORT_NUM] = { /* widget# */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 2, /* 0x8 */ + 1, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 5, /* 0xc */ + 6, /* 0xd */ + 4, /* 0xe */ + 3, /* 0xf */ +}; + +/* + * Additional PIO spaces per slot are + * recorded in this structure. + */ +struct pciio_piospace_s { + pciio_piospace_t next; /* another space for this device */ + char free; /* 1 if free, 0 if in use */ + pciio_space_t space; /* Which space is in use */ + iopaddr_t start; /* Starting address of the PIO space */ + size_t count; /* size of PIO space */ +}; + +#if PCIBR_SOFT_LIST +pcibr_list_p pcibr_list = 0; +#endif + +#define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" + +#define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) +#define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) + +#define PCIBR_VALID_SLOT(s) (s < 8) + +#ifdef SN_XXX +extern int hub_device_flags_set(devfs_handle_t widget_dev, + hub_widget_flags_t flags); +#endif +extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +extern void free_pciio_dmamap(pcibr_dmamap_t); + +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations pcibr_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; + +extern devfs_handle_t hwgraph_root; +extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); +extern int cap_able(uint64_t x); +extern uint64_t rmalloc(struct map *mp, size_t size); +extern void rmfree(struct map *mp, size_t size, uint64_t a); +extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); +extern long atoi(register char *p); +extern void *swap_ptr(void **loc, void *new); +extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); +extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); +extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr); +extern struct map *rmallocmap(uint64_t mapsiz); +extern void rmfreemap(struct map *mp); +extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); +extern int io_path_map_widget(devfs_handle_t vertex); + + + +/* ===================================================================== + * Function Table of Contents + * + * The order of functions in this file has stopped + * making much sense. We might want to take a look + * at it some time and bring back some sanity, or + * perhaps bust this file into smaller chunks. + */ + +LOCAL void do_pcibr_rrb_clear(bridge_t *, int); +LOCAL void do_pcibr_rrb_flush(bridge_t *, int); +LOCAL int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); +LOCAL int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); +LOCAL int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); +LOCAL int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); + +LOCAL void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); + +int pcibr_wrb_flush(devfs_handle_t); +int pcibr_rrb_alloc(devfs_handle_t, int *, int *); +int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); +int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); +void pcibr_rrb_flush(devfs_handle_t); + +LOCAL int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); +void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); + +LOCAL void pcibr_clearwidint(bridge_t *); +LOCAL void pcibr_setwidint(xtalk_intr_t); +LOCAL int pcibr_probe_slot(bridge_t *, cfg_p, unsigned *); + +void pcibr_init(void); +int pcibr_attach(devfs_handle_t); +int pcibr_detach(devfs_handle_t); +int pcibr_open(devfs_handle_t *, int, int, cred_t *); +int pcibr_close(devfs_handle_t, int, int, cred_t *); +int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); +int pcibr_unmap(devfs_handle_t, vhandl_t *); +int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); + +void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); + +LOCAL int pcibr_init_ext_ate_ram(bridge_t *); +LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); +LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); + +LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); +LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); +LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); + +pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +void pcibr_piomap_free(pcibr_piomap_t); +caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); +void pcibr_piomap_done(pcibr_piomap_t); +caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); +void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); + +LOCAL iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); +LOCAL bridge_ate_t pcibr_flags_to_ate(unsigned); + +pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void pcibr_dmamap_free(pcibr_dmamap_t); +LOCAL bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); +LOCAL iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); +iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); +alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); +void pcibr_dmamap_done(pcibr_dmamap_t); +cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); +iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void pcibr_dmamap_drain(pcibr_dmamap_t); +void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); +void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); +iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); + +static unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); +pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +void pcibr_intr_free(pcibr_intr_t); +LOCAL void pcibr_setpciint(xtalk_intr_t); +int pcibr_intr_connect(pcibr_intr_t); +void pcibr_intr_disconnect(pcibr_intr_t); + +devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); +void pcibr_intr_func(intr_arg_t); + +void pcibr_provider_startup(devfs_handle_t); +void pcibr_provider_shutdown(devfs_handle_t); + +int pcibr_reset(devfs_handle_t); +pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); +pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); +int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); + +LOCAL cfg_p pcibr_config_addr(devfs_handle_t, unsigned); +uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); +LOCAL uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); +LOCAL void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); + +LOCAL pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); +void pcibr_hints_fix_rrbs(devfs_handle_t); +void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); +void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); +void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); +void pcibr_hints_handsoff(devfs_handle_t); +void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); + +LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); + +#ifdef LATER +LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, + pcibr_slot_info_resp_t); +LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, + pcibr_slot_func_info_resp_t); +#endif /* LATER */ + +LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); +LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, + pciio_slot_t, int); +LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, + pciio_slot_t, int); + +LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); +LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); +#ifdef LATER +LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); +#endif + +/* ===================================================================== + * RRB management + */ + +#define LSBIT(word) ((word) &~ ((word)-1)) + +#define PCIBR_RRB_SLOT_VIRTUAL 8 + +LOCAL void +do_pcibr_rrb_clear(bridge_t *bridge, int rrb) +{ + bridgereg_t status; + + /* bridge_lock must be held; + * this RRB must be disabled. + */ + + /* wait until RRB has no outstanduing XIO packets. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + } +} + +LOCAL void +do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) +{ + reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; + bridgereg_t rrbv; + int shft = 4 * (rrbn >> 1); + unsigned ebit = BRIDGE_RRB_EN << shft; + + rrbv = *rrbp; + if (rrbv & ebit) + *rrbp = rrbv & ~ebit; + + do_pcibr_rrb_clear(bridge, rrbn); + + if (rrbv & ebit) + *rrbp = rrbv; +} + +/* + * pcibr_rrb_count_valid: count how many RRBs are + * marked valid for the specified PCI slot on this + * bridge. + * + * NOTE: The "slot" parameter for all pcibr_rrb + * management routines must include the "virtual" + * bit; when manageing both the normal and the + * virtual channel, separate calls to these + * routines must be made. To denote the virtual + * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot + * number. + * + * IMPL NOTE: The obvious algorithm is to iterate + * through the RRB fields, incrementing a count if + * the RRB is valid and matches the slot. However, + * it is much simpler to use an algorithm derived + * from the "partitioned add" idea. First, XOR in a + * pattern such that the fields that match this + * slot come up "all ones" and all other fields + * have zeros in the mismatching bits. Then AND + * together the bits in the field, so we end up + * with one bit turned on for each field that + * matched. Now we need to count these bits. This + * can be done either with a series of shift/add + * instructions or by using "tmp % 15"; I expect + * that the cascaded shift/add will be faster. + */ + +LOCAL int +do_pcibr_rrb_count_valid(bridge_t *bridge, + pciio_slot_t slot) +{ + bridgereg_t tmp; + + tmp = bridge->b_rrb_map[slot & 1].reg; + tmp ^= 0x11111111 * (7 - slot / 2); + tmp &= (0xCCCCCCCC & tmp) >> 2; + tmp &= (0x22222222 & tmp) >> 1; + tmp += tmp >> 4; + tmp += tmp >> 8; + tmp += tmp >> 16; + return tmp & 15; +} + +/* + * do_pcibr_rrb_count_avail: count how many RRBs are + * available to be allocated for the specified slot. + * + * IMPL NOTE: similar to the above, except we are + * just counting how many fields have the valid bit + * turned off. + */ +LOCAL int +do_pcibr_rrb_count_avail(bridge_t *bridge, + pciio_slot_t slot) +{ + bridgereg_t tmp; + + tmp = bridge->b_rrb_map[slot & 1].reg; + tmp = (0x88888888 & ~tmp) >> 3; + tmp += tmp >> 4; + tmp += tmp >> 8; + tmp += tmp >> 16; + return tmp & 15; +} + +/* + * do_pcibr_rrb_alloc: allocate some additional RRBs + * for the specified slot. Returns -1 if there were + * insufficient free RRBs to satisfy the request, + * or 0 if the request was fulfilled. + * + * Note that if a request can be partially filled, + * it will be, even if we return failure. + * + * IMPL NOTE: again we avoid iterating across all + * the RRBs; instead, we form up a word containing + * one bit for each free RRB, then peel the bits + * off from the low end. + */ +LOCAL int +do_pcibr_rrb_alloc(bridge_t *bridge, + pciio_slot_t slot, + int more) +{ + int rv = 0; + bridgereg_t reg, tmp, bit; + + reg = bridge->b_rrb_map[slot & 1].reg; + tmp = (0x88888888 & ~reg) >> 3; + while (more-- > 0) { + bit = LSBIT(tmp); + if (!bit) { + rv = -1; + break; + } + tmp &= ~bit; + reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); + } + bridge->b_rrb_map[slot & 1].reg = reg; + return rv; +} + +/* + * do_pcibr_rrb_free: release some of the RRBs that + * have been allocated for the specified + * slot. Returns zero for success, or negative if + * it was unable to free that many RRBs. + * + * IMPL NOTE: We form up a bit for each RRB + * allocated to the slot, aligned with the VALID + * bitfield this time; then we peel bits off one at + * a time, releasing the corresponding RRB. + */ +LOCAL int +do_pcibr_rrb_free(bridge_t *bridge, + pciio_slot_t slot, + int less) +{ + int rv = 0; + bridgereg_t reg, tmp, clr, bit; + int i; + + clr = 0; + reg = bridge->b_rrb_map[slot & 1].reg; + + /* This needs to be done otherwise the rrb's on the virtual channel + * for this slot won't be freed !! + */ + tmp = reg & 0xbbbbbbbb; + + tmp ^= (0x11111111 * (7 - slot / 2)); + tmp &= (0x33333333 & tmp) << 2; + tmp &= (0x44444444 & tmp) << 1; + while (less-- > 0) { + bit = LSBIT(tmp); + if (!bit) { + rv = -1; + break; + } + tmp &= ~bit; + reg &= ~bit; + clr |= bit; + } + bridge->b_rrb_map[slot & 1].reg = reg; + + for (i = 0; i < 8; i++) + if (clr & (8 << (4 * i))) + do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); + + return rv; +} + +LOCAL void +do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, + int slot, + int more_rrbs) +{ + bridge_t *bridge = pcibr_soft->bs_base; + int got; + + for (got = 0; got < more_rrbs; ++got) { + if (pcibr_soft->bs_rrb_res[slot & 7] > 0) + pcibr_soft->bs_rrb_res[slot & 7]--; + else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) + pcibr_soft->bs_rrb_avail[slot & 1]--; + else + break; + if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) + break; +#if PCIBR_RRB_DEBUG + printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n", + slot & 7, slot & 8 ? "v" : ""); +#endif + pcibr_soft->bs_rrb_valid[slot]++; + } +#if PCIBR_RRB_DEBUG + printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + for (slot = 0; slot < 8; ++slot) + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + printk("\n"); +#endif +} + +/* + * Device driver interface to flush the write buffers for a specified + * device hanging off the bridge. + */ +int +pcibr_wrb_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + volatile bridgereg_t *wrb_flush; + + wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); + while (*wrb_flush); + + return(0); +} +/* + * Device driver interface to request RRBs for a specified device + * hanging off a Bridge. The driver requests the total number of + * RRBs it would like for the normal channel (vchan0) and for the + * "virtual channel" (vchan1). The actual number allocated to each + * channel is returned. + * + * If we cannot allocate at least one RRB to a channel that needs + * at least one, return -1 (failure). Otherwise, satisfy the request + * as best we can and return 0. + */ +int +pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, + int *count_vchan0, + int *count_vchan1) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + int desired_vchan0; + int desired_vchan1; + int orig_vchan0; + int orig_vchan1; + int delta_vchan0; + int delta_vchan1; + int final_vchan0; + int final_vchan1; + int avail_rrbs; + unsigned long s; + int error; + + /* + * TBD: temper request with admin info about RRB allocation, + * and according to demand from other devices on this Bridge. + * + * One way of doing this would be to allocate two RRBs + * for each device on the bus, before any drivers start + * asking for extras. This has the weakness that one + * driver might not give back an "extra" RRB until after + * another driver has already failed to get one that + * it wanted. + */ + + s = pcibr_lock(pcibr_soft); + + /* How many RRBs do we own? */ + orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; + orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + + /* How many RRBs do we want? */ + desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; + desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; + + /* How many RRBs are free? */ + avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] + + pcibr_soft->bs_rrb_res[pciio_slot]; + + /* Figure desired deltas */ + delta_vchan0 = desired_vchan0 - orig_vchan0; + delta_vchan1 = desired_vchan1 - orig_vchan1; + + /* Trim back deltas to something + * that we can actually meet, by + * decreasing the ending allocation + * for whichever channel wants + * more RRBs. If both want the same + * number, cut the second channel. + * NOTE: do not change the allocation for + * a channel that was passed as NULL. + */ + while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { + if (count_vchan0 && + (!count_vchan1 || + ((orig_vchan0 + delta_vchan0) > + (orig_vchan1 + delta_vchan1)))) + delta_vchan0--; + else + delta_vchan1--; + } + + /* Figure final RRB allocations + */ + final_vchan0 = orig_vchan0 + delta_vchan0; + final_vchan1 = orig_vchan1 + delta_vchan1; + + /* If either channel wants RRBs but our actions + * would leave it with none, declare an error, + * but DO NOT change any RRB allocations. + */ + if ((desired_vchan0 && !final_vchan0) || + (desired_vchan1 && !final_vchan1)) { + + error = -1; + + } else { + + /* Commit the allocations: free, then alloc. + */ + if (delta_vchan0 < 0) + (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); + if (delta_vchan1 < 0) + (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); + + if (delta_vchan0 > 0) + (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); + if (delta_vchan1 > 0) + (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); + + /* Return final values to caller. + */ + if (count_vchan0) + *count_vchan0 = final_vchan0; + if (count_vchan1) + *count_vchan1 = final_vchan1; + + /* prevent automatic changes to this slot's RRBs + */ + pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; + + /* Track the actual allocations, release + * any further reservations, and update the + * number of available RRBs. + */ + + pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; + pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; + pcibr_soft->bs_rrb_avail[pciio_slot & 1] = + pcibr_soft->bs_rrb_avail[pciio_slot & 1] + + pcibr_soft->bs_rrb_res[pciio_slot] + - delta_vchan0 + - delta_vchan1; + pcibr_soft->bs_rrb_res[pciio_slot] = 0; + +#if PCIBR_RRB_DEBUG + printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", + pciio_slot, final_vchan0, final_vchan1, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], + 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[pciio_slot]); + printk("\n"); +#endif + + error = 0; + } + + pcibr_unlock(pcibr_soft, s); + return error; +} + +/* + * Device driver interface to check the current state + * of the RRB allocations. + * + * pconn_vhdl is your PCI connection point (specifies which + * PCI bus and which slot). + * + * count_vchan0 points to where to return the number of RRBs + * assigned to the primary DMA channel, used by all DMA + * that does not explicitly ask for the alternate virtual + * channel. + * + * count_vchan1 points to where to return the number of RRBs + * assigned to the secondary DMA channel, used when + * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. + * + * count_reserved points to where to return the number of RRBs + * that have been automatically reserved for your device at + * startup, but which have not been assigned to a + * channel. RRBs must be assigned to a channel to be used; + * this can be done either with an explicit pcibr_rrb_alloc + * call, or automatically by the infrastructure when a DMA + * translation is constructed. Any call to pcibr_rrb_alloc + * will release any unassigned reserved RRBs back to the + * free pool. + * + * count_pool points to where to return the number of RRBs + * that are currently unassigned and unreserved. This + * number can (and will) change as other drivers make calls + * to pcibr_rrb_alloc, or automatically allocate RRBs for + * DMA beyond their initial reservation. + * + * NULL may be passed for any of the return value pointers + * the caller is not interested in. + * + * The return value is "0" if all went well, or "-1" if + * there is a problem. Additionally, if the wrong vertex + * is passed in, one of the subsidiary support functions + * could panic with a "bad pciio fingerprint." + */ + +int +pcibr_rrb_check(devfs_handle_t pconn_vhdl, + int *count_vchan0, + int *count_vchan1, + int *count_reserved, + int *count_pool) +{ + pciio_info_t pciio_info; + pciio_slot_t pciio_slot; + pcibr_soft_t pcibr_soft; + unsigned long s; + int error = -1; + + if ((pciio_info = pciio_info_get(pconn_vhdl)) && + (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && + ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { + + s = pcibr_lock(pcibr_soft); + + if (count_vchan0) + *count_vchan0 = + pcibr_soft->bs_rrb_valid[pciio_slot]; + + if (count_vchan1) + *count_vchan1 = + pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + + if (count_reserved) + *count_reserved = + pcibr_soft->bs_rrb_res[pciio_slot]; + + if (count_pool) + *count_pool = + pcibr_soft->bs_rrb_avail[pciio_slot & 1]; + + error = 0; + + pcibr_unlock(pcibr_soft, s); + } + return error; +} + +/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities + * requested for each of the devies. The evn_odd argument indicates whether + * allcoation for the odd or even rrbs is requested and next group of four pairse + * are the amount to assign to each device (they should sum to <= 8) and + * whether to set the viritual bit for that device (1 indictaes yes, 0 indicates no) + * the devices in order are either 0, 2, 4, 6 or 1, 3, 5, 7 + * if even_odd is even we alloc even rrbs else we allocate odd rrbs + * returns 0 if no errors else returns -1 + */ + +int +pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, + int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, + int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) +{ + devfs_handle_t pcibr_vhdl; + pcibr_soft_t pcibr_soft = NULL; + bridge_t *bridge = NULL; + + uint32_t rrb_setting = 0; + int rrb_shift = 7; + uint32_t cur_rrb; + int dev_rrbs[4]; + int virt[4]; + int i, j; + unsigned long s; + + if (GRAPH_SUCCESS == + hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (pcibr_soft) + bridge = pcibr_soft->bs_base; + hwgraph_vertex_unref(pcibr_vhdl); + } + if (bridge == NULL) + bridge = (bridge_t *) xtalk_piotrans_addr + (vhdl, NULL, 0, sizeof(bridge_t), 0); + + even_odd &= 1; + + dev_rrbs[0] = dev_1_rrbs; + dev_rrbs[1] = dev_2_rrbs; + dev_rrbs[2] = dev_3_rrbs; + dev_rrbs[3] = dev_4_rrbs; + + virt[0] = virt1; + virt[1] = virt2; + virt[2] = virt3; + virt[3] = virt4; + + if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { + return -1; + } + if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { + return -1; + } + /* walk through rrbs */ + for (i = 0; i < 4; i++) { + if (virt[i]) { + cur_rrb = i | 0xc; + cur_rrb = cur_rrb << (rrb_shift * 4); + rrb_shift--; + rrb_setting = rrb_setting | cur_rrb; + dev_rrbs[i] = dev_rrbs[i] - 1; + } + for (j = 0; j < dev_rrbs[i]; j++) { + cur_rrb = i | 0x8; + cur_rrb = cur_rrb << (rrb_shift * 4); + rrb_shift--; + rrb_setting = rrb_setting | cur_rrb; + } + } + + if (pcibr_soft) + s = pcibr_lock(pcibr_soft); + + bridge->b_rrb_map[even_odd].reg = rrb_setting; + + if (pcibr_soft) { + + pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; + + /* since we've "FIXED" the allocations + * for these slots, we probably can dispense + * with tracking avail/res/valid data, but + * keeping it up to date helps debugging. + */ + + pcibr_soft->bs_rrb_avail[even_odd] = + 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); + + pcibr_soft->bs_rrb_res[even_odd + 0] = 0; + pcibr_soft->bs_rrb_res[even_odd + 2] = 0; + pcibr_soft->bs_rrb_res[even_odd + 4] = 0; + pcibr_soft->bs_rrb_res[even_odd + 6] = 0; + + pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; + pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; + pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; + pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; + + pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; + pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; + pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; + pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; + + pcibr_unlock(pcibr_soft, s); + } + return 0; +} + +/* + * pcibr_rrb_flush: chase down all the RRBs assigned + * to the specified connection point, and flush + * them. + */ +void +pcibr_rrb_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + unsigned long s; + reg_p rrbp; + unsigned rrbm; + int i; + int rrbn; + unsigned sval; + unsigned mask; + + sval = BRIDGE_RRB_EN | (pciio_slot >> 1); + mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; + rrbn = pciio_slot & 1; + rrbp = &bridge->b_rrb_map[rrbn].reg; + + s = pcibr_lock(pcibr_soft); + rrbm = *rrbp; + for (i = 0; i < 8; ++i) { + if ((rrbm & mask) == sval) + do_pcibr_rrb_flush(bridge, rrbn); + rrbm >>= 4; + rrbn += 2; + } + pcibr_unlock(pcibr_soft, s); +} + +/* ===================================================================== + * Device(x) register management + */ + +/* pcibr_try_set_device: attempt to modify Device(x) + * for the specified slot on the specified bridge + * as requested in flags, limited to the specified + * bits. Returns which BRIDGE bits were in conflict, + * or ZERO if everything went OK. + * + * Caller MUST hold pcibr_lock when calling this function. + */ +LOCAL int +pcibr_try_set_device(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + unsigned flags, + bridgereg_t mask) +{ + bridge_t *bridge; + pcibr_soft_slot_t slotp; + bridgereg_t old; + bridgereg_t new; + bridgereg_t chg; + bridgereg_t bad; + bridgereg_t badpmu; + bridgereg_t badd32; + bridgereg_t badd64; + bridgereg_t fix; + unsigned long s; + bridgereg_t xmask; + + xmask = mask; + if (pcibr_soft->bs_xbridge) { + if (mask == BRIDGE_DEV_PMU_BITS) + xmask = XBRIDGE_DEV_PMU_BITS; + if (mask == BRIDGE_DEV_D64_BITS) + xmask = XBRIDGE_DEV_D64_BITS; + } + + slotp = &pcibr_soft->bs_slot[slot]; + + s = pcibr_lock(pcibr_soft); + + bridge = pcibr_soft->bs_base; + + old = slotp->bss_device; + + /* figure out what the desired + * Device(x) bits are based on + * the flags specified. + */ + + new = old; + + /* Currently, we inherit anything that + * the new caller has not specified in + * one way or another, unless we take + * action here to not inherit. + * + * This is needed for the "swap" stuff, + * since it could have been set via + * pcibr_endian_set -- altho note that + * any explicit PCIBR_BYTE_STREAM or + * PCIBR_WORD_VALUES will freely override + * the effect of that call (and vice + * versa, no protection either way). + * + * I want to get rid of pcibr_endian_set + * in favor of tracking DMA endianness + * using the flags specified when DMA + * channels are created. + */ + +#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) +#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) + + /* Do not use Barrier, Write Gather, + * or Prefetch unless asked. + * Leave everything else as it + * was from the last time. + */ + new = new + & ~BRIDGE_DEV_BARRIER + & ~BRIDGE_DEV_WRGA_BITS + & ~BRIDGE_DEV_PREF + ; + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { + new = (new + & ~BRIDGE_DEV_BARRIER) /* barrier off */ + | BRIDGE_DEV_PREF; /* prefetch on */ + + } + if (flags & PCIIO_DMA_CMD) { + new = ((new + & ~BRIDGE_DEV_PREF) /* prefetch off */ + & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ + | BRIDGE_DEV_BARRIER; /* barrier on */ + } + /* Generic detail flags + */ + if (flags & PCIIO_WRITE_GATHER) + new |= BRIDGE_DEV_WRGA_BITS; + if (flags & PCIIO_NOWRITE_GATHER) + new &= ~BRIDGE_DEV_WRGA_BITS; + + if (flags & PCIIO_PREFETCH) + new |= BRIDGE_DEV_PREF; + if (flags & PCIIO_NOPREFETCH) + new &= ~BRIDGE_DEV_PREF; + + if (flags & PCIBR_WRITE_GATHER) + new |= BRIDGE_DEV_WRGA_BITS; + if (flags & PCIBR_NOWRITE_GATHER) + new &= ~BRIDGE_DEV_WRGA_BITS; + + if (flags & PCIIO_BYTE_STREAM) + new |= (pcibr_soft->bs_xbridge) ? + BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; + if (flags & PCIIO_WORD_VALUES) + new &= (pcibr_soft->bs_xbridge) ? + ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; + + /* Provider-specific flags + */ + if (flags & PCIBR_PREFETCH) + new |= BRIDGE_DEV_PREF; + if (flags & PCIBR_NOPREFETCH) + new &= ~BRIDGE_DEV_PREF; + + if (flags & PCIBR_PRECISE) + new |= BRIDGE_DEV_PRECISE; + if (flags & PCIBR_NOPRECISE) + new &= ~BRIDGE_DEV_PRECISE; + + if (flags & PCIBR_BARRIER) + new |= BRIDGE_DEV_BARRIER; + if (flags & PCIBR_NOBARRIER) + new &= ~BRIDGE_DEV_BARRIER; + + if (flags & PCIBR_64BIT) + new |= BRIDGE_DEV_DEV_SIZE; + if (flags & PCIBR_NO64BIT) + new &= ~BRIDGE_DEV_DEV_SIZE; + + chg = old ^ new; /* what are we changing, */ + chg &= xmask; /* of the interesting bits */ + + if (chg) { + + badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; + if (pcibr_soft->bs_xbridge) { + badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; + badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; + } else { + badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; + badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; + } + bad = badpmu | badd32 | badd64; + + if (bad) { + + /* some conflicts can be resolved by + * forcing the bit on. this may cause + * some performance degredation in + * the stream(s) that want the bit off, + * but the alternative is not allowing + * the new stream at all. + */ + if ( (fix = bad & (BRIDGE_DEV_PRECISE | + BRIDGE_DEV_BARRIER)) ){ + bad &= ~fix; + /* don't change these bits if + * they are already set in "old" + */ + chg &= ~(fix & old); + } + /* some conflicts can be resolved by + * forcing the bit off. this may cause + * some performance degredation in + * the stream(s) that want the bit on, + * but the alternative is not allowing + * the new stream at all. + */ + if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | + BRIDGE_DEV_PREF)) ) { + bad &= ~fix; + /* don't change these bits if + * we wanted to turn them on. + */ + chg &= ~(fix & new); + } + /* conflicts in other bits mean + * we can not establish this DMA + * channel while the other(s) are + * still present. + */ + if (bad) { + pcibr_unlock(pcibr_soft, s); +#if (DEBUG && PCIBR_DEV_DEBUG) + printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); +#endif + return bad; + } + } + } + if (mask == BRIDGE_DEV_PMU_BITS) + slotp->bss_pmu_uctr++; + if (mask == BRIDGE_DEV_D32_BITS) + slotp->bss_d32_uctr++; + if (mask == BRIDGE_DEV_D64_BITS) + slotp->bss_d64_uctr++; + + /* the value we want to write is the + * original value, with the bits for + * our selected changes flipped, and + * with any disabled features turned off. + */ + new = old ^ chg; /* only change what we want to change */ + + if (slotp->bss_device == new) { + pcibr_unlock(pcibr_soft, s); + return 0; + } + bridge->b_device[slot].reg = new; + slotp->bss_device = new; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); +#endif + + return 0; +} + +void +pcibr_release_device(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + bridgereg_t mask) +{ + pcibr_soft_slot_t slotp; + unsigned long s; + + slotp = &pcibr_soft->bs_slot[slot]; + + s = pcibr_lock(pcibr_soft); + + if (mask == BRIDGE_DEV_PMU_BITS) + slotp->bss_pmu_uctr--; + if (mask == BRIDGE_DEV_D32_BITS) + slotp->bss_d32_uctr--; + if (mask == BRIDGE_DEV_D64_BITS) + slotp->bss_d64_uctr--; + + pcibr_unlock(pcibr_soft, s); +} + +/* + * flush write gather buffer for slot + */ +LOCAL void +pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, + pciio_slot_t slot) +{ + bridge_t *bridge; + unsigned long s; + volatile uint32_t wrf; + s = pcibr_lock(pcibr_soft); + bridge = pcibr_soft->bs_base; + wrf = bridge->b_wr_req_buf[slot].reg; + pcibr_unlock(pcibr_soft, s); +} + +/* ===================================================================== + * Bridge (pcibr) "Device Driver" entry points + */ + +/* + * pcibr_probe_slot: read a config space word + * while trapping any errors; reutrn zero if + * all went OK, or nonzero if there was an error. + * The value read, if any, is passed back + * through the valp parameter. + */ +LOCAL int +pcibr_probe_slot(bridge_t *bridge, + cfg_p cfg, + unsigned *valp) +{ + int rv; + bridgereg_t old_enable, new_enable; + int badaddr_val(volatile void *, int, volatile void *); + + + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + + bridge->b_int_enable = new_enable; + + /* + * The xbridge doesn't clear b_err_int_view unless + * multi-err is cleared... + */ + if (is_xbridge(bridge)) + if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { + bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; + } + + if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { + bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; + (void) bridge->b_wid_tflush; /* flushbus */ + } + rv = badaddr_val((void *) cfg, 4, valp); + + /* + * The xbridge doesn't set master timeout in b_int_status + * here. Fortunately it's in error_interrupt_view. + */ + if (is_xbridge(bridge)) + if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { + bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; + rv = 1; /* unoccupied slot */ + } + + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + return rv; +} + +/* + * pcibr_init: called once during system startup or + * when a loadable driver is loaded. + * + * The driver_register function should normally + * be in _reg, not _init. But the pcibr driver is + * required by devinit before the _reg routines + * are called, so this is an exception. + */ +void +pcibr_init(void) +{ +#if DEBUG && ATTACH_DEBUG + printk("pcibr_init\n"); +#endif + + xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, + XBRIDGE_WIDGET_MFGR_NUM, + "pcibr_", + 0); + xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, + BRIDGE_WIDGET_MFGR_NUM, + "pcibr_", + 0); +} + +/* + * open/close mmap/munmap interface would be used by processes + * that plan to map the PCI bridge, and muck around with the + * registers. This is dangerous to do, and will be allowed + * to a select brand of programs. Typically these are + * diagnostics programs, or some user level commands we may + * write to do some weird things. + * To start with expect them to have root priveleges. + * We will ask for more later. + */ +/* ARGSUSED */ +int +pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) +{ + return 0; +} + +/*ARGSUSED */ +int +pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) +{ + return 0; +} + +/*ARGSUSED */ +int +pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) +{ + int error; + devfs_handle_t vhdl = dev_to_vhdl(dev); + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge = pcibr_soft->bs_base; + + hwgraph_vertex_unref(pcibr_vhdl); + + ASSERT(pcibr_soft); + len = ctob(btoc(len)); /* Make len page aligned */ + error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); + + /* + * If the offset being mapped corresponds to the flash prom + * base, and if the mapping succeeds, and if the user + * has requested the protections to be WRITE, enable the + * flash prom to be written. + * + * XXX- deprecate this in favor of using the + * real flash driver ... + */ + if (!error && + ((off == BRIDGE_EXTERNAL_FLASH) || + (len > BRIDGE_EXTERNAL_FLASH))) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + return error; +} + +/*ARGSUSED */ +int +pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) +{ + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge = pcibr_soft->bs_base; + + hwgraph_vertex_unref(pcibr_vhdl); + + /* + * If flashprom write was enabled, disable it, as + * this is the last unmap. + */ + if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + return 0; +} + +/* This is special case code used by grio. There are plans to make + * this a bit more general in the future, but till then this should + * be sufficient. + */ +pciio_slot_t +pcibr_device_slot_get(devfs_handle_t dev_vhdl) +{ + char devname[MAXDEVNAME]; + devfs_handle_t tdev; + pciio_info_t pciio_info; + pciio_slot_t slot = PCIIO_SLOT_NONE; + + vertex_to_name(dev_vhdl, devname, MAXDEVNAME); + + /* run back along the canonical path + * until we find a PCI connection point. + */ + tdev = hwgraph_connectpt_get(dev_vhdl); + while (tdev != GRAPH_VERTEX_NONE) { + pciio_info = pciio_info_chk(tdev); + if (pciio_info) { + slot = pciio_info_slot_get(pciio_info); + break; + } + hwgraph_vertex_unref(tdev); + tdev = hwgraph_connectpt_get(tdev); + } + hwgraph_vertex_unref(tdev); + + return slot; +} + +/*========================================================================== + * BRIDGE PCI SLOT RELATED IOCTLs + */ +char *pci_space_name[] = {"NONE", + "ROM", + "IO", + "", + "MEM", + "MEM32", + "MEM64", + "CFG", + "WIN0", + "WIN1", + "WIN2", + "WIN3", + "WIN4", + "WIN5", + "", + "BAD"}; + + +#ifdef LATER + +void +pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, + int func, + pcibr_slot_func_info_resp_t funcp) +{ + pcibr_info_t pcibr_info = pcibr_infoh[func]; + int win; + + funcp->resp_f_status = 0; + + if (!pcibr_info) { + return; + } + + funcp->resp_f_status |= FUNC_IS_VALID; +#ifdef SUPPORT_PRINTING_V_FORMAT + sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); +#else + sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex); +#endif + + if(is_sys_critical_vertex(pcibr_info->f_vertex)) { + funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; + } + + funcp->resp_f_bus = pcibr_info->f_bus; + funcp->resp_f_slot = pcibr_info->f_slot; + funcp->resp_f_func = pcibr_info->f_func; +#ifdef SUPPORT_PRINTING_V_FORMAT + sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); +#else + sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master); +#endif + funcp->resp_f_pops = pcibr_info->f_pops; + funcp->resp_f_efunc = pcibr_info->f_efunc; + funcp->resp_f_einfo = pcibr_info->f_einfo; + + funcp->resp_f_vendor = pcibr_info->f_vendor; + funcp->resp_f_device = pcibr_info->f_device; + + for(win = 0 ; win < 6 ; win++) { + funcp->resp_f_window[win].resp_w_base = + pcibr_info->f_window[win].w_base; + funcp->resp_f_window[win].resp_w_size = + pcibr_info->f_window[win].w_size; + sprintf(funcp->resp_f_window[win].resp_w_space, + "%s", + pci_space_name[pcibr_info->f_window[win].w_space]); + } + + funcp->resp_f_rbase = pcibr_info->f_rbase; + funcp->resp_f_rsize = pcibr_info->f_rsize; + + for (win = 0 ; win < 4; win++) { + funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; + } + + funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; + +} + +int +pcibr_slot_info_return(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pcibr_slot_info_resp_t respp) +{ + pcibr_soft_slot_t pss; + int func; + bridge_t *bridge = pcibr_soft->bs_base; + reg_p b_respp; + pcibr_slot_info_resp_t slotp; + pcibr_slot_func_info_resp_t funcp; + + slotp = snia_kmem_zalloc(sizeof(*slotp), KM_SLEEP); + if (slotp == NULL) { + return(ENOMEM); + } + + pss = &pcibr_soft->bs_slot[slot]; + + printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot); + + slotp->resp_has_host = pss->has_host; + slotp->resp_host_slot = pss->host_slot; +#ifdef SUPPORT_PRINTING_V_FORMAT + sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); +#else + sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn); +#endif + slotp->resp_slot_status = pss->slot_status; + slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); + + if (is_sys_critical_vertex(pss->slot_conn)) { + slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; + } + + slotp->resp_bss_ninfo = pss->bss_ninfo; + + for (func = 0; func < pss->bss_ninfo; func++) { + funcp = &(slotp->resp_func[func]); + pcibr_slot_func_info_return(pss->bss_infos, func, funcp); + } + + sprintf(slotp->resp_bss_devio_bssd_space, "%s", + pci_space_name[pss->bss_devio.bssd_space]); + slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; + slotp->resp_bss_device = pss->bss_device; + + slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; + slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; + slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; + + slotp->resp_bss_d64_base = pss->bss_d64_base; + slotp->resp_bss_d64_flags = pss->bss_d64_flags; + slotp->resp_bss_d32_base = pss->bss_d32_base; + slotp->resp_bss_d32_flags = pss->bss_d32_flags; + + slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active); + + slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; + slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; + + slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; + slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; + + if (slot & 1) { + b_respp = &bridge->b_odd_resp; + } else { + b_respp = &bridge->b_even_resp; + } + + slotp->resp_b_resp = *b_respp; + + slotp->resp_b_int_device = bridge->b_int_device; + slotp->resp_b_int_enable = bridge->b_int_enable; + slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; + + if (COPYOUT(slotp, respp, sizeof(*respp))) { + return(EFAULT); + } + + snia_kmem_free(slotp, sizeof(*slotp)); + + return(0); +} + +/* + * pcibr_slot_query + * Return information about the PCI slot maintained by the infrastructure. + * Information is requested in the request structure. + * + * Information returned in the response structure: + * Slot hwgraph name + * Vendor/Device info + * Base register info + * Interrupt mapping from device pins to the bridge pins + * Devio register + * Software RRB info + * RRB register info + * Host/Gues info + * PCI Bus #,slot #, function # + * Slot provider hwgraph name + * Provider Functions + * Error handler + * DMA mapping usage counters + * DMA direct translation info + * External SSRAM workaround info + */ +int +pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pciio_slot_t slot = reqp->req_slot; + pciio_slot_t tmp_slot; + pcibr_slot_info_resp_t respp = (pcibr_slot_info_resp_t) reqp->req_respp; + int size = reqp->req_size; + int error; + + /* Make sure that we are dealing with a bridge device vertex */ + if (!pcibr_soft) { + return(EINVAL); + } + + /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ + if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { + return(EINVAL); + } + + /* Return information for the requested PCI slot */ + if (slot != PCIIO_SLOT_NONE) { + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[slot].slot_lock); + + return(error); + } + + /* Return information for all the slots */ + for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { + + if (size < sizeof(*respp)) { + return(EINVAL); + } + + /* Acquire read access to the slot */ + mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); + + /* Release the slot lock */ + mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock); + + if (error) { + return(error); + } + + ++respp; + size -= sizeof(*respp); + } + + return(error); +} +#endif /* LATER */ + + +/*ARGSUSED */ +int +pcibr_ioctl(devfs_handle_t dev, + int cmd, + void *arg, + int flag, + struct cred *cr, + int *rvalp) +{ + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); +#ifdef LATER + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); +#endif + int error = 0; + + hwgraph_vertex_unref(pcibr_vhdl); + + switch (cmd) { +#ifdef LATER + case GIOCSETBW: + { + grio_ioctl_info_t info; + pciio_slot_t slot = 0; + + if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { + error = EFAULT; + break; + } +#ifdef GRIO_DEBUG + printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", + info.prev_vhdl, info.reqbw); +#endif /* GRIO_DEBUG */ + + if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == + PCIIO_SLOT_NONE) { + error = EIO; + break; + } + if (info.reqbw) + pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); + break; + } + + case GIOCRELEASEBW: + { + grio_ioctl_info_t info; + pciio_slot_t slot = 0; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { + error = EFAULT; + break; + } +#ifdef GRIO_DEBUG + printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", + info.prev_vhdl, info.reqbw); +#endif /* GRIO_DEBUG */ + + if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == + PCIIO_SLOT_NONE) { + error = EIO; + break; + } + if (info.reqbw) + pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); + break; + } + + case PCIBR_SLOT_POWERUP: + { + pciio_slot_t slot; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + slot = (pciio_slot_t)(uint64_t)arg; + error = pcibr_slot_powerup(pcibr_vhdl,slot); + break; + } + case PCIBR_SLOT_SHUTDOWN: + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + slot = (pciio_slot_t)(uint64_t)arg; + error = pcibr_slot_powerup(pcibr_vhdl,slot); + break; + } + case PCIBR_SLOT_QUERY: + { + struct pcibr_slot_info_req_s req; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_query(pcibr_vhdl, &req); + break; + } +#endif /* LATER */ + default: + break; + + } + + return error; +} + +void +pcibr_freeblock_sub(iopaddr_t *free_basep, + iopaddr_t *free_lastp, + iopaddr_t base, + size_t size) +{ + iopaddr_t free_base = *free_basep; + iopaddr_t free_last = *free_lastp; + iopaddr_t last = base + size - 1; + + if ((last < free_base) || (base > free_last)); /* free block outside arena */ + + else if ((base <= free_base) && (last >= free_last)) + /* free block contains entire arena */ + *free_basep = *free_lastp = 0; + + else if (base <= free_base) + /* free block is head of arena */ + *free_basep = last + 1; + + else if (last >= free_last) + /* free block is tail of arena */ + *free_lastp = base - 1; + + /* + * We are left with two regions: the free area + * in the arena "below" the block, and the free + * area in the arena "above" the block. Keep + * the one that is bigger. + */ + + else if ((base - free_base) > (free_last - last)) + *free_lastp = base - 1; /* keep lower chunk */ + else + *free_basep = last + 1; /* keep upper chunk */ +} + +/* Convert from ssram_bits in control register to number of SSRAM entries */ +#define ATE_NUM_ENTRIES(n) _ate_info[n] + +/* Possible choices for number of ATE entries in Bridge's SSRAM */ +LOCAL int _ate_info[] = +{ + 0, /* 0 entries */ + 8 * 1024, /* 8K entries */ + 16 * 1024, /* 16K entries */ + 64 * 1024 /* 64K entries */ +}; + +#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) +#define ATE_PROBE_VALUE 0x0123456789abcdefULL + +/* + * Determine the size of this bridge's external mapping SSRAM, and set + * the control register appropriately to reflect this size, and initialize + * the external SSRAM. + */ +LOCAL int +pcibr_init_ext_ate_ram(bridge_t *bridge) +{ + int largest_working_size = 0; + int num_entries, entry; + int i, j; + bridgereg_t old_enable, new_enable; + int s; + + /* Probe SSRAM to determine its size. */ + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; + + for (i = 1; i < ATE_NUM_SIZES; i++) { + /* Try writing a value */ + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; + + /* Guard against wrap */ + for (j = 1; j < i; j++) + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; + + /* See if value was written */ + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + largest_working_size = i; + } + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + + s = splhi(); + bridge->b_wid_control = (bridge->b_wid_control + & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) + | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + + num_entries = ATE_NUM_ENTRIES(largest_working_size); + +#if PCIBR_ATE_DEBUG + if (num_entries) + printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); + else + printk("bridge at 0x%x: no externa9422l ATE RAM found\n", bridge); +#endif + + /* Initialize external mapping entries */ + for (entry = 0; entry < num_entries; entry++) + bridge->b_ext_ate_ram[entry] = 0; + + return (num_entries); +} + +/* + * Allocate "count" contiguous Bridge Address Translation Entries + * on the specified bridge to be used for PCI to XTALK mappings. + * Indices in rm map range from 1..num_entries. Indicies returned + * to caller range from 0..num_entries-1. + * + * Return the start index on success, -1 on failure. + */ +LOCAL int +pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) +{ + int index = 0; + + index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); +/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ + + if (!index && pcibr_soft->bs_ext_ate_map) + index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); + + /* rmalloc manages resources in the 1..n + * range, with 0 being failure. + * pcibr_ate_alloc manages resources + * in the 0..n-1 range, with -1 being failure. + */ + return index - 1; +} + +LOCAL void +pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) +/* Who says there's no such thing as a free meal? :-) */ +{ + /* note the "+1" since rmalloc handles 1..n but + * we start counting ATEs at zero. + */ +/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ + + rmfree((index < pcibr_soft->bs_int_ate_size) + ? pcibr_soft->bs_int_ate_map + : pcibr_soft->bs_ext_ate_map, + count, index + 1); +} + +LOCAL pcibr_info_t +pcibr_info_get(devfs_handle_t vhdl) +{ + return (pcibr_info_t) pciio_info_get(vhdl); +} + +pcibr_info_t +pcibr_device_info_new( + pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pciio_function_t rfunc, + pciio_vendor_id_t vendor, + pciio_device_id_t device) +{ + pcibr_info_t pcibr_info; + pciio_function_t func; + int ibit; + + func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; + + NEW(pcibr_info); + pciio_device_info_new(&pcibr_info->f_c, + pcibr_soft->bs_vhdl, + slot, rfunc, + vendor, device); + + if (slot != PCIIO_SLOT_NONE) { + + /* + * Currently favored mapping from PCI + * slot number and INTA/B/C/D to Bridge + * PCI Interrupt Bit Number: + * + * SLOT A B C D + * 0 0 4 0 4 + * 1 1 5 1 5 + * 2 2 6 2 6 + * 3 3 7 3 7 + * 4 4 0 4 0 + * 5 5 1 5 1 + * 6 6 2 6 2 + * 7 7 3 7 3 + * + * XXX- allow pcibr_hints to override default + * XXX- allow ADMIN to override pcibr_hints + */ + for (ibit = 0; ibit < 4; ++ibit) + pcibr_info->f_ibit[ibit] = + (slot + 4 * ibit) & 7; + + /* + * Record the info in the sparse func info space. + */ + if (func < pcibr_soft->bs_slot[slot].bss_ninfo) + pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; + } + return pcibr_info; +} + +void +pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pcibr_info_t pcibr_info; + pciio_function_t func; + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; + int nfunc = slotp->bss_ninfo; + + + for (func = 0; func < nfunc; func++) { + pcibr_info = slotp->bss_infos[func]; + + if (!pcibr_info) + continue; + + slotp->bss_infos[func] = 0; + pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); + pciio_device_info_free(&pcibr_info->f_c); + DEL(pcibr_info); + } + + /* Clear the DEVIO(x) for this slot */ + slotp->bss_devio.bssd_space = PCIIO_SPACE_NONE; + slotp->bss_devio.bssd_base = PCIBR_D32_BASE_UNSET; + slotp->bss_device = 0; + + + /* Reset the mapping usage counters */ + slotp->bss_pmu_uctr = 0; + slotp->bss_d32_uctr = 0; + slotp->bss_d64_uctr = 0; + + /* Clear the Direct translation info */ + slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; + slotp->bss_d64_flags = 0; + slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; + slotp->bss_d32_flags = 0; + + /* Clear out shadow info necessary for the external SSRAM workaround */ + slotp->bss_ext_ates_active = ATOMIC_INIT(0); + slotp->bss_cmd_pointer = 0; + slotp->bss_cmd_shadow = 0; + +} + +/* + * PCI_ADDR_SPACE_LIMITS_LOAD + * Gets the current values of + * pci io base, + * pci io last, + * pci low memory base, + * pci low memory last, + * pci high memory base, + * pci high memory last + */ +#define PCI_ADDR_SPACE_LIMITS_LOAD() \ + pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ + pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ + pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ + pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ + pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ + pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; +/* + * PCI_ADDR_SPACE_LIMITS_STORE + * Sets the current values of + * pci io base, + * pci io last, + * pci low memory base, + * pci low memory last, + * pci high memory base, + * pci high memory last + */ +#define PCI_ADDR_SPACE_LIMITS_STORE() \ + pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ + pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ + pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ + pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ + pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ + pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; + +#define PCI_ADDR_SPACE_LIMITS_PRINT() \ + printf("+++++++++++++++++++++++\n" \ + "IO base 0x%x last 0x%x\n" \ + "SWIN base 0x%x last 0x%x\n" \ + "MEM base 0x%x last 0x%x\n" \ + "+++++++++++++++++++++++\n", \ + pcibr_soft->bs_spinfo.pci_io_base, \ + pcibr_soft->bs_spinfo.pci_io_last, \ + pcibr_soft->bs_spinfo.pci_swin_base, \ + pcibr_soft->bs_spinfo.pci_swin_last, \ + pcibr_soft->bs_spinfo.pci_mem_base, \ + pcibr_soft->bs_spinfo.pci_mem_last); + +/* + * pcibr_slot_info_init + * Probe for this slot and see if it is populated. + * If it is populated initialize the generic PCI infrastructural + * information associated with this particular PCI device. + */ +int +pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + cfg_p cfgw; + unsigned idword; + unsigned pfail; + unsigned idwords[8]; + pciio_vendor_id_t vendor; + pciio_device_id_t device; + unsigned htype; + cfg_p wptr; + int win; + pciio_space_t space; + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + int nfunc; + pciio_function_t rfunc; + int func; + devfs_handle_t conn_vhdl; + pcibr_soft_slot_t slotp; + + /* Get the basic software information required to proceed */ + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + if (!PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization + * is done by the host slot then we are done. + */ + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + /* Check for a slot with any system critical functions */ + if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + /* Load the current values of allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); + + /* Try to read the device-id/vendor-id from the config space */ + cfgw = bridge->b_type0_cfg_dev[slot].l; + + if (pcibr_probe_slot(bridge, cfgw, &idword)) + return(ENODEV); + + slotp = &pcibr_soft->bs_slot[slot]; + slotp->slot_status |= SLOT_POWER_UP; + + vendor = 0xFFFF & idword; + /* If the vendor id is not valid then the slot is not populated + * and we are done. + */ + if (vendor == 0xFFFF) + return(ENODEV); + + device = 0xFFFF & (idword >> 16); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); + + nfunc = 1; + rfunc = PCIIO_FUNC_NONE; + pfail = 0; + + /* NOTE: if a card claims to be multifunction + * but only responds to config space 0, treat + * it as a unifunction card. + */ + + if (htype & 0x80) { /* MULTIFUNCTION */ + for (func = 1; func < 8; ++func) { + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { + pfail |= 1 << func; + continue; + } + vendor = 0xFFFF & idwords[func]; + if (vendor == 0xFFFF) { + pfail |= 1 << func; + continue; + } + nfunc = func + 1; + rfunc = 0; + } + cfgw = bridge->b_type0_cfg_dev[slot].l; + } + NEWA(pcibr_infoh, nfunc); + + pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; + pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; + + for (func = 0; func < nfunc; ++func) { + unsigned cmd_reg; + + if (func) { + if (pfail & (1 << func)) + continue; + + idword = idwords[func]; + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + + device = 0xFFFF & (idword >> 16); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); + rfunc = func; + } + htype &= 0x7f; + if (htype != 0x00) { + printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", + pcibr_soft->bs_name, slot, func, htype); + continue; + } +#if DEBUG && ATTACH_DEBUG + printk(KERN_NOTICE + "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", + pcibr_soft->bs_name, slot, func, vendor, device); +#endif + + pcibr_info = pcibr_device_info_new + (pcibr_soft, slot, rfunc, vendor, device); + conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); + if (func == 0) + slotp->slot_conn = conn_vhdl; + +#ifdef LITTLE_ENDIAN + cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4]; +#else + cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; +#endif + + wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; + + for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { + iopaddr_t base, mask, code; + size_t size; + + /* + * GET THE BASE & SIZE OF THIS WINDOW: + * + * The low two or four bits of the BASE register + * determines which address space we are in; the + * rest is a base address. BASE registers + * determine windows that are power-of-two sized + * and naturally aligned, so we can get the size + * of a window by writing all-ones to the + * register, reading it back, and seeing which + * bits are used for decode; the least + * significant nonzero bit is also the size of + * the window. + * + * WARNING: someone may already have allocated + * some PCI space to this window, and in fact + * PIO may be in process at this very moment + * from another processor (or even from this + * one, if we get interrupted)! So, if the BASE + * already has a nonzero address, be generous + * and use the LSBit of that address as the + * size; this could overstate the window size. + * Usually, when one card is set up, all are set + * up; so, since we don't bitch about + * overlapping windows, we are ok. + * + * UNFORTUNATELY, some cards do not clear their + * BASE registers on reset. I have two heuristics + * that can detect such cards: first, if the + * decode enable is turned off for the space + * that the window uses, we can disregard the + * initial value. second, if the address is + * outside the range that we use, we can disregard + * it as well. + * + * This is looking very PCI generic. Except for + * knowing how many slots and where their config + * spaces are, this window loop and the next one + * could probably be shared with other PCI host + * adapters. It would be interesting to see if + * this could be pushed up into pciio, when we + * start supporting more PCI providers. + */ +#ifdef LITTLE_ENDIAN + base = wptr[((win*4)^4)/4]; +#else + base = wptr[win]; +#endif + + if (base & PCI_BA_IO_SPACE) { + /* BASE is in I/O space. */ + space = PCIIO_SPACE_IO; + mask = -4; + code = base & 3; + base = base & mask; + if (base == 0) { + ; /* not assigned */ + } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { + base = 0; /* decode not enabled */ + } + } else { + /* BASE is in MEM space. */ + space = PCIIO_SPACE_MEM; + mask = -16; + code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ + base = base & mask; + if (base == 0) { + ; /* not assigned */ + } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { + base = 0; /* decode not enabled */ + } else if (base & 0xC0000000) { + base = 0; /* outside permissable range */ + } else if ((code == PCI_BA_MEM_64BIT) && +#ifdef LITTLE_ENDIAN + (wptr[(((win + 1)*4)^4)/4] != 0)) { +#else + (wptr[win + 1] != 0)) { +#endif /* LITTLE_ENDIAN */ + base = 0; /* outside permissable range */ + } + } + + if (base != 0) { /* estimate size */ + size = base & -base; + } else { /* calculate size */ +#ifdef LITTLE_ENDIAN + wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ + size = wptr[((win*4)^4)/4]; /* get stored bits */ +#else + wptr[win] = ~0; /* turn on all bits */ + size = wptr[win]; /* get stored bits */ +#endif /* LITTLE_ENDIAN */ + size &= mask; /* keep addr */ + size &= -size; /* keep lsbit */ + if (size == 0) + continue; + } + + pcibr_info->f_window[win].w_space = space; + pcibr_info->f_window[win].w_base = base; + pcibr_info->f_window[win].w_size = size; + + /* + * If this window already has PCI space + * allocated for it, "subtract" that space from + * our running freeblocks. Don't worry about + * overlaps in existing allocated windows; we + * may be overstating their sizes anyway. + */ + + if (base && size) { + if (space == PCIIO_SPACE_IO) { + pcibr_freeblock_sub(&pci_io_fb, + &pci_io_fl, + base, size); + } else { + pcibr_freeblock_sub(&pci_lo_fb, + &pci_lo_fl, + base, size); + pcibr_freeblock_sub(&pci_hi_fb, + &pci_hi_fl, + base, size); + } + } +#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) + /* + * IOC3 BASE_ADDR* BUG WORKAROUND + * + + * If we write to BASE1 on the IOC3, the + * data in BASE0 is replaced. The + * original workaround was to remember + * the value of BASE0 and restore it + * when we ran off the end of the BASE + * registers; however, a later + * workaround was added (I think it was + * rev 1.44) to avoid setting up + * anything but BASE0, with the comment + * that writing all ones to BASE1 set + * the enable-parity-error test feature + * in IOC3's SCR bit 14. + * + * So, unless we defer doing any PCI + * space allocation until drivers + * attach, and set up a way for drivers + * (the IOC3 in paricular) to tell us + * generically to keep our hands off + * BASE registers, we gotta "know" about + * the IOC3 here. + * + * Too bad the PCI folks didn't reserve the + * all-zero value for 'no BASE here' (it is a + * valid code for an uninitialized BASE in + * 32-bit PCI memory space). + */ + + if ((vendor == IOC3_VENDOR_ID_NUM) && + (device == IOC3_DEVICE_ID_NUM)) + break; +#endif + if (code == PCI_BA_MEM_64BIT) { + win++; /* skip upper half */ +#ifdef LITTLE_ENDIAN + wptr[((win*4)^4)/4] = 0; /* which must be zero */ +#else + wptr[win] = 0; /* which must be zero */ +#endif /* LITTLE_ENDIAN */ + } + } /* next win */ + } /* next func */ + + /* Store back the values for allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_STORE(); + return(0); +} + +/* + * pcibr_slot_info_free + * Remove all the PCI infrastructural information associated + * with a particular PCI device. + */ +int +pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + int nfunc; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + + pcibr_device_info_free(pcibr_vhdl, slot); + + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + DELA(pcibr_infoh,nfunc); + pcibr_soft->bs_slot[slot].bss_ninfo = 0; + + return(0); +} + +int as_debug = 0; +/* + * pcibr_slot_addr_space_init + * Reserve chunks of PCI address space as required by + * the base registers in the card. + */ +int +pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + size_t align; + iopaddr_t mask; + int nbars; + int nfunc; + int func; + int win; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* Get the current values for the allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); + + if (as_debug) +#ifdef LATER + PCI_ADDR_SPACE_LIMITS_PRINT(); +#endif + /* allocate address space, + * for windows that have not been + * previously assigned. + */ + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + if (nfunc < 1) + return(EINVAL); + + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + if (!pcibr_infoh) + return(EINVAL); + + /* + * Try to make the DevIO windows not + * overlap by pushing the "io" and "hi" + * allocation areas up to the next one + * or two megabyte bound. This also + * keeps them from being zero. + * + * DO NOT do this with "pci_lo" since + * the entire "lo" area is only a + * megabyte, total ... + */ + align = (slot < 2) ? 0x200000 : 0x100000; + mask = -align; + pci_io_fb = (pci_io_fb + align - 1) & mask; + pci_hi_fb = (pci_hi_fb + align - 1) & mask; + + for (func = 0; func < nfunc; ++func) { + cfg_p cfgw; + cfg_p wptr; + pciio_space_t space; + iopaddr_t base; + size_t size; + cfg_p pci_cfg_cmd_reg_p; + unsigned pci_cfg_cmd_reg; + unsigned pci_cfg_cmd_reg_add = 0; + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; + + nbars = PCI_CFG_BASE_ADDRS; + + for (win = 0; win < nbars; ++win) { + + space = pcibr_info->f_window[win].w_space; + base = pcibr_info->f_window[win].w_base; + size = pcibr_info->f_window[win].w_size; + + if (size < 1) + continue; + + if (base >= size) { +#if DEBUG && PCI_DEBUG + printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", + slot, func, win, space, base, base + size - 1); +#endif + continue; /* already allocated */ + } + align = size; /* ie. 0x00001000 */ + if (align < _PAGESZ) + align = _PAGESZ; /* ie. 0x00004000 */ + mask = -align; /* ie. 0xFFFFC000 */ + + switch (space) { + case PCIIO_SPACE_IO: + base = (pci_io_fb + align - 1) & mask; + if ((base + size) > pci_io_fl) { + base = 0; + break; + } + pci_io_fb = base + size; + break; + + case PCIIO_SPACE_MEM: +#ifdef LITTLE_ENDIAN + if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == +#else + if ((wptr[win] & PCI_BA_MEM_LOCATION) == +#endif /* LITTLE_ENDIAN */ + PCI_BA_MEM_1MEG) { + /* allocate from 20-bit PCI space */ + base = (pci_lo_fb + align - 1) & mask; + if ((base + size) > pci_lo_fl) { + base = 0; + break; + } + pci_lo_fb = base + size; + } else { + /* allocate from 32-bit or 64-bit PCI space */ + base = (pci_hi_fb + align - 1) & mask; + if ((base + size) > pci_hi_fl) { + base = 0; + break; + } + pci_hi_fb = base + size; + } + break; + + default: + base = 0; +#if DEBUG && PCI_DEBUG + printk("pcibr: slot %d window %d had bad space code %d\n", + slot, win, space); +#endif + } + pcibr_info->f_window[win].w_base = base; +#ifdef LITTLE_ENDIAN + wptr[((win*4)^4)/4] = base; +#if DEBUG && PCI_DEBUG + printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); +#endif +#else + wptr[win] = base; +#endif /* LITTLE_ENDIAN */ + +#if DEBUG && PCI_DEBUG + if (base >= size) + printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", + slot, func, win, space, base, base + size - 1); + else + printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", + slot, func, win, size, space); +#endif + } /* next base */ + + /* + * Allocate space for the EXPANSION ROM + * NOTE: DO NOT DO THIS ON AN IOC3, + * as it blows the system away. + */ + base = size = 0; + if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || + (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { + + wptr = cfgw + PCI_EXPANSION_ROM / 4; +#ifdef LITTLE_ENDIAN + wptr[1] = 0xFFFFF000; + mask = wptr[1]; +#else + *wptr = 0xFFFFF000; + mask = *wptr; +#endif /* LITTLE_ENDIAN */ + if (mask & 0xFFFFF000) { + size = mask & -mask; + align = size; + if (align < _PAGESZ) + align = _PAGESZ; + mask = -align; + base = (pci_hi_fb + align - 1) & mask; + if ((base + size) > pci_hi_fl) + base = size = 0; + else { + pci_hi_fb = base + size; +#ifdef LITTLE_ENDIAN + wptr[1] = base; +#else + *wptr = base; +#endif /* LITTLE_ENDIAN */ +#if DEBUG && PCI_DEBUG + printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", + pcibr_soft->bs_name, slot, + base, base + size - 1); +#endif + } + } + } + pcibr_info->f_rbase = base; + pcibr_info->f_rsize = size; + + /* + * if necessary, update the board's + * command register to enable decoding + * in the windows we added. + * + * There are some bits we always want to + * be sure are set. + */ + pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; + + /* + * The Adaptec 1160 FC Controller WAR #767995: + * The part incorrectly ignores the upper 32 bits of a 64 bit + * address when decoding references to it's registers so to + * keep it from responding to a bus cycle that it shouldn't + * we only use I/O space to get at it's registers. Don't + * enable memory space accesses on that PCI device. + */ + #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ + #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ + + if ((pcibr_info->f_vendor != FCADP_VENDID) || + (pcibr_info->f_device != FCADP_DEVID)) + pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + + pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; + + pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; + pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; +#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ + if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) + fast_back_to_back_enable = 0; +#endif + pci_cfg_cmd_reg &= 0xFFFF; + if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) + *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; + + } /* next func */ + + /* Now that we have allocated new chunks of PCI address spaces to this + * card we need to update the bookkeeping values which indicate + * the current PCI address space allocations. + */ + PCI_ADDR_SPACE_LIMITS_STORE(); + return(0); +} + +/* + * pcibr_slot_device_init + * Setup the device register in the bridge for this PCI slot. + */ +int +pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + bridgereg_t devreg; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* + * Adjustments to Device(x) + * and init of bss_device shadow + */ + devreg = bridge->b_device[slot].reg; + devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; + devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; +#ifdef LITTLE_ENDIAN + devreg |= BRIDGE_DEV_DEV_SWAP; +#endif + pcibr_soft->bs_slot[slot].bss_device = devreg; + bridge->b_device[slot].reg = devreg; + +#if DEBUG && PCI_DEBUG + printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); +#endif + +#if DEBUG && PCI_DEBUG + printk("pcibr: PCI space allocation done.\n"); +#endif + + return(0); +} + +/* + * pcibr_slot_guest_info_init + * Setup the host/guest relations for a PCI slot. + */ +int +pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + pcibr_soft_slot_t slotp; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + slotp = &pcibr_soft->bs_slot[slot]; + + /* create info and verticies for guest slots; + * for compatibilitiy macros, create info + * for even unpopulated slots (but do not + * build verticies for them). + */ + if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { + NEWA(pcibr_infoh, 1); + pcibr_soft->bs_slot[slot].bss_ninfo = 1; + pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; + + pcibr_info = pcibr_device_info_new + (pcibr_soft, slot, PCIIO_FUNC_NONE, + PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + + if (pcibr_soft->bs_slot[slot].has_host) { + slotp->slot_conn = pciio_device_info_register + (pcibr_vhdl, &pcibr_info->f_c); + } + } + + /* generate host/guest relations + */ + if (pcibr_soft->bs_slot[slot].has_host) { + int host = pcibr_soft->bs_slot[slot].host_slot; + pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; + + hwgraph_edge_add(slotp->slot_conn, + host_slotp->slot_conn, + EDGE_LBL_HOST); + + /* XXX- only gives us one guest edge per + * host. If/when we have a host with more than + * one guest, we will need to figure out how + * the host finds all its guests, and sorts + * out which one is which. + */ + hwgraph_edge_add(host_slotp->slot_conn, + slotp->slot_conn, + EDGE_LBL_GUEST); + } + + return(0); +} + +/* + * pcibr_slot_initial_rrb_alloc + * Allocate a default number of rrbs for this slot on + * the two channels. This is dictated by the rrb allocation + * strategy routine defined per platform. + */ + +int +pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + int c0, c1; + int r; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* How may RRBs are on this slot? + */ + c0 = do_pcibr_rrb_count_valid(bridge, slot); + c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); + +#if PCIBR_RRB_DEBUG + printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); +#endif + + /* Do we really need any? + */ + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + pcibr_info = pcibr_infoh[0]; + if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && + !pcibr_soft->bs_slot[slot].has_host) { + if (c0 > 0) + do_pcibr_rrb_free(bridge, slot, c0); + if (c1 > 0) + do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); + pcibr_soft->bs_rrb_valid[slot] = 0x1000; + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; + return(ENODEV); + } + + pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; + pcibr_soft->bs_rrb_valid[slot] = c0; + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; + + pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); + pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); + + r = 3 - (c0 + c1); + + if (r > 0) { + pcibr_soft->bs_rrb_res[slot] = r; + pcibr_soft->bs_rrb_avail[slot & 1] -= r; + } + +#if PCIBR_RRB_DEBUG + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + printk("\n"); +#endif + + return(0); +} + +/* + * pcibr_slot_call_device_attach + * This calls the associated driver attach routine for the PCI + * card in this slot. + */ +int +pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + async_attach_t aa = NULL; + int func; + devfs_handle_t xconn_vhdl,conn_vhdl; + int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + + if (pcibr_soft->bs_slot[slot].has_host) { + return(EPERM); + } + + xconn_vhdl = pcibr_soft->bs_conn; + aa = async_attach_get_info(xconn_vhdl); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + +#ifdef LATER + /* + * Activate if and when we support cdl. + */ + if (aa) + async_attach_add_info(conn_vhdl, aa); +#endif /* LATER */ + + error_func = pciio_device_attach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; + } + + return(error); +} + +/* + * pcibr_slot_call_device_detach + * This calls the associated driver detach routine for the PCI + * card in this slot. + */ +int +pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + int func; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + if (pcibr_soft->bs_slot[slot].has_host) + return(EPERM); + + /* Make sure that we do not detach a system critical function vertex */ + if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + + error_func = pciio_device_detach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } else { + if (conn_vhdl != GRAPH_VERTEX_NONE) + pcibr_device_unregister(conn_vhdl); + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; + } + + return(error); +} + +/* + * pcibr_slot_detach + * This is a place holder routine to keep track of all the + * slot-specific freeing that needs to be done. + */ +int +pcibr_slot_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + int error; + + /* Call the device detach function */ + error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); + return (error); + +} + +/* + * pcibr_is_slot_sys_critical + * Check slot for any functions that are system critical. + * Return 1 if any are system critical or 0 otherwise. + * + * This function will always return 0 when called by + * pcibr_attach() because the system critical vertices + * have not yet been set in the hwgraph. + */ +int +pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int func; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(0); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + if (is_sys_critical_vertex(conn_vhdl)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); +#else + printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); +#endif + return(1); + } + + } + + return(0); +} + +/* + * pcibr_device_unregister + * This frees up any hardware resources reserved for this PCI device + * and removes any PCI infrastructural information setup for it. + * This is usually used at the time of shutting down of the PCI card. + */ +int +pcibr_device_unregister(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + int error_call; + int error = 0; + + pciio_info = pciio_info_get(pconn_vhdl); + + pcibr_vhdl = pciio_info_master_get(pciio_info); + slot = pciio_info_slot_get(pciio_info); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + + /* Clear all the hardware xtalk resources for this device */ + xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); + + /* Flush all the rrbs */ + pcibr_rrb_flush(pconn_vhdl); + + /* Free the rrbs allocated to this slot */ + error_call = do_pcibr_rrb_free(bridge, slot, + pcibr_soft->bs_rrb_valid[slot] + + pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]); + + if (error_call) + error = ERANGE; + + pcibr_soft->bs_rrb_valid[slot] = 0; + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; + pcibr_soft->bs_rrb_res[slot] = 0; + + /* Flush the write buffers !! */ + error_call = pcibr_wrb_flush(pconn_vhdl); + + if (error_call) + error = error_call; + + /* Clear the information specific to the slot */ + error_call = pcibr_slot_info_free(pcibr_vhdl, slot); + + if (error_call) + error = error_call; + + return(error); + +} + +/* + * build a convenience link path in the + * form of "...//bus/" + * + * returns 1 on success, 0 otherwise + * + * depends on hwgraph separator == '/' + */ +int +pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) +{ + char dst[MAXDEVNAME]; + char *dp = dst; + char *cp, *xp; + int widgetnum; + char pcibus[8]; + devfs_handle_t nvtx, svtx; + int rv; + +#if DEBUG + printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", + slot, f_c); + { + int pos; + char dname[256]; + pos = devfs_generate_path(f_c, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } +#endif + + if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) + return 0; + + /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ + + /* find the widget number */ + xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); + if (xp == NULL) + return 0; + widgetnum = atoi(xp+7); + if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) + return 0; + + /* remove "/pci/direct" from path */ + cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); + if (cp == NULL) + return 0; + *cp = (char)NULL; + + /* get the vertex for the widget */ + if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) + return 0; + + *xp = (char)NULL; /* remove "/xtalk/..." from path */ + + /* dst example now == /hw/module/001c02/Pbrick */ + + /* get the bus number */ + strcat(dst, "/bus"); + sprintf(pcibus, "%d", p_busnum[widgetnum]); + + /* link to bus to widget */ + rv = hwgraph_path_add(NULL, dp, &nvtx); + if (GRAPH_SUCCESS == rv) + rv = hwgraph_edge_add(nvtx, svtx, pcibus); + + return (rv == GRAPH_SUCCESS); +} + + +/* + * pcibr_attach: called every time the crosstalk + * infrastructure is asked to initialize a widget + * that matches the part number we handed to the + * registration routine above. + */ +/*ARGSUSED */ +int +pcibr_attach(devfs_handle_t xconn_vhdl) +{ + /* REFERENCED */ + graph_error_t rc; + devfs_handle_t pcibr_vhdl; + devfs_handle_t ctlr_vhdl; + bridge_t *bridge = NULL; + bridgereg_t id; + int rev; + pcibr_soft_t pcibr_soft; + pcibr_info_t pcibr_info; + xwidget_info_t info; + xtalk_intr_t xtalk_intr; + device_desc_t dev_desc = (device_desc_t)0; + int slot; + int ibit; + devfs_handle_t noslot_conn; + char devnm[MAXDEVNAME], *s; + pcibr_hints_t pcibr_hints; + bridgereg_t b_int_enable; + unsigned rrb_fixed = 0; + + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + + int spl_level; +#ifdef LATER + char *nicinfo = (char *)0; +#endif + +#if PCI_FBBE + int fast_back_to_back_enable; +#endif + l1sc_t *scp; + nasid_t nasid; + + async_attach_t aa = NULL; + + aa = async_attach_get_info(xconn_vhdl); + +#if DEBUG && ATTACH_DEBUG + printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); + { + int pos; + char dname[256]; + pos = devfs_generate_path(xconn_vhdl, dname, 256); + printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); + } +#endif + + /* Setup the PRB for the bridge in CONVEYOR BELT + * mode. PRBs are setup in default FIRE-AND-FORGET + * mode during the initialization. + */ + hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); + + bridge = (bridge_t *) + xtalk_piotrans_addr(xconn_vhdl, NULL, + 0, sizeof(bridge_t), 0); + +#ifndef MEDUSA_HACK + if ((bridge->b_wid_stat & BRIDGE_STAT_PCI_GIO_N) == 0) + return -1; /* someone else handles GIO bridges. */ +#endif + + if (XWIDGET_PART_REV_NUM(bridge->b_wid_id) == XBRIDGE_PART_REV_A) + NeedXbridgeSwap = 1; + + /* + * Create the vertex for the PCI bus, which we + * will also use to hold the pcibr_soft and + * which will be the "master" vertex for all the + * pciio connection points we will hang off it. + * This needs to happen before we call nic_bridge_vertex_info + * as we are some of the *_vmc functions need access to the edges. + * + * Opening this vertex will provide access to + * the Bridge registers themselves. + */ + rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); + ASSERT(rc == GRAPH_SUCCESS); + + ctlr_vhdl = NULL; + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pcibr_fops, NULL); + + ASSERT(ctlr_vhdl != NULL); + + /* + * decode the nic, and hang its stuff off our + * connection point where other drivers can get + * at it. + */ +#ifdef LATER + nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); +#endif + + /* + * Get the hint structure; if some NIC callback + * marked this vertex as "hands-off" then we + * just return here, before doing anything else. + */ + pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); + + if (pcibr_hints && pcibr_hints->ph_hands_off) + return -1; /* generic operations disabled */ + + id = bridge->b_wid_id; + rev = XWIDGET_PART_REV_NUM(id); + + hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); + + /* + * allocate soft state structure, fill in some + * fields, and hook it up to our vertex. + */ + NEW(pcibr_soft); + BZERO(pcibr_soft, sizeof *pcibr_soft); + pcibr_soft_set(pcibr_vhdl, pcibr_soft); + + pcibr_soft->bs_conn = xconn_vhdl; + pcibr_soft->bs_vhdl = pcibr_vhdl; + pcibr_soft->bs_base = bridge; + pcibr_soft->bs_rev_num = rev; + pcibr_soft->bs_intr_bits = pcibr_intr_bits; + if (is_xbridge(bridge)) { + pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; + pcibr_soft->bs_xbridge = 1; + } else { + pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; + pcibr_soft->bs_xbridge = 0; + } + + nasid = NASID_GET(bridge); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + pcibr_soft->bs_l1sc = scp; + pcibr_soft->bs_moduleid = iobrick_module_get(scp); + pcibr_soft->bsi_err_intr = 0; + + /* Bridges up through REV C + * are unable to set the direct + * byteswappers to BYTE_STREAM. + */ + if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { + pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; + pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; + } +#if PCIBR_SOFT_LIST + { + pcibr_list_p self; + + NEW(self); + self->bl_soft = pcibr_soft; + self->bl_vhdl = pcibr_vhdl; + self->bl_next = pcibr_list; + self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); + } +#endif + + /* + * get the name of this bridge vertex and keep the info. Use this + * only where it is really needed now: like error interrupts. + */ + s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); + pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); + strcpy(pcibr_soft->bs_name, s); + +#if SHOW_REVS || DEBUG +#if !DEBUG + if (kdebug) +#endif + printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", + is_xbridge(bridge) ? "X" : "", + (rev == BRIDGE_PART_REV_A) ? "A" : + (rev == BRIDGE_PART_REV_B) ? "B" : + (rev == BRIDGE_PART_REV_C) ? "C" : + (rev == BRIDGE_PART_REV_D) ? "D" : + (rev == XBRIDGE_PART_REV_A) ? "A" : + (rev == XBRIDGE_PART_REV_B) ? "B" : + "unknown", + rev, pcibr_soft->bs_name); +#endif + + info = xwidget_info_get(xconn_vhdl); + pcibr_soft->bs_xid = xwidget_info_id_get(info); + pcibr_soft->bs_master = xwidget_info_master_get(info); + pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); + + /* + * Init bridge lock. + */ + spin_lock_init(&pcibr_soft->bs_lock); + + /* + * If we have one, process the hints structure. + */ + if (pcibr_hints) { + rrb_fixed = pcibr_hints->ph_rrb_fixed; + + pcibr_soft->bs_rrb_fixed = rrb_fixed; + + if (pcibr_hints->ph_intr_bits) + pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; + + for (slot = 0; slot < 8; ++slot) { + int hslot = pcibr_hints->ph_host_slot[slot] - 1; + + if (hslot < 0) { + pcibr_soft->bs_slot[slot].host_slot = slot; + } else { + pcibr_soft->bs_slot[slot].has_host = 1; + pcibr_soft->bs_slot[slot].host_slot = hslot; + } + } + } + /* + * set up initial values for state fields + */ + for (slot = 0; slot < 8; ++slot) { + pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; + pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; + pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; + pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); + } + + for (ibit = 0; ibit < 8; ++ibit) { + pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = + &(bridge->b_int_status); + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; + } + + /* + * Initialize various Bridge registers. + */ + + /* + * On pre-Rev.D bridges, set the PCI_RETRY_CNT + * to zero to avoid dropping stores. (#475347) + */ + if (rev < BRIDGE_PART_REV_D) + bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; + + /* + * Clear all pending interrupts. + */ + bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); + + /* + * Until otherwise set up, + * assume all interrupts are + * from slot 7. + */ + bridge->b_int_device = (uint32_t) 0xffffffff; + + { + bridgereg_t dirmap; + paddr_t paddr; + iopaddr_t xbase; + xwidgetnum_t xport; + iopaddr_t offset; + int num_entries = 0; + int entry; + cnodeid_t cnodeid; + nasid_t nasid; + + /* Set the Bridge's 32-bit PCI to XTalk + * Direct Map register to the most useful + * value we can determine. Note that we + * must use a single xid for all of: + * direct-mapped 32-bit DMA accesses + * direct-mapped 64-bit DMA accesses + * DMA accesses through the PMU + * interrupts + * This is the only way to guarantee that + * completion interrupts will reach a CPU + * after all DMA data has reached memory. + * (Of course, there may be a few special + * drivers/controlers that explicitly manage + * this ordering problem.) + */ + + cnodeid = 0; /* default node id */ + /* + * Determine the base address node id to be used for all 32-bit + * Direct Mapping I/O. The default is node 0, but this can be changed + * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE + * attribute in the irix.sm config file. A device driver can obtain + * this node value via a call to pcibr_get_dmatrans_node(). + */ + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + paddr = NODE_OFFSET(nasid) + 0; + + /* currently, we just assume that if we ask + * for a DMA mapping to "zero" the XIO + * host will transmute this into a request + * for the lowest hunk of memory. + */ + xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, + paddr, _PAGESZ, 0); + + if (xbase != XIO_NOWHERE) { + if (XIO_PACKED(xbase)) { + xport = XIO_PORT(xbase); + xbase = XIO_ADDR(xbase); + } else + xport = pcibr_soft->bs_mxid; + + offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); + xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; + + dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; + + if (xbase) + dirmap |= BRIDGE_DIRMAP_OFF & xbase; + else if (offset >= (512 << 20)) + dirmap |= BRIDGE_DIRMAP_ADD512; + + bridge->b_dir_map = dirmap; + } + /* + * Set bridge's idea of page size according to the system's + * idea of "IO page size". TBD: The idea of IO page size + * should really go away. + */ + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + spl_level = splhi(); +#if IOPGSIZE == 4096 + bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; +#elif IOPGSIZE == 16384 + bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; +#else + <<>>; +#endif + bridge->b_wid_control; /* inval addr bug war */ + splx(spl_level); + + /* Initialize internal mapping entries */ + for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) + bridge->b_int_ate_ram[entry].wr = 0; + + /* + * Determine if there's external mapping SSRAM on this + * bridge. Set up Bridge control register appropriately, + * inititlize SSRAM, and set software up to manage RAM + * entries as an allocatable resource. + * + * Currently, we just use the rm* routines to manage ATE + * allocation. We should probably replace this with a + * Best Fit allocator. + * + * For now, if we have external SSRAM, avoid using + * the internal ssram: we can't turn PREFETCH on + * when we use the internal SSRAM; and besides, + * this also guarantees that no allocation will + * straddle the internal/external line, so we + * can increment ATE write addresses rather than + * recomparing against BRIDGE_INTERNAL_ATES every + * time. + */ + if (is_xbridge(bridge)) + num_entries = 0; + else + num_entries = pcibr_init_ext_ate_ram(bridge); + + /* we always have 128 ATEs (512 for Xbridge) inside the chip + * even if disabled for debugging. + */ + pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); + pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); +#endif + + if (num_entries > pcibr_soft->bs_int_ate_size) { +#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ + printk("pcibr_attach: disabling internal ATEs.\n"); + pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); +#endif + pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); + pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, + num_entries - pcibr_soft->bs_int_ate_size); +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: %d EXTERNAL ATEs\n", + num_entries - pcibr_soft->bs_int_ate_size); +#endif + } + } + + { + bridgereg_t dirmap; + iopaddr_t xbase; + + /* + * now figure the *real* xtalk base address + * that dirmap sends us to. + */ + dirmap = bridge->b_dir_map; + if (dirmap & BRIDGE_DIRMAP_OFF) + xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) + << BRIDGE_DIRMAP_OFF_ADDRSHFT; + else if (dirmap & BRIDGE_DIRMAP_ADD512) + xbase = 512 << 20; + else + xbase = 0; + + pcibr_soft->bs_dir_xbase = xbase; + + /* it is entirely possible that we may, at this + * point, have our dirmap pointing somewhere + * other than our "master" port. + */ + pcibr_soft->bs_dir_xport = + (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; + } + + /* pcibr sources an error interrupt; + * figure out where to send it. + * + * If any interrupts are enabled in bridge, + * then the prom set us up and our interrupt + * has already been reconnected in mlreset + * above. + * + * Need to set the D_INTR_ISERR flag + * in the dev_desc used for allocating the + * error interrupt, so our interrupt will + * be properly routed and prioritized. + * + * If our crosstalk provider wants to + * fix widget error interrupts to specific + * destinations, D_INTR_ISERR is how it + * knows to do this. + */ + + xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); + ASSERT(xtalk_intr != NULL); + + pcibr_soft->bsi_err_intr = xtalk_intr; + + /* + * On IP35 with XBridge, we do some extra checks in pcibr_setwidint + * in order to work around some addressing limitations. In order + * for that fire wall to work properly, we need to make sure we + * start from a known clean state. + */ + pcibr_clearwidint(bridge); + + xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); + + /* + * now we can start handling error interrupts; + * enable all of them. + * NOTE: some PCI ints may already be enabled. + */ + b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; + + + bridge->b_int_enable = b_int_enable; + bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ + + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + /* + * Depending on the rev of bridge, disable certain features. + * Easiest way seems to be to force the PCIBR_NOwhatever + * flag to be on for all DMA calls, which overrides any + * PCIBR_whatever flag or even the setting of whatever + * from the PCIIO_DMA_class flags (or even from the other + * PCIBR flags, since NO overrides YES). + */ + pcibr_soft->bs_dma_flags = 0; + + /* PREFETCH: + * Always completely disabled for REV.A; + * at "pcibr_prefetch_enable_rev", anyone + * asking for PCIIO_PREFETCH gets it. + * Between these two points, you have to ask + * for PCIBR_PREFETCH, which promises that + * your driver knows about known Bridge WARs. + */ + if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) + pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; + else if (pcibr_soft->bs_rev_num < + (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) + pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; + + /* WRITE_GATHER: + * Disabled up to but not including the + * rev number in pcibr_wg_enable_rev. There + * is no "WAR range" as with prefetch. + */ + if (pcibr_soft->bs_rev_num < + (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) + pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; + + pciio_provider_register(pcibr_vhdl, &pcibr_provider); + pciio_provider_startup(pcibr_vhdl); + + pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ + pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ + + pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ + pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ + + pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ + pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ + + + PCI_ADDR_SPACE_LIMITS_STORE(); + + /* build "no-slot" connection point + */ + pcibr_info = pcibr_device_info_new + (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, + PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + noslot_conn = pciio_device_info_register + (pcibr_vhdl, &pcibr_info->f_c); + + /* Remember the no slot connection point info for tearing it + * down during detach. + */ + pcibr_soft->bs_noslot_conn = noslot_conn; + pcibr_soft->bs_noslot_info = pcibr_info; +#if PCI_FBBE + fast_back_to_back_enable = 1; +#endif + +#if PCI_FBBE + if (fast_back_to_back_enable) { + /* + * All devices on the bus are capable of fast back to back, so + * we need to set the fast back to back bit in all devices on + * the bus that are capable of doing such accesses. + */ + } +#endif + +#ifdef LATER + /* If the bridge has been reset then there is no need to reset + * the individual PCI slots. + */ + for (slot = 0; slot < 8; ++slot) + /* Reset all the slots */ + (void)pcibr_slot_reset(pcibr_vhdl, slot); +#endif + + for (slot = 0; slot < 8; ++slot) + /* Find out what is out there */ + (void)pcibr_slot_info_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Set up the address space for this slot in the pci land */ + (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Setup the device register */ + (void)pcibr_slot_device_init(pcibr_vhdl, slot); + +#ifndef __ia64 + for (slot = 0; slot < 8; ++slot) + /* Set up convenience links */ + if (is_xbridge(bridge)) + if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ + pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); +#endif + + for (slot = 0; slot < 8; ++slot) + /* Setup host/guest relations */ + (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Initial RRB management */ + (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); + + /* driver attach routines should be called out from generic linux code */ + for (slot = 0; slot < 8; ++slot) + /* Call the device attach */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + + /* + * Each Pbrick PCI bus only has slots 1 and 2. Similarly for + * widget 0xe on Ibricks. Allocate RRB's accordingly. + */ + if (pcibr_soft->bs_moduleid > 0) { + switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { + case 'p': /* Pbrick */ + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + break; + case 'i': /* Ibrick */ + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); + } + break; + } /* switch */ + } + +#ifdef LATER + if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); +#if PCIBR_RRB_DEBUG + printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); + + printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", + pcibr_vhdl, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + + for (slot = 0; slot < 8; ++slot) + printf("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + + printf("\n"); +#endif + } +#else + FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); +#endif + + if (aa) + async_attach_add_info(noslot_conn, aa); + + pciio_device_attach(noslot_conn, 0); + + + /* + * Tear down pointer to async attach info -- async threads for + * bridge's descendants may be running but the bridge's work is done. + */ + if (aa) + async_attach_del_info(xconn_vhdl); + + return 0; +} +/* + * pcibr_detach: + * Detach the bridge device from the hwgraph after cleaning out all the + * underlying vertices. + */ +int +pcibr_detach(devfs_handle_t xconn) +{ + pciio_slot_t slot; + devfs_handle_t pcibr_vhdl; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + + /* Get the bridge vertex from its xtalk connection point */ + if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) + return(1); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + + /* Disable the interrupts from the bridge */ + bridge->b_int_enable = 0; + + /* Detach all the PCI devices talking to this bridge */ + for(slot = 0; slot < 8; slot++) { +#ifdef DEBUG + printk("pcibr_device_detach called for %p/%d\n", + pcibr_vhdl,slot); +#endif + pcibr_slot_detach(pcibr_vhdl, slot, 0); + } + + /* Unregister the no-slot connection point */ + pciio_device_info_unregister(pcibr_vhdl, + &(pcibr_soft->bs_noslot_info->f_c)); + + spin_lock_destroy(&pcibr_soft->bs_lock); + kfree(pcibr_soft->bs_name); + + /* Error handler gets unregistered when the widget info is + * cleaned + */ + /* Free the soft ATE maps */ + if (pcibr_soft->bs_int_ate_map) + rmfreemap(pcibr_soft->bs_int_ate_map); + if (pcibr_soft->bs_ext_ate_map) + rmfreemap(pcibr_soft->bs_ext_ate_map); + + /* Disconnect the error interrupt and free the xtalk resources + * associated with it. + */ + xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); + xtalk_intr_free(pcibr_soft->bsi_err_intr); + + /* Clear the software state maintained by the bridge driver for this + * bridge. + */ + DEL(pcibr_soft); + /* Remove the Bridge revision labelled info */ + (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); + /* Remove the character device associated with this bridge */ + (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); + /* Remove the PCI bridge vertex */ + (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); + + return(0); +} + +int +pcibr_asic_rev(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t pcibr_vhdl; + arbitrary_info_t ainfo; + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) + return -1; + + if (GRAPH_SUCCESS != + hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) + return -1; + + return (int) ainfo; +} + +int +pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + pciio_slot_t slot; + slot = pciio_info_slot_get(pciio_info); + pcibr_device_write_gather_flush(pcibr_soft, slot); + return 0; +} + +/* ===================================================================== + * PIO MANAGEMENT + */ + +LOCAL iopaddr_t +pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, + pciio_slot_t slot, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + unsigned flags) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + + unsigned bar; /* which BASE reg on device is decoding */ + iopaddr_t xio_addr = XIO_NOWHERE; + + pciio_space_t wspace; /* which space device is decoding */ + iopaddr_t wbase; /* base of device decode on PCI */ + size_t wsize; /* size of device decode on PCI */ + + int try; /* DevIO(x) window scanning order control */ + int win; /* which DevIO(x) window is being used */ + pciio_space_t mspace; /* target space for devio(x) register */ + iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ + size_t msize; /* size of devio(x) mapped area on PCI */ + size_t mmask; /* addr bits stored in Device(x) */ + + unsigned long s; + + s = pcibr_lock(pcibr_soft); + + if (pcibr_soft->bs_slot[slot].has_host) { + slot = pcibr_soft->bs_slot[slot].host_slot; + pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; + } + if (space == PCIIO_SPACE_NONE) + goto done; + + if (space == PCIIO_SPACE_CFG) { + /* + * Usually, the first mapping + * established to a PCI device + * is to its config space. + * + * In any case, we definitely + * do NOT need to worry about + * PCI BASE registers, and + * MUST NOT attempt to point + * the DevIO(x) window at + * this access ... + */ + if (((flags & PCIIO_BYTE_STREAM) == 0) && + ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) + xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); + + goto done; + } + if (space == PCIIO_SPACE_ROM) { + /* PIO to the Expansion Rom. + * Driver is responsible for + * enabling and disabling + * decodes properly. + */ + wbase = pcibr_info->f_rbase; + wsize = pcibr_info->f_rsize; + + /* + * While the driver should know better + * than to attempt to map more space + * than the device is decoding, he might + * do it; better to bail out here. + */ + if ((pci_addr + req_size) > wsize) + goto done; + + pci_addr += wbase; + space = PCIIO_SPACE_MEM; + } + /* + * reduce window mappings to raw + * space mappings (maybe allocating + * windows), and try for DevIO(x) + * usage (setting it if it is available). + */ + bar = space - PCIIO_SPACE_WIN0; + if (bar < 6) { + wspace = pcibr_info->f_window[bar].w_space; + if (wspace == PCIIO_SPACE_NONE) + goto done; + + /* get PCI base and size */ + wbase = pcibr_info->f_window[bar].w_base; + wsize = pcibr_info->f_window[bar].w_size; + + /* + * While the driver should know better + * than to attempt to map more space + * than the device is decoding, he might + * do it; better to bail out here. + */ + if ((pci_addr + req_size) > wsize) + goto done; + + /* shift from window relative to + * decoded space relative. + */ + pci_addr += wbase; + space = wspace; + } else + bar = -1; + + /* Scan all the DevIO(x) windows twice looking for one + * that can satisfy our request. The first time through, + * only look at assigned windows; the second time, also + * look at PCIIO_SPACE_NONE windows. Arrange the order + * so we always look at our own window first. + * + * We will not attempt to satisfy a single request + * by concatinating multiple windows. + */ + for (try = 0; try < 16; ++try) { + bridgereg_t devreg; + unsigned offset; + + win = (try + slot) % 8; + + /* If this DevIO(x) mapping area can provide + * a mapping to this address, use it. + */ + msize = (win < 2) ? 0x200000 : 0x100000; + mmask = -msize; + if (space != PCIIO_SPACE_IO) + mmask &= 0x3FFFFFFF; + + offset = pci_addr & (msize - 1); + + /* If this window can't possibly handle that request, + * go on to the next window. + */ + if (((pci_addr & (msize - 1)) + req_size) > msize) + continue; + + devreg = pcibr_soft->bs_slot[win].bss_device; + + /* Is this window "nailed down"? + * If not, maybe we can use it. + * (only check this the second time through) + */ + mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; + if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { + + /* If this is the primary DevIO(x) window + * for some other device, skip it. + */ + if ((win != slot) && + (PCIIO_VENDOR_ID_NONE != + pcibr_soft->bs_slot[win].bss_vendor_id)) + continue; + + /* It's a free window, and we fit in it. + * Set up Device(win) to our taste. + */ + mbase = pci_addr & mmask; + + /* check that we would really get from + * here to there. + */ + if ((mbase | offset) != pci_addr) + continue; + + devreg &= ~BRIDGE_DEV_OFF_MASK; + if (space != PCIIO_SPACE_IO) + devreg |= BRIDGE_DEV_DEV_IO_MEM; + else + devreg &= ~BRIDGE_DEV_DEV_IO_MEM; + devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; + + /* default is WORD_VALUES. + * if you specify both, + * operation is undefined. + */ + if (flags & PCIIO_BYTE_STREAM) + devreg |= BRIDGE_DEV_DEV_SWAP; + else + devreg &= ~BRIDGE_DEV_DEV_SWAP; + + if (pcibr_soft->bs_slot[win].bss_device != devreg) { + bridge->b_device[win].reg = devreg; + pcibr_soft->bs_slot[win].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + +#if DEBUG && PCI_DEBUG + printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); +#endif + } + pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; + pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; + xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + +#if DEBUG && PCI_DEBUG + printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", + __FUNCTION__, __LINE__, space, space_desc, + pci_addr, pci_addr + req_size - 1, + slot, win, devreg); +#endif + + goto done; + } /* endif DevIO(x) not pointed */ + mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; + + /* Now check for request incompat with DevIO(x) + */ + if ((mspace != space) || + (pci_addr < mbase) || + ((pci_addr + req_size) > (mbase + msize)) || + ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || + (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) + continue; + + /* DevIO(x) window is pointed at PCI space + * that includes our target. Calculate the + * final XIO address, release the lock and + * return. + */ + xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + +#if DEBUG && PCI_DEBUG + printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", + __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); +#endif + goto done; + } + + switch (space) { + /* + * Accesses to device decode + * areas that do a not fit + * within the DevIO(x) space are + * modified to be accesses via + * the direct mapping areas. + * + * If necessary, drivers can + * explicitly ask for mappings + * into these address spaces, + * but this should never be needed. + */ + case PCIIO_SPACE_MEM: /* "mem space" */ + case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ + if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= + BRIDGE_PCI_MEM32_LIMIT) + xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; + break; + + case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ + if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= + BRIDGE_PCI_MEM64_LIMIT) + xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; + break; + + case PCIIO_SPACE_IO: /* "i/o space" */ + /* Bridge Hardware Bug WAR #482741: + * The 4G area that maps directly from + * XIO space to PCI I/O space is busted + * until Bridge Rev D. + */ + if ((pcibr_soft->bs_rev_num > BRIDGE_PART_REV_C) && + ((pci_addr + BRIDGE_PCI_IO_BASE + req_size - 1) <= + BRIDGE_PCI_IO_LIMIT)) + xio_addr = pci_addr + BRIDGE_PCI_IO_BASE; + break; + } + + /* Check that "Direct PIO" byteswapping matches, + * try to change it if it does not. + */ + if (xio_addr != XIO_NOWHERE) { + unsigned bst; /* nonzero to set bytestream */ + unsigned *bfp; /* addr of record of how swapper is set */ + unsigned swb; /* which control bit to mung */ + unsigned bfo; /* current swapper setting */ + unsigned bfn; /* desired swapper setting */ + + bfp = ((space == PCIIO_SPACE_IO) + ? (&pcibr_soft->bs_pio_end_io) + : (&pcibr_soft->bs_pio_end_mem)); + + bfo = *bfp; + + bst = flags & PCIIO_BYTE_STREAM; + + bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; + + if (bfn == bfo) { /* we already match. */ + ; + } else if (bfo != 0) { /* we have a conflict. */ +#if DEBUG && PCI_DEBUG + printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", + space, + bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); +#endif + xio_addr = XIO_NOWHERE; + } else { /* OK to make the change. */ + bridgereg_t octl, nctl; + + swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; + octl = bridge->b_wid_control; + nctl = bst ? octl | swb : octl & ~swb; + + if (octl != nctl) /* make the change if any */ + bridge->b_wid_control = nctl; + + *bfp = bfn; /* record the assignment */ + +#if DEBUG && PCI_DEBUG + printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", + space, + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); +#endif + } + } + done: + pcibr_unlock(pcibr_soft, s); + return xio_addr; +} + +/*ARGSUSED6 */ +pcibr_piomap_t +pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + size_t req_size_max, + unsigned flags) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + pcibr_piomap_t *mapptr; + pcibr_piomap_t maplist; + pcibr_piomap_t pcibr_piomap; + iopaddr_t xio_addr; + xtalk_piomap_t xtalk_piomap; + unsigned long s; + + /* Make sure that the req sizes are non-zero */ + if ((req_size < 1) || (req_size_max < 1)) + return NULL; + + /* + * Code to translate slot/space/addr + * into xio_addr is common between + * this routine and pcibr_piotrans_addr. + */ + xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); + + if (xio_addr == XIO_NOWHERE) + return NULL; + + /* Check the piomap list to see if there is already an allocated + * piomap entry but not in use. If so use that one. Otherwise + * allocate a new piomap entry and add it to the piomap list + */ + mapptr = &(pcibr_info->f_piomap); + + s = pcibr_lock(pcibr_soft); + for (pcibr_piomap = *mapptr; + pcibr_piomap != NULL; + pcibr_piomap = pcibr_piomap->bp_next) { + if (pcibr_piomap->bp_mapsz == 0) + break; + } + + if (pcibr_piomap) + mapptr = NULL; + else { + pcibr_unlock(pcibr_soft, s); + NEW(pcibr_piomap); + } + + pcibr_piomap->bp_dev = pconn_vhdl; + pcibr_piomap->bp_slot = pciio_slot; + pcibr_piomap->bp_flags = flags; + pcibr_piomap->bp_space = space; + pcibr_piomap->bp_pciaddr = pci_addr; + pcibr_piomap->bp_mapsz = req_size; + pcibr_piomap->bp_soft = pcibr_soft; + pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); + + if (mapptr) { + s = pcibr_lock(pcibr_soft); + maplist = *mapptr; + pcibr_piomap->bp_next = maplist; + *mapptr = pcibr_piomap; + } + pcibr_unlock(pcibr_soft, s); + + + if (pcibr_piomap) { + xtalk_piomap = + xtalk_piomap_alloc(xconn_vhdl, 0, + xio_addr, + req_size, req_size_max, + flags & PIOMAP_FLAGS); + if (xtalk_piomap) { + pcibr_piomap->bp_xtalk_addr = xio_addr; + pcibr_piomap->bp_xtalk_pio = xtalk_piomap; + } else { + pcibr_piomap->bp_mapsz = 0; + pcibr_piomap = 0; + } + } + return pcibr_piomap; +} + +/*ARGSUSED */ +void +pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) +{ + xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); + pcibr_piomap->bp_xtalk_pio = 0; + pcibr_piomap->bp_mapsz = 0; +} + +/*ARGSUSED */ +caddr_t +pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, + iopaddr_t pci_addr, + size_t req_size) +{ + return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, + pcibr_piomap->bp_xtalk_addr + + pci_addr - pcibr_piomap->bp_pciaddr, + req_size); +} + +/*ARGSUSED */ +void +pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) +{ + xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); +} + +/*ARGSUSED */ +caddr_t +pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + iopaddr_t xio_addr; + + xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); + + if (xio_addr == XIO_NOWHERE) + return NULL; + + return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); +} + +/* + * PIO Space allocation and management. + * Allocate and Manage the PCI PIO space (mem and io space) + * This routine is pretty simplistic at this time, and + * does pretty trivial management of allocation and freeing.. + * The current scheme is prone for fragmentation.. + * Change the scheme to use bitmaps. + */ + +/*ARGSUSED */ +iopaddr_t +pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + size_t req_size, + size_t alignment) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + pciio_piospace_t piosp; + unsigned long s; + + iopaddr_t *pciaddr, *pcilast; + iopaddr_t start_addr; + size_t align_mask; + + /* + * Check for proper alignment + */ + ASSERT(alignment >= NBPP); + ASSERT((alignment & (alignment - 1)) == 0); + + align_mask = alignment - 1; + s = pcibr_lock(pcibr_soft); + + /* + * First look if a previously allocated chunk exists. + */ + if ((piosp = pcibr_info->f_piospace)) { + /* + * Look through the list for a right sized free chunk. + */ + do { + if (piosp->free && + (piosp->space == space) && + (piosp->count >= req_size) && + !(piosp->start & align_mask)) { + piosp->free = 0; + pcibr_unlock(pcibr_soft, s); + return piosp->start; + } + piosp = piosp->next; + } while (piosp); + } + ASSERT(!piosp); + + switch (space) { + case PCIIO_SPACE_IO: + pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; + pcilast = &pcibr_soft->bs_spinfo.pci_io_last; + break; + case PCIIO_SPACE_MEM: + case PCIIO_SPACE_MEM32: + pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; + pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; + break; + default: + ASSERT(0); + pcibr_unlock(pcibr_soft, s); + return 0; + } + + start_addr = *pciaddr; + + /* + * Align start_addr. + */ + if (start_addr & align_mask) + start_addr = (start_addr + align_mask) & ~align_mask; + + if ((start_addr + req_size) > *pcilast) { + /* + * If too big a request, reject it. + */ + pcibr_unlock(pcibr_soft, s); + return 0; + } + *pciaddr = (start_addr + req_size); + + NEW(piosp); + piosp->free = 0; + piosp->space = space; + piosp->start = start_addr; + piosp->count = req_size; + piosp->next = pcibr_info->f_piospace; + pcibr_info->f_piospace = piosp; + + pcibr_unlock(pcibr_soft, s); + return start_addr; +} + +/*ARGSUSED */ +void +pcibr_piospace_free(devfs_handle_t pconn_vhdl, + pciio_space_t space, + iopaddr_t pciaddr, + size_t req_size) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + + pciio_piospace_t piosp; + unsigned long s; + char name[1024]; + + /* + * Look through the bridge data structures for the pciio_piospace_t + * structure corresponding to 'pciaddr' + */ + s = pcibr_lock(pcibr_soft); + piosp = pcibr_info->f_piospace; + while (piosp) { + /* + * Piospace free can only be for the complete + * chunk and not parts of it.. + */ + if (piosp->start == pciaddr) { + if (piosp->count == req_size) + break; + /* + * Improper size passed for freeing.. + * Print a message and break; + */ + hwgraph_vertex_name_get(pconn_vhdl, name, 1024); + printk(KERN_WARNING "pcibr_piospace_free: error"); + printk(KERN_WARNING "Device %s freeing size (0x%lx) different than allocated (0x%lx)", + name, req_size, piosp->count); + printk(KERN_WARNING "Freeing 0x%lx instead", piosp->count); + break; + } + piosp = piosp->next; + } + + if (!piosp) { + printk(KERN_WARNING + "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", + pciaddr, req_size); + pcibr_unlock(pcibr_soft, s); + return; + } + piosp->free = 1; + pcibr_unlock(pcibr_soft, s); + return; +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * The Bridge ASIC provides three methods of doing + * DMA: via a "direct map" register available in + * 32-bit PCI space (which selects a contiguous 2G + * address space on some other widget), via + * "direct" addressing via 64-bit PCI space (all + * destination information comes from the PCI + * address, including transfer attributes), and via + * a "mapped" region that allows a bunch of + * different small mappings to be established with + * the PMU. + * + * For efficiency, we most prefer to use the 32-bit + * direct mapping facility, since it requires no + * resource allocations. The advantage of using the + * PMU over the 64-bit direct is that single-cycle + * PCI addressing can be used; the advantage of + * using 64-bit direct over PMU addressing is that + * we do not have to allocate entries in the PMU. + */ + +/* + * Convert PCI-generic software flags and Bridge-specific software flags + * into Bridge-specific Direct Map attribute bits. + */ +LOCAL iopaddr_t +pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) +{ + iopaddr_t attributes = 0; + + /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ +#ifdef LATER + ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); +#endif + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { /* standard data channel */ + attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ + attributes |= PCI64_ATTR_PREF; /* prefetch on */ + } + if (flags & PCIIO_DMA_CMD) { /* standard command channel */ + attributes |= PCI64_ATTR_BAR; /* barrier bit on */ + attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ + } + /* Generic detail flags + */ + if (flags & PCIIO_PREFETCH) + attributes |= PCI64_ATTR_PREF; + if (flags & PCIIO_NOPREFETCH) + attributes &= ~PCI64_ATTR_PREF; + + /* the swap bit is in the address attributes for xbridge */ + if (pcibr_soft->bs_xbridge) { + if (flags & PCIIO_BYTE_STREAM) + attributes |= PCI64_ATTR_SWAP; + if (flags & PCIIO_WORD_VALUES) + attributes &= ~PCI64_ATTR_SWAP; + } + + /* Provider-specific flags + */ + if (flags & PCIBR_BARRIER) + attributes |= PCI64_ATTR_BAR; + if (flags & PCIBR_NOBARRIER) + attributes &= ~PCI64_ATTR_BAR; + + if (flags & PCIBR_PREFETCH) + attributes |= PCI64_ATTR_PREF; + if (flags & PCIBR_NOPREFETCH) + attributes &= ~PCI64_ATTR_PREF; + + if (flags & PCIBR_PRECISE) + attributes |= PCI64_ATTR_PREC; + if (flags & PCIBR_NOPRECISE) + attributes &= ~PCI64_ATTR_PREC; + + if (flags & PCIBR_VCHAN1) + attributes |= PCI64_ATTR_VIRTUAL; + if (flags & PCIBR_VCHAN0) + attributes &= ~PCI64_ATTR_VIRTUAL; + + return (attributes); +} + +/* + * Convert PCI-generic software flags and Bridge-specific software flags + * into Bridge-specific Address Translation Entry attribute bits. + */ +LOCAL bridge_ate_t +pcibr_flags_to_ate(unsigned flags) +{ + bridge_ate_t attributes; + + /* default if nothing specified: + * NOBARRIER + * NOPREFETCH + * NOPRECISE + * COHERENT + * Plus the valid bit + */ + attributes = ATE_CO | ATE_V; + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { /* standard data channel */ + attributes &= ~ATE_BAR; /* no barrier */ + attributes |= ATE_PREF; /* prefetch on */ + } + if (flags & PCIIO_DMA_CMD) { /* standard command channel */ + attributes |= ATE_BAR; /* barrier bit on */ + attributes &= ~ATE_PREF; /* disable prefetch */ + } + /* Generic detail flags + */ + if (flags & PCIIO_PREFETCH) + attributes |= ATE_PREF; + if (flags & PCIIO_NOPREFETCH) + attributes &= ~ATE_PREF; + + /* Provider-specific flags + */ + if (flags & PCIBR_BARRIER) + attributes |= ATE_BAR; + if (flags & PCIBR_NOBARRIER) + attributes &= ~ATE_BAR; + + if (flags & PCIBR_PREFETCH) + attributes |= ATE_PREF; + if (flags & PCIBR_NOPREFETCH) + attributes &= ~ATE_PREF; + + if (flags & PCIBR_PRECISE) + attributes |= ATE_PREC; + if (flags & PCIBR_NOPRECISE) + attributes &= ~ATE_PREC; + + return (attributes); +} + +/*ARGSUSED */ +pcibr_dmamap_t +pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + size_t req_size_max, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t slot; + xwidgetnum_t xio_port; + + xtalk_dmamap_t xtalk_dmamap; + pcibr_dmamap_t pcibr_dmamap; + int ate_count; + int ate_index; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + +#ifdef IRIX + NEWf(pcibr_dmamap, flags); +#else + /* + * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() + * can be called within an interrupt thread. + */ + pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); +#endif + + if (!pcibr_dmamap) + return 0; + + xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, + flags & DMAMAP_FLAGS); + if (!xtalk_dmamap) { +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); +#endif +#ifdef IRIX + DEL(pcibr_dmamap); +#else + free_pciio_dmamap(pcibr_dmamap); +#endif + return 0; + } + xio_port = pcibr_soft->bs_mxid; + slot = pciio_info_slot_get(pciio_info); + + pcibr_dmamap->bd_dev = pconn_vhdl; + pcibr_dmamap->bd_slot = slot; + pcibr_dmamap->bd_soft = pcibr_soft; + pcibr_dmamap->bd_xtalk = xtalk_dmamap; + pcibr_dmamap->bd_max_size = req_size_max; + pcibr_dmamap->bd_xio_port = xio_port; + + if (flags & PCIIO_DMA_A64) { + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { + iopaddr_t pci_addr; + int have_rrbs; + int min_rrbs; + + /* Device is capable of A64 operations, + * and the attributes of the DMA are + * consistant with any previous DMA + * mappings using shared resources. + */ + + pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); + + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_xio_addr = 0; + pcibr_dmamap->bd_pci_addr = pci_addr; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { + if (flags & PCIBR_VCHAN1) + slot += PCIBR_RRB_SLOT_VIRTUAL; + have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + if (have_rrbs < 2) { + if (pci_addr & PCI64_ATTR_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using direct64\n"); +#endif + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use direct64\n"); +#endif + flags &= ~PCIIO_DMA_A64; + } + if (flags & PCIIO_FIXED) { + /* warning: mappings may fail later, + * if direct32 can't get to the address. + */ + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { + /* User desires DIRECT A32 operations, + * and the attributes of the DMA are + * consistant with any previous DMA + * mappings using shared resources. + * Mapping calls may fail if target + * is outside the direct32 range. + */ +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using direct32\n"); +#endif + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; + pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use direct32\n"); +#endif + /* If the user demands FIXED and we can't + * give it to him, fail. + */ + xtalk_dmamap_free(xtalk_dmamap); +#ifdef IRIX + DEL(pcibr_dmamap); +#else + free_pciio_dmamap(pcibr_dmamap); +#endif + return 0; + } + /* + * Allocate Address Translation Entries from the mapping RAM. + * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, + * the maximum number of ATEs is based on the worst-case + * scenario, where the requested target is in the + * last byte of an ATE; thus, mapping IOPGSIZE+2 + * does end up requiring three ATEs. + */ + if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { + ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ + +req_size_max /* max mapping bytes */ + - 1) + 1; /* round UP */ + } else { /* assume requested target is page aligned */ + ate_count = IOPG(req_size_max /* max mapping bytes */ + - 1) + 1; /* round UP */ + } + + ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); + + if (ate_index != -1) { + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { + bridge_ate_t ate_proto; + int have_rrbs; + int min_rrbs; + +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using PMU\n"); +#endif + + ate_proto = pcibr_flags_to_ate(flags); + + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_pci_addr = + PCI32_MAPPED_BASE + IOPGSIZE * ate_index; + /* + * for xbridge the byte-swap bit == bit 29 of PCI address + */ + if (pcibr_soft->bs_xbridge) { + if (flags & PCIIO_BYTE_STREAM) + ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); + /* + * If swap was set in bss_device in pcibr_endian_set() + * we need to change the address bit. + */ + if (pcibr_soft->bs_slot[slot].bss_device & + BRIDGE_DEV_SWAP_PMU) + ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); + if (flags & PCIIO_WORD_VALUES) + ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); + } + pcibr_dmamap->bd_xio_addr = 0; + pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); + pcibr_dmamap->bd_ate_index = ate_index; + pcibr_dmamap->bd_ate_count = ate_count; + pcibr_dmamap->bd_ate_proto = ate_proto; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { + have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + if (have_rrbs < 2) { + if (ate_proto & ATE_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + } + } + if (ate_index >= pcibr_soft->bs_int_ate_size && + !pcibr_soft->bs_xbridge) { + bridge_t *bridge = pcibr_soft->bs_base; + volatile unsigned *cmd_regp; + unsigned cmd_reg; + unsigned long s; + + pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; + + s = pcibr_lock(pcibr_soft); + cmd_regp = &(bridge-> + b_type0_cfg_dev[slot]. + l[PCI_CFG_COMMAND / 4]); + cmd_reg = *cmd_regp; + pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; + pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; + pcibr_unlock(pcibr_soft, s); + } + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use PMU\n"); +#endif + pcibr_ate_free(pcibr_soft, ate_index, ate_count); + } + /* total failure: sorry, you just can't + * get from here to there that way. + */ +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: complete failure.\n"); +#endif + xtalk_dmamap_free(xtalk_dmamap); +#ifdef IRIX + DEL(pcibr_dmamap); +#else + free_pciio_dmamap(pcibr_dmamap); +#endif + return 0; +} + +/*ARGSUSED */ +void +pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; + pciio_slot_t slot = pcibr_dmamap->bd_slot; + + unsigned flags = pcibr_dmamap->bd_flags; + + /* Make sure that bss_ext_ates_active + * is properly kept up to date. + */ + + if (PCIBR_DMAMAP_BUSY & flags) + if (PCIBR_DMAMAP_SSRAM & flags) + atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); + + xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); + + if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { + pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); + } + if (pcibr_dmamap->bd_ate_count) { + pcibr_ate_free(pcibr_dmamap->bd_soft, + pcibr_dmamap->bd_ate_index, + pcibr_dmamap->bd_ate_count); + pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); + } +#ifdef IRIX + DEL(pcibr_dmamap); +#else + free_pciio_dmamap(pcibr_dmamap); +#endif +} + +/* + * Setup an Address Translation Entry as specified. Use either the Bridge + * internal maps or the external map RAM, as appropriate. + */ +LOCAL bridge_ate_p +pcibr_ate_addr(pcibr_soft_t pcibr_soft, + int ate_index) +{ + bridge_t *bridge = pcibr_soft->bs_base; + + return (ate_index < pcibr_soft->bs_int_ate_size) + ? &(bridge->b_int_ate_ram[ate_index].wr) + : &(bridge->b_ext_ate_ram[ate_index]); +} + +/* + * pcibr_addr_xio_to_pci: given a PIO range, hand + * back the corresponding base PCI MEM address; + * this is used to short-circuit DMA requests that + * loop back onto this PCI bus. + */ +LOCAL iopaddr_t +pcibr_addr_xio_to_pci(pcibr_soft_t soft, + iopaddr_t xio_addr, + size_t req_size) +{ + iopaddr_t xio_lim = xio_addr + req_size - 1; + iopaddr_t pci_addr; + pciio_slot_t slot; + + if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && + (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= BRIDGE_PCI_MEM64_BASE) && + (xio_lim <= BRIDGE_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; + return pci_addr; + } + for (slot = 0; slot < 8; ++slot) + if ((xio_addr >= BRIDGE_DEVIO(slot)) && + (xio_lim < BRIDGE_DEVIO(slot + 1))) { + bridgereg_t dev; + + dev = soft->bs_slot[slot].bss_device; + pci_addr = dev & BRIDGE_DEV_OFF_MASK; + pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; + pci_addr += xio_addr - BRIDGE_DEVIO(slot); + return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; + } + return 0; +} + +/* We are starting to get more complexity + * surrounding writing ATEs, so pull + * the writing code into this new function. + */ + +#if PCIBR_FREEZE_TIME +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) +#else +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) +#endif + +LOCAL unsigned +ate_freeze(pcibr_dmamap_t pcibr_dmamap, +#if PCIBR_FREEZE_TIME + unsigned *freeze_time_ptr, +#endif + unsigned *cmd_regs) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; +#ifdef LATER + int dma_slot = pcibr_dmamap->bd_slot; +#endif + int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; + int slot; + + unsigned long s; + unsigned cmd_reg; + volatile unsigned *cmd_lwa; + unsigned cmd_lwd; + + if (!ext_ates) + return 0; + + /* Bridge Hardware Bug WAR #484930: + * Bridge can't handle updating External ATEs + * while DMA is occuring that uses External ATEs, + * even if the particular ATEs involved are disjoint. + */ + + /* need to prevent anyone else from + * unfreezing the grant while we + * are working; also need to prevent + * this thread from being interrupted + * to keep PCI grant freeze time + * at an absolute minimum. + */ + s = pcibr_lock(pcibr_soft); + +#ifdef LATER + /* just in case pcibr_dmamap_done was not called */ + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { + pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) + atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); + xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); + } +#endif /* LATER */ +#if PCIBR_FREEZE_TIME + *freeze_time_ptr = get_timestamp(); +#endif + + cmd_lwa = 0; + for (slot = 0; slot < 8; ++slot) + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { + cmd_reg = pcibr_soft-> + bs_slot[slot]. + bss_cmd_shadow; + if (cmd_reg & PCI_CMD_BUS_MASTER) { + cmd_lwa = pcibr_soft-> + bs_slot[slot]. + bss_cmd_pointer; + cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; + cmd_lwa[0] = cmd_lwd; + } + cmd_regs[slot] = cmd_reg; + } else + cmd_regs[slot] = 0; + + if (cmd_lwa) { + bridge_t *bridge = pcibr_soft->bs_base; + + /* Read the last master bit that has been cleared. This PIO read + * on the PCI bus is to ensure the completion of any DMAs that + * are due to bus requests issued by PCI devices before the + * clearing of master bits. + */ + cmd_lwa[0]; + + /* Flush all the write buffers in the bridge */ + for (slot = 0; slot < 8; ++slot) + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { + /* Flush the write buffer associated with this + * PCI device which might be using dma map RAM. + */ + bridge->b_wr_req_buf[slot].reg; + } + } + return s; +} + +#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) + +LOCAL void +ate_write(bridge_ate_p ate_ptr, + int ate_count, + bridge_ate_t ate) +{ + while (ate_count-- > 0) { + *ate_ptr++ = ate; + ate += IOPGSIZE; + } +} + + +#if PCIBR_FREEZE_TIME +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) +#else +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) +#endif + +LOCAL void +ate_thaw(pcibr_dmamap_t pcibr_dmamap, + int ate_index, +#if PCIBR_FREEZE_TIME + bridge_ate_t ate, + int ate_total, + unsigned freeze_time_start, +#endif + unsigned *cmd_regs, + unsigned s) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; + int dma_slot = pcibr_dmamap->bd_slot; + int slot; + bridge_t *bridge = pcibr_soft->bs_base; + int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; + + unsigned cmd_reg; + +#if PCIBR_FREEZE_TIME + unsigned freeze_time; + static unsigned max_freeze_time = 0; + static unsigned max_ate_total; +#endif + + if (!ext_ates) + return; + + /* restore cmd regs */ + for (slot = 0; slot < 8; ++slot) + if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) + bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; + + pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; + atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); + +#if PCIBR_FREEZE_TIME + freeze_time = get_timestamp() - freeze_time_start; + + if ((max_freeze_time < freeze_time) || + (max_ate_total < ate_total)) { + if (max_freeze_time < freeze_time) + max_freeze_time = freeze_time; + if (max_ate_total < ate_total) + max_ate_total = ate_total; + pcibr_unlock(pcibr_soft, s); + printk("%s: pci freeze time %d usec for %d ATEs\n" + "\tfirst ate: %R\n", + pcibr_soft->bs_name, + freeze_time * 1000 / 1250, + ate_total, + ate, ate_bits); + } else +#endif + pcibr_unlock(pcibr_soft, s); +} + +/*ARGSUSED */ +iopaddr_t +pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, + paddr_t paddr, + size_t req_size) +{ + pcibr_soft_t pcibr_soft; + iopaddr_t xio_addr; + xwidgetnum_t xio_port; + iopaddr_t pci_addr; + unsigned flags; + + ASSERT(pcibr_dmamap != NULL); + ASSERT(req_size > 0); + ASSERT(req_size <= pcibr_dmamap->bd_max_size); + + pcibr_soft = pcibr_dmamap->bd_soft; + + flags = pcibr_dmamap->bd_flags; + + xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); + if (XIO_PACKED(xio_addr)) { + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_dmamap->bd_xio_port; + + /* If this DMA is to an address that + * refers back to this Bridge chip, + * reduce it back to the correct + * PCI MEM address. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); + } else if (flags & PCIIO_DMA_A64) { + /* A64 DMA: + * always use 64-bit direct mapping, + * which always works. + * Device(x) was set up during + * dmamap allocation. + */ + + /* attributes are already bundled up into bd_pci_addr. + */ + pci_addr = pcibr_dmamap->bd_pci_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) + | xio_addr; + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + pci_addr &= ~PCI64_ATTR_PREF; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmamap_addr (direct64):\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tXIO port 0x%x offset 0x%x\n" + "\treturning PCI 0x%x\n", + paddr, paddr + req_size - 1, + xio_port, xio_addr, pci_addr); +#endif + } else if (flags & PCIIO_FIXED) { + /* A32 direct DMA: + * always use 32-bit direct mapping, + * which may fail. + * Device(x) was set up during + * dmamap allocation. + */ + + if (xio_port != pcibr_soft->bs_dir_xport) + pci_addr = 0; /* wrong DIDN */ + else if (xio_addr < pcibr_dmamap->bd_xio_addr) + pci_addr = 0; /* out of range */ + else if ((xio_addr + req_size) > + (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) + pci_addr = 0; /* out of range */ + else + pci_addr = pcibr_dmamap->bd_pci_addr + + xio_addr - pcibr_dmamap->bd_xio_addr; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmamap_addr (direct32):\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tXIO port 0x%x offset 0x%x\n" + "\treturning PCI 0x%x\n", + paddr, paddr + req_size - 1, + xio_port, xio_addr, pci_addr); +#endif + } else { + bridge_t *bridge = pcibr_soft->bs_base; + iopaddr_t offset = IOPGOFF(xio_addr); + bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; + int ate_count = IOPG(offset + req_size - 1) + 1; + + int ate_index = pcibr_dmamap->bd_ate_index; + unsigned cmd_regs[8]; + unsigned s; + +#if PCIBR_FREEZE_TIME + int ate_total = ate_count; + unsigned freeze_time; +#endif + +#if PCIBR_ATE_DEBUG + bridge_ate_t ate_cmp; + bridge_ate_p ate_cptr; + unsigned ate_lo, ate_hi; + int ate_bad = 0; + int ate_rbc = 0; +#endif + bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; + bridge_ate_t ate; + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + ate_proto &= ~ATE_PREF; + + ate = ate_proto + | (xio_port << ATE_TIDSHIFT) + | (xio_addr - offset); + + pci_addr = pcibr_dmamap->bd_pci_addr + offset; + + /* Fill in our mapping registers + * with the appropriate xtalk data, + * and hand back the PCI address. + */ + + ASSERT(ate_count > 0); + if (ate_count <= pcibr_dmamap->bd_ate_count) { + ATE_FREEZE(); + ATE_WRITE(); + ATE_THAW(); + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } else { + /* The number of ATE's required is greater than the number + * allocated for this map. One way this can happen is if + * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP + * flag, and then when that map is used (right now), the + * target address tells us we really did need to roundup. + * The other possibility is that the map is just plain too + * small to handle the requested target area. + */ +#if PCIBR_ATE_DEBUG + printk(KERN_WARNING "pcibr_dmamap_addr :\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tate_count 0x%x bd_ate_count 0x%x\n" + "\tATE's required > number allocated\n", + paddr, paddr + req_size - 1, + ate_count, pcibr_dmamap->bd_ate_count); +#endif + pci_addr = 0; + } + + } + return pci_addr; +} + +/*ARGSUSED */ +alenlist_t +pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, + alenlist_t palenlist, + unsigned flags) +{ + pcibr_soft_t pcibr_soft; + bridge_t *bridge=NULL; + + unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; + int inplace = flags & PCIIO_INPLACE; + + alenlist_t pciio_alenlist = 0; + alenlist_t xtalk_alenlist; + size_t length; + iopaddr_t offset; + unsigned direct64; + int ate_index = 0; + int ate_count = 0; + int ate_total = 0; + bridge_ate_p ate_ptr = (bridge_ate_p)0; + bridge_ate_t ate_proto = (bridge_ate_t)0; + bridge_ate_t ate_prev; + bridge_ate_t ate; + alenaddr_t xio_addr; + xwidgetnum_t xio_port; + iopaddr_t pci_addr; + alenaddr_t new_addr; + + unsigned cmd_regs[8]; + unsigned s = 0; + +#if PCIBR_FREEZE_TIME + unsigned freeze_time; +#endif + int ate_freeze_done = 0; /* To pair ATE_THAW + * with an ATE_FREEZE + */ + + pcibr_soft = pcibr_dmamap->bd_soft; + + xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, + flags & DMAMAP_FLAGS); + if (!xtalk_alenlist) + goto fail; + + alenlist_cursor_init(xtalk_alenlist, 0, NULL); + + if (inplace) { + pciio_alenlist = xtalk_alenlist; + } else { + pciio_alenlist = alenlist_create(al_flags); + if (!pciio_alenlist) + goto fail; + } + + direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; + if (!direct64) { + bridge = pcibr_soft->bs_base; + ate_ptr = pcibr_dmamap->bd_ate_ptr; + ate_index = pcibr_dmamap->bd_ate_index; + ate_proto = pcibr_dmamap->bd_ate_proto; + ATE_FREEZE(); + ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ + } + pci_addr = pcibr_dmamap->bd_pci_addr; + + ate_prev = 0; /* matches no valid ATEs */ + while (ALENLIST_SUCCESS == + alenlist_get(xtalk_alenlist, NULL, 0, + &xio_addr, &length, al_flags)) { + if (XIO_PACKED(xio_addr)) { + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_dmamap->bd_xio_port; + + if (xio_port == pcibr_soft->bs_xid) { + new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); + if (new_addr == PCI_NOWHERE) + goto fail; + } else if (direct64) { + new_addr = pci_addr | xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + new_addr &= ~PCI64_ATTR_PREF; + + } else { + /* calculate the ate value for + * the first address. If it + * matches the previous + * ATE written (ie. we had + * multiple blocks in the + * same IOPG), then back up + * and reuse that ATE. + * + * We are NOT going to + * aggressively try to + * reuse any other ATEs. + */ + offset = IOPGOFF(xio_addr); + ate = ate_proto + | (xio_port << ATE_TIDSHIFT) + | (xio_addr - offset); + if (ate == ate_prev) { +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_list: ATE share\n"); +#endif + ate_ptr--; + ate_index--; + pci_addr -= IOPGSIZE; + } + new_addr = pci_addr + offset; + + /* Fill in the hardware ATEs + * that contain this block. + */ + ate_count = IOPG(offset + length - 1) + 1; + ate_total += ate_count; + + /* Ensure that this map contains enough ATE's */ + if (ate_total > pcibr_dmamap->bd_ate_count) { +#if PCIBR_ATE_DEBUG + printk(KERN_WARNING "pcibr_dmamap_list :\n" + "\twanted xio_addr [0x%x..0x%x]\n" + "\tate_total 0x%x bd_ate_count 0x%x\n" + "\tATE's required > number allocated\n", + xio_addr, xio_addr + length - 1, + ate_total, pcibr_dmamap->bd_ate_count); +#endif + goto fail; + } + + ATE_WRITE(); + + ate_index += ate_count; + ate_ptr += ate_count; + + ate_count <<= IOPFNSHIFT; + ate += ate_count; + pci_addr += ate_count; + } + + /* write the PCI DMA address + * out to the scatter-gather list. + */ + if (inplace) { + if (ALENLIST_SUCCESS != + alenlist_replace(pciio_alenlist, NULL, + &new_addr, &length, al_flags)) + goto fail; + } else { + if (ALENLIST_SUCCESS != + alenlist_append(pciio_alenlist, + new_addr, length, al_flags)) + goto fail; + } + } + if (!inplace) + alenlist_done(xtalk_alenlist); + + /* Reset the internal cursor of the alenlist to be returned back + * to the caller. + */ + alenlist_cursor_init(pciio_alenlist, 0, NULL); + + + /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the + * changes that ATE_FREEZE has done to implement the external SSRAM + * bug workaround. + */ + if (ate_freeze_done) { + ATE_THAW(); + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + return pciio_alenlist; + + fail: + /* There are various points of failure after doing an ATE_FREEZE + * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. + * The decision to do an ATE_THAW needs to be based on whether a + * an ATE_FREEZE was done before. + */ + if (ate_freeze_done) { + ATE_THAW(); + bridge->b_wid_tflush; + } + if (pciio_alenlist && !inplace) + alenlist_destroy(pciio_alenlist); + return 0; +} + +/*ARGSUSED */ +void +pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) +{ + /* + * We could go through and invalidate ATEs here; + * for performance reasons, we don't. + * We also don't enforce the strict alternation + * between _addr/_list and _done, but Hub does. + */ + + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { + pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; + + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) + atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); + } + + xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); +} + + +/* + * For each bridge, the DIR_OFF value in the Direct Mapping Register + * determines the PCI to Crosstalk memory mapping to be used for all + * 32-bit Direct Mapping memory accesses. This mapping can be to any + * node in the system. This function will return that compact node id. + */ + +/*ARGSUSED */ +cnodeid_t +pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) +{ + + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); +} + +/*ARGSUSED */ +iopaddr_t +pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + paddr_t paddr, + size_t req_size, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; + + xwidgetnum_t xio_port; + iopaddr_t xio_addr; + iopaddr_t pci_addr; + + int have_rrbs; + int min_rrbs; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + + xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, + flags & DMAMAP_FLAGS); + + if (!xio_addr) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + /* + * find which XIO port this goes to. + */ + if (XIO_PACKED(xio_addr)) { + if (xio_addr == XIO_NOWHERE) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + + } else + xio_port = pcibr_soft->bs_mxid; + + /* + * If this DMA comes back to us, + * return the PCI MEM address on + * which it would land, or NULL + * if the target is something + * on bridge other than PCI MEM. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); + return pci_addr; + } + /* If the caller can use A64, try to + * satisfy the request with the 64-bit + * direct map. This can fail if the + * configuration bits in Device(x) + * conflict with our flags. + */ + + if (flags & PCIIO_DMA_A64) { + pci_addr = slotp->bss_d64_base; + if (!(flags & PCIBR_VCHAN1)) + flags |= PCIBR_VCHAN0; + if ((pci_addr != PCIBR_D64_BASE_UNSET) && + (flags == slotp->bss_d64_flags)) { + + pci_addr |= xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + +#if DEBUG && PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr: [reuse]\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tdirect 64bit address is 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, pci_addr); +#endif + return (pci_addr); + } + if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { + pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); + slotp->bss_d64_flags = flags; + slotp->bss_d64_base = pci_addr; + pci_addr |= xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { + if (flags & PCIBR_VCHAN1) + pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + if (have_rrbs < 2) { + if (pci_addr & PCI64_ATTR_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tdirect 64bit address is 0x%x\n" + "\tnew flags: 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, pci_addr, (uint64_t) flags); +#endif + return (pci_addr); + } + /* our flags conflict with Device(x). + */ + flags = flags + & ~PCIIO_DMA_A64 + & ~PCIBR_VCHAN0 + ; + +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tUnable to set Device(x) bits for Direct-64\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } + /* Try to satisfy the request with the 32-bit direct + * map. This can fail if the configuration bits in + * Device(x) conflict with our flags, or if the + * target address is outside where DIR_OFF points. + */ + { + size_t map_size = 1ULL << 31; + iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; + iopaddr_t offset = xio_addr - xio_base; + iopaddr_t endoff = req_size + offset; + + if ((req_size > map_size) || + (xio_addr < xio_base) || + (xio_port != pcibr_soft->bs_dir_xport) || + (endoff > map_size)) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\txio region outside direct32 target\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } else { + pci_addr = slotp->bss_d32_base; + if ((pci_addr != PCIBR_D32_BASE_UNSET) && + (flags == slotp->bss_d32_flags)) { + + pci_addr |= offset; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr: [reuse]\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tmapped via direct32 offset 0x%x\n" + "\twill DMA via pci addr 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, offset, pci_addr); +#endif + return (pci_addr); + } + if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { + + pci_addr = PCI32_DIRECT_BASE; + slotp->bss_d32_flags = flags; + slotp->bss_d32_base = pci_addr; + pci_addr |= offset; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + if (have_rrbs < 2) { + if (slotp->bss_device & BRIDGE_DEV_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tmapped via direct32 offset 0x%x\n" + "\twill DMA via pci addr 0x%x\n" + "\tnew flags: 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, offset, pci_addr, (uint64_t) flags); +#endif + return (pci_addr); + } + /* our flags conflict with Device(x). + */ +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tUnable to set Device(x) bits for Direct-32\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } + } + +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tno acceptable PCI address found or constructable\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + + return 0; +} + +/*ARGSUSED */ +alenlist_t +pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + alenlist_t palenlist, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; + xwidgetnum_t xio_port; + + alenlist_t pciio_alenlist = 0; + alenlist_t xtalk_alenlist = 0; + + int inplace; + unsigned direct64; + unsigned al_flags; + + iopaddr_t xio_base; + alenaddr_t xio_addr; + size_t xio_size; + + size_t map_size; + iopaddr_t pci_base; + alenaddr_t pci_addr; + + unsigned relbits = 0; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + + inplace = flags & PCIIO_INPLACE; + direct64 = flags & PCIIO_DMA_A64; + al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; + + if (direct64) { + map_size = 1ull << 48; + xio_base = 0; + pci_base = slotp->bss_d64_base; + if ((pci_base != PCIBR_D64_BASE_UNSET) && + (flags == slotp->bss_d64_flags)) { + /* reuse previous base info */ + } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { + /* DMA configuration conflict */ + goto fail; + } else { + relbits = BRIDGE_DEV_D64_BITS; + pci_base = + pcibr_flags_to_d64(flags, pcibr_soft); + } + } else { + xio_base = pcibr_soft->bs_dir_xbase; + map_size = 1ull << 31; + pci_base = slotp->bss_d32_base; + if ((pci_base != PCIBR_D32_BASE_UNSET) && + (flags == slotp->bss_d32_flags)) { + /* reuse previous base info */ + } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { + /* DMA configuration conflict */ + goto fail; + } else { + relbits = BRIDGE_DEV_D32_BITS; + pci_base = PCI32_DIRECT_BASE; + } + } + + xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, + flags & DMAMAP_FLAGS); + if (!xtalk_alenlist) + goto fail; + + alenlist_cursor_init(xtalk_alenlist, 0, NULL); + + if (inplace) { + pciio_alenlist = xtalk_alenlist; + } else { + pciio_alenlist = alenlist_create(al_flags); + if (!pciio_alenlist) + goto fail; + } + + while (ALENLIST_SUCCESS == + alenlist_get(xtalk_alenlist, NULL, 0, + &xio_addr, &xio_size, al_flags)) { + + /* + * find which XIO port this goes to. + */ + if (XIO_PACKED(xio_addr)) { + if (xio_addr == XIO_NOWHERE) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_soft->bs_mxid; + + /* + * If this DMA comes back to us, + * return the PCI MEM address on + * which it would land, or NULL + * if the target is something + * on bridge other than PCI MEM. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); + if ( (pci_addr == (alenaddr_t)NULL) ) + goto fail; + } else if (direct64) { + ASSERT(xio_port != 0); + pci_addr = pci_base | xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + } else { + iopaddr_t offset = xio_addr - xio_base; + iopaddr_t endoff = xio_size + offset; + + if ((xio_size > map_size) || + (xio_addr < xio_base) || + (xio_port != pcibr_soft->bs_dir_xport) || + (endoff > map_size)) + goto fail; + + pci_addr = pci_base + (xio_addr - xio_base); + } + + /* write the PCI DMA address + * out to the scatter-gather list. + */ + if (inplace) { + if (ALENLIST_SUCCESS != + alenlist_replace(pciio_alenlist, NULL, + &pci_addr, &xio_size, al_flags)) + goto fail; + } else { + if (ALENLIST_SUCCESS != + alenlist_append(pciio_alenlist, + pci_addr, xio_size, al_flags)) + goto fail; + } + } + + if (relbits) { + if (direct64) { + slotp->bss_d64_flags = flags; + slotp->bss_d64_base = pci_base; + } else { + slotp->bss_d32_flags = flags; + slotp->bss_d32_base = pci_base; + } + } + if (!inplace) + alenlist_done(xtalk_alenlist); + + /* Reset the internal cursor of the alenlist to be returned back + * to the caller. + */ + alenlist_cursor_init(pciio_alenlist, 0, NULL); + return pciio_alenlist; + + fail: + if (relbits) + pcibr_release_device(pcibr_soft, pciio_slot, relbits); + if (pciio_alenlist && !inplace) + alenlist_destroy(pciio_alenlist); + return 0; +} + +void +pcibr_dmamap_drain(pcibr_dmamap_t map) +{ + xtalk_dmamap_drain(map->bd_xtalk); +} + +void +pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, + paddr_t paddr, + size_t bytes) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); +} + +void +pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, + alenlist_t list) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + xtalk_dmalist_drain(xconn_vhdl, list); +} + +/* + * Get the starting PCIbus address out of the given DMA map. + * This function is supposed to be used by a close friend of PCI bridge + * since it relies on the fact that the starting address of the map is fixed at + * the allocation time in the current implementation of PCI bridge. + */ +iopaddr_t +pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) +{ + return (pcibr_dmamap->bd_pci_addr); +} + +/* + * There are end cases where a deadlock can occur if interrupt + * processing completes and the Bridge b_int_status bit is still set. + * + * One scenerio is if a second PCI interrupt occurs within 60ns of + * the previous interrupt being cleared. In this case the Bridge + * does not detect the transition, the Bridge b_int_status bit + * remains set, and because no transition was detected no interrupt + * packet is sent to the Hub/Heart. + * + * A second scenerio is possible when a b_int_status bit is being + * shared by multiple devices: + * Device #1 generates interrupt + * Bridge b_int_status bit set + * Device #2 generates interrupt + * interrupt processing begins + * ISR for device #1 runs and + * clears interrupt + * Device #1 generates interrupt + * ISR for device #2 runs and + * clears interrupt + * (b_int_status bit still set) + * interrupt processing completes + * + * Interrupt processing is now complete, but an interrupt is still + * outstanding for Device #1. But because there was no transition of + * the b_int_status bit, no interrupt packet will be generated and + * a deadlock will occur. + * + * To avoid these deadlock situations, this function is used + * to check if a specific Bridge b_int_status bit is set, and if so, + * cause the setting of the corresponding interrupt bit. + * + * On a XBridge (IP35), we do this by writing the appropriate Bridge Force + * Interrupt register. + */ +void +pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +{ + unsigned bit; + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); + + bit = wrap->iw_intr; + + if (pcibr_soft->bs_xbridge) { + bridge->b_force_pin[bit].intr = 1; + } else if ((1 << bit) & *wrap->iw_stat) { + cpuid_t cpu; + unsigned intr_bit; + xtalk_intr_t xtalk_intr = + pcibr_soft->bs_intr[bit].bsi_xtalk_intr; + + intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); + cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); +#if defined(CONFIG_IA64_SGI_SN1) + REMOTE_CPU_SEND_INTR(cpu, intr_bit); +#endif + } +} + +/* ===================================================================== + * INTERRUPT MANAGEMENT + */ + +static unsigned +pcibr_intr_bits(pciio_info_t info, + pciio_intr_line_t lines) +{ + pciio_slot_t slot = pciio_info_slot_get(info); + unsigned bbits = 0; + + /* + * Currently favored mapping from PCI + * slot number and INTA/B/C/D to Bridge + * PCI Interrupt Bit Number: + * + * SLOT A B C D + * 0 0 4 0 4 + * 1 1 5 1 5 + * 2 2 6 2 6 + * 3 3 7 3 7 + * 4 4 0 4 0 + * 5 5 1 5 1 + * 6 6 2 6 2 + * 7 7 3 7 3 + */ + + if (slot < 8) { + if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) + bbits |= 1 << slot; + if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) + bbits |= 1 << (slot ^ 4); + } + return bbits; +} + + +/*ARGSUSED */ +pcibr_intr_t +pcibr_intr_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_intr_line_t lines, + devfs_handle_t owner_dev) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pcibr_info->f_slot; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + bridge_t *bridge = pcibr_soft->bs_base; + int is_threaded = 0; + int thread_swlevel; + + xtalk_intr_t *xtalk_intr_p; + pcibr_intr_t *pcibr_intr_p; + pcibr_intr_list_t *intr_list_p; + + unsigned pcibr_int_bits; + unsigned pcibr_int_bit; + xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; + hub_intr_t hub_intr; + pcibr_intr_t pcibr_intr; + pcibr_intr_list_t intr_entry; + pcibr_intr_list_t intr_list; + bridgereg_t int_dev; + +#if DEBUG && INTR_DEBUG + printk("%v: pcibr_intr_alloc\n" + "%v:%s%s%s%s%s\n", + owner_dev, pconn_vhdl, + !(lines & 15) ? " No INTs?" : "", + lines & 1 ? " INTA" : "", + lines & 2 ? " INTB" : "", + lines & 4 ? " INTC" : "", + lines & 8 ? " INTD" : ""); +#endif + + NEW(pcibr_intr); + if (!pcibr_intr) + return NULL; + + if (dev_desc) { + cpuid_t intr_target_from_desc(device_desc_t, int); + } else { + extern int default_intr_pri; + + is_threaded = 1; /* PCI interrupts are threaded, by default */ + thread_swlevel = default_intr_pri; + } + + pcibr_intr->bi_dev = pconn_vhdl; + pcibr_intr->bi_lines = lines; + pcibr_intr->bi_soft = pcibr_soft; + pcibr_intr->bi_ibits = 0; /* bits will be added below */ + pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; + pcibr_intr->bi_mustruncpu = CPU_NONE; + mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); + + pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); + + + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and make sure there are xtalk resources + * allocated for it. + */ +#if DEBUG && INTR_DEBUG + printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); +#endif + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + xtalk_intr = *xtalk_intr_p; + + if (xtalk_intr == NULL) { + /* + * This xtalk_intr_alloc is constrained for two reasons: + * 1) Normal interrupts and error interrupts need to be delivered + * through a single xtalk target widget so that there aren't any + * ordering problems with DMA, completion interrupts, and error + * interrupts. (Use of xconn_vhdl forces this.) + * + * 2) On IP35, addressing constraints on IP35 and Bridge force + * us to use a single PI number for all interrupts from a + * single Bridge. (IP35-specific code forces this, and we + * verify in pcibr_setwidint.) + */ + + /* + * All code dealing with threaded PCI interrupt handlers + * is located at the pcibr level. Because of this, + * we always want the lower layers (hub/heart_intr_alloc, + * intr_level_connect) to treat us as non-threaded so we + * don't set up a duplicate threaded environment. We make + * this happen by calling a special xtalk interface. + */ + xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, + owner_dev); +#if DEBUG && INTR_DEBUG + printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); +#endif + + /* both an assert and a runtime check on this: + * we need to check in non-DEBUG kernels, and + * the ASSERT gets us more information when + * we use DEBUG kernels. + */ + ASSERT(xtalk_intr != NULL); + if (xtalk_intr == NULL) { + /* it is quite possible that our + * xtalk_intr_alloc failed because + * someone else got there first, + * and we can find their results + * in xtalk_intr_p. + */ + if (!*xtalk_intr_p) { +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_ALERT + "pcibr_intr_alloc %v: unable to get xtalk interrupt resources", + xconn_vhdl); +#else + printk(KERN_ALERT + "pcibr_intr_alloc 0x%p: unable to get xtalk interrupt resources", + (void *)xconn_vhdl); +#endif + /* yes, we leak resources here. */ + return 0; + } + } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { + /* + * now tell the bridge which slot is + * using this interrupt line. + */ + int_dev = bridge->b_int_device; + int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); + int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); + bridge->b_int_device = int_dev; /* XXXMP */ + +#if DEBUG && INTR_DEBUG + printk("%v: bridge intr bit %d clears my wrb\n", + pconn_vhdl, pcibr_int_bit); +#endif + } else { + /* someone else got one allocated first; + * free the one we just created, and + * retrieve the one they allocated. + */ + xtalk_intr_free(xtalk_intr); + xtalk_intr = *xtalk_intr_p; +#if PARANOID + /* once xtalk_intr is set, we never clear it, + * so if the CAS fails above, this condition + * can "never happen" ... + */ + if (!xtalk_intr) { + printk(KERN_ALERT + "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", + xconn_vhdl); + /* yes, we leak resources here. */ + return 0; + } +#endif + } + } + + pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; + + NEW(intr_entry); + intr_entry->il_next = NULL; + intr_entry->il_intr = pcibr_intr; + intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); + intr_list_p = + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; +#if DEBUG && INTR_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("0x%x: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#else + printk("%v: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#endif +#endif + + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* we are the first interrupt on this bridge bit. + */ +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + intr_list = *intr_list_p; + pcibr_intr_p = &intr_list->il_intr; + if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { + /* first entry on list was erased, + * and we replaced it, so we + * don't need our intr_entry. + */ + DEL(intr_entry); +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + intr_list_p = &intr_list->il_next; + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* we are the new second interrupt on this bit. + */ + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + while (1) { + pcibr_intr_p = &intr_list->il_intr; + if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { + /* an entry on list was erased, + * and we replaced it, so we + * don't need our intr_entry. + */ + DEL(intr_entry); +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + break; + } + intr_list_p = &intr_list->il_next; + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* entry appended to share list + */ +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) is new Nth\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + break; + } + /* step to next record in chain + */ + intr_list = *intr_list_p; + } + } + } + +#if DEBUG && INTR_DEBUG + printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); +#endif + hub_intr = (hub_intr_t)xtalk_intr; + pcibr_intr->bi_irq = hub_intr->i_bit; + pcibr_intr->bi_cpu = hub_intr->i_cpuid; + return pcibr_intr; +} + +/*ARGSUSED */ +void +pcibr_intr_free(pcibr_intr_t pcibr_intr) +{ + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + unsigned pcibr_int_bit; + pcibr_intr_list_t intr_list; + int intr_shared; + xtalk_intr_t *xtalk_intrp; + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + for (intr_list = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; + intr_list != NULL; + intr_list = intr_list->il_next) + if (compare_and_swap_ptr((void **) &intr_list->il_intr, + pcibr_intr, + NULL)) { +#if DEBUG && INTR_DEBUG + printk("%s: cleared a handler from bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif + } + /* If this interrupt line is not being shared between multiple + * devices release the xtalk interrupt resources. + */ + intr_shared = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; + xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + if ((!intr_shared) && (*xtalk_intrp)) { + + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t int_dev; + + xtalk_intr_free(*xtalk_intrp); + *xtalk_intrp = 0; + + /* Clear the PCI device interrupt to bridge interrupt pin + * mapping. + */ + int_dev = bridge->b_int_device; + int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); + bridge->b_int_device = int_dev; + + } + } + } + DEL(pcibr_intr); +} + +LOCAL void +pcibr_setpciint(xtalk_intr_t xtalk_intr) +{ + iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); + xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); + bridgereg_t *int_addr = (bridgereg_t *) + xtalk_intr_sfarg_get(xtalk_intr); + +#ifdef CONFIG_IA64_SGI_SN2 + *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 26)) | + (BRIDGE_INT_ADDR_FLD & vect)); +#elif CONFIG_IA64_SGI_SN1 + *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | + (BRIDGE_INT_ADDR_FLD & vect)); +#endif +} + +/*ARGSUSED */ +int +pcibr_intr_connect(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + bridge_t *bridge = pcibr_soft->bs_base; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + bridgereg_t b_int_enable; + unsigned long s; + + if (pcibr_intr == NULL) + return -1; + +#if DEBUG && INTR_DEBUG + printk("%v: pcibr_intr_connect\n", + pcibr_intr->bi_dev); +#endif + + *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; + + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and make sure there are xtalk resources + * allocated for it. + */ + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + xtalk_intr_t xtalk_intr; + + xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + /* + * If this interrupt line is being shared and the connect has + * already been done, no need to do it again. + */ + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) + continue; + + + /* + * Use the pcibr wrapper function to handle all Bridge interrupts + * regardless of whether the interrupt line is shared or not. + */ + xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint, + (void *)&(bridge->b_int_addr[pcibr_int_bit].addr)); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; + +#if DEBUG && INTR_DEBUG + printk("%v bridge bit %d wrapper connected\n", + pcibr_intr->bi_dev, pcibr_int_bit); +#endif + } + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable |= pcibr_int_bits; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + + return 0; +} + +/*ARGSUSED */ +void +pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + bridge_t *bridge = pcibr_soft->bs_base; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + bridgereg_t b_int_enable; + unsigned long s; + + /* Stop calling the function. Now. + */ + *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and disconnect the interrupt. + */ + + /* don't disable interrupts for lines that + * are shared between devices. + */ + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if ((pcibr_int_bits & (1 << pcibr_int_bit)) && + (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) + pcibr_int_bits &= ~(1 << pcibr_int_bit); + if (!pcibr_int_bits) + return; + + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable &= ~pcibr_int_bits; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + /* if the interrupt line is now shared, + * do not disconnect it. + */ + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) + continue; + + xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; + +#if DEBUG && INTR_DEBUG + printk("%s: xtalk disconnect done for Bridge bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif + + /* if we are sharing the interrupt line, + * connect us up; this closes the hole + * where the another pcibr_intr_alloc() + * was in progress as we disconnected. + */ + if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) + continue; + + xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, + (xtalk_intr_setfunc_t)pcibr_setpciint, + (void *) &(bridge->b_int_addr[pcibr_int_bit].addr)); + } +} + +/*ARGSUSED */ +devfs_handle_t +pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) + return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + return 0; +} + +/* ===================================================================== + * INTERRUPT HANDLING + */ +LOCAL void +pcibr_clearwidint(bridge_t *bridge) +{ + bridge->b_wid_int_upper = 0; + bridge->b_wid_int_lower = 0; +} + +LOCAL void +pcibr_setwidint(xtalk_intr_t intr) +{ + xwidgetnum_t targ = xtalk_intr_target_get(intr); + iopaddr_t addr = xtalk_intr_addr_get(intr); + xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); + widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; + widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; + + bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); + + NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + + OLD_b_wid_int_upper = bridge->b_wid_int_upper; + OLD_b_wid_int_lower = bridge->b_wid_int_lower; + + /* Verify that all interrupts from this Bridge are using a single PI */ + if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { + /* + * Once set, these registers shouldn't change; they should + * be set multiple times with the same values. + * + * If we're attempting to change these registers, it means + * that our heuristics for allocating interrupts in a way + * appropriate for IP35 have failed, and the admin needs to + * explicitly direct some interrupts (or we need to make the + * heuristics more clever). + * + * In practice, we hope this doesn't happen very often, if + * at all. + */ + if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || + (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { + printk(KERN_WARNING "Interrupt allocation is too complex.\n"); + printk(KERN_WARNING "Use explicit administrative interrupt targetting.\n"); + printk(KERN_WARNING "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); + printk(KERN_WARNING "NEW=0x%x/0x%x OLD=0x%x/0x%x\n", + NEW_b_wid_int_upper, NEW_b_wid_int_lower, + OLD_b_wid_int_upper, OLD_b_wid_int_lower); + PRINT_PANIC("PCI Bridge interrupt targetting error\n"); + } + } + + bridge->b_wid_int_upper = NEW_b_wid_int_upper; + bridge->b_wid_int_lower = NEW_b_wid_int_lower; + bridge->b_int_host_err = vect; +} + +/* + * pcibr_intr_preset: called during mlreset time + * if the platform specific code needs to route + * one of the Bridge's xtalk interrupts before the + * xtalk infrastructure is available. + */ +void +pcibr_xintr_preset(void *which_widget, + int which_widget_intr, + xwidgetnum_t targ, + iopaddr_t addr, + xtalk_intr_vector_t vect) +{ + bridge_t *bridge = (bridge_t *) which_widget; + + if (which_widget_intr == -1) { + /* bridge widget error interrupt */ + bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + bridge->b_int_host_err = vect; + + /* turn on all interrupts except + * the PCI interrupt requests, + * at least at heart. + */ + bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; + + } else { + /* routing a PCI device interrupt. + * targ and low 38 bits of addr must + * be the same as the already set + * value for the widget error interrupt. + */ + bridge->b_int_addr[which_widget_intr].addr = + ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | + (BRIDGE_INT_ADDR_FLD & vect)); + /* + * now bridge can let it through; + * NB: still should be blocked at + * xtalk provider end, until the service + * function is set. + */ + bridge->b_int_enable |= 1 << vect; + } + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ +} + + +/* + * pcibr_intr_func() + * + * This is the pcibr interrupt "wrapper" function that is called, + * in interrupt context, to initiate the interrupt handler(s) registered + * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded + * handlers will be called directly, and threaded handlers will have their + * thread woken up. + */ +void +pcibr_intr_func(intr_arg_t arg) +{ + pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; + reg_p wrbf; + pcibr_intr_t intr; + pcibr_intr_list_t list; + int clearit; + int do_nonthreaded = 1; + int is_threaded = 0; + int x = 0; + + /* + * If any handler is still running from a previous interrupt + * just return. If there's a need to call the handler(s) again, + * another interrupt will be generated either by the device or by + * pcibr_force_interrupt(). + */ + + if (wrap->iw_hdlrcnt) { + return; + } + + /* + * Call all interrupt handlers registered. + * First, the pcibr_intrd threads for any threaded handlers will be + * awoken, then any non-threaded handlers will be called sequentially. + */ + + clearit = 1; + while (do_nonthreaded) { + for (list = wrap->iw_list; list != NULL; list = list->il_next) { + if ((intr = list->il_intr) && + (intr->bi_flags & PCIIO_INTR_CONNECTED)) { + + /* + * This device may have initiated write + * requests since the bridge last saw + * an edge on this interrupt input; flushing + * the buffer prior to invoking the handler + * should help but may not be sufficient if we + * get more requests after the flush, followed + * by the card deciding it wants service, before + * the interrupt handler checks to see if things need + * to be done. + * + * There is a similar race condition if + * an interrupt handler loops around and + * notices further service is required. + * Perhaps we need to have an explicit + * call that interrupt handlers need to + * do between noticing that DMA to memory + * has completed, but before observing the + * contents of memory? + */ + + if ((do_nonthreaded) && (!is_threaded)) { + /* Non-threaded. + * Call the interrupt handler at interrupt level + */ + + /* Only need to flush write buffers if sharing */ + + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if ((x = *wrbf)) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_ALERT "pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); +#else + printk(KERN_ALERT "pcibr_intr_func %p: \n" + "write buffer flush failed, wrbf=0x%lx\n", + (void *)list->il_intr->bi_dev, (long) wrbf); +#endif + } + } + + clearit = 0; + } + } + + do_nonthreaded = 0; + /* + * If the non-threaded handler was the last to complete, + * (i.e., no threaded handlers still running) force an + * interrupt to avoid a potential deadlock situation. + */ + if (wrap->iw_hdlrcnt == 0) { + pcibr_force_interrupt(wrap); + } + } + + /* If there were no handlers, + * disable the interrupt and return. + * It will get enabled again after + * a handler is connected. + * If we don't do this, we would + * sit here and spin through the + * list forever. + */ + if (clearit) { + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t b_int_enable; + bridgereg_t mask = 1 << wrap->iw_intr; + unsigned long s; + + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable &= ~mask; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + return; + } +} + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ +/*ARGSUSED */ +void +pcibr_provider_startup(devfs_handle_t pcibr) +{ +} + +/*ARGSUSED */ +void +pcibr_provider_shutdown(devfs_handle_t pcibr) +{ +} + +int +pcibr_reset(devfs_handle_t conn) +{ + pciio_info_t pciio_info = pciio_info_get(conn); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t ctlreg; + unsigned cfgctl[8]; + unsigned long s; + int f, nf; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + int win; + + if (pcibr_soft->bs_slot[pciio_slot].has_host) { + pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; + pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; + } + if (pciio_slot < 4) { + s = pcibr_lock(pcibr_soft); + nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; + for (f = 0; f < nf; ++f) + if (pcibr_infoh[f]) + cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; + + ctlreg = bridge->b_wid_control; + bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); + /* XXX delay? */ + bridge->b_wid_control = ctlreg; + /* XXX delay? */ + + for (f = 0; f < nf; ++f) + if ((pcibr_info = pcibr_infoh[f])) + for (win = 0; win < 6; ++win) + if (pcibr_info->f_window[win].w_base != 0) + bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = + pcibr_info->f_window[win].w_base; + for (f = 0; f < nf; ++f) + if (pcibr_infoh[f]) + bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; + pcibr_unlock(pcibr_soft, s); + + return 0; + } +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_WARNING "%v: pcibr_reset unimplemented for slot %d\n", + conn, pciio_slot); +#endif + return -1; +} + +pciio_endian_t +pcibr_endian_set(devfs_handle_t pconn_vhdl, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridgereg_t devreg; + unsigned long s; + + /* + * Bridge supports hardware swapping; so we can always + * arrange for the caller's desired endianness. + */ + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + if (device_end != desired_end) + devreg |= BRIDGE_DEV_SWAP_BITS; + else + devreg &= ~BRIDGE_DEV_SWAP_BITS; + + /* NOTE- if we ever put SWAP bits + * onto the disabled list, we will + * have to change the logic here. + */ + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); + +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); +#endif + + return desired_end; +} + +/* This (re)sets the GBR and REALTIME bits and also keeps track of how + * many sets are outstanding. Reset succeeds only if the number of outstanding + * sets == 1. + */ +int +pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, + pciio_slot_t pciio_slot, + pciio_priority_t device_prio) +{ + unsigned long s; + int *counter; + bridgereg_t rtbits = 0; + bridgereg_t devreg; + int rc = PRIO_SUCCESS; + + /* in dual-slot configurations, the host and the + * guest have separate DMA resources, so they + * have separate requirements for priority bits. + */ + + counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); + + /* + * Bridge supports PCI notions of LOW and HIGH priority + * arbitration rings via a "REAL_TIME" bit in the per-device + * Bridge register. The "GBR" bit controls access to the GBR + * ring on the xbow. These two bits are (re)set together. + * + * XXX- Bug in Rev B Bridge Si: + * Symptom: Prefetcher starts operating incorrectly. This happens + * due to corruption of the address storage ram in the prefetcher + * when a non-real time PCI request is pulled and a real-time one is + * put in it's place. Workaround: Use only a single arbitration ring + * on PCI bus. GBR and RR can still be uniquely used per + * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. + */ + + if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) + rtbits |= BRIDGE_DEV_RT; + + /* NOTE- if we ever put DEV_RT or DEV_GBR on + * the disabled list, we will have to take + * it into account here. + */ + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + if (device_prio == PCI_PRIO_HIGH) { + if ((++*counter == 1)) { + if (rtbits) + devreg |= rtbits; + else + rc = PRIO_FAIL; + } + } else if (device_prio == PCI_PRIO_LOW) { + if (*counter <= 0) + rc = PRIO_FAIL; + else if (--*counter == 0) + if (rtbits) + devreg &= ~rtbits; + } + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); + + return rc; +} + +pciio_priority_t +pcibr_priority_set(devfs_handle_t pconn_vhdl, + pciio_priority_t device_prio) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); + + return device_prio; +} + +/* + * Interfaces to allow special (e.g. SGI) drivers to set/clear + * Bridge-specific device flags. Many flags are modified through + * PCI-generic interfaces; we don't allow them to be directly + * manipulated here. Only flags that at this point seem pretty + * Bridge-specific can be set through these special interfaces. + * We may add more flags as the need arises, or remove flags and + * create PCI-generic interfaces as the need arises. + * + * Returns 0 on failure, 1 on success + */ +int +pcibr_device_flags_set(devfs_handle_t pconn_vhdl, + pcibr_device_flags_t flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridgereg_t set = 0; + bridgereg_t clr = 0; + + ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); + + if (flags & PCIBR_WRITE_GATHER) + set |= BRIDGE_DEV_PMU_WRGA_EN; + if (flags & PCIBR_NOWRITE_GATHER) + clr |= BRIDGE_DEV_PMU_WRGA_EN; + + if (flags & PCIBR_WRITE_GATHER) + set |= BRIDGE_DEV_DIR_WRGA_EN; + if (flags & PCIBR_NOWRITE_GATHER) + clr |= BRIDGE_DEV_DIR_WRGA_EN; + + if (flags & PCIBR_PREFETCH) + set |= BRIDGE_DEV_PREF; + if (flags & PCIBR_NOPREFETCH) + clr |= BRIDGE_DEV_PREF; + + if (flags & PCIBR_PRECISE) + set |= BRIDGE_DEV_PRECISE; + if (flags & PCIBR_NOPRECISE) + clr |= BRIDGE_DEV_PRECISE; + + if (flags & PCIBR_BARRIER) + set |= BRIDGE_DEV_BARRIER; + if (flags & PCIBR_NOBARRIER) + clr |= BRIDGE_DEV_BARRIER; + + if (flags & PCIBR_64BIT) + set |= BRIDGE_DEV_DEV_SIZE; + if (flags & PCIBR_NO64BIT) + clr |= BRIDGE_DEV_DEV_SIZE; + + if (set || clr) { + bridgereg_t devreg; + unsigned long s; + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + devreg = (devreg & ~clr) | set; + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); +#endif + } + return (1); +} + +#ifdef LITTLE_ENDIAN +/* + * on sn-ia we need to twiddle the the addresses going out + * the pci bus because we use the unswizzled synergy space + * (the alternative is to use the swizzled synergy space + * and byte swap the data) + */ +#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) +#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) +#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) +#else +#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) +#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) +#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) +#endif /* LITTLE_ENDIAN */ + + +LOCAL cfg_p +pcibr_config_addr(devfs_handle_t conn, + unsigned reg) +{ + pcibr_info_t pcibr_info; + pciio_slot_t pciio_slot; + pciio_function_t pciio_func; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + cfg_p cfgbase = (cfg_p)0; + + pcibr_info = pcibr_info_get(conn); + + pciio_slot = pcibr_info->f_slot; + if (pciio_slot == PCIIO_SLOT_NONE) + pciio_slot = PCI_TYPE1_SLOT(reg); + + pciio_func = pcibr_info->f_func; + if (pciio_func == PCIIO_FUNC_NONE) + pciio_func = PCI_TYPE1_FUNC(reg); + + pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + + bridge = pcibr_soft->bs_base; + + cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; + + return cfgbase; +} + +uint64_t +pcibr_config_get(devfs_handle_t conn, + unsigned reg, + unsigned size) +{ + return do_pcibr_config_get(pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size); +} + +LOCAL uint64_t +do_pcibr_config_get( + cfg_p cfgbase, + unsigned reg, + unsigned size) +{ + unsigned value; + + + value = CW(cfgbase, reg); + + if (reg & 3) + value >>= 8 * (reg & 3); + if (size < 4) + value &= (1 << (8 * size)) - 1; + + return value; +} + +void +pcibr_config_set(devfs_handle_t conn, + unsigned reg, + unsigned size, + uint64_t value) +{ + do_pcibr_config_set(pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size, value); +} + +LOCAL void +do_pcibr_config_set(cfg_p cfgbase, + unsigned reg, + unsigned size, + uint64_t value) +{ + switch (size) { + case 1: + CB(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { + CB(cfgbase, reg) = value; + CB(cfgbase, reg + 1) = value >> 8; + } else + CS(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CB(cfgbase, reg) = value; + CS(cfgbase, (reg + 1)) = value >> 8; + } else { + CS(cfgbase, reg) = value; + CB(cfgbase, reg + 2) = value >> 16; + } + break; + + case 4: + CW(cfgbase, reg) = value; + break; + } +} + +pciio_provider_t pcibr_provider = +{ + (pciio_piomap_alloc_f *) pcibr_piomap_alloc, + (pciio_piomap_free_f *) pcibr_piomap_free, + (pciio_piomap_addr_f *) pcibr_piomap_addr, + (pciio_piomap_done_f *) pcibr_piomap_done, + (pciio_piotrans_addr_f *) pcibr_piotrans_addr, + (pciio_piospace_alloc_f *) pcibr_piospace_alloc, + (pciio_piospace_free_f *) pcibr_piospace_free, + + (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, + (pciio_dmamap_free_f *) pcibr_dmamap_free, + (pciio_dmamap_addr_f *) pcibr_dmamap_addr, + (pciio_dmamap_list_f *) pcibr_dmamap_list, + (pciio_dmamap_done_f *) pcibr_dmamap_done, + (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, + (pciio_dmatrans_list_f *) pcibr_dmatrans_list, + (pciio_dmamap_drain_f *) pcibr_dmamap_drain, + (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, + (pciio_dmalist_drain_f *) pcibr_dmalist_drain, + + (pciio_intr_alloc_f *) pcibr_intr_alloc, + (pciio_intr_free_f *) pcibr_intr_free, + (pciio_intr_connect_f *) pcibr_intr_connect, + (pciio_intr_disconnect_f *) pcibr_intr_disconnect, + (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, + + (pciio_provider_startup_f *) pcibr_provider_startup, + (pciio_provider_shutdown_f *) pcibr_provider_shutdown, + (pciio_reset_f *) pcibr_reset, + (pciio_write_gather_flush_f *) pcibr_write_gather_flush, + (pciio_endian_set_f *) pcibr_endian_set, + (pciio_priority_set_f *) pcibr_priority_set, + (pciio_config_get_f *) pcibr_config_get, + (pciio_config_set_f *) pcibr_config_set, + + (pciio_error_devenable_f *) 0, + (pciio_error_extract_f *) 0, + +#ifdef LATER + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, + (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, +#else + (pciio_driver_reg_callback_f *) 0, + (pciio_driver_unreg_callback_f *) 0, +#endif + (pciio_device_unregister_f *) pcibr_device_unregister, + (pciio_dma_enabled_f *) pcibr_dma_enabled, +}; + +LOCAL pcibr_hints_t +pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) +{ + arbitrary_info_t ainfo = 0; + graph_error_t rv; + pcibr_hints_t hint; + + rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); + + if (alloc && (rv != GRAPH_SUCCESS)) { + + NEW(hint); + hint->rrb_alloc_funct = NULL; + hint->ph_intr_bits = NULL; + rv = hwgraph_info_add_LBL(xconn_vhdl, + INFO_LBL_PCIBR_HINTS, + (arbitrary_info_t) hint); + if (rv != GRAPH_SUCCESS) + goto abnormal_exit; + + rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); + + if (rv != GRAPH_SUCCESS) + goto abnormal_exit; + + if (ainfo != (arbitrary_info_t) hint) + goto abnormal_exit; + } + return (pcibr_hints_t) ainfo; + +abnormal_exit: +#ifdef LATER + printf("SHOULD NOT BE HERE\n"); +#endif + DEL(hint); + return(NULL); + +} + +void +pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_rrb_fixed = mask; +#if DEBUG + else + printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) +{ + pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); +} + +void +pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, + pciio_slot_t host, + pciio_slot_t guest) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_host_slot[guest] = host + 1; +#if DEBUG + else + printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, + pcibr_intr_bits_f *xxx_intr_bits) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_intr_bits = xxx_intr_bits; +#if DEBUG + else + printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->rrb_alloc_funct = rrb_alloc_funct; +} + +void +pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_hands_off = 1; +#if DEBUG + else + printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, + pciio_slot_t slot, + uint64_t subdevs) +{ + arbitrary_info_t ainfo = 0; + char sdname[16]; + devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; + + sprintf(sdname, "pci/%d", slot); + (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); + if (pconn_vhdl == GRAPH_VERTEX_NONE) { +#if DEBUG + printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" + "\t%p (seeking %s)\n", xconn_vhdl, sdname); +#endif + return; + } + hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); + if (ainfo == 0) { + uint64_t *subdevp; + + NEW(subdevp); + if (!subdevp) { +#if DEBUG + printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" + "\t%p\n", pconn_vhdl); +#endif + return; + } + *subdevp = subdevs; + hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); + hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); + if (ainfo == (arbitrary_info_t) subdevp) + return; + DEL(subdevp); + if (ainfo == (arbitrary_info_t) NULL) { +#if DEBUG + printk("pcibr_hints_subdevs: null subdevs ptr at\n" + "\t%p\n", pconn_vhdl); +#endif + return; + } +#if DEBUG + printk("pcibr_subdevs_get: dup subdev add_LBL at\n" + "\t%p\n", pconn_vhdl); +#endif + } + *(uint64_t *) ainfo = subdevs; +} + + +#ifdef LATER + +#include +#include + +char *pci_space[] = {"NONE", + "ROM", + "IO", + "", + "MEM", + "MEM32", + "MEM64", + "CFG", + "WIN0", + "WIN1", + "WIN2", + "WIN3", + "WIN4", + "WIN5", + "", + "BAD"}; + +void +idbg_pss_func(pcibr_info_h pcibr_infoh, int func) +{ + pcibr_info_t pcibr_info = pcibr_infoh[func]; + char name[MAXDEVNAME]; + int win; + + if (!pcibr_info) + return; + qprintf("Per-slot Function Info\n"); +#ifdef SUPPORT_PRINTING_V_FORMAT + sprintf(name, "%v", pcibr_info->f_vertex); +#endif + qprintf("\tSlot Name : %s\n",name); + qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); + qprintf("Slot : %d ", pcibr_info->f_slot); + qprintf("Function : %d ", pcibr_info->f_func); + qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); + qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); +#ifdef SUPPORT_PRINTING_V_FORMAT + sprintf(name, "%v", pcibr_info->f_master); +#endif + qprintf("\tBus provider : %s\n",name); + qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); + qprintf("Error Handler : 0x%x Arg 0x%x\n", + pcibr_info->f_efunc,pcibr_info->f_einfo); + for(win = 0 ; win < 6 ; win++) + qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", + win,pci_space[pcibr_info->f_window[win].w_space], + pcibr_info->f_window[win].w_base, + pcibr_info->f_window[win].w_size); + + qprintf("\tRom base 0x%x size 0x%x\n", + pcibr_info->f_rbase,pcibr_info->f_rsize); + + qprintf("\tInterrupt Bit Map\n"); + qprintf("\t\tPCI Int#\tBridge Pin#\n"); + for (win = 0 ; win < 4; win++) + qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); + qprintf("\n"); +} + + +void +idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) +{ + pcibr_soft_slot_t pss; + char slot_conn_name[MAXDEVNAME]; + int func; + + pss = &pcibr_soft->bs_slot[slot]; + qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); + qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); + qprintf("\tHost Slot : %d\n",pss->host_slot); + sprintf(slot_conn_name, "%v", pss->slot_conn); + qprintf("\tSlot Conn : %s\n",slot_conn_name); + qprintf("\t#Functions : %d\n",pss->bss_ninfo); + for (func = 0; func < pss->bss_ninfo; func++) + idbg_pss_func(pss->bss_infos,func); + qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); + qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); + qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); + qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", + pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); + + qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" + "d32_base 0x%x d32_flags 0x%x\n", + pss->bss_d64_base, pss->bss_d64_flags, + pss->bss_d32_base, pss->bss_d32_flags); + + qprintf("\tExt ATEs active ? %s", + atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); + qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); + qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); + + qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", + pcibr_soft->bs_rrb_valid[slot], + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + +} + +int ips = 0; + +void +idbg_pss(pcibr_soft_t pcibr_soft) +{ + pciio_slot_t slot; + + + if (ips >= 0 && ips < 8) + idbg_pss_info(pcibr_soft,ips); + else if (ips < 0) + for (slot = 0; slot < 8; slot++) + idbg_pss_info(pcibr_soft,slot); + else + qprintf("Invalid ips %d\n",ips); +} + +#endif /* LATER */ + +int +pcibr_dma_enabled(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + + return xtalk_dma_enabled(pcibr_soft->bs_conn); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/bte_error.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/bte_error.c --- linux-2.4.18/arch/ia64/sn/io/sn2/bte_error.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/bte_error.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,190 @@ +/* $Id: bte_error.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * * + * BTE ERROR RECOVERY * + * * + * Given a BTE error, the node causing the error must do the following: * + * a) Clear all crbs relating to that BTE * + * 1) Read CRBA value for crb in question * + * 2) Mark CRB as VALID, store local physical * + * address known to be good in the address field * + * (bte_notification_targ is a known good local * + * address). * + * 3) Write CRBA * + * 4) Using ICCR, FLUSH the CRB, and wait for it to * + * complete. * + * ... BTE BUSY bit should now be clear (or at least * + * should be after ALL CRBs associated with the * + * transfer are complete. * + * * + * b) Re-enable BTE * + * 1) Write IMEM with BTE Enable + XXX bits + * 2) Write IECLR with BTE clear bits + * 3) Clear IIDSR INT_SENT bits. + * * + ************************************************************************/ + +#ifdef BTE_ERROR +// This routine is not called. Yet. It may be someday. It probably +// *should* be someday. Until then, ifdef it out. +bte_result_t +bte_error_handler(bte_handle_t *bh) +/* + * Function: bte_error_handler + * Purpose: Process a BTE error after a transfer has failed. + * Parameters: bh - bte handle of bte that failed. + * Returns: The BTE error type. + * Notes: + */ +{ + devfs_handle_t hub_v; + hubinfo_t hinfo; + int il; + hubreg_t iidsr, imem, ieclr; + hubreg_t bte_status; + + bh->bh_bte->bte_error_count++; + + /* + * Process any CRB logs - we know that the bte_context contains + * the BTE completion status, but to avoid a race with error + * processing, we force a call to pick up any CRB errors pending. + * After this call, we know that we have any CRB errors related to + * this BTE transfer in the context. + */ + hub_v = cnodeid_to_vertex(bh->bh_bte->bte_cnode); + hubinfo_get(hub_v, &hinfo); + (void)hubiio_crb_error_handler(hub_v, hinfo); + + /* Be sure BTE is stopped */ + + (void)BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_CTRL); + + /* + * Now clear up the rest of the error - be sure to hold crblock + * to avoid race with other cpu on this node. + */ + imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); + ieclr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IECLR); + if (bh->bh_bte->bte_num == 0) { + imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; + ieclr|= IECLR_BTE0; + } else { + imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; + ieclr|= IECLR_BTE1; + } + + REMOTE_HUB_S(hinfo->h_nasid, IIO_IMEM, imem); + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, ieclr); + + iidsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR); + iidsr &= ~IIO_IIDSR_SENT_MASK; + iidsr |= IIO_IIDSR_ENB_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, iidsr); + mutex_spinunlock(&hinfo->h_crblock, il); + + bte_status = BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT); + BTE_STORE(bh->bh_bte->bte_base, BTEOFF_STAT, bte_status & ~IBLS_BUSY); + ASSERT(!BTE_IS_BUSY(BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT))); + + switch(bh->bh_error) { + case IIO_ICRB_ECODE_PERR: + return(BTEFAIL_POISON); + case IIO_ICRB_ECODE_WERR: + return(BTEFAIL_PROT); + case IIO_ICRB_ECODE_AERR: + return(BTEFAIL_ACCESS); + case IIO_ICRB_ECODE_TOUT: + return(BTEFAIL_TOUT); + case IIO_ICRB_ECODE_XTERR: + return(BTEFAIL_ERROR); + case IIO_ICRB_ECODE_DERR: + return(BTEFAIL_DIR); + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_PRERR: + /* NO BREAK */ + default: + printk("BTE failure (%d) unexpected\n", + bh->bh_error); + return(BTEFAIL_ERROR); + } +} +#endif // BTE_ERROR + +void +bte_crb_error_handler(devfs_handle_t hub_v, int btenum, + int crbnum, ioerror_t *ioe) +/* + * Function: bte_crb_error_handler + * Purpose: Process a CRB for a specific HUB/BTE + * Parameters: hub_v - vertex of hub in HW graph + * btenum - bte number on hub (0 == a, 1 == b) + * crbnum - crb number being processed + * Notes: + * This routine assumes serialization at a higher level. A CRB + * should not be processed more than once. The error recovery + * follows the following sequence - if you change this, be real + * sure about what you are doing. + * + */ +{ + hubinfo_t hinfo; + icrba_t crba; + icrbb_t crbb; + nasid_t n; + + hubinfo_get(hub_v, &hinfo); + + + n = hinfo->h_nasid; + + /* Step 1 */ + crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); + crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); + + + /* Zero error and error code to prevent error_dump complaining + * about these CRBs. + */ + crbb.b_error=0; + crbb.b_ecode=0; + + /* Step 2 */ + REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); + /* Step 3 */ + REMOTE_HUB_S(n, IIO_ICCR, + IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); + while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) + ; +} + diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/ml_SN_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/ml_SN_intr.c --- linux-2.4.18/arch/ia64/sn/io/sn2/ml_SN_intr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/ml_SN_intr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,469 @@ +/* $Id: ml_SN_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * intr.c- + * This file contains all of the routines necessary to set up and + * handle interrupts on an IPXX board. + */ + +#ident "$Revision: 1.1 $" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern irqpda_t *irqpdaindr[]; +extern cnodeid_t master_node_get(devfs_handle_t vhdl); +extern nasid_t master_nasid; + +// Initialize some shub registers for interrupts, both IO and error. + +void +intr_init_vecblk( nodepda_t *npda, + cnodeid_t node, + int sn) +{ + int nasid = cnodeid_to_nasid(node); + nasid_t console_nasid; + sh_ii_int0_config_u_t ii_int_config; + cpuid_t cpu; + cpuid_t cpu0, cpu1; + nodepda_t *lnodepda; + sh_ii_int0_enable_u_t ii_int_enable; + sh_local_int0_config_u_t local_int_config; + sh_local_int0_enable_u_t local_int_enable; + sh_fsb_system_agent_config_u_t fsb_system_agent; + sh_int_node_id_config_u_t node_id_config; + int is_console; + + console_nasid = get_console_nasid(); + if (console_nasid < 0) { + console_nasid = master_nasid; + } + + is_console = nasid == console_nasid; + + if (is_headless_node(node) ) { + int cnode; + struct ia64_sal_retval ret_stuff; + + // retarget all interrupts on this node to the master node. + node_id_config.sh_int_node_id_config_regval = 0; + node_id_config.sh_int_node_id_config_s.node_id = master_nasid; + node_id_config.sh_int_node_id_config_s.id_sel = 1; + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_INT_NODE_ID_CONFIG), + node_id_config.sh_int_node_id_config_regval); + cnode = nasid_to_cnodeid(master_nasid); + lnodepda = NODEPDA(cnode); + cpu = lnodepda->node_first_cpu; + cpu = cpu_physical_id(cpu); + SAL_CALL(ret_stuff, SN_SAL_REGISTER_CE, nasid, cpu, master_nasid,0,0,0,0); + if (ret_stuff.status < 0) { + printk("%s: SN_SAL_REGISTER_CE SAL_CALL failed\n",__FUNCTION__); + } + } else { + lnodepda = NODEPDA(node); + cpu = lnodepda->node_first_cpu; + cpu = cpu_physical_id(cpu); + } + + // Get the physical id's of the cpu's on this node. + cpu0 = id_eid_to_cpu_physical_id(nasid, 0); + cpu1 = id_eid_to_cpu_physical_id(nasid, 1); + + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); + + // The II_INT_CONFIG register for cpu 0. + ii_int_config.sh_ii_int0_config_s.type = 0; + ii_int_config.sh_ii_int0_config_s.agt = 0; + ii_int_config.sh_ii_int0_config_s.pid = cpu0; + ii_int_config.sh_ii_int0_config_s.base = 0; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG), + ii_int_config.sh_ii_int0_config_regval); + + // The II_INT_CONFIG register for cpu 1. + ii_int_config.sh_ii_int0_config_s.type = 0; + ii_int_config.sh_ii_int0_config_s.agt = 0; + ii_int_config.sh_ii_int0_config_s.pid = cpu1; + ii_int_config.sh_ii_int0_config_s.base = 0; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG), + ii_int_config.sh_ii_int0_config_regval); + + // Enable interrupts for II_INT0 and 1. + ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), + ii_int_enable.sh_ii_int0_enable_regval); + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE), + ii_int_enable.sh_ii_int0_enable_regval); + + // init error regs + // LOCAL_INT0 is for the UART only. + + local_int_config.sh_local_int0_config_s.type = 0; + local_int_config.sh_local_int0_config_s.agt = 0; + local_int_config.sh_local_int0_config_s.pid = cpu; + local_int_config.sh_local_int0_config_s.base = 0; + local_int_config.sh_local_int0_config_s.idx = SGI_UART_VECTOR; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_CONFIG), + local_int_config.sh_local_int0_config_regval); + + // LOCAL_INT1 is for all hardware errors. + // It will send a BERR, which will result in an MCA. + local_int_config.sh_local_int0_config_s.idx = 0; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG), + local_int_config.sh_local_int0_config_regval); + + // Clear the LOCAL_INT_ENABLE register. + local_int_enable.sh_local_int0_enable_regval = 0; + + if (is_console) { + // Enable the UART interrupt. Only applies to the console nasid. + local_int_enable.sh_local_int0_enable_s.uart_int = 1; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + } + + // Enable all the error interrupts. + local_int_enable.sh_local_int0_enable_s.uart_int = 0; + local_int_enable.sh_local_int0_enable_s.pi_hw_int = 1; + local_int_enable.sh_local_int0_enable_s.md_hw_int = 1; + local_int_enable.sh_local_int0_enable_s.xn_hw_int = 1; + local_int_enable.sh_local_int0_enable_s.lb_hw_int = 1; + local_int_enable.sh_local_int0_enable_s.ii_hw_int = 1; + local_int_enable.sh_local_int0_enable_s.pi_uce_int = 1; + local_int_enable.sh_local_int0_enable_s.md_uce_int = 1; + local_int_enable.sh_local_int0_enable_s.xn_uce_int = 1; + local_int_enable.sh_local_int0_enable_s.system_shutdown_int = 1; + local_int_enable.sh_local_int0_enable_s.l1_nmi_int = 1; + local_int_enable.sh_local_int0_enable_s.stop_clock = 1; + + + // Send BERR, rather than an interrupt, for shub errors. + local_int_config.sh_local_int0_config_s.agt = 1; + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG), + local_int_config.sh_local_int0_config_regval); + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + + // Make sure BERR is enabled. + fsb_system_agent.sh_fsb_system_agent_config_regval = + HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG) ); + fsb_system_agent.sh_fsb_system_agent_config_s.berr_assert_en = 1; + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG), + fsb_system_agent.sh_fsb_system_agent_config_regval); + + // Set LOCAL_INT2 to field CEs + + local_int_enable.sh_local_int0_enable_regval = 0; + + local_int_config.sh_local_int0_config_s.agt = 0; + local_int_config.sh_local_int0_config_s.idx = SGI_SHUB_ERROR_VECTOR; + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_CONFIG), + local_int_config.sh_local_int0_config_regval); + + local_int_enable.sh_local_int0_enable_s.pi_ce_int = 1; + local_int_enable.sh_local_int0_enable_s.md_ce_int = 1; + local_int_enable.sh_local_int0_enable_s.xn_ce_int = 1; + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + + // Make sure all the rest of the LOCAL_INT regs are disabled. + local_int_enable.sh_local_int0_enable_regval = 0; + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT3_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT4_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + + HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), + local_int_enable.sh_local_int0_enable_regval); + +} + +// (Un)Reserve an irq on this cpu. + +static int +do_intr_reserve_level(cpuid_t cpu, + int bit, + int reserve) +{ + int i; + irqpda_t *irqs = irqpdaindr[cpu]; + + if (reserve) { + if (bit < 0) { + for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) { + if (irqs->irq_flags[i] == 0) { + bit = i; + break; + } + } + } + if (bit < 0) { + return -1; + } + if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) { + return -1; + } else { + irqs->num_irq_used++; + irqs->irq_flags[bit] |= SN2_IRQ_RESERVED; + return bit; + } + } else { + if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) { + irqs->num_irq_used--; + irqs->irq_flags[bit] &= ~SN2_IRQ_RESERVED; + return bit; + } else { + return -1; + } + } +} + +int +intr_reserve_level(cpuid_t cpu, + int bit, + int resflags, + devfs_handle_t owner_dev, + char *name) +{ + return(do_intr_reserve_level(cpu, bit, 1)); +} + +void +intr_unreserve_level(cpuid_t cpu, + int bit) +{ + (void)do_intr_reserve_level(cpu, bit, 0); +} + +// Mark an irq on this cpu as (dis)connected. + +static int +do_intr_connect_level(cpuid_t cpu, + int bit, + int connect) +{ + irqpda_t *irqs = irqpdaindr[cpu]; + + if (connect) { + if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) { + return -1; + } else { + irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED; + return bit; + } + } else { + if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) { + irqs->irq_flags[bit] &= ~SN2_IRQ_CONNECTED; + return bit; + } else { + return -1; + } + } + return(bit); +} + +int +intr_connect_level(cpuid_t cpu, + int bit, + ilvl_t is, + intr_func_t intr_prefunc) +{ + return(do_intr_connect_level(cpu, bit, 1)); +} + +int +intr_disconnect_level(cpuid_t cpu, + int bit) +{ + return(do_intr_connect_level(cpu, bit, 0)); +} + +// Choose a cpu on this node. +// We choose the one with the least number of int's assigned to it. + +static cpuid_t +do_intr_cpu_choose(cnodeid_t cnode) { + cpuid_t cpu, best_cpu = CPU_NONE; + int slice, min_count = 1000; + irqpda_t *irqs; + + for (slice = 0; slice < CPUS_PER_NODE; slice++) { + int intrs; + + cpu = cnode_slice_to_cpuid(cnode, slice); + if (cpu == CPU_NONE) { + continue; + } + + if (!cpu_enabled(cpu)) { + continue; + } + + irqs = irqpdaindr[cpu]; + intrs = irqs->num_irq_used; + + if (min_count > intrs) { + min_count = intrs; + best_cpu = cpu; + } + } + return best_cpu; +} + +static cpuid_t +intr_cpu_choose_from_node(cnodeid_t cnode) +{ + return(do_intr_cpu_choose(cnode)); +} + +// See if we can use this cpu/vect. + +static cpuid_t +intr_bit_reserve_test(cpuid_t cpu, + int favor_subnode, + cnodeid_t cnode, + int req_bit, + int resflags, + devfs_handle_t owner_dev, + char *name, + int *resp_bit) +{ + ASSERT( (cpu == CPU_NONE) || (cnode == CNODEID_NONE) ); + + if (cnode != CNODEID_NONE) { + cpu = intr_cpu_choose_from_node(cnode); + } + + if (cpu != CPU_NONE) { + *resp_bit = do_intr_reserve_level(cpu, req_bit, 1); + if (*resp_bit >= 0) { + return(cpu); + } + } + return CPU_NONE; +} + +// Find the node to assign for this interrupt. + +cpuid_t +intr_heuristic(devfs_handle_t dev, + device_desc_t dev_desc, + int req_bit, + int resflags, + devfs_handle_t owner_dev, + char *name, + int *resp_bit) +{ + cpuid_t cpuid; + cnodeid_t candidate = -1; + devfs_handle_t pconn_vhdl; + pcibr_soft_t pcibr_soft; + +/* SN2 + pcibr addressing limitation */ +/* Due to this limitation, all interrupts from a given bridge must go to the name node.*/ +/* This limitation does not exist on PIC. */ + + if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && + ( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) { + if (pcibr_soft->bsi_err_intr) { + candidate = cpuid_to_cnodeid( ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid); + } + } + + if (candidate >= 0) { + // The node was chosen already when we assigned the error interrupt. + cpuid = intr_bit_reserve_test(CPU_NONE, + 0, + candidate, + req_bit, + 0, + owner_dev, + name, + resp_bit); + } else { + // Need to choose one. Try the controlling c-brick first. + cpuid = intr_bit_reserve_test(CPU_NONE, + 0, + master_node_get(dev), + req_bit, + 0, + owner_dev, + name, + resp_bit); + } + + if (cpuid != CPU_NONE) { + return cpuid; + } + + if (candidate >= 0) { + printk("Cannot target interrupt to target node (%d).\n",candidate); + return CPU_NONE; + } else { + printk("Cannot target interrupt to closest node (%d) 0x%p\n", + master_node_get(dev), (void *)owner_dev); + } + + // We couldn't put it on the closest node. Try to find another one. + // Do a stupid round-robin assignment of the node. + + { + static cnodeid_t last_node = -1; + if (last_node >= numnodes) last_node = 0; + for (candidate = last_node + 1; candidate != last_node; candidate++) { + if (candidate == numnodes) candidate = 0; + cpuid = intr_bit_reserve_test(CPU_NONE, + 0, + candidate, + req_bit, + 0, + owner_dev, + name, + resp_bit); + if (cpuid != CPU_NONE) { + return cpuid; + } + } + } + + printk("cannot target interrupt: 0x%p\n",(void *)owner_dev); + return CPU_NONE; +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,454 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +uint64_t atealloc(struct map *mp, size_t size); +void atefree(struct map *mp, size_t size, uint64_t a); +void atemapfree(struct map *mp); +struct map *atemapalloc(uint64_t mapsiz); + +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + + +#ifdef LATER +#if (PCIBR_FREEZE_TIME) || PCIBR_ATE_DEBUG +LOCAL struct reg_desc ate_bits[] = +{ + {0xFFFF000000000000ull, -48, "RMF", "%x"}, + {~(IOPGSIZE - 1) & /* may trim off some low bits */ + 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, + {0x0000000000000F00ull, -8, "port", "%x"}, + {0x0000000000000010ull, 0, "Barrier"}, + {0x0000000000000008ull, 0, "Prefetch"}, + {0x0000000000000004ull, 0, "Precise"}, + {0x0000000000000002ull, 0, "Coherent"}, + {0x0000000000000001ull, 0, "Valid"}, + {0} +}; +#endif +#endif /* LATER */ + +#ifndef LOCAL +#define LOCAL static +#endif + +/* + * functions + */ +int pcibr_init_ext_ate_ram(bridge_t *); +int pcibr_ate_alloc(pcibr_soft_t, int); +void pcibr_ate_free(pcibr_soft_t, int, int); +bridge_ate_t pcibr_flags_to_ate(unsigned); +bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); +unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, +#if PCIBR_FREEZE_TIME + unsigned *freeze_time_ptr, +#endif + unsigned *cmd_regs); +void ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); +void ate_thaw(pcibr_dmamap_t pcibr_dmamap, + int ate_index, +#if PCIBR_FREEZE_TIME + bridge_ate_t ate, + int ate_total, + unsigned freeze_time_start, +#endif + unsigned *cmd_regs, + unsigned s); + + +/* Convert from ssram_bits in control register to number of SSRAM entries */ +#define ATE_NUM_ENTRIES(n) _ate_info[n] + +/* Possible choices for number of ATE entries in Bridge's SSRAM */ +LOCAL int _ate_info[] = +{ + 0, /* 0 entries */ + 8 * 1024, /* 8K entries */ + 16 * 1024, /* 16K entries */ + 64 * 1024 /* 64K entries */ +}; + +#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) +#define ATE_PROBE_VALUE 0x0123456789abcdefULL + +/* + * Determine the size of this bridge's external mapping SSRAM, and set + * the control register appropriately to reflect this size, and initialize + * the external SSRAM. + */ +int +pcibr_init_ext_ate_ram(bridge_t *bridge) +{ + int largest_working_size = 0; + int num_entries, entry; + int i, j; + bridgereg_t old_enable, new_enable; + int s; + + /* Probe SSRAM to determine its size. */ + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; + + for (i = 1; i < ATE_NUM_SIZES; i++) { + /* Try writing a value */ + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; + + /* Guard against wrap */ + for (j = 1; j < i; j++) + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; + + /* See if value was written */ + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + largest_working_size = i; + } + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + + s = splhi(); + bridge->b_wid_control = (bridge->b_wid_control + & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) + | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + + num_entries = ATE_NUM_ENTRIES(largest_working_size); + +#if PCIBR_ATE_DEBUG + if (num_entries) + printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); + else + printk("bridge at 0x%x: no external ATE RAM found\n", bridge); +#endif + + /* Initialize external mapping entries */ + for (entry = 0; entry < num_entries; entry++) + bridge->b_ext_ate_ram[entry] = 0; + + return (num_entries); +} + +/* + * Allocate "count" contiguous Bridge Address Translation Entries + * on the specified bridge to be used for PCI to XTALK mappings. + * Indices in rm map range from 1..num_entries. Indicies returned + * to caller range from 0..num_entries-1. + * + * Return the start index on success, -1 on failure. + */ +int +pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) +{ + int index = 0; + + index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); + + if (!index && pcibr_soft->bs_ext_ate_map) + index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); + + /* rmalloc manages resources in the 1..n + * range, with 0 being failure. + * pcibr_ate_alloc manages resources + * in the 0..n-1 range, with -1 being failure. + */ + return index - 1; +} + +void +pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) +/* Who says there's no such thing as a free meal? :-) */ +{ + /* note the "+1" since rmalloc handles 1..n but + * we start counting ATEs at zero. + */ + rmfree((index < pcibr_soft->bs_int_ate_size) + ? pcibr_soft->bs_int_ate_map + : pcibr_soft->bs_ext_ate_map, + count, index + 1); +} + +/* + * Convert PCI-generic software flags and Bridge-specific software flags + * into Bridge-specific Address Translation Entry attribute bits. + */ +bridge_ate_t +pcibr_flags_to_ate(unsigned flags) +{ + bridge_ate_t attributes; + + /* default if nothing specified: + * NOBARRIER + * NOPREFETCH + * NOPRECISE + * COHERENT + * Plus the valid bit + */ + attributes = ATE_CO | ATE_V; + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { /* standard data channel */ + attributes &= ~ATE_BAR; /* no barrier */ + attributes |= ATE_PREF; /* prefetch on */ + } + if (flags & PCIIO_DMA_CMD) { /* standard command channel */ + attributes |= ATE_BAR; /* barrier bit on */ + attributes &= ~ATE_PREF; /* disable prefetch */ + } + /* Generic detail flags + */ + if (flags & PCIIO_PREFETCH) + attributes |= ATE_PREF; + if (flags & PCIIO_NOPREFETCH) + attributes &= ~ATE_PREF; + + /* Provider-specific flags + */ + if (flags & PCIBR_BARRIER) + attributes |= ATE_BAR; + if (flags & PCIBR_NOBARRIER) + attributes &= ~ATE_BAR; + + if (flags & PCIBR_PREFETCH) + attributes |= ATE_PREF; + if (flags & PCIBR_NOPREFETCH) + attributes &= ~ATE_PREF; + + if (flags & PCIBR_PRECISE) + attributes |= ATE_PREC; + if (flags & PCIBR_NOPRECISE) + attributes &= ~ATE_PREC; + + return (attributes); +} + +/* + * Setup an Address Translation Entry as specified. Use either the Bridge + * internal maps or the external map RAM, as appropriate. + */ +bridge_ate_p +pcibr_ate_addr(pcibr_soft_t pcibr_soft, + int ate_index) +{ + bridge_t *bridge = pcibr_soft->bs_base; + + return (ate_index < pcibr_soft->bs_int_ate_size) + ? &(bridge->b_int_ate_ram[ate_index].wr) + : &(bridge->b_ext_ate_ram[ate_index]); +} + +/* We are starting to get more complexity + * surrounding writing ATEs, so pull + * the writing code into this new function. + */ + +#if PCIBR_FREEZE_TIME +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) +#else +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) +#endif + +unsigned +ate_freeze(pcibr_dmamap_t pcibr_dmamap, +#if PCIBR_FREEZE_TIME + unsigned *freeze_time_ptr, +#endif + unsigned *cmd_regs) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; +#ifdef LATER + int dma_slot = pcibr_dmamap->bd_slot; +#endif + int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; + int slot; + + unsigned long s; + unsigned cmd_reg; + volatile unsigned *cmd_lwa; + unsigned cmd_lwd; + + if (!ext_ates) + return 0; + + /* Bridge Hardware Bug WAR #484930: + * Bridge can't handle updating External ATEs + * while DMA is occuring that uses External ATEs, + * even if the particular ATEs involved are disjoint. + */ + + /* need to prevent anyone else from + * unfreezing the grant while we + * are working; also need to prevent + * this thread from being interrupted + * to keep PCI grant freeze time + * at an absolute minimum. + */ + s = pcibr_lock(pcibr_soft); + +#ifdef LATER + /* just in case pcibr_dmamap_done was not called */ + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { + pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) + atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); + xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); + } +#endif /* LATER */ +#if PCIBR_FREEZE_TIME + *freeze_time_ptr = get_timestamp(); +#endif + + cmd_lwa = 0; + for (slot = 0; slot < 8; ++slot) + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { + cmd_reg = pcibr_soft-> + bs_slot[slot]. + bss_cmd_shadow; + if (cmd_reg & PCI_CMD_BUS_MASTER) { + cmd_lwa = pcibr_soft-> + bs_slot[slot]. + bss_cmd_pointer; + cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; + cmd_lwa[0] = cmd_lwd; + } + cmd_regs[slot] = cmd_reg; + } else + cmd_regs[slot] = 0; + + if (cmd_lwa) { + bridge_t *bridge = pcibr_soft->bs_base; + + /* Read the last master bit that has been cleared. This PIO read + * on the PCI bus is to ensure the completion of any DMAs that + * are due to bus requests issued by PCI devices before the + * clearing of master bits. + */ + cmd_lwa[0]; + + /* Flush all the write buffers in the bridge */ + for (slot = 0; slot < 8; ++slot) + if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { + /* Flush the write buffer associated with this + * PCI device which might be using dma map RAM. + */ + bridge->b_wr_req_buf[slot].reg; + } + } + return s; +} + +#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) + +void +ate_write(bridge_ate_p ate_ptr, + int ate_count, + bridge_ate_t ate) +{ + while (ate_count-- > 0) { + *ate_ptr++ = ate; + ate += IOPGSIZE; + } +} + +#if PCIBR_FREEZE_TIME +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) +#else +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) +#endif + +void +ate_thaw(pcibr_dmamap_t pcibr_dmamap, + int ate_index, +#if PCIBR_FREEZE_TIME + bridge_ate_t ate, + int ate_total, + unsigned freeze_time_start, +#endif + unsigned *cmd_regs, + unsigned s) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; + int dma_slot = pcibr_dmamap->bd_slot; + int slot; + bridge_t *bridge = pcibr_soft->bs_base; + int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; + + unsigned cmd_reg; + +#if PCIBR_FREEZE_TIME + unsigned freeze_time; + static unsigned max_freeze_time = 0; + static unsigned max_ate_total; +#endif + + if (!ext_ates) + return; + + /* restore cmd regs */ + for (slot = 0; slot < 8; ++slot) + if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) + bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; + + pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; + atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); + +#if PCIBR_FREEZE_TIME + freeze_time = get_timestamp() - freeze_time_start; + + if ((max_freeze_time < freeze_time) || + (max_ate_total < ate_total)) { + if (max_freeze_time < freeze_time) + max_freeze_time = freeze_time; + if (max_ate_total < ate_total) + max_ate_total = ate_total; + pcibr_unlock(pcibr_soft, s); + printk("%s: pci freeze time %d usec for %d ATEs\n" + "\tfirst ate: %R\n", + pcibr_soft->bs_name, + freeze_time * 1000 / 1250, + ate_total, + ate, ate_bits); + } else +#endif + pcibr_unlock(pcibr_soft, s); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,167 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern pcibr_info_t pcibr_info_get(devfs_handle_t); + +uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); +uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); +void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); + +#ifdef LITTLE_ENDIAN +#ifdef CONFIG_IA64_SGI_SN1 +/* + * on sn-ia we need to twiddle the the addresses going out + * the pci bus because we use the unswizzled synergy space + * (the alternative is to use the swizzled synergy space + * and byte swap the data) + */ +#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) +#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) +#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) +#else +#ifdef CONFIG_IA64_SGI_SN2 +/* + * On sn-ia sn2 everything is little endian. No swizzling + * or byte swapping of addresses required. + */ +#define CB(b,r) (((volatile uint8_t *) b)[(r)]) +#define CS(b,r) (((volatile uint16_t *) b)[(r)/2]) +#define CW(b,r) (((volatile uint32_t *) b)[(r)/4]) +#endif +#endif +#else +#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) +#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) +#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) +#endif + + +cfg_p +pcibr_config_addr(devfs_handle_t conn, + unsigned reg) +{ + pcibr_info_t pcibr_info; + pciio_slot_t pciio_slot; + pciio_function_t pciio_func; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + cfg_p cfgbase = (cfg_p)0; + + pcibr_info = pcibr_info_get(conn); + + pciio_slot = pcibr_info->f_slot; + if (pciio_slot == PCIIO_SLOT_NONE) + pciio_slot = PCI_TYPE1_SLOT(reg); + + pciio_func = pcibr_info->f_func; + if (pciio_func == PCIIO_FUNC_NONE) + pciio_func = PCI_TYPE1_FUNC(reg); + + pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + + bridge = pcibr_soft->bs_base; + + cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; + + return cfgbase; +} + +uint64_t +pcibr_config_get(devfs_handle_t conn, + unsigned reg, + unsigned size) +{ + return do_pcibr_config_get(pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size); +} + +uint64_t +do_pcibr_config_get( + cfg_p cfgbase, + unsigned reg, + unsigned size) +{ + unsigned value; + + value = CW(cfgbase, reg); + + if (reg & 3) + value >>= 8 * (reg & 3); + if (size < 4) + value &= (1 << (8 * size)) - 1; + return value; +} + +void +pcibr_config_set(devfs_handle_t conn, + unsigned reg, + unsigned size, + uint64_t value) +{ + do_pcibr_config_set(pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size, value); +} + +void +do_pcibr_config_set(cfg_p cfgbase, + unsigned reg, + unsigned size, + uint64_t value) +{ + switch (size) { + case 1: + CB(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { + CB(cfgbase, reg) = value; + CB(cfgbase, reg + 1) = value >> 8; + } else + CS(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CB(cfgbase, reg) = value; + CS(cfgbase, (reg + 1)) = value >> 8; + } else { + CS(cfgbase, reg) = value; + CB(cfgbase, reg + 2) = value >> 16; + } + break; + + case 4: + CW(cfgbase, reg) = value; + break; + } +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,4288 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +/* + * Macros related to the Lucent USS 302/312 usb timeout workaround. It + * appears that if the lucent part can get into a retry loop if it sees a + * DAC on the bus during a pio read retry. The loop is broken after about + * 1ms, so we need to set up bridges holding this part to allow at least + * 1ms for pio. + */ + +#define USS302_TIMEOUT_WAR + +#ifdef USS302_TIMEOUT_WAR +#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 +#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 +#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 +#define USS302_BRIDGE_TIMEOUT_HLD 4 +#endif + +int pcibr_devflag = D_MP; + +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations pcibr_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: NULL, + open: NULL, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL +}; + +#ifdef LATER + +#if PCIBR_ATE_DEBUG +static struct reg_values ssram_sizes[] = +{ + {BRIDGE_CTRL_SSRAM_512K, "512k"}, + {BRIDGE_CTRL_SSRAM_128K, "128k"}, + {BRIDGE_CTRL_SSRAM_64K, "64k"}, + {BRIDGE_CTRL_SSRAM_1K, "1k"}, + {0} +}; + +static struct reg_desc control_bits[] = +{ + {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, + {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, + {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, + {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, + {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, + {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, + {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, + {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, + {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, + {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, + {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, + {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, + {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, + {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, + {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, + {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, + + {BRIDGE_CTRL_BUS_SPEED_MASK, -4, "BUS_SPEED", "%d"}, + {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, + {0} +}; +#endif +#endif /* LATER */ + +/* kbrick widgetnum-to-bus layout */ +int p_busnum[MAX_PORT_NUM] = { /* widget# */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 2, /* 0x8 */ + 1, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 5, /* 0xc */ + 6, /* 0xd */ + 4, /* 0xe */ + 3, /* 0xf */ +}; + +/* + * Additional PIO spaces per slot are + * recorded in this structure. + */ +struct pciio_piospace_s { + pciio_piospace_t next; /* another space for this device */ + char free; /* 1 if free, 0 if in use */ + pciio_space_t space; /* Which space is in use */ + iopaddr_t start; /* Starting address of the PIO space */ + size_t count; /* size of PIO space */ +}; + +#if PCIBR_SOFT_LIST +pcibr_list_p pcibr_list = 0; +#endif + +extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); +extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); +extern long atoi(register char *p); +extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); +extern void *swap_ptr(void **loc, void *new); +extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); +extern struct map *atemapalloc(uint64_t); +extern void atefree(struct map *, size_t, uint64_t); +extern void atemapfree(struct map *); +extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +extern void free_pciio_dmamap(pcibr_dmamap_t); + +#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) +#if PCIBR_FREEZE_TIME +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) +#else +#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) +#endif /* PCIBR_FREEZE_TIME */ + +#if PCIBR_FREEZE_TIME +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) +#else +#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) +#endif + + +/* ===================================================================== + * Function Table of Contents + * + * The order of functions in this file has stopped + * making much sense. We might want to take a look + * at it some time and bring back some sanity, or + * perhaps bust this file into smaller chunks. + */ + +extern void do_pcibr_rrb_clear(bridge_t *, int); +extern void do_pcibr_rrb_flush(bridge_t *, int); +extern int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); +extern int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); +extern int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); +extern int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); + +extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); + +extern int pcibr_wrb_flush(devfs_handle_t); +extern int pcibr_rrb_alloc(devfs_handle_t, int *, int *); +extern int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); +extern int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); +extern void pcibr_rrb_flush(devfs_handle_t); + +static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); +void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); + +extern void pcibr_clearwidint(bridge_t *); +extern void pcibr_setwidint(xtalk_intr_t); + +void pcibr_init(void); +int pcibr_attach(devfs_handle_t); +int pcibr_detach(devfs_handle_t); +int pcibr_open(devfs_handle_t *, int, int, cred_t *); +int pcibr_close(devfs_handle_t, int, int, cred_t *); +int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); +int pcibr_unmap(devfs_handle_t, vhandl_t *); +int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); + +void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); + +extern int pcibr_init_ext_ate_ram(bridge_t *); +extern int pcibr_ate_alloc(pcibr_soft_t, int); +extern void pcibr_ate_free(pcibr_soft_t, int, int); + +extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, +#if PCIBR_FREEZE_TIME + unsigned *freeze_time_ptr, +#endif + unsigned *cmd_regs); +extern void ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); +extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, +#if PCIBR_FREEZE_TIME + bridge_ate_t ate, + int ate_total, + unsigned freeze_time_start, +#endif + unsigned *cmd_regs, + unsigned s); + +pcibr_info_t pcibr_info_get(devfs_handle_t); + +static iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); + +pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +void pcibr_piomap_free(pcibr_piomap_t); +caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); +void pcibr_piomap_done(pcibr_piomap_t); +caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); +void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); + +static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); +extern bridge_ate_t pcibr_flags_to_ate(unsigned); + +pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void pcibr_dmamap_free(pcibr_dmamap_t); +extern bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); +static iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); +iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); +alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); +void pcibr_dmamap_done(pcibr_dmamap_t); +cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); +iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void pcibr_dmamap_drain(pcibr_dmamap_t); +void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); +void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); +iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); + +extern unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); +extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +extern void pcibr_intr_free(pcibr_intr_t); +extern void pcibr_setpciint(xtalk_intr_t); +extern int pcibr_intr_connect(pcibr_intr_t); +extern void pcibr_intr_disconnect(pcibr_intr_t); + +extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +extern void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); +extern void pcibr_intr_func(intr_arg_t); + +extern void print_bridge_errcmd(uint32_t, char *); + +extern void pcibr_error_dump(pcibr_soft_t); +extern uint32_t pcibr_errintr_group(uint32_t); +extern void pcibr_pioerr_check(pcibr_soft_t); +extern void pcibr_error_intr_handler(intr_arg_t); + +extern int pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *); +extern void pcibr_error_cleanup(pcibr_soft_t, int); +extern void pcibr_device_disable(pcibr_soft_t, int); +extern int pcibr_pioerror(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); +extern int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); +extern int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); +extern int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); +extern int pcibr_error_devenable(devfs_handle_t, int); + +void pcibr_provider_startup(devfs_handle_t); +void pcibr_provider_shutdown(devfs_handle_t); + +int pcibr_reset(devfs_handle_t); +pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); +pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); +int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); + +extern cfg_p pcibr_config_addr(devfs_handle_t, unsigned); +extern uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); +extern void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); +extern void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); + +extern pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); +extern void pcibr_hints_fix_rrbs(devfs_handle_t); +extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); +extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); +extern void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); +extern void pcibr_hints_handsoff(devfs_handle_t); +extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); + +#ifdef BRIDGE_B_DATACORR_WAR +extern int ql_bridge_rev_b_war(devfs_handle_t); +extern int bridge_rev_b_data_check_disable; +char *rev_b_datacorr_warning = +"***************************** WARNING! ******************************\n"; +char *rev_b_datacorr_mesg = +"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n"; +#endif + +extern int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); +extern int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_call_device_attach(devfs_handle_t, pciio_slot_t, int); +extern int pcibr_slot_call_device_detach(devfs_handle_t, pciio_slot_t, int); +extern int pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, char *, int *); +extern int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); +extern int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); + +#ifdef LATER +extern int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t); +extern int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t); +extern int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t); +#endif + +extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t); +extern int pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t); + + + +/* ===================================================================== + * Device(x) register management + */ + +/* pcibr_try_set_device: attempt to modify Device(x) + * for the specified slot on the specified bridge + * as requested in flags, limited to the specified + * bits. Returns which BRIDGE bits were in conflict, + * or ZERO if everything went OK. + * + * Caller MUST hold pcibr_lock when calling this function. + */ +static int +pcibr_try_set_device(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + unsigned flags, + bridgereg_t mask) +{ + bridge_t *bridge; + pcibr_soft_slot_t slotp; + bridgereg_t old; + bridgereg_t new; + bridgereg_t chg; + bridgereg_t bad; + bridgereg_t badpmu; + bridgereg_t badd32; + bridgereg_t badd64; + bridgereg_t fix; + unsigned long s; + bridgereg_t xmask; + + xmask = mask; + if (pcibr_soft->bs_xbridge) { + if (mask == BRIDGE_DEV_PMU_BITS) + xmask = XBRIDGE_DEV_PMU_BITS; + if (mask == BRIDGE_DEV_D64_BITS) + xmask = XBRIDGE_DEV_D64_BITS; + } + + slotp = &pcibr_soft->bs_slot[slot]; + + s = pcibr_lock(pcibr_soft); + + bridge = pcibr_soft->bs_base; + + old = slotp->bss_device; + + /* figure out what the desired + * Device(x) bits are based on + * the flags specified. + */ + + new = old; + + /* Currently, we inherit anything that + * the new caller has not specified in + * one way or another, unless we take + * action here to not inherit. + * + * This is needed for the "swap" stuff, + * since it could have been set via + * pcibr_endian_set -- altho note that + * any explicit PCIBR_BYTE_STREAM or + * PCIBR_WORD_VALUES will freely override + * the effect of that call (and vice + * versa, no protection either way). + * + * I want to get rid of pcibr_endian_set + * in favor of tracking DMA endianness + * using the flags specified when DMA + * channels are created. + */ + +#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) +#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) + + /* Do not use Barrier, Write Gather, + * or Prefetch unless asked. + * Leave everything else as it + * was from the last time. + */ + new = new + & ~BRIDGE_DEV_BARRIER + & ~BRIDGE_DEV_WRGA_BITS + & ~BRIDGE_DEV_PREF + ; + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { + new = (new + & ~BRIDGE_DEV_BARRIER) /* barrier off */ + | BRIDGE_DEV_PREF; /* prefetch on */ + + } + if (flags & PCIIO_DMA_CMD) { + new = ((new + & ~BRIDGE_DEV_PREF) /* prefetch off */ + & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ + | BRIDGE_DEV_BARRIER; /* barrier on */ + } + /* Generic detail flags + */ + if (flags & PCIIO_WRITE_GATHER) + new |= BRIDGE_DEV_WRGA_BITS; + if (flags & PCIIO_NOWRITE_GATHER) + new &= ~BRIDGE_DEV_WRGA_BITS; + + if (flags & PCIIO_PREFETCH) + new |= BRIDGE_DEV_PREF; + if (flags & PCIIO_NOPREFETCH) + new &= ~BRIDGE_DEV_PREF; + + if (flags & PCIBR_WRITE_GATHER) + new |= BRIDGE_DEV_WRGA_BITS; + if (flags & PCIBR_NOWRITE_GATHER) + new &= ~BRIDGE_DEV_WRGA_BITS; + + if (flags & PCIIO_BYTE_STREAM) + new |= (pcibr_soft->bs_xbridge) ? + BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; + if (flags & PCIIO_WORD_VALUES) + new &= (pcibr_soft->bs_xbridge) ? + ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; + + /* Provider-specific flags + */ + if (flags & PCIBR_PREFETCH) + new |= BRIDGE_DEV_PREF; + if (flags & PCIBR_NOPREFETCH) + new &= ~BRIDGE_DEV_PREF; + + if (flags & PCIBR_PRECISE) + new |= BRIDGE_DEV_PRECISE; + if (flags & PCIBR_NOPRECISE) + new &= ~BRIDGE_DEV_PRECISE; + + if (flags & PCIBR_BARRIER) + new |= BRIDGE_DEV_BARRIER; + if (flags & PCIBR_NOBARRIER) + new &= ~BRIDGE_DEV_BARRIER; + + if (flags & PCIBR_64BIT) + new |= BRIDGE_DEV_DEV_SIZE; + if (flags & PCIBR_NO64BIT) + new &= ~BRIDGE_DEV_DEV_SIZE; + + chg = old ^ new; /* what are we changing, */ + chg &= xmask; /* of the interesting bits */ + + if (chg) { + + badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; + if (pcibr_soft->bs_xbridge) { + badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; + badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; + } else { + badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; + badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; + } + bad = badpmu | badd32 | badd64; + + if (bad) { + + /* some conflicts can be resolved by + * forcing the bit on. this may cause + * some performance degredation in + * the stream(s) that want the bit off, + * but the alternative is not allowing + * the new stream at all. + */ + if ( (fix = bad & (BRIDGE_DEV_PRECISE | + BRIDGE_DEV_BARRIER)) ){ + bad &= ~fix; + /* don't change these bits if + * they are already set in "old" + */ + chg &= ~(fix & old); + } + /* some conflicts can be resolved by + * forcing the bit off. this may cause + * some performance degredation in + * the stream(s) that want the bit on, + * but the alternative is not allowing + * the new stream at all. + */ + if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | + BRIDGE_DEV_PREF)) ) { + bad &= ~fix; + /* don't change these bits if + * we wanted to turn them on. + */ + chg &= ~(fix & new); + } + /* conflicts in other bits mean + * we can not establish this DMA + * channel while the other(s) are + * still present. + */ + if (bad) { + pcibr_unlock(pcibr_soft, s); +#if (DEBUG && PCIBR_DEV_DEBUG) + printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); +#endif + return bad; + } + } + } + if (mask == BRIDGE_DEV_PMU_BITS) + slotp->bss_pmu_uctr++; + if (mask == BRIDGE_DEV_D32_BITS) + slotp->bss_d32_uctr++; + if (mask == BRIDGE_DEV_D64_BITS) + slotp->bss_d64_uctr++; + + /* the value we want to write is the + * original value, with the bits for + * our selected changes flipped, and + * with any disabled features turned off. + */ + new = old ^ chg; /* only change what we want to change */ + + if (slotp->bss_device == new) { + pcibr_unlock(pcibr_soft, s); + return 0; + } + bridge->b_device[slot].reg = new; + slotp->bss_device = new; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); +#endif + + return 0; +} + +void +pcibr_release_device(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + bridgereg_t mask) +{ + pcibr_soft_slot_t slotp; + unsigned long s; + + slotp = &pcibr_soft->bs_slot[slot]; + + s = pcibr_lock(pcibr_soft); + + if (mask == BRIDGE_DEV_PMU_BITS) + slotp->bss_pmu_uctr--; + if (mask == BRIDGE_DEV_D32_BITS) + slotp->bss_d32_uctr--; + if (mask == BRIDGE_DEV_D64_BITS) + slotp->bss_d64_uctr--; + + pcibr_unlock(pcibr_soft, s); +} + +/* + * flush write gather buffer for slot + */ +static void +pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, + pciio_slot_t slot) +{ + bridge_t *bridge; + unsigned long s; + volatile uint32_t wrf; + s = pcibr_lock(pcibr_soft); + bridge = pcibr_soft->bs_base; + wrf = bridge->b_wr_req_buf[slot].reg; + pcibr_unlock(pcibr_soft, s); +} + +/* ===================================================================== + * Bridge (pcibr) "Device Driver" entry points + */ + + +/* + * pcibr_init: called once during system startup or + * when a loadable driver is loaded. + * + * The driver_register function should normally + * be in _reg, not _init. But the pcibr driver is + * required by devinit before the _reg routines + * are called, so this is an exception. + */ +void +pcibr_init(void) +{ +#if DEBUG && ATTACH_DEBUG + printk("pcibr_init\n"); +#endif + + xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, + XBRIDGE_WIDGET_MFGR_NUM, + "pcibr_", + 0); + xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, + BRIDGE_WIDGET_MFGR_NUM, + "pcibr_", + 0); +} + +/* + * open/close mmap/munmap interface would be used by processes + * that plan to map the PCI bridge, and muck around with the + * registers. This is dangerous to do, and will be allowed + * to a select brand of programs. Typically these are + * diagnostics programs, or some user level commands we may + * write to do some weird things. + * To start with expect them to have root priveleges. + * We will ask for more later. + */ +/* ARGSUSED */ +int +pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) +{ + return 0; +} + +/*ARGSUSED */ +int +pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) +{ + return 0; +} + +/*ARGSUSED */ +int +pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) +{ + int error; + devfs_handle_t vhdl = dev_to_vhdl(dev); + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge = pcibr_soft->bs_base; + + hwgraph_vertex_unref(pcibr_vhdl); + + ASSERT(pcibr_soft); + len = ctob(btoc(len)); /* Make len page aligned */ + error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); + + /* + * If the offset being mapped corresponds to the flash prom + * base, and if the mapping succeeds, and if the user + * has requested the protections to be WRITE, enable the + * flash prom to be written. + * + * XXX- deprecate this in favor of using the + * real flash driver ... + */ + if (!error && + ((off == BRIDGE_EXTERNAL_FLASH) || + (len > BRIDGE_EXTERNAL_FLASH))) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + + return error; +} + +/*ARGSUSED */ +int +pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) +{ + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge = pcibr_soft->bs_base; + + hwgraph_vertex_unref(pcibr_vhdl); + + /* + * If flashprom write was enabled, disable it, as + * this is the last unmap. + */ + if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + return 0; +} + +/* This is special case code used by grio. There are plans to make + * this a bit more general in the future, but till then this should + * be sufficient. + */ +pciio_slot_t +pcibr_device_slot_get(devfs_handle_t dev_vhdl) +{ + char devname[MAXDEVNAME]; + devfs_handle_t tdev; + pciio_info_t pciio_info; + pciio_slot_t slot = PCIIO_SLOT_NONE; + + vertex_to_name(dev_vhdl, devname, MAXDEVNAME); + + /* run back along the canonical path + * until we find a PCI connection point. + */ + tdev = hwgraph_connectpt_get(dev_vhdl); + while (tdev != GRAPH_VERTEX_NONE) { + pciio_info = pciio_info_chk(tdev); + if (pciio_info) { + slot = pciio_info_slot_get(pciio_info); + break; + } + hwgraph_vertex_unref(tdev); + tdev = hwgraph_connectpt_get(tdev); + } + hwgraph_vertex_unref(tdev); + + return slot; +} + +/*ARGSUSED */ +int +pcibr_ioctl(devfs_handle_t dev, + int cmd, + void *arg, + int flag, + struct cred *cr, + int *rvalp) +{ + devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); +#ifdef LATER + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); +#endif + int error = 0; + + hwgraph_vertex_unref(pcibr_vhdl); + + switch (cmd) { +#ifdef LATER + case GIOCSETBW: + { + grio_ioctl_info_t info; + pciio_slot_t slot = 0; + + if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { + error = EFAULT; + break; + } +#ifdef GRIO_DEBUG + printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", + info.prev_vhdl, info.reqbw); +#endif /* GRIO_DEBUG */ + + if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == + PCIIO_SLOT_NONE) { + error = EIO; + break; + } + if (info.reqbw) + pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); + break; + } + + case GIOCRELEASEBW: + { + grio_ioctl_info_t info; + pciio_slot_t slot = 0; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { + error = EFAULT; + break; + } +#ifdef GRIO_DEBUG + printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", + info.prev_vhdl, info.reqbw); +#endif /* GRIO_DEBUG */ + + if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == + PCIIO_SLOT_NONE) { + error = EIO; + break; + } + if (info.reqbw) + pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); + break; + } + + case PCIBR_SLOT_STARTUP: + { + struct pcibr_slot_req_s req; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_startup(pcibr_vhdl, &req); + break; + } + case PCIBR_SLOT_SHUTDOWN: + { + struct pcibr_slot_req_s req; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_shutdown(pcibr_vhdl, &req); + break; + } + case PCIBR_SLOT_QUERY: + { + struct pcibr_slot_req_s req; + + if (!cap_able(CAP_DEVICE_MGT)) { + error = EPERM; + break; + } + + if (COPYIN(arg, &req, sizeof(req))) { + error = EFAULT; + break; + } + + error = pcibr_slot_query(pcibr_vhdl, &req); + break; + } +#endif /* LATER */ + default: + break; + + } + + return error; +} + +void +pcibr_freeblock_sub(iopaddr_t *free_basep, + iopaddr_t *free_lastp, + iopaddr_t base, + size_t size) +{ + iopaddr_t free_base = *free_basep; + iopaddr_t free_last = *free_lastp; + iopaddr_t last = base + size - 1; + + if ((last < free_base) || (base > free_last)); /* free block outside arena */ + + else if ((base <= free_base) && (last >= free_last)) + /* free block contains entire arena */ + *free_basep = *free_lastp = 0; + + else if (base <= free_base) + /* free block is head of arena */ + *free_basep = last + 1; + + else if (last >= free_last) + /* free block is tail of arena */ + *free_lastp = base - 1; + + /* + * We are left with two regions: the free area + * in the arena "below" the block, and the free + * area in the arena "above" the block. Keep + * the one that is bigger. + */ + + else if ((base - free_base) > (free_last - last)) + *free_lastp = base - 1; /* keep lower chunk */ + else + *free_basep = last + 1; /* keep upper chunk */ +} + +pcibr_info_t +pcibr_info_get(devfs_handle_t vhdl) +{ + return (pcibr_info_t) pciio_info_get(vhdl); +} + +pcibr_info_t +pcibr_device_info_new( + pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pciio_function_t rfunc, + pciio_vendor_id_t vendor, + pciio_device_id_t device) +{ + pcibr_info_t pcibr_info; + pciio_function_t func; + int ibit; + + func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; + + NEW(pcibr_info); + + pciio_device_info_new(&pcibr_info->f_c, + pcibr_soft->bs_vhdl, + slot, rfunc, + vendor, device); + +/* pfg - this is new ..... */ + /* Set PCI bus number */ + pcibr_info->f_bus = io_path_map_widget(pcibr_soft->bs_vhdl); + + if (slot != PCIIO_SLOT_NONE) { + + /* + * Currently favored mapping from PCI + * slot number and INTA/B/C/D to Bridge + * PCI Interrupt Bit Number: + * + * SLOT A B C D + * 0 0 4 0 4 + * 1 1 5 1 5 + * 2 2 6 2 6 + * 3 3 7 3 7 + * 4 4 0 4 0 + * 5 5 1 5 1 + * 6 6 2 6 2 + * 7 7 3 7 3 + * + * XXX- allow pcibr_hints to override default + * XXX- allow ADMIN to override pcibr_hints + */ + for (ibit = 0; ibit < 4; ++ibit) + pcibr_info->f_ibit[ibit] = + (slot + 4 * ibit) & 7; + + /* + * Record the info in the sparse func info space. + */ + if (func < pcibr_soft->bs_slot[slot].bss_ninfo) + pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; + } + return pcibr_info; +} + + +/* FIXME: for now this is needed by both pcibr.c and + * pcibr_slot.c. Need to find a better way, the least + * of which would be to move it to pcibr_private.h + */ + +/* + * PCI_ADDR_SPACE_LIMITS_STORE + * Sets the current values of + * pci io base, + * pci io last, + * pci low memory base, + * pci low memory last, + * pci high memory base, + * pci high memory last + */ +#define PCI_ADDR_SPACE_LIMITS_STORE() \ + pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ + pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ + pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ + pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ + pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ + pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; + + +/* + * pcibr_device_unregister + * This frees up any hardware resources reserved for this PCI device + * and removes any PCI infrastructural information setup for it. + * This is usually used at the time of shutting down of the PCI card. + */ +int +pcibr_device_unregister(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + int count_vchan0, count_vchan1; + unsigned s; + int error_call; + int error = 0; + + pciio_info = pciio_info_get(pconn_vhdl); + + pcibr_vhdl = pciio_info_master_get(pciio_info); + slot = pciio_info_slot_get(pciio_info); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + + /* Clear all the hardware xtalk resources for this device */ + xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); + + /* Flush all the rrbs */ + pcibr_rrb_flush(pconn_vhdl); + + /* + * If the RRB configuration for this slot has changed, set it + * back to the boot-time default + */ + if (pcibr_soft->bs_rrb_valid_dflt[slot] >= 0) { + + s = pcibr_lock(pcibr_soft); + + /* Free the rrbs allocated to this slot */ + error_call = do_pcibr_rrb_free(bridge, slot, + pcibr_soft->bs_rrb_valid[slot] + + pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]); + + if (error_call) + error = ERANGE; + + pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + + pcibr_soft->bs_rrb_valid[slot] + + pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + + count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot]; + count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + + pcibr_unlock(pcibr_soft, s); + + pcibr_rrb_alloc(pconn_vhdl, &count_vchan0, &count_vchan1); + + } + + /* Flush the write buffers !! */ + error_call = pcibr_wrb_flush(pconn_vhdl); + + if (error_call) + error = error_call; + + /* Clear the information specific to the slot */ + error_call = pcibr_slot_info_free(pcibr_vhdl, slot); + + if (error_call) + error = error_call; + + return(error); + +} + +/* + * pcibr_driver_reg_callback + * CDL will call this function for each device found in the PCI + * registry that matches the vendor/device IDs supported by + * the driver being registered. The device's connection vertex + * and the driver's attach function return status enable the + * slot's device status to be set. + */ +void +pcibr_driver_reg_callback(devfs_handle_t pconn_vhdl, + int key1, int key2, int error) +{ + pciio_info_t pciio_info; + pcibr_info_t pcibr_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; + + /* Do not set slot status for vendor/device ID wildcard drivers */ + if ((key1 == -1) || (key2 == -1)) + return; + + pciio_info = pciio_info_get(pconn_vhdl); + pcibr_info = pcibr_info_get(pconn_vhdl); + + pcibr_vhdl = pciio_info_master_get(pciio_info); + slot = pciio_info_slot_get(pciio_info); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + /* This may be a loadable driver so lock out any pciconfig actions */ + mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); + + pcibr_info->f_att_det_error = error; + + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; + + if (error) { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; + } + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + +} + +/* + * pcibr_driver_unreg_callback + * CDL will call this function for each device found in the PCI + * registry that matches the vendor/device IDs supported by + * the driver being unregistered. The device's connection vertex + * and the driver's detach function return status enable the + * slot's device status to be set. + */ +void +pcibr_driver_unreg_callback(devfs_handle_t pconn_vhdl, + int key1, int key2, int error) +{ + pciio_info_t pciio_info; + pcibr_info_t pcibr_info; + devfs_handle_t pcibr_vhdl; + pciio_slot_t slot; + pcibr_soft_t pcibr_soft; + + /* Do not set slot status for vendor/device ID wildcard drivers */ + if ((key1 == -1) || (key2 == -1)) + return; + + pciio_info = pciio_info_get(pconn_vhdl); + pcibr_info = pcibr_info_get(pconn_vhdl); + + pcibr_vhdl = pciio_info_master_get(pciio_info); + slot = pciio_info_slot_get(pciio_info); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + /* This may be a loadable driver so lock out any pciconfig actions */ + mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); + + pcibr_info->f_att_det_error = error; + + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; + + if (error) { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; + } + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + +} + +/* + * build a convenience link path in the + * form of "...//bus/" + * + * returns 1 on success, 0 otherwise + * + * depends on hwgraph separator == '/' + */ +int +pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) +{ + char dst[MAXDEVNAME]; + char *dp = dst; + char *cp, *xp; + int widgetnum; + char pcibus[8]; + devfs_handle_t nvtx, svtx; + int rv; + +#if DEBUG + printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", + slot, f_c); + { + int pos; + char dname[256]; + pos = devfs_generate_path(f_c, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } +#endif + + if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) + return 0; + + /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ + + /* find the widget number */ + xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); + if (xp == NULL) + return 0; + widgetnum = atoi(xp+7); + if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) + return 0; + + /* remove "/pci/direct" from path */ + cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); + if (cp == NULL) + return 0; + *cp = (char)NULL; + + /* get the vertex for the widget */ + if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) + return 0; + + *xp = (char)NULL; /* remove "/xtalk/..." from path */ + + /* dst example now == /hw/module/001c02/Pbrick */ + + /* get the bus number */ + strcat(dst, "/bus"); + sprintf(pcibus, "%d", p_busnum[widgetnum]); + + /* link to bus to widget */ + rv = hwgraph_path_add(NULL, dp, &nvtx); + if (GRAPH_SUCCESS == rv) + rv = hwgraph_edge_add(nvtx, svtx, pcibus); + + return (rv == GRAPH_SUCCESS); +} + + +/* + * pcibr_attach: called every time the crosstalk + * infrastructure is asked to initialize a widget + * that matches the part number we handed to the + * registration routine above. + */ +/*ARGSUSED */ +int +pcibr_attach(devfs_handle_t xconn_vhdl) +{ + /* REFERENCED */ + graph_error_t rc; + devfs_handle_t pcibr_vhdl; + devfs_handle_t ctlr_vhdl; + bridge_t *bridge = NULL; + bridgereg_t id; + int rev; + pcibr_soft_t pcibr_soft; + pcibr_info_t pcibr_info; + xwidget_info_t info; + xtalk_intr_t xtalk_intr; + device_desc_t dev_desc = (device_desc_t)0; + int slot; + int ibit; + devfs_handle_t noslot_conn; + char devnm[MAXDEVNAME], *s; + pcibr_hints_t pcibr_hints; + bridgereg_t b_int_enable; + unsigned rrb_fixed = 0; + + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + + int spl_level; +#ifdef LATER + char *nicinfo = (char *)0; +#endif + +#if PCI_FBBE + int fast_back_to_back_enable; +#endif + l1sc_t *scp; + nasid_t nasid; + + async_attach_t aa = NULL; + + aa = async_attach_get_info(xconn_vhdl); + +#if DEBUG && ATTACH_DEBUG + printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); + { + int pos; + char dname[256]; + pos = devfs_generate_path(xconn_vhdl, dname, 256); + printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); + } +#endif + + /* Setup the PRB for the bridge in CONVEYOR BELT + * mode. PRBs are setup in default FIRE-AND-FORGET + * mode during the initialization. + */ + hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); + + bridge = (bridge_t *) + xtalk_piotrans_addr(xconn_vhdl, NULL, + 0, sizeof(bridge_t), 0); + + /* + * Create the vertex for the PCI bus, which we + * will also use to hold the pcibr_soft and + * which will be the "master" vertex for all the + * pciio connection points we will hang off it. + * This needs to happen before we call nic_bridge_vertex_info + * as we are some of the *_vmc functions need access to the edges. + * + * Opening this vertex will provide access to + * the Bridge registers themselves. + */ + rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); + ASSERT(rc == GRAPH_SUCCESS); + + ctlr_vhdl = NULL; + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &pcibr_fops, NULL); + + ASSERT(ctlr_vhdl != NULL); + + /* + * decode the nic, and hang its stuff off our + * connection point where other drivers can get + * at it. + */ +#ifdef LATER + nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); +#endif + + /* + * Get the hint structure; if some NIC callback + * marked this vertex as "hands-off" then we + * just return here, before doing anything else. + */ + pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); + + if (pcibr_hints && pcibr_hints->ph_hands_off) + return -1; /* generic operations disabled */ + + id = bridge->b_wid_id; + rev = XWIDGET_PART_REV_NUM(id); + + hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); + + /* + * allocate soft state structure, fill in some + * fields, and hook it up to our vertex. + */ + NEW(pcibr_soft); + BZERO(pcibr_soft, sizeof *pcibr_soft); + pcibr_soft_set(pcibr_vhdl, pcibr_soft); + + pcibr_soft->bs_conn = xconn_vhdl; + pcibr_soft->bs_vhdl = pcibr_vhdl; + pcibr_soft->bs_base = bridge; + pcibr_soft->bs_rev_num = rev; + pcibr_soft->bs_intr_bits = pcibr_intr_bits; + if (is_xbridge(bridge)) { + pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; + pcibr_soft->bs_xbridge = 1; + } else { + pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; + pcibr_soft->bs_xbridge = 0; + } + + nasid = NASID_GET(bridge); + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + pcibr_soft->bs_l1sc = scp; + pcibr_soft->bs_moduleid = iobrick_module_get(scp); + pcibr_soft->bsi_err_intr = 0; + + /* Bridges up through REV C + * are unable to set the direct + * byteswappers to BYTE_STREAM. + */ + if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { + pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; + pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; + } +#if PCIBR_SOFT_LIST + { + pcibr_list_p self; + + NEW(self); + self->bl_soft = pcibr_soft; + self->bl_vhdl = pcibr_vhdl; + self->bl_next = pcibr_list; + self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); + } +#endif + + /* + * get the name of this bridge vertex and keep the info. Use this + * only where it is really needed now: like error interrupts. + */ + s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); + pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); + strcpy(pcibr_soft->bs_name, s); + +#if SHOW_REVS || DEBUG +#if !DEBUG + if (kdebug) +#endif + printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", + is_xbridge(bridge) ? "X" : "", + (rev == BRIDGE_PART_REV_A) ? "A" : + (rev == BRIDGE_PART_REV_B) ? "B" : + (rev == BRIDGE_PART_REV_C) ? "C" : + (rev == BRIDGE_PART_REV_D) ? "D" : + (rev == XBRIDGE_PART_REV_A) ? "A" : + (rev == XBRIDGE_PART_REV_B) ? "B" : + "unknown", + rev, pcibr_soft->bs_name); +#endif + + info = xwidget_info_get(xconn_vhdl); + pcibr_soft->bs_xid = xwidget_info_id_get(info); + pcibr_soft->bs_master = xwidget_info_master_get(info); + pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); + + /* + * Init bridge lock. + */ + spin_lock_init(&pcibr_soft->bs_lock); + + /* + * If we have one, process the hints structure. + */ + if (pcibr_hints) { + rrb_fixed = pcibr_hints->ph_rrb_fixed; + + pcibr_soft->bs_rrb_fixed = rrb_fixed; + + if (pcibr_hints->ph_intr_bits) + pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; + + for (slot = 0; slot < 8; ++slot) { + int hslot = pcibr_hints->ph_host_slot[slot] - 1; + + if (hslot < 0) { + pcibr_soft->bs_slot[slot].host_slot = slot; + } else { + pcibr_soft->bs_slot[slot].has_host = 1; + pcibr_soft->bs_slot[slot].host_slot = hslot; + } + } + } + /* + * set up initial values for state fields + */ + for (slot = 0; slot < 8; ++slot) { + pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; + pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; + pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; + pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); + } + + for (ibit = 0; ibit < 8; ++ibit) { + pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = + &(bridge->b_int_status); + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; + } + + /* + * Initialize various Bridge registers. + */ + + /* + * On pre-Rev.D bridges, set the PCI_RETRY_CNT + * to zero to avoid dropping stores. (#475347) + */ + if (rev < BRIDGE_PART_REV_D) + bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; + + /* + * Clear all pending interrupts. + */ + bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); + + /* + * Until otherwise set up, + * assume all interrupts are + * from slot 7. + */ + bridge->b_int_device = (uint32_t) 0xffffffff; + + { + bridgereg_t dirmap; + paddr_t paddr; + iopaddr_t xbase; + xwidgetnum_t xport; + iopaddr_t offset; + int num_entries = 0; + int entry; + cnodeid_t cnodeid; + nasid_t nasid; + + /* Set the Bridge's 32-bit PCI to XTalk + * Direct Map register to the most useful + * value we can determine. Note that we + * must use a single xid for all of: + * direct-mapped 32-bit DMA accesses + * direct-mapped 64-bit DMA accesses + * DMA accesses through the PMU + * interrupts + * This is the only way to guarantee that + * completion interrupts will reach a CPU + * after all DMA data has reached memory. + * (Of course, there may be a few special + * drivers/controlers that explicitly manage + * this ordering problem.) + */ + + cnodeid = 0; /* default node id */ + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + paddr = NODE_OFFSET(nasid) + 0; + + /* currently, we just assume that if we ask + * for a DMA mapping to "zero" the XIO + * host will transmute this into a request + * for the lowest hunk of memory. + */ + xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, + paddr, _PAGESZ, 0); + + if (xbase != XIO_NOWHERE) { + if (XIO_PACKED(xbase)) { + xport = XIO_PORT(xbase); + xbase = XIO_ADDR(xbase); + } else + xport = pcibr_soft->bs_mxid; + + offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); + xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; + + dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; + + if (xbase) + dirmap |= BRIDGE_DIRMAP_OFF & xbase; + else if (offset >= (512 << 20)) + dirmap |= BRIDGE_DIRMAP_ADD512; + + bridge->b_dir_map = dirmap; + } + /* + * Set bridge's idea of page size according to the system's + * idea of "IO page size". TBD: The idea of IO page size + * should really go away. + */ + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + spl_level = splhi(); +#if IOPGSIZE == 4096 + bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; +#elif IOPGSIZE == 16384 + bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; +#else + <<>>; +#endif + bridge->b_wid_control; /* inval addr bug war */ + splx(spl_level); + + /* Initialize internal mapping entries */ + for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) { + bridge->b_int_ate_ram[entry].wr = 0; + } + + /* + * Determine if there's external mapping SSRAM on this + * bridge. Set up Bridge control register appropriately, + * inititlize SSRAM, and set software up to manage RAM + * entries as an allocatable resource. + * + * Currently, we just use the rm* routines to manage ATE + * allocation. We should probably replace this with a + * Best Fit allocator. + * + * For now, if we have external SSRAM, avoid using + * the internal ssram: we can't turn PREFETCH on + * when we use the internal SSRAM; and besides, + * this also guarantees that no allocation will + * straddle the internal/external line, so we + * can increment ATE write addresses rather than + * recomparing against BRIDGE_INTERNAL_ATES every + * time. + */ + if (is_xbridge(bridge)) + num_entries = 0; + else + num_entries = pcibr_init_ext_ate_ram(bridge); + + /* we always have 128 ATEs (512 for Xbridge) inside the chip + * even if disabled for debugging. + */ + pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); + pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); +#endif + + if (num_entries > pcibr_soft->bs_int_ate_size) { +#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ + printk("pcibr_attach: disabling internal ATEs.\n"); + pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); +#endif + pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); + pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, + num_entries - pcibr_soft->bs_int_ate_size); +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: %d EXTERNAL ATEs\n", + num_entries - pcibr_soft->bs_int_ate_size); +#endif + } + } + + { + bridgereg_t dirmap; + iopaddr_t xbase; + + /* + * now figure the *real* xtalk base address + * that dirmap sends us to. + */ + dirmap = bridge->b_dir_map; + if (dirmap & BRIDGE_DIRMAP_OFF) + xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) + << BRIDGE_DIRMAP_OFF_ADDRSHFT; + else if (dirmap & BRIDGE_DIRMAP_ADD512) + xbase = 512 << 20; + else + xbase = 0; + + pcibr_soft->bs_dir_xbase = xbase; + + /* it is entirely possible that we may, at this + * point, have our dirmap pointing somewhere + * other than our "master" port. + */ + pcibr_soft->bs_dir_xport = + (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; + } + + /* pcibr sources an error interrupt; + * figure out where to send it. + * + * If any interrupts are enabled in bridge, + * then the prom set us up and our interrupt + * has already been reconnected in mlreset + * above. + * + * Need to set the D_INTR_ISERR flag + * in the dev_desc used for allocating the + * error interrupt, so our interrupt will + * be properly routed and prioritized. + * + * If our crosstalk provider wants to + * fix widget error interrupts to specific + * destinations, D_INTR_ISERR is how it + * knows to do this. + */ + + xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); + ASSERT(xtalk_intr != NULL); + + pcibr_soft->bsi_err_intr = xtalk_intr; + + /* + * On IP35 with XBridge, we do some extra checks in pcibr_setwidint + * in order to work around some addressing limitations. In order + * for that fire wall to work properly, we need to make sure we + * start from a known clean state. + */ + pcibr_clearwidint(bridge); + + xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); + + /* + * now we can start handling error interrupts; + * enable all of them. + * NOTE: some PCI ints may already be enabled. + */ + b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; + + + bridge->b_int_enable = b_int_enable; + bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ + + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + /* + * Depending on the rev of bridge, disable certain features. + * Easiest way seems to be to force the PCIBR_NOwhatever + * flag to be on for all DMA calls, which overrides any + * PCIBR_whatever flag or even the setting of whatever + * from the PCIIO_DMA_class flags (or even from the other + * PCIBR flags, since NO overrides YES). + */ + pcibr_soft->bs_dma_flags = 0; + + /* PREFETCH: + * Always completely disabled for REV.A; + * at "pcibr_prefetch_enable_rev", anyone + * asking for PCIIO_PREFETCH gets it. + * Between these two points, you have to ask + * for PCIBR_PREFETCH, which promises that + * your driver knows about known Bridge WARs. + */ + if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) + pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; + else if (pcibr_soft->bs_rev_num < + (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) + pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; + + /* WRITE_GATHER: + * Disabled up to but not including the + * rev number in pcibr_wg_enable_rev. There + * is no "WAR range" as with prefetch. + */ + if (pcibr_soft->bs_rev_num < + (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) + pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; + + pciio_provider_register(pcibr_vhdl, &pcibr_provider); + pciio_provider_startup(pcibr_vhdl); + + pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ + pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ + + pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ + pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ + + pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ + pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ + + + PCI_ADDR_SPACE_LIMITS_STORE(); + + /* build "no-slot" connection point + */ + pcibr_info = pcibr_device_info_new + (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, + PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + noslot_conn = pciio_device_info_register + (pcibr_vhdl, &pcibr_info->f_c); + + /* Remember the no slot connection point info for tearing it + * down during detach. + */ + pcibr_soft->bs_noslot_conn = noslot_conn; + pcibr_soft->bs_noslot_info = pcibr_info; +#if PCI_FBBE + fast_back_to_back_enable = 1; +#endif + +#if PCI_FBBE + if (fast_back_to_back_enable) { + /* + * All devices on the bus are capable of fast back to back, so + * we need to set the fast back to back bit in all devices on + * the bus that are capable of doing such accesses. + */ + } +#endif + +#ifdef LATER + /* If the bridge has been reset then there is no need to reset + * the individual PCI slots. + */ + for (slot = 0; slot < 8; ++slot) + /* Reset all the slots */ + (void)pcibr_slot_reset(pcibr_vhdl, slot); +#endif + + for (slot = 0; slot < 8; ++slot) + /* Find out what is out there */ + (void)pcibr_slot_info_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Set up the address space for this slot in the pci land */ + (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Setup the device register */ + (void)pcibr_slot_device_init(pcibr_vhdl, slot); + + for (slot = 0; slot < 8; ++slot) + /* Setup host/guest relations */ + (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); + + for (slot = 0; slot < 8; ++slot) + /* Initial RRB management */ + (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); + + /* driver attach routines should be called out from generic linux code */ + for (slot = 0; slot < 8; ++slot) + /* Call the device attach */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + + /* + * Each Pbrick PCI bus only has slots 1 and 2. Similarly for + * widget 0xe on Ibricks. Allocate RRB's accordingly. + */ + if (pcibr_soft->bs_moduleid > 0) { + switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { + case 'p': /* Pbrick */ + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + break; + case 'i': /* Ibrick */ + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); + } + break; + } /* switch */ + } + +#ifdef LATER + if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); +#if PCIBR_RRB_DEBUG + printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); + + printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", + pcibr_vhdl, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + + for (slot = 0; slot < 8; ++slot) + printf("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + + printf("\n"); +#endif + } +#else + FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); +#endif + + if (aa) + async_attach_add_info(noslot_conn, aa); + + pciio_device_attach(noslot_conn, 0); + + + /* + * Tear down pointer to async attach info -- async threads for + * bridge's descendants may be running but the bridge's work is done. + */ + if (aa) + async_attach_del_info(xconn_vhdl); + + return 0; +} +/* + * pcibr_detach: + * Detach the bridge device from the hwgraph after cleaning out all the + * underlying vertices. + */ +int +pcibr_detach(devfs_handle_t xconn) +{ + pciio_slot_t slot; + devfs_handle_t pcibr_vhdl; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + + /* Get the bridge vertex from its xtalk connection point */ + if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) + return(1); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + + /* Disable the interrupts from the bridge */ + bridge->b_int_enable = 0; + + /* Detach all the PCI devices talking to this bridge */ + for(slot = 0; slot < 8; slot++) { +#ifdef DEBUG + printk("pcibr_device_detach called for %p/%d\n", + pcibr_vhdl,slot); +#endif + pcibr_slot_detach(pcibr_vhdl, slot, 0); + } + + /* Unregister the no-slot connection point */ + pciio_device_info_unregister(pcibr_vhdl, + &(pcibr_soft->bs_noslot_info->f_c)); + + spin_lock_destroy(&pcibr_soft->bs_lock); + kfree(pcibr_soft->bs_name); + + /* Error handler gets unregistered when the widget info is + * cleaned + */ + /* Free the soft ATE maps */ + if (pcibr_soft->bs_int_ate_map) + rmfreemap(pcibr_soft->bs_int_ate_map); + if (pcibr_soft->bs_ext_ate_map) + rmfreemap(pcibr_soft->bs_ext_ate_map); + + /* Disconnect the error interrupt and free the xtalk resources + * associated with it. + */ + xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); + xtalk_intr_free(pcibr_soft->bsi_err_intr); + + /* Clear the software state maintained by the bridge driver for this + * bridge. + */ + DEL(pcibr_soft); + /* Remove the Bridge revision labelled info */ + (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); + /* Remove the character device associated with this bridge */ + (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); + /* Remove the PCI bridge vertex */ + (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); + + return(0); +} + +int +pcibr_asic_rev(devfs_handle_t pconn_vhdl) +{ + devfs_handle_t pcibr_vhdl; + arbitrary_info_t ainfo; + + if (GRAPH_SUCCESS != + hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) + return -1; + + if (GRAPH_SUCCESS != + hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) + return -1; + + return (int) ainfo; +} + +int +pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + pciio_slot_t slot; + slot = pciio_info_slot_get(pciio_info); + pcibr_device_write_gather_flush(pcibr_soft, slot); + return 0; +} + +/* ===================================================================== + * PIO MANAGEMENT + */ + +static iopaddr_t +pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, + pciio_slot_t slot, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + unsigned flags) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + + unsigned bar; /* which BASE reg on device is decoding */ + iopaddr_t xio_addr = XIO_NOWHERE; + + pciio_space_t wspace; /* which space device is decoding */ + iopaddr_t wbase; /* base of device decode on PCI */ + size_t wsize; /* size of device decode on PCI */ + + int try; /* DevIO(x) window scanning order control */ + int win; /* which DevIO(x) window is being used */ + pciio_space_t mspace; /* target space for devio(x) register */ + iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ + size_t msize; /* size of devio(x) mapped area on PCI */ + size_t mmask; /* addr bits stored in Device(x) */ + + unsigned long s; + + s = pcibr_lock(pcibr_soft); + + if (pcibr_soft->bs_slot[slot].has_host) { + slot = pcibr_soft->bs_slot[slot].host_slot; + pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; + } + if (space == PCIIO_SPACE_NONE) + goto done; + + if (space == PCIIO_SPACE_CFG) { + /* + * Usually, the first mapping + * established to a PCI device + * is to its config space. + * + * In any case, we definitely + * do NOT need to worry about + * PCI BASE registers, and + * MUST NOT attempt to point + * the DevIO(x) window at + * this access ... + */ + if (((flags & PCIIO_BYTE_STREAM) == 0) && + ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) + xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); + + goto done; + } + if (space == PCIIO_SPACE_ROM) { + /* PIO to the Expansion Rom. + * Driver is responsible for + * enabling and disabling + * decodes properly. + */ + wbase = pcibr_info->f_rbase; + wsize = pcibr_info->f_rsize; + + /* + * While the driver should know better + * than to attempt to map more space + * than the device is decoding, he might + * do it; better to bail out here. + */ + if ((pci_addr + req_size) > wsize) + goto done; + + pci_addr += wbase; + space = PCIIO_SPACE_MEM; + } + /* + * reduce window mappings to raw + * space mappings (maybe allocating + * windows), and try for DevIO(x) + * usage (setting it if it is available). + */ + bar = space - PCIIO_SPACE_WIN0; + if (bar < 6) { + wspace = pcibr_info->f_window[bar].w_space; + if (wspace == PCIIO_SPACE_NONE) + goto done; + + /* get PCI base and size */ + wbase = pcibr_info->f_window[bar].w_base; + wsize = pcibr_info->f_window[bar].w_size; + + /* + * While the driver should know better + * than to attempt to map more space + * than the device is decoding, he might + * do it; better to bail out here. + */ + if ((pci_addr + req_size) > wsize) + goto done; + + /* shift from window relative to + * decoded space relative. + */ + pci_addr += wbase; + space = wspace; + } else + bar = -1; + + /* Scan all the DevIO(x) windows twice looking for one + * that can satisfy our request. The first time through, + * only look at assigned windows; the second time, also + * look at PCIIO_SPACE_NONE windows. Arrange the order + * so we always look at our own window first. + * + * We will not attempt to satisfy a single request + * by concatinating multiple windows. + */ + for (try = 0; try < 16; ++try) { + bridgereg_t devreg; + unsigned offset; + + win = (try + slot) % 8; + + /* If this DevIO(x) mapping area can provide + * a mapping to this address, use it. + */ + msize = (win < 2) ? 0x200000 : 0x100000; + mmask = -msize; + if (space != PCIIO_SPACE_IO) + mmask &= 0x3FFFFFFF; + + offset = pci_addr & (msize - 1); + + /* If this window can't possibly handle that request, + * go on to the next window. + */ + if (((pci_addr & (msize - 1)) + req_size) > msize) + continue; + + devreg = pcibr_soft->bs_slot[win].bss_device; + + /* Is this window "nailed down"? + * If not, maybe we can use it. + * (only check this the second time through) + */ + mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; + if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { + + /* If this is the primary DevIO(x) window + * for some other device, skip it. + */ + if ((win != slot) && + (PCIIO_VENDOR_ID_NONE != + pcibr_soft->bs_slot[win].bss_vendor_id)) + continue; + + /* It's a free window, and we fit in it. + * Set up Device(win) to our taste. + */ + mbase = pci_addr & mmask; + + /* check that we would really get from + * here to there. + */ + if ((mbase | offset) != pci_addr) + continue; + + devreg &= ~BRIDGE_DEV_OFF_MASK; + if (space != PCIIO_SPACE_IO) + devreg |= BRIDGE_DEV_DEV_IO_MEM; + else + devreg &= ~BRIDGE_DEV_DEV_IO_MEM; + devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; + + /* default is WORD_VALUES. + * if you specify both, + * operation is undefined. + */ + if (flags & PCIIO_BYTE_STREAM) + devreg |= BRIDGE_DEV_DEV_SWAP; + else + devreg &= ~BRIDGE_DEV_DEV_SWAP; + + if (pcibr_soft->bs_slot[win].bss_device != devreg) { + bridge->b_device[win].reg = devreg; + pcibr_soft->bs_slot[win].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + +#if DEBUG && PCI_DEBUG + printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); +#endif + } + pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; + pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; + xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + +#if DEBUG && PCI_DEBUG + printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", + __FUNCTION__, __LINE__, space, space_desc, + pci_addr, pci_addr + req_size - 1, + slot, win, devreg); +#endif + + goto done; + } /* endif DevIO(x) not pointed */ + mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; + + /* Now check for request incompat with DevIO(x) + */ + if ((mspace != space) || + (pci_addr < mbase) || + ((pci_addr + req_size) > (mbase + msize)) || + ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || + (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) + continue; + + /* DevIO(x) window is pointed at PCI space + * that includes our target. Calculate the + * final XIO address, release the lock and + * return. + */ + xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + +#if DEBUG && PCI_DEBUG + printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", + __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); +#endif + goto done; + } + + switch (space) { + /* + * Accesses to device decode + * areas that do a not fit + * within the DevIO(x) space are + * modified to be accesses via + * the direct mapping areas. + * + * If necessary, drivers can + * explicitly ask for mappings + * into these address spaces, + * but this should never be needed. + */ + case PCIIO_SPACE_MEM: /* "mem space" */ + case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ + if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= + BRIDGE_PCI_MEM32_LIMIT) + xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; + break; + + case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ + if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= + BRIDGE_PCI_MEM64_LIMIT) + xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; + break; + + case PCIIO_SPACE_IO: /* "i/o space" */ + /* Bridge Hardware Bug WAR #482741: + * The 4G area that maps directly from + * XIO space to PCI I/O space is busted + * until Bridge Rev D. + */ + if ((pcibr_soft->bs_rev_num > BRIDGE_PART_REV_C) && + ((pci_addr + BRIDGE_PCI_IO_BASE + req_size - 1) <= + BRIDGE_PCI_IO_LIMIT)) + xio_addr = pci_addr + BRIDGE_PCI_IO_BASE; + break; + } + + /* Check that "Direct PIO" byteswapping matches, + * try to change it if it does not. + */ + if (xio_addr != XIO_NOWHERE) { + unsigned bst; /* nonzero to set bytestream */ + unsigned *bfp; /* addr of record of how swapper is set */ + unsigned swb; /* which control bit to mung */ + unsigned bfo; /* current swapper setting */ + unsigned bfn; /* desired swapper setting */ + + bfp = ((space == PCIIO_SPACE_IO) + ? (&pcibr_soft->bs_pio_end_io) + : (&pcibr_soft->bs_pio_end_mem)); + + bfo = *bfp; + + bst = flags & PCIIO_BYTE_STREAM; + + bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; + + if (bfn == bfo) { /* we already match. */ + ; + } else if (bfo != 0) { /* we have a conflict. */ +#if DEBUG && PCI_DEBUG + printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", + space, + bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); +#endif + xio_addr = XIO_NOWHERE; + } else { /* OK to make the change. */ + bridgereg_t octl, nctl; + + swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; + octl = bridge->b_wid_control; + nctl = bst ? octl | swb : octl & ~swb; + + if (octl != nctl) /* make the change if any */ + bridge->b_wid_control = nctl; + + *bfp = bfn; /* record the assignment */ + +#if DEBUG && PCI_DEBUG + printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", + space, + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); +#endif + } + } + done: + pcibr_unlock(pcibr_soft, s); + return xio_addr; +} + +/*ARGSUSED6 */ +pcibr_piomap_t +pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + size_t req_size_max, + unsigned flags) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + pcibr_piomap_t *mapptr; + pcibr_piomap_t maplist; + pcibr_piomap_t pcibr_piomap; + iopaddr_t xio_addr; + xtalk_piomap_t xtalk_piomap; + unsigned long s; + + /* Make sure that the req sizes are non-zero */ + if ((req_size < 1) || (req_size_max < 1)) + return NULL; + + /* + * Code to translate slot/space/addr + * into xio_addr is common between + * this routine and pcibr_piotrans_addr. + */ + xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); + + if (xio_addr == XIO_NOWHERE) + return NULL; + + /* Check the piomap list to see if there is already an allocated + * piomap entry but not in use. If so use that one. Otherwise + * allocate a new piomap entry and add it to the piomap list + */ + mapptr = &(pcibr_info->f_piomap); + + s = pcibr_lock(pcibr_soft); + for (pcibr_piomap = *mapptr; + pcibr_piomap != NULL; + pcibr_piomap = pcibr_piomap->bp_next) { + if (pcibr_piomap->bp_mapsz == 0) + break; + } + + if (pcibr_piomap) + mapptr = NULL; + else { + pcibr_unlock(pcibr_soft, s); + NEW(pcibr_piomap); + } + + pcibr_piomap->bp_dev = pconn_vhdl; + pcibr_piomap->bp_slot = pciio_slot; + pcibr_piomap->bp_flags = flags; + pcibr_piomap->bp_space = space; + pcibr_piomap->bp_pciaddr = pci_addr; + pcibr_piomap->bp_mapsz = req_size; + pcibr_piomap->bp_soft = pcibr_soft; + pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); + + if (mapptr) { + s = pcibr_lock(pcibr_soft); + maplist = *mapptr; + pcibr_piomap->bp_next = maplist; + *mapptr = pcibr_piomap; + } + pcibr_unlock(pcibr_soft, s); + + + if (pcibr_piomap) { + xtalk_piomap = + xtalk_piomap_alloc(xconn_vhdl, 0, + xio_addr, + req_size, req_size_max, + flags & PIOMAP_FLAGS); + if (xtalk_piomap) { + pcibr_piomap->bp_xtalk_addr = xio_addr; + pcibr_piomap->bp_xtalk_pio = xtalk_piomap; + } else { + pcibr_piomap->bp_mapsz = 0; + pcibr_piomap = 0; + } + } + return pcibr_piomap; +} + +/*ARGSUSED */ +void +pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) +{ + xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); + pcibr_piomap->bp_xtalk_pio = 0; + pcibr_piomap->bp_mapsz = 0; +} + +/*ARGSUSED */ +caddr_t +pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, + iopaddr_t pci_addr, + size_t req_size) +{ + return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, + pcibr_piomap->bp_xtalk_addr + + pci_addr - pcibr_piomap->bp_pciaddr, + req_size); +} + +/*ARGSUSED */ +void +pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) +{ + xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); +} + +/*ARGSUSED */ +caddr_t +pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + iopaddr_t pci_addr, + size_t req_size, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + iopaddr_t xio_addr; + + xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); + + if (xio_addr == XIO_NOWHERE) + return NULL; + + return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); +} + +/* + * PIO Space allocation and management. + * Allocate and Manage the PCI PIO space (mem and io space) + * This routine is pretty simplistic at this time, and + * does pretty trivial management of allocation and freeing.. + * The current scheme is prone for fragmentation.. + * Change the scheme to use bitmaps. + */ + +/*ARGSUSED */ +iopaddr_t +pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_space_t space, + size_t req_size, + size_t alignment) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_info_t pciio_info = &pcibr_info->f_c; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + pciio_piospace_t piosp; + unsigned long s; + + iopaddr_t *pciaddr, *pcilast; + iopaddr_t start_addr; + size_t align_mask; + + /* + * Check for proper alignment + */ + ASSERT(alignment >= NBPP); + ASSERT((alignment & (alignment - 1)) == 0); + + align_mask = alignment - 1; + s = pcibr_lock(pcibr_soft); + + /* + * First look if a previously allocated chunk exists. + */ + if ((piosp = pcibr_info->f_piospace)) { + /* + * Look through the list for a right sized free chunk. + */ + do { + if (piosp->free && + (piosp->space == space) && + (piosp->count >= req_size) && + !(piosp->start & align_mask)) { + piosp->free = 0; + pcibr_unlock(pcibr_soft, s); + return piosp->start; + } + piosp = piosp->next; + } while (piosp); + } + ASSERT(!piosp); + + switch (space) { + case PCIIO_SPACE_IO: + pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; + pcilast = &pcibr_soft->bs_spinfo.pci_io_last; + break; + case PCIIO_SPACE_MEM: + case PCIIO_SPACE_MEM32: + pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; + pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; + break; + default: + ASSERT(0); + pcibr_unlock(pcibr_soft, s); + return 0; + } + + start_addr = *pciaddr; + + /* + * Align start_addr. + */ + if (start_addr & align_mask) + start_addr = (start_addr + align_mask) & ~align_mask; + + if ((start_addr + req_size) > *pcilast) { + /* + * If too big a request, reject it. + */ + pcibr_unlock(pcibr_soft, s); + return 0; + } + *pciaddr = (start_addr + req_size); + + NEW(piosp); + piosp->free = 0; + piosp->space = space; + piosp->start = start_addr; + piosp->count = req_size; + piosp->next = pcibr_info->f_piospace; + pcibr_info->f_piospace = piosp; + + pcibr_unlock(pcibr_soft, s); + return start_addr; +} + +/*ARGSUSED */ +void +pcibr_piospace_free(devfs_handle_t pconn_vhdl, + pciio_space_t space, + iopaddr_t pciaddr, + size_t req_size) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + + pciio_piospace_t piosp; + unsigned long s; + char name[1024]; + + /* + * Look through the bridge data structures for the pciio_piospace_t + * structure corresponding to 'pciaddr' + */ + s = pcibr_lock(pcibr_soft); + piosp = pcibr_info->f_piospace; + while (piosp) { + /* + * Piospace free can only be for the complete + * chunk and not parts of it.. + */ + if (piosp->start == pciaddr) { + if (piosp->count == req_size) + break; + /* + * Improper size passed for freeing.. + * Print a message and break; + */ + hwgraph_vertex_name_get(pconn_vhdl, name, 1024); + printk(KERN_WARNING "pcibr_piospace_free: error"); + printk(KERN_WARNING "Device %s freeing size (0x%lx) different than allocated (0x%lx)", + name, req_size, piosp->count); + printk(KERN_WARNING "Freeing 0x%lx instead", piosp->count); + break; + } + piosp = piosp->next; + } + + if (!piosp) { + printk(KERN_WARNING + "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", + pciaddr, req_size); + pcibr_unlock(pcibr_soft, s); + return; + } + piosp->free = 1; + pcibr_unlock(pcibr_soft, s); + return; +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * The Bridge ASIC provides three methods of doing + * DMA: via a "direct map" register available in + * 32-bit PCI space (which selects a contiguous 2G + * address space on some other widget), via + * "direct" addressing via 64-bit PCI space (all + * destination information comes from the PCI + * address, including transfer attributes), and via + * a "mapped" region that allows a bunch of + * different small mappings to be established with + * the PMU. + * + * For efficiency, we most prefer to use the 32-bit + * direct mapping facility, since it requires no + * resource allocations. The advantage of using the + * PMU over the 64-bit direct is that single-cycle + * PCI addressing can be used; the advantage of + * using 64-bit direct over PMU addressing is that + * we do not have to allocate entries in the PMU. + */ + +/* + * Convert PCI-generic software flags and Bridge-specific software flags + * into Bridge-specific Direct Map attribute bits. + */ +static iopaddr_t +pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) +{ + iopaddr_t attributes = 0; + + /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ +#ifdef LATER + ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); +#endif + + /* Generic macro flags + */ + if (flags & PCIIO_DMA_DATA) { /* standard data channel */ + attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ + attributes |= PCI64_ATTR_PREF; /* prefetch on */ + } + if (flags & PCIIO_DMA_CMD) { /* standard command channel */ + attributes |= PCI64_ATTR_BAR; /* barrier bit on */ + attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ + } + /* Generic detail flags + */ + if (flags & PCIIO_PREFETCH) + attributes |= PCI64_ATTR_PREF; + if (flags & PCIIO_NOPREFETCH) + attributes &= ~PCI64_ATTR_PREF; + + /* the swap bit is in the address attributes for xbridge */ + if (pcibr_soft->bs_xbridge) { + if (flags & PCIIO_BYTE_STREAM) + attributes |= PCI64_ATTR_SWAP; + if (flags & PCIIO_WORD_VALUES) + attributes &= ~PCI64_ATTR_SWAP; + } + + /* Provider-specific flags + */ + if (flags & PCIBR_BARRIER) + attributes |= PCI64_ATTR_BAR; + if (flags & PCIBR_NOBARRIER) + attributes &= ~PCI64_ATTR_BAR; + + if (flags & PCIBR_PREFETCH) + attributes |= PCI64_ATTR_PREF; + if (flags & PCIBR_NOPREFETCH) + attributes &= ~PCI64_ATTR_PREF; + + if (flags & PCIBR_PRECISE) + attributes |= PCI64_ATTR_PREC; + if (flags & PCIBR_NOPRECISE) + attributes &= ~PCI64_ATTR_PREC; + + if (flags & PCIBR_VCHAN1) + attributes |= PCI64_ATTR_VIRTUAL; + if (flags & PCIBR_VCHAN0) + attributes &= ~PCI64_ATTR_VIRTUAL; + + return (attributes); +} + +/*ARGSUSED */ +pcibr_dmamap_t +pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + size_t req_size_max, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t slot; + xwidgetnum_t xio_port; + + xtalk_dmamap_t xtalk_dmamap; + pcibr_dmamap_t pcibr_dmamap; + int ate_count; + int ate_index; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + + /* + * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() + * can be called within an interrupt thread. + */ + pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); + + if (!pcibr_dmamap) + return 0; + + xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, + flags & DMAMAP_FLAGS); + if (!xtalk_dmamap) { +#if PCIBR_ATE_DEBUG + printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); +#endif + free_pciio_dmamap(pcibr_dmamap); + return 0; + } + xio_port = pcibr_soft->bs_mxid; + slot = pciio_info_slot_get(pciio_info); + + pcibr_dmamap->bd_dev = pconn_vhdl; + pcibr_dmamap->bd_slot = slot; + pcibr_dmamap->bd_soft = pcibr_soft; + pcibr_dmamap->bd_xtalk = xtalk_dmamap; + pcibr_dmamap->bd_max_size = req_size_max; + pcibr_dmamap->bd_xio_port = xio_port; + + if (flags & PCIIO_DMA_A64) { + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { + iopaddr_t pci_addr; + int have_rrbs; + int min_rrbs; + + /* Device is capable of A64 operations, + * and the attributes of the DMA are + * consistant with any previous DMA + * mappings using shared resources. + */ + + pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); + + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_xio_addr = 0; + pcibr_dmamap->bd_pci_addr = pci_addr; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { + if (flags & PCIBR_VCHAN1) + slot += PCIBR_RRB_SLOT_VIRTUAL; + have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + if (have_rrbs < 2) { + if (pci_addr & PCI64_ATTR_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using direct64\n"); +#endif + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use direct64\n"); +#endif + flags &= ~PCIIO_DMA_A64; + } + if (flags & PCIIO_FIXED) { + /* warning: mappings may fail later, + * if direct32 can't get to the address. + */ + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { + /* User desires DIRECT A32 operations, + * and the attributes of the DMA are + * consistant with any previous DMA + * mappings using shared resources. + * Mapping calls may fail if target + * is outside the direct32 range. + */ +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using direct32\n"); +#endif + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; + pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use direct32\n"); +#endif + /* If the user demands FIXED and we can't + * give it to him, fail. + */ + xtalk_dmamap_free(xtalk_dmamap); + free_pciio_dmamap(pcibr_dmamap); + return 0; + } + /* + * Allocate Address Translation Entries from the mapping RAM. + * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, + * the maximum number of ATEs is based on the worst-case + * scenario, where the requested target is in the + * last byte of an ATE; thus, mapping IOPGSIZE+2 + * does end up requiring three ATEs. + */ + if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { + ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ + +req_size_max /* max mapping bytes */ + - 1) + 1; /* round UP */ + } else { /* assume requested target is page aligned */ + ate_count = IOPG(req_size_max /* max mapping bytes */ + - 1) + 1; /* round UP */ + } + + ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); + + if (ate_index != -1) { + if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { + bridge_ate_t ate_proto; + int have_rrbs; + int min_rrbs; + +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: using PMU\n"); +#endif + + ate_proto = pcibr_flags_to_ate(flags); + + pcibr_dmamap->bd_flags = flags; + pcibr_dmamap->bd_pci_addr = + PCI32_MAPPED_BASE + IOPGSIZE * ate_index; + /* + * for xbridge the byte-swap bit == bit 29 of PCI address + */ + if (pcibr_soft->bs_xbridge) { + if (flags & PCIIO_BYTE_STREAM) + ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); + /* + * If swap was set in bss_device in pcibr_endian_set() + * we need to change the address bit. + */ + if (pcibr_soft->bs_slot[slot].bss_device & + BRIDGE_DEV_SWAP_PMU) + ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); + if (flags & PCIIO_WORD_VALUES) + ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); + } + pcibr_dmamap->bd_xio_addr = 0; + pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); + pcibr_dmamap->bd_ate_index = ate_index; + pcibr_dmamap->bd_ate_count = ate_count; + pcibr_dmamap->bd_ate_proto = ate_proto; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { + have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + if (have_rrbs < 2) { + if (ate_proto & ATE_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + } + } + if (ate_index >= pcibr_soft->bs_int_ate_size && + !pcibr_soft->bs_xbridge) { + bridge_t *bridge = pcibr_soft->bs_base; + volatile unsigned *cmd_regp; + unsigned cmd_reg; + unsigned long s; + + pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; + + s = pcibr_lock(pcibr_soft); + cmd_regp = &(bridge-> + b_type0_cfg_dev[slot]. + l[PCI_CFG_COMMAND / 4]); + cmd_reg = *cmd_regp; + pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; + pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; + pcibr_unlock(pcibr_soft, s); + } + return pcibr_dmamap; + } +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: unable to use PMU\n"); +#endif + pcibr_ate_free(pcibr_soft, ate_index, ate_count); + } + /* total failure: sorry, you just can't + * get from here to there that way. + */ +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_alloc: complete failure.\n"); +#endif + xtalk_dmamap_free(xtalk_dmamap); + free_pciio_dmamap(pcibr_dmamap); + return 0; +} + +/*ARGSUSED */ +void +pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) +{ + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; + pciio_slot_t slot = pcibr_dmamap->bd_slot; + + unsigned flags = pcibr_dmamap->bd_flags; + + /* Make sure that bss_ext_ates_active + * is properly kept up to date. + */ + + if (PCIBR_DMAMAP_BUSY & flags) + if (PCIBR_DMAMAP_SSRAM & flags) + atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); + + xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); + + if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { + pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); + } + if (pcibr_dmamap->bd_ate_count) { + pcibr_ate_free(pcibr_dmamap->bd_soft, + pcibr_dmamap->bd_ate_index, + pcibr_dmamap->bd_ate_count); + pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); + } + + free_pciio_dmamap(pcibr_dmamap); +} + +/* + * pcibr_addr_xio_to_pci: given a PIO range, hand + * back the corresponding base PCI MEM address; + * this is used to short-circuit DMA requests that + * loop back onto this PCI bus. + */ +static iopaddr_t +pcibr_addr_xio_to_pci(pcibr_soft_t soft, + iopaddr_t xio_addr, + size_t req_size) +{ + iopaddr_t xio_lim = xio_addr + req_size - 1; + iopaddr_t pci_addr; + pciio_slot_t slot; + + if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && + (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= BRIDGE_PCI_MEM64_BASE) && + (xio_lim <= BRIDGE_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; + return pci_addr; + } + for (slot = 0; slot < 8; ++slot) + if ((xio_addr >= BRIDGE_DEVIO(slot)) && + (xio_lim < BRIDGE_DEVIO(slot + 1))) { + bridgereg_t dev; + + dev = soft->bs_slot[slot].bss_device; + pci_addr = dev & BRIDGE_DEV_OFF_MASK; + pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; + pci_addr += xio_addr - BRIDGE_DEVIO(slot); + return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; + } + return 0; +} + +/*ARGSUSED */ +iopaddr_t +pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, + paddr_t paddr, + size_t req_size) +{ + pcibr_soft_t pcibr_soft; + iopaddr_t xio_addr; + xwidgetnum_t xio_port; + iopaddr_t pci_addr; + unsigned flags; + + ASSERT(pcibr_dmamap != NULL); + ASSERT(req_size > 0); + ASSERT(req_size <= pcibr_dmamap->bd_max_size); + + pcibr_soft = pcibr_dmamap->bd_soft; + + flags = pcibr_dmamap->bd_flags; + + xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); + if (XIO_PACKED(xio_addr)) { + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_dmamap->bd_xio_port; + + /* If this DMA is to an address that + * refers back to this Bridge chip, + * reduce it back to the correct + * PCI MEM address. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); + } else if (flags & PCIIO_DMA_A64) { + /* A64 DMA: + * always use 64-bit direct mapping, + * which always works. + * Device(x) was set up during + * dmamap allocation. + */ + + /* attributes are already bundled up into bd_pci_addr. + */ + pci_addr = pcibr_dmamap->bd_pci_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) + | xio_addr; + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + pci_addr &= ~PCI64_ATTR_PREF; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmamap_addr (direct64):\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tXIO port 0x%x offset 0x%x\n" + "\treturning PCI 0x%x\n", + paddr, paddr + req_size - 1, + xio_port, xio_addr, pci_addr); +#endif + } else if (flags & PCIIO_FIXED) { + /* A32 direct DMA: + * always use 32-bit direct mapping, + * which may fail. + * Device(x) was set up during + * dmamap allocation. + */ + + if (xio_port != pcibr_soft->bs_dir_xport) + pci_addr = 0; /* wrong DIDN */ + else if (xio_addr < pcibr_dmamap->bd_xio_addr) + pci_addr = 0; /* out of range */ + else if ((xio_addr + req_size) > + (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) + pci_addr = 0; /* out of range */ + else + pci_addr = pcibr_dmamap->bd_pci_addr + + xio_addr - pcibr_dmamap->bd_xio_addr; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmamap_addr (direct32):\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tXIO port 0x%x offset 0x%x\n" + "\treturning PCI 0x%x\n", + paddr, paddr + req_size - 1, + xio_port, xio_addr, pci_addr); +#endif + } else { + bridge_t *bridge = pcibr_soft->bs_base; + iopaddr_t offset = IOPGOFF(xio_addr); + bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; + int ate_count = IOPG(offset + req_size - 1) + 1; + + int ate_index = pcibr_dmamap->bd_ate_index; + unsigned cmd_regs[8]; + unsigned s; + +#if PCIBR_FREEZE_TIME + int ate_total = ate_count; + unsigned freeze_time; +#endif + +#if PCIBR_ATE_DEBUG + bridge_ate_t ate_cmp; + bridge_ate_p ate_cptr; + unsigned ate_lo, ate_hi; + int ate_bad = 0; + int ate_rbc = 0; +#endif + bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; + bridge_ate_t ate; + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + ate_proto &= ~ATE_PREF; + + ate = ate_proto + | (xio_port << ATE_TIDSHIFT) + | (xio_addr - offset); + + pci_addr = pcibr_dmamap->bd_pci_addr + offset; + + /* Fill in our mapping registers + * with the appropriate xtalk data, + * and hand back the PCI address. + */ + + ASSERT(ate_count > 0); + if (ate_count <= pcibr_dmamap->bd_ate_count) { + ATE_FREEZE(); + ATE_WRITE(); + ATE_THAW(); + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } else { + /* The number of ATE's required is greater than the number + * allocated for this map. One way this can happen is if + * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP + * flag, and then when that map is used (right now), the + * target address tells us we really did need to roundup. + * The other possibility is that the map is just plain too + * small to handle the requested target area. + */ +#if PCIBR_ATE_DEBUG + printk(KERN_WARNING "pcibr_dmamap_addr :\n" + "\twanted paddr [0x%x..0x%x]\n" + "\tate_count 0x%x bd_ate_count 0x%x\n" + "\tATE's required > number allocated\n", + paddr, paddr + req_size - 1, + ate_count, pcibr_dmamap->bd_ate_count); +#endif + pci_addr = 0; + } + + } + return pci_addr; +} + +/*ARGSUSED */ +alenlist_t +pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, + alenlist_t palenlist, + unsigned flags) +{ + pcibr_soft_t pcibr_soft; + bridge_t *bridge=NULL; + + unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; + int inplace = flags & PCIIO_INPLACE; + + alenlist_t pciio_alenlist = 0; + alenlist_t xtalk_alenlist; + size_t length; + iopaddr_t offset; + unsigned direct64; + int ate_index = 0; + int ate_count = 0; + int ate_total = 0; + bridge_ate_p ate_ptr = (bridge_ate_p)0; + bridge_ate_t ate_proto = (bridge_ate_t)0; + bridge_ate_t ate_prev; + bridge_ate_t ate; + alenaddr_t xio_addr; + xwidgetnum_t xio_port; + iopaddr_t pci_addr; + alenaddr_t new_addr; + unsigned cmd_regs[8]; + unsigned s = 0; + +#if PCIBR_FREEZE_TIME + unsigned freeze_time; +#endif + int ate_freeze_done = 0; /* To pair ATE_THAW + * with an ATE_FREEZE + */ + + pcibr_soft = pcibr_dmamap->bd_soft; + + xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, + flags & DMAMAP_FLAGS); + if (!xtalk_alenlist) + goto fail; + + alenlist_cursor_init(xtalk_alenlist, 0, NULL); + + if (inplace) { + pciio_alenlist = xtalk_alenlist; + } else { + pciio_alenlist = alenlist_create(al_flags); + if (!pciio_alenlist) + goto fail; + } + + direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; + if (!direct64) { + bridge = pcibr_soft->bs_base; + ate_ptr = pcibr_dmamap->bd_ate_ptr; + ate_index = pcibr_dmamap->bd_ate_index; + ate_proto = pcibr_dmamap->bd_ate_proto; + ATE_FREEZE(); + ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ + } + pci_addr = pcibr_dmamap->bd_pci_addr; + + ate_prev = 0; /* matches no valid ATEs */ + while (ALENLIST_SUCCESS == + alenlist_get(xtalk_alenlist, NULL, 0, + &xio_addr, &length, al_flags)) { + if (XIO_PACKED(xio_addr)) { + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_dmamap->bd_xio_port; + + if (xio_port == pcibr_soft->bs_xid) { + new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); + if (new_addr == PCI_NOWHERE) + goto fail; + } else if (direct64) { + new_addr = pci_addr | xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + + /* Bridge Hardware WAR #482836: + * If the transfer is not cache aligned + * and the Bridge Rev is <= B, force + * prefetch to be off. + */ + if (flags & PCIBR_NOPREFETCH) + new_addr &= ~PCI64_ATTR_PREF; + + } else { + /* calculate the ate value for + * the first address. If it + * matches the previous + * ATE written (ie. we had + * multiple blocks in the + * same IOPG), then back up + * and reuse that ATE. + * + * We are NOT going to + * aggressively try to + * reuse any other ATEs. + */ + offset = IOPGOFF(xio_addr); + ate = ate_proto + | (xio_port << ATE_TIDSHIFT) + | (xio_addr - offset); + if (ate == ate_prev) { +#if PCIBR_ATE_DEBUG + printk("pcibr_dmamap_list: ATE share\n"); +#endif + ate_ptr--; + ate_index--; + pci_addr -= IOPGSIZE; + } + new_addr = pci_addr + offset; + + /* Fill in the hardware ATEs + * that contain this block. + */ + ate_count = IOPG(offset + length - 1) + 1; + ate_total += ate_count; + + /* Ensure that this map contains enough ATE's */ + if (ate_total > pcibr_dmamap->bd_ate_count) { +#if PCIBR_ATE_DEBUG + printk(KERN_WARNING "pcibr_dmamap_list :\n" + "\twanted xio_addr [0x%x..0x%x]\n" + "\tate_total 0x%x bd_ate_count 0x%x\n" + "\tATE's required > number allocated\n", + xio_addr, xio_addr + length - 1, + ate_total, pcibr_dmamap->bd_ate_count); +#endif + goto fail; + } + + ATE_WRITE(); + + ate_index += ate_count; + ate_ptr += ate_count; + + ate_count <<= IOPFNSHIFT; + ate += ate_count; + pci_addr += ate_count; + } + + /* write the PCI DMA address + * out to the scatter-gather list. + */ + if (inplace) { + if (ALENLIST_SUCCESS != + alenlist_replace(pciio_alenlist, NULL, + &new_addr, &length, al_flags)) + goto fail; + } else { + if (ALENLIST_SUCCESS != + alenlist_append(pciio_alenlist, + new_addr, length, al_flags)) + goto fail; + } + } + if (!inplace) + alenlist_done(xtalk_alenlist); + + /* Reset the internal cursor of the alenlist to be returned back + * to the caller. + */ + alenlist_cursor_init(pciio_alenlist, 0, NULL); + + + /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the + * changes that ATE_FREEZE has done to implement the external SSRAM + * bug workaround. + */ + if (ate_freeze_done) { + ATE_THAW(); + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + return pciio_alenlist; + + fail: + /* There are various points of failure after doing an ATE_FREEZE + * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. + * The decision to do an ATE_THAW needs to be based on whether a + * an ATE_FREEZE was done before. + */ + if (ate_freeze_done) { + ATE_THAW(); + bridge->b_wid_tflush; + } + if (pciio_alenlist && !inplace) + alenlist_destroy(pciio_alenlist); + return 0; +} + +/*ARGSUSED */ +void +pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) +{ + /* + * We could go through and invalidate ATEs here; + * for performance reasons, we don't. + * We also don't enforce the strict alternation + * between _addr/_list and _done, but Hub does. + */ + + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { + pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; + + if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) + atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); + } + xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); +} + + +/* + * For each bridge, the DIR_OFF value in the Direct Mapping Register + * determines the PCI to Crosstalk memory mapping to be used for all + * 32-bit Direct Mapping memory accesses. This mapping can be to any + * node in the system. This function will return that compact node id. + */ + +/*ARGSUSED */ +cnodeid_t +pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) +{ + + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); +} + +/*ARGSUSED */ +iopaddr_t +pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + paddr_t paddr, + size_t req_size, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; + + xwidgetnum_t xio_port; + iopaddr_t xio_addr; + iopaddr_t pci_addr; + + int have_rrbs; + int min_rrbs; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + + xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, + flags & DMAMAP_FLAGS); + if (!xio_addr) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + /* + * find which XIO port this goes to. + */ + if (XIO_PACKED(xio_addr)) { + if (xio_addr == XIO_NOWHERE) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + + } else + xio_port = pcibr_soft->bs_mxid; + + /* + * If this DMA comes back to us, + * return the PCI MEM address on + * which it would land, or NULL + * if the target is something + * on bridge other than PCI MEM. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); + return pci_addr; + } + /* If the caller can use A64, try to + * satisfy the request with the 64-bit + * direct map. This can fail if the + * configuration bits in Device(x) + * conflict with our flags. + */ + + if (flags & PCIIO_DMA_A64) { + pci_addr = slotp->bss_d64_base; + if (!(flags & PCIBR_VCHAN1)) + flags |= PCIBR_VCHAN0; + if ((pci_addr != PCIBR_D64_BASE_UNSET) && + (flags == slotp->bss_d64_flags)) { + +#ifdef CONFIG_IA64_SGI_SN2 + pci_addr |= (PHYS_TO_DMA(xio_addr)) + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); +#else + pci_addr |= xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); +#endif + +#if DEBUG && PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr: [reuse]\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tdirect 64bit address is 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, pci_addr); +#endif + return (pci_addr); + } + if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { + pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); + slotp->bss_d64_flags = flags; + slotp->bss_d64_base = pci_addr; +#ifdef CONFIG_IA64_SGI_SN2 + pci_addr |= (PHYS_TO_DMA(xio_addr)) + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); +#else + pci_addr |= xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); +#endif + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { + if (flags & PCIBR_VCHAN1) + pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + if (have_rrbs < 2) { + if (pci_addr & PCI64_ATTR_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tdirect 64bit address is 0x%x\n" + "\tnew flags: 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, pci_addr, (uint64_t) flags); +#endif + return (pci_addr); + } + /* our flags conflict with Device(x). + */ + flags = flags + & ~PCIIO_DMA_A64 + & ~PCIBR_VCHAN0 + ; + +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tUnable to set Device(x) bits for Direct-64\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } + /* Try to satisfy the request with the 32-bit direct + * map. This can fail if the configuration bits in + * Device(x) conflict with our flags, or if the + * target address is outside where DIR_OFF points. + */ + { + size_t map_size = 1ULL << 31; + iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; + iopaddr_t offset = xio_addr - xio_base; + iopaddr_t endoff = req_size + offset; + + if ((req_size > map_size) || + (xio_addr < xio_base) || + (xio_port != pcibr_soft->bs_dir_xport) || + (endoff > map_size)) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\txio region outside direct32 target\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } else { + pci_addr = slotp->bss_d32_base; + if ((pci_addr != PCIBR_D32_BASE_UNSET) && + (flags == slotp->bss_d32_flags)) { + + pci_addr |= offset; + +#if DEBUG && PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr: [reuse]\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tmapped via direct32 offset 0x%x\n" + "\twill DMA via pci addr 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, offset, pci_addr); +#endif + return (pci_addr); + } + if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { + + pci_addr = PCI32_DIRECT_BASE; + slotp->bss_d32_flags = flags; + slotp->bss_d32_base = pci_addr; + pci_addr |= offset; + + /* Make sure we have an RRB (or two). + */ + if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + if (have_rrbs < 2) { + if (slotp->bss_device & BRIDGE_DEV_PREF) + min_rrbs = 2; + else + min_rrbs = 1; + if (have_rrbs < min_rrbs) + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + } + } +#if PCIBR_DMA_DEBUG +#if HWG_PERF_CHECK + if (xio_addr != 0x20000000) +#endif + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tmapped via direct32 offset 0x%x\n" + "\twill DMA via pci addr 0x%x\n" + "\tnew flags: 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr, offset, pci_addr, (uint64_t) flags); +#endif + return (pci_addr); + } + /* our flags conflict with Device(x). + */ +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tUnable to set Device(x) bits for Direct-32\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + } + } + +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n" + "\tno acceptable PCI address found or constructable\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + + return 0; +} + +/*ARGSUSED */ +alenlist_t +pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + alenlist_t palenlist, + unsigned flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; + xwidgetnum_t xio_port; + + alenlist_t pciio_alenlist = 0; + alenlist_t xtalk_alenlist = 0; + + int inplace; + unsigned direct64; + unsigned al_flags; + + iopaddr_t xio_base; + alenaddr_t xio_addr; + size_t xio_size; + + size_t map_size; + iopaddr_t pci_base; + alenaddr_t pci_addr; + + unsigned relbits = 0; + + /* merge in forced flags */ + flags |= pcibr_soft->bs_dma_flags; + + inplace = flags & PCIIO_INPLACE; + direct64 = flags & PCIIO_DMA_A64; + al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; + + if (direct64) { + map_size = 1ull << 48; + xio_base = 0; + pci_base = slotp->bss_d64_base; + if ((pci_base != PCIBR_D64_BASE_UNSET) && + (flags == slotp->bss_d64_flags)) { + /* reuse previous base info */ + } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { + /* DMA configuration conflict */ + goto fail; + } else { + relbits = BRIDGE_DEV_D64_BITS; + pci_base = + pcibr_flags_to_d64(flags, pcibr_soft); + } + } else { + xio_base = pcibr_soft->bs_dir_xbase; + map_size = 1ull << 31; + pci_base = slotp->bss_d32_base; + if ((pci_base != PCIBR_D32_BASE_UNSET) && + (flags == slotp->bss_d32_flags)) { + /* reuse previous base info */ + } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { + /* DMA configuration conflict */ + goto fail; + } else { + relbits = BRIDGE_DEV_D32_BITS; + pci_base = PCI32_DIRECT_BASE; + } + } + + xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, + flags & DMAMAP_FLAGS); + if (!xtalk_alenlist) + goto fail; + + alenlist_cursor_init(xtalk_alenlist, 0, NULL); + + if (inplace) { + pciio_alenlist = xtalk_alenlist; + } else { + pciio_alenlist = alenlist_create(al_flags); + if (!pciio_alenlist) + goto fail; + } + + while (ALENLIST_SUCCESS == + alenlist_get(xtalk_alenlist, NULL, 0, + &xio_addr, &xio_size, al_flags)) { + + /* + * find which XIO port this goes to. + */ + if (XIO_PACKED(xio_addr)) { + if (xio_addr == XIO_NOWHERE) { +#if PCIBR_DMA_DEBUG + printk("pcibr_dmatrans_addr:\n" + "\tpciio connection point %v\n" + "\txtalk connection point %v\n" + "\twanted paddr [0x%x..0x%x]\n" + "\txtalk_dmatrans_addr returned 0x%x\n", + pconn_vhdl, xconn_vhdl, + paddr, paddr + req_size - 1, + xio_addr); +#endif + return 0; + } + xio_port = XIO_PORT(xio_addr); + xio_addr = XIO_ADDR(xio_addr); + } else + xio_port = pcibr_soft->bs_mxid; + + /* + * If this DMA comes back to us, + * return the PCI MEM address on + * which it would land, or NULL + * if the target is something + * on bridge other than PCI MEM. + */ + if (xio_port == pcibr_soft->bs_xid) { + pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); + if ( (pci_addr == (alenaddr_t)NULL) ) + goto fail; + } else if (direct64) { + ASSERT(xio_port != 0); + pci_addr = pci_base | xio_addr + | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + } else { + iopaddr_t offset = xio_addr - xio_base; + iopaddr_t endoff = xio_size + offset; + + if ((xio_size > map_size) || + (xio_addr < xio_base) || + (xio_port != pcibr_soft->bs_dir_xport) || + (endoff > map_size)) + goto fail; + + pci_addr = pci_base + (xio_addr - xio_base); + } + + /* write the PCI DMA address + * out to the scatter-gather list. + */ + if (inplace) { + if (ALENLIST_SUCCESS != + alenlist_replace(pciio_alenlist, NULL, + &pci_addr, &xio_size, al_flags)) + goto fail; + } else { + if (ALENLIST_SUCCESS != + alenlist_append(pciio_alenlist, + pci_addr, xio_size, al_flags)) + goto fail; + } + } + + if (relbits) { + if (direct64) { + slotp->bss_d64_flags = flags; + slotp->bss_d64_base = pci_base; + } else { + slotp->bss_d32_flags = flags; + slotp->bss_d32_base = pci_base; + } + } + if (!inplace) + alenlist_done(xtalk_alenlist); + + /* Reset the internal cursor of the alenlist to be returned back + * to the caller. + */ + alenlist_cursor_init(pciio_alenlist, 0, NULL); + return pciio_alenlist; + + fail: + if (relbits) + pcibr_release_device(pcibr_soft, pciio_slot, relbits); + if (pciio_alenlist && !inplace) + alenlist_destroy(pciio_alenlist); + return 0; +} + +void +pcibr_dmamap_drain(pcibr_dmamap_t map) +{ + xtalk_dmamap_drain(map->bd_xtalk); +} + +void +pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, + paddr_t paddr, + size_t bytes) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); +} + +void +pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, + alenlist_t list) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + + xtalk_dmalist_drain(xconn_vhdl, list); +} + +/* + * Get the starting PCIbus address out of the given DMA map. + * This function is supposed to be used by a close friend of PCI bridge + * since it relies on the fact that the starting address of the map is fixed at + * the allocation time in the current implementation of PCI bridge. + */ +iopaddr_t +pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) +{ + return (pcibr_dmamap->bd_pci_addr); +} + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ +/*ARGSUSED */ +void +pcibr_provider_startup(devfs_handle_t pcibr) +{ +} + +/*ARGSUSED */ +void +pcibr_provider_shutdown(devfs_handle_t pcibr) +{ +} + +int +pcibr_reset(devfs_handle_t conn) +{ + pciio_info_t pciio_info = pciio_info_get(conn); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t ctlreg; + unsigned cfgctl[8]; + unsigned long s; + int f, nf; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + int win; + + if (pcibr_soft->bs_slot[pciio_slot].has_host) { + pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; + pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; + } + if (pciio_slot < 4) { + s = pcibr_lock(pcibr_soft); + nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; + for (f = 0; f < nf; ++f) + if (pcibr_infoh[f]) + cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; + + ctlreg = bridge->b_wid_control; + bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); + /* XXX delay? */ + bridge->b_wid_control = ctlreg; + /* XXX delay? */ + + for (f = 0; f < nf; ++f) + if ((pcibr_info = pcibr_infoh[f])) + for (win = 0; win < 6; ++win) + if (pcibr_info->f_window[win].w_base != 0) + bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = + pcibr_info->f_window[win].w_base; + for (f = 0; f < nf; ++f) + if (pcibr_infoh[f]) + bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; + pcibr_unlock(pcibr_soft, s); + + return 0; + } +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_WARNING "%v: pcibr_reset unimplemented for slot %d\n", + conn, pciio_slot); +#endif + return -1; +} + +pciio_endian_t +pcibr_endian_set(devfs_handle_t pconn_vhdl, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridgereg_t devreg; + unsigned long s; + + /* + * Bridge supports hardware swapping; so we can always + * arrange for the caller's desired endianness. + */ + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + if (device_end != desired_end) + devreg |= BRIDGE_DEV_SWAP_BITS; + else + devreg &= ~BRIDGE_DEV_SWAP_BITS; + + /* NOTE- if we ever put SWAP bits + * onto the disabled list, we will + * have to change the logic here. + */ + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); + +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); +#endif + + return desired_end; +} + +/* This (re)sets the GBR and REALTIME bits and also keeps track of how + * many sets are outstanding. Reset succeeds only if the number of outstanding + * sets == 1. + */ +int +pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, + pciio_slot_t pciio_slot, + pciio_priority_t device_prio) +{ + unsigned long s; + int *counter; + bridgereg_t rtbits = 0; + bridgereg_t devreg; + int rc = PRIO_SUCCESS; + + /* in dual-slot configurations, the host and the + * guest have separate DMA resources, so they + * have separate requirements for priority bits. + */ + + counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); + + /* + * Bridge supports PCI notions of LOW and HIGH priority + * arbitration rings via a "REAL_TIME" bit in the per-device + * Bridge register. The "GBR" bit controls access to the GBR + * ring on the xbow. These two bits are (re)set together. + * + * XXX- Bug in Rev B Bridge Si: + * Symptom: Prefetcher starts operating incorrectly. This happens + * due to corruption of the address storage ram in the prefetcher + * when a non-real time PCI request is pulled and a real-time one is + * put in it's place. Workaround: Use only a single arbitration ring + * on PCI bus. GBR and RR can still be uniquely used per + * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. + */ + + if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) + rtbits |= BRIDGE_DEV_RT; + + /* NOTE- if we ever put DEV_RT or DEV_GBR on + * the disabled list, we will have to take + * it into account here. + */ + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + if (device_prio == PCI_PRIO_HIGH) { + if ((++*counter == 1)) { + if (rtbits) + devreg |= rtbits; + else + rc = PRIO_FAIL; + } + } else if (device_prio == PCI_PRIO_LOW) { + if (*counter <= 0) + rc = PRIO_FAIL; + else if (--*counter == 0) + if (rtbits) + devreg &= ~rtbits; + } + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); + + return rc; +} + +pciio_priority_t +pcibr_priority_set(devfs_handle_t pconn_vhdl, + pciio_priority_t device_prio) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); + + return device_prio; +} + +/* + * Interfaces to allow special (e.g. SGI) drivers to set/clear + * Bridge-specific device flags. Many flags are modified through + * PCI-generic interfaces; we don't allow them to be directly + * manipulated here. Only flags that at this point seem pretty + * Bridge-specific can be set through these special interfaces. + * We may add more flags as the need arises, or remove flags and + * create PCI-generic interfaces as the need arises. + * + * Returns 0 on failure, 1 on success + */ +int +pcibr_device_flags_set(devfs_handle_t pconn_vhdl, + pcibr_device_flags_t flags) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridgereg_t set = 0; + bridgereg_t clr = 0; + + ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); + + if (flags & PCIBR_WRITE_GATHER) + set |= BRIDGE_DEV_PMU_WRGA_EN; + if (flags & PCIBR_NOWRITE_GATHER) + clr |= BRIDGE_DEV_PMU_WRGA_EN; + + if (flags & PCIBR_WRITE_GATHER) + set |= BRIDGE_DEV_DIR_WRGA_EN; + if (flags & PCIBR_NOWRITE_GATHER) + clr |= BRIDGE_DEV_DIR_WRGA_EN; + + if (flags & PCIBR_PREFETCH) + set |= BRIDGE_DEV_PREF; + if (flags & PCIBR_NOPREFETCH) + clr |= BRIDGE_DEV_PREF; + + if (flags & PCIBR_PRECISE) + set |= BRIDGE_DEV_PRECISE; + if (flags & PCIBR_NOPRECISE) + clr |= BRIDGE_DEV_PRECISE; + + if (flags & PCIBR_BARRIER) + set |= BRIDGE_DEV_BARRIER; + if (flags & PCIBR_NOBARRIER) + clr |= BRIDGE_DEV_BARRIER; + + if (flags & PCIBR_64BIT) + set |= BRIDGE_DEV_DEV_SIZE; + if (flags & PCIBR_NO64BIT) + clr |= BRIDGE_DEV_DEV_SIZE; + + if (set || clr) { + bridgereg_t devreg; + unsigned long s; + + s = pcibr_lock(pcibr_soft); + devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; + devreg = (devreg & ~clr) | set; + if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { + bridge_t *bridge = pcibr_soft->bs_base; + + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + pcibr_unlock(pcibr_soft, s); +#if DEBUG && PCIBR_DEV_DEBUG + printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); +#endif + } + return (1); +} + +pciio_provider_t pcibr_provider = +{ + (pciio_piomap_alloc_f *) pcibr_piomap_alloc, + (pciio_piomap_free_f *) pcibr_piomap_free, + (pciio_piomap_addr_f *) pcibr_piomap_addr, + (pciio_piomap_done_f *) pcibr_piomap_done, + (pciio_piotrans_addr_f *) pcibr_piotrans_addr, + (pciio_piospace_alloc_f *) pcibr_piospace_alloc, + (pciio_piospace_free_f *) pcibr_piospace_free, + + (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, + (pciio_dmamap_free_f *) pcibr_dmamap_free, + (pciio_dmamap_addr_f *) pcibr_dmamap_addr, + (pciio_dmamap_list_f *) pcibr_dmamap_list, + (pciio_dmamap_done_f *) pcibr_dmamap_done, + (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, + (pciio_dmatrans_list_f *) pcibr_dmatrans_list, + (pciio_dmamap_drain_f *) pcibr_dmamap_drain, + (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, + (pciio_dmalist_drain_f *) pcibr_dmalist_drain, + + (pciio_intr_alloc_f *) pcibr_intr_alloc, + (pciio_intr_free_f *) pcibr_intr_free, + (pciio_intr_connect_f *) pcibr_intr_connect, + (pciio_intr_disconnect_f *) pcibr_intr_disconnect, + (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, + + (pciio_provider_startup_f *) pcibr_provider_startup, + (pciio_provider_shutdown_f *) pcibr_provider_shutdown, + (pciio_reset_f *) pcibr_reset, + (pciio_write_gather_flush_f *) pcibr_write_gather_flush, + (pciio_endian_set_f *) pcibr_endian_set, + (pciio_priority_set_f *) pcibr_priority_set, + (pciio_config_get_f *) pcibr_config_get, + (pciio_config_set_f *) pcibr_config_set, + + (pciio_error_devenable_f *) 0, + (pciio_error_extract_f *) 0, + +#ifdef LATER + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, + (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, +#else + (pciio_driver_reg_callback_f *) 0, + (pciio_driver_unreg_callback_f *) 0, +#endif + (pciio_device_unregister_f *) pcibr_device_unregister, + (pciio_dma_enabled_f *) pcibr_dma_enabled, +}; + +int +pcibr_dma_enabled(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + + return xtalk_dma_enabled(pcibr_soft->bs_conn); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1737 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +extern int hubii_check_widget_disabled(nasid_t, int); + +/* ===================================================================== + * ERROR HANDLING + */ + +#ifdef DEBUG +#ifdef ERROR_DEBUG +#define BRIDGE_PIOERR_TIMEOUT 100 /* Timeout with ERROR_DEBUG defined */ +#else +#define BRIDGE_PIOERR_TIMEOUT 40 /* Timeout in debug mode */ +#endif +#else +#define BRIDGE_PIOERR_TIMEOUT 1 /* Timeout in non-debug mode */ +#endif + +#ifdef DEBUG +#ifdef ERROR_DEBUG +bridgereg_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK; +#else +bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP; +#endif +#else +bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL | + BRIDGE_ISR_PCIBUS_PIOERR; +#endif + +#if defined (PCIBR_LLP_CONTROL_WAR) +int pcibr_llp_control_war_cnt; +#endif /* PCIBR_LLP_CONTROL_WAR */ + +/* FIXME: can these arrays be local ? */ + +#ifdef LATER + +struct reg_values xio_cmd_pactyp[] = +{ + {0x0, "RdReq"}, + {0x1, "RdResp"}, + {0x2, "WrReqWithResp"}, + {0x3, "WrResp"}, + {0x4, "WrReqNoResp"}, + {0x5, "Reserved(5)"}, + {0x6, "FetchAndOp"}, + {0x7, "Reserved(7)"}, + {0x8, "StoreAndOp"}, + {0x9, "Reserved(9)"}, + {0xa, "Reserved(a)"}, + {0xb, "Reserved(b)"}, + {0xc, "Reserved(c)"}, + {0xd, "Reserved(d)"}, + {0xe, "SpecialReq"}, + {0xf, "SpecialResp"}, + {0} +}; + +struct reg_desc xio_cmd_bits[] = +{ + {WIDGET_DIDN, -28, "DIDN", "%x"}, + {WIDGET_SIDN, -24, "SIDN", "%x"}, + {WIDGET_PACTYP, -20, "PACTYP", 0, xio_cmd_pactyp}, + {WIDGET_TNUM, -15, "TNUM", "%x"}, + {WIDGET_COHERENT, 0, "COHERENT"}, + {WIDGET_DS, 0, "DS"}, + {WIDGET_GBR, 0, "GBR"}, + {WIDGET_VBPM, 0, "VBPM"}, + {WIDGET_ERROR, 0, "ERROR"}, + {WIDGET_BARRIER, 0, "BARRIER"}, + {0} +}; + +#define F(s,n) { 1l<<(s),-(s), n } + +struct reg_desc bridge_int_status_desc[] = +{ + F(31, "MULTI_ERR"), + F(30, "PMU_ESIZE_EFAULT"), + F(29, "UNEXPECTED_RESP"), + F(28, "BAD_XRESP_PACKET"), + F(27, "BAD_XREQ_PACKET"), + F(26, "RESP_XTALK_ERROR"), + F(25, "REQ_XTALK_ERROR"), + F(24, "INVALID_ADDRESS"), + F(23, "UNSUPPORTED_XOP"), + F(22, "XREQ_FIFO_OFLOW"), + F(21, "LLP_REC_SNERROR"), + F(20, "LLP_REC_CBERROR"), + F(19, "LLP_RCTY"), + F(18, "LLP_TX_RETRY"), + F(17, "LLP_TCTY"), + F(16, "SSRAM_PERR"), + F(15, "PCI_ABORT"), + F(14, "PCI_PARITY"), + F(13, "PCI_SERR"), + F(12, "PCI_PERR"), + F(11, "PCI_MASTER_TOUT"), + F(10, "PCI_RETRY_CNT"), + F(9, "XREAD_REQ_TOUT"), + F(8, "GIO_BENABLE_ERR"), + F(7, "INT7"), + F(6, "INT6"), + F(5, "INT5"), + F(4, "INT4"), + F(3, "INT3"), + F(2, "INT2"), + F(1, "INT1"), + F(0, "INT0"), + {0} +}; + +struct reg_values space_v[] = +{ + {PCIIO_SPACE_NONE, "none"}, + {PCIIO_SPACE_ROM, "ROM"}, + {PCIIO_SPACE_IO, "I/O"}, + {PCIIO_SPACE_MEM, "MEM"}, + {PCIIO_SPACE_MEM32, "MEM(32)"}, + {PCIIO_SPACE_MEM64, "MEM(64)"}, + {PCIIO_SPACE_CFG, "CFG"}, + {PCIIO_SPACE_WIN(0), "WIN(0)"}, + {PCIIO_SPACE_WIN(1), "WIN(1)"}, + {PCIIO_SPACE_WIN(2), "WIN(2)"}, + {PCIIO_SPACE_WIN(3), "WIN(3)"}, + {PCIIO_SPACE_WIN(4), "WIN(4)"}, + {PCIIO_SPACE_WIN(5), "WIN(5)"}, + {PCIIO_SPACE_BAD, "BAD"}, + {0} +}; +struct reg_desc space_desc[] = +{ + {0xFF, 0, "space", 0, space_v}, + {0} +}; +#define device_desc device_bits +struct reg_desc device_bits[] = +{ + {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, + {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, + {BRIDGE_DEV_FORCE_PCI_PAR, 0, "FORCE_PCI_PAR"}, + {BRIDGE_DEV_VIRTUAL_EN, 0, "VIRTUAL_EN"}, + {BRIDGE_DEV_PMU_WRGA_EN, 0, "PMU_WRGA_EN"}, + {BRIDGE_DEV_DIR_WRGA_EN, 0, "DIR_WRGA_EN"}, + {BRIDGE_DEV_DEV_SIZE, 0, "DEV_SIZE"}, + {BRIDGE_DEV_RT, 0, "RT"}, + {BRIDGE_DEV_SWAP_PMU, 0, "SWAP_PMU"}, + {BRIDGE_DEV_SWAP_DIR, 0, "SWAP_DIR"}, + {BRIDGE_DEV_PREF, 0, "PREF"}, + {BRIDGE_DEV_PRECISE, 0, "PRECISE"}, + {BRIDGE_DEV_COH, 0, "COH"}, + {BRIDGE_DEV_BARRIER, 0, "BARRIER"}, + {BRIDGE_DEV_GBR, 0, "GBR"}, + {BRIDGE_DEV_DEV_SWAP, 0, "DEV_SWAP"}, + {BRIDGE_DEV_DEV_IO_MEM, 0, "DEV_IO_MEM"}, + {BRIDGE_DEV_OFF_MASK, BRIDGE_DEV_OFF_ADDR_SHFT, "DEV_OFF", "%x"}, + {0} +}; + +#endif /* LATER */ + +void +print_bridge_errcmd(uint32_t cmdword, char *errtype) +{ + printk( + "\t Bridge %s Error Command Word Register %R\n", + errtype, cmdword, xio_cmd_bits); +} + +char *pcibr_isr_errs[] = +{ + "", "", "", "", "", "", "", "", + "08: GIO non-contiguous byte enable in crosstalk packet", + "09: PCI to Crosstalk read request timeout", + "10: PCI retry operation count exhausted.", + "11: PCI bus device select timeout", + "12: PCI device reported parity error", + "13: PCI Address/Cmd parity error ", + "14: PCI Bridge detected parity error", + "15: PCI abort condition", + "16: SSRAM parity error", + "17: LLP Transmitter Retry count wrapped", + "18: LLP Transmitter side required Retry", + "19: LLP Receiver retry count wrapped", + "20: LLP Receiver check bit error", + "21: LLP Receiver sequence number error", + "22: Request packet overflow", + "23: Request operation not supported by bridge", + "24: Request packet has invalid address for bridge widget", + "25: Incoming request xtalk command word error bit set or invalid sideband", + "26: Incoming response xtalk command word error bit set or invalid sideband", + "27: Framing error, request cmd data size does not match actual", + "28: Framing error, response cmd data size does not match actual", + "29: Unexpected response arrived", + "30: PMU Access Fault", + "31: Multiple errors occurred", +}; + +#define BEM_ADD_STR(s) printk("%s", (s)) +#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v)) +#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc) +#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc) +#define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s) + +/* + * display memory directory state + */ +void +pcibr_show_dir_state(paddr_t paddr, char *prefix) +{ + int state; + uint64_t vec_ptr; + hubreg_t elo; + extern char *dir_state_str[]; + extern void get_dir_ent(paddr_t, int *, uint64_t *, hubreg_t *); + + get_dir_ent(paddr, &state, &vec_ptr, &elo); + + printf("%saddr 0x%x: state 0x%x owner 0x%x (%s)\n", + prefix, paddr, state, vec_ptr, dir_state_str[state]); +} + + +/* + * Dump relevant error information for Bridge error interrupts. + */ +/*ARGSUSED */ +void +pcibr_error_dump(pcibr_soft_t pcibr_soft) +{ + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t int_status; + bridgereg_t mult_int; + int bit; + int i; + char *reg_desc; + paddr_t addr; + + int_status = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); + if (!int_status) { + /* No error bits set */ + return; + } + + /* Check if dumping the same error information multiple times */ + if (test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, + int_status) == int_status) { + return; + } + + printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%X for %s\n" + " Dumping relevant %sBridge registers for each bit set...\n", + int_status, pcibr_soft->bs_name, + (is_xbridge(bridge) ? "X" : "")); + + for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) { + bit = 1 << i; + + /* + * A number of int_status bits are only defined for Bridge. + * Ignore them in the case of an XBridge. + */ + if (is_xbridge(bridge) && ((bit == BRIDGE_ISR_MULTI_ERR) || + (bit == BRIDGE_ISR_SSRAM_PERR) || + (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) { + continue; + } + + if (int_status & bit) { + printk("\t%s\n", pcibr_isr_errs[i]); + + switch (bit) { + case BRIDGE_ISR_PAGE_FAULT: /* PMU_PAGE_FAULT (XBridge) */ +/* case BRIDGE_ISR_PMU_ESIZE_FAULT: PMU_ESIZE_FAULT (Bridge) */ + if (is_xbridge(bridge)) + reg_desc = "Map Fault Address"; + else + reg_desc = "SSRAM Parity Error"; + + printk("\t %s Register: 0x%x\n", reg_desc, + bridge->b_ram_perr_or_map_fault); + break; + + case BRIDGE_ISR_UNEXP_RESP: /* UNEXPECTED_RESP */ + print_bridge_errcmd(bridge->b_wid_aux_err, "Aux"); + break; + + case BRIDGE_ISR_BAD_XRESP_PKT: /* BAD_RESP_PACKET */ + case BRIDGE_ISR_RESP_XTLK_ERR: /* RESP_XTALK_ERROR */ + case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* XREAD_REQ_TOUT */ + + addr = (((uint64_t) (bridge->b_wid_resp_upper & 0xFFFF) << 32) + | bridge->b_wid_resp_lower); + printk( + "\t Bridge Response Buffer Error Upper Address Register: 0x%x\n" + "\t Bridge Response Buffer Error Lower Address Register: 0x%x\n" + "\t dev-num %d buff-num %d addr 0x%x\n", + bridge->b_wid_resp_upper, bridge->b_wid_resp_lower, + ((bridge->b_wid_resp_upper >> 20) & 0x3), + ((bridge->b_wid_resp_upper >> 16) & 0xF), + addr); + if (bit == BRIDGE_ISR_RESP_XTLK_ERR) { + /* display memory directory associated with cacheline */ + pcibr_show_dir_state(addr, "\t "); + } + break; + + case BRIDGE_ISR_BAD_XREQ_PKT: /* BAD_XREQ_PACKET */ + case BRIDGE_ISR_REQ_XTLK_ERR: /* REQ_XTALK_ERROR */ + case BRIDGE_ISR_INVLD_ADDR: /* INVALID_ADDRESS */ + case BRIDGE_ISR_UNSUPPORTED_XOP: /* UNSUPPORTED_XOP */ + print_bridge_errcmd(bridge->b_wid_aux_err, ""); + printk("\t Bridge Error Upper Address Register: 0x%x\n" + "\t Bridge Error Lower Address Register: 0x%x\n" + "\t Bridge Error Address: 0x%x\n", + (uint64_t) bridge->b_wid_err_upper, + (uint64_t) bridge->b_wid_err_lower, + (((uint64_t) bridge->b_wid_err_upper << 32) | + bridge->b_wid_err_lower)); + break; + + case BRIDGE_ISR_SSRAM_PERR: /* SSRAM_PERR */ + if (!is_xbridge(bridge)) { /* only defined on Bridge */ + printk( + "\t Bridge SSRAM Parity Error Register: 0x%x\n", + bridge->b_ram_perr); + } + break; + + case BRIDGE_ISR_PCI_ABORT: /* PCI_ABORT */ + case BRIDGE_ISR_PCI_PARITY: /* PCI_PARITY */ + case BRIDGE_ISR_PCI_SERR: /* PCI_SERR */ + case BRIDGE_ISR_PCI_PERR: /* PCI_PERR */ + case BRIDGE_ISR_PCI_MST_TIMEOUT: /* PCI_MASTER_TOUT */ + case BRIDGE_ISR_PCI_RETRY_CNT: /* PCI_RETRY_CNT */ + case BRIDGE_ISR_GIO_B_ENBL_ERR: /* GIO BENABLE_ERR */ + printk("\t PCI Error Upper Address Register: 0x%x\n" + "\t PCI Error Lower Address Register: 0x%x\n" + "\t PCI Error Address: 0x%x\n", + (uint64_t) bridge->b_pci_err_upper, + (uint64_t) bridge->b_pci_err_lower, + (((uint64_t) bridge->b_pci_err_upper << 32) | + bridge->b_pci_err_lower)); + break; + } + } + } + + if (is_xbridge(bridge) && (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK)) { + mult_int = bridge->b_mult_int; + printk(" XBridge Multiple Interrupt Register is 0x%x\n", + mult_int); + for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) { + if (mult_int & (1 << i)) + printk("\t%s\n", pcibr_isr_errs[i]); + } + } +} + +#define PCIBR_ERRINTR_GROUP(error) \ + (( error & (BRIDGE_IRR_PCI_GRP|BRIDGE_IRR_GIO_GRP) + +uint32_t +pcibr_errintr_group(uint32_t error) +{ + uint32_t group = BRIDGE_IRR_MULTI_CLR; + + if (error & BRIDGE_IRR_PCI_GRP) + group |= BRIDGE_IRR_PCI_GRP_CLR; + if (error & BRIDGE_IRR_SSRAM_GRP) + group |= BRIDGE_IRR_SSRAM_GRP_CLR; + if (error & BRIDGE_IRR_LLP_GRP) + group |= BRIDGE_IRR_LLP_GRP_CLR; + if (error & BRIDGE_IRR_REQ_DSP_GRP) + group |= BRIDGE_IRR_REQ_DSP_GRP_CLR; + if (error & BRIDGE_IRR_RESP_BUF_GRP) + group |= BRIDGE_IRR_RESP_BUF_GRP_CLR; + if (error & BRIDGE_IRR_CRP_GRP) + group |= BRIDGE_IRR_CRP_GRP_CLR; + + return group; + +} + + +/* pcibr_pioerr_check(): + * Check to see if this pcibr has a PCI PIO + * TIMEOUT error; if so, bump the timeout-count + * on any piomaps that could cover the address. + */ +static void +pcibr_pioerr_check(pcibr_soft_t soft) +{ + bridge_t *bridge; + bridgereg_t b_int_status; + bridgereg_t b_pci_err_lower; + bridgereg_t b_pci_err_upper; + iopaddr_t pci_addr; + pciio_slot_t slot; + pcibr_piomap_t map; + iopaddr_t base; + size_t size; + unsigned win; + int func; + + bridge = soft->bs_base; + b_int_status = bridge->b_int_status; + if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { + b_pci_err_lower = bridge->b_pci_err_lower; + b_pci_err_upper = bridge->b_pci_err_upper; + b_int_status = bridge->b_int_status; + if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { + + pci_addr = b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK; + pci_addr = (pci_addr << 32) | b_pci_err_lower; + + slot = 8; + while (slot-- > 0) { + int nfunc = soft->bs_slot[slot].bss_ninfo; + pcibr_info_h pcibr_infoh = soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; func++) { + pcibr_info_t pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + for (map = pcibr_info->f_piomap; + map != NULL; map = map->bp_next) { + base = map->bp_pciaddr; + size = map->bp_mapsz; + win = map->bp_space - PCIIO_SPACE_WIN(0); + if (win < 6) + base += + soft->bs_slot[slot].bss_window[win].bssw_base; + else if (map->bp_space == PCIIO_SPACE_ROM) + base += pcibr_info->f_rbase; + if ((pci_addr >= base) && (pci_addr < (base + size))) + atomicAddInt(map->bp_toc, 1); + } + } + } + } + } +} + +/* + * PCI Bridge Error interrupt handler. + * This gets invoked, whenever a PCI bridge sends an error interrupt. + * Primarily this servers two purposes. + * - If an error can be handled (typically a PIO read/write + * error, we try to do it silently. + * - If an error cannot be handled, we die violently. + * Interrupt due to PIO errors: + * - Bridge sends an interrupt, whenever a PCI operation + * done by the bridge as the master fails. Operations could + * be either a PIO read or a PIO write. + * PIO Read operation also triggers a bus error, and it's + * We primarily ignore this interrupt in that context.. + * For PIO write errors, this is the only indication. + * and we have to handle with the info from here. + * + * So, there is no way to distinguish if an interrupt is + * due to read or write error!. + */ + + +void +pcibr_error_intr_handler(intr_arg_t arg) +{ + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + bridgereg_t int_status; + bridgereg_t err_status; + int i; + + /* REFERENCED */ + bridgereg_t disable_errintr_mask = 0; + int rv; + int error_code = IOECODE_DMA | IOECODE_READ; + ioerror_mode_t mode = MODE_DEVERROR; + ioerror_t ioe; + nasid_t nasid; + +#if PCIBR_SOFT_LIST + { + extern pcibr_list_p pcibr_list; + pcibr_list_p entry; + + entry = pcibr_list; + while (1) { + if (entry == NULL) { + PRINT_PANIC( + "pcibr_error_intr_handler:\n" + "\tmy parameter (0x%x) is not a pcibr_soft!", + arg); + } + if ((intr_arg_t) entry->bl_soft == arg) + break; + entry = entry->bl_next; + } + } +#endif + pcibr_soft = (pcibr_soft_t) arg; + bridge = pcibr_soft->bs_base; + + /* + * pcibr_error_intr_handler gets invoked whenever bridge encounters + * an error situation, and the interrupt for that error is enabled. + * This routine decides if the error is fatal or not, and takes + * action accordingly. + * + * In the case of PIO read/write timeouts, there is no way + * to know if it was a read or write request that timed out. + * If the error was due to a "read", a bus error will also occur + * and the bus error handling code takes care of it. + * If the error is due to a "write", the error is currently logged + * by this routine. For SN1 and SN0, if fire-and-forget mode is + * disabled, a write error response xtalk packet will be sent to + * the II, which will cause an II error interrupt. No write error + * recovery actions of any kind currently take place at the pcibr + * layer! (e.g., no panic on unrecovered write error) + * + * Prior to reading the Bridge int_status register we need to ensure + * that there are no error bits set in the lower layers (hubii) + * that have disabled PIO access to the widget. If so, there is nothing + * we can do until the bits clear, so we setup a timeout and try again + * later. + */ + + nasid = NASID_GET(bridge); + if (hubii_check_widget_disabled(nasid, pcibr_soft->bs_xid)) { + timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT); + pcibr_soft->bs_errinfo.bserr_toutcnt++; + return; + } + + /* int_status is which bits we have to clear; + * err_status is the bits we haven't handled yet. + */ + + int_status = bridge->b_int_status & ~BRIDGE_ISR_INT_MSK; + err_status = int_status & ~BRIDGE_ISR_MULTI_ERR; + + if (!(int_status & ~BRIDGE_ISR_INT_MSK)) { + /* + * No error bit set!!. + */ + return; + } + /* + * If we have a PCIBUS_PIOERR, hand it to the logger. + */ + if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { + pcibr_pioerr_check(pcibr_soft); + } + + if (err_status) { + struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; + + for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++, bs_estat++) { + if (err_status & (1 << i)) { + uint32_t errrate = 0; + uint32_t errcount = 0; + uint32_t errinterval = 0, current_tick = 0; + int llp_tx_retry_errors = 0; + int is_llp_tx_retry_intr = 0; + + bs_estat->bs_errcount_total++; + + current_tick = lbolt; + errinterval = (current_tick - bs_estat->bs_lasterr_timestamp); + errcount = (bs_estat->bs_errcount_total - + bs_estat->bs_lasterr_snapshot); + + is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY == (1 << i)); + + /* Check for the divide by zero condition while + * calculating the error rates. + */ + + if (errinterval) { + errrate = errcount / errinterval; + /* If able to calculate error rate + * on a LLP transmitter retry interrupt, check + * if the error rate is nonzero and we have seen + * a certain minimum number of errors. + * + * NOTE : errcount is being compared to + * PCIBR_ERRTIME_THRESHOLD to make sure that we are not + * seeing cases like x error interrupts per y ticks for + * very low x ,y (x > y ) which could result in a + * rate > 100/tick. + */ + if (is_llp_tx_retry_intr && + errrate && + (errcount >= PCIBR_ERRTIME_THRESHOLD)) { + llp_tx_retry_errors = 1; + } + } else { + errrate = 0; + /* Since we are not able to calculate the + * error rate check if we exceeded a certain + * minimum number of errors for LLP transmitter + * retries. Note that this can only happen + * within the first tick after the last snapshot. + */ + if (is_llp_tx_retry_intr && + (errcount >= PCIBR_ERRINTR_DISABLE_LEVEL)) { + llp_tx_retry_errors = 1; + } + } + + /* + * If a non-zero error rate (which is equivalent to + * to 100 errors/tick at least) for the LLP transmitter + * retry interrupt was seen, check if we should print + * a warning message. + */ + + if (llp_tx_retry_errors) { + static uint32_t last_printed_rate; + + if (errrate > last_printed_rate) { + last_printed_rate = errrate; + /* Print the warning only if the error rate + * for the transmitter retry interrupt + * exceeded the previously printed rate. + */ + printk(KERN_WARNING + "%s: %s, Excessive error interrupts : %d/tick\n", + pcibr_soft->bs_name, + pcibr_isr_errs[i], + errrate); + + } + /* + * Update snapshot, and time + */ + bs_estat->bs_lasterr_timestamp = current_tick; + bs_estat->bs_lasterr_snapshot = + bs_estat->bs_errcount_total; + + } + /* + * If the error rate is high enough, print the error rate. + */ + if (errinterval > PCIBR_ERRTIME_THRESHOLD) { + + if (errrate > PCIBR_ERRRATE_THRESHOLD) { + printk(KERN_NOTICE "%s: %s, Error rate %d/tick", + pcibr_soft->bs_name, + pcibr_isr_errs[i], + errrate); + /* + * Update snapshot, and time + */ + bs_estat->bs_lasterr_timestamp = current_tick; + bs_estat->bs_lasterr_snapshot = + bs_estat->bs_errcount_total; + } + } + if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) { + /* + * We have seen a fairly large number of errors of + * this type. Let's disable the interrupt. But flash + * a message about the interrupt being disabled. + */ + printk(KERN_NOTICE + "%s Disabling error interrupt type %s. Error count %d", + pcibr_soft->bs_name, + pcibr_isr_errs[i], + bs_estat->bs_errcount_total); + disable_errintr_mask |= (1 << i); + } + } + } + } + + if (disable_errintr_mask) { + /* + * Disable some high frequency errors as they + * could eat up too much cpu time. + */ + bridge->b_int_enable &= ~disable_errintr_mask; + } + /* + * If we leave the PROM cacheable, T5 might + * try to do a cache line sized writeback to it, + * which will cause a BRIDGE_ISR_INVLD_ADDR. + */ + if ((err_status & BRIDGE_ISR_INVLD_ADDR) && + (0x00000000 == bridge->b_wid_err_upper) && + (0x00C00000 == (0xFFC00000 & bridge->b_wid_err_lower)) && + (0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) { + err_status &= ~BRIDGE_ISR_INVLD_ADDR; + } +#if defined (PCIBR_LLP_CONTROL_WAR) + /* + * The bridge bug, where the llp_config or control registers + * need to be read back after being written, affects an MP + * system since there could be small windows between writing + * the register and reading it back on one cpu while another + * cpu is fielding an interrupt. If we run into this scenario, + * workaround the problem by ignoring the error. (bug 454474) + * pcibr_llp_control_war_cnt keeps an approximate number of + * times we saw this problem on a system. + */ + + if ((err_status & BRIDGE_ISR_INVLD_ADDR) && + ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) + == (BRIDGE_INT_RST_STAT & 0xff0))) { +#if 0 + if (kdebug) + printk(KERN_NOTICE "%s bridge: ignoring llp/control address interrupt", + pcibr_soft->bs_name); +#endif + pcibr_llp_control_war_cnt++; + err_status &= ~BRIDGE_ISR_INVLD_ADDR; + } +#endif /* PCIBR_LLP_CONTROL_WAR */ + +#ifdef EHE_ENABLE + /* Check if this is the RESP_XTALK_ERROR interrupt. + * This can happen due to a failed DMA READ operation. + */ + if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) { + /* Phase 1 : Look at the error state in the bridge and further + * down in the device layers. + */ + (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP); + IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid); + (void)pcibr_error_handler((error_handler_arg_t)pcibr_soft, + error_code, + mode, + &ioe); + /* Phase 2 : Perform the action agreed upon in phase 1. + */ + (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION); + rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft, + error_code, + mode, + &ioe); + } + if (rv != IOERROR_HANDLED) { +#endif /* EHE_ENABLE */ + + /* Dump/Log Bridge error interrupt info */ + if (err_status & bridge_errors_to_dump) { + printk("BRIDGE ERR_STATUS 0x%x\n", err_status); + pcibr_error_dump(pcibr_soft); + } + + if (err_status & BRIDGE_ISR_ERROR_FATAL) { + machine_error_dump(""); + cmn_err_tag(14, CE_PANIC, "PCI Bridge Error interrupt killed the system"); + /*NOTREACHED */ + } + +#ifdef EHE_ENABLE + } +#endif + + /* + * We can't return without re-enabling the interrupt, since + * it would cause problems for devices like IOC3 (Lost + * interrupts ?.). So, just cleanup the interrupt, and + * use saved values later.. + */ + bridge->b_int_rst_stat = pcibr_errintr_group(int_status); + + /* Zero out bserr_intstat field */ + test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, 0); +} + +/* + * pcibr_addr_toslot + * Given the 'pciaddr' find out which slot this address is + * allocated to, and return the slot number. + * While we have the info handy, construct the + * function number, space code and offset as well. + * + * NOTE: if this routine is called, we don't know whether + * the address is in CFG, MEM, or I/O space. We have to guess. + * This will be the case on PIO stores, where the only way + * we have of getting the address is to check the Bridge, which + * stores the PCI address but not the space and not the xtalk + * address (from which we could get it). + */ +int +pcibr_addr_toslot(pcibr_soft_t pcibr_soft, + iopaddr_t pciaddr, + pciio_space_t *spacep, + iopaddr_t *offsetp, + pciio_function_t *funcp) +{ + int s, f, w; + iopaddr_t base; + size_t size; + pciio_piospace_t piosp; + + /* + * Check if the address is in config space + */ + + if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { + + if (pciaddr >= BRIDGE_CONFIG1_BASE) + pciaddr -= BRIDGE_CONFIG1_BASE; + else + pciaddr -= BRIDGE_CONFIG_BASE; + + s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; + pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; + + if (funcp) { + f = pciaddr / 0x100; + pciaddr %= 0x100; + } + if (spacep) + *spacep = PCIIO_SPACE_CFG; + if (offsetp) + *offsetp = pciaddr; + if (funcp) + *funcp = f; + + return s; + } + for (s = 0; s < 8; s++) { + int nf = pcibr_soft->bs_slot[s].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; + + for (f = 0; f < nf; f++) { + pcibr_info_t pcibr_info = pcibr_infoh[f]; + + if (!pcibr_info) + continue; + for (w = 0; w < 6; w++) { + if (pcibr_info->f_window[w].w_space + == PCIIO_SPACE_NONE) { + continue; + } + base = pcibr_info->f_window[w].w_base; + size = pcibr_info->f_window[w].w_size; + + if ((pciaddr >= base) && (pciaddr < (base + size))) { + if (spacep) + *spacep = PCIIO_SPACE_WIN(w); + if (offsetp) + *offsetp = pciaddr - base; + if (funcp) + *funcp = f; + return s; + } /* endif match */ + } /* next window */ + } /* next func */ + } /* next slot */ + + /* + * Check if the address was allocated as part of the + * pcibr_piospace_alloc calls. + */ + for (s = 0; s < 8; s++) { + int nf = pcibr_soft->bs_slot[s].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; + + for (f = 0; f < nf; f++) { + pcibr_info_t pcibr_info = pcibr_infoh[f]; + + if (!pcibr_info) + continue; + piosp = pcibr_info->f_piospace; + while (piosp) { + if ((piosp->start <= pciaddr) && + ((piosp->count + piosp->start) > pciaddr)) { + if (spacep) + *spacep = piosp->space; + if (offsetp) + *offsetp = pciaddr - piosp->start; + return s; + } /* endif match */ + piosp = piosp->next; + } /* next piosp */ + } /* next func */ + } /* next slot */ + + /* + * Some other random address on the PCI bus ... + * we have no way of knowing whether this was + * a MEM or I/O access; so, for now, we just + * assume that the low 1G is MEM, the next + * 3G is I/O, and anything above the 4G limit + * is obviously MEM. + */ + + if (spacep) + *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : + (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : + PCIIO_SPACE_MEM); + if (offsetp) + *offsetp = pciaddr; + + return PCIIO_SLOT_NONE; + +} + +void +pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) +{ + bridge_t *bridge = pcibr_soft->bs_base; + + ASSERT(error_code & IOECODE_PIO); + error_code = error_code; + + bridge->b_int_rst_stat = + (BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR); + (void) bridge->b_wid_tflush; /* flushbus */ +} + +/* + * pcibr_error_extract + * Given the 'pcibr vertex handle' find out which slot + * the bridge status error address (from pcibr_soft info + * hanging off the vertex) + * allocated to, and return the slot number. + * While we have the info handy, construct the + * space code and offset as well. + * + * NOTE: if this routine is called, we don't know whether + * the address is in CFG, MEM, or I/O space. We have to guess. + * This will be the case on PIO stores, where the only way + * we have of getting the address is to check the Bridge, which + * stores the PCI address but not the space and not the xtalk + * address (from which we could get it). + * + * XXX- this interface has no way to return the function + * number on a multifunction card, even though that data + * is available. + */ + +pciio_slot_t +pcibr_error_extract(devfs_handle_t pcibr_vhdl, + pciio_space_t *spacep, + iopaddr_t *offsetp) +{ + pcibr_soft_t pcibr_soft = 0; + iopaddr_t bserr_addr; + bridge_t *bridge; + pciio_slot_t slot = PCIIO_SLOT_NONE; + arbitrary_info_t rev; + + /* Do a sanity check as to whether we really got a + * bridge vertex handle. + */ + if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != + GRAPH_SUCCESS) + return(slot); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (pcibr_soft) { + bridge = pcibr_soft->bs_base; + bserr_addr = + bridge->b_pci_err_lower | + ((uint64_t) (bridge->b_pci_err_upper & + BRIDGE_ERRUPPR_ADDRMASK) << 32); + + slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, + spacep, offsetp, NULL); + } + return slot; +} + +/*ARGSUSED */ +void +pcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum) +{ + /* + * XXX + * Device failed to handle error. Take steps to + * disable this device ? HOW TO DO IT ? + * + * If there are any Read response buffers associated + * with this device, it's time to get them back!! + * + * We can disassociate any interrupt level associated + * with this device, and disable that interrupt level + * + * For now it's just a place holder + */ +} + +/* + * pcibr_pioerror + * Handle PIO error that happened at the bridge pointed by pcibr_soft. + * + * Queries the Bus interface attached to see if the device driver + * mapping the device-number that caused error can handle the + * situation. If so, it will clean up any error, and return + * indicating the error was handled. If the device driver is unable + * to handle the error, it expects the bus-interface to disable that + * device, and takes any steps needed here to take away any resources + * associated with this device. + */ + +#define BEM_ADD_STR(s) printk("%s", (s)) +#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v)) +#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc) + +#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc) +#define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s) + +/* BEM_ADD_IOE doesn't dump the whole ioerror, it just + * decodes the PCI specific portions -- we count on our + * callers to dump the raw IOE data. + */ +#define BEM_ADD_IOE(ioe) \ + do { \ + if (IOERROR_FIELDVALID(ioe, busspace)) { \ + unsigned spc; \ + unsigned win; \ + \ + spc = IOERROR_GETVALUE(ioe, busspace); \ + win = spc - PCIIO_SPACE_WIN(0); \ + \ + switch (spc) { \ + case PCIIO_SPACE_CFG: \ + printk( \ + "\tPCI Slot %d Func %d CFG space Offset 0x%x\n", \ + pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ + pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ + IOERROR_GETVALUE(ioe, busaddr)); \ + break; \ + case PCIIO_SPACE_IO: \ + printk( \ + "\tPCI I/O space Offset 0x%x\n", \ + IOERROR_GETVALUE(ioe, busaddr)); \ + break; \ + case PCIIO_SPACE_MEM: \ + case PCIIO_SPACE_MEM32: \ + case PCIIO_SPACE_MEM64: \ + printk( \ + "\tPCI MEM space Offset 0x%x\n", \ + IOERROR_GETVALUE(ioe, busaddr)); \ + break; \ + default: \ + if (win < 6) { \ + printk( \ + "\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\ + pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ + pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ + win, \ + IOERROR_GETVALUE(ioe, busaddr)); \ + } \ + break; \ + } \ + } \ + } while (0) + +/*ARGSUSED */ +int +pcibr_pioerror( + pcibr_soft_t pcibr_soft, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioe) +{ + int retval = IOERROR_HANDLED; + + devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + bridge_t *bridge = pcibr_soft->bs_base; + + iopaddr_t bad_xaddr; + + pciio_space_t raw_space; /* raw PCI space */ + iopaddr_t raw_paddr; /* raw PCI address */ + + pciio_space_t space; /* final PCI space */ + pciio_slot_t slot; /* final PCI slot, if appropriate */ + pciio_function_t func; /* final PCI func, if appropriate */ + iopaddr_t offset; /* final PCI offset */ + + int cs, cw, cf; + pciio_space_t wx; + iopaddr_t wb; + size_t ws; + iopaddr_t wl; + + + /* + * We expect to have an "xtalkaddr" coming in, + * and need to construct the slot/space/offset. + */ + + bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); + + slot = PCIIO_SLOT_NONE; + func = PCIIO_FUNC_NONE; + raw_space = PCIIO_SPACE_NONE; + raw_paddr = 0; + + if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) && + (bad_xaddr < BRIDGE_TYPE1_CFG)) { + raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0; + slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF; + raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF; + raw_space = PCIIO_SPACE_CFG; + } + if ((bad_xaddr >= BRIDGE_TYPE1_CFG) && + (bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) { + /* Type 1 config space: + * slot and function numbers not known. + * Perhaps we can read them back? + */ + raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG; + raw_space = PCIIO_SPACE_CFG; + } + if ((bad_xaddr >= BRIDGE_DEVIO0) && + (bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) { + int x; + + raw_paddr = bad_xaddr - BRIDGE_DEVIO0; + x = raw_paddr / BRIDGE_DEVIO_OFF; + raw_paddr %= BRIDGE_DEVIO_OFF; + /* first two devio windows are double-sized */ + if ((x == 1) || (x == 3)) + raw_paddr += BRIDGE_DEVIO_OFF; + if (x > 0) + x--; + if (x > 1) + x--; + /* x is which devio reg; no guarantee + * PCI slot x will be responding. + * still need to figure out who decodes + * space/offset on the bus. + */ + raw_space = pcibr_soft->bs_slot[x].bss_devio.bssd_space; + if (raw_space == PCIIO_SPACE_NONE) { + /* Someone got an error because they + * accessed the PCI bus via a DevIO(x) + * window that pcibr has not yet assigned + * to any specific PCI address. It is + * quite possible that the Device(x) + * register has been changed since they + * made their access, but we will give it + * our best decode shot. + */ + raw_space = pcibr_soft->bs_slot[x].bss_device + & BRIDGE_DEV_DEV_IO_MEM + ? PCIIO_SPACE_MEM + : PCIIO_SPACE_IO; + raw_paddr += + (pcibr_soft->bs_slot[x].bss_device & + BRIDGE_DEV_OFF_MASK) << + BRIDGE_DEV_OFF_ADDR_SHFT; + } else + raw_paddr += pcibr_soft->bs_slot[x].bss_devio.bssd_base; + } + if ((bad_xaddr >= BRIDGE_PCI_MEM32_BASE) && + (bad_xaddr <= BRIDGE_PCI_MEM32_LIMIT)) { + raw_space = PCIIO_SPACE_MEM32; + raw_paddr = bad_xaddr - BRIDGE_PCI_MEM32_BASE; + } + if ((bad_xaddr >= BRIDGE_PCI_MEM64_BASE) && + (bad_xaddr <= BRIDGE_PCI_MEM64_LIMIT)) { + raw_space = PCIIO_SPACE_MEM64; + raw_paddr = bad_xaddr - BRIDGE_PCI_MEM64_BASE; + } + if ((bad_xaddr >= BRIDGE_PCI_IO_BASE) && + (bad_xaddr <= BRIDGE_PCI_IO_LIMIT)) { + raw_space = PCIIO_SPACE_IO; + raw_paddr = bad_xaddr - BRIDGE_PCI_IO_BASE; + } + space = raw_space; + offset = raw_paddr; + + if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { + /* we've got a space/offset but not which + * PCI slot decodes it. Check through our + * notions of which devices decode where. + * + * Yes, this "duplicates" some logic in + * pcibr_addr_toslot; the difference is, + * this code knows which space we are in, + * and can really really tell what is + * going on (no guessing). + */ + + for (cs = 0; (cs < 8) && (slot == PCIIO_SLOT_NONE); cs++) { + int nf = pcibr_soft->bs_slot[cs].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; + + for (cf = 0; (cf < nf) && (slot == PCIIO_SLOT_NONE); cf++) { + pcibr_info_t pcibr_info = pcibr_infoh[cf]; + + if (!pcibr_info) + continue; + for (cw = 0; (cw < 6) && (slot == PCIIO_SLOT_NONE); ++cw) { + if (((wx = pcibr_info->f_window[cw].w_space) != PCIIO_SPACE_NONE) && + ((wb = pcibr_info->f_window[cw].w_base) != 0) && + ((ws = pcibr_info->f_window[cw].w_size) != 0) && + ((wl = wb + ws) > wb) && + ((wb <= offset) && (wl > offset))) { + /* MEM, MEM32 and MEM64 need to + * compare as equal ... + */ + if ((wx == space) || + (((wx == PCIIO_SPACE_MEM) || + (wx == PCIIO_SPACE_MEM32) || + (wx == PCIIO_SPACE_MEM64)) && + ((space == PCIIO_SPACE_MEM) || + (space == PCIIO_SPACE_MEM32) || + (space == PCIIO_SPACE_MEM64)))) { + slot = cs; + func = cf; + space = PCIIO_SPACE_WIN(cw); + offset -= wb; + } /* endif window space match */ + } /* endif window valid and addr match */ + } /* next window unless slot set */ + } /* next func unless slot set */ + } /* next slot unless slot set */ + /* XXX- if slot is still -1, no PCI devices are + * decoding here using their standard PCI BASE + * registers. This would be a really good place + * to cross-coordinate with the pciio PCI + * address space allocation routines, to find + * out if this address is "allocated" by any of + * our subsidiary devices. + */ + } + /* Scan all piomap records on this PCI bus to update + * the TimeOut Counters on all matching maps. If we + * don't already know the slot number, take it from + * the first matching piomap. Note that we have to + * compare maps against raw_space and raw_paddr + * since space and offset could already be + * window-relative. + * + * There is a chance that one CPU could update + * through this path, and another CPU could also + * update due to an interrupt. Closing this hole + * would only result in the possibility of some + * errors never getting logged at all, and since the + * use for bp_toc is as a logical test rather than a + * strict count, the excess counts are not a + * problem. + */ + for (cs = 0; cs < 8; ++cs) { + int nf = pcibr_soft->bs_slot[cs].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; + + for (cf = 0; cf < nf; cf++) { + pcibr_info_t pcibr_info = pcibr_infoh[cf]; + pcibr_piomap_t map; + + if (!pcibr_info) + continue; + + for (map = pcibr_info->f_piomap; + map != NULL; map = map->bp_next) { + wx = map->bp_space; + wb = map->bp_pciaddr; + ws = map->bp_mapsz; + cw = wx - PCIIO_SPACE_WIN(0); + if (cw < 6) { + wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; + wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space; + } + if (wx == PCIIO_SPACE_ROM) { + wb += pcibr_info->f_rbase; + wx = PCIIO_SPACE_MEM; + } + if ((wx == PCIIO_SPACE_MEM32) || + (wx == PCIIO_SPACE_MEM64)) + wx = PCIIO_SPACE_MEM; + wl = wb + ws; + if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { + atomicAddInt(map->bp_toc, 1); + if (slot == PCIIO_SLOT_NONE) { + slot = cs; + space = map->bp_space; + if (cw < 6) + offset -= pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; + } + } + } + } + } + + if (space != PCIIO_SPACE_NONE) { + if (slot != PCIIO_SLOT_NONE) + if (func != PCIIO_FUNC_NONE) + IOERROR_SETVALUE(ioe, widgetdev, + pciio_widgetdev_create(slot,func)); + else + IOERROR_SETVALUE(ioe, widgetdev, + pciio_widgetdev_create(slot,0)); + + IOERROR_SETVALUE(ioe, busspace, space); + IOERROR_SETVALUE(ioe, busaddr, offset); + } + if (mode == MODE_DEVPROBE) { + /* + * During probing, we don't really care what the + * error is. Clean up the error in Bridge, notify + * subsidiary devices, and return success. + */ + pcibr_error_cleanup(pcibr_soft, error_code); + + /* if appropriate, give the error handler for this slot + * a shot at this probe access as well. + */ + return (slot == PCIIO_SLOT_NONE) ? IOERROR_HANDLED : + pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); + } + /* + * If we don't know what "PCI SPACE" the access + * was targeting, we may have problems at the + * Bridge itself. Don't touch any bridge registers, + * and do complain loudly. + */ + + if (space == PCIIO_SPACE_NONE) { + printk("XIO Bus Error at %s\n" + "\taccess to XIO bus offset 0x%x\n" + "\tdoes not correspond to any PCI address\n", + pcibr_soft->bs_name, bad_xaddr); + + /* caller will dump contents of ioe struct */ + return IOERROR_XTALKLEVEL; + } + + /* + * Actual PCI Error handling situation. + * Typically happens when a user level process accesses + * PCI space, and it causes some error. + * + * Due to PCI Bridge implementation, we get two indication + * for a read error: an interrupt and a Bus error. + * We like to handle read error in the bus error context. + * But the interrupt comes and goes before bus error + * could make much progress. (NOTE: interrupd does + * come in _after_ bus error processing starts. But it's + * completed by the time bus error code reaches PCI PIO + * error handling. + * Similarly write error results in just an interrupt, + * and error handling has to be done at interrupt level. + * There is no way to distinguish at interrupt time, if an + * error interrupt is due to read/write error.. + */ + + /* We know the xtalk addr, the raw PCI bus space, + * the raw PCI bus address, the decoded PCI bus + * space, the offset within that space, and the + * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot + * is known to be involved). + */ + + /* + * Hand the error off to the handler registered + * for the slot that should have decoded the error, + * or to generic PCI handling (if pciio decides that + * such is appropriate). + */ + retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); + + if (retval != IOERROR_HANDLED) { + + /* Generate a generic message for IOERROR_UNHANDLED + * since the subsidiary handlers were silent, and + * did no recovery. + */ + if (retval == IOERROR_UNHANDLED) { + retval = IOERROR_PANIC; + + /* we may or may not want to print some of this, + * depending on debug level and which error code. + */ + + printk(KERN_ALERT + "PIO Error on PCI Bus %s", + pcibr_soft->bs_name); + /* this decodes part of the ioe; our caller + * will dump the raw details in DEBUG and + * kdebug kernels. + */ + BEM_ADD_IOE(ioe); + } +#if defined(FORCE_ERRORS) + if (0) { +#elif !DEBUG + if (kdebug) { +#endif + /* + * Dump raw data from Bridge/PCI layer. + */ + + BEM_ADD_STR("Raw info from Bridge/PCI layer:\n"); + if (bridge->b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) + pcibr_error_dump(pcibr_soft); + BEM_ADD_SPC(raw_space); + BEM_ADD_VAR(raw_paddr); + if (IOERROR_FIELDVALID(ioe, widgetdev)) { + + slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, + widgetdev)); + func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, + widgetdev)); + if (slot < 8) { + bridgereg_t device = bridge->b_device[slot].reg; + + BEM_ADD_VAR(slot); + BEM_ADD_VAR(func); + BEM_ADD_REG(device); + } + } +#if !DEBUG || defined(FORCE_ERRORS) + } +#endif + + /* + * Since error could not be handled at lower level, + * error data logged has not been cleared. + * Clean up errors, and + * re-enable bridge to interrupt on error conditions. + * NOTE: Wheather we get the interrupt on PCI_ABORT or not is + * dependent on INT_ENABLE register. This write just makes sure + * that if the interrupt was enabled, we do get the interrupt. + * + * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges + * a group of interrupts. If while handling this error, + * some other error has occured, that would be + * implicitly cleared by this write. + * Need a way to ensure we don't inadvertently clear some + * other errors. + */ + if (IOERROR_FIELDVALID(ioe, widgetdev)) + pcibr_device_disable(pcibr_soft, + pciio_widgetdev_slot_get( + IOERROR_GETVALUE(ioe, widgetdev))); + + if (mode == MODE_DEVUSERERROR) + pcibr_error_cleanup(pcibr_soft, error_code); + } + return retval; +} + +/* + * bridge_dmaerror + * Some error was identified in a DMA transaction. + * This routine will identify the that caused the error, + * and try to invoke the appropriate bus service to handle this. + */ + +#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT) + +int +pcibr_dmard_error( + pcibr_soft_t pcibr_soft, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioe) +{ + devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t bus_lowaddr, bus_uppraddr; + int retval = 0; + int bufnum; + + /* + * In case of DMA errors, bridge should have logged the + * address that caused the error. + * Look up the address, in the bridge error registers, and + * take appropriate action + */ + ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid); + ASSERT(bridge); + + /* + * read error log registers + */ + bus_lowaddr = bridge->b_wid_resp_lower; + bus_uppraddr = bridge->b_wid_resp_upper; + + bufnum = BRIDGE_RESP_ERRUPPR_BUFNUM(bus_uppraddr); + IOERROR_SETVALUE(ioe, widgetdev, + pciio_widgetdev_create( + BRIDGE_RESP_ERRUPPR_DEVICE(bus_uppraddr), + 0)); + IOERROR_SETVALUE(ioe, busaddr, + (bus_lowaddr | + ((iopaddr_t) + (bus_uppraddr & + BRIDGE_ERRUPPR_ADDRMASK) << 32))); + + /* + * need to ensure that the xtalk adress in ioe + * maps to PCI error address read from bridge. + * How to convert PCI address back to Xtalk address ? + * (better idea: convert XTalk address to PCI address + * and then do the compare!) + */ + + retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); + if (retval != IOERROR_HANDLED) + pcibr_device_disable(pcibr_soft, + pciio_widgetdev_slot_get( + IOERROR_GETVALUE(ioe,widgetdev))); + + /* + * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR + * NOTE: Wheather we get the interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR or + * not is dependent on INT_ENABLE register. This write just makes sure + * that if the interrupt was enabled, we do get the interrupt. + */ + bridge->b_int_rst_stat = BRIDGE_IRR_RESP_BUF_GRP_CLR; + + /* + * Also, release the "bufnum" back to buffer pool that could be re-used. + * This is done by "disabling" the buffer for a moment, then restoring + * the original assignment. + */ + + { + reg_p regp; + bridgereg_t regv; + bridgereg_t mask; + + regp = (bufnum & 1) + ? &bridge->b_odd_resp + : &bridge->b_even_resp; + + mask = 0xF << ((bufnum >> 1) * 4); + + regv = *regp; + *regp = regv & ~mask; + *regp = regv; + } + + return retval; +} + +/* + * pcibr_dmawr_error: + * Handle a dma write error caused by a device attached to this bridge. + * + * ioe has the widgetnum, widgetdev, and memaddr fields updated + * But we don't know the PCI address that corresponds to "memaddr" + * nor do we know which device driver is generating this address. + * + * There is no easy way to find out the PCI address(es) that map + * to a specific system memory address. Bus handling code is also + * of not much help, since they don't keep track of the DMA mapping + * that have been handed out. + * So it's a dead-end at this time. + * + * If translation is available, we could invoke the error handling + * interface of the device driver. + */ +/*ARGSUSED */ +int +pcibr_dmawr_error( + pcibr_soft_t pcibr_soft, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioe) +{ + devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + int retval; + + retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); + + if (retval != IOERROR_HANDLED) { + pcibr_device_disable(pcibr_soft, + pciio_widgetdev_slot_get( + IOERROR_GETVALUE(ioe, widgetdev))); + + } + return retval; +} + +/* + * Bridge error handler. + * Interface to handle all errors that involve bridge in some way. + * + * This normally gets called from xtalk error handler. + * ioe has different set of fields set depending on the error that + * was encountered. So, we have a bit field indicating which of the + * fields are valid. + * + * NOTE: This routine could be operating in interrupt context. So, + * don't try to sleep here (till interrupt threads work!!) + */ +int +pcibr_error_handler( + error_handler_arg_t einfo, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioe) +{ + pcibr_soft_t pcibr_soft; + int retval = IOERROR_BADERRORCODE; + +#ifdef EHE_ENABLE + devfs_handle_t xconn_vhdl,pcibr_vhdl; + error_state_t e_state; +#endif /* EHE_ENABLE */ + + pcibr_soft = (pcibr_soft_t) einfo; + +#ifdef EHE_ENABLE + xconn_vhdl = pcibr_soft->bs_conn; + pcibr_vhdl = pcibr_soft->bs_vhdl; + + e_state = error_state_get(xconn_vhdl); + + if (error_state_set(pcibr_vhdl, e_state) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); + + /* If we are in the action handling phase clean out the error state + * on the xswitch. + */ + if (e_state == ERROR_STATE_ACTION) + (void)error_state_set(xconn_vhdl, ERROR_STATE_NONE); +#endif /* EHE_ENABLE */ + +#if DEBUG && ERROR_DEBUG + printk("%s: pcibr_error_handler\n", pcibr_soft->bs_name); +#endif + + ASSERT(pcibr_soft != NULL); + + if (error_code & IOECODE_PIO) + retval = pcibr_pioerror(pcibr_soft, error_code, mode, ioe); + + if (error_code & IOECODE_DMA) { + if (error_code & IOECODE_READ) { + /* + * DMA read error occurs when a device attached to the bridge + * tries to read some data from system memory, and this + * either results in a timeout or access error. + * First case is indicated by the bit "XREAD_REQ_TOUT" + * and second case by "RESP_XTALK_ERROR" bit in bridge error + * interrupt status register. + * + * pcibr_error_intr_handler would get invoked first, and it has + * the responsibility of calling pcibr_error_handler with + * suitable parameters. + */ + + retval = pcibr_dmard_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); + } + if (error_code & IOECODE_WRITE) { + /* + * A device attached to this bridge has been generating + * bad DMA writes. Find out the device attached, and + * slap on it's wrist. + */ + + retval = pcibr_dmawr_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); + } + } + return retval; + +} + +/* + * Reenable a device after handling the error. + * This is called by the lower layers when they wish to be reenabled + * after an error. + * Note that each layer would be calling the previous layer to reenable + * first, before going ahead with their own re-enabling. + */ + +int +pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + ASSERT(error_code & IOECODE_PIO); + + /* If the error is not known to be a write, + * we have to call devenable. + * write errors are isolated to the bridge. + */ + if (!(error_code & IOECODE_WRITE)) { + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + int rc; + + rc = xtalk_error_devenable(xconn_vhdl, pciio_slot, error_code); + if (rc != IOERROR_HANDLED) + return rc; + } + pcibr_error_cleanup(pcibr_soft, error_code); + return IOERROR_HANDLED; +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,204 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); +void pcibr_hints_fix_rrbs(devfs_handle_t); +void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); +void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); +void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); +void pcibr_hints_handsoff(devfs_handle_t); +void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); + +pcibr_hints_t +pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) +{ + arbitrary_info_t ainfo = 0; + graph_error_t rv; + pcibr_hints_t hint; + + rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); + + if (alloc && (rv != GRAPH_SUCCESS)) { + + NEW(hint); + hint->rrb_alloc_funct = NULL; + hint->ph_intr_bits = NULL; + rv = hwgraph_info_add_LBL(xconn_vhdl, + INFO_LBL_PCIBR_HINTS, + (arbitrary_info_t) hint); + if (rv != GRAPH_SUCCESS) + goto abnormal_exit; + + rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); + + if (rv != GRAPH_SUCCESS) + goto abnormal_exit; + + if (ainfo != (arbitrary_info_t) hint) + goto abnormal_exit; + } + return (pcibr_hints_t) ainfo; + +abnormal_exit: +#ifdef LATER + printf("SHOULD NOT BE HERE\n"); +#endif + DEL(hint); + return(NULL); + +} + +void +pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_rrb_fixed = mask; +#if DEBUG + else + printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) +{ + pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); +} + +void +pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, + pciio_slot_t host, + pciio_slot_t guest) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_host_slot[guest] = host + 1; +#if DEBUG + else + printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, + pcibr_intr_bits_f *xxx_intr_bits) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_intr_bits = xxx_intr_bits; +#if DEBUG + else + printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->rrb_alloc_funct = rrb_alloc_funct; +} + +void +pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) +{ + pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); + + if (hint) + hint->ph_hands_off = 1; +#if DEBUG + else + printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" + "\t%p\n", xconn_vhdl); +#endif +} + +void +pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, + pciio_slot_t slot, + uint64_t subdevs) +{ + arbitrary_info_t ainfo = 0; + char sdname[16]; + devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; + + sprintf(sdname, "pci/%d", slot); + (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); + if (pconn_vhdl == GRAPH_VERTEX_NONE) { +#if DEBUG + printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" + "\t%p (seeking %s)\n", xconn_vhdl, sdname); +#endif + return; + } + hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); + if (ainfo == 0) { + uint64_t *subdevp; + + NEW(subdevp); + if (!subdevp) { +#if DEBUG + printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" + "\t%p\n", pconn_vhdl); +#endif + return; + } + *subdevp = subdevs; + hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); + hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); + if (ainfo == (arbitrary_info_t) subdevp) + return; + DEL(subdevp); + if (ainfo == (arbitrary_info_t) NULL) { +#if DEBUG + printk("pcibr_hints_subdevs: null subdevs ptr at\n" + "\t%p\n", pconn_vhdl); +#endif + return; + } +#if DEBUG + printk("pcibr_subdevs_get: dup subdev add_LBL at\n" + "\t%p\n", pconn_vhdl); +#endif + } + *(uint64_t *) ainfo = subdevs; +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,147 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LATER + +char *pci_space[] = {"NONE", + "ROM", + "IO", + "", + "MEM", + "MEM32", + "MEM64", + "CFG", + "WIN0", + "WIN1", + "WIN2", + "WIN3", + "WIN4", + "WIN5", + "", + "BAD"}; + +void +idbg_pss_func(pcibr_info_h pcibr_infoh, int func) +{ + pcibr_info_t pcibr_info = pcibr_infoh[func]; + char name[MAXDEVNAME]; + int win; + + if (!pcibr_info) + return; + qprintf("Per-slot Function Info\n"); + sprintf(name, "%v", pcibr_info->f_vertex); + qprintf("\tSlot Name : %s\n",name); + qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); + qprintf("Slot : %d ", pcibr_info->f_slot); + qprintf("Function : %d ", pcibr_info->f_func); + qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); + qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); + sprintf(name, "%v", pcibr_info->f_master); + qprintf("\tBus provider : %s\n",name); + qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); + qprintf("Error Handler : 0x%x Arg 0x%x\n", + pcibr_info->f_efunc,pcibr_info->f_einfo); + for(win = 0 ; win < 6 ; win++) + qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", + win,pci_space[pcibr_info->f_window[win].w_space], + pcibr_info->f_window[win].w_base, + pcibr_info->f_window[win].w_size); + + qprintf("\tRom base 0x%x size 0x%x\n", + pcibr_info->f_rbase,pcibr_info->f_rsize); + + qprintf("\tInterrupt Bit Map\n"); + qprintf("\t\tPCI Int#\tBridge Pin#\n"); + for (win = 0 ; win < 4; win++) + qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); + qprintf("\n"); +} + + +void +idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) +{ + pcibr_soft_slot_t pss; + char slot_conn_name[MAXDEVNAME]; + int func; + + pss = &pcibr_soft->bs_slot[slot]; + qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); + qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); + qprintf("\tHost Slot : %d\n",pss->host_slot); + sprintf(slot_conn_name, "%v", pss->slot_conn); + qprintf("\tSlot Conn : %s\n",slot_conn_name); + qprintf("\t#Functions : %d\n",pss->bss_ninfo); + for (func = 0; func < pss->bss_ninfo; func++) + idbg_pss_func(pss->bss_infos,func); + qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); + qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); + qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); + qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", + pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); + + qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" + "d32_base 0x%x d32_flags 0x%x\n", + pss->bss_d64_base, pss->bss_d64_flags, + pss->bss_d32_base, pss->bss_d32_flags); + + qprintf("\tExt ATEs active ? %s", + pss->bss_ext_ates_active ? "yes" : "no"); + qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); + qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); + + qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", + pcibr_soft->bs_rrb_valid[slot], + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + +} + +int ips = 0; + +void +idbg_pss(pcibr_soft_t pcibr_soft) +{ + pciio_slot_t slot; + + + if (ips >= 0 && ips < 8) + idbg_pss_info(pcibr_soft,ips); + else if (ips < 0) + for (slot = 0; slot < 8; slot++) + idbg_pss_info(pcibr_soft,slot); + else + qprintf("Invalid ips %d\n",ips); +} +#endif /* LATER */ diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,907 @@ +/* + * + * 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) 2001 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); +pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +void pcibr_intr_free(pcibr_intr_t); +void pcibr_setpciint(xtalk_intr_t); +int pcibr_intr_connect(pcibr_intr_t); +void pcibr_intr_disconnect(pcibr_intr_t); + +devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); +void pcibr_intr_func(intr_arg_t); + +extern pcibr_info_t pcibr_info_get(devfs_handle_t); + +/* ===================================================================== + * INTERRUPT MANAGEMENT + */ + +unsigned +pcibr_intr_bits(pciio_info_t info, + pciio_intr_line_t lines) +{ + pciio_slot_t slot = pciio_info_slot_get(info); + unsigned bbits = 0; + + /* + * Currently favored mapping from PCI + * slot number and INTA/B/C/D to Bridge + * PCI Interrupt Bit Number: + * + * SLOT A B C D + * 0 0 4 0 4 + * 1 1 5 1 5 + * 2 2 6 2 6 + * 3 3 7 3 7 + * 4 4 0 4 0 + * 5 5 1 5 1 + * 6 6 2 6 2 + * 7 7 3 7 3 + */ + + if (slot < 8) { + if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) + bbits |= 1 << slot; + if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) + bbits |= 1 << (slot ^ 4); + } + return bbits; +} + + +/* + * Get the next wrapper pointer queued in the interrupt circular buffer. + */ +pcibr_intr_wrap_t +pcibr_wrap_get(pcibr_intr_cbuf_t cbuf) +{ + pcibr_intr_wrap_t wrap; + + if (cbuf->ib_in == cbuf->ib_out) + PRINT_PANIC( "pcibr intr circular buffer empty, cbuf=0x%p, ib_in=ib_out=%d\n", + (void *)cbuf, cbuf->ib_out); + + wrap = cbuf->ib_cbuf[cbuf->ib_out++]; + cbuf->ib_out = cbuf->ib_out % IBUFSIZE; + return(wrap); +} + +/* + * Queue a wrapper pointer in the interrupt circular buffer. + */ +void +pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) +{ + int in; + int s; + + /* + * Multiple CPUs could be executing this code simultaneously + * if a handler has registered multiple interrupt lines and + * the interrupts are directed to different CPUs. + */ + s = mutex_spinlock(&cbuf->ib_lock); + in = (cbuf->ib_in + 1) % IBUFSIZE; + if (in == cbuf->ib_out) + PRINT_PANIC( "pcibr intr circular buffer full, cbuf=0x%p, ib_in=%d\n", + (void *)cbuf, cbuf->ib_in); + + cbuf->ib_cbuf[cbuf->ib_in] = wrap; + cbuf->ib_in = in; + mutex_spinunlock(&cbuf->ib_lock, s); + return; +} + +/* + * There are end cases where a deadlock can occur if interrupt + * processing completes and the Bridge b_int_status bit is still set. + * + * One scenerio is if a second PCI interrupt occurs within 60ns of + * the previous interrupt being cleared. In this case the Bridge + * does not detect the transition, the Bridge b_int_status bit + * remains set, and because no transition was detected no interrupt + * packet is sent to the Hub/Heart. + * + * A second scenerio is possible when a b_int_status bit is being + * shared by multiple devices: + * Device #1 generates interrupt + * Bridge b_int_status bit set + * Device #2 generates interrupt + * interrupt processing begins + * ISR for device #1 runs and + * clears interrupt + * Device #1 generates interrupt + * ISR for device #2 runs and + * clears interrupt + * (b_int_status bit still set) + * interrupt processing completes + * + * Interrupt processing is now complete, but an interrupt is still + * outstanding for Device #1. But because there was no transition of + * the b_int_status bit, no interrupt packet will be generated and + * a deadlock will occur. + * + * To avoid these deadlock situations, this function is used + * to check if a specific Bridge b_int_status bit is set, and if so, + * cause the setting of the corresponding interrupt bit. + * + * On a XBridge (IP35), we do this by writing the appropriate Bridge Force + * Interrupt register. + */ +void +pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +{ + unsigned bit; + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); + + bit = wrap->iw_intr; + + if (pcibr_soft->bs_xbridge) { + bridge->b_force_pin[bit].intr = 1; + } else if ((1 << bit) & *wrap->iw_stat) { + cpuid_t cpu; + unsigned intr_bit; + xtalk_intr_t xtalk_intr = + pcibr_soft->bs_intr[bit].bsi_xtalk_intr; + + intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); + cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); +#if defined(CONFIG_IA64_SGI_SN1) + REMOTE_CPU_SEND_INTR(cpu, intr_bit); +#endif + } +} + +/*ARGSUSED */ +pcibr_intr_t +pcibr_intr_alloc(devfs_handle_t pconn_vhdl, + device_desc_t dev_desc, + pciio_intr_line_t lines, + devfs_handle_t owner_dev) +{ + pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pcibr_info->f_slot; + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; + devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + bridge_t *bridge = pcibr_soft->bs_base; + int is_threaded = 0; + int thread_swlevel; + + xtalk_intr_t *xtalk_intr_p; + pcibr_intr_t *pcibr_intr_p; + pcibr_intr_list_t *intr_list_p; + + unsigned pcibr_int_bits; + unsigned pcibr_int_bit; + xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; + hub_intr_t hub_intr; + pcibr_intr_t pcibr_intr; + pcibr_intr_list_t intr_entry; + pcibr_intr_list_t intr_list; + bridgereg_t int_dev; + +#if DEBUG && INTR_DEBUG + printk("%v: pcibr_intr_alloc\n" + "%v:%s%s%s%s%s\n", + owner_dev, pconn_vhdl, + !(lines & 15) ? " No INTs?" : "", + lines & 1 ? " INTA" : "", + lines & 2 ? " INTB" : "", + lines & 4 ? " INTC" : "", + lines & 8 ? " INTD" : ""); +#endif + + NEW(pcibr_intr); + if (!pcibr_intr) + return NULL; + + if (dev_desc) { + cpuid_t intr_target_from_desc(device_desc_t, int); + } else { + extern int default_intr_pri; + + is_threaded = 1; /* PCI interrupts are threaded, by default */ + thread_swlevel = default_intr_pri; + } + + pcibr_intr->bi_dev = pconn_vhdl; + pcibr_intr->bi_lines = lines; + pcibr_intr->bi_soft = pcibr_soft; + pcibr_intr->bi_ibits = 0; /* bits will be added below */ + pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; + pcibr_intr->bi_mustruncpu = CPU_NONE; + pcibr_intr->bi_ibuf.ib_in = 0; + pcibr_intr->bi_ibuf.ib_out = 0; + mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); + + pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); + + + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and make sure there are xtalk resources + * allocated for it. + */ +#if DEBUG && INTR_DEBUG + printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); +#endif + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + xtalk_intr = *xtalk_intr_p; + + if (xtalk_intr == NULL) { + /* + * This xtalk_intr_alloc is constrained for two reasons: + * 1) Normal interrupts and error interrupts need to be delivered + * through a single xtalk target widget so that there aren't any + * ordering problems with DMA, completion interrupts, and error + * interrupts. (Use of xconn_vhdl forces this.) + * + * 2) On IP35, addressing constraints on IP35 and Bridge force + * us to use a single PI number for all interrupts from a + * single Bridge. (IP35-specific code forces this, and we + * verify in pcibr_setwidint.) + */ + + /* + * All code dealing with threaded PCI interrupt handlers + * is located at the pcibr level. Because of this, + * we always want the lower layers (hub/heart_intr_alloc, + * intr_level_connect) to treat us as non-threaded so we + * don't set up a duplicate threaded environment. We make + * this happen by calling a special xtalk interface. + */ + xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, + owner_dev); +#if DEBUG && INTR_DEBUG + printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); +#endif + + /* both an assert and a runtime check on this: + * we need to check in non-DEBUG kernels, and + * the ASSERT gets us more information when + * we use DEBUG kernels. + */ + ASSERT(xtalk_intr != NULL); + if (xtalk_intr == NULL) { + /* it is quite possible that our + * xtalk_intr_alloc failed because + * someone else got there first, + * and we can find their results + * in xtalk_intr_p. + */ + if (!*xtalk_intr_p) { +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_ALERT + "pcibr_intr_alloc %v: unable to get xtalk interrupt resources", + xconn_vhdl); +#else + printk(KERN_ALERT + "pcibr_intr_alloc 0x%p: unable to get xtalk interrupt resources", + (void *)xconn_vhdl); +#endif + /* yes, we leak resources here. */ + return 0; + } + } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { + /* + * now tell the bridge which slot is + * using this interrupt line. + */ + int_dev = bridge->b_int_device; + int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); + int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); + bridge->b_int_device = int_dev; /* XXXMP */ + +#if DEBUG && INTR_DEBUG + printk("%v: bridge intr bit %d clears my wrb\n", + pconn_vhdl, pcibr_int_bit); +#endif + } else { + /* someone else got one allocated first; + * free the one we just created, and + * retrieve the one they allocated. + */ + xtalk_intr_free(xtalk_intr); + xtalk_intr = *xtalk_intr_p; +#if PARANOID + /* once xtalk_intr is set, we never clear it, + * so if the CAS fails above, this condition + * can "never happen" ... + */ + if (!xtalk_intr) { + printk(KERN_ALERT + "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", + xconn_vhdl); + /* yes, we leak resources here. */ + return 0; + } +#endif + } + } + + pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; + + NEW(intr_entry); + intr_entry->il_next = NULL; + intr_entry->il_intr = pcibr_intr; + intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); + intr_list_p = + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; +#if DEBUG && INTR_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("0x%x: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#else + printk("%v: Bridge bit %d wrap=0x%x\n", + pconn_vhdl, pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); +#endif +#endif + + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* we are the first interrupt on this bridge bit. + */ +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + intr_list = *intr_list_p; + pcibr_intr_p = &intr_list->il_intr; + if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { + /* first entry on list was erased, + * and we replaced it, so we + * don't need our intr_entry. + */ + DEL(intr_entry); +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + intr_list_p = &intr_list->il_next; + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* we are the new second interrupt on this bit. + */ + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + continue; + } + while (1) { + pcibr_intr_p = &intr_list->il_intr; + if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { + /* an entry on list was erased, + * and we replaced it, so we + * don't need our intr_entry. + */ + DEL(intr_entry); +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + break; + } + intr_list_p = &intr_list->il_next; + if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { + /* entry appended to share list + */ +#if DEBUG && INTR_DEBUG + printk("%v INT 0x%x (bridge bit %d) is new Nth\n", + pconn_vhdl, pcibr_int_bits, pcibr_int_bit); +#endif + break; + } + /* step to next record in chain + */ + intr_list = *intr_list_p; + } + } + } + +#if DEBUG && INTR_DEBUG + printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); +#endif + hub_intr = (hub_intr_t)xtalk_intr; + pcibr_intr->bi_irq = hub_intr->i_bit; + pcibr_intr->bi_cpu = hub_intr->i_cpuid; + return pcibr_intr; +} + +/*ARGSUSED */ +void +pcibr_intr_free(pcibr_intr_t pcibr_intr) +{ + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + unsigned pcibr_int_bit; + pcibr_intr_list_t intr_list; + int intr_shared; + xtalk_intr_t *xtalk_intrp; + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + for (intr_list = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; + intr_list != NULL; + intr_list = intr_list->il_next) + if (compare_and_swap_ptr((void **) &intr_list->il_intr, + pcibr_intr, + NULL)) { +#if DEBUG && INTR_DEBUG + printk("%s: cleared a handler from bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif + } + /* If this interrupt line is not being shared between multiple + * devices release the xtalk interrupt resources. + */ + intr_shared = + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; + xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + if ((!intr_shared) && (*xtalk_intrp)) { + + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t int_dev; + + xtalk_intr_free(*xtalk_intrp); + *xtalk_intrp = 0; + + /* Clear the PCI device interrupt to bridge interrupt pin + * mapping. + */ + int_dev = bridge->b_int_device; + int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); + bridge->b_int_device = int_dev; + + } + } + } + DEL(pcibr_intr); +} + +void +pcibr_setpciint(xtalk_intr_t xtalk_intr) +{ + iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); + xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); + bridgereg_t *int_addr = (bridgereg_t *) + xtalk_intr_sfarg_get(xtalk_intr); + + *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | + (BRIDGE_INT_ADDR_FLD & vect)); +} + +/*ARGSUSED */ +int +pcibr_intr_connect(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + bridge_t *bridge = pcibr_soft->bs_base; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + bridgereg_t b_int_enable; + unsigned long s; + + if (pcibr_intr == NULL) + return -1; + +#if DEBUG && INTR_DEBUG + printk("%v: pcibr_intr_connect\n", + pcibr_intr->bi_dev); +#endif + + *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; + + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and make sure there are xtalk resources + * allocated for it. + */ + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + xtalk_intr_t xtalk_intr; + + xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + + /* + * If this interrupt line is being shared and the connect has + * already been done, no need to do it again. + */ + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) + continue; + + + /* + * Use the pcibr wrapper function to handle all Bridge interrupts + * regardless of whether the interrupt line is shared or not. + */ + xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint, + (void *)&(bridge->b_int_addr[pcibr_int_bit].addr)); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; + +#if DEBUG && INTR_DEBUG + printk("%v bridge bit %d wrapper connected\n", + pcibr_intr->bi_dev, pcibr_int_bit); +#endif + } + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable |= pcibr_int_bits; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + + return 0; +} + +/*ARGSUSED */ +void +pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + bridge_t *bridge = pcibr_soft->bs_base; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + bridgereg_t b_int_enable; + unsigned long s; + + /* Stop calling the function. Now. + */ + *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; + + /* + * For each PCI interrupt line requested, figure + * out which Bridge PCI Interrupt Line it maps + * to, and disconnect the interrupt. + */ + + /* don't disable interrupts for lines that + * are shared between devices. + */ + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if ((pcibr_int_bits & (1 << pcibr_int_bit)) && + (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) + pcibr_int_bits &= ~(1 << pcibr_int_bit); + if (!pcibr_int_bits) + return; + + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable &= ~pcibr_int_bits; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) { + /* if the interrupt line is now shared, + * do not disconnect it. + */ + if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) + continue; + + xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; + +#if DEBUG && INTR_DEBUG + printk("%s: xtalk disconnect done for Bridge bit %d\n", + pcibr_soft->bs_name, pcibr_int_bit); +#endif + + /* if we are sharing the interrupt line, + * connect us up; this closes the hole + * where the another pcibr_intr_alloc() + * was in progress as we disconnected. + */ + if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) + continue; + + xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, + (xtalk_intr_setfunc_t)pcibr_setpciint, + (void *) &(bridge->b_int_addr[pcibr_int_bit].addr)); + } +} + +/*ARGSUSED */ +devfs_handle_t +pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) +{ + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + unsigned pcibr_int_bits = pcibr_intr->bi_ibits; + unsigned pcibr_int_bit; + + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) + if (pcibr_int_bits & (1 << pcibr_int_bit)) + return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); + return 0; +} + +/* ===================================================================== + * INTERRUPT HANDLING + */ +void +pcibr_clearwidint(bridge_t *bridge) +{ + bridge->b_wid_int_upper = 0; + bridge->b_wid_int_lower = 0; +} + + +void +pcibr_setwidint(xtalk_intr_t intr) +{ + xwidgetnum_t targ = xtalk_intr_target_get(intr); + iopaddr_t addr = xtalk_intr_addr_get(intr); + xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); + widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; + widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; + + bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); + + NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + + OLD_b_wid_int_upper = bridge->b_wid_int_upper; + OLD_b_wid_int_lower = bridge->b_wid_int_lower; + + /* Verify that all interrupts from this Bridge are using a single PI */ + if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { + /* + * Once set, these registers shouldn't change; they should + * be set multiple times with the same values. + * + * If we're attempting to change these registers, it means + * that our heuristics for allocating interrupts in a way + * appropriate for IP35 have failed, and the admin needs to + * explicitly direct some interrupts (or we need to make the + * heuristics more clever). + * + * In practice, we hope this doesn't happen very often, if + * at all. + */ + if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || + (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { + printk(KERN_WARNING "Interrupt allocation is too complex.\n"); + printk(KERN_WARNING "Use explicit administrative interrupt targetting.\n"); + printk(KERN_WARNING "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); + printk(KERN_WARNING "NEW=0x%x/0x%x OLD=0x%x/0x%x\n", + NEW_b_wid_int_upper, NEW_b_wid_int_lower, + OLD_b_wid_int_upper, OLD_b_wid_int_lower); + PRINT_PANIC("PCI Bridge interrupt targetting error\n"); + } + } + + bridge->b_wid_int_upper = NEW_b_wid_int_upper; + bridge->b_wid_int_lower = NEW_b_wid_int_lower; + bridge->b_int_host_err = vect; +} + +/* + * pcibr_intr_preset: called during mlreset time + * if the platform specific code needs to route + * one of the Bridge's xtalk interrupts before the + * xtalk infrastructure is available. + */ +void +pcibr_xintr_preset(void *which_widget, + int which_widget_intr, + xwidgetnum_t targ, + iopaddr_t addr, + xtalk_intr_vector_t vect) +{ + bridge_t *bridge = (bridge_t *) which_widget; + + if (which_widget_intr == -1) { + /* bridge widget error interrupt */ + bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + bridge->b_int_host_err = vect; + + /* turn on all interrupts except + * the PCI interrupt requests, + * at least at heart. + */ + bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; + + } else { + /* routing a PCI device interrupt. + * targ and low 38 bits of addr must + * be the same as the already set + * value for the widget error interrupt. + */ + bridge->b_int_addr[which_widget_intr].addr = + ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | + (BRIDGE_INT_ADDR_FLD & vect)); + /* + * now bridge can let it through; + * NB: still should be blocked at + * xtalk provider end, until the service + * function is set. + */ + bridge->b_int_enable |= 1 << vect; + } + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ +} + + +/* + * pcibr_intr_func() + * + * This is the pcibr interrupt "wrapper" function that is called, + * in interrupt context, to initiate the interrupt handler(s) registered + * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded + * handlers will be called directly, and threaded handlers will have their + * thread woken up. + */ +void +pcibr_intr_func(intr_arg_t arg) +{ + pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; + reg_p wrbf; + pcibr_intr_t intr; + pcibr_intr_list_t list; + int clearit; + int do_nonthreaded = 1; + int is_threaded = 0; + int x = 0; + + /* + * If any handler is still running from a previous interrupt + * just return. If there's a need to call the handler(s) again, + * another interrupt will be generated either by the device or by + * pcibr_force_interrupt(). + */ + + if (wrap->iw_hdlrcnt) { + return; + } + + /* + * Call all interrupt handlers registered. + * First, the pcibr_intrd threads for any threaded handlers will be + * awoken, then any non-threaded handlers will be called sequentially. + */ + + clearit = 1; + while (do_nonthreaded) { + for (list = wrap->iw_list; list != NULL; list = list->il_next) { + if ((intr = list->il_intr) && + (intr->bi_flags & PCIIO_INTR_CONNECTED)) { + + /* + * This device may have initiated write + * requests since the bridge last saw + * an edge on this interrupt input; flushing + * the buffer prior to invoking the handler + * should help but may not be sufficient if we + * get more requests after the flush, followed + * by the card deciding it wants service, before + * the interrupt handler checks to see if things need + * to be done. + * + * There is a similar race condition if + * an interrupt handler loops around and + * notices further service is required. + * Perhaps we need to have an explicit + * call that interrupt handlers need to + * do between noticing that DMA to memory + * has completed, but before observing the + * contents of memory? + */ + + if ((do_nonthreaded) && (!is_threaded)) { + /* Non-threaded. + * Call the interrupt handler at interrupt level + */ + + /* Only need to flush write buffers if sharing */ + + if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { + if ((x = *wrbf)) /* write request buffer flush */ +#ifdef SUPPORT_PRINTING_V_FORMAT + printk(KERN_ALERT "pcibr_intr_func %v: \n" + "write buffer flush failed, wrbf=0x%x\n", + list->il_intr->bi_dev, wrbf); +#else + printk(KERN_ALERT "pcibr_intr_func %p: \n" + "write buffer flush failed, wrbf=0x%lx\n", + (void *)list->il_intr->bi_dev, (long) wrbf); +#endif + } + } + + clearit = 0; + } + } + + do_nonthreaded = 0; + /* + * If the non-threaded handler was the last to complete, + * (i.e., no threaded handlers still running) force an + * interrupt to avoid a potential deadlock situation. + */ + if (wrap->iw_hdlrcnt == 0) { + pcibr_force_interrupt(wrap); + } + } + + /* If there were no handlers, + * disable the interrupt and return. + * It will get enabled again after + * a handler is connected. + * If we don't do this, we would + * sit here and spin through the + * list forever. + */ + if (clearit) { + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + bridgereg_t b_int_enable; + bridgereg_t mask = 1 << wrap->iw_intr; + unsigned long s; + + s = pcibr_lock(pcibr_soft); + b_int_enable = bridge->b_int_enable; + b_int_enable &= ~mask; + bridge->b_int_enable = b_int_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); + return; + } +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,896 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void do_pcibr_rrb_clear(bridge_t *, int); +void do_pcibr_rrb_flush(bridge_t *, int); +int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); +int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); +int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); +int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); + +void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); + +int pcibr_wrb_flush(devfs_handle_t); +int pcibr_rrb_alloc(devfs_handle_t, int *, int *); +int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); +int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); +void pcibr_rrb_flush(devfs_handle_t); +int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); + +/* + * RRB Management + */ + +#define LSBIT(word) ((word) &~ ((word)-1)) + +void +do_pcibr_rrb_clear(bridge_t *bridge, int rrb) +{ + bridgereg_t status; + + /* bridge_lock must be held; + * this RRB must be disabled. + */ + + /* wait until RRB has no outstanduing XIO packets. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + } +} + +void +do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) +{ + reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; + bridgereg_t rrbv; + int shft = 4 * (rrbn >> 1); + unsigned ebit = BRIDGE_RRB_EN << shft; + + rrbv = *rrbp; + if (rrbv & ebit) + *rrbp = rrbv & ~ebit; + + do_pcibr_rrb_clear(bridge, rrbn); + + if (rrbv & ebit) + *rrbp = rrbv; +} + +/* + * pcibr_rrb_count_valid: count how many RRBs are + * marked valid for the specified PCI slot on this + * bridge. + * + * NOTE: The "slot" parameter for all pcibr_rrb + * management routines must include the "virtual" + * bit; when manageing both the normal and the + * virtual channel, separate calls to these + * routines must be made. To denote the virtual + * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot + * number. + * + * IMPL NOTE: The obvious algorithm is to iterate + * through the RRB fields, incrementing a count if + * the RRB is valid and matches the slot. However, + * it is much simpler to use an algorithm derived + * from the "partitioned add" idea. First, XOR in a + * pattern such that the fields that match this + * slot come up "all ones" and all other fields + * have zeros in the mismatching bits. Then AND + * together the bits in the field, so we end up + * with one bit turned on for each field that + * matched. Now we need to count these bits. This + * can be done either with a series of shift/add + * instructions or by using "tmp % 15"; I expect + * that the cascaded shift/add will be faster. + */ + +int +do_pcibr_rrb_count_valid(bridge_t *bridge, + pciio_slot_t slot) +{ + bridgereg_t tmp; + + tmp = bridge->b_rrb_map[slot & 1].reg; + tmp ^= 0x11111111 * (7 - slot / 2); + tmp &= (0xCCCCCCCC & tmp) >> 2; + tmp &= (0x22222222 & tmp) >> 1; + tmp += tmp >> 4; + tmp += tmp >> 8; + tmp += tmp >> 16; + return tmp & 15; +} + +/* + * do_pcibr_rrb_count_avail: count how many RRBs are + * available to be allocated for the specified slot. + * + * IMPL NOTE: similar to the above, except we are + * just counting how many fields have the valid bit + * turned off. + */ +int +do_pcibr_rrb_count_avail(bridge_t *bridge, + pciio_slot_t slot) +{ + bridgereg_t tmp; + + tmp = bridge->b_rrb_map[slot & 1].reg; + tmp = (0x88888888 & ~tmp) >> 3; + tmp += tmp >> 4; + tmp += tmp >> 8; + tmp += tmp >> 16; + return tmp & 15; +} + +/* + * do_pcibr_rrb_alloc: allocate some additional RRBs + * for the specified slot. Returns -1 if there were + * insufficient free RRBs to satisfy the request, + * or 0 if the request was fulfilled. + * + * Note that if a request can be partially filled, + * it will be, even if we return failure. + * + * IMPL NOTE: again we avoid iterating across all + * the RRBs; instead, we form up a word containing + * one bit for each free RRB, then peel the bits + * off from the low end. + */ +int +do_pcibr_rrb_alloc(bridge_t *bridge, + pciio_slot_t slot, + int more) +{ + int rv = 0; + bridgereg_t reg, tmp, bit; + + reg = bridge->b_rrb_map[slot & 1].reg; + tmp = (0x88888888 & ~reg) >> 3; + while (more-- > 0) { + bit = LSBIT(tmp); + if (!bit) { + rv = -1; + break; + } + tmp &= ~bit; + reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); + } + bridge->b_rrb_map[slot & 1].reg = reg; + return rv; +} + +/* + * do_pcibr_rrb_free: release some of the RRBs that + * have been allocated for the specified + * slot. Returns zero for success, or negative if + * it was unable to free that many RRBs. + * + * IMPL NOTE: We form up a bit for each RRB + * allocated to the slot, aligned with the VALID + * bitfield this time; then we peel bits off one at + * a time, releasing the corresponding RRB. + */ +int +do_pcibr_rrb_free(bridge_t *bridge, + pciio_slot_t slot, + int less) +{ + int rv = 0; + bridgereg_t reg, tmp, clr, bit; + int i; + + clr = 0; + reg = bridge->b_rrb_map[slot & 1].reg; + + /* This needs to be done otherwise the rrb's on the virtual channel + * for this slot won't be freed !! + */ + tmp = reg & 0xbbbbbbbb; + + tmp ^= (0x11111111 * (7 - slot / 2)); + tmp &= (0x33333333 & tmp) << 2; + tmp &= (0x44444444 & tmp) << 1; + while (less-- > 0) { + bit = LSBIT(tmp); + if (!bit) { + rv = -1; + break; + } + tmp &= ~bit; + reg &= ~bit; + clr |= bit; + } + bridge->b_rrb_map[slot & 1].reg = reg; + + for (i = 0; i < 8; i++) + if (clr & (8 << (4 * i))) + do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); + + return rv; +} + +void +do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, + int slot, + int more_rrbs) +{ + bridge_t *bridge = pcibr_soft->bs_base; + int got; + + for (got = 0; got < more_rrbs; ++got) { + if (pcibr_soft->bs_rrb_res[slot & 7] > 0) + pcibr_soft->bs_rrb_res[slot & 7]--; + else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) + pcibr_soft->bs_rrb_avail[slot & 1]--; + else + break; + if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) + break; +#if PCIBR_RRB_DEBUG + printk("do_pcibr_rrb_autoalloc: add one to slot %d%s\n", + slot & 7, slot & 8 ? "v" : ""); +#endif + pcibr_soft->bs_rrb_valid[slot]++; + } +#if PCIBR_RRB_DEBUG + printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + for (slot = 0; slot < 8; ++slot) + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + printk("\n"); +#endif +} + +/* + * Device driver interface to flush the write buffers for a specified + * device hanging off the bridge. + */ +int +pcibr_wrb_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + volatile bridgereg_t *wrb_flush; + + wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); + while (*wrb_flush); + + return(0); +} + +/* + * Device driver interface to request RRBs for a specified device + * hanging off a Bridge. The driver requests the total number of + * RRBs it would like for the normal channel (vchan0) and for the + * "virtual channel" (vchan1). The actual number allocated to each + * channel is returned. + * + * If we cannot allocate at least one RRB to a channel that needs + * at least one, return -1 (failure). Otherwise, satisfy the request + * as best we can and return 0. + */ +int +pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, + int *count_vchan0, + int *count_vchan1) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + int desired_vchan0; + int desired_vchan1; + int orig_vchan0; + int orig_vchan1; + int delta_vchan0; + int delta_vchan1; + int final_vchan0; + int final_vchan1; + int avail_rrbs; + int res_rrbs; + unsigned long s; + int error; + + /* + * TBD: temper request with admin info about RRB allocation, + * and according to demand from other devices on this Bridge. + * + * One way of doing this would be to allocate two RRBs + * for each device on the bus, before any drivers start + * asking for extras. This has the weakness that one + * driver might not give back an "extra" RRB until after + * another driver has already failed to get one that + * it wanted. + */ + + s = pcibr_lock(pcibr_soft); + + /* Save the boot-time RRB configuration for this slot */ + if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] < 0) { + pcibr_soft->bs_rrb_valid_dflt[pciio_slot] = + pcibr_soft->bs_rrb_valid[pciio_slot]; + pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = + pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + pcibr_soft->bs_rrb_res_dflt[pciio_slot] = + pcibr_soft->bs_rrb_res[pciio_slot]; + + } + + /* How many RRBs do we own? */ + orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; + orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + + /* How many RRBs do we want? */ + desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; + desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; + + /* How many RRBs are free? */ + avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] + + pcibr_soft->bs_rrb_res[pciio_slot]; + + /* Figure desired deltas */ + delta_vchan0 = desired_vchan0 - orig_vchan0; + delta_vchan1 = desired_vchan1 - orig_vchan1; + + /* Trim back deltas to something + * that we can actually meet, by + * decreasing the ending allocation + * for whichever channel wants + * more RRBs. If both want the same + * number, cut the second channel. + * NOTE: do not change the allocation for + * a channel that was passed as NULL. + */ + while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { + if (count_vchan0 && + (!count_vchan1 || + ((orig_vchan0 + delta_vchan0) > + (orig_vchan1 + delta_vchan1)))) + delta_vchan0--; + else + delta_vchan1--; + } + + /* Figure final RRB allocations + */ + final_vchan0 = orig_vchan0 + delta_vchan0; + final_vchan1 = orig_vchan1 + delta_vchan1; + + /* If either channel wants RRBs but our actions + * would leave it with none, declare an error, + * but DO NOT change any RRB allocations. + */ + if ((desired_vchan0 && !final_vchan0) || + (desired_vchan1 && !final_vchan1)) { + + error = -1; + + } else { + + /* Commit the allocations: free, then alloc. + */ + if (delta_vchan0 < 0) + (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); + if (delta_vchan1 < 0) + (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); + + if (delta_vchan0 > 0) + (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); + if (delta_vchan1 > 0) + (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); + + /* Return final values to caller. + */ + if (count_vchan0) + *count_vchan0 = final_vchan0; + if (count_vchan1) + *count_vchan1 = final_vchan1; + + /* prevent automatic changes to this slot's RRBs + */ + pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; + + /* Track the actual allocations, release + * any further reservations, and update the + * number of available RRBs. + */ + + pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; + pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; + pcibr_soft->bs_rrb_avail[pciio_slot & 1] = + pcibr_soft->bs_rrb_avail[pciio_slot & 1] + + pcibr_soft->bs_rrb_res[pciio_slot] + - delta_vchan0 + - delta_vchan1; + pcibr_soft->bs_rrb_res[pciio_slot] = 0; + + /* + * Reserve enough RRBs so this slot's RRB configuration can be + * reset to its boot-time default following a hot-plug shut-down + */ + res_rrbs = (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] - + pcibr_soft->bs_rrb_valid[pciio_slot]) + + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot + + PCIBR_RRB_SLOT_VIRTUAL] - + pcibr_soft->bs_rrb_valid[pciio_slot + + PCIBR_RRB_SLOT_VIRTUAL]) + + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] - + pcibr_soft->bs_rrb_res[pciio_slot]); + + if (res_rrbs > 0) { + pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs; + pcibr_soft->bs_rrb_avail[pciio_slot & 1] = + pcibr_soft->bs_rrb_avail[pciio_slot & 1] + - res_rrbs; + } + +#if PCIBR_RRB_DEBUG + printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", + pciio_slot, final_vchan0, final_vchan1, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], + 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[pciio_slot]); + printk("\n"); +#endif + + error = 0; + } + + pcibr_unlock(pcibr_soft, s); + + return error; +} + +/* + * Device driver interface to check the current state + * of the RRB allocations. + * + * pconn_vhdl is your PCI connection point (specifies which + * PCI bus and which slot). + * + * count_vchan0 points to where to return the number of RRBs + * assigned to the primary DMA channel, used by all DMA + * that does not explicitly ask for the alternate virtual + * channel. + * + * count_vchan1 points to where to return the number of RRBs + * assigned to the secondary DMA channel, used when + * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. + * + * count_reserved points to where to return the number of RRBs + * that have been automatically reserved for your device at + * startup, but which have not been assigned to a + * channel. RRBs must be assigned to a channel to be used; + * this can be done either with an explicit pcibr_rrb_alloc + * call, or automatically by the infrastructure when a DMA + * translation is constructed. Any call to pcibr_rrb_alloc + * will release any unassigned reserved RRBs back to the + * free pool. + * + * count_pool points to where to return the number of RRBs + * that are currently unassigned and unreserved. This + * number can (and will) change as other drivers make calls + * to pcibr_rrb_alloc, or automatically allocate RRBs for + * DMA beyond their initial reservation. + * + * NULL may be passed for any of the return value pointers + * the caller is not interested in. + * + * The return value is "0" if all went well, or "-1" if + * there is a problem. Additionally, if the wrong vertex + * is passed in, one of the subsidiary support functions + * could panic with a "bad pciio fingerprint." + */ + +int +pcibr_rrb_check(devfs_handle_t pconn_vhdl, + int *count_vchan0, + int *count_vchan1, + int *count_reserved, + int *count_pool) +{ + pciio_info_t pciio_info; + pciio_slot_t pciio_slot; + pcibr_soft_t pcibr_soft; + unsigned long s; + int error = -1; + + if ((pciio_info = pciio_info_get(pconn_vhdl)) && + (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && + ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { + + s = pcibr_lock(pcibr_soft); + + if (count_vchan0) + *count_vchan0 = + pcibr_soft->bs_rrb_valid[pciio_slot]; + + if (count_vchan1) + *count_vchan1 = + pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + + if (count_reserved) + *count_reserved = + pcibr_soft->bs_rrb_res[pciio_slot]; + + if (count_pool) + *count_pool = + pcibr_soft->bs_rrb_avail[pciio_slot & 1]; + + error = 0; + + pcibr_unlock(pcibr_soft, s); + } + return error; +} + +/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities + * requested for each of the devices. The evn_odd argument indicates whether + * allocation is for the odd or even rrbs. The next group of four argument + * pairs indicate the amount of rrbs to be assigned to each device. The first + * argument of each pair indicate the total number of rrbs to allocate for that + * device. The second argument of each pair indicates how many rrb's from the + * first argument should be assigned to the virtual channel. The total of all + * of the first arguments should be <= 8. The second argument should be <= the + * first argument. + * if even_odd = 0 the devices in order are 0, 2, 4, 6 + * if even_odd = 1 the devices in order are 1, 3, 5, 7 + * returns 0 if no errors else returns -1 + */ + +int +pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, + int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, + int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) +{ + devfs_handle_t pcibr_vhdl; + pcibr_soft_t pcibr_soft = (pcibr_soft_t)0; + bridge_t *bridge = NULL; + + uint32_t rrb_setting = 0; + int rrb_shift = 7; + uint32_t cur_rrb; + int dev_rrbs[4]; + int virt[4]; + int i, j; + unsigned long s; + + if (GRAPH_SUCCESS == + hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (pcibr_soft) + bridge = pcibr_soft->bs_base; + hwgraph_vertex_unref(pcibr_vhdl); + } + if (bridge == NULL) + bridge = (bridge_t *) xtalk_piotrans_addr + (vhdl, NULL, 0, sizeof(bridge_t), 0); + + even_odd &= 1; + + dev_rrbs[0] = dev_1_rrbs; + dev_rrbs[1] = dev_2_rrbs; + dev_rrbs[2] = dev_3_rrbs; + dev_rrbs[3] = dev_4_rrbs; + + virt[0] = virt1; + virt[1] = virt2; + virt[2] = virt3; + virt[3] = virt4; + + if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { + return -1; + } + if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { + return -1; + } + /* walk through rrbs */ + for (i = 0; i < 4; i++) { + if (virt[i]) { + for( j = 0; j < virt[i]; j++) { + cur_rrb = i | 0xc; + cur_rrb = cur_rrb << (rrb_shift * 4); + rrb_shift--; + rrb_setting = rrb_setting | cur_rrb; + dev_rrbs[i] = dev_rrbs[i] - 1; + } + } + for (j = 0; j < dev_rrbs[i]; j++) { + cur_rrb = i | 0x8; + cur_rrb = cur_rrb << (rrb_shift * 4); + rrb_shift--; + rrb_setting = rrb_setting | cur_rrb; + } + } + + if (pcibr_soft) + s = pcibr_lock(pcibr_soft); + + bridge->b_rrb_map[even_odd].reg = rrb_setting; + + if (pcibr_soft) { + + pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; + + /* since we've "FIXED" the allocations + * for these slots, we probably can dispense + * with tracking avail/res/valid data, but + * keeping it up to date helps debugging. + */ + + pcibr_soft->bs_rrb_avail[even_odd] = + 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); + + pcibr_soft->bs_rrb_res[even_odd + 0] = 0; + pcibr_soft->bs_rrb_res[even_odd + 2] = 0; + pcibr_soft->bs_rrb_res[even_odd + 4] = 0; + pcibr_soft->bs_rrb_res[even_odd + 6] = 0; + + pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; + pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; + pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; + pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; + + pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; + pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; + pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; + pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; + + pcibr_unlock(pcibr_soft, s); + } + return 0; +} + +/* + * pcibr_rrb_flush: chase down all the RRBs assigned + * to the specified connection point, and flush + * them. + */ +void +pcibr_rrb_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + unsigned long s; + reg_p rrbp; + unsigned rrbm; + int i; + int rrbn; + unsigned sval; + unsigned mask; + + sval = BRIDGE_RRB_EN | (pciio_slot >> 1); + mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; + rrbn = pciio_slot & 1; + rrbp = &bridge->b_rrb_map[rrbn].reg; + + s = pcibr_lock(pcibr_soft); + rrbm = *rrbp; + for (i = 0; i < 8; ++i) { + if ((rrbm & mask) == sval) + do_pcibr_rrb_flush(bridge, rrbn); + rrbm >>= 4; + rrbn += 2; + } + pcibr_unlock(pcibr_soft, s); +} + +/* + * pcibr_slot_initial_rrb_alloc + * Allocate a default number of rrbs for this slot on + * the two channels. This is dictated by the rrb allocation + * strategy routine defined per platform. + */ + +int +pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + int c0, c1, r; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* How may RRBs are on this slot? + */ + c0 = do_pcibr_rrb_count_valid(bridge, slot); + c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); + +#if PCIBR_RRB_DEBUG + printk( + "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n", + slot, c0, c1); +#endif + + /* Do we really need any? + */ + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + pcibr_info = pcibr_infoh[0]; + if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && + !pcibr_soft->bs_slot[slot].has_host) { + if (c0 > 0) + do_pcibr_rrb_free(bridge, slot, c0); + if (c1 > 0) + do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); + pcibr_soft->bs_rrb_valid[slot] = 0x1000; + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; + return(ENODEV); + } + + pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; + pcibr_soft->bs_rrb_valid[slot] = c0; + pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; + + pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); + pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); + + r = 3 - (c0 + c1); + + if (r > 0) { + pcibr_soft->bs_rrb_res[slot] = r; + pcibr_soft->bs_rrb_avail[slot & 1] -= r; + } + +#if PCIBR_RRB_DEBUG + printk("\t%d+%d+%d", + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + printk("\n"); +#endif + + return(0); +} + +/* + * pcibr_initial_rrb + * Assign an equal total number of RRBs to all candidate slots, + * where the total is the sum of the number of RRBs assigned to + * the normal channel, the number of RRBs assigned to the virtual + * channel, and the number of RRBs assigned as reserved. + * + * A candidate slot is a populated slot on a non-SN1 system or + * any existing (populated or empty) slot on an SN1 system. + * Empty SN1 slots need RRBs to support hot-plug operations. + */ + +int +pcibr_initial_rrb(devfs_handle_t pcibr_vhdl, + pciio_slot_t first, pciio_slot_t last) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge = pcibr_soft->bs_base; + pciio_slot_t slot; + int c0, c1; + int have[2][3]; + int res[2]; + int eo; + + have[0][0] = have[0][1] = have[0][2] = 0; + have[1][0] = have[1][1] = have[1][2] = 0; + res[0] = res[1] = 0; + + for (slot = 0; slot < 8; ++slot) { + /* Initial RRB management; give back RRBs in all non-existent slots */ + (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); + + /* Base calculations only on existing slots */ + if ((slot >= first) && (slot <= last)) { + c0 = pcibr_soft->bs_rrb_valid[slot]; + c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; + if ((c0 + c1) < 3) + have[slot & 1][c0 + c1]++; + } + } + + /* Initialize even/odd slot available RRB counts */ + pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); + pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); + + /* + * Calculate reserved RRBs for slots based on current RRB usage + */ + for (eo = 0; eo < 2; eo++) { + if ((3 * have[eo][0] + 2 * have[eo][1] + have[eo][2]) <= pcibr_soft->bs_rrb_avail[eo]) + res[eo] = 3; + else if ((2 * have[eo][0] + have[eo][1]) <= pcibr_soft->bs_rrb_avail[eo]) + res[eo] = 2; + else if (have[eo][0] <= pcibr_soft->bs_rrb_avail[eo]) + res[eo] = 1; + else + res[eo] = 0; + + } + + /* Assign reserved RRBs to existing slots */ + for (slot = first; slot <= last; ++slot) { + int r; + + c0 = pcibr_soft->bs_rrb_valid[slot]; + c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; + r = res[slot & 1] - (c0 + c1); + + if (r > 0) { + pcibr_soft->bs_rrb_res[slot] = r; + pcibr_soft->bs_rrb_avail[slot & 1] -= r; + } + } + +#if PCIBR_RRB_DEBUG + printk("%v RRB MANAGEMENT: %d+%d free\n", + pcibr_vhdl, + pcibr_soft->bs_rrb_avail[0], + pcibr_soft->bs_rrb_avail[1]); + for (slot = first; slot <= last; ++slot) + printk("\tslot %d: %d+%d+%d", slot, + 0xFFF & pcibr_soft->bs_rrb_valid[slot], + 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], + pcibr_soft->bs_rrb_res[slot]); + printk("\n"); +#endif + + return 0; + +} + diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c --- linux-2.4.18/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1692 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern pcibr_info_t pcibr_info_get(devfs_handle_t); +extern int pcibr_widget_to_bus(int); +extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +extern void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); +extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +#if 0 +int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +#endif + +int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, int drv_flags); +int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, int drv_flags); +int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); +int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); +void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); +extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); + +#ifdef LATER +int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, + int drv_flags, char *l1_msg, int *sub_errorp); +int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *); +int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t); +int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t); +void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func, + pcibr_slot_func_info_resp_t funcp); +int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot, + pcibr_slot_info_resp_t respp); +int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t); +#endif /* LATER */ + +extern devfs_handle_t baseio_pci_vhdl; +int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t); + +/* For now .... */ +/* + * PCI Hot-Plug Capability Flags + */ +#define D_PCI_HOT_PLUG_ATTACH 0x200 /* Driver supports PCI hot-plug attach */ +#define D_PCI_HOT_PLUG_DETACH 0x400 /* Driver supports PCI hot-plug detach */ + + +/*========================================================================== + * BRIDGE PCI SLOT RELATED IOCTLs + */ + +#ifdef LATER + +/* + * pcibr_slot_startup + * Software start-up the PCI slot. + */ +int +pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pciio_slot_t slot = reqp->req_slot; + int error = 0; + char l1_msg[BRL1_QSIZE+1]; + struct pcibr_slot_up_resp_s tmp_up_resp; + + /* Make sure that we are dealing with a bridge device vertex */ + if (!pcibr_soft) { + return(PCI_NOT_A_BRIDGE); + } + + /* Do not allow start-up of a slot in a shoehorn */ + if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { + return(PCI_SLOT_IN_SHOEHORN); + } + + /* Check for the valid slot */ + if (!PCIBR_VALID_SLOT(slot)) + return(PCI_NOT_A_SLOT); + + /* Acquire update access to the bus */ + mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); + + if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) { + error = PCI_SLOT_ALREADY_UP; + goto startup_unlock; + } + + error = pcibr_slot_attach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_ATTACH, + l1_msg, &tmp_up_resp.resp_sub_errno); + + strncpy(tmp_up_resp.resp_l1_msg, l1_msg, L1_QSIZE); + tmp_up_resp.resp_l1_msg[L1_QSIZE] = '\0'; + + if (COPYOUT(&tmp_up_resp, reqp->req_respp.up, reqp->req_size)) { + return(EFAULT); + } + + startup_unlock: + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + + return(error); +} + +/* + * pcibr_slot_shutdown + * Software shut-down the PCI slot + */ +int +pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge; + pciio_slot_t slot = reqp->req_slot; + int error = 0; + char l1_msg[BRL1_QSIZE+1]; + struct pcibr_slot_down_resp_s tmp_down_resp; + pciio_slot_t tmp_slot; + + /* Make sure that we are dealing with a bridge device vertex */ + if (!pcibr_soft) { + return(PCI_NOT_A_BRIDGE); + } + + bridge = pcibr_soft->bs_base; + + /* Check for valid slot */ + if (!PCIBR_VALID_SLOT(slot)) + return(PCI_NOT_A_SLOT); + + /* Do not allow shut-down of a slot in a shoehorn */ + if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { + return(PCI_SLOT_IN_SHOEHORN); + } + + /* Acquire update access to the bus */ + mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); + + if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) || + ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) { + error = PCI_SLOT_ALREADY_DOWN; + /* + * RJR - Should we invoke an L1 slot power-down command just in case + * a previous shut-down failed to power-down the slot? + */ + goto shutdown_unlock; + } + + /* Do not allow the last 33 MHz card to be removed */ + if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) == + BRIDGE_CTRL_BUS_SPEED_33) { + for (tmp_slot = pcibr_soft->bs_first_slot; + tmp_slot <= pcibr_soft->bs_last_slot; tmp_slot++) + if (tmp_slot != slot) + if (pcibr_soft->bs_slot[tmp_slot].slot_status & SLOT_POWER_UP) { + error++; + break; + } + if (!error) { + error = PCI_EMPTY_33MHZ; + goto shutdown_unlock; + } + } + + error = pcibr_slot_detach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_DETACH, + l1_msg, &tmp_down_resp.resp_sub_errno); + + strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE); + tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0'; + + if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) { + return(EFAULT); + } + + shutdown_unlock: + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + + return(error); +} + +char *pci_space_name[] = {"NONE", + "ROM", + "IO", + "", + "MEM", + "MEM32", + "MEM64", + "CFG", + "WIN0", + "WIN1", + "WIN2", + "WIN3", + "WIN4", + "WIN5", + "", + "BAD"}; + +void +pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, + int func, + pcibr_slot_func_info_resp_t funcp) +{ + pcibr_info_t pcibr_info = pcibr_infoh[func]; + int win; + + funcp->resp_f_status = 0; + + if (!pcibr_info) { + return; + } + + funcp->resp_f_status |= FUNC_IS_VALID; + sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); + + if(is_sys_critical_vertex(pcibr_info->f_vertex)) { + funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; + } + + funcp->resp_f_bus = pcibr_info->f_bus; + funcp->resp_f_slot = pcibr_info->f_slot; + funcp->resp_f_func = pcibr_info->f_func; + sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); + funcp->resp_f_pops = pcibr_info->f_pops; + funcp->resp_f_efunc = pcibr_info->f_efunc; + funcp->resp_f_einfo = pcibr_info->f_einfo; + + funcp->resp_f_vendor = pcibr_info->f_vendor; + funcp->resp_f_device = pcibr_info->f_device; + + for(win = 0 ; win < 6 ; win++) { + funcp->resp_f_window[win].resp_w_base = + pcibr_info->f_window[win].w_base; + funcp->resp_f_window[win].resp_w_size = + pcibr_info->f_window[win].w_size; + sprintf(funcp->resp_f_window[win].resp_w_space, + "%s", + pci_space_name[pcibr_info->f_window[win].w_space]); + } + + funcp->resp_f_rbase = pcibr_info->f_rbase; + funcp->resp_f_rsize = pcibr_info->f_rsize; + + for (win = 0 ; win < 4; win++) { + funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; + } + + funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; + +} + +int +pcibr_slot_info_return(pcibr_soft_t pcibr_soft, + pciio_slot_t slot, + pcibr_slot_info_resp_t respp) +{ + pcibr_soft_slot_t pss; + int func; + bridge_t *bridge = pcibr_soft->bs_base; + reg_p b_respp; + pcibr_slot_info_resp_t slotp; + pcibr_slot_func_info_resp_t funcp; + + slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP); + if (slotp == NULL) { + return(ENOMEM); + } + + pss = &pcibr_soft->bs_slot[slot]; + + slotp->resp_has_host = pss->has_host; + slotp->resp_host_slot = pss->host_slot; + sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); + slotp->resp_slot_status = pss->slot_status; + + slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); + + if (is_sys_critical_vertex(pss->slot_conn)) { + slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; + } + + slotp->resp_bss_ninfo = pss->bss_ninfo; + + for (func = 0; func < pss->bss_ninfo; func++) { + funcp = &(slotp->resp_func[func]); + pcibr_slot_func_info_return(pss->bss_infos, func, funcp); + } + + sprintf(slotp->resp_bss_devio_bssd_space, "%s", + pci_space_name[pss->bss_devio.bssd_space]); + slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; + slotp->resp_bss_device = pss->bss_device; + + slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; + slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; + slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; + + slotp->resp_bss_d64_base = pss->bss_d64_base; + slotp->resp_bss_d64_flags = pss->bss_d64_flags; + slotp->resp_bss_d32_base = pss->bss_d32_base; + slotp->resp_bss_d32_flags = pss->bss_d32_flags; + + slotp->resp_bss_ext_ates_active = pss->bss_ext_ates_active; + + slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; + slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; + + slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; + slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + + PCIBR_RRB_SLOT_VIRTUAL]; + slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; + + if (slot & 1) { + b_respp = &bridge->b_odd_resp; + } else { + b_respp = &bridge->b_even_resp; + } + + slotp->resp_b_resp = *b_respp; + + slotp->resp_b_wid_control = bridge->b_wid_control; + slotp->resp_b_int_device = bridge->b_int_device; + slotp->resp_b_int_enable = bridge->b_int_enable; + slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; + + if (COPYOUT(slotp, respp, sizeof(*respp))) { + return(EFAULT); + } + + kmem_free(slotp, sizeof(*slotp)); + + return(0); +} + +/* + * pcibr_slot_query + * Return information about the PCI slot maintained by the infrastructure. + * Information is requested in the request structure. + * + * Information returned in the response structure: + * Slot hwgraph name + * Vendor/Device info + * Base register info + * Interrupt mapping from device pins to the bridge pins + * Devio register + * Software RRB info + * RRB register info + * Host/Gues info + * PCI Bus #,slot #, function # + * Slot provider hwgraph name + * Provider Functions + * Error handler + * DMA mapping usage counters + * DMA direct translation info + * External SSRAM workaround info + */ +int +pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pciio_slot_t slot = reqp->req_slot; + pciio_slot_t tmp_slot; + pcibr_slot_info_resp_t respp = reqp->req_respp.query; + int size = reqp->req_size; + int error; + + /* Make sure that we are dealing with a bridge device vertex */ + if (!pcibr_soft) { + return(PCI_NOT_A_BRIDGE); + } + + /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ + if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { + return(PCI_NOT_A_SLOT); + } + + /* Do not allow a query of a slot in a shoehorn */ + if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { + return(PCI_SLOT_IN_SHOEHORN); + } + + /* Return information for the requested PCI slot */ + if (slot != PCIIO_SLOT_NONE) { + if (size < sizeof(*respp)) { + return(PCI_RESP_AREA_TOO_SMALL); + } + + /* Acquire read access to the bus */ + mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, slot, respp); + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + + return(error); + } + + /* Return information for all the slots */ + for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { + + if (size < sizeof(*respp)) { + return(PCI_RESP_AREA_TOO_SMALL); + } + + /* Acquire read access to the bus */ + mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO); + + error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); + + /* Release the bus lock */ + mrunlock(pcibr_soft->bs_bus_lock); + + if (error) { + return(error); + } + + ++respp; + size -= sizeof(*respp); + } + + return(error); +} +#endif /* LATER */ + +/* FIXME: there should be a better way to do this. + * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE + */ + +/* + * PCI_ADDR_SPACE_LIMITS_LOAD + * Gets the current values of + * pci io base, + * pci io last, + * pci low memory base, + * pci low memory last, + * pci high memory base, + * pci high memory last + */ +#define PCI_ADDR_SPACE_LIMITS_LOAD() \ + pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ + pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ + pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ + pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ + pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ + pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; +/* + * PCI_ADDR_SPACE_LIMITS_STORE + * Sets the current values of + * pci io base, + * pci io last, + * pci low memory base, + * pci low memory last, + * pci high memory base, + * pci high memory last + */ +#define PCI_ADDR_SPACE_LIMITS_STORE() \ + pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ + pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ + pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ + pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ + pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ + pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; + +#define PCI_ADDR_SPACE_LIMITS_PRINT() \ + printf("+++++++++++++++++++++++\n" \ + "IO base 0x%x last 0x%x\n" \ + "SWIN base 0x%x last 0x%x\n" \ + "MEM base 0x%x last 0x%x\n" \ + "+++++++++++++++++++++++\n", \ + pcibr_soft->bs_spinfo.pci_io_base, \ + pcibr_soft->bs_spinfo.pci_io_last, \ + pcibr_soft->bs_spinfo.pci_swin_base, \ + pcibr_soft->bs_spinfo.pci_swin_last, \ + pcibr_soft->bs_spinfo.pci_mem_base, \ + pcibr_soft->bs_spinfo.pci_mem_last); + + +/* + * pcibr_slot_info_init + * Probe for this slot and see if it is populated. + * If it is populated initialize the generic PCI infrastructural + * information associated with this particular PCI device. + */ +int +pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + cfg_p cfgw; + unsigned idword; + unsigned pfail; + unsigned idwords[8]; + pciio_vendor_id_t vendor; + pciio_device_id_t device; + unsigned htype; + cfg_p wptr; + int win; + pciio_space_t space; + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + int nfunc; + pciio_function_t rfunc; + int func; + devfs_handle_t conn_vhdl; + pcibr_soft_slot_t slotp; + + /* Get the basic software information required to proceed */ + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + if (!PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization + * is done by the host slot then we are done. + */ + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + /* Check for a slot with any system critical functions */ + if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + /* Load the current values of allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); + + /* Try to read the device-id/vendor-id from the config space */ + cfgw = bridge->b_type0_cfg_dev[slot].l; + + if (pcibr_probe_slot(bridge, cfgw, &idword)) + return(ENODEV); + + slotp = &pcibr_soft->bs_slot[slot]; + slotp->slot_status |= SLOT_POWER_UP; + + vendor = 0xFFFF & idword; + /* If the vendor id is not valid then the slot is not populated + * and we are done. + */ + if (vendor == 0xFFFF) + return(ENODEV); + + device = 0xFFFF & (idword >> 16); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); + + nfunc = 1; + rfunc = PCIIO_FUNC_NONE; + pfail = 0; + + /* NOTE: if a card claims to be multifunction + * but only responds to config space 0, treat + * it as a unifunction card. + */ + + if (htype & 0x80) { /* MULTIFUNCTION */ + for (func = 1; func < 8; ++func) { + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { + pfail |= 1 << func; + continue; + } + vendor = 0xFFFF & idwords[func]; + if (vendor == 0xFFFF) { + pfail |= 1 << func; + continue; + } + nfunc = func + 1; + rfunc = 0; + } + cfgw = bridge->b_type0_cfg_dev[slot].l; + } + NEWA(pcibr_infoh, nfunc); + + pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; + pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; + + for (func = 0; func < nfunc; ++func) { + unsigned cmd_reg; + + if (func) { + if (pfail & (1 << func)) + continue; + + idword = idwords[func]; + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + + device = 0xFFFF & (idword >> 16); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); + rfunc = func; + } + htype &= 0x7f; + if (htype != 0x00) { + printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", + pcibr_soft->bs_name, slot, func, htype); + continue; + } +#if DEBUG && ATTACH_DEBUG + printk(KERN_NOTICE + "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", + pcibr_soft->bs_name, slot, func, vendor, device); +#endif + + pcibr_info = pcibr_device_info_new + (pcibr_soft, slot, rfunc, vendor, device); + conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); + if (func == 0) + slotp->slot_conn = conn_vhdl; + +#ifdef SN1_LITTLE_ENDIAN + cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4]; +#else + cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; +#endif + + wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; + + for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { + iopaddr_t base, mask, code; + size_t size; + + /* + * GET THE BASE & SIZE OF THIS WINDOW: + * + * The low two or four bits of the BASE register + * determines which address space we are in; the + * rest is a base address. BASE registers + * determine windows that are power-of-two sized + * and naturally aligned, so we can get the size + * of a window by writing all-ones to the + * register, reading it back, and seeing which + * bits are used for decode; the least + * significant nonzero bit is also the size of + * the window. + * + * WARNING: someone may already have allocated + * some PCI space to this window, and in fact + * PIO may be in process at this very moment + * from another processor (or even from this + * one, if we get interrupted)! So, if the BASE + * already has a nonzero address, be generous + * and use the LSBit of that address as the + * size; this could overstate the window size. + * Usually, when one card is set up, all are set + * up; so, since we don't bitch about + * overlapping windows, we are ok. + * + * UNFORTUNATELY, some cards do not clear their + * BASE registers on reset. I have two heuristics + * that can detect such cards: first, if the + * decode enable is turned off for the space + * that the window uses, we can disregard the + * initial value. second, if the address is + * outside the range that we use, we can disregard + * it as well. + * + * This is looking very PCI generic. Except for + * knowing how many slots and where their config + * spaces are, this window loop and the next one + * could probably be shared with other PCI host + * adapters. It would be interesting to see if + * this could be pushed up into pciio, when we + * start supporting more PCI providers. + */ +#ifdef SN1_LITTLE_ENDIAN + base = wptr[((win*4)^4)/4]; +#else + base = wptr[win]; +#endif + + if (base & PCI_BA_IO_SPACE) { + /* BASE is in I/O space. */ + space = PCIIO_SPACE_IO; + mask = -4; + code = base & 3; + base = base & mask; + if (base == 0) { + ; /* not assigned */ + } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { + base = 0; /* decode not enabled */ + } + } else { + /* BASE is in MEM space. */ + space = PCIIO_SPACE_MEM; + mask = -16; + code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ + base = base & mask; + if (base == 0) { + ; /* not assigned */ + } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { + base = 0; /* decode not enabled */ + } else if (base & 0xC0000000) { + base = 0; /* outside permissable range */ + } else if ((code == PCI_BA_MEM_64BIT) && +#ifdef SN1_LITTLE_ENDIAN + (wptr[(((win + 1)*4)^4)/4] != 0)) { +#else + (wptr[win + 1] != 0)) { +#endif /* LITTLE_ENDIAN */ + base = 0; /* outside permissable range */ + } + } + + if (base != 0) { /* estimate size */ + size = base & -base; + } else { /* calculate size */ +#ifdef SN1_LITTLE_ENDIAN + wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ + size = wptr[((win*4)^4)/4]; /* get stored bits */ +#else + wptr[win] = ~0; /* turn on all bits */ + size = wptr[win]; /* get stored bits */ +#endif /* LITTLE_ENDIAN */ + size &= mask; /* keep addr */ + size &= -size; /* keep lsbit */ + if (size == 0) + continue; + } + + pcibr_info->f_window[win].w_space = space; + pcibr_info->f_window[win].w_base = base; + pcibr_info->f_window[win].w_size = size; + + /* + * If this window already has PCI space + * allocated for it, "subtract" that space from + * our running freeblocks. Don't worry about + * overlaps in existing allocated windows; we + * may be overstating their sizes anyway. + */ + + if (base && size) { + if (space == PCIIO_SPACE_IO) { + pcibr_freeblock_sub(&pci_io_fb, + &pci_io_fl, + base, size); + } else { + pcibr_freeblock_sub(&pci_lo_fb, + &pci_lo_fl, + base, size); + pcibr_freeblock_sub(&pci_hi_fb, + &pci_hi_fl, + base, size); + } + } +#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) + /* + * IOC3 BASE_ADDR* BUG WORKAROUND + * + + * If we write to BASE1 on the IOC3, the + * data in BASE0 is replaced. The + * original workaround was to remember + * the value of BASE0 and restore it + * when we ran off the end of the BASE + * registers; however, a later + * workaround was added (I think it was + * rev 1.44) to avoid setting up + * anything but BASE0, with the comment + * that writing all ones to BASE1 set + * the enable-parity-error test feature + * in IOC3's SCR bit 14. + * + * So, unless we defer doing any PCI + * space allocation until drivers + * attach, and set up a way for drivers + * (the IOC3 in paricular) to tell us + * generically to keep our hands off + * BASE registers, we gotta "know" about + * the IOC3 here. + * + * Too bad the PCI folks didn't reserve the + * all-zero value for 'no BASE here' (it is a + * valid code for an uninitialized BASE in + * 32-bit PCI memory space). + */ + + if ((vendor == IOC3_VENDOR_ID_NUM) && + (device == IOC3_DEVICE_ID_NUM)) + break; +#endif + if (code == PCI_BA_MEM_64BIT) { + win++; /* skip upper half */ +#ifdef SN1_LITTLE_ENDIAN + wptr[((win*4)^4)/4] = 0; /* which must be zero */ +#else + wptr[win] = 0; /* which must be zero */ +#endif /* LITTLE_ENDIAN */ + } + } /* next win */ + } /* next func */ + + /* Store back the values for allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_STORE(); + return(0); +} + +/* + * pcibr_slot_info_free + * Remove all the PCI infrastructural information associated + * with a particular PCI device. + */ +int +pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + int nfunc; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + + pcibr_device_info_free(pcibr_vhdl, slot); + + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + DELA(pcibr_infoh,nfunc); + pcibr_soft->bs_slot[slot].bss_ninfo = 0; + + return(0); +} + +int as_debug = 0; +/* + * pcibr_slot_addr_space_init + * Reserve chunks of PCI address space as required by + * the base registers in the card. + */ +int +pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + bridge_t *bridge; + iopaddr_t pci_io_fb, pci_io_fl; + iopaddr_t pci_lo_fb, pci_lo_fl; + iopaddr_t pci_hi_fb, pci_hi_fl; + size_t align; + iopaddr_t mask; + int nbars; + int nfunc; + int func; + int win; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* Get the current values for the allocated PCI address spaces */ + PCI_ADDR_SPACE_LIMITS_LOAD(); + + if (as_debug) +#ifdef LATER + PCI_ADDR_SPACE_LIMITS_PRINT(); +#endif + + /* allocate address space, + * for windows that have not been + * previously assigned. + */ + if (pcibr_soft->bs_slot[slot].has_host) { + return(0); + } + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + if (nfunc < 1) + return(EINVAL); + + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + if (!pcibr_infoh) + return(EINVAL); + + /* + * Try to make the DevIO windows not + * overlap by pushing the "io" and "hi" + * allocation areas up to the next one + * or two megabyte bound. This also + * keeps them from being zero. + * + * DO NOT do this with "pci_lo" since + * the entire "lo" area is only a + * megabyte, total ... + */ + align = (slot < 2) ? 0x200000 : 0x100000; + mask = -align; + pci_io_fb = (pci_io_fb + align - 1) & mask; + pci_hi_fb = (pci_hi_fb + align - 1) & mask; + + for (func = 0; func < nfunc; ++func) { + cfg_p cfgw; + cfg_p wptr; + pciio_space_t space; + iopaddr_t base; + size_t size; + cfg_p pci_cfg_cmd_reg_p; + unsigned pci_cfg_cmd_reg; + unsigned pci_cfg_cmd_reg_add = 0; + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; + + nbars = PCI_CFG_BASE_ADDRS; + + for (win = 0; win < nbars; ++win) { + + space = pcibr_info->f_window[win].w_space; + base = pcibr_info->f_window[win].w_base; + size = pcibr_info->f_window[win].w_size; + + if (size < 1) + continue; + + if (base >= size) { +#if DEBUG && PCI_DEBUG + printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", + slot, func, win, space, base, base + size - 1); +#endif + continue; /* already allocated */ + } + align = size; /* ie. 0x00001000 */ + if (align < _PAGESZ) + align = _PAGESZ; /* ie. 0x00004000 */ + mask = -align; /* ie. 0xFFFFC000 */ + + switch (space) { + case PCIIO_SPACE_IO: + base = (pci_io_fb + align - 1) & mask; + if ((base + size) > pci_io_fl) { + base = 0; + break; + } + pci_io_fb = base + size; + break; + + case PCIIO_SPACE_MEM: +#ifdef SN1_LITTLE_ENDIAN + if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == +#else + if ((wptr[win] & PCI_BA_MEM_LOCATION) == +#endif /* LITTLE_ENDIAN */ + PCI_BA_MEM_1MEG) { + /* allocate from 20-bit PCI space */ + base = (pci_lo_fb + align - 1) & mask; + if ((base + size) > pci_lo_fl) { + base = 0; + break; + } + pci_lo_fb = base + size; + } else { + /* allocate from 32-bit or 64-bit PCI space */ + base = (pci_hi_fb + align - 1) & mask; + if ((base + size) > pci_hi_fl) { + base = 0; + break; + } + pci_hi_fb = base + size; + } + break; + + default: + base = 0; +#if DEBUG && PCI_DEBUG + printk("pcibr: slot %d window %d had bad space code %d\n", + slot, win, space); +#endif + } + pcibr_info->f_window[win].w_base = base; +#ifdef SN1_LITTLE_ENDIAN + wptr[((win*4)^4)/4] = base; +#if DEBUG && PCI_DEBUG + printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); +#endif +#else + wptr[win] = base; +#endif /* LITTLE_ENDIAN */ + +#if DEBUG && PCI_DEBUG + if (base >= size) + printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", + slot, func, win, space, base, base + size - 1); + else + printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", + slot, func, win, size, space); +#endif + } /* next base */ + + /* + * Allocate space for the EXPANSION ROM + * NOTE: DO NOT DO THIS ON AN IOC3, + * as it blows the system away. + */ + base = size = 0; + if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || + (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { + + wptr = cfgw + PCI_EXPANSION_ROM / 4; +#ifdef SN1_LITTLE_ENDIAN + wptr[1] = 0xFFFFF000; + mask = wptr[1]; +#else + *wptr = 0xFFFFF000; + mask = *wptr; +#endif /* LITTLE_ENDIAN */ + if (mask & 0xFFFFF000) { + size = mask & -mask; + align = size; + if (align < _PAGESZ) + align = _PAGESZ; + mask = -align; + base = (pci_hi_fb + align - 1) & mask; + if ((base + size) > pci_hi_fl) + base = size = 0; + else { + pci_hi_fb = base + size; +#ifdef SN1_LITTLE_ENDIAN + wptr[1] = base; +#else + *wptr = base; +#endif /* LITTLE_ENDIAN */ +#if DEBUG && PCI_DEBUG + printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", + pcibr_soft->bs_name, slot, + base, base + size - 1); +#endif + } + } + } + pcibr_info->f_rbase = base; + pcibr_info->f_rsize = size; + + /* + * if necessary, update the board's + * command register to enable decoding + * in the windows we added. + * + * There are some bits we always want to + * be sure are set. + */ + pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; + + /* + * The Adaptec 1160 FC Controller WAR #767995: + * The part incorrectly ignores the upper 32 bits of a 64 bit + * address when decoding references to it's registers so to + * keep it from responding to a bus cycle that it shouldn't + * we only use I/O space to get at it's registers. Don't + * enable memory space accesses on that PCI device. + */ + #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ + #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ + + if ((pcibr_info->f_vendor != FCADP_VENDID) || + (pcibr_info->f_device != FCADP_DEVID)) + pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; + + pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; + + pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; + pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; +#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ + if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) + fast_back_to_back_enable = 0; +#endif + pci_cfg_cmd_reg &= 0xFFFF; + if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) + *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; + + } /* next func */ + + /* Now that we have allocated new chunks of PCI address spaces to this + * card we need to update the bookkeeping values which indicate + * the current PCI address space allocations. + */ + PCI_ADDR_SPACE_LIMITS_STORE(); + return(0); +} + +/* + * pcibr_slot_device_init + * Setup the device register in the bridge for this PCI slot. + */ +int +pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + bridgereg_t devreg; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + bridge = pcibr_soft->bs_base; + + /* + * Adjustments to Device(x) + * and init of bss_device shadow + */ + devreg = bridge->b_device[slot].reg; + devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; + devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; +#ifdef LITTLE_ENDIAN + devreg |= BRIDGE_DEV_DEV_SWAP; +#endif + pcibr_soft->bs_slot[slot].bss_device = devreg; + bridge->b_device[slot].reg = devreg; + +#if DEBUG && PCI_DEBUG + printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); +#endif + +#if DEBUG && PCI_DEBUG + printk("pcibr: PCI space allocation done.\n"); +#endif + + return(0); +} + +/* + * pcibr_slot_guest_info_init + * Setup the host/guest relations for a PCI slot. + */ +int +pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + pcibr_soft_slot_t slotp; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + slotp = &pcibr_soft->bs_slot[slot]; + + /* create info and verticies for guest slots; + * for compatibilitiy macros, create info + * for even unpopulated slots (but do not + * build verticies for them). + */ + if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { + NEWA(pcibr_infoh, 1); + pcibr_soft->bs_slot[slot].bss_ninfo = 1; + pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; + + pcibr_info = pcibr_device_info_new + (pcibr_soft, slot, PCIIO_FUNC_NONE, + PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + + if (pcibr_soft->bs_slot[slot].has_host) { + slotp->slot_conn = pciio_device_info_register + (pcibr_vhdl, &pcibr_info->f_c); + } + } + + /* generate host/guest relations + */ + if (pcibr_soft->bs_slot[slot].has_host) { + int host = pcibr_soft->bs_slot[slot].host_slot; + pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; + + hwgraph_edge_add(slotp->slot_conn, + host_slotp->slot_conn, + EDGE_LBL_HOST); + + /* XXX- only gives us one guest edge per + * host. If/when we have a host with more than + * one guest, we will need to figure out how + * the host finds all its guests, and sorts + * out which one is which. + */ + hwgraph_edge_add(host_slotp->slot_conn, + slotp->slot_conn, + EDGE_LBL_GUEST); + } + + return(0); +} + + +/* + * pcibr_slot_call_device_attach + * This calls the associated driver attach routine for the PCI + * card in this slot. + */ +int +pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + async_attach_t aa = NULL; + int func; + devfs_handle_t xconn_vhdl,conn_vhdl; + int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + + if (pcibr_soft->bs_slot[slot].has_host) { + return(EPERM); + } + + xconn_vhdl = pcibr_soft->bs_conn; + aa = async_attach_get_info(xconn_vhdl); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + +#ifdef LATER + /* + * Activate if and when we support cdl. + */ + if (aa) + async_attach_add_info(conn_vhdl, aa); +#endif /* LATER */ + + error_func = pciio_device_attach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } else { + pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; + } + + return(error); +} + +/* + * pcibr_slot_call_device_detach + * This calls the associated driver detach routine for the PCI + * card in this slot. + */ +int +pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + int func; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int error_func; + int error_slot = 0; + int error = ENODEV; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(EINVAL); + + if (pcibr_soft->bs_slot[slot].has_host) + return(EPERM); + + /* Make sure that we do not detach a system critical function vertex */ + if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(EPERM); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + + error_func = pciio_device_detach(conn_vhdl, drv_flags); + + pcibr_info->f_att_det_error = error_func; + + if (error_func) + error_slot = error_func; + + error = error_slot; + + } /* next func */ + + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; + + if (error) { + if ((error != ENODEV) && (error != EUNATCH)) + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } else { + if (conn_vhdl != GRAPH_VERTEX_NONE) + pcibr_device_unregister(conn_vhdl); + pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; + } + + return(error); +} + +#ifdef LATER + +/* + * pcibr_slot_attach + * This is a place holder routine to keep track of all the + * slot-specific initialization that needs to be done. + * This is usually called when we want to initialize a new + * PCI card on the bus. + */ +int +pcibr_slot_attach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags, + char *l1_msg, + int *sub_errorp) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + timespec_t ts; + int error; + + if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) { + /* Power-up the slot */ + error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_L1_ERR); + } else { + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK; + pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP; + } + +#ifdef LATER + /* + * Allow cards like the Alteon Gigabit Ethernet Adapter to complete + * on-card initialization following the slot reset + */ + ts.tv_sec = 0; /* 0 secs */ + ts.tv_nsec = 500 * (1000 * 1000); /* 500 msecs */ + nano_delay(&ts); +#else +#endif +#if 0 + /* Reset the slot */ + error = pcibr_slot_reset(pcibr_vhdl, slot) + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_RESET_ERR); + } +#endif + + /* Find out what is out there */ + error = pcibr_slot_info_init(pcibr_vhdl, slot); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_INFO_INIT_ERR); + } + + /* Set up the address space for this slot in the PCI land */ + error = pcibr_slot_addr_space_init(pcibr_vhdl, slot); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_ADDR_INIT_ERR); + } + + /* Setup the device register */ + error = pcibr_slot_device_init(pcibr_vhdl, slot); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_DEV_INIT_ERR); + } + + /* Setup host/guest relations */ + error = pcibr_slot_guest_info_init(pcibr_vhdl, slot); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_GUEST_INIT_ERR); + } + + /* Initial RRB management */ + error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_RRB_ALLOC_ERR); + } + + } + + /* Call the device attach */ + error = pcibr_slot_call_device_attach(pcibr_vhdl, slot, drv_flags); + if (error) { + if (sub_errorp) + *sub_errorp = error; + if (error == EUNATCH) + return(PCI_NO_DRIVER); + else + return(PCI_SLOT_DRV_ATTACH_ERR); + } + + return(0); +} +#endif /* LATER */ + +/* + * pcibr_slot_detach + * This is a place holder routine to keep track of all the + * slot-specific freeing that needs to be done. + */ +int +pcibr_slot_detach(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot, + int drv_flags) +{ + int error; + + /* Call the device detach function */ + error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); + return (error); + +} + +/* + * pcibr_is_slot_sys_critical + * Check slot for any functions that are system critical. + * Return 1 if any are system critical or 0 otherwise. + * + * This function will always return 0 when called by + * pcibr_attach() because the system critical vertices + * have not yet been set in the hwgraph. + */ +int +pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, + pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + int nfunc; + int func; + boolean_t is_sys_critical_vertex(devfs_handle_t); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + return(0); + + nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; + pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; ++func) { + + pcibr_info = pcibr_infoh[func]; + if (!pcibr_info) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + conn_vhdl = pcibr_info->f_vertex; + if (is_sys_critical_vertex(conn_vhdl)) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); +#else + printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); +#endif + return(1); + } + + } + + return(0); +} + +/* + * pcibr_probe_slot: read a config space word + * while trapping any errors; reutrn zero if + * all went OK, or nonzero if there was an error. + * The value read, if any, is passed back + * through the valp parameter. + */ +int +pcibr_probe_slot(bridge_t *bridge, + cfg_p cfg, + unsigned *valp) +{ + int rv; + bridgereg_t old_enable, new_enable; + int badaddr_val(volatile void *, int, volatile void *); + + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + + bridge->b_int_enable = new_enable; + + /* + * The xbridge doesn't clear b_err_int_view unless + * multi-err is cleared... + */ + if (is_xbridge(bridge)) + if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { + bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; + } + + if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { + bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; + (void) bridge->b_wid_tflush; /* flushbus */ + } + rv = badaddr_val((void *) cfg, 4, valp); + + /* + * The xbridge doesn't set master timeout in b_int_status + * here. Fortunately it's in error_interrupt_view. + */ + if (is_xbridge(bridge)) + if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { + bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; + rv = 1; /* unoccupied slot */ + } + + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + return rv; +} + +void +pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + pcibr_info_t pcibr_info; + pciio_function_t func; + pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; + int nfunc = slotp->bss_ninfo; + int bar; + int devio_index; + int s; + + + for (func = 0; func < nfunc; func++) { + pcibr_info = slotp->bss_infos[func]; + + if (!pcibr_info) + continue; + + s = pcibr_lock(pcibr_soft); + + for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { + if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) + continue; + + /* Get index of the DevIO(x) register used to access this BAR */ + devio_index = pcibr_info->f_window[bar].w_devio_index; + + + /* On last use, clear the DevIO(x) used to access this BAR */ + if (! --pcibr_soft->bs_slot[devio_index].bss_devio.bssd_ref_cnt) { + pcibr_soft->bs_slot[devio_index].bss_devio.bssd_space = + PCIIO_SPACE_NONE; + pcibr_soft->bs_slot[devio_index].bss_devio.bssd_base = + PCIBR_D32_BASE_UNSET; + pcibr_soft->bs_slot[devio_index].bss_device = 0; + } + } + + pcibr_unlock(pcibr_soft, s); + + slotp->bss_infos[func] = 0; + pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); + pciio_device_info_free(&pcibr_info->f_c); + + DEL(pcibr_info); + } + + /* Reset the mapping usage counters */ + slotp->bss_pmu_uctr = 0; + slotp->bss_d32_uctr = 0; + slotp->bss_d64_uctr = 0; + + /* Clear the Direct translation info */ + slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; + slotp->bss_d64_flags = 0; + slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; + slotp->bss_d32_flags = 0; + + /* Clear out shadow info necessary for the external SSRAM workaround */ + slotp->bss_ext_ates_active = ATOMIC_INIT(0); + slotp->bss_cmd_pointer = 0; + slotp->bss_cmd_shadow = 0; + +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/shub_intr.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/shub_intr.c --- linux-2.4.18/arch/ia64/sn/io/sn2/shub_intr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/shub_intr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,215 @@ +/* $Id: shub_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void hub_device_desc_update(device_desc_t, ilvl_t, cpuid_t); + +/* ARGSUSED */ +void +hub_intr_init(devfs_handle_t hubv) +{ + extern void sn_cpei_handler(int, void *, struct pt_regs *); + extern void sn_init_cpei_timer(void); + + if (request_irq(SGI_SHUB_ERROR_VECTOR, sn_cpei_handler, 0, "SN hub error", NULL) ) { + printk("hub_intr_init: Couldn't register SGI_SHUB_ERROR_VECTOR = %x\n",SGI_SHUB_ERROR_VECTOR); + } + sn_init_cpei_timer(); +} + +xwidgetnum_t +hub_widget_id(nasid_t nasid) +{ + hubii_wcr_t ii_wcr; /* the control status register */ + + ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); + + return ii_wcr.wcr_fields_s.wcr_widget_id; +} + +static hub_intr_t +do_hub_intr_alloc(devfs_handle_t dev, + device_desc_t dev_desc, + devfs_handle_t owner_dev, + int uncond_nothread) +{ + cpuid_t cpu = 0; + int vector; + hub_intr_t intr_hdl; + cnodeid_t cnode; + int cpuphys, slice; + int nasid; + iopaddr_t xtalk_addr; + struct xtalk_intr_s *xtalk_info; + xwidget_info_t xwidget_info; + ilvl_t intr_swlevel = 0; + + cpu = intr_heuristic(dev, dev_desc, -1, 0, owner_dev, NULL, &vector); + + if (cpu == CPU_NONE) { + printk("Unable to allocate interrupt for 0x%p\n", (void *)owner_dev); + return(0); + } + + cpuphys = cpu_physical_id(cpu); + slice = cpu_physical_id_to_slice(cpuphys); + nasid = cpu_physical_id_to_nasid(cpuphys); + cnode = cpuid_to_cnodeid(cpu); + + if (slice) { + xtalk_addr = SH_II_INT1 | GLOBAL_MMR_SPACE | + ((unsigned long)nasid << 36) | (1UL << 47); + } else { + xtalk_addr = SH_II_INT0 | GLOBAL_MMR_SPACE | + ((unsigned long)nasid << 36) | (1UL << 47); + } + + intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, cnode); + ASSERT_ALWAYS(intr_hdl); + + xtalk_info = &intr_hdl->i_xtalk_info; + xtalk_info->xi_dev = dev; + xtalk_info->xi_vector = vector; + xtalk_info->xi_addr = xtalk_addr; + + xwidget_info = xwidget_info_get(dev); + if (xwidget_info) { + xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); + } + + intr_hdl->i_swlevel = intr_swlevel; + intr_hdl->i_cpuid = cpu; + intr_hdl->i_bit = vector; + intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED; + + hub_device_desc_update(dev_desc, intr_swlevel, cpu); + return(intr_hdl); +} + +hub_intr_t +hub_intr_alloc(devfs_handle_t dev, + device_desc_t dev_desc, + devfs_handle_t owner_dev) +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); +} + +hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, + device_desc_t dev_desc, + devfs_handle_t owner_dev) +{ + return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); +} + +void +hub_intr_free(hub_intr_t intr_hdl) +{ + cpuid_t cpu = intr_hdl->i_cpuid; + int vector = intr_hdl->i_bit; + xtalk_intr_t xtalk_info; + + if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { + xtalk_info = &intr_hdl->i_xtalk_info; + xtalk_info->xi_dev = NODEV; + xtalk_info->xi_vector = 0; + xtalk_info->xi_addr = 0; + hub_intr_disconnect(intr_hdl); + } + + if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) { + kfree(intr_hdl); + } + intr_unreserve_level(cpu, vector); +} + +int +hub_intr_connect(hub_intr_t intr_hdl, + xtalk_intr_setfunc_t setfunc, + void *setfunc_arg) +{ + int rv; + cpuid_t cpu = intr_hdl->i_cpuid; + int vector = intr_hdl->i_bit; + + ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); + + rv = intr_connect_level(cpu, vector, intr_hdl->i_swlevel, NULL); + + if (rv < 0) { + return rv; + } + + intr_hdl->i_xtalk_info.xi_setfunc = setfunc; + intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; + + if (setfunc) { + (*setfunc)((xtalk_intr_t)intr_hdl); + } + + intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; + + return 0; +} + +/* + * Disassociate handler with the specified interrupt. + */ +void +hub_intr_disconnect(hub_intr_t intr_hdl) +{ + /*REFERENCED*/ + int rv; + cpuid_t cpu = intr_hdl->i_cpuid; + int bit = intr_hdl->i_bit; + xtalk_intr_setfunc_t setfunc; + + setfunc = intr_hdl->i_xtalk_info.xi_setfunc; + + /* TBD: send disconnected interrupts somewhere harmless */ + if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); + + rv = intr_disconnect_level(cpu, bit); + ASSERT(rv == 0); + intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; +} + + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +hub_intr_cpu_get(hub_intr_t intr_hdl) +{ + cpuid_t cpuid = intr_hdl->i_cpuid; + + ASSERT(cpuid != CPU_NONE); + + return(cpuid_to_vertex(cpuid)); +} diff -urN linux-2.4.18/arch/ia64/sn/io/sn2/shuberror.c linux-2.4.19-pre5/arch/ia64/sn/io/sn2/shuberror.c --- linux-2.4.18/arch/ia64/sn/io/sn2/shuberror.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/io/sn2/shuberror.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,478 @@ +/* $Id: shuberror.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void hubni_eint_init(cnodeid_t cnode); +extern void hubii_eint_init(cnodeid_t cnode); +extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); +int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); +extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe); + +extern int maxcpus; + +#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ + + +void +hub_error_clear(nasid_t nasid) +{ + int i; + hubreg_t idsr; + + /* + * Make sure spurious write response errors are cleared + * (values are from hub_set_prb()) + */ + for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { + iprb_t prb; + + prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); + + /* Clear out some fields */ + prb.iprb_ovflow = 1; + prb.iprb_bnakctr = 0; + prb.iprb_anakctr = 0; + + prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ + + REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); + } + + REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); + idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); + REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); + +} + + +/* + * Function : hub_error_init + * Purpose : initialize the error handling requirements for a given hub. + * Parameters : cnode, the compact nodeid. + * Assumptions : Called only once per hub, either by a local cpu. Or by a + * remote cpu, when this hub is headless.(cpuless) + * Returns : None + */ + +void +hub_error_init(cnodeid_t cnode) +{ + nasid_t nasid; + + nasid = cnodeid_to_nasid(cnode); + hub_error_clear(nasid); + + + /* + * Now setup the hub ii error interrupt handler. + */ + + hubii_eint_init(cnode); + + return; +} + +/* + * Function : hubii_eint_init + * Parameters : cnode + * Purpose : to initialize the hub iio error interrupt. + * Assumptions : Called once per hub, by the cpu which will ultimately + * handle this interrupt. + * Returns : None. + */ + + +void +hubii_eint_init(cnodeid_t cnode) +{ + int bit, rv; + ii_iidsr_u_t hubio_eint; + hubinfo_t hinfo; + cpuid_t intr_cpu; + devfs_handle_t hub_v; + ii_ilcsr_u_t ilcsr; + int bit_pos_to_irq(int bit); + int synergy_intr_connect(int bit, int cpuid); + + + hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); + ASSERT_ALWAYS(hub_v); + hubinfo_get(hub_v, &hinfo); + + ASSERT(hinfo); + ASSERT(hinfo->h_cnodeid == cnode); + + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. + * Just disable LLP, and don't connect any interrupts. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + return; + } + /* Select a possible interrupt target where there is a free interrupt + * bit and also reserve the interrupt bit for this IO error interrupt + */ + intr_cpu = intr_heuristic(hub_v,0,-1,0,hub_v, + "HUB IO error interrupt",&bit); + if (intr_cpu == CPU_NONE) { + printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); + return; + } + + rv = intr_connect_level(intr_cpu, bit, 0, NULL); + request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); + ASSERT_ALWAYS(rv >= 0); + hubio_eint.ii_iidsr_regval = 0; + hubio_eint.ii_iidsr_fld_s.i_enable = 1; + hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ + hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); + hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); + +} + + +/*ARGSUSED*/ +void +hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) +{ + devfs_handle_t hub_v; + hubinfo_t hinfo; + ii_wstat_u_t wstat; + hubreg_t idsr; + + + /* two levels of casting avoids compiler warning.!! */ + hub_v = (devfs_handle_t)(long)(arg); + ASSERT(hub_v); + + hubinfo_get(hub_v, &hinfo); + + /* + * Identify the reason for error. + */ + wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); + + if (wstat.ii_wstat_fld_s.w_crazy) { + char *reason; + /* + * We can do a couple of things here. + * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check + * which of these caused the CRAZY bit to be set. + * You may be able to check if the Link is up really. + */ + if (wstat.ii_wstat_fld_s.w_tx_mx_rty) + reason = "Micro Packet Retry Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_tail_to) + reason = "Crosstalk Tail Timeout"; + else if (wstat.ii_wstat_fld_s.w_xt_crd_to) + reason = "Crosstalk Credit Timeout"; + else { + hubreg_t hubii_imem; + /* + * Check if widget 0 has been marked as shutdown, or + * if BTE 0/1 has been marked. + */ + hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); + if (hubii_imem & IIO_IMEM_W0ESD) + reason = "Hub Widget 0 has been Shutdown"; + else if (hubii_imem & IIO_IMEM_B0ESD) + reason = "BTE 0 has been shutdown"; + else if (hubii_imem & IIO_IMEM_B1ESD) + reason = "BTE 1 has been shutdown"; + else reason = "Unknown"; + + } + /* + * Note: we may never be able to print this, if the II talking + * to Xbow which hosts the console is dead. + */ + printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_cnodeid, reason); + } + + /* + * It's a toss as to which one among PRB/CRB to check first. + * Current decision is based on the severity of the errors. + * IO CRB errors tend to be more severe than PRB errors. + * + * It is possible for BTE errors to have been handled already, so we + * may not see any errors handled here. + */ + (void)hubiio_crb_error_handler(hub_v, hinfo); + (void)hubiio_prb_error_handler(hub_v, hinfo); + /* + * If we reach here, it indicates crb/prb handlers successfully + * handled the error. So, re-enable II to send more interrupt + * and return. + */ + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); +} + +/* + * Free the hub CRB "crbnum" which encountered an error. + * Assumption is, error handling was successfully done, + * and we now want to return the CRB back to Hub for normal usage. + * + * In order to free the CRB, all that's needed is to de-allocate it + * + * Assumption: + * No other processor is mucking around with the hub control register. + * So, upper layer has to single thread this. + */ +void +hubiio_crb_free(hubinfo_t hinfo, int crbnum) +{ + ii_icrb0_a_u_t icrba; + + /* + * The hardware does NOT clear the mark bit, so it must get cleared + * here to be sure the error is not processed twice. + */ + icrba.ii_icrb0_a_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_A(crbnum)); + icrba.a_valid = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_A(crbnum), icrba.ii_icrb0_a_regval); + /* + * Deallocate the register. + */ + + REMOTE_HUB_S(hinfo->h_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); + + /* + * Wait till hub indicates it's done. + */ + while (REMOTE_HUB_L(hinfo->h_nasid, IIO_ICDR) & IIO_ICDR_PND) + us_delay(1); + +} + + +/* + * Array of error names that get logged in CRBs + */ +char *hubiio_crb_errors[] = { + "Directory Error", + "CRB Poison Error", + "I/O Write Error", + "I/O Access Error", + "I/O Partial Write Error", + "I/O Partial Read Error", + "I/O Timeout Error", + "Xtalk Error Packet" +}; + +/* + * hubiio_crb_error_handler + * + * This routine gets invoked when a hub gets an error + * interrupt. So, the routine is running in interrupt context + * at error interrupt level. + * Action: + * It's responsible for identifying ALL the CRBs that are marked + * with error, and process them. + * + * If you find the CRB that's marked with error, map this to the + * reason it caused error, and invoke appropriate error handler. + * + * XXX Be aware of the information in the context register. + * + * NOTE: + * Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt + * handler can be run on any node. (not necessarily the node + * corresponding to the hub that encountered error). + */ + +int +hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +{ + cnodeid_t cnode; + nasid_t nasid; + ii_icrb0_a_u_t icrba; /* II CRB Register A */ + ii_icrb0_b_u_t icrbb; /* II CRB Register B */ + ii_icrb0_c_u_t icrbc; /* II CRB Register C */ + ii_icrb0_d_u_t icrbd; /* II CRB Register D */ + int i; + int num_errors = 0; /* Num of errors handled */ + ioerror_t ioerror; + + nasid = hinfo->h_nasid; + cnode = NASID_TO_COMPACT_NODEID(nasid); + + /* + * Scan through all CRBs in the Hub, and handle the errors + * in any of the CRBs marked. + */ + for (i = 0; i < IIO_NUM_CRBS; i++) { + icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); + + IOERROR_INIT(&ioerror); + + /* read other CRB error registers. */ + icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); + icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); + icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); + + IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + /* Check if this error is due to BTE operation, + * and handle it separately. + */ + if (icrbd.d_bteop || + ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || + icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && + (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || + icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))){ + + int bte_num; + + if (icrbd.d_bteop) + bte_num = icrbc.c_btenum; + else /* b_initiator bit 2 gives BTE number */ + bte_num = (icrbb.b_initiator & 0x4) >> 2; + + bte_crb_error_handler(hub_v, bte_num, + i, &ioerror); + hubiio_crb_free(hinfo, i); + num_errors++; + continue; + } + + /* + * XXX + * Assuming the only other error that would reach here is + * crosstalk errors. + * If CRB times out on a message from Xtalk, it changes + * the message type to CRB. + * + * If we get here due to other errors (SN0net/CRB) + * what's the action ? + */ + + /* + * Pick out the useful fields in CRB, and + * tuck them away into ioerror structure. + */ + IOERROR_SETVALUE(&ioerror,xtalkaddr,icrba.a_addr << IIO_ICRB_ADDR_SHFT); + IOERROR_SETVALUE(&ioerror,widgetnum,icrba.a_sidn); + + + if (icrba.a_iow){ + /* + * XXX We shouldn't really have BRIDGE-specific code + * here, but alas.... + * + * The BRIDGE (or XBRIDGE) sets the upper bit of TNUM + * to indicate a WRITE operation. It sets the next + * bit to indicate an INTERRUPT operation. The bottom + * 3 bits of TNUM indicate which device was responsible. + */ + IOERROR_SETVALUE(&ioerror,widgetdev, + TNUM_TO_WIDGET_DEV(icrba.a_tnum)); + + } + + } + return num_errors; +} + +/*ARGSUSED*/ +/* + * hubii_prb_handler + * Handle the error reported in the PRB for wiget number wnum. + * This typically happens on a PIO write error. + * There is nothing much we can do in this interrupt context for + * PIO write errors. For e.g. QL scsi controller has the + * habit of flaking out on PIO writes. + * Print a message and try to continue for now + * Cleanup involes freeing the PRB register + */ +static void +hubii_prb_handler(devfs_handle_t hub_v, hubinfo_t hinfo, int wnum) +{ + nasid_t nasid; + + nasid = hinfo->h_nasid; + /* + * Clear error bit by writing to IECLR register. + */ + REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, (1 << wnum)); + /* + * PIO Write to Widget 'i' got into an error. + * Invoke hubiio_error_handler with this information. + */ + printk( "Hub nasid %d got a PIO Write error from widget %d, cleaning up and continuing", + nasid, wnum); + /* + * XXX + * It may be necessary to adjust IO PRB counter + * to account for any lost credits. + */ +} + +int +hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +{ + int wnum; + nasid_t nasid; + int num_errors = 0; + iprb_t iprb; + + nasid = hinfo->h_nasid; + /* + * Check if IPRB0 has any error first. + */ + iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(0)); + if (iprb.iprb_error) { + num_errors++; + hubii_prb_handler(hub_v, hinfo, 0); + } + /* + * Look through PRBs 8 - F to see if any of them has error bit set. + * If true, invoke hub iio error handler for this widget. + */ + for (wnum = HUB_WIDGET_ID_MIN; wnum <= HUB_WIDGET_ID_MAX; wnum++) { + iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum)); + + if (!iprb.iprb_error) + continue; + + num_errors++; + hubii_prb_handler(hub_v, hinfo, wnum); + } + + return num_errors; +} + diff -urN linux-2.4.18/arch/ia64/sn/io/stubs.c linux-2.4.19-pre5/arch/ia64/sn/io/stubs.c --- linux-2.4.18/arch/ia64/sn/io/stubs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/stubs.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. */ #include @@ -21,6 +20,7 @@ #include #include #include +#include /****** ****** hack defines ...... @@ -61,45 +61,45 @@ } void * -kmem_alloc_node(register size_t size, register int flags, cnodeid_t node) +snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node) { /* Allocates on node 'node' */ - FIXME("kmem_alloc_node : use kmalloc"); + FIXME("snia_kmem_alloc_node : use kmalloc"); return(kmalloc(size, GFP_KERNEL)); } void * -kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node) +snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node) { - FIXME("kmem_zalloc_node : use kmalloc"); + FIXME("snia_kmem_zalloc_node : use kmalloc"); return(kmalloc(size, GFP_KERNEL)); } void -kmem_free(void *where, int size) +snia_kmem_free(void *where, int size) { - FIXME("kmem_free : use kfree"); + FIXME("snia_kmem_free : use kfree"); return(kfree(where)); } void * -kmem_zone_alloc(register zone_t *zone, int flags) +snia_kmem_zone_alloc(register zone_t *zone, int flags) { - FIXME("kmem_zone_alloc : return null"); + FIXME("snia_kmem_zone_alloc : return null"); return((void *)0); } void -kmem_zone_free(register zone_t *zone, void *ptr) +snia_kmem_zone_free(register zone_t *zone, void *ptr) { - FIXME("kmem_zone_free : no-op"); + FIXME("snia_kmem_zone_free : no-op"); } zone_t * -kmem_zone_init(register int size, char *zone_name) +snia_kmem_zone_init(register int size, char *zone_name) { - FIXME("kmem_zone_free : returns NULL"); + FIXME("snia_kmem_zone_free : returns NULL"); return((zone_t *)0); } diff -urN linux-2.4.18/arch/ia64/sn/io/xbow.c linux-2.4.19-pre5/arch/ia64/sn/io/xbow.c --- linux-2.4.18/arch/ia64/sn/io/xbow.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/xbow.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include @@ -19,6 +18,7 @@ #include #include #include +#include /* #define DEBUG 1 */ /* #define XBOW_DEBUG 1 */ @@ -102,7 +102,6 @@ #ifdef LATER static void xbow_setwidint(xtalk_intr_t); static void xbow_errintr_handler(intr_arg_t); -static error_handler_f xbow_error_handler; #endif void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); @@ -281,7 +280,7 @@ /* &hcl_fops */ (void *)&vhdl, NULL); if (!vhdl) { printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", - conn); + (void *)conn); } /* @@ -306,7 +305,7 @@ /* * get the name of this xbow vertex and keep the info. - * This is needed during errors and interrupts, but as + * This is needed during errors and interupts, but as * long as we have it, we can use it elsewhere. */ s = dev_to_name(vhdl, devnm, MAXDEVNAME); @@ -371,36 +370,9 @@ } /* - * attach the crossbow error interrupt. - */ -#ifdef LATER - dev_desc = device_desc_dup(vhdl); - device_desc_flags_set(dev_desc, - device_desc_flags_get(dev_desc) | D_INTR_ISERR); - device_desc_intr_name_set(dev_desc, "Crossbow error"); - - intr_hdl = xtalk_intr_alloc(conn, dev_desc, vhdl); - ASSERT(intr_hdl != NULL); - - xtalk_intr_connect(intr_hdl, - (intr_func_t) xbow_errintr_handler, - (intr_arg_t) soft, - (xtalk_intr_setfunc_t) xbow_setwidint, - (void *) xbow, - (void *) 0); - device_desc_free(dev_desc); - - xwidget_error_register(conn, xbow_error_handler, soft); - -#else - FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n"); -#endif /* LATER */ - - /* * Enable xbow error interrupts */ - xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | - XB_WID_CTRL_XTALK_IE); + xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); /* * take a census of the widgets present, @@ -918,460 +890,6 @@ return 1; } -/* - * xbow_errintr_handler will be called if the xbow - * sends an interrupt request to report an error. - */ - -#ifdef LATER -static void -xbow_errintr_handler(intr_arg_t arg) -{ - ioerror_t ioe[1]; - xbow_soft_t soft = (xbow_soft_t) arg; - xbow_t *xbow = soft->base; - xbowreg_t wid_control; - xbowreg_t wid_stat; - xbowreg_t wid_err_cmdword; - xbowreg_t wid_err_upper; - xbowreg_t wid_err_lower; - w_err_cmd_word_u wid_err; - uint64_t wid_err_addr; - - int fatal = 0; - int dump_ioe = 0; - - wid_control = xbow->xb_wid_control; - wid_stat = xbow->xb_wid_stat_clr; - wid_err_cmdword = xbow->xb_wid_err_cmdword; - wid_err_upper = xbow->xb_wid_err_upper; - wid_err_lower = xbow->xb_wid_err_lower; - xbow->xb_wid_err_cmdword = 0; - - wid_err_addr = - wid_err_lower - | (((iopaddr_t) wid_err_upper - & WIDGET_ERR_UPPER_ADDR_ONLY) - << 32); - - if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) { - int port; - - wid_err.r = wid_err_cmdword; - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; port++) { - if (wid_stat & XB_WID_STAT_LINK_INTR(port)) { - xb_linkregs_t *link = &(xbow->xb_link(port)); - xbowreg_t link_control = link->link_control; - xbowreg_t link_status = link->link_status_clr; - xbowreg_t link_aux_status = link->link_aux_status; - xbowreg_t link_pend; - - link_pend = link_status & link_control & - (XB_STAT_ILLEGAL_DST_ERR - | XB_STAT_OALLOC_IBUF_ERR - | XB_STAT_RCV_CNT_OFLOW_ERR - | XB_STAT_XMT_CNT_OFLOW_ERR - | XB_STAT_XMT_MAX_RTRY_ERR - | XB_STAT_RCV_ERR - | XB_STAT_XMT_RTRY_ERR - | XB_STAT_MAXREQ_TOUT_ERR - | XB_STAT_SRC_TOUT_ERR - ); - - if (link_pend & XB_STAT_ILLEGAL_DST_ERR) { - if (wid_err.f.sidn == port) { - IOERROR_INIT(ioe); - IOERROR_SETVALUE(ioe, widgetnum, port); - IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr); - if (IOERROR_HANDLED == - xbow_error_handler(soft, - IOECODE_DMA, - MODE_DEVERROR, - ioe)) { - link_pend &= ~XB_STAT_ILLEGAL_DST_ERR; - } else { - dump_ioe++; - } - } - } - /* Xbow/Bridge WAR: - * if the bridge signals an LLP Transmitter Retry, - * rewrite its control register. - * If someone else triggers this interrupt, - * ignore (and disable) the interrupt. - */ - if (link_pend & XB_STAT_XMT_RTRY_ERR) { - if (!xbow_xmit_retry_error(soft, port)) { - link_control &= ~XB_CTRL_XMT_RTRY_IE; - link->link_control = link_control; - link->link_control; /* stall until written */ - } - link_pend &= ~XB_STAT_XMT_RTRY_ERR; - } - if (link_pend) { - devfs_handle_t xwidget_vhdl; - char *xwidget_name; - - /* Get the widget name corresponding to the current - * xbow link. - */ - xwidget_vhdl = xbow_widget_lookup(soft->busv,port); - xwidget_name = xwidget_name_get(xwidget_vhdl); - -#ifdef LATER - printk("%s port %X[%s] XIO Bus Error", - soft->name, port, xwidget_name); - if (link_status & XB_STAT_MULTI_ERR) - XEM_ADD_STR("\tMultiple Errors\n"); - if (link_status & XB_STAT_ILLEGAL_DST_ERR) - XEM_ADD_STR("\tInvalid Packet Destination\n"); - if (link_status & XB_STAT_OALLOC_IBUF_ERR) - XEM_ADD_STR("\tInput Overallocation Error\n"); - if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR) - XEM_ADD_STR("\tLLP receive error counter overflow\n"); - if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR) - XEM_ADD_STR("\tLLP transmit retry counter overflow\n"); - if (link_status & XB_STAT_XMT_MAX_RTRY_ERR) - XEM_ADD_STR("\tLLP Max Transmitter Retry\n"); - if (link_status & XB_STAT_RCV_ERR) - XEM_ADD_STR("\tLLP Receiver error\n"); - if (link_status & XB_STAT_XMT_RTRY_ERR) - XEM_ADD_STR("\tLLP Transmitter Retry\n"); - if (link_status & XB_STAT_MAXREQ_TOUT_ERR) - XEM_ADD_STR("\tMaximum Request Timeout\n"); - if (link_status & XB_STAT_SRC_TOUT_ERR) - XEM_ADD_STR("\tSource Timeout Error\n"); -#endif /* LATER */ - { - int other_port; - - for (other_port = 8; other_port < 16; ++other_port) { - if (link_aux_status & (1 << other_port)) { - /* XXX- need to go to "other_port" - * and clean up after the timeout? - */ - XEM_ADD_VAR(other_port); - } - } - } - -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); - - if (dump_ioe) { - XEM_ADD_IOE(); - dump_ioe = 0; - } -#if !DEBUG - } -#endif - fatal++; - } - } - } - } - if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) { - /* we have a "widget zero" problem */ - - if (wid_stat & (XB_WID_STAT_MULTI_ERR - | XB_WID_STAT_XTALK_ERR - | XB_WID_STAT_REG_ACC_ERR)) { - - printk("%s Port 0 XIO Bus Error", - soft->name); - if (wid_stat & XB_WID_STAT_MULTI_ERR) - XEM_ADD_STR("\tMultiple Error\n"); - if (wid_stat & XB_WID_STAT_XTALK_ERR) - XEM_ADD_STR("\tXIO Error\n"); - if (wid_stat & XB_WID_STAT_REG_ACC_ERR) - XEM_ADD_STR("\tRegister Access Error\n"); - - fatal++; - } - } - if (fatal) { - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_control); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - PRINT_PANIC("XIO Bus Error"); - } -} -#endif /* LATER */ - -/* - * XBOW ERROR Handling routines. - * These get invoked as part of walking down the error handling path - * from hub/heart towards the I/O device that caused the error. - */ - -/* - * xbow_error_handler - * XBow error handling dispatch routine. - * This is the primary interface used by external world to invoke - * in case of an error related to a xbow. - * Only functionality in this layer is to identify the widget handle - * given the widgetnum. Otherwise, xbow does not gathers any error - * data. - */ - -#ifdef LATER -static int -xbow_error_handler( - void *einfo, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - int retval = IOERROR_WIDGETLEVEL; - - xbow_soft_t soft = (xbow_soft_t) einfo; - int port; - devfs_handle_t conn; - devfs_handle_t busv; - - xbow_t *xbow = soft->base; - xbowreg_t wid_stat; - xbowreg_t wid_err_cmdword; - xbowreg_t wid_err_upper; - xbowreg_t wid_err_lower; - uint64_t wid_err_addr; - - xb_linkregs_t *link; - xbowreg_t link_control; - xbowreg_t link_status; - xbowreg_t link_aux_status; - - ASSERT(soft != 0); - busv = soft->busv; - -#if DEBUG && ERROR_DEBUG - printk("%s: xbow_error_handler\n", soft->name, busv); -#endif - - port = IOERROR_GETVALUE(ioerror, widgetnum); - - if (port == 0) { - /* error during access to xbow: - * do NOT attempt to access xbow regs. - */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - PRINT_ALERT("DMA error blamed on Crossbow at %s\n" - "\tbut Crosbow never initiates DMA!", - soft->name); - } - if (error_code & IOECODE_PIO) { - PRINT_ALERt("PIO Error on XIO Bus %s\n" - "\tattempting to access XIO controller\n" - "\twith offset 0x%X", - soft->name, - IOERROR_GETVALUE(ioerror, xtalkaddr)); - } - /* caller will dump contents of ioerror - * in DEBUG and kdebug kernels. - */ - - return retval; - } - /* - * error not on port zero: - * safe to read xbow registers. - */ - wid_stat = xbow->xb_wid_stat; - wid_err_cmdword = xbow->xb_wid_err_cmdword; - wid_err_upper = xbow->xb_wid_err_upper; - wid_err_lower = xbow->xb_wid_err_lower; - - wid_err_addr = - wid_err_lower - | (((iopaddr_t) wid_err_upper - & WIDGET_ERR_UPPER_ADDR_ONLY) - << 32); - - if ((port < BASE_XBOW_PORT) || - (port >= MAX_PORT_NUM)) { - - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" - "\tbut Crossbow does not support that port", - soft->name, port); - } - if (error_code & IOECODE_PIO) { - PRINT_ALERT("PIO Error on XIO Bus %s\n" - "\tattempting to access XIO port %d\n" - "\t(which Crossbow does not support)" - "\twith offset 0x%X", - soft->name, port, - IOERROR_GETVALUE(ioerror, xtalkaddr)); - } -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); -#if !DEBUG - } -#endif - - /* caller will dump contents of ioerror - * in DEBUG and kdebug kernels. - */ - - return retval; - } - /* access to valid port: - * ok to check port status. - */ - - link = &(xbow->xb_link(port)); - link_control = link->link_control; - link_status = link->link_status; - link_aux_status = link->link_aux_status; - - /* Check that there is something present - * in that XIO port. - */ - if (!(link_aux_status & XB_AUX_STAT_PRESENT)) { - /* nobody connected. */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - PRINT_ALERT("DMA error blamed on XIO port at %s/%d\n" - "\tbut there is no device connected there.", - soft->name, port); - } - if (error_code & IOECODE_PIO) { - PRINT_ALERT("PIO Error on XIO Bus %s\n" - "\tattempting to access XIO port %d\n" - "\t(which has no device connected)" - "\twith offset 0x%X", - soft->name, port, - IOERROR_GETVALUE(ioerror, xtalkaddr)); - } -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - XEM_ADD_VAR(port); - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); -#if !DEBUG - } -#endif - return retval; - - } - /* Check that the link is alive. - */ - if (!(link_status & XB_STAT_LINKALIVE)) { - /* nobody connected. */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - PRINT_ALERT("%s%sError on XIO Bus %s port %d", - (error_code & IOECODE_DMA) ? "DMA " : "", - (error_code & IOECODE_PIO) ? "PIO " : "", - soft->name, port); - - if ((error_code & IOECODE_PIO) && - (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - printk("\tAccess attempted to offset 0x%X\n", - IOERROR_GETVALUE(ioerror, xtalkaddr)); - } - if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) - XEM_ADD_STR("\tLink never came out of reset\n"); - else - XEM_ADD_STR("\tLink failed while transferring data\n"); - - } - /* get the connection point for the widget - * involved in this error; if it exists and - * is not our connectpoint, cycle back through - * xtalk_error_handler to deliver control to - * the proper handler (or to report a generic - * crosstalk error). - * - * If the downstream handler won't handle - * the problem, we let our upstream caller - * deal with it, after (in DEBUG and kdebug - * kernels) dumping the xbow state for this - * port. - */ - conn = xbow_widget_lookup(busv, port); - if ((conn != GRAPH_VERTEX_NONE) && - (conn != soft->conn)) { - retval = xtalk_error_handler(conn, error_code, mode, ioerror); - if (retval == IOERROR_HANDLED) - return IOERROR_HANDLED; - } - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (retval == IOERROR_UNHANDLED) { - retval = IOERROR_PANIC; - - PRINT_ALERT("%s%sError on XIO Bus %s port %d", - (error_code & IOECODE_DMA) ? "DMA " : "", - (error_code & IOECODE_PIO) ? "PIO " : "", - soft->name, port); - - if ((error_code & IOECODE_PIO) && - (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - printk("\tAccess attempted to offset 0x%X\n", - IOERROR_GETVALUE(ioerror, xtalkaddr)); - } - } - -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - XEM_ADD_VAR(port); - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); -#if !DEBUG - } -#endif - /* caller will dump raw ioerror data - * in DEBUG and kdebug kernels. - */ - - return retval; -} - -#endif /* LATER */ - void xbow_update_perf_counters(devfs_handle_t vhdl) { @@ -1520,7 +1038,7 @@ if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { #ifdef LATER - PRINT_WARNING("link %d[%s]: bad status 0x%x\n", + printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", link, xwidget_name, lnk_sts.linkstatus); #endif } diff -urN linux-2.4.18/arch/ia64/sn/io/xswitch.c linux-2.4.19-pre5/arch/ia64/sn/io/xswitch.c --- linux-2.4.18/arch/ia64/sn/io/xswitch.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/xswitch.c Sat Mar 30 22:55:26 2002 @@ -4,14 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include #include #include -#include +#include #include #include #include diff -urN linux-2.4.18/arch/ia64/sn/io/xtalk.c linux-2.4.19-pre5/arch/ia64/sn/io/xtalk.c --- linux-2.4.18/arch/ia64/sn/io/xtalk.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/io/xtalk.c Sat Mar 30 22:55:26 2002 @@ -4,24 +4,22 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. */ #include #include #include -#include +#include +#include #include #include #include #include #include - #include #include #include - #include /* @@ -41,7 +39,6 @@ cdl_p xtalk_registry = NULL; -#include #define DEV_FUNC(dev,func) hub_##func #define CAST_PIOMAP(x) ((hub_piomap_t)(x)) #define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) @@ -72,7 +69,7 @@ xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); void xtalk_intr_free(xtalk_intr_t); -int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *, void *); +int xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *); void xtalk_intr_disconnect(xtalk_intr_t); devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); @@ -113,8 +110,6 @@ xwidgetnum_t, devfs_handle_t, xwidgetnum_t, async_attach_t); int xwidget_unregister(devfs_handle_t); -void xwidget_error_register(devfs_handle_t, error_handler_f *, - error_handler_arg_t); void xwidget_reset(devfs_handle_t); char *xwidget_name_get(devfs_handle_t); #if !defined(DEV_FUNC) @@ -472,14 +467,11 @@ */ int xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - intr_func_t intr_func, /* xtalk intr handler */ - intr_arg_t intr_arg, /* arg to intr handler */ xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg, /* arg to setfunc */ - void *thread) -{ /* intr thread to use */ + void *setfunc_arg) /* arg to setfunc */ +{ return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), intr_func, intr_arg, setfunc, setfunc_arg, thread); + (CAST_INTR(intr_hdl), setfunc, setfunc_arg); } @@ -506,85 +498,6 @@ } -/* - * ===================================================================== - * ERROR MANAGEMENT - */ - -/* - * xtalk_error_handler: - * pass this error on to the handler registered - * at the specified xtalk connecdtion point, - * or complain about it here if there is no handler. - * - * This routine plays two roles during error delivery - * to most widgets: first, the external agent (heart, - * hub, or whatever) calls in with the error and the - * connect point representing the crosstalk switch, - * or whatever crosstalk device is directly connected - * to the agent. - * - * If there is a switch, it will generally look at the - * widget number stashed in the ioerror structure; and, - * if the error came from some widget other than the - * switch, it will call back into xtalk_error_handler - * with the connection point of the offending port. - */ -int -xtalk_error_handler( - devfs_handle_t xconn, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - xwidget_info_t xwidget_info; - -#if DEBUG && ERROR_DEBUG -#ifdef SUPPORT_PRINTING_V_FORMAT - printk("%v: xtalk_error_handler\n", xconn); -#else - printk("%x: xtalk_error_handler\n", xconn); -#endif -#endif - - xwidget_info = xwidget_info_get(xconn); - /* Make sure that xwidget_info is a valid pointer before derefencing it. - * We could come in here during very early initialization. - */ - if (xwidget_info && xwidget_info->w_efunc) - return xwidget_info->w_efunc - (xwidget_info->w_einfo, - error_code, mode, ioerror); - /* - * no error handler registered for - * the offending port. it's not clear - * what needs to be done, but reporting - * it would be a good thing, unless it - * is a mode that requires nothing. - */ - if ((mode == MODE_DEVPROBE) || (mode == MODE_DEVUSERERROR) || - (mode == MODE_DEVREENABLE)) - return IOERROR_HANDLED; - -#ifdef LATER -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_WARNING("Xbow at %v encountered Fatal error", xconn); -#else - PRINT_WARNING("Xbow at %x encountered Fatal error", xconn); -#endif -#endif /* LATER */ - ioerror_dump("xtalk", error_code, mode, ioerror); - - return IOERROR_UNHANDLED; -} - -int -xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) -{ - return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code); -} - - /* ===================================================================== * CONFIGURATION MANAGEMENT */ @@ -977,7 +890,7 @@ widget_info->w_einfo = 0; /* * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interrupts, but as + * This is needed during errors and interupts, but as * long as we have it, we can use it elsewhere. */ s = dev_to_name(widget,devnm,MAXDEVNAME); @@ -1038,19 +951,6 @@ return(0); } -void -xwidget_error_register(devfs_handle_t xwidget, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - xwidget_info_t xwidget_info; - - xwidget_info = xwidget_info_get(xwidget); - ASSERT(xwidget_info != NULL); - xwidget_info->w_efunc = efunc; - xwidget_info->w_einfo = einfo; -} - /* * Issue a link reset to a widget. */ @@ -1120,17 +1020,5 @@ xwidget_unregister(widget_vhdl); - return(0); -} -/* - * xtalk_device_inquiry - * Find out hardware information about the xtalk widget. - */ -int -xtalk_device_inquiry(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - - extern void hub_device_inquiry(devfs_handle_t, xwidgetnum_t); - hub_device_inquiry(xbus_vhdl, widget); return(0); } diff -urN linux-2.4.18/arch/ia64/sn/kernel/Makefile linux-2.4.19-pre5/arch/ia64/sn/kernel/Makefile --- linux-2.4.18/arch/ia64/sn/kernel/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,62 @@ +# arch/ia64/sn/Makefile +# +# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/NoticeExplan +# + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +.S.s: + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< +.S.o: + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< + +O_TARGET = sn.o + +ifeq ($(CONFIG_MODULES),y) +export-objs = sn_ksyms.o +endif + +subdir-$(CONFIG_IA64_SGI_SN1) = sn1 +subdir-$(CONFIG_IA64_SGI_SN2) = sn2 + +obj-y = probe.o setup.o sn_asm.o sv.o bte.o iomv.o +obj-$(CONFIG_IA64_SGI_SN1) += irq.o mca.o +obj-$(CONFIG_IA64_SGI_SN2) += irq.o mca.o + +obj-$(CONFIG_IA64_SGI_SN1) += sn1/sn1.a +obj-$(CONFIG_IA64_SGI_SN2) += sn2/sn2.a + +obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o +obj-$(CONFIG_IA64_GENERIC) += machvec.o +obj-$(CONFIG_MODULES) += sn_ksyms.o + + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/kernel/bte.c linux-2.4.19-pre5/arch/ia64/sn/kernel/bte.c --- linux-2.4.18/arch/ia64/sn/kernel/bte.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/bte.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,263 @@ +/* + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; + +/* + * bte_init_node(nodepda, cnode, cmdline_p) + * + * Initialize the nodepda structure with BTE base addresses and + * spinlocks. + * + */ +void +bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode, char **cmdline_p) +{ + int bteTestMode = 0; + int cmdoffset = 0; + int i; + +#ifdef ZZZ + if (!cmdoffset) { + for (;cmdline_p[cmdoffset]; cmdoffset++) { + if (strstr(cmdline_p[cmdoffset], "btetest")) { + bteTestMode = 1; + break; + } + } + } +#endif + + /* + * Indicate that all the block transfer engines on this node + * are available. + */ + for (i = 0; i < BTES_PER_NODE; i++) { +#ifdef CONFIG_IA64_SGI_SN2 + /* >>> Don't know why the 0x1800000L is here. Robin */ + mynodepda->node_bte_info[i].bte_base_addr = + (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); +#elif CONFIG_IA64_SGI_SN1 + mynodepda->node_bte_info[i].bte_base_addr = + (char *)LOCAL_HUB_ADDR(bte_offsets[i]); +#else +#error BTE Not defined for this hardware platform. +#endif + +#ifdef CONFIG_IA64_SGI_BTE_LOCKING + /* Initialize the notification and spinlock */ + /* so the first transfer can occur. */ + mynodepda->node_bte_info[i].mostRecentNotification = + &(mynodepda->node_bte_info[i].notify); + mynodepda->node_bte_info[i].notify = 0L; + spin_lock_init(&mynodepda->node_bte_info[i].spinlock); +#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + + if (bteTestMode) { + mynodepda->node_bte_info[i].bteTestBuf = + alloc_bootmem_node(NODE_DATA(cnode), + BTE_MAX_XFER); + } + } +} + +/* + * bte_init_cpu() + * + * Initialize the cpupda structure with pointers to the + * nodepda bte blocks. + * + */ +void +bte_init_cpu(void) +{ + /* Called by setup.c as each cpu is being added to the nodepda */ + if (local_node_data->active_cpu_count & 0x1) { + pda.cpubte[0] = &(nodepda->node_bte_info[0]); + pda.cpubte[1] = &(nodepda->node_bte_info[1]); + } else { + pda.cpubte[0] = &(nodepda->node_bte_info[1]); + pda.cpubte[1] = &(nodepda->node_bte_info[0]); + } +} + + +/* + * bte_unaligned_copy(src, dest, len, mode) + * + * use the block transfer engine to move kernel + * memory from src to dest using the assigned mode. + * + * Paramaters: + * src - physical address of the transfer source. + * dest - physical address of the transfer destination. + * len - number of bytes to transfer from source to dest. + * mode - hardware defined. See reference information + * for IBCT0/1 in the SGI documentation. + * bteBlock - kernel virtual address of a temporary + * buffer used during unaligned transfers. + * + * NOTE: If the source, dest, and len are all cache line aligned, + * then it would be _FAR_ preferrable to use bte_copy instead. + */ +bte_result_t +bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode, char *bteBlock) +{ + int destFirstCacheOffset; + u64 headBteSource; + u64 headBteLen; + u64 headBcopySrcOffset; + u64 headBcopyDest; + u64 headBcopyLen; + u64 footBteSource; + u64 footBteLen; + u64 footBcopyDest; + u64 footBcopyLen; + bte_result_t rv; + + if (len == 0) { + return (BTE_SUCCESS); + } + + headBcopySrcOffset = src & L1_CACHE_MASK; + destFirstCacheOffset = dest & L1_CACHE_MASK; + + /* + * At this point, the transfer is broken into + * (up to) three sections. The first section is + * from the start address to the first physical + * cache line, the second is from the first physical + * cache line to the last complete cache line, + * and the third is from the last cache line to the + * end of the buffer. The first and third sections + * are handled by bte copying into a temporary buffer + * and then bcopy'ing the necessary section into the + * final location. The middle section is handled with + * a standard bte copy. + * + * One nasty exception to the above rule is when the + * source and destination are not symetrically + * mis-aligned. If the source offset from the first + * cache line is different from the destination offset, + * we make the first section be the entire transfer + * and the bcopy the entire block into place. + */ + if (headBcopySrcOffset == destFirstCacheOffset) { + + /* + * Both the source and destination are the same + * distance from a cache line boundary so we can + * use the bte to transfer the bulk of the + * data. + */ + headBteSource = src & ~L1_CACHE_MASK; + headBcopyDest = dest; + if (headBcopySrcOffset) { + headBcopyLen = + (len > + (L1_CACHE_BYTES - + headBcopySrcOffset) ? L1_CACHE_BYTES + - headBcopySrcOffset : len); + headBteLen = L1_CACHE_BYTES; + } else { + headBcopyLen = 0; + headBteLen = 0; + } + + if (len > headBcopyLen) { + footBcopyLen = + (len - headBcopyLen) & L1_CACHE_MASK; + footBteLen = L1_CACHE_BYTES; + + footBteSource = src + len - footBcopyLen; + footBcopyDest = dest + len - footBcopyLen; + + if (footBcopyDest == + (headBcopyDest + headBcopyLen)) { + /* + * We have two contigous bcopy + * blocks. Merge them. + */ + headBcopyLen += footBcopyLen; + headBteLen += footBteLen; + } else if (footBcopyLen > 0) { + rv = bte_copy(footBteSource, + __pa(bteBlock), + footBteLen, mode, NULL); + if (rv != BTE_SUCCESS) { + return (rv); + } + + + memcpy(__va(footBcopyDest), + (char *)bteBlock, footBcopyLen); + } + } else { + footBcopyLen = 0; + footBteLen = 0; + } + + if (len > (headBcopyLen + footBcopyLen)) { + /* now transfer the middle. */ + rv = bte_copy((src + headBcopyLen), + (dest + + headBcopyLen), + (len - headBcopyLen - + footBcopyLen), mode, NULL); + if (rv != BTE_SUCCESS) { + return (rv); + } + + } + } else { + + + /* + * The transfer is not symetric, we will + * allocate a buffer large enough for all the + * data, bte_copy into that buffer and then + * bcopy to the destination. + */ + + /* Add the leader from source */ + headBteLen = len + (src & L1_CACHE_MASK); + /* Add the trailing bytes from footer. */ + headBteLen += + L1_CACHE_BYTES - (headBteLen & L1_CACHE_MASK); + headBteSource = src & ~L1_CACHE_MASK; + headBcopySrcOffset = src & L1_CACHE_MASK; + headBcopyDest = dest; + headBcopyLen = len; + } + + if (headBcopyLen > 0) { + rv = bte_copy(headBteSource, + __pa(bteBlock), headBteLen, mode, NULL); + if (rv != BTE_SUCCESS) { + return (rv); + } + + memcpy(__va(headBcopyDest), ((char *)bteBlock + + headBcopySrcOffset), + headBcopyLen); + } + return (BTE_SUCCESS); +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/iomv.c linux-2.4.19-pre5/arch/ia64/sn/kernel/iomv.c --- linux-2.4.18/arch/ia64/sn/kernel/iomv.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/iomv.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,119 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include + +#if 1 /* ##jh */ +#ifdef CONFIG_IA64_SGI_SN1 +#define mmiob sn1_mmiob +#else +#define mmiob sn2_mmiob +#endif +extern void mmiob(void); +#endif /* ##jh */ + +extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */ + +/** + * sn_inb - read a byte from a port + * @port: port to read from + * + * Reads a byte from @port and returns it to the caller. + */ +unsigned int +sn_inb (unsigned long port) +{ + volatile unsigned char *addr = sn_io_addr(port); + unsigned char ret; + + ret = *addr; + __ia64_mf_a(); + return ret; +} + +/** + * sn_inw - read a word from a port + * @port: port to read from + * + * Reads a word from @port and returns it to the caller. + */ +unsigned int +sn_inw (unsigned long port) +{ + volatile unsigned short *addr = sn_io_addr(port); + unsigned short ret; + + ret = *addr; + __ia64_mf_a(); + return ret; +} + +/** + * sn_inl - read a word from a port + * @port: port to read from + * + * Reads a word from @port and returns it to the caller. + */ +unsigned int +sn_inl (unsigned long port) +{ + volatile unsigned int *addr = sn_io_addr(port); + unsigned int ret; + + ret = *addr; + __ia64_mf_a(); + return ret; +} + +/** + * sn_outb - write a byte to a port + * @port: port to write to + * @val: value to write + * + * Writes @val to @port. + */ +void +sn_outb (unsigned char val, unsigned long port) +{ + volatile unsigned char *addr = sn_io_addr(port); + + *addr = val; + mmiob(); +} + +/** + * sn_outw - write a word to a port + * @port: port to write to + * @val: value to write + * + * Writes @val to @port. + */ +void +sn_outw (unsigned short val, unsigned long port) +{ + volatile unsigned short *addr = sn_io_addr(port); + + *addr = val; + mmiob(); +} + +/** + * sn_outl - write a word to a port + * @port: port to write to + * @val: value to write + * + * Writes @val to @port. + */ +void +sn_outl (unsigned int val, unsigned long port) +{ + volatile unsigned int *addr = sn_io_addr(port); + + *addr = val; + mmiob(); +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/irq.c linux-2.4.19-pre5/arch/ia64/sn/kernel/irq.c --- linux-2.4.18/arch/ia64/sn/kernel/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,343 @@ +/* + * Platform dependent support for SGI SN1 + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ajmtestintr +#include +#include +#endif /* ajmtestintr */ +#include +#include +#include +#include +#include +#include + +int irq_to_bit_pos(int irq); + + + +static unsigned int +sn_startup_irq(unsigned int irq) +{ + return(0); +} + +static void +sn_shutdown_irq(unsigned int irq) +{ +} + +static void +sn_disable_irq(unsigned int irq) +{ +} + +static void +sn_enable_irq(unsigned int irq) +{ +} + +static void +sn_ack_irq(unsigned int irq) +{ +#ifdef CONFIG_IA64_SGI_SN1 + int bit = -1; + unsigned long long intpend_val; + int subnode; +#endif +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long event_occurred, mask = 0; +#endif + int nasid; + + irq = irq & 0xff; + nasid = smp_physical_node_id(); +#ifdef CONFIG_IA64_SGI_SN1 + subnode = cpuid_to_subnode(smp_processor_id()); + if (irq == SGI_UART_IRQ) { + intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); + if (intpend_val & (1L<> 8; + + irq = irq & 0xff; + + return(_sn_irq_desc[cpu] + irq); +} + +u8 +sn_irq_to_vector(u8 irq) { + return(irq & 0xff); +} + +unsigned int +sn_local_vector_to_irq(u8 vector) { + return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); +} + +int +sn_valid_irq(u8 irq) { + + return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) ); +} + +void *kmalloc(size_t, int); + +void +sn_irq_init (void) +{ + int i; + irq_desc_t *base_desc = _irq_desc; + + for (i=IA64_FIRST_DEVICE_VECTOR; i 118) bit = 118; + +#ifdef CONFIG_IA64_SGI_SN1 + if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { + return SGI_UART_IRQ; + } +#endif + + return bit + BIT_TO_IRQ; +} + +int +irq_to_bit_pos(int irq) { +#define IRQ_TO_BIT 64 + int bit = irq - IRQ_TO_BIT; + + return bit; +} + +#ifdef ajmtestintr + +#include +struct timer_list intr_test_timer; +int intr_test_icount[NR_IRQS]; +struct intr_test_reg_struct { + pcibr_soft_t pcibr_soft; + int slot; +}; +struct intr_test_reg_struct intr_test_registered[NR_IRQS]; + +void +intr_test_handle_timer(unsigned long data) { + int i; + bridge_t *bridge; + + for (i=0;ibs_intr[intr_test_registered[i].slot].bsi_xtalk_intr; + /* send interrupt */ + bridge = pcibr_soft->bs_base; + bridge->b_force_always[intr_test_registered[i].slot].intr = 1; + } + } + del_timer(&intr_test_timer); + intr_test_timer.expires = jiffies + HZ/100; + add_timer(&intr_test_timer); +} + +void +intr_test_set_timer(void) { + intr_test_timer.expires = jiffies + HZ/100; + intr_test_timer.function = intr_test_handle_timer; + add_timer(&intr_test_timer); +} + +void +intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) { + irq = irq & 0xff; + intr_test_registered[irq].pcibr_soft = pcibr_soft; + intr_test_registered[irq].slot = slot; +} + +void +intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) { + intr_test_icount[irq]++; + printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq); +} +#endif /* ajmtestintr */ diff -urN linux-2.4.18/arch/ia64/sn/kernel/llsc4.c linux-2.4.19-pre5/arch/ia64/sn/kernel/llsc4.c --- linux-2.4.18/arch/ia64/sn/kernel/llsc4.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/llsc4.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1044 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llsc4.h" + + +#ifdef STANDALONE +#include "lock.h" +#endif + +#ifdef INTTEST +static int inttest=0; +#endif + +#ifdef IA64_SEMFIX_INSN +#undef IA64_SEMFIX_INSN +#endif +#ifdef IA64_SEMFIX +#undef IA64_SEMFIX +#endif +# define IA64_SEMFIX_INSN +# define IA64_SEMFIX "" + +#define NOLOCK 0xdead +#define BGUARD(linei) (0xbbbb0000 | (linei)); +#define EGUARD(linei) (0xeeee0000 | (linei)); +#define GUARDLINE(v) ((v)&0xffff) + +/* + * Test parameter table for AUTOTEST + */ +typedef struct { + int passes; + int linecount; + int linepad; +} autotest_table_t; + +autotest_table_t autotest_table[] = { + {50000000, 2, 0x2b4 }, + {50000000, 16, 0, }, + {50000000, 16, 4, }, + {50000000, 128, 0x44 }, + {50000000, 128, 0x84 }, + {50000000, 128, 0x200 }, + {50000000, 128, 0x204 }, + {50000000, 128, 0x2b4 }, + {50000000, 2, 8*MB+0x2b4 }, + {50000000, 16, 8*MB+0 }, + {50000000, 16, 8*MB+4 }, + {50000000, 128, 8*MB+0x44 }, + {50000000, 128, 8*MB+0x84 }, + {50000000, 128, 8*MB+0x200 }, + {50000000, 128, 8*MB+0x204 }, + {50000000, 128, 8*MB+0x2b4 }, + {0}}; + +/* + * Array of virtual addresses available for test purposes. + */ + +typedef struct { + long vstart; + long vend; + long nextaddr; + long nextinit; + int wrapcount; +} memmap_t; + +#define MAPCHUNKS 128 +memmap_t memmap[MAPCHUNKS]; +int memmapx=0; + +typedef struct { + void *addr; + long data[16]; + long data_fc[16]; +} capture_line_t; + +typedef struct { + int size; + void *blockaddr; + void *shadaddr; + long blockdata[48]; + long shaddata[48]; + long blockdata_fc[48]; + long shaddata_fc[48]; + long synerr; +} capture_t; + +/* + * PORTING NOTE: revisit this statement. On hardware we put mbase at 0 and + * the rest of the tables have to start at 1MB to skip PROM tables. + */ +#define THREADPRIVATESZ() ((sizeof(threadprivate_t)+511)/512*512) +#define THREADPRIVATE(t) ((threadprivate_t*)(((long)mbase)+4096+t*THREADPRIVATESZ())) + +#define k_capture mbase->sk_capture +#define k_go mbase->sk_go +#define k_linecount mbase->sk_linecount +#define k_passes mbase->sk_passes +#define k_napticks mbase->sk_napticks +#define k_stop_on_error mbase->sk_stop_on_error +#define k_verbose mbase->sk_verbose +#define k_threadprivate mbase->sk_threadprivate +#define k_blocks mbase->sk_blocks +#define k_iter_msg mbase->sk_iter_msg +#define k_vv mbase->sk_vv +#define k_linepad mbase->sk_linepad +#define k_options mbase->sk_options +#define k_testnumber mbase->sk_testnumber +#define k_currentpass mbase->sk_currentpass + +static long blocks[MAX_LINECOUNT]; /* addresses of data blocks */ +static control_t *mbase; +static vint initialized=0; + +static unsigned int ran_conf_llsc(int); +static int rerr(capture_t *, char *, void *, void *, int, int, int, int, int, int); +static void dumpline(void *, char *, char *, void *, void *, int); +static int checkstop(int, int, uint); +static void spin(int); +static void capturedata(capture_t *, uint, void *, void *, int); +static int randn(uint max, uint *seed); +static uint zrandom (uint *zranseed); +static int set_lock(uint *, uint); +static int clr_lock(uint *, uint); +static void Speedo(void); + +int autotest_enabled=0; +static int llsctest_number=-1; +static int errstop_enabled=0; +static int fail_enabled=0; +static int l4_opt=0; +static int selective_trigger=0; +static int dump_block_addrs_opt=0; +static lock_t errlock=NOLOCK; +static private_t init_private[LLSC_MAXCPUS]; + +static int __init autotest_enable(char *str) +{ + autotest_enabled = 1; + return 1; +} +static int __init set_llscblkadr(char *str) +{ + dump_block_addrs_opt = 1; + return 1; +} +static int __init set_llscselt(char *str) +{ + selective_trigger = 1; + return 1; +} +static int __init set_llsctest(char *str) +{ + llsctest_number = simple_strtol(str, &str, 10); + if (llsctest_number < 0 || llsctest_number > 15) + llsctest_number = -1; + return 1; +} +static int __init set_llscerrstop(char *str) +{ + errstop_enabled = 1; + return 1; +} +static int __init set_llscfail(char *str) +{ + fail_enabled = 8; + return 1; +} +static int __init set_llscl4(char *str) +{ + l4_opt = 1; + return 1; +} + +static void print_params(void) +{ + printk ("********* Enter AUTOTEST facility on master cpu *************\n"); + printk (" Test options:\n"); + printk (" llsctest=\t%d\tTest number to run (all = -1)\n", llsctest_number); + printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); + printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); + printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); + printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); + printk (" llscl4 \t%s\tRun only tests that evict from L4\n", l4_opt ? "on" : "off"); + printk (" SEMFIX: %s\n", IA64_SEMFIX); + printk ("\n"); +} +__setup("autotest", autotest_enable); +__setup("llsctest=", set_llsctest); +__setup("llscerrstop", set_llscerrstop); +__setup("llscfail", set_llscfail); +__setup("llscselt", set_llscselt); +__setup("llscblkadr", set_llscblkadr); +__setup("llscl4", set_llscl4); + + + +static inline int +set_lock(uint *lock, uint id) +{ + uint old; + old = cmpxchg_acq(lock, NOLOCK, id); + return (old == NOLOCK); +} + +static inline int +clr_lock(uint *lock, uint id) +{ + uint old; + old = cmpxchg_rel(lock, id, NOLOCK); + return (old == id); +} + +static inline void +init_lock(uint *lock) +{ + *lock = NOLOCK; +} + +/*------------------------------------------------------------------------+ +| Routine : ran_conf_llsc - ll/sc shared data test | +| Description: This test checks the coherency of shared data | ++------------------------------------------------------------------------*/ +static unsigned int +ran_conf_llsc(int thread) +{ + private_t pval; + share_t sval, sval2; + uint vv, linei, slinei, sharei, pass; + long t; + lock_t lockpat; + share_t *sharecopy; + long verbose, napticks, passes, linecount, lcount; + dataline_t *linep, *slinep; + int s, seed; + threadprivate_t *tp; + uint iter_msg, iter_msg_i=0; + int vv_mask; + int correct_errors; + int errs=0; + int stillbad; + capture_t capdata; + private_t *privp; + share_t *sharep; + + + linecount = k_linecount; + napticks = k_napticks; + verbose = k_verbose; + passes = k_passes; + iter_msg = k_iter_msg; + seed = (thread + 1) * 647; + tp = THREADPRIVATE(thread); + vv_mask = (k_vv>>((thread%16)*4)) & 0xf; + correct_errors = k_options&0xff; + + memset (&capdata, 0, sizeof(capdata)); + for (linei=0; lineiprivate[linei] = thread; + + for (pass = 1; passes == 0 || pass < passes; pass++) { + lockpat = (pass & 0x0fffffff) + (thread <<28); + if (lockpat == NOLOCK) + continue; + tp->threadpasses = pass; + if (checkstop(thread, pass, lockpat)) + return 0; + iter_msg_i++; + if (iter_msg && iter_msg_i > iter_msg) { + printk("Thread %d, Pass %d\n", thread, pass); + iter_msg_i = 0; + } + lcount = 0; + + /* + * Select line to perform operations on. + */ + linei = randn(linecount, &seed); + sharei = randn(2, &seed); + slinei = (linei + (linecount/2))%linecount; /* I dont like this - fix later */ + + linep = (dataline_t *)blocks[linei]; + slinep = (dataline_t *)blocks[slinei]; + if (sharei == 0) + sharecopy = &slinep->share0; + else + sharecopy = &slinep->share1; + + + vv = randn(4, &seed); + if ((vv_mask & (1<private[thread]; + sharep = &linep->share[sharei]; + + switch(vv) { + case 0: + /* Read and verify private count on line. */ + pval = *privp; + if (verbose) + printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); + if (pval != tp->private[linei]) { + capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); + stillbad = (*privp != tp->private[linei]); + if (rerr(&capdata, "Private count", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { + return 1; + } + if (correct_errors) { + tp->private[linei] = *privp; + } + errs++; + } + break; + + case 1: + /* Read, verify, and increment private count on line. */ + pval = *privp; + if (verbose) + printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); + if (pval != tp->private[linei]) { + capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); + stillbad = (*privp != tp->private[linei]); + if (rerr(&capdata, "Private count & inc", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { + return 1; + } + errs++; + } + pval = (pval==255) ? 0 : pval+1; + *privp = pval; + tp->private[linei] = pval; + break; + + case 2: + /* Lock line, read and verify shared data. */ + if (verbose) + printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); + lcount = 0; + while (LOCK(sharei) != 1) { + if (checkstop(thread, pass, lockpat)) + return 0; + if (lcount++>1000000) { + capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); + stillbad = (GETLOCK(sharei) != 0); + rerr(&capdata, "Shared data lock", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); + return 1; + } + if ((lcount&0x3fff) == 0) + udelay(1000); + } + + sval = *sharep; + sval2 = *sharecopy; + if (pass > 12 && thread == 0 && fail_enabled == 1) + sval++; + if (sval != sval2) { + capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); + stillbad = (*sharep != *sharecopy); + if (!stillbad && *sharep != sval && *sharecopy == sval2) + stillbad = 2; + if (rerr(&capdata, "Shared data", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { + return 1; + } + if (correct_errors) + *sharep = *sharecopy; + errs++; + } + + + if ( (s=UNLOCK(sharei)) != 1) { + capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); + stillbad = (GETLOCK(sharei) != lockpat); + if (rerr(&capdata, "Shared data unlock", linep, slinep, thread, pass, linei, lockpat, GETLOCK(sharei), stillbad)) + return 1; + if (correct_errors) + ZEROLOCK(sharei); + errs++; + } + break; + + case 3: + /* Lock line, read and verify shared data, modify shared data. */ + if (verbose) + printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); + lcount = 0; + while (LOCK(sharei) != 1) { + if (checkstop(thread, pass, lockpat)) + return 0; + if (lcount++>1000000) { + capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); + stillbad = (GETLOCK(sharei) != 0); + rerr(&capdata, "Shared data lock & inc", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); + return 1; + } + if ((lcount&0x3fff) == 0) + udelay(1000); + } + sval = *sharep; + sval2 = *sharecopy; + if (sval != sval2) { + capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); + stillbad = (*sharep != *sharecopy); + if (!stillbad && *sharep != sval && *sharecopy == sval2) + stillbad = 2; + if (rerr(&capdata, "Shared data & inc", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { + return 1; + } + errs++; + } + + *sharep = lockpat; + *sharecopy = lockpat; + + + if ( (s=UNLOCK(sharei)) != 1) { + capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); + stillbad = (GETLOCK(sharei) != lockpat); + if (rerr(&capdata, "Shared data & inc unlock", linep, slinep, thread, pass, linei, thread, GETLOCK(sharei), stillbad)) + return 1; + if (correct_errors) + ZEROLOCK(sharei); + errs++; + } + break; + } + } + + return (errs > 0); +} + +static void +trigger_la(long val) +{ + long *p; + + p = (long*)0xc0000a0001000020L; /* PI_CPU_NUM */ + *p = val; +} + +static long +getsynerr(void) +{ + long err, *errp; + + errp = (long*)0xc0000e0000000340L; /* SYN_ERR */ + err = *errp; + if (err) + *errp = -1L; + return (err & ~0x60); +} + +static int +rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int badlinei, int exp, int found, int stillbad) +{ + int cpu, i, linei; + long synerr; + int selt; + + + selt = selective_trigger && stillbad > 1 && + memcmp(cap->blockdata, cap->blockdata_fc, 128) != 0 && + memcmp(cap->shaddata, cap->shaddata_fc, 128) == 0; + if (selt) { + trigger_la(pass); + } else if (selective_trigger) { + k_go = ST_STOP; + return k_stop_on_error;; + } + + spin(1); + i = 100; + while (i && set_lock(&errlock, 1) != 1) { + spin(1); + i--; + } + printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", + msg, k_testnumber, thread, badlinei, pass, pass, jiffies, exp, found); + + dumpline (lp, "Corrupted data", "D ", cap->blockaddr, cap->blockdata, cap->size); +#ifdef ZZZ + if (memcmp(cap->blockdata, cap->blockdata_fc, 128)) + dumpline (lp, "Corrupted data", "DF", cap->blockaddr, cap->blockdata_fc, cap->size); +#endif + + if (cap->shadaddr) { + dumpline (slp, "Shadow data", "S ", cap->shadaddr, cap->shaddata, cap->size); +#ifdef ZZZ + if (memcmp(cap->shaddata, cap->shaddata_fc, 128)) + dumpline (slp, "Shadow data", "SF", cap->shadaddr, cap->shaddata_fc, cap->size); +#endif + } + + printk("Threadpasses: "); + for (cpu=0,i=0; cputhreadpasses) { + if (i && (i%8) == 0) + printk("\n : "); + printk(" %d:0x%x", cpu, k_threadprivate[cpu]->threadpasses); + i++; + } + printk("\n"); + + for (linei=0; lineiguard1); + g2linei = GUARDLINE(linep->guard2); + g1err = (g1linei != linei); + g2err = (g2linei != linei); + sh0err = (linep->share[0] != slinep->share0); + sh1err = (linep->share[1] != slinep->share1); + + if (g1err || g2err || sh0err || sh1err) { + printk("Line 0x%lx (%03d), %sG1 0x%lx (%03d), %sG2 0x%lx (%03d), %sSH0 %08x (%08x), %sSH1 %08x (%08x)\n", + blocks[linei], linei, + g1err ? "*" : " ", blocks[g1linei], g1linei, + g2err ? "*" : " ", blocks[g2linei], g2linei, + sh0err ? "*" : " ", linep->share[0], slinep->share0, + sh1err ? "*" : " ", linep->share[1], slinep->share1); + + + } + } + + printk("\nData was %sfixed by flushcache\n", (stillbad == 1 ? "**** NOT **** " : " ")); + synerr = getsynerr(); + if (synerr) + printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); + spin(2); + printk("\n\n"); + clr_lock(&errlock, 1); + + if (errstop_enabled) { + local_irq_disable(); + while(1); + } + return k_stop_on_error; +} + + +static void +dumpline(void *lp, char *str1, char *str2, void *addr, void *data, int size) +{ + long *p; + int i, off; + + printk("%s at 0x%lx, size %d, block starts at 0x%lx\n", str1, (long)addr, size, (long)lp); + p = (long*) data; + for (i=0; i<48; i++, p++) { + if (i%8 == 0) printk("%2s", i==16 ? str2 : " "); + printk(" %016lx", *p); + if ((i&7)==7) printk("\n"); + } + printk(" "); + off = (((long)addr) ^ size) & 63L; + for (i=0; i=off) ? "--" : " "); + if ((i%8) == 7) + printk(" "); + } + + off = ((long)addr) & 127; + printk(" (line %d)\n", 2+off/64+1); +} + + +static int +randn(uint max, uint *seedp) +{ + if (max == 1) + return(0); + else + return((int)(zrandom(seedp)>>10) % max); +} + + +static int +checkstop(int thread, int pass, uint lockpat) +{ + long synerr; + + if (k_go == ST_RUN) + return 0; + if (k_go == ST_STOP) + return 1; + + if (errstop_enabled) { + local_irq_disable(); + while(1); + } + synerr = getsynerr(); + spin(2); + if (k_go == ST_STOP) + return 1; + if (synerr) + printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); + return 1; +} + + +static void +spin(int j) +{ + udelay(j * 500000); +} + +static void +capturedata(capture_t *cap, uint pass, void *blockaddr, void *shadaddr, int size) +{ + + if (!selective_trigger) + trigger_la (pass); + + memcpy (cap->blockdata, CACHEALIGN(blockaddr)-128, 3*128); + if (shadaddr) + memcpy (cap->shaddata, CACHEALIGN(shadaddr)-128, 3*128); + + if (k_stop_on_error) { + k_go = ST_ERRSTOP; + } + + cap->size = size; + cap->blockaddr = blockaddr; + cap->shadaddr = shadaddr; + + asm volatile ("fc %0" :: "r"(blockaddr) : "memory"); + ia64_sync_i(); + ia64_srlz_d(); + memcpy (cap->blockdata_fc, CACHEALIGN(blockaddr)-128, 3*128); + + if (shadaddr) { + asm volatile ("fc %0" :: "r"(shadaddr) : "memory"); + ia64_sync_i(); + ia64_srlz_d(); + memcpy (cap->shaddata_fc, CACHEALIGN(shadaddr)-128, 3*128); + } +} + +int zranmult = 0x48c27395; + +static uint +zrandom (uint *seedp) +{ + *seedp = (*seedp * zranmult) & 0x7fffffff; + return (*seedp); +} + + +void +set_autotest_params(void) +{ + static int testnumber=-1; + + if (llsctest_number >= 0) { + testnumber = llsctest_number; + } else { + testnumber++; + if (autotest_table[testnumber].passes == 0) { + testnumber = 0; + dump_block_addrs_opt = 0; + } + } + if (testnumber == 0 && l4_opt) testnumber = 9; + + k_passes = autotest_table[testnumber].passes; + k_linepad = autotest_table[testnumber].linepad; + k_linecount = autotest_table[testnumber].linecount; + k_testnumber = testnumber; + + if (IS_RUNNING_ON_SIMULATOR()) { + printk ("llsc start test %ld\n", k_testnumber); + k_passes = 1000; + } +} + + +static void +set_leds(int errs) +{ + unsigned char leds=0; + + /* + * Leds are: + * ppppeee- + * where + * pppp = test number + * eee = error count but top bit is stick + */ + + leds = ((errs&7)<<1) | ((k_testnumber&15)<<4) | (errs ? 0x08 : 0); + set_led_bits(leds, LED_MASK_AUTOTEST); +} + +static void +setup_block_addresses(void) +{ + int i, stride, memmapi; + dataline_t *dp; + long *ip, *ipe; + + + stride = k_linepad + sizeof(dataline_t); + memmapi = 0; + for (i=0; i= memmap[memmapi].vend) { + memmap[memmapi].wrapcount++; + memmap[memmapi].nextaddr = memmap[memmapi].vstart + + memmap[memmapi].wrapcount * sizeof(dataline_t); + } + + ip = (long*)((memmap[memmapi].nextinit+7)&~7); + ipe = (long*)(memmap[memmapi].nextaddr+2*sizeof(dataline_t)+8); + while(ip <= ipe && ip < ((long*)memmap[memmapi].vend-8)) + *ip++ = (long)ip; + memmap[memmapi].nextinit = (long) ipe; + dp->guard1 = BGUARD(i); + dp->guard2 = EGUARD(i); + dp->lock[0] = dp->lock[1] = NOLOCK; + dp->share[0] = dp->share0 = 0x1111; + dp->share[1] = dp->share1 = 0x2222; + memcpy(dp->private, init_private, LLSC_MAXCPUS*sizeof(private_t)); + + + if (stride > 16384) { + memmapi++; + if (memmapi == memmapx) + memmapi = 0; + } + } + +} + +static void +dump_block_addrs(void) +{ + int i; + + printk("LLSC TestNumber %ld\n", k_testnumber); + + for (i=0; ithreadstate == TS_KILLED) { + set_led_bits(LED_MASK_AUTOTEST, LED_MASK_AUTOTEST); + while(1); + } + k_threadprivate[cpuid]->threadstate = state; +} + +#define MINBLK (16*1024*1024) +static int +build_mem_map(unsigned long start, unsigned long end, void *arg) +{ + long lstart, lend; + long align = 8*MB; + + printk ("LLSC memmap: start 0x%lx, end 0x%lx, (0x%lx - 0x%lx)\n", + start, end, (long) virt_to_page(start), (long) virt_to_page(end-PAGE_SIZE)); + + if (memmapx >= MAPCHUNKS || (end-start) < MINBLK) + return 0; + + /* + * Start in the middle of the range & find the first non-free page in both directions + * from the midpoint. This is likely to be the bigest free block. + */ + lend = lstart = start + (end-start)/2; + while (lend < end && !PageReserved(virt_to_page(lend)) && virt_to_page(lend)->count.counter == 0) + lend += PAGE_SIZE; + lend -= PAGE_SIZE; + + while (lstart >= start && !PageReserved(virt_to_page(lstart)) && virt_to_page(lstart)->count.counter == 0) + lstart -= PAGE_SIZE; + lstart += PAGE_SIZE; + + lstart = (lstart + align -1) /align * align; + end = end / align * align; + if (lstart >= end) + return 0; + printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); + + memmap[memmapx].vstart = lstart; + memmap[memmapx].vend = end; + memmapx++; + return 0; +} + +void int_test(void); + +int +llsc_main (int cpuid) +{ + int i, cpu, is_master, repeatcnt=0; + unsigned int preverr=0, errs=0, pass=0; + int automode=0; + +#ifdef INTTEST + if (inttest) + int_test(); +#endif + + if (!autotest_enabled) + return 0; + +#ifdef CONFIG_SMP + is_master = !smp_processor_id(); +#else + is_master = 1; +#endif + + + if (is_master) { + mbase = (control_t*) __get_free_pages(GFP_KERNEL, get_order(4096+THREADPRIVATESZ()*LLSC_MAXCPUS)); + printk("LLSC: mbase 0x%lx\n", (long)mbase); + print_params(); + if(!IS_RUNNING_ON_SIMULATOR()) + spin(10); + k_currentpass = 0; + k_go = ST_IDLE; + k_passes = DEF_PASSES; + k_napticks = DEF_NAPTICKS; + k_stop_on_error = DEF_STOP_ON_ERROR; + k_verbose = DEF_VERBOSE; + k_linecount = DEF_LINECOUNT; + k_iter_msg = DEF_ITER_MSG; + k_vv = DEF_VV; + k_linepad = DEF_LINEPAD; + k_blocks = (void*)blocks; + efi_memmap_walk(build_mem_map, 0); + +#ifdef CONFIG_IA64_SGI_AUTOTEST + automode = 1; +#endif + + for (i=0; i 5) { + set_autotest_params(); + repeatcnt = 0; + } + } else { + while (k_go == ST_IDLE); + } + + k_go = ST_INIT; + if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; + k_linecount = k_linecount & ~1; + setup_block_addresses(); + if (!preverr && dump_block_addrs_opt) + dump_block_addrs(); + + k_currentpass = pass++; + k_go = ST_RUN; + if (fail_enabled) + fail_enabled--; + + } else { + while (k_go != ST_RUN || k_currentpass != pass); + pass++; + } + + + set_leds(errs); + set_thread_state(cpuid, TS_RUNNING); + + errs += ran_conf_llsc(cpuid); + preverr = (k_go == ST_ERRSTOP); + + set_leds(errs); + set_thread_state(cpuid, TS_STOPPED); + + if (is_master) { + Speedo(); + for (i=0, cpu=0; cputhreadstate == TS_RUNNING) { + i++; + if (i == 10000) { + k_go = ST_STOP; + printk (" llsc master stopping test number %ld\n", k_testnumber); + } + if (i > 100000) { + k_threadprivate[cpu]->threadstate = TS_KILLED; + printk (" llsc: master killing cpuid %d, running test number %ld\n", + cpu, k_testnumber); + } + udelay(1000); + } + } + } + + goto loop; +} + + +static void +Speedo(void) +{ + static int i = 0; + + switch (++i%4) { + case 0: + printk("|\b"); + break; + case 1: + printk("\\\b"); + break; + case 2: + printk("-\b"); + break; + case 3: + printk("/\b"); + break; + } +} + +#ifdef INTTEST + +/* ======================================================================================================== + * + * Some test code to verify that interrupts work + * + * Add the following to the arch/ia64/kernel/smp.c after the comment "Reschedule callback" + * if (zzzprint_resched) printk(" cpu %d got interrupt\n", smp_processor_id()); + * + * Enable the code in arch/ia64/sn/sn1/smp.c to print sending IPIs. + * + */ + +static int __init set_inttest(char *str) +{ + inttest = 1; + autotest_enabled = 1; + + return 1; +} + +__setup("inttest=", set_inttest); + +int zzzprint_resched=0; + +void +int_test() { + int mycpu, cpu; + static volatile int control_cpu=0; + + mycpu = smp_processor_id(); + zzzprint_resched = 2; + + printk("Testing cross interrupts\n"); + + while (control_cpu != smp_num_cpus) { + if (mycpu == cpu_logical_map(control_cpu)) { + for (cpu=0; cpulock[(i)] +#define LOCK(i) set_lock(LOCKADDR(i), lockpat) +#define UNLOCK(i) clr_lock(LOCKADDR(i), lockpat) +#define GETLOCK(i) *LOCKADDR(i) +#define ZEROLOCK(i) init_lock(LOCKADDR(i)) + +#define CACHEALIGN(a) ((char*)((long)(a) & ~127L)) + +typedef uint guard_t; +typedef uint lock_t; +typedef uint share_t; +typedef uchar private_t; + +typedef struct { + guard_t guard1; + lock_t lock[2]; + share_t share[2]; + private_t private[LLSC_MAXCPUS]; + share_t share0; + share_t share1; + guard_t guard2; +} dataline_t ; + + +#define LINEPAD k_linepad +#define LINESTRIDE (((sizeof(dataline_t)+CACHELINE-1)/CACHELINE)*CACHELINE + LINEPAD) + + +typedef struct { + vint threadstate; + uint threadpasses; + private_t private[MAX_LINECOUNT]; +} threadprivate_t; + +typedef struct { + vlong sk_go; /* 0=idle, 1=init, 2=run */ + long sk_linecount; + long sk_passes; + long sk_napticks; + long sk_stop_on_error; + long sk_verbose; + long sk_iter_msg; + long sk_vv; + long sk_linepad; + long sk_options; + long sk_testnumber; + vlong sk_currentpass; + void *sk_blocks; + threadprivate_t *sk_threadprivate[LLSC_MAXCPUS]; +} control_t; + +/* Run state (k_go) constants */ +#define ST_IDLE 0 +#define ST_INIT 1 +#define ST_RUN 2 +#define ST_STOP 3 +#define ST_ERRSTOP 4 + + +/* Threadstate constants */ +#define TS_STOPPED 0 +#define TS_RUNNING 1 +#define TS_KILLED 2 + + + +int llsc_main (int cpuid); + diff -urN linux-2.4.18/arch/ia64/sn/kernel/machvec.c linux-2.4.19-pre5/arch/ia64/sn/kernel/machvec.c --- linux-2.4.18/arch/ia64/sn/kernel/machvec.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/machvec.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include + +#ifdef CONFIG_IA64_SGI_SN1 +#define MACHVEC_PLATFORM_NAME sn1 +#else CONFIG_IA64_SGI_SN1 +#define MACHVEC_PLATFORM_NAME sn2 +#else +#error "unknown platform" +#endif + +#include +#include +#include +void* +sn_mk_io_addr_MACRO + +dma_addr_t +sn_pci_map_single_MACRO + +int +sn_pci_map_sg_MACRO + +unsigned long +sn_virt_to_phys_MACRO + +void * +sn_phys_to_virt_MACRO diff -urN linux-2.4.18/arch/ia64/sn/kernel/mca.c linux-2.4.19-pre5/arch/ia64/sn/kernel/mca.c --- linux-2.4.18/arch/ia64/sn/kernel/mca.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/mca.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,280 @@ +/* + * File: mca.c + * Purpose: SN specific MCA code. + * + * Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static char *shub_mmr_names[] = { + "sh_event_occurred", + "sh_first_error", + "sh_event_overflow", + +/* PI */ + "sh_pi_first_error", + "sh_pi_error_summary", + "sh_pi_error_overflow", + +/* PI HW */ + "sh_pi_error_detail_1", + "sh_pi_error_detail_2", + "sh_pi_hw_time_stamp", + +/* PI UCE */ + "sh_pi_uncorrected_detail_1", + "sh_pi_uncorrected_detail_2", + "sh_pi_uncorrected_detail_3", + "sh_pi_uncorrected_detail_4", + "sh_pi_uncor_time_stamp", + +/* PI CE */ + "sh_pi_corrected_detail_1", + "sh_pi_corrected_detail_2", + "sh_pi_corrected_detail_3", + "sh_pi_corrected_detail_4", + "sh_pi_cor_time_stamp", + +/* MD */ + "sh_mem_error_summary", + "sh_mem_error_overflow", +/* MD HW */ + "sh_misc_err_hdr_upper", + "sh_misc_err_hdr_lower", + "sh_md_dqlp_mmr_xperr_val", + "sh_md_dqlp_mmr_yperr_val", + "sh_md_dqrp_mmr_xperr_val", + "sh_md_dqrp_mmr_yperr_val", + "sh_md_hw_time_stamp", + +/* MD UCE */ + "sh_dir_uc_err_hdr_lower", + "sh_dir_uc_err_hdr_upper", + "sh_md_dqlp_mmr_xuerr1", + "sh_md_dqlp_mmr_xuerr2", + "sh_md_dqlp_mmr_yuerr1", + "sh_md_dqlp_mmr_yuerr2", + "sh_md_dqrp_mmr_xuerr1", + "sh_md_dqrp_mmr_xuerr2", + "sh_md_dqrp_mmr_yuerr1", + "sh_md_dqrp_mmr_yuerr2", + "sh_md_uncor_time_stamp", + +/* MD CE */ + "sh_dir_cor_err_hdr_lower", + "sh_dir_cor_err_hdr_upper", + "sh_md_dqlp_mmr_xcerr1", + "sh_md_dqlp_mmr_xcerr2", + "sh_md_dqlp_mmr_ycerr1", + "sh_md_dqlp_mmr_ycerr2", + "sh_md_dqrp_mmr_xcerr1", + "sh_md_dqrp_mmr_xcerr2", + "sh_md_dqrp_mmr_ycerr1", + "sh_md_dqrp_mmr_ycerr2", + "sh_md_cor_time_stamp", + +/* MD CE, UCE */ + "sh_md_dqls_mmr_xamopw_err", + "sh_md_dqrs_mmr_yamopw_err", + +/* XN */ + "sh_xn_error_summary", + "sh_xn_first_error", + "sh_xn_error_overflow", + +/* XN HW */ + "sh_xniilb_error_summary", + "sh_xniilb_first_error", + "sh_xniilb_error_overflow", + "sh_xniilb_error_detail_1", + "sh_xniilb_error_detail_2", + "sh_xniilb_error_detail_3", + + "sh_ni0_error_summary_1", + "sh_ni0_first_error_1", + "sh_ni0_error_overflow_1", + + "sh_ni0_error_summary_2", + "sh_ni0_first_error_2", + "sh_ni0_error_overflow_2", + "sh_ni0_error_detail_1", + "sh_ni0_error_detail_2", + "sh_ni0_error_detail_3", + + "sh_ni1_error_summary_1", + "sh_ni1_first_error_1", + "sh_ni1_error_overflow_1", + + "sh_ni1_error_summary_2", + "sh_ni1_first_error_2", + "sh_ni1_error_overflow_2", + + "sh_ni1_error_detail_1", + "sh_ni1_error_detail_2", + "sh_ni1_error_detail_3", + + "sh_xn_hw_time_stamp", + +/* XN HW & UCE & SBE */ + "sh_xnpi_error_summary", + "sh_xnpi_first_error", + "sh_xnpi_error_overflow", + "sh_xnpi_error_detail_1", + + "sh_xnmd_error_summary", + "sh_xnmd_first_error", + "sh_xnmd_error_overflow", + "sh_xnmd_ecc_err_report", + "sh_xnmd_error_detail_1", + +/* XN UCE */ + "sh_xn_uncorrected_detail_1", + "sh_xn_uncorrected_detail_2", + "sh_xn_uncorrected_detail_3", + "sh_xn_uncorrected_detail_4", + "sh_xn_uncor_time_stamp", + +/* XN CE */ + "sh_xn_corrected_detail_1", + "sh_xn_corrected_detail_2", + "sh_xn_corrected_detail_3", + "sh_xn_corrected_detail_4", + "sh_xn_cor_time_stamp", + +/* LB HW */ + "sh_lb_error_summary", + "sh_lb_first_error", + "sh_lb_error_overflow", + "sh_lb_error_detail_1", + "sh_lb_error_detail_2", + "sh_lb_error_detail_3", + "sh_lb_error_detail_4", + "sh_lb_error_detail_5", + "sh_junk_error_status", +}; + +void +sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) +{ + sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data; + u64 *mmr_val = (u64 *)&(sh_info->shub_state); + char **mmr_name = shub_mmr_names; + int mmr_count = sizeof(sal_log_shub_state_t)>>3; + + while(mmr_count) { + if(*mmr_val) { + prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val); + } + mmr_name++; + mmr_val++; + mmr_count--; + } + +} + +sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) +{ + struct ia64_sal_retval isrv; + + /* + * this function's sole purpose is to call SAL when we receive + * a CE interrupt from SHUB or when the timer routine decides + * we need to call SAL to check for CEs. + */ + + /* CALL SAL_LOG_CE */ + SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0); +} + +#include + +#define CPEI_INTERVAL (HZ/100) +struct timer_list sn_cpei_timer; +void sn_init_cpei_timer(void); + +void +sn_cpei_timer_handler(unsigned long dummy) { + sn_cpei_handler(-1, NULL, NULL); + del_timer(&sn_cpei_timer); + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + add_timer(&sn_cpei_timer); +} + +void +sn_init_cpei_timer() { + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_timer.function = sn_cpei_timer_handler; + add_timer(&sn_cpei_timer); +} + +#ifdef ajmtestceintr + +struct timer_list sn_ce_timer; + +void +sn_ce_timer_handler(long dummy) { + unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; + + *pi_ce_error_inject_reg = 0x0000000000000100; + del_timer(&sn_ce_timer); + sn_ce_timer.expires = jiffies + CPEI_INTERVAL; + add_timer(&sn_ce_timer); +} + +sn_init_ce_timer() { + sn_ce_timer.expires = jiffies + CPEI_INTERVAL; + sn_ce_timer.function = sn_ce_timer_handler; + add_timer(&sn_ce_timer); +} +#endif /* ajmtestceintr */ diff -urN linux-2.4.18/arch/ia64/sn/kernel/misctest.c linux-2.4.19-pre5/arch/ia64/sn/kernel/misctest.c --- linux-2.4.18/arch/ia64/sn/kernel/misctest.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/misctest.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,122 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + + +extern int autotest_enabled; +int mcatest=0; + + + +/* + * mcatest + * 1 = expected MCA + * 2 = unexpected MCA + * 3 = expected MCA + unexpected MCA + * 4 = INIT + * 5 = speculative load to garbage memory address + * 6 = speculative load with ld8.s (needs poison hack in PROM) + * 7 = speculative load from mis-predicted branch (needs poison hack in PROM) + */ +static int __init set_mcatest(char *str) +{ + get_option(&str, &mcatest); + return 1; +} + +__setup("mcatest=", set_mcatest); + +void +sgi_mcatest(void) +{ + if (mcatest == 1 || mcatest == 3) { + long *p, result, adrs[] = {0xc0000a000f021004UL, 0xc0000a000f026004UL, 0x800000000, 0x500000, 0}; + long size[] = {1,2,4,8}; + int r, i, j; + p = (long*)0xc000000000000000UL; + ia64_fc(p); + *p = 0x0123456789abcdefL; + for (i=0; i<5; i++) { + for (j=0; j<4; j++) { + printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); + result = -1; + r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); + printk(" status %d, val 0x%lx\n", r, result); + } + } + } + if (mcatest == 2 || mcatest == 3) { + void zzzmca(int, int, int); + printk("About to cause unexpected MCA\n"); + zzzmca(mcatest, 0x32dead, 0x33dead); + } + if (mcatest == 4) { + long *p; + int delivery_mode = 5; + printk("About to try to cause an INIT on cpu 0\n"); + p = (long*)((0xc0000a0000000000LL | ((long)get_nasid())<<33) | 0x1800080); + *p = (delivery_mode << 8); + udelay(10000); + printk("Returned from INIT\n"); + } + if (mcatest == 5) { + int zzzspec(long); + int i; + long flags, dcr, res, val, addr=0xff00000000UL; + + dcr = ia64_get_dcr(); + for (i=0; i<5; i++) { + printk("Default DCR: 0x%lx\n", ia64_get_dcr()); + printk("zzzspec: 0x%x\n", zzzspec(addr)); + ia64_set_dcr(0); + printk("New DCR: 0x%lx\n", ia64_get_dcr()); + printk("zzzspec: 0x%x\n", zzzspec(addr)); + ia64_set_dcr(dcr); + res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val); + printk("zzzspec: probe %ld, 0x%lx\n", res, val); + ia64_clear_ic(flags); + ia64_itc(0x2, 0xe00000ff00000000UL, + pte_val(mk_pte_phys(0xff00000000UL, + __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M); + local_irq_restore(flags); + ia64_srlz_i (); + } + + } + if (mcatest == 6) { + int zzzspec(long); + int i; + long dcr, addr=0xe000000008000000UL; + + dcr = ia64_get_dcr(); + for (i=0; i<5; i++) { + printk("zzzspec: 0x%x\n", zzzspec(addr)); + ia64_set_dcr(0); + } + ia64_set_dcr(dcr); + } + if (mcatest == 7) { + int zzzspec2(long, long); + int i; + long addr=0xe000000008000000UL; + long addr2=0xe000000007000000UL; + + for (i=0; i<5; i++) { + printk("zzzspec2\n"); + zzzspec2(addr, addr2); + } + } +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/probe.c linux-2.4.19-pre5/arch/ia64/sn/kernel/probe.c --- linux-2.4.18/arch/ia64/sn/kernel/probe.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/probe.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,81 @@ +/* + * Platform dependent support for IO probing. + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include + +/** + * ia64_sn_probe_io_slot - test a memory location for readability + * @paddr: physical address to probe + * @size: number bytes to read (1,2,4,8) + * @data_ptr: address to store value read by probe (-1 returned if probe fails) + * + * This function will probe a physical address to determine if + * the address can be read. If reading the address causes a BUS + * error, an error is returned. If the probe succeeds, the contents + * of the memory location is returned. + * + * Return values: + * 0 - probe successful + * 1 - probe failed (generated MCA) + * 2 - Bad arg + * <0 - PAL error + */ +u64 +ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) +{ + struct ia64_sal_retval isrv; + + SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); + + if (data_ptr) { + switch (size) { + case 1: + *((u8*)data_ptr) = (u8)isrv.v0; + break; + case 2: + *((u16*)data_ptr) = (u16)isrv.v0; + break; + case 4: + *((u32*)data_ptr) = (u32)isrv.v0; + break; + case 8: + *((u64*)data_ptr) = (u64)isrv.v0; + break; + default: + isrv.status = 2; + } + } + + return isrv.status; +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/setup.c linux-2.4.19-pre5/arch/ia64/sn/kernel/setup.c --- linux-2.4.18/arch/ia64/sn/kernel/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,415 @@ +/* + * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_IA64_MCA +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_IA64_SGI_SN2 +#include +#endif + +extern void bte_init_node (nodepda_t *, cnodeid_t, char **); +extern void bte_init_cpu (void); + +long sn_rtc_cycles_per_second; + +/* + * This is the address of the RRegs in the HSpace of the global + * master. It is used by a hack in serial.c (serial_[in|out], + * printk.c (early_printk), and kdb_io.c to put console output on that + * node's Bedrock UART. It is initialized here to 0, so that + * early_printk won't try to access the UART before + * master_node_bedrock_address is properly calculated. + */ +u64 master_node_bedrock_address = 0UL; + +static void sn_init_pdas(char **); + +extern struct irq_desc *_sn_irq_desc[]; + +#if defined(CONFIG_IA64_SGI_SN1) +extern synergy_da_t *Synergy_da_indr[]; +#endif + +static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; + +#ifdef CONFIG_IA64_SGI_SN2 +irqpda_t *irqpdaindr[NR_CPUS]; +#endif /* CONFIG_IA64_SGI_SN2 */ + + +/* + * 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 sn_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]; + +/** + * sn_map_nr - return the mem_map entry for a given kernel address + * @addr: kernel address to query + * + * Finds the mem_map entry for the kernel address given. Used by + * virt_to_page() (asm-ia64/page.h), among other things. + */ +unsigned long +sn_map_nr (unsigned long addr) +{ + return MAP_NR_DISCONTIG(addr); +} + +/** + * early_sn_setup - early setup routine for SN platforms + * + * Sets up an intial console to aid debugging. Intended primarily + * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK + * are turned on. See start_kernel() in init/main.c. + */ +#if defined(CONFIG_IA64_EARLY_PRINTK) && defined(CONFIG_IA64_SGI_SN) +void __init +early_sn_setup(void) +{ + if ( IS_RUNNING_ON_SIMULATOR() ) { +#if defined(CONFIG_IA64_SGI_SN1) + master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); +#else + master_node_bedrock_address = (u64)REMOTE_HUB(get_nasid(), SH_JUNK_BUS_UART0); +#endif + printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); + } +} +#endif /* CONFIG_IA64_EARLY_PRINTK && CONFIG_IA64_SGI_SN */ + +#ifdef NOT_YET_CONFIG_IA64_MCA +extern void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs); +static struct irqaction mca_cpe_irqaction = { + handler: ia64_mca_cpe_int_handler, + flags: SA_INTERRUPT, + name: "cpe_hndlr" +}; +#endif +#ifdef CONFIG_IA64_MCA +extern int platform_irq_list[]; +#endif + +extern nasid_t master_nasid; + +/** + * sn_setup - SN platform setup routine + * @cmdline_p: kernel command line + * + * Handles platform setup for SN machines. This includes determining + * the RTC frequency (via a SAL call), initializing secondary CPUs, and + * setting up per-node data areas. The console is also initialized here. + */ +void __init +sn_setup(char **cmdline_p) +{ + long status, ticks_per_sec, drift; + int i; + + master_nasid = get_nasid(); + (void)get_console_nasid(); + + status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift); + if (status != 0 || ticks_per_sec < 100000) + printk(KERN_WARNING "unable to determine platform RTC clock frequency\n"); + else + sn_rtc_cycles_per_second = ticks_per_sec; + + for (i=0;ithread.flags |= IA64_THREAD_FPEMU_NOPRINT; +} + +/** + * sn_init_pdas - setup node data areas + * + * One time setup for Node Data Area. Called by sn_setup(). + */ +void +sn_init_pdas(char **cmdline_p) +{ + cnodeid_t cnode; + + /* + * Make sure that the PDA fits entirely in the same page as the + * cpu_data area. + */ + if ((PDAADDR&~PAGE_MASK)+sizeof(pda_t) > PAGE_SIZE) + panic("overflow of cpu_data page"); + + /* + * Allocate & initalize the nodepda for each node. + */ + for (cnode=0; cnode < numnodes; cnode++) { + nodepdaindr[cnode] = alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t)); + memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); + +#if defined(CONFIG_IA64_SGI_SN1) + Synergy_da_indr[cnode * 2] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); + Synergy_da_indr[cnode * 2 + 1] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); + memset(Synergy_da_indr[cnode * 2], 0, sizeof(synergy_da_t)); + memset(Synergy_da_indr[cnode * 2 + 1], 0, sizeof(synergy_da_t)); +#endif + } + + /* + * Now copy the array of nodepda pointers to each nodepda. + */ + for (cnode=0; cnode < numnodes; cnode++) + memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); + + + /* + * Set up IO related platform-dependent nodepda fields. + * The following routine actually sets up the hubinfo struct + * in nodepda. + */ + for (cnode = 0; cnode < numnodes; cnode++) { + init_platform_nodepda(nodepdaindr[cnode], cnode); + bte_init_node (nodepdaindr[cnode], cnode, cmdline_p); + } +} + +/** + * sn_cpu_init - initialize per-cpu data areas + * @cpuid: cpuid of the caller + * + * Called during cpu initialization on each cpu as it starts. + * Currently, initializes the per-cpu data area for SNIA. + * Also sets up a few fields in the nodepda. Also known as + * platform_cpu_init() by the ia64 machvec code. + */ +void __init +sn_cpu_init(void) +{ + int cpuid; + int cpuphyid; + int nasid; + int slice; + int cnode; + + /* + * The boot cpu makes this call again after platform initialization is + * complete. + */ + if (nodepdaindr[0] == NULL) + return; + + cpuid = smp_processor_id(); + cpuphyid = ((ia64_get_lid() >> 16) & 0xffff); + nasid = cpu_physical_id_to_nasid(cpuphyid); + cnode = nasid_to_cnodeid(nasid); + slice = cpu_physical_id_to_slice(cpuphyid); + + pda.p_nodepda = nodepdaindr[cnode]; + pda.led_address = (long*) (LED0 + (slice<active_cpu_count == 1) + nodepda->node_first_cpu = cpuid; + +#ifdef CONFIG_IA64_SGI_SN1 + { + int synergy; + synergy = cpu_physical_id_to_synergy(cpuphyid); + pda.p_subnodepda = &nodepdaindr[cnode]->snpda[synergy]; + } +#endif + +#ifdef CONFIG_IA64_SGI_SN2 + + /* + * We must use different memory allocators for first cpu (bootmem + * allocator) than for the other cpus (regular allocator). + */ + if (cpuid == 0) + irqpdaindr[cpuid] = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t)); + else + irqpdaindr[cpuid] = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL, get_order(sizeof(irqpda_t)))); + memset(irqpdaindr[cpuid], 0, sizeof(irqpda_t)); + pda.p_irqpda = irqpdaindr[cpuid]; + pda.pio_write_status_addr = (volatile unsigned long *)LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); +#endif + +#ifdef CONFIG_IA64_SGI_SN1 + pda.bedrock_rev_id = (volatile unsigned long *) LOCAL_HUB(LB_REV_ID); + if (cpuid_to_synergy(cpuid)) + /* CPU B */ + pda.pio_write_status_addr = (volatile unsigned long *) GBL_PERF_B_ADDR; + else + /* CPU A */ + pda.pio_write_status_addr = (volatile unsigned long *) GBL_PERF_A_ADDR; +#endif + + + bte_init_cpu(); +} + + +/** + * cnodeid_to_cpuid - convert a cnode to a cpuid of a cpu on the node. + * @cnode: node to get a cpuid from + * + * Returns -1 if no cpus exist on the node. + * NOTE:BRINGUP ZZZ This is NOT a good way to find cpus on the node. + * Need a better way!! + */ +int +cnodeid_to_cpuid(int cnode) { + int cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) + if (cpuid_to_cnodeid(cpu) == cnode) + break; + + if (cpu == smp_num_cpus) + cpu = -1; + + return cpu; +} + +#if 0 /* ##jh */ +/** + * get_cycles - return a non-decreasing timestamp + * + * On SN, we use an RTC read for this function + */ +cycles_t +get_cycles (void) +{ + return GET_RTC_COUNTER(); +} +#endif diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn1/Makefile linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/Makefile --- linux-2.4.18/arch/ia64/sn/kernel/sn1/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,51 @@ +# +# ia64/platform/sn/sn1/Makefile +# +# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/NoticeExplan +# + + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +.S.s: + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< +.S.o: + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< + +all: sn1.a + +O_TARGET = sn1.a + +obj-y = cache.o error.o iomv.o synergy.o sn1_smp.o + +clean:: + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn1/cache.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/cache.c --- linux-2.4.18/arch/ia64/sn/kernel/sn1/cache.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/cache.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,81 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +#ifndef MB +#define MB (1024*1024) +#endif + +/* + * Lock for protecting SYN_TAG_DISABLE_WAY. + * Consider making this a per-FSB lock. + */ +static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED; + +/** + * sn_flush_all_caches - flush a range of addresses from all caches (incl. L4) + * @flush_addr: identity mapped region 7 address to start flushing + * @bytes: number of bytes to flush + * + * Flush a range of addresses from all caches including L4. All addresses + * fully or partially contained within @flush_addr to @flush_addr + @bytes + * are flushed from the all caches. + */ +void +sn_flush_all_caches(long flush_addr, long bytes) +{ + ulong addr, baddr, eaddr, bitbucket; + int way, alias; + + /* + * Because of the way synergy implements "fc", this flushes the + * data from all caches on all cpus & L4's on OTHER FSBs. It also + * flushes both cpus on the local FSB. It does NOT flush it from + * the local FSB. + */ + flush_icache_range(flush_addr, flush_addr+bytes); + + /* + * Memory DIMMs are a minimum of 256MB and start on 256MB + * boundaries. Convert the start address to an address + * that is between +0MB & +128 of the same DIMM. + * Then add 8MB to skip the uncached MinState areas if the address + * is on the master node. + */ + if (bytes > SYNERGY_L4_BYTES_PER_WAY) + bytes = SYNERGY_L4_BYTES_PER_WAY; + baddr = TO_NODE(smp_physical_node_id(), PAGE_OFFSET + (flush_addr & (128*MB-1)) + 8*MB); + eaddr = (baddr+bytes+SYNERGY_BLOCK_SIZE-1) & ~(SYNERGY_BLOCK_SIZE-1); + baddr = baddr & ~(SYNERGY_BLOCK_SIZE-1); + + /* + * Now flush the local synergy. + */ + spin_lock(&flush_lock); + for(way=0; way +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * snia_error_intr_handler - handle SN specific error interrupts + * @irq: error interrupt received + * @devid: device causing the interrupt + * @pt_regs: saved register state + * + * This routine is called when certain interrupts occur on SN systems. + * It will either recover from the situations that caused the interrupt + * or panic. + */ +void +snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) +{ + unsigned long long intpend_val; + unsigned long long bit; + + switch (irq) { + case SGI_UART_IRQ: + /* + * This isn't really an error interrupt. We're just + * here because we have to do something with them. + * This is probably wrong, and this code will be + * removed. + */ + intpend_val = LOCAL_HUB_L(PI_INT_PEND0); + if ( (bit = ~(1L< +#include +#include +#include +#include + +/** + * sn_io_addr - convert an in/out port to an i/o address + * @port: port to convert + * + * Legacy in/out instructions are converted to ld/st instructions + * on IA64. This routine will convert a port number into a valid + * SN i/o address. Used by sn_in*() and sn_out*(). + */ +void * +sn_io_addr(unsigned long port) +{ + if (!IS_RUNNING_ON_SIMULATOR()) { + return( (void *) (port | __IA64_UNCACHED_OFFSET)); + } else { + unsigned long io_base; + unsigned long addr; + + /* + * word align port, but need more than 10 bits + * for accessing registers in bedrock local block + * (so we don't do port&0xfff) + */ + if ((port >= 0x1f0 && port <= 0x1f7) || + port == 0x3f6 || port == 0x3f7) { + io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; + addr = io_base | ((port >> 2) << 12) | (port & 0xfff); + } else { + addr = __ia64_get_io_port_base() | ((port >> 2) << 2); + } + return(void *) addr; + } +} + +/** + * sn1_mmiob - I/O space memory barrier + * + * Acts as a memory mapped I/O barrier for platforms that queue writes to + * I/O space. This ensures that subsequent writes to I/O space arrive after + * all previous writes. For most ia64 platforms, this is a simple + * 'mf.a' instruction. For other platforms, mmiob() may have to read + * a chipset register to ensure ordering. + * + * On SN1, we wait for the PIO_WRITE_STATUS Bedrock register to clear. + */ +void +sn1_mmiob (void) +{ + (volatile unsigned long) (*pda.bedrock_rev_id); + while (!(volatile unsigned long) (*pda.pio_write_status_addr)) + udelay(5); +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn1/sn1_smp.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/sn1_smp.c --- linux-2.4.18/arch/ia64/sn/kernel/sn1/sn1_smp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/sn1_smp.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,474 @@ +/* + * SN1 Platform specific SMP Support + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The following structure is used to pass params thru smp_call_function + * to other cpus for flushing TLB ranges. + */ +typedef struct { + unsigned long start; + unsigned long end; + unsigned long nbits; + unsigned int rid; + atomic_t unfinished_count; +} ptc_params_t; + +#define NUMPTC 512 + +static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); + +/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ +static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); +static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; + +/*REFERENCED*/ +static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; + +static int ptcInit = 0; +#ifdef PTCDEBUG +static int ptcParamsAllBusy = 0; /* debugging/statistics */ +static int ptcCountBacklog = 0; +static int ptcBacklog[NUMPTC+1]; +static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); +static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); +#endif + +/* + * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, + * so that we get a clean compile with the ia64 patch without the + * actual SN1 specific code in arch/ia64/kernel/smp.c. + */ +extern void smp_send_flush_tlb (void) __attribute((weak)); + +/* + * The following table/struct is for remembering PTC coherency domains. It + * is also used to translate sapicid into cpuids. We dont want to start + * cpus unless we know their cache domain. + */ +#ifdef PTC_NOTYET +sn_sapicid_info_t sn_sapicid_info[NR_CPUS]; +#endif + +/** + * sn1_ptc_l_range - purge local translation cache + * @start: start of virtual address range + * @end: end of virtual address range + * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) + * + * Purges the range specified from the local processor's translation cache + * (as opposed to the translation registers). Note that more than the specified + * range *may* be cleared from the cache by some processors. + * + * This is probably not good enough, but I don't want to try to make it better + * until I get some statistics on a running system. At a minimum, we should only + * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's + * own FSB. Also, we only have to serialize per FSB, not globally. + * + * More likely, we will have to do some work to reduce the frequency of calls to + * this routine. + */ +static inline void +sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) +{ + do { + __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); + start += (1UL << nbits); + } while (start < end); + ia64_srlz_d(); +} + +/** + * sn1_received_flush_tlb - cpu tlb flush routine + * + * Flushes the TLB of a given processor. + */ +void +sn1_received_flush_tlb(void) +{ + unsigned long start, end, nbits; + unsigned int rid, saved_rid; + int cpu = smp_processor_id(); + int result; + ptc_params_t *ptcParams; + + ptcParams = ptcParamsNextByCpu[cpu*16]; + if (ptcParams == ptcParamsEmpty) + return; + + do { + start = ptcParams->start; + saved_rid = (unsigned int) ia64_get_rr(start); + end = ptcParams->end; + nbits = ptcParams->nbits; + rid = ptcParams->rid; + + if (saved_rid != rid) { + ia64_set_rr(start, (unsigned long)rid); + ia64_srlz_d(); + } + + sn1_ptc_l_range(start, end, nbits); + + if (saved_rid != rid) + ia64_set_rr(start, (unsigned long)saved_rid); + + ia64_srlz_i(); + + result = atomic_dec(&ptcParams->unfinished_count); +#ifdef PTCDEBUG + { + int i = ptcParams-&ptcParamArray[0]; + ptcParamsResults[cpu][i] = (char) result; + ptcParamsCounts[cpu][i]++; + } +#endif /* PTCDEBUG */ + + if (++ptcParams == &ptcParamArray[NUMPTC]) + ptcParams = &ptcParamArray[0]; + + } while (ptcParams != ptcParamsEmpty); + + ptcParamsNextByCpu[cpu*16] = ptcParams; +} + +/** + * sn1_global_tlb_purge - flush a translation cache range on all processors + * @start: start of virtual address range to flush + * @end: end of virtual address range + * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) + * + * Flushes the translation cache of all processors from @start to @end. + */ +void +sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +{ + ptc_params_t *params; + ptc_params_t *next; + unsigned long irqflags; +#ifdef PTCDEBUG + ptc_params_t *nextnext; + int backlog = 0; +#endif + + if (smp_num_cpus == 1) { + sn1_ptc_l_range(start, end, nbits); + return; + } + + if (in_interrupt()) { + /* + * If at interrupt level and cannot get spinlock, + * then do something useful by flushing own tlbflush queue + * so as to avoid a possible deadlock. + */ + while (!spin_trylock(&ptcParamsLock)) { + local_irq_save(irqflags); + sn1_received_flush_tlb(); + local_irq_restore(irqflags); + udelay(10); /* take it easier on the bus */ + } + } else { + spin_lock(&ptcParamsLock); + } + + if (!ptcInit) { + int cpu; + ptcInit = 1; + memset(ptcParamArray, 0, sizeof(ptcParamArray)); + ptcParamsEmpty = &ptcParamArray[0]; + for (cpu=0; cpu= &ptcParamArray[0]) { + if (atomic_read(&ptr->unfinished_count) == 0) + break; + ++backlog; + } + + if (backlog) { + /* check the end of the array */ + ptr = &ptcParamArray[NUMPTC]; + while (--ptr > params) { + if (atomic_read(&ptr->unfinished_count) == 0) + break; + ++backlog; + } + } + ptcBacklog[backlog]++; + } +#endif /* PTCDEBUG */ + + /* wait for the next entry to clear...should be rare */ + if (atomic_read(&next->unfinished_count) > 0) { +#ifdef PTCDEBUG + ptcParamsAllBusy++; + + if (atomic_read(&nextnext->unfinished_count) == 0) { + if (atomic_read(&next->unfinished_count) > 0) { + panic("\nnonzero next zero nextnext %lx %lx\n", + (long)next, (long)nextnext); + } + } +#endif + + /* it could be this cpu that is behind */ + local_irq_save(irqflags); + sn1_received_flush_tlb(); + local_irq_restore(irqflags); + + /* now we know it's not this cpu, so just wait */ + while (atomic_read(&next->unfinished_count) > 0) { + barrier(); + } + } + + params->start = start; + params->end = end; + params->nbits = nbits; + params->rid = (unsigned int) ia64_get_rr(start); + atomic_set(¶ms->unfinished_count, smp_num_cpus); + + /* The atomic_set above can hit memory *after* the update + * to ptcParamsEmpty below, which opens a timing window + * that other cpus can squeeze into! + */ + mb(); + + /* everything is ready to process: + * -- global lock is held + * -- new entry + 1 is free + * -- new entry is set up + * so now: + * -- update the global next pointer + * -- unlock the global lock + * -- send IPI to notify other cpus + * -- process the data ourselves + */ + ptcParamsEmpty = next; + spin_unlock(&ptcParamsLock); + smp_send_flush_tlb(); + + local_irq_save(irqflags); + sn1_received_flush_tlb(); + local_irq_restore(irqflags); + + /* Currently we don't think global TLB purges need to be atomic. + * All CPUs get sent IPIs, so if they haven't done the purge, + * they're busy with interrupts that are at the IPI level, which is + * priority 15. We're asserting that any code at that level + * shouldn't be using user TLB entries. To change this to wait + * for all the flushes to complete, enable the following code. + */ +#ifdef SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE + /* this code is not tested */ + /* wait for the flush to complete */ + while (atomic_read(¶ms.unfinished_count) > 1) + barrier(); + + atomic_set(¶ms->unfinished_count, 0); +#endif +} + +/** + * sn_send_IPI_phys - send an IPI to a Nasid and slice + * @physid: physical cpuid to receive the interrupt. + * @vector: command to send + * @delivery_mode: delivery mechanism + * + * Sends an IPI (interprocessor interrupt) to the processor specified by + * @physid + * + * @delivery_mode can be one of the following + * + * %IA64_IPI_DM_INT - pend an interrupt + * %IA64_IPI_DM_PMI - pend a PMI + * %IA64_IPI_DM_NMI - pend an NMI + * %IA64_IPI_DM_INIT - pend an INIT interrupt + */ +void +sn_send_IPI_phys(long physid, int vector, int delivery_mode) +{ + long *p; + long nasid, slice; + + static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; + + nasid = cpu_physical_id_to_nasid(physid); + slice = cpu_physical_id_to_slice(physid); + + p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); + +#if defined(ZZZBRINGUP) + { + static int count=0; + if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx\n", + smp_processor_id(), vector, nasid, slice, (long)p); + } +#endif + mb(); + *p = (delivery_mode << 8) | (vector & 0xff); +} + + +/** + * sn1_send_IPI - send an IPI to a processor + * @cpuid: target of the IPI + * @vector: command to send + * @delivery_mode: delivery mechanism + * @redirect: redirect the IPI? + * + * Sends an IPI (interprocessor interrupt) to the processor specified by + * @cpuid. @delivery_mode can be one of the following + * + * %IA64_IPI_DM_INT - pend an interrupt + * %IA64_IPI_DM_PMI - pend a PMI + * %IA64_IPI_DM_NMI - pend an NMI + * %IA64_IPI_DM_INIT - pend an INIT interrupt + */ +void +sn1_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) +{ + long physid; + + physid = cpu_physical_id(cpuid); + + sn_send_IPI_phys(physid, vector, delivery_mode); +} +#ifdef CONFIG_SMP + +#ifdef PTC_NOTYET +static void __init +process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) +{ + ia64_sal_ptc_domain_proc_entry_t *pe; + int i, sapicid, cpuid; + + pe = __va(di->proc_list); + for (i=0; iproc_count; i++, pe++) { + sapicid = id_eid_to_sapicid(pe->id, pe->eid); + cpuid = cpu_logical_id(sapicid); + sn_sapicid_info[cpuid].domain = domain; + sn_sapicid_info[cpuid].sapicid = sapicid; + } +} + + +static void __init +process_sal_desc_ptc(ia64_sal_desc_ptc_t *ptc) +{ + ia64_sal_ptc_domain_info_t *di; + int i; + + di = __va(ptc->domain_info); + for (i=0; inum_domains; i++, di++) { + process_sal_ptc_domain_info(di, i); + } +} +#endif /* PTC_NOTYET */ + +/** + * init_sn1_smp_config - setup PTC domains per processor + */ +void __init +init_sn1_smp_config(void) +{ + if (!ia64_ptc_domain_info) { + printk("SMP: Can't find PTC domain info. Forcing UP mode\n"); + smp_num_cpus = 1; + return; + } + +#ifdef PTC_NOTYET + memset (sn_sapicid_info, -1, sizeof(sn_sapicid_info)); + process_sal_desc_ptc(ia64_ptc_domain_info); +#endif +} + +#else /* CONFIG_SMP */ + +void __init +init_sn1_smp_config(void) +{ + +#ifdef PTC_NOTYET + sn_sapicid_info[0].sapicid = hard_smp_processor_id(); +#endif +} + +#endif /* CONFIG_SMP */ diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn1/synergy.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/synergy.c --- linux-2.4.18/arch/ia64/sn/kernel/sn1/synergy.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn1/synergy.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,532 @@ +/* + * SN1 Platform specific synergy Support + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int bit_pos_to_irq(int bit); +void setclear_mask_b(int irq, int cpuid, int set); +void setclear_mask_a(int irq, int cpuid, int set); +void * kmalloc(size_t size, int flags); + +static int synergy_perf_initialized = 0; + +void +synergy_intr_alloc(int bit, int cpuid) { + return; +} + +int +synergy_intr_connect(int bit, + int cpuid) +{ + int irq; + unsigned is_b; + + irq = bit_pos_to_irq(bit); + + is_b = (cpuid_to_slice(cpuid)) & 1; + if (is_b) { + setclear_mask_b(irq,cpuid,1); + setclear_mask_a(irq,cpuid, 0); + } else { + setclear_mask_a(irq, cpuid, 1); + setclear_mask_b(irq, cpuid, 0); + } + return 0; +} +void +setclear_mask_a(int irq, int cpuid, int set) +{ + int synergy; + int nasid; + int reg_num; + unsigned long mask; + unsigned long addr; + unsigned long reg; + unsigned long val; + int my_cnode, my_synergy; + int target_cnode, target_synergy; + + /* + * Perform some idiot checks .. + */ + if ( (irq < 0) || (irq > 255) || + (cpuid < 0) || (cpuid > 512) ) { + printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid); + return; + } + + target_cnode = cpuid_to_cnodeid(cpuid); + target_synergy = cpuid_to_synergy(cpuid); + my_cnode = cpuid_to_cnodeid(smp_processor_id()); + my_synergy = cpuid_to_synergy(smp_processor_id()); + + reg_num = irq / 64; + mask = 1; + mask <<= (irq % 64); + switch (reg_num) { + case 0: + reg = VEC_MASK0A; + addr = VEC_MASK0A_ADDR; + break; + case 1: + reg = VEC_MASK1A; + addr = VEC_MASK1A_ADDR; + break; + case 2: + reg = VEC_MASK2A; + addr = VEC_MASK2A_ADDR; + break; + case 3: + reg = VEC_MASK3A; + addr = VEC_MASK3A_ADDR; + break; + default: + reg = addr = 0; + break; + } + if (my_cnode == target_cnode && my_synergy == target_synergy) { + // local synergy + val = READ_LOCAL_SYNERGY_REG(addr); + if (set) { + val |= mask; + } else { + val &= ~mask; + } + WRITE_LOCAL_SYNERGY_REG(addr, val); + val = READ_LOCAL_SYNERGY_REG(addr); + } else { /* remote synergy */ + synergy = cpuid_to_synergy(cpuid); + nasid = cpuid_to_nasid(cpuid); + val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); + if (set) { + val |= mask; + } else { + val &= ~mask; + } + REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); + } +} + +void +setclear_mask_b(int irq, int cpuid, int set) +{ + int synergy; + int nasid; + int reg_num; + unsigned long mask; + unsigned long addr; + unsigned long reg; + unsigned long val; + int my_cnode, my_synergy; + int target_cnode, target_synergy; + + /* + * Perform some idiot checks .. + */ + if ( (irq < 0) || (irq > 255) || + (cpuid < 0) || (cpuid > 512) ) { + printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid); + return; + } + + target_cnode = cpuid_to_cnodeid(cpuid); + target_synergy = cpuid_to_synergy(cpuid); + my_cnode = cpuid_to_cnodeid(smp_processor_id()); + my_synergy = cpuid_to_synergy(smp_processor_id()); + + reg_num = irq / 64; + mask = 1; + mask <<= (irq % 64); + switch (reg_num) { + case 0: + reg = VEC_MASK0B; + addr = VEC_MASK0B_ADDR; + break; + case 1: + reg = VEC_MASK1B; + addr = VEC_MASK1B_ADDR; + break; + case 2: + reg = VEC_MASK2B; + addr = VEC_MASK2B_ADDR; + break; + case 3: + reg = VEC_MASK3B; + addr = VEC_MASK3B_ADDR; + break; + default: + reg = addr = 0; + break; + } + if (my_cnode == target_cnode && my_synergy == target_synergy) { + // local synergy + val = READ_LOCAL_SYNERGY_REG(addr); + if (set) { + val |= mask; + } else { + val &= ~mask; + } + WRITE_LOCAL_SYNERGY_REG(addr, val); + val = READ_LOCAL_SYNERGY_REG(addr); + } else { /* remote synergy */ + synergy = cpuid_to_synergy(cpuid); + nasid = cpuid_to_nasid(cpuid); + val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); + if (set) { + val |= mask; + } else { + val &= ~mask; + } + REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); + } +} + +/* + * Synergy perf stats. Multiplexed via timer_interrupt. + */ + +static int +synergy_perf_append(uint64_t modesel) +{ + int cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int checked = 0; + int err = 0; + + /* bit 45 is enable */ + modesel |= (1UL << 45); + + for (cnode=0; cnode < numnodes; cnode++) { + /* for each node, insert a new synergy_perf entry */ + if ((npdap = NODEPDA(cnode)) == NULL) { + printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, (void *)nodepda); + continue; + } + + if (npdap->synergy_perf_enabled) { + /* user must disable counting to append new events */ + err = -EBUSY; + break; + } + + if (!checked && npdap->synergy_perf_data != NULL) { + checked = 1; + for (p = npdap->synergy_perf_first; ;) { + if (p->modesel == modesel) + return 0; /* event already registered */ + if ((p = p->next) == npdap->synergy_perf_first) + break; + } + } + + /* XX use kmem_alloc_node() when it is implemented */ + p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); + if ((((uint64_t)p) & 7UL) != 0) + BUG(); /* bad alignment */ + if (p == NULL) { + err = -ENOMEM; + break; + } + else { + memset(p, 0, sizeof(synergy_perf_t)); + p->modesel = modesel; + + spin_lock_irq(&npdap->synergy_perf_lock); + if (npdap->synergy_perf_data == NULL) { + /* circular list */ + p->next = p; + npdap->synergy_perf_first = p; + npdap->synergy_perf_data = p; + } + else { + p->next = npdap->synergy_perf_data->next; + npdap->synergy_perf_data->next = p; + } + spin_unlock_irq(&npdap->synergy_perf_lock); + } + } + + return err; +} + +static void +synergy_perf_set_freq(int freq) +{ + int cnode; + nodepda_t *npdap; + + for (cnode=0; cnode < numnodes; cnode++) { + if ((npdap = NODEPDA(cnode)) != NULL) + npdap->synergy_perf_freq = freq; + } +} + +static void +synergy_perf_set_enable(int enable) +{ + int cnode; + nodepda_t *npdap; + + for (cnode=0; cnode < numnodes; cnode++) { + if ((npdap = NODEPDA(cnode)) != NULL) + npdap->synergy_perf_enabled = enable; + } + printk("NOTICE: synergy perf counting %sabled on all nodes\n", enable ? "en" : "dis"); +} + +static int +synergy_perf_size(nodepda_t *npdap) +{ + synergy_perf_t *p; + int n; + + if (npdap->synergy_perf_enabled == 0) { + /* no stats to return */ + return 0; + } + + spin_lock_irq(&npdap->synergy_perf_lock); + for (n=0, p = npdap->synergy_perf_first; p;) { + n++; + p = p->next; + if (p == npdap->synergy_perf_first) + break; + } + spin_unlock_irq(&npdap->synergy_perf_lock); + + /* bytes == n pairs of {event,counter} */ + return n * 2 * sizeof(uint64_t); +} + +static int +synergy_perf_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int cnode; + nodepda_t *npdap; + synergy_perf_t *p; + int intarg; + int fsb; + uint64_t longarg; + uint64_t *stats; + int n; + devfs_handle_t d; + arbitrary_info_t info; + + if ((d = devfs_get_handle_from_inode(inode)) == NULL) + return -ENODEV; + info = hwgraph_fastinfo_get(d); + + cnode = SYNERGY_PERF_INFO_CNODE(info); + fsb = SYNERGY_PERF_INFO_FSB(info); + npdap = NODEPDA(cnode); + + switch (cmd) { + case SNDRV_GET_SYNERGY_VERSION: + /* return int, version of data structure for SNDRV_GET_SYNERGYINFO */ + intarg = 1; /* version 1 */ + if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) + return -EFAULT; + break; + + case SNDRV_GET_INFOSIZE: + /* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */ + intarg = synergy_perf_size(npdap); + if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) + return -EFAULT; + break; + + case SNDRV_GET_SYNERGYINFO: + /* return array of event/value pairs, this node only */ + if ((intarg = synergy_perf_size(npdap)) <= 0) + return -ENODATA; + if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL) + return -ENOMEM; + spin_lock_irq(&npdap->synergy_perf_lock); + for (n=0, p = npdap->synergy_perf_first; p;) { + stats[n++] = p->modesel; + if (p->intervals > 0) + stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals; + else + stats[n++] = 0; + p = p->next; + if (p == npdap->synergy_perf_first) + break; + } + spin_unlock_irq(&npdap->synergy_perf_lock); + + if (copy_to_user((void *)arg, stats, intarg)) { + kfree(stats); + return -EFAULT; + } + + kfree(stats); + break; + + case SNDRV_SYNERGY_APPEND: + /* reads 64bit event, append synergy perf event to all nodes */ + if (copy_from_user(&longarg, (void *)arg, sizeof(longarg))) + return -EFAULT; + return synergy_perf_append(longarg); + break; + + case SNDRV_GET_SYNERGY_STATUS: + /* return int, 1 if enabled else 0 */ + intarg = npdap->synergy_perf_enabled; + if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) + return -EFAULT; + break; + + case SNDRV_SYNERGY_ENABLE: + /* read int, if true enable counting else disable */ + if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) + return -EFAULT; + synergy_perf_set_enable(intarg); + break; + + case SNDRV_SYNERGY_FREQ: + /* read int, set jiffies per update */ + if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) + return -EFAULT; + if (intarg < 0 || intarg >= HZ) + return -EINVAL; + synergy_perf_set_freq(intarg); + break; + + default: + printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%d\n", cmd, cnode, fsb); + return -EINVAL; + } + return(0); +} + +struct file_operations synergy_mon_fops = { + ioctl: synergy_perf_ioctl, +}; + +void +synergy_perf_update(int cpu) +{ + nasid_t nasid; + cnodeid_t cnode; + struct nodepda_s *npdap; + + /* + * synergy_perf_initialized is set by synergy_perf_init() + * which is called last thing by sn_mp_setup(), i.e. well + * after nodepda has been initialized. + */ + if (!synergy_perf_initialized) + return; + + cnode = cpuid_to_cnodeid(cpu); + npdap = NODEPDA(cnode); + + if (npdap == NULL || cnode < 0 || cnode >= numnodes) + /* this should not happen: still in early io init */ + return; + +#if 0 + /* use this to check nodepda initialization */ + if (((uint64_t)npdap) & 0x7) { + printk("\nERROR on cpu %d : cnode=%d, npdap == %p, not aligned\n", cpu, cnode, npdap); + BUG(); + } +#endif + + if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) { + /* Not enabled, or no events to monitor */ + return; + } + + if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { + /* don't multiplex on every timer interrupt */ + return; + } + + /* + * Read registers for last interval and increment counters. + * Hold the per-node synergy_perf_lock so concurrent readers get + * consistent values. + */ + spin_lock_irq(&npdap->synergy_perf_lock); + + nasid = cpuid_to_nasid(cpu); + npdap->synergy_active_intervals++; + npdap->synergy_perf_data->intervals++; + npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals; + + npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); + + npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & + REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); + + /* skip to next in circular list */ + npdap->synergy_perf_data = npdap->synergy_perf_data->next; + + spin_unlock_irq(&npdap->synergy_perf_lock); + + /* set the counter 0 selection modes for both A and B */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); + + /* and reset the counter registers to zero */ + REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); + REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); +} + +void +synergy_perf_init(void) +{ + printk("synergy_perf_init(), counting is initially disabled\n"); + synergy_perf_initialized++; +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn2/Makefile linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/Makefile --- linux-2.4.18/arch/ia64/sn/kernel/sn2/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,51 @@ +# +# ia64/platform/sn/sn1/Makefile +# +# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/NoticeExplan +# + + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +.S.s: + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< +.S.o: + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< + +all: sn2.a + +O_TARGET = sn2.a + +obj-y = cache.o iomv.o sn2_smp.o + +clean:: + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn2/cache.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/cache.c --- linux-2.4.18/arch/ia64/sn/kernel/sn2/cache.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/cache.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,29 @@ +/* + * + * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * + */ + +#include + +/** + * sn_flush_all_caches - flush a range of address from all caches (incl. L4) + * @flush_addr: identity mapped region 7 address to start flushing + * @bytes: number of bytes to flush + * + * Flush a range of addresses from all caches including L4. + * All addresses fully or partially contained within + * @flush_addr to @flush_addr + @bytes are flushed + * from the all caches. + */ +void +sn_flush_all_caches(long flush_addr, long bytes) +{ + flush_icache_range(flush_addr, flush_addr+bytes); +} + + diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn2/iomv.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/iomv.c --- linux-2.4.18/arch/ia64/sn/kernel/sn2/iomv.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/iomv.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,65 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +/** + * sn_io_addr - convert an in/out port to an i/o address + * @port: port to convert + * + * Legacy in/out instructions are converted to ld/st instructions + * on IA64. This routine will convert a port number into a valid + * SN i/o address. Used by sn_in*() and sn_out*(). + */ +void * +sn_io_addr(unsigned long port) +{ + if (!IS_RUNNING_ON_SIMULATOR()) { + return( (void *) (port | __IA64_UNCACHED_OFFSET)); + } else { + unsigned long io_base; + unsigned long addr; + + /* + * word align port, but need more than 10 bits + * for accessing registers in bedrock local block + * (so we don't do port&0xfff) + */ + if ((port >= 0x1f0 && port <= 0x1f7) || + port == 0x3f6 || port == 0x3f7) { + io_base = (0xc000000fcc000000 | ((unsigned long)get_nasid() << 38)); + addr = io_base | ((port >> 2) << 12) | (port & 0xfff); + } else { + addr = __ia64_get_io_port_base() | ((port >> 2) << 2); + } + return(void *) addr; + } +} + +/** + * sn2_mmiob - I/O space memory barrier + * + * Acts as a memory mapped I/O barrier for platforms that queue writes to + * I/O space. This ensures that subsequent writes to I/O space arrive after + * all previous writes. For most ia64 platforms, this is a simple + * 'mf.a' instruction. For other platforms, mmiob() may have to read + * a chipset register to ensure ordering. + * + * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. + */ +void +sn2_mmiob (void) +{ + while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000) + udelay(5); +} diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn2/sn2_smp.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/sn2_smp.c --- linux-2.4.18/arch/ia64/sn/kernel/sn2/sn2_smp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn2/sn2_smp.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,184 @@ +/* + * SN2 Platform specific SMP Support + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * sn2_global_tlb_purge - globally purge translation cache of virtual address range + * @start: start of virtual address range + * @end: end of virtual address range + * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) + * + * Purges the translation caches of all processors of the given virtual address + * range. + */ +void +sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +{ + int cnode, nasid; + volatile long *ptc0, *ptc1, *piows; + unsigned long ws, next, data0, data1; + + piows = (long*)LOCAL_MMR_ADDR(get_slice() ? SH_PIO_WRITE_STATUS_1 : SH_PIO_WRITE_STATUS_0); + data0 = (1UL<>8)< +#ifdef CONFIG_IA64_SGI_AUTOTEST + +// Testing only. +// Routine will cause MCAs +// zzzmsa(n) +// n=0 MCA via duplicate TLB dropin +// n=0 MCA via read of garbage address +// + +#define ITIR(key, ps) ((key<<8) | (ps<<2)) +#define TLB_PAGESIZE 28 // Use 256MB pages for now. + + .global zzzmca + .proc zzzmca +zzzmca: + alloc loc4 = ar.pfs,2,8,1,0;; + cmp.ne p6,p0=r32,r0;; + movl r2=0x2dead + movl r3=0x3dead + movl r15=0x15dead + movl r16=0x16dead + movl r31=0x31dead + movl loc0=0x34beef + movl loc1=0x35beef + movl loc2=0x36beef + movl loc3=0x37beef + movl out0=0x42beef + + movl r20=0x32feed;; + mov ar32=r20 + movl r20=0x36feed;; + mov ar36=r20 + movl r20=0x65feed;; + mov ar65=r20 + movl r20=0x66feed;; + mov ar66=r20 + +(p6) br.cond.sptk 1f + + rsm 0x2000;; + srlz.d; + mov r11 = 1 + mov r3 = ITIR(0,TLB_PAGESIZE);; + mov cr.itir = r3 + mov r10 = 0;; + itr.d dtr[r11] = r10;; + mov r11 = 2 + + itr.d dtr[r11] = r10;; + br 9f + +1: movl r8=0xfe00000048;; + ld8 r9=[r8];; + mf + mf.a + srlz.d + +9: mov ar.pfs=loc4 + br.ret.sptk rp + + .endp zzzmca + + .global zzzspec + .proc zzzspec +zzzspec: + mov r8=r32 + movl r9=0xe000000000000000 + movl r10=0x4000;; + ld8.s r16=[r8];; + ld8.s r17=[r9];; + add r8=r8,r10;; + ld8.s r18=[r8];; + add r8=r8,r10;; + ld8.s r19=[r8];; + add r8=r8,r10;; + ld8.s r20=[r8];; + mov r8=r0 + tnat.nz p6,p0=r16 + tnat.nz p7,p0=r17 + tnat.nz p8,p0=r18 + tnat.nz p9,p0=r19 + tnat.nz p10,p0=r20;; + (p6) dep r8=-1,r8,0,1;; + (p7) dep r8=-1,r8,1,1;; + (p8) dep r8=-1,r8,2,1;; + (p9) dep r8=-1,r8,3,1;; + (p10) dep r8=-1,r8,4,1;; + br.ret.sptk rp + .endp zzzspec + + .global zzzspec2 + .proc zzzspec2 +zzzspec2: + cmp.eq p6,p7=r2,r2 + movl r16=0xc0000a0001000020 + ;; + mf + ;; + ld8 r9=[r16] + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r16];; + cmp.ne p6,p7=r9,r16 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + ld8 r9=[r33];; + cmp.ne p6,p7=r9,r33 + (p6) br.spnt 1f + ld8 r10=[r32] + ;; + 1: mf.a + mf + + tpa r23=r32 + add r20=512,r33 + add r21=1024,r33;; + ld8 r9=[r20] + ld8 r10=[r21];; + nop.i 0 + { .mib + nop.m 0 + cmp.ne p6,p7=r10,r33 + (p6) br.spnt 1f + } + ld8 r10=[r32] + ;; + 1: mf.a + mf + br.ret.sptk rp + + .endp zzzspec + +#endif + diff -urN linux-2.4.18/arch/ia64/sn/kernel/sn_ksyms.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sn_ksyms.c --- linux-2.4.18/arch/ia64/sn/kernel/sn_ksyms.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sn_ksyms.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,67 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + + +/* + * Architecture-specific kernel symbols + */ + +#include +#include + +#include +#include + +/* + * other stuff (more to be added later, cleanup then) + */ +EXPORT_SYMBOL(sn_pci_map_sg); +EXPORT_SYMBOL(sn_pci_unmap_sg); +EXPORT_SYMBOL(sn_pci_alloc_consistent); +EXPORT_SYMBOL(sn_pci_free_consistent); +EXPORT_SYMBOL(sn_dma_address); + +#include +#include +extern devfs_handle_t base_io_scsi_ctlr_vhdl[]; +#include +extern cnodeid_t master_node_get(devfs_handle_t vhdl); +#include +EXPORT_SYMBOL(base_io_scsi_ctlr_vhdl); +EXPORT_SYMBOL(master_node_get); + + +/* + * symbols referenced by the PCIBA module + */ +#include +#include +#include +#include + +devfs_handle_t +devfn_to_vertex(unsigned char busnum, unsigned int devfn); +EXPORT_SYMBOL(devfn_to_vertex); +EXPORT_SYMBOL(hwgraph_vertex_unref); +EXPORT_SYMBOL(pciio_config_get); +EXPORT_SYMBOL(pciio_info_slot_get); +EXPORT_SYMBOL(hwgraph_edge_add); +EXPORT_SYMBOL(pciio_info_master_get); +EXPORT_SYMBOL(pciio_info_get); +#ifdef CONFIG_IA64_SGI_SN_DEBUG +EXPORT_SYMBOL(__pa_debug); +EXPORT_SYMBOL(__va_debug); +#endif + +/* Support IPIs for loaded modules. */ +EXPORT_SYMBOL(sn_send_IPI_phys); + +#include +EXPORT_SYMBOL(sn_pci_unmap_single); +EXPORT_SYMBOL(sn_pci_map_single); +EXPORT_SYMBOL(sn_pci_dma_sync_single); diff -urN linux-2.4.18/arch/ia64/sn/kernel/sv.c linux-2.4.19-pre5/arch/ia64/sn/kernel/sv.c --- linux-2.4.18/arch/ia64/sn/kernel/sv.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ia64/sn/kernel/sv.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,552 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved + * + * This implemenation of synchronization variables is heavily based on + * one done by Steve Lord + * + * Paul Cassella + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* Define this to have sv_test() run some simple tests. + kernel_thread() must behave as expected when this is called. */ +#undef RUN_SV_TEST + +#define DEBUG + +/* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast() + can sanity check interrupt state on architectures where we know + how. */ +#ifdef DEBUG + #define SV_DEBUG_INTERRUPT_STATE + #ifdef __mips64 + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0) + #define SV_INTERRUPT_TEST_WORKERS 31 + #elif defined(__ia64) + #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0) + #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0) + #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */ + #else + #undef SV_DEBUG_INTERRUPT_STATE + #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */ + #endif /* __mips64 */ +#endif /* DEBUG */ + + +/* XXX FIXME hack hack hack. Our mips64 tree is from before the + switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */ +#ifdef TASK_EXCLUSIVE + #undef EXCLUSIVE_IN_QUEUE +#else + #define EXCLUSIVE_IN_QUEUE + #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */ +#endif + + +static inline void sv_lock(sv_t *sv) { + spin_lock(&sv->sv_lock); +} + +static inline void sv_unlock(sv_t *sv) { + spin_unlock(&sv->sv_lock); +} + +/* up() is "extern inline", so we can't pass its address to sv_wait. + Use this function's address instead. */ +static void up_wrapper(struct semaphore *sem) { + up(sem); +} + +/* spin_unlock() is sometimes a macro. */ +static void spin_unlock_wrapper(spinlock_t *s) { + spin_unlock(s); +} + +/* XXX Perhaps sv_wait() should do the switch() each time and avoid + the extra indirection and the need for the _wrapper functions? */ + +static inline void sv_set_mon_type(sv_t *sv, int type) { + switch (type) { + case SV_MON_SPIN: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)spin_unlock_wrapper; + break; + case SV_MON_SEMA: + sv->sv_mon_unlock_func = + (sv_mon_unlock_func_t)up_wrapper; + if(sv->sv_flags & SV_INTS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with interrupts if it is a " + "semaphore!\n"); + BUG(); + } + if(sv->sv_flags & SV_BHS) { + printk(KERN_ERR "sv_set_mon_type: The monitor lock " + "cannot be shared with bottom-halves if it is " + "a semaphore!\n"); + BUG(); + } + break; +#if 0 + /* + * If needed, and will need to think about interrupts. This + * may be needed, for example, if someone wants to use sv's + * with something like dev_base; writers need to hold two + * locks. + */ + case SV_MON_CUSTOM: + { + struct sv_mon_custom *c = lock; + sv->sv_mon_unlock_func = c->sv_mon_unlock_func; + sv->sv_mon_lock = c->sv_mon_lock; + break; + } +#endif + + default: + printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! " + "(flags 0x%x)\n", type, type, sv->sv_flags); + BUG(); + break; + } + sv->sv_flags |= type; +} + +static inline void sv_set_ord(sv_t *sv, int ord) { + if (!ord) + ord = SV_ORDER_DEFAULT; + + if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) { + printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ", + ord, ord); + BUG(); + } + + sv->sv_flags |= ord; +} + +void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags) +{ + int ord = flags & SV_ORDER_MASK; + int type = flags & SV_MON_MASK; + + /* Copy all non-order, non-type flags */ + sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK)); + + if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) { + printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n"); + BUG(); + } + + sv_set_ord(sv, ord); + sv_set_mon_type(sv, type); + + /* If lock is NULL, we'll get it from sv_wait_compat() (and + ignore it in sv_signal() and sv_broadcast()). */ + sv->sv_mon_lock = lock; + + spin_lock_init(&sv->sv_lock); + init_waitqueue_head(&sv->sv_waiters); +} + +/* + * The associated lock must be locked on entry. It is unlocked on return. + * + * Return values: + * + * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0 + * n = 0 : timeout expired + * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0 + */ +signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) +{ + DECLARE_WAITQUEUE( wait, current ); + unsigned long flags; + signed long ret = 0; + +#ifdef SV_DEBUG_INTERRUPT_STATE + { + unsigned long flags; + __save_flags(flags); + + if(sv->sv_flags & SV_INTS) { + if(SV_TEST_INTERRUPTS_ENABLED(flags)) { + printk(KERN_ERR "sv_wait: SV_INTS and interrupts " + "enabled (flags: 0x%lx)\n", flags); + BUG(); + } + } else { + if (SV_TEST_INTERRUPTS_DISABLED(flags)) { + printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts " + "disabled! (flags: 0x%lx)\n", flags); + } + } + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + + sv->sv_mon_unlock_func(sv->sv_mon_lock); + + /* Add ourselves to the wait queue and set the state before + * releasing the sv_lock so as to avoid racing with the + * wake_up() in sv_signal() and sv_broadcast(). + */ + + /* don't need the _irqsave part, but there is no wq_write_lock() */ + wq_write_lock_irqsave(&sv->sv_waiters.lock, flags); + +#ifdef EXCLUSIVE_IN_QUEUE + wait.flags |= WQ_FLAG_EXCLUSIVE; +#endif + + switch(sv->sv_flags & SV_ORDER_MASK) { + case SV_ORDER_FIFO: + __add_wait_queue_tail(&sv->sv_waiters, &wait); + break; + case SV_ORDER_FILO: + __add_wait_queue(&sv->sv_waiters, &wait); + break; + default: + printk(KERN_ERR "sv_wait: unknown order! (sv: 0x%p, flags: 0x%x)\n", + (void *)sv, sv->sv_flags); + BUG(); + } + wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags); + + if(sv_wait_flags & SV_WAIT_SIG) + set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE ); + else + set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE); + + spin_unlock(&sv->sv_lock); + + if(sv->sv_flags & SV_INTS) + local_irq_enable(); + else if(sv->sv_flags & SV_BHS) + local_bh_enable(); + + if (timeout) + ret = schedule_timeout(timeout); + else + schedule(); + + if(current->state != TASK_RUNNING) /* XXX Is this possible? */ { + printk(KERN_ERR "sv_wait: state not TASK_RUNNING after " + "schedule().\n"); + set_current_state(TASK_RUNNING); + } + + remove_wait_queue(&sv->sv_waiters, &wait); + + /* Return cases: + - woken by a sv_signal/sv_broadcast + - woken by a signal + - woken by timeout expiring + */ + + /* XXX This isn't really accurate; we may have been woken + before the signal anyway.... */ + if(signal_pending(current)) + return timeout ? -ret : -1; + return timeout ? ret : 1; +} + + +void sv_signal(sv_t *sv) +{ + /* If interrupts can acquire this lock, they can also acquire the + sv_mon_lock, which we must already have to have called this, so + interrupts must be disabled already. If interrupts cannot + contend for this lock, we don't have to worry about it. */ + +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_signal: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_broadcast(sv_t *sv) +{ +#ifdef SV_DEBUG_INTERRUPT_STATE + if(sv->sv_flags & SV_INTS) { + unsigned long flags; + __save_flags(flags); + if(SV_TEST_INTERRUPTS_ENABLED(flags)) + printk(KERN_ERR "sv_broadcast: SV_INTS and " + "interrupts enabled! (flags: 0x%lx)\n", flags); + } +#endif /* SV_DEBUG_INTERRUPT_STATE */ + + sv_lock(sv); + wake_up_all(&sv->sv_waiters); + sv_unlock(sv); +} + +void sv_destroy(sv_t *sv) +{ + if(!spin_trylock(&sv->sv_lock)) { + printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", (void *)sv); + BUG(); + } + + /* XXX Check that the waitqueue is empty? + Mark the sv destroyed? + */ +} + + +#ifdef RUN_SV_TEST + +static DECLARE_MUTEX_LOCKED(talkback); +static DECLARE_MUTEX_LOCKED(sem); +sv_t sv; +sv_t sv_filo; + +static int sv_test_1_w(void *arg) +{ + printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg); + + spin_lock((spinlock_t*)arg); + printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n"); + + up(&sem); + + printk("sv_test_1_w: sv_spin_wait()'ing.\n"); + + sv_spin_wait(&sv, arg); + + printk("sv_test_1_w: talkback.\n"); + up(&talkback); + + printk("sv_test_1_w: exiting.\n"); + return 0; +} + +static int sv_test_1_s(void *arg) +{ + printk("sv_test_1_s: waiting for semaphore.\n"); + down(&sem); + printk("sv_test_1_s: semaphore acquired. Acquiring spinlock.\n"); + spin_lock((spinlock_t*)arg); + printk("sv_test_1_s: spinlock acquired. sv_signaling.\n"); + sv_signal(&sv); + printk("sv_test_1_s: talkback.\n"); + up(&talkback); + printk("sv_test_1_s: exiting.\n"); + return 0; + +} + +static int count; +static DECLARE_MUTEX(monitor); + +static int sv_test_2_w(void *arg) +{ + int dummy = count++; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + up(&talkback); + printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy); + sv_sema_wait(sv, &monitor); + printk("sv_test_2_w: thread %d woken, exiting.\n", dummy); + up(&sem); + return 0; +} + +static int sv_test_2_s_1(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s_1: waking one thread.\n"); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_2_s_1: signaling and broadcasting again. Nothing should happen.\n"); + sv_signal(sv); + sv_broadcast(sv); + sv_signal(sv); + sv_broadcast(sv); + + printk("sv_test_2_s_1: talkbacking.\n"); + up(&talkback); + up(&monitor); + return 0; +} + +static int sv_test_2_s(void *arg) +{ + int i; + sv_t *sv = (sv_t *)arg; + + down(&monitor); + for(i = 0; i < 3; i++) { + printk("sv_test_2_s: waking one thread (should be %d.)\n", i); + sv_signal(sv); + down(&sem); + } + + printk("sv_test_3_s: waking remaining threads with broadcast.\n"); + sv_broadcast(sv); + for(; i < 10; i++) + down(&sem); + + printk("sv_test_3_s: sending talkback.\n"); + up(&talkback); + + printk("sv_test_3_s: exiting.\n"); + up(&monitor); + return 0; +} + + +static void big_test(sv_t *sv) +{ + int i; + + count = 0; + + for(i = 0; i < 3; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning first wake-up thread.\n"); + kernel_thread(sv_test_2_s_1, sv, 0); + + down(&talkback); + printk("big_test: talkback happened.\n"); + + + for(i = 3; i < 13; i++) { + printk("big_test: spawning thread %d.\n", i); + kernel_thread(sv_test_2_w, sv, 0); + down(&talkback); + } + + printk("big_test: spawning wake-up thread.\n"); + kernel_thread(sv_test_2_s, sv, 0); + + down(&talkback); +} + +sv_t int_test_sv; +spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED; +int int_test_ready; +static int irqtestcount; + +static int interrupt_test_worker(void *unused) +{ + int id = ++irqtestcount; + int it = 0; + unsigned long flags, flags2; + + printk("ITW: thread %d started.\n", id); + + while(1) { + __save_flags(flags2); + if(jiffies % 3) { + printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2); + spin_lock_irqsave(&int_test_spin, flags); + } else { + printk("ITW %2d %5d: spin_lock_irqing (%lx)\n", id, it, flags2); + spin_lock_irq(&int_test_spin); + } + + __save_flags(flags2); + printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2); + sv_wait(&int_test_sv, 0, 0); + + __save_flags(flags2); + printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(jiffies & 0xf); + if(current->state != TASK_RUNNING) + printk("ITW: current->state isn't RUNNING after schedule!\n"); + it++; + } +} + +static void interrupt_test(void) +{ + int i; + + printk("interrupt_test: initing sv.\n"); + sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS); + + for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) { + printk("interrupt_test: starting test thread %d.\n", i); + kernel_thread(interrupt_test_worker, 0, 0); + } + printk("interrupt_test: done with init part.\n"); + int_test_ready = 1; +} + +int sv_test(void) +{ + spinlock_t s = SPIN_LOCK_UNLOCKED; + + sv_init(&sv, &s, SV_MON_SPIN); + printk("sv_test: starting sv_test_1_w.\n"); + kernel_thread(sv_test_1_w, &s, 0); + printk("sv_test: starting sv_test_1_s.\n"); + kernel_thread(sv_test_1_s, &s, 0); + + printk("sv_test: waiting for talkback.\n"); + down(&talkback); down(&talkback); + printk("sv_test: talkback happened, sv_destroying.\n"); + sv_destroy(&sv); + + count = 0; + + printk("sv_test: beginning big_test on sv.\n"); + + sv_init(&sv, &monitor, SV_MON_SEMA); + big_test(&sv); + sv_destroy(&sv); + + printk("sv_test: beginning big_test on sv_filo.\n"); + sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO); + big_test(&sv_filo); + sv_destroy(&sv_filo); + + interrupt_test(); + + printk("sv_test: done.\n"); + return 0; +} + +__initcall(sv_test); + +#endif /* RUN_SV_TEST */ diff -urN linux-2.4.18/arch/ia64/sn/sn1/Makefile linux-2.4.19-pre5/arch/ia64/sn/sn1/Makefile --- linux-2.4.18/arch/ia64/sn/sn1/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/Makefile Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -# -# ia64/platform/sn/sn1/Makefile -# -# Copyright (C) 1999 Silicon Graphics, Inc. -# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) -# - -EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \ - -DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \ - -DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \ - -DNEW_INTERRUPTS - -.S.s: - $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< - -all: sn1.a - -O_TARGET = sn1.a - -obj-y = irq.o setup.o iomv.o mm.o smp.o synergy.o sn1_asm.o \ - discontig.o probe.o error.o sv.o - -obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o -obj-$(CONFIG_IA64_GENERIC) += machvec.o -obj-$(CONFIG_MODULES) += sn1_ksyms.o - -clean:: - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ia64/sn/sn1/discontig.c linux-2.4.19-pre5/arch/ia64/sn/sn1/discontig.c --- linux-2.4.18/arch/ia64/sn/sn1/discontig.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/discontig.c Thu Jan 1 01:00:00 1970 @@ -1,159 +0,0 @@ -/* - * Copyright 2000, Silicon Graphics, sprasad@engr.sgi.com - * Copyright 2000, Kanoj Sarcar, kanoj@sgi.com - */ - -/* - * Contains common definitions and globals for NUMA platform - * support. For now, SN-IA64 and SN-MIPS are the NUMA platforms. - */ - -#include -#include -#include -#include -#include -#include - -extern int numnodes ; - -plat_pg_data_t plat_node_data[MAXNODES]; -bootmem_data_t bdata[MAXNODES]; -int chunktonid[MAXCHUNKS]; -int nasid_map[MAXNASIDS]; - -void __init -init_chunktonid(void) -{ - memset(chunktonid, -1, sizeof(chunktonid)) ; -} - -void __init -init_nodeidmap(void) -{ - memset(nasid_map, -1, sizeof(nasid_map)) ; -} - -int cnodeid_map[MAXNODES] ; -void __init -init_cnodeidmap(void) -{ - memset(cnodeid_map, -1, sizeof(cnodeid_map)) ; -} - -int -numa_debug(void) -{ - panic("NUMA debug\n"); - return(0); -} - -int __init -build_cnodeid_map(void) -{ - int i,j ; - - for (i=0,j=0;i= 0) - cnodeid_map[j++] = i ; - } - return j ; -} - -/* - * Since efi_memmap_walk merges contiguous banks, this code will need - * to find all the nasids covered by the input memory descriptor. - */ -static int __init -build_nasid_map(unsigned long start, unsigned long end, void *arg) -{ - unsigned long vaddr = start; - int nasid = GetNasId(__pa(vaddr)); - - while (vaddr < end) { - if (nasid < MAXNASIDS) - nasid_map[nasid] = 0; - else - panic("build_nasid_map"); - vaddr = (unsigned long)__va((unsigned long)(++nasid) << - SN1_NODE_ADDR_SHIFT); - } - return 0; -} - -void __init -fix_nasid_map(void) -{ - int i ; - int j ; - - /* For every nasid */ - for (j=0;jbdata ; - printk("%d 0x%016lx 0x%016lx 0x%016lx\n", i, - bdata->node_boot_start, bdata->node_low_pfn, - (unsigned long)bdata->node_bootmem_map) ; - } -} - -void __init -discontig_mem_init(void) -{ - extern void setup_sn1_bootmem(int); - int maxnodes ; - - init_chunktonid() ; - init_nodeidmap() ; - init_cnodeidmap() ; - efi_memmap_walk(build_nasid_map, 0) ; - maxnodes = build_cnodeid_map() ; - fix_nasid_map() ; -#ifdef CONFIG_DISCONTIGMEM - setup_sn1_bootmem(maxnodes) ; -#endif - numnodes = maxnodes; - dump_bootmem_info() ; -} - -void -dump_node_data(void) -{ - int i; - - printk("NODE DATA ....\n") ; - printk("Node, Start, Size, MemMap, BitMap, StartP, Mapnr, Size, Id\n") ; - for (i=0;ivalid_addr_bitmap, - NODE_DATA(i)->node_start_paddr, - NODE_DATA(i)->node_start_mapnr, - NODE_DATA(i)->node_size, - NODE_DATA(i)->node_id) ; - } -} - diff -urN linux-2.4.18/arch/ia64/sn/sn1/error.c linux-2.4.19-pre5/arch/ia64/sn/sn1/error.c --- linux-2.4.18/arch/ia64/sn/sn1/error.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/error.c Thu Jan 1 01:00:00 1970 @@ -1,149 +0,0 @@ - - -/* - * SN1 Platform specific error Support - * - * Copyright (C) 2001 Silicon Graphics, Inc. - * Copyright (C) 2001 Alan Mayer (ajm@sgi.com) - */ - - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -void -snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) { - unsigned long long intpend_val; - unsigned long long bit; - - switch (irq) { - case SGI_UART_IRQ: - // This isn't really an error interrupt. We're just - // here because we have to do something with them. - // This is probably wrong, and this code will be - // removed. - intpend_val = LOCAL_HUB_L(PI_INT_PEND0); - if ( (bit = ~(1L< -#include - -static inline void * -sn1_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if (port >= 0x1f0 && port <= 0x1f7 || - port == 0x3f6 || port == 0x3f7) { - io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -unsigned int -sn1_inb (unsigned long port) -{ - volatile unsigned char *addr = sn1_io_addr(port); - unsigned char ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -unsigned int -sn1_inw (unsigned long port) -{ - volatile unsigned short *addr = sn1_io_addr(port); - unsigned short ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -unsigned int -sn1_inl (unsigned long port) -{ - volatile unsigned int *addr = sn1_io_addr(port); - unsigned int ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -void -sn1_outb (unsigned char val, unsigned long port) -{ - volatile unsigned char *addr = sn1_io_addr(port); - - *addr = val; - __ia64_mf_a(); -} - -void -sn1_outw (unsigned short val, unsigned long port) -{ - volatile unsigned short *addr = sn1_io_addr(port); - - *addr = val; - __ia64_mf_a(); -} - -void -sn1_outl (unsigned int val, unsigned long port) -{ - volatile unsigned int *addr = sn1_io_addr(port); - - *addr = val; - __ia64_mf_a(); -} diff -urN linux-2.4.18/arch/ia64/sn/sn1/irq.c linux-2.4.19-pre5/arch/ia64/sn/sn1/irq.c --- linux-2.4.18/arch/ia64/sn/sn1/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/irq.c Thu Jan 1 01:00:00 1970 @@ -1,183 +0,0 @@ -/* - * Platform dependent support for SGI SN1 - * - * Copyright (C) 2000 Silicon Graphics - * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) - * Copyright (C) 2000 Alan Mayer (ajm@sgi.com) - * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com) - */ - -#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 IRQ_BIT_OFFSET 64 - -int bit_pos_to_irq(int bit) -{ - if (bit > 118) - bit = 118; - return (bit + IRQ_BIT_OFFSET); -} - -static inline int irq_to_bit_pos(int irq) -{ - int bit = irq - IRQ_BIT_OFFSET; - - if (bit > 63) - bit -= 64; - return bit; -} - -static unsigned 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 void -sn1_ack_irq(unsigned int irq) -{ -} - -static void -sn1_end_irq(unsigned int irq) -{ - int bit; - - bit = irq_to_bit_pos(irq); - LOCAL_HUB_CLR_INTR(bit); -} - -static void -sn1_set_affinity_irq(unsigned int irq, unsigned long mask) -{ -} - -struct hw_interrupt_type irq_type_sn1 = { - "sn1_irq", - sn1_startup_irq, - sn1_shutdown_irq, - sn1_enable_irq, - sn1_disable_irq, - sn1_ack_irq, - sn1_end_irq, - sn1_set_affinity_irq -}; - - -void -sn1_irq_init (void) -{ - int i; - - for (i = 0; i <= NR_IRQS; ++i) { - if (idesc_from_vector(i)->handler == &no_irq_type) { - idesc_from_vector(i)->handler = &irq_type_sn1; - } - } -} - - - -#if !defined(CONFIG_IA64_SGI_SN1) -void -sn1_pci_fixup(int arg) -{ -} -#endif - -#ifdef CONFIG_PERCPU_IRQ - -extern irq_desc_t irq_descX[NR_IRQS]; -irq_desc_t *irq_desc_ptr[NR_CPUS] = { irq_descX }; - -/* - * Each slave AP allocates its own irq table. - */ -int __init cpu_irq_init(void) -{ - irq_desc_ptr[smp_processor_id()] = (irq_desc_t *)kmalloc(sizeof(irq_descX), GFP_KERNEL); - if (irq_desc_ptr[smp_processor_id()] == 0) - return(-1); - memcpy(irq_desc_ptr[smp_processor_id()], irq_desc_ptr[0], - sizeof(irq_descX)); - return(0); -} - -/* - * This can also allocate the irq tables for the other cpus, specifically - * on their nodes. - */ -int __init master_irq_init(void) -{ - return(0); -} - -/* - * The input is an ivt level. - */ -irq_desc_t *idesc_from_vector(unsigned int ivnum) -{ - return(irq_desc_ptr[smp_processor_id()] + ivnum); -} - -/* - * The input is a "soft" level, that we encoded in. - */ -irq_desc_t *idesc_from_irq(unsigned int irq) -{ - return(irq_desc_ptr[irq >> 8] + (irq & 0xff)); -} - -unsigned int ivector_from_irq(unsigned int irq) -{ - return(irq & 0xff); -} - -/* - * This should return the Linux irq # for the i/p vector on the - * i/p cpu. We currently do not track this. - */ -unsigned int irq_from_cpuvector(int cpunum, unsigned int vector) -{ - return (vector); -} - -#endif /* CONFIG_PERCPU_IRQ */ diff -urN linux-2.4.18/arch/ia64/sn/sn1/llsc4.c linux-2.4.19-pre5/arch/ia64/sn/sn1/llsc4.c --- linux-2.4.18/arch/ia64/sn/sn1/llsc4.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/llsc4.c Thu Jan 1 01:00:00 1970 @@ -1,952 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void bringup_set_led_bits(u8 bits, u8 mask); - -#include "llsc4.h" - - -#ifdef STANDALONE -#include "lock.h" -#endif - -#ifdef INTTEST -static int inttest=0; -#endif - -/* - * Test parameter table for AUTOTEST - */ -typedef struct { - int passes; - int linecount; - int linepad; -} autotest_table_t; - -autotest_table_t autotest_table[] = { - {5000000, 2, 0x2b4 }, - {5000000, 16, 0, }, - {5000000, 16, 4, }, - {5000000, 128, 0x44 }, - {5000000, 128, 0x84 }, - {5000000, 128, 0x200 }, - {5000000, 128, 0x204 }, - {5000000, 128, 0x2b4 }, - {5000000, 2, 8*MB+0x2b4 }, - {5000000, 16, 8*MB+0 }, - {5000000, 16, 8*MB+4 }, - {5000000, 128, 8*MB+0x44 }, - {5000000, 128, 8*MB+0x84 }, - {5000000, 128, 8*MB+0x200 }, - {5000000, 128, 8*MB+0x204 }, - {5000000, 128, 8*MB+0x2b4 }, - {0}}; - -/* - * Array of virtual addresses available for test purposes. - */ - -typedef struct { - long vstart; - long vend; - long nextaddr; - int wrapcount; -} memmap_t; - -memmap_t memmap[MAXCHUNKS]; -int memmapx=0; - -typedef struct { - void *addr; - long data[16]; - long data_fc[16]; -} capture_line_t; - -typedef struct { - int size; - void *blockaddr; - void *shadaddr; - long blockdata[16]; - long shaddata[16]; - long blockdata_fc[16]; - long shaddata_fc[16]; - long synerr; -} capture_t; - -/* - * PORTING NOTE: revisit this statement. On hardware we put mbase at 0 and - * the rest of the tables have to start at 1MB to skip PROM tables. - */ -#define THREADPRIVATE(t) ((threadprivate_t*)(((long)mbase)+1024*1024+t*((sizeof(threadprivate_t)+511)/512*512))) - -#define k_capture mbase->sk_capture -#define k_go mbase->sk_go -#define k_linecount mbase->sk_linecount -#define k_passes mbase->sk_passes -#define k_napticks mbase->sk_napticks -#define k_stop_on_error mbase->sk_stop_on_error -#define k_verbose mbase->sk_verbose -#define k_threadprivate mbase->sk_threadprivate -#define k_blocks mbase->sk_blocks -#define k_iter_msg mbase->sk_iter_msg -#define k_vv mbase->sk_vv -#define k_linepad mbase->sk_linepad -#define k_options mbase->sk_options -#define k_testnumber mbase->sk_testnumber -#define k_currentpass mbase->sk_currentpass - -static long blocks[MAX_LINECOUNT]; /* addresses of data blocks */ -static control_t *mbase; -static vint initialized=0; - -static unsigned int ran_conf_llsc(int); -static int rerr(capture_t *, char *, void *, void *, int, int, int, int, int, int); -static void dumpline(void *, char *, char *, void *, void *, int); -static int checkstop(int, int, uint); -static void spin(int); -static void capturedata(capture_t *, uint, void *, void *, int); -static int randn(uint max, uint *seed); -static uint zrandom (uint *zranseed); -static int set_lock(uint *, uint); -static int clr_lock(uint *, uint); -static void Speedo(void); - -int autotest_enabled=0; -static int llsctest_number=-1; -static int errstop_enabled=0; -static int fail_enabled=0; -static int selective_trigger=0; -static int dump_block_addrs_opt=0; -static uint errlock=0; - -static int __init autotest_enable(char *str) -{ - autotest_enabled = 1; - return 1; -} -static int __init set_llscblkadr(char *str) -{ - dump_block_addrs_opt = 1; - return 1; -} -static int __init set_llscselt(char *str) -{ - selective_trigger = 1; - return 1; -} -static int __init set_llsctest(char *str) -{ - llsctest_number = simple_strtol(str, &str, 10); - if (llsctest_number < 0 || llsctest_number > 15) - llsctest_number = -1; - return 1; -} -static int __init set_llscerrstop(char *str) -{ - errstop_enabled = 1; - return 1; -} -static int __init set_llscfail(char *str) -{ - fail_enabled = 8; - return 1; -} - -static void print_params(void) -{ - printk ("********* Enter AUTOTEST facility on master cpu *************\n"); - printk (" Test options:\n"); - printk (" llsctest=\t%d\tTest number to run (all = -1)\n", llsctest_number); - printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); - printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); - printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk ("\n"); -} -__setup("autotest", autotest_enable); -__setup("llsctest=", set_llsctest); -__setup("llscerrstop", set_llscerrstop); -__setup("llscfail", set_llscfail); -__setup("llscselt", set_llscselt); -__setup("llscblkadr", set_llscblkadr); - - -extern inline int -set_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_acq(lock, 0, id); - return (old == 0); -} - -extern inline int -clr_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_rel(lock, id, 0); - return (old == id); -} - -extern inline void -zero_lock(uint *lock) -{ - *lock = 0; -} - -/*------------------------------------------------------------------------+ -| Routine : ran_conf_llsc - ll/sc shared data test | -| Description: This test checks the coherency of shared data | -+------------------------------------------------------------------------*/ -static unsigned int -ran_conf_llsc(int thread) -{ - private_t pval; - share_t sval, sval2; - uint vv, linei, slinei, sharei, pass; - long t; - lock_t lockpat; - share_t *sharecopy; - long verbose, napticks, passes, linecount, lcount; - dataline_t *linep, *slinep; - int s, seed; - threadprivate_t *tp; - uint iter_msg, iter_msg_i=0; - int vv_mask; - int correct_errors; - int errs=0; - int stillbad; - capture_t capdata; - private_t *privp; - share_t *sharep; - - - linecount = k_linecount; - napticks = k_napticks; - verbose = k_verbose; - passes = k_passes; - iter_msg = k_iter_msg; - seed = (thread + 1) * 647; - tp = THREADPRIVATE(thread); - vv_mask = (k_vv>>((thread%16)*4)) & 0xf; - correct_errors = k_options&0xff; - - memset (&tp->private, 0, sizeof(tp->private)); - memset (&capdata, 0, sizeof(capdata)); - - for (pass = 1; passes == 0 || pass < passes; pass++) { - lockpat = (pass & 0x0fffffff) + (thread <<28); - tp->threadpasses = pass; - if (checkstop(thread, pass, lockpat)) - return 0; - iter_msg_i++; - if (iter_msg && iter_msg_i > iter_msg) { - printk("Thread %d, Pass %d\n", thread, pass); - iter_msg_i = 0; - } - lcount = 0; - - /* - * Select line to perform operations on. - */ - linei = randn(linecount, &seed); - sharei = randn(2, &seed); - slinei = (linei + (linecount/2))%linecount; /* I dont like this - fix later */ - - linep = (dataline_t *)blocks[linei]; - slinep = (dataline_t *)blocks[slinei]; - if (sharei == 0) - sharecopy = &slinep->share0; - else - sharecopy = &slinep->share1; - - - vv = randn(4, &seed); - if ((vv_mask & (1<private[thread]; - sharep = &linep->share[sharei]; - - switch(vv) { - case 0: - /* Read and verify private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - if (correct_errors) { - tp->private[linei] = *privp; - } - errs++; - } - break; - - case 1: - /* Read, verify, and increment private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count & inc", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - errs++; - } - pval++; - *privp = pval; - tp->private[linei] = pval; - break; - - case 2: - /* Lock line, read and verify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - - sval = *sharep; - sval2 = *sharecopy; - if (pass > 12 && thread == 0 && fail_enabled == 1) - sval++; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - if (correct_errors) - *sharep = *sharecopy; - errs++; - } - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data unlock", linep, slinep, thread, pass, linei, lockpat, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - - case 3: - /* Lock line, read and verify shared data, modify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock & inc", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - sval = *sharep; - sval2 = *sharecopy; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data & inc", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - errs++; - } - - *sharep = lockpat; - *sharecopy = lockpat; - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data & inc unlock", linep, slinep, thread, pass, linei, thread, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - } - } - - return (errs > 0); -} - -static void -trigger_la(long val) -{ - long *p; - - p = (long*)0xc0000a0001000020L; /* PI_CPU_NUM */ - *p = val; -} - -static long -getsynerr(void) -{ - long err, *errp; - - errp = (long*)0xc0000e0000000340L; /* SYN_ERR */ - err = *errp; - if (err) - *errp = -1L; - return (err & ~0x60); -} - -static int -rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int linei, int exp, int found, int stillbad) -{ - int cpu, i; - long synerr; - int selt; - - - selt = selective_trigger && stillbad > 1 && - memcmp(cap->blockdata, cap->blockdata_fc, 128) != 0 && - memcmp(cap->shaddata, cap->shaddata_fc, 128) == 0; - if (selt) { - trigger_la(pass); - } else if (selective_trigger) { - k_go = ST_STOP; - return k_stop_on_error;; - } - - spin(1); - i = 100; - while (i && set_lock(&errlock, 1) != 1) { - spin(1); - i--; - } - printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", - msg, k_testnumber, thread, linei, pass, pass, jiffies, exp, found); - - dumpline (lp, "Corrupted data", "D ", cap->blockaddr, cap->blockdata, cap->size); - if (memcmp(cap->blockdata, cap->blockdata_fc, 128)) - dumpline (lp, "Corrupted data", "DF", cap->blockaddr, cap->blockdata_fc, cap->size); - - if (cap->shadaddr) { - dumpline (slp, "Shadow data", "S ", cap->shadaddr, cap->shaddata, cap->size); - if (memcmp(cap->shaddata, cap->shaddata_fc, 128)) - dumpline (slp, "Shadow data", "SF", cap->shadaddr, cap->shaddata_fc, cap->size); - } - - printk("Threadpasses: "); - for (cpu=0; cputhreadpasses) - printk(" %d:0x%x", cpu, k_threadprivate[cpu]->threadpasses); - - - printk("\nData was %sfixed by flushcache\n", (stillbad == 1 ? "**** NOT **** " : " ")); - synerr = getsynerr(); - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - spin(2); - printk("\n\n"); - clr_lock(&errlock, 1); - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - return k_stop_on_error; -} - - -static void -dumpline(void *lp, char *str1, char *str2, void *addr, void *data, int size) -{ - long *p; - int i, off; - - printk("%s at 0x%lx, size %d, block starts at 0x%lx\n", str1, (long)addr, size, (long)lp); - p = (long*) data; - for (i=0; i<16; i++, p++) { - if (i==0) printk("%2s", str2); - if (i==8) printk(" "); - printk(" %016lx", *p); - if ((i&7)==7) printk("\n"); - } - printk(" "); - off = (((long)addr) ^ size) & 63L; - for (i=0; i=off) ? "--" : " "); - if ((i%8) == 7) - printk(" "); - } - - off = ((long)addr) & 127; - printk(" (line %d)\n", off/64+1); -} - - -static int -randn(uint max, uint *seedp) -{ - if (max == 1) - return(0); - else - return((int)(zrandom(seedp)>>10) % max); -} - - -static int -checkstop(int thread, int pass, uint lockpat) -{ - long synerr; - - if (k_go == ST_RUN) - return 0; - if (k_go == ST_STOP) - return 1; - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - synerr = getsynerr(); - spin(2); - if (k_go == ST_STOP) - return 1; - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - return 1; -} - - -static void -spin(int j) -{ - udelay(j * 500000); -} - -static void -capturedata(capture_t *cap, uint pass, void *blockaddr, void *shadaddr, int size) -{ - - if (!selective_trigger) - trigger_la (pass); - - memcpy (cap->blockdata, CACHEALIGN(blockaddr), 128); - if (shadaddr) - memcpy (cap->shaddata, CACHEALIGN(shadaddr), 128); - - if (k_stop_on_error) { - k_go = ST_ERRSTOP; - } - - cap->size = size; - cap->blockaddr = blockaddr; - cap->shadaddr = shadaddr; - - asm volatile ("fc %0" :: "r"(blockaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->blockdata_fc, CACHEALIGN(blockaddr), 128); - - if (shadaddr) { - asm volatile ("fc %0" :: "r"(shadaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->shaddata_fc, CACHEALIGN(shadaddr), 128); - } -} - -int zranmult = 0x48c27395; - -static uint -zrandom (uint *seedp) -{ - *seedp = (*seedp * zranmult) & 0x7fffffff; - return (*seedp); -} - - -void -set_autotest_params(void) -{ - static int testnumber=-1; - - if (llsctest_number >= 0) { - testnumber = llsctest_number; - } else { - testnumber++; - if (autotest_table[testnumber].passes == 0) { - testnumber = 0; - dump_block_addrs_opt = 0; - } - } - k_passes = autotest_table[testnumber].passes; - k_linepad = autotest_table[testnumber].linepad; - k_linecount = autotest_table[testnumber].linecount; - k_testnumber = testnumber; - - if (IS_RUNNING_ON_SIMULATOR()) { - printk ("llsc start test %ld\n", k_testnumber); - k_passes = 1000; - } -} - - -static void -set_leds(int errs) -{ - unsigned char leds=0; - - /* - * Leds are: - * ppppeee- - * where - * pppp = test number - * eee = error count but top bit is stick - */ - - leds = ((errs&7)<<1) | ((k_testnumber&15)<<4) | (errs ? 0x08 : 0); - bringup_set_led_bits(leds, 0xfe); -} - -static void -setup_block_addresses(void) -{ - int i, stride, memmapi; - - stride = LINESTRIDE; - memmapi = 0; - for (i=0; i= memmap[memmapi].vend) { - memmap[memmapi].wrapcount++; - memmap[memmapi].nextaddr = memmap[memmapi].vstart + - memmap[memmapi].wrapcount * sizeof(dataline_t); - } - - memset((void*)blocks[i], 0, sizeof(dataline_t)); - - if (stride > 16384) { - memmapi++; - if (memmapi == memmapx) - memmapi = 0; - } - } - -} - -static void -dump_block_addrs(void) -{ - int i; - - printk("LLSC TestNumber %ld\n", k_testnumber); - - for (i=0; ithreadstate == TS_KILLED) { - bringup_set_led_bits(0xfe, 0xfe); - while(1); - } - k_threadprivate[cpuid]->threadstate = state; -} - -static int -build_mem_map(unsigned long start, unsigned long end, void *arg) -{ - long lstart; - long align = 8*MB; - /* - * HACK - skip the kernel on the first node - */ - - printk ("LLSC memmap: start 0x%lx, end 0x%lx, (0x%lx - 0x%lx)\n", - start, end, (long) virt_to_page(start), (long) virt_to_page(end-PAGE_SIZE)); - - while (end > start && (PageReserved(virt_to_page(end-PAGE_SIZE)) || virt_to_page(end-PAGE_SIZE)->count.counter > 0)) - end -= PAGE_SIZE; - - lstart = end; - while (lstart > start && (!PageReserved(virt_to_page(lstart-PAGE_SIZE)) && virt_to_page(lstart-PAGE_SIZE)->count.counter == 0)) - lstart -= PAGE_SIZE; - - lstart = (lstart + align -1) /align * align; - end = end / align * align; - if (lstart >= end) - return 0; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); - - memmap[memmapx].vstart = lstart; - memmap[memmapx].vend = end; - memmapx++; - return 0; -} - -void int_test(void); - -int -llsc_main (int cpuid, long mbasex) -{ - int i, cpu, is_master, repeatcnt=0; - unsigned int preverr=0, errs=0, pass=0; - int automode=0; - -#ifdef INTTEST - if (inttest) - int_test(); -#endif - - if (!autotest_enabled) - return 0; - -#ifdef CONFIG_SMP - is_master = !smp_processor_id(); -#else - is_master = 1; -#endif - - - if (is_master) { - print_params(); - if(!IS_RUNNING_ON_SIMULATOR()) - spin(10); - mbase = (control_t*)mbasex; - k_currentpass = 0; - k_go = ST_IDLE; - k_passes = DEF_PASSES; - k_napticks = DEF_NAPTICKS; - k_stop_on_error = DEF_STOP_ON_ERROR; - k_verbose = DEF_VERBOSE; - k_linecount = DEF_LINECOUNT; - k_iter_msg = DEF_ITER_MSG; - k_vv = DEF_VV; - k_linepad = DEF_LINEPAD; - k_blocks = (void*)blocks; - efi_memmap_walk(build_mem_map, 0); - -#ifdef CONFIG_IA64_SGI_AUTOTEST - automode = 1; -#endif - - for (i=0; i 5) { - set_autotest_params(); - repeatcnt = 0; - } - } else { - while (k_go == ST_IDLE); - } - - k_go = ST_INIT; - if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; - k_linecount = k_linecount & ~1; - setup_block_addresses(); - if (dump_block_addrs_opt) - dump_block_addrs(); - - k_currentpass = pass++; - k_go = ST_RUN; - if (fail_enabled) - fail_enabled--; - - } else { - while (k_go != ST_RUN || k_currentpass != pass); - pass++; - } - - - set_leds(errs); - set_thread_state(cpuid, TS_RUNNING); - - errs += ran_conf_llsc(cpuid); - preverr = (k_go == ST_ERRSTOP); - - set_leds(errs); - set_thread_state(cpuid, TS_STOPPED); - - if (is_master) { - Speedo(); - for (i=0, cpu=0; cputhreadstate == TS_RUNNING) { - i++; - if (i == 10000) { - k_go = ST_STOP; - printk (" llsc master stopping test number %ld\n", k_testnumber); - } - if (i > 100000) { - k_threadprivate[cpu]->threadstate = TS_KILLED; - printk (" llsc: master killing cpuid %d, running test number %ld\n", - cpu, k_testnumber); - } - udelay(1000); - } - } - } - - goto loop; -} - - -static void -Speedo(void) -{ - static int i = 0; - - switch (++i%4) { - case 0: - printk("|\b"); - break; - case 1: - printk("\\\b"); - break; - case 2: - printk("-\b"); - break; - case 3: - printk("/\b"); - break; - } -} - -#ifdef INTTEST - -/* ======================================================================================================== - * - * Some test code to verify that interrupts work - * - * Add the following to the arch/ia64/kernel/smp.c after the comment "Reschedule callback" - * if (zzzprint_resched) printk(" cpu %d got interrupt\n", smp_processor_id()); - * - * Enable the code in arch/ia64/sn/sn1/smp.c to print sending IPIs. - * - */ - -static int __init set_inttest(char *str) -{ - inttest = 1; - autotest_enabled = 1; - - return 1; -} - -__setup("inttest=", set_inttest); - -int zzzprint_resched=0; - -void -int_test() { - int mycpu, cpu; - static volatile int control_cpu=0; - - mycpu = smp_processor_id(); - zzzprint_resched = 2; - - printk("Testing cross interrupts\n"); - - while (control_cpu != smp_num_cpus) { - if (mycpu == cpu_logical_map(control_cpu)) { - for (cpu=0; cpulock[(i)] -#define LOCK(i) set_lock(LOCKADDR(i), lockpat) -#define UNLOCK(i) clr_lock(LOCKADDR(i), lockpat) -#define GETLOCK(i) *LOCKADDR(i) -#define ZEROLOCK(i) zero_lock(LOCKADDR(i)) - -#define CACHEALIGN(a) ((void*)((long)(a) & ~127L)) - -typedef uint lock_t; -typedef uint share_t; -typedef uint private_t; - -typedef struct { - lock_t lock[2]; - share_t share[2]; - private_t private[MAXCPUS]; - share_t share0; - share_t share1; -} dataline_t ; - - -#define LINEPAD k_linepad -#define LINESTRIDE (((sizeof(dataline_t)+CACHELINE-1)/CACHELINE)*CACHELINE + LINEPAD) - - -typedef struct { - vint threadstate; - uint threadpasses; - private_t private[MAX_LINECOUNT]; -} threadprivate_t; - -typedef struct { - vlong sk_go; /* 0=idle, 1=init, 2=run */ - long sk_linecount; - long sk_passes; - long sk_napticks; - long sk_stop_on_error; - long sk_verbose; - long sk_iter_msg; - long sk_vv; - long sk_linepad; - long sk_options; - long sk_testnumber; - vlong sk_currentpass; - void *sk_blocks; - threadprivate_t *sk_threadprivate[MAXCPUS]; -} control_t; - -/* Run state (k_go) constants */ -#define ST_IDLE 0 -#define ST_INIT 1 -#define ST_RUN 2 -#define ST_STOP 3 -#define ST_ERRSTOP 4 - - -/* Threadstate constants */ -#define TS_STOPPED 0 -#define TS_RUNNING 1 -#define TS_KILLED 2 - - - -int llsc_main (int cpuid, long mbasex); - diff -urN linux-2.4.18/arch/ia64/sn/sn1/machvec.c linux-2.4.19-pre5/arch/ia64/sn/sn1/machvec.c --- linux-2.4.18/arch/ia64/sn/sn1/machvec.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/machvec.c Thu Jan 1 01:00:00 1970 @@ -1,18 +0,0 @@ -#define MACHVEC_PLATFORM_NAME sn1 -#include -#include -#include -void* -sn1_mk_io_addr_MACRO - -dma_addr_t -sn1_pci_map_single_MACRO - -int -sn1_pci_map_sg_MACRO - -unsigned long -sn1_virt_to_phys_MACRO - -void * -sn1_phys_to_virt_MACRO diff -urN linux-2.4.18/arch/ia64/sn/sn1/mm.c linux-2.4.19-pre5/arch/ia64/sn/sn1/mm.c --- linux-2.4.18/arch/ia64/sn/sn1/mm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/mm.c Thu Jan 1 01:00:00 1970 @@ -1,394 +0,0 @@ -/* - * Copyright, 2000-2001, Silicon Graphics. - * Copyright Srinivasa Thirumalachar (sprasad@engr.sgi.com) - * Copyright 2000-2001 Kanoj Sarcar (kanoj@sgi.com) - */ - -#include -#include -#include -#include -#include -#include - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -#define DONE_NOTHING 0 -#define DONE_FINDING 1 -#define DONE_BUILDING 2 - -struct nodemem_s { - u64 start; /* start of kernel usable memory */ - u64 end; /* end of kernel usable memory */ - u64 mtot; /* total kernel usable memory */ - u64 done; /* state of bootmem initialization */ - u64 bstart; /* where should the bootmem area be */ - u64 bsize; /* bootmap size */ - u64 hole[SN1_MAX_BANK_PER_NODE]; -} nodemem[MAXNODES]; - -static int nodemem_valid = 0; - -static int __init -free_unused_memmap_hole(int nid, unsigned long start, unsigned long end) -{ - struct page * page, *pageend; - unsigned long count = 0; - - if (start >= end) - return 0; - - /* - * Get the memmap ptrs to the start and end of the holes. - * virt_to_page(start) will panic, if start is in hole. - * Can we do virt_to_page(end), if end is on the next node? - */ - - page = virt_to_page(start - 1); - page++; - pageend = virt_to_page(end); - - printk("hpage=0x%lx, hpageend=0x%lx\n", (u64)page, (u64)pageend) ; - free_bootmem_node(NODE_DATA(nid), __pa(page), (u64)pageend - (u64)page); - - return count; -} - -static void __init -free_unused_memmap_node(int nid) -{ - u64 i = 0; - u64 holestart = -1; - u64 start = nodemem[nid].start; - - start = ((start >> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - do { - holestart = nodemem[nid].hole[i]; - i++; - while ((i < SN1_MAX_BANK_PER_NODE) && - (nodemem[nid].hole[i] == (u64)-1)) - i++; - if (i < SN1_MAX_BANK_PER_NODE) - free_unused_memmap_hole(nid, holestart, - start + (i<> SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - - nodesize = nodemem[nid].end - start ; - numpfn = nodesize >> PAGE_SHIFT; - - bank0size = nodemem[nid].hole[0] - start ; - /* If nid == master node && no kernel text replication */ - bank0size -= 0xA00000 ; /* Kernel text + stuff */ - bank0size -= ((numpfn + 7) >> 3); - - if ((numpfn * sizeof(mem_map_t)) > bank0size) { - printk("nid = %d, ns=0x%lx, npfn=0x%lx, bank0size=0x%lx\n", - nid, nodesize, numpfn, bank0size) ; - return 0 ; - } - - return 1 ; -} - -static void __init -check_pgtbl_size(int nid) -{ - int bank = SN1_MAX_BANK_PER_NODE - 1 ; - - /* Find highest bank with valid memory */ - while ((nodemem[nid].hole[bank] == -1) && (bank)) - bank-- ; - - while (!pgtbl_size_ok(nid)) { - /* Remove that bank of memory */ - /* Collect some numbers later */ - printk("Ignoring node %d bank %d\n", nid, bank) ; - nodemem[nid].hole[bank--] = -1 ; - /* Get to the next populated bank */ - while ((nodemem[nid].hole[bank] == -1) && (bank)) - bank-- ; - printk("Using only upto bank %d on node %d\n", bank,nid) ; - nodemem[nid].end = nodemem[nid].hole[bank] ; - if (!bank) break ; - } -} - -void dump_nodemem_map(int) ; - -#ifdef CONFIG_DISCONTIGMEM - -extern bootmem_data_t bdata[]; - -/* - * This assumes there will be a hole in kernel-usable memory between nodes - * (due to prom). The memory descriptors invoked via efi_memmap_walk are - * in increasing order. It tries to identify first suitable free area to - * put the bootmem for the node in. When presented with the md holding - * the kernel, it only searches at the end of the kernel area. - */ -static int __init -find_node_bootmem(unsigned long start, unsigned long end, void *arg) -{ - int nasid = GetNasId(__pa(start)); - int cnodeid = NASID_TO_CNODEID(nasid); - unsigned long nodesize; - extern char _end; - unsigned long kaddr = (unsigned long)&_end; - - /* - * Track memory available to kernel. - */ - nodemem[cnodeid].mtot += ((end - start) >> PAGE_SHIFT); - if (nodemem[cnodeid].done != DONE_NOTHING) - return(0); - nodesize = nodemem[cnodeid].end - ((nodemem[cnodeid].start >> - SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - nodesize >>= PAGE_SHIFT; - - /* - * Adjust limits for the md holding the kernel. - */ - if ((start < kaddr) && (end > kaddr)) - start = PAGE_ALIGN(kaddr); - - /* - * We need space for mem_map, bootmem map plus a few more pages - * to satisfy alloc_bootmems out of node 0. - */ - if ((end - start) > ((nodesize * sizeof(struct page)) + (nodesize/8) - + (10 * PAGE_SIZE))) { - nodemem[cnodeid].bstart = start; - nodemem[cnodeid].done = DONE_FINDING; - } - return(0); -} - -/* - * This assumes there will be a hole in kernel-usable memory between nodes - * (due to prom). The memory descriptors invoked via efi_memmap_walk are - * in increasing order. - */ -static int __init -build_node_bootmem(unsigned long start, unsigned long end, void *arg) -{ - int nasid = GetNasId(__pa(start)); - int curnodeid = NASID_TO_CNODEID(nasid); - int i; - unsigned long pstart, pend; - extern char _end, _stext; - unsigned long kaddr = (unsigned long)&_end; - - if (nodemem[curnodeid].done == DONE_FINDING) { - /* - * This is where we come to know the node is present. - * Do node wide tasks. - */ - nodemem[curnodeid].done = DONE_BUILDING; - NODE_DATA(curnodeid)->bdata = &(bdata[curnodeid]); - - /* - * Update the chunktonid array as a node wide task. There - * are too many smalls mds on first node to do this per md. - */ - pstart = __pa(nodemem[curnodeid].start); - pend = __pa(nodemem[curnodeid].end); - pstart &= CHUNKMASK; - pend = (pend + CHUNKSZ - 1) & CHUNKMASK; - /* Possible check point to enforce minimum node size */ - if (nodemem[curnodeid].bstart == -1) { - printk("No valid bootmem area on node %d\n", curnodeid); - while(1); - } - for (i = PCHUNKNUM(pstart); i <= PCHUNKNUM(pend - 1); i++) - chunktonid[i] = curnodeid; - if ((CHUNKTONID(PCHUNKNUM(pend)) > MAXCHUNKS) || - (PCHUNKNUM(pstart) >= PCHUNKNUM(pend))) { - printk("Ign 0x%lx-0x%lx, ", __pa(start), __pa(end)); - return(0); - } - - /* - * NODE_START and NODE_SIZE determine the physical range - * on the node that mem_map array needs to be set up for. - */ - NODE_START(curnodeid) = ((nodemem[curnodeid].start >> - SN1_NODE_ADDR_SHIFT) << SN1_NODE_ADDR_SHIFT); - NODE_SIZE(curnodeid) = (nodemem[curnodeid].end - - NODE_START(curnodeid)); - - nodemem[curnodeid].bsize = - init_bootmem_node(NODE_DATA(curnodeid), - (__pa(nodemem[curnodeid].bstart) >> PAGE_SHIFT), - (__pa((nodemem[curnodeid].start >> SN1_NODE_ADDR_SHIFT) - << SN1_NODE_ADDR_SHIFT) >> PAGE_SHIFT), - (__pa(nodemem[curnodeid].end) >> PAGE_SHIFT)); - - } else if (nodemem[curnodeid].done == DONE_NOTHING) { - printk("build_node_bootmem: node %d weirdness\n", curnodeid); - while(1); /* Paranoia */ - } - - /* - * Free the entire md. - */ - free_bootmem_node(NODE_DATA(curnodeid), __pa(start), (end - start)); - - /* - * Reclaim back the bootmap and kernel areas. - */ - if ((start <= nodemem[curnodeid].bstart) && (end > - nodemem[curnodeid].bstart)) - reserve_bootmem_node(NODE_DATA(curnodeid), - __pa(nodemem[curnodeid].bstart), nodemem[curnodeid].bsize); - if ((start <= kaddr) && (end > kaddr)) - reserve_bootmem_node(NODE_DATA(curnodeid), - __pa(&_stext), (&_end - &_stext)); - - return(0); -} - -void __init -setup_sn1_bootmem(int maxnodes) -{ - int i; - - for (i = 0; i < MAXNODES; i++) { - nodemem[i].start = nodemem[i].bstart = -1; - nodemem[i].end = nodemem[i].bsize = nodemem[i].mtot = 0; - nodemem[i].done = DONE_NOTHING; - memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)); - } - efi_memmap_walk(build_nodemem_map, 0); - - nodemem_valid = 1; - - /* - * After building the nodemem map, check if the node memmap - * will fit in the first bank of each node. If not change - * the node end addr till it fits. - */ - - for (i = 0; i < maxnodes; i++) - check_pgtbl_size(i); - - dump_nodemem_map(maxnodes); - - efi_memmap_walk(find_node_bootmem, 0); - efi_memmap_walk(build_node_bootmem, 0); -} -#endif - -void __init -discontig_paging_init(void) -{ - int i; - unsigned long max_dma, zones_size[MAX_NR_ZONES], holes_size[MAX_NR_ZONES]; - extern void dump_node_data(void); - - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - for (i = 0; i < numnodes; i++) { - unsigned long startpfn = __pa((void *)NODE_START(i)) >> PAGE_SHIFT; - unsigned long numpfn = NODE_SIZE(i) >> PAGE_SHIFT; - memset(zones_size, 0, sizeof(zones_size)); - memset(holes_size, 0, sizeof(holes_size)); - holes_size[ZONE_DMA] = numpfn - nodemem[i].mtot; - - if ((startpfn + numpfn) < max_dma) { - zones_size[ZONE_DMA] = numpfn; - } else if (startpfn > max_dma) { - zones_size[ZONE_NORMAL] = numpfn; - panic("discontig_paging_init: %d\n", i); - } else { - zones_size[ZONE_DMA] = (max_dma - startpfn); - zones_size[ZONE_NORMAL] = numpfn - zones_size[ZONE_DMA]; - panic("discontig_paging_init: %d\n", i); - } - free_area_init_node(i, NODE_DATA(i), NULL, zones_size, startpfn< ") ; - for (j=0;j - -/* - * ia64_sn_probe_io_slot - * This function will probe a physical address to determine if - * the address can be read. If reading the address causes a BUS - * error, an error is returned. If the probe succeeds, the contents - * of the memory location is returned. - * - * Calling sequence: - * ia64_probe_io_slot(paddr, size, data_ptr) - * - * Input: - * paddr Physical address to probe - * size Number bytes to read (1,2,4,8) - * data_ptr Address to store value read by probe - * (-1 returned if probe fails) - * - * Output: - * Status - * 0 - probe successful - * 1 - probe failed (generated MCA) - * 2 - Bad arg - * <0 - PAL error - */ - - -u64 -ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) -{ - struct ia64_sal_retval isrv; - - SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); - - if (data_ptr) { - switch (size) { - case 1: - *((u8*)data_ptr) = (u8)isrv.v0; - break; - case 2: - *((u16*)data_ptr) = (u16)isrv.v0; - break; - case 4: - *((u32*)data_ptr) = (u32)isrv.v0; - break; - case 8: - *((u64*)data_ptr) = (u64)isrv.v0; - break; - default: - isrv.status = 2; - } - } - - return isrv.status; -} diff -urN linux-2.4.18/arch/ia64/sn/sn1/setup.c linux-2.4.19-pre5/arch/ia64/sn/sn1/setup.c --- linux-2.4.18/arch/ia64/sn/sn1/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/setup.c Thu Jan 1 01:00:00 1970 @@ -1,254 +0,0 @@ -/* - * - * 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 -#include -#include -#include -#include -#include -#include -#include - - -/* - * This is the address of the RRegs in the HSpace of the global - * master. It is used by a hack in serial.c (serial_[in|out], - * printk.c (early_printk), and kdb_io.c to put console output on that - * node's Bedrock UART. It is initialized here to 0, so that - * early_printk won't try to access the UART before - * master_node_bedrock_address is properly calculated. - */ -u64 master_node_bedrock_address = 0UL; - -static void sn_fix_ivt_for_partitioned_system(void); - - -/* - * 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) -{ -#ifdef CONFIG_DISCONTIGMEM - return MAP_NR_SN1(addr); -#else - return MAP_NR_DENSE(addr); -#endif -} - -#if defined(BRINGUP) && defined(CONFIG_IA64_EARLY_PRINTK) -void __init -early_sn1_setup(void) -{ - master_node_bedrock_address = - (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); - printk("early_sn1_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); -} -#endif /* BRINGUP && CONFIG_IA64_EARLY_PRINTK */ - -void __init -sn1_setup(char **cmdline_p) -{ -#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - struct serial_struct req; -#endif - - MAX_DMA_ADDRESS = PAGE_OFFSET + 0x10000000000UL; - master_node_bedrock_address = - (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); - printk("sn1_setup: setting master_node_bedrock_address to 0x%lx\n", - master_node_bedrock_address); - -#if defined(CONFIG_SERIAL) && !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - /* - * We do early_serial_setup() to clean out the rs-table[] from the - * statically compiled in version. - */ - memset(&req, 0, sizeof(struct serial_struct)); - req.line = 0; - req.baud_base = 124800; - req.port = 0; - req.port_high = 0; - req.irq = 0; - req.flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST); - req.io_type = SERIAL_IO_MEM; - req.hub6 = 0; - req.iomem_base = (u8 *)(master_node_bedrock_address + 0x80); - req.iomem_reg_shift = 3; - req.type = 0; - req.xmit_fifo_size = 0; - req.custom_divisor = 0; - req.closing_wait = 0; - early_serial_setup(&req); -#endif /* CONFIG_SERIAL && !CONFIG_SERIAL_SGI_L1_PROTOCOL */ - - ROOT_DEV = to_kdev_t(0x0301); /* default to first IDE drive */ - sn_fix_ivt_for_partitioned_system(); - -#ifdef CONFIG_SMP - init_smp_config(); -#endif - screen_info = sn1_screen_info; -} - - -/* - * sn_fix_ivt_for_partitioned_system - * - * This is an ugly hack that is needed for partitioned systems. - * - * On a partitioned system, most partitions do NOT have a physical address 0. - * Unfortunately, the exception handling code in ivt.S has a couple of physical - * addresses of kernel structures hardcoded into "movl" instructions. - * These addresses are correct on partition 0 only. On all other partitions, - * the addresses must be changed to reference the correct address. - * - * This routine scans the ivt code and replaces the hardcoded addresses with - * the correct address. - * - * Note that we could have made the ivt.S code dynamically determine the correct - * address but this would add code to performance critical pathes. This option - * was rejected. - */ - -#define TEMP_mlx 4 /* template type that contains movl instruction */ -#define TEMP_mlX 5 /* template type that contains movl instruction */ - -typedef union { /* Instruction encoding for movl instruction */ - struct { - unsigned long qp:6; - unsigned long r1:7; - unsigned long imm7b:7; - unsigned long vc:1; - unsigned long ic:1; - unsigned long imm5c:5; - unsigned long imm9d:9; - unsigned long i:1; - unsigned long op:4; - unsigned long fill:23; - } b; - unsigned long l; -} movl_instruction_t; - -#define MOVL_OPCODE 6 -#define MOVL_ARG(a,b) (((long)a.i<<63) | ((long)b<<22) | ((long)a.ic<<21) | \ - ((long)a.imm5c<<16) | ((long)a.imm9d<<7) | ((long)a.imm7b)) - -typedef struct { /* Instruction bundle */ - unsigned long template:5; - unsigned long ins2:41; - unsigned long ins1l:18; - unsigned long ins1u:23; - unsigned long ins0:41; -} instruction_bundle_t; - - -static void __init -sn_fix_ivt_for_partitioned_system(void) -{ - extern int ia64_ivt; - instruction_bundle_t *p, *pend; - movl_instruction_t ins0, ins1, ins2; - long new_ins1, phys_offset; - unsigned long val; - - /* - * Setup to scan the ivt code. - */ - p = (instruction_bundle_t*)&ia64_ivt; - pend = p + 0x8000/sizeof(instruction_bundle_t); - phys_offset = __pa(p) & ~0x1ffffffffUL; - - /* - * Hunt for movl instructions that contain the node 0 physical address - * of "SWAPPER_PGD_ADDR". These addresses must be relocated to reference the - * actual node that the kernel is loaded on. - */ - for (; p < pend; p++) { - if (p->template != TEMP_mlx && p->template != TEMP_mlX) - continue; - ins0.l = p->ins0; - if (ins0.b.op != MOVL_OPCODE) - continue; - ins1.l = ((long)p->ins1u<<18) | p->ins1l; - ins2.l = p->ins2; - val = MOVL_ARG(ins0.b, ins1.l); - - /* - * Test for correct address. SWAPPER_PGD_ADDR will - * always be a node 0 virtual address. Note that we cant - * use the __pa or __va macros here since they may contain - * debug code that gets fooled here. - */ - if ((PAGE_OFFSET | val) != SWAPPER_PGD_ADDR) - continue; - - /* - * We found an instruction that needs to be fixed. The following - * inserts the NASID of the ivt into the movl instruction. - */ - new_ins1 = ins1.l | (phys_offset>>22); - p->ins1l = new_ins1 & 0x3ffff; - p->ins1u = (new_ins1>>18) & 0x7fffff; - ia64_fc(p); - } - - /* - * Do necessary serialization. - */ - ia64_sync_i(); - ia64_srlz_i(); - -} - -int -IS_RUNNING_ON_SIMULATOR(void) -{ -#ifdef CONFIG_IA64_SGI_SN1_SIM - long sn; - asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); - return(sn == SNMAGIC); -#else - return(0); -#endif -} diff -urN linux-2.4.18/arch/ia64/sn/sn1/smp.c linux-2.4.19-pre5/arch/ia64/sn/sn1/smp.c --- linux-2.4.18/arch/ia64/sn/sn1/smp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/smp.c Thu Jan 1 01:00:00 1970 @@ -1,186 +0,0 @@ -/* - * SN1 Platform specific SMP Support - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 Jack Steiner - */ - - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - - - -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - unsigned long start; - unsigned long end; - unsigned long nbits; -} ptc_params_t; - - -/* - * The following table/struct is for remembering PTC coherency domains. It - * is also used to translate sapicid into cpuids. We dont want to start - * cpus unless we know their cache domain. - */ -#ifdef PTC_NOTYET -sn_sapicid_info_t sn_sapicid_info[NR_CPUS]; -#endif - - - -#ifdef PTC_NOTYET -/* - * NOTE: This is probably not good enough, but I dont want to try to make - * it better until I get some statistics on a running system. - * At a minimum, we should only send IPIs to 1 processor in each TLB domain - * & have it issue a ptc.g on it's own FSB. Also, serialize per FSB, not - * globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ - -static void -sn1_ptc_local(void *arg) -{ - ptc_params_t *params = arg; - unsigned long start, end, nbits; - - start = params->start; - end = params->end; - nbits = params->nbits; - - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); -} - - -void -sn1_ptc_global (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t params; - - params.start = start; - params.end = end; - params.nbits = nbits; - - if (smp_call_function(sn1_ptc_local, ¶ms, 1, 0) != 0) - panic("Unable to do ptc_global - timed out"); - - sn1_ptc_local(¶ms); -} -#endif - - - - -void -sn1_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) -{ - long *p, nasid, slice; - static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; - - /* - * ZZZ - Replace with standard macros when available. - */ - nasid = cpuid_to_nasid(cpuid); - slice = cpuid_to_slice(cpuid); - p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); - -#if defined(ZZZBRINGUP) - { - static int count=0; - if (count++ < 10) printk("ZZ sendIPI 0x%x->0x%x, vec %d, nasid 0x%lx, slice %ld, adr 0x%lx\n", - smp_processor_id(), cpuid, vector, nasid, slice, (long)p); - } -#endif - mb(); - *p = (delivery_mode << 8) | (vector & 0xff); - -} - - -#ifdef CONFIG_SMP - -#ifdef PTC_NOTYET -static void __init -process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) -{ - ia64_sal_ptc_domain_proc_entry_t *pe; - int i, sapicid, cpuid; - - pe = __va(di->proc_list); - for (i=0; iproc_count; i++, pe++) { - sapicid = id_eid_to_sapicid(pe->id, pe->eid); - cpuid = cpu_logical_id(sapicid); - sn_sapicid_info[cpuid].domain = domain; - sn_sapicid_info[cpuid].sapicid = sapicid; - } -} - - -static void __init -process_sal_desc_ptc(ia64_sal_desc_ptc_t *ptc) -{ - ia64_sal_ptc_domain_info_t *di; - int i; - - di = __va(ptc->domain_info); - for (i=0; inum_domains; i++, di++) { - process_sal_ptc_domain_info(di, i); - } -} -#endif - - -void __init -init_sn1_smp_config(void) -{ - - if (!ia64_ptc_domain_info) { - printk("SMP: Can't find PTC domain info. Forcing UP mode\n"); - smp_num_cpus = 1; - return; - } - -#ifdef PTC_NOTYET - memset (sn_sapicid_info, -1, sizeof(sn_sapicid_info)); - process_sal_desc_ptc(ia64_ptc_domain_info); -#endif - -} - -#else /* CONFIG_SMP */ - -void __init -init_sn1_smp_config(void) -{ - -#ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_smp_processor_id(); -#endif -} - -#endif /* CONFIG_SMP */ diff -urN linux-2.4.18/arch/ia64/sn/sn1/sn1_asm.S linux-2.4.19-pre5/arch/ia64/sn/sn1/sn1_asm.S --- linux-2.4.18/arch/ia64/sn/sn1/sn1_asm.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/sn1_asm.S Thu Jan 1 01:00:00 1970 @@ -1,149 +0,0 @@ - -/* - * Copyright (C) 2000 Silicon Graphics - * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) - */ - -#include -#ifdef CONFIG_IA64_SGI_AUTOTEST - -// Testing only. -// Routine will cause MCAs -// zzzmsa(n) -// n=0 MCA via duplicate TLB dropin -// n=0 MCA via read of garbage address -// - -#define ITIR(key, ps) ((key<<8) | (ps<<2)) -#define TLB_PAGESIZE 28 // Use 256MB pages for now. - - .global zzzmca - .proc zzzmca -zzzmca: - alloc loc4 = ar.pfs,2,8,1,0;; - cmp.ne p6,p0=r32,r0;; - movl r2=0x2dead - movl r3=0x3dead - movl r15=0x15dead - movl r16=0x16dead - movl r31=0x31dead - movl loc0=0x34beef - movl loc1=0x35beef - movl loc2=0x36beef - movl loc3=0x37beef - movl out0=0x42beef - - movl r20=0x32feed;; - mov ar32=r20 - movl r20=0x36feed;; - mov ar36=r20 - movl r20=0x65feed;; - mov ar65=r20 - movl r20=0x66feed;; - mov ar66=r20 - -(p6) br.cond.sptk 1f - - rsm 0x2000;; - srlz.d; - mov r11 = 1 - mov r3 = ITIR(0,TLB_PAGESIZE);; - mov cr.itir = r3 - mov r10 = 0;; - itr.d dtr[r11] = r10;; - mov r11 = 2 - - itr.d dtr[r11] = r10;; - br 9f - -1: movl r8=0xfe00000048;; - ld8 r9=[r8];; - mf - mf.a - srlz.d - -9: mov ar.pfs=loc4 - br.ret.sptk rp - - .endp zzzmca - - .global zzzspec - .proc zzzspec -zzzspec: - mov r8=r32 - movl r9=0xe000000000000000 - movl r10=0x4000;; - ld8.s r16=[r8];; - ld8.s r17=[r9];; - add r8=r8,r10;; - ld8.s r18=[r8];; - add r8=r8,r10;; - ld8.s r19=[r8];; - add r8=r8,r10;; - ld8.s r20=[r8];; - mov r8=r0 - tnat.nz p6,p0=r16 - tnat.nz p7,p0=r17 - tnat.nz p8,p0=r18 - tnat.nz p9,p0=r19 - tnat.nz p10,p0=r20;; - (p6) dep r8=-1,r8,0,1;; - (p7) dep r8=-1,r8,1,1;; - (p8) dep r8=-1,r8,2,1;; - (p9) dep r8=-1,r8,3,1;; - (p10) dep r8=-1,r8,4,1;; - br.ret.sptk rp - .endp zzzspec - - .global zzzspec2 - .proc zzzspec2 -zzzspec2: - cmp.eq p6,p7=r2,r2 - movl r16=0xc0000a0001000020 - ;; - mf - ;; - ld8 r9=[r16] - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - ld8 r9=[r16];; - cmp.ne p6,p7=r9,r16 - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - ld8 r9=[r33];; - cmp.ne p6,p7=r9,r33 - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - tpa r23=r32 - add r20=512,r33 - add r21=1024,r33;; - ld8 r9=[r20] - ld8 r10=[r21];; - nop.i 0 - { .mib - nop.m 0 - cmp.ne p6,p7=r10,r33 - (p6) br.spnt 1f - } - ld8 r10=[r32] - ;; - 1: mf.a - mf - br.ret.sptk rp - - .endp zzzspec - -#endif - diff -urN linux-2.4.18/arch/ia64/sn/sn1/sn1_ksyms.c linux-2.4.19-pre5/arch/ia64/sn/sn1/sn1_ksyms.c --- linux-2.4.18/arch/ia64/sn/sn1/sn1_ksyms.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/sn1_ksyms.c Thu Jan 1 01:00:00 1970 @@ -1,39 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 Jesse Barnes (jbarnes@sgi.com) - */ - - -/* - * Architecture-specific kernel symbols - */ - -#include - -#include - -/* - * I/O routines - */ -EXPORT_SYMBOL(sn1_outb); -EXPORT_SYMBOL(sn1_outl); -EXPORT_SYMBOL(sn1_outw); -EXPORT_SYMBOL(sn1_inw); -EXPORT_SYMBOL(sn1_inb); -EXPORT_SYMBOL(sn1_inl); - -/* - * other stuff (more to be added later, cleanup then) - */ -EXPORT_SYMBOL(sn1_pci_map_sg); -EXPORT_SYMBOL(sn1_pci_unmap_sg); -EXPORT_SYMBOL(sn1_pci_alloc_consistent); -EXPORT_SYMBOL(sn1_pci_free_consistent); -EXPORT_SYMBOL(sn1_dma_address); - -#include -EXPORT_SYMBOL(alloc_pages); diff -urN linux-2.4.18/arch/ia64/sn/sn1/sv.c linux-2.4.19-pre5/arch/ia64/sn/sn1/sv.c --- linux-2.4.18/arch/ia64/sn/sn1/sv.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/sv.c Thu Jan 1 01:00:00 1970 @@ -1,551 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. All rights reserved - * - * This implemenation of synchronization variables is heavily based on - * one done by Steve Lord - * - * Paul Cassella - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* Define this to have sv_test() run some simple tests. - kernel_thread() must behave as expected when this is called. */ -#undef RUN_SV_TEST - -#define DEBUG - -/* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast() - can sanity check interrupt state on architectures where we know - how. */ -#ifdef DEBUG - #define SV_DEBUG_INTERRUPT_STATE - #ifdef __mips64 - #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0) - #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0) - #define SV_INTERRUPT_TEST_WORKERS 31 - #elif defined(__ia64) - #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0) - #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0) - #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */ - #else - #undef SV_DEBUG_INTERRUPT_STATE - #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */ - #endif /* __mips64 */ -#endif /* DEBUG */ - - -/* XXX FIXME hack hack hack. Our mips64 tree is from before the - switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */ -#ifdef TASK_EXCLUSIVE - #undef EXCLUSIVE_IN_QUEUE -#else - #define EXCLUSIVE_IN_QUEUE - #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */ -#endif - - -static inline void sv_lock(sv_t *sv) { - spin_lock(&sv->sv_lock); -} - -static inline void sv_unlock(sv_t *sv) { - spin_unlock(&sv->sv_lock); -} - -/* up() is "extern inline", so we can't pass its address to sv_wait. - Use this function's address instead. */ -static void up_wrapper(struct semaphore *sem) { - up(sem); -} - -/* spin_unlock() is sometimes a macro. */ -static void spin_unlock_wrapper(spinlock_t *s) { - spin_unlock(s); -} - -/* XXX Perhaps sv_wait() should do the switch() each time and avoid - the extra indirection and the need for the _wrapper functions? */ - -static inline void sv_set_mon_type(sv_t *sv, int type) { - switch (type) { - case SV_MON_SPIN: - sv->sv_mon_unlock_func = - (sv_mon_unlock_func_t)spin_unlock_wrapper; - break; - case SV_MON_SEMA: - sv->sv_mon_unlock_func = - (sv_mon_unlock_func_t)up_wrapper; - if(sv->sv_flags & SV_INTS) { - printk(KERN_ERR "sv_set_mon_type: The monitor lock " - "cannot be shared with interrupts if it is a " - "semaphore!\n"); - BUG(); - } - if(sv->sv_flags & SV_BHS) { - printk(KERN_ERR "sv_set_mon_type: The monitor lock " - "cannot be shared with bottom-halves if it is " - "a semaphore!\n"); - BUG(); - } - break; -#if 0 - /* - * If needed, and will need to think about interrupts. This - * may be needed, for example, if someone wants to use sv's - * with something like dev_base; writers need to hold two - * locks. - */ - case SV_MON_CUSTOM: - { - struct sv_mon_custom *c = lock; - sv->sv_mon_unlock_func = c->sv_mon_unlock_func; - sv->sv_mon_lock = c->sv_mon_lock; - break; - } -#endif - - default: - printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! " - "(flags 0x%x)\n", type, type, sv->sv_flags); - BUG(); - break; - } - sv->sv_flags |= type; -} - -static inline void sv_set_ord(sv_t *sv, int ord) { - if (!ord) - ord = SV_ORDER_DEFAULT; - - if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) { - printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ", - ord, ord); - BUG(); - } - - sv->sv_flags |= ord; -} - -void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags) -{ - int ord = flags & SV_ORDER_MASK; - int type = flags & SV_MON_MASK; - - /* Copy all non-order, non-type flags */ - sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK)); - - if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) { - printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n"); - BUG(); - } - - sv_set_ord(sv, ord); - sv_set_mon_type(sv, type); - - /* If lock is NULL, we'll get it from sv_wait_compat() (and - ignore it in sv_signal() and sv_broadcast()). */ - sv->sv_mon_lock = lock; - - spin_lock_init(&sv->sv_lock); - init_waitqueue_head(&sv->sv_waiters); -} - -/* - * The associated lock must be locked on entry. It is unlocked on return. - * - * Return values: - * - * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0 - * n = 0 : timeout expired - * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0 - */ -signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) -{ - DECLARE_WAITQUEUE( wait, current ); - unsigned long flags; - signed long ret = 0; - -#ifdef SV_DEBUG_INTERRUPT_STATE - { - unsigned long flags; - __save_flags(flags); - - if(sv->sv_flags & SV_INTS) { - if(SV_TEST_INTERRUPTS_ENABLED(flags)) { - printk(KERN_ERR "sv_wait: SV_INTS and interrupts " - "enabled (flags: 0x%lx)\n", flags); - BUG(); - } - } else { - if (SV_TEST_INTERRUPTS_DISABLED(flags)) { - printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts " - "disabled! (flags: 0x%lx)\n", flags); - } - } - } -#endif /* SV_DEBUG_INTERRUPT_STATE */ - - sv_lock(sv); - - sv->sv_mon_unlock_func(sv->sv_mon_lock); - - /* Add ourselves to the wait queue and set the state before - * releasing the sv_lock so as to avoid racing with the - * wake_up() in sv_signal() and sv_broadcast(). - */ - - /* don't need the _irqsave part, but there is no wq_write_lock() */ - wq_write_lock_irqsave(&sv->sv_waiters.lock, flags); - -#ifdef EXCLUSIVE_IN_QUEUE - wait.flags |= WQ_FLAG_EXCLUSIVE; -#endif - - switch(sv->sv_flags & SV_ORDER_MASK) { - case SV_ORDER_FIFO: - __add_wait_queue_tail(&sv->sv_waiters, &wait); - break; - case SV_ORDER_FILO: - __add_wait_queue(&sv->sv_waiters, &wait); - break; - default: - printk(KERN_ERR "sv_wait: unknown order! (sv: 0x%p, flags: 0x%x)\n", - sv, sv->sv_flags); - BUG(); - } - wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags); - - if(sv_wait_flags & SV_WAIT_SIG) - set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE ); - else - set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE); - - spin_unlock(&sv->sv_lock); - - if(sv->sv_flags & SV_INTS) - local_irq_enable(); - else if(sv->sv_flags & SV_BHS) - local_bh_enable(); - - if (timeout) - ret = schedule_timeout(timeout); - else - schedule(); - - if(current->state != TASK_RUNNING) /* XXX Is this possible? */ { - printk(KERN_ERR "sv_wait: state not TASK_RUNNING after " - "schedule().\n"); - set_current_state(TASK_RUNNING); - } - - remove_wait_queue(&sv->sv_waiters, &wait); - - /* Return cases: - - woken by a sv_signal/sv_broadcast - - woken by a signal - - woken by timeout expiring - */ - - /* XXX This isn't really accurate; we may have been woken - before the signal anyway.... */ - if(signal_pending(current)) - return timeout ? -ret : -1; - return timeout ? ret : 1; -} - - -void sv_signal(sv_t *sv) -{ - /* If interrupts can acquire this lock, they can also acquire the - sv_mon_lock, which we must already have to have called this, so - interrupts must be disabled already. If interrupts cannot - contend for this lock, we don't have to worry about it. */ - -#ifdef SV_DEBUG_INTERRUPT_STATE - if(sv->sv_flags & SV_INTS) { - unsigned long flags; - __save_flags(flags); - if(SV_TEST_INTERRUPTS_ENABLED(flags)) - printk(KERN_ERR "sv_signal: SV_INTS and " - "interrupts enabled! (flags: 0x%lx)\n", flags); - } -#endif /* SV_DEBUG_INTERRUPT_STATE */ - - sv_lock(sv); - wake_up(&sv->sv_waiters); - sv_unlock(sv); -} - -void sv_broadcast(sv_t *sv) -{ -#ifdef SV_DEBUG_INTERRUPT_STATE - if(sv->sv_flags & SV_INTS) { - unsigned long flags; - __save_flags(flags); - if(SV_TEST_INTERRUPTS_ENABLED(flags)) - printk(KERN_ERR "sv_broadcast: SV_INTS and " - "interrupts enabled! (flags: 0x%lx)\n", flags); - } -#endif /* SV_DEBUG_INTERRUPT_STATE */ - - sv_lock(sv); - wake_up_all(&sv->sv_waiters); - sv_unlock(sv); -} - -void sv_destroy(sv_t *sv) -{ - if(!spin_trylock(&sv->sv_lock)) { - printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", sv); - BUG(); - } - - /* XXX Check that the waitqueue is empty? - Mark the sv destroyed? - */ -} - - -#ifdef RUN_SV_TEST - -static DECLARE_MUTEX_LOCKED(talkback); -static DECLARE_MUTEX_LOCKED(sem); -sv_t sv; -sv_t sv_filo; - -static int sv_test_1_w(void *arg) -{ - printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg); - - spin_lock((spinlock_t*)arg); - printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n"); - - up(&sem); - - printk("sv_test_1_w: sv_spin_wait()'ing.\n"); - - sv_spin_wait(&sv, arg); - - printk("sv_test_1_w: talkback.\n"); - up(&talkback); - - printk("sv_test_1_w: exiting.\n"); - return 0; -} - -static int sv_test_1_s(void *arg) -{ - printk("sv_test_1_s: waiting for semaphore.\n"); - down(&sem); - printk("sv_test_1_s: semaphore acquired. Acquiring spinlock.\n"); - spin_lock((spinlock_t*)arg); - printk("sv_test_1_s: spinlock acquired. sv_signaling.\n"); - sv_signal(&sv); - printk("sv_test_1_s: talkback.\n"); - up(&talkback); - printk("sv_test_1_s: exiting.\n"); - return 0; - -} - -static int count; -static DECLARE_MUTEX(monitor); - -static int sv_test_2_w(void *arg) -{ - int dummy = count++; - sv_t *sv = (sv_t *)arg; - - down(&monitor); - up(&talkback); - printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy); - sv_sema_wait(sv, &monitor); - printk("sv_test_2_w: thread %d woken, exiting.\n", dummy); - up(&sem); - return 0; -} - -static int sv_test_2_s_1(void *arg) -{ - int i; - sv_t *sv = (sv_t *)arg; - - down(&monitor); - for(i = 0; i < 3; i++) { - printk("sv_test_2_s_1: waking one thread.\n"); - sv_signal(sv); - down(&sem); - } - - printk("sv_test_2_s_1: signaling and broadcasting again. Nothing should happen.\n"); - sv_signal(sv); - sv_broadcast(sv); - sv_signal(sv); - sv_broadcast(sv); - - printk("sv_test_2_s_1: talkbacking.\n"); - up(&talkback); - up(&monitor); - return 0; -} - -static int sv_test_2_s(void *arg) -{ - int i; - sv_t *sv = (sv_t *)arg; - - down(&monitor); - for(i = 0; i < 3; i++) { - printk("sv_test_2_s: waking one thread (should be %d.)\n", i); - sv_signal(sv); - down(&sem); - } - - printk("sv_test_3_s: waking remaining threads with broadcast.\n"); - sv_broadcast(sv); - for(; i < 10; i++) - down(&sem); - - printk("sv_test_3_s: sending talkback.\n"); - up(&talkback); - - printk("sv_test_3_s: exiting.\n"); - up(&monitor); - return 0; -} - - -static void big_test(sv_t *sv) -{ - int i; - - count = 0; - - for(i = 0; i < 3; i++) { - printk("big_test: spawning thread %d.\n", i); - kernel_thread(sv_test_2_w, sv, 0); - down(&talkback); - } - - printk("big_test: spawning first wake-up thread.\n"); - kernel_thread(sv_test_2_s_1, sv, 0); - - down(&talkback); - printk("big_test: talkback happened.\n"); - - - for(i = 3; i < 13; i++) { - printk("big_test: spawning thread %d.\n", i); - kernel_thread(sv_test_2_w, sv, 0); - down(&talkback); - } - - printk("big_test: spawning wake-up thread.\n"); - kernel_thread(sv_test_2_s, sv, 0); - - down(&talkback); -} - -sv_t int_test_sv; -spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED; -int int_test_ready; -static int irqtestcount; - -static int interrupt_test_worker(void *unused) -{ - int id = ++irqtestcount; - int it = 0; - unsigned long flags, flags2; - - printk("ITW: thread %d started.\n", id); - - while(1) { - __save_flags(flags2); - if(jiffies % 3) { - printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2); - spin_lock_irqsave(&int_test_spin, flags); - } else { - printk("ITW %2d %5d: spin_lock_irqing (%lx)\n", id, it, flags2); - spin_lock_irq(&int_test_spin); - } - - __save_flags(flags2); - printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2); - sv_wait(&int_test_sv, 0, 0); - - __save_flags(flags2); - printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies & 0xf); - if(current->state != TASK_RUNNING) - printk("ITW: current->state isn't RUNNING after schedule!\n"); - it++; - } -} - -static void interrupt_test(void) -{ - int i; - - printk("interrupt_test: initing sv.\n"); - sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS); - - for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) { - printk("interrupt_test: starting test thread %d.\n", i); - kernel_thread(interrupt_test_worker, 0, 0); - } - printk("interrupt_test: done with init part.\n"); - int_test_ready = 1; -} - -int sv_test(void) -{ - spinlock_t s = SPIN_LOCK_UNLOCKED; - - sv_init(&sv, &s, SV_MON_SPIN); - printk("sv_test: starting sv_test_1_w.\n"); - kernel_thread(sv_test_1_w, &s, 0); - printk("sv_test: starting sv_test_1_s.\n"); - kernel_thread(sv_test_1_s, &s, 0); - - printk("sv_test: waiting for talkback.\n"); - down(&talkback); down(&talkback); - printk("sv_test: talkback happened, sv_destroying.\n"); - sv_destroy(&sv); - - count = 0; - - printk("sv_test: beginning big_test on sv.\n"); - - sv_init(&sv, &monitor, SV_MON_SEMA); - big_test(&sv); - sv_destroy(&sv); - - printk("sv_test: beginning big_test on sv_filo.\n"); - sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO); - big_test(&sv_filo); - sv_destroy(&sv_filo); - - interrupt_test(); - - printk("sv_test: done.\n"); - return 0; -} - -__initcall(sv_test); - -#endif /* RUN_SV_TEST */ diff -urN linux-2.4.18/arch/ia64/sn/sn1/synergy.c linux-2.4.19-pre5/arch/ia64/sn/sn1/synergy.c --- linux-2.4.18/arch/ia64/sn/sn1/synergy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/sn1/synergy.c Thu Jan 1 01:00:00 1970 @@ -1,429 +0,0 @@ - -/* - * SN1 Platform specific synergy Support - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 2000 Alan Mayer (ajm@sgi.com) - */ - - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -int bit_pos_to_irq(int bit); -void setclear_mask_b(int irq, int cpuid, int set); -void setclear_mask_a(int irq, int cpuid, int set); -void * kmalloc(size_t size, int flags); - - -void -synergy_intr_alloc(int bit, int cpuid) { - return; -} - -int -synergy_intr_connect(int bit, - int cpuid) -{ - int irq; - unsigned is_b; - - irq = bit_pos_to_irq(bit); - - is_b = (cpuid_to_slice(cpuid)) & 1; - if (is_b) { - setclear_mask_b(irq,cpuid,1); - setclear_mask_a(irq,cpuid, 0); - } else { - setclear_mask_a(irq, cpuid, 1); - setclear_mask_b(irq, cpuid, 0); - } - return 0; -} -void -setclear_mask_a(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0A; - addr = VEC_MASK0A_ADDR; - break; - case 1: - reg = VEC_MASK1A; - addr = VEC_MASK1A_ADDR; - break; - case 2: - reg = VEC_MASK2A; - addr = VEC_MASK2A_ADDR; - break; - case 3: - reg = VEC_MASK3A; - addr = VEC_MASK3A_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -void -setclear_mask_b(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0B; - addr = VEC_MASK0B_ADDR; - break; - case 1: - reg = VEC_MASK1B; - addr = VEC_MASK1B_ADDR; - break; - case 2: - reg = VEC_MASK2B; - addr = VEC_MASK2B_ADDR; - break; - case 3: - reg = VEC_MASK3B; - addr = VEC_MASK3B_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) - -/* - * Synergy perf registers. Multiplexed via timer_interrupt - */ -static struct proc_dir_entry *synergy_perf_proc = NULL; - -/* - * read handler for /proc/synergy - */ -static int -synergy_perf_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - cnodeid_t cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int len = 0; - - len += sprintf(page+len, "# cnode module slot event synergy-A synergy-B\n"); - - /* walk the event list for each node */ - for (cnode=0; cnode < numnodes; cnode++) { - npdap = NODEPDA(cnode); - if (npdap->synergy_perf_enabled == 0) { - len += sprintf(page+len, "# DISABLED\n"); - break; - } - - spin_lock_irq(&npdap->synergy_perf_lock); - for (p = npdap->synergy_perf_first; p;) { - uint64_t cnt_a=0, cnt_b=0; - - if (p->intervals > 0) { - cnt_a = p->counts[0] * npdap->synergy_active_intervals / p->intervals; - cnt_b = p->counts[1] * npdap->synergy_active_intervals / p->intervals; - } - - len += sprintf(page+len, "%d %d %d %12lx %lu %lu\n", - (int)cnode, (int)npdap->module_id, (int)npdap->slotdesc, - p->modesel, cnt_a, cnt_b); - - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - } - - 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 -synergy_perf_append(uint64_t modesel) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int err = 0; - - /* bit 45 is enable */ - modesel |= (1UL << 45); - - for (cnode=0; cnode < numnodes; cnode++) { - /* for each node, insert a new synergy_perf entry */ - if ((npdap = NODEPDA(cnode)) == NULL) { - printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, nodepda); - continue; - } - - /* XX use kmem_alloc_node() when it is implemented */ - p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); - if (p == NULL) - err = -ENOMEM; - else { - memset(p, 0, sizeof(synergy_perf_t)); - p->modesel = modesel; - if (npdap->synergy_perf_data == NULL) { - /* circular list */ - p->next = p; - npdap->synergy_perf_data = p; - npdap->synergy_perf_first = p; - } - else { - /* - * Jumble up the insertion order so we get better sampling. - * Once the list is complete, "first" stays the same so the - * reporting order is consistent. - */ - p->next = npdap->synergy_perf_first->next; - npdap->synergy_perf_first->next = p; - npdap->synergy_perf_first = p->next; - } - } - } - - return err; -} - -static int -synergy_perf_write_proc (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - int cnode; - nodepda_t *npdap; - uint64_t modesel; - char cmd[64]; - extern long atoi(char *); - - if (count == sizeof(uint64_t)) { - if (copy_from_user(&modesel, buffer, sizeof(uint64_t))) - return -EFAULT; - synergy_perf_append(modesel); - } - else { - if (copy_from_user(cmd, buffer, count < sizeof(cmd) ? count : sizeof(cmd))) - return -EFAULT; - if (strncmp(cmd, "enable", 6) == 0) { - /* enable counting */ - for (cnode=0; cnode < numnodes; cnode++) { - npdap = NODEPDA(cnode); - npdap->synergy_perf_enabled = 1; - } - printk("NOTICE: synergy perf counting enabled\n"); - } - else - if (strncmp(cmd, "disable", 7) == 0) { - /* disable counting */ - for (cnode=0; cnode < numnodes; cnode++) { - npdap = NODEPDA(cnode); - npdap->synergy_perf_enabled = 0; - } - printk("NOTICE: synergy perf counting disabled\n"); - } - else - if (strncmp(cmd, "frequency", 9) == 0) { - /* set the update frequency (timer-interrupts per update) */ - int freq; - - if (count < 12) - return -EINVAL; - freq = atoi(cmd + 10); - if (freq <= 0 || freq > 100) - return -EINVAL; - for (cnode=0; cnode < numnodes; cnode++) { - npdap = NODEPDA(cnode); - npdap->synergy_perf_freq = (uint64_t)freq; - } - printk("NOTICE: synergy perf freq set to %d\n", freq); - } - else - return -EINVAL; - } - - return count; -} - -void -synergy_perf_update(int cpu) -{ - nasid_t nasid; - cnodeid_t cnode = cpuid_to_cnodeid(cpu); - struct nodepda_s *npdap; - extern struct nodepda_s *nodepda; - - if (nodepda == NULL || (npdap=NODEPDA(cnode)) == NULL || npdap->synergy_perf_enabled == 0 || - npdap->synergy_perf_data == NULL) { - /* I/O not initialized, or not enabled, or no events to monitor */ - return; - } - - if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { - /* don't multiplex on every timer interrupt */ - return; - } - - /* - * Read registers for last interval and increment counters. - * Hold the per-node synergy_perf_lock so concurrent readers get - * consistent values. - */ - spin_lock_irq(&npdap->synergy_perf_lock); - - nasid = cpuid_to_nasid(cpu); - npdap->synergy_active_intervals++; - npdap->synergy_perf_data->intervals++; - - npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); - - npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); - - /* skip to next in circular list */ - npdap->synergy_perf_data = npdap->synergy_perf_data->next; - - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* set the counter 0 selection modes for both A and B */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); - - /* and reset the counter registers to zero */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); -} - -void -synergy_perf_init(void) -{ - if ((synergy_perf_proc = create_proc_entry("synergy", 0644, NULL)) != NULL) { - synergy_perf_proc->read_proc = synergy_perf_read_proc; - synergy_perf_proc->write_proc = synergy_perf_write_proc; - printk("markgw: synergy_perf_init()\n"); - } -} - -#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ - diff -urN linux-2.4.18/arch/ia64/sn/tools/make_textsym linux-2.4.19-pre5/arch/ia64/sn/tools/make_textsym --- linux-2.4.18/arch/ia64/sn/tools/make_textsym Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/sn/tools/make_textsym Sat Mar 30 22:55:26 2002 @@ -1,5 +1,14 @@ #!/bin/sh +# # Build a textsym file for use in the Arium ITP probe. +# +# +# 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. +# help() { cat < $TMPSYM +SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l` + +# Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE. +# Eventually, these values should be: +# dataprefix ffffffff +# textprefix fffffffe +# but right now they're still changing, so make them dynamic. +dataprefix=`awk ' / \.data / { print substr($1, 0, 8) ; exit ; }' $TMPSYM` +textprefix=`awk ' / \.text / { print substr($1, 0, 8) ; exit ; }' $TMPSYM` # pipe everything thru sort echo "TEXTSYM V1.0" (cat < 0) { + n = n*16 + substr(s,1,1) + s = substr(s,2) + } + printf "GLOBAL | %s | DATA | %s | %d\n", $1, $NF, n + } } if($NF == "_end") exit } -' ) | egrep -v " __device| __vendor" | awk ' +' $TMPSYM ) | egrep -v " __device| __vendor" | awk -v sn1="$SN1" ' /GLOBAL/ { print $0 - print substr($0,1,9) substr($0,18,18) "Phy_" substr($0,36) + if (sn1 != 0) { + /* 32 bits of sn1 physical addrs, */ + print substr($0,1,9) substr($0,18,18) "Phy_" substr($0,36) + } else { + /* 38 bits of sn2 physical addrs, need addr space bits */ + print substr($0,1,9) "30" substr($0,18,18) "Phy_" substr($0,36) + } } ' | sort -k3 - - N=`wc -l $TEXTSYM|awk '{print $1}'` echo "Generated TEXTSYM file" >&2 diff -urN linux-2.4.18/arch/ia64/tools/print_offsets.c linux-2.4.19-pre5/arch/ia64/tools/print_offsets.c --- linux-2.4.18/arch/ia64/tools/print_offsets.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/tools/print_offsets.c Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ * Utility to generate asm-ia64/offsets.h. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang + * 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 @@ -58,7 +58,7 @@ { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, #ifdef CONFIG_PERFMON - { "IA64_TASK_PFM_MUST_BLOCK_OFFSET",offsetof(struct task_struct, thread.pfm_must_block) }, + { "IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET",offsetof(struct task_struct, thread.pfm_ovfl_block_reset) }, #endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, diff -urN linux-2.4.18/arch/ia64/vmlinux.lds.S linux-2.4.19-pre5/arch/ia64/vmlinux.lds.S --- linux-2.4.18/arch/ia64/vmlinux.lds.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ia64/vmlinux.lds.S Sat Mar 30 22:55:26 2002 @@ -13,6 +13,8 @@ *(.text.exit) *(.data.exit) *(.exitcall.exit) + *(.IA_64.unwind.text.exit) + *(.IA_64.unwind_info.text.exit) } v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ diff -urN linux-2.4.18/arch/m68k/atari/ataints.c linux-2.4.19-pre5/arch/m68k/atari/ataints.c --- linux-2.4.18/arch/m68k/atari/ataints.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/atari/ataints.c Sat Mar 30 22:55:33 2002 @@ -168,7 +168,7 @@ void atari_slow_irq_##n##_dummy (void) { \ __asm__ (__ALIGN_STR "\n" \ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ -" addql #1,"SYMBOL_NAME_STR(irq_stat)"+8\n" /* local_irq_count */ \ +" addql #1,%5\n" /* local_irq_count++ */ \ SAVE_ALL_INT "\n" \ GET_CURRENT(%%d0) "\n" \ " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ @@ -193,8 +193,10 @@ : : "i" (&kstat.irqs[0][n+8]), "i" (&irq_handler[n+8]), \ "n" (PT_OFF_SR), "n" (n), \ "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ - : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)) \ + : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ + "m" (local_irq_count(0)) \ ); \ + for (;;); /* fake noreturn */ \ } BUILD_SLOW_IRQ(0); @@ -274,7 +276,7 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": orw #0x700,%%sr /* disable all interrupts */ "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t - addql #1,"SYMBOL_NAME_STR(irq_stat)"+8\n" /* local_irq_count */ + addql #1,%2\n" /* local_irq_count++ */ SAVE_ALL_INT "\n" GET_CURRENT(%%d0) " /* get vector number from stack frame and convert to source */ @@ -294,8 +296,10 @@ addql #8,%%sp addql #4,%%sp jbra "SYMBOL_NAME_STR(ret_from_interrupt) - : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC) + : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC), + "m" (local_irq_count(0)) ); + for (;;); } /* GK: diff -urN linux-2.4.18/arch/m68k/atari/stram.c linux-2.4.19-pre5/arch/m68k/atari/stram.c --- linux-2.4.18/arch/m68k/atari/stram.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/atari/stram.c Sat Mar 30 22:55:33 2002 @@ -236,8 +236,8 @@ static void do_stram_request(request_queue_t *); static int stram_open( struct inode *inode, struct file *filp ); static int stram_release( struct inode *inode, struct file *filp ); -#endif static void reserve_region(void *start, void *end); +#endif static BLOCK *add_region( void *addr, unsigned long size ); static BLOCK *find_region( void *addr ); static int remove_region( BLOCK *block ); @@ -296,7 +296,7 @@ max_swap_size = (!MACH_IS_HADES && (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= - (high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; + ((unsigned long)high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); #endif @@ -759,7 +759,7 @@ /* Get a page for the entry, using the existing swap cache page if there is one. Otherwise, get a clean page and read the swap into it. */ - page = read_swap_cache(entry); + page = read_swap_cache_async(entry); if (!page) { swap_free(entry); return -ENOMEM; @@ -768,7 +768,7 @@ for_each_task(p) unswap_process(p->mm, entry, page); read_unlock(&tasklist_lock); - shm_unuse(entry, page); + shmem_unuse(entry, page); /* Now get rid of the extra reference to the temporary page we've been using. */ if (PageSwapCache(page)) @@ -1072,7 +1072,6 @@ return( 0 ); } -#endif /* CONFIG_STRAM_SWAP */ /* ------------------------------------------------------------------------ */ @@ -1085,6 +1084,7 @@ reserve_bootmem (virt_to_phys(start), end - start); } +#endif /* CONFIG_STRAM_SWAP */ /* ------------------------------------------------------------------------ */ diff -urN linux-2.4.18/arch/m68k/atari/time.c linux-2.4.19-pre5/arch/m68k/atari/time.c --- linux-2.4.18/arch/m68k/atari/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/atari/time.c Sat Mar 30 22:55:33 2002 @@ -83,14 +83,14 @@ #define RTC_READ(reg) \ ({ unsigned char __val; \ - (void) writeb(reg,&tt_rtc.regsel); \ + (void) atari_writeb(reg,&tt_rtc.regsel); \ __val = tt_rtc.data; \ __val; \ }) #define RTC_WRITE(reg,val) \ do { \ - writeb(reg,&tt_rtc.regsel); \ + atari_writeb(reg,&tt_rtc.regsel); \ tt_rtc.data = (val); \ } while(0) diff -urN linux-2.4.18/arch/m68k/config.in linux-2.4.19-pre5/arch/m68k/config.in --- linux-2.4.18/arch/m68k/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/config.in Sat Mar 30 22:55:33 2002 @@ -26,7 +26,6 @@ mainmenu_option next_comment comment 'Platform dependent setup' -define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n define_bool CONFIG_PCMCIA n @@ -146,11 +145,18 @@ fi fi +if [ "$CONFIG_Q40" = "y" -o "$CONFIG_AMIGA_PCMCIA" = "y" \ + -o "$CONFIG_GG2" = "y" ]; then + define_bool CONFIG_ISA y +else + define_bool CONFIG_ISA n +fi + source drivers/pci/Config.in source drivers/zorro/Config.in if [ "$CONFIG_Q40" = "y" ]; then -source drivers/pnp/Config.in + source drivers/pnp/Config.in fi endmenu @@ -297,9 +303,17 @@ bool ' Keepalive and linefill' CONFIG_SLIP_SMART bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 fi - tristate ' PPP (point-to-point) support' CONFIG_PPP + tristate 'PPP (point-to-point protocol) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' + dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL + dep_bool ' PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER + dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP + dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP + dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP + dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP + fi fi tristate ' EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_ZORRO" = "y" ]; then @@ -352,7 +366,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT fi - tristate 'NE2000/NE1000 support' CONFIG_NE2000 + dep_tristate 'NE2000/NE1000 support' CONFIG_NE2000 m fi fi endmenu @@ -543,6 +557,11 @@ mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Verbose BUG() reporting' CONFIG_DEBUG_BUGVERBOSE +fi + endmenu diff -urN linux-2.4.18/arch/m68k/hp300/time.c linux-2.4.19-pre5/arch/m68k/hp300/time.c --- linux-2.4.18/arch/m68k/hp300/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/hp300/time.c Sat Mar 30 22:55:33 2002 @@ -41,7 +41,7 @@ unsigned long tmp; void (*vector)(int, void *, struct pt_regs *) = dev_id; readb(CLOCKBASE + CLKSR); - asm volatile ("movpw %1@(5),%0" : "=r" (tmp) : "a" (CLOCKBASE)); + asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); vector(irq, NULL, regs); } diff -urN linux-2.4.18/arch/m68k/kernel/entry.S linux-2.4.19-pre5/arch/m68k/kernel/entry.S --- linux-2.4.18/arch/m68k/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -184,7 +184,7 @@ #if 0 #if CONFIG_AMIGA SYMBOL_NAME_LABEL(ami_inthandler) - addql #1,SYMBOL_NAME(irq_stat)+8 | local_irq_count + addql #1,SYMBOL_NAME(irq_stat)+4 | local_irq_count SAVE_ALL_INT GET_CURRENT(%d0) @@ -216,7 +216,7 @@ SYMBOL_NAME_LABEL(inthandler) SAVE_ALL_INT GET_CURRENT(%d0) - addql #1,SYMBOL_NAME(irq_stat)+8 | local_irq_count + addql #1,SYMBOL_NAME(irq_stat)+4 | local_irq_count | put exception # in d0 bfextu %sp@(PT_VECTOR){#4,#10},%d0 @@ -235,7 +235,7 @@ 3: addql #8,%sp | pop parameters off stack SYMBOL_NAME_LABEL(ret_from_interrupt) - subql #1,SYMBOL_NAME(irq_stat)+8 | local_irq_count + subql #1,SYMBOL_NAME(irq_stat)+4 | local_irq_count jeq 1f 2: RESTORE_ALL @@ -248,11 +248,8 @@ jhi 2b #endif /* check if we need to do software interrupts */ - - movel SYMBOL_NAME(irq_stat),%d0 | softirq_active - andl SYMBOL_NAME(irq_stat)+4,%d0 | softirq_mask + tstl SYMBOL_NAME(irq_stat) | softirq_pending ? jeq SYMBOL_NAME(ret_from_exception) - pea SYMBOL_NAME(ret_from_exception) jra SYMBOL_NAME(do_softirq) @@ -642,10 +639,12 @@ .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_setfsuid) /* 215 */ .long SYMBOL_NAME(sys_setfsgid) - .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_pivot_root) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_gettid) + .long SYMBOL_NAME(sys_tkill) .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) diff -urN linux-2.4.18/arch/m68k/kernel/process.c linux-2.4.19-pre5/arch/m68k/kernel/process.c --- linux-2.4.18/arch/m68k/kernel/process.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/process.c Sat Mar 30 22:55:33 2002 @@ -136,6 +136,7 @@ register long retval __asm__ ("d0"); register long clone_arg __asm__ ("d1") = flags | CLONE_VM; + retval = __NR_clone; __asm__ __volatile__ ("clrl %%d2\n\t" "trap #0\n\t" /* Linux/m68k system call */ @@ -145,14 +146,15 @@ "movel %3,%%sp@-\n\t" /* push argument */ "jsr %4@\n\t" /* call fn */ "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%0\n\t" /* exit */ + "movel %2,%%d0\n\t" /* exit */ "trap #0\n" "1:" - : "=d" (retval) - : "0" (__NR_clone), "i" (__NR_exit), + : "+d" (retval) + : "i" (__NR_clone), "i" (__NR_exit), "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), "i" (-KTHREAD_SIZE) - : "d0", "d2"); + : "d2"); + pid = retval; } diff -urN linux-2.4.18/arch/m68k/kernel/ptrace.c linux-2.4.19-pre5/arch/m68k/kernel/ptrace.c --- linux-2.4.18/arch/m68k/kernel/ptrace.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/ptrace.c Sat Mar 30 22:55:33 2002 @@ -103,7 +103,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - unsigned long flags; int ret; lock_kernel(); diff -urN linux-2.4.18/arch/m68k/kernel/setup.c linux-2.4.19-pre5/arch/m68k/kernel/setup.c --- linux-2.4.18/arch/m68k/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/setup.c Sat Mar 30 22:55:33 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,7 @@ char *mach_sysrq_xlate = NULL; #endif -#if defined(CONFIG_ISA) +#if defined(CONFIG_ISA) && defined(MULTI_ISA) int isa_type; int isa_sex; #endif @@ -388,7 +389,7 @@ paging_init(); /* set ISA defs early as possible */ -#if defined(CONFIG_ISA) +#if defined(CONFIG_ISA) && defined(MULTI_ISA) #if defined(CONFIG_Q40) if (MACH_IS_Q40) { isa_type = Q40_ISA; @@ -408,7 +409,7 @@ #endif } -int get_cpuinfo(char * buffer) +static int show_cpuinfo(struct seq_file *m, void *v) { const char *cpu, *mmu, *fpu; unsigned long clockfreq, clockfactor; @@ -469,7 +470,7 @@ clockfreq = loops_per_jiffy*HZ*clockfactor; - return(sprintf(buffer, "CPU:\t\t%s\n" + seq_printf(m, "CPU:\t\t%s\n" "MMU:\t\t%s\n" "FPU:\t\t%s\n" "Clocking:\t%lu.%1luMHz\n" @@ -478,9 +479,28 @@ cpu, mmu, fpu, clockfreq/1000000,(clockfreq/100000)%10, loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, - loops_per_jiffy)); + loops_per_jiffy); + return 0; +} +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} +static void c_stop(struct seq_file *m, void *v) +{ } +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; int get_hardware_list(char *buffer) { @@ -495,7 +515,7 @@ strcpy(model, "Unknown m68k"); len += sprintf(buffer+len, "Model:\t\t%s\n", model); - len += get_cpuinfo(buffer+len); + //len += get_cpuinfo(buffer+len); for (mem = 0, i = 0; i < m68k_num_memory; i++) mem += m68k_memory[i].size; len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); diff -urN linux-2.4.18/arch/m68k/kernel/signal.c linux-2.4.19-pre5/arch/m68k/kernel/signal.c --- linux-2.4.18/arch/m68k/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -1118,14 +1119,17 @@ continue; /* FALLTHRU */ - case SIGSTOP: + case SIGSTOP: { + struct signal_struct *sig; 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); + sig = current->p_pptr->sig; + if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags +& SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); schedule(); continue; + } case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: @@ -1135,10 +1139,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/m68k/kernel/sun3-head.S linux-2.4.19-pre5/arch/m68k/kernel/sun3-head.S --- linux-2.4.18/arch/m68k/kernel/sun3-head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/sun3-head.S Sat Mar 30 22:55:33 2002 @@ -15,9 +15,6 @@ .globl SYMBOL_NAME(bootup_user_stack) .globl SYMBOL_NAME(bootup_kernel_stack) .globl SYMBOL_NAME(pg0) -.globl SYMBOL_NAME(empty_bad_page) -.globl SYMBOL_NAME(empty_bad_page_table) -.globl SYMBOL_NAME(empty_zero_page) .globl SYMBOL_NAME(swapper_pg_dir) .globl SYMBOL_NAME(kernel_pmd_table) .globl SYMBOL_NAME(availmem) @@ -26,10 +23,7 @@ | todo: all these should be in bss! SYMBOL_NAME(swapper_pg_dir): .skip 0x2000 SYMBOL_NAME(pg0): .skip 0x2000 -SYMBOL_NAME(empty_bad_page): .skip 0x2000 -SYMBOL_NAME(empty_bad_page_table): .skip 0x2000 SYMBOL_NAME(kernel_pmd_table): .skip 0x2000 -SYMBOL_NAME(empty_zero_page): .skip 0x2000 .globl SYMBOL_NAME(kernel_pg_dir) .equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table) diff -urN linux-2.4.18/arch/m68k/kernel/traps.c linux-2.4.19-pre5/arch/m68k/kernel/traps.c --- linux-2.4.18/arch/m68k/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/kernel/traps.c Sat Mar 30 22:55:33 2002 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -224,7 +224,7 @@ unsigned long addr = fp->un.fmt4.effaddr; if (fslw & MMU060_MA) - addr = (addr + 7) & -8; + addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; errorcode = 1; if (fslw & MMU060_DESC_ERR) { @@ -258,16 +258,12 @@ set_fs(MAKE_MM_SEG(wbs)); - asm volatile (".chip 68040"); - if (iswrite) - asm volatile ("ptestw (%0)" : : "a" (addr)); + asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); else - asm volatile ("ptestr (%0)" : : "a" (addr)); + asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); - asm volatile ("movec %%mmusr,%0" : "=r" (mmusr)); - - asm volatile (".chip 68k"); + asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); set_fs(old_fs); @@ -816,15 +812,71 @@ int kstack_depth_to_print = 48; +extern struct module kernel_module; + +static inline int kernel_text_address(unsigned long addr) +{ + struct module *mod; + int retval = 0; + extern char _stext, _etext; + + if (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext) + return 1; + +#ifdef CONFIG_MODULES + for (mod = module_list; mod != &kernel_module; mod = mod->next) { + /* mod_bound tests for addr being inside the vmalloc'ed + * module area. Of course it'd be better to test only + * for the .text subset... */ + if (mod_bound(addr, 0, mod)) { + retval = 1; + break; + } + } +#endif + + return retval; +} + +void show_trace(unsigned long *stack) +{ + unsigned long *endstack; + unsigned long addr; + int i; + + printk("Call Trace:"); + addr = (unsigned long)stack + THREAD_SIZE - 1; + endstack = (unsigned long *)(addr & -THREAD_SIZE); + i = 0; + while (stack + 1 <= endstack) { + 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 (kernel_text_address(addr)) { + if (i % 4 == 0) + printk("\n "); + printk(" [<%08lx>]", addr); + i++; + } + } + printk("\n"); +} -/* MODULE_RANGE is a guess of how much space is likely to be - vmalloced. */ -#define MODULE_RANGE (8*1024*1024) +void show_trace_task(struct task_struct *tsk) +{ + show_trace((unsigned long *)tsk->thread.esp0); +} static void dump_stack(struct frame *fp) { - unsigned long *stack, *endstack, addr, module_start, module_end; - extern char _start, _etext; + unsigned long *stack, *endstack, addr; int i; addr = (unsigned long)&fp->un; @@ -881,7 +933,7 @@ } stack = (unsigned long *)addr; - endstack = (unsigned long *)PAGE_ALIGN(addr); + endstack = (unsigned long *)((addr + THREAD_SIZE - 1) & -THREAD_SIZE); printk("Stack from %08lx:", (unsigned long)stack); for (i = 0; i < kstack_depth_to_print; i++) { @@ -891,32 +943,10 @@ printk("\n "); printk(" %08lx", *stack++); } + printk("\n"); + show_trace((unsigned long *)addr); - printk ("\nCall Trace:"); - stack = (unsigned long *) addr; - i = 0; - module_start = VMALLOC_START; - module_end = module_start + MODULE_RANGE; - while (stack + 1 <= endstack) { - 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) &_start) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i % 4 == 0) - printk("\n "); - printk(" [<%08lx>]", addr); - i++; - } - } - printk("\nCode: "); + printk("Code: "); for (i = 0; i < 10; i++) printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); printk ("\n"); diff -urN linux-2.4.18/arch/m68k/math-emu/fp_emu.h linux-2.4.19-pre5/arch/m68k/math-emu/fp_emu.h --- linux-2.4.18/arch/m68k/math-emu/fp_emu.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/math-emu/fp_emu.h Sat Mar 30 22:55:33 2002 @@ -38,7 +38,9 @@ #ifndef _FP_EMU_H #define _FP_EMU_H +#ifdef __ASSEMBLY__ #include "../kernel/m68k_defs.h" +#endif #include #ifndef __ASSEMBLY__ diff -urN linux-2.4.18/arch/m68k/math-emu/multi_arith.h linux-2.4.19-pre5/arch/m68k/math-emu/multi_arith.h --- linux-2.4.18/arch/m68k/math-emu/multi_arith.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/math-emu/multi_arith.h Sat Mar 30 22:55:33 2002 @@ -376,7 +376,7 @@ asm ("divu.l %2,%1:%0" : "=d" (quot), "=d" (rem) \ : "dm" (div), "1" (srch), "0" (srcl)) #define fp_add64(dest1, dest2, src1, src2) ({ \ - asm ("add.l %1,%0" : "=d,=dm" (dest2) \ + asm ("add.l %1,%0" : "=d,dm" (dest2) \ : "dm,d" (src2), "0,0" (dest2)); \ asm ("addx.l %1,%0" : "=d" (dest1) \ : "d" (src1), "0" (dest1)); \ @@ -391,14 +391,14 @@ : "d" (0), "0" (dest->m32[0])); \ }) #define fp_sub64(dest, src) ({ \ - asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[1]) \ + asm ("sub.l %1,%0" : "=d,dm" (dest.m32[1]) \ : "dm,d" (src.m32[1]), "0,0" (dest.m32[1])); \ asm ("subx.l %1,%0" : "=d" (dest.m32[0]) \ : "d" (src.m32[0]), "0" (dest.m32[0])); \ }) #define fp_sub96c(dest, srch, srcm, srcl) ({ \ char carry; \ - asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[2]) \ + asm ("sub.l %1,%0" : "=d,dm" (dest.m32[2]) \ : "dm,d" (srcl), "0,0" (dest.m32[2])); \ asm ("subx.l %1,%0" : "=d" (dest.m32[1]) \ : "d" (srcm), "0" (dest.m32[1])); \ diff -urN linux-2.4.18/arch/m68k/mm/fault.c linux-2.4.19-pre5/arch/m68k/mm/fault.c --- linux-2.4.18/arch/m68k/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/mm/fault.c Sat Mar 30 22:55:33 2002 @@ -152,14 +152,24 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ + + survive: fault = handle_mm_fault(mm, vma, address, write); #ifdef DEBUG printk("handle_mm_fault returns %d\n",fault); #endif - if (fault < 0) - goto out_of_memory; - if (!fault) + switch (fault) { + case 1: + current->min_flt++; + break; + case 2: + current->maj_flt++; + break; + case 0: goto bus_err; + default: + goto out_of_memory; + } /* There seems to be a missing invalidate somewhere in do_no_page. * Until I found it, this one cures the problem and makes @@ -176,6 +186,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: + up_read(&mm->mmap_sem); + if (current->pid == 1) { + current->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); diff -urN linux-2.4.18/arch/m68k/mm/memory.c linux-2.4.19-pre5/arch/m68k/mm/memory.c --- linux-2.4.18/arch/m68k/mm/memory.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/mm/memory.c Sat Mar 30 22:55:33 2002 @@ -253,10 +253,6 @@ if (voff == 0) return m68k_memory[i-1].addr + m68k_memory[i-1].size; - /* As a special case allow `__pa(high_memory)'. */ - if (voff == 0) - return m68k_memory[i-1].addr + m68k_memory[i-1].size; - return mm_vtop_fallback(vaddr); } #endif diff -urN linux-2.4.18/arch/m68k/sun3/sun3dvma.c linux-2.4.19-pre5/arch/m68k/sun3/sun3dvma.c --- linux-2.4.18/arch/m68k/sun3/sun3dvma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/m68k/sun3/sun3dvma.c Sat Mar 30 22:55:33 2002 @@ -14,6 +14,8 @@ #include #include +#undef DVMA_DEBUG + #ifdef CONFIG_SUN3X extern void dvma_unmap_iommu(unsigned long baddr, int len); #else @@ -22,6 +24,10 @@ } #endif +#ifdef CONFIG_SUN3 +extern void sun3_dvma_init(void); +#endif + unsigned long iommu_use[IOMMU_TOTAL_ENTRIES]; #define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT) @@ -39,6 +45,60 @@ static struct list_head hole_cache; static struct hole initholes[64]; +#ifdef DVMA_DEBUG + +static unsigned long dvma_allocs = 0; +static unsigned long dvma_frees = 0; +static unsigned long long dvma_alloc_bytes = 0; +static unsigned long long dvma_free_bytes = 0; + +static void print_use(void) +{ + + int i; + int j = 0; + + printk("dvma entry usage:\n"); + + for(i = 0; i < IOMMU_TOTAL_ENTRIES; i++) { + if(!iommu_use[i]) + continue; + + j++; + + printk("dvma entry: %08lx len %08lx\n", + ( i << DVMA_PAGE_SHIFT) + DVMA_START, + iommu_use[i]); + } + + printk("%d entries in use total\n", j); + + printk("allocation/free calls: %lu/%lu\n", dvma_allocs, dvma_frees); + printk("allocation/free bytes: %Lx/%Lx\n", dvma_alloc_bytes, + dvma_free_bytes); +} + +static void print_holes(struct list_head *holes) +{ + + struct list_head *cur; + struct hole *hole; + + printk("listing dvma holes\n"); + list_for_each(cur, holes) { + hole = list_entry(cur, struct hole, list); + + if((hole->start == 0) && (hole->end == 0) && (hole->size == 0)) + continue; + + printk("hole: start %08lx end %08lx size %08lx\n", hole->start, hole->end, hole->size); + } + + printk("end of hole listing...\n"); + +} +#endif DVMA_DEBUG + static inline int refill(void) { @@ -93,7 +153,11 @@ struct hole *hole; if(list_empty(&hole_list)) { - printk("out of dvma holes!\n"); +#ifdef DVMA_DEBUG + printk("out of dvma holes! (printing hole cache)\n"); + print_holes(&hole_cache); + print_use(); +#endif BUG(); } @@ -111,11 +175,19 @@ hole->end -= newlen; hole->size -= newlen; dvma_entry_use(hole->end) = newlen; +#ifdef DVMA_DEBUG + dvma_allocs++; + dvma_alloc_bytes += newlen; +#endif return hole->end; } else if(hole->size == newlen) { list_del(&(hole->list)); list_add(&(hole->list), &hole_cache); dvma_entry_use(hole->start) = newlen; +#ifdef DVMA_DEBUG + dvma_allocs++; + dvma_alloc_bytes += newlen; +#endif return hole->start; } @@ -139,6 +211,11 @@ dvma_entry_use(baddr) = 0; baddr &= DVMA_PAGE_MASK; dvma_unmap_iommu(baddr, len); + +#ifdef DVMA_DEBUG + dvma_frees++; + dvma_free_bytes += len; +#endif list_for_each(cur, &hole_list) { hole = list_entry(cur, struct hole, list); diff -urN linux-2.4.18/arch/mips/Makefile linux-2.4.19-pre5/arch/mips/Makefile --- linux-2.4.18/arch/mips/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/Makefile Sat Mar 30 22:55:26 2002 @@ -50,6 +50,9 @@ ifdef CONFIG_CPU_R3000 GCCFLAGS += -mcpu=r3000 -mips1 endif +ifdef CONFIG_CPU_TX39XX +GCCFLAGS += -mcpu=r3000 -mips1 +endif ifdef CONFIG_CPU_R6000 GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap endif @@ -62,6 +65,9 @@ ifdef CONFIG_CPU_R4X00 GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap endif +ifdef CONFIG_CPU_TX49XX +GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap +endif ifdef CONFIG_CPU_MIPS32 GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap endif @@ -83,6 +89,9 @@ endif ifdef CONFIG_CPU_SB1 GCCFLAGS += -mcpu=sb1 -mips2 -Wa,--trap +ifdef CONFIG_SB1_PASS_1_WORKAROUNDS +MODFLAGS += -msb1-pass1-workarounds +endif endif GCCFLAGS += -pipe @@ -98,6 +107,16 @@ SUBDIRS +=arch/mips/math-emu # +# ramdisk/initrd support +# You need a compressed ramdisk image, named ramdisk.gz in +# arch/mips/ramdisk +# +ifdef CONFIG_EMBEDDED_RAMDISK +CORE_FILES += arch/mips/ramdisk/ramdisk.o +SUBDIRS += arch/mips/ramdisk +endif + +# # Board-dependent options and extra files # ifdef CONFIG_ALGOR_P4032 @@ -138,6 +157,12 @@ LOADADDR += 0x80080000 endif +ifdef CONFIG_MIPS_COBALT +SUBDIRS += arch/mips/cobalt +CORE_FILES += arch/mips/cobalt/cobalt.o +LOADADDR += 0x80080000 +endif + ifdef CONFIG_SNI_RM200_PCI CORE_FILES += arch/mips/sni/sni.o SUBDIRS += arch/mips/sni arch/mips/arc @@ -146,9 +171,9 @@ endif ifdef CONFIG_SGI_IP22 -CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o +CORE_FILES += arch/mips/sgi-ip22/ip22-kern.o LIBS += arch/mips/arc/arclib.a -SUBDIRS += arch/mips/sgi/kernel arch/mips/arc +SUBDIRS += arch/mips/sgi-ip22 arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, # 0x88002000 for production kernels. Note that the value must be @@ -180,8 +205,9 @@ # NEC DDB Vrc-5476 # ifdef CONFIG_DDB5476 -SUBDIRS += arch/mips/ddb5476 -LIBS += arch/mips/ddb5476/ddb5476.a +SUBDIRS += arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5476 +LIBS += arch/mips/ddb5xxx/common/ddb5xxx.o \ + arch/mips/ddb5xxx/ddb5476/ddb5476.o LOADADDR += 0x80080000 endif @@ -197,6 +223,16 @@ endif # +# NEC Osprey (vr4181) board +# +ifdef CONFIG_NEC_OSPREY +SUBDIRS += arch/mips/vr4181/common arch/mips/vr4181/osprey +LIBS += arch/mips/vr4181/common/vr4181.o \ + arch/mips/vr4181/osprey/osprey.o +LOADADDR += 0x80002000 +endif + +# # Galileo EV64120 Board # ifdef CONFIG_MIPS_EV64120 @@ -256,10 +292,58 @@ # Au1000 eval board # ifdef CONFIG_MIPS_PB1000 -LIBS += arch/mips/au1000/pb1000/pb1000.o arch/mips/au1000/common/au1000.o +LIBS += arch/mips/au1000/pb1000/pb1000.o \ + arch/mips/au1000/common/au1000.o SUBDIRS += arch/mips/au1000/pb1000 arch/mips/au1000/common LOADADDR += 0x80100000 endif + +ifdef CONFIG_MIPS_PB1500 +LIBS += arch/mips/au1000/pb1500/pb1500.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/pb1500 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +# +# Sibyte SB1250 SOC +# +ifdef CONFIG_SIBYTE_SB1250 +# This is a LIB so that it links at the end, and initcalls are later +# the sequence; but it is built as an object so that modules don't get +# removed (as happens, even if they have __initcall/module_init) +LIBS += arch/mips/sibyte/sb1250/sb1250.o +SUBDIRS += arch/mips/sibyte/sb1250 +endif + +# +# Sibyte SWARM board +# +ifdef CONFIG_SB1_CACHE_ERROR +LIBS += arch/mips/sibyte/sb1/sb1kern.a +SUBDIRS += arch/mips/sibyte/sb1 +endif + +ifdef CONFIG_SIBYTE_SWARM +LIBS += arch/mips/sibyte/swarm/sbswarm.a +SUBDIRS += arch/mips/sibyte/swarm +LOADADDR += 0x80100000 +endif + +# +# HP LaserJet +# +ifdef CONFIG_HP_LASERJET +SUBDIRS += arch/mips/hp-lj +LIBS += arch/mips/hp-lj/hp-lj.o +LOADADDR := 0x80030000 +endif + +ifdef CONFIG_TOSHIBA_JMR3927 +CORE_FILES += arch/mips/jmr3927/rbhma3100/jmr3927.o arch/mips/jmr3927/common/tx3927.o +SUBDIRS += arch/mips/jmr3927/rbhma3100 arch/mips/jmr3927/common +LOADADDR += 0x80050000 +endif # # Choosing incompatible machines durings configuration will result in diff -urN linux-2.4.18/arch/mips/arc/cmdline.c linux-2.4.19-pre5/arch/mips/arc/cmdline.c --- linux-2.4.18/arch/mips/arc/cmdline.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/cmdline.c Sat Mar 30 22:55:26 2002 @@ -12,7 +12,7 @@ #undef DEBUG_CMDLINE -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; char * __init prom_getcmdline(void) { diff -urN linux-2.4.18/arch/mips/arc/console.c linux-2.4.19-pre5/arch/mips/arc/console.c --- linux-2.4.18/arch/mips/arc/console.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/console.c Sat Mar 30 22:55:26 2002 @@ -31,7 +31,7 @@ char it = c; bc_disable(); - romvec->write(1, &it, 1, &cnt); + ArcWrite(1, &it, 1, &cnt); bc_enable(); } @@ -41,7 +41,7 @@ char c; bc_disable(); - romvec->read(0, &c, 1, &cnt); + ArcRead(0, &c, 1, &cnt); bc_enable(); return c; diff -urN linux-2.4.18/arch/mips/arc/env.c linux-2.4.19-pre5/arch/mips/arc/env.c --- linux-2.4.18/arch/mips/arc/env.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/env.c Sat Mar 30 22:55:26 2002 @@ -1,24 +1,27 @@ /* + * 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. + * * env.c: ARCS environment variable routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: env.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include #include +#include #include PCHAR __init ArcGetEnvironmentVariable(CHAR *name) { - return romvec->get_evar(name); + return (CHAR *) ARC_CALL1(get_evar, name); } LONG __init ArcSetEnvironmentVariable(PCHAR name, PCHAR value) { - return romvec->set_evar(name, value); + return ARC_CALL2(set_evar, name, value); } diff -urN linux-2.4.18/arch/mips/arc/file.c linux-2.4.19-pre5/arch/mips/arc/file.c --- linux-2.4.18/arch/mips/arc/file.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/file.c Sat Mar 30 22:55:26 2002 @@ -1,59 +1,75 @@ /* - * file.c: ARCS firmware interface to files. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * ARC firmware interface. * - * $Id: file.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include + +#include #include -long __init prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt) +LONG __init +ArcGetDirectoryEntry(ULONG FileID, struct linux_vdirent *Buffer, + ULONG N, ULONG *Count) { - return romvec->get_vdirent(fd, ent, num, cnt); + return ARC_CALL4(get_vdirent, FileID, Buffer, N, Count); } -long __init prom_open(char *name, enum linux_omode md, unsigned long *fd) +LONG __init +ArcOpen(CHAR *Path, enum linux_omode OpenMode, ULONG *FileID) { - return romvec->open(name, md, fd); + return ARC_CALL3(open, Path, OpenMode, FileID); } -long __init prom_close(unsigned long fd) +LONG __init +ArcClose(ULONG FileID) { - return romvec->close(fd); + return ARC_CALL1(close, FileID); } -long __init prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt) +LONG __init +ArcRead(ULONG FileID, VOID *Buffer, ULONG N, ULONG *Count) { - return romvec->read(fd, buf, num, cnt); + return ARC_CALL4(read, FileID, Buffer, N, Count); } -long __init prom_getrstatus(unsigned long fd) +LONG __init +ArcGetReadStatus(ULONG FileID) { - return romvec->get_rstatus(fd); + return ARC_CALL1(get_rstatus, FileID); } -long __init prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt) +LONG __init +ArcWrite(ULONG FileID, PVOID Buffer, ULONG N, PULONG Count) { - return romvec->write(fd, buf, num, cnt); + return ARC_CALL4(write, FileID, Buffer, N, Count); } -long __init prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm) +LONG __init +ArcSeek(ULONG FileID, struct linux_bigint *Position, enum linux_seekmode SeekMode) { - return romvec->seek(fd, off, sm); + return ARC_CALL3(seek, FileID, Position, SeekMode); } -long __init prom_mount(char *name, enum linux_mountops op) +LONG __init +ArcMount(char *name, enum linux_mountops op) { - return romvec->mount(name, op); + return ARC_CALL2(mount, name, op); } -long __init prom_getfinfo(unsigned long fd, struct linux_finfo *buf) +LONG __init +ArcGetFileInformation(ULONG FileID, struct linux_finfo *Information) { - return romvec->get_finfo(fd, buf); + return ARC_CALL2(get_finfo, FileID, Information); } -long __init prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk) +LONG __init ArcSetFileInformation(ULONG FileID, ULONG AttributeFlags, + ULONG AttributeMask) { - return romvec->set_finfo(fd, flags, msk); + return ARC_CALL3(set_finfo, FileID, AttributeFlags, AttributeMask); } diff -urN linux-2.4.18/arch/mips/arc/identify.c linux-2.4.19-pre5/arch/mips/arc/identify.c --- linux-2.4.18/arch/mips/arc/identify.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/identify.c Sat Mar 30 22:55:26 2002 @@ -17,49 +17,81 @@ #include struct smatch { - char *name; + char *arcname; + char *liname; int group; int type; int flags; }; static struct smatch mach_table[] = { - {"SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS}, - {"Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0}, - {"PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0}, - {"RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0} + { "SGI-IP22", + "SGI Indy", + MACH_GROUP_SGI, + MACH_SGI_INDY, + PROM_FLAG_ARCS + }, { "Microsoft-Jazz", + "Jazz MIPS_Magnum_4000", + MACH_GROUP_JAZZ, + MACH_MIPS_MAGNUM_4000, + 0 + }, { "PICA-61", + "Jazz Acer_PICA_61", + MACH_GROUP_JAZZ, + MACH_ACER_PICA_61, + 0 + }, { "RM200PCI", + "SNI RM200_PCI", + MACH_GROUP_SNI_RM, + MACH_SNI_RM200_PCI, + 0 + } }; int prom_flags; -static struct smatch *__init string_to_mach(char *s) +static struct smatch *__init string_to_mach(const char *s) { int i; for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) { - if (!strcmp(s, mach_table[i].name)) + if (!strcmp(s, mach_table[i].arcname)) return &mach_table[i]; } - prom_printf("\nYeee, could not determine architecture type <%s>\n", - s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - return NULL; + + panic("Yeee, could not determine architecture type <%s>", s); +} + +char *system_type; + +const char *get_system_type(void) +{ + return system_type; } void __init prom_identify_arch(void) { pcomponent *p; struct smatch *mach; + const char *iname; /* * The root component tells us what machine architecture we * have here. */ - p = prom_getchild(PROM_NULL_COMPONENT); - printk("ARCH: %s\n", p->iname); - mach = string_to_mach(p->iname); + p = ArcGetChild(PROM_NULL_COMPONENT); + if (p == NULL) { +#ifdef CONFIG_SGI_IP27 + /* IP27 PROM bisbehaves, seems to not implement ARC + GetChild(). So we just assume it's an IP27. */ + iname = "SGI-IP27"; +#endif + } else + iname = (char *) (long) p->iname; + + printk("ARCH: %s\n", iname); + mach = string_to_mach(iname); + system_type = mach->liname; mips_machgroup = mach->group; mips_machtype = mach->type; diff -urN linux-2.4.18/arch/mips/arc/init.c linux-2.4.19-pre5/arch/mips/arc/init.c --- linux-2.4.18/arch/mips/arc/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/init.c Sat Mar 30 22:55:26 2002 @@ -16,18 +16,16 @@ /* Master romvec interface. */ struct linux_romvec *romvec; -struct linux_promblock *sgi_pblock; +PSYSTEM_PARAMETER_BLOCK sgi_pblock; int prom_argc; char **prom_argv, **prom_envp; unsigned short prom_vers, prom_rev; extern void prom_testtree(void); -extern void arc_setup_console(void); - void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { - struct linux_promblock *pb; + PSYSTEM_PARAMETER_BLOCK pb; romvec = ROMVECTOR; pb = sgi_pblock = PROMBLOCK; @@ -35,19 +33,6 @@ prom_argv = argv; prom_envp = envp; -#if 0 - /* arc_printf should not use prom_printf as soon as we free - * the prom buffers - This horribly breaks on Indys with framebuffer - * as it simply stops after initialising swap - On the Indigo2 serial - * console you will get A LOT illegal instructions - Only enable - * this for early init crashes - This also brings up artefacts of - * printing everything twice on serial console and on GFX Console - * this has the effect of having the prom printing everything - * in the small rectangle and the kernel printing around. - */ - - arc_setup_console(); -#endif if (pb->magic != 0x53435241) { prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); while(1) diff -urN linux-2.4.18/arch/mips/arc/memory.c linux-2.4.19-pre5/arch/mips/arc/memory.c --- linux-2.4.18/arch/mips/arc/memory.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/memory.c Sat Mar 30 22:55:26 2002 @@ -22,7 +22,7 @@ struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) { - return romvec->get_mdesc(Current); + return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); } #ifdef DEBUG /* convenient for debugging */ diff -urN linux-2.4.18/arch/mips/arc/misc.c linux-2.4.19-pre5/arch/mips/arc/misc.c --- linux-2.4.18/arch/mips/arc/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/misc.c Sat Mar 30 22:55:26 2002 @@ -1,13 +1,21 @@ /* - * misc.c: Miscellaneous ARCS PROM routines. + * 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. + * + * Miscellaneous ARCS PROM routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include #include #include #include + +#include #include #include #include @@ -15,68 +23,81 @@ extern void *sgiwd93_host; extern void reset_wd33c93(void *instance); -void prom_halt(void) +VOID +ArcHalt(VOID) { bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif - romvec->halt(); + ARC_CALL0(halt); +never: goto never; } -void prom_powerdown(void) +VOID +ArcPowerDown(VOID) { bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif - romvec->pdown(); + ARC_CALL0(pdown); +never: goto never; } /* XXX is this a soft reset basically? XXX */ -void prom_restart(void) +VOID +ArcRestart(VOID) { bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif - romvec->restart(); + ARC_CALL0(restart); +never: goto never; } -void prom_reboot(void) +VOID +ArcReboot(VOID) { bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif - romvec->reboot(); + ARC_CALL0(reboot); +never: goto never; } -void ArcEnterInteractiveMode(void) +VOID +ArcEnterInteractiveMode(VOID) { bc_disable(); cli(); #if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif - romvec->imode(); + ARC_CALL0(imode); +never: goto never; } -long prom_cfgsave(void) +LONG +ArcSaveConfiguration(VOID) { - return romvec->cfg_save(); + return ARC_CALL0(cfg_save); } -struct linux_sysid *prom_getsysid(void) +struct linux_sysid * +ArcGetSystemId(VOID) { - return romvec->get_sysid(); + return (struct linux_sysid *) ARC_CALL0(get_sysid); } -void __init prom_cacheflush(void) +VOID __init +ArcFlushAllCaches(VOID) { - romvec->cache_flush(); + ARC_CALL0(cache_flush); } diff -urN linux-2.4.18/arch/mips/arc/salone.c linux-2.4.19-pre5/arch/mips/arc/salone.c --- linux-2.4.18/arch/mips/arc/salone.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/salone.c Sat Mar 30 22:55:26 2002 @@ -3,8 +3,6 @@ * program images using ARCS PROM firmware. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: salone.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ */ #include #include diff -urN linux-2.4.18/arch/mips/arc/time.c linux-2.4.19-pre5/arch/mips/arc/time.c --- linux-2.4.18/arch/mips/arc/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/time.c Sat Mar 30 22:55:26 2002 @@ -1,19 +1,25 @@ /* - * time.c: Extracting time information from ARCS prom. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Extracting time information from ARCS prom. * - * $Id: time.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include + +#include #include -struct linux_tinfo * __init prom_gettinfo(void) +struct linux_tinfo * __init +ArcGetTime(VOID) { - return romvec->get_tinfo(); + return (struct linux_tinfo *) ARC_CALL0(get_tinfo); } -unsigned long __init prom_getrtime(void) +ULONG __init +ArcGetRelativeTime(VOID) { - return romvec->get_rtime(); + return ARC_CALL0(get_rtime); } diff -urN linux-2.4.18/arch/mips/arc/tree.c linux-2.4.19-pre5/arch/mips/arc/tree.c --- linux-2.4.18/arch/mips/arc/tree.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/arc/tree.c Sat Mar 30 22:55:26 2002 @@ -1,72 +1,88 @@ /* - * tree.c: PROM component device tree code. + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * PROM component device tree code. * - * $Id: tree.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include +#include #include -#define DEBUG_PROM_TREE +#undef DEBUG_PROM_TREE -pcomponent * __init prom_getsibling(pcomponent *this) +pcomponent * __init +ArcGetPeer(pcomponent *Current) { - if(this == PROM_NULL_COMPONENT) + if (Current == PROM_NULL_COMPONENT) return PROM_NULL_COMPONENT; - return romvec->next_component(this); + + return (pcomponent *) ARC_CALL1(next_component, Current); } -pcomponent * __init prom_getchild(pcomponent *this) +pcomponent * __init +ArcGetChild(pcomponent *Current) { - return romvec->child_component(this); + return (pcomponent *) ARC_CALL1(child_component, Current); } -pcomponent * __init prom_getparent(pcomponent *child) +pcomponent * __init +ArcGetParent(pcomponent *Current) { - if(child == PROM_NULL_COMPONENT) + if (Current == PROM_NULL_COMPONENT) return PROM_NULL_COMPONENT; - return romvec->parent_component(child); + + return (pcomponent *) ARC_CALL1(parent_component, Current); } -long __init prom_getcdata(void *buffer, pcomponent *this) +LONG __init +ArcGetConfigurationData(VOID *Buffer, pcomponent *Current) { - return romvec->component_data(buffer, this); + return ARC_CALL2(component_data, Buffer, Current); } -pcomponent * __init prom_childadd(pcomponent *this, pcomponent *tmp, void *data) +pcomponent * __init +ArcAddChild(pcomponent *Current, pcomponent *Template, VOID *ConfigurationData) { - return romvec->child_add(this, tmp, data); + return (pcomponent *) + ARC_CALL3(child_add, Current, Template, ConfigurationData); } -long __init prom_delcomponent(pcomponent *this) +LONG __init +ArcDeleteComponent(pcomponent *ComponentToDelete) { - return romvec->comp_del(this); + return ARC_CALL1(comp_del, ComponentToDelete); } -pcomponent * __init prom_componentbypath(char *path) +pcomponent * __init +ArcGetComponent(CHAR *Path) { - return romvec->component_by_path(path); + return (pcomponent *)ARC_CALL1(component_by_path, Path); } #ifdef DEBUG_PROM_TREE + static char *classes[] = { "system", "processor", "cache", "adapter", "controller", "peripheral", "memory" }; static char *types[] = { - "arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", "sccache", - "memdev", "eisa adapter", "tc adapter", "scsi adapter", "dti adapter", - "multi-func adapter", "disk controller", "tp controller", - "cdrom controller", "worm controller", "serial controller", - "net controller", "display controller", "parallel controller", - "pointer controller", "keyboard controller", "audio controller", - "misc controller", "disk peripheral", "floppy peripheral", - "tp peripheral", "modem peripheral", "monitor peripheral", - "printer peripheral", "pointer peripheral", "keyboard peripheral", - "terminal peripheral", "line peripheral", "net peripheral", - "misc peripheral", "anonymous" + "arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", + "sccache", "memdev", "eisa adapter", "tc adapter", "scsi adapter", + "dti adapter", "multi-func adapter", "disk controller", + "tp controller", "cdrom controller", "worm controller", + "serial controller", "net controller", "display controller", + "parallel controller", "pointer controller", "keyboard controller", + "audio controller", "misc controller", "disk peripheral", + "floppy peripheral", "tp peripheral", "modem peripheral", + "monitor peripheral", "printer peripheral", "pointer peripheral", + "keyboard peripheral", "terminal peripheral", "line peripheral", + "net peripheral", "misc peripheral", "anonymous" }; static char *iflags[] = { @@ -74,7 +90,8 @@ "input", "output" }; -static void __init dump_component(pcomponent *p) +static void __init +dump_component(pcomponent *p) { prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>", p, classes[p->class], types[p->type], @@ -83,27 +100,28 @@ p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); } -static void __init traverse(pcomponent *p, int op) +static void __init +traverse(pcomponent *p, int op) { dump_component(p); - if(prom_getchild(p)) - traverse(prom_getchild(p), 1); - if(prom_getsibling(p) && op) - traverse(prom_getsibling(p), 1); + if(ArcGetChild(p)) + traverse(ArcGetChild(p), 1); + if(ArcGetPeer(p) && op) + traverse(ArcGetPeer(p), 1); } -void __init prom_testtree(void) +void __init +prom_testtree(void) { pcomponent *p; - p = prom_getchild(PROM_NULL_COMPONENT); + p = ArcGetChild(PROM_NULL_COMPONENT); dump_component(p); - p = prom_getchild(p); + p = ArcGetChild(p); while(p) { dump_component(p); - p = prom_getsibling(p); + p = ArcGetPeer(p); } - prom_printf("press a key\n"); - prom_getchar(); } -#endif + +#endif /* DEBUG_PROM_TREE */ diff -urN linux-2.4.18/arch/mips/au1000/common/Makefile linux-2.4.19-pre5/arch/mips/au1000/common/Makefile --- linux-2.4.18/arch/mips/au1000/common/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/Makefile Sat Mar 30 22:55:26 2002 @@ -19,13 +19,13 @@ O_TARGET := au1000.o -obj-y := prom.o dbg_io.o int-handler.o irq.o puts.o time.o reset.o +export-objs = prom.o serial.o clocks.o + +obj-y := prom.o int-handler.o dma.o irq.o puts.o time.o reset.o power.o clocks.o obj-$(CONFIG_AU1000_UART) += serial.o +obj-$(CONFIG_AU1000_USB_DEVICE) += usbdev.o obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o -obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o - -ramdisk.o: - mkramobj ramdisk ramdisk.o +obj-$(CONFIG_RTC) += rtc.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/au1000/common/clocks.c linux-2.4.19-pre5/arch/mips/au1000/common/clocks.c --- linux-2.4.18/arch/mips/au1000/common/clocks.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/common/clocks.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,98 @@ +/* + * BRIEF MODULE DESCRIPTION + * Simple Au1000 clocks routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +static unsigned int au1000_clock; // Hz +static unsigned int lcd_clock; // KHz +static unsigned long uart_baud_base; + +/* + * Set the au1000_clock + */ +void set_au1000_speed(unsigned int new_freq) +{ + au1000_clock = new_freq; +} + +unsigned int get_au1000_speed(void) +{ + return au1000_clock; +} + + + +/* + * The UART baud base is not known at compile time ... if + * we want to be able to use the same code on different + * speed CPUs. + */ +unsigned long get_au1000_uart_baud_base(void) +{ + return uart_baud_base; +} + +void set_au1000_uart_baud_base(unsigned long new_baud_base) +{ + uart_baud_base = new_baud_base; +} + +/* + * Calculate the Au1000's LCD clock based on the current + * cpu clock and the system bus clock, and try to keep it + * below 40 MHz (the Pb1000 board can lock-up if the LCD + * clock is over 40 MHz). + */ +void set_au1000_lcd_clock(void) +{ + unsigned int static_cfg0; + unsigned int sys_busclk = + (get_au1000_speed()/1000) / + ((int)(inl(SYS_POWERCTRL)&0x03) + 2); + + static_cfg0 = inl(MEM_STCFG0); + + if (static_cfg0 & (1<<11)) + lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */ + else + lcd_clock = sys_busclk / 4; + + if (lcd_clock > 50000) /* Epson MAX */ + printk(__FUNCTION__ + ": warning: LCD clock too high (%d KHz)\n", + lcd_clock); +} + +unsigned int get_au1000_lcd_clock(void) +{ + return lcd_clock; +} + +EXPORT_SYMBOL(get_au1000_lcd_clock); diff -urN linux-2.4.18/arch/mips/au1000/common/dbg_io.c linux-2.4.19-pre5/arch/mips/au1000/common/dbg_io.c --- linux-2.4.18/arch/mips/au1000/common/dbg_io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/dbg_io.c Sat Mar 30 22:55:26 2002 @@ -53,8 +53,11 @@ #define UART_MOD_CNTRL 0x100 /* Module Control */ /* memory-mapped read/write of the port */ -#define UART16550_READ(y) (inl(DEBUG_BASE + y) & 0xff) -#define UART16550_WRITE(y,z) (outl(z&0xff, DEBUG_BASE + y)) +#define UART16550_READ(y) (readl(DEBUG_BASE + y) & 0xff) +#define UART16550_WRITE(y,z) (writel(z&0xff, DEBUG_BASE + y)) + +extern unsigned long get_au1000_uart_baud_base(void); +extern unsigned long cal_r4koff(void); void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) { @@ -72,12 +75,12 @@ uint32 divisor; /* set divisor */ - divisor = get_au1000_uart_baud() / baud; + divisor = get_au1000_uart_baud_base() / baud; UART16550_WRITE(UART_CLK, divisor & 0xffff); } /* set data format */ - UART16550_WRITE(UART_LCR, data | parity | stop); + UART16550_WRITE(UART_LCR, (data | parity | stop)); } static int remoteDebugInitialized = 0; @@ -99,7 +102,8 @@ int putDebugChar(uint8 byte) { - int i; +// int i; + if (!remoteDebugInitialized) { remoteDebugInitialized = 1; debugInit(UART16550_BAUD_115200, diff -urN linux-2.4.18/arch/mips/au1000/common/dma.c linux-2.4.19-pre5/arch/mips/au1000/common/dma.c --- linux-2.4.18/arch/mips/au1000/common/dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/common/dma.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,195 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * A DMA channel allocator for Au1000. API is modeled loosely off of + * linux/kernel/dma.c. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* + * A note on resource allocation: + * + * All drivers needing DMA channels, should allocate and release them + * through the public routines `request_dma()' and `free_dma()'. + * + * In order to avoid problems, all processes should allocate resources in + * the same sequence and release them in the reverse order. + * + * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. + * When releasing them, first release the IRQ, then release the DMA. The + * main reason for this order is that, if you are requesting the DMA buffer + * done interrupt, you won't know the irq number until the DMA channel is + * returned from request_dma. + */ + + +spinlock_t au1000_dma_spin_lock = SPIN_LOCK_UNLOCKED; + +struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = { + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,} +}; + +// Device FIFO addresses and default DMA modes +static const struct { + unsigned int fifo_addr; + unsigned int dma_mode; +} dma_dev_table[DMA_NUM_DEV] = { + { + UART0_ADDR + UART_TX, 0}, { + UART0_ADDR + UART_RX, 0}, { + 0, 0}, { + 0, 0}, { + AC97C_DATA, DMA_DW16 | DMA_NC}, { + AC97C_DATA, DMA_DR | DMA_DW16 | DMA_NC}, { + UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, { + UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, { + USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, { + USBD_EP0WR, DMA_DW8 | DMA_NC}, { + USBD_EP2WR, DMA_DW8 | DMA_NC}, { + USBD_EP3WR, DMA_DW8 | DMA_NC}, { + USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, { + USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, { + I2S_DATA, DMA_DW32 | DMA_NC}, { + I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC} +}; + + +int au1000_dma_read_proc(char *buf, char **start, off_t fpos, + int length, int *eof, void *data) +{ + int i, len = 0; + struct dma_chan *chan; + + for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) { + if ((chan = get_dma_chan(i)) != NULL) { + len += + sprintf(buf + len, "%2d: %s\n", i, + chan->dev_str); + } + } + + if (fpos >= len) { + *start = buf; + *eof = 1; + return 0; + } + *start = buf + fpos; + if ((len -= fpos) > length) + return length; + *eof = 1; + return len; +} + + +void dump_au1000_dma_channel(unsigned int dmanr) +{ + struct dma_chan *chan; + + if (dmanr > NUM_AU1000_DMA_CHANNELS) + return; + chan = &au1000_dma_table[dmanr]; + + printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr); + printk(KERN_INFO " mode = 0x%08x\n", + inl(chan->io + DMA_MODE_SET)); + printk(KERN_INFO " addr = 0x%08x\n", + inl(chan->io + DMA_PERIPHERAL_ADDR)); + printk(KERN_INFO " start0 = 0x%08x\n", + inl(chan->io + DMA_BUFFER0_START)); + printk(KERN_INFO " start1 = 0x%08x\n", + inl(chan->io + DMA_BUFFER1_START)); + printk(KERN_INFO " count0 = 0x%08x\n", + inl(chan->io + DMA_BUFFER0_COUNT)); + printk(KERN_INFO " count1 = 0x%08x\n", + inl(chan->io + DMA_BUFFER1_COUNT)); +} + + +/* + * Finds a free channel, and binds the requested device to it. + * Returns the allocated channel number, or negative on error. + */ +int request_au1000_dma(int dev_id, const char *dev_str) +{ + struct dma_chan *chan; + int i; + + if (dev_id < 0 || dev_id >= DMA_NUM_DEV) + return -EINVAL; + + for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) { + if (au1000_dma_table[i].dev_id < 0) + break; + } + if (i == NUM_AU1000_DMA_CHANNELS) + return -ENODEV; + + chan = &au1000_dma_table[i]; + + // fill it in + chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; + chan->irq = AU1000_DMA_INT_BASE + i; + chan->dev_id = dev_id; + chan->dev_str = dev_str; + chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; + chan->mode = dma_dev_table[dev_id].dma_mode; + + return i; +} + + +void free_au1000_dma(unsigned int dmanr) +{ + struct dma_chan *chan = get_dma_chan(dmanr); + if (!chan) { + printk("Trying to free DMA%d\n", dmanr); + return; + } + + disable_dma(dmanr); + + chan->dev_id = -1; +} /* free_dma */ diff -urN linux-2.4.18/arch/mips/au1000/common/int-handler.S linux-2.4.19-pre5/arch/mips/au1000/common/int-handler.S --- linux-2.4.18/arch/mips/au1000/common/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/int-handler.S Sat Mar 30 22:55:26 2002 @@ -65,7 +65,5 @@ 5: move a0, sp - jal mips_spurious_interrupt -done: - j ret_from_irq + j spurious_interrupt END(au1000_IRQ) diff -urN linux-2.4.18/arch/mips/au1000/common/irq.c linux-2.4.19-pre5/arch/mips/au1000/common/irq.c --- linux-2.4.18/arch/mips/au1000/common/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/irq.c Sat Mar 30 22:55:26 2002 @@ -47,7 +47,13 @@ #include #include -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +#if defined(CONFIG_MIPS_PB1000) +#include +#elif defined(CONFIG_MIPS_PB1500) +#include +#else +#error unsupported alchemy board +#endif #undef DEBUG_IRQ #ifdef DEBUG_IRQ @@ -68,11 +74,8 @@ #endif extern asmlinkage void au1000_IRQ(void); - extern void set_debug_traps(void); -extern irq_cpustat_t irq_stat []; -extern irq_desc_t irq_desc[NR_IRQS]; - +extern irq_cpustat_t irq_stat [NR_CPUS]; unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; @@ -82,147 +85,106 @@ static inline void mask_and_ack_level_irq(unsigned int irq_nr); static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr); static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr); -static inline void local_enable_irq(unsigned int irq_nr); -static inline void local_disable_irq(unsigned int irq_nr); +inline void local_enable_irq(unsigned int irq_nr); +inline void local_disable_irq(unsigned int irq_nr); -unsigned long spurious_interrupts; extern unsigned int do_IRQ(int irq, struct pt_regs *regs); extern void __init init_generic_irq(void); -static inline void sync(void) -{ - __asm volatile ("sync"); -} - - -/* Function for careful CP0 interrupt mask access */ -static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) -{ - unsigned long status = read_32bit_cp0_register(CP0_STATUS); - status &= ~((clr_mask & 0xFF) << 8); - status |= (set_mask & 0xFF) << 8; - write_32bit_cp0_register(CP0_STATUS, status); -} - - -static inline void mask_cpu_irq_input(unsigned int irq_nr) -{ - modify_cp0_intmask(irq_nr, 0); -} - - -static inline void unmask_cpu_irq_input(unsigned int irq_nr) -{ - modify_cp0_intmask(0, irq_nr); -} - - -static void disable_cpu_irq_input(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - mask_cpu_irq_input(irq_nr); - restore_flags(flags); -} - - -static void enable_cpu_irq_input(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - unmask_cpu_irq_input(irq_nr); - restore_flags(flags); -} +#ifdef CONFIG_PM +extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs); +#endif static void setup_local_irq(unsigned int irq_nr, int type, int int_req) { + if (irq_nr > AU1000_MAX_INTR) return; /* Config2[n], Config1[n], Config0[n] */ if (irq_nr > AU1000_LAST_INTC0_INT) { switch (type) { case INTC_INT_RISE_EDGE: /* 0:0:1 */ - outl(1< AU1000_LAST_INTC0_INT) { - outl(1< AU1000_LAST_INTC0_INT) { - outl(1< AU1000_LAST_INTC0_INT) { - outl(1< AU1000_LAST_INTC0_INT) { - outl(1<>= 1; } } @@ -417,55 +512,86 @@ void intc0_req1_irqdispatch(struct pt_regs *regs) { int irq = 0, i; - unsigned long int_request; + static unsigned long intc0_req1 = 0; - int_request = inl(INTC0_REQ1_INT); + intc0_req1 = inl(IC0_REQ1INT); - if (!int_request) return; + if (!intc0_req1) return; for (i=0; i<32; i++) { - if ((int_request & 0x1)) { - do_IRQ(irq, regs); + if ((intc0_req1 & (1<>= 1; } } +/* + * Interrupt Controller 1: + * interrupts 32 - 63 + */ void intc1_req0_irqdispatch(struct pt_regs *regs) { int irq = 0, i; - unsigned long int_request; + static unsigned long intc1_req0 = 0; + volatile unsigned short levels, mdr; + unsigned char ide_status; - int_request = inl(INTC1_REQ0_INT); + intc1_req0 |= inl(IC1_REQ0INT); - if (!int_request) return; + if (!intc1_req0) return; +#ifdef CONFIG_MIPS_PB1000 + writew(1, CPLD_AUX0); /* debug led 0 */ +#endif for (i=0; i<32; i++) { - if ((int_request & 0x1)) { - do_IRQ(irq, regs); + if ((intc1_req0 & (1<>= 1; } +#ifdef CONFIG_MIPS_PB1000 + writew(0, CPLD_AUX0); +#endif } void intc1_req1_irqdispatch(struct pt_regs *regs) { int irq = 0, i; - unsigned long int_request; + static unsigned long intc1_req1 = 0; - int_request = inl(INTC1_REQ1_INT); + intc1_req1 |= inl(IC1_REQ1INT); - if (!int_request) return; + if (!intc1_req1) return; for (i=0; i<32; i++) { - if ((int_request & 0x1)) { - do_IRQ(irq, regs); + if ((intc1_req1 & (1<>= 1; } } diff -urN linux-2.4.18/arch/mips/au1000/common/power.c linux-2.4.19-pre5/arch/mips/au1000/common/power.c --- linux-2.4.18/arch/mips/au1000/common/power.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/common/power.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,341 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1000 Power Management routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Some of the routines are right out of init/main.c, whose + * copyrights apply here. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG 1 +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +inline void au1_wait(void); +static void calibrate_delay(void); + +extern void set_au1000_speed(unsigned int new_freq); +extern unsigned int get_au1000_speed(void); +extern unsigned long get_au1000_uart_baud_base(void); +extern void set_au1000_uart_baud_base(unsigned long new_baud_base); +extern unsigned long save_local_and_disable(int controller); +extern void restore_local_and_enable(int controller, unsigned long mask); +extern void local_enable_irq(unsigned int irq_nr); + +/* Quick acpi hack. This will have to change! */ +#define CTL_ACPI 9999 +#define ACPI_S1_SLP_TYP 19 +#define ACPI_SLEEP 21 + +#ifdef CONFIG_PM + +unsigned long suspend_mode; + +void wakeup_from_suspend(void) +{ + suspend_mode = 0; +} + +int au_sleep(void) +{ + unsigned long wakeup, flags; + save_and_cli(flags); + + flush_cache_all(); + /* pin 6 is gpio */ + writel(readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); + + /* gpio 6 can cause a wake up event */ + wakeup = readl(SYS_WAKEMSK); + wakeup &= ~(1 << 8); /* turn off match20 wakeup */ + wakeup |= 1 << 6; /* turn on gpio 6 wakeup */ + writel(wakeup, SYS_WAKEMSK); + + writel(1, SYS_WAKESRC); /* clear cause */ + writel(1, SYS_SLPPWR); /* prepare to sleep */ + + __asm__("la $4, 1f\n\t" + "lui $5, 0xb190\n\t" + "ori $5, 0x18\n\t" + "sw $4, 0($5)\n\t" + "li $4, 1\n\t" + "lui $5, 0xb190\n\t" + "ori $5, 0x7c\n\t" + "sw $4, 0($5)\n\t" "sync\n\t" "1:\t\n\t" "nop\n\t"); + + /* after a wakeup, the cpu vectors back to 0x1fc00000 so + * it's up to the boot code to get us back here. + */ + restore_flags(flags); + return 0; +} + +static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0; + + if (!write) { + *len = 0; + } else { + retval = pm_send_all(PM_SUSPEND, (void *) 2); + if (retval) + return retval; + + au_sleep(); + retval = pm_send_all(PM_RESUME, (void *) 0); + } + return retval; +} + +static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0; + + if (!write) { + *len = 0; + } else { + retval = pm_send_all(PM_SUSPEND, (void *) 2); + if (retval) + return retval; + suspend_mode = 1; + au1_wait(); + retval = pm_send_all(PM_RESUME, (void *) 0); + } + return retval; +} + + +static int pm_do_freq(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0, i; + unsigned long val, pll; +#define TMPBUFLEN 64 +#define MAX_CPU_FREQ 396 + char buf[8], *p; + unsigned long flags, intc0_mask, intc1_mask; + unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, + old_refresh; + unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; + + save_and_cli(flags); + if (!write) { + *len = 0; + } else { + /* Parse the new frequency */ + if (*len > TMPBUFLEN - 1) { + restore_flags(flags); + return -EFAULT; + } + if (copy_from_user(buf, buffer, *len)) { + restore_flags(flags); + return -EFAULT; + } + buf[*len] = 0; + p = buf; + val = simple_strtoul(p, &p, 0); + if (val > MAX_CPU_FREQ) { + restore_flags(flags); + return -EFAULT; + } + + pll = val / 12; + if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ + /* revisit this for higher speed cpus */ + restore_flags(flags); + return -EFAULT; + } + + old_baud_base = get_au1000_uart_baud_base(); + old_cpu_freq = get_au1000_speed(); + + new_cpu_freq = pll * 12 * 1000000; + new_baud_base = (new_cpu_freq / 4) / 16; + set_au1000_speed(new_cpu_freq); + set_au1000_uart_baud_base(new_baud_base); + + old_refresh = readl(MEM_SDREFCFG) & 0x1ffffff; + new_refresh = + ((old_refresh * new_cpu_freq) / + old_cpu_freq) | (readl(MEM_SDREFCFG) & ~0x1ffffff); + + writel(pll, SYS_CPUPLL); + au_sync_delay(1); + writel(new_refresh, MEM_SDREFCFG); + au_sync_delay(1); + + for (i = 0; i < 4; i++) { + if (readl + (UART_BASE + UART_MOD_CNTRL + + i * 0x00100000) == 3) { + old_clk = + readl(UART_BASE + UART_CLK + + i * 0x00100000); + // baud_rate = baud_base/clk + baud_rate = old_baud_base / old_clk; + /* we won't get an exact baud rate and the error + * could be significant enough that our new + * calculation will result in a clock that will + * give us a baud rate that's too far off from + * what we really want. + */ + if (baud_rate > 100000) + baud_rate = 115200; + else if (baud_rate > 50000) + baud_rate = 57600; + else if (baud_rate > 30000) + baud_rate = 38400; + else if (baud_rate > 17000) + baud_rate = 19200; + else + (baud_rate = 9600); + // new_clk = new_baud_base/baud_rate + new_clk = new_baud_base / baud_rate; + writel(new_clk, + UART_BASE + UART_CLK + + i * 0x00100000); + au_sync_delay(10); + } + } + } + + + /* We don't want _any_ interrupts other than + * match20. Otherwise our calibrate_delay() + * calculation will be off, potentially a lot. + */ + intc0_mask = save_local_and_disable(0); + intc1_mask = save_local_and_disable(1); + local_enable_irq(AU1000_TOY_MATCH2); + restore_flags(flags); + calibrate_delay(); + restore_local_and_enable(0, intc0_mask); + restore_local_and_enable(1, intc1_mask); + return retval; +} + + +static struct ctl_table pm_table[] = { + {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend}, + {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep}, + {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq}, + {0} +}; + +static struct ctl_table pm_dir_table[] = { + {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, + {0} +}; + +/* + * Initialize power interface + */ +static int __init pm_init(void) +{ + register_sysctl_table(pm_dir_table, 1); + return 0; +} + +__initcall(pm_init); + +inline void au1_wait(void) +{ + __asm__(".set\tmips3\n\t" + "wait\n\t" + "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set\tmips0"); +} + + +/* + * This is right out of init/main.c + */ + +/* This is the number of bits of precision for the loops_per_jiffy. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +static void calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_jiffy = (1 << 12); + + while (loops_per_jiffy <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */ ; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_jiffy set to equal one clock + (up to lps_precision bits) */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while (lps_precision-- && (loopbit >>= 1)) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } +} + + +#else /* CONFIG_PM */ + +void au1_wait(void) +{ + __asm__("nop\n\t" "nop\n\t"); +} + +#endif /* CONFIG_PM */ diff -urN linux-2.4.18/arch/mips/au1000/common/prom.c linux-2.4.19-pre5/arch/mips/au1000/common/prom.c --- linux-2.4.18/arch/mips/au1000/common/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/prom.c Sat Mar 30 22:55:26 2002 @@ -4,7 +4,7 @@ * PROM library initialisation code, assuming a version of * pmon is the boot code. * - * Copyright 2000 MontaVista Software Inc. + * Copyright 2000,2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. * ppopov@mvista.com or source@mvista.com * @@ -35,7 +35,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include #include #include #include @@ -44,22 +44,23 @@ /* #define DEBUG_CMDLINE */ -char arcs_cmdline[COMMAND_LINE_SIZE]; -int prom_argc; -char **prom_argv, **prom_envp; +char arcs_cmdline[CL_SIZE]; +extern int prom_argc; +extern char **prom_argv, **prom_envp; -typedef struct { - char *name; -/* char *val; */ -} t_env_var; +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; -char * __init prom_getcmdline(void) +char * prom_getcmdline(void) { return &(arcs_cmdline[0]); } -void __init prom_init_cmdline(void) +void prom_init_cmdline(void) { char *cp; int actr; @@ -101,7 +102,7 @@ return(NULL); } -static inline unsigned char str2hexnum(unsigned char c) +inline unsigned char str2hexnum(unsigned char c) { if(c >= '0' && c <= '9') return c - '0'; @@ -110,11 +111,43 @@ return 0; /* foo */ } -int __init page_is_ram(unsigned long pagenr) +inline void str2eaddr(unsigned char *ea, unsigned char *str) { - return 1; -} + int i; -void prom_free_prom_memory (void) + for(i = 0; i < 6; i++) { + unsigned char num; + + if((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) { + int i; + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + +#if 0 + printk("get_ethernet_addr: "); + for (i=0; i<5; i++) + printk("%02x:", (unsigned char)*(ethernet_addr+i)); + printk("%02x\n", *(ethernet_addr+i)); +#endif + + return 0; } + +void prom_free_prom_memory (void) {} +EXPORT_SYMBOL(prom_getcmdline); +EXPORT_SYMBOL(get_ethernet_addr); diff -urN linux-2.4.18/arch/mips/au1000/common/reset.c linux-2.4.19-pre5/arch/mips/au1000/common/reset.c --- linux-2.4.18/arch/mips/au1000/common/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/reset.c Sat Mar 30 22:55:26 2002 @@ -36,8 +36,56 @@ #include #include +extern int au_sleep(void); + void au1000_restart(char *command) { + /* Set all integrated peripherals to disabled states */ + u32 prid = read_32bit_cp0_register(CP0_PRID); + + printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n"); + switch (prid & 0xFF000000) + { + case 0x00000000: /* Au1000 */ + outl(0x02, 0xb0000010); /* ac97_enable */ + outl(0x08, 0xb017fffc); /* usbh_enable - early errata */ + asm("sync"); + outl(0x00, 0xb017fffc); /* usbh_enable */ + outl(0x00, 0xb0200058); /* usbd_enable */ + outl(0x00, 0xb0300040); /* ir_enable */ + outl(0x00, 0xb0520000); /* macen0 */ + outl(0x00, 0xb0520004); /* macen1 */ + outl(0x00, 0xb1000008); /* i2s_enable */ + outl(0x00, 0xb1100100); /* uart0_enable */ + outl(0x00, 0xb1200100); /* uart1_enable */ + outl(0x00, 0xb1300100); /* uart2_enable */ + outl(0x00, 0xb1400100); /* uart3_enable */ + outl(0x02, 0xb1600100); /* ssi0_enable */ + outl(0x02, 0xb1680100); /* ssi1_enable */ + outl(0x00, 0xb1900020); /* sys_freqctrl0 */ + outl(0x00, 0xb1900024); /* sys_freqctrl1 */ + outl(0x00, 0xb1900028); /* sys_clksrc */ + outl(0x00, 0xb1900100); /* sys_pininputen */ + break; + case 0x01000000: /* Au1500 */ + outl(0x02, 0xb0000010); /* ac97_enable */ + outl(0x08, 0xb017fffc); /* usbh_enable - early errata */ + asm("sync"); + outl(0x00, 0xb017fffc); /* usbh_enable */ + outl(0x00, 0xb0200058); /* usbd_enable */ + outl(0x00, 0xb1520000); /* macen0 */ + outl(0x00, 0xb1520004); /* macen1 */ + outl(0x00, 0xb1100100); /* uart0_enable */ + outl(0x00, 0xb1400100); /* uart3_enable */ + outl(0x00, 0xb1900020); /* sys_freqctrl0 */ + outl(0x00, 0xb1900024); /* sys_freqctrl1 */ + outl(0x00, 0xb1900028); /* sys_clksrc */ + outl(0x00, 0xb1900100); /* sys_pininputen */ + + default: + break; + } + set_cp0_status(ST0_BEV | ST0_ERL); set_cp0_config(CONF_CM_UNCACHED); flush_cache_all(); @@ -48,10 +96,18 @@ void au1000_halt(void) { printk(KERN_NOTICE "\n** You can safely turn off the power\n"); +#ifdef CONFIG_PM + au_sleep(); + + /* should not get here */ + printk(KERN_ERR "Unable to put cpu in sleep mode\n"); + while(1); +#else while (1) __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0"); +#endif } void au1000_power_off(void) diff -urN linux-2.4.18/arch/mips/au1000/common/rtc.c linux-2.4.19-pre5/arch/mips/au1000/common/rtc.c --- linux-2.4.18/arch/mips/au1000/common/rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/common/rtc.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,36 @@ +/* + * 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. + * + * RTC routines for PC style attached Dallas chip. + * + * Copyright (C) 1998, 2001 by Ralf Baechle + */ +#include +#include + +#define PB1500_RTC_ADDR 0xAC000000 + +static unsigned char std_rtc_read_data(unsigned long addr) +{ + addr <<= 2; + return readb(addr + PB1500_RTC_ADDR); +} + +static void std_rtc_write_data(unsigned char data, unsigned long addr) +{ + addr <<= 2; + writeb(data, addr + PB1500_RTC_ADDR); +} + +static int std_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops pb1500_rtc_ops = { + &std_rtc_read_data, + &std_rtc_write_data, + &std_rtc_bcd_mode +}; diff -urN linux-2.4.18/arch/mips/au1000/common/serial.c linux-2.4.19-pre5/arch/mips/au1000/common/serial.c --- linux-2.4.18/arch/mips/au1000/common/serial.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/serial.c Sat Mar 30 22:55:26 2002 @@ -131,7 +131,7 @@ static struct timer_list serial_timer; -extern unsigned long get_au1000_uart_baud(void); +extern unsigned long get_au1000_uart_baud_base(void); /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL @@ -241,12 +241,12 @@ static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) { - return (inl(info->port+offset) & 0xff); + return (inl(info->port+offset) & 0xffff); } static _INLINE_ void serial_out(struct async_struct *info, int offset, int value) { - outl(value & 0xff, info->port+offset); + outl(value & 0xffff, info->port+offset); } @@ -752,6 +752,7 @@ if (inl(UART_MOD_CNTRL + state->port) != 0x3) { outl(3, UART_MOD_CNTRL + state->port); + au_sync_delay(10); } #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d (irq %d)...", info->line, state->irq); @@ -986,6 +987,10 @@ set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; +#ifndef CONFIG_REMOTE_DEBUG + outl(0, UART_MOD_CNTRL + state->port); + au_sync_delay(10); +#endif restore_flags(flags); } @@ -1037,7 +1042,8 @@ if (!baud) { baud = 9600; /* B0 transition handled in rs_set_termios */ } - baud_base = info->state->baud_base; + baud_base = get_au1000_uart_baud_base(); + //if (baud == 38400 && if (((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { quot = info->state->custom_divisor; @@ -2511,6 +2517,7 @@ if (inl(UART_MOD_CNTRL + state->port) != 0x3) { outl(3, UART_MOD_CNTRL + state->port); + au_sync_delay(10); } state->type = PORT_16550; @@ -2541,7 +2548,11 @@ serial_outp(info, UART_FCR, 0); (void)serial_in(info, UART_RX); serial_outp(info, UART_IER, 0); - + +#ifndef CONFIG_REMOTE_DEBUG + outl(0, UART_MOD_CNTRL + state->port); + au_sync_delay(10); +#endif restore_flags(flags); } @@ -2643,12 +2654,12 @@ callout_driver.proc_entry = 0; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->baud_base = get_au1000_uart_baud(); + state->baud_base = get_au1000_uart_baud_base(); state->magic = SSTATE_MAGIC; state->line = i; state->type = PORT_UNKNOWN; @@ -3044,7 +3055,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; - state->baud_base = get_au1000_uart_baud(); + state->baud_base = get_au1000_uart_baud_base(); quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); diff -urN linux-2.4.18/arch/mips/au1000/common/time.c linux-2.4.19-pre5/arch/mips/au1000/common/time.c --- linux-2.4.18/arch/mips/au1000/common/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/common/time.c Sat Mar 30 22:55:26 2002 @@ -1,4 +1,5 @@ /* + * * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com * Copied and modified Carsten Langgaard's time.c * @@ -23,7 +24,10 @@ * ######################################################################## * * Setting up the clock on the MIPS boards. + * */ + +#include #include #include #include @@ -32,28 +36,38 @@ #include #include +#include +#include #include #include #include #include +extern void startup_match20_interrupt(void); + extern volatile unsigned long wall_jiffies; unsigned long missed_heart_beats = 0; -unsigned long uart_baud_base; static unsigned long r4k_offset; /* Amount to increment compare reg each time */ static unsigned long r4k_cur; /* What counter should be at next timer irq */ extern rwlock_t xtime_lock; +unsigned int mips_counter_frequency = 0; + +/* Cycle counter value at the previous timer interrupt.. */ +static unsigned int timerhi = 0, timerlo = 0; -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +#ifdef CONFIG_PM +#define MATCH20_INC 328 +extern void startup_match20_interrupt(void); +static unsigned long last_pc0, last_match20; +#endif static inline void ack_r4ktimer(unsigned long newval) { write_32bit_cp0_register(CP0_COMPARE, newval); } - /* * There are a lot of conceptually broken versions of the MIPS timer interrupt * handler floating around. This one is rather different, but the algorithm @@ -62,12 +76,27 @@ unsigned long wtimer; void mips_timer_interrupt(struct pt_regs *regs) { - int irq = 7; + int irq = 63; + unsigned long count; + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + +#ifdef CONFIG_PM + printk(KERN_ERR "Unexpected CP0 interrupt\n"); + regs->cp0_status &= ~IE_IRQ5; /* disable CP0 interrupt */ + return; +#endif if (r4k_offset == 0) goto null; do { + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + kstat.irqs[0][irq]++; do_timer(regs); r4k_cur += r4k_offset; @@ -76,12 +105,61 @@ } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) - r4k_cur) < 0x7fffffff); + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); return; null: ack_r4ktimer(0); } +#ifdef CONFIG_PM +void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long pc0; + int time_elapsed; + static int jiffie_drift = 0; + + kstat.irqs[0][irq]++; + if (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { + /* should never happen! */ + printk(KERN_WARNING "counter 0 w status eror\n"); + return; + } + + pc0 = inl(SYS_TOYREAD); + if (pc0 < last_match20) { + /* counter overflowed */ + time_elapsed = (0xffffffff - last_match20) + pc0; + } + else { + time_elapsed = pc0 - last_match20; + } + + while (time_elapsed > 0) { + do_timer(regs); + time_elapsed -= MATCH20_INC; + last_match20 += MATCH20_INC; + jiffie_drift++; + } + + last_pc0 = pc0; + outl(last_match20 + MATCH20_INC, SYS_TOYMATCH2); + au_sync(); + + /* our counter ticks at 10.009765625 ms/tick, we we're running + * almost 10uS too slow per tick. + */ + + if (jiffie_drift >= 999) { + jiffie_drift -= 999; + do_timer(regs); /* increment jiffies by one */ + } +} +#endif + /* * Figure out the r4k offset, the amount to increment the compare * register for each time tick. @@ -90,49 +168,48 @@ unsigned long cal_r4koff(void) { unsigned long count; - unsigned long cpu_pll; unsigned long cpu_speed; unsigned long start, end; unsigned long counter; - int i; int trim_divide = 16; + unsigned long flags; - counter = inl(PC_COUNTER_CNTRL); - outl(counter | PC_CNTRL_EN1, PC_COUNTER_CNTRL); + save_and_cli(flags); - while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S); - outl(trim_divide-1, PC1_TRIM); /* RTC now ticks at 32.768/16 kHz */ - while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S); - - while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S); - outl (0, PC1_COUNTER_WRITE); - while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S); + counter = inl(SYS_COUNTER_CNTRL); + outl(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL); - start = inl(PC1_COUNTER_READ); + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); + outl(trim_divide-1, SYS_RTCTRIM); /* RTC now ticks at 32.768/16 kHz */ + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); + + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); + outl (0, SYS_TOYWRITE); + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); + + start = inl(SYS_RTCREAD); start += 2; /* wait for the beginning of a new tick */ - while (inl(PC1_COUNTER_READ) < start); + while (inl(SYS_RTCREAD) < start); /* Start r4k counter. */ write_32bit_cp0_register(CP0_COUNT, 0); end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */ - while (end > inl(PC1_COUNTER_READ)); + while (end > inl(SYS_RTCREAD)); count = read_32bit_cp0_register(CP0_COUNT); cpu_speed = count * 2; - uart_baud_base = (((cpu_speed) / 4) / 16); + mips_counter_frequency = count; + set_au1000_uart_baud_base(((cpu_speed) / 4) / 16); + restore_flags(flags); return (cpu_speed / HZ); } -static unsigned long __init get_mips_time(void) -{ - return inl(PC0_COUNTER_READ); -} void __init time_init(void) { - unsigned int est_freq, flags; + unsigned int est_freq; printk("calculating r4koff... "); r4k_offset = cal_r4koff(); @@ -144,25 +221,51 @@ est_freq -= est_freq%10000; printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, (est_freq%1000000)*100/1000000); + set_au1000_speed(est_freq); + set_au1000_lcd_clock(); // program the LCD clock r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); write_32bit_cp0_register(CP0_COMPARE, r4k_cur); - set_cp0_status(ALLINTS); - /* Read time from the RTC chipset. */ - write_lock_irqsave (&xtime_lock, flags); - xtime.tv_sec = get_mips_time(); + /* no RTC on the pb1000 */ + xtime.tv_sec = 0; xtime.tv_usec = 0; - write_unlock_irqrestore(&xtime_lock, flags); + +#ifdef CONFIG_PM + /* + * setup counter 0, since it keeps ticking after a + * 'wait' instruction has been executed. The CP0 timer and + * counter 1 do NOT continue running after 'wait' + * + * It's too early to call request_irq() here, so we handle + * counter 0 interrupt as a special irq and it doesn't show + * up under /proc/interrupts. + */ + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); + writel(0, SYS_TOYWRITE); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); + + writel(readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK); + writel(~0, SYS_WAKESRC); + au_sync(); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); + + /* setup match20 to interrupt once every 10ms */ + last_pc0 = last_match20 = readl(SYS_TOYREAD); + writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); + au_sync(); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); + startup_match20_interrupt(); +#endif + + //set_cp0_status(ALLINTS); + au_sync(); } /* This is for machines which generate the exact clock. */ #define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff) - -/* Cycle counter value at the previous timer interrupt.. */ +#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff) -static unsigned int timerhi = 0, timerlo = 0; static unsigned long div64_32(unsigned long v1, unsigned long v2, unsigned long v3) @@ -173,11 +276,28 @@ } -/* - * FIXME: Does playing with the RP bit in c0_status interfere with this code? - */ static unsigned long do_fast_gettimeoffset(void) { +#ifdef CONFIG_PM + unsigned long pc0; + unsigned long offset; + + pc0 = readl(SYS_TOYREAD); + if (pc0 < last_pc0) { + offset = 0xffffffff - last_pc0 + pc0; + printk("offset over: %x\n", (unsigned)offset); + } + else { + offset = (unsigned long)(((pc0 - last_pc0) * 305) / 10); + } + if ((pc0-last_pc0) > 2*MATCH20_INC) { + printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", + (unsigned)offset, (unsigned)last_pc0, + (unsigned)last_match20, (unsigned)pc0); + } + au_sync(); + return offset; +#else u32 count; unsigned long res, tmp; unsigned long r0; @@ -225,6 +345,7 @@ res = USECS_PER_JIFFY-1; return res; +#endif } void do_gettimeofday(struct timeval *tv) @@ -273,14 +394,4 @@ time_esterror = NTP_PHASE_LIMIT; write_unlock_irq (&xtime_lock); -} - -/* - * The UART baud base is not known at compile time ... if - * we want to be able to use the same code on different - * speed CPUs. - */ -unsigned long get_au1000_uart_baud() -{ - return uart_baud_base; } diff -urN linux-2.4.18/arch/mips/au1000/common/usbdev.c linux-2.4.19-pre5/arch/mips/au1000/common/usbdev.c --- linux-2.4.18/arch/mips/au1000/common/usbdev.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/common/usbdev.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1844 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1000 USB Device-Side Serial TTY Driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DEBUG +#include + +#include +#include +#include +#include +#include +#include + +/* Module information */ +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com"); +MODULE_DESCRIPTION("Au1000 USB Device-Side Serial TTY Driver"); + +#undef USBDEV_PIO + +#define SERIAL_TTY_MAJOR 189 + +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL) + +#define MAX_NUM_PORTS 2 + +#define NUM_PORTS 1 +#define NUM_EP 2*NUM_PORTS + +#define EP0_MAX_PACKET_SIZE 64 +#define EP2_MAX_PACKET_SIZE 64 +#define EP3_MAX_PACKET_SIZE 64 +#define EP4_MAX_PACKET_SIZE 64 +#define EP5_MAX_PACKET_SIZE 64 + +#ifdef USBDEV_PIO +#define EP_FIFO_DEPTH 8 +#endif + +typedef enum { + ATTACHED = 0, + POWERED, + DEFAULT, + ADDRESS, + CONFIGURED +} dev_state_t; + +/* local function prototypes */ +static int serial_open(struct tty_struct *tty, struct file *filp); +static void serial_close(struct tty_struct *tty, struct file *filp); +static int serial_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count); +static int serial_write_room(struct tty_struct *tty); +static int serial_chars_in_buffer(struct tty_struct *tty); +static void serial_throttle(struct tty_struct *tty); +static void serial_unthrottle(struct tty_struct *tty); +static int serial_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static void serial_set_termios (struct tty_struct *tty, struct termios * old); + +typedef struct { + int read_fifo; + int write_fifo; + int ctrl_stat; + int read_fifo_status; + int write_fifo_status; +} endpoint_reg_t; + +typedef struct pkt { + int size; + u8 *bufptr; + struct pkt *next; + u8 buf[0]; +} pkt_t; + +typedef struct { + pkt_t *head; + pkt_t *tail; + int count; +} pkt_list_t; + +typedef struct { + struct usb_endpoint_descriptor *desc; + endpoint_reg_t *reg; + // Only one of these are used, unless this is a control ep + pkt_list_t inlist; + pkt_list_t outlist; + unsigned int indma, outdma; // DMA channel numbers for IN, OUT + int inirq, outirq; // DMA buffer done irq numbers + int max_pkt_size; + spinlock_t lock; +} endpoint_t; + +struct usb_serial_port { + struct usb_serial *serial; /* ptr back to the owner of this port */ + struct tty_struct *tty; /* the coresponding tty for this port */ + unsigned char number; + char active; /* someone has this device open */ + spinlock_t port_lock; + + endpoint_t ep_bulkin; + endpoint_t ep_bulkout; + + wait_queue_head_t write_wait; + + /* task queue for line discipline waking up on send packet complete */ + struct tq_struct send_complete_tq; + /* task queue for line discipline wakeup on receive packet complete */ + struct tq_struct receive_complete_tq; + + int open_count; /* number of times this port has been opened */ +}; + +struct usb_serial { + struct tty_driver *tty_driver; /* the tty_driver for this device */ + unsigned char minor; /* the minor number for this device */ + + endpoint_t ep_ctrl; + + struct usb_device_descriptor *dev_desc; + struct usb_interface_descriptor *if_desc; + struct usb_config_descriptor *conf_desc; + struct usb_string_descriptor *str_desc[6]; + + struct usb_serial_port port[NUM_PORTS]; + + dev_state_t state; // device state + int suspended; // suspended flag + int address; // device address + int interface; + u8 alternate_setting; + u8 configuration; // configuration value + int remote_wakeup_en; +}; + + +static struct usb_device_descriptor dev_desc = { + bLength:USB_DT_DEVICE_SIZE, + bDescriptorType:USB_DT_DEVICE, + bcdUSB:0x0110, //usb rev 1.0 + bDeviceClass:USB_CLASS_PER_INTERFACE, //class (none) + bDeviceSubClass:0x00, //subclass (none) + bDeviceProtocol:0x00, //protocol (none) + bMaxPacketSize0:EP0_MAX_PACKET_SIZE, //max packet size for ep0 + idVendor:0x6d04, //vendor id + idProduct:0x0bc0, //product id + bcdDevice:0x0001, //BCD rev 0.1 + iManufacturer:0x01, //manufactuer string index + iProduct:0x02, //product string index + iSerialNumber:0x03, //serial# string index + bNumConfigurations:0x01 //num configurations +}; + +static struct usb_endpoint_descriptor ep_desc[] = { + { + // EP2, Bulk IN for Port 0 + bLength:USB_DT_ENDPOINT_SIZE, + bDescriptorType:USB_DT_ENDPOINT, + bEndpointAddress:USB_DIR_IN | 0x02, + bmAttributes:USB_ENDPOINT_XFER_BULK, + wMaxPacketSize:EP2_MAX_PACKET_SIZE, + bInterval:0x00 // ignored for bulk + }, + { + // EP4, Bulk OUT for Port 0 + bLength:USB_DT_ENDPOINT_SIZE, + bDescriptorType:USB_DT_ENDPOINT, + bEndpointAddress:USB_DIR_OUT | 0x04, + bmAttributes:USB_ENDPOINT_XFER_BULK, + wMaxPacketSize:EP4_MAX_PACKET_SIZE, + bInterval:0x00 // ignored for bulk + }, + { + // EP3, Bulk IN for Port 1 + bLength:USB_DT_ENDPOINT_SIZE, + bDescriptorType:USB_DT_ENDPOINT, + bEndpointAddress:USB_DIR_IN | 0x03, + bmAttributes:USB_ENDPOINT_XFER_BULK, + wMaxPacketSize:EP3_MAX_PACKET_SIZE, + bInterval:0x00 // ignored for bulk + }, + { + // EP5, Bulk OUT for Port 1 + bLength:USB_DT_ENDPOINT_SIZE, + bDescriptorType:USB_DT_ENDPOINT, + bEndpointAddress:USB_DIR_OUT | 0x05, + bmAttributes:USB_ENDPOINT_XFER_BULK, + wMaxPacketSize:EP5_MAX_PACKET_SIZE, + bInterval:0x00 // ignored for bulk + }, +}; + +static struct usb_interface_descriptor if_desc = { + bLength:USB_DT_INTERFACE_SIZE, + bDescriptorType:USB_DT_INTERFACE, + bInterfaceNumber:0x00, + bAlternateSetting:0x00, + bNumEndpoints:NUM_EP, + bInterfaceClass:0xff, + bInterfaceSubClass:0xab, + bInterfaceProtocol:0x00, + iInterface:0x05 +}; + +#define CONFIG_DESC_LEN \ + USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZE + +static struct usb_config_descriptor config_desc = { + bLength:USB_DT_CONFIG_SIZE, + bDescriptorType:USB_DT_CONFIG, + wTotalLength:CONFIG_DESC_LEN, + bNumInterfaces:0x01, + bConfigurationValue:0x01, + iConfiguration:0x04, // configuration string + bmAttributes:0xc0, // self-powered + MaxPower:20 // 40 mA +}; + +// These strings will be converted to Unicode before sending +static char *strings[5] = { + "Alchemy Semiconductor", + "Alchemy Au1000", + "1.0", + "Au1000 UART Config", + "Au1000 UART Interface" +}; + +// String[0] is a list of Language IDs supported by this device +static struct usb_string_descriptor string_desc0 = { + bLength:4, + bDescriptorType:USB_DT_STRING, + wData:{0x0409} // English, US +}; + + +static endpoint_reg_t ep_reg[] = { + // FIFO's 0 and 1 are EP0 default control + {USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT}, + // FIFO 2 is EP2, Port 0, bulk IN + { -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT }, + // FIFO 4 is EP4, Port 0, bulk OUT + {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP3WR, -1}, + // FIFO 3 is EP3, Port 1, bulk IN + { -1, USBD_EP3WRSTAT, USBD_EP3CS, -1, USBD_EP3WRSTAT }, + // FIFO 5 is EP5, Port 1, bulk OUT + {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1} +}; + +static struct { + unsigned int id; + const char *str; +} ep_dma_id[] = { + { DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" }, + { DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" }, + { DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" }, + { DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" }, + { DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" }, + { DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" } +}; + +static int serial_refcount; +static struct tty_driver serial_tty_driver; +static struct tty_struct *serial_tty[1]; +static struct termios *serial_termios[1]; +static struct termios *serial_termios_locked[1]; +static struct usb_serial usbserial; + +#define DIR_OUT 0 +#define DIR_IN (1<<3) + +static const u32 au1000_config_table[25] __devinitdata = { + 0x00, + ((EP0_MAX_PACKET_SIZE & 0x380) >> 7) | + (USB_ENDPOINT_XFER_CONTROL << 4), + (EP0_MAX_PACKET_SIZE & 0x7f) << 1, + 0x00, + 0x01, + + 0x10, + ((EP2_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN | + (USB_ENDPOINT_XFER_BULK << 4), + (EP2_MAX_PACKET_SIZE & 0x7f) << 1, + 0x00, + 0x02, + + 0x20, + ((EP3_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN | + (USB_ENDPOINT_XFER_BULK << 4), + (EP3_MAX_PACKET_SIZE & 0x7f) << 1, + 0x00, + 0x03, + + 0x30, + ((EP4_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT | + (USB_ENDPOINT_XFER_BULK << 4), + (EP4_MAX_PACKET_SIZE & 0x7f) << 1, + 0x00, + 0x04, + + 0x40, + ((EP5_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT | + (USB_ENDPOINT_XFER_BULK << 4), + (EP5_MAX_PACKET_SIZE & 0x7f) << 1, + 0x00, + 0x05 +}; + +static inline endpoint_t * +fifonum_to_ep(struct usb_serial* serial, int fifo_num) +{ + switch (fifo_num) { + case 0: + case 1: + return &serial->ep_ctrl; + case 2: + return &serial->port[0].ep_bulkin; + case 3: + return &serial->port[1].ep_bulkin; + case 4: + return &serial->port[0].ep_bulkout; + case 5: + return &serial->port[1].ep_bulkout; + } + + return NULL; +} + +static inline struct usb_serial_port * +fifonum_to_port(struct usb_serial* serial, int fifo_num) +{ + switch (fifo_num) { + case 2: + case 4: + return &serial->port[0]; + case 3: + case 5: + return &serial->port[1]; + } + + return NULL; +} + +static inline endpoint_t * +epnum_to_ep(struct usb_serial* serial, int ep_num) +{ + switch (ep_num) { + case 0: + return &serial->ep_ctrl; + case 2: + return &serial->port[0].ep_bulkin; + case 3: + return &serial->port[1].ep_bulkin; + case 4: + return &serial->port[0].ep_bulkout; + case 5: + return &serial->port[1].ep_bulkout; + } + + return NULL; +} + + +static inline int +port_paranoia_check(struct usb_serial_port *port, const char *function) +{ + if (!port) { + dbg("%s - port == NULL", function); + return -1; + } + if (!port->serial) { + dbg("%s - port->serial == NULL", function); + return -1; + } + if (!port->tty) { + dbg("%s - port->tty == NULL", function); + return -1; + } + + return 0; +} + +static inline struct usb_serial* +get_usb_serial (struct usb_serial_port *port, const char *function) +{ + /* if no port was specified, or it fails a paranoia check */ + if (!port || port_paranoia_check(port, function)) { + /* then say that we dont have a valid usb_serial thing, + * which will end up genrating -ENODEV return values */ + return NULL; + } + + return port->serial; +} + + +static inline pkt_t * +alloc_packet(int data_size) +{ + pkt_t* pkt = (pkt_t *)kmalloc(sizeof(pkt_t) + data_size, ALLOC_FLAGS); + if (!pkt) + return NULL; + pkt->size = data_size; + pkt->bufptr = pkt->buf; +#ifndef USBDEV_PIO + pkt->bufptr = KSEG1ADDR(pkt->bufptr); +#endif + pkt->next = NULL; + return pkt; +} + + +/* + * Link a packet to the tail of the enpoint's packet list. + */ +static void +link_packet(endpoint_t * ep, pkt_list_t * list, pkt_t * pkt) +{ + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + + if (!list->tail) { + list->head = list->tail = pkt; + list->count = 1; + } else { + list->tail->next = pkt; + list->tail = pkt; + list->count++; + } + + spin_unlock_irqrestore(&ep->lock, flags); +} + +/* + * Unlink and return a packet from the head of the enpoint's packet list. + */ +static pkt_t * +unlink_packet(endpoint_t * ep, pkt_list_t * list) +{ + unsigned long flags; + pkt_t *pkt; + + spin_lock_irqsave(&ep->lock, flags); + + pkt = list->head; + if (!pkt || !list->count) { + spin_unlock_irqrestore(&ep->lock, flags); + return NULL; + } + + list->head = pkt->next; + if (!list->head) { + list->head = list->tail = NULL; + list->count = 0; + } else + list->count--; + + spin_unlock_irqrestore(&ep->lock, flags); + + return pkt; +} + +/* + * Create and attach a new packet to the tail of the enpoint's + * packet list. + */ +static pkt_t * +add_packet(endpoint_t * ep, pkt_list_t * list, int size) +{ + pkt_t *pkt = alloc_packet(size); + if (!pkt) + return NULL; + + link_packet(ep, list, pkt); + return pkt; +} + + +/* + * Unlink and free a packet from the head of the enpoint's + * packet list. + */ +static inline void +free_packet(endpoint_t * ep, pkt_list_t * list) +{ + kfree(unlink_packet(ep, list)); +} + +static inline void +flush_pkt_list(endpoint_t * ep, pkt_list_t * list) +{ + while (list->count) + free_packet(ep, list); +} + + +static inline void +flush_write_fifo(endpoint_t * ep) +{ + if (ep->reg->write_fifo_status >= 0) { + outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->write_fifo_status); + udelay(100); + outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, + ep->reg->write_fifo_status); + } +} + + +static inline void +flush_read_fifo(endpoint_t * ep) +{ + if (ep->reg->read_fifo_status >= 0) { + outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->read_fifo_status); + udelay(100); + outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, + ep->reg->read_fifo_status); + } +} + + +static void +endpoint_flush(endpoint_t * ep) +{ + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + + // First, flush all packets + flush_pkt_list(ep, &ep->inlist); + flush_pkt_list(ep, &ep->outlist); + + // Now flush the endpoint's h/w FIFO(s) + flush_write_fifo(ep); + flush_read_fifo(ep); + + spin_unlock_irqrestore(&ep->lock, flags); +} + + +static void +endpoint_stall(endpoint_t * ep) +{ + unsigned long flags; + u32 cs; + + dbg(__FUNCTION__); + + spin_lock_irqsave(&ep->lock, flags); + + cs = inl(ep->reg->ctrl_stat) | USBDEV_CS_STALL; + outl_sync(cs, ep->reg->ctrl_stat); + + spin_unlock_irqrestore(&ep->lock, flags); +} + +static void +endpoint_unstall(endpoint_t * ep) +{ + unsigned long flags; + u32 cs; + + dbg(__FUNCTION__); + + spin_lock_irqsave(&ep->lock, flags); + + cs = inl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL; + outl_sync(cs, ep->reg->ctrl_stat); + + spin_unlock_irqrestore(&ep->lock, flags); +} + +static void +endpoint_reset_datatoggle(endpoint_t * ep) +{ + // FIXME: is this possible? +} + + +#ifdef USBDEV_PIO +static int +endpoint_fifo_read(endpoint_t * ep) +{ + unsigned long flags; + int read_count = 0; + u8 *bufptr; + pkt_t *pkt = ep->outlist.tail; + + if (!pkt) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + + bufptr = pkt->bufptr; + while (inl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) { + *bufptr++ = inl(ep->reg->read_fifo) & 0xff; + read_count++; + pkt->size++; + } + pkt->bufptr = bufptr; + + spin_unlock_irqrestore(&ep->lock, flags); + return read_count; +} + + +static int +endpoint_fifo_write(endpoint_t * ep) +{ + unsigned long flags; + int write_count = 0; + u8 *bufptr; + pkt_t *pkt = ep->inlist.head; + + if (!pkt) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + + bufptr = pkt->bufptr; + while ((inl(ep->reg->write_fifo_status) & USBDEV_FSTAT_FCNT_MASK) < + EP_FIFO_DEPTH) { + if (bufptr < pkt->buf + pkt->size) { + outl_sync(*bufptr++, ep->reg->write_fifo); + write_count++; + } else { + break; + } + } + pkt->bufptr = bufptr; + + spin_unlock_irqrestore(&ep->lock, flags); + return write_count; +} +#endif // USBDEV_PIO + +/* + * This routine is called to restart transmission of a packet. + * The endpoint's TSIZE must be set to the new packet's size, + * and DMA to the write FIFO needs to be restarted. + */ +static void +kickstart_send_packet(endpoint_t * ep) +{ + u32 cs; + pkt_t *pkt = ep->inlist.head; + + dbg(__FUNCTION__ ": pkt=%p", pkt); + + if (!pkt) + return; + + /* + * The write fifo should already be drained if things are + * working right, but flush it anyway just in case. + */ + flush_write_fifo(ep); + cs = inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL; + cs |= (pkt->size << USBDEV_CS_TSIZE_BIT); + outl_sync(cs, ep->reg->ctrl_stat); +#ifdef USBDEV_PIO + endpoint_fifo_write(ep); +#else + disable_dma(ep->indma); + if (get_dma_active_buffer(ep->indma)) { + set_dma_count1(ep->indma, pkt->size); + set_dma_addr1(ep->indma, virt_to_phys(pkt->bufptr)); + enable_dma_buffer1(ep->indma); // reenable + } else { + set_dma_count0(ep->indma, pkt->size); + set_dma_addr0(ep->indma, virt_to_phys(pkt->bufptr)); + enable_dma_buffer0(ep->indma); // reenable + } + enable_dma(ep->indma); +#endif +} + + +/* + * This routine is called when a packet in the inlist has been + * completed. Frees the completed packet and starts sending the + * next. + */ +static void +send_packet_complete(endpoint_t * ep) +{ + if (ep->inlist.head) + dbg(__FUNCTION__ ": pkt=%p, ab=%d", + ep->inlist.head, get_dma_active_buffer(ep->indma)); + + outl_sync(inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL, + ep->reg->ctrl_stat); + //disable_dma(ep->indma); + free_packet(ep, &ep->inlist); + // begin transmitting next packet in the inlist + if (ep->inlist.count) + kickstart_send_packet(ep); +} + + +/* + * Unlink and return a packet from the head of the given ep's packet + * outlist. It is the responsibility of the caller to free the packet. + * The receive complete interrupt adds packets to the tail of this list. + */ +static pkt_t * +receive_packet(endpoint_t * ep) +{ + pkt_t *pkt = unlink_packet(ep, &ep->outlist); + //dma_cache_inv((unsigned long)pkt->buf, pkt->size); + return pkt; +} + +/* + * This routine is called to restart reception of a packet. + */ +static void +kickstart_receive_packet(endpoint_t * ep) +{ + pkt_t *pkt; + + // get and link a new packet for next reception + if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) { + err(__FUNCTION__ ": could not alloc new packet"); + return; + } + + /* + * The read fifo should already be drained if things are + * working right, but flush it anyway just in case. + */ + flush_read_fifo(ep); +#ifndef USBDEV_PIO + if (get_dma_active_buffer(ep->outdma)) { + set_dma_count1(ep->outdma, ep->max_pkt_size); + set_dma_addr1(ep->outdma, virt_to_phys(pkt->bufptr)); + enable_dma_buffer1(ep->outdma); // reenable + } else { + set_dma_count0(ep->outdma, ep->max_pkt_size); + set_dma_addr0(ep->outdma, virt_to_phys(pkt->bufptr)); + enable_dma_buffer0(ep->outdma); // reenable + } + enable_dma(ep->outdma); +#endif +} + + +/* + * This routine is called when a packet in the outlist has been + * completed (received) and we need to prepare for a new packet + * to be received. Halts DMA and computes the packet size from the + * remaining DMA counter. Then prepares a new packet for reception + * and restarts DMA. FIXME: what if another packet comes in + * on top of the completed packet? Counter would be wrong. + */ +static void +receive_packet_complete(endpoint_t * ep) +{ + pkt_t *pkt = ep->outlist.tail; + + if (!pkt) + return; + + disable_dma(ep->outdma); + pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma); +#ifdef USBDEV_PIO + pkt->bufptr = pkt->buf; // reset bufptr +#endif + dbg(__FUNCTION__ ": size=%d", pkt->size); + + kickstart_receive_packet(ep); +} + + + +/* + * Add a new packet to the tail of the given ep's packet + * inlist. The transmit complete interrupt frees packets from + * the head of this list. + */ +static int +send_packet(endpoint_t * ep, u8 * data, int data_len, int from_user) +{ + unsigned long flags; + pkt_list_t *list = &ep->inlist; + pkt_t *pkt; + + if (!data || !data_len) + return 0; + + if (!(pkt = alloc_packet(data_len))) { + err(__FUNCTION__ ": could not alloc new packet"); + return -ENOMEM; + } + + if (from_user) + copy_from_user(pkt->bufptr, data, data_len); + else + memcpy(pkt->bufptr, data, data_len); + au_sync(); + + //dma_cache_wback_inv((unsigned long)pkt->buf, data_len); + + link_packet(ep, list, pkt); + + spin_lock_irqsave(&ep->lock, flags); + + dbg(__FUNCTION__ ": size=%d, list count=%d", pkt->size, list->count); + + if (list->count == 1) { + /* + * if the packet count is one, it means the list was empty, + * and no more data will go out this ep until we kick-start + * it again. + */ + kickstart_send_packet(ep); + } + + spin_unlock_irqrestore(&ep->lock, flags); + return data_len; +} + + +// SETUP packet request parser +static void +process_setup (struct usb_serial* serial, devrequest* setup) +{ + int desc_len, strnum; + + dbg(__FUNCTION__ ": req %d", setup->request); + + switch (setup->request) { + case USB_REQ_SET_ADDRESS: + serial->address = le16_to_cpu(setup->value); + dbg(__FUNCTION__ ": our address=%d", serial->address); + if (serial->address > 127 || serial->state == CONFIGURED) { + // usb spec doesn't tell us what to do, so just go to + // default state + serial->state = DEFAULT; + serial->address = 0; + } else if (serial->address) + serial->state = ADDRESS; + else + serial->state = DEFAULT; + break; + case USB_REQ_GET_DESCRIPTOR: + desc_len = le16_to_cpu(setup->length); + switch (le16_to_cpu(setup->value) >> 8) { + case USB_DT_DEVICE: + // send device descriptor! + desc_len = desc_len > serial->dev_desc->bLength ? + serial->dev_desc->bLength : desc_len; + dbg("sending device desc, size=%d", desc_len); + send_packet(&serial->ep_ctrl, (u8*)serial->dev_desc, + desc_len, 0); + break; + case USB_DT_CONFIG: + // If the config descr index in low-byte of + // setup->value is valid, send config descr, + // otherwise stall ep0. + if ((le16_to_cpu(setup->value) & 0xff) == 0) { + // send config descriptor! + if (desc_len <= USB_DT_CONFIG_SIZE) { + dbg("sending partial config desc, size=%d", + desc_len); + send_packet(&serial->ep_ctrl, + (u8*)serial->conf_desc, + desc_len, 0); + } else { + u8 full_conf_desc[CONFIG_DESC_LEN]; + int i, index = 0; + memcpy(&full_conf_desc[index], + serial->conf_desc, + USB_DT_CONFIG_SIZE); + index += USB_DT_CONFIG_SIZE; + memcpy(&full_conf_desc[index], + serial->if_desc, + USB_DT_INTERFACE_SIZE); + index += USB_DT_INTERFACE_SIZE; + for (i = 0; i < NUM_PORTS; i++) { + memcpy(&full_conf_desc[index], + serial->port[i].ep_bulkin.desc, + USB_DT_ENDPOINT_SIZE); + index += USB_DT_ENDPOINT_SIZE; + memcpy(&full_conf_desc[index], + serial->port[i].ep_bulkout.desc, + USB_DT_ENDPOINT_SIZE); + index += USB_DT_ENDPOINT_SIZE; + } + dbg("sending whole config desc, size=%d, our size=%d", + desc_len, CONFIG_DESC_LEN); + desc_len = desc_len > CONFIG_DESC_LEN ? + CONFIG_DESC_LEN : desc_len; + send_packet(&serial->ep_ctrl, + full_conf_desc, desc_len, 0); + } + } else + endpoint_stall(&serial->ep_ctrl); + break; + case USB_DT_STRING: + // If the string descr index in low-byte of setup->value + // is valid, send string descr, otherwise stall ep0. + strnum = le16_to_cpu(setup->value) & 0xff; + if (strnum >= 0 && strnum < 6) { + struct usb_string_descriptor *desc = + serial->str_desc[strnum]; + desc_len = desc_len > desc->bLength ? + desc->bLength : desc_len; + dbg("sending string desc %d", strnum); + send_packet(&serial->ep_ctrl, (u8 *) desc, + desc_len, 0); + } else + endpoint_stall(&serial->ep_ctrl); + break; + default: // Invalid request + dbg("invalid get desc=%d, stalled", + le16_to_cpu(setup->value) >> 8); + endpoint_stall(&serial->ep_ctrl); // Stall endpoint 0 + break; + } + break; + case USB_REQ_SET_DESCRIPTOR: + // FIXME: anything to set here? + break; + case USB_REQ_GET_INTERFACE: + // interface must be zero. + if ((le16_to_cpu(setup->index) & 0xff) || + serial->state == ADDRESS) { + // FIXME: respond with "request error". how? + } else if (serial->state == CONFIGURED) { + // send serial->alternate_setting + dbg("sending alt setting"); + send_packet(&serial->ep_ctrl, + &serial->alternate_setting, 1, 0); + } + break; + case USB_REQ_SET_INTERFACE: + if (serial->state == ADDRESS) { + // FIXME: respond with "request error". how? + } else if (serial->state == CONFIGURED) { + serial->interface = le16_to_cpu(setup->index) & 0xff; + serial->alternate_setting = + le16_to_cpu(setup->value) & 0xff; + // interface and alternate_setting must be zero + if (serial->interface || serial->alternate_setting) { + // FIXME: respond with "request error". how? + } + } + break; + case USB_REQ_SET_CONFIGURATION: + // set active config to low-byte of serial.value + serial->configuration = le16_to_cpu(setup->value) & 0xff; + dbg("set config, config=%d", serial->configuration); + if (!serial->configuration && serial->state > DEFAULT) + serial->state = ADDRESS; + else if (serial->configuration == 1) + serial->state = CONFIGURED; + else { + // FIXME: "respond with request error" - how? + } + break; + case USB_REQ_GET_CONFIGURATION: + // send serial->configuration + dbg("sending config"); + send_packet(&serial->ep_ctrl, &serial->configuration, 1, 0); + break; + case USB_REQ_GET_STATUS: + // FIXME: looks like the h/w handles this one + switch (setup->requesttype) { + case 0x80: // Device + // FIXME: send device status + break; + case 0x81: // Interface + // FIXME: send interface status + break; + case 0x82: // End Point + // FIXME: send endpoint status + break; + default: // Invalid Command + endpoint_stall(&serial->ep_ctrl); // Stall End Point 0 + break; + } + break; + case USB_REQ_CLEAR_FEATURE: + switch (setup->requesttype) { + case 0x00: // Device + if ((le16_to_cpu(setup->value) & 0xff) == 1) + serial->remote_wakeup_en = 0; + else + endpoint_stall(&serial->ep_ctrl); + break; + case 0x02: // End Point + if ((le16_to_cpu(setup->value) & 0xff) == 0) { + endpoint_t *ep = + epnum_to_ep(serial, + le16_to_cpu(setup->index) & 0xff); + + endpoint_unstall(ep); + endpoint_reset_datatoggle(ep); + } else + endpoint_stall(&serial->ep_ctrl); + break; + } + break; + case USB_REQ_SET_FEATURE: + switch (setup->requesttype) { + case 0x00: // Device + if ((le16_to_cpu(setup->value) & 0xff) == 1) + serial->remote_wakeup_en = 1; + else + endpoint_stall(&serial->ep_ctrl); + break; + case 0x02: // End Point + if ((le16_to_cpu(setup->value) & 0xff) == 0) { + endpoint_t *ep = + epnum_to_ep(serial, + le16_to_cpu(setup->index) & 0xff); + + endpoint_stall(ep); + } else + endpoint_stall(&serial->ep_ctrl); + break; + } + break; + default: + endpoint_stall(&serial->ep_ctrl); // Stall End Point 0 + break; + } +} + + +/* + * A complete packet (SETUP, DATA0, or DATA1) has been received + * on the given endpoint's fifo. + */ +static void +process_complete (struct usb_serial* serial, int fifo_num) +{ + endpoint_t *ep = fifonum_to_ep(serial, fifo_num); + struct usb_serial_port *port = NULL; + pkt_t *pkt = 0; + u32 cs; + + cs = inl(ep->reg->ctrl_stat); + + switch (fifo_num) { + case 0: + spin_lock(&ep->lock); + // complete packet and prepare a new packet + receive_packet_complete(ep); + + // Get it immediately from endpoint. + if (!(pkt = receive_packet(ep))) { + spin_unlock(&ep->lock); + return; + } + + // SETUP packet received ? + //if (cs & USBDEV_CS_SU) { FIXME: uncomment! + if (pkt->size == sizeof(devrequest)) { + devrequest setup; + if ((cs & (USBDEV_CS_NAK | USBDEV_CS_ACK)) == + USBDEV_CS_ACK) + dbg("got SETUP"); + else + dbg("got NAK SETUP, cs=%08x", cs); + memcpy(&setup, pkt->bufptr, sizeof(devrequest)); + process_setup(serial, &setup); + //} else FIXME: uncomment! + //dbg(__FUNCTION__ ": wrong size SETUP received"); + } else { + // DATAx packet received on endpoint 0 + // FIXME: will need a state machine for control + // OUT transactions + dbg("got DATAx on EP0, size=%d, cs=%08x", + pkt->size, cs); + } + + spin_unlock(&ep->lock); + // we're done processing the packet, free it + kfree(pkt); + break; + + case 4: + case 5: + port = fifonum_to_port(serial, fifo_num); + dbg("got DATAx on port %d, cs=%08x", port->number, cs); + spin_lock(&ep->lock); + receive_packet_complete(ep); + spin_unlock(&ep->lock); + // mark a bh to push this data up to the tty + queue_task(&port->receive_complete_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + break; + + default: + break; + } +} + + + +// This ISR needs to ack both the complete and suspend events +static void +req_sus_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct usb_serial *serial = (struct usb_serial *) dev_id; + int i; + u32 status; + + status = inl(USB_DEV_INT_STATUS); + outl_sync(status, USB_DEV_INT_STATUS); // ack'em + +#ifdef USBDEV_PIO + for (i = 0; i < 6; i++) { + if (status & (1 << (USBDEV_INT_HF_BIT + i))) { + endpoint_t *ep = fifonum_to_ep(serial, i); + + if (ep->desc->bEndpointAddress & USB_DIR_IN) + endpoint_fifo_write(ep); + else + endpoint_fifo_read(ep); + } + } +#endif + + for (i = 0; i < 6; i++) { + if (status & (1 << i)) + process_complete(serial, i); + } +} + + +static void +dma_done_ctrl(struct usb_serial* serial) +{ + endpoint_t *ep = &serial->ep_ctrl; + u32 cs0, buff_done; + + spin_lock(&ep->lock); + cs0 = inl(ep->reg->ctrl_stat); + + // first check packet transmit done + if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) { + // transmitted a DATAx packet on control endpoint 0 + // clear DMA done bit + if (buff_done == DMA_D0) + clear_dma_done0(ep->indma); + else + clear_dma_done1(ep->indma); + + send_packet_complete(ep); + } + + /* + * Now check packet receive done. Shouldn't get these, + * the receive packet complete intr should happen + * before the DMA done intr occurs. + */ + if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) { + // clear DMA done bit + if (buff_done == DMA_D0) + clear_dma_done0(ep->outdma); + else + clear_dma_done1(ep->outdma); + } + + spin_unlock(&ep->lock); +} + +static void +dma_done_port(struct usb_serial_port * port) +{ + endpoint_t *ep; + u32 buff_done; + + // first check packet transmit done (bulk IN ep) + ep = &port->ep_bulkin; + spin_lock(&ep->lock); + if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) { + // transmitted a DATAx packet on the port's bulk IN endpoint + // clear DMA done bit + if (buff_done == DMA_D0) + clear_dma_done0(ep->indma); + else + clear_dma_done1(ep->indma); + + send_packet_complete(ep); + // mark a bh to wakeup any tty write system call on the port. + queue_task(&port->send_complete_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + spin_unlock(&ep->lock); + + /* + * Now check packet receive done (bulk OUT ep). Shouldn't + * get these, the receive packet complete intr should happen + * before the DMA done intr occurs. + */ + ep = &port->ep_bulkout; + spin_lock(&ep->lock); + if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) { + // received a DATAx packet on the port's bulk OUT endpoint + // clear DMA done bit + if (buff_done == DMA_D0) + clear_dma_done0(ep->outdma); + else + clear_dma_done1(ep->outdma); + } + spin_unlock(&ep->lock); +} + + +// This ISR needs to handle dma done events for ALL endpoints! +static void +dma_done_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct usb_serial *serial = (struct usb_serial *) dev_id; + int i; + + dma_done_ctrl(serial); + for (i = 0; i < NUM_PORTS; i++) + dma_done_port(&serial->port[i]); +} + + + +/***************************************************************************** + * Here begins the tty driver interface functions + *****************************************************************************/ + +static int serial_open(struct tty_struct *tty, struct file *filp) +{ + int portNumber; + struct usb_serial_port *port; + struct usb_serial *serial = &usbserial; + unsigned long flags; + + /* initialize the pointer incase something fails */ + tty->driver_data = NULL; + + MOD_INC_USE_COUNT; + + /* set up our port structure making the tty driver remember + our port object, and us it */ + portNumber = MINOR(tty->device) - serial->minor; + port = &serial->port[portNumber]; + tty->driver_data = port; + port->tty = tty; + + if (port_paranoia_check(port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave(&port->port_lock, flags); + + ++port->open_count; + + if (!port->active) { + port->active = 1; + + /* + * force low_latency on so that our tty_push actually forces + * the data through, otherwise it is scheduled, and with high + * data rates (like with OHCI) data can get lost. + */ + port->tty->low_latency = 1; + + } + + spin_unlock_irqrestore(&port->port_lock, flags); + + return 0; +} + + +static void serial_close(struct tty_struct *tty, struct file *filp) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + unsigned long flags; + + if (!serial) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!port->active) { + dbg(__FUNCTION__ " - port not opened"); + return; + } + + spin_lock_irqsave(&port->port_lock, flags); + + --port->open_count; + + if (port->open_count <= 0) { + port->active = 0; + port->open_count = 0; + } + + spin_unlock_irqrestore(&port->port_lock, flags); + MOD_DEC_USE_COUNT; +} + + +static int serial_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + endpoint_t *ep = &port->ep_bulkin; + + if (!serial) + return -ENODEV; + + if (!port->active) { + dbg(__FUNCTION__ " - port not opened"); + return -EINVAL; + } + + if (count == 0) { + dbg(__FUNCTION__ " - write request of 0 bytes"); + return (0); + } + + count = (count > ep->max_pkt_size) ? ep->max_pkt_size : count; + send_packet(ep, (u8 *) buf, count, from_user); + + return (count); +} + + +static int serial_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + endpoint_t *ep = &port->ep_bulkin; + + if (!serial) + return -ENODEV; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return -EINVAL; + } + + return ep->max_pkt_size; +} + + +static int serial_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + endpoint_t *ep = &port->ep_bulkin; + pkt_list_t *list = &ep->inlist; + pkt_t *scan; + unsigned long flags; + int chars = 0; + + if (!serial) + return -ENODEV; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return -EINVAL; + } + + spin_lock_irqsave(&ep->lock, flags); + for (scan = list->head; scan; scan = scan->next) + chars += scan->size; + spin_unlock_irqrestore(&ep->lock, flags); + + return (chars); +} + + +static void serial_throttle(struct tty_struct *tty) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + + if (!serial) + return; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return; + } + // FIXME: anything to do? +} + + +static void serial_unthrottle(struct tty_struct *tty) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + + if (!serial) + return; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return; + } + // FIXME: anything to do? +} + + +static int serial_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + + if (!serial) + return -ENODEV; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return -ENODEV; + } + // FIXME: need any IOCTLs? + + return -ENOIOCTLCMD; +} + + +static void serial_set_termios(struct tty_struct *tty, struct termios *old) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + + if (!serial) + return; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return; + } + // FIXME: anything to do? +} + + +static void serial_break(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = + (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + + if (!serial) + return; + + if (!port->active) { + dbg(__FUNCTION__ " - port not open"); + return; + } + // FIXME: anything to do? +} + + +static void port_send_complete(void *private) +{ + struct usb_serial_port *port = (struct usb_serial_port *) private; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + struct tty_struct *tty; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + return; + } + + tty = port->tty; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) { + dbg(__FUNCTION__ " - write wakeup call."); + (tty->ldisc.write_wakeup) (tty); + } + + wake_up_interruptible(&tty->write_wait); +} + + +static void port_receive_complete(void *private) +{ + struct usb_serial_port *port = (struct usb_serial_port *) private; + struct usb_serial *serial = get_usb_serial(port, __FUNCTION__); + struct tty_struct *tty = port->tty; + pkt_t *pkt; + int i; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + return; + } + + if (!(pkt = receive_packet(&port->ep_bulkout))) + return; + + for (i = 0; i < pkt->size; i++) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, + we drop them. */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through + unless tty->low_latency is set */ + tty_insert_flip_char(tty, pkt->bufptr[i], 0); + } + tty_flip_buffer_push(tty); + + // we're done processing the packet, free it + kfree(pkt); +} + + +static struct tty_driver serial_tty_driver = { + magic:TTY_DRIVER_MAGIC, + driver_name:"usbdev-serial", + name:"usb/ttsdev/%d", + major:SERIAL_TTY_MAJOR, + minor_start:0, + num:1, + type:TTY_DRIVER_TYPE_SERIAL, + subtype:SERIAL_TYPE_NORMAL, + flags:TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, + refcount:&serial_refcount, + table:serial_tty, + termios:serial_termios, + termios_locked:serial_termios_locked, + + open:serial_open, + close:serial_close, + write:serial_write, + write_room:serial_write_room, + ioctl:serial_ioctl, + set_termios:serial_set_termios, + throttle:serial_throttle, + unthrottle:serial_unthrottle, + break_ctl:serial_break, + chars_in_buffer:serial_chars_in_buffer, +}; + + +void usbdev_serial_exit(void) +{ + endpoint_t *ep; + int i; + + outl_sync(0, USB_DEV_INT_ENABLE); // disable usb dev ints + outl_sync(0, USB_DEV_ENABLE); // disable usb dev + + // first free all control endpoint resources + ep = &usbserial.ep_ctrl; + free_irq(AU1000_USB_DEV_REQ_INT, &usbserial); + free_irq(AU1000_USB_DEV_SUS_INT, &usbserial); + free_irq(ep->inirq, &usbserial); + //free_irq(ep->outirq, &usbserial); + free_au1000_dma(ep->indma); + free_au1000_dma(ep->outdma); + endpoint_flush(ep); + + // now free all port resources + for (i = 0; i < NUM_PORTS; i++) { + // free port's bulk IN endpoint resources + ep = &usbserial.port[i].ep_bulkin; + free_irq(ep->inirq, &usbserial); + free_au1000_dma(ep->indma); + endpoint_flush(ep); + + // free port's bulk OUT endpoint resources + ep = &usbserial.port[i].ep_bulkout; + //free_irq(ep->outirq, &usbserial); + free_au1000_dma(ep->outdma); + endpoint_flush(ep); + + tty_unregister_devfs(&serial_tty_driver, i); + info("usbdev serial converter now disconnected from ttyUSBdev%d", + i); + } + + kfree(usbserial.str_desc[0]); + tty_unregister_driver(&serial_tty_driver); +} + +int usbdev_serial_init(void) +{ + struct usb_serial_port *port; + endpoint_t *ep; + void *str_desc_buf; + int str_desc_len; + int i; + + /* register the tty driver */ + serial_tty_driver.init_termios = tty_std_termios; + serial_tty_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + + if (tty_register_driver(&serial_tty_driver)) { + err(__FUNCTION__ ": failed to register tty driver"); + return -1; + } + + memset(&usbserial, 0, sizeof(struct usb_serial)); + usbserial.minor = 0; + + usbserial.state = DEFAULT; + + usbserial.dev_desc = &dev_desc; + usbserial.if_desc = &if_desc; + usbserial.conf_desc = &config_desc; + + /* + * initialize the string descriptors + */ + + /* alloc buffer big enough for all string descriptors */ + str_desc_len = string_desc0.bLength; + for (i = 0; i < 5; i++) + str_desc_len += 2 + 2 * strlen(strings[i]); + str_desc_buf = (void *) kmalloc(str_desc_len, ALLOC_FLAGS); + if (!str_desc_buf) { + err(__FUNCTION__ ": failed to alloc string descriptors"); + return -1; + } + + usbserial.str_desc[0] = (struct usb_string_descriptor *)str_desc_buf; + memcpy(usbserial.str_desc[0], &string_desc0, string_desc0.bLength); + usbserial.str_desc[1] = (struct usb_string_descriptor *) + (str_desc_buf + string_desc0.bLength); + for (i = 1; i < 6; i++) { + struct usb_string_descriptor *desc = usbserial.str_desc[i]; + char *str = strings[i - 1]; + int j, str_len = strlen(str); + + desc->bLength = 2 + 2 * str_len; + desc->bDescriptorType = USB_DT_STRING; + for (j = 0; j < str_len; j++) { + desc->wData[j] = (u16) str[j]; + } + if (i < 5) + usbserial.str_desc[i + 1] = + (struct usb_string_descriptor *) + ((u8 *) desc + desc->bLength); + } + + // request the USB device transfer complete interrupt + if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_SHIRQ, + "USBdev req", &usbserial)) { + err("Can't get device request intr\n"); + goto err_out; + } + // request the USB device suspend interrupt + if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_SHIRQ, + "USBdev sus", &usbserial)) { + err("Can't get device suspend intr\n"); + goto err_out; + } + + // Initialize default control endpoint + ep = &usbserial.ep_ctrl; + spin_lock_init(&ep->lock); + ep->desc = NULL; // ep0 has no ep descriptor + ep->reg = &ep_reg[0]; + ep->max_pkt_size = usbserial.dev_desc->bMaxPacketSize0; + ep->indma = ep->outdma = -1; + if ((ep->indma = request_au1000_dma(ep_dma_id[0].id, + ep_dma_id[0].str)) < 0) { + err("Can't get %s DMA\n", ep_dma_id[0].str); + goto err_out; + } + if ((ep->outdma = request_au1000_dma(ep_dma_id[1].id, + ep_dma_id[1].str)) < 0) { + err("Can't get %s DMA\n", ep_dma_id[1].str); + goto err_out; + } + ep->inirq = get_dma_done_irq(ep->indma); + ep->outirq = get_dma_done_irq(ep->outdma); + // allocate EP0's DMA done interrupts. + if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT, + "USBdev ep0 IN", &usbserial)) { + err("Can't get ep0 IN dma done irq\n"); + goto err_out; + } +#if 0 + if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT, + "USBdev ep0 OUT", &usbserial)) { + err("Can't get ep0 OUT dma done irq\n"); + goto err_out; + } +#endif + + /* initialize the devfs nodes for this device and let the user + know what ports we are bound to */ + for (i = 0; i < NUM_PORTS; ++i) { + tty_register_devfs(&serial_tty_driver, 0, i); + info("usbdev serial attached to ttyUSBdev%d (or devfs usb/ttsdev/%d)", + i, i); + port = &usbserial.port[i]; + port->serial = &usbserial; + port->number = i; + port->send_complete_tq.routine = port_send_complete; + port->send_complete_tq.data = port; + port->receive_complete_tq.routine = port_receive_complete; + port->receive_complete_tq.data = port; + spin_lock_init(&port->port_lock); + + // Initialize the port's bulk IN endpoint + ep = &port->ep_bulkin; + spin_lock_init(&ep->lock); + ep->desc = &ep_desc[NUM_PORTS * i]; + ep->reg = &ep_reg[1 + NUM_PORTS * i]; + ep->max_pkt_size = ep->desc->wMaxPacketSize; + ep->indma = ep->outdma = -1; + if ((ep->indma = + request_au1000_dma(ep_dma_id[2+NUM_PORTS*i].id, + ep_dma_id[2 + NUM_PORTS * i].str)) < 0) { + err("Can't get %s DMA\n", + ep_dma_id[2 + NUM_PORTS * i].str); + goto err_out; + } + ep->inirq = get_dma_done_irq(ep->indma); + if (request_irq(ep->inirq, dma_done_intr, SA_INTERRUPT, + "USBdev bulk IN", &usbserial)) { + err("Can't get port %d bulk IN dma done irq\n", i); + goto err_out; + } + // Initialize the port's bulk OUT endpoint + ep = &port->ep_bulkout; + spin_lock_init(&ep->lock); + ep->desc = &ep_desc[NUM_PORTS * i + 1]; + ep->reg = &ep_reg[1 + NUM_PORTS * i + 1]; + ep->max_pkt_size = ep->desc->wMaxPacketSize; + ep->indma = ep->outdma = -1; + if ((ep->outdma = + request_au1000_dma(ep_dma_id[2+NUM_PORTS*i + 1].id, + ep_dma_id[2+NUM_PORTS*i + 1].str)) < 0) { + err("Can't get %s DMA\n", + ep_dma_id[2 + NUM_PORTS * i + 1].str); + goto err_out; + } + ep->outirq = get_dma_done_irq(ep->outdma); +#if 0 + if (request_irq(ep->outirq, dma_done_intr, SA_INTERRUPT, + "USBdev bulk OUT", &usbserial)) { + err("Can't get port %d bulk OUT dma done irq\n", i); + goto err_out; + } +#endif + } + + // enable device controller + outl_sync(0x0002, USB_DEV_ENABLE); + udelay(100); + outl_sync(0x0003, USB_DEV_ENABLE); + udelay(100); + for (i = 0; i < sizeof(au1000_config_table) / sizeof(u32); ++i) + outl_sync(au1000_config_table[i], USB_DEV_CONFIG); + + // Flush the endpoint buffers and FIFOs + ep = &usbserial.ep_ctrl; + endpoint_flush(ep); + // start packet reception on control ep + kickstart_receive_packet(ep); + + for (i = 0; i < NUM_PORTS; ++i) { + struct usb_serial_port *port = &usbserial.port[i]; + endpoint_flush(&port->ep_bulkin); + endpoint_flush(&port->ep_bulkout); + // start packet reception on bulk OUT endpoint + kickstart_receive_packet(&port->ep_bulkout); + } + + /* + * Enable Receive FIFO Complete interrupts only. Transmit + * complete is being handled by the DMA done interrupts. + */ + outl_sync(0x31, USB_DEV_INT_ENABLE); + + return 0; + + err_out: + usbdev_serial_exit(); + return -1; +} + + +module_init(usbdev_serial_init); +module_exit(usbdev_serial_exit); diff -urN linux-2.4.18/arch/mips/au1000/pb1000/Makefile linux-2.4.19-pre5/arch/mips/au1000/pb1000/Makefile --- linux-2.4.18/arch/mips/au1000/pb1000/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1000/Makefile Sat Mar 30 22:55:26 2002 @@ -15,10 +15,10 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -all: pb1000.o - O_TARGET := pb1000.o obj-y := init.o setup.o + +obj-$(CONFIG_PCI) += pci_fixup.o pci_ops.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/au1000/pb1000/init.c linux-2.4.19-pre5/arch/mips/au1000/pb1000/init.c --- linux-2.4.18/arch/mips/au1000/pb1000/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1000/init.c Sat Mar 30 22:55:26 2002 @@ -27,6 +27,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include @@ -38,12 +39,21 @@ #include #include -extern int prom_argc; -extern char **prom_argv, **prom_envp; +int prom_argc; +char **prom_argv, **prom_envp; extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); + +const char *get_system_type(void) +{ + return "Alchemy Pb1000"; +} int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { + unsigned char *memsize_str; + unsigned long memsize; + prom_argc = argc; prom_argv = argv; prom_envp = envp; @@ -52,8 +62,12 @@ mips_machtype = MACH_PB1000; prom_init_cmdline(); - - add_memory_region(1, 64 << 20, BOOT_MEM_RAM); - + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + memsize = 0x04000000; + } else { + memsize = simple_strtol(memsize_str, NULL, 0); + } + add_memory_region(0, memsize, BOOT_MEM_RAM); return 0; } diff -urN linux-2.4.18/arch/mips/au1000/pb1000/pci_fixup.c linux-2.4.19-pre5/arch/mips/au1000/pb1000/pci_fixup.c --- linux-2.4.18/arch/mips/au1000/pb1000/pci_fixup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1000/pci_fixup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,90 @@ +/* + * BRIEF MODULE DESCRIPTION + * Board specific pci fixups. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ + /* will need to fixup IO resources */ +} + +void __init pcibios_fixup(void) +{ + unsigned long pci_mem_start = (unsigned long) PCI_MEM_START; + + writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0 + writel(0, SDRAM_MBAR); // set mbar to 0 + writel(0x2, SDRAM_CMD); // enable memory accesses + au_sync_delay(1); + + // set extend byte to mbar of ext slot + writel(((pci_mem_start >> 24) & 0xff) | + (1 << 8 | 1 << 9 | 1 << 10 | 1 << 27), PCI_BRIDGE_CONFIG); + DBG("Set bridge config to %x\n", readl(PCI_BRIDGE_CONFIG)); +} + +void __init pcibios_fixup_irqs(void) +{ + unsigned int slot, func; + unsigned char pin; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (dev->bus->number != 0) + return; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + slot = PCI_SLOT(dev->devfn); + func = PCI_FUNC(dev->devfn); + dev->irq = AU1000_GPIO_15; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + DBG("slot %d func %d irq %d\n", slot, func, dev->irq); + } +} +unsigned int pcibios_assign_all_busses(void) +{ + return 0; +} +#endif diff -urN linux-2.4.18/arch/mips/au1000/pb1000/pci_ops.c linux-2.4.19-pre5/arch/mips/au1000/pb1000/pci_ops.c --- linux-2.4.18/arch/mips/au1000/pb1000/pci_ops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1000/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,200 @@ +/* + * BRIEF MODULE DESCRIPTION + * PB1000 specific pci support. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct resource pci_io_resource = { + "pci IO space", + PCI_IO_START, + PCI_IO_END, + IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + "pci memory space", + PCI_MEM_START, + PCI_MEM_END, + IORESOURCE_MEM +}; + +extern struct pci_ops pb1000_pci_ops; + +struct pci_channel mips_pci_channels[] = { + {&pb1000_pci_ops, &pci_io_resource, &pci_mem_resource, 0, 1}, + {(struct pci_ops *) NULL, (struct resource *) NULL, + (struct resource *) NULL, (int) NULL, (int) NULL} +}; + + +/* + * "Bus 2" is really the first and only external slot on the pb1000. + * We'll call that bus 0, and limit the accesses to that single + * external slot only. The SDRAM is already initialized in setup.c. + */ +static int config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 * data) +{ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + unsigned long config; + + if (((dev_fn >> 3) != 0) || (bus != 0)) { + *data = 0xffffffff; + return -1; + } + + config = PCI_CONFIG_BASE | (where & ~0x3); + + if (access_type == PCI_ACCESS_WRITE) { + outl(*data, config); + } else { + *data = inl(config); + } + au_sync_udelay(1); + + DBG("config_access: %d bus %d dev_fn %x at %x *data %x, conf %x\n", + access_type, bus, dev_fn, where, *data, config); + + DBG("bridge config reg: %x (%x)\n", inl(PCI_BRIDGE_CONFIG), *data); + + if (inl(PCI_BRIDGE_CONFIG) & (1 << 16)) { + *data = 0xffffffff; + return -1; + } else { + return PCIBIOS_SUCCESSFUL; + } +} + + +static int read_config_byte(struct pci_dev *dev, int where, u8 * val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, &data); + *val = data & 0xff; + return ret; +} + + +static int read_config_word(struct pci_dev *dev, int where, u16 * val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, &data); + *val = data & 0xffff; + return ret; +} + +static int read_config_dword(struct pci_dev *dev, int where, u32 * val) +{ + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, val); + return ret; +} + + +static int write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_word(struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops pb1000_pci_ops = { + read_config_byte, + read_config_word, + read_config_dword, + write_config_byte, + write_config_word, + write_config_dword +}; +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/au1000/pb1000/setup.c linux-2.4.19-pre5/arch/mips/au1000/pb1000/setup.c --- linux-2.4.18/arch/mips/au1000/pb1000/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1000/setup.c Sat Mar 30 22:55:26 2002 @@ -1,7 +1,7 @@ /* * * BRIEF MODULE DESCRIPTION - * Au1000-based board setup. + * Alchemy Pb1000 board setup. * * Copyright 2000 MontaVista Software Inc. * Author: MontaVista Software, Inc. @@ -31,45 +31,51 @@ #include #include #include +#include #include #include +#include #include #include #include +#include #include #include +#include #include +#include + +#ifdef CONFIG_USB_OHCI +// Enable the workaround for the OHCI DoneHead +// register corruption problem. +#define CONFIG_AU1000_OHCI_FIX +#endif #if defined(CONFIG_AU1000_SERIAL_CONSOLE) extern void console_setup(char *, int *); char serial_console[20]; #endif +#ifdef CONFIG_BLK_DEV_INITRD +extern unsigned long initrd_start, initrd_end; +extern void * __rd_start, * __rd_end; +#endif + +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +extern struct ide_ops *ide_ops; +#endif + void (*__wbflush) (void); extern struct rtc_ops no_rtc_ops; extern char * __init prom_getcmdline(void); -extern void au1000_restart(void); +extern void au1000_restart(char *); extern void au1000_halt(void); extern void au1000_power_off(void); +extern struct resource ioport_resource; +extern struct resource iomem_resource; -struct { - struct resource ram; - struct resource io; - struct resource sram; - struct resource flash; - struct resource boot; - struct resource pcmcia; - struct resource lcd; -} au1000_resources = { - { "RAM", 0, 0x3FFFFFF, IORESOURCE_MEM }, - { "I/O", 0x10000000, 0x119FFFFF }, - { "SRAM", 0x1e000000, 0x1E03FFFF }, - { "System Flash", 0x1F800000, 0x1FBFFFFF }, - { "Boot ROM", 0x1FC00000, 0x1FFFFFFF }, - { "PCMCIA", 0x20000000, 0x27FFFFFF }, - { "LCD", 0x60000000, 0x603FFFFF }, -}; void au1000_wbflush(void) { @@ -79,39 +85,223 @@ void __init au1000_setup(void) { char *argptr; - + u32 pin_func, static_cfg0; + u32 sys_freqctrl, sys_clksrc; + u32 prid = read_32bit_cp0_register(CP0_PRID); + argptr = prom_getcmdline(); + /* Various early Au1000 Errata corrected by this */ + set_cp0_config(1<<19); /* Config[OD] */ + #ifdef CONFIG_AU1000_SERIAL_CONSOLE - if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { + if ((argptr = strstr(argptr, "console=")) == NULL) { argptr = prom_getcmdline(); strcat(argptr, " console=ttyS0,115200"); } #endif - //set_cp0_status(ST0_FR,0); rtc_ops = &no_rtc_ops; __wbflush = au1000_wbflush; _machine_restart = au1000_restart; _machine_halt = au1000_halt; _machine_power_off = au1000_power_off; - /* - * IO/MEM resources. - */ - mips_io_port_base = KSEG1; - ioport_resource.start = au1000_resources.io.start; - ioport_resource.end = au1000_resources.lcd.end; + // IO/MEM resources. + set_io_port_base(0); + ioport_resource.start = 0x10000000; + ioport_resource.end = 0xffffffff; + iomem_resource.start = 0x10000000; + iomem_resource.end = 0xffffffff; #ifdef CONFIG_BLK_DEV_INITRD ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_start = (unsigned long)&__rd_start; + initrd_end = (unsigned long)&__rd_end; #endif - outl(PC_CNTRL_E0 | PC_CNTRL_EN0 | PC_CNTRL_EN0, PC_COUNTER_CNTRL); - while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T0S); - outl(0x8000-1, PC0_TRIM); + // set AUX clock to 12MHz * 8 = 96 MHz + outl(8, SYS_AUXPLL); + outl(0, SYS_PINSTATERD); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE) +#ifdef CONFIG_USB_OHCI + if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) { + char usb_args[80]; + argptr = prom_getcmdline(); + memset(usb_args, 0, sizeof(usb_args)); + sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d", + USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT); + strcat(argptr, usb_args); + } +#endif - printk("Alchemy Semi PB1000 Board\n"); - printk("Au1000/PB1000 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); -} + /* zero and disable FREQ2 */ + sys_freqctrl = inl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + outl(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD clocks */ + sys_clksrc = inl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + outl(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = inl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = inl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + + switch (prid & 0x000000FF) + { + case 0x00: /* DA */ + case 0x01: /* HA */ + case 0x02: /* HB */ + /* CPU core freq to 48MHz to slow it way down... */ + outl(4, SYS_CPUPLL); + + /* + * Setup 48MHz FREQ2 from CPUPLL for USB Host + */ + /* FRDIV2=3 -> div by 8 of 384MHz -> 48MHz */ + sys_freqctrl |= ((3<<22) | (1<<21) | (0<<20)); + outl(sys_freqctrl, SYS_FREQCTRL0); + + /* CPU core freq to 384MHz */ + outl(0x20, SYS_CPUPLL); + + printk("Au1000: 48MHz OHCI workaround enabled\n"); + break; + + default: /* HC and newer */ + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + outl(sys_freqctrl, SYS_FREQCTRL0); + break; + } + /* + * Route 48MHz FREQ2 into USB Host and/or Device + */ +#ifdef CONFIG_USB_OHCI + sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); +#endif +#ifdef CONFIG_AU1000_USB_DEVICE + sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); +#endif + outl(sys_clksrc, SYS_CLKSRC); + +#ifdef CONFIG_USB_OHCI + // enable host controller and wait for reset done + outl(0x08, USB_HOST_CONFIG); + udelay(1000); + outl(0x0E, USB_HOST_CONFIG); + udelay(1000); + inl(USB_HOST_CONFIG); // throw away first read + while (!(inl(USB_HOST_CONFIG) & 0x10)) + inl(USB_HOST_CONFIG); +#endif + + // configure pins GPIO[14:9] as GPIO + pin_func = inl(SYS_PINFUNC) & (u32)(~0x8080); + +#ifndef CONFIG_AU1000_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + outl(pin_func, SYS_PINFUNC); + outl(0x2800, SYS_TRIOUTCLR); + outl(0x0030, SYS_OUTPUTCLR); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE) + + // make gpio 15 an input (for interrupt line) + pin_func = inl(SYS_PINFUNC) & (u32)(~0x100); + // we don't need I2S, so make it available for GPIO[31:29] + pin_func |= (1<<5); + outl(pin_func, SYS_PINFUNC); + + outl(0x8000, SYS_TRIOUTCLR); + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + static_cfg0 = inl(MEM_STCFG0) & (u32)(~0xc00); + outl(static_cfg0, MEM_STCFG0); + + // configure RCE2* for LCD + outl(0x00000004, MEM_STCFG2); + + // MEM_STTIME2 + outl(0x09000000, MEM_STTIME2); + + // Set 32-bit base address decoding for RCE2* + outl(0x10003ff0, MEM_STADDR2); + + // PCI CPLD setup + // expand CE0 to cover PCI + outl(0x11803e40, MEM_STADDR1); + + // burst visibility on + outl(inl(MEM_STCFG0) | 0x1000, MEM_STCFG0); + + outl(0x83, MEM_STCFG1); // ewait enabled, flash timing + outl(0x33030a10, MEM_STTIME1); // slower timing for FPGA + +#ifdef CONFIG_FB_E1356 + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=e1356fb:system:pb1000,mmunalign:1"); + } +#endif // CONFIG_FB_E1356 + + +#ifdef CONFIG_PCI + outl(0, PCI_BRIDGE_CONFIG); // set extend byte to 0 + outl(0, SDRAM_MBAR); // set mbar to 0 + outl(0x2, SDRAM_CMD); // enable memory accesses + au_sync_delay(1); +#endif + +#ifndef CONFIG_SERIAL_NONSTANDARD + /* don't touch the default serial console */ + outl(0, UART0_ADDR + UART_CLK); +#endif + outl(0, UART1_ADDR + UART_CLK); + outl(0, UART2_ADDR + UART_CLK); + outl(0, UART3_ADDR + UART_CLK); + +#ifdef CONFIG_BLK_DEV_IDE + { + argptr = prom_getcmdline(); + strcat(argptr, " ide0=noprobe"); + } + ide_ops = &std_ide_ops; +#endif + + // setup irda clocks + // aux clock, divide by 2, clock from 2/4 divider + writel(readl(SYS_CLKSRC) | 0x7, SYS_CLKSRC); + pin_func = inl(SYS_PINFUNC) & (u32)(~(1<<2)); // clear IRTXD + outl(pin_func, SYS_PINFUNC); + + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S); + outl(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL); + au_sync(); + while (inl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S); + outl(0, SYS_TOYTRIM); + + /* Enable Au1000 BCLK switching - note: sed1356 must not use + * its BCLK (Au1000 LCLK) for any timings */ + switch (prid & 0x000000FF) + { + case 0x00: /* DA */ + case 0x01: /* HA */ + case 0x02: /* HB */ + break; + default: /* HC and newer */ + outl(0x00000060, 0xb190003c); + break; + } +} diff -urN linux-2.4.18/arch/mips/au1000/pb1500/Makefile linux-2.4.19-pre5/arch/mips/au1000/pb1500/Makefile --- linux-2.4.18/arch/mips/au1000/pb1500/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1500/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,24 @@ +# +# Copyright 2000,2001 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor Pb1500 board. +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := pb1500.o + +obj-y := init.o setup.o + +obj-$(CONFIG_PCI) += pci_fixup.o pci_ops.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/au1000/pb1500/init.c linux-2.4.19-pre5/arch/mips/au1000/pb1500/init.c --- linux-2.4.18/arch/mips/au1000/pb1500/init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1500/init.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,73 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PB1500 board setup + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int prom_argc; +char **prom_argv, **prom_envp; +extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); + +const char *get_system_type(void) +{ + return "Alchemy Pb1500"; +} + +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_PB1500; + + prom_init_cmdline(); + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + memsize = 0x04000000; + } else { + memsize = simple_strtol(memsize_str, NULL, 0); + } + add_memory_region(0, memsize, BOOT_MEM_RAM); + return 0; +} diff -urN linux-2.4.18/arch/mips/au1000/pb1500/pci_fixup.c linux-2.4.19-pre5/arch/mips/au1000/pb1500/pci_fixup.c --- linux-2.4.18/arch/mips/au1000/pb1500/pci_fixup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1500/pci_fixup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,119 @@ +/* + * BRIEF MODULE DESCRIPTION + * Board specific pci fixups. + * + * Copyright 2001,2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static void fixup_resource(int r_num, struct pci_dev *dev) ; +static unsigned long virt_io_addr; + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ + /* will need to fixup IO resources */ +} + +void __init pcibios_fixup(void) +{ + int i; + struct pci_dev *dev; + + virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, + Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1); + + if (!virt_io_addr) { + printk(KERN_ERR "Unable to ioremap pci space\n"); + return; + } + + pci_for_each_dev(dev) { + for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { + if (dev->resource[i].start) { + fixup_resource(i, dev); + } + } + } +} + +void __init pcibios_fixup_irqs(void) +{ + unsigned int slot, func; + unsigned char pin; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (dev->bus->number != 0) + return; + + dev->irq = 0xff; + slot = PCI_SLOT(dev->devfn); + switch (slot) { + case 12: + case 13: + dev->irq = AU1000_PCI_INTA; + break; + + } + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + DBG("slot %d irq %d\n", slot, dev->irq); + } +} +unsigned int pcibios_assign_all_busses(void) +{ + return 0; +} + +static void fixup_resource(int r_num, struct pci_dev *dev) +{ + unsigned long start, size, new_start; + + if (dev->resource[r_num].flags & IORESOURCE_IO) { + start = dev->resource[r_num].start; + size = dev->resource[r_num].end - start; + new_start = virt_io_addr + (start - Au1500_PCI_IO_START); + dev->resource[r_num].start = new_start; + dev->resource[r_num].end = new_start + size; + } +} + +#endif diff -urN linux-2.4.18/arch/mips/au1000/pb1500/pci_ops.c linux-2.4.19-pre5/arch/mips/au1000/pb1500/pci_ops.c --- linux-2.4.18/arch/mips/au1000/pb1500/pci_ops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1500/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,241 @@ +/* + * BRIEF MODULE DESCRIPTION + * Pb1500 specific pci support. + * + * Copyright 2001,2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* TBD */ +static struct resource pci_io_resource = { + "pci IO space", + Au1500_PCI_IO_START, + Au1500_PCI_IO_END, + IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + "pci memory space", + Au1500_PCI_MEM_START, + Au1500_PCI_MEM_END, + IORESOURCE_MEM +}; + +extern struct pci_ops pb1500_pci_ops; + +struct pci_channel mips_pci_channels[] = { + {&pb1500_pci_ops, &pci_io_resource, &pci_mem_resource, (10<<3),(16<<3)}, + {(struct pci_ops *) NULL, (struct resource *) NULL, + (struct resource *) NULL, (int) NULL, (int) NULL} +}; + +static unsigned long cfg_addr; +static int config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 * data) +{ + unsigned char bus = dev->bus->number; + unsigned int dev_fn = dev->devfn; + unsigned int device, function; + unsigned long config, status; + static int first = 1; + + /* + * 7:3 = slot + * 2:0 = function + */ + + if (bus != 0) { + *data = 0xffffffff; + return -1; + } + + if (first) { + first = 0; + cfg_addr = ioremap(Au1500_EXT_CFG, 0x10000000); + if (!cfg_addr) + printk (KERN_ERR "PCI unable to ioremap cfg space\n"); + } + + device = (dev_fn >> 3) & 0x1f; + function = dev_fn & 0x7; + +#if 1 + //if (!cfg_addr || (device < 10) || (device > 16)) { + if (!cfg_addr || (device > 16)) { + *data = 0xffffffff; + return -1; + } +#endif + + writel(((0x2000 << 16) | (readl(Au1500_PCI_STATCMD) & 0xffff)), + Au1500_PCI_STATCMD); + //writel(readl(Au1500_PCI_CFG) & ~PCI_ERROR, Au1500_PCI_CFG); + au_sync_udelay(1); + + /* setup the lower 31 bits of the 36 bit address */ + config = cfg_addr | + ((1<> 28) & 0xf) { + DBG("PCI ERR detected: status %x\n", status); + *data = 0xffffffff; + return -1; + } + else { + return PCIBIOS_SUCCESSFUL; + } +} + + +static int read_config_byte(struct pci_dev *dev, int where, u8 * val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, &data); + if (where & 1) data >>= 8; + if (where & 2) data >>= 16; + *val = data & 0xff; + return ret; +} + + +static int read_config_word(struct pci_dev *dev, int where, u16 * val) +{ + u32 data; + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, &data); + if (where & 2) data >>= 16; + *val = data & 0xffff; + return ret; +} + +static int read_config_dword(struct pci_dev *dev, int where, u32 * val) +{ + int ret; + + ret = config_access(PCI_ACCESS_READ, dev, where, val); + return ret; +} + + +static int write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_word(struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops pb1500_pci_ops = { + read_config_byte, + read_config_word, + read_config_dword, + write_config_byte, + write_config_word, + write_config_dword +}; +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/au1000/pb1500/setup.c linux-2.4.19-pre5/arch/mips/au1000/pb1500/setup.c --- linux-2.4.18/arch/mips/au1000/pb1500/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/au1000/pb1500/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,256 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Alchemy Pb1000 board setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USB_OHCI +// Enable the workaround for the OHCI DoneHead +// register corruption problem. +#define CONFIG_AU1000_OHCI_FIX +#endif + +#if defined(CONFIG_AU1000_SERIAL_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD +extern unsigned long initrd_start, initrd_end; +extern void * __rd_start, * __rd_end; +#endif + +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops std_ide_ops; +extern struct ide_ops *ide_ops; +#endif + +#ifdef CONFIG_RTC +extern struct rtc_ops pb1500_rtc_ops; +#endif + +void (*__wbflush) (void); +extern char * __init prom_getcmdline(void); +extern void au1000_restart(char *); +extern void au1000_halt(void); +extern void au1000_power_off(void); +extern struct resource ioport_resource; +extern struct resource iomem_resource; + + +void au1500_wbflush(void) +{ + __asm__ volatile ("sync"); +} + +void __init au1500_setup(void) +{ + char *argptr; + u32 pin_func, static_cfg0; + u32 sys_freqctrl, sys_clksrc; + + argptr = prom_getcmdline(); + + /* NOTE: The memory map is established by YAMON 2.08+ */ + + /* Various early Au1500 Errata corrected by this */ + set_cp0_config(1<<19); /* Config[OD] */ + +#ifdef CONFIG_AU1000_SERIAL_CONSOLE + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS0,115200"); + } +#endif + +#ifdef CONFIG_SOUND_AU1000 + strcat(argptr, " au1000_audio=vra"); + argptr = prom_getcmdline(); +#endif + + __wbflush = au1500_wbflush; + _machine_restart = au1000_restart; + _machine_halt = au1000_halt; + _machine_power_off = au1000_power_off; + + // IO/MEM resources. + set_io_port_base(0); + ioport_resource.start = 0x10000000; + ioport_resource.end = 0xffffffff; + iomem_resource.start = 0x10000000; + iomem_resource.end = 0xffffffff; + +#ifdef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_start = (unsigned long)&__rd_start; + initrd_end = (unsigned long)&__rd_end; +#endif + + // set AUX clock to 12MHz * 8 = 96 MHz + writel(8, SYS_AUXPLL); + outl(0, SYS_PINSTATERD); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE) +#ifdef CONFIG_USB_OHCI + if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) { + char usb_args[80]; + argptr = prom_getcmdline(); + memset(usb_args, 0, sizeof(usb_args)); + sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d", + USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT); + strcat(argptr, usb_args); + } +#endif + + /* zero and disable FREQ2 */ + sys_freqctrl = readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD clocks */ + sys_clksrc = readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + writel(sys_freqctrl, SYS_FREQCTRL0); + + /* + * Route 48MHz FREQ2 into USB Host and/or Device + */ +#ifdef CONFIG_USB_OHCI + sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); +#endif +#ifdef CONFIG_AU1000_USB_DEVICE + sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); +#endif + writel(sys_clksrc, SYS_CLKSRC); + + + pin_func = readl(SYS_PINFUNC) & (u32)(~0x8000); +#ifndef CONFIG_AU1000_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + writel(pin_func, SYS_PINFUNC); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1000_USB_DEVICE) + + +#ifdef CONFIG_USB_OHCI + // enable host controller and wait for reset done + writel(0x08, USB_HOST_CONFIG); + udelay(1000); + writel(0x0c, USB_HOST_CONFIG); + udelay(1000); + readl(USB_HOST_CONFIG); + while (!(readl(USB_HOST_CONFIG) & 0x10)) + ; + readl(USB_HOST_CONFIG); +#endif + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + +#ifdef CONFIG_FB_E1356 + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=e1356fb:system:pb1500,mmunalign:1"); + } +#endif // CONFIG_FB_E1356 + +#ifndef CONFIG_SERIAL_NONSTANDARD + /* don't touch the default serial console */ + writel(0, UART0_ADDR + UART_CLK); +#endif + writel(0, UART3_ADDR + UART_CLK); + +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + +#ifdef CONFIG_PCI + // Setup PCI bus controller + writel(0, Au1500_PCI_CMEM); + writel(0x00003fff, Au1500_CFG_BASE); + writel(0xf, Au1500_PCI_CFG); + writel(0xf0000000, Au1500_PCI_MWMASK_DEV); + writel(0, Au1500_PCI_MWBASE_REV_CCL); + writel(0x02a00356, Au1500_PCI_STATCMD); + writel(0x00003c04, Au1500_PCI_HDRTYPE); + writel(0x00000008, Au1500_PCI_MBAR); + au_sync(); +#endif + + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S); + writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL); + au_sync(); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S); + outl(0, SYS_TOYTRIM); + + /* Enable BCLK switching */ + writel(0x00000060, 0xb190003c); + +#ifdef CONFIG_RTC + rtc_ops = &pb1500_rtc_ops; + // Enable the RTC if not already enabled + if (!(readb(0xac000028) & 0x20)) { + writeb(readb(0xac000028) | 0x20, 0xac000028); + } + // Put the clock in BCD mode + if (readb(0xac00002C) & 0x4) { /* reg B */ + writeb(readb(0xac00002c) & ~0x4, 0xac00002c); + au_sync(); + } +#endif +} diff -urN linux-2.4.18/arch/mips/baget/baget.c linux-2.4.19-pre5/arch/mips/baget/baget.c --- linux-2.4.18/arch/mips/baget/baget.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/baget.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: baget.c,v 1.1 1999/01/17 03:49:37 ralf Exp $ - * +/* * baget.c: Baget low level stuff * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov diff -urN linux-2.4.18/arch/mips/baget/bagetIRQ.S linux-2.4.19-pre5/arch/mips/baget/bagetIRQ.S --- linux-2.4.18/arch/mips/baget/bagetIRQ.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/bagetIRQ.S Sat Mar 30 22:55:26 2002 @@ -1,9 +1,8 @@ -/* $Id: bagetIRQ.S,v 1.1 1999/01/17 03:49:37 ralf Exp $ +/* * bagetIRQ.S: Interrupt exception dispatch code for Baget/MIPS * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov */ - #include #include #include diff -urN linux-2.4.18/arch/mips/baget/balo.c linux-2.4.19-pre5/arch/mips/baget/balo.c --- linux-2.4.18/arch/mips/baget/balo.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/balo.c Sat Mar 30 22:55:26 2002 @@ -1,9 +1,7 @@ -/* $Id$ - * +/* * balo.c: BAget LOader * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov - * */ #include #include @@ -42,27 +40,29 @@ static __inline__ void reset_and_jump(int start, int mem_upper) { + unsigned long tmp; + __asm__ __volatile__( ".set\tnoreorder\n\t" ".set\tnoat\n\t" - "mfc0\t$1,$12\n\t" + "mfc0\t$1, $12\n\t" "nop\n\t" "nop\n\t" "nop\n\t" - "ori\t$1,$1,0xff00\n\t" - "xori\t$1,$1,0xff00\n\t" - "mtc0\t$1,$12\n\t" + "ori\t$1, $1, 0xff00\n\t" + "xori\t$1, $1, 0xff00\n\t" + "mtc0\t$1, $12\n\t" "nop\n\t" "nop\n\t" "nop\n\t" - "move\t$4,%1\n\t" - "jr\t%0\n\t" + "move\t%0, %2\n\t" + "jr\t%1\n\t" "nop\n\t" ".set\tat\n\t" ".set\treorder" - : /* no outputs */ - :"Ir" (start), "Ir" (mem_upper) - :"$1", "$4", "memory"); + : "=&r" (tmp) + : "Ir" (start), "Ir" (mem_upper) + : "memory"); } static void start_kernel(void) diff -urN linux-2.4.18/arch/mips/baget/balo_supp.S linux-2.4.19-pre5/arch/mips/baget/balo_supp.S --- linux-2.4.18/arch/mips/baget/balo_supp.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/balo_supp.S Sat Mar 30 22:55:26 2002 @@ -1,9 +1,8 @@ -/* $Id: balo_supp.S,v 1.1 1999/01/17 03:49:38 ralf Exp $ +/* * balo_supp.S: BAget Loader supplement * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov */ - #include #include #include diff -urN linux-2.4.18/arch/mips/baget/irq.c linux-2.4.19-pre5/arch/mips/baget/irq.c --- linux-2.4.18/arch/mips/baget/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/irq.c Sat Mar 30 22:55:26 2002 @@ -27,7 +27,7 @@ #include -unsigned long spurious_count = 0; +volatile unsigned long irq_err_count; /* * This table is a correspondence between IRQ numbers and CPU PILs diff -urN linux-2.4.18/arch/mips/baget/print.c linux-2.4.19-pre5/arch/mips/baget/print.c --- linux-2.4.18/arch/mips/baget/print.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/print.c Sat Mar 30 22:55:26 2002 @@ -1,9 +1,7 @@ -/* $Id: print.c,v 1.1 1999/01/17 03:49:38 ralf Exp $ - * +/* * print.c: Simple print fascility * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov - * */ #include #include diff -urN linux-2.4.18/arch/mips/baget/prom/init.c linux-2.4.19-pre5/arch/mips/baget/prom/init.c --- linux-2.4.18/arch/mips/baget/prom/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/prom/init.c Sat Mar 30 22:55:26 2002 @@ -7,7 +7,13 @@ #include #include -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; + +const char *get_system_type(void) +{ + /* Should probably return one of "BT23-201", "BT23-202" */ + return "Baget"; +} void __init prom_init(unsigned int mem_upper) { diff -urN linux-2.4.18/arch/mips/baget/setup.c linux-2.4.19-pre5/arch/mips/baget/setup.c --- linux-2.4.18/arch/mips/baget/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/setup.c Sat Mar 30 22:55:26 2002 @@ -1,9 +1,7 @@ -/* $Id: setup.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ - * +/* * setup.c: Baget/MIPS specific setup, including init of the feature struct. * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov - * */ #include #include diff -urN linux-2.4.18/arch/mips/baget/vacserial.c linux-2.4.19-pre5/arch/mips/baget/vacserial.c --- linux-2.4.18/arch/mips/baget/vacserial.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/baget/vacserial.c Sat Mar 30 22:55:33 2002 @@ -1785,7 +1785,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING; @@ -2406,9 +2406,9 @@ callout_driver.proc_entry = 0; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; diff -urN linux-2.4.18/arch/mips/boot/addinitrd.c linux-2.4.19-pre5/arch/mips/boot/addinitrd.c --- linux-2.4.18/arch/mips/boot/addinitrd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/boot/addinitrd.c Sat Mar 30 22:55:26 2002 @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "ecoff.h" @@ -44,7 +46,7 @@ char buf[1024]; unsigned long loadaddr; unsigned long initrd_header[2]; - int i; + int i,cnt; int swab = 0; if (argc != 4) { @@ -60,7 +62,6 @@ die ("read aout header"); if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs) die ("read section headers"); - /* * check whether the file is good for us */ @@ -98,9 +99,20 @@ die ("write aout header"); if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs) die ("write section headers"); - while ((i = read (fd_vmlinux, buf, sizeof buf)) > 0) + /* skip padding */ + if(lseek(fd_vmlinux, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) + die ("lseek vmlinux"); + if(lseek(fd_outfile, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) + die ("lseek outfile"); + /* copy text segment */ + cnt = SWAB(eaout.tsize); + while (cnt) { + if ((i = read (fd_vmlinux, buf, sizeof buf)) <= 0) + die ("read vmlinux"); if (write (fd_outfile, buf, i) != i) die ("write vmlinux"); + cnt -= i; + } if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header) die ("write initrd header"); while ((i = read (fd_initrd, buf, sizeof buf)) > 0) diff -urN linux-2.4.18/arch/mips/boot/elf2ecoff.c linux-2.4.19-pre5/arch/mips/boot/elf2ecoff.c --- linux-2.4.18/arch/mips/boot/elf2ecoff.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/boot/elf2ecoff.c Sat Mar 30 22:55:26 2002 @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "ecoff.h" @@ -56,9 +58,10 @@ unsigned long len; }; +void combine (struct sect* base, struct sect* new, int pad); int phcmp (); char *saveRead (int file, off_t offset, off_t len, char *name); -int copy (int, int, off_t, off_t); +void copy (int, int, off_t, off_t); int translate_syms (int, int, off_t, off_t, off_t, off_t); void convert_elf_hdr (Elf32_Ehdr *); void convert_elf_phdrs (Elf32_Phdr *, int); @@ -71,14 +74,13 @@ int must_convert_endian = 0; int format_bigendian = 0; +int main (int argc, char **argv, char **envp) { Elf32_Ehdr ex; Elf32_Phdr *ph; Elf32_Shdr *sh; - Elf32_Sym *symtab; char *shstrtab; - int strtabix, symtabix; int i, pad; struct sect text, data, bss; struct filehdr efh; @@ -168,7 +170,8 @@ /* Section types we can't handle... */ else if (ph [i].p_type != PT_LOAD) { - fprintf (stderr, "Program header %d type %d can't be converted.\n"); + fprintf (stderr, "Program header %d type %d can't be converted.\n", + ex.e_phnum, ph[i].p_type ); exit (1); } /* Writable (data) segment? */ @@ -330,7 +333,7 @@ for (i = 0; i < nosecs; i++) { - printf ("Section %d: %s phys %x size %x file offset %x\n", + printf ("Section %d: %s phys %lx size %lx file offset %lx\n", i, esecs [i].s_name, esecs [i].s_paddr, esecs [i].s_size, esecs [i].s_scnptr); } @@ -384,11 +387,11 @@ char obuf [1024]; if (gap > 65536) { - fprintf (stderr, "Intersegment gap (%d bytes) too large.\n", + fprintf (stderr, "Intersegment gap (%ld bytes) too large.\n", gap); exit (1); } - fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap); + fprintf (stderr, "Warning: %ld byte intersegment gap.\n", gap); memset (obuf, 0, sizeof obuf); while (gap) { @@ -428,6 +431,7 @@ exit (0); } +void copy (out, in, offset, size) int out, in; off_t offset, size; @@ -465,6 +469,7 @@ /* Combine two segments, which must be contiguous. If pad is true, it's okay for there to be padding between. */ +void combine (base, new, pad) struct sect *base, *new; int pad; @@ -488,6 +493,7 @@ } } +int phcmp (h1, h2) Elf32_Phdr *h1, *h2; { @@ -511,7 +517,7 @@ } if (!(tmp = (char *)malloc (len))) { - fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len); + fprintf (stderr, "%s: Can't allocate %ld bytes.\n", name, len); exit (1); } count = read (file, tmp, len); diff -urN linux-2.4.18/arch/mips/cobalt/Makefile linux-2.4.19-pre5/arch/mips/cobalt/Makefile --- linux-2.4.18/arch/mips/cobalt/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,19 @@ +# +# Makefile for the Cobalt micro systems family specific parts of the 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). +# +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := cobalt.o + +obj-y := irq.o int-handler.o pci.o reset.o setup.o via.o promcon.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/cobalt/int-handler.S linux-2.4.19-pre5/arch/mips/cobalt/int-handler.S --- linux-2.4.18/arch/mips/cobalt/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,105 @@ +/* + * Cobalt interrupt handler + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include +#include + +/* + * cobalt_handle_int: Interrupt handler for Cobalt boards + */ + .text + .set noreorder + .set noat + .align 5 + NESTED(cobalt_handle_int, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + /* + * Get pending Interrupts + */ + mfc0 s0,CP0_CAUSE # get irq mask + + andi a0,s0,CAUSEF_IP2 /* Check for Galileo timer */ + beq a0,zero,1f + andi a0,s0,CAUSEF_IP6 /* Check for Via chip */ + + /* Galileo interrupt */ + jal galileo_irq + move a0,sp + j ret_from_irq + nop + +1: + beq a0,zero,1f /* Check IP6 */ + andi a0,s0,CAUSEF_IP3 + + /* Via interrupt */ + jal via_irq + move a0,sp + j ret_from_irq + nop + +1: + beq a0,zero,1f /* Check IP3 */ + andi a0,s0,CAUSEF_IP4 + + /* Ethernet 0 interrupt */ + li a0,4 + jal do_IRQ + move a1,sp + + j ret_from_irq + nop + +1: + beq a0,zero,1f /* Check IP4 */ + andi a0,s0,CAUSEF_IP5 + + /* Ethernet 1 interrupt */ + li a0,13 + jal do_IRQ + move a1,sp + + j ret_from_irq + nop +1: + beq a0,zero,1f /* Check IP5 */ + andi a0,s0,CAUSEF_IP7 + + /* Serial interrupt */ + li a0,7 + jal do_IRQ + move a1,sp + + j ret_from_irq + nop +1: + beq a0,zero,1f /* Check IP7 */ + nop + + /* PCI interrupt */ + li a0,9 + jal do_IRQ + move a1,sp + +1: + j ret_from_irq + nop + + END(cobalt_handle_int) + diff -urN linux-2.4.18/arch/mips/cobalt/irq.c linux-2.4.19-pre5/arch/mips/cobalt/irq.c --- linux-2.4.18/arch/mips/cobalt/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,223 @@ +/* + * IRQ vector handles + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* Cobalt Exception handler */ +extern void cobalt_handle_int(void); + +/* Via masking routines */ +extern void unmask_irq(unsigned int irqr); +extern void mask_irq(unsigned int irq); + + +/* + * We have two types of interrupts that we handle, ones that come + * in through the CPU interrupt lines, and ones that come in on + * the via chip. The CPU mappings are: + * 0,1 - S/W (ignored) + * 2 - Galileo chip (timer) + * 3 - Tulip 0 + NCR SCSI + * 4 - Tulip 1 + * 5 - 16550 UART + * 6 - VIA southbridge PIC + * 7 - PCI + * + * The VIA chip is a master/slave 8259 setup and has the + * following interrupts + * 8 - RTC + * 14 - IDE0 + * 15 - IDE1 + * + * In the table we use a 1 to indicate that we use a VIA interrupt + * line, and IE_IRQx to indicate that we use a CPU interrupt line + * + * We map all of these onto linux IRQ #s 0-15 and forget the rest + */ +#define NOINT_LINE 0 +#define CPUINT_LINE(x) IE_IRQ##x +#define VIAINT_LINE 1 + +#define COBALT_IRQS 16 + +static unsigned short irqnr_to_type[COBALT_IRQS] = +{ CPUINT_LINE(0), NOINT_LINE, VIAINT_LINE, NOINT_LINE, + CPUINT_LINE(1), NOINT_LINE, NOINT_LINE, CPUINT_LINE(3), + VIAINT_LINE, CPUINT_LINE(5), NOINT_LINE, NOINT_LINE, + NOINT_LINE, CPUINT_LINE(2), VIAINT_LINE, VIAINT_LINE }; + +/* + * Cobalt CPU irq + */ + +static void enable_cpu_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + change_cp0_status(irqnr_to_type[irq], irqnr_to_type[irq]); + restore_flags(flags); +} + +static unsigned startup_cpu_irq(unsigned int irq) +{ + enable_cpu_irq(irq); + + return 0; +} + +static void disable_cpu_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + change_cp0_status(irqnr_to_type[irq], ~(irqnr_to_type[irq])); + restore_flags(flags); +} + +#define shutdown_cpu_irq disable_cpu_irq +#define mask_and_ack_cpu_irq disable_cpu_irq + +static void end_cpu_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_cpu_irq(irq); +} + +static struct hw_interrupt_type cobalt_cpu_irq_type = { + "Cobalt CPU", + startup_cpu_irq, + shutdown_cpu_irq, + enable_cpu_irq, + disable_cpu_irq, + mask_and_ack_cpu_irq, + end_cpu_irq, + NULL +}; + + +/* + * Cobalt VIA irq + */ + +static void enable_via_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + unmask_irq(irq); + restore_flags(flags); +} + +static unsigned startup_via_irq(unsigned int irq) +{ + enable_via_irq(irq); + + return 0; +} + +static void disable_via_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq); + restore_flags(flags); +} + +#define shutdown_via_irq disable_via_irq +#define mask_and_ack_via_irq disable_via_irq + +static void end_via_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_via_irq(irq); +} + +static struct hw_interrupt_type cobalt_via_irq_type = { + "Cobalt VIA", + startup_via_irq, + shutdown_via_irq, + enable_via_irq, + disable_via_irq, + mask_and_ack_via_irq, + end_via_irq, + NULL +}; + + +static struct irqaction via_irq2 = { + no_action, 0, 0, "slave cascade", NULL, NULL +}; + +static struct resource pic1_io_resource = { + "VIA PIC Master", 0x20, 0x3f, IORESOURCE_BUSY +}; + +static struct resource pic2_io_resource = { + "VIA PIC Slave", 0xa0, 0xbf, IORESOURCE_BUSY +}; + + +void __init init_IRQ(void) +{ + int i; + + /* Initialise all of the IRQ descriptors */ + init_generic_irq(); + + /* Map the irqnr to the type int we have */ + for (i=0; i < COBALT_IRQS; i++) { + if (irqnr_to_type[i] >= CPUINT_LINE(0)) + /* cobalt_cpu_irq_type */ + irq_desc[i].handler = &cobalt_cpu_irq_type; + else if (irqnr_to_type[i] == VIAINT_LINE) + /* VIA/8259 irq_type */ + irq_desc[i].handler = &cobalt_via_irq_type; + else {} /* Leave it as disabled/no handler */ + } + + /* Setup the VIA interrupts */ + request_resource(&ioport_resource, &pic1_io_resource); + request_resource(&ioport_resource, &pic2_io_resource); + setup_irq(2, &via_irq2); + + /* This may be too simple.. FIX it later */ + VIA_PORT_WRITE(0x20, 0x10); + VIA_PORT_WRITE(0x21, 0x00); + VIA_PORT_WRITE(0x21, 0x00); + + VIA_PORT_WRITE(0xa0, 0x10); + VIA_PORT_WRITE(0xa1, 0x00); + VIA_PORT_WRITE(0xa1, 0x00); + + /* Mask all cpu interrupts + (except IE4, we already masked those at VIA level) */ + clear_cp0_status(ST0_IM); + set_cp0_status(IE_IRQ4); + + cli(); + + set_except_vector(0, cobalt_handle_int); +} diff -urN linux-2.4.18/arch/mips/cobalt/pci.c linux-2.4.19-pre5/arch/mips/cobalt/pci.c --- linux-2.4.18/arch/mips/cobalt/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/pci.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,422 @@ +/* + * Cobalt Qube/Raq PCI support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_PCI + +static void qube_expansion_slot_bist(void) +{ + unsigned char ctrl; + int timeout = 100000; + + pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl); + if(!(ctrl & PCI_BIST_CAPABLE)) + return; + + pcibios_write_config_byte(0, (0x0a<<3), PCI_BIST, ctrl|PCI_BIST_START); + do { + pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl); + if(!(ctrl & PCI_BIST_START)) + break; + } while(--timeout > 0); + if((timeout <= 0) || (ctrl & PCI_BIST_CODE_MASK)) + printk("PCI: Expansion slot card failed BIST with code %x\n", + (ctrl & PCI_BIST_CODE_MASK)); +} + +static void qube_expansion_slot_fixup(void) +{ + unsigned short pci_cmd; + unsigned long ioaddr_base = 0x108000; /* It's magic, ask Doug. */ + unsigned long memaddr_base = 0x12000000; + int i; + + /* Enable bits in COMMAND so driver can talk to it. */ + pcibios_read_config_word(0, (0x0a<<3), PCI_COMMAND, &pci_cmd); + pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pcibios_write_config_word(0, (0x0a<<3), PCI_COMMAND, pci_cmd); + + /* Give it a working IRQ. */ + pcibios_write_config_byte(0, (0x0a<<3), PCI_INTERRUPT_LINE, 9); + + /* Fixup base addresses, we only support I/O at the moment. */ + for(i = 0; i <= 5; i++) { + unsigned int regaddr = (PCI_BASE_ADDRESS_0 + (i * 4)); + unsigned int rval, mask, size, alignme, aspace; + unsigned long *basep = &ioaddr_base; + + /* Check type first, punt if non-IO. */ + pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval); + aspace = (rval & PCI_BASE_ADDRESS_SPACE); + if(aspace != PCI_BASE_ADDRESS_SPACE_IO) + basep = &memaddr_base; + + /* Figure out how much it wants, if anything. */ + pcibios_write_config_dword(0, (0x0a<<3), regaddr, 0xffffffff); + pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval); + + /* Unused? */ + if(rval == 0) + continue; + + rval &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~rval << 1) | 0x1; + size = (mask & rval) & 0xffffffff; + alignme = size; + if(alignme < 0x400) + alignme = 0x400; + rval = ((*basep + (alignme - 1)) & ~(alignme - 1)); + *basep = (rval + size); + pcibios_write_config_dword(0, (0x0a<<3), regaddr, rval | aspace); + } + qube_expansion_slot_bist(); +} + +static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) +{ + unsigned short cfgword; + unsigned char lt; + + /* Enable Bus Mastering and fast back to back. */ + pci_read_config_word(dev, PCI_COMMAND, &cfgword); + cfgword |= (PCI_COMMAND_FAST_BACK | PCI_COMMAND_MASTER); + pci_write_config_word(dev, PCI_COMMAND, cfgword); + + /* Enable both ide interfaces. ROM only enables primary one. */ + pci_write_config_byte(dev, 0x40, 0xb); + + /* Set latency timer to reasonable value. */ + pci_read_config_byte(dev, PCI_LATENCY_TIMER, <); + if(lt < 64) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7); +} + +static void qube_raq_tulip_fixup(struct pci_dev *dev) +{ + unsigned short pci_cmd; + extern int cobalt_is_raq; + + /* Fixup the first tulip located at device PCICONF_ETH0 */ + if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_ETH0) { + /* + * Now tell the Ethernet device that we expect an interrupt at + * IRQ 13 and not the default 189. + * + * The IRQ of the first Tulip is different on Qube and RaQ + */ + if (!cobalt_is_raq) { + /* All Qube's route this the same way. */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + COBALT_QUBE_ETH_IRQ); + } else { + /* Setup the first Tulip on the RAQ */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + COBALT_RAQ_ETH0_IRQ); + } + dev->resource[0].start = 0x100000; + dev->resource[0].end = 0x10007f; + if (dev->resource[1].start < 0x10000000) { + dev->resource[1].start = 0xe9ffec00; + dev->resource[1].end = 0xe9ffefff; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0xe9ffec00); + } + /* Fixup the second tulip located at device PCICONF_ETH1 */ + } else if (PCI_SLOT(dev->devfn) == COBALT_PCICONF_ETH1) { + + /* Enable the second Tulip device. */ + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER); + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Give it it's IRQ. */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + COBALT_RAQ_ETH1_IRQ); + + /* And finally, a usable I/O space allocation, right after what + * the first Tulip uses. + */ + dev->resource[0].start = 0x101000; + dev->resource[0].end = 0x10107f; + } +} + +static void qube_raq_scsi_fixup(struct pci_dev *dev) +{ + unsigned short pci_cmd; + extern int cobalt_is_raq; + + /* + * Tell the SCSI device that we expect an interrupt at + * IRQ 7 and not the default 0. + */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, COBALT_SCSI_IRQ); + + if (cobalt_is_raq) { + + /* Enable the device. */ + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + + pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY + | PCI_COMMAND_INVALIDATE); + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Give it it's RAQ IRQ. */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 4); + + /* And finally, a usable I/O space allocation, right after what + * the second Tulip uses. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x10102001); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x00002000); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, 0x00100000); + } +} + +static void qube_raq_galileo_fixup(struct pci_dev *dev) +{ + unsigned short galileo_id; + + /* Fix PCI latency-timer and cache-line-size values in Galileo + * host bridge. + */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7); + + /* On all machines prior to Q2, we had the STOP line disconnected + * from Galileo to VIA on PCI. The new Galileo does not function + * correctly unless we have it connected. + * + * Therefore we must set the disconnect/retry cycle values to + * something sensible when using the new Galileo. + */ + pci_read_config_word(dev, PCI_REVISION_ID, &galileo_id); + galileo_id &= 0xff; /* mask off class info */ + if (galileo_id == 0x10) { + /* New Galileo, assumes PCI stop line to VIA is connected. */ + *((volatile unsigned int *)0xb4000c04) = 0x00004020; + } else if (galileo_id == 0x1 || galileo_id == 0x2) { + signed int timeo; + /* XXX WE MUST DO THIS ELSE GALILEO LOCKS UP! -DaveM */ + timeo = *((volatile unsigned int *)0xb4000c04); + /* Old Galileo, assumes PCI STOP line to VIA is disconnected. */ + *((volatile unsigned int *)0xb4000c04) = 0x0000ffff; + } +} + +static void +qube_pcibios_fixup(struct pci_dev *dev) +{ + unsigned int tmp; + + /* See if there is a device in the expansion slot, if so + * fixup IRQ, fix base addresses, and enable master + + * I/O + memory accesses in config space. + */ + pcibios_read_config_dword(0, 0x0a<<3, PCI_VENDOR_ID, &tmp); + if(tmp != 0xffffffff && tmp != 0x00000000) + qube_expansion_slot_fixup(); +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, qube_raq_via_bmIDE_fixup }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, qube_raq_tulip_fixup }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, qube_raq_galileo_fixup }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C860, qube_raq_scsi_fixup }, + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, qube_pcibios_fixup } +}; + + +static __inline__ int pci_range_ck(struct pci_dev *dev) +{ + if ((dev->bus->number == 0) + && ((PCI_SLOT (dev->devfn) == 0) + || ((PCI_SLOT (dev->devfn) > 6) + && (PCI_SLOT (dev->devfn) <= 12)))) + return 0; /* OK device number */ + + return -1; /* NOT ok device number */ +} + +#define PCI_CFG_DATA ((volatile unsigned long *)0xb4000cfc) +#define PCI_CFG_CTRL ((volatile unsigned long *)0xb4000cf8) + +#define PCI_CFG_SET(dev,where) \ + ((*PCI_CFG_CTRL) = (0x80000000 | (PCI_SLOT ((dev)->devfn) << 11) | \ + (PCI_FUNC ((dev)->devfn) << 8) | (where))) + +static int qube_pci_read_config_dword (struct pci_dev *dev, + int where, + u32 *val) +{ + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck (dev)) { + *val = 0xFFFFFFFF; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, where); + *val = *PCI_CFG_DATA; + return PCIBIOS_SUCCESSFUL; +} + +static int qube_pci_read_config_word (struct pci_dev *dev, + int where, + u16 *val) +{ + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck (dev)) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, (where & ~0x3)); + *val = *PCI_CFG_DATA >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +static int qube_pci_read_config_byte (struct pci_dev *dev, + int where, + u8 *val) +{ + if (pci_range_ck (dev)) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, (where & ~0x3)); + *val = *PCI_CFG_DATA >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +static int qube_pci_write_config_dword (struct pci_dev *dev, + int where, + u32 val) +{ + if(where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck (dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, where); + *PCI_CFG_DATA = val; + return PCIBIOS_SUCCESSFUL; +} + +static int +qube_pci_write_config_word (struct pci_dev *dev, + int where, + u16 val) +{ + unsigned long tmp; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck (dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, (where & ~0x3)); + tmp = *PCI_CFG_DATA; + tmp &= ~(0xffff << ((where & 0x3) * 8)); + tmp |= (val << ((where & 0x3) * 8)); + *PCI_CFG_DATA = tmp; + return PCIBIOS_SUCCESSFUL; +} + +static int +qube_pci_write_config_byte (struct pci_dev *dev, + int where, + u8 val) +{ + unsigned long tmp; + + if (pci_range_ck (dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, (where & ~0x3)); + tmp = *PCI_CFG_DATA; + tmp &= ~(0xff << ((where & 0x3) * 8)); + tmp |= (val << ((where & 0x3) * 8)); + *PCI_CFG_DATA = tmp; + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops qube_pci_ops = { + qube_pci_read_config_byte, + qube_pci_read_config_word, + qube_pci_read_config_dword, + qube_pci_write_config_byte, + qube_pci_write_config_word, + qube_pci_write_config_dword +}; + +void __init pcibios_init(void) +{ + printk("PCI: Probing PCI hardware\n"); + + ioport_resource.start = 0x00000000; + ioport_resource.end = 0x0fffffff; + + iomem_resource.start = 0x01000000; + iomem_resource.end = 0xffffffff; + + pci_scan_bus(0, &qube_pci_ops, NULL); +} + +char *pcibios_setup(char *str) +{ + return str; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, status; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_read_config_word(dev, PCI_STATUS, &status); + printk("PCI: Enabling device %s (%04x %04x)\n", dev->slot_name, cmd, status); + /* We'll sort this out when we know it isn't enabled ;) */ + + return 0; +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + + panic("Uhhoh called pcibios_align_resource\n"); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + + panic("Uhhoh called pcibios_update_resource\n"); +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + /* We don't have sub-busses to fixup here */ +} + +unsigned int __init pcibios_assign_all_busses(void) +{ + return 1; +} + +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/cobalt/promcon.c linux-2.4.19-pre5/arch/mips/cobalt/promcon.c --- linux-2.4.18/arch/mips/cobalt/promcon.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/promcon.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,91 @@ +/* + * PROM console for Cobalt Raq2 + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static unsigned long port = 0xc800000; + +static __inline__ void ns16550_cons_put_char(char ch, unsigned long ioaddr) +{ + char lsr; + + do { + lsr = inb(ioaddr + UART_LSR); + } while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE)); + outb(ch, ioaddr + UART_TX); +} + +static __inline__ char ns16550_cons_get_char(unsigned long ioaddr) +{ + while ((inb(ioaddr + UART_LSR) & UART_LSR_DR) == 0) + udelay(1); + return inb(ioaddr + UART_RX); +} + +void ns16550_console_write(struct console *co, const char *s, unsigned count) +{ + char lsr, ier; + unsigned i; + + ier = inb(port + UART_IER); + outb(0x00, port + UART_IER); + for (i=0; i < count; i++, s++) { + + if(*s == '\n') + ns16550_cons_put_char('\r', port); + ns16550_cons_put_char(*s, port); + } + + do { + lsr = inb(port + UART_LSR); + } while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE)); + + outb(ier, port + UART_IER); +} + +char getDebugChar(void) +{ + return ns16550_cons_get_char(port); +} + +void putDebugChar(char kgdb_char) +{ + ns16550_cons_put_char(kgdb_char, port); +} + +static kdev_t +ns16550_console_dev(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console ns16550_console = { + name: "prom", + setup: NULL, + write: ns16550_console_write, + device: ns16550_console_dev, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init ns16550_setup_console(void) +{ + register_console(&ns16550_console); +} diff -urN linux-2.4.18/arch/mips/cobalt/reset.c linux-2.4.19-pre5/arch/mips/cobalt/reset.c --- linux-2.4.18/arch/mips/cobalt/reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/reset.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,70 @@ +/* + * Cobalt Reset operations + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void cobalt_machine_restart(char *command) +{ + *(volatile char *)0xbc000000 = 0x0f; + + /* + * Ouch, we're still alive ... This time we take the silver bullet ... + * ... and find that we leave the hardware in a state in which the + * kernel in the flush locks up somewhen during of after the PCI + * detection stuff. + */ + set_cp0_status(ST0_BEV | ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__( + "jr\t%0" + : + : "r" (0xbfc00000)); +} + +extern int led_state; +#define kLED 0xBC000000 +#define LEDSet(x) (*(volatile unsigned char *) kLED) = (( unsigned char)x) + +void cobalt_machine_halt(void) +{ + int mark; + + /* Blink our cute? little LED (number 3)... */ + while (1) { + led_state = led_state | ( 1 << 3 ); + LEDSet(led_state); + mark = jiffies; + while (jiffies<(mark+HZ)); + led_state = led_state & ~( 1 << 3 ); + LEDSet(led_state); + mark = jiffies; + while (jiffies<(mark+HZ)); + } +} + +/* + * This triggers the luser mode device driver for the power switch ;-) + */ +void cobalt_machine_power_off(void) +{ + printk("You can switch the machine off now.\n"); + cobalt_machine_halt(); +} diff -urN linux-2.4.18/arch/mips/cobalt/setup.c linux-2.4.19-pre5/arch/mips/cobalt/setup.c --- linux-2.4.18/arch/mips/cobalt/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,122 @@ +/* + * Setup pointers to hardware dependent routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void cobalt_machine_restart(char *command); +extern void cobalt_machine_halt(void); +extern void cobalt_machine_power_off(void); + +extern struct rtc_ops std_rtc_ops; +extern struct ide_ops std_ide_ops; + + +char arcs_cmdline[CL_SIZE] = { "console=ttyS0,115200 root=/dev/hda1" }; + +const char *get_system_type(void) +{ + return "MIPS Cobalt"; +} + + +#define GALILEO_T0_VAL 0xb4000850 +#define GALILEO_TIMER_CTRL 0xb4000864 +#define GALILEO_CPU_MASK 0xb4000c1c + +#define GALILEO_ENTC0 0x01 +#define GALILEO_SELTC0 0x02 + +static void __init cobalt_time_init(void) +{ + rtc_ops = &std_rtc_ops; +} + +static void __init cobalt_timer_setup(struct irqaction *irq) +{ + /* Load timer value for 150 Hz */ + volatile unsigned long *timer_reg = (volatile unsigned long *)GALILEO_T0_VAL; + + *timer_reg = 500000; + + /* Register our timer interrupt */ + setup_irq(0, irq); + + /* Enable timer ints */ + *((volatile unsigned long *) GALILEO_TIMER_CTRL) = + (unsigned long) (GALILEO_ENTC0 | GALILEO_SELTC0); + /* Unmask timer int */ + *((volatile unsigned long *) GALILEO_CPU_MASK) = (unsigned long) 0x00000100; +} + +int cobalt_serial_present; +int cobalt_serial_type; +int cobalt_is_raq; + +void __init cobalt_setup(void) +{ + + _machine_restart = cobalt_machine_restart; + _machine_halt = cobalt_machine_halt; + _machine_power_off = cobalt_machine_power_off; + + board_time_init = cobalt_time_init; + board_timer_setup = cobalt_timer_setup; + +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + set_io_port_base(0xb0000000); + + /* + * This is a prom style console. We just poke at the + * UART to make it talk. + * Only use this console if you really screw up and can't + * get to the stage of setting up a real serial console. + */ + /*ns16550_setup_console();*/ + + /* We have to do this early, here, before the value could + * possibly be overwritten by the bootup sequence. + */ + cobalt_serial_present = *((unsigned long *) 0xa020001c); + cobalt_serial_type = *((unsigned long *) 0xa0200020); + cobalt_is_raq = (cobalt_serial_present != 0x0 + && cobalt_serial_type == 0x1); +} + +/* Prom init. We read our one and only communication with the + firmware. Grab the amount of installed memory */ +void __init prom_init(int argc) +{ + mips_machgroup = MACH_GROUP_COBALT; + + add_memory_region(0x0, argc & 0x7fffffff, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ + /* Nothing to do! */ +} diff -urN linux-2.4.18/arch/mips/cobalt/via.c linux-2.4.19-pre5/arch/mips/cobalt/via.c --- linux-2.4.18/arch/mips/cobalt/via.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/cobalt/via.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,99 @@ +/* + * VIA chipset irq handling + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Ralf Baechle + * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) + * + */ + +#include +#include +#include +#include +#include + +extern void do_IRQ(int irq, struct pt_regs * regs); + +/* Cached values of VIA PIC masks, we start with cascade enabled */ +static unsigned int cached_irq_mask = 0xfffb; + +#define __byte(x,y) (((unsigned char *)&(y))[x]) +#define cached_21 (__byte(0,cached_irq_mask)) +#define cached_A1 (__byte(1,cached_irq_mask)) + + +void mask_irq(unsigned int irq) +{ + unsigned int mask = 1 << irq; + + cached_irq_mask |= mask; + if (irq & 8) { + VIA_PORT_WRITE(0xA1, cached_A1); + } else { + VIA_PORT_WRITE(0x21, cached_21); + } +} + +void unmask_irq(unsigned int irq) +{ + unsigned int mask = ~(1 << irq); + + cached_irq_mask &= mask; + if (irq & 8) { + VIA_PORT_WRITE(0xA1, cached_A1); + } else { + VIA_PORT_WRITE(0x21, cached_21); + } +} + +asmlinkage void via_irq(struct pt_regs *regs) +{ + char mstat, sstat; + + /* Read Master Status */ + VIA_PORT_WRITE(0x20, 0x0C); + mstat = VIA_PORT_READ(0x20); + + if (mstat < 0) { + mstat &= 0x7f; + if (mstat != 2) { + do_IRQ(mstat, regs); + VIA_PORT_WRITE(0x20, mstat | 0x20); + } else { + sstat = VIA_PORT_READ(0xA0); + + /* Slave interrupt */ + VIA_PORT_WRITE(0xA0, 0x0C); + sstat = VIA_PORT_READ(0xA0); + + if (sstat < 0) { + do_IRQ((sstat + 8) & 0x7f, regs); + VIA_PORT_WRITE(0x20, 0x22); + VIA_PORT_WRITE(0xA0, (sstat & 0x7f) | 0x20); + } else { + printk("Spurious slave interrupt...\n"); + } + } + } else + printk("Spurious master interrupt..."); +} + +#define GALILEO_INTCAUSE 0xb4000c18 +#define GALILEO_T0EXP 0x00000100 + +asmlinkage void galileo_irq(struct pt_regs *regs) +{ + unsigned long irq_src = *((unsigned long *) GALILEO_INTCAUSE); + + /* Check for timer irq ... */ + if (irq_src & GALILEO_T0EXP) { + /* Clear the int line */ + *((volatile unsigned long *) GALILEO_INTCAUSE) = 0; + do_IRQ(0, regs); + } else + printk("Spurious Galileo interrupt...\n"); +} diff -urN linux-2.4.18/arch/mips/config.in linux-2.4.19-pre5/arch/mips/config.in --- linux-2.4.18/arch/mips/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/config.in Sat Mar 30 22:55:26 2002 @@ -3,7 +3,7 @@ # see Documentation/kbuild/config-language.txt. # define_bool CONFIG_MIPS y -define_bool CONFIG_SMP n +define_bool CONFIG_MIPS32 y mainmenu_name "Linux Kernel Configuration" @@ -18,9 +18,9 @@ bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS + bool 'Support for Cobalt Server (EXPERIMENTAL)' CONFIG_MIPS_COBALT bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 - bool 'Support for Galileo EV96100 Evaluation board' CONFIG_MIPS_EV96100 bool 'Support for Galileo EV64120 Evaluation board' CONFIG_MIPS_EV64120 if [ "$CONFIG_MIPS_EV64120" = "y" ]; then bool 'Enable Second PCI (PCI1)' CONFIG_EVB_PCI1 @@ -29,6 +29,7 @@ 83.3 CONFIG_SYSCLK_83\ 100 CONFIG_SYSCLK_100" CONFIG_SYSCLK_83 fi + bool 'Support for Galileo EV96100 Evaluation board' CONFIG_MIPS_EV96100 bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO @@ -38,35 +39,45 @@ Model-200/210/312/320/325/350/390 CONFIG_NINO_8MB \ Model-500/510 CONFIG_NINO_16MB" CONFIG_NINO_8MB fi + bool 'Support for SiByte SB1250 SOC' CONFIG_SIBYTE_SB1250 + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for SB1250 onchip PCI controller' CONFIG_PCI + bool ' Support for SB1250 profiling - SB1/SCD perf counters' CONFIG_SIBYTE_SB1250_PROF + bool ' Support for BCM1250 profiling using trace buffer' CONFIG_BCM1250_TBPROF + bool ' Remote debugging (kgdb over UART 1)' CONFIG_REMOTE_DEBUG + bool ' Support for SiByte SWARM board' CONFIG_SIBYTE_SWARM + if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + bool ' Running under simulation' CONFIG_SIMULATION + bool ' Configure for L3proc Demo' CONFIG_L3DEMO + int ' Maximum memory chunks' CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS 16 + bool ' Multi-Processing support' CONFIG_SMP + fi + fi fi bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 bool 'Support for Momentum Ocelot board' CONFIG_MOMENCO_OCELOT bool 'Support for NEC DDB Vrc-5476' CONFIG_DDB5476 bool 'Support for NEC DDB Vrc-5477' CONFIG_DDB5477 +bool 'Support for NEC Osprey board' CONFIG_NEC_OSPREY bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 bool 'Support for SGI IP22' CONFIG_SGI_IP22 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI bool 'Support for ITE 8172G board' CONFIG_MIPS_ITE8172 - if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then - bool ' Support for older IT8172 (Rev C)' CONFIG_IT8172_REVC - bool ' Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD - if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then - define_bool CONFIG_IT8172_CIR y - else - bool ' Enable PS2 Keyboard Support ' CONFIG_PC_KEYB - fi - bool ' Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 - bool ' Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 - fi - bool 'Support for Globespan IVR board' CONFIG_MIPS_IVR - if [ "$CONFIG_MIPS_IVR" = "y" ]; then - bool ' Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD - if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then - define_bool CONFIG_IT8172_CIR y - fi - bool ' Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 - fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + bool ' Support for older IT8172 (Rev C)' CONFIG_IT8172_REVC +fi +bool 'Support for Globespan IVR board' CONFIG_MIPS_IVR bool 'Support for Alchemy Semi PB1000 board' CONFIG_MIPS_PB1000 +if [ "$CONFIG_MIPS_PB1000" = "y" ]; then + bool ' Support for PCI AUTO Config' CONFIG_PCI_AUTO +fi +bool 'Support for Alchemy Semi PB1500 board' CONFIG_MIPS_PB1500 +bool 'Support for Toshiba JMR-TX3927 board' CONFIG_TOSHIBA_JMR3927 +bool 'Support for Hewlett Packard LaserJet board' CONFIG_HP_LASERJET + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'High Memory Support (experimental)' CONFIG_HIGHMEM +fi define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n @@ -74,37 +85,39 @@ # # Select some configuration options automatically for certain systems. # -unset CONFIG_ARC32 -unset CONFIG_BOARD_SCACHE -unset CONFIG_COHERENT_IO -unset CONFIG_HAVE_STD_PC_SERIAL_PORT -unset CONFIG_I8259 -unset CONFIG_ISA -unset CONFIG_PCI -unset CONFIG_MIPS_JAZZ -unset CONFIG_SWAP_IO_SPACE -unset CONFIG_VIDEO_G364 -unset CONFIG_PC_KEYB define_bool CONFIG_MCA n define_bool CONFIG_SBUS n +if [ "$CONFIG_DECSTATION" = "y" ]; then + define_bool CONFIG_NONCOHERENT_IO y +fi + +if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_SWAP_IO_SPACE y +fi + if [ "$CONFIG_MIPS_EV96100" = "y" ]; then define_bool CONFIG_PCI y define_bool CONFIG_MIPS_GT96100 y - define_bool CONFIG_SWAP_IO_SPACE y + define_bool CONFIG_NEW_IRQ y define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_SWAP_IO_SPACE y fi if [ "$CONFIG_MIPS_EV64120" = "y" ]; then define_bool CONFIG_PCI y define_bool CONFIG_ISA n define_bool CONFIG_MIPS_GT64120 y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_ALGOR_P4032" = "y" ]; then define_bool CONFIG_PCI y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ @@ -115,6 +128,7 @@ define_bool CONFIG_FB y define_bool CONFIG_FB_G364 y define_bool CONFIG_MIPS_JAZZ y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PC_KEYB y define_bool CONFIG_OLD_TIME_C y fi @@ -123,11 +137,15 @@ define_bool CONFIG_I8259 y define_bool CONFIG_ISA y define_bool CONFIG_MIPS_JAZZ y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PC_KEYB y define_bool CONFIG_ROTTEN_IRQ y define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PCI y define_bool CONFIG_SWAP_IO_SPACE y fi @@ -136,6 +154,8 @@ define_bool CONFIG_PCI y define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_SWAP_IO_SPACE y fi if [ "$CONFIG_MOMENCO_OCELOT" = "y" ]; then @@ -143,65 +163,152 @@ define_bool CONFIG_SYSCLK_100 y define_bool CONFIG_SWAP_IO_SPACE y define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_SGI_IP22" = "y" ]; then define_bool CONFIG_ARC32 y define_bool CONFIG_BOARD_SCACHE y + define_bool CONFIG_IRQ_CPU y define_bool CONFIG_PC_KEYB y define_bool CONFIG_SGI y define_bool CONFIG_NEW_IRQ y - define_bool CONFIG_OLD_TIME_C y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then define_bool CONFIG_ARC32 y define_bool CONFIG_I8259 y define_bool CONFIG_ISA y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_OLD_TIME_C y define_bool CONFIG_PC_KEYB y define_bool CONFIG_PCI y - define_bool CONFIG_ROTTEN_IRQ y - define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_DDB5074" = "y" ]; then + define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y define_bool CONFIG_I8259 y define_bool CONFIG_ISA y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PCI y define_bool CONFIG_PC_KEYB y define_bool CONFIG_ROTTEN_IRQ y - define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_DDB5476" = "y" ]; then define_bool CONFIG_ISA y define_bool CONFIG_PCI y define_bool CONFIG_PC_KEYB y - define_bool CONFIG_ROTTEN_IRQ y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_I8259 y define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_PCI_AUTO y define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y fi if [ "$CONFIG_DDB5477" = "y" ]; then - define_bool CONFIG_CPU_LITTLE_ENDIAN y define_bool CONFIG_PCI y define_bool CONFIG_NEW_TIME_C y define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_DUMMY_KEYB y +fi +if [ "$CONFIG_NEC_OSPREY" = "y" ]; then + define_bool CONFIG_VR4181 y + define_bool CONFIG_SERIAL y + define_bool CONFIG_SERIAL_MANY_PORTS y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_DUMMY_KEYB y + define_bool CONFIG_SCSI n +fi +if [ "$CONFIG_MIPS_COBALT" = "y" ]; then + define_bool CONFIG_COBALT_LCD y + define_bool CONFIG_PCI y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y fi if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then define_bool CONFIG_PCI y define_bool CONFIG_IT8712 y define_bool CONFIG_PC_KEYB y define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_IT8172_CIR y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y fi if [ "$CONFIG_MIPS_IVR" = "y" ]; then define_bool CONFIG_PCI y + define_bool CONFIG_PC_KEYB y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_IT8172_CIR y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y fi if [ "$CONFIG_MIPS_PB1000" = "y" ]; then define_bool CONFIG_MIPS_AU1000 y define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_PCI y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PC_KEYB y + define_int MAX_HWIFS 1 +fi +if [ "$CONFIG_MIPS_PB1500" = "y" ]; then + define_bool CONFIG_MIPS_AU1000 y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_PCI y + define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PC_KEYB y fi if [ "$CONFIG_NINO" = "y" ]; then + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_PC_KEYB y fi +if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then + define_bool CONFIG_NONCOHERENT_IO y +fi +if [ "$CONFIG_HP_LASERJET" = "y" ]; then + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PCI y + #not yet define_bool CONFIG_PCI_AUTO y +fi + +if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + define_bool CONFIG_NEW_TIME_C y +fi + +if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then + define_bool CONFIG_TOSHIBA_BOARDS y + define_bool CONFIG_PCI y + define_bool CONFIG_NEW_PCI y + define_bool CONFIG_PCI_AUTO y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_SWAP_IO_SPACE y + define_bool CONFIG_PC_KEYB y +fi if [ "$CONFIG_ISA" != "y" ]; then define_bool CONFIG_ISA n @@ -209,14 +316,6 @@ else define_bool CONFIG_EISA y fi - -if [ "$CONFIG_PCI" != "y" ]; then - define_bool CONFIG_PCI n -fi - -if [ "$CONFIG_I8259" != "y" ]; then - define_bool CONFIG_I8259 n -fi endmenu mainmenu_option next_comment @@ -233,10 +332,12 @@ choice 'CPU type' \ "R3000 CONFIG_CPU_R3000 \ + R39XX CONFIG_CPU_TX39XX \ R6000 CONFIG_CPU_R6000 \ R41xx CONFIG_CPU_VR41XX \ R4300 CONFIG_CPU_R4300 \ R4x00 CONFIG_CPU_R4X00 \ + R49XX CONFIG_CPU_TX49XX \ R5000 CONFIG_CPU_R5000 \ R5432 CONFIG_CPU_R5432 \ RM7000 CONFIG_CPU_RM7000 \ @@ -246,15 +347,45 @@ MIPS32 CONFIG_CPU_MIPS32 \ MIPS64 CONFIG_CPU_MIPS64" R4x00 -bool 'Override CPU Options' CONFIG_CPU_ADVANCED +if [ "$CONFIG_CPU_MIPS32" = "y" ]; then + define_bool CONFIG_CPU_HAS_PREFETCH y +fi + +if [ "$CONFIG_CPU_MIPS64" = "y" ]; then + define_bool CONFIG_CPU_HAS_PREFETCH y +fi + +if [ "$CONFIG_CPU_RM7000" = "y" ]; then + define_bool CONFIG_CPU_HAS_PREFETCH y +fi + +if [ "$CONFIG_CPU_SB1" = "y" ]; then + bool ' Workarounds for pass 1 sb1 bugs' CONFIG_SB1_PASS_1_WORKAROUNDS + bool ' Support for SB1 Cache Error handler' CONFIG_SB1_CACHE_ERROR + define_bool CONFIG_VTAG_ICACHE y + define_bool CONFIG_CPU_HAS_PREFETCH y +fi + +if [ "$CONFIG_CPU_R4X00" = "y" -o \ + "$CONFIG_CPU_R5000" = "y" -o \ + "$CONFIG_CPU_RM7000" = "y" -o \ + "$CONFIG_CPU_R10000" = "y" -o \ + "$CONFIG_CPU_SB1" = "y" -o \ + "$CONFIG_CPU_MIPS32" = "y" -o \ + "$CONFIG_CPU_MIPS64" = "y" ]; then + bool ' Support for 64-bit physical addresspace' CONFIG_64BIT_PHYS_ADDR +fi +bool 'Override CPU Options' CONFIG_CPU_ADVANCED if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then bool ' ll/sc Instructions available' CONFIG_CPU_HAS_LLSC bool ' lld/scd Instructions available' CONFIG_CPU_HAS_LLDSCD bool ' Writeback Buffer available' CONFIG_CPU_HAS_WB else - if [ "$CONFIG_CPU_R3000" = "y" -o "$CONFIG_CPU_VR41XX" = "y" ]; then - if [ "CONFIG_DECSTATION" = "y" ]; then + if [ "$CONFIG_CPU_R3000" = "y" -o \ + "$CONFIG_CPU_VR41XX" = "y" -o \ + "$CONFIG_CPU_TX39XX" = "y" ]; then + if [ "$CONFIG_DECSTATION" = "y" ]; then define_bool CONFIG_CPU_HAS_LLSC n define_bool CONFIG_CPU_HAS_LLDSCD n define_bool CONFIG_CPU_HAS_WB y @@ -281,13 +412,17 @@ comment 'General setup' if [ "$CONFIG_DECSTATION" = "y" -o \ "$CONFIG_DDB5074" = "y" -o \ - "$CONFIG_DDB5476" = "y" -o \ - "$CONFIG_NINO" = "y" ]; then + "$CONFIG_NINO" = "y" -o \ + "$CONFIG_MIPS_COBALT" = "y" ]; then define_bool CONFIG_CPU_LITTLE_ENDIAN y else bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN fi +if [ "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then + bool 'DS1742 BRAM/RTC support' CONFIG_RTC_DS1742 +fi + if [ "$CONFIG_PROC_FS" = "y" ]; then define_bool CONFIG_KCORE_ELF y fi @@ -305,6 +440,9 @@ define_bool CONFIG_BINFMT_AOUT n define_bool CONFIG_BINFMT_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then +dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL +fi bool 'Networking support' CONFIG_NET @@ -314,8 +452,10 @@ if [ "$CONFIG_HOTPLUG" = "y" ] ; then source drivers/pcmcia/Config.in + source drivers/hotplug/Config.in else define_bool CONFIG_PCMCIA n + define_bool CONFIG_HOTPLUG_PCI n fi bool 'System V IPC' CONFIG_SYSVIPC @@ -339,6 +479,12 @@ source drivers/parport/Config.in source drivers/block/Config.in +if [ "$CONFIG_BLK_DEV_INITRD" = "y" ]; then + mainmenu_option next_comment + comment 'MIPS initrd options' + bool ' Embed root filesystem ramdisk into the kernel' CONFIG_EMBEDDED_RAMDISK + endmenu +fi source drivers/md/Config.in @@ -424,11 +570,6 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then mainmenu_option next_comment comment 'DECStation Character devices' - - bool 'Virtual terminal' CONFIG_VT - if [ "$CONFIG_VT" = "y" ]; then - bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE - fi tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then bool 'DZ11 Serial Support' CONFIG_DZ @@ -437,24 +578,17 @@ fi bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi - bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS - if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 - fi # if [ "$CONFIG_ACCESSBUS" = "y" ]; then # bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE # fi bool 'Enhanced Real Time Clock Support' CONFIG_RTC - endmenu fi if [ "$CONFIG_SGI_IP22" = "y" ]; then mainmenu_option next_comment comment 'SGI Character devices' - bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then - bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then define_bool CONFIG_DUMMY_CONSOLE y @@ -462,14 +596,6 @@ define_bool CONFIG_FONT_8x16 y fi fi - bool 'PS/2 mouse support' CONFIG_PSMOUSE - if [ "$CONFIG_PSMOUSE" != "n" ]; then - define_bool CONFIG_MOUSE y - fi - bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS - if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 - fi endmenu fi @@ -512,9 +638,7 @@ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG dep_bool 'Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_REMOTE_DEBUG fi -if [ "$CONFIG_SERIAL" = "y" ]; then - bool 'Low-level debugging' CONFIG_LL_DEBUG -fi +bool 'Enable run-time debugging' CONFIG_DEBUG bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ if [ "$CONFIG_SMP" != "y" ]; then bool 'Run uncached' CONFIG_MIPS_UNCACHED diff -urN linux-2.4.18/arch/mips/ddb5074/prom.c linux-2.4.19-pre5/arch/mips/ddb5074/prom.c --- linux-2.4.18/arch/mips/ddb5074/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5074/prom.c Sat Mar 30 22:55:26 2002 @@ -13,7 +13,12 @@ #include -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; + +const char *get_system_type(void) +{ + return "NEC DDB Vrc-5074"; +} void __init prom_init(const char *s) { diff -urN linux-2.4.18/arch/mips/ddb5074/setup.c linux-2.4.19-pre5/arch/mips/ddb5074/setup.c --- linux-2.4.18/arch/mips/ddb5074/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5074/setup.c Sat Mar 30 22:55:26 2002 @@ -96,7 +96,7 @@ extern int panic_timeout; irq_setup = ddb_irq_setup; - mips_io_port_base = NILE4_PCI_IO_BASE; + set_io_port_base(NILE4_PCI_IO_BASE); isa_slot_offset = NILE4_PCI_MEM_BASE; request_region(0x00, 0x20, "dma1"); request_region(0x40, 0x20, "timer"); diff -urN linux-2.4.18/arch/mips/ddb5476/Makefile linux-2.4.19-pre5/arch/mips/ddb5476/Makefile --- linux-2.4.18/arch/mips/ddb5476/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/Makefile Thu Jan 1 01:00:00 1970 @@ -1,23 +0,0 @@ -# -# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines -# under Linux. -# -# 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: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -O_TARGET = ddb5476.a - -obj-y += setup.o irq.o time.o prom.o pci.o \ - int-handler.o nile4.o -obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ddb5476/dbg_io.c linux-2.4.19-pre5/arch/mips/ddb5476/dbg_io.c --- linux-2.4.18/arch/mips/ddb5476/dbg_io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/dbg_io.c Thu Jan 1 01:00:00 1970 @@ -1,125 +0,0 @@ - -#include - -#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG)) - -/* --- CONFIG --- */ - -/* we need uint32 uint8 */ -/* #include "types.h" */ -typedef unsigned char uint8; -typedef unsigned int uint32; - -/* --- END OF CONFIG --- */ - -#define UART16550_BAUD_2400 2400 -#define UART16550_BAUD_4800 4800 -#define UART16550_BAUD_9600 9600 -#define UART16550_BAUD_19200 19200 -#define UART16550_BAUD_38400 38400 -#define UART16550_BAUD_57600 57600 -#define UART16550_BAUD_115200 115200 - -#define UART16550_PARITY_NONE 0 -#define UART16550_PARITY_ODD 0x08 -#define UART16550_PARITY_EVEN 0x18 -#define UART16550_PARITY_MARK 0x28 -#define UART16550_PARITY_SPACE 0x38 - -#define UART16550_DATA_5BIT 0x0 -#define UART16550_DATA_6BIT 0x1 -#define UART16550_DATA_7BIT 0x2 -#define UART16550_DATA_8BIT 0x3 - -#define UART16550_STOP_1BIT 0x0 -#define UART16550_STOP_2BIT 0x4 - -/* ----------------------------------------------------- */ - -/* === CONFIG === */ - -/* [jsun] we use the second serial port for kdb */ -#define BASE 0xa60002f8 -#define MAX_BAUD 115200 - -/* === END OF CONFIG === */ - -/* register offset */ -#define OFS_RCV_BUFFER 0 -#define OFS_TRANS_HOLD 0 -#define OFS_SEND_BUFFER 0 -#define OFS_INTR_ENABLE 1 -#define OFS_INTR_ID 2 -#define OFS_DATA_FORMAT 3 -#define OFS_LINE_CONTROL 3 -#define OFS_MODEM_CONTROL 4 -#define OFS_RS232_OUTPUT 4 -#define OFS_LINE_STATUS 5 -#define OFS_MODEM_STATUS 6 -#define OFS_RS232_INPUT 6 -#define OFS_SCRATCH_PAD 7 - -#define OFS_DIVISOR_LSB 0 -#define OFS_DIVISOR_MSB 1 - - -/* memory-mapped read/write of the port */ -#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) -#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) - -void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) -{ - /* disable interrupts */ - UART16550_WRITE(OFS_INTR_ENABLE, 0); - - /* set up buad rate */ - { - uint32 divisor; - - /* set DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x80); - - /* set divisor */ - divisor = MAX_BAUD / baud; - UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); - UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); - - /* clear DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x0); - } - - /* set data format */ - UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); -} - -static int remoteDebugInitialized = 0; - -uint8 getDebugChar(void) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_38400, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); - return UART16550_READ(OFS_RCV_BUFFER); -} - - -int putDebugChar(uint8 byte) -{ - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_9600, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); - UART16550_WRITE(OFS_SEND_BUFFER, byte); - return 1; -} - -#endif diff -urN linux-2.4.18/arch/mips/ddb5476/int-handler.S linux-2.4.19-pre5/arch/mips/ddb5476/int-handler.S --- linux-2.4.18/arch/mips/ddb5476/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/int-handler.S Thu Jan 1 01:00:00 1970 @@ -1,136 +0,0 @@ -/* - * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler - * - * Based on arch/mips/sgi/kernel/indyIRQ.S - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include - -/* - * A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop and moving across - * all the pending IRQ bits in the cause register is _NOT_ the answer, the - * common case is one pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register IRQ mask, that - * would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in - * between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the INDY look basically (barring software IRQs - * which we don't use at all) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Local IRQ level zero - * 3 Local IRQ level one - * 4 8254 Timer zero - * 5 8254 Timer one - * 6 Bus Error - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Local IRQ zero - * Local IRQ one - * Bus Error - * 8254 Timer zero - * Lowest ---- 8254 Timer one - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - - .text - .set noreorder - .set noat - .align 5 - NESTED(ddbIRQ, PT_SIZE, sp) - SAVE_ALL - CLI - .set at - mfc0 s1, CP0_CAUSE # get irq mask - -#if 1 - mfc0 t2,CP0_STATUS # get enabled interrupts - and s0, s1, t2 # isolate allowed ones -#endif - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 # cpu timer */ - bnez a0, cpu_timer_irq - andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP3 # delay slot, check local level one - - /* Wheee, local level zero interrupt. */ - jal ddb_local0_irqdispatch - move a0, sp # delay slot - - j ret_from_irq - nop # delay slot - -1: - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP6 # delay slot, check bus error - - /* Wheee, local level one interrupt. */ - move a0, sp - jal ddb_local1_irqdispatch - nop - - j ret_from_irq - nop - -1: - beq a0, zero, 1f - nop - - /* Wheee, an asynchronous bus error... */ - move a0, sp - jal ddb_buserror_irq - nop - - j ret_from_irq - nop - -1: - /* Here by mistake? This is possible, what can happen - * is that by the time we take the exception the IRQ - * pin goes low, so just leave if this is the case. - */ - andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) - beq a0, zero, 1f - - /* Must be one of the 8254 timers... */ - move a0, sp - jal ddb_8254timer_irq - nop -1: - /* phamtom interrupt */ - move a0, s1 - jal ddb_phantom_irq - nop - j ret_from_irq - nop - -cpu_timer_irq: - li a0, 0 - move a1, sp - jal do_IRQ - /* jal ll_timer_interrupt */ - nop - j ret_from_irq - nop - END(ddbIRQ) diff -urN linux-2.4.18/arch/mips/ddb5476/irq.c linux-2.4.19-pre5/arch/mips/ddb5476/irq.c --- linux-2.4.18/arch/mips/ddb5476/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/irq.c Thu Jan 1 01:00:00 1970 @@ -1,251 +0,0 @@ -/* - * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern void __init i8259_init(void); -extern void i8259_disable_irq(unsigned int irq_nr); -extern void i8259_enable_irq(unsigned int irq_nr); - -extern asmlinkage void ddbIRQ(void); -extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); -extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); - - -void no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} - - -#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ -#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ -#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ - -#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ -#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ -#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ - -#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ -#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ - -#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ -#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ - -#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ -#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ - -static struct { - struct resource m1543_config; - struct resource pic_elcr; -} m1543_ioport = { - { "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1, - IORESOURCE_BUSY}, - { "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1, - IORESOURCE_BUSY} -}; - -static void m1543_irq_setup(void) -{ - /* - * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all - * the possible IO sources in the M1543 are in use by us. We will - * use the following mapping: - * - * IRQ1 - keyboard (default set by M1543) - * IRQ3 - reserved for UART B (default set by M1543) (note that - * the schematics for the DDB Vrc-5476 board seem to - * indicate that IRQ3 is connected to the DS1386 - * watchdog timer interrupt output so we might have - * a conflict) - * IRQ4 - reserved for UART A (default set by M1543) - * IRQ5 - parallel (default set by M1543) - * IRQ8 - DS1386 time of day (RTC) interrupt - * IRQ9 - USB (hardwired in ddb_setup) - * IRQ10 - PMU (hardwired in ddb_setup) - * IRQ12 - mouse - * IRQ14,15 - IDE controller (need to be confirmed, jsun) - */ - - /* - * Assing mouse interrupt to IRQ12 - */ - - /* Enter configuration mode */ - outb(0x51, M1543_PNP_CONFIG); - outb(0x23, M1543_PNP_CONFIG); - - /* Select logical device 7 (Keyboard) */ - outb(0x07, M1543_PNP_INDEX); - outb(0x07, M1543_PNP_DATA); - - /* Select IRQ12 */ - outb(0x72, M1543_PNP_INDEX); - outb(0x0c, M1543_PNP_DATA); - - /* Leave configration mode */ - outb(0xbb, M1543_PNP_CONFIG); - - - /* Initialize the 8259 PIC in the M1543 */ - i8259_init(); - - /* Enable the interrupt cascade from M1543 */ - nile4_enable_irq(NILE4_INT_INTC); - - /* request io ports */ - if (request_resource(&ioport_resource, &m1543_ioport.m1543_config) - || request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) { - printk("m1543_irq_setup : requesting io ports failed.\n"); - for (;;); - } -} - -static void nile4_irq_setup(void) -{ - int i; - - /* Map all interrupts to CPU int #0 */ - nile4_map_irq_all(0); - - /* PCI INTA#-E# must be level triggered */ - nile4_set_pci_irq_level_or_edge(0, 1); - nile4_set_pci_irq_level_or_edge(1, 1); - nile4_set_pci_irq_level_or_edge(2, 1); - nile4_set_pci_irq_level_or_edge(3, 1); - - /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ - nile4_set_pci_irq_polarity(0, 0); - nile4_set_pci_irq_polarity(1, 0); - nile4_set_pci_irq_polarity(2, 1); - nile4_set_pci_irq_polarity(3, 0); - - for (i = 0; i < 16; i++) - nile4_clear_irq(i); - - /* Enable CPU int #0 */ - nile4_enable_irq_output(0); - - /* memory resource acquire in ddb_setup */ -} - - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; - - -void disable_irq(unsigned int irq_nr) -{ - if (is_i8259_irq(irq_nr)) - i8259_disable_irq(irq_nr); - else - nile4_disable_irq(irq_to_nile4(irq_nr)); -} - -void enable_irq(unsigned int irq_nr) -{ - if (is_i8259_irq(irq_nr)) - i8259_enable_irq(irq_nr); - else - nile4_enable_irq(irq_to_nile4(irq_nr)); -} - -int table[16] = { 0, }; - -void ddb_local0_irqdispatch(struct pt_regs *regs) -{ - u32 mask; - int nile4_irq; -#if 0 - volatile static int nesting = 0; - if (nesting++ == 0) - ddb5476_led_d3(1); - ddb5476_led_hex(nesting < 16 ? nesting : 15); -#endif - - mask = nile4_get_irq_stat(0); - nile4_clear_irq_mask(mask); - - /* Handle the timer interrupt first */ - if (mask & (1 << NILE4_INT_GPT)) { - nile4_disable_irq(NILE4_INT_GPT); - do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); - nile4_enable_irq(NILE4_INT_GPT); - mask &= ~(1 << NILE4_INT_GPT); - } - for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) - if (mask & 1) { - nile4_disable_irq(nile4_irq); - if (nile4_irq == NILE4_INT_INTC) { - int i8259_irq = nile4_i8259_iack(); - i8259_do_irq(i8259_irq, regs); - } else { - do_IRQ(nile4_to_irq(nile4_irq), regs); - } - nile4_enable_irq(nile4_irq); - } -#if 0 - if (--nesting == 0) - ddb5476_led_d3(0); - ddb5476_led_hex(nesting < 16 ? nesting : 15); -#endif -} - -void ddb_local1_irqdispatch(void) -{ - printk("ddb_local1_irqdispatch called\n"); -} - -void ddb_buserror_irq(void) -{ - printk("ddb_buserror_irq called\n"); -} - -void ddb_8254timer_irq(void) -{ - printk("ddb_8254timer_irq called\n"); -} - -void ddb_phantom_irq(unsigned long cause) -{ - printk("phantom interrupts detected : \n"); - printk("\tcause \t\t0x%08x\n", cause); - printk("\tcause reg\t0x%08x\n", - read_32bit_cp0_register(CP0_CAUSE)); - printk("\tstatus reg\t0x%08x\n", - read_32bit_cp0_register(CP0_STATUS)); -} - -void __init ddb_irq_setup(void) -{ -#ifdef CONFIG_REMOTE_DEBUG - printk("Wait for gdb client connection ...\n"); - set_debug_traps(); - breakpoint(); /* you may move this line to whereever you want :-) */ -#endif - i8259_setup_irq(2, &irq2); - - nile4_irq_setup(); - m1543_irq_setup(); - - /* we pin #0 - #4 (no internal timer) */ - change_cp0_status(ST0_IM, - IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); - - set_except_vector(0, ddbIRQ); -} diff -urN linux-2.4.18/arch/mips/ddb5476/nile4.c linux-2.4.19-pre5/arch/mips/ddb5476/nile4.c --- linux-2.4.18/arch/mips/ddb5476/nile4.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/nile4.c Thu Jan 1 01:00:00 1970 @@ -1,293 +0,0 @@ -/* - * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include - -#include - - -/* - * Physical Device Address Registers - * - * Note: 32 bit addressing only! - */ -void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, - int on_memory_bus, int visible) -{ - u32 maskbits; - u32 widthbits; - - if (pdar > NILE4_BOOTCS || (pdar & 7)) { - printk("nile4_set_pdar: invalid pdar %d\n", pdar); - return; - } - if (pdar == NILE4_INTCS && size != 0x00200000) { - printk("nile4_set_pdar: INTCS size must be 2 MB\n"); - return; - } - switch (size) { -#if 0 /* We don't support 4 GB yet */ - case 0x100000000: /* 4 GB */ - maskbits = 4; - break; -#endif - case 0x80000000: /* 2 GB */ - maskbits = 5; - break; - case 0x40000000: /* 1 GB */ - maskbits = 6; - break; - case 0x20000000: /* 512 MB */ - maskbits = 7; - break; - case 0x10000000: /* 256 MB */ - maskbits = 8; - break; - case 0x08000000: /* 128 MB */ - maskbits = 9; - break; - case 0x04000000: /* 64 MB */ - maskbits = 10; - break; - case 0x02000000: /* 32 MB */ - maskbits = 11; - break; - case 0x01000000: /* 16 MB */ - maskbits = 12; - break; - case 0x00800000: /* 8 MB */ - maskbits = 13; - break; - case 0x00400000: /* 4 MB */ - maskbits = 14; - break; - case 0x00200000: /* 2 MB */ - maskbits = 15; - break; - case 0: /* OFF */ - maskbits = 0; - break; - default: - printk("nile4_set_pdar: unsupported size %p\n", - (void *) size); - return; - } - switch (width) { - case 8: - widthbits = 0; - break; - case 16: - widthbits = 1; - break; - case 32: - widthbits = 2; - break; - case 64: - widthbits = 3; - break; - default: - printk("nile4_set_pdar: unsupported width %d\n", width); - return; - } - nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | - (visible ? 0x20 : 0) | (widthbits << 6) | - (phys & 0xffe00000)); - nile4_out32(pdar + 4, 0); - /* - * When programming a PDAR, the register should be read immediately - * after writing it. This ensures that address decoders are properly - * configured. - */ - nile4_in32(pdar); - nile4_in32(pdar + 4); -} - - -/* - * PCI Master Registers - * - * Note: 32 bit addressing only! - */ -void nile4_set_pmr(u32 pmr, u32 type, u32 addr) -{ - if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { - printk("nile4_set_pmr: invalid pmr %d\n", pmr); - return; - } - switch (type) { - case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ - case NILE4_PCICMD_IO: /* PCI I/O Space */ - case NILE4_PCICMD_MEM: /* PCI Memory Space */ - case NILE4_PCICMD_CFG: /* PCI Configuration Space */ - break; - default: - printk("nile4_set_pmr: invalid type %d\n", type); - return; - } - nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); - nile4_out32(pmr + 4, 0); -} - - -/* - * Interrupt Programming - */ -void nile4_map_irq(int nile4_irq, int cpu_irq) -{ - u32 offset, t; - - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(7 << (nile4_irq * 4)); - t |= cpu_irq << (nile4_irq * 4); - nile4_out32(offset, t); -} - -void nile4_map_irq_all(int cpu_irq) -{ - u32 all, t; - - all = cpu_irq; - all |= all << 4; - all |= all << 8; - all |= all << 16; - t = nile4_in32(NILE4_INTCTRL); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL, t); - t = nile4_in32(NILE4_INTCTRL + 4); - t &= 0x88888888; - t |= all; - nile4_out32(NILE4_INTCTRL + 4, t); -} - -void nile4_enable_irq(int nile4_irq) -{ - u32 offset, t; - - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t |= 8 << (nile4_irq * 4); - nile4_out32(offset, t); -} - -void nile4_disable_irq(int nile4_irq) -{ - u32 offset, t; - - offset = NILE4_INTCTRL; - if (nile4_irq >= 8) { - offset += 4; - nile4_irq -= 8; - } - t = nile4_in32(offset); - t &= ~(8 << (nile4_irq * 4)); - nile4_out32(offset, t); -} - -void nile4_disable_irq_all(void) -{ - nile4_out32(NILE4_INTCTRL, 0); - nile4_out32(NILE4_INTCTRL + 4, 0); -} - -u16 nile4_get_irq_stat(int cpu_irq) -{ - return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2); -} - -void nile4_enable_irq_output(int cpu_irq) -{ - u32 t; - - t = nile4_in32(NILE4_INTSTAT1 + 4); - t |= 1 << (16 + cpu_irq); - nile4_out32(NILE4_INTSTAT1, t); -} - -void nile4_disable_irq_output(int cpu_irq) -{ - u32 t; - - t = nile4_in32(NILE4_INTSTAT1 + 4); - t &= ~(1 << (16 + cpu_irq)); - nile4_out32(NILE4_INTSTAT1, t); -} - -void nile4_set_pci_irq_polarity(int pci_irq, int high) -{ - u32 t; - - t = nile4_in32(NILE4_INTPPES); - if (high) - t &= ~(1 << (pci_irq * 2)); - else - t |= 1 << (pci_irq * 2); - nile4_out32(NILE4_INTPPES, t); -} - -void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) -{ - u32 t; - - t = nile4_in32(NILE4_INTPPES); - if (level) - t |= 2 << (pci_irq * 2); - else - t &= ~(2 << (pci_irq * 2)); - nile4_out32(NILE4_INTPPES, t); -} - -void nile4_clear_irq(int nile4_irq) -{ - nile4_out32(NILE4_INTCLR, 1 << nile4_irq); -} - -void nile4_clear_irq_mask(u32 mask) -{ - nile4_out32(NILE4_INTCLR, mask); -} - -u8 nile4_i8259_iack(void) -{ - u8 irq; - - /* Set window 0 for interrupt acknowledge */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); - irq = *(volatile u8 *) NILE4_PCI_IACK_BASE; - /* Set window 0 for PCI I/O space */ - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); - return irq; -} - -#if 0 -void nile4_dump_irq_status(void) -{ - printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4), - (void *) nile4_in32(NILE4_CPUSTAT)); - printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4), - (void *) nile4_in32(NILE4_INTCTRL)); - printk("INTSTAT0 = %p:%p\n", - (void *) nile4_in32(NILE4_INTSTAT0 + 4), - (void *) nile4_in32(NILE4_INTSTAT0)); - printk("INTSTAT1 = %p:%p\n", - (void *) nile4_in32(NILE4_INTSTAT1 + 4), - (void *) nile4_in32(NILE4_INTSTAT1)); - printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4), - (void *) nile4_in32(NILE4_INTCLR)); - printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4), - (void *) nile4_in32(NILE4_INTPPES)); -} -#endif diff -urN linux-2.4.18/arch/mips/ddb5476/pci.c linux-2.4.19-pre5/arch/mips/ddb5476/pci.c --- linux-2.4.18/arch/mips/ddb5476/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/pci.c Thu Jan 1 01:00:00 1970 @@ -1,499 +0,0 @@ -/* - * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Albert Dorofeev - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include - -#include - -static u32 nile4_pre_pci_access0(int slot_num) -{ - u32 pci_addr = 0; - u32 virt_addr = NILE4_PCI_CFG_BASE; - - /* work around the bug for Vrc5476 */ - if (slot_num == 13) - return NILE4_BASE + NILE4_PCI_BASE; - - /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0, - 0); - - // [jsun] we start scanning from addr:10, - // with 128M we can go up to addr:26 (slot 16) - if (slot_num <= 16) { - virt_addr += 0x00000400 << slot_num; - } else { - /* for high slot, we have to set higher PCI base addr */ - pci_addr = 0x00000400 << slot_num; - } - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); - return virt_addr; -} - -static void nile4_post_pci_access0(void) -{ - /* - * Set window 1 back to address 08000000 - 32 bit - 128 MB - * (PCI IO space) - */ - nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), - 0x08000000, 32, 1, 1); - // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); -} - - -static int nile4_pci_read_config_dword(struct pci_dev *dev, - int where, u32 * val) -{ - int slot_num, func_num; - u32 base; - u32 addr; - - /* - * Do we need to generate type 1 configure transaction? - */ - if (dev->bus->number) { - /* FIXME - not working yet */ - return PCIBIOS_FUNC_NOT_SUPPORTED; - - /* - * the largest type 1 configuration addr is 16M, < 256M - * config space - */ - slot_num = 0; - addr = - (dev->bus->number << 16) | (dev->devfn < - 8) | where | 1; - } else { - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - addr = (func_num << 8) + where; - } - - base = nile4_pre_pci_access0(slot_num); - *val = *(volatile u32 *) (base + addr); - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, - u32 val) -{ - int slot_num, func_num; - u32 base; - u32 addr; - - /* - * Do we need to generate type 1 configure transaction? - */ - if (dev->bus->number) { - /* FIXME - not working yet */ - return PCIBIOS_FUNC_NOT_SUPPORTED; - - /* the largest type 1 configuration addr is 16M, < 256M config space */ - slot_num = 0; - addr = - (dev->bus->number << 16) | (dev->devfn < - 8) | where | 1; - } else { - slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - addr = (func_num << 8) + where; - } - - base = nile4_pre_pci_access0(slot_num); - *(volatile u32 *) (base + addr) = val; - nile4_post_pci_access0(); - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_word(struct pci_dev *dev, int where, - u16 * val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - result >>= 16; - *val = result & 0xffff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, - u8 * val) -{ - int status; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 1) - result >>= 8; - if (where & 2) - result >>= 16; - *val = result & 0xff; - return PCIBIOS_SUCCESSFUL; -} - -static int nile4_pci_write_config_word(struct pci_dev *dev, int where, - u16 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - result &= ~(0xffff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where & ~3, result); -} - -static int nile4_pci_write_config_byte(struct pci_dev *dev, int where, - u8 val) -{ - int status, shift = 0; - u32 result; - - status = nile4_pci_read_config_dword(dev, where & ~3, &result); - if (status != PCIBIOS_SUCCESSFUL) - return status; - if (where & 2) - shift += 16; - if (where & 1) - shift += 8; - result &= ~(0xff << shift); - result |= val << shift; - return nile4_pci_write_config_dword(dev, where & ~3, result); -} - -struct pci_ops nile4_pci_ops = { - nile4_pci_read_config_byte, - nile4_pci_read_config_word, - nile4_pci_read_config_dword, - nile4_pci_write_config_byte, - nile4_pci_write_config_word, - nile4_pci_write_config_dword -}; - -struct { - struct resource ram; - struct resource flash; - struct resource isa_io; - struct resource pci_io; - struct resource isa_mem; - struct resource pci_mem; - struct resource nile4; - struct resource boot; -} ddb5476_resources = { - // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { - "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, { - "Flash ROM", 0x04000000, 0x043fffff}, { - "Nile4 ISA I/O", 0x06000000, 0x060fffff}, { - "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, { - "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, { - "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM}, - // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, - { - "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, { - "Boot ROM", 0x1fc00000, 0x1fffffff} -}; - -struct resource M5229_resources[5] = { - {"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO}, - {"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO}, - {"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO}, - {"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO}, - {"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO} -}; - -static void __init ddb5476_pci_fixup(void) -{ - struct pci_dev *dev; - - pci_for_each_dev(dev) { - if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_VRC5476) { - /* - * The first 64-bit PCI base register should point to - * the Nile4 control registers. Unfortunately this - * isn't the case, so we fix it ourselves. This allows - * the serial driver to find the UART. - */ - dev->resource[0] = ddb5476_resources.nile4; - request_resource(&iomem_resource, - &dev->resource[0]); - /* - * The second 64-bit PCI base register points to the - * first memory bank. Unfortunately the address is - * wrong, so we fix it (again). - */ - - /* [jsun] We cannot request the resource anymore, - * because kernel/setup.c has already reserved "System - * RAM" resource at the same spot. - * The fundamental problem here is that PCI host - * controller should not put system RAM mapping in BAR - * and make subject to PCI resource assignement. - * Current fix is a total hack. We set parent to 1 so - * so that PCI resource assignement code is fooled to - * think the resource is assigned, and will not attempt - * to mess with it. - */ - dev->resource[2] = ddb5476_resources.ram; - if (request_resource(&iomem_resource, - &dev->resource[2]) ) { - dev->resource[2].parent = 0x1; - } - - } else if (dev->vendor == PCI_VENDOR_ID_AL - && dev->device == PCI_DEVICE_ID_AL_M7101) { - /* - * It's nice to have the LEDs on the GPIO pins - * available for debugging - */ - extern struct pci_dev *pci_pmu; - u8 t8; - - pci_pmu = dev; /* for LEDs D2 and D3 */ - /* Program the lines for LEDs D2 and D3 to output */ - nile4_pci_read_config_byte(dev, 0x7d, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7d, t8); - /* Turn LEDs D2 and D3 off */ - nile4_pci_read_config_byte(dev, 0x7e, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7e, t8); - } else if (dev->vendor == PCI_VENDOR_ID_AL && - dev->device == 0x5229) { - int i; - for (i = 0; i < 5; i++) { - dev->resource[i] = M5229_resources[i]; - request_resource(&ioport_resource, - &dev->resource[i]); - } - } - } -} - -static void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev; - int slot_num; - - pci_for_each_dev(dev) { - slot_num = PCI_SLOT(dev->devfn); - switch (slot_num) { - case 3: /* re-programmed to USB */ - dev->irq = 9; /* hard-coded; see irq.c */ - break; - case 4: /* re-programmed to PMU */ - dev->irq = 10; /* hard-coded; see irq.c */ - break; - case 6: /* on-board pci-pci bridge */ - dev->irq = 0xff; - break; - case 7: /* on-board ether */ - dev->irq = nile4_to_irq(NILE4_INT_INTB); - break; - case 8: /* ISA-PCI bridge */ - dev->irq = nile4_to_irq(NILE4_INT_INTC); - break; - case 9: /* ext slot #3 */ - dev->irq = nile4_to_irq(NILE4_INT_INTD); - break; - case 10: /* ext slot #4 */ - dev->irq = nile4_to_irq(NILE4_INT_INTA); - break; - case 13: /* Vrc5476 */ - dev->irq = 0xff; - break; - case 14: /* HD controller, M5229 */ - dev->irq = 14; - break; - default: - printk - ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n", - slot_num); - panic - ("JSUN : in pcibios_fixup_irqs - unkown slot.\n"); - } - } -} - -void __init pcibios_init(void) -{ - printk("PCI: Emulate bios initialization \n"); - /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ - *(long *) (NILE4_BASE + NILE4_BAR0) = 0x8; - - printk("PCI: Probing PCI hardware\n"); - ioport_resource.end = 0x1ffffff; /* 32 MB */ - iomem_resource.end = 0x1fffffff; /* 512 MB */ - - /* `ram' and `nile4' are requested through the Nile4 pci_dev */ - request_resource(&iomem_resource, &ddb5476_resources.flash); - request_resource(&iomem_resource, &ddb5476_resources.isa_io); - request_resource(&iomem_resource, &ddb5476_resources.pci_io); - request_resource(&iomem_resource, &ddb5476_resources.isa_mem); - request_resource(&iomem_resource, &ddb5476_resources.pci_mem); - request_resource(&iomem_resource, &ddb5476_resources.boot); - - pci_scan_bus(0, &nile4_pci_ops, NULL); - ddb5476_pci_fixup(); - pci_assign_unassigned_resources(); - pcibios_fixup_irqs(); -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ - /* [jsun] we don't know how to fix sub-buses yet */ - if (bus->number == 0) { - bus->resource[1] = &ddb5476_resources.pci_mem; - } -} - -char *pcibios_setup(char *str) -{ - return str; -} - -void __init pcibios_update_irq(struct pci_dev *dev, int irq) -{ - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -} - -void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, - struct pbus_set_ranges_data *ranges) -{ - /* - * our caller figure out range by going through the dev structures. - * I guess this is the place to fix things up if the bus is using a - * different view of the addressing space. - */ - -#if 0 /* original DDB5074 code */ - if (bus->number == 0) { - 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; - } -#endif -} - -int pcibios_enable_resources(struct pci_dev *dev) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - /* - * Don't touch the Nile 4 - */ - if (dev->vendor == PCI_VENDOR_ID_NEC && - dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0; - - 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; -} - -int pcibios_enable_device(struct pci_dev *dev) -{ - return pcibios_enable_resources(dev); -} - -void pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - u32 new, check; - int reg; - - new = res->start | (res->flags & PCI_REGION_FLAG_MASK); - if (resource < 6) { - reg = PCI_BASE_ADDRESS_0 + 4 * resource; - } else if (resource == PCI_ROM_RESOURCE) { - res->flags |= PCI_ROM_ADDRESS_ENABLE; - reg = dev->rom_base_reg; - } else { - /* - * Somebody might have asked allocation of a non-standard - * resource - */ - return; - } - - pci_write_config_dword(dev, reg, new); - pci_read_config_dword(dev, reg, &check); - if ((new ^ check) & - ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : - PCI_BASE_ADDRESS_MEM_MASK)) { - printk(KERN_ERR "PCI: Error while updating region " - "%s/%d (%08x != %08x)\n", dev->slot_name, resource, - new, check); - } -} - -void pcibios_align_resource(void *data, struct resource *res, - unsigned long size) -{ - struct pci_dev *dev = data; - - if (res->flags & IORESOURCE_IO) { - unsigned long start = res->start; - - /* We need to avoid collisions with `mirrored' VGA ports - and other strange ISA hardware, so we always want the - addresses kilobyte aligned. */ - if (size > 0x100) { - printk(KERN_ERR "PCI: I/O Region %s/%d too large" - " (%ld bytes)\n", dev->slot_name, - dev->resource - res, size); - } - - start = (start + 1024 - 1) & ~(1024 - 1); - res->start = start; - } -} - -unsigned __init int pcibios_assign_all_busses(void) -{ - return 1; -} - -struct pci_fixup pcibios_fixups[] = { {0} }; diff -urN linux-2.4.18/arch/mips/ddb5476/prom.c linux-2.4.19-pre5/arch/mips/ddb5476/prom.c --- linux-2.4.18/arch/mips/ddb5476/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/prom.c Thu Jan 1 01:00:00 1970 @@ -1,43 +0,0 @@ -/* - * arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - * - * Jun Sun - modified for DDB5476. - */ -#include -#include -#include -#include - -#include -#include - - -char arcs_cmdline[COMMAND_LINE_SIZE]; - -/* [jsun@junsun.net] PMON passes arguments in C main() style */ -void __init prom_init(int argc, const char **arg) -{ - int i; - - /* arg[0] is "g", the rest is boot parameters */ - arcs_cmdline[0] = '\0'; - for (i = 1; i < argc; i++) { - if (strlen(arcs_cmdline) + strlen(arg[i] + 1) - >= sizeof(arcs_cmdline)) - break; - strcat(arcs_cmdline, arg[i]); - strcat(arcs_cmdline, " "); - } - - mips_machgroup = MACH_GROUP_NEC_DDB; - mips_machtype = MACH_NEC_DDB5476; - /* 64 MB non-upgradable */ - add_memory_region(0, 64 << 20, BOOT_MEM_RAM); -} - -void __init prom_free_prom_memory(void) -{ -} diff -urN linux-2.4.18/arch/mips/ddb5476/setup.c linux-2.4.19-pre5/arch/mips/ddb5476/setup.c --- linux-2.4.18/arch/mips/ddb5476/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/setup.c Thu Jan 1 01:00:00 1970 @@ -1,393 +0,0 @@ -/* - * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef CONFIG_REMOTE_DEBUG -extern void rs_kgdb_hook(int); -extern void breakpoint(void); -#endif - -#if defined(CONFIG_SERIAL_CONSOLE) -extern void console_setup(char *); -#endif - -extern struct ide_ops std_ide_ops; -extern struct rtc_ops ddb_rtc_ops; -extern struct kbd_ops std_kbd_ops; - -static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; - -static void ddb_machine_restart(char *command) -{ - u32 t; - - /* PCI cold reset */ - t = nile4_in32(NILE4_PCICTRL + 4); - t |= 0x40000000; - nile4_out32(NILE4_PCICTRL + 4, t); - /* CPU cold reset */ - t = nile4_in32(NILE4_CPUSTAT); - t |= 1; - nile4_out32(NILE4_CPUSTAT, t); - /* Call the PROM */ - back_to_prom(); -} - -static void ddb_machine_halt(void) -{ - printk("DDB Vrc-5476 halted.\n"); - while (1); -} - -static void ddb_machine_power_off(void) -{ - printk("DDB Vrc-5476 halted. Please turn off the power.\n"); - while (1); -} - -extern void ddb_irq_setup(void); - -static void __init ddb_time_init(struct irqaction *irq) -{ - printk("ddb_time_init invoked.\n"); - mips_counter_frequency = 83000000; -} - -static void __init ddb_timer_setup(struct irqaction *irq) -{ - unsigned int count; - - /* we are using the cpu counter for timer interrupts */ - i8259_setup_irq(0, irq); - set_cp0_status(IE_IRQ5); - - /* to generate the first timer interrupt */ - count = read_32bit_cp0_register(CP0_COUNT); - write_32bit_cp0_register(CP0_COMPARE, count + 1000); - -#if 0 /* the old way to do timer interrupt */ - /* set the clock to 100 Hz */ - nile4_out32(NILE4_T2CTRL, 830000); - /* enable the General-Purpose Timer */ - nile4_out32(NILE4_T2CTRL + 4, 0x00000001); - /* reset timer */ - nile4_out32(NILE4_T2CNTR, 0); - /* enable interrupt */ - nile4_enable_irq(NILE4_INT_GPT); - i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); -#endif -} - -static struct { - struct resource dma1; - struct resource pic1; - struct resource timer; - struct resource rtc; - struct resource dma_page_reg; - struct resource pic2; - struct resource dma2; -} ddb5476_ioport = { - { - "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, { - "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, { - "timer", 0x40, 0x5f, IORESOURCE_BUSY}, { - "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, { - "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, { - "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, { - "dma2", 0xc0, 0xdf, IORESOURCE_BUSY} -}; - -static struct { - struct resource nile4; -} ddb5476_iomem = { - { "Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, IORESOURCE_BUSY} -}; - -void __init ddb_setup(void) -{ - extern int panic_timeout; - - irq_setup = ddb_irq_setup; - mips_io_port_base = NILE4_PCI_IO_BASE; - isa_slot_offset = NILE4_PCI_MEM_BASE; - - board_time_init = ddb_time_init; - board_timer_setup = ddb_timer_setup; - - _machine_restart = ddb_machine_restart; - _machine_halt = ddb_machine_halt; - _machine_power_off = ddb_machine_power_off; - - /* request io port/mem resources */ - if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || - request_resource(&ioport_resource, &ddb5476_ioport.pic1) || - request_resource(&ioport_resource, &ddb5476_ioport.timer) || - request_resource(&ioport_resource, &ddb5476_ioport.rtc) || - request_resource(&ioport_resource, - &ddb5476_ioport.dma_page_reg) - || request_resource(&ioport_resource, &ddb5476_ioport.pic2) - || request_resource(&ioport_resource, &ddb5476_ioport.dma2) - || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { - printk - ("ddb_setup - requesting oo port resources failed.\n"); - for (;;); - } -#ifdef CONFIG_BLK_DEV_IDE - ide_ops = &std_ide_ops; -#endif - rtc_ops = &ddb_rtc_ops; - -#ifdef CONFIG_PC_KEYB - kbd_ops = &std_kbd_ops; -#endif - - /* Reboot on panic */ - panic_timeout = 180; - - /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ - /* *(long*)0xbfa00218 = 0x8; */ - -#ifdef CONFIG_FB - conswitchp = &dummy_con; -#endif - - - /* board initialization stuff - non-fundamental, but need to be set - * before kernel runs */ - - /* setup I/O space */ - nile4_set_pdar(NILE4_PCIW0, - PHYSADDR(NILE4_PCI_IO_BASE), 0x02000000, 32, 0, 0); - nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); - - /* map config space to 0xa8000000, 128MB */ - nile4_set_pdar(NILE4_PCIW1, - PHYSADDR(NILE4_PCI_CFG_BASE), 0x08000000, 32, 0, 0); - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0); - - /* ----- M1543 PCI setup ------ */ - - /* we know M1543 PCI-ISA controller is at addr:18 */ - /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ - *(volatile unsigned char *) 0xa8040072 &= 0xf0; - *(volatile unsigned char *) 0xa8040072 |= 0xa; - - /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) - * no IOCHRDY signal, (bit 7 - 1) - * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) - * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0) - */ - *(unsigned char *) 0xa8040074 = 0xc1; - - /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) - * SCI routing to IRQ 13 disabled (bit 7 - 1) - * SCI interrupt level to edge conversion bypassed (bit 4 - 0) - */ - *(unsigned char *) 0xa8040076 = 0x83; - - /* setup IDE controller - * enable IDE controller (bit 6 - 1) - * IDE IDSEL to be addr:24 (bit 4:5 - 11) - * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) - * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) - * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 - */ - // *(unsigned char*)0xa8040058 = 0x71; - // *(unsigned char*)0xa8040058 = 0x79; - // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state - *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state - -#if 0 - /* this is not necessary if M5229 does not use SIRQ */ - *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 - *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 -#endif - - /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ - /* M5229 IDSEL is addr:24; see above setting */ - *(unsigned char *) 0xa9000050 |= 0x1; - - /* enable bus master (bit 2) and IO decoding (bit 0) */ - *(unsigned char *) 0xa9000004 |= 0x5; - - /* enable native, copied from arch/ppc/k2boot/head.S */ - /* TODO - need volatile, need to be portable */ - *(unsigned char *) 0xa9000009 = 0xff; - - /* ----- end of M1543 PCI setup ------ */ - - /* ----- reset on-board ether chip ------ */ - *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ - *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ - - /* send reset command */ - *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ - - /* disable ether chip */ - *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ - - /* put it into sleep */ - *((volatile u32 *) 0xa8020040) = 0x80000000; - - /* ----- end of reset on-board ether chip ------ */ - - /* ----- set pci window 1 to pci memory space -------- */ - nile4_set_pdar(NILE4_PCIW1, - PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, 0, 0); - // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); - nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); - -} - -#define USE_NILE4_SERIAL 0 - -#if USE_NILE4_SERIAL -#define ns16550_in(reg) nile4_in8((reg)*8) -#define ns16550_out(reg, val) nile4_out8((reg)*8, (val)) -#else -#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) -static inline u8 ns16550_in(u32 reg) -{ - return *(volatile u8 *) (NS16550_BASE + reg); -} - -static inline void ns16550_out(u32 reg, u8 val) -{ - *(volatile u8 *) (NS16550_BASE + reg) = val; -} -#endif - -#define NS16550_RBR 0 -#define NS16550_THR 0 -#define NS16550_DLL 0 -#define NS16550_IER 1 -#define NS16550_DLM 1 -#define NS16550_FCR 2 -#define NS16550_IIR 2 -#define NS16550_LCR 3 -#define NS16550_MCR 4 -#define NS16550_LSR 5 -#define NS16550_MSR 6 -#define NS16550_SCR 7 - -#define NS16550_LSR_DR 0x01 /* Data ready */ -#define NS16550_LSR_OE 0x02 /* Overrun */ -#define NS16550_LSR_PE 0x04 /* Parity error */ -#define NS16550_LSR_FE 0x08 /* Framing error */ -#define NS16550_LSR_BI 0x10 /* Break */ -#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ -#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */ -#define NS16550_LSR_ERR 0x80 /* Error */ - - -void _serinit(void) -{ -#if USE_NILE4_SERIAL - ns16550_out(NS16550_LCR, 0x80); - ns16550_out(NS16550_DLM, 0x00); - ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ - ns16550_out(NS16550_LCR, 0x00); - ns16550_out(NS16550_LCR, 0x03); - ns16550_out(NS16550_FCR, 0x47); -#else - /* done by PMON */ -#endif -} - -void _putc(char c) -{ - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, c); - if (c == '\n') { - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); - ns16550_out(NS16550_THR, '\r'); - } -} - -void _puts(const char *s) -{ - char c; - - while ((c = *s++)) - _putc(c); -} - -char _getc(void) -{ - while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); - - return ns16550_in(NS16550_RBR); -} - -int _testc(void) -{ - return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; -} - - -/* - * Hexadecimal 7-segment LED - */ -void ddb5476_led_hex(int hex) -{ - outb(hex, 0x80); -} - - -/* - * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 - */ -struct pci_dev *pci_pmu = NULL; - -void ddb5476_led_d2(int on) -{ - u8 t; - - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0x7f; - else - t |= 0x80; - pci_write_config_byte(pci_pmu, 0x7e, t); - } -} - -void ddb5476_led_d3(int on) -{ - u8 t; - - if (pci_pmu) { - pci_read_config_byte(pci_pmu, 0x7e, &t); - if (on) - t &= 0xbf; - else - t |= 0x40; - pci_write_config_byte(pci_pmu, 0x7e, t); - } -} diff -urN linux-2.4.18/arch/mips/ddb5476/time.c linux-2.4.19-pre5/arch/mips/ddb5476/time.c --- linux-2.4.18/arch/mips/ddb5476/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5476/time.c Thu Jan 1 01:00:00 1970 @@ -1,32 +0,0 @@ -/* - * arch/mips/ddb5074/time.c -- Timer routines - * - * Copyright (C) 2000 Geert Uytterhoeven - * Sony Software Development Center Europe (SDCE), Brussels - */ -#include - -#include - -static unsigned char ddb_rtc_read_data(unsigned long addr) -{ - outb_p(addr, RTC_PORT(0)); - return inb_p(RTC_PORT(1)); -} - -static void ddb_rtc_write_data(unsigned char data, unsigned long addr) -{ - outb_p(addr, RTC_PORT(0)); - outb_p(data, RTC_PORT(1)); -} - -static int ddb_rtc_bcd_mode(void) -{ - return 1; -} - -struct rtc_ops ddb_rtc_ops = { - ddb_rtc_read_data, - ddb_rtc_write_data, - ddb_rtc_bcd_mode -}; diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/Makefile linux-2.4.19-pre5/arch/mips/ddb5xxx/common/Makefile --- linux-2.4.18/arch/mips/ddb5xxx/common/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/Makefile Sat Mar 30 22:55:26 2002 @@ -13,6 +13,6 @@ O_TARGET:= ddb5xxx.o -obj-y += irq.o irq_cpu.o nile4.o prom.o pci.o pci_auto.o rtc_ds1386.o +obj-y += irq.o nile4.o prom.o rtc_ds1386.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/irq.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/irq.c --- linux-2.4.18/arch/mips/ddb5xxx/common/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/irq.c Sat Mar 30 22:55:26 2002 @@ -26,6 +26,8 @@ set_debug_traps(); breakpoint(); #endif + /* set up default irq controller */ + init_generic_irq(); /* invoke board-specific irq setup */ irq_setup(); diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/irq_cpu.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/irq_cpu.c --- linux-2.4.18/arch/mips/ddb5xxx/common/irq_cpu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/irq_cpu.c Thu Jan 1 01:00:00 1970 @@ -1,115 +0,0 @@ -/*********************************************************************** - * Copyright 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * arch/mips/ddb5xxx/common/irq_cpu.c - * This file define the irq handler for MIPS CPU interrupts. - * - * 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. - *********************************************************************** - */ - -/* - * Almost all MIPS CPUs define 8 interrupt sources. They are typically - * level triggered (i.e., cannot be cleared from CPU; must be cleared from - * device). The first two are software interrupts. The last one is - * usually cpu timer interrupt if coutner register is present. - * - * This file exports one global function: - * mips_cpu_irq_init(u32 irq_base); - */ - -#include -#include -#include - -#include - -/* [jsun] sooner or later we should move this debug stuff to MIPS common */ -#include - -static int mips_cpu_irq_base=-1; - -static void -mips_cpu_irq_enable(unsigned int irq) -{ - MIPS_ASSERT(mips_cpu_irq_base != -1); - MIPS_ASSERT(irq >= mips_cpu_irq_base); - MIPS_ASSERT(irq < mips_cpu_irq_base+8); - - clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); - set_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); -} - -static void -mips_cpu_irq_disable(unsigned int irq) -{ - MIPS_ASSERT(mips_cpu_irq_base != -1); - MIPS_ASSERT(irq >= mips_cpu_irq_base); - MIPS_ASSERT(irq < mips_cpu_irq_base+8); - - clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); -} - -static unsigned int mips_cpu_irq_startup(unsigned int irq) -{ - mips_cpu_irq_enable(irq); - return 0; -} - -#define mips_cpu_irq_shutdown mips_cpu_irq_disable - -static void -mips_cpu_irq_ack(unsigned int irq) -{ - MIPS_ASSERT(mips_cpu_irq_base != -1); - MIPS_ASSERT(irq >= mips_cpu_irq_base); - MIPS_ASSERT(irq < mips_cpu_irq_base+8); - - /* although we attemp to clear the IP bit in cause reigster, I think - * usually it is cleared by device (irq source) - */ - clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); - - /* I am not fully convinced that I should disable irq here */ -} - -static void -mips_cpu_irq_end(unsigned int irq) -{ - MIPS_ASSERT(mips_cpu_irq_base != -1); - MIPS_ASSERT(irq >= mips_cpu_irq_base); - MIPS_ASSERT(irq < mips_cpu_irq_base+8); - /* I am not fully convinced that I should enable irq here */ -} - -static hw_irq_controller mips_cpu_irq_controller = { - "CPU_irq", - mips_cpu_irq_startup, - mips_cpu_irq_shutdown, - mips_cpu_irq_enable, - mips_cpu_irq_disable, - mips_cpu_irq_ack, - mips_cpu_irq_end, - NULL /* no affinity stuff for UP */ -}; - - -void -mips_cpu_irq_init(u32 irq_base) -{ - extern irq_desc_t irq_desc[]; - u32 i; - - for (i= irq_base; i< irq_base+8; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &mips_cpu_irq_controller; - } - - mips_cpu_irq_base = irq_base; -} diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/nile4.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/nile4.c --- linux-2.4.18/arch/mips/ddb5xxx/common/nile4.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/nile4.c Sat Mar 30 22:55:26 2002 @@ -21,7 +21,6 @@ #include #include -#include u32 ddb_calc_pdar(u32 phys, u32 size, int width, @@ -73,7 +72,7 @@ maskbits = 0; break; default: - panic("nile4_set_pdar: unsupported size %p\n", (void *) size); + panic("nile4_set_pdar: unsupported size %p", (void *) size); } switch (width) { case 8: @@ -89,7 +88,7 @@ widthbits = 3; break; default: - panic("nile4_set_pdar: unsupported width %d\n", width); + panic("nile4_set_pdar: unsupported width %d", width); } return maskbits | (on_memory_bus ? 0x10 : 0) | @@ -128,7 +127,7 @@ case DDB_PCICMD_CFG: /* PCI Configuration Space */ break; default: - panic("nile4_set_pmr: invalid type %d\n", type); + panic("nile4_set_pmr: invalid type %d", type); } ddb_out32(pmr, (type << 1) | (addr & 0xffe00000) | options ); ddb_out32(pmr + 4, 0); diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/pci.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/pci.c --- linux-2.4.18/arch/mips/ddb5xxx/common/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/pci.c Thu Jan 1 01:00:00 1970 @@ -1,179 +0,0 @@ -/*********************************************************************** - * Copyright 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * arch/mips/ddb5xxx/common/pci.c - * Common PCI routines for DDB5xxx - as a matter of fact, meant for all - * MIPS machines. - * - * 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 file contains common PCI routines meant to be shared for - * all MIPS machines. - * - * Strategies: - * - * . We rely on pci_auto.c file to assign PCI resources (MEM and IO) - * TODO: this shold be optional for some machines where they do have - * a real "pcibios" that does resource assignment. - * - * . We then use pci_scan_bus() to "discover" all the resources for - * later use by Linux. - * - * . We finally reply on a board supplied function, pcibios_fixup_irq(), to - * to assign the interrupts. We may use setup-irq.c under drivers/pci - * later. - * - * . Specifically, we will *NOT* use pci_assign_unassigned_resources(), - * because we assume all PCI devices should have the resources correctly - * assigned and recorded. - * - * Limitations: - * - * . We "collapse" all IO and MEM spaces in sub-buses under a top-level bus - * into a contiguous range. - * - * . In the case of Memory space, the rnage is 1:1 mapping with CPU physical - * address space. - * - * . In the case of IO space, it starts from 0, and the beginning address - * is mapped to KSEG0ADDR(mips_io_port) in the CPU physical address. - * - * . These are the current MIPS limitations (by ioremap, etc). In the - * future, we may remove them. - * - * Credits: - * Most of the code are derived from the pci routines from PPC and Alpha, - * which were mostly writtne by - * Cort Dougan, cort@fsmlabs.com - * Matt Porter, mporter@mvista.com - * Dave Rusling david.rusling@reo.mts.dec.com - * David Mosberger davidm@cs.arizona.edu - */ - -#include -#include -#include -#include - -#include -#include - - -struct pci_fixup pcibios_fixups[] = { {0} }; - - -extern int pciauto_assign_resources(int busno, struct pci_channel * hose); -void __init pcibios_init(void) -{ - struct pci_channel *p; - struct pci_bus *bus; - int busno; - - /* assign resources */ - busno=0; - for (p= mips_pci_channels; p->pci_ops != NULL; p++) { - busno = pciauto_assign_resources(busno, p) + 1; - } - - /* scan the buses */ - busno = 0; - for (p= mips_pci_channels; p->pci_ops != NULL; p++) { - bus = pci_scan_bus(busno, p->pci_ops, p); - busno = bus->subordinate+1; - } - - /* fixup irqs (board specific routines) */ - pcibios_fixup_irqs(); - - /* - * should we do a fixup of ioport_resource and iomem_resource - * based on mips_pci_channels? - * Let us wait and see if this is a common need and whether there - * are exceptions. Until then, each board should adjust them - * perhaps in their setup() function. - */ -} - -int pcibios_enable_device(struct pci_dev *dev) -{ - /* pciauto_assign_resources() will enable all devices found */ - return 0; -} - -unsigned long __init -pci_bridge_check_io(struct pci_dev *bridge) -{ - u16 io; - - pci_read_config_word(bridge, PCI_IO_BASE, &io); - if (!io) { - pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0); - pci_read_config_word(bridge, PCI_IO_BASE, &io); - pci_write_config_word(bridge, PCI_IO_BASE, 0x0); - } - if (io) - return IORESOURCE_IO; - printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n", - bridge->name); - return 0; -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ - /* Propogate hose info into the subordinate devices. */ - - struct pci_channel *hose = bus->sysdata; - struct pci_dev *dev = bus->self; - - if (!dev) { - /* Root bus */ - bus->resource[0] = hose->io_resource; - bus->resource[1] = hose->mem_resource; - } else { - /* This is a bridge. Do not care how it's initialized, - just link its resources to the bus ones */ - int i; - - for(i=0; i<3; i++) { - bus->resource[i] = - &dev->resource[PCI_BRIDGE_RESOURCES+i]; - bus->resource[i]->name = bus->name; - } - bus->resource[0]->flags |= pci_bridge_check_io(dev); - bus->resource[1]->flags |= IORESOURCE_MEM; - /* For now, propogate hose limits to the bus; - we'll adjust them later. */ - bus->resource[0]->end = hose->io_resource->end; - bus->resource[1]->end = hose->mem_resource->end; - /* Turn off downstream PF memory address range by default */ - bus->resource[2]->start = 1024*1024; - bus->resource[2]->end = bus->resource[2]->start - 1; - } -} - -char *pcibios_setup(char *str) -{ - return str; -} - -void -pcibios_align_resource(void *data, struct resource *res, unsigned long size) -{ - /* this should not be called */ - MIPS_ASSERT(1 == 0); -} - -void -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - /* this should not be called */ - MIPS_ASSERT(1 == 0); -} diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/pci_auto.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/pci_auto.c --- linux-2.4.18/arch/mips/ddb5xxx/common/pci_auto.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/pci_auto.c Thu Jan 1 01:00:00 1970 @@ -1,396 +0,0 @@ -/* - * arch/ppc/kernel/pci_auto.c - * - * PCI autoconfiguration library - * - * Author: Matt Porter - * - * Copyright 2000, 2001 MontaVista Software Inc. - * - * 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. - */ - -/* - * Modified for MIPS by Jun Sun, jsun@mvista.com - * - * . Simplify the interface between pci_auto and the rest: a single function. - * . Assign resources from low address to upper address. - * . change most int to u32. - */ - -#include -#include -#include -#include - -#include -#include - -#define DEBUG -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* These are used for config access before all the PCI probing - has been done. */ -int early_read_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 *val); -int early_read_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 *val); -int early_read_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 *val); -int early_write_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 val); -int early_write_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 val); -int early_write_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 val); - -static u32 pciauto_lower_iospc; -static u32 pciauto_upper_iospc; - -static u32 pciauto_lower_memspc; -static u32 pciauto_upper_memspc; - -void __init -pciauto_setup_bars(struct pci_channel *hose, - int current_bus, - int pci_devfn) -{ - u32 bar_response, bar_size, bar_value; - u32 bar, addr_mask, bar_nr = 0; - u32 * upper_limit; - u32 * lower_limit; - int found_mem64 = 0; - - DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", - current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); - - for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) - { - /* Tickle the BAR and get the response */ - early_write_config_dword(hose, - current_bus, - pci_devfn, - bar, - 0xffffffff); - early_read_config_dword(hose, - current_bus, - pci_devfn, - bar, - &bar_response); - - /* If BAR is not implemented go to the next BAR */ - if (!bar_response) - continue; - - /* Check the BAR type and set our address mask */ - if (bar_response & PCI_BASE_ADDRESS_SPACE) - { - addr_mask = PCI_BASE_ADDRESS_IO_MASK; - upper_limit = &pciauto_upper_iospc; - lower_limit = &pciauto_lower_iospc; - DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); - } - else - { - if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) - found_mem64 = 1; - - addr_mask = PCI_BASE_ADDRESS_MEM_MASK; - upper_limit = &pciauto_upper_memspc; - lower_limit = &pciauto_lower_memspc; - DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); - } - - /* Calculate requested size */ - bar_size = ~(bar_response & addr_mask) + 1; - - /* Allocate a base address */ - bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; - MIPS_ASSERT(bar_value + bar_size <= *upper_limit); - - /* Write it out and update our limit */ - early_write_config_dword(hose, - current_bus, - pci_devfn, - bar, - bar_value); - - *lower_limit = bar_value + bar_size; - - /* - * If we are a 64-bit decoder then increment to the - * upper 32 bits of the bar and force it to locate - * in the lower 4GB of memory. - */ - if (found_mem64) - { - bar += 4; - early_write_config_dword(hose, - current_bus, - pci_devfn, - bar, - 0x00000000); - } - - bar_nr++; - - DBG("size=0x%x, address=0x%x\n", - bar_size, bar_value); - } - -} - -void __init -pciauto_prescan_setup_bridge(struct pci_channel *hose, - int current_bus, - int pci_devfn, - int sub_bus) -{ - int cmdstat; - - /* Configure bus number registers */ - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_PRIMARY_BUS, - current_bus); - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_SECONDARY_BUS, - sub_bus + 1); - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_SUBORDINATE_BUS, - 0xff); - - /* Round memory allocator to 1MB boundary */ - pciauto_upper_memspc &= ~(0x100000 - 1); - - /* Round I/O allocator to 4KB boundary */ - pciauto_upper_iospc &= ~(0x1000 - 1); - - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_MEMORY_LIMIT, - ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_IO_LIMIT, - ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_IO_LIMIT_UPPER16, - ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); - - /* We don't support prefetchable memory for now, so disable */ - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_PREF_MEMORY_BASE, - 0x1000); - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_PREF_MEMORY_LIMIT, - 0x1000); - - /* Enable memory and I/O accesses, enable bus master */ - early_read_config_dword(hose, - current_bus, - pci_devfn, - PCI_COMMAND, - &cmdstat); - early_write_config_dword(hose, - current_bus, - pci_devfn, - PCI_COMMAND, - cmdstat | - PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER); -} - -void __init -pciauto_postscan_setup_bridge(struct pci_channel *hose, - int current_bus, - int pci_devfn, - int sub_bus) -{ - /* Configure bus number registers */ - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_SUBORDINATE_BUS, - sub_bus); - - /* Round memory allocator to 1MB boundary */ - pciauto_upper_memspc &= ~(0x100000 - 1); - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_MEMORY_BASE, - pciauto_upper_memspc >> 16); - - /* Round I/O allocator to 4KB boundary */ - pciauto_upper_iospc &= ~(0x1000 - 1); - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_IO_BASE, - (pciauto_upper_iospc & 0x0000f000) >> 8); - early_write_config_word(hose, - current_bus, - pci_devfn, - PCI_IO_BASE_UPPER16, - pciauto_upper_iospc >> 16); -} - -#define PCIAUTO_IDE_MODE_MASK 0x05 - -int __init -pciauto_bus_scan(struct pci_channel *hose, int current_bus) -{ - int sub_bus; - u32 pci_devfn, pci_class, cmdstat, found_multi=0; - unsigned short vid; - unsigned char header_type; - - sub_bus = current_bus; - - for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) { - - if (PCI_FUNC(pci_devfn) && !found_multi) - continue; - - early_read_config_byte(hose, - current_bus, - pci_devfn, - PCI_HEADER_TYPE, - &header_type); - - if (!PCI_FUNC(pci_devfn)) - found_multi = header_type & 0x80; - - early_read_config_word(hose, - current_bus, - pci_devfn, - PCI_VENDOR_ID, - &vid); - - if (vid == 0xffff) continue; - - early_read_config_dword(hose, - current_bus, - pci_devfn, - PCI_CLASS_REVISION, &pci_class); - if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) { - DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); - pciauto_prescan_setup_bridge(hose, - current_bus, - pci_devfn, - sub_bus); - sub_bus = pciauto_bus_scan(hose, sub_bus+1); - pciauto_postscan_setup_bridge(hose, - current_bus, - pci_devfn, - sub_bus); - - } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { - - unsigned char prg_iface; - - early_read_config_byte(hose, - current_bus, - pci_devfn, - PCI_CLASS_PROG, - &prg_iface); - if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { - DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); - continue; - } - } - - /* - * Found a peripheral, enable some standard - * settings - */ - early_read_config_dword(hose, - current_bus, - pci_devfn, - PCI_COMMAND, - &cmdstat); - early_write_config_dword(hose, - current_bus, - pci_devfn, - PCI_COMMAND, - cmdstat | - PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER); - early_write_config_byte(hose, - current_bus, - pci_devfn, - PCI_LATENCY_TIMER, - 0x80); - - /* Allocate PCI I/O and/or memory space */ - pciauto_setup_bars(hose, - current_bus, - pci_devfn); - } - return sub_bus; -} - -int __init -pciauto_assign_resources(int busno, struct pci_channel *hose) -{ - /* setup resource limits */ - pciauto_lower_iospc = hose->io_resource->start; - pciauto_upper_iospc = hose->io_resource->end + 1; - pciauto_lower_memspc = hose->mem_resource->start; - pciauto_upper_memspc = hose->mem_resource->end + 1; - - return pciauto_bus_scan(hose, busno); -} - - -/* - * These functions are used early on before PCI scanning is done - * and all of the pci_dev and pci_bus structures have been created. - */ -static struct pci_dev * -fake_pci_dev(struct pci_channel *hose, int busnr, int devfn) -{ - static struct pci_dev dev; - static struct pci_bus bus; - - dev.bus = &bus; - dev.sysdata = hose; - dev.devfn = devfn; - bus.number = busnr; - bus.ops = hose->pci_ops; - return &dev; -} - -#define EARLY_PCI_OP(rw, size, type) \ -int early_##rw##_config_##size(struct pci_channel *hose, int bus, \ - int devfn, int offset, type value) \ -{ \ - return pci_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ - offset, value); \ -} - -EARLY_PCI_OP(read, byte, u8 *) -EARLY_PCI_OP(read, word, u16 *) -EARLY_PCI_OP(read, dword, u32 *) -EARLY_PCI_OP(write, byte, u8) -EARLY_PCI_OP(write, word, u16) -EARLY_PCI_OP(write, dword, u32) diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/prom.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/prom.c --- linux-2.4.18/arch/mips/ddb5xxx/common/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/prom.c Sat Mar 30 22:55:26 2002 @@ -22,8 +22,19 @@ #include #include #include +#include -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; + +const char *get_system_type(void) +{ + switch (mips_machtype) { + case MACH_NEC_DDB5074: return "NEC DDB Vrc-5074"; + case MACH_NEC_DDB5476: return "NEC DDB Vrc-5476"; + case MACH_NEC_DDB5477: return "NEC DDB Vrc-5477"; + case MACH_NEC_ROCKHOPPER: return "NEC Rockhopper"; + } +} /* [jsun@junsun.net] PMON passes arguments in C main() style */ void __init prom_init(int argc, const char **arg) @@ -40,19 +51,84 @@ strcat(arcs_cmdline, " "); } + /* by default all these boards use dhcp/nfs root fs */ + strcat(arcs_cmdline, "ip=bootp"); + mips_machgroup = MACH_GROUP_NEC_DDB; #if defined(CONFIG_DDB5074) mips_machtype = MACH_NEC_DDB5074; + add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); #elif defined(CONFIG_DDB5476) mips_machtype = MACH_NEC_DDB5476; + add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); #elif defined(CONFIG_DDB5477) - mips_machtype = MACH_NEC_DDB5477; + ddb5477_runtime_detection(); + add_memory_region(0, board_ram_size, BOOT_MEM_RAM); #endif - - add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); } void __init prom_free_prom_memory(void) { } + +#if defined(CONFIG_DDB5477) + +#define DEFAULT_LCS1_BASE 0x19000000 +#define TESTVAL1 'K' +#define TESTVAL2 'S' + +int board_ram_size; +void ddb5477_runtime_detection(void) +{ + volatile char *test_offset; + char saved_test_byte; + + /* Determine if this is a DDB5477 board, or a BSB-VR0300 + base board. We can tell by checking for the location of + the NVRAM. It lives at the beginning of LCS1 on the DDB5477, + and the beginning of LCS1 on the BSB-VR0300 is flash memory. + The first 2K of the NVRAM are reserved, so don't we'll poke + around just after that. + */ + + test_offset = (char *)KSEG1ADDR(DEFAULT_LCS1_BASE + 0x800); + saved_test_byte = *test_offset; + + *test_offset = TESTVAL1; + if (*test_offset != TESTVAL1) { + /* We couldn't set our test value, so it must not be NVRAM, + so it's a BSB_VR0300 */ + mips_machtype = MACH_NEC_ROCKHOPPER; + } else { + /* We may have gotten lucky, and the TESTVAL1 was already + stored at the test location, so we must check a second + test value */ + *test_offset = TESTVAL2; + if (*test_offset != TESTVAL2) { + /* OK, we couldn't set this value either, so it must + definately be a BSB_VR0300 */ + mips_machtype = MACH_NEC_ROCKHOPPER; + } else { + /* We could change the value twice, so it must be + NVRAM, so it's a DDB_VRC5477 */ + mips_machtype = MACH_NEC_DDB5477; + } + } + /* Restore the original byte */ + *test_offset = saved_test_byte; + + /* before we know a better way, we will trust PMON for getting + * RAM size + */ + board_ram_size = 1 << (36 - (ddb_in32(DDB_SDRAM0) & 0xf)); + + db_run(printk("DDB run-time detection : %s, %d MB RAM\n", + mips_machtype == MACH_NEC_DDB5477 ? + "DDB5477" : "Rockhopper", + board_ram_size >> 20)); + + /* we can't handle ram size > 128 MB */ + db_assert(board_ram_size <= (128 << 20)); +} +#endif diff -urN linux-2.4.18/arch/mips/ddb5xxx/common/rtc_ds1386.c linux-2.4.19-pre5/arch/mips/ddb5xxx/common/rtc_ds1386.c --- linux-2.4.18/arch/mips/ddb5xxx/common/rtc_ds1386.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/common/rtc_ds1386.c Sat Mar 30 22:55:26 2002 @@ -24,7 +24,7 @@ #include #include -#include +#include #define EPOCH 2000 @@ -101,7 +101,7 @@ } temp = READ_RTC(0x9); - month = BIN_TO_BCD(tm.tm_mon); + month = BIN_TO_BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */ if (month != (temp & 0x1f)) { WRITE_RTC( 0x9, (month & 0x1f) | (temp & ~0x1f) ); @@ -147,7 +147,7 @@ /* remember the base */ rtc_base = base; - MIPS_ASSERT((rtc_base & 0xe0000000) == KSEG1); + db_assert((rtc_base & 0xe0000000) == KSEG1); /* turn on RTC if it is not on */ byte = READ_RTC(0x9); diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/Makefile linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/Makefile --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,23 @@ +# +# Makefile for the NEC DDB Vrc-5476 specific kernel interface routines +# under Linux. +# +# 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: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET = ddb5476.o + +obj-y += setup.o irq.o int-handler.o pci.o pci_ops.o \ + nile4_pic.o vrc5476_irq.o +obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/dbg_io.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/dbg_io.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/dbg_io.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,136 @@ +/* + * kgdb io functions for DDB5476. We use the second serial port. + * + * Copyright (C) 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +/* ======================= CONFIG ======================== */ + +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xa60002f8 +#define MAX_BAUD 115200 + +/* distance in bytes between two serial registers */ +#define REG_OFFSET 1 + +/* + * 0 - kgdb does serial init + * 1 - kgdb skip serial init + */ +static int remoteDebugInitialized = 0; + +/* + * the default baud rate *if* kgdb does serial init + */ +#define BAUD_DEFAULT UART16550_BAUD_38400 + +/* ======================= END OF CONFIG ======================== */ + +typedef unsigned char uint8; +typedef unsigned int uint32; + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE (1*REG_OFFSET) +#define OFS_INTR_ID (2*REG_OFFSET) +#define OFS_DATA_FORMAT (3*REG_OFFSET) +#define OFS_LINE_CONTROL (3*REG_OFFSET) +#define OFS_MODEM_CONTROL (4*REG_OFFSET) +#define OFS_RS232_OUTPUT (4*REG_OFFSET) +#define OFS_LINE_STATUS (5*REG_OFFSET) +#define OFS_MODEM_STATUS (6*REG_OFFSET) +#define OFS_RS232_INPUT (6*REG_OFFSET) +#define OFS_SCRATCH_PAD (7*REG_OFFSET) + +#define OFS_DIVISOR_LSB (0*REG_OFFSET) +#define OFS_DIVISOR_MSB (1*REG_OFFSET) + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/int-handler.S linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/int-handler.S --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,114 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * First-level interrupt dispatcher for ddb5476 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include + +#include +#include +#include +#include +#include + +#include + +/* + * first level interrupt dispatcher for ocelot board - + * We check for the timer first, then check PCI ints A and D. + * Then check for serial IRQ and fall through. + */ + .align 5 + NESTED(ddb5476_handle_int, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + .set noreorder + mfc0 t0, CP0_CAUSE + mfc0 t2, CP0_STATUS + + and t0, t2 + + andi t1, t0, STATUSF_IP7 /* cpu timer */ + bnez t1, ll_cpu_ip7 + andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */ + bnez t1, ll_cpu_ip2 + andi t1, t0, STATUSF_IP3 + bnez t1, ll_cpu_ip3 + andi t1, t0, STATUSF_IP4 + bnez t1, ll_cpu_ip4 + andi t1, t0, STATUSF_IP5 + bnez t1, ll_cpu_ip5 + andi t1, t0, STATUSF_IP6 + bnez t1, ll_cpu_ip6 + andi t1, t0, STATUSF_IP0 /* software int 0 */ + bnez t1, ll_cpu_ip0 + andi t1, t0, STATUSF_IP1 /* software int 1 */ + bnez t1, ll_cpu_ip1 + nop + + .set reorder + + /* wrong alarm or masked ... */ + // j spurious_interrupt + move a0, sp + jal vrc5476_irq_dispatch + j ret_from_irq + nop + + .align 5 + +ll_cpu_ip0: + li a0, CPU_IRQ_BASE + 0 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip1: + li a0, CPU_IRQ_BASE + 1 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip2: /* jump to second-level dispatching */ + move a0, sp + jal vrc5476_irq_dispatch + j ret_from_irq + +ll_cpu_ip3: + li a0, CPU_IRQ_BASE + 3 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip4: + li a0, CPU_IRQ_BASE + 4 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip5: + li a0, CPU_IRQ_BASE + 5 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip6: + li a0, CPU_IRQ_BASE + 6 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip7: + li a0, CPU_IRQ_BASE + 7 + move a1, sp + jal do_IRQ + j ret_from_irq + + END(ddb5476_handle_int) diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/irq.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/irq.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,148 @@ +/* + * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + * + * Re-write the whole thing to use new irq.c file. + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + */ +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ +#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ +#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ + +#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ +#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ +#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ + +#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ +#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ + +#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ +#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ + +#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ +#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ + +static void m1543_irq_setup(void) +{ + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5476 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ9 - USB (hardwired in ddb_setup) + * IRQ10 - PMU (hardwired in ddb_setup) + * IRQ12 - mouse + * IRQ14,15 - IDE controller (need to be confirmed, jsun) + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); +} + +static void nile4_irq_setup(void) +{ + int i; + + /* Map all interrupts to CPU int #0 (IP2) */ + nile4_map_irq_all(0); + + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + + /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 1); + nile4_set_pci_irq_polarity(3, 0); + + for (i = 0; i < 16; i++) + nile4_clear_irq(i); + + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); + + /* memory resource acquire in ddb_setup */ +} + +static void error_action(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_ERR "Error interrupt happend: %d\n", irq); +} + +static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; +static struct irqaction irq_error = { no_action, 0, 0, "error", NULL, NULL }; + +extern asmlinkage void ddb5476_handle_int(void); +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +extern void mips_cpu_irq_init(u32 irq_base); +extern void vrc5476_irq_init(u32 irq_base); + +void __init ddb5476_irq_setup(void) +{ + /* hardware initialization */ + nile4_irq_setup(); + m1543_irq_setup(); + + /* controller setup */ + init_i8259_irqs(); + vrc5476_irq_init(VRC5476_IRQ_BASE); + mips_cpu_irq_init(CPU_IRQ_BASE); + + /* setup cascade interrupts */ + setup_irq(VRC5476_IRQ_BASE + VRC5476_I8259_CASCADE, &irq_cascade); + setup_irq(CPU_IRQ_BASE + CPU_VRC5476_CASCADE, &irq_cascade); + + /* setup error interrupts for debugging */ + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CPCE, &irq_error); + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CNTD, &irq_error); + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_MCE, &irq_error); + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error); + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error); + setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error); + + /* setup the grandpa intr vector */ + set_except_vector(0, ddb5476_handle_int); +} diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/nile4_pic.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/nile4_pic.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/nile4_pic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/nile4_pic.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,189 @@ +/* + * arch/mips/ddb5476/nile4.c -- + * low-level PIC code for NEC Vrc-5476 (Nile 4) + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + */ +#include +#include + +#include + +#include + + +/* + * Interrupt Programming + */ +void nile4_map_irq(int nile4_irq, int cpu_irq) +{ + u32 offset, t; + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = ddb_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + ddb_out32(offset, t); +} + +void nile4_map_irq_all(int cpu_irq) +{ + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = ddb_in32(DDB_INTCTRL); + t &= 0x88888888; + t |= all; + ddb_out32(DDB_INTCTRL, t); + t = ddb_in32(DDB_INTCTRL + 4); + t &= 0x88888888; + t |= all; + ddb_out32(DDB_INTCTRL + 4, t); +} + +void nile4_enable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = ddb_in32(offset); + t |= 8 << (nile4_irq * 4); + ddb_out32(offset, t); +} + +void nile4_disable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = ddb_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + ddb_out32(offset, t); +} + +void nile4_disable_irq_all(void) +{ + ddb_out32(DDB_INTCTRL, 0); + ddb_out32(DDB_INTCTRL + 4, 0); +} + +u16 nile4_get_irq_stat(int cpu_irq) +{ + return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2); +} + +void nile4_enable_irq_output(int cpu_irq) +{ + u32 t; + + t = ddb_in32(DDB_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + ddb_out32(DDB_INTSTAT1, t); +} + +void nile4_disable_irq_output(int cpu_irq) +{ + u32 t; + + t = ddb_in32(DDB_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + ddb_out32(DDB_INTSTAT1, t); +} + +void nile4_set_pci_irq_polarity(int pci_irq, int high) +{ + u32 t; + + t = ddb_in32(DDB_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + ddb_out32(DDB_INTPPES, t); +} + +void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) +{ + u32 t; + + t = ddb_in32(DDB_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + ddb_out32(DDB_INTPPES, t); +} + +void nile4_clear_irq(int nile4_irq) +{ + ddb_out32(DDB_INTCLR, 1 << nile4_irq); +} + +void nile4_clear_irq_mask(u32 mask) +{ + ddb_out32(DDB_INTCLR, mask); +} + +u8 nile4_i8259_iack(void) +{ + u8 irq; + u32 reg; + + /* Set window 0 for interrupt acknowledge */ + reg = ddb_in32(DDB_PCIINIT0); + + ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32); + irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); + /* restore window 0 for PCI I/O space */ + // ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); + ddb_out32(DDB_PCIINIT0, reg); + + /* i8269.c set the base vector to be 0x0 */ + return irq + I8259_IRQ_BASE; +} + +#if defined(CONFIG_LL_DEBUG) +void nile4_dump_irq_status(void) +{ + printk(KERN_DEBUG " + CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4), + (void *) ddb_in32(DDB_CPUSTAT)); + printk(KERN_DEBUG " + INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4), + (void *) ddb_in32(DDB_INTCTRL)); + printk(KERN_DEBUG + "INTSTAT0 = %p:%p\n", + (void *) ddb_in32(DDB_INTSTAT0 + 4), + (void *) ddb_in32(DDB_INTSTAT0)); + printk(KERN_DEBUG + "INTSTAT1 = %p:%p\n", + (void *) ddb_in32(DDB_INTSTAT1 + 4), + (void *) ddb_in32(DDB_INTSTAT1)); + printk(KERN_DEBUG + "INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4), + (void *) ddb_in32(DDB_INTCLR)); + printk(KERN_DEBUG + "INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4), + (void *) ddb_in32(DDB_INTPPES)); +} +#endif diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/pci.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/pci.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/pci.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +#include +#include + +#include + +static struct resource extpci_io_resource = { + "pci IO space", + 0x1000, /* leave some room for ISA bus */ + DDB_PCI_IO_SIZE -1, + IORESOURCE_IO}; + +static struct resource extpci_mem_resource = { + "pci memory space", + DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */ + DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE -1, + IORESOURCE_MEM}; + +extern struct pci_ops ddb5476_ext_pci_ops; + +struct pci_channel mips_pci_channels[] = { + { &ddb5476_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource }, + { NULL, NULL, NULL} +}; + + +/* + * we fix up irqs based on the slot number. + * The first entry is at AD:11. + * + * This does not work for devices on sub-buses yet. + */ + +/* + * temporary + */ + +#define PCI_EXT_INTA 8 +#define PCI_EXT_INTB 9 +#define PCI_EXT_INTC 10 +#define PCI_EXT_INTD 11 +#define PCI_EXT_INTE 12 + +/* + * based on ddb5477 manual page 11 + */ +#define MAX_SLOT_NUM 21 +static unsigned char irq_map[MAX_SLOT_NUM] = { + /* SLOT: 0, AD:11 */ 0xff, + /* SLOT: 1, AD:12 */ 0xff, + /* SLOT: 2, AD:13 */ 9, /* USB */ + /* SLOT: 3, AD:14 */ 10, /* PMU */ + /* SLOT: 4, AD:15 */ 0xff, + /* SLOT: 5, AD:16 */ 0x0, /* P2P bridge */ + /* SLOT: 6, AD:17 */ nile4_to_irq(PCI_EXT_INTB), + /* SLOT: 7, AD:18 */ nile4_to_irq(PCI_EXT_INTC), + /* SLOT: 8, AD:19 */ nile4_to_irq(PCI_EXT_INTD), + /* SLOT: 9, AD:20 */ nile4_to_irq(PCI_EXT_INTA), + /* SLOT: 10, AD:21 */ 0xff, + /* SLOT: 11, AD:22 */ 0xff, + /* SLOT: 12, AD:23 */ 0xff, + /* SLOT: 13, AD:24 */ 14, /* HD controller, M5229 */ + /* SLOT: 14, AD:25 */ 0xff, + /* SLOT: 15, AD:26 */ 0xff, + /* SLOT: 16, AD:27 */ 0xff, + /* SLOT: 17, AD:28 */ 0xff, + /* SLOT: 18, AD:29 */ 0xff, + /* SLOT: 19, AD:30 */ 0xff, + /* SLOT: 20, AD:31 */ 0xff +}; + +extern int vrc5477_irq_to_irq(int irq); +void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + + /* we don't do IRQ fixup for sub-bus yet */ + if (dev->bus->parent != NULL) { + db_run(printk("Don't know how to fixup irq for PCI device %d on sub-bus %d\n", + slot_num, dev->bus->number)); + continue; + } + + db_assert(slot_num < MAX_SLOT_NUM); + db_assert(irq_map[slot_num] != 0xff); + + pci_write_config_byte(dev, + PCI_INTERRUPT_LINE, + irq_map[slot_num]); + dev->irq = irq_map[slot_num]; + } +} + +#if defined(CONFIG_DEBUG) +extern void jsun_scan_pci_bus(void); +#endif + +void __init ddb_pci_reset_bus(void) +{ + u32 temp; + + /* + * I am not sure about the "official" procedure, the following + * steps work as far as I know: + * We first set PCI cold reset bit (bit 31) in PCICTRL-H. + * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H. + * The same is true for both PCI channels. + */ + temp = ddb_in32(DDB_PCICTRL+4); + temp |= 0x80000000; + ddb_out32(DDB_PCICTRL+4, temp); + temp &= ~0xc0000000; + ddb_out32(DDB_PCICTRL+4, temp); + +} + +unsigned __init int pcibios_assign_all_busses(void) +{ + /* we hope pci_auto has assigned the bus numbers to all buses */ + return 1; +} + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ +} + +void __init pcibios_fixup(void) +{ +} + diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/pci_ops.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/pci_ops.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/pci_ops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,357 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * arch/mips/ddb5xxx/ddb5476/pci_ops.c + * Define the pci_ops for DB5477. + * + * Much of the code is derived from the original DDB5074 port by + * Geert Uytterhoeven + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include + +/* + * config_swap structure records what set of pdar/pmr are used + * to access pci config space. It also provides a place hold the + * original values for future restoring. + */ +struct pci_config_swap { + u32 pdar; + u32 pmr; + u32 config_base; + u32 config_size; + u32 pdar_backup; + u32 pmr_backup; +}; + +/* + * On DDB5476, we have one set of swap registers + */ +struct pci_config_swap ext_pci_swap = { + DDB_PCIW0, + DDB_PCIINIT0, + DDB_PCI_CONFIG_BASE, + DDB_PCI_CONFIG_SIZE +}; + +static int pci_config_workaround=1; + +/* + * access config space + */ +static inline u32 ddb_access_config_base(struct pci_config_swap *swap, + u32 bus,/* 0 means top level bus */ + u32 slot_num) +{ + u32 pci_addr = 0; + u32 pciinit_offset = 0; + u32 virt_addr = swap->config_base; + u32 option; + + if (pci_config_workaround) { + /* [jsun] work around Vrc5476 controller itself, returnning + * slot 0 essentially makes vrc5476 invisible + */ + if (slot_num == 12) slot_num = 0; + +#if 0 + /* BUG : skip P2P bridge for now */ + if (slot_num == 5) slot_num = 0; +#endif + + } else { + /* now we have to be hornest, returning the true + * PCI config headers for vrc5476 + */ + if (slot_num == 12) { + swap->pdar_backup = ddb_in32(swap->pdar); + swap->pmr_backup = ddb_in32(swap->pmr); + return DDB_BASE + DDB_PCI_BASE; + } + } + + /* minimum pdar (window) size is 2MB */ + db_assert(swap->config_size >= (2 << 20)); + + db_assert(slot_num < (1 << 5)); + db_assert(bus < (1 << 8)); + + /* backup registers */ + swap->pdar_backup = ddb_in32(swap->pdar); + swap->pmr_backup = ddb_in32(swap->pmr); + + /* set the pdar (pci window) register */ + ddb_set_pdar(swap->pdar, + swap->config_base, + swap->config_size, + 32, /* 32 bit wide */ + 0, /* not on local memory bus */ + 0); /* not visible from PCI bus (N/A) */ + + /* + * calcuate the absolute pci config addr; + * according to the spec, we start scanning from adr:11 (0x800) + */ + if (bus == 0) { + /* type 0 config */ + pci_addr = 0x800 << slot_num; + } else { + /* type 1 config */ + pci_addr = (bus << 16) | (slot_num << 11); + /* panic("ddb_access_config_base: we don't support type 1 config Yet"); */ + } + + /* + * if pci_addr is less than pci config window size, we set + * pciinit_offset to 0 and adjust the virt_address. + * Otherwise we will try to adjust pciinit_offset. + */ + if (pci_addr < swap->config_size) { + virt_addr = KSEG1ADDR(swap->config_base + pci_addr); + pciinit_offset = 0; + } else { + db_assert( (pci_addr & (swap->config_size - 1)) == 0); + virt_addr = KSEG1ADDR(swap->config_base); + pciinit_offset = pci_addr; + } + + /* set the pmr register */ + option = DDB_PCI_ACCESS_32; + if (bus != 0) option |= DDB_PCI_CFGTYPE1; + ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option); + + return virt_addr; +} + +static inline void ddb_close_config_base(struct pci_config_swap *swap) +{ + ddb_out32(swap->pdar, swap->pdar_backup); + ddb_out32(swap->pmr, swap->pmr_backup); +} + +static int read_config_dword(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u32 *val) +{ + u32 bus, slot_num, func_num; + u32 base; + + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + base = ddb_access_config_base(swap, bus, slot_num); + *val = *(volatile u32*) (base + (func_num << 8) + where); + ddb_close_config_base(swap); + return PCIBIOS_SUCCESSFUL; +} + +static int read_config_word(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u16 *val) +{ + int status; + u32 result; + + db_assert((where & 1) == 0); + + status = read_config_dword(swap, dev, where & ~3, &result); + if (where & 2) result >>= 16; + *val = result & 0xffff; + return status; +} + +static int read_config_byte(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u8 *val) +{ + int status; + u32 result; + + status = read_config_dword(swap, dev, where & ~3, &result); + if (where & 1) result >>= 8; + if (where & 2) result >>= 16; + *val = result & 0xff; + return status; +} + +static int write_config_dword(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u32 val) +{ + u32 bus, slot_num, func_num; + u32 base; + + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + base = ddb_access_config_base(swap, bus, slot_num); + *(volatile u32*) (base + (func_num << 8) + where) = val; + ddb_close_config_base(swap); + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_word(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u16 val) +{ + int status, shift=0; + u32 result; + + db_assert((where & 1) == 0); + + status = read_config_dword(swap, dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) return status; + + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return write_config_dword(swap, dev, where & ~3, result); +} + +static int write_config_byte(struct pci_config_swap *swap, + struct pci_dev *dev, + u32 where, + u8 val) +{ + int status, shift=0; + u32 result; + + status = read_config_dword(swap, dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) return status; + + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return write_config_dword(swap, dev, where & ~3, result); +} + +#define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ +static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ +{ \ + return rw##_config_##unitname(pciswap, \ + dev, \ + where, \ + val); \ +} + +MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) +MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) +MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) + +MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) +MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) +MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) + +struct pci_ops ddb5476_ext_pci_ops ={ + extpci_read_config_byte, + extpci_read_config_word, + extpci_read_config_dword, + extpci_write_config_byte, + extpci_write_config_word, + extpci_write_config_dword +}; + + +#if defined(CONFIG_DEBUG) +void jsun_scan_pci_bus(void) +{ + struct pci_bus bus; + struct pci_dev dev; + unsigned int devfn; + int j; + + pci_config_workaround = 0; + + bus.parent = NULL; /* we scan the top level only */ + dev.bus = &bus; + dev.sysdata = NULL; + + /* scan ext pci bus and io pci bus*/ + for (j=0; j< 1; j++) { + printk(KERN_INFO "scan ddb5476 external PCI bus:\n"); + bus.ops = &ddb5476_ext_pci_ops; + + for (devfn = 0; devfn < 0x100; devfn += 8) { + u32 temp; + u16 temp16; + u8 temp8; + int i; + + dev.devfn = devfn; + db_verify(pci_read_config_dword(&dev, 0, &temp), + == PCIBIOS_SUCCESSFUL); + if (temp == 0xffffffff) continue; + + printk(KERN_INFO "slot %d: (addr %d) \n", devfn/8, + 11+devfn/8); + + /* verify read word and byte */ + db_verify(pci_read_config_word(&dev, 2, &temp16), + == PCIBIOS_SUCCESSFUL); + db_assert(temp16 == (temp >> 16)); + db_verify(pci_read_config_byte(&dev, 3, &temp8), + == PCIBIOS_SUCCESSFUL); + db_assert(temp8 == (temp >> 24)); + db_verify(pci_read_config_byte(&dev, 1, &temp8), + == PCIBIOS_SUCCESSFUL); + db_assert(temp8 == ((temp >> 8) & 0xff)); + + for (i=0; i < 16; i++) { + if ((i%4) == 0) + printk(KERN_INFO); + db_verify(pci_read_config_dword(&dev, i*4, &temp), + == PCIBIOS_SUCCESSFUL); + printk("\t%08X", temp); + if ((i%4) == 3) + printk("\n"); + } + } + } + + pci_config_workaround = 1; +} +#endif diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/setup.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/setup.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,331 @@ +/* + * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// #define USE_CPU_COUNTER_TIMER /* whether we use cpu counter */ + +#ifdef USE_CPU_COUNTER_TIMER + +#define CPU_COUNTER_FREQUENCY 83000000 +#else +/* otherwise we use general purpose timer */ +#define TIMER_FREQUENCY 83000000 +#define TIMER_BASE DDB_T2CTRL +#define TIMER_IRQ (VRC5476_IRQ_BASE + VRC5476_IRQ_GPT) +#endif + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +#endif + +extern struct ide_ops std_ide_ops; +extern struct kbd_ops std_kbd_ops; + +static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; + +static void ddb_machine_restart(char *command) +{ + u32 t; + + /* PCI cold reset */ + t = ddb_in32(DDB_PCICTRL + 4); + t |= 0x40000000; + ddb_out32(DDB_PCICTRL + 4, t); + /* CPU cold reset */ + t = ddb_in32(DDB_CPUSTAT); + t |= 1; + ddb_out32(DDB_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); +} + +static void ddb_machine_halt(void) +{ + printk(KERN_NOTICE "DDB Vrc-5476 halted.\n"); + while (1); +} + +static void ddb_machine_power_off(void) +{ + printk(KERN_NOTICE "DDB Vrc-5476 halted. Please turn off the power.\n"); + while (1); +} + +extern void ddb_irq_setup(void); +extern void rtc_ds1386_init(unsigned long base); + +static void __init ddb_time_init(void) +{ +#if defined(USE_CPU_COUNTER_TIMER) + mips_counter_frequency = CPU_COUNTER_FREQUENCY; +#endif + + /* we have ds1396 RTC chip */ + rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE)); +} + + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +static void __init ddb_timer_setup(struct irqaction *irq) +{ +#if defined(USE_CPU_COUNTER_TIMER) + + unsigned int count; + + /* we are using the cpu counter for timer interrupts */ + setup_irq(CPU_IRQ_BASE + 7, irq); + + /* to generate the first timer interrupt */ + count = read_32bit_cp0_register(CP0_COUNT); + write_32bit_cp0_register(CP0_COMPARE, count + 1000); + +#else + + ddb_out32(TIMER_BASE, TIMER_FREQUENCY/HZ); + ddb_out32(TIMER_BASE+4, 0x1); /* enable timer */ + setup_irq(TIMER_IRQ, irq); +#endif +} + +static struct { + struct resource dma1; + struct resource pic1; + struct resource timer; + struct resource rtc; + struct resource dma_page_reg; + struct resource pic2; + struct resource dma2; +} ddb5476_ioport = { + { + "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, { + "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, { + "timer", 0x40, 0x5f, IORESOURCE_BUSY}, { + "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, { + "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, { + "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, { + "dma2", 0xc0, 0xdf, IORESOURCE_BUSY} +}; + +static struct { + struct resource nile4; +} ddb5476_iomem = { + { "Nile 4", DDB_BASE, DDB_BASE + DDB_SIZE - 1, IORESOURCE_BUSY} +}; + +static void ddb5476_board_init(void); +extern void ddb5476_irq_setup(void); +extern void (*irq_setup)(void); + +void __init +ddb_setup(void) +{ + extern int panic_timeout; + + irq_setup = ddb5476_irq_setup; + set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE)); + + board_time_init = ddb_time_init; + board_timer_setup = ddb_timer_setup; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; + + /* request io port/mem resources */ + if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || + request_resource(&ioport_resource, &ddb5476_ioport.pic1) || + request_resource(&ioport_resource, &ddb5476_ioport.timer) || + request_resource(&ioport_resource, &ddb5476_ioport.rtc) || + request_resource(&ioport_resource, + &ddb5476_ioport.dma_page_reg) + || request_resource(&ioport_resource, &ddb5476_ioport.pic2) + || request_resource(&ioport_resource, &ddb5476_ioport.dma2) + || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { + printk + ("ddb_setup - requesting oo port resources failed.\n"); + for (;;); + } +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + +#ifdef CONFIG_PC_KEYB + kbd_ops = &std_kbd_ops; +#endif + + /* Reboot on panic */ + panic_timeout = 180; + + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + /* *(long*)0xbfa00218 = 0x8; */ + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + /* board initialization stuff */ + ddb5476_board_init(); +} + +/* + * We don't trust bios. We essentially does hardware re-initialization + * as complete as possible, as far as we know we can safely do. + */ +static void +ddb5476_board_init(void) +{ + /* ----------- setup PDARs ------------ */ + /* check SDRAM0, whether we are on MEM bus does not matter */ + db_assert((ddb_in32(DDB_SDRAM0) & 0xffffffef) == + ddb_calc_pdar(DDB_SDRAM_BASE, DDB_SDRAM_SIZE, 32, 0, 1)); + + /* SDRAM1 should be turned off. What is this for anyway ? */ + db_assert( (ddb_in32(DDB_SDRAM1) & 0xf) == 0); + + /* flash 1&2, DDB status, DDB control */ + ddb_set_pdar(DDB_DCS2, DDB_DCS2_BASE, DDB_DCS2_SIZE, 16, 0, 0); + ddb_set_pdar(DDB_DCS3, DDB_DCS3_BASE, DDB_DCS3_SIZE, 16, 0, 0); + ddb_set_pdar(DDB_DCS4, DDB_DCS4_BASE, DDB_DCS4_SIZE, 8, 0, 0); + ddb_set_pdar(DDB_DCS5, DDB_DCS5_BASE, DDB_DCS5_SIZE, 8, 0, 0); + + /* shut off other pdar so they don't accidentally get into the way */ + ddb_set_pdar(DDB_DCS6, 0xffffffff, 0, 32, 0, 0); + ddb_set_pdar(DDB_DCS7, 0xffffffff, 0, 32, 0, 0); + ddb_set_pdar(DDB_DCS8, 0xffffffff, 0, 32, 0, 0); + + /* verify VRC5477 base addr */ + /* don't care about some details */ + db_assert((ddb_in32(DDB_INTCS) & 0xffffff0f) == + ddb_calc_pdar(DDB_INTCS_BASE, DDB_INTCS_SIZE, 8, 0, 0)); + + /* verify BOOT ROM addr */ + /* don't care about some details */ + db_assert((ddb_in32(DDB_BOOTCS) & 0xffffff0f) == + ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0)); + + /* setup PCI windows - window1 for MEM/config, window0 for IO */ + ddb_set_pdar(DDB_PCIW0, DDB_PCI_IO_BASE, DDB_PCI_IO_SIZE, 32, 0, 1); + ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); + + ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); + ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); + + /* ----------- setup PDARs ------------ */ + /* this is problematic - it will reset Aladin which cause we loose + * serial port, and we don't know how to set up Aladin chip again. + */ + // ddb_pci_reset_bus(); + + ddb_out32(DDB_BAR0, 0x00000008); + + ddb_out32(DDB_BARC, 0xffffffff); + ddb_out32(DDB_BARB, 0xffffffff); + ddb_out32(DDB_BAR1, 0xffffffff); + ddb_out32(DDB_BAR2, 0xffffffff); + ddb_out32(DDB_BAR3, 0xffffffff); + ddb_out32(DDB_BAR4, 0xffffffff); + ddb_out32(DDB_BAR5, 0xffffffff); + ddb_out32(DDB_BAR6, 0xffffffff); + ddb_out32(DDB_BAR7, 0xffffffff); + ddb_out32(DDB_BAR8, 0xffffffff); + + /* ----------- switch PCI1 to PCI CONFIG space ------------ */ + ddb_set_pdar(DDB_PCIW1, DDB_PCI_CONFIG_BASE, DDB_PCI_CONFIG_SIZE, 32, 0, 1); + ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_CFG, 0x0, DDB_PCI_ACCESS_32); + + /* ----- M1543 PCI setup ------ */ + + /* we know M1543 PCI-ISA controller is at addr:18 */ + /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ + *(volatile unsigned char *) 0xa8040072 &= 0xf0; + *(volatile unsigned char *) 0xa8040072 |= 0xa; + + /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) + * no IOCHRDY signal, (bit 7 - 1) + * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) + * Make USB Master INTAJ level to edge conversion (bit 4 - 1) + */ + *(unsigned char *) 0xa8040074 = 0xd1; + + /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) + * SCI routing to IRQ 13 disabled (bit 7 - 1) + * SCI interrupt level to edge conversion bypassed (bit 4 - 0) + */ + *(unsigned char *) 0xa8040076 = 0x83; + + /* setup IDE controller + * enable IDE controller (bit 6 - 1) + * IDE IDSEL to be addr:24 (bit 4:5 - 11) + * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) + * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) + * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 + */ + // *(unsigned char*)0xa8040058 = 0x71; + // *(unsigned char*)0xa8040058 = 0x79; + // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state + *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state + +#if 0 + /* this is not necessary if M5229 does not use SIRQ */ + *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 + *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 +#endif + + /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ + /* M5229 IDSEL is addr:24; see above setting */ + *(unsigned char *) 0xa9000050 |= 0x1; + + /* enable bus master (bit 2) and IO decoding (bit 0) */ + *(unsigned char *) 0xa9000004 |= 0x5; + + /* enable native, copied from arch/ppc/k2boot/head.S */ + /* TODO - need volatile, need to be portable */ + *(unsigned char *) 0xa9000009 = 0xff; + + /* ----- end of M1543 PCI setup ------ */ + + /* ----- reset on-board ether chip ------ */ + *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ + *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ + + /* send reset command */ + *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ + + /* disable ether chip */ + *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ + + /* put it into sleep */ + *((volatile u32 *) 0xa8020040) = 0x80000000; + + /* ----- end of reset on-board ether chip ------ */ + + /* ----------- switch PCI1 back to PCI MEM space ------------ */ + ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); + ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); +} diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,113 @@ +/* + * The irq controller for vrc5476. + * + * Copyright (C) 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include + +#include + +#include + +static int irq_base; + +static void vrc5476_irq_enable(uint irq) +{ + nile4_enable_irq(irq - irq_base); +} + +static void vrc5476_irq_disable(uint irq) +{ + nile4_disable_irq(irq - irq_base); +} + +static unsigned int vrc5476_irq_startup(uint irq) +{ + nile4_enable_irq(irq - irq_base); + return 0; +} + +#define vrc5476_irq_shutdown vrc5476_irq_disable + +static void vrc5476_irq_ack(uint irq) +{ + nile4_clear_irq(irq - irq_base); + nile4_disable_irq(irq - irq_base); +} + +static void vrc5476_irq_end(uint irq) +{ + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + vrc5476_irq_enable(irq); +} + +static hw_irq_controller vrc5476_irq_controller = { + "vrc5476", + vrc5476_irq_startup, + vrc5476_irq_shutdown, + vrc5476_irq_enable, + vrc5476_irq_disable, + vrc5476_irq_ack, + vrc5476_irq_end, + NULL /* no affinity stuff for UP */ +}; + +void __init +vrc5476_irq_init(u32 base) +{ + extern irq_desc_t irq_desc[]; + u32 i; + + irq_base = base; + for (i= base; i< base + NUM_VRC5476_IRQ; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &vrc5476_irq_controller; + } +} + + +asmlinkage void +vrc5476_irq_dispatch(struct pt_regs *regs) +{ + extern unsigned int do_IRQ(int irq, struct pt_regs *regs); + extern void spurious_interrupt(void); + + u32 mask; + int nile4_irq; + + mask = nile4_get_irq_stat(0); + + /* quick check for possible time interrupt */ + if (mask & (1 << VRC5476_IRQ_GPT)) { + do_IRQ(VRC5476_IRQ_BASE + VRC5476_IRQ_GPT, regs); + return; + } + + /* check for i8259 interrupts */ + if (mask & (1 << VRC5476_I8259_CASCADE)) { + int i8259_irq = nile4_i8259_iack(); + do_IRQ(I8259_IRQ_BASE + i8259_irq, regs); + return; + } + + /* regular nile4 interrupts (we should not really have any */ + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) { + if (mask & 1) { + do_IRQ(VRC5476_IRQ_BASE + nile4_irq, regs); + return; + } + } + spurious_interrupt(); +} diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/Makefile linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/Makefile --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/Makefile Sat Mar 30 22:55:26 2002 @@ -13,9 +13,9 @@ O_TARGET:= ddb5477.o -obj-y += int-handler.o irq.o irq_5477.o setup.o pci.o pci_ops.o +obj-y += int-handler.o irq.o irq_5477.o setup.o pci.o pci_ops.o lcd44780.o -obj-$(CONFIG_LL_DEBUG) += debug.o +obj-$(CONFIG_DEBUG) += debug.o obj-$(CONFIG_REMOTE_DEBUG) += kgdb_io.o obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/debug.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/debug.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/debug.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/debug.c Sat Mar 30 22:55:26 2002 @@ -15,8 +15,6 @@ */ #include -#include -#include /* SA_INTERRUPT */ #include #include @@ -64,9 +62,9 @@ static Register pdar_regs[] = { {"DDB_SDRAM0", DDB_BASE + DDB_SDRAM0}, {"DDB_SDRAM1", DDB_BASE + DDB_SDRAM1}, - {"DDB_LDCS0", DDB_BASE + DDB_LDCS0}, - {"DDB_LDCS1", DDB_BASE + DDB_LDCS1}, - {"DDB_LDCS2", DDB_BASE + DDB_LDCS2}, + {"DDB_LCS0", DDB_BASE + DDB_LCS0}, + {"DDB_LCS1", DDB_BASE + DDB_LCS1}, + {"DDB_LCS2", DDB_BASE + DDB_LCS2}, {"DDB_INTCS", DDB_BASE + DDB_INTCS}, {"DDB_BOOTCS", DDB_BASE + DDB_BOOTCS}, {"DDB_PCIW0", DDB_BASE + DDB_PCIW0}, diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/irq.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/irq.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/irq.c Sat Mar 30 22:55:26 2002 @@ -12,16 +12,16 @@ */ #include #include -#include +#include #include #include #include #include +#include + #include -/* [jsun] sooner or later we should move this debug stuff to MIPS common */ -#include /* * IRQ mapping @@ -76,7 +76,7 @@ void ddb5477_irq_setup(void) { - MIPS_DEBUG(printk("ddb5477_irq_setup invoked.\n")); + db_run(printk("ddb5477_irq_setup invoked.\n")); /* by default, we disable all interrupts and route all vrc5477 * interrupts to pin 0 (irq 2) */ @@ -141,16 +141,16 @@ u32 bitmask; u32 i; - MIPS_ASSERT(ddb_in32(DDB_INT2STAT) == 0); - MIPS_ASSERT(ddb_in32(DDB_INT3STAT) == 0); - MIPS_ASSERT(ddb_in32(DDB_INT4STAT) == 0); - MIPS_ASSERT(ddb_in32(DDB_NMISTAT) == 0); + db_assert(ddb_in32(DDB_INT2STAT) == 0); + db_assert(ddb_in32(DDB_INT3STAT) == 0); + db_assert(ddb_in32(DDB_INT4STAT) == 0); + db_assert(ddb_in32(DDB_NMISTAT) == 0); if (ddb_in32(DDB_INT1STAT) != 0) { -#if defined(CONFIG_LL_DEBUG) +#if defined(CONFIG_DEBUG) vrc5477_show_int_regs(); #endif - panic("error interrupt has happened.\n"); + panic("error interrupt has happened."); } intStatus = ddb_in32(DDB_INT0STAT); diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/irq_5477.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/irq_5477.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/irq_5477.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/irq_5477.c Sat Mar 30 22:55:26 2002 @@ -1,4 +1,4 @@ -/*********************************************************************** +/* * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * @@ -9,7 +9,7 @@ * 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. - *********************************************************************** + * */ /* @@ -18,28 +18,26 @@ * This file exports one function: * vrc5477_irq_init(u32 irq_base); */ - -#include +#include #include #include -#include +#include -/* [jsun] sooner or later we should move this debug stuff to MIPS common */ -#include +#include /* number of total irqs supported by Vrc5477 */ #define NUM_5477_IRQ 32 -static int vrc5477_irq_base=-1; +static int vrc5477_irq_base = -1; static void vrc5477_irq_enable(unsigned int irq) { - MIPS_ASSERT(vrc5477_irq_base != -1); - MIPS_ASSERT(irq >= vrc5477_irq_base); - MIPS_ASSERT(irq < vrc5477_irq_base+ NUM_5477_IRQ); + db_assert(vrc5477_irq_base != -1); + db_assert(irq >= vrc5477_irq_base); + db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ); ll_vrc5477_irq_enable(irq - vrc5477_irq_base); } @@ -47,9 +45,9 @@ static void vrc5477_irq_disable(unsigned int irq) { - MIPS_ASSERT(vrc5477_irq_base != -1); - MIPS_ASSERT(irq >= vrc5477_irq_base); - MIPS_ASSERT(irq < vrc5477_irq_base + NUM_5477_IRQ); + db_assert(vrc5477_irq_base != -1); + db_assert(irq >= vrc5477_irq_base); + db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ); ll_vrc5477_irq_disable(irq - vrc5477_irq_base); } @@ -65,9 +63,9 @@ static void vrc5477_irq_ack(unsigned int irq) { - MIPS_ASSERT(vrc5477_irq_base != -1); - MIPS_ASSERT(irq >= vrc5477_irq_base); - MIPS_ASSERT(irq < vrc5477_irq_base+ NUM_5477_IRQ); + db_assert(vrc5477_irq_base != -1); + db_assert(irq >= vrc5477_irq_base); + db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ); /* clear the interrupt bit */ /* some irqs require the driver to clear the sources */ @@ -82,11 +80,12 @@ static void vrc5477_irq_end(unsigned int irq) { - MIPS_ASSERT(vrc5477_irq_base != -1); - MIPS_ASSERT(irq >= vrc5477_irq_base); - MIPS_ASSERT(irq < vrc5477_irq_base + NUM_5477_IRQ); + db_assert(vrc5477_irq_base != -1); + db_assert(irq >= vrc5477_irq_base); + db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ); - ll_vrc5477_irq_enable( irq - vrc5477_irq_base); + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + ll_vrc5477_irq_enable( irq - vrc5477_irq_base); } hw_irq_controller vrc5477_irq_controller = { @@ -119,8 +118,8 @@ int vrc5477_irq_to_irq(int irq) { - MIPS_ASSERT(irq >= 0); - MIPS_ASSERT(irq < NUM_5477_IRQ); + db_assert(irq >= 0); + db_assert(irq < NUM_5477_IRQ); return irq + vrc5477_irq_base; } @@ -131,10 +130,10 @@ u32 reg_bitmask; u32 reg_index; - MIPS_ASSERT(vrc5477_irq >= 0); - MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ); - MIPS_ASSERT(ip >= 0); - MIPS_ASSERT((ip < 5) || (ip == 6)); + db_assert(vrc5477_irq >= 0); + db_assert(vrc5477_irq < NUM_5477_IRQ); + db_assert(ip >= 0); + db_assert((ip < 5) || (ip == 6)); reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4; reg_value = ddb_in32(reg_index); @@ -150,13 +149,13 @@ u32 reg_bitmask; u32 reg_index; - MIPS_ASSERT(vrc5477_irq >= 0); - MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ); + db_assert(vrc5477_irq >= 0); + db_assert(vrc5477_irq < NUM_5477_IRQ); reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4; reg_value = ddb_in32(reg_index); reg_bitmask = 8 << (vrc5477_irq % 8 * 4); - MIPS_ASSERT((reg_value & reg_bitmask) == 0); + db_assert((reg_value & reg_bitmask) == 0); ddb_out32(reg_index, reg_value | reg_bitmask); } @@ -166,14 +165,14 @@ u32 reg_bitmask; u32 reg_index; - MIPS_ASSERT(vrc5477_irq >= 0); - MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ); + db_assert(vrc5477_irq >= 0); + db_assert(vrc5477_irq < NUM_5477_IRQ); reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4; reg_value = ddb_in32(reg_index); reg_bitmask = 8 << (vrc5477_irq % 8 * 4); /* we assert that the interrupt is enabled (perhaps over-zealous) */ - MIPS_ASSERT( (reg_value & reg_bitmask) != 0); + db_assert( (reg_value & reg_bitmask) != 0); ddb_out32(reg_index, reg_value & ~reg_bitmask); } diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/kgdb_io.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/kgdb_io.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/kgdb_io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/kgdb_io.c Sat Mar 30 22:55:26 2002 @@ -1,17 +1,41 @@ +/* + * kgdb io functions for DDB5477. We use the second serial port (upper one). + * + * Copyright (C) 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ -#include +/* ======================= CONFIG ======================== */ -#if (defined(CONFIG_DDB5477) && defined(CONFIG_REMOTE_DEBUG)) +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xbfa04240 +#define MAX_BAUD 115200 -/* --- CONFIG --- */ +/* distance in bytes between two serial registers */ +#define REG_OFFSET 8 + +/* + * 0 - kgdb does serial init + * 1 - kgdb skip serial init + */ +static int remoteDebugInitialized = 0; + +/* + * the default baud rate *if* kgdb does serial init + */ +#define BAUD_DEFAULT UART16550_BAUD_38400 + +/* ======================= END OF CONFIG ======================== */ -/* we need uint32 uint8 */ -/* #include "types.h" */ typedef unsigned char uint8; typedef unsigned int uint32; -/* --- END OF CONFIG --- */ - #define UART16550_BAUD_2400 2400 #define UART16550_BAUD_4800 4800 #define UART16550_BAUD_9600 9600 @@ -34,21 +58,10 @@ #define UART16550_STOP_1BIT 0x0 #define UART16550_STOP_2BIT 0x4 -/* ----------------------------------------------------- */ - -/* === CONFIG === */ - -/* [jsun] we use the second serial port for kdb */ -#define BASE 0xbfa04240 -#define MAX_BAUD 115200 -#define REG_OFFSET 8 - -/* === END OF CONFIG === */ - /* register offset */ -#define OFS_RCV_BUFFER (0*REG_OFFSET) -#define OFS_TRANS_HOLD (0*REG_OFFSET) -#define OFS_SEND_BUFFER (0*REG_OFFSET) +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 #define OFS_INTR_ENABLE (1*REG_OFFSET) #define OFS_INTR_ID (2*REG_OFFSET) #define OFS_DATA_FORMAT (3*REG_OFFSET) @@ -70,73 +83,54 @@ void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) { - /* disable interrupts */ - UART16550_WRITE(OFS_INTR_ENABLE, 0); + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); - /* set up buad rate */ - { - uint32 divisor; - - /* set DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x80); - - /* set divisor */ - divisor = MAX_BAUD / baud; - UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); - UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); - - /* clear DIAB bit */ - UART16550_WRITE(OFS_LINE_CONTROL, 0x0); - } + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } - /* set data format */ - UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); } -static int remoteDebugInitialized = 0; - -int debug_state = -1; uint8 getDebugChar(void) { - uint8 c; - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_38400, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } - while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); - c= UART16550_READ(OFS_RCV_BUFFER); -/* - if (state != 1) { - state = 1; - debug_out("\ngetDebugChar: ", 15); - } - debug_out(&c, 1); -*/ - return c; + while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); } int putDebugChar(uint8 byte) { - if (!remoteDebugInitialized) { - remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_9600, - UART16550_DATA_8BIT, - UART16550_PARITY_NONE, UART16550_STOP_1BIT); - } - - while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); - UART16550_WRITE(OFS_SEND_BUFFER, byte); - if (debug_state != 2) { - debug_state = 2; - // debug_out("\nputDebugChar: ", 15); - } - // debug_out(&byte, 1); - return 1; + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; } - -#endif diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/lcd44780.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/lcd44780.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/lcd44780.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/lcd44780.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,92 @@ +/* + * lcd44780.c + * Simple "driver" for a memory-mapped 44780-style LCD display. + * + * Copyright 2001 Bradley D. LaRonde + * + * 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. + * + */ + +#define LCD44780_COMMAND ((volatile unsigned char *)0xbe020000) +#define LCD44780_DATA ((volatile unsigned char *)0xbe020001) + +#define LCD44780_4BIT_1LINE 0x20 +#define LCD44780_4BIT_2LINE 0x28 +#define LCD44780_8BIT_1LINE 0x30 +#define LCD44780_8BIT_2LINE 0x38 +#define LCD44780_MODE_DEC 0x04 +#define LCD44780_MODE_DEC_SHIFT 0x05 +#define LCD44780_MODE_INC 0x06 +#define LCD44780_MODE_INC_SHIFT 0x07 +#define LCD44780_SCROLL_LEFT 0x18 +#define LCD44780_SCROLL_RIGHT 0x1e +#define LCD44780_CURSOR_UNDERLINE 0x0e +#define LCD44780_CURSOR_BLOCK 0x0f +#define LCD44780_CURSOR_OFF 0x0c +#define LCD44780_CLEAR 0x01 +#define LCD44780_BLANK 0x08 +#define LCD44780_RESTORE 0x0c // Same as CURSOR_OFF +#define LCD44780_HOME 0x02 +#define LCD44780_LEFT 0x10 +#define LCD44780_RIGHT 0x14 + +void lcd44780_wait(void) +{ + int i, j; + for(i=0; i < 400; i++) + for(j=0; j < 10000; j++); +} + +void lcd44780_command(unsigned char c) +{ + *LCD44780_COMMAND = c; + lcd44780_wait(); +} + +void lcd44780_data(unsigned char c) +{ + *LCD44780_DATA = c; + lcd44780_wait(); +} + +void lcd44780_puts(const char* s) +{ + int i,j; + int pos = 0; + + lcd44780_command(LCD44780_CLEAR); + while(*s) { + lcd44780_data(*s); + s++; + pos++; + if (pos == 8) { + /* We must write 32 of spaces to get cursor to 2nd line */ + for (j=0; j<32; j++) { + lcd44780_data(' '); + } + } + if (pos == 16) { + /* We have filled all 16 character positions, so stop + outputing data */ + break; + } + } +#ifdef LCD44780_PUTS_PAUSE + for(i = 1; i < 2000; i++) + lcd44780_wait(); +#endif +} + +void lcd44780_init(void) +{ + // The display on the RockHopper is physically a single + // 16 char line (two 8 char lines concatenated). bdl + lcd44780_command(LCD44780_8BIT_2LINE); + lcd44780_command(LCD44780_MODE_INC); + lcd44780_command(LCD44780_CURSOR_BLOCK); + lcd44780_command(LCD44780_CLEAR); +} diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/lcd44780.h linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/lcd44780.h --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/lcd44780.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/lcd44780.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,15 @@ +/* + * lcd44780.h + * Simple "driver" for a memory-mapped 44780-style LCD display. + * + * Copyright 2001 Bradley D. LaRonde + * + * 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. + * + */ + +void lcd44780_puts(const char* s); +void lcd44780_init(void); diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/pci.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/pci.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/pci.c Sat Mar 30 22:55:26 2002 @@ -1,11 +1,25 @@ +/* + * PCI code for DDB5477. + * + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + #include #include #include #include +#include +#include + #include -#include -#include static struct resource extpci_io_resource = { "ext pci IO space", @@ -103,8 +117,16 @@ pci_for_each_dev(dev) { slot_num = PCI_SLOT(dev->devfn); - MIPS_ASSERT(slot_num < MAX_SLOT_NUM); - MIPS_ASSERT(irq_map[slot_num] != 0xff); + + /* we don't do IRQ fixup for sub-bus yet */ + if (dev->bus->parent != NULL) { + db_run(printk("Don't know how to fixup irq for PCI device %d on sub-bus %d\n", + slot_num, dev->bus->number)); + continue; + } + + db_assert(slot_num < MAX_SLOT_NUM); + db_assert(irq_map[slot_num] != 0xff); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, @@ -113,7 +135,7 @@ } } -#if defined(CONFIG_LL_DEBUG) +#if defined(CONFIG_DEBUG) extern void jsun_scan_pci_bus(void); extern void jsun_assign_pci_resource(void); #endif @@ -143,5 +165,15 @@ unsigned __init int pcibios_assign_all_busses(void) { + /* we hope pci_auto has assigned the bus numbers to all buses */ return 1; } + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ +} + +void __init pcibios_fixup(void) +{ +} + diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/pci_ops.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/pci_ops.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/pci_ops.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -26,7 +26,8 @@ #include #include -#include +#include + #include /* @@ -72,14 +73,11 @@ u32 virt_addr = swap->config_base; u32 option; - /* [jsun] hack for testing */ - // if (slot_num == 4) slot_num = 0; - /* minimum pdar (window) size is 2MB */ - MIPS_ASSERT(swap->config_size >= (2 << 20)); + db_assert(swap->config_size >= (2 << 20)); - MIPS_ASSERT(slot_num < (1 << 5)); - MIPS_ASSERT(bus < (1 << 8)); + db_assert(slot_num < (1 << 5)); + db_assert(bus < (1 << 8)); /* backup registers */ swap->pdar_backup = ddb_in32(swap->pdar); @@ -103,7 +101,6 @@ } else { /* type 1 config */ pci_addr = (bus << 16) | (slot_num << 11); - panic("ddb_access_config_base: we don't support type 1 config Yet"); } /* @@ -115,7 +112,7 @@ virt_addr = KSEG1ADDR(swap->config_base + pci_addr); pciinit_offset = 0; } else { - MIPS_ASSERT( (pci_addr & (swap->config_size - 1)) == 0); + db_assert( (pci_addr & (swap->config_size - 1)) == 0); virt_addr = KSEG1ADDR(swap->config_base); pciinit_offset = pci_addr; } @@ -142,13 +139,13 @@ u32 bus, slot_num, func_num; u32 base; - MIPS_ASSERT((where & 3) == 0); - MIPS_ASSERT(where < (1 << 8)); + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); /* check if the bus is top-level */ if (dev->bus->parent != NULL) { bus = dev->bus->number; - MIPS_ASSERT(bus != 0); + db_assert(bus != 0); } else { bus = 0; } @@ -169,7 +166,7 @@ int status; u32 result; - MIPS_ASSERT((where & 1) == 0); + db_assert((where & 1) == 0); status = read_config_dword(swap, dev, where & ~3, &result); if (where & 2) result >>= 16; @@ -200,13 +197,13 @@ u32 bus, slot_num, func_num; u32 base; - MIPS_ASSERT((where & 3) == 0); - MIPS_ASSERT(where < (1 << 8)); + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); /* check if the bus is top-level */ if (dev->bus->parent != NULL) { bus = dev->bus->number; - MIPS_ASSERT(bus != 0); + db_assert(bus != 0); } else { bus = 0; } @@ -227,7 +224,7 @@ int status, shift=0; u32 result; - MIPS_ASSERT((where & 1) == 0); + db_assert((where & 1) == 0); status = read_config_dword(swap, dev, where & ~3, &result); if (status != PCIBIOS_SUCCESSFUL) return status; @@ -303,7 +300,7 @@ iopci_write_config_dword }; -#if defined(CONFIG_LL_DEBUG) +#if defined(CONFIG_DEBUG) void jsun_scan_pci_bus(void) { struct pci_bus bus; @@ -332,26 +329,26 @@ int i; dev.devfn = devfn; - MIPS_VERIFY(pci_read_config_dword(&dev, 0, &temp), - == PCIBIOS_SUCCESSFUL); + db_verify(pci_read_config_dword(&dev, 0, &temp), + == PCIBIOS_SUCCESSFUL); if (temp == 0xffffffff) continue; printk("slot %d: (addr %d) \n", devfn/8, 11+devfn/8); /* verify read word and byte */ - MIPS_VERIFY(pci_read_config_word(&dev, 2, &temp16), - == PCIBIOS_SUCCESSFUL); - MIPS_ASSERT(temp16 == (temp >> 16)); - MIPS_VERIFY(pci_read_config_byte(&dev, 3, &temp8), - == PCIBIOS_SUCCESSFUL); - MIPS_ASSERT(temp8 == (temp >> 24)); - MIPS_VERIFY(pci_read_config_byte(&dev, 1, &temp8), - == PCIBIOS_SUCCESSFUL); - MIPS_ASSERT(temp8 == ((temp >> 8) & 0xff)); + db_verify(pci_read_config_word(&dev, 2, &temp16), + == PCIBIOS_SUCCESSFUL); + db_assert(temp16 == (temp >> 16)); + db_verify(pci_read_config_byte(&dev, 3, &temp8), + == PCIBIOS_SUCCESSFUL); + db_assert(temp8 == (temp >> 24)); + db_verify(pci_read_config_byte(&dev, 1, &temp8), + == PCIBIOS_SUCCESSFUL); + db_assert(temp8 == ((temp >> 8) & 0xff)); for (i=0; i < 16; i++) { - MIPS_VERIFY(pci_read_config_dword(&dev, i*4, &temp), - == PCIBIOS_SUCCESSFUL); + db_verify(pci_read_config_dword(&dev, i*4, &temp), + == PCIBIOS_SUCCESSFUL); printk("\t%08X", temp); if ((i%4) == 3) printk("\n"); } @@ -374,7 +371,7 @@ /* for slot 5 (ext pci 1) eepro card */ dev.devfn = 5*8; pci_read_config_dword(&dev, 0, &temp); - MIPS_ASSERT(temp == 0x12298086); + db_assert(temp == 0x12298086); pci_write_config_dword(&dev, PCI_BASE_ADDRESS_0, DDB_PCI0_MEM_BASE); pci_write_config_dword(&dev, PCI_BASE_ADDRESS_1, 0); @@ -396,7 +393,7 @@ /* for slot 4 on board ether chip */ dev.devfn = 4*8; pci_read_config_dword(&dev, 0, &temp); - MIPS_ASSERT(temp == 0x00191011); + db_assert(temp == 0x00191011); pci_write_config_dword(&dev, PCI_BASE_ADDRESS_0, 0x1000); pci_write_config_dword(&dev, PCI_BASE_ADDRESS_1, DDB_PCI0_MEM_BASE); diff -urN linux-2.4.18/arch/mips/ddb5xxx/ddb5477/setup.c linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/setup.c --- linux-2.4.18/arch/mips/ddb5xxx/ddb5477/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ddb5xxx/ddb5477/setup.c Sat Mar 30 22:55:26 2002 @@ -10,10 +10,7 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. - * - *********************************************************************** */ - #include #include #include @@ -27,18 +24,21 @@ #include #include /* for HZ */ +#include #include #include #include #include #include #include +#include #include +#include "lcd44780.h" -#define USE_CPU_COUNTER_TIMER /* whether we use cpu counter */ +// #define USE_CPU_COUNTER_TIMER /* whether we use cpu counter */ #ifdef USE_CPU_COUNTER_TIMER #define CPU_COUNTER_FREQUENCY 83000000 @@ -60,7 +60,7 @@ /* CPU cold reset */ t = ddb_in32(DDB_CPUSTAT); - MIPS_ASSERT((t&1)); + db_assert((t&1)); ddb_out32(DDB_CPUSTAT, t); /* Call the PROM */ @@ -87,13 +87,13 @@ #endif /* we have ds1396 RTC chip */ - rtc_ds1386_init(KSEG1ADDR(DDB_LCS1_BASE)); + if (mips_machtype == MACH_NEC_ROCKHOPPER) { + rtc_ds1386_init(KSEG1ADDR(DDB_LCS2_BASE)); + } else { + rtc_ds1386_init(KSEG1ADDR(DDB_LCS1_BASE)); + } } -#if defined(CONFIG_LL_DEBUG) -int board_init_done_flag = 0; -#endif - extern int setup_irq(unsigned int irq, struct irqaction *irqaction); static void __init ddb_timer_setup(struct irqaction *irq) { @@ -115,9 +115,6 @@ setup_irq(SP_TIMER_IRQ, irq); #endif - - /* this is the last board dependent code */ - MIPS_DEBUG(board_init_done_flag = 1); } static void ddb5477_board_init(void); @@ -132,7 +129,7 @@ extern int panic_timeout; irq_setup = ddb5477_irq_setup; - mips_io_port_base = KSEG1ADDR(DDB_PCI_IO_BASE); + set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE)); board_time_init = ddb_time_init; board_timer_setup = ddb_timer_setup; @@ -148,6 +145,10 @@ /* Reboot on panic */ panic_timeout = 180; +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + /* initialize board - we don't trust the loader */ ddb5477_board_init(); @@ -156,7 +157,6 @@ initrd_start = (unsigned long)&__rd_start; initrd_end = (unsigned long)&__rd_end; #endif - } static void __init ddb5477_board_init() @@ -164,27 +164,41 @@ /* ----------- setup PDARs ------------ */ /* SDRAM should have been set */ - MIPS_ASSERT(ddb_in32(DDB_SDRAM0) == - ddb_calc_pdar(DDB_SDRAM_BASE, DDB_SDRAM_SIZE, 32, 0, 1)); + db_assert(ddb_in32(DDB_SDRAM0) == + ddb_calc_pdar(DDB_SDRAM_BASE, board_ram_size, 32, 0, 1)); /* SDRAM1 should be turned off. What is this for anyway ? */ - MIPS_ASSERT( (ddb_in32(DDB_SDRAM1) & 0xf) == 0); + db_assert( (ddb_in32(DDB_SDRAM1) & 0xf) == 0); + + /* Setup local bus. */ - /* Set LDCSs */ - /* flash */ + /* Flash U12 PDAR and timing. */ ddb_set_pdar(DDB_LCS0, DDB_LCS0_BASE, DDB_LCS0_SIZE, 16, 0, 0); - /* misc */ - ddb_set_pdar(DDB_LCS1, DDB_LCS1_BASE, DDB_LCS1_SIZE, 8, 0, 0); - /* mezzanie (?) */ - ddb_set_pdar(DDB_LCS2, DDB_LCS2_BASE, DDB_LCS2_SIZE, 16, 0, 0); + ddb_out32(DDB_LCST0, 0x00090842); + + /* We need to setup LCS1 and LCS2 differently based on the + board_version */ + if (mips_machtype == MACH_NEC_ROCKHOPPER) { + /* Flash U13 PDAR and timing. */ + ddb_set_pdar(DDB_LCS1, DDB_LCS1_BASE, DDB_LCS1_SIZE, 16, 0, 0); + ddb_out32(DDB_LCST1, 0x00090842); + + /* EPLD (NVRAM, switch, LCD, and mezzanie). */ + ddb_set_pdar(DDB_LCS2, DDB_LCS2_BASE, DDB_LCS2_SIZE, 8, 0, 0); + } else { + /* misc */ + ddb_set_pdar(DDB_LCS1, DDB_LCS1_BASE, DDB_LCS1_SIZE, 8, 0, 0); + /* mezzanie (?) */ + ddb_set_pdar(DDB_LCS2, DDB_LCS2_BASE, DDB_LCS2_SIZE, 16, 0, 0); + } /* verify VRC5477 base addr */ - MIPS_ASSERT(ddb_in32(DDB_VRC5477) == - ddb_calc_pdar(DDB_VRC5477_BASE, DDB_VRC5477_SIZE, 32, 0, 1)); + db_assert(ddb_in32(DDB_VRC5477) == + ddb_calc_pdar(DDB_VRC5477_BASE, DDB_VRC5477_SIZE, 32, 0, 1)); /* verify BOOT ROM addr */ - MIPS_ASSERT(ddb_in32(DDB_BOOTCS) == - ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0)); + db_assert(ddb_in32(DDB_BOOTCS) == + ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0)); /* setup PCI windows - window0 for MEM/config, window1 for IO */ ddb_set_pdar(DDB_PCIW0, DDB_PCI0_MEM_BASE, DDB_PCI0_MEM_SIZE, 32, 0, 1); @@ -248,4 +262,10 @@ /* For dual-function pins, make them all non-GPIO */ ddb_out32(DDB_GIUFUNSEL, 0x0); // ddb_out32(DDB_GIUFUNSEL, 0xfe0fcfff); /* NEC recommanded value */ + + if (mips_machtype == MACH_NEC_ROCKHOPPER) { + printk("lcd44780: initializing\n"); + lcd44780_init(); + lcd44780_puts("Linux/MIPS rolls"); + } } diff -urN linux-2.4.18/arch/mips/dec/int-handler.S linux-2.4.19-pre5/arch/mips/dec/int-handler.S --- linux-2.4.18/arch/mips/dec/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/int-handler.S Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ * arch/mips/dec/int-handler.S * * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen - * Copyright (C) 2000 Maciej W. Rozycki + * Copyright (C) 2000, 2001 Maciej W. Rozycki * * Written by Ralf Baechle and Andreas Busse, modified for DECStation * support by Paul Antoine and Harald Koerfgen. @@ -140,15 +140,19 @@ */ mfc0 t0,CP0_CAUSE # get pending interrupts mfc0 t2,CP0_STATUS - la t1,cpu_mask_tbl + andi t0,ST0_IM # CAUSE.CE may be non-zero! and t0,t2 # isolate allowed ones beqz t0,spurious + andi t2,t0,DEC_IE_FPU + bnez t2,fpu # handle FPU immediately + /* * Find irq with highest priority */ -1: lw t2,(t1) + la t1,cpu_mask_tbl +1: lw t2,(t1) move t3,t0 and t3,t2 beq t3,zero,1b @@ -169,7 +173,7 @@ * Handle "IRQ Controller" Interrupts * Masked Interrupts are still visible and have to be masked "by hand". */ - EXPORT(kn02_io_int) + FEXPORT(kn02_io_int) kn02_io_int: # 3max lui t0,KN02_CSR_ADDR>>16 # get interrupt status and mask lw t0,(t0) @@ -179,7 +183,7 @@ b find_int and t0,t3 # mask out allowed ones - EXPORT(kn03_io_int) + FEXPORT(kn03_io_int) kn03_io_int: # 3max+ lui t2,KN03_IOASIC_BASE>>16 # upper part of IOASIC Address lw t0,SIR(t2) # get status: IOASIC isr @@ -188,7 +192,7 @@ b find_int and t0,t3 # mask out allowed ones - EXPORT(kn02xa_io_int) + FEXPORT(kn02xa_io_int) kn02xa_io_int: # 3min/maxine lui t2,KN02XA_IOASIC_BASE>>16 # upper part of IOASIC Address @@ -219,28 +223,27 @@ j ret_from_irq nop +fpu: + j handle_fpe_int + nop + spurious: j spurious_interrupt nop END(decstation_handle_int) -/* - * Interrupt routines common to all DECStations first. - */ - EXPORT(dec_intr_fpu) -dec_intr_fpu: PANIC("Unimplemented FPU interrupt handler") /* * Generic unimplemented interrupt routines - ivec_tbl is initialised to * point all interrupts here. The table is then filled in by machine-specific * initialisation in dec_setup(). */ - EXPORT(dec_intr_unimplemented) + FEXPORT(dec_intr_unimplemented) dec_intr_unimplemented: mfc0 a1,CP0_CAUSE # cheats way of printing an arg! nop # to be sure... PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%x"); - EXPORT(asic_intr_unimplemented) + FEXPORT(asic_intr_unimplemented) asic_intr_unimplemented: move a1,t0 # cheats way of printing an arg! PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%x"); diff -urN linux-2.4.18/arch/mips/dec/irq.c linux-2.4.19-pre5/arch/mips/dec/irq.c --- linux-2.4.18/arch/mips/dec/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/irq.c Sat Mar 30 22:55:26 2002 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -34,48 +33,52 @@ extern asmlinkage void decstation_handle_int(void); -unsigned long spurious_count = 0; +atomic_t irq_err_count; static inline void mask_irq(unsigned int irq_nr) { - unsigned int dummy; + unsigned int dummy; - if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ - *imr &= ~dec_interrupt[irq_nr].iemask; - dummy = *imr; - dummy = *imr; - } else /* This is a cpu interrupt */ - change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) & ~dec_interrupt[irq_nr].cpu_mask); + if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ + *imr &= ~dec_interrupt[irq_nr].iemask; + dummy = *imr; + dummy = *imr; + } else /* This is a cpu interrupt */ + change_cp0_status(ST0_IM, + read_32bit_cp0_register(CP0_STATUS) & + ~dec_interrupt[irq_nr].cpu_mask); } static inline void unmask_irq(unsigned int irq_nr) { - unsigned int dummy; + unsigned int dummy; - if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ - *imr |= dec_interrupt[irq_nr].iemask; - dummy = *imr; - dummy = *imr; - } - change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) | dec_interrupt[irq_nr].cpu_mask); + if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ + *imr |= dec_interrupt[irq_nr].iemask; + dummy = *imr; + dummy = *imr; + } + change_cp0_status(ST0_IM, + read_32bit_cp0_register(CP0_STATUS) | + dec_interrupt[irq_nr].cpu_mask); } void disable_irq(unsigned int irq_nr) { - unsigned long flags; + unsigned long flags; - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); } void enable_irq(unsigned int irq_nr) { - unsigned long flags; + unsigned long flags; - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); } /* @@ -84,35 +87,35 @@ */ extern void interrupt(void); -static struct irqaction *irq_action[32] = -{ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +static struct irqaction *irq_action[32] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int get_irq_list(char *buf) { - int i, len = 0; - struct irqaction *action; + int i, len = 0; + struct irqaction *action; - for (i = 0; i < 32; i++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf + len, "%2d: %8d %c %s", - i, kstat.irqs[0][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action = action->next; action; action = action->next) { - len += sprintf(buf + len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + for (i = 0; i < 32; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf + len, "%2d: %8d %c %s", + i, kstat.irqs[0][i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action = action->next; action; action = action->next) { + len += sprintf(buf + len, ",%s %s", + (action-> + flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf + len, "\n"); } - len += sprintf(buf + len, "\n"); - } - return len; + return len; } /* @@ -124,33 +127,34 @@ */ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) { - struct irqaction *action; - int do_random, cpu; + struct irqaction *action; + int do_random, cpu; - cpu = smp_processor_id(); - irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; - - mask_irq(irq); - action = *(irq + irq_action); - if (action) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); + cpu = smp_processor_id(); + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + mask_irq(irq); action = *(irq + irq_action); - do_random = 0; - do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - unmask_irq(irq); - } - irq_exit(cpu, irq); + if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + unmask_irq(irq); + } + irq_exit(cpu, irq); - /* unmasking and bottom half handling is done magically for us. */ + if (softirq_pending(cpu)) + do_softirq(); } /* @@ -159,139 +163,145 @@ */ int setup_dec_irq(int irq, struct irqaction *new) { - int shared = 0; - struct irqaction *old, **p; - unsigned long flags; - - p = irq_action + irq; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) - return -EBUSY; - - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - - save_and_cli(flags); - *p = new; - - if (!shared) { - unmask_irq(irq); - } - restore_flags(flags); - return 0; + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_and_cli(flags); + *p = new; + + if (!shared) { + unmask_irq(irq); + } + restore_flags(flags); + return 0; } int request_irq(unsigned int irq, void (*handler) (int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, - void *dev_id) -{ - int retval; - struct irqaction *action; - - if (irq >= 32) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_dec_irq(irq, action); - - if (retval) - kfree(action); - return retval; + unsigned long irqflags, const char *devname, void *dev_id) +{ + int retval; + struct irqaction *action; + + if (irq >= 32) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = + (struct irqaction *) kmalloc(sizeof(struct irqaction), + GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_dec_irq(irq, action); + + if (retval) + kfree(action); + return retval; } void free_irq(unsigned int irq, void *dev_id) { - struct irqaction *action, **p; - unsigned long flags; - - if (irq > 39) { - printk("Trying to free IRQ%d\n", irq); - return; - } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; + struct irqaction *action, **p; + unsigned long flags; - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - if (!irq[irq_action]) - mask_irq(irq); - restore_flags(flags); - kfree(action); - return; - } - printk("Trying to free free IRQ%d\n", irq); + if (irq > 39) { + printk("Trying to free IRQ%d\n", irq); + return; + } + for (p = irq + irq_action; (action = *p) != NULL; + p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_and_cli(flags); + *p = action->next; + if (!irq[irq_action]) + mask_irq(irq); + restore_flags(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n", irq); } unsigned long probe_irq_on(void) { - /* TODO */ - return 0; + /* TODO */ + return 0; } int probe_irq_off(unsigned long irqs) { - /* TODO */ - return 0; + /* TODO */ + return 0; +} + +void init_irq_proc(void) +{ + /* Nothing, for now. */ } void __init init_IRQ(void) { - switch (mips_machtype) { - case MACH_DS23100: - dec_init_kn01(); - break; - case MACH_DS5100: /* DS5100 MIPSMATE */ - dec_init_kn230(); - break; - case MACH_DS5000_200: /* DS5000 3max */ - dec_init_kn02(); - break; - case MACH_DS5000_1XX: /* DS5000/100 3min */ - dec_init_kn02ba(); - break; - case MACH_DS5000_2X0: /* DS5000/240 3max+ */ - dec_init_kn03(); - break; - case MACH_DS5000_XX: /* Personal DS5000/2x */ - dec_init_kn02ca(); - break; - case MACH_DS5800: /* DS5800 Isis */ - panic("Don't know how to set this up!"); - break; - case MACH_DS5400: /* DS5400 MIPSfair */ - panic("Don't know how to set this up!"); - break; - case MACH_DS5500: /* DS5500 MIPSfair-2 */ - panic("Don't know how to set this up!"); - break; - } - set_except_vector(0, decstation_handle_int); + switch (mips_machtype) { + case MACH_DS23100: + dec_init_kn01(); + break; + case MACH_DS5100: /* DS5100 MIPSMATE */ + dec_init_kn230(); + break; + case MACH_DS5000_200: /* DS5000 3max */ + dec_init_kn02(); + break; + case MACH_DS5000_1XX: /* DS5000/100 3min */ + dec_init_kn02ba(); + break; + case MACH_DS5000_2X0: /* DS5000/240 3max+ */ + dec_init_kn03(); + break; + case MACH_DS5000_XX: /* Personal DS5000/2x */ + dec_init_kn02ca(); + break; + case MACH_DS5800: /* DS5800 Isis */ + panic("Don't know how to set this up!"); + break; + case MACH_DS5400: /* DS5400 MIPSfair */ + panic("Don't know how to set this up!"); + break; + case MACH_DS5500: /* DS5500 MIPSfair-2 */ + panic("Don't know how to set this up!"); + break; + } + set_except_vector(0, decstation_handle_int); } diff -urN linux-2.4.18/arch/mips/dec/prom/Makefile linux-2.4.19-pre5/arch/mips/dec/prom/Makefile --- linux-2.4.18/arch/mips/dec/prom/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/prom/Makefile Sat Mar 30 22:55:26 2002 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1999/01/17 03:49:44 ralf Exp $ +# # Makefile for the DECstation prom monitor library routines # under Linux. # @@ -13,17 +13,8 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = init.o memory.o cmdline.o identify.o locore.o - -all: rexlib.a - -rexlib.a: $(OBJS) - $(AR) rcs rexlib.a $(OBJS) - sync - -locore.o: locore.S +L_TARGET = rexlib.a -dep: - $(CPP) $(CPPFLAGS) -M *.c > .depend +obj-y += init.o memory.o cmdline.o identify.o locore.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/dec/prom/cmdline.c linux-2.4.19-pre5/arch/mips/dec/prom/cmdline.c --- linux-2.4.18/arch/mips/dec/prom/cmdline.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/prom/cmdline.c Sat Mar 30 22:55:26 2002 @@ -17,7 +17,7 @@ extern int (*prom_printf)(char *, ...); #endif -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; void __init prom_init_cmdline(int argc, char **argv, unsigned long magic) { diff -urN linux-2.4.18/arch/mips/dec/prom/identify.c linux-2.4.19-pre5/arch/mips/dec/prom/identify.c --- linux-2.4.18/arch/mips/dec/prom/identify.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/prom/identify.c Sat Mar 30 22:55:26 2002 @@ -2,8 +2,6 @@ * identify.c: machine identification code. * * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine - * - * $Id: identify.c,v 1.2 1999/10/09 00:00:58 ralf Exp $ */ #include #include @@ -20,6 +18,26 @@ extern unsigned long mips_machgroup; extern unsigned long mips_machtype; + +extern unsigned long mips_machtype; +const char *get_system_type(void) +{ + static char system[32]; + int called = 0; + const char *dec_system_strings[] = { "unknown", "DECstation 2100/3100", + "DECstation 5100", "DECstation 5000/200", "DECstation 5000/1xx", + "Personal DECstation 5000/xx", "DECstation 5000/2x0", + "DECstation 5400", "DECstation 5500", "DECstation 5800" + }; + + if (called == 0) { + called = 1; + strcpy(system, "Digital "); + strcat(system, dec_system_strings[mips_machtype]); + } + + return system; +} void __init prom_identify_arch (unsigned int magic) { diff -urN linux-2.4.18/arch/mips/dec/prom/memory.c linux-2.4.19-pre5/arch/mips/dec/prom/memory.c --- linux-2.4.18/arch/mips/dec/prom/memory.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/prom/memory.c Sat Mar 30 22:55:26 2002 @@ -3,8 +3,6 @@ * * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine * Copyright (C) 2000 Maciej W. Rozycki - * - * $Id: memory.c,v 1.3 1999/10/09 00:00:58 ralf Exp $ */ #include #include diff -urN linux-2.4.18/arch/mips/dec/reset.c linux-2.4.19-pre5/arch/mips/dec/reset.c --- linux-2.4.18/arch/mips/dec/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/reset.c Sat Mar 30 22:55:26 2002 @@ -1,8 +1,5 @@ /* - * $Id: $ - * - * Reset a DECstation machine. - * + * Reset a DECstation machine. */ void (*back_to_prom)(void) = (void (*)(void))0xBFC00000; diff -urN linux-2.4.18/arch/mips/dec/setup.c linux-2.4.19-pre5/arch/mips/dec/setup.c --- linux-2.4.18/arch/mips/dec/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/setup.c Sat Mar 30 22:55:26 2002 @@ -6,7 +6,7 @@ * for more details. * * Copyright (C) 1998 Harald Koerfgen - * Copyright (C) 2000 Maciej W. Rozycki + * Copyright (C) 2000, 2001 Maciej W. Rozycki */ #include #include @@ -55,7 +55,7 @@ void (*board_time_init) (struct irqaction * irq); -static struct irqaction irq10 = {dec_intr_halt, 0, 0, "halt", NULL, NULL}; +static struct irqaction haltirq = {dec_intr_halt, 0, 0, "halt", NULL, NULL}; /* * enable the periodic interrupts @@ -139,10 +139,10 @@ cpu_mask_tbl[4] = IE_IRQ4; cpu_irq_nr[4] = MEMORY; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[5] = IE_IRQ5; - cpu_irq_nr[5] = FPU; + /* + * Enable board interrupts: FPU. + */ + set_cp0_status(DEC_IE_FPU); } /* dec_init_kn01 */ /* @@ -165,10 +165,10 @@ cpu_mask_tbl[0] = IE_IRQ2; cpu_irq_nr[0] = CLOCK; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[5] = IE_IRQ5; - cpu_irq_nr[5] = FPU; + /* + * Enable board interrupts: FPU. + */ + set_cp0_status(DEC_IE_FPU); } /* dec_init_kn230 */ /* @@ -176,6 +176,8 @@ */ void __init dec_init_kn02(void) { + int dec_ie_io; + /* * Setup some memory addresses. FIXME: probably incomplete! */ @@ -184,10 +186,11 @@ imr = (void *) KN02_CSR_ADDR; /* - * Setup IOASIC interrupt + * Setup I/O interrupt */ + dec_ie_io = IE_IRQ0; cpu_ivec_tbl[1] = kn02_io_int; - cpu_mask_tbl[1] = IE_IRQ0; + cpu_mask_tbl[1] = dec_ie_io; cpu_irq_nr[1] = -1; *imr = *imr & 0xff00ff00; @@ -234,11 +237,10 @@ cpu_mask_tbl[2] = IE_IRQ3; cpu_irq_nr[2] = MEMORY; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[3] = IE_IRQ5; - cpu_irq_nr[3] = FPU; - + /* + * Enable board interrupts: FPU, I/O. + */ + set_cp0_status(DEC_IE_FPU | dec_ie_io); } /* dec_init_kn02 */ /* @@ -246,6 +248,8 @@ */ void __init dec_init_kn02ba(void) { + int dec_ie_ioasic; + /* * Setup some memory addresses. */ @@ -257,9 +261,10 @@ /* * Setup IOASIC interrupt */ - cpu_mask_tbl[0] = IE_IRQ3; - cpu_irq_nr[0] = -1; + dec_ie_ioasic = IE_IRQ3; cpu_ivec_tbl[0] = kn02xa_io_int; + cpu_mask_tbl[0] = dec_ie_ioasic; + cpu_irq_nr[0] = -1; *imr = 0; /* @@ -315,12 +320,12 @@ cpu_mask_tbl[4] = IE_IRQ4; cpu_irq_nr[4] = HALT; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[5] = IE_IRQ5; - cpu_irq_nr[5] = FPU; + /* + * Enable board interrupts: FPU, I/O ASIC. + */ + set_cp0_status(DEC_IE_FPU | dec_ie_ioasic); - dec_halt_init(&irq10); + dec_halt_init(&haltirq); } /* dec_init_kn02ba */ /* @@ -328,6 +333,8 @@ */ void __init dec_init_kn02ca(void) { + int dec_ie_ioasic; + /* * Setup some memory addresses. FIXME: probably incomplete! */ @@ -339,9 +346,10 @@ /* * Setup IOASIC interrupt */ + dec_ie_ioasic = IE_IRQ3; cpu_ivec_tbl[1] = kn02xa_io_int; + cpu_mask_tbl[1] = dec_ie_ioasic; cpu_irq_nr[1] = -1; - cpu_mask_tbl[1] = IE_IRQ3; *imr = 0; /* @@ -392,12 +400,12 @@ cpu_mask_tbl[3] = IE_IRQ4; cpu_irq_nr[3] = HALT; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[4] = IE_IRQ5; - cpu_irq_nr[4] = FPU; + /* + * Enable board interrupts: FPU, I/O ASIC. + */ + set_cp0_status(DEC_IE_FPU | dec_ie_ioasic); - dec_halt_init(&irq10); + dec_halt_init(&haltirq); } /* dec_init_kn02ca */ /* @@ -405,6 +413,8 @@ */ void __init dec_init_kn03(void) { + int dec_ie_ioasic; + /* * Setup some memory addresses. FIXME: probably incomplete! */ @@ -416,8 +426,9 @@ /* * Setup IOASIC interrupt */ + dec_ie_ioasic = IE_IRQ0; cpu_ivec_tbl[1] = kn03_io_int; - cpu_mask_tbl[1] = IE_IRQ0; + cpu_mask_tbl[1] = dec_ie_ioasic; cpu_irq_nr[1] = -1; *imr = 0; @@ -474,10 +485,10 @@ cpu_mask_tbl[3] = IE_IRQ4; cpu_irq_nr[3] = HALT; - dec_interrupt[FPU].cpu_mask = IE_IRQ5; - dec_interrupt[FPU].iemask = 0; - cpu_mask_tbl[4] = IE_IRQ5; - cpu_irq_nr[4] = FPU; + /* + * Enable board interrupts: FPU, I/O ASIC. + */ + set_cp0_status(DEC_IE_FPU | dec_ie_ioasic); - dec_halt_init(&irq10); + dec_halt_init(&haltirq); } /* dec_init_kn03 */ diff -urN linux-2.4.18/arch/mips/dec/time.c linux-2.4.19-pre5/arch/mips/dec/time.c --- linux-2.4.18/arch/mips/dec/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/dec/time.c Sat Mar 30 22:55:26 2002 @@ -8,6 +8,7 @@ * found in some MIPS systems. * */ +#include #include #include #include @@ -44,7 +45,7 @@ /* This is for machines which generate the exact clock. */ #define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff) +#define USECS_PER_JIFFY_FRAC ((u32)((1000000ULL << 32) / HZ)) /* Cycle counter value at the previous timer interrupt.. */ diff -urN linux-2.4.18/arch/mips/defconfig linux-2.4.19-pre5/arch/mips/defconfig --- linux-2.4.18/arch/mips/defconfig Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,37 +15,44 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_BOARD_SCACHE=y +CONFIG_IRQ_CPU=y CONFIG_PC_KEYB=y CONFIG_SGI=y CONFIG_NEW_IRQ=y -CONFIG_OLD_TIME_C=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_PCI is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -58,10 +65,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set CONFIG_CPU_R5000=y # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -70,6 +79,7 @@ # CONFIG_CPU_SB1 is not set # CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_LLDSCD=y @@ -90,6 +100,7 @@ CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -127,6 +138,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -134,8 +146,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -156,6 +166,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -219,6 +230,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -238,7 +250,6 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -273,7 +284,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -358,7 +368,10 @@ # Mice # # CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set # # Joysticks @@ -377,14 +390,28 @@ # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +CONFIG_INDYDOG=y # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -401,13 +428,8 @@ # # SGI Character devices # -CONFIG_VT=y -CONFIG_VT_CONSOLE=y CONFIG_SGI_NEWPORT_CONSOLE=y CONFIG_FONT_8x16=y -# CONFIG_PSMOUSE is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 # # File systems @@ -423,7 +445,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -439,8 +460,9 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -481,6 +503,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -548,9 +572,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -578,12 +604,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -606,25 +630,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -639,5 +668,6 @@ # Kernel hacking # CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-atlas linux-2.4.19-pre5/arch/mips/defconfig-atlas --- linux-2.4.18/arch/mips/defconfig-atlas Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-atlas Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,32 +15,41 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set CONFIG_MIPS_ATLAS=y # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y CONFIG_PCI=y CONFIG_SWAP_IO_SPACE=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -51,10 +60,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set CONFIG_CPU_R5000=y # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -63,6 +74,7 @@ # CONFIG_CPU_SB1 is not set # CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_LLDSCD=y @@ -83,6 +95,7 @@ # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set @@ -121,13 +134,14 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -140,11 +154,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -213,6 +229,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -233,8 +250,8 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -253,6 +270,16 @@ # CONFIG_SCSI_DEBUG is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -265,6 +292,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -274,7 +302,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -385,7 +412,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -413,7 +439,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -429,8 +454,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -471,6 +497,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -506,9 +534,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -536,12 +566,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -564,25 +592,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -599,6 +632,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-cobalt linux-2.4.19-pre5/arch/mips/defconfig-cobalt --- linux-2.4.18/arch/mips/defconfig-cobalt Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-cobalt Sat Mar 30 22:55:26 2002 @@ -0,0 +1,685 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +CONFIG_MIPS_COBALT=y +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_COBALT_LCD=y +CONFIG_PCI=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +CONFIG_CPU_NEVADA=y +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ddb5476 linux-2.4.19-pre5/arch/mips/defconfig-ddb5476 --- linux-2.4.18/arch/mips/defconfig-ddb5476 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-ddb5476 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,23 +15,30 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set CONFIG_DDB5476=y # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set @@ -39,11 +46,15 @@ CONFIG_ISA=y CONFIG_PCI=y CONFIG_PC_KEYB=y -CONFIG_ROTTEN_IRQ=y +CONFIG_NEW_IRQ=y +CONFIG_IRQ_CPU=y +CONFIG_I8259=y CONFIG_HAVE_STD_PC_SERIAL_PORT=y +CONFIG_NEW_PCI=y +CONFIG_PCI_AUTO=y CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y CONFIG_EISA=y -# CONFIG_I8259 is not set # # Loadable module support @@ -54,10 +65,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set CONFIG_CPU_R5432=y # CONFIG_CPU_RM7000 is not set @@ -84,6 +97,7 @@ # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -93,7 +107,6 @@ # # CONFIG_PNP is not set # CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set # # Memory Technology Devices (MTD) @@ -128,6 +141,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -135,7 +149,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -148,11 +162,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -266,6 +282,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -278,6 +304,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -287,7 +314,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -304,6 +330,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=y +# CONFIG_TC35815 is not set # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set @@ -316,15 +343,18 @@ CONFIG_NE2K_PCI=y # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_LAN_SAA9730 is not set # CONFIG_NET_POCKET is not set @@ -433,7 +463,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -461,7 +490,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -477,8 +505,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -519,6 +548,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -543,13 +574,14 @@ # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_E1355 is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_ATY is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_SIS is not set CONFIG_FB_3DFX=y +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -582,13 +614,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -616,12 +654,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -644,25 +680,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -679,6 +720,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +CONFIG_DEBUG=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ddb5477 linux-2.4.19-pre5/arch/mips/defconfig-ddb5477 --- linux-2.4.18/arch/mips/defconfig-ddb5477 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-ddb5477 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,34 +15,44 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set CONFIG_DDB5477=y +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set -CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_PCI=y CONFIG_NEW_TIME_C=y CONFIG_NEW_IRQ=y +CONFIG_IRQ_CPU=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI_AUTO=y +CONFIG_DUMMY_KEYB=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -53,10 +63,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set CONFIG_CPU_R5432=y # CONFIG_CPU_RM7000 is not set @@ -83,6 +95,7 @@ # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -120,6 +133,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -127,7 +141,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -140,11 +154,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -187,6 +203,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -199,6 +225,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -208,7 +235,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -222,6 +248,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=y +# CONFIG_TC35815 is not set # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set @@ -234,15 +261,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_LAN_SAA9730 is not set # CONFIG_NET_POCKET is not set @@ -309,7 +339,8 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -346,7 +377,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -374,7 +404,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -390,8 +419,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -399,7 +429,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -432,6 +462,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -444,7 +476,30 @@ # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_HAL2 is not set +CONFIG_SOUND_VRC5477=y +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support @@ -463,13 +518,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -497,12 +558,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -525,25 +584,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -560,6 +624,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -CONFIG_LL_DEBUG=y +CONFIG_DEBUG=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-decstation linux-2.4.19-pre5/arch/mips/defconfig-decstation --- linux-2.4.18/arch/mips/defconfig-decstation Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-decstation Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,31 +15,37 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set CONFIG_DECSTATION=y # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set +CONFIG_NONCOHERENT_IO=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_PCI is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -52,10 +58,12 @@ # CPU selection # CONFIG_CPU_R3000=y +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -67,7 +75,7 @@ # CONFIG_CPU_ADVANCED is not set # CONFIG_CPU_HAS_LLSC is not set # CONFIG_CPU_HAS_LLDSCD is not set -# CONFIG_CPU_HAS_WB is not set +CONFIG_CPU_HAS_WB=y # # General setup @@ -81,6 +89,7 @@ CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -119,6 +128,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -126,7 +136,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -139,11 +149,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -206,6 +218,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -225,7 +238,6 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -251,6 +263,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -259,7 +272,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -370,7 +382,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -387,13 +398,10 @@ # # DECStation Character devices # -# CONFIG_VT is not set CONFIG_SERIAL=y # CONFIG_DZ is not set CONFIG_ZS=y CONFIG_SERIAL_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_RTC is not set # @@ -410,7 +418,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -426,8 +433,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -468,6 +476,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -511,9 +521,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -541,12 +553,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -569,25 +579,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -604,6 +619,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ev64120 linux-2.4.19-pre5/arch/mips/defconfig-ev64120 --- linux-2.4.18/arch/mips/defconfig-ev64120 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-ev64120 Sat Mar 30 22:55:26 2002 @@ -0,0 +1,616 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +CONFIG_MIPS_EV64120=y +# CONFIG_EVB_PCI1 is not set +# CONFIG_SYSCLK_75 is not set +# CONFIG_SYSCLK_83 is not set +CONFIG_SYSCLK_100=y +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_PCI=y +# CONFIG_ISA is not set +CONFIG_MIPS_GT64120=y +CONFIG_NONCOHERENT_IO=y +CONFIG_OLD_TIME_C=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +CONFIG_CPU_R5000=y +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_IRIX is not set +# CONFIG_FORWARD_KEYBOARD is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ev96100 linux-2.4.19-pre5/arch/mips/defconfig-ev96100 --- linux-2.4.18/arch/mips/defconfig-ev96100 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-ev96100 Sat Mar 30 22:55:26 2002 @@ -0,0 +1,611 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +CONFIG_MIPS_EV96100=y +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_PCI=y +CONFIG_MIPS_GT96100=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI_AUTO=y +CONFIG_SWAP_IO_SPACE=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +CONFIG_CPU_RM7000=y +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_IRIX is not set +# CONFIG_FORWARD_KEYBOARD is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MIPS_GT96100ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-hp-lj linux-2.4.19-pre5/arch/mips/defconfig-hp-lj --- linux-2.4.18/arch/mips/defconfig-hp-lj Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-hp-lj Sat Mar 30 22:55:26 2002 @@ -0,0 +1,754 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +CONFIG_HP_LASERJET=y +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_IRQ_CPU=y +CONFIG_NEW_TIME_C=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +CONFIG_CPU_R5000=y +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=3 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=10040000 +CONFIG_MTD_PHYSMAP_LEN=00fc0000 +CONFIG_MTD_PHYSMAP_BUSWIDTH=4 +# CONFIG_MTD_PB1000 is not set +# CONFIG_MTD_PB1500 is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_VERIFY_WRITE is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_CMD640=y +CONFIG_BLK_DEV_CMD640_ENHANCED=y +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_PLX_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# 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 +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=3 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=m +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +CONFIG_REMOTE_DEBUG=y +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ip22 linux-2.4.19-pre5/arch/mips/defconfig-ip22 --- linux-2.4.18/arch/mips/defconfig-ip22 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-ip22 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,37 +15,44 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_ARC32=y CONFIG_BOARD_SCACHE=y +CONFIG_IRQ_CPU=y CONFIG_PC_KEYB=y CONFIG_SGI=y CONFIG_NEW_IRQ=y -CONFIG_OLD_TIME_C=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_PCI is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -58,10 +65,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set CONFIG_CPU_R5000=y # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -70,6 +79,7 @@ # CONFIG_CPU_SB1 is not set # CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_LLDSCD=y @@ -90,6 +100,7 @@ CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -127,6 +138,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -134,8 +146,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -156,6 +166,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -219,6 +230,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -238,7 +250,6 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -273,7 +284,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -358,7 +368,10 @@ # Mice # # CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set # # Joysticks @@ -377,14 +390,28 @@ # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +CONFIG_INDYDOG=y # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -401,13 +428,8 @@ # # SGI Character devices # -CONFIG_VT=y -CONFIG_VT_CONSOLE=y CONFIG_SGI_NEWPORT_CONSOLE=y CONFIG_FONT_8x16=y -# CONFIG_PSMOUSE is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 # # File systems @@ -423,7 +445,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -439,8 +460,9 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -481,6 +503,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -548,9 +572,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -578,12 +604,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -606,25 +630,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -639,5 +668,6 @@ # Kernel hacking # CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-it8172 linux-2.4.19-pre5/arch/mips/defconfig-it8172 --- linux-2.4.18/arch/mips/defconfig-it8172 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-it8172 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,28 +15,31 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set CONFIG_MIPS_ITE8172=y # CONFIG_IT8172_REVC is not set -CONFIG_QTRONIX_KEYBOARD=y -CONFIG_IT8172_CIR=y -# CONFIG_IT8172_SCR0 is not set -# CONFIG_IT8172_SCR1 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set @@ -45,26 +48,31 @@ CONFIG_IT8712=y CONFIG_PC_KEYB=y CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y CONFIG_PCI_AUTO=y +CONFIG_IT8172_CIR=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_I8259 is not set # # Loadable module support # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y # # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -91,6 +99,7 @@ CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y @@ -102,7 +111,6 @@ # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_PARTITIONS is not set # CONFIG_MTD_REDBOOT_PARTS is not set -# CONFIG_MTD_BOOTLDR_PARTS is not set # # User Modules And Translation Layers @@ -117,14 +125,17 @@ # RAM/ROM/Flash chip drivers # CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_VIRTUAL_ER is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y # CONFIG_MTD_CFI_ADV_OPTIONS is not set CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_AMDSTD is not set -# CONFIG_MTD_SHARP is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set # CONFIG_MTD_JEDEC is not set # @@ -134,16 +145,9 @@ CONFIG_MTD_PHYSMAP_START=8000000 CONFIG_MTD_PHYSMAP_LEN=2000000 CONFIG_MTD_PHYSMAP_BUSWIDTH=4 -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_SBC_GXX is not set -# CONFIG_MTD_ELAN_104NC is not set -# CONFIG_MTD_DBOX2 is not set +# CONFIG_MTD_PB1000 is not set +# CONFIG_MTD_PB1500 is not set # CONFIG_MTD_CSTM_MIPS_IXX is not set -# CONFIG_MTD_CFI_FLAGADM is not set -# CONFIG_MTD_MIXMEM is not set -# CONFIG_MTD_OCTAGON is not set -# CONFIG_MTD_VMAX is not set # CONFIG_MTD_OCELOT is not set # @@ -152,6 +156,7 @@ # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set # # Disk-On-Chip Device Drivers @@ -180,7 +185,7 @@ # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set @@ -194,16 +199,18 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set -# CONFIG_UNIX is not set +CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set @@ -213,11 +220,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -347,6 +356,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -359,6 +378,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -368,7 +388,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -382,6 +401,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=y +# CONFIG_TC35815 is not set # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set @@ -394,15 +414,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set CONFIG_8139TOO=y # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_LAN_SAA9730 is not set # CONFIG_NET_POCKET is not set @@ -469,8 +492,8 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_QTRONIX_KEYBOARD=y -CONFIG_IT8172_CIR=y +# CONFIG_QTRONIX_KEYBOARD is not set +CONFIG_PC_KEYB=y # CONFIG_IT8172_SCR0 is not set # CONFIG_IT8172_SCR1 is not set CONFIG_UNIX98_PTYS=y @@ -507,11 +530,10 @@ # CONFIG_WATCHDOG is not set # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set -# CONFIG_RTC is not set +CONFIG_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -540,7 +562,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -556,8 +577,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -598,6 +620,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -610,7 +634,31 @@ # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +CONFIG_SOUND_IT8172=y +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_HAL2 is not set +CONFIG_SOUND_IT8172=y +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support @@ -629,13 +677,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -663,12 +717,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -691,25 +743,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -726,6 +783,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ivr linux-2.4.19-pre5/arch/mips/defconfig-ivr --- linux-2.4.18/arch/mips/defconfig-ivr Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-ivr Sat Mar 30 22:55:26 2002 @@ -0,0 +1,730 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +CONFIG_MIPS_IVR=y +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_PCI=y +CONFIG_PC_KEYB=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI_AUTO=y +CONFIG_IT8172_CIR=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +CONFIG_CPU_NEVADA=y +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_IT8172=y +CONFIG_IT8172_TUNING=y +CONFIG_BLK_DEV_IT8172=y +CONFIG_IT8172_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_QTRONIX_KEYBOARD=y +CONFIG_IT8172_CIR=y +# CONFIG_IT8172_SCR0 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-jmr3927 linux-2.4.19-pre5/arch/mips/defconfig-jmr3927 --- linux-2.4.18/arch/mips/defconfig-jmr3927 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-jmr3927 Sat Mar 30 22:55:26 2002 @@ -0,0 +1,671 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +CONFIG_TOSHIBA_JMR3927=y +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_NONCOHERENT_IO=y +CONFIG_TOSHIBA_BOARDS=y +CONFIG_PCI=y +CONFIG_NEW_PCI=y +CONFIG_PCI_AUTO=y +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_PC_KEYB=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +CONFIG_CPU_TX39XX=y +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_ADVANCED is not set +# CONFIG_CPU_HAS_LLSC is not set +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_RTC_DS1742=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_IRIX is not set +# CONFIG_FORWARD_KEYBOARD is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +CONFIG_TC35815=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_AU1000_UART is not set +CONFIG_TXX927_SERIAL=y +CONFIG_TXX927_SERIAL_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +CONFIG_FBCON_MFB=y +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-malta linux-2.4.19-pre5/arch/mips/defconfig-malta --- linux-2.4.18/arch/mips/defconfig-malta Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-malta Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,23 +15,30 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set CONFIG_MIPS_MALTA=y # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set @@ -40,6 +47,8 @@ CONFIG_PCI=y CONFIG_HAVE_STD_PC_SERIAL_PORT=y CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y CONFIG_SWAP_IO_SPACE=y # CONFIG_ISA is not set # CONFIG_EISA is not set @@ -53,10 +62,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -65,6 +76,8 @@ # CONFIG_CPU_SB1 is not set CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y # CONFIG_CPU_HAS_LLDSCD is not set @@ -83,6 +96,7 @@ # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set @@ -121,13 +135,14 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -140,11 +155,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -213,6 +230,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -233,8 +251,8 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -253,6 +271,16 @@ # CONFIG_SCSI_DEBUG is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -265,6 +293,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -274,7 +303,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -288,6 +316,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set +# CONFIG_TC35815 is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set @@ -298,15 +327,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_LAN_SAA9730 is not set # CONFIG_NET_POCKET is not set @@ -411,7 +443,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -439,7 +470,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -455,8 +485,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -497,6 +528,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -532,9 +565,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -562,12 +597,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -590,25 +623,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -625,6 +663,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-nino linux-2.4.19-pre5/arch/mips/defconfig-nino --- linux-2.4.18/arch/mips/defconfig-nino Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-nino Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,35 +15,43 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set CONFIG_NINO=y # CONFIG_NINO_4MB is not set CONFIG_NINO_8MB=y # CONFIG_NINO_16MB is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set +CONFIG_NEW_IRQ=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y CONFIG_PC_KEYB=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_PCI is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -56,10 +64,12 @@ # CPU selection # CONFIG_CPU_R3000=y +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -81,10 +91,11 @@ CONFIG_ELF_KERNEL=y # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y -# CONFIG_NET is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set @@ -111,10 +122,15 @@ # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=2048 +CONFIG_BLK_DEV_RAM_SIZE=512 CONFIG_BLK_DEV_INITRD=y # +# MIPS initrd options +# +# CONFIG_EMBEDDED_RAMDISK is not set + +# # Multi-device support (RAID and LVM) # # CONFIG_MD is not set @@ -123,9 +139,54 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -145,13 +206,33 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +# CONFIG_NETDEVICES is not set + +# # Amateur Radio support # # CONFIG_HAMRADIO is not set # +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # +# CONFIG_ISDN is not set # # Old CD-ROM drivers (not SCSI, not IDE) @@ -161,7 +242,8 @@ # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set CONFIG_SERIAL_NONSTANDARD=y @@ -184,8 +266,8 @@ CONFIG_SERIAL_TX3912=y CONFIG_SERIAL_TX3912_CONSOLE=y # CONFIG_AU1000_UART is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_TXX927_SERIAL is not set +# CONFIG_UNIX98_PTYS is not set # # I2C support @@ -222,7 +304,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -250,7 +331,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -266,8 +346,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -275,7 +356,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y +# CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -285,8 +366,31 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set -# CONFIG_NCPFS_NLS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set # CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -297,6 +401,50 @@ # CONFIG_NLS is not set # +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +CONFIG_FB_TX3912=y +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +CONFIG_FBCON_MFB=y +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +# CONFIG_FBCON_CFB16 is not set +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# # Sound # # CONFIG_SOUND is not set @@ -318,13 +466,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -352,15 +506,15 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # - -# -# Networking support is needed for USB Networking device support -# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set # # USB port drivers @@ -378,25 +532,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -411,5 +570,6 @@ # Kernel hacking # CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-ocelot linux-2.4.19-pre5/arch/mips/defconfig-ocelot --- linux-2.4.18/arch/mips/defconfig-ocelot Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-ocelot Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,23 +15,30 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set CONFIG_MOMENCO_OCELOT=y # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set @@ -40,10 +47,10 @@ CONFIG_SYSCLK_100=y CONFIG_SWAP_IO_SPACE=y CONFIG_NEW_IRQ=y +CONFIG_NONCOHERENT_IO=y CONFIG_OLD_TIME_C=y # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_I8259 is not set # # Loadable module support @@ -54,10 +61,12 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set CONFIG_CPU_RM7000=y @@ -66,6 +75,8 @@ # CONFIG_CPU_SB1 is not set # CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS64 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_LLDSCD=y @@ -86,6 +97,7 @@ CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -123,13 +135,14 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -142,11 +155,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -189,6 +204,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -201,6 +226,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -210,7 +236,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -224,6 +249,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set +# CONFIG_TC35815 is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set @@ -234,15 +260,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_LAN_SAA9730 is not set # CONFIG_NET_POCKET is not set @@ -347,7 +376,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -375,7 +403,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -391,8 +418,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -433,6 +461,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -464,13 +494,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -498,12 +534,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -526,25 +560,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -561,6 +600,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set -# CONFIG_LL_DEBUG is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-osprey linux-2.4.19-pre5/arch/mips/defconfig-osprey --- linux-2.4.18/arch/mips/defconfig-osprey Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-osprey Sat Mar 30 22:55:26 2002 @@ -0,0 +1,586 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +CONFIG_NEC_OSPREY=y +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_VR4181=y +CONFIG_SERIAL=y +CONFIG_SERIAL_MANY_PORTS=y +CONFIG_NEW_IRQ=y +CONFIG_IRQ_CPU=y +CONFIG_NEW_TIME_C=y +CONFIG_NONCOHERENT_IO=y +CONFIG_DUMMY_KEYB=y +# CONFIG_SCSI is not set +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +CONFIG_CPU_VR41XX=y +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_ADVANCED is not set +# CONFIG_CPU_HAS_LLSC is not set +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set +CONFIG_NE2000=y + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-pb1000 linux-2.4.19-pre5/arch/mips/defconfig-pb1000 --- linux-2.4.18/arch/mips/defconfig-pb1000 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-pb1000 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,47 +15,62 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set # CONFIG_SNI_RM200_PCI is not set # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set CONFIG_MIPS_PB1000=y +CONFIG_PCI_AUTO=y +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_MIPS_AU1000=y CONFIG_NEW_IRQ=y +CONFIG_PCI=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PC_KEYB=y +MAX_HWIFS=1 # CONFIG_ISA is not set # CONFIG_EISA is not set -# CONFIG_PCI is not set -# CONFIG_I8259 is not set # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y # # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set # CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set @@ -64,6 +79,8 @@ # CONFIG_CPU_SB1 is not set CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set CONFIG_CPU_ADVANCED=y CONFIG_CPU_HAS_LLSC=y # CONFIG_CPU_HAS_LLDSCD is not set @@ -78,9 +95,27 @@ # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set CONFIG_NET=y -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_CARDBUS is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_AU1000=m + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -88,7 +123,65 @@ # # Memory Technology Devices (MTD) # -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PB1000=y +# CONFIG_MTD_PB1500 is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set # # Parallel port support @@ -104,7 +197,7 @@ # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set @@ -118,6 +211,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -125,7 +219,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -138,11 +232,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -175,9 +271,50 @@ # # ATA/IDE/MFM/RLL support # -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support @@ -185,6 +322,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -197,6 +344,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -204,14 +352,15 @@ CONFIG_NET_ETHERNET=y CONFIG_MIPS_AU1000_ENET=y # CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -251,6 +400,11 @@ # CONFIG_WAN is not set # +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# # Amateur Radio support # # CONFIG_HAMRADIO is not set @@ -285,6 +439,7 @@ # CONFIG_ESPSERIAL is not set # CONFIG_MOXA_INTELLIO is not set # CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set # CONFIG_SYNCLINK is not set # CONFIG_N_HDLC is not set # CONFIG_RISCOM8 is not set @@ -296,6 +451,7 @@ # CONFIG_SERIAL_TX3912_CONSOLE is not set CONFIG_AU1000_UART=y CONFIG_AU1000_SERIAL_CONSOLE=y +# CONFIG_TXX927_SERIAL is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 @@ -334,7 +490,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -344,6 +499,13 @@ # CONFIG_DRM is not set # +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +CONFIG_AU1000_GPIO=y +# CONFIG_TS_AU1000_ADS7846 is not set + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -362,7 +524,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -372,14 +533,16 @@ # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set # CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y +# CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -387,7 +550,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -420,32 +583,44 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types # -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -CONFIG_SGI_PARTITION=y -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_HAL2 is not set +CONFIG_SOUND_AU1000=y +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support @@ -464,13 +639,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -498,12 +679,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -526,25 +705,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -561,5 +745,6 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-pb1500 linux-2.4.19-pre5/arch/mips/defconfig-pb1500 --- linux-2.4.18/arch/mips/defconfig-pb1500 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-pb1500 Sat Mar 30 22:55:26 2002 @@ -0,0 +1,964 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +CONFIG_MIPS_PB1500=y +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_MIPS_AU1000=y +CONFIG_NEW_IRQ=y +CONFIG_PCI=y +CONFIG_PCI_AUTO=y +CONFIG_NEW_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PC_KEYB=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set +CONFIG_CPU_ADVANCED=y +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_LLDSCD is not set +CONFIG_CPU_HAS_WB=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_CARDBUS is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_AU1000 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PB1000 is not set +CONFIG_MTD_PB1500=y +CONFIG_MTD_PB1500_BOOT=y +# CONFIG_MTD_PB1500_USER is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_OFFBOARD=y +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MIPS_AU1000_ENET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +CONFIG_AU1000_UART=y +CONFIG_AU1000_SERIAL_CONSOLE=y +# CONFIG_TXX927_SERIAL is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_AU1000_GPIO is not set +# CONFIG_TS_AU1000_ADS7846 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=m +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=m +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_HAL2 is not set +CONFIG_SOUND_AU1000=y +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-rm200 linux-2.4.19-pre5/arch/mips/defconfig-rm200 --- linux-2.4.18/arch/mips/defconfig-rm200 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/defconfig-rm200 Sat Mar 30 22:55:26 2002 @@ -2,7 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_MIPS=y -# CONFIG_SMP is not set +CONFIG_MIPS32=y # # Code maturity level options @@ -15,23 +15,30 @@ # CONFIG_ACER_PICA_61 is not set # CONFIG_ALGOR_P4032 is not set # CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set # CONFIG_DECSTATION is not set # CONFIG_DDB5074 is not set -# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set # CONFIG_MIPS_ATLAS is not set # CONFIG_MIPS_MALTA is not set # CONFIG_NINO is not set +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_MOMENCO_OCELOT is not set # CONFIG_DDB5476 is not set # CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI_IP22 is not set CONFIG_SNI_RM200_PCI=y # CONFIG_MIPS_ITE8172 is not set # CONFIG_MIPS_IVR is not set # CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_MCA is not set @@ -39,10 +46,11 @@ CONFIG_ARC32=y CONFIG_I8259=y CONFIG_ISA=y +CONFIG_NEW_IRQ=y +CONFIG_NONCOHERENT_IO=y +CONFIG_OLD_TIME_C=y CONFIG_PC_KEYB=y CONFIG_PCI=y -CONFIG_ROTTEN_IRQ=y -CONFIG_OLD_TIME_C=y CONFIG_EISA=y # @@ -56,11 +64,13 @@ # CPU selection # # CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set -# CONFIG_CPU_R4X00 is not set -CONFIG_CPU_R5000=y +CONFIG_CPU_R4X00=y +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set # CONFIG_CPU_RM7000 is not set # CONFIG_CPU_NEVADA is not set @@ -68,6 +78,7 @@ # CONFIG_CPU_SB1 is not set # CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS64 is not set +# CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y CONFIG_CPU_HAS_LLDSCD=y @@ -87,6 +98,7 @@ # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set # CONFIG_SYSVIPC is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -96,7 +108,6 @@ # # CONFIG_PNP is not set # CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set # # Memory Technology Devices (MTD) @@ -131,6 +142,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -138,7 +150,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -148,11 +160,13 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -195,6 +209,16 @@ # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# # Network device support # # CONFIG_NETDEVICES is not set @@ -265,7 +289,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -293,7 +316,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -309,8 +331,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -351,6 +374,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -406,13 +431,19 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -440,12 +471,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -468,25 +497,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support @@ -501,5 +535,6 @@ # Kernel hacking # CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips/defconfig-sb1250-swarm linux-2.4.19-pre5/arch/mips/defconfig-sb1250-swarm --- linux-2.4.18/arch/mips/defconfig-sb1250-swarm Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/defconfig-sb1250-swarm Sat Mar 30 22:55:26 2002 @@ -0,0 +1,602 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_ALGOR_P4032 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_NINO is not set +CONFIG_SIBYTE_SB1250=y +# CONFIG_PCI is not set +# CONFIG_SIBYTE_SB1250_PROF is not set +# CONFIG_BCM1250_TBPROF is not set +# CONFIG_REMOTE_DEBUG is not set +CONFIG_SIBYTE_SWARM=y +# CONFIG_SIMULATION is not set +# CONFIG_L3DEMO is not set +CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS=16 +CONFIG_SMP=y +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_NEW_IRQ=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_NEW_TIME_C=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +CONFIG_CPU_SB1=y +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +CONFIG_SB1_PASS_1_WORKAROUNDS=y +CONFIG_SB1_CACHE_ERROR=y +CONFIG_VTAG_ICACHE=y +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y +# CONFIG_CPU_HAS_WB is not set + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_KCORE_ELF=y +CONFIG_ELF_KERNEL=y +# CONFIG_BINFMT_IRIX is not set +# CONFIG_FORWARD_KEYBOARD is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=9220 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_NET_SB1250_MAC=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# 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=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_AU1000_UART is not set +# CONFIG_TXX927_SERIAL is not set +CONFIG_SIBYTE_SB1250_DUART=y +CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE=1024 +# CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/Makefile linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/Makefile --- linux-2.4.18/arch/mips/galileo-boards/ev64120/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,29 @@ +# +# Copyright 2000 RidgeRun, Inc. +# Author: RidgeRun, Inc. +# glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com +# +# Makefile for the Galileo EV64120 board. +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: ev64120.o int-handler.o + +O_TARGET := ev64120.o + +export-objs = i2o.o + +obj-y := serialGT.o int-handler.o promcon.o reset.o setup.o irq.o \ + irq-handler.o i2o.o pci_bios.o + +int-handler.o: int-handler.S + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/cntmr.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/cntmr.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/cntmr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/cntmr.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,207 @@ +/* cntmr.c - GT counters/timers functions */ + +/* Copyright - Galileo technology. 9/3/2000 */ + +/* +DESCRIPTION +This file contains function which serves the user with a complete interface +to the GT internal counters and timers, please advise: each counter/timer unit +can function only as a counter or a timer at current time. +Counter/timer 0 is 32 bit wide. +Counters/timers 1-3 are 24 bit wide. +*/ + +/* includes */ + +#ifdef __linux__ +#include +#include +#else +#include "cntmr.h" +#include "core.h" +#endif + +/******************************************************************** +* cntTmrStart - Starts a counter/timer with given an initiate value. +* +* INPUTS: unsigned int countNum - Selects one of the 8 counters/timers. +* unsigned int countValue - Initial value for count down. +* CNT_TMR_OP_MODES opMode - Set Mode, Counter or Timer. +* +* RETURNS: false if one of the parameters is erroneous, true otherwise. +*********************************************************************/ + +bool cntTmrStart(CNTMR_NUM countNum, unsigned int countValue, + CNT_TMR_OP_MODES opMode) +{ + unsigned int command = 1; + unsigned int value; + + if (countNum > LAST_CNTMR) + return false; + else { + GT_REG_READ(TIMER_COUNTER_CONTROL, &value); + cntTmrDisable(countNum); + GT_REG_WRITE((TIMER_COUNTER0 + (4 * countNum)), + countValue); + command = command << countNum * 2; + value = value | command; + command = command << 1; + switch (opMode) { + case TIMER: /* The Timer/Counter bit set to logic '1' */ + value = value | command; + break; + case COUNTER: /* The Timer/Counter bit set to logic '0' */ + value = value & ~command; + break; + default: + return false; + } + GT_REG_WRITE(TIMER_COUNTER_CONTROL, value); + return true; + } +} + +/******************************************************************** +* cntTmrDisable - Disables the timer/counter operation and return its +* value. +* +* INPUTS: unsigned int countNum - Selects one of the 8 counters/timers. +* RETURNS: The counter/timer value (unsigned int), if any of the arguments are +* erroneous return 0. +*********************************************************************/ + +unsigned int cntTmrDisable(CNTMR_NUM countNum) +{ + unsigned int command = 1; + unsigned int regValue; + unsigned int value; + + GT_REG_READ(TIMER_COUNTER_CONTROL, &value); + if (countNum > LAST_CNTMR) + return 0; + GT_REG_READ(TIMER_COUNTER0 + 4 * countNum, ®Value); + command = command << countNum * 2; /* Disable the timer/counter */ + value = value & ~command; + GT_REG_WRITE(TIMER_COUNTER_CONTROL, value); + return regValue; +} + +/******************************************************************** +* cntTmrRead - Reads a timer or a counter value. (This operation can be +* perform while the counter/timer is active). +* +* RETURNS: The counter/timer value. If wrong input value, return 0. +*********************************************************************/ + +unsigned int cntTmrRead(CNTMR_NUM countNum) +{ + unsigned int value; + if (countNum > LAST_CNTMR) + return 0; + else + GT_REG_READ(TIMER_COUNTER0 + countNum * 4, &value); + return value; +} + +/******************************************************************** +* cntTmrEnable - Set enable-bit of timer/counter. +* Be aware: If the counter/timer is active, this function +* will terminate with an false. +* +* INPUTS: unsigned int countNum - Selects one of the 8 counters/timers. +* RETURNS: false if one of the parameters is erroneous, true otherwise. +*********************************************************************/ + +bool cntTmrEnable(CNTMR_NUM countNum) +{ + unsigned int command = 1; + unsigned int value; + GT_REG_READ(TIMER_COUNTER_CONTROL, &value); + if (countNum > LAST_CNTMR) + return false; + else { + command = command << countNum * 2; + if ((command & value) != 0) /* ==> The counter/timer is enabled */ + return false; /* doesn't make sense to Enable an "enabled" counter */ + value = value | command; + GT_REG_WRITE(TIMER_COUNTER_CONTROL, value); + return true; + } +} + +/******************************************************************** +* cntTmrLoad - loading value for timer number countNum. +* Be aware: If this function try to load value to an enabled +* counter/timer it terminate with false. +* +* INPUTS: unsigned int countNum - Selects one of the 8 counters/timers. +* unsigned int countValue - The value for load the register. +* RETURNS: false if one of the parameters is erroneous, true otherwise. +*********************************************************************/ + +bool cntTmrLoad(unsigned int countNum, unsigned int countValue) +{ + unsigned int command = 1; + unsigned int value; + GT_REG_READ(TIMER_COUNTER_CONTROL, &value); + if (countNum > LAST_CNTMR) + return false; + else { + command = command << countNum * 2; + value = value & command; + if (value != 0) { /* ==> The counter/timer is enabled */ + return false; /* can't reload value when counter/timer is enabled */ + } else { + GT_REG_WRITE((TIMER_COUNTER0 + (4 * countNum)), + countValue); + return true; + } + + } +} + +/******************************************************************** +* cntTmrSetMode - Configurate the Mode of the channel to work as a counter +* or as a timer. (for more details on the different between +* those two modes is written in the Data Sheet). +* NOTE: This function only set the counter/timer mode and +* don't enable it. +* Be aware: If this function try to load value to an enabled +* counter/timer it terminate with false. +* +* INPUTS: unsigned int countNum - Selects one of the 8 counters/timers. +* CNT_TMR_OP_MODES opMode - TIMER or COUNTER mode. +* RETURNS: false if one of the parameters is erroneous true otherwise . +*********************************************************************/ + +bool cntTmrSetMode(CNTMR_NUM countNum, CNT_TMR_OP_MODES opMode) +{ + unsigned int command = 1; + unsigned int value; + + GT_REG_READ(TIMER_COUNTER_CONTROL, &value); + if (countNum > LAST_CNTMR) + return false; + else { + command = command << countNum * 2; + value = value & command; + if (value != 0) { /* ==> The counter/timer is enabled */ + return false; /* can't set the Mode when counter/timer is enabled */ + } else { + command = command << 1; + switch (opMode) { + case TIMER: + value = value | command; /* The Timer/Counter bit set to logic '1' */ + break; + case COUNTER: + value = value & ~command; /*The Timer/Counter bit set to logic '0' */ + break; + default: + return false; + } + GT_REG_WRITE(TIMER_COUNTER_CONTROL, value); + return true; + } + } +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/Makefile linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/Makefile --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,180 @@ +# ============================================================= +# +# linux/arch/mips/galileo/compressed/Makefile +# +# By RidgeRun Inc. +# +# Description: +# Create a system containing a copy of the compressed vmlinux kernel. +# The system knows how to decompress the contained kernel and then +# jump to it resulting in a linux kernel boot. +# +# The system comes in three forms: +# +# 1. - ramsys - +# to be loaded into ram then run. When run +# it decompresses the kernel housed in its internal +# data structures and then jumps to the image which +# results in a linux kernel boot. +# +# 2. - flashsys - +# to be loaded into ram so that it can be +# burned into the onboard flash. Then the board jumpers +# can be switched so that the next power cycle caused +# the system in flash to run which then proceeds as +# described by #1 above. +# Note: burner.srec is the utility that will allow +# the user to get this image into flash. +# +# 3. - flashsys2 - +# to be loaded into ram so that it can be +# burned into the onboard flash. Then on each power +# cycle when the standard PMON prompt is presented +# the user can type `call 0xbf000000` to invoke +# the system in flash which then proceeds as +# described by #1 above. +# Note: burner.srec is the utility that will allow +# the user to get this image into flash. +# +# 4. - burner.srec - +# related to #2 and #3 above. +# +# ============================================================= + +all: ramsys.srec \ + flashsys.srec \ + flashsys2.srec \ + burner.srec + +SYSTEM = $(TOPDIR)/vmlinux + +CFLAGS_2 = -DCONSOLE_SERIAL -DDELIMITERLINES -DGALILEO_PORT \ + -DANSIESC -DELF_IMAGE -DELF_IMAGE -DDOWNLOAD_PROTO_TFTP \ + -DEVB64120A -D__MIPSEB__ -DINCLUDE_EEPRO100 \ + -DINCLUDE_GETH0 -DNOPRINTK -DPROM -DCOMPRESSEDVMLINUX + +sbdreset_evb64120A.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c sbdreset_evb64120A.S -o $*.o +memory.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c memory.c -o $*.o +pci.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c pci.c -o $*.o +pci_etherboot.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c pci_etherboot.c -o $*.o +load.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c load.c -o $*.o +flashdrv.o: + $(CC) $(CFLAGS) $(CFLAGS_2) -c flashdrv.c -o $*.o + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +gz2asm: gz2asm.c + g++ -o gz2asm gz2asm.c + +doit: doit.c + gcc -o doit doit.c + +piggy.gz: $(SYSTEM) + rm -f piggy piggy.gz + $(OBJCOPY) -S -O binary $(SYSTEM) piggy + gzip -f -9 < piggy > piggy.gz + +piggy.S: doit fixit piggy.gz + ./doit < piggy.gz > piggy.S; . ./fixit piggy.S + +OBJECTS_ramsys = head.o misc.o piggy.o ../serialGT.o +OBJECTS_flashsys = sbdreset_evb64120A.o evb64120A_Setup.o pci_etherboot.o memory.o pci.o head.o misc.o piggy.o ../serialGT.o +OBJECTS_flashsys2 = xfer.o head.o misc.o piggy.o ../serialGT.o +OBJECTS_burner = burner.o load.o flashdrv.o + +ramsys.srec : $(OBJECTS_ramsys) ld.script.gal + @# Note: this image is intended to run out of ram. No flash involved. + $(LD) -T ld.script.gal -o ramsys $(OBJECTS_ramsys) + $(NM) ramsys | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System_ramsys.map + $(OBJCOPY) -O srec ramsys ramsys.srec + cp ramsys.srec $(TOPDIR)/. + +flashsys.srec : $(OBJECTS_flashsys) ld.sys.big.Flash + @# Note1: Use the burn utility to get this image into flash. + @# Note2: This image is intended to run out of flash as invoked + @# directly at powerup when EVB64120A jumpers are configured to + @# bypass the onboard eprom. + @# Assumes that 0xBFC00000 is the bootup run address (normal MIPS). + @# And assumes that EVB64120A jumber J11 is added to the board and jumber + @# J20 is moved from the 2&3 position to the 1&2 position instead. Without + @# the jumper settings the system will execute at address 0xBFC00000, + @# as normal, yet that address will map to the onboard eeprom instead + @# of the onboard flash. + @# + $(LD) -T ld.sys.big.Flash -o flashsys $(OBJECTS_flashsys) + $(NM) flashsys | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System_flashsys.map + @# + @# Next, Create the image that we want to place in the flash part. + $(OBJCOPY) -S -g --strip-unneeded \ + --adjust-section-vma=.text+0x3f820000 \ + --adjust-section-vma=.rodata+0x3f820000 \ + --adjust-section-vma=.reginfo+0x3f820000 \ + --adjust-section-vma=.data+0x3f820000 \ + --remove-section=.bss \ + --remove-section=.scommon \ + --remove-section=.note \ + --remove-section=.comment \ + flashsys flashsys.temp + @# + @# Next, change the addresses so that when we download to + @# to the board's ram it will land starting at address 0xA0300000 + @# because this is where we have choosen to have the image temporarily sit + @# while we subsequently burn it (using some method not revealed here) into + @# the board's flash. After the burn the system can be setup (via jumpers) + @# to boot this image directory from the flash part. + $(OBJCOPY) -O srec --adjust-vma=0xe0700000 flashsys.temp flashsys.srec + cp flashsys.srec $(TOPDIR)/. + +flashsys2.srec : $(OBJECTS_flashsys2) ld.sys.big.Flash2 + @# Note1: Use the burn utility to get this image into flash. + @# Note2: This image is intended to be run out of flash as invoked + @# manually from the standard PMON running in eprom. This means that + @# the image will be set to run from location 0xBF000000 which is the + @# location the flash is mapped to when the board jumpers are set to + @# the standard location such that the board boots out of onboard + @# eprom. From the PMON prompt the user can type `call 0xbf000000` + @# to transfer control to the image we are constructing here. + @# + $(LD) -T ld.sys.big.Flash2 -o flashsys2 $(OBJECTS_flashsys2) + $(NM) flashsys2 | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System_flashsys2.map + @# + @# Next, Create the image that we want to place in the flash part. + $(OBJCOPY) -S -g --strip-unneeded \ + --adjust-section-vma=.text+0x3ec20000 \ + --adjust-section-vma=.rodata+0x3ec20000 \ + --adjust-section-vma=.reginfo+0x3ec20000 \ + --adjust-section-vma=.data+0x3ec20000 \ + --remove-section=.bss \ + --remove-section=.scommon \ + --remove-section=.note \ + --remove-section=.comment \ + flashsys2 flashsys2.temp + @# + @# Next, change the addresses so that when we download to + @# to the board's ram it will land starting at address 0xA0300000 + @# because this is where we have choosen to have the image temporarily sit + @# while we subsequently burn it (using some method not revealed here) into + @# the board's flash. After the burn a user will then be able to type + @# `call 0xbf000000` at the PMON prompt (following a power cycle) to invoke + @# the linux kernel. + $(OBJCOPY) -O srec --adjust-vma=0xe1300000 flashsys2.temp flashsys2.srec + cp flashsys2.srec $(TOPDIR)/. + +burner.srec : $(OBJECTS_burner) ld.sys.big.burner + @# This utility can be used to burn the flashsys.srec or flashsys2.srec + @# into the EVB64120A's on board flash part (1Meg minimum). + $(LD) -T ld.sys.big.burner -o burner $(OBJECTS_burner) + $(NM) burner | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System_burner.map + $(OBJCOPY) -O srec burner burner.srec + cp burner.srec $(TOPDIR)/. + +clean: + rm -f doit piggy.S piggy.gz piggy burner *.o ramsys* flashsys* System*.map *.srec diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/README linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/README --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/README Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/README Sat Mar 30 22:55:26 2002 @@ -0,0 +1,131 @@ ++------------------------------------------------+ +| $TOPDIR/arch/mips/galileo/compressed/README | +| | +| By RidgeRun Inc, | +| Aug, 2000 | ++------------------------------------------------+ + +Description: +============ + It is intended that this makefile be wired in to run as + part of a top level linux build. For example, at the + time of this writing, if the user types "make gboot" at + the top level then in addition to building vmlinux the + build system's makefiles will descend into this + directory and build the "all:" target of this + Makefile. This will have the result of compressing the + vmlinux system and producing four separate systems. The + following snippet is pulled from this directory's + Makefile and describes each system. + + Four systems are availalbe for download to the EVB64120A + board. + + 1. - ramsys - + To be loaded into ram then run. When run + it decompresses the "vmlinux" kernel housed in its internal + data structures and then jumps to the image which + results in a linux kernel boot. + + 2. - flashsys - + To be loaded into ram so that it can be + burned into the onboard flash. Then the board jumpers + can be switched so that the next power cycle caused + the system in flash to run which then proceeds as + described by #1 above. + Note: burner.srec is the utility that will allow + the user to get this image into flash. + + 3. - flashsys2 - + To be loaded into ram so that it can be + burned into the onboard flash. Then on each power + cycle when the standard PMON prompt is presented + the user can type `call 0xbf000000` to invoke + the system in flash which then proceeds as + described by #1 above. + Note: burner.srec is the utility that will allow + the user to get this image into flash. + + 4. - burner.srec - + Related to #2 and #3 above. + +Example: Running from Ram +========================== + + In this scenario the compressed system is downloaded + into ram and run directly from there. No flash is involved + in this scenario. Naturally, the download must be repeated + on every power cycle. + + 1. At the PMON prompt type `load` + 2. Assuming you have your host connected to /dev/ttyS0 + type the following command in a host shell window. + `cat ramsys.srec > /dev/ttyS0` + 3. When the download completes type the following + at the PMON prompt: `g` + + +Example: Running from flash: Scenario #1 +======================================== + + In this scenario vmlinux runs out of flash code + automatically on every power up. This means that + standard PMON code (of eprom) never runs. + + 1. Place the boot jumpers in the Boot-from-eprom + state. This is the normal state and how the jumpers + are found when booting PMON. + + Jumper settings. J11 - Removed + J20 - Moved from the 1&2 position to + the 2&3 position instead + + 2. Use PMON to "load" the burner.srec image and then + run it. This utility will prompt you to download + the image that you want burned into the flash + part. + + 3. Send the flashsys.srec image to the running burner + utility. The utililty will indicate when the burn + process has completed. + + 4. Now switch off power and change the jumpers to + the boot-from-flash position. The next power cycle + will run the flash based system automatically. + + Jumper settings. J11 - Added. + J20 - Moved from the 2&3 position to + the 1&2 position instead + +Example: Running from flash: Scenario #2 +======================================== + + In this scenario vmlinux runs out of flash only if the + PMON user decides to jump there by issuing a command to + PMON. Every power cycle would continue to bring up PMON + and a user will have to reissue the jump command to + force control transfer to the flash system. + + 1. Insure that the boot jumpers are in the Boot-from-eprom + state. This is the normal state and how the jumpers + are found when booting PMON. + + Jumper settings. J11 - Removed + J20 - Moved from the 1&2 position to + the 2&3 position instead + + 2. Use PMON to "load" the burner.srec image and then + run it. This utility will prompt you to download + the image that you want burned into the flash + part. + + 3. Send the flashsys2.srec image to the running burner + utility. The utililty will indicate when the burn + process has completed. + + 4. Now that the image is in flash the user can invoke + the following PMON command whenever a vmlinux + boot is desired: + + call 0xbf000000 + diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/burner.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/burner.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/burner.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/burner.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,232 @@ +/* + * arch/mips/galileo/compressed/burner.c + * + * By RidgeRun Inc (Leveraged from Galileo's main.c, misc.c, etc). + * + * Burn image from ram to flash + * For use with Galileo EVB64120A MIPS eval board. + */ + +#include +#include +#include +#include +#include + +#define IMAGEOFFSET 0x00300000 + +static void burn_image_from_memory(void); +static char *sprintf(char *buf, const char *fmt, ...); +static void printf(const char *fmt, ...); + +unsigned int FlashSize; + +/****************************** + Routine: + Description: + ******************************/ +int main(void) +{ + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf(" +--------------------+\n"); + printf(" | |\n"); + printf(" | Flash Burn Utility |\n"); + printf(" | |\n"); + printf(" +--------------------+\n"); + printf("\n"); + printf("Please send your *.srec image to the parallel port\n"); + printf("\n"); + printf("Note: The *.srec image should be setup to\n"); + printf(" load into address 0xa0300000 where\n"); + printf(" it will then be transferred to flash\n"); + printf("\n"); + + SET_REG_BITS(0x468, BIT20); // Set Flash to be 16 bit wide + FlashSize = flashInit(0xbf000000, 2, X16); + + galileo_dl(); // read in the users *.srec image. + burn_image_from_memory(); // put it in flash. + + printf("\n"); + printf("\n"); + printf("+---------------+\n"); + printf("| Done |\n"); + printf("|(please reboot)|\n"); + printf("+---------------+\n"); + printf("\n"); + + while (1) { + } + return 0; +} + +/****************************** + Routine: + Description: + ******************************/ +static void burn_image_from_memory(void) +{ + unsigned int count, delta, temp, temp1; + unsigned int to_sector, last_sector; + + /* Find how many sectors needed to be erased */ + to_sector = flashInWhichSector(FlashSize - 4); // skranz, modified. + if (to_sector == 0xffffffff) { + printf + ("Flash Burning Error - Flash too small - Cannot burn image\n"); // skranz, modified. + return; + } + + /* Which is the last sector */ + last_sector = flashInWhichSector(FlashSize - 4); + delta = 0; + printf("\nErasing first %d sectors\n", to_sector); + for (count = 0; count < to_sector + 1; count++) { + printf("Erasing sector %d\n", count); + flashEraseSector(count); + } + printf("flash region size = %d\n", FlashSize); // skranz, added + printf("Sdram IMAGEOFFSET = %d\n", IMAGEOFFSET); // skranz, added + + printf("Burning from Sdram to %d mark; full burn.\n", FlashSize); + for (count = 0; count < (FlashSize - delta); count = count + 4) { + flashWriteWord(count, + *(unsigned int *) ((count | NONE_CACHEABLE) + + IMAGEOFFSET)); // skranz, modified. + temp = flashReadWord(count); + temp1 = *(unsigned int *) ((count | NONE_CACHEABLE) + IMAGEOFFSET); // skranz, modified. + if (((unsigned int) temp) != ((unsigned int) temp1)) { + printf + ("Burning error at address %X : flash(%X) sdram(%X)\n", + count, flashReadWord(count), + *(unsigned int *) ((count | NONE_CACHEABLE) + IMAGEOFFSET)); // skranz, modified. + printf("Aborting Prematurally.\n"); + break; + } + } + printf("Finished burning Image\n"); +} + +/****************************** + Routine: + Description: + Formats: + %X - 4 byte ASCII (8 hex digits) + %x - 2 byte ASCII (4 hex digits) + %b - 1 byte ASCII (2 hex digits) + %d - decimal (also %i) + %c - ASCII char + %s - ASCII string + %I - Internet address in x.x.x.x notation + ******************************/ +static char hex[] = "0123456789ABCDEF"; +static char *do_printf(char *buf, const char *fmt, const int *dp) +{ + register char *p; + char tmp[16]; + while (*fmt) { + if (*fmt == '%') { /* switch() uses more space */ + fmt++; + + if (*fmt == 'X') { + const long *lp = (const long *) dp; + register long h = *lp++; + dp = (const int *) lp; + *(buf++) = hex[(h >> 28) & 0x0F]; + *(buf++) = hex[(h >> 24) & 0x0F]; + *(buf++) = hex[(h >> 20) & 0x0F]; + *(buf++) = hex[(h >> 16) & 0x0F]; + *(buf++) = hex[(h >> 12) & 0x0F]; + *(buf++) = hex[(h >> 8) & 0x0F]; + *(buf++) = hex[(h >> 4) & 0x0F]; + *(buf++) = hex[h & 0x0F]; + } + if (*fmt == 'x') { + register int h = *(dp++); + *(buf++) = hex[(h >> 12) & 0x0F]; + *(buf++) = hex[(h >> 8) & 0x0F]; + *(buf++) = hex[(h >> 4) & 0x0F]; + *(buf++) = hex[h & 0x0F]; + } + if (*fmt == 'b') { + register int h = *(dp++); + *(buf++) = hex[(h >> 4) & 0x0F]; + *(buf++) = hex[h & 0x0F]; + } + if ((*fmt == 'd') || (*fmt == 'i')) { + register int dec = *(dp++); + p = tmp; + if (dec < 0) { + *(buf++) = '-'; + dec = -dec; + } + do { + *(p++) = '0' + (dec % 10); + dec = dec / 10; + } while (dec); + while ((--p) >= tmp) + *(buf++) = *p; + } + if (*fmt == 'I') { + union { + long l; + unsigned char c[4]; + } u; + const long *lp = (const long *) dp; + u.l = *lp++; + dp = (const int *) lp; + buf = sprintf(buf, "%d.%d.%d.%d", + u.c[0], u.c[1], u.c[2], + u.c[3]); + } + if (*fmt == 'c') + *(buf++) = *(dp++); + if (*fmt == 's') { + p = (char *) *dp++; + while (*p) + *(buf++) = *p++; + } + } else + *(buf++) = *fmt; + fmt++; + } + *buf = 0; + return (buf); +} + +/****************************** + Routine: + Description: + ******************************/ +static char *sprintf(char *buf, const char *fmt, ...) +{ + return do_printf(buf, fmt, ((const int *) &fmt) + 1); +} + +/****************************** + Routine: + Description: + ******************************/ +void putchar(int c) +{ + if (c == '\n') { + serial_putc('\r'); + } + serial_putc(c); +} + +/****************************** + Routine: + Description: + ******************************/ +static void printf(const char *fmt, ...) +{ + char buf[256], *p; + p = buf; + do_printf(buf, fmt, ((const int *) &fmt) + 1); + while (*p) + putchar(*p++); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/doit.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/doit.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/doit.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/doit.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,75 @@ +/* + * By RidgeRun Inc. + * + * The input to this program is intended to be + * a compressed linux kernel. The output of this + * program is then a constructed *.S file which + * defines a large data structure -- the contents + * of which represent the compressed kernel which + * can subsequently be used in a program designed + * to access that struture for decompression at + * runtime and then subsequent kernel bootup. + * + * Example Usage: + * ./doit < piggy.gz > piggy.S + * + */ + +#include + +void printval(int i) +{ + int tth, th, h, t, d; + + if (i > 99999) { + printf("Error - printval outofbounds\n"); + return; + } + + tth = 0; + th = 0; + //tth = (i) / 10000; + //th = (i - (tth * 10000)) / 1000; + h = (i - ((tth * 10000) + (th * 1000))) / 100; + t = (i - ((tth * 10000) + (th * 1000) + (h * 100))) / 10; + d = (i - ((tth * 10000) + (th * 1000) + (h * 100) + (t * 10))); + //putchar(tth + '0'); + //putchar(th + '0'); + putchar(h + '0'); + putchar(t + '0'); + putchar(d + '0'); +} + +main(int argc, char **argv) +{ + int val; + int size = 0; + unsigned char c; + + printf("gcc2_compiled.:\n"); + printf("__gnu_compiled_c:\n"); + printf("\t.globl linux_compressed_start\n"); + printf("\t.text\n"); + printf("\t.align 2\n"); + printf("\t.type linux_compressed_start,@object\n"); + printf("linux_compressed_start:\n"); + + + val = getchar(); + while (val != EOF) { + size++; + c = (unsigned char) (val & 0x00ff); + printf("\t.byte "); + printval((int) c); + printf("\n"); + val = getchar(); + } + printf("\t.size linux_compressed_start,%d\n", size); + printf("\t.globl linux_compressed_size\n"); + printf("\t.text\n"); + printf("\t.align 2\n"); + printf("\t.type linux_compressed_size,@object\n"); + printf("\t.size linux_compressed_size,4\n"); + printf("linux_compressed_size:\n"); + printf("\t.word %d\n", size); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/etherboot.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/etherboot.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/etherboot.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/etherboot.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,566 @@ +/************************************************************************** +ETHERBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters + Date: Dec/93 + +**************************************************************************/ + +#include "osdep.h" + +/* These could be customised for different languages perhaps */ +#define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? " +#define ANS_NETWORK 'N' +#define ANS_LOCAL 'L' +#ifndef ANS_DEFAULT /* in case left out in Makefile */ +#define ANS_DEFAULT ANS_NETWORK +#endif + +#define TAGGED_IMAGE /* eventually optional */ +#if !defined(TAGGED_IMAGE) && !defined(AOUT_IMAGE) && !defined(ELF_IMAGE) +#define TAGGED_IMAGE /* choose at least one */ +#endif + +#define ESC 0x1B + +#ifndef DEFAULT_BOOTFILE +#define DEFAULT_BOOTFILE "/tftpboot/kernel" +#endif + +/* Clean up console settings... mainly CONSOLE_CRT and CONSOLE_SERIAL are used + * in the sources (except start.S and serial.S which cannot include + * etherboot.h). At least one of the CONSOLE_xxx has to be set, and + * CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL. If none is set, + * CONSOLE_CRT is assumed. */ +#ifdef CONSOLE_DUAL +#undef CONSOLE_CRT +#define CONSOLE_CRT +#undef CONSOLE_SERIAL +#define CONSOLE_SERIAL +#endif +#if defined(CONSOLE_CRT) && defined(CONSOLE_SERIAL) +#undef CONSOLE_DUAL +#define CONSOLE_DUAL +#endif +#if !defined(CONSOLE_CRT) && !defined(CONSOLE_SERIAL) +#define CONSOLE_CRT +#endif + +#ifndef DOWNLOAD_PROTO_NFS +#undef DOWNLOAD_PROTO_TFTP +#define DOWNLOAD_PROTO_TFTP /* default booting protocol */ +#endif + +#ifdef DOWNLOAD_PROTO_TFTP +#define download(fname,loader) tftp((fname),(loader)) +#endif +#ifdef DOWNLOAD_PROTO_NFS +#define download(fname,loader) nfs((fname),(loader)) +#endif + +#ifndef MAX_TFTP_RETRIES +#define MAX_TFTP_RETRIES 20 +#endif + +#ifndef MAX_BOOTP_RETRIES +#define MAX_BOOTP_RETRIES 20 +#endif + +#ifndef MAX_BOOTP_EXTLEN +#if (RELOC < 0x94000) +/* Force internal buffer (if external buffer would overlap with our code...) */ +#undef INTERNAL_BOOTP_DATA +#define INTERNAL_BOOTP_DATA +#endif +/* sizeof(struct bootp_t) == 0x240 */ +#if defined(INTERNAL_BOOTP_DATA) || (RELOC >= 0x94240) +#define MAX_BOOTP_EXTLEN 1024 +#else +#define MAX_BOOTP_EXTLEN (1024-sizeof(struct bootp_t)) +#endif +#endif + +#ifndef MAX_ARP_RETRIES +#define MAX_ARP_RETRIES 20 +#endif + +#ifndef MAX_RPC_RETRIES +#define MAX_RPC_RETRIES 20 +#endif + +#define TICKS_PER_SEC 18 + +/* Inter-packet retry in ticks */ +#define TIMEOUT (10*TICKS_PER_SEC) + +/* These settings have sense only if compiled with -DCONGESTED */ +/* total retransmission timeout in ticks */ +#define TFTP_TIMEOUT (30*TICKS_PER_SEC) +/* packet retransmission timeout in ticks */ +#define TFTP_REXMT (3*TICKS_PER_SEC) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define ETHER_ADDR_SIZE 6 /* Size of Ethernet address */ +#define ETHER_HDR_SIZE 14 /* Size of ethernet header */ +#define ETH_MIN_PACKET 64 +#define ETH_MAX_PACKET 1518 + +#define VENDOR_NONE 0 +#define VENDOR_WD 1 +#define VENDOR_NOVELL 2 +#define VENDOR_3COM 3 +#define VENDOR_3C509 4 +#define VENDOR_CS89x0 5 + +#define FLAG_PIO 0x01 +#define FLAG_16BIT 0x02 +#define FLAG_790 0x04 + +#define ARP_CLIENT 0 +#define ARP_SERVER 1 +#define ARP_GATEWAY 2 +#define ARP_ROOTSERVER 3 +#define ARP_SWAPSERVER 4 +#define MAX_ARP ARP_SWAPSERVER+1 + +#define RARP_REQUEST 3 +#define RARP_REPLY 4 + +#define IP 0x0800 +#define ARP 0x0806 +#define RARP 0x8035 + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 +#define TFTP_PORT 69 +#define SUNRPC_PORT 111 + +#define IP_UDP 17 +/* Same after going through htonl */ +#define IP_BROADCAST 0xFFFFFFFF + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define TAG_LEN(p) (*((p)+1)) +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 +#ifndef NO_DHCP_SUPPORT +#define RFC2132_REQ_ADDR 50 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MAX_SIZE 57 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 +#endif /* NO_DHCP_SUPPORT */ + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#ifdef IMAGE_FREEBSD +#define RFC1533_VENDOR_HOWTO 132 +#endif +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#ifndef NO_DHCP_SUPPORT +#define DHCP_OPT_LEN 312 +#endif /* NO_DHCP_SUPPORT */ + +#define TFTP_DEFAULTSIZE_PACKET 512 +#define TFTP_MAX_PACKET 1432 /* 512 */ + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 +#define TFTP_OACK 6 + +#define TFTP_CODE_EOF 1 +#define TFTP_CODE_MORE 2 +#define TFTP_CODE_ERROR 3 +#define TFTP_CODE_BOOT 4 +#define TFTP_CODE_CFG 5 + +#define AWAIT_ARP 0 +#define AWAIT_BOOTP 1 +#define AWAIT_TFTP 2 +#define AWAIT_RARP 3 +#define AWAIT_RPC 4 +#define AWAIT_QDRAIN 5 /* drain queue, process ARP requests */ + +typedef struct { + unsigned long s_addr; +} in_addr; + +struct arptable_t { + in_addr ipaddr; + unsigned char node[6]; +}; + +/* + * A pity sipaddr and tipaddr are not longword aligned or we could use + * in_addr. No, I don't want to use #pragma packed. + */ +struct arprequest { + unsigned short hwtype; + unsigned short protocol; + char hwlen; + char protolen; + unsigned short opcode; + char shwaddr[6]; + char sipaddr[4]; + char thwaddr[6]; + char tipaddr[4]; +}; + +struct iphdr { + char verhdrlen; + char service; + unsigned short len; + unsigned short ident; + unsigned short frags; + char ttl; + char protocol; + unsigned short chksum; + in_addr src; + in_addr dest; +}; + +struct udphdr { + unsigned short src; + unsigned short dest; + unsigned short len; + unsigned short chksum; +}; + +struct bootp_t { + struct iphdr ip; + struct udphdr udp; + char bp_op; + char bp_htype; + char bp_hlen; + char bp_hops; + unsigned long bp_xid; + unsigned short bp_secs; + unsigned short unused; + in_addr bp_ciaddr; + in_addr bp_yiaddr; + in_addr bp_siaddr; + in_addr bp_giaddr; + char bp_hwaddr[16]; + char bp_sname[64]; + char bp_file[128]; +#ifdef NO_DHCP_SUPPORT + char bp_vend[BOOTP_VENDOR_LEN]; +#else + char bp_vend[DHCP_OPT_LEN]; +#endif /* NO_DHCP_SUPPORT */ +}; + +struct bootpd_t { + struct bootp_t bootp_reply; + unsigned char bootp_extension[MAX_BOOTP_EXTLEN]; +}; + +struct tftp_t { + struct iphdr ip; + struct udphdr udp; + unsigned short opcode; + union { + char rrq[TFTP_DEFAULTSIZE_PACKET]; + struct { + unsigned short block; + char download[TFTP_MAX_PACKET]; + } data; + struct { + unsigned short block; + } ack; + struct { + unsigned short errcode; + char errmsg[TFTP_DEFAULTSIZE_PACKET]; + } err; + struct { + char data[TFTP_DEFAULTSIZE_PACKET + 2]; + } oack; + } u; +}; + +#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4) + +struct rpc_t { + struct iphdr ip; + struct udphdr udp; + union { + char data[300]; /* longest RPC call must fit!!!! */ + struct { + long id; + long type; + long rpcvers; + long prog; + long vers; + long proc; + long data[1]; + } call; + struct { + long id; + long type; + long rstatus; + long verifier; + long v2; + long astatus; + long data[1]; + } reply; + } u; +}; + +#define PROG_PORTMAP 100000 +#define PROG_NFS 100003 +#define PROG_MOUNT 100005 + +#define MSG_CALL 0 +#define MSG_REPLY 1 + +#define PORTMAP_GETPORT 3 + +#define MOUNT_ADDENTRY 1 +#define MOUNT_UMOUNTALL 4 + +#define NFS_LOOKUP 4 +#define NFS_READ 6 + +#define NFS_FHSIZE 32 + +#define NFSERR_PERM 1 +#define NFSERR_NOENT 2 +#define NFSERR_ACCES 13 + +/* Block size used for NFS read accesses. A RPC reply packet (including all + * headers) must fit within a single Ethernet frame to avoid fragmentation. + * Chosen to be a power of two, as most NFS servers are optimized for this. */ +#define NFS_READ_SIZE 1024 + +#define FLOPPY_BOOT_LOCATION 0x7c00 + +#define ROM_INFO_LOCATION 0x7dfa +/* at end of floppy boot block */ + +struct rom_info { + unsigned short rom_segment; + unsigned short rom_length; +}; + +/*************************************************************************** +External prototypes +***************************************************************************/ +/* main.c */ +extern void print_bytes P((unsigned char *bytes, int len)); +extern void load P((void)); +extern int load_linux P((int root_mount_port, int swap_mount_port, + int root_nfs_port, char *kernel_handle)); +extern int downloadkernel P((unsigned char *, int, int, int)); +extern int tftp +P((const char *name, int (*)(unsigned char *, int, int, int))); +extern void rpc_init(void); +extern int nfs +P((const char *name, int (*)(unsigned char *, int, int, int))); +extern void nfs_umountall P((int)); +extern int bootp P((void)); +extern int rarp P((void)); +extern int udp_transmit P((unsigned long destip, unsigned int srcsock, + unsigned int destsock, int len, + const void *buf)); + +extern int await_reply P((int type, int ival, void *ptr, int timeout)); +extern int decode_rfc1533 P((unsigned char *, int, int, int)); +extern unsigned short ipchksum P((unsigned short *, int len)); +extern void rfc951_sleep P((int)); +extern void cleanup_net P((void)); +extern void cleanup P((void)); + +/* config.c */ +extern void print_config(void); +extern void eth_reset(void); +extern int eth_probe(void); +extern int eth_poll(void); +extern void eth_transmit(const char *d, unsigned int t, unsigned int s, + const void *p); +extern void eth_disable(void); + +/* bootmenu.c */ +extern int execute P((char *string)); +extern void bootmenu P((int)); +extern void show_motd P((void)); +extern void parse_menuopts P((char *, int)); +extern int getoptvalue P((char **, int *, int *)); +extern void selectImage P((char **)); + +/* osloader.c */ +#if defined(AOUT_IMAGE) || defined(ELF_IMAGE) +extern int howto; +#endif +extern int os_download P((unsigned int, unsigned char *, unsigned int)); + +/* misc.c */ +extern void twiddle P((void)); +extern void sleep P((int secs)); +extern int strcasecmp P((char *a, char *b)); +extern char *substr P((char *a, char *b)); +extern int getdec P((char **)); +extern void printf P((const char *, ...)); +extern char *sprintf P((char *, const char *, ...)); +extern int inet_aton P((char *p, in_addr * i)); +extern void gateA20_set P((void)); +extern void gateA20_unset P((void)); +extern void putchar P((int)); +extern int getchar P((void)); +extern int iskey P((void)); + +/* start*.S */ +extern int getc P((void)); +extern void putc P((int)); +extern int ischar P((void)); +extern int getshift P((void)); +extern unsigned int memsize P((void)); +extern unsigned short basememsize P((void)); +extern void disk_init P((void)); +extern unsigned int disk_read P((int drv, int c, int h, int s, char *buf)); +extern void xstart P((unsigned long, unsigned long, char *)); +extern unsigned long currticks P((void)); +extern int setjmp P((void *jmpbuf)); +extern void longjmp P((void *jmpbuf, int where)); +extern void exit P((int status)); +extern void slowdownio P((void)); + +/* serial.S */ +extern int serial_getc P((void)); +extern void serial_putc P((int)); +extern int serial_ischar P((void)); +extern int serial_init P((void)); + +/* ansiesc.c */ +extern void ansi_reset P((void)); +extern void enable_cursor P((int)); +extern void handleansi P((unsigned char)); + +/* md5.c */ +extern void md5_put P((unsigned int ch)); +extern void md5_done P((unsigned char *buf)); + +/* floppy.c */ +extern int bootdisk P((int dev, int part)); + +/*************************************************************************** +External variables +***************************************************************************/ +/* main.c */ +extern const char *kernel; +extern char kernel_buf[128]; +extern struct rom_info rom; +extern int hostnamelen; +extern unsigned long netmask; +extern int jmp_bootmenu[10]; +extern struct arptable_t arptable[MAX_ARP]; +#ifdef IMAGE_MENU +extern char *motd[RFC1533_VENDOR_NUMOFMOTD]; +extern int menutmo, menudefault; +extern unsigned char *defparams; +extern int defparams_max; +#endif +#if defined(ETHERBOOT32) && !defined(INTERNAL_BOOTP_DATA) +#define BOOTP_DATA_ADDR ((struct bootpd_t *)0x93C00) +#else +extern struct bootpd_t bootp_data; +#define BOOTP_DATA_ADDR (&bootp_data) +#endif +extern unsigned char *end_of_rfc1533; +#ifdef IMAGE_FREEBSD +extern int freebsd_howto; +#endif + +/* config.c */ +extern struct nic nic; + +/* bootmenu.c */ + +/* osloader.c */ + +/* created by linker */ +extern char _start[], _edata[], _end[]; + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/evb64120A_Setup.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/evb64120A_Setup.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/evb64120A_Setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/evb64120A_Setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,199 @@ +/* + * arch/mips/galileo/compressed/evb64120A_memSetup.c + * + * By RidgeRun Inc, (Leveraged from Galileo's sbd.c) + * + * Xfer an image from flash to ram. + * For use with Galileo EVB64120A MIPS eval board. + */ + +#include +#include "ns16550.h" +#include +#include +#include + +void XferToRam(void); +bool mapMemoryBanks0and1(unsigned int bank0Base, unsigned int bank0Length, + unsigned int bank1Base, unsigned int bank1Length); +bool mapMemoryBanks2and3(unsigned int bank2Base, unsigned int bank2Length, + unsigned int bank3Base, unsigned int bank3Length); +bool mapDevices0_1and2MemorySpace(unsigned int device0Base, + unsigned int device0Length, + unsigned int device1Base, + unsigned int device1Length, + unsigned int device2Base, + unsigned int device2Length); + +#define RUNNINGFROMFLASH +#include "./xfer.c" + +/****************************** + Routine: + Description: + ******************************/ +unsigned int readWord(unsigned int addr) +{ + unsigned int tmp; + tmp = *(unsigned int *) (addr | NONE_CACHEABLE); + return WORDSWAP(tmp); +} + +/****************************** + Routine: + Description: + ******************************/ +void writeWord(unsigned int addr, unsigned int data) +{ + *((unsigned int *) (addr | NONE_CACHEABLE)) = WORDSWAP(data); +} + +/****************************** + Routine: + Description: + ******************************/ +unsigned int GetExtendedMemorySize(void) +{ + unsigned int address, data = 0x11223344, type; + unsigned int bank1_ef = false, bank2_ef = false, bank3_ef = false; + unsigned int bank0_size, bank2_size, bank3_size, total_size = 0; + + mapMemoryBanks0and1(0, 0x800000, 0x800000, 0x800000); + mapMemoryBanks2and3(0x1000000, 0x800000, 0x1800000, 0x800000); + type = readWord(0x14000810); + switch (type) { + case 16: + bank0_size = 0x1000000; + break; + case 64: + bank0_size = 0x4000000; + break; + case 128: + bank0_size = 0x8000000; + break; + case 256: + bank0_size = 0x10000000; + break; + default: + bank0_size = 0x1000000; + break; + } + + type = readWord(0x14000814); + switch (type) { + case 16: + bank2_size = 0x1000000; + bank3_size = 0x1000000; + break; + case 64: + bank2_size = 0x4000000; + bank3_size = 0x4000000; + break; + case 128: + bank2_size = 0x8000000; + bank3_size = 0x8000000; + break; + case 256: + bank2_size = 0x10000000; + bank3_size = 0x10000000; + break; + default: + bank2_size = 0x1000000; + bank3_size = 0x1000000; + break; + } + + /* Check which banks exist */ + /* Bank 1 */ + for (address = 0xffff00; address < 0x1000000; address += 4) + writeWord(address, data); + for (address = 0xffff00; address < 0x1000000; address += 4) { + if (readWord(address) != data) + break; + } + if (address == 0x1000000) + bank1_ef = true; + // Bank 2 + for (address = 0x17fff00; address < 0x1800000; address += 4) + writeWord(address, data); + for (address = 0x17fff00; address < 0x1800000; address += 4) { + if (readWord(address) != data) + break; + } + if (address == 0x1800000) + bank2_ef = true; + else + bank2_size = 0x0; + // Bank 3 + for (address = 0x1ffff00; address < 0x2000000; address += 4) + writeWord(address, data); + for (address = 0x1ffff00; address < 0x2000000; address += 4) { + if (readWord(address) != data) + break; + } + if (address == 0x2000000) + bank3_ef = true; + + // Reconfig the system with the new bank0 (and maybe bank1) size. + if (bank0_size == 0x10000000) + bank1_ef = false; + if (bank1_ef == true) { + mapMemoryBanks0and1(0, bank0_size, bank0_size, bank0_size); + // Fix the PCI bars + pci0MapMemoryBanks0_1(0, bank0_size * 2); + pci1MapMemoryBanks0_1(0, bank0_size * 2); + total_size += bank0_size * 2; + } else { + mapMemoryBanks0and1(0, bank0_size, bank0_size, 0); + // Fix the PCI bars + pci0MapMemoryBanks0_1(0, bank0_size); + pci1MapMemoryBanks0_1(0, bank0_size); + total_size += bank0_size; + } + if (total_size == 0x10000000) { + bank2_ef = false; + bank3_ef = false; + } else { + if ((total_size + bank2_size) > 0x10000000) { + bank2_size = 0x10000000 - total_size; + bank3_ef = false; + } else { + if (bank3_size + total_size + bank2_size > + 0x10000000) { + bank3_size = + 0x10000000 - (total_size + bank2_size); + } + } + } + if (bank2_ef == true) { + if (bank3_ef == true) { + mapMemoryBanks2and3(total_size, bank2_size, + total_size + bank2_size, + bank3_size); + // Fix the PCI bars + pci0MapMemoryBanks2_3(total_size, + bank2_size + bank3_size); + pci1MapMemoryBanks2_3(total_size, + bank2_size + bank3_size); + total_size += (bank2_size + bank3_size); + } else { + mapMemoryBanks2and3(total_size, bank2_size, + total_size + bank2_size, 0); + // Fix the PCI bars + pci0MapMemoryBanks2_3(total_size, bank2_size); + pci1MapMemoryBanks2_3(total_size, bank2_size); + total_size += bank2_size; + } + } else { + mapMemoryBanks2and3(total_size, 0, total_size, 0); + pci0MapMemoryBanks2_3(total_size, 0); + pci1MapMemoryBanks2_3(total_size, 0); + } + /* Reorganize the devices memory map */ + mapDevices0_1and2MemorySpace(0x1c000000, 0x800000, 0x1a000000, + 0xc00000, 0x1d000000, 0x800000); + + XferToRam(); + return 0; // Not that we'll ever get to this line of code, but + // it does satisfy a compiler warning. +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/fixit linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/fixit --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/fixit Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/fixit Sat Mar 30 22:55:26 2002 @@ -0,0 +1,17 @@ +#!/bin/ksh + +# By RidgeRun Inc. +# +# The input to this script is +# intended to be a *.S file which +# was previously created by the doit +# program. That program constructs +# a *.S file which has a defined data +# table containing values with leading +# zeroes. To satisfy our assembler those +# leading zeroes need to be stripped off +# and that is the purpose of this script. + +echo "Removing leading zeros" +sed -e "s/ 0\(.\)/ \1/g" $1 | sed -e "s/ 0\(.\)/ \1/g" > $1.new +mv $1.new $1 diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/flashdrv.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1560 @@ +/* flashdrv.c - FLASH memory functions and definitions*/ + +/* Copyright Galileo Technology. */ + +/* +DESCRIPTION +This flash driver gives the user a convenient interface to FLASH memory located +on the user`s board, it supports various layout configurations such as: +1. One pure 8 bit device (Such as AMD`s AM29LV040B). +2. 1,2,4 or 8 devices 16 bit wide configured to operate in 8 bit mode. +3. 1,2 or 4 devices each 16 bit wide. +Before using the driver you must call the initialization function at least once +or when ever you are changing the FLASH base address. +The list bellow contains the supported FLASH memory devices, new devices can be +added easily in the future. +*/ + +/*includes*/ +#ifdef __linux__ +#include +#else +#include "flashdrv.h" +#endif +/* locals */ + +#ifdef __MIPSEB__ // skranz, add +#define BE // skranz, add +#endif // skranz, add + +/****************************************************************************** +* Those two tables contain the supported flash devices information needed by +* the driver: +* The first table "flashParametrs" starts with 10 shared fields +* (currently 6 are reserved): +* index 0 => Pointer to an entry in the second table list +* index 1 => baseAddress - Flash memory device base address. +* index 2 => width - 1, 2, 4 or 8 Bytes. +* index 3 => mode - PURE8, X8 or X16 flash configuration (for X16 devices only) +* The second table (flashTypes) contains: +* Entry`s structure: +* Manufacture ID,Device ID,number of sectors,list of sector`s sizes +* (in Kbytes starting with sector number 0). +* The end of the list is pointed with a zero. +******************************************************************************/ +unsigned int flashParametrs[10]; /* 0 Entry pointer */ + /* 0 Base address */ + /* 0 Width */ + /* 0 Mode */ + /* 0,0,0,0,0,0, spare entries. */ +unsigned int flashTypes[] = { + + /* 0 */ AMD_FLASH, AM29F400BB, 11, 16, 8, 8, 32, 64, 64, 64, 64, + 64, 64, 64, + /* 1 */ AMD_FLASH, AM29F400BT, 11, 64, 64, 64, 64, 64, 64, 64, 32, + 8, 8, 16, + /* 2 */ ST_FLASH, M29W040, 8, 64, 64, 64, 64, 64, 64, 64, 64, + /* 3 */ AMD_FLASH, AM29LV040B, 8, 64, 64, 64, 64, 64, 64, 64, 64, + /* 4 */ AMD_FLASH, AM29LV800BT, 19, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, + 64, 64, 64, 64, 64, 32, 8, 8, 16, + /* 5 */ INTEL_FLASH, I28F320J3A, 32, 128, 128, 128, 128, 128, 128, + 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, + /* 6 */ INTEL_FLASH, I28F640J3A, 64, 128, 128, 128, 128, 128, 128, + 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, + /* 7 */ INTEL_FLASH, I28F128J3A, 128, 128, 128, 128, 128, 128, 128, + 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + /* 8 */ AMD_FLASH, AM29LV400BB, 11, 16, 8, 8, 32, 64, 64, 64, 64, + 64, 64, 64, + /* 9 */ AMD_FLASH, AM29LV400BT, 11, 64, 64, 64, 64, 64, 64, 64, 32, + 8, 8, 16, + /* 10 */ INTEL_FLASH, I28F320B3_T, 71, 64, 64, 64, 64, 64, 64, 64, + 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 8, 8, 8, 8, 8, 8, 8, 8, + /* 11 */ INTEL_FLASH, I28F320B3_B, 71, 8, 8, 8, 8, 8, 8, 8, 8, 64, + 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* 12 */ INTEL_FLASH, I28F160B3_B, 39, 8, 8, 8, 8, 8, 8, 8, 8, 64, + 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + /* 13 */ INTEL_FLASH, I28F160B3_T, 39, 64, 64, 64, 64, 64, 64, 64, + 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 8, 8, 8, 8, 8, 8, 8, 8, + + 0 /* End of list indicator */ +}; + +/******************************************************************** +* flashInit - Initializes the FLASH memory driver`s parameters, this function +* must be called at least once before using the FLASH memory. +* If you are changing the FLASH base address call this function +* again. +* +* INPUTS: unsigned int flashBaseAddress - The flash base Address. +* unsigned int flashWidth - Flash bus width in Bytes: 1,2,4 or 8. +* flashMode - PURE8, X8 or X16. +* RETURNS: Flash Size, zero when operation (flashInit) failed. +*********************************************************************/ +unsigned int flashInit(unsigned int flashBaseAddress, + unsigned int flashWidth, FLASHmode flashMode) +{ + unsigned short mfrId = 0; + unsigned short devId = 0xffff; + unsigned int FirstAddr, SecondAddr, ThirdAddr; + unsigned int pArray = 0; + unsigned int counter; + unsigned int flashSize = 0; + + /* update the list with relevant parametrs */ + flashParametrs[0] = 0; /* Default initialization */ + flashParametrs[1] = flashBaseAddress; + flashParametrs[2] = flashWidth; + flashParametrs[3] = flashMode; + /* Get the FLASH`s ID */ + switch (FLASH_WIDTH) { + case 1: + /* AMD or ST ?? * */ + if (flashMode == PURE8) { /* Boot Flash */ + FirstAddr = 0x5555; + SecondAddr = 0x2aaa; + ThirdAddr = 0x5555; + } else { /* X16 device configured to 8bit Mode */ + + FirstAddr = 0xaaaa; + SecondAddr = 0x5555; + ThirdAddr = 0xaaaa; + } + flashReset(); + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xAA); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0x90); + READ_CHAR(FLASH_BASE_ADDRESS + 0x0, &mfrId); + if (mfrId == AMD_FLASH || mfrId == ST_FLASH) { + flashReset(); + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xAA); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0x90); + READ_CHAR(FLASH_BASE_ADDRESS + 0x1, &devId); + break; + } + /* Micron or Intel ?? * */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0xff); /* Read Array */ + /* Flash reset for Intel/Micron */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x90); /* IDENTIFY Device */ + READ_CHAR(FLASH_BASE_ADDRESS + 0x0, &mfrId); /*Address for ManufactureID */ + if (mfrId == INTEL_FLASH || mfrId == MICRON_FLASH) { + WRITE_CHAR(FLASH_BASE_ADDRESS, 0xff); /* Read Array */ + /*Flash reset for Intel/Micron */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x90); /* IDENTIFY Device */ + READ_CHAR(FLASH_BASE_ADDRESS + 0x1, &devId); /*Address for DeviceID */ + } + break; + case 2: + case 4: + case 8: + /* AMD or ST ??? */ + flashReset(); + WRITE_SHORT(FLASH_BASE_ADDRESS + 0x5555 * FLASH_WIDTH, + 0xaa); + WRITE_SHORT(FLASH_BASE_ADDRESS + 0x2aaa * FLASH_WIDTH, + 0x55); + WRITE_SHORT(FLASH_BASE_ADDRESS + 0x5555 * FLASH_WIDTH, + 0x90); + READ_SHORT(FLASH_BASE_ADDRESS, &mfrId); + flashReset(); + /* Read the device ID */ + if (mfrId == AMD_FLASH || mfrId == ST_FLASH) { + WRITE_SHORT(FLASH_BASE_ADDRESS + + 0x5555 * FLASH_WIDTH, 0xaa); + WRITE_SHORT(FLASH_BASE_ADDRESS + + 0x2aaa * FLASH_WIDTH, 0x55); + WRITE_SHORT(FLASH_BASE_ADDRESS + + 0x5555 * FLASH_WIDTH, 0x90); + READ_SHORT(FLASH_BASE_ADDRESS + 0x1 * FLASH_WIDTH, + &devId); + break; + } + /* Micron or Intel ?? * */ + WRITE_WORD(FLASH_BASE_ADDRESS, 0x00ff00ff); + WRITE_WORD(FLASH_BASE_ADDRESS, 0x00900090); + if ((FLASH_WIDTH == 4) || (FLASH_WIDTH == 8)) { /* 32 or 64 bit */ + READ_SHORT(FLASH_BASE_ADDRESS, &mfrId); + } else { /* FLASH_WIDTH = 2 */ + + READ_SHORT(FLASH_BASE_ADDRESS, &mfrId); + } + if ((mfrId == INTEL_FLASH) || (mfrId == MICRON_FLASH)) { + /* Flash reset for Intel/Micron */ + flashReset(); + WRITE_WORD(FLASH_BASE_ADDRESS, 0x00ff00ff); + WRITE_WORD(FLASH_BASE_ADDRESS, 0x00900090); + READ_SHORT(FLASH_BASE_ADDRESS + 0x1 * FLASH_WIDTH, + &devId); + } + break; + + } + /* Try to locate the device in the supported flashes list (FLASH_TYPE). + according to the keys: + 1) mfrId - manufactor ID. + 2) devId - device ID. + */ + + while (true) { + if (flashTypes[pArray] == 0) { + flashReset(); + return 0; /* Device not in the list */ + } + if ((flashTypes[pArray] == mfrId) && + (flashTypes[pArray + 1] == devId)) { + POINTER_TO_FLASH = pArray; + for (counter = 0; + counter < flashTypes[NUMBER_OF_SECTORS]; + counter++) { + flashSize = + flashSize + + flashTypes[FIRST_SECTOR_SIZE + + counter]; + } + if (FLASH_MODE != PURE8) { + flashReset(); + return (flashSize * _1K * + (FLASH_WIDTH / (FLASH_MODE / 8))); + } else { + flashReset(); + return (flashSize * _1K * FLASH_WIDTH); + } + } + pArray += (3 + flashTypes[pArray + 2]); /* Move to next entry */ + } +} + +/******************************************************************** +* flashReset - Resets the Flash memory (FLASH`s internal protocol reset). +* +* INTPUTS: N/A +* OUTPUT: N/A +*********************************************************************/ +void flashReset() +{ + unsigned char ucData; + unsigned short usData; + unsigned int uiData; + + if ((flashTypes[POINTER_TO_FLASH] == AMD_FLASH) || + (flashTypes[POINTER_TO_FLASH]) == ST_FLASH) { + if (FLASH_MODE == X16) { + ucData = 0xf0; + usData = 0xf0; + uiData = 0x00f000f0; + } else { /* case of PURE8 or X8 */ + + ucData = 0xf0; + usData = 0xf0f0; + uiData = 0xf0f0f0f0; + } + } else { + if (FLASH_MODE == X16) { + ucData = 0xff; + usData = 0xff; + uiData = 0x00ff00ff; + } else { /* case of PURE8 or X8 */ + + ucData = 0xff; + usData = 0xffff; + uiData = 0xffffffff; + } + } + switch (FLASH_WIDTH) { + case 1: + WRITE_CHAR(FLASH_BASE_ADDRESS, ucData); + break; + case 2: + WRITE_SHORT(FLASH_BASE_ADDRESS, usData); + break; + case 4: + WRITE_WORD(FLASH_BASE_ADDRESS, uiData); + break; + case 8: + WRITE_WORD(FLASH_BASE_ADDRESS, uiData); + WRITE_WORD(FLASH_BASE_ADDRESS + 0x4, uiData); + break; + } +} + +/******************************************************************** +* flashErase - The function erases the WHOLE flash memory. +* +* +* RETURNS: true on success,false on failure +*********************************************************************/ +bool flashErase() +{ + unsigned int totalFlashSize; + unsigned int address; + unsigned int readData; + unsigned int nextSector; + + flashReset(); + totalFlashSize = flashGetSize(); + /* scan all flash memory space. */ + address = 0; + while (address < totalFlashSize) { + readData = flashReadWord(address); + if (readData != 0xffffffff) { /* offset with dirty data. */ + flashEraseSector(flashInWhichSector(address)); + nextSector = flashInWhichSector(address) + 1; + if (nextSector < flashTypes[NUMBER_OF_SECTORS]) + /* jump to next sector. */ + address = flashGetSectorOffset(nextSector); + else + /* end of erasing. */ + address = totalFlashSize; + } else + address += 4; + } + return true; +} + +/******************************************************************** +* flashEraseSector - The function erases a specific sector in the flash memory. +* +* INPUTS: Sector number. +* RETURNS: true on success,false on failure. +*********************************************************************/ +bool flashEraseSector(unsigned int sectorNumber) +{ + volatile unsigned int spin; + unsigned int regValue; + unsigned int sectorBaseAddress = 0; + unsigned int i; + unsigned int data20, dataD0, data70; + unsigned int dataPoll; + unsigned int FirstAddr, SecondAddr, ThirdAddr, FourthAddr, + FifthAddr; + unsigned int FirstData, SecondData, ThirdData; + unsigned int FourthData, FifthData, SixthData; + + /* calculate the sector base Address according to the following parametrs: + 1: FLASH_WIDTH + 2: the size of each sector which it detailed in the table */ + + /* checking the if the sectorNumber is legal. */ + if (sectorNumber > flashTypes[NUMBER_OF_SECTORS] - 1) + return false; + /* now the calculation begining of the sector Address */ + for (i = 0; i < sectorNumber; i++) { + sectorBaseAddress = + sectorBaseAddress + flashTypes[FIRST_SECTOR_SIZE + i]; + } + /* In case of X8 wide the address should be */ + if (FLASH_MODE == PURE8) + sectorBaseAddress = _1K * sectorBaseAddress; + if (FLASH_MODE == X8) + sectorBaseAddress = _1K * sectorBaseAddress; + /* In case of X16 wide the address should be */ + if (FLASH_MODE == X16) + sectorBaseAddress = _1K * sectorBaseAddress / 2; + flashReset(); + if ((flashTypes[POINTER_TO_FLASH] == AMD_FLASH) || \ + (flashTypes[POINTER_TO_FLASH] == ST_FLASH)) { + switch (FLASH_WIDTH) { + case 1: + if (FLASH_MODE == PURE8) { /* Boot Flash PURE8 */ + FirstAddr = 0x5555; + SecondAddr = 0x2aaa; + ThirdAddr = 0x5555; + FourthAddr = 0x5555; + FifthAddr = 0x2aaa; + } else { + FirstAddr = 0xaaaa; + SecondAddr = 0x5555; + ThirdAddr = 0xaaaa; + FourthAddr = 0xaaaa; + FifthAddr = 0x5555; + } + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xAA); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0x80); + WRITE_CHAR(FLASH_BASE_ADDRESS + FourthAddr, 0xAA); + WRITE_CHAR(FLASH_BASE_ADDRESS + FifthAddr, 0x55); + WRITE_CHAR( + (FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00)), + 0x30); + /* Poll on the flash */ + do { + READ_CHAR(FLASH_BASE_ADDRESS + + sectorBaseAddress, ®Value); + } while ((regValue & 0x80) != 0x80); + + break; + case 2: + if (FLASH_MODE == X16) { + FirstData = 0xaa; /* Data for the First Cycle */ + SecondData = 0x55; /* Data for the Second Cycle */ + ThirdData = 0x80; /* Data for the Third Cycle */ + FourthData = 0xaa; /* Data for the Fourth Cycle */ + FifthData = 0x55; /* Data for the Fifth Cycle */ + SixthData = 0x30; /* Data for the Sixth Cycle */ + FirstAddr = 0x5555; /* Address for the First Cycle */ + SecondAddr = 0x2aaa; /* Address for the Second Cycle */ + ThirdAddr = 0x5555; /* Address for the Third Cycle */ + FourthAddr = 0x5555; /* Address for the Fourth Cycle */ + FifthAddr = 0x2aaa; /* Address for the Fifth Cycle */ + } else { /* (FLASH_MODE = 8) */ + + FirstData = 0xaaaa; /* Data for the First Cycle */ + SecondData = 0x5555; /* Data for the Second Cycle */ + ThirdData = 0x8080; /* Data for the Third Cycle */ + FourthData = 0xaaaa; /* Data for the Fourth Cycle */ + FifthData = 0x5555; /* Data for the Fifth Cycle */ + SixthData = 0x3030; /* Data for the Sixth Cycle */ + FirstAddr = 0xaaaa; /* Address for the First Cycle */ + SecondAddr = 0x5555; /* Address for the Second Cycle */ + ThirdAddr = 0xaaaa; /* Address for the Third Cycle */ + FourthAddr = 0xaaaa; /* Address for the Fourth Cycle */ + FifthAddr = 0x5555; /* Address for the Fifth Cycle */ + } + WRITE_SHORT(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH, FirstData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH, SecondData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH, ThirdData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + FourthAddr * FLASH_WIDTH, FourthData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + FifthAddr * FLASH_WIDTH, FifthData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00) * + FLASH_WIDTH, SixthData); + /* Poll on the flash */ + if (FLASH_MODE == X16) { /* 1 device of 16 bit */ + dataPoll = 0x0080; + } else { /* (FLASH_MODE = 8) ==> 2 devices , 8 bit each => 16bit */ + + dataPoll = 0x8080; + } + do { + READ_SHORT(FLASH_BASE_ADDRESS + + sectorBaseAddress * FLASH_WIDTH, + ®Value); + for (spin = 0; spin < 100; spin++) { + } // skranz, added spin loop. + } while ((regValue & dataPoll) != dataPoll); + break; + case 4: + if (FLASH_MODE == X16) { + FirstData = 0x00aa00aa; /* Data for the First Cycle */ + SecondData = 0x00550055; /* Data for the Second Cycle */ + ThirdData = 0x00800080; /* Data for the Third Cycle */ + FourthData = 0x00aa00aa; /* Data for the Fourth Cycle */ + FifthData = 0x00550055; /* Data for the Fifth Cycle */ + SixthData = 0x00300030; /* Data for the Sixth Cycle */ + FirstAddr = 0x5555; /* Address for the First Cycle */ + SecondAddr = 0x2aaa; /* Address for the Second Cycle */ + ThirdAddr = 0x5555; /* Address for the Third Cycle */ + FourthAddr = 0x5555; /* Address for the Fourth Cycle */ + FifthAddr = 0x2aaa; /* Address for the Fifth Cycle */ + } else { /* if (FLASH_MODE == 8) */ + + FirstData = 0xaaaaaaaa; /* Data for the First Cycle */ + SecondData = 0x55555555; /* Data for the Second Cycle */ + ThirdData = 0x80808080; /* Data for the Third Cycle */ + FourthData = 0xAAAAAAAA; /* Data for the Fourth Cycle */ + FifthData = 0x55555555; /* Data for the Fifth Cycle */ + SixthData = 0x30303030; /* Data for the Sixth Cycle */ + FirstAddr = 0xaaaa; /* Address for the First Cycle */ + SecondAddr = 0x5555; /* Address for the Second Cycle */ + ThirdAddr = 0xaaaa; /* Address for the Third Cycle */ + FourthAddr = 0xaaaa; /* Address for the Fourth Cycle */ + FifthAddr = 0x5555; /* Address for the Fifth Cycle */ + } + WRITE_WORD(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH, FirstData); + WRITE_WORD(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH, SecondData); + WRITE_WORD(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH, ThirdData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FourthAddr * FLASH_WIDTH, FourthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FifthAddr * FLASH_WIDTH, FifthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00) * + FLASH_WIDTH, SixthData); + /* Poll on the flash */ + if (FLASH_MODE == X16) { /* 4 devices , 16 bit each => 64bit */ + dataPoll = 0x00800080; + } else { /* (FLASH_MODE = 8) ==> 8 devices , 8 bit each => 64bit */ + + dataPoll = 0x80808080; + } + do { + READ_WORD(FLASH_BASE_ADDRESS + + sectorBaseAddress * FLASH_WIDTH, + ®Value); + } while ((regValue & dataPoll) != dataPoll); + break; + case 8: /* In case of 64bit width the transformation is 1->8 */ + if (FLASH_MODE == X16) { + FirstData = 0x00aa00aa; /* Data for the First Cycle */ + SecondData = 0x00550055; /* Data for the Second Cycle */ + ThirdData = 0x00800080; /* Data for the Third Cycle */ + FourthData = 0x00aa00aa; /* Data for the Fourth Cycle */ + FifthData = 0x00550055; /* Data for the Fifth Cycle */ + SixthData = 0x00300030; /* Data for the Sixth Cycle */ + FirstAddr = 0x5555; /* Address for the First Cycle */ + SecondAddr = 0x2aaa; /* Address for the Second Cycle */ + ThirdAddr = 0x5555; /* Address for the Third Cycle */ + FourthAddr = 0x5555; /* Address for the Fourth Cycle */ + FifthAddr = 0x2aaa; /* Address for the Fifth Cycle */ + } else { /* (FLASH_MODE = 8 */ + + FirstData = 0xaaaaaaaa; /* Data for the First Cycle */ + SecondData = 0x55555555; /* Data for the Second Cycle */ + ThirdData = 0x80808080; /* Data for the Third Cycle */ + FourthData = 0xAAAAAAAA; /* Data for the Fourth Cycle */ + FifthData = 0x55555555; /* Data for the Fifth Cycle */ + SixthData = 0x30303030; /* Data for the Sixth Cycle */ + FirstAddr = 0xaaaa; /* Address for the First Cycle */ + SecondAddr = 0x5555; /* Address for the Second Cycle */ + ThirdAddr = 0xaaaa; /* Address for the Third Cycle */ + FourthAddr = 0xaaaa; /* Address for the Fourth Cycle */ + FifthAddr = 0x5555; /* Address for the Fifth Cycle */ + } + WRITE_WORD(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH, FirstData); + WRITE_WORD(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH, SecondData); + WRITE_WORD(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH, ThirdData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FourthAddr * FLASH_WIDTH, FourthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FifthAddr * FLASH_WIDTH, FifthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00) * + FLASH_WIDTH, SixthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH + 4, FirstData); + WRITE_WORD(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH + 4, + SecondData); + WRITE_WORD(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH + 4, ThirdData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FourthAddr * FLASH_WIDTH + 4, + FourthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + FifthAddr * FLASH_WIDTH + 4, FifthData); + WRITE_WORD(FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00) + * FLASH_WIDTH + 4, SixthData); + /* Poll on the flash */ + if (FLASH_MODE == X16) { /* 4 devices , 16 bit each => 64bit */ + dataPoll = 0x00800080; + } else { /* (FLASH_MODE = 8) ==> 8 devices , 8 bit each => 64bit */ + + dataPoll = 0x80808080; + } + do { + READ_WORD(FLASH_BASE_ADDRESS + + sectorBaseAddress * FLASH_WIDTH, + ®Value); + } while ((regValue & dataPoll) != dataPoll); + do { + READ_WORD(FLASH_BASE_ADDRESS + + sectorBaseAddress * FLASH_WIDTH + + 4, ®Value); + } while ((regValue & dataPoll) != dataPoll); + break; + default: + return false; + } + } /* End of 'flash erase sector' for AMD/ST */ + else { /* Intel/Micron */ + + switch (FLASH_WIDTH) { + case 1: + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x20); + WRITE_CHAR( + (FLASH_BASE_ADDRESS + + (sectorBaseAddress & 0xffffff00)), + 0xd0); + /* Poll on the flash */ + while (true) { + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x70); + READ_CHAR(FLASH_BASE_ADDRESS, ®Value); + if ((regValue & 0x80) == 0x80) + break; + } + break; + case 2: + if (FLASH_MODE == X16) { /* 1 device 16 bit. */ + data20 = 0x0020;; + dataD0 = 0x00d0;; + } else { /* (FLASH_MODE = 8) ==> 2 devices , 8 bit each => 16bit */ + + data20 = 0x2020; + dataD0 = 0xd0d0; + } + WRITE_SHORT(FLASH_BASE_ADDRESS, data20); + WRITE_SHORT( + (FLASH_BASE_ADDRESS + + ((sectorBaseAddress * 2) & + 0xffffff00)), dataD0); + /* Poll on the flash */ + if (FLASH_MODE == X16) { + dataPoll = 0x0080; + data70 = 0x0070; + } else { /* (FLASH_MODE = 8) */ + + dataPoll = 0x8080; + data70 = 0x7070; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + + sectorBaseAddress * 2, data70); + READ_SHORT(FLASH_BASE_ADDRESS + + sectorBaseAddress * 2, + ®Value); + if ((regValue & 0x0080) == 0x0080) + break; + } + break; + case 4: + if (FLASH_MODE == X16) { /* 2 devices , 16 bit each => 32bit */ + data20 = 0x00200020; + dataD0 = 0x00d000d0; + } else { /* (FLASH_MODE = 8) ==> 4 devices , 8 bit each => 32bit */ + + data20 = 0x20202020; + dataD0 = 0xd0d0d0d0; + } + WRITE_WORD(FLASH_BASE_ADDRESS, data20); + WRITE_WORD( + (FLASH_BASE_ADDRESS + + ((sectorBaseAddress * 4) & + 0xffffff00)), dataD0); + /* Poll on the flash */ + if (FLASH_MODE == X16) { + dataPoll = 0x0080; + data70 = 0x0070; + } else { /* (FLASH_MODE = 8) */ + + dataPoll = 0x8080; + data70 = 0x7070; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS, data70); + READ_SHORT(FLASH_BASE_ADDRESS, ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + 2, + data70); + READ_SHORT(FLASH_BASE_ADDRESS + 2, + ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + break; + case 8: + if (FLASH_MODE == X16) { /* 4 devices , 16 bit each => 64bit */ + data20 = 0x00200020; + dataD0 = 0x00d000d0; + } else { /* (FLASH_MODE = 8) ==> 8 devices , 8 bit each => 64bit */ + + data20 = 0x20202020; + dataD0 = 0xd0d0d0d0; + } + WRITE_WORD(FLASH_BASE_ADDRESS, data20); + WRITE_WORD( + (FLASH_BASE_ADDRESS + + ((sectorBaseAddress * 8) & + 0xffffff00)), dataD0); + WRITE_WORD(FLASH_BASE_ADDRESS + 4, data20); + WRITE_WORD( + (FLASH_BASE_ADDRESS + + ((sectorBaseAddress * 8) & 0xffffff00 + + 4)), dataD0); + /* Poll on the flash */ + if (FLASH_MODE == X16) { + dataPoll = 0x0080; + data70 = 0x0070; + } else { /* (FLASH_MODE = 8) */ + + dataPoll = 0x8080; + data70 = 0x7070; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + + sectorBaseAddress * 8, data70); + READ_SHORT(FLASH_BASE_ADDRESS + + sectorBaseAddress * 8, + ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + 2, + data70); + READ_SHORT(FLASH_BASE_ADDRESS + 2, + ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + 4, + data70); + READ_SHORT(FLASH_BASE_ADDRESS + 4, + ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + 6, + data70); + READ_SHORT(FLASH_BASE_ADDRESS + 6, + ®Value); + if ((regValue & dataPoll) == dataPoll) + break; + } + break; + default: + return false; + } + } + flashReset(); + return true; +} + +/******************************************************************** +* flashWriteWord - Write 32Bit to the FLASH memory at the given offset from the +* FLASH base address. +* address 0 = 0x00000000 !! +* Attention!!! data "0" cannot be programed back to +* "1" (only by first performing an earase operation). +* The function takes care of Big/Little endian conversion +* +* INPUTS: offset - The offset from the flash`s base address. +* data - The data that should be written. +* RETURNS: true on success,false on failure +*********************************************************************/ +bool flashWriteWord(unsigned int offset, unsigned int data) +{ + unsigned char c, rc; + unsigned short s, rs; + register unsigned int rw; + register unsigned int regValue; + register unsigned int FirstAddr, SecondAddr, ThirdAddr; + register unsigned int FirstData, SecondData, ThirdData; + register unsigned int data10, data20, data70, data80; + + if ((flashTypes[POINTER_TO_FLASH] == AMD_FLASH) || \ + (flashTypes[POINTER_TO_FLASH] == ST_FLASH)) { + switch (FLASH_WIDTH) { + case 1: /* Split the 32 bit write into four 8bit Writings */ + if (FLASH_MODE == PURE8) { /* Boot Flash */ + FirstAddr = 0x5555; + SecondAddr = 0x2aaa; + ThirdAddr = 0x5555; + } else { + FirstAddr = 0xaaaa; + SecondAddr = 0x5555; + ThirdAddr = 0xaaaa; + } + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xaa); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0xa0); +#ifdef BE + c = (data >> 24); +#else + c = data; +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset, c); + /* Writing first Byte */ + while (true) { + READ_CHAR(FLASH_BASE_ADDRESS + offset, + &rc); + if ((rc & 0x80) == (c & 0x80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rc & 0x20) == 0x20) { /* DQ5 =? '1' */ + READ_CHAR(FLASH_BASE_ADDRESS + + offset, &rc); + if ((rc & 0x80) == (c & 0x80)) + break; /* DQ7 = DATA */ + else + return false; /* DQ7 != DATA */ + } + } + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xaa); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0xa0); +#ifdef BE + c = (data >> 16); +#else + c = (data >> 8); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 1, c); + /* Writing second Byte */ + while (true) { + READ_CHAR(FLASH_BASE_ADDRESS + offset + 1, + &rc); + if ((rc & 0x80) == (c & 0x80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rc & 0x20) == 0x20) { /* DQ5 =? '1' */ + READ_CHAR(FLASH_BASE_ADDRESS + + offset + 1, &rc); + if ((rc & 0x80) == (c & 0x80)) + break; /* DQ7 = DATA */ + else + return false; /* DQ7 != DATA */ + } + } + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xaa); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0xa0); +#ifdef BE + c = (data >> 8); +#else + c = (data >> 16); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 2, c); + /* Writing third Byte */ + while (true) { + READ_CHAR(FLASH_BASE_ADDRESS + offset + 2, + &rc); + if ((rc & 0x80) == (c & 0x80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rc & 0x20) == 0x20) { /* DQ5 =? '1' */ + READ_CHAR(FLASH_BASE_ADDRESS + + offset + 2, &rc); + if ((rc & 0x80) == (c & 0x80)) + break; /* DQ7 = DATA */ + else + return false; /* DQ7 != DATA */ + } + } + WRITE_CHAR(FLASH_BASE_ADDRESS + FirstAddr, 0xaa); + WRITE_CHAR(FLASH_BASE_ADDRESS + SecondAddr, 0x55); + WRITE_CHAR(FLASH_BASE_ADDRESS + ThirdAddr, 0xa0); +#ifdef BE + c = data; +#else + c = (data >> 24); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 3, c); + /* Writing fourth Byte */ + while (true) { + READ_CHAR(FLASH_BASE_ADDRESS + offset + 3, + &rc); + if ((rc & 0x80) == (c & 0x80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rc & 0x20) == 0x20) { /* DQ5 =? '1' */ + READ_CHAR(FLASH_BASE_ADDRESS + + offset + 3, &rc); + if ((rc & 0x80) == (c & 0x80)) + break; /* DQ7 = DATA */ + else + return false; /* DQ7 != DATA */ + } + } + break; + case 2: /* Split the 32 bit write into two 8/16 bit Writings + (16bit width). */ + if (FLASH_MODE == X16) { + FirstData = 0xaa; /* Data for the First Cycle */ + SecondData = 0x55; /* Data for the Second Cycle */ + ThirdData = 0xa0; /* Data for the Third Cycle */ + FirstAddr = 0x5555; /* Address for the First Cycle */ + SecondAddr = 0x2aaa; /* Address for the Second Cycle */ + ThirdAddr = 0x5555; /* Address for the Third Cycle */ + } else { /* if (FLASH_MODE == 8) */ + + FirstData = 0xaaaa; /* Data for the First Cycle */ + SecondData = 0x5555; /* Data for the Second Cycle */ + ThirdData = 0xa0a0; /* Data for the Third Cycle */ + FirstAddr = 0xaaaa; /* Address for the First Cycle */ + SecondAddr = 0x5555; /* Address for the Second Cycle */ + ThirdAddr = 0xaaaa; /* Address for the Third Cycle */ + } + WRITE_SHORT(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH, FirstData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH, SecondData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH, ThirdData); +#ifdef BE + s = (data >> 16); +#else + s = data; +#endif + WRITE_SHORT(FLASH_BASE_ADDRESS + offset, s); + /* Writing Two Bytes */ + if (FLASH_MODE == X16) { + data80 = 0x80;; + data20 = 0x20;; + } else { /* if (FLASH_MODE == 8) */ + + data80 = 0x8080; + data20 = 0x2020; + } + while (true) { + READ_SHORT(FLASH_BASE_ADDRESS + offset, + &rs); + if ((rs & data80) == (s & data80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rs & data20) == data20) { /* DQ5 =? DATA */ + READ_SHORT(FLASH_BASE_ADDRESS + + offset, &rs); + if ((rs & data80) == (s & data80)) + break; /* DQ7 = DATA */ + else { + flashReset(); + return false; /* DQ7 != DATA */ + } + } + } + WRITE_SHORT(FLASH_BASE_ADDRESS + + FirstAddr * FLASH_WIDTH, FirstData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH, SecondData); + WRITE_SHORT(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH, ThirdData); +#ifdef BE + s = data; +#else + s = (data >> 16); +#endif + WRITE_SHORT(FLASH_BASE_ADDRESS + offset + 2, s); + /* Writing Two Bytes */ + while (true) { + READ_SHORT(FLASH_BASE_ADDRESS + offset + 2, + &rs); + if ((rs & data80) == (s & data80)) /* DQ7 =? DATA */ + break; /* DQ7 = DATA */ + if ((rs & data20) == data20) { /* DQ5 =? '1' */ + READ_SHORT(FLASH_BASE_ADDRESS + + offset + 2, &rs); + if ((rs & data80) == (s & data80)) + break; /* DQ7 = DATA */ + else { + flashReset(); + return false; /* DQ7 != DATA */ + } + } + } + return true; + case 4: + case 8: + if (FLASH_MODE == X16) { + FirstData = 0x00aa00aa; + SecondData = 0x00550055; + ThirdData = 0x00a000a0; + FirstAddr = 0x5555; + SecondAddr = 0x2aaa; + ThirdAddr = 0x5555; + } else { /* (FLASH_MODE == 8) */ + + FirstData = 0xaaaaaaaa; /* Data for the First Cycle */ + SecondData = 0x55555555; /* Data for the Second Cycle */ + ThirdData = 0xa0a0a0a0; /* Data for the Third Cycle */ + FirstAddr = 0xaaaaaaaa; /* Address for the First Cycle */ + SecondAddr = 0x55555555; /* Address for the Second Cycle */ + ThirdAddr = 0xaaaaaaaa; /* Address for the Third Cycle */ + } + WRITE_WORD(FLASH_BASE_ADDRESS + FirstAddr * + FLASH_WIDTH + offset % FLASH_WIDTH, + FirstData); + WRITE_WORD(FLASH_BASE_ADDRESS + + SecondAddr * FLASH_WIDTH + + offset % FLASH_WIDTH, SecondData); + WRITE_WORD(FLASH_BASE_ADDRESS + + ThirdAddr * FLASH_WIDTH + + offset % FLASH_WIDTH, ThirdData); + /* writting the word. */ + WRITE_WORD(FLASH_BASE_ADDRESS + offset, data); + /* preparing the polling patterns. */ + if (FLASH_MODE == X16) { + data80 = 0x00800080; + data20 = 0x00200020; + } else { /* (FLASH_MODE == 8) */ + + data80 = 0x80808080; + data20 = 0x20202020; + } + while (true) { /* polling loop. */ + rw = READWORD(FLASH_BASE_ADDRESS + offset); + /* DQ7 =? DATA */ + if ((rw & data80) == (data & data80)) + break; /* DQ7 = DATA */ + if ((rw & data20) == data20) { /* DQ5 =? '1' */ + rw = + READWORD(FLASH_BASE_ADDRESS + + offset); + if ((rw & data80) == + (data & data80)) break; /* DQ7 = DATA */ + else + return false; /* DQ7 != DATA */ + } + } + return true; + default: + return false; /* case of invalid flash Width. */ + } + } else { /* Intel/Micron */ + + switch (FLASH_WIDTH) { + case 1: + /* Writing First Byte */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x10); +#ifdef BE + c = (data >> 24); +#else + c = data; +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset, c); + while (true) { + /* Reading STATUS Register */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & 0x80) == 0x80) + break; /* Case of Write-Operation had Ended */ + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS, 0x70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & 0x10) == 0x10) + return false; /* Write failure */ + + /* Writing Second Byte */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 1, 0x10); +#ifdef BE + c = (data >> 16); +#else + c = (data >> 8); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 1, c); + while (true) { + /* Reading STATUS Register */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 1, 0x70); + regValue = + READCHAR(FLASH_BASE_ADDRESS + 1); + if ((regValue & 0x80) == 0x80) + break; /* Write operation ended */ + } + /* Reading STATUS Register for Writing verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 1, 0x70); + regValue = READCHAR(FLASH_BASE_ADDRESS + 1); + if ((regValue & 0x10) == 0x10) + return false; /* Write failure */ + + /* Writing Third Byte */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 2, 0x10); +#ifdef BE + c = (data >> 8); +#else + c = (data >> 16); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 2, c); + while (true) { + /* Reading STATUS Register */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 2, 0x70); + regValue = + READCHAR(FLASH_BASE_ADDRESS + 2); + if ((regValue & 0x80) == 0x80) + break; /* Write operation ended */ + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 2, 0x70); + regValue = READCHAR(FLASH_BASE_ADDRESS + 2); + if ((regValue & 0x10) == 0x10) + return false; /* Write failure */ + + /* Writing Fourth Byte */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 3, 0x10); +#ifdef BE + c = data; +#else + c = (data >> 24); +#endif + WRITE_CHAR(FLASH_BASE_ADDRESS + offset + 3, c); + while (true) { + /* Reading STATUS Register */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 3, 0x70); + regValue = + READCHAR(FLASH_BASE_ADDRESS + 3); + if ((regValue & 0x80) == 0x80) + break; /* Write operation ended */ + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS + 3, 0x70); + regValue = READCHAR(FLASH_BASE_ADDRESS + 3); + if ((regValue & 0x10) == 0x10) + return false; /* Write failure */ + flashReset(); + return true; + case 2: + if (FLASH_MODE == X16) { /* Case of one X16 bit device */ + FirstData = 0x0010; /* Data for the First Cycle */ + } else { /* if (FLASH_MODE == 8) ==> Case of two X8 bit devices */ + + FirstData = 0x1010; /* Data for the First Cycle */ + } + /* Writing First two Bytes */ + WRITE_SHORT(FLASH_BASE_ADDRESS, FirstData); +#ifdef BE + s = (data >> 16); +#else + s = data; +#endif + WRITE_SHORT(FLASH_BASE_ADDRESS + offset, s); + if (FLASH_MODE == X16) { + data70 = 0x0070; + data80 = 0x0080; + data10 = 0x0010; + } else { /* case of (FLASH_MODE == X8) */ + + data70 = 0x7070; + data80 = 0x8080; + data10 = 0x1010; + } + /* polling on writing action => when done break. */ + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS, data70); + regValue = READSHORT(FLASH_BASE_ADDRESS); + if ((regValue & data80) == data80) + break; + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS, data70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & data10) == data10) + return false; /* Write failure */ + /* Writing Last two Bytes */ + WRITE_SHORT(FLASH_BASE_ADDRESS + 2, FirstData); +#ifdef BE + s = data; +#else + s = (data >> 16); +#endif + WRITE_SHORT(FLASH_BASE_ADDRESS + offset + 2, s); + /* polling on writing action => when done break. */ + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + 2, + data70); + regValue = + READSHORT(FLASH_BASE_ADDRESS + 2); + if ((regValue & data80) == data80) + break; + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS, data70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & data10) == data10) + return false; /* Write failure */ + flashReset(); + return true; + case 4: + case 8: + if (FLASH_MODE == X16) { /* Case of one X16 bit device */ + FirstData = 0x00100010; /* Data for the First Cycle */ + } else { /* (FLASH_MODE == 8) ==> Case of two X8 bit devices */ + + FirstData = 0x10101010; /* Data for the First Cycle */ + } + /* Writing First two Bytes */ + WRITE_WORD(FLASH_BASE_ADDRESS + + offset % FLASH_WIDTH, FirstData); +#ifdef BE + s = (data >> 16); +#else + s = data; +#endif + /* writing the 32-bit data to flash. */ + WRITE_WORD(FLASH_BASE_ADDRESS + offset, data); + if (FLASH_MODE == X16) { + data70 = 0x0070; + data80 = 0x0080; + data10 = 0x0010; + } else { /* (FLASH_MODE == 8) */ + + data70 = 0x7070; + data80 = 0x8080; + data10 = 0x1010; + } + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + + offset % FLASH_WIDTH, data70); + regValue = READSHORT(FLASH_BASE_ADDRESS); + if ((regValue & data80) == data80) + break; + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS, data70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & data10) == data10) + return false; /* Write failure */ + + /* Writing Last two Bytes */ +#ifdef BE + s = data; +#else + s = (data >> 16); +#endif + while (true) { + WRITE_SHORT(FLASH_BASE_ADDRESS + + offset % FLASH_WIDTH + 2, + data70); + regValue = + READSHORT(FLASH_BASE_ADDRESS + + offset % FLASH_WIDTH + 2); + if ((regValue & data80) == data80) + break; + } + /* Reading STATUS Register for Writing Verification */ + WRITE_CHAR(FLASH_BASE_ADDRESS, data70); + regValue = READCHAR(FLASH_BASE_ADDRESS); + if ((regValue & data10) == data10) + return false; /* Write failure */ + + flashReset(); + return true; + default: + flashReset(); + return false; + } + } + flashReset(); + return true; +} + +/******************************************************************** +* flashReadWord - Read 32Bit from the FLASH memory at a given offset +* from the FLASH base address. +* address 0 = 0x00000000 !! +* The function takes care of Big/Little endian conversion +* INPUTS: offset,the offset from the flash`s base address +* RETURNS: data +*********************************************************************/ +unsigned int flashReadWord(unsigned int offset) +{ + unsigned int regValue; + flashReset(); + READ_WORD(FLASH_BASE_ADDRESS + offset, ®Value); + return regValue; +} + +/******************************************************************** +* flashInWhichSector - Returns the sector`s number at which offset is at. +* +* INPUTS: Offset +* RETURNS: Sector number,or 0xffffffff in case the address is out of range or +* flash wasn't initialize. +*********************************************************************/ +unsigned int flashInWhichSector(unsigned int offset) +{ + unsigned int sectorNumber, numberOfDevices; + unsigned int accMemory = 0; + + if ((FLASH_MODE == PURE8) || (FLASH_MODE == X8)) { + numberOfDevices = FLASH_WIDTH; + } else { /* X16 mode */ + + numberOfDevices = FLASH_WIDTH / 2; + } + for (sectorNumber = 0; + sectorNumber < flashTypes[NUMBER_OF_SECTORS]; sectorNumber++) { + accMemory = + accMemory + flashTypes[FIRST_SECTOR_SIZE + + sectorNumber]; + if (offset < accMemory * numberOfDevices * 1024) + return sectorNumber; + } + return 0xffffffff; +} + +/******************************************************************** +* flashGetSectorSize - When given a Valid sector Number returns its Size. +* +* INPUTS: unsigned int sectorNumber. +* RETURNS: Sector size. (if Sector number isn't valid or flash wasn't +* initialize return 0.) +*********************************************************************/ +unsigned int flashGetSectorSize(unsigned int sectorNumber) +{ + if (sectorNumber >= flashTypes[NUMBER_OF_SECTORS]) + return 0; + else { + if (FLASH_MODE != PURE8) + return (flashTypes + [FIRST_SECTOR_SIZE + + sectorNumber] * _1K * (FLASH_WIDTH * 8 / + FLASH_MODE)); + else /* in case of PUR8 */ + return (flashTypes + [FIRST_SECTOR_SIZE + + sectorNumber] * _1K * FLASH_WIDTH); + } +} + +/******************************************************************** +* getFlashSize - Return Total flash size. +* +* INPUTS: N/A. +* RETURNS: Flash size. (If flash wasn't initialize return 0) +*********************************************************************/ +unsigned int flashGetSize() +{ + unsigned int sectorNum; + unsigned int totalSize = 0; + + if (POINTER_TO_FLASH == 0) + return 0; /* case of flash not initialize */ + for (sectorNum = 0; sectorNum < flashTypes[NUMBER_OF_SECTORS]; + sectorNum++) { + totalSize += flashGetSectorSize(sectorNum); + } + return (totalSize); + +} + +/******************************************************************** +* flashGetSectorOffset - Returns sector base address. +* +* INPUTS: unsigned int sectorNum. +* RETURNS: Sector Base Address. +*********************************************************************/ +unsigned int flashGetSectorOffset(unsigned int sectorNum) +{ + unsigned int i; + unsigned int sectorBaseAddress = 0; + unsigned int numOfDevices; + + if (sectorNum > (flashParametrs[NUMBER_OF_SECTORS] - 1)) + return 0xffffffff; + for (i = 0; i < sectorNum; i++) { + sectorBaseAddress = + sectorBaseAddress + flashTypes[FIRST_SECTOR_SIZE + i]; + } + if (FLASH_MODE == X16) + numOfDevices = FLASH_WIDTH * 8 / FLASH_MODE; + else + numOfDevices = FLASH_WIDTH; + return (_1K * sectorBaseAddress * numOfDevices); + +} + +/******************************************************************** +* flashWriteBlock - Write block of chars to flash. +* +* INPUTS: unsigned int offset - flash destination address. +* unsigned int numOfByte - block size. +* unsigned char * blockAddress - block source address. +* RETURNS: Number of Bytes written. +*********************************************************************/ +unsigned int flashWriteBlock(unsigned int offset, unsigned int numOfByte, + unsigned char *blockAddress) +{ + register unsigned int flashWrite; + register unsigned int align; + register unsigned int num; + register unsigned int i; + + if ((offset + numOfByte) > flashGetSize()) + numOfByte = flashGetSize() - offset; /* getting to flash boundary. */ + num = numOfByte; + align = offset % 4; /* alignment toward flash. */ + /* writes chars until the offset toward flash will be align. */ + for (i = align; (i < 4) && (numOfByte > 0) && (align != 0); i++) { + flashWriteChar(offset, blockAddress[0]); + numOfByte--; + offset++; + blockAddress++; + } + while (numOfByte > 3) { +#ifdef LE + flashWrite = blockAddress[0] | (blockAddress[1] << 8) | + (blockAddress[2] << 16) | (blockAddress[3] << 24); +#else + flashWrite = blockAddress[3] | (blockAddress[2] << 8) | + (blockAddress[1] << 16) | (blockAddress[0] << 24); +#endif + if (flashWrite != 0xffffffff) /* for optimization. */ + flashWriteWord(offset, flashWrite); + numOfByte -= 4; + blockAddress += 4; + offset += 4; + } + while (numOfByte > 0) { + flashWriteChar(offset, blockAddress[0]); + numOfByte--; + blockAddress++; + offset++; + } + return num; +} + +/******************************************************************** +* flashReadBlock - Read block of chars from flash. +* +* INPUTS: unsigned int offset - flash source address. +* unsigned int numOfByte - block size. +* unsigned char * blockAddress - block destination address. +* RETURNS: Number of Bytes written. +*********************************************************************/ +unsigned int flashReadBlock(unsigned int offset, unsigned int numOfByte, + unsigned char *blockAddress) +{ + unsigned int i; + for (i = 0; i < numOfByte; i++) { + blockAddress[i] = flashReadChar(offset + i); + } + return numOfByte; +} + +/******************************************************************** +* flashReadChar - read one charecter form given flash offset. +* +* INPUTS: unsigned int offset - required offset to be read from. +* RETURNS: read charecter. +*********************************************************************/ +unsigned char flashReadChar(unsigned int offset) +{ + unsigned char regValue; + + flashReset(); + READ_CHAR(FLASH_BASE_ADDRESS + offset, ®Value); + return regValue; +} + +/******************************************************************** +* flashReadShort - read 16bit form given flash offset. +* +* INPUTS: unsigned int offset - required offset to be read from. +* RETURNS: 16bit data. +*********************************************************************/ +unsigned short flashReadShort(unsigned int offset) +{ + unsigned short regValue; + + flashReset(); + READ_SHORT(FLASH_BASE_ADDRESS + offset, ®Value); + return regValue; +} + +/******************************************************************** +* flashWriteShort - write 16bit data to a given flash offset. +* It reads the whole word 32bit wide, modify the short +* and write back the word. +* +* INPUTS: unsigned int offset - required offset to be write to. +* unsigned short sdata - data to be written. +* RETURNS: true if writting successesed false otherwise. +*********************************************************************/ +bool flashWriteShort(unsigned int offset, unsigned short sdata) +{ + unsigned int align; + unsigned int flashWrite; + unsigned int flashRead; + + align = offset % 4; + if ((align == 1) || (align == 3)) + return false; /* offset misaligned. */ + flashRead = flashReadWord(offset - align); + if (align == 0) +#ifdef BE + flashWrite = (flashRead & 0x0000ffff) | (sdata << 16); +#else + flashWrite = (flashRead & 0xffff0000) | sdata; +#endif + else /* (align == 2) */ +#ifdef BE + flashWrite = (flashRead & 0xffff0000) | sdata; +#else + flashWrite = (flashRead & 0x0000ffff) | (sdata << 16); +#endif + flashWriteWord(offset - align, flashWrite); + return true; + +} + +/******************************************************************** +* flashWriteChar - write one charecter (8 bit) to a given flash offset. +* It reads the whole word 32bit wide, modify the charecter +* and write back the word. +* +* INPUTS: unsigned int offset - required offset to be write to. +* unsigned short sdata - data to be written. +* RETURNS: true if writting successed. +*********************************************************************/ +bool flashWriteChar(unsigned int offset, unsigned char cdata) +{ + unsigned int align; + unsigned int flashWrite; + unsigned int flashRead; + + align = offset % 4; + flashRead = flashReadWord(offset - align); +#ifdef BE + flashWrite = (flashRead & ~(0xff000000 >> (8 * align))) | + (cdata << (8 * (3 - align))); +#else + flashWrite = (flashRead & ~(0xff000000 << (8 * align))) | + (cdata << (8 * align)); +#endif + flashWriteWord(offset - align, flashWrite); + return true; +} + +/******************************************************************** +* flashGetNumOfSectors - write one charecter (8 bit) to a given flash offset. +* It reads the whole word 32bit wide, modify the +* charecter and write back the word. +* +* INPUTS: N/A. +* RETURNS: Number of sectors. +*********************************************************************/ +unsigned int flashGetNumOfSectors(void) +{ + return (flashTypes[NUMBER_OF_SECTORS]); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/galileo_port.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/galileo_port.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/galileo_port.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/galileo_port.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,8 @@ +#define GFP_KERNEL 0 +#define GFP_ATOMIC 1 +#define KERN_ERR "" + +void *kmalloc(unsigned int, int); +void *memset(void *, char, unsigned int); +int memcmp(char *, char *, unsigned int); +void *memcpy(void *to, const void *from, unsigned int); diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/gt64011.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/gt64011.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/gt64011.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/gt64011.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,279 @@ +/* + * gt64011.h: Galileo PCI system controller + * Copyright (c) 1998 Algorithmics Ltd + */ + +#ifdef __ASSEMBLER__ + +/* offsets from base register */ +#define GT64011(x) (x) + +/* device is littleendian, so data may need to be swapped */ +#ifdef GALILEO_PORT +#define htoll(x) ((((x) & 0x00ff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) >> 8) & 0xff00) | \ + (((x) >> 24) & 0x00ff)) +/*#define ltohl(x) htoll(x)*/ +#else +#define htoll(x) (x) +/* #define ltohl(x) (x) */ +#endif + +#else /* !__ASSEMBLER */ + +/* offsets from base pointer, this construct allows optimisation */ +static char *const _gt64011p = (char *) PA_TO_KVA1(GT64011_BASE); + +#define GT64011(x) *(volatile unsigned long *)(_gt64011p + (x)) + +/* device is littleendian, so data may need to be swapped */ +#ifdef GALILEO_PORT +#define htoll(x) ({ \ + unsigned int v = (unsigned int)(x); \ + v = (((v & 0x00ff) << 24) | \ + ((v & 0xff00) << 8) | \ + ((v >> 8) & 0xff00) | \ + ((v >> 24) & 0x00ff)); \ + v; \ + }) +#define ltohl(x) htoll(x) + +#else +asjdsajd +#define htoll(x) (x) +#define ltohl(x) (x) +#endif +#endif /* __ASSEMBLER__ */ +/* CPU configuration */ +#define GT_CPU_CFG GT64011(0x000) +#define GT_CPU_CFG_WriteMode (1<<11) +#define GT_CPU_CFG_Endianess (1<<12) +/* Processor Address Space */ +#define GT_PAS_RAS10LO GT64011(0x008) +#define GT_PAS_RAS10HI GT64011(0x010) +#define GT_PAS_RAS32LO GT64011(0x018) +#define GT_PAS_RAS32HI GT64011(0x020) +#define GT_PAS_CS20LO GT64011(0x028) +#define GT_PAS_CS20HI GT64011(0x030) +#define GT_PAS_CS3BOOTLO GT64011(0x038) +#define GT_PAS_CS3BOOTHI GT64011(0x040) +#define GT_PAS_PCIIOLO GT64011(0x048) +#define GT_PAS_PCIIOHI GT64011(0x050) +#define GT_PAS_PCIMEMLO GT64011(0x058) +#define GT_PAS_PCIMEMHI GT64011(0x060) +#define GT_PAS_INTDEC GT64011(0x068) +#define GT_PAS_BUSERRLO GT64011(0x070) +#define GT_PAS_PCIMEM1LO GT64011(0x080) +#define GT_PAS_PCIMEM1HI GT64011(0x088) +#define GT_PAS_LOMASK_Low 0x7ff +#define GT_PAS_LOSHIFT_Low 0 +#define GT_PAS_HIMASK_High 0x07f +#define GT_PAS_HISHIFT_High 0 +/* DRAM and Device Address Space */ +#define GT_DDAS_RAS0LO GT64011(0x400) +#define GT_DDAS_RAS0HI GT64011(0x404) +#define GT_DDAS_RAS1LO GT64011(0x408) +#define GT_DDAS_RAS1HI GT64011(0x40c) +#define GT_DDAS_RAS2LO GT64011(0x410) +#define GT_DDAS_RAS2HI GT64011(0x414) +#define GT_DDAS_RAS3LO GT64011(0x418) +#define GT_DDAS_RAS3HI GT64011(0x41c) +#define GT_DDAS_CS0LO GT64011(0x420) +#define GT_DDAS_CS0HI GT64011(0x424) +#define GT_DDAS_CS1LO GT64011(0x428) +#define GT_DDAS_CS1HI GT64011(0x42c) +#define GT_DDAS_CS2LO GT64011(0x430) +#define GT_DDAS_CS2HI GT64011(0x434) +#define GT_DDAS_CS3LO GT64011(0x438) +#define GT_DDAS_CS3HI GT64011(0x43c) +#define GT_DDAS_BOOTCSLO GT64011(0x440) +#define GT_DDAS_BOOTCSHI GT64011(0x444) +#define GT_DDAS_ERROR GT64011(0x470) +#define GT_DDAS_LOMASK_Low 0xff +#define GT_DDAS_LOSHIFT_Low 0 +#define GT_DDAS_HIMASK_High 0xff +#define GT_DDAS_HISHIFT_High 0 +/* DRAM Configuration */ +#define GT_DRAM_CFG GT64011(0x448) +#define GT_DRAM_CFG_RefIntCntMASK 0x00003fff +#define GT_DRAM_CFG_RefIntCntSHIFT 0 +#define GT_DRAM_CFG_RefIntCnt(x) (((x)< +#include + + .text +NESTED(startup, 16, sp) + .set noreorder + + jal decompress_kernel + nop + + jal kernel_location_start+0x584 + nop + + END(startup) diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.script.gal Sat Mar 30 22:55:26 2002 @@ -0,0 +1,19 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH(mips) +ENTRY(startup) +SECTIONS +{ + kernel_location_start = 0x80100000; + . = 0x80400000; + .text : { + *(.text) + } + .bss : { + *(.bss) + } + .data :{ + *(.data) + } + malloc_start = .; +} + diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash Sat Mar 30 22:55:26 2002 @@ -0,0 +1,29 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH(mips) +ENTRY(sbdreset) + +SECTIONS +{ + . = 0xBFC00000; + .got : {*(.got)} + .reset : { + sbdreset = ABSOLUTE(.); + sbdreset_evb64120A.o + evb64120A_Setup.o /* <-- Note: contains xfer.c contents as well.. */ + pci_etherboot.o + memory.o + pci.o + } + kernel_location_start = 0x80100000; + . = 0x80400000; + .text : { + *(.text) + } + .bss : { + *(.bss) + } + .data :{ + *(.data) + } + malloc_start = .; +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2 linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2 --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2 Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.Flash2 Sat Mar 30 22:55:26 2002 @@ -0,0 +1,24 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH(mips) +ENTRY(XferToRam) + +SECTIONS +{ + . = 0xBF000000; + .got : {*(.got)} + .reset : { + xfer.o + } + kernel_location_start = 0x80100000; + . = 0x80400000; + .text : { + *(.text) + } + .bss : { + *(.bss) + } + .data :{ + *(.data) + } + malloc_start = .; +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.burner linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.burner --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.burner Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ld.sys.big.burner Sat Mar 30 22:55:26 2002 @@ -0,0 +1,11 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH(mips) +ENTRY(main) + +SECTIONS +{ + . = 0xA0400000; + .text : {*(.text)} + .data : {*(.data)} + .bss : {*(.bss)} +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/load.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/load.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/load.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/load.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,244 @@ + +/* control character used for download */ +#define ETX CNTRL('c') +#define ACK CNTRL('f') +#define NAK CNTRL('u') +#define XON CNTRL('q') +#define XOFF CNTRL('s') + +unsigned int csum; +unsigned int dl_entry; + +static const unsigned char hextab[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, + 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, + 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, +}; + + +unsigned char ascii_to_bin(unsigned char c) +{ + return hextab[c]; +} + +unsigned char read_char_direct(void) +{ + unsigned char c, *cp; + cp = (unsigned char *) 0xbd000020; + while (1) { + if (*(cp + 0x14) & 0x01) { + c = (volatile unsigned char) *cp; + return c; + } + cp++; + cp--; + } +} + +unsigned char get_pair(void) +{ + unsigned char byte; + + byte = ascii_to_bin(read_char_direct()) << 4; + byte |= ascii_to_bin(read_char_direct()); + csum += byte; + return (byte); +} + + +void serial_putc(int ch) +{ + unsigned long temp; + for (temp = 0; temp < 1000; temp++) { + } + *(char *) 0xbd000020 = (char) ch; +} + + +int inline serial_getc(void) +{ + return read_char_direct(); +} + +int serial_ischar(void) +{ + + unsigned char c, *cp; + unsigned count; + cp = (unsigned char *) 0xbd000020; + count = 0; + while (count != 100) { + if (*(cp + 0x14) & 0x01) { + c = (volatile unsigned char) *cp; + return c; + } + cp++; + cp--; + count++; + } + return 0; +} + +int serial_init(void) +{ + return 0; +} + + +int galileo_dl(void) +{ +#define display_char '.' +#define display_error 'E' +#define display_error_bad_7 '7' +#define display_error_unknown 'U' +#define display_error_length 'L' + + register int length, address, save_csum; + int i, first, done, eof, reccount, type, client_pc; + int src, dbl_length; + unsigned char *buffptr, databuff[258], tempo; + register int display_counter, chunks, leftovers, putter, + bytes_per_chunk; + display_counter = 0; + bytes_per_chunk = 16; + csum = 0; + + reccount = 1; + for (first = 1, done = 0; !done; first = 0, reccount++) { + while (read_char_direct() != 'S') + continue; + csum = 0; + type = read_char_direct(); + length = get_pair(); + if (length < 0 || length >= 256) { + *(char *) 0xbd000020 = display_error_length; + // *(char*)0xbd00000c = display_error_length; + return 0; + } + length--; + switch (type) { + case '0': + while (length-- > 0) + get_pair(); + break; + case '3': + address = 0; + for (i = 0; i < 4; i++) { + address <<= 8; + address |= get_pair(); + length--; + } + if (address == -1) { + eof = 1; + continue; + } + buffptr = &databuff[0]; + dbl_length = length << 1; + chunks = dbl_length / bytes_per_chunk; + leftovers = dbl_length % bytes_per_chunk; + putter = bytes_per_chunk >> 1; + while (chunks--) { + for (i = 0; i < bytes_per_chunk; i++) + databuff[i] = read_char_direct(); + src = i = 0; + while (i++ < putter) { + tempo = + (ascii_to_bin(databuff[src++]) + << 4) | + ascii_to_bin(databuff[src++]); + csum += tempo; + *(char *) address++ = tempo; + } + } + if (leftovers) { + putter = leftovers / 2; + for (i = 0; i < leftovers; i++) + databuff[i] = read_char_direct(); + src = i = 0; + while (i++ < putter) { + tempo = + (ascii_to_bin(databuff[src++]) + << 4) | + ascii_to_bin(databuff[src++]); + csum += tempo; + *(char *) address++ = tempo; + } + } + break; + + case '7': + address = 0; + for (i = 0; i < 4; i++) { + address <<= 8; + address |= get_pair(); + length--; + } + if (address == -1) { + eof = 1; + continue; + } + client_pc = address; + if (length) { + *(char *) 0xbd000020 = display_error_bad_7; + // *(char*)0xbd00000c = display_error_bad_7; + } + + done = 1; + break; + + default: + *(char *) 0xbd000020 = display_error_unknown; + // *(char*)0xbd00000c = display_error_unknown; + + break; + } + save_csum = (~csum) & 0xff; + if ((csum = get_pair()) < 0) { + eof = 1; + continue; + } + if (csum != save_csum) { + *(char *) 0xbd000020 = display_error; + // *(char*)0xbd00000c = display_error; + } else { + + if (display_counter % 50 == 0) { + *(char *) 0xbd000020 = display_char; + display_counter = 0; + } + display_counter++; + + } + } + --reccount; + dl_entry = client_pc; + return dl_entry; /* Success */ +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/meminit.S linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/meminit.S --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/meminit.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/meminit.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,187 @@ +/* + * Define BUSWIDTH to usually be real buswidth X 2 (i.e assuming + * 2-way interleaving). This is so that the test pattern and + * inverted pattern are written to the same bank of memory, which + * prevents us reading back data sitting in the dram buffers and + * getting a false match. + */ + +#ifndef BUSWIDTH +# if #cpu(r3000) || #cpu(r4300) || #cpu(r4650) +# define BUSWIDTH 8 /* 32 bit memory, bank interleaved */ +# elif #cpu(r4000) +# define BUSWIDTH 16 /* 64 bit memory, bank interleaved */ +# endif +#endif + +#ifndef RAM_BASE +#define RAM_BASE KSEG1_BASE +#endif + +#ifndef MEMSTART +#define MEMSTART 0x0 /* start of physical memory */ +#endif + +#ifndef MEMINCR +# define MEMINCR 0x10000 /* work up in 64Kb increments */ +#endif + +SLEAF(size_mem) + mfc0 t8,C0_STATUS +#if #cpu(r4000) + /* disable cache and memory parity checking */ + or t0,t8,SR_DE + mtc0 t0,C0_STATUS +#endif + + li t0,RAM_BASE+MEMSTART # start at bottom of phys mem + move t1,t0 # remember start address + li t2,0xaa55aa55 # pattern + not t3,t2 # ~pattern + + move t7,k0 + la t4,.fail # bus error exception catcher + addu k0,t4,s8 # RELOC + + /* fill first 64Kb with zero (for cache init) */ + move t4,t0 + li t5,0x10000 +1: sw zero,0(t4) + sw zero,4(t4) + sw zero,8(t4) + sw zero,12(t4) + subu t5,16 + addu t4,16 + bnez t5,1b + +.loop: + addu t0,MEMINCR + move t4,t0 + + /* store pattern in bank 0, line 0 */ + sw t2,0(t4) + addu t4,4 + +#if BUSWIDTH > 4 + /* fill remainder of line with zeros */ + li t5,BUSWIDTH-4 +1: sw zero,0(t4) + subu t5,4 + addu t4,4 + bnez t5,1b +#endif + + /* store inverse pattern in bank 0, line 1 */ + sw t3,0(t4) + addu t4,4 + +#if BUSWIDTH > 4 + /* fill remainder of line with zeros */ + li t5,BUSWIDTH-4 +1: sw zero,0(t4) + subu t5,4 + addu t4,4 + bnez t5,1b +#endif + + /* defeat write buffering */ +#if #cpu(r4000) + sync +#else + lw zero,-4(t4) +#endif + + lw t4,0(t0) # read first word of line + lw t5,0(t1) # read start of memory (should be zero) + bne t4,t2,.fail # this line wrong? + beq t5,zero,.loop # start of mem overwritten? + +.fail: + move k0,t7 # clear exception catcher + + /* restore Status register */ + mtc0 t8,C0_STATUS + + /* return top of memory offset (normally == size) */ + subu v0,t0,RAM_BASE + j ra +END(size_mem) + + +/* + * We must often initialise memory so that it has good parity/ecc, + * and this must be done before the caches are used. + */ + +/* + clear_mem (size) + - clear memory from RAM_BASE+MEMSTART to RAM_BASE+MEMSTART+size + clear_mem_range (size, start) + - clear memory from start to start+size +*/ + +SLEAF(clear_mem) + li a1,RAM_BASE+MEMSTART # start at bottom of phys mem +clear_mem_range: + beqz a0,9f + addu a0,a1 # end of memory + + /* XXX should run cached, but caches may not be initialised yet */ + .set noreorder +#if __mips >= 3 +1: sd zero,0(a1) + sd zero,8(a1) + sd zero,16(a1) + sd zero,24(a1) + sd zero,32(a1) + sd zero,40(a1) + sd zero,48(a1) + addu a1,64 + bne a1,a0,1b + sd zero,-8(a1) # BDSLOT +#else +1: sw zero,0(a1) + sw zero,4(a1) + sw zero,8(a1) + sw zero,12(a1) + sw zero,16(a1) + sw zero,20(a1) + sw zero,24(a1) + sw zero,28(a1) + sw zero,32(a1) + sw zero,36(a1) + sw zero,40(a1) + sw zero,44(a1) + sw zero,48(a1) + sw zero,52(a1) + sw zero,56(a1) + addu a1,64 + bne a1,a0,1b + sw zero,-4(a1) # BDSLOT +#endif + .set reorder + +9: j ra +END(clear_mem) + + +SLEAF(init_tlb) + /* initialise tlb */ + mtc0 zero,C0_TLBLO0 /* tlblo0 = invalid */ + mtc0 zero,C0_TLBLO1 /* tlblo1 = invalid */ + mtc0 zero,C0_PGMASK + li t8,K1BASE /* tlbhi = impossible vpn */ + li t9,(NTLBENTRIES-1) /* index */ + + .set noreorder + nop +1: mtc0 t8,C0_TLBHI + mtc0 t9,C0_INX + addu t8,0x2000 /* inc vpn */ + tlbwi + bnez t9,1b + subu t9,1 # BDSLOT + .set reorder + + j ra +END(init_tlb) diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/memory.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/memory.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/memory.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/memory.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,593 @@ +/* Memory.c - Memory mappings and remapping functions */ + +/* Copyright - Galileo technology. */ + +/* +DESCRIPTION +This file contains function which gives the user the ability to remap the +SDRAM memory and devices windows, please pay attention to overlapping windows +since the function do not take care of that for you. +When remapping the SDRAM or devices memory space pay attention to the PCI +mappings and make sure to coordinate between the two interfaces!!! +*/ + +/* includes */ + +#ifdef __linux__ +#include +#include +#else +#include "Core.h" +#include "Memory.h" +#endif + +/******************************************************************** +* getMemoryBankBaseAddress - Extract the base address of a memory bank +* - If the memory bank size is 0 then this base address has no meaning !!! +* +* INPUTS: MEMORY_BANK bank - SDRAM Bank number. +* OUTPUT: N/A +* RETURNS: Memory bank base address. +*********************************************************************/ +unsigned int getMemoryBankBaseAddress(MEMORY_BANK bank) +{ + unsigned int base, regBase; + GT_REG_READ((SCS_1_0_LOW_DECODE_ADDRESS + (bank / 2) * 0x10), + &base); + base = base << 21; + GT_REG_READ((SCS_0_LOW_DECODE_ADDRESS + bank * 8), ®Base); + base = base | (regBase << 20); + return base; +} + +/******************************************************************** +* getDeviceBaseAddress - Extract the base address of a device. +* - If the device size is 0 then this base address has no meaning!!! +* +* INPUT: DEVICE device - Bank number. +* OUTPUT: N/A +* RETURNS: Device base address. +*********************************************************************/ +unsigned int getDeviceBaseAddress(DEVICE device) +{ + unsigned int base, regBase; + GT_REG_READ((CS_2_0_LOW_DECODE_ADDRESS + (device / 3) * 0x10), + &base); + base = base << 21; + GT_REG_READ((CS_0_LOW_DECODE_ADDRESS + device * 0x8), ®Base); + base = base | (regBase << 20); + return base; +} + +/******************************************************************** +* getMemoryBankSize - Extract the size of a memory bank. +* +* INPUT: MEMORY_BANK bank - Bank number +* OUTPUT: N/A +* RETURNS: Memory bank size. +*********************************************************************/ +unsigned int getMemoryBankSize(MEMORY_BANK bank) +{ + unsigned int size, base, value; + base = getMemoryBankBaseAddress(bank); + GT_REG_READ((SCS_0_HIGH_DECODE_ADDRESS + bank * 8), &size); + size = ((size + 1) << 20) - (base & 0x0fffffff); + GT_REG_READ((SCS_0_HIGH_DECODE_ADDRESS + bank * 8), &value); + if (value == 0) + return 0; + else + return size; +} + +/******************************************************************** +* getDeviceSize - Extract the size of a device memory space +* +* INPUT: DEVICE device - Device number +* OUTPUT: N/A +* RETURNS: Size of a device memory space. +*********************************************************************/ +unsigned int getDeviceSize(DEVICE device) +{ + unsigned int size, base, value; + base = getDeviceBaseAddress(device); + GT_REG_READ((CS_0_HIGH_DECODE_ADDRESS + device * 8), &size); + size = ((size + 1) << 20) - (base & 0x0fffffff); + GT_REG_READ((CS_0_HIGH_DECODE_ADDRESS + device * 8), &value); + if ((value + 1) == 0) + return 0; + else + return size; +} + +/******************************************************************** +* getDeviceWidth - A device can be with: 1,2,4 or 8 Bytes data width. +* The width is determine in registers: 'Device Parameters' +* registers (0x45c, 0x460, 0x464, 0x468, 0x46c - for each device. +* at bits: [21:20]. +* +* INPUT: DEVICE device - Device number +* OUTPUT: N/A +* RETURNS: Device width in Bytes (1,2,4, or 8), 0 if error had occurred. +*********************************************************************/ +unsigned int getDeviceWidth(DEVICE device) +{ + unsigned int width; + unsigned int regValue; + + GT_REG_READ(DEVICE_BANK0PARAMETERS + device * 4, ®Value); + width = (regValue & 0x00300000) >> 20; + switch (width) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 4; + case 3: + return 8; + default: + return 0; + } +} + +/******************************************************************** +* mapMemoryBanks0and1 - Sets new bases and boundaries for memory banks 0 and 1 +* - Pay attention to the PCI mappings and make sure to +* coordinate between the two interfaces!!! +* - It is the programmer`s responsibility to make sure +* there are no conflicts with other memory spaces!!! +* - If a bank needs to be closed , give it a 0 length +* +* +* INPUTS: unsigned int bank0Base - required bank 0 base address. +* unsigned int bank0Length - required bank 0 size. +* unsigned int bank1Base - required bank 1 base address. +* unsigned int bank1Length - required bank 1 size. +* RETURNS: true on success, false on failure or if one of the parameters is +* erroneous. +*********************************************************************/ +bool mapMemoryBanks0and1(unsigned int bank0Base, unsigned int bank0Length, + unsigned int bank1Base, unsigned int bank1Length) +{ + unsigned int mainBank0Top = bank0Base + bank0Length; + unsigned int mainBank1Top = bank1Base + bank1Length; + unsigned int memBank0Base, bank0Top; + unsigned int memBank1Base, bank1Top; + + if (bank0Base <= bank1Base) { + if ((bank0Base + bank0Length) > bank1Base) + return false; + } else { + if ((bank1Base + bank1Length) > bank0Base) + return false; + } + + if (bank0Length == 0) + mainBank0Top++; + if (bank1Length == 0) + mainBank1Top++; + + memBank0Base = ((unsigned int) (bank0Base & 0x0fffffff)) >> 20; + bank0Top = ((unsigned int) (mainBank0Top & 0x0fffffff)) >> 20; + memBank1Base = ((unsigned int) (bank1Base & 0x0fffffff)) >> 20; + bank1Top = ((unsigned int) (mainBank1Top & 0x0fffffff)) >> 20; + + if (mainBank1Top > mainBank0Top) { + bank0Base >>= 21; + mainBank0Top = + ((unsigned int) (mainBank1Top & 0x0fffffff)) >> 21; + } else { + bank0Base = bank1Base >> 21; + mainBank0Top = + ((unsigned int) (mainBank0Top & 0x0fffffff)) >> 21; + } + GT_REG_WRITE(SCS_1_0_LOW_DECODE_ADDRESS, bank0Base); + if ((bank0Length + bank1Length) != 0) { + GT_REG_WRITE(SCS_1_0_HIGH_DECODE_ADDRESS, + mainBank0Top - 1); + } else { + GT_REG_WRITE(SCS_1_0_HIGH_DECODE_ADDRESS, 0x0); + } + if (bank1Length != 0) { + GT_REG_WRITE(SCS_1_HIGH_DECODE_ADDRESS, bank1Top - 1); + } else { + GT_REG_WRITE(SCS_1_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(SCS_1_LOW_DECODE_ADDRESS, memBank1Base); + if (bank0Length != 0) { + GT_REG_WRITE(SCS_0_HIGH_DECODE_ADDRESS, bank0Top - 1); + } else { + GT_REG_WRITE(SCS_0_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(SCS_0_LOW_DECODE_ADDRESS, memBank0Base); + return true; +} + +/******************************************************************** +* mapMemoryBanks2and3 - Sets new bases and boundaries for memory banks 2 and 3 +* - Pay attention to the PCI mappings and make sure to +* coordinate between the two interfaces!!! +* - It`s the programmer`s responsibility to make sure there +* are no conflicts with other memory spaces!!! +* - If a bank needs to be closed , give it a 0 length. +* +* +* INPUTS: unsigned int bank2Base - required bank 2 base address. +* unsigned int bank2Length - required bank 2 size. +* unsigned int bank3Base - required bank 3 base address. +* unsigned int bank3Length - required bank 3 size. +* RETURNS: true on success, false on failure or if one of the parameters is +* erroneous. +*********************************************************************/ +bool mapMemoryBanks2and3(unsigned int bank2Base, unsigned int bank2Length, + unsigned int bank3Base, unsigned int bank3Length) +{ + unsigned int mainBank2Top = + (unsigned int) (bank2Base + bank2Length); + unsigned int mainBank3Top = + (unsigned int) (bank3Base + bank3Length); + unsigned int memBank2Base, bank2Top; + unsigned int memBank3Base, bank3Top; + + if (bank2Base <= bank3Base) { + if ((bank2Base + bank2Length) > bank3Base) + return false; + } else { + if ((bank3Base + bank3Length) > bank2Base) + return false; + } + if (bank2Length == 0) + mainBank2Top++; + if (bank3Length == 0) + mainBank3Top++; + + memBank2Base = ((unsigned int) (bank2Base & 0x0fffffff)) >> 20; + bank2Top = ((unsigned int) (mainBank2Top & 0x0fffffff)) >> 20; + memBank3Base = ((unsigned int) (bank3Base & 0x0fffffff)) >> 20; + bank3Top = ((unsigned int) (mainBank3Top & 0x0fffffff)) >> 20; + + if (mainBank3Top > mainBank2Top) { + bank2Base >>= 21; + mainBank2Top = + ((unsigned int) (mainBank3Top & 0x0fffffff)) >> 21; + } else { + bank2Base = bank3Base >> 21; + mainBank2Top = + ((unsigned int) (mainBank2Top & 0x0fffffff)) >> 21; + } + GT_REG_WRITE(SCS_3_2_LOW_DECODE_ADDRESS, bank2Base); + if ((bank2Length + bank3Length) != 0) { + GT_REG_WRITE(SCS_3_2_HIGH_DECODE_ADDRESS, + mainBank2Top - 1); + } else { + GT_REG_WRITE(SCS_3_2_HIGH_DECODE_ADDRESS, 0x0); + } + if (bank3Length != 0) { + GT_REG_WRITE(SCS_3_HIGH_DECODE_ADDRESS, bank3Top - 1); + } else { + GT_REG_WRITE(SCS_3_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(SCS_3_LOW_DECODE_ADDRESS, memBank3Base); + if (bank2Length != 0) { + GT_REG_WRITE(SCS_2_HIGH_DECODE_ADDRESS, bank2Top - 1); + } else { + GT_REG_WRITE(SCS_2_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(SCS_2_LOW_DECODE_ADDRESS, memBank2Base); + return true; +} + +/******************************************************************** +* mapDevices0_1and2MemorySpace - Sets new bases and boundaries for devices 0,1 +* and 2 +* - Pay attention to the PCI mappings and make sure to +* coordinate between the two interfaces!!! +* - It`s the programmer`s responsibility to make sure there +* are no conflicts with other memory spaces!!! +* - If a device needs to be closed , give it a 0 length +* +* +* INPUTS: unsigned int device0Base - required cs_0 base address. +* unsigned int device0Length - required cs_0 size. +* unsigned int device1Base - required cs_1 base address. +* unsigned int device1Length - required cs_0 size. +* unsigned int device2Base - required cs_2 base address. +* unsigned int device2Length - required cs_2 size. +* RETURNS: true on success, false on failure or if one of the parameters is +* erroneous. +*********************************************************************/ +bool mapDevices0_1and2MemorySpace(unsigned int device0Base, + unsigned int device0Length, + unsigned int device1Base, + unsigned int device1Length, + unsigned int device2Base, + unsigned int device2Length) +{ + unsigned int deviceBank0Top = + (unsigned int) (device0Base + device0Length); + unsigned int deviceBank1Top = + (unsigned int) (device1Base + device1Length); + unsigned int deviceBank2Top = + (unsigned int) (device2Base + device2Length); + unsigned int device0BaseTemp = 0, device0TopTemp = 0; + unsigned int bank0Base, bank0Top; + unsigned int bank1Base, bank1Top; + unsigned int bank2Base, bank2Top; + bank0Base = ((unsigned int) (device0Base & 0x0fffffff)) >> 20; + bank0Top = ((unsigned int) (deviceBank0Top & 0x0fffffff)) >> 20; + bank1Base = ((unsigned int) (device1Base & 0x0fffffff)) >> 20; + bank1Top = ((unsigned int) (deviceBank1Top & 0x0fffffff)) >> 20; + bank2Base = ((unsigned int) (device2Base & 0x0fffffff)) >> 20; + bank2Top = ((unsigned int) (deviceBank2Top & 0x0fffffff)) >> 20; + + if (device0Length == 0) + deviceBank0Top++; + if (device1Length == 0) + deviceBank1Top++; + if (device2Length == 0) + deviceBank2Top++; + + if (device0Base <= device1Base && device0Base <= device2Base) { + if ((device0Base + device0Length) > device1Base || \ + (device0Base + device0Length) > device2Base) + return false; + if (device1Base <= device2Base) { + if ((device1Base + device1Length) > device2Base) + return false; + } else { + if ((device2Base + device2Length) > device1Base) + return false; + } + } + + if (device1Base <= device0Base && device1Base <= device2Base) { + if ((device1Base + device1Length) > device0Base || + (device1Base + device1Length) > device2Base) + return false; + if (device0Base <= device2Base) { + if ((device0Base + device0Length) > device2Base) + return false; + } else { + if ((device2Base + device2Length) > device0Base) + return false; + } + } + + if (device2Base <= device1Base && device2Base <= device0Base) { + if ((device2Base + device2Length) > device1Base || + (device2Base + device2Length) > device0Base) + return false; + if (device0Base <= device1Base) { + if ((device0Base + device0Length) > device1Base) + return false; + } else { + if ((device1Base + device1Length) > device0Base) + return false; + } + } + + if ((deviceBank2Top > deviceBank1Top) && (deviceBank1Top > + deviceBank0Top)) { + device0BaseTemp = device0Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank2Top & 0x0fffffff)) >> 21; + } + if ((deviceBank2Top > deviceBank0Top) + && (deviceBank0Top > deviceBank1Top)) { + device0BaseTemp = device1Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank2Top & 0x0fffffff)) >> 21; + } + if ((deviceBank1Top > deviceBank2Top) + && (deviceBank2Top > deviceBank0Top)) { + device0BaseTemp = device0Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank1Top & 0x0fffffff)) >> 21; + } + if ((deviceBank1Top > deviceBank0Top) + && (deviceBank0Top > deviceBank2Top)) { + device0BaseTemp = device2Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank1Top & 0x0fffffff)) >> 21; + } + if ((deviceBank0Top > deviceBank2Top) + && (deviceBank2Top > deviceBank1Top)) { + device0BaseTemp = device1Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank0Top & 0x0fffffff)) >> 21; + } + if ((deviceBank0Top > deviceBank1Top) + && (deviceBank1Top > deviceBank2Top)) { + device0BaseTemp = device2Base >> 21; + device0TopTemp = + ((unsigned int) (deviceBank0Top & 0x0fffffff)) >> 21; + } + GT_REG_WRITE(CS_2_0_LOW_DECODE_ADDRESS, device0BaseTemp); + if ((device0Length + device1Length + device2Length) != 0) { + GT_REG_WRITE(CS_2_0_HIGH_DECODE_ADDRESS, + device0TopTemp - 1); + } else { + GT_REG_WRITE(CS_2_0_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(CS_0_LOW_DECODE_ADDRESS, bank0Base); + if (device0Length != 0) { + GT_REG_WRITE(CS_0_HIGH_DECODE_ADDRESS, bank0Top - 1); + } else { + GT_REG_WRITE(CS_0_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(CS_1_LOW_DECODE_ADDRESS, bank1Base); + if (device1Length != 0) { + GT_REG_WRITE(CS_1_HIGH_DECODE_ADDRESS, bank1Top - 1); + } else { + GT_REG_WRITE(CS_1_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(CS_2_LOW_DECODE_ADDRESS, bank2Base); + if (device2Length != 0) { + GT_REG_WRITE(CS_2_HIGH_DECODE_ADDRESS, bank2Top - 1); + } else { + GT_REG_WRITE(CS_2_HIGH_DECODE_ADDRESS, 0x0); + } + return true; +} + +/******************************************************************** +* mapDevices3andBootMemorySpace - Sets new bases and boundaries for devices: +* 3 and boot +* - Pay attention to the PCI mappings and make sure to +* coordinate between the two interfaces!!! +* - It is the programmer`s responsibility to make sure +* there are no conflicts with other memory spaces!!! +* - If a device needs to be closed , give it a 0 length. +* +* INPUTS: base and length of device 3and boot +* RETURNS: true on success, false on failure +*********************************************************************/ +bool mapDevices3andBootMemorySpace(unsigned int device3Base, + unsigned int device3Length, + unsigned int bootDeviceBase, + unsigned int bootDeviceLength) +{ + unsigned int deviceBank3Top = + (unsigned int) (device3Base + device3Length); + unsigned int deviceBankBootTop = + (unsigned int) (bootDeviceBase + bootDeviceLength); + unsigned int bank3Base, bank3Top; + unsigned int bank4Base, bank4Top; + unsigned int Device1Base, Device1Top; + + bank3Top = ((unsigned int) (deviceBank3Top & 0x0fffffff)) >> 20; + bank4Top = ((unsigned int) (deviceBankBootTop & 0x0fffffff)) >> 20; + bank3Base = ((unsigned int) (device3Base & 0x0fffffff)) >> 20; + bank4Base = ((unsigned int) (bootDeviceBase & 0x0fffffff)) >> 20; + + if (device3Base <= bootDeviceBase) { + if (deviceBank3Top > bootDeviceBase) + return false; + } else { + if (deviceBankBootTop > device3Base) + return false; + } + + if (deviceBankBootTop > deviceBank3Top) { + Device1Base = device3Base >> 21; + Device1Top = + ((unsigned int) (deviceBankBootTop & 0x0fffffff)) >> + 21; + } else { + Device1Base = bootDeviceBase >> 21; + Device1Top = + ((unsigned int) (deviceBank3Top & 0x0fffffff)) >> 21; + } + GT_REG_WRITE(CS_3_BOOTCS_LOW_DECODE_ADDRESS, Device1Base); + if ((device3Length + bootDeviceLength) != 0) { + GT_REG_WRITE(CS_3_BOOTCS_HIGH_DECODE_ADDRESS, + Device1Top - 1); + } else { + GT_REG_WRITE(CS_3_BOOTCS_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(CS_3_LOW_DECODE_ADDRESS, bank3Base); + if (device3Length != 0) { + GT_REG_WRITE(CS_3_HIGH_DECODE_ADDRESS, bank3Top - 1); + } else { + GT_REG_WRITE(CS_3_HIGH_DECODE_ADDRESS, 0x0); + } + GT_REG_WRITE(BOOTCS_LOW_DECODE_ADDRESS, bank4Base); + if (bootDeviceLength != 0) { + GT_REG_WRITE(BOOTCS_HIGH_DECODE_ADDRESS, bank4Top - 1); + } else { + GT_REG_WRITE(BOOTCS_HIGH_DECODE_ADDRESS, 0x0); + } + return true; +} + +/******************************************************************** +* modifyDeviceParameters - This function can be used to modify a device`s +* parameters. +* - Be advised to check the spec before modifying them. +* Inputs: +* Returns: false if one of the parameters is erroneous,true otherwise. +*********************************************************************/ +bool modifyDeviceParameters(DEVICE device, unsigned int turnOff, + unsigned int accToFirst, + unsigned int accToNext, unsigned int aleToWr, + unsigned int wrActive, unsigned int wrHigh, + unsigned int width, bool paritySupport) +{ + unsigned int data, oldValue; + + if ((turnOff > 0x7 && turnOff != DONT_MODIFY) + || (accToFirst > 0xf && accToFirst != DONT_MODIFY) + || (accToNext > 0xf && accToNext != DONT_MODIFY) + || (aleToWr > 0x7 && aleToWr != DONT_MODIFY) + || (wrActive > 0x7 && wrActive != DONT_MODIFY) + || (wrHigh > 0x7 && wrHigh != DONT_MODIFY)) { + return false; + } + + GT_REG_READ((DEVICE_BANK0PARAMETERS + device * 4), &oldValue); + if (turnOff == DONT_MODIFY) + turnOff = oldValue & 0x00000007; + else + turnOff = turnOff; + + if (accToFirst == DONT_MODIFY) + accToFirst = oldValue & 0x00000078; + else + accToFirst = accToFirst << 3; + + if (accToNext == DONT_MODIFY) + accToNext = oldValue & 0x00000780; + else + accToNext = accToNext << 7; + + if (aleToWr == DONT_MODIFY) + aleToWr = oldValue & 0x00003800; + else + aleToWr = aleToWr << 11; + + if (wrActive == DONT_MODIFY) + wrActive = oldValue & 0x0001c000; + else + wrActive = wrActive << 14; + + if (wrHigh == DONT_MODIFY) + wrHigh = oldValue & 0x000e0000; + else + wrHigh = wrHigh << 17; + + data = + turnOff | accToFirst | accToNext | aleToWr | wrActive | wrHigh; + switch (width) { + case _8BIT: + break; + case _16BIT: + data = data | _16BIT; + break; + case _32BIT: + data = data | _32BIT; + break; + case _64BIT: + data = data | _64BIT; + break; + default: + return false; + } + if (paritySupport == true) + data = data | PARITY_SUPPORT; + GT_REG_WRITE(DEVICE_BANK0PARAMETERS + device * 4, data); + return true; +} + +/******************************************************************** +* remapAddress - This fubction used for address remapping +* Inputs: - regOffset: remap register +* remapHeader : remapped address +* Returns: false if one of the parameters is erroneous,true otherwise. +*********************************************************************/ +bool remapAddress(unsigned int remapReg, unsigned int remapValue) +{ + unsigned int valueForReg; + valueForReg = (remapValue & 0xffe00000) >> 21; + GT_REG_WRITE(remapReg, valueForReg); + return true; +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/misc.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/misc.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/misc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/misc.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,313 @@ +/* + * arch/mips/galileo/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * + * Modified by RidgeRun Inc. + */ + +#include +#include +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#define channel 1 + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +void variable_init(); +static void puts(const char *); + +void int2hex(int i) +{ + int tth, th, h, t, d; + + if (i > 99999) { + serial_putc(channel, "Error - int2hex outofbounds"); + return; + } + + tth = (i) / 10000; + th = (i - (tth * 10000)) / 1000; + h = (i - ((tth * 10000) + (th * 1000))) / 100; + t = (i - ((tth * 10000) + (th * 1000) + (h * 100))) / 10; + d = (i - ((tth * 10000) + (th * 1000) + (h * 100) + (t * 10))); + serial_putc(channel, tth + '0'); + serial_putc(channel, th + '0'); + serial_putc(channel, h + '0'); + serial_putc(channel, t + '0'); + serial_putc(channel, d + '0'); +} + +int checksum; +int byte_count; +static unsigned char *input_data; + +static int printCnt = 0; + +int get_byte() +{ + unsigned char c = (inptr < insize ? inbuf[inptr++] : fill_inbuf()); + byte_count++; + checksum += c; + + // if (printCnt++ < 150) + // { + // puts("\n"); + // puts("byte count = "); + // int2hex(byte_count & 0xff); + // puts(" byte val = "); + // int2hex(c); + // puts(" checksum = "); + // int2hex(checksum & 0xff); + // puts("\n"); + // } + return c; +} + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +/* + * This is set up by the setup-routine at boot-time + */ + + +#define STACK_SIZE (4096) +long user_stack[STACK_SIZE]; +long *stack_start = &user_stack[STACK_SIZE]; + +extern int linux_compressed_start; +extern int linux_compressed_size; +extern int malloc_start; + +static int input_len; + +static long bytes_out = 0; +extern int kernel_location_start; +static uch *output_data; +static unsigned long output_ptr = 0; + + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#include "../../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size < 0) + error("Malloc error\n"); + // if (free_mem_ptr <= 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *) free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +static void puts(const char *s) +{ + while (*s) { + if (*s == 10) + serial_putc(channel, 13); + serial_putc(channel, *s++); + } +} + +void *memset(void *s, int c, size_t n) +{ + int i; + char *ss = (char *) s; + + for (i = 0; i < n; i++) + ss[i] = c; + return s; +} + +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + int i; + char *d = (char *) __dest, *s = (char *) __src; + + for (i = 0; i < __n; i++) + d[i] = s[i]; + return __dest; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + if (insize != 0) { + error("ran out of input data\n"); + } + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg) outcnt; + output_ptr += (ulg) outcnt; + outcnt = 0; +} + +check_mem() +{ + int i; + + puts("\ncplens = "); + for (i = 0; i < 10; i++) { + int2hex(cplens[i]); + puts(" "); + } + puts("\ncplext = "); + for (i = 0; i < 10; i++) { + int2hex(cplext[i]); + puts(" "); + } + puts("\nborder = "); + for (i = 0; i < 10; i++) { + int2hex(border[i]); + puts(" "); + } + puts("\n"); +} + +static void error(char *x) +{ + check_mem(); + puts("\n\n"); + puts(x); + puts("byte_count = "); + int2hex(byte_count); + puts("\n"); + puts("\n\n -- System halted"); + while (1); /* Halt */ +} + +void variable_init() +{ + byte_count = 0; + checksum = 0; + input_data = (unsigned char *) &linux_compressed_start; + input_len = linux_compressed_size; + output_data = &kernel_location_start; + free_mem_ptr = (long) &malloc_start; + free_mem_end_ptr = (long) ((char *) &malloc_start + 0x400000); +} + +int decompress_kernel() +{ + //check_mem(); + + variable_init(); + + makecrc(); + puts("Uncompressing Linux... \n"); + gunzip(); // ...see inflate.c + puts("Ok, booting the kernel.\n"); + return 0; +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ns16550.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ns16550.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/ns16550.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/ns16550.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,126 @@ +/* NS16550 UART registers */ + +#ifndef NS16550H +#define NS16550H + +#define UART_BASE 0xbd000000 +#define NS16550_CHANA PHYS_TO_K1(UART_BASE + 0x20) +#define NS16550_CHANB PHYS_TO_K1(UART_BASE) + +#ifndef NS16550_HZ +#define NS16550_HZ 3686400 +#endif + +#ifdef __ASSEMBLER__ + +#ifndef NSREG +#define NSREG(x) ((x)*4) +#endif + +#define DATA NSREG(0) /* data register (R/W) */ +#define IER NSREG(1) /* interrupt enable (W) */ +#define IIR NSREG(2) /* interrupt identification (R) */ +#define FIFO IIR /* 16550 fifo control (W) */ +#define CFCR NSREG(3) /* line control register (R/W) */ +#define MCR NSREG(4) /* modem control register (R/W) */ +#define LSR NSREG(5) /* line status register (R/W) */ +#define MSR NSREG(6) /* modem status register (R/W) */ +#define SCR NSREG(7) /* scratch register (R/W) */ + +#else + +#ifndef nsreg +#if #endian(little) +#define nsreg(x) unsigned :24; unsigned char x; +#else +/*#define nsreg(x) unsigned char x; unsigned :24;*/ +#define nsreg(x) unsigned int x:8;unsigned int :24; +#endif +#endif + +typedef struct { + nsreg(data); /* data register (R/W) */ + nsreg(ier); /* interrupt enable (W) */ + nsreg(iir); /* interrupt identification (R) */ +#define fifo iir /* 16550 fifo control (W) */ + nsreg(cfcr); /* line control register (R/W) */ + nsreg(mcr); /* modem control register (R/W) */ + nsreg(lsr); /* line status register (R/W) */ + nsreg(msr); /* modem status register (R/W) */ + nsreg(scr); /* scratch register (R/W) */ +} ns16550dev; +#endif + + +/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */ +#define BRTC(x) (NS16550_HZ / (16*(x))) + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 /* int on rx ready */ +#define IER_ETXRDY 0x2 /* int on tx ready */ +#define IER_ERLS 0x4 /* int on line status change */ +#define IER_EMSC 0x8 /* int on modem status change */ + +/* interrupt identification register */ +#define IIR_IMASK 0xf /* mask */ +#define IIR_RXTOUT 0xc /* receive timeout */ +#define IIR_RLS 0x6 /* receive line status */ +#define IIR_RXRDY 0x4 /* receive ready */ +#define IIR_TXRDY 0x2 /* transmit ready */ +#define IIR_NOPEND 0x1 /* nothing */ +#define IIR_MLSC 0x0 /* modem status */ +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 /* enable fifo */ +#define FIFO_RCV_RST 0x02 /* reset receive fifo */ +#define FIFO_XMT_RST 0x04 /* reset transmit fifo */ +#define FIFO_DMA_MODE 0x08 /* enable dma mode */ +#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */ +#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */ +#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */ +#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */ + +/* character format control register */ +#define CFCR_DLAB 0x80 /* divisor latch */ +#define CFCR_SBREAK 0x40 /* send break */ +#define CFCR_PZERO 0x30 /* zero parity */ +#define CFCR_PONE 0x20 /* one parity */ +#define CFCR_PEVEN 0x10 /* even parity */ +#define CFCR_PODD 0x00 /* odd parity */ +#define CFCR_PENAB 0x08 /* parity enable */ +#define CFCR_STOPB 0x04 /* 2 stop bits */ +#define CFCR_8BITS 0x03 /* 8 data bits */ +#define CFCR_7BITS 0x02 /* 7 data bits */ +#define CFCR_6BITS 0x01 /* 6 data bits */ +#define CFCR_5BITS 0x00 /* 5 data bits */ + +/* modem control register */ +#define MCR_LOOPBACK 0x10 /* loopback */ +#define MCR_IENABLE 0x08 /* output 2 = int enable */ +#define MCR_DRS 0x04 /* output 1 = xxx */ +#define MCR_RTS 0x02 /* enable RTS */ +#define MCR_DTR 0x01 /* enable DTR */ + +/* line status register */ +#define LSR_RCV_FIFO 0x80 /* error in receive fifo */ +#define LSR_TSRE 0x40 /* transmitter empty */ +#define LSR_TXRDY 0x20 /* transmitter ready */ +#define LSR_BI 0x10 /* break detected */ +#define LSR_FE 0x08 /* framing error */ +#define LSR_PE 0x04 /* parity error */ +#define LSR_OE 0x02 /* overrun error */ +#define LSR_RXRDY 0x01 /* receiver ready */ +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 /* DCD active */ +#define MSR_RI 0x40 /* RI active */ +#define MSR_DSR 0x20 /* DSR active */ +#define MSR_CTS 0x10 /* CTS active */ +#define MSR_DDCD 0x08 /* DCD changed */ +#define MSR_TERI 0x04 /* RI changed */ +#define MSR_DDSR 0x02 /* DSR changed */ +#define MSR_DCTS 0x01 /* CTS changed */ + +#endif diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/osdep.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/osdep.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/osdep.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/osdep.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,36 @@ +#ifndef __OSDEP_H__ +#define __OSDEP_H__ + +/* + * 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) any later version. + */ + +#if defined(__linux__) || defined(__FreeBSD__) || defined (__MIPSEB__) +#define ETHERBOOT32 +#define ntohl(x) (x) +#define htonl(x) (x) +#define ntohs(x) (x) +#define htons(x) (x) + +#endif + + + + +/* ANSI prototyping macro */ +#ifdef __STDC__ +#define P(x) x +#else +#define P(x) () +#endif + +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1336 @@ +/* PCI.c - PCI functions */ + +/* Copyright - Galileo technology. */ + +#ifdef __linux__ +#include +#include +#ifndef PROM +#include +#endif + +#undef PCI_DEBUG + +#ifdef PCI_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#else +#include "core.h" +#include "pci.h" +#include +#endif + +/******************************************************************** +* pci0ScanDevices - This function scan PCI0 bus, if found any device on +* this bus it interrogate the Device for the information +* it can discover. +* The fields with all information are the following: +* char type[20]; +* unsigned int deviceNum; +* unsigned int venID; +* unsigned int deviceID; +* unsigned int bar0Base; +* unsigned int bar0Size; +* unsigned int bar1Base; +* unsigned int bar1Size; +* unsigned int bar2Base; +* unsigned int bar2Size; +* unsigned int bar3Base; +* unsigned int bar3Size; +* unsigned int bar4Base; +* unsigned int bar4Size; +* unsigned int bar5Base; +* unsigned int bar5Size; +* +* Inputs: PCI0_DEVICE* pci0Detect - Pointer to an array of STRUCT PCI0_DEVICE. +* unsigned int numberOfElment - The PCI0_DEVICE Array length. +* Output: None. +*********************************************************************/ + +void pci0ScanDevices(PCI_DEVICE * pci0Detect, unsigned int numberOfElment) +{ + PCI_DEVICE *pci0ArrayPointer = pci0Detect; + unsigned int id; /* PCI Configuration register 0x0. */ + unsigned int device; /* device`s Counter. */ + unsigned int classCode; /* PCI Configuration register 0x8 */ + unsigned int arrayCounter = 0; + unsigned int memBaseAddress; + unsigned int memSize; + unsigned int c18RegValue; + + PCI0_MASTER_ENABLE(SELF); + /* According to PCI REV 2.1 MAX agents on the bus are -21- */ + for (device = 6; device < 8; device++) { + id = pci0ReadConfigReg(PCI_0DEVICE_AND_VENDOR_ID, device); + GT_REG_READ(INTERRUPT_CAUSE_REGISTER, &c18RegValue); + /* Clearing bit 18 of in the Cause Register 0xc18 by writting 0. */ + GT_REG_WRITE(INTERRUPT_CAUSE_REGISTER, + c18RegValue & 0xfffbffff); + if ((id != 0xffffffff) && !(c18RegValue & 0x40000)) { + classCode = + pci0ReadConfigReg + (PCI_0CLASS_CODE_AND_REVISION_ID, device); + pci0ArrayPointer->deviceNum = device; + pci0ArrayPointer->venID = (id & 0xffff); + pci0ArrayPointer->deviceID = + ((id & 0xffff0000) >> 16); + DBG("\nrr: venID %x devID %x\n", + pci0ArrayPointer->venID, + pci0ArrayPointer->deviceID); + DBG("rr: device found %x\n", + pci0ArrayPointer->deviceNum); + /* BAR0 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR0, device); + pci0ArrayPointer->bar0Type = memBaseAddress & 1; + pci0ArrayPointer->bar0Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR0, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR0, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar0Size = 0; + } else { + if (pci0ArrayPointer->bar0Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar0Size = memSize; + } + DBG("rr: device BAR0 size %x\n", memSize); + DBG("rr: device BAR0 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR0, device, memBaseAddress); + /* BAR1 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR1, device); + pci0ArrayPointer->bar1Type = memBaseAddress & 1; + pci0ArrayPointer->bar1Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR1, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR1, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar1Size = 0; + } else { + if (pci0ArrayPointer->bar1Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar1Size = memSize; + } + DBG("rr: device BAR1 size %x\n", memSize); + DBG("rr: device BAR1 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR1, device, memBaseAddress); + /* BAR2 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR2, device); + pci0ArrayPointer->bar2Type = memBaseAddress & 1; + pci0ArrayPointer->bar2Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR2, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR2, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar2Size = 0; + } else { + if (pci0ArrayPointer->bar2Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar2Size = memSize; + } + DBG("rr: device BAR2 size %x\n", memSize); + DBG("rr: device BAR2 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR2, device, memBaseAddress); + /* BAR3 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR3, device); + pci0ArrayPointer->bar3Type = memBaseAddress & 1; + pci0ArrayPointer->bar3Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR3, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR3, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar3Size = 0; + } else { + if (pci0ArrayPointer->bar3Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar3Size = memSize; + } + DBG("rr: device BAR3 size %x\n", memSize); + DBG("rr: device BAR3 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR3, device, memBaseAddress); + /* BAR4 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR4, device); + pci0ArrayPointer->bar4Type = memBaseAddress & 1; + pci0ArrayPointer->bar4Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR4, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR4, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar4Size = 0; + } else { + if (pci0ArrayPointer->bar4Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar4Size = memSize; + } + DBG("rr: device BAR4 size %x\n", memSize); + DBG("rr: device BAR4 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR4, device, memBaseAddress); + /* BAR5 parameters */ + memBaseAddress = pci0ReadConfigReg(BAR5, device); + pci0ArrayPointer->bar5Type = memBaseAddress & 1; + pci0ArrayPointer->bar5Base = + memBaseAddress & 0xfffff000; + pci0WriteConfigReg(BAR5, device, 0xffffffff); + memSize = pci0ReadConfigReg(BAR5, device); + if (memSize == 0) { /* case of an empty BAR */ + pci0ArrayPointer->bar5Size = 0; + } else { + if (pci0ArrayPointer->bar5Type == 1) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci0ArrayPointer->bar5Size = memSize; + } + DBG("rr: device BAR5 size %x\n", memSize); + DBG("rr: device BAR5 address %x\n", + memBaseAddress); + pci0WriteConfigReg(BAR5, device, memBaseAddress); + /* End of BARs Detection. */ + + classCode = ((classCode & 0xff000000) >> 24); + switch (classCode) { + case 0x0: + strcpy(pci0ArrayPointer->type, + "Old generation device"); + break; + case 0x1: + strcpy(pci0ArrayPointer->type, + "Mass storage controller"); + break; + case 0x2: + strcpy(pci0ArrayPointer->type, + "Network controller"); + break; + case 0x3: + strcpy(pci0ArrayPointer->type, + "Display controller"); + break; + case 0x4: + strcpy(pci0ArrayPointer->type, + "Multimedia device"); + break; + case 0x5: + strcpy(pci0ArrayPointer->type, + "Memory controller"); + break; + case 0x6: + strcpy(pci0ArrayPointer->type, + "Bridge Device"); + break; + case 0x7: + strcpy(pci0ArrayPointer->type, + "Simple Communication controllers"); + break; + case 0x8: + strcpy(pci0ArrayPointer->type, + "Base system peripherals"); + break; + case 0x9: + strcpy(pci0ArrayPointer->type, + "Input Devices"); + break; + case 0xa: + strcpy(pci0ArrayPointer->type, + "Docking stations"); + break; + case 0xb: + strcpy(pci0ArrayPointer->type, + "Processors"); + break; + case 0xc: + strcpy(pci0ArrayPointer->type, + "Serial bus controllers"); + break; + case 0xd: + strcpy(pci0ArrayPointer->type, + "Wireless controllers"); + break; + case 0xe: + strcpy(pci0ArrayPointer->type, + "Intelligent I/O controllers"); + break; + case 0xf: + strcpy(pci0ArrayPointer->type, + "Satellite communication controllers"); + break; + case 0x10: + strcpy(pci0ArrayPointer->type, + "Encryption/Decryption controllers"); + break; + case 0x11: + strcpy(pci0ArrayPointer->type, + "Data acquisition and signal processing controllers"); + break; + default: + break; + + } + arrayCounter++; /* point to the next element in the Array. */ + if (arrayCounter == numberOfElment) + return; /* When the Array is fully used, return. */ + /* Else, points to next free Element. */ + pci0ArrayPointer = &pci0Detect[arrayCounter]; + } + } + pci0ArrayPointer->deviceNum = 0; /* 0 => End of List */ +} + + +/******************************************************************** +* pci1ScanDevices - This function scan PCI1 bus, if found any device on +* this bus it interrogate the Device for the information +* it can discover. +* The fields with all information are the following: +* char type[20]; +* unsigned int deviceNum; +* unsigned int venID; +* unsigned int deviceID; +* unsigned int bar0Base; +* unsigned int bar0Size; +* unsigned int bar1Base; +* unsigned int bar1Size; +* unsigned int bar2Base; +* unsigned int bar2Size; +* unsigned int bar3Base; +* unsigned int bar3Size; +* unsigned int bar4Base; +* unsigned int bar4Size; +* unsigned int bar5Base; +* unsigned int bar5Size; +* +* Inputs: Pointer to an array of STRUCT PCI1_DEVICE. +* Output: None. +*********************************************************************/ + +void pci1ScanDevices(PCI_DEVICE * pci1Detect, unsigned int numberOfElment) +{ + PCI_DEVICE *pci1ArrayPointer = pci1Detect; + unsigned int id; /* PCI Configuration register 0x0. */ + unsigned int device; /* device`s Counter. */ + unsigned int classCode; /* PCI Configuration register 0x8 */ + unsigned int arrayCounter = 0; + unsigned int memBaseAddress; + unsigned int memSize; + unsigned int c98RegValue; + + PCI1_MASTER_ENABLE(SELF); + /* According to PCI REV 2.1 MAX agents on the bus are -21- */ + for (device = 1; device < 22; device++) { + id = pci1ReadConfigReg(PCI_0DEVICE_AND_VENDOR_ID, device); + GT_REG_READ(HIGH_INTERRUPT_CAUSE_REGISTER, &c98RegValue); + /* Clearing bit 18 of in the High Cause Register 0xc98 */ + GT_REG_WRITE(HIGH_INTERRUPT_CAUSE_REGISTER, + c98RegValue & 0xfffbffff); + if ((id != 0xffffffff) && !(c98RegValue & 0x40000)) { + classCode = + pci1ReadConfigReg + (PCI_0CLASS_CODE_AND_REVISION_ID, device); + pci1ArrayPointer->deviceNum = device; + pci1ArrayPointer->venID = (id & 0xffff); + pci1ArrayPointer->deviceID = + ((id & 0xffff0000) >> 16); + + /* BAR0 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR0, device); + pci1ArrayPointer->bar0Type = memBaseAddress & 1; + pci1ArrayPointer->bar0Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR0, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR0, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar0Size = 0; + } else { + if (pci1ArrayPointer->bar0Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar0Size = memSize; + } + pci1WriteConfigReg(BAR0, device, memBaseAddress); + /* BAR1 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR1, device); + pci1ArrayPointer->bar1Type = memBaseAddress & 1; + pci1ArrayPointer->bar1Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR1, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR1, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar1Size = 0; + } else { + if (pci1ArrayPointer->bar1Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar1Size = memSize; + } + pci1WriteConfigReg(BAR1, device, memBaseAddress); + /* BAR2 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR2, device); + pci1ArrayPointer->bar2Type = memBaseAddress & 1; + pci1ArrayPointer->bar2Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR2, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR2, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar2Size = 0; + } else { + if (pci1ArrayPointer->bar2Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar2Size = memSize; + } + pci1WriteConfigReg(BAR2, device, memBaseAddress); + /* BAR3 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR3, device); + pci1ArrayPointer->bar3Type = memBaseAddress & 1; + pci1ArrayPointer->bar3Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR3, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR3, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar3Size = 0; + } else { + if (pci1ArrayPointer->bar3Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar3Size = memSize; + } + pci1WriteConfigReg(BAR3, device, memBaseAddress); + /* BAR4 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR4, device); + pci1ArrayPointer->bar4Type = memBaseAddress & 1; + pci1ArrayPointer->bar4Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR4, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR4, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar4Size = 0; + } else { + if (pci1ArrayPointer->bar4Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar4Size = memSize; + } + pci1WriteConfigReg(BAR4, device, memBaseAddress); + /* BAR5 parameters */ + memBaseAddress = pci1ReadConfigReg(BAR5, device); + pci1ArrayPointer->bar5Type = memBaseAddress & 1; + pci1ArrayPointer->bar5Base = + memBaseAddress & 0xfffff000; + pci1WriteConfigReg(BAR5, device, 0xffffffff); + memSize = pci1ReadConfigReg(BAR5, device); + if (memSize == 0) { /* case of an empty BAR */ + pci1ArrayPointer->bar5Size = 0; + } else { + if (pci1ArrayPointer->bar5Type == 0) /* memory space */ + memSize = + ~(memSize & 0xfffffff0) + 1; + else /* IO space */ + memSize = + ~(memSize & 0xfffffffc) + 1; + pci1ArrayPointer->bar5Size = memSize; + } + pci1WriteConfigReg(BAR5, device, memBaseAddress); + /* End of BARs Detection. */ + + classCode = ((classCode & 0xff000000) >> 24); + switch (classCode) { + case 0x0: + strcpy(pci1ArrayPointer->type, + "Old generation device"); + break; + case 0x1: + strcpy(pci1ArrayPointer->type, + "Mass storage controller"); + break; + case 0x2: + strcpy(pci1ArrayPointer->type, + "Network controller"); + break; + case 0x3: + strcpy(pci1ArrayPointer->type, + "Display controller"); + break; + case 0x4: + strcpy(pci1ArrayPointer->type, + "Multimedia device"); + break; + case 0x5: + strcpy(pci1ArrayPointer->type, + "Memory controller"); + break; + case 0x6: + strcpy(pci1ArrayPointer->type, + "Bridge Device"); + break; + case 0x7: + strcpy(pci1ArrayPointer->type, + "Simple Communication controllers"); + break; + case 0x8: + strcpy(pci1ArrayPointer->type, + "Base system peripherals"); + break; + case 0x9: + strcpy(pci1ArrayPointer->type, + "Input Devices"); + break; + case 0xa: + strcpy(pci1ArrayPointer->type, + "Docking stations"); + break; + case 0xb: + strcpy(pci1ArrayPointer->type, + "Processors"); + break; + case 0xc: + strcpy(pci1ArrayPointer->type, + "Serial bus controllers"); + break; + case 0xd: + strcpy(pci1ArrayPointer->type, + "Wireless controllers"); + break; + case 0xe: + strcpy(pci1ArrayPointer->type, + "Intelligent I/O controllers"); + break; + case 0xf: + strcpy(pci1ArrayPointer->type, + "Satellite communication controllers"); + break; + case 0x10: + strcpy(pci1ArrayPointer->type, + "Encryption/Decryption controllers"); + break; + case 0x11: + strcpy(pci1ArrayPointer->type, + "Data acquisition and signal processing controllers"); + break; + } + arrayCounter++; /* point to the next element in the Array. */ + if (arrayCounter == numberOfElment) + return; /* When the Array is fully used, return. */ + /* Else, points to next free Element. */ + pci1ArrayPointer = &pci1Detect[arrayCounter]; + } + } + pci1ArrayPointer->deviceNum = 0; /* 0 => End of List */ +} + +/******************************************************************** +* pci0WriteConfigReg - Write to a PCI configuration register +* - Make sure the GT is configured as a master before +* writingto another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* Inputs: unsigned int regOffset: The register offset as it apears in the GT spec +* (or any other PCI device spec) +* pciDevNum: The device number needs to be addressed. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ + +void pci0WriteConfigReg(unsigned int regOffset, unsigned int pciDevNum, + unsigned int data) +{ + unsigned int DataForRegCf8; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0x0fffffff; + DataForRegCf8 = (regOffset | pciDevNum | functionNum) | BIT31; + GT_REG_WRITE(PCI_0CONFIGURATION_ADDRESS, DataForRegCf8); + if (pciDevNum == SELF) { /* This board */ + GT_REG_WRITE(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + data); + } else { /* configuration Transaction over the pci. */ + + /* The PCI is working in LE Mode So it swap the Data. */ + GT_REG_WRITE(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + WORDSWAP(data)); + } +} + +/******************************************************************** +* pci1WriteConfigReg - Write to a PCI configuration register +* - Make sure the GT is configured as a master before writing +* to another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* Inputs: unsigned int regOffset: The register offset as it apears in the +* GT spec (or any other PCI device spec) +* pciDevNum: The device number needs to be addressed. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ + +void pci1WriteConfigReg(unsigned int regOffset, unsigned int pciDevNum, + unsigned int data) +{ + unsigned int DataForRegCf8; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0x0fffffff; + if (pciDevNum == SELF) { /* This board */ + /* when configurating our own PCI 1 L-unit the access is through + the PCI 0 interface with reg number = reg number + 0x80 */ + DataForRegCf8 = + (regOffset | pciDevNum | functionNum | 0x80) | BIT31; + GT_REG_WRITE(PCI_0CONFIGURATION_ADDRESS, DataForRegCf8); + } else { + DataForRegCf8 = + (regOffset | pciDevNum | functionNum) | BIT31; + GT_REG_WRITE(PCI_1CONFIGURATION_ADDRESS, DataForRegCf8); + } + if (pciDevNum == SELF) { /* This board */ + GT_REG_WRITE(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + data); + } else { + GT_REG_WRITE(PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER, + WORDSWAP(data)); + } +} + +/******************************************************************** +* pci0ReadConfigReg - Read from a PCI0 configuration register +* - Make sure the GT is configured as a master before +* reading from another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec) +* pciDevNum: The device number needs to be addressed. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ + +unsigned int pci0ReadConfigReg(unsigned int regOffset, + unsigned int pciDevNum) +{ + unsigned int DataForRegCf8; + unsigned int data; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0x0fffffff; + DataForRegCf8 = (regOffset | pciDevNum | functionNum) | BIT31; + GT_REG_WRITE(PCI_0CONFIGURATION_ADDRESS, DataForRegCf8); + if (pciDevNum == SELF) { /* This board */ + GT_REG_READ(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + &data); + return data; + } else { /* The PCI is working in LE Mode So it swap the Data. */ + + GT_REG_READ(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + &data); + return WORDSWAP(data); + } +} + +/******************************************************************** +* pci1ReadConfigReg - Read from a PCI1 configuration register +* - Make sure the GT is configured as a master before +* reading from another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec) +* pciDevNum: The device number needs to be addressed. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ + +unsigned int pci1ReadConfigReg(unsigned int regOffset, + unsigned int pciDevNum) +{ + unsigned int DataForRegCf8; + unsigned int data; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0x0fffffff; + if (pciDevNum == SELF) { /* This board */ + /* when configurating our own PCI 1 L-unit the access is through + the PCI 0 interface with reg number = reg number + 0x80 */ + DataForRegCf8 = + (regOffset | pciDevNum | functionNum | 0x80) | BIT31; + GT_REG_WRITE(PCI_0CONFIGURATION_ADDRESS, DataForRegCf8); + } else { + DataForRegCf8 = + (regOffset | pciDevNum | functionNum) | BIT31; + GT_REG_WRITE(PCI_1CONFIGURATION_ADDRESS, DataForRegCf8); + } + if (pciDevNum == SELF) { /* This board */ + GT_REG_READ(PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + &data); + return data; + } else { + GT_REG_READ(PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER, + &data); + return WORDSWAP(data); + } +} + +/******************************************************************** +* pci0MapIOspace - Maps PCI0 IO space for the master. +* Inputs: base and length of pci0Io +*********************************************************************/ + +void pci0MapIOspace(unsigned int pci0IoBase, unsigned int pci0IoLength) +{ + unsigned int pci0IoTop = + (unsigned int) (pci0IoBase + pci0IoLength); + + if (pci0IoLength == 0) + pci0IoTop++; + + pci0IoBase = (unsigned int) (pci0IoBase >> 21); + pci0IoTop = (unsigned int) (((pci0IoTop - 1) & 0x0fffffff) >> 21); + GT_REG_WRITE(PCI_0I_O_LOW_DECODE_ADDRESS, pci0IoBase); + GT_REG_WRITE(PCI_0I_O_HIGH_DECODE_ADDRESS, pci0IoTop); +} + +/******************************************************************** +* pci1MapIOspace - Maps PCI1 IO space for the master. +* Inputs: base and length of pci1Io +*********************************************************************/ + +void pci1MapIOspace(unsigned int pci1IoBase, unsigned int pci1IoLength) +{ + unsigned int pci1IoTop = + (unsigned int) (pci1IoBase + pci1IoLength); + + if (pci1IoLength == 0) + pci1IoTop++; + + pci1IoBase = (unsigned int) (pci1IoBase >> 21); + pci1IoTop = (unsigned int) (((pci1IoTop - 1) & 0x0fffffff) >> 21); + GT_REG_WRITE(PCI_1I_O_LOW_DECODE_ADDRESS, pci1IoBase); + GT_REG_WRITE(PCI_1I_O_HIGH_DECODE_ADDRESS, pci1IoTop); +} + +/******************************************************************** +* pci0MapMemory0space - Maps PCI0 memory0 space for the master. +* Inputs: base and length of pci0Mem0 +*********************************************************************/ + + +void pci0MapMemory0space(unsigned int pci0Mem0Base, + unsigned int pci0Mem0Length) +{ + unsigned int pci0Mem0Top = pci0Mem0Base + pci0Mem0Length; + + if (pci0Mem0Length == 0) + pci0Mem0Top++; + + pci0Mem0Base = pci0Mem0Base >> 21; + pci0Mem0Top = ((pci0Mem0Top - 1) & 0x0fffffff) >> 21; + GT_REG_WRITE(PCI_0MEMORY0_LOW_DECODE_ADDRESS, pci0Mem0Base); + GT_REG_WRITE(PCI_0MEMORY0_HIGH_DECODE_ADDRESS, pci0Mem0Top); +} + +/******************************************************************** +* pci1MapMemory0space - Maps PCI1 memory0 space for the master. +* Inputs: base and length of pci1Mem0 +*********************************************************************/ + +void pci1MapMemory0space(unsigned int pci1Mem0Base, + unsigned int pci1Mem0Length) +{ + unsigned int pci1Mem0Top = pci1Mem0Base + pci1Mem0Length; + + if (pci1Mem0Length == 0) + pci1Mem0Top++; + + pci1Mem0Base = pci1Mem0Base >> 21; + pci1Mem0Top = ((pci1Mem0Top - 1) & 0x0fffffff) >> 21; + GT_REG_WRITE(PCI_1MEMORY0_LOW_DECODE_ADDRESS, pci1Mem0Base); + GT_REG_WRITE(PCI_1MEMORY0_HIGH_DECODE_ADDRESS, pci1Mem0Top); +} + +/******************************************************************** +* pci0MapMemory1space - Maps PCI0 memory1 space for the master. +* Inputs: base and length of pci0Mem1 +*********************************************************************/ + +void pci0MapMemory1space(unsigned int pci0Mem1Base, + unsigned int pci0Mem1Length) +{ + unsigned int pci0Mem1Top = pci0Mem1Base + pci0Mem1Length; + + if (pci0Mem1Length == 0) + pci0Mem1Top++; + + pci0Mem1Base = pci0Mem1Base >> 21; + pci0Mem1Top = ((pci0Mem1Top - 1) & 0x0fffffff) >> 21; + GT_REG_WRITE(PCI_0MEMORY1_LOW_DECODE_ADDRESS, pci0Mem1Base); + GT_REG_WRITE(PCI_0MEMORY1_HIGH_DECODE_ADDRESS, pci0Mem1Top); +#ifndef PROM + DBG(KERN_INFO "pci0Mem1Base %x\n", pci0Mem1Base); + DBG(KERN_INFO "pci0Mem1Top %x\n", pci0Mem1Top); + GT_REG_READ(PCI_0MEMORY0_ADDRESS_REMAP, &pci0Mem1Base); + DBG(KERN_INFO "Mem 0/0 remap %x\n", pci0Mem1Base); + GT_REG_READ(PCI_0MEMORY1_ADDRESS_REMAP, &pci0Mem1Base); + DBG(KERN_INFO "Mem 0/1 remap %x\n", pci0Mem1Base); + GT_REG_WRITE(PCI_0MEMORY1_ADDRESS_REMAP, 0x500); + GT_REG_READ(PCI_0MEMORY1_ADDRESS_REMAP, &pci0Mem1Base); + DBG(KERN_INFO "Mem 0/1 remapped %x\n", pci0Mem1Base); +#endif +} + +/******************************************************************** +* pci1MapMemory1space - Maps PCI1 memory1 space for the master. +* Inputs: base and length of pci1Mem1 +*********************************************************************/ + +void pci1MapMemory1space(unsigned int pci1Mem1Base, + unsigned int pci1Mem1Length) +{ + unsigned int pci1Mem1Top = pci1Mem1Base + pci1Mem1Length; + + if (pci1Mem1Length == 0) + pci1Mem1Top++; + + pci1Mem1Base = pci1Mem1Base >> 21; + pci1Mem1Top = ((pci1Mem1Top - 1) & 0x0fffffff) >> 21; + GT_REG_WRITE(PCI_1MEMORY1_LOW_DECODE_ADDRESS, pci1Mem1Base); + GT_REG_WRITE(PCI_1MEMORY1_HIGH_DECODE_ADDRESS, pci1Mem1Top); +} + +/******************************************************************** +* pci0GetIOspaceBase - Return PCI0 IO Base Address. +* Inputs: N/A +* Returns: PCI0 IO Base Address. +*********************************************************************/ + +unsigned int pci0GetIOspaceBase() +{ + unsigned int base; + GT_REG_READ(PCI_0I_O_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci0GetIOspaceSize - Return PCI0 IO Bar Size. +* Inputs: N/A +* Returns: PCI0 IO Bar Size. +*********************************************************************/ + +unsigned int pci0GetIOspaceSize() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_0I_O_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_0I_O_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci0GetMemory0Base - Return PCI0 Memory 0 Base Address. +* Inputs: N/A +* Returns: PCI0 Memory 0 Base Address. +*********************************************************************/ + +unsigned int pci0GetMemory0Base() +{ + unsigned int base; + GT_REG_READ(PCI_0MEMORY0_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci0GetMemory0Size - Return PCI0 Memory 0 Bar Size. +* Inputs: N/A +* Returns: PCI0 Memory 0 Bar Size. +*********************************************************************/ + +unsigned int pci0GetMemory0Size() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_0MEMORY0_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_0MEMORY0_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci0GetMemory1Base - Return PCI0 Memory 1 Base Address. +* Inputs: N/A +* Returns: PCI0 Memory 1 Base Address. +*********************************************************************/ + +unsigned int pci0GetMemory1Base() +{ + unsigned int base; + GT_REG_READ(PCI_0MEMORY1_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci0GetMemory1Size - Return PCI0 Memory 1 Bar Size. +* Inputs: N/A +* Returns: PCI0 Memory 1 Bar Size. +*********************************************************************/ + +unsigned int pci0GetMemory1Size() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_0MEMORY1_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_0MEMORY1_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci1GetIOspaceBase - Return PCI1 IO Base Address. +* Inputs: N/A +* Returns: PCI1 IO Base Address. +*********************************************************************/ + +unsigned int pci1GetIOspaceBase() +{ + unsigned int base; + GT_REG_READ(PCI_1I_O_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci1GetIOspaceSize - Return PCI1 IO Bar Size. +* Inputs: N/A +* Returns: PCI1 IO Bar Size. +*********************************************************************/ + +unsigned int pci1GetIOspaceSize() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_1I_O_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_1I_O_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci1GetMemory0Base - Return PCI1 Memory 0 Base Address. +* Inputs: N/A +* Returns: PCI1 Memory 0 Base Address. +*********************************************************************/ + +unsigned int pci1GetMemory0Base() +{ + unsigned int base; + GT_REG_READ(PCI_1MEMORY0_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci1GetMemory0Size - Return PCI1 Memory 0 Bar Size. +* Inputs: N/A +* Returns: PCI1 Memory 0 Bar Size. +*********************************************************************/ + +unsigned int pci1GetMemory0Size() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_1MEMORY1_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_1MEMORY1_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci1GetMemory1Base - Return PCI1 Memory 1 Base Address. +* Inputs: N/A +* Returns: PCI1 Memory 1 Base Address. +*********************************************************************/ + +unsigned int pci1GetMemory1Base() +{ + unsigned int base; + GT_REG_READ(PCI_1MEMORY1_LOW_DECODE_ADDRESS, &base); + base = base << 21; + return base; +} + +/******************************************************************** +* pci1GetMemory1Size - Return PCI1 Memory 1 Bar Size. +* Inputs: N/A +* Returns: PCI1 Memory 1 Bar Size. +*********************************************************************/ + +unsigned int pci1GetMemory1Size() +{ + unsigned int top, base, size; + GT_REG_READ(PCI_1MEMORY1_LOW_DECODE_ADDRESS, &base); + base = base << 21; + GT_REG_READ(PCI_1MEMORY1_HIGH_DECODE_ADDRESS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/******************************************************************** +* pci0MapInternalRegSpace - Maps the internal registers memory space for the +* slave. +* Stays the same for all GT devices Disco include +* Inputs: base of pci0 internal register +*********************************************************************/ + +void pci0MapInternalRegSpace(unsigned int pci0InternalBase) +{ + pci0InternalBase = pci0InternalBase & 0xfffff000; + pci0InternalBase = + pci0InternalBase | + (pci0ReadConfigReg + (PCI_0INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS, + SELF) & 0x00000fff); + pci0WriteConfigReg + (PCI_0INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS, SELF, + pci0InternalBase); +} + +/******************************************************************** +* pci1MapInternalRegSpace - Maps the internal registers memory space for the +* slave. +* Stays the same for all GT devices Disco include +* Inputs: base of pci1 internal register +*********************************************************************/ + +void pci1MapInternalRegSpace(unsigned int pci1InternalBase) +{ + pci1InternalBase = pci1InternalBase & 0xfffff000; + pci1InternalBase = + pci1InternalBase | + (pci1ReadConfigReg + (PCI_0INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS, + SELF) & 0x00000fff); + pci1WriteConfigReg + (PCI_0INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS, SELF, + pci1InternalBase); +} + +/******************************************************************** +* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the +* slave. +* Stays the same for all GT devices Disco include +* Inputs: base of pci0 internal io register +*********************************************************************/ + +void pci0MapInternalRegIOSpace(unsigned int pci0InternalBase) +{ + pci0InternalBase = pci0InternalBase & 0xfffff000; + pci0InternalBase = + pci0InternalBase | + (pci0ReadConfigReg + (PCI_0INTERNAL_REGISTERS_I_OMAPPED_BASE_ADDRESS, + 0) & 0x00000fff); + pci0WriteConfigReg(PCI_0INTERNAL_REGISTERS_I_OMAPPED_BASE_ADDRESS, + SELF, pci0InternalBase); +} + +/******************************************************************** +* pci0MapInternalRegIOSpace - Maps the internal registers IO space for the +* slave. +* Stays the same for all GT devices Disco include +* Inputs: base of pci1 internal io register +*********************************************************************/ + +void pci1MapInternalRegIOSpace(unsigned int pci1InternalBase) +{ + pci1InternalBase = pci1InternalBase & 0xfffff000; + pci1InternalBase = + pci1InternalBase | + (pci1ReadConfigReg + (PCI_0INTERNAL_REGISTERS_I_OMAPPED_BASE_ADDRESS, + SELF) & 0x00000fff); + pci1WriteConfigReg(PCI_0INTERNAL_REGISTERS_I_OMAPPED_BASE_ADDRESS, + SELF, pci1InternalBase); +} + +/******************************************************************** +* pci0MapMemoryBanks0_1 - Maps PCI0 memory banks 0 and 1 for the slave. +* for Discovery we need two function: SCS0 & SCS1 +* (instead of SCS[1:0]) +* Inputs: base and size of pci0 dram +*********************************************************************/ + + +void pci0MapMemoryBanks0_1(unsigned int pci0Dram0_1Base, + unsigned int pci0Dram0_1Size) +{ + pci0Dram0_1Base = pci0Dram0_1Base & 0xfffff000; + pci0Dram0_1Base = + pci0Dram0_1Base | + (pci0ReadConfigReg(PCI_0SCS_1_0_BASE_ADDRESS, SELF) & + 0x00000fff); + pci0WriteConfigReg(PCI_0SCS_1_0_BASE_ADDRESS, SELF, + pci0Dram0_1Base); + /* swapped Bar */ + pci0WriteConfigReg(PCI_0SWAPPED_SCS_1_0_BASE_ADDRESS, SELF, + pci0Dram0_1Base); + if (pci0Dram0_1Size == 0) + pci0Dram0_1Size++; + GT_REG_WRITE(PCI_0SCS_1_0_BANK_SIZE, pci0Dram0_1Size - 1); +} + +/******************************************************************** +* pci1MapMemoryBanks0_1 - Maps PCI1 memory banks 0 and 1 for the slave. +* for Discovery we need two function: SCS0 & SCS1 +* (instead of SCS[1:0]) +* Inputs: base and size of pci1 dram +*********************************************************************/ + +void pci1MapMemoryBanks0_1(unsigned int pci1Dram0_1Base, + unsigned int pci1Dram0_1Size) +{ + pci1Dram0_1Base = pci1Dram0_1Base & 0xfffff000; + pci1Dram0_1Base = + pci1Dram0_1Base | + (pci1ReadConfigReg(PCI_0SCS_1_0_BASE_ADDRESS, SELF) & + 0x00000fff); + pci1WriteConfigReg(PCI_0SCS_1_0_BASE_ADDRESS, SELF, + pci1Dram0_1Base); + /* swapped Bar */ + pci1WriteConfigReg(PCI_0SWAPPED_SCS_1_0_BASE_ADDRESS, SELF, + pci1Dram0_1Base); + if (pci1Dram0_1Size == 0) + pci1Dram0_1Size++; + GT_REG_WRITE(PCI_1SCS_1_0_BANK_SIZE, pci1Dram0_1Size - 1); +} + +/******************************************************************** +* pci0MapMemoryBanks2_3 - Maps PCI0 memory banks 2 and 3 for the slave. +* for Discovery we need two function: SCS2 & SCS3 +* (instead of SCS[3:2]) +* Inputs: base and size of pci0 dram +*********************************************************************/ + +void pci0MapMemoryBanks2_3(unsigned int pci0Dram2_3Base, + unsigned int pci0Dram2_3Size) +{ + pci0Dram2_3Base = pci0Dram2_3Base & 0xfffff000; + pci0Dram2_3Base = + pci0Dram2_3Base | + (pci0ReadConfigReg(PCI_0SCS_3_2_BASE_ADDRESS, SELF) & + 0x00000fff); + pci0WriteConfigReg(PCI_0SCS_3_2_BASE_ADDRESS, SELF, + pci0Dram2_3Base); + /* swapped Bar */ + pci0WriteConfigReg(PCI_0SWAPPED_SCS_3_2_BASE_ADDRESS, SELF, + pci0Dram2_3Base); + if (pci0Dram2_3Size == 0) + pci0Dram2_3Size++; + GT_REG_WRITE(PCI_0SCS_3_2_BANK_SIZE, pci0Dram2_3Size - 1); +} + +/******************************************************************** +* pci1MapMemoryBanks2_3 - Maps PCI1 memory banks 2 and 3 for the slave. +* for Discovery we need two function: SCS2 & SCS3 +* (instead of SCS[3:2]) +* Inputs: base and size of pci1 dram +*********************************************************************/ + +void pci1MapMemoryBanks2_3(unsigned int pci1Dram2_3Base, + unsigned int pci1Dram2_3Size) +{ + pci1Dram2_3Base = pci1Dram2_3Base & 0xfffff000; + pci1Dram2_3Base = + pci1Dram2_3Base | + (pci1ReadConfigReg(PCI_0SCS_3_2_BASE_ADDRESS, SELF) & + 0x00000fff); + pci1WriteConfigReg(PCI_0SCS_3_2_BASE_ADDRESS, SELF, + pci1Dram2_3Base); + /* swapped Bar */ + pci1WriteConfigReg(PCI_0SWAPPED_SCS_3_2_BASE_ADDRESS, SELF, + pci1Dram2_3Base); + if (pci1Dram2_3Size == 0) + pci1Dram2_3Size++; + GT_REG_WRITE(PCI_1SCS_3_2_BANK_SIZE, pci1Dram2_3Size - 1); +} + +/******************************************************************** +* pci0MapDevices0_1and2MemorySpace - Maps PCI0 devices 0,1 and 2 memory spaces +* for the slave. +* For the Discovery there are 3 separate +* fucnction's +* Inputs: base and lengthof pci0 devises012 +*********************************************************************/ + + +void pci0MapDevices0_1and2MemorySpace(unsigned int pci0Dev012Base, + unsigned int pci0Dev012Length) +{ + pci0Dev012Base = pci0Dev012Base & 0xfffff000; + pci0Dev012Base = + pci0Dev012Base | + (pci0ReadConfigReg(PCI_0CS_2_0_BASE_ADDRESS, SELF) & + 0x00000fff); + pci0WriteConfigReg(PCI_0CS_2_0_BASE_ADDRESS, SELF, pci0Dev012Base); + if (pci0Dev012Length == 0) + pci0Dev012Length++; + GT_REG_WRITE(PCI_0CS_2_0_BANK_SIZE, pci0Dev012Length - 1); +} + +/******************************************************************** +* pci1MapDevices0_1and2MemorySpace - Maps PCI1 devices 0,1 and 2 memory spaces +* for the slave. +* For the Discovery there are 3 separate +* fucnction's +* Inputs: base and lengthof pci1 devises012 +*********************************************************************/ + +void pci1MapDevices0_1and2MemorySpace(unsigned int pci1Dev012Base, + unsigned int pci1Dev012Length) +{ + pci1Dev012Base = pci1Dev012Base & 0xfffff000; + pci1Dev012Base = + pci1Dev012Base | + (pci1ReadConfigReg(PCI_0CS_2_0_BASE_ADDRESS, SELF) & + 0x00000fff); + pci1WriteConfigReg(PCI_0CS_2_0_BASE_ADDRESS, SELF, pci1Dev012Base); + if (pci1Dev012Length == 0) + pci1Dev012Length++; + GT_REG_WRITE(PCI_1CS_2_0_BANK_SIZE, pci1Dev012Length - 1); +} + +/******************************************************************** +* pci0MapDevices3andBootMemorySpace - Maps PCI0 devices 3 and boot memory +* spaces for the slave. +* For the Discovery there are 2 separate +* fucnction's +* Inputs: base and length of pci0 device3/ boot +*********************************************************************/ + +void pci0MapDevices3andBootMemorySpace(unsigned int pci0Dev3andBootBase, + unsigned int pci0Dev3andBootLength) +{ + pci0Dev3andBootBase = pci0Dev3andBootBase & 0xfffff000; + pci0Dev3andBootBase = + pci0Dev3andBootBase | + (pci0ReadConfigReg(PCI_0CS_3_BOOTCS_BASE_ADDRESS, SELF) & + 0x00000fff); + pci0WriteConfigReg(PCI_0CS_3_BOOTCS_BASE_ADDRESS, SELF, + pci0Dev3andBootBase); + /* swapped Bar */ + pci0WriteConfigReg(PCI_0SWAPPED_CS_3_BOOTCS_BASE_ADDRESS, SELF, + pci0Dev3andBootBase); + if (pci0Dev3andBootLength == 0) + pci0Dev3andBootLength++; + GT_REG_WRITE(PCI_0CS_3_BOOTCS_BANK_SIZE, + pci0Dev3andBootLength - 1); +} + +/******************************************************************** +* pci1MapDevices3andBootMemorySpace - Maps PCI1 devices 3 and boot memory +* spaces for the slave. +* For the Discovery there are 2 separate +* fucnction's +* Inputs: base and length of pci1 device3/ boot +*********************************************************************/ + +void pci1MapDevices3andBootMemorySpace(unsigned int pci1Dev3andBootBase, + unsigned int pci1Dev3andBootLength) +{ + pci1Dev3andBootBase = pci1Dev3andBootBase & 0xfffff000; + pci1Dev3andBootBase = + pci1Dev3andBootBase | + (pci1ReadConfigReg(PCI_0CS_3_BOOTCS_BASE_ADDRESS, SELF) & + 0x00000fff); + pci1WriteConfigReg(PCI_0CS_3_BOOTCS_BASE_ADDRESS, SELF, + pci1Dev3andBootBase); + /* swapped Bar */ + pci1WriteConfigReg(PCI_0SWAPPED_CS_3_BOOTCS_BASE_ADDRESS, SELF, + pci1Dev3andBootBase); + if (pci1Dev3andBootLength == 0) + pci1Dev3andBootLength++; + GT_REG_WRITE(PCI_1CS_3_BOOTCS_BANK_SIZE, + pci1Dev3andBootLength - 1); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,318 @@ +/* + * 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) any later version. + */ + +#include "etherboot.h" +#include +#include +#include "pci_etherboot.h" +//#include "gt64120ARegs.h" +#include "galileo_port.h" + +#define MAX_PCI_DEVS 10 +PCI_DEVICE pci0_devices[MAX_PCI_DEVS]; +PCI_DEVICE pci1_devices[MAX_PCI_DEVS]; + +static int pci_range_ck(unsigned char bus, unsigned char dev) +{ + if ((bus == 0) && (dev >= 0) && (dev < 30)) + return 0; // Bus/Device Number OK + + return -1; // Bus/Device Number not OK +} + +/******************************************************************** + * pcibios_(read/write)_config_(byte/word/dword) + * + *Inputs : + *bus - bus number + *dev - device number + *offset - register offset in the configuration space + *val - value to be written / read + * + *Outputs : + *Sucees/Failure + *********************************************************************/ +#define PCI_CFG_DATA ((volatile unsigned long *)0xb4000cfc) +#define PCI_CFG_CTRL ((volatile unsigned long *)0xb4000cf8) + +#define PCI_CFG_SET(dev,fun,off) \ + ((*PCI_CFG_CTRL) = cpu_to_le32((0x80000000 | ((dev)<<11) | ((fun)<<8) | (off)))) + +int pcibios_read_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int *val) +{ + + if (offset & 0x3) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + if (pci_range_ck(bus, dev)) { + *val = 0xFFFFFFFF; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, 0, offset); + if (dev != 0) { + *val = *PCI_CFG_DATA; + } else { + *val = cpu_to_le32(*PCI_CFG_DATA); + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short *val) +{ + if (offset & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck(bus, dev)) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, 0, (offset & ~0x3)); + if (dev != 0) { + *val = *PCI_CFG_DATA >> ((offset & 3) * 8); + } else { + *val = cpu_to_le32(*PCI_CFG_DATA) >> ((offset & 3) * 8); + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char *val) +{ + if (pci_range_ck(bus, dev)) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + PCI_CFG_SET(dev, 0, (offset & ~0x3)); + if (dev != 0) { + *val = *PCI_CFG_DATA >> ((offset & 3) * 8); + } else { + *val = cpu_to_le32(*PCI_CFG_DATA >> ((offset & 3) * 8)); + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int val) +{ + if (offset & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, 0, offset); + if (dev != 0) { + *PCI_CFG_DATA = val; + } else { + *PCI_CFG_DATA = cpu_to_le32(val); + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short val) +{ + unsigned long tmp; + + if (offset & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, 0, (offset & ~0x3)); + if (dev != 0) { + tmp = *PCI_CFG_DATA; + } else { + tmp = cpu_to_le32(*PCI_CFG_DATA); + } + tmp &= ~(0xffff << ((offset & 0x3) * 8)); + tmp |= (val << ((offset & 0x3) * 8)); + if (dev != 0) { + *PCI_CFG_DATA = tmp; + } else { + *PCI_CFG_DATA = cpu_to_le32(tmp); + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char val) +{ + unsigned long tmp; + + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + PCI_CFG_SET(dev, 0, (offset & ~0x3)); + if (dev != 0) { + tmp = *PCI_CFG_DATA; + } else { + tmp = cpu_to_le32(*PCI_CFG_DATA); + } + tmp &= ~(0xff << ((offset & 0x3) * 8)); + tmp |= (val << ((offset & 0x3) * 8)); + *PCI_CFG_DATA = cpu_to_le32(tmp); + return PCIBIOS_SUCCESSFUL; +} + + +/******************************************************************** + * eth_pci_init - Fill pci_devi + * + *Inputs : + *bus - bus number + *dev - device number + *offset - register offset in the configuration space + *val - value to be written / read + * + *Outputs : + *Sucees/Failure + *********************************************************************/ +void eth_pci_init(struct pci_device *pcidev) +{ + int i, count; + pcibios_write_config_word(0, 0, 4, 0x7); + pcibios_write_config_dword(0, 8, BAR0, 0x12000000); + pcibios_write_config_dword(0, 8, BAR1, 0x10000001); + pcibios_write_config_dword(0, 8, BAR2, 0x12100000); + strcpy(pci0_devices[0].type, "Network Controller"); + pci0_devices[0].deviceNum = 8; + pci0_devices[0].venID = 0x8086; + pci0_devices[0].deviceID = 0x1229; + + pci0_devices[0].bar0Base = 0x12000000; + pci0_devices[0].bar0Size = 0x00001000; + pci0_devices[0].bar0Type = 0; + pci0_devices[0].bar1Base = 0x10000000; + pci0_devices[0].bar1Size = 0x40; + pci0_devices[0].bar1Type = 1; + pci0_devices[0].bar2Base = 0x12100000; + pci0_devices[0].bar2Size = 0x00100000; + pci0_devices[0].bar2Type = 0; + for (i = 0; pcidev[i].vendor != 0; i++) { + /* Look for device in PCI0 first */ + for (count = 0; count < MAX_PCI_DEVS; count++) { + if ((pci0_devices[count].type[0] != 0) + && ((unsigned short) pci0_devices[count]. + venID == (unsigned short) pcidev[i].vendor) + && ((unsigned short) pci0_devices[count]. + deviceID == + (unsigned short) pcidev[i].dev_id)) { + if ((pci0_devices[count].bar0Type == 1) + && (pci0_devices[count].bar0Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar0Base; + if ((pci0_devices[count].bar1Type == 1) + && (pci0_devices[count].bar1Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar1Base; + if ((pci0_devices[count].bar2Type == 1) + && (pci0_devices[count].bar2Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar2Base; + if ((pci0_devices[count].bar3Type == 1) + && (pci0_devices[count].bar3Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar3Base; + if ((pci0_devices[count].bar4Type == 1) + && (pci0_devices[count].bar4Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar4Base; + if ((pci0_devices[count].bar5Type == 1) + && (pci0_devices[count].bar5Size != 0)) + pcidev[i].ioaddr = + pci0_devices[count].bar5Base; + + if ((pci0_devices[count].bar0Type == 0) + && (pci0_devices[count].bar0Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar0Base; + if ((pci0_devices[count].bar1Type == 0) + && (pci0_devices[count].bar1Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar1Base; + if ((pci0_devices[count].bar2Type == 0) + && (pci0_devices[count].bar2Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar2Base; + if ((pci0_devices[count].bar3Type == 0) + && (pci0_devices[count].bar3Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar3Base; + if ((pci0_devices[count].bar4Type == 0) + && (pci0_devices[count].bar4Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar4Base; + if ((pci0_devices[count].bar5Type == 0) + && (pci0_devices[count].bar5Size != 0)) + pcidev[i].membase = + pci0_devices[count].bar5Base; + pcidev[i].bus = 0; + pcidev[i].devfn = + pci0_devices[count].deviceNum; + } +#ifdef CONFIG_EVB_PCI1 + if ((pci1_devices[count].type[0] != 0) + && (pci1_devices[count].venID == + pcidev[i].vendor) + && (pci1_devices[count].deviceID == + pcidev[i].dev_id)) { + if ((pci1_devices[count].bar0Type == 1) + && (pci1_devices[count].bar0Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar0Base; + if ((pci1_devices[count].bar1Type == 1) + && (pci1_devices[count].bar1Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar1Base; + if ((pci1_devices[count].bar2Type == 1) + && (pci1_devices[count].bar2Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar2Base; + if ((pci1_devices[count].bar3Type == 1) + && (pci1_devices[count].bar3Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar3Base; + if ((pci1_devices[count].bar4Type == 1) + && (pci1_devices[count].bar4Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar4Base; + if ((pci1_devices[count].bar5Type == 1) + && (pci1_devices[count].bar5Size != 0)) + pcidev[i].ioaddr = + pci1_devices[count].bar5Base; + + if ((pci1_devices[count].bar0Type == 0) + && (pci1_devices[count].bar0Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar0Base; + if ((pci1_devices[count].bar1Type == 0) + && (pci1_devices[count].bar1Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar1Base; + if ((pci1_devices[count].bar2Type == 0) + && (pci1_devices[count].bar2Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar2Base; + if ((pci1_devices[count].bar3Type == 0) + && (pci1_devices[count].bar3Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar3Base; + if ((pci1_devices[count].bar4Type == 0) + && (pci1_devices[count].bar4Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar4Base; + if ((pci1_devices[count].bar5Type == 0) + && (pci1_devices[count].bar5Size != 0)) + pcidev[i].membase = + pci1_devices[count].bar5Base; + + pcidev[i].bus = 1; + pcidev[i].devfn = + pci1_devices[count].deviceNum; + } +#endif + } + } +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/pci_etherboot.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,144 @@ +#ifndef PCI_H +#define PCI_H + +/* +** Support for NE2000 PCI clones added David Monro June 1997 +** Generalised for other PCI NICs by Ken Yap July 1997 +** +** Most of this is taken from: +** +** /usr/src/linux/drivers/pci/pci.c +** /usr/src/linux/include/linux/pci.h +** /usr/src/linux/arch/i386/bios32.c +** /usr/src/linux/include/linux/bios32.h +** /usr/src/linux/drivers/net/ne.c +*/ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ + +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ + + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ + +#define PCI_CLASS_CODE 0x0b /* 8 bits */ +#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ + +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */ +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */ +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ + +#ifndef PCI_BASE_ADDRESS_IO_MASK +#define PCI_BASE_ADDRESS_IO_MASK (~0x03) +#endif +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 +#define PCI_ROM_ADDRESS 0x30 /* 32 bits */ +#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM, + bits 31..11 are address, + 10..2 are reserved */ + +#define PCI_FUNC(devfn) ((devfn) & 0x07) + +#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) + +/* PCI signature: "PCI " */ +#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24)) + +/* PCI service signature: "$PCI" */ +#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24)) + +#define KERN_CODE_SEG 0x8 /* This _MUST_ match start.S */ + +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8029 0x8029 +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 +#define PCI_VENDOR_ID_WINBOND2 0x1050 +#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401 +#define PCI_VENDOR_ID_KTI 0x8e2e +#define PCI_DEVICE_ID_KTI_ET32P2 0x3000 +#define PCI_VENDOR_ID_NETVIN 0x4a14 +#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000 +#define PCI_VENDOR_ID_3COM 0x10b7 +#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000 +#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001 +#define PCI_DEVICE_ID_3COM_3C905TX 0x9050 +#define PCI_DEVICE_ID_3COM_3C905T4 0x9051 +#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055 +#define PCI_DEVICE_ID_3COM_3C905C_TXM 0x9200 +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_VENDOR_ID_SMC_1211 0x1113 +#define PCI_DEVICE_ID_SMC_1211 0x1211 +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_TULIP 0x0002 +#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 +#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 +#define PCI_DEVICE_ID_DEC_21142 0x0019 +#define PCI_VENDOR_ID_SMC 0x10B8 +#ifndef PCI_DEVICE_ID_SMC_EPIC100 +# define PCI_DEVICE_ID_SMC_EPIC100 0x0005 +#endif +#define PCI_VENDOR_ID_MACRONIX 0x10d9 +#define PCI_DEVICE_ID_MX987x5 0x0531 +#define PCI_VENDOR_ID_LINKSYS 0x11AD +#define PCI_DEVICE_ID_LC82C115 0xC115 +#define PCI_VENDOR_ID_VIATEC 0x1106 +#define PCI_DEVICE_ID_VIA_RHINE_I 0x3043 +#define PCI_DEVICE_ID_VIA_86C100A 0x6100 +#define PCI_VENDOR_ID_DAVICOM 0x1282 +#define PCI_DEVICE_ID_DM9102 0x9102 + +struct pci_device { + unsigned short vendor, dev_id; + const char *name; + unsigned int membase; + unsigned int ioaddr; + unsigned short devfn; + unsigned short bus; +}; + +extern void eth_pci_init(struct pci_device *); +int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char *val); +int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short *val); +int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int *val); +int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char val); +int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short val); +int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int val); + +/* + * Error values that may be returned by the PCI bios. + */ +#define PCIBIOS_SUCCESSFUL 0x00 +#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 +#define PCIBIOS_BAD_VENDOR_ID 0x83 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 +#define PCIBIOS_SET_FAILED 0x88 +#define PCIBIOS_BUFFER_TOO_SMALL 0x89 + + + +#endif /* PCI_H */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/sbd.h linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/sbd.h --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/sbd.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/sbd.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,52 @@ +/* + * sbd.h: cpu board definitions for Galileo-9 + * Copyright (c) 1997 Algorithmics Ltd + */ + +#ifndef MHZ +/* fastest possible pipeline clock */ +#define MHZ 150 +#endif + +/* FIXME These timings are completely fictional */ +#define RAMCYCLE 60 /* 60ns dram cycle */ +#define ROMCYCLE 750 /* ~750ns rom cycle */ +#define CACHECYCLE (1000/MHZ) /* internal clock */ +#define CYCLETIME CACHECYCLE +#define CACHEMISS (CYCLETIME * 6) + +/* + * rough scaling factors for 2 instruction DELAY loop to get 1ms and 1us delays + */ +#define ASMDELAY(ns,icycle) \ + (((ns) + (icycle)) / ((icycle) * 2)) + +#define CACHEUS ASMDELAY(1000, CACHECYCLE) +#define RAMUS ASMDELAY(1000, CACHEMISS+RAMCYCLE) +#define ROMUS ASMDELAY(1000, CACHEMISS+ROMCYCLE) +#define CACHEMS ASMDELAY(1000000, CACHECYCLE) +#define RAMMS ASMDELAY(1000000, CACHEMISS+RAMCYCLE) +#define ROMMS ASMDELAY(1000000, CACHEMISS+ROMCYCLE) + +#ifndef __ASSEMBLER__ +#define nsdelay(ns) mips_cycle (ASMDELAY (ns, CACHECYCLE)) +#define usdelay(us) mips_cycle (ASMDELAY ((us)*1000, CACHECYCLE)) +#endif + +#define DRAM_BASE 0x00000000 +#define PCI_IO_BASE 0x10000000 +#define PCI_IO_SIZE 0x02000000 +#define PCI_MEM_BASE 0x12000000 +#define PCI_MEM_SIZE 0x02000000 +#define GT64011_BASE 0x14000000 +#define DUART_BASE 0x1d000000 +#define FLASH_BASE 0x1f000000 +#define PROM_BASE 0x1fc00000 + + +#define LOCAL_MEM DRAM_BASE +#define LOCAL_MEM_SIZE (128*1024*1024) /* SDRAM size (16MB) */ + +#define BOOTPROM_BASE PROM_BASE + +#define DUART_CLOCK 3686400 diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/sbdreset_evb64120A.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1050 @@ +/* + * Copyright 1997 Algorithmics Ltd + * All Rights Reserved + * + * gal9/sbdreset.sx -- low level board dependent routines + */ + +#ifdef EVB64120A +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sbd.h" + + +#include "gt64011.h" +#include "ns16550.h" + +#ifdef GALILEO_PORT // miniBios crack +#define C0_CONFIG CP0_CONFIG +#define C0_STATUS CP0_STATUS +#define C0_TLBLO0 CP0_ENTRYLO0 +#define C0_TLBLO1 CP0_ENTRYLO1 +#define C0_PGMASK CP0_PAGEMASK +#define C0_TLBHI CP0_ENTRYHI +#define C0_INX CP0_INDEX +#define NTLBENTRIES 48 + + +#define CFG_IB CONF_IB +#define CFG_DB CONF_DB +#define CFG_C_NONCOHERENT CONF_CM_CACHABLE_NONCOHERENT +#define C0_SR CP0_STATUS +#define SR_DE ST0_DE + + + #define SLEAF(x) LEAF(x) + #define SEND(x) END(x) + #define XLEAF(x) LEAF(x) + #define SBD_DISPLAY(a,b,c,d,e) ; + +#define K0BASE 0x80000000 +#define K0SIZE 0x20000000 +#define K1BASE 0xa0000000 +#define K1SIZE 0x20000000 +#define K2BASE 0xc0000000 + +#define PHYS_TO_K0(pa) ((pa)|K0BASE) +#define PHYS_TO_K1(pa) ((pa)|K1BASE) +#define K0_TO_PHYS(va) ((va)&(K0SIZE-1)) +#define K1_TO_PHYS(va) ((va)&(K1SIZE-1)) +#define K0_TO_K1(va) ((va)|K1SIZE) +#define K1_TO_K0(va) ((va)&~K1SIZE) + +#define PA_TO_KVA0(pa) PHYS_TO_K0(pa) +#define PA_TO_KVA1(pa) PHYS_TO_K1(pa) +#define KVA_TO_PA(pa) K1_TO_PHYS(pa) +#define KSEG0_BASE K0BASE +#define KSEG1_BASE K1BASE + + +#endif + +#define MB 0x100000 + +#define MemTypeNone 0x8000 +#define MemRasMask 0x0f00 +#define MemRasShift 8 +#define MemCasMask 0x000f +#define MemCasShift 0 + +#define rasave s0 +#define p64011 s1 +#define bank0 s2 +#define bank1 s3 +#define bank2 s4 +#define bank3 s5 +#define memtop s6 +#define membase s7 + +/*#if #endian(big) */ +#ifdef __MIPSEB__ + +#define HTOLL(sr,tr) \ + .set noat ; \ + srl AT,sr,24 ; \ + srl tr,sr,8 ; \ + and tr,0xff00 ; \ + or AT,tr ; \ + and tr,sr,0xff00 ; \ + sll tr,8 ; \ + or AT,tr ; \ + sll tr,sr,24 ; \ + or sr,AT,tr ; \ + .set at +#else +#define HTOLL(sr,tr) +#endif + +#undef DBGSBD + +#ifdef DBGSBD +#define DBG(s) \ + .rdata ; \ +88: .asciiz s ; \ + .text ; \ + la a0, 88b ; \ + jal _dbgmsg + +LEAF(_dbgmsg) + .set noat + li AT,PHYS_TO_K1(NS16550_CHANB) +waitrdy: + lbu v1,LSR(AT) + .set noreorder; nop; nop; nop; nop; nop; nop; nop; nop; .set reorder + and v1,LSR_TXRDY + beqz v1,waitrdy + + lbu v1,(a0) + addu a0,1 + beqz v1,9f + sb v1,DATA(AT) + .set noreorder; nop; nop; nop; nop; nop; nop; nop; nop; .set reorder + b waitrdy +9: j ra + .set at +END(_dbgmsg) + +LEAF(_dbghex) + li a1,PHYS_TO_K1(NS16550_CHANB) + li t0,8 +1: + lbu t1,LSR(a1) + .set noreorder; nop; nop; nop; nop; nop; nop; nop; nop; .set reorder + and t1,LSR_TXRDY + beqz t1,1b + + srl t1,a0,28 + addu t1,'0' + ble t1,'9',2f + addu t1,'a'-'0'-10 +2: sb t1,DATA(a1) + .set noreorder; nop; nop; nop; nop; nop; nop; nop; nop; .set reorder + + sll a0,4 + sub t0,1 + bnez t0,1b + + j ra + .set at +END(_dbghex) + + .rdata +initb_str: + .byte 9,0x40 /* Reset CH B */ + .byte 1,0x00 /* Interrupt disabled */ + .byte 3,0xc1 /* 8 bits/char rx enable */ + .byte 4,0x44 /* x16 clk mode 1 stop bit */ + .byte 5,0x6a /* tx 8/bit RTS & tx enable */ + .byte 9,0x0a /* MIE Master int enab. and NV No Vector */ + .byte 11,0x50 /* Select BR gen. out for both rx and ts */ + .byte 0,0x10 + .byte 0,0x10 + .byte 14,0x01 /* enable baud rate gen. */ + .byte 15,0x00 /* known state for reg 15 */ + + .byte 14,0x00 /* disable baud rate gen. */ + .byte 12,0x0a /* 0x0a = 9600 baud time const. - lower 8 bits */ + .byte 13,0x00 /* 9600 buad time const. - upper 8 bits */ + .byte 14,0x01 /* enable baud rate gen. */ + .byte 0xff + + .text + +SLEAF(_dbginit) + /* + li v0,PHYS_TO_K1(NS16550_CHANB) + la a0,initb_str + or a0,K1BASE +1: lbu t0,0(a0) + beq t0,0xff,1f + sb t0,LSR(v0) + .set noreorder; nop; nop; nop; nop; nop; nop; nop; nop; .set reorder + addu a0,1 + b 1b + */ + jal init_ns16550_chan_b # Debug channel + j ra +SEND(_dbginit) +#else +#define DBG(s) +#endif + +LEAF(sbdreset) + move rasave,ra + + /* if launched by ITROM, leave Config alone */ +#ifndef ITBASE + /* set config register for 32b/32b cachelines, kseg0 cacheable */ + mfc0 t1,C0_CONFIG + and t1,~0x3f # set bits 5..0 only + or t1,CFG_IB | CFG_DB | CFG_C_NONCOHERENT + mtc0 t1,C0_CONFIG +#endif + + /* Initialize stack pointer to 6MB address */ + li sp,0xa0600000 + + + /* + * slight amount of kludgery here to stop RAM resident + * program from overwriting itself... + */ +// li v1,0x1fc00000 /* check return address is in ROM */ +// and v0,ra,v1 +// bne v0,v1,.noinit + + /* table driven hardware register initialization */ + la a0, reginittab + or a0, K1BASE /* force to kseg1 */ + +1: lw v0,0(a0) + lw v1,4(a0) + addu a0,8 + beqz v0,8f + + sw v1,0(v0) + b 1b +8: + +#ifdef DBGSBD + jal init_ns16550_chan_b # was - _dbginit + DBG("sbdreset\r\n") +#endif +#define DEVICE_BANK0PARAMETERS 0x45C +#define DEVICE_BANK1PARAMETERS 0x460 +#define DEVICE_BANK2PARAMETERS 0x464 +#define DEVICE_BANK3PARAMETERS 0x468 +#define DEVICE_BOOT_BANK_PARAMETERS 0x46C +#define GT_INTERNAL_REG_BASE 0xb4000000 + + li p64011, PA_TO_KVA1(GT64011_BASE) + + li v0,0xb400046c /* Boot Device */ + lw t0,0(v0) + and t0,0x00003000 /* Keep the correct boot size */ + or t0,htoll(0x3847de70) + sw t0,0(v0) + + li v0,0xb4000468 /* CS3 Device - 16 bit FLASH memory */ + li t0,htoll(0x3859e6e8) + sw t0,0(v0) + + + li v0,0xb4000c84 /* PCI 1 timeout register */ + li t0,htoll(0xffff) + sw t0,0(v0) + + + li v0,0xb4000c3c /* Enable I/O response on PCI0 */ + li t0,htoll(0x7) + sw t0,0(v0) + + li v0,0xb4000cbc /* Enable I/O response on PCI1 */ + li t0,htoll(0x7) + sw t0,0(v0) + + /* GT-64120 Initialization */ + + li p64011, PA_TO_KVA1(GT64011_BASE) + + /*********************************************************************/ + /************************* SDRAM initializing ************************/ + /******************************* START *******************************/ + + + /* SDRAM banks 0,1,2,3 parameters */ + li t0,htoll(0x01908200) /* - Standard Monitor: Interleave enabled */ + li v0,0xb4000448 /* - Registered SDRAM (Bit 23) */ + sw t0,0(v0) /* - Duplicate Dadr11,BankSel1 and Dadr12 */ + /* - Cas latency: 2 Cycles */ + /* - Flow Through enable: One sample */ + /* - SRAS - precharge time: 3 Cycles */ + /* - No ECC */ + /* - No ByPass */ + /* - Burst length: 8 */ + + /* Detect whether we have a 16,64,128 or 256 Mbit SDRAM on DIMM0 */ + /* Set bank0`s range to: 0 - 0x10000000 (256 MByte) */ +_DIMM0: + li v0,0xb4000008 + li t0,htoll(0x0) + sw t0,0(v0) + + li v0,0xb4000010 + li t0,htoll(0x7f) + sw t0,0(v0) + + /* Close banks 2 and 3 */ + li v0,0xb4000018 + li t0,htoll(0x7ff) + sw t0,0(v0) + li v0,0xb4000020 + li t0,htoll(0x00) + sw t0,0(v0) + + /* Extend bank0 to 0x10000000 and Close bank1,2 and 3 */ + DBG("Extend bank0 to 0x10000000 and Close bank1,2 and 3...\r\n") + li v0,0xb4000400 + li t0,htoll(0x0) + sw t0,0(v0) + li v0,0xb4000404 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb4000408 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb400040c + li t0,htoll(0x00) + sw t0,0(v0) + li v0,0xb4000410 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb4000414 + li t0,htoll(0x00) + sw t0,0(v0) + li v0,0xb4000418 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb400041c + li t0,htoll(0x00) + sw t0,0(v0) + + /* Configure bank0 to 256 Mbit */ + DBG("Configure bank0 to 256 Mbit...\r\n") + li v0,0xb400044c + li t0,htoll(0x00004c69) + sw t0,0(v0) + + /* Config the SDRAM banks decode system */ + li v0,0xb400047c + li t0,htoll(2) + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa0000000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + /* Write to address 0x2000000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x2000000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate Dadr12 */ + li v0,0xa2000000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + bne t0,v0,_256MBIT + + /* Write to address 0x1000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x1000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate bank select1*/ + li v0,0xa0001000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + beq t0,v0,_16MBIT + + /* Write to address 0x8000000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x8000000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate Dadr9 which on the column cycle is in active with 64 Mbit + device */ + li v0,0xa8000000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + beq t0,v0,_64MBIT + b _128MBIT + +_16MBIT: + DBG("16 Mbit SDRAM detected...\r\n") + /* In 16 Mbit SDRAM we must use 2 way bank interleaving!!! */ + li v0,0xb4000810 + li t0,htoll(16) + sw t0,0(v0) + li t1,htoll(0x00000449) + b _DIMM1 + +_64MBIT: + DBG("64 Mbit SDRAM detected...\r\n") + /* In 64 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000810 + li t0,htoll(64) + sw t0,0(v0) + li t1,htoll(0x00000c69) + b _DIMM1 + +_128MBIT: + DBG("128 Mbit SDRAM detected...\r\n") + /* In 128 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000810 + li t0,htoll(128) + sw t0,0(v0) + li t1,htoll(0x00000c69) + b _DIMM1 + +_256MBIT: + DBG("256 Mbit SDRAM detected...\r\n") + /* In 256 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000810 + li t0,htoll(256) + sw t0,0(v0) + li t1,htoll(0x00004c69) + b _DIMM1 + +_DIMM1: + li v0,0xb400044c + sw t1,0(v0) # Bank0 + sw t1,4(v0) # Bank1 + + /* Detect whether we have a 16,64,128 or 256 Mbit SDRAM on DIMM1 */ + /* Close banks 0 and 1 */ + li v0,0xb4000008 + li t0,htoll(0xff) + sw t0,0(v0) + + li v0,0xb4000010 + li t0,htoll(0x0) + sw t0,0(v0) + + /* Set bank2`s range to: 0 - 0x10000000 (256 MByte) */ + li v0,0xb4000018 + li t0,htoll(0x0) + sw t0,0(v0) + li v0,0xb4000020 + li t0,htoll(0x7f) + sw t0,0(v0) + + /* Extend bank2 to 0x10000000 and Close bank0,1 and 3 */ + DBG("Extend bank2 to 0x10000000 and Close banks 0,1 and 3...\r\n") + li v0,0xb4000400 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb4000404 + li t0,htoll(0x00) + sw t0,0(v0) + li v0,0xb4000408 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb400040c + li t0,htoll(0x00) + sw t0,0(v0) + li v0,0xb4000410 + li t0,htoll(0x00) + sw t0,0(v0) + li v0,0xb4000414 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb4000418 + li t0,htoll(0xff) + sw t0,0(v0) + li v0,0xb400041c + li t0,htoll(0x00) + sw t0,0(v0) + + /* Configure bank2 to 256 Mbit */ + DBG("Configure bank2 to 256 Mbit...\r\n") + li v0,0xb4000454 + li t0,htoll(0x00004c69) + sw t0,0(v0) + + /* Config the SDRAM banks decode system */ + li v0,0xb400047c + li t0,htoll(2) + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa0000000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + /* Write to address 0x2000000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x2000000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate Dadr12 */ + li v0,0xa2000000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + bne t0,v0,_256MBIT2 + + /* Write to address 0x1000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x1000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate bank select1*/ + li v0,0xa0001000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + beq t0,v0,_16MBIT2 + + /* Write to address 0x8000000 and check if 0x00000000 is being written too */ + DBG("Write to address 0x8000000 and check if 0x00000000 is being written too...\r\n") + li v0,0xa0000000 + li t1,0xa0000010 + li t0,htoll(0x0) +1: sw t0,0(v0) + addu v0,4 + bne t1,v0,1b + + /* The address should activate Dadr9 which on the column cycle is in active with 64 Mbit + device */ + li v0,0xa8000000 + li t0,0x11111111 + sw t0,0(v0) + li v0,0xa0000010 + li t1,0xa0000100 + li t0,0x22222222 +2: sw t0,0(v0) + addu v0,4 + bne t1,v0,2b + + DBG("Check address 0x00000000 for duplications...\r\n") + li t0,0xa0000000 + li v0,0x11111111 + lw t0,(t0) + beq t0,v0,_64MBIT2 + b _128MBIT2 + +_16MBIT2: + DBG("16 Mbit SDRAM detected...\r\n") + /* In 16 Mbit SDRAM we must use 2 way bank interleaving!!! */ + li v0,0xb4000814 + li t0,htoll(16) + sw t0,0(v0) + li t1,htoll(0x00000449) + b _INIT_SDRAM + +_64MBIT2: + DBG("64 Mbit SDRAM detected...\r\n") + /* In 64 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000814 + li t0,htoll(64) + sw t0,0(v0) + li t1,htoll(0x00000c69) + b _INIT_SDRAM + +_128MBIT2: + DBG("128 Mbit SDRAM detected...\r\n") + /* In 128 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000814 + li t0,htoll(128) + sw t0,0(v0) + li t1,htoll(0x00000c69) + b _INIT_SDRAM + +_256MBIT2: + DBG("256 Mbit SDRAM detected...\r\n") + /* In 256 Mbit SDRAM we must use 4 way bank interleaving!!! */ + li v0,0xb4000814 + li t0,htoll(256) + sw t0,0(v0) + li t1,htoll(0x00004c69) + b _INIT_SDRAM + +_INIT_SDRAM: + /* Restore defaults */ + DBG("Restoring defaults...\r\n") + li v0,0xb4000404 + li t0,htoll(0x07) + sw t0,0(v0) + li v0,0xb4000408 + li t0,htoll(0x08) + sw t0,0(v0) + li v0,0xb400040c + li t0,htoll(0x0f) + sw t0,0(v0) + li v0,0xb4000410 + li t0,htoll(0x10) + sw t0,0(v0) + li v0,0xb4000414 + li t0,htoll(0x17) + sw t0,0(v0) + li v0,0xb4000418 + li t0,htoll(0x18) + sw t0,0(v0) + li v0,0xb400041c + li t0,htoll(0x1f) + sw t0,0(v0) + li v0,0xb4000010 + li t0,htoll(0x07) + sw t0,0(v0) + li v0,0xb4000018 + li t0,htoll(0x008) + sw t0,0(v0) + li v0,0xb4000020 + li t0,htoll(0x0f) + sw t0,0(v0) + + li v0,0xb400044c + sw t1,8(v0) # Bank2 + sw t1,12(v0) # Bank3 + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa0000000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa0800000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa1000000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x3) + sw t0,0(v0) + + li v0,0xa1800000 + li t0,0 + sw t0,0(v0) + + li v0,0xb4000474 + li t0,htoll(0x0) + sw t0,0(v0) + + /*********************************************************************/ + /************************* SDRAM initializing ************************/ + /******************************* END *********************************/ + + li p64011, PA_TO_KVA1(GT64011_BASE) + + li t0,htoll(0x00000000) /* RAS[1:0] low decode address */ + sw t0,0x008(p64011) + + li t0,htoll(0x00000007) /* RAS[1:0] high decode address */ + sw t0,0x010(p64011) + + li t0,htoll(0x00000000) /* RAS[0] Low decode address */ + sw t0,0x400(p64011) + + li t0,htoll(0x0000000f) /* RAS[0] High decode address */ + sw t0,0x404(p64011) + + li t0,htoll(0x00000008) /* RAS[3:2] low decode address */ + sw t0,0x018(p64011) + + li t0,htoll(0x0000000f) /* RAS[3:2] high decode address */ + sw t0,0x020(p64011) + + li t0,htoll(0x0000000f) /* RAS[1] Low Decode Address */ + sw t0,0x408(p64011) + + li t0,htoll(0x00000008) /* RAS[1] High Decode Address */ + sw t0,0x40c(p64011) + + li t0,htoll(0x00000010) /* RAS[2] Low Decode Address */ + sw t0,0x410(p64011) + + li t0,htoll(0x00000017) /* RAS[2] High Decode Address */ + sw t0,0x414(p64011) + + li t0,htoll(0x00000018) /* RAS[3] Low Decode Address */ + sw t0,0x418(p64011) + + li t0,htoll(0x0000001f) /* RAS[3] High Decode Address <<<<<< 1*/ + sw t0,0x41c(p64011) + +#ifdef DBGSBD +#define DREG(str,rname) \ + DBG(str); \ + DBG(":\t") ; \ + lw a0,rname(p64011) ; \ + HTOLL(a0,t0) ; \ + jal _dbghex ; \ + DBG("\r\n") + + DBG("GT-64120 settings:\r\n") + DREG("DRAMPAR_BANK0 (44c)",GT_DRAMPAR_BANK0) + DREG("DRAMPAR_BANK1 (450)",GT_DRAMPAR_BANK1) + DREG("DRAMPAR_BANK2 (454)",GT_DRAMPAR_BANK2) + DREG("DRAMPAR_BANK3 (458)",GT_DRAMPAR_BANK3) + DREG("PAS_RAS10LO (008)",GT_PAS_RAS10LO) + DREG("PAS_RAS10HI (010)",GT_PAS_RAS10HI) + DREG("PAS_RAS32LO (018)",GT_PAS_RAS32LO) + DREG("PAS_RAS32HI (020)",GT_PAS_RAS32HI) + DREG("DDAS_RAS0LO (400)",GT_DDAS_RAS0LO) + DREG("DDAS_RAS0HI (404)",GT_DDAS_RAS0HI) + DREG("DDAS_RAS1LO (408)",GT_DDAS_RAS1LO) + DREG("DDAS_RAS1HI (40c)",GT_DDAS_RAS1HI) + DREG("DDAS_RAS2LO (410)",GT_DDAS_RAS2LO) + DREG("DDAS_RAS2HI (414)",GT_DDAS_RAS2HI) + DREG("DDAS_RAS3LO (418)",GT_DDAS_RAS3LO) + DREG("DDAS_RAS3HI (41c)",GT_DDAS_RAS3HI) + DREG("GT_DRAM_CFG (448)",GT_DRAM_CFG) + DREG("GT_DEVPAR_BANK0 (45c)",GT_DEVPAR_BANK0) + DREG("GT_DEVPAR_BANK1 (460)",GT_DEVPAR_BANK1) + DREG("GT_DEVPAR_BANK2 (464)",GT_DEVPAR_BANK2) + DREG("GT_DEVPAR_BANK3 (468)",GT_DEVPAR_BANK3) + DREG("GT_IPCI_TOR (c04)",GT_IPCI_TOR) +#endif + + /* we can now initialise the caches for a fast clear_mem */ + SBD_DISPLAY ('C','A','C','H',CHKPNT_CACH) + DBG("init_cache\r\n") +// jal mips_init_cache + +.noinit: + + /* initialise tlb */ + SBD_DISPLAY ('I','T','L','B', CHKPNT_ITLB) + DBG("init_tlb\r\n") +// bal init_tlb + +// DBG("sbdreset completed\r\n") +// move ra,rasave + j GetExtendedMemorySize + nop + +END(sbdreset) + +LEAF(_sbd_memfail) + SBD_DISPLAY ('!','M','E','M',CHKPNT_0MEM) +1: b 1b + j ra +END(_sbd_memfail) + + .rdata +RefreshBits: + .word htoll(GT_DRAMPAR_Refresh512) + .word htoll(GT_DRAMPAR_Refresh1024) + .word htoll(GT_DRAMPAR_Refresh2048) + .word htoll(GT_DRAMPAR_Refresh4096) + .text + +/* DRAM: */ +#define GT_DRAM_CFG_INIT \ + GT_DRAM_CFG_RefIntCnt(160) | \ + GT_DRAM_CFG_StagRefOn | \ + GT_DRAM_CFG_ADSFunctDRAM | \ + GT_DRAM_CFG_DRAMLatchActive + +/* serial port: widest timings even 8 bit bus, latch enabled no parity */ +#define GT_DEVPAR_SERIALINIT \ + GT_DEVPAR_TurnOff(7) | \ + GT_DEVPAR_AccToFirst(15) | \ + GT_DEVPAR_AccToNext(15) | \ + GT_DEVPAR_ADStoWr(7) | \ + GT_DEVPAR_WrActive(7) | \ + GT_DEVPAR_WrHigh(7) | \ + GT_DEVPAR_DevWidth8 | \ + GT_DEVPAR_DevLocEven | \ + GT_DEVPAR_LatchFunctTransparent | \ + GT_DEVPAR_ParityDisable | \ + GT_DEVPAR_Reserved + +/* PCI: */ +#define GT_IPCI_TOR_INIT \ + GT_IPCI_TOR_Timeout0(255) | \ + GT_IPCI_TOR_Timeout1(255) | \ + GT_IPCI_TOR_RetryCtr(0) + +#define INIT(addr,val) \ + .word addr, val +#define GTINIT(addr,val) \ + INIT(PHYS_TO_K1(GT64011_BASE+(addr)), htoll(val)) + + .rdata +reginittab: + + /* disable ras1:0 and ras3:2 decodes */ + GTINIT(GT_PAS_RAS10LO, GT_PAS_LOMASK_Low); + GTINIT(GT_PAS_RAS10HI, 0); + GTINIT(GT_PAS_RAS32LO, GT_PAS_LOMASK_Low); + GTINIT(GT_PAS_RAS32HI, 0); + + /* disable RAS[0123] */ + GTINIT(GT_DDAS_RAS0LO, GT_DDAS_LOMASK_Low) + GTINIT(GT_DDAS_RAS0HI, 0); + GTINIT(GT_DDAS_RAS1LO, GT_DDAS_LOMASK_Low) + GTINIT(GT_DDAS_RAS1HI, 0); + GTINIT(GT_DDAS_RAS2LO, GT_DDAS_LOMASK_Low) + GTINIT(GT_DDAS_RAS2HI, 0); + GTINIT(GT_DDAS_RAS3LO, GT_DDAS_LOMASK_Low) + GTINIT(GT_DDAS_RAS3HI, 0); + + /* 0x45c, 0x460, 0x464, 0x468 */ + /*GTINIT(GT_DEVPAR_BANK0, GT_DEVPAR_SERIALINIT)*/ + GTINIT(GT_DEVPAR_BANK0, 0x3847de60) + GTINIT(GT_DEVPAR_BANK1, 0x146fffff) + GTINIT(GT_DEVPAR_BANK2, 0x144fffff) + GTINIT(GT_DEVPAR_BANK3, 0x167fffff) + + GTINIT(GT_IPCI_TOR, GT_IPCI_TOR_INIT) + INIT(0,0) + .text + + .globl sbddelay + +LEAF(sbdberrenb) + mfc0 v0,C0_SR + li t0,SR_DE + bnez a0,1f + or t1,v0,t0 # disable cache/parity errors (SR_DE = 1) + b 2f +1: not t1,t0 # enable cache/parity errors (SR_DE = 0) + and t1,v0 +2: mtc0 t1,C0_SR + and v0,t0 # get old SR_DE bit + xor v0,t0 # and invert to make it an enable bit + j ra +END(sbdberrenb) + + +LEAF(sbdberrcnt) + move v0,zero + j ra +END(sbdberrcnt) + + .lcomm wbfltmp,4 + +LEAF(wbflush) +//XLEAF(mips_wbflush) + sync + la t0,wbfltmp + or t0,K1BASE + lw zero,0(t0) + j ra +END(wbflush) + + +LEAF(sbddelay) + li t1,CACHEUS + and t0,ra,0x20000000 + beqz t0,1f + li t1,ROMUS +1: mul a0,t1 + subu a0,15 # approx number of loops so far + + .set noreorder + .set nomacro + nop +2: bgtz a0,2b + subu a0,1 + .set macro + .set reorder + + j ra +END(sbddelay) + +#include "meminit.S" + + +LEAF(mips_cycle) + .set noreorder + .set nomacro +1: bgtz a0,1b + subu a0,1 + .set macro + .set reorder + j ra +END(mips_cycle) + +LEAF(init_ns16550_chan_b) + # enable 16550 fifo if it is there + li a0,NS16550_CHANB + li t0,FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4 + sb t0,FIFO(a0) + + /* convert baud rate in a1 into register value */ + li t2,NS16550_HZ/(16*115200) # brtc = CLK/16/speed + + li t0,CFCR_DLAB # select brtc divisor + sb t0,CFCR(a0) + sb t2,DATA(a0) # store divisor lsb + srl t2,8 + sb t2,IER(a0) # store divisor msb + + li t0,CFCR_8BITS # set 8N1 mode + sb t0,CFCR(a0) + + li t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE # enable DTR & RTS + sb t0,MCR(a0) + li t0,0 # Galileo IER_ERXRDY # enable receive interrupt(!) + sb t0,IER(a0) + + move v0,zero # indicate success + j ra + +END(init_ns16550_chan_b) + +LEAF(init_ns16550_chan_a) + # enable 16550 fifo if it is there + li a0,NS16550_CHANA + li t0,FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4 + sb t0,FIFO(a0) + + /* convert baud rate in a1 into register value */ + li t2,NS16550_HZ/(16*9600) # brtc = CLK/16/speed + + li t0,CFCR_DLAB # select brtc divisor + sb t0,CFCR(a0) + sb t2,DATA(a0) # store divisor lsb + srl t2,8 + sb t2,IER(a0) # store divisor msb + + li t0,CFCR_8BITS # set 8N1 mode + sb t0,CFCR(a0) + + li t0,MCR_DTR|MCR_RTS # Galileo |MCR_IENABLE # enable DTR & RTS + sb t0,MCR(a0) + li t0,0 # Galileo IER_ERXRDY # enable receive interrupt(!) + sb t0,IER(a0) + + move v0,zero # indicate success + j ra + +END(init_ns16550_chan_a) + +#endif /* EVB64120A */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/xfer.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/xfer.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/compressed/xfer.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/compressed/xfer.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,114 @@ +/* + * arch/mips/galileo/compressed/xfer.c + * + * By RidgeRun Inc, + * + * Xfer an image from flash to ram. + * For use with Galileo EVB64120A MIPS eval board. + */ + +#include "linux/serial_reg.h" + +#define port 0xbd000000 +#define inb(addr) (*(volatile unsigned char *) ((unsigned long)(addr))) +#define outb(b,addr) (*(volatile unsigned char *) ((unsigned long)(addr)) = (b)) + +#ifdef RUNNINGFROMFLASH +// This is where our image of interest is mapped to +// when the jumbers are set for booting out of flash. +// (flash part starts at address 0xbfC00000) +#define srcAddr 0xbfC20000 +#else +// This is where our image of interest is mapped to +// when the jumbers are set for booting out of eprom. +// (flash part starts at address 0xbf000000) +#define srcAddr 0xbf020000 +#endif + +static int PortAddress(unsigned int channel, unsigned char reg); +static void inline cons_hook(void); +static void print_message(const char *string); + +/****************************** + Routine: + Description: + ******************************/ +void XferToRam(void) +{ + unsigned int temp; + void (*entry_point) (void); + + cons_hook(); + + print_message("Copying image from Flash to Ram.\n"); + for (temp = 0; temp < (0x100000 - 0x20000); temp = temp + 4) { + *(volatile unsigned int *) (temp + 0xa0400000) = + *(volatile unsigned int *) (temp + srcAddr); + if (*(volatile unsigned int *) (temp + 0xa0400000) != + *(volatile unsigned int *) (temp + srcAddr)) { + print_message + ("Error!: copy verification failed.\n"); + break; + } + } + + print_message("Now jumping to the code just xferred to ram.\n"); + entry_point = (void *) 0x80400000; + entry_point(); +} + +/****************************** + Routine: + Description: + ******************************/ +static int PortAddress(unsigned int channel, unsigned char reg) +{ + unsigned int channelOffset = 0x20; + unsigned int regDelta = 4; + return (port + (channel * channelOffset) + (reg * regDelta)); +} + +/****************************** + Routine: + Description: + ******************************/ +static void cons_hook(void) +{ + register int comstat; + unsigned temp; + unsigned int channel = 1; // Channel 1 is the main serial + // connector of the EVB64120A. Channel 0 + // is the secondary serial port (typically + // the unsoldered connector of the board). + + temp = *(unsigned int *) 0xb4000464; + *(unsigned int *) 0xb4000464 = 0xffff4f14; + + // Set Baud Rate, baud=115K + outb(0x83, PortAddress(channel, UART_LCR)); + outb(0x00, PortAddress(channel, UART_DLM)); + outb(0x02, PortAddress(channel, UART_DLL)); + outb(0x03, PortAddress(channel, UART_LCR)); + + comstat = inb(PortAddress(channel, UART_LSR)); + comstat = inb(PortAddress(channel, UART_RX)); + outb(0x00, PortAddress(channel, UART_IER)); +} + +/****************************** + Routine: + Description: + ******************************/ +static void print_message(const char *string) +{ + register int count, loop; + /* Display Opening Message */ + for (count = 0; string[count]; count++) { + if (string[count] == '\n') { + *(char *) 0xbd000020 = '\r'; + } + *(char *) 0xbd000020 = string[count]; + for (loop = 0; loop < 2000; loop++) { + } + } +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/dma.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/dma.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/dma.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,168 @@ +/* DMA.C - DMA functions and definitions */ + +/* Copyright Galileo Technology. */ + +/* +DESCRIPTION +This file gives the user a complete interface to the powerful DMA engines, +including functions for controling the priority mechanism. +To fully understand the capabilities of the DMA engines please spare some +time to go trough the spec. +*/ + +/* includes */ + +#ifdef __linux__ +#include +#include +#else +#include "Core.h" +#include "DMA.h" +#endif +/******************************************************************** +* dmaCommand - Write a command to a DMA channel +* +* Inputs: DMA_ENGINE channel - choosing one of the four engine. +* unsigned int command - The command to be written to the control register. +* Returns: false if one of the parameters is erroneous else returns true. +*********************************************************************/ + +bool dmaCommand(DMA_ENGINE channel, unsigned int command) +{ + if (channel > LAST_DMA_ENGINE) + return false; + GT_REG_WRITE(CHANNEL0CONTROL + channel * 4, command); + return true; +} + +/******************************************************************** +* dmaTransfer - transfer data from sourceAddr to destAddr on DMA channel +* Inputs: +* DMA_RECORED *nextRecoredPointer: If we are using chain mode DMA transfer, +* then this pointer should point to the next recored,otherwise it should be +* NULL. +* VERY IMPORTANT !!! When using chain mode, the records must be 16 Bytes +* aligned, the function will take care of that for you, but you need to +* allocate one more record for that, meaning: if you are having 3 records , +* declare 4 (see the example bellow) and start using the second one. +* Example: +* Performing a chain mode DMA transfer(Copy a 1/4 mega of data using +* chain mode DMA): +* DMA_RECORED dmaRecoredArray[4]; +* dmaRecoredArray[1].ByteCnt = _64KB; +* dmaRecoredArray[1].DestAdd = destAddress + _64KB; +* dmaRecoredArray[1].SrcAdd = sourceAddress + _64KB; +* dmaRecoredArray[1].NextRecPtr = &dmaRecoredArray[2]; +* dmaRecoredArray[2].ByteCnt = _64KB; +* dmaRecoredArray[2].DestAdd = destAddress + 2*_64KB; +* dmaRecoredArray[2].SrcAdd = sourceAddress + 2*_64KB; +* dmaRecoredArray[2].NextRecPtr = &dmaRecoredArray[3]; +* dmaRecoredArray[3].ByteCnt = _64KB; +* dmaRecoredArray[3].DestAdd = destAddress + 3*_64KB; +* dmaRecoredArray[3].SrcAdd = sourceAddress + 3*_64KB; +* dmaRecoredArray[3].NextRecPtr = NULL; +* performCmDma(0,sourceAddress,destAddress,_64KB,PLAIN,WAIT_TO_END, +* &dmaRecoredArray[1]); +* Returns: NO_SUCH_CHANNEL if channel does not exist, CHANNEL_BUSY if channel +* is active and true if the transfer ended successfully +*********************************************************************/ + +DMA_STATUS dmaTransfer(DMA_ENGINE channel, unsigned int sourceAddr, + unsigned int destAddr, unsigned int numOfBytes, + unsigned int command, + DMA_RECORED * nextRecoredPointer) +{ + unsigned int tempData, checkBits, alignmentOffset = 0; + DMA_RECORED *next = nextRecoredPointer; + + if (channel > LAST_DMA_ENGINE) + return NO_SUCH_CHANNEL; + if (numOfBytes > 0xffff) + return GENERAL_ERROR; + if (isDmaChannelActive(channel)) + return CHANNEL_BUSY; + if (next != NULL) { /* case of chain Mode */ + alignmentOffset = ((unsigned int) next % 16); + } + checkBits = command & 0x6000000; + if (checkBits == 0) { + while (next != NULL) { + WRITE_WORD((unsigned int) next - alignmentOffset, + next->ByteCnt); + tempData = (unsigned int) next->SrcAdd; + WRITE_WORD((unsigned int) next + 4 - + alignmentOffset, tempData & 0x5fffffff); + tempData = (unsigned int) next->DestAdd; + WRITE_WORD((unsigned int) next + 8 - + alignmentOffset, tempData & 0x5fffffff); + tempData = (unsigned int) next->NextRecPtr; + WRITE_WORD((unsigned int) next + 12 - + alignmentOffset, + tempData & 0x5fffffff - + alignmentOffset); + next = (DMA_RECORED *) tempData; + if (next == nextRecoredPointer) + next = NULL; + } + } + GT_REG_WRITE(CHANNEL0_DMA_BYTE_COUNT + channel * 4, numOfBytes); + tempData = sourceAddr; + GT_REG_WRITE(CHANNEL0_DMA_SOURCE_ADDRESS + channel * 4, + tempData & 0x5fffffff); + tempData = destAddr; + GT_REG_WRITE(CHANNEL0_DMA_DESTINATION_ADDRESS + channel * 4, + tempData & 0x5fffffff); + if (nextRecoredPointer != NULL) { + tempData = + (unsigned int) nextRecoredPointer - alignmentOffset; + GT_REG_WRITE(CHANNEL0NEXT_RECORD_POINTER + 4 * channel, + tempData & 0x5fffffff); + command = command | CHANNEL_ENABLE; + } else { + command = command | CHANNEL_ENABLE | NON_CHAIN_MOD; + } + /* Activate DMA engine By writting to dmaControlRegister */ + GT_REG_WRITE(CHANNEL0CONTROL + channel * 4, command); + + return DMA_OK; +} + +/******************************************************************** +* isDmaChannelActive - check if channel is busy +* +* Inputs: channel number +* RETURNS: True if the channel is busy, false otherwise. +*********************************************************************/ + +bool isDmaChannelActive(DMA_ENGINE channel) +{ + unsigned int data; + + if (channel > LAST_DMA_ENGINE) + return false; + GT_REG_READ(CHANNEL0CONTROL + 4 * channel, &data); + if (data & DMA_ACTIVITY_STATUS) + return true; + else + return false; +} + + +/******************************************************************** +* changeDmaPriority - update the arbiter`s priority for channels 0-3 +* +* Inputs: priority for channels 0-1, priority for channels 2-3, + priority for groups and other priority options +* RETURNS: false if one of the parameters is erroneous and true else +*********************************************************************/ + +bool changeDmaPriority(PRIO_CHAN_0_1 prio_01, PRIO_CHAN_2_3 prio_23, + PRIO_GROUP prioGrp, PRIO_OPT prioOpt) +{ + unsigned int prioReg = 0; + + prioReg = (prio_01 & 0x3) + ((prio_23 & 0x3) << 2) + + ((prioGrp & 0x3) << 4) + (prioOpt << 6); + GT_REG_WRITE(ARBITER_CONTROL, prioReg); + return true; +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/i2o.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/i2o.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/i2o.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/i2o.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,689 @@ +/* i2o.c - Drivers for the I2O */ + +/* Copyright - Galileo technology. */ + +/*includes*/ + +#include + +#ifdef __linux__ +#include +#include +#else +#include "Core.h" +#include "i2o.h" +#endif + +/******************************************************************** +* getInBoundMessage - When the GT is configured for I2O support +* it can receive a message from an agent on the pci bus. +* This message is a 32 bit wide and can be read by +* the CPU. +* The messaging unit contains two sets of registers +* so, actually it can receive a 64 bit message. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: Data received from the remote agent. +*********************************************************************/ +unsigned int getInBoundMessage(I2O_MESSAGE_REG messageRegNum) +{ + unsigned int regValue; + + GT_REG_READ(INBOUND_MESSAGE_REGISTER0_CPU_SIDE + 4 * messageRegNum, + ®Value); + return (regValue); +} + + +/******************************************************************** +* checkInboundIntAndClear - When a message is received an interrupt is +* generated, to enable polling instead the use of +* an interrupt handler the user can use this fuction. +* You will need to mask the incomming interrupt for +* proper use. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true if the corresponding bit in the cause register is set otherwise +* false. +*********************************************************************/ +bool checkInBoundIntAndClear(I2O_MESSAGE_REG messageRegNum) +{ + unsigned int regValue; + + GT_REG_READ(INBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, ®Value); + /* clears bit 0 for message register 0 or bit 1 for message register 1 */ + GT_REG_WRITE(INBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, + BIT1 * messageRegNum); + switch (messageRegNum) { + case MESSAGE_REG_0: + if (regValue & BIT0) + return true; + break; + case MESSAGE_REG_1: + if (regValue & BIT1) + return true; + break; + } + return false; +} + +/******************************************************************** +* sendOutBoundMessage - When the GT is configured for I2O support +* it can send a message to an agent on the pci bus. +* This message is a 32 bit wide and can be read by +* the PCI agent. +* The messaging unit contains two sets of registers +* so, actually it can send a 64 bit message. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* unsigned int message - Message to be sent. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool sendOutBoundMessage(I2O_MESSAGE_REG messageRegNum, + unsigned int message) +{ + GT_REG_WRITE(OUTBOUND_MESSAGE_REGISTER0_CPU_SIDE + + 4 * messageRegNum, message); + return true; +} + +/******************************************************************** +* checkOutboundInt - When the CPU sends a message to the Outbound +* register it generates an interrupt which is refelcted on +* the Outbound Interrupt cause register, the interrupt can +* be cleard only by the PCI agent which read the message. +* After sending the message you can acknowledge it by +* monitoring the corresponding bit in the cause register. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true if the corresponding bit in the cause register is set otherwise +* false. +*********************************************************************/ +bool outBoundMessageAcknowledge(I2O_MESSAGE_REG messageRegNum) +{ + unsigned int regValue; + + GT_REG_READ(OUTBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, ®Value); + switch (messageRegNum) { + case MESSAGE_REG_0: + if (regValue & BIT0) + return true; + break; + case MESSAGE_REG_1: + if (regValue & BIT1) + return true; + break; + } + return false; +} + +/******************************************************************** +* maskInBoundMessageInterrupt - Mask the inbound interrupt, when masking +* the interrupt you can work in polling mode +* using the checkInboundIntAndClear function. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool maskInBoundMessageInterrupt(I2O_MESSAGE_REG messageRegNum) +{ + switch (messageRegNum) { + case MESSAGE_REG_0: + SET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT0); + break; + case MESSAGE_REG_1: + SET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT1); + break; + } + return true; +} + +/******************************************************************** +* enableInBoundMessageInterrupt - unMask the inbound interrupt. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool enableInBoundMessageInterrupt(I2O_MESSAGE_REG messageRegNum) +{ + switch (messageRegNum) { + case MESSAGE_REG_0: + RESET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT0); + break; + case MESSAGE_REG_1: + RESET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT1); + break; + } + return true; +} + +/******************************************************************** +* maskOutboundMessageInterrupt - Mask the out bound interrupt, when doing so +* the PCI agent needs to poll on the interrupt +* cause register to monitor an incoming message. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool maskOutBoundMessageInterrupt(I2O_MESSAGE_REG messageRegNum) +{ + switch (messageRegNum) { + case MESSAGE_REG_0: + SET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT0); + break; + case MESSAGE_REG_1: + SET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT1); + break; + } + return true; +} + +/******************************************************************** +* enableOutboundMessageInterrupt - Mask the out bound interrupt, when doing so +* the PCI agent needs to poll on the interrupt +* cause register to monitor an incoming message. +* +* INPUTS: I2O_MESSAGE_REG messageRegNum - Selected set (0 or 1) register. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool enableOutBoundMessageInterrupt(I2O_MESSAGE_REG messageRegNum) +{ + switch (messageRegNum) { + case MESSAGE_REG_0: + RESET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT0); + break; + case MESSAGE_REG_1: + RESET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + BIT1); + break; + } + return true; +} + +/******************************************************************** +* initiateOutBoundDoorBellInt - Setting a bit in this register to '1' by the +* CPU generates a PCI interrupt (if it is not masked by +* the Outbound interrupt Mask register) +* Only the PCI agent which recieved the interrupt can +* clear it, only after clearing all the bits the +* interrupt will be de-asserted. +* +* INPUTS: unsigned int data - Requested interrupt bits. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool initiateOutBoundDoorBellInt(unsigned int data) +{ + GT_REG_WRITE(OUTBOUND_DOORBELL_REGISTER_CPU_SIDE, data); + return true; +} + +/******************************************************************** +* readInBoundDoorBellInt - Read the in bound door bell interrupt cause +* register. +* +* OUTPUT: N/A. +* RETURNS: The 32 bit interrupt cause register. +*********************************************************************/ +unsigned int readInBoundDoorBellInt() +{ + unsigned int regData; + GT_REG_READ(INBOUND_DOORBELL_REGISTER_CPU_SIDE, ®Data); + return regData; +} + +/******************************************************************** +* clearInBoundDoorBellInt - An interrupt generated by a PCI agent through +* the in bound door bell mechanisem can be cleared +* only by the CPU. The interrupt will be de-asserted +* only if all the bits which where set by the PCI +* agent are cleared. +* +* INPUTS: unsigned int data - Bits to be cleared. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool clearInBoundDoorBellInt(unsigned int data) +{ + GT_REG_WRITE(INBOUND_DOORBELL_REGISTER_CPU_SIDE, data); + return true; +} + +/******************************************************************** +* isInBoundDoorBellInterruptSet - Check if Inbound Doorbell Interrupt is set, +* can be used for polling mode. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true if the corresponding bit in the cause register is set otherwise +* false. +*********************************************************************/ +bool isInBoundDoorBellInterruptSet() +{ + unsigned int regData; + + GT_REG_READ(INBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, ®Data); + return (regData & BIT2); +} + +/******************************************************************** +* isOutBoundDoorBellInterruptSet - Check if out bound Doorbell Interrupt is +* set, can be used for acknowledging interrupt +* handling by the agent who recieived the +* interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true if the corresponding bit in the cause register is set otherwise +* false. +*********************************************************************/ +bool isOutBoundDoorBellInterruptSet() +{ + unsigned int regData; + + GT_REG_READ(OUTBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, ®Data); + return (regData & BIT2); +} + +/******************************************************************** +* maskInboundDoorBellInterrupt - Mask the Inbound Doorbell Interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool maskInBoundDoorBellInterrupt() +{ + SET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, BIT2); + return true; +} + +/******************************************************************** +* enableInboundDoorBellInterrupt - unMask the Inbound Doorbell Interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool enableInBoundDoorBellInterrupt() +{ + RESET_REG_BITS(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, BIT2); + return true; +} + +/******************************************************************** +* maskOutboundDoorBellInterrupt - Mask the Outbound Doorbell Interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool maskOutBoundDoorBellInterrupt() +{ + SET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, BIT2); + return true; +} + +/******************************************************************** +* enableOutboundDoorBellInterrupt - unMask the Outbound Doorbell Interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool enableOutBoundDoorBellInterrupt() +{ + RESET_REG_BITS(OUTBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, BIT2); + return true; +} + +/******************************************************************** +* circularQueueEnable - Initialize the I2O messaging mechanism. +* +* INPUTS: CIRCULE_QUEUE_SIZE cirQueSize - Bits 5:1 in the: +* Queue Control Register, Offset 0x50 (0x1c50). +* Defines the queues size (refer to the data sheet +* for more information) +* unsigned int queueBaseAddr - The base address for the first queue. +* The other queues base Address will be determined as follows: +* Inbound Free = queueBaseAddr +* Inbound Post = queueBaseAddr + cirQueSize +* Outbound Post = queueBaseAddr + cirQueSize +* +* OUTPUT: N/A. +* RETURNS: true. +* +* The Circular Queue Starting Addresses as written in the spec: +* ---------------------------------------- +* | Queue | Starting Address | +* |----------------|---------------------| +* | Inbound Free | QBAR | +* | Inbound Post | QBAR + Queue Size | +* | Outbound Post | QBAR + 2*Queue Size | +* | Outbound Free | QBAR + 3*Queue Size | +* ---------------------------------------- +*********************************************************************/ +bool circularQueueEnable(CIRCULAR_QUEUE_SIZE cirQueSize, + unsigned int queueBaseAddr) +{ + unsigned int regData; + + regData = BIT0 | (cirQueSize << 1); + /* Enable Queue Operation */ + GT_REG_WRITE(QUEUE_CONTROL_REGISTER_CPU_SIDE, regData); + /* Writing The base Address for the 4 Queues */ + GT_REG_WRITE(QUEUE_BASE_ADDRESS_REGISTER_CPU_SIDE, queueBaseAddr); + /* Update The Inbound Free Queue Base Address, offset=0 */ + GT_REG_WRITE(INBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, 0); + GT_REG_WRITE(INBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, 0); + /* Update The Inbound Post Queue Base Address, offset=_16K*cirQueSize */ + GT_REG_WRITE(INBOUND_POST_HEAD_POINTER_REGISTER_CPU_SIDE, + _16K * cirQueSize); + GT_REG_WRITE(INBOUND_POST_TAIL_POINTER_REGISTER_CPU_SIDE, + _16K * cirQueSize); + /* Update The Outbound Post Queue Base Address, offset=2*_16K*cirQueSize */ + GT_REG_WRITE(OUTBOUND_POST_HEAD_POINTER_REGISTER_CPU_SIDE, + 2 * _16K * cirQueSize); + GT_REG_WRITE(OUTBOUND_POST_TAIL_POINTER_REGISTER_CPU_SIDE, + 2 * _16K * cirQueSize); + /* Update The Outbound Free Queue Base Address, offset=3*_16K*cirQueSize */ + GT_REG_WRITE(OUTBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, + 3 * _16K * cirQueSize); + GT_REG_WRITE(OUTBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, + 3 * _16K * cirQueSize); + return true; +} + +/******************************************************************** +* inBoundPostQueuePop - Two actions are being taken upon pop: +* 1) Getting out the data from the Queue`s head. +* 2) Increment the tail pointer in a cyclic way (The HEAD is +* incremented automaticaly by the GT) +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: Data pointed by tail. +*********************************************************************/ +unsigned int inBoundPostQueuePop() +{ + unsigned int tailAddrPointer; + unsigned int data; + unsigned int cirQueSize; + unsigned int qBar; + unsigned int inBoundPostQbase; + + /* Gets the Inbound Post TAIL pointer */ + GT_REG_READ(INBOUND_POST_TAIL_POINTER_REGISTER_CPU_SIDE, + &tailAddrPointer); + /* Gets the Data From the pointer Address */ + READ_WORD(tailAddrPointer, &data); + /* incrementing head process: */ + /* Gets the fifo's base Address */ + GT_REG_READ(QUEUE_BASE_ADDRESS_REGISTER_CPU_SIDE, &qBar); + qBar = qBar & 0xfff00000; + /* Gets the fifo's size */ + GT_REG_READ(QUEUE_CONTROL_REGISTER_CPU_SIDE, &cirQueSize); + cirQueSize = 0x1f && (cirQueSize >> 1); + /* calculating The Inbound Post Queue Base Address */ + inBoundPostQbase = qBar + 1 * cirQueSize * _16K; + /* incrementing Inbound Post queue TAIL in a cyclic loop */ + tailAddrPointer = inBoundPostQbase + ((tailAddrPointer + 4) % + (_16K * cirQueSize)); + /* updating the pointer back to INBOUND_POST_TAIL_POINTER_REGISTER */ + GT_REG_WRITE(INBOUND_POST_TAIL_POINTER_REGISTER_CPU_SIDE, + tailAddrPointer); + return data; +} + +/******************************************************************** +* isInBoundPostQueueInterruptSet - Check if in bound interrupt is set. +* can be used for polling mode. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true if the corresponding bit in the cause register is set otherwise +* false. +*********************************************************************/ +bool isInBoundPostQueueInterruptSet() +{ + unsigned int regData; + + GT_REG_READ(INBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, ®Data); + return (regData & BIT4); /* if set return '1' (true), else '0' (false) */ +} + +/******************************************************************** +* clearInBoundPostQueueInterrupt - Clears the Post queue interrupt. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool clearInBoundPostQueueInterrupt() +{ + GT_REG_WRITE(INBOUND_INTERRUPT_CAUSE_REGISTER_CPU_SIDE, BIT4); + return true; +} + +/******************************************************************** +* maskInBoundPostQueueInterrupt - Mask the inbound interrupt, when masking +* the interrupt you can work in polling mode. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: +*********************************************************************/ +void maskInBoundPostQueueInterrupt() +{ + unsigned int regData; + + GT_REG_READ(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, ®Data); + GT_REG_WRITE(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + regData | BIT4); + +} + +/******************************************************************** +* enableInBoundPostQueueInterrupt - Enable interrupt when ever there is a new +* message from the PCI agent. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: +*********************************************************************/ +void enableInBoundPostQueueInterrupt() +{ + unsigned int regData; + + GT_REG_READ(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, ®Data); + GT_REG_WRITE(INBOUND_INTERRUPT_MASK_REGISTER_CPU_SIDE, + regData & 0xfffffffb); +} + +/******************************************************************** +* inBoundFreeQueuePush - Two actions are being taken upon push: +* 1) Place the user`s data on the Queue`s head. +* 2) Increment the haed pointer in a cyclic way (The tail is +* decremented automaticaly by the GT) +* +* INPUTS: unsigned int data - Data to be placed in the queue. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool inBoundFreeQueuePush(unsigned int data) +{ + unsigned int headPointer; + unsigned int cirQueSize; + unsigned int qBar; + unsigned int inBoundFreeQbase; + + GT_REG_READ(INBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, + &headPointer); + /* placing the data in the queue */ + WRITE_WORD(headPointer, data); + /* incrementing head process: */ + /* Gets the fifo's base Address */ + GT_REG_READ(QUEUE_BASE_ADDRESS_REGISTER_CPU_SIDE, &qBar); + qBar = qBar & 0xfff00000; + /* Gets the fifo's size */ + GT_REG_READ(QUEUE_CONTROL_REGISTER_CPU_SIDE, &cirQueSize); + cirQueSize = 0x1f && (cirQueSize >> 1); + /* calculating The Inbound Free Queue Base Address */ + inBoundFreeQbase = qBar; + /* incrementing Inbound Free queue HEAD in a cyclic loop */ + headPointer = + inBoundFreeQbase + ((headPointer + 4) % (_16K * cirQueSize)); + /* updating the pointer back to OUTBOUND_POST_HEAD_POINTER_REGISTER */ + GT_REG_WRITE(INBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, + headPointer); + return true; +} + +/******************************************************************** +* isInBoundFreeQueueEmpty - Check if Inbound Free Queue Empty. +* Can be used for acknowledging the messages +* being sent by us to the PCI agent. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true if the queue is empty , otherwise false. +*********************************************************************/ +bool isInBoundFreeQueueEmpty() +{ + unsigned int inBoundFreeQueHead; + unsigned int inBoundFreeQueTail; + + GT_REG_READ(INBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, + &inBoundFreeQueHead); + GT_REG_READ(INBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, + &inBoundFreeQueTail); + if (inBoundFreeQueHead == inBoundFreeQueTail) { + return true; + } else + return false; +} + +/******************************************************************** +* outBoundPostQueuePush - Two actions are being taken upon push: +* 1) Place the user`s data on the Queue`s head. +* 2) Increment the haed pointer in a cyclic way (The tail is +* decremented automaticaly by the GT when the Agent on the +* PCI have read data from the Outbound Port). +* +* INPUTS: unsigned int data - Data to be placed in the queue`s head. +* OUTPUT: N/A. +* RETURNS: true. +*********************************************************************/ +bool outBoundPostQueuePush(unsigned int data) +{ + unsigned int headPointer; + unsigned int cirQueSize; + unsigned int qBar; + unsigned int outBoundPostQbase; + + GT_REG_READ(OUTBOUND_POST_HEAD_POINTER_REGISTER_CPU_SIDE, + &headPointer); + /* placing the data in the queue (where the head point to..) */ + WRITE_WORD(headPointer, data); + /* incrementing head process: */ + /* Gets the fifo's base Address */ + GT_REG_READ(QUEUE_BASE_ADDRESS_REGISTER_CPU_SIDE, &qBar); + qBar = qBar & 0xfff00000; + /* Gets the fifo's size */ + GT_REG_READ(QUEUE_CONTROL_REGISTER_CPU_SIDE, &cirQueSize); + cirQueSize = 0x1f && (cirQueSize >> 1); + /* calculating The Outbound Post Queue Base Address */ + outBoundPostQbase = qBar + 2 * cirQueSize * _16K; + /* incrementing Outbound Post queue in a cyclic loop */ + headPointer = + outBoundPostQbase + ((headPointer + 4) % (_16K * cirQueSize)); + /* updating the pointer back to OUTBOUND_POST_HEAD_POINTER_REGISTER */ + GT_REG_WRITE(OUTBOUND_POST_HEAD_POINTER_REGISTER_CPU_SIDE, + headPointer); + return true; +} + +/******************************************************************** +* isOutBoundPostQueueEmpty - Check if Outbound Post Queue Empty. +* Can be used for acknowledging the messages +* being sent by us to the PCI agent. +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: true if the queue is empty , otherwise false. +*********************************************************************/ +bool isOutBoundPostQueueEmpty() +{ + unsigned int outBoundPostQueHead; + unsigned int outBoundPostQueTail; + + GT_REG_READ(INBOUND_FREE_HEAD_POINTER_REGISTER_CPU_SIDE, + &outBoundPostQueHead); + GT_REG_READ(INBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, + &outBoundPostQueTail); + if (outBoundPostQueHead == outBoundPostQueTail) { + return true; + } else + return false; +} + +/******************************************************************** +* outBoundFreeQueuePop - Two actions are being taken upon pop: +* 1) Getting out the data from the Queue`s head. +* 2) Increment the tail pointer in a cyclic way (The HEAD is +* incremented automaticaly by the GT) +* +* INPUTS: N/A. +* OUTPUT: N/A. +* RETURNS: Data pointed by tail. +*********************************************************************/ +unsigned int outBoundFreeQueuePop() +{ + unsigned int tailAddrPointer; + unsigned int data; + unsigned int cirQueSize; + unsigned int qBar; + unsigned int outBoundFreeQbase; + + /* Gets the Inbound Post TAIL pointer */ + GT_REG_READ(OUTBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, + &tailAddrPointer); + /* Gets the Data From the pointer Address */ + READ_WORD(tailAddrPointer, &data); + /* incrementing head process: */ + /* Gets the fifo's base Address */ + GT_REG_READ(QUEUE_BASE_ADDRESS_REGISTER_CPU_SIDE, &qBar); + qBar = qBar & 0xfff00000; + /* Gets the fifo's size */ + GT_REG_READ(QUEUE_CONTROL_REGISTER_CPU_SIDE, &cirQueSize); + cirQueSize = 0x1f && (cirQueSize >> 1); + /* calculating The Inbound Post Queue Base Address */ + outBoundFreeQbase = qBar + 3 * cirQueSize * _16K; + /* incrementing Outbound Free queue TAlL in a cyclic loop */ + tailAddrPointer = outBoundFreeQbase + ((tailAddrPointer + 4) % + (_16K * cirQueSize)); + /* updating the pointer back to OUTBOUND_FREE_TAIL_POINTER_REGISTER */ + GT_REG_WRITE(OUTBOUND_FREE_TAIL_POINTER_REGISTER_CPU_SIDE, + tailAddrPointer); + return data; +} + + +EXPORT_SYMBOL(isInBoundDoorBellInterruptSet); +EXPORT_SYMBOL(initiateOutBoundDoorBellInt); +EXPORT_SYMBOL(clearInBoundDoorBellInt); diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/int-handler.S linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/int-handler.S --- linux-2.4.18/arch/mips/galileo-boards/ev64120/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,114 @@ +/* + * int-handler.S + * + * Based on the cobalt handler. + */ +#include +#include +#include +#include +#include +#include + +/* + * galileo_handle_int - + * We check for the timer first, then check PCI ints A and D. + * Then check for serial IRQ and fall through. + */ + .align 5 + .set reorder + .set noat + NESTED(galileo_handle_int, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 t0,CP0_CAUSE + mfc0 t2,CP0_STATUS + + and t0,t2 + + andi t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */ + bnez t1,ll_galileo_irq + andi t1,t0,STATUSF_IP2 /* int0 hardware line */ + bnez t1,ll_pci_intA + andi t1,t0,STATUSF_IP5 /* int3 hardware line */ + bnez t1,ll_pci_intD + andi t1,t0,STATUSF_IP6 /* int4 hardware line */ + bnez t1,ll_serial_irq + andi t1,t0,STATUSF_IP7 /* compare int */ + bnez t1,ll_compare_irq + nop + + /* wrong alarm or masked ... */ + j spurious_interrupt + nop + END(galileo_handle_int) + + + .align 5 + .set reorder +ll_galileo_irq: + li a0,4 + move a1,sp + jal do_IRQ + nop + j ret_from_irq + nop + + .align 5 + .set reorder +ll_compare_irq: + li a0,7 + move a1,sp + jal do_IRQ + nop + j ret_from_irq + nop + + .align 5 + .set reorder +ll_pci_intA: + move a0,sp + jal pci_intA + nop + j ret_from_irq + nop + +#if 0 + .align 5 + .set reorder +ll_pci_intB: + move a0,sp + jal pci_intB + nop + j ret_from_irq + nop + + .align 5 + .set reorder +ll_pci_intC: + move a0,sp + jal pci_intC + nop + j ret_from_irq + nop +#endif + + .align 5 + .set reorder +ll_pci_intD: + move a0,sp + jal pci_intD + nop + j ret_from_irq + nop + + .align 5 + .set reorder +ll_serial_irq: + li a0,6 + move a1,sp + jal do_IRQ + nop + j ret_from_irq + nop diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/irq-handler.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/irq-handler.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/irq-handler.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/irq-handler.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,270 @@ +/* + * Galileo Technology chip interrupt handler + * + * Modified by RidgeRun, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * These are interrupt handlers for the GT on-chip interrupts. They all come + * in to the MIPS on a single interrupt line, and have to be handled and ack'ed + * differently than other MIPS interrupts. + */ + +#if CURRENTLY_UNUSED + +struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH]; +void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr); + +/* + * hook_irq_handler + * + * Hooks IRQ handler to the system. When the system is interrupted + * the interrupt service routine is called. + * + * Inputs : + * int_cause - The interrupt cause number. In EVB64120 two parameters + * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH. + * bit_num - Indicates which bit number in the cause register + * isr_ptr - Pointer to the interrupt service routine + * + * Outputs : + */ +void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr) +{ + irq_handlers[int_cause][bit_num].routine = isr_ptr; +} + + +/* + * enable_galileo_irq + * + * Enables the IRQ on Galileo Chip + * + * Inputs : + * int_cause - The interrupt cause number. In EVB64120 two parameters + * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH. + * bit_num - Indicates which bit number in the cause register + * + * Outputs : + * 1 if succesful, 0 if failure + */ +int enable_galileo_irq(int int_cause, int bit_num) +{ + if (int_cause == INT_CAUSE_MAIN) + SET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, (1 << bit_num)); + else if (int_cause == INT_CAUSE_HIGH) + SET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER, + (1 << bit_num)); + else + return 0; + return 1; +} + +/* + * disable_galileo_irq + * + * Disables the IRQ on Galileo Chip + * + * Inputs : + * int_cause - The interrupt cause number. In EVB64120 two parameters + * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH. + * bit_num - Indicates which bit number in the cause register + * + * Outputs : + * 1 if succesful, 0 if failure + */ +int disable_galileo_irq(int int_cause, int bit_num) +{ + if (int_cause == INT_CAUSE_MAIN) + RESET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, + (1 << bit_num)); + else if (int_cause == INT_CAUSE_HIGH) + RESET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER, + (1 << bit_num)); + else + return 0; + return 1; +} + +#endif /* UNUSED */ + +/* + * galileo_irq - + * + * Interrupt handler for interrupts coming from the Galileo chip. + * It could be timer interrupt, built in ethernet ports etc... + * + * Inputs : + * + * Outputs : + * + */ +static void galileo_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int irq_src, int_high_src, irq_src_mask, + int_high_src_mask; + int handled; + unsigned int count; + static int counter = 0; + + GT_READ(GT_INTRCAUSE_OFS, &irq_src); + GT_READ(GT_INTRMASK_OFS, &irq_src_mask); + GT_READ(GT_HINTRCAUSE_OFS, &int_high_src); + GT_READ(GT_HINTRMASK_OFS, &int_high_src_mask); + irq_src = irq_src & irq_src_mask; + int_high_src = int_high_src & int_high_src_mask; + + handled = 0; + + /* Execute all interrupt handlers */ + /* Check for timer interrupt */ + if (irq_src & 0x00000800) { + handled = 1; + irq_src &= ~0x00000800; + // RESET_REG_BITS (INTERRUPT_CAUSE_REGISTER,BIT8); + do_timer(regs); + } + + if (irq_src) { + printk(KERN_INFO + "Other Galileo interrupt received irq_src %x\n", + irq_src); +#if CURRENTLY_UNUSED + for (count = 0; count < MAX_CAUSE_REG_WIDTH; count++) { + if (irq_src & (1 << count)) { + if (irq_handlers[INT_CAUSE_MAIN][count]. + routine) { + queue_task(&irq_handlers + [INT_CAUSE_MAIN][count], + &tq_immediate); + mark_bh(IMMEDIATE_BH); + handled = 1; + } + } + } +#endif /* UNUSED */ + } + GT_WRITE(GT_INTRCAUSE_OFS, 0); + GT_WRITE(GT_HINTRCAUSE_OFS, 0); + +#undef GALILEO_I2O +#ifdef GALILEO_I2O + /* + Future I2O support. We currently attach I2O interrupt handlers to the + Galileo interrupt (int 4) and handle them in do_IRQ. + */ + if (isInBoundDoorBellInterruptSet()) { + printk(KERN_INFO "I2O doorbell interrupt received.\n"); + handled = 1; + } + + if (isInBoundPostQueueInterruptSet()) { + printk(KERN_INFO "I2O Queue interrupt received.\n"); + handled = 1; + } + + /* + This normally would be outside of the ifdef, but since + we're handling I2O outside of this handler, this + printk shows up every time we get a valid I2O + interrupt. So turn this off for now. + */ + if (handled == 0) { + if (counter < 50) { + printk("Spurious Galileo interrupt...\n"); + counter++; + } + } +#endif +} + +/* + * galileo_time_init - + * + * Initializes timer using galileo's built in timer. + * + * + * Inputs : + * irq - number of irq to be used by the timer + * + * Outpus : + * + */ +#ifdef CONFIG_SYSCLK_100 +#define Sys_clock (100 * 1000000) // 100 MHz +#endif +#ifdef CONFIG_SYSCLK_83 +#define Sys_clock (83.333 * 1000000) // 83.333 MHz +#endif +#ifdef CONFIG_SYSCLK_75 +#define Sys_clock (75 * 1000000) // 75 MHz +#endif + +/* + * This will ignore the standard MIPS timer interrupt handler that is passed + * in as *irq (=irq0 in ../kernel/time.c). We will do our own timer interrupt + * handling. + */ +void galileo_time_init(struct irqaction *irq) +{ + extern irq_desc_t irq_desc[NR_IRQS]; + static struct irqaction timer; + + /* Disable timer first */ + GT_WRITE(GT_TC_CONTROL_OFS, 0); + /* Load timer value for 100 Hz */ + GT_WRITE(GT_TC3_OFS, Sys_clock / 100); + + /* + * Create the IRQ structure entry for the timer. Since we're too early + * in the boot process to use the "request_irq()" call, we'll hard-code + * the values to the correct interrupt line. + */ + timer.handler = &galileo_irq; + timer.flags = SA_SHIRQ; + timer.name = "timer"; + timer.dev_id = NULL; + timer.next = NULL; + timer.mask = 0; + irq_desc[TIMER].action = &timer; + + /* Enable timer ints */ + GT_WRITE(GT_TC_CONTROL_OFS, 0xc0); + /* clear Cause register first */ + GT_WRITE(GT_INTRCAUSE_OFS, 0x0); + /* Unmask timer int */ + GT_WRITE(GT_INTRMASK_OFS, 0x800); + /* Clear High int register */ + GT_WRITE(GT_HINTRCAUSE_OFS, 0x0); + /* Mask All interrupts at High cause interrupt */ + GT_WRITE(GT_HINTRMASK_OFS, 0x0); + +} + +void galileo_irq_init(void) +{ + int i, j; + +#if CURRENTLY_UNUSED + /* Reset irq handlers pointers to NULL */ + for (i = 0; i < MAX_CAUSE_REGS; i++) { + for (j = 0; j < MAX_CAUSE_REG_WIDTH; j++) { + irq_handlers[i][j].next = NULL; + irq_handlers[i][j].sync = 0; + irq_handlers[i][j].routine = NULL; + irq_handlers[i][j].data = NULL; + } + } +#endif +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/irq.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/irq.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,455 @@ +/* + * BRIEF MODULE DESCRIPTION + * Code to handle irqs on GT64120A boards + * Derived from mips/orion and Cort + * + * Copyright (C) 2000 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef IRQ_DEBUG + +#ifdef IRQ_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + +asmlinkage void do_IRQ(int irq, struct pt_regs *regs); + +#define MAX_AGENTS_PER_INT 21 /* Random number */ +unsigned char pci_int_irq[MAX_AGENTS_PER_INT]; +static int max_interrupts = 0; + +/* Duplicate interrupt handlers. */ +/******************************************************************** + *pci_int(A/B/C/D) - + * + *Calls all the handlers connected to PCI interrupt A/B/C/D + * + *Inputs : + * + *Outpus : + * + *********************************************************************/ +asmlinkage __inline__ void pci_intA(struct pt_regs *regs) +{ + unsigned int count = 0; + DBG(KERN_INFO "pci_intA, max_interrupts %d\n", max_interrupts); + for (count = 0; count < max_interrupts; count++) { + do_IRQ(pci_int_irq[count], regs); + } +} + +asmlinkage __inline__ void pci_intD(struct pt_regs *regs) +{ + unsigned int count = 0; + DBG(KERN_INFO "pci_intD, max_interrupts %d\n", max_interrupts); + for (count = 0; count < max_interrupts; count++) { + do_IRQ(pci_int_irq[count], regs); + } +} + + +/* Function for careful CP0 interrupt mask access */ +static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) +{ + unsigned long status = read_32bit_cp0_register(CP0_STATUS); + DBG(KERN_INFO "modify_cp0_intmask clr %x, set %x\n", clr_mask, + set_mask); + DBG(KERN_INFO "modify_cp0_intmask status %x\n", status); + status &= ~((clr_mask & 0xFF) << 8); + status |= (set_mask & 0xFF) << 8; + DBG(KERN_INFO "modify_cp0_intmask status %x\n", status); + write_32bit_cp0_register(CP0_STATUS, status); +} + +static inline void mask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(irq_nr, 0); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(0, irq_nr); +} + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + DBG(KERN_INFO "disable_irq, irq %d\n", irq_nr); + save_and_cli(flags); + if (irq_nr >= 8) { // All PCI interrupts are on line 5 or 2 + mask_irq(9 << 2); + } else { + mask_irq(1 << irq_nr); + } + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + DBG(KERN_INFO "enable_irq, irq %d\n", irq_nr); + save_and_cli(flags); + if (irq_nr >= 8) { // All PCI interrupts are on line 5 or 2 + DBG(KERN_INFO __FUNCTION__ " pci interrupt %d\n", irq_nr); + unmask_irq(9 << 2); + } else { + DBG(KERN_INFO __FUNCTION__ " interrupt set mask %d\n", + 1 << irq_nr); + unmask_irq(1 << irq_nr); + } + restore_flags(flags); +} + +/* + * Generic no controller code + */ + +static void no_irq_enable_disable(unsigned int irq) +{ +} +static unsigned int no_irq_startup(unsigned int irq) +{ + return 0; +} + +#if 0 +static void no_irq_ack(unsigned int irq) +{ + printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq); +} +#endif + +struct hw_interrupt_type no_irq_type = { + typename:"none", + startup:no_irq_startup, + shutdown:no_irq_enable_disable, + enable:no_irq_enable_disable, + disable:no_irq_enable_disable, + ack:NULL, + end:no_irq_enable_disable, +}; + +// ack: no_irq_ack, re-enable later -- SKJ + + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS]; + +atomic_t irq_err_count; + +int get_irq_list(char *buf) +{ + int i, len = 0, j; + struct irqaction *action; + + len += sprintf(buf + len, " "); + for (j = 0; j < smp_num_cpus; j++) + len += sprintf(buf + len, "CPU%d ", j); + *(char *) (buf + len++) = '\n'; + + for (i = 0; i < NR_IRQS; i++) { + action = irq_desc[i].action; + if (!action || !action->handler) + continue; + len += sprintf(buf + len, "%3d: ", i); + len += sprintf(buf + len, "%10u ", kstat_irqs(i)); + if (irq_desc[i].handler) + len += + sprintf(buf + len, " %s ", + irq_desc[i].handler->typename); + else + len += sprintf(buf + len, " None "); + len += sprintf(buf + len, " %s", action->name); + for (action = action->next; action; action = action->next) { + len += sprintf(buf + len, ", %s", action->name); + } + len += sprintf(buf + len, "\n"); + } + len += sprintf(buf + len, "BAD: %10lu\n", atomic_read(&irq_err_count)); + return len; +} + +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int cpu; + +#ifdef IRQ_DEBUG + if (irq != TIMER) + DBG(KERN_INFO __FUNCTION__ " irq = %d\n", irq); + if (irq != TIMER) + DBG(KERN_INFO "cause register = %x\n", + read_32bit_cp0_register(CP0_CAUSE)); + if (irq != TIMER) + DBG(KERN_INFO "status register = %x\n", + read_32bit_cp0_register(CP0_STATUS)); +#endif + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + if (irq_desc[irq].handler->ack) { + irq_desc[irq].handler->ack(irq); + } + + disable_irq(irq); + + action = irq_desc[irq].action; + if (action && action->handler) { +#ifdef IRQ_DEBUG + if (irq != TIMER) + DBG(KERN_INFO + "rr: irq %d action %p and handler %p\n", irq, + action, action->handler); +#endif + if (!(action->flags & SA_INTERRUPT)) + __sti(); + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + __cli(); + if (irq_desc[irq].handler) { + if (irq_desc[irq].handler->end) + irq_desc[irq].handler->end(irq); + else if (irq_desc[irq].handler->enable) + irq_desc[irq].handler->enable(irq); + } + } + + enable_irq(irq); + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); + + /* unmasking and bottom half handling is done magically for us. */ +} + +int request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long irqflags, const char *devname, void *dev_id) +{ + struct irqaction *old, **p, *action; + unsigned long flags; + + DBG(KERN_INFO "rr:dev %s irq %d handler %x\n", devname, irq, + handler); + if (irq >= NR_IRQS) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = NULL; + + save_flags(flags); + cli(); + + p = &irq_desc[irq].action; + + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & action->flags & SA_SHIRQ)) + return -EBUSY; + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + } + *p = action; + + restore_flags(flags); + if (irq >= 8) { + DBG(KERN_INFO "request_irq, max_interrupts %d\n", + max_interrupts); + pci_int_irq[max_interrupts++] = irq; // NOTE: Add error-handling if > max + } + enable_irq(irq); + return 0; +} + + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *p, *old = NULL; + unsigned long flags; + int count, tmp, removed = 0; + + for (p = irq_desc[irq].action; p != NULL; old = p, p = p->next) { + /* Found the IRQ, is it the correct dev_id? */ + if (dev_id == p->dev_id) { + save_flags(flags); + cli(); + + // remove link from list + if (old) + old->next = p->next; + else + irq_desc[irq].action = p->next; + + restore_flags(flags); + kfree(p); + removed = 1; + break; + } + } + + /* + Remove PCI interrupts from the pci_int_irq list. Make sure + that some handler was removed before decrementing max_interrupts. + */ + if ((irq >= 8) && (removed)) { + for (count = 0; count < max_interrupts; count++) { + if (pci_int_irq[count] == irq) { + for (tmp = count; tmp < max_interrupts; + tmp++) { + pci_int_irq[tmp] = + pci_int_irq[tmp + 1]; + } + } + } + max_interrupts--; + DBG(KERN_INFO "free_irq, max_interrupts %d\n", + max_interrupts); + } +} + +unsigned long probe_irq_on(void) +{ + printk(KERN_INFO "probe_irq_on\n"); + return 0; +} + +int probe_irq_off(unsigned long irqs) +{ + printk(KERN_INFO "probe_irq_off\n"); + return 0; +} + +/******************************************************************** + *galileo_irq_setup - + * + *Initializes CPU interrupts + * + * + *Inputs : + * + *Outpus : + * + *********************************************************************/ +void galileo_irq_setup(void) +{ + extern asmlinkage void galileo_handle_int(void); + extern void galileo_irq_init(void); + + DBG(KERN_INFO "rr: galileo_irq_setup entry\n"); + + galileo_irq_init(); + + /* + * Clear all of the interrupts while we change the able around a bit. + */ + clear_cp0_status(ST0_IM); + + /* Sets the exception_handler array. */ + set_except_vector(0, galileo_handle_int); + + cli(); + + /* + * Enable timer. Other interrupts will be enabled as they are + * registered. + */ + set_cp0_status(IE_IRQ2); + + +#ifdef CONFIG_REMOTE_DEBUG + { + extern int DEBUG_CHANNEL; + serial_init(DEBUG_CHANNEL); + serial_set(DEBUG_CHANNEL, 115200); + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ + } +#endif +} + +void init_irq_proc(void) +{ + /* Nothing, for now. */ +} + +void __init init_IRQ(void) +{ + int i; + + DBG(KERN_INFO "rr:init_IRQ\n"); + + /* Let's initialize our IRQ descriptors */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = 0; + irq_desc[i].handler = &no_irq_type; + irq_desc[i].action = NULL; + irq_desc[i].depth = 0; + irq_desc[i].lock = SPIN_LOCK_UNLOCKED; + } + + galileo_irq_setup(); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/pci_bios.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/pci_bios.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/pci_bios.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/pci_bios.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1236 @@ +/* + * BRIEF MODULE DESCRIPTION + * Galileo Evaluation Boards PCI support. + * + * The general-purpose functions to read/write and configure the GT64120A's + * PCI registers (function names start with pci0 or pci1) are either direct + * copies of functions written by Galileo Technology, or are modifications + * of their functions to work with Linux 2.4 vs Linux 2.2. These functions + * are Copyright - Galileo Technology. + * + * Other functions are derived from other MIPS PCI implementations, or were + * written by RidgeRun, Inc, Copyright (C) 2000 RidgeRun, Inc. + * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#undef PCI_DEBUG + +#ifdef PCI_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_PCI + +#define SELF 0 + +/* + * These functions and structures provide the BIOS scan and mapping of the PCI + * devices. + */ + +#define MAX_PCI_DEVS 10 + +struct pci_device { + u32 slot; + u32 BARtype[6]; + u32 BARsize[6]; +}; + +static void __init scan_and_initialize_pci(void); +static u32 __init scan_pci_bus(struct pci_device *pci_devices); +static void __init allocate_pci_space(struct pci_device *pci_devices); + +static void __init galileo_pcibios_fixup_bus(struct pci_bus *bus); + +/* + * The functions that actually read and write to the controller. + * Copied from or modified from Galileo Technology code. + */ +static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device); +static void pci0WriteConfigReg(unsigned int offset, + struct pci_dev *device, unsigned int data); +static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device); +static void pci1WriteConfigReg(unsigned int offset, + struct pci_dev *device, unsigned int data); + +static void pci0MapIOspace(unsigned int pci0IoBase, + unsigned int pci0IoLength); +static void pci1MapIOspace(unsigned int pci1IoBase, + unsigned int pci1IoLength); +static void pci0MapMemory0space(unsigned int pci0Mem0Base, + unsigned int pci0Mem0Length); +static void pci1MapMemory0space(unsigned int pci1Mem0Base, + unsigned int pci1Mem0Length); +static void pci0MapMemory1space(unsigned int pci0Mem1Base, + unsigned int pci0Mem1Length); +static void pci1MapMemory1space(unsigned int pci1Mem1Base, + unsigned int pci1Mem1Length); +static unsigned int pci0GetIOspaceBase(void); +static unsigned int pci0GetIOspaceSize(void); +static unsigned int pci0GetMemory0Base(void); +static unsigned int pci0GetMemory0Size(void); +static unsigned int pci0GetMemory1Base(void); +static unsigned int pci0GetMemory1Size(void); +static unsigned int pci1GetIOspaceBase(void); +static unsigned int pci1GetIOspaceSize(void); +static unsigned int pci1GetMemory0Base(void); +static unsigned int pci1GetMemory0Size(void); +static unsigned int pci1GetMemory1Base(void); +static unsigned int pci1GetMemory1Size(void); + + +/* Functions to implement "pci ops" */ +static int galileo_pcibios_read_config_word(struct pci_dev *dev, + int offset, u16 * val); +static int galileo_pcibios_read_config_byte(struct pci_dev *dev, + int offset, u8 * val); +static int galileo_pcibios_read_config_dword(struct pci_dev *dev, + int offset, u32 * val); +static int galileo_pcibios_write_config_byte(struct pci_dev *dev, + int offset, u8 val); +static int galileo_pcibios_write_config_word(struct pci_dev *dev, + int offset, u16 val); +static int galileo_pcibios_write_config_dword(struct pci_dev *dev, + int offset, u32 val); +static void galileo_pcibios_set_master(struct pci_dev *dev); + +/* + * General-purpose PCI functions. + */ + +/* + * pci0MapIOspace - Maps PCI0 IO space for the master. + * Inputs: base and length of pci0Io + */ +static void pci0MapIOspace(unsigned int pci0IoBase, unsigned int pci0IoLength) +{ + unsigned int pci0IoTop = + (unsigned int) (pci0IoBase + pci0IoLength); + + if (pci0IoLength == 0) + pci0IoTop++; + + pci0IoBase = (unsigned int) (pci0IoBase >> 21); + pci0IoTop = (unsigned int) (((pci0IoTop - 1) & 0x0fffffff) >> 21); + GT_WRITE(GT_PCI0IOLD_OFS, pci0IoBase); + GT_WRITE(GT_PCI0IOHD_OFS, pci0IoTop); +} + +/* + * pci1MapIOspace - Maps PCI1 IO space for the master. + * Inputs: base and length of pci1Io + */ + +static void pci1MapIOspace(unsigned int pci1IoBase, + unsigned int pci1IoLength) +{ + unsigned int pci1IoTop = + (unsigned int) (pci1IoBase + pci1IoLength); + + if (pci1IoLength == 0) + pci1IoTop++; + + pci1IoBase = (unsigned int) (pci1IoBase >> 21); + pci1IoTop = (unsigned int) (((pci1IoTop - 1) & 0x0fffffff) >> 21); + GT_WRITE(GT_PCI1IOLD_OFS, pci1IoBase); + GT_WRITE(GT_PCI1IOHD_OFS, pci1IoTop); +} + +/* + * pci0MapMemory0space - Maps PCI0 memory0 space for the master. + * Inputs: base and length of pci0Mem0 + */ + +static void pci0MapMemory0space(unsigned int pci0Mem0Base, + unsigned int pci0Mem0Length) +{ + unsigned int pci0Mem0Top = pci0Mem0Base + pci0Mem0Length; + + if (pci0Mem0Length == 0) + pci0Mem0Top++; + + pci0Mem0Base = pci0Mem0Base >> 21; + pci0Mem0Top = ((pci0Mem0Top - 1) & 0x0fffffff) >> 21; + GT_WRITE(GT_PCI0M0LD_OFS, pci0Mem0Base); + GT_WRITE(GT_PCI0M0HD_OFS, pci0Mem0Top); +} + +/* + * pci1MapMemory0space - Maps PCI1 memory0 space for the master. + * Inputs: base and length of pci1Mem0 + */ + +static void pci1MapMemory0space(unsigned int pci1Mem0Base, + unsigned int pci1Mem0Length) +{ + unsigned int pci1Mem0Top = pci1Mem0Base + pci1Mem0Length; + + if (pci1Mem0Length == 0) + pci1Mem0Top++; + + pci1Mem0Base = pci1Mem0Base >> 21; + pci1Mem0Top = ((pci1Mem0Top - 1) & 0x0fffffff) >> 21; + GT_WRITE(GT_PCI1M0LD_OFS, pci1Mem0Base); + GT_WRITE(GT_PCI1M0HD_OFS, pci1Mem0Top); +} + +/* + * pci0MapMemory1space - Maps PCI0 memory1 space for the master. + * Inputs: base and length of pci0Mem1 + */ + +static void pci0MapMemory1space(unsigned int pci0Mem1Base, + unsigned int pci0Mem1Length) +{ + unsigned int pci0Mem1Top = pci0Mem1Base + pci0Mem1Length; + + if (pci0Mem1Length == 0) + pci0Mem1Top++; + + pci0Mem1Base = pci0Mem1Base >> 21; + pci0Mem1Top = ((pci0Mem1Top - 1) & 0x0fffffff) >> 21; + GT_WRITE(GT_PCI0M1LD_OFS, pci0Mem1Base); + GT_WRITE(GT_PCI0M1HD_OFS, pci0Mem1Top); + +} + +/* + * pci1MapMemory1space - Maps PCI1 memory1 space for the master. + * Inputs: base and length of pci1Mem1 + */ + +static void pci1MapMemory1space(unsigned int pci1Mem1Base, + unsigned int pci1Mem1Length) +{ + unsigned int pci1Mem1Top = pci1Mem1Base + pci1Mem1Length; + + if (pci1Mem1Length == 0) + pci1Mem1Top++; + + pci1Mem1Base = pci1Mem1Base >> 21; + pci1Mem1Top = ((pci1Mem1Top - 1) & 0x0fffffff) >> 21; + GT_WRITE(GT_PCI1M1LD_OFS, pci1Mem1Base); + GT_WRITE(GT_PCI1M1HD_OFS, pci1Mem1Top); +} + +/* + * pci0GetIOspaceBase - Return PCI0 IO Base Address. + * Inputs: N/A + * Returns: PCI0 IO Base Address. + */ + +static unsigned int pci0GetIOspaceBase(void) +{ + unsigned int base; + GT_READ(GT_PCI0IOLD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci0GetIOspaceSize - Return PCI0 IO Bar Size. + * Inputs: N/A + * Returns: PCI0 IO Bar Size. + */ +static unsigned int pci0GetIOspaceSize(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI0IOLD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI0IOHD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/* + * pci0GetMemory0Base - Return PCI0 Memory 0 Base Address. + * Inputs: N/A + * Returns: PCI0 Memory 0 Base Address. + */ +static unsigned int pci0GetMemory0Base(void) +{ + unsigned int base; + GT_READ(GT_PCI0M0LD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci0GetMemory0Size - Return PCI0 Memory 0 Bar Size. + * Inputs: N/A + * Returns: PCI0 Memory 0 Bar Size. + */ +static unsigned int pci0GetMemory0Size(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI0M0LD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI0M0HD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/* + * pci0GetMemory1Base - Return PCI0 Memory 1 Base Address. + * Inputs: N/A + * Returns: PCI0 Memory 1 Base Address. + */ +static unsigned int pci0GetMemory1Base(void) +{ + unsigned int base; + GT_READ(GT_PCI0M1LD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci0GetMemory1Size - Return PCI0 Memory 1 Bar Size. + * Inputs: N/A + * Returns: PCI0 Memory 1 Bar Size. + */ + +static unsigned int pci0GetMemory1Size(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI0M1LD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI0M1HD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/* + * pci1GetIOspaceBase - Return PCI1 IO Base Address. + * Inputs: N/A + * Returns: PCI1 IO Base Address. + */ + +static unsigned int pci1GetIOspaceBase(void) +{ + unsigned int base; + GT_READ(GT_PCI1IOLD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci1GetIOspaceSize - Return PCI1 IO Bar Size. + * Inputs: N/A + * Returns: PCI1 IO Bar Size. + */ + +static unsigned int pci1GetIOspaceSize(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI1IOLD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI1IOHD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/* + * pci1GetMemory0Base - Return PCI1 Memory 0 Base Address. + * Inputs: N/A + * Returns: PCI1 Memory 0 Base Address. + */ + +static unsigned int pci1GetMemory0Base(void) +{ + unsigned int base; + GT_READ(GT_PCI1M0LD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci1GetMemory0Size - Return PCI1 Memory 0 Bar Size. + * Inputs: N/A + * Returns: PCI1 Memory 0 Bar Size. + */ + +static unsigned int pci1GetMemory0Size(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI1M1LD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI1M1HD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + +/* + * pci1GetMemory1Base - Return PCI1 Memory 1 Base Address. + * Inputs: N/A + * Returns: PCI1 Memory 1 Base Address. + */ + +static unsigned int pci1GetMemory1Base(void) +{ + unsigned int base; + GT_READ(GT_PCI1M1LD_OFS, &base); + base = base << 21; + return base; +} + +/* + * pci1GetMemory1Size - Return PCI1 Memory 1 Bar Size. + * Inputs: N/A + * Returns: PCI1 Memory 1 Bar Size. + */ + +static unsigned int pci1GetMemory1Size(void) +{ + unsigned int top, base, size; + GT_READ(GT_PCI1M1LD_OFS, &base); + base = base << 21; + GT_READ(GT_PCI1M1HD_OFS, &top); + top = (top << 21); + size = ((top - base) & 0xfffffff); + size = size | 0x1fffff; + return (size + 1); +} + + + +/* + * pci_range_ck - + * + * Check if the pci device that are trying to access does really exists + * on the evaluation board. + * + * Inputs : + * bus - bus number (0 for PCI 0 ; 1 for PCI 1) + * dev - number of device on the specific pci bus + * + * Outpus : + * 0 - if OK , 1 - if failure + */ +static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev) +{ + //DBG(KERN_INFO "p_r_c %d %d\n",bus,dev); + if (((bus == 0) || (bus == 1)) && (dev >= 6) && (dev <= 8)) + return 0; // Bus/Device Number OK + return -1; // Bus/Device Number not OK +} + +/* + * pciXReadConfigReg - Read from a PCI configuration register + * - Make sure the GT is configured as a master before + * reading from another device on the PCI. + * - The function takes care of Big/Little endian conversion. + * INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI + * spec) + * pciDevNum: The device number needs to be addressed. + * RETURNS: data , if the data == 0xffffffff check the master abort bit in the + * cause register to make sure the data is valid + * + * Configuration Address 0xCF8: + * + * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number + * |congif|Reserved| Bus |Device|Function|Register|00| + * |Enable| |Number|Number| Number | Number | | <=field Name + * + */ +static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device) +{ + unsigned int DataForRegCf8; + unsigned int data; + + DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) | + (PCI_FUNC(device->devfn) << 8) | + (offset & ~0x3)) | 0x80000000; + GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8); + + /* The casual observer might wonder why the READ is duplicated here, + rather than immediately following the WRITE, and just have the + swap in the "if". That's because there is a latency problem + with trying to read immediately after setting up the address + register. The "if" check gives enough time for the address + to stabilize, so the READ can work. + */ + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + GT_READ(GT_PCI0_CFGDATA_OFS, &data); + return data; + } else { /* The PCI is working in LE Mode so swap the Data. */ + GT_READ(GT_PCI0_CFGDATA_OFS, &data); + return cpu_to_le32(data); + } +} + +static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device) +{ + unsigned int DataForRegCf8; + unsigned int data; + + DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) | + (PCI_FUNC(device->devfn) << 8) | + (offset & ~0x3)) | 0x80000000; + /* The casual observer might wonder why the READ is duplicated here, + rather than immediately following the WRITE, and just have the + swap in the "if". That's because there is a latency problem + with trying to read immediately after setting up the address + register. The "if" check gives enough time for the address + to stabilize, so the READ can work. + */ + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + /* when configurating our own PCI 1 L-unit the access is through + the PCI 0 interface with reg number = reg number + 0x80 */ + DataForRegCf8 |= 0x80; + GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8); + } else { /* The PCI is working in LE Mode so swap the Data. */ + GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8); + } + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + GT_READ(GT_PCI0_CFGDATA_OFS, &data); + return data; + } else { + GT_READ(GT_PCI1_CFGDATA_OFS, &data); + return cpu_to_le32(data); + } +} + + + +/* + * pciXWriteConfigReg - Write to a PCI configuration register + * - Make sure the GT is configured as a master before + * writingto another device on the PCI. + * - The function takes care of Big/Little endian conversion. + * Inputs: unsigned int regOffset: The register offset as it apears in the + * GT spec + * (or any other PCI device spec) + * pciDevNum: The device number needs to be addressed. + * + * Configuration Address 0xCF8: + * + * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number + * |congif|Reserved| Bus |Device|Function|Register|00| + * |Enable| |Number|Number| Number | Number | | <=field Name + * + */ +static void pci0WriteConfigReg(unsigned int offset, + struct pci_dev *device, unsigned int data) +{ + unsigned int DataForRegCf8; + + DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) | + (PCI_FUNC(device->devfn) << 8) | + (offset & ~0x3)) | 0x80000000; + GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8); + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, data); + } else { /* configuration Transaction over the pci. */ + /* The PCI is working in LE Mode so swap the Data. */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, le32_to_cpu(data)); + } +} + +static void pci1WriteConfigReg(unsigned int offset, + struct pci_dev *device, unsigned int data) +{ + unsigned int DataForRegCf8; + + DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) | + (PCI_FUNC(device->devfn) << 8) | + (offset & ~0x3)) | 0x80000000; + /* There is a latency problem + with trying to read immediately after setting up the address + register. The "if" check gives enough time for the address + to stabilize, so the WRITE can work. + */ + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + /* when configurating our own PCI 1 L-unit the access is through + the PCI 0 interface with reg number = reg number + 0x80 */ + DataForRegCf8 |= 0x80; + GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8); + } else { /* configuration Transaction over the pci. */ + /* The PCI is working in LE Mode so swap the Data. */ + GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8); + } + if (PCI_SLOT(device->devfn) == SELF) { /* This board */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, data); + } else { /* configuration Transaction over the pci. */ + GT_WRITE(GT_PCI1_CFGADDR_OFS, le32_to_cpu(data)); + } +} + + +/* + * galileo_pcibios_(read/write)_config_(dword/word/byte) - + * + * reads/write a dword/word/byte register from the configuration space + * of a device. + * + * Inputs : + * bus - bus number + * dev - device number + * offset - register offset in the configuration space + * val - value to be written / read + * + * Outputs : + * PCIBIOS_SUCCESSFUL when operation was succesfull + * PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous + * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned + */ + +static int galileo_pcibios_read_config_dword(struct pci_dev *device, + int offset, u32 * val) +{ + int dev, bus; + //DBG(KERN_INFO "rcd entry \n",offset,val); + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + if (offset & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus == 0) + *val = pci0ReadConfigReg(offset, device); +// if (bus == 1) *val = pci1ReadConfigReg (offset,device); + DBG(KERN_INFO "rr: rcd dev %d offset %x %x\n", dev, offset, *val); + + /* + * This is so that the upper PCI layer will get the correct return + * value if we're not attached to anything. + */ + if ((offset == 0) && (*val == 0xffffffff)) { + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_read_config_word(struct pci_dev *device, + int offset, u16 * val) +{ + int dev, bus; + + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + if (offset & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (bus == 0) + *val = (unsigned short) (pci0ReadConfigReg(offset, device) >> + ((offset & ~0x3) * 8)); +// if (bus == 1) *val = (unsigned short) (pci1ReadConfigReg(offset,device) >> ((offset & ~0x3) * 8)); + + DBG(KERN_INFO "rr: rcw dev %d offset %x %x\n", dev, offset, *val); + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_read_config_byte(struct pci_dev *device, + int offset, u8 * val) +{ + int dev, bus; + + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + if (bus == 0) + *val = + (unsigned char) (pci0ReadConfigReg(offset, device) >> + ((offset & ~0x3) * 8)); +// if (bus == 1) *val = (unsigned char) (pci1ReadConfigReg(offset,device) >> ((offset & ~0x3) * 8)); + + DBG(KERN_INFO "rr: rcb dev %d offset %x %x\n", dev, offset, *val); + + /* This is so that the upper PCI layer will get the correct return value if + we're not attached to anything. */ + if ((offset == 0xe) && (*val == 0xff)) { + u32 MasterAbort; + GT_READ(GT_INTRCAUSE_OFS, &MasterAbort); + if (MasterAbort & 0x40000) { + DBG(KERN_INFO "PCI Master Abort, ICR %x\n", + MasterAbort); + GT_WRITE(GT_INTRCAUSE_OFS, + (MasterAbort & 0xfffbffff)); + return PCIBIOS_DEVICE_NOT_FOUND; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_write_config_dword(struct pci_dev *device, + int offset, u32 val) +{ + int dev, bus; + + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus == 0) + pci0WriteConfigReg(offset, device, val); +// if (bus == 1) pci1WriteConfigReg (offset,device,val); + + DBG(KERN_INFO "rr: wcd dev %d, offset %x, val %x\n", dev, offset, + val); + return PCIBIOS_SUCCESSFUL; +} + + +static int galileo_pcibios_write_config_word(struct pci_dev *device, + int offset, u16 val) +{ + int dev, bus; + unsigned long tmp; + + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus == 0) + tmp = pci0ReadConfigReg(offset, device); +// if (bus == 1) tmp = pci1ReadConfigReg (offset,device); + + if ((offset % 4) == 0) + tmp = (tmp & 0xffff0000) | (val & 0xffff); + if ((offset % 4) == 2) + tmp = (tmp & 0x0000ffff) | ((val & 0xffff) << 16); + + if (bus == 0) + pci0WriteConfigReg(offset, device, tmp); +// if (bus == 1) pci1WriteConfigReg (offset,device,tmp); + DBG(KERN_INFO "rr: wcw dev %d, offset %x, val %x\n", dev, offset, + val); + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_write_config_byte(struct pci_dev *device, + int offset, u8 val) +{ + int dev, bus; + unsigned long tmp; + + bus = device->bus->number; + dev = PCI_SLOT(device->devfn); + + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (bus == 0) + tmp = pci0ReadConfigReg(offset, device); +// if (bus == 1) tmp = pci1ReadConfigReg (offset,device); + + if ((offset % 4) == 0) + tmp = (tmp & 0xffffff00) | (val & 0xff); + if ((offset % 4) == 1) + tmp = (tmp & 0xffff00ff) | ((val & 0xff) << 8); + if ((offset % 4) == 2) + tmp = (tmp & 0xff00ffff) | ((val & 0xff) << 16); + if ((offset % 4) == 3) + tmp = (tmp & 0x00ffffff) | ((val & 0xff) << 24); + + if (bus == 0) + pci0WriteConfigReg(offset, device, tmp); +// if (bus == 1) pci1WriteConfigReg (offset,device,tmp); + DBG(KERN_INFO "rr: wcb dev %d, offset %x, val %x\n", dev, offset, + val); + + return PCIBIOS_SUCCESSFUL; +} + +static void galileo_pcibios_set_master(struct pci_dev *dev) +{ + u16 cmd; + + DBG(KERN_INFO "rr: galileo_pcibios_set_master\n"); + + galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd); + DBG("PCI: Enabling device %s (%04x)\n", dev->slot_name, cmd); +} + +/* Externally-expected functions. Do not change function names */ + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + u16 tmp; + u8 tmp1; + int idx; + struct resource *r; + + DBG(KERN_INFO "rr: pcibios_enable_resources\n"); + + galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + DBG(KERN_INFO + "rr: BAR %d, start %lx, end %lx, flags %lx\n", idx, + r->start, r->end, r->flags); + 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) { + DBG(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd); + } + + /* + Let's fix up the latency timer and cache line size here. Cache line size = + 32 bytes / sizeof dword (4) = 8. + Latency timer must be > 8. 32 is random but appears to work. + */ + galileo_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1); + if (tmp1 != 8) { + DBG(KERN_INFO + "rr: PCI setting cache line size to 8 from %d\n", + tmp1); + galileo_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + 8); + } + galileo_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1); + if (tmp1 < 32) { + DBG(KERN_INFO + "rr: PCI setting latency timer to 32 from %d\n", tmp1); + galileo_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER, + 32); + } + + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + DBG(KERN_INFO "rr: pcibios_enable_device\n"); + return pcibios_enable_resources(dev); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + DBG(KERN_INFO "rr: pcibios_update_resource\n"); + return; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4 * resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & + ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)) { + DBG(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + struct pci_dev *dev = data; + + DBG(KERN_INFO "pcibios_align_resource\n"); + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size > 0x100) { + DBG(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } +} + +/* + * structure galileo_pci_ops + * + * This structure holds the pointers for the PCI configuration space + * access, and the fixup for the interrupts. + * This structure is registered to the operating system in boot time + */ +struct pci_ops galileo_pci_ops = { + galileo_pcibios_read_config_byte, + galileo_pcibios_read_config_word, + galileo_pcibios_read_config_dword, + galileo_pcibios_write_config_byte, + galileo_pcibios_write_config_word, + galileo_pcibios_write_config_dword +}; + +/* + * galileo_pcibios_fixup_bus - + * + * After detecting all agents over the PCI , this function is called + * in order to give an interrupt number for each PCI device starting + * from IRQ 20. It does also enables master for each device. + * + * Inputs : + * mem_start , mem_end are not relevant in MIPS architecture. + * + * Outpus : + * return always mem_start + */ +static void __init galileo_pcibios_fixup_bus(struct pci_bus *bus) +{ + unsigned int Current_IRQ = 20; + struct pci_bus *current_bus = bus; + struct pci_dev *devices; + struct list_head *devices_link; + + list_for_each(devices_link, &(current_bus->devices)) { + devices = pci_dev_b(devices_link); + if (devices != NULL) { + devices->irq = Current_IRQ++; + + /* Assign an interrupt number for the device */ + galileo_pcibios_write_config_byte(devices, + PCI_INTERRUPT_LINE, + Current_IRQ); + galileo_pcibios_set_master(devices); + + } + } + +} + +struct pci_fixup pcibios_fixups[] = { +// { PCI_FIXUP_HEADER, 0x4620, 0x11ab, galileo_pcibios_fixup }, + {0} +}; + +void __init pcibios_fixup_bus(struct pci_bus *c) +{ + DBG(KERN_INFO "rr: pcibios_fixup_bus\n"); + galileo_pcibios_fixup_bus(c); +} + +/* + * This code was derived from Galileo Technology's example + * and significantly reworked. + * + * This is very simple. It does not scan multiple function devices. It does + * not scan behind bridges. Those would be simple to implement, but we don't + * currently need this. + */ +static void __init scan_and_initialize_pci(void) +{ + struct pci_device pci_devices[MAX_PCI_DEVS]; + + if (scan_pci_bus(pci_devices)) { + allocate_pci_space(pci_devices); + } +} + +/* + * This is your basic PCI scan. It goes through each slot and checks to + * see if there's something that responds. If so, then get the size and + * type of each of the responding BARs. Save them for later. + */ + +static u32 __init scan_pci_bus(struct pci_device *pci_devices) +{ + u32 arrayCounter = 0; + u32 memType; + u32 memSize; + u32 pci_slot, bar; + u32 id; + u32 c18RegValue; + struct pci_dev device; + + DBG(KERN_INFO "rr: scan_pci_bus\n"); + + /* + According to PCI REV 2.1 MAX agents on the bus are 21. + We don't bother scanning ourselves (slot 0). + */ + for (pci_slot = 1; pci_slot < 22; pci_slot++) { + + device.devfn = PCI_DEVFN(pci_slot, 0); + id = pci0ReadConfigReg(PCI_VENDOR_ID, &device); + + /* Check for a PCI Master Abort (nothing responds in the slot) */ + GT_READ(GT_INTRCAUSE_OFS, &c18RegValue); + /* Clearing bit 18 of in the Cause Register 0xc18 by writting 0. */ + GT_WRITE(GT_INTRCAUSE_OFS, (c18RegValue & 0xfffbffff)); + if ((id != 0xffffffff) && !(c18RegValue & 0x40000)) { + DBG(KERN_INFO "rr: found device %x, slot %d\n", id, + pci_slot); + pci_devices[arrayCounter].slot = pci_slot; + for (bar = 0; bar < 6; bar++) { + memType = + pci0ReadConfigReg(PCI_BASE_ADDRESS_0 + + (bar * 4), &device); + pci_devices[arrayCounter].BARtype[bar] = + memType & 1; + pci0WriteConfigReg(PCI_BASE_ADDRESS_0 + + (bar * 4), &device, + 0xffffffff); + memSize = + pci0ReadConfigReg(PCI_BASE_ADDRESS_0 + + (bar * 4), &device); + if (memType & 1) { /* IO space */ + pci_devices[arrayCounter]. + BARsize[bar] = + ~(memSize & 0xfffffffc) + 1; + } else { /* memory space */ + pci_devices[arrayCounter]. + BARsize[bar] = + ~(memSize & 0xfffffff0) + 1; + } + DBG(KERN_INFO + "rr: BAR %d, type %d, size %x\n", bar, + (memType & 1), + pci_devices[arrayCounter]. + BARsize[bar]); + } /* BAR counter */ + + arrayCounter++; + } + /* found a device */ + } /* slot counter */ + + DBG(KERN_INFO "rr: found %d devices\n", arrayCounter); + if (arrayCounter < MAX_PCI_DEVS) { + pci_devices[arrayCounter].slot = -1; + } + return (arrayCounter); +} + +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) +#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) + +/* + * This function goes through the list of devices and allocates the BARs in + * either IO or MEM space. It does it in order of size, which will limit the + * amount of fragmentation we have in the IO and MEM spaces. + */ + +static void __init allocate_pci_space(struct pci_device *pci_devices) +{ + u32 count, maxcount, bar; + u32 maxSize, maxDevice, maxBAR; + u32 alignto; + u32 base; + u32 pci0_mem_base = pci0GetMemory0Base(); + u32 pci0_io_base = pci0GetIOspaceBase(); + struct pci_dev device; + + DBG(KERN_INFO "rr: allocate_pci_space\n"); + + DBG(KERN_INFO "pci0_io_base %x\n", pci0_io_base); + DBG(KERN_INFO "pci0_mem_base %x\n", pci0_mem_base); + + /* How many PCI devices do we have? */ + maxcount = MAX_PCI_DEVS; + for (count = 0; count < MAX_PCI_DEVS; count++) { + if (pci_devices[count].slot == -1) { + maxcount = count; + break; + } + } + +// DBG(KERN_INFO "Found %d devices\n", maxcount); + + do { + /* Find the largest size BAR we need to allocate */ + maxSize = 0; + for (count = 0; count < maxcount; count++) { + for (bar = 0; bar < 6; bar++) { + if (pci_devices[count].BARsize[bar] > + maxSize) { + maxSize = + pci_devices[count]. + BARsize[bar]; + maxDevice = count; + maxBAR = bar; + } + } + } + + /* + We've found the largest BAR. Allocate it into IO or + mem space. We don't idiot check the bases to make + sure they haven't overflowed the current size for that aperture. + + Don't bother to enable the device's IO or MEM space here. That will + be done in pci_enable_resources if the device is activated by a driver. + */ + if (maxSize) { + device.devfn = + PCI_DEVFN(pci_devices[maxDevice].slot, 0); + if (pci_devices[maxDevice].BARtype[maxBAR] == 1) { + alignto = MAX(0x1000, maxSize); + base = ALIGN(pci0_io_base, alignto); + pci0WriteConfigReg(PCI_BASE_ADDRESS_0 + + (maxBAR * 4), &device, + base | 0x1); + pci0_io_base = base + alignto; + DBG(KERN_INFO + "Device %d BAR %d address %x\n", + pci_devices[maxDevice].slot, maxBAR, + base); + DBG(KERN_INFO "New IO base %x\n", + pci0_io_base); + } else { + alignto = MAX(0x1000, maxSize); + base = ALIGN(pci0_mem_base, alignto); + pci0WriteConfigReg(PCI_BASE_ADDRESS_0 + + (maxBAR * 4), &device, + base); + pci0_mem_base = base + alignto; + DBG(KERN_INFO + "Device %d BAR %d address %x\n", + pci_devices[maxDevice].slot, maxBAR, + base); + DBG(KERN_INFO "New mem base %x\n", + pci0_mem_base); + } + /* + This entry is finished. Remove it from the list we'll scan. + */ + pci_devices[maxDevice].BARsize[maxBAR] = 0; + } + } while (maxSize); +} + +unsigned __init int pcibios_assign_all_busses(void) +{ + return 1; +} + +void __init pcibios_init(void) +{ + + u32 tmp; + struct pci_dev controller; + + controller.devfn = SELF; + + DBG(KERN_INFO "rr: pcibios_init\n"); + GT_READ(GT_PCI0_CMD_OFS, &tmp); + DBG(KERN_INFO "rr: PCI0 command - %x\n", tmp); + GT_READ(GT_PCI0_BARE_OFS, &tmp); + DBG(KERN_INFO "rr: BAR0 - %x\n", tmp); + + /* + * You have to enable bus mastering to configure any other + * card on the bus. + */ + tmp = pci0ReadConfigReg(PCI_COMMAND, &controller); + DBG(KERN_INFO "rr: command/status - %x\n", tmp); + tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR; + DBG(KERN_INFO "rr: new command/status - %x\n", tmp); + pci0WriteConfigReg(PCI_COMMAND, &controller, tmp); + + /* This scans the PCI bus and sets up initial values. */ + scan_and_initialize_pci(); + + /* + * Reset PCI I/O and PCI MEM values to ones supported by EVM. + */ + ioport_resource.start = 0x10000000; + ioport_resource.end = 0x11ffffff; /* 32 MB */ + iomem_resource.start = 0x12000000; + iomem_resource.end = 0x13ffffff; /* 32 MB */ + + pci_scan_bus(0, &galileo_pci_ops, NULL); + +} + +char *pcibios_setup(char *str) +{ + printk(KERN_INFO "rr: pcibios_setup\n"); + /* Nothing to do for now. */ + + return str; +} + +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/promcon.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/promcon.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/promcon.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/promcon.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,80 @@ +/* + * Wrap-around code for a console using the + * SGI PROM io-routines. + * + * Copyright (c) 1999 Ulf Carlsson + * + * Derived from DECstation promcon.c + * Copyright (c) 1998 Harald Koerfgen + */ + +#include +#include +#include +#include +#include +#include +/* +#include +*/ + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + extern int CONSOLE_CHANNEL; // The default serial port + unsigned i; + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + serial_putc(CONSOLE_CHANNEL, 13); + serial_putc(CONSOLE_CHANNEL, *s++); + } +} +int prom_getchar(void) +{ + return 0; +} +static int prom_console_wait_key(struct console *co) +{ + return prom_getchar(); +} + +static int __init prom_console_setup(struct console *co, char *options) +{ + + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console sercons = { + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +/* + * Register console. + */ + +void gal_serial_console_init(void) +{ + // serial_init(); + //serial_set(115200); + + register_console(&sercons); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/reset.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/reset.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/reset.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,45 @@ +/* + * 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) 1997 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include + +void galileo_machine_restart(char *command) +{ + *(volatile char *) 0xbc000000 = 0x0f; + /* + * Ouch, we're still alive ... This time we take the silver bullet ... + * ... and find that we leave the hardware in a state in which the + * kernel in the flush locks up somewhen during of after the PCI + * detection stuff. + */ + set_cp0_status(ST0_BEV | ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void galileo_machine_halt(void) +{ + printk(KERN_NOTICE "You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); + +} + +void galileo_machine_power_off(void) +{ + galileo_machine_halt(); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/serialGT.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/serialGT.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/serialGT.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/serialGT.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,212 @@ +/* + * serialGT.c + * + * BRIEF MODULE DESCRIPTION + * Low Level Serial Port control for use + * with the Galileo EVB64120A MIPS eval board and + * its on board two channel 16552 Uart. + * + * Copyright (C) 2000 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +// Note: +// Serial CHANNELS - 0 is the bottom connector of evb64120A. +// (The one that maps to the "B" channel of the +// board's uart) +// 1 is the top connector of evb64120A. +// (The one that maps to the "A" channel of the +// board's uart) +int DEBUG_CHANNEL = 0; // See Note Above +int CONSOLE_CHANNEL = 1; // See Note Above + +#define DUART 0xBD000000 /* Base address of Uart. */ +#define CHANNELOFFSET 0x20 /* DUART+CHANNELOFFSET gets you to the ChanA + register set of the 16552 Uart device. + DUART+0 gets you to the ChanB register set. + */ +#define DUART_DELTA 0x4 +#define FIFO_ENABLE 0x07 +#define INT_ENABLE 0x04 /* default interrupt mask */ + +#define RBR 0x00 +#define THR 0x00 +#define DLL 0x00 +#define IER 0x01 +#define DLM 0x01 +#define IIR 0x02 +#define FCR 0x02 +#define LCR 0x03 +#define MCR 0x04 +#define LSR 0x05 +#define MSR 0x06 +#define SCR 0x07 + +#define LCR_DLAB 0x80 +#define XTAL 1843200 +#define LSR_THRE 0x20 +#define LSR_BI 0x10 +#define LSR_DR 0x01 +#define MCR_LOOP 0x10 +#define ACCESS_DELAY 0x10000 + +/****************************** + Routine: + Description: + ******************************/ +int inreg(int channel, int reg) +{ + int val; + val = + *((volatile unsigned char *) DUART + + (channel * CHANNELOFFSET) + (reg * DUART_DELTA)); + return val; +} + +/****************************** + Routine: + Description: + ******************************/ +void outreg(int channel, int reg, unsigned char val) +{ + *((volatile unsigned char *) DUART + (channel * CHANNELOFFSET) + + (reg * DUART_DELTA)) = val; +} + +/****************************** + Routine: + Description: + Initialize the device driver. + ******************************/ +void serial_init(int channel) +{ + /* + * Configure active port, (CHANNELOFFSET already set.) + * + * Set 8 bits, 1 stop bit, no parity. + * + * LCR<7> 0 divisor latch access bit + * LCR<6> 0 break control (1=send break) + * LCR<5> 0 stick parity (0=space, 1=mark) + * LCR<4> 0 parity even (0=odd, 1=even) + * LCR<3> 0 parity enable (1=enabled) + * LCR<2> 0 # stop bits (0=1, 1=1.5) + * LCR<1:0> 11 bits per character(00=5, 01=6, 10=7, 11=8) + */ + outreg(channel, LCR, 0x3); + + outreg(channel, FCR, FIFO_ENABLE); /* Enable the FIFO */ + + outreg(channel, IER, INT_ENABLE); /* Enable appropriate interrupts */ +} + +/****************************** + Routine: + Description: + Set the baud rate. + ******************************/ +void serial_set(int channel, unsigned long baud) +{ + unsigned char sav_lcr; + + /* + * Enable access to the divisor latches by setting DLAB in LCR. + * + */ + sav_lcr = inreg(channel, LCR); + +#if 0 + /* + * Set baud rate + */ + outreg(channel, LCR, LCR_DLAB | sav_lcr); + // outreg(DLL,(XTAL/(16*2*(baud))-2)); + outreg(channel, DLL, XTAL / (16 * baud)); + // outreg(DLM,(XTAL/(16*2*(baud))-2)>>8); + outreg(channel, DLM, (XTAL / (16 * baud)) >> 8); +#else + /* + * Note: Set baud rate, hardcoded here for rate of 115200 + * since became unsure of above "buad rate" algorithm (??). + */ + outreg(channel, LCR, 0x83); + outreg(channel, DLM, 0x00); // See note above + outreg(channel, DLL, 0x02); // See note above. + outreg(channel, LCR, 0x03); +#endif + + /* + * Restore line control register + */ + outreg(channel, LCR, sav_lcr); +} + + +/****************************** + Routine: + Description: + Transmit a character. + ******************************/ +void serial_putc(int channel, int c) +{ + while ((inreg(channel, LSR) & LSR_THRE) == 0); + outreg(channel, THR, c); +} + +/****************************** + Routine: + Description: + Read a received character if one is + available. Return -1 otherwise. + ******************************/ +int serial_getc(int channel) +{ + if (inreg(channel, LSR) & LSR_DR) { + return inreg(channel, RBR); + } + return -1; +} + +/****************************** + Routine: + Description: + Used by embedded gdb client. (example; gdb-stub.c) + ******************************/ +char getDebugChar() +{ + int val; + while ((val = serial_getc(DEBUG_CHANNEL)) == -1); // loop until we get a character in. + return (char) val; +} + +/****************************** + Routine: + Description: + Used by embedded gdb target. (example; gdb-stub.c) + ******************************/ +void putDebugChar(char c) +{ + serial_putc(DEBUG_CHANNEL, (int) c); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev64120/setup.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/setup.c --- linux-2.4.18/arch/mips/galileo-boards/ev64120/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev64120/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,183 @@ +/* + * setup.c + * + * BRIEF MODULE DESCRIPTION + * Galileo Evaluation Boards - board dependent boot routines + * + * Copyright (C) 2000 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct rtc_ops no_rtc_ops; + +/* These functions are used for rebooting or halting the machine*/ +extern void galileo_machine_restart(char *command); +extern void galileo_machine_halt(void); +extern void galileo_machine_power_off(void); +/* + *This structure holds pointers to the pci configuration space accesses + *and interrupts allocating routine for device over the PCI + */ +extern struct pci_ops galileo_pci_ops; + +extern unsigned long mips_machgroup; + +char arcs_cmdline[CL_SIZE] = { "console=ttyS0,115200 " + "root=/dev/nfs rw nfsroot=192.168.1.1:/mnt/disk2/fs.gal " + "ip=192.168.1.211:192.168.1.1:::gt::" +}; + +//struct eeprom_parameters eeprom_param; + +/* + * This function is added because arch/mips/mm/init.c needs it + * basically it does nothing + */ +void prom_free_prom_memory(void) +{ +} + +extern void (*board_time_init) (struct irqaction * irq); + +static unsigned char galileo_rtc_read_data(unsigned long addr) +{ + return 0; +} + +static void galileo_rtc_write_data(unsigned char data, unsigned long addr) +{ +} + +static int galileo_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops galileo_rtc_ops = { + &galileo_rtc_read_data, + &galileo_rtc_write_data, + &galileo_rtc_bcd_mode +}; + +/******************************************************************** + *ev64120_setup - + * + *Initializes basic routines and structures pointers, memory size (as + *given by the bios and saves the command line. + * + * + *Inputs : + * + *Outpus : + * + *********************************************************************/ +extern void galileo_time_init(); +void ev64120_setup(void) +{ + unsigned int i, j; + + //printk(KERN_INFO "ev64120_setup\n"); + + _machine_restart = galileo_machine_restart; + _machine_halt = galileo_machine_halt; + _machine_power_off = galileo_machine_power_off; + + rtc_ops = &galileo_rtc_ops; + + board_time_init = galileo_time_init; + set_io_port_base(KSEG1); + +#ifdef CONFIG_L2_L3_CACHE +#error "external cache not implemented yet" + config_register = read_32bit_cp0_register(CP0_CONFIG); + printk("\n\n\nchecking second level cache cp0_config = %08lx\n", + config_register); + if (config_register & CONF_SC) { // second/third level cache available + config_register = config_register & (1 << 12); + write_32bit_cp0_register(CP0_CONFIG, config_register); + printk + ("\n\n\nchecking second level cache cp0_config = %08lx\n", + config_register); + } +#endif + +} + +const char *get_system_type(void) +{ + return "Galileo EV64120A"; +} + +/* + * SetUpBootInfo - + * + * This function is called at very first stages of kernel startup. + * It specifies for the kernel the evaluation board that the linux + * is running on. Then it saves the eprom parameters that holds the + * command line, memory size etc... + * + * Inputs : + * argc - nothing + * argv - holds a pointer to the eprom parameters + * envp - nothing + */ + +void SetUpBootInfo(int argc, char **argv, char **envp) +{ + mips_machgroup = MACH_GROUP_GALILEO; + mips_machtype = MACH_EV64120A; +} + +void __init prom_init(int a, char **b, char **c, int *d) +{ + unsigned long free_start, free_end, start_pfn, bootmap_size; + + mips_machgroup = MACH_GROUP_GALILEO; + add_memory_region(0, 32 << 20, BOOT_MEM_RAM); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/Makefile linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/Makefile --- linux-2.4.18/arch/mips/galileo-boards/ev96100/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,23 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Galileo EV96100 board. +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET:= ev96100.o + +obj-y := init.o pci_ops.o pci_fixups.o time.o irq.o int-handler.o setup.o \ + puts.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/init.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/init.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/init.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,175 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/generic/generic.c + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* Environment variable */ + +typedef struct { + char *name; + char *val; +} t_env_var; + +int prom_argc; +char **prom_argv, **prom_envp; +char arcs_cmdline[CL_SIZE]; + +int init_debug = 0; + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void prom_free_prom_memory (void) +{ +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; +} + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + */ + + t_env_var *env = (t_env_var *) prom_envp; + int i; + + i = strlen(envname); + + while (env->name) { + if (strncmp(envname, env->name, i) == 0) { + return (env->val); + } + env++; + } + return (NULL); +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +static inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for (i = 0; i < 6; i++) { + unsigned char num; + + if ((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) +{ + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + + if (init_debug > 1) { + int i; + printk("get_ethernet_addr: "); + for (i = 0; i < 5; i++) + printk("%02x:", + (unsigned char) *(ethernet_addr + i)); + printk("%02x\n", *(ethernet_addr + i)); + } + + return 0; +} + +const char *get_system_type(void) +{ + return "Galileo EV96100"; +} + +void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + volatile unsigned char *uart; + char ppbuf[8]; + + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_machgroup = MACH_GROUP_GALILEO; + mips_machtype = MACH_EV96100; + + prom_init_cmdline(); + + /* 32 MB upgradable */ + add_memory_region(0, 32 << 20, BOOT_MEM_RAM); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/int-handler.S linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/int-handler.S --- linux-2.4.18/arch/mips/galileo-boards/ev96100/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,32 @@ +#include +#include +#include +#include + + .set noat + .align 5 + +NESTED(ev96100IRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + + mfc0 t0, CP0_CAUSE # get pending interrupts + mfc0 t1, CP0_STATUS # get enabled interrupts + and t0, t1 # isolate allowed ones + + # FIX ME add R7000 extensions + andi t0,0xff00 # isolate pending bits + andi a0, t0, CAUSEF_IP7 + beq a0, zero, 1f + move a0, sp + jal mips_timer_interrupt + j ret_from_irq + +1: beqz t0, 3f # spurious interrupt + move a0, t0 + move a1, sp # delay slot + jal ev96100_cpu_irq + j ret_from_irq + +3: j spurious_interrupt + END(ev96100IRQ) diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/irq.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/irq.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,135 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/atlas/atlas_int.c. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); + +extern void mips_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void ev96100IRQ(void); + +static void disable_ev96100_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + clear_cp0_status(0x100 << irq_nr); + restore_flags(flags); +} + +static inline void enable_ev96100_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + set_cp0_status(0x100 << irq_nr); + restore_flags(flags); +} + +static unsigned int startup_ev96100_irq(unsigned int irq) +{ + enable_ev96100_irq(irq); + + return 0; /* never anything pending */ +} + +#define shutdown_ev96100_irq disable_ev96100_irq +#define mask_and_ack_ev96100_irq disable_ev96100_irq + +static void end_ev96100_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_ev96100_irq(irq); +} + +static inline unsigned int ffz8(unsigned int word) +{ + unsigned long k; + + k = 7; + if (word & 0x0fUL) { k -= 4; word <<= 4; } + if (word & 0x30UL) { k -= 2; word <<= 2; } + if (word & 0x40UL) { k -= 1; } + + return k; +} + +asmlinkage void ev96100_cpu_irq(unsigned long cause, struct pt_regs * regs) +{ + if (!(cause & 0xff00)) + return; + + do_IRQ(ffz8((cause >> 8) & 0xff), regs); +} + +static struct hw_interrupt_type ev96100_irq_type = { + "EV96100", + startup_ev96100_irq, + shutdown_ev96100_irq, + enable_ev96100_irq, + disable_ev96100_irq, + mask_and_ack_ev96100_irq, + end_ev96100_irq +}; + +void __init init_IRQ(void) +{ + int i; + + set_except_vector(0, ev96100IRQ); + init_generic_irq(); + + for (i = 0; i < 8; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &ev96100_irq_type; + } +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/pci_fixups.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/pci_fixups.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/pci_fixups.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/pci_fixups.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,96 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * EV96100 Board specific pci fixups. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include +#include + +#include +#include + +extern unsigned short get_gt_devid(void); + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ +} + +void __init pcibios_fixup(void) +{ +} + +void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + unsigned int slot; + u32 vendor; + unsigned short gt_devid = get_gt_devid(); + + /* + ** EV96100/A interrupt routing for pci bus 0 + ** + ** Note: EV96100A board with irq jumper set on 'VxWorks' + ** for EV96100 compatibility. + */ + + pci_for_each_dev(dev) { + if (dev->bus->number != 0) + return; + + slot = PCI_SLOT(dev->devfn); + pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor); + +#ifdef DEBUG + printk("devfn %x, slot %d devid %x\n", + dev->devfn, slot, gt_devid); +#endif + + /* fixup irq line based on slot # */ + if (slot == 8) { + dev->irq = 5; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + dev->irq); + } + else if (slot == 9) { + dev->irq = 2; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + dev->irq); + } + } +} +unsigned int pcibios_assign_all_busses(void) +{ + return 0; +} +#endif diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/pci_ops.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/pci_ops.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/pci_ops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,274 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Galileo EV96100 board specific pci support. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/generic/pci.c + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#define GT_PCI_MEM_BASE 0x12000000 +#define GT_PCI_MEM_SIZE 0x02000000 +#define GT_PCI_IO_BASE 0x10000000 +#define GT_PCI_IO_SIZE 0x02000000 +static struct resource pci_io_resource = { + "io pci IO space", + 0x10000000, + 0x10000000 + 0x02000000, + IORESOURCE_IO}; + +static struct resource pci_mem_resource = { + "ext pci memory space", + 0x12000000, + 0x12000000 + 0x02000000, + IORESOURCE_MEM}; + +extern struct pci_ops gt96100_pci_ops; + +struct pci_channel mips_pci_channels[] = { + { >96100_pci_ops, &pci_io_resource, &pci_mem_resource, 1, 0xff }, + { NULL, NULL, NULL, NULL, NULL} +}; + +int +static gt96100_config_access(unsigned char access_type, struct pci_dev *dev, + unsigned char where, u32 *data) +{ + unsigned char bus = dev->bus->number; + unsigned char dev_fn = dev->devfn; + u32 intr; + + + if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0))) { + return -1; /* Because of a bug in the galileo (for slot 31). */ + } + + /* Clear cause register bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + udelay(2); + + + if (access_type == PCI_ACCESS_WRITE) { + if (dev_fn != 0) { + *data = le32_to_cpu(*data); + } + GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } + else { + GT_READ(GT_PCI0_CFGDATA_OFS, *data); + if (dev_fn != 0) { + *data = le32_to_cpu(*data); + } + } + + udelay(2); + + /* Check for master or target abort */ + GT_READ(GT_INTRCAUSE_OFS, intr); + + if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) + { + //printk("config access error: %x:%x\n", dev_fn,where); + /* Error occured */ + + /* Clear bits */ + GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT) ); + + if (access_type == PCI_ACCESS_READ) { + *data = 0xffffffff; + } + return -1; + } + return 0; +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int +read_config_byte (struct pci_dev *dev, int where, u8 *val) +{ + u32 data = 0; + + if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) { + *val = 0xff; + return -1; + } + + *val = (data >> ((where & 3) << 3)) & 0xff; + DBG("cfg read byte: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); + + return PCIBIOS_SUCCESSFUL; +} + + +static int +read_config_word (struct pci_dev *dev, int where, u16 *val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) { + *val = 0xffff; + return -1; + } + + *val = (data >> ((where & 3) << 3)) & 0xffff; + DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); + + return PCIBIOS_SUCCESSFUL; +} + +static int +read_config_dword (struct pci_dev *dev, int where, u32 *val) +{ + u32 data = 0; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) { + *val = 0xffffffff; + return -1; + } + + *val = data; + DBG("cfg read dword: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); + + return PCIBIOS_SUCCESSFUL; +} + + +static int +write_config_byte (struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + + if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + DBG("cfg write byte: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, val); + + if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +write_config_word (struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (gt96100_config_access(PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + DBG("cfg write word: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, val); + + if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + + return PCIBIOS_SUCCESSFUL; +} + +static int +write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + DBG("cfg write dword: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, val); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops gt96100_pci_ops = { + read_config_byte, + read_config_word, + read_config_dword, + write_config_byte, + write_config_word, + write_config_dword +}; + +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/puts.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/puts.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/puts.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/puts.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,144 @@ + +/* + * Debug routines which directly access the uart. + */ + +#include +#include + + +//#define SERIAL_BASE EV96100_UART0_REGS_BASE +#define SERIAL_BASE 0xBD000020 +#define NS16550_BASE SERIAL_BASE + +#define SERA_CMD 0x0D +#define SERA_DATA 0x08 +//#define SERB_CMD 0x05 +#define SERB_CMD 20 +#define SERB_DATA 0x00 +#define TX_BUSY 0x20 + +#define TIMEOUT 0xffff +#undef SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; +static volatile unsigned char * const com1 = (unsigned char *)SERIAL_BASE; + + +#ifdef SLOW_DOWN +static inline void slow_down() +{ + int k; + for (k=0; k<10000; k++); +} +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + unsigned char ch; + int i = 0; + + do { + ch = com1[SERB_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SERB_DATA] = c; +} + +void +putchar(const unsigned char c) +{ + unsigned char ch; + int i = 0; + + do { + ch = com1[SERB_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SERB_DATA] = c; +} + +void +puts(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + do { + ch = com1[SERB_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SERB_DATA] = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + unsigned char ch; + int i = 0; + + while (*cp) { + + do { + ch = com1[SERB_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (0 == (ch & TX_BUSY)); + com1[SERB_DATA] = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/setup.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/setup.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,213 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Galileo EV96100 setup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/atlas/atlas_setup.c. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +void (*__wbflush) (void); + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +char serial_console[20]; +#endif + +extern char * __init prom_getcmdline(void); + +extern void mips_reboot_setup(void); +extern struct rtc_ops no_rtc_ops; +extern struct resource ioport_resource; + +static void rm7000_wbflush(void) +{ + __asm__ __volatile__ ("sync"); +} + +unsigned char mac_0_1[12]; + + +void __init ev96100_setup(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + unsigned long status = read_32bit_cp0_register(CP0_STATUS); + unsigned long info = read_32bit_cp0_register(CP0_INFO); + u32 tmp; + + char *argptr; + + clear_cp0_status(ST0_FR); + __wbflush = rm7000_wbflush; + + if (config & 0x8) { + printk("Secondary cache is enabled\n"); + } + else { + printk("Secondary cache is disabled\n"); + } + + if (status & (1<<27)) { + printk("User-mode cache ops enabled\n"); + } + else { + printk("User-mode cache ops disabled\n"); + } + + printk("CP0 info reg: %x\n", (unsigned)info); + if (info & (1<<28)) { + printk("burst mode Scache RAMS\n"); + } + else { + printk("pipelined Scache RAMS\n"); + } + + if ((info & (0x3<<26)) >> 26 == 0) { + printk("67 percent drive strength\n"); + } + else if ((info & (0x3<<26)) >> 26 == 1) { + printk("50 percent drive strength\n"); + } + else if ((info & (0x3<<26)) >> 26 == 2) { + printk("100 percent drive strength\n"); + } + else if ((info & (0x3<<26)) >> 26 == 3) { + printk("83 percent drive strength\n"); + } + + + if ((info & (0x3<<23)) >> 23 == 0) { + printk("Write Protocol: R4000 compatible\n"); + } + else if ((info & (0x3<<23)) >> 23 == 1) { + printk("Write Protocol: Reserved\n"); + } + else if ((info & (0x3<<23)) >> 23 == 2) { + printk("Write Protocol: Pipelined\n"); + } + else if ((info & (0x3<<23)) >> 23 == 3) { + printk("Write Protocol: Write re-issue\n"); + } + + if (info & 0x1) { + printk("Atomic Enable is set\n"); + } + + argptr = prom_getcmdline(); +#ifdef CONFIG_SERIAL_CONSOLE + if (strstr(argptr, "console=") == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS0,115200"); + } +#endif + + rtc_ops = &no_rtc_ops; + mips_reboot_setup(); + set_io_port_base(KSEG1); + ioport_resource.start = GT_PCI_IO_BASE; + ioport_resource.end = GT_PCI_IO_BASE + 0x01ffffff; + +#ifdef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); +#endif + + + /* + * setup gt controller master bit so we can do config cycles + */ + + /* Clear cause register bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + udelay(2); + tmp = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS)); + + tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + udelay(2); + *(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS) = cpu_to_le32(tmp); + + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + udelay(2); + tmp = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS)); +} + +unsigned short get_gt_devid() +{ + u32 gt_devid; + + /* Figure out if this is a gt96100 or gt96100A */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((PCI_VENDOR_ID / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + udelay(4); + gt_devid = le32_to_cpu(*(volatile u32 *) + (MIPS_GT_BASE+GT_PCI0_CFGDATA_OFS)); + return (unsigned short)(gt_devid>>16); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/ev96100/time.c linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/time.c --- linux-2.4.18/arch/mips/galileo-boards/ev96100/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/ev96100/time.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,272 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Galileo EV96100 rtc routines. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/atlas/atlas_rtc.c. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) + +extern volatile unsigned long wall_jiffies; +unsigned long missed_heart_beats = 0; + +static unsigned long r4k_offset; /* Amount to increment compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +extern rwlock_t xtime_lock; + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_32bit_cp0_register(CP0_COMPARE, newval); +} + +static int set_rtc_mmss(unsigned long nowtime) +{ + /* EV96100 does not have a real time clock */ + int retval = 0; + + return retval; +} + + + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. + * Use the RTC to calculate offset. + */ +static unsigned long __init cal_r4koff(void) +{ + unsigned long count; + count = 300000000/2; + return (count / HZ); +} + + +static unsigned long __init get_mips_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + + year = 2000; + mon = 10; + day = 31; + hour = 0; + min = 0; + sec = 0; + return mktime(year, mon, day, hour, min, sec); +} + + +/* + * called from start_kernel() + */ +void __init time_init(void) +{ + + unsigned int est_freq; + + r4k_offset = cal_r4koff(); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + + /* FIX ME */ + change_cp0_status(ST0_IM, IE_IRQ5); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY)); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned int flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_fast_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +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 -= do_fast_gettimeoffset(); + + if (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); +} + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is probably more robust. + */ +void mips_timer_interrupt(struct pt_regs *regs) +{ + int irq = 7; /* FIX ME */ + + if (r4k_offset == 0) { + goto null; + } + + do { + kstat.irqs[0][irq]++; + do_timer(regs); + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) + - r4k_cur) < 0x7fffffff); + return; + +null: + ack_r4ktimer(0); +} diff -urN linux-2.4.18/arch/mips/galileo-boards/generic/Makefile linux-2.4.19-pre5/arch/mips/galileo-boards/generic/Makefile --- linux-2.4.18/arch/mips/galileo-boards/generic/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/generic/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,39 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# ######################################################################## +# +# This program is free software; you can distribute it and/or modify it +# under the terms of the GNU General Public License (Version 2) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# ####################################################################### +# +# Makefile for the MIPS boards generic routines under Linux. +# +# 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: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET:= galboards.o + +obj-y := reset.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/galileo-boards/generic/reset.c linux-2.4.19-pre5/arch/mips/galileo-boards/generic/reset.c --- linux-2.4.18/arch/mips/galileo-boards/generic/reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/galileo-boards/generic/reset.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,73 @@ +/* + * BRIEF MODULE DESCRIPTION + * Galileo EV96100 reset routines. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/generic/reset.c + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void mips_machine_restart(char *command); +static void mips_machine_halt(void); + +static void mips_machine_restart(char *command) +{ + set_cp0_status(ST0_BEV | ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); + while (1); +} + +static void mips_machine_halt(void) +{ + printk(KERN_NOTICE "You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +void mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; +} diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/dbg_io.c linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/dbg_io.c --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/dbg_io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/dbg_io.c Sat Mar 30 22:55:26 2002 @@ -2,6 +2,8 @@ #if defined(CONFIG_REMOTE_DEBUG) +#include /* For the serial port location and base baud */ + /* --- CONFIG --- */ typedef unsigned char uint8; @@ -36,8 +38,8 @@ /* === CONFIG === */ /* [jsun] we use the second serial port for kdb */ -#define BASE 0xbd000020 -#define MAX_BAUD 115200 +#define BASE OCELOT_SERIAL1_BASE +#define MAX_BAUD OCELOT_BASE_BAUD /* === END OF CONFIG === */ @@ -111,7 +113,7 @@ { if (!remoteDebugInitialized) { remoteDebugInitialized = 1; - debugInit(UART16550_BAUD_9600, + debugInit(UART16550_BAUD_38400, UART16550_DATA_8BIT, UART16550_PARITY_NONE, UART16550_STOP_1BIT); } diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/irq.c linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/irq.c --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/irq.c Sat Mar 30 22:55:26 2002 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -144,9 +143,8 @@ /* * Clear all of the interrupts while we change the able around a bit. - * int-handler is not on bootstrap */ - clear_cp0_status(ST0_IM | ST0_BEV); + clear_cp0_status(ST0_IM); __cli(); /* Sets the first-level interrupt dispatcher. */ diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/ocelot_pld.h linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/ocelot_pld.h --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/ocelot_pld.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/ocelot_pld.h Sat Mar 30 22:55:26 2002 @@ -1,14 +1,10 @@ /* - * $Id$ - * * Ocelot Board Register Definitions * * (C) 2001 Red Hat, Inc. * * GPL'd - * */ - #ifndef __MOMENCO_OCELOT_PLD_H__ #define __MOMENCO_OCELOT_PLD_H__ diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/prom.c linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/prom.c --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/prom.c Sat Mar 30 22:55:26 2002 @@ -32,7 +32,12 @@ #define PLD_REG(x) ((uint8_t*)(PLD_BASE+(x))) -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; + +const char *get_system_type(void) +{ + return "Momentum Ocelot"; +} /* [jsun@junsun.net] PMON passes arguments in C main() style */ void __init prom_init(int argc, const char **arg) diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/reset.c linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/reset.c --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/reset.c Sat Mar 30 22:55:26 2002 @@ -15,22 +15,21 @@ #include #include #include +#include void momenco_ocelot_restart(char *command) { - *(volatile char *) 0xbc000000 = 0x0f; + void *nvram = ioremap_nocache(0x2c807000, 0x1000); - /* - * Ouch, we're still alive ... This time we take the silver bullet ... - * ... and find that we leave the hardware in a state in which the - * kernel in the flush locks up somewhen during of after the PCI - * detection stuff. - */ - clear_cp0_status(ST0_BEV | ST0_ERL); - change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); - write_32bit_cp0_register(CP0_WIRED, 0); - __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); + if (!nvram) { + printk(KERN_NOTICE "ioremap of reset register failed\n"); + return; + } + writeb(0x84, nvram + 0xff7); /* Ask the NVRAM/RTC/watchdog chip to + assert reset in 1/16 second */ + mdelay(10+(1000/16)); + iounmap(nvram); + printk(KERN_NOTICE "Watchdog reset failed\n"); } void momenco_ocelot_halt(void) diff -urN linux-2.4.18/arch/mips/gt64120/momenco_ocelot/setup.c linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/setup.c --- linux-2.4.18/arch/mips/gt64120/momenco_ocelot/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/gt64120/momenco_ocelot/setup.c Sat Mar 30 22:55:26 2002 @@ -2,11 +2,12 @@ * setup.c * * BRIEF MODULE DESCRIPTION - * Galileo Evaluation Boards - board dependent boot routines + * Momentum Computer Ocelot (CP7000) - board dependent boot routines * * Copyright (C) 1996, 1997, 2001 Ralf Baechle * Copyright (C) 2000 RidgeRun, Inc. * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2002 Momentum Computer * * Author: RidgeRun, Inc. * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com @@ -116,8 +117,7 @@ /* Also a temporary entry to let us talk to the Ocelot PLD and NVRAM in the CS[012] region. We can't use ioremap() yet. The NVRAM - appears to be one of the variants of ST M48T35 - see - http://www.st.com/stonline/bin/sftab.exe?table=172&filter0=M48T35 + is a ST M48T37Y, which includes NVRAM, RTC, and Watchdog functions. Ocelot PLD (CS0) 0x2c000000 0xe0020000 NVRAM 0x2c800000 0xe0030000 @@ -155,6 +155,7 @@ GT_WRITE(GT_PCI1M0LD_OFS, 0x32000000 >> 21); GT_WRITE(GT_PCI1M1LD_OFS, 0x34000000 >> 21); + /* For the initial programming, we assume 512MB configuration */ /* Relocate the CPU's view of the RAM... */ GT_WRITE(GT_SCS10LD_OFS, 0); GT_WRITE(GT_SCS10HD_OFS, 0x0fe00000 >> 21); @@ -207,17 +208,66 @@ switch(tmpword &3) { case 3: /* 512MiB */ - add_memory_region(256<<20, 256<<20, BOOT_MEM_RAM); + /* Decoders are allready set -- just add the + * appropriate region */ + add_memory_region( 0x40<<20, 0xC0<<20, BOOT_MEM_RAM); + add_memory_region(0x100<<20, 0x100<<20, BOOT_MEM_RAM); + break; case 2: - /* 256MiB */ - /* FIXME: Is it actually here, or at 0x10000000? */ - add_memory_region(128<<20, 128<<20, BOOT_MEM_RAM); + /* 256MiB -- two banks of 128MiB */ + GT_WRITE(GT_SCS10HD_OFS, 0x07e00000 >> 21); + GT_WRITE(GT_SCS32LD_OFS, 0x08000000 >> 21); + GT_WRITE(GT_SCS32HD_OFS, 0x0fe00000 >> 21); + + GT_WRITE(GT_SCS0HD_OFS, 0x7f); + GT_WRITE(GT_SCS2LD_OFS, 0x80); + GT_WRITE(GT_SCS2HD_OFS, 0xff); + + /* reconfigure the PCI0 interface view of memory */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, 0x80000014); + GT_WRITE(GT_PCI0_CFGDATA_OFS, 0x08000000); + GT_WRITE(GT_PCI0_BS_SCS10_OFS, 0x0ffff000); + GT_WRITE(GT_PCI0_BS_SCS32_OFS, 0x0ffff000); + + add_memory_region(0x40<<20, 0x40<<20, BOOT_MEM_RAM); + add_memory_region(0x80<<20, 0x80<<20, BOOT_MEM_RAM); + break; case 1: - /* 128MiB */ - add_memory_region(64<<20, 64<<20, BOOT_MEM_RAM); + /* 128MiB -- 64MiB per bank */ + GT_WRITE(GT_SCS10HD_OFS, 0x03e00000 >> 21); + GT_WRITE(GT_SCS32LD_OFS, 0x04000000 >> 21); + GT_WRITE(GT_SCS32HD_OFS, 0x07e00000 >> 21); + + GT_WRITE(GT_SCS0HD_OFS, 0x3f); + GT_WRITE(GT_SCS2LD_OFS, 0x40); + GT_WRITE(GT_SCS2HD_OFS, 0x7f); + + /* reconfigure the PCI0 interface view of memory */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, 0x80000014); + GT_WRITE(GT_PCI0_CFGDATA_OFS, 0x04000000); + GT_WRITE(GT_PCI0_BS_SCS10_OFS, 0x03fff000); + GT_WRITE(GT_PCI0_BS_SCS32_OFS, 0x03fff000); + + /* add the appropriate region */ + add_memory_region(0x40<<20, 0x40<<20, BOOT_MEM_RAM); + break; case 0: /* 64MiB */ - ; + GT_WRITE(GT_SCS10HD_OFS, 0x01e00000 >> 21); + GT_WRITE(GT_SCS32LD_OFS, 0x02000000 >> 21); + GT_WRITE(GT_SCS32HD_OFS, 0x03e00000 >> 21); + + GT_WRITE(GT_SCS0HD_OFS, 0x1f); + GT_WRITE(GT_SCS2LD_OFS, 0x20); + GT_WRITE(GT_SCS2HD_OFS, 0x3f); + + /* reconfigure the PCI0 interface view of memory */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, 0x80000014); + GT_WRITE(GT_PCI0_CFGDATA_OFS, 0x04000000); + GT_WRITE(GT_PCI0_BS_SCS10_OFS, 0x01fff000); + GT_WRITE(GT_PCI0_BS_SCS32_OFS, 0x01fff000); + + break; } /* Fix up the DiskOnChip mapping */ @@ -272,11 +322,13 @@ static int io_base_ioremap(void) { void *io_remap_range = ioremap(GT_PCI_IO_BASE, GT_PCI_IO_SIZE); + if (!io_remap_range) { - panic("Could not ioremap I/O port range\n"); + panic("Could not ioremap I/O port range"); } - mips_io_port_base = io_remap_range - GT_PCI_IO_BASE; + set_io_port_base(io_remap_range - GT_PCI_IO_BASE); + return 0; } -module_init(io_base_ioremap); +module_init(io_base_ioremap); diff -urN linux-2.4.18/arch/mips/hp-lj/Makefile linux-2.4.19-pre5/arch/mips/hp-lj/Makefile --- linux-2.4.18/arch/mips/hp-lj/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,43 @@ +# +# Makefile for the HP specific kernel interface routines +# under Linux. +# +# 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). +# + +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: hp-lj.o + +O_TARGET := hp-lj.o + +export-objs := utils.o + +obj-y := init.o setup.o irq.o int-handler.o pci.o utils.o asic.o + +obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o +obj-$(CONFIG_DIRECT_PRINTK) += gdb_hook.o + +obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o + +clean: + rm *.o + +forceit: + +# package filesystem from rootfs directory into binary package +romfs.bin: forceit ./rootfs + @genromfs -d ./rootfs -f $@ + +# transform rootfs.bin into object file format for linking +initrd.o: romfs.bin + @echo "" | $(CROSS_COMPILE)as -o $@ + @$(CROSS_COMPILE)objcopy --add-section .initrd=$< $@ + + +include $(TOPDIR)/Rules.make + +.PHONY: forceit diff -urN linux-2.4.18/arch/mips/hp-lj/asic.c linux-2.4.19-pre5/arch/mips/hp-lj/asic.c --- linux-2.4.18/arch/mips/hp-lj/asic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/asic.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,28 @@ + + +#include "asm/hp-lj/asic.h" + +AsicId GetAsicId(void) +{ + static int asic = IllegalAsic; + + if (asic == IllegalAsic) { + if (*(unsigned int *)0xbff70000 == 0x1114103c) + asic = HarmonyAsic; + else if (*(unsigned int *)0xbff80000 == 0x110d103c) + asic = AndrosAsic; + else + asic = UnknownAsic; + } + return asic; +} + + +const char* const GetAsicName(void) +{ + static const char* const Names[] = + { "Illegal", "Unknown", "Andros", "Harmony" }; + + return Names[(int)GetAsicId()]; +} + diff -urN linux-2.4.18/arch/mips/hp-lj/gdb_hook.c linux-2.4.19-pre5/arch/mips/hp-lj/gdb_hook.c --- linux-2.4.18/arch/mips/hp-lj/gdb_hook.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/gdb_hook.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,102 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * This is the interface to the remote debugger stub. + * + */ + +#include +#include +#include + +#include +#include +#include + + +int putDebugChar(char c); +char getDebugChar(void); + + +/////////////////////// andros values /////////////////////////////////////////////////////// +#define SERIAL_REG(offset) (*((volatile unsigned int*)(HPSR_BASE_ADDR|offset))) + +// Register set base address +#define HPSR_BASE_ADDR 0xbfe00000UL + +// Transmit / Receive Data +#define HPSR_DATA_OFFSET 0x00020010UL +// Transmit control / status +#define HPSR_TX_STAT_OFFSET 0x0002000CUL +// Receive status +#define HPSR_RX_STAT_OFFSET 0x00020008UL + +#define HPSR_TX_STAT_READY 0x8UL +#define HPSR_RX_DATA_AVAIL 0x4UL + + +/////////////////////// harmony values /////////////////////////////////////////////////////// +// Transmit / Receive Data +#define H_HPSR_DATA_TX *((volatile unsigned int*)0xbff65014) +// Transmit / Receive Data +#define H_HPSR_DATA_RX *((volatile unsigned int*)0xbff65018) +// Status +#define H_HPSR_STAT *((volatile unsigned int*)0xbff65004) + +// harmony serial status bits +#define H_SER_STAT_TX_EMPTY 0x04 +#define H_SER_STAT_RX_EMPTY 0x10 + + + + +int putDebugChar(char c) +{ + if (GetAsicId() == HarmonyAsic) { + while (!( ( (H_HPSR_STAT) & H_SER_STAT_TX_EMPTY) != 0)); + + H_HPSR_DATA_TX = (unsigned int) c; + + } else if (GetAsicId() == AndrosAsic) { + while (((SERIAL_REG(HPSR_TX_STAT_OFFSET) & HPSR_TX_STAT_READY) == 0)) + ; + SERIAL_REG(HPSR_DATA_OFFSET) = (unsigned int) c; + } + return 1; +} + +char getDebugChar(void) +{ + if (GetAsicId() == HarmonyAsic) { + while (!(((H_HPSR_STAT) & H_SER_STAT_RX_EMPTY) == 0)); + + return H_HPSR_DATA_RX; + + } else if (GetAsicId() == AndrosAsic) { + while ((SERIAL_REG(HPSR_RX_STAT_OFFSET) & HPSR_RX_DATA_AVAIL) == 0) + ; + + return (SERIAL_REG(HPSR_DATA_OFFSET)); + + } +} + + diff -urN linux-2.4.18/arch/mips/hp-lj/init.c linux-2.4.19-pre5/arch/mips/hp-lj/init.c --- linux-2.4.18/arch/mips/hp-lj/init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/init.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,53 @@ +/* + * init.c: PROM library initialisation code. + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +#include +#include +#include +#include +#include + +#include "utils.h" + + +#define Delimiter "CMDLINE=" +const char CommandLine[] = Delimiter + "root=/dev/hda3 "; + +char arcs_cmdline[CL_SIZE]; + +int __init prom_init(int argc, char ** argv, char **envp) +{ + ulong mem_size = get_mem_avail(); + int reserve_size = 0; + + printk("Total Memory: %ld bytes\n", mem_size); + + reserve_buffer(CommandLine, mem_size); + + reserve_size = get_reserved_buffer_size(); + mem_size -= reserve_size; + + add_memory_region(0x0,mem_size, BOOT_MEM_RAM); + add_memory_region(mem_size,reserve_size, BOOT_MEM_RESERVED); + + printk("Main Memory: %ld bytes\n", mem_size); + printk("Reserved Memory: %ld bytes at 0x%08x\n", + get_reserved_buffer_size(), (ulong)get_reserved_buffer()); + + printk("Detected %s ASIC\n", GetAsicName()); + mips_machgroup = MACH_GROUP_HP_LJ; + mips_machtype = MACH_UNKNOWN; + + strcpy(arcs_cmdline, CommandLine+strlen(Delimiter)); + + return 0; +} + + +void prom_free_prom_memory (void) +{ +} diff -urN linux-2.4.18/arch/mips/hp-lj/int-handler.S linux-2.4.19-pre5/arch/mips/hp-lj/int-handler.S --- linux-2.4.18/arch/mips/hp-lj/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,70 @@ +#include + +#include +#include +#include + + .text + .set mips1 + .set reorder + .set macro + .set noat + .align 5 + +# MIPS has 16 exception vectors numbered 0 to 15 +# vector number 0 is for interrupts and the others are for various exceptions +# The following code is installed as the handler for exception 0 +# There are 8 possible interrupts that can cause this exception. +# The cause register indicates which are pending +# The status register indicates which are enabled +# This code segment basically will decipher which interrup occurred (7 downto 0) +# and pass an integer indicating which was the highest priority pending interrupt +# to the do_IRQ routine. + +NESTED(hpIRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + /* + * Get pending interrupts + */ + + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + andi t0,0xff00 # isolate pending bits + sll t0,16 # shift the pending bits down + beqz t0,3f # no pending intrs, then spurious + nop # delay slot + + /* + * Find irq with highest priority + * FIXME: This is slow - use binary search + */ + + la a0,7 +1: bltz t0,2f # found pending irq + subu a0,1 + sll t0,1 + b 1b + nop # delay slot + + +call_do_IRQ: +2: move a1,sp + jal do_IRQ + nop # delay slot + j ret_from_irq + nop + +/* + mfc0 t0,CP0_STATUS # disable interrupts + ori t0,1 + xori t0,1 + mtc0 t0,CP0_STATUS + + la a1, ret_from_irq + jr a1 +*/ +3: j spurious_interrupt +END(hpIRQ) + diff -urN linux-2.4.18/arch/mips/hp-lj/irq.c linux-2.4.19-pre5/arch/mips/hp-lj/irq.c --- linux-2.4.18/arch/mips/hp-lj/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,41 @@ +/* + * 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. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ + +#include +#include +#include +#include +#include +#include + + +/* install the handler for exception 0 */ +void __init init_IRQ(void) +{ + extern void hpIRQ(void); + extern void mips_cpu_irq_init(u32 base); + mips_cpu_irq_init(0); + set_except_vector(0, hpIRQ); + +#ifdef CONFIG_REMOTE_DEBUG + { + extern void breakpoint(void); + extern int remote_debug; + + if (remote_debug) { + set_debug_traps(); + breakpoint(); + } + } +#endif + +} + diff -urN linux-2.4.18/arch/mips/hp-lj/pci-dma.c linux-2.4.19-pre5/arch/mips/hp-lj/pci-dma.c --- linux-2.4.18/arch/mips/hp-lj/pci-dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/pci-dma.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2000 Ani Joshi + * + * + * Dynamic DMA mapping support. + * + * swiped from i386, and cloned for MIPS by Geert. + * + */ + +#include +#include +#include +#include +#include + +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); + + + // REVISIT this needs reviewal as mentioned in bug report + // currently we bump kseg0 allocates to kseg1 uncacheable space + + if ((((unsigned int) ret) & 0xe0000000) == 0x80000000) { + //flush the cache to eliminate coherency problems + // and assure dirty lines won't later get written over any dma, etc. + flush_cache_all(); + ret = (void*)((unsigned int)ret | 0x20000000); + } + + + } + 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 -urN linux-2.4.18/arch/mips/hp-lj/pci.c linux-2.4.19-pre5/arch/mips/hp-lj/pci.c --- linux-2.4.18/arch/mips/hp-lj/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/pci.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,230 @@ +/* + * 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. + * + * SNI specific PCI support for RM200/RM300. + * + * Copyright (C) 1997 - 2000 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PCI + +volatile u32* pci_config_address_reg = (volatile u32*)0xfdead000; +volatile u32* pci_config_data_reg = (volatile u32*)0xfdead000; + + + +#define cfgaddr(dev, where) (((dev->bus->number & 0xff) << 0x10) | \ + ((dev->devfn & 0xff) << 0x08) | \ + (where & 0xfc)) + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int pcimt_read_config_byte (struct pci_dev *dev, + int where, unsigned char *val) +{ + *pci_config_address_reg = cfgaddr(dev, where); + *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xff; + //printk("pci_read_byte 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +static int pcimt_read_config_word (struct pci_dev *dev, + int where, unsigned short *val) +{ + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xffff; + //printk("pci_read_word 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +int pcimt_read_config_dword (struct pci_dev *dev, + int where, unsigned int *val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *val = le32_to_cpu(*pci_config_data_reg); + //printk("pci_read_dword 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +static int pcimt_write_config_byte (struct pci_dev *dev, + int where, unsigned char val) +{ + *pci_config_address_reg = cfgaddr(dev, where); + *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; + //printk("pci_write_byte 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + +static int pcimt_write_config_word (struct pci_dev *dev, + int where, unsigned short val) +{ + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = + le16_to_cpu(val); + //printk("pci_write_word 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + +int pcimt_write_config_dword (struct pci_dev *dev, + int where, unsigned int val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *pci_config_data_reg = le32_to_cpu(val); + //printk("pci_write_dword 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + + + +struct pci_ops hp_pci_ops = { + pcimt_read_config_byte, + pcimt_read_config_word, + pcimt_read_config_dword, + pcimt_write_config_byte, + pcimt_write_config_word, + pcimt_write_config_dword +}; + + +struct pci_channel mips_pci_channels[] = { + { &hp_pci_ops, &ioport_resource, &iomem_resource }, + { NULL, NULL, NULL } +}; + +unsigned __init int pcibios_assign_all_busses(void) +{ + return 1; +} + +void __init pcibios_fixup(void) +{ +} + + +void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch(slot_num) { + case 2: dev->irq = 3; break; + case 3: dev->irq = 4; break; + case 4: dev->irq = 5; break; + default: break; + } + } +} + +#define IO_MEM_LOGICAL_START 0x3e000000 +#define IO_MEM_LOGICAL_END 0x3fefffff + +#define IO_PORT_LOGICAL_START 0x3ff00000 +#define IO_PORT_LOGICAL_END 0x3fffffff + + +#define IO_MEM_VIRTUAL_OFFSET 0xb0000000 +#define IO_PORT_VIRTUAL_OFFSET 0xb0000000 + +#define ONE_MEG (1024 * 1024) + +void __init pci_setup(void) +{ + u32 pci_regs_base_offset = 0xfdead000; + + switch(GetAsicId()) { + case AndrosAsic: pci_regs_base_offset = 0xbff80000; break; + case HarmonyAsic: pci_regs_base_offset = 0xbff70000; break; + default: + printk("ERROR: PCI does not support %s Asic\n", GetAsicName()); + while(1); + break; + } + + // set bus stat/command reg + // REVIST this setting may need vary depending on the hardware + *((volatile unsigned int*)(pci_regs_base_offset | 0x0004)) = 0x38000007; + + + iomem_resource.start = IO_MEM_LOGICAL_START + IO_MEM_VIRTUAL_OFFSET; + iomem_resource.end = IO_MEM_LOGICAL_END + IO_MEM_VIRTUAL_OFFSET; + + ioport_resource.start = IO_PORT_LOGICAL_START + IO_PORT_VIRTUAL_OFFSET; + ioport_resource.end = IO_PORT_LOGICAL_END + IO_PORT_VIRTUAL_OFFSET; + + // KLUDGE (mips_io_port_base is screwed up, we've got to work around it here) + // by letting both low (illegal) and high (legal) addresses appear in pci io space + ioport_resource.start = 0x0; + + set_io_port_base(IO_PORT_LOGICAL_START + IO_PORT_VIRTUAL_OFFSET); + + // map the PCI address space + // global map - all levels & processes can access + // except that the range is outside user space + // parameters: lo0, lo1, hi, pagemask + // lo indicates physical page, hi indicates virtual address + add_wired_entry((IO_MEM_LOGICAL_START >> 6) | 0x17, + ((IO_MEM_LOGICAL_START + (16 * ONE_MEG)) >> 6) | 0x17, + 0xee000000, PM_16M); + + + // These are used in pci r/w routines so need to preceed bus scan + pci_config_data_reg = (u32*) (((u32)mips_io_port_base) | 0xcfc); + pci_config_address_reg = (u32*) (((u32)pci_regs_base_offset) | 0xcf8); + +} + + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ + int pos; + int bases; + + printk("adjusting pci device: %s\n", dev->name); + + switch (dev->hdr_type) { + case PCI_HEADER_TYPE_NORMAL: bases = 6; break; + case PCI_HEADER_TYPE_BRIDGE: bases = 2; break; + case PCI_HEADER_TYPE_CARDBUS: bases = 1; break; + default: bases = 0; break; + } + for (pos=0; pos < bases; pos++) { + struct resource* res = &dev->resource[pos]; + if (res->start >= IO_MEM_LOGICAL_START && + res->end <= IO_MEM_LOGICAL_END) { + res->start += IO_MEM_VIRTUAL_OFFSET; + res->end += IO_MEM_VIRTUAL_OFFSET; + } + if (res->start >= IO_PORT_LOGICAL_START && + res->end <= IO_PORT_LOGICAL_END) { + res->start += IO_PORT_VIRTUAL_OFFSET; + res->end += IO_PORT_VIRTUAL_OFFSET; + } + } + +} + + +#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/hp-lj/setup.c linux-2.4.19-pre5/arch/mips/hp-lj/setup.c --- linux-2.4.18/arch/mips/hp-lj/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,161 @@ +/* + * Setup pointers to hardware-dependent routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +#ifdef CONFIG_REMOTE_DEBUG +int remote_debug = 0; +#endif + +const char *get_system_type(void) +{ + return "HP LaserJet"; /* But which exactly? */ +} + +static void (*timer_interrupt_service)(int irq, void *dev_id, struct pt_regs * regs) = NULL; + + +static void andros_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + if (!(*((volatile unsigned int*)0xbfea0010) & 0x20)) // mask = pend & en + return; + + /* clear timer interrupt */ + { + unsigned int tmr = *((volatile unsigned int*)0xbfe90040); // ctl bits + *((volatile unsigned int*)0xbfe90040) = tmr; // write to ack + *((volatile unsigned int*)0xbfea000c) = 0x20; // sys int ack + } + + /* service interrupt */ + timer_interrupt_service(irq, dev_id, regs); +} + +static void harmony_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + if (!(*((volatile unsigned int*)0xbff63000) & 0x01)) + return; // big sys int reg, 01-timer did it + if (!(*((volatile unsigned int*)0xbff610a4) & 0x01)) + return; // local small int reg, 01-timer0 did it + + *((volatile unsigned int*)0xbff610a4) = 1; // ack local timer0 bit + *((volatile unsigned int*)0xbff63000) = 1; // ack global timer bit + + /* service interrupt */ + timer_interrupt_service(irq, dev_id, regs); +} + + +#define ASIC_IRQ_NUMBER 2 + + +static void __init hp_time_init(struct irqaction *irq) +{ + timer_interrupt_service = irq->handler; + + if (GetAsicId() == AndrosAsic) { + //*((volatile unsigned int*)0xbfe90000) = 0x2f; // set by bootloader to 0x20 // prescaler + *((volatile unsigned int*)0xbfe90040) = 0x21; // 20-res of 1kHz,1-int ack // control + *((volatile unsigned int*)0xbfe90048) = 0x09; // 09-reload val // reload + *((volatile unsigned int*)0xbfe90044) = 0x09; // 09-count val // count + *((volatile unsigned int*)0xbfe90040) = 0x2f; // 8-int enable,4-reload en,2-count down en,1-int-ack + + irq->handler = andros_timer_interrupt; + irq->flags |= SA_INTERRUPT | SA_SHIRQ; + printk("setting up timer in hp_time_init\n"); + setup_irq(ASIC_IRQ_NUMBER, irq); + + // enable timer interrupt + *((volatile unsigned int*)0xbfea0000) = 0x20; + + } else if (GetAsicId() == HarmonyAsic) { + + *((volatile unsigned int*)0xbff61000) = 99; // prescaler, 100Mz sys clk + *((volatile unsigned int*)0xbff61028) = 0x09; // reload reg + *((volatile unsigned int*)0xbff61024) = 0x09; // count reg + *((volatile unsigned int*)0xbff61020) = 0x0b; // 80-1khz res on timer, 2 reload en, 1 - count down en + + irq->handler = harmony_timer_interrupt; + irq->flags |= SA_INTERRUPT | SA_SHIRQ; + setup_irq(ASIC_IRQ_NUMBER, irq); + + *((volatile unsigned int*)0xbff610a0) |= 1; // turn on timer0 + + } else if (GetAsicId() == UnknownAsic) + printk("Unknown asic in hp_time_init()\n"); + else + printk("Unsupported asic in hp_time_init()\n"); +} + + +static void hplj_restart(void) +{ + if (GetAsicId() == AndrosAsic) + *((volatile unsigned int *) 0xbfe900c0) = 0; + + + if (GetAsicId() == HarmonyAsic) + *((volatile unsigned int *) 0xbff62030) = 0; + + printk("Restart Failed ... halting instead\n"); + while(1); +} + +static void hplj_halt(void) +{ + while(1); +} + + +void __init hp_setup(void) +{ +#ifdef CONFIG_PCI + extern void pci_setup(void); + pci_setup(); +#endif + +#ifdef CONFIG_IDE + { + extern struct ide_ops std_ide_ops; + ide_ops = &std_ide_ops; + } +#endif + + _machine_restart =(void (*)(char *)) hplj_restart; + _machine_halt = hplj_halt; + _machine_power_off = hplj_halt; + + board_timer_setup = hp_time_init; + +#ifdef CONFIG_REMOTE_DEBUG + { + extern char CommandLine[]; + remote_debug = (strstr(CommandLine, "kgdb") != NULL); + } +#endif + + printk("HP SETUP\n"); +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + diff -urN linux-2.4.18/arch/mips/hp-lj/utils.c linux-2.4.19-pre5/arch/mips/hp-lj/utils.c --- linux-2.4.18/arch/mips/hp-lj/utils.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/utils.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,71 @@ +/* + * + * + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "utils.h" + + +#define miu_chan_cfg(x) ((volatile unsigned long *)(0xbff40000+x*4)) /* for andros */ + +int mbsize[8] = {1,2,4,8,16,32,64,128}; + +unsigned long get_mem_avail(void) { + + unsigned long cfg[10],i,total_mem=0; + + for(i=0;i<10;i++) + cfg[i] = *miu_chan_cfg(i); + + for(i=0;i<10;i++){ + if(cfg[i]==0x1fc160c2) continue; // skip empties + if( ( (cfg[i]>>12) & 0xf ) <= 0xb ) continue; // skip roms + total_mem += mbsize[(cfg[i]>>16)&0x7] *1024*1024; + } + return total_mem; +} + + + + +static ulong* buffer_ptr = NULL; +static ulong buffer_size = 0; + +ulong* get_reserved_buffer(void) {return KSEG0ADDR(buffer_ptr);} +ulong* get_reserved_buffer_virtual(void) {return (ulong*)ReservedMemVirtualAddr;} +ulong get_reserved_buffer_size(void) {return buffer_size;} + +#define MIN_GEN_MEM (4 << 20) + + +void reserve_buffer(const char* cl, ulong base_mem) +{ + char* pos = strstr(cl, "reserved_buffer="); + if (pos) { + buffer_size = simple_strtol(pos+strlen("reserved_buffer="), + 0, 10); + buffer_size <<= 20; + if (buffer_size + MIN_GEN_MEM > base_mem) + buffer_size = base_mem - MIN_GEN_MEM; + if (buffer_size > 0) + buffer_ptr = (ulong*)(base_mem - buffer_size); + else + buffer_size = 0; + } +} + + + +EXPORT_SYMBOL(get_reserved_buffer); +EXPORT_SYMBOL(get_reserved_buffer_virtual); +EXPORT_SYMBOL(get_reserved_buffer_size); + + diff -urN linux-2.4.18/arch/mips/hp-lj/utils.h linux-2.4.19-pre5/arch/mips/hp-lj/utils.h --- linux-2.4.18/arch/mips/hp-lj/utils.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/hp-lj/utils.h Sat Mar 30 22:55:26 2002 @@ -0,0 +1,19 @@ +/* + * + * + * + */ + +#include + +#define ReservedMemVirtualAddr 0x50000000 + +unsigned long get_mem_avail(void); + +ulong* get_reserved_buffer(void); +ulong* get_reserved_buffer_virtual(void); +ulong get_reserved_buffer_size(void); + +void reserve_buffer(const char* cl, ulong base_mem); + + diff -urN linux-2.4.18/arch/mips/ite-boards/generic/Makefile linux-2.4.19-pre5/arch/mips/ite-boards/generic/Makefile --- linux-2.4.18/arch/mips/ite-boards/generic/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/Makefile Sat Mar 30 22:55:26 2002 @@ -21,16 +21,8 @@ obj-y := it8172_rtc.o it8172_setup.o irq.o int-handler.o pmon_prom.o time.o lpc.o puts.o reset.o -ifdef CONFIG_PCI -obj-y += it8172_pci.o -endif - -ifdef CONFIG_IT8172_CIR -obj-y += it8172_cir.o -endif - -ifdef CONFIG_REMOTE_DEBUG - obj-y += dbg_io.o -endif +obj-$(CONFIG_PCI) += it8172_pci.o +obj-$(CONFIG_IT8172_CIR) += it8172_cir.o +obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ite-boards/generic/int-handler.S linux-2.4.19-pre5/arch/mips/ite-boards/generic/int-handler.S --- linux-2.4.18/arch/mips/ite-boards/generic/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/int-handler.S Sat Mar 30 22:55:26 2002 @@ -27,7 +27,7 @@ andi a0, t0, CAUSEF_IP7 beq a0, zero, 1f move a0, sp - jal mips_timer_interrupt + jal local_timer_interrupt j ret_from_irq nop diff -urN linux-2.4.18/arch/mips/ite-boards/generic/irq.c linux-2.4.19-pre5/arch/mips/ite-boards/generic/irq.c --- linux-2.4.18/arch/mips/ite-boards/generic/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/irq.c Sat Mar 30 22:55:26 2002 @@ -72,17 +72,17 @@ #define EXT_IRQ0_TO_IP 2 /* IP 2 */ #define EXT_IRQ5_TO_IP 7 /* IP 7 */ -extern void set_debug_traps(void); -extern void mips_timer_interrupt(int irq, struct pt_regs *regs); -extern asmlinkage void it8172_IRQ(void); +#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4) + unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -unsigned long spurious_count = 0; -irq_desc_t irq_desc[NR_IRQS]; -irq_desc_t *irq_desc_base=&irq_desc[0]; void disable_it8172_irq(unsigned int irq_nr); void enable_it8172_irq(unsigned int irq_nr); +extern void set_debug_traps(void); +extern void mips_timer_interrupt(int irq, struct pt_regs *regs); +extern asmlinkage void it8172_IRQ(void); + struct it8172_intc_regs volatile *it8172_hw0_icregs = (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); @@ -105,7 +105,7 @@ modify_cp0_intmask(0, irq_nr); } -void disable_irq(unsigned int irq_nr) +void local_disable_irq(unsigned int irq_nr) { unsigned long flags; @@ -114,7 +114,7 @@ restore_flags(flags); } -void enable_irq(unsigned int irq_nr) +void local_enable_irq(unsigned int irq_nr) { unsigned long flags; @@ -130,63 +130,70 @@ if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { /* LPC interrupt */ - DPRINTK("disable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); - it8172_hw0_icregs->lpc_mask |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); - DPRINTK("disable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + DPRINTK("DB lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask |= + (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("DA lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { /* Local Bus interrupt */ - DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); - it8172_hw0_icregs->lb_mask |= (1 << (irq_nr - IT8172_LB_IRQ_BASE)); - DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + DPRINTK("DB lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask |= + (1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("DA lb_mask %x\n", it8172_hw0_icregs->lb_mask); } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { /* PCI and other interrupts */ - DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); - it8172_hw0_icregs->pci_mask |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); - DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + DPRINTK("DB pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask |= + (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("DA pci_mask %x\n", it8172_hw0_icregs->pci_mask); } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { /* NMI interrupts */ - DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); - it8172_hw0_icregs->nmi_mask |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); - DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + DPRINTK("DB nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask |= + (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("DA nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); } else { - panic("disable_it8172_irq: bad irq %d\n", irq_nr); + panic("disable_it8172_irq: bad irq %d", irq_nr); } } - void enable_it8172_irq(unsigned int irq_nr) { DPRINTK("enable_it8172_irq %d\n", irq_nr); if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) { /* LPC interrupt */ - DPRINTK("enable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); - it8172_hw0_icregs->lpc_mask &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); - DPRINTK("enable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + DPRINTK("EB before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); + it8172_hw0_icregs->lpc_mask &= + ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + DPRINTK("EA after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask); } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) { /* Local Bus interrupt */ - DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask); - it8172_hw0_icregs->lb_mask &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); - DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask); + DPRINTK("EB lb_mask %x\n", it8172_hw0_icregs->lb_mask); + it8172_hw0_icregs->lb_mask &= + ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); + DPRINTK("EA lb_mask %x\n", it8172_hw0_icregs->lb_mask); } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) { /* PCI and other interrupts */ - DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask); - it8172_hw0_icregs->pci_mask &= ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); - DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask); + DPRINTK("EB pci_mask %x\n", it8172_hw0_icregs->pci_mask); + it8172_hw0_icregs->pci_mask &= + ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + DPRINTK("EA pci_mask %x\n", it8172_hw0_icregs->pci_mask); } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) { /* NMI interrupts */ - DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); - it8172_hw0_icregs->nmi_mask &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); - DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + DPRINTK("EB nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); + it8172_hw0_icregs->nmi_mask &= + ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + DPRINTK("EA nmi_mask %x\n", it8172_hw0_icregs->nmi_mask); } else { - panic("enable_it8172_irq: bad irq %d\n", irq_nr); + panic("enable_it8172_irq: bad irq %d", irq_nr); } } @@ -217,160 +224,25 @@ }; -int get_irq_list(char *buf) -{ - int i, len = 0, j; - struct irqaction * action; - - len += sprintf(buf+len, " "); - for (j=0; jhandler ) - continue; - len += sprintf(buf+len, "%3d: ", i); - len += sprintf(buf+len, "%10u ", kstat_irqs(i)); - if ( irq_desc[i].handler ) - len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); - else - len += sprintf(buf+len, " None "); - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); - } - len += sprintf(buf+len, "BAD: %10lu\n", spurious_count); - return len; -} - -asmlinkage void do_IRQ(int irq, struct pt_regs *regs) -{ - struct irqaction *action; - int cpu; - - cpu = smp_processor_id(); - irq_enter(cpu, irq); - - kstat.irqs[cpu][irq]++; -#if 0 - if (irq_desc[irq].handler && irq_desc[irq].handler->ack) { - // printk("invoking ack handler\n"); - irq_desc[irq].handler->ack(irq); - } -#endif - - action = irq_desc[irq].action; - - if (action && action->handler) - { - //mask_irq(1<handler %x\n", action->handler); - disable_it8172_irq(irq); - //if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */ - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while ( action ); - //__cli(); /* disable ints */ - if (irq_desc[irq].handler) - { - } - //unmask_irq(1<cp0_cause); - disable_it8172_irq(irq); - } - irq_exit(cpu, irq); -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - struct irqaction *old, **p, *action; - unsigned long flags; +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) { } + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +static struct hw_interrupt_type cp0_irq_type = { + "CP0 Count", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; - /* - * IP0 and IP1 are software interrupts. IP7 is typically the timer interrupt. - * - * The ITE QED-4N-S01B board has one single interrupt line going from - * the system controller to the CPU. It's connected to the CPU external - * irq pin 1, which is IP2. The interrupt numbers are listed in it8172_int.h; - * the ISA interrupts are numbered from 0 to 15, and the rest go from - * there. - */ - - //printk("request_irq: %d handler %x\n", irq, handler); - if (irq >= NR_IRQS) - return -EINVAL; - - if (!handler) - { - /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - disable_it8172_irq(irq); - restore_flags(flags); - kfree(action); - return 0; - } - return -ENOENT; - } - - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - memset(action, 0, sizeof(struct irqaction)); - - save_flags(flags); - cli(); - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = NULL; - - p = &irq_desc[irq].action; - - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & action->flags & SA_SHIRQ)) - return -EBUSY; - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - } - *p = action; - enable_it8172_irq(irq); - restore_flags(flags); -#if 0 - printk("request_irq: status %x cause %x\n", - read_32bit_cp0_register(CP0_STATUS), read_32bit_cp0_register(CP0_CAUSE)); -#endif - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} void enable_cpu_timer(void) { @@ -381,26 +253,17 @@ restore_flags(flags); } -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - void __init init_IRQ(void) { int i; unsigned long flags; - memset(irq_desc, 0, sizeof(irq_desc)); set_except_vector(0, it8172_IRQ); + init_generic_irq(); + /* mask all interrupts */ it8172_hw0_icregs->lb_mask = 0xffff; it8172_hw0_icregs->lpc_mask = 0xffff; @@ -431,20 +294,11 @@ ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE)); #endif - for (i = 0; i <= IT8172_INT_END; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - irq_desc[i].handler = &it8172_irq_type; + for (i = 0; i <= IT8172_LAST_IRQ; i++) { + irq_desc[i].handler = &it8172_irq_type; } - - /* - * Enable external int line 2 - * All ITE interrupts are masked for now. - */ - save_and_cli(flags); - unmask_irq(1<intstatus; if (intstatus & 0x8) { - panic("Got NMI interrupt\n"); + panic("Got NMI interrupt"); } else if (intstatus & 0x4) { /* PCI interrupt */ irq = 0; - status = it8172_hw0_icregs->pci_req; + status |= it8172_hw0_icregs->pci_req; while (!(status & 0x1)) { irq++; status >>= 1; @@ -493,7 +347,7 @@ else if (intstatus & 0x1) { /* Local Bus interrupt */ irq = 0; - status = it8172_hw0_icregs->lb_req; + status |= it8172_hw0_icregs->lb_req; while (!(status & 0x1)) { irq++; status >>= 1; @@ -507,7 +361,7 @@ * we could lose an interrupt this way because * we acknowledge all ints at onces. Revisit. */ - status = it8172_hw0_icregs->lpc_req; + status |= it8172_hw0_icregs->lpc_req; it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */ irq = 0; while (!(status & 0x1)) { diff -urN linux-2.4.18/arch/mips/ite-boards/generic/it8172_pci.c linux-2.4.19-pre5/arch/mips/ite-boards/generic/it8172_pci.c --- linux-2.4.18/arch/mips/ite-boards/generic/it8172_pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/it8172_pci.c Sat Mar 30 22:55:26 2002 @@ -1,4 +1,5 @@ /* + * * BRIEF MODULE DESCRIPTION * IT8172 system controller specific pci support. * @@ -35,6 +36,7 @@ #include #include +#include #include #include @@ -42,7 +44,47 @@ #define PCI_ACCESS_WRITE 1 #undef DEBUG -#undef DEBUG_CONFIG_CYCLES +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct resource pci_mem_resource_1; + +static struct resource pci_io_resource = { + "io pci IO space", + 0x14000000, + 0x17FFFFFF, + IORESOURCE_IO +}; + +static struct resource pci_mem_resource_0 = { + "ext pci memory space 0/1", + 0x0C000000, + 0x13FFFFFF, + IORESOURCE_MEM, + &pci_mem_resource_0, + NULL, + &pci_mem_resource_1 +}; + +static struct resource pci_mem_resource_1 = { + "ext pci memory space 2/3", + 0x1A000000, + 0x1FBFFFFF, + IORESOURCE_MEM, + &pci_mem_resource_0, + NULL, + NULL +}; + +extern struct pci_ops it8172_pci_ops; + +struct pci_channel mips_pci_channels[] = { + { &it8172_pci_ops, &pci_io_resource, &pci_mem_resource_0, 0, 0xff }, + { NULL, NULL, NULL, NULL, NULL} +}; static int it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, @@ -54,12 +96,9 @@ unsigned char bus = dev->bus->number; unsigned char dev_fn = dev->devfn; -#ifdef DEBUG_CONFIG_CYCLES - printk("it config: type %d dev %x bus %d dev_fn %x data %x\n", + DBG("it config: type %d dev %x bus %d dev_fn %x data %x\n", access_type, dev, bus, dev_fn, *data); -#endif - /* Setup address */ IT_WRITE(IT_CONFADDR, (bus << IT_BUSNUM_SHF) | (dev_fn << IT_FUNCNUM_SHF) | (where & ~0x3)); @@ -86,7 +125,7 @@ * read/write a 32bit word and mask/modify the data we actually want. */ static int -it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) +read_config_byte (struct pci_dev *dev, int where, u8 *val) { u32 data = 0; @@ -94,17 +133,15 @@ return -1; *val = (data >> ((where & 3) << 3)) & 0xff; -#ifdef DEBUG - printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n", + DBG("cfg read byte: bus %d dev_fn %x where %x: val %x\n", dev->bus->number, dev->devfn, where, *val); -#endif return PCIBIOS_SUCCESSFUL; } static int -it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) +read_config_word (struct pci_dev *dev, int where, u16 *val) { u32 data = 0; @@ -115,16 +152,14 @@ return -1; *val = (data >> ((where & 3) << 3)) & 0xffff; -#ifdef DEBUG - printk("cfg read word: bus %d dev_fn %x where %x: val %x\n", + DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n", dev->bus->number, dev->devfn, where, *val); -#endif return PCIBIOS_SUCCESSFUL; } static int -it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) +read_config_dword (struct pci_dev *dev, int where, u32 *val) { u32 data = 0; @@ -135,17 +170,15 @@ return -1; *val = data; -#ifdef DEBUG - printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n", + DBG("cfg read dword: bus %d dev_fn %x where %x: val %x\n", dev->bus->number, dev->devfn, where, *val); -#endif return PCIBIOS_SUCCESSFUL; } static int -it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) +write_config_byte (struct pci_dev *dev, int where, u8 val) { u32 data = 0; @@ -162,7 +195,7 @@ } static int -it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) +write_config_word (struct pci_dev *dev, int where, u16 val) { u32 data = 0; @@ -183,7 +216,7 @@ } static int -it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) +write_config_dword(struct pci_dev *dev, int where, u32 val) { if (where & 3) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -195,87 +228,16 @@ } struct pci_ops it8172_pci_ops = { - it8172_pcibios_read_config_byte, - it8172_pcibios_read_config_word, - it8172_pcibios_read_config_dword, - it8172_pcibios_write_config_byte, - it8172_pcibios_write_config_word, - it8172_pcibios_write_config_dword + read_config_byte, + read_config_word, + read_config_dword, + write_config_byte, + write_config_word, + write_config_dword }; -void __init pcibios_init(void) -{ - - printk("PCI: Probing PCI hardware on host bus 0.\n"); - pci_scan_bus(0, &it8172_pci_ops, NULL); -} - -int __init -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 (dev->resource[PCI_ROM_RESOURCE].start) - 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; -} - - -void __init -pcibios_align_resource(void *data, struct resource *res, unsigned long size) -{ - printk("pcibios_align_resource\n"); -} - -char * __init -pcibios_setup(char *str) -{ - /* Nothing to do for now. */ - - return str; -} - -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); -} - -void __init pcibios_fixup_bus(struct pci_bus *b) -{ - //printk("pcibios_fixup_bus\n"); -} - unsigned __init int pcibios_assign_all_busses(void) { - return 1; + return 1; } - #endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips/ite-boards/generic/it8172_setup.c linux-2.4.19-pre5/arch/mips/ite-boards/generic/it8172_setup.c --- linux-2.4.18/arch/mips/ite-boards/generic/it8172_setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/it8172_setup.c Sat Mar 30 22:55:26 2002 @@ -53,7 +53,6 @@ extern struct rtc_ops it8172_rtc_ops; extern struct resource ioport_resource; -extern unsigned long mips_io_port_base; #ifdef CONFIG_BLK_DEV_IDE extern struct ide_ops std_ide_ops; extern struct ide_ops *ide_ops; @@ -70,6 +69,14 @@ extern void it8172_halt(void); extern void it8172_power_off(void); +extern void (*board_time_init)(void); +extern void (*board_timer_setup)(struct irqaction *irq); +extern unsigned long (*rtc_get_time)(void); +extern int (*rtc_set_time)(unsigned long); +extern void it8172_time_init(void); +extern void it8172_timer_setup(struct irqaction *irq); +extern unsigned long it8172_rtc_get_time(void); + #ifdef CONFIG_IT8172_REVC struct { struct resource ram; @@ -116,6 +123,7 @@ { unsigned short dsr; char *argptr; + u32 it_ver; argptr = prom_getcmdline(); #ifdef CONFIG_SERIAL_CONSOLE @@ -128,6 +136,11 @@ clear_cp0_status(ST0_FR); rtc_ops = &it8172_rtc_ops; + board_time_init = it8172_time_init; + board_timer_setup = it8172_timer_setup; + rtc_get_time = it8172_rtc_get_time; + //rtc_set_time = it8172_rtc_set_time; + _machine_restart = it8172_restart; _machine_halt = it8172_halt; _machine_power_off = it8172_power_off; @@ -137,7 +150,7 @@ * * revisit this area. */ - mips_io_port_base = KSEG1; + set_io_port_base(KSEG1); ioport_resource.start = it8172_resources.pci_io.start; ioport_resource.end = it8172_resources.pci_io.end; #ifdef CONFIG_IT8172_REVC diff -urN linux-2.4.18/arch/mips/ite-boards/generic/pmon_prom.c linux-2.4.19-pre5/arch/mips/ite-boards/generic/pmon_prom.c --- linux-2.4.18/arch/mips/ite-boards/generic/pmon_prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/pmon_prom.c Sat Mar 30 22:55:26 2002 @@ -44,7 +44,7 @@ /* #define DEBUG_CMDLINE */ -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; extern int prom_argc; extern char **prom_argv, **prom_envp; diff -urN linux-2.4.18/arch/mips/ite-boards/generic/time.c linux-2.4.19-pre5/arch/mips/ite-boards/generic/time.c --- linux-2.4.18/arch/mips/ite-boards/generic/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/generic/time.c Sat Mar 30 22:55:26 2002 @@ -28,135 +28,18 @@ #include #include #include +#include +#include #include #include #include +#include -#include -#include - -extern void enable_cpu_timer(void); -extern volatile unsigned long wall_jiffies; -extern rwlock_t xtime_lock; - -unsigned long missed_heart_beats = 0; -static long last_rtc_update = 0; static unsigned long r4k_offset; /* Amount to increment compare reg each time */ static unsigned long r4k_cur; /* What counter should be at next timer irq */ -static unsigned int timer_tick_count=0; - -static inline void ack_r4ktimer(unsigned long newval) -{ - write_32bit_cp0_register(CP0_COMPARE, newval); -} - - -/* - * In order to set the CMOS clock precisely, set_rtc_mmss has to be - * called 500 ms after the second nowtime has started, because when - * nowtime is written into the registers of the CMOS clock, it will - * jump to the next second precisely 500 ms later. Check the Motorola - * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you won't notice until after reboot! - */ -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return retval; -} - - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is provably more robust. - */ -void mips_timer_interrupt(struct pt_regs *regs) -{ - if (r4k_offset == 0) - goto null; - - do { - kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++; - do_timer(regs); - - /* Historical comment/code: - * RTC time of day s updated approx. every 11 - * minutes. Because of how the numbers work out - * we need to make absolutely sure we do this update - * within 500ms before the * next second starts, - * thus the following code. - */ - read_lock(&xtime_lock); - if ((time_status & STA_UNSYNC) == 0 - && xtime.tv_sec > last_rtc_update + 660 - && xtime.tv_usec >= 500000 - (tick >> 1) - && xtime.tv_usec <= 500000 + (tick >> 1)) - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else { - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 600; - } - read_unlock(&xtime_lock); - - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) - - r4k_cur) < 0x7fffffff); - - return; - -null: - ack_r4ktimer(0); -} +extern unsigned int mips_counter_frequency; +extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); /* * Figure out the r4k offset, the amount to increment the compare @@ -165,7 +48,6 @@ */ static unsigned long __init cal_r4koff(void) { - unsigned long count; unsigned int flags; __save_and_cli(flags); @@ -181,15 +63,15 @@ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - count = read_32bit_cp0_register(CP0_COUNT); + mips_counter_frequency = read_32bit_cp0_register(CP0_COUNT); /* restore interrupts */ __restore_flags(flags); - return (count / HZ); + return (mips_counter_frequency / HZ); } -static unsigned long __init get_mips_time(void) +unsigned long it8172_rtc_get_time(void) { unsigned int year, mon, day, hour, min, sec; unsigned char save_control; @@ -224,10 +106,11 @@ return mktime(year, mon, day, hour, min, sec); } -void __init time_init(void) +void __init it8172_time_init(void) { unsigned int est_freq, flags; + __save_and_cli(flags); /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); @@ -240,140 +123,25 @@ est_freq -= est_freq%10000; printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, (est_freq%1000000)*100/1000000); - r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); - - write_32bit_cp0_register(CP0_COMPARE, r4k_cur); - - enable_cpu_timer(); - - /* Read time from the RTC chipset. */ - write_lock_irqsave (&xtime_lock, flags); - xtime.tv_sec = get_mips_time(); - xtime.tv_usec = 0; - write_unlock_irqrestore(&xtime_lock, flags); -} - -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) - -/* Cycle counter value at the previous timer interrupt.. */ - -static unsigned int timerhi = 0, timerlo = 0; - -/* - * FIXME: Does playing with the RP bit in c0_status interfere with this code? - */ -static unsigned long do_fast_gettimeoffset(void) -{ - u32 count; - unsigned long res, tmp; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies=0; - unsigned long quotient; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient=0; - - tmp = jiffies; - - quotient = cached_quotient; - - if (tmp && last_jiffies != tmp) { - last_jiffies = tmp; - __asm__(".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "lwu\t%0,%2\n\t" - "dsll32\t$1,%1,0\n\t" - "or\t$1,$1,%0\n\t" - "ddivu\t$0,$1,%3\n\t" - "mflo\t$1\n\t" - "dsll32\t%0,%4,0\n\t" - "nop\n\t" - "ddivu\t$0,%0,$1\n\t" - "mflo\t%0\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=&r" (quotient) - :"r" (timerhi), - "m" (timerlo), - "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); - cached_quotient = quotient; - } - - /* Get last timer tick in absolute kernel time */ - count = read_32bit_cp0_register(CP0_COUNT); - - /* .. relative to previous jiffy (32 bits is enough) */ - count -= timerlo; - - __asm__("multu\t%1,%2\n\t" - "mfhi\t%0" - :"=r" (res) - :"r" (count), - "r" (quotient)); - - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (res >= USECS_PER_JIFFY) - res = USECS_PER_JIFFY-1; - - return res; + __restore_flags(flags); } -void do_gettimeofday(struct timeval *tv) +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +void __init it8172_timer_setup(struct irqaction *irq) { - unsigned int flags; + puts("timer_setup\n"); + put32(NR_IRQS); + puts(""); + /* we are using the cpu counter for timer interrupts */ + setup_irq(MIPS_CPU_TIMER_IRQ, irq); - read_lock_irqsave (&xtime_lock, flags); - *tv = xtime; - tv->tv_usec += do_fast_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. jiffies - wall_jiffies - * is nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore (&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } + /* to generate the first timer interrupt */ + r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); + write_32bit_cp0_register(CP0_COMPARE, r4k_cur); + set_cp0_status(ALLINTS); } -void do_settimeofday(struct timeval *tv) +void local_timer_interrupt(struct pt_regs *regs) { - 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 -= do_fast_gettimeoffset(); - - if (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); + do_IRQ(MIPS_CPU_TIMER_IRQ, regs); } diff -urN linux-2.4.18/arch/mips/ite-boards/ivr/Makefile linux-2.4.19-pre5/arch/mips/ite-boards/ivr/Makefile --- linux-2.4.18/arch/mips/ite-boards/ivr/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/ivr/Makefile Sat Mar 30 22:55:26 2002 @@ -22,7 +22,6 @@ obj-y := init.o -obj-CONFIG_PCI += pci_fixup.o -obj-CONFIG_BLK_DEV_INITRD += le_ramdisk.o +obj-$(CONFIG_PCI) += pci_fixup.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ite-boards/ivr/init.c linux-2.4.19-pre5/arch/mips/ite-boards/ivr/init.c --- linux-2.4.18/arch/mips/ite-boards/ivr/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/ivr/init.c Sat Mar 30 22:55:26 2002 @@ -52,6 +52,10 @@ #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) +const char *get_system_type(void) +{ + return "Globespan IVR"; +} int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { diff -urN linux-2.4.18/arch/mips/ite-boards/ivr/pci_fixup.c linux-2.4.19-pre5/arch/mips/ite-boards/ivr/pci_fixup.c --- linux-2.4.18/arch/mips/ite-boards/ivr/pci_fixup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/ivr/pci_fixup.c Sat Mar 30 22:55:26 2002 @@ -40,10 +40,19 @@ #include #include -void __init board_int_line_fixup(struct pci_dev *dev) +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ +} + +void __init pcibios_fixup(void) +{ +} + +void __init pcibios_fixup_irqs(void) { unsigned int slot, func; unsigned char pin; + struct pci_dev *dev; const int internal_func_irqs[7] = { IT8172_AC97_IRQ, IT8172_DMA_IRQ, @@ -54,57 +63,51 @@ IT8172_MC68K_IRQ }; -#ifdef DEBUG - printk("board_int_line_fixup bus %d\n", dev->bus->number); -#endif - if (dev->bus->number != 0) - return; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - -#ifdef DEBUG - pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor); -#endif - - slot = PCI_SLOT(dev->devfn); - func = PCI_FUNC(dev->devfn); + pci_for_each_dev(dev) { + if (dev->bus->number != 0) + return; - switch (slot) { - case 0x01: - /* - * Internal device 1 is actually 7 different internal - * devices on the IT8172G (a multi-function device). - */ - if (func < 7) - dev->irq = internal_func_irqs[func]; - break; - case 0x11: - switch (pin) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + slot = PCI_SLOT(dev->devfn); + func = PCI_FUNC(dev->devfn); + + switch (slot) { + case 0x01: + /* + * Internal device 1 is actually 7 different + * internal devices on the IT8172G (multi-function + * device). + */ + if (func < 7) + dev->irq = internal_func_irqs[func]; + break; + case 0x11: // Realtek RTL-8139 + switch (pin) { + case 0: /* pin A, hardware bug */ + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x12: // ivr slot + switch (pin) { case 0: /* pin A, hardware bug */ case 1: /* pin A */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - case 4: /* pin D */ dev->irq = IT8172_PCI_INTB_IRQ; break; - default: - dev->irq = 0xff; - break; - - } - break; - case 0x13: - switch (pin) { - case 0: /* pin A, hardware bug */ - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; case 2: /* pin B */ dev->irq = IT8172_PCI_INTB_IRQ; break; @@ -118,22 +121,37 @@ dev->irq = 0xff; break; - } - break; - default: - return; - } - + } + break; + case 0x13: // expansion slot + switch (pin) { + case 0: /* pin A, hardware bug */ + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + default: + break; + } #ifdef DEBUG - printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n", - slot, vendor, pin, dev->irq); + printk("irq fixup: slot %d, int line %d, int number %d\n", + slot, pin, dev->irq); #endif - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } } - -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup }, - { 0 } -}; #endif diff -urN linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/Makefile linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/Makefile --- linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/Makefile Sat Mar 30 22:55:26 2002 @@ -16,22 +16,11 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -all: ite.o - O_TARGET := ite.o obj-y := init.o -ifdef CONFIG_PCI -obj-y += pci_fixup.o -endif - -ifdef CONFIG_BLK_DEV_INITRD -obj-y += le_ramdisk.o -endif - - -dep: - $(CPP) -M *.c > .depend +obj-$(CONFIG_PCI) += pci_fixup.o +obj-$(CONFIG_BLK_DEV_INITRD) += le_ramdisk.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/init.c linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/init.c --- linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/init.c Sat Mar 30 22:55:26 2002 @@ -52,6 +52,10 @@ #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) +const char *get_system_type(void) +{ + return "ITE QED-4N-S01B"; +} int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { diff -urN linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c --- linux-2.4.18/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/ite-boards/qed-4n-s01b/pci_fixup.c Sat Mar 30 22:55:26 2002 @@ -40,10 +40,19 @@ #include #include -void __init board_int_line_fixup(struct pci_dev *dev) +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ +} + +void __init pcibios_fixup(void) +{ +} + +void __init pcibios_fixup_irqs(void) { unsigned int slot, func; unsigned char pin; + struct pci_dev *dev; const int internal_func_irqs[7] = { IT8172_AC97_IRQ, IT8172_DMA_IRQ, @@ -54,144 +63,133 @@ IT8172_MC68K_IRQ }; -#ifdef DEBUG - printk("board_int_line_fixup bus %d\n", dev->bus->number); -#endif - if (dev->bus->number != 0) - return; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - -#ifdef DEBUG - pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor); -#endif - - slot = PCI_SLOT(dev->devfn); - func = PCI_FUNC(dev->devfn); - - switch (slot) { - case 0x01: - /* - * Internal device 1 is actually 7 different internal - * devices on the IT8172G (a multi-function device). - */ - if (func < 7) - dev->irq = internal_func_irqs[func]; - break; - case 0x10: - switch (pin) { - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTB_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - case 4: /* pin D */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - default: - dev->irq = 0xff; - break; - - } - break; - case 0x11: - switch (pin) { - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTB_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - case 4: /* pin D */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - default: - dev->irq = 0xff; - break; - - } - break; - case 0x12: - switch (pin) { - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTB_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - case 4: /* pin D */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - default: - dev->irq = 0xff; - break; - - } - break; - case 0x13: - switch (pin) { - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - case 4: /* pin D */ - dev->irq = IT8172_PCI_INTB_IRQ; - break; - default: - dev->irq = 0xff; - break; - - } - break; - case 0x14: - switch (pin) { - case 1: /* pin A */ - dev->irq = IT8172_PCI_INTD_IRQ; - break; - case 2: /* pin B */ - dev->irq = IT8172_PCI_INTA_IRQ; - break; - case 3: /* pin C */ - dev->irq = IT8172_PCI_INTB_IRQ; - break; - case 4: /* pin D */ - dev->irq = IT8172_PCI_INTC_IRQ; - break; - default: - dev->irq = 0xff; - break; - - } - break; - default: + pci_for_each_dev(dev) { + if (dev->bus->number != 0) { return; - } + } + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + slot = PCI_SLOT(dev->devfn); + func = PCI_FUNC(dev->devfn); + + switch (slot) { + case 0x01: + /* + * Internal device 1 is actually 7 different + * internal devices on the IT8172G (a multi- + * function device). + */ + if (func < 7) + dev->irq = internal_func_irqs[func]; + break; + case 0x10: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x11: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x12: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x13: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + case 0x14: + switch (pin) { + case 1: /* pin A */ + dev->irq = IT8172_PCI_INTD_IRQ; + break; + case 2: /* pin B */ + dev->irq = IT8172_PCI_INTA_IRQ; + break; + case 3: /* pin C */ + dev->irq = IT8172_PCI_INTB_IRQ; + break; + case 4: /* pin D */ + dev->irq = IT8172_PCI_INTC_IRQ; + break; + default: + dev->irq = 0xff; + break; + + } + break; + default: + continue; /* do nothing */ + } #ifdef DEBUG - printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n", - slot, vendor, pin, dev->irq); + printk("irq fixup: slot %d, int line %d, int number %d\n", + slot, pin, dev->irq); #endif - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } } - -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup }, - { 0 } -}; #endif diff -urN linux-2.4.18/arch/mips/jmr3927/common/Makefile linux-2.4.19-pre5/arch/mips/jmr3927/common/Makefile --- linux-2.4.18/arch/mips/jmr3927/common/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/common/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,18 @@ +# +# Makefile for the common code of TOSHIBA JMR-TX3927 board +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET:= tx3927.o + +obj-y += prom.o puts.o rtc_ds1742.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/jmr3927/common/prom.c linux-2.4.19-pre5/arch/mips/jmr3927/common/prom.c --- linux-2.4.18/arch/mips/jmr3927/common/prom.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/common/prom.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,91 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, assuming a version of + * pmon is the boot code. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/au1000/common/prom.c + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/xx files. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include + +/* #define DEBUG_CMDLINE */ + +char arcs_cmdline[CL_SIZE]; +extern int prom_argc; +extern char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + +void prom_free_prom_memory (void) +{ +} diff -urN linux-2.4.18/arch/mips/jmr3927/common/puts.c linux-2.4.19-pre5/arch/mips/jmr3927/common/puts.c --- linux-2.4.18/arch/mips/jmr3927/common/puts.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/common/puts.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,168 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a TX[34]927 SIO. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com or source@mvista.com + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * Based on arch/mips/au1000/common/puts.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + int i = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = c; + return; +} + +unsigned char getch(void) +{ + int i = 0; + int dicr; + char c; + + /* diable RX int. */ + dicr = tx3927_sioptr(1)->dicr; + tx3927_sioptr(1)->dicr = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (tx3927_sioptr(1)->disr & TXx927_SIDISR_UVALID) + ; + c = tx3927_sioptr(1)->rfifo; + + /* clear RX int. status */ + tx3927_sioptr(1)->disr &= ~TXx927_SIDISR_RDIS; + /* enable RX int. */ + tx3927_sioptr(1)->dicr = dicr; + + return c; +} +void +do_jmr3927_led_set(char n) +{ + /* and with current leds */ + jmr3927_led_and_set(n); +} + +void +puts(unsigned char *cp) +{ + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} diff -urN linux-2.4.18/arch/mips/jmr3927/common/rtc_ds1742.c linux-2.4.19-pre5/arch/mips/jmr3927/common/rtc_ds1742.c --- linux-2.4.18/arch/mips/jmr3927/common/rtc_ds1742.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/common/rtc_ds1742.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,173 @@ +/*********************************************************************** + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * arch/mips/jmr3927/common/rtc_ds1742.c + * Based on arch/mips/ddb5xxx/common/rtc_ds1386.c + * low-level RTC hookups for s for Dallas 1742 chip. + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************** + */ + + +/* + * This file exports a function, rtc_ds1386_init(), which expects an + * uncached base address as the argument. It will set the two function + * pointers expected by the MIPS generic timer code. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#define EPOCH 2000 + +#undef BCD_TO_BIN +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) + +#undef BIN_TO_BCD +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) + +static unsigned long rtc_base; + +static unsigned long +rtc_ds1742_get_time(void) +{ + unsigned int year, month, day, hour, minute, second; + unsigned int century; + + CMOS_WRITE(RTC_READ, RTC_CONTROL); + second = BCD_TO_BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + minute = BCD_TO_BIN(CMOS_READ(RTC_MINUTES)); + hour = BCD_TO_BIN(CMOS_READ(RTC_HOURS)); + day = BCD_TO_BIN(CMOS_READ(RTC_DATE)); + month = BCD_TO_BIN(CMOS_READ(RTC_MONTH)); + year = BCD_TO_BIN(CMOS_READ(RTC_YEAR)); + century = BCD_TO_BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK); + CMOS_WRITE(0, RTC_CONTROL); + + year += century * 100; + + return mktime(year, month, day, hour, minute, second); +} +extern void to_tm(unsigned long tim, struct rtc_time * tm); + +static int +rtc_ds1742_set_time(unsigned long t) +{ + struct rtc_time tm; + u8 year, month, day, hour, minute, second; + u8 cmos_year, cmos_month, cmos_day, cmos_hour, cmos_minute, cmos_second; + int cmos_century; + + CMOS_WRITE(RTC_READ, RTC_CONTROL); + cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + cmos_minute = (u8)CMOS_READ(RTC_MINUTES); + cmos_hour = (u8)CMOS_READ(RTC_HOURS); + cmos_day = (u8)CMOS_READ(RTC_DATE); + cmos_month = (u8)CMOS_READ(RTC_MONTH); + cmos_year = (u8)CMOS_READ(RTC_YEAR); + cmos_century = CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK; + + CMOS_WRITE(RTC_WRITE, RTC_CONTROL); + + /* convert */ + to_tm(t, &tm); + + /* check each field one by one */ + year = BIN_TO_BCD(tm.tm_year - EPOCH); + if (year != cmos_year) { + CMOS_WRITE(year,RTC_YEAR); + } + + month = BIN_TO_BCD(tm.tm_mon); + if (month != (cmos_month & 0x1f)) { + CMOS_WRITE((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH); + } + + day = BIN_TO_BCD(tm.tm_mday); + if (day != cmos_day) { + + CMOS_WRITE(day, RTC_DATE); + } + + if (cmos_hour & 0x40) { + /* 12 hour format */ + hour = 0x40; + if (tm.tm_hour > 12) { + hour |= 0x20 | (BIN_TO_BCD(hour-12) & 0x1f); + } else { + hour |= BIN_TO_BCD(tm.tm_hour); + } + } else { + /* 24 hour format */ + hour = BIN_TO_BCD(tm.tm_hour) & 0x3f; + } + if (hour != cmos_hour) CMOS_WRITE(hour, RTC_HOURS); + + minute = BIN_TO_BCD(tm.tm_min); + if (minute != cmos_minute) { + CMOS_WRITE(minute, RTC_MINUTES); + } + + second = BIN_TO_BCD(tm.tm_sec); + if (second != cmos_second) { + CMOS_WRITE(second & RTC_SECONDS_MASK,RTC_SECONDS); + } + + /* RTC_CENTURY and RTC_CONTROL share same address... */ + CMOS_WRITE(cmos_century, RTC_CONTROL); + + return 0; +} + +void +rtc_ds1742_init(unsigned long base) +{ + u8 cmos_second; + + /* remember the base */ + rtc_base = base; + db_assert((rtc_base & 0xe0000000) == KSEG1); + + /* set the function pointers */ + rtc_get_time = rtc_ds1742_get_time; + rtc_set_time = rtc_ds1742_set_time; + + /* clear oscillator stop bit */ + CMOS_WRITE(RTC_READ, RTC_CONTROL); + cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + CMOS_WRITE(RTC_WRITE, RTC_CONTROL); + CMOS_WRITE(cmos_second, RTC_SECONDS); /* clear msb */ + CMOS_WRITE(0, RTC_CONTROL); +} diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/Makefile linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/Makefile --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/Makefile Sat Mar 30 22:55:26 2002 @@ -0,0 +1,21 @@ +# +# Makefile for TOSHIBA JMR-TX3927 board +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET:= jmr3927.o + +obj-y += init.o int-handler.o irq.o setup.o rtc.o pci_fixup.o pci_ops.o + +obj-$(CONFIG_LL_DEBUG) += debug.o +obj-$(CONFIG_REMOTE_DEBUG) += kgdb_io.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/init.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/init.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/init.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,80 @@ +/*********************************************************************** + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * arch/mips/jmr3927/common/init.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************** + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int prom_argc; +char **prom_argv, **prom_envp; +extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); +unsigned long mips_nofpu = 0; + +const char *get_system_type(void) +{ + return "Toshiba" +#ifdef CONFIG_TOSHIBA_JMR3927 + " JMR_TX3927" +#endif + ; +} + +extern void puts(unsigned char *cp); +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ +#ifdef CONFIG_TOSHIBA_JMR3927 + /* CCFG */ + if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) + puts("Warning: TX3927 TLB off\n"); +#endif + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_machgroup = MACH_GROUP_TOSHIBA; + +#ifdef CONFIG_TOSHIBA_JMR3927 + mips_machtype = MACH_TOSHIBA_JMR3927; +#endif + + prom_init_cmdline(); + add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); + return 0; +} diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/int-handler.S linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/int-handler.S --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/int-handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/int-handler.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,74 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/tsdb/kernel/int-handler.S + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + + /* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop + * and moving across all the pending IRQ bits in the cause + * register is _NOT_ the answer, the common case is one + * pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register + * IRQ mask, that would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs + * off, nothing in between like BSD spl() brain-damage. + * + */ + +/* Flush write buffer (needed?) + * NOTE: TX39xx performs "non-blocking load", so explicitly use the target + * register of LBU to flush immediately. + */ +#define FLUSH_WB(tmp) \ + la tmp, JMR3927_IOC_REV_ADDR; \ + lbu tmp, (tmp); \ + move tmp, zero; + + .text + .set noreorder + .set noat + .align 5 + NESTED(jmr3927_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + jal jmr3927_irc_irqdispatch + move a0, sp + FLUSH_WB(t0) + j ret_from_irq + nop + END(jmr3927_IRQ) diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/irq.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/irq.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/irq.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,515 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if JMR3927_IRQ_END > NR_IRQS +#error JMR3927_IRQ_END > NR_IRQS +#endif + +struct tb_irq_space* tb_irq_spaces; + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +static int jmr3927_irq_base=-1; + +#ifdef CONFIG_PCI +static int jmr3927_gen_iack(void) +{ + /* generate ACK cycle */ +#ifdef __BIG_ENDIAN + return (tx3927_pcicptr->iiadp >> 24) & 0xff; +#else + return tx3927_pcicptr->iiadp & 0xff; +#endif +} +#endif + +extern asmlinkage void jmr3927_IRQ(void); + +#define irc_dlevel 0 +#define irc_elevel 1 +static unsigned char irc_level[TX3927_NUM_IR] = { + 5, 5, 5, 5, 5, 5, /* INT[5:0] */ + 7, 7, /* SIO */ + 5, 5, 5, 0, 0, /* DMA, PIO, PCI */ + 6, 6, 6 /* TMR */ +}; + +static inline void mask_irq(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->mask_func) + sp->mask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->unmask_func) + sp->unmask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } +} + +static void jmr3927_irq_disable(unsigned int irq_nr); +static void jmr3927_irq_enable(unsigned int irq_nr); + +static unsigned int jmr3927_irq_startup(unsigned int irq) +{ + jmr3927_irq_enable(irq); + return 0; +} + +#define jmr3927_irq_shutdown jmr3927_irq_disable + +static void jmr3927_irq_ack(unsigned int irq) +{ + db_assert(jmr3927_irq_base != -1); + db_assert(irq >= jmr3927_irq_base); + db_assert(irq < jmr3927_irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC); + + if (irq == JMR3927_IRQ_IRC_TMR0) { + jmr3927_tmrptr->tisr = 0; /* ack interrupt */ + } + + jmr3927_irq_disable(irq); +} + +static void jmr3927_irq_end(unsigned int irq) +{ + db_assert(jmr3927_irq_base != -1); + db_assert(irq >= jmr3927_irq_base); + db_assert(irq < jmr3927_irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC); + + jmr3927_irq_enable(irq); +} + +static void jmr3927_irq_disable(unsigned int irq_nr) +{ + unsigned long flags; + + db_assert(jmr3927_irq_base != -1); + db_assert(irq >= jmr3927_irq_base); + db_assert(irq < jmr3927_irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC); + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +static void jmr3927_irq_enable(unsigned int irq_nr) +{ + unsigned long flags; + + db_assert(jmr3927_irq_base != -1); + db_assert(irq >= jmr3927_irq_base); + db_assert(irq < jmr3927_irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC); + + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + +/* + * CP0_STATUS is a thread's resource (saved/restored on context switch). + * So disable_irq/enable_irq MUST handle IOC/ISAC/IRC registers. + */ +static void mask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask & ~bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} +static void unmask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask | bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} + +static void mask_irq_ioc(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} +static void unmask_irq_ioc(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} + +static void mask_irq_irc(int irq_nr, int space_id) +{ + volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; + if (irq_nr & 1) + *ilrp = (*ilrp & 0x00ff) | (irc_dlevel << 8); + else + *ilrp = (*ilrp & 0xff00) | irc_dlevel; + /* update IRCSR */ + tx3927_ircptr->imr = 0; + tx3927_ircptr->imr = irc_elevel; +} +static void unmask_irq_irc(int irq_nr, int space_id) +{ + volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; + if (irq_nr & 1) + *ilrp = (*ilrp & 0x00ff) | (irc_level[irq_nr] << 8); + else + *ilrp = (*ilrp & 0xff00) | irc_level[irq_nr]; + /* update IRCSR */ + tx3927_ircptr->imr = 0; + tx3927_ircptr->imr = irc_elevel; +} + +struct tb_irq_space jmr3927_isac_irqspace = { + next: NULL, + start_irqno: JMR3927_IRQ_ISAC, + nr_irqs : JMR3927_NR_IRQ_ISAC, + mask_func: mask_irq_isac, + unmask_func: unmask_irq_isac, + name: "ISAC", + space_id: 0, + can_share : 0 +}; +struct tb_irq_space jmr3927_ioc_irqspace = { + next: NULL, + start_irqno: JMR3927_IRQ_IOC, + nr_irqs : JMR3927_NR_IRQ_IOC, + mask_func: mask_irq_ioc, + unmask_func: unmask_irq_ioc, + name: "IOC", + space_id: 0, + can_share : 1 +}; +struct tb_irq_space jmr3927_irc_irqspace = { + next: NULL, + start_irqno: JMR3927_IRQ_IRC, + nr_irqs : JMR3927_NR_IRQ_IRC, + mask_func: mask_irq_irc, + unmask_func: unmask_irq_irc, + name: "on-chip", + space_id: 0, + can_share : 0 +}; + +void jmr3927_spurious(struct pt_regs *regs) +{ +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(regs); +#endif + printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", + regs->cp0_cause, regs->cp0_epc, regs->regs[31]); +} + +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); +void jmr3927_irc_irqdispatch(struct pt_regs *regs) +{ + int irq; + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(regs); +#endif + if ((regs->cp0_cause & CAUSEF_IP7) == 0) { +#if 0 + jmr3927_spurious(regs); +#endif + return; + } + irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; + + do_IRQ(irq + JMR3927_IRQ_IRC, regs); +} + +static void jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); + int i; + + for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { + if (istat & (1 << i)) { + irq = JMR3927_IRQ_IOC + i; + do_IRQ(irq, regs); + } + } +} + +static struct irqaction ioc_action = { + jmr3927_ioc_interrupt, 0, 0, "IOC", NULL, NULL, +}; + +static void jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); + int i; + + for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { + if (istat & (1 << i)) { + irq = JMR3927_IRQ_ISAC + i; + do_IRQ(irq, regs); + } + } +} + +static struct irqaction isac_action = { + jmr3927_isac_interrupt, 0, 0, "ISAC", NULL, NULL, +}; + + +static void jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); +} +static struct irqaction isaerr_action = { + jmr3927_isaerr_interrupt, 0, 0, "ISA error", NULL, NULL, +}; + +static void jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); + printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", + tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); +} +static struct irqaction pcierr_action = { + jmr3927_pcierr_interrupt, 0, 0, "PCI error", NULL, NULL, +}; + +int jmr3927_ether1_irq = 0; + +void jmr3927_irq_init(u32 irq_base); +void jmr3927_irq_setup(void) +{ + /* look for io board's presence */ + int have_isac = jmr3927_have_isac(); + + /* Now, interrupt control disabled, */ + /* all IRC interrupts are masked, */ + /* all IRC interrupt mode are Low Active. */ + + if (have_isac) { + + /* ETHER1 (NE2000 compatible 10M-Ether) parameter setup */ + /* temporary enable interrupt control */ + tx3927_ircptr->cer = 1; + /* ETHER1 Int. Is High-Active. */ + if (tx3927_ircptr->ssr & (1 << 0)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT0; +#if 0 /* INT3 may be asserted by ether0 (even after reboot...) */ + else if (tx3927_ircptr->ssr & (1 << 3)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT3; +#endif + /* disable interrupt control */ + tx3927_ircptr->cer = 0; + + /* Ether1: High Active */ + if (jmr3927_ether1_irq) { + int ether1_irc = jmr3927_ether1_irq - JMR3927_IRQ_IRC; + tx3927_ircptr->cr[ether1_irc / 8] |= + TX3927_IRCR_HIGH << ((ether1_irc % 8) * 2); + } + } + + /* mask all IOC interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_INTM_ADDR); + /* setup IOC interrupt mode (SOFT:High Active, Others:Low Active) */ + jmr3927_ioc_reg_out(JMR3927_IOC_INTF_SOFT, JMR3927_IOC_INTP_ADDR); + + if (have_isac) { + /* mask all ISAC interrupts */ + jmr3927_isac_reg_out(0, JMR3927_ISAC_INTM_ADDR); + /* setup ISAC interrupt mode (ISAIRQ3,ISAIRQ5:Low Active ???) */ + jmr3927_isac_reg_out(JMR3927_ISAC_INTF_IRQ3|JMR3927_ISAC_INTF_IRQ5, JMR3927_ISAC_INTP_ADDR); + } + + /* clear PCI Soft interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_INTS1_ADDR); + /* clear PCI Reset interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + + /* enable interrupt control */ + tx3927_ircptr->cer = TX3927_IRCER_ICE; + tx3927_ircptr->imr = irc_elevel; + + jmr3927_irq_init(NR_ISA_IRQS); + + set_except_vector(0, jmr3927_IRQ); + + /* setup irq space */ + add_tb_irq_space(&jmr3927_isac_irqspace); + add_tb_irq_space(&jmr3927_ioc_irqspace); + add_tb_irq_space(&jmr3927_irc_irqspace); + + /* setup IOC interrupt 1 (PCI, MODEM) */ + setup_irq(JMR3927_IRQ_IOCINT, &ioc_action); + + if (have_isac) { + setup_irq(JMR3927_IRQ_ISACINT, &isac_action); + setup_irq(JMR3927_IRQ_ISAC_ISAER, &isaerr_action); + } + +#ifdef CONFIG_PCI + setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action); +#endif + + /* enable all CPU interrupt bits. */ + set_cp0_status(ST0_IM); /* IE bit is still 0. */ +} + +void (*irq_setup)(void); +void __init init_IRQ(void) +{ + +#ifdef CONFIG_REMOTE_DEBUG + extern void breakpoint(void); + extern void set_debug_traps(void); + + puts("Wait for gdb client connection ...\n"); + set_debug_traps(); + breakpoint(); +#endif + + /* invoke board-specific irq setup */ + irq_setup(); +} + +hw_irq_controller jmr3927_irq_controller = { + "jmr3927_irq", + jmr3927_irq_startup, + jmr3927_irq_shutdown, + jmr3927_irq_enable, + jmr3927_irq_disable, + jmr3927_irq_ack, + jmr3927_irq_end, + NULL /* no affinity stuff for UP */ +}; + +void +jmr3927_irq_init(u32 irq_base) +{ + extern irq_desc_t irq_desc[]; + u32 i; + + for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &jmr3927_irq_controller; + } + + jmr3927_irq_base = irq_base; +} + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND +static int tx_branch_likely_bug_count = 0; +static int have_tx_branch_likely_bug = 0; +void tx_branch_likely_bug_fixup(struct pt_regs *regs) +{ + /* TX39/49-BUG: Under this condition, the insn in delay slot + of the branch likely insn is executed (not nullified) even + the branch condition is false. */ + if (!have_tx_branch_likely_bug) + return; + if ((regs->cp0_epc & 0xfff) == 0xffc && + KSEGX(regs->cp0_epc) != KSEG0 && + KSEGX(regs->cp0_epc) != KSEG1) { + unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); + /* beql,bnel,blezl,bgtzl */ + /* bltzl,bgezl,blezall,bgezall */ + /* bczfl, bcztl */ + if ((insn & 0xf0000000) == 0x50000000 || + (insn & 0xfc0e0000) == 0x04020000 || + (insn & 0xf3fe0000) == 0x41020000) { + regs->cp0_epc -= 4; + tx_branch_likely_bug_count++; + printk(KERN_INFO + "fix branch-likery bug in %s (insn %08x)\n", + current->comm, insn); + } + } +} +#endif diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/kgdb_io.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/kgdb_io.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/kgdb_io.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/kgdb_io.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,155 @@ +/* + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a TX[34]927 SIO. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com or source@mvista.com + * + * Based on arch/mips/ddb5xxx/ddb5477/kgdb_io.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif + +static int remoteDebugInitialized = 0; + +int putDebugChar(unsigned char c) +{ + int i = 0; + + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(38400); + } + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(0)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(0)->tfifo = c; + + return 1; +} + +unsigned char getDebugChar(void) +{ + int i = 0; + int dicr; + char c; + + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(38400); + } + + /* diable RX int. */ + dicr = tx3927_sioptr(0)->dicr; + tx3927_sioptr(0)->dicr = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (tx3927_sioptr(0)->disr & TXx927_SIDISR_UVALID) + ; + c = tx3927_sioptr(0)->rfifo; + + /* clear RX int. status */ + tx3927_sioptr(0)->disr &= ~TXx927_SIDISR_RDIS; + /* enable RX int. */ + tx3927_sioptr(0)->dicr = dicr; + + return c; +} + +void debugInit(int baud) +{ + /* + volatile unsigned long lcr; + volatile unsigned long dicr; + volatile unsigned long disr; + volatile unsigned long cisr; + volatile unsigned long fcr; + volatile unsigned long flcr; + volatile unsigned long bgr; + volatile unsigned long tfifo; + volatile unsigned long rfifo; + */ + + tx3927_sioptr(0)->lcr = 0x020; + tx3927_sioptr(0)->dicr = 0; + tx3927_sioptr(0)->disr = 0x4100; + tx3927_sioptr(0)->cisr = 0x014; + tx3927_sioptr(0)->fcr = 0; + tx3927_sioptr(0)->flcr = 0x02; + tx3927_sioptr(0)->bgr = ((JMR3927_BASE_BAUD + baud / 2) / baud) | + TXx927_SIBGR_BCLK_T0; +#if 0 + /* + * Reset the UART. + */ + tx3927_sioptr(0)->fcr = TXx927_SIFCR_SWRST; + while (tx3927_sioptr(0)->fcr & TXx927_SIFCR_SWRST) + ; + + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + tx3927_sioptr(0)->lcr = TXx927_SILCR_UMODE_8BIT | + TXx927_SILCR_USBL_1BIT | + TXx927_SILCR_SCS_IMCLK_BG; + tx3927_sioptr(0)->bgr = + ((JMR3927_BASE_BAUD + baud / 2) / baud) | + TXx927_SIBGR_BCLK_T0; + + /* HW RTS/CTS control */ + if (ser->flags & ASYNC_HAVE_CTS_LINE) + tx3927_sioptr(0)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + tx3927_sioptr(0)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); +#endif +} diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/pci_fixup.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/pci_fixup.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/pci_fixup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/pci_fixup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,140 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Board specific pci fixups. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ + /* will need to fixup IO resources */ +} + +void __init pcibios_fixup(void) +{ + /* nothing to do here */ +} + +int pci_get_irq(struct pci_dev *dev, int pin) +{ + unsigned char irq = pin; + + /* IRQ rotation (PICMG) */ + irq--; /* 0-3 */ + if (dev->bus->parent == NULL && + PCI_SLOT(dev->devfn) == TX3927_PCIC_IDSEL_AD_TO_SLOT(23)) { + /* PCI CardSlot (IDSEL=A23, DevNu=12) */ + /* PCIA => PCIC (IDSEL=A23) */ + /* NOTE: JMR3927 JP1 must be set to OPEN */ + irq = (irq + 2) % 4; + } else if (dev->bus->parent == NULL && + PCI_SLOT(dev->devfn) == TX3927_PCIC_IDSEL_AD_TO_SLOT(22)) { + /* PCI CardSlot (IDSEL=A22, DevNu=11) */ + /* PCIA => PCIA (IDSEL=A22) */ + /* NOTE: JMR3927 JP1 must be set to OPEN */ + irq = (irq + 0) % 4; + } else { + /* PCI Backplane */ + irq = (irq + 3 + PCI_SLOT(dev->devfn)) % 4; +#if 0 /* ??? */ + for (bus = dev->bus; bus->parent != NULL; bus = bus->parent) { + irq = (irq + 3 + PCI_SLOT(bus->self->devfn)) % 4; + } +#endif + } + irq++; /* 1-4 */ + + switch (irq) { + case 1: + irq = JMR3927_IRQ_IOC_PCIA; + break; + case 2: + // wrong for backplane irq = JMR3927_IRQ_IOC_PCIB; + irq = JMR3927_IRQ_IOC_PCID; + break; + case 3: + irq = JMR3927_IRQ_IOC_PCIC; + break; + case 4: + // wrong for backplane irq = JMR3927_IRQ_IOC_PCID; + irq = JMR3927_IRQ_IOC_PCIB; + break; + } + + /* Check OnBoard Ethernet (IDSEL=A24, DevNu=13) */ + if (dev->bus->parent == NULL && + PCI_SLOT(dev->devfn) == TX3927_PCIC_IDSEL_AD_TO_SLOT(24)) { + extern int jmr3927_ether1_irq; + /* check this irq line was reserved for ether1 */ + if (jmr3927_ether1_irq != JMR3927_IRQ_ETHER0) + irq = JMR3927_IRQ_ETHER0; + else + irq = 0; /* disable */ + } + return irq; +} + +void __init pcibios_fixup_irqs(void) +{ + unsigned char irq; + struct pci_dev *dev; + + pci_for_each_dev(dev) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq); + if (irq == 0) + return; + + /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */ + if (!(dev->vendor == PCI_VENDOR_ID_EFAR && + dev->device == PCI_DEVICE_ID_EFAR_SLC90E66_1)) { + irq = pci_get_irq(dev, irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + } + + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + printk(KERN_INFO "PCI: %02x:%02x IRQ %02x\n", + dev->bus->number, dev->devfn, irq); + dev->irq = irq; + } +} +#endif diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/pci_ops.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/pci_ops.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/pci_ops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/pci_ops.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,471 @@ +/*********************************************************************** + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c + * + * Define the pci_ops for JMR3927. + * + * Much of the code is derived from the original DDB5074 port by + * Geert Uytterhoeven + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + *********************************************************************** + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct resource pci_io_resource = { + "pci IO space", + 0x1000, /* reserve regacy I/O space */ + 0x1000 + JMR3927_PCIIO_SIZE -1, + IORESOURCE_IO}; + +struct resource pci_mem_resource = { + "pci memory space", + JMR3927_PCIMEM, + JMR3927_PCIMEM + JMR3927_PCIMEM_SIZE -1, + IORESOURCE_MEM}; + +extern struct pci_ops jmr3927_pci_ops; + +struct pci_channel mips_pci_channels[] = { + { &jmr3927_pci_ops, &pci_io_resource, &pci_mem_resource, 0, 0xff }, + { NULL, NULL, NULL, NULL, NULL} +}; + +unsigned int pcibios_assign_all_busses(void) +{ + return 1; +} + +static int +mkaddr(unsigned char bus, unsigned char dev_fn, unsigned char where, int *flagsp) +{ + if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0)) + return -1; + + tx3927_pcicptr->ica = ((bus & 0xff) << 0x10) | + ((dev_fn & 0xff) << 0x08) | + (where & 0xfc); + /* clear M_ABORT and Disable M_ABORT Int. */ + tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; + tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT; + return 0; +} + +static int +check_abort(int flags) +{ + int code = PCIBIOS_SUCCESSFUL; + if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) { + tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; + tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; + code =PCIBIOS_DEVICE_NOT_FOUND; + } + return code; +} + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int jmr3927_pcibios_read_config_byte (struct pci_dev *dev, + int where, + unsigned char *val) +{ + int flags; + unsigned char bus, func_num; + + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + *val = *(volatile u8 *)((ulong)&tx3927_pcicptr->icd | (where&3)); + return check_abort(flags); +} + +static int jmr3927_pcibios_read_config_word (struct pci_dev *dev, + int where, + unsigned short *val) +{ + int flags; + unsigned char bus, func_num; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + *val = le16_to_cpu(*(volatile u16 *)((ulong)&tx3927_pcicptr->icd | (where&3))); + return check_abort(flags); +} + +static int jmr3927_pcibios_read_config_dword (struct pci_dev *dev, + int where, + unsigned int *val) +{ + int flags; + unsigned char bus, func_num; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + db_assert((where & 3) == 0); + db_assert(where < (1 << 8)); + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + *val = le32_to_cpu(tx3927_pcicptr->icd); + return check_abort(flags); +} + +static int jmr3927_pcibios_write_config_byte (struct pci_dev *dev, + int where, + unsigned char val) +{ + int flags; + unsigned char bus, func_num; + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + *(volatile u8 *)((ulong)&tx3927_pcicptr->icd | (where&3)) = val; + return check_abort(flags); +} + +static int jmr3927_pcibios_write_config_word (struct pci_dev *dev, + int where, + unsigned short val) +{ + int flags; + unsigned char bus, func_num; + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + *(volatile u16 *)((ulong)&tx3927_pcicptr->icd | (where&3)) = cpu_to_le16(val); + return check_abort(flags); +} + +static int jmr3927_pcibios_write_config_dword (struct pci_dev *dev, + int where, + unsigned int val) +{ + int flags; + unsigned char bus, func_num; + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + /* check if the bus is top-level */ + if (dev->bus->parent != NULL) { + bus = dev->bus->number; + db_assert(bus != 0); + } else { + bus = 0; + } + + func_num = PCI_FUNC(dev->devfn); + if (mkaddr(bus, dev->devfn, where, &flags)) + return -1; + tx3927_pcicptr->icd = cpu_to_le32(val); + return check_abort(flags); +} +struct pci_ops jmr3927_pci_ops = { + jmr3927_pcibios_read_config_byte, + jmr3927_pcibios_read_config_word, + jmr3927_pcibios_read_config_dword, + jmr3927_pcibios_write_config_byte, + jmr3927_pcibios_write_config_word, + jmr3927_pcibios_write_config_dword +}; + +#ifndef JMR3927_INIT_INDIRECT_PCI +inline unsigned long tc_readl(volatile __u32 *addr) +{ + return readl(addr); +} +inline void tc_writel(unsigned long data, volatile __u32 *addr) +{ + writel(data, addr); +} +#else +unsigned long tc_readl(volatile __u32 *addr) +{ + unsigned long val; + + addr = PHYSADDR(addr); + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)addr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_MEMREAD << PCI_IPCIBE_ICMD_SHIFT) | PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + val = le32_to_cpu(*(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} +void tc_writel(unsigned long data, volatile __u32 *addr) +{ + addr = PHYSADDR(addr); + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata = cpu_to_le32(data); + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)addr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_MEMWRITE << PCI_IPCIBE_ICMD_SHIFT) | PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} +unsigned char tx_ioinb(unsigned char *addr) +{ + unsigned long val; + __u32 ioaddr; + int offset; + int byte; + + ioaddr = (unsigned long)addr; + offset = ioaddr & 0x3; + if (offset == 0) + byte = 0x7; + else if (offset == 1) + byte = 0xb; + else if (offset == 2) + byte = 0xd; + else if (offset == 3) + byte = 0xe; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + val = le32_to_cpu(*(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata); + val = val & 0xff; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} +void tx_iooutb(unsigned long data, unsigned char *addr) +{ + __u32 ioaddr; + int offset; + int byte; + + data = data | (data << 8) | (data << 16) | (data << 24); + ioaddr = (unsigned long)addr; + offset = ioaddr & 0x3; + if (offset == 0) + byte = 0x7; + else if (offset == 1) + byte = 0xb; + else if (offset == 2) + byte = 0xd; + else if (offset == 3) + byte = 0xe; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata = data; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} +unsigned short tx_ioinw(unsigned short *addr) +{ + unsigned long val; + __u32 ioaddr; + int offset; + int byte; + + ioaddr = (unsigned long)addr; + offset = ioaddr & 0x3; + if (offset == 0) + byte = 0x3; + else if (offset == 2) + byte = 0xc; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + val = le32_to_cpu(*(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata); + val = val & 0xffff; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; + +} +void tx_iooutw(unsigned long data, unsigned short *addr) +{ + __u32 ioaddr; + int offset; + int byte; + + data = data | (data << 16); + ioaddr = (unsigned long)addr; + offset = ioaddr & 0x3; + if (offset == 0) + byte = 0x3; + else if (offset == 2) + byte = 0xc; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata = data; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} +unsigned long tx_ioinl(unsigned int *addr) +{ + unsigned long val; + __u32 ioaddr; + + ioaddr = (unsigned long)addr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + val = le32_to_cpu(*(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} +void tx_iooutl(unsigned long data, unsigned int *addr) +{ + __u32 ioaddr; + + ioaddr = (unsigned long)addr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcidata = cpu_to_le32(data); + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipciaddr = (unsigned long)ioaddr; + *(volatile u32 *)(ulong)&tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)) ; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} +void tx_insbyte(unsigned char *addr,void *buffer,unsigned int count) +{ + unsigned char *ptr = (unsigned char *) buffer; + + while (count--) { + *ptr++ = tx_ioinb(addr); + } +} +void tx_insword(unsigned short *addr,void *buffer,unsigned int count) +{ + unsigned short *ptr = (unsigned short *) buffer; + + while (count--) { + *ptr++ = tx_ioinw(addr); + } +} +void tx_inslong(unsigned int *addr,void *buffer,unsigned int count) +{ + unsigned long *ptr = (unsigned long *) buffer; + + while (count--) { + *ptr++ = tx_ioinl(addr); + } +} +void tx_outsbyte(unsigned char *addr,void *buffer,unsigned int count) +{ + unsigned char *ptr = (unsigned char *) buffer; + + while (count--) { + tx_iooutb(*ptr++,addr); + } +} +void tx_outsword(unsigned short *addr,void *buffer,unsigned int count) +{ + unsigned short *ptr = (unsigned short *) buffer; + + while (count--) { + tx_iooutw(*ptr++,addr); + } +} +void tx_outslong(unsigned int *addr,void *buffer,unsigned int count) +{ + unsigned long *ptr = (unsigned long *) buffer; + + while (count--) { + tx_iooutl(*ptr++,addr); + } +} +#endif diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/rtc.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/rtc.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/rtc.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,56 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * RTC routines for Dallas chip. + * + * 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) 200-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include /* bad name... */ +#include + +static unsigned char jmr3927_rtc_read_data(unsigned long addr) +{ + return jmr3927_nvram_in(addr); +} + +static void jmr3927_rtc_write_data(unsigned char data, unsigned long addr) +{ + jmr3927_nvram_out(data, addr); +} + +static int jmr3927_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops jmr3927_rtc_ops = { + &jmr3927_rtc_read_data, + &jmr3927_rtc_write_data, + &jmr3927_rtc_bcd_mode +}; diff -urN linux-2.4.18/arch/mips/jmr3927/rbhma3100/setup.c linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/setup.c --- linux-2.4.18/arch/mips/jmr3927/rbhma3100/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/jmr3927/rbhma3100/setup.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,525 @@ +/*********************************************************************** + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/ddb5xxx/ddb5477/setup.c + * + * Setup file for JMR3927. + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for ROOT_DEV */ +#include +#include /* for HZ */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Tick Timer divider */ +#define JMR3927_TIMER_CCD 0 /* 1/2 */ +#define JMR3927_TIMER_CLK (JMR3927_IMCLK / (2 << JMR3927_TIMER_CCD)) + +unsigned char led_state = 0xf; + +struct { + struct resource ram0; + struct resource ram1; + struct resource pcimem; + struct resource iob; + struct resource ioc; + struct resource pciio; + struct resource jmy1394; + struct resource rom1; + struct resource rom0; + struct resource sio0; + struct resource sio1; +} jmr3927_resources = { + { "RAM0", 0, 0x01FFFFFF, IORESOURCE_MEM }, + { "RAM1", 0x02000000, 0x03FFFFFF, IORESOURCE_MEM }, + { "PCIMEM", 0x08000000, 0x07FFFFFF, IORESOURCE_MEM }, + { "IOB", 0x10000000, 0x13FFFFFF }, + { "IOC", 0x14000000, 0x14FFFFFF }, + { "PCIIO", 0x15000000, 0x15FFFFFF }, + { "JMY1394", 0x1D000000, 0x1D3FFFFF }, + { "ROM1", 0x1E000000, 0x1E3FFFFF }, + { "ROM0", 0x1FC00000, 0x1FFFFFFF }, + { "SIO0", 0xFFFEF300, 0xFFFEF3FF }, + { "SIO1", 0xFFFEF400, 0xFFFEF4FF }, +}; + +/* don't enable - see errata */ +int jmr3927_ccfg_toeon = 0; + +static inline void do_reset(void) +{ +#ifdef CONFIG_TC35815 + extern void tc35815_killall(void); + tc35815_killall(); +#endif +#if 1 /* Resetting PCI bus */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, JMR3927_IOC_RESET_ADDR); + (void)jmr3927_ioc_reg_in(JMR3927_IOC_RESET_ADDR); /* flush WB */ + mdelay(1); + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); +#endif + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_CPU, JMR3927_IOC_RESET_ADDR); +} + +static void jmr3927_machine_restart(char *command) +{ + cli(); + puts("Rebooting..."); + do_reset(); +} + +static void jmr3927_machine_halt(void) +{ + puts("JMR-TX3927 halted.\n"); + while (1); +} + +static void jmr3927_machine_power_off(void) +{ + puts("JMR-TX3927 halted. Please turn off the power.\n"); + while (1); +} + +#define USE_RTC_DS1742 +#ifdef USE_RTC_DS1742 +extern void rtc_ds1742_init(unsigned long base); +#endif +static void __init jmr3927_time_init(void) +{ +#ifdef USE_RTC_DS1742 + if (jmr3927_have_nvram()) { + rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR); + } +#endif +} + +unsigned long jmr3927_do_gettimeoffset(void); +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +static void __init jmr3927_timer_setup(struct irqaction *irq) +{ + do_gettimeoffset = jmr3927_do_gettimeoffset; + + jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ; + jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE; + jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; + jmr3927_tmrptr->tcr = + TXx927_TMTCR_TCE | TXx927_TMTCR_CCDE | TXx927_TMTCR_TMODE_ITVL; + + setup_irq(JMR3927_IRQ_TICK, irq); +} + +#define USECS_PER_JIFFY (1000000/HZ) +unsigned long jmr3927_do_gettimeoffset(void) +{ + unsigned long count; + unsigned long res = 0; + + /* MUST read TRR before TISR. */ + count = jmr3927_tmrptr->trr; + + if (jmr3927_tmrptr->tisr & TXx927_TMTISR_TIIS) { + /* timer interrupt is pending. use Max value. */ + res = USECS_PER_JIFFY - 1; + } else { + /* convert to usec */ + /* res = count / (JMR3927_TIMER_CLK / 1000000); */ + res = (count << 7) / ((JMR3927_TIMER_CLK << 7) / 1000000); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + } + + return res; +} + +#if defined(CONFIG_BLK_DEV_INITRD) +extern unsigned long __rd_start, __rd_end, initrd_start, initrd_end; +#endif + +//#undef DO_WRITE_THROUGH +#define DO_WRITE_THROUGH +#define DO_ENABLE_CACHE + +extern char * __init prom_getcmdline(void); +static void jmr3927_board_init(void); +extern void jmr3927_irq_setup(void); +extern struct resource pci_io_resource; +extern struct resource pci_mem_resource; +void __init jmr3927_setup(void) +{ + extern int panic_timeout; + char *argptr; + + irq_setup = jmr3927_irq_setup; + mips_io_port_base = JMR3927_PORT_BASE + JMR3927_PCIIO; + + board_time_init = jmr3927_time_init; + board_timer_setup = jmr3927_timer_setup; + + _machine_restart = jmr3927_machine_restart; + _machine_halt = jmr3927_machine_halt; + _machine_power_off = jmr3927_machine_power_off; + + /* + * IO/MEM resources. + */ + ioport_resource.start = pci_io_resource.start; + ioport_resource.end = pci_io_resource.end; + iomem_resource.start = pci_mem_resource.start; + iomem_resource.end = pci_mem_resource.end; + + /* Reboot on panic */ + panic_timeout = 180; + + { + unsigned int conf; + conf = read_32bit_cp0_register(CP0_CONF); + } + +#if 1 + /* cache setup */ + { + unsigned int conf; +#ifdef DO_ENABLE_CACHE + int mips_ic_disable = 0, mips_dc_disable = 0; +#else + int mips_ic_disable = 1, mips_dc_disable = 1; +#endif +#ifdef DO_WRITE_THROUGH + int mips_config_cwfon = 0; + int mips_config_wbon = 0; +#else + int mips_config_cwfon = 1; + int mips_config_wbon = 1; +#endif + + conf = read_32bit_cp0_register(CP0_CONF); + conf &= ~(TX39_CONF_ICE | TX39_CONF_DCE | TX39_CONF_WBON | TX39_CONF_CWFON); + conf |= mips_ic_disable ? 0 : TX39_CONF_ICE; + conf |= mips_dc_disable ? 0 : TX39_CONF_DCE; + conf |= mips_config_wbon ? TX39_CONF_WBON : 0; + conf |= mips_config_cwfon ? TX39_CONF_CWFON : 0; + + write_32bit_cp0_register(CP0_CONF, conf); + write_32bit_cp0_register(CP0_TX39_CACHE, 0); + } +#endif + + /* initialize board */ + jmr3927_board_init(); + + argptr = prom_getcmdline(); + + if ((argptr = strstr(argptr, "toeon")) != NULL) { + jmr3927_ccfg_toeon = 1; + } + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "ip=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " ip=bootp"); + } + +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS1,115200"); + } +#endif +} + + +static void tx3927_setup(void); + +#ifdef CONFIG_PCI +unsigned long mips_pci_io_base; +unsigned long mips_pci_io_size; +unsigned long mips_pci_mem_base; +unsigned long mips_pci_mem_size; +/* for legacy I/O, PCI I/O PCI Bus address must be 0 */ +unsigned long mips_pci_io_pciaddr = 0; +#endif +extern struct rtc_ops *rtc_ops; +extern struct rtc_ops jmr3927_rtc_ops; +static void jmr3927_board_init() +{ + char *argptr; + +#ifdef CONFIG_PCI + mips_pci_io_base = JMR3927_PCIIO; + mips_pci_io_size = JMR3927_PCIIO_SIZE; + mips_pci_mem_base = JMR3927_PCIMEM; + mips_pci_mem_size = JMR3927_PCIMEM_SIZE; +#endif + + tx3927_setup(); + +#ifdef CONFIG_VT + conswitchp = &dummy_con; +#endif + + if (jmr3927_have_isac()) { + +#ifdef CONFIG_FB_E1355 + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=e1355fb:crt16h"); + } +#endif + +#ifdef CONFIG_BLK_DEV_IDE + /* overrides PCI-IDE */ +#endif + +#ifdef CONFIG_PC_KEYB + //not yet kbd_ops = &jmr3927_kbd_ops; +#endif + } +#ifdef USE_RTC_DS1742 + if (jmr3927_have_nvram()) { + rtc_ops = &jmr3927_rtc_ops; + } +#endif + + /* SIO0 DTR on */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); + + jmr3927_led_set(0); + + + if (jmr3927_have_isac()) + jmr3927_io_led_set(0); + printk("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", + jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, + jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_dipsw1(), jmr3927_dipsw2(), + jmr3927_dipsw3(), jmr3927_dipsw4()); + if (jmr3927_have_isac()) + printk("JMI-3927IO2 --- ISAC(Rev %d) DIPSW:%01x\n", + jmr3927_isac_reg_in(JMR3927_ISAC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_io_dipsw()); +} +static void tx3927_setup(void) +{ + int i; + + /* SDRAMC are configured by PROM */ + + /* ROMC */ + tx3927_romcptr->cr[1] = JMR3927_ROMCE1 | 0x00030048; + tx3927_romcptr->cr[2] = JMR3927_ROMCE2 | 0x000064c8; + tx3927_romcptr->cr[3] = JMR3927_ROMCE3 | 0x0003f698; + tx3927_romcptr->cr[5] = JMR3927_ROMCE5 | 0x0000f218; + + /* CCFG */ + /* enable Timeout BusError */ + if (jmr3927_ccfg_toeon) + tx3927_ccfgptr->ccfg |= TX3927_CCFG_TOE; + + /* clear BusErrorOnWrite flag */ + tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_BEOW; + /* Disable PCI snoop */ + tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_PSNP; + +#ifdef DO_WRITE_THROUGH + /* Enable PCI SNOOP - with write through only */ + tx3927_ccfgptr->ccfg |= TX3927_CCFG_PSNP; +#endif + + /* Pin selection */ + tx3927_ccfgptr->pcfg &= ~TX3927_PCFG_SELALL; + tx3927_ccfgptr->pcfg |= + TX3927_PCFG_SELSIOC(0) | TX3927_PCFG_SELSIO_ALL | + (TX3927_PCFG_SELDMA_ALL & ~TX3927_PCFG_SELDMA(1)); + + printk("TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", + tx3927_ccfgptr->crir, + tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg); + + /* IRC */ + /* disable interrupt control */ + tx3927_ircptr->cer = 0; + /* mask all IRC interrupts */ + tx3927_ircptr->imr = 0; + for (i = 0; i < TX3927_NUM_IR / 2; i++) { + tx3927_ircptr->ilr[i] = 0; + } + /* setup IRC interrupt mode (Low Active) */ + for (i = 0; i < TX3927_NUM_IR / 8; i++) { + tx3927_ircptr->cr[i] = 0; + } + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX3927_NR_TMR; i++) { + tx3927_tmrptr(i)->tcr = TXx927_TMTCR_CRE; + tx3927_tmrptr(i)->tisr = 0; + tx3927_tmrptr(i)->cpra = 0xffffffff; + tx3927_tmrptr(i)->itmr = 0; + tx3927_tmrptr(i)->ccdr = 0; + tx3927_tmrptr(i)->pgmr = 0; + } + + /* DMA */ + tx3927_dmaptr->mcr = 0; + for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) { + /* reset channel */ + tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; + tx3927_dmaptr->ch[i].ccr = 0; + } + /* enable DMA */ +#ifdef __BIG_ENDIAN + tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN; +#else + tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN | TX3927_DMA_MCR_LE; +#endif + +#ifdef CONFIG_PCI + /* PCIC */ + printk("TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:", + tx3927_pcicptr->did, tx3927_pcicptr->vid, + tx3927_pcicptr->rid); + if (!(tx3927_ccfgptr->ccfg & TX3927_CCFG_PCIXARB)) { + printk("External\n"); + /* XXX */ + } else { + printk("Internal\n"); + + /* Reset PCI Bus */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + udelay(100); + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, + JMR3927_IOC_RESET_ADDR); + udelay(100); + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + + + /* Disable External PCI Config. Access */ + tx3927_pcicptr->lbc = TX3927_PCIC_LBC_EPCAD; +#ifdef __BIG_ENDIAN + tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_IBSE | + TX3927_PCIC_LBC_TIBSE | + TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE; +#endif + /* LB->PCI mappings */ + tx3927_pcicptr->iomas = ~(mips_pci_io_size - 1); + tx3927_pcicptr->ilbioma = mips_pci_io_base; + tx3927_pcicptr->ipbioma = mips_pci_io_pciaddr; + tx3927_pcicptr->mmas = ~(mips_pci_mem_size - 1); + tx3927_pcicptr->ilbmma = mips_pci_mem_base; + tx3927_pcicptr->ipbmma = mips_pci_mem_base; + /* PCI->LB mappings */ + tx3927_pcicptr->iobas = 0xffffffff; + tx3927_pcicptr->ioba = 0; + tx3927_pcicptr->tlbioma = 0; + tx3927_pcicptr->mbas = ~(mips_pci_mem_size - 1); + tx3927_pcicptr->mba = 0; + tx3927_pcicptr->tlbmma = 0; +#ifndef JMR3927_INIT_INDIRECT_PCI + /* Enable Direct mapping Address Space Decoder */ + tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE; +#endif + + /* Clear All Local Bus Status */ + tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; + /* Enable All Local Bus Interrupts */ + tx3927_pcicptr->lbim = TX3927_PCIC_LBIM_ALL; + /* Clear All PCI Status Error */ + tx3927_pcicptr->pcistat = TX3927_PCIC_PCISTATIM_ALL; + /* Enable All PCI Status Error Interrupts */ + tx3927_pcicptr->pcistatim = TX3927_PCIC_PCISTATIM_ALL; + + /* PCIC Int => IRC IRQ10 */ + tx3927_pcicptr->il = TX3927_IR_PCI; +#if 1 + /* Target Control (per errata) */ + tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E; +#endif + + /* Enable Bus Arbiter */ +#if 0 + tx3927_pcicptr->req_trace = 0x73737373; +#endif + tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN; + + tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY | +#if 1 + PCI_COMMAND_IO | +#endif + PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + } +#endif /* CONFIG_PCI */ + + /* PIO */ + /* PIO[15:12] connected to LEDs */ + tx3927_pioptr->dir = 0x0000f000; + tx3927_pioptr->maskcpu = 0; + tx3927_pioptr->maskext = 0; + { + unsigned int conf; + + conf = read_32bit_cp0_register(CP0_CONF); + if (!(conf & TX39_CONF_ICE)) + printk("TX3927 I-Cache disabled.\n"); + if (!(conf & TX39_CONF_DCE)) + printk("TX3927 D-Cache disabled.\n"); + else if (!(conf & TX39_CONF_WBON)) + printk("TX3927 D-Cache WriteThrough.\n"); + else if (!(conf & TX39_CONF_CWFON)) + printk("TX3927 D-Cache WriteBack.\n"); + else + printk("TX3927 D-Cache WriteBack (CWF) .\n"); + } +} diff -urN linux-2.4.18/arch/mips/kernel/Makefile linux-2.4.19-pre5/arch/mips/kernel/Makefile --- linux-2.4.18/arch/mips/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/Makefile Sat Mar 30 22:55:26 2002 @@ -11,36 +11,43 @@ .S.o: $(CC) $(AFLAGS) -c $< -o $@ -EXTRA_AFLAGS = -mips3 -mcpu=r4000 - all: kernel.o head.o init_task.o O_TARGET := kernel.o +export-objs = irq.o pci-dma.o setup.o smp.o mips_ksyms.o \ + old-irq.o + obj-y += branch.o process.o signal.o entry.o \ traps.o ptrace.o vm86.o ioport.o reset.o \ semaphore.o setup.o syscall.o sysmips.o \ ipc.o scall_o32.o unaligned.o obj-$(CONFIG_MODULES) += mips_ksyms.o -ifdef CONFIG_CPU_R3000 -obj-y += r2300_misc.o r2300_fpu.o r2300_switch.o -else -obj-y += r4k_misc.o r4k_switch.o -ifdef CONFIG_CPU_R6000 -obj-y += r6000_fpu.o -else -obj-y += r4k_fpu.o -endif -endif +obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o +obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o +obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R4000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R4300) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R4X00) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R5000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R5432) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_RM7000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o # Old style irq support, going to die in 2.5. -export-objs += old-irq.o obj-$(CONFIG_NEW_IRQ) += irq.o obj-$(CONFIG_ROTTEN_IRQ) += old-irq.o obj-$(CONFIG_I8259) += i8259.o +obj-$(CONFIG_IRQ_CPU) += irq_cpu.o # transition from old time.c to new time.c # some boards uses old-time.c, some use time.c, and some use their own ones @@ -51,13 +58,13 @@ obj-$(CONFIG_BINFMT_IRIX) += irixelf.o irixioctl.o irixsig.o sysirix.o \ irixinv.o obj-$(CONFIG_REMOTE_DEBUG) += gdb-low.o gdb-stub.o -obj-$(CONFIG_PCI) += pci-dma.o obj-$(CONFIG_PROC_FS) += proc.o -ifdef CONFIG_PCI -obj-$(CONFIG_NEW_PCI) += pci.o -obj-$(CONFIG_PCI_AUTO) += pci_auto.o +obj-$(CONFIG_NEW_PCI) += pci.o +ifndef CONFIG_MAPPED_PCI_IO +obj-y += pci-dma.o endif +obj-$(CONFIG_PCI_AUTO) += pci_auto.o entry.o: entry.S head.o: head.S diff -urN linux-2.4.18/arch/mips/kernel/branch.c linux-2.4.19-pre5/arch/mips/kernel/branch.c --- linux-2.4.18/arch/mips/kernel/branch.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/branch.c Sat Mar 30 22:55:26 2002 @@ -16,7 +16,6 @@ #include #include #include -#include #include /* @@ -164,10 +163,10 @@ * And now the FPA/cp1 branch instructions. */ case cop1_op: - if(!(mips_cpu.options & MIPS_CPU_FPU)) + if (!(mips_cpu.options & MIPS_CPU_FPU)) fcr31 = current->thread.fpu.soft.sr; else - asm ("cfc1\t%0,$31":"=r" (fcr31)); + asm("cfc1\t%0,$31":"=r" (fcr31)); bit = (insn.i_format.rt >> 2); bit += (bit != 0); bit += 23; diff -urN linux-2.4.18/arch/mips/kernel/entry.S linux-2.4.19-pre5/arch/mips/kernel/entry.S --- linux-2.4.18/arch/mips/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/entry.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ /* -/* * 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. @@ -9,10 +8,12 @@ * Copyright (C) 2001 MIPS Technologies, Inc. */ #include +#include #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ lw v1, TASK_SIGPENDING($28) bnez v0, reschedule bnez v1, signal_return + FEXPORT(restore_all) restore_all: .set noat RESTORE_ALL_AND_RET .set at @@ -93,15 +95,89 @@ * Someone tried to fool us by sending an interrupt but we * couldn't find a cause for it. */ - lui t1,%hi(spurious_count) - .set reorder - lw t0,%lo(spurious_count)(t1) - .set noreorder + lui t1,%hi(irq_err_count) + lw t0,%lo(irq_err_count)(t1) addiu t0,1 - sw t0,%lo(spurious_count)(t1) + sw t0,%lo(irq_err_count)(t1) j ret_from_irq END(spurious_interrupt) + __INIT + + .set reorder + + NESTED(except_vec1_generic, 0, sp) + PANIC("Exception vector 1 called") + END(except_vec1_generic) + + /* + * General exception vector. Used for all CPUs except R4000 + * and R4400 SC and MC versions. + */ + NESTED(except_vec3_generic, 0, sp) + mfc0 k1, CP0_CAUSE + la k0, exception_handlers + andi k1, k1, 0x7c + addu k0, k0, k1 + lw k0, (k0) + jr k0 + END(except_vec3_generic) + .set at + + /* General exception vector R4000 version. */ + NESTED(except_vec3_r4000, 0, sp) + .set push + .set mips3 + .set noat + mfc0 k1, CP0_CAUSE + li k0, 31<<2 + andi k1, k1, 0x7c + .set noreorder + beq k1, k0, handle_vced + li k0, 14<<2 + beq k1, k0, handle_vcei + la k0, exception_handlers + .set reorder + addu k0, k0, k1 + lw k0, (k0) + jr k0 + + /* + * Big shit, we now may have two dirty primary cache lines for + * the same physical address. We can savely invalidate the + * line pointed to by c0_badvaddr because after return from + * this exception handler the load / store will be re-executed. + */ +handle_vced: + mfc0 k0, CP0_BADVADDR + li k1, -4 + and k0, k1 + mtc0 zero, CP0_TAGLO + cache Index_Store_Tag_D,(k0) + cache Hit_Writeback_Inv_SD,(k0) +#ifdef CONFIG_PROC_FS + lui k0, %hi(vced_count) + lw k1, %lo(vced_count)(k0) + addiu k1, 1 + sw k1, %lo(vced_count)(k0) +#endif + eret + +handle_vcei: + mfc0 k0, CP0_BADVADDR + cache Hit_Writeback_Inv_SD, (k0) # also cleans pi +#ifdef CONFIG_PROC_FS + lui k0, %hi(vcei_count) + lw k1, %lo(vcei_count)(k0) + addiu k1, 1 + sw k1, %lo(vcei_count)(k0) +#endif + eret + .set pop + END(except_vec3_r4000) + + __FINIT + /* * Build a default exception handler for the exceptions that don't need * special handlers. If you didn't know yet - I *like* playing games with @@ -148,6 +224,7 @@ NESTED(handle_##exception, PT_SIZE, sp); \ .set noat; \ SAVE_ALL; \ + FEXPORT(handle_##exception##_int); \ __BUILD_clear_##clear(exception); \ .set at; \ __BUILD_##verbose(exception); \ @@ -159,7 +236,7 @@ BUILD_HANDLER(adel,ade,ade,silent) /* #4 */ BUILD_HANDLER(ades,ade,ade,silent) /* #5 */ - BUILD_HANDLER(ibe,ibe,cli,verbose) /* #6 */ + BUILD_HANDLER(ibe,ibe,cli,silent) /* #6 */ BUILD_HANDLER(dbe,dbe,cli,silent) /* #7 */ BUILD_HANDLER(bp,bp,sti,silent) /* #9 */ BUILD_HANDLER(ri,ri,sti,silent) /* #10 */ @@ -167,8 +244,9 @@ BUILD_HANDLER(ov,ov,sti,silent) /* #12 */ BUILD_HANDLER(tr,tr,sti,silent) /* #13 */ BUILD_HANDLER(fpe,fpe,fpe,silent) /* #15 */ - BUILD_HANDLER(watch,watch,sti,verbose) /* #23 */ - BUILD_HANDLER(reserved,reserved,sti,verbose) /* others */ + BUILD_HANDLER(watch,watch,sti,silent) /* #23 */ + BUILD_HANDLER(mcheck,mcheck,cli,silent) /* #24 */ + BUILD_HANDLER(reserved,reserved,sti,silent) /* others */ .set pop diff -urN linux-2.4.18/arch/mips/kernel/gdb-low.S linux-2.4.19-pre5/arch/mips/kernel/gdb-low.S --- linux-2.4.18/arch/mips/kernel/gdb-low.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/gdb-low.S Sat Mar 30 22:55:26 2002 @@ -145,9 +145,9 @@ * FPU control registers */ - mfc1 v0,CP1_STATUS + cfc1 v0,CP1_STATUS sw v0,GDB_FR_FSR(sp) - mfc1 v0,CP1_REVISION + cfc1 v0,CP1_REVISION sw v0,GDB_FR_FIR(sp) /* @@ -304,7 +304,7 @@ lw v1,GDB_FR_REG3(sp) lw v0,GDB_FR_REG2(sp) lw $1,GDB_FR_REG1(sp) -#ifdef CONFIG_CPU_R3000 +#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) lw k0, GDB_FR_EPC(sp) lw sp, GDB_FR_REG29(sp) /* Deallocate stack */ jr k0 @@ -321,11 +321,7 @@ END(trap_low) LEAF(kgdb_read_byte) - .set push - .set noreorder - .set nomacro 4: lb t0, (a0) - .set pop sb t0, (a1) li v0, 0 jr ra @@ -335,11 +331,7 @@ END(kgdb_read_byte) LEAF(kgdb_write_byte) - .set push - .set noreorder - .set nomacro 5: sb a0, (a1) - .set pop li v0, 0 jr ra .section __ex_table,"a" @@ -349,6 +341,7 @@ .type kgdbfault@function .ent kgdbfault + kgdbfault: li v0, -EFAULT jr ra .end kgdbfault diff -urN linux-2.4.18/arch/mips/kernel/gdb-stub.c linux-2.4.19-pre5/arch/mips/kernel/gdb-stub.c --- linux-2.4.18/arch/mips/kernel/gdb-stub.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/gdb-stub.c Sat Mar 30 22:55:26 2002 @@ -11,8 +11,6 @@ * Send complaints, suggestions etc. to * * Copyright (C) 1995 Andreas Busse - * - * $Id: gdb-stub.c,v 1.6 1999/05/01 22:40:35 ralf Exp $ */ /* @@ -578,7 +576,7 @@ async_bp.addr = epc; async_bp.val = *(unsigned *)epc; *(unsigned *)epc = BP; - flush_cache_all(); + __flush_cache_all(); } @@ -805,7 +803,7 @@ * NB: We flush both caches, just to be sure... */ - flush_cache_all(); + __flush_cache_all(); return; /* NOTREACHED */ break; @@ -834,7 +832,7 @@ * use breakpoints and continue, instead. */ single_step(regs); - flush_cache_all(); + __flush_cache_all(); return; /* NOTREACHED */ @@ -925,9 +923,8 @@ #ifdef CONFIG_GDB_CONSOLE -void gdb_puts(const char *str) +void gdb_putsn(const char *str, int l) { - int l = strlen(str); char outbuf[18]; outbuf[0]='O'; @@ -949,7 +946,7 @@ static void gdb_console_write(struct console *con, const char *s, unsigned n) { - gdb_puts(s); + gdb_putsn(s, n); } static struct console gdb_console = { diff -urN linux-2.4.18/arch/mips/kernel/head.S linux-2.4.19-pre5/arch/mips/kernel/head.S --- linux-2.4.18/arch/mips/kernel/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/head.S Sat Mar 30 22:55:26 2002 @@ -1,6 +1,4 @@ /* - * arch/mips/kernel/head.S - * * 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. @@ -13,550 +11,177 @@ * Further modifications by David S. Miller and Harald Koerfgen * Copyright (C) 1999 Silicon Graphics, Inc. * - * Head.S contains the MIPS exception handler and startup code. - * - ************************************************************************** - * 9 Nov, 2000. - * Added Cache Error exception handler and SBDDP EJTAG debug exception. - * - * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - ************************************************************************** + * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #include +#include #include #include -#include #include #include +#include #include #include #include #include #include -#include - - .text - /* - * Reserved space for exception handlers. - * Necessary for machines which link their kernels at KSEG0. - * FIXME: Use the initcode feature to get rid of unused handler - * variants. - */ - .fill 0x280 -/* - * This is space for the interrupt handlers. - * After trap_init() they are located at virtual address KSEG0. - * - * These handlers much be written in a relocatable manner - * because based upon the cpu type an arbitrary one of the - * following pieces of code will be copied to the KSEG0 - * vector location. - */ - /* TLB refill, EXL == 0, R4xx0, non-R4600 version */ - .set noreorder - .set noat - LEAF(except_vec0_r4000) - .set mips3 -#ifdef CONFIG_SMP - mfc0 k1, CP0_CONTEXT - la k0, current_pgd - srl k1, 23 - sll k1, 2 - addu k1, k0, k1 - lw k1, (k1) -#else - lw k1, current_pgd # get pgd pointer -#endif - mfc0 k0, CP0_BADVADDR # Get faulting address - srl k0, k0, 22 # get pgd only bits - - sll k0, k0, 2 - addu k1, k1, k0 # add in pgd offset - mfc0 k0, CP0_CONTEXT # get context reg - lw k1, (k1) -#if defined(CONFIG_CPU_VR41XX) - srl k0, k0, 3 # get pte offset -#else - srl k0, k0, 1 # get pte offset -#endif - and k0, k0, 0xff8 - addu k1, k1, k0 # add in offset - lw k0, 0(k1) # get even pte - lw k1, 4(k1) # get odd pte - srl k0, k0, 6 # convert to entrylo0 - mtc0 k0, CP0_ENTRYLO0 # load it - srl k1, k1, 6 # convert to entrylo1 - mtc0 k1, CP0_ENTRYLO1 # load it - b 1f - tlbwr # write random tlb entry -1: - nop - eret # return from trap - END(except_vec0_r4000) - - /* TLB refill, EXL == 0, R4600 version */ - LEAF(except_vec0_r4600) - .set mips3 - mfc0 k0, CP0_BADVADDR - srl k0, k0, 22 - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - srl k0, k0, 1 - and k0, k0, 0xff8 - addu k1, k1, k0 - lw k0, 0(k1) - lw k1, 4(k1) - srl k0, k0, 6 - mtc0 k0, CP0_ENTRYLO0 - srl k1, k1, 6 - mtc0 k1, CP0_ENTRYLO1 - nop - tlbwr - nop - eret - END(except_vec0_r4600) - - /* TLB refill, EXL == 0, R52x0 "Nevada" version */ - /* - * This version has a bug workaround for the Nevada. It seems - * as if under certain circumstances the move from cp0_context - * might produce a bogus result when the mfc0 instruction and - * it's consumer are in a different cacheline or a load instruction, - * probably any memory reference, is between them. This is - * potencially slower than the R4000 version, so we use this - * special version. - */ - .set noreorder - .set noat - LEAF(except_vec0_nevada) - .set mips3 - mfc0 k0, CP0_BADVADDR # Get faulting address - srl k0, k0, 22 # get pgd only bits - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 # add in pgd offset - lw k1, (k1) - mfc0 k0, CP0_CONTEXT # get context reg - srl k0, k0, 1 # get pte offset - and k0, k0, 0xff8 - addu k1, k1, k0 # add in offset - lw k0, 0(k1) # get even pte - lw k1, 4(k1) # get odd pte - srl k0, k0, 6 # convert to entrylo0 - mtc0 k0, CP0_ENTRYLO0 # load it - srl k1, k1, 6 # convert to entrylo1 - mtc0 k1, CP0_ENTRYLO1 # load it - nop # QED specified nops - nop - tlbwr # write random tlb entry - nop # traditional nop - eret # return from trap - END(except_vec0_nevada) - - /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */ - LEAF(except_vec0_r45k_bvahwbug) - .set mips3 - mfc0 k0, CP0_BADVADDR - srl k0, k0, 22 - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - srl k0, k0, 1 - and k0, k0, 0xff8 - addu k1, k1, k0 - lw k0, 0(k1) - lw k1, 4(k1) - nop /* XXX */ - tlbp - srl k0, k0, 6 - mtc0 k0, CP0_ENTRYLO0 - srl k1, k1, 6 - mfc0 k0, CP0_INDEX - mtc0 k1, CP0_ENTRYLO1 - bltzl k0, 1f - tlbwr -1: - nop - eret - END(except_vec0_r45k_bvahwbug) - -#ifdef CONFIG_SMP - /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */ - LEAF(except_vec0_r4k_mphwbug) - .set mips3 - mfc0 k0, CP0_BADVADDR - srl k0, k0, 22 - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - srl k0, k0, 1 - and k0, k0, 0xff8 - addu k1, k1, k0 - lw k0, 0(k1) - lw k1, 4(k1) - nop /* XXX */ - tlbp - srl k0, k0, 6 - mtc0 k0, CP0_ENTRYLO0 - srl k1, k1, 6 - mfc0 k0, CP0_INDEX - mtc0 k1, CP0_ENTRYLO1 - bltzl k0, 1f - tlbwr -1: - nop - eret - END(except_vec0_r4k_mphwbug) -#endif - - /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */ - LEAF(except_vec0_r4k_250MHZhwbug) - .set mips3 - mfc0 k0, CP0_BADVADDR - srl k0, k0, 22 - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - srl k0, k0, 1 - and k0, k0, 0xff8 - addu k1, k1, k0 - lw k0, 0(k1) - lw k1, 4(k1) - srl k0, k0, 6 - mtc0 zero, CP0_ENTRYLO0 - mtc0 k0, CP0_ENTRYLO0 - srl k1, k1, 6 - mtc0 zero, CP0_ENTRYLO1 - mtc0 k1, CP0_ENTRYLO1 - b 1f - tlbwr -1: - nop - eret - END(except_vec0_r4k_250MHZhwbug) - -#ifdef CONFIG_SMP - /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */ - LEAF(except_vec0_r4k_MP250MHZhwbug) - .set mips3 - mfc0 k0, CP0_BADVADDR - srl k0, k0, 22 - lw k1, current_pgd # get pgd pointer - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - srl k0, k0, 1 - and k0, k0, 0xff8 - addu k1, k1, k0 - lw k0, 0(k1) - lw k1, 4(k1) - nop /* XXX */ - tlbp - srl k0, k0, 6 - mtc0 zero, CP0_ENTRYLO0 - mtc0 k0, CP0_ENTRYLO0 - mfc0 k0, CP0_INDEX - srl k1, k1, 6 - mtc0 zero, CP0_ENTRYLO1 - mtc0 k1, CP0_ENTRYLO1 - bltzl k0, 1f - tlbwr -1: - nop - eret - END(except_vec0_r4k_MP250MHZhwbug) -#endif - - /* TLB refill, R[23]00 version */ - LEAF(except_vec0_r2300) - .set noat - .set mips1 - mfc0 k0, CP0_BADVADDR - lw k1, current_pgd # get pgd pointer - srl k0, k0, 22 - sll k0, k0, 2 - addu k1, k1, k0 - mfc0 k0, CP0_CONTEXT - lw k1, (k1) - and k0, k0, 0xffc - addu k1, k1, k0 - lw k0, (k1) - nop - mtc0 k0, CP0_ENTRYLO0 - mfc0 k1, CP0_EPC - tlbwr - jr k1 - rfe - END(except_vec0_r2300) - - - /* XTLB refill, EXL == 0, R4xx0 cpus only use this... */ - NESTED(except_vec1_generic, 0, sp) - .set noat - .set mips3 - /* Register saving is delayed as long as we don't know - * which registers really need to be saved. - */ - mfc0 k1, CP0_CONTEXT - dsra k1, 1 - lwu k0, (k1) # May cause another exception - lwu k1, 4(k1) - dsrl k0, 6 # Convert to EntryLo format - dsrl k1, 6 # Convert to EntryLo format - dmtc0 k0, CP0_ENTRYLO0 - dmtc0 k1, CP0_ENTRYLO1 - nop # Needed for R4[04]00 pipeline - tlbwr - nop # Needed for R4[04]00 pipeline - nop - nop - eret - nop /* Workaround for R4000 bug. */ - eret - END(except_vec1_generic) - - /* Cache Error */ - LEAF(except_vec2_generic) - .set noat - .set mips0 - /* - * This is a very bad place to be. Our cache error - * detection has triggered. If we have write-back data - * in the cache, we may not be able to recover. As a - * first-order desperate measure, turn off KSEG0 cacheing. - */ - mfc0 k0,CP0_CONFIG - li k1,~CONF_CM_CMASK - and k0,k0,k1 - ori k0,k0,CONF_CM_UNCACHED - mtc0 k0,CP0_CONFIG - /* Give it a few cycles to sink in... */ - nop - nop - nop - - j cache_parity_error - nop - END(except_vec2_generic) - - /* General exception vector R4000 version. */ - NESTED(except_vec3_r4000, 0, sp) - .set noat - mfc0 k1, CP0_CAUSE - andi k1, k1, 0x7c - li k0, 31<<2 - beq k1, k0, handle_vced - li k0, 14<<2 - beq k1, k0, handle_vcei - la k0, exception_handlers - addu k0, k0, k1 - lw k0, (k0) - nop - jr k0 - nop -/* - * Big shit, we now may have two dirty primary cache lines for the same - * physical address. We can savely invalidate the line pointed to by - * c0_badvaddr because after return from this exception handler the load / - * store will be re-executed. - */ - .set mips3 -handle_vced: - mfc0 k0, CP0_BADVADDR - li k1, -4 - and k0, k1 - mtc0 zero, CP0_TAGLO - cache Index_Store_Tag_D,(k0) - cache Hit_Writeback_Inv_SD,(k0) -#ifdef CONFIG_PROC_FS - lui k0, %hi(vced_count) - lw k1, %lo(vced_count)(k0) - addiu k1, 1 - sw k1, %lo(vced_count)(k0) -#endif - eret - -handle_vcei: - mfc0 k0, CP0_BADVADDR - cache Hit_Writeback_Inv_SD,(k0) # also cleans pi -#ifdef CONFIG_PROC_FS - lui k0, %hi(vcei_count) - lw k1, %lo(vcei_count)(k0) - addiu k1, 1 - sw k1, %lo(vcei_count)(k0) -#endif - eret - - END(except_vec3_r4000) - .set at + __INIT - /* General exception vector. */ - NESTED(except_vec3_generic, 0, sp) - .set noat - .set mips0 - mfc0 k1, CP0_CAUSE - la k0, exception_handlers - andi k1, k1, 0x7c - addu k0, k0, k1 - lw k0, (k0) - nop - jr k0 - nop - END(except_vec3_generic) - .set at - - /* - * Special interrupt vector for embedded MIPS. This is a - * dedicated interrupt vector which reduces interrupt processing - * overhead. The jump instruction will be inserted here at - * initialization time. This handler may only be 8 bytes in size! - */ - NESTED(except_vec4, 0, sp) -1: j 1b /* Dummy, will be replaced */ - nop - END(except_vec4) - - /* - * SBDDP EJTAG debug exception handler. - * The EJTAG debug exception entry point is 0xbfc00480, which - * normally is in the boot PROM, so the boot PROM must do a - * unconditional jump to this vector. - */ - NESTED(except_vec_ejtag_debug, 0, sp) - j ejtag_debug_handler - nop - END(except_vec_ejtag_debug) - - /* - * EJTAG debug exception handler. - */ - NESTED(ejtag_debug_handler, PT_SIZE, sp) - .set noat - .set noreorder - SAVE_ALL - PRINT("SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); - mfc0 k0, $23 # Get EJTAG Debug register. - mfc0 k1, $24 # Get DEPC register. - bgez k0, 1f - addiu k1, k1, 4 # SBDDP inst. in delay slot. - addiu k1, k1, 4 -1: mtc0 k1, $24 - RESTORE_ALL - .word 0x4200001f # deret, return EJTAG debug exception. - nop - .set at - END(ejtag_debug_handler) - - -/* - * Kernel entry point - */ + .text + /* + * Reserved space for exception handlers. + * Necessary for machines which link their kernels at KSEG0. + */ + .fill 0x280 + + /* Cache Error */ + LEAF(except_vec2_generic) + .set noreorder + .set noat + .set mips0 + /* + * This is a very bad place to be. Our cache error + * detection has triggered. If we have write-back data + * in the cache, we may not be able to recover. As a + * first-order desperate measure, turn off KSEG0 cacheing. + */ + mfc0 k0,CP0_CONFIG + li k1,~CONF_CM_CMASK + and k0,k0,k1 + ori k0,k0,CONF_CM_UNCACHED + mtc0 k0,CP0_CONFIG + /* Give it a few cycles to sink in... */ + nop + nop + nop + + j cache_parity_error + nop + END(except_vec2_generic) + + .set at + + /* + * Special interrupt vector for embedded MIPS. This is a + * dedicated interrupt vector which reduces interrupt processing + * overhead. The jump instruction will be inserted here at + * initialization time. This handler may only be 8 bytes in + * size! + */ + NESTED(except_vec4, 0, sp) +1: j 1b /* Dummy, will be replaced */ + nop + END(except_vec4) + + /* + * SBDDP EJTAG debug exception handler. + * The EJTAG debug exception entry point is 0xbfc00480, which + * normally is in the boot PROM, so the boot PROM must do a + * unconditional jump to this vector. + */ + NESTED(except_vec_ejtag_debug, 0, sp) + j ejtag_debug_handler + nop + END(except_vec_ejtag_debug) + + /* + * EJTAG debug exception handler. + */ + NESTED(ejtag_debug_handler, PT_SIZE, sp) + .set noat + .set noreorder + SAVE_ALL + PRINT("SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); + mfc0 k0, $23 # Get EJTAG Debug register. + mfc0 k1, $24 # Get DEPC register. + bgez k0, 1f + addiu k1, k1, 4 # SBDDP inst. in delay slot. + addiu k1, k1, 4 +1: mtc0 k1, $24 + RESTORE_ALL + .word 0x4200001f # deret, return EJTAG debug exception. + nop + .set at + END(ejtag_debug_handler) + + /* + * Kernel entry point + */ NESTED(kernel_entry, 16, sp) - .set noreorder - /* The following two symbols are used for kernel profiling. */ - EXPORT(stext) - EXPORT(_stext) - - /* - * Stack for kernel and init, current variable - */ - la $28, init_task_union - addiu t0, $28, KERNEL_STACK_SIZE-32 - subu sp, t0, 4*SZREG - - sw t0, kernelsp - /* The firmware/bootloader passes argc/argp/envp - * to us as arguments. But clear bss first because - * the romvec and other important info is stored there - * by prom_init(). - */ - la t0, _edata - sw zero, (t0) - la t1, (_end - 4) -1: - addiu t0, 4 - bne t0, t1, 1b - sw zero, (t0) - - jal init_arch - nop - END(kernel_entry) + .set noreorder + /* The following two symbols are used for kernel profiling. */ + EXPORT(stext) + EXPORT(_stext) + + /* + * Stack for kernel and init, current variable + */ + la $28, init_task_union + addiu t0, $28, KERNEL_STACK_SIZE-32 + subu sp, t0, 4*SZREG + + sw t0, kernelsp + /* The firmware/bootloader passes argc/argp/envp + * to us as arguments. But clear bss first because + * the romvec and other important info is stored there + * by prom_init(). + */ + la t0, _edata + sw zero, (t0) + la t1, (_end - 4) +1: + addiu t0, 4 + bne t0, t1, 1b + sw zero, (t0) + + jal init_arch + nop + END(kernel_entry) #ifdef CONFIG_SMP /* - * SMP slave cpus entry point. Board specific code - * for bootstrap calls this function after setting up - * the stack and gp registers. - */ - LEAF(smp_bootstrap) - .set push - .set noreorder - mtc0 zero, CP0_WIRED - CLI - mfc0 t0, CP0_STATUS - li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV); - and t0, t1 - or t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR); - addiu a0, zero, 0 - jal start_secondary - mtc0 t0, CP0_STATUS - .set pop - END(smp_bootstrap) -#endif - -/* - * This buffer is reserved for the use of the cache error handler. - */ - .data - EXPORT(cache_error_buffer) - .fill 32*4,1,0 - -#ifndef CONFIG_SMP -EXPORT(kernelsp) - PTR 0 -EXPORT(current_pgd) - PTR 0 -#else - /* There's almost certainly a better way to do this with the macros...*/ - .globl kernelsp - .comm kernelsp, NR_CPUS * 8, 8 - .globl current_pgd - .comm current_pgd, NR_CPUS * 8, 8 -#endif - .text - .org 0x1000 -EXPORT(swapper_pg_dir) - - .org 0x2000 -EXPORT(empty_bad_page) - - .org 0x3000 -EXPORT(empty_bad_page_table) - - .org 0x4000 -EXPORT(invalid_pte_table) - - .org 0x5000 -/* XXX This label is required to keep GAS trying to be too clever ... - Bug? */ -dummy: -/* - * Align to 8kb boundary for init_task_union which follows in the - * .text segment. + * SMP slave cpus entry point. Board specific code for bootstrap calls this + * function after setting up the stack and gp registers. */ - .align 13 + LEAF(smp_bootstrap) + .set push + .set noreorder + mtc0 zero, CP0_WIRED + CLI + mfc0 t0, CP0_STATUS + li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX) + and t0, t1 + or t0, (ST0_CU0|ST0_FR); + jal start_secondary + mtc0 t0, CP0_STATUS + .set pop + END(smp_bootstrap) +#endif + + __FINIT + + .comm kernelsp, NR_CPUS * 8, 8 + .comm pgd_current, NR_CPUS * 8, 8 + +#undef PAGE_SIZE +#define PAGE_SIZE 0x1000 + + .macro page name, order=0 + .globl \name +\name: .size \name, (PAGE_SIZE << \order) + .org . + (PAGE_SIZE << \order) + .type \name, @object + .endm + + .data + .align 12 + + page swapper_pg_dir, PGD_ORDER + page empty_bad_page, 0 + page empty_bad_page_table, 0 + page invalid_pte_table, 0 diff -urN linux-2.4.18/arch/mips/kernel/i8259.c linux-2.4.19-pre5/arch/mips/kernel/i8259.c --- linux-2.4.18/arch/mips/kernel/i8259.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/i8259.c Sat Mar 30 22:55:26 2002 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -30,7 +29,7 @@ * moves to arch independent land */ -spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; static void end_8259A_irq (unsigned int irq) { @@ -69,9 +68,8 @@ */ static unsigned int cached_irq_mask = 0xffff; -#define __byte(x,y) (((unsigned char *)&(y))[x]) -#define cached_21 (__byte(0,cached_irq_mask)) -#define cached_A1 (__byte(1,cached_irq_mask)) +#define cached_21 (cached_irq_mask) +#define cached_A1 (cached_irq_mask >> 8) void disable_8259A_irq(unsigned int irq) { @@ -211,7 +209,7 @@ printk("spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } - irq_err_count++; + atomic_inc(&irq_err_count); /* * Theoretically we do not have to handle this IRQ, * but in Linux this does not cause problems and is @@ -234,7 +232,7 @@ * outb_p - this has to work on a wide range of PC hardware. */ outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ - outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ + outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */ outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ if (auto_eoi) outb_p(0x03, 0x21); /* master does Auto EOI */ @@ -242,7 +240,7 @@ outb_p(0x01, 0x21); /* master expects normal EOI */ outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ - outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ + outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */ outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode is to be investigated) */ diff -urN linux-2.4.18/arch/mips/kernel/init_task.c linux-2.4.19-pre5/arch/mips/kernel/init_task.c --- linux-2.4.18/arch/mips/kernel/init_task.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/init_task.c Sat Mar 30 22:55:26 2002 @@ -20,5 +20,5 @@ * The things we do for performance.. */ union task_union init_task_union - __attribute__((__section__(".text"))) = + __attribute__((__section__(".data.init_task"))) = { INIT_TASK(init_task_union.task) }; diff -urN linux-2.4.18/arch/mips/kernel/irix5sys.h linux-2.4.19-pre5/arch/mips/kernel/irix5sys.h --- linux-2.4.18/arch/mips/kernel/irix5sys.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/irix5sys.h Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: irix5sys.h,v 1.2 1998/08/17 10:16:25 ralf Exp $ - * +/* * irix5sys.h: 32-bit IRIX5 ABI system call table. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -urN linux-2.4.18/arch/mips/kernel/irixinv.c linux-2.4.19-pre5/arch/mips/kernel/irixinv.c --- linux-2.4.18/arch/mips/kernel/irixinv.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/irixinv.c Sat Mar 30 22:55:26 2002 @@ -4,8 +4,6 @@ * use the linked lists for the inventory yet. * * Miguel de Icaza, 1997. - * - * $Id: irixinv.c,v 1.3 1998/04/05 11:23:51 ralf Exp $ */ #include #include @@ -79,3 +77,5 @@ add_to_inventory (2, 2, 0, 1, 0); add_to_inventory (7, 14, 0, 0, 6); } + +module_init(init_inventory); diff -urN linux-2.4.18/arch/mips/kernel/irq.c linux-2.4.19-pre5/arch/mips/kernel/irq.c --- linux-2.4.18/arch/mips/kernel/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/irq.c Sat Mar 30 22:55:26 2002 @@ -8,17 +8,22 @@ * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle */ +#include #include -#include +#include #include #include #include +#include +#include #include #include #include #include +#include #include +#include /* * Controller mappings for all interrupt sources: @@ -63,7 +68,7 @@ end_none }; -volatile unsigned long irq_err_count, spurious_count; +atomic_t irq_err_count; /* * Generic, controller-independent functions: @@ -97,6 +102,177 @@ return p - buf; } +#ifdef CONFIG_SMP +int global_irq_holder = NO_PROC_ID; +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; + +/* + * Most of this code is take from the mips64 tree (ip27-irq.c). It's virtually + * identical to the i386 implentation in arh/i386/irq.c, with translations for + * the interrupt enable bit + */ + +#define MAXCOUNT 100000000 +#define SYNC_OTHER_CORES(x) udelay(x+1) + +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 (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + break; + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + + for (;;) { + if (!--count) { + printk("Count spun out. Huh?\n"); + count = ~0; + } + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + if (irqs_running()) + continue; + if (spin_is_locked(&global_irq_lock)) + continue; + 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 + * 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) +{ + if (irqs_running()) { + /* Stupid approach */ + cli(); + sti(); + } +} + +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 int flags; + + __save_flags(flags); + if (flags & ST0_IE) { + 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; + int cpu = smp_processor_id(); + + __save_flags(flags); + local_enabled = (flags & ST0_IE); + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count(cpu)) { + if (local_enabled) + retval = 1; + if (global_irq_holder == cpu) + 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\n", flags); + } +} +#endif /* CONFIG_SMP */ + /* * This should really return information about whether * we should do bottom half handling etc. Right now we @@ -690,7 +866,7 @@ } spin_unlock_irqrestore(&desc->lock,flags); - /* register_irq_proc(irq); */ + register_irq_proc(irq); return 0; } @@ -704,4 +880,177 @@ irq_desc[i].depth = 1; irq_desc[i].handler = &no_irq_type; } +} + +EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(probe_irq_mask); + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; + +#define HEX_DIGITS 8 + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (long) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +#endif + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || + irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + +#if CONFIG_SMP + { + struct proc_dir_entry *entry; + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) + register_irq_proc(i); } diff -urN linux-2.4.18/arch/mips/kernel/irq_cpu.c linux-2.4.19-pre5/arch/mips/kernel/irq_cpu.c --- linux-2.4.18/arch/mips/kernel/irq_cpu.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/kernel/irq_cpu.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,91 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This file define the irq handler for MIPS CPU interrupts. + * + * 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. + */ + +/* + * Almost all MIPS CPUs define 8 interrupt sources. They are typically + * level triggered (i.e., cannot be cleared from CPU; must be cleared from + * device). The first two are software interrupts. The last one is + * usually cpu timer interrupt if coutner register is present. + * + * This file exports one global function: + * mips_cpu_irq_init(u32 irq_base); + */ +#include +#include +#include + +#include + +static int mips_cpu_irq_base = -1; + +static void mips_cpu_irq_enable(unsigned int irq) +{ + clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); + set_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); +} + +static void mips_cpu_irq_disable(unsigned int irq) +{ + clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); +} + +static unsigned int mips_cpu_irq_startup(unsigned int irq) +{ + mips_cpu_irq_enable(irq); + + return 0; +} + +#define mips_cpu_irq_shutdown mips_cpu_irq_disable + +static void mips_cpu_irq_ack(unsigned int irq) +{ + /* although we attemp to clear the IP bit in cause reigster, I think + * usually it is cleared by device (irq source) + */ + clear_cp0_cause(1 << (irq - mips_cpu_irq_base + 8)); + + /* disable this interrupt - so that we safe proceed to the handler */ + mips_cpu_irq_disable(irq); +} + +static void mips_cpu_irq_end(unsigned int irq) +{ + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mips_cpu_irq_enable(irq); +} + +static hw_irq_controller mips_cpu_irq_controller = { + "CPU_irq", + mips_cpu_irq_startup, + mips_cpu_irq_shutdown, + mips_cpu_irq_enable, + mips_cpu_irq_disable, + mips_cpu_irq_ack, + mips_cpu_irq_end, + NULL /* no affinity stuff for UP */ +}; + + +void mips_cpu_irq_init(u32 irq_base) +{ + u32 i; + + for (i = irq_base; i < irq_base + 8; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &mips_cpu_irq_controller; + } + + mips_cpu_irq_base = irq_base; +} diff -urN linux-2.4.18/arch/mips/kernel/mips_ksyms.c linux-2.4.19-pre5/arch/mips/kernel/mips_ksyms.c --- linux-2.4.18/arch/mips/kernel/mips_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/mips/kernel/mips_ksyms.c Sat Mar 30 22:55:26 2002 @@ -62,8 +62,6 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL(_clear_page); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* @@ -87,8 +85,6 @@ */ EXPORT_SYMBOL(_flush_page_to_ram); EXPORT_SYMBOL(_flush_cache_all); -EXPORT_SYMBOL(_dma_cache_wback_inv); -EXPORT_SYMBOL(_dma_cache_inv); EXPORT_SYMBOL(invalid_pte_table); @@ -101,11 +97,6 @@ EXPORT_SYMBOL(__up); /* - * Base address of ports for Intel style I/O. - */ -EXPORT_SYMBOL(mips_io_port_base); - -/* * Architecture specific stuff. */ #ifdef CONFIG_MIPS_JAZZ @@ -124,9 +115,6 @@ #include #include -int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); -int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); - #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif @@ -136,4 +124,3 @@ #endif EXPORT_SYMBOL(get_wchan); -EXPORT_SYMBOL(flush_tlb_page); diff -urN linux-2.4.18/arch/mips/kernel/old-irq.c linux-2.4.19-pre5/arch/mips/kernel/old-irq.c --- linux-2.4.18/arch/mips/kernel/old-irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/old-irq.c Sat Mar 30 22:55:26 2002 @@ -69,7 +69,7 @@ #define cached_21 (__byte(0,cached_irq_mask)) #define cached_A1 (__byte(1,cached_irq_mask)) -unsigned long spurious_count = 0; +volatile unsigned long irq_err_count; /* * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and @@ -403,3 +403,6 @@ /* i8259_init(); */ irq_setup(); } + +EXPORT_SYMBOL(free_irq); +EXPORT_SYMBOL(request_irq); diff -urN linux-2.4.18/arch/mips/kernel/old-time.c linux-2.4.19-pre5/arch/mips/kernel/old-time.c --- linux-2.4.18/arch/mips/kernel/old-time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/old-time.c Sat Mar 30 22:55:26 2002 @@ -89,8 +89,7 @@ :"r" (timerhi), "m" (timerlo), "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); + "r" (USECS_PER_JIFFY)); cached_quotient = quotient; } @@ -389,15 +388,19 @@ xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; } - /* As we return to user mode fire off the other CPU schedulers.. this is - basically because we don't yet share IRQ's around. This message is - rigged to be safe on the 386 - basically it's a hack, so don't look - closely for now.. */ + + /* + * As we return to user mode fire off the other CPU schedulers.. this + * is basically because we don't yet share IRQ's around. This message + * is rigged to be safe on the 386 - basically it's a hack, so don't + * look closely for now.. + */ /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ read_unlock (&xtime_lock); } @@ -442,10 +445,12 @@ void indy_r4k_timer_interrupt (struct pt_regs *regs) { - static const int INDY_R4K_TIMER_IRQ = 7; int cpu = smp_processor_id(); + int irq = 7; - r4k_timer_interrupt (INDY_R4K_TIMER_IRQ, NULL, regs); + irq_enter(cpu, irq); + r4k_timer_interrupt(irq, NULL, regs); + irq_exit(cpu, irq); if (softirq_pending(cpu)) do_softirq(); diff -urN linux-2.4.18/arch/mips/kernel/pci-dma.c linux-2.4.19-pre5/arch/mips/kernel/pci-dma.c --- linux-2.4.18/arch/mips/kernel/pci-dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/pci-dma.c Sat Mar 30 22:55:26 2002 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,7 @@ if (ret != NULL) { memset(ret, 0, size); -#ifndef CONFIG_COHERENT_IO +#ifdef CONFIG_NONCOHERENT_IO dma_cache_wback_inv((unsigned long) ret, size); ret = KSEG1ADDR(ret); #endif @@ -42,8 +43,11 @@ { unsigned long addr = (unsigned long) vaddr; -#ifndef CONFIG_COHERENT_IO +#ifdef CONFIG_NONCOHERENT_IO addr = KSEG0ADDR(addr); #endif free_pages(addr, get_order(size)); } + +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); diff -urN linux-2.4.18/arch/mips/kernel/pci_auto.c linux-2.4.19-pre5/arch/mips/kernel/pci_auto.c --- linux-2.4.18/arch/mips/kernel/pci_auto.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/pci_auto.c Sat Mar 30 22:55:26 2002 @@ -4,6 +4,7 @@ * Author: Matt Porter * * Copyright 2000, 2001 MontaVista Software Inc. + * Copyright 2001 Bradley D. LaRonde * * 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 @@ -19,6 +20,15 @@ * . change most int to u32. * * Further modified to include it as mips generic code, ppopov@mvista.com. + * + * 2001-10-26 Bradley D. LaRonde + * - Add a top_bus argument to the "early config" functions so that + * they can set a fake parent bus pointer to convince the underlying + * pci ops to use type 1 configuration for sub busses. + * - Set bridge base and limit registers correctly. + * - Align io and memory base properly before and after bridge setup. + * - Don't fall through to pci_setup_bars for bridge. + * - Reformat the debug output to look more like lspci's output. */ #include @@ -35,13 +45,49 @@ #define DBG(x...) #endif -/* These are used for config access before all the PCI probing has been done. */ -int early_read_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 *val); -int early_read_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 *val); -int early_read_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 *val); -int early_write_config_byte(struct pci_channel *hose, int bus, int dev_fn, int where, u8 val); -int early_write_config_word(struct pci_channel *hose, int bus, int dev_fn, int where, u16 val); -int early_write_config_dword(struct pci_channel *hose, int bus, int dev_fn, int where, u32 val); +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +static struct pci_dev *fake_pci_dev(struct pci_channel *hose, + int top_bus, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose->pci_ops; + + if(busnr != top_bus) + /* Fake a parent bus structure. */ + bus.parent = &bus; + else + bus.parent = NULL; + + return &dev; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_channel *hose, \ + int top_bus, int bus, int devfn, int offset, type value) \ +{ \ + return pci_##rw##_config_##size( \ + fake_pci_dev(hose, top_bus, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + +static struct resource *io_resource_inuse; +static struct resource *mem_resource_inuse; static u32 pciauto_lower_iospc; static u32 pciauto_upper_iospc; @@ -51,6 +97,7 @@ void __init pciauto_setup_bars(struct pci_channel *hose, + int top_bus, int current_bus, int pci_devfn) { @@ -60,17 +107,14 @@ u32 * lower_limit; int found_mem64 = 0; - DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", - current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); - for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) { /* Tickle the BAR and get the response */ - early_write_config_dword(hose, + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, bar, 0xffffffff); - early_read_config_dword(hose, + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, bar, @@ -80,12 +124,21 @@ if (!bar_response) continue; + /* + * Workaround for a BAR that doesn't use its upper word, + * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457). + * bdl + */ + if (!(bar_response & 0xffff0000)) + bar_response |= 0xffff0000; + +retry: /* Check the BAR type and set our address mask */ if (bar_response & PCI_BASE_ADDRESS_SPACE) { addr_mask = PCI_BASE_ADDRESS_IO_MASK; upper_limit = &pciauto_upper_iospc; lower_limit = &pciauto_lower_iospc; - DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + DBG(" I/O"); } else { if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) @@ -94,17 +147,45 @@ addr_mask = PCI_BASE_ADDRESS_MEM_MASK; upper_limit = &pciauto_upper_memspc; lower_limit = &pciauto_lower_memspc; - DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + DBG(" Mem"); } + /* Calculate requested size */ bar_size = ~(bar_response & addr_mask) + 1; /* Allocate a base address */ bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; + if ((bar_value + bar_size) > *upper_limit) { + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + if (io_resource_inuse->child) { + io_resource_inuse = + io_resource_inuse->child; + pciauto_lower_iospc = + io_resource_inuse->start; + pciauto_upper_iospc = + io_resource_inuse->end + 1; + goto retry; + } + + } else { + if (mem_resource_inuse->child) { + mem_resource_inuse = + mem_resource_inuse->child; + pciauto_lower_memspc = + mem_resource_inuse->start; + pciauto_upper_memspc = + mem_resource_inuse->end + 1; + goto retry; + } + } + DBG(" unavailable -- skipping\n"); + continue; + } + /* Write it out and update our limit */ - early_write_config_dword(hose, current_bus, pci_devfn, + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, bar, bar_value); *lower_limit = bar_value + bar_size; @@ -116,97 +197,99 @@ */ if (found_mem64) { bar += 4; - early_write_config_dword(hose, + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, bar, 0x00000000); } - bar_nr++; + DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size); - DBG("size=0x%x, address=0x%x\n", - bar_size, bar_value); + bar_nr++; } } void __init pciauto_prescan_setup_bridge(struct pci_channel *hose, + int top_bus, int current_bus, int pci_devfn, int sub_bus) { - int cmdstat; - /* Configure bus number registers */ - early_write_config_byte(hose, current_bus, pci_devfn, + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_PRIMARY_BUS, current_bus); - early_write_config_byte(hose, current_bus, pci_devfn, + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_SECONDARY_BUS, sub_bus + 1); - early_write_config_byte(hose, current_bus, pci_devfn, + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_SUBORDINATE_BUS, 0xff); - /* Round memory allocator to 1MB boundary */ - pciauto_upper_memspc &= ~(0x100000 - 1); + /* Align memory and I/O to 1MB and 4KB boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) + & ~(0x100000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) + & ~(0x1000 - 1); + + /* Set base (lower limit) of address range behind bridge. */ + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_MEMORY_BASE, pciauto_lower_memspc >> 16); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16); - /* Round I/O allocator to 4KB boundary */ - pciauto_upper_iospc &= ~(0x1000 - 1); - - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ - early_write_config_word(hose, current_bus, pci_devfn, PCI_MEMORY_LIMIT, - ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); - early_write_config_byte(hose, current_bus, pci_devfn, PCI_IO_LIMIT, - ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); - early_write_config_word(hose, current_bus, pci_devfn, - PCI_IO_LIMIT_UPPER16, - ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); - /* We don't support prefetchable memory for now, so disable */ - early_write_config_word(hose, current_bus, pci_devfn, - PCI_PREF_MEMORY_BASE, 0x1000); - early_write_config_word(hose, current_bus, pci_devfn, - PCI_PREF_MEMORY_LIMIT, 0x1000); - - /* Enable memory and I/O accesses, enable bus master */ - early_read_config_dword(hose, current_bus, pci_devfn, PCI_COMMAND, - &cmdstat); - early_write_config_dword(hose, current_bus, pci_devfn, PCI_COMMAND, - cmdstat | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_PREF_MEMORY_BASE, 0); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_PREF_MEMORY_LIMIT, 0); } void __init pciauto_postscan_setup_bridge(struct pci_channel *hose, + int top_bus, int current_bus, int pci_devfn, int sub_bus) { + u32 temp; + /* Configure bus number registers */ - early_write_config_byte(hose, current_bus, pci_devfn, + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_SUBORDINATE_BUS, sub_bus); - /* Round memory allocator to 1MB boundary */ - pciauto_upper_memspc &= ~(0x100000 - 1); - early_write_config_word(hose, current_bus, pci_devfn, PCI_MEMORY_BASE, - pciauto_upper_memspc >> 16); - - /* Round I/O allocator to 4KB boundary */ - pciauto_upper_iospc &= ~(0x1000 - 1); - early_write_config_byte(hose, current_bus, pci_devfn, PCI_IO_BASE, - (pciauto_upper_iospc & 0x0000f000) >> 8); - early_write_config_word(hose, current_bus, pci_devfn, - PCI_IO_BASE_UPPER16, pciauto_upper_iospc >> 16); + /* Set upper limit of address range behind bridge. */ + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16); + + /* Align memory and I/O to 1MB and 4KB boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) + & ~(0x100000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) + & ~(0x1000 - 1); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, &temp); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY + | PCI_COMMAND_MASTER); } #define PCIAUTO_IDE_MODE_MASK 0x05 int __init -pciauto_bus_scan(struct pci_channel *hose, int current_bus) +pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) { int sub_bus; u32 pci_devfn, pci_class, cmdstat, found_multi=0; - unsigned short vid; + unsigned short vid, did; unsigned char header_type; int devfn_start = 0; int devfn_stop = 0xff; @@ -223,54 +306,70 @@ if (PCI_FUNC(pci_devfn) && !found_multi) continue; - early_read_config_byte(hose, current_bus, pci_devfn, + early_read_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_VENDOR_ID, &vid); + + if (vid == 0xffff) continue; + + early_read_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_HEADER_TYPE, &header_type); if (!PCI_FUNC(pci_devfn)) found_multi = header_type & 0x80; - early_read_config_word(hose, current_bus, pci_devfn, - PCI_VENDOR_ID, &vid); - - if (vid == 0xffff) continue; + early_read_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_DEVICE_ID, &did); - early_read_config_dword(hose, current_bus, pci_devfn, + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, PCI_CLASS_REVISION, &pci_class); + + DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn), + pci_class >> 16, vid, did); + if (pci_class & 0xff) + DBG(" (rev %.2x)", pci_class & 0xff); + DBG("\n"); + if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { - DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); - pciauto_prescan_setup_bridge(hose, current_bus, + DBG(" Bridge: primary=%.2x, secondary=%.2x\n", + current_bus, sub_bus + 1); + pciauto_prescan_setup_bridge(hose, top_bus, current_bus, pci_devfn, sub_bus); - sub_bus = pciauto_bus_scan(hose, sub_bus+1); - pciauto_postscan_setup_bridge(hose, current_bus, + DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", + sub_bus + 1, + pciauto_lower_iospc, pciauto_lower_memspc); + sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); + DBG("Back to bus %.2x\n", current_bus); + pciauto_postscan_setup_bridge(hose, top_bus, current_bus, pci_devfn, sub_bus); - + continue; } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { unsigned char prg_iface; - early_read_config_byte(hose, current_bus, pci_devfn, - PCI_CLASS_PROG, &prg_iface); + early_read_config_byte(hose, top_bus, current_bus, + pci_devfn, PCI_CLASS_PROG, &prg_iface); if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { - DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + DBG("Skipping legacy mode IDE controller\n"); continue; } } - /* + /* * Found a peripheral, enable some standard * settings */ - early_read_config_dword(hose, current_bus, pci_devfn, + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, PCI_COMMAND, &cmdstat); - early_write_config_dword(hose, current_bus, pci_devfn, + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, PCI_COMMAND, cmdstat | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - early_write_config_byte(hose, current_bus, pci_devfn, + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, PCI_LATENCY_TIMER, 0x80); /* Allocate PCI I/O and/or memory space */ - pciauto_setup_bars(hose, current_bus, pci_devfn); + pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn); } return sub_bus; } @@ -279,45 +378,17 @@ pciauto_assign_resources(int busno, struct pci_channel *hose) { /* setup resource limits */ - pciauto_lower_iospc = hose->io_resource->start; - pciauto_upper_iospc = hose->io_resource->end + 1; - pciauto_lower_memspc = hose->mem_resource->start; - pciauto_upper_memspc = hose->mem_resource->end + 1; - - return pciauto_bus_scan(hose, busno); -} - - -/* - * These functions are used early on before PCI scanning is done - * and all of the pci_dev and pci_bus structures have been created. - */ -static struct pci_dev *fake_pci_dev(struct pci_channel *hose, int busnr, - int devfn) -{ - static struct pci_dev dev; - static struct pci_bus bus; - - dev.bus = &bus; - dev.sysdata = hose; - dev.devfn = devfn; - bus.number = busnr; - bus.ops = hose->pci_ops; + io_resource_inuse = hose->io_resource; + mem_resource_inuse = hose->mem_resource; - return &dev; -} + pciauto_lower_iospc = io_resource_inuse->start; + pciauto_upper_iospc = io_resource_inuse->end + 1; + pciauto_lower_memspc = mem_resource_inuse->start; + pciauto_upper_memspc = mem_resource_inuse->end + 1; + DBG("Autoconfig PCI channel 0x%p\n", hose); + DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n", + busno, pciauto_lower_iospc, pciauto_upper_iospc, + pciauto_lower_memspc, pciauto_upper_memspc); -#define EARLY_PCI_OP(rw, size, type) \ -int early_##rw##_config_##size(struct pci_channel *hose, int bus, \ - int devfn, int offset, type value) \ -{ \ - return pci_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ - offset, value); \ + return pciauto_bus_scan(hose, busno, busno); } - -EARLY_PCI_OP(read, byte, u8 *) -EARLY_PCI_OP(read, word, u16 *) -EARLY_PCI_OP(read, dword, u32 *) -EARLY_PCI_OP(write, byte, u8) -EARLY_PCI_OP(write, word, u16) -EARLY_PCI_OP(write, dword, u32) diff -urN linux-2.4.18/arch/mips/kernel/proc.c linux-2.4.19-pre5/arch/mips/kernel/proc.c --- linux-2.4.18/arch/mips/kernel/proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/proc.c Sat Mar 30 22:55:26 2002 @@ -8,102 +8,138 @@ #include #include #include +#include #include #include #include #include #include -extern unsigned long unaligned_instructions; unsigned int vced_count, vcei_count; + #ifndef CONFIG_CPU_HAS_LLSC unsigned long ll_ops, sc_ops; #endif -/* - * BUFFER is PAGE_SIZE bytes long. - * - * Currently /proc/cpuinfo is being abused to print data about the - * number of date/instruction cacheflushes. - */ -int get_cpuinfo(char *buffer) +static const char *cpu_name[] = { + [CPU_UNKNOWN] "unknown", + [CPU_R2000] "R2000", + [CPU_R3000] "R3000", + [CPU_R3000A] "R3000A", + [CPU_R3041] "R3041", + [CPU_R3051] "R3051", + [CPU_R3052] "R3052", + [CPU_R3081] "R3081", + [CPU_R3081E] "R3081E", + [CPU_R4000PC] "R4000PC", + [CPU_R4000SC] "R4000SC", + [CPU_R4000MC] "R4000MC", + [CPU_R4200] "R4200", + [CPU_R4400PC] "R4400PC", + [CPU_R4400SC] "R4400SC", + [CPU_R4400MC] "R4400MC", + [CPU_R4600] "R4600", + [CPU_R6000] "R6000", + [CPU_R6000A] "R6000A", + [CPU_R8000] "R8000", + [CPU_R10000] "R10000", + [CPU_R4300] "R4300", + [CPU_R4650] "R4650", + [CPU_R4700] "R4700", + [CPU_R5000] "R5000", + [CPU_R5000A] "R5000A", + [CPU_R4640] "R4640", + [CPU_NEVADA] "Nevada", + [CPU_RM7000] "RM7000", + [CPU_R5432] "R5432", + [CPU_4KC] "MIPS 4Kc", + [CPU_5KC] "MIPS 5Kc", + [CPU_R4310] "R4310", + [CPU_SB1] "SiByte SB1", + [CPU_TX3912] "TX3912", + [CPU_TX3922] "TX3922", + [CPU_TX3927] "TX3927", + [CPU_AU1000] "Au1000", + [CPU_AU1500] "Au1500", + [CPU_4KEC] "MIPS 4KEc", + [CPU_4KSC] "MIPS 4KSc", + [CPU_VR41XX] "NEC Vr41xx", + [CPU_R5500] "R5500", + [CPU_TX49XX] "TX49xx", + [CPU_TX39XX] "TX39xx" +}; + + +static int show_cpuinfo(struct seq_file *m, void *v) { + unsigned int version = mips_cpu.processor_id; + unsigned int fp_vers = mips_cpu.fpu_id; + unsigned long n = (unsigned long) v - 1; char fmt [64]; - const char *cpu_name[] = CPU_NAMES; - const char *mach_group_names[] = GROUP_NAMES; - const char *mach_unknown_names[] = GROUP_UNKNOWN_NAMES; - const char *mach_jazz_names[] = GROUP_JAZZ_NAMES; - const char *mach_dec_names[] = GROUP_DEC_NAMES; - const char *mach_arc_names[] = GROUP_ARC_NAMES; - const char *mach_sni_rm_names[] = GROUP_SNI_RM_NAMES; - const char *mach_acn_names[] = GROUP_ACN_NAMES; - const char *mach_sgi_names[] = GROUP_SGI_NAMES; - const char *mach_cobalt_names[] = GROUP_COBALT_NAMES; - const char *mach_nec_ddb_names[] = GROUP_NEC_DDB_NAMES; - const char *mach_baget_names[] = GROUP_BAGET_NAMES; - const char *mach_cosine_names[] = GROUP_COSINE_NAMES; - const char *mach_galileo_names[] = GROUP_GALILEO_NAMES; - const char *mach_momenco_names[] = GROUP_MOMENCO_NAMES; - const char *mach_ite_names[] = GROUP_ITE_NAMES; - const char *mach_philips_names[] = GROUP_PHILIPS_NAMES; - const char *mach_globespan_names[] = GROUP_GLOBESPAN_NAMES; - const char *mach_sibyte_names[] = GROUP_SIBYTE_NAMES; - const char *mach_toshiba_names[] = GROUP_TOSHIBA_NAMES; - const char *mach_alchemy_names[] = GROUP_ALCHEMY_NAMES; - const char **mach_group_to_name[] = { mach_unknown_names, - mach_jazz_names, mach_dec_names, mach_arc_names, - mach_sni_rm_names, mach_acn_names, mach_sgi_names, - mach_cobalt_names, mach_nec_ddb_names, mach_baget_names, - mach_cosine_names, mach_galileo_names, mach_momenco_names, - mach_ite_names, mach_philips_names, mach_globespan_names, - mach_sibyte_names, mach_toshiba_names, mach_alchemy_names}; - unsigned int version = read_32bit_cp0_register(CP0_PRID); - int len; - - len = sprintf(buffer, "cpu\t\t\t: MIPS\n"); - len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", - cpu_name[mips_cpu.cputype <= CPU_LAST ? - mips_cpu.cputype : CPU_UNKNOWN], - (version >> 4) & 0x0f, version & 0x0f); - len += sprintf(buffer + len, "system type\t\t: %s %s\n", - mach_group_names[mips_machgroup], - mach_group_to_name[mips_machgroup][mips_machtype]); - len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100); -#if defined (__MIPSEB__) - len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); -#endif -#if defined (__MIPSEL__) - len += sprintf(buffer + len, "byteorder\t\t: little endian\n"); +#ifdef CONFIG_SMP + if (!(cpu_online_map & (1<> 4) & 0x0f, version & 0x0f, + (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); + seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); + seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); + seq_printf(m, "microsecond timers\t: %s\n", + (mips_cpu.options & MIPS_CPU_COUNTER) ? "yes" : "no"); + seq_printf(m, "tlb_entries\t\t: %d\n", mips_cpu.tlbsize); + seq_printf(m, "extra interrupt vector\t: %s\n", + (mips_cpu.options & MIPS_CPU_DIVEC) ? "yes" : "no"); + seq_printf(m, "hardware watchpoint\t: %s\n", + watch_available ? "yes" : "no"); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", (mips_cpu.options & MIPS_CPU_VCE) ? "%d" : "not available"); - len += sprintf(buffer + len, fmt, 'D', vced_count); - len += sprintf(buffer + len, fmt, 'I', vcei_count); + seq_printf(m, fmt, 'D', vced_count); + seq_printf(m, fmt, 'I', vcei_count); #ifndef CONFIG_CPU_HAS_LLSC - len += sprintf(buffer + len, "ll emulations\t\t: %lu\n", - ll_ops); - len += sprintf(buffer + len, "sc emulations\t\t: %lu\n", - sc_ops); + seq_printf(m, "ll emulations\t\t: %lu\n", ll_ops); + seq_printf(m, "sc emulations\t\t: %lu\n", sc_ops); #endif - return len; + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; + + return i < NR_CPUS ? (void *) (i + 1) : NULL; } -void init_irq_proc(void) +static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - /* Nothing, for now. */ + ++*pos; + return c_start(m, pos); } + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; diff -urN linux-2.4.18/arch/mips/kernel/process.c linux-2.4.19-pre5/arch/mips/kernel/process.c --- linux-2.4.18/arch/mips/kernel/process.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/process.c Sat Mar 30 22:55:26 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,7 @@ #include #include -void cpu_idle(void) +ATTRIB_NORET void cpu_idle(void) { /* endless idle loop with no priority at all */ current->nice = 20; @@ -55,8 +56,8 @@ void exit_thread(void) { /* Forget lazy fpu state */ - if (last_task_used_math == current) { - set_cp0_status(ST0_CU1); + if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) { + __enable_fpu(); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -65,8 +66,8 @@ void flush_thread(void) { /* Forget lazy fpu state */ - if (last_task_used_math == current) { - set_cp0_status(ST0_CU1); + if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) { + __enable_fpu(); __asm__ __volatile__("cfc1\t$0,$31"); last_task_used_math = NULL; } @@ -84,7 +85,7 @@ if (last_task_used_math == current) if (mips_cpu.options & MIPS_CPU_FPU) { - set_cp0_status(ST0_CU1); + __enable_fpu(); save_fp(p); } /* set up new TSS. */ @@ -174,16 +175,15 @@ "1: addiu $sp,32 \n" " move %0,$2 \n" ".set reorder" - :"=r" (retval) - :"i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "r" (fn), - "r" (flags | CLONE_VM) + : "=r" (retval) + : "i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), + "r" (flags | CLONE_VM) /* * The called subroutine might have destroyed any of the * at, result, argument or temporary registers ... */ - :"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", - "$9","$10","$11","$12","$13","$14","$15","$24","$25"); + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$9","$10","$11","$12","$13","$14","$15","$24","$25"); return retval; } diff -urN linux-2.4.18/arch/mips/kernel/ptrace.c linux-2.4.19-pre5/arch/mips/kernel/ptrace.c --- linux-2.4.18/arch/mips/kernel/ptrace.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/ptrace.c Sat Mar 30 22:55:26 2002 @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -42,7 +41,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - int res; + int ret; extern void save_fp(struct task_struct *); lock_kernel(); @@ -54,15 +53,15 @@ if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { - res = -EPERM; + ret = -EPERM; goto out; } /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; - res = 0; + ret = 0; goto out; } - res = -ESRCH; + ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) @@ -71,23 +70,19 @@ if (!child) goto out; - res = -EPERM; + ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out; if (request == PTRACE_ATTACH) { - res = ptrace_attach(child); + ret = ptrace_attach(child); goto out_tsk; } - res = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; + switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { @@ -95,10 +90,10 @@ int copied; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - res = -EIO; + ret = -EIO; if (copied != sizeof(tmp)) break; - res = put_user(tmp,(unsigned long *) data); + ret = put_user(tmp,(unsigned long *) data); goto out; } @@ -126,9 +121,9 @@ child->thread.fpu.soft.regs; } else if (last_task_used_math == child) { - enable_cp1(); + __enable_fpu(); save_fp(child); - disable_cp1(); + __disable_fpu(); last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; } @@ -174,33 +169,37 @@ case FPC_EIR: { /* implementation / version register */ unsigned int flags; + if (!(mips_cpu.options & MIPS_CPU_FPU)) { + break; + } + __save_flags(flags); - enable_cp1(); + __enable_fpu(); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); __restore_flags(flags); break; } default: tmp = 0; - res = -EIO; + ret = -EIO; goto out; } - res = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, (unsigned long *) data); goto out; } case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - res = 0; + ret = 0; if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; - res = -EIO; + ret = -EIO; goto out; case PTRACE_POKEUSR: { struct pt_regs *regs; - res = 0; + ret = 0; regs = (struct pt_regs *) ((unsigned long) child + KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); @@ -217,9 +216,9 @@ fregs = (unsigned long long *) child->thread.fpu.soft.regs; } else { - enable_cp1(); + __enable_fpu(); save_fp(child); - disable_cp1(); + __disable_fpu(); last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; } @@ -266,7 +265,7 @@ break; default: /* The rest are not allowed. */ - res = -EIO; + ret = -EIO; break; } break; @@ -274,7 +273,7 @@ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ - res = -EIO; + ret = -EIO; if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) @@ -283,7 +282,7 @@ child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process(child); - res = 0; + ret = 0; break; } @@ -293,7 +292,7 @@ * exit. */ case PTRACE_KILL: - res = 0; + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; @@ -301,7 +300,7 @@ break; case PTRACE_DETACH: /* detach a process that was attached. */ - res = ptrace_detach(child, data); + ret = ptrace_detach(child, data); break; case PTRACE_SETOPTIONS: @@ -309,18 +308,18 @@ child->ptrace |= PT_TRACESYSGOOD; else child->ptrace &= ~PT_TRACESYSGOOD; - res = 0; + ret = 0; break; default: - res = -EIO; + ret = -EIO; goto out; } out_tsk: free_task_struct(child); out: unlock_kernel(); - return res; + return ret; } asmlinkage void syscall_trace(void) diff -urN linux-2.4.18/arch/mips/kernel/r2300_misc.S linux-2.4.19-pre5/arch/mips/kernel/r2300_misc.S --- linux-2.4.18/arch/mips/kernel/r2300_misc.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/r2300_misc.S Thu Jan 1 01:00:00 1970 @@ -1,199 +0,0 @@ -/* $Id: r2300_misc.S,v 1.8 1999/12/08 22:05:10 harald Exp $ - * misc.S: Misc. exception handling code for R3000/R2000. - * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse - * - * Multi-CPU abstraction reworking: - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * Further modifications to make this work: - * Copyright (c) 1998 Harald Koerfgen - * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - .text - .set mips1 - .set noreorder - -#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */ - - /* ABUSE of CPP macros 101. */ - - /* After this macro runs, the pte faulted on is - * in register PTE, a ptr into the table in which - * the pte belongs is in PTR. - */ -#define LOAD_PTE(pte, ptr) \ - mfc0 pte, CP0_BADVADDR; \ - lw ptr, current_pgd; \ - srl pte, pte, 22; \ - sll pte, pte, 2; \ - addu ptr, ptr, pte; \ - mfc0 pte, CP0_CONTEXT; \ - lw ptr, (ptr); \ - andi pte, pte, 0xffc; \ - addu ptr, ptr, pte; \ - lw pte, (ptr); \ - nop; - - /* This places the even/odd pte pair in the page - * table at PTR into ENTRYLO0 and ENTRYLO1 using - * TMP as a scratch register. - */ -#define PTE_RELOAD(ptr) \ - lw ptr, (ptr) ; \ - nop ; \ - mtc0 ptr, CP0_ENTRYLO0; \ - nop; - -#define DO_FAULT(write) \ - .set noat; \ - .set macro; \ - SAVE_ALL; \ - mfc0 a2, CP0_BADVADDR; \ - STI; \ - .set at; \ - move a0, sp; \ - jal do_page_fault; \ - li a1, write; \ - j ret_from_sys_call; \ - nop; \ - .set noat; \ - .set nomacro; - - /* Check is PTE is present, if not then jump to LABEL. - * PTR points to the page table where this PTE is located, - * when the macro is done executing PTE will be restored - * with it's original value. - */ -#define PTE_PRESENT(pte, ptr, label) \ - andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ - xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ - bnez pte, label; \ - .set push; \ - .set reorder; \ - lw pte, (ptr); \ - .set pop; - - /* Make PTE valid, store result in PTR. */ -#define PTE_MAKEVALID(pte, ptr) \ - ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ - sw pte, (ptr); - - /* Check if PTE can be written to, if not branch to LABEL. - * Regardless restore PTE with value from PTR when done. - */ -#define PTE_WRITABLE(pte, ptr, label) \ - andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ - xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ - bnez pte, label; \ - .set push; \ - .set reorder; \ - lw pte, (ptr); \ - .set pop; - - - /* Make PTE writable, update software status bits as well, - * then store at PTR. - */ -#define PTE_MAKEWRITE(pte, ptr) \ - ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ - _PAGE_VALID | _PAGE_DIRTY); \ - sw pte, (ptr); - -/* - * The index register may have the probe fail bit set, - * because we would trap on access kseg2, i.e. without refill. - */ -#define TLB_WRITE(reg) \ - mfc0 reg, CP0_INDEX; \ - nop; \ - bltz reg, 1f; \ - nop; \ - tlbwi; \ - j 2f; \ - nop; \ -1: tlbwr; \ -2: - -#define RET(reg) \ - mfc0 reg, CP0_EPC; \ - nop; \ - jr reg; \ - rfe - - .set noreorder - - .align 5 -NESTED(handle_tlbl, PT_SIZE, sp) - .set noat - -#ifndef NOTLB_OPTIMIZE - /* Test present bit in entry. */ - LOAD_PTE(k0, k1) - tlbp - PTE_PRESENT(k0, k1, nopage_tlbl) - PTE_MAKEVALID(k0, k1) - PTE_RELOAD(k1) - TLB_WRITE(k0) - RET(k0) -nopage_tlbl: -#endif - - DO_FAULT(0) -END(handle_tlbl) - -NESTED(handle_tlbs, PT_SIZE, sp) - .set noat - -#ifndef NOTLB_OPTIMIZE - LOAD_PTE(k0, k1) - tlbp # find faulting entry - PTE_WRITABLE(k0, k1, nopage_tlbs) - PTE_MAKEWRITE(k0, k1) - PTE_RELOAD(k1) - TLB_WRITE(k0) - RET(k0) -nopage_tlbs: -#endif - - DO_FAULT(1) -END(handle_tlbs) - - .align 5 -NESTED(handle_mod, PT_SIZE, sp) - .set noat -#ifndef NOTLB_OPTIMIZE - LOAD_PTE(k0, k1) - tlbp # find faulting entry - andi k0, k0, _PAGE_WRITE - beqz k0, nowrite_mod - .set push - .set reorder - lw k0, (k1) - .set pop - - /* Present and writable bits set, set accessed and dirty bits. */ - PTE_MAKEWRITE(k0, k1) - - /* Now reload the entry into the tlb. */ - PTE_RELOAD(k1) - tlbwi - RET(k0) -#endif - -nowrite_mod: - DO_FAULT(1) -END(handle_mod) diff -urN linux-2.4.18/arch/mips/kernel/r2300_switch.S linux-2.4.19-pre5/arch/mips/kernel/r2300_switch.S --- linux-2.4.18/arch/mips/kernel/r2300_switch.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/r2300_switch.S Sat Mar 30 22:55:26 2002 @@ -11,7 +11,6 @@ * Copyright (c) 1998-2000 Harald Koerfgen */ #include -#include #include #include #include diff -urN linux-2.4.18/arch/mips/kernel/r4k_misc.S linux-2.4.19-pre5/arch/mips/kernel/r4k_misc.S --- linux-2.4.18/arch/mips/kernel/r4k_misc.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/r4k_misc.S Thu Jan 1 01:00:00 1970 @@ -1,236 +0,0 @@ -/* $Id: r4k_misc.S,v 1.8 1999/10/09 00:00:58 ralf Exp $ - * - * r4k_misc.S: Misc. exception handling code for r4k. - * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse - * - * Multi-cpu abstraction and reworking: - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -/************************************************************************** - * 14 Nov, 2000. - * Made support for MIPS32 CPUs. - * - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - *************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */ - - /* ABUSE of CPP macros 101. */ - - /* After this macro runs, the pte faulted on is - * in register PTE, a ptr into the table in which - * the pte belongs is in PTR. - */ - -#ifdef CONFIG_SMP -#define GET_PGD(scratch, ptr) \ - mfc0 ptr, CP0_CONTEXT; \ - la scratch, current_pgd;\ - srl ptr, 23; \ - sll ptr, 2; \ - addu ptr, scratch, ptr; \ - lw ptr, (ptr); -#else -#define GET_PGD(scratch, ptr) \ - lw ptr, current_pgd; -#endif - - -#define LOAD_PTE(pte, ptr) \ - GET_PGD(pte, ptr) \ - mfc0 pte, CP0_BADVADDR; \ - srl pte, pte, 22; \ - sll pte, pte, 2; \ - addu ptr, ptr, pte; \ - mfc0 pte, CP0_BADVADDR; \ - lw ptr, (ptr); \ - srl pte, pte, 10; \ - and pte, pte, 0xffc; \ - addu ptr, ptr, pte; \ - lw pte, (ptr); - - /* This places the even/odd pte pair in the page - * table at PTR into ENTRYLO0 and ENTRYLO1 using - * TMP as a scratch register. - */ -#define PTE_RELOAD(ptr, tmp) \ - ori ptr, ptr, 0x4; \ - xori ptr, ptr, 0x4; \ - lw tmp, 4(ptr); \ - lw ptr, 0(ptr); \ - srl tmp, tmp, 6; \ - mtc0 tmp, CP0_ENTRYLO1; \ - srl ptr, ptr, 6; \ - mtc0 ptr, CP0_ENTRYLO0; - -#define DO_FAULT(write) \ - .set noat; \ - SAVE_ALL; \ - mfc0 a2, CP0_BADVADDR; \ - STI; \ - .set at; \ - move a0, sp; \ - jal do_page_fault; \ - li a1, write; \ - j ret_from_sys_call; \ - nop; \ - .set noat; - - /* Check is PTE is present, if not then jump to LABEL. - * PTR points to the page table where this PTE is located, - * when the macro is done executing PTE will be restored - * with it's original value. - */ -#define PTE_PRESENT(pte, ptr, label) \ - andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ - xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ - bnez pte, label; \ - lw pte, (ptr); - - /* Make PTE valid, store result in PTR. */ -#define PTE_MAKEVALID(pte, ptr) \ - ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ - sw pte, (ptr); - - /* Check if PTE can be written to, if not branch to LABEL. - * Regardless restore PTE with value from PTR when done. - */ -#define PTE_WRITABLE(pte, ptr, label) \ - andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ - xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ - bnez pte, label; \ - lw pte, (ptr); - - /* Make PTE writable, update software status bits as well, - * then store at PTR. - */ -#define PTE_MAKEWRITE(pte, ptr) \ - ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ - _PAGE_VALID | _PAGE_DIRTY); \ - sw pte, (ptr); - - .set noreorder - -/* - * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0: - * 2. A timing hazard exists for the TLBP instruction. - * - * stalling_instruction - * TLBP - * - * The JTLB is being read for the TLBP throughout the stall generated by the - * previous instruction. This is not really correct as the stalling instruction - * can modify the address used to access the JTLB. The failure symptom is that - * the TLBP instruction will use an address created for the stalling instruction - * and not the address held in C0_ENHI and thus report the wrong results. - * - * The software work-around is to not allow the instruction preceding the TLBP - * to stall - make it an NOP or some other instruction guaranteed not to stall. - * - * Errata 2 will not be fixed. This errata is also on the R5000. - * - * As if we MIPS hackers wouldn't know how to nop pipelines happy ... - */ -#define R5K_HAZARD nop - - /* - * Note for many R4k variants tlb probes cannot be executed out - * of the instruction cache else you get bogus results. - */ - .align 5 - NESTED(handle_tlbl, PT_SIZE, sp) - .set noat -invalid_tlbl: -#ifndef NOTLB_OPTIMIZE - /* Test present bit in entry. */ - LOAD_PTE(k0, k1) - R5K_HAZARD - tlbp - PTE_PRESENT(k0, k1, nopage_tlbl) - PTE_MAKEVALID(k0, k1) - PTE_RELOAD(k1, k0) - nop - b 1f - tlbwi -1: - nop - .set mips3 - eret - .set mips0 -#endif - -nopage_tlbl: - DO_FAULT(0) - END(handle_tlbl) - - .align 5 - NESTED(handle_tlbs, PT_SIZE, sp) - .set noat -#ifndef NOTLB_OPTIMIZE - LOAD_PTE(k0, k1) - R5K_HAZARD - tlbp # find faulting entry - PTE_WRITABLE(k0, k1, nopage_tlbs) - PTE_MAKEWRITE(k0, k1) - PTE_RELOAD(k1, k0) - nop - b 1f - tlbwi -1: - nop - .set mips3 - eret - .set mips0 -#endif - -nopage_tlbs: - DO_FAULT(1) - END(handle_tlbs) - - .align 5 - NESTED(handle_mod, PT_SIZE, sp) - .set noat -#ifndef NOTLB_OPTIMIZE - LOAD_PTE(k0, k1) - R5K_HAZARD - tlbp # find faulting entry - andi k0, k0, _PAGE_WRITE - beqz k0, nowrite_mod - lw k0, (k1) - - /* Present and writable bits set, set accessed and dirty bits. */ - PTE_MAKEWRITE(k0, k1) -#if 0 - ori k0, k0, (_PAGE_ACCESSED | _PAGE_DIRTY) - sw k0, (k1) -#endif - - /* Now reload the entry into the tlb. */ - PTE_RELOAD(k1, k0) - nop - b 1f - tlbwi -1: - nop - .set mips3 - eret - .set mips0 -#endif - -nowrite_mod: - DO_FAULT(1) - END(handle_mod) diff -urN linux-2.4.18/arch/mips/kernel/r4k_switch.S linux-2.4.19-pre5/arch/mips/kernel/r4k_switch.S --- linux-2.4.18/arch/mips/kernel/r4k_switch.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/r4k_switch.S Sat Mar 30 22:55:26 2002 @@ -12,7 +12,6 @@ */ #include #include -#include #include #include #include diff -urN linux-2.4.18/arch/mips/kernel/scall_o32.S linux-2.4.19-pre5/arch/mips/kernel/scall_o32.S --- linux-2.4.18/arch/mips/kernel/scall_o32.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/scall_o32.S Sat Mar 30 22:55:26 2002 @@ -3,7 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1997, 1998, 1999, 2000 by Ralf Baechle + * Copyright (C) 1997, 1998, 1999, 2000, 2001 by Ralf Baechle + * Copyright (C) 2001 MIPS Technologies, Inc. */ #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include /* This duplicates the definition from */ @@ -86,13 +88,13 @@ ori t0, t0, 1 mtc0 t0, CP0_STATUS + SAVE_STATIC move a0, zero move a1, sp jal do_signal b restore_all o32_reschedule: - SAVE_STATIC jal schedule b o32_ret_from_sys_call @@ -192,3 +194,80 @@ sw t0, PT_R7(sp) j ret_from_sys_call END(handle_sys) + + LEAF(mips_atomic_set) + andi v0, a1, 3 # must be word aligned + bnez v0, bad_alignment + + lw v1, THREAD_CURDS($28) # in legal address range? + addiu a0, a1, 4 + or a0, a0, a1 + and a0, a0, v1 + bltz a0, bad_address + +#ifdef CONFIG_CPU_HAS_LLSC + /* Ok, this is the ll/sc case. World is sane :-) */ +1: ll v0, (a1) + move a0, a2 +2: sc a0, (a1) + beqz a0, 1b + + .section __ex_table,"a" + PTR 1b, bad_stack + PTR 2b, bad_stack + .previous +#else + sw a1, 16(sp) + sw a2, 20(sp) + + move a0, sp + move a2, a1 + li a1, 1 + jal do_page_fault + + lw a1, 16(sp) + lw a2, 20(sp) + + /* + * At this point the page should be readable and writable unless + * there was no more memory available. + */ +1: lw v0, (a1) +2: sw a2, (a1) + + .section __ex_table,"a" + PTR 1b, no_mem + PTR 2b, no_mem + .previous +#endif + + sw v0, PT_R2(sp) # result +1: + + /* Success, so skip usual error handling garbage. */ + lw t0, TASK_PTRACE($28) # syscall tracing enabled? + andi t0, PT_TRACESYS + bnez t0, 1f + b o32_ret_from_sys_call + +1: SAVE_STATIC + jal syscall_trace + li a3, 0 # success + j ret_from_sys_call + +no_mem: li v0, -ENOMEM + jr ra + +bad_address: + li v0, -EFAULT + jr ra + +bad_alignment: + li v0, -EINVAL + jr ra + END(mips_atomic_set) + + LEAF(sys_sysmips) + beq a0, MIPS_ATOMIC_SET, mips_atomic_set + j _sys_sysmips + END(sys_sysmips) diff -urN linux-2.4.18/arch/mips/kernel/setup.c linux-2.4.19-pre5/arch/mips/kernel/setup.c --- linux-2.4.18/arch/mips/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/setup.c Sat Mar 30 22:55:26 2002 @@ -4,9 +4,10 @@ * for more details. * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Ralf Baechle + * Copyright (C) 1995 Waldorf Electronics + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Ralf Baechle * Copyright (C) 1996 Stoned Elipot - * Copyright (C) 2000 Maciej W. Rozycki + * Copyright (C) 2000, 2001 Maciej W. Rozycki */ #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -41,8 +43,9 @@ #include #endif - -struct mips_cpuinfo boot_cpu_data = { 0, NULL, NULL, 0 }; +#ifndef CONFIG_SMP +struct cpuinfo_mips cpu_data[1]; +#endif /* * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, @@ -95,21 +98,24 @@ unsigned char aux_device_present; extern char _ftext, _etext, _fdata, _edata, _end; -static char command_line[COMMAND_LINE_SIZE]; - char saved_command_line[COMMAND_LINE_SIZE]; -extern char arcs_cmdline[COMMAND_LINE_SIZE]; +static char command_line[CL_SIZE]; + char saved_command_line[CL_SIZE]; +extern char arcs_cmdline[CL_SIZE]; /* * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -unsigned long mips_io_port_base; +const unsigned long mips_io_port_base = -1; +EXPORT_SYMBOL(mips_io_port_base); + /* * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped * for the processor. */ unsigned long isa_slot_offset; +EXPORT_SYMBOL(isa_slot_offset); extern void sgi_sysinit(void); extern void SetUpBootInfo(void); @@ -120,6 +126,44 @@ static struct resource code_resource = { "Kernel code" }; static struct resource data_resource = { "Kernel data" }; +static inline void check_wait(void) +{ + printk("Checking for 'wait' instruction... "); + switch(mips_cpu.cputype) { + case CPU_R3081: + case CPU_R3081E: + cpu_wait = r3081_wait; + printk(" available.\n"); + break; + case CPU_TX3927: + case CPU_TX39XX: + cpu_wait = r39xx_wait; + printk(" available.\n"); + break; + case CPU_R4200: +/* case CPU_R4300: */ + case CPU_R4600: + case CPU_R4640: + case CPU_R4650: + case CPU_R4700: + case CPU_R5000: + case CPU_NEVADA: + case CPU_RM7000: + case CPU_TX49XX: + cpu_wait = r4k_wait; + printk(" available.\n"); + break; + default: + printk(" unavailable.\n"); + break; + } +} + +void __init check_bugs(void) +{ + check_wait(); +} + /* * Probe whether cpu has config register by trying to play with * alternate cache bit and see whether it matters. @@ -142,9 +186,34 @@ #endif } +/* + * Get the FPU Implementation/Revision. + */ +static inline unsigned long cpu_get_fpu_id(void) +{ + unsigned long tmp, fpu_id; + + tmp = read_32bit_cp0_register(CP0_STATUS); + __enable_fpu(); + fpu_id = read_32bit_cp1_register(CP1_REVISION); + write_32bit_cp0_register(CP0_STATUS, tmp); + return fpu_id; +} + +/* + * Check the CPU has an FPU the official way. + */ +static inline int cpu_has_fpu(void) +{ + return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE); +} + /* declaration of the global struct */ -struct mips_cpu mips_cpu = {PRID_IMP_UNKNOWN, CPU_UNKNOWN, 0, 0, 0, - {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; +struct mips_cpu mips_cpu = { + processor_id: PRID_IMP_UNKNOWN, + fpu_id: FPIR_IMP_NONE, + cputype: CPU_UNKNOWN +}; /* Shortcut for assembler access to mips_cpu.options */ int *cpuoptions = &mips_cpu.options; @@ -154,7 +223,6 @@ static inline void cpu_probe(void) { - #ifdef CONFIG_CPU_MIPS32 unsigned long config1; #endif @@ -167,6 +235,8 @@ mips_cpu.cputype = CPU_R2000; mips_cpu.isa_level = MIPS_CPU_ISA_I; mips_cpu.options = MIPS_CPU_TLB; + if (cpu_has_fpu()) + mips_cpu.options |= MIPS_CPU_FPU; mips_cpu.tlbsize = 64; break; case PRID_IMP_R3000: @@ -179,6 +249,8 @@ mips_cpu.cputype = CPU_R3000; mips_cpu.isa_level = MIPS_CPU_ISA_I; mips_cpu.options = MIPS_CPU_TLB; + if (cpu_has_fpu()) + mips_cpu.options |= MIPS_CPU_FPU; mips_cpu.tlbsize = 64; break; case PRID_IMP_R4000: @@ -187,8 +259,9 @@ else mips_cpu.cputype = CPU_R4000SC; mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_VCE; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH | + MIPS_CPU_VCE; mips_cpu.tlbsize = 48; break; case PRID_IMP_VR41XX: @@ -197,67 +270,100 @@ mips_cpu.options = R4K_OPTS; mips_cpu.tlbsize = 32; break; + case PRID_IMP_R4300: + mips_cpu.cputype = CPU_R4300; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 32; + break; case PRID_IMP_R4600: mips_cpu.cputype = CPU_R4600; mips_cpu.isa_level = MIPS_CPU_ISA_III; mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; mips_cpu.tlbsize = 48; break; -/* - * This processor doesn't have an MMU, so it's not "real easy" to - * run Linux on it. It is left purely for documentation. - * case PRID_IMP_R4650: + #if 0 + case PRID_IMP_R4650: + /* + * This processor doesn't have an MMU, so it's not + * "real easy" to run Linux on it. It is left purely + * for documentation. Commented out because it shares + * it's c0_prid id number with the TX3900. + */ mips_cpu.cputype = CPU_R4650; mips_cpu.isa_level = MIPS_CPU_ISA_III; mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; mips_cpu.tlbsize = 48; break; -*/ + #endif case PRID_IMP_TX39: mips_cpu.isa_level = MIPS_CPU_ISA_I; mips_cpu.options = MIPS_CPU_TLB; - switch (mips_cpu.processor_id & 0xff) { - case PRID_REV_TX3912: - mips_cpu.cputype = CPU_TX3912; - mips_cpu.tlbsize = 32; - break; - case PRID_REV_TX3922: - mips_cpu.cputype = CPU_TX3922; - mips_cpu.tlbsize = 64; - break; - case PRID_REV_TX3927: + if ((mips_cpu.processor_id & 0xf0) == + (PRID_REV_TX3927 & 0xf0)) { mips_cpu.cputype = CPU_TX3927; mips_cpu.tlbsize = 64; - break; - default: - mips_cpu.cputype = CPU_UNKNOWN; - break; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; + } else { + switch (mips_cpu.processor_id & 0xff) { + case PRID_REV_TX3912: + mips_cpu.cputype = CPU_TX3912; + mips_cpu.tlbsize = 32; + break; + case PRID_REV_TX3922: + mips_cpu.cputype = CPU_TX3922; + mips_cpu.tlbsize = 64; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } } break; case PRID_IMP_R4700: mips_cpu.cputype = CPU_R4700; mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; mips_cpu.tlbsize = 48; break; + case PRID_IMP_TX49: + mips_cpu.cputype = CPU_TX49XX; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 4; + mips_cpu.dcache.ways = 4; + break; case PRID_IMP_R5000: mips_cpu.cputype = CPU_R5000; mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; mips_cpu.tlbsize = 48; break; case PRID_IMP_R5432: mips_cpu.cputype = CPU_R5432; mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5500: + mips_cpu.cputype = CPU_R5500; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH; mips_cpu.tlbsize = 48; break; case PRID_IMP_NEVADA: mips_cpu.cputype = CPU_NEVADA; mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_DIVEC; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_DIVEC; mips_cpu.tlbsize = 48; mips_cpu.icache.ways = 2; mips_cpu.dcache.ways = 2; @@ -277,7 +383,17 @@ case PRID_IMP_RM7000: mips_cpu.cputype = CPU_RM7000; mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + /* + * Undocumented RM7000: Bit 29 in the info register of + * the RM7000 v2.0 indicates if the TLB has 48 or 64 + * entries. + * + * 29 1 => 64 entry JTLB + * 0 => 48 entry JTLB + */ + mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48; break; case PRID_IMP_R8000: mips_cpu.cputype = CPU_R8000; @@ -311,11 +427,15 @@ case PRID_IMP_4KSC: mips_cpu.cputype = CPU_4KSC; cpu_4kc: - /* Why do we set all these options by default, THEN query them?? */ - mips_cpu.cputype = MIPS_CPU_ISA_M32; + /* + * Why do we set all these options by default, THEN + * query them?? + */ + mips_cpu.isa_level = MIPS_CPU_ISA_M32; mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + MIPS_CPU_DIVEC | MIPS_CPU_WATCH | + MIPS_CPU_MCHECK; config1 = read_mips32_cp0_config1(); if (config1 & (1 << 3)) mips_cpu.options |= MIPS_CPU_WATCH; @@ -327,11 +447,12 @@ break; case PRID_IMP_5KC: mips_cpu.cputype = CPU_5KC; - mips_cpu.cputype = MIPS_CPU_ISA_M64; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; /* See comment above about querying options */ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + MIPS_CPU_DIVEC | MIPS_CPU_WATCH | + MIPS_CPU_MCHECK; config1 = read_mips32_cp0_config1(); if (config1 & (1 << 3)) mips_cpu.options |= MIPS_CPU_WATCH; @@ -339,19 +460,21 @@ mips_cpu.options |= MIPS_CPU_MIPS16; if (config1 & 1) mips_cpu.options |= MIPS_CPU_FPU; - break; mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; default: mips_cpu.cputype = CPU_UNKNOWN; break; } break; -#endif case PRID_COMP_ALCHEMY: switch (mips_cpu.processor_id & 0xff00) { -#ifdef CONFIG_CPU_MIPS32 - case PRID_IMP_AU1000: - mips_cpu.cputype = CPU_AU1000; + case PRID_IMP_AU1_REV1: + case PRID_IMP_AU1_REV2: + if (mips_cpu.processor_id & 0xff000000) + mips_cpu.cputype = CPU_AU1500; + else + mips_cpu.cputype = CPU_AU1000; mips_cpu.isa_level = MIPS_CPU_ISA_M32; mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | @@ -365,19 +488,24 @@ mips_cpu.options |= MIPS_CPU_FPU; mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; break; -#endif default: mips_cpu.cputype = CPU_UNKNOWN; break; } break; +#endif /* CONFIG_CPU_MIPS32 */ case PRID_COMP_SIBYTE: switch (mips_cpu.processor_id & 0xff00) { case PRID_IMP_SB1: mips_cpu.cputype = CPU_SB1; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | MIPS_CPU_FPU | - MIPS_CPU_VCE; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | + MIPS_CPU_MCHECK; +#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS + /* FPU in pass1 is known to have issues. */ + mips_cpu.options |= MIPS_CPU_FPU; +#endif break; default: mips_cpu.cputype = CPU_UNKNOWN; @@ -387,6 +515,15 @@ default: mips_cpu.cputype = CPU_UNKNOWN; } + if (mips_cpu.options & MIPS_CPU_FPU) + mips_cpu.fpu_id = cpu_get_fpu_id(); +} + +static inline void cpu_report(void) +{ + printk("CPU revision is: %08x\n", mips_cpu.processor_id); + if (mips_cpu.options & MIPS_CPU_FPU) + printk("FPU revision is: %08x\n", mips_cpu.fpu_id); } asmlinkage void __init @@ -403,6 +540,8 @@ sgi_sysinit(); #endif + cpu_report(); + /* * Determine the mmu/cache attached to this machine, * then flush the tlb and caches. On the r4xx0 @@ -419,7 +558,7 @@ start_kernel(); } -void __init add_memory_region(unsigned long start, unsigned long size, +void __init add_memory_region(phys_t start, phys_t size, long type) { int x = boot_mem_map.nr_map; @@ -440,8 +579,9 @@ int i; for (i = 0; i < boot_mem_map.nr_map; i++) { - printk(" memory: %08lx @ %08lx ", - boot_mem_map.map[i].size, boot_mem_map.map[i].addr); + printk(" memory: %08Lx @ %08Lx ", + (unsigned long long) boot_mem_map.map[i].size, + (unsigned long long) boot_mem_map.map[i].addr); switch (boot_mem_map.map[i].type) { case BOOT_MEM_RAM: printk("(usable)\n"); @@ -498,7 +638,7 @@ c = *(from++); if (!c) break; - if (COMMAND_LINE_SIZE <= ++len) + if (CL_SIZE <= ++len) break; *(to++) = c; } @@ -514,19 +654,30 @@ { void atlas_setup(void); void baget_setup(void); + void cobalt_setup(void); void ddb_setup(void); void decstation_setup(void); void deskstation_setup(void); void jazz_setup(void); void sni_rm200_pci_setup(void); - void sgi_setup(void); + void ip22_setup(void); void ev96100_setup(void); void malta_setup(void); + void ikos_setup(void); void momenco_ocelot_setup(void); void nino_setup(void); + void nec_osprey_setup(void); + void jmr3927_setup(void); + void it8172_setup(void); + void swarm_setup(void); + void hp_setup(void); unsigned long bootmap_size; - unsigned long start_pfn, max_pfn, first_usable_pfn; + unsigned long start_pfn, max_pfn, max_low_pfn, first_usable_pfn; +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long* initrd_header; +#endif int i; @@ -551,6 +702,11 @@ baget_setup(); break; #endif +#ifdef CONFIG_MIPS_COBALT + case MACH_GROUP_COBALT: + cobalt_setup(); + break; +#endif #ifdef CONFIG_DECSTATION case MACH_GROUP_DEC: decstation_setup(); @@ -579,7 +735,7 @@ #ifdef CONFIG_SGI_IP22 /* As of now this is only IP22. */ case MACH_GROUP_SGI: - sgi_setup(); + ip22_setup(); break; #endif #ifdef CONFIG_SNI_RM200_PCI @@ -602,6 +758,11 @@ ddb_setup(); break; #endif +#ifdef CONFIG_NEC_OSPREY + case MACH_GROUP_NEC_VR41XX: + nec_osprey_setup(); + break; +#endif #ifdef CONFIG_MIPS_EV96100 case MACH_GROUP_GALILEO: ev96100_setup(); @@ -628,6 +789,26 @@ au1000_setup(); break; #endif +#ifdef CONFIG_MIPS_PB1500 + case MACH_GROUP_ALCHEMY: + au1500_setup(); + break; +#endif +#ifdef CONFIG_TOSHIBA_JMR3927 + case MACH_GROUP_TOSHIBA: + jmr3927_setup(); + break; +#endif +#ifdef CONFIG_SIBYTE_SWARM + case MACH_GROUP_SIBYTE: + swarm_setup(); + break; +#endif +#ifdef CONFIG_HP_LASERJET + case MACH_GROUP_HP_LJ: + hp_setup(); + break; +#endif default: panic("Unsupported architecture"); } @@ -643,11 +824,26 @@ #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) #define PFN_PHYS(x) ((x) << PAGE_SHIFT) +#define MAXMEM HIGHMEM_START +#define MAXMEM_PFN PFN_DOWN(MAXMEM) + +#ifdef CONFIG_BLK_DEV_INITRD + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + } + start_pfn = PFN_UP(__pa((&_end)+(initrd_end - initrd_start) + PAGE_SIZE)); +#else /* * Partially used pages are not usable - thus * we are rounding upwards. */ start_pfn = PFN_UP(__pa(&_end)); +#endif /* CONFIG_BLK_DEV_INITRD */ /* Find the highest page frame number we have available. */ max_pfn = 0; @@ -674,9 +870,36 @@ } } } - - /* Initialize the boot-time allocator. */ - bootmap_size = init_bootmem(first_usable_pfn, max_pfn); + + /* + * Determine low and high memory ranges + */ + max_low_pfn = max_pfn; + if (max_low_pfn > MAXMEM_PFN) { + max_low_pfn = MAXMEM_PFN; +#ifndef CONFIG_HIGHMEM + /* Maximum memory usable is what is directly addressable */ + printk(KERN_WARNING "Warning only %ldMB will be used.\n", + MAXMEM>>20); + printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); +#endif + } + +#ifdef CONFIG_HIGHMEM + /* + * Crude, we really should make a better attempt at detecting + * highstart_pfn + */ + highstart_pfn = highend_pfn = max_pfn; + if (max_pfn > MAXMEM_PFN) { + highstart_pfn = MAXMEM_PFN; + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", + (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT)); + } +#endif + + /* Initialize the boot-time allocator with low memory only. */ + bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); /* * Register fully available low RAM pages with the bootmem allocator. @@ -694,7 +917,7 @@ * We are rounding up the start address of usable memory: */ curr_pfn = PFN_UP(boot_mem_map.map[i].addr); - if (curr_pfn >= max_pfn) + if (curr_pfn >= max_low_pfn) continue; if (curr_pfn < start_pfn) curr_pfn = start_pfn; @@ -705,8 +928,19 @@ last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size); - if (last_pfn > max_pfn) - last_pfn = max_pfn; + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + /* + * Only register lowmem part of lowmem segment with bootmem. + */ + size = last_pfn - curr_pfn; + if (curr_pfn > PFN_DOWN(HIGHMEM_START)) + continue; + if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START)) + size = PFN_DOWN(HIGHMEM_START) - curr_pfn; + if (!size) + continue; /* * ... finally, did all the rounding and playing @@ -715,7 +949,7 @@ if (last_pfn <= curr_pfn) continue; - size = last_pfn - curr_pfn; + /* Register lowmem ranges */ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); } @@ -725,7 +959,7 @@ #ifdef CONFIG_BLK_DEV_INITRD /* Board specific code should have set up initrd_start and initrd_end */ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - if( __rd_start != __rd_end ) { + if (&__rd_start != &__rd_end) { initrd_start = (unsigned long)&__rd_start; initrd_end = (unsigned long)&__rd_end; } @@ -757,6 +991,7 @@ */ for (i = 0; i < boot_mem_map.nr_map; i++) { struct resource *res; + unsigned long addr_pfn, end_pfn; res = alloc_bootmem(sizeof(struct resource)); switch (boot_mem_map.map[i].type) { @@ -768,8 +1003,16 @@ default: res->name = "reserved"; } + addr_pfn = PFN_UP(boot_mem_map.map[i].addr); + end_pfn = PFN_UP(boot_mem_map.map[i].addr+boot_mem_map.map[i].size); + if (addr_pfn > max_low_pfn) + continue; res->start = boot_mem_map.map[i].addr; - res->end = res->start + boot_mem_map.map[i].size - 1; + if (end_pfn < max_low_pfn) { + res->end = res->start + boot_mem_map.map[i].size - 1; + } else { + res->end = max_low_pfn - 1; + } res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; request_resource(&iomem_resource, res); @@ -789,9 +1032,22 @@ write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT); } +void r39xx_wait(void) +{ + unsigned long cfg = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT); +} + void r4k_wait(void) { __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0"); } + +int __init fpu_disable(char *s) +{ + mips_cpu.options &= ~MIPS_CPU_FPU; + return 1; +} +__setup("nofpu", fpu_disable); diff -urN linux-2.4.18/arch/mips/kernel/signal.c linux-2.4.19-pre5/arch/mips/kernel/signal.c --- linux-2.4.18/arch/mips/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -204,7 +204,7 @@ #define restore_gp_reg(i) do { \ err |= __get_user(reg, &sc->sc_regs[i]); \ regs->regs[i] = reg; \ -} while(0); +} while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); @@ -661,10 +661,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/mips/kernel/smp.c linux-2.4.19-pre5/arch/mips/kernel/smp.c --- linux-2.4.18/arch/mips/kernel/smp.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/smp.c Sat Mar 30 22:55:26 2002 @@ -1,11 +1,4 @@ /* - * - * arch/mips/kernel/smp.c - * - * Copyright (C) 2000 Sibyte - * - * Written by Justin Carlson (carlson@sibyte.com) - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -20,20 +13,25 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * Copyright (C) 2000, 2001 Kanoj Sarcar + * Copyright (C) 2000, 2001 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. + * Copyright (C) 2000, 2001 Broadcom Corporation */ - - #include +#include #include #include #include #include +#include #include #include #include -#include +#include #include +#include #include #include #include @@ -42,38 +40,26 @@ #include #include -/* - * This was written with the BRCM12500 MP SOC in mind, but tries to - * be generic. It's modelled on the mips64 smp.c code, which is - * derived from Sparc, I'm guessing, which is derived from... - * - * It's probably horribly designed for very large ccNUMA systems - * as it doesn't take any node clustering into account. -*/ - - /* Ze Big Kernel Lock! */ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; -int smp_threads_ready; /* Not used */ -int smp_num_cpus; -int global_irq_holder = NO_PROC_ID; -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -struct mips_cpuinfo cpu_data[NR_CPUS]; - -struct smp_fn_call_struct smp_fn_call = -{ SPIN_LOCK_UNLOCKED, ATOMIC_INIT(0), NULL, NULL}; +int smp_threads_ready; +int smp_num_cpus = 1; /* Number that came online. */ +cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */ +struct cpuinfo_mips cpu_data[NR_CPUS]; +void (*volatile smp_cpu0_finalize)(void); -static atomic_t cpus_booted = ATOMIC_INIT(0); +// static atomic_t cpus_booted = ATOMIC_INIT(0); +atomic_t cpus_booted = ATOMIC_INIT(0); /* These are defined by the board-specific code. */ -/* Cause the function described by smp_fn_call - to be executed on the passed cpu. When the function - has finished, increment the finished field of - smp_fn_call. */ - -void core_call_function(int cpu); +/* + * Cause the function described by call_data to be executed on the passed + * cpu. When the function has finished, increment the finished field of + * call_data. + */ +void core_send_ipi(int cpu, unsigned int action); /* * Clear all undefined state in the cpu, set up sp and gp to the passed @@ -85,91 +71,37 @@ * After we've done initial boot, this function is called to allow the * board code to clean up state, if needed */ - void prom_init_secondary(void); - -void cpu_idle(void); - -/* Do whatever setup needs to be done for SMP at the board level. Return - the number of cpus in the system, including this one */ +/* + * Do whatever setup needs to be done for SMP at the board level. Return + * the number of cpus in the system, including this one + */ int prom_setup_smp(void); -int start_secondary(void *unused) +/* + * Hook for doing final board-specific setup after the generic smp setup + * is done + */ +asmlinkage void start_secondary(void) { + unsigned int cpu = smp_processor_id(); + prom_init_secondary(); - write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); - current_pgd[smp_processor_id()] = init_mm.pgd; + per_cpu_trap_init(); + + /* + * XXX parity protection should be folded in here when it's converted + * to an option instead of something based on .cputype + */ + + pgd_current[cpu] = init_mm.pgd; + cpu_data[cpu].udelay_val = loops_per_jiffy; + prom_smp_finish(); printk("Slave cpu booted successfully\n"); + CPUMASK_SETB(cpu_online_map, cpu); atomic_inc(&cpus_booted); cpu_idle(); - return 0; -} - -void __init smp_boot_cpus(void) -{ - int i; - - smp_num_cpus = prom_setup_smp(); - init_new_context(current, &init_mm); - current->processor = 0; - atomic_set(&cpus_booted, 1); /* Master CPU is already booted... */ - init_idle(); - for (i = 1; i < smp_num_cpus; i++) { - struct task_struct *p; - struct pt_regs regs; - printk("Starting CPU %d... ", i); - - /* Spawn a new process normally. Grab a pointer to - its task struct so we can mess with it */ - do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); - p = init_task.prev_task; - - /* Schedule the first task manually */ - p->processor = i; - p->cpus_runnable = 1 << i; /* we schedule the first task manually */ - - /* Attach to the address space of init_task. */ - atomic_inc(&init_mm.mm_count); - p->active_mm = &init_mm; - init_tasks[i] = p; - - del_from_runqueue(p); - unhash_process(p); - - prom_boot_secondary(i, - (unsigned long)p + KERNEL_STACK_SIZE - 32, - (unsigned long)p); - -#if 0 - - /* This is copied from the ip-27 code in the mips64 tree */ - - struct task_struct *p; - - /* - * The following code is purely to make sure - * Linux can schedule processes on this slave. - */ - kernel_thread(0, NULL, CLONE_PID); - p = init_task.prev_task; - sprintf(p->comm, "%s%d", "Idle", i); - init_tasks[i] = p; - p->processor = i; - p->cpus_runnable = 1 << i; /* we schedule the first task manually * - del_from_runqueue(p); - unhash_process(p); - /* Attach to the address space of init_task. */ - atomic_inc(&init_mm.mm_count); - p->active_mm = &init_mm; - prom_boot_secondary(i, - (unsigned long)p + KERNEL_STACK_SIZE - 32, - (unsigned long)p); -#endif - } - - /* Wait for everyone to come up */ - while (atomic_read(&cpus_booted) != smp_num_cpus); } void __init smp_commence(void) @@ -177,16 +109,14 @@ /* Not sure what to do here yet */ } -static void reschedule_this_cpu(void *dummy) +void smp_send_reschedule(int cpu) { - current->need_resched = 1; + core_send_ipi(cpu, SMP_RESCHEDULE_YOURSELF); } -void FASTCALL(smp_send_reschedule(int cpu)) -{ - smp_call_function(reschedule_this_cpu, NULL, 0, 0); -} +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; +struct call_data_struct *call_data; /* * The caller of this wants the passed function to run on every cpu. If wait @@ -196,43 +126,76 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { - int cpus = smp_num_cpus - 1; - int i; + struct call_data_struct data; + int i, cpus = smp_num_cpus - 1; + int cpu = smp_processor_id(); - if (smp_num_cpus < 2) { + if (!cpus) return 0; - } - spin_lock_bh(&smp_fn_call.lock); + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + + /* Send a message to all other CPUs and wait for them to respond */ + for (i = 0; i < smp_num_cpus; i++) + if (i != cpu) + core_send_ipi(i, SMP_CALL_FUNCTION); + + /* Wait for response */ + /* FIXME: lock-up detection, backtrace on lock-up */ + while (atomic_read(&data.started) != cpus) + barrier(); + + if (wait) + while (atomic_read(&data.finished) != cpus) + barrier(); + spin_unlock_bh(&call_lock); - atomic_set(&smp_fn_call.finished, 0); - smp_fn_call.fn = func; - smp_fn_call.data = info; - - for (i = 0; i < smp_num_cpus; i++) { - if (i != smp_processor_id()) { - /* Call the board specific routine */ - core_call_function(i); - } - } - - if (wait) { - while(atomic_read(&smp_fn_call.finished) != cpus) {} - } - - spin_unlock_bh(&smp_fn_call.lock); return 0; } -void synchronize_irq(void) +void smp_call_function_interrupt(void) { - panic("synchronize_irq"); + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + int cpu = smp_processor_id(); + + irq_enter(cpu, 0); /* XXX choose an irq number? */ + /* + * Notify initiating CPU that I've grabbed the data + * and am about to execute the function + */ + mb(); + atomic_inc(&call_data->started); + + /* + * At this point the info structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) { + mb(); + atomic_inc(&call_data->finished); + } + irq_exit(cpu, 0); /* XXX choose an irq number? */ } static void stop_this_cpu(void *dummy) { - printk("Cpu stopping\n"); - for (;;); + int cpu = smp_processor_id(); + if (cpu) + for (;;); /* XXX Use halt like i386 */ + + /* XXXKW this isn't quite there yet */ + while (!smp_cpu0_finalize) ; + smp_cpu0_finalize(); } void smp_send_stop(void) @@ -247,157 +210,109 @@ return 0; } +static void flush_tlb_all_ipi(void *info) +{ + local_flush_tlb_all(); +} -/* - * Most of this code is take from the mips64 tree (ip27-irq.c). It's virtually - * identical to the i386 implentation in arh/i386/irq.c, with translations for - * the interrupt enable bit - */ - -#define MAXCOUNT 100000000 -#define SYNC_OTHER_CORES(x) udelay(x+1) +void flush_tlb_all(void) +{ + smp_call_function(flush_tlb_all_ipi, 0, 1, 1); + local_flush_tlb_all(); +} -static inline void wait_on_irq(int cpu) +static void flush_tlb_mm_ipi(void *mm) { - int count = MAXCOUNT; + local_flush_tlb_mm((struct mm_struct *)mm); +} - for (;;) { +/* + * The following tlb flush calls are invoked when old translations are + * being torn down, or pte attributes are changing. For single threaded + * address spaces, a new context is obtained on the current cpu, and tlb + * context on other cpus are invalidated to force a new context allocation + * at switch_mm time, should the mm ever be used on other cpus. For + * multithreaded address spaces, intercpu interrupts have to be sent. + * Another case where intercpu interrupts are required is when the target + * mm might be active on another cpu (eg debuggers doing the flushes on + * behalf of debugees, kswapd stealing pages from another process etc). + * Kanoj 07/00. + */ - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - spin_unlock(&global_irq_lock); - - for (;;) { - if (!--count) { - printk("Count spun out. Huh?\n"); - count = ~0; - } - __sti(); - SYNC_OTHER_CORES(cpu); - __cli(); - if (irqs_running()) - continue; - if (spin_is_locked(&global_irq_lock)) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } +void flush_tlb_mm(struct mm_struct *mm) +{ + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1); + } else { + int i; + for (i = 0; i < smp_num_cpus; i++) + if (smp_processor_id() != i) + CPU_CONTEXT(i, mm) = 0; } + local_flush_tlb_mm(mm); } +struct flush_tlb_data { + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long addr1; + unsigned long addr2; +}; -static inline void get_irqlock(int cpu) +static void flush_tlb_range_ipi(void *info) { - 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); + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; - /* - * Ok, finally.. - */ - global_irq_holder = cpu; + local_flush_tlb_range(fd->mm, fd->addr1, fd->addr2); } - -/* - * 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) +void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - unsigned int flags; + if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { + struct flush_tlb_data fd; - __save_flags(flags); - if (flags & ST0_IE) { - int cpu = smp_processor_id(); - __cli(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); + fd.mm = mm; + fd.addr1 = start; + fd.addr2 = end; + smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1); + } else { + int i; + for (i = 0; i < smp_num_cpus; i++) + if (smp_processor_id() != i) + CPU_CONTEXT(i, mm) = 0; } + local_flush_tlb_range(mm, start, end); } -void __global_sti(void) +static void flush_tlb_page_ipi(void *info) { - int cpu = smp_processor_id(); + struct flush_tlb_data *fd = (struct flush_tlb_data *)info; - if (!local_irq_count(cpu)) - release_irqlock(cpu); - __sti(); + local_flush_tlb_page(fd->vma, fd->addr1); } -/* - * SMP flags value to restore to: - * 0 - global cli - * 1 - global sti - * 2 - local cli - * 3 - local sti - */ -unsigned long __global_save_flags(void) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - int retval; - int local_enabled; - unsigned long flags; - int cpu = smp_processor_id(); + if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) { + struct flush_tlb_data fd; - __save_flags(flags); - local_enabled = (flags & ST0_IE); - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { - if (local_enabled) - retval = 1; - if (global_irq_holder == cpu) - retval = 0; + fd.vma = vma; + fd.addr1 = page; + smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1); + } else { + int i; + for (i = 0; i < smp_num_cpus; i++) + if (smp_processor_id() != i) + CPU_CONTEXT(i, vma->vm_mm) = 0; } - - return retval; + local_flush_tlb_page(vma, page); } -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\n", flags); - } -} +EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); diff -urN linux-2.4.18/arch/mips/kernel/syscall.c linux-2.4.19-pre5/arch/mips/kernel/syscall.c --- linux-2.4.18/arch/mips/kernel/syscall.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/syscall.c Sat Mar 30 22:55:26 2002 @@ -82,7 +82,16 @@ asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, off_t offset) { - return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + int result; + + result = -EINVAL; + if (offset & ~PAGE_MASK) + goto out; + + result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + +out: + return result; } asmlinkage long diff -urN linux-2.4.18/arch/mips/kernel/syscalls.h linux-2.4.19-pre5/arch/mips/kernel/syscalls.h --- linux-2.4.18/arch/mips/kernel/syscalls.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/syscalls.h Sat Mar 30 22:55:33 2002 @@ -235,3 +235,20 @@ SYS(sys_madvise, 3) SYS(sys_getdents64, 3) SYS(sys_fcntl64, 3) /* 4220 */ +SYS(sys_ni_syscall, 0) +SYS(sys_gettid, 0) +SYS(sys_readahead, 5) +SYS(sys_ni_syscall, 0) /* reserved for setxattr */ +SYS(sys_ni_syscall, 0) /* 4225 res. for lsetxattr */ +SYS(sys_ni_syscall, 0) /* reserved for fsetxattr */ +SYS(sys_ni_syscall, 0) /* reserved for getxattr */ +SYS(sys_ni_syscall, 0) /* reserved for lgetxattr */ +SYS(sys_ni_syscall, 0) /* reserved for fgetxattr */ +SYS(sys_ni_syscall, 0) /* 4230 res. for listxattr */ +SYS(sys_ni_syscall, 0) /* reserved for llistxattr */ +SYS(sys_ni_syscall, 0) /* reserved for flistxattr */ +SYS(sys_ni_syscall, 0) /* reserved for removexattr */ +SYS(sys_ni_syscall, 0) /* reserved for lremovexattr */ +SYS(sys_ni_syscall, 0) /* 4235 res. for fremovexattr */ +SYS(sys_gettid, 0) +SYS(sys_tkill, 2) diff -urN linux-2.4.18/arch/mips/kernel/sysirix.c linux-2.4.19-pre5/arch/mips/kernel/sysirix.c --- linux-2.4.18/arch/mips/kernel/sysirix.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/sysirix.c Sat Mar 30 22:55:26 2002 @@ -1876,7 +1876,8 @@ return 0; } -asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) +asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, + unsigned int count, int *eob) { struct file *file; struct irix_dirent32 *lastdirent; @@ -1900,6 +1901,7 @@ error = vfs_readdir(file, irix_filldir32, &buf); if (error < 0) goto out_putf; + error = buf.error; lastdirent = buf.previous; if (lastdirent) { @@ -1908,10 +1910,9 @@ } if (put_user(0, eob) < 0) { - error = EFAULT; + error = -EFAULT; goto out_putf; } - #ifdef DEBUG_GETDENTS printk("eob=%d returning %d\n", *eob, count - buf.count); diff -urN linux-2.4.18/arch/mips/kernel/sysmips.c linux-2.4.19-pre5/arch/mips/kernel/sysmips.c --- linux-2.4.18/arch/mips/kernel/sysmips.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/sysmips.c Sat Mar 30 22:55:26 2002 @@ -1,11 +1,10 @@ /* - * MIPS specific syscalls - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1997, 2000 by Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 2000, 2001 by Ralf Baechle + * Copyright (C) 2001 MIPS Technologies, Inc. */ #include #include @@ -48,11 +47,10 @@ } asmlinkage int -sys_sysmips(int cmd, int arg1, int arg2, int arg3) +_sys_sysmips(int cmd, int arg1, int arg2, int arg3) { - int *p; char *name; - int tmp, len, retval, errno; + int tmp, len, retval; switch(cmd) { case SETNAME: { @@ -74,55 +72,10 @@ return 0; } - case MIPS_ATOMIC_SET: { -#ifdef CONFIG_CPU_HAS_LLSC - unsigned int tmp; - - p = (int *) arg1; - errno = verify_area(VERIFY_WRITE, p, sizeof(*p)); - if (errno) - return errno; - errno = 0; - - __asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t" - ".set\tmips2\n\t" - ".set\tnoat\n\t" - "1:\tll\t%0, %4\n\t" - "move\t$1, %3\n\t" - "2:\tsc\t$1, %1\n\t" - "beqz\t$1, 1b\n\t" - ".set\tpop\n\t" - ".section\t.fixup,\"ax\"\n" - "3:\tli\t%2, 1\t\t\t# error\n\t" - ".previous\n\t" - ".section\t__ex_table,\"a\"\n\t" - ".word\t1b, 3b\n\t" - ".word\t2b, 3b\n\t" - ".previous\n\t" - : "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno) - : "r" (arg2), "o" (* (u32 *) p), "2" (errno) - : "$1"); - - if (errno) - return -EFAULT; - - /* We're skipping error handling etc. */ - if (current->ptrace & PT_TRACESYS) - syscall_trace(); - - ((struct pt_regs *)&cmd)->regs[2] = tmp; - ((struct pt_regs *)&cmd)->regs[7] = 0; - - __asm__ __volatile__( - "move\t$29, %0\n\t" - "j\to32_ret_from_sys_call" - : /* No outputs */ - : "r" (&cmd)); - /* Unreached */ -#else - printk("sys_sysmips(MIPS_ATOMIC_SET, ...) not ready for !CONFIG_CPU_HAS_LLSC\n"); -#endif - } + case MIPS_ATOMIC_SET: + printk(KERN_CRIT "How did I get here?\n"); + retval = -EINVAL; + goto out; case MIPS_FIXADE: tmp = current->thread.mflags & ~3; @@ -131,7 +84,7 @@ goto out; case FLUSH_CACHE: - flush_cache_all(); + __flush_cache_all(); retval = 0; goto out; diff -urN linux-2.4.18/arch/mips/kernel/time.c linux-2.4.19-pre5/arch/mips/kernel/time.c --- linux-2.4.18/arch/mips/kernel/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/time.c Sat Mar 30 22:55:26 2002 @@ -30,7 +30,7 @@ /* This is for machines which generate the exact clock. */ #define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff) +#define USECS_PER_JIFFY_FRAC ((u32)((1000000ULL << 32) / HZ)) /* * forward reference @@ -255,8 +255,7 @@ :"r" (timerhi), "m" (timerlo), "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); + "r" (USECS_PER_JIFFY)); cached_quotient = quotient; } @@ -407,7 +406,8 @@ 0, "timer", NULL, - NULL}; + NULL +}; void __init time_init(void) { @@ -475,10 +475,10 @@ void to_tm(unsigned long tim, struct rtc_time * tm) { - long hms, day; + long hms, day, gday; int i; - day = tim / SECDAY; + gday = day = tim / SECDAY; hms = tim % SECDAY; /* Hours, minutes, seconds are easy */ @@ -497,7 +497,7 @@ for (i = 1; day >= days_in_month(i); i++) day -= days_in_month(i); days_in_month(FEBRUARY) = 28; - tm->tm_mon = i; + tm->tm_mon = i-1; /* tm_mon starts from 0 to 11 */ /* Days are what is left over (+1) from all that. */ tm->tm_mday = day + 1; @@ -505,5 +505,5 @@ /* * Determine the day of week */ - tm->tm_wday = (day + 3) % 7; + tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */ } diff -urN linux-2.4.18/arch/mips/kernel/traps.c linux-2.4.19-pre5/arch/mips/kernel/traps.c --- linux-2.4.18/arch/mips/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/traps.c Sat Mar 30 22:55:26 2002 @@ -77,12 +77,9 @@ */ #define MODULE_RANGE (8*1024*1024) -#ifndef CONFIG_CPU_HAS_LLSC /* * This stuff is needed for the userland ll-sc emulation for R2300 */ -void simulate_ll(struct pt_regs *regs, unsigned int opcode); -void simulate_sc(struct pt_regs *regs, unsigned int opcode); #define OPCODE 0xfc000000 #define BASE 0x03e00000 @@ -90,8 +87,97 @@ #define OFFSET 0x0000ffff #define LL 0xc0000000 #define SC 0xe0000000 + +/* + * The ll_bit is cleared by r*_switch.S + */ + +unsigned long ll_bit; +#ifdef CONFIG_PROC_FS +extern unsigned long ll_ops; +extern unsigned long sc_ops; +#endif + +static struct task_struct *ll_task = NULL; + +static inline void simulate_ll(struct pt_regs *regp, unsigned int opcode) +{ + unsigned long value, *vaddr; + long offset; + int signal = 0; + + /* + * analyse the ll instruction that just caused a ri exception + * and put the referenced address to addr. + */ + + /* sign extend offset */ + offset = opcode & OFFSET; + offset <<= 16; + offset >>= 16; + + vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); + +#ifdef CONFIG_PROC_FS + ll_ops++; +#endif + + if ((unsigned long)vaddr & 3) + signal = SIGBUS; + else if (get_user(value, vaddr)) + signal = SIGSEGV; + else { + if (ll_task == NULL || ll_task == current) { + ll_bit = 1; + } else { + ll_bit = 0; + } + ll_task = current; + regp->regs[(opcode & RT) >> 16] = value; + } + if (compute_return_epc(regp)) + return; + if (signal) + send_sig(signal, current, 1); +} + +static inline void simulate_sc(struct pt_regs *regp, unsigned int opcode) +{ + unsigned long *vaddr, reg; + long offset; + int signal = 0; + + /* + * analyse the sc instruction that just caused a ri exception + * and put the referenced address to addr. + */ + + /* sign extend offset */ + offset = opcode & OFFSET; + offset <<= 16; + offset >>= 16; + + vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); + reg = (opcode & RT) >> 16; + +#ifdef CONFIG_PROC_FS + sc_ops++; #endif + if ((unsigned long)vaddr & 3) + signal = SIGBUS; + else if (ll_bit == 0 || ll_task != current) + regp->regs[reg] = 0; + else if (put_user(regp->regs[reg], vaddr)) + signal = SIGSEGV; + else + regp->regs[reg] = 1; + if (compute_return_epc(regp)) + return; + if (signal) + send_sig(signal, current, 1); +} + /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... @@ -101,7 +187,7 @@ int i; unsigned int *stack; - stack = sp; + stack = sp ? sp : (unsigned int *)&sp; i = 0; printk("Stack:"); @@ -128,12 +214,13 @@ void show_trace(unsigned int *sp) { int i; + int column = 0; unsigned int *stack; unsigned long kernel_start, kernel_end; unsigned long module_start, module_end; extern char _stext, _etext; - stack = sp; + stack = sp ? sp : (unsigned int *) &sp; i = 0; kernel_start = (unsigned long) &_stext; @@ -164,12 +251,23 @@ (addr >= module_start && addr < module_end)) { printk(" [<%08lx>]", addr); + if (column++ == 5) { + printk("\n"); + column = 0; + } if (++i > 40) { printk(" ..."); break; } } } + if (column != 0) + printk("\n"); +} + +void show_trace_task(struct task_struct *tsk) +{ + show_trace((unsigned int *)tsk->thread.reg29); } void show_code(unsigned int *pc) @@ -188,17 +286,36 @@ } } -spinlock_t die_lock; +void show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + 0, regs->regs[1], regs->regs[2], regs->regs[3], + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11], + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19], + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[24], regs->regs[25], + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + printk("Hi : %08lx\n", regs->hi); + printk("Lo : %08lx\n", regs->lo); + + /* + * Saved cp0 registers + */ + printk("epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n", + regs->cp0_epc, print_tainted(), regs->cp0_status, + regs->cp0_cause); +} -extern void __die(const char * str, struct pt_regs * regs, const char *where, - unsigned long line) +void show_registers(struct pt_regs *regs) { - console_verbose(); - spin_lock_irq(&die_lock); - printk("%s", str); - if (where) - printk(" in %s, line %ld", where, line); - printk(":\n"); show_regs(regs); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long) current); @@ -206,6 +323,20 @@ show_trace((unsigned int *) regs->regs[29]); show_code((unsigned int *) regs->cp0_epc); printk("\n"); +} + +static spinlock_t die_lock = SPIN_LOCK_UNLOCKED; + +void __die(const char * str, struct pt_regs * regs, const char *where, + unsigned long line) +{ + console_verbose(); + spin_lock_irq(&die_lock); + printk("%s", str); + if (where) + printk(" in %s, line %ld", where, line); + printk(":\n"); + show_registers(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -375,7 +506,6 @@ return; force_sig(SIGFPE, current); - printk(KERN_DEBUG "Sent send SIGFPE to %s\n", current->comm); } static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) @@ -424,7 +554,7 @@ info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)compute_return_epc(regs); + info.si_addr = (void *)regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -464,7 +594,7 @@ info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)compute_return_epc(regs); + info.si_addr = (void *)regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -476,12 +606,6 @@ force_sig(SIGSEGV, current); } -#ifndef CONFIG_CPU_HAS_LLSC - -#ifdef CONFIG_SMP -#error "ll/sc emulation is not SMP safe" -#endif - /* * userland emulation for R2300 CPUs * needed for the multithreading part of glibc @@ -491,11 +615,18 @@ */ asmlinkage void do_ri(struct pt_regs *regs) { - unsigned int opcode; - if (!user_mode(regs)) BUG(); +#ifndef CONFIG_CPU_HAS_LLSC + +#ifdef CONFIG_SMP +#error "ll/sc emulation is not SMP safe" +#endif + + { + unsigned int opcode; + if (!get_insn_opcode(regs, &opcode)) { if ((opcode & OPCODE) == LL) { simulate_ll(regs, opcode); @@ -506,121 +637,19 @@ return; } } - - if (compute_return_epc(regs)) - return; - force_sig(SIGILL, current); -} - -/* - * The ll_bit is cleared by r*_switch.S - */ - -unsigned long ll_bit; -#ifdef CONFIG_PROC_FS -extern unsigned long ll_ops; -extern unsigned long sc_ops; -#endif - -static struct task_struct *ll_task = NULL; - -void simulate_ll(struct pt_regs *regp, unsigned int opcode) -{ - unsigned long value, *vaddr; - long offset; - int signal = 0; - - /* - * analyse the ll instruction that just caused a ri exception - * and put the referenced address to addr. - */ - - /* sign extend offset */ - offset = opcode & OFFSET; - offset <<= 16; - offset >>= 16; - - vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); - -#ifdef CONFIG_PROC_FS - ll_ops++; -#endif - - if ((unsigned long)vaddr & 3) - signal = SIGBUS; - else if (get_user(value, vaddr)) - signal = SIGSEGV; - else { - if (ll_task == NULL || ll_task == current) { - ll_bit = 1; - } else { - ll_bit = 0; - } - ll_task = current; - regp->regs[(opcode & RT) >> 16] = value; } - if (compute_return_epc(regp)) - return; - if (signal) - send_sig(signal, current, 1); -} - -void simulate_sc(struct pt_regs *regp, unsigned int opcode) -{ - unsigned long *vaddr, reg; - long offset; - int signal = 0; - - /* - * analyse the sc instruction that just caused a ri exception - * and put the referenced address to addr. - */ +#endif /* CONFIG_CPU_HAS_LLSC */ - /* sign extend offset */ - offset = opcode & OFFSET; - offset <<= 16; - offset >>= 16; - - vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); - reg = (opcode & RT) >> 16; - -#ifdef CONFIG_PROC_FS - sc_ops++; -#endif - - if ((unsigned long)vaddr & 3) - signal = SIGBUS; - else if (ll_bit == 0 || ll_task != current) - regp->regs[reg] = 0; - else if (put_user(regp->regs[reg], vaddr)) - signal = SIGSEGV; - else - regp->regs[reg] = 1; - if (compute_return_epc(regp)) - return; - if (signal) - send_sig(signal, current, 1); -} - -#else /* MIPS 2 or higher */ - -asmlinkage void do_ri(struct pt_regs *regs) -{ - unsigned int opcode; - - get_insn_opcode(regs, &opcode); if (compute_return_epc(regs)) return; - force_sig(SIGILL, current); } -#endif - asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; extern void lazy_fpu_switch(void *); + extern void save_fp(struct task_struct *); extern void init_fpu(void); void fpu_emulator_init_fpu(void); int sig; @@ -639,10 +668,13 @@ if (current->used_math) { /* Using the FPU again. */ lazy_fpu_switch(last_task_used_math); } else { /* First time FPU user. */ + if (last_task_used_math != NULL) + save_fp(last_task_used_math); init_fpu(); current->used_math = 1; } last_task_used_math = current; + return; fp_emul: @@ -659,15 +691,27 @@ return; bad_cid: +#ifndef CONFIG_CPU_HAS_LLSC + switch (mips_cpu.cputype) { + case CPU_TX3927: + case CPU_TX39XX: + do_ri(regs); + return; + } +#endif + compute_return_epc(regs); force_sig(SIGILL, current); } asmlinkage void do_watch(struct pt_regs *regs) { + extern void dump_tlb_all(void); + /* * We use the watch exception where available to detect stack * overflows. */ + dump_tlb_all(); show_regs(regs); panic("Caught WATCH exception - probably caused by stack overflow."); } @@ -782,19 +826,32 @@ extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); +void __init per_cpu_trap_init(void) +{ + unsigned int cpu = smp_processor_id(); + + /* Some firmware leaves the BEV flag set, clear it. */ + clear_cp0_status(ST0_BEV); + + /* + * Some MIPS CPUs have a dedicated interrupt vector which reduces the + * interrupt processing overhead. Use it where available. + */ + if (mips_cpu.options & MIPS_CPU_DIVEC) + set_cp0_cause(CAUSEF_IV); + + cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; + set_context(cpu << 23); +} + void __init trap_init(void) { - extern char except_vec0_nevada, except_vec0_r4000; - extern char except_vec0_r4600, except_vec0_r2300; extern char except_vec1_generic, except_vec2_generic; extern char except_vec3_generic, except_vec3_r4000; extern char except_vec4; extern char except_vec_ejtag_debug; unsigned long i; - /* Some firmware leaves the BEV flag set, clear it. */ - clear_cp0_status(ST0_BEV); - /* Copy the generic exception handler code to it's final destination. */ memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80); memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); @@ -810,7 +867,8 @@ * Copy the EJTAG debug exception vector handler code to it's final * destination. */ - memcpy((void *)(KSEG0 + 0x300), &except_vec_ejtag_debug, 0x80); + if (mips_cpu.options & MIPS_CPU_EJTAG) + memcpy((void *)(KSEG0 + 0x200), &except_vec_ejtag_debug, 0x80); /* * Only some CPUs have the watch exceptions or a dedicated @@ -858,19 +916,14 @@ if (mips_cpu.options & MIPS_CPU_FPU) set_except_vector(15, handle_fpe); + if (mips_cpu.options & MIPS_CPU_MCHECK) + set_except_vector(24, handle_mcheck); /* * Handling the following exceptions depends mostly of the cpu type */ if ((mips_cpu.options & MIPS_CPU_4KEX) && (mips_cpu.options & MIPS_CPU_4KTLB)) { - if (mips_cpu.cputype == CPU_NEVADA) { - memcpy((void *)KSEG0, &except_vec0_nevada, 0x80); - } else if (mips_cpu.cputype == CPU_R4600) - memcpy((void *)KSEG0, &except_vec0_r4600, 0x80); - else - memcpy((void *)KSEG0, &except_vec0_r4000, 0x80); - /* Cache error vector already set above. */ if (mips_cpu.options & MIPS_CPU_VCE) { @@ -894,8 +947,14 @@ * XXX - This should be folded in to the "cleaner" handling, * above */ - memcpy((void *)KSEG0, &except_vec0_r4000, 0x80); memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, 0x80); +#ifdef CONFIG_SB1_CACHE_ERROR + /* Special cache error handler for SB1 */ + extern char except_vec2_sb1; + memcpy((void *)(KSEG0 + 0x100), &except_vec2_sb1, 0x80); + memcpy((void *)(KSEG1 + 0x100), &except_vec2_sb1, 0x80); +#endif + save_fp_context = _save_fp_context; restore_fp_context = _restore_fp_context; @@ -907,7 +966,7 @@ case CPU_R6000A: save_fp_context = _save_fp_context; restore_fp_context = _restore_fp_context; - + /* * The R6000 is the only R-series CPU that features a machine * check exception (similar to the R4000 cache error) and @@ -929,9 +988,9 @@ case CPU_TX3912: case CPU_TX3922: case CPU_TX3927: + case CPU_TX39XX: save_fp_context = _save_fp_context; restore_fp_context = _restore_fp_context; - memcpy((void *)KSEG0, &except_vec0_r2300, 0x80); memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80); break; @@ -939,6 +998,11 @@ default: panic("Unknown CPU type"); } + if (!(mips_cpu.options & MIPS_CPU_FPU)) { + save_fp_context = fpu_emulator_save_context; + restore_fp_context = fpu_emulator_restore_context; + } + flush_icache_range(KSEG0, KSEG0 + 0x200); if (mips_cpu.isa_level == MIPS_CPU_ISA_IV) @@ -946,6 +1010,8 @@ atomic_inc(&init_mm.mm_count); /* XXX UP? */ current->active_mm = &init_mm; - write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); - current_pgd[0] = init_mm.pgd; + + /* XXX Must be done for all CPUs */ + current_cpu_data.asid_cache = ASID_FIRST_VERSION; + TLBMISS_HANDLER_SETUP(); } diff -urN linux-2.4.18/arch/mips/kernel/unaligned.c linux-2.4.19-pre5/arch/mips/kernel/unaligned.c --- linux-2.4.18/arch/mips/kernel/unaligned.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/kernel/unaligned.c Sat Mar 30 22:55:26 2002 @@ -96,13 +96,12 @@ if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \ goto sigbus; -static inline void -emulate_load_store_insn(struct pt_regs *regs, - unsigned long addr, - unsigned long pc) +static inline int emulate_load_store_insn(struct pt_regs *regs, + unsigned long addr, unsigned long pc) { union mips_instruction insn; unsigned long value, fixup; + unsigned int res; regs->regs[0] = 0; /* @@ -145,116 +144,96 @@ */ case lh_op: check_axs(pc, addr, 2); - __asm__( - ".set\tnoat\n" + __asm__(".set\tnoat\n" #ifdef __BIG_ENDIAN - "1:\tlb\t%0,0(%1)\n" - "2:\tlbu\t$1,1(%1)\n\t" + "1:\tlb\t%0, 0(%2)\n" + "2:\tlbu\t$1, 1(%2)\n\t" #endif #ifdef __LITTLE_ENDIAN - "1:\tlb\t%0,1(%1)\n" - "2:\tlbu\t$1,0(%1)\n\t" + "1:\tlb\t%0, 1(%2)\n" + "2:\tlbu\t$1, 0(%2)\n\t" #endif - "sll\t%0,0x8\n\t" - "or\t%0,$1\n\t" - ".set\tat\n\t" + "sll\t%0, 0x8\n\t" + "or\t%0, $1\n\t" + "li\t%1, 0\n" + "3:\t.set\tat\n\t" + ".section\t.fixup,\"ax\"\n\t" + "4:\tli\t%1, %3\n\t" + "j\t3b\n\t" + ".previous\n\t" ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" + STR(PTR)"\t1b, 4b\n\t" + STR(PTR)"\t2b, 4b\n\t" ".previous" - :"=&r" (value) - :"r" (addr), "i" (&&fault) - :"$1"); + : "=&r" (value), "=r" (res) + : "r" (addr), "i" (-EFAULT)); + if (res) + goto fault; regs->regs[insn.i_format.rt] = value; - return; + return 0; case lw_op: check_axs(pc, addr, 4); __asm__( #ifdef __BIG_ENDIAN - "1:\tlwl\t%0,(%1)\n" - "2:\tlwr\t%0,3(%1)\n\t" + "1:\tlwl\t%0, (%2)\n" + "2:\tlwr\t%0, 3(%2)\n\t" #endif #ifdef __LITTLE_ENDIAN - "1:\tlwl\t%0,3(%1)\n" - "2:\tlwr\t%0,(%1)\n\t" + "1:\tlwl\t%0, 3(%2)\n" + "2:\tlwr\t%0, (%2)\n\t" #endif + "li\t%1, 0\n" + "3:\t.section\t.fixup,\"ax\"\n\t" + "4:\tli\t%1, %3\n\t" + "j\t3b\n\t" + ".previous\n\t" ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" + STR(PTR)"\t1b, 4b\n\t" + STR(PTR)"\t2b, 4b\n\t" ".previous" - :"=&r" (value) - :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; - return; + : "=&r" (value), "=r" (res) + : "r" (addr), "i" (-EFAULT)); + if (res) + goto fault; + regs->regs[insn.i_format.rt] = value; + return 0; case lhu_op: check_axs(pc, addr, 2); __asm__( ".set\tnoat\n" #ifdef __BIG_ENDIAN - "1:\tlbu\t%0,0(%1)\n" - "2:\tlbu\t$1,1(%1)\n\t" + "1:\tlbu\t%0, 0(%2)\n" + "2:\tlbu\t$1, 1(%2)\n\t" #endif #ifdef __LITTLE_ENDIAN - "1:\tlbu\t%0,1(%1)\n" - "2:\tlbu\t$1,0(%1)\n\t" + "1:\tlbu\t%0, 1(%2)\n" + "2:\tlbu\t$1, 0(%2)\n\t" #endif - "sll\t%0,0x8\n\t" - "or\t%0,$1\n\t" - ".set\tat\n\t" + "sll\t%0, 0x8\n\t" + "or\t%0, $1\n\t" + "li\t%1, 0\n" + "3:\t.set\tat\n\t" + ".section\t.fixup,\"ax\"\n\t" + "4:\tli\t%1, %3\n\t" + "j\t3b\n\t" + ".previous\n\t" ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" + STR(PTR)"\t1b, 4b\n\t" + STR(PTR)"\t2b, 4b\n\t" ".previous" - :"=&r" (value) - :"r" (addr), "i" (&&fault) - :"$1"); + : "=&r" (value), "=r" (res) + : "r" (addr), "i" (-EFAULT)); + if (res) + goto fault; regs->regs[insn.i_format.rt] = value; - return; + return 0; case lwu_op: - check_axs(pc, addr, 4); - __asm__( -#ifdef __BIG_ENDIAN - "1:\tlwl\t%0,(%1)\n" - "2:\tlwr\t%0,3(%1)\n\t" -#endif -#ifdef __LITTLE_ENDIAN - "1:\tlwl\t%0,3(%1)\n" - "2:\tlwr\t%0,(%1)\n\t" -#endif - ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" - ".previous" - :"=&r" (value) - :"r" (addr), "i" (&&fault)); - value &= 0xffffffff; - regs->regs[insn.i_format.rt] = value; - return; - case ld_op: - check_axs(pc, addr, 8); - __asm__( - ".set\tmips3\n" -#ifdef __BIG_ENDIAN - "1:\tldl\t%0,(%1)\n" - "2:\tldr\t%0,7(%1)\n\t" -#endif -#ifdef __LITTLE_ENDIAN - "1:\tldl\t%0,7(%1)\n" - "2:\tldr\t%0,(%1)\n\t" -#endif - ".set\tmips0\n\t" - ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" - ".previous" - :"=&r" (value) - :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; - return; + /* Cannot handle 64-bit instructions in 32-bit kernel */ + goto sigill; case sh_op: check_axs(pc, addr, 2); @@ -262,68 +241,65 @@ __asm__( #ifdef __BIG_ENDIAN ".set\tnoat\n" - "1:\tsb\t%0,1(%1)\n\t" - "srl\t$1,%0,0x8\n" - "2:\tsb\t$1,0(%1)\n\t" + "1:\tsb\t%1, 1(%2)\n\t" + "srl\t$1, %1, 0x8\n" + "2:\tsb\t$1, 0(%2)\n\t" ".set\tat\n\t" #endif #ifdef __LITTLE_ENDIAN ".set\tnoat\n" - "1:\tsb\t%0,0(%1)\n\t" - "srl\t$1,%0,0x8\n" - "2:\tsb\t$1,1(%1)\n\t" + "1:\tsb\t%1, 0(%2)\n\t" + "srl\t$1,%1, 0x8\n" + "2:\tsb\t$1, 1(%2)\n\t" ".set\tat\n\t" #endif + "li\t%0, 0\n" + "3:\n\t" + ".section\t.fixup,\"ax\"\n\t" + "4:\tli\t%0, %3\n\t" + "j\t3b\n\t" + ".previous\n\t" ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" + STR(PTR)"\t1b, 4b\n\t" + STR(PTR)"\t2b, 4b\n\t" ".previous" - : /* no outputs */ - :"r" (value), "r" (addr), "i" (&&fault) - :"$1"); - return; + : "=r" (res) + : "r" (value), "r" (addr), "i" (-EFAULT)); + if (res) + goto fault; + return 0; case sw_op: check_axs(pc, addr, 4); value = regs->regs[insn.i_format.rt]; __asm__( #ifdef __BIG_ENDIAN - "1:\tswl\t%0,(%1)\n" - "2:\tswr\t%0,3(%1)\n\t" + "1:\tswl\t%1,(%2)\n" + "2:\tswr\t%1, 3(%2)\n\t" #endif #ifdef __LITTLE_ENDIAN - "1:\tswl\t%0,3(%1)\n" - "2:\tswr\t%0,(%1)\n\t" + "1:\tswl\t%1, 3(%2)\n" + "2:\tswr\t%1, (%2)\n\t" #endif + "li\t%0, 0\n" + "3:\n\t" + ".section\t.fixup,\"ax\"\n\t" + "4:\tli\t%0, %3\n\t" + "j\t3b\n\t" + ".previous\n\t" ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" + STR(PTR)"\t1b, 4b\n\t" + STR(PTR)"\t2b, 4b\n\t" ".previous" - : /* no outputs */ - :"r" (value), "r" (addr), "i" (&&fault)); - return; + : "=r" (res) + : "r" (value), "r" (addr), "i" (-EFAULT)); + if (res) + goto fault; + return 0; case sd_op: - check_axs(pc, addr, 8); - value = regs->regs[insn.i_format.rt]; - __asm__( - ".set\tmips3\n" -#ifdef __BIG_ENDIAN - "1:\tsdl\t%0,(%1)\n" - "2:\tsdr\t%0,7(%1)\n\t" -#endif -#ifdef __LITTLE_ENDIAN - "1:\tsdl\t%0,7(%1)\n" - "2:\tsdr\t%0,(%1)\n\t" -#endif - ".set\tmips0\n\t" - ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,%2\n\t" - STR(PTR)"\t2b,%2\n\t" - ".previous" - : /* no outputs */ - :"r" (value), "r" (addr), "i" (&&fault)); - return; + /* Cannot handle 64-bit instructions in 32-bit kernel */ + goto sigill; case lwc1_op: case ldc1_op: @@ -352,7 +328,7 @@ */ goto sigill; } - return; + return 0; fault: /* Did we have an exception handler installed? */ @@ -363,20 +339,24 @@ printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)\n", current->comm, regs->cp0_epc, new_epc); regs->cp0_epc = new_epc; - return; + return 1; } die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); - return; + + return 0; + sigbus: - die_if_kernel ("Unhandled kernel unaligned access", regs); + die_if_kernel("Unhandled kernel unaligned access", regs); send_sig(SIGBUS, current, 1); - return; + + return 0; + sigill: - die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs); + die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); send_sig(SIGILL, current, 1); - return; + return 0; } #ifdef CONFIG_PROC_FS @@ -394,11 +374,10 @@ * of the CPU after executing the instruction * in the delay slot of an emulated branch. */ + /* Terminate if exception was recognized as a delay slot return */ + if(do_dsemulret(regs)) return; - if ((unsigned long)regs->cp0_epc == current->thread.dsemul_aerpc) { - do_dsemulret(regs); - return; - } + /* Otherwise handle as normal */ /* * Did we catch a fault trying to load an instruction? @@ -409,12 +388,16 @@ goto sigbus; pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); - if (compute_return_epc(regs)) - return; if ((current->thread.mflags & MF_FIXADE) == 0) goto sigbus; - emulate_load_store_insn(regs, regs->cp0_badvaddr, pc); + /* + * Do branch emulation only if we didn't forward the exception. + * This is all so but ugly ... + */ + if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc)) + compute_return_epc(regs); + #ifdef CONFIG_PROC_FS unaligned_instructions++; #endif @@ -422,8 +405,12 @@ return; sigbus: - die_if_kernel ("Kernel unaligned instruction access", regs); + die_if_kernel("Kernel unaligned instruction access", regs); force_sig(SIGBUS, current); + + /* + * XXX On return from the signal handler we should advance the epc + */ return; } diff -urN linux-2.4.18/arch/mips/lib/Makefile linux-2.4.19-pre5/arch/mips/lib/Makefile --- linux-2.4.18/arch/mips/lib/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/Makefile Sat Mar 30 22:55:26 2002 @@ -14,7 +14,7 @@ watch.o strlen_user.o strncpy_user.o \ strnlen_user.o -ifdef CONFIG_CPU_R3000 +ifeq ($(CONFIG_CPU_R3000)$(CONFIG_CPU_TX39XX),y) obj-y += r3k_dump_tlb.o else obj-y += dump_tlb.o diff -urN linux-2.4.18/arch/mips/lib/csum_partial.S linux-2.4.19-pre5/arch/mips/lib/csum_partial.S --- linux-2.4.18/arch/mips/lib/csum_partial.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/csum_partial.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: csum_partial.S,v 1.1 1998/05/04 09:12:52 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/csum_partial_copy.c linux-2.4.19-pre5/arch/mips/lib/csum_partial_copy.c --- linux-2.4.18/arch/mips/lib/csum_partial_copy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/csum_partial_copy.c Sat Mar 30 22:55:26 2002 @@ -13,8 +13,6 @@ * 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. - * - * $Id: csum_partial_copy.c,v 1.2 1998/09/19 19:16:17 ralf Exp $ */ #include #include diff -urN linux-2.4.18/arch/mips/lib/dump_tlb.c linux-2.4.19-pre5/arch/mips/lib/dump_tlb.c --- linux-2.4.18/arch/mips/lib/dump_tlb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/dump_tlb.c Sat Mar 30 22:55:26 2002 @@ -4,30 +4,47 @@ * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. * Copyright (C) 1999 by Silicon Graphics, Inc. */ +#include #include #include #include #include #include +#include #include #include #include #include -#define mips_tlb_entries 48 +static inline const char *msg2str(unsigned int mask) +{ + switch (mask) { + case PM_4K: return "4kb"; + case PM_16K: return "16kb"; + case PM_64K: return "64kb"; + case PM_256K: return "256kb"; +#ifndef CONFIG_CPU_VR41XX + case PM_1M: return "1Mb"; + case PM_4M: return "4Mb"; + case PM_16M: return "16Mb"; + case PM_64M: return "64Mb"; + case PM_256M: return "256Mb"; +#endif + } +} -void -dump_tlb(int first, int last) +void dump_tlb(int first, int last) { int i; unsigned int pagemask, c0, c1, asid; - unsigned long entryhi, entrylo0, entrylo1; + unsigned long long entrylo0, entrylo1; + unsigned long entryhi; asid = get_entryhi() & 0xff; - for(i=first;i<=last;i++) - { + printk("\n"); + for(i=first;i<=last;i++) { write_32bit_cp0_register(CP0_INDEX, i); __asm__ __volatile__( ".set\tmips3\n\t" @@ -39,49 +56,45 @@ ".set\tmips0\n\t"); pagemask = read_32bit_cp0_register(CP0_PAGEMASK); entryhi = read_32bit_cp0_register(CP0_ENTRYHI); - entrylo0 = read_32bit_cp0_register(CP0_ENTRYLO0); - entrylo1 = read_32bit_cp0_register(CP0_ENTRYLO1); + entrylo0 = get_entrylo0(); + entrylo1 = get_entrylo1(); - /* Unused entries have a virtual address of KSEG0. */ - if ((entryhi & 0xffffe000) != 0x80000000 + /* Unused entries have a virtual address in KSEG0. */ + if ((entryhi & 0xf0000000) != 0x80000000 && (entryhi & 0xff) == asid) { /* * Only print entries in use */ - printk("Index: %2d pgmask=%08x ", i, pagemask); + printk("Index: %2d pgmask=%s ", i, msg2str(pagemask)); c0 = (entrylo0 >> 3) & 7; c1 = (entrylo1 >> 3) & 7; - printk("va=%08lx asid=%08lx" - " [pa=%06lx c=%d d=%d v=%d g=%ld]" - " [pa=%06lx c=%d d=%d v=%d g=%ld]", - (entryhi & 0xffffe000), - entryhi & 0xff, - entrylo0 & PAGE_MASK, c0, + printk("va=%08lx asid=%02lx\n", + (entryhi & 0xffffe000), (entryhi & 0xff)); + printk("\t\t\t[pa=%08Lx c=%d d=%d v=%d g=%Ld]\n", + (entrylo0 << 6) & PAGE_MASK, c0, (entrylo0 & 4) ? 1 : 0, (entrylo0 & 2) ? 1 : 0, - (entrylo0 & 1), - entrylo1 & PAGE_MASK, c1, + (entrylo0 & 1)); + printk("\t\t\t[pa=%08Lx c=%d d=%d v=%d g=%Ld]\n", + (entrylo1 << 6) & PAGE_MASK, c1, (entrylo1 & 4) ? 1 : 0, (entrylo1 & 2) ? 1 : 0, (entrylo1 & 1)); - + printk("\n"); } } - printk("\n"); set_entryhi(asid); } -void -dump_tlb_all(void) +void dump_tlb_all(void) { - dump_tlb(0, mips_tlb_entries - 1); + dump_tlb(0, mips_cpu.tlbsize - 1); } -void -dump_tlb_wired(void) +void dump_tlb_wired(void) { int wired; @@ -125,7 +138,7 @@ void dump_tlb_nonwired(void) { - dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_tlb_entries - 1); + dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_cpu.tlbsize - 1); } void @@ -140,12 +153,20 @@ addr = (unsigned int) address; printk("Addr == %08x\n", addr); - printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); - - page_dir = pgd_offset(t->mm, 0); + printk("task == %08p\n", t); + printk("task->mm == %08p\n", t->mm); + //printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); + + if (addr > KSEG0) + page_dir = pgd_offset_k(0); + else + page_dir = pgd_offset(t->mm, 0); printk("page_dir == %08x\n", (unsigned int) page_dir); - pgd = pgd_offset(t->mm, addr); + if (addr > KSEG0) + pgd = pgd_offset_k(addr); + else + pgd = pgd_offset(t->mm, addr); printk("pgd == %08x, ", (unsigned int) pgd); pmd = pmd_offset(pgd, addr); @@ -155,7 +176,11 @@ printk("pte == %08x, ", (unsigned int) pte); page = *pte; - printk("page == %08x\n", (unsigned int) pte_val(page)); +#ifdef CONFIG_64BIT_PHYS_ADDR + printk("page == %08Lx\n", (unsigned long long) pte_val(page)); +#else + printk("page == %08lx\n", (unsigned int) pte_val(page)); +#endif val = pte_val(page); if (val & _PAGE_PRESENT) printk("present "); diff -urN linux-2.4.18/arch/mips/lib/floppy-no.c linux-2.4.19-pre5/arch/mips/lib/floppy-no.c --- linux-2.4.18/arch/mips/lib/floppy-no.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/floppy-no.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: floppy-no.c,v 1.1 1998/05/07 18:38:32 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/floppy-std.c linux-2.4.19-pre5/arch/mips/lib/floppy-std.c --- linux-2.4.18/arch/mips/lib/floppy-std.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/floppy-std.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: floppy-std.c,v 1.2 1999/01/04 16:03:51 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/ide-no.c linux-2.4.19-pre5/arch/mips/lib/ide-no.c --- linux-2.4.18/arch/mips/lib/ide-no.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/ide-no.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: ide-no.c,v 1.2 1998/06/30 00:21:54 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/kbd-no.c linux-2.4.19-pre5/arch/mips/lib/kbd-no.c --- linux-2.4.18/arch/mips/lib/kbd-no.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/kbd-no.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: kbd-no.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/kbd-std.c linux-2.4.19-pre5/arch/mips/lib/kbd-std.c --- linux-2.4.18/arch/mips/lib/kbd-std.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/kbd-std.c Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: kbd-std.c,v 1.2 1999/06/11 14:29:45 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/memcpy.S linux-2.4.19-pre5/arch/mips/lib/memcpy.S --- linux-2.4.18/arch/mips/lib/memcpy.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/memcpy.S Sat Mar 30 22:55:26 2002 @@ -4,407 +4,445 @@ * for more details. * * Unified implementation of memcpy, memmove and the __copy_user backend. - * For __rmemcpy and memmove an exception is always a kernel bug, therefore - * they're not protected. In order to keep the exception fixup routine - * simple all memory accesses in __copy_user to src rsp. dst are stricly - * incremental. The fixup routine depends on $at not being changed. + * + * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc. + * Copyright (C) 2002 Broadcom, Inc. + * memcpy/copy_user author: Mark Vandevoorde + * + * Mnemonic names for arguments to memcpy/__copy_user */ #include #include #include +#include + +#define dst a0 +#define src a1 +#define len a2 /* - * The fixup routine for copy_to_user depends on copying strictly in - * increasing order. Gas expands the ulw/usw macros in the wrong order for - * little endian machines, so we cannot depend on them. + * Spec + * + * memcpy copies len bytes from src to dst and sets v0 to dst. + * It assumes that + * - src and dst don't overlap + * - src is readable + * - dst is writable + * memcpy uses the standard calling convention + * + * __copy_user copies up to len bytes from src to dst and sets a2 (len) to + * the number of uncopied bytes due to an exception caused by a read or write. + * __copy_user assumes that src and dst don't overlap, and that the call is + * implementing one of the following: + * copy_to_user + * - src is readable (no exceptions when reading src) + * copy_from_user + * - dst is writable (no exceptions when writing dst) + * __copy_user uses a non-standard calling convention; see + * include/asm-mips/uaccess.h + * + * When an exception happens on a load, the handler must + # ensure that all of the destination buffer is overwritten to prevent + * leaking information to user mode programs. */ -#ifdef __MIPSEB__ -#define uswL swl -#define uswU swr -#define ulwL lwl -#define ulwU lwr -#endif -#ifdef __MIPSEL__ -#define uswL swr -#define uswU swl -#define ulwL lwr -#define ulwU lwl -#endif -#define EX(insn,reg,addr,handler) \ -9: insn reg, addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - .previous +/* + * Implementation + */ -#define UEX(insn,reg,addr,handler) \ -9: insn ## L reg, addr; \ -10: insn ## U reg, 3 + addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - PTR 10b, handler; \ +/* + * The exception handler for loads requires that: + * 1- AT contain the address of the byte just past the end of the source + * of the copy, + * 2- src_entry <= src < AT, and + * 3- (dst - src) == (dst_entry - src_entry), + * The _entry suffix denotes values when __copy_user was called. + * + * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user + * (2) is met by incrementing src by the number of bytes copied + * (3) is met by not doing loads between a pair of increments of dst and src + * + * The exception handlers for stores adjust len (if necessary) and return. + * These handlers do not need to overwrite any data. + * + * For __rmemcpy and memmove an exception is always a kernel bug, therefore + * they're not protected. + */ + +#define EXC(inst_reg,addr,handler) \ +9: inst_reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ .previous -/* ascending order, destination aligned */ -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - EX(lw, t0, (offset + 0x00)(src), l_fixup); \ - EX(lw, t1, (offset + 0x04)(src), l_fixup); \ - EX(lw, t2, (offset + 0x08)(src), l_fixup); \ - EX(lw, t3, (offset + 0x0c)(src), l_fixup); \ - EX(sw, t0, (offset + 0x00)(dst), s_fixup); \ - EX(sw, t1, (offset + 0x04)(dst), s_fixup); \ - EX(sw, t2, (offset + 0x08)(dst), s_fixup); \ - EX(sw, t3, (offset + 0x0c)(dst), s_fixup); \ - EX(lw, t0, (offset + 0x10)(src), l_fixup); \ - EX(lw, t1, (offset + 0x14)(src), l_fixup); \ - EX(lw, t2, (offset + 0x18)(src), l_fixup); \ - EX(lw, t3, (offset + 0x1c)(src), l_fixup); \ - EX(sw, t0, (offset + 0x10)(dst), s_fixup); \ - EX(sw, t1, (offset + 0x14)(dst), s_fixup); \ - EX(sw, t2, (offset + 0x18)(dst), s_fixup); \ - EX(sw, t3, (offset + 0x1c)(dst), s_fixup) - -/* ascending order, destination unaligned */ -#define UMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - EX(lw, t0, (offset + 0x00)(src), l_fixup); \ - EX(lw, t1, (offset + 0x04)(src), l_fixup); \ - EX(lw, t2, (offset + 0x08)(src), l_fixup); \ - EX(lw, t3, (offset + 0x0c)(src), l_fixup); \ - UEX(usw, t0, (offset + 0x00)(dst), s_fixup); \ - UEX(usw, t1, (offset + 0x04)(dst), s_fixup); \ - UEX(usw, t2, (offset + 0x08)(dst), s_fixup); \ - UEX(usw, t3, (offset + 0x0c)(dst), s_fixup); \ - EX(lw, t0, (offset + 0x10)(src), l_fixup); \ - EX(lw, t1, (offset + 0x14)(src), l_fixup); \ - EX(lw, t2, (offset + 0x18)(src), l_fixup); \ - EX(lw, t3, (offset + 0x1c)(src), l_fixup); \ - UEX(usw, t0, (offset + 0x10)(dst), s_fixup); \ - UEX(usw, t1, (offset + 0x14)(dst), s_fixup); \ - UEX(usw, t2, (offset + 0x18)(dst), s_fixup); \ - UEX(usw, t3, (offset + 0x1c)(dst), s_fixup) +/* + * In the mips (not mips64) tree, so we can't use doubles + */ +#undef USE_DOUBLE + +#if defined(USE_DOUBLE) + +#define LOAD ld +#define LOADL ldl +#define LOADR ldr +#define STOREL sdl +#define STORER sdr +#define STORE sd +#define ADD daddu +#define SUB dsubu +#define SRL dsrl +#define SRA dsra +#define SLL dsll +#define SLLV dsllv +#define SRLV dsrlv +#define NBYTES 8 +#define LOG_NBYTES 3 + +#else + +#define LOAD lw +#define LOADL lwl +#define LOADR lwr +#define STOREL swl +#define STORER swr +#define STORE sw +#define ADD addu +#define SUB subu +#define SRL srl +#define SLL sll +#define SRA sra +#define SLLV sllv +#define SRLV srlv +#define NBYTES 4 +#define LOG_NBYTES 2 + +#endif /* USE_DOUBLE */ + +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define LDFIRST LOADR +#define LDREST LOADL +#define STFIRST STORER +#define STREST STOREL +#define SHIFT_DISCARD SLLV +#else +#define LDFIRST LOADL +#define LDREST LOADR +#define STFIRST STOREL +#define STREST STORER +#define SHIFT_DISCARD SRLV +#endif + +#define FIRST(unit) ((unit)*NBYTES) +#define REST(unit) (FIRST(unit)+NBYTES-1) +#define UNIT(unit) FIRST(unit) + +#define ADDRMASK (NBYTES-1) .text .set noreorder .set noat +/* + * A combined memcpy/__copy_user + * __copy_user sets len to 0 for success; else to an upper bound of + * the number of uncopied bytes. + * memcpy sets v0 to dst. + */ .align 5 LEAF(memcpy) /* a0=dst a1=src a2=len */ - move v0, a0 /* return value */ + move v0, dst /* return value */ __memcpy: -EXPORT(__copy_user) - xor t0, a0, a1 - andi t0, t0, 0x3 - move t7, a0 - beqz t0, can_align - sltiu t8, a2, 0x8 - - b memcpy_u_src # bad alignment - move t2, a2 - -can_align: - bnez t8, small_memcpy # < 8 bytes to copy - move t2, a2 - - beqz a2, out - andi t8, a1, 0x1 - -hword_align: - beqz t8, word_align - andi t8, a1, 0x2 - - EX(lb, t0, (a1), l_fixup) - subu a2, a2, 0x1 - EX(sb, t0, (a0), s_fixup) - addu a1, a1, 0x1 - addu a0, a0, 0x1 - andi t8, a1, 0x2 - -word_align: - beqz t8, dword_align - sltiu t8, a2, 56 - - EX(lh, t0, (a1), l_fixup) - subu a2, a2, 0x2 - EX(sh, t0, (a0), s_fixup) - sltiu t8, a2, 56 - addu a0, a0, 0x2 - addu a1, a1, 0x2 - -dword_align: - bnez t8, do_end_words - move t8, a2 - - andi t8, a1, 0x4 - beqz t8, qword_align - andi t8, a1, 0x8 - - EX(lw, t0, 0x00(a1), l_fixup) - subu a2, a2, 0x4 - EX(sw, t0, 0x00(a0), s_fixup) - addu a1, a1, 0x4 - addu a0, a0, 0x4 - andi t8, a1, 0x8 - -qword_align: - beqz t8, oword_align - andi t8, a1, 0x10 - - EX(lw, t0, 0x00(a1), l_fixup) - EX(lw, t1, 0x04(a1), l_fixup) - subu a2, a2, 0x8 - EX(sw, t0, 0x00(a0), s_fixup) - EX(sw, t1, 0x04(a0), s_fixup) - addu a1, a1, 0x8 - andi t8, a1, 0x10 - addu a0, a0, 0x8 - -oword_align: - beqz t8, begin_movement - srl t8, a2, 0x7 - - EX(lw, t3, 0x00(a1), l_fixup) - EX(lw, t4, 0x04(a1), l_fixup) - EX(lw, t0, 0x08(a1), l_fixup) - EX(lw, t1, 0x0c(a1), l_fixup) - EX(sw, t3, 0x00(a0), s_fixup) - EX(sw, t4, 0x04(a0), s_fixup) - EX(sw, t0, 0x08(a0), s_fixup) - EX(sw, t1, 0x0c(a0), s_fixup) - subu a2, a2, 0x10 - addu a1, a1, 0x10 - srl t8, a2, 0x7 - addu a0, a0, 0x10 - -begin_movement: - beqz t8, 0f - andi t2, a2, 0x40 - -move_128bytes: - MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - MOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - MOVE_BIGCHUNK(a1, a0, 0x40, t0, t1, t3, t4) - MOVE_BIGCHUNK(a1, a0, 0x60, t0, t1, t3, t4) - subu t8, t8, 0x01 - addu a1, a1, 0x80 - bnez t8, move_128bytes - addu a0, a0, 0x80 - -0: - beqz t2, 1f - andi t2, a2, 0x20 - -move_64bytes: - MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - MOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - addu a1, a1, 0x40 - addu a0, a0, 0x40 - +FEXPORT(__copy_user) + /* + * Note: dst & src may be unaligned, len may be 0 + * Temps + */ +#define rem t8 + + /* + * The "issue break"s below are very approximate. + * Issue delays for dcache fills will perturb the schedule, as will + * load queue full replay traps, etc. + * + * If len < NBYTES use byte operations. + */ + PREF( 0, 0(src) ) + PREF( 1, 0(dst) ) + sltu t2, len, NBYTES + and t1, dst, ADDRMASK + PREF( 0, 1*32(src) ) + PREF( 1, 1*32(dst) ) + bnez t2, copy_bytes_checklen + and t0, src, ADDRMASK + PREF( 0, 2*32(src) ) + PREF( 1, 2*32(dst) ) + bnez t1, dst_unaligned + nop + bnez t0, src_unaligned_dst_aligned + /* + * use delay slot for fall-through + * src and dst are aligned; need to compute rem + */ +both_aligned: + SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter + beqz t0, cleanup_both_aligned # len < 8*NBYTES + and rem, len, (8*NBYTES-1) # rem = len % (8*NBYTES) + PREF( 0, 3*32(src) ) + PREF( 1, 3*32(dst) ) + .align 4 1: - beqz t2, do_end_words - andi t8, a2, 0x1c - -move_32bytes: - MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - andi t8, a2, 0x1c - addu a1, a1, 0x20 - addu a0, a0, 0x20 - -do_end_words: - beqz t8, maybe_end_cruft - srl t8, t8, 0x2 - -end_words: - EX(lw, t0, (a1), l_fixup) - subu t8, t8, 0x1 - EX(sw, t0, (a0), s_fixup) - addu a1, a1, 0x4 - bnez t8, end_words - addu a0, a0, 0x4 - -maybe_end_cruft: - andi t2, a2, 0x3 - -small_memcpy: - beqz t2, out - move a2, t2 - -end_bytes: - EX(lb, t0, (a1), l_fixup) - subu a2, a2, 0x1 - EX(sb, t0, (a0), s_fixup) - addu a1, a1, 0x1 - bnez a2, end_bytes - addu a0, a0, 0x1 - -out: jr ra - move a2, zero - -/* ------------------------------------------------------------------------- */ +EXC( LOAD t0, UNIT(0)(src), l_exc) +EXC( LOAD t1, UNIT(1)(src), l_exc_copy) +EXC( LOAD t2, UNIT(2)(src), l_exc_copy) +EXC( LOAD t3, UNIT(3)(src), l_exc_copy) + SUB len, len, 8*NBYTES +EXC( LOAD t4, UNIT(4)(src), l_exc_copy) +EXC( LOAD t7, UNIT(5)(src), l_exc_copy) +EXC( STORE t0, UNIT(0)(dst), s_exc_p8u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p7u) +EXC( LOAD t0, UNIT(6)(src), l_exc_copy) +EXC( LOAD t1, UNIT(7)(src), l_exc_copy) + ADD src, src, 8*NBYTES + ADD dst, dst, 8*NBYTES +EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u) +EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u) +EXC( STORE t4, UNIT(-4)(dst), s_exc_p4u) +EXC( STORE t7, UNIT(-3)(dst), s_exc_p3u) +EXC( STORE t0, UNIT(-2)(dst), s_exc_p2u) +EXC( STORE t1, UNIT(-1)(dst), s_exc_p1u) + PREF( 0, 8*32(src) ) + PREF( 1, 8*32(dst) ) + bne len, rem, 1b + nop -/* Bad, bad. At least try to align the source */ + /* + * len == rem == the number of bytes left to copy < 8*NBYTES + */ +cleanup_both_aligned: + beqz len, done + sltu t0, len, 4*NBYTES + bnez t0, less_than_4units + and rem, len, (NBYTES-1) # rem = len % NBYTES + /* + * len >= 4*NBYTES + */ +EXC( LOAD t0, UNIT(0)(src), l_exc) +EXC( LOAD t1, UNIT(1)(src), l_exc_copy) +EXC( LOAD t2, UNIT(2)(src), l_exc_copy) +EXC( LOAD t3, UNIT(3)(src), l_exc_copy) + SUB len, len, 4*NBYTES + ADD src, src, 4*NBYTES +EXC( STORE t0, UNIT(0)(dst), s_exc_p4u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) +EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) +EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) + beqz len, done + ADD dst, dst, 4*NBYTES +less_than_4units: + /* + * rem = len % NBYTES + */ + beq rem, len, copy_bytes + nop +1: +EXC( LOAD t0, 0(src), l_exc) + ADD src, src, NBYTES + SUB len, len, NBYTES +EXC( STORE t0, 0(dst), s_exc) + bne rem, len, 1b + ADD dst, dst, NBYTES + + /* + * src and dst are aligned, need to copy rem bytes (rem < NBYTES) + * A loop would do only a byte at a time with possible branch + * mispredicts. Can't do an explicit LOAD dst,mask,or,STORE + * because can't assume read-access to dst. Instead, use + * STREST dst, which doesn't require read access to dst. + * + * This code should perform better than a simple loop on modern, + * wide-issue mips processors because the code has fewer branches and + * more instruction-level parallelism. + */ +#define bits t2 + beqz len, done + ADD t1, dst, len # t1 is just past last byte of dst + li bits, 8*NBYTES + SLL rem, len, 3 # rem = number of bits to keep +EXC( LOAD t0, 0(src), l_exc) + SUB bits, bits, rem # bits = number of bits to discard + SHIFT_DISCARD t0, t0, bits +EXC( STREST t0, -1(t1), s_exc) + jr ra + move len, zero +dst_unaligned: + /* + * dst is unaligned + * t0 = src & ADDRMASK + * t1 = dst & ADDRMASK; T1 > 0 + * len >= NBYTES + * + * Copy enough bytes to align dst + * Set match = (src and dst have same alignment) + */ +#define match rem +EXC( LDFIRST t3, FIRST(0)(src), l_exc) + ADD t2, zero, NBYTES +EXC( LDREST t3, REST(0)(src), l_exc_copy) + SUB t2, t2, t1 # t2 = number of bytes copied + xor match, t0, t1 +EXC( STFIRST t3, FIRST(0)(dst), s_exc) + beq len, t2, done + SUB len, len, t2 + ADD dst, dst, t2 + beqz match, both_aligned + ADD src, src, t2 + +src_unaligned_dst_aligned: + SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter + PREF( 0, 3*32(src) ) + beqz t0, cleanup_src_unaligned + and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES + PREF( 1, 3*32(dst) ) +1: +/* + * Avoid consecutive LD*'s to the same register since some mips + * implementations can't issue them in the same cycle. + * It's OK to load FIRST(N+1) before REST(N) because the two addresses + * are to the same unit (unless src is aligned, but it's not). + */ +EXC( LDFIRST t0, FIRST(0)(src), l_exc) +EXC( LDFIRST t1, FIRST(1)(src), l_exc_copy) + SUB len, len, 4*NBYTES +EXC( LDREST t0, REST(0)(src), l_exc_copy) +EXC( LDREST t1, REST(1)(src), l_exc_copy) +EXC( LDFIRST t2, FIRST(2)(src), l_exc_copy) +EXC( LDFIRST t3, FIRST(3)(src), l_exc_copy) +EXC( LDREST t2, REST(2)(src), l_exc_copy) +EXC( LDREST t3, REST(3)(src), l_exc_copy) + PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed) + ADD src, src, 4*NBYTES +#ifdef CONFIG_CPU_SB1 + nop # improves slotting +#endif +EXC( STORE t0, UNIT(0)(dst), s_exc_p4u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) +EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) +EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) + PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) + bne len, rem, 1b + ADD dst, dst, 4*NBYTES + +cleanup_src_unaligned: + beqz len, done + and rem, len, NBYTES-1 # rem = len % NBYTES + beq rem, len, copy_bytes +1: +EXC( LDFIRST t0, FIRST(0)(src), l_exc) +EXC( LDREST t0, REST(0)(src), l_exc_copy) + ADD src, src, NBYTES + SUB len, len, NBYTES +EXC( STORE t0, 0(dst), s_exc_p1u) + bne len, rem, 1b + ADD dst, dst, NBYTES -memcpy_u_src: - bnez t8, small_memcpy # < 8 bytes? - move t2, a2 - - addiu t0, a1, 7 # t0: how much to align - ori t0, 7 - xori t0, 7 - subu t0, a1 - - UEX(ulw, t1, 0(a1), l_fixup) # dword alignment - UEX(ulw, t2, 4(a1), l_fixup) - UEX(usw, t1, 0(a0), s_fixup) - UEX(usw, t2, 4(a0), s_fixup) - - addu a1, t0 # src - addu a0, t0 # dst - subu a2, t0 # len - - sltiu t8, a2, 56 - bnez t8, u_do_end_words - andi t8, a2, 0x3c - - andi t8, a1, 8 # now qword aligned? - -u_qword_align: - beqz t8, u_oword_align - andi t8, a1, 0x10 - - EX(lw, t0, 0x00(a1), l_fixup) - EX(lw, t1, 0x04(a1), l_fixup) - subu a2, a2, 0x8 - UEX(usw, t0, 0x00(a0), s_fixup) - UEX(usw, t1, 0x04(a0), s_fixup) - addu a1, a1, 0x8 - andi t8, a1, 0x10 - addu a0, a0, 0x8 - -u_oword_align: - beqz t8, u_begin_movement - srl t8, a2, 0x7 - - EX(lw, t3, 0x08(a1), l_fixup) - EX(lw, t4, 0x0c(a1), l_fixup) - EX(lw, t0, 0x00(a1), l_fixup) - EX(lw, t1, 0x04(a1), l_fixup) - UEX(usw, t3, 0x08(a0), s_fixup) - UEX(usw, t4, 0x0c(a0), s_fixup) - UEX(usw, t0, 0x00(a0), s_fixup) - UEX(usw, t1, 0x04(a0), s_fixup) - subu a2, a2, 0x10 - addu a1, a1, 0x10 - srl t8, a2, 0x7 - addu a0, a0, 0x10 - -u_begin_movement: - beqz t8, 0f - andi t2, a2, 0x40 - -u_move_128bytes: - UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - UMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - UMOVE_BIGCHUNK(a1, a0, 0x40, t0, t1, t3, t4) - UMOVE_BIGCHUNK(a1, a0, 0x60, t0, t1, t3, t4) - subu t8, t8, 0x01 - addu a1, a1, 0x80 - bnez t8, u_move_128bytes - addu a0, a0, 0x80 - -0: - beqz t2, 1f - andi t2, a2, 0x20 - -u_move_64bytes: - UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - UMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - addu a1, a1, 0x40 - addu a0, a0, 0x40 +copy_bytes_checklen: + beqz len, done + nop +copy_bytes: + /* 0 < len < NBYTES */ +#define COPY_BYTE(N) \ +EXC( lb t0, N(src), l_exc); \ + SUB len, len, 1; \ + beqz len, done; \ +EXC( sb t0, N(dst), s_exc_p1) + + COPY_BYTE(0) + COPY_BYTE(1) +#ifdef USE_DOUBLE + COPY_BYTE(2) + COPY_BYTE(3) + COPY_BYTE(4) + COPY_BYTE(5) +#endif +EXC( lb t0, NBYTES-2(src), l_exc) + SUB len, len, 1 + jr ra +EXC( sb t0, NBYTES-2(dst), s_exc_p1) +done: + jr ra + nop + END(memcpy) +l_exc_copy: + /* + * Copy bytes from src until faulting load address (or until a + * lb faults) + * + * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28) + * may be more than a byte beyond the last address. + * Hence, the lb below may get an exception. + * + * Assumes src < THREAD_BUADDR($28) + */ + lw t0, THREAD_BUADDR($28) 1: - beqz t2, u_do_end_words - andi t8, a2, 0x1c +EXC( lb t1, 0(src), l_exc) + ADD src, src, 1 + sb t1, 0(dst) # can't fault -- we're copy_from_user + bne src, t0, 1b + ADD dst, dst, 1 +l_exc: + lw t0, THREAD_BUADDR($28) # t0 is just past last good address + nop + subu len, AT, t0 # len number of uncopied bytes + /* + * Here's where we rely on src and dst being incremented in tandem, + * See (3) above. + * dst += (fault addr - src) to put dst at first byte to clear + */ + addu dst, t0 # compute start address in a1 + subu dst, src + /* + * Clear len bytes starting at dst. Can't call __bzero because it + * might modify len. An inefficient loop for these rare times... + */ + beqz len, done + SUB src, len, 1 +1: sb zero, 0(dst) + ADD dst, dst, 1 + bnez src, 1b + SUB src, src, 1 + jr ra + nop -u_move_32bytes: - UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - andi t8, a2, 0x1c - addu a1, a1, 0x20 - addu a0, a0, 0x20 - -u_do_end_words: - beqz t8, u_maybe_end_cruft - srl t8, t8, 0x2 - -u_end_words: - EX(lw, t0, 0x00(a1), l_fixup) - subu t8, t8, 0x1 - UEX(usw, t0, 0x00(a0), s_fixup) - addu a1, a1, 0x4 - bnez t8, u_end_words - addu a0, a0, 0x4 - -u_maybe_end_cruft: - andi t2, a2, 0x3 - -u_cannot_optimize: - beqz t2, out - move a2, t2 -u_end_bytes: - EX(lb, t0, (a1), l_fixup) - subu a2, a2, 0x1 - EX(sb, t0, (a0), s_fixup) - addu a1, a1, 0x1 - bnez a2, u_end_bytes - addu a0, a0, 0x1 +#define SEXC(n) \ +s_exc_p ## n ## u: \ + jr ra; \ + ADD len, len, n*NBYTES + +SEXC(8) +SEXC(7) +SEXC(6) +SEXC(5) +SEXC(4) +SEXC(3) +SEXC(2) +SEXC(1) +s_exc_p1: jr ra - move a2, zero - END(memcpy) - -/* descending order, destination aligned */ -#define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lw t0, (offset + 0x10)(src); \ - lw t1, (offset + 0x14)(src); \ - lw t2, (offset + 0x18)(src); \ - lw t3, (offset + 0x1c)(src); \ - sw t0, (offset + 0x10)(dst); \ - sw t1, (offset + 0x14)(dst); \ - sw t2, (offset + 0x18)(dst); \ - sw t3, (offset + 0x1c)(dst); \ - lw t0, (offset + 0x00)(src); \ - lw t1, (offset + 0x04)(src); \ - lw t2, (offset + 0x08)(src); \ - lw t3, (offset + 0x0c)(src); \ - sw t0, (offset + 0x00)(dst); \ - sw t1, (offset + 0x04)(dst); \ - sw t2, (offset + 0x08)(dst); \ - sw t3, (offset + 0x0c)(dst) - -/* descending order, destination ununaligned */ -#define RUMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lw t0, (offset + 0x10)(src); \ - lw t1, (offset + 0x14)(src); \ - lw t2, (offset + 0x18)(src); \ - lw t3, (offset + 0x1c)(src); \ - usw t0, (offset + 0x10)(dst); \ - usw t1, (offset + 0x14)(dst); \ - usw t2, (offset + 0x18)(dst); \ - usw t3, (offset + 0x1c)(dst); \ - lw t0, (offset + 0x00)(src); \ - lw t1, (offset + 0x04)(src); \ - lw t2, (offset + 0x08)(src); \ - lw t3, (offset + 0x0c)(src); \ - usw t0, (offset + 0x00)(dst); \ - usw t1, (offset + 0x04)(dst); \ - usw t2, (offset + 0x08)(dst); \ - usw t3, (offset + 0x0c)(dst) + ADD len, len, 1 +s_exc: + jr ra + nop .align 5 LEAF(memmove) addu t0, a0, a2 - sltu t0, a1, t0 # dst + len <= src -> memcpy addu t1, a1, a2 + sltu t0, a1, t0 # dst + len <= src -> memcpy sltu t1, a0, t1 # dst >= src + len -> memcpy and t0, t1 beqz t0, __memcpy @@ -412,152 +450,14 @@ beqz a2, r_out END(memmove) + /* fall through to __rmemcpy */ LEAF(__rmemcpy) /* a0=dst a1=src a2=len */ - sltu t0, a1, a0 + sltu t0, a1, a0 beqz t0, r_end_bytes_up # src >= dst nop addu a0, a2 # dst = dst + len addu a1, a2 # src = src + len -#if 0 /* Horror fix */ - xor t0, a0, a1 - andi t0, t0, 0x3 - move t7, a0 - beqz t0, r_can_align - sltiu t8, a2, 0x8 - - b r_memcpy_u_src # bad alignment - move t2, a2 - -r_can_align: - bnez t8, r_small_memcpy # < 8 bytes to copy - move t2, a2 - - beqz a2, r_out - andi t8, a1, 0x1 - -r_hword_align: - beqz t8, r_word_align - andi t8, a1, 0x2 - - lb t0, -1(a1) - subu a2, a2, 0x1 - sb t0, -1(a0) - subu a1, a1, 0x1 - subu a0, a0, 0x1 - andi t8, a1, 0x2 - -r_word_align: - beqz t8, r_dword_align - sltiu t8, a2, 56 - - lh t0, -2(a1) - subu a2, a2, 0x2 - sh t0, -2(a0) - sltiu t8, a2, 56 - subu a0, a0, 0x2 - subu a1, a1, 0x2 - -r_dword_align: - bnez t8, r_do_end_words - move t8, a2 - - andi t8, a1, 0x4 - beqz t8, r_qword_align - andi t8, a1, 0x8 - - lw t0, -4(a1) - subu a2, a2, 0x4 - sw t0, -4(a0) - subu a1, a1, 0x4 - subu a0, a0, 0x4 - andi t8, a1, 0x8 - -r_qword_align: - beqz t8, r_oword_align - andi t8, a1, 0x10 - - subu a1, a1, 0x8 - lw t0, 0x04(a1) - lw t1, 0x00(a1) - subu a0, a0, 0x8 - sw t0, 0x04(a0) - sw t1, 0x00(a0) - subu a2, a2, 0x8 - - andi t8, a1, 0x10 - -r_oword_align: - beqz t8, r_begin_movement - srl t8, a2, 0x7 - - subu a1, a1, 0x10 - lw t3, 0x08(a1) # assumes subblock ordering - lw t4, 0x0c(a1) - lw t0, 0x00(a1) - lw t1, 0x04(a1) - subu a0, a0, 0x10 - sw t3, 0x08(a0) - sw t4, 0x0c(a0) - sw t0, 0x00(a0) - sw t1, 0x04(a0) - subu a2, a2, 0x10 - srl t8, a2, 0x7 - -r_begin_movement: - beqz t8, 0f - andi t2, a2, 0x40 - -r_move_128bytes: - RMOVE_BIGCHUNK(a1, a0, -0x80, t0, t1, t3, t4) - RMOVE_BIGCHUNK(a1, a0, -0x60, t0, t1, t3, t4) - RMOVE_BIGCHUNK(a1, a0, -0x40, t0, t1, t3, t4) - RMOVE_BIGCHUNK(a1, a0, -0x20, t0, t1, t3, t4) - subu t8, t8, 0x01 - subu a1, a1, 0x80 - bnez t8, r_move_128bytes - subu a0, a0, 0x80 - -0: - beqz t2, 1f - andi t2, a2, 0x20 - -r_move_64bytes: - subu a1, a1, 0x40 - subu a0, a0, 0x40 - RMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - RMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - -1: - beqz t2, r_do_end_words - andi t8, a2, 0x1c - -r_move_32bytes: - subu a1, a1, 0x20 - subu a0, a0, 0x20 - RMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - andi t8, a2, 0x1c - -r_do_end_words: - beqz t8, r_maybe_end_cruft - srl t8, t8, 0x2 - -r_end_words: - lw t0, -4(a1) - subu t8, t8, 0x1 - sw t0, -4(a0) - subu a1, a1, 0x4 - bnez t8, r_end_words - subu a0, a0, 0x4 - -r_maybe_end_cruft: - andi t2, a2, 0x3 - -r_small_memcpy: - beqz t2, r_out - move a2, t2 -#endif /* Horror fix */ - r_end_bytes: lb t0, -1(a1) subu a2, a2, 0x1 @@ -580,140 +480,4 @@ jr ra move a2, zero - -#if 0 /* Horror fix */ -/* ------------------------------------------------------------------------- */ - -/* Bad, bad. At least try to align the source */ - -r_memcpy_u_src: - bnez t8, r_small_memcpy # < 8 bytes? - move t2, a2 - - andi t0, a1, 7 # t0: how much to align - - ulw t1, -8(a1) # dword alignment - ulw t2, -4(a1) - usw t1, -8(a0) - usw t2, -4(a0) - - subu a1, t0 # src - subu a0, t0 # dst - subu a2, t0 # len - - sltiu t8, a2, 56 - bnez t8, ru_do_end_words - andi t8, a2, 0x3c - - andi t8, a1, 8 # now qword aligned? - -ru_qword_align: - beqz t8, ru_oword_align - andi t8, a1, 0x10 - - subu a1, a1, 0x8 - lw t0, 0x00(a1) - lw t1, 0x04(a1) - subu a0, a0, 0x8 - usw t0, 0x00(a0) - usw t1, 0x04(a0) - subu a2, a2, 0x8 - - andi t8, a1, 0x10 - -ru_oword_align: - beqz t8, ru_begin_movement - srl t8, a2, 0x7 - - subu a1, a1, 0x10 - lw t3, 0x08(a1) # assumes subblock ordering - lw t4, 0x0c(a1) - lw t0, 0x00(a1) - lw t1, 0x04(a1) - subu a0, a0, 0x10 - usw t3, 0x08(a0) - usw t4, 0x0c(a0) - usw t0, 0x00(a0) - usw t1, 0x04(a0) - subu a2, a2, 0x10 - - srl t8, a2, 0x7 - -ru_begin_movement: - beqz t8, 0f - andi t2, a2, 0x40 - -ru_move_128bytes: - RUMOVE_BIGCHUNK(a1, a0, -0x80, t0, t1, t3, t4) - RUMOVE_BIGCHUNK(a1, a0, -0x60, t0, t1, t3, t4) - RUMOVE_BIGCHUNK(a1, a0, -0x40, t0, t1, t3, t4) - RUMOVE_BIGCHUNK(a1, a0, -0x20, t0, t1, t3, t4) - subu t8, t8, 0x01 - subu a1, a1, 0x80 - bnez t8, ru_move_128bytes - subu a0, a0, 0x80 - -0: - beqz t2, 1f - andi t2, a2, 0x20 - -ru_move_64bytes: - subu a1, a1, 0x40 - subu a0, a0, 0x40 - RUMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4) - RUMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - -1: - beqz t2, ru_do_end_words - andi t8, a2, 0x1c - -ru_move_32bytes: - subu a1, a1, 0x20 - subu a0, a0, 0x20 - RUMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4) - andi t8, a2, 0x1c - -ru_do_end_words: - beqz t8, ru_maybe_end_cruft - srl t8, t8, 0x2 - -ru_end_words: - lw t0, -4(a1) - usw t0, -4(a0) - subu t8, t8, 0x1 - subu a1, a1, 0x4 - bnez t8, ru_end_words - subu a0, a0, 0x4 - -ru_maybe_end_cruft: - andi t2, a2, 0x3 - -ru_cannot_optimize: - beqz t2, r_out - move a2, t2 - -ru_end_bytes: - lb t0, -1(a1) - subu a2, a2, 0x1 - sb t0, -1(a0) - subu a1, a1, 0x1 - bnez a2, ru_end_bytes - subu a0, a0, 0x1 - - jr ra - move a2, zero -#endif /* Horror fix */ END(__rmemcpy) - -l_fixup: # clear the rest of the buffer - lw t0, THREAD_BUADDR($28) - nop - subu a2, AT, t0 # a2 bytes to go - addu a0, t0 # compute start address in a1 - subu a0, a1 - j __bzero - move a1, zero - -s_fixup: - jr ra - nop diff -urN linux-2.4.18/arch/mips/lib/r3k_dump_tlb.c linux-2.4.19-pre5/arch/mips/lib/r3k_dump_tlb.c --- linux-2.4.18/arch/mips/lib/r3k_dump_tlb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/r3k_dump_tlb.c Sat Mar 30 22:55:26 2002 @@ -12,11 +12,12 @@ #include #include +#include #include #include #include -#define mips_tlb_entries 64 +extern int r3k_have_wired_reg; /* defined in tlb-r3k.c */ void dump_tlb(int first, int last) @@ -65,16 +66,16 @@ void dump_tlb_all(void) { - dump_tlb(0, mips_tlb_entries - 1); + dump_tlb(0, mips_cpu.tlbsize - 1); } void dump_tlb_wired(void) { - int wired = 7; + int wired = r3k_have_wired_reg ? get_wired() : 8; printk("Wired: %d", wired); - dump_tlb(0, read_32bit_cp0_register(CP0_WIRED)); + dump_tlb(0, wired - 1); } void @@ -103,7 +104,8 @@ void dump_tlb_nonwired(void) { - dump_tlb(8, mips_tlb_entries - 1); + int wired = r3k_have_wired_reg ? get_wired() : 8; + dump_tlb(wired, mips_cpu.tlbsize - 1); } void diff -urN linux-2.4.18/arch/mips/lib/strlen_user.S linux-2.4.19-pre5/arch/mips/lib/strlen_user.S --- linux-2.4.18/arch/mips/lib/strlen_user.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/strlen_user.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: strlen_user.S,v 1.3 1999/08/21 22:19:11 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -35,7 +34,7 @@ bnez t0, 1b subu v0, a0 jr ra - END(__strlen_user_nocheck_asm) + END(__strlen_user_asm) .section __ex_table,"a" PTR 1b, fault diff -urN linux-2.4.18/arch/mips/lib/strncpy_user.S linux-2.4.19-pre5/arch/mips/lib/strncpy_user.S --- linux-2.4.18/arch/mips/lib/strncpy_user.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/strncpy_user.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: strncpy_user.S,v 1.3 1999/08/21 22:19:11 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/strnlen_user.S linux-2.4.19-pre5/arch/mips/lib/strnlen_user.S --- linux-2.4.18/arch/mips/lib/strnlen_user.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/strnlen_user.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id: strnlen_user.S,v 1.2 1999/11/19 20:35:21 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/lib/watch.S linux-2.4.19-pre5/arch/mips/lib/watch.S --- linux-2.4.18/arch/mips/lib/watch.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/lib/watch.S Sat Mar 30 22:55:26 2002 @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/math-emu/cp1emu.c linux-2.4.19-pre5/arch/mips/math-emu/cp1emu.c --- linux-2.4.18/arch/mips/math-emu/cp1emu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/cp1emu.c Sat Mar 30 22:55:26 2002 @@ -173,7 +173,7 @@ if (!user_mode(xcp)) { *perr = 0; - return (*(unsigned long *) va); + return *(unsigned long *) va; } *perr = (int) get_user(temp, (unsigned long *) va); @@ -187,7 +187,7 @@ if (!user_mode(xcp)) { *perr = 0; - return (*(unsigned long long *) va); + return *(unsigned long long *) va; } *perr = (int) get_user(temp, (unsigned long long *) va); @@ -230,7 +230,7 @@ * Two instructions if the instruction is in a branch delay slot. */ -static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) +static int cop1Emulate(struct pt_regs *regs, struct mips_fpu_soft_struct *ctx) { mips_instruction ir; vaddr_t emulpc; @@ -238,17 +238,17 @@ unsigned int cond; int err = 0; - ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err); + ir = mips_get_word(regs, REG_TO_VA regs->cp0_epc, &err); if (err) { fpuemuprivate.stats.errors++; return SIGBUS; } /* XXX NEC Vr54xx bug workaround */ - if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) - xcp->cp0_cause &= ~CAUSEF_BD; + if ((regs->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) + regs->cp0_cause &= ~CAUSEF_BD; - if (xcp->cp0_cause & CAUSEF_BD) { + if (regs->cp0_cause & CAUSEF_BD) { /* * The instruction to be emulated is in a branch delay slot * which means that we have to emulate the branch instruction @@ -261,24 +261,27 @@ * Linux MIPS branch emulator operates on context, updating the * cp0_epc. */ - emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */ + emulpc = REG_TO_VA(regs->cp0_epc + 4); /* Snapshot emulation target */ - if (__compute_return_epc(xcp)) { + if (__compute_return_epc(regs)) { #ifdef CP1DBG printk("failed to emulate branch at %p\n", - REG_TO_VA(xcp->cp0_epc)); + REG_TO_VA(regs->cp0_epc)); #endif - return SIGILL;; + return SIGILL; } - ir = mips_get_word(xcp, emulpc, &err); + ir = mips_get_word(regs, emulpc, &err); if (err) { fpuemuprivate.stats.errors++; return SIGBUS; } - contpc = REG_TO_VA xcp->cp0_epc; + /* __computer_return_epc() will have updated cp0_epc */ + contpc = REG_TO_VA regs->cp0_epc; + /* In order not to confuse ptrace() et al, tweak context */ + regs->cp0_epc = VA_TO_REG emulpc - 4; } else { - emulpc = REG_TO_VA xcp->cp0_epc; - contpc = REG_TO_VA xcp->cp0_epc + 4; + emulpc = REG_TO_VA regs->cp0_epc; + contpc = REG_TO_VA regs->cp0_epc + 4; } emul: @@ -289,12 +292,12 @@ #ifndef SINGLE_ONLY_FPU case ldc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); int ft = MIPSInst_RT(ir); - if (!(xcp->cp0_status & ST0_FR)) + if (!(regs->cp0_status & ST0_FR)) ft &= ~1; - ctx->regs[ft] = mips_get_dword(xcp, va, &err); + ctx->regs[ft] = mips_get_dword(regs, va, &err); fpuemuprivate.stats.loads++; if (err) { fpuemuprivate.stats.errors++; @@ -305,13 +308,13 @@ case sdc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); int ft = MIPSInst_RT(ir); - if (!(xcp->cp0_status & ST0_FR)) + if (!(regs->cp0_status & ST0_FR)) ft &= ~1; fpuemuprivate.stats.stores++; - if (mips_put_dword(xcp, va, ctx->regs[ft])) { + if (mips_put_dword(regs, va, ctx->regs[ft])) { fpuemuprivate.stats.errors++; return SIGBUS; } @@ -321,17 +324,17 @@ case lwc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); fpureg_t val; int ft = MIPSInst_RT(ir); fpuemuprivate.stats.loads++; - val = mips_get_word(xcp, va, &err); + val = mips_get_word(regs, va, &err); if (err) { fpuemuprivate.stats.errors++; return SIGBUS; } - if (xcp->cp0_status & ST0_FR) { + if (regs->cp0_status & ST0_FR) { /* load whole register */ ctx->regs[ft] = val; } else if (ft & 1) { @@ -353,12 +356,12 @@ case swc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); unsigned int val; int ft = MIPSInst_RT(ir); fpuemuprivate.stats.stores++; - if (xcp->cp0_status & ST0_FR) { + if (regs->cp0_status & ST0_FR) { /* store whole register */ val = ctx->regs[ft]; } else if (ft & 1) { @@ -373,7 +376,7 @@ /* store from l.s. 32 bits */ val = ctx->regs[ft]; } - if (mips_put_word(xcp, va, val)) { + if (mips_put_word(regs, va, val)) { fpuemuprivate.stats.errors++; return SIGBUS; } @@ -382,10 +385,10 @@ #else /* old 32-bit fpu registers */ case lwc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); ctx->regs[MIPSInst_RT(ir)] = - mips_get_word(xcp, va, &err); + mips_get_word(regs, va, &err); fpuemuprivate.stats.loads++; if (err) { fpuemuprivate.stats.errors++; @@ -396,11 +399,11 @@ case swc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); fpuemuprivate.stats.stores++; if (mips_put_word - (xcp, va, ctx->regs[MIPSInst_RT(ir)])) { + (regs, va, ctx->regs[MIPSInst_RT(ir)])) { fpuemuprivate.stats.errors++; return SIGBUS; } @@ -408,24 +411,24 @@ break; case ldc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); unsigned int rt = MIPSInst_RT(ir) & ~1; int errs = 0; fpuemuprivate.stats.loads++; #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) ctx->regs[rt + 1] = - mips_get_word(xcp, va + 0, &err); + mips_get_word(regs, va + 0, &err); errs += err; ctx->regs[rt + 0] = - mips_get_word(xcp, va + 4, &err); + mips_get_word(regs, va + 4, &err); errs += err; #else ctx->regs[rt + 0] = - mips_get_word(xcp, va + 0, &err); + mips_get_word(regs, va + 0, &err); errs += err; ctx->regs[rt + 1] = - mips_get_word(xcp, va + 4, &err); + mips_get_word(regs, va + 4, &err); errs += err; #endif if (err) @@ -435,19 +438,19 @@ case sdc1_op: { - void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + void *va = REG_TO_VA(regs->regs[MIPSInst_RS(ir)]) + MIPSInst_SIMM(ir); unsigned int rt = MIPSInst_RT(ir) & ~1; fpuemuprivate.stats.stores++; #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) - if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1])) + if (mips_put_word(regs, va + 0, ctx->regs[rt + 1])) return SIGBUS; - if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0])) + if (mips_put_word(regs, va + 4, ctx->regs[rt + 0])) return SIGBUS; #else - if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0])) + if (mips_put_word(regs, va + 0, ctx->regs[rt + 0])) return SIGBUS; - if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1])) + if (mips_put_word(regs, va + 4, ctx->regs[rt + 1])) return SIGBUS; #endif } @@ -463,9 +466,9 @@ /* copregister fs -> gpr[rt] */ if (MIPSInst_RT(ir) != 0) { int fs = MIPSInst_RD(ir); - if (!(xcp->cp0_status & ST0_FR)) + if (!(regs->cp0_status & ST0_FR)) fs &= ~1; - xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs]; + regs->regs[MIPSInst_RT(ir)] = ctx->regs[fs]; } break; @@ -473,11 +476,11 @@ /* copregister fs <- rt */ fpureg_t value; int fs = MIPSInst_RD(ir); - if (!(xcp->cp0_status & ST0_FR)) + if (!(regs->cp0_status & ST0_FR)) fs &= ~1; value = (MIPSInst_RT(ir) == - 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + 0) ? 0 : regs->regs[MIPSInst_RT(ir)]; ctx->regs[fs] = value; break; } @@ -493,7 +496,7 @@ /* illegal register in single-float mode */ return SIGILL; #else - if (!(xcp->cp0_status & ST0_FR)) { + if (!(regs->cp0_status & ST0_FR)) { /* move from m.s. 32 bits */ value = ctx-> @@ -502,7 +505,7 @@ } #endif } - xcp->regs[MIPSInst_RT(ir)] = value; + regs->regs[MIPSInst_RT(ir)] = value; } break; @@ -514,14 +517,14 @@ value = 0; else value = - (unsigned int) xcp-> + (unsigned int) regs-> regs[MIPSInst_RT(ir)]; if (MIPSInst_RD(ir) & 1) { #ifdef SINGLE_ONLY_FPU /* illegal register in single-float mode */ return SIGILL; #else - if (!(xcp->cp0_status & ST0_FR)) { + if (!(regs->cp0_status & ST0_FR)) { /* move to m.s. 32 bits */ ctx-> regs[ @@ -550,7 +553,7 @@ if (MIPSInst_RT(ir) != 0) { unsigned value = ctx->regs[MIPSInst_RD(ir)]; - xcp->regs[MIPSInst_RT(ir)] = value; + regs->regs[MIPSInst_RT(ir)] = value; } break; @@ -560,7 +563,7 @@ unsigned value; value = (MIPSInst_RT(ir) == - 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + 0) ? 0 : regs->regs[MIPSInst_RT(ir)]; ctx->regs[MIPSInst_RD(ir)] = value; } break; @@ -576,7 +579,7 @@ #ifdef CSRTRACE printk ("%p gpr[%d]<-csr=%08x\n", - REG_TO_VA(xcp->cp0_epc), + REG_TO_VA(regs->cp0_epc), MIPSInst_RT(ir), value); #endif } else if (MIPSInst_RD(ir) == FPCREG_RID) @@ -584,7 +587,7 @@ else value = 0; if (MIPSInst_RT(ir)) - xcp->regs[MIPSInst_RT(ir)] = value; + regs->regs[MIPSInst_RT(ir)] = value; } break; @@ -596,7 +599,7 @@ if (MIPSInst_RT(ir) == 0) value = 0; else - value = xcp->regs[MIPSInst_RT(ir)]; + value = regs->regs[MIPSInst_RT(ir)]; /* we only have one writable control reg */ @@ -604,11 +607,14 @@ #ifdef CSRTRACE printk ("%p gpr[%d]->csr=%08x\n", - REG_TO_VA(xcp->cp0_epc), + REG_TO_VA(regs->cp0_epc), MIPSInst_RT(ir), value); #endif ctx->sr = value; - /* copy new rounding mode to ieee library state! */ + /* copy new rounding mode and + flush bit to ieee library state! */ + ieee754_csr.nod = + (ctx->sr & 0x1000000) != 0; ieee754_csr.rm = ieee_rm[value & 0x3]; } @@ -618,7 +624,7 @@ case bc_op: { int likely = 0; - if (xcp->cp0_cause & CAUSEF_BD) + if (regs->cp0_cause & CAUSEF_BD) return SIGILL; #if __mips >= 4 @@ -641,14 +647,14 @@ return SIGILL; } - xcp->cp0_cause |= CAUSEF_BD; + regs->cp0_cause |= CAUSEF_BD; if (cond) { /* branch taken: emulate dslot instruction */ - xcp->cp0_epc += 4; - contpc = REG_TO_VA xcp->cp0_epc + + regs->cp0_epc += 4; + contpc = REG_TO_VA regs->cp0_epc + (MIPSInst_SIMM(ir) << 2); - ir = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), + ir = mips_get_word(regs, REG_TO_VA(regs->cp0_epc), &err); if (err) { fpuemuprivate.stats.errors++; @@ -680,16 +686,21 @@ * Single step the non-cp1 instruction in the * dslot */ - return mips_dsemul(xcp, ir, contpc); + return mips_dsemul(regs, ir, contpc); } else { /* branch not taken */ - if (likely) + if (likely) { /* * branch likely nullifies dslot if not * taken */ - xcp->cp0_epc += 4; - /* else continue & execute dslot as normal insn */ + regs->cp0_epc += 4; + contpc += 4; + /* + * else continue & execute dslot as + * normal insn + */ + } } break; } @@ -701,7 +712,7 @@ return SIGILL; /* a real fpu computation instruction */ - if ((sig = fpu_emu(xcp, ctx, ir))) + if ((sig = fpu_emu(regs, ctx, ir))) return sig; } } @@ -711,7 +722,7 @@ case cop1x_op: { int sig; - if ((sig = fpux_emu(xcp, ctx, ir))) + if ((sig = fpux_emu(regs, ctx, ir))) return sig; } break; @@ -722,9 +733,9 @@ if (MIPSInst_FUNC(ir) != movc_op) return SIGILL; cond = fpucondbit[MIPSInst_RT(ir) >> 2]; - if (((ctx->sr & cond) != 0) != - ((MIPSInst_RT(ir) & 1) != 0)) return 0; - xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + if (((ctx->sr & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0)) + return 0; + regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)]; break; #endif @@ -733,8 +744,8 @@ } /* we did it !! */ - xcp->cp0_epc = VA_TO_REG(contpc); - xcp->cp0_cause &= ~CAUSEF_BD; + regs->cp0_epc = VA_TO_REG(contpc); + regs->cp0_cause &= ~CAUSEF_BD; return 0; } @@ -755,37 +766,84 @@ * execution of delay-slot instruction execution. */ +/* Instruction inserted following delay slot instruction to force trap */ +#define AdELOAD 0x8c000001 /* lw $0,1($0) */ + +/* Instruction inserted following the AdELOAD to further tag the sequence */ +#define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */ + int do_dsemulret(struct pt_regs *xcp) { + unsigned long *pinst; + unsigned long stackitem; + int err = 0; + + /* See if this trap was deliberate. First check the instruction */ + + pinst = (unsigned long *) REG_TO_VA(xcp->cp0_epc); + + /* + * If we can't even access the area, something is very wrong, but we'll + * leave that to the default handling + */ + if (verify_area(VERIFY_READ, pinst, sizeof(unsigned long) * 3)) + return 0; + + /* Is the instruction pointed to by the EPC an AdELOAD? */ + stackitem = mips_get_word(xcp, pinst, &err); + if (err || (stackitem != AdELOAD)) + return 0; + + /* Is the following memory word the BD_COOKIE? */ + + stackitem = mips_get_word(xcp, pinst+1, &err); + if (err || (stackitem != BD_COOKIE)) + return 0; + + /* + * At this point, we are satisfied that it's a BD emulation trap. Yes, + * a user might have deliberately put two malformed and useless + * instructions in a row in his program, in which case he's in for a + * nasty surprise - the next instruction will be treated as a + * continuation address! Alas, this seems to be the only way that we + * can handle signals, recursion, and longjmps() in the context of + * emulating the branch delay instruction. + */ + #ifdef DSEMUL_TRACE printk("desemulret\n"); #endif + /* Fetch the Saved EPC to Resume */ + + stackitem = mips_get_word(xcp, pinst+2, &err); + if (err) { + /* This is not a good situation to be in */ + fpuemuprivate.stats.errors++; + force_sig(SIGBUS, current); + return 1; + } + /* Set EPC to return to post-branch instruction */ - xcp->cp0_epc = current->thread.dsemul_epc; - /* - * Clear the state that got us here. - */ - current->thread.dsemul_aerpc = (unsigned long) 0; + xcp->cp0_epc = stackitem; - return 0; + return 1; } #define AdELOAD 0x8c000001 /* lw $0,1($0) */ -static int -mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc) +static int mips_dsemul(struct pt_regs *regs, mips_instruction ir, vaddr_t cpc) { mips_instruction *dsemul_insns; - mips_instruction forcetrap; extern asmlinkage void handle_dsemulret(void); if (ir == 0) { /* a nop is easy */ - xcp->cp0_epc = VA_TO_REG(cpc); + regs->cp0_epc = VA_TO_REG(cpc); + regs->cp0_cause &= ~CAUSEF_BD; return 0; } #ifdef DSEMUL_TRACE - printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc); + printk("desemul %p %p\n", REG_TO_VA(regs->cp0_epc), cpc); #endif /* @@ -793,21 +851,7 @@ * and put a trap after it which we can catch and jump to * the required address any alternative apart from full * instruction emulation!!. - */ - dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3); - dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */ - - /* Verify that the stack pointer is not competely insane */ - if (verify_area(VERIFY_WRITE, dsemul_insns, - sizeof(mips_instruction) * 2)) - return SIGBUS; - - if (mips_put_word(xcp, &dsemul_insns[0], ir)) { - fpuemuprivate.stats.errors++; - return SIGBUS; - } - - /* + * * Algorithmics used a system call instruction, and * borrowed that vector. MIPS/Linux version is a bit * more heavyweight in the interests of portability and @@ -816,23 +860,39 @@ * address error excpetion. */ - /* If one is *really* paranoid, one tests for a bad stack pointer */ - if ((xcp->regs[29] & 0x3) == 0x3) - forcetrap = AdELOAD - 1; - else - forcetrap = AdELOAD; + /* Ensure that the two instructions are in the same cache line */ + dsemul_insns = (mips_instruction *) (regs->regs[29] & ~0xf); + dsemul_insns -= 4; /* Retain 16-byte alignment */ + + /* Verify that the stack pointer is not competely insane */ + if (verify_area + (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 4)) + return SIGBUS; - if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) { + if (mips_put_word(regs, &dsemul_insns[0], ir)) { fpuemuprivate.stats.errors++; return (SIGBUS); } - /* Set thread state to catch and handle the exception */ - current->thread.dsemul_epc = (unsigned long) cpc; - current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1]; - xcp->cp0_epc = VA_TO_REG & dsemul_insns[0]; - flush_cache_sigtramp((unsigned long) dsemul_insns); + if (mips_put_word(regs, &dsemul_insns[1], (mips_instruction)AdELOAD)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + if (mips_put_word(regs, &dsemul_insns[2], + (mips_instruction)BD_COOKIE)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + if (mips_put_word(regs, &dsemul_insns[3], (mips_instruction)cpc)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + regs->cp0_epc = VA_TO_REG & dsemul_insns[0]; + + flush_cache_sigtramp((unsigned long)dsemul_insns); return SIGILL; /* force out of emulation loop */ } @@ -881,6 +941,22 @@ * Additional MIPS4 instructions */ +#define DEF3OP(name, p, f1, f2, f3) \ +static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ + ieee754##p t) \ +{ \ + struct ieee754_csr ieee754_csr_save; \ + s = f1 (s, t); \ + ieee754_csr_save = ieee754_csr; \ + s = f2 (s, r); \ + ieee754_csr_save.cx |= ieee754_csr.cx; \ + ieee754_csr_save.sx |= ieee754_csr.sx; \ + s = f3 (s); \ + ieee754_csr.cx |= ieee754_csr_save.cx; \ + ieee754_csr.sx |= ieee754_csr_save.sx; \ + return s; \ +} + static ieee754dp fpemu_dp_recip(ieee754dp d) { return ieee754dp_div(ieee754dp_one(0), d); @@ -901,47 +977,14 @@ return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); } - -static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t) -{ - return ieee754dp_add(ieee754dp_mul(s, t), r); -} - -static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t) -{ - return ieee754dp_sub(ieee754dp_mul(s, t), r); -} - -static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t) -{ - return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r)); -} - -static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t) -{ - return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r)); -} - - -static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t) -{ - return ieee754sp_add(ieee754sp_mul(s, t), r); -} - -static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t) -{ - return ieee754sp_sub(ieee754sp_mul(s, t), r); -} - -static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t) -{ - return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r)); -} - -static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t) -{ - return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r)); -} +DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, ); +DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, ); +DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); +DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); +DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, ); +DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); +DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); +DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, mips_instruction ir) @@ -1086,6 +1129,8 @@ ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if (ieee754_csr.nod) + ctx->sr |= 0x1000000; if ((ctx->sr >> 5) & ctx-> sr & FPU_CSR_ALL_E) { /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ @@ -1274,7 +1319,8 @@ case fmov_op: /* an easy one */ SPFROMREG(rv.s, MIPSInst_FS(ir)); - break; + goto copcsr; + /* binary op on handler */ scopbop: { @@ -1386,13 +1432,16 @@ rfmt = -1; if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION)) rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; - } else { - return SIGILL; - } - break; + else + goto copcsr; + + } else { + return SIGILL; } break; } + break; + } #if !defined(SINGLE_ONLY_FPU) case d_fmt: { @@ -1456,7 +1505,7 @@ case fmov_op: /* an easy one */ DPFROMREG(rv.d, MIPSInst_FS(ir)); - break; + goto copcsr; /* binary op on handler */ dcopbop: @@ -1553,6 +1602,9 @@ rfmt = -1; if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION)) rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + } else { return SIGILL; } @@ -1683,8 +1735,14 @@ fpuemuprivate.stats.errors++; return SIGBUS; } - if (insn != 0) + if (insn != 0) { + /* Update ieee754_csr. Only relevant if we have a + h/w FPU */ + ieee754_csr.nod = (ctx->sr & 0x1000000) != 0; + ieee754_csr.rm = ieee_rm[ctx->sr & 0x3]; + ieee754_csr.cx = (ctx->sr >> 12) & 0x1f; sig = cop1Emulate(xcp, ctx); + } else xcp->cp0_epc += 4; /* skip nops */ @@ -1747,7 +1805,7 @@ * i.e. denormalised results, underflow, overflow etc, which * must be emulated in s/w. */ -#ifdef 1 +#if 1 /* r4000 or above use dedicate exception */ xcption(XCPTFPE, cop1Patcher); #else diff -urN linux-2.4.18/arch/mips/math-emu/dp_add.c linux-2.4.19-pre5/arch/mips/math-emu/dp_add.c --- linux-2.4.18/arch/mips/math-emu/dp_add.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_add.c Sat Mar 30 22:55:26 2002 @@ -38,27 +38,23 @@ CLEARCX; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x, - y); + FLUSHXDP; + FLUSHYDP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y, "add", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x, "add", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754dp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -66,6 +62,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/dp_cmp.c linux-2.4.19-pre5/arch/mips/math-emu/dp_cmp.c --- linux-2.4.18/arch/mips/math-emu/dp_cmp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_cmp.c Sat Mar 30 22:55:26 2002 @@ -29,9 +29,18 @@ int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp) { - CLEARCX; + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + FLUSHXDP; + FLUSHYDP; + CLEARCX; /* Even clear inexact flag here */ if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { + if (xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) + SETCX(IEEE754_INVALID_OPERATION); if (cmp & IEEE754_CUN) return 1; if (cmp & (IEEE754_CLT | IEEE754_CGT)) { diff -urN linux-2.4.18/arch/mips/math-emu/dp_div.c linux-2.4.19-pre5/arch/mips/math-emu/dp_div.c --- linux-2.4.18/arch/mips/math-emu/dp_div.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_div.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXDP; COMPYDP; - CLEARCX; - EXPLODEXDP; EXPLODEYDP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x, - y); + CLEARCX; + + FLUSHXDP; + FLUSHYDP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y, "div", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x, "div", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754dp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/dp_fsp.c linux-2.4.19-pre5/arch/mips/math-emu/dp_fsp.c --- linux-2.4.18/arch/mips/math-emu/dp_fsp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_fsp.c Sat Mar 30 22:55:26 2002 @@ -31,13 +31,17 @@ { COMPXSP; + EXPLODEXSP; + CLEARCX; - EXPLODEXSP; + FLUSHXSP; switch (xc) { - case IEEE754_CLASS_QNAN: case IEEE754_CLASS_SNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp"); + case IEEE754_CLASS_QNAN: return ieee754dp_nanxcpt(builddp(xs, DP_EMAX + 1 + DP_EBIAS, ((unsigned long long) xm diff -urN linux-2.4.18/arch/mips/math-emu/dp_mul.c linux-2.4.19-pre5/arch/mips/math-emu/dp_mul.c --- linux-2.4.18/arch/mips/math-emu/dp_mul.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_mul.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXDP; COMPYDP; - CLEARCX; - EXPLODEXDP; EXPLODEYDP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x, - y); + CLEARCX; + + FLUSHXDP; + FLUSHYDP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y, "mul", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x, "mul", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754dp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/dp_simple.c linux-2.4.19-pre5/arch/mips/math-emu/dp_simple.c --- linux-2.4.18/arch/mips/math-emu/dp_simple.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_simple.c Sat Mar 30 22:55:26 2002 @@ -42,7 +42,16 @@ ieee754dp ieee754dp_neg(ieee754dp x) { + COMPXDP; + + EXPLODEXDP; CLEARCX; + FLUSHXDP; + + if (xc == IEEE754_CLASS_SNAN) { + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "neg"); + } if (ieee754dp_isnan(x)) /* but not infinity */ return ieee754dp_nanxcpt(x, "neg", x); @@ -55,7 +64,16 @@ ieee754dp ieee754dp_abs(ieee754dp x) { + COMPXDP; + + EXPLODEXDP; CLEARCX; + FLUSHXDP; + + if (xc == IEEE754_CLASS_SNAN) { + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "neg"); + } if (ieee754dp_isnan(x)) /* but not infinity */ return ieee754dp_nanxcpt(x, "abs", x); diff -urN linux-2.4.18/arch/mips/math-emu/dp_sqrt.c linux-2.4.19-pre5/arch/mips/math-emu/dp_sqrt.c --- linux-2.4.18/arch/mips/math-emu/dp_sqrt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_sqrt.c Sat Mar 30 22:55:26 2002 @@ -27,16 +27,6 @@ #include "ieee754dp.h" -static const struct ieee754dp_konst knan = { -#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) - 0, 0, DP_EBIAS + DP_EMAX + 1, 0 -#else - 0, DP_EBIAS + DP_EMAX + 1, 0, 0 -#endif -}; - -#define nan ((ieee754dp)knan) - static const unsigned table[] = { 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740, 58733, 67158, 75992, @@ -53,29 +43,37 @@ COMPXDP; EXPLODEXDP; + CLEARCX; + FLUSHXDP; /* x == INF or NAN? */ switch (xc) { case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_SNAN: /* sqrt(Nan) = Nan */ return ieee754dp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_SNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); case IEEE754_CLASS_ZERO: /* sqrt(0) = 0 */ return x; case IEEE754_CLASS_INF: - if (xs) + if (xs) { /* sqrt(-Inf) = Nan */ - return ieee754dp_nanxcpt(nan, "sqrt"); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); + } /* sqrt(+Inf) = Inf */ return x; case IEEE754_CLASS_DNORM: DPDNORMX; /* fall through */ case IEEE754_CLASS_NORM: - if (xs) + if (xs) { /* sqrt(-x) = Nan */ - return ieee754dp_nanxcpt(nan, "sqrt"); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); + } break; } diff -urN linux-2.4.18/arch/mips/math-emu/dp_sub.c linux-2.4.19-pre5/arch/mips/math-emu/dp_sub.c --- linux-2.4.18/arch/mips/math-emu/dp_sub.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_sub.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXDP; COMPYDP; - CLEARCX; - EXPLODEXDP; EXPLODEYDP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x, - y); + CLEARCX; + + FLUSHXDP; + FLUSHYDP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y, "sub", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x, "sub", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754dp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/dp_tint.c linux-2.4.19-pre5/arch/mips/math-emu/dp_tint.c --- linux-2.4.18/arch/mips/math-emu/dp_tint.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_tint.c Sat Mar 30 22:55:26 2002 @@ -35,38 +35,76 @@ CLEARCX; EXPLODEXDP; + FLUSHXDP; switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); case IEEE754_CLASS_INF: - SETCX(IEEE754_OVERFLOW); - return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); case IEEE754_CLASS_ZERO: return 0; - case IEEE754_CLASS_DNORM: /* much to small */ - SETCX(IEEE754_UNDERFLOW); - return ieee754si_xcpt(0, "fixdp", x); + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; } if (xe >= 31) { - SETCX(IEEE754_OVERFLOW); - return ieee754si_xcpt(ieee754si_indef(), "fix", x); - } - if (xe < 0) { - SETCX(IEEE754_UNDERFLOW); - return ieee754si_xcpt(0, "fix", x); + /* look for valid corner case */ + if (xe == 31 && xs && xm == DP_HIDDEN_BIT) + return -2147483648; + /* Set invalid. We will only use overflow for floating + point overflow */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); } /* oh gawd */ if (xe > DP_MBITS) { xm <<= xe - DP_MBITS; } else if (xe < DP_MBITS) { - /* XXX no rounding - */ - xm >>= DP_MBITS - xe; + unsigned long long residue; + int round; + int sticky; + int odd; + + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; + } + else { + residue = xm << (64 - DP_MBITS + xe); + round = (residue >> 63) != 0; + sticky = (residue << 1) != 0; + xm >>= DP_MBITS - xe; + } + /* Note: At this point upper 32 bits of xm are guaranteed + to be zero */ + odd = (xm & 0x1) != 0x0; + switch (ieee754_csr.rm) { + case IEEE754_RN: + if (round && (sticky || odd)) + xm++; + break; + case IEEE754_RZ: + break; + case IEEE754_RU: /* toward +Infinity */ + if ((round || sticky) && !xs) + xm++; + break; + case IEEE754_RD: /* toward -Infinity */ + if ((round || sticky) && xs) + xm++; + break; + } + if ((xm >> 31) != 0) { + /* This can happen after rounding */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); + } + if (round || sticky) + SETCX(IEEE754_INEXACT); } if (xs) return -xm; diff -urN linux-2.4.18/arch/mips/math-emu/dp_tlong.c linux-2.4.19-pre5/arch/mips/math-emu/dp_tlong.c --- linux-2.4.18/arch/mips/math-emu/dp_tlong.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/dp_tlong.c Sat Mar 30 22:55:26 2002 @@ -34,92 +34,74 @@ CLEARCX; EXPLODEXDP; + FLUSHXDP; switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); case IEEE754_CLASS_INF: - SETCX(IEEE754_OVERFLOW); + SETCX(IEEE754_INVALID_OPERATION); return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); case IEEE754_CLASS_ZERO: return 0; - case IEEE754_CLASS_DNORM: /* much too small */ - SETCX(IEEE754_UNDERFLOW); - return ieee754di_xcpt(0, "dp_tlong", x); + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; } if (xe >= 63) { - SETCX(IEEE754_OVERFLOW); + /* look for valid corner case */ + if (xe == 63 && xs && xm == DP_HIDDEN_BIT) + return -9223372036854775808LL; + /* Set invalid. We will only use overflow for floating + point overflow */ + SETCX(IEEE754_INVALID_OPERATION); return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); } - if (xe < 0) { - if (ieee754_csr.rm == IEEE754_RU) { - if (xs) { /* Negative */ - return 0x0000000000000000LL; - } else { /* Positive */ - return 0x0000000000000001LL; - } - } else if (ieee754_csr.rm == IEEE754_RD) { - if (xs) { /* Negative , return -1 */ - return 0xffffffffffffffffLL; - } else { /* Positive */ - return 0x0000000000000000LL; - } - } else { - SETCX(IEEE754_UNDERFLOW); - return ieee754di_xcpt(0, "dp_tlong", x); - } - } /* oh gawd */ if (xe > DP_MBITS) { xm <<= xe - DP_MBITS; } else if (xe < DP_MBITS) { unsigned long long residue; - unsigned long long mask = 0; - int i; int round; int sticky; int odd; - /* compute mask */ - for (i = 0; i < DP_MBITS - xe; i++) { - mask = mask << 1; - mask = mask | 0x1; + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; } - residue = (xm & mask) << (64 - (DP_MBITS - xe)); - round = - ((0x8000000000000000LL & residue) != - 0x0000000000000000LL); - sticky = - ((0x7fffffffffffffffLL & residue) != - 0x0000000000000000LL); - - xm >>= DP_MBITS - xe; - - odd = ((xm & 0x1) != 0x0000000000000000LL); - - /* Do the rounding */ - if (!round && sticky) { - if ((ieee754_csr.rm == IEEE754_RU && !xs) - || (ieee754_csr.rm == IEEE754_RD && xs)) { + else { + residue = xm << (64 - DP_MBITS + xe); + round = (residue >> 63) != 0; + sticky = (residue << 1) != 0; + xm >>= DP_MBITS - xe; + } + odd = (xm & 0x1) != 0x0; + switch (ieee754_csr.rm) { + case IEEE754_RN: + if (round && (sticky || odd)) xm++; - } - } else if (round && !sticky) { - if ((ieee754_csr.rm == IEEE754_RU && !xs) - || (ieee754_csr.rm == IEEE754_RD && xs) - || (ieee754_csr.rm == IEEE754_RN && odd)) { + break; + case IEEE754_RZ: + break; + case IEEE754_RU: /* toward +Infinity */ + if ((round || sticky) && !xs) xm++; - } - } else if (round && sticky) { - if ((ieee754_csr.rm == IEEE754_RU && !xs) - || (ieee754_csr.rm == IEEE754_RD && xs) - || (ieee754_csr.rm == IEEE754_RN)) { + break; + case IEEE754_RD: /* toward -Infinity */ + if ((round || sticky) && xs) xm++; - } + break; + } + if ((xm >> 63) != 0) { + /* This can happen after rounding */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); } + if (round || sticky) + SETCX(IEEE754_INEXACT); } if (xs) return -xm; diff -urN linux-2.4.18/arch/mips/math-emu/ieee754.c linux-2.4.19-pre5/arch/mips/math-emu/ieee754.c --- linux-2.4.18/arch/mips/math-emu/ieee754.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754.c Sat Mar 30 22:55:26 2002 @@ -77,7 +77,7 @@ DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ - DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0), /* + indef quiet Nan */ + DPSTR(0,DP_EMAX+1+DP_EBIAS,0x7FFFF,0xFFFFFFFF), /* + indef quiet Nan */ DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ @@ -97,7 +97,7 @@ SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ - SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000), /* + indef quiet Nan */ + SPSTR(0,SP_EMAX+1+SP_EBIAS,0x3FFFFF), /* + indef quiet Nan */ SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ diff -urN linux-2.4.18/arch/mips/math-emu/ieee754.h linux-2.4.19-pre5/arch/mips/math-emu/ieee754.h --- linux-2.4.18/arch/mips/math-emu/ieee754.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754.h Sat Mar 30 22:55:26 2002 @@ -325,7 +325,6 @@ */ struct ieee754_csr { unsigned pad:13; - unsigned noq:1; /* set 1 for no quiet NaN's */ unsigned nod:1; /* set 1 for no denormalised numbers */ unsigned cx:5; /* exceptions this operation */ unsigned mx:5; /* exception enable mask */ @@ -453,11 +452,11 @@ /* indefinite integer value */ -#define ieee754si_indef() INT_MIN -#ifdef LONG_LONG_MIN -#define ieee754di_indef() LONG_LONG_MIN +#define ieee754si_indef() INT_MAX +#ifdef LONG_LONG_MAX +#define ieee754di_indef() LONG_LONG_MAX #else -#define ieee754di_indef() (-9223372036854775807LL-1) +#define ieee754di_indef() ((long long)(~0ULL>>1)) #endif /* IEEE exception context, passed to handler */ diff -urN linux-2.4.18/arch/mips/math-emu/ieee754d.c linux-2.4.19-pre5/arch/mips/math-emu/ieee754d.c --- linux-2.4.18/arch/mips/math-emu/ieee754d.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754d.c Sat Mar 30 22:55:26 2002 @@ -1,12 +1,11 @@ -/* some debug functions -*/ /* + * Some debug functions + * * MIPS floating point support + * * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. * http://www.algor.co.uk * - * ######################################################################## - * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. @@ -20,17 +19,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * - * ######################################################################## - */ - -/************************************************************************** * Nov 7, 2000 * Modified to build and operate in Linux kernel environment. * * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - *************************************************************************/ + */ +#include #include "ieee754.h" #define DP_EBIAS 1023 diff -urN linux-2.4.18/arch/mips/math-emu/ieee754dp.c linux-2.4.19-pre5/arch/mips/math-emu/ieee754dp.c --- linux-2.4.18/arch/mips/math-emu/ieee754dp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754dp.c Sat Mar 30 22:55:26 2002 @@ -42,9 +42,7 @@ int ieee754dp_issnan(ieee754dp x) { assert(ieee754dp_isnan(x)); - if (ieee754_csr.noq) - return 1; - return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1)); + return ((DPMANT(x) & DP_MBIT(DP_MBITS-1)) == DP_MBIT(DP_MBITS-1)); } @@ -73,10 +71,11 @@ if (!SETCX(IEEE754_INVALID_OPERATION)) { /* not enabled convert to a quiet NaN */ - if (ieee754_csr.noq) + DPMANT(r) &= (~DP_MBIT(DP_MBITS-1)); + if (ieee754dp_isnan(r)) return r; - DPMANT(r) |= DP_MBIT(DP_MBITS - 1); - return r; + else + return ieee754dp_indef(); } ax.op = op; @@ -99,6 +98,32 @@ } +static unsigned long long get_rounding(int sn, unsigned long long xm) +{ + /* inexact must round of 3 bits + */ + if (xm & (DP_MBIT(3) - 1)) { + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + } + return xm; +} + + /* generate a normal/denormal number with over,under handeling * sn is sign * xe is an unbiased exponent @@ -117,40 +142,59 @@ if (ieee754_csr.nod) { SETCX(IEEE754_UNDERFLOW); - return ieee754dp_zero(sn); - } + SETCX(IEEE754_INEXACT); - /* sticky right shift es bits - */ - xm = XDPSRS(xm, es); - xe += es; + switch(ieee754_csr.rm) { + case IEEE754_RN: + return ieee754dp_zero(sn); + case IEEE754_RZ: + return ieee754dp_zero(sn); + case IEEE754_RU: /* toward +Infinity */ + if(sn == 0) + return ieee754dp_min(0); + else + return ieee754dp_zero(1); + case IEEE754_RD: /* toward -Infinity */ + if(sn == 0) + return ieee754dp_zero(0); + else + return ieee754dp_min(1); + } + } - assert((xm & (DP_HIDDEN_BIT << 3)) == 0); - assert(xe == DP_EMIN); + if (xe == DP_EMIN - 1 + && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3)) + { + /* Not tiny after rounding */ + SETCX(IEEE754_INEXACT); + xm = get_rounding(sn, xm); + xm >>= 1; + /* Clear grs bits */ + xm &= ~(DP_MBIT(3) - 1); + xe++; + } + else { + /* sticky right shift es bits + */ + xm = XDPSRS(xm, es); + xe += es; + assert((xm & (DP_HIDDEN_BIT << 3)) == 0); + assert(xe == DP_EMIN); + } } if (xm & (DP_MBIT(3) - 1)) { SETCX(IEEE754_INEXACT); + if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { + SETCX(IEEE754_UNDERFLOW); + } + /* inexact must round of 3 bits */ - switch (ieee754_csr.rm) { - case IEEE754_RZ: - break; - case IEEE754_RN: - xm += 0x3 + ((xm >> 3) & 1); - /* xm += (xm&0x8)?0x4:0x3 */ - break; - case IEEE754_RU: /* toward +Infinity */ - if (!sn) /* ?? */ - xm += 0x8; - break; - case IEEE754_RD: /* toward -Infinity */ - if (sn) /* ?? */ - xm += 0x8; - break; - } + xm = get_rounding(sn, xm); /* adjust exponent for rounding add overflowing */ - if (xm >> (DP_MBITS + 3 + 1)) { /* add causes mantissa overflow */ + if (xm >> (DP_MBITS + 3 + 1)) { + /* add causes mantissa overflow */ xm >>= 1; xe++; } @@ -163,6 +207,7 @@ if (xe > DP_EMAX) { SETCX(IEEE754_OVERFLOW); + SETCX(IEEE754_INEXACT); /* -O can be table indexed by (rm,sn) */ switch (ieee754_csr.rm) { case IEEE754_RN: @@ -186,7 +231,8 @@ if ((xm & DP_HIDDEN_BIT) == 0) { /* we underflow (tiny/zero) */ assert(xe == DP_EMIN); - SETCX(IEEE754_UNDERFLOW); + if (ieee754_csr.mx & IEEE754_UNDERFLOW) + SETCX(IEEE754_UNDERFLOW); return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); } else { assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ diff -urN linux-2.4.18/arch/mips/math-emu/ieee754int.h linux-2.4.19-pre5/arch/mips/math-emu/ieee754int.h --- linux-2.4.18/arch/mips/math-emu/ieee754int.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754int.h Sat Mar 30 22:55:26 2002 @@ -82,9 +82,9 @@ if(vm == 0)\ vc = IEEE754_CLASS_INF;\ else if(vm & SP_MBIT(SP_MBITS-1)) \ - vc = IEEE754_CLASS_QNAN;\ - else \ vc = IEEE754_CLASS_SNAN;\ + else \ + vc = IEEE754_CLASS_QNAN;\ } else if(ve == SP_EMIN-1+SP_EBIAS) {\ if(vm) {\ ve = SP_EMIN;\ @@ -116,9 +116,9 @@ if(vm == 0)\ vc = IEEE754_CLASS_INF;\ else if(vm & DP_MBIT(DP_MBITS-1)) \ - vc = IEEE754_CLASS_QNAN;\ - else \ vc = IEEE754_CLASS_SNAN;\ + else \ + vc = IEEE754_CLASS_QNAN;\ } else if(ve == DP_EMIN-1+DP_EBIAS) {\ if(vm) {\ ve = DP_EMIN;\ @@ -133,3 +133,30 @@ } #define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm) #define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym) + +#define FLUSHDP(v,vc,vs,ve,vm) \ + if(vc==IEEE754_CLASS_DNORM) {\ + if(ieee754_csr.nod) {\ + SETCX(IEEE754_INEXACT);\ + vc = IEEE754_CLASS_ZERO;\ + ve = DP_EMIN-1+DP_EBIAS;\ + vm = 0;\ + v = ieee754dp_zero(vs);\ + }\ + } + +#define FLUSHSP(v,vc,vs,ve,vm) \ + if(vc==IEEE754_CLASS_DNORM) {\ + if(ieee754_csr.nod) {\ + SETCX(IEEE754_INEXACT);\ + vc = IEEE754_CLASS_ZERO;\ + ve = SP_EMIN-1+SP_EBIAS;\ + vm = 0;\ + v = ieee754sp_zero(vs);\ + }\ + } + +#define FLUSHXDP FLUSHDP(x,xc,xs,xe,xm) +#define FLUSHYDP FLUSHDP(y,yc,ys,ye,ym) +#define FLUSHXSP FLUSHSP(x,xc,xs,xe,xm) +#define FLUSHYSP FLUSHSP(y,yc,ys,ye,ym) diff -urN linux-2.4.18/arch/mips/math-emu/ieee754sp.c linux-2.4.19-pre5/arch/mips/math-emu/ieee754sp.c --- linux-2.4.18/arch/mips/math-emu/ieee754sp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/ieee754sp.c Sat Mar 30 22:55:26 2002 @@ -42,9 +42,7 @@ int ieee754sp_issnan(ieee754sp x) { assert(ieee754sp_isnan(x)); - if (ieee754_csr.noq) - return 1; - return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1)); + return (SPMANT(x) & SP_MBIT(SP_MBITS-1)); } @@ -74,10 +72,11 @@ if (!SETCX(IEEE754_INVALID_OPERATION)) { /* not enabled convert to a quiet NaN */ - if (ieee754_csr.noq) + SPMANT(r) &= (~SP_MBIT(SP_MBITS-1)); + if (ieee754sp_isnan(r)) return r; - SPMANT(r) |= SP_MBIT(SP_MBITS - 1); - return r; + else + return ieee754sp_indef(); } ax.op = op; @@ -100,6 +99,32 @@ } +static unsigned get_rounding(int sn, unsigned xm) +{ + /* inexact must round of 3 bits + */ + if (xm & (SP_MBIT(3) - 1)) { + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + } + return xm; +} + + /* generate a normal/denormal number with over,under handeling * sn is sign * xe is an unbiased exponent @@ -118,39 +143,58 @@ if (ieee754_csr.nod) { SETCX(IEEE754_UNDERFLOW); - return ieee754sp_zero(sn); - } + SETCX(IEEE754_INEXACT); - /* sticky right shift es bits - */ - SPXSRSXn(es); + switch(ieee754_csr.rm) { + case IEEE754_RN: + return ieee754sp_zero(sn); + case IEEE754_RZ: + return ieee754sp_zero(sn); + case IEEE754_RU: /* toward +Infinity */ + if(sn == 0) + return ieee754sp_min(0); + else + return ieee754sp_zero(1); + case IEEE754_RD: /* toward -Infinity */ + if(sn == 0) + return ieee754sp_zero(0); + else + return ieee754sp_min(1); + } + } - assert((xm & (SP_HIDDEN_BIT << 3)) == 0); - assert(xe == SP_EMIN); + if (xe == SP_EMIN - 1 + && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3)) + { + /* Not tiny after rounding */ + SETCX(IEEE754_INEXACT); + xm = get_rounding(sn, xm); + xm >>= 1; + /* Clear grs bits */ + xm &= ~(SP_MBIT(3) - 1); + xe++; + } + else { + /* sticky right shift es bits + */ + SPXSRSXn(es); + assert((xm & (SP_HIDDEN_BIT << 3)) == 0); + assert(xe == SP_EMIN); + } } if (xm & (SP_MBIT(3) - 1)) { SETCX(IEEE754_INEXACT); + if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { + SETCX(IEEE754_UNDERFLOW); + } + /* inexact must round of 3 bits */ - switch (ieee754_csr.rm) { - case IEEE754_RZ: - break; - case IEEE754_RN: - xm += 0x3 + ((xm >> 3) & 1); - /* xm += (xm&0x8)?0x4:0x3 */ - break; - case IEEE754_RU: /* toward +Infinity */ - if (!sn) /* ?? */ - xm += 0x8; - break; - case IEEE754_RD: /* toward -Infinity */ - if (sn) /* ?? */ - xm += 0x8; - break; - } + xm = get_rounding(sn, xm); /* adjust exponent for rounding add overflowing */ - if (xm >> (SP_MBITS + 1 + 3)) { /* add causes mantissa overflow */ + if (xm >> (SP_MBITS + 1 + 3)) { + /* add causes mantissa overflow */ xm >>= 1; xe++; } @@ -163,6 +207,7 @@ if (xe > SP_EMAX) { SETCX(IEEE754_OVERFLOW); + SETCX(IEEE754_INEXACT); /* -O can be table indexed by (rm,sn) */ switch (ieee754_csr.rm) { case IEEE754_RN: @@ -186,7 +231,8 @@ if ((xm & SP_HIDDEN_BIT) == 0) { /* we underflow (tiny/zero) */ assert(xe == SP_EMIN); - SETCX(IEEE754_UNDERFLOW); + if (ieee754_csr.mx & IEEE754_UNDERFLOW) + SETCX(IEEE754_UNDERFLOW); return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); } else { assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ diff -urN linux-2.4.18/arch/mips/math-emu/kernel_linkage.c linux-2.4.19-pre5/arch/mips/math-emu/kernel_linkage.c --- linux-2.4.18/arch/mips/math-emu/kernel_linkage.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/kernel_linkage.c Sat Mar 30 22:55:26 2002 @@ -20,13 +20,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * - *************************************************************************/ -/* * Routines corresponding to Linux kernel FP context * manipulation primitives for the Algorithmics MIPS * FPU Emulator */ - #include #include #include @@ -45,7 +42,7 @@ if (first) { first = 0; - printk("Algorithmics/MIPS FPU Emulator v1.4\n"); + printk("Algorithmics/MIPS FPU Emulator v1.5\n"); } current->thread.fpu.soft.sr = 0; diff -urN linux-2.4.18/arch/mips/math-emu/sp_add.c linux-2.4.19-pre5/arch/mips/math-emu/sp_add.c --- linux-2.4.18/arch/mips/math-emu/sp_add.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_add.c Sat Mar 30 22:55:26 2002 @@ -37,27 +37,23 @@ CLEARCX; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x, - y); + FLUSHXSP; + FLUSHYSP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y, "add", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x, "add", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754sp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/sp_cmp.c linux-2.4.19-pre5/arch/mips/math-emu/sp_cmp.c --- linux-2.4.18/arch/mips/math-emu/sp_cmp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_cmp.c Sat Mar 30 22:55:26 2002 @@ -29,9 +29,18 @@ int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp) { - CLEARCX; + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + FLUSHXSP; + FLUSHYSP; + CLEARCX; /* Even clear inexact flag here */ if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { + if (xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) + SETCX(IEEE754_INVALID_OPERATION); if (cmp & IEEE754_CUN) return 1; if (cmp & (IEEE754_CLT | IEEE754_CGT)) { diff -urN linux-2.4.18/arch/mips/math-emu/sp_div.c linux-2.4.19-pre5/arch/mips/math-emu/sp_div.c --- linux-2.4.18/arch/mips/math-emu/sp_div.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_div.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXSP; COMPYSP; - CLEARCX; - EXPLODEXSP; EXPLODEYSP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x, - y); + CLEARCX; + + FLUSHXSP; + FLUSHYSP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y, "div", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x, "div", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754sp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/sp_fdp.c linux-2.4.19-pre5/arch/mips/math-emu/sp_fdp.c --- linux-2.4.18/arch/mips/math-emu/sp_fdp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_fdp.c Sat Mar 30 22:55:26 2002 @@ -30,20 +30,24 @@ ieee754sp ieee754sp_fdp(ieee754dp x) { COMPXDP; + ieee754sp nan; + + EXPLODEXDP; CLEARCX; - EXPLODEXDP; + FLUSHXDP; switch (xc) { - case IEEE754_CLASS_QNAN: case IEEE754_CLASS_SNAN: - return ieee754sp_nanxcpt(buildsp(xs, - SP_EMAX + 1 + SP_EBIAS, - (unsigned long) - (xm >> - (DP_MBITS - SP_MBITS))), - "fdp", x); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp"); + case IEEE754_CLASS_QNAN: + nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (unsigned long) + (xm >> (DP_MBITS - SP_MBITS))); + if (!ieee754sp_isnan(nan)) + nan = ieee754sp_indef(); + return ieee754sp_nanxcpt(nan, "fdp", x); case IEEE754_CLASS_INF: return ieee754sp_inf(xs); case IEEE754_CLASS_ZERO: @@ -51,6 +55,10 @@ case IEEE754_CLASS_DNORM: /* cant possibly be sp representable */ SETCX(IEEE754_UNDERFLOW); + SETCX(IEEE754_INEXACT); + if ((ieee754_csr.rm == IEEE754_RU && !xs) || + (ieee754_csr.rm == IEEE754_RD && xs)) + return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x); return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); case IEEE754_CLASS_NORM: break; diff -urN linux-2.4.18/arch/mips/math-emu/sp_mul.c linux-2.4.19-pre5/arch/mips/math-emu/sp_mul.c --- linux-2.4.18/arch/mips/math-emu/sp_mul.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_mul.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXSP; COMPYSP; - CLEARCX; - EXPLODEXSP; EXPLODEYSP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x, - y); + CLEARCX; + + FLUSHXSP; + FLUSHYSP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y, "mul", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x, "mul", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754sp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/sp_simple.c linux-2.4.19-pre5/arch/mips/math-emu/sp_simple.c --- linux-2.4.18/arch/mips/math-emu/sp_simple.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_simple.c Sat Mar 30 22:55:26 2002 @@ -42,7 +42,16 @@ ieee754sp ieee754sp_neg(ieee754sp x) { + COMPXSP; + + EXPLODEXSP; CLEARCX; + FLUSHXSP; + + if (xc == IEEE754_CLASS_SNAN) { + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "neg"); + } if (ieee754sp_isnan(x)) /* but not infinity */ return ieee754sp_nanxcpt(x, "neg", x); @@ -55,7 +64,16 @@ ieee754sp ieee754sp_abs(ieee754sp x) { + COMPXSP; + + EXPLODEXSP; CLEARCX; + FLUSHXSP; + + if (xc == IEEE754_CLASS_SNAN) { + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "abs"); + } if (ieee754sp_isnan(x)) /* but not infinity */ return ieee754sp_nanxcpt(x, "abs", x); diff -urN linux-2.4.18/arch/mips/math-emu/sp_sqrt.c linux-2.4.19-pre5/arch/mips/math-emu/sp_sqrt.c --- linux-2.4.18/arch/mips/math-emu/sp_sqrt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_sqrt.c Sat Mar 30 22:55:26 2002 @@ -27,43 +27,45 @@ #include "ieee754sp.h" -static const struct ieee754sp_konst knan = { - 0, SP_EBIAS + SP_EMAX + 1, 0 -}; - -#define nan ((ieee754sp)knan) - ieee754sp ieee754sp_sqrt(ieee754sp x) { int sign = (int) 0x80000000; int ix, s, q, m, t, i; unsigned int r; - COMPXDP; + COMPXSP; /* take care of Inf and NaN */ - EXPLODEXDP; + EXPLODEXSP; + CLEARCX; + FLUSHXSP; /* x == INF or NAN? */ switch (xc) { case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_SNAN: /* sqrt(Nan) = Nan */ return ieee754sp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_SNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); case IEEE754_CLASS_ZERO: /* sqrt(0) = 0 */ return x; case IEEE754_CLASS_INF: - if (xs) + if (xs) { /* sqrt(-Inf) = Nan */ - return ieee754sp_nanxcpt(nan, "sqrt"); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); + } /* sqrt(+Inf) = Inf */ return x; case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: - if (xs) + if (xs) { /* sqrt(-x) = Nan */ - return ieee754sp_nanxcpt(nan, "sqrt"); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); + } break; } @@ -99,6 +101,7 @@ } if (ix != 0) { + SETCX(IEEE754_INEXACT); switch (ieee754_csr.rm) { case IEEE754_RP: q += 2; diff -urN linux-2.4.18/arch/mips/math-emu/sp_sub.c linux-2.4.19-pre5/arch/mips/math-emu/sp_sub.c --- linux-2.4.18/arch/mips/math-emu/sp_sub.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_sub.c Sat Mar 30 22:55:26 2002 @@ -32,32 +32,28 @@ COMPXSP; COMPYSP; - CLEARCX; - EXPLODEXSP; EXPLODEYSP; - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x, - y); + CLEARCX; + + FLUSHXSP; + FLUSHYSP; + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y, "sub", x, y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x, "sub", x, y); - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - return ieee754sp_bestnan(x, y); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): @@ -65,6 +61,7 @@ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return y; + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): diff -urN linux-2.4.18/arch/mips/math-emu/sp_tint.c linux-2.4.19-pre5/arch/mips/math-emu/sp_tint.c --- linux-2.4.18/arch/mips/math-emu/sp_tint.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_tint.c Sat Mar 30 22:55:26 2002 @@ -35,38 +35,74 @@ CLEARCX; EXPLODEXSP; + FLUSHXSP; switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); case IEEE754_CLASS_INF: - SETCX(IEEE754_OVERFLOW); - return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); case IEEE754_CLASS_ZERO: return 0; - case IEEE754_CLASS_DNORM: /* much to small */ - SETCX(IEEE754_UNDERFLOW); - return ieee754si_xcpt(0, "fixsp", x); + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; } if (xe >= 31) { - SETCX(IEEE754_OVERFLOW); - return ieee754si_xcpt(ieee754si_indef(), "fix", x); - } - if (xe < 0) { - SETCX(IEEE754_UNDERFLOW); - return ieee754si_xcpt(0, "fix", x); + /* look for valid corner case */ + if (xe == 31 && xs && xm == SP_HIDDEN_BIT) + return -2147483648; + /* Set invalid. We will only use overflow for floating + point overflow */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); } /* oh gawd */ if (xe > SP_MBITS) { xm <<= xe - SP_MBITS; - } else if (xe < SP_MBITS) { - /* XXX no rounding - */ - xm >>= SP_MBITS - xe; + } else { + unsigned long residue; + int round; + int sticky; + int odd; + + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; + } + else { + residue = xm << (32 - SP_MBITS + xe); + round = (residue >> 31) != 0; + sticky = (residue << 1) != 0; + xm >>= SP_MBITS - xe; + } + odd = (xm & 0x1) != 0x0; + switch (ieee754_csr.rm) { + case IEEE754_RN: + if (round && (sticky || odd)) + xm++; + break; + case IEEE754_RZ: + break; + case IEEE754_RU: /* toward +Infinity */ + if ((round || sticky) && !xs) + xm++; + break; + case IEEE754_RD: /* toward -Infinity */ + if ((round || sticky) && xs) + xm++; + break; + } + if ((xm >> 31) != 0) { + /* This can happen after rounding */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); + } + if (round || sticky) + SETCX(IEEE754_INEXACT); } if (xs) return -xm; diff -urN linux-2.4.18/arch/mips/math-emu/sp_tlong.c linux-2.4.19-pre5/arch/mips/math-emu/sp_tlong.c --- linux-2.4.18/arch/mips/math-emu/sp_tlong.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/math-emu/sp_tlong.c Sat Mar 30 22:55:26 2002 @@ -34,38 +34,74 @@ CLEARCX; EXPLODEXSP; + FLUSHXSP; switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - SETCX(IEEE754_INVALID_OPERATION); - return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); case IEEE754_CLASS_INF: - SETCX(IEEE754_OVERFLOW); + SETCX(IEEE754_INVALID_OPERATION); return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); case IEEE754_CLASS_ZERO: return 0; - case IEEE754_CLASS_DNORM: /* much to small */ - SETCX(IEEE754_UNDERFLOW); - return ieee754di_xcpt(0, "sp_tlong", x); + case IEEE754_CLASS_DNORM: case IEEE754_CLASS_NORM: break; } if (xe >= 63) { - SETCX(IEEE754_OVERFLOW); + /* look for valid corner case */ + if (xe == 63 && xs && xm == SP_HIDDEN_BIT) + return -9223372036854775808LL; + /* Set invalid. We will only use overflow for floating + point overflow */ + SETCX(IEEE754_INVALID_OPERATION); return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); } - if (xe < 0) { - SETCX(IEEE754_UNDERFLOW); - return ieee754di_xcpt(0, "sp_tlong", x); - } /* oh gawd */ if (xe > SP_MBITS) { xm <<= xe - SP_MBITS; } else if (xe < SP_MBITS) { - /* XXX no rounding - */ - xm >>= SP_MBITS - xe; + unsigned long residue; + int round; + int sticky; + int odd; + + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; + } + else { + residue = xm << (32 - SP_MBITS + xe); + round = (residue >> 31) != 0; + sticky = (residue << 1) != 0; + xm >>= SP_MBITS - xe; + } + odd = (xm & 0x1) != 0x0; + switch (ieee754_csr.rm) { + case IEEE754_RN: + if (round && (sticky || odd)) + xm++; + break; + case IEEE754_RZ: + break; + case IEEE754_RU: /* toward +Infinity */ + if ((round || sticky) && !xs) + xm++; + break; + case IEEE754_RD: /* toward -Infinity */ + if ((round || sticky) && xs) + xm++; + break; + } + if ((xm >> 63) != 0) { + /* This can happen after rounding */ + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754di_indef(), "sp_tlong", x); + } + if (round || sticky) + SETCX(IEEE754_INEXACT); } if (xs) return -xm; diff -urN linux-2.4.18/arch/mips/mips-boards/atlas/atlas_int.c linux-2.4.19-pre5/arch/mips/mips-boards/atlas/atlas_int.c --- linux-2.4.18/arch/mips/mips-boards/atlas/atlas_int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/atlas/atlas_int.c Sat Mar 30 22:55:26 2002 @@ -42,20 +42,12 @@ extern asmlinkage void mipsIRQ(void); extern void do_IRQ(int irq, struct pt_regs *regs); -unsigned long spurious_count = 0; -irq_desc_t irq_desc[NR_IRQS]; - #if 0 #define DEBUG_INT(x...) printk(x) #else #define DEBUG_INT(x...) #endif -void inline disable_irq_nosync(unsigned int irq_nr) -{ - disable_atlas_irq(irq_nr); -} - void disable_atlas_irq(unsigned int irq_nr) { atlas_hw0_icregs->intrsten = (1 << irq_nr); @@ -93,76 +85,6 @@ NULL }; -int get_irq_list(char *buf) -{ - int i, len = 0; - int num = 0; - struct irqaction *action; - - for (i = 0; i < ATLASINT_END; i++, num++) { - action = irq_desc[i].action; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [hw0]\n"); - } - return len; -} - -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - struct irqaction *action; - - DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); - - if (irq >= ATLASINT_END) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if(!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = 0; - irq_desc[irq].action = action; - enable_atlas_irq(irq); - - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction *action; - - if (irq >= ATLASINT_END) { - printk("Trying to free IRQ%d\n",irq); - return; - } - - action = irq_desc[irq].action; - irq_desc[irq].action = NULL; - disable_atlas_irq(irq); - kfree(action); -} - static inline int ls1bit32(unsigned int x) { int b = 31, s; @@ -194,9 +116,9 @@ DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); /* if action == NULL, then we don't have a handler for the irq */ - if ( action == NULL ) { + if (action == NULL) { printk("No handler for hw0 irq: %i\n", irq); - spurious_count++; + atomic_inc(&irq_err_count); return; } @@ -206,17 +128,6 @@ irq_exit(cpu, irq); return; -} - -unsigned long probe_irq_on (void) -{ - return 0; -} - - -int probe_irq_off (unsigned long irqs) -{ - return 0; } #ifdef CONFIG_REMOTE_DEBUG diff -urN linux-2.4.18/arch/mips/mips-boards/atlas/atlas_setup.c linux-2.4.19-pre5/arch/mips/mips-boards/atlas/atlas_setup.c --- linux-2.4.18/arch/mips/mips-boards/atlas/atlas_setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/atlas/atlas_setup.c Sat Mar 30 22:55:26 2002 @@ -28,8 +28,9 @@ #include #include #include -#include #include +#include +#include #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) extern void console_setup(char *, int *); @@ -47,6 +48,17 @@ extern void mips_reboot_setup(void); +const char *get_system_type(void) +{ + return "MIPS Atlas"; +} + +void __init bus_error_init(void) +{ +} + +extern void mips_time_init(void); + void __init atlas_setup(void) { #ifdef CONFIG_REMOTE_DEBUG @@ -110,6 +122,7 @@ mips_cpu.options &= ~MIPS_CPU_FPU; rtc_ops = &atlas_rtc_ops; + board_time_init = mips_time_init; mips_reboot_setup(); } diff -urN linux-2.4.18/arch/mips/mips-boards/generic/Makefile linux-2.4.19-pre5/arch/mips/mips-boards/generic/Makefile --- linux-2.4.18/arch/mips/mips-boards/generic/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/generic/Makefile Sat Mar 30 22:55:26 2002 @@ -2,8 +2,6 @@ # Carsten Langgaard, carstenl@mips.com # Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. # -# ######################################################################## -# # This program is free software; you can distribute it and/or modify it # under the terms of the GNU General Public License (Version 2) as # published by the Free Software Foundation. @@ -17,8 +15,6 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # -# ####################################################################### -# # Makefile for the MIPS boards generic routines under Linux. # # Note! Dependencies are done automagically by 'make dep', which also @@ -34,8 +30,9 @@ O_TARGET := mipsboards.o -obj-y := mipsIRQ.o pci.o reset.o display.o init.o \ +obj-y := mipsIRQ.o reset.o display.o init.o \ memory.o printf.o cmdline.o time.o +obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/mips-boards/generic/cmdline.c linux-2.4.19-pre5/arch/mips/mips-boards/generic/cmdline.c --- linux-2.4.18/arch/mips/mips-boards/generic/cmdline.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/generic/cmdline.c Sat Mar 30 22:55:26 2002 @@ -26,7 +26,7 @@ extern int prom_argc; extern char **prom_argv; -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; char * __init prom_getcmdline(void) { diff -urN linux-2.4.18/arch/mips/mips-boards/generic/init.c linux-2.4.19-pre5/arch/mips/mips-boards/generic/init.c --- linux-2.4.18/arch/mips/mips-boards/generic/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/generic/init.c Sat Mar 30 22:55:26 2002 @@ -29,8 +29,7 @@ #include /* Environment variable */ -typedef struct -{ +typedef struct { char *name; char *val; } t_env_var; @@ -126,9 +125,9 @@ #endif #if defined(CONFIG_MIPS_MALTA) - mips_io_port_base = MALTA_PORT_BASE; + set_io_port_base(MALTA_PORT_BASE); #else - mips_io_port_base = KSEG1; + set_io_port_base(KSEG1); #endif setup_prom_printf(0); prom_printf("\nLINUX started...\n"); diff -urN linux-2.4.18/arch/mips/mips-boards/generic/printf.c linux-2.4.19-pre5/arch/mips/mips-boards/generic/printf.c --- linux-2.4.18/arch/mips/mips-boards/generic/printf.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/generic/printf.c Sat Mar 30 22:55:26 2002 @@ -40,12 +40,12 @@ */ unsigned int atlas_serial_in(struct async_struct *info, int offset) { - return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff); + return inl(info->port + offset*8) & 0xff; } void atlas_serial_out(struct async_struct *info, int offset, int value) { - *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value; + outl(value, info->port + offset*8); } #define serial_in atlas_serial_in diff -urN linux-2.4.18/arch/mips/mips-boards/generic/time.c linux-2.4.19-pre5/arch/mips/mips-boards/generic/time.c --- linux-2.4.18/arch/mips/mips-boards/generic/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/generic/time.c Sat Mar 30 22:55:26 2002 @@ -23,6 +23,7 @@ * */ +#include #include #include #include @@ -31,8 +32,10 @@ #include #include +#include #include +#include #include #include @@ -133,13 +136,15 @@ */ void mips_timer_interrupt(struct pt_regs *regs) { + int cpu = smp_processor_id(); int irq = 7; if (r4k_offset == 0) goto null; + irq_enter(cpu, irq); do { - kstat.irqs[0][irq]++; + kstat.irqs[cpu][irq]++; do_timer(regs); /* Historical comment/code: @@ -153,12 +158,13 @@ if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec >= 500000 - (tick >> 1) - && xtime.tv_usec <= 500000 + (tick >> 1)) + && xtime.tv_usec <= 500000 + (tick >> 1)) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else /* do it again in 60 s */ last_rtc_update = xtime.tv_sec - 600; + } read_unlock(&xtime_lock); if ((timer_tick_count++ % HZ) == 0) { @@ -172,6 +178,10 @@ } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT) - r4k_cur) < 0x7fffffff); + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); return; @@ -245,7 +255,7 @@ return mktime(year, mon, day, hour, min, sec); } -void __init time_init(void) +void __init mips_time_init(void) { unsigned int est_freq, flags; @@ -271,140 +281,4 @@ xtime.tv_sec = get_mips_time(); xtime.tv_usec = 0; write_unlock_irqrestore(&xtime_lock, flags); -} - -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC ((1000000 << 32) / HZ & 0xffffffff) - -/* Cycle counter value at the previous timer interrupt.. */ - -static unsigned int timerhi = 0, timerlo = 0; - -/* - * FIXME: Does playing with the RP bit in c0_status interfere with this code? - */ -static unsigned long do_fast_gettimeoffset(void) -{ - u32 count; - unsigned long res, tmp; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies=0; - unsigned long quotient; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient=0; - - tmp = jiffies; - - quotient = cached_quotient; - - if (tmp && last_jiffies != tmp) { - last_jiffies = tmp; -#ifdef CONFIG_CPU_MIPS32 - if (last_jiffies != 0) { - unsigned long r0; - do_div64_32(r0, timerhi, timerlo, tmp); - do_div64_32(quotient, USECS_PER_JIFFY, - USECS_PER_JIFFY_FRAC, r0); - cached_quotient = quotient; - } -#else - __asm__(".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "lwu\t%0,%2\n\t" - "dsll32\t$1,%1,0\n\t" - "or\t$1,$1,%0\n\t" - "ddivu\t$0,$1,%3\n\t" - "mflo\t$1\n\t" - "dsll32\t%0,%4,0\n\t" - "nop\n\t" - "ddivu\t$0,%0,$1\n\t" - "mflo\t%0\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=&r" (quotient) - :"r" (timerhi), - "m" (timerlo), - "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); - cached_quotient = quotient; -#endif - } - - /* Get last timer tick in absolute kernel time */ - count = read_32bit_cp0_register(CP0_COUNT); - - /* .. relative to previous jiffy (32 bits is enough) */ - count -= timerlo; - - __asm__("multu\t%1,%2\n\t" - "mfhi\t%0" - :"=r" (res) - :"r" (count), - "r" (quotient)); - - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (res >= USECS_PER_JIFFY) - res = USECS_PER_JIFFY-1; - - return res; -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned int flags; - - read_lock_irqsave (&xtime_lock, flags); - *tv = xtime; - tv->tv_usec += do_fast_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. jiffies - wall_jiffies - * is nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore (&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} - -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 -= do_fast_gettimeoffset(); - - if (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); } diff -urN linux-2.4.18/arch/mips/mips-boards/malta/malta_int.c linux-2.4.19-pre5/arch/mips/mips-boards/malta/malta_int.c --- linux-2.4.18/arch/mips/mips-boards/malta/malta_int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/malta/malta_int.c Sat Mar 30 22:55:26 2002 @@ -50,18 +50,6 @@ GT_READ(GT_PCI0_IACK_OFS, irq); irq &= 0xFF; - /* - * IRQ7 is used to detect spurious interrupts. The interrupt - * acknowledge cycle returns IRQ7, if no interrupts is requested. We - * can differentiate between this situation and a "normal" IRQ7 by - * reading the ISR. - */ - if (irq == 7) { - outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3); - if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) - return; /* Spurious interrupt. */ - } - do_IRQ(irq, regs); } diff -urN linux-2.4.18/arch/mips/mips-boards/malta/malta_setup.c linux-2.4.19-pre5/arch/mips/mips-boards/malta/malta_setup.c --- linux-2.4.18/arch/mips/mips-boards/malta/malta_setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mips-boards/malta/malta_setup.c Sat Mar 30 22:55:26 2002 @@ -36,6 +36,7 @@ #include #endif #include +#include #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) extern void console_setup(char *, int *); @@ -65,6 +66,17 @@ #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) +const char *get_system_type(void) +{ + return "MIPS Malta"; +} + +void __init bus_error_init(void) +{ +} + +extern void mips_time_init(void); + void __init malta_setup(void) { #ifdef CONFIG_REMOTE_DEBUG @@ -122,6 +134,8 @@ mips_cpu.options &= ~MIPS_CPU_FPU; rtc_ops = &malta_rtc_ops; + board_time_init = mips_time_init; + #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif diff -urN linux-2.4.18/arch/mips/mm/Makefile linux-2.4.19-pre5/arch/mips/mm/Makefile --- linux-2.4.18/arch/mips/mm/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/Makefile Sat Mar 30 22:55:26 2002 @@ -5,23 +5,33 @@ # 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... + +.S.s: + $(CPP) $(AFLAGS) $< -o $@ +.S.o: + $(CC) $(AFLAGS) -c $< -o $@ O_TARGET := mm.o -export-objs += ioremap.o umap.o +export-objs += ioremap.o loadmmu.o umap.o obj-y += extable.o init.o ioremap.o fault.o loadmmu.o -obj-$(CONFIG_CPU_R3000) += r2300.o -obj-$(CONFIG_CPU_R4300) += r4xx0.o -obj-$(CONFIG_CPU_R4X00) += r4xx0.o -obj-$(CONFIG_CPU_VR41XX) += r4xx0.o -obj-$(CONFIG_CPU_R5000) += r4xx0.o -obj-$(CONFIG_CPU_NEVADA) += r4xx0.o -obj-$(CONFIG_CPU_R5432) += r5432.o -obj-$(CONFIG_CPU_RM7000) += rm7k.o -obj-$(CONFIG_CPU_MIPS32) += mips32.o -obj-$(CONFIG_CPU_MIPS64) += mips32.o +obj-$(CONFIG_CPU_R3000) += pg-r3k.o c-r3k.o c-tx39.o tlb-r3k.o \ + tlbex-r3k.o +obj-$(CONFIG_CPU_TX39XX) += pg-r3k.o c-tx39.o tlb-r3k.o tlbex-r3k.o +obj-$(CONFIG_CPU_TX49XX) += pg-r4k.o c-tx49.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R4300) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R4X00) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_VR41XX) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R5000) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_NEVADA) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R5432) += pg-r5432.o c-r5432.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_RM7000) += pg-rm7k.o c-rm7k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R10000) += pg-andes.o c-andes.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_MIPS32) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_MIPS64) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_SB1) += pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o + obj-$(CONFIG_SGI_IP22) += umap.o obj-$(CONFIG_BAGET_MIPS) += umap.o diff -urN linux-2.4.18/arch/mips/mm/andes.c linux-2.4.19-pre5/arch/mips/mm/andes.c --- linux-2.4.18/arch/mips/mm/andes.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/andes.c Thu Jan 1 01:00:00 1970 @@ -1,196 +0,0 @@ -/* - * andes.c: MMU and cache operations for the R10000 (ANDES). - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* page functions */ -void andes_clear_page(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%2\n" - "1:\tsw\t$0,(%0)\n\t" - "sw\t$0,4(%0)\n\t" - "sw\t$0,8(%0)\n\t" - "sw\t$0,12(%0)\n\t" - "addiu\t%0,32\n\t" - "sw\t$0,-16(%0)\n\t" - "sw\t$0,-12(%0)\n\t" - "sw\t$0,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t$0,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE) - :"$1","memory"); -} - -static void andes_copy_page(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%8\n" - "1:\tlw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "addiu\t%0,64\n\t" - "addiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE)); -} - -/* Cache operations. XXX Write these dave... */ -static inline void andes_flush_cache_all(void) -{ - /* XXX */ -} - -static void andes_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void andes_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void andes_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void andes_flush_page_to_ram(struct page * page) -{ - /* XXX */ -} - -static void __andes_flush_icache_range(unsigned long start, unsigned long end) -{ - /* XXX */ -} - -static void andes_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - /* XXX */ -} - -static void andes_flush_cache_sigtramp(unsigned long page) -{ - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); -} - -/* TLB operations. XXX Write these dave... */ -void flush_tlb_all(void) -{ - /* XXX */ -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -void pgd_init(unsigned long page) -{ -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - /* XXX */ -} - -void __init ld_mmu_andes(void) -{ - _clear_page = andes_clear_page; - _copy_page = andes_copy_page; - - _flush_cache_all = andes_flush_cache_all; - ___flush_cache_all = andes_flush_cache_all; - _flush_cache_mm = andes_flush_cache_mm; - _flush_cache_range = andes_flush_cache_range; - _flush_cache_page = andes_flush_cache_page; - _flush_cache_sigtramp = andes_flush_cache_sigtramp; - _flush_page_to_ram = andes_flush_page_to_ram; - _flush_icache_page = andes_flush_icache_page; - _flush_icache_range = andes_flush_icache_range; - - write_32bit_cp0_register(CP0_FRAMEMASK, 0); - - flush_cache_all(); - flush_tlb_all(); - - /* - * The R10k might even work for Linux/MIPS - but we're paranoid - * and refuse to run until this is tested on real silicon - */ - panic("CPU too expensive - making holiday in the ANDES!"); -} diff -urN linux-2.4.18/arch/mips/mm/c-andes.c linux-2.4.19-pre5/arch/mips/mm/c-andes.c --- linux-2.4.18/arch/mips/mm/c-andes.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-andes.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,129 @@ +/* + * 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) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int scache_lsz64; + +static void andes_flush_cache_all(void) +{ +} + +static void andes_flush_cache_mm(struct mm_struct *mm) +{ +} + +static void andes_flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ +} + +static void andes_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ +} + +static void andes_flush_page_to_ram(struct page *page) +{ +} + +/* Cache operations. These are only used with the virtual memory system, + not for non-coherent I/O so it's ok to ignore the secondary caches. */ +static void +andes_flush_cache_l1(void) +{ + blast_dcache32(); blast_icache64(); +} + +/* + * This is only used during initialization time. vmalloc() also calls + * this, but that will be changed pretty soon. + */ +static void +andes_flush_cache_l2(void) +{ + switch (sc_lsize()) { + case 64: + blast_scache64(); + break; + case 128: + blast_scache128(); + break; + default: + printk("Unknown L2 line size\n"); + while(1); + } +} + +static void andes___flush_cache_all(void) +{ + andes_flush_cache_l1(); + andes_flush_cache_l2(); +} + +void +andes_flush_icache_page(unsigned long page) +{ + if (scache_lsz64) + blast_scache64_page(page); + else + blast_scache128_page(page); +} + +static void +andes_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +void __init ld_mmu_andes(void) +{ + printk("Primary instruction cache %dkb, linesize %d bytes\n", + icache_size >> 10, ic_lsize); + printk("Primary data cache %dkb, linesize %d bytes\n", + dcache_size >> 10, dc_lsize); + printk("Secondary cache sized at %ldK, linesize %ld\n", + scache_size() >> 10, sc_lsize()); + + _clear_page = andes_clear_page; + _copy_page = andes_copy_page; + + _flush_cache_all = andes_flush_cache_all; + ___flush_cache_all = andes___flush_cache_all; + _flush_cache_mm = andes_flush_cache_mm; + _flush_cache_page = andes_flush_cache_page; + _flush_page_to_ram = andes_flush_page_to_ram; + _flush_cache_l1 = andes_flush_cache_l1; + _flush_cache_l2 = andes_flush_cache_l2; + _flush_cache_sigtramp = andes_flush_cache_sigtramp; + + switch (sc_lsize()) { + case 64: + scache_lsz64 = 1; + break; + case 128: + scache_lsz64 = 0; + break; + default: + printk("Unknown L2 line size\n"); + while(1); + } + + flush_cache_l1(); +} diff -urN linux-2.4.18/arch/mips/mm/c-mips32.c linux-2.4.19-pre5/arch/mips/mm/c-mips32.c --- linux-2.4.18/arch/mips/mm/c-mips32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-mips32.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,670 @@ +/* + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * MIPS32 CPU variant specific MMU/Cache routines. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* Primary cache parameters. */ +int icache_size, dcache_size; /* Size in bytes */ +int ic_lsize, dc_lsize; /* LineSize in bytes */ + +/* Secondary cache (if present) parameters. */ +unsigned int scache_size, sc_lsize; /* Again, in bytes */ + +#include +#include + +#undef DEBUG_CACHE + +/* + * Dummy cache handling routines for machines without boardcaches + */ +static void no_sc_noop(void) {} + +static struct bcache_ops no_sc_ops = { + (void *)no_sc_noop, (void *)no_sc_noop, + (void *)no_sc_noop, (void *)no_sc_noop +}; + +struct bcache_ops *bcops = &no_sc_ops; + +static inline void mips32_flush_cache_all_sc(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache(); blast_icache(); blast_scache(); + __restore_flags(flags); +} + +static inline void mips32_flush_cache_all_pc(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache(); blast_icache(); + __restore_flags(flags); +} + +static void +mips32_flush_cache_range_sc(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if(mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if(vma) { + if(mm->context != current->mm->context) { + mips32_flush_cache_all_sc(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void mips32_flush_cache_range_pc(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache(); blast_icache(); + __restore_flags(flags); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void mips32_flush_cache_mm_sc(struct mm_struct *mm) +{ + if(mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + mips32_flush_cache_all_sc(); + } +} + +static void mips32_flush_cache_mm_pc(struct mm_struct *mm) +{ + if(mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + mips32_flush_cache_all_pc(); + } +} + + + + + +static void mips32_flush_cache_page_sc(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache_page_indexed(page); + blast_scache_page_indexed(page); + } else + blast_scache_page(page); +out: + __restore_flags(flags); +} + +static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since Mips32 caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm == current->active_mm) { + blast_dcache_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache_page_indexed(page); + } +out: + __restore_flags(flags); +} + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void mips32_flush_page_to_ram_sc(struct page *page) +{ + blast_scache_page((unsigned long)page_address(page)); +} + +static void mips32_flush_page_to_ram_pc(struct page *page) +{ + blast_dcache_page((unsigned long)page_address(page)); +} + +static void +mips32_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) +{ + /* + * We did an scache flush therefore PI is already clean. + */ +} + +static void +mips32_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +static void +mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + int address; + + if (!(vma->vm_flags & VM_EXEC)) + return; + + address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & (dcache_size - 1)); + blast_icache_page_indexed(address); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + */ +static void +mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + bc_wback_inv(addr, size); +} + +static void +mips32_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + + bc_inv(addr, size); +} + +static void +mips32_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +mips32_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("mips32_dma_cache called - should not happen."); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void mips32_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +/* Detect and size the various caches. */ +static void __init probe_icache(unsigned long config) +{ + unsigned long config1; + unsigned int lsize; + + if (!(config & (1 << 31))) { + /* + * Not a MIPS32 complainant CPU. + * Config 1 register not supported, we assume R4k style. + */ + icache_size = 1 << (12 + ((config >> 9) & 7)); + ic_lsize = 16 << ((config >> 5) & 1); + mips_cpu.icache.linesz = ic_lsize; + + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1; + mips_cpu.icache.sets = + (icache_size / ic_lsize) / mips_cpu.icache.ways; + } else { + config1 = read_mips32_cp0_config1(); + + if ((lsize = ((config1 >> 19) & 7))) + mips_cpu.icache.linesz = 2 << lsize; + else + mips_cpu.icache.linesz = lsize; + mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7); + mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7); + + ic_lsize = mips_cpu.icache.linesz; + icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * + ic_lsize; + } + printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n", + icache_size >> 10, ic_lsize, mips_cpu.icache.ways); +} + +static void __init probe_dcache(unsigned long config) +{ + unsigned long config1; + unsigned int lsize; + + if (!(config & (1 << 31))) { + /* + * Not a MIPS32 complainant CPU. + * Config 1 register not supported, we assume R4k style. + */ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + dc_lsize = 16 << ((config >> 4) & 1); + mips_cpu.dcache.linesz = dc_lsize; + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1; + mips_cpu.dcache.sets = + (dcache_size / dc_lsize) / mips_cpu.dcache.ways; + } else { + config1 = read_mips32_cp0_config1(); + + if ((lsize = ((config1 >> 10) & 7))) + mips_cpu.dcache.linesz = 2 << lsize; + else + mips_cpu.dcache.linesz= lsize; + mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7); + mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7); + + dc_lsize = mips_cpu.dcache.linesz; + dcache_size = + mips_cpu.dcache.sets * mips_cpu.dcache.ways + * dc_lsize; + } + printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n", + dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways); +} + + +/* If you even _breathe_ on this function, look at the gcc output + * and make sure it does not pop things on and off the stack for + * the cache sizing loop that executes in KSEG1 space or else + * you will crash and burn badly. You have been warned. + */ +static int __init probe_scache(unsigned long config) +{ + extern unsigned long stext; + unsigned long flags, addr, begin, end, pow2; + int tmp; + + if (mips_cpu.scache.flags == MIPS_CACHE_NOT_PRESENT) + return 0; + + tmp = ((config >> 17) & 1); + if(tmp) + return 0; + tmp = ((config >> 22) & 3); + switch(tmp) { + case 0: + sc_lsize = 16; + break; + case 1: + sc_lsize = 32; + break; + case 2: + sc_lsize = 64; + break; + case 3: + sc_lsize = 128; + break; + } + + begin = (unsigned long) &stext; + begin &= ~((4 * 1024 * 1024) - 1); + end = begin + (4 * 1024 * 1024); + + /* This is such a bitch, you'd think they would make it + * easy to do this. Away you daemons of stupidity! + */ + __save_and_cli(flags); + + /* Fill each size-multiple cache line with a valid tag. */ + pow2 = (64 * 1024); + for(addr = begin; addr < end; addr = (begin + pow2)) { + unsigned long *p = (unsigned long *) addr; + __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ + pow2 <<= 1; + } + + /* Load first line with zero (therefore invalid) tag. */ + set_taglo(0); + set_taghi(0); + __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 8, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 9, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 11, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + + /* Now search for the wrap around point. */ + pow2 = (128 * 1024); + tmp = 0; + for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) { + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 7, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (addr)); + __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ + if(!get_taglo()) + break; + pow2 <<= 1; + } + __restore_flags(flags); + addr -= begin; + printk("Secondary cache sized at %dK linesize %d bytes.\n", + (int) (addr >> 10), sc_lsize); + scache_size = addr; + return 1; +} + +static void __init setup_noscache_funcs(void) +{ + _clear_page = (void *)mips32_clear_page_dc; + _copy_page = (void *)mips32_copy_page_dc; + _flush_cache_all = mips32_flush_cache_all_pc; + ___flush_cache_all = mips32_flush_cache_all_pc; + _flush_cache_mm = mips32_flush_cache_mm_pc; + _flush_cache_range = mips32_flush_cache_range_pc; + _flush_cache_page = mips32_flush_cache_page_pc; + _flush_page_to_ram = mips32_flush_page_to_ram_pc; + + _flush_icache_page = mips32_flush_icache_page; + + _dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc; + _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_inv = mips32_dma_cache_inv_pc; +} + +static void __init setup_scache_funcs(void) +{ + _flush_cache_all = mips32_flush_cache_all_sc; + ___flush_cache_all = mips32_flush_cache_all_sc; + _flush_cache_mm = mips32_flush_cache_mm_sc; + _flush_cache_range = mips32_flush_cache_range_sc; + _flush_cache_page = mips32_flush_cache_page_sc; + _flush_page_to_ram = mips32_flush_page_to_ram_sc; + _clear_page = (void *)mips32_clear_page_sc; + _copy_page = (void *)mips32_copy_page_sc; + + _flush_icache_page = mips32_flush_icache_page_s; + + _dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc; + _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_inv = mips32_dma_cache_inv_sc; +} + +typedef int (*probe_func_t)(unsigned long); + +static inline void __init setup_scache(unsigned int config) +{ + probe_func_t probe_scache_kseg1; + int sc_present = 0; + + /* Maybe the cpu knows about a l2 cache? */ + probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); + sc_present = probe_scache_kseg1(config); + + if (sc_present) { + mips_cpu.scache.linesz = sc_lsize; + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1; + mips_cpu.scache.sets = + (scache_size / sc_lsize) / mips_cpu.scache.ways; + + setup_scache_funcs(); + return; + } + + setup_noscache_funcs(); +} + +void __init ld_mmu_mips32(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + +#ifdef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + setup_scache(config); + + _flush_cache_sigtramp = mips32_flush_cache_sigtramp; + _flush_icache_range = mips32_flush_icache_range; /* Ouch */ + + __flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips/mm/c-r3k.c linux-2.4.19-pre5/arch/mips/mm/c-r3k.c --- linux-2.4.18/arch/mips/mm/c-r3k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-r3k.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,347 @@ +/* + * r2300.c: R2000 and R3000 specific mmu/cache code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * with a lot of changes to make this thing work for R3000s + * Tx39XX R4k style caches added. HK + * Copyright (C) 1998, 1999, 2000 Harald Koerfgen + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long icache_size, dcache_size; /* Size in bytes */ +static unsigned long icache_lsize, dcache_lsize; /* Size in bytes */ + +#undef DEBUG_CACHE + +unsigned long __init r3k_cache_size(unsigned long ca_flags) +{ + unsigned long flags, status, dummy, size; + volatile unsigned long *p; + + p = (volatile unsigned long *) KSEG0; + + flags = read_32bit_cp0_register(CP0_STATUS); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); + + *p = 0xa5a55a5a; + dummy = *p; + status = read_32bit_cp0_register(CP0_STATUS); + + if (dummy != 0xa5a55a5a || (status & ST0_CM)) { + size = 0; + } else { + for (size = 128; size <= 0x40000; size <<= 1) + *(p + size) = 0; + *p = -1; + for (size = 128; + (size <= 0x40000) && (*(p + size) == 0); + size <<= 1) + ; + if (size > 0x40000) + size = 0; + } + + write_32bit_cp0_register(CP0_STATUS, flags); + + return size * sizeof(*p); +} + +unsigned long __init r3k_cache_lsize(unsigned long ca_flags) +{ + unsigned long flags, status, lsize, i; + volatile unsigned long *p; + + p = (volatile unsigned long *) KSEG0; + + flags = read_32bit_cp0_register(CP0_STATUS); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); + + for (i = 0; i < 128; i++) + *(p + i) = 0; + *(volatile unsigned char *)p = 0; + for (lsize = 1; lsize < 128; lsize <<= 1) { + *(p + lsize); + status = read_32bit_cp0_register(CP0_STATUS); + if (!(status & ST0_CM)) + break; + } + for (i = 0; i < 128; i += lsize) + *(volatile unsigned char *)(p + i) = 0; + + write_32bit_cp0_register(CP0_STATUS, flags); + + return lsize * sizeof(*p); +} + +static void __init r3k_probe_cache(void) +{ + dcache_size = r3k_cache_size(ST0_ISC); + if (dcache_size) + dcache_lsize = r3k_cache_lsize(ST0_ISC); + + + icache_size = r3k_cache_size(ST0_ISC|ST0_SWC); + if (icache_size) + icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC); +} + +static void r3k_flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long size, i, flags; + volatile unsigned char *p; + + size = end - start; + if (size > icache_size || KSEGX(start) != KSEG0) { + start = KSEG0; + size = icache_size; + } + p = (char *)start; + + flags = read_32bit_cp0_register(CP0_STATUS); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); + + for (i = 0; i < size; i += 0x080) { + asm ( "sb\t$0, 0x000(%0)\n\t" + "sb\t$0, 0x004(%0)\n\t" + "sb\t$0, 0x008(%0)\n\t" + "sb\t$0, 0x00c(%0)\n\t" + "sb\t$0, 0x010(%0)\n\t" + "sb\t$0, 0x014(%0)\n\t" + "sb\t$0, 0x018(%0)\n\t" + "sb\t$0, 0x01c(%0)\n\t" + "sb\t$0, 0x020(%0)\n\t" + "sb\t$0, 0x024(%0)\n\t" + "sb\t$0, 0x028(%0)\n\t" + "sb\t$0, 0x02c(%0)\n\t" + "sb\t$0, 0x030(%0)\n\t" + "sb\t$0, 0x034(%0)\n\t" + "sb\t$0, 0x038(%0)\n\t" + "sb\t$0, 0x03c(%0)\n\t" + "sb\t$0, 0x040(%0)\n\t" + "sb\t$0, 0x044(%0)\n\t" + "sb\t$0, 0x048(%0)\n\t" + "sb\t$0, 0x04c(%0)\n\t" + "sb\t$0, 0x050(%0)\n\t" + "sb\t$0, 0x054(%0)\n\t" + "sb\t$0, 0x058(%0)\n\t" + "sb\t$0, 0x05c(%0)\n\t" + "sb\t$0, 0x060(%0)\n\t" + "sb\t$0, 0x064(%0)\n\t" + "sb\t$0, 0x068(%0)\n\t" + "sb\t$0, 0x06c(%0)\n\t" + "sb\t$0, 0x070(%0)\n\t" + "sb\t$0, 0x074(%0)\n\t" + "sb\t$0, 0x078(%0)\n\t" + "sb\t$0, 0x07c(%0)\n\t" + : : "r" (p) ); + p += 0x080; + } + + write_32bit_cp0_register(CP0_STATUS, flags); +} + +static void r3k_flush_dcache_range(unsigned long start, unsigned long end) +{ + unsigned long size, i, flags; + volatile unsigned char *p; + + size = end - start; + if (size > dcache_size || KSEGX(start) != KSEG0) { + start = KSEG0; + size = dcache_size; + } + p = (char *)start; + + flags = read_32bit_cp0_register(CP0_STATUS); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC); + + for (i = 0; i < size; i += 0x080) { + asm ( "sb\t$0, 0x000(%0)\n\t" + "sb\t$0, 0x004(%0)\n\t" + "sb\t$0, 0x008(%0)\n\t" + "sb\t$0, 0x00c(%0)\n\t" + "sb\t$0, 0x010(%0)\n\t" + "sb\t$0, 0x014(%0)\n\t" + "sb\t$0, 0x018(%0)\n\t" + "sb\t$0, 0x01c(%0)\n\t" + "sb\t$0, 0x020(%0)\n\t" + "sb\t$0, 0x024(%0)\n\t" + "sb\t$0, 0x028(%0)\n\t" + "sb\t$0, 0x02c(%0)\n\t" + "sb\t$0, 0x030(%0)\n\t" + "sb\t$0, 0x034(%0)\n\t" + "sb\t$0, 0x038(%0)\n\t" + "sb\t$0, 0x03c(%0)\n\t" + "sb\t$0, 0x040(%0)\n\t" + "sb\t$0, 0x044(%0)\n\t" + "sb\t$0, 0x048(%0)\n\t" + "sb\t$0, 0x04c(%0)\n\t" + "sb\t$0, 0x050(%0)\n\t" + "sb\t$0, 0x054(%0)\n\t" + "sb\t$0, 0x058(%0)\n\t" + "sb\t$0, 0x05c(%0)\n\t" + "sb\t$0, 0x060(%0)\n\t" + "sb\t$0, 0x064(%0)\n\t" + "sb\t$0, 0x068(%0)\n\t" + "sb\t$0, 0x06c(%0)\n\t" + "sb\t$0, 0x070(%0)\n\t" + "sb\t$0, 0x074(%0)\n\t" + "sb\t$0, 0x078(%0)\n\t" + "sb\t$0, 0x07c(%0)\n\t" + : : "r" (p) ); + p += 0x080; + } + + write_32bit_cp0_register(CP0_STATUS,flags); +} + +static inline unsigned long get_phys_page (unsigned long addr, + struct mm_struct *mm) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long physpage; + + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + pte = pte_offset(pmd, addr); + + if ((physpage = pte_val(*pte)) & _PAGE_VALID) + return KSEG0ADDR(physpage & PAGE_MASK); + + return 0; +} + +static inline void r3k_flush_cache_all(void) +{ +} + +static inline void r3k___flush_cache_all(void) +{ + r3k_flush_icache_range(KSEG0, KSEG0 + icache_size); +} + +static void r3k_flush_cache_mm(struct mm_struct *mm) +{ +} + +static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ +} + +static void r3k_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ +} + +static void r3k_flush_page_to_ram(struct page * page) +{ + /* + * Nothing to be done + */ +} + +static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long physpage; + + if (mm->context == 0) + return; + + if (!(vma->vm_flags & VM_EXEC)) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + + physpage = (unsigned long) page_address(page); + if (physpage) + r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); +} + +static void r3k_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("csigtramp[%08lx]", addr); +#endif + + flags = read_32bit_cp0_register(CP0_STATUS); + + write_32bit_cp0_register(CP0_STATUS, flags&~ST0_IEC); + + /* Fill the TLB to avoid an exception with caches isolated. */ + asm ( "lw\t$0, 0x000(%0)\n\t" + "lw\t$0, 0x004(%0)\n\t" + : : "r" (addr) ); + + write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); + + asm ( "sb\t$0, 0x000(%0)\n\t" + "sb\t$0, 0x004(%0)\n\t" + : : "r" (addr) ); + + write_32bit_cp0_register(CP0_STATUS, flags); +} + +static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) +{ + wbflush(); + r3k_flush_dcache_range(start, start + size); +} + +void __init ld_mmu_r23000(void) +{ + unsigned long config; + + _clear_page = r3k_clear_page; + _copy_page = r3k_copy_page; + + r3k_probe_cache(); + + _flush_cache_all = r3k_flush_cache_all; + ___flush_cache_all = r3k___flush_cache_all; + _flush_cache_mm = r3k_flush_cache_mm; + _flush_cache_range = r3k_flush_cache_range; + _flush_cache_page = r3k_flush_cache_page; + _flush_cache_sigtramp = r3k_flush_cache_sigtramp; + _flush_page_to_ram = r3k_flush_page_to_ram; + _flush_icache_page = r3k_flush_icache_page; + _flush_icache_range = r3k_flush_icache_range; + + _dma_cache_wback_inv = r3k_dma_cache_wback_inv; + + printk("Primary instruction cache %dkb, linesize %d bytes\n", + (int) (icache_size >> 10), (int) icache_lsize); + printk("Primary data cache %dkb, linesize %d bytes\n", + (int) (dcache_size >> 10), (int) dcache_lsize); + +} diff -urN linux-2.4.18/arch/mips/mm/c-r4k.c linux-2.4.19-pre5/arch/mips/mm/c-r4k.c --- linux-2.4.18/arch/mips/mm/c-r4k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-r4k.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,1575 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org + * + * To do: + * + * - this code is a overbloated pig + * - many of the bug workarounds are not efficient at all, but at + * least they are functional ... + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +static int ic_lsize, dc_lsize; /* LineSize in bytes */ + +/* Secondary cache (if present) parameters. */ +static unsigned int scache_size, sc_lsize; /* Again, in bytes */ + +#include +#include + +#undef DEBUG_CACHE + +/* + * Dummy cache handling routines for machines without boardcaches + */ +static void no_sc_noop(void) {} + +static struct bcache_ops no_sc_ops = { + (void *)no_sc_noop, (void *)no_sc_noop, + (void *)no_sc_noop, (void *)no_sc_noop +}; + +struct bcache_ops *bcops = &no_sc_ops; + +/* + * On processors with QED R4600 style two set assosicative cache + * this is the bit which selects the way in the cache for the + * indexed cachops. + */ +#define icache_waybit (icache_size >> 1) +#define dcache_waybit (dcache_size >> 1) + +/* + * If you think for one second that this stuff coming up is a lot + * of bulky code eating too many kernel cache lines. Think _again_. + * + * Consider: + * 1) Taken branches have a 3 cycle penalty on R4k + * 2) The branch itself is a real dead cycle on even R4600/R5000. + * 3) Only one of the following variants of each type is even used by + * the kernel based upon the cache parameters we detect at boot time. + * + * QED. + */ + +static inline void r4k_flush_cache_all_s16d16i16(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); blast_scache16(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s32d16i16(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); blast_scache32(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s64d16i16(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); blast_scache64(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s128d16i16(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); blast_scache128(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s32d32i32(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache32(); blast_icache32(); blast_scache32(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s64d32i32(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache32(); blast_icache32(); blast_scache64(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_s128d32i32(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache32(); blast_icache32(); blast_scache128(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_d16i16(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); + __restore_flags(flags); +} + +static inline void r4k_flush_cache_all_d32i32(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache32(); blast_icache32(); + __restore_flags(flags); +} + +static void +r4k_flush_cache_range_s16d16i16(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s16d16i16(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while (start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache16_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void +r4k_flush_cache_range_s32d16i16(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s32d16i16(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache32_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if(vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s64d16i16(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache64_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s128d16i16(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache128_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s32d32i32(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache32_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s64d32i32(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache64_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + r4k_flush_cache_all_s128d32i32(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache128_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void r4k_flush_cache_range_d16i16(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache16(); blast_icache16(); + __restore_flags(flags); + } +} + +static void r4k_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache32(); blast_icache32(); + __restore_flags(flags); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void r4k_flush_cache_mm_s16d16i16(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s16d16i16(); + } +} + +static void r4k_flush_cache_mm_s32d16i16(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s32d16i16(); + } +} + +static void r4k_flush_cache_mm_s64d16i16(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s64d16i16(); + } +} + +static void r4k_flush_cache_mm_s128d16i16(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s128d16i16(); + } +} + +static void r4k_flush_cache_mm_s32d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s32d32i32(); + } +} + +static void r4k_flush_cache_mm_s64d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s64d32i32(); + } +} + +static void r4k_flush_cache_mm_s128d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_s128d32i32(); + } +} + +static void r4k_flush_cache_mm_d16i16(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_d16i16(); + } +} + +static void r4k_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r4k_flush_cache_all_d32i32(); + } +} + +static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache16_page_indexed(page); + blast_scache16_page_indexed(page); + } else + blast_scache16_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache16_page_indexed(page); + blast_scache32_page_indexed(page); + } else + blast_scache32_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache16_page_indexed(page); + blast_scache64_page_indexed(page); + } else + blast_scache64_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache16_page_indexed(page); + blast_scache128_page_indexed(page); + } else + blast_scache128_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache32_page_indexed(page); + blast_scache32_page_indexed(page); + } else + blast_scache32_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache32_page_indexed(page); + blast_scache64_page_indexed(page); + } else + blast_scache64_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache32_page_indexed(page); + blast_scache128_page_indexed(page); + } else + blast_scache128_page(page); +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm == current->active_mm) { + blast_dcache16_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache16_page_indexed(page); + } +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + } +out: + __restore_flags(flags); +} + +static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + blast_dcache32_page_indexed(page ^ dcache_waybit); + } +out: + __restore_flags(flags); +} + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void r4k_flush_page_to_ram_s16(struct page *page) +{ + blast_scache16_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_s32(struct page *page) +{ + blast_scache32_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_s64(struct page *page) +{ + blast_scache64_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_s128(struct page *page) +{ + blast_scache128_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_d16(struct page *page) +{ + blast_dcache16_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_d32(struct page *page) +{ + blast_dcache32_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_d32_r4600(struct page *page) +{ + unsigned long flags; + + __save_and_cli(flags); /* For R4600 v1.7 bug. */ + blast_dcache32_page((unsigned long)page_address(page)); + __restore_flags(flags); +} + +static void +r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) +{ + /* + * We did an scache flush therefore PI is already clean. + */ +} + +static void +r4k_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + flush_cache_all(); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + * + * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Inv_D, + * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Exclusive_D will only + * operate correctly if the internal data cache refill buffer is empty. These + * CACHE instructions should be separated from any potential data cache miss + * by a load instruction to an uncached address to empty the response buffer." + * (Revision 2.0 device errata from IDT available on http://www.idt.com/ + * in .pdf format.) + */ +static void +r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + /* Workaround for R4600 bug. See comment above. */ + __save_and_cli(flags); + *(volatile unsigned long *)KSEG1; + + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + bc_wback_inv(addr, size); +} + +static void +r4k_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + /* Workaround for R4600 bug. See comment above. */ + __save_and_cli(flags); + *(volatile unsigned long *)KSEG1; + + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + + bc_inv(addr, size); +} + +static void +r4k_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +r4k_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("r4k_dma_cache called - should not happen."); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void r4k_flush_cache_sigtramp(unsigned long addr) +{ + __asm__ __volatile__("nop;nop;nop;nop"); /* R4600 V1.7 */ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +static void r4600v20k_flush_cache_sigtramp(unsigned long addr) +{ + unsigned int flags; + + __save_and_cli(flags); + + /* Clear internal cache refill buffer */ + *(volatile unsigned int *)KSEG1; + + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); + + __restore_flags(flags); +} + +/* Detect and size the various r4k caches. */ +static void __init probe_icache(unsigned long config) +{ + switch (mips_cpu.cputype) { + case CPU_VR41XX: + icache_size = 1 << (10 + ((config >> 9) & 7)); + break; + default: + icache_size = 1 << (12 + ((config >> 9) & 7)); + break; + } + ic_lsize = 16 << ((config >> 5) & 1); + + printk("Primary instruction cache %dkb, linesize %d bytes.\n", + icache_size >> 10, ic_lsize); +} + +static void __init probe_dcache(unsigned long config) +{ + switch (mips_cpu.cputype) { + case CPU_VR41XX: + dcache_size = 1 << (10 + ((config >> 6) & 7)); + break; + default: + dcache_size = 1 << (12 + ((config >> 6) & 7)); + break; + } + dc_lsize = 16 << ((config >> 4) & 1); + + printk("Primary data cache %dkb, linesize %d bytes.\n", + dcache_size >> 10, dc_lsize); +} + + +/* If you even _breathe_ on this function, look at the gcc output + * and make sure it does not pop things on and off the stack for + * the cache sizing loop that executes in KSEG1 space or else + * you will crash and burn badly. You have been warned. + */ +static int __init probe_scache(unsigned long config) +{ + extern unsigned long stext; + unsigned long flags, addr, begin, end, pow2; + int tmp; + + tmp = ((config >> 17) & 1); + if(tmp) + return 0; + tmp = ((config >> 22) & 3); + switch(tmp) { + case 0: + sc_lsize = 16; + break; + case 1: + sc_lsize = 32; + break; + case 2: + sc_lsize = 64; + break; + case 3: + sc_lsize = 128; + break; + } + + begin = (unsigned long) &stext; + begin &= ~((4 * 1024 * 1024) - 1); + end = begin + (4 * 1024 * 1024); + + /* This is such a bitch, you'd think they would make it + * easy to do this. Away you daemons of stupidity! + */ + __save_and_cli(flags); + + /* Fill each size-multiple cache line with a valid tag. */ + pow2 = (64 * 1024); + for(addr = begin; addr < end; addr = (begin + pow2)) { + unsigned long *p = (unsigned long *) addr; + __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ + pow2 <<= 1; + } + + /* Load first line with zero (therefore invalid) tag. */ + set_taglo(0); + set_taghi(0); + __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 8, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 9, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 11, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + + /* Now search for the wrap around point. */ + pow2 = (128 * 1024); + tmp = 0; + for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) { + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 7, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (addr)); + __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ + if(!get_taglo()) + break; + pow2 <<= 1; + } + __restore_flags(flags); + addr -= begin; + printk("Secondary cache sized at %dK linesize %d bytes.\n", + (int) (addr >> 10), sc_lsize); + scache_size = addr; + return 1; +} + +static void __init setup_noscache_funcs(void) +{ + unsigned int prid; + + switch(dc_lsize) { + case 16: + _clear_page = r4k_clear_page_d16; + _copy_page = r4k_copy_page_d16; + _flush_cache_all = r4k_flush_cache_all_d16i16; + _flush_cache_mm = r4k_flush_cache_mm_d16i16; + _flush_cache_range = r4k_flush_cache_range_d16i16; + _flush_cache_page = r4k_flush_cache_page_d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_d16; + break; + case 32: + prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0; + if (prid == 0x2010) { /* R4600 V1.7 */ + _clear_page = r4k_clear_page_r4600_v1; + _copy_page = r4k_copy_page_r4600_v1; + _flush_page_to_ram = r4k_flush_page_to_ram_d32_r4600; + } else if (prid == 0x2020) { /* R4600 V2.0 */ + _clear_page = r4k_clear_page_r4600_v2; + _copy_page = r4k_copy_page_r4600_v2; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; + } else { + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; + } + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_cache_range = r4k_flush_cache_range_d32i32; + _flush_cache_page = r4k_flush_cache_page_d32i32; + break; + } + ___flush_cache_all = _flush_cache_all; + + _flush_icache_page = r4k_flush_icache_page_p; + + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_pc; +} + +static void __init setup_scache_funcs(void) +{ + switch(sc_lsize) { + case 16: + switch(dc_lsize) { + case 16: + _flush_cache_all = r4k_flush_cache_all_s16d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s16d16i16; + _flush_cache_range = r4k_flush_cache_range_s16d16i16; + _flush_cache_page = r4k_flush_cache_page_s16d16i16; + break; + case 32: + panic("Invalid cache configuration detected"); + }; + _flush_page_to_ram = r4k_flush_page_to_ram_s16; + _clear_page = r4k_clear_page_s16; + _copy_page = r4k_copy_page_s16; + break; + case 32: + switch(dc_lsize) { + case 16: + _flush_cache_all = r4k_flush_cache_all_s32d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s32d16i16; + _flush_cache_range = r4k_flush_cache_range_s32d16i16; + _flush_cache_page = r4k_flush_cache_page_s32d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s32d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; + _flush_cache_range = r4k_flush_cache_range_s32d32i32; + _flush_cache_page = r4k_flush_cache_page_s32d32i32; + break; + }; + _flush_page_to_ram = r4k_flush_page_to_ram_s32; + _clear_page = r4k_clear_page_s32; + _copy_page = r4k_copy_page_s32; + break; + case 64: + switch(dc_lsize) { + case 16: + _flush_cache_all = r4k_flush_cache_all_s64d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s64d16i16; + _flush_cache_range = r4k_flush_cache_range_s64d16i16; + _flush_cache_page = r4k_flush_cache_page_s64d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s64d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; + _flush_cache_range = r4k_flush_cache_range_s64d32i32; + _flush_cache_page = r4k_flush_cache_page_s64d32i32; + break; + }; + _flush_page_to_ram = r4k_flush_page_to_ram_s64; + _clear_page = r4k_clear_page_s64; + _copy_page = r4k_copy_page_s64; + break; + case 128: + switch(dc_lsize) { + case 16: + _flush_cache_all = r4k_flush_cache_all_s128d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s128d16i16; + _flush_cache_range = r4k_flush_cache_range_s128d16i16; + _flush_cache_page = r4k_flush_cache_page_s128d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s128d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; + _flush_cache_range = r4k_flush_cache_range_s128d32i32; + _flush_cache_page = r4k_flush_cache_page_s128d32i32; + break; + }; + _flush_page_to_ram = r4k_flush_page_to_ram_s128; + _clear_page = r4k_clear_page_s128; + _copy_page = r4k_copy_page_s128; + break; + } + ___flush_cache_all = _flush_cache_all; + _flush_icache_page = r4k_flush_icache_page_s; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_sc; +} + +typedef int (*probe_func_t)(unsigned long); + +static inline void __init setup_scache(unsigned int config) +{ + probe_func_t probe_scache_kseg1; + int sc_present = 0; + + /* Maybe the cpu knows about a l2 cache? */ + probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); + sc_present = probe_scache_kseg1(config); + + if (sc_present) { + setup_scache_funcs(); + return; + } + + setup_noscache_funcs(); +} + +void __init ld_mmu_r4xx0(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + +#ifdef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + setup_scache(config); + + switch(mips_cpu.cputype) { + case CPU_R4600: /* QED style two way caches? */ + case CPU_R4700: + case CPU_R5000: + case CPU_NEVADA: + _flush_cache_page = r4k_flush_cache_page_d32i32_r4600; + } + + _flush_cache_sigtramp = r4k_flush_cache_sigtramp; + _flush_icache_range = r4k_flush_icache_range; /* Ouch */ + if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { + _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; + } + + __flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips/mm/c-r5432.c linux-2.4.19-pre5/arch/mips/mm/c-r5432.c --- linux-2.4.18/arch/mips/mm/c-r5432.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-r5432.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,480 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r5432.c: NEC Vr5432 processor. We cannot use r4xx0.c because of + * its unique way-selection method for indexed operations. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000 Jun Sun (jsun@mvista.com) + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +#include +#include + +#undef DEBUG_CACHE + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +static int ic_lsize, dc_lsize; /* LineSize in bytes */ + + +/* -------------------------------------------------------------------- */ +/* #include */ + +static inline void flush_icache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + "cache %1, 1(%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Invalidate_I)); +} + +static inline void flush_dcache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + "cache %1, 1(%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Writeback_Inv_D)); +} + +static inline void flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +static inline void flush_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Writeback_Inv_D)); +} + +static inline void invalidate_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_D)); +} + + +/* + * The next two are for badland addresses like signal trampolines. + */ +static inline void protected_flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +static inline void protected_writeback_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Writeback_D)); +} + + +#define cache32_unroll32(base,op) \ + __asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, 0x000(%0); cache %1, 0x020(%0); \ + cache %1, 0x040(%0); cache %1, 0x060(%0); \ + cache %1, 0x080(%0); cache %1, 0x0a0(%0); \ + cache %1, 0x0c0(%0); cache %1, 0x0e0(%0); \ + cache %1, 0x100(%0); cache %1, 0x120(%0); \ + cache %1, 0x140(%0); cache %1, 0x160(%0); \ + cache %1, 0x180(%0); cache %1, 0x1a0(%0); \ + cache %1, 0x1c0(%0); cache %1, 0x1e0(%0); \ + cache %1, 0x200(%0); cache %1, 0x220(%0); \ + cache %1, 0x240(%0); cache %1, 0x260(%0); \ + cache %1, 0x280(%0); cache %1, 0x2a0(%0); \ + cache %1, 0x2c0(%0); cache %1, 0x2e0(%0); \ + cache %1, 0x300(%0); cache %1, 0x320(%0); \ + cache %1, 0x340(%0); cache %1, 0x360(%0); \ + cache %1, 0x380(%0); cache %1, 0x3a0(%0); \ + cache %1, 0x3c0(%0); cache %1, 0x3e0(%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +static inline void blast_dcache32(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + dcache_size/2); + + while(start < end) { + cache32_unroll32(start,Index_Writeback_Inv_D); + cache32_unroll32(start+1,Index_Writeback_Inv_D); + start += 0x400; + } +} + +static inline void blast_dcache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Hit_Writeback_Inv_D); + start += 0x400; + } +} + +static inline void blast_dcache32_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Index_Writeback_Inv_D); + cache32_unroll32(start+1,Index_Writeback_Inv_D); + start += 0x400; + } +} + +static inline void blast_icache32(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + icache_size/2); + + while(start < end) { + cache32_unroll32(start,Index_Invalidate_I); + cache32_unroll32(start+1,Index_Invalidate_I); + start += 0x400; + } +} + +static inline void blast_icache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Hit_Invalidate_I); + start += 0x400; + } +} + +static inline void blast_icache32_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Index_Invalidate_I); + cache32_unroll32(start+1,Index_Invalidate_I); + start += 0x400; + } +} + +/* -------------------------------------------------------------------- */ + +/* + * If you think for one second that this stuff coming up is a lot + * of bulky code eating too many kernel cache lines. Think _again_. + * + * Consider: + * 1) Taken branches have a 3 cycle penalty on R4k + * 2) The branch itself is a real dead cycle on even R4600/R5000. + * 3) Only one of the following variants of each type is even used by + * the kernel based upon the cache parameters we detect at boot time. + * + * QED. + */ + +static inline void r5432_flush_cache_all_d32i32(void) +{ + blast_dcache32(); blast_icache32(); +} + +static void r5432_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + blast_dcache32(); blast_icache32(); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void r5432_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r5432_flush_cache_all_d32i32(); + } +} + +static void r5432_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + return; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + } +} + + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void r5432_flush_page_to_ram_d32(struct page *page) +{ + blast_dcache32_page((unsigned long)page_address(page)); +} + +static void +r5432_flush_icache_range(unsigned long start, unsigned long end) +{ + r5432_flush_cache_all_d32i32(); +} + +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r5432_flush_icache_page_i32(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + r5432_flush_cache_all_d32i32(); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + */ +static void +r5432_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + } + bc_wback_inv(addr, size); +} + +static void +r5432_dma_cache_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + } + + bc_inv(addr, size); +} + +static void +r5432_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("r5432_dma_cache called - should not happen."); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void r5432_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +/* Detect and size the various r4k caches. */ +static void __init probe_icache(unsigned long config) +{ + icache_size = 1 << (12 + ((config >> 9) & 7)); + ic_lsize = 16 << ((config >> 5) & 1); + + printk("Primary instruction cache %dkb, linesize %d bytes.\n", + icache_size >> 10, ic_lsize); +} + +static void __init probe_dcache(unsigned long config) +{ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + dc_lsize = 16 << ((config >> 4) & 1); + + printk("Primary data cache %dkb, linesize %d bytes.\n", + dcache_size >> 10, dc_lsize); +} + + +void __init ld_mmu_r5432(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); + + probe_icache(config); + probe_dcache(config); + + _clear_page = r5432_clear_page_d32; + _copy_page = r5432_copy_page_d32; + _flush_cache_all = r5432_flush_cache_all_d32i32; + ___flush_cache_all = r5432_flush_cache_all_d32i32; + _flush_page_to_ram = r5432_flush_page_to_ram_d32; + _flush_cache_mm = r5432_flush_cache_mm_d32i32; + _flush_cache_range = r5432_flush_cache_range_d32i32; + _flush_cache_page = r5432_flush_cache_page_d32i32; + _flush_icache_page = r5432_flush_icache_page_i32; + _dma_cache_wback_inv = r5432_dma_cache_wback_inv_pc; + _dma_cache_wback = r5432_dma_cache_wback; + _dma_cache_inv = r5432_dma_cache_inv_pc; + + _flush_cache_sigtramp = r5432_flush_cache_sigtramp; + _flush_icache_range = r5432_flush_icache_range; /* Ouch */ + + __flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips/mm/c-rm7k.c linux-2.4.19-pre5/arch/mips/mm/c-rm7k.c --- linux-2.4.18/arch/mips/mm/c-rm7k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-rm7k.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,350 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org + * + * To do: + * + * - this code is a overbloated pig + * - many of the bug workarounds are not efficient at all, but at + * least they are functional ... + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ + +#define ic_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define dc_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define sc_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define tc_pagesize (32*128) + +/* Secondary cache parameters. */ +#define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ + +#include +#include + +int rm7k_tcache_enabled = 0; + +/* + * Not added to asm/r4kcache.h because it seems to be RM7000-specific. + */ +#define Page_Invalidate_T 0x16 + +static inline void invalidate_tcache_page(unsigned long addr) +{ + __asm__ __volatile__( + ".set\tnoreorder\t\t\t# invalidate_tcache_page\n\t" + ".set\tmips3\n\t" + "cache\t%1, (%0)\n\t" + ".set\tmips0\n\t" + ".set\treorder" + : + : "r" (addr), + "i" (Page_Invalidate_T)); +} + +static void __flush_cache_all_d32i32(void) +{ + blast_dcache32(); + blast_icache32(); +} + +static inline void rm7k_flush_cache_all_d32i32(void) +{ + /* Yes! Caches that don't suck ... */ +} + +static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_page_to_ram_d32i32(struct page * page) +{ + /* Yes! Caches that don't suck! */ +} + +static void rm7k_flush_icache_range(unsigned long start, unsigned long end) +{ + /* + * FIXME: This is overdoing things and harms performance. + */ + __flush_cache_all_d32i32(); +} + +static void rm7k_flush_icache_page(struct vm_area_struct *vma, + struct page *page) +{ + /* + * FIXME: We should not flush the entire cache but establish some + * temporary mapping and use hit_invalidate operation to flush out + * the line from the cache. + */ + __flush_cache_all_d32i32(); +} + + +/* + * Writeback and invalidate the primary cache dcache before DMA. + * (XXX These need to be fixed ...) + */ +static void +rm7k_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + flush_icache_line(a); /* Hit_Invalidate_I */ + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } + + if (!rm7k_tcache_enabled) + return; + + a = addr & ~(tc_pagesize - 1); + end = (addr + size) & ~(tc_pagesize - 1); + while(1) { + invalidate_tcache_page(a); /* Page_Invalidate_T */ + if (a == end) break; + a += tc_pagesize; + } +} + +static void +rm7k_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + invalidate_dcache_line(a); /* Hit_Invalidate_D */ + flush_icache_line(a); /* Hit_Invalidate_I */ + invalidate_scache_line(a); /* Hit_Invalidate_SD */ + if (a == end) break; + a += sc_lsize; + } + + if (!rm7k_tcache_enabled) + return; + + a = addr & ~(tc_pagesize - 1); + end = (addr + size) & ~(tc_pagesize - 1); + while(1) { + invalidate_tcache_page(a); /* Page_Invalidate_T */ + if (a == end) break; + a += tc_pagesize; + } +} + +static void +rm7k_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("rm7k_dma_cache_wback called - should not happen."); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void rm7k_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +/* Detect and size the caches. */ +static inline void probe_icache(unsigned long config) +{ + icache_size = 1 << (12 + ((config >> 9) & 7)); + + printk(KERN_INFO "Primary instruction cache %dKiB.\n", icache_size >> 10); +} + +static inline void probe_dcache(unsigned long config) +{ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + + printk(KERN_INFO "Primary data cache %dKiB.\n", dcache_size >> 10); +} + + +/* + * This function is executed in the uncached segment KSEG1. + * It must not touch the stack, because the stack pointer still points + * into KSEG0. + * + * Three options: + * - Write it in assembly and guarantee that we don't use the stack. + * - Disable caching for KSEG0 before calling it. + * - Pray that GCC doesn't randomly start using the stack. + * + * This being Linux, we obviously take the least sane of those options - + * following DaveM's lead in r4xx0.c + * + * It seems we get our kicks from relying on unguaranteed behaviour in GCC + */ +static __init void setup_scache(void) +{ + int register i; + + set_cp0_config(1<<3 /* CONF_SE */); + + set_taglo(0); + set_taghi(0); + + for (i=0; i> 31) & 1) + return; + + printk(KERN_INFO "Secondary cache %dKiB, linesize %d bytes.\n", + (scache_size >> 10), sc_lsize); + + if ((config >> 3) & 1) + return; + + printk(KERN_INFO "Enabling secondary cache..."); + func(); + printk("Done\n"); +} + +static inline void probe_tcache(unsigned long config) +{ + if ((config >> 17) & 1) + return; + + /* We can't enable the L3 cache yet. There may be board-specific + * magic necessary to turn it on, and blindly asking the CPU to + * start using it would may give cache errors. + * + * Also, board-specific knowledge may allow us to use the + * CACHE Flash_Invalidate_T instruction if the tag RAM supports + * it, and may specify the size of the L3 cache so we don't have + * to probe it. + */ + printk(KERN_INFO "Tertiary cache present, %s enabled\n", + config&(1<<12) ? "already" : "not (yet)"); + + if ((config >> 12) & 1) + rm7k_tcache_enabled = 1; +} + +void __init ld_mmu_rm7k(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + unsigned long addr; + + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + + /* RM7000 erratum #31. The icache is screwed at startup. */ + set_taglo(0); + set_taghi(0); + for (addr = KSEG0; addr <= KSEG0 + 4096; addr += ic_lsize) { + __asm__ __volatile__ ( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache\t%1, 0(%0)\n\t" + "cache\t%1, 0x1000(%0)\n\t" + "cache\t%1, 0x2000(%0)\n\t" + "cache\t%1, 0x3000(%0)\n\t" + "cache\t%2, 0(%0)\n\t" + "cache\t%2, 0x1000(%0)\n\t" + "cache\t%2, 0x2000(%0)\n\t" + "cache\t%2, 0x3000(%0)\n\t" + "cache\t%1, 0(%0)\n\t" + "cache\t%1, 0x1000(%0)\n\t" + "cache\t%1, 0x2000(%0)\n\t" + "cache\t%1, 0x3000(%0)\n\t" + ".set\tmips0\n\t" + ".set\treorder\n\t" + : + : "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill)); + } + +#ifndef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + probe_scache(config); + probe_tcache(config); + + _clear_page = rm7k_clear_page; + _copy_page = rm7k_copy_page; + + _flush_cache_all = rm7k_flush_cache_all_d32i32; + ___flush_cache_all = __flush_cache_all_d32i32; + _flush_cache_mm = rm7k_flush_cache_mm_d32i32; + _flush_cache_range = rm7k_flush_cache_range_d32i32; + _flush_cache_page = rm7k_flush_cache_page_d32i32; + _flush_page_to_ram = rm7k_flush_page_to_ram_d32i32; + _flush_cache_sigtramp = rm7k_flush_cache_sigtramp; + _flush_icache_range = rm7k_flush_icache_range; + _flush_icache_page = rm7k_flush_icache_page; + + _dma_cache_wback_inv = rm7k_dma_cache_wback_inv; + _dma_cache_wback = rm7k_dma_cache_wback; + _dma_cache_inv = rm7k_dma_cache_inv; + + __flush_cache_all_d32i32(); +} diff -urN linux-2.4.18/arch/mips/mm/c-sb1.c linux-2.4.19-pre5/arch/mips/mm/c-sb1.c --- linux-2.4.18/arch/mips/mm/c-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-sb1.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,512 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +/* These are probed at ld_mmu time */ +static unsigned int icache_size; +static unsigned int dcache_size; + +static unsigned int icache_line_size; +static unsigned int dcache_line_size; + +static unsigned int icache_index_mask; + +static unsigned int icache_assoc; +static unsigned int dcache_assoc; + +static unsigned int icache_sets; +static unsigned int dcache_sets; + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +/* + * The dcache is fully coherent to the system, with one + * big caveat: the instruction stream. In other words, + * if we miss in the icache, and have dirty data in the + * L1 dcache, then we'll go out to memory (or the L2) and + * get the not-as-recent data. + * + * So the only time we have to flush the dcache is when + * we're flushing the icache. Since the L2 is fully + * coherent to everything, including I/O, we never have + * to flush it + */ + +static void sb1_flush_cache_all(void) +{ +} + +static void local_sb1___flush_cache_all(void) +{ + /* + * Haven't worried too much about speed here; given that we're flushing + * the icache, the time to invalidate is dwarfed by the time it's going + * to take to refill it. Register usage: + * + * $1 - moving cache index + * $2 - set count + */ + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* WB/Invalidate this index */ + " addiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " addu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (dcache_line_size), "r" (dcache_sets * dcache_assoc), + "r" (KSEG0), "i" (Index_Writeback_Inv_D)); + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set mips2 \n" + "sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + "sync \n" +#endif + ".set pop \n"); + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* Invalidate this index */ + " addiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " addu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (icache_line_size), "r" (icache_sets * icache_assoc), + "r" (KSEG0), "i" (Index_Invalidate_I)); +} + +#ifdef CONFIG_SMP +extern void sb1___flush_cache_all_ipi(void *ignored); +asm("sb1___flush_cache_all_ipi = local_sb1___flush_cache_all"); + +static void sb1___flush_cache_all(void) +{ + smp_call_function(sb1___flush_cache_all_ipi, 0, 1, 1); + local_sb1___flush_cache_all(); +} +#else +extern void sb1___flush_cache_all(void); +asm("sb1___flush_cache_all = local_sb1___flush_cache_all"); +#endif + + +/* + * When flushing a range in the icache, we have to first writeback + * the dcache for the same range, so new ifetches will see any + * data that was dirty in the dcache. + * + * The start/end arguments are expected to be Kseg addresses. + */ + +static void local_sb1_flush_icache_range(unsigned long start, unsigned long end) +{ +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + unsigned long flags; + local_irq_save(flags); +#endif + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %0 \n" + "1: \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + ".align 3 \n" + " lw $0, 0($1) \n" /* Bug 1370, 1368 */ + " sync \n" +#endif + " cache %3, 0($1) \n" /* Hit-WB{,-inval} this address */ + " bne $1, %1, 1b \n" /* loop test */ + " addu $1, $1, %2 \n" /* next line */ + ".set pop \n" + : + : "r" (start & ~(dcache_line_size - 1)), + "r" ((end - 1) & ~(dcache_line_size - 1)), + "r" (dcache_line_size), +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + "i" (Hit_Writeback_Inv_D) +#else + "i" (Hit_Writeback_D) +#endif + ); + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set mips2 \n" + "sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + "sync \n" +#endif + ".set pop \n"); +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + local_irq_restore(flags); +#endif + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %0 \n" + ".align 3 \n" + "1: cache %3, (0<<13)($1) \n" /* Index-inval this address */ + " cache %3, (1<<13)($1) \n" /* Index-inval this address */ + " cache %3, (2<<13)($1) \n" /* Index-inval this address */ + " cache %3, (3<<13)($1) \n" /* Index-inval this address */ + " bne $1, %1, 1b \n" /* loop test */ + " addu $1, $1, %2 \n" /* next line */ + ".set pop \n" + : + : "r" (start & ~(icache_line_size - 1)), + "r" ((end - 1) & ~(dcache_line_size - 1)), + "r" (icache_line_size), + "i" (Index_Invalidate_I)); +} + +#ifdef CONFIG_SMP +struct flush_icache_range_args { + unsigned long start; + unsigned long end; +}; + +static void sb1_flush_icache_range_ipi(void *info) +{ + struct flush_icache_range_args *args = info; + + local_sb1_flush_icache_range(args->start, args->end); +} + +void sb1_flush_icache_range(unsigned long start, unsigned long end) +{ + struct flush_icache_range_args args; + + args.start = start; + args.end = end; + smp_call_function(sb1_flush_icache_range_ipi, &args, 1, 1); + local_sb1_flush_icache_range(start, end); +} +#else +void sb1_flush_icache_range(unsigned long start, unsigned long end); +asm("sb1_flush_icache_range = local_sb1_flush_icache_range"); +#endif + +/* + * If there's no context yet, or the page isn't executable, no icache flush + * is needed + */ +static void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if ((vma->vm_mm->context == 0) || !(vma->vm_flags & VM_EXEC)) { + return; + } + + /* + * We're not sure of the virtual address(es) involved here, so + * conservatively flush the entire caches on all processors + * (ouch). + */ + sb1___flush_cache_all(); +} + +static inline void protected_flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips4 \n" + "1: cache %1, (%0) \n" + "2: .set pop \n" + " .section __ex_table,\"a\"\n" + " .word 1b, 2b \n" + " .previous" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +static inline void protected_writeback_dcache_line(unsigned long addr) +{ +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + /* Have to be sure the TLB entry exists for the cache op, + so we have to be sure that nothing happens in between the + lw and the cache op + */ + unsigned long flags; + local_irq_save(flags); +#endif + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips4 \n" + "1: \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + " lw $0, (%0) \n" + " sync \n" +#endif + " cache %1, 0(%0) \n" /* Hit-WB{-inval} this address */ + /* XXX: should be able to do this after both dcache cache + ops, but there's no guarantee that this will be inlined, + and the pass1 restriction checker can't detect syncs + following cache ops except in the following basic block. + */ + " sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + " sync \n" +#endif + "2: .set pop \n" + " .section __ex_table,\"a\"\n" + " .word 1b, 2b \n" + " .previous" + : + : "r" (addr), +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + "i" (Hit_Writeback_Inv_D) +#else + "i" (Hit_Writeback_D) +#endif + ); +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + local_irq_restore(flags); +#endif +} + +/* + * XXX - Still need to really understand this. This is mostly just + * derived from the r10k and r4k implementations, and seems to work + * but things that "seem to work" when I don't understand *why* they + * "seem to work" disturb me greatly...JDC + */ +static void local_sb1_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dcache_line_size - 1); + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dcache_line_size); + iaddr = addr & ~(icache_line_size - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + icache_line_size); +} + +#ifdef CONFIG_SMP +extern void sb1_flush_cache_sigtramp_ipi(void *ignored); +asm("sb1_flush_cache_sigtramp_ipi = local_sb1_flush_cache_sigtramp"); + +static void sb1_flush_cache_sigtramp(unsigned long addr) +{ + smp_call_function(sb1_flush_cache_sigtramp_ipi, (void *) addr, 1, 1); + local_sb1_flush_cache_sigtramp(addr); +} +#else +void sb1_flush_cache_sigtramp(unsigned long addr); +asm("sb1_flush_cache_sigtramp = local_sb1_flush_cache_sigtramp"); +#endif + +static void sb1_flush_icache_all(void) +{ + /* + * Haven't worried too much about speed here; given that we're flushing + * the icache, the time to invalidate is dwarfed by the time it's going + * to take to refill it. Register usage: + * + * $1 - moving cache index + * $2 - set count + */ + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* Invalidate this index */ + " addiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " addu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (icache_line_size), "r" (icache_sets * icache_assoc), + "r" (KSEG0), "i" (Index_Invalidate_I)); +} + +/* + * Anything that just flushes dcache state can be ignored, as we're always + * coherent in dcache space. This is just a dummy function that all the + * nop'ed routines point to + */ + +static void sb1_nop(void) +{ +} + +/* + * This only needs to make sure stores done up to this + * point are visible to other agents outside the CPU. Given + * the coherent nature of the ZBbus, all that's required here is + * a sync to make sure the data gets out to the caches and is + * visible to an arbitrary A Phase from an external agent + * + * Actually, I'm not even sure that's necessary; the semantics + * of this function aren't clear. If it's supposed to serve as + * a memory barrier, this is needed. If it's only meant to + * prevent data from being invisible to non-cpu memory accessors + * for some indefinite period of time (e.g. in a non-coherent + * dcache) then this function would be a complete nop. + */ +static void sb1_flush_page_to_ram(struct page *page) +{ + __asm__ __volatile__( + " sync \n" /* Short pipe */ + :::"memory"); +} + +/* + * Cache set values (from the mips64 spec) + * 0 - 64 + * 1 - 128 + * 2 - 256 + * 3 - 512 + * 4 - 1024 + * 5 - 2048 + * 6 - 4096 + * 7 - Reserved + */ + +static unsigned int decode_cache_sets(unsigned int config_field) +{ + if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + return (1<<(config_field + 6)); +} + +/* + * Cache line size values (from the mips64 spec) + * 0 - No cache present. + * 1 - 4 bytes + * 2 - 8 bytes + * 3 - 16 bytes + * 4 - 32 bytes + * 5 - 64 bytes + * 6 - 128 bytes + * 7 - Reserved + */ + +static unsigned int decode_cache_line_size(unsigned int config_field) +{ + if (config_field == 0) { + return 0; + } else if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + return (1<<(config_field + 1)); +} + +/* + * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs) + * + * 24:22 Icache sets per way + * 21:19 Icache line size + * 18:16 Icache Associativity + * 15:13 Dcache sets per way + * 12:10 Dcache line size + * 9:7 Dcache Associativity + */ + +static __init void probe_cache_sizes(void) +{ + u32 config1; + + config1 = read_mips32_cp0_config1(); + icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7); + dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7); + icache_sets = decode_cache_sets((config1 >> 22) & 0x7); + dcache_sets = decode_cache_sets((config1 >> 13) & 0x7); + icache_assoc = ((config1 >> 16) & 0x7) + 1; + dcache_assoc = ((config1 >> 7) & 0x7) + 1; + icache_size = icache_line_size * icache_sets * icache_assoc; + dcache_size = dcache_line_size * dcache_sets * dcache_assoc; + icache_index_mask = (icache_sets - 1) * icache_line_size; +} + +/* + * This is called from loadmmu.c. We have to set up all the + * memory management function pointers, as well as initialize + * the caches and tlbs + */ +void ld_mmu_sb1(void) +{ + probe_cache_sizes(); + + _clear_page = sb1_clear_page; + _copy_page = sb1_copy_page; + + _flush_cache_all = sb1_flush_cache_all; + ___flush_cache_all = sb1___flush_cache_all; + _flush_cache_mm = (void (*)(struct mm_struct *))sb1_nop; + _flush_cache_range = (void *) sb1_nop; + _flush_page_to_ram = sb1_flush_page_to_ram; + _flush_icache_page = sb1_flush_icache_page; + _flush_icache_range = sb1_flush_icache_range; + + /* None of these are needed for the sb1 */ + _flush_cache_page = (void *) sb1_nop; + + _flush_cache_sigtramp = sb1_flush_cache_sigtramp; + _flush_icache_all = sb1_flush_icache_all; + + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW); + flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips/mm/c-tx39.c linux-2.4.19-pre5/arch/mips/mm/c-tx39.c --- linux-2.4.18/arch/mips/mm/c-tx39.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-tx39.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,339 @@ +/* + * r2300.c: R2000 and R3000 specific mmu/cache code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * with a lot of changes to make this thing work for R3000s + * Tx39XX R4k style caches added. HK + * Copyright (C) 1998, 1999, 2000 Harald Koerfgen + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* For R3000 cores with R4000 style caches */ +static unsigned long icache_size, dcache_size; /* Size in bytes */ +extern long scache_size; + +#define icache_lsize mips_cpu.icache.linesz +#define dcache_lsize mips_cpu.dcache.linesz + +#include + +extern int r3k_have_wired_reg; /* in r3k-tlb.c */ + +static void tx39h_flush_page_to_ram(struct page * page) +{ +} + +/* TX39H-style cache flush routines. */ +static void tx39h_flush_icache_all(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + icache_size); + unsigned long flags, config; + + /* disable icache (set ICE#) */ + __save_and_cli(flags); + config = read_32bit_cp0_register(CP0_CONF); + + /* invalidate icache */ + while (start < end) { + cache16_unroll32(start, Index_Invalidate_I); + start += 0x200; + } + + write_32bit_cp0_register(CP0_CONF, config); + __restore_flags(flags); +} + +static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + wbflush(); + + a = addr & ~(dcache_lsize - 1); + end = (addr + size) & ~(dcache_lsize - 1); + while (1) { + invalidate_dcache_line(a); /* Hit_Invalidate_D */ + if (a == end) break; + a += dcache_lsize; + } +} + + +/* TX39H2,TX39H3 */ +static inline void tx39_flush_cache_all(void) +{ + unsigned long flags, config; + + __save_and_cli(flags); + blast_dcache16_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE); + blast_icache16_wayLSB(); + write_32bit_cp0_register(CP0_CONF, config); + __restore_flags(flags); +} + +static void tx39_flush_cache_mm(struct mm_struct *mm) +{ + if(mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + tx39_flush_cache_all(); + } +} + +static void tx39_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags, config; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache16_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE); + blast_icache16_wayLSB(); + write_32bit_cp0_register(CP0_CONF, config); + __restore_flags(flags); + } +} + +static void tx39_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if(mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if(!(pte_val(*ptep) & _PAGE_PRESENT)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache16_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache16_page_indexed_wayLSB(page); + } +out: + __restore_flags(flags); +} + +static void tx39_flush_page_to_ram(struct page * page) +{ + blast_dcache16_page((unsigned long)page_address(page)); +} + +static void tx39_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + flush_cache_all(); +} + +static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dcache_lsize - 1); + end = (addr + size) & ~(dcache_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dcache_lsize; + } + } +} + +static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dcache_lsize - 1); + end = (addr + size) & ~(dcache_lsize - 1); + while (1) { + invalidate_dcache_line(a); /* Hit_Invalidate_D */ + if (a == end) break; + a += dcache_lsize; + } + } +} + +static void tx39_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("tx39_dma_cache called - should not happen."); +} + +static void tx39_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long config; + unsigned int flags; + + __save_and_cli(flags); + protected_writeback_dcache_line(addr & ~(dcache_lsize - 1)); + + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE); + protected_flush_icache_line(addr & ~(icache_lsize - 1)); + write_32bit_cp0_register(CP0_CONF, config); + __restore_flags(flags); +} + +static __init void tx39_probe_cache(void) +{ + unsigned long config; + + config = read_32bit_cp0_register(CP0_CONF); + + icache_size = 1 << (10 + ((config >> 19) & 3)); + dcache_size = 1 << (10 + ((config >> 16) & 3)); + + icache_lsize = 16; + switch (mips_cpu.cputype) { + case CPU_TX3912: + dcache_lsize = 4; + break; + case CPU_TX3922: + case CPU_TX3927: + case CPU_TX39XX: + default: + dcache_lsize = 16; + break; + } +} + +void __init ld_mmu_tx39(void) +{ + unsigned long config; + + _clear_page = r3k_clear_page; + _copy_page = r3k_copy_page; + + config = read_32bit_cp0_register(CP0_CONF); + config &= ~TX39_CONF_WBON; + write_32bit_cp0_register(CP0_CONF, config); + + tx39_probe_cache(); + + switch (mips_cpu.cputype) { + case CPU_TX3912: + /* TX39/H core (writethru direct-map cache) */ + _flush_cache_all = tx39h_flush_icache_all; + ___flush_cache_all = tx39h_flush_icache_all; + _flush_cache_mm = (void *) tx39h_flush_icache_all; + _flush_cache_range = (void *) tx39h_flush_icache_all; + _flush_cache_page = (void *) tx39h_flush_icache_all; + _flush_cache_sigtramp = (void *) tx39h_flush_icache_all; + _flush_page_to_ram = tx39h_flush_page_to_ram; + _flush_icache_page = (void *) tx39h_flush_icache_all; + _flush_icache_range = (void *) tx39h_flush_icache_all; + + _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; + break; + + case CPU_TX3922: + case CPU_TX3927: + default: + /* TX39/H2,H3 core (writeback 2way-set-associative cache) */ + r3k_have_wired_reg = 1; + set_wired (0); /* set 8 on reset... */ + /* board-dependent init code may set WBON */ + + _flush_cache_all = tx39_flush_cache_all; + ___flush_cache_all = tx39_flush_cache_all; + _flush_cache_mm = tx39_flush_cache_mm; + _flush_cache_range = tx39_flush_cache_range; + _flush_cache_page = tx39_flush_cache_page; + _flush_cache_sigtramp = tx39_flush_cache_sigtramp; + _flush_page_to_ram = tx39_flush_page_to_ram; + _flush_icache_page = tx39_flush_icache_page; + _flush_icache_range = tx39_flush_icache_range; + + _dma_cache_wback_inv = tx39_dma_cache_wback_inv; + _dma_cache_wback = tx39_dma_cache_wback; + _dma_cache_inv = tx39_dma_cache_inv; + + break; + } + + if (mips_cpu.icache.ways == 0) + mips_cpu.icache.ways = 1; + if (mips_cpu.dcache.ways == 0) + mips_cpu.dcache.ways = 1; + mips_cpu.icache.sets = + icache_size / mips_cpu.icache.ways / mips_cpu.icache.linesz; + mips_cpu.dcache.sets = + dcache_size / mips_cpu.dcache.ways / mips_cpu.dcache.linesz; + + printk("Primary instruction cache %dkb, linesize %d bytes\n", + (int) (icache_size >> 10), (int) icache_lsize); + printk("Primary data cache %dkb, linesize %d bytes\n", + (int) (dcache_size >> 10), (int) dcache_lsize); +} diff -urN linux-2.4.18/arch/mips/mm/c-tx49.c linux-2.4.19-pre5/arch/mips/mm/c-tx49.c --- linux-2.4.18/arch/mips/mm/c-tx49.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/c-tx49.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,438 @@ +/* + * 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. + * + * r49xx.c: TX49 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org + * + * Modified for R4300/TX49xx (Jun/2001) + * Copyright (C) 1999-2001 Toshiba Corporation + * + * To do: + * + * - this code is a overbloated pig + * - many of the bug workarounds are not efficient at all, but at + * least they are functional ... + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +#define ic_lsize mips_cpu.icache.linesz +#define dc_lsize mips_cpu.dcache.linesz +static unsigned long scache_size; + +#include +#include + +#undef DEBUG_CACHE + +/* TX49 does can not flush the line contains the CACHE insn itself... */ +/* r4k_xxx routines are completely same as those in r4xx0.c */ + +/* + * If you think for one second that this stuff coming up is a lot + * of bulky code eating too many kernel cache lines. Think _again_. + * + * Consider: + * 1) Taken branches have a 3 cycle penalty on R4k + * 2) The branch itself is a real dead cycle on even R4600/R5000. + * 3) Only one of the following variants of each type is even used by + * the kernel based upon the cache parameters we detect at boot time. + * + * QED. + */ + +static inline void r49_flush_cache_all_d16i32(void) +{ + unsigned long flags, config; + + __save_and_cli(flags); + blast_dcache16_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONFIG); + write_32bit_cp0_register(CP0_CONFIG, config|TX49_CONF_IC); + blast_icache32_wayLSB(); + write_32bit_cp0_register(CP0_CONFIG, config); + __restore_flags(flags); +} + +static inline void r49_flush_cache_all_d32i32(void) +{ + unsigned long flags, config; + + __save_and_cli(flags); + blast_dcache32_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONFIG); + write_32bit_cp0_register(CP0_CONFIG, config|TX49_CONF_IC); + blast_icache32_wayLSB(); + write_32bit_cp0_register(CP0_CONFIG, config); + __restore_flags(flags); +} + +static void r49_flush_cache_range_d16i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags, config; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache16_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONFIG); + write_32bit_cp0_register(CP0_CONFIG, config|TX49_CONF_IC); + blast_icache32_wayLSB(); + write_32bit_cp0_register(CP0_CONFIG, config); + __restore_flags(flags); + } +} + +static void r49_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags, config; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache32_wayLSB(); + /* disable icache (set ICE#) */ + config = read_32bit_cp0_register(CP0_CONFIG); + write_32bit_cp0_register(CP0_CONFIG, config|TX49_CONF_IC); + blast_icache32_wayLSB(); + write_32bit_cp0_register(CP0_CONFIG, config); + __restore_flags(flags); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void r49_flush_cache_mm_d16i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r49_flush_cache_all_d16i32(); + } +} + +static void r49_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r49_flush_cache_all_d32i32(); + } +} + +static void r49_flush_cache_page_d16i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache16_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache16_page_indexed_wayLSB(page); + } +out: + __restore_flags(flags); +} + +static void r49_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed_wayLSB(page); + } +out: + __restore_flags(flags); +} + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void r4k_flush_page_to_ram_d16(struct page *page) +{ + blast_dcache16_page((unsigned long)page_address(page)); +} + +static void r4k_flush_page_to_ram_d32(struct page *page) +{ + blast_dcache32_page((unsigned long)page_address(page)); +} + +static void +r4k_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r4k_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + flush_cache_all(); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + */ +static void +r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } +} + +static void +r4k_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } +} + +static void +r4k_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("r4k_dma_cache called - should not happen."); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void r4k_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +/* Detect and size the various r4k caches. */ +static void __init probe_icache(unsigned long config) +{ + icache_size = 1 << (12 + ((config >> 9) & 7)); + ic_lsize = 16 << ((config >> 5) & 1); + + printk("Primary instruction cache %dkb, linesize %d bytes.\n", + icache_size >> 10, ic_lsize); +} + +static void __init probe_dcache(unsigned long config) +{ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + dc_lsize = 16 << ((config >> 4) & 1); + + printk("Primary data cache %dkb, linesize %d bytes.\n", + dcache_size >> 10, dc_lsize); +} + +int mips_configk0 = -1; /* board-specific setup routine can override this */ +void __init ld_mmu_tx49(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + if (mips_configk0 != -1) + change_cp0_config(CONF_CM_CMASK, mips_configk0); + else +#ifdef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + if (mips_cpu.icache.ways == 0) + mips_cpu.icache.ways = 1; + if (mips_cpu.dcache.ways == 0) + mips_cpu.dcache.ways = 1; + mips_cpu.icache.sets = + icache_size / mips_cpu.icache.ways / mips_cpu.icache.linesz; + mips_cpu.dcache.sets = + dcache_size / mips_cpu.dcache.ways / mips_cpu.dcache.linesz; + + switch(dc_lsize) { + case 16: + _clear_page = r4k_clear_page_d16; + _copy_page = r4k_copy_page_d16; + _flush_page_to_ram = r4k_flush_page_to_ram_d16; + _flush_cache_all = r49_flush_cache_all_d16i32; + _flush_cache_mm = r49_flush_cache_mm_d16i32; + _flush_cache_range = r49_flush_cache_range_d16i32; + _flush_cache_page = r49_flush_cache_page_d16i32; + break; + case 32: + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; + _flush_cache_all = r49_flush_cache_all_d32i32; + _flush_cache_mm = r49_flush_cache_mm_d32i32; + _flush_cache_range = r49_flush_cache_range_d32i32; + _flush_cache_page = r49_flush_cache_page_d32i32; + break; + } + ___flush_cache_all = _flush_cache_all; + + _flush_icache_page = r4k_flush_icache_page; + + _dma_cache_wback_inv = r4k_dma_cache_wback_inv; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv; + + _flush_cache_sigtramp = r4k_flush_cache_sigtramp; + _flush_icache_range = r4k_flush_icache_range; /* Ouch */ + + __flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips/mm/fault.c linux-2.4.19-pre5/arch/mips/mm/fault.c --- linux-2.4.18/arch/mips/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/fault.c Sat Mar 30 22:55:26 2002 @@ -28,13 +28,44 @@ #define development_version (LINUX_VERSION_CODE & 0x100) -unsigned long asid_cache = ASID_FIRST_VERSION; - /* * Macro for exception fixup code to access integer registers. */ #define dpf_reg(r) (regs->regs[r]) +extern spinlock_t timerlist_lock; + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out (timerlist_lock is acquired through the + * console unblank code) + */ +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + /* Many serial drivers do __global_cli() */ + global_irq_lock = SPIN_LOCK_UNLOCKED; +#endif + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -58,7 +89,7 @@ * only copy the information from the master page table, * nothing more. */ - if (address >= TASK_SIZE) + if (address >= VMALLOC_START) goto vmalloc_fault; info.si_code = SEGV_MAPERR; @@ -97,6 +128,7 @@ goto bad_area; } +survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -170,7 +202,7 @@ "address %08lx, epc == %08lx, ra == %08lx\n", address, regs->cp0_epc, regs->regs[31]); die("Oops", regs); - do_exit(SIGKILL); + /* Game over. */ /* * We ran out of memory, or some other thing happened to us that made @@ -178,6 +210,12 @@ */ out_of_memory: up_read(&mm->mmap_sem); + if (tsk->pid == 1) { + tsk->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", tsk->comm); if (user_mode(regs)) do_exit(SIGKILL); @@ -191,7 +229,7 @@ * or user mode. */ tsk->thread.cp0_badvaddr = address; - info.si_code = SIGBUS; + info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; info.si_addr = (void *) address; diff -urN linux-2.4.18/arch/mips/mm/init.c linux-2.4.19-pre5/arch/mips/mm/init.c --- linux-2.4.18/arch/mips/mm/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/init.c Sat Mar 30 22:55:26 2002 @@ -25,9 +25,7 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD #include -#endif #include #include @@ -37,15 +35,13 @@ #include #include #include -#ifdef CONFIG_SGI_IP22 -#include -#endif #include #include mmu_gather_t mmu_gathers[NR_CPUS]; - +unsigned long highstart_pfn, highend_pfn; static unsigned long totalram_pages; +static unsigned long totalhigh_pages; extern void prom_free_prom_memory(void); @@ -98,19 +94,39 @@ { int freed = 0; - if(pgtable_cache_size > high) { + if (pgtable_cache_size > high) { do { - if(pgd_quicklist) + if (pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) + if (pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) + if (pte_quicklist) free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); + } while (pgtable_cache_size > low); } return freed; } +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +static void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + + kmap_prot = PAGE_KERNEL; +} + +#endif /* CONFIG_HIGHMEM */ + void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -145,19 +161,79 @@ extern char _ftext, _etext, _fdata, _edata; extern char __init_begin, __init_end; -void __init paging_init(void) +static void __init fixrange_init (unsigned long start, unsigned long end, + pgd_t *pgd_base) { - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; - unsigned long max_dma, low; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int i, j; + unsigned long vaddr; + + vaddr = start; + i = __pgd_offset(vaddr); + j = __pmd_offset(vaddr); + pgd = pgd_base + i; + + for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { + pmd = (pmd_t *)pgd; + for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(pte)); + if (pte != pte_offset(pmd, 0)) + BUG(); + } + vaddr += PMD_SIZE; + } + j = 0; + } +} + +void __init pagetable_init(void) +{ + unsigned long vaddr; + pgd_t *pgd, *pgd_base; + pmd_t *pmd; + pte_t *pte; /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); - pgd_init((unsigned long)swapper_pg_dir + PAGE_SIZE / 2); + pgd_init((unsigned long)swapper_pg_dir + + sizeof(pgd_t ) * USER_PTRS_PER_PGD); + + pgd_base = swapper_pg_dir; + +#ifdef CONFIG_HIGHMEM + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + pkmap_page_table = pte; +#endif +} + +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma, high, low; + + pagetable_init(); + +#ifdef CONFIG_HIGHMEM + kmap_init(); +#endif max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; low = max_low_pfn; + high = highend_pfn; -#if defined(CONFIG_PCI) || defined(CONFIG_ISA) +#ifdef CONFIG_ISA if (low < max_dma) zones_size[ZONE_DMA] = low; else { @@ -167,6 +243,9 @@ #else zones_size[ZONE_DMA] = low; #endif +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = high - low; +#endif free_area_init(zones_size); } @@ -201,8 +280,17 @@ unsigned long codesize, reservedpages, datasize, initsize; unsigned long tmp, ram; +#ifdef CONFIG_HIGHMEM + highstart_pfn = (KSEG1 - KSEG0) >> PAGE_SHIFT; + highmem_start_page = mem_map + highstart_pfn; +#ifdef CONFIG_DISCONTIGMEM +#error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet" +#endif + max_mapnr = num_physpages = highend_pfn; +#else max_mapnr = num_physpages = max_low_pfn; - high_memory = (void *) __va(max_mapnr << PAGE_SHIFT); +#endif + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); totalram_pages += free_all_bootmem(); totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */ @@ -215,18 +303,36 @@ reservedpages++; } +#ifdef CONFIG_HIGHMEM + for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { + struct page *page = mem_map + tmp; + + if (!page_is_ram(tmp)) { + SetPageReserved(page); + continue; + } + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; +#endif + codesize = (unsigned long) &_etext - (unsigned long) &_ftext; datasize = (unsigned long) &_edata - (unsigned long) &_fdata; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, " - "%ldk data, %ldk init)\n", + "%ldk data, %ldk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), ram << (PAGE_SHIFT-10), codesize >> 10, reservedpages << (PAGE_SHIFT-10), datasize >> 10, - initsize >> 10); + initsize >> 10, + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); } #ifdef CONFIG_BLK_DEV_INITRD @@ -269,10 +375,10 @@ void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; - val->sharedram = atomic_read(&shmem_nrpages); + val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); - val->totalhigh = 0; + val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; diff -urN linux-2.4.18/arch/mips/mm/ioremap.c linux-2.4.19-pre5/arch/mips/mm/ioremap.c --- linux-2.4.18/arch/mips/mm/ioremap.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/ioremap.c Sat Mar 30 22:55:26 2002 @@ -14,10 +14,10 @@ #include #include -static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, - unsigned long phys_addr, unsigned long flags) +static inline void remap_area_pte(pte_t * pte, unsigned long address, + phys_t size, phys_t phys_addr, unsigned long flags) { - unsigned long end; + phys_t end; pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE | __WRITEABLE | flags); @@ -39,10 +39,10 @@ } while (address && (address < end)); } -static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, - unsigned long phys_addr, unsigned long flags) +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, + phys_t size, phys_t phys_addr, unsigned long flags) { - unsigned long end; + phys_t end; address &= ~PGDIR_MASK; end = address + size; @@ -62,8 +62,8 @@ return 0; } -static int remap_area_pages(unsigned long address, unsigned long phys_addr, - unsigned long size, unsigned long flags) +static int remap_area_pages(unsigned long address, phys_t phys_addr, + phys_t size, unsigned long flags) { int error; pgd_t * dir; @@ -107,13 +107,14 @@ * caller shouldn't need to know that small detail. */ -#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) +#define IS_LOW512(addr) (!((phys_t)(addr) & ~0x1fffffffUL)) -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags) { - void * addr; struct vm_struct * area; - unsigned long offset, last_addr; + unsigned long offset; + phys_t last_addr; + void * addr; /* Don't allow wraparound or zero size */ last_addr = phys_addr + size - 1; @@ -124,7 +125,7 @@ * Map objects in the low 512mb of address space using KSEG1, otherwise * map using page tables. */ - if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1)) + if (IS_LOW512(phys_addr) && IS_LOW512(last_addr)) return (void *) KSEG1ADDR(phys_addr); /* diff -urN linux-2.4.18/arch/mips/mm/loadmmu.c linux-2.4.19-pre5/arch/mips/mm/loadmmu.c --- linux-2.4.18/arch/mips/mm/loadmmu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/loadmmu.c Sat Mar 30 22:55:26 2002 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -29,17 +30,30 @@ unsigned long end); void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); void (*_flush_cache_sigtramp)(unsigned long addr); -void (*_flush_page_to_ram)(struct page * page); void (*_flush_icache_range)(unsigned long start, unsigned long end); void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page); +void (*_flush_page_to_ram)(struct page * page); +void (*_flush_icache_all)(void); + +#ifdef CONFIG_NONCOHERENT_IO + /* DMA cache operations. */ void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); void (*_dma_cache_wback)(unsigned long start, unsigned long size); void (*_dma_cache_inv)(unsigned long start, unsigned long size); +EXPORT_SYMBOL(_dma_cache_wback_inv); +EXPORT_SYMBOL(_dma_cache_wback); +EXPORT_SYMBOL(_dma_cache_inv); + +#endif /* CONFIG_NONCOHERENT_IO */ + + extern void ld_mmu_r23000(void); extern void ld_mmu_r4xx0(void); +extern void ld_mmu_tx39(void); +extern void ld_mmu_tx49(void); extern void ld_mmu_r5432(void); extern void ld_mmu_r6000(void); extern void ld_mmu_rm7k(void); @@ -47,53 +61,72 @@ extern void ld_mmu_andes(void); extern void ld_mmu_sb1(void); extern void ld_mmu_mips32(void); +extern void r3k_tlb_init(void); +extern void r4k_tlb_init(void); +extern void sb1_tlb_init(void); void __init loadmmu(void) { - if (mips_cpu.options & MIPS_CPU_4KTLB) { #if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_VR41XX) || \ defined(CONFIG_CPU_R4300) || defined(CONFIG_CPU_R5000) || \ defined(CONFIG_CPU_NEVADA) - printk("Loading R4000 MMU routines.\n"); ld_mmu_r4xx0(); + r4k_tlb_init(); #endif #if defined(CONFIG_CPU_RM7000) - printk("Loading RM7000 MMU routines.\n"); - ld_mmu_rm7k(); + ld_mmu_rm7k(); + r4k_tlb_init(); #endif -#if defined(CONFIG_CPU_R5432) - printk("Loading R5432 MMU routines.\n"); +#if defined(CONFIG_CPU_R5432) || defined(CONFIG_CPU_R5500) ld_mmu_r5432(); + r4k_tlb_init(); +#endif +#if defined(CONFIG_CPU_TX49XX) + ld_mmu_tx49(); + r4k_tlb_init(); #endif #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) - printk("Loading MIPS32 MMU routines.\n"); ld_mmu_mips32(); + r4k_tlb_init(); #endif } else switch(mips_cpu.cputype) { #ifdef CONFIG_CPU_R3000 case CPU_R2000: case CPU_R3000: case CPU_R3000A: + case CPU_R3081E: + ld_mmu_r23000(); + r3k_tlb_init(); + break; case CPU_TX3912: case CPU_TX3922: case CPU_TX3927: - case CPU_R3081E: - printk("Loading R[23]000 MMU routines.\n"); - ld_mmu_r23000(); + case CPU_TX39XX: + ld_mmu_tx39(); + r3k_tlb_init(); + break; +#endif +#ifdef CONFIG_CPU_TX39XX + case CPU_TX3912: + case CPU_TX3922: + case CPU_TX3927: + case CPU_TX39XX: + ld_mmu_tx39(); + r3k_tlb_init(); break; #endif #ifdef CONFIG_CPU_R10000 case CPU_R10000: - printk("Loading R10000 MMU routines.\n"); ld_mmu_andes(); + r4k_tlb_init(); break; #endif #ifdef CONFIG_CPU_SB1 case CPU_SB1: - printk("Loading SB1 MMU routines.\n"); ld_mmu_sb1(); + sb1_tlb_init(); break; #endif default: diff -urN linux-2.4.18/arch/mips/mm/mips32.c linux-2.4.19-pre5/arch/mips/mm/mips32.c --- linux-2.4.18/arch/mips/mm/mips32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/mips32.c Thu Jan 1 01:00:00 1970 @@ -1,1064 +0,0 @@ -/* - * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * MIPS32 CPU variant specific MMU/Cache routines. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* CP0 hazard avoidance. */ -#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ - "nop; nop; nop; nop; nop; nop;\n\t" \ - ".set reorder\n\t") - -/* Primary cache parameters. */ -static int icache_size, dcache_size; /* Size in bytes */ -static int ic_lsize, dc_lsize; /* LineSize in bytes */ - -/* Secondary cache (if present) parameters. */ -static unsigned int scache_size, sc_lsize; /* Again, in bytes */ - -#include -#include - -#undef DEBUG_CACHE - -/* - * Dummy cache handling routines for machines without boardcaches - */ -static void no_sc_noop(void) {} - -static struct bcache_ops no_sc_ops = { - (void *)no_sc_noop, (void *)no_sc_noop, - (void *)no_sc_noop, (void *)no_sc_noop -}; - -struct bcache_ops *bcops = &no_sc_ops; - - -/* - * Zero an entire page. - */ - -static void mips32_clear_page_dc(unsigned long page) -{ - unsigned long i; - - if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) { - for (i=page; icontext == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if(vma) { - if(mm->context != current->mm->context) { - mips32_flush_cache_all_sc(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void mips32_flush_cache_range_pc(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if(mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - __save_and_cli(flags); - blast_dcache(); blast_icache(); - __restore_flags(flags); - } -} - -/* - * On architectures like the Sparc, we could get rid of lines in - * the cache created only by a certain context, but on the MIPS - * (and actually certain Sparc's) we cannot. - */ -static void mips32_flush_cache_mm_sc(struct mm_struct *mm) -{ - if(mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - mips32_flush_cache_all_sc(); - } -} - -static void mips32_flush_cache_mm_pc(struct mm_struct *mm) -{ - if(mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - mips32_flush_cache_all_pc(); - } -} - - - - - -static void mips32_flush_cache_page_sc(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache_page_indexed(page); - blast_scache_page_indexed(page); - } else - blast_scache_page(page); -out: - __restore_flags(flags); -} - -static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since Mips32 caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm == current->active_mm) { - blast_dcache_page(page); - } else { - /* Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (dcache_size - 1))); - blast_dcache_page_indexed(page); - } -out: - __restore_flags(flags); -} - -/* If the addresses passed to these routines are valid, they are - * either: - * - * 1) In KSEG0, so we can do a direct flush of the page. - * 2) In KSEG2, and since every process can translate those - * addresses all the time in kernel mode we can do a direct - * flush. - * 3) In KSEG1, no flush necessary. - */ -static void mips32_flush_page_to_ram_sc(struct page *page) -{ - blast_scache_page((unsigned long)page_address(page)); -} - -static void mips32_flush_page_to_ram_pc(struct page *page) -{ - blast_dcache_page((unsigned long)page_address(page)); -} - -static void -mips32_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) -{ - /* - * We did an scache flush therefore PI is already clean. - */ -} - -static void -mips32_flush_icache_range(unsigned long start, unsigned long end) -{ - flush_cache_all(); -} - -static void -mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - int address; - - if (!(vma->vm_flags & VM_EXEC)) - return; - - address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & (dcache_size - 1)); - blast_icache_page_indexed(address); -} - -/* - * Writeback and invalidate the primary cache dcache before DMA. - */ -static void -mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - unsigned int flags; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - __save_and_cli(flags); - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - __restore_flags(flags); - } - bc_wback_inv(addr, size); -} - -static void -mips32_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= scache_size) { - flush_cache_all(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) break; - a += sc_lsize; - } -} - -static void -mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - unsigned int flags; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - __save_and_cli(flags); - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - __restore_flags(flags); - } - - bc_inv(addr, size); -} - -static void -mips32_dma_cache_inv_sc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= scache_size) { - flush_cache_all(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) break; - a += sc_lsize; - } -} - -static void -mips32_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("mips32_dma_cache called - should not happen.\n"); -} - -/* - * While we're protected against bad userland addresses we don't care - * very much about what happens in that case. Usually a segmentation - * fault will dump the process later on anyway ... - */ -static void mips32_flush_cache_sigtramp(unsigned long addr) -{ - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); -} - -#undef DEBUG_TLB -#undef DEBUG_TLBUPDATE - -void flush_tlb_all(void) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - -#ifdef DEBUG_TLB - printk("[tlball]"); -#endif - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - set_entryhi(KSEG0); - set_entrylo0(0); - set_entrylo1(0); - BARRIER; - - entry = get_wired(); - - /* Blast 'em all away. */ - while(entry < mips_cpu.tlbsize) { - /* Make sure all entries differ. */ - set_entryhi(KSEG0+entry*0x2000); - set_index(entry); - BARRIER; - tlb_write_indexed(); - BARRIER; - entry++; - } - BARRIER; - set_entryhi(old_ctx); - __restore_flags(flags); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_TLB - printk("[tlbmm<%d>]", mm->context); -#endif - __save_and_cli(flags); - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - __restore_flags(flags); - } -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm->context != 0) { - unsigned long flags; - int size; - -#ifdef DEBUG_TLB - printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), - start, end); -#endif - __save_and_cli(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - size = (size + 1) >> 1; - if(size <= mips_cpu.tlbsize/2) { - int oldpid = (get_entryhi() & 0xff); - int newpid = (mm->context & 0xff); - - start &= (PAGE_MASK << 1); - end += ((PAGE_SIZE << 1) - 1); - end &= (PAGE_MASK << 1); - while(start < end) { - int idx; - - set_entryhi(start | newpid); - start += (PAGE_SIZE << 1); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - if(idx < 0) - continue; - /* Make sure all entries differ. */ - set_entryhi(KSEG0+idx*0x2000); - BARRIER; - tlb_write_indexed(); - BARRIER; - } - set_entryhi(oldpid); - } else { - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - } - __restore_flags(flags); - } -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if (vma->vm_mm->context != 0) { - unsigned long flags; - int oldpid, newpid, idx; - -#ifdef DEBUG_TLB - printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); -#endif - newpid = (vma->vm_mm->context & 0xff); - page &= (PAGE_MASK << 1); - __save_and_cli(flags); - oldpid = (get_entryhi() & 0xff); - set_entryhi(page | newpid); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - if(idx < 0) - goto finish; - /* Make sure all entries differ. */ - set_entryhi(KSEG0+idx*0x2000); - BARRIER; - tlb_write_indexed(); - - finish: - BARRIER; - set_entryhi(oldpid); - __restore_flags(flags); - } -} - -void pgd_init(unsigned long page) -{ - unsigned long *p = (unsigned long *) page; - int i; - - for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { - p[i + 0] = (unsigned long) invalid_pte_table; - p[i + 1] = (unsigned long) invalid_pte_table; - p[i + 2] = (unsigned long) invalid_pte_table; - p[i + 3] = (unsigned long) invalid_pte_table; - p[i + 4] = (unsigned long) invalid_pte_table; - p[i + 5] = (unsigned long) invalid_pte_table; - p[i + 6] = (unsigned long) invalid_pte_table; - p[i + 7] = (unsigned long) invalid_pte_table; - } -} - -/* - * Updates the TLB with the new pte(s). - */ -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx, pid; - - /* - * Handle debugger faulting in for debugee. - */ - if (current->active_mm != vma->vm_mm) - return; - - pid = get_entryhi() & 0xff; - -#ifdef DEBUG_TLB - if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", - (int) (vma->vm_mm->context & 0xff), pid); - } -#endif - - __save_and_cli(flags); - address &= (PAGE_MASK << 1); - set_entryhi(address | (pid)); - pgdp = pgd_offset(vma->vm_mm, address); - BARRIER; - tlb_probe(); - BARRIER; - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - BARRIER; - set_entrylo0(pte_val(*ptep++) >> 6); - set_entrylo1(pte_val(*ptep) >> 6); - set_entryhi(address | (pid)); - BARRIER; - if(idx < 0) { - tlb_write_random(); - } else { - tlb_write_indexed(); - } - BARRIER; - set_entryhi(pid); - BARRIER; - __restore_flags(flags); -} - -void show_regs(struct pt_regs * regs) -{ - /* Saved main processor registers. */ - printk("$0 : %08lx %08lx %08lx %08lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk("$4 : %08lx %08lx %08lx %08lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk("$12: %08lx %08lx %08lx %08lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk("$20: %08lx %08lx %08lx %08lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk("$24: %08lx %08lx\n", - regs->regs[24], regs->regs[25]); - printk("$28: %08lx %08lx %08lx %08lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - - /* Saved cp0 registers. */ - printk("epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_status, regs->cp0_cause); -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - old_pagemask = get_pagemask(); - wired = get_wired(); - set_wired (wired + 1); - set_index (wired); - BARRIER; - set_pagemask (pagemask); - set_entryhi(entryhi); - set_entrylo0(entrylo0); - set_entrylo1(entrylo1); - BARRIER; - tlb_write_indexed(); - BARRIER; - - set_entryhi(old_ctx); - BARRIER; - set_pagemask (old_pagemask); - flush_tlb_all(); - __restore_flags(flags); -} - -/* Detect and size the various caches. */ -static void __init probe_icache(unsigned long config) -{ - unsigned long config1; - unsigned int lsize; - - if (!(config & (1 << 31))) { - /* - * Not a MIPS32 complainant CPU. - * Config 1 register not supported, we assume R4k style. - */ - icache_size = 1 << (12 + ((config >> 9) & 7)); - ic_lsize = 16 << ((config >> 5) & 1); - mips_cpu.icache.linesz = ic_lsize; - - /* - * We cannot infer associativity - assume direct map - * unless probe template indicates otherwise - */ - if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1; - mips_cpu.icache.sets = - (icache_size / ic_lsize) / mips_cpu.icache.ways; - } else { - config1 = read_mips32_cp0_config1(); - - if ((lsize = ((config1 >> 19) & 7))) - mips_cpu.icache.linesz = 2 << lsize; - else - mips_cpu.icache.linesz = lsize; - mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7); - mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7); - - ic_lsize = mips_cpu.icache.linesz; - icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * - ic_lsize; - } - printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n", - icache_size >> 10, ic_lsize, mips_cpu.icache.ways); -} - -static void __init probe_dcache(unsigned long config) -{ - unsigned long config1; - unsigned int lsize; - - if (!(config & (1 << 31))) { - /* - * Not a MIPS32 complainant CPU. - * Config 1 register not supported, we assume R4k style. - */ - dcache_size = 1 << (12 + ((config >> 6) & 7)); - dc_lsize = 16 << ((config >> 4) & 1); - mips_cpu.dcache.linesz = dc_lsize; - /* - * We cannot infer associativity - assume direct map - * unless probe template indicates otherwise - */ - if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1; - mips_cpu.dcache.sets = - (dcache_size / dc_lsize) / mips_cpu.dcache.ways; - } else { - config1 = read_mips32_cp0_config1(); - - if ((lsize = ((config1 >> 10) & 7))) - mips_cpu.dcache.linesz = 2 << lsize; - else - mips_cpu.dcache.linesz= lsize; - mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7); - mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7); - - dc_lsize = mips_cpu.dcache.linesz; - dcache_size = - mips_cpu.dcache.sets * mips_cpu.dcache.ways - * dc_lsize; - } - printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n", - dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways); -} - - -/* If you even _breathe_ on this function, look at the gcc output - * and make sure it does not pop things on and off the stack for - * the cache sizing loop that executes in KSEG1 space or else - * you will crash and burn badly. You have been warned. - */ -static int __init probe_scache(unsigned long config) -{ - extern unsigned long stext; - unsigned long flags, addr, begin, end, pow2; - int tmp; - - if (mips_cpu.scache.flags == MIPS_CACHE_NOT_PRESENT) - return 0; - - tmp = ((config >> 17) & 1); - if(tmp) - return 0; - tmp = ((config >> 22) & 3); - switch(tmp) { - case 0: - sc_lsize = 16; - break; - case 1: - sc_lsize = 32; - break; - case 2: - sc_lsize = 64; - break; - case 3: - sc_lsize = 128; - break; - } - - begin = (unsigned long) &stext; - begin &= ~((4 * 1024 * 1024) - 1); - end = begin + (4 * 1024 * 1024); - - /* This is such a bitch, you'd think they would make it - * easy to do this. Away you daemons of stupidity! - */ - __save_and_cli(flags); - - /* Fill each size-multiple cache line with a valid tag. */ - pow2 = (64 * 1024); - for(addr = begin; addr < end; addr = (begin + pow2)) { - unsigned long *p = (unsigned long *) addr; - __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ - pow2 <<= 1; - } - - /* Load first line with zero (therefore invalid) tag. */ - set_taglo(0); - set_taghi(0); - __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 8, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 9, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 11, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - - /* Now search for the wrap around point. */ - pow2 = (128 * 1024); - tmp = 0; - for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) { - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 7, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (addr)); - __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ - if(!get_taglo()) - break; - pow2 <<= 1; - } - __restore_flags(flags); - addr -= begin; - printk("Secondary cache sized at %dK linesize %d bytes.\n", - (int) (addr >> 10), sc_lsize); - scache_size = addr; - return 1; -} - -static void __init setup_noscache_funcs(void) -{ - _clear_page = (void *)mips32_clear_page_dc; - _copy_page = (void *)mips32_copy_page_dc; - _flush_cache_all = mips32_flush_cache_all_pc; - ___flush_cache_all = mips32_flush_cache_all_pc; - _flush_cache_mm = mips32_flush_cache_mm_pc; - _flush_cache_range = mips32_flush_cache_range_pc; - _flush_cache_page = mips32_flush_cache_page_pc; - _flush_page_to_ram = mips32_flush_page_to_ram_pc; - - _flush_icache_page = mips32_flush_icache_page; - - _dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc; - _dma_cache_wback = mips32_dma_cache_wback; - _dma_cache_inv = mips32_dma_cache_inv_pc; -} - -static void __init setup_scache_funcs(void) -{ - _flush_cache_all = mips32_flush_cache_all_sc; - ___flush_cache_all = mips32_flush_cache_all_sc; - _flush_cache_mm = mips32_flush_cache_mm_sc; - _flush_cache_range = mips32_flush_cache_range_sc; - _flush_cache_page = mips32_flush_cache_page_sc; - _flush_page_to_ram = mips32_flush_page_to_ram_sc; - _clear_page = (void *)mips32_clear_page_sc; - _copy_page = (void *)mips32_copy_page_sc; - - _flush_icache_page = mips32_flush_icache_page_s; - - _dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc; - _dma_cache_wback = mips32_dma_cache_wback; - _dma_cache_inv = mips32_dma_cache_inv_sc; -} - -typedef int (*probe_func_t)(unsigned long); - -static inline void __init setup_scache(unsigned int config) -{ - probe_func_t probe_scache_kseg1; - int sc_present = 0; - - /* Maybe the cpu knows about a l2 cache? */ - probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); - sc_present = probe_scache_kseg1(config); - - if (sc_present) { - mips_cpu.scache.linesz = sc_lsize; - /* - * We cannot infer associativity - assume direct map - * unless probe template indicates otherwise - */ - if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1; - mips_cpu.scache.sets = - (scache_size / sc_lsize) / mips_cpu.scache.ways; - - setup_scache_funcs(); - return; - } - - setup_noscache_funcs(); -} - -static void __init probe_tlb(unsigned long config) -{ - unsigned long config1; - - if (!(config & (1 << 31))) { - /* - * Not a MIPS32 complainant CPU. - * Config 1 register not supported, we assume R4k style. - */ - mips_cpu.tlbsize = 48; - } else { - config1 = read_mips32_cp0_config1(); - if (!((config >> 7) & 3)) - panic("No MMU present"); - else - mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1; - } - - printk("Number of TLB entries %d.\n", mips_cpu.tlbsize); -} - -void __init ld_mmu_mips32(void) -{ - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - - printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - -#ifdef CONFIG_MIPS_UNCACHED - change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); -#else - change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); -#endif - - probe_icache(config); - probe_dcache(config); - setup_scache(config); - probe_tlb(config); - - _flush_cache_sigtramp = mips32_flush_cache_sigtramp; - _flush_icache_range = mips32_flush_icache_range; /* Ouch */ - - __flush_cache_all(); - write_32bit_cp0_register(CP0_WIRED, 0); - - /* - * You should never change this register: - * - The entire mm handling assumes the c0_pagemask register to - * be set for 4kb pages. - */ - write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); - flush_tlb_all(); -} diff -urN linux-2.4.18/arch/mips/mm/pg-andes.S linux-2.4.19-pre5/arch/mips/mm/pg-andes.S --- linux-2.4.18/arch/mips/mm/pg-andes.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-andes.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,67 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org + */ +#include +#include + +#define PAGE_SIZE 0x1000 + + .text + .set mips4 + .set noat + +/* + * This is suboptimal for 32-bit kernels; we assume that R10000 is only used + * with 64-bit kernels. The prefetch offsets have been experimentally tuned + * an Origin 200. + */ + +LEAF(andes_clear_page) + LONG_ADDIU AT, a0, PAGE_SIZE +1: pref 7, 512(a0) + LONG_S zero, 0*SZREG(a0) + LONG_S zero, 1*SZREG(a0) + LONG_S zero, 2*SZREG(a0) + LONG_S zero, 3*SZREG(a0) + LONG_ADDIU a0, a0, 8*SZREG + LONG_S zero, -4*SZREG(a0) + LONG_S zero, -3*SZREG(a0) + LONG_S zero, -2*SZREG(a0) + LONG_S zero, -1*SZREG(a0) + bne AT, a0, 1b + j ra + .end andes_clear_page + END(andes_clear_page) + +LEAF(andes_copy_page) + LONG_ADDIU AT, a0, PAGE_SIZE +1: pref 0, 2*128(a1) + pref 1, 2*128(a0) + LONG_L a3, 0*SZREG(a1) + LONG_L a2, 1*SZREG8(a1) + LONG_L v1, 2*SZREG(a1) + LONG_L v0, 3*SZREG(a1) + LONG_S a3, 0*SZREG(a0) + LONG_S a2, 1*SZREG(a0) + LONG_S v1, 2*SZREG(a0) + LONG_S v0, 3*SZREG(a0) + LONG_ADDIU a0, a0, 8*SZREG + LONG_ADDIU a1, a1, 8*SZREG + LONG_L a3, -4*SZREG(a1) + LONG_L a2, -3*SZREG(a1) + LONG_L v1, -2*SZREG(a1) + LONG_L v0, -1*SZREG(a1) + LONG_S a3, -4*SZREG(a0) + LONG_S a2, -3*SZREG(a0) + LONG_S v1, -2*SZREG(a0) + LONG_S v0, -1*SZREG(a0) + bne AT, a0,1b + j ra + END(andes_copy_page) diff -urN linux-2.4.18/arch/mips/mm/pg-mips32.c linux-2.4.19-pre5/arch/mips/mm/pg-mips32.c --- linux-2.4.18/arch/mips/mm/pg-mips32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-mips32.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,140 @@ +/* + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * MIPS32 CPU variant specific MMU/Cache routines. + */ +#include +#include + +#include +#include +#include + +extern int dc_lsize, ic_lsize, sc_lsize; + +/* + * Zero an entire page. + */ + +void mips32_clear_page_dc(unsigned long page) +{ + unsigned long i; + + if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) { + for (i=page; i +#include + +/* page functions */ +void r3k_clear_page(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "addiu\t$1,%0,%2\n" + "1:\tsw\t$0,(%0)\n\t" + "sw\t$0,4(%0)\n\t" + "sw\t$0,8(%0)\n\t" + "sw\t$0,12(%0)\n\t" + "addiu\t%0,32\n\t" + "sw\t$0,-16(%0)\n\t" + "sw\t$0,-12(%0)\n\t" + "sw\t$0,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t$0,-4(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE) + : "memory"); +} + +void r3k_copy_page(void * to, void * from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "addiu\t$1,%0,%8\n" + "1:\tlw\t%2,(%1)\n\t" + "lw\t%3,4(%1)\n\t" + "lw\t%4,8(%1)\n\t" + "lw\t%5,12(%1)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%3,4(%0)\n\t" + "sw\t%4,8(%0)\n\t" + "sw\t%5,12(%0)\n\t" + "lw\t%2,16(%1)\n\t" + "lw\t%3,20(%1)\n\t" + "lw\t%4,24(%1)\n\t" + "lw\t%5,28(%1)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%3,20(%0)\n\t" + "sw\t%4,24(%0)\n\t" + "sw\t%5,28(%0)\n\t" + "addiu\t%0,64\n\t" + "addiu\t%1,64\n\t" + "lw\t%2,-32(%1)\n\t" + "lw\t%3,-28(%1)\n\t" + "lw\t%4,-24(%1)\n\t" + "lw\t%5,-20(%1)\n\t" + "sw\t%2,-32(%0)\n\t" + "sw\t%3,-28(%0)\n\t" + "sw\t%4,-24(%0)\n\t" + "sw\t%5,-20(%0)\n\t" + "lw\t%2,-16(%1)\n\t" + "lw\t%3,-12(%1)\n\t" + "lw\t%4,-8(%1)\n\t" + "lw\t%5,-4(%1)\n\t" + "sw\t%2,-16(%0)\n\t" + "sw\t%3,-12(%0)\n\t" + "sw\t%4,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t%5,-4(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + : "0" (to), "1" (from), + "I" (PAGE_SIZE)); +} + +/* + * Initialize new page directory with pointers to invalid ptes + */ +void pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * The plain and boring version for the R3000. No cache flushing + * stuff is implemented since the R3000 has physical caches. + */ + __asm__ __volatile__( + ".set\tnoreorder\n" + "1:\tsw\t%2, (%0)\n\t" + "sw\t%2, 4(%0)\n\t" + "sw\t%2, 8(%0)\n\t" + "sw\t%2, 12(%0)\n\t" + "sw\t%2, 16(%0)\n\t" + "sw\t%2, 20(%0)\n\t" + "sw\t%2, 24(%0)\n\t" + "sw\t%2, 28(%0)\n\t" + "subu\t%1, 1\n\t" + "bnez\t%1, 1b\n\t" + "addiu\t%0, 32\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2) + :"r" ((unsigned long) invalid_pte_table), "0" (page), + "1" (USER_PTRS_PER_PGD / 8)); +} diff -urN linux-2.4.18/arch/mips/mm/pg-r4k.S linux-2.4.19-pre5/arch/mips/mm/pg-r4k.S --- linux-2.4.18/arch/mips/mm/pg-r4k.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-r4k.S Sat Mar 30 22:55:26 2002 @@ -0,0 +1,690 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org + */ +#include +#include +#include +#include +#include +#include + +#define PAGE_SIZE 0x1000 +#ifdef CONFIG_64BIT_PHYS_ADDR +#define PGD_SIZE 0x2000 +#else +#define PGD_SIZE 0x1000 +#endif + + .text + .set mips3 + .set noat + +/* + * Zero an entire page. Basically a simple unrolled loop should do the + * job but we want more performance by saving memory bus bandwidth. We + * have five flavours of the routine available for: + * + * - 16byte cachelines and no second level cache + * - 32byte cachelines second level cache + * - a version which handles the buggy R4600 v1.x + * - a version which handles the buggy R4600 v2.0 + * - Finally a last version without fancy cache games for the SC and MC + * versions of R4000 and R4400. + */ + +LEAF(r4k_clear_page_d16) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_D, (a0) + sd zero, (a0) + sd zero, 8(a0) + cache Create_Dirty_Excl_D, 16(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + cache Create_Dirty_Excl_D, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + cache Create_Dirty_Excl_D, -16(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_d16) + +LEAF(r4k_clear_page_d32) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_D, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + cache Create_Dirty_Excl_D, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_d32) + +/* + * This flavour of r4k_clear_page is for the R4600 V1.x. Cite from the + * IDT R4600 V1.7 errata: + * + * 18. The CACHE instructions Hit_Writeback_Invalidate_D, Hit_Writeback_D, + * Hit_Invalidate_D and Create_Dirty_Excl_D should only be + * executed if there is no other dcache activity. If the dcache is + * accessed for another instruction immeidately preceding when these + * cache instructions are executing, it is possible that the dcache + * tag match outputs used by these cache instructions will be + * incorrect. These cache instructions should be preceded by at least + * four instructions that are not any kind of load or store + * instruction. + * + * This is not allowed: lw + * nop + * nop + * nop + * cache Hit_Writeback_Invalidate_D + * + * This is allowed: lw + * nop + * nop + * nop + * nop + * cache Hit_Writeback_Invalidate_D + */ + +LEAF(r4k_clear_page_r4600_v1) + addiu AT, a0, PAGE_SIZE +1: nop + nop + nop + nop + cache Create_Dirty_Excl_D, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + nop + nop + nop + cache Create_Dirty_Excl_D, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_r4600_v1) + +LEAF(r4k_clear_page_r4600_v2) + mfc0 a1, CP0_STATUS + ori AT, a1, 1 + xori AT, 1 + mtc0 AT, CP0_STATUS + nop + nop + nop + + .set volatile + la AT, KSEG1 + lw zero, (AT) + .set novolatile + + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_D, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + cache Create_Dirty_Excl_D, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + + mfc0 AT, CP0_STATUS # __restore_flags + andi a1, 1 + ori AT, 1 + xori AT, 1 + or a1, AT + mtc0 a1, CP0_STATUS + nop + nop + nop + + jr ra + END(r4k_clear_page_r4600_v2) + +/* + * The next 4 versions are optimized for all possible scache configurations + * of the SC / MC versions of R4000 and R4400 ... + * + * Todo: For even better performance we should have a routine optimized for + * every legal combination of dcache / scache linesize. When I (Ralf) tried + * this the kernel crashed shortly after mounting the root filesystem. CPU + * bug? Weirdo cache instruction semantics? + */ + +LEAF(r4k_clear_page_s16) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + sd zero, (a0) + sd zero, 8(a0) + cache Create_Dirty_Excl_SD, 16(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + cache Create_Dirty_Excl_SD, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + cache Create_Dirty_Excl_SD, -16(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_s16) + +LEAF(r4k_clear_page_s32) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + cache Create_Dirty_Excl_SD, -32(a0) + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_s32) + +LEAF(r4k_clear_page_s64) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + addiu a0, 64 + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_s64) + +LEAF(r4k_clear_page_s128) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + sd zero, (a0) + sd zero, 8(a0) + sd zero, 16(a0) + sd zero, 24(a0) + sd zero, 32(a0) + sd zero, 40(a0) + sd zero, 48(a0) + sd zero, 56(a0) + addiu a0, 128 + sd zero, -64(a0) + sd zero, -56(a0) + sd zero, -48(a0) + sd zero, -40(a0) + sd zero, -32(a0) + sd zero, -24(a0) + sd zero, -16(a0) + sd zero, -8(a0) + bne AT, a0, 1b + jr ra + END(r4k_clear_page_s128) + +/* + * This is still inefficient. We only can do better if we know the + * virtual address where the copy will be accessed. + */ + +LEAF(r4k_copy_page_d16) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_D, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + cache Create_Dirty_Excl_D, 16(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + cache Create_Dirty_Excl_D, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + cache Create_Dirty_Excl_D, -16(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_d16) + +LEAF(r4k_copy_page_d32) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_D, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + cache Create_Dirty_Excl_D, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_d32) + +/* + * Again a special version for the R4600 V1.x + */ + +LEAF(r4k_copy_page_r4600_v1) + addiu AT, a0, PAGE_SIZE +1: nop + nop + nop + nop + cache Create_Dirty_Excl_D, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + nop + nop + nop + nop + cache Create_Dirty_Excl_D, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_r4600_v1) + +LEAF(r4k_copy_page_r4600_v2) + mfc0 v1, CP0_STATUS + ori AT, v1, 1 + xori AT, 1 + + mtc0 AT, CP0_STATUS + nop + nop + nop + + addiu AT, a0, PAGE_SIZE +1: nop + nop + nop + nop + cache Create_Dirty_Excl_D, (a0) + lw t1, (a1) + lw t0, 4(a1) + lw a3, 8(a1) + lw a2, 12(a1) + sw t1, (a0) + sw t0, 4(a0) + sw a3, 8(a0) + sw a2, 12(a0) + lw t1, 16(a1) + lw t0, 20(a1) + lw a3, 24(a1) + lw a2, 28(a1) + sw t1, 16(a0) + sw t0, 20(a0) + sw a3, 24(a0) + sw a2, 28(a0) + nop + nop + nop + nop + cache Create_Dirty_Excl_D, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw t1, -32(a1) + lw t0, -28(a1) + lw a3, -24(a1) + lw a2, -20(a1) + sw t1, -32(a0) + sw t0, -28(a0) + sw a3, -24(a0) + sw a2, -20(a0) + lw t1, -16(a1) + lw t0, -12(a1) + lw a3, -8(a1) + lw a2, -4(a1) + sw t1, -16(a0) + sw t0, -12(a0) + sw a3, -8(a0) + sw a2, -4(a0) + bne AT, a0, 1b + + mfc0 AT, CP0_STATUS # __restore_flags + andi v1, 1 + ori AT, 1 + xori AT, 1 + or v1, AT + mtc0 v1, CP0_STATUS + nop + nop + nop + jr ra + END(r4k_copy_page_r4600_v2) + +/* + * These are for R4000SC / R4400MC + */ + +LEAF(r4k_copy_page_s16) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + cache Create_Dirty_Excl_SD, 16(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + cache Create_Dirty_Excl_SD, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + cache Create_Dirty_Excl_SD, -16(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_s16) + +LEAF(r4k_copy_page_s32) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + cache Create_Dirty_Excl_SD, 32(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_s32) + +LEAF(r4k_copy_page_s64) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + addiu a0, 64 + addiu a1, 64 + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_s64) + +LEAF(r4k_copy_page_s128) + addiu AT, a0, PAGE_SIZE +1: cache Create_Dirty_Excl_SD, (a0) + lw a3, (a1) + lw a2, 4(a1) + lw v1, 8(a1) + lw v0, 12(a1) + sw a3, (a0) + sw a2, 4(a0) + sw v1, 8(a0) + sw v0, 12(a0) + lw a3, 16(a1) + lw a2, 20(a1) + lw v1, 24(a1) + lw v0, 28(a1) + sw a3, 16(a0) + sw a2, 20(a0) + sw v1, 24(a0) + sw v0, 28(a0) + lw a3, 32(a1) + lw a2, 36(a1) + lw v1, 40(a1) + lw v0, 44(a1) + sw a3, 32(a0) + sw a2, 36(a0) + sw v1, 40(a0) + sw v0, 44(a0) + lw a3, 48(a1) + lw a2, 52(a1) + lw v1, 56(a1) + lw v0, 60(a1) + sw a3, 48(a0) + sw a2, 52(a0) + sw v1, 56(a0) + sw v0, 60(a0) + addiu a0, 128 + addiu a1, 128 + lw a3, -64(a1) + lw a2, -60(a1) + lw v1, -56(a1) + lw v0, -52(a1) + sw a3, -64(a0) + sw a2, -60(a0) + sw v1, -56(a0) + sw v0, -52(a0) + lw a3, -48(a1) + lw a2, -44(a1) + lw v1, -40(a1) + lw v0, -36(a1) + sw a3, -48(a0) + sw a2, -44(a0) + sw v1, -40(a0) + sw v0, -36(a0) + lw a3, -32(a1) + lw a2, -28(a1) + lw v1, -24(a1) + lw v0, -20(a1) + sw a3, -32(a0) + sw a2, -28(a0) + sw v1, -24(a0) + sw v0, -20(a0) + lw a3, -16(a1) + lw a2, -12(a1) + lw v1, -8(a1) + lw v0, -4(a1) + sw a3, -16(a0) + sw a2, -12(a0) + sw v1, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(r4k_copy_page_s128) + +/* This one still needs to receive cache optimizations */ +LEAF(pgd_init) + addiu AT, a0, PGD_SIZE / 2 + la v0, invalid_pte_table +1: sw v0, (a0) + sw v0, 4(a0) + sw v0, 8(a0) + sw v0, 12(a0) + addiu a0, 32 + sw v0, -16(a0) + sw v0, -12(a0) + sw v0, -8(a0) + sw v0, -4(a0) + bne AT, a0, 1b + jr ra + END(pgd_init) diff -urN linux-2.4.18/arch/mips/mm/pg-r5432.c linux-2.4.19-pre5/arch/mips/mm/pg-r5432.c --- linux-2.4.18/arch/mips/mm/pg-r5432.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-r5432.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,117 @@ +/* + * 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) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org) + */ +#include +#include + +#include + +void r5432_clear_page_d32(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "addiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "addiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); +} + +/* + * This is still inefficient. We only can do better if we know the + * virtual address where the copy will be accessed. + */ + +void r5432_copy_page_d32(void * to, void * from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "addiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "lw\t%2,(%1)\n\t" + "lw\t%3,4(%1)\n\t" + "lw\t%4,8(%1)\n\t" + "lw\t%5,12(%1)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%3,4(%0)\n\t" + "sw\t%4,8(%0)\n\t" + "sw\t%5,12(%0)\n\t" + "lw\t%2,16(%1)\n\t" + "lw\t%3,20(%1)\n\t" + "lw\t%4,24(%1)\n\t" + "lw\t%5,28(%1)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%3,20(%0)\n\t" + "sw\t%4,24(%0)\n\t" + "sw\t%5,28(%0)\n\t" + "cache\t%9,32(%0)\n\t" + "addiu\t%0,64\n\t" + "addiu\t%1,64\n\t" + "lw\t%2,-32(%1)\n\t" + "lw\t%3,-28(%1)\n\t" + "lw\t%4,-24(%1)\n\t" + "lw\t%5,-20(%1)\n\t" + "sw\t%2,-32(%0)\n\t" + "sw\t%3,-28(%0)\n\t" + "sw\t%4,-24(%0)\n\t" + "sw\t%5,-20(%0)\n\t" + "lw\t%2,-16(%1)\n\t" + "lw\t%3,-12(%1)\n\t" + "lw\t%4,-8(%1)\n\t" + "lw\t%5,-4(%1)\n\t" + "sw\t%2,-16(%0)\n\t" + "sw\t%3,-12(%0)\n\t" + "sw\t%4,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t%5,-4(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + :"0" (to), "1" (from), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} diff -urN linux-2.4.18/arch/mips/mm/pg-rm7k.c linux-2.4.19-pre5/arch/mips/mm/pg-rm7k.c --- linux-2.4.18/arch/mips/mm/pg-rm7k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-rm7k.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,120 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org + */ +#include +#include + +#include + +/* + * Zero an entire page. Note that while the RM7000 has a second level cache + * it doesn't have a Create_Dirty_Excl_SD operation. + */ +void rm7k_clear_page(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "addiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "addiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); +} + +/* + * Copy an entire page. Note that while the RM7000 has a second level cache + * it doesn't have a Create_Dirty_Excl_SD operation. + */ +void rm7k_copy_page(void * to, void * from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "addiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "lw\t%2,(%1)\n\t" + "lw\t%3,4(%1)\n\t" + "lw\t%4,8(%1)\n\t" + "lw\t%5,12(%1)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%3,4(%0)\n\t" + "sw\t%4,8(%0)\n\t" + "sw\t%5,12(%0)\n\t" + "lw\t%2,16(%1)\n\t" + "lw\t%3,20(%1)\n\t" + "lw\t%4,24(%1)\n\t" + "lw\t%5,28(%1)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%3,20(%0)\n\t" + "sw\t%4,24(%0)\n\t" + "sw\t%5,28(%0)\n\t" + "cache\t%9,32(%0)\n\t" + "addiu\t%0,64\n\t" + "addiu\t%1,64\n\t" + "lw\t%2,-32(%1)\n\t" + "lw\t%3,-28(%1)\n\t" + "lw\t%4,-24(%1)\n\t" + "lw\t%5,-20(%1)\n\t" + "sw\t%2,-32(%0)\n\t" + "sw\t%3,-28(%0)\n\t" + "sw\t%4,-24(%0)\n\t" + "sw\t%5,-20(%0)\n\t" + "lw\t%2,-16(%1)\n\t" + "lw\t%3,-12(%1)\n\t" + "lw\t%4,-8(%1)\n\t" + "lw\t%5,-4(%1)\n\t" + "sw\t%2,-16(%0)\n\t" + "sw\t%3,-12(%0)\n\t" + "sw\t%4,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t%5,-4(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + : "0" (to), "1" (from), "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} diff -urN linux-2.4.18/arch/mips/mm/pg-sb1.c linux-2.4.19-pre5/arch/mips/mm/pg-sb1.c --- linux-2.4.18/arch/mips/mm/pg-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/pg-sb1.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,135 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000 Sibyte + * + * Written by Justin Carlson (carlson@sibyte.com) + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include + +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS +#define SB1_PREF_LOAD_STREAMED_HINT "0" +#define SB1_PREF_STORE_STREAMED_HINT "1" +#else +#define SB1_PREF_LOAD_STREAMED_HINT "4" +#define SB1_PREF_STORE_STREAMED_HINT "5" +#endif + +/* These are the functions hooked by the memory management function pointers */ +void sb1_clear_page(void *page) +{ + /* JDCXXX - This should be bottlenecked by the write buffer, but these + things tend to be mildly unpredictable...should check this on the + performance model */ + + /* We prefetch 4 lines ahead. We're also "cheating" slightly here... + since we know we're on an SB1, we force the assembler to take + 64-bit operands to speed things up */ + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " addiu $1, %0, %2 \n" /* Calculate the end of the page to clear */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%0) \n" /* Prefetch the first 4 lines */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%0) \n" + "1: sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ + " sd $0, 8(%0) \n" + " sd $0, 16(%0) \n" + " sd $0, 24(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ",128(%0) \n" /* Prefetch 4 lines ahead */ + " bne $1, %0, 1b \n" + " addiu %0, %0, 32 \n" /* Next cacheline (This instruction better be short piped!) */ + ".set pop \n" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE-32) + :"$1","memory"); + +} + +void sb1_copy_page(void *to, void *from) +{ + + /* This should be optimized in assembly...can't use ld/sd, though, + * because the top 32 bits could be nuked if we took an interrupt + * during the routine. And this is not a good place to be cli()'ing + */ + + /* The pref's used here are using "streaming" hints, which cause the + * copied data to be kicked out of the cache sooner. A page copy often + * ends up copying a lot more data than is commonly used, so this seems + * to make sense in terms of reducing cache pollution, but I've no real + * performance data to back this up + */ + + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " addiu $1, %0, %4 \n" /* Calculate the end of the page to copy */ + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 0(%0) \n" /* Prefetch the first 3 lines */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%1) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 32(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%1) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 64(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%1) \n" + "1: lw $2, 0(%0) \n" /* Block copy a cacheline */ + " lw $3, 4(%0) \n" + " lw $4, 8(%0) \n" + " lw $5, 12(%0) \n" + " lw $6, 16(%0) \n" + " lw $7, 20(%0) \n" + " lw $8, 24(%0) \n" + " lw $9, 28(%0) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 96(%0) \n" /* Prefetch ahead */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%1) \n" + " sw $2, 0(%1) \n" + " sw $3, 4(%1) \n" + " sw $4, 8(%1) \n" + " sw $5, 12(%1) \n" + " sw $6, 16(%1) \n" + " sw $7, 20(%1) \n" + " sw $8, 24(%1) \n" + " sw $9, 28(%1) \n" + " addiu %1, %1, 32 \n" /* Next cacheline */ + " nop \n" /* Force next add to short pipe */ + " nop \n" /* Force next add to short pipe */ + " bne $1, %0, 1b \n" + " addiu %0, %0, 32 \n" /* Next cacheline */ + ".set pop \n" + :"=r" (to), + "=r" (from) + : + "0" (from), + "1" (to), + "I" (PAGE_SIZE-32) + :"$1","$2","$3","$4","$5","$6","$7","$8","$9","memory"); +/* + unsigned long *src = from; + unsigned long *dest = to; + unsigned long *target = (unsigned long *) (((unsigned long)src) + PAGE_SIZE); + while (src != target) { + *dest++ = *src++; + } +*/ +} diff -urN linux-2.4.18/arch/mips/mm/r2300.c linux-2.4.19-pre5/arch/mips/mm/r2300.c --- linux-2.4.18/arch/mips/mm/r2300.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/r2300.c Thu Jan 1 01:00:00 1970 @@ -1,806 +0,0 @@ -/* - * r2300.c: R2000 and R3000 specific mmu/cache code. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * with a lot of changes to make this thing work for R3000s - * Tx39XX R4k style caches added. HK - * Copyright (C) 1998, 1999, 2000 Harald Koerfgen - * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * According to the paper written by D. Miller about Linux cache & TLB - * flush implementation, DMA/Driver coherence should be done at the - * driver layer. Thus, normally, we don't need flush dcache for R3000. - * Define this if driver does not handle cache consistency during DMA ops. - */ - -/* For R3000 cores with R4000 style caches */ -static unsigned long icache_size, dcache_size; /* Size in bytes */ -static unsigned long icache_lsize, dcache_lsize; /* Size in bytes */ -static unsigned long scache_size; - -#include -#include - -#undef DEBUG_TLB -#undef DEBUG_CACHE - -/* page functions */ -void r3k_clear_page(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%2\n" - "1:\tsw\t$0,(%0)\n\t" - "sw\t$0,4(%0)\n\t" - "sw\t$0,8(%0)\n\t" - "sw\t$0,12(%0)\n\t" - "addiu\t%0,32\n\t" - "sw\t$0,-16(%0)\n\t" - "sw\t$0,-12(%0)\n\t" - "sw\t$0,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t$0,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE) - :"$1","memory"); -} - -static void r3k_copy_page(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%8\n" - "1:\tlw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "addiu\t%0,64\n\t" - "addiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE)); -} - -unsigned long __init r3k_cache_size(unsigned long ca_flags) -{ - unsigned long flags, status, dummy, size; - volatile unsigned long *p; - - p = (volatile unsigned long *) KSEG0; - - flags = read_32bit_cp0_register(CP0_STATUS); - - /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); - - *p = 0xa5a55a5a; - dummy = *p; - status = read_32bit_cp0_register(CP0_STATUS); - - if (dummy != 0xa5a55a5a || (status & ST0_CM)) { - size = 0; - } else { - for (size = 128; size <= 0x40000; size <<= 1) - *(p + size) = 0; - *p = -1; - for (size = 128; - (size <= 0x40000) && (*(p + size) == 0); - size <<= 1) - ; - if (size > 0x40000) - size = 0; - } - - write_32bit_cp0_register(CP0_STATUS, flags); - - return size * sizeof(*p); -} - -unsigned long __init r3k_cache_lsize(unsigned long ca_flags) -{ - unsigned long flags, status, lsize, i, j; - volatile unsigned long *p; - - p = (volatile unsigned long *) KSEG0; - - flags = read_32bit_cp0_register(CP0_STATUS); - - /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); - - for (i = 0; i < 128; i++) - *(p + i) = 0; - *(volatile unsigned char *)p = 0; - for (lsize = 1; lsize < 128; lsize <<= 1) { - *(p + lsize); - status = read_32bit_cp0_register(CP0_STATUS); - if (!(status & ST0_CM)) - break; - } - for (i = 0; i < 128; i += lsize) - *(volatile unsigned char *)(p + i) = 0; - - write_32bit_cp0_register(CP0_STATUS, flags); - - return lsize * sizeof(*p); -} - -static void __init r3k_probe_cache(void) -{ - dcache_size = r3k_cache_size(ST0_ISC); - if (dcache_size) - dcache_lsize = r3k_cache_lsize(ST0_ISC); - - - icache_size = r3k_cache_size(ST0_ISC|ST0_SWC); - if (icache_size) - icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC); -} - -static void r3k_flush_icache_range(unsigned long start, unsigned long end) -{ - unsigned long size, i, flags; - volatile unsigned char *p = (char *)start; - - size = end - start; - if (size > icache_size) - size = icache_size; - - flags = read_32bit_cp0_register(CP0_STATUS); - - /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); - - for (i = 0; i < size; i += 0x080) { - asm ( "sb\t$0,0x000(%0)\n\t" - "sb\t$0,0x004(%0)\n\t" - "sb\t$0,0x008(%0)\n\t" - "sb\t$0,0x00c(%0)\n\t" - "sb\t$0,0x010(%0)\n\t" - "sb\t$0,0x014(%0)\n\t" - "sb\t$0,0x018(%0)\n\t" - "sb\t$0,0x01c(%0)\n\t" - "sb\t$0,0x020(%0)\n\t" - "sb\t$0,0x024(%0)\n\t" - "sb\t$0,0x028(%0)\n\t" - "sb\t$0,0x02c(%0)\n\t" - "sb\t$0,0x030(%0)\n\t" - "sb\t$0,0x034(%0)\n\t" - "sb\t$0,0x038(%0)\n\t" - "sb\t$0,0x03c(%0)\n\t" - "sb\t$0,0x040(%0)\n\t" - "sb\t$0,0x044(%0)\n\t" - "sb\t$0,0x048(%0)\n\t" - "sb\t$0,0x04c(%0)\n\t" - "sb\t$0,0x050(%0)\n\t" - "sb\t$0,0x054(%0)\n\t" - "sb\t$0,0x058(%0)\n\t" - "sb\t$0,0x05c(%0)\n\t" - "sb\t$0,0x060(%0)\n\t" - "sb\t$0,0x064(%0)\n\t" - "sb\t$0,0x068(%0)\n\t" - "sb\t$0,0x06c(%0)\n\t" - "sb\t$0,0x070(%0)\n\t" - "sb\t$0,0x074(%0)\n\t" - "sb\t$0,0x078(%0)\n\t" - "sb\t$0,0x07c(%0)\n\t" - : : "r" (p) ); - p += 0x080; - } - - write_32bit_cp0_register(CP0_STATUS,flags); -} - -static void r3k_flush_dcache_range(unsigned long start, unsigned long end) -{ - unsigned long size, i, flags; - volatile unsigned char *p = (char *)start; - - size = end - start; - if (size > dcache_size) - size = dcache_size; - - flags = read_32bit_cp0_register(CP0_STATUS); - - /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC); - - for (i = 0; i < size; i += 0x080) { - asm ( "sb\t$0,0x000(%0)\n\t" - "sb\t$0,0x004(%0)\n\t" - "sb\t$0,0x008(%0)\n\t" - "sb\t$0,0x00c(%0)\n\t" - "sb\t$0,0x010(%0)\n\t" - "sb\t$0,0x014(%0)\n\t" - "sb\t$0,0x018(%0)\n\t" - "sb\t$0,0x01c(%0)\n\t" - "sb\t$0,0x020(%0)\n\t" - "sb\t$0,0x024(%0)\n\t" - "sb\t$0,0x028(%0)\n\t" - "sb\t$0,0x02c(%0)\n\t" - "sb\t$0,0x030(%0)\n\t" - "sb\t$0,0x034(%0)\n\t" - "sb\t$0,0x038(%0)\n\t" - "sb\t$0,0x03c(%0)\n\t" - "sb\t$0,0x040(%0)\n\t" - "sb\t$0,0x044(%0)\n\t" - "sb\t$0,0x048(%0)\n\t" - "sb\t$0,0x04c(%0)\n\t" - "sb\t$0,0x050(%0)\n\t" - "sb\t$0,0x054(%0)\n\t" - "sb\t$0,0x058(%0)\n\t" - "sb\t$0,0x05c(%0)\n\t" - "sb\t$0,0x060(%0)\n\t" - "sb\t$0,0x064(%0)\n\t" - "sb\t$0,0x068(%0)\n\t" - "sb\t$0,0x06c(%0)\n\t" - "sb\t$0,0x070(%0)\n\t" - "sb\t$0,0x074(%0)\n\t" - "sb\t$0,0x078(%0)\n\t" - "sb\t$0,0x07c(%0)\n\t" - : : "r" (p) ); - p += 0x080; - } - - write_32bit_cp0_register(CP0_STATUS,flags); -} - -static inline unsigned long get_phys_page (unsigned long addr, - struct mm_struct *mm) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long physpage; - - pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - pte = pte_offset(pmd, addr); - - if ((physpage = pte_val(*pte)) & _PAGE_VALID) - return KSEG0ADDR(physpage & PAGE_MASK); - - return 0; -} - -static inline void r3k_flush_cache_all(void) -{ - r3k_flush_icache_range(KSEG0, KSEG0 + icache_size); -} - -static void r3k_flush_cache_mm(struct mm_struct *mm) -{ - if (mm->context != 0) { - -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r3k_flush_cache_all(); - } -} - -static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (!vma) - return; - - if (mm->context != current->active_mm->context) { - flush_cache_all(); - } else { - unsigned long flags, physpage; - - save_and_cli(flags); - while (start < end) { - if ((physpage = get_phys_page(start, mm))) - r3k_flush_icache_range(physpage, - physpage + PAGE_SIZE); - start += PAGE_SIZE; - } - restore_flags(flags); - } -} - -static void r3k_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - if (vma->vm_flags & VM_EXEC) { - unsigned long physpage; - - if ((physpage = get_phys_page(page, vma->vm_mm))) - r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); - } -} - -static void r3k_flush_page_to_ram(struct page * page) -{ - /* - * Nothing to be done - */ -} - -static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long physpage; - - if (mm->context == 0) - return; - - if (!(vma->vm_flags & VM_EXEC)) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - - physpage = (unsigned long) page_address(page); - if (physpage) - r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); -} - -static void r3k_flush_cache_sigtramp(unsigned long addr) -{ - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("csigtramp[%08lx]", addr); -#endif - - flags = read_32bit_cp0_register(CP0_STATUS); - - write_32bit_cp0_register(CP0_STATUS, flags&~ST0_IEC); - - /* Fill the TLB to avoid an exception with caches isolated. */ - asm ( "lw\t$0,0x000(%0)\n\t" - "lw\t$0,0x004(%0)\n\t" - : : "r" (addr) ); - - write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); - - asm ( "sb\t$0,0x000(%0)\n\t" - "sb\t$0,0x004(%0)\n\t" - : : "r" (addr) ); - - write_32bit_cp0_register(CP0_STATUS, flags); -} - -static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) -{ - wbflush(); - r3k_flush_dcache_range(start, start + size); -} - -/* TLB operations. */ -void flush_tlb_all(void) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - -#ifdef DEBUG_TLB - printk("[tlball]"); -#endif - - save_and_cli(flags); - old_ctx = (get_entryhi() & 0xfc0); - write_32bit_cp0_register(CP0_ENTRYLO0, 0); - for (entry = 8; entry < mips_cpu.tlbsize; entry++) { - write_32bit_cp0_register(CP0_INDEX, entry << 8); - write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12)); - __asm__ __volatile__("tlbwi"); - } - set_entryhi(old_ctx); - restore_flags(flags); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_TLB - printk("[tlbmm<%lu>]", (unsigned long) mm->context); -#endif - save_and_cli(flags); - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xfc0); - restore_flags(flags); - } -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if (mm->context != 0) { - unsigned long flags; - int size; - -#ifdef DEBUG_TLB - printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", - (mm->context & 0xfc0), start, end); -#endif - save_and_cli(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - if(size <= mips_cpu.tlbsize) { - int oldpid = (get_entryhi() & 0xfc0); - int newpid = (mm->context & 0xfc0); - - start &= PAGE_MASK; - end += (PAGE_SIZE - 1); - end &= PAGE_MASK; - while(start < end) { - int idx; - - set_entryhi(start | newpid); - start += PAGE_SIZE; - tlb_probe(); - idx = get_index(); - set_entrylo0(0); - set_entryhi(KSEG0); - if(idx < 0) - continue; - tlb_write_indexed(); - } - set_entryhi(oldpid); - } else { - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xfc0); - } - restore_flags(flags); - } -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm->context != 0) { - unsigned long flags; - int oldpid, newpid, idx; - -#ifdef DEBUG_TLB - printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page); -#endif - newpid = (vma->vm_mm->context & 0xfc0); - page &= PAGE_MASK; - save_and_cli(flags); - oldpid = (get_entryhi() & 0xfc0); - set_entryhi(page | newpid); - tlb_probe(); - idx = get_index(); - set_entrylo0(0); - set_entryhi(KSEG0); - if(idx < 0) - goto finish; - tlb_write_indexed(); - -finish: - set_entryhi(oldpid); - restore_flags(flags); - } -} - -/* - * Initialize new page directory with pointers to invalid ptes - */ -void pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - - /* - * The plain and boring version for the R3000. No cache flushing - * stuff is implemented since the R3000 has physical caches. - */ - __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tsw\t%2,(%0)\n\t" - "sw\t%2,4(%0)\n\t" - "sw\t%2,8(%0)\n\t" - "sw\t%2,12(%0)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%2,20(%0)\n\t" - "sw\t%2,24(%0)\n\t" - "sw\t%2,28(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,32\n\t" - ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2) - :"r" ((unsigned long) invalid_pte_table), - "0" (page), - "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); -} - -void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, - pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx, pid; - - /* - * Handle debugger faulting in for debugee. - */ - if (current->active_mm != vma->vm_mm) - return; - - pid = get_entryhi() & 0xfc0; - -#ifdef DEBUG_TLB - if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", - (vma->vm_mm->context & 0xfc0), pid); - } -#endif - - save_and_cli(flags); - address &= PAGE_MASK; - set_entryhi(address | (pid)); - pgdp = pgd_offset(vma->vm_mm, address); - tlb_probe(); - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - set_entrylo0(pte_val(*ptep)); - set_entryhi(address | (pid)); - if(idx < 0) { - tlb_write_random(); -#if 0 - printk("[MISS]"); -#endif - } else { - tlb_write_indexed(); -#if 0 - printk("[HIT]"); -#endif - } - set_entryhi(pid); - restore_flags(flags); -} - -void show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx %s\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, - print_tainted(), - (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -/* Todo: handle r4k-style TX39 TLB */ -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - unsigned long flags; - unsigned long old_ctx; - static unsigned long wired = 0; - - if (wired < 8) { - save_and_cli(flags); - old_ctx = get_entryhi() & 0xfc0; - set_entrylo0(entrylo0); - set_entryhi(entryhi); - set_index(wired); - wired++; - tlb_write_indexed(); - set_entryhi(old_ctx); - flush_tlb_all(); - restore_flags(flags); - } -} - -static void tx39_flush_icache_all(void ) -{ - - unsigned long start = KSEG0; - unsigned long end = (start + icache_size); - unsigned long dummy = 0; - - /* disable icache and stop streaming */ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - "mfc0\t%0,$3\n\t" - "xori\t%0,32\n\t" - "mtc0\t%0,$3\n\t" - "j\t1f\n\t" - "nop\n\t" - "1:\t.set\treorder\n\t" - : : "r"(dummy)); - - /* invalidate icache */ - while (start < end) { - cache16_unroll32(start,Index_Invalidate_I); - start += 0x200; - } - - /* enable icache */ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - "mfc0\t%0,$3\n\t" - "xori\t%0,32\n\t" - "mtc0\t%0,$3\n\t" - ".set\treorder\n\t" - : : "r"(dummy)); -} - -static __init void tx39_probe_cache(void) -{ - unsigned long config; - - config = read_32bit_cp0_register(CP0_CONF); - - icache_size = 1 << (10 + ((config >> 19) & 3)); - icache_lsize = 16; - - dcache_size = 1 << (10 + ((config >> 16) & 3)); - dcache_lsize = 4; -} - -void __init ld_mmu_r23000(void) -{ - unsigned long config; - - printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - - _clear_page = r3k_clear_page; - _copy_page = r3k_copy_page; - - switch (mips_cpu.cputype) { - case CPU_R2000: - case CPU_R3000: - case CPU_R3000A: - case CPU_R3081: - case CPU_R3081E: - - r3k_probe_cache(); - - _flush_cache_all = r3k_flush_cache_all; - ___flush_cache_all = r3k_flush_cache_all; - _flush_cache_mm = r3k_flush_cache_mm; - _flush_cache_range = r3k_flush_cache_range; - _flush_cache_page = r3k_flush_cache_page; - _flush_cache_sigtramp = r3k_flush_cache_sigtramp; - _flush_page_to_ram = r3k_flush_page_to_ram; - _flush_icache_page = r3k_flush_icache_page; - _flush_icache_range = r3k_flush_icache_range; - - _dma_cache_wback_inv = r3k_dma_cache_wback_inv; - break; - - case CPU_TX3912: - case CPU_TX3922: - case CPU_TX3927: - - config=read_32bit_cp0_register(CP0_CONF); - config &= ~TX39_CONF_WBON; - write_32bit_cp0_register(CP0_CONF, config); - - tx39_probe_cache(); - - _flush_cache_all = tx39_flush_icache_all; - ___flush_cache_all = tx39_flush_icache_all; - _flush_cache_mm = tx39_flush_icache_all; - _flush_cache_range = tx39_flush_icache_all; - _flush_cache_page = tx39_flush_icache_all; - _flush_cache_sigtramp = tx39_flush_icache_all; - _flush_page_to_ram = r3k_flush_page_to_ram; - _flush_icache_page = tx39_flush_icache_all; - _flush_icache_range = tx39_flush_icache_all; - - _dma_cache_wback_inv = r3k_dma_cache_wback_inv; - - break; - } - - printk("Primary instruction cache %dkb, linesize %d bytes\n", - (int) (icache_size >> 10), (int) icache_lsize); - printk("Primary data cache %dkb, linesize %d bytes\n", - (int) (dcache_size >> 10), (int) dcache_lsize); - - flush_tlb_all(); -} diff -urN linux-2.4.18/arch/mips/mm/r4xx0.c linux-2.4.19-pre5/arch/mips/mm/r4xx0.c --- linux-2.4.18/arch/mips/mm/r4xx0.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/r4xx0.c Thu Jan 1 01:00:00 1970 @@ -1,2713 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * r4xx0.c: R4000 processor variant specific MMU/Cache routines. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org - * - * To do: - * - * - this code is a overbloated pig - * - many of the bug workarounds are not efficient at all, but at - * least they are functional ... - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* CP0 hazard avoidance. */ -#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ - "nop; nop; nop; nop; nop; nop;\n\t" \ - ".set reorder\n\t") - -/* Primary cache parameters. */ -static int icache_size, dcache_size; /* Size in bytes */ -static int ic_lsize, dc_lsize; /* LineSize in bytes */ - -/* Secondary cache (if present) parameters. */ -static unsigned int scache_size, sc_lsize; /* Again, in bytes */ - -#include -#include - -#undef DEBUG_CACHE - -/* - * Dummy cache handling routines for machines without boardcaches - */ -static void no_sc_noop(void) {} - -static struct bcache_ops no_sc_ops = { - (void *)no_sc_noop, (void *)no_sc_noop, - (void *)no_sc_noop, (void *)no_sc_noop -}; - -struct bcache_ops *bcops = &no_sc_ops; - -/* - * On processors with QED R4600 style two set assosicative cache - * this is the bit which selects the way in the cache for the - * indexed cachops. - */ -#define icache_waybit (icache_size >> 1) -#define dcache_waybit (dcache_size >> 1) - -/* - * Zero an entire page. Basically a simple unrolled loop should do the - * job but we want more performance by saving memory bus bandwidth. We - * have five flavours of the routine available for: - * - * - 16byte cachelines and no second level cache - * - 32byte cachelines second level cache - * - a version which handles the buggy R4600 v1.x - * - a version which handles the buggy R4600 v2.0 - * - Finally a last version without fancy cache games for the SC and MC - * versions of R4000 and R4400. - */ - -static void r4k_clear_page_d16(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "cache\t%3,16(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "cache\t%3,-16(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); -} - -static void r4k_clear_page_d32(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); -} - - -/* - * This flavour of r4k_clear_page is for the R4600 V1.x. Cite from the - * IDT R4600 V1.7 errata: - * - * 18. The CACHE instructions Hit_Writeback_Invalidate_D, Hit_Writeback_D, - * Hit_Invalidate_D and Create_Dirty_Excl_D should only be - * executed if there is no other dcache activity. If the dcache is - * accessed for another instruction immeidately preceding when these - * cache instructions are executing, it is possible that the dcache - * tag match outputs used by these cache instructions will be - * incorrect. These cache instructions should be preceded by at least - * four instructions that are not any kind of load or store - * instruction. - * - * This is not allowed: lw - * nop - * nop - * nop - * cache Hit_Writeback_Invalidate_D - * - * This is allowed: lw - * nop - * nop - * nop - * nop - * cache Hit_Writeback_Invalidate_D - */ -static void r4k_clear_page_r4600_v1(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tnop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "cache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); -} - -/* - * And this one is for the R4600 V2.0 - */ -static void r4k_clear_page_r4600_v2(void * page) -{ - unsigned int flags; - - __save_and_cli(flags); - *(volatile unsigned int *)KSEG1; - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); - __restore_flags(flags); -} - -/* - * The next 4 versions are optimized for all possible scache configurations - * of the SC / MC versions of R4000 and R4400 ... - * - * Todo: For even better performance we should have a routine optimized for - * every legal combination of dcache / scache linesize. When I (Ralf) tried - * this the kernel crashed shortly after mounting the root filesystem. CPU - * bug? Weirdo cache instruction semantics? - */ -static void r4k_clear_page_s16(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "cache\t%3,16(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "cache\t%3,-16(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1","memory"); -} - -static void r4k_clear_page_s32(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1","memory"); -} - -static void r4k_clear_page_s64(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1","memory"); -} - -static void r4k_clear_page_s128(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "sd\t$0,32(%0)\n\t" - "sd\t$0,40(%0)\n\t" - "sd\t$0,48(%0)\n\t" - "sd\t$0,56(%0)\n\t" - "daddiu\t%0,128\n\t" - "sd\t$0,-64(%0)\n\t" - "sd\t$0,-56(%0)\n\t" - "sd\t$0,-48(%0)\n\t" - "sd\t$0,-40(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1","memory"); -} - - -/* - * This is still inefficient. We only can do better if we know the - * virtual address where the copy will be accessed. - */ - -static void r4k_copy_page_d16(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "cache\t%9,16(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "cache\t%9,-16(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); -} - -static void r4k_copy_page_d32(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); -} - -/* - * Again a special version for the R4600 V1.x - */ -static void r4k_copy_page_r4600_v1(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tnop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); -} - -static void r4k_copy_page_r4600_v2(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - unsigned int flags; - - __save_and_cli(flags); - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tnop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); - __restore_flags(flags); -} - -/* - * These are for R4000SC / R4400MC - */ -static void r4k_copy_page_s16(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "cache\t%9,16(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "cache\t%9,-16(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD)); -} - -static void r4k_copy_page_s32(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD)); -} - -static void r4k_copy_page_s64(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD)); -} - -static void r4k_copy_page_s128(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "lw\t%2,32(%1)\n\t" - "lw\t%3,36(%1)\n\t" - "lw\t%4,40(%1)\n\t" - "lw\t%5,44(%1)\n\t" - "sw\t%2,32(%0)\n\t" - "sw\t%3,36(%0)\n\t" - "sw\t%4,40(%0)\n\t" - "sw\t%5,44(%0)\n\t" - "lw\t%2,48(%1)\n\t" - "lw\t%3,52(%1)\n\t" - "lw\t%4,56(%1)\n\t" - "lw\t%5,60(%1)\n\t" - "sw\t%2,48(%0)\n\t" - "sw\t%3,52(%0)\n\t" - "sw\t%4,56(%0)\n\t" - "sw\t%5,60(%0)\n\t" - "daddiu\t%0,128\n\t" - "daddiu\t%1,128\n\t" - "lw\t%2,-64(%1)\n\t" - "lw\t%3,-60(%1)\n\t" - "lw\t%4,-56(%1)\n\t" - "lw\t%5,-52(%1)\n\t" - "sw\t%2,-64(%0)\n\t" - "sw\t%3,-60(%0)\n\t" - "sw\t%4,-56(%0)\n\t" - "sw\t%5,-52(%0)\n\t" - "lw\t%2,-48(%1)\n\t" - "lw\t%3,-44(%1)\n\t" - "lw\t%4,-40(%1)\n\t" - "lw\t%5,-36(%1)\n\t" - "sw\t%2,-48(%0)\n\t" - "sw\t%3,-44(%0)\n\t" - "sw\t%4,-40(%0)\n\t" - "sw\t%5,-36(%0)\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD)); -} - - -/* - * If you think for one second that this stuff coming up is a lot - * of bulky code eating too many kernel cache lines. Think _again_. - * - * Consider: - * 1) Taken branches have a 3 cycle penalty on R4k - * 2) The branch itself is a real dead cycle on even R4600/R5000. - * 3) Only one of the following variants of each type is even used by - * the kernel based upon the cache parameters we detect at boot time. - * - * QED. - */ - -static inline void r4k_flush_cache_all_s16d16i16(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); blast_scache16(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s32d16i16(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); blast_scache32(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s64d16i16(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); blast_scache64(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s128d16i16(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); blast_scache128(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s32d32i32(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache32(); blast_icache32(); blast_scache32(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s64d32i32(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache32(); blast_icache32(); blast_scache64(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_s128d32i32(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache32(); blast_icache32(); blast_scache128(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_d16i16(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); - __restore_flags(flags); -} - -static inline void r4k_flush_cache_all_d32i32(void) -{ - unsigned long flags; - - __save_and_cli(flags); - blast_dcache32(); blast_icache32(); - __restore_flags(flags); -} - -static void -r4k_flush_cache_range_s16d16i16(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s16d16i16(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache16_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void -r4k_flush_cache_range_s32d16i16(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s32d16i16(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache32_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if(vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s64d16i16(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache64_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s128d16i16(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache128_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s32d32i32(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache32_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s64d32i32(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache64_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - struct vm_area_struct *vma; - unsigned long flags; - - if (mm->context == 0) - return; - - start &= PAGE_MASK; -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - r4k_flush_cache_all_s128d32i32(); - } else { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - __save_and_cli(flags); - while(start < end) { - pgd = pgd_offset(mm, start); - pmd = pmd_offset(pgd, start); - pte = pte_offset(pmd, start); - - if(pte_val(*pte) & _PAGE_VALID) - blast_scache128_page(start); - start += PAGE_SIZE; - } - __restore_flags(flags); - } - } -} - -static void r4k_flush_cache_range_d16i16(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - __save_and_cli(flags); - blast_dcache16(); blast_icache16(); - __restore_flags(flags); - } -} - -static void r4k_flush_cache_range_d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - __save_and_cli(flags); - blast_dcache32(); blast_icache32(); - __restore_flags(flags); - } -} - -/* - * On architectures like the Sparc, we could get rid of lines in - * the cache created only by a certain context, but on the MIPS - * (and actually certain Sparc's) we cannot. - */ -static void r4k_flush_cache_mm_s16d16i16(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s16d16i16(); - } -} - -static void r4k_flush_cache_mm_s32d16i16(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s32d16i16(); - } -} - -static void r4k_flush_cache_mm_s64d16i16(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s64d16i16(); - } -} - -static void r4k_flush_cache_mm_s128d16i16(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s128d16i16(); - } -} - -static void r4k_flush_cache_mm_s32d32i32(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s32d32i32(); - } -} - -static void r4k_flush_cache_mm_s64d32i32(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s64d32i32(); - } -} - -static void r4k_flush_cache_mm_s128d32i32(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_s128d32i32(); - } -} - -static void r4k_flush_cache_mm_d16i16(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_d16i16(); - } -} - -static void r4k_flush_cache_mm_d32i32(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r4k_flush_cache_all_d32i32(); - } -} - -static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache16_page_indexed(page); - blast_scache16_page_indexed(page); - } else - blast_scache16_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache16_page_indexed(page); - blast_scache32_page_indexed(page); - } else - blast_scache32_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache16_page_indexed(page); - blast_scache64_page_indexed(page); - } else - blast_scache64_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache16_page_indexed(page); - blast_scache128_page_indexed(page); - } else - blast_scache128_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache32_page_indexed(page); - blast_scache32_page_indexed(page); - } else - blast_scache32_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache32_page_indexed(page); - blast_scache64_page_indexed(page); - } else - blast_scache64_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm->context != current->active_mm->context) { - /* Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (scache_size - 1))); - blast_dcache32_page_indexed(page); - blast_scache128_page_indexed(page); - } else - blast_scache128_page(page); -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_VALID)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if (mm == current->active_mm) { - blast_dcache16_page(page); - } else { - /* Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (dcache_size - 1))); - blast_dcache16_page_indexed(page); - } -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_PRESENT)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { - blast_dcache32_page(page); - } else { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (dcache_size - 1))); - blast_dcache32_page_indexed(page); - } -out: - __restore_flags(flags); -} - -static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - __save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_PRESENT)) - goto out; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { - blast_dcache32_page(page); - } else { - /* Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (dcache_size - 1))); - blast_dcache32_page_indexed(page); - blast_dcache32_page_indexed(page ^ dcache_waybit); - } -out: - __restore_flags(flags); -} - -/* If the addresses passed to these routines are valid, they are - * either: - * - * 1) In KSEG0, so we can do a direct flush of the page. - * 2) In KSEG2, and since every process can translate those - * addresses all the time in kernel mode we can do a direct - * flush. - * 3) In KSEG1, no flush necessary. - */ -static void r4k_flush_page_to_ram_s16(struct page *page) -{ - blast_scache16_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_s32(struct page *page) -{ - blast_scache32_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_s64(struct page *page) -{ - blast_scache64_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_s128(struct page *page) -{ - blast_scache128_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_d16(struct page *page) -{ - blast_dcache16_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_d32(struct page *page) -{ - blast_dcache32_page((unsigned long)page_address(page)); -} - -static void r4k_flush_page_to_ram_d32_r4600(struct page *page) -{ - unsigned long flags; - - __save_and_cli(flags); /* For R4600 v1.7 bug. */ - blast_dcache32_page((unsigned long)page_address(page)); - __restore_flags(flags); -} - -static void -r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) -{ - /* - * We did an scache flush therefore PI is already clean. - */ -} - -static void -r4k_flush_icache_range(unsigned long start, unsigned long end) -{ - flush_cache_all(); -} - -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. - */ -static void -r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page) -{ - if (!(vma->vm_flags & VM_EXEC)) - return; - - flush_cache_all(); -} - -/* - * Writeback and invalidate the primary cache dcache before DMA. - * - * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Inv_D, - * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Exclusive_D will only - * operate correctly if the internal data cache refill buffer is empty. These - * CACHE instructions should be separated from any potential data cache miss - * by a load instruction to an uncached address to empty the response buffer." - * (Revision 2.0 device errata from IDT available on http://www.idt.com/ - * in .pdf format.) - */ -static void -r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - unsigned int flags; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); - *(volatile unsigned long *)KSEG1; - - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - __restore_flags(flags); - } - bc_wback_inv(addr, size); -} - -static void -r4k_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= scache_size) { - flush_cache_all(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) break; - a += sc_lsize; - } -} - -static void -r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - unsigned int flags; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); - *(volatile unsigned long *)KSEG1; - - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - __restore_flags(flags); - } - - bc_inv(addr, size); -} - -static void -r4k_dma_cache_inv_sc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= scache_size) { - flush_cache_all(); - return; - } - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) break; - a += sc_lsize; - } -} - -static void -r4k_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("r4k_dma_cache called - should not happen.\n"); -} - -/* - * While we're protected against bad userland addresses we don't care - * very much about what happens in that case. Usually a segmentation - * fault will dump the process later on anyway ... - */ -static void r4k_flush_cache_sigtramp(unsigned long addr) -{ - __asm__ __volatile__("nop;nop;nop;nop"); /* R4600 V1.7 */ - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); -} - -static void r4600v20k_flush_cache_sigtramp(unsigned long addr) -{ - unsigned int flags; - - __save_and_cli(flags); - - /* Clear internal cache refill buffer */ - *(volatile unsigned int *)KSEG1; - - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); - - __restore_flags(flags); -} - -#undef DEBUG_TLB -#undef DEBUG_TLBUPDATE - -void flush_tlb_all(void) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - -#ifdef DEBUG_TLB - printk("[tlball]"); -#endif - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - set_entryhi(KSEG0); - set_entrylo0(0); - set_entrylo1(0); - BARRIER; - - entry = get_wired(); - - /* Blast 'em all away. */ - while(entry < mips_cpu.tlbsize) { - set_index(entry); - BARRIER; - tlb_write_indexed(); - BARRIER; - entry++; - } - BARRIER; - set_entryhi(old_ctx); - __restore_flags(flags); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_TLB - printk("[tlbmm<%d>]", mm->context); -#endif - __save_and_cli(flags); - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - __restore_flags(flags); - } -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm->context != 0) { - unsigned long flags; - int size; - -#ifdef DEBUG_TLB - printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), - start, end); -#endif - __save_and_cli(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - size = (size + 1) >> 1; - if(size <= mips_cpu.tlbsize/2) { - int oldpid = (get_entryhi() & 0xff); - int newpid = (mm->context & 0xff); - - start &= (PAGE_MASK << 1); - end += ((PAGE_SIZE << 1) - 1); - end &= (PAGE_MASK << 1); - while(start < end) { - int idx; - - set_entryhi(start | newpid); - start += (PAGE_SIZE << 1); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - BARRIER; - if(idx < 0) - continue; - tlb_write_indexed(); - BARRIER; - } - set_entryhi(oldpid); - } else { - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - } - __restore_flags(flags); - } -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if (vma->vm_mm->context != 0) { - unsigned long flags; - int oldpid, newpid, idx; - -#ifdef DEBUG_TLB - printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); -#endif - newpid = (vma->vm_mm->context & 0xff); - page &= (PAGE_MASK << 1); - __save_and_cli(flags); - oldpid = (get_entryhi() & 0xff); - set_entryhi(page | newpid); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - if(idx < 0) - goto finish; - BARRIER; - tlb_write_indexed(); - - finish: - BARRIER; - set_entryhi(oldpid); - __restore_flags(flags); - } -} - -void pgd_init(unsigned long page) -{ - unsigned long *p = (unsigned long *) page; - int i; - - for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { - p[i + 0] = (unsigned long) invalid_pte_table; - p[i + 1] = (unsigned long) invalid_pte_table; - p[i + 2] = (unsigned long) invalid_pte_table; - p[i + 3] = (unsigned long) invalid_pte_table; - p[i + 4] = (unsigned long) invalid_pte_table; - p[i + 5] = (unsigned long) invalid_pte_table; - p[i + 6] = (unsigned long) invalid_pte_table; - p[i + 7] = (unsigned long) invalid_pte_table; - } -} - -/* We will need multiple versions of update_mmu_cache(), one that just - * updates the TLB with the new pte(s), and another which also checks - * for the R4k "end of page" hardware bug and does the needy. - */ -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx, pid; - - /* - * Handle debugger faulting in for debugee. - */ - if (current->active_mm != vma->vm_mm) - return; - - pid = get_entryhi() & 0xff; - -#ifdef DEBUG_TLB - if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", - (int) (vma->vm_mm->context & 0xff), pid); - } -#endif - - __save_and_cli(flags); - address &= (PAGE_MASK << 1); - set_entryhi(address | (pid)); - pgdp = pgd_offset(vma->vm_mm, address); - BARRIER; - tlb_probe(); - BARRIER; - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - BARRIER; - set_entrylo0(pte_val(*ptep++) >> 6); - set_entrylo1(pte_val(*ptep) >> 6); - set_entryhi(address | (pid)); - BARRIER; - if(idx < 0) { - tlb_write_random(); - } else { - tlb_write_indexed(); - } - BARRIER; - set_entryhi(pid); - BARRIER; - __restore_flags(flags); -} - -#if 0 -static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx; - - __save_and_cli(flags); - address &= (PAGE_MASK << 1); - set_entryhi(address | (get_entryhi() & 0xff)); - pgdp = pgd_offset(vma->vm_mm, address); - tlb_probe(); - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - set_entrylo0(pte_val(*ptep++) >> 6); - set_entrylo1(pte_val(*ptep) >> 6); - BARRIER; - if(idx < 0) - tlb_write_random(); - else - tlb_write_indexed(); - BARRIER; - __restore_flags(flags); -} -#endif - -void show_regs(struct pt_regs * regs) -{ - /* Saved main processor registers. */ - printk("$0 : %08lx %08lx %08lx %08lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk("$4 : %08lx %08lx %08lx %08lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk("$12: %08lx %08lx %08lx %08lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk("$20: %08lx %08lx %08lx %08lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk("$24: %08lx %08lx\n", - regs->regs[24], regs->regs[25]); - printk("$28: %08lx %08lx %08lx %08lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - - /* Saved cp0 registers. */ - printk("epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_status, regs->cp0_cause); -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - old_pagemask = get_pagemask(); - wired = get_wired(); - set_wired (wired + 1); - set_index (wired); - BARRIER; - set_pagemask (pagemask); - set_entryhi(entryhi); - set_entrylo0(entrylo0); - set_entrylo1(entrylo1); - BARRIER; - tlb_write_indexed(); - BARRIER; - - set_entryhi(old_ctx); - BARRIER; - set_pagemask (old_pagemask); - flush_tlb_all(); - __restore_flags(flags); -} - -/* Detect and size the various r4k caches. */ -static void __init probe_icache(unsigned long config) -{ - switch (mips_cpu.cputype) { - case CPU_VR41XX: - icache_size = 1 << (10 + ((config >> 9) & 7)); - break; - default: - icache_size = 1 << (12 + ((config >> 9) & 7)); - break; - } - ic_lsize = 16 << ((config >> 5) & 1); - - printk("Primary instruction cache %dkb, linesize %d bytes.\n", - icache_size >> 10, ic_lsize); -} - -static void __init probe_dcache(unsigned long config) -{ - switch (mips_cpu.cputype) { - case CPU_VR41XX: - dcache_size = 1 << (10 + ((config >> 6) & 7)); - break; - default: - dcache_size = 1 << (12 + ((config >> 6) & 7)); - break; - } - dc_lsize = 16 << ((config >> 4) & 1); - - printk("Primary data cache %dkb, linesize %d bytes.\n", - dcache_size >> 10, dc_lsize); -} - - -/* If you even _breathe_ on this function, look at the gcc output - * and make sure it does not pop things on and off the stack for - * the cache sizing loop that executes in KSEG1 space or else - * you will crash and burn badly. You have been warned. - */ -static int __init probe_scache(unsigned long config) -{ - extern unsigned long stext; - unsigned long flags, addr, begin, end, pow2; - int tmp; - - tmp = ((config >> 17) & 1); - if(tmp) - return 0; - tmp = ((config >> 22) & 3); - switch(tmp) { - case 0: - sc_lsize = 16; - break; - case 1: - sc_lsize = 32; - break; - case 2: - sc_lsize = 64; - break; - case 3: - sc_lsize = 128; - break; - } - - begin = (unsigned long) &stext; - begin &= ~((4 * 1024 * 1024) - 1); - end = begin + (4 * 1024 * 1024); - - /* This is such a bitch, you'd think they would make it - * easy to do this. Away you daemons of stupidity! - */ - __save_and_cli(flags); - - /* Fill each size-multiple cache line with a valid tag. */ - pow2 = (64 * 1024); - for(addr = begin; addr < end; addr = (begin + pow2)) { - unsigned long *p = (unsigned long *) addr; - __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ - pow2 <<= 1; - } - - /* Load first line with zero (therefore invalid) tag. */ - set_taglo(0); - set_taghi(0); - __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 8, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 9, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 11, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (begin)); - - /* Now search for the wrap around point. */ - pow2 = (128 * 1024); - tmp = 0; - for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) { - __asm__ __volatile__("\n\t.set noreorder\n\t" - ".set mips3\n\t" - "cache 7, (%0)\n\t" - ".set mips0\n\t" - ".set reorder\n\t" : : "r" (addr)); - __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ - if(!get_taglo()) - break; - pow2 <<= 1; - } - __restore_flags(flags); - addr -= begin; - printk("Secondary cache sized at %dK linesize %d bytes.\n", - (int) (addr >> 10), sc_lsize); - scache_size = addr; - return 1; -} - -static void __init setup_noscache_funcs(void) -{ - unsigned int prid; - - switch(dc_lsize) { - case 16: - _clear_page = r4k_clear_page_d16; - _copy_page = r4k_copy_page_d16; - _flush_cache_all = r4k_flush_cache_all_d16i16; - _flush_cache_mm = r4k_flush_cache_mm_d16i16; - _flush_cache_range = r4k_flush_cache_range_d16i16; - _flush_cache_page = r4k_flush_cache_page_d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_d16; - break; - case 32: - prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0; - if (prid == 0x2010) { /* R4600 V1.7 */ - _clear_page = r4k_clear_page_r4600_v1; - _copy_page = r4k_copy_page_r4600_v1; - _flush_page_to_ram = r4k_flush_page_to_ram_d32_r4600; - } else if (prid == 0x2020) { /* R4600 V2.0 */ - _clear_page = r4k_clear_page_r4600_v2; - _copy_page = r4k_copy_page_r4600_v2; - _flush_page_to_ram = r4k_flush_page_to_ram_d32; - } else { - _clear_page = r4k_clear_page_d32; - _copy_page = r4k_copy_page_d32; - _flush_page_to_ram = r4k_flush_page_to_ram_d32; - } - _flush_cache_all = r4k_flush_cache_all_d32i32; - _flush_cache_mm = r4k_flush_cache_mm_d32i32; - _flush_cache_range = r4k_flush_cache_range_d32i32; - _flush_cache_page = r4k_flush_cache_page_d32i32; - break; - } - ___flush_cache_all = _flush_cache_all; - - _flush_icache_page = r4k_flush_icache_page_p; - - _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; - _dma_cache_wback = r4k_dma_cache_wback; - _dma_cache_inv = r4k_dma_cache_inv_pc; -} - -static void __init setup_scache_funcs(void) -{ - switch(sc_lsize) { - case 16: - switch(dc_lsize) { - case 16: - _flush_cache_all = r4k_flush_cache_all_s16d16i16; - _flush_cache_mm = r4k_flush_cache_mm_s16d16i16; - _flush_cache_range = r4k_flush_cache_range_s16d16i16; - _flush_cache_page = r4k_flush_cache_page_s16d16i16; - break; - case 32: - panic("Invalid cache configuration detected"); - }; - _flush_page_to_ram = r4k_flush_page_to_ram_s16; - _clear_page = r4k_clear_page_s16; - _copy_page = r4k_copy_page_s16; - break; - case 32: - switch(dc_lsize) { - case 16: - _flush_cache_all = r4k_flush_cache_all_s32d16i16; - _flush_cache_mm = r4k_flush_cache_mm_s32d16i16; - _flush_cache_range = r4k_flush_cache_range_s32d16i16; - _flush_cache_page = r4k_flush_cache_page_s32d16i16; - break; - case 32: - _flush_cache_all = r4k_flush_cache_all_s32d32i32; - _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; - _flush_cache_range = r4k_flush_cache_range_s32d32i32; - _flush_cache_page = r4k_flush_cache_page_s32d32i32; - break; - }; - _flush_page_to_ram = r4k_flush_page_to_ram_s32; - _clear_page = r4k_clear_page_s32; - _copy_page = r4k_copy_page_s32; - break; - case 64: - switch(dc_lsize) { - case 16: - _flush_cache_all = r4k_flush_cache_all_s64d16i16; - _flush_cache_mm = r4k_flush_cache_mm_s64d16i16; - _flush_cache_range = r4k_flush_cache_range_s64d16i16; - _flush_cache_page = r4k_flush_cache_page_s64d16i16; - break; - case 32: - _flush_cache_all = r4k_flush_cache_all_s64d32i32; - _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; - _flush_cache_range = r4k_flush_cache_range_s64d32i32; - _flush_cache_page = r4k_flush_cache_page_s64d32i32; - break; - }; - _flush_page_to_ram = r4k_flush_page_to_ram_s64; - _clear_page = r4k_clear_page_s64; - _copy_page = r4k_copy_page_s64; - break; - case 128: - switch(dc_lsize) { - case 16: - _flush_cache_all = r4k_flush_cache_all_s128d16i16; - _flush_cache_mm = r4k_flush_cache_mm_s128d16i16; - _flush_cache_range = r4k_flush_cache_range_s128d16i16; - _flush_cache_page = r4k_flush_cache_page_s128d16i16; - break; - case 32: - _flush_cache_all = r4k_flush_cache_all_s128d32i32; - _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; - _flush_cache_range = r4k_flush_cache_range_s128d32i32; - _flush_cache_page = r4k_flush_cache_page_s128d32i32; - break; - }; - _flush_page_to_ram = r4k_flush_page_to_ram_s128; - _clear_page = r4k_clear_page_s128; - _copy_page = r4k_copy_page_s128; - break; - } - ___flush_cache_all = _flush_cache_all; - _flush_icache_page = r4k_flush_icache_page_s; - _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; - _dma_cache_wback = r4k_dma_cache_wback; - _dma_cache_inv = r4k_dma_cache_inv_sc; -} - -typedef int (*probe_func_t)(unsigned long); - -static inline void __init setup_scache(unsigned int config) -{ - probe_func_t probe_scache_kseg1; - int sc_present = 0; - - /* Maybe the cpu knows about a l2 cache? */ - probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); - sc_present = probe_scache_kseg1(config); - - if (sc_present) { - setup_scache_funcs(); - return; - } - - setup_noscache_funcs(); -} - -void __init ld_mmu_r4xx0(void) -{ - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - - printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - -#ifdef CONFIG_MIPS_UNCACHED - change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); -#else - change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); -#endif - - probe_icache(config); - probe_dcache(config); - setup_scache(config); - - switch(mips_cpu.cputype) { - case CPU_R4600: /* QED style two way caches? */ - case CPU_R4700: - case CPU_R5000: - case CPU_NEVADA: - _flush_cache_page = r4k_flush_cache_page_d32i32_r4600; - } - - _flush_cache_sigtramp = r4k_flush_cache_sigtramp; - _flush_icache_range = r4k_flush_icache_range; /* Ouch */ - if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { - _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; - } - - __flush_cache_all(); - write_32bit_cp0_register(CP0_WIRED, 0); - - /* - * You should never change this register: - * - On R4600 1.7 the tlbp never hits for pages smaller than - * the value in the c0_pagemask register. - * - The entire mm handling assumes the c0_pagemask register to - * be set for 4kb pages. - */ - set_pagemask(PM_4K); - flush_tlb_all(); -} diff -urN linux-2.4.18/arch/mips/mm/r5432.c linux-2.4.19-pre5/arch/mips/mm/r5432.c --- linux-2.4.18/arch/mips/mm/r5432.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/r5432.c Thu Jan 1 01:00:00 1970 @@ -1,862 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * r5432.c: NEC Vr5432 processor. We cannot use r4xx0.c because of - * its unique way-selection method for indexed operations. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 2000 Jun Sun (jsun@mvista.com) - * - */ - -/* - * [jsun] - * In a sense, this is really silly. We cannot re-use r4xx0.c because - * the lowest-level indexed cache operation does not take way-selection - * into account. So all what I am doing here is to copy all the funcs - * and macros (in r4kcache.h) relavent to R5432 to this file, and then - * modify a few indexed cache operations. *sigh* - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* CP0 hazard avoidance. */ -#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ - "nop; nop; nop; nop; nop; nop;\n\t" \ - ".set reorder\n\t") - -#include -#include - -#undef DEBUG_CACHE - -/* Primary cache parameters. */ -static int icache_size, dcache_size; /* Size in bytes */ -static int ic_lsize, dc_lsize; /* LineSize in bytes */ - - -/* -------------------------------------------------------------------- */ -/* #include */ - -extern inline void flush_icache_line_indexed(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache %1, (%0)\n\t" - "cache %1, 1(%0)\n\t" - ".set mips0\n\t" - ".set reorder" - : - : "r" (addr), - "i" (Index_Invalidate_I)); -} - -extern inline void flush_dcache_line_indexed(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache %1, (%0)\n\t" - "cache %1, 1(%0)\n\t" - ".set mips0\n\t" - ".set reorder" - : - : "r" (addr), - "i" (Index_Writeback_Inv_D)); -} - -extern inline void flush_icache_line(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache %1, (%0)\n\t" - ".set mips0\n\t" - ".set reorder" - : - : "r" (addr), - "i" (Hit_Invalidate_I)); -} - -extern inline void flush_dcache_line(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache %1, (%0)\n\t" - ".set mips0\n\t" - ".set reorder" - : - : "r" (addr), - "i" (Hit_Writeback_Inv_D)); -} - -extern inline void invalidate_dcache_line(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache %1, (%0)\n\t" - ".set mips0\n\t" - ".set reorder" - : - : "r" (addr), - "i" (Hit_Invalidate_D)); -} - - -/* - * The next two are for badland addresses like signal trampolines. - */ -extern inline void protected_flush_icache_line(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n" - "1:\tcache %1,(%0)\n" - "2:\t.set mips0\n\t" - ".set reorder\n\t" - ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,2b\n\t" - ".previous" - : - : "r" (addr), - "i" (Hit_Invalidate_I)); -} - -extern inline void protected_writeback_dcache_line(unsigned long addr) -{ - __asm__ __volatile__( - ".set noreorder\n\t" - ".set mips3\n" - "1:\tcache %1,(%0)\n" - "2:\t.set mips0\n\t" - ".set reorder\n\t" - ".section\t__ex_table,\"a\"\n\t" - STR(PTR)"\t1b,2b\n\t" - ".previous" - : - : "r" (addr), - "i" (Hit_Writeback_D)); -} - - -#define cache32_unroll32(base,op) \ - __asm__ __volatile__(" \ - .set noreorder; \ - .set mips3; \ - cache %1, 0x000(%0); cache %1, 0x020(%0); \ - cache %1, 0x040(%0); cache %1, 0x060(%0); \ - cache %1, 0x080(%0); cache %1, 0x0a0(%0); \ - cache %1, 0x0c0(%0); cache %1, 0x0e0(%0); \ - cache %1, 0x100(%0); cache %1, 0x120(%0); \ - cache %1, 0x140(%0); cache %1, 0x160(%0); \ - cache %1, 0x180(%0); cache %1, 0x1a0(%0); \ - cache %1, 0x1c0(%0); cache %1, 0x1e0(%0); \ - cache %1, 0x200(%0); cache %1, 0x220(%0); \ - cache %1, 0x240(%0); cache %1, 0x260(%0); \ - cache %1, 0x280(%0); cache %1, 0x2a0(%0); \ - cache %1, 0x2c0(%0); cache %1, 0x2e0(%0); \ - cache %1, 0x300(%0); cache %1, 0x320(%0); \ - cache %1, 0x340(%0); cache %1, 0x360(%0); \ - cache %1, 0x380(%0); cache %1, 0x3a0(%0); \ - cache %1, 0x3c0(%0); cache %1, 0x3e0(%0); \ - .set mips0; \ - .set reorder" \ - : \ - : "r" (base), \ - "i" (op)); - -extern inline void blast_dcache32(void) -{ - unsigned long start = KSEG0; - unsigned long end = (start + dcache_size/2); - - while(start < end) { - cache32_unroll32(start,Index_Writeback_Inv_D); - cache32_unroll32(start+1,Index_Writeback_Inv_D); - start += 0x400; - } -} - -extern inline void blast_dcache32_page(unsigned long page) -{ - unsigned long start = page; - unsigned long end = (start + PAGE_SIZE); - - while(start < end) { - cache32_unroll32(start,Hit_Writeback_Inv_D); - start += 0x400; - } -} - -extern inline void blast_dcache32_page_indexed(unsigned long page) -{ - unsigned long start = page; - unsigned long end = (start + PAGE_SIZE); - - while(start < end) { - cache32_unroll32(start,Index_Writeback_Inv_D); - cache32_unroll32(start+1,Index_Writeback_Inv_D); - start += 0x400; - } -} - -extern inline void blast_icache32(void) -{ - unsigned long start = KSEG0; - unsigned long end = (start + icache_size/2); - - while(start < end) { - cache32_unroll32(start,Index_Invalidate_I); - cache32_unroll32(start+1,Index_Invalidate_I); - start += 0x400; - } -} - -extern inline void blast_icache32_page(unsigned long page) -{ - unsigned long start = page; - unsigned long end = (start + PAGE_SIZE); - - while(start < end) { - cache32_unroll32(start,Hit_Invalidate_I); - start += 0x400; - } -} - -extern inline void blast_icache32_page_indexed(unsigned long page) -{ - unsigned long start = page; - unsigned long end = (start + PAGE_SIZE); - - while(start < end) { - cache32_unroll32(start,Index_Invalidate_I); - cache32_unroll32(start+1,Index_Invalidate_I); - start += 0x400; - } -} - -/* -------------------------------------------------------------------- */ - -static void r5432_clear_page_d32(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); -} - - - -/* - * This is still inefficient. We only can do better if we know the - * virtual address where the copy will be accessed. - */ - -static void r5432_copy_page_d32(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); -} - - -/* - * If you think for one second that this stuff coming up is a lot - * of bulky code eating too many kernel cache lines. Think _again_. - * - * Consider: - * 1) Taken branches have a 3 cycle penalty on R4k - * 2) The branch itself is a real dead cycle on even R4600/R5000. - * 3) Only one of the following variants of each type is even used by - * the kernel based upon the cache parameters we detect at boot time. - * - * QED. - */ - -static inline void r5432_flush_cache_all_d32i32(void) -{ - blast_dcache32(); blast_icache32(); -} - -static void r5432_flush_cache_range_d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - blast_dcache32(); blast_icache32(); - } -} - -/* - * On architectures like the Sparc, we could get rid of lines in - * the cache created only by a certain context, but on the MIPS - * (and actually certain Sparc's) we cannot. - */ -static void r5432_flush_cache_mm_d32i32(struct mm_struct *mm) -{ - if (mm->context != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - r5432_flush_cache_all_d32i32(); - } -} - -static void r5432_flush_cache_page_d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (mm->context == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if (!(pte_val(*ptep) & _PAGE_PRESENT)) - return; - - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { - blast_dcache32_page(page); - } else { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (KSEG0 + (page & (dcache_size - 1))); - blast_dcache32_page_indexed(page); - } -} - - -/* If the addresses passed to these routines are valid, they are - * either: - * - * 1) In KSEG0, so we can do a direct flush of the page. - * 2) In KSEG2, and since every process can translate those - * addresses all the time in kernel mode we can do a direct - * flush. - * 3) In KSEG1, no flush necessary. - */ -static void r5432_flush_page_to_ram_d32(struct page *page) -{ - blast_dcache32_page((unsigned long)page_address(page)); -} - -static void -r5432_flush_icache_range(unsigned long start, unsigned long end) -{ - r5432_flush_cache_all_d32i32(); -} - -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. - */ -static void -r5432_flush_icache_page_i32(struct vm_area_struct *vma, struct page *page) -{ - if (!(vma->vm_flags & VM_EXEC)) - return; - - r5432_flush_cache_all_d32i32(); -} - -/* - * Writeback and invalidate the primary cache dcache before DMA. - */ -static void -r5432_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - } - bc_wback_inv(addr, size); -} - -static void -r5432_dma_cache_inv_pc(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - if (size >= dcache_size) { - flush_cache_all(); - } else { - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - if (a == end) break; - a += dc_lsize; - } - } - - bc_inv(addr, size); -} - -static void -r5432_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("r5432_dma_cache called - should not happen.\n"); -} - -/* - * While we're protected against bad userland addresses we don't care - * very much about what happens in that case. Usually a segmentation - * fault will dump the process later on anyway ... - */ -static void r5432_flush_cache_sigtramp(unsigned long addr) -{ - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); -} - -#undef DEBUG_TLB -#undef DEBUG_TLBUPDATE - -#define NTLB_ENTRIES 48 /* Fixed on all R4XX0 variants... */ - -#define NTLB_ENTRIES_HALF 24 /* Fixed on all R4XX0 variants... */ - -void flush_tlb_all(void) -{ - unsigned long old_ctx; - int entry; - unsigned long flags; - -#ifdef DEBUG_TLB - printk("[tlball]"); -#endif - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - set_entryhi(KSEG0); - set_entrylo0(0); - set_entrylo1(0); - BARRIER; - - entry = get_wired(); - - /* Blast 'em all away. */ - while(entry < NTLB_ENTRIES) { - set_index(entry); - BARRIER; - tlb_write_indexed(); - BARRIER; - entry++; - } - BARRIER; - set_entryhi(old_ctx); - __restore_flags(flags); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (mm->context != 0) { - unsigned long flags; - -#ifdef DEBUG_TLB - printk("[tlbmm<%d>]", mm->context); -#endif - __save_and_cli(flags); - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - __restore_flags(flags); - } -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm->context != 0) { - unsigned long flags; - int size; - -#ifdef DEBUG_TLB - printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), - start, end); -#endif - __save_and_cli(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - size = (size + 1) >> 1; - if(size <= NTLB_ENTRIES_HALF) { - int oldpid = (get_entryhi() & 0xff); - int newpid = (mm->context & 0xff); - - start &= (PAGE_MASK << 1); - end += ((PAGE_SIZE << 1) - 1); - end &= (PAGE_MASK << 1); - while(start < end) { - int idx; - - set_entryhi(start | newpid); - start += (PAGE_SIZE << 1); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - BARRIER; - if(idx < 0) - continue; - tlb_write_indexed(); - BARRIER; - } - set_entryhi(oldpid); - } else { - get_new_mmu_context(mm, asid_cache); - if (mm == current->active_mm) - set_entryhi(mm->context & 0xff); - } - __restore_flags(flags); - } -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if (vma->vm_mm->context != 0) { - unsigned long flags; - int oldpid, newpid, idx; - -#ifdef DEBUG_TLB - printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); -#endif - newpid = (vma->vm_mm->context & 0xff); - page &= (PAGE_MASK << 1); - __save_and_cli(flags); - oldpid = (get_entryhi() & 0xff); - set_entryhi(page | newpid); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - if(idx < 0) - goto finish; - BARRIER; - tlb_write_indexed(); - - finish: - BARRIER; - set_entryhi(oldpid); - __restore_flags(flags); - } -} - -void pgd_init(unsigned long page) -{ - unsigned long *p = (unsigned long *) page; - int i; - - for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { - p[i + 0] = (unsigned long) invalid_pte_table; - p[i + 1] = (unsigned long) invalid_pte_table; - p[i + 2] = (unsigned long) invalid_pte_table; - p[i + 3] = (unsigned long) invalid_pte_table; - p[i + 4] = (unsigned long) invalid_pte_table; - p[i + 5] = (unsigned long) invalid_pte_table; - p[i + 6] = (unsigned long) invalid_pte_table; - p[i + 7] = (unsigned long) invalid_pte_table; - } -} - -/* We will need multiple versions of update_mmu_cache(), one that just - * updates the TLB with the new pte(s), and another which also checks - * for the R4k "end of page" hardware bug and does the needy. - */ -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx, pid; - - /* - * Handle debugger faulting in for debugee. - */ - if (current->active_mm != vma->vm_mm) - return; - - pid = get_entryhi() & 0xff; - -#ifdef DEBUG_TLB - if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", - (int) (vma->vm_mm->context & 0xff), pid); - } -#endif - - __save_and_cli(flags); - address &= (PAGE_MASK << 1); - set_entryhi(address | (pid)); - pgdp = pgd_offset(vma->vm_mm, address); - BARRIER; - tlb_probe(); - BARRIER; - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - BARRIER; - set_entrylo0(pte_val(*ptep++) >> 6); - set_entrylo1(pte_val(*ptep) >> 6); - set_entryhi(address | (pid)); - BARRIER; - if(idx < 0) { - tlb_write_random(); - } else { - tlb_write_indexed(); - } - BARRIER; - set_entryhi(pid); - BARRIER; - __restore_flags(flags); -} - -void show_regs(struct pt_regs * regs) -{ - /* Saved main processor registers. */ - printk("$0 : %08lx %08lx %08lx %08lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk("$4 : %08lx %08lx %08lx %08lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk("$12: %08lx %08lx %08lx %08lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk("$20: %08lx %08lx %08lx %08lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk("$24: %08lx %08lx\n", - regs->regs[24], regs->regs[25]); - printk("$28: %08lx %08lx %08lx %08lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - - /* Saved cp0 registers. */ - printk("epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_status, regs->cp0_cause); -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - old_pagemask = get_pagemask(); - wired = get_wired(); - set_wired (wired + 1); - set_index (wired); - BARRIER; - set_pagemask (pagemask); - set_entryhi(entryhi); - set_entrylo0(entrylo0); - set_entrylo1(entrylo1); - BARRIER; - tlb_write_indexed(); - BARRIER; - - set_entryhi(old_ctx); - BARRIER; - set_pagemask (old_pagemask); - flush_tlb_all(); - __restore_flags(flags); -} - -/* Detect and size the various r4k caches. */ -static void __init probe_icache(unsigned long config) -{ - icache_size = 1 << (12 + ((config >> 9) & 7)); - ic_lsize = 16 << ((config >> 5) & 1); - - printk("Primary instruction cache %dkb, linesize %d bytes.\n", - icache_size >> 10, ic_lsize); -} - -static void __init probe_dcache(unsigned long config) -{ - dcache_size = 1 << (12 + ((config >> 6) & 7)); - dc_lsize = 16 << ((config >> 4) & 1); - - printk("Primary data cache %dkb, linesize %d bytes.\n", - dcache_size >> 10, dc_lsize); -} - - -void __init ld_mmu_r5432(void) -{ - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - - printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - - change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); - - probe_icache(config); - probe_dcache(config); - - _clear_page = r5432_clear_page_d32; - _copy_page = r5432_copy_page_d32; - _flush_cache_all = r5432_flush_cache_all_d32i32; - ___flush_cache_all = r5432_flush_cache_all_d32i32; - _flush_page_to_ram = r5432_flush_page_to_ram_d32; - _flush_cache_mm = r5432_flush_cache_mm_d32i32; - _flush_cache_range = r5432_flush_cache_range_d32i32; - _flush_cache_page = r5432_flush_cache_page_d32i32; - _flush_icache_page = r5432_flush_icache_page_i32; - _dma_cache_wback_inv = r5432_dma_cache_wback_inv_pc; - _dma_cache_wback = r5432_dma_cache_wback; - _dma_cache_inv = r5432_dma_cache_inv_pc; - - _flush_cache_sigtramp = r5432_flush_cache_sigtramp; - _flush_icache_range = r5432_flush_icache_range; /* Ouch */ - - __flush_cache_all(); - write_32bit_cp0_register(CP0_WIRED, 0); - - /* - * You should never change this register: - * - On R4600 1.7 the tlbp never hits for pages smaller than - * the value in the c0_pagemask register. - * - The entire mm handling assumes the c0_pagemask register to - * be set for 4kb pages. - */ - write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); - flush_tlb_all(); -} diff -urN linux-2.4.18/arch/mips/mm/rm7k.c linux-2.4.19-pre5/arch/mips/mm/rm7k.c --- linux-2.4.18/arch/mips/mm/rm7k.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/rm7k.c Thu Jan 1 01:00:00 1970 @@ -1,751 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * r4xx0.c: R4000 processor variant specific MMU/Cache routines. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org - * - * To do: - * - * - this code is a overbloated pig - * - many of the bug workarounds are not efficient at all, but at - * least they are functional ... - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* CP0 hazard avoidance. */ -#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ - "nop; nop; nop; nop; nop; nop;\n\t" \ - ".set reorder\n\t") - -/* Primary cache parameters. */ -static int icache_size, dcache_size; /* Size in bytes */ - -#define ic_lsize 32 /* Fixed to 32 byte on RM7000 */ -#define dc_lsize 32 /* Fixed to 32 byte on RM7000 */ -#define sc_lsize 32 /* Fixed to 32 byte on RM7000 */ -#define tc_pagesize (32*128) - -/* Secondary cache parameters. */ -#define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ - -#include -#include - -int rm7k_tcache_enabled = 0; - -/* - * Not added to asm/r4kcache.h because it seems to be RM7000-specific. - */ -#define Page_Invalidate_T 0x16 - -static inline void invalidate_tcache_page(unsigned long addr) -{ - __asm__ __volatile__( - ".set\tnoreorder\t\t\t# invalidate_tcache_page\n\t" - ".set\tmips3\n\t" - "cache\t%1, (%0)\n\t" - ".set\tmips0\n\t" - ".set\treorder" - : - : "r" (addr), - "i" (Page_Invalidate_T)); -} - -/* - * Zero an entire page. Note that while the RM7000 has a second level cache - * it doesn't have a Create_Dirty_Excl_SD operation. - */ -static void rm7k_clear_page(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tcache\t%3,(%0)\n\t" - "sd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "cache\t%3,-32(%0)\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1","memory"); -} - - -/* - * Copy an entire page. Note that while the RM7000 has a second level cache - * it doesn't have a Create_Dirty_Excl_SD operation. - */ -static void rm7k_copy_page(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "daddiu\t$1,%0,%8\n" - "1:\tcache\t%9,(%0)\n\t" - "lw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "cache\t%9,32(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D)); -} - -static void __flush_cache_all_d32i32(void) -{ - blast_dcache32(); - blast_icache32(); -} - -static inline void rm7k_flush_cache_all_d32i32(void) -{ - /* Yes! Caches that don't suck ... */ -} - -static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* RM7000 caches are sane ... */ -} - -static void rm7k_flush_cache_mm_d32i32(struct mm_struct *mm) -{ - /* RM7000 caches are sane ... */ -} - -static void rm7k_flush_cache_page_d32i32(struct vm_area_struct *vma, - unsigned long page) -{ - /* RM7000 caches are sane ... */ -} - -static void rm7k_flush_page_to_ram_d32i32(struct page * page) -{ - /* Yes! Caches that don't suck! */ -} - -static void rm7k_flush_icache_range(unsigned long start, unsigned long end) -{ - /* - * FIXME: This is overdoing things and harms performance. - */ - __flush_cache_all_d32i32(); -} - -static void rm7k_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - /* - * FIXME: We should not flush the entire cache but establish some - * temporary mapping and use hit_invalidate operation to flush out - * the line from the cache. - */ - __flush_cache_all_d32i32(); -} - - -/* - * Writeback and invalidate the primary cache dcache before DMA. - * (XXX These need to be fixed ...) - */ -static void -rm7k_dma_cache_wback_inv(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - flush_dcache_line(a); /* Hit_Writeback_Inv_D */ - flush_icache_line(a); /* Hit_Invalidate_I */ - flush_scache_line(a); /* Hit_Writeback_Inv_SD */ - if (a == end) break; - a += sc_lsize; - } - - if (!rm7k_tcache_enabled) - return; - - a = addr & ~(tc_pagesize - 1); - end = (addr + size) & ~(tc_pagesize - 1); - while(1) { - invalidate_tcache_page(a); /* Page_Invalidate_T */ - if (a == end) break; - a += tc_pagesize; - } -} - -static void -rm7k_dma_cache_inv(unsigned long addr, unsigned long size) -{ - unsigned long end, a; - - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); - while (1) { - invalidate_dcache_line(a); /* Hit_Invalidate_D */ - flush_icache_line(a); /* Hit_Invalidate_I */ - invalidate_scache_line(a); /* Hit_Invalidate_SD */ - if (a == end) break; - a += sc_lsize; - } - - if (!rm7k_tcache_enabled) - return; - - a = addr & ~(tc_pagesize - 1); - end = (addr + size) & ~(tc_pagesize - 1); - while(1) { - invalidate_tcache_page(a); /* Page_Invalidate_T */ - if (a == end) break; - a += tc_pagesize; - } -} - -static void -rm7k_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("rm7k_dma_cache_wback called - should not happen.\n"); -} - -/* - * While we're protected against bad userland addresses we don't care - * very much about what happens in that case. Usually a segmentation - * fault will dump the process later on anyway ... - */ -static void rm7k_flush_cache_sigtramp(unsigned long addr) -{ - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); - protected_flush_icache_line(addr & ~(ic_lsize - 1)); -} - -/* - * Undocumented RM7000: Bit 29 in the info register of the RM7000 v2.0 - * indicates if the TLB has 48 or 64 entries. - * - * 29 1 => 64 entry JTLB - * 0 => 48 entry JTLB - */ -static inline int __attribute__((const)) ntlb_entries(void) -{ - if (get_info() & (1 << 29)) - return 64; - - return 48; -} - -void flush_tlb_all(void) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = get_entryhi() & 0xff; - set_entryhi(KSEG0); - set_entrylo0(0); - set_entrylo1(0); - BARRIER; - - entry = get_wired(); - - /* Blast 'em all away. */ - while (entry < ntlb_entries()) { - set_index(entry); - BARRIER; - tlb_write_indexed(); - BARRIER; - entry++; - } - BARRIER; - set_entryhi(old_ctx); - __restore_flags(flags); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if(mm->context != 0) { - unsigned long flags; - - __save_and_cli(flags); - get_new_mmu_context(mm, asid_cache); - if (mm == current->mm) - set_entryhi(mm->context & 0xff); - __restore_flags(flags); - } -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - if(mm->context != 0) { - unsigned long flags; - int size; - - __save_and_cli(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - size = (size + 1) >> 1; - if (size <= (ntlb_entries() / 2)) { - int oldpid = (get_entryhi() & 0xff); - int newpid = (mm->context & 0xff); - - start &= (PAGE_MASK << 1); - end += ((PAGE_SIZE << 1) - 1); - end &= (PAGE_MASK << 1); - while(start < end) { - int idx; - - set_entryhi(start | newpid); - start += (PAGE_SIZE << 1); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - BARRIER; - if(idx < 0) - continue; - tlb_write_indexed(); - BARRIER; - } - set_entryhi(oldpid); - } else { - get_new_mmu_context(mm, asid_cache); - if(mm == current->mm) - set_entryhi(mm->context & 0xff); - } - __restore_flags(flags); - } -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - if(vma->vm_mm->context != 0) { - unsigned long flags; - int oldpid, newpid, idx; - - newpid = (vma->vm_mm->context & 0xff); - page &= (PAGE_MASK << 1); - __save_and_cli(flags); - oldpid = (get_entryhi() & 0xff); - set_entryhi(page | newpid); - BARRIER; - tlb_probe(); - BARRIER; - idx = get_index(); - set_entrylo0(0); - set_entrylo1(0); - set_entryhi(KSEG0); - if(idx < 0) - goto finish; - BARRIER; - tlb_write_indexed(); - - finish: - BARRIER; - set_entryhi(oldpid); - __restore_flags(flags); - } -} - -void pgd_init(unsigned long page) -{ - unsigned long *p = (unsigned long *) page; - int i; - - for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { - p[i + 0] = (unsigned long) invalid_pte_table; - p[i + 1] = (unsigned long) invalid_pte_table; - p[i + 2] = (unsigned long) invalid_pte_table; - p[i + 3] = (unsigned long) invalid_pte_table; - p[i + 4] = (unsigned long) invalid_pte_table; - p[i + 5] = (unsigned long) invalid_pte_table; - p[i + 6] = (unsigned long) invalid_pte_table; - p[i + 7] = (unsigned long) invalid_pte_table; - } -} - -/* - * We will need multiple versions of update_mmu_cache(), one that just - * updates the TLB with the new pte(s), and another which also checks - * for the R4k "end of page" hardware bug and does the needy. - */ -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int idx, pid; - - /* - * Handle debugger faulting in for debugee. - */ - if (current->active_mm != vma->vm_mm) - return; - - pid = get_entryhi() & 0xff; - - __save_and_cli(flags); - address &= (PAGE_MASK << 1); - set_entryhi(address | (pid)); - pgdp = pgd_offset(vma->vm_mm, address); - BARRIER; - tlb_probe(); - BARRIER; - pmdp = pmd_offset(pgdp, address); - idx = get_index(); - ptep = pte_offset(pmdp, address); - BARRIER; - set_entrylo0(pte_val(*ptep++) >> 6); - set_entrylo1(pte_val(*ptep) >> 6); - set_entryhi(address | (pid)); - BARRIER; - if (idx < 0) { - tlb_write_random(); - } else { - tlb_write_indexed(); - } - BARRIER; - set_entryhi(pid); - BARRIER; - __restore_flags(flags); -} - -void show_regs(struct pt_regs * regs) -{ - /* Saved main processor registers. */ - printk(KERN_INFO "$0 : %08lx %08lx %08lx %08lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk(KERN_INFO "$4 : %08lx %08lx %08lx %08lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk(KERN_INFO "$8 : %08lx %08lx %08lx %08lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk(KERN_INFO "$12: %08lx %08lx %08lx %08lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk(KERN_INFO "$16: %08lx %08lx %08lx %08lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk(KERN_INFO "$20: %08lx %08lx %08lx %08lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk(KERN_INFO "$24: %08lx %08lx\n", - regs->regs[24], regs->regs[25]); - printk(KERN_INFO "$28: %08lx %08lx %08lx %08lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - - /* Saved cp0 registers. */ - printk(KERN_INFO "epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_status, regs->cp0_cause); -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - old_pagemask = get_pagemask(); - wired = get_wired(); - set_wired (wired + 1); - set_index (wired); - BARRIER; - set_pagemask (pagemask); - set_entryhi(entryhi); - set_entrylo0(entrylo0); - set_entrylo1(entrylo1); - BARRIER; - tlb_write_indexed(); - BARRIER; - - set_entryhi(old_ctx); - BARRIER; - set_pagemask (old_pagemask); - flush_tlb_all(); - __restore_flags(flags); -} - -/* Used for loading TLB entries before trap_init() has started, when we - don't actually want to add a wired entry which remains throughout the - lifetime of the system */ - -static int temp_tlb_entry __initdata; - -__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - int ret = 0; - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - old_pagemask = get_pagemask(); - wired = get_wired(); - if (--temp_tlb_entry < wired) { - printk(KERN_WARNING "No TLB space left for add_temporary_entry\n"); - ret = -ENOSPC; - goto out; - } - - set_index (temp_tlb_entry); - BARRIER; - set_pagemask (pagemask); - set_entryhi(entryhi); - set_entrylo0(entrylo0); - set_entrylo1(entrylo1); - BARRIER; - tlb_write_indexed(); - BARRIER; - - set_entryhi(old_ctx); - BARRIER; - set_pagemask (old_pagemask); - out: - __restore_flags(flags); - return ret; -} - - - -/* Detect and size the caches. */ -static inline void probe_icache(unsigned long config) -{ - icache_size = 1 << (12 + ((config >> 9) & 7)); - - printk(KERN_INFO "Primary instruction cache %dKiB.\n", icache_size >> 10); -} - -static inline void probe_dcache(unsigned long config) -{ - dcache_size = 1 << (12 + ((config >> 6) & 7)); - - printk(KERN_INFO "Primary data cache %dKiB.\n", dcache_size >> 10); -} - - -/* - * This function is executed in the uncached segment KSEG1. - * It must not touch the stack, because the stack pointer still points - * into KSEG0. - * - * Three options: - * - Write it in assembly and guarantee that we don't use the stack. - * - Disable caching for KSEG0 before calling it. - * - Pray that GCC doesn't randomly start using the stack. - * - * This being Linux, we obviously take the least sane of those options - - * following DaveM's lead in r4xx0.c - * - * It seems we get our kicks from relying on unguaranteed behaviour in GCC - */ -static __init void setup_scache(void) -{ - int register i; - - set_cp0_config(1<<3 /* CONF_SE */); - - set_taglo(0); - set_taghi(0); - - for (i=0; i> 31) & 1) - return; - - printk(KERN_INFO "Secondary cache %dKiB, linesize %d bytes.\n", - (scache_size >> 10), sc_lsize); - - if ((config >> 3) & 1) - return; - - printk(KERN_INFO "Enabling secondary cache..."); - func(); - printk("Done\n"); -} - -static inline void probe_tcache(unsigned long config) -{ - if ((config >> 17) & 1) - return; - - /* We can't enable the L3 cache yet. There may be board-specific - * magic necessary to turn it on, and blindly asking the CPU to - * start using it would may give cache errors. - * - * Also, board-specific knowledge may allow us to use the - * CACHE Flash_Invalidate_T instruction if the tag RAM supports - * it, and may specify the size of the L3 cache so we don't have - * to probe it. - */ - printk(KERN_INFO "Tertiary cache present, %s enabled\n", - config&(1<<12) ? "already" : "not (yet)"); - - if ((config >> 12) & 1) - rm7k_tcache_enabled = 1; -} - -void __init ld_mmu_rm7k(void) -{ - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - unsigned long addr; - - printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - - change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - - /* RM7000 erratum #31. The icache is screwed at startup. */ - set_taglo(0); - set_taghi(0); - for (addr = KSEG0; addr <= KSEG0 + 4096; addr += ic_lsize) { - __asm__ __volatile__ ( - ".set noreorder\n\t" - ".set mips3\n\t" - "cache\t%1, 0(%0)\n\t" - "cache\t%1, 0x1000(%0)\n\t" - "cache\t%1, 0x2000(%0)\n\t" - "cache\t%1, 0x3000(%0)\n\t" - "cache\t%2, 0(%0)\n\t" - "cache\t%2, 0x1000(%0)\n\t" - "cache\t%2, 0x2000(%0)\n\t" - "cache\t%2, 0x3000(%0)\n\t" - "cache\t%1, 0(%0)\n\t" - "cache\t%1, 0x1000(%0)\n\t" - "cache\t%1, 0x2000(%0)\n\t" - "cache\t%1, 0x3000(%0)\n\t" - ".set\tmips0\n\t" - ".set\treorder\n\t" - : - : "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill)); - } - -#ifndef CONFIG_MIPS_UNCACHED - change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); -#endif - - probe_icache(config); - probe_dcache(config); - probe_scache(config); - probe_tcache(config); - - printk("TLB has %d entries.\n", ntlb_entries()); - - _clear_page = rm7k_clear_page; - _copy_page = rm7k_copy_page; - - _flush_cache_all = rm7k_flush_cache_all_d32i32; - ___flush_cache_all = __flush_cache_all_d32i32; - _flush_cache_mm = rm7k_flush_cache_mm_d32i32; - _flush_cache_range = rm7k_flush_cache_range_d32i32; - _flush_cache_page = rm7k_flush_cache_page_d32i32; - _flush_page_to_ram = rm7k_flush_page_to_ram_d32i32; - _flush_cache_sigtramp = rm7k_flush_cache_sigtramp; - _flush_icache_range = rm7k_flush_icache_range; - _flush_icache_page = rm7k_flush_icache_page; - - _dma_cache_wback_inv = rm7k_dma_cache_wback_inv; - _dma_cache_wback = rm7k_dma_cache_wback; - _dma_cache_inv = rm7k_dma_cache_inv; - - __flush_cache_all_d32i32(); - write_32bit_cp0_register(CP0_WIRED, 0); - temp_tlb_entry = ntlb_entries() - 1; - write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); - flush_tlb_all(); -} diff -urN linux-2.4.18/arch/mips/mm/sb1.c linux-2.4.19-pre5/arch/mips/mm/sb1.c --- linux-2.4.18/arch/mips/mm/sb1.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/sb1.c Thu Jan 1 01:00:00 1970 @@ -1,436 +0,0 @@ -/* - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 2000 Sibyte - * - * Written by Justin Carlson (carlson@sibyte.com) - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/* - * In this entire file, I'm not sure what the role of the L2 on the sb1250 - * is. Since it is coherent to the system, we should never need to flush - * it...right?...right??? -JDC - */ - -#include - -/* These are probed at ld_mmu time */ -static unsigned int icache_size; -static unsigned int dcache_size; - -static unsigned int icache_line_size; -static unsigned int dcache_line_size; - -static unsigned int icache_assoc; -static unsigned int dcache_assoc; - -static unsigned int icache_sets; -static unsigned int dcache_sets; -static unsigned int tlb_entries; - -void pgd_init(unsigned long page) -{ - unsigned long *p = (unsigned long *) page; - int i; - - for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { - p[i + 0] = (unsigned long) invalid_pte_table; - p[i + 1] = (unsigned long) invalid_pte_table; - p[i + 2] = (unsigned long) invalid_pte_table; - p[i + 3] = (unsigned long) invalid_pte_table; - p[i + 4] = (unsigned long) invalid_pte_table; - p[i + 5] = (unsigned long) invalid_pte_table; - p[i + 6] = (unsigned long) invalid_pte_table; - p[i + 7] = (unsigned long) invalid_pte_table; - } -} - -void flush_tlb_all(void) -{ - unsigned long flags; - unsigned long old_ctx; - int entry; - - __save_and_cli(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = (get_entryhi() & 0xff); - set_entrylo0(0); - set_entrylo1(0); - for (entry = 0; entry < tlb_entries; entry++) { - set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry); - set_index(entry); - tlb_write_indexed(); - } - set_entryhi(old_ctx); - __restore_flags(flags); -} - - - -/* These are the functions hooked by the memory management function pointers */ -static void sb1_clear_page(void *page) -{ - /* JDCXXX - This should be bottlenecked by the write buffer, but these - things tend to be mildly unpredictable...should check this on the - performance model */ - - /* We prefetch 4 lines ahead. We're also "cheating" slightly here... - since we know we're on an SB1, we force the assembler to take - 64-bit operands to speed things up */ - __asm__ __volatile__( - ".set push \n" - ".set noreorder \n" - ".set noat \n" - ".set mips4 \n" - " addiu $1, %0, %2 \n" /* Calculate the end of the page to clear */ - " pref 5, 0(%0) \n" /* Prefetch the first 4 lines */ - " pref 5, 32(%0) \n" - " pref 5, 64(%0) \n" - " pref 5, 96(%0) \n" - "1: sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ - " sd $0, 8(%0) \n" - " sd $0, 16(%0) \n" - " sd $0, 24(%0) \n" - " pref 5,128(%0) \n" /* Prefetch 4 lines ahead */ - " bne $1, %0, 1b \n" - " addiu %0, %0, 32 \n" /* Next cacheline (This instruction better be short piped!) */ - ".set pop \n" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE-32) - :"$1","memory"); - -} - -static void sb1_copy_page(void *to, void *from) -{ - - /* This should be optimized in assembly...can't use ld/sd, though, - * because the top 32 bits could be nuked if we took an interrupt - * during the routine. And this is not a good place to be cli()'ing - */ - - /* The pref's used here are using "streaming" hints, which cause the - * copied data to be kicked out of the cache sooner. A page copy often - * ends up copying a lot more data than is commonly used, so this seems - * to make sense in terms of reducing cache pollution, but I've no real - * performance data to back this up - */ - - __asm__ __volatile__( - ".set push \n" - ".set noreorder \n" - ".set noat \n" - ".set mips4 \n" - " addiu $1, %0, %4 \n" /* Calculate the end of the page to copy */ - " pref 4, 0(%0) \n" /* Prefetch the first 3 lines to be read and copied */ - " pref 5, 0(%1) \n" - " pref 4, 32(%0) \n" - " pref 5, 32(%1) \n" - " pref 4, 64(%0) \n" - " pref 5, 64(%1) \n" - "1: lw $2, 0(%0) \n" /* Block copy a cacheline */ - " lw $3, 4(%0) \n" - " lw $4, 8(%0) \n" - " lw $5, 12(%0) \n" - " lw $6, 16(%0) \n" - " lw $7, 20(%0) \n" - " lw $8, 24(%0) \n" - " lw $9, 28(%0) \n" - " pref 4, 96(%0) \n" /* Prefetch ahead */ - " pref 5, 96(%1) \n" - " sw $2, 0(%1) \n" - " sw $3, 4(%1) \n" - " sw $4, 8(%1) \n" - " sw $5, 12(%1) \n" - " sw $6, 16(%1) \n" - " sw $7, 20(%1) \n" - " sw $8, 24(%1) \n" - " sw $9, 28(%1) \n" - " addiu %1, %1, 32 \n" /* Next cacheline */ - " nop \n" /* Force next add to short pipe */ - " nop \n" /* Force next add to short pipe */ - " bne $1, %0, 1b \n" - " addiu %0, %0, 32 \n" /* Next cacheline */ - ".set pop \n" - :"=r" (to), - "=r" (from) - : - "0" (from), - "1" (to), - "I" (PAGE_SIZE-32) - :"$1","$2","$3","$4","$5","$6","$7","$8","$9","memory"); -/* - unsigned long *src = from; - unsigned long *dest = to; - unsigned long *target = (unsigned long *) (((unsigned long)src) + PAGE_SIZE); - while (src != target) { - *dest++ = *src++; - } -*/ -} - -/* - * The dcache is fully coherent to the system, with one - * big caveat: the instruction stream. In other words, - * if we miss in the icache, and have dirty data in the - * L1 dcache, then we'll go out to memory (or the L2) and - * get the not-as-recent data. - * - * So the only time we have to flush the dcache is when - * we're flushing the icache. Since the L2 is fully - * coherent to everything, including I/O, we never have - * to flush it - */ - -static void sb1_flush_cache_all(void) -{ - - /* - * Haven't worried too much about speed here; given that we're flushing - * the icache, the time to invalidate is dwarfed by the time it's going - * to take to refill it. Register usage: - * - * $1 - moving cache index - * $2 - set count - */ - if (icache_sets) { - __asm__ __volatile__ ( - ".set push \n" - ".set noreorder \n" - ".set noat \n" - ".set mips4 \n" - " move $1, %2 \n" /* Start at index 0 */ - "1: cache 0, 0($1) \n" /* Invalidate this index */ - " addiu %1, %1, -1 \n" /* Decrement loop count */ - " bnez %1, 1b \n" /* loop test */ - " addu $1, $1, %0 \n" /* Next address JDCXXX - Should be short piped */ - ".set pop \n" - ::"r" (icache_line_size), - "r" (icache_sets * icache_assoc), - "r" (KSEG0) - :"$1"); - } - if (dcache_sets) { - __asm__ __volatile__ ( - ".set push \n" - ".set noreorder \n" - ".set noat \n" - ".set mips4 \n" - " move $1, %2 \n" /* Start at index 0 */ - "1: cache 0x1, 0($1) \n" /* WB/Invalidate this index */ - " addiu %1, %1, -1 \n" /* Decrement loop count */ - " bnez %1, 1b \n" /* loop test */ - " addu $1, $1, %0 \n" /* Next address JDCXXX - Should be short piped */ - ".set pop \n" - ::"r" (dcache_line_size), - "r" (dcache_sets * dcache_assoc), - "r" (KSEG0) - :"$1"); - } -} - -/* - * When flushing a range in the icache, we have to first writeback - * the dcache for the same range, so new ifetches will see any - * data that was dirty in the dcache - */ - -static void sb1_flush_icache_range(unsigned long start, unsigned long end) -{ - - /* JDCXXX - Implement me! */ - sb1_flush_cache_all(); -} - -static void sb1_flush_cache_mm(struct mm_struct *mm) -{ - /* Don't need to do this, as the dcache is physically tagged */ -} - -static void sb1_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* Don't need to do this, as the dcache is physically tagged */ -} - - -static void sb1_flush_cache_sigtramp(unsigned long page) -{ - /* JDCXXX - Implement me! */ - sb1_flush_cache_all(); -} - - -/* - * This only needs to make sure stores done up to this - * point are visible to other agents outside the CPU. Given - * the coherent nature of the ZBus, all that's required here is - * a sync to make sure the data gets out to the caches and is - * visible to an arbitrary A Phase from an external agent - * - * Actually, I'm not even sure that's necessary; the semantics - * of this function aren't clear. If it's supposed to serve as - * a memory barrier, this is needed. If it's only meant to - * prevent data from being invisible to non-cpu memory accessors - * for some indefinite period of time (e.g. in a non-coherent - * dcache) then this function would be a complete nop. - */ -static void sb1_flush_page_to_ram(struct page *page) -{ - __asm__ __volatile__( - " sync \n" /* Short pipe */ - :::"memory"); -} - - -/* Cribbed from the r2300 code */ -static void sb1_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - sb1_flush_cache_all(); -#if 0 - struct mm_struct *mm = vma->vm_mm; - unsigned long physpage; - - /* No icache flush needed without context; */ - if (mm->context == 0) - return; - - /* No icache flush needed if the page isn't executable */ - if (!(vma->vm_flags & VM_EXEC)) - return; - - physpage = (unsigned long) page_address(page); - if (physpage) - sb1_flush_icache_range(physpage, physpage + PAGE_SIZE); -#endif -} - - -/* - * Cache set values (from the mips64 spec) - * 0 - 64 - * 1 - 128 - * 2 - 256 - * 3 - 512 - * 4 - 1024 - * 5 - 2048 - * 6 - 4096 - * 7 - Reserved - */ -static unsigned int decode_cache_sets(unsigned int config_field) -{ - if (config_field == 7) { - /* JDCXXX - Find a graceful way to abort. */ - return 0; - } - - return (1<<(config_field + 6)); -} - -/* - * Cache line size values (from the mips64 spec) - * 0 - No cache present. - * 1 - 4 bytes - * 2 - 8 bytes - * 3 - 16 bytes - * 4 - 32 bytes - * 5 - 64 bytes - * 6 - 128 bytes - * 7 - Reserved - */ -static unsigned int decode_cache_line_size(unsigned int config_field) -{ - if (config_field == 0) { - return 0; - } else if (config_field == 7) { - /* JDCXXX - Find a graceful way to abort. */ - return 0; - } - return (1<<(config_field + 1)); -} - -/* - * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs) - * - * 24:22 Icache sets per way - * 21:19 Icache line size - * 18:16 Icache Associativity - * 15:13 Dcache sets per way - * 12:10 Dcache line size - * 9:7 Dcache Associativity - */ - - -static void probe_cache_sizes(void) -{ - u32 config1; - - __asm__ __volatile__( - ".set push \n" - ".set mips64 \n" - " mfc0 %0, $16, 1 \n" /* Get config1 register */ - ".set pop \n" - :"=r" (config1)); - icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7); - dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7); - icache_sets = decode_cache_sets((config1 >> 22) & 0x7); - dcache_sets = decode_cache_sets((config1 >> 13) & 0x7); - icache_assoc = ((config1 >> 16) & 0x7) + 1; - dcache_assoc = ((config1 >> 7) & 0x7) + 1; - icache_size = icache_line_size * icache_sets * icache_assoc; - dcache_size = dcache_line_size * dcache_sets * dcache_assoc; - tlb_entries = ((config1 >> 25) & 0x3f) + 1; -} - - -/* This is called from loadmmu.c. We have to set up all the - memory management function pointers, as well as initialize - the caches and tlbs */ -void ld_mmu_sb1(void) -{ - probe_cache_sizes(); - - _clear_page = sb1_clear_page; - _copy_page = sb1_copy_page; - - _flush_cache_all = sb1_flush_cache_all; - _flush_cache_mm = sb1_flush_cache_mm; - _flush_cache_range = sb1_flush_cache_range; - _flush_cache_page = sb1_flush_cache_page; - _flush_cache_sigtramp = sb1_flush_cache_sigtramp; - - _flush_page_to_ram = sb1_flush_page_to_ram; - _flush_icache_page = sb1_flush_cache_page; - _flush_icache_range = sb1_flush_icache_range; - - - /* - * JDCXXX I'm not sure whether these are necessary: is this the right - * place to initialize the tlb? If it is, why is it done - * at this level instead of as common code in loadmmu()? - */ - flush_cache_all(); - flush_tlb_all(); - - /* Turn on caching in kseg0 */ - set_cp0_config(CONF_CM_CMASK, 0); -} diff -urN linux-2.4.18/arch/mips/mm/tlb-r3k.c linux-2.4.19-pre5/arch/mips/mm/tlb-r3k.c --- linux-2.4.18/arch/mips/mm/tlb-r3k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/tlb-r3k.c Sat Mar 30 22:55:26 2002 @@ -0,0 +1,256 @@ +/* + * r2300.c: R2000 and R3000 specific mmu/cache code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * with a lot of changes to make this thing work for R3000s + * Tx39XX R4k style caches added. HK + * Copyright (C) 1998, 1999, 2000 Harald Koerfgen + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char except_vec0_r2300; + +#undef DEBUG_TLB + +int r3k_have_wired_reg = 0; /* should be in mips_cpu? */ + +/* TLB operations. */ +void local_flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + +#ifdef DEBUG_TLB + printk("[tlball]"); +#endif + + save_and_cli(flags); + old_ctx = (get_entryhi() & 0xfc0); + write_32bit_cp0_register(CP0_ENTRYLO0, 0); +#ifdef CONFIG_CPU_TX39XX + entry = r3k_have_wired_reg ? get_wired() : 8; +#else + entry = 8; +#endif + for (; entry < mips_cpu.tlbsize; entry++) { + write_32bit_cp0_register(CP0_INDEX, entry << 8); + write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12)); + __asm__ __volatile__("tlbwi"); + } + set_entryhi(old_ctx); + restore_flags(flags); +} + +void local_flush_tlb_mm(struct mm_struct *mm) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlbmm<%lu>]", (unsigned long) mm->context); +#endif + save_and_cli(flags); + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xfc0); + restore_flags(flags); + } +} + +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags; + int size; + +#ifdef DEBUG_TLB + printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", + (mm->context & 0xfc0), start, end); +#endif + save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size <= mips_cpu.tlbsize) { + int oldpid = (get_entryhi() & 0xfc0); + int newpid = (mm->context & 0xfc0); + + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + while (start < end) { + int idx; + + set_entryhi(start | newpid); + start += PAGE_SIZE; + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entryhi(KSEG0); + if (idx < 0) + continue; + tlb_write_indexed(); + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xfc0); + } + restore_flags(flags); + } +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (!vma || vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + +#ifdef DEBUG_TLB + printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page); +#endif + newpid = (vma->vm_mm->context & 0xfc0); + page &= PAGE_MASK; + save_and_cli(flags); + oldpid = (get_entryhi() & 0xfc0); + set_entryhi(page | newpid); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entryhi(KSEG0); + if (idx < 0) + goto finish; + tlb_write_indexed(); + +finish: + set_entryhi(oldpid); + restore_flags(flags); + } +} + +void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, + pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + pid = get_entryhi() & 0xfc0; + +#ifdef DEBUG_TLB + if ((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", + (vma->vm_mm->context & 0xfc0), pid); + } +#endif + + save_and_cli(flags); + address &= PAGE_MASK; + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + tlb_probe(); + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + set_entrylo0(pte_val(*ptep)); + set_entryhi(address | (pid)); + if (idx < 0) { + tlb_write_random(); +#if 0 + printk("[MISS]"); +#endif + } else { + tlb_write_indexed(); +#if 0 + printk("[HIT]"); +#endif + } + set_entryhi(pid); + restore_flags(flags); +} + +void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + unsigned long flags; + unsigned long old_ctx; + static unsigned long wired = 0; + +#ifdef CONFIG_CPU_TX39XX + if (r3k_have_wired_reg) { + unsigned long old_pagemask; + unsigned long w; + +#ifdef DEBUG_TLB + printk("[tlbwired]"); + printk("ently lo0 %8x, hi %8x\n, pagemask %8x\n", + entrylo0, entryhi, pagemask); +#endif + save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + old_pagemask = get_pagemask(); + w = get_wired(); + set_wired (w + 1); + if (get_wired() != w + 1) { + printk("[tlbwired] No WIRED reg?\n"); + return; + } + set_index (w << 8); + set_pagemask (pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + tlb_write_indexed(); + + set_entryhi(old_ctx); + set_pagemask (old_pagemask); + local_flush_tlb_all(); + restore_flags(flags); + return; + } +#endif + + if (wired < 8) { + __save_and_cli(flags); + old_ctx = get_entryhi() & 0xfc0; + set_entrylo0(entrylo0); + set_entryhi(entryhi); + set_index(wired); + wired++; + tlb_write_indexed(); + set_entryhi(old_ctx); + local_flush_tlb_all(); + __restore_flags(flags); + } +} + +void __init r3k_tlb_init(void) +{ + local_flush_tlb_all(); + memcpy((void *)KSEG0, &except_vec0_r2300, 0x80); + flush_icache_range(KSEG0, KSEG0 + 0x80); +} diff -urN linux-2.4.18/arch/mips/mm/tlb-r4k.c linux-2.4.19-pre5/arch/mips/mm/tlb-r4k.c --- linux-2.4.18/arch/mips/mm/tlb-r4k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/tlb-r4k.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,383 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org + * + * To do: + * + * - this code is a overbloated pig + * - many of the bug workarounds are not efficient at all, but at + * least they are functional ... + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#undef DEBUG_TLB +#undef DEBUG_TLBUPDATE + +extern char except_vec0_nevada, except_vec0_r4000, except_vec0_r4600; + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +void local_flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + +#ifdef DEBUG_TLB + printk("[tlball]"); +#endif + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entrylo0(0); + set_entrylo1(0); + BARRIER; + + entry = get_wired(); + + /* Blast 'em all away. */ + while (entry < mips_cpu.tlbsize) { + /* + * Make sure all entries differ. If they're not different + * MIPS32 will take revenge ... + */ + set_entryhi(KSEG0 + entry*0x2000); + set_index(entry); + BARRIER; + tlb_write_indexed(); + BARRIER; + entry++; + } + BARRIER; + set_entryhi(old_ctx); + __restore_flags(flags); +} + +void local_flush_tlb_mm(struct mm_struct *mm) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlbmm<%d>]", mm->context); +#endif + __save_and_cli(flags); + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + __restore_flags(flags); + } +} + +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { + unsigned long flags; + int size; + +#ifdef DEBUG_TLB + printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), + start, end); +#endif + __save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if (size <= mips_cpu.tlbsize/2) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (mm->context & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while (start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0); + if (idx < 0) + continue; + BARRIER; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+idx*0x2000); + tlb_write_indexed(); + BARRIER; + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (!vma || vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); +#endif + newpid = (vma->vm_mm->context & 0xff); + page &= (PAGE_MASK << 1); + __save_and_cli(flags); + oldpid = (get_entryhi() & 0xff); + set_entryhi(page | newpid); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + if(idx < 0) + goto finish; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+idx*0x2000); + BARRIER; + tlb_write_indexed(); + + finish: + BARRIER; + set_entryhi(oldpid); + __restore_flags(flags); + } +} + +/* We will need multiple versions of update_mmu_cache(), one that just + * updates the TLB with the new pte(s), and another which also checks + * for the R4k "end of page" hardware bug and does the needy. + */ +void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, + pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + pid = get_entryhi() & 0xff; + +#ifdef DEBUG_TLB + if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (vma->vm_mm->context & 0xff), pid); + } +#endif + + __save_and_cli(flags); + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + BARRIER; + tlb_probe(); + BARRIER; + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + BARRIER; + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + BARRIER; + if (idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + BARRIER; + set_entryhi(pid); + BARRIER; + __restore_flags(flags); +} + +#if 0 +static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx; + + __save_and_cli(flags); + address &= (PAGE_MASK << 1); + set_entryhi(address | (get_entryhi() & 0xff)); + pgdp = pgd_offset(vma->vm_mm, address); + tlb_probe(); + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + BARRIER; + if (idx < 0) + tlb_write_random(); + else + tlb_write_indexed(); + BARRIER; + __restore_flags(flags); +} +#endif + +void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = get_entryhi() & 0xff; + old_pagemask = get_pagemask(); + wired = get_wired(); + set_wired(wired + 1); + set_index(wired); + BARRIER; + set_pagemask(pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask(old_pagemask); + local_flush_tlb_all(); + __restore_flags(flags); +} + +/* + * Used for loading TLB entries before trap_init() has started, when we + * don't actually want to add a wired entry which remains throughout the + * lifetime of the system + */ + +static int temp_tlb_entry __initdata; + +__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + int ret = 0; + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = get_entryhi() & 0xff; + old_pagemask = get_pagemask(); + wired = get_wired(); + if (--temp_tlb_entry < wired) { + printk(KERN_WARNING "No TLB space left for add_temporary_entry\n"); + ret = -ENOSPC; + goto out; + } + + set_index(temp_tlb_entry); + BARRIER; + set_pagemask(pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask(old_pagemask); +out: + __restore_flags(flags); + return ret; +} + +static void __init probe_tlb(unsigned long config) +{ + unsigned int prid, config1; + + prid = read_32bit_cp0_register(CP0_PRID) & 0xff00; + if (prid == PRID_IMP_RM7000 || !(config & (1 << 31))) + /* + * Not a MIPS32 complianant CPU. Config 1 register not + * supported, we assume R4k style. Cpu probing already figured + * out the number of tlb entries. + */ + return; + + config1 = read_mips32_cp0_config1(); + if (!((config >> 7) & 3)) + panic("No MMU present"); + else + mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1; +} + +void __init r4k_tlb_init(void) +{ + u32 config = read_32bit_cp0_register(CP0_CONFIG); + + /* + * You should never change this register: + * - On R4600 1.7 the tlbp never hits for pages smaller than + * the value in the c0_pagemask register. + * - The entire mm handling assumes the c0_pagemask register to + * be set for 4kb pages. + */ + probe_tlb(config); + set_pagemask(PM_4K); + write_32bit_cp0_register(CP0_WIRED, 0); + temp_tlb_entry = mips_cpu.tlbsize - 1; + local_flush_tlb_all(); + + if ((mips_cpu.options & MIPS_CPU_4KEX) + && (mips_cpu.options & MIPS_CPU_4KTLB)) { + if (mips_cpu.cputype == CPU_NEVADA) + memcpy((void *)KSEG0, &except_vec0_nevada, 0x80); + else if (mips_cpu.cputype == CPU_R4600) + memcpy((void *)KSEG0, &except_vec0_r4600, 0x80); + else + memcpy((void *)KSEG0, &except_vec0_r4000, 0x80); + flush_icache_range(KSEG0, KSEG0 + 0x80); + } +} diff -urN linux-2.4.18/arch/mips/mm/tlb-sb1.c linux-2.4.19-pre5/arch/mips/mm/tlb-sb1.c --- linux-2.4.18/arch/mips/mm/tlb-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/tlb-sb1.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,307 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include + +extern char except_vec0_r4000[]; + +/* Dump the current entry* and pagemask registers */ +static inline void dump_cur_tlb_regs(void) +{ + unsigned int entryhihi, entryhilo, entrylo0hi, entrylo0lo, entrylo1hi; + unsigned int entrylo1lo, pagemask; + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set mips64 \n" + ".set noat \n" + " tlbr \n" + " dmfc0 $1, $10 \n" + " dsrl32 %0, $1, 0 \n" + " sra %1, $1, 0 \n" + " dmfc0 $1, $2 \n" + " dsrl32 %2, $1, 0 \n" + " sra %3, $1, 0 \n" + " dmfc0 $1, $3 \n" + " dsrl32 %4, $1, 0 \n" + " sra %5, $1, 0 \n" + " mfc0 %6, $5 \n" + ".set pop \n" + : "=r" (entryhihi), + "=r" (entryhilo), + "=r" (entrylo0hi), + "=r" (entrylo0lo), + "=r" (entrylo1hi), + "=r" (entrylo1lo), + "=r" (pagemask)); + printk("%08X%08X %08X%08X %08X%08X %08X", + entryhihi, entryhilo, + entrylo0hi, entrylo0lo, + entrylo1hi, entrylo1lo, + pagemask); +} + +void sb1_dump_tlb(void) +{ + int entry; + printk("Current TLB registers state:\n" + " EntryHi EntryLo0 EntryLo1 PageMask Index\n" + "--------------------------------------------------------------------\n"); + dump_cur_tlb_regs(); + printk(" %08X\n", read_32bit_cp0_register(CP0_INDEX)); + printk("\n\nFull TLB Dump:" + "Idx EntryHi EntryLo0 EntryLo1 PageMask\n" + "--------------------------------------------------------------\n"); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + set_index(entry); + printk("\n%02i ", entry); + __asm__ __volatile__ ( + ".set push \n" + ".set mips64 \n" + " tlbr \n" + ".set pop \n"); + dump_cur_tlb_regs(); + } + printk("\n"); +} + +void local_flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entrylo0(0); + set_entrylo1(0); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry); + set_index(entry); + tlb_write_indexed(); + } + set_entryhi(old_ctx); + __restore_flags(flags); +} + + +/* + * Use a bogus region of memory (starting at 0) to sanitize the TLB's. + * Use increments of the maximum page size (16MB), and check for duplicate + * entries before doing a given write. Then, when we're safe from collisions + * with the firmware, go back and give all the entries invalid addresses with + * the normal flush routine. + */ +void sb1_sanitize_tlb(void) +{ + int entry; + long addr = 0; + + long inc = 1<<24; /* 16MB */ + /* Save old context and create impossible VPN2 value */ + set_entrylo0(0); + set_entrylo1(0); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + do { + addr += inc; + set_entryhi(addr); + tlb_probe(); + } while ((int)(get_index()) >= 0); + set_index(entry); + tlb_write_indexed(); + } + /* Now that we know we're safe from collisions, we can safely flush + the TLB with the "normal" routine. */ + local_flush_tlb_all(); +} + + +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + unsigned long flags; + int cpu; + + __save_and_cli(flags); + cpu = smp_processor_id(); + if(CPU_CONTEXT(cpu, mm) != 0) { + int size; + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if(size <= (mips_cpu.tlbsize/2)) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (CPU_CONTEXT(cpu, mm) & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0 + (idx << (PAGE_SHIFT+1))); + if(idx < 0) + continue; + tlb_write_indexed(); + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, cpu); + if (mm == current->active_mm) + set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff); + } + } + __restore_flags(flags); +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long flags; + +#ifdef CONFIG_SMP + /* + * This variable is eliminated from CPU_CONTEXT() if SMP isn't defined, + * so conditional it to get rid of silly "unused variable" compiler + * complaints + */ + int cpu = smp_processor_id(); +#endif + + __save_and_cli(flags); + if (CPU_CONTEXT(cpu, vma->vm_mm) != 0) { + int oldpid, newpid, idx; +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", CPU_CONTEXT(cpu, vma->vm_mm), page); +#endif + newpid = (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff); + page &= (PAGE_MASK << 1); + oldpid = (get_entryhi() & 0xff); + set_entryhi (page | newpid); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + if(idx < 0) + goto finish; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1))); + tlb_write_indexed(); + finish: + set_entryhi(oldpid); + } + __restore_flags(flags); +} + + +/* All entries common to a mm share an asid. To effectively flush + these entries, we just bump the asid. */ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + unsigned long flags; + int cpu; + __save_and_cli(flags); + cpu = smp_processor_id(); + if (CPU_CONTEXT(cpu, mm) != 0) { + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) { + set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff); + } + } + __restore_flags(flags); +} + +/* Stolen from mips32 routines */ + +void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, + pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + __save_and_cli(flags); + + + pid = get_entryhi() & 0xff; + +#ifdef DEBUG_TLB + if((pid != (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff)) || (CPU_CONTEXT(cpu, vma->vm_mm) == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff), pid); + } +#endif + + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + tlb_probe(); + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + if(idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + set_entryhi(pid); + __restore_flags(flags); +} + +/* + * This is called from loadmmu.c. We have to set up all the + * memory management function pointers, as well as initialize + * the caches and tlbs + */ +void sb1_tlb_init(void) +{ + u32 config1; + + config1 = read_mips32_cp0_config1(); + mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1; + + /* + * We don't know what state the firmware left the TLB's in, so this is + * the ultra-conservative way to flush the TLB's and avoid machine + * check exceptions due to duplicate TLB entries + */ + sb1_sanitize_tlb(); + + memcpy((void *)KSEG0, except_vec0_r4000, 0x80); + flush_icache_range(KSEG0, KSEG0 + 0x80); +} diff -urN linux-2.4.18/arch/mips/mm/tlbex-r3k.S linux-2.4.19-pre5/arch/mips/mm/tlbex-r3k.S --- linux-2.4.18/arch/mips/mm/tlbex-r3k.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/tlbex-r3k.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,226 @@ +/* + * TLB exception handling code for R2000/R3000. + * + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse + * + * Multi-CPU abstraction reworking: + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Further modifications to make this work: + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov + * Copyright (c) 2001 Ralf Baechle + * Copyright (c) 2001 MIPS Technologies, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TLB_OPTIMIZE /* If you are paranoid, disable this. */ + + .text + .set mips1 + .set noreorder + + __INIT + + /* TLB refill, R[23]00 version */ + LEAF(except_vec0_r2300) + .set noat + .set mips1 + mfc0 k0, CP0_BADVADDR + lw k1, pgd_current # get pgd pointer + srl k0, k0, 22 + sll k0, k0, 2 + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) + and k0, k0, 0xffc + addu k1, k1, k0 + lw k0, (k1) + nop + mtc0 k0, CP0_ENTRYLO0 + mfc0 k1, CP0_EPC + tlbwr + jr k1 + rfe + END(except_vec0_r2300) + + __FINIT + + /* ABUSE of CPP macros 101. */ + + /* After this macro runs, the pte faulted on is + * in register PTE, a ptr into the table in which + * the pte belongs is in PTR. + */ +#define LOAD_PTE(pte, ptr) \ + mfc0 pte, CP0_BADVADDR; \ + lw ptr, pgd_current; \ + srl pte, pte, 22; \ + sll pte, pte, 2; \ + addu ptr, ptr, pte; \ + mfc0 pte, CP0_CONTEXT; \ + lw ptr, (ptr); \ + andi pte, pte, 0xffc; \ + addu ptr, ptr, pte; \ + lw pte, (ptr); \ + nop; + + /* This places the even/odd pte pair in the page + * table at PTR into ENTRYLO0 and ENTRYLO1 using + * TMP as a scratch register. + */ +#define PTE_RELOAD(ptr) \ + lw ptr, (ptr) ; \ + nop ; \ + mtc0 ptr, CP0_ENTRYLO0; \ + nop; + +#define DO_FAULT(write) \ + .set noat; \ + .set macro; \ + SAVE_ALL; \ + mfc0 a2, CP0_BADVADDR; \ + STI; \ + .set at; \ + move a0, sp; \ + jal do_page_fault; \ + li a1, write; \ + j ret_from_exception; \ + nop; \ + .set noat; \ + .set nomacro; + + /* Check is PTE is present, if not then jump to LABEL. + * PTR points to the page table where this PTE is located, + * when the macro is done executing PTE will be restored + * with it's original value. + */ +#define PTE_PRESENT(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + bnez pte, label; \ + .set push; \ + .set reorder; \ + lw pte, (ptr); \ + .set pop; + + /* Make PTE valid, store result in PTR. */ +#define PTE_MAKEVALID(pte, ptr) \ + ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ + sw pte, (ptr); + + /* Check if PTE can be written to, if not branch to LABEL. + * Regardless restore PTE with value from PTR when done. + */ +#define PTE_WRITABLE(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + bnez pte, label; \ + .set push; \ + .set reorder; \ + lw pte, (ptr); \ + .set pop; + + + /* Make PTE writable, update software status bits as well, + * then store at PTR. + */ +#define PTE_MAKEWRITE(pte, ptr) \ + ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ + _PAGE_VALID | _PAGE_DIRTY); \ + sw pte, (ptr); + +/* + * The index register may have the probe fail bit set, + * because we would trap on access kseg2, i.e. without refill. + */ +#define TLB_WRITE(reg) \ + mfc0 reg, CP0_INDEX; \ + nop; \ + bltz reg, 1f; \ + nop; \ + tlbwi; \ + j 2f; \ + nop; \ +1: tlbwr; \ +2: + +#define RET(reg) \ + mfc0 reg, CP0_EPC; \ + nop; \ + jr reg; \ + rfe + + .set noreorder + + .align 5 +NESTED(handle_tlbl, PT_SIZE, sp) + .set noat + +#ifdef TLB_OPTIMIZE + /* Test present bit in entry. */ + LOAD_PTE(k0, k1) + tlbp + PTE_PRESENT(k0, k1, nopage_tlbl) + PTE_MAKEVALID(k0, k1) + PTE_RELOAD(k1) + TLB_WRITE(k0) + RET(k0) +nopage_tlbl: +#endif + + DO_FAULT(0) +END(handle_tlbl) + +NESTED(handle_tlbs, PT_SIZE, sp) + .set noat + +#ifdef TLB_OPTIMIZE + LOAD_PTE(k0, k1) + tlbp # find faulting entry + PTE_WRITABLE(k0, k1, nopage_tlbs) + PTE_MAKEWRITE(k0, k1) + PTE_RELOAD(k1) + TLB_WRITE(k0) + RET(k0) +nopage_tlbs: +#endif + + DO_FAULT(1) +END(handle_tlbs) + + .align 5 +NESTED(handle_mod, PT_SIZE, sp) + .set noat +#ifdef TLB_OPTIMIZE + LOAD_PTE(k0, k1) + tlbp # find faulting entry + andi k0, k0, _PAGE_WRITE + beqz k0, nowrite_mod + .set push + .set reorder + lw k0, (k1) + .set pop + + /* Present and writable bits set, set accessed and dirty bits. */ + PTE_MAKEWRITE(k0, k1) + + /* Now reload the entry into the tlb. */ + PTE_RELOAD(k1) + tlbwi + RET(k0) +#endif + +nowrite_mod: + DO_FAULT(1) +END(handle_mod) diff -urN linux-2.4.18/arch/mips/mm/tlbex-r4k.S linux-2.4.19-pre5/arch/mips/mm/tlbex-r4k.S --- linux-2.4.18/arch/mips/mm/tlbex-r4k.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/mm/tlbex-r4k.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,709 @@ +/* + * TLB exception handling code for r4k. + * + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse + * + * Multi-cpu abstraction and reworking: + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TLB_OPTIMIZE /* If you are paranoid, disable this. */ + +#ifdef CONFIG_64BIT_PHYS_ADDR +#define PTE_L ld +#define PTE_S sd +#define PTE_SRL dsrl +#define P_MTC0 dmtc0 +#define PTE_SIZE 8 +#define PTEP_INDX_MSK 0xff0 +#define PTE_INDX_MSK 0xff8 +#define PTE_INDX_SHIFT 9 +#else +#define PTE_L lw +#define PTE_S sw +#define PTE_SRL srl +#define P_MTC0 mtc0 +#define PTE_SIZE 4 +#define PTEP_INDX_MSK 0xff8 +#define PTE_INDX_MSK 0xffc +#define PTE_INDX_SHIFT 10 +#endif + + __INIT + +#ifdef CONFIG_64BIT_PHYS_ADDR +#define GET_PTE_OFF(reg) +#elif CONFIG_CPU_VR41XX +#define GET_PTE_OFF(reg) srl reg, reg, 3 +#else +#define GET_PTE_OFF(reg) srl reg, reg, 1 +#endif + +/* + * These handlers much be written in a relocatable manner + * because based upon the cpu type an arbitrary one of the + * following pieces of code will be copied to the KSEG0 + * vector location. + */ + /* TLB refill, EXL == 0, R4xx0, non-R4600 version */ + .set noreorder + .set noat + LEAF(except_vec0_r4000) + .set mips3 +#ifdef CONFIG_SMP + mfc0 k1, CP0_CONTEXT + la k0, pgd_current + srl k1, 23 + sll k1, 2 # log2(sizeof(pgd_t) + addu k1, k0, k1 + lw k1, (k1) +#else + lw k1, pgd_current # get pgd pointer +#endif + mfc0 k0, CP0_BADVADDR # Get faulting address + srl k0, k0, PGDIR_SHIFT # get pgd only bits + + sll k0, k0, 2 + addu k1, k1, k0 # add in pgd offset + mfc0 k0, CP0_CONTEXT # get context reg + lw k1, (k1) + GET_PTE_OFF(k0) # get pte offset + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 # add in offset + PTE_L k0, 0(k1) # get even pte + PTE_L k1, PTE_SIZE(k1) # get odd pte + PTE_SRL k0, k0, 6 # convert to entrylo0 + P_MTC0 k0, CP0_ENTRYLO0 # load it + PTE_SRL k1, k1, 6 # convert to entrylo1 + P_MTC0 k1, CP0_ENTRYLO1 # load it + b 1f + tlbwr # write random tlb entry +1: + nop + eret # return from trap + END(except_vec0_r4000) + + /* TLB refill, EXL == 0, R4600 version */ + LEAF(except_vec0_r4600) + .set mips3 + mfc0 k0, CP0_BADVADDR + srl k0, k0, PGDIR_SHIFT + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 + PTE_L k0, 0(k1) + PTE_L k1, PTE_SIZE(k1) + PTE_SRL k0, k0, 6 + P_MTC0 k0, CP0_ENTRYLO0 + PTE_SRL k1, k1, 6 + P_MTC0 k1, CP0_ENTRYLO1 + nop + tlbwr + nop + eret + END(except_vec0_r4600) + + /* TLB refill, EXL == 0, R52x0 "Nevada" version */ + /* + * This version has a bug workaround for the Nevada. It seems + * as if under certain circumstances the move from cp0_context + * might produce a bogus result when the mfc0 instruction and + * it's consumer are in a different cacheline or a load instruction, + * probably any memory reference, is between them. This is + * potencially slower than the R4000 version, so we use this + * special version. + */ + .set noreorder + .set noat + LEAF(except_vec0_nevada) + .set mips3 + mfc0 k0, CP0_BADVADDR # Get faulting address + srl k0, k0, PGDIR_SHIFT # get pgd only bits + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 # add in pgd offset + lw k1, (k1) + mfc0 k0, CP0_CONTEXT # get context reg +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 # get pte offset +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 # add in offset + PTE_L k0, 0(k1) # get even pte + PTE_L k1, PTE_SIZE(k1) # get odd pte + PTE_SRL k0, k0, 6 # convert to entrylo0 + P_MTC0 k0, CP0_ENTRYLO0 # load it + PTE_SRL k1, k1, 6 # convert to entrylo1 + P_MTC0 k1, CP0_ENTRYLO1 # load it + nop # QED specified nops + nop + tlbwr # write random tlb entry + nop # traditional nop + eret # return from trap + END(except_vec0_nevada) + + /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */ + LEAF(except_vec0_r45k_bvahwbug) + .set mips3 + mfc0 k0, CP0_BADVADDR + srl k0, k0, PGDIR_SHIFT + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 + PTE_L k0, 0(k1) + PTE_L k1, PTE_SIZE(k1) + nop /* XXX */ + tlbp + PTE_SRL k0, k0, 6 + P_MTC0 k0, CP0_ENTRYLO0 + PTE_SRL k1, k1, 6 + mfc0 k0, CP0_INDEX + P_MTC0 k1, CP0_ENTRYLO1 + bltzl k0, 1f + tlbwr +1: + nop + eret + END(except_vec0_r45k_bvahwbug) + +#ifdef CONFIG_SMP + /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */ + LEAF(except_vec0_r4k_mphwbug) + .set mips3 + mfc0 k0, CP0_BADVADDR + srl k0, k0, PGDIR_SHIFT + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 + PTE_L k0, 0(k1) + PTE_L k1, PTE_SIZE(k1) + nop /* XXX */ + tlbp + PTE_SRL k0, k0, 6 + P_MTC0 k0, CP0_ENTRYLO0 + PTE_SRL k1, k1, 6 + mfc0 k0, CP0_INDEX + P_MTC0 k1, CP0_ENTRYLO1 + bltzl k0, 1f + tlbwr +1: + nop + eret + END(except_vec0_r4k_mphwbug) +#endif + + /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */ + LEAF(except_vec0_r4k_250MHZhwbug) + .set mips3 + mfc0 k0, CP0_BADVADDR + srl k0, k0, PGDIR_SHIFT + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 + PTE_L k0, 0(k1) + PTE_L k1, PTE_SIZE(k1) + PTE_SRL k0, k0, 6 + P_MTC0 zero, CP0_ENTRYLO0 + P_MTC0 k0, CP0_ENTRYLO0 + PTE_SRL k1, k1, 6 + P_MTC0 zero, CP0_ENTRYLO1 + P_MTC0 k1, CP0_ENTRYLO1 + b 1f + tlbwr +1: + nop + eret + END(except_vec0_r4k_250MHZhwbug) + +#ifdef CONFIG_SMP + /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */ + LEAF(except_vec0_r4k_MP250MHZhwbug) + .set mips3 + mfc0 k0, CP0_BADVADDR + srl k0, k0, PGDIR_SHIFT + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 + mfc0 k0, CP0_CONTEXT + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 + PTE_L k0, 0(k1) + PTE_L k1, PTE_SIZE(k1) + nop /* XXX */ + tlbp + PTE_SRL k0, k0, 6 + P_MTC0 zero, CP0_ENTRYLO0 + P_MTC0 k0, CP0_ENTRYLO0 + mfc0 k0, CP0_INDEX + PTE_SRL k1, k1, 6 + P_MTC0 zero, CP0_ENTRYLO1 + P_MTC0 k1, CP0_ENTRYLO1 + bltzl k0, 1f + tlbwr +1: + nop + eret + END(except_vec0_r4k_MP250MHZhwbug) +#endif + +#ifdef CONFIG_MIPS_AU1000 + /* TLB refill, EXL == 0, Au1000 version */ + /* we'll worry about smp later */ + .set noreorder + .set noat + LEAF(except_vec0_au1000) + .set mips3 + mfc0 k0, CP0_BADVADDR # Get faulting address + srl k0, k0, PGDIR_SHIFT # get pgd only bits + lw k1, pgd_current # get pgd pointer + sll k0, k0, 2 # log2(sizeof(pgd_t) + addu k1, k1, k0 # add in pgd offset + mfc0 k0, CP0_CONTEXT # get context reg + lw k1, (k1) +#ifndef CONFIG_64BIT_PHYS_ADDR + srl k0, k0, 1 # get pte offset +#endif + and k0, k0, PTEP_INDX_MSK + addu k1, k1, k0 # add in offset + j translate_pte + nop + END(except_vec0_au1000) +#endif + + + __FINIT + +/* + * ABUSE of CPP macros 101. + * + * After this macro runs, the pte faulted on is + * in register PTE, a ptr into the table in which + * the pte belongs is in PTR. + */ + +#ifdef CONFIG_SMP +#define GET_PGD(scratch, ptr) \ + mfc0 ptr, CP0_CONTEXT; \ + la scratch, pgd_current;\ + srl ptr, 23; \ + sll ptr, 2; \ + addu ptr, scratch, ptr; \ + lw ptr, (ptr); +#else +#define GET_PGD(scratch, ptr) \ + lw ptr, pgd_current; +#endif + +#define LOAD_PTE(pte, ptr) \ + GET_PGD(pte, ptr) \ + mfc0 pte, CP0_BADVADDR; \ + srl pte, pte, PGDIR_SHIFT; \ + sll pte, pte, 2; \ + addu ptr, ptr, pte; \ + mfc0 pte, CP0_BADVADDR; \ + lw ptr, (ptr); \ + srl pte, pte, PTE_INDX_SHIFT; \ + and pte, pte, PTE_INDX_MSK; \ + addu ptr, ptr, pte; \ + PTE_L pte, (ptr); + + /* This places the even/odd pte pair in the page + * table at PTR into ENTRYLO0 and ENTRYLO1 using + * TMP as a scratch register. + */ +#define PTE_RELOAD(ptr, tmp) \ + ori ptr, ptr, PTE_SIZE; \ + xori ptr, ptr, PTE_SIZE; \ + PTE_L tmp, PTE_SIZE(ptr); \ + PTE_L ptr, 0(ptr); \ + PTE_SRL tmp, tmp, 6; \ + P_MTC0 tmp, CP0_ENTRYLO1; \ + PTE_SRL ptr, ptr, 6; \ + P_MTC0 ptr, CP0_ENTRYLO0; + +#define DO_FAULT(write) \ + .set noat; \ + SAVE_ALL; \ + mfc0 a2, CP0_BADVADDR; \ + STI; \ + .set at; \ + move a0, sp; \ + jal do_page_fault; \ + li a1, write; \ + j ret_from_exception; \ + nop; \ + .set noat; + + /* Check is PTE is present, if not then jump to LABEL. + * PTR points to the page table where this PTE is located, + * when the macro is done executing PTE will be restored + * with it's original value. + */ +#define PTE_PRESENT(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + bnez pte, label; \ + PTE_L pte, (ptr); + + /* Make PTE valid, store result in PTR. */ +#define PTE_MAKEVALID(pte, ptr) \ + ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ + PTE_S pte, (ptr); + + /* Check if PTE can be written to, if not branch to LABEL. + * Regardless restore PTE with value from PTR when done. + */ +#define PTE_WRITABLE(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + bnez pte, label; \ + PTE_L pte, (ptr); + + /* Make PTE writable, update software status bits as well, + * then store at PTR. + */ +#define PTE_MAKEWRITE(pte, ptr) \ + ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ + _PAGE_VALID | _PAGE_DIRTY); \ + PTE_S pte, (ptr); + + .set noreorder + +/* + * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0: + * 2. A timing hazard exists for the TLBP instruction. + * + * stalling_instruction + * TLBP + * + * The JTLB is being read for the TLBP throughout the stall generated by the + * previous instruction. This is not really correct as the stalling instruction + * can modify the address used to access the JTLB. The failure symptom is that + * the TLBP instruction will use an address created for the stalling instruction + * and not the address held in C0_ENHI and thus report the wrong results. + * + * The software work-around is to not allow the instruction preceding the TLBP + * to stall - make it an NOP or some other instruction guaranteed not to stall. + * + * Errata 2 will not be fixed. This errata is also on the R5000. + * + * As if we MIPS hackers wouldn't know how to nop pipelines happy ... + */ +#define R5K_HAZARD nop + + /* + * Note for many R4k variants tlb probes cannot be executed out + * of the instruction cache else you get bogus results. + */ + .align 5 + NESTED(handle_tlbl, PT_SIZE, sp) + .set noat +invalid_tlbl: +#ifdef TLB_OPTIMIZE + /* Test present bit in entry. */ + LOAD_PTE(k0, k1) + R5K_HAZARD + tlbp + PTE_PRESENT(k0, k1, nopage_tlbl) + PTE_MAKEVALID(k0, k1) + PTE_RELOAD(k1, k0) + nop + b 1f + tlbwi +1: + nop + .set mips3 + eret + .set mips0 +#endif + +nopage_tlbl: + DO_FAULT(0) + END(handle_tlbl) + + .align 5 + NESTED(handle_tlbs, PT_SIZE, sp) + .set noat +#ifdef TLB_OPTIMIZE + .set mips3 + li k0,0 + LOAD_PTE(k0, k1) + R5K_HAZARD + tlbp # find faulting entry + PTE_WRITABLE(k0, k1, nopage_tlbs) + PTE_MAKEWRITE(k0, k1) + PTE_RELOAD(k1, k0) + nop + b 1f + tlbwi +1: + nop + .set mips3 + eret + .set mips0 +#endif + +nopage_tlbs: + DO_FAULT(1) + END(handle_tlbs) + + .align 5 + NESTED(handle_mod, PT_SIZE, sp) + .set noat +#ifdef TLB_OPTIMIZE + .set mips3 + LOAD_PTE(k0, k1) + R5K_HAZARD + tlbp # find faulting entry + andi k0, k0, _PAGE_WRITE + beqz k0, nowrite_mod + PTE_L k0, (k1) + + /* Present and writable bits set, set accessed and dirty bits. */ + PTE_MAKEWRITE(k0, k1) + + /* Now reload the entry into the tlb. */ + PTE_RELOAD(k1, k0) + nop + b 1f + tlbwi +1: + nop + .set mips3 + eret + .set mips0 +#endif + +nowrite_mod: + DO_FAULT(1) + END(handle_mod) + +#ifdef CONFIG_MIPS_AU1000 + +#ifdef CONFIG_MIPS_PB1500 +#define PSEUDO_ADDR_BASE 0x20000000 +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define PSEUDO_ADDR_BASE 0xC0000000 +#endif + +/* + * On entry k0 contains the pte with the pseudo address. + * On exit, k0 contains the "real" address, which is a + * 36 bit physicall address. + * This function is called only after it has been + * determined that the pte is a pseudo physical address. + * + * Destroys k0, k1, and at. It's assumed that the calling + * function will preserve those. + */ +LEAF(get_real_pte) + .set mips3 + .set at + + li k1, 0xe0000000 # check lcd + bltu k0, k1, check_pcmcia_socket_1 + nop + # lcd pseudo access + li k1, 0x0fffffff + and k0, k0, k1 # get offset +#ifdef CONFIG_MIPS_PB1500 + lui k1, 0x1b00 + addu k0, k0, k1 +#endif + srl k0, k0, 6 + lui k1, 0xe000>>2 + or k0, k0, k1 + j ra + nop +check_pcmcia_socket_1: + li k1, 0xD0000000 + bltu k0, k1, pcmcia_socket_0 + nop + # famous last words, should not happen ... +1: + b 1b # fixme -- to something a little more useful + # pcmcia socket 1 pseudo access + +pcmcia_socket_0: + # check mem access + li k1, 0xC8000000 + bltu k0, k1, check_attr + # handle pseudo memory access + li k1, 0x00ffffff + and k1, k0, k1 # get access offset + lui k0, 0x8000 + or k0, k0, k1 + # now we have the correct even pte ... bits 31:0 + srl k0, k0, 6 + lui k1, 0xf000>>2 + or k0, k0, k1 + j ra # done + nop +check_attr: + li k1, 0xC4000000 + bltu k0, k1, io_access + # handle pseudo attribute access + li k1, 0x00ffffff + and k1, k0, k1 # get access offset + lui k0, 0x4000 + or k0, k0, k1 + # now we have the correct even pte ... bits 31:0 + srl k0, k0, 6 + lui k1, 0xf000>>2 + or k0, k0, k1 + j ra # done + nop +io_access: +#ifdef CONFIG_MIPS_PB1500 + li k1, 0xC0000000 + bltu k0, k1, pci_access +#endif + # handle pseudo io access + li k1, 0x00ffffff + and k0, k0, k1 # get access offset + # now we have the correct even pte ... bits 31:0 + srl k0, k0, 6 + lui k1, 0xf000>>2 + or k0, k0, k1 + j ra # done + nop +#ifdef CONFIG_MIPS_PB1500 +pci_access: + li k1, 0x80000000 + bltu k0, k1, pci_io_access + lui k1, 0x4000>>2 + # handle pseudo pci mem access + srl k0, k0, 6 + or k0, k0, k1 + j ra # done + nop +pci_io_access: + li k1, 0x70000000 + bltu k0, k1, pci_cfg_access + lui k1, 0x5000>>2 + # handle pseudo pci io access + srl k0, k0, 6 + or k0, k0, k1 + j ra # done + nop +pci_cfg_access: + # handle pseudo pci ext cfg access + li k1, 0x0fffffff + and k0, k0, k1 # get access offset + srl k0, k0, 6 + lui k1, 0x6000>>2 + or k0, k0, k1 + j ra # done + nop +#endif + .set noat +END(get_real_pte) + +/* + * On entry k1 contains pte pointer. Clobbers only k0 and k1. + */ + LEAF(translate_pte) + .set mips3 + lui k0, %hi(__saved_at) + .set noat + sw $at, %lo(__saved_at)(k0) # save at + .set at + sw k1, %lo(__saved_pte)(k0) # save pte pointer + sw ra, %lo(__saved_ra)(k0) # save ra + lw k0, 0(k1) # get even pte + + li k1, PSEUDO_ADDR_BASE # check pseudo addr + bltu k0, k1, 1f + nop + bal get_real_pte + nop + b 2f + nop +1: + srl k0, k0, 6 +2: + mtc0 k0, CP0_ENTRYLO0 # load it + + lui k1, %hi(__saved_pte) + lw k1, %lo(__saved_pte)(k1) # recover pte pointer + lw k0, 4(k1) # get odd pte + + li k1, PSEUDO_ADDR_BASE # check pseudo addr + bltu k0, k1, 1f + nop + bal get_real_pte + nop + b 2f + nop + +1: + srl k0, k0, 6 # convert to entrylo0 +2: + mtc0 k0, CP0_ENTRYLO1 # load it + nop + b 1f + tlbwr # write random tlb entry +1: + lui k0, %hi(__saved_at) + .set noat + lw $at, %lo(__saved_at)(k0) # restore at + .set at + lw ra, %lo(__saved_ra)(k0) # restore ra + eret # return from trap + .set noat + END(translate_pte) + +__saved_at: PTR 0 +__saved_pte: PTR 0 +__saved_ra: PTR 0 +#endif diff -urN linux-2.4.18/arch/mips/mm/umap.c linux-2.4.19-pre5/arch/mips/mm/umap.c --- linux-2.4.18/arch/mips/mm/umap.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/mm/umap.c Sat Mar 30 22:55:27 2002 @@ -101,7 +101,7 @@ start = (start + PGDIR_SIZE) & PGDIR_MASK; dir++; } - flush_tlb_range (task->mm, beg, end); + local_flush_tlb_range (task->mm, beg, end); up_write (&task->mm->mmap_sem); } @@ -213,6 +213,6 @@ from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } - flush_tlb_range(current->mm, beg, end); + local_flush_tlb_range(current->mm, beg, end); return error; } diff -urN linux-2.4.18/arch/mips/philips/nino/Makefile linux-2.4.19-pre5/arch/mips/philips/nino/Makefile --- linux-2.4.18/arch/mips/philips/nino/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/Makefile Sat Mar 30 22:55:27 2002 @@ -11,21 +11,13 @@ .S.o: $(CC) $(AFLAGS) -c $< -o $@ -O_TARGET := nino.o +O_TARGET := nino.o all: nino.o -obj-y := int-handler.o setup.o irq.o time.o reset.o rtc.o prom.o power.o +obj-y := int-handler.o irq.o setup.o prom.o power.o int-handler.o: int-handler.S - -obj-$(CONFIG_REMOTE_DEBUG) += kgdb.o - -obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o - -ramdisk.o: - $(MAKE) -C ramdisk - mv ramdisk/ramdisk.o ramdisk.o clean: rm -f *.o diff -urN linux-2.4.18/arch/mips/philips/nino/TODO linux-2.4.19-pre5/arch/mips/philips/nino/TODO --- linux-2.4.18/arch/mips/philips/nino/TODO Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/philips/nino/TODO Sat Mar 30 22:55:27 2002 @@ -0,0 +1,18 @@ +This is a basic TODO list for the Philips Nino porting effort. Things +will be added and removed from time to time. Pick an item and help +me out! Thanks! + +- COMPACTFLASH + * get IDE/PCMCIA chip interface working to read flash cards and the + ethernet card +- FRAMEBUFFER + * complete rewrite to match new framebuffer API + * get 2bpp and 4bpp working (use Microwindows driver examples) +- GPIO + * go through all the interrupt sources in status registers 1-5 + and see what all the different IO pins are hooked to +- KGDB + * get stub working +- MMU + * Use CONFIG_CPU_TX39XX instead of current CONFIG_CPU_R3000 and + start using 3912 specific MMU management. diff -urN linux-2.4.18/arch/mips/philips/nino/int-handler.S linux-2.4.19-pre5/arch/mips/philips/nino/int-handler.S --- linux-2.4.18/arch/mips/philips/nino/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/int-handler.S Sat Mar 30 22:55:27 2002 @@ -1,137 +1,66 @@ /* - * linux/arch/mips/philips/nino/int-handler.S + * arch/mips/philips/nino/int-handler.S * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick (jim@jimpick.com) * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Interrupt handler for Philips Nino. + * Interrupt exception dispatch code for Philips Nino */ #include -#include #include +#include #include -#include - - .data - .globl HighPriVect - -HighPriVect: .word spurious # Reserved - .word io_posnegint0 # IOPOSINT(0) or IONEGINT(0) - .word spurious # CHIDMACNTINT - .word spurious # TELDMACNTINT - .word spurious # SNDDMACNTINT - .word spurious # Reserved - .word io_negint56 # IONEGINT(6) or IONEGINT(5) - .word spurious # Reserved - .word io_posint56 # IOPOSINT(6) or IOPOSINT(5) - .word spurious # Reserved - .word spurious # UARTBRXINT - .word uarta_rx # UARTARXINT - .word spurious # Reserved - .word periodic_timer # PERINT - .word spurious # ALARMINT - .word spurious # POSPWROKINT or NEGPWROKINT - -/* - * Here is the entry point to handle all interrupts. - */ - .text - .set noreorder - .align 5 - NESTED(nino_handle_int, PT_SIZE, ra) - .set noat - SAVE_ALL - CLI - .set at - - /* - * Get pending Interrupts - */ - mfc0 t0, CP0_CAUSE # Get pending interrupts - andi t2, t0, IE_IRQ4 # IRQ4 (high priority) - bne t2, IE_IRQ4, low_priority - nop - -/* - * Ok, we've got a high priority interrupt (a.k.a. an external interrupt). - * Read Interrupt Status Register 6 to get vector. - */ -high_priority: - lui t0, %hi(IntStatus6) - lw t1, %lo(IntStatus6)(t0) - andi t1, INT6_INTVECT - la t2, HighPriVect - addu t1, t1, t2 - lw t2, 0(t1) - jr t2 - nop - -/* - * Ok, we've got one of over a hundred other interupts. - */ -low_priority: - lui t0, %hi(IntStatus1) - lw t1, %lo(IntStatus1)(t0) - j handle_it - li a0, 20 - -/* - * We don't currently handle spurious interrupts. - */ -spurious: - j spurious_interrupt - nop - -/* - * We have the IRQ number, dispatch to the real handler. - */ -handle_it: jal do_IRQ - move a1,sp - j ret_from_irq - nop - -/************************************ - * High priority interrupt mappings * - ************************************/ - -/* - * Periodic timer - IRQ 0 - */ -periodic_timer: - j handle_it - li a0, 0 - -/* - * UARTA RX - IRQ 3 - */ -uarta_rx: - j handle_it - li a0, 3 - -/* - * GPIO Pin 0 transition - IRQ 10 - */ -io_posnegint0: - j handle_it - li a0, 10 - -/* - * GPIO Pin 5 or 6 transition (0-to-1) - IRQ 11 - */ -io_posint56: - j handle_it - li a0, 11 - -/* - * GPIO Pin 5 or 6 transition (1-to-0) - IRQ 12 - */ -io_negint56: - j handle_it - li a0, 12 - END(nino_handle_int) + /* + * Here is the table of interrupts for the Philips Nino + * which uses the Philips PR31700/Toshiba TMPR3912 core. + * + * MIPS IRQ Description + * -------- -------------------------------- + * 0 SW0 interrupt (unused) + * 1 SW1 interrupt (unused) + * 2 + * 3 + * 4 PR31700 low priority interrupts + * 5 + * 6 PR31700 high priority interrupts + * 7 + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(ninoIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 s0, CP0_CAUSE # determine cause + + andi a0, s0, CAUSEF_IP6 + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP4 # delay slot + move a0, sp + jal irq6_dispatch + nop # delay slot + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + nop # delay slot + move a0, sp + jal irq4_dispatch + nop # delay slot + j ret_from_irq + nop # delay slot + +1: + /* We should never get here */ + move a0, sp + j irq_bad + nop + END(ninoIRQ) diff -urN linux-2.4.18/arch/mips/philips/nino/irq.c linux-2.4.19-pre5/arch/mips/philips/nino/irq.c --- linux-2.4.18/arch/mips/philips/nino/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/irq.c Sat Mar 30 22:55:27 2002 @@ -1,314 +1,264 @@ /* - * linux/arch/mips/philips/nino/irq.c + * arch/mips/philips/nino/irq.c * - * Copyright (C) 1992 Linus Torvalds - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Pavel Machek (pavel@suse.cz) * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * Generic interrupt handler for Philips Nino. + * + * Interrupt service routines for Philips Nino */ -#include #include -#include -#include #include -#include #include -#include -#include -#include -#include - -#include -#include #include -#include #include -#include #include -unsigned long spurious_count = 0; +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) -irq_cpustat_t irq_stat [NR_CPUS]; +extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); -static inline void mask_irq(unsigned int irq_nr) +static void enable_irq6(unsigned int irq) { - switch (irq_nr) { - case 0: /* Periodic Timer Interrupt */ - IntClear5 = INT5_PERIODICINT; - IntClear6 = INT6_PERIODICINT; - IntEnable6 &= ~INT6_PERIODICINT; - break; + if(irq == 0) { + outl(inl(TX3912_INT6_ENABLE) | + TX3912_INT6_ENABLE_PRIORITYMASK_PERINT, + TX3912_INT6_ENABLE); + outl(inl(TX3912_INT5_ENABLE) | TX3912_INT5_PERINT, + TX3912_INT5_ENABLE); + } + if(irq == 3) { + outl(inl(TX3912_INT6_ENABLE) | + TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT, + TX3912_INT6_ENABLE); + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + } +} - case 3: - /* Serial port receive interrupt */ - break; +static unsigned int startup_irq6(unsigned int irq) +{ + enable_irq6(irq); - case 2: - /* Serial port transmit interrupt */ - break; + return 0; /* Never anything pending */ +} - default: - printk( "Attempt to mask unknown IRQ %d?\n", irq_nr ); +static void disable_irq6(unsigned int irq) +{ + if(irq == 0) { + outl(inl(TX3912_INT6_ENABLE) & + ~TX3912_INT6_ENABLE_PRIORITYMASK_PERINT, + TX3912_INT6_ENABLE); + outl(inl(TX3912_INT5_ENABLE) & ~TX3912_INT5_PERINT, + TX3912_INT5_ENABLE); + outl(inl(TX3912_INT5_CLEAR) | TX3912_INT5_PERINT, + TX3912_INT5_CLEAR); + } + if(irq == 3) { + outl(inl(TX3912_INT6_ENABLE) & + ~TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT, + TX3912_INT6_ENABLE); + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); } } -static inline void unmask_irq(unsigned int irq_nr) +#define shutdown_irq6 disable_irq6 +#define mask_and_ack_irq6 disable_irq6 + +static void end_irq6(unsigned int irq) { - switch (irq_nr) { - case 0: - IntEnable6 |= INT6_PERIODICINT; - break; + if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_irq6(irq); +} - case 3: - /* Serial port receive interrupt */ - break; +static struct hw_interrupt_type irq6_type = { + "MIPS", + startup_irq6, + shutdown_irq6, + enable_irq6, + disable_irq6, + mask_and_ack_irq6, + end_irq6, + NULL +}; - case 2: - /* Serial port transmit interrupt */ - break; +void irq6_dispatch(struct pt_regs *regs) +{ + int irq = -1; - default: - printk( "Attempt to unmask unknown IRQ %d?\n", irq_nr ); + if((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_UARTARXINT) == + TX3912_INT6_STATUS_INTVEC_UARTARXINT) { + irq = 3; + goto done; + } + if ((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_PERINT) == + TX3912_INT6_STATUS_INTVEC_PERINT) { + irq = 0; + goto done; } -} -void disable_irq(unsigned int irq_nr) -{ - unsigned long flags; + /* if irq == -1, then interrupt was cleared or is invalid */ + if (irq == -1) { + panic("Unhandled High Priority PR31700 Interrupt = 0x%08x", + inl(TX3912_INT6_STATUS)); + } - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); +done: + do_IRQ(irq, regs); } -void enable_irq(unsigned int irq_nr) +static void enable_irq4(unsigned int irq) { - unsigned long flags; - - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); + set_cp0_status(STATUSF_IP4); + if (irq == 2) { + outl(inl(TX3912_INT2_CLEAR) | TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_CLEAR); + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + } } -/* - * Pointers to the low-level handlers: first the general ones, then the - * fast ones, then the bad ones. - */ -extern void interrupt(void); - -static struct irqaction *irq_action[NR_IRQS] = +static unsigned int startup_irq4(unsigned int irq) { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; + enable_irq4(irq); -int get_irq_list(char *buf) -{ - int i, len = 0; - struct irqaction *action; + return 0; /* Never anything pending */ +} - for (i = 0; i < NR_IRQS; i++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf + len, "%2d: %8d %c %s", - i, kstat.irqs[0][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action = action->next; action; action = action->next) { - len += sprintf(buf + len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf + len, "\n"); - } - return len; -} - -atomic_t __mips_bh_counter; - -/* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. - */ -asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +static void disable_irq4(unsigned int irq) { - struct irqaction *action; - int do_random, cpu; + clear_cp0_status(STATUSF_IP4); +} - if (irq == 20) { - if (IntStatus2 & 0xfffff00) { - if (IntStatus2 & 0x0f000000) - return do_IRQ(2, regs); - } - } - - cpu = smp_processor_id(); - irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; - - if (irq == 20) { - printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n", - IntStatus1, IntStatus2, IntStatus3, - IntStatus4, IntStatus5 ); - printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n", - IntEnable1, IntEnable2, IntEnable3, - IntEnable4, IntEnable5 ); - - } - - mask_irq(irq); - action = *(irq + irq_action); - if (action) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do_random = 0; - do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - unmask_irq(irq); - __cli(); - } else { - IntClear1 = ~0; - IntClear3 = ~0; - IntClear4 = ~0; - IntClear5 = ~0; - unmask_irq(irq); - } - irq_exit(cpu, irq); - - /* unmasking and bottom half handling is done magically for us. */ -} - -/* - * Idea is to put all interrupts - * in a single table and differenciate them just by number. - */ -int setup_nino_irq(int irq, struct irqaction *new) +#define shutdown_irq4 disable_irq4 +#define mask_and_ack_irq4 disable_irq4 + +static void end_irq4(unsigned int irq) { - int shared = 0; - struct irqaction *old, **p; - unsigned long flags; - - p = irq_action + irq; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) - return -EBUSY; - - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - - save_and_cli(flags); - *p = new; - - if (!shared) { - unmask_irq(irq); - } - restore_flags(flags); - return 0; -} - -int request_irq(unsigned int irq, - void (*handler) (int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, - void *dev_id) -{ - int retval; - struct irqaction *action; - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_nino_irq(irq, action); - - if (retval) - kfree(action); - return retval; + if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_irq4(irq); } -void free_irq(unsigned int irq, void *dev_id) +static struct hw_interrupt_type irq4_type = { + "MIPS", + startup_irq4, + shutdown_irq4, + enable_irq4, + disable_irq4, + mask_and_ack_irq4, + end_irq4, + NULL +}; + +void irq4_dispatch(struct pt_regs *regs) { - struct irqaction *action, **p; - unsigned long flags; + int irq = -1; - if (irq >= NR_IRQS) { - printk(KERN_CRIT __FUNCTION__ ": trying to free IRQ%d\n", irq); - return; - } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - if (!irq[irq_action]) - mask_irq(irq); - restore_flags(flags); - kfree(action); + if(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTA_TX_BITS) { + irq = 2; + goto done; + } + + /* if irq == -1, then interrupt was cleared or is invalid */ + if (irq == -1) { + printk("PR31700 Interrupt Status Register 1 = 0x%08x\n", + inl(TX3912_INT1_STATUS)); + printk("PR31700 Interrupt Status Register 2 = 0x%08x\n", + inl(TX3912_INT2_STATUS)); + printk("PR31700 Interrupt Status Register 3 = 0x%08x\n", + inl(TX3912_INT3_STATUS)); + printk("PR31700 Interrupt Status Register 4 = 0x%08x\n", + inl(TX3912_INT4_STATUS)); + printk("PR31700 Interrupt Status Register 5 = 0x%08x\n", + inl(TX3912_INT5_STATUS)); + panic("Unhandled Low Priority PR31700 Interrupt"); + } + +done: + do_IRQ(irq, regs); return; - } - printk(KERN_CRIT __FUNCTION__ ": trying to free free IRQ%d\n", irq); } -unsigned long probe_irq_on(void) +void irq_bad(struct pt_regs *regs) { - /* TODO */ - return 0; -} + /* This should never happen */ + printk(" CAUSE register = 0x%08lx\n", regs->cp0_cause); + printk("STATUS register = 0x%08lx\n", regs->cp0_status); + printk(" EPC register = 0x%08lx\n", regs->cp0_epc); + panic("Stray interrupt, spinning..."); +} + +void __init nino_irq_setup(void) +{ + extern asmlinkage void ninoIRQ(void); + + unsigned int i; + + /* Disable all hardware interrupts */ + change_cp0_status(ST0_IM, 0x00); + + /* Clear interrupts */ + outl(0xffffffff, TX3912_INT1_CLEAR); + outl(0xffffffff, TX3912_INT2_CLEAR); + outl(0xffffffff, TX3912_INT3_CLEAR); + outl(0xffffffff, TX3912_INT4_CLEAR); + outl(0xffffffff, TX3912_INT5_CLEAR); + + /* + * Disable all PR31700 interrupts. We let the various + * device drivers in the system register themselves + * and set the proper hardware bits. + */ + outl(0x00000000, TX3912_INT1_ENABLE); + outl(0x00000000, TX3912_INT2_ENABLE); + outl(0x00000000, TX3912_INT3_ENABLE); + outl(0x00000000, TX3912_INT4_ENABLE); + outl(0x00000000, TX3912_INT5_ENABLE); + + /* Initialize IRQ vector table */ + init_generic_irq(); + + /* Initialize IRQ action handlers */ + for (i = 0; i < 16; i++) { + hw_irq_controller *handler = NULL; + if (i == 0 || i == 3) + handler = &irq6_type; + else + handler = &irq4_type; + + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = handler; + } -int probe_irq_off(unsigned long irqs) -{ - /* TODO */ - return 0; + /* Set up the external interrupt exception vector */ + set_except_vector(0, ninoIRQ); + + /* Enable high priority interrupts */ + outl(TX3912_INT6_ENABLE_GLOBALEN | TX3912_INT6_ENABLE_HIGH_PRIORITY, + TX3912_INT6_ENABLE); + + /* Enable all interrupts */ + change_cp0_status(ST0_IM, ALLINTS); } +void (*irq_setup)(void); + void __init init_IRQ(void) { - irq_setup(); +#ifdef CONFIG_REMOTE_DEBUG + extern void breakpoint(void); + extern void set_debug_traps(void); + + printk("Wait for gdb client connection ...\n"); + set_debug_traps(); + breakpoint(); +#endif + + /* Invoke board-specific irq setup */ + irq_setup(); } diff -urN linux-2.4.18/arch/mips/philips/nino/kgdb.c linux-2.4.19-pre5/arch/mips/philips/nino/kgdb.c --- linux-2.4.18/arch/mips/philips/nino/kgdb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/kgdb.c Thu Jan 1 01:00:00 1970 @@ -1,83 +0,0 @@ -/* - * linux/arch/mips/philips/nino/kgdb.c - * - * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Kernel debugging on the Philips Nino. - */ -#include -#include - -static int remoteDebugInitialized = 0; - -void debugInit(void) -{ -/* - * If low-level debugging (before GDB or console operational) is - * configured, then we do not need to re-initialize the UART. - */ -#ifndef CONFIG_DEBUG_LL - earlyInitUartPR31700(); -#endif -} - -char getDebugChar(void) -{ - char buf; - unsigned long int2, flags; - - if (!remoteDebugInitialized) { - debugInit(); - remoteDebugInitialized = 1; - } - - save_and_cli(flags); - - int2 = IntEnable2; - - IntEnable2 = 0; - - while(!(UartA_Ctrl1 & UART_RX_HOLD_FULL)); - - buf = UartA_Data; - - IntEnable2 = int2; - - restore_flags(flags); - - return buf; -} - -int putDebugChar(char c) -{ - int i; - unsigned long int2; - - if (!remoteDebugInitialized) { - debugInit(); - remoteDebugInitialized = 1; - } - - int2 = IntEnable2; - - IntEnable2 &= - ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY); - - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++); - - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; - - UartA_Data = c; - - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++); - - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; - - IntEnable2 = int2; - - return 1; -} diff -urN linux-2.4.18/arch/mips/philips/nino/power.c linux-2.4.19-pre5/arch/mips/philips/nino/power.c --- linux-2.4.18/arch/mips/philips/nino/power.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/power.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * linux/arch/mips/philips/nino/power.c + * arch/mips/philips/nino/power.c * * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) @@ -8,21 +8,24 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Power management routines on the Philips Nino. + * Power management routines for the Philips Nino */ +#include #include void nino_wait(void) { /* We stop the CPU to conserve power */ - PowerControl |= PWR_STOPCPU; + outl(inl(TX3912_POWER_CTRL) | TX3912_POWER_CTRL_STOPCPU, + TX3912_POWER_CTRL); /* * We wait until an interrupt happens... */ /* We resume here */ - PowerControl &= ~PWR_STOPCPU; + outl(inl(TX3912_POWER_CTRL) & ~TX3912_POWER_CTRL_STOPCPU, + TX3912_POWER_CTRL); /* Give ourselves a little delay */ __asm__ __volatile__( diff -urN linux-2.4.18/arch/mips/philips/nino/prom.c linux-2.4.19-pre5/arch/mips/philips/nino/prom.c --- linux-2.4.18/arch/mips/philips/nino/prom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/prom.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * linux/arch/mips/philips/nino/prom.c + * arch/mips/philips/nino/prom.c * * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Early initialization code for the Philips Nino. + * Early initialization code for the Philips Nino */ #include #include @@ -17,29 +17,25 @@ #include #include -char arcs_cmdline[COMMAND_LINE_SIZE]; +char arcs_cmdline[CL_SIZE]; #ifdef CONFIG_FB_TX3912 -extern u_long tx3912fb_paddr; -extern u_long tx3912fb_vaddr; -extern u_long tx3912fb_size; +extern unsigned long tx3912fb_paddr; +extern unsigned long tx3912fb_vaddr; +extern unsigned long tx3912fb_size; #endif +const char *get_system_type(void) +{ + return "Philips Nino"; +} + /* Do basic initialization */ -void __init prom_init(int argc, char **argv, - unsigned long magic, int *prom_vec) +void __init prom_init(int argc, char **argv, unsigned long magic, int *prom_vec) { - u_long free_end, mem_size; - u_int i; + unsigned long mem_size; - /* - * collect args and prepare cmd_line - */ - for (i = 1; i < argc; i++) { - strcat(arcs_cmdline, argv[i]); - if (i < (argc - 1)) - strcat(arcs_cmdline, " "); - } + strcpy(arcs_cmdline, "console=tty0 console=ttyS0,115200"); mips_machgroup = MACH_GROUP_PHILIPS; mips_machtype = MACH_PHILIPS_NINO; @@ -53,6 +49,9 @@ #endif #ifdef CONFIG_FB_TX3912 +{ + unsigned long free_end; + /* * The LCD controller requires that the framebuffer * start address fall within a 1MB segment and is @@ -70,6 +69,7 @@ */ tx3912fb_paddr = PHYSADDR(free_end); tx3912fb_vaddr = KSEG1ADDR(free_end); +} #else add_memory_region(0, mem_size, BOOT_MEM_RAM); #endif diff -urN linux-2.4.18/arch/mips/philips/nino/ramdisk/Makefile linux-2.4.19-pre5/arch/mips/philips/nino/ramdisk/Makefile --- linux-2.4.18/arch/mips/philips/nino/ramdisk/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/ramdisk/Makefile Thu Jan 1 01:00:00 1970 @@ -1,12 +0,0 @@ -# -# Makefile for the Philips Nino ramdisk -# -# 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). -# - -ramdisk.o: ramdisk.gz ld.script - $(LD) -T ld.script -b binary -o $@ ramdisk.gz - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/philips/nino/ramdisk/ld.script linux-2.4.19-pre5/arch/mips/philips/nino/ramdisk/ld.script --- linux-2.4.18/arch/mips/philips/nino/ramdisk/ld.script Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/ramdisk/ld.script Thu Jan 1 01:00:00 1970 @@ -1,9 +0,0 @@ -OUTPUT_FORMAT("ecoff-littlemips") -OUTPUT_ARCH(mips) -SECTIONS -{ - .initrd : - { - *(.data) - } -} diff -urN linux-2.4.18/arch/mips/philips/nino/reset.c linux-2.4.19-pre5/arch/mips/philips/nino/reset.c --- linux-2.4.18/arch/mips/philips/nino/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/reset.c Thu Jan 1 01:00:00 1970 @@ -1,37 +0,0 @@ -/* - * linux/arch/mips/philips/nino/reset.c - * - * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Generic restart, halt and power off functions for Philips Nino. - */ -#include -#include - -void (*reset_vector)(void) = (void (*)(void)) 0xBFC00000; - -void nino_machine_restart(char *command) -{ - reset_vector(); -} - -void nino_machine_halt(void) -{ - reset_vector(); -} - -void nino_machine_power_off(void) -{ - reset_vector(); -} - -void __init setup_nino_reset_vectors(void) -{ - _machine_restart = nino_machine_restart; - _machine_halt = nino_machine_halt; - _machine_power_off = nino_machine_power_off; -} diff -urN linux-2.4.18/arch/mips/philips/nino/rtc.c linux-2.4.19-pre5/arch/mips/philips/nino/rtc.c --- linux-2.4.18/arch/mips/philips/nino/rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/rtc.c Thu Jan 1 01:00:00 1970 @@ -1,34 +0,0 @@ -/* - * linux/arch/mips/philips/nino/rtc.c - * - * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Functions to access RTC on the Philips Nino. - */ -#include -#include - -static unsigned char nino_rtc_read_data(unsigned long addr) -{ - return 0; -} - -static void nino_rtc_write_data(unsigned char data, unsigned long addr) -{ -} - -static int nino_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops nino_rtc_ops = -{ - &nino_rtc_read_data, - &nino_rtc_write_data, - &nino_rtc_bcd_mode -}; diff -urN linux-2.4.18/arch/mips/philips/nino/setup.c linux-2.4.19-pre5/arch/mips/philips/nino/setup.c --- linux-2.4.18/arch/mips/philips/nino/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/setup.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * linux/arch/mips/philips/nino/setup.c + * arch/mips/philips/nino/setup.c * * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * @@ -7,114 +7,99 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Interrupt and exception initialization for Philips Nino. + * Interrupt and exception initialization for Philips Nino */ #include #include #include -#include #include #include -#include +#include #include -#include +#include +#include #include -extern struct rtc_ops nino_rtc_ops; - -extern void nino_wait(void); -extern void setup_nino_reset_vectors(void); -extern asmlinkage void nino_handle_int(void); -extern int setup_nino_irq(int, struct irqaction *); -void (*board_time_init) (struct irqaction * irq); - -#ifdef CONFIG_REMOTE_DEBUG -extern void set_debug_traps(void); -extern void breakpoint(void); -static int remote_debug = 0; -#endif - -static void __init nino_irq_setup(void) +static void nino_machine_restart(char *command) { - unsigned int tmp; + static void (*back_to_prom)(void) = (void (*)(void)) 0xbfc00000; - /* Turn all interrupts off */ - IntEnable1 = 0; - IntEnable2 = 0; - IntEnable3 = 0; - IntEnable4 = 0; - IntEnable5 = 0; - IntEnable6 = 0; - - /* Clear all interrupts */ - IntClear1 = 0xffffffff; - IntClear2 = 0xffffffff; - IntClear3 = 0xffffffff; - IntClear4 = 0xffffffff; - IntClear5 = 0xffffffff; - IntClear6 = 0xffffffff; + /* Reboot */ + back_to_prom(); +} - /* - * Enable only the interrupts for the UART and negative - * edge (1-to-0) triggered multi-function I/O pins. - */ - change_cp0_status(ST0_BEV, 0); - tmp = read_32bit_cp0_register(CP0_STATUS); - change_cp0_status(ST0_IM, tmp | IE_IRQ2 | IE_IRQ4); - - /* Register the global interrupt handler */ - set_except_vector(0, nino_handle_int); - -#ifdef CONFIG_REMOTE_DEBUG - if (remote_debug) { - set_debug_traps(); - breakpoint(); - } -#endif +static void nino_machine_halt(void) +{ + printk("Nino halted.\n"); + while(1); } -static __init void nino_time_init(struct irqaction *irq) +static void nino_machine_power_off(void) { - unsigned int scratch = 0; + printk("Nino halted. Please turn off power.\n"); + while(1); +} +static void __init nino_board_init() +{ /* - * Enable periodic interrupts + * Set up the master clock module. The value set in + * the Clock Control Register by WindowsCE is 0x00432ba. + * We set a few values here and let the device drivers + * handle the rest. + * + * NOTE: The UART clocks must be enabled here to provide + * enough time for them to settle. */ - setup_nino_irq(0, irq); + outl(0x00000000, TX3912_CLK_CTRL); + outl((TX3912_CLK_CTRL_SIBMCLKDIR | TX3912_CLK_CTRL_SIBMCLKDIV_2 | + TX3912_CLK_CTRL_ENSIBMCLK | TX3912_CLK_CTRL_CSERSEL | + TX3912_CLK_CTRL_CSERDIV_3 | TX3912_CLK_CTRL_ENCSERCLK | + TX3912_CLK_CTRL_ENUARTACLK | TX3912_CLK_CTRL_ENUARTBCLK), + TX3912_CLK_CTRL); +} - RTCperiodTimer = PER_TIMER_COUNT; - RTCtimerControl = TIM_ENPERTIMER; - IntEnable5 |= INT5_PERIODICINT; - - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= TX3912_CLK_CTRL_ENTIMERCLK; - outl(scratch, TX3912_CLK_CTRL_BASE); +static __init void nino_time_init(void) +{ + /* Load the counter and enable the timer */ + outl(TX3912_SYS_TIMER_VALUE, TX3912_TIMER_PERIOD); + outl(TX3912_TIMER_CTRL_ENPERTIMER, TX3912_TIMER_CTRL); + + /* Enable the master timer clock */ + outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENTIMERCLK, + TX3912_CLK_CTRL); + + /* Enable the interrupt */ + outl(inl(TX3912_INT5_ENABLE) | TX3912_INT5_PERINT, + TX3912_INT5_ENABLE); +} - /* Enable all interrupts */ - IntEnable6 |= INT6_GLOBALEN | INT6_PERIODICINT; +static __init void nino_timer_setup(struct irqaction *irq) +{ + irq->dev_id = (void *) irq; + setup_irq(0, irq); } void __init nino_setup(void) { - irq_setup = nino_irq_setup; + extern void nino_irq_setup(void); + extern void nino_wait(void); - board_time_init = nino_time_init; + irq_setup = nino_irq_setup; + set_io_port_base(KSEG1ADDR(0x10c00000)); - /* Base address to use for PC type I/O accesses */ - mips_io_port_base = KSEG1ADDR(0xB0C00000); + _machine_restart = nino_machine_restart; + _machine_halt = nino_machine_halt; + _machine_power_off = nino_machine_power_off; - setup_nino_reset_vectors(); + board_time_init = nino_time_init; + board_timer_setup = nino_timer_setup; - /* Function called during process idle (cpu_idle) */ cpu_wait = nino_wait; #ifdef CONFIG_FB conswitchp = &dummy_con; #endif -#ifdef CONFIG_REMOTE_DEBUG - remote_debug = 1; -#endif - - rtc_ops = &nino_rtc_ops; + nino_board_init(); } diff -urN linux-2.4.18/arch/mips/philips/nino/time.c linux-2.4.19-pre5/arch/mips/philips/nino/time.c --- linux-2.4.18/arch/mips/philips/nino/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/philips/nino/time.c Thu Jan 1 01:00:00 1970 @@ -1,216 +0,0 @@ -/* - * linux/arch/mips/philips/nino/time.c - * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Pavel Machek (pavel@suse.cz) - * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Time handling functinos for Philips Nino. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern volatile unsigned long wall_jiffies; -extern rwlock_t xtime_lock; - -static struct timeval xbase; - -#define USECS_PER_JIFFY (1000000/HZ) - -/* - * Poll the Interrupt Status Registers - */ -#undef POLL_STATUS - -static unsigned long do_gettimeoffset(void) -{ - /* - * This is a kludge - */ - return 0; -} - -static -void inline readRTC(unsigned long *high, unsigned long *low) -{ - /* read twice, and keep reading till we find two - * the same pairs. This is needed in case the RTC - * was updating its registers and we read a old - * High but a new Low. */ - do { - *high = RTChigh & RTC_HIGHMASK; - *low = RTClow; - } while (*high != (RTChigh & RTC_HIGHMASK) || RTClow!=*low); -} - -/* - * This version of gettimeofday has near millisecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long high, low; - - read_lock_irqsave(&xtime_lock, flags); - // 40 bit RTC, driven by 32khz source: - // +-----------+-----------------------------------------+ - // | HHHH.HHHH | LLLL.LLLL.LLLL.LLLL.LMMM.MMMM.MMMM.MMMM | - // +-----------+-----------------------------------------+ - readRTC(&high,&low); - tv->tv_sec = (high << 17) | (low >> 15); - tv->tv_usec = (low % 32768) * 1953 / 64; - tv->tv_sec += xbase.tv_sec; - tv->tv_usec += xbase.tv_usec; - - tv->tv_usec += do_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. lost_ticks is - * nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore(&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} - -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 -= do_gettimeoffset(); - - if (tv->tv_usec < 0) { - tv->tv_usec += 1000000; - tv->tv_sec--; - } - - /* reset RTC to 0 (real time is xbase + RTC) */ - xbase = *tv; - RTCtimerControl |= TIM_RTCCLEAR; - RTCtimerControl &= ~TIM_RTCCLEAR; - RTCalarmHigh = RTCalarmLow = ~0UL; - - xtime = *tv; - time_state = TIME_BAD; - time_maxerror = MAXPHASE; - time_esterror = MAXPHASE; - write_unlock_irq(&xtime_lock); -} - -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - - return retval; -} - -/* last time the cmos clock got updated */ -static long last_rtc_update = 0; - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ - -int do_write = 1; - -static void -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef POLL_STATUS - static unsigned long old_IntStatus1 = 0; - static unsigned long old_IntStatus3 = 0; - static unsigned long old_IntStatus4 = 0; - static unsigned long old_IntStatus5 = 0; - static int counter = 0; - int i; - - new_spircv = SPIData & 0xff; - if ((old_spircv != new_spircv) && (new_spircv != 0xff)) { - printk( "SPIData changed: %x\n", new_spircv ); - } - old_spircv = new_spircv; - if (do_write) - SPIData = 0; -#endif - - if (!user_mode(regs)) { - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long pc = regs->cp0_epc; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Dont ignore out-of-bounds pc values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *) & prof_buffer[pc]); - } - } - - /* - * aaaand... action! - */ - do_timer(regs); - - /* - * If we have an externally syncronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) - { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ - } -} - -static struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0, - "timer", NULL, NULL}; - -void (*board_time_init) (struct irqaction * irq); - -int __init time_init(void) -{ - struct timeval starttime; - - starttime.tv_sec = mktime(2000, 1, 1, 0, 0, 0); - starttime.tv_usec = 0; - do_settimeofday(&starttime); - - board_time_init(&irq0); - - return 0; -} diff -urN linux-2.4.18/arch/mips/ramdisk/Makefile linux-2.4.19-pre5/arch/mips/ramdisk/Makefile --- linux-2.4.18/arch/mips/ramdisk/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ramdisk/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,15 @@ +# +# Makefile for a ramdisk image +# +# 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). +# + +O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) +ramdisk.o: ramdisk.gz ld.script + echo "O_FORMAT: " $(O_FORMAT) + $(LD) -T ld.script -b binary --oformat $(O_FORMAT) -o $@ ramdisk.gz + +include $(TOPDIR)/Rules.make + diff -urN linux-2.4.18/arch/mips/ramdisk/ld.script linux-2.4.19-pre5/arch/mips/ramdisk/ld.script --- linux-2.4.18/arch/mips/ramdisk/ld.script Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/ramdisk/ld.script Sat Mar 30 22:55:27 2002 @@ -0,0 +1,9 @@ +OUTPUT_ARCH(mips) +SECTIONS +{ + .initrd : + { + *(.data) + } +} + diff -urN linux-2.4.18/arch/mips/sgi/kernel/Makefile linux-2.4.19-pre5/arch/mips/sgi/kernel/Makefile --- linux-2.4.18/arch/mips/sgi/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/Makefile Thu Jan 1 01:00:00 1970 @@ -1,25 +0,0 @@ -# -# Makefile for the SGI specific kernel interface routines -# under Linux. -# -# 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: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -O_TARGET := ip22-kern.o - -all: ip22-kern.o indyIRQ.o - -obj-y += indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \ - indyIRQ.o reset.o setup.o time.o - -indyIRQ.o: indyIRQ.S - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/sgi/kernel/indyIRQ.S linux-2.4.19-pre5/arch/mips/sgi/kernel/indyIRQ.S --- linux-2.4.18/arch/mips/sgi/kernel/indyIRQ.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indyIRQ.S Thu Jan 1 01:00:00 1970 @@ -1,126 +0,0 @@ -/* - * indyIRQ.S: Interrupt exception dispatch code for FullHouse and - * Guiness. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ - -#include -#include -#include -#include - - /* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop - * and moving across all the pending IRQ bits in the cause - * register is _NOT_ the answer, the common case is one - * pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register - * IRQ mask, that would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs - * off, nothing in between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the INDY look basically (barring - * software IRQs which we don't use at all) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Local IRQ level zero - * 3 Local IRQ level one - * 4 8254 Timer zero - * 5 8254 Timer one - * 6 Bus Error - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Local IRQ zero - * Local IRQ one - * Bus Error - * 8254 Timer zero - * Lowest ---- 8254 Timer one - * - * then we just return, if multiple IRQs are pending then - * we will just take another exception, big deal. - */ - - .text - .set noreorder - .set noat - .align 5 - NESTED(indyIRQ, PT_SIZE, sp) - SAVE_ALL - CLI - .set at - mfc0 s0, CP0_CAUSE # get irq mask - - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero - - /* Wheee, a timer interrupt. */ - move a0, sp - jal indy_r4k_timer_interrupt - nop # delay slot - - j ret_from_irq - nop # delay slot - -1: - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP3 # delay slot, check local level one - - /* Wheee, local level zero interrupt. */ - jal indy_local0_irqdispatch - move a0, sp # delay slot - - j ret_from_irq - nop # delay slot - -1: - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP6 # delay slot, check bus error - - /* Wheee, local level one interrupt. */ - move a0, sp - jal indy_local1_irqdispatch - nop - - j ret_from_irq - nop - -1: - beq a0, zero, 1f - nop - - /* Wheee, an asynchronous bus error... */ - move a0, sp - jal indy_buserror_irq - nop - - j ret_from_irq - nop - -1: - /* Here by mistake? This is possible, what can happen - * is that by the time we take the exception the IRQ - * pin goes low, so just leave if this is the case. - */ - andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) - beq a0, zero, 1f - - /* Must be one of the 8254 timers... */ - move a0, sp - jal indy_8254timer_irq - nop -1: - j ret_from_irq - nop - END(indyIRQ) diff -urN linux-2.4.18/arch/mips/sgi/kernel/indy_hpc.c linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_hpc.c --- linux-2.4.18/arch/mips/sgi/kernel/indy_hpc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_hpc.c Thu Jan 1 01:00:00 1970 @@ -1,106 +0,0 @@ -/* $Id: indy_hpc.c,v 1.9 1999/12/04 03:59:00 ralf Exp $ - * - * indy_hpc.c: Routines for generic manipulation of the HPC controllers. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1998 Ralf Baechle - */ -#include -#include - -#include -#include -#include -#include -#include - -/* #define DEBUG_SGIHPC */ - -struct hpc3_regs *hpc3c0, *hpc3c1; -struct hpc3_miscregs *hpc3mregs; - -/* We need software copies of these because they are write only. */ -unsigned int sgi_hpc_write1, sgi_hpc_write2; - -/* Machine specific identifier knobs. */ -int sgi_has_ioc2 = 0; -int sgi_guiness = 0; -int sgi_boardid; - -void __init sgihpc_init(void) -{ - unsigned long sid, crev, brev; - - hpc3c0 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP0_PBASE); - hpc3c1 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP1_PBASE); - hpc3mregs = (struct hpc3_miscregs *) (KSEG1 + HPC3_MREGS_PBASE); - sid = hpc3mregs->sysid; - - sid &= 0xff; - crev = (sid & 0xe0) >> 5; - brev = (sid & 0x1e) >> 1; - -#ifdef DEBUG_SGIHPC - prom_printf("sgihpc_init: crev<%2x> brev<%2x>\n", crev, brev); - prom_printf("sgihpc_init: "); -#endif - - /* This test works now thanks to William J. Earl */ - if ((sid & 1) == 0 ) { -#ifdef DEBUG_SGIHPC - prom_printf("GUINESS "); -#endif - sgi_guiness = 1; - mips_machtype = MACH_SGI_INDY; - } else { -#ifdef DEBUG_SGIHPC - prom_printf("FULLHOUSE "); -#endif - mips_machtype = MACH_SGI_INDIGO2; - sgi_guiness = 0; - } - sgi_boardid = brev; - -#ifdef DEBUG_SGIHPC - prom_printf("sgi_boardid<%d> ", sgi_boardid); -#endif - - if(crev == 1) { - if((sid & 1) || (brev >= 2)) { -#ifdef DEBUG_SGIHPC - prom_printf("IOC2 "); -#endif - sgi_has_ioc2 = 1; - } else { -#ifdef DEBUG_SGIHPC - prom_printf("IOC1 revision 1 "); -#endif - } - } else { -#ifdef DEBUG_SGIHPC - prom_printf("IOC1 revision 0 "); -#endif - } -#ifdef DEBUG_SGIHPC - prom_printf("\n"); -#endif - - sgi_hpc_write1 = (HPC3_WRITE1_PRESET | - HPC3_WRITE1_KMRESET | - HPC3_WRITE1_ERESET | - HPC3_WRITE1_LC0OFF); - - sgi_hpc_write2 = (HPC3_WRITE2_EASEL | - HPC3_WRITE2_NTHRESH | - HPC3_WRITE2_TPSPEED | - HPC3_WRITE2_EPSEL | - HPC3_WRITE2_U0AMODE | - HPC3_WRITE2_U1AMODE); - - if(!sgi_guiness) - sgi_hpc_write1 |= HPC3_WRITE1_GRESET; - hpc3mregs->write1 = sgi_hpc_write1; - hpc3mregs->write2 = sgi_hpc_write2; - - hpc3c0->pbus_piocfgs[0][6] |= HPC3_PIOPCFG_HW; -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/indy_int.c linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_int.c --- linux-2.4.18/arch/mips/sgi/kernel/indy_int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_int.c Thu Jan 1 01:00:00 1970 @@ -1,528 +0,0 @@ -/* - * indy_int.c: Routines for generic manipulation of the INT[23] ASIC - * found on INDY workstations.. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - * - Indigo2 changes - * - Interrupt handling fixes - */ -#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 - -/* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. - */ - -/* #define DEBUG_SGINT */ - -struct sgi_int2_regs *sgi_i2regs; -struct sgi_int3_regs *sgi_i3regs; -struct sgi_ioc_ints *ioc_icontrol; -struct sgi_ioc_timers *ioc_timers; -volatile unsigned char *ioc_tclear; - -static char lc0msk_to_irqnr[256]; -static char lc1msk_to_irqnr[256]; -static char lc2msk_to_irqnr[256]; -static char lc3msk_to_irqnr[256]; - -extern asmlinkage void indyIRQ(void); - -/* Local IRQ's are layed out logically like this: - * - * 0 --> 7 == local 0 interrupts - * 8 --> 15 == local 1 interrupts - * 16 --> 23 == vectored level 2 interrupts - * 24 --> 31 == vectored level 3 interrupts (not used) - */ -static void enable_local0_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - ioc_icontrol->imask0 |= (1 << (irq - SGINT_LOCAL0)); - restore_flags(flags); -} - -static unsigned int startup_local0_irq(unsigned int irq) -{ - enable_local0_irq(irq); - - return 0; /* Never anything pending */ -} - -static void disable_local0_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - ioc_icontrol->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); - restore_flags(flags); -} - -#define shutdown_local0_irq disable_local0_irq -#define mask_and_ack_local0_irq disable_local0_irq - -static void end_local0_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local0_irq(irq); -} - -static struct hw_interrupt_type ip22_local0_irq_type = { - "IP22 local 0", - startup_local0_irq, - shutdown_local0_irq, - enable_local0_irq, - disable_local0_irq, - mask_and_ack_local0_irq, - end_local0_irq, - NULL -}; - -static void enable_local1_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - ioc_icontrol->imask1 |= (1 << (irq - SGINT_LOCAL1)); - restore_flags(flags); -} - -static unsigned int startup_local1_irq(unsigned int irq) -{ - enable_local1_irq(irq); - - return 0; /* Never anything pending */ -} - -void disable_local1_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - ioc_icontrol->imask1 &= ~(1 << (irq- SGINT_LOCAL1)); - restore_flags(flags); -} - -#define shutdown_local1_irq disable_local1_irq -#define mask_and_ack_local1_irq disable_local1_irq - -static void end_local1_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local1_irq(irq); -} - -static struct hw_interrupt_type ip22_local1_irq_type = { - "IP22 local 1", - startup_local1_irq, - shutdown_local1_irq, - enable_local1_irq, - disable_local1_irq, - mask_and_ack_local1_irq, - end_local1_irq, - NULL -}; - -static void enable_local2_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - enable_local0_irq(7); - ioc_icontrol->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); - restore_flags(flags); -} - -static unsigned int startup_local2_irq(unsigned int irq) -{ - enable_local2_irq(irq); - - return 0; /* Never anything pending */ -} - -void disable_local2_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - ioc_icontrol->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); - restore_flags(flags); -} - -#define shutdown_local2_irq disable_local2_irq -#define mask_and_ack_local2_irq disable_local2_irq - -static void end_local2_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local2_irq(irq); -} - -static struct hw_interrupt_type ip22_local2_irq_type = { - "IP22 local 2", - startup_local2_irq, - shutdown_local2_irq, - enable_local2_irq, - disable_local2_irq, - mask_and_ack_local2_irq, - end_local2_irq, - NULL -}; - -static void enable_local3_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - printk("Yeeee, got passed irq_nr %d at enable_local3_irq\n", irq); - panic("INVALID IRQ level!"); - restore_flags(flags); -} - -static unsigned int startup_local3_irq(unsigned int irq) -{ - enable_local3_irq(irq); - - return 0; /* Never anything pending */ -} - -void disable_local3_irq(unsigned int irq) -{ - unsigned long flags; - - save_and_cli(flags); - /* - * This way we'll see if anyone would ever want vectored level 3 - * interrupts. Highly unlikely. - */ - printk("Yeeee, got passed irq_nr %d at disable_local3_irq\n", irq); - panic("INVALID IRQ level!"); - restore_flags(flags); -} - -#define shutdown_local3_irq disable_local3_irq -#define mask_and_ack_local3_irq disable_local3_irq - -static void end_local3_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_local3_irq(irq); -} - -static struct hw_interrupt_type ip22_local3_irq_type = { - "IP22 local 3", - startup_local3_irq, - shutdown_local3_irq, - enable_local3_irq, - disable_local3_irq, - mask_and_ack_local3_irq, - end_local3_irq, - NULL -}; - -void enable_gio_irq(unsigned int irq) -{ - /* XXX TODO XXX */ -} - -static unsigned int startup_gio_irq(unsigned int irq) -{ - enable_gio_irq(irq); - - return 0; /* Never anything pending */ -} - -void disable_gio_irq(unsigned int irq) -{ - /* XXX TODO XXX */ -} - -#define shutdown_gio_irq disable_gio_irq -#define mask_and_ack_gio_irq disable_gio_irq - -static void end_gio_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_gio_irq(irq); -} - -static struct hw_interrupt_type ip22_gio_irq_type = { - "IP22 GIO", - startup_gio_irq, - shutdown_gio_irq, - enable_gio_irq, - disable_gio_irq, - mask_and_ack_gio_irq, - end_gio_irq, - NULL -}; - -void enable_hpcdma_irq(unsigned int irq) -{ - /* XXX TODO XXX */ -} - -static unsigned int startup_hpcdma_irq(unsigned int irq) -{ - enable_hpcdma_irq(irq); - - return 0; /* Never anything pending */ -} - -void disable_hpcdma_irq(unsigned int irq) -{ - /* XXX TODO XXX */ -} - -#define shutdown_hpcdma_irq disable_hpcdma_irq -#define mask_and_ack_hpcdma_irq disable_hpcdma_irq - -static void end_hpcdma_irq (unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_hpcdma_irq(irq); -} - -static struct hw_interrupt_type ip22_hpcdma_irq_type = { - "IP22 HPC DMA", - startup_hpcdma_irq, - shutdown_hpcdma_irq, - enable_hpcdma_irq, - disable_hpcdma_irq, - mask_and_ack_hpcdma_irq, - end_hpcdma_irq, - NULL -}; - -static struct irqaction r4ktimer_action = { - NULL, 0, 0, "R4000 timer/counter", NULL, NULL, -}; - -static struct irqaction indy_berr_action = { - NULL, 0, 0, "IP22 Bus Error", NULL, NULL, -}; - -static struct irqaction *irq_action[16] = { - NULL, NULL, NULL, NULL, - NULL, NULL, &indy_berr_action, &r4ktimer_action, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -void indy_local0_irqdispatch(struct pt_regs *regs) -{ - unsigned char mask = ioc_icontrol->istat0; - unsigned char mask2 = 0; - int irq; - - mask &= ioc_icontrol->imask0; - if (mask & ISTAT0_LIO2) { - mask2 = ioc_icontrol->vmeistat; - mask2 &= ioc_icontrol->cmeimask0; - irq = lc2msk_to_irqnr[mask2]; - } else { - irq = lc0msk_to_irqnr[mask]; - } - - /* if irq == 0, then the interrupt has already been cleared */ - if (irq == 0) - goto end; - - do_IRQ(irq, regs); - goto end; - -no_handler: - printk("No handler for local0 irq: %i\n", irq); - -end: - return; -} - -void indy_local1_irqdispatch(struct pt_regs *regs) -{ - unsigned char mask = ioc_icontrol->istat1; - unsigned char mask2 = 0; - int irq; - - mask &= ioc_icontrol->imask1; - if (mask & ISTAT1_LIO3) { - printk("WHee: Got an LIO3 irq, winging it...\n"); - mask2 = ioc_icontrol->vmeistat; - mask2 &= ioc_icontrol->cmeimask1; - irq = lc3msk_to_irqnr[ioc_icontrol->vmeistat]; - } else { - irq = lc1msk_to_irqnr[mask]; - } - - /* if irq == 0, then the interrupt has already been cleared */ - /* not sure if it is needed here, but it is needed for local0 */ - if (irq == 0) - goto end; - - do_IRQ(irq, regs); - goto end; - -no_handler: - printk("No handler for local1 irq: %i\n", irq); - -end: - return; -} - -void indy_buserror_irq(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - int irq = 6; - - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - printk("Got a bus error IRQ, shouldn't happen yet\n"); - show_regs(regs); - printk("Spinning...\n"); - while(1); - irq_exit(cpu, irq); -} - -void __init init_IRQ(void) -{ - int i; - - sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE); - sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE); - - /* Init local mask --> irq tables. */ - for (i = 0; i < 256; i++) { - if (i & 0x80) { - lc0msk_to_irqnr[i] = 7; - lc1msk_to_irqnr[i] = 15; - lc2msk_to_irqnr[i] = 23; - lc3msk_to_irqnr[i] = 31; - } else if (i & 0x40) { - lc0msk_to_irqnr[i] = 6; - lc1msk_to_irqnr[i] = 14; - lc2msk_to_irqnr[i] = 22; - lc3msk_to_irqnr[i] = 30; - } else if (i & 0x20) { - lc0msk_to_irqnr[i] = 5; - lc1msk_to_irqnr[i] = 13; - lc2msk_to_irqnr[i] = 21; - lc3msk_to_irqnr[i] = 29; - } else if (i & 0x10) { - lc0msk_to_irqnr[i] = 4; - lc1msk_to_irqnr[i] = 12; - lc2msk_to_irqnr[i] = 20; - lc3msk_to_irqnr[i] = 28; - } else if (i & 0x08) { - lc0msk_to_irqnr[i] = 3; - lc1msk_to_irqnr[i] = 11; - lc2msk_to_irqnr[i] = 19; - lc3msk_to_irqnr[i] = 27; - } else if (i & 0x04) { - lc0msk_to_irqnr[i] = 2; - lc1msk_to_irqnr[i] = 10; - lc2msk_to_irqnr[i] = 18; - lc3msk_to_irqnr[i] = 26; - } else if (i & 0x02) { - lc0msk_to_irqnr[i] = 1; - lc1msk_to_irqnr[i] = 9; - lc2msk_to_irqnr[i] = 17; - lc3msk_to_irqnr[i] = 25; - } else if (i & 0x01) { - lc0msk_to_irqnr[i] = 0; - lc1msk_to_irqnr[i] = 8; - lc2msk_to_irqnr[i] = 16; - lc3msk_to_irqnr[i] = 24; - } else { - lc0msk_to_irqnr[i] = 0; - lc1msk_to_irqnr[i] = 0; - lc2msk_to_irqnr[i] = 0; - lc3msk_to_irqnr[i] = 0; - } - } - - /* Indy uses an INT3, Indigo2 uses an INT2 */ - if (sgi_guiness) { - ioc_icontrol = &sgi_i3regs->ints; - ioc_timers = &sgi_i3regs->timers; - ioc_tclear = &sgi_i3regs->tclear; - } else { - ioc_icontrol = &sgi_i2regs->ints; - ioc_timers = &sgi_i2regs->timers; - ioc_tclear = &sgi_i2regs->tclear; - } - - /* Mask out all interrupts. */ - ioc_icontrol->imask0 = 0; - ioc_icontrol->imask1 = 0; - ioc_icontrol->cmeimask0 = 0; - ioc_icontrol->cmeimask1 = 0; - - set_except_vector(0, indyIRQ); - - init_generic_irq(); - - for (i = SGINT_LOCAL0; i < SGINT_END; i++) { - hw_irq_controller *handler; - - if (i < SGINT_LOCAL1) - handler = &ip22_local0_irq_type; - else if (i < SGINT_LOCAL2) - handler = &ip22_local1_irq_type; - else if (i < SGINT_LOCAL3) - handler = &ip22_local2_irq_type; - else if (i < SGINT_GIO) - handler = &ip22_local3_irq_type; - else if (i < SGINT_HPCDMA) - handler = &ip22_gio_irq_type; - else if (i < SGINT_END) - handler = &ip22_hpcdma_irq_type; - - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - irq_desc[i].handler = handler; - } -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/indy_mc.c linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_mc.c --- linux-2.4.18/arch/mips/sgi/kernel/indy_mc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_mc.c Thu Jan 1 01:00:00 1970 @@ -1,159 +0,0 @@ -/* - * indy_mc.c: Routines for manipulating the INDY memory controller. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes - * - * $Id: indy_mc.c,v 1.7 1999/12/04 03:59:00 ralf Exp $ - */ -#include -#include - -#include -#include -#include -#include -#include - -/* #define DEBUG_SGIMC */ - -struct sgimc_misc_ctrl *mcmisc_regs; -u32 *rpsscounter; -struct sgimc_dma_ctrl *dmactrlregs; - -static inline char *mconfig_string(unsigned long val) -{ - switch(val & SGIMC_MCONFIG_RMASK) { - case SGIMC_MCONFIG_FOURMB: - return "4MB"; - - case SGIMC_MCONFIG_EIGHTMB: - return "8MB"; - - case SGIMC_MCONFIG_SXTEENMB: - return "16MB"; - - case SGIMC_MCONFIG_TTWOMB: - return "32MB"; - - case SGIMC_MCONFIG_SFOURMB: - return "64MB"; - - case SGIMC_MCONFIG_OTEIGHTMB: - return "128MB"; - - default: - return "wheee, unknown"; - }; -} - -void __init sgimc_init(void) -{ - unsigned long tmpreg; - - mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); - rpsscounter = (unsigned int *) (KSEG1 + 0x1fa01004); - dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000); - - printk("MC: SGI memory controller Revision %d\n", - (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV); - -#if 0 /* XXX Until I figure out what this bit really indicates XXX */ - /* XXX Is this systemid bit reliable? */ - if(mcmisc_regs->systemid & SGIMC_SYSID_EPRESENT) { - EISA_bus = 1; - printk("with EISA\n"); - } else { - EISA_bus = 0; - printk("no EISA\n"); - } -#endif - -#ifdef DEBUG_SGIMC - prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n", - mconfig_string(mcmisc_regs->mconfig0), - mconfig_string(mcmisc_regs->mconfig1)); - - prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n", - mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1); - prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n", - mcmisc_regs->divider, mcmisc_regs->gioparm); -#endif - - /* Place the MC into a known state. This must be done before - * interrupts are first enabled etc. - */ - - /* Step 1: The CPU/GIO error status registers will not latch - * up a new error status until the register has been - * cleared by the cpu. These status registers are - * cleared by writing any value to them. - */ - mcmisc_regs->cstat = mcmisc_regs->gstat = 0; - - /* Step 2: Enable all parity checking in cpu control register - * zero. - */ - tmpreg = mcmisc_regs->cpuctrl0; - tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | - SGIMC_CCTRL0_R4KNOCHKPARR); - mcmisc_regs->cpuctrl0 = tmpreg; - - /* Step 3: Setup the MC write buffer depth, this is controlled - * in cpu control register 1 in the lower 4 bits. - */ - tmpreg = mcmisc_regs->cpuctrl1; - tmpreg &= ~0xf; - tmpreg |= 0xd; - mcmisc_regs->cpuctrl1 = tmpreg; - - /* Step 4: Initialize the RPSS divider register to run as fast - * as it can correctly operate. The register is laid - * out as follows: - * - * ---------------------------------------- - * | RESERVED | INCREMENT | DIVIDER | - * ---------------------------------------- - * 31 16 15 8 7 0 - * - * DIVIDER determines how often a 'tick' happens, - * INCREMENT determines by how the RPSS increment - * registers value increases at each 'tick'. Thus, - * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 - */ - mcmisc_regs->divider = 0x101; - - /* Step 5: Initialize GIO64 arbitrator configuration register. - * - * NOTE: If you dork with startup code the HPC init code in - * sgihpc_init() must run before us because of how we - * need to know Guiness vs. FullHouse and the board - * revision on this machine. You have been warned. - */ - - /* First the basic invariants across all gio64 implementations. */ - tmpreg = SGIMC_GIOPARM_HPC64; /* All 1st HPC's interface at 64bits. */ - tmpreg |= SGIMC_GIOPARM_ONEBUS; /* Only one physical GIO bus exists. */ - - if(sgi_guiness) { - /* Guiness specific settings. */ - tmpreg |= SGIMC_GIOPARM_EISA64; /* MC talks to EISA at 64bits */ - tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */ - } else { - /* Fullhouse specific settings. */ - if(sgi_boardid < 2) { - tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */ - tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */ - tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */ - } else { - tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP1; - tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */ - /* someone forgot this poor little guy... */ - tmpreg |= SGIMC_GIOPARM_GFX64; /* GFX at 64 bits */ - } - } - mcmisc_regs->gioparm = tmpreg; /* poof */ -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/indy_rtc.c linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_rtc.c --- linux-2.4.18/arch/mips/sgi/kernel/indy_rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_rtc.c Thu Jan 1 01:00:00 1970 @@ -1,36 +0,0 @@ -/* - * 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. - * - * RTC routines for Indy style attached Dallas chip. - * - * Copyright (C) 1998, 2001 by Ralf Baechle - */ -#include -#include - -static unsigned char indy_rtc_read_data(unsigned long addr) -{ - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; - - return rtcregs[addr]; -} - -static void indy_rtc_write_data(unsigned char data, unsigned long addr) -{ - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; - - rtcregs[addr] = data; -} - -static int indy_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops indy_rtc_ops = { - &indy_rtc_read_data, - &indy_rtc_write_data, - &indy_rtc_bcd_mode -}; diff -urN linux-2.4.18/arch/mips/sgi/kernel/indy_sc.c linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_sc.c --- linux-2.4.18/arch/mips/sgi/kernel/indy_sc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/indy_sc.c Thu Jan 1 01:00:00 1970 @@ -1,226 +0,0 @@ -/* - * indy_sc.c: Indy cache management functions. - * - * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org), - * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Secondary cache size in bytes, if present. */ -static unsigned long scache_size; - -#undef DEBUG_CACHE - -#define SC_SIZE 0x00080000 -#define SC_LINE 32 -#define CI_MASK (SC_SIZE - SC_LINE) -#define SC_INDEX(n) ((n) & CI_MASK) - -static inline void indy_sc_wipe(unsigned long first, unsigned long last) -{ - unsigned long tmp; - - __asm__ __volatile__( - ".set\tnoreorder\t\t\t# indy_sc_wipe\n\t" - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "mfc0\t%2, $12\n\t" - "li\t$1, 0x80\t\t\t# Go 64 bit\n\t" - "mtc0\t$1, $12\n\t" - - "dli\t$1, 0x9000000080000000\n\t" - "or\t%0, $1\t\t\t# first line to flush\n\t" - "or\t%1, $1\t\t\t# last line to flush\n\t" - ".set\tat\n\t" - - "1:\tsw\t$0, 0(%0)\n\t" - "bne\t%0, %1, 1b\n\t" - "daddu\t%0, 32\n\t" - - "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t" - "nop; nop; nop; nop;\n\t" - ".set\tmips0\n\t" - ".set\treorder" - : "=r" (first), "=r" (last), "=&r" (tmp) - : "0" (first), "1" (last) - : "$1"); -} - -static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) -{ - unsigned long first_line, last_line; - unsigned int flags; - -#ifdef DEBUG_CACHE - printk("indy_sc_wback_invalidate[%08lx,%08lx]", addr, size); -#endif - - if (!size) - return; - - /* Which lines to flush? */ - first_line = SC_INDEX(addr); - last_line = SC_INDEX(addr + size - 1); - - __save_and_cli(flags); - if (first_line <= last_line) { - indy_sc_wipe(first_line, last_line); - goto out; - } - - indy_sc_wipe(first_line, SC_SIZE - SC_LINE); - indy_sc_wipe(0, last_line); -out: - __restore_flags(flags); -} - -static void indy_sc_enable(void) -{ - unsigned long addr, tmp1, tmp2; - - /* This is really cool... */ -#ifdef DEBUG_CACHE - printk("Enabling R4600 SCACHE\n"); -#endif - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - ".set\tmips3\n\t" - "mfc0\t%2, $12\n\t" - "nop; nop; nop; nop;\n\t" - "li\t%1, 0x80\n\t" - "mtc0\t%1, $12\n\t" - "nop; nop; nop; nop;\n\t" - "li\t%0, 0x1\n\t" - "dsll\t%0, 31\n\t" - "lui\t%1, 0x9000\n\t" - "dsll32\t%1, 0\n\t" - "or\t%0, %1, %0\n\t" - "sb\t$0, 0(%0)\n\t" - "mtc0\t$0, $12\n\t" - "nop; nop; nop; nop;\n\t" - "mtc0\t%2, $12\n\t" - "nop; nop; nop; nop;\n\t" - ".set\tpop" - : "=r" (tmp1), "=r" (tmp2), "=r" (addr)); -} - -static void indy_sc_disable(void) -{ - unsigned long tmp1, tmp2, tmp3; - -#ifdef DEBUG_CACHE - printk("Disabling R4600 SCACHE\n"); -#endif - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - ".set\tmips3\n\t" - "li\t%0, 0x1\n\t" - "dsll\t%0, 31\n\t" - "lui\t%1, 0x9000\n\t" - "dsll32\t%1, 0\n\t" - "or\t%0, %1, %0\n\t" - "mfc0\t%2, $12\n\t" - "nop; nop; nop; nop\n\t" - "li\t%1, 0x80\n\t" - "mtc0\t%1, $12\n\t" - "nop; nop; nop; nop\n\t" - "sh\t$0, 0(%0)\n\t" - "mtc0\t$0, $12\n\t" - "nop; nop; nop; nop\n\t" - "mtc0\t%2, $12\n\t" - "nop; nop; nop; nop\n\t" - ".set\tpop" - : "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)); -} - -static inline int __init indy_sc_probe(void) -{ - volatile unsigned int *cpu_control; - unsigned short cmd = 0xc220; - unsigned long data = 0; - int i, n; - -#ifdef __MIPSEB__ - cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00034); -#else - cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00030); -#endif -#define DEASSERT(bit) (*(cpu_control) &= (~(bit))) -#define ASSERT(bit) (*(cpu_control) |= (bit)) -#define DELAY for(n = 0; n < 100000; n++) __asm__ __volatile__("") - DEASSERT(SGIMC_EEPROM_PRE); - DEASSERT(SGIMC_EEPROM_SDATAO); - DEASSERT(SGIMC_EEPROM_SECLOCK); - DEASSERT(SGIMC_EEPROM_PRE); - DELAY; - ASSERT(SGIMC_EEPROM_CSEL); ASSERT(SGIMC_EEPROM_SECLOCK); - for(i = 0; i < 11; i++) { - if(cmd & (1<<15)) - ASSERT(SGIMC_EEPROM_SDATAO); - else - DEASSERT(SGIMC_EEPROM_SDATAO); - DEASSERT(SGIMC_EEPROM_SECLOCK); - ASSERT(SGIMC_EEPROM_SECLOCK); - cmd <<= 1; - } - DEASSERT(SGIMC_EEPROM_SDATAO); - for(i = 0; i < (sizeof(unsigned short) * 8); i++) { - unsigned int tmp; - - DEASSERT(SGIMC_EEPROM_SECLOCK); - DELAY; - ASSERT(SGIMC_EEPROM_SECLOCK); - DELAY; - data <<= 1; - tmp = *cpu_control; - if(tmp & SGIMC_EEPROM_SDATAI) - data |= 1; - } - DEASSERT(SGIMC_EEPROM_SECLOCK); - DEASSERT(SGIMC_EEPROM_CSEL); - ASSERT(SGIMC_EEPROM_PRE); - ASSERT(SGIMC_EEPROM_SECLOCK); - - data <<= PAGE_SHIFT; - if (data == 0) - return 0; - - scache_size = data; - - printk("R4600/R5000 SCACHE size %ldK, linesize 32 bytes.\n", - scache_size >> 10); - - return 1; -} - -/* XXX Check with wje if the Indy caches can differenciate between - writeback + invalidate and just invalidate. */ -struct bcache_ops indy_sc_ops = { - indy_sc_enable, - indy_sc_disable, - indy_sc_wback_invalidate, - indy_sc_wback_invalidate -}; - -void __init indy_sc_init(void) -{ - if (indy_sc_probe()) { - indy_sc_enable(); - bcops = &indy_sc_ops; - } -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/reset.c linux-2.4.19-pre5/arch/mips/sgi/kernel/reset.c --- linux-2.4.18/arch/mips/sgi/kernel/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/reset.c Thu Jan 1 01:00:00 1970 @@ -1,241 +0,0 @@ -/* - * 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) 1997, 1998, 2001 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. - * I'm not shure if this feature is a good idea, for now it's here just to - * make the power button make behave just like under IRIX. - */ -#define POWERDOWN_TIMEOUT 120 - -/* - * Blink frequency during reboot grace period and when paniced. - */ -#define POWERDOWN_FREQ (HZ / 4) -#define PANIC_FREQ (HZ / 8) - -static unsigned char sgi_volume; - -static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; -static int shuting_down, has_paniced; - -static void sgi_machine_restart(char *command) __attribute__((noreturn)); -static void sgi_machine_halt(void) __attribute__((noreturn)); -static void sgi_machine_power_off(void) __attribute__((noreturn)); - -/* XXX How to pass the reboot command to the firmware??? */ -static void sgi_machine_restart(char *command) -{ - if (shuting_down) - sgi_machine_power_off(); - prom_reboot(); -} - -static void sgi_machine_halt(void) -{ - if (shuting_down) - sgi_machine_power_off(); - ArcEnterInteractiveMode(); -} - -static void sgi_machine_power_off(void) -{ - struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; - - cli(); - - clock->cmd |= 0x08; /* Disable watchdog */ - clock->whsec = 0; - clock->wsec = 0; - - while(1) { - hpc3mregs->panel=0xfe; - /* Good bye cruel world ... */ - - /* If we're still running, we probably got sent an alarm - interrupt. Read the flag to clear it. */ - clock->halarm; - } -} - -static void power_timeout(unsigned long data) -{ - sgi_machine_power_off(); -} - -static void blink_timeout(unsigned long data) -{ - /* XXX fix this for fullhouse */ - sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF); - hpc3mregs->write1 = sgi_hpc_write1; - - mod_timer(&blink_timer, jiffies+data); -} - -static void debounce(unsigned long data) -{ - del_timer(&debounce_timer); - if (ioc_icontrol->istat1 & 2) { /* Interrupt still being sent. */ - debounce_timer.expires = jiffies + 5; /* 0.05s */ - add_timer(&debounce_timer); - - hpc3mregs->panel = 0xf3; - - return; - } - - if (has_paniced) - prom_reboot(); - - enable_irq(SGI_PANEL_IRQ); -} - -static inline void power_button(void) -{ - if (has_paniced) - return; - - if (shuting_down || kill_proc(1, SIGINT, 1)) { - /* No init process or button pressed twice. */ - sgi_machine_power_off(); - } - - shuting_down = 1; - blink_timer.data = POWERDOWN_FREQ; - blink_timeout(POWERDOWN_FREQ); - - init_timer(&power_timer); - power_timer.function = power_timeout; - power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; - add_timer(&power_timer); -} - -void inline sgi_volume_set(unsigned char volume) -{ - sgi_volume = volume; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; -} - -void inline sgi_volume_get(unsigned char *volume) -{ - *volume = sgi_volume; -} - -static inline void volume_up_button(unsigned long data) -{ - del_timer(&volume_timer); - - if (sgi_volume < 0xff) - sgi_volume++; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; - - if (ioc_icontrol->istat1 & 2) { - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } - -} - -static inline void volume_down_button(unsigned long data) -{ - del_timer(&volume_timer); - - if (sgi_volume > 0) - sgi_volume--; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; - - if (ioc_icontrol->istat1 & 2) { - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } -} - -static void panel_int(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int buttons; - - buttons = hpc3mregs->panel; - hpc3mregs->panel = 3; /* power_interrupt | power_supply_on */ - - if (ioc_icontrol->istat1 & 2) { /* Wait until interrupt goes away */ - disable_irq(SGI_PANEL_IRQ); - init_timer(&debounce_timer); - debounce_timer.function = debounce; - debounce_timer.expires = jiffies + 5; - add_timer(&debounce_timer); - } - - if (!(buttons & 2)) /* Power button was pressed */ - power_button(); - if (!(buttons & 0x40)) { /* Volume up button was pressed */ - init_timer(&volume_timer); - volume_timer.function = volume_up_button; - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } - if (!(buttons & 0x10)) { /* Volume down button was pressed */ - init_timer(&volume_timer); - volume_timer.function = volume_down_button; - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } -} - -static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - if (has_paniced) - return NOTIFY_DONE; - has_paniced = 1; - - blink_timer.data = PANIC_FREQ; - blink_timeout(PANIC_FREQ); - - return NOTIFY_DONE; -} - -static struct notifier_block panic_block = { - panic_event, - NULL, - 0 -}; - -void indy_reboot_setup(void) -{ - static int setup_done; - - if (setup_done) - return; - setup_done = 1; - - _machine_restart = sgi_machine_restart; - _machine_halt = sgi_machine_halt; - _machine_power_off = sgi_machine_power_off; - - request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); - init_timer(&blink_timer); - blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/setup.c linux-2.4.19-pre5/arch/mips/sgi/kernel/setup.c --- linux-2.4.18/arch/mips/sgi/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/setup.c Thu Jan 1 01:00:00 1970 @@ -1,308 +0,0 @@ -/* - * setup.c: SGI specific setup, including init of the feature struct. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_REMOTE_DEBUG -extern void rs_kgdb_hook(int); -extern void breakpoint(void); -static int remote_debug = 0; -#endif - -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_ARC_CONSOLE) -extern void console_setup(char *); -#endif - -extern unsigned long r4k_interval; /* Cycle counter ticks per 1/HZ seconds */ - -extern struct rtc_ops indy_rtc_ops; -void indy_reboot_setup(void); -void sgi_volume_set(unsigned char); - -#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64)) - -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ - -static void sgi_request_region(void) -{ - /* No I/O ports are being used on the Indy. */ -} - -static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *)) -{ - /* Dirty hack, this get's called as a callback from the keyboard - driver. We piggyback the initialization of the front panel - button handling on it even though they're technically not - related with the keyboard driver in any way. Doing it from - indy_setup wouldn't work since kmalloc isn't initialized yet. */ - indy_reboot_setup(); - - return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL); -} - -static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) -{ - /* Nothing to do, interrupt is shared with the keyboard hw */ - return 0; -} - -static void sgi_aux_free_irq(void) -{ - /* Nothing to do, interrupt is shared with the keyboard hw */ -} - -static unsigned char sgi_read_input(void) -{ - return sgi_kh->data; -} - -static void sgi_write_output(unsigned char val) -{ - int status; - - do { - status = sgi_kh->command; - } while (status & KBD_STAT_IBF); - sgi_kh->data = val; -} - -static void sgi_write_command(unsigned char val) -{ - int status; - - do { - status = sgi_kh->command; - } while (status & KBD_STAT_IBF); - sgi_kh->command = val; -} - -static unsigned char sgi_read_status(void) -{ - return sgi_kh->command; -} - -struct kbd_ops sgi_kbd_ops = { - sgi_request_region, - sgi_request_irq, - - sgi_aux_request_irq, - sgi_aux_free_irq, - - sgi_read_input, - sgi_write_output, - sgi_write_command, - sgi_read_status -}; - -static unsigned long dosample(volatile unsigned char *tcwp, - volatile unsigned char *tc2p) -{ - unsigned long ct0, ct1; - unsigned char msb, lsb; - - /* Start the counter. */ - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN); - *tc2p = (SGINT_TCSAMP_COUNTER & 0xff); - *tc2p = (SGINT_TCSAMP_COUNTER >> 8); - - /* Get initial counter invariant */ - ct0 = read_32bit_cp0_register(CP0_COUNT); - - /* Latch and spin until top byte of counter2 is zero */ - do { - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT); - lsb = *tc2p; - msb = *tc2p; - ct1 = read_32bit_cp0_register(CP0_COUNT); - } while(msb); - - /* Stop the counter. */ - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST); - - /* - * Return the difference, this is how far the r4k counter increments - * for every 1/HZ seconds. We round off the nearest 1 MHz of master - * clock (= 1000000 / 100 / 2 = 5000 count). - */ - - return ((ct1 - ct0) / 5000) * 5000; -} - -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) - -void sgi_time_init (struct irqaction *irq) { - /* Here we need to calibrate the cycle counter to at least be close. - * We don't need to actually register the irq handler because that's - * all done in indyIRQ.S. - */ - struct sgi_ioc_timers *p; - volatile unsigned char *tcwp, *tc2p; - unsigned long r4k_ticks[3]; - unsigned long r4k_next; - - /* Figure out the r4k offset, the algorithm is very simple - * and works in _all_ cases as long as the 8254 counter - * register itself works ok (as an interrupt driving timer - * it does not because of bug, this is why we are using - * the onchip r4k counter/compare register to serve this - * purpose, but for r4k_offset calculation it will work - * ok for us). There are other very complicated ways - * of performing this calculation but this one works just - * fine so I am not going to futz around. ;-) - */ - p = ioc_timers; - tcwp = &p->tcword; - tc2p = &p->tcnt2; - - printk("Calibrating system timer... "); - dosample(tcwp, tc2p); /* Prime cache. */ - dosample(tcwp, tc2p); /* Prime cache. */ - /* Zero is NOT an option. */ - do { - r4k_ticks[0] = dosample (tcwp, tc2p); - } while (!r4k_ticks[0]); - do { - r4k_ticks[1] = dosample (tcwp, tc2p); - } while (!r4k_ticks[1]); - - if (r4k_ticks[0] != r4k_ticks[1]) { - printk ("warning: timer counts differ, retrying..."); - r4k_ticks[2] = dosample (tcwp, tc2p); - if (r4k_ticks[2] == r4k_ticks[0] - || r4k_ticks[2] == r4k_ticks[1]) - r4k_interval = r4k_ticks[2]; - else { - printk ("disagreement, using average..."); - r4k_interval = (r4k_ticks[0] + r4k_ticks[1] - + r4k_ticks[2]) / 3; - } - } else - r4k_interval = r4k_ticks[0]; - - printk("%d [%d.%02d MHz CPU]\n", (int) r4k_interval, - (int) (r4k_interval / 5000), (int) (r4k_interval % 5000) / 50); - - /* Set ourselves up for future interrupts */ - r4k_next = (read_32bit_cp0_register(CP0_COUNT) + r4k_interval); - write_32bit_cp0_register(CP0_COMPARE, r4k_next); - change_cp0_status(ST0_IM, ALLINTS); - sti (); -} - -void __init sgi_setup(void) -{ -#ifdef CONFIG_SERIAL_CONSOLE - char *ctype; -#endif -#ifdef CONFIG_REMOTE_DEBUG - char *kgdb_ttyd; -#endif - - board_time_init = sgi_time_init; - - /* Init the INDY HPC I/O controller. Need to call this before - * fucking with the memory controller because it needs to know the - * boardID and whether this is a Guiness or a FullHouse machine. - */ - sgihpc_init(); - - /* Init INDY memory controller. */ - sgimc_init(); - - /* Now enable boardcaches, if any. */ - indy_sc_init(); - -#ifdef CONFIG_SERIAL_CONSOLE - /* ARCS console environment variable is set to "g?" for - * graphics console, it is set to "d" for the first serial - * line and "d2" for the second serial line. - */ - ctype = ArcGetEnvironmentVariable("console"); - if(*ctype == 'd') { - if(*(ctype+1)=='2') - console_setup ("ttyS1"); - else - console_setup ("ttyS0"); - } -#endif - -#ifdef CONFIG_REMOTE_DEBUG - kgdb_ttyd = prom_getcmdline(); - if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) { - int line; - kgdb_ttyd += strlen("kgdb=ttyd"); - if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2') - printk("KGDB: Uknown serial line /dev/ttyd%c, " - "falling back to /dev/ttyd1\n", *kgdb_ttyd); - line = *kgdb_ttyd == '2' ? 0 : 1; - printk("KGDB: Using serial line /dev/ttyd%d for session\n", - line ? 1 : 2); - rs_kgdb_hook(line); - - printk("KGDB: Using serial line /dev/ttyd%d for session, " - "please connect your debugger\n", line ? 1 : 2); - - remote_debug = 1; - /* Breakpoints and stuff are in sgi_irq_setup() */ - } -#endif - -#ifdef CONFIG_ARC_CONSOLE - console_setup("ttyS0"); -#endif - - sgi_volume_set(simple_strtoul(ArcGetEnvironmentVariable("volume"), NULL, 10)); - -#ifdef CONFIG_VT -#ifdef CONFIG_SGI_NEWPORT_CONSOLE - conswitchp = &newport_con; - - screen_info = (struct screen_info) { - 0, 0, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig_video_page */ - 0, /* orig_video_mode */ - 160, /* orig_video_cols */ - 0, 0, 0, /* unused, ega_bx, unused */ - 64, /* orig_video_lines */ - 0, /* orig_video_isVGA */ - 16 /* orig_video_points */ - }; -#else - conswitchp = &dummy_con; -#endif -#endif - - rtc_ops = &indy_rtc_ops; - kbd_ops = &sgi_kbd_ops; -#ifdef CONFIG_PSMOUSE - aux_device_present = 0xaa; -#endif -#ifdef CONFIG_VIDEO_VINO - init_vino(); -#endif -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/system.c linux-2.4.19-pre5/arch/mips/sgi/kernel/system.c --- linux-2.4.18/arch/mips/sgi/kernel/system.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/system.c Thu Jan 1 01:00:00 1970 @@ -1,132 +0,0 @@ -/* - * system.c: Probe the system type using ARCS prom interface library. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: system.c,v 1.8 1999/10/09 00:00:59 ralf Exp $ - */ -#include -#include -#include -#include - -#include -#include -#include - -enum sgi_mach sgimach; - -struct smatch { - char *name; - int type; -}; - -static struct smatch sgi_cputable[] = { - { "MIPS-R2000", CPU_R2000 }, - { "MIPS-R3000", CPU_R3000 }, - { "MIPS-R3000A", CPU_R3000A }, - { "MIPS-R4000", CPU_R4000SC }, - { "MIPS-R4400", CPU_R4400SC }, - { "MIPS-R4600", CPU_R4600 }, - { "MIPS-R8000", CPU_R8000 }, - { "MIPS-R5000", CPU_R5000 }, - { "MIPS-R5000A", CPU_R5000A } -}; - -#define NUM_CPUS 9 /* for now */ - -static int __init string_to_cpu(char *s) -{ - int i; - - for(i = 0; i < NUM_CPUS; i++) { - if(!strcmp(s, sgi_cputable[i].name)) - return sgi_cputable[i].type; - } - prom_printf("\nYeee, could not determine MIPS cpu type <%s>\n", s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - return 0; -} - -/* - * We' call this early before loadmmu(). If we do the other way around - * the firmware will crash and burn. - */ -void __init sgi_sysinit(void) -{ - pcomponent *p, *toplev, *cpup = 0; - int cputype = -1; - - - /* The root component tells us what machine architecture we - * have here. - */ - p = prom_getchild(PROM_NULL_COMPONENT); - - /* Now scan for cpu(s). */ - toplev = p = prom_getchild(p); - while(p) { - int ncpus = 0; - - if(p->type == Cpu) { - if(++ncpus > 1) { - prom_printf("\nYeee, SGI MP not ready yet\n"); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - } - printk("CPU: %s ", p->iname); - cpup = p; - cputype = string_to_cpu(cpup->iname); - } - p = prom_getsibling(p); - } - if(cputype == -1) { - prom_printf("\nYeee, could not find cpu ARCS component\n"); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - } - p = prom_getchild(cpup); - while(p) { - switch(p->class) { - case processor: - switch(p->type) { - case Fpu: - printk("FPU<%s> ", p->iname); - break; - - default: - break; - }; - break; - - case cache: - switch(p->type) { - case picache: - printk("ICACHE "); - break; - - case pdcache: - printk("DCACHE "); - break; - - case sccache: - printk("SCACHE "); - break; - - default: - break; - - }; - break; - - default: - break; - }; - p = prom_getsibling(p); - } - printk("\n"); -} diff -urN linux-2.4.18/arch/mips/sgi/kernel/time.c linux-2.4.19-pre5/arch/mips/sgi/kernel/time.c --- linux-2.4.18/arch/mips/sgi/kernel/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sgi/kernel/time.c Thu Jan 1 01:00:00 1970 @@ -1,21 +0,0 @@ -/* - * time.c: Generic SGI handler for (spurious) 8254 interrupts - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include -#include -#include - -void indy_8254timer_irq(void) -{ - int cpu = smp_processor_id(); - int irq = 4; - - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); - prom_getchar(); - ArcEnterInteractiveMode(); - irq_exit(cpu, irq); -} diff -urN linux-2.4.18/arch/mips/sgi-ip22/Makefile linux-2.4.19-pre5/arch/mips/sgi-ip22/Makefile --- linux-2.4.18/arch/mips/sgi-ip22/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,25 @@ +# +# Makefile for the SGI specific kernel interface routines +# under Linux. +# +# 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: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := ip22-kern.o + +all: ip22-kern.o ip22-irq.o + +obj-y += ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-rtc.o \ + ip22-irq.o ip22-system.o ip22-reset.o ip22-setup.o + +ip22-irq.o: ip22-irq.S + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-hpc.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-hpc.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-hpc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-hpc.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,92 @@ +/* + * ip22-hpc.c: Routines for generic manipulation of the HPC controllers. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1998 Ralf Baechle + */ +#include +#include + +#include +#include +#include +#include +#include + +#if 0 +#define HPC_DEBUG(args...) printk(args) +#else +#define HPC_DEBUG(args...) +#endif + +struct hpc3_regs *hpc3c0, *hpc3c1; +struct hpc3_miscregs *hpc3mregs; + +/* We need software copies of these because they are write only. */ +u32 sgi_hpc_write1, sgi_hpc_write2; + +/* Machine specific identifier knobs. */ +int sgi_has_ioc2 = 0; +int sgi_guiness = 0; +int sgi_boardid; + +extern char *system_type; + +void __init sgihpc_init(void) +{ + unsigned int sid, crev, brev; + + hpc3c0 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP0_PBASE); + hpc3c1 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP1_PBASE); + hpc3mregs = (struct hpc3_miscregs *) (KSEG1 + HPC3_MREGS_PBASE); + sid = hpc3mregs->sysid; + + sid &= 0xff; + crev = (sid & 0xe0) >> 5; + brev = (sid & 0x1e) >> 1; + + HPC_DEBUG("sgihpc_init: crev<%2x> brev<%2x>\n", crev, brev); + HPC_DEBUG("sgihpc_init: "); + + /* This test works now thanks to William J. Earl */ + if ((sid & 1) == 0 ) { + HPC_DEBUG("GUINESS "); + sgi_guiness = 1; + mips_machtype = MACH_SGI_INDY; + system_type = "SGI Indy"; + } else { + HPC_DEBUG("FULLHOUSE "); + mips_machtype = MACH_SGI_INDIGO2; + sgi_guiness = 0; + system_type = "SGI Indigo2"; + } + sgi_boardid = brev; + + HPC_DEBUG("sgi_boardid<%d> ", sgi_boardid); + + if(crev == 1) { + if((sid & 1) || (brev >= 2)) { + HPC_DEBUG("IOC2 "); + sgi_has_ioc2 = 1; + } else { + HPC_DEBUG("IOC1 revision 1 "); + } + } else { + HPC_DEBUG("IOC1 revision 0 "); + } + HPC_DEBUG("\n"); + + sgi_hpc_write1 = (HPC3_WRITE1_PRESET | HPC3_WRITE1_KMRESET | + HPC3_WRITE1_ERESET | HPC3_WRITE1_LC0OFF); + + sgi_hpc_write2 = (HPC3_WRITE2_EASEL | HPC3_WRITE2_NTHRESH | + HPC3_WRITE2_TPSPEED | HPC3_WRITE2_EPSEL | + HPC3_WRITE2_U0AMODE | HPC3_WRITE2_U1AMODE); + + if(!sgi_guiness) + sgi_hpc_write1 |= HPC3_WRITE1_GRESET; + hpc3mregs->write1 = sgi_hpc_write1; + hpc3mregs->write2 = sgi_hpc_write2; + + hpc3c0->pbus_piocfgs[0][6] |= HPC3_PIOPCFG_HW; +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-int.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-int.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-int.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-int.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,419 @@ +/* + * ip22-int.c: Routines for generic manipulation of the INT[23] ASIC + * found on INDY and Indigo2 workstations.. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) + * - Indigo2 changes + * - Interrupt handling fixes + * Copyright (C) 2001 Ladislav Michl (ladis@psi.cz) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* #define DEBUG_SGINT */ +#undef I_REALLY_NEED_THIS_IRQ + +struct sgi_int2_regs *sgi_i2regs; +struct sgi_int3_regs *sgi_i3regs; +struct sgi_ioc_ints *ioc_icontrol; +struct sgi_ioc_timers *ioc_timers; +volatile unsigned char *ioc_tclear; + +static char lc0msk_to_irqnr[256]; +static char lc1msk_to_irqnr[256]; +static char lc2msk_to_irqnr[256]; +static char lc3msk_to_irqnr[256]; + +extern asmlinkage void indyIRQ(void); +extern void do_IRQ(int irq, struct pt_regs *regs); + +static void enable_local0_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + /* don't allow mappable interrupt to be enabled from setup_irq, + * we have our own way to do so */ + if (irq != SGI_MAP_0_IRQ) + ioc_icontrol->imask0 |= (1 << (irq - SGINT_LOCAL0)); + restore_flags(flags); +} + +static unsigned int startup_local0_irq(unsigned int irq) +{ + enable_local0_irq(irq); + return 0; /* Never anything pending */ +} + +static void disable_local0_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); + restore_flags(flags); +} + +#define shutdown_local0_irq disable_local0_irq +#define mask_and_ack_local0_irq disable_local0_irq + +static void end_local0_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_local0_irq(irq); +} + +static struct hw_interrupt_type ip22_local0_irq_type = { + "IP22 local 0", + startup_local0_irq, + shutdown_local0_irq, + enable_local0_irq, + disable_local0_irq, + mask_and_ack_local0_irq, + end_local0_irq, + NULL +}; + +static void enable_local1_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + /* don't allow mappable interrupt to be enabled from setup_irq, + * we have our own way to do so */ + if (irq != SGI_MAP_1_IRQ) + ioc_icontrol->imask1 |= (1 << (irq - SGINT_LOCAL1)); + restore_flags(flags); +} + +static unsigned int startup_local1_irq(unsigned int irq) +{ + enable_local1_irq(irq); + return 0; /* Never anything pending */ +} + +void disable_local1_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); + restore_flags(flags); +} + +#define shutdown_local1_irq disable_local1_irq +#define mask_and_ack_local1_irq disable_local1_irq + +static void end_local1_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_local1_irq(irq); +} + +static struct hw_interrupt_type ip22_local1_irq_type = { + "IP22 local 1", + startup_local1_irq, + shutdown_local1_irq, + enable_local1_irq, + disable_local1_irq, + mask_and_ack_local1_irq, + end_local1_irq, + NULL +}; + +static void enable_local2_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); + ioc_icontrol->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); + restore_flags(flags); +} + +static unsigned int startup_local2_irq(unsigned int irq) +{ + enable_local2_irq(irq); + return 0; /* Never anything pending */ +} + +void disable_local2_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); + if (!ioc_icontrol->cmeimask0) + ioc_icontrol->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); + restore_flags(flags); +} + +#define shutdown_local2_irq disable_local2_irq +#define mask_and_ack_local2_irq disable_local2_irq + +static void end_local2_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_local2_irq(irq); +} + +static struct hw_interrupt_type ip22_local2_irq_type = { + "IP22 local 2", + startup_local2_irq, + shutdown_local2_irq, + enable_local2_irq, + disable_local2_irq, + mask_and_ack_local2_irq, + end_local2_irq, + NULL +}; + +static void enable_local3_irq(unsigned int irq) +{ +#ifdef I_REALLY_NEED_THIS_IRQ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); + ioc_icontrol->cmeimask1 |= (1 << (irq - SGINT_LOCAL3)); + restore_flags(flags); +#else + panic("Who need local 3 irq? see ip22-int.c"); +#endif +} + +static unsigned int startup_local3_irq(unsigned int irq) +{ + enable_local3_irq(irq); + return 0; /* Never anything pending */ +} + +void disable_local3_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + ioc_icontrol->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3)); + if (!ioc_icontrol->cmeimask1) + ioc_icontrol->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); + restore_flags(flags); +} + +#define shutdown_local3_irq disable_local3_irq +#define mask_and_ack_local3_irq disable_local3_irq + +static void end_local3_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_local3_irq(irq); +} + +static struct hw_interrupt_type ip22_local3_irq_type = { + "IP22 local 3", + startup_local3_irq, + shutdown_local3_irq, + enable_local3_irq, + disable_local3_irq, + mask_and_ack_local3_irq, + end_local3_irq, + NULL +}; + +void indy_local0_irqdispatch(struct pt_regs *regs) +{ + unsigned char mask = ioc_icontrol->istat0; + unsigned char mask2 = 0; + int irq; + + mask &= ioc_icontrol->imask0; + if (mask & ISTAT0_LIO2) { + mask2 = ioc_icontrol->vmeistat; + mask2 &= ioc_icontrol->cmeimask0; + irq = lc2msk_to_irqnr[mask2]; + } else { + irq = lc0msk_to_irqnr[mask]; + } + + /* if irq == 0, then the interrupt has already been cleared */ + if (irq) + do_IRQ(irq, regs); + return; +} + +void indy_local1_irqdispatch(struct pt_regs *regs) +{ + unsigned char mask = ioc_icontrol->istat1; + unsigned char mask2 = 0; + int irq; + + mask &= ioc_icontrol->imask1; + if (mask & ISTAT1_LIO3) { +#ifndef I_REALLY_NEED_THIS_IRQ + printk("Whee: Got an LIO3 irq, winging it...\n"); +#endif + mask2 = ioc_icontrol->vmeistat; + mask2 &= ioc_icontrol->cmeimask1; + irq = lc3msk_to_irqnr[mask2]; + } else { + irq = lc1msk_to_irqnr[mask]; + } + + /* if irq == 0, then the interrupt has already been cleared */ + if (irq) + do_IRQ(irq, regs); + return; +} + +void indy_buserror_irq(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int irq = SGI_BUSERR_IRQ; + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + die("Got a bus error IRQ, shouldn't happen yet\n", regs); + printk("Spinning...\n"); + while(1); + irq_exit(cpu, irq); +} + +static struct irqaction local0_cascade = + { no_action, SA_INTERRUPT, 0, "local0 cascade", NULL, NULL }; +static struct irqaction local1_cascade = + { no_action, SA_INTERRUPT, 0, "local1 cascade", NULL, NULL }; +static struct irqaction buserr = + { no_action, SA_INTERRUPT, 0, "Bus Error", NULL, NULL }; +static struct irqaction map0_cascade = + { no_action, SA_INTERRUPT, 0, "mappable0 cascade", NULL, NULL }; +#ifdef I_REALLY_NEED_THIS_IRQ +static struct irqaction map1_cascade = + { no_action, SA_INTERRUPT, 0, "mappable1 cascade", NULL, NULL }; +#endif + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +extern void mips_cpu_irq_init(u32 irq_base); + +void __init init_IRQ(void) +{ + int i; + + sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE); + sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE); + + /* Init local mask --> irq tables. */ + for (i = 0; i < 256; i++) { + if (i & 0x80) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7; + } else if (i & 0x40) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6; + } else if (i & 0x20) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5; + } else if (i & 0x10) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4; + } else if (i & 0x08) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3; + } else if (i & 0x04) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2; + } else if (i & 0x02) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1; + } else if (i & 0x01) { + lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0; + lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0; + lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0; + lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0; + } else { + lc0msk_to_irqnr[i] = 0; + lc1msk_to_irqnr[i] = 0; + lc2msk_to_irqnr[i] = 0; + lc3msk_to_irqnr[i] = 0; + } + } + + /* Indy uses an INT3, Indigo2 uses an INT2 */ + if (sgi_guiness) { + ioc_icontrol = &sgi_i3regs->ints; + ioc_timers = &sgi_i3regs->timers; + ioc_tclear = &sgi_i3regs->tclear; + } else { + ioc_icontrol = &sgi_i2regs->ints; + ioc_timers = &sgi_i2regs->timers; + ioc_tclear = &sgi_i2regs->tclear; + } + + /* Mask out all interrupts. */ + ioc_icontrol->imask0 = 0; + ioc_icontrol->imask1 = 0; + ioc_icontrol->cmeimask0 = 0; + ioc_icontrol->cmeimask1 = 0; + + set_except_vector(0, indyIRQ); + + init_generic_irq(); + /* init CPU irqs */ + mips_cpu_irq_init(SGINT_CPU); + + for (i = SGINT_LOCAL0; i < SGINT_END; i++) { + hw_irq_controller *handler; + + if (i < SGINT_LOCAL1) + handler = &ip22_local0_irq_type; + else if (i < SGINT_LOCAL2) + handler = &ip22_local1_irq_type; + else if (i < SGINT_LOCAL3) + handler = &ip22_local2_irq_type; + else + handler = &ip22_local3_irq_type; + + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = handler; + } + + /* vector handler. this register the IRQ as non-sharable */ + setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade); + setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade); + setup_irq(SGI_BUSERR_IRQ, &buserr); + + /* cascade in cascade. i love Indy ;-) */ + setup_irq(SGI_MAP_0_IRQ, &map0_cascade); +#ifdef I_REALLY_NEED_THIS_IRQ + setup_irq(SGI_MAP_1_IRQ, &map1_cascade); +#endif +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-irq.S linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-irq.S --- linux-2.4.18/arch/mips/sgi-ip22/ip22-irq.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-irq.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,125 @@ +/* + * ip22-irq.S: Interrupt exception dispatch code for FullHouse and + * Guiness. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ + +#include +#include +#include +#include + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(indyIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 s0, CP0_CAUSE # get irq mask + + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP7 + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero + + /* Wheee, a timer interrupt. */ + move a0, sp + jal indy_r4k_timer_interrupt + nop # delay slot + + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP3 # delay slot, check local level one + + /* Wheee, local level zero interrupt. */ + jal indy_local0_irqdispatch + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP6 # delay slot, check bus error + + /* Wheee, local level one interrupt. */ + move a0, sp + jal indy_local1_irqdispatch + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, an asynchronous bus error... */ + move a0, sp + jal indy_buserror_irq + nop + + j ret_from_irq + nop + +1: + /* Here by mistake? It is possible, that by the time we take + * the exception the IRQ pin goes low, so just leave if this + * is the case. + */ + andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) + beq a0, zero, 1f + + /* Must be one of the 8254 timers... */ + move a0, sp + jal indy_8254timer_irq + nop +1: + j ret_from_irq + nop + END(indyIRQ) diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-mc.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-mc.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-mc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-mc.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,164 @@ +/* + * ip22-mc.c: Routines for manipulating the INDY memory controller. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes + */ +#include +#include + +#include +#include +#include +#include +#include + +/* #define DEBUG_SGIMC */ + +struct sgimc_misc_ctrl *mcmisc_regs; +u32 *rpsscounter; +struct sgimc_dma_ctrl *dmactrlregs; + +static inline char *mconfig_string(unsigned long val) +{ + switch(val & SGIMC_MCONFIG_RMASK) { + case SGIMC_MCONFIG_FOURMB: + return "4MB"; + + case SGIMC_MCONFIG_EIGHTMB: + return "8MB"; + + case SGIMC_MCONFIG_SXTEENMB: + return "16MB"; + + case SGIMC_MCONFIG_TTWOMB: + return "32MB"; + + case SGIMC_MCONFIG_SFOURMB: + return "64MB"; + + case SGIMC_MCONFIG_OTEIGHTMB: + return "128MB"; + + default: + return "wheee, unknown"; + }; +} + +void __init sgimc_init(void) +{ + unsigned long tmpreg; + + mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); + rpsscounter = (unsigned int *) (KSEG1 + 0x1fa01004); + dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000); + + printk("MC: SGI memory controller Revision %d\n", + (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV); + +#if 0 /* XXX Until I figure out what this bit really indicates XXX */ + /* XXX Is this systemid bit reliable? */ + if(mcmisc_regs->systemid & SGIMC_SYSID_EPRESENT) { + EISA_bus = 1; + printk("with EISA\n"); + } else { + EISA_bus = 0; + printk("no EISA\n"); + } +#endif + +#ifdef DEBUG_SGIMC + prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n", + mconfig_string(mcmisc_regs->mconfig0), + mconfig_string(mcmisc_regs->mconfig1)); + + prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n", + mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1); + prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n", + mcmisc_regs->divider, mcmisc_regs->gioparm); +#endif + + /* Place the MC into a known state. This must be done before + * interrupts are first enabled etc. + */ + + /* Step 0: Make sure we turn off the watchdog in case it's + * still running (which might be the case after a + * soft reboot). + */ + tmpreg = mcmisc_regs->cpuctrl0; + tmpreg &= ~SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = tmpreg; + + /* Step 1: The CPU/GIO error status registers will not latch + * up a new error status until the register has been + * cleared by the cpu. These status registers are + * cleared by writing any value to them. + */ + mcmisc_regs->cstat = mcmisc_regs->gstat = 0; + + /* Step 2: Enable all parity checking in cpu control register + * zero. + */ + tmpreg = mcmisc_regs->cpuctrl0; + tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | + SGIMC_CCTRL0_R4KNOCHKPARR); + mcmisc_regs->cpuctrl0 = tmpreg; + + /* Step 3: Setup the MC write buffer depth, this is controlled + * in cpu control register 1 in the lower 4 bits. + */ + tmpreg = mcmisc_regs->cpuctrl1; + tmpreg &= ~0xf; + tmpreg |= 0xd; + mcmisc_regs->cpuctrl1 = tmpreg; + + /* Step 4: Initialize the RPSS divider register to run as fast + * as it can correctly operate. The register is laid + * out as follows: + * + * ---------------------------------------- + * | RESERVED | INCREMENT | DIVIDER | + * ---------------------------------------- + * 31 16 15 8 7 0 + * + * DIVIDER determines how often a 'tick' happens, + * INCREMENT determines by how the RPSS increment + * registers value increases at each 'tick'. Thus, + * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 + */ + mcmisc_regs->divider = 0x101; + + /* Step 5: Initialize GIO64 arbitrator configuration register. + * + * NOTE: If you dork with startup code the HPC init code in + * sgihpc_init() must run before us because of how we + * need to know Guiness vs. FullHouse and the board + * revision on this machine. You have been warned. + */ + + /* First the basic invariants across all gio64 implementations. */ + tmpreg = SGIMC_GIOPARM_HPC64; /* All 1st HPC's interface at 64bits. */ + tmpreg |= SGIMC_GIOPARM_ONEBUS; /* Only one physical GIO bus exists. */ + + if(sgi_guiness) { + /* Guiness specific settings. */ + tmpreg |= SGIMC_GIOPARM_EISA64; /* MC talks to EISA at 64bits */ + tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */ + } else { + /* Fullhouse specific settings. */ + if(sgi_boardid < 2) { + tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */ + tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */ + tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */ + tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */ + } else { + tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */ + tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */ + tmpreg |= SGIMC_GIOPARM_PLINEEXP1; + tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */ + tmpreg |= SGIMC_GIOPARM_GFX64; /* GFX at 64 bits */ + } + } + mcmisc_regs->gioparm = tmpreg; /* poof */ +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-reset.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-reset.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-reset.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,242 @@ +/* + * 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) 1997, 1998, 2001 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. + * I'm not sure if this feature is a good idea, for now it's here just to + * make the power button make behave just like under IRIX. + */ +#define POWERDOWN_TIMEOUT 120 + +/* + * Blink frequency during reboot grace period and when paniced. + */ +#define POWERDOWN_FREQ (HZ / 4) +#define PANIC_FREQ (HZ / 8) + +static unsigned char sgi_volume; + +static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; +static int shuting_down = 0, has_paniced = 0, setup_done = 0; + +static void sgi_machine_restart(char *command) __attribute__((noreturn)); +static void sgi_machine_halt(void) __attribute__((noreturn)); +static void sgi_machine_power_off(void) __attribute__((noreturn)); + +/* XXX How to pass the reboot command to the firmware??? */ +static void sgi_machine_restart(char *command) +{ + if (shuting_down) + sgi_machine_power_off(); + ArcReboot(); +} + +static void sgi_machine_halt(void) +{ + if (shuting_down) + sgi_machine_power_off(); + ArcEnterInteractiveMode(); +} + +static void sgi_machine_power_off(void) +{ + unsigned char val; + + cli(); + + /* Disable watchdog */ + val = CMOS_READ(RTC_CMD); + CMOS_WRITE(val|RTC_WAM, RTC_CMD); + CMOS_WRITE(0, RTC_WSEC); + CMOS_WRITE(0, RTC_WHSEC); + + while(1) { + hpc3mregs->panel=0xfe; + /* Good bye cruel world ... */ + + /* If we're still running, we probably got sent an alarm + interrupt. Read the flag to clear it. */ + val = CMOS_READ(RTC_HOURS_ALARM); + } +} + +static void power_timeout(unsigned long data) +{ + sgi_machine_power_off(); +} + +static void blink_timeout(unsigned long data) +{ + /* XXX fix this for fullhouse */ + sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF); + hpc3mregs->write1 = sgi_hpc_write1; + + mod_timer(&blink_timer, jiffies+data); +} + +static void debounce(unsigned long data) +{ + del_timer(&debounce_timer); + if (ioc_icontrol->istat1 & 2) { /* Interrupt still being sent. */ + debounce_timer.expires = jiffies + 5; /* 0.05s */ + add_timer(&debounce_timer); + + hpc3mregs->panel = 0xf3; + + return; + } + + if (has_paniced) + ArcReboot(); + + enable_irq(SGI_PANEL_IRQ); +} + +static inline void power_button(void) +{ + if (has_paniced) + return; + + if (shuting_down || kill_proc(1, SIGINT, 1)) { + /* No init process or button pressed twice. */ + sgi_machine_power_off(); + } + + shuting_down = 1; + blink_timer.data = POWERDOWN_FREQ; + blink_timeout(POWERDOWN_FREQ); + + init_timer(&power_timer); + power_timer.function = power_timeout; + power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; + add_timer(&power_timer); +} + +void inline sgi_volume_set(unsigned char volume) +{ + sgi_volume = volume; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; +} + +void inline sgi_volume_get(unsigned char *volume) +{ + *volume = sgi_volume; +} + +static inline void volume_up_button(unsigned long data) +{ + del_timer(&volume_timer); + + if (sgi_volume < 0xff) + sgi_volume++; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; + + if (ioc_icontrol->istat1 & 2) { + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } + +} + +static inline void volume_down_button(unsigned long data) +{ + del_timer(&volume_timer); + + if (sgi_volume > 0) + sgi_volume--; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; + + if (ioc_icontrol->istat1 & 2) { + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } +} + +static void panel_int(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int buttons; + + buttons = hpc3mregs->panel; + hpc3mregs->panel = 0x03; /* power_interrupt | power_supply_on */ + + if (ioc_icontrol->istat1 & 2) { /* Wait until interrupt goes away */ + disable_irq(SGI_PANEL_IRQ); + init_timer(&debounce_timer); + debounce_timer.function = debounce; + debounce_timer.expires = jiffies + 5; + add_timer(&debounce_timer); + } + + if (!(buttons & 0x02)) /* Power button was pressed */ + power_button(); + if (!(buttons & 0x40)) { /* Volume up button was pressed */ + init_timer(&volume_timer); + volume_timer.function = volume_up_button; + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } + if (!(buttons & 0x10)) { /* Volume down button was pressed */ + init_timer(&volume_timer); + volume_timer.function = volume_down_button; + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } +} + +static int panic_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + if (has_paniced) + return NOTIFY_DONE; + has_paniced = 1; + + blink_timer.data = PANIC_FREQ; + blink_timeout(PANIC_FREQ); + + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + panic_event, + NULL, + 0 +}; + +void indy_reboot_setup(void) +{ + if (setup_done) + return; + setup_done = 1; + + _machine_restart = sgi_machine_restart; + _machine_halt = sgi_machine_halt; + _machine_power_off = sgi_machine_power_off; + + request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); + init_timer(&blink_timer); + blink_timer.function = blink_timeout; + notifier_chain_register(&panic_notifier_list, &panic_block); +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-rtc.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-rtc.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-rtc.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,36 @@ +/* + * 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. + * + * RTC routines for Indy style attached Dallas chip. + * + * Copyright (C) 1998, 2001 by Ralf Baechle + */ +#include +#include + +static unsigned char indy_rtc_read_data(unsigned long addr) +{ + volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; + + return rtcregs[addr]; +} + +static void indy_rtc_write_data(unsigned char data, unsigned long addr) +{ + volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; + + rtcregs[addr] = data; +} + +static int indy_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops indy_rtc_ops = { + &indy_rtc_read_data, + &indy_rtc_write_data, + &indy_rtc_bcd_mode +}; diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-sc.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-sc.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-sc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-sc.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,225 @@ +/* + * ip22-sc.c: Indy cache management functions. + * + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org), + * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Secondary cache size in bytes, if present. */ +static unsigned long scache_size; + +#undef DEBUG_CACHE + +#define SC_SIZE 0x00080000 +#define SC_LINE 32 +#define CI_MASK (SC_SIZE - SC_LINE) +#define SC_INDEX(n) ((n) & CI_MASK) + +static inline void indy_sc_wipe(unsigned long first, unsigned long last) +{ + unsigned long tmp; + + __asm__ __volatile__( + ".set\tnoreorder\t\t\t# indy_sc_wipe\n\t" + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "mfc0\t%2, $12\n\t" + "li\t$1, 0x80\t\t\t# Go 64 bit\n\t" + "mtc0\t$1, $12\n\t" + + "dli\t$1, 0x9000000080000000\n\t" + "or\t%0, $1\t\t\t# first line to flush\n\t" + "or\t%1, $1\t\t\t# last line to flush\n\t" + ".set\tat\n\t" + + "1:\tsw\t$0, 0(%0)\n\t" + "bne\t%0, %1, 1b\n\t" + "daddu\t%0, 32\n\t" + + "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t" + "nop; nop; nop; nop;\n\t" + ".set\tmips0\n\t" + ".set\treorder" + : "=r" (first), "=r" (last), "=&r" (tmp) + : "0" (first), "1" (last)); +} + +static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) +{ + unsigned long first_line, last_line; + unsigned int flags; + +#ifdef DEBUG_CACHE + printk("indy_sc_wback_invalidate[%08lx,%08lx]", addr, size); +#endif + + if (!size) + return; + + /* Which lines to flush? */ + first_line = SC_INDEX(addr); + last_line = SC_INDEX(addr + size - 1); + + __save_and_cli(flags); + if (first_line <= last_line) { + indy_sc_wipe(first_line, last_line); + goto out; + } + + indy_sc_wipe(first_line, SC_SIZE - SC_LINE); + indy_sc_wipe(0, last_line); +out: + __restore_flags(flags); +} + +static void indy_sc_enable(void) +{ + unsigned long addr, tmp1, tmp2; + + /* This is really cool... */ +#ifdef DEBUG_CACHE + printk("Enabling R4600 SCACHE\n"); +#endif + __asm__ __volatile__( + ".set\tpush\n\t" + ".set\tnoreorder\n\t" + ".set\tmips3\n\t" + "mfc0\t%2, $12\n\t" + "nop; nop; nop; nop;\n\t" + "li\t%1, 0x80\n\t" + "mtc0\t%1, $12\n\t" + "nop; nop; nop; nop;\n\t" + "li\t%0, 0x1\n\t" + "dsll\t%0, 31\n\t" + "lui\t%1, 0x9000\n\t" + "dsll32\t%1, 0\n\t" + "or\t%0, %1, %0\n\t" + "sb\t$0, 0(%0)\n\t" + "mtc0\t$0, $12\n\t" + "nop; nop; nop; nop;\n\t" + "mtc0\t%2, $12\n\t" + "nop; nop; nop; nop;\n\t" + ".set\tpop" + : "=r" (tmp1), "=r" (tmp2), "=r" (addr)); +} + +static void indy_sc_disable(void) +{ + unsigned long tmp1, tmp2, tmp3; + +#ifdef DEBUG_CACHE + printk("Disabling R4600 SCACHE\n"); +#endif + __asm__ __volatile__( + ".set\tpush\n\t" + ".set\tnoreorder\n\t" + ".set\tmips3\n\t" + "li\t%0, 0x1\n\t" + "dsll\t%0, 31\n\t" + "lui\t%1, 0x9000\n\t" + "dsll32\t%1, 0\n\t" + "or\t%0, %1, %0\n\t" + "mfc0\t%2, $12\n\t" + "nop; nop; nop; nop\n\t" + "li\t%1, 0x80\n\t" + "mtc0\t%1, $12\n\t" + "nop; nop; nop; nop\n\t" + "sh\t$0, 0(%0)\n\t" + "mtc0\t$0, $12\n\t" + "nop; nop; nop; nop\n\t" + "mtc0\t%2, $12\n\t" + "nop; nop; nop; nop\n\t" + ".set\tpop" + : "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)); +} + +static inline int __init indy_sc_probe(void) +{ + volatile unsigned int *cpu_control; + unsigned short cmd = 0xc220; + unsigned long data = 0; + int i, n; + +#ifdef __MIPSEB__ + cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00034); +#else + cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00030); +#endif +#define DEASSERT(bit) (*(cpu_control) &= (~(bit))) +#define ASSERT(bit) (*(cpu_control) |= (bit)) +#define DELAY for(n = 0; n < 100000; n++) __asm__ __volatile__("") + DEASSERT(SGIMC_EEPROM_PRE); + DEASSERT(SGIMC_EEPROM_SDATAO); + DEASSERT(SGIMC_EEPROM_SECLOCK); + DEASSERT(SGIMC_EEPROM_PRE); + DELAY; + ASSERT(SGIMC_EEPROM_CSEL); ASSERT(SGIMC_EEPROM_SECLOCK); + for(i = 0; i < 11; i++) { + if(cmd & (1<<15)) + ASSERT(SGIMC_EEPROM_SDATAO); + else + DEASSERT(SGIMC_EEPROM_SDATAO); + DEASSERT(SGIMC_EEPROM_SECLOCK); + ASSERT(SGIMC_EEPROM_SECLOCK); + cmd <<= 1; + } + DEASSERT(SGIMC_EEPROM_SDATAO); + for(i = 0; i < (sizeof(unsigned short) * 8); i++) { + unsigned int tmp; + + DEASSERT(SGIMC_EEPROM_SECLOCK); + DELAY; + ASSERT(SGIMC_EEPROM_SECLOCK); + DELAY; + data <<= 1; + tmp = *cpu_control; + if(tmp & SGIMC_EEPROM_SDATAI) + data |= 1; + } + DEASSERT(SGIMC_EEPROM_SECLOCK); + DEASSERT(SGIMC_EEPROM_CSEL); + ASSERT(SGIMC_EEPROM_PRE); + ASSERT(SGIMC_EEPROM_SECLOCK); + + data <<= PAGE_SHIFT; + if (data == 0) + return 0; + + scache_size = data; + + printk("R4600/R5000 SCACHE size %ldK, linesize 32 bytes.\n", + scache_size >> 10); + + return 1; +} + +/* XXX Check with wje if the Indy caches can differenciate between + writeback + invalidate and just invalidate. */ +struct bcache_ops indy_sc_ops = { + indy_sc_enable, + indy_sc_disable, + indy_sc_wback_invalidate, + indy_sc_wback_invalidate +}; + +void __init indy_sc_init(void) +{ + if (indy_sc_probe()) { + indy_sc_enable(); + bcops = &indy_sc_ops; + } +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-setup.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-setup.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-setup.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,213 @@ +/* + * ip22-setup.c: SGI specific setup, including init of the feature struct. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +static int remote_debug = 0; +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_ARC_CONSOLE) +extern void console_setup(char *); +#endif + +extern void sgitime_init(void); + +extern struct rtc_ops indy_rtc_ops; +extern void indy_reboot_setup(void); +extern void sgi_volume_set(unsigned char); + +#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64)) + +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ + +static void sgi_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Dirty hack, this get's called as a callback from the keyboard + driver. We piggyback the initialization of the front panel + button handling on it even though they're technically not + related with the keyboard driver in any way. Doing it from + indy_setup wouldn't work since kmalloc isn't initialized yet. */ + indy_reboot_setup(); + + return request_irq(SGI_KEYBD_IRQ, handler, 0, "keyboard", NULL); +} + +static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ + return 0; +} + +static void sgi_aux_free_irq(void) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ +} + +static unsigned char sgi_read_input(void) +{ + return sgi_kh->data; +} + +static void sgi_write_output(unsigned char val) +{ + int status; + + do { + status = sgi_kh->command; + } while (status & KBD_STAT_IBF); + sgi_kh->data = val; +} + +static void sgi_write_command(unsigned char val) +{ + int status; + + do { + status = sgi_kh->command; + } while (status & KBD_STAT_IBF); + sgi_kh->command = val; +} + +static unsigned char sgi_read_status(void) +{ + return sgi_kh->command; +} + +struct kbd_ops sgi_kbd_ops = { + sgi_request_region, + sgi_request_irq, + + sgi_aux_request_irq, + sgi_aux_free_irq, + + sgi_read_input, + sgi_write_output, + sgi_write_command, + sgi_read_status +}; + +void __init bus_error_init(void) +{ +} + +void __init ip22_setup(void) +{ +#ifdef CONFIG_SERIAL_CONSOLE + char *ctype; +#endif +#ifdef CONFIG_REMOTE_DEBUG + char *kgdb_ttyd; +#endif + sgitime_init(); + /* Init the INDY HPC I/O controller. Need to call this before + * fucking with the memory controller because it needs to know the + * boardID and whether this is a Guiness or a FullHouse machine. + */ + sgihpc_init(); + + /* Init INDY memory controller. */ + sgimc_init(); + + /* Now enable boardcaches, if any. */ + indy_sc_init(); + +#ifdef CONFIG_SERIAL_CONSOLE + /* ARCS console environment variable is set to "g?" for + * graphics console, it is set to "d" for the first serial + * line and "d2" for the second serial line. + */ + ctype = ArcGetEnvironmentVariable("console"); + if(*ctype == 'd') { + if(*(ctype+1)=='2') + console_setup ("ttyS1"); + else + console_setup ("ttyS0"); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + kgdb_ttyd = prom_getcmdline(); + if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) { + int line; + kgdb_ttyd += strlen("kgdb=ttyd"); + if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2') + printk("KGDB: Uknown serial line /dev/ttyd%c, " + "falling back to /dev/ttyd1\n", *kgdb_ttyd); + line = *kgdb_ttyd == '2' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyd%d for session\n", + line ? 1 : 2); + rs_kgdb_hook(line); + + printk("KGDB: Using serial line /dev/ttyd%d for session, " + "please connect your debugger\n", line ? 1 : 2); + + remote_debug = 1; + /* Breakpoints and stuff are in sgi_irq_setup() */ + } +#endif + +#ifdef CONFIG_ARC_CONSOLE + console_setup("ttyS0"); +#endif + + sgi_volume_set(simple_strtoul(ArcGetEnvironmentVariable("volume"), NULL, 10)); + +#ifdef CONFIG_VT +#ifdef CONFIG_SGI_NEWPORT_CONSOLE + conswitchp = &newport_con; + + screen_info = (struct screen_info) { + 0, 0, /* orig-x, orig-y */ + 0, /* unused */ + 0, /* orig_video_page */ + 0, /* orig_video_mode */ + 160, /* orig_video_cols */ + 0, 0, 0, /* unused, ega_bx, unused */ + 64, /* orig_video_lines */ + 0, /* orig_video_isVGA */ + 16 /* orig_video_points */ + }; +#else + conswitchp = &dummy_con; +#endif +#endif + + rtc_ops = &indy_rtc_ops; + kbd_ops = &sgi_kbd_ops; +#ifdef CONFIG_PSMOUSE + aux_device_present = 0xaa; +#endif +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-system.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-system.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-system.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-system.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,134 @@ +/* + * ip22-system.c: Probe the system type using ARCS prom interface library. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include +#include + +#include +#include +#include + +enum sgi_mach sgimach; + +struct smatch { + char *name; + int type; +}; + +static struct smatch sgi_cputable[] = { + { "MIPS-R2000", CPU_R2000 }, + { "MIPS-R3000", CPU_R3000 }, + { "MIPS-R3000A", CPU_R3000A }, + { "MIPS-R4000", CPU_R4000SC }, + { "MIPS-R4400", CPU_R4400SC }, + { "MIPS-R4600", CPU_R4600 }, + { "MIPS-R8000", CPU_R8000 }, + { "MIPS-R5000", CPU_R5000 }, + { "MIPS-R5000A", CPU_R5000A } +}; + +#define NUM_CPUS 9 /* for now */ + +static int __init string_to_cpu(char *s) +{ + long cnt; + char c; + int i; + + for(i = 0; i < NUM_CPUS; i++) { + if(!strcmp(s, sgi_cputable[i].name)) + return sgi_cputable[i].type; + } + prom_printf("\nYeee, could not determine MIPS cpu type <%s>\n", s); + prom_printf("press a key to reboot\n"); + ArcRead(0, &c, 1, &cnt); + ArcEnterInteractiveMode(); + return 0; +} + +/* + * We' call this early before loadmmu(). If we do the other way around + * the firmware will crash and burn. + */ +void __init sgi_sysinit(void) +{ + pcomponent *p, *toplev, *cpup = 0; + int cputype = -1; + long cnt; + char c; + + + /* The root component tells us what machine architecture we + * have here. + */ + p = ArcGetChild(PROM_NULL_COMPONENT); + + /* Now scan for cpu(s). */ + toplev = p = ArcGetChild(p); + while(p) { + int ncpus = 0; + + if(p->type == Cpu) { + if(++ncpus > 1) { + prom_printf("\nYeee, SGI MP not ready yet\n"); + prom_printf("press a key to reboot\n"); + ArcRead(0, &c, 1, &cnt); + ArcEnterInteractiveMode(); + } + printk("CPU: %s ", p->iname); + cpup = p; + cputype = string_to_cpu(cpup->iname); + } + p = ArcGetPeer(p); + } + if (cputype == -1) { + prom_printf("\nYeee, could not find cpu ARCS component\n"); + prom_printf("press a key to reboot\n"); + ArcRead(0, &c, 1, &cnt); + ArcEnterInteractiveMode(); + } + p = ArcGetChild(cpup); + while(p) { + switch(p->class) { + case processor: + switch(p->type) { + case Fpu: + printk("FPU<%s> ", p->iname); + break; + + default: + break; + }; + break; + + case cache: + switch(p->type) { + case picache: + printk("ICACHE "); + break; + + case pdcache: + printk("DCACHE "); + break; + + case sccache: + printk("SCACHE "); + break; + + default: + break; + + }; + break; + + default: + break; + }; + p = ArcGetPeer(p); + } + printk("\n"); +} diff -urN linux-2.4.18/arch/mips/sgi-ip22/ip22-time.c linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-time.c --- linux-2.4.18/arch/mips/sgi-ip22/ip22-time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sgi-ip22/ip22-time.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,242 @@ +/* + * 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. + * + * Time operations for IP22 machines. Original code may come from + * Ralf Baechle or David S. Miller (sorry guys, i'm really not sure) + * + * Copyright (C) 2001 by Ladislav Michl + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * note that mktime uses month from 1 to 12 while to_tm + * uses 0 to 11. + */ +static unsigned long indy_rtc_get_time(void) +{ + unsigned char yrs, mon, day, hrs, min, sec; + unsigned char save_control; + + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hrs = CMOS_READ(RTC_HOURS) & 0x1f; + day = CMOS_READ(RTC_DATE); + mon = CMOS_READ(RTC_MONTH) & 0x1f; + yrs = CMOS_READ(RTC_YEAR); + + CMOS_WRITE(save_control, RTC_CMD); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hrs); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(yrs); + + if (yrs < 45) + yrs += 30; + if ((yrs += 40) < 70) + yrs += 100; + + return mktime((int)yrs + 1900, mon, day, hrs, min, sec); +} + +static int indy_rtc_set_time(unsigned long tim) +{ + struct rtc_time tm; + unsigned char save_control; + + to_tm(tim, &tm); + + tm.tm_mon += 1; /* tm_mon starts at zero */ + tm.tm_year -= 1940; + if (tm.tm_year >= 100) + tm.tm_year -= 100; + + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_year); + + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + CMOS_WRITE(tm.tm_year, RTC_YEAR); + CMOS_WRITE(tm.tm_mon, RTC_MONTH); + CMOS_WRITE(tm.tm_mday, RTC_DATE); + CMOS_WRITE(tm.tm_hour, RTC_HOURS); + CMOS_WRITE(tm.tm_min, RTC_MINUTES); + CMOS_WRITE(tm.tm_sec, RTC_SECONDS); + CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); + + CMOS_WRITE(save_control, RTC_CMD); + + return 0; +} + +static unsigned long dosample(volatile unsigned char *tcwp, + volatile unsigned char *tc2p) +{ + unsigned long ct0, ct1; + unsigned char msb, lsb; + + /* Start the counter. */ + *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN); + *tc2p = (SGINT_TCSAMP_COUNTER & 0xff); + *tc2p = (SGINT_TCSAMP_COUNTER >> 8); + + /* Get initial counter invariant */ + ct0 = read_32bit_cp0_register(CP0_COUNT); + + /* Latch and spin until top byte of counter2 is zero */ + do { + *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT); + lsb = *tc2p; + msb = *tc2p; + ct1 = read_32bit_cp0_register(CP0_COUNT); + } while(msb); + + /* Stop the counter. */ + *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST); + + /* + * Return the difference, this is how far the r4k counter increments + * for every 1/HZ seconds. We round off the nearest 1 MHz of master + * clock (= 1000000 / 100 / 2 = 5000 count). + */ + return ((ct1 - ct0) / 5000) * 5000; +} + +/* + * Here we need to calibrate the cycle counter to at least be close. + */ +void indy_time_init(void) +{ + struct sgi_ioc_timers *p; + volatile unsigned char *tcwp, *tc2p; + unsigned long r4k_ticks[3]; + unsigned long r4k_tick; + + /* Figure out the r4k offset, the algorithm is very simple + * and works in _all_ cases as long as the 8254 counter + * register itself works ok (as an interrupt driving timer + * it does not because of bug, this is why we are using + * the onchip r4k counter/compare register to serve this + * purpose, but for r4k_offset calculation it will work + * ok for us). There are other very complicated ways + * of performing this calculation but this one works just + * fine so I am not going to futz around. ;-) + */ + p = ioc_timers; + tcwp = &p->tcword; + tc2p = &p->tcnt2; + + printk("Calibrating system timer... "); + dosample(tcwp, tc2p); /* Prime cache. */ + dosample(tcwp, tc2p); /* Prime cache. */ + /* Zero is NOT an option. */ + do { + r4k_ticks[0] = dosample (tcwp, tc2p); + } while (!r4k_ticks[0]); + do { + r4k_ticks[1] = dosample (tcwp, tc2p); + } while (!r4k_ticks[1]); + + if (r4k_ticks[0] != r4k_ticks[1]) { + printk ("warning: timer counts differ, retrying..."); + r4k_ticks[2] = dosample (tcwp, tc2p); + if (r4k_ticks[2] == r4k_ticks[0] + || r4k_ticks[2] == r4k_ticks[1]) + r4k_tick = r4k_ticks[2]; + else { + printk ("disagreement, using average..."); + r4k_tick = (r4k_ticks[0] + r4k_ticks[1] + + r4k_ticks[2]) / 3; + } + } else + r4k_tick = r4k_ticks[0]; + + printk("%d [%d.%02d MHz CPU]\n", (int) r4k_tick, + (int) (r4k_tick / 5000), (int) (r4k_tick % 5000) / 50); + + mips_counter_frequency = r4k_tick * HZ; +} + +/* Generic SGI handler for (spurious) 8254 interrupts */ +void indy_8254timer_irq(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int irq = SGI_8254_0_IRQ; + long cnt; + char c; + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); + ArcRead(0, &c, 1, &cnt); + ArcEnterInteractiveMode(); + irq_exit(cpu, irq); +} + +void indy_r4k_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int irq = SGI_TIMER_IRQ; + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + timer_interrupt(irq, NULL, regs); + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); +} + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); + +static void indy_timer_setup(struct irqaction *irq) +{ + unsigned long count; + + /* over-write the handler, we use our own way */ + irq->handler = no_action; + + /* set time for first interrupt */ + count = read_32bit_cp0_register(CP0_COUNT); + count += mips_counter_frequency / HZ; + write_32bit_cp0_register(CP0_COMPARE, count); + + /* setup irqaction */ + setup_irq(SGI_TIMER_IRQ, irq); +} + +void sgitime_init(void) +{ + /* setup hookup functions */ + rtc_get_time = indy_rtc_get_time; + rtc_set_time = indy_rtc_set_time; + + board_time_init = indy_time_init; + board_timer_setup = indy_timer_setup; +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1/Makefile linux-2.4.19-pre5/arch/mips/sibyte/sb1/Makefile --- linux-2.4.18/arch/mips/sibyte/sb1/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,10 @@ +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +L_TARGET = sb1kern.a + +obj-$(CONFIG_SB1_CACHE_ERROR) += cache_err_handler.o cache_error.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/sibyte/sb1/cache_err_handler.S linux-2.4.19-pre5/arch/mips/sibyte/sb1/cache_err_handler.S --- linux-2.4.18/arch/mips/sibyte/sb1/cache_err_handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1/cache_err_handler.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include + +#include +#include +#include + + .text + /* Special Cache Error handler for SB1 for now */ + LEAF(except_vec2_sb1) + .set noat + .set mips0 + /* + * This is a very bad place to be. Our cache error detection has + * triggered. If we have write-back data in the cache, we may not be + * able to recover. As a first-order desperate measure, turn off KSEG0 + * cacheing. + */ + .set push + #.set mips64 + .set mips4 + .set reorder + # look for signature of spurious CErr + mfc0 k1, $26 # mfc0 k1, $26, 0 + # check if error was recoverable + # XXXKW - count them + bltz k1, leave_cerr + nop + +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + # look for signature of spurious CErr + lui k0, 0x4000 + bne k0, k1, real_cerr + .word 0x401Bd801 # mfc0 k1, $27, 1 + lui k0, 0xffe0 + and k1, k0, k1 + lui k0, 0x0200 + bne k0, k1, real_cerr + nop +#else + j real_cerr + nop +#endif + # XXXKW - count spurious errors +leave_cerr: + # clear/unlock the registers + mtc0 zero, $26 # mtc0 zero, $26, 0 + mtc0 zero, $27 # mtc0 zero, $27, 0 + .word 0x4080d801 # mtc0 zero, $27, 1 + .word 0x4080d803 # mtc0 zero, $27, 3 + eret + +real_cerr: + mfc0 k0, CP0_CONFIG + li k1, ~CONF_CM_CMASK + and k0, k0, k1 + ori k0, k0, CONF_CM_UNCACHED + mtc0 k0, CP0_CONFIG + /* Give it a few cycles to sink in... */ + sll zero, zero, 0x1 # ssnop + sll zero, zero, 0x1 # ssnop + sll zero, zero, 0x1 # ssnop + sll zero, zero, 0x1 # ssnop + sll zero, zero, 0x1 # ssnop + sll zero, zero, 0x1 # ssnop + + j sb1_cache_error + nop + + .set pop + END(except_vec2_sb1) diff -urN linux-2.4.18/arch/mips/sibyte/sb1/cache_error.c linux-2.4.19-pre5/arch/mips/sibyte/sb1/cache_error.c --- linux-2.4.18/arch/mips/sibyte/sb1/cache_error.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1/cache_error.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +/* SB1 definitions */ +#define CP0_ERRCTL_RECOVERABLE (1 << 31) +#define CP0_ERRCTL_DCACHE (1 << 30) +#define CP0_ERRCTL_ICACHE (1 << 29) +#define CP0_ERRCTL_MULTIBUS (1 << 23) +#define CP0_ERRCTL_MC_TLB (1 << 15) +#define CP0_ERRCTL_MC_TIMEOUT (1 << 14) + +#define CP0_CERRI_TAG_PARITY (1 << 29) +#define CP0_CERRI_DATA_PARITY (1 << 28) +#define CP0_CERRI_EXTERNAL (1 << 26) +#define CP0_CERRI_CACHE_IDX (0xff << 5) + +#define CP0_CERRD_MULTIPLE (1 << 31) +#define CP0_CERRD_TAG_STATE (1 << 30) +#define CP0_CERRD_TAG_ADDRESS (1 << 29) +#define CP0_CERRD_DATA_SBE (1 << 28) +#define CP0_CERRD_DATA_DBE (1 << 27) +#define CP0_CERRD_EXTERNAL (1 << 26) +#define CP0_CERRD_LOAD (1 << 25) +#define CP0_CERRD_STORE (1 << 24) +#define CP0_CERRD_FILLWB (1 << 23) +#define CP0_CERRD_COHERENCY (1 << 22) +#define CP0_CERRD_DUPTAG (1 << 21) +#define CP0_CERRD_CACHE_IDX (0xff << 5) + +asmlinkage void sb1_cache_error(void) +{ + unsigned int errctl, cerr_i, cerr_d, cerr_dpa; + unsigned long eepc; + + eepc = get_errorepc(); + + __asm__ __volatile__ ( + ".set push\n" + "#.set mips64\n" + ".set mips4\n" + ".word 0x4001D000; move %0, $1; # mfc0 %0, $26, 0\n" + ".word 0x4001D800; move %1, $1; # mfc0 %1, $27, 0\n" + ".word 0x4001D801; move %2, $1; # mfc0 %2, $27, 1\n" + ".word 0x4001D803; move %3, $1; # mfc0 %3, $27, 3\n" + ".set pop\n" + : "=r" (errctl), "=r" (cerr_i), + "=r" (cerr_d), "=r" (cerr_dpa)); + + printk("Cache error exception:\n"); + printk(" cp0_errorepc == 0x%0lx\n", eepc); + printk(" cp0_errctl == 0x%08x\n", errctl); + + if (errctl & CP0_ERRCTL_DCACHE) { + printk(" cp0_cerr_d == 0x%08x\n", cerr_d); + printk(" cp0_cerr_dpa == 0x%08x\n", cerr_dpa); + } + if (errctl & CP0_ERRCTL_ICACHE) { + printk(" cp0_cerr_i == 0x%08x\n", cerr_i); + } + + panic("Can't handle the cache error!"); +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/Makefile linux-2.4.19-pre5/arch/mips/sibyte/sb1250/Makefile --- linux-2.4.18/arch/mips/sibyte/sb1250/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,15 @@ +.S.s: + $(CPP) $(AFLAGS) $< -o $@ +.S.o: + $(CC) $(AFLAGS) -c $< -o $@ + +O_TARGET := sb1250.o + +obj-y := setup.o irq.o irq_handler.o time.o + +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_BCM1250_TBPROF) += bcm1250_tbprof.o +obj-$(CONFIG_MIPS32) += lib_hssubr.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/bcm1250_tbprof.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/bcm1250_tbprof.c --- linux-2.4.18/arch/mips/sibyte/sb1250/bcm1250_tbprof.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/bcm1250_tbprof.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define SBPROF_TB_DEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bcm1250_tbprof.h" + +#define DEVNAME "sb1250_tbprof" + +static struct sbprof_tb *sbp; + +/************************************************************************ + * Support for ZBbus sampling using the trace buffer + * + * We use the SCD performance counter interrupt, caused by a Zclk counter + * overflow, to trigger the start of tracing. + * + * We set the trace buffer to sample everything and freeze on + * overflow. + * + * We map the interrupt for trace_buffer_freeze to handle it on CPU 0. + * + ************************************************************************/ + +/* Once per second on a 500 Mhz 1250 */ +#define TB_PERIOD 250000000ULL + +static void arm_tb(void) +{ + unsigned long long next = (1ULL << 40) - TB_PERIOD; + /* Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to + trigger start of trace. XXX vary sampling period */ + out64(0, KSEG1 + A_SCD_PERF_CNT_1); + out64(in64(KSEG1 + A_SCD_PERF_CNT_CFG) | // keep counters 0,2,3 as is + M_SPC_CFG_ENABLE | // enable counting + V_SPC_CFG_SRC1(1), // counter 1 counts cycles + KSEG1 + A_SCD_PERF_CNT_CFG); + out64(next, KSEG1 + A_SCD_PERF_CNT_1); + /* Reset the trace buffer */ + out64(M_SCD_TRACE_CFG_RESET, KSEG1 + A_SCD_TRACE_CFG); + out64(M_SCD_TRACE_CFG_FREEZE_FULL, KSEG1 + A_SCD_TRACE_CFG); + sbp->tb_armed = 1; +} + +static void sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + DBG(printk(DEVNAME ": tb_intr\n")); + if (sbp->next_tb_sample < MAX_TB_SAMPLES) { + /* XXX should use XKPHYS to make writes bypass L2 */ + unsigned long long *p = sbp->sbprof_tbbuf[sbp->next_tb_sample++]; + /* Read out trace */ + out64(M_SCD_TRACE_CFG_START_READ, KSEG1 + A_SCD_TRACE_CFG); + __asm__ __volatile__ ("sync" : : : "memory"); + /* Loop runs backwards because bundles are read out in reverse order */ + for (i = 256 * 6; i > 0; i -= 6) { + // Subscripts decrease to put bundle in the order + // t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi + p[i-1] = in64(KSEG1 + A_SCD_TRACE_READ); // read t2 hi + p[i-2] = in64(KSEG1 + A_SCD_TRACE_READ); // read t2 lo + p[i-3] = in64(KSEG1 + A_SCD_TRACE_READ); // read t1 hi + p[i-4] = in64(KSEG1 + A_SCD_TRACE_READ); // read t1 lo + p[i-5] = in64(KSEG1 + A_SCD_TRACE_READ); // read t0 hi + p[i-6] = in64(KSEG1 + A_SCD_TRACE_READ); // read t0 lo + } + if (!sbp->tb_enable) { + DBG(printk(DEVNAME ": tb_intr shutdown\n")); + out64(M_SCD_TRACE_CFG_RESET, KSEG1 + A_SCD_TRACE_CFG); + sbp->tb_armed = 0; + wake_up(&sbp->tb_sync); + } else { + arm_tb(); // knock down current interrupt and get another one later + } + } else { + /* No more trace buffer samples */ + DBG(printk(DEVNAME ": tb_intr full\n")); + out64(M_SCD_TRACE_CFG_RESET, KSEG1 + A_SCD_TRACE_CFG); + sbp->tb_armed = 0; + if (!sbp->tb_enable) { + wake_up(&sbp->tb_sync); + } + } +} + +static void sbprof_pc_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + panic(DEVNAME ": pc_intr"); +} + +static int sbprof_zbprof_start(struct file *filp) +{ + if (sbp->tb_enable) + return -EBUSY; + + DBG(printk(DEVNAME ": starting\n")); + + sbp->tb_enable = 1; + sbp->next_tb_sample = 0; + filp->f_pos = 0; + + if (request_irq + (K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, "sbprof_tb trace freeze", sbp)) { + return -EBUSY; + } + if (request_irq + (K_INT_PERF_CNT, sbprof_pc_intr, 0, "sbprof_tb scd perfcnt", sbp)) { + free_irq(K_INT_TRACE_FREEZE, sbp); + return -EBUSY; + } + + /* I need the core to mask these, but the interrupt mapper to + pass them through. I am exploiting my knowledge that + cp0_status masks out IP[5]. krw */ + out64(K_INT_MAP_I3, + KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_PERF_CNT<<3)); + + /* Initialize address traps */ + out64(0, KSEG1 + A_ADDR_TRAP_UP_0); + out64(0, KSEG1 + A_ADDR_TRAP_UP_1); + out64(0, KSEG1 + A_ADDR_TRAP_UP_2); + out64(0, KSEG1 + A_ADDR_TRAP_UP_3); + + out64(0, KSEG1 + A_ADDR_TRAP_DOWN_0); + out64(0, KSEG1 + A_ADDR_TRAP_DOWN_1); + out64(0, KSEG1 + A_ADDR_TRAP_DOWN_2); + out64(0, KSEG1 + A_ADDR_TRAP_DOWN_3); + + out64(0, KSEG1 + A_ADDR_TRAP_CFG_0); + out64(0, KSEG1 + A_ADDR_TRAP_CFG_1); + out64(0, KSEG1 + A_ADDR_TRAP_CFG_2); + out64(0, KSEG1 + A_ADDR_TRAP_CFG_3); + + /* Initialize Trace Event 0-7 */ + // when interrupt + out64(M_SCD_TREVT_INTERRUPT, KSEG1 + A_SCD_TRACE_EVENT_0); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_1); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_2); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_3); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_4); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_5); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_6); + out64(0, KSEG1 + A_SCD_TRACE_EVENT_7); + + /* Initialize Trace Sequence 0-7 */ + // Start on event 0 (interrupt) + out64(V_SCD_TRSEQ_FUNC_START|0x0fff, + KSEG1 + A_SCD_TRACE_SEQUENCE_0); + // dsamp when d used | asamp when a used + out64(M_SCD_TRSEQ_ASAMPLE|M_SCD_TRSEQ_DSAMPLE|K_SCD_TRSEQ_TRIGGER_ALL, + KSEG1 + A_SCD_TRACE_SEQUENCE_1); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_2); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_3); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_4); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_5); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_6); + out64(0, KSEG1 + A_SCD_TRACE_SEQUENCE_7); + + /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */ + out64((1ULL << K_INT_PERF_CNT), KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)); + + arm_tb(); + + DBG(printk(DEVNAME ": done starting\n")); + + return 0; +} + +static int sbprof_zbprof_stop(void) +{ + DBG(printk(DEVNAME ": stopping\n")); + + if (sbp->tb_enable) { + sbp->tb_enable = 0; + /* XXXKW there is a window here where the intr handler + may run, see the disable, and do the wake_up before + this sleep happens. */ + if (sbp->tb_armed) { + DBG(printk(DEVNAME ": wait for disarm\n")); + interruptible_sleep_on(&sbp->tb_sync); + DBG(printk(DEVNAME ": disarm complete\n")); + } + free_irq(K_INT_TRACE_FREEZE, sbp); + free_irq(K_INT_PERF_CNT, sbp); + } + + DBG(printk(DEVNAME ": done stopping\n")); + + return 0; +} + +static int sbprof_tb_open(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + if (minor != 0) { + return -ENODEV; + } + if (sbp != NULL) { + return -EBUSY; + } + + /* XXXKW spinlock? */ + sbp = kmalloc(sizeof(struct sbprof_tb), GFP_KERNEL); + if (!sbp) { + return -ENOMEM; + } + memset(sbp, 0, sizeof(struct sbprof_tb)); + sbp->sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES); + if (!sbp->sbprof_tbbuf) { + kfree(sbp); + sbp = NULL; + return -ENOMEM; + } + memset(sbp->sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES); + init_waitqueue_head(&sbp->tb_sync); + + return 0; +} + +static int sbprof_tb_release(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + if (minor != 0 || sbp == NULL) { + return -ENODEV; + } + + if (sbp->tb_armed || sbp->tb_enable) { + sbprof_zbprof_stop(); + } + + vfree(sbp->sbprof_tbbuf); + kfree(sbp); + sbp = NULL; + + return 0; +} + +static ssize_t sbprof_tb_read(struct file *filp, char *buf, + size_t size, loff_t *offp) +{ + int cur_sample, sample_off, cur_count, sample_left; + char *src; + int count = 0; + char *dest = buf; + long cur_off = *offp; + + count = 0; + cur_sample = cur_off / TB_SAMPLE_SIZE; + sample_off = cur_off % TB_SAMPLE_SIZE; + sample_left = TB_SAMPLE_SIZE - sample_off; + while (size && (cur_sample < sbp->next_tb_sample)) { + cur_count = size < sample_left ? size : sample_left; + src = (char *)(((long)sbp->sbprof_tbbuf[cur_sample])+sample_off); + copy_to_user(dest, src, cur_count); + DBG(printk(DEVNAME ": read from sample %d, %d bytes\n", cur_sample, cur_count)); + size -= cur_count; + sample_left -= cur_count; + if (!sample_left) { + cur_sample++; + sample_off = 0; + sample_left = TB_SAMPLE_SIZE; + } else { + sample_off += cur_count; + } + cur_off += cur_count; + dest += cur_count; + count += cur_count; + } + *offp = cur_off; + + return count; +} + +#define SBPROF_ZBSTART _IOW('s', 0, int) +#define SBPROF_ZBSTOP _IOW('s', 1, int) +#define SBPROF_ZBFULL _IOW('s', 2, int) + +static int sbprof_tb_ioctl(struct inode *inode, + struct file *filp, + unsigned int command, + unsigned long arg) +{ + int error = 0; + int full; + + switch (command) { + case SBPROF_ZBSTART: + error = sbprof_zbprof_start(filp); + break; + case SBPROF_ZBSTOP: + error = sbprof_zbprof_stop(); + break; + case SBPROF_ZBFULL: + full = (sbp->next_tb_sample == MAX_TB_SAMPLES); + return put_user(full, (int *) arg); + default: + error = -EINVAL; + break; + } + + return error; +} + +static struct file_operations sbprof_tb_fops = { + owner: THIS_MODULE, + open: sbprof_tb_open, + release: sbprof_tb_release, + read: sbprof_tb_read, + ioctl: sbprof_tb_ioctl, + mmap: NULL, +}; + +static devfs_handle_t devfs_handle; + +static int __init sbprof_tb_init(void) +{ + if (devfs_register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) { + printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n", + SBPROF_TB_MAJOR); + return -EIO; + } + devfs_handle = devfs_register(NULL, DEVNAME, + DEVFS_FL_DEFAULT, SBPROF_TB_MAJOR, 0, + S_IFCHR | S_IRUGO | S_IWUGO, + &sbprof_tb_fops, NULL); + sbp = NULL; + printk(KERN_INFO DEVNAME ": initialized\n"); + return 0; +} + +static void __exit sbprof_tb_cleanup(void) +{ + devfs_unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME); + devfs_unregister(devfs_handle); +} + +module_init(sbprof_tb_init); +module_exit(sbprof_tb_cleanup); diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/bcm1250_tbprof.h linux-2.4.19-pre5/arch/mips/sibyte/sb1250/bcm1250_tbprof.h --- linux-2.4.18/arch/mips/sibyte/sb1250/bcm1250_tbprof.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/bcm1250_tbprof.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef BCM1250_TBPROF_H + +#if SBPROF_TB_DEBUG +#define DBG(a) a +#else +#define DBG(a) +#endif + +#define SBPROF_TB_MAJOR 240 + +typedef u_int64_t tb_sample_t[6*256]; + +struct sbprof_tb { + tb_sample_t *sbprof_tbbuf; + int next_tb_sample; + + volatile int tb_enable; + volatile int tb_armed; + + wait_queue_head_t tb_sync; +}; + +#define MAX_SAMPLE_BYTES (24*1024*1024) +#define MAX_TBSAMPLE_BYTES (12*1024*1024) + +#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t)) +#define TB_SAMPLE_SIZE (sizeof(tb_sample_t)) +#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE) + +/*************************************************************************** + * Routines for gathering ZBbus profiles using trace buffer + ***************************************************************************/ + +/* Requires: Already called zclk_timer_init with a value that won't + saturate 40 bits. No subsequent use of SCD performance counters + or trace buffer. + Effect: Starts gathering random ZBbus profiles using trace buffer. */ +static int sbprof_zbprof_start(struct file *filp); + +/* Effect: Stops collection of ZBbus profiles */ +static int sbprof_zbprof_stop(void); + + +/*************************************************************************** + * Routines for using 40-bit SCD cycle counter + * + * Client responsible for either handling interrupts or making sure + * the cycles counter never saturates, e.g., by doing + * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs. + ***************************************************************************/ + +/* Configures SCD counter 0 to count ZCLKs starting from val; + Configures SCD counters1,2,3 to count nothing. + Must not be called while gathering ZBbus profiles. + +unsigned long long val; */ +#define zclk_timer_init(val) \ + __asm__ __volatile__ (".set push;" \ + ".set mips64;" \ + "la $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \ + "sd %0, 0x10($8);" /* write val to counter0 */ \ + "sd %1, 0($8);" /* config counter0 for zclks*/ \ + ".set pop" \ + : /* no outputs */ \ + /* enable, counter0 */ \ + : /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \ + : /* modifies */ "$8" ) + + +/* Reads SCD counter 0 and puts result in value + unsigned long long val; */ +#define zclk_get(val) \ + __asm__ __volatile__ (".set push;" \ + ".set mips64;" \ + "la $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \ + "ld %0, 0x10($8);" /* write val to counter0 */ \ + ".set pop" \ + : /* outputs */ "=r"(val) \ + : /* inputs */ \ + : /* modifies */ "$8" ) + +#endif diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/irq.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/irq.c --- linux-2.4.18/arch/mips/sibyte/sb1250/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/irq.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * These are the routines that handle all the low level interrupt stuff. + * Actions handled here are: initialization of the interrupt map, requesting of + * interrupt lines by handlers, dispatching if interrupts to handlers, probing + * for interrupt lines + */ + + +#define shutdown_sb1250_irq disable_sb1250_irq +static void end_sb1250_irq(unsigned int irq); +static void enable_sb1250_irq(unsigned int irq); +static void disable_sb1250_irq(unsigned int irq); +static unsigned int startup_sb1250_irq(unsigned int irq); +static void ack_sb1250_irq(unsigned int irq); + +#ifdef CONFIG_REMOTE_DEBUG +extern void breakpoint(void); +#endif + +#define NR_IRQS 64 + +static struct hw_interrupt_type sb1250_irq_type = { + "SB1250-IMR", + startup_sb1250_irq, + shutdown_sb1250_irq, + enable_sb1250_irq, + disable_sb1250_irq, + ack_sb1250_irq, + end_sb1250_irq, + NULL +}; + +spinlock_t sb1250_imr_lock = SPIN_LOCK_UNLOCKED; + +void sb1250_mask_irq(int cpu, int irq) +{ + unsigned long flags; + u64 cur_ints; + + spin_lock_irqsave(&sb1250_imr_lock, flags); + cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK); + cur_ints |= (((u64) 1) << irq); + out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK); + spin_unlock_irqrestore(&sb1250_imr_lock, flags); +} + +void sb1250_unmask_irq(int cpu, int irq) +{ + unsigned long flags; + u64 cur_ints; + + spin_lock_irqsave(&sb1250_imr_lock, flags); + cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK); + cur_ints &= ~(((u64) 1) << irq); + out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK); + spin_unlock_irqrestore(&sb1250_imr_lock, flags); +} + + + +/* Defined in arch/mips/sibyte/sb1250/irq_handler.S */ +extern void sb1250_irq_handler(void); + +/*****************************************************************************/ + +static unsigned int startup_sb1250_irq(unsigned int irq) +{ + sb1250_unmask_irq(0, irq); + + return 0; /* never anything pending */ +} + + +static void disable_sb1250_irq(unsigned int irq) +{ + sb1250_mask_irq(0, irq); +} + +static void enable_sb1250_irq(unsigned int irq) +{ + sb1250_unmask_irq(0, irq); +} + + +static void ack_sb1250_irq(unsigned int irq) +{ + u64 pending; + + /* + * If the interrupt was an LDT interrupt, now is the time + * to clear it. + */ + pending = in64(KSEG1 + A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT)); + pending &= ((u64)1 << (irq)); + if (pending) + out64(pending, KSEG1+A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT_CLR)); + + sb1250_mask_irq(0, irq); +} + + +static void end_sb1250_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + sb1250_unmask_irq(0, irq); + } +} + + +void __init init_sb1250_irqs(void) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &sb1250_irq_type; + } +} + + +/* + * init_IRQ is called early in the boot sequence from init/main.c. It + * is responsible for setting up the interrupt mapper and installing the + * handler that will be responsible for dispatching interrupts to the + * "right" place. + */ +/* + * For now, map all interrupts to IP[2]. We could save + * some cycles by parceling out system interrupts to different + * IP lines, but keep it simple for bringup. We'll also direct + * all interrupts to a single CPU; we should probably route + * PCI and LDT to one cpu and everything else to the other + * to balance the load a bit. + * + * On the second cpu, everything is set to IP5, which is + * ignored, EXCEPT the mailbox interrupt. That one is + * set to IP[2] so it is handled. This is needed so we + * can do cross-cpu function calls, as requred by SMP + */ + +#define IMR_IP2_VAL K_INT_MAP_I0 +#define IMR_IP3_VAL K_INT_MAP_I1 +#define IMR_IP4_VAL K_INT_MAP_I2 + +void __init init_IRQ(void) +{ + + unsigned int i; + u64 tmp; + + /* Default everything to IP2 */ + for (i = 0; i < NR_IRQS; i++) { /* was I0 */ + out64(IMR_IP2_VAL, + KSEG1 + A_IMR_REGISTER(0, + R_IMR_INTERRUPT_MAP_BASE) + + (i << 3)); + out64(IMR_IP2_VAL, + KSEG1 + A_IMR_REGISTER(1, + R_IMR_INTERRUPT_MAP_BASE) + + (i << 3)); + } + + init_sb1250_irqs(); + + /* + * Map the high 16 bits of the mailbox registers to IP[3], for + * inter-cpu messages + */ + /* Was I1 */ + out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + + (K_INT_MBOX_0 << 3)); + out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MAP_BASE) + + (K_INT_MBOX_0 << 3)); + + /* Clear the mailboxes. The firmware may leave them dirty */ + out64(0xffffffffffffffff, + KSEG1 + A_IMR_REGISTER(0, R_IMR_MAILBOX_CLR_CPU)); + out64(0xffffffffffffffff, + KSEG1 + A_IMR_REGISTER(1, R_IMR_MAILBOX_CLR_CPU)); + + /* Mask everything except the mailbox registers for both cpus */ + tmp = ~((u64) 0) ^ (((u64) 1) << K_INT_MBOX_0); + out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK)); + out64(tmp, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK)); + + /* + * Note that the timer interrupts are also mapped, but this is + * done in sb1250_time_init() + */ + +#ifdef CONFIG_SIBYTE_SB1250_PROF + /* Enable IP[7,4:0], disable the rest */ + clear_cp0_status(0x6000); + set_cp0_status(0x9f00); +#else + /* Enable IP[4:0], disable the rest */ + clear_cp0_status(0xe000); + set_cp0_status(0x1f00); +#endif + set_except_vector(0, sb1250_irq_handler); + +#ifdef CONFIG_REMOTE_DEBUG + /* If local serial I/O used for debug port, enter kgdb at once */ +// puts("Waiting for kgdb to connect..."); + set_debug_traps(); + breakpoint(); +#endif +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/irq_handler.S linux-2.4.19-pre5/arch/mips/sibyte/sb1250/irq_handler.S --- linux-2.4.18/arch/mips/sibyte/sb1250/irq_handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/irq_handler.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * sb1250_handle_int() is the routine that is actually called when an interrupt + * occurs. It is installed as the exception vector handler in init_IRQ() in + * arch/mips/sibyte/sb1250/irq.c + * + * In the handle we figure out which interrupts need handling, and use that to + * call the dispatcher, which will take care of actually calling registered + * handlers + * + * Note that we take care of all raised interrupts in one go at the handler. + * This is more BSDish than the Indy code, and also, IMHO, more sane. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * What a pain. We have to be really careful saving the upper 32 bits of any + * register across function calls if we don't want them trashed--since were + * running in -o32, the calling routing never saves the full 64 bits of a + * register across a function call. Being the interrupt handler, we're + * guaranteed that interrupts are disabled during this code so we don't have + * to worry about random interrupts blasting the high 32 bits. + */ + + .text + .set push + .set noreorder + .set noat + #.set mips64 + .set mips4 + .align 5 + NESTED(sb1250_irq_handler, PT_SIZE, sp) + SAVE_ALL + CLI + +#ifdef CONFIG_SIBYTE_SB1250_PROF + /* Set compare to count to silence count/compare timer interrupts */ + mfc0 t1, CP0_COUNT + mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */ +#endif + /* Read cause */ + mfc0 s0, CP0_CAUSE + +#ifdef CONFIG_SIBYTE_SB1250_PROF + /* Cpu performance counter interrupt is routed to IP[7] */ + andi t1, s0, CAUSEF_IP7 + beqz t1, 0f + srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */ + and t1, t1, 0x4 /* mask to get just BD bit */ + mfc0 a0, CP0_EPC + jal sbprof_cpu_intr + addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */ + j ret_from_irq + nop # delay slot +0: +#endif + /* Timer interrupt is routed to IP[4] */ + andi t1, s0, CAUSEF_IP4 + beqz t1, 1f + nop + jal sb1250_timer_interrupt + move a0, sp /* Pass the registers along */ + j ret_from_irq + nop # delay slot +1: + +#ifdef CONFIG_SMP + /* Mailbox interrupt is routed to IP[3] */ + andi t1, s0, CAUSEF_IP3 + beqz t1, 2f + nop + jal sb1250_mailbox_interrupt + move a0, sp + j ret_from_irq + nop # delay slot +2: +#endif + + and t1, s0, CAUSEF_IP2 + beqz t1, 4f + nop + + /* + * Default...we've hit an IP[2] interrupt, which means we've got to + * check the 1250 interrupt registers to figure out what to do + */ + la v0, KSEG1 + A_IMR_CPU0_BASE + ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */ + + beqz s0, 4f /* No interrupts. Return */ + move a1, sp + +3: #dclz s1, s0 /* Find the next interrupt */ + .word 0x72118824 # dclz s1, s0 + dsubu a0, zero, s1 + daddiu a0, a0, 63 + jal do_IRQ + nop + +4: j ret_from_irq + nop + + .set pop + END(sb1250_irq_handler) diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/lib_hssubr.S linux-2.4.19-pre5/arch/mips/sibyte/sb1250/lib_hssubr.S --- linux-2.4.18/arch/mips/sibyte/sb1250/lib_hssubr.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/lib_hssubr.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include + + .set mips64 + +#define HAZARD SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP ; SSNOP + + +/* ********************************************************************* + * hs_read8 - read 8-bit bytes + ********************************************************************* */ + + +LEAF(hs_read8) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0,v0 + lb v0, (a0) + and v0, 0xFF + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_read8) + +/* ********************************************************************* + * hs_read16 - read 16-bit shorts + ********************************************************************* */ + +LEAF(hs_read16) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + lh v0, (a0) + and v0, 0xFFFF + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_read16) + +/* ********************************************************************* + * hs_read32 - read 32-bit ints + ********************************************************************* */ + +LEAF(hs_read32) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + lw v0, (a0) + and v0, 0xFFFFFFFF + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_read32) + +/* ********************************************************************* + * hs_read64 - read 64-bit longs + ********************************************************************* */ + +LEAF(hs_read64) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + ld v0, (a0) + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_read64) + +/* ********************************************************************* + * hs_write8 - write 8-bit bytes + ********************************************************************* */ + +LEAF(hs_write8) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + sb a1, (a0) + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_write8) + +/* ********************************************************************* + * hs_write16 - write 16-bit shorts + ********************************************************************* */ + +LEAF(hs_write16) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + sh a1, (a0) + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_write16) + +/* ********************************************************************* + * hs_write32 - write 32-bit longs + ********************************************************************* */ + +LEAF(hs_write32) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + sw a1, (a0) + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_write32) + +/* ********************************************************************* + * hs_write64 - write 64-bit longs + ********************************************************************* */ + +LEAF(hs_write64) + mfc0 t2, CP0_STATUS + or t1, t2, ST0_KX + mtc0 t1, CP0_STATUS + HAZARD + + dli v0, PHYS_TO_XKSEG_UNCACHED(0) + dsll a0, a0, 32 + dsrl a0, a0, 32 + or a0, a0, v0 + sd a1, (a0) + + mtc0 t2, CP0_STATUS + HAZARD + j ra +END(hs_write64) diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/lib_hssubr.h linux-2.4.19-pre5/arch/mips/sibyte/sb1250/lib_hssubr.h --- linux-2.4.18/arch/mips/sibyte/sb1250/lib_hssubr.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/lib_hssubr.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LIB_HSSUBR_H +#define _LIB_HSSUBR_H + +/* + * If __long64 we can do this via macros. Otherwise, call + * the magic functions. + */ + +#if __long64 + +typedef long hsaddr_t; + +#define hs_write8(a,b) *((volatile uint8_t *) (a)) = (b) +#define hs_write16(a,b) *((volatile uint16_t *) (a)) = (b) +#define hs_write32(a,b) *((volatile uint32_t *) (a)) = (b) +#define hs_write64(a,b) *((volatile uint32_t *) (a)) = (b) +#define hs_read8(a) *((volatile uint8_t *) (a)) +#define hs_read16(a) *((volatile uint16_t *) (a)) +#define hs_read32(a) *((volatile uint32_t *) (a)) +#define hs_read64(a) *((volatile uint64_t *) (a)) + +#else /* not __long64 */ + +typedef long hsaddr_t; + +extern void hs_write8(hsaddr_t a,uint8_t b); +extern void hs_write16(hsaddr_t a,uint16_t b); +extern void hs_write32(hsaddr_t a,uint32_t b); +extern void hs_write64(hsaddr_t a,uint64_t b); +extern uint8_t hs_read8(hsaddr_t a); +extern uint16_t hs_read16(hsaddr_t a); +extern uint32_t hs_read32(hsaddr_t a); +extern uint64_t hs_read64(hsaddr_t a); +#endif + +#endif diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/pci.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/pci.c --- linux-2.4.18/arch/mips/sibyte/sb1250/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/pci.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * SB1250-specific PCI support + * + * This module provides the glue between Linux's PCI subsystem + * and the hardware. We basically provide glue for accessing + * configuration space, and set up the translation for I/O + * space accesses. + * + * To access configuration space, we call some assembly-level + * stubs that flip the KX bit on and off in the status + * register, and do XKSEG addressed memory accesses there. + * It's slow (7 SSNOPs to guarantee that KX is set!) but + * fortunately, config space accesses are rare. + * + * We could use the ioremap functionality for the confguration + * space as well as I/O space, but I'm not sure of the + * implications of setting aside 16MB of KSEG2 for something + * that is used so rarely (how much space in the page tables?) + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lib_hssubr.h" + +/* + * This macro calculates the offset into config space where + * a given bus, device/function, and offset live on the sb1250 + */ + +#define CFGOFFSET(bus,devfn,where) (((bus)<<16)+((devfn)<<8)+(where)) + +/* + * Using the above offset, this macro calcuates the actual + * address. Note that the physical address is not accessible + * without remapping or setting KX. We use 'match bits' + * as our endian policy to guarantee that 32-bit accesses + * look the same from either endianness. + */ +#define CFGADDR(dev,where) (A_PHYS_LDTPCI_CFG_MATCH_BITS + \ + CFGOFFSET(dev->bus->number,dev->devfn,where)) + +/* + * Read/write 32-bit values in config space. + */ + +#define READCFG32(addr) hs_read32((addr)&~3) +#define WRITECFG32(addr,data) hs_write32(((addr)&~3),(data)) + +/* + * This variable is the KSEG2 (kernel virtual) mapping + * of the ISA/PCI I/O space area. We map 64K here and + * the offsets from this address get treated with "match bytes" + * policy to make everything look little-endian. So, + * you need to also set CONFIG_SWAP_IO_SPACE, but this is the + * combination that works correctly with most of Linux's drivers. + */ + +#define PCI_BUS_ENABLED 1 +#define LDT_BUS_ENABLED 2 + +static int sb1250_bus_status = 0; + +#define MATCH_BITS 0x20000000 /* really belongs in an include file */ + +#define LDT_BRIDGE_START ((A_PCI_TYPE01_HEADER|MATCH_BITS)+0x00) +#define LDT_BRIDGE_END ((A_PCI_TYPE01_HEADER|MATCH_BITS)+0x20) + +/* + * Read/write access functions for various sizes of values + * in config space. + */ + +static int +sb1250_pci_read_config_byte(struct pci_dev *dev, int where, u8 * val) +{ + u32 data = 0; + u32 cfgaddr = CFGADDR(dev, where); + + data = READCFG32(cfgaddr); + + /* + * If the LDT was not configured, make it look like the bridge + * header is not there. + */ + if (!(sb1250_bus_status & LDT_BUS_ENABLED) && + (cfgaddr >= LDT_BRIDGE_START) && (cfgaddr < LDT_BRIDGE_END)) { + data = 0xFFFFFFFF; + } + + *val = (data >> ((where & 3) << 3)) & 0xff; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +sb1250_pci_read_config_word(struct pci_dev *dev, int where, u16 * val) +{ + u32 data = 0; + u32 cfgaddr = CFGADDR(dev, where); + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = READCFG32(cfgaddr); + + /* + * If the LDT was not configured, make it look like the bridge + * header is not there. + */ + if (!(sb1250_bus_status & LDT_BUS_ENABLED) && + (cfgaddr >= LDT_BRIDGE_START) && (cfgaddr < LDT_BRIDGE_END)) { + data = 0xFFFFFFFF; + } + + *val = (data >> ((where & 3) << 3)) & 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int +sb1250_pci_read_config_dword(struct pci_dev *dev, int where, u32 * val) +{ + u32 data = 0; + u32 cfgaddr = CFGADDR(dev, where); + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + + data = READCFG32(cfgaddr); + + /* + * If the LDT was not configured, make it look like the bridge + * header is not there. + */ + if (!(sb1250_bus_status & LDT_BUS_ENABLED) && + (cfgaddr >= LDT_BRIDGE_START) && (cfgaddr < LDT_BRIDGE_END)) { + data = 0xFFFFFFFF; + } + + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +sb1250_pci_write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + u32 data = 0; + u32 cfgaddr = CFGADDR(dev, where); + + data = READCFG32(cfgaddr); + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + WRITECFG32(cfgaddr, data); + + return PCIBIOS_SUCCESSFUL; +} + +static int +sb1250_pci_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + u32 data = 0; + u32 cfgaddr = CFGADDR(dev, where); + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = READCFG32(cfgaddr); + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + WRITECFG32(cfgaddr, data); + + return PCIBIOS_SUCCESSFUL; +} + +static int +sb1250_pci_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + u32 cfgaddr = CFGADDR(dev, where); + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + WRITECFG32(cfgaddr, val); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sb1250_pci_ops = { + sb1250_pci_read_config_byte, + sb1250_pci_read_config_word, + sb1250_pci_read_config_dword, + sb1250_pci_write_config_byte, + sb1250_pci_write_config_word, + sb1250_pci_write_config_dword +}; + + +void __init pcibios_init(void) +{ + uint32_t cmdreg; + + /* + * See if the PCI bus has been configured by the firmware. + */ + + cmdreg = READCFG32((A_PCI_TYPE00_HEADER | MATCH_BITS) + + R_PCI_TYPE0_CMDSTATUS); + + if (!(cmdreg & M_PCI_CMD_MASTER_EN)) { + printk + ("PCI: Skipping PCI probe. Bus is not initialized.\n"); + return; + } + + sb1250_bus_status |= PCI_BUS_ENABLED; + + /* + * Establish a mapping from KSEG2 (kernel virtual) to PCI I/O space + * Use "match bytes", even though this exposes endianness. + * big-endian Linuxes will have CONFIG_SWAP_IO_SPACE set. + */ + + set_io_port_base(ioremap(A_PHYS_LDTPCI_IO_MATCH_BYTES, 65536)); + + /* + * Also check the LDT bridge's enable, just in case we didn't + * initialize that one. + */ + + cmdreg = READCFG32((A_PCI_TYPE01_HEADER | MATCH_BITS) + + R_PCI_TYPE0_CMDSTATUS); + + if (cmdreg & M_PCI_CMD_MASTER_EN) { + sb1250_bus_status |= LDT_BUS_ENABLED; + } + + /* Probe for PCI hardware */ + + printk("PCI: Probing PCI hardware on host bus 0.\n"); + pci_scan_bus(0, &sb1250_pci_ops, NULL); + +} + +int __init pcibios_enable_device(struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +void __init +pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ +} + +char *__init pcibios_setup(char *str) +{ + /* Nothing to do for now. */ + + return str; +} + +struct pci_fixup pcibios_fixups[] = { + {0} +}; + +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); +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +unsigned __init int pcibios_assign_all_busses(void) +{ + return 1; +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/setup.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/setup.c --- linux-2.4.18/arch/mips/sibyte/sb1250/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/setup.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Setup code likely to be common to all SB1250 platforms */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include +#ifdef CONFIG_RTC +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * + */ + + +void sb1250_setup(void) +{ +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/smp.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/smp.c --- linux-2.4.18/arch/mips/sibyte/sb1250/smp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/smp.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* + * These are routines for dealing with the sb1250 smp capabilities + * independent of board/firmware + */ + +static u64 mailbox_set_regs[] = { + KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU, + KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU +}; + +static u64 mailbox_clear_regs[] = { + KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU, + KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU +}; + +static u64 mailbox_regs[] = { + KSEG1 + A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU, + KSEG1 + A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU +}; + + +/* + * Simple enough; everything is set up, so just poke the appropriate mailbox + * register, and we should be set + */ +void core_send_ipi(int cpu, unsigned int action) +{ + out64((((u64)action)<< 48), mailbox_set_regs[cpu]); +} + + +void sb1250_smp_finish(void) +{ + extern void sb1_sanitize_tlb(void); + + sb1_sanitize_tlb(); + sb1250_time_init(); +} + +void sb1250_mailbox_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + unsigned int action; + + /* Load the mailbox register to figure out what we're supposed to do */ + action = (in64(mailbox_regs[cpu]) >> 48) & 0xffff; + + /* Clear the mailbox to clear the interrupt */ + out64(((u64)action)<<48, mailbox_clear_regs[cpu]); + + /* + * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the + * interrupt will do the reschedule for us + */ + + if (action & SMP_CALL_FUNCTION) { + smp_call_function_interrupt(); + } +} diff -urN linux-2.4.18/arch/mips/sibyte/sb1250/time.c linux-2.4.19-pre5/arch/mips/sibyte/sb1250/time.c --- linux-2.4.18/arch/mips/sibyte/sb1250/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/sb1250/time.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * These are routines to set up and handle interrupts from the + * sb1250 general purpose timer 0. We're using the timer as a + * system clock, so we set it up to run at 100 Hz. On every + * interrupt, we update our idea of what the time of day is, + * then call do_timer() in the architecture-independent kernel + * code to do general bookkeeping (e.g. update jiffies, run + * bottom halves, etc.) + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); + + + +#define IMR_IP2_VAL K_INT_MAP_I0 +#define IMR_IP3_VAL K_INT_MAP_I1 +#define IMR_IP4_VAL K_INT_MAP_I2 + +void sb1250_time_init(void) +{ + int cpu = smp_processor_id(); + + /* Only have 4 general purpose timers */ + if (cpu > 3) { + BUG(); + } + + sb1250_mask_irq(cpu, K_INT_TIMER_0 + cpu); + + /* Map the timer interrupt to ip[4] of this cpu */ + out64(IMR_IP4_VAL, KSEG1 + A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + + ((K_INT_TIMER_0 + cpu)<<3)); + + /* the general purpose timer ticks at 1 Mhz independent if the rest of the system */ + /* Disable the timer and set up the count */ + out64(0, KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + out64( +#ifndef CONFIG_SIMULATION + 1000000/HZ +#else + 50000/HZ +#endif + , KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); + + /* Set the timer running */ + out64(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, + KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + sb1250_unmask_irq(cpu, K_INT_TIMER_0 + cpu); + /* + * This interrupt is "special" in that it doesn't use the request_irq + * way to hook the irq line. The timer interrupt is initialized early + * enough to make this a major pain, and it's also firing enough to + * warrant a bit of special case code. sb1250_timer_interrupt is + * called directly from irq_handler.S when IP[4] is set during an + * interrupt + */ +} + +extern int set_rtc_mmss(unsigned long nowtime); +extern rwlock_t xtime_lock; +static long last_rtc_update = 0; + +void sb1250_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + /* Reset the timer */ + out64(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, + KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + /* + * Need to do some stuff here with xtime, too, but that looks like + * it should be architecture independent...does it really belong here? + */ + if (!cpu) { + do_timer(regs); + + read_lock(&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 + && xtime.tv_sec > last_rtc_update + 660 + && xtime.tv_usec >= 500000 - (tick >> 1) + && xtime.tv_usec <= 500000 + (tick >> 1)) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 600; + } + read_unlock(&xtime_lock); + } + +#ifdef CONFIG_SMP + /* + * We need to make like a normal interrupt -- otherwise timer + * interrupts ignore the global interrupt lock, which would be + * a Bad Thing. + */ + irq_enter(cpu, 0); + update_process_times(user_mode(regs)); + irq_exit(cpu, 0); + + if (softirq_pending(cpu)) + do_softirq(); +#endif /* CONFIG_SMP */ +} diff -urN linux-2.4.18/arch/mips/sibyte/swarm/Makefile linux-2.4.19-pre5/arch/mips/sibyte/swarm/Makefile --- linux-2.4.18/arch/mips/sibyte/swarm/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,35 @@ +.S.s: + $(CPP) $(AFLAGS) $< -o $@ +.S.o: + $(CC) $(AFLAGS) -c $< -o $@ + +EXTRA_AFLAGS = -mips3 -mcpu=r4000 + +all: sbswarm.a + +OBJS-y = setup.o cmdline.o rtc.o time.o memory.o cfe_api.o + +OBJS-$(CONFIG_SMP) += smp.o + +OBJS-$(CONFIG_L3DEMO) += procl3switch.o l3procbootstrap.o l3proc.o +OBJS-$(CONFIG_REMOTE_DEBUG) += dbg_io.o + +#XMITTER=1 + +ifdef XMITTER +l3proc.bin: xmitter + ln xmitter l3proc.bin +else +l3proc.bin: l3proc + ln l3proc l3proc.bin +endif + +l3proc.o: l3proc.bin + mips-linux-ld -Tl3proc.lds -bbinary -o l3proc.o l3proc.bin + +sbswarm.a: $(OBJS-y) + $(AR) rcs sbswarm.a $^ + rm -f l3proc.o l3proc.bin + +include $(TOPDIR)/Rules.make + diff -urN linux-2.4.18/arch/mips/sibyte/swarm/cfe_api.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_api.c --- linux-2.4.18/arch/mips/sibyte/swarm/cfe_api.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_api.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Function stubs File: cfe_api.c + * + * This module contains device function stubs (small routines to + * call the standard "iocb" interface entry point to CFE). + * There should be one routine here per iocb function call. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* */ + + +#include "cfe_xiocb.h" +#include "cfe_api.h" +#include + +static long cfe_console_handle = -1; +static int (*cfe_dispfunc)(long handle,cfe_xiocb_t *xiocb) = 0; +static cfe_xuint_t cfe_handle = 0; + +/* + * This macro makes a "signed 64-bit pointer" - basically extending a regular + * pointer to its 64-bit compatibility space equivalent. + */ +#define BIGPTR(x) (long long) (long) (x) + +typedef unsigned long intptr_t; + +int cfe_init(cfe_xuint_t handle) +{ + unsigned int *sealloc = (unsigned int *) (intptr_t) (int) CFE_APISEAL; + if (*sealloc != CFE_EPTSEAL) return -1; + cfe_dispfunc = (void *) (cfe_xptr_t) (int) CFE_APIENTRY; + if (handle) cfe_handle = handle; + return 0; +} + +int cfe_iocb_dispatch(cfe_xiocb_t *xiocb) +{ + if (!cfe_dispfunc) + return -1; + + return (*cfe_dispfunc)(cfe_handle,xiocb); +} + +static int cfe_strlen(char *name) +{ + int count = 0; + + while (*name) { + count++; + name++; + } + + return count; +} + +int cfe_open(char *name) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = 0; + xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(name); + xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle; +} + +int cfe_close(int handle) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status); + +} + +int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_READ; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen; +} + +int cfe_read(int handle,unsigned char *buffer,int length) +{ + return cfe_readblk(handle,0,buffer,length); +} + + +int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.plist.xiocb_buffer.buf_retlen; +} + +int cfe_write(int handle,unsigned char *buffer,int length) +{ + return cfe_writeblk(handle,0,buffer,length); +} + + +int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_ioctlcmd = (cfe_xint_t) ioctlnum; + xiocb.plist.xiocb_buffer.buf_ptr = BIGPTR(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (retlen) *retlen = xiocb.plist.xiocb_buffer.buf_retlen; + return xiocb.xiocb_status; +} + +int cfe_inpstat(int handle) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_inpstat_t); + xiocb.plist.xiocb_inpstat.inp_status = 0; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) return xiocb.xiocb_status; + + return xiocb.plist.xiocb_inpstat.inp_status; + +} + +long long cfe_getticks(void) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_time_t); + xiocb.plist.xiocb_time.ticks = 0; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.plist.xiocb_time.ticks; + +} + +int cfe_getenv(char *name,char *dest,int destlen) +{ + cfe_xiocb_t xiocb; + + *dest = 0; + + xiocb.xiocb_fcode = CFE_CMD_ENV_GET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = 0; + xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); + xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); + xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(dest); + xiocb.plist.xiocb_envbuf.val_length = destlen; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + +int cfe_setenv(char *name,char *val) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_ENV_SET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = 0; + xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); + xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); + xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val); + xiocb.plist.xiocb_envbuf.val_length = cfe_strlen(val); + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + +int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type) +{ + cfe_xiocb_t xiocb; + xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_meminfo_t); + xiocb.plist.xiocb_meminfo.mi_idx = idx; + + cfe_iocb_dispatch(&xiocb); + + (*addr) = xiocb.plist.xiocb_meminfo.mi_addr; + (*size) = xiocb.plist.xiocb_meminfo.mi_size; + (*type) = xiocb.plist.xiocb_meminfo.mi_type; + + return xiocb.xiocb_status; +} + + +int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_ENV_SET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = idx; + xiocb.plist.xiocb_envbuf.name_ptr = BIGPTR(name); + xiocb.plist.xiocb_envbuf.name_length = namelen; + xiocb.plist.xiocb_envbuf.val_ptr = BIGPTR(val); + xiocb.plist.xiocb_envbuf.val_length = vallen; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + +int cfe_exit(int warm, int status) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_RESTART; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0; + xiocb.xiocb_psize = sizeof(xiocb_exitstat_t); + xiocb.plist.xiocb_exitstat.status = (cfe_xint_t) status; + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status); +} + +int cfe_flushcache(int flg) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = flg; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + +int cfe_getstdhandle(int flg) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = flg; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + return (xiocb.xiocb_status < 0) ? xiocb.xiocb_status : xiocb.xiocb_handle; + +} + +int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t); + xiocb.plist.xiocb_cpuctl.cpu_number = cpu; + xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START; + xiocb.plist.xiocb_cpuctl.gp_val = gp; + xiocb.plist.xiocb_cpuctl.sp_val = sp; + xiocb.plist.xiocb_cpuctl.a1_val = a1; + xiocb.plist.xiocb_cpuctl.start_addr = (long)fn; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + + +void cfe_open_console() +{ + cfe_console_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); +} + +void cfe_console_print(char *str) +{ + int len = strlen(str); + int res; + + if (cfe_console_handle != -1) { + cfe_write(cfe_console_handle, str, strlen(str)); + do { + res = cfe_writeblk(cfe_console_handle, 0, str, len); + if (res < 0) + break; + str += res; + len -= res; + } while (len); + } +} diff -urN linux-2.4.18/arch/mips/sibyte/swarm/cfe_api.h linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_api.h --- linux-2.4.18/arch/mips/sibyte/swarm/cfe_api.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_api.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device function prototypes File: cfe_api.h + * + * This module contains prototypes for cfe_devfuncs.c, a set + * of wrapper routines to the IOCB interface. This file, + * along with cfe_api.c, can be incorporated into programs + * that need to call CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* */ + + +#define CFE_EPTSEAL 0x43464531 +#define CFE_APIENTRY 0x9FC00500 +#define CFE_APISEAL 0x9FC00508 + +#ifndef __ASSEMBLER__ +int cfe_init(cfe_xuint_t handle); +int cfe_open(char *name); +int cfe_close(int handle); +int cfe_readblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length); +int cfe_read(int handle,unsigned char *buffer,int length); +int cfe_writeblk(int handle,cfe_xint_t offset,unsigned char *buffer,int length); +int cfe_write(int handle,unsigned char *buffer,int length); +int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen); +int cfe_inpstat(int handle); +int cfe_enumenv(int idx,char *name,int namelen,char *val,int vallen); +int cfe_enummem(long idx, unsigned long long *addr, unsigned long long *size, long *type); +int cfe_setenv(char *name,char *val); +int cfe_getenv(char *name,char *dest,int destlen); +long long cfe_getticks(void); +int cfe_exit(int warm, int status); +int cfe_flushcache(int flg); +int cfe_getstdhandle(int flg); +int cfe_start_cpu(int cpu, void (*fn)(void), long sp, long gp, long a1); + +void cfe_open_console(void); +void cfe_console_print(char *); +#endif diff -urN linux-2.4.18/arch/mips/sibyte/swarm/cfe_error.h linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_error.h --- linux-2.4.18/arch/mips/sibyte/swarm/cfe_error.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_error.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Error codes File: cfe_error.h + * + * CFE's global error code list is here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* */ + + + + +#define CFE_OK 0 +#define CFE_ERR -1 /* generic error */ +#define CFE_ERR_INV_COMMAND -2 +#define CFE_ERR_EOF -3 +#define CFE_ERR_IOERR -4 +#define CFE_ERR_NOMEM -5 +#define CFE_ERR_DEVNOTFOUND -6 +#define CFE_ERR_DEVOPEN -7 +#define CFE_ERR_INV_PARAM -8 +#define CFE_ERR_ENVNOTFOUND -9 +#define CFE_ERR_ENVREADONLY -10 + +#define CFE_ERR_NOTELF -11 +#define CFE_ERR_NOT32BIT -12 +#define CFE_ERR_WRONGENDIAN -13 +#define CFE_ERR_BADELFVERS -14 +#define CFE_ERR_NOTMIPS -15 +#define CFE_ERR_BADELFFMT -16 +#define CFE_ERR_BADADDR -17 + +#define CFE_ERR_FILENOTFOUND -18 +#define CFE_ERR_UNSUPPORTED -19 + +#define CFE_ERR_HOSTUNKNOWN -20 + +#define CFE_ERR_TIMEOUT -21 + +#define CFE_ERR_PROTOCOLERR -22 + +#define CFE_ERR_NETDOWN -23 +#define CFE_ERR_NONAMESERVER -24 + +#define CFE_ERR_NOHANDLES -25 +#define CFE_ERR_ALREADYBOUND -26 + +#define CFE_ERR_CANNOTSET -27 +#define CFE_ERR_NOMORE -28 +#define CFE_ERR_BADFILESYS -29 +#define CFE_ERR_FSNOTAVAIL -30 + +#define CFE_ERR_INVBOOTBLOCK -31 +#define CFE_ERR_WRONGDEVTYPE -32 +#define CFE_ERR_BBCHECKSUM -33 +#define CFE_ERR_BOOTPROGCHKSUM -34 + + + + + diff -urN linux-2.4.18/arch/mips/sibyte/swarm/cfe_xiocb.h linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_xiocb.h --- linux-2.4.18/arch/mips/sibyte/swarm/cfe_xiocb.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/cfe_xiocb.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB definitions File: cfe_iocb.h + * + * This module describes CFE's IOCB structure, the main + * data structure used to communicate API requests with CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* */ + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_INPSTAT 12 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_IOCTL 15 +#define CFE_CMD_DEV_CLOSE 16 +#define CFE_CMD_DEV_GETINFO 17 + +#define CFE_CMD_ENV_ENUM 20 +#define CFE_CMD_ENV_GET 22 +#define CFE_CMD_ENV_SET 23 +#define CFE_CMD_ENV_DEL 24 + +#define CFE_CMD_MAX 32 + +#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ +#define CFE_MI_AVAILABLE 1 /* memory is available */ + +#define CFE_FLG_WARMSTART 0x00000001 + +#define CFE_FLG_ENV_PERMANENT 0x00000001 + +#define CFE_CPU_CMD_START 1 +#define CFE_CPU_CMD_STOP 0 + +#define CFE_STDHANDLE_CONSOLE 0 + +#define CFE_DEV_NETWORK 1 +#define CFE_DEV_DISK 2 +#define CFE_DEV_FLASH 3 +#define CFE_DEV_SERIAL 4 +#define CFE_DEV_CPU 5 +#define CFE_DEV_NVRAM 6 +#define CFE_DEV_OTHER 7 +#define CFE_DEV_MASK 0x0F + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef unsigned long long cfe_xuint_t; +typedef long long cfe_xint_t; +typedef long long cfe_xptr_t; + +typedef struct xiocb_buffer_s { + cfe_xuint_t buf_offset; /* offset on device (bytes) */ + cfe_xptr_t buf_ptr; /* pointer to a buffer */ + cfe_xuint_t buf_length; /* length of this buffer */ + cfe_xuint_t buf_retlen; /* returned length (for read ops) */ + cfe_xuint_t buf_ioctlcmd; /* IOCTL command (used only for IOCTLs) */ +} xiocb_buffer_t; + +#define buf_devflags buf_ioctlcmd /* returned device info flags */ + +typedef struct xiocb_inpstat_s { + cfe_xuint_t inp_status; /* 1 means input available */ +} xiocb_inpstat_t; + +typedef struct xiocb_envbuf_s { + cfe_xint_t enum_idx; /* 0-based enumeration index */ + cfe_xptr_t name_ptr; /* name string buffer */ + cfe_xint_t name_length; /* size of name buffer */ + cfe_xptr_t val_ptr; /* value string buffer */ + cfe_xint_t val_length; /* size of value string buffer */ +} xiocb_envbuf_t; + +typedef struct xiocb_cpuctl_s { + cfe_xuint_t cpu_number; /* cpu number to control */ + cfe_xuint_t cpu_command; /* command to issue to CPU */ + cfe_xuint_t start_addr; /* CPU start address */ + cfe_xuint_t gp_val; /* starting GP value */ + cfe_xuint_t sp_val; /* starting SP value */ + cfe_xuint_t a1_val; /* starting A1 value */ +} xiocb_cpuctl_t; + +typedef struct xiocb_time_s { + cfe_xint_t ticks; /* current time in ticks */ +} xiocb_time_t; + +typedef struct xiocb_exitstat_s { + cfe_xint_t status; +} xiocb_exitstat_t; + +typedef struct xiocb_meminfo_s { + cfe_xint_t mi_idx; /* 0-based enumeration index */ + cfe_xint_t mi_type; /* type of memory block */ + cfe_xuint_t mi_addr; /* physical start address */ + cfe_xuint_t mi_size; /* block size */ +} xiocb_meminfo_t; + +#define CFE_FWI_64BIT 0x00000001 +#define CFE_FWI_32BIT 0x00000002 +#define CFE_FWI_RELOC 0x00000004 +#define CFE_FWI_UNCACHED 0x00000008 +#define CFE_FWI_MULTICPU 0x00000010 +#define CFE_FWI_FUNCSIM 0x00000020 +#define CFE_FWI_RTLSIM 0x00000040 + +typedef struct xiocb_fwinfo_s { + cfe_xint_t fwi_version; /* major, minor, eco version */ + cfe_xint_t fwi_totalmem; /* total installed mem */ + cfe_xint_t fwi_flags; /* various flags */ + cfe_xint_t fwi_boardid; /* board ID */ + cfe_xint_t fwi_bootarea_va; /* VA of boot area */ + cfe_xint_t fwi_bootarea_pa; /* PA of boot area */ + cfe_xint_t fwi_bootarea_size; /* size of boot area */ + cfe_xint_t fwi_reserved1; + cfe_xint_t fwi_reserved2; + cfe_xint_t fwi_reserved3; +} xiocb_fwinfo_t,cfe_fwinfo_t; + +typedef struct cfe_xiocb_s { + cfe_xuint_t xiocb_fcode; /* IOCB function code */ + cfe_xint_t xiocb_status; /* return status */ + cfe_xint_t xiocb_handle; /* file/device handle */ + cfe_xuint_t xiocb_flags; /* flags for this IOCB */ + cfe_xuint_t xiocb_psize; /* size of parameter list */ + union { + xiocb_buffer_t xiocb_buffer; /* buffer parameters */ + xiocb_inpstat_t xiocb_inpstat; /* input status parameters */ + xiocb_envbuf_t xiocb_envbuf; /* environment function parameters */ + xiocb_cpuctl_t xiocb_cpuctl; /* CPU control parameters */ + xiocb_time_t xiocb_time; /* timer parameters */ + xiocb_meminfo_t xiocb_meminfo; /* memory arena info parameters */ + xiocb_fwinfo_t xiocb_fwinfo; /* firmware information */ + xiocb_exitstat_t xiocb_exitstat; /* Exit status */ + } plist; +} cfe_xiocb_t; + + diff -urN linux-2.4.18/arch/mips/sibyte/swarm/cmdline.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/cmdline.c --- linux-2.4.18/arch/mips/sibyte/swarm/cmdline.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/cmdline.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include + +/* + * The naming of this variable is a remnant of the initial mips port to + * ARC-firmware based SGI consoles. We don't really need to do anything for + * the variable other than provide an instantiation. Everything about + * arcs_cmdline seems more than a little bit hackish... + */ +char arcs_cmdline[CL_SIZE]; diff -urN linux-2.4.18/arch/mips/sibyte/swarm/memory.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/memory.c --- linux-2.4.18/arch/mips/sibyte/swarm/memory.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/memory.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Memory related routines + */ + +#include +#include +#include + +extern phys_t swarm_mem_region_addrs[]; +extern phys_t swarm_mem_region_sizes[]; +extern unsigned int swarm_mem_region_count; + +int page_is_ram(unsigned long pagenr) +{ + phys_t addr = pagenr << PAGE_SHIFT; +#ifdef CONFIG_SWARM_STANDALONE + if (addr < (CONFIG_SIBYTE_SWARM_RAM_SIZE * 1024 * 1024)) { + return 1; + } +#else + int i; + for (i = 0; i < swarm_mem_region_count; i++) { + if ((addr >= swarm_mem_region_addrs[i]) + && (addr < (swarm_mem_region_addrs[i] + swarm_mem_region_sizes[i]))) { + return 1; + } + } +#endif + return 0; +} diff -urN linux-2.4.18/arch/mips/sibyte/swarm/rtc.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/rtc.c --- linux-2.4.18/arch/mips/sibyte/swarm/rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/rtc.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Not really sure what is supposed to be here, yet + */ + +#include +#include + +static unsigned char swarm_rtc_read_data(unsigned long addr) +{ + return 0; +} + +static void swarm_rtc_write_data(unsigned char data, unsigned long addr) +{ +} + +static int swarm_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops swarm_rtc_ops = { + &swarm_rtc_read_data, + &swarm_rtc_write_data, + &swarm_rtc_bcd_mode +}; diff -urN linux-2.4.18/arch/mips/sibyte/swarm/setup.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/setup.c --- linux-2.4.18/arch/mips/sibyte/swarm/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/setup.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Setup code for the SWARM board + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cfe_xiocb.h" +#include "cfe_api.h" +#include "cfe_error.h" + +extern struct rtc_ops swarm_rtc_ops; +extern int cfe_console_handle; + +#ifdef CONFIG_BLK_DEV_IDE_SWARM +extern struct ide_ops *ide_ops; +#endif + + +#ifdef CONFIG_L3DEMO +extern void *l3info; +#endif + +/* Max ram addressable in 32-bit segments */ +#ifdef CONFIG_HIGHMEM +#ifdef CONFIG_64BIT_PHYS_ADDR +#define MAX_RAM_SIZE (~0ULL) +#else +#define MAX_RAM_SIZE (0xffffffffULL) +#endif +#else +#ifdef CONFIG_MIPS64 +#define MAX_RAM_SIZE (~0ULL) +#else +#define MAX_RAM_SIZE (0x1fffffffULL) +#endif +#endif + + +#ifndef CONFIG_SWARM_STANDALONE + +phys_t swarm_mem_region_addrs[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS]; +phys_t swarm_mem_region_sizes[CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS]; +unsigned int swarm_mem_region_count; + +#endif + +const char *get_system_type(void) +{ + return "SiByte Swarm"; +} + +#ifdef CONFIG_BLK_DEV_IDE_SWARM +static int swarm_ide_default_irq(ide_ioreg_t base) +{ + return 0; +} + +static ide_ioreg_t swarm_ide_default_io_base(int index) +{ + return 0; +} + +static void swarm_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + ide_ioreg_t reg = data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; + } + if (irq != NULL) + *irq = 0; + hw->io_ports[IDE_IRQ_OFFSET] = 0; +} + +static int swarm_ide_request_irq(unsigned int irq, + void (*handler)(int,void *, struct pt_regs *), + unsigned long flags, const char *device, + void *dev_id) +{ + return request_irq(irq, handler, flags, device, dev_id); +} + +static void swarm_ide_free_irq(unsigned int irq, void *dev_id) +{ + free_irq(irq, dev_id); +} + +static int swarm_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + /* Note: "check_region" and friends do conflict management on ISA I/O + space. Our disk is not in that space, so this check won't work */ + /* return check_region(from, extent); */ + return 0; +} + +static void swarm_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + /* request_region(from, extent, name); */ +} + +static void swarm_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + /* release_region(from, extent); */ +} + + +void swarm_ideproc(ide_ide_action_t action, ide_drive_t *drive, + void *buffer, unsigned int count) +{ + /* slow? vlb_sync? */ + switch (action) { + case ideproc_ide_input_data: + if (drive->io_32bit) { + swarm_insl(IDE_DATA_REG, buffer, count); + } else { + swarm_insw(IDE_DATA_REG, buffer, count<<1); + } + break; + case ideproc_ide_output_data: + if (drive->io_32bit) { + swarm_outsl(IDE_DATA_REG, buffer, count); + } else { + swarm_outsw(IDE_DATA_REG, buffer, count<<1); + } + break; + case ideproc_atapi_input_bytes: + count++; + if (drive->io_32bit) { + swarm_insl(IDE_DATA_REG, buffer, count>>2); + } else { + swarm_insw(IDE_DATA_REG, buffer, count>>1); + } + if ((count & 3) >= 2) + swarm_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1); + break; + case ideproc_atapi_output_bytes: + count++; + if (drive->io_32bit) { + swarm_outsl(IDE_DATA_REG, buffer, count>>2); + } else { + swarm_outsw(IDE_DATA_REG, buffer, count>>1); + } + if ((count & 3) >= 2) + swarm_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1); + break; + } +} + +struct ide_ops swarm_ide_ops = { + &swarm_ide_default_irq, + &swarm_ide_default_io_base, + &swarm_ide_init_hwif_ports, + &swarm_ide_request_irq, + &swarm_ide_free_irq, + &swarm_ide_check_region, + &swarm_ide_request_region, + &swarm_ide_release_region +}; +#endif + + +#ifdef CONFIG_SMP +static void smp_cpu0_exit(void *unused) +{ + printk("swarm_linux_exit called (cpu1) - passing control back to CFE\n"); + cfe_exit(1,0); +} +#endif + +static void swarm_linux_exit(void) +{ +#ifdef CONFIG_SMP + if (smp_processor_id()) { + smp_call_function(smp_cpu0_exit,NULL,1,1); + while(1); + } +#endif + printk("swarm_linux_exit called...passing control back to CFE\n"); + cfe_exit(1, 0); + printk("cfe_exit returned??\n"); + while(1); +} + +void __init bus_error_init(void) +{ +} + +extern void swarm_time_init(void); + +void __init swarm_setup(void) +{ + extern int panic_timeout; + + rtc_ops = &swarm_rtc_ops; + panic_timeout = 5; /* For debug. This should probably be raised later */ + _machine_restart = (void (*)(char *))swarm_linux_exit; + _machine_halt = swarm_linux_exit; + _machine_power_off = swarm_linux_exit; + +#ifdef CONFIG_L3DEMO + if (l3info != NULL) { + printk("\n"); + } +#endif + printk("This kernel optimized for " +#ifdef CONFIG_SIMULATION + "simulation" +#else + "board" +#endif + " runs\n"); + + board_timer_setup = swarm_time_init; + +#ifdef CONFIG_BLK_DEV_IDE_SWARM + ide_ops = &swarm_ide_ops; +#endif +} + +/* This is the kernel command line. Actually, it's + copied, eventually, to command_line, and looks to be + quite redundant. But not something to fix just now */ +extern char arcs_cmdline[]; + +#ifdef CONFIG_EMBEDDED_RAMDISK +/* These are symbols defined by the ramdisk linker script */ +extern unsigned char __rd_start; +extern unsigned char __rd_end; +#endif + +static __init void prom_meminit(void) +{ + u64 addr, size; /* regardless of 64BIT_PHYS_ADDR */ + long type; + unsigned int idx; + int rd_flag; + +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long initrd_pstart; + unsigned long initrd_pend; + +#ifdef CONFIG_EMBEDDED_RAMDISK + /* If we're using an embedded ramdisk, then __rd_start and __rd_end + are defined by the linker to be on either side of the ramdisk + area. Otherwise, initrd_start should be defined by kernel command + line arguments */ + if (initrd_start == 0) { + initrd_start = (unsigned long)&__rd_start; + initrd_end = (unsigned long)&__rd_end; + } +#endif + + initrd_pstart = __pa(initrd_start); + initrd_pend = __pa(initrd_end); + if (initrd_start && + ((initrd_pstart > MAX_RAM_SIZE) + || (initrd_pend > MAX_RAM_SIZE))) { + setleds("INRD"); + panic("initrd out of addressable memory"); + } + +#endif /* INITRD */ + + for (idx = 0; cfe_enummem(idx, &addr, &size, &type) != CFE_ERR_NOMORE; + idx++) { + rd_flag = 0; + if (type == CFE_MI_AVAILABLE) { + /* + * See if this block contains (any portion of) the + * ramdisk + */ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + if ((initrd_pstart > addr) && + (initrd_pstart < (addr + size))) { + add_memory_region(addr, + initrd_pstart - addr, + BOOT_MEM_RAM); + rd_flag = 1; + } + if ((initrd_pend > addr) && + (initrd_pend < (addr + size))) { + add_memory_region(initrd_pend, + (addr + size) - initrd_pend, + BOOT_MEM_RAM); + rd_flag = 1; + } + } +#endif + if (!rd_flag) { + if (addr > MAX_RAM_SIZE) + continue; + if (addr+size > MAX_RAM_SIZE) + size = MAX_RAM_SIZE - (addr+size) + 1; + add_memory_region(addr, size, BOOT_MEM_RAM); + } + swarm_mem_region_addrs[swarm_mem_region_count] = addr; + swarm_mem_region_sizes[swarm_mem_region_count] = size; + swarm_mem_region_count++; + if (swarm_mem_region_count == + CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS) { + /* + * Too many regions. Need to configure more + */ + while(1); + } + } + } +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + add_memory_region(initrd_pstart, initrd_pend - initrd_pstart, + BOOT_MEM_RESERVED); + } +#endif +} + + +#ifdef CONFIG_BLK_DEV_INITRD +static int __init initrd_setup(char *str) +{ + /* + *Initrd location comes in the form "@" + * e.g. initrd=3abfd@80010000. This is set up by the loader. + */ + char *tmp, *endptr; + unsigned long initrd_size; + for (tmp = str; *tmp != '@'; tmp++) { + if (!*tmp) { + goto fail; + } + } + *tmp = 0; + tmp++; + if (!*tmp) { + goto fail; + } + initrd_size = simple_strtol(str, &endptr, 16); + if (*endptr) { + goto fail; + } + initrd_start = simple_strtol(tmp, &endptr, 16); + if (*endptr) { + goto fail; + } + initrd_end = initrd_start + initrd_size; + printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start); + return 1; + fail: + printk("Bad initrd argument. Disabling initrd\n"); + initrd_start = 0; + initrd_end = 0; + return 1; +} + +#endif + +/* + * prom_init is called just after the cpu type is determined, from init_arch() + */ +__init int prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + /* + * This should go away. Detect if we're booting + * straight from cfe without a loader. If we + * are, then we've got a prom vector in a0. Otherwise, + * argc (and argv and envp, for that matter) will be 0) + */ + if (argc < 0) { + prom_vec = (int *)argc; + } + cfe_init((long)prom_vec); + cfe_open_console(); + if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) { + if (argc < 0) { + /* + * It's OK for direct boot to not provide a + * command line + */ + strcpy(arcs_cmdline, "root=/dev/ram0 "); + } else { + /* The loader should have set the command line */ + setleds("CMDL"); + panic("LINUX_CMDLINE not defined in cfe."); + } + } + +#ifdef CONFIG_BLK_DEV_INITRD + { + char *ptr; + /* Need to find out early whether we've got an initrd. So scan + the list looking now */ + for (ptr = arcs_cmdline; *ptr; ptr++) { + while (*ptr == ' ') { + ptr++; + } + if (!strncmp(ptr, "initrd=", 7)) { + initrd_setup(ptr+7); + break; + } else { + while (*ptr && (*ptr != ' ')) { + ptr++; + } + } + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Not sure this is needed, but it's the safe way. */ + arcs_cmdline[CL_SIZE-1] = 0; + + mips_machgroup = MACH_GROUP_SIBYTE; + prom_meminit(); + + return 0; +} + +void prom_free_prom_memory(void) +{ + /* Not sure what I'm supposed to do here. Nothing, I think */ +} + +static void setled(unsigned int index, char c) +{ + volatile unsigned char *led_ptr; + + led_ptr = (unsigned char *)(IO_SPACE_BASE | LED_BASE_ADDR); + if (index < 4) { + led_ptr[(3-index)<<3] = c; + } +} + +void setleds(char *str) +{ + int i; + for (i = 0; i < 4; i++) { + if (!str[i]) { + for (; i < 4; i++) { + setled(' ', str[i]); + } + } else { + setled(i, str[i]); + } + } +} + +#include + +static struct timer_list led_timer; +static unsigned char default_led_msg[] = + "Today: the CSWARM. Tomorrow: the WORLD!!!! "; +static unsigned char *led_msg = default_led_msg; +static unsigned char *led_msg_ptr = default_led_msg; + +void set_led_msg(char *new_msg) +{ + led_msg = new_msg; + led_msg_ptr = new_msg; + setleds(" "); +} + +static void move_leds(unsigned long arg) +{ + int i; + unsigned char *tmp = led_msg_ptr; + for (i = 0; i < 4; i++) { + setled(i, *tmp); + tmp++; + if (!*tmp) { + tmp = led_msg; + } + } + led_msg_ptr++; + if (!*led_msg_ptr) { + led_msg_ptr = led_msg; + } + del_timer(&led_timer); + led_timer.expires = jiffies + (HZ/8); + add_timer(&led_timer); +} + +void hack_leds(void) +{ + init_timer(&led_timer); + led_timer.expires = jiffies + (HZ/8); + led_timer.data = 0; + led_timer.function = move_leds; + add_timer(&led_timer); +} diff -urN linux-2.4.18/arch/mips/sibyte/swarm/smp.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/smp.c --- linux-2.4.18/arch/mips/sibyte/swarm/smp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/smp.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cfe_xiocb.h" +#include "cfe_api.h" + +extern void asmlinkage smp_bootstrap(void); + +/* Boot all other cpus in the system, initialize them, and + bring them into the boot fn */ +int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp) +{ + int retval; + + if ((retval = cfe_start_cpu(1, &smp_bootstrap, sp, gp, 0)) != 0) { + printk("cfe_start_cpu returned %i\n" , retval); + panic("secondary bootstrap failed"); + } + + return 1; +} + + +void prom_init_secondary(void) +{ + /* Set up kseg0 to be cachable coherent */ + clear_cp0_config(CONF_CM_CMASK); + set_cp0_config(0x5); + + /* Enable interrupts for lines 0-4 */ + clear_cp0_status(0xe000); + set_cp0_status(0x1f01); +} + + +/* + * Set up state, return the total number of cpus in the system, including + * the master + */ +int prom_setup_smp(void) +{ + /* Nothing to do here */ + return 2; +} + +void prom_smp_finish(void) +{ + sb1250_smp_finish(); +} + +/* + * XXX This is really halfway portable code and halfway system specific code. + */ +extern atomic_t cpus_booted; + +void __init smp_boot_cpus(void) +{ + int i; + + smp_num_cpus = prom_setup_smp(); + init_new_context(current, &init_mm); + current->processor = 0; + cpu_data[0].udelay_val = loops_per_jiffy; + cpu_data[0].asid_cache = ASID_FIRST_VERSION; + CPUMASK_CLRALL(cpu_online_map); + CPUMASK_SETB(cpu_online_map, 0); + atomic_set(&cpus_booted, 1); /* Master CPU is already booted... */ + init_idle(); + for (i = 1; i < smp_num_cpus; i++) { + struct task_struct *p; + struct pt_regs regs; + printk("Starting CPU %d... ", i); + + /* Spawn a new process normally. Grab a pointer to + its task struct so we can mess with it */ + do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); + p = init_task.prev_task; + + /* Schedule the first task manually */ + p->processor = i; + p->cpus_runnable = 1 << i; /* we schedule the first task manually */ + + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + init_tasks[i] = p; + + del_from_runqueue(p); + unhash_process(p); + + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); + +#if 0 + /* This is copied from the ip-27 code in the mips64 tree */ + + struct task_struct *p; + + /* + * The following code is purely to make sure + * Linux can schedule processes on this slave. + */ + kernel_thread(0, NULL, CLONE_PID); + p = init_task.prev_task; + sprintf(p->comm, "%s%d", "Idle", i); + init_tasks[i] = p; + p->processor = i; + p->cpus_runnable = 1 << i; /* we schedule the first task manually */ + del_from_runqueue(p); + unhash_process(p); + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); +#endif + } + + /* Wait for everyone to come up */ + while (atomic_read(&cpus_booted) != smp_num_cpus); + + smp_threads_ready = 1; +} diff -urN linux-2.4.18/arch/mips/sibyte/swarm/time.c linux-2.4.19-pre5/arch/mips/sibyte/swarm/time.c --- linux-2.4.18/arch/mips/sibyte/swarm/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/sibyte/swarm/time.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Time routines for the swarm board. We pass all the hard stuff + * through to the sb1250 handling code. Only thing we really keep + * track of here is what time of day we think it is. And we don't + * really even do a good job of that... + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern rwlock_t xtime_lock; + +/* Xicor 1241 definitions */ + +/* + * Register bits + */ + +#define X1241REG_SR_BAT 0x80 /* currently on battery power */ +#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ +#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ +#define X1241REG_SR_RTCF 0x01 /* clock failed */ +#define X1241REG_BL_BP2 0x80 /* block protect 2 */ +#define X1241REG_BL_BP1 0x40 /* block protect 1 */ +#define X1241REG_BL_BP0 0x20 /* block protect 0 */ +#define X1241REG_BL_WD1 0x10 +#define X1241REG_BL_WD0 0x08 +#define X1241REG_HR_MIL 0x80 /* military time format */ + +/* + * Register numbers + */ + +#define X1241REG_BL 0x10 /* block protect bits */ +#define X1241REG_INT 0x11 /* */ +#define X1241REG_SC 0x30 /* Seconds */ +#define X1241REG_MN 0x31 /* Minutes */ +#define X1241REG_HR 0x32 /* Hours */ +#define X1241REG_DT 0x33 /* Day of month */ +#define X1241REG_MO 0x34 /* Month */ +#define X1241REG_YR 0x35 /* Year */ +#define X1241REG_DW 0x36 /* Day of Week */ +#define X1241REG_Y2K 0x37 /* Year 2K */ +#define X1241REG_SR 0x3F /* Status register */ + +#define X1241_CCR_ADDRESS 0x6F + +#define SMB_CSR(reg) (KSEG1 | A_SMB_REGISTER(1, reg)) + +static int xicor_read(uint8_t addr) +{ + while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) + ; + + out64((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); + out64((addr & 0xff), SMB_CSR(R_SMB_DATA)); + out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), SMB_CSR(R_SMB_START)); + + while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) + ; + + out64((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), SMB_CSR(R_SMB_START)); + + while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) + ; + + if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { + /* Clear error bit by writing a 1 */ + out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); + return -1; + } + + return (in64(SMB_CSR(R_SMB_DATA)) & 0xff); +} + +static int xicor_write(uint8_t addr, int b) +{ + while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) + ; + + out64(addr, SMB_CSR(R_SMB_CMD)); + out64((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); + out64(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, + SMB_CSR(R_SMB_START)); + + while (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) + ; + + if (in64(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { + /* Clear error bit by writing a 1 */ + out64(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); + return -1; + } else { + return 0; + } +} + +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ +int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + + cmos_minutes = xicor_read(X1241REG_MN); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + /* unlock writes to the CCR */ + xicor_write(X1241REG_SR, X1241REG_SR_WEL); + xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + xicor_write(X1241REG_SC, real_seconds); + xicor_write(X1241REG_MN, real_minutes); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + xicor_write(X1241REG_SR, 0); + + printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds); + + return retval; +} + +static unsigned long __init get_swarm_time(void) +{ + unsigned int year, mon, day, hour, min, sec, y2k; + + sec = xicor_read(X1241REG_SC); + min = xicor_read(X1241REG_MN); + hour = xicor_read(X1241REG_HR); + + if (hour & X1241REG_HR_MIL) { + hour &= 0x3f; + } else { + if (hour & 0x20) + hour = (hour & 0xf) + 0x12; + } + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + + day = xicor_read(X1241REG_DT); + mon = xicor_read(X1241REG_MO); + year = xicor_read(X1241REG_YR); + y2k = xicor_read(X1241REG_Y2K); + + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(y2k); + + year += (y2k * 100); + + return mktime(year, mon, day, hour, min, sec); +} + +/* + * Bring up the timer at 100 Hz. + */ +void __init swarm_time_init(void) +{ + unsigned int flags; + int status; + + /* Set up the scd general purpose timer 0 to cpu 0 */ + sb1250_time_init(); + + /* Establish communication with the Xicor 1241 RTC */ + /* XXXKW how do I share the SMBus with the I2C subsystem? */ + + out64(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ)); + out64(0, SMB_CSR(R_SMB_CONTROL)); + + if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) { + printk("x1241: couldn't detect on SWARM SMBus 1\n"); + } else { + if (status & X1241REG_SR_RTCF) + printk("x1241: battery failed -- time is probably wrong\n"); + write_lock_irqsave (&xtime_lock, flags); + xtime.tv_sec = get_swarm_time(); + xtime.tv_usec = 0; + write_unlock_irqrestore(&xtime_lock, flags); + } +} diff -urN linux-2.4.18/arch/mips/sni/int-handler.S linux-2.4.19-pre5/arch/mips/sni/int-handler.S --- linux-2.4.18/arch/mips/sni/int-handler.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/int-handler.S Sat Mar 30 22:55:27 2002 @@ -1,7 +1,7 @@ /* * SNI RM200 PCI specific interrupt handler code. * - * Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000 by Ralf Baechle + * Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000, 01 by Ralf Baechle */ #include #include @@ -9,12 +9,13 @@ #include #include -/* The PCI ASIC has the nasty property that it may delay writes if it is busy. - As a consequence from writes that have not graduated when we exit from the - interrupt handler we might catch a spurious interrupt. To avoid this we - force the PCI ASIC to graduate all writes by executing a read from the - PCI bus. */ - +/* + * The PCI ASIC has the nasty property that it may delay writes if it is busy. + * As a consequence from writes that have not graduated when we exit from the + * interrupt handler we might catch a spurious interrupt. To avoid this we + * force the PCI ASIC to graduate all writes by executing a read from the + * PCI bus. + */ .set noreorder .set noat .align 5 @@ -46,7 +47,7 @@ bnez t1, _hwint0 nop - j return # spurious interrupt + j restore_all # spurious interrupt nop ############################################################################## diff -urN linux-2.4.18/arch/mips/sni/io.c linux-2.4.19-pre5/arch/mips/sni/io.c --- linux-2.4.18/arch/mips/sni/io.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/io.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,4 @@ -/* $Id: io.c,v 1.4 1999/08/18 23:37:46 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -urN linux-2.4.18/arch/mips/sni/irq.c linux-2.4.19-pre5/arch/mips/sni/irq.c --- linux-2.4.18/arch/mips/sni/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/irq.c Sat Mar 30 22:55:27 2002 @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include @@ -126,7 +125,7 @@ void __init init_pciasic(void) { - unsigned int flags; + unsigned long flags; spin_lock_irqsave(&pciasic_lock, flags); * (volatile u8 *) PCIMT_IRQSEL = diff -urN linux-2.4.18/arch/mips/sni/pci.c linux-2.4.19-pre5/arch/mips/sni/pci.c --- linux-2.4.18/arch/mips/sni/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/pci.c Sat Mar 30 22:55:27 2002 @@ -25,7 +25,7 @@ ((dev->bus->number & 0xff) << 0x10) | \ ((dev->devfn & 0xff) << 0x08) | \ (where & 0xfc); \ -} while(0); +} while(0) #if 0 /* To do: Bring this uptodate ... */ diff -urN linux-2.4.18/arch/mips/sni/pcimt_scache.c linux-2.4.19-pre5/arch/mips/sni/pcimt_scache.c --- linux-2.4.18/arch/mips/sni/pcimt_scache.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/pcimt_scache.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,4 @@ -/* $Id: pcimt_scache.c,v 1.4 1999/01/04 16:03:59 ralf Exp $ - * +/* * arch/mips/sni/pcimt_scache.c * * This file is subject to the terms and conditions of the GNU General Public diff -urN linux-2.4.18/arch/mips/sni/setup.c linux-2.4.19-pre5/arch/mips/sni/setup.c --- linux-2.4.18/arch/mips/sni/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/sni/setup.c Sat Mar 30 22:55:27 2002 @@ -30,6 +30,7 @@ #include #include #include +#include extern void sni_machine_restart(char *command); extern void sni_machine_halt(void); @@ -39,8 +40,6 @@ extern struct rtc_ops std_rtc_ops; extern struct kbd_ops std_kbd_ops; -void (*board_time_init)(struct irqaction *irq); - static void __init sni_rm200_pci_time_init(struct irqaction *irq) { /* set the clock to 100 Hz */ @@ -50,7 +49,6 @@ setup_irq(0, irq); } -unsigned char aux_device_present; extern unsigned char sni_map_isa_cache; /* @@ -80,7 +78,7 @@ sni_pcimt_detect(); sni_pcimt_sc_init(); - mips_io_port_base = SNI_PORT_BASE; + set_io_port_base(SNI_PORT_BASE); /* * Setup (E)ISA I/O memory access stuff diff -urN linux-2.4.18/arch/mips/tools/Makefile linux-2.4.19-pre5/arch/mips/tools/Makefile --- linux-2.4.18/arch/mips/tools/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/tools/Makefile Sat Mar 30 22:55:27 2002 @@ -3,8 +3,6 @@ # Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) # Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu) # -# $Id: Makefile,v 1.2 1997/09/23 06:23:49 ralf Exp $ -# TARGET := $(TOPDIR)/include/asm-$(ARCH)/offset.h .S.s: diff -urN linux-2.4.18/arch/mips/tools/offset.c linux-2.4.19-pre5/arch/mips/tools/offset.c --- linux-2.4.18/arch/mips/tools/offset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips/tools/offset.c Sat Mar 30 22:55:27 2002 @@ -121,10 +121,6 @@ thread.irix_trampoline); offset("#define THREAD_OLDCTX ", struct task_struct, \ thread.irix_oldctx); - offset("#define THREAD_DSEEPC ", struct task_struct, \ - thread.dsemul_epc); - offset("#define THREAD_DSEAERPC ", struct task_struct, \ - thread.dsemul_aerpc); linefeed; } diff -urN linux-2.4.18/arch/mips/vr4181/common/Makefile linux-2.4.19-pre5/arch/mips/vr4181/common/Makefile --- linux-2.4.18/arch/mips/vr4181/common/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/common/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,18 @@ +# +# Makefile for common code of NEC vr4181 based boards +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET:= vr4181.o + +obj-y := irq.o int_handler.o serial.o time.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/vr4181/common/int_handler.S linux-2.4.19-pre5/arch/mips/vr4181/common/int_handler.S --- linux-2.4.18/arch/mips/vr4181/common/int_handler.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/common/int_handler.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,206 @@ +/* + * arch/mips/vr4181/common/int_handler.S + * + * Adapted to the VR4181 and almost entirely rewritten: + * Copyright (C) 1999 Bradley D. LaRonde and Michael Klar + * + * Clean up to conform to the new IRQ + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include + +#include + +/* + * [jsun] + * See include/asm/vr4181/irq.h for IRQ assignment and strategy. + */ + + .text + .set noreorder + + .align 5 + NESTED(vr4181_handle_irq, PT_SIZE, ra) + + .set noat + SAVE_ALL + CLI + + .set at + .set noreorder + + mfc0 t0, CP0_CAUSE + mfc0 t2, CP0_STATUS + + and t0, t2 + + /* we check IP3 first; it happens most frequently */ + andi t1, t0, STATUSF_IP3 + bnez t1, ll_cpu_ip3 + andi t1, t0, STATUSF_IP2 + bnez t1, ll_cpu_ip2 + andi t1, t0, STATUSF_IP7 /* cpu timer */ + bnez t1, ll_cputimer_irq + andi t1, t0, STATUSF_IP4 + bnez t1, ll_cpu_ip4 + andi t1, t0, STATUSF_IP5 + bnez t1, ll_cpu_ip5 + andi t1, t0, STATUSF_IP6 + bnez t1, ll_cpu_ip6 + andi t1, t0, STATUSF_IP0 /* software int 0 */ + bnez t1, ll_cpu_ip0 + andi t1, t0, STATUSF_IP1 /* software int 1 */ + bnez t1, ll_cpu_ip1 + nop + + .set reorder +do_spurious: + j spurious_interrupt + +/* + * regular CPU irqs + */ +ll_cputimer_irq: + li a0, VR4181_IRQ_TIMER + move a1, sp + jal do_IRQ + j ret_from_irq + + +ll_cpu_ip0: + li a0, VR4181_IRQ_SW1 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip1: + li a0, VR4181_IRQ_SW2 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip3: + li a0, VR4181_IRQ_INT1 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip4: + li a0, VR4181_IRQ_INT2 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip5: + li a0, VR4181_IRQ_INT3 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_cpu_ip6: + li a0, VR4181_IRQ_INT4 + move a1, sp + jal do_IRQ + j ret_from_irq + +/* + * One of the sys irq has happend. + * + * In the interest of speed, we first determine in the following order + * which 16-irq block have pending interrupts: + * sysint1 (16 sources, including cascading intrs from GPIO) + * sysint2 + * gpio (16 intr sources) + * + * Then we do binary search to find the exact interrupt source. + */ +ll_cpu_ip2: + + lui t3,%hi(VR4181_SYSINT1REG) + lhu t0,%lo(VR4181_SYSINT1REG)(t3) + lhu t2,%lo(VR4181_MSYSINT1REG)(t3) + and t0, 0xfffb /* hack - remove RTC Long 1 intr */ + and t0, t2 + beqz t0, check_sysint2 + + /* check for GPIO interrupts */ + andi t1, t0, 0x0100 + bnez t1, check_gpio_int + + /* so we have an interrupt in sysint1 which is not gpio int */ + li a0, VR4181_SYS_IRQ_BASE - 1 + j check_16 + +check_sysint2: + + lhu t0,%lo(VR4181_SYSINT2REG)(t3) + lhu t2,%lo(VR4181_MSYSINT2REG)(t3) + and t0, 0xfffe /* hack - remove RTC Long 2 intr */ + and t0, t2 + li a0, VR4181_SYS_IRQ_BASE + 16 - 1 + j check_16 + +check_gpio_int: + lui t3,%hi(VR4181_GPINTMSK) + lhu t0,%lo(VR4181_GPINTMSK)(t3) + lhu t2,%lo(VR4181_GPINTSTAT)(t3) + xori t0, 0xffff /* why? reverse logic? */ + and t0, t2 + li a0, VR4181_GPIO_IRQ_BASE - 1 + j check_16 + +/* + * When we reach check_16, we have 16-bit status in t0 and base irq number + * in a0. + */ +check_16: + andi t1, t0, 0xff + bnez t1, check_8 + + srl t0, 8 + addi a0, 8 + j check_8 + +/* + * When we reach check_8, we have 8-bit status in t0 and base irq number + * in a0. + */ +check_8: + andi t1, t0, 0xf + bnez t1, check_4 + + srl t0, 4 + addi a0, 4 + j check_4 + +/* + * When we reach check_4, we have 4-bit status in t0 and base irq number + * in a0. + */ +check_4: + andi t0, t0, 0xf + beqz t0, do_spurious + +loop: + andi t2, t0, 0x1 + srl t0, 1 + addi a0, 1 + beqz t2, loop + +found_it: + move a1, sp + jal do_IRQ + + j ret_from_irq + + END(vr4181_handle_irq) diff -urN linux-2.4.18/arch/mips/vr4181/common/irq.c linux-2.4.19-pre5/arch/mips/vr4181/common/irq.c --- linux-2.4.18/arch/mips/vr4181/common/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/common/irq.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * linux/arch/mips/vr4181/common/irq.c + * Completely re-written to use the new irq.c + * + * Credits to Bradley D. LaRonde and Michael Klar for writing the original + * irq.c file which was derived from the common irq.c file. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* + * Strategy: + * + * We essentially have three irq controllers, CPU, system, and gpio. + * + * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and + * CONFIG_IRQ_CPU config option. + * + * We here provide sys_irq and gpio_irq controller code. + */ + +static int sys_irq_base; +static int gpio_irq_base; + +/* ---------------------- sys irq ------------------------ */ +static void +sys_irq_enable(unsigned int irq) +{ + irq -= sys_irq_base; + if (irq < 16) { + *VR4181_MSYSINT1REG |= (u16)(1 << irq); + } else { + irq -= 16; + *VR4181_MSYSINT2REG |= (u16)(1 << irq); + } +} + +static void +sys_irq_disable(unsigned int irq) +{ + irq -= sys_irq_base; + if (irq < 16) { + *VR4181_MSYSINT1REG &= ~((u16)(1 << irq)); + } else { + irq -= 16; + *VR4181_MSYSINT2REG &= ~((u16)(1 << irq)); + } + +} + +static unsigned int +sys_irq_startup(unsigned int irq) +{ + sys_irq_enable(irq); + return 0; +} + +#define sys_irq_shutdown sys_irq_disable +#define sys_irq_ack sys_irq_disable + +static void +sys_irq_end(unsigned int irq) +{ + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + sys_irq_enable(irq); +} + +static hw_irq_controller sys_irq_controller = { + "vr4181_sys_irq", + sys_irq_startup, + sys_irq_shutdown, + sys_irq_enable, + sys_irq_disable, + sys_irq_ack, + sys_irq_end, + NULL /* no affinity stuff for UP */ +}; + +/* ---------------------- gpio irq ------------------------ */ +/* gpio irq lines use reverse logic */ +static void +gpio_irq_enable(unsigned int irq) +{ + irq -= gpio_irq_base; + *VR4181_GPINTMSK &= ~((u16)(1 << irq)); +} + +static void +gpio_irq_disable(unsigned int irq) +{ + irq -= gpio_irq_base; + *VR4181_GPINTMSK |= (u16)(1 << irq); +} + +static unsigned int +gpio_irq_startup(unsigned int irq) +{ + gpio_irq_enable(irq); + + irq -= gpio_irq_base; + *VR4181_GPINTEN |= (u16)(1 << irq ); + + return 0; +} + +static void +gpio_irq_shutdown(unsigned int irq) +{ + gpio_irq_disable(irq); + + irq -= gpio_irq_base; + *VR4181_GPINTEN &= ~((u16)(1 << irq )); +} + +static void +gpio_irq_ack(unsigned int irq) +{ + u16 irqtype; + u16 irqshift; + + gpio_irq_disable(irq); + + /* we clear interrupt if it is edge triggered */ + irq -= gpio_irq_base; + if (irq < 8) { + irqtype = *VR4181_GPINTTYPL; + irqshift = 2 << (irq*2); + } else { + irqtype = *VR4181_GPINTTYPH; + irqshift = 2 << ((irq-8)*2); + } + if ( ! (irqtype & irqshift) ) { + *VR4181_GPINTSTAT = (u16) (1 << irq); + } +} + +static void +gpio_irq_end(unsigned int irq) +{ + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + gpio_irq_enable(irq); +} + +static hw_irq_controller gpio_irq_controller = { + "vr4181_gpio_irq", + gpio_irq_startup, + gpio_irq_shutdown, + gpio_irq_enable, + gpio_irq_disable, + gpio_irq_ack, + gpio_irq_end, + NULL /* no affinity stuff for UP */ +}; + +/* --------------------- IRQ init stuff ---------------------- */ + +extern asmlinkage void vr4181_handle_irq(void); +extern void breakpoint(void); +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +extern void mips_cpu_irq_init(u32 irq_base); + +static struct irqaction cascade = + { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL }; +static struct irqaction reserved = + { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL }; + +void __init init_IRQ(void) +{ + int i; + extern irq_desc_t irq_desc[]; + + set_except_vector(0, vr4181_handle_irq); + + /* init CPU irqs */ + mips_cpu_irq_init(VR4181_CPU_IRQ_BASE); + + /* init sys irqs */ + sys_irq_base = VR4181_SYS_IRQ_BASE; + for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &sys_irq_controller; + } + + /* init gpio irqs */ + gpio_irq_base = VR4181_GPIO_IRQ_BASE; + for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &gpio_irq_controller; + } + + /* Default all ICU IRQs to off ... */ + *VR4181_MSYSINT1REG = 0; + *VR4181_MSYSINT2REG = 0; + + /* We initialize the level 2 ICU registers to all bits disabled. */ + *VR4181_MPIUINTREG = 0; + *VR4181_MAIUINTREG = 0; + *VR4181_MKIUINTREG = 0; + + /* disable all GPIO intrs */ + *VR4181_GPINTMSK = 0xffff; + + /* vector handler. What these do is register the IRQ as non-sharable */ + setup_irq(VR4181_IRQ_INT0, &cascade); + setup_irq(VR4181_IRQ_GIU, &cascade); + + /* + * RTC interrupts are interesting. They have two destinations. + * One is at sys irq controller, and the other is at CPU IP3 and IP4. + * RTC timer is used as system timer. + * We enable them here, but timer routine will register later + * with CPU IP3/IP4. + */ + setup_irq(VR4181_IRQ_RTCL1, &reserved); + setup_irq(VR4181_IRQ_RTCL2, &reserved); + +#ifdef CONFIG_REMOTE_DEBUG + printk("Setting debug traps - please connect the remote debugger.\n"); + + set_debug_traps(); + + // you may move this line to whereever you want + breakpoint(); +#endif +} diff -urN linux-2.4.18/arch/mips/vr4181/common/serial.c linux-2.4.19-pre5/arch/mips/vr4181/common/serial.c --- linux-2.4.18/arch/mips/vr4181/common/serial.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/common/serial.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,51 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * arch/mips/vr4181/common/serial.c + * initialize serial port on vr4181. + * + * 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. + * + */ + +/* + * [jsun, 010925] + * You need to make sure rs_table has at least one element in + * drivers/char/serial.c file. There is no good way to do it right + * now. A workaround is to include CONFIG_SERIAL_MANY_PORTS in your + * configure file, which would gives you 64 ports and wastes 11K ram. + */ + +#include +#include +#include +#include + +#include + +void __init vr4181_init_serial(void) +{ + struct serial_struct s; + + /* turn on UART clock */ + *VR4181_CMUCLKMSK |= VR4181_CMUCLKMSK_MSKSIU; + + /* clear memory */ + memset(&s, 0, sizeof(s)); + + s.line = 0; /* we set the first one */ + s.baud_base = 1152000; + s.irq = VR4181_IRQ_SIU; + s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; /* STD_COM_FLAGS */ + s.iomem_base = (u8*)VR4181_SIURB; + s.iomem_reg_shift = 0; + s.io_type = SERIAL_IO_MEM; + if (early_serial_setup(&s) != 0) { + panic("vr4181_init_serial() failed!"); + } +} + diff -urN linux-2.4.18/arch/mips/vr4181/common/time.c linux-2.4.19-pre5/arch/mips/vr4181/common/time.c --- linux-2.4.18/arch/mips/vr4181/common/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/common/time.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,145 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * rtc and time ops for vr4181. Part of code is drived from + * linux-vr, originally written by Bradley D. LaRonde & Michael Klar. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include /* for HZ */ +#include +#include + +#include +#include + +#include + +#define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ) + +/* + * RTC ops + */ + +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +/* per VR41xx docs, bad data can be read if between 2 counts */ +static inline unsigned short +read_time_reg(volatile unsigned short *reg) +{ + unsigned short value; + do { + value = *reg; + barrier(); + } while (value != *reg); + return value; +} + +static unsigned long +vr4181_rtc_get_time(void) +{ + unsigned short regh, regm, regl; + + // why this crazy order, you ask? to guarantee that neither m + // nor l wrap before all 3 read + do { + regm = read_time_reg(VR4181_ETIMEMREG); + barrier(); + regh = read_time_reg(VR4181_ETIMEHREG); + barrier(); + regl = read_time_reg(VR4181_ETIMELREG); + } while (regm != read_time_reg(VR4181_ETIMEMREG)); + return ((regh << 17) | (regm << 1) | (regl >> 15)); +} + +static int +vr4181_rtc_set_time(unsigned long timeval) +{ + unsigned short intreg; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + intreg = *VR4181_RTCINTREG & 0x05; + barrier(); + *VR4181_ETIMELREG = timeval << 15; + *VR4181_ETIMEMREG = timeval >> 1; + *VR4181_ETIMEHREG = timeval >> 17; + barrier(); + // assume that any ints that just triggered are invalid, since the + // time value is written non-atomically in 3 separate regs + *VR4181_RTCINTREG = 0x05 ^ intreg; + spin_unlock_irqrestore(&rtc_lock, flags); + + return 0; +} + + +/* + * timer interrupt routine (wrapper) + * + * we need our own interrupt routine because we need to clear + * RTC1 interrupt. + */ +static void +vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* Clear the interrupt. */ + *VR4181_RTCINTREG = 0x2; + + /* call the generic one */ + timer_interrupt(irq, dev_id, regs); +} + + +/* + * vr4181_time_init: + * + * We pick the following choices: + * . we use elapsed timer as the RTC. We set some reasonable init data since + * it does not persist across reset + * . we use RTC1 as the system timer interrupt source. + * . we use CPU counter for fast_gettimeoffset and we calivrate the cpu + * frequency. In other words, we use calibrate_div64_gettimeoffset(). + * . we use our own timer interrupt routine which clears the interrupt + * and then calls the generic high-level timer interrupt routine. + * + */ + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); + +static void +vr4181_timer_setup(struct irqaction *irq) +{ + /* over-write the handler to be our own one */ + irq->handler = vr4181_timer_interrupt; + + /* sets up the frequency */ + *VR4181_RTCL1LREG = COUNTS_PER_JIFFY; + *VR4181_RTCL1HREG = 0; + + /* and ack any pending ints */ + *VR4181_RTCINTREG = 0x2; + + /* setup irqaction */ + setup_irq(VR4181_IRQ_INT1, irq); + +} + +void +vr4181_init_time(void) +{ + /* setup hookup functions */ + rtc_get_time = vr4181_rtc_get_time; + rtc_set_time = vr4181_rtc_set_time; + + board_timer_setup = vr4181_timer_setup; +} + diff -urN linux-2.4.18/arch/mips/vr4181/osprey/Makefile linux-2.4.19-pre5/arch/mips/vr4181/osprey/Makefile --- linux-2.4.18/arch/mips/vr4181/osprey/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/osprey/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,20 @@ +# +# Makefile for common code of NEC Osprey board +# +# 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). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET := osprey.o + +obj-y := setup.o prom.o reset.o + +obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips/vr4181/osprey/dbg_io.c linux-2.4.19-pre5/arch/mips/vr4181/osprey/dbg_io.c --- linux-2.4.18/arch/mips/vr4181/osprey/dbg_io.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/osprey/dbg_io.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,136 @@ +/* + * kgdb io functions for osprey. We use the serial port on debug board. + * + * Copyright (C) 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +/* ======================= CONFIG ======================== */ + +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xb7fffff0 +#define MAX_BAUD 115200 + +/* distance in bytes between two serial registers */ +#define REG_OFFSET 1 + +/* + * 0 - kgdb does serial init + * 1 - kgdb skip serial init + */ +static int remoteDebugInitialized = 1; + +/* + * the default baud rate *if* kgdb does serial init + */ +#define BAUD_DEFAULT UART16550_BAUD_38400 + +/* ======================= END OF CONFIG ======================== */ + +typedef unsigned char uint8; +typedef unsigned int uint32; + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE (1*REG_OFFSET) +#define OFS_INTR_ID (2*REG_OFFSET) +#define OFS_DATA_FORMAT (3*REG_OFFSET) +#define OFS_LINE_CONTROL (3*REG_OFFSET) +#define OFS_MODEM_CONTROL (4*REG_OFFSET) +#define OFS_RS232_OUTPUT (4*REG_OFFSET) +#define OFS_LINE_STATUS (5*REG_OFFSET) +#define OFS_MODEM_STATUS (6*REG_OFFSET) +#define OFS_RS232_INPUT (6*REG_OFFSET) +#define OFS_SCRATCH_PAD (7*REG_OFFSET) + +#define OFS_DIVISOR_LSB (0*REG_OFFSET) +#define OFS_DIVISOR_MSB (1*REG_OFFSET) + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(BAUD_DEFAULT, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} diff -urN linux-2.4.18/arch/mips/vr4181/osprey/prom.c linux-2.4.19-pre5/arch/mips/vr4181/osprey/prom.c --- linux-2.4.18/arch/mips/vr4181/osprey/prom.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/osprey/prom.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,56 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * arch/mips/vr4181/osprey/prom.c + * prom code for osprey. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +char arcs_cmdline[CL_SIZE]; + +const char *get_system_type(void) +{ + return "NEC_Vr41xx Osprey"; +} + +/* + * [jsun] right now we assume it is the nec debug monitor, which does + * not pass any arguments. + */ +void __init prom_init() +{ + strcpy(arcs_cmdline, "ip=bootp "); + strcat(arcs_cmdline, "ether=46,0x03fe0300,eth0 "); + // strcpy(arcs_cmdline, "ether=0,0x0300,eth0 " + // strcat(arcs_cmdline, "video=vr4181fb:xres:240,yres:320,bpp:8 "); + + mips_machgroup = MACH_GROUP_NEC_VR41XX; + mips_machtype = MACH_NEC_OSPREY; + + /* 16MB fixed */ + add_memory_region(0, 16 << 20, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} + +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +{ +} + diff -urN linux-2.4.18/arch/mips/vr4181/osprey/reset.c linux-2.4.19-pre5/arch/mips/vr4181/osprey/reset.c --- linux-2.4.18/arch/mips/vr4181/osprey/reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/osprey/reset.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright (C) 1997, 2001 Ralf Baechle + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + */ +#include +#include +#include +#include +#include +#include +#include + +void nec_osprey_restart(char *command) +{ + set_cp0_status(ST0_ERL); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void nec_osprey_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +void nec_osprey_power_off(void) +{ + nec_osprey_halt(); +} diff -urN linux-2.4.18/arch/mips/vr4181/osprey/setup.c linux-2.4.19-pre5/arch/mips/vr4181/osprey/setup.c --- linux-2.4.18/arch/mips/vr4181/osprey/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips/vr4181/osprey/setup.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,71 @@ +/* + * linux/arch/mips/vr4181/setup.c + * + * VR41xx setup routines + * + * Copyright (C) 1999 Bradley D. LaRonde + * Copyright (C) 1999, 2000 Michael Klar + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +extern void nec_osprey_restart(char* c); +extern void nec_osprey_halt(void); +extern void nec_osprey_power_off(void); + +extern void vr4181_init_serial(void); +extern void vr4181_init_time(void); + +void __init nec_osprey_setup(void) +{ + set_io_port_base(VR4181_PORT_BASE); + isa_slot_offset = VR4181_ISAMEM_BASE; + + vr4181_init_serial(); + vr4181_init_time(); + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + _machine_restart = nec_osprey_restart; + _machine_halt = nec_osprey_halt; + _machine_power_off = nec_osprey_power_off; + + /* setup resource limit */ + ioport_resource.end = 0xffffffff; + iomem_resource.end = 0xffffffff; + + /* [jsun] hack */ + /* + printk("[jsun] hack to change external ISA control register, %x -> %x\n", + (*VR4181_XISACTL), + (*VR4181_XISACTL) | 0x2); + *VR4181_XISACTL |= 0x2; + */ + + // *VR4181_GPHIBSTH = 0x2000; + // *VR4181_GPMD0REG = 0x00c0; + // *VR4181_GPINTEN = 1<<6; + + /* [jsun] I believe this will get the interrupt type right + * for the ether port. + */ + *VR4181_GPINTTYPL = 0x3000; +} diff -urN linux-2.4.18/arch/mips64/Makefile linux-2.4.19-pre5/arch/mips64/Makefile --- linux-2.4.18/arch/mips64/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/Makefile Sat Mar 30 22:55:27 2002 @@ -46,22 +46,25 @@ # CPU-dependent compiler/assembler options for optimization. # ifdef CONFIG_CPU_R4300 -CFLAGS := $(CFLAGS) -mcpu=r4300 -mips3 +CFLAGS += -mcpu=r4300 -mips3 endif ifdef CONFIG_CPU_R4X00 -CFLAGS := $(CFLAGS) -mcpu=r4600 -mips3 +CFLAGS += -mcpu=r4600 -mips3 endif ifdef CONFIG_CPU_R5000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +CFLAGS += -mcpu=r8000 -mips4 endif ifdef CONFIG_CPU_NEVADA -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips3 -mmad +CFLAGS += -mcpu=r8000 -mips3 -mmad endif ifdef CONFIG_CPU_R8000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +CFLAGS += -mcpu=r8000 -mips4 endif ifdef CONFIG_CPU_R10000 -CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +CFLAGS += -mcpu=r8000 -mips4 +endif +ifdef CONFIG_CPU_SB1 +CFLAGS += -mcpu=r8000 -mips4 endif ifdef CONFIG_MIPS_FPU_EMULATOR @@ -72,9 +75,21 @@ # # Board-dependent options and extra files # +ifdef CONFIG_MIPS_ATLAS +LIBS += arch/mips/mips-boards/atlas/atlas.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_MALTA +LIBS += arch/mips/mips-boards/malta/malta.o arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/malta arch/mips/mips-boards/generic +LOADADDR += 0x80100000 +endif + ifdef CONFIG_SGI_IP22 -LIBS += arch/mips64/sgi-ip22/ip22.a arch/mips64/arc/arclib.a -SUBDIRS += arch/mips64/sgi-ip22 arch/mips64/arc +LIBS += arch/mips/sgi-ip22/ip22-kern.o arch/mips64/arc/arclib.a +SUBDIRS += arch/mips/sgi-ip22 arch/mips64/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, # 0x88004000 for production kernels. Note that the value must be @@ -109,6 +124,31 @@ # 16kb aligned or the handling of the current variable will break. # LOADADDR += 0x80002000 +endif + +# +# Sibyte SB1250 SOC +# +ifdef CONFIG_SIBYTE_SB1250 +# This is a LIB so that it links at the end, and initcalls are later +# the sequence; but it is built as an object so that modules don't get +# removed (as happens, even if they have __initcall/module_init) +LIBS += arch/mips/sibyte/sb1250/sb1250.o +SUBDIRS += arch/mips/sibyte/sb1250 +endif + +# +# Sibyte SWARM board +# +ifdef CONFIG_SB1_CACHE_ERROR +LIBS += arch/mips/sibyte/sb1/sb1kern.a +SUBDIRS += arch/mips/sibyte/sb1 +endif + +ifdef CONFIG_SIBYTE_SWARM +LIBS += arch/mips/sibyte/swarm/sbswarm.a +SUBDIRS += arch/mips/sibyte/swarm +LOADADDR += 0x80100000 endif # diff -urN linux-2.4.18/arch/mips64/arc/arc_con.c linux-2.4.19-pre5/arch/mips64/arc/arc_con.c --- linux-2.4.18/arch/mips64/arc/arc_con.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/arc/arc_con.c Sat Mar 30 22:55:27 2002 @@ -44,28 +44,18 @@ return 0; } -static int __init prom_console_setup(struct console *co, char *options) -{ - return 0; -} - static kdev_t prom_console_device(struct console *c) { return MKDEV(TTY_MAJOR, 64 + c->index); } static struct console arc_cons = { - "ttyS", - prom_console_write, - NULL, - prom_console_device, - prom_console_wait_key, - NULL, - prom_console_setup, - CON_PRINTBUFFER, - -1, - 0, - NULL + name: "ttyS", + write: prom_console_write, + device: prom_console_device, + wait_key: prom_console_wait_key, + flags: CON_PRINTBUFFER, + index: -1, }; /* diff -urN linux-2.4.18/arch/mips64/arc/identify.c linux-2.4.19-pre5/arch/mips64/arc/identify.c --- linux-2.4.18/arch/mips64/arc/identify.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/arc/identify.c Sat Mar 30 22:55:27 2002 @@ -21,38 +21,70 @@ #include struct smatch { - char *name; + char *arcname; + char *liname; int group; int type; int flags; }; static struct smatch mach_table[] = { - { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS }, - { "SGI-IP27", MACH_GROUP_SGI, MACH_SGI_IP27, PROM_FLAG_ARCS }, - { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 }, - { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 }, - { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 } + { "SGI-IP22", + "SGI Indy", + MACH_GROUP_SGI, + MACH_SGI_INDY, + PROM_FLAG_ARCS + }, { "SGI-IP27", + "SGI Origin", + MACH_GROUP_SGI, + MACH_SGI_IP27, + PROM_FLAG_ARCS + }, { "SGI-IP32", + "SGI IP32", + MACH_GROUP_SGI, + MACH_SGI_IP32, + PROM_FLAG_ARCS + }, { "Microsoft-Jazz", + "Jazz MIPS_Magnum_4000", + MACH_GROUP_JAZZ, + MACH_MIPS_MAGNUM_4000, + 0 + }, { "PICA-61", + "Jazz Acer_PICA_61", + MACH_GROUP_JAZZ, + MACH_ACER_PICA_61, + 0 + }, { "RM200PCI", + "SNI RM200_PCI", + MACH_GROUP_SNI_RM, + MACH_SNI_RM200_PCI, + 0 + } }; int prom_flags; -static struct smatch * __init -string_to_mach(const char *s) +static struct smatch * __init string_to_mach(const char *s) { int i; for (i = 0; i < (sizeof (mach_table) / sizeof (mach_table[0])); i++) { - if(!strcmp(s, mach_table[i].name)) + if(!strcmp(s, mach_table[i].arcname)) return &mach_table[i]; } - panic("\nYeee, could not determine architecture type <%s>", s); + panic("Yeee, could not determine architecture type <%s>", s); return NULL; } -void __init -prom_identify_arch(void) +char *system_type; + +const char *get_system_type(void) +{ + return system_type; +} + +void __init prom_identify_arch(void) { pcomponent *p; struct smatch *mach; @@ -72,6 +104,7 @@ printk("ARCH: %s\n", iname); mach = string_to_mach(iname); + system_type = mach->liname; mips_machgroup = mach->group; mips_machtype = mach->type; diff -urN linux-2.4.18/arch/mips64/arc/misc.c linux-2.4.19-pre5/arch/mips64/arc/misc.c --- linux-2.4.18/arch/mips64/arc/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/arc/misc.c Sat Mar 30 22:55:27 2002 @@ -20,7 +20,6 @@ #include #include -extern unsigned long mips_cputype; extern void *sgiwd93_host; extern void reset_wd33c93(void *instance); diff -urN linux-2.4.18/arch/mips64/arc/tree.c linux-2.4.19-pre5/arch/mips64/arc/tree.c --- linux-2.4.18/arch/mips64/arc/tree.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/arc/tree.c Sat Mar 30 22:55:27 2002 @@ -10,8 +10,10 @@ * Copyright (C) 1999 Silicon Graphics, Inc. */ #include + #include #include +#include #undef DEBUG_PROM_TREE diff -urN linux-2.4.18/arch/mips64/config.in linux-2.4.19-pre5/arch/mips64/config.in --- linux-2.4.18/arch/mips64/config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/config.in Sat Mar 30 22:55:27 2002 @@ -2,6 +2,9 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # +define_bool CONFIG_MIPS y +define_bool CONFIG_MIPS64 y + mainmenu_name "Linux Kernel Configuration" mainmenu_option next_comment @@ -11,9 +14,29 @@ mainmenu_option next_comment comment 'Machine selection' -choice 'Machine type' \ - "SGI-IP22,Indy/Indigo2 CONFIG_SGI_IP22 \ - SGI-IP27,Origin200/2000 CONFIG_SGI_IP27 SGI-IP27,Origin200/2000" +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS + bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA +fi +bool ' Support for SGI-IP27 (Origin200/2000)' CONFIG_SGI_IP27 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Support for SGI-IP22 (Indy/Indigo2)' CONFIG_SGI_IP22 + bool ' Support for SGI-IP32 (O2)' CONFIG_SGI_IP32 +fi +bool 'Support for SiByte SB1250 SOC' CONFIG_SIBYTE_SB1250 +if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for SB1250 onchip PCI controller' CONFIG_PCI + bool ' Support for SB1250 profiling - SB1/SCD perf counters' CONFIG_SIBYTE_SB1250_PROF + bool ' Support for BCM1250 profiling using trace buffer' CONFIG_BCM1250_TBPROF + bool ' Remote debugging (kgdb over UART 1)' CONFIG_REMOTE_DEBUG + bool ' Support for SiByte SWARM board' CONFIG_SIBYTE_SWARM + if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + bool ' Running under simulation' CONFIG_SIMULATION + bool ' Configure for L3proc Demo' CONFIG_L3DEMO + int ' Maximum memory chunks' CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS 16 + bool ' Multi-Processing support' CONFIG_SMP + fi +fi if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' IP27 N-Mode' CONFIG_SGI_SN0_N_MODE @@ -33,22 +56,33 @@ # # Select some configuration options automatically based on user selections # -unset CONFIG_ARC32 -unset CONFIG_ARC64 -unset CONFIG_BINFMT_ELF32 -unset CONFIG_BOARD_SCACHE -unset CONFIG_BOOT_ELF32 -unset CONFIG_BOOT_ELF64 -unset CONFIG_COHERENT_IO -unset CONFIG_ISA -unset CONFIG_MAPPED_PCI_IO -unset CONFIG_PCI -if [ "$CONFIG_SGI_IP22" = "y" ]; then +if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then define_bool CONFIG_BOOT_ELF32 y + define_int CONFIG_L1_CACHE_SHIFT 5 + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PCI y + define_bool CONFIG_SWAP_IO_SPACE y +fi + +if [ "$CONFIG_MIPS_MALTA" = "y" ]; then + define_bool CONFIG_BOOT_ELF32 y + define_bool CONFIG_I8259 y + define_int CONFIG_L1_CACHE_SHIFT 5 + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_PCI y + define_bool CONFIG_SWAP_IO_SPACE y +fi + +if [ "$CONFIG_SGI_IP22" = "y" ]; then define_bool CONFIG_ARC32 y - define_bool CONFIG_BOARD_SCACHE y + define_bool CONFIG_ARC_CONSOLE y define_bool CONFIG_ARC_MEMORY y + define_bool CONFIG_BOARD_SCACHE y + define_bool CONFIG_IRQ_CPU y + define_bool CONFIG_PC_KEYB y + define_bool CONFIG_BOOT_ELF32 y + define_bool CONFIG_NONCOHERENT_IO y define_bool CONFIG_SGI y define_int CONFIG_L1_CACHE_SHIFT 5 fi @@ -56,13 +90,32 @@ if [ "$CONFIG_SGI_IP27" = "y" ]; then define_bool CONFIG_BOOT_ELF64 y define_bool CONFIG_ARC64 y - define_bool CONFIG_COHERENT_IO y define_bool CONFIG_MAPPED_PCI_IO y define_bool CONFIG_PCI y define_bool CONFIG_QL_ISP_A64 y define_int CONFIG_L1_CACHE_SHIFT 7 fi +if [ "$CONFIG_SGI_IP32" = "y" ]; then + define_bool CONFIG_BOOT_ELF32 y + define_bool CONFIG_ARC32 y + define_bool CONFIG_PC_KEYB y + define_bool CONFIG_PCI y + #define_bool CONFIG_BOARD_SCACHE y + define_bool CONFIG_MAPPED_PCI_IO n + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_ARC_MEMORY y + define_int CONFIG_L1_CACHE_SHIFT 5 +fi + +if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + define_bool CONFIG_BOOT_ELF32 y + define_bool CONFIG_SWAP_IO_SPACE y + define_bool CONFIG_CFE y + define_bool CONFIG_SIBYTE_SB1250 y + define_int CONFIG_L1_CACHE_SHIFT 5 +fi + if [ "$CONFIG_ISA" != "y" ]; then define_bool CONFIG_ISA n define_bool CONFIG_EISA n @@ -86,9 +139,19 @@ R5000 CONFIG_CPU_R5000 \ R52x0 CONFIG_CPU_NEVADA \ R8000 CONFIG_CPU_R8000 \ - R10000 CONFIG_CPU_R10000" R4x00 + R10000 CONFIG_CPU_R10000 \ + SB1 CONFIG_CPU_SB1" R4x00 endmenu +if [ "$CONFIG_CPU_SB1" = "y" ]; then + bool ' Workarounds for pass 1 sb1 bugs' CONFIG_SB1_PASS_1_WORKAROUNDS + bool ' Support for SB1 Cache Error handler' CONFIG_SB1_CACHE_ERROR + define_bool CONFIG_VTAG_ICACHE y +fi + +define_bool CONFIG_CPU_HAS_LLSC y +define_bool CONFIG_CPU_HAS_LLDSCD y + mainmenu_option next_comment comment 'General setup' @@ -109,8 +172,10 @@ if [ "$CONFIG_HOTPLUG" = "y" ] ; then source drivers/pcmcia/Config.in + source drivers/hotplug/Config.in else define_bool CONFIG_PCMCIA n + define_bool CONFIG_HOTPLUG_PCI n fi bool 'System V IPC' CONFIG_SYSVIPC diff -urN linux-2.4.18/arch/mips64/defconfig linux-2.4.19-pre5/arch/mips64/defconfig --- linux-2.4.18/arch/mips64/defconfig Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/defconfig Sat Mar 30 22:55:27 2002 @@ -1,6 +1,8 @@ # # Automatically generated make config: don't edit # +CONFIG_MIPS=y +CONFIG_MIPS64=y # # Code maturity level options @@ -10,8 +12,8 @@ # # Machine selection # -# CONFIG_SGI_IP22 is not set CONFIG_SGI_IP27=y +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_SGI_SN0_N_MODE is not set CONFIG_DISCONTIGMEM=y CONFIG_NUMA=y @@ -23,7 +25,6 @@ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF64=y CONFIG_ARC64=y -CONFIG_COHERENT_IO=y CONFIG_MAPPED_PCI_IO=y CONFIG_PCI=y CONFIG_QL_ISP_A64=y @@ -42,6 +43,9 @@ # CONFIG_CPU_NEVADA is not set # CONFIG_CPU_R8000 is not set CONFIG_CPU_R10000=y +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y # # General setup @@ -52,6 +56,7 @@ CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -99,6 +104,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -106,8 +112,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -204,8 +208,8 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -245,7 +249,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -380,7 +383,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -396,8 +398,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -439,6 +442,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -488,9 +493,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -518,12 +525,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -546,25 +551,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support diff -urN linux-2.4.18/arch/mips64/defconfig-atlas linux-2.4.19-pre5/arch/mips64/defconfig-atlas --- linux-2.4.18/arch/mips64/defconfig-atlas Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/defconfig-atlas Sat Mar 30 22:55:27 2002 @@ -0,0 +1,593 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS64=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +CONFIG_MIPS_ATLAS=y +# CONFIG_MIPS_MALTA is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_SB1250 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_BOOT_ELF32=y +CONFIG_L1_CACHE_SHIFT=5 +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI=y +CONFIG_SWAP_IO_SPACE=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set + +# +# CPU selection +# +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +CONFIG_CPU_R5000=y +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +CONFIG_MIPS32_COMPAT=y +CONFIG_BINFMT_ELF32=y +# CONFIG_BINFMT_MISC is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +CONFIG_PCI_NAMES=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_EFS_FS=y +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips64/defconfig-ip22 linux-2.4.19-pre5/arch/mips64/defconfig-ip22 --- linux-2.4.18/arch/mips64/defconfig-ip22 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/defconfig-ip22 Sat Mar 30 22:55:27 2002 @@ -1,6 +1,8 @@ # # Automatically generated make config: don't edit # +CONFIG_MIPS=y +CONFIG_MIPS64=y # # Code maturity level options @@ -10,14 +12,22 @@ # # Machine selection # -CONFIG_SGI_IP22=y +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set # CONFIG_SGI_IP27 is not set +CONFIG_SGI_IP22=y +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_SB1250 is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_BOOT_ELF32=y CONFIG_ARC32=y -CONFIG_BOARD_SCACHE=y +CONFIG_ARC_CONSOLE=y CONFIG_ARC_MEMORY=y +CONFIG_BOARD_SCACHE=y +CONFIG_IRQ_CPU=y +CONFIG_PC_KEYB=y +CONFIG_BOOT_ELF32=y +CONFIG_NONCOHERENT_IO=y CONFIG_SGI=y CONFIG_L1_CACHE_SHIFT=5 # CONFIG_ISA is not set @@ -35,6 +45,9 @@ # CONFIG_CPU_NEVADA is not set # CONFIG_CPU_R8000 is not set # CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y # # General setup @@ -44,10 +57,11 @@ CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -# CONFIG_ARC_CONSOLE is not set +CONFIG_ARC_CONSOLE=y CONFIG_BINFMT_ELF=y CONFIG_MIPS32_COMPAT=y CONFIG_BINFMT_ELF32=y @@ -93,6 +107,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -100,8 +115,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -122,6 +135,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -192,6 +206,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -211,7 +226,6 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -246,7 +260,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -350,14 +363,28 @@ # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +CONFIG_INDYDOG=y # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -385,7 +412,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -401,8 +427,9 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -443,6 +470,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -511,9 +540,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -541,12 +572,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -569,25 +598,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support diff -urN linux-2.4.18/arch/mips64/defconfig-ip27 linux-2.4.19-pre5/arch/mips64/defconfig-ip27 --- linux-2.4.18/arch/mips64/defconfig-ip27 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/defconfig-ip27 Sat Mar 30 22:55:27 2002 @@ -1,6 +1,8 @@ # # Automatically generated make config: don't edit # +CONFIG_MIPS=y +CONFIG_MIPS64=y # # Code maturity level options @@ -10,8 +12,8 @@ # # Machine selection # -# CONFIG_SGI_IP22 is not set CONFIG_SGI_IP27=y +# CONFIG_SIBYTE_SB1250 is not set # CONFIG_SGI_SN0_N_MODE is not set CONFIG_DISCONTIGMEM=y CONFIG_NUMA=y @@ -23,7 +25,6 @@ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF64=y CONFIG_ARC64=y -CONFIG_COHERENT_IO=y CONFIG_MAPPED_PCI_IO=y CONFIG_PCI=y CONFIG_QL_ISP_A64=y @@ -42,6 +43,9 @@ # CONFIG_CPU_NEVADA is not set # CONFIG_CPU_R8000 is not set CONFIG_CPU_R10000=y +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y # # General setup @@ -52,6 +56,7 @@ CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -99,6 +104,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -106,8 +112,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -204,8 +208,8 @@ # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR_D700 is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -245,7 +249,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -380,7 +383,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -396,8 +398,9 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -439,6 +442,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -488,9 +493,11 @@ # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -518,12 +525,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -546,25 +551,30 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set # # Input core support diff -urN linux-2.4.18/arch/mips64/defconfig-ip32 linux-2.4.19-pre5/arch/mips64/defconfig-ip32 --- linux-2.4.18/arch/mips64/defconfig-ip32 Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/defconfig-ip32 Sat Mar 30 22:55:27 2002 @@ -1,6 +1,8 @@ # # Automatically generated make config: don't edit # +CONFIG_MIPS=y +CONFIG_MIPS64=y # # Code maturity level options @@ -10,15 +12,20 @@ # # Machine selection # -# CONFIG_SGI_IP22 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set # CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP22 is not set CONFIG_SGI_IP32=y +# CONFIG_SIBYTE_SB1250 is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF32=y CONFIG_ARC32=y CONFIG_PC_KEYB=y CONFIG_PCI=y +# CONFIG_MAPPED_PCI_IO is not set +CONFIG_NONCOHERENT_IO=y CONFIG_ARC_MEMORY=y CONFIG_L1_CACHE_SHIFT=5 # CONFIG_ISA is not set @@ -35,6 +42,9 @@ # CONFIG_CPU_NEVADA is not set # CONFIG_CPU_R8000 is not set # CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y # # General setup @@ -45,10 +55,11 @@ CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y -# CONFIG_PROM_CONSOLE is not set +CONFIG_ARC_CONSOLE=y CONFIG_BINFMT_ELF=y CONFIG_MIPS32_COMPAT=y CONFIG_BINFMT_ELF32=y @@ -93,6 +104,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -100,7 +112,7 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -113,11 +125,13 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -145,6 +159,7 @@ # # CONFIG_PHONE is not set # CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set # # ATA/IDE/MFM/RLL support @@ -187,10 +202,12 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -209,6 +226,7 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -227,16 +245,6 @@ # CONFIG_SCSI_DEBUG is not set # -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -249,60 +257,40 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_NET_SB1000 is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +CONFIG_SGI_O2MACE_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -CONFIG_TULIP=y -# CONFIG_DE4X5 is not set -# CONFIG_DGRS is not set -# CONFIG_DM9102 is not set -CONFIG_EEPRO100=y -# CONFIG_EEPRO100_PM is not set -# CONFIG_LNE390 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_NE3210 is not set -# CONFIG_ES3210 is not set -# CONFIG_8139TOO is not set -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_WINBOND_840 is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_LAN_SAA9730 is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -372,7 +360,11 @@ # # Joysticks # -# CONFIG_JOYSTICK is not set +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# # # Input core support is needed for joysticks @@ -410,22 +402,28 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set CONFIG_TMPFS=y # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -441,7 +439,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -451,6 +448,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y @@ -469,6 +467,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -480,6 +480,7 @@ # CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set @@ -498,9 +499,112 @@ # CONFIG_USB is not set # +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# # Input core support # # CONFIG_INPUT 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 # # Kernel hacking diff -urN linux-2.4.18/arch/mips64/defconfig-malta linux-2.4.19-pre5/arch/mips64/defconfig-malta --- linux-2.4.18/arch/mips64/defconfig-malta Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/defconfig-malta Sat Mar 30 22:55:27 2002 @@ -0,0 +1,594 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS64=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Machine selection +# +# CONFIG_MIPS_ATLAS is not set +CONFIG_MIPS_MALTA=y +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_SB1250 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_BOOT_ELF32=y +CONFIG_I8259=y +CONFIG_L1_CACHE_SHIFT=5 +CONFIG_NONCOHERENT_IO=y +CONFIG_PCI=y +CONFIG_SWAP_IO_SPACE=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set + +# +# CPU selection +# +# CONFIG_CPU_R4300 is not set +CONFIG_CPU_R4X00=y +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_MIPS_FPU_EMULATOR is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +CONFIG_MIPS32_COMPAT=y +CONFIG_BINFMT_ELF32=y +# CONFIG_BINFMT_MISC is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +CONFIG_PCI_NAMES=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# 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_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_EFS_FS=y +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -urN linux-2.4.18/arch/mips64/defconfig-sb1250-swarm linux-2.4.19-pre5/arch/mips64/defconfig-sb1250-swarm --- linux-2.4.18/arch/mips64/defconfig-sb1250-swarm Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/defconfig-sb1250-swarm Sat Mar 30 22:55:27 2002 @@ -0,0 +1,552 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS64=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Machine selection +# +# CONFIG_SGI_IP27 is not set +CONFIG_SIBYTE_SB1250=y +# CONFIG_PCI is not set +# CONFIG_SIBYTE_SB1250_PROF is not set +# CONFIG_BCM1250_TBPROF is not set +# CONFIG_REMOTE_DEBUG is not set +CONFIG_SIBYTE_SWARM=y +# CONFIG_SIMULATION is not set +# CONFIG_L3DEMO is not set +CONFIG_SIBYTE_SWARM_MAX_MEM_REGIONS=16 +CONFIG_SMP=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_BOOT_ELF32=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_CFE=y +CONFIG_SIBYTE_SB1250=y +CONFIG_L1_CACHE_SHIFT=5 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_PCI is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set + +# +# CPU selection +# +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +CONFIG_CPU_SB1=y +CONFIG_SB1_PASS_1_WORKAROUNDS=y +CONFIG_SB1_CACHE_ERROR=y +CONFIG_VTAG_ICACHE=y +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_LLDSCD=y + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_NET=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +CONFIG_MIPS32_COMPAT=y +CONFIG_BINFMT_ELF32=y +# CONFIG_BINFMT_MISC is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_NET_SB1250_MAC=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# 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=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_AU1000_UART is not set +# CONFIG_TXX927_SERIAL is not set +CONFIG_SIBYTE_SB1250_DUART=y +CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE=1024 +# CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Input core support +# +# CONFIG_INPUT 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 + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set diff -urN linux-2.4.18/arch/mips64/kernel/Makefile linux-2.4.19-pre5/arch/mips64/kernel/Makefile --- linux-2.4.18/arch/mips64/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/Makefile Sat Mar 30 22:55:27 2002 @@ -13,19 +13,25 @@ O_TARGET := kernel.o -export-objs = mips64_ksyms.o +export-objs = irq.o mips64_ksyms.o pci-dma.o smp.o -obj-y := branch.o entry.o proc.o process.o ptrace.o r4k_cache.o r4k_fpu.o \ - r4k_genex.o r4k_switch.o r4k_tlb.o r4k_tlb_debug.o r4k_tlb_glue.o \ - scall_64.o semaphore.o setup.o signal.o softfp.o syscall.o \ - traps.o unaligned.o +obj-y := branch.o entry.o irq.o proc.o process.o ptrace.o r4k_cache.o \ + r4k_fpu.o r4k_genex.o r4k_switch.o reset.o scall_64.o \ + semaphore.o setup.o signal.o softfp.o syscall.o time.o traps.o \ + unaligned.o + +obj-$(CONFIG_I8259) += i8259.o +obj-$(CONFIG_IRQ_CPU) += irq_cpu.o obj-$(CONFIG_MODULES) += mips64_ksyms.o obj-$(CONFIG_MIPS32_COMPAT) += linux32.o scall_o32.o signal32.o ioctl32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o obj-$(CONFIG_SMP) += smp.o +ifndef CONFIG_MAPPED_PCI_IO +obj-y += pci-dma.o +endif + CFLAGS_r4k_genex.o := -P -CFLAGS_r4k_tlb_glue.o := -P include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/kernel/branch.c linux-2.4.19-pre5/arch/mips64/kernel/branch.c --- linux-2.4.18/arch/mips64/kernel/branch.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/branch.c Sat Mar 30 22:55:27 2002 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -163,7 +164,10 @@ * And now the FPA/cp1 branch instructions. */ case cop1_op: - asm ("cfc1\t%0,$31":"=r" (fcr31)); + if (!(mips_cpu.options & MIPS_CPU_FPU)) + fcr31 = current->thread.fpu.soft.sr; + else + asm("cfc1\t%0,$31":"=r" (fcr31)); bit = (insn.i_format.rt >> 2); bit += (bit != 0); bit += 23; diff -urN linux-2.4.18/arch/mips64/kernel/entry.S linux-2.4.19-pre5/arch/mips64/kernel/entry.S --- linux-2.4.18/arch/mips64/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/entry.S Sat Mar 30 22:55:27 2002 @@ -81,9 +81,10 @@ * Someone tried to fool us by sending an interrupt but we * couldn't find a cause for it. */ - lui t1,%hi(spurious_count) - lw t0,%lo(spurious_count)(t1) - addiu t0,1 - sw t0,%lo(spurious_count)(t1) + lui t1, %hi(irq_err_count) +1: ll t0, %lo(irq_err_count)(t1) + addiu t0, 1 + sc t0, %lo(irq_err_count)(t1) + beqz t0, 1b j ret_from_irq END(spurious_interrupt) diff -urN linux-2.4.18/arch/mips64/kernel/head.S linux-2.4.19-pre5/arch/mips64/kernel/head.S --- linux-2.4.18/arch/mips64/kernel/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/head.S Sat Mar 30 22:55:27 2002 @@ -35,13 +35,13 @@ #ifdef CONFIG_SGI_IP27 /* - * outputs the local nasid into t1. + * outputs the local nasid into res. IP27 stuff. */ - .macro GET_NASID_ASM - dli t1, LOCAL_HUB_ADDR(NI_STATUS_REV_ID) - ld t1, (t1) - and t1, NSRI_NODEID_MASK - dsrl t1, NSRI_NODEID_SHFT + .macro GET_NASID_ASM res + dli \res, LOCAL_HUB_ADDR(NI_STATUS_REV_ID) + ld \res, (\res) + and \res, NSRI_NODEID_MASK + dsrl \res, NSRI_NODEID_SHFT .endm #endif /* CONFIG_SGI_IP27 */ @@ -97,7 +97,7 @@ xori sp, 0xf #ifdef CONFIG_SGI_IP27 - GET_NASID_ASM + GET_NASID_ASM t1 move t2, t1 # text and data are here MAPPED_KERNEL_SETUP_TLB #endif /* IP27 */ @@ -106,39 +106,25 @@ CLI # disable interrupts - mfc0 t0, CP0_STATUS - /* - * On IP27, I am seeing the TS bit set when the - * kernel is loaded. Maybe because the kernel is - * in ckseg0 and not xkphys? Clear it anyway ... - */ - li t1, ~(ST0_TS|ST0_CU1|ST0_CU2|ST0_CU3) - and t0, t1 - or t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR) # Bogosity: cu0 indicates kernel - mtc0 t0, CP0_STATUS # thread in copy_thread. - la $28, init_task_union # init current pointer - daddiu t0, $28, KERNEL_STACK_SIZE-32 - sd t0, kernelsp - dsubu sp, t0, 4*SZREG # init stack pointer - move t0, $28 -#ifdef CONFIG_SMP - mtc0 t0, CP0_WATCHLO - dsrl32 t0, t0, 0 - mtc0 t0, CP0_WATCHHI -#endif - /* Note that all firmware passed argument registers still - have their values. */ - jal prom_init # initialize firmware + daddiu sp, $28, KERNEL_STACK_SIZE-32 + set_saved_sp sp, t0 + + dsubu sp, 4*SZREG # init stack pointer - jal start_kernel -1: b 1b # just in case ... + j init_arch END(kernel_entry) +#ifdef CONFIG_SMP +/* + * SMP slave cpus entry point. Board specific code for bootstrap calls this + * function after setting up the stack and gp registers. + */ +NESTED(smp_bootstrap, 16, sp) #ifdef CONFIG_SGI_IP27 -NESTED(bootstrap, 16, sp) - GET_NASID_ASM - li t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + KLDIR_OFF_POINTER + K0BASE + GET_NASID_ASM t1 + li t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + \ + KLDIR_OFF_POINTER + K0BASE dsll t1, NASID_SHFT or t0, t0, t1 ld t0, 0(t0) # t0 points to kern_vars struct @@ -146,19 +132,29 @@ lh t2, KV_RW_NASID_OFFSET(t0) MAPPED_KERNEL_SETUP_TLB ARC64_TWIDDLE_PC - CLI - mfc0 t0, CP0_STATUS - li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3) - and t0, t1 - or t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR) # Bogosity: cu0 indicates kernel - mtc0 t0, CP0_STATUS # thread in copy_thread. - jal cboot - END(bootstrap) #endif /* CONFIG_SGI_IP27 */ + CLI + + /* + * For the moment set ST0_KU so the CPU will not spit fire when + * executing 64-bit instructions. The full initialization of the + * CPU's status register is done later in per_cpu_trap_init(). + */ + mfc0 t0, CP0_STATUS + or t0, ST0_KX + mtc0 t0, CP0_STATUS + + set_saved_sp sp, t0 + + jal start_secondary # XXX: IP27: cboot + + END(smp_bootstrap) +#endif /* CONFIG_SMP */ + __FINIT - .comm kernelsp, 8, 8 # current stackpointer + declare_saved_sp #undef PAGE_SIZE #define PAGE_SIZE 0x1000 diff -urN linux-2.4.18/arch/mips64/kernel/i8259.c linux-2.4.19-pre5/arch/mips64/kernel/i8259.c --- linux-2.4.18/arch/mips64/kernel/i8259.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/i8259.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,307 @@ +/* + * 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. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include + +#include + +void enable_8259A_irq(unsigned int irq); +void disable_8259A_irq(unsigned int irq); + +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ + +static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; + +static void end_8259A_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_8259A_irq(irq); +} + +#define shutdown_8259A_irq disable_8259A_irq + +void mask_and_ack_8259A(unsigned int); + +static unsigned int startup_8259A_irq(unsigned int irq) +{ + enable_8259A_irq(irq); + + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type i8259A_irq_type = { + "XT-PIC", + startup_8259A_irq, + shutdown_8259A_irq, + enable_8259A_irq, + disable_8259A_irq, + mask_and_ack_8259A, + end_8259A_irq, + NULL +}; + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + */ +static unsigned int cached_irq_mask = 0xffff; + +#define cached_21 (cached_irq_mask) +#define cached_A1 (cached_irq_mask >> 8) + +void disable_8259A_irq(unsigned int irq) +{ + unsigned int mask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask |= mask; + if (irq & 8) + outb(cached_A1,0xA1); + else + outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +void enable_8259A_irq(unsigned int irq) +{ + unsigned int mask = ~(1 << irq); + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask &= mask; + if (irq & 8) + outb(cached_A1,0xA1); + else + outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +int i8259A_irq_pending(unsigned int irq) +{ + unsigned int mask = 1 << irq; + unsigned long flags; + int ret; + + spin_lock_irqsave(&i8259A_lock, flags); + if (irq < 8) + ret = inb(0x20) & mask; + else + ret = inb(0xA0) & (mask >> 8); + spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; +} + +void make_8259A_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &i8259A_irq_type; + enable_irq(irq); +} + +/* + * This function assumes to be called rarely. Switching between + * 8259A registers is slow. + * This has to be protected by the irq controller spinlock + * before being called. + */ +static inline int i8259A_irq_real(unsigned int irq) +{ + int value; + int irqmask = 1 << irq; + + if (irq < 8) { + outb(0x0B,0x20); /* ISR register */ + value = inb(0x20) & irqmask; + outb(0x0A,0x20); /* back to the IRR register */ + return value; + } + outb(0x0B,0xA0); /* ISR register */ + value = inb(0xA0) & (irqmask >> 8); + outb(0x0A,0xA0); /* back to the IRR register */ + return value; +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +void mask_and_ack_8259A(unsigned int irq) +{ + unsigned int irqmask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + /* + * Lightweight spurious IRQ detection. We do not want to overdo + * spurious IRQ handling - it's usually a sign of hardware problems, so + * we only do the checks we can do without slowing down good hardware + * nnecesserily. + * + * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting + * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A. + * Thus we can check spurious 8259A IRQs without doing the quite slow + * i8259A_irq_real() call for every IRQ. This does not cover 100% of + * spurious interrupts, but should be enough to warn the user that + * there is something bad going on ... + */ + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + cached_irq_mask |= irqmask; + +handle_real_irq: + if (irq & 8) { + inb(0xA1); /* DUMMY - (do we need this?) */ + outb(cached_A1,0xA1); + outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ + outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + } else { + inb(0x21); /* DUMMY - (do we need this?) */ + outb(cached_21,0x21); + outb(0x60+irq,0x20); /* 'Specific EOI' to master */ + } + spin_unlock_irqrestore(&i8259A_lock, flags); + return; + +spurious_8259A_irq: + /* + * this is the slow path - should happen rarely. + */ + if (i8259A_irq_real(irq)) + /* + * oops, the IRQ _is_ in service according to the + * 8259A - not spurious, go handle it. + */ + goto handle_real_irq; + + { + static int spurious_irq_mask = 0; + /* + * At this point we can be sure the IRQ is spurious, + * lets ACK and report it. [once per IRQ] + */ + if (!(spurious_irq_mask & irqmask)) { + printk("spurious 8259A interrupt: IRQ%d.\n", irq); + spurious_irq_mask |= irqmask; + } + atomic_inc(&irq_err_count); + /* + * Theoretically we do not have to handle this IRQ, + * but in Linux this does not cause problems and is + * simpler for us. + */ + goto handle_real_irq; + } +} + +void __init init_8259A(int auto_eoi) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-2 */ + + /* + * outb_p - this has to work on a wide range of PC hardware. + */ + outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ + outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */ + outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) + outb_p(0x03, 0x21); /* master does Auto EOI */ + else + outb_p(0x01, 0x21); /* master expects normal EOI */ + + outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ + outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */ + outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ + outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode + is to be investigated) */ + + if (auto_eoi) + /* + * in AEOI mode we just have to mask the interrupt + * when acking. + */ + i8259A_irq_type.ack = disable_8259A_irq; + else + i8259A_irq_type.ack = mask_and_ack_8259A; + + udelay(100); /* wait for 8259A to initialize */ + + outb(cached_21, 0x21); /* restore master IRQ mask */ + outb(cached_A1, 0xA1); /* restore slave IRQ mask */ + + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +asmlinkage void i8259_do_irq(int irq, struct pt_regs regs) +{ + panic("i8259_do_irq: I want to be implemented"); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { + no_action, 0, 0, "cascade", NULL, NULL +}; + +static struct resource pic1_io_resource = { + "pic1", 0x20, 0x3f, IORESOURCE_BUSY +}; + +static struct resource pic2_io_resource = { + "pic2", 0xa0, 0xbf, IORESOURCE_BUSY +}; + +/* + * On systems with i8259-style interrupt controllers we assume for + * driver compatibility reasons interrupts 0 - 15 to be the i8295 + * interrupts even if the hardware uses a different interrupt numbering. + */ +void __init init_i8259_irqs (void) +{ + int i; + + request_resource(&ioport_resource, &pic1_io_resource); + request_resource(&ioport_resource, &pic2_io_resource); + + init_8259A(0); + + for (i = 0; i < 16; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &i8259A_irq_type; + } + + setup_irq(2, &irq2); +} diff -urN linux-2.4.18/arch/mips64/kernel/ioctl32.c linux-2.4.19-pre5/arch/mips64/kernel/ioctl32.c --- linux-2.4.18/arch/mips64/kernel/ioctl32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/ioctl32.c Sat Mar 30 22:55:27 2002 @@ -27,6 +27,10 @@ #include #include #include +#include +#undef __KERNEL__ /* This file was born to be ugly ... */ +#include +#define __KERNEL__ #include #include @@ -619,6 +623,7 @@ IOCTL32_DEFAULT(FIONBIO), IOCTL32_DEFAULT(FIONREAD), + /* Big K */ IOCTL32_DEFAULT(PIO_FONT), IOCTL32_DEFAULT(GIO_FONT), IOCTL32_DEFAULT(KDSIGACCEPT), @@ -650,6 +655,17 @@ IOCTL32_DEFAULT(PIO_FONTRESET), IOCTL32_DEFAULT(PIO_UNIMAPCLR), + /* Big S */ + IOCTL32_DEFAULT(SCSI_IOCTL_GET_IDLUN), + IOCTL32_DEFAULT(SCSI_IOCTL_DOORLOCK), + IOCTL32_DEFAULT(SCSI_IOCTL_DOORUNLOCK), + IOCTL32_DEFAULT(SCSI_IOCTL_TEST_UNIT_READY), + IOCTL32_DEFAULT(SCSI_IOCTL_TAGGED_ENABLE), + IOCTL32_DEFAULT(SCSI_IOCTL_TAGGED_DISABLE), + IOCTL32_DEFAULT(SCSI_IOCTL_GET_BUS_NUMBER), + IOCTL32_DEFAULT(SCSI_IOCTL_SEND_COMMAND), + + /* Big V */ IOCTL32_DEFAULT(VT_SETMODE), IOCTL32_DEFAULT(VT_GETMODE), IOCTL32_DEFAULT(VT_GETSTATE), diff -urN linux-2.4.18/arch/mips64/kernel/irq.c linux-2.4.19-pre5/arch/mips64/kernel/irq.c --- linux-2.4.18/arch/mips64/kernel/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/irq.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,1056 @@ +/* + * 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. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +/* + * Special irq handlers. + */ + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ + printk("unexpected interrupt %d\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +atomic_t irq_err_count; + +/* + * Generic, controller-independent functions: + */ + +int get_irq_list(char *buf) +{ + struct irqaction * action; + char *p = buf; + int i; + + p += sprintf(p, " "); + for (i=0; i < 1 /*smp_num_cpus*/; i++) + p += sprintf(p, "CPU%d ", i); + *p++ = '\n'; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; + if (!action) + continue; + p += sprintf(p, "%3d: ",i); + p += sprintf(p, "%10u ", kstat_irqs(i)); + p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + p += sprintf(p, ", %s", action->name); + *p++ = '\n'; + } + p += sprintf(p, "ERR: %10lu\n", irq_err_count); + return p - buf; +} + +#ifdef CONFIG_SMP +int global_irq_holder = NO_PROC_ID; +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; + +/* + * Most of this code is take from the mips64 tree (ip27-irq.c). It's virtually + * identical to the i386 implentation in arh/i386/irq.c, with translations for + * the interrupt enable bit + */ + +#define MAXCOUNT 100000000 +#define SYNC_OTHER_CORES(x) udelay(x+1) + +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 (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + break; + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + + for (;;) { + if (!--count) { + printk("Count spun out. Huh?\n"); + count = ~0; + } + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + if (irqs_running()) + continue; + if (spin_is_locked(&global_irq_lock)) + continue; + 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 + * 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) +{ + if (irqs_running()) { + /* Stupid approach */ + cli(); + sti(); + } +} + +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 int flags; + + __save_flags(flags); + if (flags & ST0_IE) { + 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; + int cpu = smp_processor_id(); + + __save_flags(flags); + local_enabled = (flags & ST0_IE); + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count(cpu)) { + if (local_enabled) + retval = 1; + if (global_irq_holder == cpu) + 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\n", flags); + } +} +#endif /* CONFIG_SMP */ + +/* + * 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 handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +{ + int status; + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + + status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + + irq_exit(cpu, irq); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +void inline disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count(smp_processor_id())) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int cpu = smp_processor_id(); + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; + + kstat.irqs[cpu][irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + if (softirq_pending(cpu)) + do_softirq(); + return 1; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * 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) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + +#ifdef CONFIG_SMP + /* Wait to make sure it's not being used on another CPU */ + while (desc->status & IRQ_INPROGRESS) + barrier(); +#endif + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (i < 16 && !(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; +} + +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); + return 0; +} + +void __init init_generic_irq(void) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &no_irq_type; + } +} + +EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(probe_irq_mask); + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; + +#define HEX_DIGITS 8 + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (long) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +#endif + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || + irq_dir[irq]) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + +#if CONFIG_SMP + { + struct proc_dir_entry *entry; + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } + + smp_affinity_entry[irq] = entry; + } +#endif +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) + register_irq_proc(i); +} diff -urN linux-2.4.18/arch/mips64/kernel/irq_cpu.c linux-2.4.19-pre5/arch/mips64/kernel/irq_cpu.c --- linux-2.4.18/arch/mips64/kernel/irq_cpu.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/irq_cpu.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,91 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This file define the irq handler for MIPS CPU interrupts. + * + * 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. + */ + +/* + * Almost all MIPS CPUs define 8 interrupt sources. They are typically + * level triggered (i.e., cannot be cleared from CPU; must be cleared from + * device). The first two are software interrupts. The last one is + * usually cpu timer interrupt if coutner register is present. + * + * This file exports one global function: + * mips_cpu_irq_init(u32 irq_base); + */ +#include +#include +#include + +#include + +static int mips_cpu_irq_base = -1; + +static void mips_cpu_irq_enable(unsigned int irq) +{ + clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8)); + set_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); +} + +static void mips_cpu_irq_disable(unsigned int irq) +{ + clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8)); +} + +static unsigned int mips_cpu_irq_startup(unsigned int irq) +{ + mips_cpu_irq_enable(irq); + + return 0; +} + +#define mips_cpu_irq_shutdown mips_cpu_irq_disable + +static void mips_cpu_irq_ack(unsigned int irq) +{ + /* although we attemp to clear the IP bit in cause reigster, I think + * usually it is cleared by device (irq source) + */ + clear_cp0_cause(1 << (irq - mips_cpu_irq_base + 8)); + + /* disable this interrupt - so that we safe proceed to the handler */ + mips_cpu_irq_disable(irq); +} + +static void mips_cpu_irq_end(unsigned int irq) +{ + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mips_cpu_irq_enable(irq); +} + +static hw_irq_controller mips_cpu_irq_controller = { + "CPU_irq", + mips_cpu_irq_startup, + mips_cpu_irq_shutdown, + mips_cpu_irq_enable, + mips_cpu_irq_disable, + mips_cpu_irq_ack, + mips_cpu_irq_end, + NULL /* no affinity stuff for UP */ +}; + + +void mips_cpu_irq_init(u32 irq_base) +{ + u32 i; + + for (i = irq_base; i < irq_base + 8; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &mips_cpu_irq_controller; + } + + mips_cpu_irq_base = irq_base; +} diff -urN linux-2.4.18/arch/mips64/kernel/linux32.c linux-2.4.19-pre5/arch/mips64/kernel/linux32.c --- linux-2.4.18/arch/mips64/kernel/linux32.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/mips64/kernel/linux32.c Sat Mar 30 22:55:27 2002 @@ -36,6 +36,13 @@ #define A(__x) ((unsigned long)(__x)) +#ifdef __MIPSEB__ +#define merge_64(r1,r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) +#endif +#ifdef __MIPSEL__ +#define merge_64(r1,r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL)) +#endif + /* * Revalidate the inode. This is required for proper NFS attribute caching. */ @@ -887,9 +894,9 @@ unsigned long offset_low, loff_t * result, unsigned int origin); -extern asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high, - unsigned int offset_low, loff_t * result, - unsigned int origin) +asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high, + unsigned int offset_low, loff_t * result, + unsigned int origin) { return sys_llseek(fd, offset_high, offset_low, result, origin); } @@ -1043,11 +1050,12 @@ non-seekable files. */ asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf, - size_t count, u32 unused, loff_t pos) + size_t count, u32 unused, u64 a4, u64 a5) { ssize_t ret; struct file * file; ssize_t (*read)(struct file *, char *, size_t, loff_t *); + loff_t pos; ret = -EBADF; file = fget(fd); @@ -1055,6 +1063,7 @@ goto bad_file; if (!(file->f_mode & FMODE_READ)) goto out; + pos = merge_64(a4, a5); ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, file, pos, count); if (ret) @@ -1074,11 +1083,12 @@ } asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf, - size_t count, u32 unused, loff_t pos) + size_t count, u32 unused, u64 a4, u64 a5) { ssize_t ret; struct file * file; ssize_t (*write)(struct file *, const char *, size_t, loff_t *); + loff_t pos; ret = -EBADF; file = fget(fd); @@ -1086,6 +1096,7 @@ goto bad_file; if (!(file->f_mode & FMODE_WRITE)) goto out; + pos = merge_64(a4, a5); ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode, file, pos, count); if (ret) @@ -1140,7 +1151,7 @@ } return 0; #else - <> +#error little endian support must define this #endif } @@ -2328,4 +2339,12 @@ sockfd_put(sock); out: return err; +} + +asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count); + +asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3, + size_t count) +{ + return sys_readahead(fd, merge_64(a2, a3), count); } diff -urN linux-2.4.18/arch/mips64/kernel/mips64_ksyms.c linux-2.4.19-pre5/arch/mips64/kernel/mips64_ksyms.c --- linux-2.4.18/arch/mips64/kernel/mips64_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/mips64/kernel/mips64_ksyms.c Sat Mar 30 22:55:27 2002 @@ -13,9 +13,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -58,8 +58,6 @@ EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL(_clear_page); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* @@ -83,7 +81,8 @@ */ EXPORT_SYMBOL(_flush_page_to_ram); EXPORT_SYMBOL(_flush_cache_l1); -#ifndef CONFIG_COHERENT_IO + +#ifdef CONFIG_NONCOHERENT_IO EXPORT_SYMBOL(_dma_cache_wback_inv); EXPORT_SYMBOL(_dma_cache_inv); #endif @@ -117,4 +116,3 @@ #endif EXPORT_SYMBOL(get_wchan); -EXPORT_SYMBOL(_flush_tlb_page); diff -urN linux-2.4.18/arch/mips64/kernel/pci-dma.c linux-2.4.19-pre5/arch/mips64/kernel/pci-dma.c --- linux-2.4.18/arch/mips64/kernel/pci-dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/pci-dma.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,44 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Ani Joshi + * Copyright (C) 2000 Ralf Baechle + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ +#include +#include +#include +#include + +#include +#include + +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); +#ifdef CONFIG_NONCOHERENT_IO + dma_cache_wback_inv((unsigned long) ret, size); + ret = KSEG1ADDR(ret); +#endif + *dma_handle = __pa(ret); + return ret; + } + return NULL; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long) KSEG0ADDR(vaddr), get_order(size)); +} diff -urN linux-2.4.18/arch/mips64/kernel/proc.c linux-2.4.19-pre5/arch/mips64/kernel/proc.c --- linux-2.4.18/arch/mips64/kernel/proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/proc.c Sat Mar 30 22:55:27 2002 @@ -1,76 +1,143 @@ /* - * 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. + * linux/arch/mips/kernel/proc.c * - * Copyright (C) 1995, 1996, 1999, 2001 Ralf Baechle - * Copyright (C) 2001 MIPS Technologies, Inc. + * Copyright (C) 1995, 1996, 2001 Ralf Baechle + * Copyright (C) 2001 MIPS Technologies, Inc. */ +#include #include #include #include -#include +#include #include +#include #include #include #include -extern unsigned long unaligned_instructions; unsigned int vced_count, vcei_count; -/* - * BUFFER is PAGE_SIZE bytes long. - * - * Currently /proc/cpuinfo is being abused to print data about the - * number of date/instruction cacheflushes. - */ -int get_cpuinfo(char *buffer) +#ifndef CONFIG_CPU_HAS_LLSC +unsigned long ll_ops, sc_ops; +#endif + +static const char *cpu_name[] = { + [CPU_UNKNOWN] "unknown", + [CPU_R2000] "R2000", + [CPU_R3000] "R3000", + [CPU_R3000A] "R3000A", + [CPU_R3041] "R3041", + [CPU_R3051] "R3051", + [CPU_R3052] "R3052", + [CPU_R3081] "R3081", + [CPU_R3081E] "R3081E", + [CPU_R4000PC] "R4000PC", + [CPU_R4000SC] "R4000SC", + [CPU_R4000MC] "R4000MC", + [CPU_R4200] "R4200", + [CPU_R4400PC] "R4400PC", + [CPU_R4400SC] "R4400SC", + [CPU_R4400MC] "R4400MC", + [CPU_R4600] "R4600", + [CPU_R6000] "R6000", + [CPU_R6000A] "R6000A", + [CPU_R8000] "R8000", + [CPU_R10000] "R10000", + [CPU_R4300] "R4300", + [CPU_R4650] "R4650", + [CPU_R4700] "R4700", + [CPU_R5000] "R5000", + [CPU_R5000A] "R5000A", + [CPU_R4640] "R4640", + [CPU_NEVADA] "Nevada", + [CPU_RM7000] "RM7000", + [CPU_R5432] "R5432", + [CPU_4KC] "MIPS 4Kc", + [CPU_5KC] "MIPS 5Kc", + [CPU_R4310] "R4310", + [CPU_SB1] "SiByte SB1", + [CPU_TX3912] "TX3912", + [CPU_TX3922] "TX3922", + [CPU_TX3927] "TX3927", + [CPU_AU1000] "Au1000", + [CPU_4KEC] "MIPS 4KEc", + [CPU_4KSC] "MIPS 4KSc", + [CPU_VR41XX] "NEC Vr41xx", + [CPU_R5500] "R5500", + [CPU_TX49XX] "TX49xx", + [CPU_TX39XX] "TX39xx" +}; + + +static int show_cpuinfo(struct seq_file *m, void *v) { + unsigned int version = mips_cpu.processor_id; + unsigned int fp_vers = mips_cpu.fpu_id; + unsigned long n = (unsigned long) v - 1; char fmt [64]; - size_t len; - len = sprintf(buffer, "cpu\t\t\t: MIPS\n"); -#if 0 - len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", - cpu_name[mips_cputype <= CPU_LAST ? - mips_cputype : - CPU_UNKNOWN], - (version >> 4) & 0x0f, - version & 0x0f); - len += sprintf(buffer + len, "system type\t\t: %s %s\n", - mach_group_names[mips_machgroup], - mach_group_to_name[mips_machgroup][mips_machtype]); -#endif - len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", - (loops_per_jiffy + 2500) / (500000/HZ), - ((loops_per_jiffy + 2500) / (5000/HZ)) % 100); - len += sprintf(buffer + len, "Number of cpus\t\t: %d\n", smp_num_cpus); -#if defined (__MIPSEB__) - len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); +#ifdef CONFIG_SMP + if (!(cpu_online_map & (1<> 4) & 0x0f, version & 0x0f, + (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); + seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); + seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); + seq_printf(m, "microsecond timers\t: %s\n", + (mips_cpu.options & MIPS_CPU_COUNTER) ? "yes" : "no"); + seq_printf(m, "extra interrupt vector\t: %s\n", + (mips_cpu.options & MIPS_CPU_DIVEC) ? "yes" : "no"); + seq_printf(m, "hardware watchpoint\t: %s\n", + watch_available ? "yes" : "no"); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", - vce_available ? "%d" : "not available"); - len += sprintf(buffer + len, fmt, 'D', vced_count); - len += sprintf(buffer + len, fmt, 'I', vcei_count); + (mips_cpu.options & MIPS_CPU_VCE) ? "%d" : "not available"); + seq_printf(m, fmt, 'D', vced_count); + seq_printf(m, fmt, 'I', vcei_count); + +#ifndef CONFIG_CPU_HAS_LLSC + seq_printf(m, "ll emulations\t\t: %lu\n", ll_ops); + seq_printf(m, "sc emulations\t\t: %lu\n", sc_ops); +#endif + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; - return len; + return i < NR_CPUS ? (void *) (i + 1) : NULL; } -void init_irq_proc(void) +static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - /* Nothing, for now. */ + ++*pos; + return c_start(m, pos); } + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; diff -urN linux-2.4.18/arch/mips64/kernel/process.c linux-2.4.19-pre5/arch/mips64/kernel/process.c --- linux-2.4.18/arch/mips64/kernel/process.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/process.c Sat Mar 30 22:55:27 2002 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ #include #include -asmlinkage int cpu_idle(void) +ATTRIB_NORET void cpu_idle(void) { /* endless idle loop with no priority at all */ init_idle(); @@ -37,8 +38,8 @@ current->counter = -100; while (1) { while (!current->need_resched) - if (wait_available) - __asm__("wait"); + if (cpu_wait) + (*cpu_wait)(); schedule(); check_pgt_cache(); } @@ -52,7 +53,7 @@ { /* Forget lazy fpu state */ if (IS_FPU_OWNER()) { - set_cp0_status(ST0_CU1, ST0_CU1); + __enable_fpu(); __asm__ __volatile__("cfc1\t$0,$31"); CLEAR_FPU_OWNER(); } @@ -62,7 +63,7 @@ { /* Forget lazy fpu state */ if (IS_FPU_OWNER()) { - set_cp0_status(ST0_CU1, ST0_CU1); + __enable_fpu(); __asm__ __volatile__("cfc1\t$0,$31"); CLEAR_FPU_OWNER(); } @@ -122,10 +123,11 @@ /* We actually store the FPU info in the task->thread * area. */ - if(regs->cp0_status & ST0_CU1) { + if (regs->cp0_status & ST0_CU1) { memcpy(r, ¤t->thread.fpu, sizeof(current->thread.fpu)); return 1; } + return 0; /* Task didn't use the fpu at all. */ } @@ -172,8 +174,8 @@ /* The called subroutine might have destroyed any of the * at, result, argument or temporary registers ... */ - :"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", - "$9","$10","$11","$12","$13","$14","$15","$24","$25"); + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$9","$10","$11","$12","$13","$14","$15","$24","$25"); return retval; } diff -urN linux-2.4.18/arch/mips64/kernel/ptrace.c linux-2.4.19-pre5/arch/mips64/kernel/ptrace.c --- linux-2.4.18/arch/mips64/kernel/ptrace.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/ptrace.c Sat Mar 30 22:55:27 2002 @@ -22,11 +22,13 @@ #include #include +#include #include #include #include #include #include +#include /* * Called by kernel/ptrace.c when detaching.. @@ -75,15 +77,11 @@ ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; + switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -114,17 +112,23 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { - unsigned long *fregs = - (void *) child->thread.fpu.hard.fp_regs; - + unsigned long long *fregs + = (unsigned long long *) + &child->thread.fpu.hard.fp_regs[0]; + if (mips_cpu.options & MIPS_CPU_FPU) { #ifndef CONFIG_SMP - if (last_task_used_math == child) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(child); - set_cp0_status(ST0_CU1, 0); - last_task_used_math = NULL; - } + if (last_task_used_math == child) { + __enable_fpu(); + save_fp(child); + __disable_fpu(); + last_task_used_math = NULL; + } #endif + } else { + fregs = (unsigned long long *) + child->thread.fpu.soft.regs; + } + /* * The odd registers are actually the high * order bits of the values stored in the even @@ -154,12 +158,15 @@ tmp = regs->lo; break; case FPC_CSR: - tmp = child->thread.fpu.hard.control; + if (mips_cpu.options & MIPS_CPU_FPU) + tmp = child->thread.fpu.hard.control; + else + tmp = child->thread.fpu.soft.sr; break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; __save_flags(flags); - set_cp0_status(ST0_CU1, ST0_CU1); + __enable_fpu(); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); __restore_flags(flags); break; @@ -192,17 +199,21 @@ regs->regs[addr] = data; break; case FPR_BASE ... FPR_BASE + 31: { - unsigned long *fregs = - (void *) child->thread.fpu.hard.fp_regs; + unsigned long long *fregs; + fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0]; if (child->used_math) { #ifndef CONFIG_SMP - if (last_task_used_math == child) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(child); - set_cp0_status(ST0_CU1, 0); - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } + if (last_task_used_math == child) + if (mips_cpu.options & MIPS_CPU_FPU) { + __enable_fpu(); + save_fp(child); + __disable_fpu(); + last_task_used_math = NULL; + regs->cp0_status &= ~ST0_CU1; + } else { + fregs = (unsigned long long *) + child->thread.fpu.soft.regs; + } #endif } else { /* FP not yet used */ @@ -234,7 +245,10 @@ regs->lo = data; break; case FPC_CSR: - child->thread.fpu.hard.control = data; + if (mips_cpu.options & MIPS_CPU_FPU) + child->thread.fpu.hard.control = data; + else + child->thread.fpu.soft.sr = data; break; default: /* The rest are not allowed. */ @@ -334,14 +348,9 @@ ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { @@ -377,14 +386,20 @@ unsigned long long *fregs = (unsigned long long *) &child->thread.fpu.hard.fp_regs[0]; + if (mips_cpu.options & MIPS_CPU_FPU) { #ifndef CONFIG_SMP - if (last_task_used_math == child) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(child); - set_cp0_status(ST0_CU1, 0); - last_task_used_math = NULL; - } + if (last_task_used_math == child) { + __enable_fpu(); + save_fp(child); + __disable_fpu(); + last_task_used_math = NULL; + } #endif + } else { + fregs = (unsigned long long *) + child->thread.fpu.soft.regs; + } + /* * The odd registers are actually the high * order bits of the values stored in the even @@ -414,12 +429,15 @@ tmp = regs->lo; break; case FPC_CSR: - tmp = child->thread.fpu.hard.control; + if (mips_cpu.options & MIPS_CPU_FPU) + tmp = child->thread.fpu.hard.control; + else + tmp = child->thread.fpu.soft.sr; break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; __save_flags(flags); - set_cp0_status(ST0_CU1, ST0_CU1); + __enable_fpu(); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); __restore_flags(flags); break; @@ -452,16 +470,22 @@ regs->regs[addr] = data; break; case FPR_BASE ... FPR_BASE + 31: { - unsigned long *fregs = - (void *) child->thread.fpu.hard.fp_regs; + unsigned long long *fregs = (unsigned long long *) + &child->thread.fpu.hard.fp_regs[0]; + if (child->used_math) { #ifndef CONFIG_SMP - if (last_task_used_math == child) { - set_cp0_status(ST0_CU1, ST0_CU1); - save_fp(child); - set_cp0_status(ST0_CU1, 0); - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; + if (mips_cpu.options & MIPS_CPU_FPU) { + if (last_task_used_math == child) { + __enable_fpu(); + save_fp(child); + __disable_fpu(); + last_task_used_math = NULL; + regs->cp0_status &= ~ST0_CU1; + } else { + fregs = (unsigned long long *) + child->thread.fpu.soft.regs; + } } #endif } else { @@ -494,7 +518,10 @@ regs->lo = data; break; case FPC_CSR: - child->thread.fpu.hard.control = data; + if (mips_cpu.options & MIPS_CPU_FPU) + child->thread.fpu.hard.control = data; + else + child->thread.fpu.soft.sr = data; break; default: /* The rest are not allowed. */ diff -urN linux-2.4.18/arch/mips64/kernel/r4k_genex.S linux-2.4.19-pre5/arch/mips64/kernel/r4k_genex.S --- linux-2.4.18/arch/mips64/kernel/r4k_genex.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/r4k_genex.S Sat Mar 30 22:55:27 2002 @@ -15,77 +15,9 @@ #include #include #include +#include #include - .macro __build_clear_none - .endm - - .macro __build_clear_sti - STI - .endm - - .macro __build_clear_cli - CLI - .endm - - .macro __build_clear_fpe - cfc1 a1, fcr31 - li a2, ~(0x3f << 13) - and a2, a1 - ctc1 a2, fcr31 - STI - .endm - - .macro __build_clear_ade - dmfc0 t0, CP0_BADVADDR - sd t0, PT_BVADDR(sp) - KMODE - .endm - - .macro __BUILD_silent exception - .endm - - /* Gas tries to parse the PRINT argument as a string containing - string escapes and emits bogus warnings if it believes to - recognize an unknown escape code. So make the arguments - start with an n and gas will believe \n is ok ... */ - .macro __BUILD_verbose nexception - ld a1, PT_EPC(sp) - PRINT("Got \nexception at %016lx\012") - .endm - - .macro __BUILD_count exception - .set reorder - ld t0,exception_count_\exception - daddiu t0, 1 - sd t0,exception_count_\exception - .set noreorder - .comm exception_count\exception, 8, 8 - .endm - - .macro BUILD_HANDLER exception handler clear verbose - .align 5 - NESTED(handle_\exception, PT_SIZE, sp) - .set noat - SAVE_ALL -#if DEBUG_MIPS64 -jal dodebug2 -ld $4, PT_R4(sp) -ld $5, PT_R5(sp) -ld $6, PT_R6(sp) -ld $7, PT_R7(sp) -ld $2, PT_R2(sp) -#endif - __BUILD_clear_\clear - .set at - __BUILD_\verbose \exception - move a0, sp - jal do_\handler - j ret_from_sys_call - nop - END(handle_\exception) - .endm - BUILD_HANDLER adel ade ade silent /* #4 */ BUILD_HANDLER ades ade ade silent /* #5 */ BUILD_HANDLER ibe ibe cli silent /* #6 */ @@ -97,6 +29,7 @@ BUILD_HANDLER tr tr sti silent /* #13 */ BUILD_HANDLER fpe fpe fpe silent /* #15 */ BUILD_HANDLER watch watch sti verbose /* #23 */ + BUILD_HANDLER mcheck mcheck cli verbose /* #24 */ BUILD_HANDLER reserved reserved sti verbose /* others */ __INIT diff -urN linux-2.4.18/arch/mips64/kernel/r4k_switch.S linux-2.4.19-pre5/arch/mips64/kernel/r4k_switch.S --- linux-2.4.18/arch/mips64/kernel/r4k_switch.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/r4k_switch.S Sat Mar 30 22:55:27 2002 @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include @@ -43,14 +42,10 @@ */ move $28, a1 cpu_restore_nonscratch $28 -#ifndef CONFIG_SMP - daddiu t0, $28, KERNEL_STACK_SIZE-32 - sd t0, kernelsp -#else - mtc0 a1, CP0_WATCHLO - dsrl32 a1, a1, 0 - mtc0 a1, CP0_WATCHHI -#endif + + daddiu a1, $28, KERNEL_STACK_SIZE-32 + set_saved_sp a1 t0 + mfc0 t1, CP0_STATUS /* Do we really need this? */ li a3, 0xff00 and t1, a3 diff -urN linux-2.4.18/arch/mips64/kernel/r4k_tlb.S linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb.S --- linux-2.4.18/arch/mips64/kernel/r4k_tlb.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb.S Thu Jan 1 01:00:00 1970 @@ -1,126 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Silicon Graphics, Inc. - * Written by Ulf Carlsson (ulfc@engr.sgi.com) - */ -#include -#include -#include -#include -#include -#include -#include - - .data - .comm pgd_current, NR_CPUS * 8, 8 - - /* - * After this macro runs we have a pointer to the pte of the address - * that caused the fault in in PTR. - */ - - .macro LOAD_PTE2, ptr, tmp -#ifdef CONFIG_SMP - dmfc0 \tmp, CP0_CONTEXT - dla \ptr, pgd_current - dsrl \tmp, 23 - daddu \ptr, \tmp -#else - dla \ptr, pgd_current -#endif - dmfc0 \tmp, CP0_BADVADDR - ld \ptr, (\ptr) - bltz \tmp, kaddr - dsrl \tmp, (PGDIR_SHIFT-3) # get pgd offset in bytes - andi \tmp, ((PTRS_PER_PGD - 1)<<3) - daddu \ptr, \tmp # add in pgd offset - dmfc0 \tmp, CP0_BADVADDR - ld \ptr, (\ptr) # get pmd pointer - dsrl \tmp, (PMD_SHIFT-3) # get pmd offset in bytes - andi \tmp, ((PTRS_PER_PMD - 1)<<3) - daddu \ptr, \tmp # add in pmd offset - dmfc0 \tmp, CP0_XCONTEXT - ld \ptr, (\ptr) # get pte pointer - andi \tmp, 0xff0 # get pte offset - daddu \ptr, \tmp - .endm - - /* - * This places the even/odd pte pair in the page table at the pte - * entry pointed to by PTE into ENTRYLO0 and ENTRYLO1. - */ - .macro PTE_RELOAD, pte0, pte1 - dsrl \pte0, 6 # convert to entrylo0 - dmtc0 \pte0, CP0_ENTRYLO0 # load it - dsrl \pte1, 6 # convert to entrylo1 - dmtc0 \pte1, CP0_ENTRYLO1 # load it - .endm - - .text - .set noreorder - .set mips3 - - .align 5 -FEXPORT(except_vec0) - .set noat -1: b 1b - nop - - /* TLB refill handler for the R10000. - * Attention: We may only use 32 instructions. - */ - - .align 5 -FEXPORT(except_vec1_r10k) - .set noat - LOAD_PTE2 k1 k0 - ld k0, 0(k1) # get even pte - ld k1, 8(k1) # get odd pte - PTE_RELOAD k0 k1 - nop - tlbwr - eret -kaddr: - dla k0, handle_vmalloc_address # MAPPED kernel needs this - jr k0 - nop - - .align 5 -FEXPORT(handle_vmalloc_address) - .set noat - /* - * First, determine that the address is in/above vmalloc range. - */ - dmfc0 k0, CP0_BADVADDR - dli k1, VMALLOC_START - - /* - * Now find offset into kptbl. - */ - dsubu k0, k0, k1 - dla k1, kptbl - dsrl k0, (PAGE_SHIFT+1) # get vpn2 - dsll k0, 4 # byte offset of pte - daddu k1, k1, k0 - - /* - * Determine that fault address is within vmalloc range. - */ - dla k0, ekptbl - sltu k0, k1, k0 - beqz k0, not_vmalloc - - /* - * Load cp0 registers. - */ - ld k0, 0(k1) # get even pte - ld k1, 8(k1) # get odd pte - -not_vmalloc: - PTE_RELOAD k0 k1 - nop - tlbwr - eret diff -urN linux-2.4.18/arch/mips64/kernel/r4k_tlb_debug.c linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb_debug.c --- linux-2.4.18/arch/mips64/kernel/r4k_tlb_debug.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb_debug.c Thu Jan 1 01:00:00 1970 @@ -1,71 +0,0 @@ -/* - * 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) 1999 Ralf Baechle - * Copyright (C) 1999 Silicon Graphics, Inc. - * - * TLB debugging routines. These perform horribly slow but can easily be - * modified for debugging purposes. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, - unsigned long address); - -asmlinkage void tlb_refill_debug(struct pt_regs regs) -{ - show_regs(®s); - panic(__FUNCTION__ " called. This Does Not Happen (TM)."); -} - -asmlinkage void xtlb_refill_debug(struct pt_regs *regs) -{ - unsigned long addr; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - addr = regs->cp0_badvaddr & ~((PAGE_SIZE << 1) - 1); - pgd = pgd_offset(current->active_mm, addr); - pmd = pmd_offset(pgd, addr); - pte = pte_offset(pmd, addr); - - set_entrylo0(pte_val(pte[0]) >> 6); - set_entrylo1(pte_val(pte[1]) >> 6); - __asm__ __volatile__("nop;nop;nop"); - - tlb_write_random(); -} - -asmlinkage void xtlb_mod_debug(struct pt_regs *regs) -{ - unsigned long addr; - - addr = regs->cp0_badvaddr; - do_page_fault(regs, 1, addr); -} - -asmlinkage void xtlb_tlbl_debug(struct pt_regs *regs) -{ - unsigned long addr; - - addr = regs->cp0_badvaddr; - do_page_fault(regs, 0, addr); -} - -asmlinkage void xtlb_tlbs_debug(struct pt_regs *regs) -{ - unsigned long addr; - - addr = regs->cp0_badvaddr; - do_page_fault(regs, 1, addr); -} diff -urN linux-2.4.18/arch/mips64/kernel/r4k_tlb_glue.S linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb_glue.S --- linux-2.4.18/arch/mips64/kernel/r4k_tlb_glue.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/r4k_tlb_glue.S Thu Jan 1 01:00:00 1970 @@ -1,46 +0,0 @@ -/* - * 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) 1999 Ralf Baechle - * Copyright (C) 1999 Silicon Graphics, Inc. - */ -#define __ASSEMBLY__ -#include -#include -#include -#include - - .macro __BUILD_cli - CLI - .endm - - .macro __BUILD_sti - STI - .endm - - .macro tlb_handler name interruptible writebit - NESTED(__\name, PT_SIZE, sp) - SAVE_ALL -#if DEBUG_MIPS64 -jal dodebug2 -ld $4, PT_R4(sp) -ld $5, PT_R5(sp) -ld $6, PT_R6(sp) -ld $7, PT_R7(sp) -ld $2, PT_R2(sp) -#endif - dmfc0 a2, CP0_BADVADDR - __BUILD_\interruptible - li a1, \writebit - sd a2, PT_BVADDR(sp) - move a0, sp - jal do_page_fault - j ret_from_sys_call - END(__\name) - .endm - - tlb_handler xtlb_mod sti 1 - tlb_handler xtlb_tlbl sti 0 - tlb_handler xtlb_tlbs sti 1 diff -urN linux-2.4.18/arch/mips64/kernel/reset.c linux-2.4.19-pre5/arch/mips64/kernel/reset.c --- linux-2.4.18/arch/mips64/kernel/reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/reset.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,36 @@ +/* + * 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) 2001 by Ralf Baechle + * Copyright (C) 2001 MIPS Technologies, Inc. + */ +#include +#include +#include +#include + +/* + * Urgs ... Too many MIPS machines to handle this in a generic way. + * So handle all using function pointers to machine specific + * functions. + */ +void (*_machine_restart)(char *command); +void (*_machine_halt)(void); +void (*_machine_power_off)(void); + +void machine_restart(char *command) +{ + _machine_restart(command); +} + +void machine_halt(void) +{ + _machine_halt(); +} + +void machine_power_off(void) +{ + _machine_power_off(); +} diff -urN linux-2.4.18/arch/mips64/kernel/scall_64.S linux-2.4.19-pre5/arch/mips64/kernel/scall_64.S --- linux-2.4.18/arch/mips64/kernel/scall_64.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/scall_64.S Sat Mar 30 22:55:33 2002 @@ -347,3 +347,19 @@ PTR sys_mincore PTR sys_madvise PTR sys_getdents64 + PTR sys_ni_syscall + PTR sys_gettid /* 5215 */ + PTR sys_readahead + PTR sys_ni_syscall /* reserved for setxattr */ + PTR sys_ni_syscall /* reserved for lsetxattr */ + PTR sys_ni_syscall /* reserved for fsetxattr */ + PTR sys_ni_syscall /* 5220 res. for getxattr */ + PTR sys_ni_syscall /* reserved for lgetxattr */ + PTR sys_ni_syscall /* reserved for fgetxattr */ + PTR sys_ni_syscall /* reserved for listxattr */ + PTR sys_ni_syscall /* reserved for llistxattr */ + PTR sys_ni_syscall /* 5225 res. for flistxattr */ + PTR sys_ni_syscall /* reserved for removexattr */ + PTR sys_ni_syscall /* reserved for lremovexattr */ + PTR sys_ni_syscall /* reserved for fremovexattr */ + PTR sys_tkill diff -urN linux-2.4.18/arch/mips64/kernel/scall_o32.S linux-2.4.19-pre5/arch/mips64/kernel/scall_o32.S --- linux-2.4.18/arch/mips64/kernel/scall_o32.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/scall_o32.S Sat Mar 30 22:55:33 2002 @@ -43,6 +43,12 @@ daddiu t1, 4 # skip to next instruction beqz t0, not_o32_scall sd t1, PT_EPC(sp) +#if 0 + SAVE_ALL + move a1, v0 + PRINT("Scall %ld\n") + RESTORE_ALL +#endif /* XXX Put both in one cacheline, should save a bit. */ dsll t0, v0, 3 # offset into table @@ -192,12 +198,14 @@ END(handle_sys) LEAF(mips_atomic_set) - ld v1, THREAD_CURDS($28) + andi v0, a1, 3 # must be word aligned + bnez v0, bad_alignment + + ld v1, THREAD_CURDS($28) # in legal address range? daddiu a0, a1, 4 or a0, a0, a1 - li v0, -EFAULT and a0, a0, v1 - bltz a0, 9f + bltz a0, bad_address /* Ok, this is the ll/sc case. World is sane :-) */ 1: ll v0, (a1) @@ -223,7 +231,12 @@ li a3, 0 # success j ret_from_sys_call -9: li v0, -EFAULT +bad_address: + li v0, -EFAULT + jr ra + +bad_alignment: + li v0, -EINVAL jr ra END(mips_atomic_set) @@ -454,6 +467,23 @@ sys sys_madvise 3 sys sys_getdents64 3 sys sys32_fcntl64 3 /* 4220 */ + sys sys_ni_syscall 0 + sys sys_gettid 0 + sys sys32_readahead 5 + sys sys_ni_syscall 0 /* reserved for setxattr */ + sys sys_ni_syscall 0 /* 4225 res. for lsetxattr */ + sys sys_ni_syscall 0 /* reserved for fsetxattr */ + sys sys_ni_syscall 0 /* reserved for getxattr */ + sys sys_ni_syscall 0 /* reserved for lgetxattr */ + sys sys_ni_syscall 0 /* reserved for fgetxattr */ + sys sys_ni_syscall 0 /* 4230 res. for listxattr */ + sys sys_ni_syscall 0 /* reserved for llistxattr */ + sys sys_ni_syscall 0 /* reserved for flistxattr */ + sys sys_ni_syscall 0 /* reserved for removexattr */ + sys sys_ni_syscall 0 /* reserved for lremovexattr */ + sys sys_ni_syscall 0 /* 4235 res. for fremovexattr */ + sys sys32_tkill 2 + .endm .macro sys function, nargs diff -urN linux-2.4.18/arch/mips64/kernel/setup.c linux-2.4.19-pre5/arch/mips64/kernel/setup.c --- linux-2.4.18/arch/mips64/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/setup.c Sat Mar 30 22:55:27 2002 @@ -4,7 +4,8 @@ * for more details. * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1995 Waldorf Electronics + * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Ralf Baechle * Copyright (C) 1996 Stoned Elipot * Copyright (C) 1999 Silicon Graphics, Inc. */ @@ -27,10 +28,10 @@ #include #endif -#include +#include #include -#include #include +#include #include #include #include @@ -39,6 +40,15 @@ struct cpuinfo_mips cpu_data[1]; #endif +/* + * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, + * the implementation of the "wait" feature differs between CPU families. This + * points to the function that implements CPU specific wait. + * The wait instruction stops the pipeline and reduces the power consumption of + * the CPU very much. + */ +void (*cpu_wait)(void) = NULL; + #ifdef CONFIG_VT struct screen_info screen_info; #endif @@ -51,11 +61,6 @@ char wait_available; /* - * Do we have a cyclecounter available? - */ -char cyclecounter_available; - -/* * Set if box has EISA slots. */ int EISA_bus = 0; @@ -81,7 +86,6 @@ * * These are initialized so they are in the .data section */ -unsigned long mips_cputype = CPU_UNKNOWN; unsigned long mips_machtype = MACH_UNKNOWN; unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; @@ -95,58 +99,647 @@ char saved_command_line[CL_SIZE]; extern char arcs_cmdline[CL_SIZE]; +/* + * mips_io_port_base is the begin of the address space to which x86 style + * I/O ports are mapped. + */ +const unsigned long mips_io_port_base = -1; +EXPORT_SYMBOL(mips_io_port_base); + extern void ip22_setup(void); extern void ip27_setup(void); +extern void ip32_setup(void); -static inline void cpu_probe(void) -{ - unsigned int prid = read_32bit_cp0_register(CP0_PRID); +extern void sgi_sysinit(void); +extern void SetUpBootInfo(void); +extern void load_mmu(void); +extern ATTRIB_NORET asmlinkage void start_kernel(void); +extern void prom_init(int, char **, char **, int *); - switch(prid & 0xff00) { - case PRID_IMP_R4000: - if((prid & 0xff) == PRID_REV_R4400) - mips_cputype = CPU_R4400SC; - else - mips_cputype = CPU_R4000SC; +static inline void check_wait(void) +{ + printk("Checking for 'wait' instruction... "); + switch(mips_cpu.cputype) { + case CPU_R3081: + case CPU_R3081E: + cpu_wait = r3081_wait; + printk(" available.\n"); break; - case PRID_IMP_R4600: - mips_cputype = CPU_R4600; + case CPU_TX3927: + case CPU_TX39XX: + cpu_wait = r39xx_wait; + printk(" available.\n"); break; - case PRID_IMP_R4700: - mips_cputype = CPU_R4700; + case CPU_R4200: +/* case CPU_R4300: */ + case CPU_R4600: + case CPU_R4640: + case CPU_R4650: + case CPU_R4700: + case CPU_R5000: + case CPU_NEVADA: + case CPU_RM7000: + case CPU_TX49XX: + cpu_wait = r4k_wait; + printk(" available.\n"); break; - case PRID_IMP_R5000: - mips_cputype = CPU_R5000; + default: + printk(" unavailable.\n"); break; - case PRID_IMP_NEVADA: - mips_cputype = CPU_NEVADA; + } +} + +void __init check_bugs(void) +{ + check_wait(); +} + +/* + * Probe whether cpu has config register by trying to play with + * alternate cache bit and see whether it matters. + * It's used by cpu_probe to distinguish between R3000A and R3081. + */ +static inline int cpu_has_confreg(void) +{ +#ifdef CONFIG_CPU_R3000 + extern unsigned long r3k_cache_size(unsigned long); + unsigned long size1, size2; + unsigned long cfg = read_32bit_cp0_register(CP0_CONF); + + size1 = r3k_cache_size(ST0_ISC); + write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC); + size2 = r3k_cache_size(ST0_ISC); + write_32bit_cp0_register(CP0_CONF, cfg); + return size1 != size2; +#else + return 0; +#endif +} + +/* declaration of the global struct */ +struct mips_cpu mips_cpu = { + processor_id: PRID_IMP_UNKNOWN, + fpu_id: FPIR_IMP_NONE, + cputype: CPU_UNKNOWN +}; + +#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \ + | MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX) + +static inline void cpu_probe(void) +{ +#ifdef CONFIG_CPU_MIPS32 + unsigned long config1; +#endif + + mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID); + switch (mips_cpu.processor_id & 0xff0000) { + case PRID_COMP_LEGACY: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_R2000: + mips_cpu.cputype = CPU_R2000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R3000: + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) + if (cpu_has_confreg()) + mips_cpu.cputype = CPU_R3081E; + else + mips_cpu.cputype = CPU_R3000A; + else + mips_cpu.cputype = CPU_R3000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R4000: + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400) + mips_cpu.cputype = CPU_R4400SC; + else + mips_cpu.cputype = CPU_R4000SC; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH | + MIPS_CPU_VCE; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_VR41XX: + mips_cpu.cputype = CPU_VR41XX; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_R4300: + mips_cpu.cputype = CPU_R4300; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_R4600: + mips_cpu.cputype = CPU_R4600; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; + #if 0 + case PRID_IMP_R4650: + /* + * This processor doesn't have an MMU, so it's not + * "real easy" to run Linux on it. It is left purely + * for documentation. Commented out because it shares + * it's c0_prid id number with the TX3900. + */ + mips_cpu.cputype = CPU_R4650; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; + #endif + case PRID_IMP_TX39: + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + + if ((mips_cpu.processor_id & 0xf0) == + (PRID_REV_TX3927 & 0xf0)) { + mips_cpu.cputype = CPU_TX3927; + mips_cpu.tlbsize = 64; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; + } else { + switch (mips_cpu.processor_id & 0xff) { + case PRID_REV_TX3912: + mips_cpu.cputype = CPU_TX3912; + mips_cpu.tlbsize = 32; + break; + case PRID_REV_TX3922: + mips_cpu.cputype = CPU_TX3922; + mips_cpu.tlbsize = 64; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } + } + break; + case PRID_IMP_R4700: + mips_cpu.cputype = CPU_R4700; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_TX49: + mips_cpu.cputype = CPU_TX49XX; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 4; + mips_cpu.dcache.ways = 4; + break; + case PRID_IMP_R5000: + mips_cpu.cputype = CPU_R5000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5432: + mips_cpu.cputype = CPU_R5432; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5500: + mips_cpu.cputype = CPU_R5500; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_NEVADA: + mips_cpu.cputype = CPU_NEVADA; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR | MIPS_CPU_DIVEC; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; + break; + case PRID_IMP_R6000: + mips_cpu.cputype = CPU_R6000; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_R6000A: + mips_cpu.cputype = CPU_R6000A; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_RM7000: + mips_cpu.cputype = CPU_RM7000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | + MIPS_CPU_32FPR; + /* + * Undocumented RM7000: Bit 29 in the info register of + * the RM7000 v2.0 indicates if the TLB has 48 or 64 + * entries. + * + * 29 1 => 64 entry JTLB + * 0 => 48 entry JTLB + */ + mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48; + break; + case PRID_IMP_R8000: + mips_cpu.cputype = CPU_R8000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ + break; + case PRID_IMP_R10000: + mips_cpu.cputype = CPU_R10000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_COUNTER | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 64; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } + break; +#ifdef CONFIG_CPU_MIPS32 + case PRID_COMP_MIPS: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_4KC: + mips_cpu.cputype = CPU_4KC; + goto cpu_4kc; + case PRID_IMP_4KEC: + mips_cpu.cputype = CPU_4KEC; + goto cpu_4kc; + case PRID_IMP_4KSC: + mips_cpu.cputype = CPU_4KSC; +cpu_4kc: + /* + * Why do we set all these options by default, THEN + * query them?? + */ + mips_cpu.isa_level = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH | + MIPS_CPU_MCHECK; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_5KC: + mips_cpu.cputype = CPU_5KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; + /* See comment above about querying options */ + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH | + MIPS_CPU_MCHECK; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; - case PRID_IMP_R8000: - mips_cputype = CPU_R8000; + case PRID_COMP_ALCHEMY: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_AU1_REV1: + case PRID_IMP_AU1_REV2: + mips_cpu.cputype = CPU_AU1000; + mips_cpu.isa_level = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; - case PRID_IMP_R10000: - case PRID_IMP_R12000: - mips_cputype = CPU_R10000; +#endif /* CONFIG_CPU_MIPS32 */ + case PRID_COMP_SIBYTE: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_SB1: + mips_cpu.cputype = CPU_SB1; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | + MIPS_CPU_MCHECK; +#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS + /* FPU in pass1 is known to have issues. */ + mips_cpu.options |= MIPS_CPU_FPU; +#endif + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; default: - mips_cputype = CPU_UNKNOWN; + mips_cpu.cputype = CPU_UNKNOWN; } } -void __init setup_arch(char **cmdline_p) +static inline void cpu_report(void) +{ + printk("CPU revision is: %08x\n", mips_cpu.processor_id); + if (mips_cpu.options & MIPS_CPU_FPU) + printk("FPU revision is: %08x\n", mips_cpu.fpu_id); +} + +asmlinkage void __init init_arch(int argc, char **argv, char **envp, + int *prom_vec) { + /* Determine which MIPS variant we are running on. */ cpu_probe(); + + prom_init(argc, argv, envp, prom_vec); + +#ifdef CONFIG_SGI_IP22 + sgi_sysinit(); +#endif + + cpu_report(); + + /* + * Determine the mmu/cache attached to this machine, then flush the + * tlb and caches. On the r4xx0 variants this also sets CP0_WIRED to + * zero. + */ load_mmu(); + /* + * On IP27, I am seeing the TS bit set when the kernel is loaded. + * Maybe because the kernel is in ckseg0 and not xkphys? Clear it + * anyway ... + */ + clear_cp0_status(ST0_BEV|ST0_TS|ST0_CU1|ST0_CU2|ST0_CU3); + set_cp0_status(ST0_CU0|ST0_KX|ST0_SX|ST0_FR); + + start_kernel(); +} + +void __init add_memory_region(phys_t start, phys_t size, + long type) +{ + int x = boot_mem_map.nr_map; + + if (x == BOOT_MEM_MAP_MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + boot_mem_map.map[x].addr = start; + boot_mem_map.map[x].size = size; + boot_mem_map.map[x].type = type; + boot_mem_map.nr_map++; +} + +static void __init print_memory_map(void) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + printk(" memory: %08Lx @ %08Lx ", + (unsigned long long) boot_mem_map.map[i].size, + (unsigned long long) boot_mem_map.map[i].addr); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + printk("(usable)\n"); + break; + case BOOT_MEM_ROM_DATA: + printk("(ROM data)\n"); + break; + case BOOT_MEM_RESERVED: + printk("(reserved)\n"); + break; + default: + printk("type %lu\n", boot_mem_map.map[i].type); + break; + } + } +} + +static inline void parse_mem_cmdline(void) +{ + char c = ' ', *to = command_line, *from = saved_command_line; + unsigned long start_at, mem_size; + int len = 0; + int usermem = 0; + + printk("Determined physical RAM map:\n"); + print_memory_map(); + + for (;;) { + /* + * "mem=XXX[kKmM]" defines a memory region from + * 0 to , overriding the determined size. + * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from + * to +, overriding the determined size. + */ + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + /* + * If a user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + boot_mem_map.nr_map = 0; + usermem = 1; + } + mem_size = memparse(from + 4, &from); + if (*from == '@') + start_at = memparse(from + 1, &from); + else + start_at = 0; + add_memory_region(start_at, mem_size, BOOT_MEM_RAM); + } + c = *(from++); + if (!c) + break; + if (CL_SIZE <= ++len) + break; + *(to++) = c; + } + *to = '\0'; + + if (usermem) { + printk("User-defined physical RAM map:\n"); + print_memory_map(); + } +} + +void bootmem_init(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long *initrd_header; +#endif + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn; + int i; + extern int _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + * start_pfn = PFN_UP(__pa(&_end)); + */ + start_pfn = PFN_UP((unsigned long)&_end - KSEG0); + + /* Find the highest page frame number we have available. */ + max_pfn = 0; + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + } + + /* Initialize the boot-time allocator. */ + bootmap_size = init_bootmem(start_pfn, max_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + + /* + * Reserve usable memory. + */ + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(boot_mem_map.map[i].addr); + if (curr_pfn >= max_pfn) + continue; + if (curr_pfn < start_pfn) + curr_pfn = start_pfn; + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (last_pfn > max_pfn) + last_pfn = max_pfn; + + /* + * ... finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); + +#ifdef CONFIG_BLK_DEV_INITRD +#error "Initrd is broken, please fit it." + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + initrd_below_start_ok = 1; + if (initrd_end > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); + initrd_start = 0; + } else + *memory_start_p = initrd_end; + } +#endif + +#undef PFN_UP +#undef PFN_DOWN +#undef PFN_PHYS + +} + +void __init setup_arch(char **cmdline_p) +{ #ifdef CONFIG_SGI_IP22 ip22_setup(); #endif #ifdef CONFIG_SGI_IP27 ip27_setup(); #endif +#ifdef CONFIG_SGI_IP32 + ip32_setup(); +#endif +#ifdef CONFIG_SGI_IP32 + ip32_setup(); +#endif +#ifdef CONFIG_SIBYTE_SWARM + swarm_setup(); + bootmem_init(); /* XXX */ +#endif #ifdef CONFIG_ARC_MEMORY - bootmem_init (); + bootmem_init(); #endif strncpy(command_line, arcs_cmdline, CL_SIZE); @@ -155,5 +748,33 @@ *cmdline_p = command_line; + parse_mem_cmdline(); + paging_init(); } + +void r3081_wait(void) +{ + unsigned long cfg = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT); +} + +void r39xx_wait(void) +{ + unsigned long cfg = read_32bit_cp0_register(CP0_CONF); + write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT); +} + +void r4k_wait(void) +{ + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +int __init fpu_disable(char *s) +{ + mips_cpu.options &= ~MIPS_CPU_FPU; + return 1; +} +__setup("nofpu", fpu_disable); diff -urN linux-2.4.18/arch/mips64/kernel/signal.c linux-2.4.19-pre5/arch/mips64/kernel/signal.c --- linux-2.4.18/arch/mips64/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -685,10 +685,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/mips64/kernel/signal32.c linux-2.4.19-pre5/arch/mips64/kernel/signal32.c --- linux-2.4.18/arch/mips64/kernel/signal32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/signal32.c Sat Mar 30 22:55:33 2002 @@ -537,8 +537,8 @@ regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; #if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n", - current->comm, current->pid, frame, regs->cp0_epc, frame->code); + printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n", current->comm, + current->pid, frame, regs->cp0_epc, frame->sf_code); #endif return; @@ -613,8 +613,8 @@ regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; #if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n", - current->comm, current->pid, frame, regs->cp0_epc, frame->code); + printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n", current->comm, + current->pid, frame, regs->cp0_epc, frame->rs_code); #endif return; @@ -757,10 +757,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/mips64/kernel/smp.c linux-2.4.19-pre5/arch/mips64/kernel/smp.c --- linux-2.4.18/arch/mips64/kernel/smp.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/smp.c Sat Mar 30 22:55:27 2002 @@ -1,13 +1,25 @@ -#include +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 2001 Kanoj Sarcar + * Copyright (C) 2000, 2001 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. + */ +#include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -15,86 +27,65 @@ #include #include -#ifdef CONFIG_SGI_IP27 - -#include -#include -#include -#include -#include - -#define DORESCHED 0xab -#define DOCALL 0xbc - -static void sendintr(int destid, unsigned char status) -{ - int irq; - -#if (CPUS_PER_NODE == 2) - switch (status) { - case DORESCHED: irq = CPU_RESCHED_A_IRQ; break; - case DOCALL: irq = CPU_CALL_A_IRQ; break; - default: panic("sendintr"); - } - irq += cputoslice(destid); - - /* - * Convert the compact hub number to the NASID to get the correct - * part of the address space. Then set the interrupt bit associated - * with the CPU we want to send the interrupt to. - */ - REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)), - FAST_IRQ_TO_LEVEL(irq)); -#else - << Bomb! Must redefine this for more than 2 CPUS. >> -#endif -} - -#endif /* CONFIG_SGI_IP27 */ - /* The 'big kernel lock' */ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; int smp_threads_ready; /* Not used */ atomic_t smp_commenced = ATOMIC_INIT(0); struct cpuinfo_mips cpu_data[NR_CPUS]; -int smp_num_cpus = 1; /* Number that came online. */ +void (*volatile smp_cpu0_finalize)(void); + +// static atomic_t cpus_booted = ATOMIC_INIT(0); +atomic_t cpus_booted = ATOMIC_INIT(0); + +int smp_num_cpus = 1; /* Number that came online. */ +cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */ int __cpu_number_map[NR_CPUS]; int __cpu_logical_map[NR_CPUS]; cycles_t cacheflush_time; -static void smp_tune_scheduling (void) +// static void smp_tune_scheduling (void) +void smp_tune_scheduling (void) { } -void __init smp_boot_cpus(void) +void __init smp_callin(void) { - extern void allowboot(void); - - init_new_context(current, &init_mm); - current->processor = 0; - init_idle(); - smp_tune_scheduling(); - allowboot(); +#if 0 + calibrate_delay(); + smp_store_cpu_info(cpuid); +#endif } -void __init smp_commence(void) +#ifndef CONFIG_SGI_IP27 +/* + * Hook for doing final board-specific setup after the generic smp setup + * is done + */ +asmlinkage void start_secondary(void) { - wmb(); - atomic_set(&smp_commenced,1); -} + unsigned int cpu = smp_processor_id(); + + prom_init_secondary(); + per_cpu_trap_init(); -static void stop_this_cpu(void *dummy) -{ /* - * Remove this CPU + * XXX parity protection should be folded in here when it's converted + * to an option instead of something based on .cputype */ - for (;;); + pgd_current[cpu] = init_mm.pgd; + cpu_data[cpu].udelay_val = loops_per_jiffy; + prom_smp_finish(); + printk("Slave cpu booted successfully\n"); + CPUMASK_SETB(cpu_online_map, cpu); + atomic_inc(&cpus_booted); + cpu_idle(); } +#endif /* CONFIG_SGI_IP27 */ -void smp_send_stop(void) +void __init smp_commence(void) { - smp_call_function(stop_this_cpu, NULL, 1, 0); - smp_num_cpus = 1; + wmb(); + atomic_set(&smp_commenced, 1); } /* @@ -104,7 +95,7 @@ */ void smp_send_reschedule(int cpu) { - sendintr(cpu, DORESCHED); + core_send_ipi(cpu, SMP_RESCHEDULE_YOURSELF); } /* Not really SMP stuff ... */ @@ -113,6 +104,10 @@ return 0; } +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; + +struct call_data_struct *call_data; + /* * Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. @@ -124,22 +119,15 @@ * Does not return until remote CPUs are nearly ready to execute * or are or have executed. */ -static volatile struct call_data_struct { - void (*func) (void *info); - void *info; - atomic_t started; - atomic_t finished; - int wait; -} *call_data; int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { struct call_data_struct data; - int i, cpus = smp_num_cpus-1; - static spinlock_t lock = SPIN_LOCK_UNLOCKED; + int i, cpus = smp_num_cpus - 1; + int cpu = smp_processor_id(); - if (cpus == 0) + if (!cpus) return 0; data.func = func; @@ -149,12 +137,13 @@ if (wait) atomic_set(&data.finished, 0); - spin_lock_bh(&lock); + spin_lock_bh(&call_lock); call_data = &data; + /* Send a message to all other CPUs and wait for them to respond */ for (i = 0; i < smp_num_cpus; i++) - if (smp_processor_id() != i) - sendintr(i, DOCALL); + if (i != cpu) + core_send_ipi(i, SMP_CALL_FUNCTION); /* Wait for response */ /* FIXME: lock-up detection, backtrace on lock-up */ @@ -164,45 +153,68 @@ if (wait) while (atomic_read(&data.finished) != cpus) barrier(); - spin_unlock_bh(&lock); + spin_unlock_bh(&call_lock); + return 0; } -extern void smp_call_function_interrupt(int irq, void *d, struct pt_regs *r) +void smp_call_function_interrupt(void) { void (*func) (void *info) = call_data->func; void *info = call_data->info; int wait = call_data->wait; + int cpu = smp_processor_id(); + irq_enter(cpu, 0); /* XXX choose an irq number? */ /* * Notify initiating CPU that I've grabbed the data and am * about to execute the function. */ + mb(); atomic_inc(&call_data->started); /* * At this point the info structure may be out of scope unless wait==1. */ (*func)(info); - if (wait) + if (wait) { + mb(); atomic_inc(&call_data->finished); + } + irq_exit(cpu, 0); /* XXX choose an irq number? */ +} + +static void stop_this_cpu(void *dummy) +{ + int cpu = smp_processor_id(); + if (cpu) + for (;;); /* XXX Use halt like i386 */ + + /* XXXKW this isn't quite there yet */ + while (!smp_cpu0_finalize) ; + smp_cpu0_finalize(); +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; } - static void flush_tlb_all_ipi(void *info) { - _flush_tlb_all(); + local_flush_tlb_all(); } void flush_tlb_all(void) { smp_call_function(flush_tlb_all_ipi, 0, 1, 1); - _flush_tlb_all(); + local_flush_tlb_all(); } static void flush_tlb_mm_ipi(void *mm) { - _flush_tlb_mm((struct mm_struct *)mm); + local_flush_tlb_mm((struct mm_struct *)mm); } /* @@ -228,7 +240,7 @@ if (smp_processor_id() != i) CPU_CONTEXT(i, mm) = 0; } - _flush_tlb_mm(mm); + local_flush_tlb_mm(mm); } struct flush_tlb_data { @@ -242,7 +254,7 @@ { struct flush_tlb_data *fd = (struct flush_tlb_data *)info; - _flush_tlb_range(fd->mm, fd->addr1, fd->addr2); + local_flush_tlb_range(fd->mm, fd->addr1, fd->addr2); } void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) @@ -260,14 +272,14 @@ if (smp_processor_id() != i) CPU_CONTEXT(i, mm) = 0; } - _flush_tlb_range(mm, start, end); + local_flush_tlb_range(mm, start, end); } static void flush_tlb_page_ipi(void *info) { struct flush_tlb_data *fd = (struct flush_tlb_data *)info; - _flush_tlb_page(fd->vma, fd->addr1); + local_flush_tlb_page(fd->vma, fd->addr1); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) @@ -284,6 +296,14 @@ if (smp_processor_id() != i) CPU_CONTEXT(i, vma->vm_mm) = 0; } - _flush_tlb_page(vma, page); + local_flush_tlb_page(vma, page); } +EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); diff -urN linux-2.4.18/arch/mips64/kernel/syscall.c linux-2.4.19-pre5/arch/mips64/kernel/syscall.c --- linux-2.4.18/arch/mips64/kernel/syscall.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/syscall.c Sat Mar 30 22:55:27 2002 @@ -55,7 +55,11 @@ unsigned long flags, unsigned long fd, off_t offset) { struct file * file = NULL; - unsigned long error = -EFAULT; + unsigned long error; + + error = -EINVAL; + if (offset & ~PAGE_MASK) + goto out; if (!(flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -70,8 +74,8 @@ up_write(¤t->mm->mmap_sem); if (file) fput(file); -out: +out: return error; } diff -urN linux-2.4.18/arch/mips64/kernel/time.c linux-2.4.19-pre5/arch/mips64/kernel/time.c --- linux-2.4.18/arch/mips64/kernel/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/kernel/time.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,508 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * Common time service routines for MIPS machines. See + * Documents/MIPS/README.txt. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) +#define USECS_PER_JIFFY_FRAC ((u32)((1000000ULL << 32) / HZ)) + +/* + * forward reference + */ +extern rwlock_t xtime_lock; +extern volatile unsigned long wall_jiffies; + +/* + * By default we provide the null RTC ops + */ +static unsigned long null_rtc_get_time(void) +{ + return mktime(2000, 1, 1, 0, 0, 0); +} + +static int null_rtc_set_time(unsigned long sec) +{ + return 0; +} + +unsigned long (*rtc_get_time)(void) = null_rtc_get_time; +int (*rtc_set_time)(unsigned long) = null_rtc_set_time; + + +/* + * timeofday services, for syscalls. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +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 -= do_gettimeoffset(); + + if (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); +} + + +/* + * Gettimeoffset routines. These routines returns the time duration + * since last timer interrupt in usecs. + * + * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset. + * Otherwise use calibrate_gettimeoffset() + * + * If the CPU does not have counter register all, you can either supply + * your own gettimeoffset() routine, or use null_gettimeoffset() routines, + * which gives the same resolution as HZ. + */ + + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* usecs per counter cycle, shifted to left by 32 bits */ +static unsigned int sll32_usecs_per_cycle=0; + +/* how many counter cycles in a jiffy */ +static unsigned long cycles_per_jiffy=0; + +/* Cycle counter value at the previous timer interrupt.. */ +static unsigned int timerhi, timerlo; + +/* last time when xtime and rtc are sync'ed up */ +static long last_rtc_update; + +/* the function pointer to one of the gettimeoffset funcs*/ +unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset; + +unsigned long null_gettimeoffset(void) +{ + return 0; +} + +unsigned long fixed_rate_gettimeoffset(void) +{ + u32 count; + unsigned long res; + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (sll32_usecs_per_cycle)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +/* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ +static unsigned long cached_quotient; + +/* Last jiffy when calibrate_divXX_gettimeoffset() was called. */ +static unsigned long last_jiffies = 0; + + +/* + * This is copied from dec/time.c:do_ioasic_gettimeoffset() by Mercij. + */ +unsigned long calibrate_div32_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + unsigned long quotient; + + tmp = jiffies; + + quotient = cached_quotient; + + if (last_jiffies != tmp) { + last_jiffies = tmp; + if (last_jiffies != 0) { + unsigned long r0; + do_div64_32(r0, timerhi, timerlo, tmp); + do_div64_32(quotient, USECS_PER_JIFFY, + USECS_PER_JIFFY_FRAC, r0); + cached_quotient = quotient; + } + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu %2,%3" + : "=l" (tmp), "=h" (res) + : "r" (count), "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY - 1; + + return res; +} + +unsigned long calibrate_div64_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + unsigned long quotient; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY)); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + + +/* + * high-level timer interrupt service routines. This function + * is set as irqaction->handler and is invoked through do_IRQ. + */ +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (mips_cpu.options & MIPS_CPU_COUNTER) { + unsigned int count; + + /* + * The cycle counter is only 32 bit which is good for about + * a minute at current count rates of upto 150MHz or so. + */ + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + + /* + * set up for next timer interrupt - no harm if the machine + * is using another timer interrupt source. + * Note that writing to COMPARE register clears the interrupt + */ + write_32bit_cp0_register (CP0_COMPARE, + count + cycles_per_jiffy); + + } + + if(!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long pc = regs->cp0_epc; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Dont ignore out-of-bounds pc values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len-1) + pc = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } + } + + /* + * call the generic timer interrupt handling + */ + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be + * called as close as possible to 500 ms before the new second starts. + */ + read_lock (&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && + xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + if (rtc_set_time(xtime.tv_sec) == 0) { + last_rtc_update = xtime.tv_sec; + } else { + last_rtc_update = xtime.tv_sec - 600; + /* do it again in 60 s */ + } + } + read_unlock (&xtime_lock); + + /* + * If jiffies has overflowed in this timer_interrupt we must + * update the timer[hi]/[lo] to make fast gettimeoffset funcs + * quotient calc still valid. -arca + */ + if (!jiffies) { + timerhi = timerlo = 0; + } +} + +asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + /* we keep interrupt disabled all the time */ + timer_interrupt(irq, NULL, regs); + + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); +} + + +/* + * time_init() - it does the following things. + * + * 1) board_time_init() - + * a) (optional) set up RTC routines, + * b) (optional) calibrate and set the mips_counter_frequency + * (only needed if you intended to use fixed_rate_gettimeoffset + * or use cpu counter as timer interrupt source) + * 2) setup xtime based on rtc_get_time(). + * 3) choose a appropriate gettimeoffset routine. + * 4) calculate a couple of cached variables for later usage + * 5) board_timer_setup() - + * a) (optional) over-write any choices made above by time_init(). + * b) machine specific code should setup the timer irqaction. + * c) enable the timer interrupt + */ + +void (*board_time_init)(void) = NULL; +void (*board_timer_setup)(struct irqaction *irq) = NULL; + +unsigned int mips_counter_frequency = 0; + +static struct irqaction timer_irqaction = { + timer_interrupt, + SA_INTERRUPT, + 0, + "timer", + NULL, + NULL}; + +void __init time_init(void) +{ + if (board_time_init) + board_time_init(); + + xtime.tv_sec = rtc_get_time(); + xtime.tv_usec = 0; + + /* choose appropriate gettimeoffset routine */ + if (!(mips_cpu.options & MIPS_CPU_COUNTER)) { + /* no cpu counter - sorry */ + do_gettimeoffset = null_gettimeoffset; + } else if (mips_counter_frequency != 0) { + /* we have cpu counter and know counter frequency! */ + do_gettimeoffset = fixed_rate_gettimeoffset; + } else if ((mips_cpu.isa_level == MIPS_CPU_ISA_M32) || + (mips_cpu.isa_level == MIPS_CPU_ISA_I) || + (mips_cpu.isa_level == MIPS_CPU_ISA_II) ) { + /* we need to calibrate the counter but we don't have + * 64-bit division. */ + do_gettimeoffset = calibrate_div32_gettimeoffset; + } else { + /* we need to calibrate the counter but we *do* have + * 64-bit division. */ + do_gettimeoffset = calibrate_div64_gettimeoffset; + } + + /* caclulate cache parameters */ + if (mips_counter_frequency) { + cycles_per_jiffy = mips_counter_frequency / HZ; + + /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */ + /* any better way to do this? */ + sll32_usecs_per_cycle = mips_counter_frequency / 100000; + sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle; + sll32_usecs_per_cycle *= 10; + } + + /* + * Call board specific timer interrupt setup. + * + * this pointer must be setup in machine setup routine. + * + * Even if the machine choose to use low-level timer interrupt, + * it still needs to setup the timer_irqaction. + * In that case, it might be better to set timer_irqaction.handler + * to be NULL function so that we are sure the high-level code + * is not invoked accidentally. + */ + board_timer_setup(&timer_irqaction); +} + +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +void to_tm(unsigned long tim, struct rtc_time * tm) +{ + long hms, day, gday; + int i; + + gday = day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i-1; /* tm_mon starts from 0 to 11 */ + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */ +} diff -urN linux-2.4.18/arch/mips64/kernel/traps.c linux-2.4.19-pre5/arch/mips64/kernel/traps.c --- linux-2.4.18/arch/mips64/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/traps.c Sat Mar 30 22:55:27 2002 @@ -11,21 +11,25 @@ #include #include #include +#include #include #include #include #include +#include #include -#include +#include +#include #include #include -#include +#include #include #include #include #include #include +#include extern asmlinkage void __xtlb_mod(void); extern asmlinkage void __xtlb_tlbl(void); @@ -42,14 +46,11 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); -static char *cpu_names[] = CPU_NAMES; - char watch_available = 0; char dedicated_iv_available = 0; -char vce_available = 0; -char mips4_available = 0; int kstack_depth_to_print = 24; @@ -143,6 +144,12 @@ } } +void show_trace_task(struct task_struct *tsk) +{ + show_trace((unsigned long *)tsk->thread.reg29); +} + + void show_code(unsigned int *pc) { long i; @@ -159,16 +166,60 @@ } } -spinlock_t die_lock; +void show_regs(struct pt_regs *regs) +{ + printk("Cpu %d\n", smp_processor_id()); + /* Saved main processor registers. */ + printk("$0 : %016lx %016lx %016lx %016lx\n", + 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); + printk("$4 : %016lx %016lx %016lx %016lx\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %016lx %016lx %016lx %016lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + printk("$12 : %016lx %016lx %016lx %016lx\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16 : %016lx %016lx %016lx %016lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + printk("$20 : %016lx %016lx %016lx %016lx\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24 : %016lx %016lx\n", + regs->regs[24], regs->regs[25]); + printk("$28 : %016lx %016lx %016lx %016lx\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + printk("Hi : %016lx\n", regs->hi); + printk("Lo : %016lx\n", regs->lo); + + /* Saved cp0 registers. */ + printk("epc : %016lx %s\nbadvaddr: %016lx\n", + regs->cp0_epc, print_tainted(), regs->cp0_badvaddr); + printk("Status : %08x [ ", (unsigned int) regs->cp0_status); + if (regs->cp0_status & ST0_KX) printk("KX "); + if (regs->cp0_status & ST0_SX) printk("SX "); + if (regs->cp0_status & ST0_UX) printk("UX "); + switch (regs->cp0_status & ST0_KSU) { + case KSU_USER: printk("USER "); break; + case KSU_SUPERVISOR: printk("SUPERVISOR "); break; + case KSU_KERNEL: printk("KERNEL "); break; + default: printk("BAD_MODE "); break; + } + if (regs->cp0_status & ST0_ERL) printk("ERL "); + if (regs->cp0_status & ST0_EXL) printk("EXL "); + if (regs->cp0_status & ST0_IE) printk("IE "); + printk("]\n"); -void die(const char * str, struct pt_regs * regs, unsigned long err) + printk("Cause : %08x\n", (unsigned int) regs->cp0_cause); +} + +static spinlock_t die_lock; + +void die(const char * str, struct pt_regs * regs) { if (user_mode(regs)) /* Just return if in user mode. */ return; console_verbose(); spin_lock_irq(&die_lock); - printk("%s: %04lx\n", str, err & 0xffff); + printk("%s\n", str); show_regs(regs); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long) current); @@ -180,10 +231,100 @@ do_exit(SIGSEGV); } -void die_if_kernel(const char * str, struct pt_regs * regs, unsigned long err) +void die_if_kernel(const char * str, struct pt_regs * regs) { if (!user_mode(regs)) - die(str, regs, err); + die(str, regs); +} + +extern const struct exception_table_entry __start___dbe_table[]; +extern const struct exception_table_entry __stop___dbe_table[]; + +void __declare_dbe_table(void) +{ + __asm__ __volatile__( + ".section\t__dbe_table,\"a\"\n\t" + ".previous" + ); +} + +static inline unsigned long +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + const struct exception_table_entry *mid; + long diff; + + while (first < last) { + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff < 0) + first = mid + 1; + else + last = mid; + } + return (first == last && first->insn == value) ? first->nextinsn : 0; +} + +extern spinlock_t modlist_lock; + +unsigned long search_dbe_table(unsigned long addr) +{ + unsigned long ret = 0; + +#ifndef CONFIG_MODULES + /* There is only the kernel to search. */ + ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr); + return ret; +#else + unsigned long flags; + + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + struct archdata *ap; + + spin_lock_irqsave(&modlist_lock, flags); + for (mp = module_list; mp != NULL; mp = mp->next) { + if (!mod_member_present(mp, archdata_end) || + !mod_archdata_member_present(mp, struct archdata, + dbe_table_end)) + continue; + ap = (struct archdata *)(mp->archdata_start); + + if (ap->dbe_table_start == NULL || + !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING))) + continue; + ret = search_one_table(ap->dbe_table_start, + ap->dbe_table_end - 1, addr); + if (ret) + break; + } + spin_unlock_irqrestore(&modlist_lock, flags); + return ret; +#endif +} + +/* Default data and instruction bus error handlers. */ +void do_ibe(struct pt_regs *regs) +{ + die("Got ibe\n", regs); +} + +void do_dbe(struct pt_regs *regs) +{ + unsigned long fixup; + + fixup = search_dbe_table(regs->cp0_epc); + if (fixup) { + long new_epc; + + new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); + regs->cp0_epc = new_epc; + return; + } + + die("Got dbe\n", regs); } void do_ov(struct pt_regs *regs) @@ -291,7 +432,7 @@ info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)compute_return_epc(regs); + info.si_addr = (void *)regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -333,7 +474,7 @@ info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)compute_return_epc(regs); + info.si_addr = (void *)regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -347,11 +488,9 @@ void do_ri(struct pt_regs *regs) { - printk("Cpu%d[%s:%d] Illegal instruction at %08lx ra=%08lx\n", - smp_processor_id(), current->comm, current->pid, regs->cp0_epc, - regs->regs[31]); if (compute_return_epc(regs)) return; + force_sig(SIGILL, current); } @@ -364,7 +503,16 @@ goto bad_cid; regs->cp0_status |= ST0_CU1; -#ifndef CONFIG_SMP + +#ifdef CONFIG_SMP + if (current->used_math) { + lazy_fpu_switch(0, current); + } else { + init_fpu(); + current->used_math = 1; + } + current->flags |= PF_USEDFPU; +#else if (last_task_used_math == current) return; @@ -376,18 +524,11 @@ current->used_math = 1; } last_task_used_math = current; -#else - if (current->used_math) { - lazy_fpu_switch(0, current); - } else { - init_fpu(); - current->used_math = 1; - } - current->flags |= PF_USEDFPU; #endif return; bad_cid: + compute_return_epc(regs); force_sig(SIGILL, current); } @@ -401,6 +542,13 @@ panic("Caught WATCH exception - probably caused by stack overflow."); } +asmlinkage void do_mcheck(struct pt_regs *regs) +{ + show_regs(regs); + panic("Caught Machine Check exception - probably caused by multiple " + "matching entries in the TLB."); +} + void do_reserved(struct pt_regs *regs) { /* @@ -430,23 +578,6 @@ } } -/* - * Some MIPS CPUs have a dedicated interrupt vector which reduces the - * interrupt processing overhead. Use it where available. - * FIXME: more CPUs than just the Nevada have this feature. - */ -static inline void setup_dedicated_int(void) -{ - extern void except_vec4(void); - - switch(mips_cputype) { - case CPU_NEVADA: - memcpy((void *)(KSEG0 + 0x200), except_vec4, 8); - set_cp0_cause(CAUSEF_IV, CAUSEF_IV); - dedicated_iv_available = 1; - } -} - unsigned long exception_handlers[32]; /* @@ -458,48 +589,48 @@ { unsigned long handler = (unsigned long) addr; exception_handlers[n] = handler; - if (n == 0 && dedicated_iv_available) { + + if (n == 0 && mips_cpu.options & MIPS_CPU_DIVEC) { *(volatile u32 *)(KSEG0+0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); flush_icache_range(KSEG0+0x200, KSEG0 + 0x204); } } -static inline void mips4_setup(void) +void __init per_cpu_trap_init(void) { - switch (mips_cputype) { - case CPU_R5000: - case CPU_R5000A: - case CPU_NEVADA: - case CPU_R8000: - case CPU_R10000: - mips4_available = 1; - set_cp0_status(ST0_XX, ST0_XX); - } -} + unsigned int cpu = smp_processor_id(); -static inline void go_64(void) -{ - unsigned int bits; + /* Some firmware leaves the BEV flag set, clear it. */ + clear_cp0_status(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV); + set_cp0_status(ST0_CU0|ST0_FR|ST0_KX|ST0_SX|ST0_UX); + + /* + * Some MIPS CPUs have a dedicated interrupt vector which reduces the + * interrupt processing overhead. Use it where available. + */ + if (mips_cpu.options & MIPS_CPU_DIVEC) + set_cp0_cause(CAUSEF_IV); - bits = ST0_KX|ST0_SX|ST0_UX; - set_cp0_status(bits, bits); - printk("Entering 64-bit mode.\n"); + cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; + set_context(cpu << 23); + set_wired(0); } void __init trap_init(void) { extern char except_vec0; extern char except_vec1_r10k; - extern char except_vec2_generic; + extern char except_vec2_generic, except_vec2_sb1; extern char except_vec3_generic, except_vec3_r4000; + extern char except_vec4; extern void bus_error_init(void); unsigned long i; + int dummy; - /* Some firmware leaves the BEV flag set, clear it. */ - set_cp0_status(ST0_BEV, 0); + per_cpu_trap_init(); - /* Copy the generic exception handler code to it's final destination. */ + /* Copy the generic exception handlers to their final destination. */ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80); @@ -513,30 +644,37 @@ * Only some CPUs have the watch exceptions or a dedicated * interrupt vector. */ - watch_init(mips_cputype); - setup_dedicated_int(); - mips4_setup(); - go_64(); /* In memoriam C128 ;-) */ + watch_init(mips_cpu.cputype); + + /* + * Some MIPS CPUs have a dedicated interrupt vector which reduces the + * interrupt processing overhead. Use it where available. + */ + memcpy((void *)(KSEG0 + 0x200), &except_vec4, 8); + + if (mips_cpu.options & MIPS_CPU_MCHECK) + set_except_vector(24, handle_mcheck); /* * Handling the following exceptions depends mostly of the cpu type */ - switch(mips_cputype) { - case CPU_R10000: - /* - * The R10000 is in most aspects similar to the R4400. It - * should get some special optimizations. - */ - write_32bit_cp0_register(CP0_FRAMEMASK, 0); - set_cp0_status(ST0_XX, ST0_XX); - goto r4k; + switch(mips_cpu.cputype) { + case CPU_SB1: +#ifdef CONFIG_SB1_CACHE_ERROR + /* Special cache error handler for SB1 */ + memcpy((void *)(KSEG0 + 0x100), &except_vec2_sb1, 0x80); + memcpy((void *)(KSEG1 + 0x100), &except_vec2_sb1, 0x80); +#endif + /* Enable timer interrupt and scd mapped interrupt */ + clear_cp0_status(0xf000); + set_cp0_status(0xc00); + goto nocache; + case CPU_R10000: case CPU_R4000MC: case CPU_R4400MC: case CPU_R4000SC: case CPU_R4400SC: - vce_available = 1; - /* Fall through ... */ case CPU_R4000PC: case CPU_R4400PC: case CPU_R4200: @@ -544,20 +682,20 @@ case CPU_R4600: case CPU_R5000: case CPU_NEVADA: -r4k: + /* Cache error vector */ + memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80); + +nocache: /* Debug TLB refill handler. */ memcpy((void *)KSEG0, &except_vec0, 0x80); memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80); - /* Cache error vector */ - memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80); - - if (vce_available) { + if (mips_cpu.options & MIPS_CPU_VCE) { memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, - 0x180); + 0x80); } else { memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, - 0x100); + 0x80); } set_except_vector(1, __xtlb_mod); @@ -566,7 +704,19 @@ set_except_vector(4, handle_adel); set_except_vector(5, handle_ades); - /* DBE / IBE exception handler are system specific. */ + set_except_vector(6, handle_ibe); + set_except_vector(7, handle_dbe); + + /* + * If nothing uses the DBE protection mechanism this is + * necessary to get the kernel to link. + */ + get_dbe(dummy, (int *)KSEG0); + + /* + * DBE / IBE handlers may be overridden by system specific + * handlers. + */ bus_error_init(); set_except_vector(8, handle_sys); @@ -579,7 +729,7 @@ break; case CPU_R8000: - panic("unsupported CPU type %s.\n", cpu_names[mips_cputype]); + panic("R8000 is unsupported"); break; case CPU_UNKNOWN: @@ -587,6 +737,9 @@ panic("Unknown CPU type"); } flush_icache_range(KSEG0, KSEG0 + 0x200); + + if (mips_cpu.isa_level == MIPS_CPU_ISA_IV) + set_cp0_status(ST0_XX); atomic_inc(&init_mm.mm_count); /* XXX UP? */ current->active_mm = &init_mm; diff -urN linux-2.4.18/arch/mips64/kernel/unaligned.c linux-2.4.19-pre5/arch/mips64/kernel/unaligned.c --- linux-2.4.18/arch/mips64/kernel/unaligned.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/kernel/unaligned.c Sat Mar 30 22:55:27 2002 @@ -96,10 +96,8 @@ if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \ goto sigbus; -static inline void -emulate_load_store_insn(struct pt_regs *regs, - unsigned long addr, - unsigned long pc) +static inline int emulate_load_store_insn(struct pt_regs *regs, + unsigned long addr, unsigned long pc) { union mips_instruction insn; unsigned long value, fixup; @@ -163,10 +161,9 @@ STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) - :"r" (addr), "i" (&&fault) - :"$1"); + :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; - return; + return 0; case lw_op: check_axs(pc, addr, 4); @@ -186,7 +183,7 @@ :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; - return; + return 0; case lhu_op: check_axs(pc, addr, 2); @@ -208,10 +205,9 @@ STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) - :"r" (addr), "i" (&&fault) - :"$1"); + :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; - return; + return 0; case lwu_op: check_axs(pc, addr, 4); @@ -232,7 +228,7 @@ :"r" (addr), "i" (&&fault)); value &= 0xffffffff; regs->regs[insn.i_format.rt] = value; - return; + return 0; case ld_op: check_axs(pc, addr, 8); @@ -254,7 +250,7 @@ :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; - return; + return 0; case sh_op: check_axs(pc, addr, 2); @@ -279,9 +275,8 @@ STR(PTR)"\t2b,%2\n\t" ".previous" : /* no outputs */ - :"r" (value), "r" (addr), "i" (&&fault) - :"$1"); - return; + :"r" (value), "r" (addr), "i" (&&fault)); + return 0; case sw_op: check_axs(pc, addr, 4); @@ -301,7 +296,7 @@ ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); - return; + return 0; case sd_op: check_axs(pc, addr, 8); @@ -323,7 +318,7 @@ ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); - return; + return 0; case lwc1_op: case ldc1_op: @@ -352,7 +347,7 @@ */ goto sigill; } - return; + return 0; fault: /* Did we have an exception handler installed? */ @@ -363,20 +358,20 @@ printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)\n", current->comm, regs->cp0_epc, new_epc); regs->cp0_epc = new_epc; - return; + return 1; } die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); - return; + return 0; sigbus: die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGBUS, current, 1); - return; + return 0; sigill: die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs); send_sig(SIGILL, current, 1); - return; + return 0; } #ifdef CONFIG_PROC_FS @@ -386,6 +381,10 @@ asmlinkage void do_ade(struct pt_regs *regs) { unsigned long pc; +#if 0 + printk("ade: Cpu%d[%s:%d:%0lx:%0lx]\n", smp_processor_id(), + current->comm, current->pid, regs->cp0_badvaddr, regs->cp0_epc); +#endif /* * Did we catch a fault trying to load an instruction? @@ -396,12 +395,16 @@ goto sigbus; pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); - if (compute_return_epc(regs)) - return; if ((current->thread.mflags & MF_FIXADE) == 0) goto sigbus; - emulate_load_store_insn(regs, regs->cp0_badvaddr, pc); + /* + * Do branch emulation only if we didn't forward the exception. + * This is all so but ugly ... + */ + if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc)) + compute_return_epc(regs); + #ifdef CONFIG_PROC_FS unaligned_instructions++; #endif @@ -409,6 +412,6 @@ return; sigbus: - die_if_kernel ("Kernel unaligned instruction access", regs); + die_if_kernel("Kernel unaligned instruction access", regs); force_sig(SIGBUS, current); } diff -urN linux-2.4.18/arch/mips64/lib/Makefile linux-2.4.19-pre5/arch/mips64/lib/Makefile --- linux-2.4.18/arch/mips64/lib/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/lib/Makefile Sat Mar 30 22:55:27 2002 @@ -9,9 +9,12 @@ L_TARGET = lib.a -obj-y += csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ - floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ +obj-y += csum_partial.o csum_partial_copy.o dump_tlb.o rtc-std.o \ rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \ strnlen_user.o watch.o + +obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +obj-$(CONFIG_IDE) += ide-std.o ide-no.o +obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/lib/dump_tlb.c linux-2.4.19-pre5/arch/mips64/lib/dump_tlb.c --- linux-2.4.18/arch/mips64/lib/dump_tlb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/lib/dump_tlb.c Sat Mar 30 22:55:27 2002 @@ -11,14 +11,27 @@ #include #include +#include #include #include #include -#define mips_tlb_entries 64 +static inline const char *msk2str(unsigned int mask) +{ + switch (mask) { + case PM_4K: return "4kb"; + case PM_16K: return "16kb"; + case PM_64K: return "64kb"; + case PM_256K: return "256kb"; + case PM_1M: return "1Mb"; + case PM_4M: return "4Mb"; + case PM_16M: return "16Mb"; + case PM_64M: return "64Mb"; + case PM_256M: return "256Mb"; + } +} -void -dump_tlb(int first, int last) +void dump_tlb(int first, int last) { unsigned long s_entryhi, entryhi, entrylo0, entrylo1, asid; unsigned int s_index, pagemask, c0, c1, i; @@ -46,25 +59,24 @@ /* * Only print entries in use */ - printk("Index: %2d pgmask=%08x ", i, pagemask); + printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); c0 = (entrylo0 >> 3) & 7; c1 = (entrylo1 >> 3) & 7; - printk("va=%08lx asid=%02lx" - " [pa=%06lx c=%d d=%d v=%d g=%ld]" - " [pa=%06lx c=%d d=%d v=%d g=%ld]\n", + printk("va=%011lx asid=%02lx\n", (entryhi & ~0x1fffUL), - entryhi & 0xff, - entrylo0 & PAGE_MASK, c0, + entryhi & 0xff); + printk("\t[pa=%011lx c=%d d=%d v=%d g=%ld] ", + (entrylo0 << 6) & PAGE_MASK, c0, (entrylo0 & 4) ? 1 : 0, (entrylo0 & 2) ? 1 : 0, - (entrylo0 & 1), - entrylo1 & PAGE_MASK, c1, + (entrylo0 & 1)); + printk("[pa=%011lx c=%d d=%d v=%d g=%ld]\n", + (entrylo1 << 6) & PAGE_MASK, c1, (entrylo1 & 4) ? 1 : 0, (entrylo1 & 2) ? 1 : 0, (entrylo1 & 1)); - } } printk("\n"); @@ -73,14 +85,12 @@ set_index(s_index); } -void -dump_tlb_all(void) +void dump_tlb_all(void) { - dump_tlb(0, mips_tlb_entries - 1); + dump_tlb(0, mips_cpu.tlbsize - 1); } -void -dump_tlb_wired(void) +void dump_tlb_wired(void) { int wired; @@ -95,8 +105,7 @@ "nop;nop;nop;nop;nop;nop;nop\n\t" \ ".set\treorder"); -void -dump_tlb_addr(unsigned long addr) +void dump_tlb_addr(unsigned long addr) { unsigned int flags, oldpid; int index; @@ -121,14 +130,12 @@ dump_tlb(index, index); } -void -dump_tlb_nonwired(void) +void dump_tlb_nonwired(void) { - dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_tlb_entries - 1); + dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_cpu.tlbsize - 1); } -void -dump_list_process(struct task_struct *t, void *address) +void dump_list_process(struct task_struct *t, void *address) { pgd_t *page_dir, *pgd; pmd_t *pmd; diff -urN linux-2.4.18/arch/mips64/lib/floppy-std.c linux-2.4.19-pre5/arch/mips64/lib/floppy-std.c --- linux-2.4.18/arch/mips64/lib/floppy-std.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/lib/floppy-std.c Sat Mar 30 22:55:27 2002 @@ -100,23 +100,9 @@ return 0x3f0; } -/* Pure 2^n version of get_order */ -static int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long std_fd_dma_mem_alloc(unsigned long size) { - int order = __get_order(size); + int order = get_order(size); unsigned long mem; mem = __get_dma_pages(GFP_KERNEL,order); @@ -126,7 +112,7 @@ static void std_fd_dma_mem_free(unsigned long addr, unsigned long size) { - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } static unsigned long std_fd_drive_type(unsigned long n) diff -urN linux-2.4.18/arch/mips64/math-emu/cp1emu.c linux-2.4.19-pre5/arch/mips64/math-emu/cp1emu.c --- linux-2.4.18/arch/mips64/math-emu/cp1emu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/math-emu/cp1emu.c Sat Mar 30 22:55:39 2002 @@ -29,7 +29,7 @@ * Notes: * 1) the IEEE754 library (-le) performs the actual arithmetic; * 2) if you know that you won't have an fpu, then you'll get much - * better performance by compiling with -msoft-float! */ + * better performance by compiling with -msoft-float! * * Nov 7, 2000 * Massive changes to integrate with Linux kernel. @@ -1780,7 +1780,7 @@ * i.e. denormalised results, underflow, overflow etc, which * must be emulated in s/w. */ -#ifdef 1 +#if 1 /* r4000 or above use dedicate exception */ xcption(XCPTFPE, cop1Patcher); #else diff -urN linux-2.4.18/arch/mips64/mips-boards/atlas/Makefile linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/Makefile --- linux-2.4.18/arch/mips64/mips-boards/atlas/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/Makefile Thu Jan 1 01:00:00 1970 @@ -1,42 +0,0 @@ -# -# Carsten Langgaard, carstenl@mips.com -# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. -# -# ######################################################################## -# -# This program is free software; you can distribute it and/or modify it -# under the terms of the GNU General Public License (Version 2) as -# published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# ####################################################################### -# -# Makefile for the MIPS Atlas specific kernel interface routines -# under Linux. -# -# 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: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -all: atlas.o - -O_TARGET := atlas.o - -obj-y := atlas_int.o atlas_rtc.o atlas_setup.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_int.c linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_int.c --- linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_int.c Thu Jan 1 01:00:00 1970 @@ -1,249 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Routines for generic manipulation of the interrupts found on the MIPS - * Atlas board. - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#ifdef CONFIG_REMOTE_DEBUG -#include -#endif - -struct atlas_ictrl_regs *atlas_hw0_icregs - = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE; - -extern asmlinkage void mipsIRQ(void); -extern void do_IRQ(int irq, struct pt_regs *regs); - -unsigned long spurious_count = 0; -irq_desc_t irq_desc[NR_IRQS]; - -#if 0 -#define DEBUG_INT(x...) printk(x) -#else -#define DEBUG_INT(x...) -#endif - -void disable_atlas_irq(unsigned int irq_nr) -{ - atlas_hw0_icregs->intrsten = (1 << irq_nr); -} - -void enable_atlas_irq(unsigned int irq_nr) -{ - atlas_hw0_icregs->intseten = (1 << irq_nr); -} - -static unsigned int startup_atlas_irq(unsigned int irq) -{ - enable_atlas_irq(irq); - return 0; /* never anything pending */ -} - -#define shutdown_atlas_irq disable_atlas_irq - -#define mask_and_ack_atlas_irq disable_atlas_irq - -static void end_atlas_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_atlas_irq(irq); -} - -static struct hw_interrupt_type atlas_irq_type = { - "Atlas", - startup_atlas_irq, - shutdown_atlas_irq, - enable_atlas_irq, - disable_atlas_irq, - mask_and_ack_atlas_irq, - end_atlas_irq, - NULL -}; - -int get_irq_list(char *buf) -{ - int i, len = 0; - int num = 0; - struct irqaction *action; - - for (i = 0; i < ATLASINT_END; i++, num++) { - action = irq_desc[i].action; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [hw0]\n"); - } - return len; -} - -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - struct irqaction *action; - - DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); - - if (irq >= ATLASINT_END) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if(!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = 0; - irq_desc[irq].action = action; - enable_atlas_irq(irq); - - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction *action; - - if (irq >= ATLASINT_END) { - printk("Trying to free IRQ%d\n",irq); - return; - } - - action = irq_desc[irq].action; - irq_desc[irq].action = NULL; - disable_atlas_irq(irq); - kfree(action); -} - -static inline int ls1bit32(unsigned int x) -{ - int b = 31, s; - - s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; - s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; - s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; - s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; - s = 1; if (x << 1 == 0) s = 0; b -= s; - - return b; -} - -void atlas_hw0_irqdispatch(struct pt_regs *regs) -{ - struct irqaction *action; - unsigned long int_status; - int irq, cpu = smp_processor_id(); - - int_status = atlas_hw0_icregs->intstatus; - - /* if int_status == 0, then the interrupt has already been cleared */ - if (int_status == 0) - return; - - irq = ls1bit32(int_status); - action = irq_desc[irq].action; - - DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); - - /* if action == NULL, then we don't have a handler for the irq */ - if ( action == NULL ) { - printk("No handler for hw0 irq: %i\n", irq); - spurious_count++; - return; - } - - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); - - return; -} - -unsigned long probe_irq_on (void) -{ - return 0; -} - - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -#ifdef CONFIG_REMOTE_DEBUG -extern void breakpoint(void); -extern int remote_debug; -#endif - -void __init init_IRQ(void) -{ - int i; - - /* - * Mask out all interrupt by writing "1" to all bit position in - * the interrupt reset reg. - */ - atlas_hw0_icregs->intrsten = 0xffffffff; - - /* Now safe to set the exception vector. */ - set_except_vector(0, mipsIRQ); - - for (i = 0; i <= ATLASINT_END; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - irq_desc[i].handler = &atlas_irq_type; - } - -#ifdef CONFIG_REMOTE_DEBUG - if (remote_debug) { - set_debug_traps(); - breakpoint(); - } -#endif -} diff -urN linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_rtc.c linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_rtc.c --- linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_rtc.c Thu Jan 1 01:00:00 1970 @@ -1,58 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * RTC routines for Atlas style attached Dallas chip. - * - */ -#include -#include - - -static unsigned char atlas_rtc_read_data(unsigned long addr) -{ - volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; - volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; - - *rtc_adr_reg = addr; - - return *rtc_dat_reg; -} - -static void atlas_rtc_write_data(unsigned char data, unsigned long addr) -{ - volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG; - volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG; - - *rtc_adr_reg = addr; - *rtc_dat_reg = data; -} - -static int atlas_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops atlas_rtc_ops = { - &atlas_rtc_read_data, - &atlas_rtc_write_data, - &atlas_rtc_bcd_mode -}; - diff -urN linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_setup.c linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_setup.c --- linux-2.4.18/arch/mips64/mips-boards/atlas/atlas_setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/atlas/atlas_setup.c Thu Jan 1 01:00:00 1970 @@ -1,123 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Atlas specific setup, including init of the feature struct. - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) -extern void console_setup(char *, int *); -char serial_console[20]; -#endif - -#ifdef CONFIG_REMOTE_DEBUG -extern void rs_kgdb_hook(int); -extern void saa9730_kgdb_hook(void); -extern void breakpoint(void); -int remote_debug = 0; -#endif - -extern struct rtc_ops atlas_rtc_ops; - -extern void mips_reboot_setup(void); - -void __init atlas_setup(void) -{ -#ifdef CONFIG_REMOTE_DEBUG - int rs_putDebugChar(char); - char rs_getDebugChar(void); - int saa9730_putDebugChar(char); - char saa9730_getDebugChar(void); - extern int (*putDebugChar)(char); - extern char (*getDebugChar)(void); -#endif - char *argptr; - - current_cpu_data.asid_cache = ASID_FIRST_VERSION; - TLBMISS_HANDLER_SETUP(); - - ioport_resource.end = 0x7fffffff; - -#ifdef CONFIG_SERIAL_CONSOLE - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) { - int i = 0; - char *s = prom_getenv("modetty0"); - while(s[i] >= '0' && s[i] <= '9') - i++; - strcpy(serial_console, "ttyS0,"); - strncpy(serial_console + 6, s, i); - prom_printf("Config serial console: %s\n", serial_console); - console_setup(serial_console, NULL); - } -#endif - -#ifdef CONFIG_REMOTE_DEBUG - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { - int line; - argptr += strlen("kgdb=ttyS"); - if (*argptr != '0' && *argptr != '1') - printk("KGDB: Uknown serial line /dev/ttyS%c, " - "falling back to /dev/ttyS1\n", *argptr); - line = *argptr == '0' ? 0 : 1; - printk("KGDB: Using serial line /dev/ttyS%d for session\n", - line ? 1 : 0); - - if(line == 0) { - rs_kgdb_hook(line); - putDebugChar = rs_putDebugChar; - getDebugChar = rs_getDebugChar; - } else { - saa9730_kgdb_hook(); - putDebugChar = saa9730_putDebugChar; - getDebugChar = saa9730_getDebugChar; - } - - prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " - "please connect your debugger\n", line ? 1 : 0); - - remote_debug = 1; - /* Breakpoints and stuff are in atlas_irq_setup() */ - } -#endif - argptr = prom_getcmdline(); - - if ((argptr = strstr(argptr, "nofpu")) != NULL) - mips_cpu.options &= ~MIPS_CPU_FPU; - - rtc_ops = &atlas_rtc_ops; -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/Makefile linux-2.4.19-pre5/arch/mips64/mips-boards/generic/Makefile --- linux-2.4.18/arch/mips64/mips-boards/generic/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/Makefile Thu Jan 1 01:00:00 1970 @@ -1,43 +0,0 @@ -# -# Carsten Langgaard, carstenl@mips.com -# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. -# -# ######################################################################## -# -# This program is free software; you can distribute it and/or modify it -# under the terms of the GNU General Public License (Version 2) as -# published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# ####################################################################### -# -# Makefile for the MIPS boards generic routines under Linux. -# -# 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: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -all: mipsboards.o - -O_TARGET := mipsboards.o - -obj-y := mipsIRQ.o pci.o reset.o display.o init.o \ - memory.o printf.o cmdline.o time.o -obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/cmdline.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/cmdline.c --- linux-2.4.18/arch/mips64/mips-boards/generic/cmdline.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/cmdline.c Thu Jan 1 01:00:00 1970 @@ -1,71 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Kernel command line creation using the prom monitor (YAMON) argc/argv. - * - */ -#include -#include -#include - -#include - -/*#define DEBUG_CMDLINE*/ - -extern int prom_argc; -extern int *_prom_argv; - -/* - * A 32-bit PROM pass arguments and environment as 32-bit pointer. - * This macro take care of sign extension. - */ -#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)])) - -char arcs_cmdline[CL_SIZE]; - -char * __init prom_getcmdline(void) -{ - return &(arcs_cmdline[0]); -} - - -void __init prom_init_cmdline(void) -{ - char *cp; - int actr; - - actr = 1; /* Always ignore argv[0] */ - - cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - strcpy(cp, prom_argv(actr)); - cp += strlen(prom_argv(actr)); - *cp++ = ' '; - actr++; - } - if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ - --cp; - *cp = '\0'; - -#ifdef DEBUG_CMDLINE - prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0])); -#endif -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/display.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/display.c --- linux-2.4.18/arch/mips64/mips-boards/generic/display.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/display.c Thu Jan 1 01:00:00 1970 @@ -1,47 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Display routines for display messages in MIPS boards ascii display. - * - */ - -#include - - -void mips_display_message(const char *str) -{ - volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE; - int i; - - for (i = 0; i <= 14; i=i+2) { - if (*str) - display[i] = *str++; - else - display[i] = ' '; - } -} - -void mips_display_word(unsigned int num) -{ - volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE; - - *display = num; -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/gdb_hook.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/gdb_hook.c --- linux-2.4.18/arch/mips64/mips-boards/generic/gdb_hook.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/gdb_hook.c Thu Jan 1 01:00:00 1970 @@ -1,202 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * This is the interface to the remote debugger stub. - * - */ - -#include -#include - -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in serial.h */ -}; - -static struct async_struct kdb_port_info = {0}; - - -static __inline__ unsigned int serial_in(struct async_struct *info, int offset) -{ - return inb(info->port + offset); -} - -static __inline__ void serial_out(struct async_struct *info, int offset, - int value) -{ - outb(value, info->port+offset); -} - -void rs_kgdb_hook(int tty_no) { - int t; - struct serial_state *ser = &rs_table[tty_no]; - - kdb_port_info.state = ser; - kdb_port_info.magic = SERIAL_MAGIC; - kdb_port_info.port = ser->port; - kdb_port_info.flags = ser->flags; - - /* - * Clear all interrupts - */ - serial_in(&kdb_port_info, UART_LSR); - serial_in(&kdb_port_info, UART_RX); - serial_in(&kdb_port_info, UART_IIR); - serial_in(&kdb_port_info, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - if (kdb_port_info.flags & ASYNC_FOURPORT) { - kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; - t = UART_MCR_DTR | UART_MCR_OUT1; - } else { - kdb_port_info.MCR - = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; - t = UART_MCR_DTR | UART_MCR_RTS; - } - - kdb_port_info.MCR = t; /* no interrupts, please */ - serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); - - /* - * and set the speed of the serial port - * (currently hardwired to 9600 8N1 - */ - - /* baud rate is fixed to 9600 (is this sufficient?)*/ - t = kdb_port_info.state->baud_base / 9600; - /* set DLAB */ - serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); - serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ - serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ - /* reset DLAB */ - serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); -} - -int rs_putDebugChar(char c) -{ - - if (!kdb_port_info.state) { /* need to init device first */ - return 0; - } - - while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) - ; - - serial_out(&kdb_port_info, UART_TX, c); - - return 1; -} - -char rs_getDebugChar(void) -{ - if (!kdb_port_info.state) { /* need to init device first */ - return 0; - } - - while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) - ; - - return(serial_in(&kdb_port_info, UART_RX)); -} - - -#ifdef CONFIG_MIPS_ATLAS - -#include -#include - -#define INB(a) inb((unsigned long)a) -#define OUTB(x,a) outb(x,(unsigned long)a) - -/* - * This is the interface to the remote debugger stub - * if the Philips part is used for the debug port, - * called from the platform setup code. - * - * PCI init will not have been done yet, we make a - * universal assumption about the way the bootloader (YAMON) - * have located and set up the chip. - */ -static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR); - -static int saa9730_kgdb_active = 0; - -void saa9730_kgdb_hook(void) -{ - volatile unsigned char t; - - /* - * Clear all interrupts - */ - t = INB(&kgdb_uart->Lsr); - t += INB(&kgdb_uart->Msr); - t += INB(&kgdb_uart->Thr_Rbr); - t += INB(&kgdb_uart->Iir_Fcr); - - /* - * Now, initialize the UART - */ - /* 8 data bits, one stop bit, no parity */ - OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr); - - /* baud rate is fixed to 9600 (is this sufficient?)*/ - OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */ - OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */ - - /* Set RTS/DTR active */ - OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr); - saa9730_kgdb_active = 1; -} - -int saa9730_putDebugChar(char c) -{ - - if (!saa9730_kgdb_active) { /* need to init device first */ - return 0; - } - - while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE)) - ; - OUTB(c, &kgdb_uart->Thr_Rbr); - - return 1; -} - -char saa9730_getDebugChar(void) -{ - char c; - - if (!saa9730_kgdb_active) { /* need to init device first */ - return 0; - } - while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR)) - ; - - c = INB(&kgdb_uart->Thr_Rbr); - return(c); -} - -#endif diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/init.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/init.c --- linux-2.4.18/arch/mips64/mips-boards/generic/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/init.c Thu Jan 1 01:00:00 1970 @@ -1,152 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * PROM library initialisation code. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Environment variable */ -typedef struct -{ - char *name; - char *val; -}t_env_var; - -int prom_argc; -int *_prom_argv, *_prom_envp; - -/* - * A 32-bit PROM pass arguments and environment as 32-bit pointer. - * This macro take care of sign extension. - */ -#define prom_envp(index) ((char *)(((int *)(int)_prom_envp)[(index)])) - -int init_debug = 0; - -char *prom_getenv(char *envname) -{ - /* - * Return a pointer to the given environment variable. - * We're using 64-bit pointers, but all pointers in the PROM - * structures are only 32-bit, so we need some workarounds. - */ - int i, index=0; - - i = strlen(envname); - - while(prom_envp(index)) { - if(strncmp(envname, prom_envp(index), i) == 0) { - return(prom_envp(index+1)); - } - index += 2; - } - - return(NULL); -} - -static inline unsigned char str2hexnum(unsigned char c) -{ - if(c >= '0' && c <= '9') - return c - '0'; - if(c >= 'a' && c <= 'f') - return c - 'a' + 10; - return 0; /* foo */ -} - -static inline void str2eaddr(unsigned char *ea, unsigned char *str) -{ - int i; - - for(i = 0; i < 6; i++) { - unsigned char num; - - if((*str == '.') || (*str == ':')) - str++; - num = str2hexnum(*str++) << 4; - num |= (str2hexnum(*str++)); - ea[i] = num; - } -} - -int get_ethernet_addr(char *ethernet_addr) -{ - char *ethaddr_str; - - ethaddr_str = prom_getenv("ethaddr"); - if (!ethaddr_str) { - printk("ethaddr not set in boot prom\n"); - return -1; - } - str2eaddr(ethernet_addr, ethaddr_str); - - if (init_debug > 1) - { - int i; - printk("get_ethernet_addr: "); - for (i=0; i<5; i++) - printk("%02x:", (unsigned char)*(ethernet_addr+i)); - printk("%02x\n", *(ethernet_addr+i)); - } - - return 0; -} - -int __init prom_init(int argc, char **argv, char **envp) -{ - prom_argc = argc; - _prom_argv = (int *)argv; - _prom_envp = (int *)envp; - - mips_display_message("LINUX"); - - /* - * Setup the North bridge to do Master byte-lane swapping when - * running in bigendian. - */ -#if defined(__MIPSEL__) - GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT | - GT_PCI0_CMD_SBYTESWAP_BIT); -#else - GT_WRITE(GT_PCI0_CMD_OFS, 0); -#endif - -#if defined(CONFIG_MIPS_MALTA) - mips_io_port_base = MALTA_PORT_BASE; -#else - mips_io_port_base = KSEG1; -#endif - - setup_prom_printf(0); - prom_printf("\nLINUX started...\n"); - prom_init_cmdline(); - prom_meminit(); - - return 0; -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/memory.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/memory.c --- linux-2.4.18/arch/mips64/mips-boards/generic/memory.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/memory.c Thu Jan 1 01:00:00 1970 @@ -1,263 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * PROM library functions for acquiring/using memory descriptors given to - * us from the YAMON. - * - */ -#include -#include -#include -#include - -#include -#include - -#include - -/*#define DEBUG*/ - -enum yamon_memtypes { - yamon_dontuse, - yamon_prom, - yamon_free, -}; -struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; - -#define MEMTYPE_DONTUSE 0 -#define MEMTYPE_PROM 1 -#define MEMTYPE_FREE 2 - -#ifdef DEBUG -static char *mtypes[3] = { - "Dont use memory", - "YAMON PROM memory", - "Free memmory", -}; -#endif - -/* References to section boundaries */ -extern char _end; - -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) - -struct prom_pmemblock * __init prom_getmdesc(void) -{ - char *memsize_str; - unsigned int memsize; - - memsize_str = prom_getenv("memsize"); - if (!memsize_str) { - prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); - memsize = 0x02000000; - } else { -#ifdef DEBUG - prom_printf("prom_memsize = %s\n", memsize_str); -#endif - memsize = simple_strtol(memsize_str, NULL, 0); - } - - memset(mdesc, 0, sizeof(mdesc)); - - mdesc[0].type = yamon_dontuse; - mdesc[0].base = 0x00000000; - mdesc[0].size = 0x00001000; - - mdesc[1].type = yamon_prom; - mdesc[1].base = 0x00001000; - mdesc[1].size = 0x000ef000; - -#if (CONFIG_MIPS_MALTA) - /* - * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the - * south bridge and PCI access always forwarded to the ISA Bus and - * BIOSCS# is always generated. - * This mean that this area can't be used as DMA memory for PCI - * devices. - */ - mdesc[2].type = yamon_dontuse; - mdesc[2].base = 0x000f0000; - mdesc[2].size = 0x00010000; -#else - mdesc[2].type = yamon_prom; - mdesc[2].base = 0x000f0000; - mdesc[2].size = 0x00010000; -#endif - - mdesc[3].type = yamon_dontuse; - mdesc[3].base = 0x00100000; - mdesc[3].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[3].base; - - mdesc[4].type = yamon_free; - mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end)); - mdesc[4].size = memsize - mdesc[4].base; - - return &mdesc[0]; -} - -int __init page_is_ram(unsigned long pagenr) -{ - if ((pagenr << PAGE_SHIFT) < mdesc[4].base + mdesc[4].size) - return 1; - - return 0; -} - -static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; - -static int __init prom_memtype_classify (unsigned int type) -{ - switch (type) { - case yamon_free: - return MEMTYPE_FREE; - case yamon_prom: - return MEMTYPE_PROM; - default: - return MEMTYPE_DONTUSE; - } -} - -static inline unsigned long find_max_low_pfn(void) -{ - struct prom_pmemblock *p, *highest; - unsigned long pfn; - - p = pblocks; - highest = 0; - while (p->size != 0) { - if (!highest || p->base > highest->base) - highest = p; - p++; - } - - pfn = (highest->base + highest->size) >> PAGE_SHIFT; -#ifdef DEBUG - prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); -#endif - return pfn; -} - -static inline struct prom_pmemblock *find_largest_memblock(void) -{ - struct prom_pmemblock *p, *largest; - - p = pblocks; - largest = 0; - while (p->size != 0) { - if (!largest || p->size > largest->size) - largest = p; - p++; - } - - return largest; -} - -void __init prom_meminit(void) -{ - struct prom_pmemblock *largest, *p; - unsigned long bootmap_size; - int totram; - int i = 0; - -#ifdef DEBUG - prom_printf("YAMON MEMORY DESCRIPTOR dump:\n"); - p = prom_getmdesc(); - while (p->size) { - prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n", - i, p, p->base, p->size, mtypes[p->type]); - p++; - i++; - } -#endif - totram = 0; - i = 0; - p = prom_getmdesc(); - - while (p->size) { - pblocks[i].type = prom_memtype_classify (p->type); - pblocks[i].base = p->base; - pblocks[i].size = p->size; - switch (pblocks[i].type) { - case MEMTYPE_FREE: - totram += pblocks[i].size; -#ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%d\n", - i, pblocks[i].base, pblocks[i].size); -#endif - i++; - break; - case MEMTYPE_PROM: -#ifdef DEBUG - prom_printf("prom_chunk[%d]: base=%08lx size=%d\n", - i, pblocks[i].base, pblocks[i].size); -#endif - i++; - break; - default: - break; - } - p++; - } - pblocks[i].base = 0xdeadbeef; - pblocks[i].size = 0; /* indicates last elem. of array */ - - max_low_pfn = find_max_low_pfn(); - largest = find_largest_memblock(); - bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); - - for (i = 0; pblocks[i].size; i++) - if (pblocks[i].type == MEMTYPE_FREE) - free_bootmem(pblocks[i].base, pblocks[i].size); - - /* This test is simpleminded. It will fail if the bootmem bitmap - falls into multiple adjacent PROM memory areas. */ - if (bootmap_size > largest->size) { - prom_printf("CRITIAL: overwriting PROM data.\n"); - BUG(); - } - - /* Reserve the memory bootmap itself */ - reserve_bootmem(largest->base, bootmap_size); - printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n", - totram, (totram/1024), (totram/1024/1024)); -} - -void prom_free_prom_memory (void) -{ - struct prom_pmemblock *p; - unsigned long freed = 0; - unsigned long addr; - - for (p = pblocks; p->size != 0; p++) { - if (p->type != MEMTYPE_PROM) - continue; - - addr = p->base; - while (addr < p->base + p->size) { - ClearPageReserved(virt_to_page(__va(addr))); - set_page_count(virt_to_page(__va(addr)), 1); - free_page(__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } - } - printk("Freeing prom memory: %ldkb freed\n", freed >> 10); -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/mipsIRQ.S linux-2.4.19-pre5/arch/mips64/mips-boards/generic/mipsIRQ.S --- linux-2.4.18/arch/mips64/mips-boards/generic/mipsIRQ.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/mipsIRQ.S Thu Jan 1 01:00:00 1970 @@ -1,122 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Interrupt exception dispatch code. - * - */ -#include - -#include -#include -#include -#include - -/* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop and moving across - * all the pending IRQ bits in the cause register is _NOT_ the answer, the - * common case is one pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register IRQ mask, that - * would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in - * between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the MIPS board look basically (barring software - * IRQs which we don't use at all and all external interrupt sources are - * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Combined hardware interrupt (hw0) - * 3 Hardware (ignored) - * 4 Hardware (ignored) - * 5 Hardware (ignored) - * 6 Hardware (ignored) - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Lowest ---- Combined hardware interrupt - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - - .text - .set noreorder - .set noat - .align 5 - NESTED(mipsIRQ, PT_SIZE, sp) - SAVE_ALL - CLI - .set at - - mfc0 s0, CP0_CAUSE # get irq mask - - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt - - /* Wheee, a timer interrupt. */ - move a0, sp - jal mips_timer_interrupt - nop - - j ret_from_irq - nop - -1: - beq a0, zero, 1f - nop - - /* Wheee, combined hardware level zero interrupt. */ -#if defined(CONFIG_MIPS_ATLAS) - jal atlas_hw0_irqdispatch -#elif defined(CONFIG_MIPS_MALTA) - jal malta_hw0_irqdispatch -#else -#error "MIPS board not supported\n" -#endif - move a0, sp # delay slot - - j ret_from_irq - nop # delay slot - -1: - /* - * Here by mistake? This is possible, what can happen is that by the - * time we take the exception the IRQ pin goes low, so just leave if - * this is the case. - */ - move a1,s0 - PRINT("Got interrupt: c0_cause = %08x\n") - mfc0 a1, CP0_EPC - PRINT("c0_epc = %08x\n") - - j ret_from_irq - nop - END(mipsIRQ) diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/pci.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/pci.c --- linux-2.4.18/arch/mips64/mips-boards/generic/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/pci.c Thu Jan 1 01:00:00 1970 @@ -1,337 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * MIPS boards specific PCI support. - * - */ -#include - -#ifdef CONFIG_PCI - -#include -#include -#include -#include - -#include -#include -#ifdef CONFIG_MIPS_MALTA -#include -#endif - -#define PCI_ACCESS_READ 0 -#define PCI_ACCESS_WRITE 1 - -static int -mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev, - unsigned char where, u32 *data) -{ - unsigned char bus = dev->bus->number; - unsigned char dev_fn = dev->devfn; - u32 intr; - - if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0))) - return -1; /* Because of a bug in the galileo (for slot 31). */ - - /* Clear cause register bits */ - GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | - GT_INTRCAUSE_TARABORT0_BIT)); - - /* Setup address */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) | - (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | - ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | - GT_PCI0_CFGADDR_CONFIGEN_BIT); - - if (access_type == PCI_ACCESS_WRITE) { - if (bus == 0 && dev_fn == 0) { - /* - * Galileo is acting differently than other devices. - */ - GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); - } else { - GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data); - } - } else { - if (bus == 0 && dev_fn == 0) { - /* - * Galileo is acting differently than other devices. - */ - GT_READ(GT_PCI0_CFGDATA_OFS, *data); - } else { - GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data); - } - } - - /* Check for master or target abort */ - GT_READ(GT_INTRCAUSE_OFS, intr); - - if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) - { - /* Error occured */ - - /* Clear bits */ - GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | - GT_INTRCAUSE_TARABORT0_BIT) ); - - return -1; - } - - return 0; -} - - -/* - * We can't address 8 and 16 bit words directly. Instead we have to - * read/write a 32bit word and mask/modify the data we actually want. - */ -static int -mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val) -{ - u32 data = 0; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xff; - - return PCIBIOS_SUCCESSFUL; -} - - -static int -mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val) -{ - u32 data = 0; - - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = (data >> ((where & 3) << 3)) & 0xffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val) -{ - u32 data = 0; - - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - *val = data; - - return PCIBIOS_SUCCESSFUL; -} - - -static int -mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val) -{ - u32 data = 0; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val) -{ - u32 data = 0; - - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data)) - return -1; - - data = (data & ~(0xffff << ((where & 3) << 3))) | - (val << ((where & 3) << 3)); - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data)) - return -1; - - - return PCIBIOS_SUCCESSFUL; -} - -static int -mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val) -{ - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - - if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val)) - return -1; - - return PCIBIOS_SUCCESSFUL; -} - -struct pci_ops mips_pci_ops = { - mips_pcibios_read_config_byte, - mips_pcibios_read_config_word, - mips_pcibios_read_config_dword, - mips_pcibios_write_config_byte, - mips_pcibios_write_config_word, - mips_pcibios_write_config_dword -}; - -void __init pcibios_init(void) -{ -#ifdef CONFIG_MIPS_MALTA - struct pci_dev *pdev; - unsigned char reg_val; -#endif - - printk("PCI: Probing PCI hardware on host bus 0.\n"); - pci_scan_bus(0, &mips_pci_ops, NULL); - - /* - * Due to a bug in the Galileo system controller, we need to setup - * the PCI BAR for the Galileo internal registers. - * This should be done in the bios/bootprom and will be fixed in - * a later revision of YAMON (the MIPS boards boot prom). - */ - GT_WRITE(GT_PCI0_CFGADDR_OFS, - (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ - (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 device */ - (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */ - ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */ - GT_PCI0_CFGADDR_CONFIGEN_BIT ); - - /* Perform the write */ - GT_WRITE( GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); - -#ifdef CONFIG_MIPS_MALTA - pci_for_each_dev(pdev) { - if ((pdev->vendor == PCI_VENDOR_ID_INTEL) - && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) - && (PCI_SLOT(pdev->devfn) == 0x0a)) { - /* - * IDE Decode enable. - */ - pci_read_config_byte(pdev, 0x41, ®_val); - pci_write_config_byte(pdev, 0x41, reg_val | 0x80); - pci_read_config_byte(pdev, 0x43, ®_val); - pci_write_config_byte(pdev, 0x43, reg_val | 0x80); - } - - if ((pdev->vendor == PCI_VENDOR_ID_INTEL) - && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0) - && (PCI_SLOT(pdev->devfn) == 0x0a)) { - /* - * Set top of main memory accessible by ISA or DMA - * devices to 16 Mb. - */ - pci_read_config_byte(pdev, 0x69, ®_val); - pci_write_config_byte(pdev, 0x69, reg_val | 0xf0); - } - } - - /* - * Activate Floppy Controller in the SMSC FDC37M817 Super I/O - * Controller. - * This should be done in the bios/bootprom and will be fixed in - * a later revision of YAMON (the MIPS boards boot prom). - */ - /* Entering config state. */ - SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); - - /* Activate floppy controller. */ - SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG); - SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG); - SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG); - SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG); - - /* Exit config state. */ - SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG); -#endif -} - -int __init -pcibios_enable_device(struct pci_dev *dev) -{ - /* Not needed, since we enable all devices at startup. */ - return 0; -} - -void __init -pcibios_align_resource(void *data, struct resource *res, unsigned long size) -{ -} - -char * __init -pcibios_setup(char *str) -{ - /* Nothing to do for now. */ - - return str; -} - -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; - -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); -} - -unsigned __init int pcibios_assign_all_busses(void) -{ - return 1; -} - -/* - * Called after each bus is probed, but before its children - * are examined. - */ -void __init pcibios_fixup_bus(struct pci_bus *b) -{ - pci_read_bridge_bases(b); -} - -#endif /* CONFIG_PCI */ diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/printf.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/printf.c --- linux-2.4.18/arch/mips64/mips-boards/generic/printf.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/printf.c Thu Jan 1 01:00:00 1970 @@ -1,140 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Putting things on the screen/serial line using YAMONs facilities. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef CONFIG_MIPS_ATLAS -/* - * Atlas registers are memory mapped on 64-bit aligned boundaries and - * only word access are allowed. - * When reading the UART 8 bit registers only the LSB are valid. - */ -unsigned int atlas_serial_in(struct async_struct *info, int offset) -{ - return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff); -} - -void atlas_serial_out(struct async_struct *info, int offset, int value) -{ - *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value; -} - -#define serial_in atlas_serial_in -#define serial_out atlas_serial_out - -#else - -static unsigned int serial_in(struct async_struct *info, int offset) -{ - return inb(info->port + offset); -} - -static void serial_out(struct async_struct *info, int offset, - int value) -{ - outb(value, info->port + offset); -} -#endif - -static struct serial_state rs_table[] = { - SERIAL_PORT_DFNS /* Defined in serial.h */ -}; - -/* - * Hooks to fake "prom" console I/O before devices - * are fully initialized. - */ -static struct async_struct prom_port_info = {0}; - -void __init setup_prom_printf(int tty_no) { - struct serial_state *ser = &rs_table[tty_no]; - - prom_port_info.state = ser; - prom_port_info.magic = SERIAL_MAGIC; - prom_port_info.port = ser->port; - prom_port_info.flags = ser->flags; - - /* No setup of UART - assume YAMON left in sane state */ -} - -int putPromChar(char c) -{ - if (!prom_port_info.state) { /* need to init device first */ - return 0; - } - - while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0) - ; - - serial_out(&prom_port_info, UART_TX, c); - - return 1; -} - -char getPromChar(void) -{ - if (!prom_port_info.state) { /* need to init device first */ - return 0; - } - - while (!(serial_in(&prom_port_info, UART_LSR) & 1)) - ; - - return(serial_in(&prom_port_info, UART_RX)); -} - -static char buf[1024]; - -void __init prom_printf(char *fmt, ...) -{ - va_list args; - int l; - char *p, *buf_end; - long flags; - - int putPromChar(char); - - /* Low level, brute force, not SMP safe... */ - save_and_cli(flags); - va_start(args, fmt); - l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ - va_end(args); - - buf_end = buf + l; - - for (p = buf; p < buf_end; p++) { - /* Crude cr/nl handling is better than none */ - if(*p == '\n')putPromChar('\r'); - putPromChar(*p); - } - restore_flags(flags); -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/reset.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/reset.c --- linux-2.4.18/arch/mips64/mips-boards/generic/reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/reset.c Thu Jan 1 01:00:00 1970 @@ -1,61 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Reset the MIPS boards. - * - */ -#include - -#include -#if defined(CONFIG_MIPS_ATLAS) -#include -#endif - -void machine_restart(char *command) __attribute__((noreturn)); -void machine_halt(void) __attribute__((noreturn)); -#if defined(CONFIG_MIPS_ATLAS) -void machine_power_off(void) __attribute__((noreturn)); -#endif - -void machine_restart(char *command) -{ - volatile unsigned int *softres_reg = (void *)SOFTRES_REG; - - *softres_reg = GORESET; -} - -void machine_halt(void) -{ - volatile unsigned int *softres_reg = (void *)SOFTRES_REG; - - *softres_reg = GORESET; -} - -void machine_power_off(void) -{ -#if defined(CONFIG_MIPS_ATLAS) - volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG; - - *psustby_reg = ATLAS_GOSTBY; -#else - machine_halt(); -#endif -} diff -urN linux-2.4.18/arch/mips64/mips-boards/generic/time.c linux-2.4.19-pre5/arch/mips64/mips-boards/generic/time.c --- linux-2.4.18/arch/mips64/mips-boards/generic/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/generic/time.c Thu Jan 1 01:00:00 1970 @@ -1,399 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Setting up the clock on the MIPS boards. - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -extern volatile unsigned long wall_jiffies; -static long last_rtc_update = 0; -unsigned long missed_heart_beats = 0; - -static unsigned long r4k_offset; /* Amount to increment compare reg each time */ -static unsigned long r4k_cur; /* What counter should be at next timer irq */ -extern rwlock_t xtime_lock; - -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) - -#if defined(CONFIG_MIPS_ATLAS) -static char display_string[] = " LINUX ON ATLAS "; -#endif -#if defined(CONFIG_MIPS_MALTA) -static char display_string[] = " LINUX ON MALTA "; -#endif -static unsigned int display_count = 0; -#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) - -static unsigned int timer_tick_count=0; - - -static inline void ack_r4ktimer(unsigned long newval) -{ - write_32bit_cp0_register(CP0_COMPARE, newval); -} - - -/* - * In order to set the CMOS clock precisely, set_rtc_mmss has to be - * called 500 ms after the second nowtime has started, because when - * nowtime is written into the registers of the CMOS clock, it will - * jump to the next second precisely 500 ms later. Check the Motorola - * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you won't notice until after reboot! - */ -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return retval; -} - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is provably more robust. - */ -void mips_timer_interrupt(struct pt_regs *regs) -{ - int irq = 7; - - if (r4k_offset == 0) - goto null; - - do { - kstat.irqs[0][irq]++; - do_timer(regs); - - /* Historical comment/code: - * RTC time of day s updated approx. every 11 - * minutes. Because of how the numbers work out - * we need to make absolutely sure we do this update - * within 500ms before the * next second starts, - * thus the following code. - */ - read_lock(&xtime_lock); - if ((time_status & STA_UNSYNC) == 0 - && xtime.tv_sec > last_rtc_update + 660 - && xtime.tv_usec >= 500000 - (tick >> 1) - && xtime.tv_usec <= 500000 + (tick >> 1)) - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 600; - read_unlock(&xtime_lock); - - if ((timer_tick_count++ % HZ) == 0) { - mips_display_message(&display_string[display_count++]); - if (display_count == MAX_DISPLAY_COUNT) - display_count = 0; - } - - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned int)read_32bit_cp0_register(CP0_COUNT) - - (unsigned int)r4k_cur) < 0x7fffffff); - - return; - -null: - ack_r4ktimer(0); -} - -/* - * Figure out the r4k offset, the amount to increment the compare - * register for each time tick. - * Use the RTC to calculate offset. - */ -static unsigned long __init cal_r4koff(void) -{ - unsigned long count; - unsigned int flags; - - __save_and_cli(flags); - - /* Start counter exactly on falling edge of update flag */ - while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - /* Start r4k counter. */ - write_32bit_cp0_register(CP0_COUNT, 0); - - /* Read counter exactly on falling edge of update flag */ - while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - count = read_32bit_cp0_register(CP0_COUNT); - - /* restore interrupts */ - __restore_flags(flags); - - return (count / HZ); -} - -static unsigned long __init get_mips_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - unsigned char save_control; - - save_control = CMOS_READ(RTC_CONTROL); - - /* Freeze it. */ - CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL); - - /* Read regs. */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - - if (!(save_control & RTC_24H)) - { - if ((hour & 0xf) == 0xc) - hour &= 0x80; - if (hour & 0x80) - hour = (hour & 0xf) + 12; - } - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - - /* Unfreeze clock. */ - CMOS_WRITE(save_control, RTC_CONTROL); - - if ((year += 1900) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -void __init time_init(void) -{ - unsigned int est_freq, flags; - - /* Set Data mode - binary. */ - CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); - - printk("calculating r4koff... "); - r4k_offset = cal_r4koff(); - printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); - - est_freq = 2*r4k_offset*HZ; - est_freq += 5000; /* round */ - est_freq -= est_freq%10000; - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); - r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); - - write_32bit_cp0_register(CP0_COMPARE, r4k_cur); - set_cp0_status(ST0_IM, ALLINTS); - - /* Read time from the RTC chipset. */ - write_lock_irqsave (&xtime_lock, flags); - xtime.tv_sec = get_mips_time(); - xtime.tv_usec = 0; - write_unlock_irqrestore(&xtime_lock, flags); -} - -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff) - -/* Cycle counter value at the previous timer interrupt.. */ - -static unsigned int timerhi = 0, timerlo = 0; - -/* - * FIXME: Does playing with the RP bit in c0_status interfere with this code? - */ -static unsigned long do_fast_gettimeoffset(void) -{ - u32 count; - unsigned long res, tmp; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies=0; - unsigned long quotient; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient=0; - - tmp = jiffies; - - quotient = cached_quotient; - - if (tmp && last_jiffies != tmp) { - last_jiffies = tmp; - __asm__(".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "lwu\t%0,%2\n\t" - "dsll32\t$1,%1,0\n\t" - "or\t$1,$1,%0\n\t" - "ddivu\t$0,$1,%3\n\t" - "mflo\t$1\n\t" - "dsll32\t%0,%4,0\n\t" - "nop\n\t" - "ddivu\t$0,%0,$1\n\t" - "mflo\t%0\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=&r" (quotient) - :"r" (timerhi), - "m" (timerlo), - "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); - cached_quotient = quotient; - } - - /* Get last timer tick in absolute kernel time */ - count = read_32bit_cp0_register(CP0_COUNT); - - /* .. relative to previous jiffy (32 bits is enough) */ - count -= timerlo; - - __asm__("multu\t%1,%2\n\t" - "mfhi\t%0" - :"=r" (res) - :"r" (count), - "r" (quotient)); - - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (res >= USECS_PER_JIFFY) - res = USECS_PER_JIFFY-1; - - return res; -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned int flags; - - read_lock_irqsave (&xtime_lock, flags); - *tv = xtime; - tv->tv_usec += do_fast_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. jiffies - wall_jiffies - * is nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore (&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} - -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 -= do_fast_gettimeoffset(); - - if (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); -} diff -urN linux-2.4.18/arch/mips64/mips-boards/malta/Makefile linux-2.4.19-pre5/arch/mips64/mips-boards/malta/Makefile --- linux-2.4.18/arch/mips64/mips-boards/malta/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/malta/Makefile Thu Jan 1 01:00:00 1970 @@ -1,42 +0,0 @@ -# -# Carsten Langgaard, carstenl@mips.com -# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. -# -# ######################################################################## -# -# This program is free software; you can distribute it and/or modify it -# under the terms of the GNU General Public License (Version 2) as -# published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# ####################################################################### -# -# Makefile for the MIPS Malta specific kernel interface routines -# under Linux. -# -# 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: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -all: malta.o - -O_TARGET := malta.o - -obj-y := malta_int.o malta_rtc.o malta_setup.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/mips-boards/malta/malta_int.c linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_int.c --- linux-2.4.18/arch/mips64/mips-boards/malta/malta_int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_int.c Thu Jan 1 01:00:00 1970 @@ -1,383 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Routines for generic manipulation of the interrupts found on the MIPS - * Malta board. - * The interrupt controller is located in the South Bridge a PIIX4 device - * with two internal 82C95 interrupt controllers. - * - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -extern asmlinkage void mipsIRQ(void); - -unsigned int local_bh_count[NR_CPUS]; -unsigned int local_irq_count[NR_CPUS]; -unsigned long spurious_count = 0; - -static struct irqaction *hw0_irq_action[MALTAINT_END] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -static struct irqaction r4ktimer_action = { - NULL, 0, 0, "R4000 timer/counter", NULL, NULL, -}; - -static struct irqaction *irq_action[8] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, &r4ktimer_action -}; - -#if 0 -#define DEBUG_INT(x...) printk(x) -#else -#define DEBUG_INT(x...) -#endif - -/* - * This contains the interrupt mask for both 82C59 interrupt controllers. - */ -static unsigned int cached_int_mask = 0xffff; - - -void disable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - if(irq_nr >= MALTAINT_END) { - printk("whee, invalid irq_nr %d\n", irq_nr); - panic("IRQ, you lose..."); - } - - save_and_cli(flags); - cached_int_mask |= (1 << irq_nr); - if (irq_nr & 8) { - outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); - } else { - outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); - } - restore_flags(flags); -} - - -void enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - - if(irq_nr >= MALTAINT_END) { - printk("whee, invalid irq_nr %d\n", irq_nr); - panic("IRQ, you lose..."); - } - - save_and_cli(flags); - cached_int_mask &= ~(1 << irq_nr); - if (irq_nr & 8) { - outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); - - /* Enable irq 2 (cascade interrupt). */ - cached_int_mask &= ~(1 << 2); - outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); - } else { - outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); - } - restore_flags(flags); -} - - -int get_irq_list(char *buf) -{ - int i, len = 0; - int num = 0; - struct irqaction *action; - - for (i = 0; i < 8; i++, num++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [on-chip]\n"); - } - for (i = 0; i < MALTAINT_END; i++, num++) { - action = hw0_irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [hw0]\n"); - } - return len; -} - -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - struct irqaction *action; - int retval; - - DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname); - - if (irq >= MALTAINT_END) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if(!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = 0; - - retval = setup_irq(irq, action); - if (retval) - kfree(action); - - return retval; -} - - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction *action, **p; - - if (irq >= MALTAINT_END) { - printk("Trying to free IRQ%d\n",irq); - return; - } - - for (p = &hw0_irq_action[irq]; (action = *p) != NULL; - p = &action->next) - { - if (action->dev_id != dev_id) - continue; - - /* Found it - now free it */ - *p = action->next; - kfree(action); - if (!hw0_irq_action[irq]) - disable_irq(irq); - return; - } - printk("Trying to free IRQ%d\n",irq); -} - -void __init init_IRQ(void) -{ - irq_setup(); -} - -static int setup_irq(unsigned int irq, struct irqaction * new) -{ - int shared = 0; - struct irqaction *old, **p; - - p = &hw0_irq_action[irq]; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) - return -EBUSY; - - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - - *p = new; - if (!shared) - enable_irq(irq); - - return 0; -} - -static inline int get_int(int *irq) -{ - /* - * Determine highest priority pending interrupt by performing - * a PCI Interrupt Acknowledge cycle. - */ - GT_READ(GT_PCI0_IACK_OFS, *irq); - *irq &= 0xFF; - - /* - * IRQ7 is used to detect spurious interrupts. - * The interrupt acknowledge cycle returns IRQ7, if no - * interrupts is requested. - * We can differentiate between this situation and a - * "Normal" IRQ7 by reading the ISR. - */ - if (*irq == 7) - { - outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3); - if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) - return -1; /* Spurious interrupt. */ - } - - return 0; -} - -static inline void ack_int(int irq) -{ - if (irq & 8) { - /* Specific EOI to cascade */ - outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2, - PIIX4_ICTLR1_OCW2); - - /* Non specific EOI to cascade */ - outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2); - } else { - /* Non specific EOI to cascade */ - outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2); - } -} - -void malta_hw0_irqdispatch(struct pt_regs *regs) -{ - struct irqaction *action; - int irq=0, cpu = smp_processor_id(); - - DEBUG_INT("malta_hw0_irqdispatch\n"); - - if (get_int(&irq)) - return; /* interrupt has already been cleared */ - - disable_irq(irq); - ack_int(irq); - - DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq); - action = hw0_irq_action[irq]; - - /* - * if action == NULL, then we don't have a handler - * for the irq - */ - if ( action == NULL ) - return; - - irq_enter(cpu, irq); - kstat.irqs[0][irq + 8]++; - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - - enable_irq(irq); - irq_exit(cpu, irq); -} - - -unsigned long probe_irq_on (void) -{ - unsigned int i, irqs = 0; - unsigned long delay; - - /* first, enable any unassigned irqs */ - for (i = MALTAINT_END-1; i > 0; i--) { - if (!hw0_irq_action[i]) { - enable_irq(i); - irqs |= (1 << i); - } - } - - /* wait for spurious interrupts to mask themselves out again */ - for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) - /* about 100ms delay */; - - /* now filter out any obviously spurious interrupts */ - return irqs & ~cached_int_mask; -} - - -int probe_irq_off (unsigned long irqs) -{ - unsigned int i; - - irqs &= cached_int_mask; - if (!irqs) - return 0; - i = ffz(~irqs); - if (irqs != (irqs & (1 << i))) - i = -i; - - return i; -} - - -void __init maltaint_init(void) -{ - /* - * Mask out all interrupt by writing "1" to all bit position in - * the IMR register. - */ - outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1); - outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1); - - /* Now safe to set the exception vector. */ - set_except_vector(0, mipsIRQ); -} diff -urN linux-2.4.18/arch/mips64/mips-boards/malta/malta_rtc.c linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_rtc.c --- linux-2.4.18/arch/mips64/mips-boards/malta/malta_rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_rtc.c Thu Jan 1 01:00:00 1970 @@ -1,50 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * RTC routines for Malta style attached PIIX4 device, which contains a - * Motorola MC146818A-compatible Real Time Clock. - * - */ -#include -#include - -static unsigned char malta_rtc_read_data(unsigned long addr) -{ - outb(addr, MALTA_RTC_ADR_REG); - return inb(MALTA_RTC_DAT_REG); -} - -static void malta_rtc_write_data(unsigned char data, unsigned long addr) -{ - outb(addr, MALTA_RTC_ADR_REG); - outb(data, MALTA_RTC_DAT_REG); -} - -static int malta_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops malta_rtc_ops = { - &malta_rtc_read_data, - &malta_rtc_write_data, - &malta_rtc_bcd_mode -}; diff -urN linux-2.4.18/arch/mips64/mips-boards/malta/malta_setup.c linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_setup.c --- linux-2.4.18/arch/mips64/mips-boards/malta/malta_setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mips-boards/malta/malta_setup.c Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * ######################################################################## - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * Malta specific setup, including init of the feature struct. - * - */ -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BLK_DEV_IDE -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BLK_DEV_FD -#include -#endif -#include -#include - -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) -extern void console_setup(char *, int *); -char serial_console[20]; -#endif - -#ifdef CONFIG_REMOTE_DEBUG -extern void set_debug_traps(void); -extern void rs_kgdb_hook(int); -extern void breakpoint(void); -static int remote_debug = 0; -#endif - -#ifdef CONFIG_BLK_DEV_IDE -extern struct ide_ops std_ide_ops; -#endif -#ifdef CONFIG_BLK_DEV_FD -extern struct fd_ops std_fd_ops; -#endif -extern struct rtc_ops malta_rtc_ops; - -extern void mips_reboot_setup(void); - -struct resource standard_io_resources[] = { - { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, - { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, - { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, - { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, - { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, - { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, -}; - -#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) - -static void __init malta_irq_setup(void) -{ - maltaint_init(); - -#ifdef CONFIG_REMOTE_DEBUG - if (remote_debug) { - set_debug_traps(); - breakpoint(); - } -#endif -} - - -void __init malta_setup(void) -{ -#ifdef CONFIG_REMOTE_DEBUG - int rs_putDebugChar(char); - char rs_getDebugChar(void); - extern int (*putDebugChar)(char); - extern char (*getDebugChar)(void); -#endif - char *argptr; - int i; - - current_cpu_data.asid_cache = ASID_FIRST_VERSION; - TLBMISS_HANDLER_SETUP(); - - irq_setup = malta_irq_setup; - - /* Request I/O space for devices used on the Malta board. */ - for (i = 0; i < STANDARD_IO_RESOURCES; i++) - request_resource(&ioport_resource, standard_io_resources+i); - - /* - * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge. - */ - enable_dma(4); - -#ifdef CONFIG_SERIAL_CONSOLE - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) - { - int i=0; - char *s = prom_getenv("modetty0"); - while(s[i] >= '0' && s[i] <= '9') - i++; - strcpy(serial_console, "ttyS0,"); - strncpy(serial_console + 6, s, i); - prom_printf("Config serial console: %s\n", serial_console); - console_setup(serial_console, NULL); - } -#endif - -#ifdef CONFIG_REMOTE_DEBUG - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { - int line; - argptr += strlen("kgdb=ttyS"); - if (*argptr != '0' && *argptr != '1') - printk("KGDB: Uknown serial line /dev/ttyS%c, " - "falling back to /dev/ttyS1\n", *argptr); - line = *argptr == '0' ? 0 : 1; - printk("KGDB: Using serial line /dev/ttyS%d for session\n", - line ? 1 : 0); - - rs_kgdb_hook(line); - putDebugChar = rs_putDebugChar; - getDebugChar = rs_getDebugChar; - - prom_printf("KGDB: Using serial line /dev/ttyS%d for session, " - "please connect your debugger\n", line ? 1 : 0); - - remote_debug = 1; - /* Breakpoints and stuff are in malta_irq_setup() */ - } -#endif - - argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "nofpu")) != NULL) - mips_cpu.options &= ~MIPS_CPU_FPU; - - rtc_ops = &malta_rtc_ops; -#ifdef CONFIG_BLK_DEV_IDE - ide_ops = &std_ide_ops; -#endif -#ifdef CONFIG_BLK_DEV_FD - fd_ops = &std_fd_ops; -#endif -} diff -urN linux-2.4.18/arch/mips64/mm/Makefile linux-2.4.19-pre5/arch/mips64/mm/Makefile --- linux-2.4.18/arch/mips64/mm/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/Makefile Sat Mar 30 22:55:27 2002 @@ -2,16 +2,29 @@ # Makefile for the Linux/MIPS-specific parts of the memory manager. # +.S.o: + $(CC) $(CFLAGS) $(CFLAGS_$@) -c $< -o $*.o + O_TARGET := mm.o export-objs += umap.o obj-y := extable.o init.o fault.o loadmmu.o -obj-$(CONFIG_CPU_R4300) += r4xx0.o -obj-$(CONFIG_CPU_R4X00) += r4xx0.o -obj-$(CONFIG_CPU_R5000) += r4xx0.o -obj-$(CONFIG_CPU_NEVADA) += r4xx0.o -obj-$(CONFIG_CPU_R10000) += andes.o +obj-$(CONFIG_CPU_R4300) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_R10000) += andes.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_SB1) += pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o \ + tlb-glue-r4k.o + +# +# Debug TLB exception handler, currently unused +# +#obj-y += tlb-dbg-r4k.o tlb-glue-r4k.o + obj-$(CONFIG_SGI_IP22) += umap.o + +CFLAGS_tlb-glue-r4k.o := -P include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/mm/andes.c linux-2.4.19-pre5/arch/mips64/mm/andes.c --- linux-2.4.18/arch/mips64/mm/andes.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/andes.c Sat Mar 30 22:55:27 2002 @@ -15,7 +15,6 @@ #include #include #include -#include #include static int scache_lsz64; @@ -43,9 +42,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE) + : "memory"); } /* R10000 has no Create_Dirty type cacheops. */ @@ -132,8 +131,7 @@ #define NTLB_ENTRIES 64 #define NTLB_ENTRIES_HALF 32 -static inline void -andes_flush_tlb_all(void) +void local_flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; @@ -153,7 +151,7 @@ entry = get_wired(); /* Blast 'em all away. */ - while(entry < NTLB_ENTRIES) { + while (entry < NTLB_ENTRIES) { set_index(entry); tlb_write_indexed(); entry++; @@ -162,7 +160,7 @@ __restore_flags(flags); } -static void andes_flush_tlb_mm(struct mm_struct *mm) +void local_flush_tlb_mm(struct mm_struct *mm) { if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { unsigned long flags; @@ -171,16 +169,15 @@ printk("[tlbmm<%d>]", mm->context); #endif __save_and_cli(flags); - get_new_cpu_mmu_context(mm, smp_processor_id()); + get_new_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); __restore_flags(flags); } } -static void -andes_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) { if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { unsigned long flags; @@ -193,7 +190,7 @@ __save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; - if(size <= NTLB_ENTRIES_HALF) { + if (size <= NTLB_ENTRIES_HALF) { int oldpid = (get_entryhi() & 0xff); int newpid = (CPU_CONTEXT(smp_processor_id(), mm) & 0xff); @@ -216,7 +213,7 @@ } set_entryhi(oldpid); } else { - get_new_cpu_mmu_context(mm, smp_processor_id()); + get_new_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); @@ -225,8 +222,7 @@ } } -static void -andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) { unsigned long flags; @@ -245,7 +241,7 @@ set_entrylo0(0); set_entrylo1(0); set_entryhi(KSEG0); - if(idx < 0) + if (idx < 0) goto finish; tlb_write_indexed(); @@ -273,16 +269,16 @@ if (current->active_mm != vma->vm_mm) return; - __save_and_cli(flags); pid = get_entryhi() & 0xff; - if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) || + if ((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) || (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) { printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d " "tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff), pid); } + __save_and_cli(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -293,7 +289,7 @@ set_entrylo0(pte_val(*ptep++) >> 6); set_entrylo1(pte_val(*ptep) >> 6); set_entryhi(address | (pid)); - if(idx < 0) { + if (idx < 0) { tlb_write_random(); } else { tlb_write_indexed(); @@ -302,36 +298,6 @@ __restore_flags(flags); } -static void andes_show_regs(struct pt_regs *regs) -{ - printk("Cpu %d\n", smp_processor_id()); - /* Saved main processor registers. */ - printk("$0 : %016lx %016lx %016lx %016lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk("$4 : %016lx %016lx %016lx %016lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk("$8 : %016lx %016lx %016lx %016lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk("$12 : %016lx %016lx %016lx %016lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk("$16 : %016lx %016lx %016lx %016lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk("$20 : %016lx %016lx %016lx %016lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk("$24 : %016lx %016lx\n", - regs->regs[24], regs->regs[25]); - printk("$28 : %016lx %016lx %016lx %016lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - printk("Hi : %016lx\n", regs->hi); - printk("Lo : %016lx\n", regs->lo); - - /* Saved cp0 registers. */ - printk("epc : %016lx %s\nbadvaddr: %016lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_badvaddr); - printk("Status : %08x\nCause : %08x\n", - (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause); -} - void __init ld_mmu_andes(void) { printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); @@ -350,11 +316,6 @@ _flush_cache_l2 = andes_flush_cache_l2; _flush_cache_sigtramp = andes_flush_cache_sigtramp; - _flush_tlb_all = andes_flush_tlb_all; - _flush_tlb_mm = andes_flush_tlb_mm; - _flush_tlb_range = andes_flush_tlb_range; - _flush_tlb_page = andes_flush_tlb_page; - switch (sc_lsize()) { case 64: scache_lsz64 = 1; @@ -367,9 +328,7 @@ while(1); } - update_mmu_cache = andes_update_mmu_cache; - - _show_regs = andes_show_regs; + _update_mmu_cache = andes_update_mmu_cache; flush_cache_l1(); @@ -381,9 +340,10 @@ * be set for 4kb pages. */ write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); + write_32bit_cp0_register(CP0_FRAMEMASK, 0); /* From this point on the ARC firmware is dead. */ - _flush_tlb_all(); + local_flush_tlb_all(); - /* Did I tell you that ARC SUCKS? */ + /* Did I tell you that ARC SUCKS? */ } diff -urN linux-2.4.18/arch/mips64/mm/c-sb1.c linux-2.4.19-pre5/arch/mips64/mm/c-sb1.c --- linux-2.4.18/arch/mips64/mm/c-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/c-sb1.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,545 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +/* These are probed at ld_mmu time */ +static unsigned long icache_size; +static unsigned long dcache_size; + +static unsigned long icache_line_size; +static unsigned long dcache_line_size; + +static unsigned int icache_index_mask; + +static unsigned long icache_assoc; +static unsigned long dcache_assoc; + +static unsigned int icache_sets; +static unsigned int dcache_sets; + +/* + * The dcache is fully coherent to the system, with one + * big caveat: the instruction stream. In other words, + * if we miss in the icache, and have dirty data in the + * L1 dcache, then we'll go out to memory (or the L2) and + * get the not-as-recent data. + * + * So the only time we have to flush the dcache is when + * we're flushing the icache. Since the L2 is fully + * coherent to everything, including I/O, we never have + * to flush it + */ + +static void sb1_flush_cache_all(void) +{ +} + +static inline void local_sb1___flush_dcache_all(void) +{ + /* + * Haven't worried too much about speed here; given that we're flushing + * the icache, the time to invalidate is dwarfed by the time it's going + * to take to refill it. Register usage: + * + * $1 - moving cache index + * $2 - set count + */ + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* WB/Invalidate this index */ + " daddiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " daddu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (dcache_line_size), "r" (dcache_sets * dcache_assoc), + "r" (KSEG0), "i" (Index_Writeback_Inv_D)); + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set mips2 \n" + "sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + "sync \n" +#endif + ".set pop \n"); +} + +static inline void local_sb1___flush_icache_all(void) +{ + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* Invalidate this index */ + " daddiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " daddu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (icache_line_size), "r" (icache_sets * icache_assoc), + "r" (KSEG0), "i" (Index_Invalidate_I)); +} + +static void local_sb1___flush_cache_all(void) +{ + local_sb1___flush_dcache_all(); + local_sb1___flush_icache_all(); +} + +#ifdef CONFIG_SMP +extern void sb1___flush_cache_all_ipi(void *ignored); +asm("sb1___flush_cache_all_ipi = local_sb1___flush_cache_all"); + +static void sb1___flush_cache_all(void) +{ + smp_call_function(sb1___flush_cache_all_ipi, 0, 1, 1); + local_sb1___flush_cache_all(); +} +#else +extern void sb1___flush_cache_all(void); +asm("sb1___flush_cache_all = local_sb1___flush_cache_all"); +#endif + + +/* + * When flushing a range in the icache, we have to first writeback + * the dcache for the same range, so new ifetches will see any + * data that was dirty in the dcache. + * + * The start/end arguments are expected to be Kseg addresses. + */ + +static void local_sb1_flush_icache_range(unsigned long start, + unsigned long end) +{ +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + unsigned long flags; + local_irq_save(flags); +#endif + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %0 \n" + "1: \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + ".align 3 \n" + " lw $0, 0($1) \n" /* Bug 1370, 1368 */ + " sync \n" +#endif + " cache %3, 0($1) \n" /* Hit-WB{,-inval} this address */ + " bne $1, %1, 1b \n" /* loop test */ + " daddu $1, $1, %2 \n" /* next line */ + ".set pop \n" + : + : "r" ((start + dcache_line_size - 1) & ~(dcache_line_size - 1)), + "r" ((end + dcache_line_size - 1) & ~(dcache_line_size - 1)), + "r" (dcache_line_size), +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + "i" (Hit_Writeback_Inv_D) +#else + "i" (Hit_Writeback_D) +#endif + ); + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set mips2 \n" + "sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + "sync \n" +#endif + ".set pop \n"); +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + local_irq_restore(flags); +#endif + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %0 \n" + ".align 3 \n" + "1: cache %3, (0<<13)($1) \n" /* Index-inval this address */ + " cache %3, (1<<13)($1) \n" /* Index-inval this address */ + " cache %3, (2<<13)($1) \n" /* Index-inval this address */ + " cache %3, (3<<13)($1) \n" /* Index-inval this address */ + " bne $1, %1, 1b \n" /* loop test */ + " daddu $1, $1, %2 \n" /* next line */ + ".set pop \n" + : + : "r" (start & ~(icache_line_size - 1)), + "r" ((end - 1) & ~(dcache_line_size - 1)), + "r" (icache_line_size), + "i" (Index_Invalidate_I)); +} + +#ifdef CONFIG_SMP +struct flush_icache_range_args { + unsigned long start; + unsigned long end; +}; + +static void sb1_flush_icache_range_ipi(void *info) +{ + struct flush_icache_range_args *args = info; + + local_sb1_flush_icache_range(args->start, args->end); +} + +void sb1_flush_icache_range(unsigned long start, unsigned long end) +{ + struct flush_icache_range_args args; + + args.start = start; + args.end = end; + smp_call_function(sb1_flush_icache_range_ipi, &args, 1, 1); + local_sb1_flush_icache_range(start, end); +} +#else +void sb1_flush_icache_range(unsigned long start, unsigned long end); +asm("sb1_flush_icache_range = local_sb1_flush_icache_range"); +#endif + +/* + * If there's no context yet, or the page isn't executable, no icache flush + * is needed + * + * This is broken. If there is no context yet we still have to writeback + * the d-cache to memory. + */ +static void sb1_flush_icache_page(struct vm_area_struct *vma, + struct page *page) +{ + unsigned int cpu = smp_processor_id(); + + if (!(vma->vm_flags & VM_EXEC)) { +// printk("sb1_flush_icache_page(): not exec\n"); + return; + } + + /* + * We're not sure of the virtual address(es) involved here, so + * conservatively flush the entire caches on all processors + * (ouch). + * + * Bumping the ASID may well be cheaper, need to experiment ... + */ +//printk("sb1_flush_icache_page(): flushing exec page\n"); + sb1___flush_cache_all(); +} + +static inline void protected_flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips4 \n" + "1: cache %1, (%0) \n" + "2: .set pop \n" + " .section __ex_table,\"a\"\n" + " .dword 1b, 2b \n" + " .previous" + : + : "r" (addr), "i" (Hit_Invalidate_I)); +} + +static inline void protected_writeback_dcache_line(unsigned long addr) +{ +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + /* Have to be sure the TLB entry exists for the cache op, + so we have to be sure that nothing happens in between the + lw and the cache op + */ + unsigned long flags; + local_irq_save(flags); +#endif + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips4 \n" + " \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + "1: lw $0, (%0) \n" + " sync \n" + " .section __ex_table,\"a\"\n" + " .dword 1b, 3f \n" + " .previous \n" +#endif + "2: cache %1, 0(%0) \n" /* Hit-WB{-inval} this address */ + /* XXX: should be able to do this after both dcache cache + ops, but there's no guarantee that this will be inlined, + and the pass1 restriction checker can't detect syncs + following cache ops except in the following basic block. + */ + " sync \n" +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* Bug 1384 */ + " sync \n" +#endif + "3: .set pop \n" + " .section __ex_table,\"a\"\n" + " .dword 2b, 3b \n" + " .previous" + : + : "r" (addr), +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + "i" (Hit_Writeback_Inv_D) +#else + "i" (Hit_Writeback_D) +#endif + ); +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + local_irq_restore(flags); +#endif +} + +/* + * A signal trampoline must fit into a single cacheline. + */ +static inline void local_sb1_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dcache_line_size - 1); + protected_writeback_dcache_line(daddr); + iaddr = addr & ~(icache_line_size - 1); + protected_flush_icache_line(iaddr); +} + +#ifdef CONFIG_SMP +struct flush_cache_sigtramp_args { + unsigned long addr; + struct mm_struct *mm; +}; + +static void sb1_flush_icache_range_ipi(void *info) +{ + struct flush_cache_sigtramp_args *args = info; + struct mm_struct *mm = args->mm; + unsigned long old_context, context = CPU_CONTEXT(cpu, mm); + + if (!context) + return; + + /* + * Urgs... Briefly switch the MMU context to the flushing process's + * context, do the flush and back to the previous context. + */ + old_context = get_context(); + set_context(context); + TLBMISS_HANDLER_SETUP_PGD(mm->pgd); + local_sb1_flush_cache_sigtramp(args->addr); + set_context(old_context); + TLBMISS_HANDLER_SETUP_PGD(current->active_mm->pgd); + + XXX This is racing with switch_mm() XXX +} + +extern void sb1_flush_cache_sigtramp_ipi(void *ignored); +asm("sb1_flush_cache_sigtramp_ipi = local_sb1_flush_cache_sigtramp"); + +static void sb1_flush_cache_sigtramp(unsigned long addr) +{ + struct flush_cache_sigtramp_args args; + + local_sb1_flush_cache_sigtramp(addr); + + args.mm = current->mm; + args.addr = addr; + smp_call_function(sb1_flush_cache_sigtramp_ipi, &args, 1, 1); +} +#else +void sb1_flush_cache_sigtramp(unsigned long addr); +asm("sb1_flush_cache_sigtramp = local_sb1_flush_cache_sigtramp"); +#endif + +static void sb1_flush_icache_all(void) +{ + /* + * Haven't worried too much about speed here; given that we're flushing + * the icache, the time to invalidate is dwarfed by the time it's going + * to take to refill it. Register usage: + * + * $1 - moving cache index + * $2 - set count + */ + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache %3, 0($1) \n" /* Invalidate this index */ + " daddiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " daddu $1, $1, %0 \n" /* Next address */ + ".set pop \n" + : + : "r" (icache_line_size), "r" (icache_sets * icache_assoc), + "r" (KSEG0), "i" (Index_Invalidate_I)); +} + +/* + * Anything that just flushes dcache state can be ignored, as we're always + * coherent in dcache space. This is just a dummy function that all the + * nop'ed routines point to + */ + +static void sb1_nop(void) +{ +} + +/* + * This only needs to make sure stores done up to this + * point are visible to other agents outside the CPU. Given + * the coherent nature of the ZBbus, all that's required here is + * a sync to make sure the data gets out to the caches and is + * visible to an arbitrary A Phase from an external agent + * + * Actually, I'm not even sure that's necessary; the semantics + * of this function aren't clear. If it's supposed to serve as + * a memory barrier, this is needed. If it's only meant to + * prevent data from being invisible to non-cpu memory accessors + * for some indefinite period of time (e.g. in a non-coherent + * dcache) then this function would be a complete nop. + */ +static void sb1_flush_page_to_ram(struct page *page) +{ + __asm__ __volatile__( + " sync \n" /* Short pipe */ + :::"memory"); +} + +/* + * Cache set values (from the mips64 spec) + * 0 - 64 + * 1 - 128 + * 2 - 256 + * 3 - 512 + * 4 - 1024 + * 5 - 2048 + * 6 - 4096 + * 7 - Reserved + */ + +static unsigned int decode_cache_sets(unsigned int config_field) +{ + if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + return (1<<(config_field + 6)); +} + +/* + * Cache line size values (from the mips64 spec) + * 0 - No cache present. + * 1 - 4 bytes + * 2 - 8 bytes + * 3 - 16 bytes + * 4 - 32 bytes + * 5 - 64 bytes + * 6 - 128 bytes + * 7 - Reserved + */ + +static unsigned int decode_cache_line_size(unsigned int config_field) +{ + if (config_field == 0) { + return 0; + } else if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + return (1<<(config_field + 1)); +} + +/* + * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs) + * + * 24:22 Icache sets per way + * 21:19 Icache line size + * 18:16 Icache Associativity + * 15:13 Dcache sets per way + * 12:10 Dcache line size + * 9:7 Dcache Associativity + */ + +static __init void probe_cache_sizes(void) +{ + u32 config1; + + config1 = read_mips32_cp0_config1(); + icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7); + dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7); + icache_sets = decode_cache_sets((config1 >> 22) & 0x7); + dcache_sets = decode_cache_sets((config1 >> 13) & 0x7); + icache_assoc = ((config1 >> 16) & 0x7) + 1; + dcache_assoc = ((config1 >> 7) & 0x7) + 1; + icache_size = icache_line_size * icache_sets * icache_assoc; + dcache_size = dcache_line_size * dcache_sets * dcache_assoc; + icache_index_mask = (icache_sets - 1) * icache_line_size; +} + +/* + * This is called from loadmmu.c. We have to set up all the + * memory management function pointers, as well as initialize + * the caches and tlbs + */ +void ld_mmu_sb1(void) +{ + probe_cache_sizes(); + + _clear_page = sb1_clear_page; + _copy_page = sb1_copy_page; + + _flush_cache_all = sb1_flush_cache_all; + ___flush_cache_all = sb1___flush_cache_all; + _flush_cache_mm = (void (*)(struct mm_struct *))sb1_nop; + _flush_cache_range = (void *) sb1_nop; + _flush_page_to_ram = sb1_flush_page_to_ram; + _flush_icache_page = sb1_flush_icache_page; + _flush_icache_range = sb1_flush_icache_range; + + /* None of these are needed for the sb1 */ + _flush_cache_page = (void *) sb1_nop; + + _flush_cache_sigtramp = sb1_flush_cache_sigtramp; + _flush_icache_all = sb1_flush_icache_all; + + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_COW); + flush_cache_all(); +} diff -urN linux-2.4.18/arch/mips64/mm/fault.c linux-2.4.19-pre5/arch/mips64/mm/fault.c --- linux-2.4.18/arch/mips64/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/fault.c Sat Mar 30 22:55:27 2002 @@ -31,7 +31,8 @@ #define development_version (LINUX_VERSION_CODE & 0x100) -extern void die(char *, struct pt_regs *, unsigned long write); +extern void die(char *, struct pt_regs *, unsigned long write) + __attribute__((noreturn)); /* * Macro for exception fixup code to access integer registers. @@ -70,6 +71,10 @@ spin_lock_init(&timerlist_lock); if (yes) { oops_in_progress = 1; +#ifdef CONFIG_SMP + /* Many serial drivers do __global_cli() */ + global_irq_lock = SPIN_LOCK_UNLOCKED; +#endif } else { int loglevel_save = console_loglevel; #ifdef CONFIG_VT @@ -101,6 +106,11 @@ unsigned long fixup; siginfo_t info; +#if 0 + printk("Cpu%d[%s:%d:%08lx:%ld:%08lx]\n", smp_processor_id(), + current->comm, current->pid, address, write, regs->cp0_epc); +#endif + /* * We fault-in kernel-space virtual memory on-demand. The * 'reference' page table is init_mm.pgd. @@ -110,7 +120,7 @@ * only copy the information from the master page table, * nothing more. */ - if (address >= TASK_SIZE) + if (address >= VMALLOC_START) goto vmalloc_fault; info.si_code = SEGV_MAPERR; @@ -120,10 +130,7 @@ */ if (in_interrupt() || mm == &init_mm) goto no_context; -#if DEBUG_MIPS64 - printk("Cpu%d[%s:%d:%08lx:%ld:%08lx]\n", smp_processor_id(), current->comm, - current->pid, address, write, regs->cp0_epc); -#endif + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -149,6 +156,7 @@ goto bad_area; } +survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -177,7 +185,6 @@ bad_area: up_read(&mm->mmap_sem); -bad_area_nosemaphore: if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; @@ -189,6 +196,7 @@ address, (unsigned long) regs->cp0_epc, (unsigned long) regs->regs[31]); +while(1); #endif info.si_signo = SIGSEGV; info.si_errno = 0; @@ -221,12 +229,9 @@ bust_spinlocks(1); printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at " - "address %08lx, epc == %08x, ra == %08x\n", - smp_processor_id(), address, (unsigned int) regs->cp0_epc, - (unsigned int) regs->regs[31]); + "address %016lx, epc == %016lx, ra == %016lx\n", + smp_processor_id(), address, regs->cp0_epc, regs->regs[31]); die("Oops", regs, write); - do_exit(SIGKILL); - bust_spinlocks(0); /* * We ran out of memory, or some other thing happened to us that made @@ -234,6 +239,12 @@ */ out_of_memory: up_read(&mm->mmap_sem); + if (tsk->pid == 1) { + tsk->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", tsk->comm); if (user_mode(regs)) do_exit(SIGKILL); @@ -247,7 +258,7 @@ * or user mode. */ tsk->thread.cp0_badvaddr = address; - info.si_code = SIGBUS; + info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; info.si_addr = (void *) address; diff -urN linux-2.4.18/arch/mips64/mm/init.c linux-2.4.19-pre5/arch/mips64/mm/init.c --- linux-2.4.18/arch/mips64/mm/init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/init.c Sat Mar 30 22:55:27 2002 @@ -32,14 +32,11 @@ #include #include #include -#ifdef CONFIG_SGI_IP22 -#include -#endif #include #include +#include mmu_gather_t mmu_gathers[NR_CPUS]; - unsigned long totalram_pages; void pgd_init(unsigned long page) @@ -135,7 +132,7 @@ unsigned long order, size; struct page *page; - switch (mips_cputype) { + switch (mips_cpu.cputype) { case CPU_R4000SC: case CPU_R4000MC: case CPU_R4400SC: @@ -164,157 +161,6 @@ return 1UL << order; } -void __init add_memory_region(unsigned long start, unsigned long size, - long type) -{ - int x = boot_mem_map.nr_map; - - if (x == BOOT_MEM_MAP_MAX) { - printk("Ooops! Too many entries in the memory map!\n"); - return; - } - - boot_mem_map.map[x].addr = start; - boot_mem_map.map[x].size = size; - boot_mem_map.map[x].type = type; - boot_mem_map.nr_map++; -} - -static void __init print_memory_map(void) -{ - int i; - - for (i = 0; i < boot_mem_map.nr_map; i++) { - printk(" memory: %08lx @ %08lx ", - boot_mem_map.map[i].size, boot_mem_map.map[i].addr); - switch (boot_mem_map.map[i].type) { - case BOOT_MEM_RAM: - printk("(usable)\n"); - break; - case BOOT_MEM_ROM_DATA: - printk("(ROM data)\n"); - break; - case BOOT_MEM_RESERVED: - printk("(reserved)\n"); - break; - default: - printk("type %lu\n", boot_mem_map.map[i].type); - break; - } - } -} - -void bootmem_init(void) { -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long tmp; - unsigned long *initrd_header; -#endif - unsigned long bootmap_size; - unsigned long start_pfn, max_pfn; - int i; - extern int _end; - -#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) - - /* - * Partially used pages are not usable - thus - * we are rounding upwards. - */ - start_pfn = PFN_UP(__pa(&_end)); - - /* Find the highest page frame number we have available. */ - max_pfn = 0; - for (i = 0; i < boot_mem_map.nr_map; i++) { - unsigned long start, end; - - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) - continue; - - start = PFN_UP(boot_mem_map.map[i].addr); - end = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); - - if (start >= end) - continue; - if (end > max_pfn) - max_pfn = end; - } - - /* Initialize the boot-time allocator. */ - bootmap_size = init_bootmem(start_pfn, max_pfn); - - /* - * Register fully available low RAM pages with the bootmem allocator. - */ - for (i = 0; i < boot_mem_map.nr_map; i++) { - unsigned long curr_pfn, last_pfn, size; - - /* - * Reserve usable memory. - */ - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) - continue; - - /* - * We are rounding up the start address of usable memory: - */ - curr_pfn = PFN_UP(boot_mem_map.map[i].addr); - if (curr_pfn >= max_pfn) - continue; - if (curr_pfn < start_pfn) - curr_pfn = start_pfn; - - /* - * ... and at the end of the usable range downwards: - */ - last_pfn = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); - - if (last_pfn > max_pfn) - last_pfn = max_pfn; - - /* - * ... finally, did all the rounding and playing - * around just make the area go away? - */ - if (last_pfn <= curr_pfn) - continue; - - size = last_pfn - curr_pfn; - free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); - } - - /* Reserve the bootmap memory. */ - reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); - -#ifdef CONFIG_BLK_DEV_INITRD -#error "Initrd is broken, please fit it." - tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; - if (tmp < (unsigned long)&_end) - tmp += PAGE_SIZE; - initrd_header = (unsigned long *)tmp; - if (initrd_header[0] == 0x494E5244) { - initrd_start = (unsigned long)&initrd_header[2]; - initrd_end = initrd_start + initrd_header[1]; - initrd_below_start_ok = 1; - if (initrd_end > memory_end) { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,memory_end); - initrd_start = 0; - } else - *memory_start_p = initrd_end; - } -#endif - -#undef PFN_UP -#undef PFN_DOWN -#undef PFN_PHYS - -} - void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -367,7 +213,7 @@ max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; low = max_low_pfn; -#if defined(CONFIG_PCI) || defined(CONFIG_ISA) +#ifdef CONFIG_ISA if (low < max_dma) zones_size[ZONE_DMA] = low; else { @@ -379,7 +225,7 @@ #endif free_area_init(zones_size); - + memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER); memset((void *)kpmdtbl, 0, PAGE_SIZE); pgd_set(swapper_pg_dir, kpmdtbl); @@ -387,7 +233,31 @@ pmd_val(*pmd) = (unsigned long)pte; } -extern int page_is_ram(unsigned long pagenr); +//extern int page_is_ram(unsigned long pagenr); + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) + +static inline int page_is_ram(unsigned long pagenr) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long addr, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + /* not usable memory */ + continue; + + addr = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size); + + if (pagenr >= addr && pagenr < end) + return 1; + } + + return 0; +} void __init mem_init(void) { @@ -463,7 +333,7 @@ si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; - val->sharedram = atomic_read(&shmem_nrpages); + val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; diff -urN linux-2.4.18/arch/mips64/mm/loadmmu.c linux-2.4.19-pre5/arch/mips64/mm/loadmmu.c --- linux-2.4.18/arch/mips64/mm/loadmmu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/loadmmu.c Sat Mar 30 22:55:27 2002 @@ -17,21 +17,26 @@ #include #include #include -#include +#include /* memory functions */ void (*_clear_page)(void * page); void (*_copy_page)(void * to, void * from); /* Cache operations. */ +void (*_flush_cache_all)(void); +void (*___flush_cache_all)(void); void (*_flush_cache_mm)(struct mm_struct *mm); void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, unsigned long end); void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); +void (*_flush_cache_sigtramp)(unsigned long addr); +void (*_flush_icache_range)(unsigned long start, unsigned long end); +void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page); void (*_flush_page_to_ram)(struct page * page); +void (*_flush_icache_all)(void); /* MIPS specific cache operations */ -void (*_flush_cache_sigtramp)(unsigned long addr); void (*_flush_cache_l2)(void); void (*_flush_cache_l1)(void); @@ -41,25 +46,18 @@ void (*_dma_cache_wback)(unsigned long start, unsigned long size); void (*_dma_cache_inv)(unsigned long start, unsigned long size); -/* TLB operations. */ -void (*_flush_tlb_all)(void); -void (*_flush_tlb_mm)(struct mm_struct *mm); -void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start, - unsigned long end); -void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page); - /* Miscellaneous. */ -void (*update_mmu_cache)(struct vm_area_struct * vma, - unsigned long address, pte_t pte); - -void (*_show_regs)(struct pt_regs *); +void (*_update_mmu_cache)(struct vm_area_struct * vma, + unsigned long address, pte_t pte); extern void ld_mmu_r4xx0(void); extern void ld_mmu_andes(void); +extern void ld_mmu_sb1(void); +extern void sb1_tlb_init(void); void __init load_mmu(void) { - switch(mips_cputype) { + switch(mips_cpu.cputype) { #if defined (CONFIG_CPU_R4300) \ || defined (CONFIG_CPU_R4X00) \ || defined (CONFIG_CPU_R5000) \ @@ -83,11 +81,17 @@ ld_mmu_r4xx0(); break; #endif - -#if defined (CONFIG_CPU_R10000) +#ifdef CONFIG_CPU_R10000 case CPU_R10000: printk("Loading R10000 MMU routines.\n"); ld_mmu_andes(); + break; +#endif +#if defined CONFIG_CPU_SB1 + case CPU_SB1: + printk("Loading SB1 MMU routines.\n"); + ld_mmu_sb1(); + sb1_tlb_init(); break; #endif diff -urN linux-2.4.18/arch/mips64/mm/pg-sb1.c linux-2.4.19-pre5/arch/mips64/mm/pg-sb1.c --- linux-2.4.18/arch/mips64/mm/pg-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/pg-sb1.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,123 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000 Sibyte + * + * Written by Justin Carlson (carlson@sibyte.com) + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include + +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS +#define SB1_PREF_LOAD_STREAMED_HINT "0" +#define SB1_PREF_STORE_STREAMED_HINT "1" +#else +#define SB1_PREF_LOAD_STREAMED_HINT "4" +#define SB1_PREF_STORE_STREAMED_HINT "5" +#endif + +/* These are the functions hooked by the memory management function pointers */ +void sb1_clear_page(void *page) +{ + /* + * JDCXXX - This should be bottlenecked by the write buffer, but these + * things tend to be mildly unpredictable...should check this on the + * performance model + * + * We prefetch 4 lines ahead. We're also "cheating" slightly here... + * since we know we're on an SB1, we force the assembler to take + * 64-bit operands to speed things up + */ + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " daddiu $1, %0, %2 \n" /* Calculate the end of the page to clear */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%0) \n" /* Prefetch the first 4 lines */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%0) \n" + "1: sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ + " sd $0, 8(%0) \n" + " sd $0, 16(%0) \n" + " sd $0, 24(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ",128(%0) \n" /* Prefetch 4 lines ahead */ + " bne $1, %0, 1b \n" + " daddiu %0, %0, 32\n" /* Next cacheline (This instruction better be short piped!) */ + ".set pop \n" + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE-32) + : "memory"); + +} + +void sb1_copy_page(void *to, void *from) +{ + /* + * This should be optimized in assembly...can't use ld/sd, though, + * because the top 32 bits could be nuked if we took an interrupt + * during the routine. And this is not a good place to be cli()'ing + * + * The pref's used here are using "streaming" hints, which cause the + * copied data to be kicked out of the cache sooner. A page copy often + * ends up copying a lot more data than is commonly used, so this seems + * to make sense in terms of reducing cache pollution, but I've no real + * performance data to back this up + */ + + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " daddiu $1, %0, %4 \n" /* Calculate the end of the page to copy */ + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 0(%0) \n" /* Prefetch the first 3 lines */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 0(%1) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 32(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 32(%1) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 64(%0) \n" + " pref " SB1_PREF_STORE_STREAMED_HINT ", 64(%1) \n" + "1: lw $2, 0(%0) \n" /* Block copy a cacheline */ + " lw $3, 4(%0) \n" + " lw $4, 8(%0) \n" + " lw $5, 12(%0) \n" + " lw $6, 16(%0) \n" + " lw $7, 20(%0) \n" + " lw $8, 24(%0) \n" + " lw $9, 28(%0) \n" + " pref " SB1_PREF_LOAD_STREAMED_HINT ", 96(%0) \n" /* Prefetch ahead */ + " pref " SB1_PREF_STORE_STREAMED_HINT ", 96(%1) \n" + " sw $2, 0(%1) \n" + " sw $3, 4(%1) \n" + " sw $4, 8(%1) \n" + " sw $5, 12(%1) \n" + " sw $6, 16(%1) \n" + " sw $7, 20(%1) \n" + " sw $8, 24(%1) \n" + " sw $9, 28(%1) \n" + " daddiu %1, %1, 32 \n" /* Next cacheline */ + " nop \n" /* Force next add to short pipe */ + " nop \n" /* Force next add to short pipe */ + " bne $1, %0, 1b \n" + " daddiu %0, %0, 32 \n" /* Next cacheline */ + ".set pop \n" + : "=r" (to), "=r" (from) + : "0" (from), "1" (to), "I" (PAGE_SIZE-32) + : "$2","$3","$4","$5","$6","$7","$8","$9","memory"); +} diff -urN linux-2.4.18/arch/mips64/mm/r4xx0.c linux-2.4.19-pre5/arch/mips64/mm/r4xx0.c --- linux-2.4.18/arch/mips64/mm/r4xx0.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/mm/r4xx0.c Sat Mar 30 22:55:27 2002 @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include /* CP0 hazard avoidance. */ #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ @@ -40,6 +40,7 @@ #undef DEBUG_CACHE + /* * Dummy cache handling routines for machines without boardcaches */ @@ -95,9 +96,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); } static void r4k_clear_page_d32(void * page) @@ -120,9 +121,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); } @@ -180,11 +181,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_D) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); } /* @@ -214,9 +213,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) + : "memory"); __restore_flags(flags); } @@ -251,9 +250,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) - :"$1","memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) + : "memory"); } static void r4k_clear_page_s32(void * page) @@ -276,9 +275,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) - :"$1","memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) + : "memory"); } static void r4k_clear_page_s64(void * page) @@ -300,11 +299,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1","memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) + : "memory"); } static void r4k_clear_page_s128(void * page) @@ -334,11 +331,9 @@ "sd\t$0,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE), - "i" (Create_Dirty_Excl_SD) - :"$1", "memory"); + : "=r" (page) + : "0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_SD) + : "memory"); } @@ -1827,7 +1822,7 @@ static void r4k_dma_cache_wback(unsigned long addr, unsigned long size) { - panic("r4k_dma_cache called - should not happen.\n"); + panic("r4k_dma_cache called - should not happen."); } /* @@ -1864,7 +1859,7 @@ #define NTLB_ENTRIES_HALF 24 /* Fixed on all R4XX0 variants... */ -static inline void r4k_flush_tlb_all(void) +void local_flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; @@ -1897,7 +1892,7 @@ __restore_flags(flags); } -static void r4k_flush_tlb_mm(struct mm_struct *mm) +void local_flush_tlb_mm(struct mm_struct *mm) { if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { unsigned long flags; @@ -1906,14 +1901,14 @@ printk("[tlbmm<%d>]", mm->context); #endif __save_and_cli(flags); - get_new_cpu_mmu_context(mm, smp_processor_id()); + get_new_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); __restore_flags(flags); } } -static void r4k_flush_tlb_range(struct mm_struct *mm, unsigned long start, +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { @@ -1954,7 +1949,7 @@ } set_entryhi(oldpid); } else { - get_new_cpu_mmu_context(mm, smp_processor_id()); + get_new_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); @@ -1963,7 +1958,7 @@ } } -static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) { unsigned long flags; @@ -2086,35 +2081,6 @@ } #endif -static void r4k_show_regs(struct pt_regs *regs) -{ - /* Saved main processor registers. */ - printk("$0 : %016lx %016lx %016lx %016lx\n", - 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); - printk("$4 : %016lx %016lx %016lx %016lx\n", - regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - printk("$8 : %016lx %016lx %016lx %016lx\n", - regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); - printk("$12 : %016lx %016lx %016lx %016lx\n", - regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); - printk("$16 : %016lx %016lx %016lx %016lx\n", - regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); - printk("$20 : %016lx %016lx %016lx %016lx\n", - regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); - printk("$24 : %016lx %016lx\n", - regs->regs[24], regs->regs[25]); - printk("$28 : %016lx %016lx %016lx %016lx\n", - regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); - printk("Hi : %016lx\n", regs->hi); - printk("Lo : %016lx\n", regs->lo); - - /* Saved cp0 registers. */ - printk("epc : %016lx %s\nbadvaddr: %016lx\n", - regs->cp0_epc, print_tainted(), regs->cp0_badvaddr); - printk("Status : %08x\nCause : %08x\n", - (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause); -} - /* Detect and size the various r4k caches. */ static void __init probe_icache(unsigned long config) { @@ -2369,16 +2335,16 @@ printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); #ifdef CONFIG_MIPS_UNCACHED - set_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); #else - set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); #endif /* UNCACHED */ probe_icache(config); probe_dcache(config); setup_scache(config); - switch(mips_cputype) { + switch(mips_cpu.cputype) { case CPU_R4600: /* QED style two way caches? */ case CPU_R4700: case CPU_R5000: @@ -2391,15 +2357,9 @@ _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; } - _flush_tlb_all = r4k_flush_tlb_all; - _flush_tlb_mm = r4k_flush_tlb_mm; - _flush_tlb_range = r4k_flush_tlb_range; - _flush_tlb_page = r4k_flush_tlb_page; _flush_cache_l2 = r4k_flush_cache_l2; - update_mmu_cache = r4k_update_mmu_cache; - - _show_regs = r4k_show_regs; + _update_mmu_cache = r4k_update_mmu_cache; flush_cache_l1(); @@ -2411,5 +2371,5 @@ * be set for 4kb pages. */ write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); - _flush_tlb_all(); + local_flush_tlb_all(); } diff -urN linux-2.4.18/arch/mips64/mm/tlb-dbg-r4k.c linux-2.4.19-pre5/arch/mips64/mm/tlb-dbg-r4k.c --- linux-2.4.18/arch/mips64/mm/tlb-dbg-r4k.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/tlb-dbg-r4k.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,71 @@ +/* + * 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) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * TLB debugging routines. These perform horribly slow but can easily be + * modified for debugging purposes. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, + unsigned long address); + +asmlinkage void tlb_refill_debug(struct pt_regs regs) +{ + show_regs(®s); + panic(__FUNCTION__ " called. This Does Not Happen (TM)."); +} + +asmlinkage void xtlb_refill_debug(struct pt_regs *regs) +{ + unsigned long addr; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + addr = regs->cp0_badvaddr & ~((PAGE_SIZE << 1) - 1); + pgd = pgd_offset(current->active_mm, addr); + pmd = pmd_offset(pgd, addr); + pte = pte_offset(pmd, addr); + + set_entrylo0(pte_val(pte[0]) >> 6); + set_entrylo1(pte_val(pte[1]) >> 6); + __asm__ __volatile__("nop;nop;nop"); + + tlb_write_random(); +} + +asmlinkage void xtlb_mod_debug(struct pt_regs *regs) +{ + unsigned long addr; + + addr = regs->cp0_badvaddr; + do_page_fault(regs, 1, addr); +} + +asmlinkage void xtlb_tlbl_debug(struct pt_regs *regs) +{ + unsigned long addr; + + addr = regs->cp0_badvaddr; + do_page_fault(regs, 0, addr); +} + +asmlinkage void xtlb_tlbs_debug(struct pt_regs *regs) +{ + unsigned long addr; + + addr = regs->cp0_badvaddr; + do_page_fault(regs, 1, addr); +} diff -urN linux-2.4.18/arch/mips64/mm/tlb-glue-r4k.S linux-2.4.19-pre5/arch/mips64/mm/tlb-glue-r4k.S --- linux-2.4.18/arch/mips64/mm/tlb-glue-r4k.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/tlb-glue-r4k.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,38 @@ +/* + * 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) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#define __ASSEMBLY__ +#include +#include +#include +#include + + .macro __BUILD_cli + CLI + .endm + + .macro __BUILD_sti + STI + .endm + + .macro tlb_handler name interruptible writebit + NESTED(__\name, PT_SIZE, sp) + SAVE_ALL + dmfc0 a2, CP0_BADVADDR + __BUILD_\interruptible + li a1, \writebit + sd a2, PT_BVADDR(sp) + move a0, sp + jal do_page_fault + j ret_from_exception + END(__\name) + .endm + + tlb_handler xtlb_mod sti 1 + tlb_handler xtlb_tlbl sti 0 + tlb_handler xtlb_tlbs sti 1 diff -urN linux-2.4.18/arch/mips64/mm/tlb-sb1.c linux-2.4.19-pre5/arch/mips64/mm/tlb-sb1.c --- linux-2.4.18/arch/mips64/mm/tlb-sb1.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/tlb-sb1.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,305 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include + +/* Dump the current entry* and pagemask registers */ +static inline void dump_cur_tlb_regs(void) +{ + unsigned int entryhihi, entryhilo, entrylo0hi, entrylo0lo, entrylo1hi; + unsigned int entrylo1lo, pagemask; + + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + "#.set mips64 \n" + ".set mips4 \n" + ".set noat \n" + " tlbr \n" + " dmfc0 $1, $10 \n" + " dsrl32 %0, $1, 0 \n" + " sra %1, $1, 0 \n" + " dmfc0 $1, $2 \n" + " dsrl32 %2, $1, 0 \n" + " sra %3, $1, 0 \n" + " dmfc0 $1, $3 \n" + " dsrl32 %4, $1, 0 \n" + " sra %5, $1, 0 \n" + " mfc0 %6, $5 \n" + ".set pop \n" + : "=r" (entryhihi), + "=r" (entryhilo), + "=r" (entrylo0hi), + "=r" (entrylo0lo), + "=r" (entrylo1hi), + "=r" (entrylo1lo), + "=r" (pagemask)); + printk("%08X%08X %08X%08X %08X%08X %08X", + entryhihi, entryhilo, + entrylo0hi, entrylo0lo, + entrylo1hi, entrylo1lo, + pagemask); +} + +void sb1_dump_tlb(void) +{ + int entry; + printk("Current TLB registers state:\n" + " EntryHi EntryLo0 EntryLo1 PageMask Index\n" + "--------------------------------------------------------------------\n"); + dump_cur_tlb_regs(); + printk(" %08X\n", read_32bit_cp0_register(CP0_INDEX)); + printk("\n\nFull TLB Dump:" + "Idx EntryHi EntryLo0 EntryLo1 PageMask\n" + "--------------------------------------------------------------\n"); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + set_index(entry); + printk("\n%02i ", entry); + __asm__ __volatile__ ( + ".set push \n" + "#.set mips64 \n" + ".set mips4 \n" + " tlbr \n" + ".set pop \n"); + dump_cur_tlb_regs(); + } + printk("\n"); +} + +void local_flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entrylo0(0); + set_entrylo1(0); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry); + set_index(entry); + tlb_write_indexed(); + } + set_entryhi(old_ctx); + __restore_flags(flags); +} + + +/* + * Use a bogus region of memory (starting at 0) to sanitize the TLB's. + * Use increments of the maximum page size (16MB), and check for duplicate + * entries before doing a given write. Then, when we're safe from collisions + * with the firmware, go back and give all the entries invalid addresses with + * the normal flush routine. + */ +void sb1_sanitize_tlb(void) +{ + int entry; + long addr = 0; + + long inc = 1<<24; /* 16MB */ + /* Save old context and create impossible VPN2 value */ + set_entrylo0(0); + set_entrylo1(0); + for (entry = 0; entry < mips_cpu.tlbsize; entry++) { + do { + addr += inc; + set_entryhi(addr); + tlb_probe(); + } while ((int)(get_index()) >= 0); + set_index(entry); + tlb_write_indexed(); + } + /* Now that we know we're safe from collisions, we can safely flush + the TLB with the "normal" routine. */ + local_flush_tlb_all(); +} + + +void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + unsigned long flags; + int cpu; + + __save_and_cli(flags); + cpu = smp_processor_id(); + if(CPU_CONTEXT(cpu, mm) != 0) { + int size; + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if(size <= (mips_cpu.tlbsize/2)) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (CPU_CONTEXT(cpu, mm) & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0 + (idx << (PAGE_SHIFT+1))); + if(idx < 0) + continue; + tlb_write_indexed(); + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, cpu); + if (mm == current->active_mm) + set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff); + } + } + __restore_flags(flags); +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long flags; + +#ifdef CONFIG_SMP + /* + * This variable is eliminated from CPU_CONTEXT() if SMP isn't defined, + * so conditional it to get rid of silly "unused variable" compiler + * complaints + */ + int cpu = smp_processor_id(); +#endif + + __save_and_cli(flags); + if (CPU_CONTEXT(cpu, vma->vm_mm) != 0) { + int oldpid, newpid, idx; +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", CPU_CONTEXT(cpu, vma->vm_mm), page); +#endif + newpid = (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff); + page &= (PAGE_MASK << 1); + oldpid = (get_entryhi() & 0xff); + set_entryhi (page | newpid); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + if(idx < 0) + goto finish; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1))); + tlb_write_indexed(); + finish: + set_entryhi(oldpid); + } + __restore_flags(flags); +} + + +/* All entries common to a mm share an asid. To effectively flush + these entries, we just bump the asid. */ +void local_flush_tlb_mm(struct mm_struct *mm) +{ + unsigned long flags; + int cpu; + __save_and_cli(flags); + cpu = smp_processor_id(); + if (CPU_CONTEXT(cpu, mm) != 0) { + get_new_mmu_context(mm, smp_processor_id()); + if (mm == current->active_mm) { + set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff); + } + } + __restore_flags(flags); +} + +/* Stolen from mips32 routines */ + +void sb1_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, + pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + __save_and_cli(flags); + + + pid = get_entryhi() & 0xff; + +#ifdef DEBUG_TLB + if((pid != (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff)) || (CPU_CONTEXT(cpu, vma->vm_mm) == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff), pid); + } +#endif + + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + tlb_probe(); + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + if (idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + set_entryhi(pid); + __restore_flags(flags); +} + +/* + * This is called from loadmmu.c. We have to set up all the + * memory management function pointers, as well as initialize + * the caches and tlbs + */ +void sb1_tlb_init(void) +{ + u32 config1; + + config1 = read_mips32_cp0_config1(); + mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1; + + /* + * We don't know what state the firmware left the TLB's in, so this is + * the ultra-conservative way to flush the TLB's and avoid machine + * check exceptions due to duplicate TLB entries + */ + sb1_sanitize_tlb(); + _update_mmu_cache = sb1_update_mmu_cache; +} diff -urN linux-2.4.18/arch/mips64/mm/tlbex-r4k.S linux-2.4.19-pre5/arch/mips64/mm/tlbex-r4k.S --- linux-2.4.18/arch/mips64/mm/tlbex-r4k.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/mm/tlbex-r4k.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,136 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Silicon Graphics, Inc. + * Written by Ulf Carlsson (ulfc@engr.sgi.com) + */ +#define __ASSEMBLY__ +#include +#include +#include +#include +#include +#include +#include +#include + + .data + .comm pgd_current, NR_CPUS * 8, 8 + + /* + * After this macro runs we have a pointer to the pte of the address + * that caused the fault in in PTR. + */ + + .macro LOAD_PTE2, ptr, tmp +#ifdef CONFIG_SMP + dmfc0 \tmp, CP0_CONTEXT + dla \ptr, pgd_current + dsrl \tmp, 23 + daddu \ptr, \tmp +#else + dla \ptr, pgd_current +#endif + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) + bltz \tmp, kaddr + dsrl \tmp, (PGDIR_SHIFT-3) # get pgd offset in bytes + andi \tmp, ((PTRS_PER_PGD - 1)<<3) + daddu \ptr, \tmp # add in pgd offset + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) # get pmd pointer + dsrl \tmp, (PMD_SHIFT-3) # get pmd offset in bytes + andi \tmp, ((PTRS_PER_PMD - 1)<<3) + daddu \ptr, \tmp # add in pmd offset + dmfc0 \tmp, CP0_XCONTEXT + ld \ptr, (\ptr) # get pte pointer + andi \tmp, 0xff0 # get pte offset + daddu \ptr, \tmp + .endm + + /* + * This places the even/odd pte pair in the page table at the pte + * entry pointed to by PTE into ENTRYLO0 and ENTRYLO1. + */ + .macro PTE_RELOAD, pte0, pte1 + dsrl \pte0, 6 # convert to entrylo0 + dmtc0 \pte0, CP0_ENTRYLO0 # load it + dsrl \pte1, 6 # convert to entrylo1 + dmtc0 \pte1, CP0_ENTRYLO1 # load it + .endm + + .text + .set noreorder + .set mips3 + + __INIT + + .align 5 +FEXPORT(except_vec0) + .set noat + PANIC("Unused vector called") +1: b 1b + nop + + /* + * TLB refill handler for the R10000. + * Attention: We may only use 32 instructions / 128 bytes. + */ + + .align 5 +LEAF(except_vec1_r10k) + .set noat + LOAD_PTE2 k1 k0 + ld k0, 0(k1) # get even pte + ld k1, 8(k1) # get odd pte + PTE_RELOAD k0 k1 + nop + tlbwr + eret +kaddr: + dla k0, handle_vmalloc_address # MAPPED kernel needs this + jr k0 + nop + END(except_vec1_r10k) + + __FINIT + + .align 5 +LEAF(handle_vmalloc_address) + .set noat + /* + * First, determine that the address is in/above vmalloc range. + */ + dmfc0 k0, CP0_BADVADDR + dli k1, VMALLOC_START + + /* + * Now find offset into kptbl. + */ + dsubu k0, k0, k1 + dla k1, kptbl + dsrl k0, (PAGE_SHIFT+1) # get vpn2 + dsll k0, 4 # byte offset of pte + daddu k1, k1, k0 + + /* + * Determine that fault address is within vmalloc range. + */ + dla k0, ekptbl + sltu k0, k1, k0 + beqz k0, not_vmalloc + + /* + * Load cp0 registers. + */ + ld k0, 0(k1) # get even pte + ld k1, 8(k1) # get odd pte + +not_vmalloc: + PTE_RELOAD k0 k1 + nop + tlbwr + eret + END(handle_vmalloc_address) diff -urN linux-2.4.18/arch/mips64/sgi-ip22/Makefile linux-2.4.19-pre5/arch/mips64/sgi-ip22/Makefile --- linux-2.4.18/arch/mips64/sgi-ip22/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/Makefile Thu Jan 1 01:00:00 1970 @@ -1,16 +0,0 @@ -# -# Makefile for the SGI specific kernel interface routines -# under Linux. -# - -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -L_TARGET = ip22.a - -obj-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ - ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-berr.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-berr.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-berr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-berr.c Thu Jan 1 01:00:00 1970 @@ -1,125 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 by Silicon Graphics - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -extern asmlinkage void handle_ibe(void); -extern asmlinkage void handle_dbe(void); - -extern const struct exception_table_entry __start___dbe_table[]; -extern const struct exception_table_entry __stop___dbe_table[]; - -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid->nextinsn; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return 0; -} - -extern spinlock_t modlist_lock; - -static inline unsigned long -search_dbe_table(unsigned long addr) -{ - unsigned long ret = 0; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr); - return ret; -#else - unsigned long flags; - - /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - struct archdata *ap; - - spin_lock_irqsave(&modlist_lock, flags); - for (mp = module_list; mp != NULL; mp = mp->next) { - if (!mod_member_present(mp, archdata_end) || - !mod_archdata_member_present(mp, struct archdata, - dbe_table_end)) - continue; - ap = (struct archdata *)(mod->archdata_start); - - if (ap->dbe_table_start == NULL || - !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING))) - continue; - ret = search_one_table(ap->dbe_table_start, - ap->dbe_table_end - 1, addr); - if (ret) - break; - } - spin_unlock_irqrestore(&modlist_lock, flags); - return ret; -#endif -} - -void do_ibe(struct pt_regs *regs) -{ - printk("Got ibe at 0x%lx\n", regs->cp0_epc); - show_regs(regs); - dump_tlb_addr(regs->cp0_epc); - force_sig(SIGBUS, current); - while(1); -} - -void do_dbe(struct pt_regs *regs) -{ - unsigned long fixup; - - fixup = search_dbe_table(regs->cp0_epc); - if (fixup) { - long new_epc; - - new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); - regs->cp0_epc = new_epc; - return; - } - - printk("Got dbe at 0x%lx\n", regs->cp0_epc); - show_regs(regs); - dump_tlb_all(); - while(1); - force_sig(SIGBUS, current); -} - -void __init -bus_error_init(void) -{ - int dummy; - - set_except_vector(6, handle_ibe); - set_except_vector(7, handle_dbe); - - /* At this time nothing uses the DBE protection mechanism on the - Indy, so this here is needed to make the kernel link. */ - get_dbe(dummy, (int *)KSEG0); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-hpc.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-hpc.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-hpc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-hpc.c Thu Jan 1 01:00:00 1970 @@ -1,104 +0,0 @@ -/* - * ip22-hpc.c: Routines for generic manipulation of the HPC controllers. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1998, 1999, 2001 Ralf Baechle - */ -#include -#include - -#include -#include -#include -#include - -#undef DEBUG_SGIHPC - -struct hpc3_regs *hpc3c0, *hpc3c1; -struct hpc3_miscregs *hpc3mregs; - -/* We need software copies of these because they are write only. */ -unsigned int sgi_hpc_write1, sgi_hpc_write2; - -/* Machine specific identifier knobs. */ -int sgi_has_ioc2 = 0; -int sgi_guiness = 0; -int sgi_boardid; - -void __init sgihpc_init(void) -{ - unsigned long sid, crev, brev; - - hpc3c0 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP0_PBASE); - hpc3c1 = (struct hpc3_regs *) (KSEG1 + HPC3_CHIP1_PBASE); - hpc3mregs = (struct hpc3_miscregs *) (KSEG1 + HPC3_MREGS_PBASE); - sid = hpc3mregs->sysid; - - sid &= 0xff; - crev = (sid & 0xe0) >> 5; - brev = (sid & 0x1e) >> 1; - -#ifdef DEBUG_SGIHPC - prom_printf("sgihpc_init: crev<%2x> brev<%2x>\n", crev, brev); - prom_printf("sgihpc_init: "); -#endif - - /* This test works now thanks to William J. Earl */ - if ((sid & 1) == 0 ) { -#ifdef DEBUG_SGIHPC - prom_printf("GUINESS "); -#endif - sgi_guiness = 1; - mips_machtype = MACH_SGI_INDY; - } else { -#ifdef DEBUG_SGIHPC - prom_printf("FULLHOUSE "); -#endif - mips_machtype = MACH_SGI_INDIGO2; - sgi_guiness = 0; - } - sgi_boardid = brev; - -#ifdef DEBUG_SGIHPC - prom_printf("sgi_boardid<%d> ", sgi_boardid); -#endif - - if(crev == 1) { - if((sid & 1) || (brev >= 2)) { -#ifdef DEBUG_SGIHPC - prom_printf("IOC2 "); -#endif - sgi_has_ioc2 = 1; - } else { -#ifdef DEBUG_SGIHPC - prom_printf("IOC1 revision 1 "); -#endif - } - } else { -#ifdef DEBUG_SGIHPC - prom_printf("IOC1 revision 0 "); -#endif - } -#ifdef DEBUG_SGIHPC - prom_printf("\n"); -#endif - - sgi_hpc_write1 = (HPC3_WRITE1_PRESET | - HPC3_WRITE1_KMRESET | - HPC3_WRITE1_ERESET | - HPC3_WRITE1_LC0OFF); - - sgi_hpc_write2 = (HPC3_WRITE2_EASEL | - HPC3_WRITE2_NTHRESH | - HPC3_WRITE2_TPSPEED | - HPC3_WRITE2_EPSEL | - HPC3_WRITE2_U0AMODE | - HPC3_WRITE2_U1AMODE); - - if(!sgi_guiness) - sgi_hpc_write1 |= HPC3_WRITE1_GRESET; - hpc3mregs->write1 = sgi_hpc_write1; - hpc3mregs->write2 = sgi_hpc_write2; - - hpc3c0->pbus_piocfgs[0][6] |= HPC3_PIOPCFG_HW; -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-int.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-int.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-int.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-int.c Thu Jan 1 01:00:00 1970 @@ -1,608 +0,0 @@ -/* - * indy_int.c: Routines for generic manipulation of the INT[23] ASIC - * found on INDY workstations.. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes - */ -#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 - -/* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. - */ - -struct sgi_int2_regs *sgi_i2regs; -struct sgi_int3_regs *sgi_i3regs; -struct sgi_ioc_ints *ioc_icontrol; -struct sgi_ioc_timers *ioc_timers; -volatile unsigned char *ioc_tclear; - -static char lc0msk_to_irqnr[256]; -static char lc1msk_to_irqnr[256]; -static char lc2msk_to_irqnr[256]; -static char lc3msk_to_irqnr[256]; - -extern asmlinkage void indyIRQ(void); - -#ifdef CONFIG_REMOTE_DEBUG -extern void rs_kgdb_hook(int); -#endif - -unsigned long spurious_count = 0; - -/* Local IRQ's are layed out logically like this: - * - * 0 --> 7 == local 0 interrupts - * 8 --> 15 == local 1 interrupts - * 16 --> 23 == vectored level 2 interrupts - * 24 --> 31 == vectored level 3 interrupts (not used) - */ -void disable_local_irq(unsigned int irq_nr) -{ - unsigned long flags; - - save_and_cli(flags); - switch(irq_nr) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - ioc_icontrol->imask0 &= ~(1 << irq_nr); - break; - - case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: - ioc_icontrol->imask1 &= ~(1 << (irq_nr - 8)); - break; - - case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: - ioc_icontrol->cmeimask0 &= ~(1 << (irq_nr - 16)); - break; - - default: - /* This way we'll see if anyone would ever want vectored - * level 3 interrupts. Highly unlikely. - */ - printk("Yeeee, got passed irq_nr %d at disable_irq\n", irq_nr); - panic("INVALID IRQ level!"); - }; - restore_flags(flags); -} - -void enable_local_irq(unsigned int irq_nr) -{ - unsigned long flags; - save_and_cli(flags); - switch(irq_nr) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - ioc_icontrol->imask0 |= (1 << irq_nr); - break; - - case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: - ioc_icontrol->imask1 |= (1 << (irq_nr - 8)); - break; - - case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: - enable_local_irq(7); - ioc_icontrol->cmeimask0 |= (1 << (irq_nr - 16)); - break; - - default: - printk("Yeeee, got passed irq_nr %d at disable_irq\n", irq_nr); - panic("INVALID IRQ level!"); - }; - restore_flags(flags); -} - -void disable_gio_irq(unsigned int irq_nr) -{ - /* XXX TODO XXX */ -} - -void enable_gio_irq(unsigned int irq_nr) -{ - /* XXX TODO XXX */ -} - -void disable_hpcdma_irq(unsigned int irq_nr) -{ - /* XXX TODO XXX */ -} - -void enable_hpcdma_irq(unsigned int irq_nr) -{ - /* XXX TODO XXX */ -} - -void disable_irq(unsigned int irq_nr) -{ - unsigned int n = irq_nr; - if(n >= SGINT_END) { - printk("whee, invalid irq_nr %d\n", irq_nr); - panic("IRQ, you lose..."); - } - if(n >= SGINT_LOCAL0 && n < SGINT_GIO) { - disable_local_irq(n - SGINT_LOCAL0); - } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) { - disable_gio_irq(n - SGINT_GIO); - } else if(n >= SGINT_HPCDMA && n < SGINT_END) { - disable_hpcdma_irq(n - SGINT_HPCDMA); - } else { - panic("how did I get here?"); - } -} - -void enable_irq(unsigned int irq_nr) -{ - unsigned int n = irq_nr; - if(n >= SGINT_END) { - printk("whee, invalid irq_nr %d\n", irq_nr); - panic("IRQ, you lose..."); - } - if(n >= SGINT_LOCAL0 && n < SGINT_GIO) { - enable_local_irq(n - SGINT_LOCAL0); - } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) { - enable_gio_irq(n - SGINT_GIO); - } else if(n >= SGINT_HPCDMA && n < SGINT_END) { - enable_hpcdma_irq(n - SGINT_HPCDMA); - } else { - panic("how did I get here?"); - } -} - -#if 0 -/* - * Currently unused. - */ -static void local_unex(int irq, void *data, struct pt_regs *regs) -{ - printk("Whee: unexpected local IRQ at %08lx\n", - (unsigned long) regs->cp0_epc); - printk("DUMP: stat0<%x> stat1<%x> vmeistat<%x>\n", - ioc_icontrol->istat0, ioc_icontrol->istat1, - ioc_icontrol->vmeistat); -} -#endif - -static struct irqaction *local_irq_action[24] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -int setup_indy_irq(int irq, struct irqaction * new) -{ - printk("setup_indy_irq: Yeee, don't know how to setup irq<%d> for %s %p\n", - irq, new->name, new->handler); - return 0; -} - -static struct irqaction r4ktimer_action = { - NULL, 0, 0, "R4000 timer/counter", NULL, NULL, -}; - -static struct irqaction indy_berr_action = { - NULL, 0, 0, "IP22 Bus Error", NULL, NULL, -}; - -static struct irqaction *irq_action[16] = { - NULL, NULL, NULL, NULL, - NULL, NULL, &indy_berr_action, &r4ktimer_action, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -int get_irq_list(char *buf) -{ - int i, len = 0; - int num = 0; - struct irqaction * action; - - for (i = 0 ; i < 16 ; i++, num++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [on-chip]\n"); - } - for (i = 0 ; i < 24 ; i++, num++) { - action = local_irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - num, kstat.irqs[0][num], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, " [local]\n"); - } - return len; -} - -/* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. - */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) -{ - struct irqaction *action; - int do_random, cpu; - - cpu = smp_processor_id(); - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - - panic(KERN_DEBUG "Got irq %d, press a key.", irq); - - /* - * mask and ack quickly, we don't want the irq controller - * thinking we're snobs just because some other CPU has - * disabled global interrupts (we have already done the - * INT_ACK cycles, it's too late to try to pretend to the - * controller that we aren't taking the interrupt). - * - * Commented out because we've already done this in the - * machinespecific part of the handler. It's reasonable to - * do this here in a highlevel language though because that way - * we could get rid of a good part of duplicated code ... - */ - /* mask_and_ack_irq(irq); */ - - action = *(irq + irq_action); - if (action) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - action = *(irq + irq_action); - do_random = 0; - do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - } - irq_exit(cpu, irq); - - /* unmasking and bottom half handling is done magically for us. */ -} - -int request_local_irq(unsigned int lirq, void (*func)(int, void *, struct pt_regs *), - unsigned long iflags, const char *dname, void *devid) -{ - struct irqaction *action; - - lirq -= SGINT_LOCAL0; - if(lirq >= 24 || !func) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if(!action) - return -ENOMEM; - - action->handler = func; - action->flags = iflags; - action->mask = 0; - action->name = dname; - action->dev_id = devid; - action->next = 0; - local_irq_action[lirq] = action; - enable_irq(lirq + SGINT_LOCAL0); - return 0; -} - -void free_local_irq(unsigned int lirq, void *dev_id) -{ - struct irqaction *action; - - lirq -= SGINT_LOCAL0; - if(lirq >= 24) { - printk("Aieee: trying to free bogus local irq %d\n", - lirq + SGINT_LOCAL0); - return; - } - action = local_irq_action[lirq]; - local_irq_action[lirq] = NULL; - disable_irq(lirq + SGINT_LOCAL0); - kfree(action); -} - -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - int retval; - struct irqaction * action; - - if (irq >= SGINT_END) - return -EINVAL; - if (!handler) - return -EINVAL; - - if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO)) - return request_local_irq(irq, handler, irqflags, devname, dev_id); - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_indy_irq(irq, action); - - if (retval) - kfree(action); - return retval; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction * action, **p; - unsigned long flags; - - if (irq >= SGINT_END) { - printk("Trying to free IRQ%d\n",irq); - return; - } - if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO)) { - free_local_irq(irq, dev_id); - return; - } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - restore_flags(flags); - kfree(action); - return; - } - printk("Trying to free free IRQ%d\n",irq); -} - -void indy_local0_irqdispatch(struct pt_regs *regs) -{ - struct irqaction *action; - unsigned char mask = ioc_icontrol->istat0; - unsigned char mask2 = 0; - int irq, cpu = smp_processor_id();; - - mask &= ioc_icontrol->imask0; - if(mask & ISTAT0_LIO2) { - mask2 = ioc_icontrol->vmeistat; - mask2 &= ioc_icontrol->cmeimask0; - irq = lc2msk_to_irqnr[mask2]; - action = local_irq_action[irq]; - } else { - irq = lc0msk_to_irqnr[mask]; - action = local_irq_action[irq]; - } - - irq_enter(cpu, irq); - kstat.irqs[0][irq + 16]++; - action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); -} - -void indy_local1_irqdispatch(struct pt_regs *regs) -{ - struct irqaction *action; - unsigned char mask = ioc_icontrol->istat1; - unsigned char mask2 = 0; - int irq, cpu = smp_processor_id();; - - mask &= ioc_icontrol->imask1; - if(mask & ISTAT1_LIO3) { - printk("WHee: Got an LIO3 irq, winging it...\n"); - mask2 = ioc_icontrol->vmeistat; - mask2 &= ioc_icontrol->cmeimask1; - irq = lc3msk_to_irqnr[ioc_icontrol->vmeistat]; - action = local_irq_action[irq]; - } else { - irq = lc1msk_to_irqnr[mask]; - action = local_irq_action[irq]; - } - irq_enter(cpu, irq); - kstat.irqs[0][irq + 24]++; - action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); -} - -void indy_buserror_irq(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - int irq = 6; - - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - printk("Got a bus error IRQ, shouldn't happen yet\n"); - show_regs(regs); - printk("Spinning...\n"); - while(1); - irq_exit(cpu, irq); -} - -/* Misc. crap just to keep the kernel linking... */ -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -static inline void sgint_init(void) -{ - int i; -#ifdef CONFIG_REMOTE_DEBUG - char *ctype; -#endif - - sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE); - sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE); - - /* Init local mask --> irq tables. */ - for(i = 0; i < 256; i++) { - if(i & 0x80) { - lc0msk_to_irqnr[i] = 7; - lc1msk_to_irqnr[i] = 15; - lc2msk_to_irqnr[i] = 23; - lc3msk_to_irqnr[i] = 31; - } else if(i & 0x40) { - lc0msk_to_irqnr[i] = 6; - lc1msk_to_irqnr[i] = 14; - lc2msk_to_irqnr[i] = 22; - lc3msk_to_irqnr[i] = 30; - } else if(i & 0x20) { - lc0msk_to_irqnr[i] = 5; - lc1msk_to_irqnr[i] = 13; - lc2msk_to_irqnr[i] = 21; - lc3msk_to_irqnr[i] = 29; - } else if(i & 0x10) { - lc0msk_to_irqnr[i] = 4; - lc1msk_to_irqnr[i] = 12; - lc2msk_to_irqnr[i] = 20; - lc3msk_to_irqnr[i] = 28; - } else if(i & 0x08) { - lc0msk_to_irqnr[i] = 3; - lc1msk_to_irqnr[i] = 11; - lc2msk_to_irqnr[i] = 19; - lc3msk_to_irqnr[i] = 27; - } else if(i & 0x04) { - lc0msk_to_irqnr[i] = 2; - lc1msk_to_irqnr[i] = 10; - lc2msk_to_irqnr[i] = 18; - lc3msk_to_irqnr[i] = 26; - } else if(i & 0x02) { - lc0msk_to_irqnr[i] = 1; - lc1msk_to_irqnr[i] = 9; - lc2msk_to_irqnr[i] = 17; - lc3msk_to_irqnr[i] = 25; - } else if(i & 0x01) { - lc0msk_to_irqnr[i] = 0; - lc1msk_to_irqnr[i] = 8; - lc2msk_to_irqnr[i] = 16; - lc3msk_to_irqnr[i] = 24; - } else { - lc0msk_to_irqnr[i] = 0; - lc1msk_to_irqnr[i] = 0; - lc2msk_to_irqnr[i] = 0; - lc3msk_to_irqnr[i] = 0; - } - } - - /* Indy uses an INT3, Indigo2 uses an INT2 */ - if (sgi_guiness) { - ioc_icontrol = &sgi_i3regs->ints; - ioc_timers = &sgi_i3regs->timers; - ioc_tclear = &sgi_i3regs->tclear; - } else { - ioc_icontrol = &sgi_i2regs->ints; - ioc_timers = &sgi_i2regs->timers; - ioc_tclear = &sgi_i2regs->tclear; - } - - /* Mask out all interrupts. */ - ioc_icontrol->imask0 = 0; - ioc_icontrol->imask1 = 0; - ioc_icontrol->cmeimask0 = 0; - ioc_icontrol->cmeimask1 = 0; - - /* Now safe to set the exception vector. */ - set_except_vector(0, indyIRQ); - -#ifdef CONFIG_REMOTE_DEBUG - ctype = prom_getcmdline(); - for(i = 0; i < strlen(ctype); i++) { - if(ctype[i]=='k' && ctype[i+1]=='g' && - ctype[i+2]=='d' && ctype[i+3]=='b' && - ctype[i+4]=='=' && ctype[i+5]=='t' && - ctype[i+6]=='t' && ctype[i+7]=='y' && - ctype[i+8]=='d' && - (ctype[i+9] == '1' || ctype[i+9] == '2')) { - printk("KGDB: Using serial line /dev/ttyd%d for " - "session\n", (ctype[i+9] - '0')); - if(ctype[i+9]=='1') - rs_kgdb_hook(1); - else if(ctype[i+9]=='2') - rs_kgdb_hook(0); - else { - printk("KGDB: whoops bogon tty line " - "requested, disabling session\n"); - } - - } - } -#endif -} - -void __init init_IRQ(void) -{ - sgint_init(); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-irq.S linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-irq.S --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-irq.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-irq.S Thu Jan 1 01:00:00 1970 @@ -1,128 +0,0 @@ -/* - * 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. - * - * indyIRQ.S: Interrupt exception dispatch code for FullHouse and - * Guiness. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include -#include -#include -#include - -/* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop and moving across - * all the pending IRQ bits in the cause register is _NOT_ the answer, the - * common case is one pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register IRQ mask, that - * would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in - * between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the INDY look basically (barring software IRQs - * which we don't use at all) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Local IRQ level zero - * 3 Local IRQ level one - * 4 8254 Timer zero - * 5 8254 Timer one - * 6 Bus Error - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Local IRQ zero - * Local IRQ one - * Bus Error - * 8254 Timer zero - * Lowest ---- 8254 Timer one - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - - .text - .set noreorder - .set noat - .align 5 - NESTED(indyIRQ, PT_SIZE, sp) - SAVE_ALL - CLI - .set at - mfc0 s0, CP0_CAUSE # get irq mask - - /* First we check for r4k counter/timer IRQ. */ - andi a0, s0, CAUSEF_IP7 - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero - - /* Wheee, a timer interrupt. */ - move a0, sp - jal indy_timer_interrupt - nop # delay slot - - j ret_from_irq - nop # delay slot - -1: - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP3 # delay slot, check local level one - - /* Wheee, local level zero interrupt. */ - jal indy_local0_irqdispatch - move a0, sp # delay slot - - j ret_from_irq - nop # delay slot - -1: - beq a0, zero, 1f - andi a0, s0, CAUSEF_IP6 # delay slot, check bus error - - /* Wheee, local level one interrupt. */ - move a0, sp - jal indy_local1_irqdispatch - nop - - j ret_from_irq - nop - -1: - beq a0, zero, 1f - nop - - /* Wheee, an asynchronous bus error... */ - move a0, sp - jal indy_buserror_irq - nop - - j ret_from_irq - nop - -1: - /* Here by mistake? This is possible, what can happen - * is that by the time we take the exception the IRQ - * pin goes low, so just leave if this is the case. - */ - andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) - beq a0, zero, 1f - - /* Must be one of the 8254 timers... */ - move a0, sp - jal indy_8254timer_irq - nop -1: - j ret_from_irq - nop - END(indyIRQ) diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-mc.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-mc.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-mc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-mc.c Thu Jan 1 01:00:00 1970 @@ -1,158 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 2001 Ralf Baechle (ralf@gnu.org) - */ -#include -#include - -#include -#include -#include -#include - -/* #define DEBUG_SGIMC */ - -struct sgimc_misc_ctrl *mcmisc_regs; -u32 *rpsscounter; -struct sgimc_dma_ctrl *dmactrlregs; - -static inline char *mconfig_string(unsigned long val) -{ - switch(val & SGIMC_MCONFIG_RMASK) { - case SGIMC_MCONFIG_FOURMB: - return "4MB"; - - case SGIMC_MCONFIG_EIGHTMB: - return "8MB"; - - case SGIMC_MCONFIG_SXTEENMB: - return "16MB"; - - case SGIMC_MCONFIG_TTWOMB: - return "32MB"; - - case SGIMC_MCONFIG_SFOURMB: - return "64MB"; - - case SGIMC_MCONFIG_OTEIGHTMB: - return "128MB"; - - default: - return "wheee, unknown"; - }; -} - -void __init sgimc_init(void) -{ - unsigned long tmpreg; - - mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); - rpsscounter = (u32 *) (KSEG1 + 0x1fa01004); - dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000); - - printk("MC: SGI memory controller Revision %d\n", - (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV); - -#if 0 /* XXX Until I figure out what this bit really indicates XXX */ - /* XXX Is this systemid bit reliable? */ - if(mcmisc_regs->systemid & SGIMC_SYSID_EPRESENT) { - EISA_bus = 1; - printk("with EISA\n"); - } else { - EISA_bus = 0; - printk("no EISA\n"); - } -#endif - -#ifdef DEBUG_SGIMC - prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n", - mconfig_string(mcmisc_regs->mconfig0), - mconfig_string(mcmisc_regs->mconfig1)); - - prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n", - mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1); - prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n", - mcmisc_regs->divider, mcmisc_regs->gioparm); -#endif - - /* Place the MC into a known state. This must be done before - * interrupts are first enabled etc. - */ - - /* Step 1: The CPU/GIO error status registers will not latch - * up a new error status until the register has been - * cleared by the cpu. These status registers are - * cleared by writing any value to them. - */ - mcmisc_regs->cstat = mcmisc_regs->gstat = 0; - - /* Step 2: Enable all parity checking in cpu control register - * zero. - */ - tmpreg = mcmisc_regs->cpuctrl0; - tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | - SGIMC_CCTRL0_R4KNOCHKPARR); - mcmisc_regs->cpuctrl0 = tmpreg; - - /* Step 3: Setup the MC write buffer depth, this is controlled - * in cpu control register 1 in the lower 4 bits. - */ - tmpreg = mcmisc_regs->cpuctrl1; - tmpreg &= ~0xf; - tmpreg |= 0xd; - mcmisc_regs->cpuctrl1 = tmpreg; - - /* Step 4: Initialize the RPSS divider register to run as fast - * as it can correctly operate. The register is laid - * out as follows: - * - * ---------------------------------------- - * | RESERVED | INCREMENT | DIVIDER | - * ---------------------------------------- - * 31 16 15 8 7 0 - * - * DIVIDER determines how often a 'tick' happens, - * INCREMENT determines by how the RPSS increment - * registers value increases at each 'tick'. Thus, - * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 - */ - mcmisc_regs->divider = 0x101; - - /* Step 5: Initialize GIO64 arbitrator configuration register. - * - * NOTE: If you dork with startup code the HPC init code in - * sgihpc_init() must run before us because of how we - * need to know Guiness vs. FullHouse and the board - * revision on this machine. You have been warned. - */ - - /* First the basic invariants across all gio64 implementations. */ - tmpreg = SGIMC_GIOPARM_HPC64; /* All 1st HPC's interface at 64bits. */ - tmpreg |= SGIMC_GIOPARM_ONEBUS; /* Only one physical GIO bus exists. */ - - if(sgi_guiness) { - /* Guiness specific settings. */ - tmpreg |= SGIMC_GIOPARM_EISA64; /* MC talks to EISA at 64bits */ - tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */ - } else { - /* Fullhouse specific settings. */ - if(sgi_boardid < 2) { - tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */ - tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */ - tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */ - } else { - tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */ - tmpreg |= SGIMC_GIOPARM_PLINEEXP1; - tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */ - /* someone forgot this poor little guy... */ - tmpreg |= SGIMC_GIOPARM_GFX64; /* GFX at 64 bits */ - } - } - mcmisc_regs->gioparm = tmpreg; /* poof */ -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-reset.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-reset.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-reset.c Thu Jan 1 01:00:00 1970 @@ -1,238 +0,0 @@ -/* - * 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. - * - * Reset an IP22. - * - * Copyright (C) 1997, 1998, 1999, 2001 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. - * I'm not shure if this feature is a good idea, for now it's here just to - * make the power button make behave just like under IRIX. - */ -#define POWERDOWN_TIMEOUT 120 - -/* - * Blink frequency during reboot grace period and when paniced. - */ -#define POWERDOWN_FREQ (HZ / 4) -#define PANIC_FREQ (HZ / 8) - -static unsigned char sgi_volume; - -static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; -static int shuting_down, has_paniced; - -void machine_restart(char *command) __attribute__((noreturn)); -void machine_halt(void) __attribute__((noreturn)); -void machine_power_off(void) __attribute__((noreturn)); - -/* XXX How to pass the reboot command to the firmware??? */ -void machine_restart(char *command) -{ - if (shuting_down) - machine_power_off(); - ArcReboot(); -} - -void machine_halt(void) -{ - if (shuting_down) - machine_power_off(); - ArcEnterInteractiveMode(); -} - -void machine_power_off(void) -{ - struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; - - cli(); - - clock->cmd |= 0x08; /* Disable watchdog */ - clock->whsec = 0; - clock->wsec = 0; - - while(1) { - hpc3mregs->panel=0xfe; - /* Good bye cruel world ... */ - - /* If we're still running, we probably got sent an alarm - interrupt. Read the flag to clear it. */ - clock->halarm; - } -} - -static void power_timeout(unsigned long data) -{ - machine_power_off(); -} - -static void blink_timeout(unsigned long data) -{ - /* XXX Fix this for Fullhouse */ - sgi_hpc_write1 ^= (HPC3_WRITE1_LC0OFF|HPC3_WRITE1_LC1OFF); - hpc3mregs->write1 = sgi_hpc_write1; - - mod_timer(&blink_timer, jiffies+data); -} - -static void debounce(unsigned long data) -{ - del_timer(&debounce_timer); - if (ioc_icontrol->istat1 & 2) { /* Interrupt still being sent. */ - debounce_timer.expires = jiffies + 5; /* 0.05s */ - add_timer(&debounce_timer); - - hpc3mregs->panel = 0xf3; - - return; - } - - if (has_paniced) - ArcReboot(); - - enable_irq(9); -} - -static inline void power_button(void) -{ - if (has_paniced) - return; - - if (shuting_down || kill_proc(1, SIGINT, 1)) { - /* No init process or button pressed twice. */ - machine_power_off(); - } - - shuting_down = 1; - blink_timer.data = POWERDOWN_FREQ; - blink_timeout(POWERDOWN_FREQ); - - init_timer(&power_timer); - power_timer.function = power_timeout; - power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; - add_timer(&power_timer); -} - -void inline ip22_volume_set(unsigned char volume) -{ - sgi_volume = volume; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; -} - -void inline ip22_volume_get(unsigned char *volume) -{ - *volume = sgi_volume; -} - -static inline void volume_up_button(unsigned long data) -{ - del_timer(&volume_timer); - - if (sgi_volume < 0xff) - sgi_volume++; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; - - if (ioc_icontrol->istat1 & 2) { - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } - -} - -static inline void volume_down_button(unsigned long data) -{ - del_timer(&volume_timer); - - if (sgi_volume > 0) - sgi_volume--; - - hpc3c0->pbus_extregs[2][0] = sgi_volume; - hpc3c0->pbus_extregs[2][1] = sgi_volume; - - if (ioc_icontrol->istat1 & 2) { - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } -} - -static void panel_int(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int buttons; - - buttons = hpc3mregs->panel; - hpc3mregs->panel = 3; /* power_interrupt | power_supply_on */ - - if (ioc_icontrol->istat1 & 2) { /* Wait until interrupt goes away */ - disable_irq(9); - init_timer(&debounce_timer); - debounce_timer.function = debounce; - debounce_timer.expires = jiffies + 5; - add_timer(&debounce_timer); - } - - if (!(buttons & 2)) /* Power button was pressed */ - power_button(); - if (!(buttons & 0x40)) { /* Volume up button was pressed */ - init_timer(&volume_timer); - volume_timer.function = volume_up_button; - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } - if (!(buttons & 0x10)) { /* Volume down button was pressed */ - init_timer(&volume_timer); - volume_timer.function = volume_down_button; - volume_timer.expires = jiffies + 1; - add_timer(&volume_timer); - } -} - -static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - if (has_paniced) - return NOTIFY_DONE; - has_paniced = 1; - - blink_timer.data = PANIC_FREQ; - blink_timeout(PANIC_FREQ); - - return NOTIFY_DONE; -} - -static struct notifier_block panic_block = { - panic_event, - NULL, - 0 -}; - -void ip22_reboot_setup(void) -{ - static int setup_done; - - if (setup_done) - return; - setup_done = 1; - - request_irq(9, panel_int, 0, "Front Panel", NULL); - init_timer(&blink_timer); - blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-rtc.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-rtc.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-rtc.c Thu Jan 1 01:00:00 1970 @@ -1,36 +0,0 @@ -/* - * 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. - * - * RTC routines for Indy style attached Dallas chip. - * - * Copyright (C) 1998, 2001 by Ralf Baechle - */ -#include -#include - -static unsigned char indy_rtc_read_data(unsigned long addr) -{ - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; - - return rtcregs[addr]; -} - -static void indy_rtc_write_data(unsigned char data, unsigned long addr) -{ - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; - - rtcregs[addr] = data; -} - -static int indy_rtc_bcd_mode(void) -{ - return 0; -} - -struct rtc_ops indy_rtc_ops = { - &indy_rtc_read_data, - &indy_rtc_write_data, - &indy_rtc_bcd_mode -}; diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-sc.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-sc.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-sc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-sc.c Thu Jan 1 01:00:00 1970 @@ -1,164 +0,0 @@ -/* - * indy_sc.c: Indy cache management functions. - * - * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org), - * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* Secondary cache size in bytes, if present. */ -static unsigned long scache_size; - -#undef DEBUG_CACHE - -#define SC_SIZE 0x00080000 -#define SC_LINE 32 -#define CI_MASK (SC_SIZE - SC_LINE) -#define SC_INDEX(n) ((n) & CI_MASK) - -static inline void indy_sc_wipe(unsigned long first, unsigned long last) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - "or\t%0, %4\t\t\t# first line to flush\n\t" - "or\t%1, %4\t\t\t# last line to flush\n" - "1:\tsw $0, 0(%0)\n\t" - "bne\t%0, %1, 1b\n\t" - "daddu\t%0, 32\n\t" - ".set reorder" - : "=r" (first), "=r" (last) - : "0" (first), "1" (last), "r" (0x9000000080000000) - : "$1"); -} - -static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) -{ - unsigned long first_line, last_line; - unsigned int flags; - -#ifdef DEBUG_CACHE - printk("indy_sc_wback_invalidate[%08lx,%08lx]", addr, size); -#endif - - if (!size) - return; - - /* Which lines to flush? */ - first_line = SC_INDEX(addr); - last_line = SC_INDEX(addr + size - 1); - - __save_and_cli(flags); - if (first_line <= last_line) { - indy_sc_wipe(first_line, last_line); - goto out; - } - - indy_sc_wipe(first_line, SC_SIZE - SC_LINE); - indy_sc_wipe(0, last_line); -out: - __restore_flags(flags); -} - -static void inline indy_sc_enable(void) -{ -#ifdef DEBUG_CACHE - printk("Enabling R4600 SCACHE\n"); -#endif - *(volatile unsigned char *) 0x9000000080000000 = 0; -} - -static void indy_sc_disable(void) -{ -#ifdef DEBUG_CACHE - printk("Disabling R4600 SCACHE\n"); -#endif - *(volatile unsigned short *) 0x9000000080000000 = 0; -} - -static inline __init int indy_sc_probe(void) -{ - volatile u32 *cpu_control; - unsigned short cmd = 0xc220; - unsigned long data = 0; - int i, n; - -#ifdef __MIPSEB__ - cpu_control = (volatile u32 *) KSEG1ADDR(0x1fa00034); -#else - cpu_control = (volatile u32 *) KSEG1ADDR(0x1fa00030); -#endif -#define DEASSERT(bit) (*(cpu_control) &= (~(bit))) -#define ASSERT(bit) (*(cpu_control) |= (bit)) -#define DELAY for(n = 0; n < 100000; n++) __asm__ __volatile__("") - DEASSERT(SGIMC_EEPROM_PRE); - DEASSERT(SGIMC_EEPROM_SDATAO); - DEASSERT(SGIMC_EEPROM_SECLOCK); - DEASSERT(SGIMC_EEPROM_PRE); - DELAY; - ASSERT(SGIMC_EEPROM_CSEL); ASSERT(SGIMC_EEPROM_SECLOCK); - for(i = 0; i < 11; i++) { - if(cmd & (1<<15)) - ASSERT(SGIMC_EEPROM_SDATAO); - else - DEASSERT(SGIMC_EEPROM_SDATAO); - DEASSERT(SGIMC_EEPROM_SECLOCK); - ASSERT(SGIMC_EEPROM_SECLOCK); - cmd <<= 1; - } - DEASSERT(SGIMC_EEPROM_SDATAO); - for(i = 0; i < (sizeof(unsigned short) * 8); i++) { - unsigned int tmp; - - DEASSERT(SGIMC_EEPROM_SECLOCK); - DELAY; - ASSERT(SGIMC_EEPROM_SECLOCK); - DELAY; - data <<= 1; - tmp = *cpu_control; - if(tmp & SGIMC_EEPROM_SDATAI) - data |= 1; - } - DEASSERT(SGIMC_EEPROM_SECLOCK); - DEASSERT(SGIMC_EEPROM_CSEL); - ASSERT(SGIMC_EEPROM_PRE); - ASSERT(SGIMC_EEPROM_SECLOCK); - - data <<= PAGE_SHIFT; - if (data == 0) - return 0; - - scache_size = data; - - printk("R4600/R5000 SCACHE size %ldK, linesize 32 bytes.\n", - scache_size >> 10); - - return 1; -} - -/* XXX Check with wje if the Indy caches can differenciate between - writeback + invalidate and just invalidate. */ -static struct bcache_ops indy_sc_ops = { - indy_sc_enable, - indy_sc_disable, - indy_sc_wback_invalidate, - indy_sc_wback_invalidate -}; - -void __init indy_sc_init(void) -{ - if (indy_sc_probe()) { - indy_sc_enable(); - bcops = &indy_sc_ops; - } -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-setup.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-setup.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-setup.c Thu Jan 1 01:00:00 1970 @@ -1,189 +0,0 @@ -/* - * 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. - * - * SGI IP22 specific setup. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 1999 Silcon Graphics, Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct rtc_ops indy_rtc_ops; -extern void ip22_reboot_setup(void); -extern void ip22_volume_set(unsigned char); - -#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64)) - -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ - -static void ip22_request_region(void) -{ - /* No I/O ports are being used on the Indy. */ -} - -static int ip22_request_irq(void (*handler)(int, void *, struct pt_regs *)) -{ - /* Dirty hack, this get's called as a callback from the keyboard - driver. We piggyback the initialization of the front panel - button handling on it even though they're technically not - related with the keyboard driver in any way. Doing it from - indy_setup wouldn't work since kmalloc isn't initialized yet. */ - ip22_reboot_setup(); - - return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL); -} - -static int ip22_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) -{ - /* Nothing to do, interrupt is shared with the keyboard hw */ - return 0; -} - -static void ip22_aux_free_irq(void) -{ - /* Nothing to do, interrupt is shared with the keyboard hw */ -} - -static unsigned char ip22_read_input(void) -{ - return sgi_kh->data; -} - -static void ip22_write_output(unsigned char val) -{ - int status; - - do { - status = sgi_kh->command; - } while (status & KBD_STAT_IBF); - sgi_kh->data = val; -} - -static void ip22_write_command(unsigned char val) -{ - int status; - - do { - status = sgi_kh->command; - } while (status & KBD_STAT_IBF); - sgi_kh->command = val; -} - -static unsigned char ip22_read_status(void) -{ - return sgi_kh->command; -} - -struct kbd_ops sgi_kbd_ops = { - ip22_request_region, - ip22_request_irq, - - ip22_aux_request_irq, - ip22_aux_free_irq, - - ip22_read_input, - ip22_write_output, - ip22_write_command, - ip22_read_status -}; - -int __init page_is_ram(unsigned long pagenr) -{ - if ((pagenr< 0x08002000) - return 1; - return 0; -} - -void __init ip22_setup(void) -{ -#ifdef CONFIG_SERIAL_CONSOLE - char *ctype; -#endif - TLBMISS_HANDLER_SETUP(); - - /* Init the INDY HPC I/O controller. Need to call this before - * fucking with the memory controller because it needs to know the - * boardID and whether this is a Guiness or a FullHouse machine. - */ - sgihpc_init(); - - /* Init INDY memory controller. */ - sgimc_init(); - - /* Now enable boardcaches, if any. */ - indy_sc_init(); - -#ifdef CONFIG_SERIAL_CONSOLE - /* ARCS console environment variable is set to "g?" for - * graphics console, it is set to "d" for the first serial - * line and "d2" for the second serial line. - */ - ctype = ArcGetEnvironmentVariable("console"); - if(*ctype == 'd') { - if(*(ctype+1)=='2') - console_setup ("ttyS1"); - else - console_setup ("ttyS0"); - } -#endif -#ifdef CONFIG_ARC_CONSOLE - console_setup("ttyS0"); -#endif - - ip22_volume_set(simple_strtoul(ArcGetEnvironmentVariable("volume"), - NULL, 10)); - -#ifdef CONFIG_VT -#ifdef CONFIG_SGI_NEWPORT_CONSOLE - conswitchp = &newport_con; - - screen_info = (struct screen_info) { - 0, 0, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig_video_page */ - 0, /* orig_video_mode */ - 160, /* orig_video_cols */ - 0, 0, 0, /* unused, ega_bx, unused */ - 64, /* orig_video_lines */ - 0, /* orig_video_isVGA */ - 16 /* orig_video_points */ - }; -#else - conswitchp = &dummy_con; -#endif -#endif - rtc_ops = &indy_rtc_ops; - kbd_ops = &sgi_kbd_ops; -#ifdef CONFIG_PSMOUSE - aux_device_present = 0xaa; -#endif -#ifdef CONFIG_VIDEO_VINO - init_vino(); -#endif -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/ip22-timer.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-timer.c --- linux-2.4.18/arch/mips64/sgi-ip22/ip22-timer.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/ip22-timer.c Thu Jan 1 01:00:00 1970 @@ -1,262 +0,0 @@ -/* - * indy_timer.c: Setting up the clock on the INDY 8254 controller. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copytight (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Because of a bug in the i8254 timer we need to use the onchip r4k - * counter as our system wide timer interrupt running at 100HZ. - */ -static unsigned long r4k_offset; /* Amount to increment compare reg each time */ -static unsigned long r4k_cur; /* What counter should be at next timer irq */ - -extern rwlock_t xtime_lock; - -static inline void ack_r4ktimer(unsigned long newval) -{ - write_32bit_cp0_register(CP0_COMPARE, newval); -} - -static int set_rtc_mmss(unsigned long nowtime) -{ - struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; - int retval = 0; - int real_seconds, real_minutes, clock_minutes; - -#define FROB_FROM_CLOCK(x) (((x) & 0xf) | ((((x) & 0xf0) >> 4) * 10)); -#define FROB_TO_CLOCK(x) ((((((x) & 0xff) / 10)<<4) | (((x) & 0xff) % 10)) & 0xff) - - clock->cmd &= ~(0x80); - clock_minutes = clock->min; - clock->cmd |= (0x80); - - clock_minutes = FROB_FROM_CLOCK(clock_minutes); - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - - if(((abs(real_minutes - clock_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - - real_minutes %= 60; - if(abs(real_minutes - clock_minutes) < 30) { - /* Force clock oscillator to be on. */ - clock->month &= ~(0x80); - - /* Write real_seconds and real_minutes into the Dallas. */ - clock->cmd &= ~(0x80); - clock->sec = real_seconds; - clock->min = real_minutes; - clock->cmd |= (0x80); - } else - return -1; - -#undef FROB_FROM_CLOCK -#undef FROB_TO_CLOCK - - return retval; -} - -static long last_rtc_update; -unsigned long missed_heart_beats; - -void indy_timer_interrupt(struct pt_regs *regs) -{ - unsigned long count; - int irq = 7; - - write_lock(&xtime_lock); - /* Ack timer and compute new compare. */ - count = read_32bit_cp0_register(CP0_COUNT); - /* This has races. */ - if ((count - r4k_cur) >= r4k_offset) { - /* If this happens to often we'll need to compensate. */ - missed_heart_beats++; - r4k_cur = count + r4k_offset; - } - else - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - kstat.irqs[0][irq]++; - do_timer(regs); - - /* We update the Dallas time of day approx. every 11 minutes, - * because of how the numbers work out we need to make - * absolutely sure we do this update within 500ms before the - * next second starts, thus the following code. - */ - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec >= 500000 - (tick >> 1) && - xtime.tv_usec <= 500000 + (tick >> 1)) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - /* do it again in 60s */ - last_rtc_update = xtime.tv_sec - 600; - } - write_unlock(&xtime_lock); -} - -static unsigned long dosample(volatile unsigned char *tcwp, - volatile unsigned char *tc2p) -{ - unsigned long ct0, ct1; - unsigned char msb, lsb; - - /* Start the counter. */ - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN); - *tc2p = (SGINT_TCSAMP_COUNTER & 0xff); - *tc2p = (SGINT_TCSAMP_COUNTER >> 8); - - /* Get initial counter invariant */ - ct0 = read_32bit_cp0_register(CP0_COUNT); - - /* Latch and spin until top byte of counter2 is zero */ - do { - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT); - lsb = *tc2p; - msb = *tc2p; - ct1 = read_32bit_cp0_register(CP0_COUNT); - } while(msb); - - /* Stop the counter. */ - *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST); - - /* Return the difference, this is how far the r4k counter increments - * for every one HZ. - */ - return ct1 - ct0; -} - -static unsigned long __init get_indy_time(void) -{ - struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; - unsigned int year, mon, day, hour, min, sec; - - /* Freeze it. */ - clock->cmd &= ~(0x80); - - /* Read regs. */ - sec = clock->sec; - min = clock->min; - hour = (clock->hr & 0x3f); - day = (clock->date & 0x3f); - mon = (clock->month & 0x1f); - year = clock->year; - - /* Unfreeze clock. */ - clock->cmd |= 0x80; - - /* Frob the bits. */ -#define FROB1(x) (((x) & 0xf) + ((((x) & 0xf0) >> 4) * 10)); -#define FROB2(x) (((x) & 0xf) + (((((x) & 0xf0) >> 4) & 0x3) * 10)); - - /* XXX Should really check that secs register is the same - * XXX as when we first read it and if not go back and - * XXX read the regs above again. - */ - sec = FROB1(sec); min = FROB1(min); day = FROB1(day); - mon = FROB1(mon); year = FROB1(year); - hour = FROB2(hour); - -#undef FROB1 -#undef FROB2 - - /* Wheee... */ - if(year < 45) - year += 30; - if ((year += 1940) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) - -void __init indy_timer_init(void) -{ - struct sgi_ioc_timers *p; - volatile unsigned char *tcwp, *tc2p; - - /* Figure out the r4k offset, the algorithm is very simple and works - * in _all_ cases as long as the 8254 counter register itself works ok - * (as an interrupt driving timer it does not because of bug, this is - * why we are using the onchip r4k counter/compare register to serve - * this purpose, but for r4k_offset calculation it will work ok for us). - * There are other very complicated ways of performing this calculation - * but this one works just fine so I am not going to futz around. ;-) - */ - p = ioc_timers; - tcwp = &p->tcword; - tc2p = &p->tcnt2; - - printk("calculating r4koff... "); - dosample(tcwp, tc2p); /* First sample. */ - dosample(tcwp, tc2p); /* Eat one. */ - r4k_offset = dosample(tcwp, tc2p); /* Second sample. */ - - printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); - - r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset); - write_32bit_cp0_register(CP0_COMPARE, r4k_cur); - set_cp0_status(ST0_IM, ALLINTS); - sti(); - - write_lock_irq(&xtime_lock); - xtime.tv_sec = get_indy_time(); /* Read time from RTC. */ - xtime.tv_usec = 0; - write_unlock_irq(&xtime_lock); -} - -void indy_8254timer_irq(void) -{ - int cpu = smp_processor_id(); - int irq = 4; - - irq_enter(cpu, irq); - kstat.irqs[0][irq]++; - panic("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); - irq_exit(cpu, irq); -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - - read_lock_irqsave(&xtime_lock, flags); - *tv = xtime; - read_unlock_irqrestore(&xtime_lock, flags); -} - -void do_settimeofday(struct timeval *tv) -{ - write_lock_irq(&xtime_lock); - 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); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/system.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/system.c --- linux-2.4.18/arch/mips64/sgi-ip22/system.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/system.c Thu Jan 1 01:00:00 1970 @@ -1,123 +0,0 @@ -/* - * 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. - * - * system.c: Probe the system type using ARCS prom interface library. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org) - */ -#include -#include -#include -#include - -#include -#include -#include - -struct smatch { - char *name; - int type; -}; - -static struct smatch sgi_cputable[] = { - { "MIPS-R2000", CPU_R2000 }, - { "MIPS-R3000", CPU_R3000 }, - { "MIPS-R3000A", CPU_R3000A }, - { "MIPS-R4000", CPU_R4000SC }, - { "MIPS-R4400", CPU_R4400SC }, - { "MIPS-R4600", CPU_R4600 }, - { "MIPS-R8000", CPU_R8000 }, - { "MIPS-R5000", CPU_R5000 }, - { "MIPS-R5000A", CPU_R5000A } -}; - -#define NUM_CPUS 9 /* for now */ - -static int __init string_to_cpu(char *s) -{ - int i; - - for(i = 0; i < NUM_CPUS; i++) { - if(!strcmp(s, sgi_cputable[i].name)) - return sgi_cputable[i].type; - } - panic("\nYeee, could not determine MIPS cpu type <%s>", s); - return 0; -} - -/* - * We' call this early before loadmmu(). If we do the other way around - * the firmware will crash and burn. - */ -void __init sgi_sysinit(void) -{ - pcomponent *p, *toplev, *cpup = 0; - int cputype = -1; - - - /* The root component tells us what machine architecture we - * have here. - */ - p = ArcGetChild(PROM_NULL_COMPONENT); - - /* Now scan for cpu(s). */ - toplev = p = ArcGetChild(p); - while(p) { - int ncpus = 0; - - if(p->type == Cpu) { - if (++ncpus > 1) - panic("\nYeee, SGI MP not ready yet"); - printk("CPU: %s ", p->iname); - cpup = p; - cputype = string_to_cpu(cpup->iname); - } - p = ArcGetPeer(p); - } - if (cputype == -1) { - panic("\nYeee, could not find cpu ARCS component"); - } - p = ArcGetChild(cpup); - while(p) { - switch(p->class) { - case processor: - switch(p->type) { - case Fpu: - printk("FPU<%s> ", p->iname); - break; - - default: - break; - }; - break; - - case cache: - switch(p->type) { - case picache: - printk("ICACHE "); - break; - - case pdcache: - printk("DCACHE "); - break; - - case sccache: - printk("SCACHE "); - break; - - default: - break; - - }; - break; - - default: - break; - }; - p = ArcGetPeer(p); - } - printk("\n"); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip22/time.c linux-2.4.19-pre5/arch/mips64/sgi-ip22/time.c --- linux-2.4.18/arch/mips64/sgi-ip22/time.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip22/time.c Thu Jan 1 01:00:00 1970 @@ -1,19 +0,0 @@ -/* - * 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. - * - * time.c: Generic SGI time_init() code, this will dispatch to the - * appropriate per-architecture time/counter init code. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include - -extern void indy_timer_init(void); - -void __init time_init(void) -{ - /* XXX assume INDY for now XXX */ - indy_timer_init(); -} diff -urN linux-2.4.18/arch/mips64/sgi-ip27/Makefile linux-2.4.19-pre5/arch/mips64/sgi-ip27/Makefile --- linux-2.4.18/arch/mips64/sgi-ip27/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/Makefile Sat Mar 30 22:55:27 2002 @@ -9,8 +9,11 @@ O_TARGET = ip27.o -obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ - ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \ - ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o +export-objs = ip27-rtc.o + +obj-y := ip27-berr.o ip27-console.o ip27-dbe-glue.o ip27-irq.o ip27-init.o \ + ip27-irq-glue.o ip27-klconfig.o ip27-klnuma.o ip27-memory.o \ + ip27-nmi.o ip27-pci.o ip27-pci-dma.o ip27-reset.o ip27-setup.o \ + ip27-timer.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-berr.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-berr.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-berr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-berr.c Sat Mar 30 22:55:27 2002 @@ -15,77 +15,15 @@ #include #include #include +#include extern void dump_tlb_addr(unsigned long addr); extern void dump_tlb_all(void); -extern asmlinkage void handle_ibe(void); -extern asmlinkage void handle_dbe(void); +extern asmlinkage void handle_ip27_ibe(void); +extern asmlinkage void handle_ip27_dbe(void); -extern const struct exception_table_entry __start___dbe_table[]; -extern const struct exception_table_entry __stop___dbe_table[]; - -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid->nextinsn; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return 0; -} - -extern spinlock_t modlist_lock; - -static inline unsigned long -search_dbe_table(unsigned long addr) -{ - unsigned long ret; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr); - return ret; -#else - unsigned long flags; - - /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - struct archdata *ap; - - spin_lock_irqsave(&modlist_lock, flags); - for (mp = module_list; mp != NULL; mp = mp->next) { - if (!mod_member_present(mp, archdata_end) || - !mod_archdata_member_present(mp, struct archdata, - dbe_table_end)) - continue; - ap = (struct archdata *)(mod->archdata_start); - - if (ap->dbe_table_start == NULL || - !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING))) - continue; - ret = search_one_table(ap->dbe_table_start, - ap->dbe_table_end - 1, addr); - if (ret) - break; - } - spin_unlock_irqrestore(&modlist_lock, flags); - return ret; -#endif -} - -void do_ibe(struct pt_regs *regs) +void do_ip27_ibe(struct pt_regs *regs) { printk("Got ibe at 0x%lx\n", regs->cp0_epc); show_regs(regs); @@ -127,7 +65,7 @@ ? : "invalid"); } -void do_dbe(struct pt_regs *regs) +void do_ip27_dbe(struct pt_regs *regs) { unsigned long fixup, errst0, errst1; int cpu = LOCAL_HUB_L(PI_CPU_NUM); @@ -153,15 +91,14 @@ force_sig(SIGBUS, current); } -void __init -bus_error_init(void) +void __init bus_error_init(void) { /* XXX Initialize all the Hub & Bridge error handling here. */ int cpu = LOCAL_HUB_L(PI_CPU_NUM); int cpuoff = cpu << 8; - set_except_vector(6, handle_ibe); - set_except_vector(7, handle_dbe); + set_except_vector(6, handle_ip27_ibe); + set_except_vector(7, handle_ip27_dbe); LOCAL_HUB_S(PI_ERR_INT_PEND, cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A); diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-dbe-glue.S linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-dbe-glue.S --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-dbe-glue.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-dbe-glue.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,20 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 - 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics + * + * Low level exception handling + */ +#define __ASSEMBLY__ +#include +#include +#include +#include +#include +#include + + BUILD_HANDLER ip27_ibe ip27_ibe cli silent /* #6 */ + BUILD_HANDLER ip27_dbe ip27_dbe cli silent /* #7 */ diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-init.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-init.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-init.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-init.c Sat Mar 30 22:55:27 2002 @@ -13,6 +13,7 @@ #include #include /* for numnodes */ #include +#include #include #include #include @@ -359,12 +360,11 @@ int cpu = smp_processor_id(); cnodeid_t cnode = get_compact_nodeid(); - current_cpu_data.asid_cache = ASID_FIRST_VERSION; TLBMISS_HANDLER_SETUP(); #if 0 intr_init(); #endif - set_cp0_status(ST0_IM, 0); + clear_cp0_status(ST0_IM); per_hub_init(cnode); cpu_time_init(); if (smp_processor_id()) /* master can't do this early, no kmalloc */ @@ -374,12 +374,12 @@ #if 0 install_tlbintr(cpu); #endif - set_cp0_status(SRB_DEV0 | SRB_DEV1, SRB_DEV0 | SRB_DEV1); + set_cp0_status(SRB_DEV0 | SRB_DEV1); if (is_slave) { - set_cp0_status(ST0_BEV, 0); - if (mips4_available) - set_cp0_status(ST0_XX, ST0_XX); - set_cp0_status(ST0_KX|ST0_SX|ST0_UX, ST0_KX|ST0_SX|ST0_UX); + clear_cp0_status(ST0_BEV); + if (mips_cpu.isa_level == MIPS_CPU_ISA_IV) + set_cp0_status(ST0_XX); + set_cp0_status(ST0_KX|ST0_SX|ST0_UX); sti(); load_mmu(); atomic_inc(&numstarted); @@ -420,47 +420,30 @@ cpu_data[cpunum].p_cpuid = cpu; } -void __init smp_callin(void) -{ -#if 0 - calibrate_delay(); - smp_store_cpu_info(cpuid); -#endif -} - -int __init start_secondary(void) -{ - extern int cpu_idle(void); - extern atomic_t smp_commenced; - - smp_callin(); - while (!atomic_read(&smp_commenced)); - return cpu_idle(); -} - static volatile cpumask_t boot_barrier; -void cboot(void) +void __init start_secondary(void) { CPUMASK_CLRB(boot_barrier, getcpuid()); /* needs atomicity */ per_cpu_init(); + per_cpu_trap_init(); #if 0 ecc_init(); bte_lateinit(); init_mfhi_war(); #endif - _flush_tlb_all(); + local_flush_tlb_all(); flush_cache_l1(); flush_cache_l2(); start_secondary(); } -void allowboot(void) +__init void allowboot(void) { int num_cpus = 0; cpuid_t cpu, mycpuid = getcpuid(); cnodeid_t cnode; - extern void bootstrap(void); + extern void smp_bootstrap(void); sn_mp_setup(); /* Master has already done per_cpu_init() */ @@ -502,16 +485,16 @@ /* Attach to the address space of init_task. */ atomic_inc(&init_mm.mm_count); p->active_mm = &init_mm; - + /* - * Launch a slave into bootstrap(). + * Launch a slave into smp_bootstrap(). * It doesn't take an argument, and we * set sp to the kernel stack of the newly * created idle process, gp to the proc struct * (so that current-> works). */ LAUNCH_SLAVE(cputonasid(num_cpus),cputoslice(num_cpus), - (launch_proc_t)MAPPED_KERN_RW_TO_K0(bootstrap), + (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), 0, (void *)((unsigned long)p + KERNEL_STACK_SIZE - 32), (void *)p); @@ -522,6 +505,7 @@ */ __cpu_number_map[cpu] = num_cpus; __cpu_logical_map[num_cpus] = cpu; + CPUMASK_SETB(cpu_online_map, cpu); num_cpus++; /* * Wait this cpu to start up and initialize its hub, @@ -554,8 +538,22 @@ smp_num_cpus = num_cpus; } +void __init smp_boot_cpus(void) +{ + extern void allowboot(void); + + init_new_context(current, &init_mm); + current->processor = 0; + init_idle(); + smp_tune_scheduling(); + allowboot(); +} + #else /* CONFIG_SMP */ -void cboot(void) {} +void __init start_secondary(void) +{ + /* XXX Why do we need this empty definition at all? */ +} #endif /* CONFIG_SMP */ diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-irq.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-irq.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-irq.c Sat Mar 30 22:55:27 2002 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -33,10 +32,13 @@ #include #include #include +#include +#include #include #include #include + #undef DEBUG_IRQ #ifdef DEBUG_IRQ #define DBG(x...) printk(x) @@ -66,12 +68,12 @@ */ extern asmlinkage void ip27_irq(void); +extern void do_IRQ(int irq, struct pt_regs *regs); + extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[]; int intr_connect_level(int cpu, int bit); int intr_disconnect_level(int cpu, int bit); -unsigned long spurious_count = 0; - /* * There is a single intpend register per node, and we want to have * distinct levels for intercpu intrs for both cpus A and B on a node. @@ -122,90 +124,20 @@ return(-1); } - -void disable_irq(unsigned int irq_nr) -{ - panic("disable_irq() called ..."); -} - -void enable_irq(unsigned int irq_nr) -{ - panic("enable_irq() called ..."); -} - -/* This is stupid for an Origin which can have thousands of IRQs ... */ -static struct irqaction *irq_action[NR_IRQS]; - -int get_irq_list(char *buf) -{ - int i, len = 0; - struct irqaction * action; - - for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %8d %c %s", i, kstat.irqs[0][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) - ? " +" : "", - action->name); - } - len += sprintf(buf+len, "\n"); - } - return len; -} - -/* - * do_IRQ handles all normal device IRQ's (the special SMP cross-CPU interrupts - * have their own specific handlers). - */ -static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs) -{ - struct irqaction *action; - int do_random; - - irq_enter(thiscpu, irq); - kstat.irqs[thiscpu][irq]++; - - action = *(irq + irq_action); - if (action) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do_random = 0; - do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - } - irq_exit(thiscpu, irq); - - if (softirq_pending(thiscpu)) - do_softirq(); -} - /* * Find first bit set */ static int ms1bit(unsigned long x) { - int b; + int b = 0, s; - if (x >> 32) b = 32, x >>= 32; - else b = 0; - if (x >> 16) b += 16, x >>= 16; - if (x >> 8) b += 8, x >>= 8; - if (x >> 4) b += 4, x >>= 4; - if (x >> 2) b += 2, x >>= 2; + s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s; + s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s; + s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s; + s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s; + s = 1; if (x >> 1 == 0) s = 0; b += s; - return b + (int) (x >> 1); + return b; } /* @@ -239,7 +171,7 @@ LOCAL_HUB_CLR_INTR(swlevel); /* "map" swlevel to irq */ irq = LEVEL_TO_IRQ(thiscpu, swlevel); - do_IRQ(thiscpu, irq, regs); + do_IRQ(irq, regs); /* clear bit in pend0 */ pend0 ^= 1ULL << swlevel; } while(pend0); @@ -252,7 +184,7 @@ /* Startup one of the (PCI ...) IRQs routes over a bridge. */ -static unsigned int bridge_startup(unsigned int irq) +static unsigned int startup_bridge_irq(unsigned int irq) { bridgereg_t device; bridge_t *bridge; @@ -260,6 +192,9 @@ cpuid_t cpu; nasid_t master = NASID_FROM_PCI_IRQ(irq); + if (irq < BASE_PCI_IRQ) + return 0; + bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq)); pin = SLOT_FROM_PCI_IRQ(irq); cpu = IRQ_TO_CPU(irq); @@ -292,12 +227,15 @@ } /* Shutdown one of the (PCI ...) IRQs routes over a bridge. */ -static unsigned int bridge_shutdown(unsigned int irq) +static unsigned int shutdown_bridge_irq(unsigned int irq) { bridge_t *bridge; int pin, swlevel; cpuid_t cpu; + if (irq < BASE_PCI_IRQ) + return 0; + bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq), WID_FROM_PCI_IRQ(irq)); DBG("bridge_shutdown: irq 0x%x\n", irq); @@ -317,312 +255,64 @@ return 0; /* Never anything pending. */ } -void irq_debug(void) +static inline void enable_bridge_irq(unsigned int irq) { - bridge_t *bridge = (bridge_t *) 0x9200000008000000; - - printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status); - printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable); - printk("PI_INT_PEND0 = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0)); - printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A)); + /* All the braindamage happens magically for us in ip27_do_irq */ } -int setup_irq(unsigned int irq, struct irqaction *new) +static void disable_bridge_irq(unsigned int irq) { - int shared = 0; - struct irqaction *old, **p; - unsigned long flags; - - DBG("setup_irq: 0x%x\n", irq); - if (irq >= NR_IRQS) { - printk("IRQ array overflow %d\n", irq); - while(1); - } - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - - save_and_cli(flags); - p = irq_action + irq; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { - restore_flags(flags); - return -EBUSY; - } - - /* Add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - - *p = new; - - if ((!shared) && (irq >= BASE_PCI_IRQ)) { - bridge_startup(irq); - } - restore_flags(flags); - - return 0; + /* All the braindamage happens magically for us in ip27_do_irq */ } -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) +static void mask_and_ack_bridge_irq(unsigned int irq) { - int retval; - struct irqaction *action; - - DBG("request_irq(): irq= 0x%x\n", irq); - if (!handler) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(*action), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - DBG("request_irq(): %s devid= 0x%x\n", devname, dev_id); - retval = setup_irq(irq, action); - DBG("request_irq(): retval= %d\n", retval); - if (retval) - kfree(action); - return retval; + /* All the braindamage happens magically for us in ip27_do_irq */ } -void free_irq(unsigned int irq, void *dev_id) +static void end_bridge_irq (unsigned int irq) { - struct irqaction * action, **p; - unsigned long flags; - - if (irq >= NR_IRQS) { - printk("Trying to free IRQ%d\n", irq); - return; - } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - if (irq >= BASE_PCI_IRQ) - bridge_shutdown(irq); - restore_flags(flags); - kfree(action); - return; - } - printk("Trying to free free IRQ%d\n",irq); + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_bridge_irq(irq); } -/* Useless ISA nonsense. */ -unsigned long probe_irq_on (void) -{ - panic("probe_irq_on called!\n"); - return 0; -} +static struct hw_interrupt_type bridge_irq_type = { + "bridge", + startup_bridge_irq, + shutdown_bridge_irq, + enable_bridge_irq, + disable_bridge_irq, + mask_and_ack_bridge_irq, + end_bridge_irq +}; -int probe_irq_off (unsigned long irqs) +void irq_debug(void) { - return 0; -} + bridge_t *bridge = (bridge_t *) 0x9200000008000000; -void __init init_IRQ(void) -{ - set_except_vector(0, ip27_irq); + printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status); + printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable); + printk("PI_INT_PEND0 = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0)); + printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A)); } -#ifdef CONFIG_SMP - -/* - * This following are the global intr on off routines, copied almost - * entirely from i386 code. - */ - -int global_irq_holder = NO_PROC_ID; -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; - -extern void show_stack(unsigned long* esp); - -static void show(char * str) +void __init init_IRQ(void) { int i; - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [",irqs_running()); - for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_irq_count(i)); - printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_bh_count(i)); - - printk(" ]\nStack dumps:"); - for(i = 0; i < smp_num_cpus; i++) { - if (i == cpu) - continue; - printk("\nCPU %d:",i); - printk("Code not developed yet\n"); - /* show_stack(0); */ - } - printk("\nCPU %d:",cpu); - printk("Code not developed yet\n"); - /* show_stack(NULL); */ - printk("\n"); -} - -#define MAXCOUNT 100000000 -#define SYNC_OTHER_CORES(x) udelay(x+1) - -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 (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - spin_unlock(&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - SYNC_OTHER_CORES(cpu); - __cli(); - if (irqs_running()) - continue; - if (spin_is_locked(&global_irq_lock)) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } - } -} -void synchronize_irq(void) -{ - if (irqs_running()) { - /* Stupid approach */ - cli(); - sti(); - } -} - -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); + set_except_vector(0, ip27_irq); /* - * Ok, finally.. + * Right now the bridge irq is our kitchen sink interrupt type */ - global_irq_holder = cpu; -} - -void __global_cli(void) -{ - unsigned int flags; - - __save_flags(flags); - if (flags & ST0_IE) { - 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; - int cpu = smp_processor_id(); - - __save_flags(flags); - local_enabled = (flags & ST0_IE); - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { - if (local_enabled) - retval = 1; - if (global_irq_holder == cpu) - retval = 0; + for (i = 0; i <= NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &bridge_irq_type; } - 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\n", flags); - } -} - -#endif /* CONFIG_SMP */ - /* * Get values that vary depending on which CPU and bit we're operating on. */ @@ -697,6 +387,39 @@ /* Nothing, the return from intr will work for us */ } +#ifdef CONFIG_SMP + +void core_send_ipi(int destid, unsigned int action) +{ + int irq; + +#if (CPUS_PER_NODE == 2) + switch (action) { + case SMP_RESCHEDULE_YOURSELF: + irq = CPU_RESCHED_A_IRQ; + break; + case SMP_CALL_FUNCTION: + irq = CPU_CALL_A_IRQ; + break; + default: + panic("sendintr"); + } + irq += cputoslice(destid); + + /* + * Convert the compact hub number to the NASID to get the correct + * part of the address space. Then set the interrupt bit associated + * with the CPU we want to send the interrupt to. + */ + REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)), + FAST_IRQ_TO_LEVEL(irq)); +#else + << Bomb! Must redefine this for more than 2 CPUS. >> +#endif +} + +#endif + extern void smp_call_function_interrupt(void); void install_cpuintr(int cpu) @@ -715,16 +438,16 @@ if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr, 0, "resched", 0)) - panic("intercpu intr unconnectible\n"); + panic("intercpu intr unconnectible"); if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr, 0, "resched", 0)) - panic("intercpu intr unconnectible\n"); + panic("intercpu intr unconnectible"); if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt, 0, "callfunc", 0)) - panic("intercpu intr unconnectible\n"); + panic("intercpu intr unconnectible"); if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt, 0, "callfunc", 0)) - panic("intercpu intr unconnectible\n"); + panic("intercpu intr unconnectible"); for (j = 0; j < PERNODE_LEVELS; j++) LEVEL_TO_IRQ(0, j) = -1; diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-pci-dma.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-pci-dma.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-pci-dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-pci-dma.c Sat Mar 30 22:55:27 2002 @@ -14,26 +14,12 @@ #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; - int order = __get_order(size); + int order = get_order(size); if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; @@ -50,7 +36,7 @@ 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)); + free_pages((unsigned long)vaddr, get_order(size)); } /* diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-pci.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-pci.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-pci.c Sat Mar 30 22:55:27 2002 @@ -192,7 +192,7 @@ if ((dev->bus->number >= MAX_PCI_BUSSES) || (pin != 1) || (slot >= MAX_DEVICES_PER_PCIBUS)) - panic("Increase supported PCI busses %d,%d,%d\n", + panic("Increase supported PCI busses %d,%d,%d", dev->bus->number, slot, pin); /* diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-reset.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-reset.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-reset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-reset.c Sat Mar 30 22:55:27 2002 @@ -14,8 +14,10 @@ #include #include #include + #include #include +#include #include #include #include @@ -30,7 +32,7 @@ #define noreturn while(1); /* Silence gcc. */ /* XXX How to pass the reboot command to the firmware??? */ -void machine_restart(char *command) +static void ip27_machine_restart(char *command) { #if 0 int i; @@ -50,7 +52,7 @@ noreturn; } -void machine_halt(void) +static void ip27_machine_halt(void) { int i; @@ -64,7 +66,7 @@ noreturn; } -void machine_power_off(void) +static void ip27_machine_power_off(void) { /* To do ... */ noreturn; @@ -72,5 +74,7 @@ void ip27_reboot_setup(void) { - /* Nothing to do on IP27. */ + _machine_restart = ip27_machine_restart; + _machine_halt = ip27_machine_halt; + _machine_power_off = ip27_machine_power_off; } diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-rtc.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-rtc.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-rtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-rtc.c Sat Mar 30 22:55:33 2002 @@ -61,6 +61,7 @@ #define RTC_TIMER_ON 0x02 /* missed irq timer active */ static unsigned char rtc_status; /* bitmapped status byte. */ +static spinlock_t rtc_status_lock = SPIN_LOCK_UNLOCKED; static unsigned long rtc_freq; /* Current periodic IRQ rate */ static struct m48t35_rtc *rtc; @@ -166,10 +167,16 @@ static int rtc_open(struct inode *inode, struct file *file) { - if(rtc_status & RTC_IS_OPEN) + spin_lock(rtc_status_lock); + + if (rtc_status & RTC_IS_OPEN) { + spin_unlock(rtc_status_lock); return -EBUSY; + } rtc_status |= RTC_IS_OPEN; + spin_unlock(rtc_status_lock); + return 0; } @@ -180,9 +187,10 @@ * in use, and clear the data. */ - lock_kernel(); + spin_lock(rtc_status_lock); rtc_status &= ~RTC_IS_OPEN; - unlock_kernel(); + spin_unlock(rtc_status_lock); + return 0; } @@ -214,7 +222,8 @@ KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0; printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); - misc_register(&rtc_dev); + if (misc_register(&rtc_dev)) + return -ENODEV; create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL); save_flags(flags); diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-setup.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-setup.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-setup.c Sat Mar 30 22:55:27 2002 @@ -14,6 +14,7 @@ #include #include #include + #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +42,6 @@ #define DBG(x...) #endif -unsigned long mips_io_port_base = IO_BASE; - /* * get_nasid() returns the physical node id number of the caller. */ @@ -275,6 +275,7 @@ } extern void ip27_setup_console(void); +extern void ip27_time_init(void); void __init ip27_setup(void) { @@ -307,4 +308,7 @@ ioc3_sio_init(); ioc3_eth_init(); per_cpu_init(); + + mips_io_port_base = IO_BASE; + board_time_init = ip27_time_init; } diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-timer.c linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-timer.c --- linux-2.4.18/arch/mips64/sgi-ip27/ip27-timer.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip27/ip27-timer.c Sat Mar 30 22:55:27 2002 @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -91,8 +92,9 @@ { int cpu = smp_processor_id(); int cpuA = ((cputoslice(cpu)) == 0); - int irq = 7; /* XXX Assign number */ + int irq = 9; /* XXX Assign number */ + irq_enter(cpu, irq); write_lock(&xtime_lock); again: @@ -109,19 +111,7 @@ do_timer(regs); #ifdef CONFIG_SMP - { - int user = user_mode(regs); - - /* - * update_process_times() expects us to have done irq_enter(). - * Besides, if we don't timer interrupts ignore the global - * interrupt lock, which is the WrongThing (tm) to do. - * Picked from i386 code. - */ - irq_enter(cpu, 0); - update_process_times(user); - irq_exit(cpu, 0); - } + update_process_times(user_mode(regs)); #endif /* CONFIG_SMP */ /* @@ -145,62 +135,19 @@ } write_unlock(&xtime_lock); + irq_exit(cpu, irq); if (softirq_pending(cpu)) do_softirq(); } -unsigned long inline do_gettimeoffset(void) +unsigned long ip27_do_gettimeoffset(void) { unsigned long ct_cur1; ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY; return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000; } -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long usec, sec; - - read_lock_irqsave(&xtime_lock, flags); - usec = do_gettimeoffset(); - { - unsigned long lost = jiffies - wall_jiffies; - if (lost) - usec += lost * (1000000 / HZ); - } - 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; -} - -void do_settimeofday(struct timeval *tv) -{ - write_lock_irq(&xtime_lock); - tv->tv_usec -= do_gettimeoffset(); - tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); - - 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); -} - /* Includes for ioc3_init(). */ #include #include @@ -239,10 +186,12 @@ return mktime(year, month, date, hour, min, sec); } -void __init time_init(void) +void __init ip27_time_init(void) { xtime.tv_sec = get_m48t35_time(); xtime.tv_usec = 0; + + do_gettimeoffset = ip27_do_gettimeoffset; } void __init cpu_time_init(void) @@ -263,7 +212,7 @@ printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); - set_cp0_status(SRB_TIMOCLK, SRB_TIMOCLK); + set_cp0_status(SRB_TIMOCLK); } void __init hub_rtc_init(cnodeid_t cnode) diff -urN linux-2.4.18/arch/mips64/sgi-ip32/Makefile linux-2.4.19-pre5/arch/mips64/sgi-ip32/Makefile --- linux-2.4.18/arch/mips64/sgi-ip32/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/Makefile Sat Mar 30 22:55:27 2002 @@ -17,11 +17,9 @@ all: ip32-kern.a ip32-irq-glue.o -obj-y += ip32-irq.o ip32-rtc.o ip32-setup.o ip32-irq-glue.o \ - ip32-berr.o ip32-timer.o crime.o +obj-y += ip32-rtc.o ip32-setup.o ip32-irq.o ip32-irq-glue.o ip32-timer.o \ + crime.o ip32-reset.o -ifdef CONFIG_PCI -obj-y += ip32-pci.o ip32-pci-dma.o -endif +obj-$(CONFIG_PCI) += ip32-pci.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/mips64/sgi-ip32/crime.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/crime.c --- linux-2.4.18/arch/mips64/sgi-ip32/crime.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/crime.c Sat Mar 30 22:55:27 2002 @@ -10,7 +10,6 @@ #include #include #include -#include void __init crime_init (void) { diff -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-irq.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-irq.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-irq.c Sat Mar 30 22:55:27 2002 @@ -12,8 +12,12 @@ #include #include #include -#include #include +#include +#include +#include +#include +#include #include #include @@ -110,30 +114,31 @@ 0, "CRIME CPU error", NULL, NULL }; -unsigned long spurious_count = 0; extern void ip32_handle_int (void); -extern void do_IRQ (unsigned int irq, struct pt_regs *regs); +asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); -/* For interrupts wired from a single device to the CPU. Only the clock +/* + * For interrupts wired from a single device to the CPU. Only the clock * uses this it seems, which is IRQ 0 and IP7. */ -static void enable_cpu_irq (unsigned int irq) +static void enable_cpu_irq(unsigned int irq) { - set_cp0_status (STATUSF_IP7); + set_cp0_status(STATUSF_IP7); } -static unsigned int startup_cpu_irq (unsigned int irq) { - enable_cpu_irq (irq); +static unsigned int startup_cpu_irq(unsigned int irq) +{ + enable_cpu_irq(irq); return 0; } -static void disable_cpu_irq (unsigned int irq) +static void disable_cpu_irq(unsigned int irq) { - clear_cp0_status (STATUSF_IP7); + clear_cp0_status(STATUSF_IP7); } -static void end_cpu_irq (unsigned int irq) +static void end_cpu_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_cpu_irq (irq); @@ -158,34 +163,34 @@ * We get to split the register in half and do faster lookups. */ -static void enable_crime_irq (unsigned int irq) +static void enable_crime_irq(unsigned int irq) { u64 crime_mask; unsigned long flags; - save_and_cli (flags); - crime_mask = crime_read_64 (CRIME_INT_MASK); + save_and_cli(flags); + crime_mask = crime_read_64(CRIME_INT_MASK); crime_mask |= 1 << (irq - 1); - crime_write_64 (CRIME_INT_MASK, crime_mask); - restore_flags (flags); + crime_write_64(CRIME_INT_MASK, crime_mask); + restore_flags(flags); } -static unsigned int startup_crime_irq (unsigned int irq) +static unsigned int startup_crime_irq(unsigned int irq) { - enable_crime_irq (irq); + enable_crime_irq(irq); return 0; /* This is probably not right; we could have pending irqs */ } -static void disable_crime_irq (unsigned int irq) +static void disable_crime_irq(unsigned int irq) { u64 crime_mask; unsigned long flags; - save_and_cli (flags); - crime_mask = crime_read_64 (CRIME_INT_MASK); + save_and_cli(flags); + crime_mask = crime_read_64(CRIME_INT_MASK); crime_mask &= ~(1 << (irq - 1)); - crime_write_64 (CRIME_INT_MASK, crime_mask); - restore_flags (flags); + crime_write_64(CRIME_INT_MASK, crime_mask); + restore_flags(flags); } static void mask_and_ack_crime_irq (unsigned int irq) @@ -197,16 +202,16 @@ if ((irq <= CRIME_GBE0_IRQ && irq >= CRIME_GBE3_IRQ) || (irq <= CRIME_RE_EMPTY_E_IRQ && irq >= CRIME_RE_IDLE_E_IRQ) || (irq <= CRIME_SOFT0_IRQ && irq >= CRIME_SOFT2_IRQ)) { - save_and_cli (flags); - crime_mask = crime_read_64 (CRIME_HARD_INT); + save_and_cli(flags); + crime_mask = crime_read_64(CRIME_HARD_INT); crime_mask &= ~(1 << (irq - 1)); - crime_write_64 (CRIME_HARD_INT, crime_mask); - restore_flags (flags); + crime_write_64(CRIME_HARD_INT, crime_mask); + restore_flags(flags); } - disable_crime_irq (irq); + disable_crime_irq(irq); } - -static void end_crime_irq (unsigned int irq) + +static void end_crime_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_crime_irq (irq); @@ -225,48 +230,52 @@ NULL }; -/* This is for MACE PCI interrupts. We can decrease bus traffic by masking +/* + * This is for MACE PCI interrupts. We can decrease bus traffic by masking * as close to the source as possible. This also means we can take the * next chunk of the CRIME register in one piece. */ -static void enable_macepci_irq (unsigned int irq) +static void enable_macepci_irq(unsigned int irq) { u32 mace_mask; u64 crime_mask; unsigned long flags; - save_and_cli (flags); - mace_mask = mace_read_32 (MACEPCI_CONTROL); - mace_mask |= MACEPCI_CONTROL_INT (irq - 9); - mace_write_32 (MACEPCI_CONTROL, mace_mask); - /* In case the CRIME interrupt isn't enabled, we must enable it; + save_and_cli(flags); + mace_mask = mace_read_32(MACEPCI_CONTROL); + mace_mask |= MACEPCI_CONTROL_INT(irq - 9); + mace_write_32(MACEPCI_CONTROL, mace_mask); + /* + * In case the CRIME interrupt isn't enabled, we must enable it; * however, we never disable interrupts at that level. */ - crime_mask = crime_read_64 (CRIME_INT_MASK); + crime_mask = crime_read_64(CRIME_INT_MASK); crime_mask |= 1 << (irq - 1); - crime_write_64 (CRIME_INT_MASK, crime_mask); - restore_flags (flags); + crime_write_64(CRIME_INT_MASK, crime_mask); + restore_flags(flags); } -static unsigned int startup_macepci_irq (unsigned int irq) { +static unsigned int startup_macepci_irq(unsigned int irq) +{ enable_macepci_irq (irq); + return 0; /* XXX */ } -static void disable_macepci_irq (unsigned int irq) +static void disable_macepci_irq(unsigned int irq) { u32 mace_mask; unsigned long flags; - save_and_cli (flags); - mace_mask = mace_read_32 (MACEPCI_CONTROL); - mace_mask &= ~MACEPCI_CONTROL_INT (irq - 9); - mace_write_32 (MACEPCI_CONTROL, mace_mask); - restore_flags (flags); + save_and_cli(flags); + mace_mask = mace_read_32(MACEPCI_CONTROL); + mace_mask &= ~MACEPCI_CONTROL_INT(irq - 9); + mace_write_32(MACEPCI_CONTROL, mace_mask); + restore_flags(flags); } -static void end_macepci_irq (unsigned int irq) +static void end_macepci_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_macepci_irq (irq); @@ -311,34 +320,35 @@ break; } DBG ("crime_int %016lx enabled\n", crime_int); - save_and_cli (flags); - crime_mask = crime_read_64 (CRIME_INT_MASK); + save_and_cli(flags); + crime_mask = crime_read_64(CRIME_INT_MASK); crime_mask |= crime_int; - crime_write_64 (CRIME_INT_MASK, crime_mask); - mace_mask = mace_read_32 (MACEISA_INT_MASK); + crime_write_64(CRIME_INT_MASK, crime_mask); + mace_mask = mace_read_32(MACEISA_INT_MASK); mace_mask |= 1 << (irq - 33); - mace_write_32 (MACEISA_INT_MASK, mace_mask); - restore_flags (flags); + mace_write_32(MACEISA_INT_MASK, mace_mask); + restore_flags(flags); } -static unsigned int startup_maceisa_irq (unsigned int irq) { - enable_maceisa_irq (irq); +static unsigned int startup_maceisa_irq (unsigned int irq) +{ + enable_maceisa_irq(irq); return 0; } -static void disable_maceisa_irq (unsigned int irq) +static void disable_maceisa_irq(unsigned int irq) { u32 mace_mask; unsigned long flags; save_and_cli (flags); - mace_mask = mace_read_32 (MACEISA_INT_MASK); + mace_mask = mace_read_32(MACEISA_INT_MASK); mace_mask &= ~(1 << (irq - 33)); - mace_write_32 (MACEISA_INT_MASK, mace_mask); - restore_flags (flags); + mace_write_32(MACEISA_INT_MASK, mace_mask); + restore_flags(flags); } -static void mask_and_ack_maceisa_irq (unsigned int irq) +static void mask_and_ack_maceisa_irq(unsigned int irq) { u32 mace_mask; unsigned long flags; @@ -347,17 +357,17 @@ case MACEISA_PARALLEL_IRQ: case MACEISA_SERIAL1_TDMAPR_IRQ: case MACEISA_SERIAL2_TDMAPR_IRQ: - save_and_cli (flags); - mace_mask = mace_read_32 (MACEISA_INT_STAT); + save_and_cli(flags); + mace_mask = mace_read_32(MACEISA_INT_STAT); mace_mask &= ~(1 << (irq - 33)); - mace_write_32 (MACEISA_INT_STAT, mace_mask); - restore_flags (flags); + mace_write_32(MACEISA_INT_STAT, mace_mask); + restore_flags(flags); break; } - disable_maceisa_irq (irq); + disable_maceisa_irq(irq); } -static void end_maceisa_irq (unsigned irq) +static void end_maceisa_irq(unsigned irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_maceisa_irq (irq); @@ -380,7 +390,7 @@ * bits 0-3 and 7 in the CRIME register. */ -static void enable_mace_irq (unsigned int irq) +static void enable_mace_irq(unsigned int irq) { u64 crime_mask; unsigned long flags; @@ -392,13 +402,13 @@ restore_flags (flags); } -static unsigned int startup_mace_irq (unsigned int irq) +static unsigned int startup_mace_irq(unsigned int irq) { - enable_mace_irq (irq); + enable_mace_irq(irq); return 0; } -static void disable_mace_irq (unsigned int irq) +static void disable_mace_irq(unsigned int irq) { u64 crime_mask; unsigned long flags; @@ -407,10 +417,10 @@ crime_mask = crime_read_64 (CRIME_INT_MASK); crime_mask &= ~(1 << (irq - 1)); crime_write_64 (CRIME_INT_MASK, crime_mask); - restore_flags (flags); + restore_flags(flags); } -static void end_mace_irq (unsigned int irq) +static void end_mace_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_mace_irq (irq); @@ -452,56 +462,16 @@ mace = mace_read_32 (MACEPCI_CONTROL); printk ("MACE PCI control register: %08x\n", mace); - printk ("Register dump:\n"); - show_regs (regs); + printk("Register dump:\n"); + show_regs(regs); - printk ("Please mail this report to linux-mips@oss.sgi.com\n"); - printk ("Spinning..."); - while (1) ; -} - -void __init ip32_irq_init(void) -{ - unsigned int irq; - extern void init_generic_irq (void); - - /* Install our interrupt handler, then clear and disable all - * CRIME and MACE interrupts. - */ - crime_write_64 (CRIME_INT_MASK, 0); - crime_write_64 (CRIME_HARD_INT, 0); - crime_write_64 (CRIME_SOFT_INT, 0); - mace_write_32 (MACEISA_INT_STAT, 0); - mace_write_32 (MACEISA_INT_MASK, 0); - set_except_vector(0, ip32_handle_int); - - init_generic_irq (); - - for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { - hw_irq_controller *controller; - - if (irq == CLOCK_IRQ) - controller = &ip32_cpu_interrupt; - else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ) - controller = &ip32_mace_interrupt; - else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ) - controller = &ip32_macepci_interrupt; - else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ) - controller = &ip32_crime_interrupt; - else - controller = &ip32_maceisa_interrupt; - - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = 0; - irq_desc[irq].depth = 0; - irq_desc[irq].handler = controller; - } - setup_irq (CRIME_MEMERR_IRQ, &memerr_irq); - setup_irq (CRIME_CPUERR_IRQ, &cpuerr_irq); + printk("Please mail this report to linux-mips@oss.sgi.com\n"); + printk("Spinning..."); + while(1) ; } /* CRIME 1.1 appears to deliver all interrupts to this one pin. */ -void ip32_irq0 (struct pt_regs *regs) +void ip32_irq0(struct pt_regs *regs) { u64 crime_int = crime_read_64 (CRIME_INT_STAT); int irq = 0; @@ -525,32 +495,77 @@ irq = ffs (crime_int) + 16; } if (irq == 0) - ip32_unknown_interrupt (regs); - DBG ("*irq %u*\n", irq); - do_IRQ (irq, regs); + ip32_unknown_interrupt(regs); + DBG("*irq %u*\n", irq); + do_IRQ(irq, regs); } -void ip32_irq1 (struct pt_regs *regs) +void ip32_irq1(struct pt_regs *regs) { ip32_unknown_interrupt (regs); } -void ip32_irq2 (struct pt_regs *regs) +void ip32_irq2(struct pt_regs *regs) { ip32_unknown_interrupt (regs); } -void ip32_irq3 (struct pt_regs *regs) +void ip32_irq3(struct pt_regs *regs) { ip32_unknown_interrupt (regs); } -void ip32_irq4 (struct pt_regs *regs) +void ip32_irq4(struct pt_regs *regs) { ip32_unknown_interrupt (regs); } -void ip32_irq5 (struct pt_regs *regs) +void ip32_irq5(struct pt_regs *regs) { do_IRQ (CLOCK_IRQ, regs); +} + +void __init init_IRQ(void) +{ + unsigned int irq; + int i; + + /* Install our interrupt handler, then clear and disable all + * CRIME and MACE interrupts. + */ + crime_write_64(CRIME_INT_MASK, 0); + crime_write_64(CRIME_HARD_INT, 0); + crime_write_64(CRIME_SOFT_INT, 0); + mace_write_32(MACEISA_INT_STAT, 0); + mace_write_32(MACEISA_INT_MASK, 0); + set_except_vector(0, ip32_handle_int); + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &no_irq_type; + } + + for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { + hw_irq_controller *controller; + + if (irq == CLOCK_IRQ) + controller = &ip32_cpu_interrupt; + else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ) + controller = &ip32_mace_interrupt; + else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ) + controller = &ip32_macepci_interrupt; + else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ) + controller = &ip32_crime_interrupt; + else + controller = &ip32_maceisa_interrupt; + + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = 0; + irq_desc[irq].depth = 0; + irq_desc[irq].handler = controller; + } + setup_irq(CRIME_MEMERR_IRQ, &memerr_irq); + setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq); } diff -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-pci-dma.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-pci-dma.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-pci-dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-pci-dma.c Thu Jan 1 01:00:00 1970 @@ -1,41 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include - -#include -#include -#include - -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_cache_wback_inv((unsigned long) ret, 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 -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-pci.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-pci.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-pci.c Sat Mar 30 22:55:27 2002 @@ -152,7 +152,7 @@ if (request_irq (MACE_PCI_BRIDGE_IRQ, macepci_error, 0, "MACE PCI error", NULL)) - panic ("PCI bridge can't get interrupt; can't happen.\n"); + panic("PCI bridge can't get interrupt; can't happen."); pci_scan_bus (0, &macepci_ops, NULL); @@ -221,11 +221,30 @@ pci_write_config_byte (dev, PCI_CACHE_LINE_SIZE, 0x20); pci_write_config_byte (dev, PCI_LATENCY_TIMER, 0x30); pci_read_config_word (dev, PCI_COMMAND, &cmd); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_PARITY); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY); pci_write_config_word (dev, PCI_COMMAND, cmd); pci_set_master (dev); } - + /* + * Fixup O2 PCI slot. Bad hack. + */ +/* devtag = pci_make_tag(0, 0, 3, 0); + + slot = macepci_conf_read(0, devtag, PCI_COMMAND_STATUS_REG); + slot |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; + macepci_conf_write(0, devtag, PCI_COMMAND_STATUS_REG, slot); + + slot = macepci_conf_read(0, devtag, PCI_MAPREG_START); + if (slot == 0xffffffe1) + macepci_conf_write(0, devtag, PCI_MAPREG_START, 0x00001000); + + slot = macepci_conf_read(0, devtag, PCI_MAPREG_START + (2 << 2)); + if ((slot & 0xffff0000) == 0) { + slot += 0x00010000; + macepci_conf_write(0, devtag, PCI_MAPREG_START + (2 << 2), + 0x00000000); + } + */ #ifdef DEBUG_MACE_PCI printk ("Triggering PCI bridge interrupt...\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST); @@ -435,4 +454,8 @@ mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_INTERRUPT_TEST); } +} +unsigned __init int pcibios_assign_all_busses(void) +{ + return 0; } diff -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-reset.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-reset.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-reset.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,34 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Keith M Wesolowski + * Copyright (C) 2001 Paul Mundt + */ +#include + +#include +#include + +static void ip32_machine_restart(char *cmd) +{ + ArcReboot(); +} + +static inline void ip32_machine_halt(void) +{ + ArcEnterInteractiveMode(); +} + +static void ip32_machine_power_off(void) +{ + ip32_machine_halt(); +} + +void __init ip32_reboot_setup(void) +{ + _machine_restart = ip32_machine_restart; + _machine_halt = ip32_machine_halt; + _machine_power_off = ip32_machine_power_off; +} diff -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-setup.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-setup.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-setup.c Sat Mar 30 22:55:27 2002 @@ -12,10 +12,10 @@ #include #include #include -#include + +#include #include #include -#include #include #include #include @@ -25,8 +25,42 @@ extern struct rtc_ops ip32_rtc_ops; extern u32 cc_interval; -void __init ip32_init (int argc, char **argv, char **envp) { - arc_meminit (); +#ifdef CONFIG_SGI_O2MACE_ETH + +/* + * This is taken care of in here 'cause they say using Arc later on is + * problematic + */ +extern char o2meth_eaddr[8]; +static inline unsigned char str2hexnum(unsigned char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +static inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for (i = 0; i < 6; i++) { + unsigned char num; + + if(*str == ':') + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} +#endif + +extern void ip32_time_init(void); + +void __init bus_error_init(void) +{ } void __init ip32_setup(void) @@ -36,6 +70,8 @@ #endif TLBMISS_HANDLER_SETUP (); + mips_io_port_base = UNCACHEDADDR(MACEPCI_HI_IO);; + #ifdef CONFIG_SERIAL_CONSOLE ctype = ArcGetEnvironmentVariable("console"); if (*ctype == 'd') { @@ -45,12 +81,19 @@ console_setup ("ttyS0"); } #endif +#ifdef CONFIG_SGI_O2MACE_ETH + { + char *mac=ArcGetEnvironmentVariable("eaddr"); + str2eaddr(o2meth_eaddr, mac); + } +#endif #ifdef CONFIG_VT conswitchp = &dummy_con; #endif rtc_ops = &ip32_rtc_ops; + board_time_init = ip32_time_init; crime_init (); } diff -urN linux-2.4.18/arch/mips64/sgi-ip32/ip32-timer.c linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-timer.c --- linux-2.4.18/arch/mips64/sgi-ip32/ip32-timer.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/sgi-ip32/ip32-timer.c Sat Mar 30 22:55:27 2002 @@ -7,21 +7,47 @@ * * Copyright (C) 2001 Keith M Wesolowski */ -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include +#include +#include +#include +#include + +extern volatile unsigned long wall_jiffies; +extern rwlock_t xtime_lock; -extern u32 cc_interval; +u32 cc_interval; + +/* Cycle counter value at the previous timer interrupt.. */ +static unsigned int timerhi, timerlo; /* An arbitrary time; this can be decreased if reliability looks good */ #define WAIT_MS 10 #define PER_MHZ (1000000 / 2 / HZ) +/* + * Change this if you have some constant time drift + */ +#define USECS_PER_JIFFY (1000000/HZ) + -void __init ip32_timer_setup (struct irqaction *irq) { +void __init ip32_timer_setup (struct irqaction *irq) +{ u64 crime_time; u32 cc_tick; @@ -44,4 +70,170 @@ printk("%d MHz CPU detected\n", (int) (cc_interval / PER_MHZ)); setup_irq (CLOCK_IRQ, irq); +} + +struct irqaction irq0 = { NULL, SA_INTERRUPT, 0, + "timer", NULL, NULL}; + +void cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 count; + + /* + * The cycle counter is only 32 bit which is good for about + * a minute at current count rates of upto 150MHz or so. + */ + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + + write_32bit_cp0_register (CP0_COMPARE, + (u32) (count + cc_interval)); + kstat.irqs[0][irq]++; + do_timer (regs); + + if (!jiffies) + { + /* + * If jiffies has overflowed in this timer_interrupt we must + * update the timer[hi]/[lo] to make do_fast_gettimeoffset() + * quotient calc still valid. -arca + */ + timerhi = timerlo = 0; + } +} + +/* + * On MIPS only R4000 and better have a cycle counter. + * + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies; + u32 quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static u32 cached_quotient; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +void __init ip32_time_init(void) +{ + unsigned int epoch = 0, year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + + /* Attempt to guess the epoch. This is the same heuristic as in + * rtc.c so no stupid things will happen to timekeeping. Who knows, + * maybe Ultrix also uses 1952 as epoch ... + */ + if (year > 10 && year < 44) + epoch = 1980; + else if (year < 96) + epoch = 1952; + year += epoch; + + write_lock_irq (&xtime_lock); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + write_unlock_irq (&xtime_lock); + + write_32bit_cp0_register(CP0_COUNT, 0); + irq0.handler = cc_timer_interrupt; + + ip32_timer_setup (&irq0); + +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) + /* Set ourselves up for future interrupts */ + write_32bit_cp0_register(CP0_COMPARE, + read_32bit_cp0_register(CP0_COUNT) + + cc_interval); + change_cp0_status(ST0_IM, ALLINTS); + sti (); } diff -urN linux-2.4.18/arch/mips64/tools/Makefile linux-2.4.19-pre5/arch/mips64/tools/Makefile --- linux-2.4.18/arch/mips64/tools/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/mips64/tools/Makefile Sat Mar 30 22:55:27 2002 @@ -23,8 +23,7 @@ clean: rm -f offset.[hs] $(TARGET).new -mrproper: - rm -f offset.[hs] $(TARGET).new +mrproper: clean rm -f $(TARGET) include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/parisc/kernel/signal.c linux-2.4.19-pre5/arch/parisc/kernel/signal.c --- linux-2.4.18/arch/parisc/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/parisc/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -581,11 +581,7 @@ /* FALLTHRU */ default: - lock_kernel(); - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/parisc/kernel/syscall.S linux-2.4.19-pre5/arch/parisc/kernel/syscall.S --- linux-2.4.18/arch/parisc/kernel/syscall.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/parisc/kernel/syscall.S Sat Mar 30 22:55:33 2002 @@ -552,6 +552,8 @@ ENTRY_UHOH(shmctl) /* 195 */ ENTRY_SAME(ni_syscall) /* streams1 */ ENTRY_SAME(ni_syscall) /* streams2 */ + ENTRY_SAME(gettid) + ENTRY_SAME(tkill) .end diff -urN linux-2.4.18/arch/ppc/amiga/config.c linux-2.4.19-pre5/arch/ppc/amiga/config.c --- linux-2.4.18/arch/ppc/amiga/config.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/amiga/config.c Sat Mar 30 22:55:33 2002 @@ -983,8 +983,9 @@ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); if (AMIGAHW_PRESENT(ZORRO)) - len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n", - AMIGAHW_PRESENT(ZORRO3) ? " III" : "", + len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " + "Device%s\n", + AMIGAHW_PRESENT(ZORRO3) ? "I" : "", zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); #undef AMIGAHW_ANNOUNCE diff -urN linux-2.4.18/arch/ppc/boot/Makefile linux-2.4.19-pre5/arch/ppc/boot/Makefile --- linux-2.4.18/arch/ppc/boot/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/Makefile Sat Mar 30 22:55:27 2002 @@ -17,29 +17,24 @@ AFLAGS += -D__BOOTER__ OBJCOPY_ARGS = -O elf32-powerpc -ifeq ($(CONFIG_SMP),y) -TFTPSIMAGE=/tftpboot/sImage.smp -else -TFTPSIMAGE=/tftpboot/sImage -endif +MKIMAGE := ./utils/mkimage.wrapper -lib/zlib.a: +lib/zlib.a: lib/zlib.c $(MAKE) -C lib images/vmlinux.gz: $(TOPDIR)/vmlinux $(MAKE) -C images vmlinux.gz -# Subdirs and tools needed for each. -subdir-y := lib images common -subdir-$(CONFIG_ALL_PPC) += chrp pmac prep -tools-$(CONFIG_ALL_PPC) := addnote piggyback mknote hack-coff mkprep -subdir-$(CONFIG_4xx) += tree -subdir-$(CONFIG_8xx) += mbx -subdir-$(CONFIG_8260) += mbx -tools-$(CONFIG_GEMINI) := mksimage - -# These are dirs we don't want to go into on BOOT_TARGETS -NONBOOT := lib images common +# Subdirs and tools needed for each. Assume we always need to go into +# 'simple' unless told otherwise. +subdir-y := lib common simple +subdir-$(CONFIG_ALL_PPC) := chrp pmac prep +tools-$(CONFIG_ALL_PPC) := addnote mknote hack-coff mkprep +tools-$(CONFIG_4xx) := mktree + +# These are dirs we don't want to go into on BOOT_TARGETS. We have them for +# the 'depend' stage. +NONBOOT := lib common # These are the subdirs we want to use BOOTDIRS = $(filter-out $(NONBOOT), $(subdir-y)) @@ -50,37 +45,29 @@ $(MAKE) -C utils $(tools-y) # The targets all boards support for boot images. -BOOT_TARGETS = zImage -ifndef CONFIG_GEMINI -BOOT_TARGETS += zImage.initrd znetboot znetboot.initrd -endif +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd -$(BOOT_TARGETS): sImage vmapus lib/zlib.a images/vmlinux.gz maketools +$(BOOT_TARGETS): vmapus lib/zlib.a images/vmlinux.gz maketools ifneq ($(BOOTDIRS),) for d in $(BOOTDIRS); do $(MAKE) -C $$d $@; done endif -sImage: $(TOPDIR)/vmlinux -ifdef CONFIG_GEMINI - $(OBJCOPY) -I elf32-powerpc -O binary $(TOPDIR)/vmlinux images/sImage -endif - vmapus: $(TOPDIR)/vmlinux ifdef CONFIG_APUS $(STRIP) $(TOPDIR)/vmlinux -o images/vmapus gzip $(GZIP_FLAGS) images/vmapus endif -ifdef CONFIG_GEMINI -znetboot : zImage - cp images/sImage $(TFTPSIMAGE) -endif +# Make an image for PPCBoot +pImage: images/vmlinux.gz + $(MKIMAGE) -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \ + -n 'Linux-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)' \ + -d $< images/vmlinux.PPCBoot + ln -sf vmlinux.PPCBoot images/pImage -# Clean up after ourselves. We have to do it like this since only some dirs -# need to be gone into. -- Tom +# These are subdirs with files not normally rm'ed. -- Tom clean: $(MAKE) -C images clean - $(MAKE) -C tree clean $(MAKE) -C utils clean include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc/boot/chrp/Makefile linux-2.4.19-pre5/arch/ppc/boot/chrp/Makefile --- linux-2.4.18/arch/ppc/boot/chrp/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/chrp/Makefile Sat Mar 30 22:55:27 2002 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.13 07/27/01 20:24:17 trini +# BK Id: SCCS/s.Makefile 1.15 01/11/02 10:46:06 trini # # Makefile for making ELF bootable images for booting on CHRP # using Open Firmware. @@ -7,19 +7,9 @@ # # Based on coffboot by Paul Mackerras -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -AFLAGS += -Wa,-mppc64bridge -else -MSIZE= -endif - -.c.o: - $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< +USE_STANDARD_AS_RULE := true -LD_ARGS = -Ttext 0x00400000 +LD_ARGS = -T ../ld.script -Ttext 0x00400000 OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \ ../common/ofcommon.o @@ -27,23 +17,22 @@ ADDNOTE = ../utils/addnote PIGGYBACK = ../utils/piggyback +ifeq ($(CONFIG_PPC64BRIDGE),y) +END += .64 +AFLAGS += -Wa,-mppc64bridge +endif ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE) +END += .smp endif +TFTPIMAGE=/tftpboot/zImage.chrp$(END) + +AFLAGS_../common/crt0.o += -I$(TOPDIR)/arch/$(ARCH)/kernel + all: zImage znetboot: zImage -ifdef CONFIG_SMP - cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.smp -else - cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux -endif -ifdef CONFIG_PPC64BRIDGE - cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux.64 -endif + cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux$(END) cp ../images/zImage.chrp $(TFTPIMAGE) znetboot.initrd: zImage.initrd @@ -52,22 +41,28 @@ floppy: zImage mcopy zImage a:zImage -image.o: $(PIGGYBACK) ../images/vmlinux.gz - $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ - -sysmap.o: $(PIGGYBACK) $(TOPDIR)/System.map - $(PIGGYBACK) sysmap < $(TOPDIR)/System.map | $(AS) -o $@ - -initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) - $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ +image.o: ../images/vmlinux.gz ../common/dummy.o + $(OBJCOPY) ../common/dummy.o $@ \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data +ifdef CONFIG_XMON + $(OBJCOPY) $@ $@ \ + --add-section=.sysmap=$(TOPDIR)/System.map \ + --set-section-flags=.sysmap=contents,alloc,load,readonly,data +endif -zImage: $(OBJS) $(LIBS) ../common/no_initrd.o $(ADDNOTE) ../images/vmlinux.gz - $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) ../common/no_initrd.o $(LIBS) +zImage: $(OBJS) $(LIBS) $(ADDNOTE) + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS) + $(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment -R .ramdisk cp ../images/$@.chrp ../images/$@.chrp-rs6k $(ADDNOTE) ../images/$@.chrp-rs6k -zImage.initrd: $(OBJS) $(LIBS) initrd.o $(ADDNOTE) ../images/vmlinux.gz - $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) initrd.o $(LIBS) +zImage.initrd: $(OBJS) $(LIBS) $(ADDNOTE) ../images/ramdisk.image.gz + $(OBJCOPY) image.o image.o \ + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data + $(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS) + $(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment cp ../images/$@.chrp ../images/$@.chrp-rs6k $(ADDNOTE) ../images/$@.chrp-rs6k diff -urN linux-2.4.18/arch/ppc/boot/chrp/main.c linux-2.4.19-pre5/arch/ppc/boot/chrp/main.c --- linux-2.4.18/arch/ppc/boot/chrp/main.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/chrp/main.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.main.c 1.13 07/27/01 20:24:17 trini + * BK Id: SCCS/s.main.c 1.16 01/12/02 10:36:33 trini */ /* * Copyright (C) Paul Mackerras 1997. @@ -11,15 +11,14 @@ */ #include "nonstdio.h" #include +#include + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; -extern char _end[]; -extern char initrd_data[]; -extern char image_data[]; -extern char sysmap_data[]; extern int getprop(void *, const char *, void *, int); -extern int initrd_len; -extern int image_len; -extern int sysmap_len; extern unsigned int heap_max; extern void claim(unsigned int virt, unsigned int size, unsigned int align); extern void *finddevice(const char *); @@ -53,22 +52,27 @@ unsigned sa, len; void *dst; unsigned char *im; - unsigned initrd_start=0, initrd_size=0; - extern char _start; + unsigned int initrd_size, initrd_start; printf("chrpboot starting: loaded at 0x%p\n\r", &_start); - if (initrd_len) { - initrd_size = initrd_len; + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; claim(initrd_start, RAM_END - initrd_start, 0); printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else { + initrd_start = 0; + initrd_size = 0; + a2 = 0xdeadbeef; } - im = image_data; - len = image_len; + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); /* claim 4MB starting at PROG_START */ claim(PROG_START, PROG_SIZE - PROG_START, 0); dst = (void *) PROG_START; diff -urN linux-2.4.18/arch/ppc/boot/common/Makefile linux-2.4.19-pre5/arch/ppc/boot/common/Makefile --- linux-2.4.18/arch/ppc/boot/common/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/common/Makefile Sat Mar 30 22:55:27 2002 @@ -8,20 +8,10 @@ # Tom Rini January 2001 # -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -OBJCOPY_ARGS = -O elf32-powerpc +USE_STANDARD_AS_RULE := true coffcrt0.o: - $(CC) $(AFLAGS) -DXCOFF -traditional -c -o coffcrt0.o crt0.S + $(CC) -I$(TOPDIR)/arch/$(ARCH)/kernel $(AFLAGS) -DXCOFF \ + -traditional -c -o coffcrt0.o crt0.S include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc/boot/common/crt0.S linux-2.4.19-pre5/arch/ppc/boot/common/crt0.S --- linux-2.4.18/arch/ppc/boot/common/crt0.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/common/crt0.S Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.crt0.S 1.12 08/09/01 17:09:10 paulus + * BK Id: SCCS/s.crt0.S 1.14 01/11/02 10:46:07 trini */ /* Copyright (c) 1997 Paul Mackerras * Initial Power Macintosh COFF version. @@ -22,7 +22,7 @@ */ #include -#include "../../kernel/ppc_asm.tmpl" +#include "ppc_asm.h" .text diff -urN linux-2.4.18/arch/ppc/boot/common/dummy.c linux-2.4.19-pre5/arch/ppc/boot/common/dummy.c --- linux-2.4.18/arch/ppc/boot/common/dummy.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/common/dummy.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,7 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ +int main(void) +{ + return 0; +} diff -urN linux-2.4.18/arch/ppc/boot/common/misc-simple.c linux-2.4.19-pre5/arch/ppc/boot/common/misc-simple.c --- linux-2.4.18/arch/ppc/boot/common/misc-simple.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/common/misc-simple.c Sat Mar 30 22:55:27 2002 @@ -3,10 +3,10 @@ * * Misc. bootloader code for many machines. This assumes you have are using * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory - * below 8MB is free. Finally, it assumes you have a NS16550-style uart for + * below 8MB is free. Finally, it assumes you have a NS16550-style uart for * your serial console. If a machine meets these requirements, it can quite * likely use this code during boot. - * + * * Author: Matt Porter * Derived from arch/ppc/boot/prep/misc.c * @@ -25,50 +25,59 @@ #include #include #include +#include #include "nonstdio.h" #include "zlib.h" -unsigned long com_port; - -char *avail_ram; -char *end_avail; -extern char _end[]; - +/* Default cmdline */ #ifdef CONFIG_CMDLINE #define CMDLINE CONFIG_CMDLINE #else #define CMDLINE "" #endif + +/* Keyboard (and VGA console)? */ +#ifdef CONFIG_VGA_CONSOLE +#define HAS_KEYB 1 +#else +#define HAS_KEYB 0 +#endif + +char *avail_ram; +char *end_avail; +char *zimage_start; char cmd_preset[] = CMDLINE; char cmd_buf[256]; char *cmd_line = cmd_buf; +int keyb_present = HAS_KEYB; +int zimage_size; -unsigned long initrd_start = 0, initrd_end = 0; +unsigned long com_port; +unsigned long initrd_size = 0; -/* These values must be variables. If not, the compiler optimizer - * will remove some code, causing the size of the code to vary - * when these values are zero. This is bad because we first - * compile with these zero to determine the size and offsets - * in an image, than compile again with these set to the proper - * discovered value. - */ -unsigned int initrd_offset, initrd_size; -char *zimage_start; -int zimage_size; +/* The linker tells us various locations in the image */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; +extern char _end[]; +/* Original location */ +extern unsigned long start; +extern int CRT_tstc(void); +extern unsigned long serial_init(int chan, void *ignored); +extern void serial_close(unsigned long com_port); extern void gunzip(void *, int, unsigned char *, int *); -extern unsigned long serial_init(int chan); +extern void serial_fixups(void); -void +struct bi_record * decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) { - int timer = 0; - extern unsigned long start; char *cp, ch; + struct bi_record *rec, *birecs; - com_port = serial_init(0); + serial_fixups(); + com_port = serial_init(0, NULL); /* assume the chunk below 8M is free */ end_avail = (char *)0x00800000; @@ -88,42 +97,31 @@ puts("\n"); } - /* we have to subtract 0x10000 here to correct for objdump including - the size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - initrd_offset = INITRD_OFFSET; - initrd_size = INITRD_SIZE; - - if ( initrd_offset ) - initrd_start = load_addr - 0x10000 + initrd_offset; - else - initrd_start = 0; - initrd_end = initrd_size + initrd_start; + /* + * We link ourself to 0x00800000. When we run, we relocate + * ourselves there. So we just need __image_begin for the + * start. -- Tom + */ + zimage_start = (char *)(unsigned long)(&__image_begin); + zimage_size = (unsigned long)(&__image_end) - + (unsigned long)(&__image_begin); + + initrd_size = (unsigned long)(&__ramdisk_end) - + (unsigned long)(&__ramdisk_begin); - /* Relocate the zImage */ + /* + * The zImage and initrd will be between start and _end, so they've + * already been moved once. We're good to go now. -- Tom + */ avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); puts("zimage at: "); puthex((unsigned long)zimage_start); puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); - zimage_start = (char *)avail_ram; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); - if ( initrd_start ) { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - /* relocate initrd */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_size + - (unsigned long)zimage_start); - memcpy( (void *)avail_ram, (void *)initrd_start, initrd_size ); - initrd_start = (unsigned long)avail_ram; - initrd_end = initrd_start + initrd_size; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); + if ( initrd_size ) { + puts("initrd at: "); + puthex((unsigned long)(&__ramdisk_begin)); + puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); } avail_ram = (char *)0x00400000; @@ -131,11 +129,28 @@ puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); puthex((unsigned long)end_avail); puts("\n"); + if (keyb_present) + CRT_tstc(); /* Forces keyboard to be initialized */ +#ifdef CONFIG_GEMINI + /* + * If cmd_line is empty and cmd_preset is not, copy cmd_preset + * to cmd_line. This way we can override cmd_preset with the + * command line from Smon. + */ + + if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0')) + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); +#endif + /* Display standard Linux/PPC boot prompt for kernel args */ puts("\nLinux/PPC load: "); cp = cmd_line; memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); while ( *cp ) putc(*cp++); + +#ifndef CONFIG_GEMINI + /* Val Henson has requested that Gemini doesn't wait for the + * user to edit the cmdline or not. */ while (timer++ < 5*1000) { if (tstc()) { while ((ch = getc()) != '\n' && ch != '\r') { @@ -161,16 +176,44 @@ udelay(1000); /* 1 msec */ } *cp = 0; +#endif puts("\n"); - /* mappings on early boot can only handle 16M */ - if ( (u32)(cmd_line) > (16<<20)) - puts("cmd_line located > 16M\n"); - puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); + /* + * Create bi_recs for cmd_line and initrds + */ + rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) + + (1 << 20) - 1, (1 << 20)); + birecs = rec; + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if ( initrd_size ) { + rec->tag = BI_INITRD; + rec->data[0] = (unsigned long)(&__ramdisk_begin); + rec->data[1] = initrd_size; + rec->size = sizeof(struct bi_record) + 2 * + 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); puts("Now booting the kernel\n"); + serial_close(com_port); + + return birecs; } diff -urN linux-2.4.18/arch/ppc/boot/common/no_initrd.c linux-2.4.19-pre5/arch/ppc/boot/common/no_initrd.c --- linux-2.4.18/arch/ppc/boot/common/no_initrd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/common/no_initrd.c Thu Jan 1 01:00:00 1970 @@ -1,5 +0,0 @@ -/* - * BK Id: SCCS/s.no_initrd.c 1.7 05/18/01 15:17:23 cort - */ -char initrd_data[1]; -int initrd_len = 0; diff -urN linux-2.4.18/arch/ppc/boot/common/ns16550.c linux-2.4.19-pre5/arch/ppc/boot/common/ns16550.c --- linux-2.4.18/arch/ppc/boot/common/ns16550.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/common/ns16550.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ns16550.c 1.12 10/08/01 17:16:50 paulus + * BK Id: SCCS/s.ns16550.c 1.14 01/11/02 10:46:07 trini */ /* * COM1 NS16550 support @@ -10,7 +10,6 @@ #include #include -/* Default serial baud rate */ #define SERIAL_BAUD 9600 extern void outb(int port, unsigned char val); @@ -23,8 +22,10 @@ static int shift; -unsigned long serial_init(int chan) { +unsigned long serial_init(int chan, void *ignored) +{ unsigned long com_port; + unsigned char lcr, dlm; /* We need to find out which type io we're expecting. If it's * 'SERIAL_IO_PORT', we get an offset from the isa_io_base. @@ -43,30 +44,33 @@ /* How far apart the registers are. */ shift = rs_table[chan].iomem_reg_shift; - - /* See if port is present */ - outb(com_port + (UART_LCR << shift), 0x00); - outb(com_port + (UART_IER << shift), 0x00); + + /* save the LCR */ + lcr = inb(com_port + (UART_LCR << shift)); /* Access baud rate */ outb(com_port + (UART_LCR << shift), 0x80); + dlm = inb(com_port + (UART_DLM << shift)); /* * Test if serial port is unconfigured. * We assume that no-one uses less than 110 baud or * less than 7 bits per character these days. * -- paulus. */ - if (inb(com_port + (UART_DLM << shift)) > 4 - || (inb(com_port + (UART_LCR << shift)) & 2) == 0) { + + if ((dlm <= 4) && (lcr & 2)) + /* port is configured, put the old LCR back */ + outb(com_port + (UART_LCR << shift), lcr); + else { /* Input clock. */ outb(com_port + (UART_DLL << shift), (BASE_BAUD / SERIAL_BAUD)); outb(com_port + (UART_DLM << shift), (BASE_BAUD / SERIAL_BAUD) >> 8); + /* 8 data, 1 stop, no parity */ + outb(com_port + (UART_LCR << shift), 0x03); + /* RTS/DTR */ + outb(com_port + (UART_MCR << shift), 0x03); } - /* 8 data, 1 stop, no parity */ - outb(com_port + (UART_LCR << shift), 0x03); - /* RTS/DTR */ - outb(com_port + (UART_MCR << shift), 0x03); /* Clear & enable FIFOs */ outb(com_port + (UART_FCR << shift), 0x07); @@ -93,4 +97,9 @@ serial_tstc(unsigned long com_port) { return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0); +} + +void +serial_close(unsigned long com_port) +{ } diff -urN linux-2.4.18/arch/ppc/boot/common/ofcommon.c linux-2.4.19-pre5/arch/ppc/boot/common/ofcommon.c --- linux-2.4.18/arch/ppc/boot/common/ofcommon.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/common/ofcommon.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ofcommon.c 1.1 07/27/01 20:24:18 trini + * BK Id: SCCS/s.ofcommon.c 1.2 01/11/02 10:46:07 trini * * Copyright (C) Paul Mackerras 1997. * @@ -14,6 +14,9 @@ #include #include +/* Information from the linker */ +extern char __sysmap_begin, __sysmap_end; + extern int strcmp(const char *s1, const char *s2); extern char *avail_ram, *avail_high; extern char *end_avail; @@ -126,15 +129,22 @@ inflateEnd(&s); } -/* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, +/* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, * a machine type for BI_MACHTYPE, and the location where the end of the * bootloader is (PROG_START + PROG_SIZE) */ void make_bi_recs(unsigned long addr, char *name, unsigned int mach, unsigned long progend) { + unsigned long sysmap_size; struct bi_record *rec; + /* FIgure out the size of a possible System.map we're going to + * pass along. + * */ + sysmap_size = (unsigned long)(&__sysmap_end) - + (unsigned long)(&__sysmap_begin); + /* leave a 1MB gap then align to the next 1MB boundary */ addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); /* oldworld machine seem very unhappy about this. -- Tom */ @@ -150,21 +160,22 @@ sprintf( (char *)rec->data, name); rec->size = sizeof(struct bi_record) + strlen(name) + 1; rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_MACHTYPE; rec->data[0] = mach; rec->data[1] = 1; rec->size = sizeof(struct bi_record) + 2 * 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) + 2 * sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -#endif /* SYSMAP_OFFSET */ - + if (sysmap_size) { + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)(&__sysmap_begin); + rec->data[1] = sysmap_size; + rec->size = sizeof(struct bi_record) + 2 * + 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 -urN linux-2.4.18/arch/ppc/boot/common/relocate.S linux-2.4.19-pre5/arch/ppc/boot/common/relocate.S --- linux-2.4.18/arch/ppc/boot/common/relocate.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/common/relocate.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,210 @@ +/* + * arch/ppc/boot/simple/relocate.S + * + * This is the common part of the loader relocation and initialization + * process. All of the board/processor specific initialization is + * done before we get here. + * + * Author: Tom Rini + * trini@mvista.com + * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others). + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include "ppc_asm.h" + +#define GETSYM(reg, sym) \ + lis reg, sym@h; ori reg, reg, sym@l + + .text + /* We get called from the early initialization code. + * Register 3 has the address where we were loaded, + * Register 4 contains any residual data passed from the + * boot rom. + */ + .globl relocate +relocate: + /* Save r3, r4 for later. + * The r8/r11 are legacy registers so I don't have to + * rewrite the code below :-). + */ + mr r8, r3 + mr r11, r4 + + /* compute the size of the whole image in words. */ + GETSYM(r4,start) + GETSYM(r5,end) + + addi r5,r5,3 /* round up */ + sub r5,r5,r4 /* end - start */ + srwi r5,r5,2 + mr r7,r5 /* Save for later use. */ + + /* + * Check if we need to relocate ourselves to the link addr or were + * we loaded there to begin with. + */ + cmp cr0,r3,r4 + beq start_ldr /* If 0, we don't need to relocate */ + + /* Move this code somewhere safe. This is max(load + size, end) + * BIG ASSUMPTION: Addresses below 0x80000000 are assumed to be + * in RAM, and addresses above 0x80000000 are assumed to be in + * Flash. The cmpw instruction below does a signed integer + * comparison, so when comparing a RAM address to a Flash address + * the RAM address will always be greater. This allows the + * relocation to work when the load address is in Flash. + * r8 == load address + */ + GETSYM(r4, start) + GETSYM(r5, end) + + sub r6,r5,r4 + add r6,r8,r6 /* r6 == phys(load + size) */ + + cmpw r5,r6 + bgt 1f + b 2f +1: + mr r6, r5 +2: + /* dest is in r6 */ + /* Ensure alignment --- this code is precautionary */ + addi r6,r6,4 + li r5,0x0003 + andc r6,r6,r5 + + /* Find physical address and size of do_relocate */ + GETSYM(r5, __relocate_start) + GETSYM(r4, __relocate_end) + GETSYM(r3, start) + + /* Size to copy */ + sub r4,r4,r5 + srwi r4,r4,2 + + /* Src addr to copy (= __relocate_start - start + where_loaded) */ + sub r3,r5,r3 + add r5,r8,r3 + + /* Save dest */ + mr r3, r6 + + /* Do the copy */ + mtctr r4 +3: lwz r4,0(r5) + stw r4,0(r3) + addi r3,r3,4 + addi r5,r5,4 + bdnz 3b + + GETSYM(r4, __relocate_start) + GETSYM(r5, do_relocate) + + sub r4,r5,r4 /* Get entry point for do_relocate in + add r6,r6,r4 * relocated section */ + + /* This will return to the relocated do_relocate */ + mtlr r6 + b flush_instruction_cache + + .section ".relocate_code","xa" + +do_relocate: + /* We have 2 cases --- start < load, or start > load + * This determines whether we copy from the end, or the start. + * Its easier to have 2 loops than to have paramaterised + * loops. Sigh. + */ + li r6,0 /* Clear checksum */ + mtctr r7 /* Setup for a loop */ + + GETSYM(r4, start) + mr r3,r8 /* Get the load addr */ + + cmp cr0,r4,r3 /* If we need to copy from the end, do so */ + bgt do_relocate_from_end + +do_relocate_from_start: +1: lwz r5,0(r3) /* Load and decrement */ + stw r5,0(r4) /* Store and decrement */ + addi r3,r3,4 + addi r4,r4,4 + xor r6,r6,r5 /* Update checksum */ + bdnz 1b /* Are we done? */ + b do_relocate_out /* Finished */ + +do_relocate_from_end: + GETSYM(r3, end) + slwi r4,r7,2 + add r4,r8,r4 /* Get the physical end */ +1: lwzu r5,-4(r4) + stwu r5, -4(r3) + xor r6,r6,r5 + bdnz 1b + +do_relocate_out: + GETSYM(r3,start_ldr) + mtlr r3 /* Easiest way to do an absolute jump */ +/* Some boards don't boot up with the I-cache enabled. Do that + * now because the decompress runs much faster that way. + * As a side effect, we have to ensure the data cache is not enabled + * so we can access the serial I/O without trouble. + */ + b flush_instruction_cache + + .previous + +start_ldr: +/* Clear all of BSS and set up stack for C calls */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp cr0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 + + /* + * Exec kernel loader + */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + bl decompress_kernel + + /* + * Make sure the kernel knows we don't have things set in + * registers. -- Tom + */ + li r4,0 + li r6,0 + + /* + * Start at the begining. + */ + li r9,0x0000 + mtlr r9 + blr + + .comm .stack,4096*2,4 diff -urN linux-2.4.18/arch/ppc/boot/common/util.S linux-2.4.19-pre5/arch/ppc/boot/common/util.S --- linux-2.4.18/arch/ppc/boot/common/util.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/common/util.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,230 @@ +/* + * arch/ppc/boot/common/util.S + * + * Useful bootup functions, which are more easily done in asm than C. + * + * NOTE: Be very very careful about the registers you use here. + * We don't follow any ABI calling convention among the + * assembler functions that call each other, especially early + * in the initialization. Please preserve at least r3 and r4 + * for these early functions, as they often contain information + * passed from boot roms into the C decompress function. + * + * Author: Tom Rini + * trini@mvista.com + * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others). + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include "ppc_asm.h" + + + .text + + .globl disable_6xx_mmu +disable_6xx_mmu: + /* Establish default MSR value, exception prefix 0xFFF. + * If necessary, this function must fix up the LR if we + * return to a different address space once the MMU is + * disabled. + */ + li r8,MSR_IP|MSR_FP + mtmsr r8 + + /* Clear BATs */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT0L,r8 + mtspr DBAT1U,r8 + mtspr DBAT1L,r8 + mtspr DBAT2U,r8 + mtspr DBAT2L,r8 + mtspr DBAT3U,r8 + mtspr DBAT3L,r8 + mtspr IBAT0U,r8 + mtspr IBAT0L,r8 + mtspr IBAT1U,r8 + mtspr IBAT1L,r8 + mtspr IBAT2U,r8 + mtspr IBAT2L,r8 + mtspr IBAT3U,r8 + mtspr IBAT3L,r8 + isync + sync + sync + + /* Set segment registers */ + li r8,16 /* load up segment register values */ + mtctr r8 /* for context 0 */ + lis r8,0x2000 /* Ku = 1, VSID = 0 */ + li r10,0 +3: mtsrin r8,r10 + addi r8,r8,0x111 /* increment VSID */ + addis r10,r10,0x1000 /* address of next segment */ + bdnz 3b + + .globl disable_6xx_l1cache +disable_6xx_l1cache: + /* Enable, invalidate and then disable the L1 icache/dcache. */ + li r8,0 + ori r8,r8,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI) + mfspr r11,HID0 + or r11,r11,r8 + andc r10,r11,r8 + isync + mtspr HID0,r8 + sync + isync + mtspr HID0,r10 + sync + isync + blr + + .globl _setup_L2CR +_setup_L2CR: +/* + * We should be skipping this section on CPUs where this results in an + * illegal instruction. If not, please send trini@kernel.crashing.org + * the PVR of your CPU. + */ + /* Invalidate/disable L2 cache */ + sync + isync + mfspr r8,L2CR + rlwinm r8,r8,0,1,31 + oris r8,r8,0x0020 + sync + isync + mtspr L2CR,r8 + sync + isync + + /* Wait for the invalidation to complete */ +1: mfspr r8,L2CR + rlwinm. r9,r8,0,31,31 + bne 1b + + rlwinm r8,r8,0,11,9 /* Turn off L2I bit */ + sync + isync + mtspr L2CR,r8 + sync + isync + blr + + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,1 /* 601 ? */ + bne .udelay_not_601 +00: li r0,86 /* Instructions / microsecond? */ + mtctr r0 +10: addi r0,r0,0 /* NOP */ + bdnz 10b + subic. r3,r3,1 + bne 00b + blr + +.udelay_not_601: + mulli r4,r3,1000 /* nanoseconds */ + addi r4,r4,59 + li r5,60 + divw r4,r4,r5 /* BUS ticks */ +1: mftbu r5 + mftb r6 + mftbu r7 + cmp 0,r5,r7 + bne 1b /* Get [synced] base time */ + addc r9,r6,r4 /* Compute end time */ + addze r8,r5 +2: mftbu r5 + cmp 0,r5,r8 + blt 2b + bgt 3f + mftb r6 + cmp 0,r6,r9 + blt 2b +3: blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + + .section ".relocate_code","xa" +/* + * Flush and enable instruction cache + * First, flush the data cache in case it was enabled and may be + * holding instructions for copy back. + */ +_GLOBAL(flush_instruction_cache) + mflr r6 + bl flush_data_cache + +#ifdef CONFIG_8xx + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr IC_CST, r3 + lis r3, IDC_DISABLE@h + mtspr DC_CST, r3 +#elif CONFIG_4xx + lis r3,start@h # r9 = &_start + lis r4,_etext@ha + addi r4,r4,_etext@l # r8 = &_etext +1: dcbf r0,r3 # Flush the data cache + icbi r0,r3 # Invalidate the instruction cache + addi r3,r3,0x10 # Increment by one cache line + cmplwi cr0,r3,r4 # Are we at the end yet? + blt 1b # No, keep flushing and invalidating +#else + /* Enable, invalidate and then disable the L1 icache/dcache. */ + li r3,0 + ori r3,r3,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI) + mfspr r4,HID0 + or r5,r4,r3 + isync + mtspr HID0,r5 + sync + isync + ori r5,r4,HID0_ICE /* Enable cache */ + mtspr HID0,r5 + sync + isync +#endif + mtlr r6 + blr + +#define NUM_CACHE_LINES 128*8 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * Do this by just reading lots of stuff into the cache. + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,L1_CACHE_BYTES /* Next line, please */ + bdnz 00b +10: blr + + .previous + diff -urN linux-2.4.18/arch/ppc/boot/images/Makefile linux-2.4.19-pre5/arch/ppc/boot/images/Makefile --- linux-2.4.18/arch/ppc/boot/images/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/images/Makefile Sat Mar 30 22:55:27 2002 @@ -5,7 +5,7 @@ include $(TOPDIR)/Rules.make vmlinux.gz: $(TOPDIR)/vmlinux - $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + $(OBJCOPY) --strip-all -S -O binary $(TOPDIR)/vmlinux vmlinux gzip -vf9 vmlinux clean: diff -urN linux-2.4.18/arch/ppc/boot/ld.script linux-2.4.19-pre5/arch/ppc/boot/ld.script --- linux-2.4.18/arch/ppc/boot/ld.script Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/ld.script Sat Mar 30 22:55:27 2002 @@ -0,0 +1,83 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + .text : + { + *(.text) + *(.fixup) + __relocate_start = .; + *(.relocate_code) + __relocate_end = .; + } + _etext = .; + PROVIDE (etext = .); + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.data.boot) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + *(.rodata) + *(.rodata.*) + *(.rodata1) + *(.got1) + __image_begin = .; + *(.image) + __image_end = .; + . = ALIGN(4096); + __ramdisk_begin = .; + *(.ramdisk) + __ramdisk_end = .; + . = ALIGN(4096); + __sysmap_begin = .; + *(.sysmap) + __sysmap_end = .; + . = ALIGN(4096); + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff -urN linux-2.4.18/arch/ppc/boot/lib/zlib.c linux-2.4.19-pre5/arch/ppc/boot/lib/zlib.c --- linux-2.4.18/arch/ppc/boot/lib/zlib.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/lib/zlib.c Sat Mar 30 22:55:33 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.zlib.c 1.8 05/18/01 15:17:24 cort + * BK Id: SCCS/s.zlib.c 1.9 12/05/01 16:19:42 mporter */ /* * This file is derived from various .h and .c files from the zlib-0.95 @@ -651,11 +651,6 @@ /* load local pointers */ #define LOAD {LOADIN LOADOUT} -/* - * The IBM 150 firmware munges the data right after _etext[]. This - * protects it. -- Cort - */ -local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; /* And'ing with mask[n] masks the lower n bits */ local uInt inflate_mask[] = { 0x0000, @@ -933,7 +928,10 @@ { r = t; if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); s->mode = BADB; + } LEAVE } s->sub.trees.index = 0; @@ -969,6 +967,7 @@ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); s->mode = BADB; z->msg = "invalid bit length repeat"; r = Z_DATA_ERROR; @@ -996,7 +995,10 @@ if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); s->mode = BADB; + } r = t; LEAVE } diff -urN linux-2.4.18/arch/ppc/boot/mbx/Makefile linux-2.4.19-pre5/arch/ppc/boot/mbx/Makefile --- linux-2.4.18/arch/ppc/boot/mbx/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/Makefile Thu Jan 1 01:00:00 1970 @@ -1,149 +0,0 @@ -# BK Id: SCCS/s.Makefile 1.9 10/15/01 10:53:29 trini -# -# -# arch/ppc/mbxboot/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) 1994 by Linus Torvalds -# Adapted for PowerPC by Gary Thomas -# modified by Cort (cort@cs.nmt.edu) -# -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - -TFTPIMAGE := /tftpboot/zImage.embedded - -OFFSET := ../utils/offset -SIZE := ../utils/size - -LIBS := ../lib/zlib.a -OBJCOPY_ARGS := -O elf32-powerpc - -ifdef CONFIG_8xx -ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00180000 -OBJECTS := head.o m8xx_tty.o -CFLAGS += -DCONFIG_8xx -endif - -ifdef CONFIG_8260 -ZLINKFLAGS := -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00400000 -OBJECTS := head_8260.o m8260_tty.o embed_config.o -CFLAGS += -DCONFIG_8260 -endif - -OBJECTS += ../common/misc-common.o misc.o ../common/string.o -OBJCOPY_ARGS = -O elf32-powerpc - -ifeq ($(CONFIG_MBX),y) -OBJECTS += iic.o embed_config.o pci.o qspan_pci.o -CFLAGS += -DCONFIG_MBX -endif -ifeq ($(CONFIG_RPXLITE),y) -CFLAGS += -DCONFIG_RPXLITE -OBJECTS += iic.o embed_config.o -endif -ifeq ($(CONFIG_RPXCLASSIC),y) -CFLAGS += -DCONFIG_RPXCLASSIC -OBJECTS += iic.o embed_config.o pci.o qspan_pci.o -endif -ifeq ($(CONFIG_BSEIP),y) -CFLAGS += -DCONFIG_BSEIP -OBJECTS += iic.o embed_config.o -endif -ifeq ($(CONFIG_FADS),y) -CFLAGS += -DCONFIG_FADS -OBJECTS += embed_config.o -endif - -all: zImage - -misc.o: misc.c - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ - -DZIMAGE_SIZE=0 -c -o $@ $*.c - -zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz -# -# Recompile misc.o again with more 'correct' bogus offsets -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0x0008c8e3 -DINITRD_SIZE=0x0000111a \ - -DZIMAGE_OFFSET=0x00018000 -DZIMAGE_SIZE=0x000748e2 \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=../images/ramdisk.image.gz \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp $@ - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ - -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ - -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ - -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=../images/ramdisk.image.gz \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp ../images/$@.embedded -# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.embedded - rm -f $@.tmp $@ - -zImage: zvmlinux -ifeq ($(CONFIG_RPXCLASSIC),y) - dd if=../images/zvmlinux.embedded of=../images/zImage.embedded bs=65536 skip=1 -else - ln -sf ../images/zvmlinux.embedded ../images/zImage.embedded -endif - -zImage.initrd: zvmlinux.initrd -ifeq ($(CONFIG_RPXCLASSIC),y) - dd if=../images/zvmlinux.initrd.embedded of=../images/zImage.initrd.embedded bs=65536 skip=1 -else - ln -sf ../images/zvmlinux.initrd.embedded ../images/zImage.initrd.embedded -endif - -zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz -# -# Recompile misc.o again with more 'correct' bogus offsets -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=0x00018000 -DZIMAGE_SIZE=0x000748e2 \ - -c -o misc.o misc.c -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ - -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp ../images/$@.embedded -# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.embedded - rm -f $@.tmp $@ - -znetboot : zImage - cp ../images/zImage.embedded $(TFTPIMAGE) - -znetboot.initrd : zImage.initrd - cp ../images/zImage.initrd.embedded $(TFTPIMAGE) - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc/boot/mbx/embed_config.c linux-2.4.19-pre5/arch/ppc/boot/mbx/embed_config.c --- linux-2.4.18/arch/ppc/boot/mbx/embed_config.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/embed_config.c Thu Jan 1 01:00:00 1970 @@ -1,593 +0,0 @@ -/* - * BK Id: SCCS/s.embed_config.c 1.7 05/18/01 07:54:04 patch - */ - -/* Board specific functions for those embedded 8xx boards that do - * not have boot monitor support for board information. - */ -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#include -#endif - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); -static u_char aschex_to_byte(u_char *cp); - -/* Supply a default Ethernet address for those eval boards that don't - * ship with one. This is an address from the MBX board I have, so - * it is unlikely you will find it on your network. - */ -static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; - -#if defined(CONFIG_MBX) - -/* The MBX hands us a pretty much ready to go board descriptor. This - * is where the idea started in the first place. - */ -void -embed_config(bd_t *bd) -{ - u_char *mp; - u_char eebuf[128]; - int i; - - /* Read the first 128 bytes of the EEPROM. There is more, - * but this is all we need. - */ - iic_read(0xa4, eebuf, 0, 128); - - /* All we are looking for is the Ethernet MAC address. The - * first 8 bytes are 'MOTOROLA', so check for part of that. - * If it's there, assume we have a valid MAC address. If not, - * grab our default one. - */ - if ((*(uint *)eebuf) == 0x4d4f544f) - mp = &eebuf[0x4c]; - else - mp = (u_char *)def_enet_addr; - - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *mp++; - } - - /* The boot rom passes these to us in MHz. Linux now expects - * them to be in Hz. - */ - bd->bi_intfreq *= 1000000; - bd->bi_busfreq *= 1000000; - - /* Stuff a baud rate here as well. - */ - bd->bi_baudrate = 9600; -} -#endif /* CONFIG_MBX */ - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPX6) - -/* Helper functions for Embedded Planet boards. -*/ -static void -rpx_eth(bd_t *bd, u_char *cp) -{ - int i; - - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = aschex_to_byte(cp); - cp += 2; - } -} - -static uint -rpx_baseten(u_char *cp) -{ - uint retval; - - retval = 0; - - while (*cp != '\n') { - retval *= 10; - retval += (*cp) - '0'; - cp++; - } - return(retval); -} - -static void -rpx_brate(bd_t *bd, u_char *cp) -{ - uint rate; - - rate = 0; - - while (*cp != '\n') { - rate *= 10; - rate += (*cp) - '0'; - cp++; - } - - bd->bi_baudrate = rate * 100; -} - -static void -rpx_memsize(bd_t *bd, u_char *cp) -{ - uint size; - - size = 0; - - while (*cp != '\n') { - size *= 10; - size += (*cp) - '0'; - cp++; - } - - bd->bi_memsize = size * 1024 * 1024; -} - -static void -rpx_cpuspeed(bd_t *bd, u_char *cp) -{ - uint num, den; - - num = den = 0; - - while (*cp != '\n') { - num *= 10; - num += (*cp) - '0'; - cp++; - if (*cp == '/') { - cp++; - den = (*cp) - '0'; - break; - } - } - - /* I don't know why the RPX just can't state the actual - * CPU speed..... - */ - if (den) { - num /= den; - num *= den; - } - bd->bi_intfreq = bd->bi_busfreq = num * 1000000; - - /* The 8xx can only run a maximum 50 MHz bus speed (until - * Motorola changes this :-). Greater than 50 MHz parts - * run internal/2 for bus speed. - */ - if (num > 50) - bd->bi_busfreq /= 2; -} - -/* Because I didn't find anything that would do this....... -*/ -u_char -aschex_to_byte(u_char *cp) -{ - u_char byte, c; - - c = *cp++; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte = c * 16; - - c = *cp; - - if ((c >= 'A') && (c <= 'F')) { - c -= 'A'; - c += 10; - } - else if ((c >= 'a') && (c <= 'f')) { - c -= 'a'; - c += 10; - } - else { - c -= '0'; - } - - byte += c; - - return(byte); -} -#endif - -#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - -/* Read the EEPROM on the RPX-Lite board. -*/ -void -embed_config(bd_t *bd) -{ - u_char eebuf[256], *cp; - - /* Read the first 256 bytes of the EEPROM. I think this - * is really all there is, and I hope if it gets bigger the - * info we want is still up front. - */ -#if 1 - iic_read(0xa8, eebuf, 0, 128); - iic_read(0xa8, &eebuf[128], 128, 128); - - /* We look for two things, the Ethernet address and the - * serial baud rate. The records are separated by - * newlines. - */ - cp = eebuf; - for (;;) { - if (*cp == 'E') { - cp++; - if (*cp == 'A') { - cp += 2; - rpx_eth(bd, cp); - } - } - if (*cp == 'S') { - cp++; - if (*cp == 'B') { - cp += 2; - rpx_brate(bd, cp); - } - } - if (*cp == 'D') { - cp++; - if (*cp == '1') { - cp += 2; - rpx_memsize(bd, cp); - } - } - if (*cp == 'H') { - cp++; - if (*cp == 'Z') { - cp += 2; - rpx_cpuspeed(bd, cp); - } - } - - /* Scan to the end of the record. - */ - while ((*cp != '\n') && (*cp != 0xff)) - cp++; - - /* If the next character is a 0 or ff, we are done. - */ - cp++; - if ((*cp == 0) || (*cp == 0xff)) - break; - } - bd->bi_memstart = 0; -#else - /* For boards without initialized EEPROM. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (8 * 1024 * 1024); - bd->bi_intfreq = 48000000; - bd->bi_busfreq = 48000000; - bd->bi_baudrate = 9600; -#endif -} -#endif /* RPXLITE || RPXCLASSIC */ - -#ifdef CONFIG_BSEIP -/* Build a board information structure for the BSE ip-Engine. - * There is more to come since we will add some environment - * variables and a function to read them. - */ -void -embed_config(bd_t *bd) -{ - u_char *cp; - int i; - - /* Baud rate and processor speed will eventually come - * from the environment variables. - */ - bd->bi_baudrate = 9600; - - /* Get the Ethernet station address from the Flash ROM. - */ - cp = (u_char *)0xfe003ffa; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } - - /* The rest of this should come from the environment as well. - */ - bd->bi_memstart = 0; - bd->bi_memsize = (16 * 1024 * 1024); - bd->bi_intfreq = 48000000; - bd->bi_busfreq = 48000000; -} -#endif /* BSEIP */ - -#ifdef CONFIG_FADS -/* Build a board information structure for the FADS. - */ -void -embed_config(bd_t *bd) -{ - u_char *cp; - int i; - - /* Just fill in some known values. - */ - bd->bi_baudrate = 9600; - - /* Use default enet. - */ - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } - - bd->bi_memstart = 0; - bd->bi_memsize = (8 * 1024 * 1024); - bd->bi_intfreq = 40000000; - bd->bi_busfreq = 40000000; -} -#endif /* FADS */ - -#ifdef CONFIG_8260 -/* Compute 8260 clock values if the rom doesn't provide them. - * We can't compute the internal core frequency (I don't know how to - * do that). - */ -static void -clk_8260(bd_t *bd) -{ - uint scmr, vco_out, clkin; - uint plldf, pllmf, busdf, brgdf, cpmdf; - volatile immap_t *ip; - - ip = (immap_t *)IMAP_ADDR; - scmr = ip->im_clkrst.car_scmr; - - /* The clkin is always bus frequency. - */ - clkin = bd->bi_busfreq; - - /* Collect the bits from the scmr. - */ - plldf = (scmr >> 12) & 1; - pllmf = scmr & 0xfff; - cpmdf = (scmr >> 16) & 0x0f; - busdf = (scmr >> 20) & 0x0f; - - /* This is arithmetic from the 8260 manual. - */ - vco_out = clkin / (plldf + 1); - vco_out *= 2 * (pllmf + 1); - bd->bi_vco = vco_out; /* Save for later */ - - bd->bi_cpmfreq = vco_out / 2; /* CPM Freq, in MHz */ - - /* Set Baud rate divisor. The power up default is divide by 16, - * but we set it again here in case it was changed. - */ - ip->im_clkrst.car_sccr = 1; /* DIV 16 BRG */ - bd->bi_brgfreq = vco_out / 16; -} -#endif - -#ifdef CONFIG_EST8260 -void -embed_config(bd_t **bdp) -{ - u_char *cp; - int i; - bd_t *bd; - - bd = *bdp; -#if 0 - /* This is actually provided by my boot rom. I have it - * here for those people that may load the kernel with - * a JTAG/COP tool and not the rom monitor. - */ - bd->bi_baudrate = 115200; - bd->bi_intfreq = 200000000; - bd->bi_busfreq = 66666666; - bd->bi_cpmfreq = 66666666; - bd->bi_brgfreq = 33333333; - bd->bi_memsize = 16 * 1024 * 1024; -#else - /* The boot rom passes these to us in MHz. Linux now expects - * them to be in Hz. - */ - bd->bi_intfreq *= 1000000; - bd->bi_busfreq *= 1000000; - bd->bi_cpmfreq *= 1000000; - bd->bi_brgfreq *= 1000000; -#endif - - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } -} -#endif /* EST8260 */ - -#ifdef CONFIG_SBS8260 -/* We have to fill in everything. -*/ -static bd_t bdinfo; - -void -embed_config(bd_t **bdp) -{ - u_char *cp; - int i; - bd_t *bd; - - /* This should provided by the boot rom. - */ - bd = &bdinfo; - *bdp = bd; - bd->bi_baudrate = 9600; - bd->bi_memsize = 64 * 1024 * 1024; - - /* Set all of the clocks. We have to know the speed of the - * external clock. The development board had 66 MHz. - */ - bd->bi_busfreq = 66666666; - clk_8260(bd); - - /* I don't know how to compute this yet. - */ - bd->bi_intfreq = 133000000; - - - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } -} -#endif /* SBS8260 */ - -#ifdef CONFIG_RPX6 -/* The pointer we are given is for the string of key values. - */ -static bd_t bdinfo; - -void -embed_config(bd_t **bdp) -{ - u_char *cp, *keyvals; - int i; - bd_t *bd; - - keyvals = (u_char *)*bdp; - - bd = &bdinfo; - *bdp = bd; - - /* This is almost identical to the RPX-Lite/Classic functions - * on the 8xx boards. It would be nice to have a key lookup - * function in a string, but the format of all of the fields - * is slightly different. - */ - cp = keyvals; - for (;;) { - if (*cp == 'E') { - cp++; - if (*cp == 'A') { - cp += 2; - rpx_eth(bd, cp); - } - } - if (*cp == 'S') { - cp++; - if (*cp == 'B') { - cp += 2; - bd->bi_baudrate = rpx_baseten(cp); - } - } - if (*cp == 'D') { - cp++; - if (*cp == '1') { - cp += 2; - bd->bi_memsize = rpx_baseten(cp) * 1024 * 1024; - } - } - if (*cp == 'X') { - cp++; - if (*cp == 'T') { - cp += 2; - bd->bi_busfreq = rpx_baseten(cp); - } - } - if (*cp == 'N') { - cp++; - if (*cp == 'V') { - cp += 2; - bd->bi_nvsize = rpx_baseten(cp) * 1024 * 1024; - } - } - - /* Scan to the end of the record. - */ - while ((*cp != '\n') && (*cp != 0xff)) - cp++; - - /* If the next character is a 0 or ff, we are done. - */ - cp++; - if ((*cp == 0) || (*cp == 0xff)) - break; - } - bd->bi_memstart = 0; - - /* The memory size includes both the 60x and local bus DRAM. - * I don't want to use the local bus DRAM for real memory, - * so subtract it out. It would be nice if they were separate - * keys. - */ - bd->bi_memsize -= 32 * 1024 * 1024; - - /* Set all of the clocks. We have to know the speed of the - * external clock. - */ - clk_8260(bd); - - /* I don't know how to compute this yet. - */ - bd->bi_intfreq = 200000000; -} -#endif /* RPX6 for testing */ - -#ifdef CONFIG_ADS8260 -/* We have to fill in everything. -*/ -static bd_t bdinfo; - -void -embed_config(bd_t **bdp) -{ - u_char *cp; - int i; - bd_t *bd; - - /* This should provided by the boot rom. - */ - bd = &bdinfo; - *bdp = bd; - bd->bi_baudrate = 9600; - bd->bi_memsize = 16 * 1024 * 1024; - - /* Set all of the clocks. We have to know the speed of the - * external clock. The development board had 66 MHz. - */ - bd->bi_busfreq = 66666666; - clk_8260(bd); - - /* I don't know how to compute this yet. - */ - bd->bi_intfreq = 200000000; - - - cp = (u_char *)def_enet_addr; - for (i=0; i<6; i++) { - bd->bi_enetaddr[i] = *cp++; - } -} -#endif /* ADS8260 */ - diff -urN linux-2.4.18/arch/ppc/boot/mbx/gzimage.c linux-2.4.19-pre5/arch/ppc/boot/mbx/gzimage.c --- linux-2.4.18/arch/ppc/boot/mbx/gzimage.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/gzimage.c Thu Jan 1 01:00:00 1970 @@ -1,11 +0,0 @@ -/* - * BK Id: SCCS/s.gzimage.c 1.6 05/18/01 15:17:06 cort - */ -/* - * gzimage.c - * - * Dummy file to allow a compressed zImage to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_gzimage; diff -urN linux-2.4.18/arch/ppc/boot/mbx/head.S linux-2.4.19-pre5/arch/ppc/boot/mbx/head.S --- linux-2.4.18/arch/ppc/boot/mbx/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/head.S Thu Jan 1 01:00:00 1970 @@ -1,243 +0,0 @@ -/* - * BK Id: SCCS/s.head.S 1.9 05/18/01 07:54:04 patch - */ -#include -#include "../../kernel/ppc_defs.h" -#include "../../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * This code is loaded by the ROM loader at some arbitrary location. - * Move it to high memory so that it can load the kernel at 0x0000. - * - * This is a three step process that will also work when booting from - * a Flash PROM normally located in high memory. - * - * First, the entire image is loaded into some high memory address. - * This is usually at or above 0x02000000. This is done by a network - * boot function supported by the board or a debugger over BDM port. - * - * Second, the start up function here will relocate the decompress - * function to run at the link address of 0x01000000. - * - * Last, the decompression function will reloate the initrd, zImage, and - * the residual data to locations under 8 Meg. This is necessary because - * the embedded kernel start up uses 8 Meg translations to access physical - * space before the MMU is enabled. Finally, the zImage is uncompressed - * to location 0 and we jump to it. - * - * On the MBX, - * R1 - Stack pointer at a high memory address. - * R3 - Pointer to Board Information Block. - * R4 - Pointer to argument string. - * Interrupts masked, cache and MMU disabled. - * - * ...and the first and second functions listed above are - * done for us (it knows ELF images). - * - * For other embedded boards we build the Board Information Block. - */ - - .globl start -start: - bl start_ -start_: -#ifndef CONFIG_MBX - lis r11, local_bd_info@h - ori r11, r11, local_bd_info@l -#else - mr r11, r3 -#endif - - mfmsr r3 /* Turn off interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r3,r3,r4 - mtmsr r3 - - li r4,0 /* Zero DER to prevent FRZ */ - mtspr SPRN_DER,r4 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 -#if 0 - cmp 0,r3,r4 - beq start_ldr /* Branch if loaded OK */ -#endif - -/* - * no matter where we're loaded, move ourselves to -Ttext address - * This computes the sizes we need to determine other things. - */ - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr - -start_ldr: -/* Most 8xx boards don't boot up with the I-cache enabled. Do that - * now because the decompress runs much faster that way. - */ - lis r3, IDC_INVALL@h - mtspr IC_CST, r3 - lis r3, IDC_ENABLE@h - mtspr IC_CST, r3 - -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b - - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Perform configuration of the various boards. This is done - * by reading some configuration data from EEPROM and building - * the board information structure. - */ - mr r3, r11 - mr r21, r11 - mr r22, r8 - mr r23, r7 - mr r24, r6 - - bl embed_config - mr r3, r21 - bl serial_init /* Init MBX serial port */ - - mr r11, r21 - mr r8, r22 - mr r7, r23 - mr r6, r24 - -#ifdef CONFIG_MBX - /* On the MBX (or anything that will TFTP load an ELF image), - * we have to find the intermediate address. The ELF loader - * only moves the Linux boostrap/decompress, not the zImage. - */ -#define ILAP_ADDRESS 0xfa000020 - lis r8, ILAP_ADDRESS@h - lwz r8, ILAP_ADDRESS@l(r8) - addis r8, r8, 1 /* Add 64K */ -#endif - - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - - /* The world starts from the beginning. - */ - li r9,0x0 - mtlr r9 - - /* Invalidate the instruction cache because we just copied a - * bunch of kernel instructions. - */ - lis r9, IDC_INVALL@h - mtspr IC_CST, r9 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - - .comm .stack,4096*2,4 -#ifndef CONFIG_MBX -local_bd_info: - .long 0 - .long 0x01000000 - .long 64 - .long 64 - .long 0 - .long 0 - .long 0 -#endif diff -urN linux-2.4.18/arch/ppc/boot/mbx/head_8260.S linux-2.4.19-pre5/arch/ppc/boot/mbx/head_8260.S --- linux-2.4.18/arch/ppc/boot/mbx/head_8260.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/head_8260.S Thu Jan 1 01:00:00 1970 @@ -1,259 +0,0 @@ -/* - * BK Id: SCCS/s.head_8260.S 1.8 05/18/01 07:54:04 patch - */ -#include "../../kernel/ppc_defs.h" -#include "../../kernel/ppc_asm.tmpl" -#include -#include - - .text - -/* - * Boot loader philosophy: - * - * ROM loads us to some arbitrary location - * ROM loads these registers: - * - * R3 = Pointer to the board configuration data - * R5 = Pointer to Open Firmware data - * - * ROM jumps to start/start_ - * Move the boot code to the link address (4 MB) - * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 4 MB - * Decompress the kernel to 0 - * Jump to the kernel entry - * -- Cort - */ - .globl start -start: - bl start_ -start_: - mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ - mtmsr r3 - -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* round up */ - sub r5,r5,r4 - srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* - * no matter where we're loaded, move ourselves to -Ttext address - */ -relocate: - mflr r3 /* Compute code bias */ - subi r3,r3,4 - mr r8,r3 - lis r4,start@h - ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 - li r6,0 - subi r3,r3,4 /* Set up for loop */ - subi r4,r4,4 -00: lwzu r5,4(r3) - stwu r5,4(r4) - xor r6,r6,r5 - bdnz 00b - lis r3,start_ldr@h - ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ - blr -start_ldr: -/* Clear all of BSS */ - lis r3,edata@h - ori r3,r3,edata@l - lis r4,end@h - ori r4,r4,end@l - subi r3,r3,4 - subi r4,r4,4 - li r0,0 -50: stwu r0,4(r3) - cmp 0,r3,r4 - bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ - lis r1,.stack@h - ori r1,r1,.stack@l - addi r1,r1,4096*2 - subi r1,r1,256 - li r2,0x000F /* Mask pointer to 16-byte boundary */ - andc r1,r1,r2 - - /* Speed us up a little. - */ - bl flush_instruction_cache - -/* Run loader */ - mr r3,r8 /* Load point */ - mr r4,r7 /* Program length */ - mr r5,r6 /* Checksum */ - mr r6,r11 /* Residual data */ - mr r7,r25 /* OFW interfaces */ - bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ - li r9,0x4 - mtlr r9 - lis r10,0xdeadc0de@h - ori r10,r10,0xdeadc0de@l - li r9,0 - stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 -00: li r0,86 /* Instructions / microsecond? */ - mtctr r0 -10: addi r0,r0,0 /* NOP */ - bdnz 10b - subic. r3,r3,1 - bne 00b - blr - -.udelay_not_601: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 - blr - -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr - .comm .stack,4096*2,4 diff -urN linux-2.4.18/arch/ppc/boot/mbx/iic.c linux-2.4.19-pre5/arch/ppc/boot/mbx/iic.c --- linux-2.4.18/arch/ppc/boot/mbx/iic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/iic.c Thu Jan 1 01:00:00 1970 @@ -1,218 +0,0 @@ -/* - * BK Id: SCCS/s.iic.c 1.10 09/14/01 19:30:13 trini - */ - -/* Minimal support functions to read configuration from IIC EEPROMS - * on MPC8xx boards. Originally written for RPGC RPX-Lite. - * Dan Malek (dmalek@jlc.net). - */ -#include -#include -#include -#include - - -/* IIC functions. - * These are just the basic master read/write operations so we can - * examine serial EEPROM. - */ -void iic_read(uint devaddr, u_char *buf, uint offset, uint count); - -static int iic_init_done; - -static void -iic_init() -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - uint dpaddr; - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - /* Reset the CPM. This is necessary on the 860 processors - * that may have started the SCC1 ethernet without relocating - * the IIC. - * This also stops the Ethernet in case we were loaded by a - * BOOTP rom monitor. - */ - cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); - - /* Wait for it. - */ - while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); - - /* Remove any microcode patches. We will install our own - * later. - */ - cp->cp_cpmcr1 = 0; - cp->cp_cpmcr2 = 0; - cp->cp_cpmcr3 = 0; - cp->cp_cpmcr4 = 0; - cp->cp_rccr = 0; - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - /* Initialize Port B IIC pins. - */ - cp->cp_pbpar |= 0x00000030; - cp->cp_pbdir |= 0x00000030; - cp->cp_pbodr |= 0x00000030; - - /* Initialize the parameter ram. - */ - - /* Allocate space for a two transmit and one receive buffer - * descriptor in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0840; - - /* Set up the IIC parameters in the parameter ram. - */ - iip->iic_tbase = dpaddr; - iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); - - iip->iic_tfcr = SMC_EB; - iip->iic_rfcr = SMC_EB; - - /* This should really be done by the reader/writer. - */ - iip->iic_mrblr = 128; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Select an arbitrary address. Just make sure it is unique. - */ - i2c->i2c_i2add = 0x34; - - /* Make clock run maximum slow. - */ - i2c->i2c_i2brg = 7; - - /* Disable interrupts. - */ - i2c->i2c_i2cmr = 0; - i2c->i2c_i2cer = 0xff; - - /* Enable SDMA. - */ - immap->im_siu_conf.sc_sdcr = 1; - - iic_init_done = 1; -} - -/* Read from IIC. - * Caller provides device address, memory buffer, and byte count. - */ -static u_char iitemp[32]; - -void -iic_read(uint devaddr, u_char *buf, uint offset, uint count) -{ - volatile iic_t *iip; - volatile i2c8xx_t *i2c; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - volatile immap_t *immap; - u_char *tb; - uint temp; - - /* If the interface has not been initialized, do that now. - */ - if (!iic_init_done) - iic_init(); - - immap = (immap_t *)IMAP_ADDR; - cp = (cpm8xx_t *)&(immap->im_cpm); - - iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - i2c = (i2c8xx_t *)&(immap->im_i2c); - - tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; - - /* Send a "dummy write" operation. This is a write request with - * only the offset sent, followed by another start condition. - * This will ensure we start reading from the first location - * of the EEPROM. - */ - tb = iitemp; - tb = (u_char *)(((uint)tb + 15) & ~15); - tbdf->cbd_bufaddr = (int)tb; - *tb = devaddr & 0xfe; /* Device address */ - *(tb+1) = offset; /* Offset */ - tbdf->cbd_datlen = 2; /* Length */ - tbdf->cbd_sc = - BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 3) == 0); - - if (tbdf->cbd_sc & BD_SC_READY) - printf("IIC ra complete but tbuf ready\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#if 0 - /* We can't do this...there is no serial port yet! - */ - if (temp == 0) { - printf("Timeout reading EEPROM\n"); - return; - } -#endif -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; - - /* To read, we need an empty buffer of the proper length. - * All that is used is the first byte for address, the remainder - * is just used for timing (and doesn't really have to exist). - */ - tbdf->cbd_bufaddr = (int)tb; - *tb = devaddr | 1; /* Device address */ - rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ - tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ - tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; - rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; - - /* Chip bug, set enable here. - */ - i2c->i2c_i2mod = 1; /* Enable */ - i2c->i2c_i2cer = 0xff; - i2c->i2c_i2com = 0x81; /* Start master */ - - /* Wait for IIC transfer. - */ -#if 0 - while ((i2c->i2c_i2cer & 1) == 0); - - if (rbdf->cbd_sc & BD_SC_EMPTY) - printf("IIC read complete but rbuf empty\n"); -#else - temp = 10000000; - while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) - temp--; -#endif - - /* Chip errata, clear enable. - */ - i2c->i2c_i2mod = 0; -} diff -urN linux-2.4.18/arch/ppc/boot/mbx/m8260_tty.c linux-2.4.19-pre5/arch/ppc/boot/mbx/m8260_tty.c --- linux-2.4.18/arch/ppc/boot/mbx/m8260_tty.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/m8260_tty.c Thu Jan 1 01:00:00 1970 @@ -1,312 +0,0 @@ -/* - * BK Id: SCCS/s.m8260_tty.c 1.7 05/18/01 07:54:04 patch - */ - - -/* Minimal serial functions needed to send messages out the serial - * port on SMC1. - */ -#include -#include -#include - -uint no_print; -extern char *params[]; -extern int nparams; -static u_char cons_hold[128], *sgptr; -static int cons_hold_cnt; - -/* If defined, enables serial console. The value (1 through 4) - * should designate which SCC is used, but this isn't complete. Only - * SCC1 is known to work at this time. - */ -#ifdef CONFIG_SCC_CONSOLE -#define SCC_CONSOLE 1 -#endif - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile scc_t *sccp; - volatile scc_uart_t *sup; - volatile cbd_t *tbdf, *rbdf; - volatile immap_t *ip; - volatile iop8260_t *io; - volatile cpm8260_t *cp; - uint dpaddr, memaddr; - - ip = (immap_t *)IMAP_ADDR; - cp = &ip->im_cpm; - io = &ip->im_ioport; - - /* Perform a reset. - */ - cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); - - /* Wait for it. - */ - while (cp->cp_cpcr & CPM_CR_FLG); - -#ifdef CONFIG_ADS8260 - /* Enable the RS-232 transceivers. - */ - *(volatile uint *)(BCSR_ADDR + 4) &= - ~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2); -#endif - -#ifdef SCC_CONSOLE - sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]); - sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - /* Use Port D for SCC1 instead of other functions. - */ - io->iop_ppard |= 0x00000003; - io->iop_psord &= ~0x00000001; /* Rx */ - io->iop_psord |= 0x00000002; /* Tx */ - io->iop_pdird &= ~0x00000001; /* Rx */ - io->iop_pdird |= 0x00000002; /* Tx */ - -#else - sp = (smc_t*)&(ip->im_smc[0]); - *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; - up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - - /* Use Port D for SMC1 instead of other functions. - */ - io->iop_ppard |= 0x00c00000; - io->iop_pdird |= 0x00400000; - io->iop_pdird &= ~0x00800000; - io->iop_psord &= ~0x00c00000; -#endif - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. - */ - memaddr = (bd->bi_memsize - 256) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+128; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ -#ifdef SCC_CONSOLE - sup->scc_genscc.scc_rbase = dpaddr; - sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t); - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; - sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; - - sup->scc_genscc.scc_mrblr = 128; - sup->scc_maxidl = 8; - sup->scc_brkcr = 1; - sup->scc_parec = 0; - sup->scc_frmec = 0; - sup->scc_nosec = 0; - sup->scc_brkec = 0; - sup->scc_uaddr1 = 0; - sup->scc_uaddr2 = 0; - sup->scc_toseq = 0; - sup->scc_char1 = 0x8000; - sup->scc_char2 = 0x8000; - sup->scc_char3 = 0x8000; - sup->scc_char4 = 0x8000; - sup->scc_char5 = 0x8000; - sup->scc_char6 = 0x8000; - sup->scc_char7 = 0x8000; - sup->scc_char8 = 0x8000; - sup->scc_rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sccp->scc_gsmrh = 0; - sccp->scc_gsmrl = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - sccp->scc_sccm = 0; - sccp->scc_scce = 0xffff; - sccp->scc_dsr = 0x7e7e; - sccp->scc_pmsr = 0x3000; - - /* Wire BRG1 to SCC1. The console driver will take care of - * others. - */ - ip->im_cpmux.cmx_scr = 0; -#else - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = CPMFCR_EB; - up->smc_tfcr = CPMFCR_EB; - up->smc_brklen = 0; - up->smc_brkec = 0; - up->smc_brkcr = 0; - up->smc_mrblr = 128; - up->smc_maxidl = 8; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - */ - ip->im_cpmux.cmx_smr = 0; -#endif - - /* The baud rate divisor needs to be coordinated with clk_8260(). - */ - ip->im_brgc1 = - (((bd->bi_brgfreq/16) / bd->bi_baudrate) << 1) | - CPM_BRG_EN; - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Initialize Tx/Rx parameters. - */ -#ifdef SCC_CONSOLE - sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#else - cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -#endif -} - -void -serial_putc(void *ignored, const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile scc_uart_t *sup; - volatile immap_t *ip; - extern bd_t *board_info; - - ip = (immap_t *)IMAP_ADDR; -#ifdef SCC_CONSOLE - sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; - tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; -#else - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; -#endif - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc(void *ignored) -{ - char c; - - if (cons_hold_cnt <= 0) { - cons_hold_cnt = serial_readbuf(cons_hold); - sgptr = cons_hold; - } - c = *sgptr++; - cons_hold_cnt--; - - return(c); -} - -int -serial_readbuf(u_char *cbuf) -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - volatile scc_uart_t *sup; - volatile immap_t *ip; - int i, nc; - - ip = (immap_t *)IMAP_ADDR; - -#ifdef SCC_CONSOLE - sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; - rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; -#else - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; -#endif - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - nc = rbdf->cbd_datlen; - for (i=0; icbd_sc |= BD_SC_EMPTY; - - return(nc); -} - -int -serial_tstc(void *ignored) -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - volatile scc_uart_t *sup; - volatile immap_t *ip; - - ip = (immap_t *)IMAP_ADDR; -#ifdef SCC_CONSOLE - sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; - rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; -#else - up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); - rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; -#endif - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -urN linux-2.4.18/arch/ppc/boot/mbx/m8xx_tty.c linux-2.4.19-pre5/arch/ppc/boot/mbx/m8xx_tty.c --- linux-2.4.18/arch/ppc/boot/mbx/m8xx_tty.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/m8xx_tty.c Thu Jan 1 01:00:00 1970 @@ -1,288 +0,0 @@ -/* - * BK Id: SCCS/s.m8xx_tty.c 1.10 09/14/01 19:30:13 trini - */ - - -/* Minimal serial functions needed to send messages out the serial - * port on the MBX console. - * - * The MBX uxes SMC1 for the serial port. We reset the port and use - * only the first BD that EPPC-Bug set up as a character FIFO. - * - * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug - * use COM1 instead of SMC1 as the console port. This kinda sucks - * for the rest of the kernel, so here we force the use of SMC1 again. - */ -#include -#include -#include -#include -#include - -#ifdef CONFIG_MBX -#define MBX_CSR1 ((volatile u_char *)0xfa100000) -#define CSR1_COMEN (u_char)0x02 -#endif - -#ifdef TQM_SMC2_CONSOLE -#define PROFF_CONS PROFF_SMC2 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 -#define SMC_INDEX 1 -static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); -#else -#define PROFF_CONS PROFF_SMC1 -#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 -#define SMC_INDEX 0 -#endif - -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - uint dpaddr, memaddr, ui; - - cp = cpmp; - sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); - up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - -#ifdef CONFIG_FADS - /* Enable SMC1/2 transceivers. - */ - *((volatile uint *)BCSR1) &= ~(BCSR1_RS232EN_1|BCSR1_RS232EN_2); -#endif - -#ifndef CONFIG_MBX - { - /* Initialize SMCx and use it for the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - -#ifdef TQM_SMC2_CONSOLE - /* Use Port A for SMC2 instead of other functions. - */ - iopp->iop_papar |= 0x00c0; - iopp->iop_padir &= ~0x00c0; - iopp->iop_paodr &= ~0x00c0; -#else - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; -#endif - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory for SMC FIFOs. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - * This wires BRG1 to SMC1 and BRG2 to SMC2; - */ - cp->cp_simode = 0x10000000; - ui = bd->bi_intfreq / 16 / bd->bi_baudrate; -#ifdef TQM_SMC2_CONSOLE - cp->cp_brgc2 = -#else - cp->cp_brgc1 = -#endif - ((ui - 1) < 4096) - ? (((ui - 1) << 1) | CPM_BRG_EN) - : ((((ui / 16) - 1) << 1) | CPM_BRG_EN | CPM_BRG_DIV16); - -#else /* CONFIG_MBX */ - if (*MBX_CSR1 & CSR1_COMEN) { - /* COM1 is enabled. Initialize SMC1 and use it for - * the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. EPPC-Bug isn't - * running any more, so we can do this. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - */ - cp->cp_simode = 0x10000000; - cp->cp_brgc1 = - (((bd->bi_intfreq/16) / 9600) << 1) | CPM_BRG_EN; - - /* Enable SMC1 for console output. - */ - *MBX_CSR1 &= ~CSR1_COMEN; - } - else { -#endif /* ndef CONFIG_MBX */ - /* SMCx is used as console port. - */ - tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; - - /* Issue a stop transmit, and wait for it. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, - CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - } - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putc(void *ignored, const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc(void *ignored) -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - char c; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - c = *buf; - rbdf->cbd_sc |= BD_SC_EMPTY; - - return(c); -} - -int -serial_tstc(void *ignored) -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -urN linux-2.4.18/arch/ppc/boot/mbx/misc.c linux-2.4.19-pre5/arch/ppc/boot/mbx/misc.c --- linux-2.4.18/arch/ppc/boot/mbx/misc.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/misc.c Thu Jan 1 01:00:00 1970 @@ -1,248 +0,0 @@ -/* - * BK Id: SCCS/s.misc.c 1.15 10/15/01 10:53:29 trini - */ -/* - * Adapted for PowerPC by Gary Thomas - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) - * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort - */ - -#include -#include -#include "zlib.h" -#include -#include -#include -#include -#include -#ifdef CONFIG_8xx -#include -#endif -#ifdef CONFIG_8260 -#include -#endif - -#include "nonstdio.h" - -/* - * The following references are needed to cause the linker to pull in the - * gzimage.o and rdimage.o files. These object files are special, - * since they get placed into the .gzimage and .rdimage ELF sections - * of the zvmlinux and zvmlinux.initrd files. - */ -extern char dummy_for_gzimage; -extern char dummy_for_rdimage; - -/* - * Please send me load/board info and such data for hardware not - * listed here so I can keep track since things are getting tricky - * with the different load addrs with different firmware. This will - * help to avoid breaking the load/boot process. - * -- Cort - */ -char *avail_ram; -char *end_avail; - -/* Because of the limited amount of memory on embedded, it presents - * loading problems. The biggest is that we load this boot program - * into a relatively low memory address, and the Linux kernel Bss often - * extends into this space when it get loaded. When the kernel starts - * and zeros the BSS space, it also writes over the information we - * save here and pass to the kernel (command line and board info). - * On these boards, we grab some known memory holes to hold this information. - */ -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -/* We need to pass along a 'dummy' com_port. */ -unsigned long com_port = 0; - -/* This is the default cmdline that will be given to the user at boot time.. - * If none was specified at compile time, we'll give it one that should work. - * -- Tom */ -#ifdef CONFIG_CMDLINE_BOOL -char compiled_string[] = CONFIG_CMDLINE; -#endif -char ramroot_string[] = "root=/dev/ram"; -char netroot_string[] = "root=/dev/nfs rw"; - -bd_t hold_resid_buf; -bd_t *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; -char *zimage_start; - -extern void gunzip(void *, int, unsigned char *, int *); - -unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) -{ - int timer, zimage_size = ZIMAGE_SIZE; - extern unsigned long start; - char *cp, ch; - -#ifdef CONFIG_8260 - /* I don't know why I didn't do it this way on the 8xx....... - */ - embed_config(&bp); - serial_init(bp); -#endif - - /* Grab some space for the command line and board info. Since - * we no longer use the ELF header, but it was loaded, grab - * that space. - */ -#ifdef CONFIG_MBX - cmd_line = (char *)(load_addr - 0x10000); - - /* To be like everyone else, we need one too, although this - * board information is passed from the boot rom. - */ - bp->bi_baudrate = 9600; -#else - cmd_line = (char *)(0x200000); -#endif - hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); - /* copy board data */ - if (bp) - memcpy(hold_residual,bp,sizeof(bd_t)); - - /* Set end of memory available to us. It is always the highest - * memory address provided by the board information. - */ - end_avail = (char *)(bp->bi_memsize); - - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( bp ) - { - puts("board data at: "); puthex((unsigned long)bp); - puts(" "); - puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); - puts("\n"); - } - - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; - else - initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; - - /* - * setup avail_ram - this is the first part of ram usable - * by the uncompress code. -- Cort - */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); - if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)(load_addr+(num_words*4)); - if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)((unsigned long)&start+(num_words*4)); - - /* relocate zimage */ - puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - /* - * There is no reason (yet) to relocate zImage for embedded boards. - * To support boot from flash rom on 8xx embedded boards, I - * assume if zimage start is over 16M we are booting from flash. - * In this case, avilable ram will start just above the space we - * have allocated for the command buffer and board information. - */ - if ((unsigned long)zimage_start > 0x01000000) - avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); - - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - - /* We only have to relocate initrd if we find it is in Flash - * rom. This is because the kernel thinks it can toss the - * pages into the free memory pool after it is done. Use - * the same 16M test. - */ - if ((unsigned long)initrd_start > 0x01000000) { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), - (void *)initrd_start, - INITRD_SIZE ); - initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); - initrd_end = initrd_start + INITRD_SIZE; - end_avail = (char *)initrd_start; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - else { - avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); - } - } - - - puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); - puthex((unsigned long)end_avail); puts("\n"); - puts("\nLinux/PPC load: "); - timer = 0; - cp = cmd_line; - /* This is where we try and pick the right command line for booting. - * If we were given one at compile time, use it. It Is Right. - * If we weren't, see if we have a ramdisk. If so, thats root. - * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom */ -#ifdef CONFIG_CMDLINE_BOOL - memcpy (cmd_line, compiled_string, sizeof(compiled_string)); -#else - if (initrd_start) - memcpy (cmd_line, ramroot_string, sizeof(ramroot_string)); - else - memcpy (cmd_line, netroot_string, sizeof(netroot_string)); -#endif - while ( *cp ) putc(*cp++); - while (timer++ < 5*1000) { - if (tstc()) { - while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b' || ch == '\177') { - if (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else if (ch == '\030' /* ^x */ - || ch == '\025') { /* ^u */ - while (cp != cmd_line) { - cp--; - puts("\b \b"); - } - } else { - *cp++ = ch; - putc(ch); - } - } - break; /* Exit 'timer' loop */ - } - udelay(1000); /* 1 msec */ - } - *cp = 0; - puts("\nUncompressing Linux..."); - - gunzip(0, 0x400000, zimage_start, &zimage_size); - puts("done.\n"); - puts("Now booting the kernel\n"); - return (unsigned long)hold_residual; -} diff -urN linux-2.4.18/arch/ppc/boot/mbx/pci.c linux-2.4.19-pre5/arch/ppc/boot/mbx/pci.c --- linux-2.4.18/arch/ppc/boot/mbx/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/pci.c Thu Jan 1 01:00:00 1970 @@ -1,255 +0,0 @@ -/* - * BK Id: SCCS/s.pci.c 1.6 05/18/01 15:17:06 cort - */ -/* Stand alone funtions for QSpan Tundra support. - */ -#include -#include -#include -#include - -/* To map PCI devices, you first write 0xffffffff into the device - * base address registers. When the register is read back, the - * number of most significant '1' bits describes the amount of address - * space needed for mapping. If the most significant bit is not set, - * either the device does not use that address register, or it has - * a fixed address that we can't change. After the address is assigned, - * the command register has to be written to enable the card. - */ -typedef struct { - u_char pci_bus; - u_char pci_devfn; - ushort pci_command; - uint pci_addrs[6]; -} pci_map_t; - -/* We should probably dynamically allocate these structures. -*/ -#define MAX_PCI_DEVS 32 -int pci_dev_cnt; -pci_map_t pci_map[MAX_PCI_DEVS]; - -void pci_conf_write(int bus, int device, int func, int reg, uint writeval); -void pci_conf_read(int bus, int device, int func, int reg, void *readval); -void probe_addresses(int bus, int devfn); -void map_pci_addrs(void); - -/* This is a really stripped version of PCI bus scan. All we are - * looking for are devices that exist. - */ -pci_scanner(int addr_probe) -{ - unsigned int devfn, l, max, class, bus_number; - unsigned char cmd, irq, tmp, hdr_type, is_multi; - int reg; - - is_multi = 0; - bus_number = 0; - for (devfn = 0; devfn < 0xff; ++devfn) { - /* The device numbers are comprised of upper 5 bits of - * device number and lower 3 bits of multi-function number. - */ - if ((devfn & 7) && !is_multi) { - /* Don't scan multifunction addresses if this is - * not a multifunction device. - */ - continue; - } - - /* Read the header to determine card type. - */ - qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, - &hdr_type); - - /* If this is a base device number, check the header to - * determine if it is mulifunction. - */ - if ((devfn & 7) == 0) - is_multi = hdr_type & 0x80; - - /* Check to see if the board is really in the slot. - */ - qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); - /* some broken boards return 0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || - l == 0xffff0000) { - /* Nothing there. - */ - is_multi = 0; - continue; - } - - /* If we are not performing an address probe, - * just simply print out some information. - */ - if (!addr_probe) { - qs_pci_read_config_dword(bus_number, devfn, - PCI_CLASS_REVISION, &class); - - class >>= 8; /* upper 3 bytes */ - -#if 0 - printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", - (devfn >> 3), (devfn & 7), - (l & 0xffff), (l >> 16) & 0xffff, class); -#else - puts("Found ("); puthex(devfn >> 3); - puts(":"); puthex(devfn & 7); - puts("): vendor "); puthex(l & 0xffff); - puts(", device "); puthex((l >> 16) & 0xffff); - puts(", class "); puthex(class); puts("\n"); -#endif - } - else { - /* If this is a "normal" device, build address list. - */ - if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) - probe_addresses(bus_number, devfn); - } - } - - /* Now map the boards. - */ - if (addr_probe) - map_pci_addrs(); -} - -/* Probe addresses for the specified device. This is a destructive - * operation because it writes the registers. - */ -void -probe_addresses(bus, devfn) -{ - int i; - uint pciaddr; - ushort pcicmd; - pci_map_t *pm; - - if (pci_dev_cnt >= MAX_PCI_DEVS) { - puts("Too many PCI devices\n"); - return; - } - - pm = &pci_map[pci_dev_cnt++]; - - pm->pci_bus = bus; - pm->pci_devfn = devfn; - - for (i=0; i<6; i++) { - qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); - qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), - &pciaddr); - pm->pci_addrs[i] = pciaddr; - qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); - pm->pci_command = pcicmd; - } -} - -/* Map the cards into the PCI space. The PCI has separate memory - * and I/O spaces. In addition, some memory devices require mapping - * below 1M. The least significant 4 bits of the address register - * provide information. If this is an I/O device, only the LS bit - * is used to indicate that, so I/O devices can be mapped to a two byte - * boundard. Memory addresses can be mapped to a 32 byte boundary. - * The QSpan implementations usually have a 1Gbyte space for each - * memory and I/O spaces. - * - * This isn't a terribly fancy algorithm. I just map the spaces from - * the top starting with the largest address space. When finished, - * the registers are written and the card enabled. - * - * While the Tundra can map a large address space on most boards, we - * need to be careful because it may overlap other devices (like IMMR). - */ -#define MEMORY_SPACE_SIZE 0x20000000 -#define IO_SPACE_SIZE 0x20000000 - -void -map_pci_addrs() -{ - uint pci_mem_top, pci_mem_low; - uint pci_io_top; - uint addr_mask, reg_addr, space; - int i, j; - pci_map_t *pm; - - pci_mem_top = MEMORY_SPACE_SIZE; - pci_io_top = IO_SPACE_SIZE; - pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ - - /* We can't map anything more than the maximum space, but test - * for it anyway to catch devices out of range. - */ - addr_mask = 0x80000000; - - do { - space = (~addr_mask) + 1; /* Size of the space */ - for (i=0; ipci_addrs[j]; - if ((reg_addr & 0x80000000) == 0) - continue; - if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { - if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) - continue; - if (pci_io_top < space) { - puts("Out of PCI I/O space\n"); - } - else { - pci_io_top -= space; - pm->pci_addrs[j] = pci_io_top; - pm->pci_command |= PCI_COMMAND_IO; - } - } - else { - if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) - continue; - - /* Memory space. Test if below 1M. - */ - if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { - if (pci_mem_low < space) { - puts("Out of PCI 1M space\n"); - } - else { - pci_mem_low -= space; - pm->pci_addrs[j] = pci_mem_low; - } - } - else { - if (pci_mem_top < space) { - puts("Out of PCI Mem space\n"); - } - else { - pci_mem_top -= space; - pm->pci_addrs[j] = pci_mem_top; - } - } - pm->pci_command |= PCI_COMMAND_MEMORY; - } - } - } - addr_mask >>= 1; - addr_mask |= 0x80000000; - } while (addr_mask != 0xfffffffe); - - /* Now, run the list one more time and map everything. - */ - for (i=0; ipci_bus, pm->pci_devfn, - PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); - } - - /* Enable memory or address mapping. - */ - qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, - pm->pci_command); - } -} - diff -urN linux-2.4.18/arch/ppc/boot/mbx/qspan_pci.c linux-2.4.19-pre5/arch/ppc/boot/mbx/qspan_pci.c --- linux-2.4.18/arch/ppc/boot/mbx/qspan_pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/qspan_pci.c Thu Jan 1 01:00:00 1970 @@ -1,271 +0,0 @@ -/* - * BK Id: SCCS/s.qspan_pci.c 1.6 05/18/01 15:17:06 cort - */ -/* - * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) - * - * QSpan Motorola bus to PCI bridge. The config address register - * is located 0x500 from the base of the bridge control/status registers. - * The data register is located at 0x504. - * This is a two step operation. First, the address register is written, - * then the data register is read/written as required. - * I don't know what to do about interrupts (yet). - */ - -#include -#include -#include -#include - -/* - * When reading the configuration space, if something does not respond - * the bus times out and we get a machine check interrupt. So, the - * good ol' exception tables come to mind to trap it and return some - * value. - * - * On an error we just return a -1, since that is what the caller wants - * returned if nothing is present. I copied this from __get_user_asm, - * with the only difference of returning -1 instead of EFAULT. - * There is an associated hack in the machine check trap code. - * - * The QSPAN is also a big endian device, that is it makes the PCI - * look big endian to us. This presents a problem for the Linux PCI - * functions, which assume little endian. For example, we see the - * first 32-bit word like this: - * ------------------------ - * | Device ID | Vendor ID | - * ------------------------ - * If we read/write as a double word, that's OK. But in our world, - * when read as a word, device ID is at location 0, not location 2 as - * the little endian PCI would believe. We have to switch bits in - * the PCI addresses given to us to get the data to/from the correct - * byte lanes. - * - * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. - * It always forces the MS bit to zero. Therefore, dev_fn values - * greater than 128 are returned as "no device found" errors. - * - * The QSPAN can only perform long word (32-bit) configuration cycles. - * The "offset" must have the two LS bits set to zero. Read operations - * require we read the entire word and then sort out what should be - * returned. Write operations other than long word require that we - * read the long word, update the proper word or byte, then write the - * entire long word back. - * - * PCI Bridge hack. We assume (correctly) that bus 0 is the primary - * PCI bus from the QSPAN. If we are called with a bus number other - * than zero, we create a Type 1 configuration access that a downstream - * PCI bridge will interpret. - */ - -#define __get_pci_config(x, addr, op) \ - __asm__ __volatile__( \ - "1: "op" %0,0(%1)\n" \ - " eieio\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: li %0,-1\n" \ - " b 2b\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".text" \ - : "=r"(x) : "r"(addr)) - -#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) -#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) - -#define mk_config_addr(bus, dev, offset) \ - (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) - -#define mk_config_type1(bus, dev, offset) \ - mk_config_addr(bus, dev, offset) | 1; - -/* Initialize the QSpan device registers after power up. -*/ -qspan_init() -{ - uint *qptr; - - - - qptr = (uint *)PCI_CSR_ADDR; - - /* PCI Configuration/status. Upper bits written to clear - * pending interrupt or status. Lower bits enable QSPAN as - * PCI master, enable memory and I/O cycles, and enable PCI - * parity error checking. - * IMPORTANT: The last two bits of this word enable PCI - * master cycles into the QBus. The QSpan is broken and can't - * meet the timing specs of the PQ bus for this to work. Therefore, - * if you don't have external bus arbitration, you can't use - * this function. - */ -#ifdef EXTERNAL_PQ_ARB - qptr[1] = 0xf9000147; -#else - qptr[1] = 0xf9000144; -#endif - - /* PCI Misc configuration. Set PCI latency timer resolution - * of 8 cycles, set cache size to 4 x 32. - */ - qptr[3] = 0; - - /* Set up PCI Target address mapping. Enable, Posted writes, - * 2Gbyte space (processor memory controller determines actual size). - */ - qptr[64] = 0x8f000080; - - /* Map processor 0x80000000 to PCI 0x00000000. - * Processor address bit 1 determines I/O type access (0x80000000) - * or memory type access (0xc0000000). - */ - qptr[65] = 0x80000000; - - /* Enable error logging and clear any pending error status. - */ - qptr[80] = 0x90000000; - - qptr[512] = 0x000c0003; - - /* Set up Qbus slave image. - */ - qptr[960] = 0x01000000; - qptr[961] = 0x000000d1; - qptr[964] = 0x00000000; - qptr[965] = 0x000000d1; - -} - -/* Functions to support PCI bios-like features to read/write configuration - * space. If the function fails for any reason, a -1 (0xffffffff) value - * must be returned. - */ -#define DEVICE_NOT_FOUND (-1) -#define SUCCESSFUL 0 - -int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *val = *cp; - return SUCCESSFUL; -} - -int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffff; - return DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); - offset ^= 0x02; - - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *val = *sp; - return SUCCESSFUL; -} - -int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) -{ - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffffffff; - return DEVICE_NOT_FOUND; - } - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); - return SUCCESSFUL; -} - -int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *cp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - qs_pci_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x02; - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *sp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return SUCCESSFUL; -} - -int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) -{ - if ((bus > 7) || (dev_fn > 127)) - return DEVICE_NOT_FOUND; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *(unsigned int *)QS_CONFIG_DATA = val; - - return SUCCESSFUL; -} - diff -urN linux-2.4.18/arch/ppc/boot/mbx/rdimage.c linux-2.4.19-pre5/arch/ppc/boot/mbx/rdimage.c --- linux-2.4.18/arch/ppc/boot/mbx/rdimage.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/mbx/rdimage.c Thu Jan 1 01:00:00 1970 @@ -1,11 +0,0 @@ -/* - * BK Id: SCCS/s.rdimage.c 1.6 05/18/01 15:17:06 cort - */ -/* - * rdimage.c - * - * Dummy file to allow a compressed initrd to be added - * into a linker section, accessed by the boot coode - */ - -char dummy_for_rdimage; diff -urN linux-2.4.18/arch/ppc/boot/pmac/Makefile linux-2.4.19-pre5/arch/ppc/boot/pmac/Makefile --- linux-2.4.18/arch/ppc/boot/pmac/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/pmac/Makefile Sat Mar 30 22:55:27 2002 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.16 09/28/01 07:39:37 trini +# BK Id: SCCS/s.Makefile 1.19 01/16/02 11:08:07 trini # # Makefile for making XCOFF bootable images for booting on PowerMacs # using Open Firmware. @@ -9,10 +9,10 @@ # Tom Rini January 2001 OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x01000000 +COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic +CHRP_LD_ARGS = -T ../ld.script -Ttext 0x01000000 -COMMONOBJS = start.o misc.o ../common/string.o image.o ../common/ofcommon.o +COMMONOBJS = start.o misc.o ../common/string.o ../common/ofcommon.o COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a @@ -20,29 +20,31 @@ MKNOTE := ../utils/mknote SIZE := ../utils/size OFFSET := ../utils/offset -PIGGYBACK := ../utils/piggyback HACKCOFF := ../utils/hack-coff -ifeq ($(CONFIG_PPC64BRIDGE),y) -MSIZE=.64 -else -MSIZE= +ifdef CONFIG_SMP +END := .smp endif - -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) -else -TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) +ifdef CONFIG_PPC64BRIDGE +END += .64 endif -../common/crt0.o: - $(MAKE) -C ../common crt0.o +TFTPIMAGE=/tftpboot/zImage.pmac$(END) + +AFLAGS_../common/crt0.o += -I$(TOPDIR)/arch/$(ARCH)/kernel ../common/coffcrt0.o: $(MAKE) -C ../common coffcrt0.o -chrpmain.o: chrpmain.c - $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c +image.o: ../images/vmlinux.gz ../common/dummy.o + $(OBJCOPY) ../common/dummy.o $@ -R .comment \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data +ifdef CONFIG_XMON + $(OBJCOPY) $@ $@ \ + --add-section=.sysmap=$(TOPDIR)/System.map \ + --set-section-flags=.sysmap=contents,alloc,load,readonly,data +endif znetboot: vmlinux.coff vmlinux.elf-pmac zImage cp ../images/vmlinux.coff $(TFTPIMAGE) @@ -52,30 +54,26 @@ cp ../images/vmlinux.initrd.coff $(TFTPIMAGE) cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).elf -#floppy: zImage -# mount -t hfs /dev/fd0 /mnt -# cp vmlinux.coff /mnt -# umount /mnt - -miboot.image: dummy.o ../images/vmlinux.gz +miboot.image: ../common/dummy.o ../images/vmlinux.gz $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ - dummy.o ../images/$@ + ../common/dummy.o ../images/$@ miboot.initrd.image: miboot.image ../images/ramdisk.image.gz $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \ ../images/miboot.image ../images/$@ -coffboot: $(COFFOBJS) $(LIBS) ../common/no_initrd.o ld.script ../images/vmlinux.gz - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) ../common/no_initrd.o $(LIBS) - -coffboot.initrd: $(COFFOBJS) $(LIBS) initrd.o ld.script ../images/vmlinux.gz - $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) - -image.o: $(PIGGYBACK) ../images/vmlinux.gz - $(PIGGYBACK) image < ../images/vmlinux.gz | $(AS) -o $@ - -initrd.o: ../images/ramdisk.image.gz $(PIGGYBACK) - $(PIGGYBACK) initrd < ../images/ramdisk.image.gz | $(AS) -o $@ +coffboot: $(COFFOBJS) image.o $(LIBS) ../ld.script + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image.o $(LIBS) + $(OBJCOPY) $@ $@ -R .comment + +coffboot.initrd: $(COFFOBJS) image.o $(LIBS) ../ld.script \ + ../images/ramdisk.image.gz + $(OBJCOPY) image.o image-coff.o \ + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image-coff.o $(LIBS) + $(OBJCOPY) $@ $@ -R .comment + rm -f image-coff.o vmlinux.coff: coffboot $(HACKCOFF) $(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@ @@ -89,24 +87,23 @@ rm -f coffboot.initrd ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac -vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) ../common/no_initrd.o $(MKNOTE) ../images/vmlinux.gz - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) +vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image.o $(MKNOTE) > note $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ - --add-section=sysmap=$(TOPDIR)/System.map -R .comment - $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ - -DSYSMAP_OFFSET=`sh $(OFFSET) $(OBJDUMP) ../images/$@ sysmap` \ - -DSYSMAP_SIZE=`sh $(SIZE) $(OBJDUMP) ../images/$@ sysmap` - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) - $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ - --add-section=sysmap=$(TOPDIR)/System.map -R .comment + -R .comment -R .ramdisk rm -f note -vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) initrd.o $(MKNOTE) ../images/vmlinux.gz - $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) initrd.o $(LIBS) +vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o \ + ../images/ramdisk.image.gz + $(OBJCOPY) image.o image-elf.o \ + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data + $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image-elf.o $(MKNOTE) > note - $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note -R .comment - rm -f note + $(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \ + -R .comment + rm -f note image-elf.o zImage: vmlinux.coff vmlinux.elf-pmac miboot.image diff -urN linux-2.4.18/arch/ppc/boot/pmac/chrpmain.c linux-2.4.19-pre5/arch/ppc/boot/pmac/chrpmain.c --- linux-2.4.18/arch/ppc/boot/pmac/chrpmain.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/pmac/chrpmain.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrpmain.c 1.16 07/27/01 20:24:18 trini + * BK Id: SCCS/s.chrpmain.c 1.18 01/11/02 10:46:07 trini */ /* * Copyright (C) Paul Mackerras 1997. @@ -10,15 +10,17 @@ * 2 of the License, or (at your option) any later version. */ #include "nonstdio.h" -#include "zlib.h" #include +#include + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; -extern char _end[]; -extern char image_data[], initrd_data[]; -extern int image_len, initrd_len; extern int getprop(void *, const char *, void *, int); extern unsigned int heap_max; -extern void *claim(unsigned int, unsigned int, unsigned int); +extern void *claim(unsigned int virt, unsigned int size, unsigned int align); extern void *finddevice(const char *); extern void flush_cache(void *start, unsigned int len); extern void gunzip(void *, int, unsigned char *, int *); @@ -45,21 +47,23 @@ void *dst; unsigned char *im; unsigned initrd_start, initrd_size; - extern char _start; printf("chrpboot starting: loaded at 0x%p\n", &_start); - if (initrd_len) { - initrd_size = initrd_len; + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { initrd_start = (RAM_END - initrd_size) & ~0xFFF; a1 = initrd_start; a2 = initrd_size; claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n", initrd_start, - initrd_data,initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); /* claim 3MB starting at PROG_START */ claim(PROG_START, PROG_SIZE, 0); dst = (void *) PROG_START; diff -urN linux-2.4.18/arch/ppc/boot/pmac/coffmain.c linux-2.4.19-pre5/arch/ppc/boot/pmac/coffmain.c --- linux-2.4.18/arch/ppc/boot/pmac/coffmain.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/pmac/coffmain.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.coffmain.c 1.14 07/27/01 20:24:18 trini + * BK Id: SCCS/s.coffmain.c 1.15 01/11/02 10:46:07 trini */ /* * Copyright (C) Paul Mackerras 1997. @@ -9,11 +9,17 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include +#include + #include "nonstdio.h" #include "zlib.h" -#include -extern char _start[], _end[]; +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; + extern char *claim(unsigned, unsigned, unsigned); extern char image_data[], initrd_data[]; extern int initrd_len, image_len; @@ -50,18 +56,21 @@ printf("coffboot starting: loaded at 0x%p\n", &_start); setup_bats(RAM_START); - if (initrd_len) { - initrd_size = initrd_len; + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { initrd_start = (RAM_END - initrd_size) & ~0xFFF; a1 = initrd_start; a2 = initrd_size; - claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n", - initrd_start, initrd_data, initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - } - im = image_data; - len = image_len; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); /* claim 4MB starting at 0 */ claim(0, PROG_SIZE, 0); dst = (void *) RAM_START; diff -urN linux-2.4.18/arch/ppc/boot/pmac/dummy.c linux-2.4.19-pre5/arch/ppc/boot/pmac/dummy.c --- linux-2.4.18/arch/ppc/boot/pmac/dummy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/pmac/dummy.c Thu Jan 1 01:00:00 1970 @@ -1,7 +0,0 @@ -/* - * BK Id: SCCS/s.dummy.c 1.6 05/18/01 15:17:15 cort - */ -int main(void) -{ - return 0; -} diff -urN linux-2.4.18/arch/ppc/boot/pmac/ld.script linux-2.4.19-pre5/arch/ppc/boot/pmac/ld.script --- linux-2.4.18/arch/ppc/boot/pmac/ld.script Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/pmac/ld.script Thu Jan 1 01:00:00 1970 @@ -1,69 +0,0 @@ -OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0 - .plt : { *(.plt) } - .text : - { - *(.text) - *(.rodata) - *(.rodata.*) - *(.rodata1) - *(.got1) - } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - _etext = .; - PROVIDE (etext = .); - /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); -} - diff -urN linux-2.4.18/arch/ppc/boot/prep/Makefile linux-2.4.19-pre5/arch/ppc/boot/prep/Makefile --- linux-2.4.18/arch/ppc/boot/prep/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/prep/Makefile Sat Mar 30 22:55:27 2002 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.28 10/21/01 20:47:58 trini +# BK Id: SCCS/s.Makefile 1.30 01/26/02 12:27:41 trini # # arch/ppc/boot/Makefile # @@ -17,16 +17,15 @@ USE_STANDARD_AS_RULE := true -ifeq ($(CONFIG_SMP),y) -TFTPIMAGE = /tftpboot/zImage.prep.smp -else TFTPIMAGE = /tftpboot/zImage.prep +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE = $(TFTPBOOT).smp endif -ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds \ - -Ttext 0x00800000 -obj-y := head.o misc.o ../common/misc-common.o \ - ../common/string.o of1275.o +LD_ARGS = -T ../ld.script -Ttext 0x00800000 -Bstatic +obj-y := head.o ../simple/legacy.o misc.o of1275.o \ + ../common/util.o ../common/string.o \ + ../common/misc-common.o OBJCOPY_ARGS = -O elf32-powerpc LIBS = ../lib/zlib.a @@ -38,69 +37,38 @@ SIZE := ../utils/size OFFSET := ../utils/offset -all: zImage +# Extra include search dirs +CFLAGS_kbd.o += -I$(TOPDIR)/drivers/char +AFLAGS_head.o += -I$(TOPDIR)/arch/$(ARCH)/kernel +AFLAGS_../common/util.o += -I$(TOPDIR)/arch/$(ARCH)/kernel +AFLAGS_../common/relocate.o += -I$(TOPDIR)/arch/$(ARCH)/kernel +AFLAGS_../simple/legacy.o += -I$(TOPDIR)/arch/$(ARCH)/kernel -misc.o: misc.c - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \ - -DZIMAGE_SIZE=0 -c -o $@ $*.c +all: zImage -zvmlinux.initrd: $(obj-y) $(LIBS) ../images/vmlinux.gz -# -# Recompile misc.oagain with more 'correct' bogus offsets -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0x00138466 -DINITRD_SIZE=0x0000111a \ - -DZIMAGE_OFFSET=0x0001b000 -DZIMAGE_SIZE=0x0011d460 \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=../images/ramdisk.image.gz \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp $@ - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ initrd` \ - -DINITRD_SIZE=`sh $(SIZE) $(OBJDUMP) $@ initrd` \ - -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ - -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS) +zImage: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o \ + $(MKPREP) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=../images/ramdisk.image.gz \ - --add-section=image=../images/vmlinux.gz \ - $@.tmp $@ - rm -f $@.tmp - -zImage: zvmlinux $(MKPREP) - $(MKPREP) -pbp zvmlinux ../images/$@.prep - rm -f zvmlinux - -zImage.initrd: zvmlinux.initrd $(MKPREP) - $(MKPREP) -pbp zvmlinux.initrd ../images/$@.prep - rm -f zvmlinux.initrd + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + ../common/dummy.o image.o + $(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr + $(MKPREP) -pbp $@ ../images/$@.prep + rm -f $@ -zvmlinux: $(obj-y) $(LIBS) ../images/vmlinux.gz -# -# Recompile misc.oagain with more 'correct' bogus offsets -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=0x0001b000 -DZIMAGE_SIZE=0x0011d460 \ - -c -o misc.o misc.c -# -# build the boot loader image and then compute the offset into it -# for the kernel image -# - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(obj-y) $(LIBS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=image=../images/vmlinux.gz zvmlinux.tmp $@ -# -# then with the offset rebuild the bootloader so we know where the kernel is -# - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) zvmlinux image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(obj-y) $(LIBS) +zImage.initrd: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz $(MKPREP) \ + ../common/dummy.o $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=image=../images/vmlinux.gz $@.tmp $@ - rm -f $@.tmp + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + ../common/dummy.o image.o + $(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr + $(MKPREP) -pbp $@ ../images/$@.prep + rm -f $@ floppy: zImage dd if=../images/zImage.prep of=/dev/fd0H1440 bs=64b diff -urN linux-2.4.18/arch/ppc/boot/prep/head.S linux-2.4.19-pre5/arch/ppc/boot/prep/head.S --- linux-2.4.18/arch/ppc/boot/prep/head.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/prep/head.S Sat Mar 30 22:55:27 2002 @@ -1,8 +1,8 @@ /* - * BK Id: SCCS/s.head.S 1.11 07/31/01 16:36:06 trini + * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini */ -#include "../../kernel/ppc_defs.h" -#include "../../kernel/ppc_asm.tmpl" + +#include "ppc_asm.h" #include #include @@ -22,34 +22,49 @@ start: bl start_ start_: + + /* Enable, invalidate, Disable L1 icache/dcache */ + li r8, 0 + ori r8, r8, (HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI) + mfspr r11,HID0 + or r11,r11,r8 + andc r10,r11,r8 + isync + mtspr HID0,r8 + sync + isync + mtspr HID0,r10 + sync + isync + mr r11,r3 /* Save pointer to residual/board data */ - mr r25,r5 /* Save OFW pointer */ - li r3,MSR_IP /* Establish default MSR value */ + mr r25,r5 /* Save OFW pointer */ + + /* Save the original MSR value */ + mfmsr r26 + + /* Establish default MSR value */ + li r3,MSR_IP|MSR_FP mtmsr r3 -/* check if we need to relocate ourselves to the link addr or were we - loaded there to begin with -- Cort */ - lis r4,start@h - ori r4,r4,start@l - mflr r3 - subi r3,r3,4 /* we get the nip, not the ip of the branch */ - mr r8,r3 - cmp 0,r3,r4 - bne 1010f -/* compute size of whole image in words. this should be moved to - * start_ldr() -- Cort - */ + /* compute the size of the whole image in words. */ lis r4,start@h ori r4,r4,start@l lis r5,end@h ori r5,r5,end@l addi r5,r5,3 /* round up */ - sub r5,r5,r4 + sub r5,r5,r4 /* end - start */ srwi r5,r5,2 - mr r7,r5 - b start_ldr -1010: -/* + mr r7,r5 /* Save for later use. */ + + /* check if we need to relocate ourselves to the link addr or were + * we loaded there to begin with -- Cort */ + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 + cmp 0,r3,r4 + beq start_ldr /* If 0, we don't need to relocate */ +/* * no matter where we're loaded, move ourselves to -Ttext address */ relocate: @@ -58,15 +73,10 @@ mr r8,r3 lis r4,start@h ori r4,r4,start@l - lis r5,end@h - ori r5,r5,end@l - addi r5,r5,3 /* Round up - just in case */ - sub r5,r5,r4 /* Compute # longwords to move */ - srwi r5,r5,2 - mtctr r5 - mr r7,r5 + mr r5,r7 /* Get the # of longwords again */ + mtctr r5 /* Setup for loop */ li r6,0 - subi r3,r3,4 /* Set up for loop */ + subi r3,r3,4 subi r4,r4,4 00: lwzu r5,4(r3) stwu r5,4(r4) @@ -74,9 +84,17 @@ bdnz 00b lis r3,start_ldr@h ori r3,r3,start_ldr@l - mtlr r3 /* Easiest way to do an absolute jump */ + mtlr r3 /* Easiest way to do an absolute jump */ blr + start_ldr: +/* Some boards don't boot up with the I-cache enabled. Do that + * now because the decompress runs much faster that way. + * As a side effect, we have to ensure the data cache is not enabled + * so we can access the serial I/O without trouble. + */ + bl flush_instruction_cache + /* Clear all of BSS */ lis r3,edata@h ori r3,r3,edata@l @@ -95,11 +113,12 @@ subi r1,r1,256 li r2,0x000F /* Mask pointer to 16-byte boundary */ andc r1,r1,r2 -/* Setup ISA_io */ - lis r3,ISA_io@h - ori r3,r3,ISA_io@l - lis r4,0x8000 - stw r4,0(r3) + + /* Store the original MSR into 'orig_MSR' */ + lis r3,orig_MSR@h + ori r3,r3,orig_MSR@l + stw r26,0(r3) + /* Run loader */ mr r3,r8 /* Load point */ mr r4,r7 /* Program length */ @@ -107,147 +126,61 @@ mr r6,r11 /* Residual data */ mr r7,r25 /* OFW interfaces */ bl decompress_kernel - - /* changed to use r3 (as firmware does) for kernel - as ptr to residual -- Cort*/ - lis r6,cmd_line@h - ori r6,r6,cmd_line@l - lwz r6, 0(r6) - subi r7,r6,1 -00: lbzu r2,1(r7) - cmpi 0,r2,0 - bne 00b - - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - - - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort + + /* + * We have to do this after decompress_kernel, just to make + * sure we don't wipe out things mapped in BATs which we need. + * -- Tom */ - li r9,0x4 + li r6,0 + /* Test for a 601 */ + mfspr r9,PVR + srwi r9,r9,16 + cmpi 0,r9,1 /* 601 ? */ + beq .clearbats_601 + + /* Clear BATS */ + mtspr DBAT0U,r6 + mtspr DBAT0L,r6 + mtspr DBAT1U,r6 + mtspr DBAT1L,r6 + mtspr DBAT2U,r6 + mtspr DBAT2L,r6 + mtspr DBAT3U,r6 + mtspr DBAT3L,r6 +.clearbats_601: + mtspr IBAT0U,r6 + mtspr IBAT0L,r6 + mtspr IBAT1U,r6 + mtspr IBAT1L,r6 + mtspr IBAT2U,r6 + mtspr IBAT2L,r6 + mtspr IBAT3U,r6 + mtspr IBAT3L,r6 + isync + sync + sync + + /* Set segment registers */ + li r6,16 /* load up segment register values */ + mtctr r6 /* for context 0 */ + lis r6,0x2000 /* Ku = 1, VSID = 0 */ + li r10,0 +3: mtsrin r6,r10 + addi r6,r6,0x111 /* increment VSID */ + addis r10,r10,0x1000 /* address of next segment */ + bdnz 3b + + /* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD, + * and tell the kernel to start on the 4th instruction since we + * overwrite the first 3 sometimes (which are 'nop'). + */ + li r9,0xc mtlr r9 lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l li r9,0 stw r10,0(r9) -/* - * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 - * so disable BATs before setting this to avoid a clash - */ - li r8,0 - mtspr DBAT0U,r8 - mtspr DBAT1U,r8 - mtspr DBAT2U,r8 - mtspr DBAT3U,r8 - mtspr IBAT0U,r8 - mtspr IBAT1U,r8 - mtspr IBAT2U,r8 - mtspr IBAT3U,r8 - - blr -hang: - b hang - -/* - * Delay for a number of microseconds - * -- Use the BUS timer (assumes 66MHz) - */ - .globl udelay -udelay: - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 -00: li r0,86 /* Instructions / microsecond? */ - mtctr r0 -10: addi r0,r0,0 /* NOP */ - bdnz 10b - subic. r3,r3,1 - bne 00b - blr - -.udelay_not_601: - mulli r4,r3,1000 /* nanoseconds */ - addi r4,r4,59 - li r5,60 - divw r4,r4,r5 /* BUS ticks */ -1: mftbu r5 - mftb r6 - mftbu r7 - cmp 0,r5,r7 - bne 1b /* Get [synced] base time */ - addc r9,r6,r4 /* Compute end time */ - addze r8,r5 -2: mftbu r5 - cmp 0,r5,r8 - blt 2b - bgt 3f - mftb r6 - cmp 0,r6,r9 - blt 2b -3: blr - -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - -.globl _get_MSR -_get_MSR: - mfmsr r3 - blr - -.globl _put_MSR -_put_MSR: - mtmsr r3 blr -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mfspr r3,HID0 /* Caches are controlled by this register */ - li r4,0 - ori r4,r4,(HID0_ICE|HID0_ICFI) - or r3,r3,r4 /* Need to enable+invalidate to clear */ - mtspr HID0,r3 - andc r3,r3,r4 - ori r3,r3,HID0_ICE /* Enable cache */ - mtspr HID0,r3 - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr .comm .stack,4096*2,4 diff -urN linux-2.4.18/arch/ppc/boot/prep/kbd.c linux-2.4.19-pre5/arch/ppc/boot/prep/kbd.c --- linux-2.4.18/arch/ppc/boot/prep/kbd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/prep/kbd.c Sat Mar 30 22:55:27 2002 @@ -1,9 +1,10 @@ /* - * BK Id: SCCS/s.kbd.c 1.7 05/18/01 06:20:29 patch + * BK Id: SCCS/s.kbd.c 1.9 01/11/02 10:46:07 trini */ + #include -#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ +#include "defkeymap.c" /* yeah I know it's bad -- Cort */ unsigned char shfts, ctls, alts, caps; @@ -130,20 +131,29 @@ goto loop; } -static void kbdreset(void) +static int __kbdreset(void) { unsigned char c; - int i; + int i, t; /* flush input queue */ + t = 2000; while ((inb(KBSTATP) & KBINRDY)) { (void)inb(KBDATAP); + if (--t == 0) + return 1; } /* Send self-test */ - while (inb(KBSTATP) & KBOUTRDY) ; + t = 20000; + while (inb(KBSTATP) & KBOUTRDY) + if (--t == 0) + return 2; outb(KBSTATP,0xAA); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + t = 200000; + while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */ + if (--t == 0) + return 3; if ((c = inb(KBDATAP)) != 0x55) { puts("Keyboard self test failed - result:"); @@ -151,15 +161,23 @@ puts("\n"); } /* Enable interrupts and keyboard controller */ - while (inb(KBSTATP) & KBOUTRDY) ; - outb(KBSTATP,0x60); - while (inb(KBSTATP) & KBOUTRDY) ; + t = 20000; + while (inb(KBSTATP) & KBOUTRDY) + if (--t == 0) return 4; + outb(KBSTATP,0x60); + t = 20000; + while (inb(KBSTATP) & KBOUTRDY) + if (--t == 0) return 5; outb(KBDATAP,0x45); for (i = 0; i < 10000; i++) udelay(1); - - while (inb(KBSTATP) & KBOUTRDY) ; + + t = 20000; + while (inb(KBSTATP) & KBOUTRDY) + if (--t == 0) return 6; outb(KBSTATP,0x20); - while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + t = 200000; + while ((inb(KBSTATP) & KBINRDY) == 0) /* wait input ready */ + if (--t == 0) return 7; if (! (inb(KBDATAP) & 0x40)) { /* * Quote from PS/2 System Reference Manual: @@ -169,15 +187,31 @@ * output-buffer-full bit in the Controller Status * register are set 0." (KBINRDY and KBOUTRDY) */ - - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + t = 200000; + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) + if (--t == 0) return 8; outb(KBDATAP,0xF0); - while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + t = 200000; + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) + if (--t == 0) return 9; outb(KBDATAP,0x01); } - - while (inb(KBSTATP) & KBOUTRDY) ; + t = 20000; + while (inb(KBSTATP) & KBOUTRDY) + if (--t == 0) return 10; outb(KBSTATP,0xAE); + return 0; +} + +static void kbdreset(void) +{ + int ret = __kbdreset(); + + if (ret) { + puts("__kbdreset failed: "); + puthex(ret); + puts("\n"); + } } /* We have to actually read the keyboard when CRT_tstc is called, diff -urN linux-2.4.18/arch/ppc/boot/prep/misc.c linux-2.4.19-pre5/arch/ppc/boot/prep/misc.c --- linux-2.4.18/arch/ppc/boot/prep/misc.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/prep/misc.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.22 10/15/01 17:46:21 trini + * BK Id: SCCS/s.misc.c 1.25 01/26/02 12:27:41 trini * * arch/ppc/boot/prep/misc.c * @@ -32,12 +32,16 @@ */ char *avail_ram; char *end_avail; + +/* The linker tells us where the image is. */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; extern char _end[]; #ifdef CONFIG_CMDLINE #define CMDLINE CONFIG_CMDLINE #else -#define CMDLINE ""; +#define CMDLINE "" #endif char cmd_preset[] = CMDLINE; char cmd_buf[256]; @@ -46,7 +50,8 @@ int keyb_present = 1; /* keyboard controller is present by default */ RESIDUAL hold_resid_buf; RESIDUAL *hold_residual = &hold_resid_buf; -unsigned long initrd_start = 0, initrd_end = 0; +unsigned long initrd_size = 0; +unsigned long orig_MSR; char *zimage_start; int zimage_size; @@ -63,16 +68,14 @@ extern int CRT_tstc(void); extern void of_init(void *handler); extern int of_finddevice(const char *device_specifier, int *phandle); -extern int of_getprop(int phandle, const char *name, void *buf, int buflen, +extern int of_getprop(int phandle, const char *name, void *buf, int buflen, int *size); extern int vga_init(unsigned char *ISA_mem); extern void gunzip(void *, int, unsigned char *, int *); -extern void _put_HID0(unsigned int val); extern void _put_MSR(unsigned int val); -extern unsigned int _get_HID0(void); -extern unsigned int _get_MSR(void); -extern unsigned long serial_init(int chan); +extern unsigned long serial_init(int chan, void *ignored); +extern void serial_fixups(void); void writel(unsigned int val, unsigned int address) @@ -82,7 +85,7 @@ *(unsigned int *)address = cpu_to_le32(val); } -unsigned int +unsigned int readl(unsigned int address) { /* Ensure I/O operations complete */ @@ -90,8 +93,8 @@ return le32_to_cpu(*(unsigned int *)address); } -#define PCI_CFG_ADDR(dev,off) ((0x80<<24) | (dev<<8) | (off&0xfc)) -#define PCI_CFG_DATA(off) (0x80000cfc+(off&3)) +#define PCI_CFG_ADDR(dev,off) ((0x80<<24) | (dev<<8) | (off&0xfc)) +#define PCI_CFG_DATA(off) (0x80000cfc+(off&3)) static void pci_read_config_32(unsigned char devfn, @@ -115,38 +118,14 @@ } #endif /* CONFIG_VGA_CONSOLE */ -/* - * This routine is used to control the second processor on the - * Motorola dual processor platforms. - */ -void -park_cpus(void) -{ - volatile void (*go)(RESIDUAL *, int, int, char *, int); - unsigned int i; - volatile unsigned long *smp_iar = &(hold_residual->VitalProductData.SmpIar); - - /* Wait for indication to continue. If the kernel - was not compiled with SMP support then the second - processor will spin forever here makeing the kernel - multiprocessor safe. */ - while (*smp_iar == 0) { - for (i=0; i < 512; i++); - } - - (unsigned long)go = hold_residual->VitalProductData.SmpIar; - go(hold_residual, 0, 0, cmd_line, sizeof(cmd_preset)); -} - unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual, void *OFW_interface) { - int timer; + int timer = 0; extern unsigned long start; char *cp, ch; unsigned long TotalMemory; - unsigned long orig_MSR; int dev_handle; int mem_info[2]; int res, size; @@ -154,26 +133,42 @@ unsigned char base_mod; int start_multi = 0; unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base; - - /* - * IBM's have the MMU on, so we have to disable it or - * things get really unhappy in the kernel when - * trying to setup the BATs with the MMU on - * -- Cort - */ - flush_instruction_cache(); - _put_HID0(_get_HID0() & ~0x0000C000); - _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); + serial_fixups(); #if defined(CONFIG_SERIAL_CONSOLE) - com_port = serial_init(0); + com_port = serial_init(0, NULL); #endif /* CONFIG_SERIAL_CONSOLE */ #if defined(CONFIG_VGA_CONSOLE) vga_init((unsigned char *)0xC0000000); #endif /* CONFIG_VGA_CONSOLE */ - if (residual) - { + /* + * Tell the user where we were loaded at and where we were relocated + * to for debugging this process. + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if (residual) { + /* + * Tell the user where the residual data is. + */ + puts("board data at: "); puthex((unsigned long)residual); + puts(" "); + puthex((unsigned long)((unsigned long)residual + + sizeof(RESIDUAL))); + puts("\nrelocated to: ");puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + + sizeof(RESIDUAL))); + puts("\n"); + /* Is this Motorola PPCBug? */ if ((1 & residual->VitalProductData.FirmwareSupports) && (1 == residual->VitalProductData.FirmwareSupplier)) { @@ -190,8 +185,7 @@ ((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) || (pci_did == PCI_DEVICE_ID_DEC_TULIP) || (pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) || - (pci_did == PCI_DEVICE_ID_DEC_21142))) - { + (pci_did == PCI_DEVICE_ID_DEC_21142))) { pci_read_config_32(0x70, 0x10, &tulip_pci_base); @@ -205,7 +199,7 @@ /* If this is genesis 2 board then check for no * keyboard controller and more than one processor. */ - if (board_type == 0xe0) { + if (board_type == 0xe0) { base_mod = inb(0x803); /* if a MVME2300/2400 or a Sitka then no keyboard */ if((base_mod == 0xFA) || (base_mod == 0xF9) || @@ -217,14 +211,17 @@ * park the other processor so that the * kernel knows where to find them. */ - if (residual->MaxNumCpus > 1) { + if (residual->MaxNumCpus > 1) start_multi = 1; - } } memcpy(hold_residual,residual,sizeof(RESIDUAL)); } else { + /* Tell the user we didn't find anything. */ + puts("No residual data found.\n"); + /* Assume 32M in the absence of more info... */ TotalMemory = 0x02000000; + /* * This is a 'best guess' check. We want to make sure * we don't try this on a PReP box without OF @@ -232,116 +229,66 @@ */ while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) { - /* The MMU needs to be on when we call OFW */ + /* We need to restore the slightly inaccurate + * MSR so that OpenFirmware will behave. -- Tom + */ _put_MSR(orig_MSR); of_init(OFW_interface); /* get handle to memory description */ - res = of_finddevice("/memory@0", + res = of_finddevice("/memory@0", &dev_handle); - // puthex(res); puts("\n"); - if (res) break; - + if (res) + break; + /* get the info */ - // puts("get info = "); - res = of_getprop(dev_handle, - "reg", - mem_info, - sizeof(mem_info), + res = of_getprop(dev_handle, + "reg", + mem_info, + sizeof(mem_info), &size); - // puthex(res); puts(", info = "); puthex(mem_info[0]); - // puts(" "); puthex(mem_info[1]); puts("\n"); - if (res) break; - + if (res) + break; + TotalMemory = mem_info[1]; break; } + hold_residual->TotalMemory = TotalMemory; residual = hold_residual; - /* Turn MMU back off */ - _put_MSR(orig_MSR & ~0x0030); - } - if (start_multi) { - hold_residual->VitalProductData.SmpIar = 0; - hold_residual->Cpus[1].CpuState = CPU_GOOD_FW; - residual->VitalProductData.SmpIar = (unsigned long)park_cpus; - residual->Cpus[1].CpuState = CPU_GOOD; - hold_residual->VitalProductData.Reserved5 = 0xdeadbeef; - } + /* Enforce a sane MSR for booting. */ + _put_MSR(MSR_IP); + } /* assume the chunk below 8M is free */ end_avail = (char *)0x00800000; - /* tell the user where we were loaded at and where we - * were relocated to for debugging this process + /* + * We link ourself to 0x00800000. When we run, we relocate + * ourselves there. So we just need __image_begin for the + * start. -- Tom */ - puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); - if ( (unsigned long)load_addr != (unsigned long)&start ) - { - puts("relocated to: "); puthex((unsigned long)&start); - puts(" "); - puthex((unsigned long)((unsigned long)&start + (4*num_words))); - puts("\n"); - } - - if ( residual ) - { - puts("board data at: "); puthex((unsigned long)residual); - puts(" "); - puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); - puts("\n"); - puts("relocated to: "); - puthex((unsigned long)hold_residual); - puts(" "); - puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); - puts("\n"); - } + zimage_start = (char *)(unsigned long)(&__image_begin); + zimage_size = (unsigned long)(&__image_end) - + (unsigned long)(&__image_begin); - /* we have to subtract 0x10000 here to correct for objdump including the - size of the elf header which we strip -- Cort */ - zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; - else - initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; + initrd_size = (unsigned long)(&__ramdisk_end) - + (unsigned long)(&__ramdisk_begin); /* - * Find a place to stick the zimage and initrd and - * relocate them if we have to. -- Cort + * The zImage and initrd will be between start and _end, so they've + * already been moved once. We're good to go now. -- Tom */ avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - if ( (unsigned long)zimage_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); - zimage_start = (char *)avail_ram; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); + puts("\n"); - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - avail_ram = (char *)PAGE_ALIGN( - (unsigned long)zimage_size+(unsigned long)zimage_start); - memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); - initrd_start = (unsigned long)avail_ram; - initrd_end = initrd_start + INITRD_SIZE; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - } else if ( initrd_start ) { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); + if ( initrd_size ) { + puts("initrd at: "); + puthex((unsigned long)(&__ramdisk_begin)); + puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); } avail_ram = (char *)0x00400000; @@ -353,10 +300,10 @@ CRT_tstc(); /* Forces keyboard to be initialized */ puts("\nLinux/PPC load: "); - timer = 0; cp = cmd_line; memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); - while ( *cp ) putc(*cp++); + while ( *cp ) + putc(*cp++); while (timer++ < 5*1000) { if (tstc()) { while ((ch = getc()) != '\n' && ch != '\r') { @@ -382,26 +329,24 @@ udelay(1000); /* 1 msec */ } *cp = 0; - puts("\n"); + puts("\nUncompressing Linux..."); - /* mappings on early boot can only handle 16M */ - if ( (int)(cmd_line) > (16<<20)) - puts("cmd_line located > 16M\n"); - if ( (int)hold_residual > (16<<20)) - puts("hold_residual located > 16M\n"); - if ( initrd_start > (16<<20)) - puts("initrd_start located > 16M\n"); - - puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); - + + if (start_multi) { + puts("Parking cpu1 at 0xc0\n"); + residual->VitalProductData.SmpIar = (unsigned long)0xc0; + residual->Cpus[1].CpuState = CPU_GOOD; + hold_residual->VitalProductData.Reserved5 = 0xdeadbeef; + } + { struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size)+(1<<20)-1,(1<<20)); - + + rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) + + (1 << 20) - 1, (1 << 20)); + rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); @@ -410,31 +355,33 @@ memcpy( (void *)rec->data, "prepboot", 9); rec->size = sizeof(struct bi_record) + 8 + 1; rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_MACHTYPE; rec->data[0] = _MACH_prep; rec->data[1] = 0; - rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); + rec->size = sizeof(struct bi_record) + 2 * + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_CMD_LINE; memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; - rec = (struct bi_record *)((ulong)rec + rec->size); - + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if ( initrd_size ) { + rec->tag = BI_INITRD; + rec->data[0] = (unsigned long)(&__ramdisk_begin); + rec->data[1] = initrd_size; + rec->size = sizeof(struct bi_record) + 2 * + 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); } puts("Now booting the kernel\n"); return (unsigned long)hold_residual; -} - -/* - * PCI/ISA I/O support - */ -unsigned long -local_to_PCI(unsigned long addr) -{ - return (addr | 0x80000000); } diff -urN linux-2.4.18/arch/ppc/boot/prep/vreset.c linux-2.4.19-pre5/arch/ppc/boot/prep/vreset.c --- linux-2.4.18/arch/ppc/boot/prep/vreset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/prep/vreset.c Sat Mar 30 22:55:27 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.vreset.c 1.11 07/25/01 18:13:07 trini + * BK Id: SCCS/s.vreset.c 1.13 01/11/02 10:46:08 trini */ /* * vreset.c @@ -29,7 +29,7 @@ struct VaRegs; /* - * VGA Register + * VGA Register */ struct VgaRegs { @@ -108,51 +108,6 @@ { ENDMK } }; -struct VgaRegs S3TextRegs[NREGS+1] = { - /* port index value */ - /* SR Regs */ - { 0x3c4, 0x1, 0x0 }, - { 0x3c4, 0x2, 0x3 }, - { 0x3c4, 0x3, 0x0 }, - { 0x3c4, 0x4, 0x2 }, - /* CR Regs */ - { 0x3d4, 0x0, 0x5f }, - { 0x3d4, 0x1, 0x4f }, - { 0x3d4, 0x2, 0x50 }, - { 0x3d4, 0x3, 0x82 }, - { 0x3d4, 0x4, 0x55 }, - { 0x3d4, 0x5, 0x81 }, - { 0x3d4, 0x6, 0xbf }, - { 0x3d4, 0x7, 0x1f }, - { 0x3d4, 0x8, 0x00 }, - { 0x3d4, 0x9, 0x4f }, - { 0x3d4, 0xa, 0x0d }, - { 0x3d4, 0xb, 0x0e }, - { 0x3d4, 0xc, 0x00 }, - { 0x3d4, 0xd, 0x00 }, - { 0x3d4, 0xe, 0x00 }, - { 0x3d4, 0xf, 0x00 }, - { 0x3d4, 0x10, 0x9c }, - { 0x3d4, 0x11, 0x8e }, - { 0x3d4, 0x12, 0x8f }, - { 0x3d4, 0x13, 0x28 }, - { 0x3d4, 0x14, 0x1f }, - { 0x3d4, 0x15, 0x96 }, - { 0x3d4, 0x16, 0xb9 }, - { 0x3d4, 0x17, 0xa3 }, - /* GR Regs */ - { 0x3ce, 0x0, 0x0 }, - { 0x3ce, 0x1, 0x0 }, - { 0x3ce, 0x2, 0x0 }, - { 0x3ce, 0x3, 0x0 }, - { 0x3ce, 0x4, 0x0 }, - { 0x3ce, 0x5, 0x10 }, - { 0x3ce, 0x6, 0xe }, - { 0x3ce, 0x7, 0x0 }, - { 0x3ce, 0x8, 0xff }, - { ENDMK } -}; - struct RGBColors { unsigned char r, g, b; @@ -161,9 +116,9 @@ /* * Default console text mode color table. * These values were obtained by booting Linux with - * text mode firmware & then dumping the registers. + * text mode firmware & then dumping the registers. */ -struct RGBColors TextCLUT[256] = +struct RGBColors TextCLUT[256] = { /* red green blue */ { 0x0, 0x0, 0x0 }, @@ -424,8 +379,8 @@ }; unsigned char AC[21] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}; static int scanPCI(int start_slt); @@ -443,20 +398,13 @@ outb(port, val >> 8); outb(port+1, val); } - -#define PPC_601 1 int vga_init(unsigned char *ISA_mem) { int slot; struct VgaRegs *VgaTextRegs; -#if 0 - if ((_get_PVR()>>16) == PPC_601) { - return(old_vga_init(ISA_mem)); - } -#endif - + /* See if VGA already in TEXT mode - exit if so! */ outb(0x3CE, 0x06); if ((inb(0x3CF) & 0x01) == 0){ @@ -470,20 +418,19 @@ while((slot = scanPCI(slot)) > -1) { /* find video card in use */ unlockVideo(slot); /* enable I/O to card */ VgaTextRegs = GenVgaTextRegs; - + switch (PCIVendor(slot)) { default: break; case(S3Vendor): unlockS3(); - VgaTextRegs = S3TextRegs; break; - + case(CirrusVendor): outw(0x3C4, 0x0612); /* unlock ext regs */ outw(0x3C4, 0x0700); /* reset ext sequence mode */ break; - + case(ParadiseVendor): /* IBM Portable 850 */ outw(0x3ce, 0x0f05); /* unlock pardise registers */ outw(0x3c4, 0x0648); @@ -508,7 +455,7 @@ } outw(0x3d4, 0x34a0); break; - + #if 0 /* Untested - probably doesn't work */ case(MatroxVendor): case(DiamondVendor): @@ -518,7 +465,7 @@ mdelay(1000); #endif }; - + outw(0x3C4, 0x0120); /* disable video */ setTextRegs(VgaTextRegs); /* initial register setup */ setTextCLUT(0); /* load color lookup table */ @@ -526,23 +473,23 @@ setTextRegs(VgaTextRegs); /* reload registers */ outw(0x3C4, 0x0100); /* re-enable video */ clearVideoMemory(); - + if (PCIVendor(slot) == S3Vendor) { outb(0x3c2, 0x63); /* MISC */ } /* endif */ - + #ifdef DEBUG printslots(); mdelay(5000); #endif - + mdelay(1000); /* give time for the video monitor to come up */ } return (1); /* 'CRT' I/O supported */ } /* - * Write to VGA Attribute registers. + * Write to VGA Attribute registers. */ void writeAttr(unsigned char index, unsigned char data, unsigned char videoOn) @@ -563,18 +510,18 @@ /* * saved settings - */ + */ while( svp->io_port != ENDMK ) { outb(svp->io_port, svp->io_index); outb(svp->io_port+1, svp->io_value); - svp++; + svp++; } outb(0x3c2, 0x67); /* MISC */ outb(0x3c6, 0xff); /* MASK */ for ( i = 0; i < 0x10; i++) - writeAttr(i, AC[i], 0); /* pallete */ + writeAttr(i, AC[i], 0); /* pallete */ writeAttr(0x10, 0x0c, 0); /* text mode */ writeAttr(0x11, 0x00, 0); /* overscan color (border) */ writeAttr(0x12, 0x0f, 0); /* plane enable */ @@ -587,9 +534,9 @@ { int i; - outb(0x3C6, 0xFF); + outb(0x3C6, 0xFF); i = inb(0x3C7); - outb(0x3C8, 0); + outb(0x3C8, 0); i = inb(0x3C7); for ( i = 0; i < 256; i++) { @@ -604,14 +551,14 @@ { int i, j; unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000]; - + outb(0x3C2, 0x67); - /* - * Load font + /* + * Load font */ i = inb(0x3DA); /* Reset Attr toggle */ - outb(0x3C0,0x30); + outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */ outw(0x3C4, 0x0001); /* reset sequencer */ @@ -706,7 +653,7 @@ } /* - * cursor() sets an offset (0-1999) into the 80x25 text area + * cursor() sets an offset (0-1999) into the 80x25 text area. */ void cursor(int x, int y) @@ -737,14 +684,14 @@ #define NPCIREGS 5 -/* - should use devfunc number/indirect method to be totally safe on - all machines, this works for now on 3 slot Moto boxes +/* + should use devfunc number/indirect method to be totally safe on + all machines, this works for now on 3 slot Moto boxes */ struct PCI_ConfigInfo { unsigned long * config_addr; - unsigned long regs[NPCIREGS]; + unsigned long regs[NPCIREGS]; } PCI_slots [NSLOTS] = { { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ @@ -761,10 +708,10 @@ /* * The following code modifies the PCI Command register - * to enable memory and I/O accesses. - */ + * to enable memory and I/O accesses. + */ void -unlockVideo(int slot) +unlockVideo(int slot) { volatile unsigned char * ppci; @@ -811,13 +758,13 @@ pslot->regs[r] = SwapBytes ( pslot->config_addr[r] ); } /* card in slot ? */ - if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { + if ( pslot->regs[DEVID] != 0xFFFFFFFF ) { /* VGA ? */ - if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || + if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) { highVgaSlot = slt; /* did firmware enable it ? */ - if ( (pslot->regs[CMD] & 0x03) ) { + if ( (pslot->regs[CMD] & 0x03) ) { theSlot = slt; break; } @@ -840,7 +787,7 @@ #ifdef DEBUG static -void printslots(void) +void printslots(void) { int i; #if 0 @@ -853,7 +800,7 @@ i, pslot->config_addr, pslot->regs[0], pslot->regs[2]); #else puts("PCI Slot number: "); puthex(i); - puts(" Vendor ID: "); + puts(" Vendor ID: "); puthex(PCIVendor(i)); puts("\n"); #endif } diff -urN linux-2.4.18/arch/ppc/boot/simple/Makefile linux-2.4.19-pre5/arch/ppc/boot/simple/Makefile --- linux-2.4.18/arch/ppc/boot/simple/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/Makefile Sat Mar 30 22:55:27 2002 @@ -0,0 +1,135 @@ +# This is far from simple, but I couldn't think of a good name. This is +# for making the 'zImage' or 'zImage.initrd' on a number of targets. +# +# Author: Tom Rini +# +# Copyright 2001 MontaVista Software Inc. +# +# Notes: For machine targets which produce more than one image, define +# ZNETBOOT and ZNETBOOTRD to the image which should be available for +# 'znetboot' and 'znetboot.initrd` +# +# 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. + +USE_STANDARD_AS_RULE := true + +# Normally, we use the 'misc-simple.c' file for decompress_kernel and +# whatnot. Sometimes we need to override this however. +MISC := ../common/misc-simple.o +ifeq ($(CONFIG_EMBEDDEDBOOT),y) +ZIMAGE := zImage-EMBEDDED +ZIMAGEINITRD := zImage.initrd-EMBEDDED +TFTPIMAGE := /tftpboot/zImage.embedded +MISC := misc-embedded.o +endif +ifeq ($(CONFIG_GEMINI),y) +ZIMAGE := zImage-SMON +ZIMAGEINITRD := zImage.initrd-SMON +HEADHELP := direct.o +TFTPIMAGE := /tftpboot/zImage.gemini +endif +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE += .smp +endif + +# Setup a default address to put ourselves, change it as needed. +LD_ARGS = -T ../ld.script -Ttext 0x00800000 -Bstatic +ifdef CONFIG_8xx +LD_ARGS := -T ../ld.script -Ttext 0x00180000 -Bstatic +endif +ifeq ($(CONFIG_8260)$(CONFIG_4xx),y) +LD_ARGS := -T ../ld.script -Ttext 0x00400000 -Bstatic +endif +OBJCOPY_ARGS := -O elf32-powerpc + +# head.o and ../common/relocate.o must be at the start. +obj-y := head.o ../common/relocate.o $(HEADHELP) \ + $(MISC) ../common/misc-common.o \ + ../common/string.o ../common/util.o +obj-$(CONFIG_4xx) += embed_config.o +obj-$(CONFIG_8xx) += embed_config.o +obj-$(CONFIG_8260) += embed_config.o +obj-$(CONFIG_BSEIP) += iic.o +obj-$(CONFIG_MBX) += iic.o +obj-$(CONFIG_RPXCLASSIC) += iic.o +obj-$(CONFIG_RPXLITE) += iic.o +# Different boards need different serial implementations. +ifeq ($(CONFIG_SERIAL_CONSOLE),y) +obj-$(CONFIG_8xx) += m8xx_tty.o +obj-$(CONFIG_8260) += m8260_tty.o +obj-$(CONFIG_SERIAL) += ../common/ns16550.o +endif + +LIBS := ../lib/zlib.a + +# Tools +MKPREP := ../utils/mkprep +MKTREE := ../utils/mktree + +AFLAGS_head.o += -I$(TOPDIR)/arch/$(ARCH)/kernel +AFLAGS_../common/util.o += -I$(TOPDIR)/arch/$(ARCH)/kernel +AFLAGS_../common/relocate.o += -I$(TOPDIR)/arch/$(ARCH)/kernel + +zvmlinux: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o + $(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + ../common/dummy.o image.o + $(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \ + -R .ramdisk -R .sysmap + +zvmlinux.initrd: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz \ + ../common/dummy.o + $(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section=.ramdisk=../images/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \ + --add-section=.image=../images/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + ../common/dummy.o image.o + $(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS) + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \ + -R .sysmap + +# Sort-of dummy rules, that let us format the image we want. +zImage: $(ZIMAGE) + rm -f zvmlinux +zImage.initrd: $(ZIMAGEINITRD) + rm -f zvmlinux.initrd + +znetboot: zImage +ifneq ($(ZNETBOOT),) + cp ../images/$(ZNETBOOT) $(TFTPIMAGE) +else + cp ../images/zImage.* $(TFTPIMAGE) +endif + +znetboot.initrd: zImage.initrd +ifneq ($(ZNETBOOTRD),) + cp ../images/$(ZNETBOOTRD) $(TFTPIMAGE) +else + cp ../images/zImage.* $(TFTPIMAGE) +endif + +zImage-EMBEDDED: zvmlinux + mv zvmlinux ../images/zImage.embedded + +zImage.initrd-EMBEDDED: zvmlinux.initrd + mv zvmlinux.initrd ../images/zImage.initrd.embedded + +zImage-SMON: zvmlinux + dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k + +zImage.initrd-SMON: zvmlinux.initrd + dd if=zvmlinux.initrd of=../images/zImage.initrd.gemini skip=64 bs=1k + +zImage-TREE: zvmlinux + $(MKTREE) zvmlinux ../images/zImage.treeboot + +zImage.initrd-TREE: zvmlinux.initrd + $(MKTREE) zvmlinux.initrd ../images/zImage.initrd.treeboot + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc/boot/simple/direct.S linux-2.4.19-pre5/arch/ppc/boot/simple/direct.S --- linux-2.4.18/arch/ppc/boot/simple/direct.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/direct.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,15 @@ +/* + * arch/ppc/boot/simple/direct.S + * + * Author: Tom Rini + * + * This is an empty function for machines which use SERIAL_IO_MEM + * and don't need ISA_io set to anything but 0, or perform any other + * serial fixups. + */ + + .text + + .globl serial_fixups +serial_fixups: + blr diff -urN linux-2.4.18/arch/ppc/boot/simple/embed_config.c linux-2.4.19-pre5/arch/ppc/boot/simple/embed_config.c --- linux-2.4.18/arch/ppc/boot/simple/embed_config.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/embed_config.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,755 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ + +/* Board specific functions for those embedded 8xx boards that do + * not have boot monitor support for board information. + */ +#include +#include +#ifdef CONFIG_8xx +#include +#endif +#ifdef CONFIG_8260 +#include +#include +#endif +#ifdef CONFIG_4xx +#include +#endif +#if defined(CONFIG_405GP) || defined(CONFIG_NP405H) || defined(CONFIG_NP405L) +#include +#endif + +/* For those boards that don't provide one. +*/ +#if !defined(CONFIG_MBX) +static bd_t bdinfo; +#endif + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); + +/* Supply a default Ethernet address for those eval boards that don't + * ship with one. This is an address from the MBX board I have, so + * it is unlikely you will find it on your network. + */ +static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; + +#if defined(CONFIG_MBX) + +/* The MBX hands us a pretty much ready to go board descriptor. This + * is where the idea started in the first place. + */ +void +embed_config(bd_t **bdp) +{ + u_char *mp; + u_char eebuf[128]; + int i; + bd_t *bd; + + bd = *bdp; + + /* Read the first 128 bytes of the EEPROM. There is more, + * but this is all we need. + */ + iic_read(0xa4, eebuf, 0, 128); + + /* All we are looking for is the Ethernet MAC address. The + * first 8 bytes are 'MOTOROLA', so check for part of that. + * If it's there, assume we have a valid MAC address. If not, + * grab our default one. + */ + if ((*(uint *)eebuf) == 0x4d4f544f) + mp = &eebuf[0x4c]; + else + mp = (u_char *)def_enet_addr; + + for (i=0; i<6; i++) + bd->bi_enetaddr[i] = *mp++; + + /* The boot rom passes these to us in MHz. Linux now expects + * them to be in Hz. + */ + bd->bi_intfreq *= 1000000; + bd->bi_busfreq *= 1000000; + + /* Stuff a baud rate here as well. + */ + bd->bi_baudrate = 9600; +} +#endif /* CONFIG_MBX */ + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) || \ + defined(CONFIG_RPX6) || defined(CONFIG_EP405) +/* Helper functions for Embedded Planet boards. +*/ +/* Because I didn't find anything that would do this....... +*/ +u_char +aschex_to_byte(u_char *cp) +{ + u_char byte, c; + + c = *cp++; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } else + c -= '0'; + + byte = c * 16; + + c = *cp; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } else + c -= '0'; + + byte += c; + + return(byte); +} + +static void +rpx_eth(bd_t *bd, u_char *cp) +{ + int i; + + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = aschex_to_byte(cp); + cp += 2; + } +} + +#ifdef CONFIG_RPX6 +static uint +rpx_baseten(u_char *cp) +{ + uint retval; + + retval = 0; + + while (*cp != '\n') { + retval *= 10; + retval += (*cp) - '0'; + cp++; + } + return(retval); +} +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) +static void +rpx_brate(bd_t *bd, u_char *cp) +{ + uint rate; + + rate = 0; + + while (*cp != '\n') { + rate *= 10; + rate += (*cp) - '0'; + cp++; + } + + bd->bi_baudrate = rate * 100; +} + +static void +rpx_cpuspeed(bd_t *bd, u_char *cp) +{ + uint num, den; + + num = den = 0; + + while (*cp != '\n') { + num *= 10; + num += (*cp) - '0'; + cp++; + if (*cp == '/') { + cp++; + den = (*cp) - '0'; + break; + } + } + + /* I don't know why the RPX just can't state the actual + * CPU speed..... + */ + if (den) { + num /= den; + num *= den; + } + bd->bi_intfreq = bd->bi_busfreq = num * 1000000; + + /* The 8xx can only run a maximum 50 MHz bus speed (until + * Motorola changes this :-). Greater than 50 MHz parts + * run internal/2 for bus speed. + */ + if (num > 50) + bd->bi_busfreq /= 2; +} +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_EP405) +static void +rpx_memsize(bd_t *bd, u_char *cp) +{ + uint size; + + size = 0; + + while (*cp != '\n') { + size *= 10; + size += (*cp) - '0'; + cp++; + } + + bd->bi_memsize = size * 1024 * 1024; +} +#endif /* LITE || CLASSIC || EP405 */ + +#endif /* Embedded Planet boards */ + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + +/* Read the EEPROM on the RPX-Lite board. +*/ +void +embed_config(bd_t **bdp) +{ + u_char eebuf[256], *cp; + bd_t *bd; + + /* Read the first 256 bytes of the EEPROM. I think this + * is really all there is, and I hope if it gets bigger the + * info we want is still up front. + */ + bd = &bdinfo; + *bdp = bd; + +#if 1 + iic_read(0xa8, eebuf, 0, 128); + iic_read(0xa8, &eebuf[128], 128, 128); + + /* We look for two things, the Ethernet address and the + * serial baud rate. The records are separated by + * newlines. + */ + cp = eebuf; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + rpx_brate(bd, cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + rpx_memsize(bd, cp); + } + } + if (*cp == 'H') { + cp++; + if (*cp == 'Z') { + cp += 2; + rpx_cpuspeed(bd, cp); + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; +#else + /* For boards without initialized EEPROM. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (8 * 1024 * 1024); + bd->bi_intfreq = 48000000; + bd->bi_busfreq = 48000000; + bd->bi_baudrate = 9600; +#endif +} +#endif /* RPXLITE || RPXCLASSIC */ + +#ifdef CONFIG_BSEIP +/* Build a board information structure for the BSE ip-Engine. + * There is more to come since we will add some environment + * variables and a function to read them. + */ +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + bd = &bdinfo; + *bdp = bd; + + /* Baud rate and processor speed will eventually come + * from the environment variables. + */ + bd->bi_baudrate = 9600; + + /* Get the Ethernet station address from the Flash ROM. + */ + cp = (u_char *)0xfe003ffa; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + /* The rest of this should come from the environment as well. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (16 * 1024 * 1024); + bd->bi_intfreq = 48000000; + bd->bi_busfreq = 48000000; +} +#endif /* BSEIP */ + +#ifdef CONFIG_FADS +/* Build a board information structure for the FADS. + */ +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + bd = &bdinfo; + *bdp = bd; + + /* Just fill in some known values. + */ + bd->bi_baudrate = 9600; + + /* Use default enet. + */ + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + bd->bi_memstart = 0; + bd->bi_memsize = (8 * 1024 * 1024); + bd->bi_intfreq = 40000000; + bd->bi_busfreq = 40000000; +} +#endif /* FADS */ + +#ifdef CONFIG_8260 +/* Compute 8260 clock values if the rom doesn't provide them. + * We can't compute the internal core frequency (I don't know how to + * do that). + */ +static void +clk_8260(bd_t *bd) +{ + uint scmr, vco_out, clkin; + uint plldf, pllmf, busdf, brgdf, cpmdf; + volatile immap_t *ip; + + ip = (immap_t *)IMAP_ADDR; + scmr = ip->im_clkrst.car_scmr; + + /* The clkin is always bus frequency. + */ + clkin = bd->bi_busfreq; + + /* Collect the bits from the scmr. + */ + plldf = (scmr >> 12) & 1; + pllmf = scmr & 0xfff; + cpmdf = (scmr >> 16) & 0x0f; + busdf = (scmr >> 20) & 0x0f; + + /* This is arithmetic from the 8260 manual. + */ + vco_out = clkin / (plldf + 1); + vco_out *= 2 * (pllmf + 1); + bd->bi_vco = vco_out; /* Save for later */ + + bd->bi_cpmfreq = vco_out / 2; /* CPM Freq, in MHz */ + + /* Set Baud rate divisor. The power up default is divide by 16, + * but we set it again here in case it was changed. + */ + ip->im_clkrst.car_sccr = 1; /* DIV 16 BRG */ + bd->bi_brgfreq = vco_out / 16; +} +#endif + +#ifdef CONFIG_EST8260 +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + bd = *bdp; +#if 0 + /* This is actually provided by my boot rom. I have it + * here for those people that may load the kernel with + * a JTAG/COP tool and not the rom monitor. + */ + bd->bi_baudrate = 115200; + bd->bi_intfreq = 200000000; + bd->bi_busfreq = 66666666; + bd->bi_cpmfreq = 66666666; + bd->bi_brgfreq = 33333333; + bd->bi_memsize = 16 * 1024 * 1024; +#else + /* The boot rom passes these to us in MHz. Linux now expects + * them to be in Hz. + */ + bd->bi_intfreq *= 1000000; + bd->bi_busfreq *= 1000000; + bd->bi_cpmfreq *= 1000000; + bd->bi_brgfreq *= 1000000; +#endif + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* EST8260 */ + +#ifdef CONFIG_SBS8260 +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + /* This should provided by the boot rom. + */ + bd = &bdinfo; + *bdp = bd; + bd->bi_baudrate = 9600; + bd->bi_memsize = 64 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. The development board had 66 MHz. + */ + bd->bi_busfreq = 66666666; + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 133000000; + + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* SBS8260 */ + +#ifdef CONFIG_RPX6 +void +embed_config(bd_t **bdp) +{ + u_char *cp, *keyvals; + int i; + bd_t *bd; + + keyvals = (u_char *)*bdp; + + bd = &bdinfo; + *bdp = bd; + + /* This is almost identical to the RPX-Lite/Classic functions + * on the 8xx boards. It would be nice to have a key lookup + * function in a string, but the format of all of the fields + * is slightly different. + */ + cp = keyvals; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + bd->bi_baudrate = rpx_baseten(cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + bd->bi_memsize = rpx_baseten(cp) * 1024 * 1024; + } + } + if (*cp == 'X') { + cp++; + if (*cp == 'T') { + cp += 2; + bd->bi_busfreq = rpx_baseten(cp); + } + } + if (*cp == 'N') { + cp++; + if (*cp == 'V') { + cp += 2; + bd->bi_nvsize = rpx_baseten(cp) * 1024 * 1024; + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; + + /* The memory size includes both the 60x and local bus DRAM. + * I don't want to use the local bus DRAM for real memory, + * so subtract it out. It would be nice if they were separate + * keys. + */ + bd->bi_memsize -= 32 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. + */ + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 200000000; +} +#endif /* RPX6 for testing */ + +#ifdef CONFIG_ADS8260 +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + /* This should provided by the boot rom. + */ + bd = &bdinfo; + *bdp = bd; + bd->bi_baudrate = 9600; + bd->bi_memsize = 16 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. The development board had 66 MHz. + */ + bd->bi_busfreq = 66666666; + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 200000000; + + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* ADS8260 */ + +#ifdef CONFIG_WILLOW +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd; + + /* Willow has Open Firmware....I should learn how to get this + * information from it. + */ + bd = &bdinfo; + *bdp = bd; + bd->bi_baudrate = 9600; + bd->bi_memsize = 32 * 1024 * 1024; + + /* Set all of the clocks. We have to know the speed of the + * external clock. The development board had 66 MHz. + */ + bd->bi_busfreq = 66666666; + clk_8260(bd); + + /* I don't know how to compute this yet. + */ + bd->bi_intfreq = 200000000; + + + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } +} +#endif /* WILLOW */ + +#ifdef CONFIG_TREEBOOT +/* This could possibly work for all treeboot roms. +*/ +#define BOARD_INFO_VECTOR 0xFFFE0B50 + +void +embed_config(bd_t **bdp) +{ + u_char *cp; + int i; + bd_t *bd, *treeboot_bd; + bd_t *(*get_board_info)(void) = + (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); +#if !defined(CONFIG_STB03xxx) + volatile emac_t *emacp; + emacp = (emac_t *)EMAC0_BASE; /* assume 1st emac - armin */ + + /* shut down the Ethernet controller that the boot rom + * sometimes leaves running. + */ + mtdcr(DCRN_MALCR, MALCR_MMSR); /* 1st reset MAL */ + while (mfdcr(DCRN_MALCR) & MALCR_MMSR) {}; /* wait for the reset */ + emacp->em0mr0 = 0x20000000; /* then reset EMAC */ + eieio(); +#endif + + bd = &bdinfo; + *bdp = bd; + if ((treeboot_bd = get_board_info()) != NULL) { + memcpy(bd, treeboot_bd, sizeof(bd_t)); + } + else { + /* Hmmm...better try to stuff some defaults. + */ + bd->bi_memsize = 16 * 1024 * 1024; + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) { + /* I should probably put different ones here, + * hopefully only one is used. + */ + bd->BD_EMAC_ADDR(0,i) = *cp; + +#ifdef CONFIG_PCI + bd->bi_pci_enetaddr[i] = *cp++; +#endif + } + bd->bi_intfreq = 200000000; + bd->bi_busfreq = 100000000; +#ifdef CONFIG_PCI + bd->bi_pci_busfreq = 66666666; +#endif + /* Yeah, this look weird, but on Redwood 4 they are + * different object in the structure. When RW5 uses + * OpenBIOS, it requires a special value. + */ +#ifdef CONFIG_REDWOOD_5 + bd->bi_intfreq = 200 * 1000 * 1000; + bd->bi_busfreq = 0; + + bd->bi_tbfreq = 27 * 1000 * 1000; +#elif CONFIG_REDWOOD_4 + bd->bi_tbfreq = bd->bi_intfreq; +#endif + } +} +#endif + +#ifdef CONFIG_EP405 +void +embed_config(bd_t **bdp) +{ + u_char *cp; + bd_t *bd; + + bd = &bdinfo; + *bdp = bd; +#if 1 + cp = (u_char *)0xF0000EE0; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + rpx_memsize(bd, cp); + } + } + + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_intfreq = 200000000; + bd->bi_busfreq = 100000000; + bd->bi_pci_busfreq= 33000000 ; +#else + + bd->bi_memsize = 64000000; + bd->bi_intfreq = 200000000; + bd->bi_busfreq = 100000000; + bd->bi_pci_busfreq= 33000000 ; +#endif +} +#endif + diff -urN linux-2.4.18/arch/ppc/boot/simple/head.S linux-2.4.19-pre5/arch/ppc/boot/simple/head.S --- linux-2.4.18/arch/ppc/boot/simple/head.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/head.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,120 @@ +/* + * arch/ppc/boot/simple/head.S + * + * Initial board bringup code for many different boards. + * + * Author: Tom Rini + * trini@mvista.com + * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others). + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include "ppc_asm.h" + + .text + +/* + * Begin at some arbitrary location in RAM or Flash + * Initialize core registers + * Configure memory controller (Not executing from RAM) + * Move the boot code to the link address (8M) + * Setup C stack + * Initialize UART + * Decompress the kernel to 0x0 + * Jump to the kernel entry + * + */ + + .globl start +start: + bl start_ +#ifdef CONFIG_TREEBOOT + /* The IBM "Tree" bootrom knows that the address of the bootrom + * read only structure is 4 bytes after _start. + */ + .long 0x62726f6d # structure ID - "brom" + .long 0x5f726f00 # - "_ro\0" + .long 1 # structure version + .long bootrom_cmdline # address of *bootrom_cmdline +#endif + +start_: +#ifdef CONFIG_FORCE + /* We have some really bad firmware. We must disable the L1 + * icache/dcache now or the board won't boot. + */ + li r4,0x0000 + isync + mtspr HID0,r4 + sync + isync +#endif + +#if defined(CONFIG_MBX) || defined(CONFIG_RPX6) + mr r29,r3 /* On the MBX860, r3 is the board info pointer. + * On the RPXSUPER, r3 points to the + * NVRAM configuration keys. + */ +#endif + + mflr r3 /* Save our actual starting address. */ + + /* The following functions we call must not modify r3 or r4..... + */ +#ifdef CONFIG_6xx + bl disable_6xx_mmu + bl disable_6xx_l1cache +#if defined(CONFIG_FORCE) || defined(CONFIG_K2) || defined(CONFIG_EV64260) + bl _setup_L2CR +#endif +#endif + +#ifdef CONFIG_8xx + mfmsr r8 /* Turn off interrupts */ + li r9,0 + ori r9,r9,MSR_EE + andc r8,r8,r9 + mtmsr r8 + + /* We do this because some boot roms don't initialize the + * processor correctly. Don't do this if you want to debug + * using a BDM device. + */ + li r4,0 /* Zero DER to prevent FRZ */ + mtspr SPRN_DER,r4 +#endif + +#ifdef CONFIG_REDWOOD_4 + /* All of this Redwood 4 stuff will soon disappear when the + * boot rom is straightened out. + */ + mr r29, r3 /* Easier than changing the other code */ + bl HdwInit + mr r3, r29 +#endif + +#if defined(CONFIG_MBX) || defined(CONFIG_RPX6) + mr r4,r29 /* put the board info pointer where the relocate + * routine will find it + */ +#endif + +#ifdef CONFIG_EV64260 + /* Move 64260's base regs & CS window for external UART */ + bl ev64260_init +#endif + + /* Get the load address. + */ + subi r3, r3, 4 /* Get the actual IP, not NIP */ + b relocate + diff -urN linux-2.4.18/arch/ppc/boot/simple/iic.c linux-2.4.19-pre5/arch/ppc/boot/simple/iic.c --- linux-2.4.18/arch/ppc/boot/simple/iic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/iic.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,218 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ + +/* Minimal support functions to read configuration from IIC EEPROMS + * on MPC8xx boards. Originally written for RPGC RPX-Lite. + * Dan Malek (dmalek@jlc.net). + */ +#include +#include +#include +#include + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +void iic_read(uint devaddr, u_char *buf, uint offset, uint count); + +static int iic_init_done; + +static void +iic_init(void) +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + uint dpaddr; + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + /* Reset the CPM. This is necessary on the 860 processors + * that may have started the SCC1 ethernet without relocating + * the IIC. + * This also stops the Ethernet in case we were loaded by a + * BOOTP rom monitor. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); + + /* Remove any microcode patches. We will install our own + * later. + */ + cp->cp_cpmcr1 = 0; + cp->cp_cpmcr2 = 0; + cp->cp_cpmcr3 = 0; + cp->cp_cpmcr4 = 0; + cp->cp_rccr = 0; + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Initialize the parameter ram. + */ + + /* Allocate space for a two transmit and one receive buffer + * descriptor in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0840; + + /* Set up the IIC parameters in the parameter ram. + */ + iip->iic_tbase = dpaddr; + iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + /* This should really be done by the reader/writer. + */ + iip->iic_mrblr = 128; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0x34; + + /* Make clock run maximum slow. + */ + i2c->i2c_i2brg = 7; + + /* Disable interrupts. + */ + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + /* Enable SDMA. + */ + immap->im_siu_conf.sc_sdcr = 1; + + iic_init_done = 1; +} + +/* Read from IIC. + * Caller provides device address, memory buffer, and byte count. + */ +static u_char iitemp[32]; + +void +iic_read(uint devaddr, u_char *buf, uint offset, uint count) +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + u_char *tb; + uint temp; + + /* If the interface has not been initialized, do that now. + */ + if (!iic_init_done) + iic_init(); + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + /* Send a "dummy write" operation. This is a write request with + * only the offset sent, followed by another start condition. + * This will ensure we start reading from the first location + * of the EEPROM. + */ + tb = iitemp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr & 0xfe; /* Device address */ + *(tb+1) = offset; /* Offset */ + tbdf->cbd_datlen = 2; /* Length */ + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 3) == 0); + + if (tbdf->cbd_sc & BD_SC_READY) + printf("IIC ra complete but tbuf ready\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#if 0 + /* We can't do this...there is no serial port yet! + */ + if (temp == 0) { + printf("Timeout reading EEPROM\n"); + return; + } +#endif +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; + + /* To read, we need an empty buffer of the proper length. + * All that is used is the first byte for address, the remainder + * is just used for timing (and doesn't really have to exist). + */ + tbdf->cbd_bufaddr = (int)tb; + *tb = devaddr | 1; /* Device address */ + rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ + tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ + tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + + /* Chip bug, set enable here. + */ + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 1) == 0); + + if (rbdf->cbd_sc & BD_SC_EMPTY) + printf("IIC read complete but rbuf empty\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; +} diff -urN linux-2.4.18/arch/ppc/boot/simple/legacy.S linux-2.4.19-pre5/arch/ppc/boot/simple/legacy.S --- linux-2.4.18/arch/ppc/boot/simple/legacy.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/legacy.S Sat Mar 30 22:55:27 2002 @@ -0,0 +1,19 @@ +/* + * arch/ppc/boot/simple/legacy.S + * + * Author: Tom Rini + * + * This will go and setup ISA_io to 0x8000000 and return. + */ + +#include "ppc_asm.h" + + .text + + .globl serial_fixups +serial_fixups: + lis r3,ISA_io@h /* Load ISA_io */ + ori r3,r3,ISA_io@l + lis r4,0x8000 /* Load the value, 0x8000000 */ + stw r4,0(r3) /* store */ + blr diff -urN linux-2.4.18/arch/ppc/boot/simple/m8260_tty.c linux-2.4.19-pre5/arch/ppc/boot/simple/m8260_tty.c --- linux-2.4.18/arch/ppc/boot/simple/m8260_tty.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/m8260_tty.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,323 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ + + +/* Minimal serial functions needed to send messages out the serial + * port on SMC1. + */ +#include +#include +#include + +uint no_print; +extern char *params[]; +extern int nparams; +static u_char cons_hold[128], *sgptr; +static int cons_hold_cnt; + +/* If defined, enables serial console. The value (1 through 4) + * should designate which SCC is used, but this isn't complete. Only + * SCC1 is known to work at this time. + */ +#ifdef CONFIG_SCC_CONSOLE +#define SCC_CONSOLE 1 +#endif + +unsigned long +serial_init(int ignored, bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; +#ifdef SCC_CONSOLE + volatile scc_t *sccp; + volatile scc_uart_t *sup; +#endif + volatile cbd_t *tbdf, *rbdf; + volatile immap_t *ip; + volatile iop8260_t *io; + volatile cpm8260_t *cp; + uint dpaddr, memaddr; + + ip = (immap_t *)IMAP_ADDR; + cp = &ip->im_cpm; + io = &ip->im_ioport; + + /* Perform a reset. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & CPM_CR_FLG); + +#ifdef CONFIG_ADS8260 + /* Enable the RS-232 transceivers. + */ + *(volatile uint *)(BCSR_ADDR + 4) &= + ~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2); +#endif + +#ifdef SCC_CONSOLE + sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]); + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Use Port D for SCC1 instead of other functions. + */ + io->iop_ppard |= 0x00000003; + io->iop_psord &= ~0x00000001; /* Rx */ + io->iop_psord |= 0x00000002; /* Tx */ + io->iop_pdird &= ~0x00000001; /* Rx */ + io->iop_pdird |= 0x00000002; /* Tx */ + +#else + sp = (smc_t*)&(ip->im_smc[0]); + *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; + up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* Use Port D for SMC1 instead of other functions. + */ + io->iop_ppard |= 0x00c00000; + io->iop_pdird |= 0x00400000; + io->iop_pdird &= ~0x00800000; + io->iop_psord &= ~0x00c00000; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. + */ + memaddr = (bd->bi_memsize - 256) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&ip->im_dprambase[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+128; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ +#ifdef SCC_CONSOLE + sup->scc_genscc.scc_rbase = dpaddr; + sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t); + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + sup->scc_genscc.scc_mrblr = 128; + sup->scc_maxidl = 8; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sccp->scc_gsmrh = 0; + sccp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + sccp->scc_sccm = 0; + sccp->scc_scce = 0xffff; + sccp->scc_dsr = 0x7e7e; + sccp->scc_pmsr = 0x3000; + + /* Wire BRG1 to SCC1. The console driver will take care of + * others. + */ + ip->im_cpmux.cmx_scr = 0; +#else + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; + up->smc_brklen = 0; + up->smc_brkec = 0; + up->smc_brkcr = 0; + up->smc_mrblr = 128; + up->smc_maxidl = 8; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + */ + ip->im_cpmux.cmx_smr = 0; +#endif + + /* The baud rate divisor needs to be coordinated with clk_8260(). + */ + ip->im_brgc1 = + (((bd->bi_brgfreq/16) / bd->bi_baudrate) << 1) | + CPM_BRG_EN; + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Initialize Tx/Rx parameters. + */ +#ifdef SCC_CONSOLE + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#else + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +#endif + + /* This is ignored. + */ + return 0; +} + +int +serial_readbuf(u_char *cbuf) +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + int i, nc; + + ip = (immap_t *)IMAP_ADDR; + +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + nc = rbdf->cbd_datlen; + for (i=0; icbd_sc |= BD_SC_EMPTY; + + return(nc); +} + +void +serial_putc(void *ignored, const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + extern bd_t *board_info; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase]; +#endif + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc(void *ignored) +{ + char c; + + if (cons_hold_cnt <= 0) { + cons_hold_cnt = serial_readbuf(cons_hold); + sgptr = cons_hold; + } + c = *sgptr++; + cons_hold_cnt--; + + return(c); +} + +int +serial_tstc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + volatile scc_uart_t *sup; + volatile immap_t *ip; + + ip = (immap_t *)IMAP_ADDR; +#ifdef SCC_CONSOLE + sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; +#else + up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]); + rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase]; +#endif + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} + +void +serial_close(unsigned long com_port) +{ +} diff -urN linux-2.4.18/arch/ppc/boot/simple/m8xx_tty.c linux-2.4.19-pre5/arch/ppc/boot/simple/m8xx_tty.c --- linux-2.4.18/arch/ppc/boot/simple/m8xx_tty.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/m8xx_tty.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,300 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ + + +/* Minimal serial functions needed to send messages out the serial + * port on the MBX console. + * + * The MBX uxes SMC1 for the serial port. We reset the port and use + * only the first BD that EPPC-Bug set up as a character FIFO. + * + * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug + * use COM1 instead of SMC1 as the console port. This kinda sucks + * for the rest of the kernel, so here we force the use of SMC1 again. + */ +#include +#include +#include +#include +#include + +#ifdef CONFIG_MBX +#define MBX_CSR1 ((volatile u_char *)0xfa100000) +#define CSR1_COMEN (u_char)0x02 +#endif + +#ifdef TQM_SMC2_CONSOLE +#define PROFF_CONS PROFF_SMC2 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC2 +#define SMC_INDEX 1 +static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport); +#else +#define PROFF_CONS PROFF_SMC1 +#define CPM_CR_CH_CONS CPM_CR_CH_SMC1 +#define SMC_INDEX 0 +#endif + +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + +unsigned long +serial_init(int ignored, bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + uint dpaddr, memaddr; +#ifndef CONFIG_MBX + uint ui; +#endif + + cp = cpmp; + sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]); + up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +#ifdef CONFIG_FADS + /* Enable SMC1/2 transceivers. + */ + *((volatile uint *)BCSR1) &= ~(BCSR1_RS232EN_1|BCSR1_RS232EN_2); +#endif + +#ifndef CONFIG_MBX + { + /* Initialize SMCx and use it for the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + +#ifdef TQM_SMC2_CONSOLE + /* Use Port A for SMC2 instead of other functions. + */ + iopp->iop_papar |= 0x00c0; + iopp->iop_padir &= ~0x00c0; + iopp->iop_paodr &= ~0x00c0; +#else + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory for SMC FIFOs. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * This wires BRG1 to SMC1 and BRG2 to SMC2; + */ + cp->cp_simode = 0x10000000; + ui = bd->bi_intfreq / 16 / bd->bi_baudrate; +#ifdef TQM_SMC2_CONSOLE + cp->cp_brgc2 = +#else + cp->cp_brgc1 = +#endif + ((ui - 1) < 4096) + ? (((ui - 1) << 1) | CPM_BRG_EN) + : ((((ui / 16) - 1) << 1) | CPM_BRG_EN | CPM_BRG_DIV16); + +#else /* CONFIG_MBX */ + if (*MBX_CSR1 & CSR1_COMEN) { + /* COM1 is enabled. Initialize SMC1 and use it for + * the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + (((bd->bi_intfreq/16) / 9600) << 1) | CPM_BRG_EN; + + /* Enable SMC1 for console output. + */ + *MBX_CSR1 &= ~CSR1_COMEN; + } + else { +#endif /* ndef CONFIG_MBX */ + /* SMCx is used as console port. + */ + tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; + + /* Issue a stop transmit, and wait for it. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Single character receive. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; + + /* This is ignored. + */ + return 0; +} + +void +serial_putc(void *ignored, const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc(void *ignored) +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} + +void +serial_close(unsigned long com_port) +{ +} diff -urN linux-2.4.18/arch/ppc/boot/simple/misc-embedded.c linux-2.4.19-pre5/arch/ppc/boot/simple/misc-embedded.c --- linux-2.4.18/arch/ppc/boot/simple/misc-embedded.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/simple/misc-embedded.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,231 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + * + * Originally adapted by Gary Thomas. Much additional work by + * Cort Dougan . On top of that still more work by + * Dan Malek . + * + * Currently maintained by: Tom Rini + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nonstdio.h" +#include "zlib.h" + +/* The linker tells us where the image is. */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; +extern char _end[]; + +/* Because of the limited amount of memory on embedded, it presents + * loading problems. The biggest is that we load this boot program + * into a relatively low memory address, and the Linux kernel Bss often + * extends into this space when it get loaded. When the kernel starts + * and zeros the BSS space, it also writes over the information we + * save here and pass to the kernel (usually board info). + * On these boards, we grab some known memory holes to hold this information. + */ +char cmd_buf[256]; +char *cmd_line = cmd_buf; +char *avail_ram; +char *end_avail; +char *zimage_start; + +/* This is for 4xx treeboot. It provides a place for the bootrom + * give us a pointer to a rom environment command line. + */ +char *bootrom_cmdline = ""; + +/* This is the default cmdline that will be given to the user at boot time.. + * If none was specified at compile time, we'll give it one that should work. + * -- Tom */ +#ifdef CONFIG_CMDLINE_BOOL +char compiled_string[] = CONFIG_CMDLINE; +#endif +char ramroot_string[] = "root=/dev/ram"; +char netroot_string[] = "root=/dev/nfs rw ip=auto"; + +/* Serial port to use. */ +unsigned long com_port; + +/* We need to make sure that this is before the images to ensure + * that it's in a mapped location. - Tom */ +bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot"))); +bd_t *hold_residual = &hold_resid_buf; + +extern unsigned long serial_init(int chan, bd_t *bp); +extern void serial_close(unsigned long com_port); +extern unsigned long start; +extern void flush_instruction_cache(void); +extern void gunzip(void *, int, unsigned char *, int *); +extern void embed_config(bd_t **bp); + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) +{ + char *cp, ch; + int timer = 0, zimage_size; + unsigned long initrd_size; + + /* First, capture the embedded board information. Then + * initialize the serial console port. + */ + embed_config(&bp); +#ifdef CONFIG_SERIAL_CONSOLE + com_port = serial_init(0, bp); +#endif + + /* copy board data */ + if (bp) + memcpy(hold_residual,bp,sizeof(bd_t)); + + /* Set end of memory available to us. It is always the highest + * memory address provided by the board information. + */ + end_avail = (char *)(bp->bi_memsize); + + puts("\nloaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( bp ) { + puts("board data at: "); puthex((unsigned long)bp); + puts(" "); + puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); + puts("\nrelocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); + puts("\n"); + } + + /* + * We link ourself to an arbitrary low address. When we run, we + * relocate outself to that address. __image_being points to + * the part of the image where the zImage is. -- Tom + */ + zimage_start = (char *)(unsigned long)(&__image_begin); + zimage_size = (unsigned long)(&__image_end) - + (unsigned long)(&__image_begin); + + initrd_size = (unsigned long)(&__ramdisk_end) - + (unsigned long)(&__ramdisk_begin); + + /* + * The zImage and initrd will be between start and _end, so they've + * already been moved once. We're good to go now. -- Tom + */ + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); + puts("\n"); + + if ( initrd_size ) { + puts("initrd at: "); + puthex((unsigned long)(&__ramdisk_begin)); + puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); + } + + /* + * setup avail_ram - this is the first part of ram usable + * by the uncompress code. Anything after this program in RAM + * is now fair game. -- Tom + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + puts("\nLinux/PPC load: "); + cp = cmd_line; + /* This is where we try and pick the right command line for booting. + * If we were given one at compile time, use it. It Is Right. + * If we weren't, see if we have a ramdisk. If so, thats root. + * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom + */ +#ifdef CONFIG_CMDLINE_BOOL + memcpy (cmd_line, compiled_string, sizeof(compiled_string)); +#else + if ( initrd_size ) + memcpy (cmd_line, ramroot_string, sizeof(ramroot_string)); + else + memcpy (cmd_line, netroot_string, sizeof(netroot_string)); +#endif + while ( *cp ) + putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b' || ch == '\177') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else if (ch == '\030' /* ^x */ + || ch == '\025') { /* ^u */ + while (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + puts("\nUncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + flush_instruction_cache(); + puts("done.\n"); + { + struct bi_record *rec; + + rec = (struct bi_record *)_ALIGN((unsigned long)zimage_size + + (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_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if ( initrd_size ) { + rec->tag = BI_INITRD; + rec->data[0] = (unsigned long)(&__ramdisk_begin); + rec->data[1] = initrd_size; + rec->size = sizeof(struct bi_record) + 2 * + 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); + } + puts("Now booting the kernel\n"); + serial_close(com_port); + + return (unsigned long)hold_residual; +} diff -urN linux-2.4.18/arch/ppc/boot/tree/Makefile linux-2.4.19-pre5/arch/ppc/boot/tree/Makefile --- linux-2.4.18/arch/ppc/boot/tree/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/Makefile Thu Jan 1 01:00:00 1970 @@ -1,66 +0,0 @@ -# BK Id: SCCS/s.Makefile 1.7 06/15/01 13:16:10 paulus -# -# -# Module name: Makefile -# -# Description: -# Makefile for the IBM "tree" evaluation board Linux kernel -# boot loaders. -# -# -# Copyright (c) 1999 Grant Erickson -# -# PPC-405 modification -# Copyright 2000-2001 MontaVista Software Inc. -# Author: MontaVista Software, Inc. -# frank_rowand@mvista.com or source@mvista.com -# debbie_chu@mvista.com -# - -HOSTCFLAGS = -O -I$(TOPDIR)/include - -CC = $(CROSS_COMPILE)gcc -LD = $(CROSS_COMPILE)ld -OBJCOPY = $(CROSS_COMPILE)objcopy -OBJDUMP = $(CROSS_COMPILE)objdump - -GZIP = gzip -vf9 -RM = rm -f -MKEVIMG = ../utils/mkevimg -l -c -MKIRIMG = ../utils/mkirimg -CFLAGS += -I$(TOPDIR)/drivers/net -LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic - -OBJS = ../common/crt0.o main.o misc.o irSect.o ../common/string.o \ - ../common/misc-common.o ../common/ns16550.o -LIBS = ../lib/zlib.a - -treeboot: $(OBJS) $(LIBS) ld.script - $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) - -zImage: vmlinux.img - -zImage.initrd: vmlinux.initrd.img - -treeboot.image: treeboot - $(OBJCOPY) --add-section=image=../images/vmlinux.gz treeboot $@ - -treeboot.initrd: treeboot.image ramdisk.image.gz - $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ - -vmlinux.img: treeboot.image - $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt - $(MKEVIMG) treeboot.image.out ../images/vmlinux.tree.img - $(RM) treeboot.image treeboot.image.out irSectStart.txt - -vmlinux.initrd.img: treeboot.initrd - $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt - $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt - $(MKEVIMG) treeboot.initrd.out ../images/vmlinux.tree.initrd.img - $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt - -clean: - rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc/boot/tree/irSect.c linux-2.4.19-pre5/arch/ppc/boot/tree/irSect.c --- linux-2.4.18/arch/ppc/boot/tree/irSect.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/irSect.c Thu Jan 1 01:00:00 1970 @@ -1,39 +0,0 @@ -/* - * BK Id: SCCS/s.irSect.c 1.6 05/18/01 15:17:22 cort - */ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.c - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#include "irSect.h" - - -/* - * The order of globals below must not change. If more globals are added, - * you must change the script 'mkirimg' accordingly. - * - */ - -/* - * irSectStart must be at beginning of file - */ -unsigned int irSectStart = 0xdeadbeaf; - -unsigned int imageSect_start = 0; -unsigned int imageSect_size = 0; -unsigned int initrdSect_start = 0; -unsigned int initrdSect_size = 0; - -/* - * irSectEnd must be at end of file - */ -unsigned int irSectEnd = 0xdeadbeaf; diff -urN linux-2.4.18/arch/ppc/boot/tree/irSect.h linux-2.4.19-pre5/arch/ppc/boot/tree/irSect.h --- linux-2.4.18/arch/ppc/boot/tree/irSect.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/irSect.h Thu Jan 1 01:00:00 1970 @@ -1,35 +0,0 @@ -/* - * BK Id: SCCS/s.irSect.h 1.6 05/18/01 15:17:22 cort - */ -/* - * - * Copyright (c) 1999 Grant Erickson - * - * Module name: irSect.h - * - * Description: - * Defines variables to hold the absolute starting address and size - * of the Linux kernel "image" and the initial RAM disk "initrd" - * sections within the boot loader. - * - */ - -#ifndef __IRSECT_H__ -#define __IRSECT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned int imageSect_start; -extern unsigned int imageSect_size; - -extern unsigned int initrdSect_start; -extern unsigned int initrdSect_size; - - -#ifdef __cplusplus -} -#endif - -#endif /* __IRSECT_H__ */ diff -urN linux-2.4.18/arch/ppc/boot/tree/ld.script linux-2.4.19-pre5/arch/ppc/boot/tree/ld.script --- linux-2.4.18/arch/ppc/boot/tree/ld.script Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/ld.script Thu Jan 1 01:00:00 1970 @@ -1,69 +0,0 @@ -OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0 - .plt : { *(.plt) } - .text : - { - *(.text) - *(.rodata) - *(.rodata.*) - *(.rodata1) - *(.got1) - } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - _etext = .; - PROVIDE (etext = .); - /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); -} - diff -urN linux-2.4.18/arch/ppc/boot/tree/main.c linux-2.4.19-pre5/arch/ppc/boot/tree/main.c --- linux-2.4.18/arch/ppc/boot/tree/main.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/main.c Thu Jan 1 01:00:00 1970 @@ -1,212 +0,0 @@ -/* - * BK Id: SCCS/s.main.c 1.9 06/15/01 13:16:10 paulus - */ -/* - * Copyright (c) 1997 Paul Mackerras - * Initial Power Macintosh COFF version. - * Copyright (c) 1999 Grant Erickson - * Modifications for an ELF-based IBM evaluation board version. - * Copyright 2000-2001 MontaVista Software Inc. - * PPC405GP modifications - * Author: MontaVista Software, Inc. - * frank_rowand@mvista.com or source@mvista.com - * debbie_chu@mvista.com - * - * Module name: main.c - * - * Description: - * This module does most of the real work for the boot loader. It - * checks the variables holding the absolute start address and size - * of the Linux kernel "image" and initial RAM disk "initrd" sections - * and if they are present, moves them to their "proper" locations. - * - * For the Linux kernel, "proper" is physical address 0x00000000. - * For the RAM disk, "proper" is the image's size below the top - * of physical memory. The Linux kernel may be in either raw - * binary form or compressed with GNU zip (aka gzip). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include - -#include "nonstdio.h" -#include "irSect.h" -#if defined(CONFIG_SERIAL_CONSOLE) -#include "ns16550.h" -#endif /* CONFIG_SERIAL_CONSOLE */ - - -/* Preprocessor Defines */ - -/* - * Location of the IBM boot ROM function pointer address for retrieving - * the board information structure. - */ - -#define BOARD_INFO_VECTOR 0xFFFE0B50 - -/* - * Warning: the board_info doesn't contain valid data until get_board_info() - * gets called in start(). - */ -#define RAM_SIZE board_info.bi_memsize - -#define RAM_PBASE 0x00000000 -#define RAM_PEND (RAM_PBASE + RAM_SIZE) - -#define RAM_VBASE 0xC0000000 -#define RAM_VEND (RAM_VBASE + RAM_SIZE) - -#define RAM_START RAM_PBASE -#define RAM_END RAM_PEND -#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) - -#define PROG_START RAM_START - - -/* Function Macros */ - -#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) - -/* Global Variables */ - -/* Needed by zalloc and zfree for allocating memory */ - -char *avail_ram; /* Indicates start of RAM available for heap */ -char *end_avail; /* Indicates end of RAM available for heap */ - -/* Needed for serial I/O. -*/ -extern unsigned long *com_port; - -bd_t board_info; - -/* -** The bootrom may change bootrom_cmdline to point to a buffer in the -** bootrom. -*/ -char *bootrom_cmdline = ""; -char treeboot_bootrom_cmdline[512]; - -#ifdef CONFIG_CMDLINE -char *cmdline = CONFIG_CMDLINE; -#else -char *cmdline = ""; -#endif - -/* Function Prototypes */ - -extern void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); - -void -kick_watchdog(void) -{ -#ifdef CONFIG_405GP - mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); -#endif -} - -void start(void) -{ - void *options; - int ns, oh, i; - unsigned long sa, len; - void *dst; - unsigned char *im; - unsigned long initrd_start, initrd_size; - bd_t *(*get_board_info)(void) = - (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); - bd_t *bip = NULL; - - - com_port = (struct NS16550 *)serial_init(0); - -#ifdef CONFIG_405GP - /* turn off on-chip ethernet */ - /* This is to fix a problem with early walnut bootrom. */ - - { - /* Physical mapping of ethernet register space. */ - static struct ppc405_enet_regs *ppc405_enet_regp = - (struct ppc405_enet_regs *)PPC405_EM0_REG_ADDR; - - mtdcr(DCRN_MALCR, MALCR_MMSR); /* 1st reset MAL */ - - while (mfdcr(DCRN_MALCR) & MALCR_MMSR) {}; /* wait for the reset */ - - ppc405_enet_regp->em0mr0 = 0x20000000; /* then reset EMAC */ - } -#endif - - if ((bip = get_board_info()) != NULL) - memcpy(&board_info, bip, sizeof(bd_t)); - - /* Init RAM disk (initrd) section */ - - kick_watchdog(); - - if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - - _printk("Initial RAM disk at 0x%08x (%u bytes)\n", - initrd_start, initrd_size); - - memcpy((char *)initrd_start, - (char *)(initrdSect_start), - initrdSect_size); - - end_avail = (char *)initrd_start; - } else { - initrd_start = initrd_size = 0; - end_avail = (char *)RAM_END; - } - - /* Linux kernel image section */ - - kick_watchdog(); - - im = (unsigned char *)(imageSect_start); - len = imageSect_size; - dst = (void *)PROG_START; - - /* Check for the gzip archive magic numbers */ - - if (im[0] == 0x1f && im[1] == 0x8b) { - - /* The gunzip routine needs everything nice and aligned */ - - void *cp = (void *)ALIGN_UP(RAM_FREE, 8); - avail_ram = (void *)(cp + ALIGN_UP(len, 8)); /* used by zalloc() */ - memcpy(cp, im, len); - - /* I'm not sure what the 0x200000 parameter is for, but it works. */ - /* It tells gzip the end of the area you wish to reserve, and it - * can use data past that point....unfortunately, this value - * isn't big enough (luck ran out). -- Dan - */ - - gunzip(dst, 0x400000, cp, (int *)&len); - } else { - memmove(dst, im, len); - } - - kick_watchdog(); - - flush_cache(dst, len); - - sa = (unsigned long)dst; - - (*(void (*)())sa)(&board_info, - initrd_start, - initrd_start + initrd_size, - cmdline, - cmdline + strlen(cmdline)); - - pause(); -} diff -urN linux-2.4.18/arch/ppc/boot/tree/misc.S linux-2.4.19-pre5/arch/ppc/boot/tree/misc.S --- linux-2.4.18/arch/ppc/boot/tree/misc.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/tree/misc.S Thu Jan 1 01:00:00 1970 @@ -1,43 +0,0 @@ -/* - * BK Id: SCCS/s.misc.S 1.7 05/18/01 06:20:29 patch - */ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include "../../kernel/ppc_asm.tmpl" - - .text - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - mfpvr r5 # Get processor version register - extrwi r5,r5,16,0 # Get the version bits - cmpwi cr0,r5,0x0020 # Is this a 403-based processor? - beq 1f # Yes, it is - li r5,32 # It is not a 403, set to 32 bytes - addi r4,r4,32-1 # len += line_size - 1 - srwi. r4,r4,5 # Convert from bytes to lines - b 2f -1: li r5,16 # It is a 403, set to 16 bytes - addi r4,r4,16-1 # len += line_size - 1 - srwi. r4,r4,4 # Convert from bytes to lines -2: mtctr r4 # Set-up the counter register - beqlr # If it is 0, we are done -3: dcbf r0,r3 # Flush and invalidate the data line - icbi r0,r3 # Invalidate the instruction line - add r3,r3,r5 # Move to the next line - bdnz 3b # Are we done yet? - sync - isync - blr # Return to the caller diff -urN linux-2.4.18/arch/ppc/boot/utils/Makefile linux-2.4.19-pre5/arch/ppc/boot/utils/Makefile --- linux-2.4.18/arch/ppc/boot/utils/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/Makefile Sat Mar 30 22:55:27 2002 @@ -10,7 +10,7 @@ all: dummy # Simple programs with 1 file and no extra CFLAGS -UTILS = addnote hack-coff mkprep mksimage mknote piggyback mkpmon mkbugboot +UTILS = addnote hack-coff mkprep mknote mktree $(UTILS): $(HOSTCC) $(HOSTCFLAGS) -o $@ $@.c diff -urN linux-2.4.18/arch/ppc/boot/utils/mkevimg linux-2.4.19-pre5/arch/ppc/boot/utils/mkevimg --- linux-2.4.18/arch/ppc/boot/utils/mkevimg Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/mkevimg Thu Jan 1 01:00:00 1970 @@ -1,488 +0,0 @@ -#!/usr/bin/perl - -# -# Copyright (c) 1998-1999 TiVo, Inc. -# All rights reserved. -# -# Copyright (c) 1999 Grant Erickson -# Major syntactic and usability rework. -# -# Module name: mkevimg -# -# Description: -# Converts an ELF output file from the linker into the format used by -# the IBM evaluation board ROM Monitor to load programs from a host -# onto the evaluation board. The ELF file must be an otherwise execut- -# able file (with the text and data addresses bound at link time) and -# have space reserved after the entry point for the load information -# block: -# -# typedef struct boot_block { -# unsigned long magic; 0x0052504F -# unsigned long dest; Target address of the image -# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks -# unsigned long debug_flag; Run the debugger or image after load -# unsigned long entry_point; The image address to jump to after load -# unsigned long checksum; 32 bit checksum including header -# unsigned long reserved[2]; -# } boot_block_t; -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hlvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -c Put checksum in load information block.\n"); - print(" -h Print out this message and exit.\n"); - print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkevimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("chlvV")) { - usage(1); - } - - if ($opt_c) { - $do_checksum = 1; - } - - if ($opt_h) { - usage(0); - } - - if ($opt_l) { - $linux = 1; - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ifile = shift(@ARGV))) { - usage(1); - } - - if (!($ofile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ifile)) { - exit(1); - } - -} - -# -# ELF file and section header field numbers -# - -require '../utils/elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - - decode_options(); - - open(ELF, "<$ifile") || die "Cannot open input file"; - - $ifilesize = (-s $ifile); - - if ($verbose) { - print("Output file: $ofile\n"); - print("Input file: $ifile, $ifilesize bytes.\n"); - } - - if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { - print("Failed to read input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ifile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); - exit (1); - } - - if ($verbose) { - print("File header:\n"); - printf(" Identifier: %s\n", $eh[$e_ident]); - printf(" Type: %d\n", $eh[$e_type]); - printf(" Machine: %d\n", $eh[$e_machine]); - printf(" Version: %d\n", $eh[$e_version]); - printf(" Entry point: 0x%08x\n", $eh[$e_entry]); - printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); - printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); - printf(" Flags: 0x%08x\n", $eh[$e_flags]); - printf(" Header size: %d\n", $eh[$e_ehsize]); - printf(" Program entry size: %d\n", $eh[$e_phentsize]); - printf(" Program table entries: %d\n", $eh[$e_phnum]); - printf(" Section header size: %d\n", $eh[$e_shentsize]); - printf(" Section table entries: %d\n", $eh[$e_shnum]); - printf(" String table section: %d\n", $eh[$e_shstrndx]); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.text' and '.bss' sections in - # particular. - - if ($verbose) { - print("Section headers:\n"); - print("Idx Name Size Address File off Algn\n"); - print("--- ------------------------ -------- -------- -------- ----\n"); - } - - $off = $eh[$e_shoff]; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - if ($verbose) { - printf("%3d %-24s %8x %08x %08x %4d\n", - $i, $name, $sh[$sh_size], $sh[$sh_addr], - $sh[$sh_offset], $sh[$sh_addralign]); - } - - # Attempt to find the .text and .bss sections - - if ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.text$/) { - ($text_addr, $text_offset, $text_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\image$/)) { - $image_found = 1; - - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($linux && ($name =~ /^\initrd$/)) { - $initrd_found = 1; - - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - printf("Text section - Address: 0x%08x, Size: 0x%08x\n", - $text_addr, $text_size); - printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", - $bss_addr, $bss_size); - - if ($linux) { - if ($image_found) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } - - if ($initrd_found) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } - } - - # - # Open output file - # - - open(BOOT, ">$ofile") || die "Cannot open output file"; - - # - # Compute image size - # - - $output_size = $bss_offset - $text_offset + $bss_size; - - if ($linux && $image_found) { - $output_size += $image_size; - } - - if ($linux && $initrd_found) { - $output_size += $initrd_size; - } - - # - # Compute size with header - # - - $header = pack("H8N7", "0052504f", 0, 0, 0, 0, 0, 0, 0); - $num_blocks = ($output_size + length($header) + 511) / 512; - - # - # Write IBM PowerPC evaluation board boot_block_t header - # - - $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, - $text_addr, 0, 0, 0); - - - $bytes = length($header); - - if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { - die("Could not write boot image header to output file."); - } - - printf("Entry point = 0x%08x\n", $text_addr); - printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", - $output_size, $output_size, $num_blocks); - - # - # Write image starting after ELF and program headers and - # continuing to beginning of bss - # - - $bytes = $bss_offset - $text_offset + $bss_size; - - if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - - # - # If configured, write out the image and initrd sections as well - # - - if ($linux) { - if ($image_found) { - $bytes = $image_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - - if ($initrd_found) { - $bytes = $initrd_size; - if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { - die("Could not write boot image to output file.\n"); - } - } - } - - # - # Pad to a multiple of 512 bytes - # If the (size of the boot image mod 512) is between 509 and 511 bytes - # then the tftp to the Walnut fails. This may be fixed in more recent - # Walnut bootrom. - # - - $pad_size = 512 - ((length($header) + $output_size) % 512); - if ($pad_size == 512) { - $pad_size = 0; - } - - if ($pad_size != 0) { - - if ($verbose) { - print("Padding boot image by an additional $pad_size bytes.\n"); - } - - $pad_string = pack("H8","deadbeef") x 128; - - syswrite(BOOT, $pad_string, $pad_size) or - die "Could not pad boot image in output file.\n"; - - } - - # - # Compute 32 bit checksum over entire file. - # - - if ($do_checksum) { - - close(BOOT); - open(BOOT, "+<$ofile") || die "Cannot open output file"; - undef $/; - $temp = unpack("%32N*", ); - # Solaris and PPC Linux return 0x80000000 for "-$temp" when $temp - # is negative. "~($temp - 1)" negates $temp properly. - $csum = ~($temp - 1); - printf("Checksum = 0x%08x\r\n", $csum); - - # - # Rewrite IBM PowerPC evaluation board boot_block_t header, - # this time with the checksum included - # - - $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, - $text_addr, $csum, 0, 0); - - seek(BOOT, 0, 0); - syswrite(BOOT, $header, length($header)) or - die("Could not write boot image header to output file."); - - } - - # - # Clean-up and leave - # - - close(BOOT); - - print("\nBoot image file \"$ofile\" built successfully.\n\n"); - - exit(0); -} diff -urN linux-2.4.18/arch/ppc/boot/utils/mkimage.wrapper linux-2.4.19-pre5/arch/ppc/boot/utils/mkimage.wrapper --- linux-2.4.18/arch/ppc/boot/utils/mkimage.wrapper Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/mkimage.wrapper Sat Mar 30 22:55:27 2002 @@ -0,0 +1,16 @@ +#!/bin/bash + +# +# Build PPCBoot image when `mkimage' tool is available. +# + +MKIMAGE=$(type -path mkimage) + +if [ -z "${MKIMAGE}" ]; then + # Doesn't exist + echo '"mkimage" command not found - PPCBoot images will not be built' >&2 + exit 0; +fi + +# Call "mkimage" to create PPCBoot image +${MKIMAGE} "$@" diff -urN linux-2.4.18/arch/ppc/boot/utils/mkirimg linux-2.4.19-pre5/arch/ppc/boot/utils/mkirimg --- linux-2.4.18/arch/ppc/boot/utils/mkirimg Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/mkirimg Thu Jan 1 01:00:00 1970 @@ -1,367 +0,0 @@ -#!/usr/bin/perl -# -# Copyright (c) 1998-1999 TiVo, Inc. -# Original ELF parsing code. -# -# Copyright (c) 1999 Grant Erickson -# Original code from 'mkevimg'. -# -# Module name: mkirimg -# -# Description: -# Reads an ELF file and assigns global variables 'imageSect_start', -# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from -# the "image" and "initrd" section header information. It then -# rewrites the input ELF file with assigned globals to an output -# file. -# -# An input file, "irSectStart.txt" has the memory address of -# 'irSectStart'. The irSectStart memory address is used to find -# the global variables in the ".data" section of the ELF file. -# The 'irSectStart' and the above global variables are defined -# in "irSect.c". -# -# - -use File::Basename; -use Getopt::Std; - -# -# usage() -# -# Description: -# This routine prints out the proper command line usage for this program -# -# Input(s): -# status - Flag determining what usage information will be printed and what -# the exit status of the program will be after the information is -# printed. -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub usage { - my($status); - $status = $_[0]; - - printf("Usage: %s [-hvV] \n", - $program); - - if ($status != 0) { - printf("Try `%s -h' for more information.\n", $program); - } - - if ($status != 1) { - print(" -h Print out this message and exit.\n"); - print(" -v Verbose. Print out lots of ELF information.\n"); - print(" -V Print out version information and exit.\n"); - } - - exit($status); -} - -# -# version() -# -# Description: -# This routine prints out program version information -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# This subroutine does not return. -# - -sub version { - print("mkirimg Version 1.1.0\n"); - print("Copyright (c) 1998-1999 TiVo, Inc.\n"); - print("Copyright (c) 1999 Grant Erickson \n"); - - exit (0); -} - -# -# file_check() -# -# Description: -# This routine checks an input file to ensure that it exists, is a -# regular file, and is readable. -# -# Input(s): -# file - Input file to be checked. -# -# Output(s): -# N/A -# -# Returns: -# 0 if the file exists, is a regular file, and is readable, otherwise -1. -# - -sub file_check { - my($file); - $file = $_[0]; - - if (!(-e $file)) { - printf("The file \"%s\" does not exist.\n", $file); - return (-1); - } elsif (!(-f $file)) { - printf("The file \"%s\" is not a regular file.\n", $file); - return (-1); - } elsif (!(-r $file)) { - printf("The file \"%s\" is not readable.\n", $file); - return (-1); - } - - return (0); -} - -# -# decode_options() -# -# Description: -# This routine steps through the command-line arguments, parsing out -# recognzied options. -# -# Input(s): -# N/A -# -# Output(s): -# N/A -# -# Returns: -# N/A -# - -sub decode_options { - - if (!getopts("hvV")) { - usage(1); - } - - if ($opt_h) { - usage(0); - } - - if ($opt_V) { - version(); - exit (0); - } - - if ($opt_v) { - $verbose = 1; - } - - if (!($ElfFile = shift(@ARGV))) { - usage(1); - } - - if (!($OutputFile = shift(@ARGV))) { - usage (1); - } - - if (!($IrFile = shift(@ARGV))) { - usage (1); - } - - if (file_check($ElfFile)) { - exit(1); - } - - if (file_check($IrFile)) { - exit(1); - } -} - -# -# ELF file and section header field numbers -# - -require '../utils/elf.pl'; - -# -# Main program body -# - -{ - $program = basename($0); - decode_options(); - - open(ELF, "<$ElfFile") || die "Cannot open input file"; - open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; - open(IR, "$IrFile") || die "Cannot open input file"; - - $ElfFilesize = (-s $ElfFile); - - if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { - print("Failed to read ELF input file!\n"); - exit(1); - } - - if (read(IR, $irbuf, 8) != 8) { - print("Failed to read Ir input file!\n"); - exit(1); - } - - # - # Parse ELF header - # - - @eh = unpack("a16n2N5n6", $ibuf); - - # - # Make sure this is actually a PowerPC ELF file. - # - - if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { - printf("The file \"%s\" is not an ELF file.\n", $ElfFile); - exit (1); - } elsif ($eh[$e_machine] != 20) { - printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); - exit (1); - } - - # - # Find the section header for the string table. - # - - $strtable_section_offset = $eh[$e_shoff] + - - $eh[$e_shstrndx] * $eh[$e_shentsize]; - - if ($verbose) { - printf("String table section header offset: 0x%x\n", - $strtable_section_offset); - } - - # - # Find the start of the string table. - # - - @strh = unpack("N10", substr($ibuf, $strtable_section_offset, - $eh[$e_shentsize])); - - if ($verbose) { - printf("Section name strings start at: 0x%x, %d bytes.\n", - $strh[$sh_offset], $strh[$sh_size]); - } - - $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); - - # Grab each section header and find '.data', 'image', and - # 'initrd' sections in particular. - - $off = $eh[$e_shoff]; - $imageFound = 0; - $initrdFound = 0; - - for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { - @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); - - # Take the first section name from the array returned by split. - - ($name) = split(/\000/, substr($names, $sh[$sh_name])); - - # Attempt to find the .data, image, and initrd sections - - if ($name =~ /^\image$/) { - ($image_addr, $image_offset, $image_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $imageFound = 1; - - } elsif ($name =~ /^\initrd$/) { - ($initrd_addr, $initrd_offset, $initrd_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - $initrdFound = 1; - - } elsif ($name =~ /^\.data$/) { - ($data_addr, $data_offset, $data_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } elsif ($name =~ /^\.bss$/) { - ($bss_addr, $bss_offset, $bss_size) = - ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); - - } - } - - if ($verbose) { - printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $data_addr, $data_size, $data_offset); - printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", - $bss_addr, $bss_size, $bss_offset); - } - - if ($verbose) { - if ($imageFound) { - printf("Image section - Address: 0x%08x, Size: 0x%08x\n", - $image_addr, $image_size); - } else { - printf("Image section not found in file: $ElfFile\n"); - } - - if ($initrdFound) { - printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", - $initrd_addr, $initrd_size); - } else { - printf("Initrd section not found in file: $ElfFile\n"); - } - } - - # get file offset of irSectStart - - $irSectStartoffset = hex ($irbuf); - - if ($verbose) { - printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); - } - - # get the offset of global variables - - $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; - - # write modified values to OUTPUT file - - syswrite(OUTPUT, $ibuf, $initialOffset); - - if ($imageFound) { - $testN = pack ("N2", $bss_addr + $bss_size, $image_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"imageSect_start\" to 0x%08x\n", - $bss_addr + $bss_size); - printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); - } else { - syswrite(OUTPUT, $ibuf, 8, $initialOffset); - } - - if ($initrdFound) { - $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); - syswrite(OUTPUT, $testN, length($testN)); - printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", - $bss_addr + $bss_size + $image_size); - printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); - } else { - syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); - } - - syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), - $initialOffset + 16); - - # - # Clean-up and leave - # - - close (ELF); - close (OUTPUT); - close (IR); - - exit (0); -} - diff -urN linux-2.4.18/arch/ppc/boot/utils/mksimage.c linux-2.4.19-pre5/arch/ppc/boot/utils/mksimage.c --- linux-2.4.18/arch/ppc/boot/utils/mksimage.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/mksimage.c Thu Jan 1 01:00:00 1970 @@ -1,127 +0,0 @@ -/* - * BK Id: SCCS/s.mksimage.c 1.7 10/11/01 11:59:05 trini - */ -/* - * - * - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define SIZE 1024 -#define BLOCK_ALIGN(x) (((x)+SIZE-1)&(~(SIZE-1))) - -static void -die(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - exit(1); -} - -static void -usage(void) -{ - printf("Usage: mkbinimg -o \n"); - exit(1); -} - -static int -copy_blocks(int ifd, int ofd, unsigned long *offset, unsigned long *size) -{ - off_t cur; - int amt; - unsigned long len = 0; - char buffer[SIZE]; - - cur = lseek(ofd, 0, SEEK_CUR); - - if (cur % SIZE) { - cur = BLOCK_ALIGN(cur); - cur = lseek(ofd, cur, SEEK_SET); - } - - *offset = (unsigned long) cur; - while((amt = read(ifd, buffer, SIZE)) > 0) { - write(ofd, buffer, amt); - len += amt; - } - *size = len; - return 0; -} - - -int -main(int argc, char *argv[]) -{ - char *kernel, *loader, *rdimage = NULL; - unsigned long ld_off, kern_off, rd_off; - unsigned long ld_size, kern_size, rd_size; - int fd, ofd, len; - char buffer[500]; - - if (argc < 5 && !strcmp(argv[argc-2], "-o")) - usage(); - - if (argc > 5) - rdimage = argv[3]; - - kernel = argv[2]; - loader = argv[1]; - - ofd = open(argv[argc-1], (O_RDWR|O_CREAT), 0755); - if (ofd < 0) { - die("can't open %s: %s", argv[5], strerror(errno)); - } - - ld_off = kern_off = rd_off = 0; - ld_size = kern_size = rd_size = 0; - memset(buffer, 0, 500); - len = 0; - - fd = open(loader, O_RDONLY); - if (fd < 0) - die("can't open loader: %s", strerror(errno)); - - copy_blocks(fd, ofd, &ld_off, &ld_size); - len = sprintf(buffer, "bootloader: %lx %lx\n", ld_off, ld_size); - close(fd); - - fd = open(kernel, O_RDONLY); - if (fd < 0) - die("can't open kernel: %s", strerror(errno)); - - copy_blocks(fd, ofd, &kern_off, &kern_size); - len += sprintf(buffer+len, "zimage: %lx %lx\n", kern_off, kern_size); - close(fd); - - if (rdimage) { - fd = open(rdimage, O_RDONLY); - if (fd < 0) - die("can't get ramdisk: %s", strerror(errno)); - - copy_blocks(fd, ofd, &rd_off, &rd_size); - close(fd); - } - - len += sprintf(buffer+len, "initrd: %lx %lx", rd_off, rd_size); - - close(ofd); - - printf("%s\n", buffer); - - return 0; -} - diff -urN linux-2.4.18/arch/ppc/boot/utils/mktree.c linux-2.4.19-pre5/arch/ppc/boot/utils/mktree.c --- linux-2.4.18/arch/ppc/boot/utils/mktree.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/mktree.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,149 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + * + * Makes a tree bootable image for IBM Evaluation boards. + * Basically, just take a zImage, skip the ELF header, and stuff + * a 32 byte header on the front. + * + * We use htonl, which is a network macro, to make sure we're doing + * The Right Thing on an LE machine. It's non-obvious, but it should + * work on anything BSD'ish. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* This gets tacked on the front of the image. There are also a few + * bytes allocated after the _start label used by the boot rom (see + * head.S for details). + */ +typedef struct boot_block { + unsigned long bb_magic; /* 0x0052504F */ + unsigned long bb_dest; /* Target address of the image */ + unsigned long bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */ + unsigned long bb_debug_flag; /* Run debugger or image after load */ + unsigned long bb_entry_point; /* The image address to start */ + unsigned long bb_checksum; /* 32 bit checksum including header */ + unsigned long reserved[2]; +} boot_block_t; + +#define IMGBLK 512 +char tmpbuf[IMGBLK]; + +int main(int argc, char *argv[]) +{ + int in_fd, out_fd; + int nblks, i; + uint cksum, *cp; + struct stat st; + boot_block_t bt; + + if (argc < 3) { + fprintf(stderr, "usage: %s [entry-point]\n",argv[0]); + exit(1); + } + + if (stat(argv[1], &st) < 0) { + perror("stat"); + exit(2); + } + + nblks = (st.st_size + IMGBLK) / IMGBLK; + + bt.bb_magic = htonl(0x0052504F); + + /* If we have the optional entry point parameter, use it */ + if (argc == 4) + bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0)); + else + bt.bb_dest = bt.bb_entry_point = htonl(0x500000); + + /* We know these from the linker command. + * ...and then move it up into memory a little more so the + * relocation can happen. + */ + bt.bb_num_512blocks = htonl(nblks); + bt.bb_debug_flag = 0; + + bt.bb_checksum = 0; + + /* To be neat and tidy :-). + */ + bt.reserved[0] = 0; + bt.reserved[1] = 0; + + if ((in_fd = open(argv[1], O_RDONLY)) < 0) { + perror("zImage open"); + exit(3); + } + + if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) { + perror("bootfile open"); + exit(3); + } + + cksum = 0; + cp = (uint *)&bt; + for (i=0; i 0) { + if (read(in_fd, tmpbuf, IMGBLK) < 0) { + perror("zImage read"); + exit(5); + } + cp = (uint *)tmpbuf; + for (i=0; i -#include - -extern long ce_exec_config[]; - -int main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 2) - { - fprintf(stderr, "usage: %s name out-file\n", - argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl %s_data\n", argv[1]); - fprintf(stdout, "%s_data:\n", argv[1]); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl %s_len\n", argv[1]); - fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -urN linux-2.4.18/arch/ppc/boot/utils/sioffset linux-2.4.19-pre5/arch/ppc/boot/utils/sioffset --- linux-2.4.18/arch/ppc/boot/utils/sioffset Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/sioffset Thu Jan 1 01:00:00 1970 @@ -1,4 +0,0 @@ -#!/bin/sh - -OFFSET=`grep $1 sImage.map | awk '{print $2}'` -echo "0x"$OFFSET diff -urN linux-2.4.18/arch/ppc/boot/utils/sisize linux-2.4.19-pre5/arch/ppc/boot/utils/sisize --- linux-2.4.18/arch/ppc/boot/utils/sisize Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/sisize Thu Jan 1 01:00:00 1970 @@ -1,4 +0,0 @@ -#!/bin/sh - -OFFSET=`grep $1 sImage.map | awk '{print $3}'` -echo "0x"$OFFSET diff -urN linux-2.4.18/arch/ppc/boot/utils/size linux-2.4.19-pre5/arch/ppc/boot/utils/size --- linux-2.4.18/arch/ppc/boot/utils/size Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/boot/utils/size Thu Jan 1 01:00:00 1970 @@ -1,4 +0,0 @@ -#!/bin/sh - -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` -echo "0x"$OFFSET diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.19-pre5/arch/ppc/config.in --- linux-2.4.18/arch/ppc/config.in Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/config.in Sat Mar 30 22:55:27 2002 @@ -122,6 +122,9 @@ bool 'Math emulation' CONFIG_MATH_EMULATION fi +if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then + define_bool CONFIG_EMBEDDEDBOOT y +fi endmenu mainmenu_option next_comment diff -urN linux-2.4.18/arch/ppc/kernel/misc.S linux-2.4.19-pre5/arch/ppc/kernel/misc.S --- linux-2.4.18/arch/ppc/kernel/misc.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/kernel/misc.S Sat Mar 30 22:55:33 2002 @@ -478,9 +478,9 @@ * snoop from the data cache. * This is a no-op on the 601 which has a unified cache. * - * void __flush_page_to_ram(void *page) + * void __flush_dcache_icache(void *page) */ -_GLOBAL(__flush_page_to_ram) +_GLOBAL(__flush_dcache_icache) mfspr r5,PVR rlwinm r5,r5,16,16,31 cmpi 0,r5,1 @@ -500,28 +500,6 @@ sync isync blr - -/* - * Flush a particular page from the instruction cache. - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * This is a no-op on the 601 which has a unified cache. - * - * void __flush_icache_page(void *page) - */ -_GLOBAL(__flush_icache_page) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ - mtctr r4 -1: icbi 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE - bdnz 1b - sync - isync - blr /* * Clear a page using the dcbz instruction, which doesn't cause any @@ -1122,6 +1100,7 @@ .long sys_madvise /* 205 */ .long sys_mincore .long sys_gettid + .long sys_tkill .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr diff -urN linux-2.4.18/arch/ppc/kernel/ppc_ksyms.c linux-2.4.19-pre5/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.18/arch/ppc/kernel/ppc_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/kernel/ppc_ksyms.c Sat Mar 30 22:55:33 2002 @@ -189,6 +189,9 @@ EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(flush_dcache_range); +EXPORT_SYMBOL(flush_icache_user_range); +EXPORT_SYMBOL(flush_icache_page); +EXPORT_SYMBOL(flush_dcache_page); EXPORT_SYMBOL(xchg_u32); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(last_task_used_altivec); diff -urN linux-2.4.18/arch/ppc/kernel/qspan_pci.c linux-2.4.19-pre5/arch/ppc/kernel/qspan_pci.c --- linux-2.4.18/arch/ppc/kernel/qspan_pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/kernel/qspan_pci.c Sat Mar 30 22:55:27 2002 @@ -14,7 +14,7 @@ * PCI access and QSpan control register addresses. The selection is * further selected by a bit setting in a board control register. * Although it should happen, we disable interrupts during this operation - * to make sure some driver doesn't accidently access the PCI while + * to make sure some driver doesn't accidentally access the PCI while * we have switched the chip select. */ diff -urN linux-2.4.18/arch/ppc/kernel/setup.c linux-2.4.19-pre5/arch/ppc/kernel/setup.c --- linux-2.4.18/arch/ppc/kernel/setup.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/kernel/setup.c Sat Mar 30 22:55:33 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setup.c 1.67 12/01/01 20:09:07 benh + * BK Id: SCCS/s.setup.c 1.70 02/15/02 09:27:13 trini */ /* * Common prep/pmac/chrp boot and setup code. @@ -50,7 +50,6 @@ extern void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); extern void bootx_init(unsigned long r4, unsigned long phys); -extern unsigned long reloc_offset(void); extern void identify_cpu(unsigned long offset, unsigned long cpu); extern void do_cpu_ftr_fixups(unsigned long offset); @@ -59,7 +58,8 @@ #endif extern boot_infos_t *boot_infos; -char saved_command_line[256]; +char saved_command_line[512]; +extern char cmd_line[512]; unsigned char aux_device_present; struct ide_machdep_calls ppc_ide_md; char *sysmap; @@ -694,8 +694,12 @@ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); id->hw_config = __le16_to_cpu(id->hw_config); - for (i = 0; i < 32; i++) - id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); + id->acoustic = __le16_to_cpu(id->acoustic); + for (i = 0; i < 5; i++) + id->words95_99[i] = __le16_to_cpu(id->words95_99[i]); + id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); + for (i = 0; i < 22; i++) + id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); id->dlf = __le16_to_cpu(id->dlf); @@ -705,6 +709,12 @@ id->word156 = __le16_to_cpu(id->word156); for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); - for (i = 0; i < 96; i++) - id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); + id->cfa_power = __le16_to_cpu(id->cfa_power); + for (i = 0; i < 14; i++) + id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); + for (i = 0; i < 31; i++) + id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); + for (i = 0; i < 48; i++) + id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); + id->integrity_word = __le16_to_cpu(id->integrity_word); } diff -urN linux-2.4.18/arch/ppc/kernel/signal.c linux-2.4.19-pre5/arch/ppc/kernel/signal.c --- linux-2.4.18/arch/ppc/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/ppc/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -645,10 +645,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/ppc/mm/init.c linux-2.4.19-pre5/arch/ppc/mm/init.c --- linux-2.4.18/arch/ppc/mm/init.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/ppc/mm/init.c Sat Mar 30 22:55:33 2002 @@ -596,23 +596,43 @@ mem_pieces_remove(&phys_avail, start, size, 1); } -void flush_page_to_ram(struct page *page) +/* + * This is called when a page has been modified by the kernel. + * It just marks the page as not i-cache clean. We do the i-cache + * flush later when the page is given to a user process, if necessary. + */ +void flush_dcache_page(struct page *page) { - unsigned long vaddr = (unsigned long) kmap(page); - __flush_page_to_ram(vaddr); - kunmap(page); + clear_bit(PG_arch_1, &page->flags); } -/* - * set_pte stores a linux PTE into the linux page table. - * On machines which use an MMU hash table we avoid changing the - * _PAGE_HASHPTE bit. - */ -void set_pte(pte_t *ptep, pte_t pte) +void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (page->mapping && !PageReserved(page) + && !test_bit(PG_arch_1, &page->flags)) { + __flush_dcache_icache(kmap(page)); + kunmap(page); + set_bit(PG_arch_1, &page->flags); + } +} + +void clear_user_page(void *page, unsigned long vaddr) { -#if _PAGE_HASHPTE != 0 - pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE); -#else - *ptep = pte; -#endif + clear_page(page); +} + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr) +{ + copy_page(vto, vfrom); + __flush_dcache_icache(vto); +} + +void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + unsigned long maddr; + + maddr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + flush_icache_range(maddr, maddr + len); + kunmap(page); } diff -urN linux-2.4.18/arch/ppc64/Makefile linux-2.4.19-pre5/arch/ppc64/Makefile --- linux-2.4.18/arch/ppc64/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,80 @@ +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Linus Torvalds +# Changes for PPC by Gary Thomas +# Rewritten by Cort Dougan and Paul Mackerras +# Adjusted for PPC64 by Tom Gall +# + +KERNELLOAD =0xc000000000000000 + +ifeq ($(shell uname -m),ppc64) +CHECKS = checks +endif + +LINKFLAGS = -T arch/ppc64/vmlinux.lds -Bstatic \ + -e $(KERNELLOAD) -Ttext $(KERNELLOAD) +CFLAGS := $(CFLAGS) -fsigned-char -msoft-float -pipe \ + -Wno-uninitialized -mminimal-toc -fno-builtin +CPP = $(CC) -E $(CFLAGS) + + +HEAD := arch/ppc64/kernel/head.o + +ARCH_SUBDIRS = arch/ppc64/kernel arch/ppc64/mm arch/ppc64/lib +SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) +ARCHIVES := arch/ppc64/kernel/kernel.o arch/ppc64/mm/mm.o arch/ppc64/lib/lib.o $(ARCHIVES) +CORE_FILES := arch/ppc64/kernel/kernel.o arch/ppc64/mm/mm.o arch/ppc64/lib/lib.o $(CORE_FILES) + +ifdef CONFIG_XMON +SUBDIRS += arch/ppc64/xmon +CORE_FILES += arch/ppc64/xmon/x.o +endif +ifdef CONFIG_KDB +SUBDIRS += arch/ppc64/kdb +CORE_FILES += arch/ppc64/kdb/kdba.o +endif + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +checks: + @$(MAKE) -C arch/$(ARCH)/kernel checks + +ifdef CONFIG_PPC_PSERIES +BOOT_TARGETS = zImage znetboot.initrd zImage.initrd +endif + +ifdef CONFIG_PPC_ISERIES +BOOT_TARGETS = vmlinux.sminitrd vmlinux.initrd vmlinux.sm +endif + +$(BOOT_TARGETS): vmlinux + @$(MAKEBOOT) $@ + +znetboot: vmlinux +ifdef CONFIG_SMP + cp -f vmlinux /tftpboot/vmlinux.smp +else + cp -f vmlinux /tftpboot/vmlinux +endif + @$(MAKEBOOT) $@ + +%_config: arch/ppc64/configs/%_defconfig + rm -f .config arch/ppc64/defconfig + cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig + +archclean: + rm -f arch/ppc64/kernel/{ppc_defs.h,checks,mk_defs.s,mk_defs_out.c,mk_defs_tpl} + @$(MAKEBOOT) clean + +archmrproper: + +archdep: + $(MAKEBOOT) fastdep diff -urN linux-2.4.18/arch/ppc64/boot/Makefile linux-2.4.19-pre5/arch/ppc64/boot/Makefile --- linux-2.4.18/arch/ppc64/boot/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,129 @@ +# Makefile for making ELF bootable images for booting on CHRP +# using Open Firmware. +# +# Geert Uytterhoeven September 1997 +# +# Based on coffboot by Paul Mackerras +# Simplified for ppc64 by Todd Inglett +# +# NOTE: this code is built for 32 bit in ELF32 format even though +# it packages a 64 bit kernel. We do this to simplify the +# bootloader and increase compatibility with OpenFirmware. +# +# To this end we need to define BOOTCC, etc, as the tools +# needed to build the 32 bit image. These are normally HOSTCC, +# but may be a third compiler if, for example, you are cross +# compiling from an intel box. Once the 64bit ppc gcc is +# stable it will probably simply be a compiler switch to +# compile for 32bit mode. +# To make it easier to setup a cross compiler, +# CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE +# in the toplevel makefile. + +CROSS32_COMPILE = +#CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux- + +BOOTCC = $(CROSS32_COMPILE)gcc +BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH) +BOOTLD = $(CROSS32_COMPILE)ld +BOOTAS = $(CROSS32_COMPILE)as +BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS) + +.c.o: + $(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $< +.S.o: + $(BOOTCC) $(BOOTAFLAGS) -traditional -c -o $*.o $< + +CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS +LD_ARGS = -Ttext 0x00400000 -e _start + +OBJS = crt0.o start.o main.o zlib.o image.o imagesize.o +#LIBS = $(TOPDIR)/lib/lib.a +LIBS = + +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.chrp.smp +else +TFTPIMAGE=/tftpboot/zImage.chrp +endif + + +ifeq ($(CONFIG_PPC_ISERIES),y) +all: vmlinux.sm +else +all: $(TOPDIR)/zImage +endif + + +znetboot: zImage + cp zImage $(TFTPIMAGE) + + +ifeq ($(CONFIG_PPC_ISERIES),y) + +addSystemMap: addSystemMap.c + $(HOSTCC) $(HOSTCFLAGS) -o addSystemMap addSystemMap.c + +vmlinux.sm: $(TOPDIR)/vmlinux addSystemMap + ./addSystemMap $(TOPDIR)/System.map $(TOPDIR)/vmlinux vmlinux.sm + + +addRamDisk: addRamDisk.c + $(HOSTCC) $(HOSTCFLAGS) -o addRamDisk addRamDisk.c + +vmlinux.initrd: $(TOPDIR)/vmlinux addRamDisk ramdisk.image.gz $(TOPDIR)/System.map + ./addRamDisk ramdisk.image.gz $(TOPDIR)/System.map $(TOPDIR)/vmlinux vmlinux.initrd + +vmlinux.sminitrd: vmlinux.sm addRamDisk ramdisk.image.gz $(TOPDIR)/System.map + ./addRamDisk ramdisk.image.gz $(TOPDIR)/System.map vmlinux.sm vmlinux.sminitrd + +endif + + +znetboot.initrd: zImage.initrd + cp zImage.initrd $(TFTPIMAGE) + +floppy: zImage + mcopy zImage a:zImage + +piggyback: piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + +addnote: addnote.c + $(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c + +image.o: piggyback vmlinux.gz + ./piggyback image < vmlinux.gz | $(BOOTAS) -o image.o + +sysmap.o: piggyback ../../../System.map + ./piggyback sysmap < ../../../System.map | $(BOOTAS) -o sysmap.o + +initrd.o: ramdisk.image.gz piggyback + ./piggyback initrd < ramdisk.image.gz | $(BOOTAS) -o initrd.o + +zImage: $(OBJS) no_initrd.o addnote + $(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) no_initrd.o $(LIBS) + ./addnote $@ + +zImage.initrd: $(OBJS) initrd.o addnote + $(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) initrd.o $(LIBS) + ./addnote $@ + + +vmlinux.gz: $(TOPDIR)/vmlinux + $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + ls -l vmlinux | awk '{printf "/* generated -- do not edit! */\nint uncompressed_size = %d;\n", $$5}' > imagesize.c + $(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "long vmlinux_end = 0x%s;\n", substr($$1,8)}' >> imagesize.c + gzip -vf9 vmlinux + +imagesize.c: vmlinux.gz + +clean: + rm -f piggyback note addnote $(OBJS) zImage zImage.initrd vmlinux.gz no_initrd.o imagesize.c addSystemMap vmlinux.sm addRamDisk vmlinux.initrd vmlinux.sminitrd + +fastdep: + $(TOPDIR)/scripts/mkdep *.[Sch] > .depend + +dep: + $(CPP) $(CPPFLAGS) -M *.S *.c > .depend + diff -urN linux-2.4.18/arch/ppc64/boot/addRamDisk.c linux-2.4.19-pre5/arch/ppc64/boot/addRamDisk.c --- linux-2.4.18/arch/ppc64/boot/addRamDisk.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/addRamDisk.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include + +#define ElfHeaderSize (64 * 1024) +#define ElfPages (ElfHeaderSize / 4096) +#define KERNELBASE (0xc000000000000000) + +void get4k(FILE *file, char *buf ) +{ + unsigned j; + unsigned num = fread(buf, 1, 4096, file); + for ( j=num; j<4096; ++j ) + buf[j] = 0; +} + +void put4k(FILE *file, char *buf ) +{ + fwrite(buf, 1, 4096, file); +} + +void death(const char *msg, FILE *fdesc, const char *fname) +{ + printf(msg); + fclose(fdesc); + unlink(fname); + exit(1); +} + +int main(int argc, char **argv) +{ + char inbuf[4096]; + FILE *ramDisk = NULL; + FILE *sysmap = NULL; + FILE *inputVmlinux = NULL; + FILE *outputVmlinux = NULL; + + unsigned i = 0; + unsigned long ramFileLen = 0; + unsigned long ramLen = 0; + unsigned long roundR = 0; + + unsigned long sysmapFileLen = 0; + unsigned long sysmapLen = 0; + unsigned long sysmapPages = 0; + char* ptr_end = NULL; + unsigned long offset_end = 0; + + unsigned long kernelLen = 0; + unsigned long actualKernelLen = 0; + unsigned long round = 0; + unsigned long roundedKernelLen = 0; + unsigned long ramStartOffs = 0; + unsigned long ramPages = 0; + unsigned long roundedKernelPages = 0; + unsigned long hvReleaseData = 0; + u_int32_t eyeCatcher = 0xc8a5d9c4; + unsigned long naca = 0; + unsigned long xRamDisk = 0; + unsigned long xRamDiskSize = 0; + long padPages = 0; + + + if (argc < 2) { + printf("Name of RAM disk file missing.\n"); + exit(1); + } + + if (argc < 3) { + printf("Name of System Map input file is missing.\n"); + exit(1); + } + + if (argc < 4) { + printf("Name of vmlinux file missing.\n"); + exit(1); + } + + if (argc < 5) { + printf("Name of vmlinux output file missing.\n"); + exit(1); + } + + + ramDisk = fopen(argv[1], "r"); + if ( ! ramDisk ) { + printf("RAM disk file \"%s\" failed to open.\n", argv[1]); + exit(1); + } + + sysmap = fopen(argv[2], "r"); + if ( ! sysmap ) { + printf("System Map file \"%s\" failed to open.\n", argv[2]); + exit(1); + } + + inputVmlinux = fopen(argv[3], "r"); + if ( ! inputVmlinux ) { + printf("vmlinux file \"%s\" failed to open.\n", argv[3]); + exit(1); + } + + outputVmlinux = fopen(argv[4], "w+"); + if ( ! outputVmlinux ) { + printf("output vmlinux file \"%s\" failed to open.\n", argv[4]); + exit(1); + } + + + + /* Input Vmlinux file */ + fseek(inputVmlinux, 0, SEEK_END); + kernelLen = ftell(inputVmlinux); + fseek(inputVmlinux, 0, SEEK_SET); + printf("kernel file size = %d\n", kernelLen); + if ( kernelLen == 0 ) { + printf("You must have a linux kernel specified as argv[3]\n"); + exit(1); + } + + actualKernelLen = kernelLen - ElfHeaderSize; + + printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen); + + round = actualKernelLen % 4096; + roundedKernelLen = actualKernelLen; + if ( round ) + roundedKernelLen += (4096 - round); + printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen, roundedKernelLen); + roundedKernelPages = roundedKernelLen / 4096; + printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages); + + + + /* Input System Map file */ + /* (needs to be processed simply to determine if we need to add pad pages due to the static variables not being included in the vmlinux) */ + fseek(sysmap, 0, SEEK_END); + sysmapFileLen = ftell(sysmap); + fseek(sysmap, 0, SEEK_SET); + printf("%s file size = %ld/0x%lx \n", argv[2], sysmapFileLen, sysmapFileLen); + + sysmapLen = sysmapFileLen; + + roundR = 4096 - (sysmapLen % 4096); + if (roundR) { + printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR); + sysmapLen += roundR; + } + printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen, sysmapLen); + + /* Process the Sysmap file to determine where _end is */ + sysmapPages = sysmapLen / 4096; + for (i=0; i +#include +#include +#include +#include +#include + +void xlate( char * inb, char * trb, unsigned len ) +{ + unsigned i; + for ( i=0; i> 4; + char c2 = c & 0xf; + if ( c1 > 9 ) + c1 = c1 + 'A' - 10; + else + c1 = c1 + '0'; + if ( c2 > 9 ) + c2 = c2 + 'A' - 10; + else + c2 = c2 + '0'; + *trb++ = c1; + *trb++ = c2; + } + *trb = 0; +} + +#define ElfHeaderSize (64 * 1024) +#define ElfPages (ElfHeaderSize / 4096) + +void get4k( /*istream *inf*/FILE *file, char *buf ) +{ + unsigned j; + unsigned num = fread(buf, 1, 4096, file); + for ( j=num; j<4096; ++j ) + buf[j] = 0; +} + +void put4k( /*ostream *outf*/FILE *file, char *buf ) +{ + fwrite(buf, 1, 4096, file); +} + +int main(int argc, char **argv) +{ + char inbuf[4096]; + FILE *sysmap = NULL; + char* ptr_end = NULL; + FILE *inputVmlinux = NULL; + FILE *outputVmlinux = NULL; + long i = 0; + unsigned long sysmapFileLen = 0; + unsigned long sysmapLen = 0; + unsigned long roundR = 0; + unsigned long kernelLen = 0; + unsigned long actualKernelLen = 0; + unsigned long round = 0; + unsigned long roundedKernelLen = 0; + unsigned long sysmapStartOffs = 0; + unsigned long sysmapPages = 0; + unsigned long roundedKernelPages = 0; + long padPages = 0; + if ( argc < 2 ) + { + printf("Name of System Map file missing.\n"); + exit(1); + } + + if ( argc < 3 ) + { + printf("Name of vmlinux file missing.\n"); + exit(1); + } + + if ( argc < 4 ) + { + printf("Name of vmlinux output file missing.\n"); + exit(1); + } + + sysmap = fopen(argv[1], "r"); + if ( ! sysmap ) + { + printf("System Map file \"%s\" failed to open.\n", argv[1]); + exit(1); + } + inputVmlinux = fopen(argv[2], "r"); + if ( ! inputVmlinux ) + { + printf("vmlinux file \"%s\" failed to open.\n", argv[2]); + exit(1); + } + outputVmlinux = fopen(argv[3], "w"); + if ( ! outputVmlinux ) + { + printf("output vmlinux file \"%s\" failed to open.\n", argv[3]); + exit(1); + } + + + + fseek(inputVmlinux, 0, SEEK_END); + kernelLen = ftell(inputVmlinux); + fseek(inputVmlinux, 0, SEEK_SET); + printf("kernel file size = %ld\n", kernelLen); + if ( kernelLen == 0 ) + { + printf("You must have a linux kernel specified as argv[2]\n"); + exit(1); + } + + + actualKernelLen = kernelLen - ElfHeaderSize; + + printf("actual kernel length (minus ELF header) = %ld/%lxx \n", actualKernelLen, actualKernelLen); + + round = actualKernelLen % 4096; + roundedKernelLen = actualKernelLen; + if ( round ) + roundedKernelLen += (4096 - round); + + printf("Kernel length rounded up to a 4k multiple = %ld/%lxx \n", roundedKernelLen, roundedKernelLen); + roundedKernelPages = roundedKernelLen / 4096; + printf("Kernel pages to copy = %ld/%lxx\n", roundedKernelPages, roundedKernelPages); + + + + /* Sysmap file */ + fseek(sysmap, 0, SEEK_END); + sysmapFileLen = ftell(sysmap); + fseek(sysmap, 0, SEEK_SET); + printf("%s file size = %ld\n", argv[1], sysmapFileLen); + + sysmapLen = sysmapFileLen; + + roundR = 4096 - (sysmapLen % 4096); + if (roundR) + { + printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR); + sysmapLen += roundR; + } + printf("Rounded System Map size is %ld\n", sysmapLen); + + /* Process the Sysmap file to determine the true end of the kernel */ + sysmapPages = sysmapLen / 4096; + printf("System map pages to copy = %ld\n", sysmapPages); + for (i=0; i +#include +#include +#include + +char arch[] = "PowerPC"; + +#define N_DESCR 6 +unsigned int descr[N_DESCR] = { + 0xffffffff, /* real-mode = true */ + 0x00c00000, /* real-base, i.e. where we expect OF to be */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x4000, /* load-base */ +}; + +unsigned char buf[512]; + +#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) +#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) + +#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ + PUT_16BE((off) + 2, (v))) + +/* Structure of an ELF file */ +#define E_IDENT 0 /* ELF header */ +#define E_PHOFF 28 +#define E_PHENTSIZE 42 +#define E_PHNUM 44 +#define E_HSIZE 52 /* size of ELF header */ + +#define EI_MAGIC 0 /* offsets in E_IDENT area */ +#define EI_CLASS 4 +#define EI_DATA 5 + +#define PH_TYPE 0 /* ELF program header */ +#define PH_OFFSET 4 +#define PH_FILESZ 16 +#define PH_HSIZE 32 /* size of program header */ + +#define PT_NOTE 4 /* Program header type = note */ + +#define ELFCLASS32 1 +#define ELFDATA2MSB 2 + +unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; + +int +main(int ac, char **av) +{ + int fd, n, i; + int ph, ps, np; + int nnote, ns; + + if (ac != 2) { + fprintf(stderr, "Usage: %s elf-file\n", av[0]); + exit(1); + } + fd = open(av[1], O_RDWR); + if (fd < 0) { + perror(av[1]); + exit(1); + } + + nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; + + n = read(fd, buf, sizeof(buf)); + if (n < 0) { + perror("read"); + exit(1); + } + + if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) + goto notelf; + + if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 + || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { + fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", + av[1]); + exit(1); + } + + ph = GET_32BE(E_PHOFF); + ps = GET_16BE(E_PHENTSIZE); + np = GET_16BE(E_PHNUM); + if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) + goto notelf; + if (ph + (np + 1) * ps + nnote > n) + goto nospace; + + for (i = 0; i < np; ++i) { + if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { + fprintf(stderr, "%s already has a note entry\n", + av[1]); + exit(0); + } + ph += ps; + } + + /* XXX check that the area we want to use is all zeroes */ + for (i = 0; i < ps + nnote; ++i) + if (buf[ph + i] != 0) + goto nospace; + + /* fill in the program header entry */ + ns = ph + ps; + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote); + + /* fill in the note area we point to */ + /* XXX we should probably make this a proper section */ + PUT_32BE(ns, strlen(arch) + 1); + PUT_32BE(ns + 4, N_DESCR * 4); + PUT_32BE(ns + 8, 0x1275); + strcpy(&buf[ns + 12], arch); + ns += 12 + strlen(arch) + 1; + for (i = 0; i < N_DESCR; ++i) + PUT_32BE(ns + i * 4, descr[i]); + + /* Update the number of program headers */ + PUT_16BE(E_PHNUM, np + 1); + + /* write back */ + lseek(fd, (long) 0, SEEK_SET); + i = write(fd, buf, n); + if (i < 0) { + perror("write"); + exit(1); + } + if (i < n) { + fprintf(stderr, "%s: write truncated\n", av[1]); + exit(1); + } + + exit(0); + + notelf: + fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); + exit(1); + + nospace: + fprintf(stderr, "sorry, I can't find space in %s to put the note\n", + av[0]); + exit(1); +} diff -urN linux-2.4.18/arch/ppc64/boot/crt0.S linux-2.4.19-pre5/arch/ppc64/boot/crt0.S --- linux-2.4.18/arch/ppc64/boot/crt0.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/crt0.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,265 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + * + * NOTE: this code runs in 32 bit mode and is packaged as ELF32. + */ + .text + .globl _start +_start: + lis 9,_start@h + lis 8,_etext@ha + addi 8,8,_etext@l +1: dcbf 0,9 + icbi 0,9 + addi 9,9,0x20 + cmplwi 0,9,8 + blt 1b + sync + isync + + ## Clear out the BSS as per ANSI C requirements + + lis 7,_end@ha + addi 7,7,_end@l # r7 = &_end + lis 8,__bss_start@ha # + addi 8,8,__bss_start@l # r8 = &_bss_start + + ## Determine how large an area, in number of words, to clear + + subf 7,8,7 # r7 = &_end - &_bss_start + 1 + addi 7,7,3 # r7 += 3 + srwi. 7,7,2 # r7 = size in words. + beq 3f # If the size is zero, do not bother + addi 8,8,-4 # r8 -= 4 + mtctr 7 # SPRN_CTR = number of words to clear + li 0,0 # r0 = 0 +2: stwu 0,4(8) # Clear out a word + bdnz 2b # If we are not done yet, keep clearing +3: + + + b start + + + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr + + +#define r0 0 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 + + .globl strcpy +strcpy: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strncpy +strncpy: + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + blr + + .globl strcat +strcat: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strcmp +strcmp: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + + .globl strlen +strlen: + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + + .globl memset +memset: + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + rlwinm r0,r5,32-2,2,31 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + + .globl bcopy +bcopy: + mr r6,r3 + mr r3,r4 + mr r4,r6 + b memcpy + + .globl memmove +memmove: + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + + .globl memcpy +memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl backwards_memcpy +backwards_memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl memcmp +memcmp: + cmpwi 0,r5,0 + blelr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr diff -urN linux-2.4.18/arch/ppc64/boot/main.c linux-2.4.19-pre5/arch/ppc64/boot/main.c --- linux-2.4.18/arch/ppc64/boot/main.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/main.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,292 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * Updates for PPC64 by Todd Inglett & Dave Engebretsen. + * + * 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. + */ +#define __KERNEL__ +#include "zlib.h" +#include +#include +#include + +void memmove(void *dst, void *im, int len); + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern void printf(const char *fmt, ...); +extern int sprintf(char *buf, const char *fmt, ...); +void gunzip(void *, int, unsigned char *, int *); +void *claim(unsigned int, unsigned int, unsigned int); +void flush_cache(void *, int); +void pause(void); +static struct bi_record *make_bi_recs(unsigned long); + +#define RAM_START 0x00000000 +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)_end) + +/* Value picked to match that used by yaboot */ +#define PROG_START 0x01400000 + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; +unsigned long initrd_start = 0; +unsigned long initrd_size = 0; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; +extern char sysmap_data[]; +extern int sysmap_len; +extern int uncompressed_size; +extern long vmlinux_end; + +static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ + +typedef void (*kernel_entry_t)( unsigned long, + unsigned long, + void *, + struct bi_record *); + +void +chrpboot(unsigned long a1, unsigned long a2, void *prom) +{ + unsigned len; + void *dst = (void *)-1; + unsigned long claim_addr; + unsigned char *im; + extern char _start; + struct bi_record *bi_recs; + kernel_entry_t kernel_entry; + + printf("chrpboot starting: loaded at 0x%x\n\r", (unsigned)&_start); + + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = a2 = 0; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", + initrd_start, (unsigned long)initrd_data, initrd_size); + memcpy((void *)initrd_start, (void *)initrd_data, initrd_size); + } + + im = image_data; + len = image_len; + uncompressed_size = PAGE_ALIGN(uncompressed_size); + + for(claim_addr = PROG_START; + claim_addr <= PROG_START * 8; + claim_addr += 0x100000) { + printf(" trying: 0x%08lx\n\r", claim_addr); + dst = claim(claim_addr, uncompressed_size, 0); + if (dst != (void *)-1) break; + } + if (dst == (void *)-1) { + printf("claim error, can't allocate kernel memory\n\r"); + return; + } + + if (im[0] == 0x1f && im[1] == 0x8b) { + avail_ram = scratch; + begin_avail = avail_high = avail_ram; + end_avail = scratch + sizeof(scratch); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", + (unsigned)dst, (unsigned)im, (unsigned)im+len); + gunzip(dst, uncompressed_size, im, &len); + printf("done %u bytes\n\r", len); + printf("%u bytes of heap consumed, max in use %u\n\r", + (unsigned)(avail_high - begin_avail), heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + + bi_recs = make_bi_recs((unsigned long)dst + vmlinux_end); + + kernel_entry = (kernel_entry_t)dst; + printf( "kernel:\n\r" + " entry addr = 0x%lx\n\r" + " a1 = 0x%lx,\n\r" + " a2 = 0x%lx,\n\r" + " prom = 0x%lx,\n\r" + " bi_recs = 0x%lx,\n\r", + (unsigned long)kernel_entry, a1, a2, + (unsigned long)prom, (unsigned long)bi_recs); + + kernel_entry( a1, a2, prom, bi_recs ); + + printf("returned?\n\r"); + + pause(); +} + +static struct bi_record * +make_bi_recs(unsigned long addr) +{ + struct bi_record *bi_recs; + struct bi_record *rec; + + bi_recs = rec = bi_rec_init(addr); + + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_FIRST; + /* rec->data[0] = ...; # Written below before return */ + /* rec->data[1] = ...; # Written below before return */ + + rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1); + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "chrpboot"); + + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_pSeries; + rec->data[1] = 1; + + if ( initrd_size > 0 ) { + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_INITRD; + rec->data[0] = initrd_start; + rec->data[1] = initrd_size; + } + +#if 0 + if ( sysmap_len > 0 ) { + rec = bi_rec_alloc(rec, 2); + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)sysmap_data; + rec->data[1] = sysmap_len; + } +#endif + + rec = bi_rec_alloc(rec, 1); + rec->tag = BI_LAST; + rec->data[0] = (bi_rec_field)bi_recs; + + /* Save the _end_ address of the bi_rec's in the first bi_rec + * data field for easy access by the kernel. + */ + bi_recs->data[0] = (bi_rec_field)rec; + bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs; + + return bi_recs; +} + +struct memchunk { + unsigned int size; + unsigned int pad; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size *= items; + size = _ALIGN(size, sizeof(struct memchunk)); + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n\r"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + struct memchunk *mp = addr; + + nb = _ALIGN(nb, sizeof(struct memchunk)); + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} + diff -urN linux-2.4.18/arch/ppc64/boot/mknote.c linux-2.4.19-pre5/arch/ppc64/boot/mknote.c --- linux-2.4.18/arch/ppc64/boot/mknote.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/mknote.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,43 @@ +/* + * Copyright (C) Cort Dougan 1999. + * + * 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. + * + * Generate a note section as per the CHRP specification. + * + */ + +#include + +#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); + +int main(void) +{ +/* header */ + /* namesz */ + PL(strlen("PowerPC")+1); + /* descrsz */ + PL(6*4); + /* type */ + PL(0x1275); + /* name */ + printf("PowerPC"); printf("%c", 0); + +/* descriptor */ + /* real-mode */ + PL(0xffffffff); + /* real-base */ + PL(0x00c00000); + /* real-size */ + PL(0xffffffff); + /* virt-base */ + PL(0xffffffff); + /* virt-size */ + PL(0xffffffff); + /* load-base */ + PL(0x4000); + return 0; +} diff -urN linux-2.4.18/arch/ppc64/boot/no_initrd.c linux-2.4.19-pre5/arch/ppc64/boot/no_initrd.c --- linux-2.4.18/arch/ppc64/boot/no_initrd.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/no_initrd.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2 @@ +char initrd_data[1]; +int initrd_len = 0; diff -urN linux-2.4.18/arch/ppc64/boot/piggyback.c linux-2.4.19-pre5/arch/ppc64/boot/piggyback.c --- linux-2.4.18/arch/ppc64/boot/piggyback.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/piggyback.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,74 @@ +/* + * Copyright 2001 IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include + +extern long ce_exec_config[]; + +int main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 2) + { + fprintf(stderr, "usage: %s name out-file\n", + argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl %s_data\n", argv[1]); + fprintf(stdout, "%s_data:\n", argv[1]); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl %s_len\n", argv[1]); + fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -urN linux-2.4.18/arch/ppc64/boot/start.c linux-2.4.19-pre5/arch/ppc64/boot/start.c --- linux-2.4.18/arch/ppc64/boot/start.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/start.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,654 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include + +#include + +int (*prom)(void *); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + +void exit(void); +void *finddevice(const char *name); +int getprop(void *phandle, const char *name, void *buf, int buflen); +void chrpboot(int a1, int a2, void *prom); /* in main.c */ + +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + prom = (int (*)(void *)) promptr; + chosen_handle = finddevice("/chosen"); + if (chosen_handle == (void *) -1) + exit(); + if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) + exit(); + stderr = stdout; + if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) + exit(); + + chrpboot(a1, a2, promptr); + for (;;) + exit(); +} + +int +write(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +int +read(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +void +exit() +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom)(&args); + } +} + +void +pause(void) +{ + struct prom_args { + char *service; + } args; + + args.service = "enter"; + (*prom)(&args); +} + +void * +finddevice(const char *name) +{ + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + void *phandle; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.phandle = (void *) -1; + (*prom)(&args); + return args.phandle; +} + +void * +claim(unsigned long virt, unsigned long size, unsigned long align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +int +getprop(void *phandle, const char *name, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *phandle; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.phandle = phandle; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*prom)(&args); + return args.size; +} + +int +putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + putc('\r', f); + return write(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return write(f, str, n) == n? 0: -1; +} + +int +readchar(void) +{ + char ch; + + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\r\n"); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int +getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + + + +/* String functions lifted from lib/vsprintf.c and lib/ctype.c */ +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +static char * number(char * str, long long num, int base, int size, int precision, int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z') { + num = va_arg(args, size_t); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + write(stdout, sprint_buf, n); + return n; +} diff -urN linux-2.4.18/arch/ppc64/boot/zImage.lds linux-2.4.19-pre5/arch/ppc64/boot/zImage.lds --- linux-2.4.18/arch/ppc64/boot/zImage.lds Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/zImage.lds Sat Mar 30 22:55:39 2002 @@ -0,0 +1,78 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .plt : { *(.plt) } + .text : + { + *(.text) + *(.fixup) + *(.got1) + } + . = ALIGN(4096); + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .kstrtab : { *(.kstrtab) } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + /* Read-write section, merged into data segment: */ + . = ALIGN(4096); + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + . = ALIGN(4096); + _edata = .; + PROVIDE (edata = .); + + .fixup : { *(.fixup) } + + . = ALIGN(4096); + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(4096); + _end = . ; + PROVIDE (end = .); +} diff -urN linux-2.4.18/arch/ppc64/boot/zlib.c linux-2.4.19-pre5/arch/ppc64/boot/zlib.c --- linux-2.4.18/arch/ppc64/boot/zlib.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/zlib.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2170 @@ +/* + * This file is derived from various .h and .c files from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - changed functions not used outside this file to "local" + * - added minCompression parameter to deflateInit2 + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp + * + Copyright (C) 1995 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + + * + * + */ + +/*+++++*/ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ + +#define _Z_UTIL_H + +#include "zlib.h" + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define FAR + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern char *z_errmsg[]; /* indexed by 1-zlib_error */ + +#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) +/* To be used only when the state is known to be valid */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + + /* common constants */ + +#define DEFLATED 8 + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + + /* functions */ + +#include +#define zmemcpy memcpy +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); + +/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ +/* void zcfree OF((voidpf opaque, voidpf ptr)); */ + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr, size) \ + (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) +#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} + +/* deflate.h -- internal compression state + * Copyright (C) 1995 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/*+++++*/ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +local inflate_blocks_statef * inflate_blocks_new OF(( + z_stream *z, + check_func c, /* check function */ + uInt w)); /* window size */ + +local int inflate_blocks OF(( + inflate_blocks_statef *, + z_stream *, + int)); /* initial return code */ + +local void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_stream *, + uLongf *)); /* check value on output */ + +local int inflate_addhistory OF(( + inflate_blocks_statef *, + z_stream *)); + +local int inflate_packet_flush OF(( + inflate_blocks_statef *)); + +/*+++++*/ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt Nalloc; /* number of these allocated here */ + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + local uInt inflate_hufts; +#endif + +local int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_stream *)); /* for zalloc, zfree functions */ + +local int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +local int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_stream *)); /* for zfree function */ + + +/*+++++*/ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +local inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_stream *)); + +local int inflate_codes OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +local void inflate_codes_free OF(( + inflate_codes_statef *, + z_stream *)); + + +/*+++++*/ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z) +z_stream *z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state, sizeof(struct internal_state)); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2(z, w) +z_stream *z; +int w; +{ + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; +/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ +/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit(z) +z_stream *z; +{ + return inflateInit2(z, DEF_WBITS); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z, f) +z_stream *z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) + { + z->state->mode = BAD; + z->msg = "unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = "invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + if ((b = NEXTBYTE) & 0x20) + { + z->state->mode = BAD; + z->msg = "invalid reserved bit"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = "incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + z->state->mode = BLOCKS; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = "incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z) +z_stream *z; +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z) +z_stream *z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE + +/*+++++*/ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ + mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + int nblens; /* # elements allocated at blens */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl, *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* + * The IBM 150 firmware munges the data right after _etext[]. This + * protects it. -- Cort + */ +local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0}; +/* And'ing with mask[n] masks the lower n bits */ +local uInt inflate_mask[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush OF(( + inflate_blocks_statef *, + z_stream *, + int)); + +/*+++++*/ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_stream *)); + + +/*+++++*/ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* Table for deflate from PKZIP's appnote.txt. */ +local uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +local void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +local inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_stream *z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +local int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = "invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if (((~b) >> 16) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : TYPE; + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.trees.nblens = t; + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + s->mode = BADB; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + s->mode = BADB; + z->msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BADB; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_stream *z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window, s->end - s->window); + ZFREE(z, s, sizeof(struct inflate_blocks_state)); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +local int inflate_addhistory(s, z) +inflate_blocks_statef *s; +z_stream *z; +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WRAP */ /* expand WRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +local int inflate_packet_flush(s) + inflate_blocks_statef *s; +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} + + +/*+++++*/ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + uIntf *, /* list of base values for non-simple codes */ + uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_stream *)); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +local void ffree OF(( + voidpf q, /* opaque pointer (not used) */ + voidpf p, /* what to free (not used) */ + uInt n)); /* number of bytes (not used) */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* actually lengths - 2; also see note #13 above about 258 */ +local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ +local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local uInt cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +uIntf *d; /* list of base values for non-simple codes */ +uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_stream *zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (all zero length codes or an + over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } + q->word.Nalloc = z + 1; +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +local int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tb, z); + z->msg = "incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_stream *z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) + { + if (r == Z_DATA_ERROR) + z->msg = "oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = "incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_lock = 0; +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local uInt fixed_left = FIXEDH; +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer (not used) */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= fixed_left, + "inflate_trees falloc overflow"); + if (q) s++; /* to make some compilers happy */ + fixed_left -= n; + return (voidpf)(fixed_mem + fixed_left); +} + + +local void ffree(q, p, n) +voidpf q; +voidpf p; +uInt n; +{ + Assert(0, "inflate_trees ffree called!"); + if (q) q = p; /* to make some compilers happy */ +} + + +local int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not built already--lock out other instances */ + while (++fixed_lock > 1) + fixed_lock--; + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = ffree; + z.opaque = Z_NULL; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + fixed_built = 1; + } + fixed_lock--; + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +local int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_stream *z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); + p = q; + } + return Z_OK; +} + +/*+++++*/ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl, *td; +z_stream *z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +local int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = "invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +local void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_stream *z; +{ + ZFREE(z, c, sizeof(struct inflate_codes_state)); + Tracev((stderr, "inflate: codes free\n")); +} + +/*+++++*/ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* copy as much as possible from the sliding window to the output area */ +local int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_stream *z; +int r; +{ + uInt n; + Bytef *p, *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + + +/*+++++*/ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +local int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl, *td; +inflate_blocks_statef *s; +z_stream *z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = "invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = "invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + + +/*+++++*/ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ + +char *zlib_version = ZLIB_VERSION; + +char *z_errmsg[] = { +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +""}; + + +/*+++++*/ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf) {s1 += *buf++; s2 += s1;} +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); +#define DO16(buf) DO8(buf); DO8(buf); + +/* ========================================================================= */ +uLong adler32(adler, buf, len) + uLong adler; + Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + k -= 16; + } + if (k != 0) do { + DO1(buf); + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff -urN linux-2.4.18/arch/ppc64/boot/zlib.h linux-2.4.19-pre5/arch/ppc64/boot/zlib.h --- linux-2.4.18/arch/ppc64/boot/zlib.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/boot/zlib.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,432 @@ +/* */ + +/* + * This file is derived from zlib.h and zconf.h from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. + */ + +/* + * ==FILEVERSION 960122== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 0.95, Aug 16th, 1995. + + Copyright (C) 1995 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + */ + +#ifndef _ZLIB_H +#define _ZLIB_H + +/* #include "zconf.h" */ /* included directly here */ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ + +/* + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. + */ + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints + * at addresses which are not a multiple of their size. + * Under DOS, -DFAR=far or -DFAR=__far may be needed. + */ + +#ifndef STDC +# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) +# define STDC +# endif +#endif + +#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ +# include +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +#ifndef FAR +# define FAR +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef Byte FAR Bytef; +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +/* end of original zconf.h */ + +#define ZLIB_VERSION "0.95P" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidp opaque; /* private data object passed to zalloc and zfree */ + + Byte data_type; /* best guess about the data type: ascii or binary */ + +} z_stream; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_FULL_FLUSH 2 +#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ +#define Z_FINISH 4 +#define Z_PACKET_FLUSH 5 +/* See deflate() below for the usage of these constants */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +/* error codes for the compression/decompression functions */ + +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Used to set the data_type field */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +extern char *zlib_version; +/* The application can compare zlib_version and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + */ + + /* basic functions */ + +extern int inflateInit OF((z_stream *strm)); +/* + Initializes the internal stream state for decompression. The fields + zalloc and zfree must be initialized before by the caller. If zalloc and + zfree are set to Z_NULL, inflateInit updates them to use default allocation + functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory. msg is set to null if there is no error message. + inflateInit does not perform any decompression: this will be done by + inflate(). +*/ + + +extern int inflate OF((z_stream *strm, int flush)); +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() always provides as much output as possible + (until there is no more input data or no more space in the output buffer). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). + + If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, + inflate flushes as much output as possible to the output buffer. The + flushing behavior of inflate is not specified for values of the flush + parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the + current implementation actually flushes as much output as possible + anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data + has been consumed, it is expecting to see the length field of a stored + block; if not, it returns Z_DATA_ERROR. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if + the stream structure was inconsistent (for example if next_in or next_out + was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no + progress is possible or if there was not enough room in the output buffer + when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then + call inflateSync to look for a good compression block. */ + + +extern int inflateEnd OF((z_stream *strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* advanced functions */ + +extern int inflateInit2 OF((z_stream *strm, + int windowBits)); +/* + This is another version of inflateInit with more compression options. The + fields next_out, zalloc and zfree must be initialized before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1< +#include +#include +#include +#include +#include +#include +#ifndef _HVCALLSC_H +#include +#endif +#include + +#ifndef _HVTYPES_H +#include +#endif + + +/*===================================================================== + * Note that this call takes at MOST one page worth of data + */ +int HvCall_readLogBuffer(HvLpIndex lpIndex, void *buffer, u64 bufLen) +{ + struct HvLpBufferList *bufList; + u64 bytesLeft = bufLen; + u64 leftThisPage; + u64 curPtr = virt_to_absolute( (unsigned long) buffer ); + u64 retVal; + int npages; + int i; + + npages = 0; + while (bytesLeft) { + npages++; + leftThisPage = ((curPtr & PAGE_MASK) + PAGE_SIZE) - curPtr; + + if (leftThisPage > bytesLeft) + bytesLeft = 0; + else + bytesLeft -= leftThisPage; + + curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE; + } + + if (npages == 0) + return 0; + + bufList = (struct HvLpBufferList *) + kmalloc(npages * sizeof(struct HvLpBufferList), GFP_ATOMIC); + bytesLeft = bufLen; + curPtr = virt_to_absolute( (unsigned long) buffer ); + for(i=0; i bytesLeft) { + bufList[i].len = bytesLeft; + bytesLeft = 0; + } else { + bufList[i].len = leftThisPage; + bytesLeft -= leftThisPage; + } + + curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE; + } + + + retVal = HvCall3(HvCallBaseReadLogBuffer, lpIndex, + virt_to_absolute((unsigned long)bufList), bufLen); + + kfree(bufList); + + return (int)retVal; +} + +/*===================================================================== + */ +void HvCall_writeLogBuffer(const void *buffer, u64 bufLen) +{ + struct HvLpBufferList bufList; + u64 bytesLeft = bufLen; + u64 leftThisPage; + u64 curPtr = virt_to_absolute( (unsigned long) buffer ); + + while (bytesLeft) { + bufList.addr = curPtr; + + leftThisPage = ((curPtr & PAGE_MASK) + PAGE_SIZE) - curPtr; + + if (leftThisPage > bytesLeft) { + bufList.len = bytesLeft; + bytesLeft = 0; + } else { + bufList.len = leftThisPage; + bytesLeft -= leftThisPage; + } + + curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE; + } + + + HvCall2(HvCallBaseWriteLogBuffer, + virt_to_absolute((unsigned long)&bufList), bufLen); + +} diff -urN linux-2.4.18/arch/ppc64/kernel/HvLpConfig.c linux-2.4.19-pre5/arch/ppc64/kernel/HvLpConfig.c --- linux-2.4.18/arch/ppc64/kernel/HvLpConfig.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/HvLpConfig.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,28 @@ +/* + * HvLpConfig.c + * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _HVLPCONFIG_H +#include +#endif + +HvLpIndex HvLpConfig_getLpIndex_outline(void) +{ + return HvLpConfig_getLpIndex(); +} + diff -urN linux-2.4.18/arch/ppc64/kernel/HvLpEvent.c linux-2.4.19-pre5/arch/ppc64/kernel/HvLpEvent.c --- linux-2.4.18/arch/ppc64/kernel/HvLpEvent.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/HvLpEvent.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,77 @@ +/* + * Copyright 2001 Mike Corrigan IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +/* Array of LpEvent handler functions */ +LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; + +/* Register a handler for an LpEvent type */ + +int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler ) +{ + int rc = 1; + if ( eventType < HvLpEvent_Type_NumTypes ) { + lpEventHandler[eventType] = handler; + rc = 0; + } + return rc; + +} + +int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ) +{ + int rc = 1; + if ( eventType < HvLpEvent_Type_NumTypes ) { + if ( !lpEventHandlerPaths[eventType] ) { + lpEventHandler[eventType] = NULL; + rc = 0; + } + } + return rc; +} + +/* (lpIndex is the partition index of the target partition. + * needed only for VirtualIo, VirtualLan and SessionMgr. Zero + * indicates to use our partition index - for the other types) + */ +int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) +{ + int rc = 1; + if ( eventType < HvLpEvent_Type_NumTypes && + lpEventHandler[eventType] ) { + if ( lpIndex == 0 ) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_openLpEventPath( lpIndex, eventType ); + ++lpEventHandlerPaths[eventType]; + rc = 0; + } + return rc; +} + +int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) +{ + int rc = 1; + if ( eventType < HvLpEvent_Type_NumTypes && + lpEventHandler[eventType] && + lpEventHandlerPaths[eventType] ) { + if ( lpIndex == 0 ) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_closeLpEventPath( lpIndex, eventType ); + --lpEventHandlerPaths[eventType]; + rc = 0; + } + return rc; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/ItLpQueue.c linux-2.4.19-pre5/arch/ppc64/kernel/ItLpQueue.c --- linux-2.4.18/arch/ppc64/kernel/ItLpQueue.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ItLpQueue.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,170 @@ +/* + * ItLpQueue.c + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __inline__ int set_inUse( struct ItLpQueue * lpQueue ) +{ + int t; + u32 * inUseP = &(lpQueue->xInUseWord); + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%2 \n\ + cmpi 0,%0,0 \n\ + li %0,0 \n\ + bne- 2f \n\ + addi %0,%0,1 \n\ + stwcx. %0,0,%2 \n\ + bne- 1b \n\ +2: eieio" + : "=&r" (t), "=m" (lpQueue->xInUseWord) + : "r" (inUseP), "m" (lpQueue->xInUseWord) + : "cc"); + + return t; +} + +static __inline__ void clear_inUse( struct ItLpQueue * lpQueue ) +{ + lpQueue->xInUseWord = 0; +} + +/* Array of LpEvent handler functions */ +extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +unsigned long ItLpQueueInProcess = 0; + +struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue ) +{ + struct HvLpEvent * nextLpEvent = + (struct HvLpEvent *)lpQueue->xSlicCurEventPtr; + if ( nextLpEvent->xFlags.xValid ) { + /* rmb() needed only for weakly consistent machines (regatta) */ + rmb(); + /* Set pointer to next potential event */ + lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 + + LpEventAlign ) / + LpEventAlign ) * + LpEventAlign; + /* Wrap to beginning if no room at end */ + if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr) + lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr; + } + else + nextLpEvent = NULL; + + return nextLpEvent; +} + +int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue ) +{ + int retval = 0; + struct HvLpEvent * nextLpEvent; + if ( lpQueue ) { + nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr; + retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending; + } + return retval; +} + +void ItLpQueue_clearValid( struct HvLpEvent * event ) +{ + /* Clear the valid bit of the event + * Also clear bits within this event that might + * look like valid bits (on 64-byte boundaries) + */ + unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) / + LpEventAlign ) - 1; + switch ( extra ) { + case 3: + ((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0; + case 2: + ((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0; + case 1: + ((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0; + case 0: + ; + } + mb(); + event->xFlags.xValid = 0; +} + +unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs ) +{ + unsigned numIntsProcessed = 0; + struct HvLpEvent * nextLpEvent; + + /* If we have recursed, just return */ + if ( !set_inUse( lpQueue ) ) + return 0; + + if (ItLpQueueInProcess == 0) + ItLpQueueInProcess = 1; + else + BUG(); + + for (;;) { + nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue ); + if ( nextLpEvent ) { + /* Count events to return to caller + * and count processed events in lpQueue + */ + ++numIntsProcessed; + lpQueue->xLpIntCount++; + /* Call appropriate handler here, passing + * a pointer to the LpEvent. The handler + * must make a copy of the LpEvent if it + * needs it in a bottom half. (perhaps for + * an ACK) + * + * Handlers are responsible for ACK processing + * + * The Hypervisor guarantees that LpEvents will + * only be delivered with types that we have + * registered for, so no type check is necessary + * here! + */ + if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes ) + lpQueue->xLpIntCountByType[nextLpEvent->xType]++; + if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes && + lpEventHandler[nextLpEvent->xType] ) + lpEventHandler[nextLpEvent->xType](nextLpEvent, regs); + else + printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType ); + + ItLpQueue_clearValid( nextLpEvent ); + } + else /* No more valid events + * If overflow events are pending + * process them + */ + if ( lpQueue->xPlicOverflowIntPending ) { + HvCallEvent_getOverflowLpEvents( + lpQueue->xIndex); + } + else /* If nothing left then we are done */ + break; + } + + ItLpQueueInProcess = 0; + mb(); + clear_inUse( lpQueue ); + + get_paca()->lpEvent_count += numIntsProcessed; + + return numIntsProcessed; +} diff -urN linux-2.4.18/arch/ppc64/kernel/LparData.c linux-2.4.19-pre5/arch/ppc64/kernel/LparData.c --- linux-2.4.18/arch/ppc64/kernel/LparData.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/LparData.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,252 @@ +/* + * Copyright 2001 Mike Corrigan, IBM Corp + * + * 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. + */ +#define __KERNEL__ 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char _start_boltedStacks[]; + +/* The LparMap data is now located at offset 0x6000 in head.S + * It was put there so that the HvReleaseData could address it + * with a 32-bit offset as required by the iSeries hypervisor + * + * The Naca has a pointer to the ItVpdAreas. The hypervisor finds + * the Naca via the HvReleaseData area. The HvReleaseData has the + * offset into the Naca of the pointer to the ItVpdAreas. + */ + +extern struct ItVpdAreas itVpdAreas; + +/* The LpQueue is used to pass event data from the hypervisor to + * the partition. This is where I/O interrupt events are communicated. + * The ItLpQueue must be initialized (even though only to all zeros) + * If it were uninitialized (in .bss) it would get zeroed after the + * kernel gets control. The hypervisor will have filled in some fields + * before the kernel gets control. By initializing it we keep it out + * of the .bss + */ + +struct ItLpQueue xItLpQueue = {}; + + +/* The HvReleaseData is the root of the information shared between + * the hypervisor and Linux. + */ + +struct HvReleaseData hvReleaseData = { + 0xc8a5d9c4, /* desc = "HvRD" ebcdic */ + sizeof(struct HvReleaseData), + offsetof(struct Naca, xItVpdAreas), + (struct Naca *)(KERNELBASE+0x4000), /* 64-bit Naca address */ + 0x6000, /* offset of LparMap within loadarea (see head.S) */ + 0, + 1, /* tags inactive */ + 0, /* 64 bit */ + 0, /* shared processors */ + 0, /* HMT allowed */ + 6, /* TEMP: This allows non-GA driver */ + 4, /* We are v5r2m0 */ + 3, /* Min supported PLIC = v5r1m0 */ + 3, /* Min usuable PLIC = v5r1m0 */ + { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4 "*/ + 0xa7, 0x40, 0xf2, 0x4b, + 0xf4, 0x4b, 0xf6, 0xf4 }, + {0} +}; + +extern void SystemReset_Iseries(void); +extern void MachineCheck_Iseries(void); +extern void DataAccess_Iseries(void); +extern void InstructionAccess_Iseries(void); +extern void HardwareInterrupt_Iseries(void); +extern void Alignment_Iseries(void); +extern void ProgramCheck_Iseries(void); +extern void FPUnavailable_Iseries(void); +extern void Decrementer_Iseries(void); +extern void Trap_0a_Iseries(void); +extern void Trap_0b_Iseries(void); +extern void SystemCall_Iseries(void); +extern void SingleStep_Iseries(void); +extern void Trap_0e_Iseries(void); +extern void PerformanceMonitor_Iseries(void); +extern void DataAccessSLB_Iseries(void); +extern void InstructionAccessSLB_Iseries(void); + +struct ItLpNaca itLpNaca = { + 0xd397d581, /* desc = "LpNa" ebcdic */ + 0x0400, /* size of ItLpNaca */ + 0x0300, 19, /* offset to int array, # ents */ + 0, 0, 0, /* Part # of primary, serv, me */ + 0, 0x100, /* # of LP queues, offset */ + 0, 0, 0, /* Piranha stuff */ + { 0,0,0,0,0 }, /* reserved */ + 0,0,0,0,0,0,0, /* stuff */ + { 0,0,0,0,0 }, /* reserved */ + 0, /* reserved */ + 0, /* VRM index of PLIC */ + 0, 0, /* min supported, compat SLIC */ + 0, /* 64-bit addr of load area */ + 0, /* chunks for load area */ + 0, 0, /* PASE mask, seg table */ + { 0 }, /* 64 reserved bytes */ + { 0 }, /* 128 reserved bytes */ + { 0 }, /* Old LP Queue */ + { 0 }, /* 384 reserved bytes */ + { + (u64)SystemReset_Iseries, /* 0x100 System Reset */ + (u64)MachineCheck_Iseries, /* 0x200 Machine Check */ + (u64)DataAccess_Iseries, /* 0x300 Data Access */ + (u64)InstructionAccess_Iseries, /* 0x400 Instruction Access */ + (u64)HardwareInterrupt_Iseries, /* 0x500 External */ + (u64)Alignment_Iseries, /* 0x600 Alignment */ + (u64)ProgramCheck_Iseries, /* 0x700 Program Check */ + (u64)FPUnavailable_Iseries, /* 0x800 FP Unavailable */ + (u64)Decrementer_Iseries, /* 0x900 Decrementer */ + (u64)Trap_0a_Iseries, /* 0xa00 Trap 0A */ + (u64)Trap_0b_Iseries, /* 0xb00 Trap 0B */ + (u64)SystemCall_Iseries, /* 0xc00 System Call */ + (u64)SingleStep_Iseries, /* 0xd00 Single Step */ + (u64)Trap_0e_Iseries, /* 0xe00 Trap 0E */ + (u64)PerformanceMonitor_Iseries,/* 0xf00 Performance Monitor */ + 0, /* int 0x1000 */ + 0, /* int 0x1010 */ + 0, /* int 0x1020 CPU ctls */ + (u64)HardwareInterrupt_Iseries, /* SC Ret Hdlr */ + (u64)DataAccessSLB_Iseries, /* 0x380 D-SLB */ + (u64)InstructionAccessSLB_Iseries /* 0x480 I-SLB */ + } +}; + +struct ItIplParmsReal xItIplParmsReal = {}; + +struct IoHriProcessorVpd xIoHriProcessorVpd[maxProcessors] = { + { + xInstCacheOperandSize: 32, + xDataCacheOperandSize: 32, + xProcFreq: 50000000, + xTimeBaseFreq: 50000000, + xPVR: 0x3600 + } +}; + + +u64 xMsVpd[3400] = {}; /* Space for Main Store Vpd 27,200 bytes */ + +u64 xRecoveryLogBuffer[32] = {}; /* Space for Recovery Log Buffer */ + +struct SpCommArea xSpCommArea = { + 0xE2D7C3C2, + 1, + {0}, + 0, 0, 0, 0, {0} +}; + +struct ItVpdAreas itVpdAreas = { + 0xc9a3e5c1, /* "ItVA" */ + sizeof( struct ItVpdAreas ), + 0, 0, + 26, /* # VPD array entries */ + 10, /* # DMA array entries */ + maxProcessors*2, maxProcessors, /* Max logical, physical procs */ + offsetof(struct ItVpdAreas,xPlicDmaToks),/* offset to DMA toks */ + offsetof(struct ItVpdAreas,xSlicVpdAdrs),/* offset to VPD addrs */ + offsetof(struct ItVpdAreas,xPlicDmaLens),/* offset to DMA lens */ + offsetof(struct ItVpdAreas,xSlicVpdLens),/* offset to VPD lens */ + 0, /* max slot labels */ + 1, /* max LP queues */ + {0}, {0}, /* reserved */ + {0}, /* DMA lengths */ + {0}, /* DMA tokens */ + { /* VPD lengths */ + 0,0,0,0, /* 0 - 3 */ + sizeof(struct Paca), /* 4 length of Paca */ + 0, /* 5 */ + sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ + 26992, /* 7 length of MS VPD */ + 0, /* 8 */ + sizeof(struct ItLpNaca),/* 9 length of LP Naca */ + 0, /* 10 */ + 256, /* 11 length of Recovery Log Buf */ + sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ + 0,0,0, /* 13 - 15 */ + sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ + 0,0,0,0,0,0, /* 17 - 22 */ + sizeof(struct ItLpQueue),/* 23 length of Lp Queue */ + 0,0 /* 24 - 25 */ + }, + { /* VPD addresses */ + 0,0,0,0, /* 0 - 3 */ + &xPaca[0], /* 4 first Paca */ + 0, /* 5 */ + &xItIplParmsReal, /* 6 IPL parms */ + &xMsVpd, /* 7 MS Vpd */ + 0, /* 8 */ + &itLpNaca, /* 9 LpNaca */ + 0, /* 10 */ + &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */ + &xSpCommArea, /* 12 SP Comm Area */ + 0,0,0, /* 13 - 15 */ + &xIoHriProcessorVpd, /* 16 Proc Vpd */ + 0,0,0,0,0,0, /* 17 - 22 */ + &xItLpQueue, /* 23 Lp Queue */ + 0,0 + } +}; + + +/* Data area used in flush_hash_page */ +long long flush_hash_page_hpte[2]; + +struct msChunks msChunks = {0, 0, 0, 0, NULL}; + +/* Depending on whether this is called from iSeries or pSeries setup + * code, the location of the msChunks struct may or may not have + * to be reloc'd, so we force the caller to do that for us by passing + * in a pointer to the structure. + */ +unsigned long +msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size) +{ + unsigned long offset = reloc_offset(); + struct msChunks *_msChunks = PTRRELOC(&msChunks); + + _msChunks->num_chunks = num_chunks; + _msChunks->chunk_size = chunk_size; + _msChunks->chunk_shift = __ilog2(chunk_size); + _msChunks->chunk_mask = (1UL<<_msChunks->chunk_shift)-1; + + mem = _ALIGN(mem, sizeof(msChunks_entry)); + _msChunks->abs = (msChunks_entry *)(mem + offset); + mem += num_chunks * sizeof(msChunks_entry); + + return mem; +} + + + + diff -urN linux-2.4.18/arch/ppc64/kernel/Makefile linux-2.4.19-pre5/arch/ppc64/kernel/Makefile --- linux-2.4.18/arch/ppc64/kernel/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,77 @@ +# +# 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... + +USE_STANDARD_AS_RULE := true + +EXTRA_CFLAGS = -mno-minimal-toc + +KHEAD := head.o + +all: $(KHEAD) kernel.o + +O_TARGET := kernel.o + +export-objs := ppc_ksyms.o setup.o + +obj-y := ppc_ksyms.o setup.o entry.o traps.o irq.o idle.o \ + time.o process.o signal.o syscalls.o misc.o ptrace.o \ + align.o semaphore.o bitops.o stab.o htab.o pacaData.o \ + LparData.o udbg.o binfmt_elf32.o sys_ppc32.o sys32.o \ + ioctl32.o ptrace32.o signal32.o open_pic.o xics.o \ + pmc.o mf_proc.o proc_pmc.o proc_pcifr.o iSeries_setup.o \ + ItLpQueue.o hvCall.o mf.o HvLpEvent.o ras.o \ + iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o \ + rtc.o + +obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_dma.o +obj-$(CONFIG_PPC_EEH) += eeh.o + +ifeq ($(CONFIG_PPC_ISERIES),y) +obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o +endif +ifeq ($(CONFIG_PPC_PSERIES),y) +obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o + +obj-y += rtasd.o +endif + +obj-$(CONFIG_KGDB) += ppc-stub.o + +obj-$(CONFIG_SMP) += smp.o + +# tibit: for matrox_init2() +ifeq ($(CONFIG_NVRAM),y) + obj-$(CONFIG_NVRAM) += pmac_nvram.o +endif + +obj-y += prom.o lmb.o rtas.o rtas-proc.o chrp_setup.o i8259.o + +include $(TOPDIR)/Rules.make + +# +# This is just to get the dependencies... +# + +head.o: head.S ppc_defs.h + +ppc_defs.h: mk_defs.c ppc_defs.head \ + $(TOPDIR)/include/asm/mmu.h \ + $(TOPDIR)/include/asm/processor.h \ + $(TOPDIR)/include/asm/pgtable.h \ + $(TOPDIR)/include/asm/ptrace.h + $(CC) $(CFLAGS) -S mk_defs.c + cp ppc_defs.head ppc_defs.h +# for bk, this way we can write to the file even if it's not checked out + chmod u+w ppc_defs.h + grep '^#define' mk_defs.s >> ppc_defs.h + rm mk_defs.s + +checks: checks.c + $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c + ./checks diff -urN linux-2.4.18/arch/ppc64/kernel/XmPciLpEvent.c linux-2.4.19-pre5/arch/ppc64/kernel/XmPciLpEvent.c --- linux-2.4.18/arch/ppc64/kernel/XmPciLpEvent.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/XmPciLpEvent.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,157 @@ +/* + * File XmPciLpEvent.h created by Wayne Holm on Mon Jan 15 2001. + * + * This module handles PCI interrupt events sent by the iSeries Hypervisor. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +long Pci_Interrupt_Count = 0; +long Pci_Event_Count = 0; + +enum XmPciLpEvent_Subtype { + XmPciLpEvent_BusCreated = 0, // PHB has been created + XmPciLpEvent_BusFailed = 1, // PHB has failed + XmPciLpEvent_BusRecovered = 12, // PHB has been recovered + XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed + XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered + XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt +}; + +struct XmPciLpEvent_BusInterrupt { + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; +}; + +struct XmPciLpEvent_NodeInterrupt { + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; + HvAgentId deviceId; +}; + +struct XmPciLpEvent { + struct HvLpEvent hvLpEvent; + + union { + u64 alignData; // Align on an 8-byte boundary + + struct { + u32 fisr; + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; + HvAgentId deviceId; + } slotInterrupt; + + struct XmPciLpEvent_BusInterrupt busFailed; + struct XmPciLpEvent_BusInterrupt busRecovered; + struct XmPciLpEvent_BusInterrupt busCreated; + + struct XmPciLpEvent_NodeInterrupt nodeFailed; + struct XmPciLpEvent_NodeInterrupt nodeRecovered; + + } eventData; + +}; + +static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm); + +static void XmPciLpEvent_handler( struct HvLpEvent* eventParm, struct pt_regs* regsParm) +{ + //PPCDBG(PPCDBG_BUSWALK,"XmPciLpEvent_handler, type 0x%x\n",eventParm->xType ); + ++Pci_Event_Count; + + if (eventParm && eventParm->xType == HvLpEvent_Type_PciIo) { + switch( eventParm->xFlags.xFunction ) { + case HvLpEvent_Function_Int: + intReceived( (struct XmPciLpEvent*)eventParm, regsParm ); + break; + case HvLpEvent_Function_Ack: + printk(KERN_ERR "XmPciLpEvent.c: unexpected ack received\n"); + break; + default: + printk(KERN_ERR "XmPciLpEvent.c: unexpected event function %d\n",(int)eventParm->xFlags.xFunction); + break; + } + } + else if (event) { + printk(KERN_ERR "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n",(int)eventParm->xType); + } + else { + printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); + } +} + +static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm) +{ + int irq; + + ++Pci_Interrupt_Count; + //PPCDBG(PPCDBG_BUSWALK,"PCI: XmPciLpEvent.c: intReceived\n"); + + switch (eventParm->hvLpEvent.xSubtype) { + case XmPciLpEvent_SlotInterrupt: + irq = eventParm->hvLpEvent.xCorrelationToken; + /* Dispatch the interrupt handlers for this irq */ + ppc_irq_dispatch_handler(regsParm, irq); + HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, + eventParm->eventData.slotInterrupt.subBusNumber, + eventParm->eventData.slotInterrupt.deviceId); + break; + /* Ignore error recovery events for now */ + case XmPciLpEvent_BusCreated: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", eventParm->eventData.busCreated.busNumber); + break; + case XmPciLpEvent_BusFailed: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", eventParm->eventData.busFailed.busNumber); + break; + case XmPciLpEvent_BusRecovered: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber); + break; + case XmPciLpEvent_NodeFailed: + printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId); + break; + case XmPciLpEvent_NodeRecovered: + printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId); + break; + default: + printk(KERN_ERR "XmPciLpEvent.c: unrecognized event subtype 0x%x\n", + eventParm->hvLpEvent.xSubtype); + break; + }; +} + + +/* This should be called sometime prior to buswalk (init_IRQ would be good) */ +int XmPciLpEvent_init() +{ + int xRc; + PPCDBG(PPCDBG_BUSWALK,"XmPciLpEvent_init, Register Event type 0x%04X\n",HvLpEvent_Type_PciIo); + + xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, &XmPciLpEvent_handler); + if (xRc == 0) { + xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); + if (xRc != 0) { + printk(KERN_ERR "XmPciLpEvent.c: open event path failed with rc 0x%x\n", xRc); + } + } + else { + printk(KERN_ERR "XmPciLpEvent.c: register handler failed with rc 0x%x\n", xRc); + } + return xRc; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/align.c linux-2.4.19-pre5/arch/ppc64/kernel/align.c --- linux-2.4.18/arch/ppc64/kernel/align.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/align.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,362 @@ +/* + * align.c - handle alignment exceptions for the Power PC. + * + * Copyright (c) 1996 Paul Mackerras + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright (c) 2001 PPC64 team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct aligninfo { + unsigned char len; + unsigned char flags; +}; + +#define OPCD(inst) (((inst) & 0xFC000000) >> 26) +#define RS(inst) (((inst) & 0x03E00000) >> 21) +#define RA(inst) (((inst) & 0x001F0000) >> 16) +#define IS_DFORM(code) ((code) >= 32 && (code) <= 47) + +#define INVALID { 0, 0 } + +#define LD 1 /* load */ +#define ST 2 /* store */ +#define SE 4 /* sign-extend value */ +#define F 8 /* to/from fp regs */ +#define U 0x10 /* update index register */ +#define M 0x20 /* multiple load/store */ +#define S 0x40 /* single-precision fp, or byte-swap value */ +#define HARD 0x80 /* string, stwcx. */ +#define D 0x100 /* double-word load/store */ + +#define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ + +/* + * The PowerPC stores certain bits of the instruction that caused the + * alignment exception in the DSISR register. This array maps those + * bits to information about the operand length and what the + * instruction would do. + */ +static struct aligninfo aligninfo[128] = { + { 4, LD }, /* 00 0 0000: lwz / lwarx */ + INVALID, /* 00 0 0001 */ + { 4, ST }, /* 00 0 0010: stw */ + INVALID, /* 00 0 0011 */ + { 2, LD }, /* 00 0 0100: lhz */ + { 2, LD+SE }, /* 00 0 0101: lha */ + { 2, ST }, /* 00 0 0110: sth */ + { 4, LD+M }, /* 00 0 0111: lmw */ + { 4, LD+F+S }, /* 00 0 1000: lfs */ + { 8, LD+F }, /* 00 0 1001: lfd */ + { 4, ST+F+S }, /* 00 0 1010: stfs */ + { 8, ST+F }, /* 00 0 1011: stfd */ + INVALID, /* 00 0 1100 */ + { 8, LD }, /* 00 0 1101: ld */ + INVALID, /* 00 0 1110 */ + { 8, ST }, /* 00 0 1111: std */ + { 4, LD+U }, /* 00 1 0000: lwzu */ + INVALID, /* 00 1 0001 */ + { 4, ST+U }, /* 00 1 0010: stwu */ + INVALID, /* 00 1 0011 */ + { 2, LD+U }, /* 00 1 0100: lhzu */ + { 2, LD+SE+U }, /* 00 1 0101: lhau */ + { 2, ST+U }, /* 00 1 0110: sthu */ + { 4, ST+M }, /* 00 1 0111: stmw */ + { 4, LD+F+S+U }, /* 00 1 1000: lfsu */ + { 8, LD+F+U }, /* 00 1 1001: lfdu */ + { 4, ST+F+S+U }, /* 00 1 1010: stfsu */ + { 8, ST+F+U }, /* 00 1 1011: stfdu */ + INVALID, /* 00 1 1100 */ + { 8, ST }, /* 00 1 1101: std */ + INVALID, /* 00 1 1110 */ + INVALID, /* 00 1 1111 */ + { 8, LD }, /* 01 0 0000: ldx */ + INVALID, /* 01 0 0001 */ + { 8, ST }, /* 01 0 0010: stdx */ + INVALID, /* 01 0 0011 */ + INVALID, /* 01 0 0100 */ + INVALID, /* 01 0 0101: lwax?? */ + INVALID, /* 01 0 0110 */ + INVALID, /* 01 0 0111 */ + { 0, LD+HARD }, /* 01 0 1000: lswx */ + { 0, LD+HARD }, /* 01 0 1001: lswi */ + { 0, ST+HARD }, /* 01 0 1010: stswx */ + { 0, ST+HARD }, /* 01 0 1011: stswi */ + INVALID, /* 01 0 1100 */ + { 8, LD+U }, /* 01 0 1101: ldu */ + INVALID, /* 01 0 1110 */ + { 8, ST+U }, /* 01 0 1111: stdu */ + { 8, LD+U }, /* 01 1 0000: ldux */ + INVALID, /* 01 1 0001 */ + { 8, ST+U }, /* 01 1 0010: stdux */ + INVALID, /* 01 1 0011 */ + INVALID, /* 01 1 0100 */ + INVALID, /* 01 1 0101: lwaux?? */ + INVALID, /* 01 1 0110 */ + INVALID, /* 01 1 0111 */ + INVALID, /* 01 1 1000 */ + INVALID, /* 01 1 1001 */ + INVALID, /* 01 1 1010 */ + INVALID, /* 01 1 1011 */ + INVALID, /* 01 1 1100 */ + INVALID, /* 01 1 1101 */ + INVALID, /* 01 1 1110 */ + INVALID, /* 01 1 1111 */ + INVALID, /* 10 0 0000 */ + INVALID, /* 10 0 0001 */ + { 0, ST+HARD }, /* 10 0 0010: stwcx. */ + INVALID, /* 10 0 0011 */ + INVALID, /* 10 0 0100 */ + INVALID, /* 10 0 0101 */ + INVALID, /* 10 0 0110 */ + INVALID, /* 10 0 0111 */ + { 4, LD+S }, /* 10 0 1000: lwbrx */ + INVALID, /* 10 0 1001 */ + { 4, ST+S }, /* 10 0 1010: stwbrx */ + INVALID, /* 10 0 1011 */ + { 2, LD+S }, /* 10 0 1100: lhbrx */ + INVALID, /* 10 0 1101 */ + { 2, ST+S }, /* 10 0 1110: sthbrx */ + INVALID, /* 10 0 1111 */ + INVALID, /* 10 1 0000 */ + INVALID, /* 10 1 0001 */ + INVALID, /* 10 1 0010 */ + INVALID, /* 10 1 0011 */ + INVALID, /* 10 1 0100 */ + INVALID, /* 10 1 0101 */ + INVALID, /* 10 1 0110 */ + INVALID, /* 10 1 0111 */ + INVALID, /* 10 1 1000 */ + INVALID, /* 10 1 1001 */ + INVALID, /* 10 1 1010 */ + INVALID, /* 10 1 1011 */ + INVALID, /* 10 1 1100 */ + INVALID, /* 10 1 1101 */ + INVALID, /* 10 1 1110 */ + { 0, ST+HARD }, /* 10 1 1111: dcbz */ + { 4, LD }, /* 11 0 0000: lwzx */ + INVALID, /* 11 0 0001 */ + { 4, ST }, /* 11 0 0010: stwx */ + INVALID, /* 11 0 0011 */ + { 2, LD }, /* 11 0 0100: lhzx */ + { 2, LD+SE }, /* 11 0 0101: lhax */ + { 2, ST }, /* 11 0 0110: sthx */ + INVALID, /* 11 0 0111 */ + { 4, LD+F+S }, /* 11 0 1000: lfsx */ + { 8, LD+F }, /* 11 0 1001: lfdx */ + { 4, ST+F+S }, /* 11 0 1010: stfsx */ + { 8, ST+F }, /* 11 0 1011: stfdx */ + INVALID, /* 11 0 1100 */ + INVALID, /* 11 0 1101 */ + INVALID, /* 11 0 1110 */ + INVALID, /* 11 0 1111 */ + { 4, LD+U }, /* 11 1 0000: lwzux */ + INVALID, /* 11 1 0001 */ + { 4, ST+U }, /* 11 1 0010: stwux */ + INVALID, /* 11 1 0011 */ + { 2, LD+U }, /* 11 1 0100: lhzux */ + { 2, LD+SE+U }, /* 11 1 0101: lhaux */ + { 2, ST+U }, /* 11 1 0110: sthux */ + INVALID, /* 11 1 0111 */ + { 4, LD+F+S+U }, /* 11 1 1000: lfsux */ + { 8, LD+F+U }, /* 11 1 1001: lfdux */ + { 4, ST+F+S+U }, /* 11 1 1010: stfsux */ + { 8, ST+F+U }, /* 11 1 1011: stfdux */ + INVALID, /* 11 1 1100 */ + INVALID, /* 11 1 1101 */ + INVALID, /* 11 1 1110 */ + INVALID, /* 11 1 1111 */ +}; + +#define SWAP(a, b) (t = (a), (a) = (b), (b) = t) + +int +fix_alignment(struct pt_regs *regs) +{ + int instr, nb, flags; + int opcode, f1, f2, f3; + int i, t; + int reg, areg; + unsigned char *addr; + union { + int l; + long ll; + float f; + double d; + unsigned char v[8]; + } data; + + if (__is_processor(PV_POWER4)) { + /* + * The POWER4 has a DSISR register but doesn't set it on + * an alignment fault. -- paulus + */ + + instr = *((unsigned int *)regs->nip); + opcode = OPCD(instr); + reg = RS(instr); + areg = RA(instr); + + if (IS_DFORM(opcode)) { + f1 = 0; + f2 = (instr & 0x04000000) >> 26; + f3 = (instr & 0x78000000) >> 27; + } else { + f1 = (instr & 0x00000006) >> 1; + f2 = (instr & 0x00000040) >> 6; + f3 = (instr & 0x00000780) >> 7; + } + + instr = ((f1 << 5) | (f2 << 4) | f3); + } else { + reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */ + areg = regs->dsisr & 0x1f; /* register to update */ + instr = (regs->dsisr >> 10) & 0x7f; + instr |= (regs->dsisr >> 13) & 0x60; + } + + nb = aligninfo[instr].len; + if (nb == 0) { + long *p; + int i; + + if (instr != DCBZ) + return 0; /* too hard or invalid instruction */ + /* + * The dcbz (data cache block zero) instruction + * gives an alignment fault if used on non-cacheable + * memory. We handle the fault mainly for the + * case when we are running with the cache disabled + * for debugging. + */ + p = (long *) (regs->dar & -L1_CACHE_BYTES); + for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i) + p[i] = 0; + return 1; + } + + flags = aligninfo[instr].flags; + addr = (unsigned char *)regs->dar; + + /* Verify the address of the operand */ + if (user_mode(regs)) { + if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb)) + return -EFAULT; /* bad address */ + } + + if ((flags & F) && (regs->msr & MSR_FP)) + giveup_fpu(current); + if (flags & M) + return 0; /* too hard for now */ + + /* If we read the operand, copy it in */ + if (flags & LD) { + if (nb == 2) { + data.v[0] = data.v[1] = 0; + if (__get_user(data.v[2], addr) + || __get_user(data.v[3], addr+1)) + return -EFAULT; + } else { + for (i = 0; i < nb; ++i) + if (__get_user(data.v[i], addr+i)) + return -EFAULT; + } + } + /* Unfortunately D (== 0x100) doesn't fit in the aligninfo[n].flags + field. So synthesize it here. */ + if ((flags & F) == 0 && nb == 8) + flags |= D; + + switch (flags & ~U) { + case LD+SE: + if (data.v[2] >= 0x80) + data.v[0] = data.v[1] = -1; + /* fall through */ + case LD: + regs->gpr[reg] = data.l; + break; + case LD+D: + regs->gpr[reg] = data.ll; + break; + case LD+S: + if (nb == 2) { + SWAP(data.v[2], data.v[3]); + } else { + SWAP(data.v[0], data.v[3]); + SWAP(data.v[1], data.v[2]); + } + regs->gpr[reg] = data.l; + break; + case ST: + data.l = regs->gpr[reg]; + break; + case ST+D: + data.ll = regs->gpr[reg]; + break; + case ST+S: + data.l = regs->gpr[reg]; + if (nb == 2) { + SWAP(data.v[2], data.v[3]); + } else { + SWAP(data.v[0], data.v[3]); + SWAP(data.v[1], data.v[2]); + } + break; + case LD+F: + current->thread.fpr[reg] = data.d; + break; + case ST+F: + data.d = current->thread.fpr[reg]; + break; + /* these require some floating point conversions... */ + /* we'd like to use the assignment, but we have to compile + * the kernel with -msoft-float so it doesn't use the + * fp regs for copying 8-byte objects. */ + case LD+F+S: + enable_kernel_fp(); + cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr); + /* current->thread.fpr[reg] = data.f; */ + break; + case ST+F+S: + enable_kernel_fp(); + cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr); + /* data.f = current->thread.fpr[reg]; */ + break; + default: + printk("align: can't handle flags=%x\n", flags); + return 0; + } + + if (flags & ST) { + if (nb == 2) { + if (__put_user(data.v[2], addr) + || __put_user(data.v[3], addr+1)) + return -EFAULT; + } else { + for (i = 0; i < nb; ++i) + if (__put_user(data.v[i], addr+i)) + return -EFAULT; + } + } + + if (flags & U) { + regs->gpr[areg] = regs->dar; + } + + return 1; +} diff -urN linux-2.4.18/arch/ppc64/kernel/binfmt_elf32.c linux-2.4.19-pre5/arch/ppc64/kernel/binfmt_elf32.c --- linux-2.4.18/arch/ppc64/kernel/binfmt_elf32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/binfmt_elf32.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,79 @@ +/* + * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons. + * based on the SPARC64 version. + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) + * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) + * + * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp + * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM + * + * 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. + */ + +#define ELF_ARCH EM_PPC +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; + +#include +#include +#include +#include + +struct timeval32 +{ + int tv_sec, tv_usec; +}; + +#define elf_prstatus elf_prstatus32 +struct elf_prstatus32 +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned int pr_sigpend; /* Set of pending signals */ + unsigned int pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval32 pr_utime; /* User time */ + struct timeval32 pr_stime; /* System time */ + struct timeval32 pr_cutime; /* Cumulative user time */ + struct timeval32 pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* General purpose registers. */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define elf_prpsinfo elf_prpsinfo32 +struct elf_prpsinfo32 +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + unsigned int pr_flag; /* flags */ + u32 pr_uid; + u32 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +extern void start_thread32(struct pt_regs *, unsigned long, unsigned long); +#undef start_thread +#define start_thread start_thread32 +#define init_elf_binfmt init_elf32_binfmt + +#undef CONFIG_BINFMT_ELF +#ifdef CONFIG_BINFMT_ELF32 +#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32 +#endif +#undef CONFIG_BINFMT_ELF_MODULE +#ifdef CONFIG_BINFMT_ELF32_MODULE +#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE +#endif + +#include "../../../fs/binfmt_elf.c" diff -urN linux-2.4.18/arch/ppc64/kernel/bitops.c linux-2.4.19-pre5/arch/ppc64/kernel/bitops.c --- linux-2.4.18/arch/ppc64/kernel/bitops.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/bitops.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * Adapted for ppc64 - Todd Inglett, Anton Blanchard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_BITOPS + +/* + * Bitops are weird when viewed on big-endian systems. They were designed + * on little endian so the size of the bitset doesn't matter (low order bytes + * come first) as long as the bit in question is valid. + * + * Bits are "tested" often using the C expression (val & (1<> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + + if (offset) { + tmp = *p++; + tmp |= ~0UL >> (64-offset); + if (size < 64) + goto found_first; + if (~tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; + if (tmp == ~0UL) + return result+size; +found_middle: + return result + ffz(tmp); +} + +void BUG_OUTLINE(char* file, unsigned line) +{ + udbg_printf("BUG - kernel BUG at %s:%d! \n", __FILE__, __LINE__); + PPCDBG_ENTER_DEBUGGER(); + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); +} + diff -urN linux-2.4.18/arch/ppc64/kernel/checks.c linux-2.4.19-pre5/arch/ppc64/kernel/checks.c --- linux-2.4.18/arch/ppc64/kernel/checks.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/checks.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,67 @@ +/* + * Copyright 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Do various before compile checks of data structures + * + * This is invoked when you do a make checks + * Is this enough or are there more things that we would like to do here? + * -- tgall + */ +int main(void) +{ + int ret = 0; +#if 0 + if ( sizeof(struct thread_struct) % 16 ) + { + printf("Thread struct is not modulo 16 bytes: " + "%d bytes total, %d bytes off\n", + sizeof(struct thread_struct), + sizeof(struct thread_struct)%16); + ret = -1; + } +#endif + + if ( sizeof(struct pt_regs) % 16 ) + { + printf("pt_regs struct is not modulo 16 bytes: " + "%d bytes total, %d bytes off\n", + sizeof(struct pt_regs), + sizeof(struct pt_regs)%16); + ret = -1; + + } + + printf("Task size : %d bytes\n" + "Tss size : %d bytes\n" + "pt_regs size : %d bytes\n" + "Kernel stack size: %d bytes\n", + sizeof(struct task_struct), sizeof(struct thread_struct), + sizeof(struct pt_regs), + sizeof(union task_union) - sizeof(struct task_struct)); + return ret; +} diff -urN linux-2.4.18/arch/ppc64/kernel/chrp_setup.c linux-2.4.19-pre5/arch/ppc64/kernel/chrp_setup.c --- linux-2.4.18/arch/ppc64/kernel/chrp_setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/chrp_setup.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,389 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by PPC64 Team, IBM Corp + * + * 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. + */ + +/* + * bootup setup stuff.. + */ + +#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 +#include + +#include "local_irq.h" +#include "i8259.h" +#include "open_pic.h" +#include "xics.h" +#include + +extern volatile unsigned char *chrp_int_ack_special; +extern struct Naca *naca; + +void chrp_setup_pci_ptrs(void); +void chrp_progress(char *, unsigned short); +void chrp_request_regions(void); + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; +extern void openpic_init_IRQ(void); +extern void init_ras_IRQ(void); + +extern void find_and_init_phbs(void); +extern void pSeries_pcibios_fixup(void); +extern void iSeries_pcibios_fixup(void); + +extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); +extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); +void pSeries_calibrate_decr(void); + +kdev_t boot_dev; +unsigned long virtPython0Facilities = 0; // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address. + +extern HPTE *Hash, *Hash_end; +extern unsigned long Hash_size, Hash_mask; +extern int probingmem; +extern unsigned long loops_per_jiffy; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +void +chrp_get_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = find_path_device("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: CHRP %s\n", model); +} + +void __init chrp_request_regions(void) { + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); +} + +void __init +chrp_setup_arch(void) +{ + extern char cmd_line[]; + struct device_node *root; + unsigned int *opprop; + + /* openpic global configuration register (64-bit format). */ + /* openpic Interrupt Source Unit pointer (64-bit format). */ + /* python0 facility area (mmio) (64-bit format) REAL address. */ + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ + + printk("Boot arguments: %s\n", cmd_line); + + /* Find and initialize PCI host bridges */ + /* iSeries needs to be done much later. */ + #ifndef CONFIG_PPC_ISERIES + find_and_init_phbs(); + #endif + + /* Find the Open PIC if present */ + root = find_path_device("/"); + opprop = (unsigned int *) get_property(root, + "platform-open-pic", NULL); + if (opprop != 0) { + int n = prom_n_addr_cells(root); + unsigned long openpic; + + for (openpic = 0; n > 0; --n) + openpic = (openpic << 32) + *opprop++; + printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic); + udbg_printf("OpenPIC addr: %lx\n", openpic); + OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE); + } + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif +} + +void __init +chrp_init2(void) +{ + /* + * It is sensitive, when this is called (not too earlu) + * -- tibit + */ + chrp_request_regions(); + ppc_md.progress(UTS_RELEASE, 0x7777); +} + + +/* Early initialization. Relocation is on but do not reference unbolted pages */ +void __init pSeries_init_early(void) +{ +#ifdef CONFIG_PPC_PSERIES /* This ifdef should go away */ + void *comport; + + hpte_init_pSeries(); + tce_init_pSeries(); + pSeries_pcibios_init_early(); + +#ifdef CONFIG_SMP + smp_init_pSeries(); +#endif + + /* Map the uart for udbg. */ + comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); + udbg_init_uart(comport); + + ppc_md.udbg_putc = udbg_putc; + ppc_md.udbg_getc = udbg_getc; + ppc_md.udbg_getc_poll = udbg_getc_poll; +#endif +} + +void __init +chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ +#if 0 /* PPPBBB remove this later... -Peter */ +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r6 ) + { + initrd_start = __va(r6); + initrd_end = __va(r6 + r7); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +#endif + + ppc_md.ppc_machine = _machine; + + ppc_md.setup_arch = chrp_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = chrp_get_cpuinfo; + if(naca->interrupt_controller == IC_OPEN_PIC) { + ppc_md.init_IRQ = openpic_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + ppc_md.post_irq = NULL; + } else { + ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.get_irq = xics_get_irq; + ppc_md.post_irq = NULL; + } + ppc_md.init_ras_IRQ = init_ras_IRQ; + + #ifndef CONFIG_PPC_ISERIES + ppc_md.pcibios_fixup = pSeries_pcibios_fixup; + #else + ppc_md.pcibios_fixup = NULL; + // ppc_md.pcibios_fixup = iSeries_pcibios_fixup; + #endif + + + ppc_md.init = chrp_init2; + + ppc_md.restart = rtas_restart; + ppc_md.power_off = rtas_power_off; + ppc_md.halt = rtas_halt; + + ppc_md.time_init = NULL; + ppc_md.get_boot_time = pSeries_get_rtc_time; + ppc_md.get_rtc_time = pSeries_get_rtc_time; + ppc_md.set_rtc_time = pSeries_set_rtc_time; + ppc_md.calibrate_decr = pSeries_calibrate_decr; + + ppc_md.progress = chrp_progress; + +#ifdef CONFIG_VT + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x63; /* Print Screen */ +#endif +#endif + + ppc_md.progress("Linux ppc64\n", 0x0); +} + +void __chrp +chrp_progress(char *s, unsigned short hex) +{ + struct device_node *root; + int width, *p; + char *os; + static int display_character, set_indicator; + static int max_width; + + if (hex) + udbg_printf(" %s\n", s); + + if (!rtas.base || (_machine != _MACH_pSeries)) + return; + + if (max_width == 0) { + if ( (root = find_path_device("/rtas")) && + (p = (unsigned int *)get_property(root, + "ibm,display-line-length", + NULL)) ) + max_width = *p; + else + max_width = 0x10; + display_character = rtas_token("display-character"); + set_indicator = rtas_token("set-indicator"); + } + if (display_character == RTAS_UNKNOWN_SERVICE) { + /* use hex display */ + if (set_indicator == RTAS_UNKNOWN_SERVICE) + return; + rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); + return; + } + + rtas_call(display_character, 1, 1, NULL, '\r'); + + width = max_width; + os = s; + while ( *os ) + { + if ( (*os == '\n') || (*os == '\r') ) + width = max_width; + else + width--; + rtas_call(display_character, 1, 1, NULL, *os++ ); + /* if we overwrite the screen length */ + if ( width == 0 ) + while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) + os++; + } + + /* Blank to end of line. */ + while ( width-- > 0 ) + rtas_call(display_character, 1, 1, NULL, ' ' ); +} + +extern void setup_default_decr(void); + +extern unsigned long ppc_proc_freq; +extern unsigned long ppc_tb_freq; + +void __init pSeries_calibrate_decr(void) +{ + struct device_node *cpu; + struct div_result divres; + int *fp; + unsigned long freq, processor_freq; + + /* + * The cpu node should have a timebase-frequency property + * to tell us the rate at which the decrementer counts. + */ + freq = 16666000; /* hardcoded default */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (int *) get_property(cpu, "timebase-frequency", NULL); + if (fp != 0) + freq = *fp; + } + ppc_tb_freq = freq; + processor_freq = freq; + if (cpu != 0) { + fp = (int *) get_property(cpu, "clock-frequency", NULL); + if (fp != 0) + processor_freq = *fp; + } + ppc_proc_freq = processor_freq; + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000 ); + printk("time_init: processor frequency = %lu.%.6lu MHz\n", + processor_freq/1000000, processor_freq%1000000 ); + + tb_ticks_per_jiffy = freq / HZ; + tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; + tb_ticks_per_usec = freq / 1000000; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres ); + tb_to_xs = divres.result_low; + + setup_default_decr(); +} + diff -urN linux-2.4.18/arch/ppc64/kernel/eeh.c linux-2.4.19-pre5/arch/ppc64/kernel/eeh.c --- linux-2.4.18/arch/ppc64/kernel/eeh.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/eeh.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,313 @@ +/* + * eeh.c + * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Change Activity: + * 2001/10/27 : engebret : Created. + * End Change Activity + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci.h" + +#define BUID_HI(buid) ((buid) >> 32) +#define BUID_LO(buid) ((buid) & 0xffffffff) +#define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8) + +unsigned long eeh_total_mmio_reads; +unsigned long eeh_total_mmio_ffs; +unsigned long eeh_false_positives; +/* RTAS tokens */ +static int ibm_set_eeh_option; +static int ibm_set_slot_reset; +static int ibm_read_slot_reset_state; + +static int eeh_implemented; +#define EEH_MAX_OPTS 4096 +static char *eeh_opts; +static int eeh_opts_last; +static int eeh_check_opts_config(struct pci_dev *dev); + + +unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset) +{ + if (phb > 0xff) + panic("eeh_token: phb 0x%lx is too large\n", phb); + if (offset & 0x0fffffff00000000) + panic("eeh_token: offset 0x%lx is out of range\n", offset); + return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff)); +} + + + +int eeh_get_state(unsigned long ea) { + return 0; +} + + +/* Check for an eeh failure at the given token address. + * The given value has been read and it should be 1's (0xff, 0xffff or 0xffffffff). + * + * Probe to determine if an error actually occurred. If not return val. + * Otherwise panic. + */ +unsigned long eeh_check_failure(void *token, unsigned long val) +{ + unsigned long config_addr = (unsigned long)token >> 24; /* PPBBDDRR */ + unsigned long phbidx = (config_addr >> 24) & 0xff; + struct pci_controller *phb; + unsigned long ret, rets[2]; + + config_addr &= 0xffff00; /* 00BBDD00 */ + + if (phbidx >= global_phb_number) { + panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1); + } + phb = phbtab[phbidx]; + eeh_false_positives++; + + ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, + config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid)); + if (ret == 0 && rets[1] == 1 && rets[2] != 0) { + struct pci_dev *dev; + int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */ + int devfn = (config_addr >> 8) & 0xff; + + dev = pci_find_slot(bus, devfn); + if (dev) + panic("EEH: MMIO failure (%ld) on device:\n %s %s\n", + rets[2], dev->slot_name, dev->name); + else + panic("EEH: MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[2], phb->buid, config_addr); + } + return val; /* good case */ +} + +void eeh_init(void) { + ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); + ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); + ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); + if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE) { + printk("PCI Enhanced I/O Error Handling Enabled\n"); + eeh_implemented = 1; + } +} + + +/* Given a PCI device check if eeh should be configured or not. + * This may look at firmware properties and/or kernel cmdline options. + */ +int is_eeh_configured(struct pci_dev *dev) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_controller *phb = PCI_GET_PHB_PTR(dev); + unsigned long ret, rets[2]; + + if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented) + return 0; + + /* Hack: turn off eeh for display class devices. + * This fixes matrox accel framebuffer. + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) + return 0; + + if (!eeh_check_opts_config(dev)) + return 0; + + ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, + CONFIG_ADDR(dn->busno, dn->devfn), + BUID_HI(phb->buid), BUID_LO(phb->buid)); + if (ret == 0 && rets[1] == 1) { + printk("EEH: %s %s is EEH capable.\n", dev->slot_name, dev->name); + return 1; + } + return 0; +} + +int eeh_set_option(struct pci_dev *dev, int option) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_controller *phb = PCI_GET_PHB_PTR(dev); + + if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented) + return -2; + + return rtas_call(ibm_set_eeh_option, 4, 1, NULL, + CONFIG_ADDR(dn->busno, dn->devfn), + BUID_HI(phb->buid), BUID_LO(phb->buid), option); +} + + +static int eeh_proc_falsepositive_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + len = sprintf(page, "eeh_false_positives=%ld\n" + "eeh_total_mmio_ffs=%ld\n" + "eeh_total_mmio_reads=%ld\n", + eeh_false_positives, eeh_total_mmio_ffs, eeh_total_mmio_reads); + return len; +} + +/* Implementation of /proc/ppc64/eeh + * For now it is one file showing false positives. + */ +void eeh_init_proc(struct proc_dir_entry *top) +{ + struct proc_dir_entry *ent = create_proc_entry("eeh", S_IRUGO, top); + if (ent) { + ent->nlink = 1; + ent->data = NULL; + ent->read_proc = (void *)eeh_proc_falsepositive_read; + } +} + +/* + * Test if "dev" should be configured on or off. + * This processes the options literally from right to left. + * This lets the user specify stupid combinations of options, + * but at least the result should be very predictable. + */ +static int eeh_check_opts_config(struct pci_dev *dev) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_controller *phb = PCI_GET_PHB_PTR(dev); + char devname[32], classname[32], phbname[32]; + char *strs[8], *s; + int nstrs, i; + int ret = 0; + + if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented) + return 0; + /* Build list of strings to match */ + nstrs = 0; + s = (char *)get_property(dn, "ibm,loc-code", 0); + if (s) + strs[nstrs++] = s; + sprintf(devname, "dev%04x:%04x", dev->vendor, dev->device); + strs[nstrs++] = devname; + sprintf(classname, "class%04x", dev->class); + strs[nstrs++] = classname; + sprintf(phbname, "pci@%lx", phb->buid); + strs[nstrs++] = phbname; + strs[nstrs++] = ""; /* yes, this matches the empty string */ + + /* Now see if any string matches the eeh_opts list. + * The eeh_opts list entries start with + or -. + */ + for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) { + for (i = 0; i < nstrs; i++) { + if (strcasecmp(strs[i], s+1) == 0) { + ret = (strs[0] == '+') ? 1 : 0; + } + } + } + return ret; +} + +/* Handle kernel eeh-on & eeh-off cmd line options for eeh. + * + * We support: + * eeh-off=loc1,loc2,loc3... + * + * and this option can be repeated so + * eeh-off=loc1,loc2 eeh=loc3 + * is the same as eeh-off=loc1,loc2,loc3 + * + * loc is an IBM location code that can be found in a manual or + * via openfirmware (or the Hardware Management Console). + * + * We also support these additional "loc" values: + * + * dev#:# vendor:device id in hex (e.g. dev1022:2000) + * class# class id in hex (e.g. class0200) + * pci@buid all devices under phb (e.g. pci@fef00000) + * + * If no location code is specified all devices are assumed + * so eeh-off means eeh by default is off. + */ + +/* This is implemented as a null separated list of strings. + * Each string looks like this: "+X" or "-X" + * where X is a loc code, dev, class or pci string (as shown above) + * or empty which is used to indicate all. + * + * We interpret this option string list during the buswalk + * so that it will literally behave left-to-right even if + * some combinations don't make sense. Give the user exactly + * what they want! :) + */ + +static int __init eeh_parm(char *str, int state) +{ + char *s, *cur, *curend; + if (!eeh_opts) { + eeh_opts = alloc_bootmem(EEH_MAX_OPTS); + eeh_opts[eeh_opts_last++] = '+'; /* default */ + eeh_opts[eeh_opts_last++] = '\0'; + } + if (*str == '\0') { + eeh_opts[eeh_opts_last++] = state ? '+' : '-'; + eeh_opts[eeh_opts_last++] = '\0'; + return 1; + } + if (*str == '=') + str++; + for (s = str; s && *s != '\0'; s = curend) { + cur = s; + while (*cur == ',') + cur++; /* ignore empties. Don't treat as "all-on" or "all-off" */ + curend = strchr(cur, ','); + if (!curend) + curend = cur + strlen(cur); + if (*cur) { + int curlen = curend-cur; + char *sym = eeh_opts+eeh_opts_last; + if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) { + printk("EEH: sorry...too many eeh cmd line options\n"); + return 1; + } + eeh_opts[eeh_opts_last++] = state ? '+' : '-'; + strncpy(eeh_opts+eeh_opts_last, cur, curlen); + eeh_opts_last += curlen; + eeh_opts[eeh_opts_last++] = '\0'; + } + } + return 1; +} + +static int __init eehoff_parm(char *str) +{ + return eeh_parm(str, 0); +} +static int __init eehon_parm(char *str) +{ + return eeh_parm(str, 1); +} + + +__setup("eeh-off", eehoff_parm); +__setup("eeh-on", eehon_parm); diff -urN linux-2.4.18/arch/ppc64/kernel/entry.S linux-2.4.19-pre5/arch/ppc64/kernel/entry.S --- linux-2.4.18/arch/ppc64/kernel/entry.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/entry.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,616 @@ +/* + * arch/ppc/kernel/entry.S + * + * + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains the system call entry code, context switch + * code, and exception/interrupt return code for PowerPC. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + + +#include "ppc_asm.h" +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + +#undef SHOW_SYSCALLS +#undef SHOW_SYSCALLS_TASK + +#ifdef SHOW_SYSCALLS_TASK + .data +show_syscalls_task: + .long -1 +#endif + +/* + * Handle a system call. + */ + .text +_GLOBAL(DoSyscall) + std r0,THREAD+LAST_SYSCALL(r13) + ld r11,_CCR(r1) /* Clear SO bit in CR */ + lis r10,0x1000 + andc r11,r11,r10 + std r11,_CCR(r1) +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + LOADBASE(r31,show_syscalls_task) + ld r31,show_syscalls_task@l(r31) + cmp 0,r13,r31 + bne 1f +#endif + LOADADDR(r3,7f) + ld r4,GPR0(r1) + ld r5,GPR3(r1) + ld r6,GPR4(r1) + ld r7,GPR5(r1) + ld r8,GPR6(r1) + ld r9,GPR7(r1) + bl .printk + LOADADDR(r3,77f) + ld r4,GPR8(r1) + ld r5,GPR9(r1) + mr r6,r13 + bl .printk + ld r0,GPR0(r1) + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r5,GPR5(r1) + ld r6,GPR6(r1) + ld r7,GPR7(r1) + ld r8,GPR8(r1) +1: +#endif /* SHOW_SYSCALLS */ + ld r10,TASK_PTRACE(r13) + andi. r10,r10,PT_TRACESYS + bne- 50f + cmpli 0,r0,NR_syscalls + bge- 66f +/* Ken Aaker: Need to vector to 32 Bit or default sys_call_table here, + * based on caller's run-mode / personality. + * + */ +#ifdef CONFIG_BINFMT_ELF32 + ld r10,THREAD+THREAD_FLAGS(r13) + andi. r10,r10,PPC_FLAG_32BIT + beq- 15f + LOADADDR(r10,.sys_call_table32) +/* Now mung the first 4 parameters into shape, by making certain that + * the high bits (most significant 32 bits in 64 bit reg) are 0 + * for the first 4 parameter regs(3-6). + */ + clrldi r3,r3,32 + clrldi r4,r4,32 + clrldi r5,r5,32 + clrldi r6,r6,32 + b 17f +15: +#endif + LOADADDR(r10,.sys_call_table) +17: + slwi r0,r0,3 + ldx r10,r10,r0 /* Fetch system call handler [ptr] */ + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ +_GLOBAL(ret_from_syscall_1) +20: std r3,RESULT(r1) /* Save result */ +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + cmp 0,r13,r31 + bne 91f +#endif + mr r4,r3 + LOADADDR(r3,79f) + bl .printk + ld r3,RESULT(r1) +91: +#endif + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 30f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 22f + li r3,EINTR +22: ld r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + std r10,_CCR(r1) +30: std r3,GPR3(r1) /* Update return value */ + b .ret_from_except +66: li r3,ENOSYS + b 22b + +/* Traced system call support */ +50: bl .syscall_trace + ld r0,GPR0(r1) /* Restore original registers */ + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r5,GPR5(r1) + ld r6,GPR6(r1) + ld r7,GPR7(r1) + ld r8,GPR8(r1) + ld r9,GPR9(r1) + cmpli 0,r0,NR_syscalls + bge- 66f +#ifdef CONFIG_BINFMT_ELF32 + ld r10,THREAD+THREAD_FLAGS(r13) + andi. r10,r10,PPC_FLAG_32BIT + beq- 55f + LOADADDR(r10,.sys_call_table32) +/* Now mung the first 4 parameters into shape, by making certain that + * the high bits (most significant 32 bits in 64 bit reg) are 0 + * for the first 4 parameter regs(3-6). + */ + clrldi r3,r3,32 + clrldi r4,r4,32 + clrldi r5,r5,32 + clrldi r6,r6,32 + b 57f +55: +#endif + LOADADDR(r10,.sys_call_table) +57: + slwi r0,r0,3 + ldx r10,r10,r0 /* Fetch system call handler [ptr] */ + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ +_GLOBAL(ret_from_syscall_2) +58: std r3,RESULT(r1) /* Save result */ + std r3,GPR0(r1) /* temporary gross hack to make strace work */ + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 60f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 57f + li r3,EINTR +57: ld r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + std r10,_CCR(r1) +60: std r3,GPR3(r1) /* Update return value */ + bl .syscall_trace + b .ret_from_except +66: li r3,ENOSYS + b 57b +#ifdef SHOW_SYSCALLS +7: .string "syscall %d(%x, %x, %x, %x, %x, " +77: .string "%x, %x), current=%p\n" +79: .string " -> %x\n" + .align 2,0 +#endif + +_GLOBAL(ppc32_sigreturn) + bl .sys32_sigreturn + b 80f + +_GLOBAL(ppc32_rt_sigreturn) + bl .sys32_rt_sigreturn + b 80f + +_GLOBAL(ppc64_sigreturn) + bl .sys_sigreturn + b 80f + +_GLOBAL(ppc64_rt_sigreturn) + bl .sys_rt_sigreturn + +80: ld r10,TASK_PTRACE(r13) + andi. r10,r10,PT_TRACESYS + bne- 81f + cmpi 0,r3,0 + bge .ret_from_except + b 20b +81: cmpi 0,r3,0 + blt 58b + bl .syscall_trace + b .ret_from_except + +/* + * This routine switches between two different tasks. The process + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory + * management hardware is updated to the second process's state. + * Finally, we can return to the second process, via ret_from_except. + * On entry, r3 points to the THREAD for the current task, r4 + * points to the THREAD for the new task. + * + * Note: there are two ways to get to the "going out" portion + * of this code; either by coming in via the entry (_switch) + * or via "fork" which must set up an environment equivalent + * to the "_switch" path. If you change this (or in particular, the + * SAVE_REGS macro), you'll have to change the fork code also. + * + * The code which creates the new task context is in 'copy_thread' + * in arch/ppc/kernel/process.c + */ +_GLOBAL(_switch) + stdu r1,-INT_FRAME_SIZE(r1) + ld r6,0(r1) + std r6,GPR1(r1) + /* r3-r13 are caller saved -- Cort */ + SAVE_GPR(2, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mflr r20 /* Return to switch caller */ + mfmsr r22 + li r6,MSR_FP /* Disable floating-point */ + andc r22,r22,r6 + mtmsrd r22 + isync + std r20,_NIP(r1) + std r22,_MSR(r1) + std r20,_LINK(r1) + mfcr r20 + std r20,_CCR(r1) + li r6,0x0ff0 + std r6,TRAP(r1) + std r1,KSP(r3) /* Set old stack pointer */ + + mfspr r5,SPRG3 /* Get Paca */ + addi r3,r3,-THREAD /* old 'current' for return value */ + addi r13,r4,-THREAD /* Convert THREAD to 'current' */ + std r13,PACACURRENT(r5) /* Set new 'current' */ + +#ifdef CONFIG_PPC_ISERIES + ld r7,THREAD_FLAGS(r4) /* Get run light flag */ + mfspr r9,CTRLF + srdi r7,r7,1 /* Align to run light bit in CTRL reg */ + insrdi r9,r7,1,63 /* Insert run light into CTRL */ + mtspr CTRLT,r9 +#endif + ld r1,KSP(r4) /* Load new stack pointer */ + ld r6,_CCR(r1) + mtcrf 0xFF,r6 + /* r3-r13 are destroyed -- Cort */ + REST_8GPRS(14, r1) + REST_10GPRS(22, r1) + + ld r7,_NIP(r1) /* Return to _switch caller in new task */ + ld r1,GPR1(r1) + mtlr r7 + blr + +_GLOBAL(ret_from_fork) + bl .schedule_tail + ld r0,TASK_PTRACE(r13) + andi. r0,r0,PT_TRACESYS + beq+ .ret_from_except + bl .syscall_trace + b .ret_from_except + +_GLOBAL(ret_from_except) +#ifdef CONFIG_PPC_ISERIES + ld r5,SOFTE(r1) + cmpdi 0,r5,0 + beq 4f +irq_recheck: + /* + * Check for pending interrupts (iSeries) + */ + CHECKANYINT(r3,r4) + beq+ 4f /* skip do_IRQ if no interrupts */ + + mfspr r5,SPRG3 + li r3,0 + stb r3,PACAPROCENABLED(r5) /* ensure we are disabled */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_IRQ + b irq_recheck /* loop back and handle more */ +4: +#endif +_GLOBAL(do_bottom_half_ret) + ld r3,_MSR(r1) /* Returning to user mode? */ + andi. r3,r3,MSR_PR + beq+ restore /* if so, check need_resched and signals */ +_GLOBAL(ret_to_user_hook) + nop + /* NEED_RESCHED is a volatile long (64-bits) */ + ld r3,NEED_RESCHED(r13) + cmpi 0,r3,0 /* check need_resched flag */ + beq+ 7f + bl .schedule + /* SIGPENDING is an int (32-bits) */ +7: + lwz r5,SIGPENDING(r13) /* Check for pending unblocked signals */ + cmpwi 0,r5,0 + beq+ restore + li r3,0 + addi r4,r1,STACK_FRAME_OVERHEAD + bl .do_signal +_GLOBAL(do_signal_ret) +restore: + ld r3,_CTR(r1) + ld r0,_LINK(r1) + mtctr r3 + mtlr r0 + ld r3,_XER(r1) + mtspr XER,r3 + REST_8GPRS(5, r1) + REST_10GPRS(14, r1) + REST_8GPRS(24, r1) + + /* make sure we hard disable here, even if rtl is active, to protect + * SRR[01] and SPRG2 -- Cort + */ + mfmsr r0 /* Get current interrupt state */ + li r4,0 + ori r4,r4,MSR_EE|MSR_RI + andc r0,r0,r4 /* clear MSR_EE and MSR_RI */ + mtmsrd r0 /* Update machine state */ +#ifdef CONFIG_PPC_ISERIES + ld r0,SOFTE(r1) + cmpi 0,r0,0 + beq+ 1f + + CHECKANYINT(r4,r3) + beq+ 1f + mfmsr r0 + ori r0,r0,MSR_EE|MSR_RI + mtmsrd r0 + b irq_recheck + +1: +#endif + stdcx. r0,0,r1 /* to clear the reservation */ + + mfspr r4,SPRG3 /* current task's PACA */ +#ifdef DO_SOFT_DISABLE + ld r0,SOFTE(r1) + stb r0,PACAPROCENABLED(r4) +#endif + /* if returning to user mode, save kernel SP */ + ld r0,_MSR(r1) + andi. r0,r0,MSR_PR + beq+ 1f + addi r0,r1,INT_FRAME_SIZE /* size of frame */ + std r0,THREAD+KSP(r13) /* save kernel stack pointer */ + std r1,PACAKSAVE(r4) /* save exception stack pointer */ +1: + ld r0,_MSR(r1) + mtspr SRR1,r0 + ld r2,_CCR(r1) + mtcrf 0xFF,r2 + ld r2,_NIP(r1) + mtspr SRR0,r2 + REST_GPR(13,r1) + ld r0,GPR0(r1) + ld r2,GPR2(r1) + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r1,GPR1(r1) + + rfid + +/* + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. + * + * In addition, we need to be in 32b mode, at least for now. + * + * Note: r3 is an input parameter to rtas, so don't trash it... + */ +_GLOBAL(enter_rtas) + mflr r0 + std r0,16(r1) + stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */ + + /* Because RTAS is running in 32b mode, it clobbers the high order half + * of all registers that it saves. We therefore save those registers + * RTAS might touch to the stack. (r0, r3-r13 are caller saved) + */ + SAVE_GPR(2, r1) /* Save the TOC */ + SAVE_GPR(13, r1) /* Save current */ + SAVE_8GPRS(14, r1) /* Save the non-volatiles */ + SAVE_10GPRS(22, r1) /* ditto */ + + mfcr r4 + std r4,_CCR(r1) + mfctr r5 + std r5,_CTR(r1) + mfspr r6,XER + std r6,_XER(r1) + mfdar r7 + std r7,_DAR(r1) + mfdsisr r8 + std r8,_DSISR(r1) + mfsrr0 r9 + std r9,_SRR0(r1) + mfsrr1 r10 + std r10,_SRR1(r1) + + /* Unfortunatly, the stack pointer and the MSR are also clobbered, + * so they are saved in the PACA (SPRG3) which allows us to restore + * our original state after RTAS returns. + */ + mfspr r4,SPRG3 /* Get PACA */ + std r1,PACAR1(r4) + mfmsr r6 + std r6,PACASAVEDMSR(r4) + + /* Setup our real return addr */ + SET_REG_TO_LABEL(r4,.rtas_return_loc) + SET_REG_TO_CONST(r9,KERNELBASE) + sub r4,r4,r9 + mtlr r4 + + li r0,0 + ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI + andc r0,r6,r0 + + li r9,1 + rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG) + ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP|MSR_RI + andc r6,r0,r9 + sync /* disable interrupts so SRR0/1 */ + mtmsrd r0 /* don't get trashed */ + + SET_REG_TO_LABEL(r4,rtas) + ld r5,RTASENTRY(r4) /* get the rtas->entry value */ + ld r4,RTASBASE(r4) /* get the rtas->base value */ + + mtspr SRR0,r5 + mtspr SRR1,r6 + rfid + +_STATIC(rtas_return_loc) + /* relocation is off at this point */ + mfspr r4,SPRG3 /* Get PACA */ + SET_REG_TO_CONST(r5, KERNELBASE) + sub r4,r4,r5 /* RELOC the PACA base pointer */ + + ld r1,PACAR1(r4) /* Restore our SP */ + LOADADDR(r3,.rtas_restore_regs) + ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ + + mtspr SRR0,r3 + mtspr SRR1,r4 + rfid + +_STATIC(rtas_restore_regs) + /* relocation is on at this point */ + REST_GPR(2, r1) /* Restore the TOC */ + REST_GPR(13, r1) /* Restore current */ + REST_8GPRS(14, r1) /* Restore the non-volatiles */ + REST_10GPRS(22, r1) /* ditto */ + + /* put back current in r13 */ + mfspr r4,SPRG3 + ld r13,PACACURRENT(r4) + + ld r4,_CCR(r1) + mtcr r4 + ld r5,_CTR(r1) + mtctr r5 + ld r6,_XER(r1) + mtspr XER,r6 + ld r7,_DAR(r1) + mtdar r7 + ld r8,_DSISR(r1) + mtdsisr r8 + ld r9,_SRR0(r1) + mtsrr0 r9 + ld r10,_SRR1(r1) + mtsrr1 r10 + + addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */ + ld r0,16(r1) /* get return address */ + + mtlr r0 + blr /* return to caller */ + + +_GLOBAL(enter_prom) + mflr r0 + std r0,16(r1) + stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + + /* Because PROM is running in 32b mode, it clobbers the high order half + * of all registers that it saves. We therefore save those registers + * PROM might touch to the stack. (r0, r3-r13 are caller saved) + */ + SAVE_8GPRS(2, r1) /* Save the TOC & incoming param(s) */ + SAVE_GPR(13, r1) /* Save current */ + SAVE_8GPRS(14, r1) /* Save the non-volatiles */ + SAVE_10GPRS(22, r1) /* ditto */ + + mfcr r4 + std r4,_CCR(r1) + mfctr r5 + std r5,_CTR(r1) + mfspr r6,XER + std r6,_XER(r1) + mfdar r7 + std r7,_DAR(r1) + mfdsisr r8 + std r8,_DSISR(r1) + mfsrr0 r9 + std r9,_SRR0(r1) + mfsrr1 r10 + std r10,_SRR1(r1) + mfmsr r11 + std r11,_MSR(r1) + + /* Unfortunatly, the stack pointer is also clobbered, so it is saved + * in the SPRG2 which allows us to restore our original state after + * PROM returns. + */ + mtspr SPRG2,r1 + + /* put a relocation offset into r3 */ + bl .reloc_offset + LOADADDR(r12,prom) + sub r12,r12,r3 + ld r12,PROMENTRY(r12) /* get the prom->entry value */ + mtlr r12 + + mfmsr r11 /* grab the current MSR */ + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + andc r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + andc r11,r11,r12 + mtmsrd r11 + isync + + REST_8GPRS(2, r1) /* Restore the TOC & param(s) */ + REST_GPR(13, r1) /* Restore current */ + REST_8GPRS(14, r1) /* Restore the non-volatiles */ + REST_10GPRS(22, r1) /* ditto */ + blrl /* Entering PROM here... */ + + mfspr r1,SPRG2 /* Restore the stack pointer */ + ld r6,_MSR(r1) /* Restore the MSR */ + mtmsrd r6 + isync + + REST_GPR(2, r1) /* Restore the TOC */ + REST_GPR(13, r1) /* Restore current */ + REST_8GPRS(14, r1) /* Restore the non-volatiles */ + REST_10GPRS(22, r1) /* ditto */ + + ld r4,_CCR(r1) + mtcr r4 + ld r5,_CTR(r1) + mtctr r5 + ld r6,_XER(r1) + mtspr XER,r6 + ld r7,_DAR(r1) + mtdar r7 + ld r8,_DSISR(r1) + mtdsisr r8 + ld r9,_SRR0(r1) + mtsrr0 r9 + ld r10,_SRR1(r1) + mtsrr1 r10 + addi r1,r1,PROM_FRAME_SIZE + ld r0,16(r1) /* get return address */ + + mtlr r0 + blr /* return to caller */ + diff -urN linux-2.4.18/arch/ppc64/kernel/flight_recorder.c linux-2.4.19-pre5/arch/ppc64/kernel/flight_recorder.c --- linux-2.4.18/arch/ppc64/kernel/flight_recorder.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/flight_recorder.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,182 @@ +/************************************************************************ + * flight_recorder.c + ************************************************************************ + * This code supports the a generic flight recorder. * + * Copyright (C) 20yy * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the: * + * Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, * + * Boston, MA 02111-1307 USA * + ************************************************************************ + * This is a simple text based flight recorder. Useful for logging + * information the you may want to retreive at a latter time. Errors or + * debug inforamtion are good examples. A good method to dump the + * information is via the proc file system. + * + * To use. + * 1. Create the flight recorder object. Passing a NULL pointer will + * kmalloc the space for you. If it is too early for kmalloc, create + * space for the object. Beware, don't lie about the size, you will + * pay for that later. + * FlightRecorder* TestFr = alloc_Flight_Recorder(NULL,"TestFr",4096); + * + * 2. Log any notable events, initialzation, error conditions, etc. + * LOGFR(TestFr,"5. Stack Variable(10) %d",StackVariable); + * + * 3. Dump the information to a buffer. + * fr_Dump(TestFr, proc_file_buffer, proc_file_buffer_size); + * + ************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +static char LogText[512]; +static int LogTextIndex; +static int LogCount = 0; +static spinlock_t Fr_Lock; + +/************************************************************************ + * Build the log time prefix based on Flags. + * 00 = No time prefix + * 01 = Date(mmddyy) Time(hhmmss) prefix + * 02 = Day(dd) Time(hhmmss) prefix + * 03 = Time(hhmmss) prefix + ************************************************************************/ +static void fr_Log_Time(FlightRecorder* Fr) +{ + struct timeval TimeClock; + struct rtc_time LogTime; + + do_gettimeofday(&TimeClock); + to_tm(TimeClock.tv_sec, &LogTime); + + if (Fr->Flags == 1) { + LogTextIndex = sprintf(LogText,"%02d%02d%02d %02d%02d%02d ", + LogTime.tm_mon, LogTime.tm_mday, LogTime.tm_year-2000, + LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec); + } + else if (Fr->Flags == 2) { + LogTextIndex = sprintf(LogText,"%02d %02d%02d%02d ", + LogTime.tm_mday, + LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec); + } + + else if (Fr->Flags == 3) { + LogTextIndex = sprintf(LogText,"%02d%02d%02d ", + LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec); + } + else { + ++LogCount; + LogTextIndex = sprintf(LogText,"%04d. ",LogCount); + } +} + +/************************************************************************/ +/* Log entry into buffer, */ +/* ->If entry is going to wrap, log "WRAP" and start at the top. */ +/************************************************************************/ +static void fr_Log_Data(FlightRecorder* Fr) +{ + int TextLen = strlen(LogText); + int Residual = ( Fr->EndPointer - Fr->NextPointer)-15; + if (TextLen > Residual) { + strcpy(Fr->NextPointer,"WRAP"); + Fr->WrapPointer = Fr->NextPointer + 5; + Fr->NextPointer = Fr->StartPointer; + } + strcpy(Fr->NextPointer,LogText); + Fr->NextPointer += TextLen+1; + strcpy(Fr->NextPointer,"<="); +} +/************************************************************************ + * Build the log text, support variable args. + ************************************************************************/ +void fr_Log_Entry(struct flightRecorder* LogFr, const char *fmt, ...) +{ + va_list arg_ptr; + spin_lock(&Fr_Lock); + + fr_Log_Time(LogFr); + va_start(arg_ptr, fmt); + vsprintf(LogText+LogTextIndex, fmt, arg_ptr); + va_end(arg_ptr); + fr_Log_Data(LogFr); + + spin_unlock(&Fr_Lock); + +} +/************************************************************************ + * Dump Flight Recorder into buffer. + * -> Handles the buffer wrapping. + ************************************************************************/ +int fr_Dump(FlightRecorder* Fr, char *Buffer, int BufferLen) +{ + int LineLen = 0; + char* StartEntry; + char* EndEntry; + spin_lock(&Fr_Lock); + /**************************************************************** + * If Buffer has wrapped, find last usable entry to start with. + ****************************************************************/ + if (Fr->WrapPointer != NULL) { + StartEntry = Fr->NextPointer+3; + StartEntry += strlen(StartEntry)+1; + EndEntry = Fr->WrapPointer; + + while (EndEntry > StartEntry && LineLen < BufferLen) { + LineLen += sprintf(Buffer+LineLen,"%s\n",StartEntry); + StartEntry += strlen(StartEntry) + 1; + } + } + + /**************************************************************** + * Dump from the beginning to the last logged entry + ****************************************************************/ + StartEntry = Fr->StartPointer; + EndEntry = Fr->NextPointer; + while (EndEntry > StartEntry && LineLen < BufferLen) { + LineLen += sprintf(Buffer+LineLen,"%s\n",StartEntry); + StartEntry += strlen(StartEntry) + 1; + } + spin_unlock(&Fr_Lock); + return LineLen; +} + +/************************************************************************ + * Allocate and Initialized the Flight Recorder + * -> If no FlightRecorder pointer is passed, the space is kmalloc. + ************************************************************************/ +FlightRecorder* alloc_Flight_Recorder(FlightRecorder* FrPtr, char* Signature, int SizeOfFr) +{ + FlightRecorder* Fr = FrPtr; /* Pointer to Object */ + int FrSize = (SizeOfFr/16)*16; /* Could be static */ + if (Fr == NULL) + Fr = (FlightRecorder*)kmalloc(SizeOfFr, GFP_KERNEL); + memset(Fr,0,SizeOfFr); + strcpy(Fr->Signature,Signature); + Fr->Size = FrSize; + Fr->Flags = 0; + Fr->StartPointer = (char*)&Fr->Buffer; + Fr->EndPointer = (char*)Fr + Fr->Size; + Fr->NextPointer = Fr->StartPointer; + + fr_Log_Entry(Fr,"Initialized."); + return Fr; +} diff -urN linux-2.4.18/arch/ppc64/kernel/head.S linux-2.4.19-pre5/arch/ppc64/kernel/head.S --- linux-2.4.18/arch/ppc64/kernel/head.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/head.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1849 @@ +/* + * arch/ppc64/kernel/head.S + * + * + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * 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. + * + */ + +#define SECONDARY_PROCESSORS + +#include "ppc_asm.h" +#include "ppc_defs.h" +#include +#include +#include +#include + +#ifdef CONFIG_PPC_ISERIES +#define DO_SOFT_DISABLE +#endif + +/* + * We layout physical memory as follows: + * 0x0000 - 0x00ff : Secondary processor spin code + * 0x0100 - 0x2fff : pSeries Interrupt prologs + * 0x3000 - 0x3fff : Interrupt support + * 0x4000 - 0x4fff : NACA + * 0x5000 - 0x5fff : Initial segment table + * 0x6000 : iSeries and common interrupt prologs + * + */ + +/* + * SPRG Usage + * + * Register Definition + * + * SPRG0 reserved for hypervisor + * SPRG1 temp - used to save gpr + * SPRG2 temp - used to save gpr + * SPRG3 virt addr of Paca + */ + +/* + * Entering into this code we make the following assumptions: + * For pSeries: + * 1. The MMU is off & open firmware is running in real mode. + * 2. The kernel is entered at __start + * + * For iSeries: + * 1. The MMU is on (as it always is for iSeries) + * 2. The kernel is entered at SystemReset_Iseries + */ + + .text + .globl _stext +_stext: +_STATIC(__start) + b .__start_initialization_pSeries + + /* At offset 0x20, there is a pointer to iSeries LPAR data. + * This is required by the hypervisor */ + . = 0x20 + .llong hvReleaseData-KERNELBASE + + /* At offset 0x28 and 0x30 are offsets to the msChunks + * array (used by the iSeries LPAR debugger to do translation + * between physical addresses and absolute addresses) and + * to the pidhash table (also used by the debugger) */ + .llong msChunks-KERNELBASE + .llong pidhash-KERNELBASE + + /* Offset 0x38 - Pointer to start of embedded System.map */ + .globl embedded_sysmap_start +embedded_sysmap_start: + .llong 0 + /* Offset 0x40 - Pointer to end of embedded System.map */ + .globl embedded_sysmap_end +embedded_sysmap_end: + .llong 0 + + /* Secondary processors spin on this value until it goes to 1. */ + .globl __secondary_hold_spinloop +__secondary_hold_spinloop: + .llong 0x0 + + /* Secondary processors write this value with their cpu # */ + /* after they enter the spin loop immediatly below. */ + .globl __secondary_hold_acknowledge +__secondary_hold_acknowledge: + .llong 0x0 + + . = 0x60 +/* + * The following code is used on pSeries to hold secondary processors + * in a spin loop after they have been freed from OpenFirmware, but + * before the bulk of the kernel has been relocated. This code + * is relocated to physical address 0x60 before prom_init is run. + * All of it must fit below the first exception vector at 0x100. + */ +_GLOBAL(__secondary_hold) + /* Grab our linux cpu number */ + mr r24,r3 + + /* Tell the master cpu we're here */ + /* Relocation is off & we are located at an address less */ + /* than 0x100, so only need to grab low order offset. */ + std r24,__secondary_hold_acknowledge@l(0) + + /* All secondary cpu's wait here until told to start. */ +100: ld r4,__secondary_hold_spinloop@l(0) + cmpdi 0,r4,1 + bne 100b + +#ifdef CONFIG_HMT + b .hmt_init +#else +#ifdef CONFIG_SMP + mr r3,r24 + b .pseries_secondary_smp_init +#else + BUG_OPCODE +#endif +#endif + +/* + * The following macros define the code that appears as + * the prologue to each of the exception handlers. They + * are split into two parts to allow a single kernel binary + * to be used for pSeries, and iSeries. + */ + +/* + * We make as much of the exception code common between native Pseries + * and Iseries LPAR implementations as possible. + */ + +/* + * This is the start of the interrupt handlers for Pseries + * This code runs with relocation off. + */ +#define EX_SRR0 0 +#define EX_SRR1 8 +#define EX_R20 16 +#define EX_R21 24 +#define EX_R22 32 +#define EX_R23 40 +#define EX_DAR 48 +#define EX_DSISR 56 + +#define EXCEPTION_PROLOG_PSERIES(label) \ + mtspr SPRG2,r20; /* use SPRG2 as scratch reg */ \ + mtspr SPRG1,r21; /* save r21 */ \ + mfspr r20,SPRG3; /* get Paca virt addr */ \ + ld r21,PACAEXCSP(r20); /* get exception stack ptr */ \ + addi r21,r21,EXC_FRAME_SIZE; /* make exception frame */ \ + std r22,EX_R22(r21); /* Save r22 in exc. frame */ \ + std r23,EX_R23(r21); /* Save r23 in exc. frame */ \ + mfspr r22,SRR0; /* EA of interrupted instr */ \ + std r22,EX_SRR0(r21); /* Save SRR0 in exc. frame */ \ + mfspr r23,SRR1; /* machine state at interrupt */ \ + std r23,EX_SRR1(r21); /* Save SRR1 in exc. frame */ \ + clrrdi r22,r20,60; /* Get 0xc part of the vaddr */ \ + ori r22,r22,(label)@l; /* add in the vaddr offset */ \ + /* assumes *_common < 16b */ \ + mfmsr r23; \ + rotldi r23,r23,4; \ + ori r23,r23,0x30B; /* Set IR, DR, SF, ISF, HV */ \ + rotldi r23,r23,60; /* for generic handlers */ \ + mtspr SRR0,r22; \ + mtspr SRR1,r23; \ + mfcr r23; /* save CR in r23 */ \ + rfid + +/* + * This is the start of the interrupt handlers for i_series + * This code runs with relocation on. + */ +#define EXCEPTION_PROLOG_ISERIES \ + mtspr SPRG2,r20; /* use SPRG2 as scratch reg */\ + mtspr SPRG1,r21; /* save r21 */\ + mfspr r20,SPRG3; /* get Paca */\ + ld r21,PACAEXCSP(r20); /* get exception stack ptr */\ + addi r21,r21,EXC_FRAME_SIZE; /* make exception frame */\ + std r22,EX_R22(r21); /* save r22 on exception frame */\ + std r23,EX_R23(r21); /* Save r23 in exc. frame */\ + ld r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\ + std r22,EX_SRR0(r21); /* save SRR0 in exc. frame */\ + ld r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */\ + std r23,EX_SRR1(r21); /* save SRR1 in exc. frame */\ + mfcr r23; /* save CR in r23 */ + +/* + * The common exception prolog is used for all except a few exceptions + * such as a segment miss on a kernel address. We have to be prepared + * to take another exception from the point where we first touch the + * kernel stack onwards. + * + * On entry r20 points to the paca and r21 points to the exception + * frame on entry, r23 contains the saved CR, and relocation is on. + */ +#define EXCEPTION_PROLOG_COMMON \ + mfspr r22,SPRG2; /* Save r20 in exc. frame */ \ + std r22,EX_R20(r21); \ + mfspr r22,SPRG1; /* Save r21 in exc. frame */ \ + std r22,EX_R21(r21); \ + mfspr r22,DAR; /* Save DAR in exc. frame */ \ + std r22,EX_DAR(r21); \ + std r21,PACAEXCSP(r20); /* update exception stack ptr */ \ + /* iff no protection flt */ \ + mfspr r22,DSISR; /* Save DSISR in exc. frame */ \ + std r22,EX_DSISR(r21); \ + ld r22,EX_SRR1(r21); /* Get SRR1 from exc. frame */ \ + andi. r22,r22,MSR_PR; /* Set CR for later branch */ \ + mr r22,r1; /* Save r1 */ \ + subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ + beq- 1f; \ + ld r1,PACAKSAVE(r20); /* kernel stack to use */ \ +1: std r22,GPR1(r1); /* save r1 in stackframe */ \ + std r22,0(r1); /* make stack chain pointer */ \ + std r23,_CCR(r1); /* save CR in stackframe */ \ + ld r22,EX_R20(r21); /* move r20 to stackframe */ \ + std r22,GPR20(r1); \ + ld r23,EX_R21(r21); /* move r21 to stackframe */ \ + std r23,GPR21(r1); \ + ld r22,EX_R22(r21); /* move r22 to stackframe */ \ + std r22,GPR22(r1); \ + ld r23,EX_R23(r21); /* move r23 to stackframe */ \ + std r23,GPR23(r1); \ + mflr r22; /* save LR in stackframe */ \ + std r22,_LINK(r1); \ + mfctr r23; /* save CTR in stackframe */ \ + std r23,_CTR(r1); \ + mfspr r22,XER; /* save XER in stackframe */ \ + std r22,_XER(r1); \ + ld r23,EX_DAR(r21); /* move DAR to stackframe */ \ + std r23,_DAR(r1); \ + ld r22,EX_DSISR(r21); /* move DSISR to stackframe */ \ + std r22,_DSISR(r1); \ + lbz r22,PACAPROCENABLED(r20); \ + std r22,SOFTE(r1); \ + ld r22,EX_SRR0(r21); /* get SRR0 from exc. frame */ \ + ld r23,EX_SRR1(r21); /* get SRR1 from exc. frame */ \ + addi r21,r21,-EXC_FRAME_SIZE;/* pop off exception frame */ \ + std r21,PACAEXCSP(r20); \ + SAVE_GPR(0, r1); /* save r0 in stackframe */ \ + SAVE_8GPRS(2, r1); /* save r2 - r13 in stackframe */ \ + SAVE_4GPRS(10, r1); \ + ld r2,PACATOC(r20); \ + ld r13,PACACURRENT(r20) + +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r1, r22 (SRR0), and r23 (SRR1). + */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION_PSERIES(n, label ) \ + . = n; \ + .globl label##_Pseries; \ +label##_Pseries: \ + EXCEPTION_PROLOG_PSERIES( label##_common ) + +#define STD_EXCEPTION_ISERIES( label ) \ + .globl label##_Iseries; \ +label##_Iseries: \ + EXCEPTION_PROLOG_ISERIES; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES( label ) \ + .globl label##_Iseries; \ +label##_Iseries: \ + EXCEPTION_PROLOG_ISERIES; \ + lbz r22,PACAPROFENABLED(r20); \ + cmpi 0,r22,0; \ + bne- label##_Iseries_profile; \ +label##_Iseries_prof_ret: \ + lbz r22,PACAPROCENABLED(r20); \ + cmpi 0,r22,0; \ + beq- label##_Iseries_masked; \ + b label##_common; \ +label##_Iseries_profile: \ + std r24,48(r21); \ + std r25,56(r21); \ + mflr r24; \ + bl do_profile; \ + mtlr r24; \ + ld r24,48(r21); \ + ld r25,56(r21); \ + b label##_Iseries_prof_ret + +#define STD_EXCEPTION_COMMON( trap, label, hdlr ) \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,0; \ + li r6,trap; \ + bl .save_remaining_regs; \ + bl hdlr; \ + b .ret_from_except + +/* + * Start of pSeries system interrupt routines + */ + . = 0x100 + .globl __start_interupts +__start_interupts: + + STD_EXCEPTION_PSERIES( 0x100, SystemReset ) + STD_EXCEPTION_PSERIES( 0x200, MachineCheck ) + STD_EXCEPTION_PSERIES( 0x300, DataAccess ) + STD_EXCEPTION_PSERIES( 0x380, DataAccessSLB ) + STD_EXCEPTION_PSERIES( 0x400, InstructionAccess ) + STD_EXCEPTION_PSERIES( 0x480, InstructionAccessSLB ) + STD_EXCEPTION_PSERIES( 0x500, HardwareInterrupt ) + STD_EXCEPTION_PSERIES( 0x600, Alignment ) + STD_EXCEPTION_PSERIES( 0x700, ProgramCheck ) + STD_EXCEPTION_PSERIES( 0x800, FPUnavailable ) + STD_EXCEPTION_PSERIES( 0x900, Decrementer ) + STD_EXCEPTION_PSERIES( 0xa00, Trap_0a ) + STD_EXCEPTION_PSERIES( 0xb00, Trap_0b ) + STD_EXCEPTION_PSERIES( 0xc00, SystemCall ) + STD_EXCEPTION_PSERIES( 0xd00, SingleStep ) + STD_EXCEPTION_PSERIES( 0xe00, Trap_0e ) + STD_EXCEPTION_PSERIES( 0xf00, PerformanceMonitor ) + STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint ) + + . = 0x4000 + .globl __end_interupts + .globl __start_naca +__end_interupts: +__start_naca: + /* Save space for naca. + * The first dword of the Naca is required by iSeries LPAR to + * point to itVpdAreas. On pSeries native, this value is not used. + */ + .llong itVpdAreas + .llong 0x0 + .llong 0x0 + .llong xPaca + + /* + * Space for the initial segment table + * For LPAR, the hypervisor must fill in at least one entry + * before we get control (with relocate on) + */ + + . = 0x5000 + .globl __end_naca + .globl __start_stab +__end_naca: +__start_stab: + + + . = 0x6000 + .globl __end_stab +__end_stab: + + /* + * The iSeries LPAR map is at this fixed address + * so that the HvReleaseData structure can address + * it with a 32-bit offset. + * + * The VSID values below are dependent on the + * VSID generation algorithm. See include/asm/mmu_context.h. + */ + + .llong 1 /* # ESIDs to be mapped by hypervisor */ + .llong 1 /* # memory ranges to be mapped by hypervisor */ + .llong 5 /* Page # of segment table within load area */ + .llong 0 /* Reserved */ + .llong 0 /* Reserved */ + .llong 0 /* Reserved */ + .llong 0 /* Reserved */ + .llong 0 /* Reserved */ + .llong 0x0c00000000 /* ESID to map (Kernel at EA = 0xC000000000000000) */ + .llong 0x06a99b4b14 /* VSID to map (Kernel at VA = 0x6a99b4b140000000) */ + .llong 8192 /* # pages to map (32 MB) */ + .llong 0 /* Offset from start of loadarea to start of map */ + .llong 0x0006a99b4b140000 /* VPN of first page to map */ + + . = 0x6100 + +/*** ISeries-LPAR interrupt handlers ***/ + + STD_EXCEPTION_ISERIES( MachineCheck ) + STD_EXCEPTION_ISERIES( DataAccess ) + STD_EXCEPTION_ISERIES( DataAccessSLB ) + STD_EXCEPTION_ISERIES( InstructionAccess ) + STD_EXCEPTION_ISERIES( InstructionAccessSLB ) + MASKABLE_EXCEPTION_ISERIES( HardwareInterrupt ) + STD_EXCEPTION_ISERIES( Alignment ) + STD_EXCEPTION_ISERIES( ProgramCheck ) + STD_EXCEPTION_ISERIES( FPUnavailable ) + MASKABLE_EXCEPTION_ISERIES( Decrementer ) + STD_EXCEPTION_ISERIES( Trap_0a ) + STD_EXCEPTION_ISERIES( Trap_0b ) + STD_EXCEPTION_ISERIES( SystemCall ) + STD_EXCEPTION_ISERIES( SingleStep ) + STD_EXCEPTION_ISERIES( Trap_0e ) + STD_EXCEPTION_ISERIES( PerformanceMonitor ) + + .globl SystemReset_Iseries +SystemReset_Iseries: + mfspr 25,SPRG3 /* Get Paca address */ + lhz r24,PACAPACAINDEX(r25) /* Get processor # */ + cmpi 0,r24,0 /* Are we processor 0? */ + beq .__start_initialization_iSeries /* Start up the first processor */ + mfspr r4,CTRLF + li r5,RUNLATCH /* Turn off the run light */ + andc r4,r4,r5 + mtspr CTRLT,r4 + +1: + HMT_LOW +#ifdef CONFIG_SMP + lbz r23,PACAPROCSTART(r25) /* Test if this processor + * should start */ + sync + LOADADDR(r3,current_set) + sldi r28,r24,4 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,TASK_UNION_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpi 0,r23,0 + beq iseries_secondary_smp_loop /* Loop until told to go */ +#ifdef SECONDARY_PROCESSORS + bne .__secondary_start /* Loop until told to go */ +#endif +iseries_secondary_smp_loop: + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ +#else /* CONFIG_SMP */ + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ +#endif /* CONFIG_SMP */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r25,SPRG3 /* Put r25 back ???? */ + b 1b /* If SMP not configured, secondaries + * loop forever */ + + .globl HardwareInterrupt_Iseries_masked +HardwareInterrupt_Iseries_masked: + b maskable_exception_exit + + .globl Decrementer_Iseries_masked +Decrementer_Iseries_masked: + li r22,1 + stb r22,PACALPPACA+LPPACADECRINT(r20) + lwz r22,PACADEFAULTDECR(r20) + mtspr DEC,r22 +maskable_exception_exit: + mtcrf 0xff,r23 /* Restore regs and free exception frame */ + ld r22,EX_SRR0(r21) + ld r23,EX_SRR1(r21) + mtspr SRR0,r22 + mtspr SRR1,r23 + ld r22,EX_R22(r21) + ld r23,EX_R23(r21) + mfspr r21,SPRG1 + mfspr r20,SPRG2 + rfid + +/*** Common interrupt handlers ***/ + + STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException ) + STD_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException ) + STD_EXCEPTION_COMMON( 0x900, Decrementer, .timer_interrupt ) + STD_EXCEPTION_COMMON( 0xa00, Trap_0a, .UnknownException ) + STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException ) + STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException ) + STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException ) + STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException ) + STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException ) + +/* + * Return from an exception which is handled without calling + * save_remaining_regs. The caller is assumed to have done + * EXCEPTION_PROLOG_COMMON. + */ +fast_exception_return: + ld r3,_CCR(r1) + ld r4,_LINK(r1) + ld r5,_CTR(r1) + ld r6,_XER(r1) + mtcr r3 + mtlr r4 + mtctr r5 + mtspr XER,r6 + REST_GPR(0, r1) + REST_8GPRS(2, r1) + REST_4GPRS(10, r1) + mtspr SRR1,r23 + mtspr SRR0,r22 + REST_4GPRS(20, r1) + ld r1,GPR1(r1) + rfid + + +/* + * Here r20 points to the PACA, r21 to the exception frame, + * r23 contains the saved CR. + * r20 - r23, SRR0 and SRR1 are saved in the exception frame. + */ + .globl DataAccess_common +DataAccess_common: + mfspr r22,DAR + srdi r22,r22,60 + cmpi 0,r22,0xc + + /* Segment fault on a bolted segment. Go off and map that segment. */ + beq .do_stab_bolted +stab_bolted_user_return: + EXCEPTION_PROLOG_COMMON + ld r3,_DSISR(r1) + andis. r0,r3,0xa450 /* weird error? */ + bne 1f /* if not, try to put a PTE */ + andis. r0,r3,0x0020 /* Is it a page table fault? */ + rlwinm r4,r3,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ + ld r3,_DAR(r1) /* into the hash table */ + + beq 2f /* If so handle it */ + li r4,0x300 /* Trap number */ + bl .do_stab_SI + b 1f + +2: bl .do_hash_page_DSI /* Try to handle as hpte fault */ +1: + ld r4,_DAR(r1) + ld r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) /* Copy saved SOFTE bit */ +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x300 + bl .save_remaining_regs + bl .do_page_fault + b .ret_from_except + + .globl DataAccessSLB_common +DataAccessSLB_common: + mfspr r22,DAR + srdi r22,r22,60 + cmpi 0,r22,0xc + + /* Segment fault on a bolted segment. Go off and map that segment. */ + beq .do_slb_bolted + + EXCEPTION_PROLOG_COMMON + ld r3,_DAR(r1) + li r4,0x380 /* Exception vector */ + bl .ste_allocate + or. r3,r3,r3 /* Check return code */ + beq fast_exception_return /* Return if we succeeded */ + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x380 + bl .save_remaining_regs + bl .do_page_fault + b .ret_from_except + + .globl InstructionAccess_common +InstructionAccess_common: + EXCEPTION_PROLOG_COMMON + + andis. r0,r23,0x0020 /* no ste found? */ + beq 2f + mr r3,r22 /* SRR0 at interrupt */ + li r4,0x400 /* Trap number */ + bl .do_stab_SI + b 1f + +2: andis. r0,r23,0x4000 /* no pte found? */ + beq 1f /* if so, try to put a PTE */ + mr r3,r22 /* into the hash table */ + bl .do_hash_page_ISI /* Try to handle as hpte fault */ +1: + mr r4,r22 + mr r5,r23 + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x400 + bl .save_remaining_regs + bl .do_page_fault + b .ret_from_except + + .globl InstructionAccessSLB_common +InstructionAccessSLB_common: + EXCEPTION_PROLOG_COMMON + mr r3,r22 /* SRR0 = NIA */ + li r4,0x480 /* Exception vector */ + bl .ste_allocate + or. r3,r3,r3 /* Check return code */ + beq fast_exception_return /* Return if we succeeded */ + + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x380 + bl .save_remaining_regs + bl .do_page_fault + b .ret_from_except + + .globl HardwareInterrupt_common +HardwareInterrupt_common: + EXCEPTION_PROLOG_COMMON +HardwareInterrupt_entry: + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,0 + li r6,0x500 + bl .save_remaining_regs + /* Determine if need to run do_irq on a hardware interrupt stack */ + /* The first invocation of do_irq will occur on the kernel */ + /* stack in the current stack */ + /* All other invocations of do_irq will run on the hardware */ + /* interrupt stack associated with the PACA of the current */ + /* processor. */ + /* */ + /* The call to do_irq will preserve the value of r14 - r31 */ + /* */ + mfspr r20,SPRG3 /* get Paca */ + lbz r21,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */ + cmpi 0,r21,1 /* */ + addi r21,r21,1 /* incr hardware interrupt cnt*/ + stb r21,PACAHRDWINTCOUNT(r20) /* */ + bne 2f /* */ + + mr r14,r1 /* preserve current r1 */ + ld r1,PACAHRDWINTSTACK(r20) /* */ + std r14,0(r1) /* set the back chain */ + bl .do_IRQ + lbz r22,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */ + cmp 0,r22,r21 /* debug test */ + bne 3f + subi r21,r21,1 + stb r21,PACAHRDWINTCOUNT(r20) /* */ + mr r1,r14 /* */ + b .ret_from_except + +2: + bl .do_IRQ + + lbz r22,PACAHRDWINTCOUNT(r20) /* get hardware interrupt cnt */ + cmp 0,r22,r21 /* debug test */ + bne 3f /* */ + subi r21,r21,1 /* decr hardware interrupt cnt*/ + stb r21,PACAHRDWINTCOUNT(r20) /* */ + + b .ret_from_except + +3: + /* error - counts out of sync */ +#ifdef CONFIG_XMON + bl .xmon +#endif +4: b 4b + + + .globl Alignment_common +Alignment_common: + EXCEPTION_PROLOG_COMMON + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x600 + bl .save_remaining_regs + bl .AlignmentException + b .ret_from_except + + .globl ProgramCheck_common +ProgramCheck_common: + EXCEPTION_PROLOG_COMMON + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0x700 + bl .save_remaining_regs + bl .ProgramCheckException + b .ret_from_except + + .globl FPUnavailable_common +FPUnavailable_common: + EXCEPTION_PROLOG_COMMON + bne .load_up_fpu /* if from user, just load it up */ + li r20,0 + li r6,0x800 + bl .save_remaining_regs /* if from kernel, take a trap */ + bl .KernelFP + b .ret_from_except + + .globl SystemCall_common +SystemCall_common: + EXCEPTION_PROLOG_COMMON +#ifdef CONFIG_PPC_ISERIES + cmpi 0,r0,0x5555 /* Special syscall to handle pending */ + bne+ 1f /* interrupts */ + andi. r6,r23,MSR_PR /* Only allowed from kernel */ + beq+ HardwareInterrupt_entry +1: +#endif + std r3,ORIG_GPR3(r1) +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif + li r6,0xC00 + bl .save_remaining_regs + bl .DoSyscall + b .ret_from_except + +_GLOBAL(do_hash_page_ISI) + li r4,0 +_GLOBAL(do_hash_page_DSI) + rlwimi r4,r23,32-13,30,30 /* Insert MSR_PR as _PAGE_USER */ + ori r4,r4,1 /* add _PAGE_PRESENT */ + + mflr r21 /* Save LR in r21 */ + +#ifdef DO_SOFT_DISABLE + /* + * We hard enable here (but first soft disable) so that the hash_page + * code can spin on the hash_table_lock with problem on a shared + * processor. + */ + li r0,0 + stb r0,PACAPROCENABLED(r20) /* Soft Disabled */ + + mfmsr r0 + ori r0,r0,MSR_EE+MSR_RI + mtmsrd r0 /* Hard Enable, RI on */ +#endif + + /* + * r3 contains the faulting address + * r4 contains the required access permissions + * + * at return r3 = 0 for success + */ + + bl .hash_page /* build HPTE if possible */ + +#ifdef DO_SOFT_DISABLE + /* + * Now go back to hard disabled. + */ + mfmsr r0 + li r4,0 + ori r4,r4,MSR_EE+MSR_RI + andc r0,r0,r4 + mtmsrd r0 /* Hard Disable, RI off */ + + ld r0,SOFTE(r1) + cmpdi 0,r0,0 /* See if we will soft enable in */ + /* save_remaining_regs */ + beq 5f + CHECKANYINT(r4,r5) + bne- HardwareInterrupt_entry /* Convert this DSI into an External */ + /* to process interrupts which occurred */ + /* during hash_page */ +5: + stb r0,PACAPROCENABLED(r20) /* Restore soft enable/disable status */ +#endif + or. r3,r3,r3 /* Check return code */ + beq fast_exception_return /* Return from exception on success */ + + mtlr r21 /* restore LR */ + blr /* Return to DSI or ISI on failure */ + +/* + * r20 points to the PACA, r21 to the exception frame, + * r23 contains the saved CR. + * r20 - r23, SRR0 and SRR1 are saved in the exception frame. + * We assume we aren't going to take any exceptions during this procedure. + */ +_GLOBAL(do_stab_bolted) + std r23,EX_DAR(r21) /* save CR in exc. frame */ + + mfspr r22,DSISR + andis. r22,r22,0x0020 + bne+ 2f + ld r22,8(r21) /* get SRR1 */ + andi. r22,r22,MSR_PR /* check if from user */ + bne+ stab_bolted_user_return /* from user, send the error on up */ + li r3,0 +#ifdef CONFIG_XMON + bl .xmon +#endif +1: b 1b +2: + /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ + mfspr r21,DAR + rldicl r20,r21,36,32 /* Permits a full 32b of ESID */ + rldicr r20,r20,15,48 + rldicl r21,r21,4,60 + or r20,r20,r21 + + li r21,9 /* VSID_RANDOMIZER */ + sldi r21,r21,32 + oris r21,r21,58231 + ori r21,r21,39831 + + mulld r20,r20,r21 + clrldi r20,r20,28 /* r20 = vsid */ + + mfsprg r21,3 + ld r21,PACASTABVIRT(r21) + + /* Hash to the primary group */ + mfspr r22,DAR + rldicl r22,r22,36,59 + rldicr r22,r22,7,56 + or r21,r21,r22 /* r21 = first ste of the group */ + + /* Search the primary group for a free entry */ + li r22,0 +1: + ld r23,0(r21) /* Test valid bit of the current ste */ + rldicl r23,r23,57,63 + cmpwi r23,0 + bne 2f + ld r23,8(r21) /* Get the current vsid part of the ste */ + rldimi r23,r20,12,0 /* Insert the new vsid value */ + std r23,8(r21) /* Put new entry back into the stab */ + eieio /* Order vsid update */ + ld r23,0(r21) /* Get the esid part of the ste */ + mfspr r20,DAR /* Get the new esid */ + rldicl r20,r20,36,28 /* Permits a full 36b of ESID */ + rldimi r23,r20,28,0 /* Insert the new esid value */ + ori r23,r23,144 /* Turn on valid and kp */ + std r23,0(r21) /* Put new entry back into the stab */ + sync /* Order the update */ + b 3f +2: + addi r22,r22,1 + addi r21,r21,16 + cmpldi r22,7 + ble 1b + + /* Stick for only searching the primary group for now. */ + /* At least for now, we use a very simple random castout scheme */ + /* Use the TB as a random number ; OR in 1 to avoid entry 0 */ + mftb r22 + andi. r22,r22,7 + ori r22,r22,1 + sldi r22,r22,4 + + /* r21 currently points to and ste one past the group of interest */ + /* make it point to the randomly selected entry */ + subi r21,r21,128 + or r21,r21,r22 /* r21 is the entry to invalidate */ + + isync /* mark the entry invalid */ + ld r23,0(r21) + li r22,-129 + and r23,r23,r22 + std r23,0(r21) + sync + + ld r23,8(r21) + rldimi r23,r20,12,0 + std r23,8(r21) + eieio + + ld r23,0(r21) /* Get the esid part of the ste */ + mr r22,r23 + mfspr r20,DAR /* Get the new esid */ + rldicl r20,r20,36,28 /* Permits a full 32b of ESID */ + rldimi r23,r20,28,0 /* Insert the new esid value */ + ori r23,r23,144 /* Turn on valid and kp */ + std r23,0(r21) /* Put new entry back into the stab */ + + rldicl r22,r22,36,28 + rldicr r22,r22,28,35 + slbie r22 + sync + +3: + /* All done -- return from exception. */ + mfsprg r20,3 /* Load the PACA pointer */ + ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */ + addi r21,r21,EXC_FRAME_SIZE + ld r23,EX_DAR(r21) /* get saved CR */ + /* note that this is almost identical to maskable_exception_exit */ + mtcr r23 /* restore CR */ + ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */ + ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */ + mtspr SRR0,r22 + mtspr SRR1,r23 + ld r22,EX_R22(r21) /* restore r22 and r23 */ + ld r23,EX_R23(r21) + mfspr r20,SPRG2 + mfspr r21,SPRG1 + rfid +_TRACEBACK(do_stab_bolted) + +/* + * r20 points to the PACA, r21 to the exception frame, + * r23 contains the saved CR. + * r20 - r23, SRR0 and SRR1 are saved in the exception frame. + * We assume we aren't going to take any exceptions during this procedure. + */ +_GLOBAL(do_slb_bolted) + std r23,48(r21) /* save CR in exc. frame */ + + /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ + mfspr r21,DAR + rldicl r20,r21,36,32 /* Permits a full 32b of ESID */ + rldicr r20,r20,15,48 + rldicl r21,r21,4,60 + or r20,r20,r21 + + li r21,9 /* VSID_RANDOMIZER */ + sldi r21,r21,32 + oris r21,r21,58231 + ori r21,r21,39831 + + mulld r20,r20,r21 + clrldi r20,r20,28 /* r20 = vsid */ + + /* Search the SLB for a free entry */ + li r22,1 +1: + slbmfee r23,r22 + rldicl r23,r23,37,63 + cmpwi r23,0 + beq 3f /* Found an invalid entry */ + + addi r22,r22,1 + cmpldi r22,64 + blt 1b + + /* No free entry - just take the next entry, round-robin */ + /* XXX we should get the number of SLB entries from the naca */ +SLB_NUM_ENTRIES = 64 + mfspr r21,SPRG3 + ld r22,PACASTABRR(r21) + addi r23,r22,1 + cmpdi r23,SLB_NUM_ENTRIES + blt 2f + li r23,1 +2: std r23,PACASTABRR(r21) + + /* r20 = vsid, r22 = entry */ +3: + /* Put together the vsid portion of the entry. */ + li r21,0 + rldimi r21,r20,12,0 + ori r20,r21,1024 +#ifndef CONFIG_PPC_ISERIES + ori r20,r20,256 /* map kernel region with large ptes */ +#endif + + /* Put together the esid portion of the entry. */ + mfspr r21,DAR /* Get the new esid */ + rldicl r21,r21,36,28 /* Permits a full 36b of ESID */ + li r23,0 + rldimi r23,r21,28,0 /* Insert esid */ + oris r21,r23,2048 /* valid bit */ + rldimi r21,r22,0,52 /* Insert entry */ + + isync + slbmte r20,r21 + isync + + /* All done -- return from exception. */ + mfsprg r20,3 /* Load the PACA pointer */ + ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */ + addi r21,r21,EXC_FRAME_SIZE + ld r23,EX_DAR(r21) /* get saved CR */ + /* note that this is almost identical to maskable_exception_exit */ + mtcr r23 /* restore CR */ + ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */ + ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */ + mtspr SRR0,r22 + mtspr SRR1,r23 + ld r22,EX_R22(r21) /* restore r22 and r23 */ + ld r23,EX_R23(r21) + mfspr r20,SPRG2 + mfspr r21,SPRG1 + rfid +_TRACEBACK(do_slb_bolted) + +_GLOBAL(do_stab_SI) + mflr r21 /* Save LR in r21 */ + + /* + * r3 contains the faulting address + * r4 contains the required access permissions + * + * at return r3 = 0 for success + */ + + bl .ste_allocate /* build STE if possible */ + or. r3,r3,r3 /* Check return code */ + beq fast_exception_return /* Return from exception on success */ + mtlr r21 /* restore LR */ + blr /* Return to DSI or ISI on failure */ + +/* + * This code finishes saving the registers to the exception frame. + * Address translation is already on. + */ +_GLOBAL(save_remaining_regs) + /* + * Save the rest of the registers into the pt_regs structure + */ + std r22,_NIP(r1) + std r23,_MSR(r1) + std r6,TRAP(r1) + ld r6,GPR6(r1) + SAVE_2GPRS(14, r1) + SAVE_4GPRS(16, r1) + SAVE_8GPRS(24, r1) + + /* + * Clear the RESULT field + */ + li r22,0 + std r22,RESULT(r1) + + /* + * Test if from user state; result will be tested later + */ + andi. r23,r23,MSR_PR /* Set CR for later branch */ + + /* + * Indicate that r1 contains the kernel stack and + * get the Kernel TOC and CURRENT pointers from the Paca + */ + mfspr r23,SPRG3 /* Get PACA */ + std r22,PACAKSAVE(r23) /* r1 is now kernel sp */ + ld r2,PACATOC(r23) /* Get Kernel TOC pointer */ + + /* + * If from user state, update THREAD.regs + */ + beq 2f /* Modify THREAD.regs if from user */ + addi r24,r1,STACK_FRAME_OVERHEAD + std r24,THREAD+PT_REGS(r13) +2: + SET_REG_TO_CONST(r22, MSR_KERNEL) + +#ifdef DO_SOFT_DISABLE + stb r20,PACAPROCENABLED(r23) /* possibly soft enable */ + ori r22,r22,MSR_EE /* always hard enable */ +#else + rldimi r22,r20,15,48 /* Insert desired EE value */ +#endif + + mtmsrd r22 + blr + + +do_profile: + ld r22,8(r21) /* Get SRR1 */ + andi. r22,r22,MSR_PR /* Test if in kernel */ + bnelr /* return if not in kernel */ + ld r22,0(r21) /* Get SRR0 */ + ld r25,PACAPROFSTEXT(r20) /* _stext */ + subf r22,r25,r22 /* offset into kernel */ + lwz r25,PACAPROFSHIFT(r20) + srd r22,r22,r25 + lwz r25,PACAPROFLEN(r20) /* length of profile table (-1) */ + cmp 0,r22,r25 /* off end? */ + ble 1f + mr r22,r25 /* force into last entry */ +1: sldi r22,r22,2 /* convert to offset into buffer */ + ld r25,PACAPROFBUFFER(r20) /* profile buffer */ + add r25,r25,r22 +2: lwarx r22,0,r25 /* atomically increment */ + addi r22,r22,1 + stwcx. r22,0,r25 + bne- 2b + blr + + +/* + * On pSeries, secondary processors spin in the following code. + * At entry, r3 = this processor's number (in Linux terms, not hardware). + */ +_GLOBAL(pseries_secondary_smp_init) + + /* turn on 64-bit mode */ + bl .enable_64b_mode + isync + + /* Set up a Paca value for this processor. */ + LOADADDR(r24, xPaca) /* Get base vaddr of Paca array */ + mulli r25,r3,PACA_SIZE /* Calculate vaddr of right Paca */ + add r25,r25,r24 /* for this processor. */ + + mtspr SPRG3,r25 /* Save vaddr of Paca in SPRG3 */ + mr r24,r3 /* __secondary_start needs cpu# */ + +1: + HMT_LOW + lbz r23,PACAPROCSTART(r25) /* Test if this processor should */ + /* start. */ + sync + + /* Create a temp kernel stack for use before relocation is on. */ + mr r1,r25 + addi r1,r1,PACAGUARD + addi r1,r1,0x1000 + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpi 0,r23,0 +#ifdef CONFIG_SMP +#ifdef SECONDARY_PROCESSORS + bne .__secondary_start +#endif +#endif + b 1b /* Loop until told to go */ + +_GLOBAL(__start_initialization_iSeries) + + LOADADDR(r1,init_task_union) + addi r1,r1,TASK_UNION_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + LOADADDR(r9,naca) + SET_REG_TO_CONST(r4, KERNELBASE) + addi r4,r4,0x4000 + std r4,0(r9) /* set the naca pointer */ + + /* Get the pointer to the segment table */ + ld r6,PACA(r4) /* Get the base Paca pointer */ + ld r4,PACASTABVIRT(r6) + + bl .iSeries_fixup_klimit + + b .start_here_common + +_GLOBAL(__start_initialization_pSeries) + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + mr r26,r8 /* YABOOT: debug_print() routine */ + mr r25,r9 /* YABOOT: debug_delay() routine */ + mr r24,r10 /* YABOOT: debug_prom() routine */ + + bl .enable_64b_mode + + /* put a relocation offset into r3 */ + bl .reloc_offset + + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + /* Relocate the TOC from a virt addr to a real addr */ + sub r2,r2,r3 + + /* setup the naca pointer which is needed by prom_init */ + LOADADDR(r9,naca) + sub r9,r9,r3 /* addr of the variable naca */ + + SET_REG_TO_CONST(r4, KERNELBASE) + sub r4,r4,r3 + addi r4,r4,0x4000 + std r4,0(r9) /* set the value of naca */ + + /* DRENG / PPPBBB Fix the following comment!!! -Peter */ + /* The following copies the first 0x100 bytes of code from the */ + /* load addr to physical addr 0x0. This code causes secondary */ + /* processors to spin until a flag in the PACA is set. This */ + /* is done at this time rather than with the entire kernel */ + /* relocation which is done below because we need to cause the */ + /* processors to spin on code that is not going to move while OF */ + /* is still alive. Although the spin code is not actually run on */ + /* a uniprocessor, we always do this copy. */ + SET_REG_TO_CONST(r4, KERNELBASE)/* Src addr */ + sub r4,r4,r3 /* current address of __start */ + /* the source addr */ + li r3,0 /* Dest addr */ + li r5,0x100 /* # bytes of memory to copy */ + li r6,0 /* Destination offset */ + bl .copy_and_flush /* copy the first 0x100 bytes */ + + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + mr r8,r26 + mr r9,r25 + mr r10,r24 + + bl .prom_init + + li r24,0 /* cpu # */ + +/* + * At this point, r3 contains the physical address we are running at, + * returned by prom_init() + */ +_STATIC(__after_prom_start) + +/* + * We need to run with __start at physical address 0. + * This will leave some code in the first 256B of + * real memory, which are reserved for software use. + * The remainder of the first page is loaded with the fixed + * interrupt vectors. The next two pages are filled with + * unknown exception placeholders. + * + * Note: This process overwrites the OF exception vectors. + * r26 == relocation offset + * r27 == KERNELBASE + */ + bl .reloc_offset + mr r26,r3 + SET_REG_TO_CONST(r27,KERNELBASE) + + li r3,0 /* target addr */ + + sub r4,r27,r26 /* source addr */ + /* current address of _start */ + /* i.e. where we are running */ + /* the source addr */ + + LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */ + sub r5,r5,r27 + + li r6,0x100 /* Start offset, the first 0x100 */ + /* bytes were copied earlier. */ + + bl .copy_and_flush /* copy the first n bytes */ + /* this includes the code being */ + /* executed here. */ + + li r0,4f@l /* Jump to the copy of this code */ + mtctr r0 /* that we just made */ + bctr + +4: LOADADDR(r9,rtas) + sub r9,r9,r26 + ld r5,RTASBASE(r9) /* get the value of rtas->base */ + ld r9,RTASSIZE(r9) /* get the value of rtas->size */ + bl .copy_and_flush /* copy upto rtas->base */ + add r6,r6,r9 /* then skip over rtas->size bytes */ + + LOADADDR(r5,klimit) + sub r5,r5,r26 + ld r5,0(r5) /* get the value of klimit */ + sub r5,r5,r27 + bl .copy_and_flush /* copy the rest */ + b .start_here_pSeries + +/* + * Copy routine used to copy the kernel to start at physical address 0 + * and flush and invalidate the caches as needed. + * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset + * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. + * + * Note: this routine *only* clobbers r0, r6 and lr + */ +_STATIC(copy_and_flush) + addi r5,r5,-8 + addi r6,r6,-8 +4: li r0,16 /* Use the least common */ + /* denominator cache line */ + /* size. This results in */ + /* extra cache line flushes */ + /* but operation is correct. */ + /* Can't get cache line size */ + /* from NACA as it is being */ + /* moved too. */ + + mtctr r0 /* put # words/line in ctr */ +3: addi r6,r6,8 /* copy a cache line */ + ldx r0,r6,r4 + stdx r0,r6,r3 + bdnz 3b + dcbst r6,r3 /* write it to memory */ + sync + icbi r6,r3 /* flush the icache line */ + cmpld 0,r6,r5 + blt 4b + sync + addi r5,r5,8 + addi r6,r6,8 + blr + +.align 8 +copy_to_here: + +/* + * Disable FP for the task which had the FPU previously, + * and save its floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + * On SMP we know the fpu is free, since we give it up every + * switch. -- Cort + */ +_STATIC(load_up_fpu) + mfmsr r5 /* grab the current MSR */ + ori r5,r5,MSR_FP + mtmsrd r5 /* enable use of fpu now */ + isync +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + * + */ +#ifndef CONFIG_SMP + LOADBASE(r3,last_task_used_math) + ld r4,last_task_used_math@l(r3) + cmpi 0,r4,0 + beq 1f + addi r4,r4,THREAD /* want THREAD of last_task_used_math */ + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r4) + ld r5,PT_REGS(r4) + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r20,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r20 /* disable FP for previous task */ + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of FP after return */ + ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 + addi r5,r13,THREAD /* Get THREAD */ + lfd fr0,THREAD_FPSCR-4(r5) + mtfsf 0xff,fr0 + REST_32FPRS(0, r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD /* Back to 'current' */ + std r4,last_task_used_math@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + b fast_exception_return + +/* + * FP unavailable trap from kernel - print a message, but let + * the task use FP in the kernel until it returns to user mode. + */ +_GLOBAL(KernelFP) + ld r3,_MSR(r1) + ori r3,r3,MSR_FP + std r3,_MSR(r1) /* enable use of FP after return */ + LOADADDR(r3,86f) + mfspr r4,SPRG3 /* Get PACA */ + ld r4,PACACURRENT(r4) /* current */ + ld r5,_NIP(r1) + b .ret_from_except +86: .string "floating point used in kernel (task=%p, pc=%x)\n" + .align 4 + +/* + * giveup_fpu(tsk) + * Disable FP for the task given as the argument, + * and save the floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + */ +_GLOBAL(giveup_fpu) + mfmsr r5 + ori r5,r5,MSR_FP + mtmsrd r5 /* enable use of fpu now */ + isync + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + ld r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32FPRS(0, r3) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r3) + beq 1f + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r3 /* disable FP for previous task */ + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + LOADBASE(r4,last_task_used_math) + std r5,last_task_used_math@l(r4) +#endif /* CONFIG_SMP */ + blr + + + +#ifdef CONFIG_SMP +/* + * This function is called after the master CPU has released the + * secondary processors. The execution environment is relocation off. + * The Paca for this processor has the following fields initialized at + * this point: + * 1. Processor number + * 2. Segment table pointer (virtual address) + * On entry the following are set: + * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries + * r24 = cpu# (in Linux terms) + * r25 = Paca virtual address + * SPRG3 = Paca virtual address + */ +_GLOBAL(__secondary_start) + + HMT_MEDIUM /* Set thread priority to MEDIUM */ + + /* set up the TOC (virtual address) */ + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + std r2,PACATOC(r25) + li r6,0 + std r6,PACAKSAVE(r25) + stb r6,PACAPROCENABLED(r25) + +#ifndef CONFIG_PPC_ISERIES + /* Initialize the page table pointer register. */ + LOADADDR(r6,_SDR1) + ld r6,0(r6) /* get the value of _SDR1 */ + mtspr SDR1,r6 /* set the htab location */ +#endif + /* Initialize the first segment table (or SLB) entry */ + ld r3,PACASTABVIRT(r25) /* get addr of segment table */ + bl .stab_initialize + + /* Initialize the kernel stack. Just a repeat for iSeries. */ + LOADADDR(r3,current_set) + sldi r28,r24,4 /* get current_set[cpu#] */ + ldx r13,r3,r28 + std r13,PACACURRENT(r25) + addi r1,r13,TASK_UNION_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + ld r3,PACASTABREAL(r25) /* get raddr of segment table */ + ori r4,r3,1 /* turn on valid bit */ + +#ifdef CONFIG_PPC_ISERIES + li r0,-1 /* hypervisor call */ + li r3,1 + sldi r3,r3,63 /* 0x8000000000000000 */ + ori r3,r3,4 /* 0x8000000000000004 */ + sc /* HvCall_setASR */ +#else + mtasr r4 /* set the stab location */ +#endif + li r7,0 + mtlr r7 + + /* enable MMU and jump to start_secondary */ + LOADADDR(r3,.start_secondary_prolog) + SET_REG_TO_CONST(r4, MSR_KERNEL) +#ifdef DO_SOFT_DISABLE + ori r4,r4,MSR_EE +#endif + mtspr SRR0,r3 + mtspr SRR1,r4 + rfid +#endif /* CONFIG_SMP */ + +/* + * Running with relocation on at this point. All we want to do is + * zero the stack back-chain pointer before going into C code. + */ +_GLOBAL(start_secondary_prolog) + li r3,0 + std r3,0(r1) /* Zero the stack frame pointer */ + bl .start_secondary + +/* + * This subroutine clobbers r11, r12 and the LR + */ +_GLOBAL(enable_64b_mode) + mfmsr r11 /* grab the current MSR */ + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + or r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + or r11,r11,r12 + mtmsrd r11 + isync + blr + +/* + * This subroutine clobbers r11, r12 and the LR + */ +_GLOBAL(enable_32b_mode) + mfmsr r11 /* grab the current MSR */ + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + andc r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + andc r11,r11,r12 + mtmsrd r11 + isync + blr + + +/* + * This is where the main kernel code starts. + */ +_STATIC(start_here_pSeries) + /* get a new offset, now that the kernel has moved. */ + bl .reloc_offset + mr r26,r3 + + /* setup the naca pointer which is needed by *tab_initialize */ + LOADADDR(r6,naca) + sub r6,r6,r26 /* addr of the variable naca */ + li r27,0x4000 + std r27,0(r6) /* set the value of naca */ + +#ifdef CONFIG_HMT + /* Start up the second thread on cpu 0 */ + mfspr r3,PVR + srwi r3,r3,16 + cmpwi r3,0x34 /* Pulsar */ + beq 90f + cmpwi r3,0x36 /* Icestar */ + beq 90f + cmpwi r3,0x37 /* SStar */ + beq 90f + b 91f /* HMT not supported */ +90: li r3,0 + bl .hmt_start_secondary +91: +#endif + +#ifdef CONFIG_SMP + /* All secondary cpus are now spinning on a common + * spinloop, release them all now so they can start + * to spin on their individual Paca spinloops. + * For non SMP kernels, the secondary cpus never + * get out of the common spinloop. + */ + li r3,1 + LOADADDR(r5,__secondary_hold_spinloop) + tophys(r4,r5) + std r3,0(r4) +#endif + + /* The following gets the stack and TOC set up with the regs */ + /* pointing to the real addr of the kernel stack. This is */ + /* all done to support the C function call below which sets */ + /* up the htab. This is done because we have relocated the */ + /* kernel but are still running in real mode. */ + + /* real ptr to current */ + LOADADDR(r3,init_task_union) + sub r3,r3,r26 + + /* set up a stack pointer (physical address) */ + addi r1,r3,TASK_UNION_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + /* set up the TOC (physical address) */ + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + sub r2,r2,r26 + + /* Init naca->debug_switch so it can be used in stab & htab init. */ + bl .ppcdbg_initialize + + /* Get the pointer to the segment table which is used by */ + /* stab_initialize */ + li r27,0x4000 + ld r6,PACA(r27) /* Get the base Paca pointer */ + sub r6,r6,r26 /* convert to physical addr */ + mtspr SPRG3,r6 /* PPPBBB: Temp... -Peter */ + ld r3,PACASTABREAL(r6) + ori r4,r3,1 /* turn on valid bit */ + mtasr r4 /* set the stab location */ + + /* Initialize an initial memory mapping and turn on relocation. */ + bl .stab_initialize + bl .htab_initialize + + LOADADDR(r6,_SDR1) + sub r6,r6,r26 + ld r6,0(r6) /* get the value of _SDR1 */ + mtspr SDR1,r6 /* set the htab location */ + + LOADADDR(r3,.start_here_common) + SET_REG_TO_CONST(r4, MSR_KERNEL) + mtspr SRR0,r3 + mtspr SRR1,r4 + rfid + + /* This is where all platforms converge execution */ +_STATIC(start_here_common) + /* relocation is on at this point */ + + /* Clear out the BSS */ + LOADADDR(r11,_end) + + LOADADDR(r8,__bss_start) + + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + + /* The following code sets up the SP and TOC now that we are */ + /* running with translation enabled. */ + + /* ptr to current */ + LOADADDR(r3,init_task_union) + + /* set up the stack */ + addi r1,r3,TASK_UNION_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + /* set up the TOC */ + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + /* setup the naca pointer */ + LOADADDR(r9,naca) + + SET_REG_TO_CONST(r8, KERNELBASE) + addi r8,r8,0x4000 + std r8,0(r9) /* set the value of the naca ptr */ + + LOADADDR(r4,naca) /* Get Naca ptr address */ + ld r4,0(r4) /* Get the location of the naca */ + ld r4,PACA(r4) /* Get the base Paca pointer */ + mtspr SPRG3,r4 + + /* ptr to current */ + LOADADDR(r13,init_task_union) + std r13,PACACURRENT(r4) + + std r2,PACATOC(r4) + li r5,0 + std r0,PACAKSAVE(r4) + + /* ptr to hardware interrupt stack for processor 0 */ + LOADADDR(r3, hardware_int_paca0) + li r5,0x1000 + sldi r5,r5,3 + subi r5,r5,STACK_FRAME_OVERHEAD + + add r3,r3,r5 + std r3,PACAHRDWINTSTACK(r4) + + li r3,0 + stb r3,PACAHRDWINTCOUNT(r4) + + + /* + * Restore the parms passed in from the bootloader. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + + bl .setup_system + + /* Load up the kernel context */ +5: +#ifdef DO_SOFT_DISABLE + mfspr r4,SPRG3 + li r5,0 + stb r5,PACAPROCENABLED(r4) /* Soft Disabled */ + mfmsr r5 + ori r5,r5,MSR_EE /* Hard Enabled */ + mtmsrd r5 +#endif + + bl .start_kernel + +_GLOBAL(hmt_init) +#ifdef CONFIG_HMT + LOADADDR(r5, hmt_thread_data) + mfspr r7,PVR + srwi r7,r7,16 + cmpwi r7,0x34 /* Pulsar */ + beq 90f + cmpwi r7,0x36 /* Icestar */ + beq 91f + cmpwi r7,0x37 /* SStar */ + beq 91f + b 101f +90: mfspr r6,PIR + andi. r6,r6,0x1f + b 92f +91: mfspr r6,PIR + andi. r6,r6,0x3ff +92: sldi r4,r24,3 + stwx r6,r5,r4 + bl .hmt_start_secondary + b 101f + +__hmt_secondary_hold: + LOADADDR(r5, hmt_thread_data) + clrldi r5,r5,4 + li r7,0 + mfspr r6,PIR + mfspr r8,PVR + srwi r8,r8,16 + cmpwi r8,0x34 + bne 93f + andi. r6,r6,0x1f + b 103f +93: andi. r6,r6,0x3f + +103: lwzx r8,r5,r7 + cmpw r8,r6 + beq 104f + addi r7,r7,8 + b 103b + +104: addi r7,r7,4 + lwzx r9,r5,r7 + mr r24,r9 +101: +#endif + mr r3,r24 + b .pseries_secondary_smp_init + +#ifdef CONFIG_HMT +_GLOBAL(hmt_start_secondary) + LOADADDR(r4,__hmt_secondary_hold) + clrldi r4,r4,4 + mtspr NIADORM, r4 + mfspr r4, MSRDORM + li r5, -65 + and r4, r4, r5 + mtspr MSRDORM, r4 + lis r4,0xffef + ori r4,r4,0x7403 + mtspr TSC, r4 + li r4,0x1f4 + mtspr TST, r4 + mfspr r4, HID0 + ori r4, r4, 0x1 + mtspr HID0, r4 + mfspr r4, CTRLF + oris r4, r4, 0x40 + mtspr CTRLT, r4 + blr +#endif + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .align 12 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + + .globl ioremap_dir +ioremap_dir: + .space 4096 + + .globl hardware_int_paca0 +hardware_int_paca0: + .space 8*4096 + + +/* 4096 * 31 bytes of storage */ + .globl stab_array +stab_array: + .space 131072 +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 diff -urN linux-2.4.18/arch/ppc64/kernel/htab.c linux-2.4.19-pre5/arch/ppc64/kernel/htab.c --- linux-2.4.18/arch/ppc64/kernel/htab.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/htab.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1230 @@ +/* + * + * + * PowerPC64 port by Mike Corrigan and Dave Engebretsen + * {mikejc|engebret}@us.ibm.com + * + * Copyright (c) 2000 Mike Corrigan + * + * Module name: htab.c + * + * Description: + * PowerPC Hashed Page Table functions + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC_EEH +#include +#endif + +/* For iSeries */ +#include + +/* Note: pte --> Linux PTE + * HPTE --> PowerPC Hashed Page Table Entry + */ + +HTAB htab_data = {NULL, 0, 0, 0, 0}; + +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp); + +void htab_initialize(void); +void make_pte_LPAR(HPTE *htab, + unsigned long va, unsigned long pa, int mode, + unsigned long hash_mask, int large); + +extern unsigned long reloc_offset(void); +extern unsigned long get_kernel_vsid( unsigned long ea ); +extern void cacheable_memzero( void *, unsigned int ); + +extern unsigned long _SDR1; +extern unsigned long klimit; +extern struct Naca *naca; + +extern unsigned long _ASR; +extern inline void make_ste(unsigned long stab, + unsigned long esid, unsigned long vsid); + +extern char _stext[], _etext[], __start_naca[], __end_stab[]; + +static spinlock_t hash_table_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) +#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) +#define RELOC(x) (*PTRRELOC(&(x))) + +extern unsigned long htab_size( unsigned long ); +unsigned long hpte_getword0_iSeries( unsigned long slot ); + +#define KB (1024) +#define MB (1024*KB) +static inline void +create_pte_mapping(unsigned long start, unsigned long end, + unsigned long mode, unsigned long mask, int large) +{ + unsigned long addr, offset = reloc_offset(); + HTAB *_htab_data = PTRRELOC(&htab_data); + HPTE *htab = (HPTE *)__v2a(_htab_data->htab); + unsigned int step; + + if (large) + step = 16*MB; + else + step = 4*KB; + + for (addr = start; addr < end; addr += step) { + unsigned long vsid = get_kernel_vsid(addr); + unsigned long va = (vsid << 28) | (addr & 0xfffffff); + make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask, + large); + } +} + +void +htab_initialize(void) +{ + unsigned long table, htab_size_bytes; + unsigned long pteg_count; + unsigned long mode_ro, mode_rw, mask; + unsigned long offset = reloc_offset(); + struct Naca *_naca = RELOC(naca); + HTAB *_htab_data = PTRRELOC(&htab_data); + + /* + * Calculate the required size of the htab. We want the number of + * PTEGs to equal one half the number of real pages. + */ + htab_size_bytes = 1UL << _naca->pftSize; + pteg_count = htab_size_bytes >> 7; + + /* For debug, make the HTAB 1/8 as big as it normally would be. */ + ifppcdebug(PPCDBG_HTABSIZE) { + pteg_count >>= 3; + htab_size_bytes = pteg_count << 7; + } + + _htab_data->htab_num_ptegs = pteg_count; + _htab_data->htab_hash_mask = pteg_count - 1; + + if(_machine == _MACH_pSeries) { + /* Find storage for the HPT. Must be contiguous in + * the absolute address space. + */ + table = lmb_alloc(htab_size_bytes, htab_size_bytes); + if ( !table ) + panic("ERROR, cannot find space for HPTE\n"); + _htab_data->htab = (HPTE *)__a2v(table); + + /* htab absolute addr + encoded htabsize */ + RELOC(_SDR1) = table + __ilog2(pteg_count) - 11; + + /* Initialize the HPT with no entries */ + cacheable_memzero((void *)table, htab_size_bytes); + } else { + _htab_data->htab = NULL; + RELOC(_SDR1) = 0; + } + + mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX; + mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; + mask = pteg_count-1; + + /* Create PTE's for the kernel text and data sections plus + * the HPT and HPTX arrays. Make the assumption that + * (addr & KERNELBASE) == 0 (ie they are disjoint). + * We also assume that the va is <= 64 bits. + */ +#if 0 + create_pte_mapping((unsigned long)_stext, (unsigned long)__start_naca, mode_ro, mask); + create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab, mode_rw, mask); + create_pte_mapping((unsigned long)__end_stab, (unsigned long)_etext, mode_ro, mask); + create_pte_mapping((unsigned long)_etext, RELOC(klimit), mode_rw, mask); + create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask); +#else +#ifndef CONFIG_PPC_ISERIES + if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) { + create_pte_mapping((unsigned long)KERNELBASE, + KERNELBASE + 256*MB, mode_rw, mask, 0); + create_pte_mapping((unsigned long)KERNELBASE + 256*MB, + KERNELBASE + (_naca->physicalMemorySize), + mode_rw, mask, 1); + return; + } +#endif + create_pte_mapping((unsigned long)KERNELBASE, + KERNELBASE+(_naca->physicalMemorySize), + mode_rw, mask, 0); +#endif +} +#undef KB +#undef MB + +/* + * Create a pte. Used during initialization only. + * We assume the PTE will fit in the primary PTEG. + */ +void make_pte(HPTE *htab, + unsigned long va, unsigned long pa, int mode, + unsigned long hash_mask, int large) +{ + HPTE *hptep; + unsigned long hash, i; + volatile unsigned long x = 1; + unsigned long vpn; + +#ifdef CONFIG_PPC_PSERIES + if(_machine == _MACH_pSeriesLP) { + make_pte_LPAR(htab, va, pa, mode, hash_mask, large); + return; + } +#endif + + if (large) + vpn = va >> 24; + else + vpn = va >> 12; + + hash = hpt_hash(vpn, large); + + hptep = htab + ((hash & hash_mask)*HPTES_PER_GROUP); + + for (i = 0; i < 8; ++i, ++hptep) { + if ( hptep->dw0.dw0.v == 0 ) { /* !valid */ + hptep->dw1.dword1 = pa | mode; + hptep->dw0.dword0 = 0; + hptep->dw0.dw0.avpn = va >> 23; + hptep->dw0.dw0.bolted = 1; /* bolted */ + hptep->dw0.dw0.v = 1; /* make valid */ + return; + } + } + + /* We should _never_ get here and too early to call xmon. */ + for(;x;x|=1); +} + +/* Functions to invalidate a HPTE */ +static void hpte_invalidate_iSeries( unsigned long slot ) +{ + HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 ); +} + +static void hpte_invalidate_pSeries( unsigned long slot ) +{ + /* Local copy of the first doubleword of the HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + + /* Locate the HPTE */ + HPTE * hptep = htab_data.htab + slot; + + /* Get the first doubleword of the HPTE */ + hpte_dw0.d = hptep->dw0.dword0; + + /* Invalidate the hpte */ + hptep->dw0.dword0 = 0; + + /* Invalidate the tlb */ + { + unsigned long vsid, group, pi, pi_high; + + vsid = hpte_dw0.h.avpn >> 5; + group = slot >> 3; + if(hpte_dw0.h.h) { + group = ~group; + } + pi = (vsid ^ group) & 0x7ff; + pi_high = (hpte_dw0.h.avpn & 0x1f) << 11; + pi |= pi_high; + _tlbie(pi << 12); + } +} + + +/* Select an available HPT slot for a new HPTE + * return slot index (if in primary group) + * return -slot index (if in secondary group) + */ +static long hpte_selectslot_iSeries( unsigned long vpn ) +{ + HPTE hpte; + long ret_slot, orig_slot; + unsigned long primary_hash; + unsigned long hpteg_slot; + unsigned long slot; + unsigned i, k; + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + + ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn ); + if ( hpte.dw0.dw0.v ) { /* If valid ...what do we do now? */ + udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot ); + udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 ); + + return (0x8000000000000000); + /* panic("select_hpte_slot found entry already valid\n"); */ + } + if ( ret_slot == -1 ) { /* -1 indicates no available slots */ + + /* No available entry found in secondary group */ + + PMC_SW_SYSTEM(htab_capacity_castouts); + + primary_hash = hpt_hash(vpn, 0); + hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + k = htab_data.next_round_robin++ & 0x7; + + for ( i=0; idw0.dw0.v == 0 ) { + /* If an available slot found, return it */ + return hpteg_slot + i; + } + hptep++; + } + + /* No available entry found in primary group */ + + PMC_SW_SYSTEM(htab_primary_overflows); + + /* Search the secondary group */ + + hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + hptep = htab_data.htab + hpteg_slot; + + for (i=0; idw0.dw0.v == 0 ) { + /* If an available slot found, return it */ + return -(hpteg_slot + i); + } + hptep++; + } + + /* No available entry found in secondary group */ + + PMC_SW_SYSTEM(htab_capacity_castouts); + + /* Select an entry in the primary group to replace */ + + hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + hptep = htab_data.htab + hpteg_slot; + k = htab_data.next_round_robin++ & 0x7; + + for (i=0; idw0.dword0; + return dword0; +} + +static long hpte_find_iSeries(unsigned long vpn) +{ + HPTE hpte; + long slot; + + slot = HvCallHpt_findValid( &hpte, vpn ); + if ( hpte.dw0.dw0.v ) { + if ( slot < 0 ) { + slot &= 0x7fffffffffffffff; + slot = -slot; + } + } else + slot = -1; + return slot; +} + +static long hpte_find_pSeries(unsigned long vpn) +{ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + long slot; + unsigned long hash; + unsigned long i,j; + + hash = hpt_hash(vpn, 0); + for ( j=0; j<2; ++j ) { + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + for ( i=0; i> 11 ) ) && + ( hpte_dw0.h.v ) && + ( hpte_dw0.h.h == j ) ) { + /* HPTE matches */ + if ( j ) + slot = -slot; + return slot; + } + ++slot; + } + hash = ~hash; + } + return -1; +} + +/* This function is called by iSeries setup when initializing the hpt */ +void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa, + pte_t * ptep, unsigned hpteflags, unsigned bolted ) +{ + unsigned long vpn, flags; + long hpte_slot; + unsigned hash; + pte_t pte; + + vpn = ((vsid << 28) | ( ea & 0xffff000 )) >> 12; + + spin_lock_irqsave( &hash_table_lock, flags ); + + hpte_slot = ppc_md.hpte_selectslot( vpn ); + hash = 0; + if ( hpte_slot < 0 ) { + if ( hpte_slot == 0x8000000000000000 ) { + udbg_printf("hash_page: ptep = 0x%016lx\n", + (unsigned long)ptep ); + udbg_printf("hash_page: ea = 0x%016lx\n", ea ); + udbg_printf("hash_page: vpn = 0x%016lx\n", vpn ); + + panic("hash_page: hpte already exists\n"); + } + hash = 1; + hpte_slot = -hpte_slot; + } + ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep, + hpteflags, bolted ); + + if ( ptep ) { + /* Get existing pte flags */ + pte = *ptep; + pte_val(pte) &= ~_PAGE_HPTEFLAGS; + + /* Add in the has hpte flag */ + pte_val(pte) |= _PAGE_HASHPTE; + + /* Add in the _PAGE_SECONDARY flag */ + pte_val(pte) |= hash << 15; + + /* Add in the hpte slot */ + pte_val(pte) |= (hpte_slot << 12) & _PAGE_GROUP_IX; + + /* Save the new pte. */ + *ptep = pte; + + } + spin_unlock_irqrestore( &hash_table_lock, flags ); +} + + +/* Create an HPTE and validate it + * It is assumed that the HPT slot currently is invalid. + * The HPTE is set with the vpn, rpn (converted to absolute) + * and flags + */ +static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn, + unsigned long prpn, unsigned hash, + void * ptep, unsigned hpteflags, + unsigned bolted ) +{ + /* Local copy of HPTE */ + struct { + /* Local copy of first doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } dw0; + /* Local copy of second doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword1 h; + Hpte_dword1_flags f; + } dw1; + } lhpte; + + unsigned long avpn = vpn >> 11; + unsigned long arpn = physRpn_to_absRpn( prpn ); + + /* Fill in the local HPTE with absolute rpn, avpn and flags */ + lhpte.dw1.d = 0; + lhpte.dw1.h.rpn = arpn; + lhpte.dw1.f.flags = hpteflags; + + lhpte.dw0.d = 0; + lhpte.dw0.h.avpn = avpn; + lhpte.dw0.h.h = hash; + lhpte.dw0.h.bolted = bolted; + lhpte.dw0.h.v = 1; + + /* Now fill in the actual HPTE */ + HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte ); +} + +static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn, + unsigned long prpn, unsigned hash, + void * ptep, unsigned hpteflags, + unsigned bolted) +{ + /* Local copy of HPTE */ + struct { + /* Local copy of first doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } dw0; + /* Local copy of second doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword1 h; + Hpte_dword1_flags f; + } dw1; + } lhpte; + + unsigned long avpn = vpn >> 11; + unsigned long arpn = physRpn_to_absRpn( prpn ); + + HPTE *hptep; + + /* Fill in the local HPTE with absolute rpn, avpn and flags */ + lhpte.dw1.d = 0; + lhpte.dw1.h.rpn = arpn; + lhpte.dw1.f.flags = hpteflags; + + lhpte.dw0.d = 0; + lhpte.dw0.h.avpn = avpn; + lhpte.dw0.h.h = hash; + lhpte.dw0.h.bolted = bolted; + lhpte.dw0.h.v = 1; + + /* Now fill in the actual HPTE */ + hptep = htab_data.htab + slot; + + /* Set the second dword first so that the valid bit + * is the last thing set + */ + + hptep->dw1.dword1 = lhpte.dw1.d; + + /* Guarantee the second dword is visible before + * the valid bit + */ + + __asm__ __volatile__ ("eieio" : : : "memory"); + + /* Now set the first dword including the valid bit */ + hptep->dw0.dword0 = lhpte.dw0.d; + + __asm__ __volatile__ ("ptesync" : : : "memory"); +} + +/* find_linux_pte returns the address of a linux pte for a given + * effective address and directory. If not found, it returns zero. + */ + +pte_t * find_linux_pte( pgd_t * pgdir, unsigned long ea ) +{ + pgd_t *pg; + pmd_t *pm; + pte_t *pt = NULL; + pte_t pte; + pg = pgdir + pgd_index( ea ); + if ( ! pgd_none( *pg ) ) { + + pm = pmd_offset( pg, ea ); + if ( ! pmd_none( *pm ) ) { + pt = pte_offset( pm, ea ); + pte = *pt; + if ( ! pte_present( pte ) ) + pt = NULL; + } + } + + return pt; + +} + +static inline unsigned long computeHptePP( unsigned long pte ) +{ + return ( pte & _PAGE_USER ) | + ( ( ( pte & _PAGE_USER ) >> 1 ) & + ( ( ~( ( pte >> 2 ) & /* _PAGE_RW */ + ( pte >> 7 ) ) ) & /* _PAGE_DIRTY */ + 1 ) ); +} + +static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va) +{ + HvCallHpt_setPp( slot, newpp ); +} + +static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va) +{ + /* Local copy of first doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + + /* Local copy of second doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword1 h; + Hpte_dword1_flags f; + } hpte_dw1; + + HPTE * hptep = htab_data.htab + slot; + + /* Turn off valid bit in HPTE */ + hpte_dw0.d = hptep->dw0.dword0; + hpte_dw0.h.v = 0; + hptep->dw0.dword0 = hpte_dw0.d; + + /* Ensure it is out of the tlb too */ + _tlbie( va ); + + /* Insert the new pp bits into the HPTE */ + hpte_dw1.d = hptep->dw1.dword1; + hpte_dw1.h.pp = newpp; + hptep->dw1.dword1 = hpte_dw1.d; + + /* Ensure it is visible before validating */ + __asm__ __volatile__ ("eieio" : : : "memory"); + + /* Turn the valid bit back on in HPTE */ + hpte_dw0.h.v = 1; + hptep->dw0.dword0 = hpte_dw0.d; + + __asm__ __volatile__ ("ptesync" : : : "memory"); +} + +/* + * Update the page protection bits. Intended to be used to create + * guard pages for kernel data structures on pages which are bolted + * in the HPT. Assumes pages being operated on will not be stolen. + */ +void hpte_updateboltedpp_iSeries(unsigned long newpp, unsigned long ea ) +{ + unsigned long vsid,va,vpn; + long slot; + + vsid = get_kernel_vsid( ea ); + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + vpn = va >> PAGE_SHIFT; + + slot = ppc_md.hpte_find( vpn ); + HvCallHpt_setPp( slot, newpp ); +} + + +static __inline__ void set_pp_bit(unsigned long pp, HPTE *addr) +{ + unsigned long old; + unsigned long *p = (unsigned long *)(&(addr->dw1)); + + __asm__ __volatile__( + "1: ldarx %0,0,%3\n\ + rldimi %0,%2,0,62\n\ + stdcx. %0,0,%3\n\ + bne 1b" + : "=&r" (old), "=m" (*p) + : "r" (pp), "r" (p), "m" (*p) + : "cc"); +} + +/* + * Update the page protection bits. Intended to be used to create + * guard pages for kernel data structures on pages which are bolted + * in the HPT. Assumes pages being operated on will not be stolen. + */ +void hpte_updateboltedpp_pSeries(unsigned long newpp, unsigned long ea) +{ + unsigned long vsid,va,vpn,flags; + long slot; + HPTE *hptep; + + vsid = get_kernel_vsid( ea ); + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + vpn = va >> PAGE_SHIFT; + + slot = ppc_md.hpte_find( vpn ); + hptep = htab_data.htab + slot; + + set_pp_bit(newpp , hptep); + + /* Ensure it is out of the tlb too */ + spin_lock_irqsave( &hash_table_lock, flags ); + _tlbie( va ); + spin_unlock_irqrestore( &hash_table_lock, flags ); +} + + + +/* This is called very early. */ +void hpte_init_iSeries(void) +{ + ppc_md.hpte_invalidate = hpte_invalidate_iSeries; + ppc_md.hpte_updatepp = hpte_updatepp_iSeries; + ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_iSeries; + ppc_md.hpte_getword0 = hpte_getword0_iSeries; + ppc_md.hpte_selectslot = hpte_selectslot_iSeries; + ppc_md.hpte_create_valid = hpte_create_valid_iSeries; + ppc_md.hpte_find = hpte_find_iSeries; +} +void hpte_init_pSeries(void) +{ + ppc_md.hpte_invalidate = hpte_invalidate_pSeries; + ppc_md.hpte_updatepp = hpte_updatepp_pSeries; + ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeries; + ppc_md.hpte_getword0 = hpte_getword0_pSeries; + ppc_md.hpte_selectslot = hpte_selectslot_pSeries; + ppc_md.hpte_create_valid = hpte_create_valid_pSeries; + ppc_md.hpte_find = hpte_find_pSeries; +} + +/* Handle a fault by adding an HPTE + * If the address can't be determined to be valid + * via Linux page tables, return 1. If handled + * return 0 + */ +int hash_page( unsigned long ea, unsigned long access ) +{ + int rc = 1; + void * pgdir = NULL; + unsigned long va, vsid, vpn; + unsigned long newpp, hash_ind, prpn; + unsigned long hpteflags, regionid; + long slot; + struct mm_struct * mm; + pte_t old_pte, new_pte, *ptep; + + /* Check for invalid addresses. */ + if (!IS_VALID_EA(ea)) { + return 1; + } + + regionid = REGION_ID(ea); + switch ( regionid ) { + case USER_REGION_ID: + mm = current->mm; + if ( mm == NULL ) { + PPCDBG(PPCDBG_MM, "hash_page returning; mm = 0\n"); + return 1; + } + vsid = get_vsid(mm->context, ea ); + break; + case IO_REGION_ID: + mm = &ioremap_mm; + vsid = get_kernel_vsid( ea ); + break; + case VMALLOC_REGION_ID: + mm = &init_mm; + vsid = get_kernel_vsid( ea ); + break; +#ifdef CONFIG_PPC_EEH + case IO_UNMAPPED_REGION_ID: + udbg_printf("EEH Error ea = 0x%lx\n", ea); + PPCDBG_ENTER_DEBUGGER(); + panic("EEH Error ea = 0x%lx\n", ea); + break; +#endif + case KERNEL_REGION_ID: + /* As htab_initialize is now, we shouldn't ever get here since + * we're bolting the entire 0xC0... region. + */ + udbg_printf("Little faulted on kernel address 0x%lx\n", ea); + PPCDBG_ENTER_DEBUGGER(); + panic("Little faulted on kernel address 0x%lx\n", ea); + break; + default: + /* Not a valid range, send the problem up to do_page_fault */ + return 1; + break; + } + + /* Search the Linux page table for a match with va */ + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + vpn = va >> PAGE_SHIFT; + pgdir = mm->pgd; + PPCDBG(PPCDBG_MM, "hash_page ea = 0x%16.16lx, va = 0x%16.16lx\n current = 0x%16.16lx, access = %lx\n", ea, va, current, access); + if ( pgdir == NULL ) { + return 1; + } + + /* Lock the Linux page table to prevent mmap and kswapd + * from modifying entries while we search and update + */ + + spin_lock( &mm->page_table_lock ); + + ptep = find_linux_pte( pgdir, ea ); + /* If no pte found, send the problem up to do_page_fault */ + if ( ! ptep ) { + spin_unlock( &mm->page_table_lock ); + return 1; + } + + /* Acquire the hash table lock to guarantee that the linux + * pte we fetch will not change + */ + spin_lock( &hash_table_lock ); + + old_pte = *ptep; + + /* If the pte is not "present" (valid), send the problem + * up to do_page_fault. + */ + if ( ! pte_present( old_pte ) ) { + spin_unlock( &hash_table_lock ); + spin_unlock( &mm->page_table_lock ); + return 1; + } + + /* At this point we have found a pte (which was present). + * The spinlocks prevent this status from changing + * The hash_table_lock prevents the _PAGE_HASHPTE status + * from changing (RPN, DIRTY and ACCESSED too) + * The page_table_lock prevents the pte from being + * invalidated or modified + */ + +/* At this point, we have a pte (old_pte) which can be used to build or update + * an HPTE. There are 5 cases: + * + * 1. There is a valid (present) pte with no associated HPTE (this is + * the most common case) + * 2. There is a valid (present) pte with an associated HPTE. The + * current values of the pp bits in the HPTE prevent access because the + * user doesn't have appropriate access rights. + * 3. There is a valid (present) pte with an associated HPTE. The + * current values of the pp bits in the HPTE prevent access because we are + * doing software DIRTY bit management and the page is currently not DIRTY. + * 4. This is a Kernel address (0xC---) for which there is no page directory. + * There is an HPTE for this page, but the pp bits prevent access. + * Since we always set up kernel pages with R/W access for the kernel + * this case only comes about for users trying to access the kernel. + * This case is always an error and is not dealt with further here. + * 5. This is a Kernel address (0xC---) for which there is no page directory. + * There is no HPTE for this page. + + * Check the user's access rights to the page. If access should be prevented + * then send the problem up to do_page_fault. + */ + + access |= _PAGE_PRESENT; + if ( 0 == ( access & ~(pte_val(old_pte)) ) ) { + /* + * Check if pte might have an hpte, but we have + * no slot information + */ + if ( pte_val(old_pte) & _PAGE_HPTENOIX ) { + unsigned long slot; + pte_val(old_pte) &= ~_PAGE_HPTEFLAGS; + slot = ppc_md.hpte_find( vpn ); + if ( slot != -1 ) { + if ( slot < 0 ) { + pte_val(old_pte) |= _PAGE_SECONDARY; + slot = -slot; + } + pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE; + + } + } + + /* User has appropriate access rights. */ + new_pte = old_pte; + /* If the attempted access was a store */ + if ( access & _PAGE_RW ) + pte_val(new_pte) |= _PAGE_ACCESSED | + _PAGE_DIRTY; + else + pte_val(new_pte) |= _PAGE_ACCESSED; + + /* Only cases 1, 3 and 5 still in play */ + + newpp = computeHptePP( pte_val(new_pte) ); + + /* Check if pte already has an hpte (case 3) */ + if ( pte_val(old_pte) & _PAGE_HASHPTE ) { + /* There MIGHT be an HPTE for this pte */ + unsigned long hash, slot, secondary; + /* Local copy of first doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + hash = hpt_hash(vpn, 0); + secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15; + if ( secondary ) + hash = ~hash; + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12; + /* If there is an HPTE for this page it is indexed by slot */ + hpte_dw0.d = ppc_md.hpte_getword0( slot ); + if ( (hpte_dw0.h.avpn == (vpn >> 11) ) && + (hpte_dw0.h.v) && + (hpte_dw0.h.h == secondary ) ){ + /* HPTE matches */ + ppc_md.hpte_updatepp( slot, newpp, va ); + if ( !pte_same( old_pte, new_pte ) ) + *ptep = new_pte; + } + else { + /* HPTE is not for this pte */ + pte_val(old_pte) &= ~_PAGE_HPTEFLAGS; + } + } + if ( !( pte_val(old_pte) & _PAGE_HASHPTE ) ) { + /* Cases 1 and 5 */ + /* For these cases we need to create a new + * HPTE and update the linux pte (for + * case 1). For case 5 there is no linux pte. + * + * Find an available HPTE slot + */ + slot = ppc_md.hpte_selectslot( vpn ); + + /* Debug code */ + if ( slot == 0x8000000000000000 ) { + unsigned long xold_pte = pte_val(old_pte); + unsigned long xnew_pte = pte_val(new_pte); + + udbg_printf("hash_page: ptep = 0x%016lx\n", (unsigned long)ptep ); + udbg_printf("hash_page: old_pte = 0x%016lx\n", xold_pte ); + udbg_printf("hash_page: new_pte = 0x%016lx\n", xnew_pte ); + udbg_printf("hash_page: ea = 0x%016lx\n", ea ); + udbg_printf("hash_page: va = 0x%016lx\n", va ); + udbg_printf("hash_page: access = 0x%016lx\n", access ); + + panic("hash_page: hpte already exists\n"); + } + + hash_ind = 0; + if ( slot < 0 ) { + slot = -slot; + hash_ind = 1; + } + + /* Set the physical address */ + prpn = pte_val(old_pte) >> PTE_SHIFT; + + if ( ptep ) { + /* Update the linux pte with the HPTE slot */ + pte_val(new_pte) &= ~_PAGE_HPTEFLAGS; + pte_val(new_pte) |= hash_ind << 15; + pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX; + pte_val(new_pte) |= _PAGE_HASHPTE; + /* No need to use ldarx/stdcx here because all + * who might be updating the pte will hold the page_table_lock + * or the hash_table_lock (we hold both) + */ + *ptep = new_pte; + } + + /* copy appropriate flags from linux pte */ + hpteflags = (pte_val(new_pte) & 0x1f8) | newpp; + + /* Create the HPTE */ + ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 ); + + } + + /* Indicate success */ + rc = 0; + } + + spin_unlock( &hash_table_lock ); + if (ptep) + spin_unlock( &mm->page_table_lock ); + + return rc; +} + +void flush_hash_page( unsigned long context, unsigned long ea, pte_t pte ) +{ + unsigned long vsid, vpn, va, hash, secondary, slot, flags; + /* Local copy of first doubleword of HPTE */ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + + if ( (ea >= USER_START ) && ( ea <= USER_END ) ) + vsid = get_vsid( context, ea ); + else + vsid = get_kernel_vsid( ea ); + va = (vsid << 28) | (ea & 0x0fffffff); + vpn = va >> PAGE_SHIFT; + hash = hpt_hash(vpn, 0); + secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15; + if ( secondary ) + hash = ~hash; + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12; + /* If there is an HPTE for this page it is indexed by slot */ + + spin_lock_irqsave( &hash_table_lock, flags); + hpte_dw0.d = ppc_md.hpte_getword0( slot ); + if ( (hpte_dw0.h.avpn == (vpn >> 11) ) && + (hpte_dw0.h.v) && + (hpte_dw0.h.h == secondary ) ){ + /* HPTE matches */ + ppc_md.hpte_invalidate( slot ); + } + else { + unsigned k; + /* Temporarily lets check for the hpte in all possible slots */ + for ( secondary = 0; secondary < 2; ++secondary ) { + hash = hpt_hash(vpn, 0); + if ( secondary ) + hash = ~hash; + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + for ( k=0; k<8; ++k ) { + hpte_dw0.d = ppc_md.hpte_getword0( slot+k ); + if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) && + ( hpte_dw0.h.v ) && + ( hpte_dw0.h.h == secondary ) ) { + while (1) ; + } + } + } + + } + spin_unlock_irqrestore( &hash_table_lock, flags ); +} + +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int vleft, first=1, len, left, val; +#define TMPBUFLEN 256 + char buf[TMPBUFLEN], *p; + static const char *sizestrings[4] = { + "2MB", "256KB", "512KB", "1MB" + }; + static const char *clockstrings[8] = { + "clock disabled", "+1 clock", "+1.5 clock", "reserved(3)", + "+2 clock", "+2.5 clock", "+3 clock", "reserved(7)" + }; + static const char *typestrings[4] = { + "flow-through burst SRAM", "reserved SRAM", + "pipelined burst SRAM", "pipelined late-write SRAM" + }; + static const char *holdstrings[4] = { + "0.5", "1.0", "(reserved2)", "(reserved3)" + }; + + if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12)) + return -EFAULT; + + if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + vleft = table->maxlen / sizeof(int); + left = *lenp; + + for (; left /*&& vleft--*/; first=0) { + if (write) { + while (left) { + char c; + if(get_user(c,(char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0); + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + buffer += len; + left -= len; +#if 0 + /* DRENG need a def */ + _set_L2CR(0); + _set_L2CR(val); + while ( _get_L2CR() & 0x1 ) + /* wait for invalidate to finish */; +#endif + + } else { + p = buf; + if (!first) + *p++ = '\t'; +#if 0 + /* DRENG need a def */ + val = _get_L2CR(); +#endif + p += sprintf(p, "0x%08x: ", val); + p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" : + "disabled"); + p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no "); + p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]); + p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]); + p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]); + p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : ""); + p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": ""); + p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" : + "copy-back"); + p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : ""); + p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]); + p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : ""); + p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :""); + p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :""); + + p += sprintf(p,"\n"); + + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + break; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/hvCall.S linux-2.4.19-pre5/arch/ppc64/kernel/hvCall.S --- linux-2.4.18/arch/ppc64/kernel/hvCall.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/hvCall.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,99 @@ +/* + * arch/ppc64/kernel/hvCall.S + * + * + * This file contains the code to perform calls to the + * iSeries LPAR hypervisor + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "ppc_asm.h" +#include +#include + + .text + +/* + * Hypervisor call + * + * Invoke the iSeries hypervisor via the System Call instruction + * Parameters are passed to this routine in registers r3 - r10 + * + * r3 contains the HV function to be called + * r4-r10 contain the operands to the hypervisor function + * + */ + +_GLOBAL(HvCall) +_GLOBAL(HvCall0) +_GLOBAL(HvCall1) +_GLOBAL(HvCall2) +_GLOBAL(HvCall3) +_GLOBAL(HvCall4) +_GLOBAL(HvCall5) +_GLOBAL(HvCall6) +_GLOBAL(HvCall7) + + + mfcr r0 + std r0,-8(r1) + stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) + + /* r0 = 0xffffffffffffffff indicates a hypervisor call */ + + li r0,-1 + + /* Invoke the hypervisor */ + + sc + + ld r1,0(r1) + ld r0,-8(r1) + mtcrf 0xff,r0 + + /* return to caller, return value in r3 */ + + blr + +_GLOBAL(HvCall0Ret16) +_GLOBAL(HvCall1Ret16) +_GLOBAL(HvCall2Ret16) +_GLOBAL(HvCall3Ret16) +_GLOBAL(HvCall4Ret16) +_GLOBAL(HvCall5Ret16) +_GLOBAL(HvCall6Ret16) +_GLOBAL(HvCall7Ret16) + + mfcr r0 + std r0,-8(r1) + std r31,-16(r1) + stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1) + + mr r31,r4 + li r0,-1 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + mr r9,r10 + + sc + + std r3,0(r31) + std r4,8(r31) + + mr r3,r5 + + ld r1,0(r1) + ld r0,-8(r1) + mtcrf 0xff,r0 + ld r31,-16(r1) + + blr + + diff -urN linux-2.4.18/arch/ppc64/kernel/i8259.c linux-2.4.19-pre5/arch/ppc64/kernel/i8259.c --- linux-2.4.18/arch/ppc64/kernel/i8259.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/i8259.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,164 @@ +/* + * c 2001 PPC64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include "i8259.h" +#include +#include + +unsigned char cached_8259[2] = { 0xff, 0xff }; +#define cached_A1 (cached_8259[0]) +#define cached_21 (cached_8259[1]) + +static spinlock_t i8259_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; + +int i8259_pic_irq_offset; + +int i8259_irq(int cpu) +{ + int irq; + + spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); + /* + * Perform an interrupt acknowledge cycle on controller 1 + */ + outb(0x0C, 0x20); + irq = inb(0x20) & 7; + if (irq == 2) + { + /* + * Interrupt is cascaded so perform interrupt + * acknowledge on controller 2 + */ + outb(0x0C, 0xA0); + irq = (inb(0xA0) & 7) + 8; + } + else if (irq==7) + { + /* + * This may be a spurious interrupt + * + * Read the interrupt status register. If the most + * significant bit is not set then there is no valid + * interrupt + */ + outb(0x0b, 0x20); + if(~inb(0x20)&0x80) { + spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); + return -1; + } + } + spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); + return irq; +} + +static void i8259_mask_and_ack_irq(unsigned int irq_nr) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259_lock, flags); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + + if (irq_nr > 7) { + cached_A1 |= 1 << (irq_nr-8); + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); /* Non-specific EOI */ + outb(0x20,0x20); /* Non-specific EOI to cascade */ + } else { + cached_21 |= 1 << irq_nr; + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); /* Non-specific EOI */ + } + spin_unlock_irqrestore(&i8259_lock, flags); +} + +static void i8259_set_irq_mask(int irq_nr) +{ + outb(cached_A1,0xA1); + outb(cached_21,0x21); +} + +static void i8259_mask_irq(unsigned int irq_nr) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259_lock, flags); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 |= 1 << irq_nr; + else + cached_A1 |= 1 << (irq_nr-8); + i8259_set_irq_mask(irq_nr); + spin_unlock_irqrestore(&i8259_lock, flags); +} + +static void i8259_unmask_irq(unsigned int irq_nr) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259_lock, flags); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 &= ~(1 << irq_nr); + else + cached_A1 &= ~(1 << (irq_nr-8)); + i8259_set_irq_mask(irq_nr); + spin_unlock_irqrestore(&i8259_lock, flags); +} + +static void i8259_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + i8259_unmask_irq(irq); +} + +struct hw_interrupt_type i8259_pic = { + " i8259 ", + NULL, + NULL, + i8259_unmask_irq, + i8259_mask_irq, + i8259_mask_and_ack_irq, + i8259_end_irq, + NULL +}; + +void __init i8259_init(void) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259_lock, flags); + /* init master interrupt controller */ + outb(0x11, 0x20); /* Start init sequence */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0x21); /* Select 8086 mode */ + outb(0xFF, 0x21); /* Mask all */ + /* init slave interrupt controller */ + outb(0x11, 0xA0); /* Start init sequence */ + outb(0x08, 0xA1); /* Vector base */ + outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0xA1); /* Select 8086 mode */ + outb(0xFF, 0xA1); /* Mask all */ + outb(cached_A1, 0xA1); + outb(cached_21, 0x21); + spin_unlock_irqrestore(&i8259_lock, flags); + request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, + "82c59 secondary cascade", NULL ); + +} diff -urN linux-2.4.18/arch/ppc64/kernel/i8259.h linux-2.4.19-pre5/arch/ppc64/kernel/i8259.h --- linux-2.4.18/arch/ppc64/kernel/i8259.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/i8259.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,19 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _PPC_KERNEL_i8259_H +#define _PPC_KERNEL_i8259_H + +#include "local_irq.h" + +extern struct hw_interrupt_type i8259_pic; + +void i8259_init(void); +int i8259_irq(int); + +#endif /* _PPC_KERNEL_i8259_H */ diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_IoMmTable.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_IoMmTable.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,163 @@ +/************************************************************************/ +/* This module supports the iSeries I/O Address translation mapping */ +/* Copyright (C) 20yy */ +/* */ +/* 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 */ +/************************************************************************/ +/* Change Activity: */ +/* Created, December 14, 2000 */ +/* Added Bar table for IoMm performance. */ +/* Ported to ppc64 */ +/* Added dynamic table allocation */ +/* End Change Activity */ +/************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iSeries_IoMmTable.h" +#include "pci.h" + +/*******************************************************************/ +/* Table defines */ +/* Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. */ +/*******************************************************************/ +#define Max_Entries 1024 +unsigned long iSeries_IoMmTable_Entry_Size = 0x0000000000400000; +unsigned long iSeries_Base_Io_Memory = 0xE000000000000000; +unsigned long iSeries_Max_Io_Memory = 0xE000000000000000; +static long iSeries_CurrentIndex = 0; + +/*******************************************************************/ +/* Lookup Tables. */ +/*******************************************************************/ +struct iSeries_Device_Node** iSeries_IoMmTable; +u8* iSeries_IoBarTable; + +/*******************************************************************/ +/* Static and Global variables */ +/*******************************************************************/ +static char* iSeriesPciIoText = "iSeries PCI I/O"; +static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED; + +/*******************************************************************/ +/* iSeries_IoMmTable_Initialize */ +/*******************************************************************/ +/* Allocates and initalizes the Address Translation Table and Bar */ +/* Tables to get them ready for use. Must be called before any */ +/* I/O space is handed out to the device BARs. */ +/* A follow up method,iSeries_IoMmTable_Status can be called to */ +/* adjust the table after the device BARs have been assiged to */ +/* resize the table. */ +/*******************************************************************/ +void iSeries_IoMmTable_Initialize(void) +{ + spin_lock(&iSeriesIoMmTableLock); + iSeries_IoMmTable = kmalloc(sizeof(void*)*Max_Entries,GFP_KERNEL); + iSeries_IoBarTable = kmalloc(sizeof(u8)*Max_Entries, GFP_KERNEL); + spin_unlock(&iSeriesIoMmTableLock); + PCIFR("IoMmTable Initialized 0x%p", iSeries_IoMmTable); + if(iSeries_IoMmTable == NULL || iSeries_IoBarTable == NULL) { + panic("PCI: I/O tables allocation failed.\n"); + } +} + +/*******************************************************************/ +/* iSeries_IoMmTable_AllocateEntry */ +/*******************************************************************/ +/* Adds pci_dev entry in address translation table */ +/*******************************************************************/ +/* - Allocates the number of entries required in table base on BAR */ +/* size. */ +/* - Allocates starting at iSeries_Base_Io_Memory and increases. */ +/* - The size is round up to be a multiple of entry size. */ +/* - CurrentIndex is incremented to keep track of the last entry. */ +/* - Builds the resource entry for allocated BARs. */ +/*******************************************************************/ +static void iSeries_IoMmTable_AllocateEntry(struct pci_dev* PciDev, int BarNumber) +{ + struct resource* BarResource = &PciDev->resource[BarNumber]; + long BarSize = pci_resource_len(PciDev,BarNumber); + /***********************************************************/ + /* No space to allocate, quick exit, skip Allocation. */ + /***********************************************************/ + if(BarSize == 0) return; + /***********************************************************/ + /* Set Resource values. */ + /***********************************************************/ + spin_lock(&iSeriesIoMmTableLock); + BarResource->name = iSeriesPciIoText; + BarResource->start = iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex; + BarResource->start+= iSeries_Base_Io_Memory; + BarResource->end = BarResource->start+BarSize-1; + /***********************************************************/ + /* Allocate the number of table entries needed for BAR. */ + /***********************************************************/ + while (BarSize > 0 ) { + *(iSeries_IoMmTable +iSeries_CurrentIndex) = (struct iSeries_Device_Node*)PciDev->sysdata; + *(iSeries_IoBarTable+iSeries_CurrentIndex) = BarNumber; + BarSize -= iSeries_IoMmTable_Entry_Size; + ++iSeries_CurrentIndex; + } + iSeries_Max_Io_Memory = (iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex)+iSeries_Base_Io_Memory; + spin_unlock(&iSeriesIoMmTableLock); +} + +/*******************************************************************/ +/* iSeries_allocateDeviceBars */ +/*******************************************************************/ +/* - Allocates ALL pci_dev BAR's and updates the resources with the*/ +/* BAR value. BARS with zero length will have the resources */ +/* The HvCallPci_getBarParms is used to get the size of the BAR */ +/* space. It calls iSeries_IoMmTable_AllocateEntry to allocate */ +/* each entry. */ +/* - Loops through The Bar resourses(0 - 5) including the the ROM */ +/* is resource(6). */ +/*******************************************************************/ +void iSeries_allocateDeviceBars(struct pci_dev* PciDev) +{ + struct resource* BarResource; + int BarNumber; + for(BarNumber = 0; BarNumber <= PCI_ROM_RESOURCE; ++BarNumber) { + BarResource = &PciDev->resource[BarNumber]; + iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber); + } +} + +/************************************************************************/ +/* Translates the IoAddress to the device that is mapped to IoSpace. */ +/* This code is inlined, see the iSeries_pci.c file for the replacement.*/ +/************************************************************************/ +struct iSeries_Device_Node* iSeries_xlateIoMmAddress(void* IoAddress) +{ + return NULL; +} + +/************************************************************************ + * Status hook for IoMmTable + ************************************************************************/ +void iSeries_IoMmTable_Status(void) +{ + PCIFR("IoMmTable......: 0x%p",iSeries_IoMmTable); + PCIFR("IoMmTable Range: 0x%p to 0x%p",iSeries_Base_Io_Memory,iSeries_Max_Io_Memory); + return; +} diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_IoMmTable.h linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.h --- linux-2.4.18/arch/ppc64/kernel/iSeries_IoMmTable.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,85 @@ +#ifndef _ISERIES_IOMMTABLE_H +#define _ISERIES_IOMMTABLE_H +/************************************************************************/ +/* File iSeries_IoMmTable.h created by Allan Trautman on Dec 12 2001. */ +/************************************************************************/ +/* Interfaces for the write/read Io address translation table. */ +/* Copyright (C) 20yy Allan H Trautman, IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the: */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, */ +/* Boston, MA 02111-1307 USA */ +/************************************************************************/ +/* Change Activity: */ +/* Created December 12, 2000 */ +/* Ported to ppc64, August 30, 2001 */ +/* End Change Activity */ +/************************************************************************/ + +struct pci_dev; +struct iSeries_Device_Node; + +extern struct iSeries_Device_Node** iSeries_IoMmTable; +extern u8* iSeries_IoBarTable; +extern unsigned long iSeries_Base_Io_Memory; +extern unsigned long iSeries_Max_Io_Memory; +extern unsigned long iSeries_Base_Io_Memory; +extern unsigned long iSeries_IoMmTable_Entry_Size; +/************************************************************************/ +/* iSeries_IoMmTable_Initialize */ +/************************************************************************/ +/* - Initalizes the Address Translation Table and get it ready for use. */ +/* Must be called before any client calls any of the other methods. */ +/* */ +/* Parameters: None. */ +/* */ +/* Return: None. */ +/************************************************************************/ +extern void iSeries_IoMmTable_Initialize(void); +extern void iSeries_IoMmTable_Status(void); + +/************************************************************************/ +/* iSeries_allocateDeviceBars */ +/************************************************************************/ +/* - Allocates ALL pci_dev BAR's and updates the resources with the BAR */ +/* value. BARS with zero length will not have the resources. The */ +/* HvCallPci_getBarParms is used to get the size of the BAR space. */ +/* It calls iSeries_IoMmTable_AllocateEntry to allocate each entry. */ +/* */ +/* Parameters: */ +/* pci_dev = Pointer to pci_dev structure that will be mapped to pseudo */ +/* I/O Address. */ +/* */ +/* Return: */ +/* The pci_dev I/O resources updated with pseudo I/O Addresses. */ +/************************************************************************/ +extern void iSeries_allocateDeviceBars(struct pci_dev* ); + +/************************************************************************/ +/* iSeries_xlateIoMmAddress */ +/************************************************************************/ +/* - Translates an I/O Memory address to Device Node that has been the */ +/* allocated the psuedo I/O Address. */ +/* */ +/* Parameters: */ +/* IoAddress = I/O Memory Address. */ +/* */ +/* Return: */ +/* An iSeries_Device_Node to the device mapped to the I/O address. The*/ +/* BarNumber and BarOffset are valid if the Device Node is returned. */ +/************************************************************************/ +extern struct iSeries_Device_Node* iSeries_xlateIoMmAddress(void* IoAddress); + +#endif /* _ISERIES_IOMMTABLE_H */ diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_VpdInfo.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_VpdInfo.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_VpdInfo.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_VpdInfo.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,317 @@ +/************************************************************************/ +/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. */ +/************************************************************************/ +/* This code gets the card location of the hardware */ +/* Copyright (C) 20yy */ +/* */ +/* 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 */ +/************************************************************************/ +/* Change Activity: */ +/* Created, Feb 2, 2001 */ +/* Ported to ppc64, August 20, 2001 */ +/* End Change Activity */ +/************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +//#include +#include +#include "pci.h" + +/************************************************/ +/* Size of Bus VPD data */ +/************************************************/ +#define BUS_VPDSIZE 1024 +/************************************************/ +/* Bus Vpd Tags */ +/************************************************/ +#define VpdEndOfDataTag 0x78 +#define VpdEndOfAreaTag 0x79 +#define VpdIdStringTag 0x82 +#define VpdVendorAreaTag 0x84 +/************************************************/ +/* Mfg Area Tags */ +/************************************************/ +#define VpdFruFlag 0x4647 // "FG" +#define VpdFruFrameId 0x4649 // "FI" +#define VpdSlotMapFormat 0x4D46 // "MF" +#define VpdAsmPartNumber 0x504E // "PN" +#define VpdFruSerial 0x534E // "SN" +#define VpdSlotMap 0x534D // "SM" + +/************************************************/ +/* Structures of the areas */ +/************************************************/ +struct MfgVpdAreaStruct { + u16 Tag; + u8 TagLength; + u8 AreaData1; + u8 AreaData2; +}; +typedef struct MfgVpdAreaStruct MfgArea; +#define MFG_ENTRY_SIZE 3 + +struct SlotMapStruct { + u8 AgentId; + u8 SecondaryAgentId; + u8 PhbId; + char CardLocation[3]; + char Parms[8]; + char Reserved[2]; +}; +typedef struct SlotMapStruct SlotMap; +#define SLOT_ENTRY_SIZE 16 + +/**************************************************************** + * * + * Bus, Card, Board, FrameId, CardLocation. * + ****************************************************************/ +LocationData* iSeries_GetLocationData(struct pci_dev* PciDev) +{ + struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata; + LocationData* LocationPtr = (LocationData*)kmalloc(LOCATION_DATA_SIZE, GFP_KERNEL); + if (LocationPtr == NULL) { + printk("PCI: LocationData area allocation failed!\n"); + return NULL; + } + memset(LocationPtr,0,LOCATION_DATA_SIZE); + LocationPtr->Bus = ISERIES_BUS(DevNode); + LocationPtr->Board = DevNode->Board; + LocationPtr->FrameId = DevNode->FrameId; + LocationPtr->Card = PCI_SLOT(DevNode->DevFn); + strcpy(&LocationPtr->CardLocation[0],&DevNode->CardLocation[0]); + return LocationPtr; +} + +/************************************************************************/ +/* Formats the device information. */ +/* - Pass in pci_dev* pointer to the device. */ +/* - Pass in buffer to place the data. Danger here is the buffer must */ +/* be as big as the client says it is. Should be at least 128 bytes.*/ +/* Return will the length of the string data put in the buffer. */ +/* Format: */ +/* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet */ +/* controller */ +/************************************************************************/ +int iSeries_Device_Information(struct pci_dev* PciDev,char* Buffer, int BufferSize) +{ + struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata; + char* BufPtr = Buffer; + int LineLen = 0; + + if (DevNode == NULL) { + LineLen = sprintf(BufPtr+LineLen, "PCI: iSeries_Device_Information DevNode is NULL"); + return LineLen; + } + + if (BufferSize >= 128) { + LineLen = sprintf(BufPtr+LineLen,"PCI: Bus%3d, Device%3d, Vendor %04X ", + ISERIES_BUS(DevNode), PCI_SLOT(PciDev->devfn),PciDev->vendor); + + LineLen += sprintf(BufPtr+LineLen,"Frame%3d, Card %4s ", DevNode->FrameId,DevNode->CardLocation); + + if (pci_class_name(PciDev->class >> 8) == 0) { + LineLen += sprintf(BufPtr+LineLen,"0x%04X ",(int)(PciDev->class >> 8)); + } + else { + LineLen += sprintf(BufPtr+LineLen,"%s",pci_class_name(PciDev->class >> 8) ); + } + } + return LineLen; +} +/************************************************************************/ +/* Build a character string of the device location, Frame 1, Card C10 */ +/************************************************************************/ +int device_Location(struct pci_dev* PciDev,char* BufPtr) +{ + struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata; + return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %s", + DevNode->DsaAddr.busNumber, + DevNode->AgentId, + DevNode->Vendor, + DevNode->Location); +} + +/*****************************************************************/ +/* Parse the Slot Area */ +/*****************************************************************/ +void iSeries_Parse_SlotArea(SlotMap* MapPtr,int MapLen, struct iSeries_Device_Node* DevNode) +{ + int SlotMapLen = MapLen; + SlotMap* SlotMapPtr = MapPtr; + /*************************************************************/ + /* Parse Slot label until we find the one requrested */ + /*************************************************************/ + while (SlotMapLen > 0) { + if (SlotMapPtr->AgentId == DevNode->AgentId ) { + /*******************************************************/ + /* If Phb wasn't found, grab the entry first one found.*/ + /*******************************************************/ + if (DevNode->PhbId == 0xff) { + DevNode->PhbId = SlotMapPtr->PhbId; + } + /**************************************************/ + /* Found it, extract the data. */ + /**************************************************/ + if (SlotMapPtr->PhbId == DevNode->PhbId ) { + memcpy(&DevNode->CardLocation,&SlotMapPtr->CardLocation,3); + DevNode->CardLocation[3] = 0; + break; + } + } + /*********************************************************/ + /* Point to the next Slot */ + /*********************************************************/ + SlotMapPtr = (SlotMap*)((char*)SlotMapPtr+SLOT_ENTRY_SIZE); + SlotMapLen -= SLOT_ENTRY_SIZE; + } +} + +/*****************************************************************/ +/* Parse the Mfg Area */ +/*****************************************************************/ +static void iSeries_Parse_MfgArea(u8* AreaData,int AreaLen, struct iSeries_Device_Node* DevNode) +{ + MfgArea* MfgAreaPtr = (MfgArea*)AreaData; + int MfgAreaLen = AreaLen; + u16 SlotMapFmt = 0; + + /*************************************************************/ + /* Parse Mfg Data */ + /*************************************************************/ + while (MfgAreaLen > 0) { + int MfgTagLen = MfgAreaPtr->TagLength; + /*******************************************************/ + /* Frame ID (FI 4649020310 ) */ + /*******************************************************/ + if (MfgAreaPtr->Tag == VpdFruFrameId) { /* FI */ + DevNode->FrameId = MfgAreaPtr->AreaData1; + } + /*******************************************************/ + /* Slot Map Format (MF 4D46020004 ) */ + /*******************************************************/ + else if (MfgAreaPtr->Tag == VpdSlotMapFormat){ /* MF */ + SlotMapFmt = (MfgAreaPtr->AreaData1*256)+(MfgAreaPtr->AreaData2); + } + /*******************************************************/ + /* Slot Map (SM 534D90 */ + /*******************************************************/ + else if (MfgAreaPtr->Tag == VpdSlotMap){ /* SM */ + SlotMap* SlotMapPtr; + if (SlotMapFmt == 0x1004) SlotMapPtr = (SlotMap*)((char*)MfgAreaPtr+MFG_ENTRY_SIZE+1); + else SlotMapPtr = (SlotMap*)((char*)MfgAreaPtr+MFG_ENTRY_SIZE); + iSeries_Parse_SlotArea(SlotMapPtr,MfgTagLen, DevNode); + } + /*********************************************************/ + /* Point to the next Mfg Area */ + /* Use defined size, sizeof give wrong answer */ + /*********************************************************/ + MfgAreaPtr = (MfgArea*)((char*)MfgAreaPtr + MfgTagLen + MFG_ENTRY_SIZE); + MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); + } +} + +/*****************************************************************/ +/* Look for "BUS".. Data is not Null terminated. */ +/* PHBID of 0xFF indicates PHB was not found in VPD Data. */ +/*****************************************************************/ +static int iSeries_Parse_PhbId(u8* AreaPtr,int AreaLength) +{ + u8* PhbPtr = AreaPtr; + int DataLen = AreaLength; + char PhbId = 0xFF; + while (DataLen > 0) { + if (*PhbPtr == 'B' && *(PhbPtr+1) == 'U' && *(PhbPtr+2) == 'S') { + PhbPtr += 3; + while(*PhbPtr == ' ') ++PhbPtr; + PhbId = (*PhbPtr & 0x0F); + break; + } + ++PhbPtr; + --DataLen; + } + return PhbId; +} + +/****************************************************************/ +/* Parse out the VPD Areas */ +/****************************************************************/ +static void iSeries_Parse_Vpd(u8* VpdData, int VpdDataLen, struct iSeries_Device_Node* DevNode) +{ + u8* TagPtr = VpdData; + int DataLen = VpdDataLen-3; + /*************************************************************/ + /* Parse the Areas */ + /*************************************************************/ + while (*TagPtr != VpdEndOfAreaTag && DataLen > 0) { + int AreaLen = *(TagPtr+1) + (*(TagPtr+2)*256); + u8* AreaData = TagPtr+3; + + if (*TagPtr == VpdIdStringTag) { + DevNode->PhbId = iSeries_Parse_PhbId(AreaData,AreaLen); + } + else if (*TagPtr == VpdVendorAreaTag) { + iSeries_Parse_MfgArea(AreaData,AreaLen,DevNode); + } + /********************************************************* + * Point to next Area. + *********************************************************/ + TagPtr = AreaData + AreaLen; + DataLen -= AreaLen; + } +} + +/**************************************************************** + * iSeries_Get_Location_Code(struct iSeries_Device_Node*) * + * + ****************************************************************/ +void iSeries_Get_Location_Code(struct iSeries_Device_Node* DevNode) +{ + int BusVpdLen = 0; + u8* BusVpdPtr = (u8*)kmalloc(BUS_VPDSIZE, GFP_KERNEL); + if (BusVpdPtr == NULL) { + printk("PCI: Bus VPD Buffer allocation failure.\n"); + return; + } + BusVpdLen = HvCallPci_getBusVpd(ISERIES_BUS(DevNode),REALADDR(BusVpdPtr),BUS_VPDSIZE); + if (BusVpdLen == 0) { + kfree(BusVpdPtr); + printk("PCI: Bus VPD Buffer zero length.\n"); + return; + } + //printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); + /*************************************************************/ + /* Make sure this is what I think it is */ + /*************************************************************/ + if (*BusVpdPtr != VpdIdStringTag) { /*0x82 */ + printk("PCI: Bus VPD Buffer missing starting tag.\n"); + kfree(BusVpdPtr); + return; + } + /***************************************************************/ + /***************************************************************/ + iSeries_Parse_Vpd(BusVpdPtr,BusVpdLen, DevNode); + sprintf(DevNode->Location,"Frame%3d, Card %-4s",DevNode->FrameId,DevNode->CardLocation); + kfree(BusVpdPtr); +} diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_irq.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_irq.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_irq.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,259 @@ +/************************************************************************/ +/* This module supports the iSeries PCI bus interrupt handling */ +/* Copyright (C) 20yy */ +/* */ +/* 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 */ +/************************************************************************/ +/* Change Activity: */ +/* Created, December 13, 2000 by Wayne Holm */ +/* End Change Activity */ +/************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +hw_irq_controller iSeries_IRQ_handler = { + "iSeries irq controller", + iSeries_startup_IRQ, /* startup */ + iSeries_shutdown_IRQ, /* shutdown */ + iSeries_enable_IRQ, /* enable */ + iSeries_disable_IRQ, /* disable */ + NULL, /* ack */ + iSeries_end_IRQ, /* end */ + NULL /* set_affinity */ +}; + + +struct iSeries_irqEntry { + u32 dsa; + struct iSeries_irqEntry* next; +}; + +struct iSeries_irqAnchor { + u8 valid : 1; + u8 reserved : 7; + u16 entryCount; + struct iSeries_irqEntry* head; +}; + +struct iSeries_irqAnchor iSeries_irqMap[NR_IRQS]; + +void iSeries_init_irqMap(int irq); + +/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */ +void __init iSeries_init_IRQ(void) +{ + int i; + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].handler = &iSeries_IRQ_handler; + irq_desc[i].status = 0; + irq_desc[i].status |= IRQ_DISABLED; + irq_desc[i].depth = 1; + iSeries_init_irqMap(i); + } + /* Register PCI event handler and open an event path */ + PPCDBG(PPCDBG_BUSWALK,"Register PCI event handler and open an event path\n"); + XmPciLpEvent_init(); + return; +} + +/********************************************************************** + * Called by iSeries_init_IRQ + * Prevent IRQs 0 and 255 from being used. IRQ 0 appears in + * uninitialized devices. IRQ 255 appears in the PCI interrupt + * line register if a PCI error occurs, + *********************************************************************/ +void __init iSeries_init_irqMap(int irq) +{ + iSeries_irqMap[irq].valid = (irq == 0 || irq == 255)? 0 : 1; + iSeries_irqMap[irq].entryCount = 0; + iSeries_irqMap[irq].head = NULL; +} + +/* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot */ +/* It calculates the irq value for the slot. */ +int __init iSeries_allocate_IRQ(HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId) +{ + u8 idsel = (deviceId >> 4); + u8 function = deviceId & 0x0F; + int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 253) + 2; + return irq; +} + +/* This is called out of iSeries_scan_slot to assign the EADS slot to its IRQ number */ +int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId) +{ + int rc; + u32 dsa = (busNumber << 16) | (subBusNumber << 8) | deviceId; + struct iSeries_irqEntry* newEntry; + unsigned long flags; + + if (irq < 0 || irq >= NR_IRQS) { + return -1; + } + newEntry = kmalloc(sizeof(*newEntry), GFP_KERNEL); + if (newEntry == NULL) { + return -ENOMEM; + } + newEntry->dsa = dsa; + newEntry->next = NULL; + /******************************************************************** + * Probably not necessary to lock the irq since allocation is only + * done during buswalk, but it should not hurt anything except a + * little performance to be smp safe. + *******************************************************************/ + spin_lock_irqsave(&irq_desc[irq].lock, flags); + + if (iSeries_irqMap[irq].valid) { + /* Push the new element onto the irq stack */ + newEntry->next = iSeries_irqMap[irq].head; + iSeries_irqMap[irq].head = newEntry; + ++iSeries_irqMap[irq].entryCount; + rc = 0; + PPCDBG(PPCDBG_BUSWALK,"iSeries_assign_IRQ 0x%04X.%02X.%02X = 0x%04X\n",busNumber, subBusNumber, deviceId, irq); + } + else { + printk("PCI: Something is wrong with the iSeries_irqMap. \n"); + kfree(newEntry); + rc = -1; + } + spin_unlock_irqrestore(&irq_desc[irq].lock, flags); + return rc; +} + + +/* This is called by iSeries_activate_IRQs */ +unsigned int iSeries_startup_IRQ(unsigned int irq) +{ + struct iSeries_irqEntry* entry; + u32 bus, subBus, deviceId, function, mask; + for(entry=iSeries_irqMap[irq].head; entry!=NULL; entry=entry->next) { + bus = (entry->dsa >> 16) & 0xFFFF; + subBus = (entry->dsa >> 8) & 0xFF; + deviceId = entry->dsa & 0xFF; + function = deviceId & 0x0F; + /* Link the IRQ number to the bridge */ + HvCallXm_connectBusUnit(bus, subBus, deviceId, irq); + /* Unmask bridge interrupts in the FISR */ + mask = 0x01010000 << function; + HvCallPci_unmaskFisr(bus, subBus, deviceId, mask); + PPCDBG(PPCDBG_BUSWALK,"iSeries_activate_IRQ 0x%02X.%02X.%02X Irq:0x%02X\n",bus,subBus,deviceId,irq); + } + return 0; +} + +/* This is called out of iSeries_fixup to activate interrupt + * generation for usable slots */ +void __init iSeries_activate_IRQs() +{ + int irq; + unsigned long flags; + for (irq=0; irq < NR_IRQS; irq++) { + spin_lock_irqsave(&irq_desc[irq].lock, flags); + irq_desc[irq].handler->startup(irq); + spin_unlock_irqrestore(&irq_desc[irq].lock, flags); + } +} + +/* this is not called anywhere currently */ +void iSeries_shutdown_IRQ(unsigned int irq) { + struct iSeries_irqEntry* entry; + u32 bus, subBus, deviceId, function, mask; + + /* irq should be locked by the caller */ + + for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) { + bus = (entry->dsa >> 16) & 0xFFFF; + subBus = (entry->dsa >> 8) & 0xFF; + deviceId = entry->dsa & 0xFF; + function = deviceId & 0x0F; + /* Invalidate the IRQ number in the bridge */ + HvCallXm_connectBusUnit(bus, subBus, deviceId, 0); + /* Mask bridge interrupts in the FISR */ + mask = 0x01010000 << function; + HvCallPci_maskFisr(bus, subBus, deviceId, mask); + } + +} + +/*********************************************************** + * This will be called by device drivers (via disable_IRQ) + * to disable INTA in the bridge interrupt status register. + ***********************************************************/ +void iSeries_disable_IRQ(unsigned int irq) +{ + struct iSeries_irqEntry* entry; + u32 bus, subBus, deviceId, mask; + + /* The IRQ has already been locked by the caller */ + + for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) { + bus = (entry->dsa >> 16) & 0xFFFF; + subBus = (entry->dsa >> 8) & 0xFF; + deviceId = entry->dsa & 0xFF; + /* Mask secondary INTA */ + mask = 0x80000000; + HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); + PPCDBG(PPCDBG_BUSWALK,"iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",bus,subBus,deviceId,irq); + } +} + +/*********************************************************** + * This will be called by device drivers (via enable_IRQ) + * to enable INTA in the bridge interrupt status register. + ***********************************************************/ +void iSeries_enable_IRQ(unsigned int irq) +{ + struct iSeries_irqEntry* entry; + u32 bus, subBus, deviceId, mask; + + /* The IRQ has already been locked by the caller */ + for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) { + bus = (entry->dsa >> 16) & 0xFFFF; + subBus = (entry->dsa >> 8) & 0xFF; + deviceId = entry->dsa & 0xFF; + /* Unmask secondary INTA */ + mask = 0x80000000; + HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); + PPCDBG(PPCDBG_BUSWALK,"iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",bus,subBus,deviceId,irq); + } +} + +/* Need to define this so ppc_irq_dispatch_handler will NOT call + enable_IRQ at the end of interrupt handling. However, this + does nothing because there is not enough information provided + to do the EOI HvCall. This is done by XmPciLpEvent.c */ +void iSeries_end_IRQ(unsigned int irq) +{ +} + diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_pci.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,926 @@ +/* + * iSeries_pci.c + * + * Copyright (C) 2001 Allan Trautman, IBM Corporation + * + * iSeries specific routines for PCI. + * + * Based on code from pci.c and iSeries_pci.c 32bit + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "iSeries_IoMmTable.h" +#include "pci.h" + +extern struct pci_controller* hose_head; +extern struct pci_controller** hose_tail; +extern int global_phb_number; +extern int panic_timeout; + +extern struct Naca *naca; +extern struct device_node *allnodes; +extern unsigned long phb_tce_table_init(struct pci_controller *phb); +extern unsigned long iSeries_Base_Io_Memory; + +extern struct pci_ops iSeries_pci_ops; +extern struct flightRecorder* PciFr; +extern struct TceTable* tceTables[256]; + +/******************************************************************* + * Counters and control flags. + *******************************************************************/ +extern long Pci_Io_Read_Count; +extern long Pci_Io_Write_Count; +extern long Pci_Cfg_Read_Count; +extern long Pci_Cfg_Write_Count; +extern long Pci_Error_Count; + +extern int Pci_Retry_Max; +extern int Pci_Error_Flag; +extern int Pci_Trace_Flag; + +extern void iSeries_MmIoTest(void); + + +/******************************************************************* + * Forward declares of prototypes. + *******************************************************************/ +struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev); +struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev); + +unsigned long find_and_init_phbs(void); +void fixup_resources(struct pci_dev *dev); +void iSeries_pcibios_fixup(void); +struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ; + +void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb); +void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel); +int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* Info); +void list_device_nodes(void); + +struct pci_dev; + +extern struct list_head iSeries_Global_Device_List; + +int DeviceCount = 0; + +/********************************************************************************** + * Log Error infor in Flight Recorder to system Console. + * Filter out the device not there errors. + * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx + * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx + * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx + **********************************************************************************/ +void pci_Log_Error(char* Error_Text, int Bus, int SubBus, int AgentId, int HvRc) +{ + if( HvRc != 0x0302) { + char ErrorString[128]; + sprintf(ErrorString,"%s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",Error_Text,Bus,SubBus,AgentId,HvRc); + PCIFR(ErrorString); + printk("PCI: %s\n",ErrorString); + } +} + +/********************************************************************************** + * Dump the iSeries Temp Device Node + *<4>buswalk [swapper : - DeviceNode: 0xC000000000634300 + *<4>00. Device Node = 0xC000000000634300 + *<4> - PciDev = 0x0000000000000000 + *<4> - tDevice = 0x 17:01.00 0x1022 00 + *<4> 4. Device Node = 0xC000000000634480 + *<4> - PciDev = 0x0000000000000000 + *<4> - Device = 0x 18:38.16 Irq:0xA7 Vendor:0x1014 Flags:0x00 + *<4> - Devfn = 0xB0: 22.18 + **********************************************************************************/ +void dumpDevice_Node(struct iSeries_Device_Node* DevNode) +{ + udbg_printf("Device Node = 0x%p\n",DevNode); + udbg_printf(" - PciDev = 0x%p\n",DevNode->PciDev); + udbg_printf(" - Device = 0x%4X:%02X.%02X (0x%02X)\n", + ISERIES_BUS(DevNode), + ISERIES_SUBBUS(DevNode), + DevNode->AgentId, + DevNode->DevFn); + udbg_printf(" - LSlot = 0x%02X\n",DevNode->LogicalSlot); + udbg_printf(" - TceTable = 0x%p\n ",DevNode->DevTceTable); + + udbg_printf(" - DSA = 0x%04X\n",ISERIES_DSA(DevNode)>>32 ); + + udbg_printf(" = Irq:0x%02X Vendor:0x%04X Flags:0x%02X\n", + DevNode->Irq, + DevNode->Vendor, + DevNode->Flags ); + udbg_printf(" - Location = %s\n",DevNode->CardLocation); + + +} +/********************************************************************************** + * Walk down the device node chain + **********************************************************************************/ +void list_device_nodes(void) +{ + struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next; + while(Device_Node_Ptr != &iSeries_Global_Device_List) { + dumpDevice_Node( (struct iSeries_Device_Node*)Device_Node_Ptr ); + Device_Node_Ptr = Device_Node_Ptr->next; + } +} + + +/*********************************************************************** + * build_device_node(u16 Bus, int SubBus, u8 DevFn) + * + ***********************************************************************/ +struct iSeries_Device_Node* build_device_node(HvBusNumber Bus, HvSubBusNumber SubBus, int AgentId, int Function) +{ + struct iSeries_Device_Node* DeviceNode; + + PPCDBG(PPCDBG_BUSWALK,"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function); + + DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); + if(DeviceNode == NULL) return NULL; + + memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) ); + list_add_tail(&DeviceNode->Device_List,&iSeries_Global_Device_List); + /*DeviceNode->DsaAddr = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32); */ + ISERIES_BUS(DeviceNode) = Bus; + ISERIES_SUBBUS(DeviceNode) = SubBus; + DeviceNode->DsaAddr.deviceId = 0x10; + DeviceNode->DsaAddr.barNumber = 0; + DeviceNode->AgentId = AgentId; + DeviceNode->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId),Function ); + DeviceNode->IoRetry = 0; + iSeries_Get_Location_Code(DeviceNode); + PCIFR("Device 0x%02X.%2X, Node:0x%p ",ISERIES_BUS(DeviceNode),ISERIES_DEVFUN(DeviceNode),DeviceNode); + return DeviceNode; +} +/**************************************************************************** +* +* Allocate pci_controller(phb) initialized common variables. +* +*****************************************************************************/ +struct pci_controller* pci_alloc_pci_controllerX(char *model, enum phb_types controller_type) +{ + struct pci_controller *hose; + hose = (struct pci_controller*)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); + if(hose == NULL) return NULL; + + memset(hose, 0, sizeof(struct pci_controller)); + if(strlen(model) < 8) strcpy(hose->what,model); + else memcpy(hose->what,model,7); + hose->type = controller_type; + hose->global_number = global_phb_number; + global_phb_number++; + + *hose_tail = hose; + hose_tail = &hose->next; + return hose; +} + +/**************************************************************************** + * + * unsigned int __init find_and_init_phbs(void) + * + * Description: + * This function checks for all possible system PCI host bridges that connect + * PCI buses. The system hypervisor is queried as to the guest partition + * ownership status. A pci_controller is build for any bus which is partially + * owned or fully owned by this guest partition. + ****************************************************************************/ +unsigned long __init find_and_init_phbs(void) +{ + struct pci_controller* phb; + HvBusNumber BusNumber; + + PPCDBG(PPCDBG_BUSWALK,"find_and_init_phbs Entry\n"); + + /* Check all possible buses. */ + for (BusNumber = 0; BusNumber < 256; BusNumber++) { + int RtnCode = HvCallXm_testBus(BusNumber); + if (RtnCode == 0) { + phb = pci_alloc_pci_controllerX("PHB HV", phb_type_hypervisor); + if(phb == NULL) { + printk("PCI: Allocate pci_controller failed.\n"); + PCIFR( "Allocate pci_controller failed."); + return -1; + } + phb->pci_mem_offset = phb->local_number = BusNumber; + phb->first_busno = BusNumber; + phb->last_busno = BusNumber; + phb->ops = &iSeries_pci_ops; + + PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",phb,BusNumber); + PCIFR("Create iSeries PHB controller: %04X",BusNumber); + + /***************************************************/ + /* Find and connect the devices. */ + /***************************************************/ + iSeries_Scan_PHBs_Slots(phb); + } + /* Check for Unexpected Return code, a clue that something */ + /* has gone wrong. */ + else if(RtnCode != 0x0301) { + PCIFR("Unexpected Return on Probe(0x%04X): 0x%04X",BusNumber,RtnCode); + } + + } + return 0; +} +/*********************************************************************** + * ppc64_pcibios_init + * + * Chance to initialize and structures or variable before PCI Bus walk. + * + *<4>buswalk [swapper : iSeries_pcibios_init Entry. + *<4>buswalk [swapper : IoMmTable Initialized 0xC00000000034BD30 + *<4>buswalk [swapper : find_and_init_phbs Entry + *<4>buswalk [swapper : Create iSeries pci_controller:(0xC00000001F5C7000), Bus 0x0017 + *<4>buswalk [swapper : Connect EADs: 0x17.00.12 = 0x00 + *<4>buswalk [swapper : iSeries_assign_IRQ 0x0017.00.12 = 0x0091 + *<4>buswalk [swapper : - allocate and assign IRQ 0x17.00.12 = 0x91 + *<4>buswalk [swapper : - FoundDevice: 0x17.28.10 = 0x12AE + *<4>buswalk [swapper : - build_device_node 0x17.28.12 + *<4>buswalk [swapper : iSeries_pcibios_init Exit. + ***********************************************************************/ +void iSeries_pcibios_init(void) +{ + PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Entry.\n"); + + iSeries_IoMmTable_Initialize(); + + find_and_init_phbs(); + + pci_assign_all_busses = 0; + PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n"); +} +/*********************************************************************** + * iSeries_pcibios_fixup(void) + ***********************************************************************/ +void __init iSeries_pcibios_fixup(void) +{ + struct pci_dev* PciDev; + struct iSeries_Device_Node* DeviceNode; + char Buffer[256]; + int DeviceCount = 0; + + PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup Entry.\n"); + /******************************************************/ + /* Fix up at the device node and pci_dev relationship */ + /******************************************************/ + mf_displaySrc(0xC9000100); + + pci_for_each_dev(PciDev) { + DeviceNode = find_Device_Node(PciDev); + if(DeviceNode != NULL) { + ++DeviceCount; + PciDev->sysdata = (void*)DeviceNode; + DeviceNode->PciDev = PciDev; + + PPCDBG(PPCDBG_BUSWALK,"PciDev 0x%p <==> DevNode 0x%p\n",PciDev,DeviceNode ); + + iSeries_allocateDeviceBars(PciDev); + + PPCDBGCALL(PPCDBG_BUSWALK,dumpPci_Dev(PciDev) ); + + iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) ); + printk("%d. %s\n",DeviceCount,Buffer); + + create_pci_bus_tce_table((unsigned long)DeviceNode); + } else { + printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev); + } + } + iSeries_IoMmTable_Status(); + + iSeries_activate_IRQs(); + + mf_displaySrc(0xC9000200); +} + +/*********************************************************************** + * iSeries_pcibios_fixup_bus(int Bus) + * + ***********************************************************************/ +void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus) +{ + PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number); + +} + + +/*********************************************************************** + * fixup_resources(struct pci_dev *dev) + * + ***********************************************************************/ +void fixup_resources(struct pci_dev *PciDev) +{ + PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev); +} + + +/******************************************************************************** +* Loop through each node function to find usable EADs bridges. +*********************************************************************************/ +void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb) +{ + struct HvCallPci_DeviceInfo* DevInfo; + HvBusNumber Bus = Phb->local_number; /* System Bus */ + HvSubBusNumber SubBus = 0; /* EADs is always 0. */ + int HvRc = 0; + int IdSel = 1; + int MaxAgents = 8; + + DevInfo = (struct HvCallPci_DeviceInfo*)kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL); + if(DevInfo == NULL) return; + + /******************************************************************************** + * Probe for EADs Bridges + ********************************************************************************/ + for (IdSel=1; IdSel < MaxAgents; ++IdSel) { + HvRc = HvCallPci_getDeviceInfo(Bus, SubBus, IdSel,REALADDR(DevInfo), sizeof(struct HvCallPci_DeviceInfo)); + if (HvRc == 0) { + if(DevInfo->deviceType == HvCallPci_NodeDevice) { + iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel); + } + else printk("PCI: Invalid System Configuration(0x%02X.\n",DevInfo->deviceType); + } + else pci_Log_Error("getDeviceInfo",Bus, SubBus, IdSel,HvRc); + } + kfree(DevInfo); +} + +/******************************************************************************** +* +*********************************************************************************/ +void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel) +{ + struct HvCallPci_BridgeInfo* BridgeInfo; + HvAgentId AgentId; + int Function; + int HvRc; + + BridgeInfo = (struct HvCallPci_BridgeInfo*)kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL); + if(BridgeInfo == NULL) return; + + /********************************************************************* + * Note: hvSubBus and irq is always be 0 at this level! + *********************************************************************/ + for (Function=0; Function < 8; ++Function) { + AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, 0); + if (HvRc == 0) { + /* Connect EADs: 0x18.00.12 = 0x00 */ + PPCDBG(PPCDBG_BUSWALK,"PCI:Connect EADs: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId); + PCIFR( "Connect EADs: 0x%02X.%02X.%02X", Bus, SubBus, AgentId); + HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId, + REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo)); + if (HvRc == 0) { + PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", + BridgeInfo->busUnitInfo.deviceType, + BridgeInfo->subBusNumber, + BridgeInfo->maxAgents, + BridgeInfo->maxSubBusNumber, + BridgeInfo->logicalSlotNumber); + PCIFR( "BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X", + BridgeInfo->busUnitInfo.deviceType, + BridgeInfo->subBusNumber, + BridgeInfo->maxAgents, + BridgeInfo->maxSubBusNumber, + BridgeInfo->logicalSlotNumber); + + if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice) { + /* Scan_Bridge_Slot...: 0x18.00.12 */ + iSeries_Scan_Bridge_Slot(Bus,BridgeInfo); + } + else printk("PCI: Invalid Bridge Configuration(0x%02X)",BridgeInfo->busUnitInfo.deviceType); + } + } + else if(HvRc != 0x000B) pci_Log_Error("EADs Connect",Bus,SubBus,AgentId,HvRc); + } + kfree(BridgeInfo); +} + +/******************************************************************************** +* +* This assumes that the node slot is always on the primary bus! +* +*********************************************************************************/ +int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* BridgeInfo) +{ + struct iSeries_Device_Node* DeviceNode; + HvSubBusNumber SubBus = BridgeInfo->subBusNumber; + u16 VendorId = 0; + int HvRc = 0; + int Irq = 0; + int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus); + int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus); + HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); + int FirstSlotId = 0; + + /**********************************************************/ + /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ + /**********************************************************/ + Irq = iSeries_allocate_IRQ(Bus, 0, AgentId); + iSeries_assign_IRQ(Irq, Bus, 0, AgentId); + PPCDBG(PPCDBG_BUSWALK,"PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",Bus, 0, AgentId, Irq ); + + /**************************************************************************** + * Connect all functions of any device found. + ****************************************************************************/ + for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { + for (Function = 0; Function < 8; ++Function) { + AgentId = ISERIES_PCI_AGENTID(IdSel, Function); + HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq); + if( HvRc == 0) { + HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, PCI_VENDOR_ID, &VendorId); + if( HvRc == 0) { + /**********************************************************/ + /* FoundDevice: 0x18.28.10 = 0x12AE */ + /**********************************************************/ + HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq); + PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n", + Bus, SubBus, AgentId, VendorId); + ++DeviceCount; + DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function); + DeviceNode->Vendor = VendorId; + DeviceNode->Irq = Irq; + DeviceNode->LogicalSlot = BridgeInfo->logicalSlotNumber; + PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X", + DeviceCount,Bus, SubBus, AgentId, + DeviceNode->LogicalSlot,DeviceNode->Vendor); + + /*********************************************************** + * On the first device/function, assign irq to slot + ***********************************************************/ + if(Function == 0) { + FirstSlotId = AgentId; + // AHT iSeries_assign_IRQ(Irq, Bus, SubBus, AgentId); + } + } + else pci_Log_Error("Read Vendor",Bus,SubBus,AgentId,HvRc); + } + else pci_Log_Error("Connect Bus Unit",Bus,SubBus, AgentId,HvRc); + } /* for (Function = 0; Function < 8; ++Function) */ + } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ + return HvRc; +} +/************************************************************************/ +/* I/0 Memory copy MUST use mmio commands on iSeries */ +/* To do; For performance, include the hv call directly */ +/************************************************************************/ +void* iSeries_memset(void* dest, char c, size_t Count) +{ + u8 ByteValue = c; + long NumberOfBytes = Count; + char* IoBuffer = dest; + while(NumberOfBytes > 0) { + iSeries_Write_Byte( ByteValue, (void*)IoBuffer ); + ++IoBuffer; + -- NumberOfBytes; + } + return dest; +} +void* iSeries_memcpy_toio(void *dest, void *source, size_t count) +{ + char *dst = dest; + char *src = source; + long NumberOfBytes = count; + while(NumberOfBytes > 0) { + iSeries_Write_Byte(*src++, (void*)dst++); + -- NumberOfBytes; + } + return dest; +} +void* iSeries_memcpy_fromio(void *dest, void *source, size_t count) +{ + char *dst = dest; + char *src = source; + long NumberOfBytes = count; + while(NumberOfBytes > 0) { + *dst++ = iSeries_Read_Byte( (void*)src++); + -- NumberOfBytes; + } + return dest; +} +/********************************************************************************** + * Look down the chain to find the matching Device Device + **********************************************************************************/ +struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev) +{ + struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next; + int Bus = PciDev->bus->number; + int DevFn = PciDev->devfn; + + while(Device_Node_Ptr != &iSeries_Global_Device_List) { + struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)Device_Node_Ptr; + if(Bus == ISERIES_BUS(DevNode) && DevFn == DevNode->DevFn) { + return DevNode; + } + Device_Node_Ptr = Device_Node_Ptr->next; + } + return NULL; +} +/******************************************************************/ +/* Returns the device node for the passed pci_dev */ +/* Sanity Check Node PciDev to passed pci_dev */ +/* If none is found, returns a NULL which the client must handle. */ +/******************************************************************/ +struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev) +{ + struct iSeries_Device_Node* Node; + Node = (struct iSeries_Device_Node*)PciDev->sysdata; + if(Node == NULL ) { + Node = find_Device_Node(PciDev); + } + else if(Node->PciDev != PciDev) { + Node = find_Device_Node(PciDev); + } + return Node; +} +/********************************************************************************** + * + * Read PCI Config Space Code + * + **********************************************************************************/ +/** BYTE *************************************************************************/ +int iSeries_Node_read_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8* ReadValue) +{ + u8 ReadData; + if(DevNode == NULL) { return 0x301; } + ++Pci_Cfg_Read_Count; + DevNode->ReturnCode = HvCallPci_configLoad8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,&ReadData); + if(Pci_Trace_Flag == 1) { + PCIFR("RCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: RCB: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "RCB: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + } + *ReadValue = ReadData; + return DevNode->ReturnCode; +} +/** WORD *************************************************************************/ +int iSeries_Node_read_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16* ReadValue) +{ + u16 ReadData; + if(DevNode == NULL) { return 0x301; } + ++Pci_Cfg_Read_Count; + DevNode->ReturnCode = HvCallPci_configLoad16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,&ReadData); + if(Pci_Trace_Flag == 1) { + PCIFR("RCW: 0x%04X.%02X 0x%04X = 0x%04X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: RCW: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "RCW: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + + } + *ReadValue = ReadData; + return DevNode->ReturnCode; +} +/** DWORD *************************************************************************/ +int iSeries_Node_read_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32* ReadValue) +{ + u32 ReadData; + if(DevNode == NULL) { return 0x301; } + ++Pci_Cfg_Read_Count; + DevNode->ReturnCode = HvCallPci_configLoad32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,&ReadData); + if(Pci_Trace_Flag == 1) { + PCIFR("RCL: 0x%04X.%02X 0x%04X = 0x%08X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: RCL: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "RCL: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + } + *ReadValue = ReadData; + return DevNode->ReturnCode; +} +int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) { + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_read_config_byte( DevNode ,Offset,ReadValue); +} +int iSeries_pci_read_config_word(struct pci_dev* PciDev, int Offset, u16* ReadValue) { + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_read_config_word( DevNode ,Offset,ReadValue ); +} +int iSeries_pci_read_config_dword(struct pci_dev* PciDev, int Offset, u32* ReadValue) { + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_read_config_dword(DevNode ,Offset,ReadValue ); +} +/**********************************************************************************/ +/* */ +/* Write PCI Config Space */ +/* */ +/** BYTE *************************************************************************/ +int iSeries_Node_write_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8 WriteData) +{ + ++Pci_Cfg_Write_Count; + DevNode->ReturnCode = HvCallPci_configStore8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,WriteData); + if(Pci_Trace_Flag == 1) { + PCIFR("WCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: WCB: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "WCB: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + } + return DevNode->ReturnCode; +} +/** WORD *************************************************************************/ +int iSeries_Node_write_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16 WriteData) +{ + ++Pci_Cfg_Write_Count; + DevNode->ReturnCode = HvCallPci_configStore16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,WriteData); + if(Pci_Trace_Flag == 1) { + PCIFR("WCW: 0x%04X.%02X 0x%04X = 0x%04X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: WCW: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "WCW: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + } + return DevNode->ReturnCode; +} +/** DWORD *************************************************************************/ +int iSeries_Node_write_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32 WriteData) +{ + ++Pci_Cfg_Write_Count; + DevNode->ReturnCode = HvCallPci_configStore32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10, + Offset,WriteData); + if(Pci_Trace_Flag == 1) { + PCIFR("WCL: 0x%04X.%02X 0x%04X = 0x%08X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData); + } + if(DevNode->ReturnCode != 0 ) { + printk("PCI: WCL: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + PCIFR( "WCL: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode); + } + return DevNode->ReturnCode; +} +int iSeries_pci_write_config_byte( struct pci_dev* PciDev,int Offset, u8 WriteValue) +{ + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_write_config_byte( DevNode,Offset,WriteValue); +} +int iSeries_pci_write_config_word( struct pci_dev* PciDev,int Offset,u16 WriteValue) +{ + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_write_config_word( DevNode,Offset,WriteValue); +} +int iSeries_pci_write_config_dword(struct pci_dev* PciDev,int Offset,u32 WriteValue) +{ + struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev); + if(DevNode == NULL) return 0x0301; + return iSeries_Node_write_config_dword(DevNode,Offset,WriteValue); +} + +/************************************************************************/ +/* Branch Table */ +/************************************************************************/ +struct pci_ops iSeries_pci_ops = { + iSeries_pci_read_config_byte, + iSeries_pci_read_config_word, + iSeries_pci_read_config_dword, + iSeries_pci_write_config_byte, + iSeries_pci_write_config_word, + iSeries_pci_write_config_dword +}; + +/************************************************************************ + * Check Return Code + * -> On Failure, print and log information. + * Increment Retry Count, if exceeds max, panic partition. + * -> If in retry, print and log success + ************************************************************************ + * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 + * PCI: Device 23.90 ReadL Retry( 1) + * PCI: Device 23.90 ReadL Retry Successful(1) + ************************************************************************/ +int CheckReturnCode(char* TextHdr, struct iSeries_Device_Node* DevNode, u64 RtnCode) +{ + if(RtnCode != 0) { + ++Pci_Error_Count; + ++DevNode->IoRetry; + PCIFR( "%s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X", + TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode); + printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", + TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode); + /*******************************************************/ + /* Bump the retry and check for retry count exceeded. */ + /* If, Exceeded, panic the system. */ + /*******************************************************/ + if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag > 0 ) { + mf_displaySrc(0xB6000103); + panic_timeout = 0; + panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n"); + } + return -1; /* Retry Try */ + } + /******************************************************************** + * If retry was in progress, log success and rest retry count * + *********************************************************************/ + else if(DevNode->IoRetry > 0) { + PCIFR("%s: Device 0x%04X:%02X Retry Successful(%2d).", + TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry); + DevNode->IoRetry = 0; + return 0; + } + return 0; +} +/************************************************************************/ +/* Translate the I/O Address into a device node, bar, and bar offset. */ +/* Note: Make sure the passed variable end up on the stack to avoid */ +/* the exposure of being device global. */ +/************************************************************************/ +static inline struct iSeries_Device_Node* xlateIoMmAddress(void* IoAddress, + union HvDsaMap* DsaPtr, + u64* BarOffsetPtr) { + + unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory; + long TableIndex = BaseIoAddr/iSeries_IoMmTable_Entry_Size; + struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable +TableIndex); + if(DevNode != NULL) { + DsaPtr->DsaAddr = ISERIES_DSA(DevNode); + DsaPtr->Dsa.barNumber = *(iSeries_IoBarTable+TableIndex); + *BarOffsetPtr = BaseIoAddr % iSeries_IoMmTable_Entry_Size; + } + else { + panic("PCI: Invalid PCI IoAddress detected!\n"); + } + return DevNode; +} + +/************************************************************************/ +/* Read MM I/O Instructions for the iSeries */ +/* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*/ +/* else, data is returned in big Endian format. */ +/************************************************************************/ +/* iSeries_Read_Byte = Read Byte ( 8 bit) */ +/* iSeries_Read_Word = Read Word (16 bit) */ +/* iSeries_Read_Long = Read Long (32 bit) */ +/************************************************************************/ +u8 iSeries_Read_Byte(void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad8, &Return, DsaData.DsaAddr,BarOffset, 0); + } while (CheckReturnCode("RDB",DevNode, Return.rc) != 0); + + if(Pci_Trace_Flag == 1) PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value); + return (u8)Return.value; +} +u16 iSeries_Read_Word(void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad16,&Return, DsaData.DsaAddr,BarOffset, 0); + } while (CheckReturnCode("RDW",DevNode, Return.rc) != 0); + + if(Pci_Trace_Flag == 1) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, swab16((u16)Return.value)); + return swab16((u16)Return.value); +} +u32 iSeries_Read_Long(void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Read_Count; + HvCall3Ret16(HvCallPciBarLoad32,&Return, DsaData.DsaAddr,BarOffset, 0); + } while (CheckReturnCode("RDL",DevNode, Return.rc) != 0); + + if(Pci_Trace_Flag == 1) PCIFR("RDL: IoAddress 0x%p = 0x%04X",IoAddress, swab32((u32)Return.value)); + return swab32((u32)Return.value); +} +/************************************************************************/ +/* Write MM I/O Instructions for the iSeries */ +/************************************************************************/ +/* iSeries_Write_Byte = Write Byte (8 bit) */ +/* iSeries_Write_Word = Write Word(16 bit) */ +/* iSeries_Write_Long = Write Long(32 bit) */ +/************************************************************************/ +void iSeries_Write_Byte(u8 Data, void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Write_Count; + Return.rc = HvCall4(HvCallPciBarStore8, DsaData.DsaAddr,BarOffset, Data, 0); + } while (CheckReturnCode("WWB",DevNode, Return.rc) != 0); + if(Pci_Trace_Flag == 1) PCIFR("WWB: IoAddress 0x%p = 0x%02X",IoAddress,Data); +} +void iSeries_Write_Word(u16 Data, void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Write_Count; + Return.rc = HvCall4(HvCallPciBarStore16,DsaData.DsaAddr,BarOffset, swab16(Data), 0); + } while (CheckReturnCode("WWW",DevNode, Return.rc) != 0); + if(Pci_Trace_Flag == 1) PCIFR("WWW: IoAddress 0x%p = 0x%04X",IoAddress,Data); +} +void iSeries_Write_Long(u32 Data, void* IoAddress) +{ + u64 BarOffset; + union HvDsaMap DsaData; + struct HvCallPci_LoadReturn Return; + struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset); + + do { + ++Pci_Io_Write_Count; + Return.rc = HvCall4(HvCallPciBarStore32,DsaData.DsaAddr,BarOffset, swab32(Data), 0); + } while (CheckReturnCode("WWL",DevNode, Return.rc) != 0); + if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data); +} +/* + * This is called very early before the page table is setup. + * There are warnings here because of type mismatches.. Okay for now. AHT + */ +void +iSeries_pcibios_init_early(void) +{ + //ppc_md.pcibios_read_config_byte = iSeries_Node_read_config_byte; + //ppc_md.pcibios_read_config_word = iSeries_Node_read_config_word; + //ppc_md.pcibios_read_config_dword = iSeries_Node_read_config_dword; + //ppc_md.pcibios_write_config_byte = iSeries_Node_write_config_byte; + //ppc_md.pcibios_write_config_word = iSeries_Node_write_config_word; + //ppc_md.pcibios_write_config_dword = iSeries_Node_write_config_dword; +} + +/************************************************************************/ +/* Set the slot reset line to the state passed in. */ +/* This is the platform specific for code for the pci_reset_device */ +/* function. */ +/************************************************************************/ +int pci_set_reset(struct pci_dev* PciDev, int State) { + struct iSeries_Device_Node* DeviceNode = (struct iSeries_Device_Node*)PciDev->sysdata; + if (DeviceNode == NULL) { + printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n",PciDev); + return -1; + } + DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId,State); + return DeviceNode->ReturnCode; +} diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_pci_reset.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci_reset.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_pci_reset.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci_reset.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,88 @@ +/************************************************************************/ +/* File iSeries_pci_reset.c created by Allan Trautman on Mar 21 2001. */ +/************************************************************************/ +/* This code supports the pci interface on the IBM iSeries systems. */ +/* Copyright (C) 20yy */ +/* */ +/* 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 */ +/************************************************************************/ +/* Change Activity: */ +/* Created, March 20, 2001 */ +/* April 30, 2001, Added return codes on functions. */ +/* September 10, 2001, Ported to ppc64. */ +/* End Change Activity */ +/************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "pci.h" + +/************************************************************************/ +/* Interface to toggle the reset line */ +/* Time is in .1 seconds, need for seconds. */ +/************************************************************************/ +int iSeries_Device_ToggleReset(struct pci_dev* PciDev, int AssertTime, int DelayTime) +{ + unsigned long AssertDelay, WaitDelay; + struct iSeries_Device_Node* DeviceNode = (struct iSeries_Device_Node*)PciDev->sysdata; + if (DeviceNode == NULL) { + printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n",PciDev); + return -1; + } + /******************************************************************** + * Set defaults, Assert is .5 second, Wait is 3 seconds. + ********************************************************************/ + if (AssertTime == 0) AssertDelay = ( 5 * HZ)/10; + else AssertDelay = (AssertTime*HZ)/10; + if (WaitDelay == 0) WaitDelay = (30 * HZ)/10; + else WaitDelay = (DelayTime* HZ)/10; + + /******************************************************************** + * Assert reset + ********************************************************************/ + DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId,1); + if (DeviceNode->ReturnCode == 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(AssertDelay); /* Sleep for the time */ + DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId, 0); + + /*************************************************************** + * Wait for device to reset + ***************************************************************/ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(WaitDelay); + } + if (DeviceNode->ReturnCode == 0) { + PCIFR("Slot 0x%04X.%02 Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId ); + } + else { + printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode); + PCIFR( "Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode); + } + return DeviceNode->ReturnCode; +} diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_proc.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_proc.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_proc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,142 @@ +/* + * iSeries_proc.c + * Copyright (C) 2001 Kyle A. Lucke IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* Change Activity: */ +/* End Change Activity */ + +#include +#include +#ifndef _ISERIES_PROC_H +#include +#endif + + +static struct proc_dir_entry * iSeries_proc_root = NULL; +static int iSeries_proc_initializationDone = 0; +static spinlock_t iSeries_proc_lock; + +struct iSeries_proc_registration +{ + struct iSeries_proc_registration *next; + iSeriesProcFunction functionMember; +}; + + +struct iSeries_proc_registration preallocated[16]; +#define MYQUEUETYPE(T) struct MYQueue##T +#define MYQUEUE(T) \ +MYQUEUETYPE(T) \ +{ \ + struct T *head; \ + struct T *tail; \ +} +#define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0) +#define MYQUEUEENQ(q, p) \ +do { \ + (p)->next = NULL; \ + if ((q)->head != NULL) { \ + (q)->head->next = (p); \ + (q)->head = (p); \ + } else { \ + (q)->tail = (q)->head = (p); \ + } \ +} while(0) + +#define MYQUEUEDEQ(q,p) \ +do { \ + (p) = (q)->tail; \ + if ((p) != NULL) { \ + (q)->tail = (p)->next; \ + (p)->next = NULL; \ + } \ + if ((q)->tail == NULL) \ + (q)->head = NULL; \ +} while(0) +MYQUEUE(iSeries_proc_registration); +typedef MYQUEUETYPE(iSeries_proc_registration) aQueue; + + +aQueue iSeries_free; +aQueue iSeries_queued; + +void iSeries_proc_early_init(void) +{ + int i = 0; + unsigned long flags; + iSeries_proc_initializationDone = 0; + spin_lock_init(&iSeries_proc_lock); + MYQUEUECTOR(&iSeries_free); + MYQUEUECTOR(&iSeries_queued); + + spin_lock_irqsave(&iSeries_proc_lock, flags); + for (i = 0; i < 16; ++i) { + MYQUEUEENQ(&iSeries_free, preallocated+i); + } + spin_unlock_irqrestore(&iSeries_proc_lock, flags); +} + +void iSeries_proc_create(void) +{ + unsigned long flags; + struct iSeries_proc_registration *reg = NULL; + spin_lock_irqsave(&iSeries_proc_lock, flags); + printk("iSeries_proc: Creating /proc/iSeries\n"); + + iSeries_proc_root = proc_mkdir("iSeries", 0); + if (!iSeries_proc_root) return; + + MYQUEUEDEQ(&iSeries_queued, reg); + + while (reg != NULL) { + (*(reg->functionMember))(iSeries_proc_root); + + MYQUEUEDEQ(&iSeries_queued, reg); + } + + iSeries_proc_initializationDone = 1; + spin_unlock_irqrestore(&iSeries_proc_lock, flags); +} + +void iSeries_proc_callback(iSeriesProcFunction initFunction) +{ + unsigned long flags; + spin_lock_irqsave(&iSeries_proc_lock, flags); + + if (iSeries_proc_initializationDone) { + (*initFunction)(iSeries_proc_root); + } else { + struct iSeries_proc_registration *reg = NULL; + + MYQUEUEDEQ(&iSeries_free, reg); + + if (reg != NULL) { + /* printk("Registering %p in reg %p\n", initFunction, reg); */ + reg->functionMember = initFunction; + + MYQUEUEENQ(&iSeries_queued, reg); + } else { + printk("Couldn't get a queue entry\n"); + } + } + + spin_unlock_irqrestore(&iSeries_proc_lock, flags); +} + + diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_rtc.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_rtc.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_rtc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,264 @@ +/* + * Real Time Clock interface for IBM iSeries + * + * Based on rtc.c by Paul Gortmaker + * + * This driver allows use of the real time clock + * from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the + * /proc/driver/rtc pseudo-file for status information. + * + * iSeries does not support RTC interrupts nor an alarm. + * + * 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. + * + * 1.0 Mike Corrigan: IBM iSeries rtc support + */ + +#define RTC_VERSION "1.0" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin); + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos); + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static void get_rtc_time (struct rtc_time *rtc_tm); + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Now all the various file operations that we export. + */ + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return -EIO; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time wtime; + + switch (cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 70) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ( yrs > 169 ) + return -EINVAL; + + mf_setRtc( &rtc_tm ); + + return 0; + } + case RTC_EPOCH_READ: /* Read the epoch. */ + { + return put_user (epoch, (unsigned long *)arg); + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { + /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) + return -EINVAL; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + epoch = arg; + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_llseek, + read: rtc_read, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int __init rtc_init(void) +{ + misc_register(&rtc_dev); + create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + + printk(KERN_INFO "iSeries Real Time Clock Driver v" RTC_VERSION "\n"); + + return 0; +} + +static void __exit rtc_exit (void) +{ + remove_proc_entry ("driver/rtc", NULL); + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); +EXPORT_NO_SYMBOLS; + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_output (char *buf) +{ + + char *p; + struct rtc_time tm; + + p = buf; + + get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + p += sprintf(p, + "DST_enable\t: no\n" + "BCD\t\t: yes\n" + "24hr\t\t: yes\n" ); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_proc_output (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 void get_rtc_time(struct rtc_time *rtc_tm) +{ + mf_getRtc( rtc_tm ); + + rtc_tm->tm_mon--; +} + + diff -urN linux-2.4.18/arch/ppc64/kernel/iSeries_setup.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.c --- linux-2.4.18/arch/ppc64/kernel/iSeries_setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,901 @@ +/* + * + * + * Copyright (c) 2000 Mike Corrigan + * Copyright (c) 1999-2000 Grant Erickson + * + * Module name: iSeries_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "iSeries_setup.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function Prototypes */ + +extern void abort(void); +#ifdef CONFIG_PPC_ISERIES +static void build_iSeries_Memory_Map( void ); +static void setup_iSeries_cache_sizes( void ); +static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); +#endif +void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa, + pte_t * ptep, unsigned hpteflags, unsigned bolted ); +extern void ppcdbg_initialize(void); +extern void iSeries_pcibios_init(void); +extern void iSeries_pcibios_fixup(void); +extern void iSeries_pcibios_fixup_bus(int); +static void iSeries_setup_dprofile(void); + +/* Global Variables */ + +static unsigned long procFreqHz = 0; +static unsigned long procFreqMhz = 0; +static unsigned long procFreqMhzHundreths = 0; + +static unsigned long tbFreqHz = 0; +static unsigned long tbFreqMhz = 0; +static unsigned long tbFreqMhzHundreths = 0; + +unsigned long dprof_shift = 0; +unsigned long dprof_len = 0; +unsigned int * dprof_buffer = NULL; + +int piranha_simulator = 0; + +extern char _end[]; + +extern struct Naca *naca; +extern int rd_size; /* Defined in drivers/block/rd.c */ +extern unsigned long klimit; +extern unsigned long embedded_sysmap_start; +extern unsigned long embedded_sysmap_end; + +extern unsigned long iSeries_recal_tb; +extern unsigned long iSeries_recal_titan; + +extern char _stext; +extern char _etext; + +static int mf_initialized = 0; + +struct MemoryBlock { + unsigned long absStart; + unsigned long absEnd; + unsigned long logicalStart; + unsigned long logicalEnd; +}; + +/* + * Process the main store vpd to determine where the holes in memory are + * and return the number of physical blocks and fill in the array of + * block data. + */ + +unsigned long iSeries_process_Condor_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries ) +{ + /* Determine if absolute memory has any + * holes so that we can interpret the + * access map we get back from the hypervisor + * correctly. + */ + + unsigned long holeFirstChunk, holeSizeChunks; + unsigned long numMemoryBlocks = 1; + struct IoHriMainStoreSegment4 * msVpd = (struct IoHriMainStoreSegment4 *)xMsVpd; + unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; + unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; + unsigned long holeSize = holeEnd - holeStart; + + printk("Mainstore_VPD: Condor\n"); + + mb_array[0].logicalStart = 0; + mb_array[0].logicalEnd = 0x100000000; + mb_array[0].absStart = 0; + mb_array[0].absEnd = 0x100000000; + + if ( holeSize ) { + numMemoryBlocks = 2; + holeStart = holeStart & 0x000fffffffffffff; + holeStart = addr_to_chunk(holeStart); + holeFirstChunk = holeStart; + holeSize = addr_to_chunk(holeSize); + holeSizeChunks = holeSize; + printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", + holeFirstChunk, holeSizeChunks ); + mb_array[0].logicalEnd = holeFirstChunk; + mb_array[0].absEnd = holeFirstChunk; + mb_array[1].logicalStart = holeFirstChunk; + mb_array[1].logicalEnd = 0x100000000 - holeSizeChunks; + mb_array[1].absStart = holeFirstChunk + holeSizeChunks; + mb_array[1].absEnd = 0x100000000; + } + + + return numMemoryBlocks; +} + +#define MaxSegmentAreas 32 +#define MaxSegmentAdrRangeBlocks 128 +#define MaxAreaRangeBlocks 4 +unsigned long iSeries_process_Regatta_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries ) +{ + struct IoHriMainStoreSegment5 * msVpdP = (struct IoHriMainStoreSegment5 *)xMsVpd; + unsigned long numSegmentBlocks = 0; + u32 existsBits = msVpdP->msAreaExists; + unsigned long area_num; + + printk("Mainstore_VPD: Regatta\n"); + + for ( area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { + unsigned long numAreaBlocks; + struct IoHriMainStoreArea4 * currentArea; + + if ( existsBits & 0x80000000 ) { + unsigned long block_num; + + currentArea = &msVpdP->msAreaArray[area_num]; + numAreaBlocks = currentArea->numAdrRangeBlocks; + + printk("ms_vpd: processing area %2ld blocks=%ld", area_num, numAreaBlocks); + + for ( block_num = 0; block_num < numAreaBlocks; ++block_num ) { + /* Process an address range block */ + struct MemoryBlock tempBlock; + unsigned long i; + + tempBlock.absStart = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; + tempBlock.absEnd = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; + tempBlock.logicalStart = 0; + tempBlock.logicalEnd = 0; + + printk("\n block %ld absStart=%016lx absEnd=%016lx", block_num, + tempBlock.absStart, tempBlock.absEnd); + + for ( i=0; i 1 ) { + unsigned long m, n; + for ( m=0; mxRamDisk ) { + initrd_start = (unsigned long)__va(naca->xRamDisk); + initrd_end = initrd_start + naca->xRamDiskSize * PAGE_SIZE; + initrd_below_start_ok = 1; // ramdisk in kernel space + ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 ); + + if ( ((rd_size*1024)/PAGE_SIZE) < naca->xRamDiskSize ) + rd_size = (naca->xRamDiskSize*PAGE_SIZE)/1024; + } else + +#endif /* CONFIG_BLK_DEV_INITRD */ + { + + /* ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); */ + } + + iSeries_recal_tb = get_tb(); + iSeries_recal_titan = HvCallXm_loadTod(); + + ppc_md.setup_arch = iSeries_setup_arch; + ppc_md.setup_residual = iSeries_setup_residual; + ppc_md.get_cpuinfo = iSeries_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = iSeries_init_IRQ; + ppc_md.init_ras_IRQ = NULL; + ppc_md.get_irq = iSeries_get_irq; + ppc_md.init = NULL; + + ppc_md.pcibios_fixup = iSeries_pcibios_fixup; + ppc_md.pcibios_fixup_bus = iSeries_pcibios_fixup_bus; + + ppc_md.restart = iSeries_restart; + ppc_md.power_off = iSeries_power_off; + ppc_md.halt = iSeries_halt; + + ppc_md.time_init = NULL; + ppc_md.get_boot_time = iSeries_get_boot_time; + ppc_md.set_rtc_time = iSeries_set_rtc_time; + ppc_md.get_rtc_time = iSeries_get_rtc_time; + ppc_md.calibrate_decr = iSeries_calibrate_decr; + ppc_md.progress = iSeries_progress; + + 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 + + hpte_init_iSeries(); + tce_init_iSeries(); + + /* Initialize the table which translate Linux physical addresses to + * AS/400 absolute addresses + */ + + build_iSeries_Memory_Map(); + + setup_iSeries_cache_sizes(); + + /* Initialize machine-dependency vectors */ + + +#ifdef CONFIG_SMP + smp_init_iSeries(); +#endif + + if ( itLpNaca.xPirEnvironMode == 0 ) + piranha_simulator = 1; +#endif +} + +/* + * void __init iSeries_init() + */ + +void __init +iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* Associate Lp Event Queue 0 with processor 0 */ + HvCallEvent_setLpEventQueueInterruptProc( 0, 0 ); + + { + /* copy the command line parameter from the primary VSP */ + char *p, *q; + HvCallEvent_dmaToSp( cmd_line, + 2*64*1024, + 256, + HvLpDma_Direction_RemoteToLocal ); + + p = q = cmd_line + 255; + while( p > cmd_line ) { + if ((*p == 0) || (*p == ' ') || (*p == '\n')) + --p; + else + break; + } + if ( p < q ) + *(p+1) = 0; + } + + if (strstr(cmd_line, "dprofile=")) { + char *p, *q; + + for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) { + unsigned long size, new_klimit; + q = p + 9; + if (p > cmd_line && p[-1] != ' ') + continue; + dprof_shift = simple_strtoul(q, &q, 0); + dprof_len = (unsigned long)&_etext - (unsigned long)&_stext; + dprof_len >>= dprof_shift; + size = ((dprof_len * sizeof(unsigned int)) + (PAGE_SIZE-1)) & PAGE_MASK; + dprof_buffer = (unsigned int *)((klimit + (PAGE_SIZE-1)) & PAGE_MASK); + new_klimit = ((unsigned long)dprof_buffer) + size; + lmb_reserve( __pa(klimit), (new_klimit-klimit)); + klimit = new_klimit; + memset( dprof_buffer, 0, size ); + } + } + + iSeries_setup_dprofile(); + + iSeries_proc_early_init(); + mf_init(); + mf_initialized = 1; + mb(); + + iSeries_proc_callback( &pmc_proc_init ); +} + +#ifdef CONFIG_PPC_ISERIES +/* + * The iSeries may have very large memories ( > 128 GB ) and a partition + * may get memory in "chunks" that may be anywhere in the 2**52 real + * address space. The chunks are 256K in size. To map this to the + * memory model Linux expects, the AS/400 specific code builds a + * translation table to translate what Linux thinks are "physical" + * addresses to the actual real addresses. This allows us to make + * it appear to Linux that we have contiguous memory starting at + * physical address zero while in fact this could be far from the truth. + * To avoid confusion, I'll let the words physical and/or real address + * apply to the Linux addresses while I'll use "absolute address" to + * refer to the actual hardware real address. + * + * build_iSeries_Memory_Map gets information from the Hypervisor and + * looks at the Main Store VPD to determine the absolute addresses + * of the memory that has been assigned to our partition and builds + * a table used to translate Linux's physical addresses to these + * absolute addresses. Absolute addresses are needed when + * communicating with the hypervisor (e.g. to build HPT entries) + */ + +static void __init build_iSeries_Memory_Map(void) +{ + u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; + u32 nextPhysChunk; + u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; + u32 num_ptegs; + u32 totalChunks,moreChunks; + u32 currChunk, thisChunk, absChunk; + u32 currDword; + u32 chunkBit; + u64 map; + struct MemoryBlock mb[32]; + unsigned long numMemoryBlocks, curBlock; + + /* Chunk size on iSeries is 256K bytes */ + totalChunks = (u32)HvLpConfig_getMsChunks(); + klimit = msChunks_alloc(klimit, totalChunks, 1UL<<18); + + /* Get absolute address of our load area + * and map it to physical address 0 + * This guarantees that the loadarea ends up at physical 0 + * otherwise, it might not be returned by PLIC as the first + * chunks + */ + + loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); + loadAreaSize = itLpNaca.xLoadAreaChunks; + + /* Only add the pages already mapped here. + * Otherwise we might add the hpt pages + * The rest of the pages of the load area + * aren't in the HPT yet and can still + * be assigned an arbitrary physical address + */ + if ( (loadAreaSize * 64) > HvPagesToMap ) + loadAreaSize = HvPagesToMap / 64; + + loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; + + /* TODO Do we need to do something if the HPT is in the 64MB load area? + * This would be required if the itLpNaca.xLoadAreaChunks includes + * the HPT size + */ + + printk( "Mapping load area - physical addr = 0000000000000000\n" + " absolute addr = %016lx\n", + chunk_to_addr(loadAreaFirstChunk) ); + printk( "Load area size %dK\n", loadAreaSize*256 ); + + for ( nextPhysChunk = 0; + nextPhysChunk < loadAreaSize; + ++nextPhysChunk ) { + msChunks.abs[nextPhysChunk] = loadAreaFirstChunk+nextPhysChunk; + } + + /* Get absolute address of our HPT and remember it so + * we won't map it to any physical address + */ + + hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); + hptSizePages = (u32)(HvCallHpt_getHptPages()); + hptSizeChunks = hptSizePages >> (msChunks.chunk_shift-PAGE_SHIFT); + hptLastChunk = hptFirstChunk + hptSizeChunks - 1; + + printk( "HPT absolute addr = %016lx, size = %dK\n", + chunk_to_addr(hptFirstChunk), hptSizeChunks*256 ); + + /* Fill in the htab_data structure */ + + /* Fill in size of hashed page table */ + num_ptegs = hptSizePages * (PAGE_SIZE/(sizeof(HPTE)*HPTES_PER_GROUP)); + htab_data.htab_num_ptegs = num_ptegs; + htab_data.htab_hash_mask = num_ptegs - 1; + + /* The actual hashed page table is in the hypervisor, we have no direct access */ + htab_data.htab = NULL; + + /* Determine if absolute memory has any + * holes so that we can interpret the + * access map we get back from the hypervisor + * correctly. + */ + numMemoryBlocks = iSeries_process_mainstore_vpd( mb, 32 ); + + /* Process the main store access map from the hypervisor + * to build up our physical -> absolute translation table + */ + curBlock = 0; + currChunk = 0; + currDword = 0; + moreChunks = totalChunks; + + while ( moreChunks ) { + map = HvCallSm_get64BitsOfAccessMap( itLpNaca.xLpIndex, + currDword ); + thisChunk = currChunk; + while ( map ) { + chunkBit = map >> 63; + map <<= 1; + if ( chunkBit ) { + --moreChunks; + + while ( thisChunk >= mb[curBlock].logicalEnd ) { + ++curBlock; + if ( curBlock >= numMemoryBlocks ) + panic("out of memory blocks"); + } + if ( thisChunk < mb[curBlock].logicalStart ) + panic("memory block error"); + + absChunk = mb[curBlock].absStart + ( thisChunk - mb[curBlock].logicalStart ); + + if ( ( ( absChunk < hptFirstChunk ) || + ( absChunk > hptLastChunk ) ) && + ( ( absChunk < loadAreaFirstChunk ) || + ( absChunk > loadAreaLastChunk ) ) ) { + msChunks.abs[nextPhysChunk] = absChunk; + ++nextPhysChunk; + } + } + ++thisChunk; + } + ++currDword; + currChunk += 64; + } + + /* main store size (in chunks) is + * totalChunks - hptSizeChunks + * which should be equal to + * nextPhysChunk + */ + naca->physicalMemorySize = chunk_to_addr(nextPhysChunk); + + /* Bolt kernel mappings for all of memory */ + iSeries_bolt_kernel( 0, naca->physicalMemorySize ); + + lmb_init(); + lmb_add( 0, naca->physicalMemorySize ); + lmb_analyze(); /* ?? */ + lmb_reserve( 0, __pa(klimit)); + + /* + * Hardcode to GP size. I am not sure where to get this info. DRENG + */ + naca->slb_size = 64; +} + +/* + * Set up the variables that describe the cache line sizes + * for this machine. + */ + +static void __init setup_iSeries_cache_sizes(void) +{ + unsigned i,n; + unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex; + + naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize; + naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize; + naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize; + naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize; + i = naca->iCacheL1LineSize; + n = 0; + while ((i=(i/2))) ++n; + naca->iCacheL1LogLineSize = n; + i = naca->dCacheL1LineSize; + n = 0; + while ((i=(i/2))) ++n; + naca->dCacheL1LogLineSize = n; + + printk( "D-cache line size = %d (log = %d)\n", + (unsigned)naca->dCacheL1LineSize, + (unsigned)naca->dCacheL1LogLineSize ); + printk( "I-cache line size = %d (log = %d)\n", + (unsigned)naca->iCacheL1LineSize, + (unsigned)naca->iCacheL1LogLineSize ); + +} + +/* + * Bolt the kernel addr space into the HPT + */ + +static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) +{ + unsigned long pa; + unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; + HPTE hpte; + + for (pa=saddr; pa < eaddr ;pa+=PAGE_SIZE) { + unsigned long ea = (unsigned long)__va(pa); + unsigned long vsid = get_kernel_vsid( ea ); + unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff ); + unsigned long vpn = va >> PAGE_SHIFT; + unsigned long slot = HvCallHpt_findValid( &hpte, vpn ); + if ( hpte.dw0.dw0.v ) { + /* HPTE exists, so just bolt it */ + HvCallHpt_setSwBits( slot, 0x10, 0 ); + } else { + /* No HPTE exists, so create a new bolted one */ + build_valid_hpte(vsid, ea, pa, NULL, mode_rw, 1); + } + } +} +#endif /* CONFIG_PPC_ISERIES */ + +extern unsigned long ppc_proc_freq; +extern unsigned long ppc_tb_freq; + +/* + * Document me. + */ +void __init +iSeries_setup_arch(void) +{ + void * eventStack; + unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex; + + /* Setup the Lp Event Queue */ + + /* Allocate a page for the Event Stack + * The hypervisor wants the absolute real address, so + * we subtract out the KERNELBASE and add in the + * absolute real address of the kernel load area + */ + + eventStack = alloc_bootmem_pages( LpEventStackSize ); + + memset( eventStack, 0, LpEventStackSize ); + + /* Invoke the hypervisor to initialize the event stack */ + + HvCallEvent_setLpEventStack( 0, eventStack, LpEventStackSize ); + + /* Initialize fields in our Lp Event Queue */ + + xItLpQueue.xSlicEventStackPtr = (char *)eventStack; + xItLpQueue.xSlicCurEventPtr = (char *)eventStack; + xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack + + (LpEventStackSize - LpEventMaxSize); + xItLpQueue.xIndex = 0; + + /* Compute processor frequency */ + procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq ); + procFreqMhz = procFreqHz / 1000000; + procFreqMhzHundreths = (procFreqHz/10000) - (procFreqMhz*100); + + ppc_proc_freq = procFreqHz; + + /* Compute time base frequency */ + tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq ); + tbFreqMhz = tbFreqHz / 1000000; + tbFreqMhzHundreths = (tbFreqHz/10000) - (tbFreqMhz*100); + + ppc_tb_freq = tbFreqHz; + + printk("Max logical processors = %d\n", + itVpdAreas.xSlicMaxLogicalProcs ); + printk("Max physical processors = %d\n", + itVpdAreas.xSlicMaxPhysicalProcs ); + printk("Processor frequency = %lu.%02lu\n", + procFreqMhz, + procFreqMhzHundreths ); + printk("Time base frequency = %lu.%02lu\n", + tbFreqMhz, + tbFreqMhzHundreths ); + printk("Processor version = %x\n", + xIoHriProcessorVpd[procIx].xPVR ); + +} + +/* + * int as400_setup_residual() + * + * Description: + * This routine pretty-prints CPU information gathered from the VPD + * for use in /proc/cpuinfo + * + * Input(s): + * *buffer - Buffer into which CPU data is to be printed. + * + * Output(s): + * *buffer - Buffer with CPU data. + * + * Returns: + * The number of bytes copied into 'buffer' if OK, otherwise zero or less + * on error. + */ +void iSeries_setup_residual(struct seq_file *m) +{ + + seq_printf(m,"clock\t\t: %lu.%02luMhz\n", + procFreqMhz, procFreqMhzHundreths ); + seq_printf(m,"time base\t: %lu.%02luMHz\n", + tbFreqMhz, tbFreqMhzHundreths ); + seq_printf(m,"i-cache\t\t: %d\n", + naca->iCacheL1LineSize); + seq_printf(m,"d-cache\t\t: %d\n", + naca->dCacheL1LineSize); + +} + +void iSeries_get_cpuinfo(struct seq_file *m) +{ + + seq_printf(m,"machine\t\t: 64-bit iSeries Logical Partition\n"); + +} + +/* + * Document me. + * and Implement me. + */ +int +iSeries_get_irq(struct pt_regs *regs) +{ + /* -2 means ignore this interrupt */ + return -2; +} + +/* + * Document me. + */ +void +iSeries_restart(char *cmd) +{ + mf_reboot(); +} + +/* + * Document me. + */ +void +iSeries_power_off(void) +{ + mf_powerOff(); +} + +/* + * Document me. + */ +void +iSeries_halt(void) +{ + mf_powerOff(); +} + +/* + * Nothing to do here. + */ +void __init +iSeries_time_init(void) +{ + /* Nothing to do */ +} + +/* JDH Hack */ +unsigned long jdh_time = 0; + +extern void setup_default_decr(void); + +/* + * void __init iSeries_calibrate_decr() + * + * Description: + * This routine retrieves the internal processor frequency from the VPD, + * and sets up the kernel timer decrementer based on that value. + * + */ +void __init +iSeries_calibrate_decr(void) +{ + unsigned long cyclesPerUsec; + + struct div_result divres; + + /* Compute decrementer (and TB) frequency + * in cycles/sec + */ + + cyclesPerUsec = ppc_tb_freq / 1000000; /* cycles / usec */ + + /* Set the amount to refresh the decrementer by. This + * is the number of decrementer ticks it takes for + * 1/HZ seconds. + */ + + tb_ticks_per_jiffy = ppc_tb_freq / HZ; + +#if 0 + /* TEST CODE FOR ADJTIME */ + tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000; + /* END OF TEST CODE */ +#endif + + /* + * tb_ticks_per_sec = freq; would give better accuracy + * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures + * that jiffies (and xtime) will match the time returned + * by do_gettimeofday. + */ + tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; + tb_ticks_per_usec = cyclesPerUsec; + tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); + div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres ); + tb_to_xs = divres.result_low; + setup_default_decr(); +} + +void __init +iSeries_progress( char * st, unsigned short code ) +{ + printk( "Progress: [%04x] - %s\n", (unsigned)code, st ); + if ( !piranha_simulator && mf_initialized ) { + if (code != 0xffff) + mf_displayProgress( code ); + else + mf_clearSrc(); + } +} + + +void iSeries_fixup_klimit(void) +{ + /* Change klimit to take into account any ram disk that may be included */ + if (naca->xRamDisk) + klimit = KERNELBASE + (u64)naca->xRamDisk + (naca->xRamDiskSize * PAGE_SIZE); + else { + /* No ram disk was included - check and see if there was an embedded system map */ + /* Change klimit to take into account any embedded system map */ + if (embedded_sysmap_end) + klimit = KERNELBASE + ((embedded_sysmap_end+4095) & 0xfffffffffffff000); + } +} + +static void iSeries_setup_dprofile(void) +{ + if ( dprof_buffer ) { + unsigned i; + for (i=0; i + * Copyright (c) 1999-2000 Grant Erickson + * + * Module name: as400_setup.h + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __ISERIES_SETUP_H__ +#define __ISERIES_SETUP_H__ + +extern void iSeries_init_early(void); +extern void iSeries_init(unsigned long r3, + unsigned long ird_start, + unsigned long ird_end, + unsigned long cline_start, + unsigned long cline_end); +extern void iSeries_setup_arch(void); +extern void iSeries_setup_residual(struct seq_file *m); +extern void iSeries_get_cpuinfo(struct seq_file *m); +extern void iSeries_init_IRQ(void); +extern int iSeries_get_irq(struct pt_regs *regs); +extern void iSeries_restart(char *cmd); +extern void iSeries_power_off(void); +extern void iSeries_halt(void); +extern void iSeries_time_init(void); +extern void iSeries_get_boot_time(struct rtc_time *tm); +extern int iSeries_set_rtc_time(unsigned long now); +extern unsigned long iSeries_get_rtc_time(void); +extern void iSeries_calibrate_decr(void); +extern void iSeries_progress( char *, unsigned short ); + +#endif /* __ISERIES_SETUP_H__ */ diff -urN linux-2.4.18/arch/ppc64/kernel/idle.c linux-2.4.19-pre5/arch/ppc64/kernel/idle.c --- linux-2.4.18/arch/ppc64/kernel/idle.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/idle.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,135 @@ +/* + * Idle daemon for PowerPC. Idle daemon will handle any action + * that needs to be taken when the system becomes idle. + * + * Written by Cort Dougan (cort@cs.nmt.edu) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +unsigned long maxYieldTime = 0; +unsigned long minYieldTime = 0xffffffffffffffffUL; + +#ifdef CONFIG_PPC_ISERIES +static void yield_shared_processor(void) +{ + struct Paca *paca; + unsigned long tb; + unsigned long yieldTime; + + paca = (struct Paca *)mfspr(SPRG3); + HvCall_setEnabledInterrupts( HvCall_MaskIPI | + HvCall_MaskLpEvent | + HvCall_MaskLpProd | + HvCall_MaskTimeout ); + + tb = get_tb(); + /* Compute future tb value when yield should expire */ + HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy ); + + yieldTime = get_tb() - tb; + if ( yieldTime > maxYieldTime ) + maxYieldTime = yieldTime; + + if ( yieldTime < minYieldTime ) + minYieldTime = yieldTime; + + /* The decrementer stops during the yield. Force a fake decrementer + * here and let the timer_interrupt code sort out the actual time. + */ + paca->xLpPaca.xIntDword.xFields.xDecrInt = 1; + process_iSeries_events(); +} +#endif /* CONFIG_PPC_ISERIES */ + +int idled(void) +{ + struct Paca *paca; + long oldval; +#ifdef CONFIG_PPC_ISERIES + unsigned long CTRL; +#endif + + /* endless loop with no priority at all */ + current->nice = 20; + current->counter = -100; +#ifdef CONFIG_PPC_ISERIES + /* ensure iSeries run light will be out when idle */ + current->thread.flags &= ~PPC_FLAG_RUN_LIGHT; + CTRL = mfspr(CTRLF); + CTRL &= ~RUNLATCH; + mtspr(CTRLT, CTRL); +#endif + init_idle(); + + paca = (struct Paca *)mfspr(SPRG3); + + for (;;) { +#ifdef CONFIG_PPC_ISERIES + if ( paca->xLpPaca.xSharedProc ) { + if ( ItLpQueue_isLpIntPending( paca->lpQueuePtr ) ) + process_iSeries_events(); + if ( !current->need_resched ) + yield_shared_processor(); + } + else +#endif + { + /* Avoid an IPI by setting need_resched */ + oldval = xchg(¤t->need_resched, -1); + if (!oldval) { + while(current->need_resched == -1) { +#ifdef CONFIG_PPC_ISERIES + HMT_medium(); + if ( ItLpQueue_isLpIntPending( paca->lpQueuePtr ) ) + process_iSeries_events(); +#endif + HMT_low(); + } + } + } + HMT_medium(); + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + } + return 0; +} + +/* + * SMP entry into the idle task - calls the same thing as the + * non-smp versions. -- Cort + */ +int cpu_idle(void) +{ + idled(); + return 0; +} diff -urN linux-2.4.18/arch/ppc64/kernel/ioctl32.c linux-2.4.19-pre5/arch/ppc64/kernel/ioctl32.c --- linux-2.4.18/arch/ppc64/kernel/ioctl32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ioctl32.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,4498 @@ +/* + * ioctl32.c: Conversion between 32bit and 64bit native ioctls. + * + * Based on sparc64 ioctl32.c by: + * + * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * + * ppc64 changes: + * + * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com) + * Copyright (C) 2001 Anton Blanchard (antonb@au.ibm.com) + * + * These routines maintain argument size conversion between 32bit and 64bit + * ioctls. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +#include +#endif /* LVM */ + +#include +/* Ugly hack. */ +#undef __KERNEL__ +#include +#define __KERNEL__ +#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 + +/* Use this to get at 32-bit user passed pointers. + See sys_sparc32.c for description about these. */ +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) \ +({ unsigned long __ret; \ + __asm__ ("clrldi %0, %0, 32" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) + +/* Aiee. Someone does not find a difference between int and long */ +#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) +#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) +#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) +#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) + +extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + int err; + unsigned long val; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)arg)) + return -EFAULT; + return err; +} + +static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + int err; + unsigned long val; + + if (get_user(val, (u32 *)arg)) + return -EFAULT; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)arg)) + return -EFAULT; + return err; +} + +static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; + case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; + case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; + case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; + } + return sys_ioctl(fd, cmd, arg); +} + +struct video_tuner32 { + s32 tuner; + u8 name[32]; + u32 rangelow, rangehigh; + u32 flags; + u16 mode, signal; +}; + +static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if (get_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __get_user(kp->name[i], &up->name[i]); + __get_user(kp->rangelow, &up->rangelow); + __get_user(kp->rangehigh, &up->rangehigh); + __get_user(kp->flags, &up->flags); + __get_user(kp->mode, &up->mode); + __get_user(kp->signal, &up->signal); + return 0; +} + +static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if (put_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __put_user(kp->name[i], &up->name[i]); + __put_user(kp->rangelow, &up->rangelow); + __put_user(kp->rangehigh, &up->rangehigh); + __put_user(kp->flags, &up->flags); + __put_user(kp->mode, &up->mode); + __put_user(kp->signal, &up->signal); + return 0; +} + +struct video_buffer32 { + /* void * */ u32 base; + s32 height, width, depth, bytesperline; +}; + +static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp; + + if (get_user(tmp, &up->base)) + return -EFAULT; + kp->base = (void *) ((unsigned long)tmp); + __get_user(kp->height, &up->height); + __get_user(kp->width, &up->width); + __get_user(kp->depth, &up->depth); + __get_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp = (u32)((unsigned long)kp->base); + + if (put_user(tmp, &up->base)) + return -EFAULT; + __put_user(kp->height, &up->height); + __put_user(kp->width, &up->width); + __put_user(kp->depth, &up->depth); + __put_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +struct video_clip32 { + s32 x, y, width, height; + /* struct video_clip32 * */ u32 next; +}; + +struct video_window32 { + u32 x, y, width, height, chromakey, flags; + /* struct video_clip32 * */ u32 clips; + s32 clipcount; +}; + +static void free_kvideo_clips(struct video_window *kp) +{ + struct video_clip *cp; + + cp = kp->clips; + if (cp != NULL) + kfree(cp); +} + +static int get_video_window32(struct video_window *kp, struct video_window32 *up) +{ + struct video_clip32 *ucp; + struct video_clip *kcp; + int nclips, err, i; + u32 tmp; + + if (get_user(kp->x, &up->x)) + return -EFAULT; + __get_user(kp->y, &up->y); + __get_user(kp->width, &up->width); + __get_user(kp->height, &up->height); + __get_user(kp->chromakey, &up->chromakey); + __get_user(kp->flags, &up->flags); + __get_user(kp->clipcount, &up->clipcount); + __get_user(tmp, &up->clips); + ucp = (struct video_clip32 *)A(tmp); + kp->clips = NULL; + + nclips = kp->clipcount; + if (nclips == 0) + return 0; + + if (ucp == 0) + return -EINVAL; + + /* Peculiar interface... */ + if (nclips < 0) + nclips = VIDEO_CLIPMAP_SIZE; + + kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); + err = -ENOMEM; + if (kcp == NULL) + goto cleanup_and_err; + + kp->clips = kcp; + for(i = 0; i < nclips; i++) { + __get_user(kcp[i].x, &ucp[i].x); + __get_user(kcp[i].y, &ucp[i].y); + __get_user(kcp[i].width, &ucp[i].width); + __get_user(kcp[i].height, &ucp[i].height); + kcp[nclips].next = NULL; + } + + return 0; + +cleanup_and_err: + free_kvideo_clips(kp); + return err; +} + +/* You get back everything except the clips... */ +static int put_video_window32(struct video_window *kp, struct video_window32 *up) +{ + if (put_user(kp->x, &up->x)) + return -EFAULT; + __put_user(kp->y, &up->y); + __put_user(kp->width, &up->width); + __put_user(kp->height, &up->height); + __put_user(kp->chromakey, &up->chromakey); + __put_user(kp->flags, &up->flags); + __put_user(kp->clipcount, &up->clipcount); + return 0; +} + +#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) +#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) +#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) +#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) +#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) +#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) +#define VIDIOCGFREQ32 _IOR('v',14, u32) +#define VIDIOCSFREQ32 _IOW('v',15, u32) + +static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + union { + struct video_tuner vt; + struct video_buffer vb; + struct video_window vw; + unsigned long vx; + } karg; + mm_segment_t old_fs = get_fs(); + void *up = (void *)arg; + int err = 0; + + /* First, convert the command. */ + switch(cmd) { + case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; + case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; + case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; + case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; + case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; + case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; + case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; + case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + }; + + switch(cmd) { + case VIDIOCSTUNER: + case VIDIOCGTUNER: + err = get_video_tuner32(&karg.vt, up); + break; + + case VIDIOCSWIN: + err = get_video_window32(&karg.vw, up); + break; + + case VIDIOCSFBUF: + err = get_video_buffer32(&karg.vb, up); + break; + + case VIDIOCSFREQ: + err = get_user(karg.vx, (u32 *)up); + break; + }; + if (err) + goto out; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&karg); + set_fs(old_fs); + + if (cmd == VIDIOCSWIN) + free_kvideo_clips(&karg.vw); + + if (err == 0) { + switch(cmd) { + case VIDIOCGTUNER: + err = put_video_tuner32(&karg.vt, up); + break; + + case VIDIOCGWIN: + err = put_video_window32(&karg.vw, up); + break; + + case VIDIOCGFBUF: + err = put_video_buffer32(&karg.vb, up); + break; + + case VIDIOCGFREQ: + err = put_user(((u32)karg.vx), (u32 *)up); + break; + }; + } +out: + return err; +} + +struct timeval32 { + int tv_sec; + int tv_usec; +}; + +static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct timeval32 *up = (struct timeval32 *)arg; + struct timeval ktv; + mm_segment_t old_fs = get_fs(); + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&ktv); + set_fs(old_fs); + if (!err) { + err = put_user(ktv.tv_sec, &up->tv_sec); + err |= __put_user(ktv.tv_usec, &up->tv_usec); + } + return err; +} + +struct ifmap32 { + u32 mem_start; + u32 mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + __kernel_caddr_t32 ifru_data; + } ifr_ifru; +}; + +struct ifconf32 { + int ifc_len; /* size of buffer */ + __kernel_caddr_t32 ifcbuf; +}; + +#ifdef CONFIG_NET +static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct net_device *dev; + struct ifreq32 ifr32; + int err; + + if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + + dev = dev_get_by_index(ifr32.ifr_ifindex); + if (!dev) + return -ENODEV; + + strcpy(ifr32.ifr_name, dev->name); + + err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); + return (err ? -EFAULT : 0); +} +#endif + +static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifconf32 ifc32; + struct ifconf ifc; + struct ifreq32 *ifr32; + struct ifreq *ifr; + mm_segment_t old_fs; + unsigned int i, j; + int err; + + if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32))) + return -EFAULT; + + if (ifc32.ifcbuf == 0) { + ifc32.ifc_len = 0; + ifc.ifc_len = 0; + ifc.ifc_buf = NULL; + } else { + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + sizeof (struct ifreq); + ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); + if (!ifc.ifc_buf) + return -ENOMEM; + } + ifr = ifc.ifc_req; + ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); + for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { + if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { + kfree (ifc.ifc_buf); + return -EFAULT; + } + } + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); + set_fs (old_fs); + if (!err) { + ifr = ifc.ifc_req; + ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); + for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; + i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { + if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { + err = -EFAULT; + break; + } + } + if (!err) { + if (ifc32.ifcbuf == 0) { + /* Translate from 64-bit structure multiple to + * a 32-bit one. + */ + i = ifc.ifc_len; + i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); + ifc32.ifc_len = i; + } else { + if (i <= ifc32.ifc_len) + ifc32.ifc_len = i; + else + ifc32.ifc_len = i - sizeof (struct ifreq32); + } + if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) + err = -EFAULT; + } + } + if (ifc.ifc_buf != NULL) + kfree (ifc.ifc_buf); + return err; +} + +static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data, ethcmd; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + + if (get_user(ethcmd, (u32 *)A(data))) { + err = -EFAULT; + goto out; + } + switch (ethcmd) { + case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break; + case ETHTOOL_GMSGLVL: + case ETHTOOL_SMSGLVL: + case ETHTOOL_GLINK: + case ETHTOOL_NWAY_RST: len = sizeof(struct ethtool_value); break; + case ETHTOOL_GREGS: { + struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data); + /* darned variable size arguments */ + if (get_user(len, (u32 *)®addr->len)) { + err = -EFAULT; + goto out; + } + len += sizeof(struct ethtool_regs); + break; + } + case ETHTOOL_GSET: + case ETHTOOL_SSET: len = sizeof(struct ethtool_cmd); break; + default: + err = -EOPNOTSUPP; + goto out; + } + + if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + u32 data; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + +static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + switch (cmd) { + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + len = IFNAMSIZ * sizeof(char); + break; + case SIOCBONDSLAVEINFOQUERY: + len = sizeof(struct ifslave); + break; + case SIOCBONDINFOQUERY: + len = sizeof(struct ifbond); + break; + default: + err = -EINVAL; + goto out; + }; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + +static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err; + + switch (cmd) { + case SIOCSIFMAP: + err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); + err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) + return -EFAULT; + break; + default: + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + break; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + switch (cmd) { + case SIOCGIFFLAGS: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFMEM: + case SIOCGIFHWADDR: + case SIOCGIFINDEX: + case SIOCGIFADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCGIFTXQLEN: + if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) + return -EFAULT; + break; + case SIOCGIFMAP: + err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); + err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) + err = -EFAULT; + break; + } + } + return err; +} + +struct rtentry32 { + u32 rt_pad1; + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + u32 rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + /* char * */ u32 rt_dev; /* forcing the device at add */ + u32 rt_mtu; /* per route MTU/Window */ + u32 rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ + +}; + +struct in6_rtmsg32 { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + u32 rtmsg_type; + u16 rtmsg_dst_len; + u16 rtmsg_src_len; + u32 rtmsg_metric; + u32 rtmsg_info; + u32 rtmsg_flags; + s32 rtmsg_ifindex; +}; + +extern struct socket *sockfd_lookup(int fd, int *err); + +static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int ret; + void *r = NULL; + struct in6_rtmsg r6; + struct rtentry r4; + char devname[16]; + u32 rtdev; + mm_segment_t old_fs = get_fs(); + + struct socket *mysock = sockfd_lookup(fd, &ret); + + if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ + ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), + 3 * sizeof(struct in6_addr)); + ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); + ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); + ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); + ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); + ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); + ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); + ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); + + r = (void *) &r6; + } else { /* ipv4 */ + ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); + ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); + ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); + ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); + ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); + ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); + ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); + if (rtdev) { + ret |= copy_from_user (devname, (char *)A(rtdev), 15); + r4.rt_dev = devname; devname[15] = 0; + } else + r4.rt_dev = 0; + + r = (void *) &r4; + } + + if (ret) + return -EFAULT; + + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, cmd, (long) r); + set_fs (old_fs); + + return ret; +} + +struct hd_geometry32 { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + u32 start; +}; + +static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct hd_geometry geo; + int err; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); + set_fs (old_fs); + if (!err) { + err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4); + err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)); + } + return err ? -EFAULT : 0; +} + + +static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + unsigned long kval; + unsigned int *uvp; + int error; + + set_fs(KERNEL_DS); + error = sys_ioctl(fd, cmd, (long)&kval); + set_fs(old_fs); + + if (error == 0) { + uvp = (unsigned int *)arg; + if (put_user(kval, uvp)) + error = -EFAULT; + } + return error; +} + +struct floppy_struct32 { + unsigned int size; + unsigned int sect; + unsigned int head; + unsigned int track; + unsigned int stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const __kernel_caddr_t32 name; +}; + +struct floppy_drive_params32 { + char cmos; + u32 max_dtr; + u32 hlt; + u32 hut; + u32 srt; + u32 spinup; + u32 spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + u32 timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + int checkfreq; + int native_format; +}; + +struct floppy_drive_struct32 { + signed char flags; + u32 spinup_date; + u32 select_date; + u32 first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + int generation; + int keep_data; + int fd_ref; + int fd_device; + int last_checked; + __kernel_caddr_t32 dmabuf; + int bufblocks; +}; + +struct floppy_fdc_state32 { + int spec1; + int spec2; + int dtr; + unsigned char version; + unsigned char dor; + u32 address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct floppy_write_errors32 { + unsigned int write_errors; + u32 first_error_sector; + int first_error_generation; + u32 last_error_sector; + int last_error_generation; + unsigned int badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) +#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) + +static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + void *karg = NULL; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + struct floppy_struct *f; + + f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct floppy_drive_params *f; + + f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors)); + err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); + err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + goto out; + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + + err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + break; + } + case FDGETDRVPRM32: + { + struct floppy_drive_params *f = karg; + + err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors)); + err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect)); + err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct floppy_drive_struct *f = karg; + + err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags); + err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date); + err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date); + err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date); + err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format); + err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track); + err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock); + err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack); + err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation); + err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data); + err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref); + err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device); + err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked); + err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf); + err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks); + break; + } + case FDGETFDCSTAT32: + { + struct floppy_fdc_state *f = karg; + + err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1); + err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2); + err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr); + err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version); + err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor); + err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address); + err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address + + sizeof(((struct floppy_fdc_state32 *)arg)->address), + (char *)&f->address + sizeof(f->address), sizeof(int)); + err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version); + err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track)); + break; + } + case FDWERRORGET32: + { + struct floppy_write_errors *f = karg; + + err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors); + err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector); + err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation); + err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector); + err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation); + err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness); + break; + } + default: + break; + } + if (err) + err = -EFAULT; + +out: if (karg) kfree(karg); + return err; +} + +struct ppp_option_data32 { + __kernel_caddr_t32 ptr; + __u32 length; + int transmit; +}; +#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) + +struct ppp_idle32 { + __kernel_time_t32 xmit_idle; + __kernel_time_t32 recv_idle; +}; +#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) + +static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct ppp_option_data32 data32; + struct ppp_option_data data; + struct ppp_idle32 idle32; + struct ppp_idle idle; + unsigned int kcmd; + void *karg; + int err = 0; + + switch (cmd) { + case PPPIOCGIDLE32: + kcmd = PPPIOCGIDLE; + karg = &idle; + break; + case PPPIOCSCOMPRESS32: + if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32))) + return -EFAULT; + data.ptr = kmalloc (data32.length, GFP_KERNEL); + if (!data.ptr) + return -ENOMEM; + if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) { + kfree(data.ptr); + return -EFAULT; + } + data.length = data32.length; + data.transmit = data32.transmit; + kcmd = PPPIOCSCOMPRESS; + karg = &data; + break; + default: + do { + static int count = 0; + if (++count <= 20) + printk("ppp_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while (0); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + switch (cmd) { + case PPPIOCGIDLE32: + if (err) + return err; + idle32.xmit_idle = idle.xmit_idle; + idle32.recv_idle = idle.recv_idle; + if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32))) + return -EFAULT; + break; + case PPPIOCSCOMPRESS32: + kfree(data.ptr); + break; + default: + break; + } + return err; +} + + +struct mtget32 { + __u32 mt_type; + __u32 mt_resid; + __u32 mt_dsreg; + __u32 mt_gstat; + __u32 mt_erreg; + __kernel_daddr_t32 mt_fileno; + __kernel_daddr_t32 mt_blkno; +}; +#define MTIOCGET32 _IOR('m', 2, struct mtget32) + +struct mtpos32 { + __u32 mt_blkno; +}; +#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) + +struct mtconfiginfo32 { + __u32 mt_type; + __u32 ifc_type; + __u16 irqnr; + __u16 dmanr; + __u16 port; + __u32 debug; + __u32 have_dens:1; + __u32 have_bsf:1; + __u32 have_fsr:1; + __u32 have_bsr:1; + __u32 have_eod:1; + __u32 have_seek:1; + __u32 have_tell:1; + __u32 have_ras1:1; + __u32 have_ras2:1; + __u32 have_ras3:1; + __u32 have_qfa:1; + __u32 pad1:5; + char reserved[10]; +}; +#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) +#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) + +static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct mtconfiginfo info; + struct mtget get; + struct mtpos pos; + unsigned long kcmd; + void *karg; + int err = 0; + + switch(cmd) { + case MTIOCPOS32: + kcmd = MTIOCPOS; + karg = &pos; + break; + case MTIOCGET32: + kcmd = MTIOCGET; + karg = &get; + break; + case MTIOCGETCONFIG32: + kcmd = MTIOCGETCONFIG; + karg = &info; + break; + case MTIOCSETCONFIG32: + kcmd = MTIOCSETCONFIG; + karg = &info; + err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_from_user((char *)&info.debug + sizeof(info.debug), + (char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32)); + if (err) + return -EFAULT; + break; + default: + do { + static int count = 0; + if (++count <= 20) + printk("mt_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while (0); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + return err; + switch (cmd) { + case MTIOCPOS32: + err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno); + break; + case MTIOCGET32: + err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); + err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid); + err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg); + err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat); + err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg); + err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno); + err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno); + break; + case MTIOCGETCONFIG32: + err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), + (char *)&info.debug + sizeof(info.debug), sizeof(__u32)); + break; + case MTIOCSETCONFIG32: + break; + } + return err ? -EFAULT: 0; +} + +struct cdrom_read_audio32 { + union cdrom_addr addr; + u_char addr_format; + int nframes; + __kernel_caddr_t32 buf; +}; + +struct cdrom_generic_command32 { + unsigned char cmd[CDROM_PACKET_SIZE]; + __kernel_caddr_t32 buffer; + unsigned int buflen; + int stat; + __kernel_caddr_t32 sense; + __kernel_caddr_t32 reserved[3]; +}; + +static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct cdrom_read_audio cdreadaudio; + struct cdrom_generic_command cgc; + __kernel_caddr_t32 addr; + char *data = 0; + void *karg; + int err = 0; + + switch(cmd) { + case CDROMREADAUDIO: + karg = &cdreadaudio; + err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr)); + err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format); + err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); + err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf); + if (err) + return -EFAULT; + data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL); + if (!data) + return -ENOMEM; + cdreadaudio.buf = data; + break; + case CDROM_SEND_PACKET: + karg = &cgc; + err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); + err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); + err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); + if (err) + return -EFAULT; + if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL) + return -ENOMEM; + cgc.buffer = data; + break; + default: + do { + static int count = 0; + if (++count <= 20) + printk("cdrom_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while (0); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + goto out; + switch (cmd) { + case CDROMREADAUDIO: + err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352); + break; + case CDROM_SEND_PACKET: + err = copy_to_user((char *)A(addr), data, cgc.buflen); + break; + default: + break; + } +out: if (data) + kfree(data); + return err ? -EFAULT : 0; +} + +struct loop_info32 { + int lo_number; /* ioctl r/o */ + __kernel_dev_t32 lo_device; /* ioctl r/o */ + unsigned int lo_inode; /* ioctl r/o */ + __kernel_dev_t32 lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned int lo_init[2]; + char reserved[4]; +}; + +static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct loop_info l; + int err = -EINVAL; + + switch(cmd) { + case LOOP_SET_STATUS: + err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, + 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) { + err = -EFAULT; + } else { + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + } + break; + case LOOP_GET_STATUS: + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + if (!err) { + err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, + (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) + err = -EFAULT; + } + break; + default: { + static int count = 0; + if (++count <= 20) + printk("%s: Unknown loop ioctl cmd, fd(%d) " + "cmd(%08x) arg(%08lx)\n", + __FUNCTION__, fd, cmd, arg); + } + } + return err; +} + +extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); + +#ifdef CONFIG_VT +static int vt_check(struct file *file) +{ + struct tty_struct *tty; + struct inode *inode = file->f_dentry->d_inode; + + if (file->f_op->ioctl != tty_ioctl) + return -EINVAL; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) + return -EINVAL; + + if (tty->driver.ioctl != vt_ioctl) + return -EINVAL; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + if (current->tty == tty || suser()) + return 1; + return 0; +} + +struct consolefontdesc32 { + unsigned short charcount; /* characters in font (256 or 512) */ + unsigned short charheight; /* scan lines per character (1-32) */ + u32 chardata; /* font data in expanded form */ +}; + +static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) +{ + struct consolefontdesc cfdarg; + struct console_font_op op; + int i, perm; + + perm = vt_check(file); + if (perm < 0) return perm; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) + return -EFAULT; + + cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata); + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + return con_font_op(fg_console, &op); + case GIO_FONTX: + if (!cfdarg.chardata) + return 0; + op.op = KD_FONT_OP_GET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + i = con_font_op(fg_console, &op); + if (i) + return i; + cfdarg.charheight = op.height; + cfdarg.charcount = op.charcount; + ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32))) + return -EFAULT; + return 0; + } + return -EINVAL; +} + +struct console_font_op32 { + unsigned int op; /* operation code KD_FONT_OP_* */ + unsigned int flags; /* KD_FONT_FLAG_* */ + unsigned int width, height; /* font size */ + unsigned int charcount; + u32 data; /* font data with height fixed to 32 */ +}; + +static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) +{ + struct console_font_op op; + int perm = vt_check(file), i; + struct vt_struct *vt; + + if (perm < 0) return perm; + + if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); + op.flags |= KD_FONT_FLAG_OLD; + vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; + i = con_font_op(vt->vc_num, &op); + if (i) return i; + ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; + if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) + return -EFAULT; + return 0; +} + +struct fb_fix_screeninfo32 { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned int smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + __u32 smem_len; /* Length of frame buffer mem */ + __u32 type; /* see FB_TYPE_* */ + __u32 type_aux; /* Interleave for interleaved Planes */ + __u32 visual; /* see FB_VISUAL_* */ + __u16 xpanstep; /* zero if no hardware panning */ + __u16 ypanstep; /* zero if no hardware panning */ + __u16 ywrapstep; /* zero if no hardware ywrap */ + __u32 line_length; /* length of a line in bytes */ + unsigned int mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + __u32 mmio_len; /* Length of Memory Mapped I/O */ + __u32 accel; /* Type of acceleration available */ + __u16 reserved[3]; /* Reserved for future compatibility */ +}; + +static int do_fbioget_fscreeninfo_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct fb_fix_screeninfo fix; + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (long)&fix); + set_fs(old_fs); + + if (err == 0) { + unsigned int smem_start = fix.smem_start; /* lose top 32 bits */ + unsigned int mmio_start = fix.mmio_start; /* lose top 32 bits */ + int i; + + err = put_user(fix.id[0], &((struct fb_fix_screeninfo32 *)arg)->id[0]); + for (i=1; i<16; i++) { + err |= __put_user(fix.id[i], &((struct fb_fix_screeninfo32 *)arg)->id[i]); + } + err |= __put_user(smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start); + err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len); + err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type); + err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux); + err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual); + err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep); + err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep); + err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep); + err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length); + err |= __put_user(mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start); + err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len); + err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel); + err |= __put_user(fix.reserved[0], &((struct fb_fix_screeninfo32 *)arg)->reserved[0]); + err |= __put_user(fix.reserved[1], &((struct fb_fix_screeninfo32 *)arg)->reserved[1]); + err |= __put_user(fix.reserved[2], &((struct fb_fix_screeninfo32 *)arg)->reserved[2]); + if (err) + err = -EFAULT; + } + return err; +} + +struct fb_cmap32 { + __u32 start; /* First entry */ + __u32 len; /* Number of entries */ + __u32 redptr; /* Red values */ + __u32 greenptr; + __u32 blueptr; + __u32 transpptr; /* transparency, can be NULL */ +}; + +static int do_fbiogetcmap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct fb_cmap cmap; + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (long)&cmap); + set_fs(old_fs); + + if (err == 0) { + __u32 redptr = (__u32)(__u64)cmap.red; + __u32 greenptr = (__u32)(__u64)cmap.green; + __u32 blueptr = (__u32)(__u64)cmap.blue; + __u32 transpptr = (__u32)(__u64)cmap.transp; + + err = put_user(cmap.start, &((struct fb_cmap32 *)arg)->start); + err |= __put_user(cmap.len, &((struct fb_cmap32 *)arg)->len); + err |= __put_user(redptr, &((struct fb_cmap32 *)arg)->redptr); + err |= __put_user(greenptr, &((struct fb_cmap32 *)arg)->greenptr); + err |= __put_user(blueptr, &((struct fb_cmap32 *)arg)->blueptr); + err |= __put_user(transpptr, &((struct fb_cmap32 *)arg)->transpptr); + if (err) + err = -EFAULT; + } + return err; +} + +static int do_fbioputcmap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct fb_cmap cmap; + __u32 redptr, greenptr, blueptr, transpptr; + int err; + + err = get_user(cmap.start, &((struct fb_cmap32 *)arg)->start); + err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len); + err |= __get_user(redptr, &((struct fb_cmap32 *)arg)->redptr); + err |= __get_user(greenptr, &((struct fb_cmap32 *)arg)->greenptr); + err |= __get_user(blueptr, &((struct fb_cmap32 *)arg)->blueptr); + err |= __get_user(transpptr, &((struct fb_cmap32 *)arg)->transpptr); + + if (err) { + err = -EFAULT; + } else { + cmap.red = (__u16 *)(__u64)redptr; + cmap.green = (__u16 *)(__u64)greenptr; + cmap.blue = (__u16 *)(__u64)blueptr; + cmap.transp = (__u16 *)(__u64)transpptr; + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&cmap); + set_fs (old_fs); + } + return err; +} + +struct unimapdesc32 { + unsigned short entry_ct; + u32 entries; +}; + +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) +{ + struct unimapdesc32 tmp; + int perm = vt_check(file); + + if (perm < 0) return perm; + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) return -EPERM; + return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); + case GIO_UNIMAP: + return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + } + return 0; +} +#endif /* CONFIG_VT */ +static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + __kernel_uid_t kuid; + int err; + + cmd = SMB_IOC_GETMOUNTUID; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&kuid); + set_fs(old_fs); + + if (err >= 0) + err = put_user(kuid, (__kernel_uid_t32 *)arg); + + 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) +#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) +#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) +#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, 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 }, + { ATM_GETLOOP32, ATM_GETLOOP }, + { ATM_SETLOOP32, ATM_SETLOOP }, + { ATM_QUERYLOOP32, ATM_QUERYLOOP } +}; + +#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, (void *)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((void *)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, (void *)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((void *)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 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); + } + + 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: + case ATM_GETLOOP: + case ATM_SETLOOP: + case ATM_QUERYLOOP: + return do_atmif_sioc(fd, cmd, arg); + } + + return -EINVAL; +} + +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */ +typedef struct { + uint8_t vg_name[NAME_LEN]; + uint32_t vg_number; + uint32_t vg_access; + uint32_t vg_status; + uint32_t lv_max; + uint32_t lv_cur; + uint32_t lv_open; + uint32_t pv_max; + uint32_t pv_cur; + uint32_t pv_act; + uint32_t dummy; + uint32_t vgda; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pvg_total; + u32 proc; + u32 pv[ABS_MAX_PV + 1]; + u32 lv[ABS_MAX_LV + 1]; + uint8_t vg_uuid[UUID_LEN+1]; /* volume group UUID */ + uint8_t dummy1[200]; +} vg32_t; + +typedef struct { + uint8_t id[2]; + uint16_t version; + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; + kdev_t pv_dev; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pe_stale; + u32 pe; + u32 inode; + uint8_t pv_uuid[UUID_LEN+1]; +} pv32_t; + +typedef struct { + char lv_name[NAME_LEN]; + u32 lv; +} lv_req32_t; + +typedef struct { + u32 lv_index; + u32 lv; + /* Transfer size because user space and kernel space differ */ + uint16_t size; +} lv_status_byindex_req32_t; + +typedef struct { + __kernel_dev_t32 dev; + u32 lv; +} lv_status_bydev_req32_t; + +typedef struct { + uint8_t lv_name[NAME_LEN]; + kdev_t old_dev; + kdev_t new_dev; + u32 old_pe; + u32 new_pe; +} le_remap_req32_t; + +typedef struct { + char pv_name[NAME_LEN]; + u32 pv; +} pv_status_req32_t; + +typedef struct { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; + kdev_t lv_dev; + uint32_t lv_number; + uint32_t lv_mirror_copies; + uint32_t lv_recovery; + uint32_t lv_schedule; + uint32_t lv_size; + u32 lv_current_pe; + uint32_t lv_current_le; + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; + uint32_t lv_allocation; + uint32_t lv_io_timeout; + uint32_t lv_read_ahead; + /* delta to version 1 starts here */ + u32 lv_snapshot_org; + u32 lv_snapshot_prev; + u32 lv_snapshot_next; + u32 lv_block_exception; + uint32_t lv_remap_ptr; + uint32_t lv_remap_end; + uint32_t lv_chunk_size; + uint32_t lv_snapshot_minor; + char dummy[200]; +} lv32_t; + +typedef struct { + u32 hash[2]; + u32 rsector_org; + kdev_t rdev_org; + u32 rsector_new; + kdev_t rdev_new; +} lv_block_exception32_t; + +static void put_lv_t(lv_t *l) +{ + if (l->lv_current_pe) vfree(l->lv_current_pe); + if (l->lv_block_exception) vfree(l->lv_block_exception); + kfree(l); +} + +static lv_t *get_lv_t(u32 p, int *errp) +{ + int err, i; + u32 ptr1, ptr2; + size_t size; + lv_block_exception32_t *lbe32; + lv_block_exception_t *lbe; + lv32_t *ul = (lv32_t *)A(p); + lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL); + + if (!l) { + *errp = -ENOMEM; + return NULL; + } + memset(l, 0, sizeof(lv_t)); + err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe); + err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le, + ((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le)); + err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr, + ((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr)); + err |= __get_user(ptr1, &ul->lv_current_pe); + err |= __get_user(ptr2, &ul->lv_block_exception); + if (err) { + kfree(l); + *errp = -EFAULT; + return NULL; + } + if (ptr1) { + size = l->lv_allocated_le * sizeof(pe_t); + l->lv_current_pe = vmalloc(size); + if (l->lv_current_pe) + err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size); + } + if (!err && ptr2) { + size = l->lv_remap_end * sizeof(lv_block_exception_t); + l->lv_block_exception = lbe = vmalloc(size); + if (l->lv_block_exception) { + lbe32 = (lv_block_exception32_t *)A(ptr2); + memset(lbe, 0, size); + for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { + err |= get_user(lbe->rsector_org, &lbe32->rsector_org); + err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); + err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); + err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); + + } + } + } + if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) { + if (!err) + *errp = -ENOMEM; + else + *errp = -EFAULT; + put_lv_t(l); + return NULL; + } + return l; +} + +static int copy_lv_t(u32 ptr, lv_t *l) +{ + int err; + lv32_t *ul = (lv32_t *)A(ptr); + u32 ptr1; + size_t size; + + err = get_user(ptr1, &ul->lv_current_pe); + if (err) + return -EFAULT; + err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe); + err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le, + ((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le)); + err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr, + ((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr)); + size = l->lv_allocated_le * sizeof(pe_t); + if (ptr1) + err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size); + return err ? -EFAULT : 0; +} + +static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + vg_t *v = NULL; + union { + lv_req_t lv_req; + le_remap_req_t le_remap; + lv_status_byindex_req_t lv_byindex; + lv_status_bydev_req_t lv_bydev; + pv_status_req_t pv_status; + } u; + pv_t p; + int err; + u32 ptr = 0; + int i; + mm_segment_t old_fs; + void *karg = &u; + + switch (cmd) { + case VG_STATUS: + v = kmalloc(sizeof(vg_t), GFP_KERNEL); + if (!v) return -ENOMEM; + karg = v; + break; + + case VG_CREATE_OLD: + case VG_CREATE: + v = kmalloc(sizeof(vg_t), GFP_KERNEL); + if (!v) return -ENOMEM; + if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) || + __get_user(v->proc, &((vg32_t *)arg)->proc)) { + kfree(v); + return -EFAULT; + } + /* 'proc' field is unused, just NULL it out. */ + v->proc = NULL; + if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) { + kfree(v); + return -EFAULT; + } + + karg = v; + memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv)); + if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV) + return -EPERM; + for (i = 0; i < v->pv_max; i++) { + err = __get_user(ptr, &((vg32_t *)arg)->pv[i]); + if (err) break; + if (ptr) { + v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL); + if (!v->pv[i]) { + err = -ENOMEM; + break; + } + err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) { + err = -EFAULT; + break; + } + err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1); + if (err) { + err = -EFAULT; + break; + } + + + v->pv[i]->pe = NULL; v->pv[i]->inode = NULL; + } + } + if (!err) { + for (i = 0; i < v->lv_max; i++) { + err = __get_user(ptr, &((vg32_t *)arg)->lv[i]); + if (err) break; + if (ptr) { + v->lv[i] = get_lv_t(ptr, &err); + if (err) break; + } + } + } + break; + case LV_CREATE: + case LV_EXTEND: + case LV_REDUCE: + case LV_REMOVE: + case LV_RENAME: + case LV_STATUS_BYNAME: + err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); + if (err) return -EFAULT; + if (cmd != LV_REMOVE) { + err = __get_user(ptr, &((lv_req32_t *)arg)->lv); + if (err) return err; + u.lv_req.lv = get_lv_t(ptr, &err); + } else + u.lv_req.lv = NULL; + break; + + + case LV_STATUS_BYINDEX: + err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index); + err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv); + if (err) return err; + u.lv_byindex.lv = get_lv_t(ptr, &err); + break; + case LV_STATUS_BYDEV: + err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev); + u.lv_bydev.lv = get_lv_t(ptr, &err); + if (err) return err; + u.lv_bydev.lv = &p; + p.pe = NULL; p.inode = NULL; + break; + case VG_EXTEND: + err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) return -EFAULT; + err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1); + if (err) return -EFAULT; + p.pe = NULL; p.inode = NULL; + karg = &p; + break; + case PV_CHANGE: + case PV_STATUS: + err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name)); + if (err) return -EFAULT; + err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv); + if (err) return err; + u.pv_status.pv = &p; + if (cmd == PV_CHANGE) { + err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) return -EFAULT; + p.pe = NULL; p.inode = NULL; + } + break; + } + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)karg); + set_fs (old_fs); + switch (cmd) { + case VG_STATUS: + if (!err) { + if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) || + clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc)) + err = -EFAULT; + } + if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) { + err = -EFAULT; + } + kfree(v); + break; + + case VG_CREATE_OLD: + case VG_CREATE: + for (i = 0; i < v->pv_max; i++) { + if (v->pv[i]) + kfree(v->pv[i]); + } + for (i = 0; i < v->lv_max; i++) { + if (v->lv[i]) + put_lv_t(v->lv[i]); + } + kfree(v); + break; + case LV_STATUS_BYNAME: + if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv); + /* Fall through */ + case LV_CREATE: + case LV_EXTEND: + case LV_REDUCE: + if (u.lv_req.lv) put_lv_t(u.lv_req.lv); + break; + case LV_STATUS_BYINDEX: + if (u.lv_byindex.lv) { + if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv); + put_lv_t(u.lv_byindex.lv); + } + break; + + case LV_STATUS_BYDEV: + if (u.lv_bydev.lv) { + if (!err) + err = copy_lv_t(ptr, u.lv_bydev.lv); + put_lv_t(u.lv_byindex.lv); + } + break; + + case PV_STATUS: + if (!err) { + err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) return -EFAULT; + err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1); + if (err) return -EFAULT; + } + break; + }; + + return err; +} +#endif + +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +/* This really belongs in include/linux/drm.h -DaveM */ +#include "../../../drivers/char/drm/drm.h" + +typedef struct drm32_version { + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel;/* Patch level */ + int name_len; /* Length of name buffer */ + u32 name; /* Name of driver */ + int date_len; /* Length of date buffer */ + u32 date; /* User-space buffer to hold date */ + int desc_len; /* Length of desc buffer */ + u32 desc; /* User-space buffer to hold desc */ +} drm32_version_t; +#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t) + +static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_version_t *uversion = (drm32_version_t *)arg; + char *name_ptr, *date_ptr, *desc_ptr; + u32 tmp1, tmp2, tmp3; + drm_version_t kversion; + mm_segment_t old_fs; + int ret; + + memset(&kversion, 0, sizeof(kversion)); + if (get_user(kversion.name_len, &uversion->name_len) || + get_user(kversion.date_len, &uversion->date_len) || + get_user(kversion.desc_len, &uversion->desc_len) || + get_user(tmp1, &uversion->name) || + get_user(tmp2, &uversion->date) || + get_user(tmp3, &uversion->desc)) + return -EFAULT; + + name_ptr = (char *) A(tmp1); + date_ptr = (char *) A(tmp2); + desc_ptr = (char *) A(tmp3); + + ret = -ENOMEM; + if (kversion.name_len && name_ptr) { + kversion.name = kmalloc(kversion.name_len, GFP_KERNEL); + if (!kversion.name) + goto out; + } + if (kversion.date_len && date_ptr) { + kversion.date = kmalloc(kversion.date_len, GFP_KERNEL); + if (!kversion.date) + goto out; + } + if (kversion.desc_len && desc_ptr) { + kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL); + if (!kversion.desc) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion); + set_fs(old_fs); + + if (!ret) { + if ((kversion.name && + copy_to_user(name_ptr, kversion.name, kversion.name_len)) || + (kversion.date && + copy_to_user(date_ptr, kversion.date, kversion.date_len)) || + (kversion.desc && + copy_to_user(desc_ptr, kversion.desc, kversion.desc_len))) + ret = -EFAULT; + if (put_user(kversion.version_major, &uversion->version_major) || + put_user(kversion.version_minor, &uversion->version_minor) || + put_user(kversion.version_patchlevel, &uversion->version_patchlevel) || + put_user(kversion.name_len, &uversion->name_len) || + put_user(kversion.date_len, &uversion->date_len) || + put_user(kversion.desc_len, &uversion->desc_len)) + ret = -EFAULT; + } + +out: + if (kversion.name) + kfree(kversion.name); + if (kversion.date) + kfree(kversion.date); + if (kversion.desc) + kfree(kversion.desc); + return ret; +} + +typedef struct drm32_unique { + int unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ +} drm32_unique_t; +#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t) +#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t) + +static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_unique_t *uarg = (drm32_unique_t *)arg; + drm_unique_t karg; + mm_segment_t old_fs; + char *uptr; + u32 tmp; + int ret; + + if (get_user(karg.unique_len, &uarg->unique_len)) + return -EFAULT; + karg.unique = NULL; + + if (get_user(tmp, &uarg->unique)) + return -EFAULT; + + uptr = (char *) A(tmp); + + if (uptr) { + karg.unique = kmalloc(karg.unique_len, GFP_KERNEL); + if (!karg.unique) + return -ENOMEM; + if (cmd == DRM32_IOCTL_SET_UNIQUE && + copy_from_user(karg.unique, uptr, karg.unique_len)) { + kfree(karg.unique); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + if (cmd == DRM32_IOCTL_GET_UNIQUE) + ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg); + else + ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg); + set_fs(old_fs); + + if (!ret) { + if (cmd == DRM32_IOCTL_GET_UNIQUE && + uptr != NULL && + copy_to_user(uptr, karg.unique, karg.unique_len)) + ret = -EFAULT; + if (put_user(karg.unique_len, &uarg->unique_len)) + ret = -EFAULT; + } + + if (karg.unique != NULL) + kfree(karg.unique); + + return ret; +} + +typedef struct drm32_map { + u32 offset; /* Requested physical address (0 for SAREA)*/ + u32 size; /* Requested physical size (bytes) */ + drm_map_type_t type; /* Type of memory to map */ + drm_map_flags_t flags; /* Flags */ + u32 handle; /* User-space: "Handle" to pass to mmap */ + /* Kernel-space: kernel-virtual address */ + int mtrr; /* MTRR slot used */ + /* Private data */ +} drm32_map_t; +#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t) + +static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_map_t *uarg = (drm32_map_t *) arg; + drm_map_t karg; + mm_segment_t old_fs; + u32 tmp; + int ret; + + ret = get_user(karg.offset, &uarg->offset); + ret |= get_user(karg.size, &uarg->size); + ret |= get_user(karg.type, &uarg->type); + ret |= get_user(karg.flags, &uarg->flags); + ret |= get_user(tmp, &uarg->handle); + ret |= get_user(karg.mtrr, &uarg->mtrr); + if (ret) + return -EFAULT; + + karg.handle = (void *) A(tmp); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + ret = put_user(karg.offset, &uarg->offset); + ret |= put_user(karg.size, &uarg->size); + ret |= put_user(karg.type, &uarg->type); + ret |= put_user(karg.flags, &uarg->flags); + tmp = (u32) (long)karg.handle; + ret |= put_user(tmp, &uarg->handle); + ret |= put_user(karg.mtrr, &uarg->mtrr); + if (ret) + ret = -EFAULT; + } + + return ret; +} + +typedef struct drm32_buf_info { + int count; /* Entries in list */ + u32 list; /* (drm_buf_desc_t *) */ +} drm32_buf_info_t; +#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t) + +static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg; + drm_buf_desc_t *ulist; + drm_buf_info_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (drm_buf_desc_t *) A(tmp); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL); + if (!karg.list) + return -EFAULT; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (karg.count <= orig_count && + (copy_to_user(ulist, karg.list, + karg.count * sizeof(drm_buf_desc_t)))) + ret = -EFAULT; + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_free { + int count; + u32 list; /* (int *) */ +} drm32_buf_free_t; +#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t) + +static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg; + drm_buf_free_t karg; + mm_segment_t old_fs; + int *ulist; + int ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (int *) A(tmp); + + karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int)))) + goto out; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg); + set_fs(old_fs); + +out: + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_pub { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int used; /* Amount of buffer in use (for DMA) */ + u32 address; /* Address of buffer (void *) */ +} drm32_buf_pub_t; + +typedef struct drm32_buf_map { + int count; /* Length of buflist */ + u32 virtual; /* Mmaped area in user-virtual (void *) */ + u32 list; /* Buffer information (drm_buf_pub_t *) */ +} drm32_buf_map_t; +#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t) + +static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg; + drm32_buf_pub_t *ulist; + drm_buf_map_t karg; + mm_segment_t old_fs; + int orig_count, ret, i; + u32 tmp1, tmp2; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp1, &uarg->virtual) || + get_user(tmp2, &uarg->list)) + return -EFAULT; + + karg.virtual = (void *) A(tmp1); + ulist = (drm32_buf_pub_t *) A(tmp2); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + for (i = 0; i < karg.count; i++) { + if (get_user(karg.list[i].idx, &ulist[i].idx) || + get_user(karg.list[i].total, &ulist[i].total) || + get_user(karg.list[i].used, &ulist[i].used) || + get_user(tmp1, &ulist[i].address)) + goto out; + + karg.list[i].address = (void *) A(tmp1); + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + for (i = 0; i < orig_count; i++) { + tmp1 = (u32) (long) karg.list[i].address; + if (put_user(karg.list[i].idx, &ulist[i].idx) || + put_user(karg.list[i].total, &ulist[i].total) || + put_user(karg.list[i].used, &ulist[i].used) || + put_user(tmp1, &ulist[i].address)) { + ret = -EFAULT; + goto out; + } + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + +out: + kfree(karg.list); + return ret; +} + +typedef struct drm32_dma { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int context; /* Context handle */ + int send_count; /* Number of buffers to send */ + u32 send_indices; /* List of handles to buffers (int *) */ + u32 send_sizes; /* Lengths of data to send (int *) */ + drm_dma_flags_t flags; /* Flags */ + int request_count; /* Number of buffers requested */ + int request_size; /* Desired size for buffers */ + u32 request_indices; /* Buffer information (int *) */ + u32 request_sizes; /* (int *) */ + int granted_count; /* Number of buffers granted */ +} drm32_dma_t; +#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t) + +/* RED PEN The DRM layer blindly dereferences the send/request + * indice/size arrays even though they are userland + * pointers. -DaveM + */ +static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_dma_t *uarg = (drm32_dma_t *) arg; + int *u_si, *u_ss, *u_ri, *u_rs; + drm_dma_t karg; + mm_segment_t old_fs; + int ret; + u32 tmp1, tmp2, tmp3, tmp4; + + karg.send_indices = karg.send_sizes = NULL; + karg.request_indices = karg.request_sizes = NULL; + + if (get_user(karg.context, &uarg->context) || + get_user(karg.send_count, &uarg->send_count) || + get_user(tmp1, &uarg->send_indices) || + get_user(tmp2, &uarg->send_sizes) || + get_user(karg.flags, &uarg->flags) || + get_user(karg.request_count, &uarg->request_count) || + get_user(karg.request_size, &uarg->request_size) || + get_user(tmp3, &uarg->request_indices) || + get_user(tmp4, &uarg->request_sizes) || + get_user(karg.granted_count, &uarg->granted_count)) + return -EFAULT; + + u_si = (int *) A(tmp1); + u_ss = (int *) A(tmp2); + u_ri = (int *) A(tmp3); + u_rs = (int *) A(tmp4); + + if (karg.send_count) { + karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.send_indices || !karg.send_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.send_indices, u_si, + (karg.send_count * sizeof(int))) || + copy_from_user(karg.send_sizes, u_ss, + (karg.send_count * sizeof(int)))) + goto out; + } + + if (karg.request_count) { + karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.request_indices || !karg.request_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.request_indices, u_ri, + (karg.request_count * sizeof(int))) || + copy_from_user(karg.request_sizes, u_rs, + (karg.request_count * sizeof(int)))) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (put_user(karg.context, &uarg->context) || + put_user(karg.send_count, &uarg->send_count) || + put_user(karg.flags, &uarg->flags) || + put_user(karg.request_count, &uarg->request_count) || + put_user(karg.request_size, &uarg->request_size) || + put_user(karg.granted_count, &uarg->granted_count)) + ret = -EFAULT; + + if (karg.send_count) { + if (copy_to_user(u_si, karg.send_indices, + (karg.send_count * sizeof(int))) || + copy_to_user(u_ss, karg.send_sizes, + (karg.send_count * sizeof(int)))) + ret = -EFAULT; + } + if (karg.request_count) { + if (copy_to_user(u_ri, karg.request_indices, + (karg.request_count * sizeof(int))) || + copy_to_user(u_rs, karg.request_sizes, + (karg.request_count * sizeof(int)))) + ret = -EFAULT; + } + } + +out: + if (karg.send_indices) + kfree(karg.send_indices); + if (karg.send_sizes) + kfree(karg.send_sizes); + if (karg.request_indices) + kfree(karg.request_indices); + if (karg.request_sizes) + kfree(karg.request_sizes); + + return ret; +} + +typedef struct drm32_ctx_res { + int count; + u32 contexts; /* (drm_ctx_t *) */ +} drm32_ctx_res_t; +#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t) + +static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg; + drm_ctx_t *ulist; + drm_ctx_res_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + karg.contexts = NULL; + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->contexts)) + return -EFAULT; + + ulist = (drm_ctx_t *) A(tmp); + + orig_count = karg.count; + if (karg.count && ulist) { + karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL); + if (!karg.contexts) + return -ENOMEM; + if (copy_from_user(karg.contexts, ulist, + (karg.count * sizeof(drm_ctx_t)))) { + kfree(karg.contexts); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (orig_count) { + if (copy_to_user(ulist, karg.contexts, + (orig_count * sizeof(drm_ctx_t)))) + ret = -EFAULT; + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + if (karg.contexts) + kfree(karg.contexts); + + return ret; +} + +#endif + +static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return -EINVAL; +} + +static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* The mkswap binary hard codes it to Intel value :-((( */ + return w_long(fd, BLKGETSIZE, arg); +} + +struct blkpg_ioctl_arg32 { + int op; + int flags; + int datalen; + u32 data; +}; + +static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int err; + mm_segment_t old_fs = get_fs(); + + err = get_user(a.op, &arg->op); + err |= __get_user(a.flags, &arg->flags); + err |= __get_user(a.datalen, &arg->datalen); + err |= __get_user((long)a.data, &arg->data); + if (err) return err; + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + if (a.datalen < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + a.data = &p; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&a); + set_fs (old_fs); + default: + return -EINVAL; + } + return err; +} + +static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); +} + +struct usbdevfs_ctrltransfer32 { + __u8 requesttype; + __u8 request; + __u16 value; + __u16 index; + __u16 length; + __u32 timeout; /* in milliseconds */ + __u32 data; +}; + +#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32) + +static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct usbdevfs_ctrltransfer kctrl; + struct usbdevfs_ctrltransfer32 *uctrl; + mm_segment_t old_fs; + __u32 udata; + void *uptr, *kptr; + int err; + + uctrl = (struct usbdevfs_ctrltransfer32 *) arg; + + if (copy_from_user(&kctrl, uctrl, + (sizeof(struct usbdevfs_ctrltransfer) - + sizeof(void *)))) + return -EFAULT; + + if (get_user(udata, &uctrl->data)) + return -EFAULT; + uptr = (void *) A(udata); + + /* In usbdevice_fs, it limits the control buffer to a page, + * for simplicity so do we. + */ + if (!uptr || kctrl.length > PAGE_SIZE) + return -EINVAL; + + kptr = (void *)__get_free_page(GFP_KERNEL); + + if ((kctrl.requesttype & 0x80) == 0) { + err = -EFAULT; + if (copy_from_user(kptr, uptr, kctrl.length)) + goto out; + } + + kctrl.data = kptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl); + set_fs(old_fs); + + if (err >= 0 && + ((kctrl.requesttype & 0x80) != 0)) { + if (copy_to_user(uptr, kptr, kctrl.length)) + err = -EFAULT; + } + +out: + free_page((unsigned long) kptr); + return err; +} + +struct usbdevfs_bulktransfer32 { + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + __u32 data; +}; + +#define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32) + +static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct usbdevfs_bulktransfer kbulk; + struct usbdevfs_bulktransfer32 *ubulk; + mm_segment_t old_fs; + __u32 udata; + void *uptr, *kptr; + int err; + + ubulk = (struct usbdevfs_bulktransfer32 *) arg; + + if (get_user(kbulk.ep, &ubulk->ep) || + get_user(kbulk.len, &ubulk->len) || + get_user(kbulk.timeout, &ubulk->timeout) || + get_user(udata, &ubulk->data)) + return -EFAULT; + + uptr = (void *) A(udata); + + /* In usbdevice_fs, it limits the control buffer to a page, + * for simplicity so do we. + */ + if (!uptr || kbulk.len > PAGE_SIZE) + return -EINVAL; + + kptr = (void *) __get_free_page(GFP_KERNEL); + + if ((kbulk.ep & 0x80) == 0) { + err = -EFAULT; + if (copy_from_user(kptr, uptr, kbulk.len)) + goto out; + } + + kbulk.data = kptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk); + set_fs(old_fs); + + if (err >= 0 && + ((kbulk.ep & 0x80) != 0)) { + if (copy_to_user(uptr, kptr, kbulk.len)) + err = -EFAULT; + } + +out: + free_page((unsigned long) kptr); + return err; +} + +/* This needs more work before we can enable it. Unfortunately + * because of the fancy asynchronous way URB status/error is written + * back to userspace, we'll need to fiddle with USB devio internals + * and/or reimplement entirely the frontend of it ourselves. -DaveM + * + * The issue is: + * + * When an URB is submitted via usbdevicefs it is put onto an + * asynchronous queue. When the URB completes, it may be reaped + * via another ioctl. During this reaping the status is written + * back to userspace along with the length of the transfer. + * + * We must translate into 64-bit kernel types so we pass in a kernel + * space copy of the usbdevfs_urb structure. This would mean that we + * must do something to deal with the async entry reaping. First we + * have to deal somehow with this transitory memory we've allocated. + * This is problematic since there are many call sites from which the + * async entries can be destroyed (and thus when we'd need to free up + * this kernel memory). One of which is the close() op of usbdevicefs. + * To handle that we'd need to make our own file_operations struct which + * overrides usbdevicefs's release op with our own which runs usbdevicefs's + * real release op then frees up the kernel memory. + * + * But how to keep track of these kernel buffers? We'd need to either + * keep track of them in some table _or_ know about usbdevicefs internals + * (ie. the exact layout of it's file private, which is actually defined + * in linux/usbdevice_fs.h, the layout of the async queues are private to + * devio.c) + * + * There is one possible other solution I considered, also involving knowledge + * of usbdevicefs internals: + * + * After an URB is submitted, we "fix up" the address back to the user + * space one. This would work if the status/length fields written back + * by the async URB completion lines up perfectly in the 32-bit type with + * the 64-bit kernel type. Unfortunately, it does not because the iso + * frame descriptors, at the end of the struct, can be written back. + * + * I think we'll just need to simply duplicate the devio URB engine here. + */ +#if 0 +struct usbdevfs_urb32 { + __u8 type; + __u8 endpoint; + __s32 status; + __u32 flags; + __u32 buffer; + __s32 buffer_length; + __s32 actual_length; + __s32 start_frame; + __s32 number_of_packets; + __s32 error_count; + __u32 signr; + __u32 usercontext; /* unused */ + struct usbdevfs_iso_packet_desc iso_frame_desc[0]; +}; + +#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) + +static int get_urb32(struct usbdevfs_urb *kurb, + struct usbdevfs_urb32 *uurb) +{ + if (get_user(kurb->type, &uurb->type) || + __get_user(kurb->endpoint, &uurb->endpoint) || + __get_user(kurb->status, &uurb->status) || + __get_user(kurb->flags, &uurb->flags) || + __get_user(kurb->buffer_length, &uurb->buffer_length) || + __get_user(kurb->actual_length, &uurb->actual_length) || + __get_user(kurb->start_frame, &uurb->start_frame) || + __get_user(kurb->number_of_packets, &uurb->number_of_packets) || + __get_user(kurb->error_count, &uurb->error_count) || + __get_user(kurb->signr, &uurb->signr)) + return -EFAULT; + + kurb->usercontext = 0; /* unused currently */ + + return 0; +} + +/* Just put back the values which usbdevfs actually changes. */ +static int put_urb32(struct usbdevfs_urb *kurb, + struct usbdevfs_urb32 *uurb) +{ + if (put_user(kurb->status, &uurb->status) || + __put_user(kurb->actual_length, &uurb->actual_length) || + __put_user(kurb->error_count, &uurb->error_count)) + return -EFAULT; + + if (kurb->number_of_packets != 0) { + int i; + + for (i = 0; i < kurb->number_of_packets; i++) { + if (__put_user(kurb->iso_frame_desc[i].actual_length, + &uurb->iso_frame_desc[i].actual_length) || + __put_user(kurb->iso_frame_desc[i].status, + &uurb->iso_frame_desc[i].status)) + return -EFAULT; + } + } + + return 0; +} + +static int get_urb32_isoframes(struct usbdevfs_urb *kurb, + struct usbdevfs_urb32 *uurb) +{ + unsigned int totlen; + int i; + + if (kurb->type != USBDEVFS_URB_TYPE_ISO) { + kurb->number_of_packets = 0; + return 0; + } + + if (kurb->number_of_packets < 1 || + kurb->number_of_packets > 128) + return -EINVAL; + + if (copy_from_user(&kurb->iso_frame_desc[0], + &uurb->iso_frame_desc[0], + sizeof(struct usbdevfs_iso_packet_desc) * + kurb->number_of_packets)) + return -EFAULT; + + totlen = 0; + for (i = 0; i < kurb->number_of_packets; i++) { + unsigned int this_len; + + this_len = kurb->iso_frame_desc[i].length; + if (this_len > 1023) + return -EINVAL; + + totlen += this_len; + } + + if (totlen > 32768) + return -EINVAL; + + kurb->buffer_length = totlen; + + return 0; +} + +static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct usbdevfs_urb *kurb; + struct usbdevfs_urb32 *uurb; + mm_segment_t old_fs; + __u32 udata; + void *uptr, *kptr; + unsigned int buflen; + int err; + + uurb = (struct usbdevfs_urb32 *) arg; + + err = -ENOMEM; + kurb = kmalloc(sizeof(struct usbdevfs_urb) + + (sizeof(struct usbdevfs_iso_packet_desc) * 128), + GFP_KERNEL); + if (!kurb) + goto out; + + err = -EFAULT; + if (get_urb32(kurb, uurb)) + goto out; + + err = get_urb32_isoframes(kurb, uurb); + if (err) + goto out; + + err = -EFAULT; + if (__get_user(udata, &uurb->buffer)) + goto out; + uptr = (void *) A(udata); + + err = -ENOMEM; + buflen = kurb->buffer_length; + kptr = kmalloc(buflen, GFP_KERNEL); + if (!kptr) + goto out; + + kurb->buffer = kptr; + + err = -EFAULT; + if (copy_from_user(kptr, uptr, buflen)) + goto out_kptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb); + set_fs(old_fs); + + if (err >= 0) { + /* XXX Shit, this doesn't work for async URBs :-( XXX */ + if (put_urb32(kurb, uurb)) { + err = -EFAULT; + } else if ((kurb->endpoint & USB_DIR_IN) != 0) { + if (copy_to_user(uptr, kptr, buflen)) + err = -EFAULT; + } + } + +out_kptr: + kfree(kptr); + +out: + kfree(kurb); + return err; +} +#endif + +#define USBDEVFS_REAPURB32 _IOW('U', 12, u32) +#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32) + +static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs; + void *kptr; + int err; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, + (cmd == USBDEVFS_REAPURB32 ? + USBDEVFS_REAPURB : + USBDEVFS_REAPURBNDELAY), + (unsigned long) &kptr); + set_fs(old_fs); + + if (err >= 0 && + put_user(((u32)(long)kptr), (u32 *) A(arg))) + err = -EFAULT; + + return err; +} + +struct usbdevfs_disconnectsignal32 { + unsigned int signr; + u32 context; +}; + +#define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32) + +static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct usbdevfs_disconnectsignal kdis; + struct usbdevfs_disconnectsignal32 *udis; + mm_segment_t old_fs; + u32 uctx; + int err; + + udis = (struct usbdevfs_disconnectsignal32 *) arg; + + if (get_user(kdis.signr, &udis->signr) || + __get_user(uctx, &udis->context)) + return -EFAULT; + + kdis.context = (void *) (long)uctx; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis); + set_fs(old_fs); + + return err; +} + +struct mtd_oob_buf32 { + u32 start; + u32 length; + u32 ptr; /* unsigned char* */ +}; + +#define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) +#define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) + +static inline int +mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct mtd_oob_buf32 *uarg = (struct mtd_oob_buf32 *)arg; + struct mtd_oob_buf karg; + u32 tmp; + char *ptr; + int ret; + + if (get_user(karg.start, &uarg->start) || + get_user(karg.length, &uarg->length) || + get_user(tmp, &uarg->ptr)) + return -EFAULT; + + ptr = (char *)A(tmp); + if (0 >= karg.length) + return -EINVAL; + + karg.ptr = kmalloc(karg.length, GFP_KERNEL); + if (NULL == karg.ptr) + return -ENOMEM; + + if (copy_from_user(karg.ptr, ptr, karg.length)) { + kfree(karg.ptr); + return -EFAULT; + } + + set_fs(KERNEL_DS); + if (MEMREADOOB32 == cmd) + ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg); + else if (MEMWRITEOOB32 == cmd) + ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg); + else + ret = -EINVAL; + set_fs(old_fs); + + if (0 == ret && cmd == MEMREADOOB32) { + ret = copy_to_user(ptr, karg.ptr, karg.length); + ret |= put_user(karg.start, &uarg->start); + ret |= put_user(karg.length, &uarg->length); + } + + kfree(karg.ptr); + return ((0 == ret) ? 0 : -EFAULT); +} + +struct sg_io_hdr_32 +{ + int interface_id; + int dxfer_direction; + unsigned char cmd_len; + unsigned char mx_sb_len; + unsigned short iovec_count; + unsigned int dxfer_len; + u32 dxferp; + u32 cmdp; + u32 sbp; + unsigned int timeout; + unsigned int flags; + int pack_id; + u32 usr_ptr; + unsigned char status; + unsigned char masked_status; + unsigned char msg_status; + unsigned char sb_len_wr; + unsigned short host_status; + unsigned short driver_status; + int resid; + unsigned int duration; + unsigned int info; +}; + +static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL); + struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg; + u32 dxferp_32; + u32 cmdp_32; + u32 sbp_32; + u32 usr_ptr_32; + int ret = -EFAULT; + int err; + mm_segment_t old_fs = get_fs(); + + if (!sg) + return -ENOMEM; + + memset(sg, 0, sizeof(*sg)); + + err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp)); + err |= __get_user(dxferp_32, &sg_32->dxferp); + err |= __get_user(cmdp_32, &sg_32->cmdp); + err |= __get_user(sbp_32, &sg_32->sbp); + + if (err) + goto error; + + sg->dxferp = (void *)A(dxferp_32); + sg->cmdp = (void *)A(cmdp_32); + sg->sbp = (void *)A(sbp_32); + + err = __copy_from_user(&sg->timeout, &sg_32->timeout, + (long)&sg->usr_ptr - (long)&sg->timeout); + + err |= __get_user(usr_ptr_32, &sg_32->usr_ptr); + + if (err) + goto error; + + sg->usr_ptr = (void *)A(usr_ptr_32); + + err = __copy_from_user(&sg->status, &sg_32->status, + sizeof(struct sg_io_hdr) - + offsetof(struct sg_io_hdr, status)); + + if (err) + goto error; + + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, cmd, (unsigned long)sg); + set_fs(old_fs); + + err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp)); + + dxferp_32 = (unsigned long)sg->dxferp; + cmdp_32 = (unsigned long)sg->cmdp; + sbp_32 = (unsigned long)sg->sbp; + err |= __put_user(dxferp_32, &sg_32->dxferp); + err |= __put_user(cmdp_32, &sg_32->cmdp); + err |= __put_user(sbp_32, &sg_32->sbp); + + if (err) { + ret = -EFAULT; + goto error; + } + + err = __copy_to_user(&sg_32->timeout, &sg->timeout, + (long)&sg->usr_ptr - (long)&sg->timeout); + + usr_ptr_32 = (unsigned long)sg->usr_ptr; + err |= __put_user(usr_ptr_32, &sg_32->usr_ptr); + + if (err) { + ret = -EFAULT; + goto error; + } + + err = __copy_to_user(&sg_32->status, &sg->status, + sizeof(struct sg_io_hdr) - + offsetof(struct sg_io_hdr, status)); + + if (err) + ret = -EFAULT; + +error: + kfree(sg); + return ret; +} + +struct ioctl_trans { + unsigned long cmd; + unsigned long handler; + unsigned long next; +}; + +#define COMPATIBLE_IOCTL(cmd) { cmd, (unsigned long)sys_ioctl, 0 } + +#define HANDLE_IOCTL(cmd,handler) { cmd, (unsigned long)handler, 0 } + +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) +#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32) + +static struct ioctl_trans ioctl_translations[] = { + /* List here explicitly which ioctl's need translation, + * all others default to calling sys_ioctl(). + */ +/* Big T */ +COMPATIBLE_IOCTL(TCGETA), +COMPATIBLE_IOCTL(TCSETA), +COMPATIBLE_IOCTL(TCSETAW), +COMPATIBLE_IOCTL(TCSETAF), +COMPATIBLE_IOCTL(TCSBRK), +COMPATIBLE_IOCTL(TCXONC), +COMPATIBLE_IOCTL(TCFLSH), +COMPATIBLE_IOCTL(TCGETS), +COMPATIBLE_IOCTL(TCSETS), +COMPATIBLE_IOCTL(TCSETSW), +COMPATIBLE_IOCTL(TCSETSF), +COMPATIBLE_IOCTL(TIOCLINUX), +COMPATIBLE_IOCTL(TIOCSTART), +/* Little t */ +COMPATIBLE_IOCTL(TIOCGETD), +COMPATIBLE_IOCTL(TIOCSETD), +COMPATIBLE_IOCTL(TIOCEXCL), +COMPATIBLE_IOCTL(TIOCNXCL), +COMPATIBLE_IOCTL(TIOCCONS), +COMPATIBLE_IOCTL(TIOCGSOFTCAR), +COMPATIBLE_IOCTL(TIOCSSOFTCAR), +COMPATIBLE_IOCTL(TIOCSWINSZ), +COMPATIBLE_IOCTL(TIOCGWINSZ), +COMPATIBLE_IOCTL(TIOCMGET), +COMPATIBLE_IOCTL(TIOCMBIC), +COMPATIBLE_IOCTL(TIOCMBIS), +COMPATIBLE_IOCTL(TIOCMSET), +COMPATIBLE_IOCTL(TIOCPKT), +COMPATIBLE_IOCTL(TIOCNOTTY), +COMPATIBLE_IOCTL(TIOCSTI), +COMPATIBLE_IOCTL(TIOCOUTQ), +COMPATIBLE_IOCTL(TIOCSPGRP), +COMPATIBLE_IOCTL(TIOCGPGRP), +COMPATIBLE_IOCTL(TIOCSCTTY), +COMPATIBLE_IOCTL(TIOCGPTN), +COMPATIBLE_IOCTL(TIOCSPTLCK), +COMPATIBLE_IOCTL(TIOCGSERIAL), +COMPATIBLE_IOCTL(TIOCSSERIAL), +COMPATIBLE_IOCTL(TIOCSERGETLSR), +COMPATIBLE_IOCTL(TIOCSLTC), +/* Big F */ +COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO), +COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO), +COMPATIBLE_IOCTL(FBIOPAN_DISPLAY), +COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO), +COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO), +COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO), +COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE), +COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE), +COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP), +COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP), +#if 0 +COMPATIBLE_IOCTL(FBIOBLANK), +#endif +/* Little f */ +COMPATIBLE_IOCTL(FIOCLEX), +COMPATIBLE_IOCTL(FIONCLEX), +COMPATIBLE_IOCTL(FIOASYNC), +COMPATIBLE_IOCTL(FIONBIO), +COMPATIBLE_IOCTL(FIONREAD), /* This is also TIOCINQ */ +/* 0x00 */ +COMPATIBLE_IOCTL(FIBMAP), +COMPATIBLE_IOCTL(FIGETBSZ), +/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ +COMPATIBLE_IOCTL(HDIO_GET_IDENTITY), +COMPATIBLE_IOCTL(HDIO_SET_DMA), +COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS), +COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR), +COMPATIBLE_IOCTL(HDIO_SET_NOWERR), +COMPATIBLE_IOCTL(HDIO_SET_32BIT), +COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT), +COMPATIBLE_IOCTL(HDIO_DRIVE_CMD), +COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE), +COMPATIBLE_IOCTL(HDIO_SCAN_HWIF), +COMPATIBLE_IOCTL(HDIO_SET_NICE), +/* 0x02 -- Floppy ioctls */ +COMPATIBLE_IOCTL(FDMSGON), +COMPATIBLE_IOCTL(FDMSGOFF), +COMPATIBLE_IOCTL(FDSETEMSGTRESH), +COMPATIBLE_IOCTL(FDFLUSH), +COMPATIBLE_IOCTL(FDWERRORCLR), +COMPATIBLE_IOCTL(FDSETMAXERRS), +COMPATIBLE_IOCTL(FDGETMAXERRS), +COMPATIBLE_IOCTL(FDGETDRVTYP), +COMPATIBLE_IOCTL(FDEJECT), +COMPATIBLE_IOCTL(FDCLRPRM), +COMPATIBLE_IOCTL(FDFMTBEG), +COMPATIBLE_IOCTL(FDFMTEND), +COMPATIBLE_IOCTL(FDRESET), +COMPATIBLE_IOCTL(FDTWADDLE), +COMPATIBLE_IOCTL(FDFMTTRK), +COMPATIBLE_IOCTL(FDRAWCMD), +/* 0x12 */ +COMPATIBLE_IOCTL(BLKROSET), +COMPATIBLE_IOCTL(BLKROGET), +COMPATIBLE_IOCTL(BLKRRPART), +COMPATIBLE_IOCTL(BLKFLSBUF), +COMPATIBLE_IOCTL(BLKRASET), +COMPATIBLE_IOCTL(BLKFRASET), +COMPATIBLE_IOCTL(BLKSECTSET), +COMPATIBLE_IOCTL(BLKSSZGET), +COMPATIBLE_IOCTL(BLKBSZGET), +COMPATIBLE_IOCTL(BLKBSZSET), +COMPATIBLE_IOCTL(BLKGETSIZE64), + +/* RAID */ +COMPATIBLE_IOCTL(RAID_VERSION), +COMPATIBLE_IOCTL(GET_ARRAY_INFO), +COMPATIBLE_IOCTL(GET_DISK_INFO), +COMPATIBLE_IOCTL(PRINT_RAID_DEBUG), +COMPATIBLE_IOCTL(CLEAR_ARRAY), +COMPATIBLE_IOCTL(ADD_NEW_DISK), +COMPATIBLE_IOCTL(HOT_REMOVE_DISK), +COMPATIBLE_IOCTL(SET_ARRAY_INFO), +COMPATIBLE_IOCTL(SET_DISK_INFO), +COMPATIBLE_IOCTL(WRITE_RAID_INFO), +COMPATIBLE_IOCTL(UNPROTECT_ARRAY), +COMPATIBLE_IOCTL(PROTECT_ARRAY), +COMPATIBLE_IOCTL(HOT_ADD_DISK), +COMPATIBLE_IOCTL(SET_DISK_FAULTY), +COMPATIBLE_IOCTL(RUN_ARRAY), +COMPATIBLE_IOCTL(START_ARRAY), +COMPATIBLE_IOCTL(STOP_ARRAY), +COMPATIBLE_IOCTL(STOP_ARRAY_RO), +COMPATIBLE_IOCTL(RESTART_ARRAY_RW), +/* Big K */ +COMPATIBLE_IOCTL(PIO_FONT), +COMPATIBLE_IOCTL(GIO_FONT), +COMPATIBLE_IOCTL(KDSIGACCEPT), +COMPATIBLE_IOCTL(KDGETKEYCODE), +COMPATIBLE_IOCTL(KDSETKEYCODE), +COMPATIBLE_IOCTL(KIOCSOUND), +COMPATIBLE_IOCTL(KDMKTONE), +COMPATIBLE_IOCTL(KDGKBTYPE), +COMPATIBLE_IOCTL(KDSETMODE), +COMPATIBLE_IOCTL(KDGETMODE), +COMPATIBLE_IOCTL(KDSKBMODE), +COMPATIBLE_IOCTL(KDGKBMODE), +COMPATIBLE_IOCTL(KDSKBMETA), +COMPATIBLE_IOCTL(KDGKBMETA), +COMPATIBLE_IOCTL(KDGKBENT), +COMPATIBLE_IOCTL(KDSKBENT), +COMPATIBLE_IOCTL(KDGKBSENT), +COMPATIBLE_IOCTL(KDSKBSENT), +COMPATIBLE_IOCTL(KDGKBDIACR), +COMPATIBLE_IOCTL(KDKBDREP), +COMPATIBLE_IOCTL(KDSKBDIACR), +COMPATIBLE_IOCTL(KDGKBLED), +COMPATIBLE_IOCTL(KDSKBLED), +COMPATIBLE_IOCTL(KDGETLED), +COMPATIBLE_IOCTL(KDSETLED), +COMPATIBLE_IOCTL(GIO_SCRNMAP), +COMPATIBLE_IOCTL(PIO_SCRNMAP), +COMPATIBLE_IOCTL(GIO_UNISCRNMAP), +COMPATIBLE_IOCTL(PIO_UNISCRNMAP), +COMPATIBLE_IOCTL(PIO_FONTRESET), +COMPATIBLE_IOCTL(PIO_UNIMAPCLR), +/* Big S */ +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN), +COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST), +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI), +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK), +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK), +COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY), +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE), +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE), +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER), +COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND), +/* Big V */ +COMPATIBLE_IOCTL(VT_SETMODE), +COMPATIBLE_IOCTL(VT_GETMODE), +COMPATIBLE_IOCTL(VT_GETSTATE), +COMPATIBLE_IOCTL(VT_OPENQRY), +COMPATIBLE_IOCTL(VT_ACTIVATE), +COMPATIBLE_IOCTL(VT_WAITACTIVE), +COMPATIBLE_IOCTL(VT_RELDISP), +COMPATIBLE_IOCTL(VT_DISALLOCATE), +COMPATIBLE_IOCTL(VT_RESIZE), +COMPATIBLE_IOCTL(VT_RESIZEX), +COMPATIBLE_IOCTL(VT_LOCKSWITCH), +COMPATIBLE_IOCTL(VT_UNLOCKSWITCH), +/* Little v, the video4linux ioctls */ +COMPATIBLE_IOCTL(VIDIOCGCAP), +COMPATIBLE_IOCTL(VIDIOCGCHAN), +COMPATIBLE_IOCTL(VIDIOCSCHAN), +COMPATIBLE_IOCTL(VIDIOCGPICT), +COMPATIBLE_IOCTL(VIDIOCSPICT), +COMPATIBLE_IOCTL(VIDIOCCAPTURE), +COMPATIBLE_IOCTL(VIDIOCKEY), +COMPATIBLE_IOCTL(VIDIOCGAUDIO), +COMPATIBLE_IOCTL(VIDIOCSAUDIO), +COMPATIBLE_IOCTL(VIDIOCSYNC), +COMPATIBLE_IOCTL(VIDIOCMCAPTURE), +COMPATIBLE_IOCTL(VIDIOCGMBUF), +COMPATIBLE_IOCTL(VIDIOCGUNIT), +COMPATIBLE_IOCTL(VIDIOCGCAPTURE), +COMPATIBLE_IOCTL(VIDIOCSCAPTURE), +/* BTTV specific... */ +COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256])), +COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256])), +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)), +COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])), /* struct bttv_pll_info */ +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)), +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)), +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)), +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)), +/* Little p (/dev/rtc, /dev/envctrl, etc.) */ +COMPATIBLE_IOCTL(_IOR('p', 20, int[7])), /* RTCGET */ +COMPATIBLE_IOCTL(_IOW('p', 21, int[7])), /* RTCSET */ +COMPATIBLE_IOCTL(RTC_AIE_ON), +COMPATIBLE_IOCTL(RTC_AIE_OFF), +COMPATIBLE_IOCTL(RTC_UIE_ON), +COMPATIBLE_IOCTL(RTC_UIE_OFF), +COMPATIBLE_IOCTL(RTC_PIE_ON), +COMPATIBLE_IOCTL(RTC_PIE_OFF), +COMPATIBLE_IOCTL(RTC_WIE_ON), +COMPATIBLE_IOCTL(RTC_WIE_OFF), +COMPATIBLE_IOCTL(RTC_ALM_SET), +COMPATIBLE_IOCTL(RTC_ALM_READ), +COMPATIBLE_IOCTL(RTC_RD_TIME), +COMPATIBLE_IOCTL(RTC_SET_TIME), +COMPATIBLE_IOCTL(RTC_WKALM_SET), +COMPATIBLE_IOCTL(RTC_WKALM_RD), +/* Little m */ +COMPATIBLE_IOCTL(MTIOCTOP), +/* Socket level stuff */ +COMPATIBLE_IOCTL(FIOSETOWN), +COMPATIBLE_IOCTL(SIOCSPGRP), +COMPATIBLE_IOCTL(FIOGETOWN), +COMPATIBLE_IOCTL(SIOCGPGRP), +COMPATIBLE_IOCTL(SIOCATMARK), +COMPATIBLE_IOCTL(SIOCSIFLINK), +COMPATIBLE_IOCTL(SIOCSIFENCAP), +COMPATIBLE_IOCTL(SIOCGIFENCAP), +COMPATIBLE_IOCTL(SIOCSIFBR), +COMPATIBLE_IOCTL(SIOCGIFBR), +COMPATIBLE_IOCTL(SIOCSARP), +COMPATIBLE_IOCTL(SIOCGARP), +COMPATIBLE_IOCTL(SIOCDARP), +COMPATIBLE_IOCTL(SIOCSRARP), +COMPATIBLE_IOCTL(SIOCGRARP), +COMPATIBLE_IOCTL(SIOCDRARP), +COMPATIBLE_IOCTL(SIOCADDDLCI), +COMPATIBLE_IOCTL(SIOCDELDLCI), +/* SG stuff */ +COMPATIBLE_IOCTL(SG_SET_TIMEOUT), +COMPATIBLE_IOCTL(SG_GET_TIMEOUT), +COMPATIBLE_IOCTL(SG_EMULATED_HOST), +COMPATIBLE_IOCTL(SG_SET_TRANSFORM), +COMPATIBLE_IOCTL(SG_GET_TRANSFORM), +COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE), +COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE), +COMPATIBLE_IOCTL(SG_GET_SCSI_ID), +COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA), +COMPATIBLE_IOCTL(SG_GET_LOW_DMA), +COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID), +COMPATIBLE_IOCTL(SG_GET_PACK_ID), +COMPATIBLE_IOCTL(SG_GET_NUM_WAITING), +COMPATIBLE_IOCTL(SG_SET_DEBUG), +COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE), +COMPATIBLE_IOCTL(SG_GET_COMMAND_Q), +COMPATIBLE_IOCTL(SG_SET_COMMAND_Q), +COMPATIBLE_IOCTL(SG_GET_VERSION_NUM), +COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN), +COMPATIBLE_IOCTL(SG_SCSI_RESET), +COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE), +COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN), +COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN), +/* PPP stuff */ +COMPATIBLE_IOCTL(PPPIOCGFLAGS), +COMPATIBLE_IOCTL(PPPIOCSFLAGS), +COMPATIBLE_IOCTL(PPPIOCGASYNCMAP), +COMPATIBLE_IOCTL(PPPIOCSASYNCMAP), +COMPATIBLE_IOCTL(PPPIOCGUNIT), +COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP), +COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP), +COMPATIBLE_IOCTL(PPPIOCGMRU), +COMPATIBLE_IOCTL(PPPIOCSMRU), +COMPATIBLE_IOCTL(PPPIOCSMAXCID), +COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP), +COMPATIBLE_IOCTL(LPGETSTATUS), +COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP), +COMPATIBLE_IOCTL(PPPIOCXFERUNIT), +COMPATIBLE_IOCTL(PPPIOCGNPMODE), +COMPATIBLE_IOCTL(PPPIOCSNPMODE), +COMPATIBLE_IOCTL(PPPIOCGDEBUG), +COMPATIBLE_IOCTL(PPPIOCSDEBUG), +COMPATIBLE_IOCTL(PPPIOCNEWUNIT), +COMPATIBLE_IOCTL(PPPIOCATTACH), +COMPATIBLE_IOCTL(PPPIOCDETACH), +COMPATIBLE_IOCTL(PPPIOCSMRRU), +COMPATIBLE_IOCTL(PPPIOCCONNECT), +COMPATIBLE_IOCTL(PPPIOCDISCONN), +COMPATIBLE_IOCTL(PPPIOCATTCHAN), +COMPATIBLE_IOCTL(PPPIOCGCHAN), +/* PPPOX */ +COMPATIBLE_IOCTL(PPPOEIOCSFWD), +COMPATIBLE_IOCTL(PPPOEIOCDFWD), +/* CDROM stuff */ +COMPATIBLE_IOCTL(CDROMPAUSE), +COMPATIBLE_IOCTL(CDROMRESUME), +COMPATIBLE_IOCTL(CDROMPLAYMSF), +COMPATIBLE_IOCTL(CDROMPLAYTRKIND), +COMPATIBLE_IOCTL(CDROMREADCOOKED), +COMPATIBLE_IOCTL(CDROMREADMODE1), +COMPATIBLE_IOCTL(CDROMREADMODE2), +COMPATIBLE_IOCTL(CDROMREADRAW), +COMPATIBLE_IOCTL(CDROMREADTOCHDR), +COMPATIBLE_IOCTL(CDROMREADTOCENTRY), +COMPATIBLE_IOCTL(CDROMSTOP), +COMPATIBLE_IOCTL(CDROMSTART), +COMPATIBLE_IOCTL(CDROMEJECT), +COMPATIBLE_IOCTL(CDROMVOLCTRL), +COMPATIBLE_IOCTL(CDROMSUBCHNL), +COMPATIBLE_IOCTL(CDROMEJECT_SW), +COMPATIBLE_IOCTL(CDROMMULTISESSION), +COMPATIBLE_IOCTL(CDROM_GET_MCN), +COMPATIBLE_IOCTL(CDROMRESET), +COMPATIBLE_IOCTL(CDROMVOLREAD), +COMPATIBLE_IOCTL(CDROMSEEK), +COMPATIBLE_IOCTL(CDROMPLAYBLK), +COMPATIBLE_IOCTL(CDROMCLOSETRAY), +COMPATIBLE_IOCTL(CDROM_SET_OPTIONS), +COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS), +COMPATIBLE_IOCTL(CDROM_SELECT_SPEED), +COMPATIBLE_IOCTL(CDROM_SELECT_DISC), +COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED), +COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS), +COMPATIBLE_IOCTL(CDROM_DISC_STATUS), +COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS), +COMPATIBLE_IOCTL(CDROM_LOCKDOOR), +COMPATIBLE_IOCTL(CDROM_DEBUG), +COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY), +/* DVD ioctls */ +COMPATIBLE_IOCTL(DVD_READ_STRUCT), +COMPATIBLE_IOCTL(DVD_WRITE_STRUCT), +COMPATIBLE_IOCTL(DVD_AUTH), +/* Big L */ +COMPATIBLE_IOCTL(LOOP_SET_FD), +COMPATIBLE_IOCTL(LOOP_CLR_FD), +/* Big Q for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET), +COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC), +COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO), +COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE), +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT), +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT), +COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE), +COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR), +COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI), +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES), +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS), +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS), +COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO), +COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD), +COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL), +COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE), +COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC), +COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND), +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME), +COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID), +COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL), +COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE), +/* Big T for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE), +COMPATIBLE_IOCTL(SNDCTL_TMR_START), +COMPATIBLE_IOCTL(SNDCTL_TMR_STOP), +COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE), +COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO), +COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE), +COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME), +COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT), +/* Little m for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME), +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE), +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD), +/* Big P for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_DSP_RESET), +COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC), +COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED), +COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE), +COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS), +COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER), +COMPATIBLE_IOCTL(SNDCTL_DSP_POST), +COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE), +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS), +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE), +COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER), +COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR), +/* SNDCTL_DSP_MAPINBUF, XXX needs translation */ +/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */ +COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO), +COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX), +COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY), +COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE), +COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE), +COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS), +COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS), +COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER), +/* Big C for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_COPR_RESET), +COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD), +COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA), +COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE), +COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA), +COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE), +COMPATIBLE_IOCTL(SNDCTL_COPR_RUN), +COMPATIBLE_IOCTL(SNDCTL_COPR_HALT), +COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG), +COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG), +/* Big M for sound/OSS */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO)), +COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR)), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE), +/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */ +/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS), +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO)), +COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR)), +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE), +/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */ +/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC), +COMPATIBLE_IOCTL(SOUND_MIXER_INFO), +COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO), +COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS), +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1), +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2), +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3), +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4), +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5), +COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS), +COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS), +COMPATIBLE_IOCTL(OSS_GETVERSION), +/* AUTOFS */ +COMPATIBLE_IOCTL(AUTOFS_IOC_READY), +COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL), +COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC), +COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER), +COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE), +/* DEVFS */ +COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV), +COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK), +COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE), +COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK), +/* Raw devices */ +COMPATIBLE_IOCTL(RAW_SETBIND), +COMPATIBLE_IOCTL(RAW_GETBIND), +/* SMB ioctls which do not need any translations */ +COMPATIBLE_IOCTL(SMB_IOC_NEWCONN), +/* Little a */ +COMPATIBLE_IOCTL(ATMSIGD_CTRL), +COMPATIBLE_IOCTL(ATMARPD_CTRL), +COMPATIBLE_IOCTL(ATMLEC_CTRL), +COMPATIBLE_IOCTL(ATMLEC_MCAST), +COMPATIBLE_IOCTL(ATMLEC_DATA), +COMPATIBLE_IOCTL(ATM_SETSC), +COMPATIBLE_IOCTL(SIOCSIFATMTCP), +COMPATIBLE_IOCTL(SIOCMKCLIP), +COMPATIBLE_IOCTL(ATMARP_MKIP), +COMPATIBLE_IOCTL(ATMARP_SETENTRY), +COMPATIBLE_IOCTL(ATMARP_ENCAP), +COMPATIBLE_IOCTL(ATMTCP_CREATE), +COMPATIBLE_IOCTL(ATMTCP_REMOVE), +COMPATIBLE_IOCTL(ATMMPC_CTRL), +COMPATIBLE_IOCTL(ATMMPC_DATA), +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +/* 0xfe - lvm */ +COMPATIBLE_IOCTL(VG_SET_EXTENDABLE), +COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT), +COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST), +COMPATIBLE_IOCTL(VG_REMOVE), +COMPATIBLE_IOCTL(VG_RENAME), +COMPATIBLE_IOCTL(VG_REDUCE), +COMPATIBLE_IOCTL(PE_LOCK_UNLOCK), +COMPATIBLE_IOCTL(PV_FLUSH), +COMPATIBLE_IOCTL(LVM_LOCK_LVM), +COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION), +#ifdef LVM_TOTAL_RESET +COMPATIBLE_IOCTL(LVM_RESET), +#endif +COMPATIBLE_IOCTL(LV_SET_ACCESS), +COMPATIBLE_IOCTL(LV_SET_STATUS), +COMPATIBLE_IOCTL(LV_SET_ALLOCATION), +COMPATIBLE_IOCTL(LE_REMAP), +COMPATIBLE_IOCTL(LV_BMAP), +COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE), +#endif /* LVM */ +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC), +COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID), +COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC), +COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK), +COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK), +COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL), +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS), +COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS), +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX), +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW), +COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW), +COMPATIBLE_IOCTL(DRM_IOCTL_LOCK), +COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK), +COMPATIBLE_IOCTL(DRM_IOCTL_FINISH), +#endif /* DRM */ +/* elevator */ +COMPATIBLE_IOCTL(BLKELVGET), +COMPATIBLE_IOCTL(BLKELVSET), +/* Big W */ +/* WIOC_GETSUPPORT not yet implemented -E */ +COMPATIBLE_IOCTL(WDIOC_GETSTATUS), +COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS), +COMPATIBLE_IOCTL(WDIOC_GETTEMP), +COMPATIBLE_IOCTL(WDIOC_SETOPTIONS), +COMPATIBLE_IOCTL(WDIOC_KEEPALIVE), +/* Bluetooth ioctls */ +COMPATIBLE_IOCTL(HCIDEVUP), +COMPATIBLE_IOCTL(HCIDEVDOWN), +COMPATIBLE_IOCTL(HCIDEVRESET), +COMPATIBLE_IOCTL(HCIRESETSTAT), +COMPATIBLE_IOCTL(HCIGETINFO), +COMPATIBLE_IOCTL(HCIGETDEVLIST), +COMPATIBLE_IOCTL(HCISETRAW), +COMPATIBLE_IOCTL(HCISETSCAN), +COMPATIBLE_IOCTL(HCISETAUTH), +COMPATIBLE_IOCTL(HCIINQUIRY), +COMPATIBLE_IOCTL(PCIIOC_CONTROLLER), +COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO), +COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM), +COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE), +/* USB */ +COMPATIBLE_IOCTL(USBDEVFS_RESETEP), +COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE), +COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION), +COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER), +COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB), +COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE), +COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE), +COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO), +COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO), +COMPATIBLE_IOCTL(USBDEVFS_RESET), +COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT), +/* MTD */ +COMPATIBLE_IOCTL(MEMGETINFO), +COMPATIBLE_IOCTL(MEMERASE), +COMPATIBLE_IOCTL(MEMLOCK), +COMPATIBLE_IOCTL(MEMUNLOCK), +COMPATIBLE_IOCTL(MEMGETREGIONCOUNT), +COMPATIBLE_IOCTL(MEMGETREGIONINFO), +/* NBD */ +COMPATIBLE_IOCTL(NBD_SET_SOCK), +COMPATIBLE_IOCTL(NBD_SET_BLKSIZE), +COMPATIBLE_IOCTL(NBD_SET_SIZE), +COMPATIBLE_IOCTL(NBD_DO_IT), +COMPATIBLE_IOCTL(NBD_CLEAR_SOCK), +COMPATIBLE_IOCTL(NBD_CLEAR_QUE), +COMPATIBLE_IOCTL(NBD_PRINT_DEBUG), +COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS), +COMPATIBLE_IOCTL(NBD_DISCONNECT), +/* Remove *PRIVATE in 2.5 */ +COMPATIBLE_IOCTL(SIOCDEVPRIVATE), +COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1), +COMPATIBLE_IOCTL(SIOCDEVPRIVATE+2), +COMPATIBLE_IOCTL(SIOCGMIIPHY), +COMPATIBLE_IOCTL(SIOCGMIIREG), +COMPATIBLE_IOCTL(SIOCSMIIREG), +/* And these ioctls need translation */ +HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob), +HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob), +#ifdef CONFIG_NET +HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32), +#endif +HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf), +HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc), +HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc), +HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc), +HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc), +HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl), +HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl), +HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl), +HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl), +HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl), +HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl), +HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl), +HANDLE_IOCTL(SIOCADDRT, routing_ioctl), +HANDLE_IOCTL(SIOCDELRT, routing_ioctl), +/* Note SIOCRTMSG is no longer, so this is safe and + * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(SIOCRTMSG, ret_einval), +HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp), +HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo), +HANDLE_IOCTL(BLKRAGET, w_long), +HANDLE_IOCTL(BLKGETSIZE, w_long), +HANDLE_IOCTL(0x1260, broken_blkgetsize), +HANDLE_IOCTL(BLKFRAGET, w_long), +HANDLE_IOCTL(BLKSECTGET, w_long), +HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans), +HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans), +HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans), +HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans), +HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans), +HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans), +HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans), +HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans), +HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans), +HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans), +HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans), +HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans), +HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans), +HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans), +HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans), +HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans), +HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans), +HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans), +HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans), +HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans), +HANDLE_IOCTL(LOOP_SET_STATUS, loop_status), +HANDLE_IOCTL(LOOP_GET_STATUS, loop_status), +HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout), +#ifdef CONFIG_VT +HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl), +HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl), +HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl), +HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl), +HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl), +HANDLE_IOCTL(FBIOGET_FSCREENINFO, do_fbioget_fscreeninfo_ioctl), +HANDLE_IOCTL(FBIOGETCMAP, do_fbiogetcmap_ioctl), +HANDLE_IOCTL(FBIOPUTCMAP, do_fbioputcmap_ioctl), +#endif +HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl), +HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl), +HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl), +HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl), +HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl), +HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl), +/* One SMB ioctl needs translations. */ +HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid), +HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl), +HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl), +HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl), +HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl), +HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl), +HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl), +HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl), +HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl), +HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl), +HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl), +HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl), +HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl), +HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl), +HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl), +HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl), +HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl), +HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl), +HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl), +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl), +HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl), +HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl), +HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl), +HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl), +HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl), +HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl), +HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl), +HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl), +HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl), +HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl), +HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl), +HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl), +HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl), +#endif /* LVM */ +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version), +HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique), +HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique), +HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap), +HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs), +HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs), +HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs), +HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma), +HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx), +#endif /* DRM */ +HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control), +HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk), +/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/ +HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb), +HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb), +HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal), +HANDLE_IOCTL(SG_IO, do_sg_io), +}; + +unsigned long ioctl32_hash_table[1024]; + +static inline unsigned long ioctl32_hash(unsigned long cmd) +{ + return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff; +} + +static void ioctl32_insert_translation(struct ioctl_trans *trans) +{ + unsigned long hash; + struct ioctl_trans *t; + + hash = ioctl32_hash (trans->cmd); + if (!ioctl32_hash_table[hash]) + ioctl32_hash_table[hash] = (long)trans; + else { + t = (struct ioctl_trans *)ioctl32_hash_table[hash]; + while (t->next) + t = (struct ioctl_trans *)(long)t->next; + trans->next = 0; + t->next = (long)trans; + } +} + +static int __init init_sys32_ioctl(void) +{ + int i, size = sizeof(ioctl_translations) / sizeof(struct ioctl_trans); + for (i=0; i < size ;i++) + ioctl32_insert_translation(&ioctl_translations[i]); + return 0; +} + +__initcall(init_sys32_ioctl); + +static struct ioctl_trans *additional_ioctls; + +/* Always call these with kernel lock held! */ + +int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)) +{ + int i; + if (!additional_ioctls) { + additional_ioctls = module_map(PAGE_SIZE); + if (!additional_ioctls) + return -ENOMEM; + memset(additional_ioctls, 0, PAGE_SIZE); + } + for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++) + if (!additional_ioctls[i].cmd) + break; + if (i == PAGE_SIZE/sizeof(struct ioctl_trans)) + return -ENOMEM; + additional_ioctls[i].cmd = cmd; + if (!handler) + additional_ioctls[i].handler = (long)sys_ioctl; + else + additional_ioctls[i].handler = (long)handler; + ioctl32_insert_translation(&additional_ioctls[i]); + return 0; +} + +int unregister_ioctl32_conversion(unsigned int cmd) +{ + unsigned long hash = ioctl32_hash(cmd); + struct ioctl_trans *t, *t1; + + t = (struct ioctl_trans *)ioctl32_hash_table[hash]; + if (!t) return -EINVAL; + if (t->cmd == cmd && t >= additional_ioctls && + (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + ioctl32_hash_table[hash] = t->next; + t->cmd = 0; + return 0; + } else while (t->next) { + t1 = (struct ioctl_trans *)t->next; + if (t1->cmd == cmd && t1 >= additional_ioctls && + (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + t1->cmd = 0; + t->next = t1->next; + return 0; + } + t = t1; + } + return -EINVAL; +} + +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int error = -EBADF; + int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); + struct ioctl_trans *t; + + filp = fget(fd); + if (!filp) + goto out2; + + if (!filp->f_op || !filp->f_op->ioctl) { + error = sys_ioctl (fd, cmd, arg); + goto out; + } + + t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)]; + + while (t && t->cmd != cmd) + t = (struct ioctl_trans *)t->next; + if (t) { + handler = (void *)t->handler; + error = handler(fd, cmd, arg, filp); + } else { + static int count = 0; + if (++count <= 20) + printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + current->comm, current->pid, + (int)fd, (unsigned int)cmd, (unsigned int)arg); + error = -EINVAL; + } +out: + fput(filp); +out2: + return error; +} diff -urN linux-2.4.18/arch/ppc64/kernel/irq.c linux-2.4.19-pre5/arch/ppc64/kernel/irq.c --- linux-2.4.18/arch/ppc64/kernel/irq.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/irq.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,972 @@ +/* + * + * + * arch/ppc/kernel/irq.c + * + * Derived from arch/i386/kernel/irq.c + * Copyright (C) 1992 Linus Torvalds + * Adapted from arch/i386 by Gary Thomas + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Updated and modified by Cort Dougan (cort@cs.nmt.edu) + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * 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 file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + + +#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 "local_irq.h" + +atomic_t ipi_recv; +atomic_t ipi_sent; +void enable_irq(unsigned int irq_nr); +void disable_irq(unsigned int irq_nr); + +#ifdef CONFIG_SMP +extern void iSeries_smp_message_recv( struct pt_regs * ); +#endif + +volatile unsigned char *chrp_int_ack_special; +static void register_irq_proc (unsigned int irq); + +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +int ppc_spurious_interrupts = 0; +struct irqaction *ppc_irq_action[NR_IRQS]; +unsigned long lpEvent_count = 0; +#ifdef CONFIG_XMON +extern void xmon(struct pt_regs *regs); +extern int xmon_bpt(struct pt_regs *regs); +extern int xmon_sstep(struct pt_regs *regs); +extern int xmon_iabr_match(struct pt_regs *regs); +extern int xmon_dabr_match(struct pt_regs *regs); +extern void (*xmon_fault_handler)(struct pt_regs *regs); +#endif +#ifdef CONFIG_XMON +extern void (*debugger)(struct pt_regs *regs); +extern int (*debugger_bpt)(struct pt_regs *regs); +extern int (*debugger_sstep)(struct pt_regs *regs); +extern int (*debugger_iabr_match)(struct pt_regs *regs); +extern int (*debugger_dabr_match)(struct pt_regs *regs); +extern void (*debugger_fault_handler)(struct pt_regs *regs); +#endif + +/* nasty hack for shared irq's since we need to do kmalloc calls but + * can't very early in the boot when we need to do a request irq. + * this needs to be removed. + * -- Cort + */ +#define IRQ_KMALLOC_ENTRIES 8 +static int cache_bitmask = 0; +static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES]; +extern int mem_init_done; + +void *irq_kmalloc(size_t size, int pri) +{ + unsigned int i; + if ( mem_init_done ) + return kmalloc(size,pri); + for ( i = 0; i < IRQ_KMALLOC_ENTRIES ; i++ ) + if ( ! ( cache_bitmask & (1<flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); + unmask_irq(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); + return 0; +} + +/* This could be promoted to a real free_irq() ... */ +static int +do_free_irq(int irq, void* dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + mask_irq(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + +#ifdef CONFIG_SMP + /* Wait to make sure it's not being used on another CPU */ + while (desc->status & IRQ_INPROGRESS) + barrier(); +#endif + irq_kfree(action); + return 0; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + break; + } + return -ENOENT; +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + struct irqaction *action; + int retval; + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + /* We could implement really free_irq() instead of that... */ + return do_free_irq(irq, dev_id); + + action = (struct irqaction *) + irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) { + printk(KERN_ERR "irq_kmalloc() failed for irq %d !\n", irq); + return -ENOMEM; + } + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = NULL; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + request_irq(irq, NULL, 0, NULL, dev_id); +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + + void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + if (!(desc->status & IRQ_PER_CPU)) + desc->status |= IRQ_DISABLED; + mask_irq(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count(smp_processor_id())) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + unmask_irq(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced\n", irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* one would think this function has one foot in the grave */ +int get_irq_list(char *buf) +{ + int i, len = 0, j; + struct irqaction * action; + + len += sprintf(buf+len, " "); + for (j=0; jhandler ) + continue; + len += sprintf(buf+len, "%3d: ", i); +#ifdef CONFIG_SMP + for (j = 0; j < smp_num_cpus; j++) + len += sprintf(buf+len, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); +#else + len += sprintf(buf+len, "%10u ", kstat_irqs(i)); +#endif /* CONFIG_SMP */ +if ( irq_desc[i].handler ) +len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); +else +len += sprintf(buf+len, " None "); +len += sprintf(buf+len, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge "); +len += sprintf(buf+len, " %s",action->name); +for (action=action->next; action; action = action->next) { +len += sprintf(buf+len, ", %s", action->name); +} +len += sprintf(buf+len, "\n"); +} +#ifdef CONFIG_SMP +/* should this be per processor send/receive? */ +len += sprintf(buf+len, "IPI (recv/sent): %10u/%u\n", +atomic_read(&ipi_recv), atomic_read(&ipi_sent)); +#endif +len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts); +return len; +} + + + +int show_interrupts(struct seq_file *p, void *v) +{ + int i, j; + struct irqaction * action; + + seq_printf(p, " "); + for (j=0; jhandler) + continue; + seq_printf(p, "%3d: ", i); +#ifdef CONFIG_SMP + for (j = 0; j < smp_num_cpus; j++) + seq_printf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); +#else + seq_printf(p, "%10u ", kstat_irqs(i)); +#endif /* CONFIG_SMP */ + if (irq_desc[i].handler) + seq_printf(p, " %s ", irq_desc[i].handler->typename ); + else + seq_printf(p, " None "); + seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge "); + seq_printf(p, " %s",action->name); + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); + } +#ifdef CONFIG_SMP + /* should this be per processor send/receive? */ + seq_printf(p, "IPI (recv/sent): %10u/%u\n", + atomic_read(&ipi_recv), atomic_read(&ipi_sent)); +#endif + seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); + return 0; +} + +static inline void +handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) +{ + int status = 0; + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); +} + +/* + * Eventually, this should take an array of interrupts and an array size + * so it can dispatch multiple interrupts. + */ +void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) +{ + int status; + struct irqaction *action; + int cpu = smp_processor_id(); + irq_desc_t *desc = irq_desc + irq; + + kstat.irqs[cpu][irq]++; + spin_lock(&desc->lock); + ack_irq(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + if (!(status & IRQ_PER_CPU)) + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + if (!action || !action->handler) { + ppc_spurious_interrupts++; + printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq); + /* We can't call disable_irq here, it would deadlock */ + if (!desc->depth) + desc->depth = 1; + desc->status |= IRQ_DISABLED; + /* This is not a real spurrious interrupt, we + * have to eoi it, so we jump to out + */ + mask_irq(irq); + goto out; + } + status &= ~IRQ_PENDING; /* we commit to handling */ + if (!(status & IRQ_PER_CPU)) + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + goto out; + + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_irq_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + if (irq_desc[irq].handler) { + if (irq_desc[irq].handler->end) + irq_desc[irq].handler->end(irq); + else if (irq_desc[irq].handler->enable) + irq_desc[irq].handler->enable(irq); + } + spin_unlock(&desc->lock); +} + +int do_IRQ(struct pt_regs *regs, int isfake) +{ + int cpu = smp_processor_id(); + int irq; + struct Paca * paca; + struct ItLpQueue * lpq; + + /* if(cpu) udbg_printf("Entering do_IRQ\n"); */ + + irq_enter(cpu); + + if ( _machine != _MACH_iSeries ) { + + /* every arch is required to have a get_irq -- Cort */ + irq = ppc_md.get_irq( regs ); + + if ( irq >= 0 ) { + ppc_irq_dispatch_handler( regs, irq ); + if (ppc_md.post_irq) + ppc_md.post_irq( regs, irq ); + } else { + /* -2 means ignore, already handled */ + if (irq != -2) { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + } + } + /* if on iSeries partition */ + else { + paca = (struct Paca *)mfspr(SPRG3); +#ifdef CONFIG_SMP + if ( paca->xLpPaca.xIntDword.xFields.xIpiCnt ) { + paca->xLpPaca.xIntDword.xFields.xIpiCnt = 0; + iSeries_smp_message_recv( regs ); + } +#endif /* CONFIG_SMP */ + lpq = paca->lpQueuePtr; + if ( lpq && ItLpQueue_isLpIntPending( lpq ) ) + lpEvent_count += ItLpQueue_process( lpq, regs ); + } + + irq_exit(cpu); + + if ( _machine == _MACH_iSeries ) { + if ( paca->xLpPaca.xIntDword.xFields.xDecrInt ) { + paca->xLpPaca.xIntDword.xFields.xDecrInt = 0; + /* Signal a fake decrementer interrupt */ + timer_interrupt( regs ); + } + } + + if (softirq_pending(cpu)) + do_softirq(); + + return 1; /* lets ret_from_int know we can do checks */ +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +unsigned int probe_irq_mask(unsigned long irqs) +{ + return 0; +} + +void __init init_IRQ(void) +{ + static int once = 0; + + if ( once ) + return; + else + once++; + + ppc_md.init_IRQ(); + if(ppc_md.init_ras_IRQ) ppc_md.init_ras_IRQ(); +} + +#ifdef CONFIG_SMP +unsigned char global_irq_holder = NO_PROC_ID; + +static void show(char * str) +{ + int cpu = smp_processor_id(); + int i; + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [ ", irqs_running()); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]); + printk("]\nbh: %d [ ", + (spin_is_locked(&global_bh_lock) ? 1 : 0)); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", local_bh_count(i)); + printk("]\n"); +} + +#define MAXCOUNT 10000000 + +void synchronize_irq(void) +{ + if (irqs_running()) { + cli(); + sti(); + } +} + +static inline void get_irqlock(int cpu) +{ + int count; + + if ((unsigned char)cpu == global_irq_holder) + return; + + count = MAXCOUNT; +again: + br_write_lock(BR_GLOBALIRQ_LOCK); + for (;;) { + spinlock_t *lock; + + if (!irqs_running() && + (local_bh_count(smp_processor_id()) || !spin_is_locked(&global_bh_lock))) + break; + + br_write_unlock(BR_GLOBALIRQ_LOCK); + lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock; + while (irqs_running() || + spin_is_locked(lock) || + (!local_bh_count(smp_processor_id()) && spin_is_locked(&global_bh_lock))) { + if (!--count) { + show("get_irqlock"); + count = (~0 >> 1); + } + __sti(); + barrier(); + __cli(); + } + goto again; + } + + 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 & (1UL << 15)) { + 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 >> 15) & 1; + /* 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: %016lx caller %p\n", + flags, __builtin_return_address(0)); + } +} + +#endif /* CONFIG_SMP */ + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +#ifdef CONFIG_IRQ_ALL_CPUS +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; +#else /* CONFIG_IRQ_ALL_CPUS */ +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000}; +#endif /* CONFIG_IRQ_ALL_CPUS */ + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", irq_affinity[(int)(long)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (int)(long) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +/* Why is this disabled ? --BenH */ +#if 0/*CONFIG_SMP*/ + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + +#ifdef CONFIG_PPC_ISERIES + { + unsigned i; + for (i=0; i>= 1; + } + } +#endif + + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == NULL)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == NULL) + continue; + register_irq_proc(i); + } +} + +void no_action(int irq, void *dev, struct pt_regs *regs) +{ +} diff -urN linux-2.4.18/arch/ppc64/kernel/lmb.c linux-2.4.19-pre5/arch/ppc64/kernel/lmb.c --- linux-2.4.18/arch/ppc64/kernel/lmb.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/lmb.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,373 @@ +/* + * + * Procedures for interfacing to Open Firmware. + * + * Peter Bergner, IBM Corp. June 2001. + * Copyright (C) 2001 Peter Bergner. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long klimit; +extern unsigned long reloc_offset(void); + + +static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long); + +struct lmb lmb = { + 0, + {0,0,0,0,{{0,0,0}}}, + {0,0,0,0,{{0,0,0}}} +}; + + +/* Assumption: base addr of region 1 < base addr of region 2 */ +static void +lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2) +{ + unsigned long i; + + rgn->region[r1].size += rgn->region[r2].size; + for (i=r2; i < rgn->cnt-1 ;i++) { + rgn->region[i].base = rgn->region[i+1].base; + rgn->region[i].physbase = rgn->region[i+1].physbase; + rgn->region[i].size = rgn->region[i+1].size; + rgn->region[i].type = rgn->region[i+1].type; + } + rgn->cnt--; +} + + +/* This routine called with relocation disabled. */ +void +lmb_init(void) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + + /* Create a dummy zero size LMB which will get coalesced away later. + * This simplifies the lmb_add() code below... + */ + _lmb->memory.region[0].base = 0; + _lmb->memory.region[0].size = 0; + _lmb->memory.region[0].type = LMB_MEMORY_AREA; + _lmb->memory.cnt = 1; + + /* Ditto. */ + _lmb->reserved.region[0].base = 0; + _lmb->reserved.region[0].size = 0; + _lmb->reserved.region[0].type = LMB_MEMORY_AREA; + _lmb->reserved.cnt = 1; +} + +/* This routine called with relocation disabled. */ +void +lmb_analyze(void) +{ + unsigned long i, physbase = 0; + unsigned long mem_size = 0; + unsigned long io_size = 0; + unsigned long size_mask = 0; + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + + for (i=0; i < _lmb->memory.cnt ;i++) { + unsigned long lmb_type = _lmb->memory.region[i].type; + unsigned long lmb_size; + + if ( lmb_type != LMB_MEMORY_AREA ) + continue; + + lmb_size = _lmb->memory.region[i].size; + +#ifdef CONFIG_MSCHUNKS + _lmb->memory.region[i].physbase = physbase; + physbase += lmb_size; +#else + _lmb->memory.region[i].physbase = _lmb->memory.region[i].base; +#endif + mem_size += lmb_size; + size_mask |= lmb_size; + } + + for (i=0; i < _lmb->memory.cnt ;i++) { + unsigned long lmb_type = _lmb->memory.region[i].type; + unsigned long lmb_size; + + if ( lmb_type != LMB_IO_AREA ) + continue; + + lmb_size = _lmb->memory.region[i].size; + +#ifdef CONFIG_MSCHUNKS + _lmb->memory.region[i].physbase = physbase; + physbase += lmb_size; +#else + _lmb->memory.region[i].physbase = _lmb->memory.region[i].base; +#endif + io_size += lmb_size; + size_mask |= lmb_size; + } + + _lmb->memory.size = mem_size; + _lmb->memory.iosize = io_size; + _lmb->memory.lcd_size = (1UL << cnt_trailing_zeros(size_mask)); +} + +/* This routine called with relocation disabled. */ +long +lmb_add(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_rgn = &(_lmb->memory); + + return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA); + +} + +/* This routine called with relocation disabled. */ +long +lmb_add_io(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_rgn = &(_lmb->memory); + + return lmb_add_region(_rgn, base, size, LMB_IO_AREA); + +} + +long +lmb_reserve(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_rgn = &(_lmb->reserved); + + return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA); +} + +/* This routine called with relocation disabled. */ +static long +lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size, + unsigned long type) +{ + unsigned long i, coalesced = 0; + long adjacent; + + /* First try and coalesce this LMB with another. */ + for (i=0; i < rgn->cnt ;i++) { + unsigned long rgnbase = rgn->region[i].base; + unsigned long rgnsize = rgn->region[i].size; + unsigned long rgntype = rgn->region[i].type; + + if ( rgntype != type ) + continue; + + adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); + if ( adjacent > 0 ) { + rgn->region[i].base -= size; + rgn->region[i].physbase -= size; + rgn->region[i].size += size; + coalesced++; + break; + } + else if ( adjacent < 0 ) { + rgn->region[i].size += size; + coalesced++; + break; + } + } + + if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { + lmb_coalesce_regions(rgn, i, i+1); + coalesced++; + } + + if ( coalesced ) { + return coalesced; + } else if ( rgn->cnt >= MAX_LMB_REGIONS ) { + return -1; + } + + /* Couldn't coalesce the LMB, so add it to the sorted table. */ + for (i=rgn->cnt-1; i >= 0 ;i--) { + if (base < rgn->region[i].base) { + rgn->region[i+1].base = rgn->region[i].base; + rgn->region[i+1].physbase = rgn->region[i].physbase; + rgn->region[i+1].size = rgn->region[i].size; + rgn->region[i+1].type = rgn->region[i].type; + } else { + rgn->region[i+1].base = base; + rgn->region[i+1].physbase = lmb_abs_to_phys(base); + rgn->region[i+1].size = size; + rgn->region[i+1].type = type; + break; + } + } + rgn->cnt++; + + return 0; +} + +long +lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, unsigned long size) +{ + unsigned long i; + + for (i=0; i < rgn->cnt ;i++) { + unsigned long rgnbase = rgn->region[i].base; + unsigned long rgnsize = rgn->region[i].size; + if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { + break; + } + } + + return (i < rgn->cnt) ? i : -1; +} + + +unsigned long +lmb_alloc(unsigned long size, unsigned long align) +{ + long i, j; + unsigned long base; + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_mem = &(_lmb->memory); + struct lmb_region *_rsv = &(_lmb->reserved); + + for (i=_mem->cnt-1; i >= 0 ;i--) { + unsigned long lmbbase = _mem->region[i].base; + unsigned long lmbsize = _mem->region[i].size; + unsigned long lmbtype = _mem->region[i].type; + + if ( lmbtype != LMB_MEMORY_AREA ) + continue; + + base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); + + while ( (lmbbase <= base) && + ((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) { + base = _ALIGN_DOWN(_rsv->region[j].base-size, align); + } + + if ( (base != 0) && (lmbbase <= base) ) + break; + } + + if ( i < 0 ) + return 0; + + lmb_add_region(_rsv, base, size, LMB_MEMORY_AREA); + + return base; +} + +unsigned long +lmb_phys_mem_size(void) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + return _lmb->memory.size; +} + +unsigned long +lmb_end_of_DRAM(void) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_mem = &(_lmb->memory); + unsigned long idx = _mem->cnt-1; + + for(idx=_mem->cnt-1; idx >= 0 ;idx--) { + unsigned long lastbase, lastsize; + if ( _mem->region[idx].type != LMB_MEMORY_AREA ) + continue; +#ifdef CONFIG_MSCHUNKS + return (_mem->region[idx].physbase + _mem->region[idx].size); +#else + return (_mem->region[idx].base + _mem->region[idx].size); +#endif /* CONFIG_MSCHUNKS */ + } + + return 0; +} + + +unsigned long +lmb_abs_to_phys(unsigned long aa) +{ + unsigned long i, pa = aa; + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb_region *_mem = &(_lmb->memory); + + for (i=0; i < _mem->cnt ;i++) { + unsigned long lmbbase = _mem->region[i].base; + unsigned long lmbsize = _mem->region[i].size; + if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) { + pa = _mem->region[i].physbase + (aa - lmbbase); + break; + } + } + + return pa; +} + +void +lmb_dump(char *str) +{ + unsigned long i; + + udbg_printf("\nlmb_dump: %s\n", str); + udbg_printf(" debug = %s\n", + (lmb.debug) ? "TRUE" : "FALSE"); + udbg_printf(" memory.cnt = %d\n", + lmb.memory.cnt); + udbg_printf(" memory.size = 0x%lx\n", + lmb.memory.size); + udbg_printf(" memory.lcd_size = 0x%lx\n", + lmb.memory.lcd_size); + for (i=0; i < lmb.memory.cnt ;i++) { + udbg_printf(" memory.region[%d].base = 0x%lx\n", + i, lmb.memory.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + lmb.memory.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + lmb.memory.region[i].size); + udbg_printf(" .type = 0x%lx\n", + lmb.memory.region[i].type); + } + + udbg_printf("\n"); + udbg_printf(" reserved.cnt = %d\n", + lmb.reserved.cnt); + udbg_printf(" reserved.size = 0x%lx\n", + lmb.reserved.size); + udbg_printf(" reserved.lcd_size = 0x%lx\n", + lmb.reserved.lcd_size); + for (i=0; i < lmb.reserved.cnt ;i++) { + udbg_printf(" reserved.region[%d].base = 0x%lx\n", + i, lmb.reserved.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + lmb.reserved.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + lmb.reserved.region[i].size); + udbg_printf(" .type = 0x%lx\n", + lmb.reserved.region[i].type); + } +} diff -urN linux-2.4.18/arch/ppc64/kernel/local_irq.h linux-2.4.19-pre5/arch/ppc64/kernel/local_irq.h --- linux-2.4.18/arch/ppc64/kernel/local_irq.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/local_irq.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,26 @@ +/* + * c 2001 PowerPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _PPC_KERNEL_LOCAL_IRQ_H +#define _PPC_KERNEL_LOCAL_IRQ_H + +#include +#include +#include +#include +#include + +void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); + +#define NR_MASK_WORDS ((NR_IRQS + 63) / 64) + +extern int ppc_spurious_interrupts; +extern int ppc_second_irq; +extern struct irqaction *ppc_irq_action[NR_IRQS]; + +#endif /* _PPC_KERNEL_LOCAL_IRQ_H */ diff -urN linux-2.4.18/arch/ppc64/kernel/mf.c linux-2.4.19-pre5/arch/ppc64/kernel/mf.c --- linux-2.4.18/arch/ppc64/kernel/mf.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/mf.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1202 @@ +/* + * mf.c + * Copyright (C) 2001 Troy D. Armstrong IBM Corporation + * + * This modules exists as an interface between a Linux secondary partition + * running on an iSeries and the primary partition's Virtual Service + * Processor (VSP) object. The VSP has final authority over powering on/off + * all partitions in the iSeries. It also provides miscellaneous low-level + * machine facility type operations. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct pci_dev * iSeries_vio_dev; + +/* + * This is the structure layout for the Machine Facilites LPAR event + * flows. + */ +struct VspCmdData; +struct CeMsgData; +union SafeCast +{ + u64 ptrAsU64; + void *ptr; +}; + + +typedef void (*CeMsgCompleteHandler)( void *token, struct CeMsgData *vspCmdRsp ); + +struct CeMsgCompleteData +{ + CeMsgCompleteHandler xHdlr; + void *xToken; +}; + +struct VspRspData +{ + struct semaphore *xSemaphore; + struct VspCmdData *xResponse; +}; + +struct IoMFLpEvent +{ + struct HvLpEvent xHvLpEvent; + + u16 xSubtypeRc; + u16 xRsvd1; + u32 xRsvd2; + + union + { + + struct AllocData + { + u16 xSize; + u16 xType; + u32 xCount; + u16 xRsvd3; + u8 xRsvd4; + HvLpIndex xTargetLp; + } xAllocData; + + struct CeMsgData + { + u8 xCEMsg[12]; + char xReserved[4]; + struct CeMsgCompleteData *xToken; + } xCEMsgData; + + struct VspCmdData + { + union SafeCast xTokenUnion; + u16 xCmd; + HvLpIndex xLpIndex; + u8 xRc; + u32 xReserved1; + + union VspCmdSubData + { + struct + { + u64 xState; + } xGetStateOut; + + struct + { + u64 xIplType; + } xGetIplTypeOut, xFunction02SelectIplTypeIn; + + struct + { + u64 xIplMode; + } xGetIplModeOut, xFunction02SelectIplModeIn; + + struct + { + u64 xPage[4]; + } xGetSrcHistoryIn; + + struct + { + u64 xFlag; + } xGetAutoIplWhenPrimaryIplsOut, + xSetAutoIplWhenPrimaryIplsIn, + xWhiteButtonPowerOffIn, + xFunction08FastPowerOffIn, + xIsSpcnRackPowerIncompleteOut; + + struct + { + u64 xToken; + u64 xAddressType; + u64 xSide; + u32 xTransferLength; + u32 xOffset; + } xSetKernelImageIn, + xGetKernelImageIn, + xSetKernelCmdLineIn, + xGetKernelCmdLineIn; + + struct + { + u32 xTransferLength; + } xGetKernelImageOut,xGetKernelCmdLineOut; + + + u8 xReserved2[80]; + + } xSubData; + } xVspCmd; + } xUnion; +}; + + +/* + * All outgoing event traffic is kept on a FIFO queue. The first + * pointer points to the one that is outstanding, and all new + * requests get stuck on the end. Also, we keep a certain number of + * preallocated stack elements so that we can operate very early in + * the boot up sequence (before kmalloc is ready). + */ +struct StackElement +{ + struct StackElement * next; + struct IoMFLpEvent event; + MFCompleteHandler hdlr; + char dmaData[72]; + unsigned dmaDataLength; + unsigned remoteAddress; +}; +static spinlock_t spinlock; +static struct StackElement * head = NULL; +static struct StackElement * tail = NULL; +static struct StackElement * avail = NULL; +static struct StackElement prealloc[16]; + +/* + * Put a stack element onto the available queue, so it can get reused. + * Attention! You must have the spinlock before calling! + */ +void free( struct StackElement * element ) +{ + if ( element != NULL ) + { + element->next = avail; + avail = element; + } +} + +/* + * Enqueue the outbound event onto the stack. If the queue was + * empty to begin with, we must also issue it via the Hypervisor + * interface. There is a section of code below that will touch + * the first stack pointer without the protection of the spinlock. + * This is OK, because we know that nobody else will be modifying + * the first pointer when we do this. + */ +static int signalEvent( struct StackElement * newElement ) +{ + int rc = 0; + unsigned long flags; + int go = 1; + struct StackElement * element; + HvLpEvent_Rc hvRc; + + /* enqueue the event */ + if ( newElement != NULL ) + { + spin_lock_irqsave( &spinlock, flags ); + if ( head == NULL ) + head = newElement; + else { + go = 0; + tail->next = newElement; + } + newElement->next = NULL; + tail = newElement; + spin_unlock_irqrestore( &spinlock, flags ); + } + + /* send the event */ + while ( go ) + { + go = 0; + + /* any DMA data to send beforehand? */ + if ( head->dmaDataLength > 0 ) + HvCallEvent_dmaToSp( head->dmaData, head->remoteAddress, head->dmaDataLength, HvLpDma_Direction_LocalToRemote ); + + hvRc = HvCallEvent_signalLpEvent(&head->event.xHvLpEvent); + if ( hvRc != HvLpEvent_Rc_Good ) + { + printk( KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n", (int)hvRc ); + + spin_lock_irqsave( &spinlock, flags ); + element = head; + head = head->next; + if ( head != NULL ) + go = 1; + spin_unlock_irqrestore( &spinlock, flags ); + + if ( element == newElement ) + rc = -EIO; + else { + if ( element->hdlr != NULL ) + { + union SafeCast mySafeCast; + mySafeCast.ptrAsU64 = element->event.xHvLpEvent.xCorrelationToken; + (*element->hdlr)( mySafeCast.ptr, -EIO ); + } + } + + spin_lock_irqsave( &spinlock, flags ); + free( element ); + spin_unlock_irqrestore( &spinlock, flags ); + } + } + + return rc; +} + +/* + * Allocate a new StackElement structure, and initialize it. + */ +static struct StackElement * newStackElement( void ) +{ + struct StackElement * newElement = NULL; + HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex(); + unsigned long flags; + + if ( newElement == NULL ) + { + spin_lock_irqsave( &spinlock, flags ); + if ( avail != NULL ) + { + newElement = avail; + avail = avail->next; + } + spin_unlock_irqrestore( &spinlock, flags ); + } + + if ( newElement == NULL ) + newElement = kmalloc(sizeof(struct StackElement),GFP_ATOMIC); + + if ( newElement == NULL ) + { + printk( KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", sizeof(struct StackElement) ); + return NULL; + } + + memset( newElement, 0, sizeof(struct StackElement) ); + newElement->event.xHvLpEvent.xFlags.xValid = 1; + newElement->event.xHvLpEvent.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck; + newElement->event.xHvLpEvent.xFlags.xAckInd = HvLpEvent_AckInd_DoAck; + newElement->event.xHvLpEvent.xFlags.xFunction = HvLpEvent_Function_Int; + newElement->event.xHvLpEvent.xType = HvLpEvent_Type_MachineFac; + newElement->event.xHvLpEvent.xSourceLp = HvLpConfig_getLpIndex(); + newElement->event.xHvLpEvent.xTargetLp = primaryLp; + newElement->event.xHvLpEvent.xSizeMinus1 = sizeof(newElement->event)-1; + newElement->event.xHvLpEvent.xRc = HvLpEvent_Rc_Good; + newElement->event.xHvLpEvent.xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac); + newElement->event.xHvLpEvent.xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac); + + return newElement; +} + +static int signalVspInstruction( struct VspCmdData *vspCmd ) +{ + struct StackElement * newElement = newStackElement(); + int rc = 0; + struct VspRspData response; + DECLARE_MUTEX_LOCKED(Semaphore); + response.xSemaphore = &Semaphore; + response.xResponse = vspCmd; + + if ( newElement == NULL ) + rc = -ENOMEM; + else { + newElement->event.xHvLpEvent.xSubtype = 6; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0); + newElement->event.xUnion.xVspCmd.xTokenUnion.ptr = &response; + newElement->event.xUnion.xVspCmd.xCmd = vspCmd->xCmd; + newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex(); + newElement->event.xUnion.xVspCmd.xRc = 0xFF; + newElement->event.xUnion.xVspCmd.xReserved1 = 0; + memcpy(&(newElement->event.xUnion.xVspCmd.xSubData),&(vspCmd->xSubData), sizeof(vspCmd->xSubData)); + mb(); + + rc = signalEvent(newElement); + } + + if (rc == 0) + { + down(&Semaphore); + } + + return rc; +} + + +/* + * Send a 12-byte CE message to the primary partition VSP object + */ +static int signalCEMsg( char * ceMsg, void * token ) +{ + struct StackElement * newElement = newStackElement(); + int rc = 0; + + if ( newElement == NULL ) + rc = -ENOMEM; + else { + newElement->event.xHvLpEvent.xSubtype = 0; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0); + memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 ); + newElement->event.xUnion.xCEMsgData.xToken = token; + rc = signalEvent(newElement); + } + + return rc; +} + +/* + * Send a 12-byte CE message and DMA data to the primary partition VSP object + */ +static int dmaAndSignalCEMsg( char * ceMsg, void * token, void * dmaData, unsigned dmaDataLength, unsigned remoteAddress ) +{ + struct StackElement * newElement = newStackElement(); + int rc = 0; + + if ( newElement == NULL ) + rc = -ENOMEM; + else { + newElement->event.xHvLpEvent.xSubtype = 0; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0); + memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 ); + newElement->event.xUnion.xCEMsgData.xToken = token; + memcpy( newElement->dmaData, dmaData, dmaDataLength ); + newElement->dmaDataLength = dmaDataLength; + newElement->remoteAddress = remoteAddress; + rc = signalEvent(newElement); + } + + return rc; +} + +/* + * Initiate a nice (hopefully) shutdown of Linux. We simply are + * going to try and send the init process a SIGINT signal. If + * this fails (why?), we'll simply force it off in a not-so-nice + * manner. + */ +static int shutdown( void ) +{ + int rc = kill_proc(1,SIGINT,1); + + if ( rc ) + { + printk( KERN_ALERT "mf.c: SIGINT to init failed (%d), hard shutdown commencing\n", rc ); + mf_powerOff(); + } + else + printk( KERN_ALERT "mf.c: init has been successfully notified to proceed with shutdown\n" ); + + return rc; +} + +/* + * The primary partition VSP object is sending us a new + * event flow. Handle it... + */ +static void intReceived( struct IoMFLpEvent * event ) +{ + int freeIt = 0; + struct StackElement * two = NULL; + /* ack the interrupt */ + event->xHvLpEvent.xRc = HvLpEvent_Rc_Good; + HvCallEvent_ackLpEvent( &event->xHvLpEvent ); + + /* process interrupt */ + switch( event->xHvLpEvent.xSubtype ) + { + case 0: /* CE message */ + switch( event->xUnion.xCEMsgData.xCEMsg[3] ) + { + case 0x5B: /* power control notification */ + if ( (event->xUnion.xCEMsgData.xCEMsg[5]&0x20) != 0 ) + { + printk( KERN_ALERT "mf.c: Commencing partition shutdown\n" ); + if ( shutdown() == 0 ) + signalCEMsg( "\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL ); + } + break; + case 0xC0: /* get time */ + { + if ( (head != NULL) && ( head->event.xUnion.xCEMsgData.xCEMsg[3] == 0x40 ) ) + { + freeIt = 1; + if ( head->event.xUnion.xCEMsgData.xToken != 0 ) + { + CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr; + void * token = head->event.xUnion.xCEMsgData.xToken->xToken; + + if (xHdlr != NULL) + (*xHdlr)( token, &(event->xUnion.xCEMsgData) ); + } + } + } + break; + } + + /* remove from queue */ + if ( freeIt == 1 ) + { + unsigned long flags; + spin_lock_irqsave( &spinlock, flags ); + if ( head != NULL ) + { + struct StackElement *oldHead = head; + head = head->next; + two = head; + free( oldHead ); + } + spin_unlock_irqrestore( &spinlock, flags ); + } + + /* send next waiting event */ + if ( two != NULL ) + signalEvent( NULL ); + break; + case 1: /* IT sys shutdown */ + printk( KERN_ALERT "mf.c: Commencing system shutdown\n" ); + shutdown(); + break; + } +} + +/* + * The primary partition VSP object is acknowledging the receipt + * of a flow we sent to them. If there are other flows queued + * up, we must send another one now... + */ +static void ackReceived( struct IoMFLpEvent * event ) +{ + unsigned long flags; + struct StackElement * two = NULL; + unsigned long freeIt = 0; + + /* handle current event */ + if ( head != NULL ) + { + switch( event->xHvLpEvent.xSubtype ) + { + case 0: /* CE msg */ + if ( event->xUnion.xCEMsgData.xCEMsg[3] == 0x40 ) + { + if ( event->xUnion.xCEMsgData.xCEMsg[2] != 0 ) + { + freeIt = 1; + if ( head->event.xUnion.xCEMsgData.xToken != 0 ) + { + CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr; + void * token = head->event.xUnion.xCEMsgData.xToken->xToken; + + if (xHdlr != NULL) + (*xHdlr)( token, &(event->xUnion.xCEMsgData) ); + } + } + } else { + freeIt = 1; + } + break; + case 4: /* allocate */ + case 5: /* deallocate */ + if ( head->hdlr != NULL ) + { + union SafeCast mySafeCast; + mySafeCast.ptrAsU64 = event->xHvLpEvent.xCorrelationToken; + (*head->hdlr)( mySafeCast.ptr, event->xUnion.xAllocData.xCount ); + } + freeIt = 1; + break; + case 6: + { + struct VspRspData *rsp = (struct VspRspData *)event->xUnion.xVspCmd.xTokenUnion.ptr; + + if (rsp != NULL) + { + if (rsp->xResponse != NULL) + memcpy(rsp->xResponse, &(event->xUnion.xVspCmd), sizeof(event->xUnion.xVspCmd)); + if (rsp->xSemaphore != NULL) + up(rsp->xSemaphore); + } else { + printk( KERN_ERR "mf.c: no rsp\n"); + } + freeIt = 1; + } + break; + } + } + else + printk( KERN_ERR "mf.c: stack empty for receiving ack\n" ); + + /* remove from queue */ + spin_lock_irqsave( &spinlock, flags ); + if (( head != NULL ) && ( freeIt == 1 )) + { + struct StackElement *oldHead = head; + head = head->next; + two = head; + free( oldHead ); + } + spin_unlock_irqrestore( &spinlock, flags ); + + /* send next waiting event */ + if ( two != NULL ) + signalEvent( NULL ); +} + +/* + * This is the generic event handler we are registering with + * the Hypervisor. Ensure the flows are for us, and then + * parse it enough to know if it is an interrupt or an + * acknowledge. + */ +static void hvHandler( struct HvLpEvent * event, struct pt_regs * regs ) +{ + if ( (event != NULL) && (event->xType == HvLpEvent_Type_MachineFac) ) + { + switch( event->xFlags.xFunction ) + { + case HvLpEvent_Function_Ack: + ackReceived( (struct IoMFLpEvent *)event ); + break; + case HvLpEvent_Function_Int: + intReceived( (struct IoMFLpEvent *)event ); + break; + default: + printk( KERN_ERR "mf.c: non ack/int event received\n" ); + break; + } + } + else + printk( KERN_ERR "mf.c: alien event received\n" ); +} + +/* + * Global kernel interface to allocate and seed events into the + * Hypervisor. + */ +void mf_allocateLpEvents( HvLpIndex targetLp, + HvLpEvent_Type type, + unsigned size, + unsigned count, + MFCompleteHandler hdlr, + void * userToken ) +{ + struct StackElement * newElement = newStackElement(); + int rc = 0; + + if ( newElement == NULL ) + rc = -ENOMEM; + else { + union SafeCast mine; + mine.ptr = userToken; + newElement->event.xHvLpEvent.xSubtype = 4; + newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('A'<<0); + newElement->event.xUnion.xAllocData.xTargetLp = targetLp; + newElement->event.xUnion.xAllocData.xType = type; + newElement->event.xUnion.xAllocData.xSize = size; + newElement->event.xUnion.xAllocData.xCount = count; + newElement->hdlr = hdlr; + rc = signalEvent(newElement); + } + + if ( (rc != 0) && (hdlr != NULL) ) + (*hdlr)( userToken, rc ); +} + +/* + * Global kernel interface to unseed and deallocate events already in + * Hypervisor. + */ +void mf_deallocateLpEvents( HvLpIndex targetLp, + HvLpEvent_Type type, + unsigned count, + MFCompleteHandler hdlr, + void * userToken ) +{ + struct StackElement * newElement = newStackElement(); + int rc = 0; + + if ( newElement == NULL ) + rc = -ENOMEM; + else { + union SafeCast mine; + mine.ptr = userToken; + newElement->event.xHvLpEvent.xSubtype = 5; + newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('D'<<0); + newElement->event.xUnion.xAllocData.xTargetLp = targetLp; + newElement->event.xUnion.xAllocData.xType = type; + newElement->event.xUnion.xAllocData.xCount = count; + newElement->hdlr = hdlr; + rc = signalEvent(newElement); + } + + if ( (rc != 0) && (hdlr != NULL) ) + (*hdlr)( userToken, rc ); +} + +/* + * Global kernel interface to tell the VSP object in the primary + * partition to power this partition off. + */ +void mf_powerOff( void ) +{ + printk( KERN_ALERT "mf.c: Down it goes...\n" ); + signalCEMsg( "\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL ); + for (;;); +} + +/* + * Global kernel interface to tell the VSP object in the primary + * partition to reboot this partition. + */ +void mf_reboot( void ) +{ + printk( KERN_ALERT "mf.c: Preparing to bounce...\n" ); + signalCEMsg( "\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL ); + for (;;); +} + +/* + * Display a single word SRC onto the VSP control panel. + */ +void mf_displaySrc( u32 word ) +{ + u8 ce[12]; + + memcpy( ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12 ); + ce[8] = word>>24; + ce[9] = word>>16; + ce[10] = word>>8; + ce[11] = word; + signalCEMsg( ce, NULL ); +} + +/* + * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. + */ +void mf_displayProgress( u16 value ) +{ + u8 ce[12]; + u8 src[72]; + + memcpy( ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12 ); + memcpy( src, + "\x01\x00\x00\x01" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "PROGxxxx" + " ", + 72 ); + src[6] = value>>8; + src[7] = value&255; + src[44] = "0123456789ABCDEF"[(value>>12)&15]; + src[45] = "0123456789ABCDEF"[(value>>8)&15]; + src[46] = "0123456789ABCDEF"[(value>>4)&15]; + src[47] = "0123456789ABCDEF"[value&15]; + dmaAndSignalCEMsg( ce, NULL, src, sizeof(src), 9*64*1024 ); +} + +/* + * Clear the VSP control panel. Used to "erase" an SRC that was + * previously displayed. + */ +void mf_clearSrc( void ) +{ + signalCEMsg( "\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL ); +} + +/* + * Initialization code here. + */ +void mf_init( void ) +{ + int i; + + /* initialize */ + spin_lock_init( &spinlock ); + for ( i = 0; i < sizeof(prealloc)/sizeof(*prealloc); ++i ) + free( &prealloc[i] ); + HvLpEvent_registerHandler( HvLpEvent_Type_MachineFac, &hvHandler ); + + /* virtual continue ack */ + signalCEMsg( "\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL ); + + /* initialization complete */ + printk( KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n" ); + + iSeries_proc_callback(&mf_proc_init); +} + +void mf_setSide(char side) +{ + int rc = 0; + u64 newSide = 0; + struct VspCmdData myVspCmd; + + memset(&myVspCmd, 0, sizeof(myVspCmd)); + if (side == 'A') + newSide = 0; + else if (side == 'B') + newSide = 1; + else if (side == 'C') + newSide = 2; + else + newSide = 3; + + myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = newSide; + myVspCmd.xCmd = 10; + + rc = signalVspInstruction(&myVspCmd); +} + +char mf_getSide(void) +{ + char returnValue = ' '; + int rc = 0; + struct VspCmdData myVspCmd; + + memset(&myVspCmd, 0, sizeof(myVspCmd)); + myVspCmd.xCmd = 2; + myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = 0; + mb(); + rc = signalVspInstruction(&myVspCmd); + + if (rc != 0) + { + return returnValue; + } else { + if (myVspCmd.xRc == 0) + { + if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 0) + returnValue = 'A'; + else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 1) + returnValue = 'B'; + else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 2) + returnValue = 'C'; + else + returnValue = 'D'; + } + } + + return returnValue; +} + +void mf_getSrcHistory(char *buffer, int size) +{ + /* struct IplTypeReturnStuff returnStuff; + struct StackElement * newElement = newStackElement(); + int rc = 0; + char *pages[4]; + + pages[0] = kmalloc(4096, GFP_ATOMIC); + pages[1] = kmalloc(4096, GFP_ATOMIC); + pages[2] = kmalloc(4096, GFP_ATOMIC); + pages[3] = kmalloc(4096, GFP_ATOMIC); + if (( newElement == NULL ) || (pages[0] == NULL) || (pages[1] == NULL) || (pages[2] == NULL) || (pages[3] == NULL)) + rc = -ENOMEM; + else + { + returnStuff.xType = 0; + returnStuff.xRc = 0; + returnStuff.xDone = 0; + newElement->event.xHvLpEvent.xSubtype = 6; + newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0); + newElement->event.xUnion.xVspCmd.xEvent = &returnStuff; + newElement->event.xUnion.xVspCmd.xCmd = 4; + newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex(); + newElement->event.xUnion.xVspCmd.xRc = 0xFF; + newElement->event.xUnion.xVspCmd.xReserved1 = 0; + newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[0] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[0])); + newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[1] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[1])); + newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[2] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[2])); + newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[3] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[3])); + mb(); + rc = signalEvent(newElement); + } + + if (rc != 0) + { + return; + } + else + { + while (returnStuff.xDone != 1) + { + udelay(10); + } + + if (returnStuff.xRc == 0) + { + memcpy(buffer, pages[0], size); + } + } + + kfree(pages[0]); + kfree(pages[1]); + kfree(pages[2]); + kfree(pages[3]);*/ +} + +void mf_setCmdLine(const char *cmdline, int size, u64 side) +{ + struct VspCmdData myVspCmd; + int rc = 0; + dma_addr_t dma_addr = 0; + char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr); + + if (page == NULL) { + printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n"); + return; + } + + copy_from_user(page, cmdline, size); + + memset(&myVspCmd, 0, sizeof(myVspCmd)); + myVspCmd.xCmd = 31; + myVspCmd.xSubData.xSetKernelCmdLineIn.xToken = dma_addr; + myVspCmd.xSubData.xSetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex; + myVspCmd.xSubData.xSetKernelCmdLineIn.xSide = side; + myVspCmd.xSubData.xSetKernelCmdLineIn.xTransferLength = size; + mb(); + rc = signalVspInstruction(&myVspCmd); + + pci_free_consistent(iSeries_vio_dev, size, page, dma_addr); +} + +int mf_getCmdLine(char *cmdline, int *size, u64 side) +{ + struct VspCmdData myVspCmd; + int rc = 0; + int len = *size; + dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, cmdline, *size, PCI_DMA_FROMDEVICE); + + memset(cmdline, 0, *size); + memset(&myVspCmd, 0, sizeof(myVspCmd)); + myVspCmd.xCmd = 33; + myVspCmd.xSubData.xGetKernelCmdLineIn.xToken = dma_addr; + myVspCmd.xSubData.xGetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex; + myVspCmd.xSubData.xGetKernelCmdLineIn.xSide = side; + myVspCmd.xSubData.xGetKernelCmdLineIn.xTransferLength = *size; + mb(); + rc = signalVspInstruction(&myVspCmd); + + if ( ! rc ) { + + if (myVspCmd.xRc == 0) + { + len = myVspCmd.xSubData.xGetKernelCmdLineOut.xTransferLength; + } + /* else + { + memcpy(cmdline, "Bad cmdline", 11); + } + */ + } + + pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE); + + return len; +} + + +int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side) +{ + struct VspCmdData myVspCmd; + int rc = 0; + + dma_addr_t dma_addr = 0; + + char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr); + + if (page == NULL) { + printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); + return -ENOMEM; + } + + copy_from_user(page, buffer, size); + memset(&myVspCmd, 0, sizeof(myVspCmd)); + + myVspCmd.xCmd = 30; + myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr; + myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex; + myVspCmd.xSubData.xGetKernelImageIn.xSide = side; + myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset; + myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = size; + mb(); + rc = signalVspInstruction(&myVspCmd); + + if (rc == 0) + { + if (myVspCmd.xRc == 0) + { + rc = 0; + } else { + rc = -ENOMEM; + } + } + + pci_free_consistent(iSeries_vio_dev, size, page, dma_addr); + + return rc; +} + +int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) +{ + struct VspCmdData myVspCmd; + int rc = 0; + int len = *size; + + dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, buffer, *size, PCI_DMA_FROMDEVICE); + + memset(buffer, 0, len); + + memset(&myVspCmd, 0, sizeof(myVspCmd)); + myVspCmd.xCmd = 32; + myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr; + myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex; + myVspCmd.xSubData.xGetKernelImageIn.xSide = side; + myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset; + myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = len; + mb(); + rc = signalVspInstruction(&myVspCmd); + + if (rc == 0) + { + if (myVspCmd.xRc == 0) + { + *size = myVspCmd.xSubData.xGetKernelImageOut.xTransferLength; + } else { + rc = -ENOMEM; + } + } + + pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE); + + return rc; +} + +int mf_setRtcTime(unsigned long time) +{ + struct rtc_time tm; + + to_tm(time, &tm); + + return mf_setRtc( &tm ); +} + +struct RtcTimeData +{ + struct semaphore *xSemaphore; + struct CeMsgData xCeMsg; + int xRc; +}; + +void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg) +{ + struct RtcTimeData *rtc = (struct RtcTimeData *)token; + + memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg)); + + rtc->xRc = 0; + up(rtc->xSemaphore); +} + +static unsigned long lastsec = 1; + +int mf_getRtcTime(unsigned long *time) +{ +/* unsigned long usec, tsec; */ + + u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart)); + u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1); + int year = 1970; + int year1 = ( dataWord1 >> 24 ) & 0x000000FF; + int year2 = ( dataWord1 >> 16 ) & 0x000000FF; + int sec = ( dataWord1 >> 8 ) & 0x000000FF; + int min = dataWord1 & 0x000000FF; + int hour = ( dataWord2 >> 24 ) & 0x000000FF; + int day = ( dataWord2 >> 8 ) & 0x000000FF; + int mon = dataWord2 & 0x000000FF; + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year1); + BCD_TO_BIN(year2); + year = year1 * 100 + year2; + + *time = mktime(year, mon, day, hour, min, sec); + + *time += ( jiffies / HZ ); + + /* Now THIS is a nasty hack! + * It ensures that the first two calls to mf_getRtcTime get different + * answers. That way the loop in init_time (time.c) will not think + * the clock is stuck. + */ + if ( lastsec ) { + *time -= lastsec; + --lastsec; + } + + return 0; + +} + +int mf_getRtc( struct rtc_time * tm ) +{ + + struct CeMsgCompleteData ceComplete; + struct RtcTimeData rtcData; + int rc = 0; + DECLARE_MUTEX_LOCKED(Semaphore); + + memset(&ceComplete, 0, sizeof(ceComplete)); + memset(&rtcData, 0, sizeof(rtcData)); + + rtcData.xSemaphore = &Semaphore; + + ceComplete.xHdlr = &getRtcTimeComplete; + ceComplete.xToken = (void *)&rtcData; + + rc = signalCEMsg( "\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00", &ceComplete ); + + if ( rc == 0 ) + { + down(&Semaphore); + + if ( rtcData.xRc == 0) + { + if ( ( rtcData.xCeMsg.xCEMsg[2] == 0xa9 ) || + ( rtcData.xCeMsg.xCEMsg[2] == 0xaf ) ) { + /* TOD clock is not set */ + tm->tm_sec = 1; + tm->tm_min = 1; + tm->tm_hour = 1; + tm->tm_mday = 10; + tm->tm_mon = 8; + tm->tm_year = 71; + mf_setRtc( tm ); + } + { + u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.xCEMsg+4)); + u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.xCEMsg+8)); + u8 year = (dataWord1 >> 16 ) & 0x000000FF; + u8 sec = ( dataWord1 >> 8 ) & 0x000000FF; + u8 min = dataWord1 & 0x000000FF; + u8 hour = ( dataWord2 >> 24 ) & 0x000000FF; + u8 day = ( dataWord2 >> 8 ) & 0x000000FF; + u8 mon = dataWord2 & 0x000000FF; + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ( year <= 69 ) + year += 100; + + tm->tm_sec = sec; + tm->tm_min = min; + tm->tm_hour = hour; + tm->tm_mday = day; + tm->tm_mon = mon; + tm->tm_year = year; + } + } else { + rc = rtcData.xRc; + tm->tm_sec = 0; + tm->tm_min = 0; + tm->tm_hour = 0; + tm->tm_mday = 15; + tm->tm_mon = 5; + tm->tm_year = 52; + + } + tm->tm_wday = 0; + tm->tm_yday = 0; + tm->tm_isdst = 0; + + } + + return rc; + +} + +int mf_setRtc(struct rtc_time * tm) +{ + char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00"; + int rc = 0; + u8 day, mon, hour, min, sec, y1, y2; + unsigned year; + + year = 1900 + tm->tm_year; + y1 = year / 100; + y2 = year % 100; + + sec = tm->tm_sec; + min = tm->tm_min; + hour = tm->tm_hour; + day = tm->tm_mday; + mon = tm->tm_mon + 1; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(mon); + BIN_TO_BCD(day); + BIN_TO_BCD(y1); + BIN_TO_BCD(y2); + + ceTime[4] = y1; + ceTime[5] = y2; + ceTime[6] = sec; + ceTime[7] = min; + ceTime[8] = hour; + ceTime[10] = day; + ceTime[11] = mon; + + rc = signalCEMsg( ceTime, NULL ); + + return rc; +} + + + diff -urN linux-2.4.18/arch/ppc64/kernel/mf_proc.c linux-2.4.19-pre5/arch/ppc64/kernel/mf_proc.c --- linux-2.4.18/arch/ppc64/kernel/mf_proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/mf_proc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,301 @@ +/* + * mf_proc.c + * Copyright (C) 2001 Kyle A. Lucke IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* Change Activity: */ +/* End Change Activity */ + +#ifndef _MF_PROC_H +#include +#endif +#ifndef MF_H_INCLUDED +#include +#endif +#include + +static struct proc_dir_entry *mf_proc_root = NULL; + +int proc_mf_dump_cmdline +(char *page, char **start, off_t off, int count, int *eof, void *data); + +int proc_mf_dump_vmlinux +(char *page, char **start, off_t off, int count, int *eof, void *data); + +int proc_mf_dump_side +(char *page, char **start, off_t off, int count, int *eof, void *data); + +int proc_mf_change_side +(struct file *file, const char *buffer, unsigned long count, void *data); + +int proc_mf_dump_src +(char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_mf_change_src (struct file *file, const char *buffer, unsigned long count, void *data); +int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data); +int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data); + + +void mf_proc_init(struct proc_dir_entry *iSeries_proc) +{ + struct proc_dir_entry *ent = NULL; + struct proc_dir_entry *mf_a = NULL; + struct proc_dir_entry *mf_b = NULL; + struct proc_dir_entry *mf_c = NULL; + struct proc_dir_entry *mf_d = NULL; + + mf_proc_root = proc_mkdir("mf", iSeries_proc); + if (!mf_proc_root) return; + + mf_a = proc_mkdir("A", mf_proc_root); + if (!mf_a) return; + + ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_a); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_mf_dump_cmdline; + ent->write_proc = proc_mf_change_cmdline; + + ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_a); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_mf_dump_vmlinux; + ent->write_proc = proc_mf_change_vmlinux; + + mf_b = proc_mkdir("B", mf_proc_root); + if (!mf_b) return; + + ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_b); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)1; + ent->read_proc = proc_mf_dump_cmdline; + ent->write_proc = proc_mf_change_cmdline; + + ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_b); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)1; + ent->read_proc = proc_mf_dump_vmlinux; + ent->write_proc = proc_mf_change_vmlinux; + + mf_c = proc_mkdir("C", mf_proc_root); + if (!mf_c) return; + + ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_c); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)2; + ent->read_proc = proc_mf_dump_cmdline; + ent->write_proc = proc_mf_change_cmdline; + + ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_c); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)2; + ent->read_proc = proc_mf_dump_vmlinux; + ent->write_proc = proc_mf_change_vmlinux; + + mf_d = proc_mkdir("D", mf_proc_root); + if (!mf_d) return; + + + ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_d); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)3; + ent->read_proc = proc_mf_dump_cmdline; + ent->write_proc = proc_mf_change_cmdline; + + ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR, mf_d); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)3; + ent->read_proc = proc_mf_dump_vmlinux; + ent->write_proc = NULL; + + ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_mf_dump_side; + ent->write_proc = proc_mf_change_side; + + ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_mf_dump_src; + ent->write_proc = proc_mf_change_src; +} + +int proc_mf_dump_cmdline +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = count; + char *p; + + len = mf_getCmdLine(page, &len, (u64)data); + + p = page + len - 1; + while ( p > page ) { + if ( (*p == 0) || (*p == ' ') ) + --p; + else + break; + } + if ( *p != '\n' ) { + ++p; + *p = '\n'; + } + ++p; + *p = 0; + len = p - page; + + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + +int proc_mf_dump_vmlinux +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int sizeToGet = count; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) + { + if (sizeToGet != 0) + { + *start = page + off; + printk("mf_proc.c: got count %d off %d\n", sizeToGet, (int)off); + return sizeToGet; + } else { + printk("mf_proc.c: eof\n"); + *eof = 1; + return 0; + } + } else { + printk("mf_proc.c: eof\n"); + *eof = 1; + return 0; + } +} + + +int proc_mf_dump_side +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + char mf_current_side = mf_getSide(); + len = sprintf(page, "%c\n", mf_current_side); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if ((*buffer != 'A') && + (*buffer != 'B') && + (*buffer != 'C') && + (*buffer != 'D')) + { + printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); + return -EINVAL; + } + + mf_setSide(*buffer); + + return count; +} + +int proc_mf_dump_src +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + mf_getSrcHistory(page, count); + len = count; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + +int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if ((count < 4) && (count != 1)) + { + printk(KERN_ERR "mf_proc: invalid src\n"); + return -EINVAL; + } + + if ((count == 1) && ((*buffer) == '\0')) + { + mf_clearSrc(); + } else { + mf_displaySrc(*(u32 *)buffer); + } + + return count; +} + +int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + mf_setCmdLine(buffer, count, (u64)data); + + return count; +} + +int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + mf_setVmlinuxChunk(buffer, count, file->f_pos, (u64)data); + file->f_pos += count; + + return count; +} diff -urN linux-2.4.18/arch/ppc64/kernel/misc.S linux-2.4.19-pre5/arch/ppc64/kernel/misc.S --- linux-2.4.18/arch/ppc64/kernel/misc.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/misc.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,948 @@ +/* + * arch/ppc/kernel/misc.S + * + * + * + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * PPC64 updates by Dave Engebretsen (engebret@us.ibm.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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ppc_asm.h" + + .text + +/* + * Returns (address we're running at) - (address we were linked at) + * for use before the text and data are mapped to KERNELBASE. + */ + +_GLOBAL(reloc_offset) + mflr r0 + bl 1f +1: mflr r3 + LOADADDR(r4,1b) + sub r3,r4,r3 + mtlr r0 + blr + +_GLOBAL(get_msr) + mfmsr r3 + blr + +_GLOBAL(get_dar) + mfdar r3 + blr + +_GLOBAL(get_srr0) + mfsrr0 r3 + blr + +_GLOBAL(get_srr1) + mfsrr1 r3 + blr + +_GLOBAL(get_sp) + mr r3,r1 + blr + +#ifdef CONFIG_PPC_ISERIES +/* unsigned long __no_use_save_flags(void) */ +_GLOBAL(__no_use_save_flags) + mfspr r4,SPRG3 + lbz r3,PACAPROCENABLED(r4) + blr + +/* void __no_use_restore_flags(unsigned long flags) */ +_GLOBAL(__no_use_restore_flags) +/* + * Just set/clear the MSR_EE bit through restore/flags but do not + * change anything else. This is needed by the RT system and makes + * sense anyway. + * -- Cort + */ + mfspr r6,SPRG3 + lbz r5,PACAPROCENABLED(r6) + /* Check if things are setup the way we want _already_. */ + cmpw 0,r3,r5 + beqlr + /* are we enabling interrupts? */ + cmpi 0,r3,0 + stb r3,PACAPROCENABLED(r6) + beqlr + /* Check pending interrupts */ + CHECKANYINT(r4,r5) + beqlr + + /* + * Handle pending interrupts in interrupt context + */ + li r0,0x5555 + sc + blr + +_GLOBAL(__no_use_cli) + mfspr r5,SPRG3 + lbz r3,PACAPROCENABLED(r5) + li r4,0 + stb r4,PACAPROCENABLED(r5) + blr /* Done */ + +_GLOBAL(__no_use_sti) + mfspr r6,SPRG3 + li r3,1 + stb r3,PACAPROCENABLED(r6) + + /* Check for pending interrupts + * A decrementer, IPI or PMC interrupt may have occurred + * while we were in the hypervisor (which enables) + */ + CHECKANYINT(r4,r5) + beqlr + + /* + * Handle pending interrupts in interrupt context + */ + li r0,0x5555 + sc + blr +#endif +/* + * Flush instruction cache. + */ +_GLOBAL(flush_instruction_cache) + +/* + * This is called by kgdb code + * and should probably go away + * to be replaced by invalidating + * the cache lines that are actually + * modified + */ + /* use invalidate-all bit in HID0 + * - is this consistent across all 64-bit cpus? -- paulus */ + mfspr r3,HID0 + ori r3,r3,HID0_ICFI + mtspr HID0,r3 + sync + isync + blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * + * flush_icache_range(unsigned long start, unsigned long stop) + * + * flush all bytes from start through stop-1 inclusive + */ + +_GLOBAL(flush_icache_range) + +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + * and in some cases i-cache and d-cache line sizes differ from + * each other. + */ + LOADADDR(r10,naca) /* Get Naca address */ + ld r10,0(r10) + lhz r7,DCACHEL1LINESIZE(r10) /* Get cache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lhz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +1: dcbst 0,r6 + add r6,r6,r7 + bdnz 1b + sync + +/* Now invalidate the instruction cache */ + + lhz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 + lhz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +2: icbi 0,r6 + add r6,r6,r7 + bdnz 2b + isync + blr + +/* + * Like above, but only do the D-cache. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + * + * flush all bytes from start to stop-1 inclusive + */ +_GLOBAL(flush_dcache_range) + +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + */ + LOADADDR(r10,naca) /* Get Naca address */ + ld r10,0(r10) + lhz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lhz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +0: dcbst 0,r6 + add r6,r6,r7 + bdnz 0b + sync + blr + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + * void __flush_dcache_icache(void *page) + */ +_GLOBAL(__flush_dcache_icache) +/* + * Flush the data cache to memory + * + * Different systems have different cache line sizes + */ + +/* Flush the dcache */ + LOADADDR(r7,naca) + ld r7,0(r7) + clrrdi r3,r3,12 /* Page align */ + lhz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ + lhz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ + mr r6,r3 + mtctr r4 +0: dcbst 0,r6 + add r6,r6,r5 + bdnz 0b + sync + +/* Now invalidate the icache */ + + lhz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ + lhz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ + mtctr r4 +1: icbi 0,r3 + add r3,r3,r5 + bdnz 1b + isync + blr + +/* + * Copy a whole page. Assumes a 4096B page size. + */ +_GLOBAL(copy_page) + clrrdi r3,r3,12 /* Page align */ + clrrdi r4,r4,12 /* Page align */ + li r5,256 + mtctr r5 + addi r3,r3,-8 + addi r4,r4,-8 + +1: ld r6,8(r4) + ldu r7,16(r4) + std r6,8(r3) + stdu r7,16(r3) + bdnz+ 1b + blr + +/* + * I/O string operations + * + * insb(port, buf, len) + * outsb(port, buf, len) + * insw(port, buf, len) + * outsw(port, buf, len) + * insl(port, buf, len) + * outsl(port, buf, len) + * insw_ns(port, buf, len) + * outsw_ns(port, buf, len) + * insl_ns(port, buf, len) + * outsl_ns(port, buf, len) + * + * The *_ns versions don't do byte-swapping. + */ +_GLOBAL(_insb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbz r5,0(r3) + eieio + stbu r5,1(r4) + bdnz 00b + blr + +_GLOBAL(_outsb) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,1 + blelr- +00: lbzu r5,1(r4) + stb r5,0(r3) + eieio + bdnz 00b + blr + +_GLOBAL(_insw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhbrx r5,0,r3 + eieio + sthu r5,2(r4) + bdnz 00b + blr + +_GLOBAL(_outsw) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + eieio + sthbrx r5,0,r3 + bdnz 00b + blr + +_GLOBAL(_insl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwbrx r5,0,r3 + eieio + stwu r5,4(r4) + bdnz 00b + blr + +_GLOBAL(_outsl) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stwbrx r5,0,r3 + eieio + bdnz 00b + blr + +_GLOBAL(ide_insw) +_GLOBAL(_insw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhz r5,0(r3) + eieio + sthu r5,2(r4) + bdnz 00b + blr + +_GLOBAL(ide_outsw) +_GLOBAL(_outsw_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,2 + blelr- +00: lhzu r5,2(r4) + sth r5,0(r3) + eieio + bdnz 00b + blr + +_GLOBAL(_insl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwz r5,0(r3) + eieio + stwu r5,4(r4) + bdnz 00b + blr + +_GLOBAL(_outsl_ns) + cmpwi 0,r5,0 + mtctr r5 + subi r4,r4,4 + blelr- +00: lwzu r5,4(r4) + stw r5,0(r3) + eieio + bdnz 00b + blr + +/* + * Extended precision shifts + * + * R3/R4 has 64 bit value + * R5 has shift count + * result in R3/R4 + * + * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ + * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000 + * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ + */ +/* MIKEC: These may no longer be needed...what does gcc expect ? */ + +_GLOBAL(__ashrdi3) + li r6,32 + sub r6,r6,r5 + slw r7,r3,r6 /* isolate YYY */ + srw r4,r4,r5 /* isolate ZZZ */ + or r4,r4,r7 /* YYYZZZ */ + sraw r3,r3,r5 /* SSSXXX */ + blr + +_GLOBAL(__ashldi3) + li r6,32 + sub r6,r6,r5 + srw r7,r4,r6 /* isolate ZZZ */ + slw r4,r4,r5 /* AAA000 */ + slw r3,r3,r5 /* YYY--- */ + or r3,r3,r7 /* YYYZZZ */ + blr + +_GLOBAL(__lshrdi3) + li r6,32 + sub r6,r6,r5 + slw r7,r3,r6 /* isolate YYY */ + srw r4,r4,r5 /* isolate ZZZ */ + or r4,r4,r7 /* YYYZZZ */ + srw r3,r3,r5 /* 000XXX */ + blr + +_GLOBAL(abs) + cmpi 0,r3,0 + bge 10f + neg r3,r3 +10: blr + +_GLOBAL(_get_SP) + mr r3,r1 /* Close enough */ + blr + +_GLOBAL(_get_PVR) + mfspr r3,PVR + blr + +_GLOBAL(_get_PIR) + mfspr r3,PIR + blr + +_GLOBAL(_get_HID0) + mfspr r3,HID0 + blr + +_GLOBAL(cvt_fd) + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfs 0,0(r3) + stfd 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr + +_GLOBAL(cvt_df) + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr + +/* + * Create a kernel thread + * kernel_thread(fn, arg, flags) + */ +_GLOBAL(kernel_thread) + mr r6,r3 /* function */ + ori r3,r5,CLONE_VM /* flags */ + li r0,__NR_clone + sc + cmpi 0,r3,0 /* parent or child? */ + bnelr /* return if parent */ + + li r0,0 /* clear out p->thread.regs */ + std r0,THREAD+PT_REGS(r13) /* since we don't have user ctx */ + li r0,RUN_FLAG /* Run light on */ + std r0,THREAD+THREAD_FLAGS(r13) + + ld r2,8(r6) + ld r6,0(r6) + mtlr r6 /* fn addr in lr */ + mr r3,r4 /* load arg and call fn */ + blrl + li r0,__NR_exit /* exit after child exits */ + li r3,0 + sc + +#ifdef CONFIG_BINFMT_ELF32 +/* Why isn't this a) automatic, b) written in 'C'? */ + .data + .align 8 +_GLOBAL(sys_call_table32) + .llong .sys_ni_syscall /* 0 - old "setup()" system call */ + .llong .sys32_exit + .llong .sys32_fork + .llong .sys_read + .llong .sys_write + .llong .sys32_open /* 5 */ + .llong .sys_close + .llong .sys32_waitpid + .llong .sys32_creat + .llong .sys_link + .llong .sys_unlink /* 10 */ + .llong .sys32_execve + .llong .sys_chdir + .llong .sys32_time + .llong .sys32_mknod + .llong .sys32_chmod /* 15 */ + .llong .sys_lchown + .llong .sys_ni_syscall /* old break syscall holder */ + .llong .sys32_stat + .llong .sys32_lseek + .llong .sys_getpid /* 20 */ + .llong .sys32_mount + .llong .sys_oldumount + .llong .sys_setuid + .llong .sys_getuid + .llong .ppc64_sys32_stime /* 25 */ + .llong .sys32_ptrace + .llong .sys_alarm + .llong .sys32_fstat + .llong .sys32_pause + .llong .sys32_utime /* 30 */ + .llong .sys_ni_syscall /* old stty syscall holder */ + .llong .sys_ni_syscall /* old gtty syscall holder */ + .llong .sys32_access + .llong .sys32_nice + .llong .sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .llong .sys_sync + .llong .sys32_kill + .llong .sys_rename + .llong .sys32_mkdir + .llong .sys_rmdir /* 40 */ + .llong .sys_dup + .llong .sys_pipe + .llong .sys32_times + .llong .sys_ni_syscall /* old prof syscall holder */ + .llong .sys_brk /* 45 */ + .llong .sys_setgid + .llong .sys_getgid + .llong .sys_signal + .llong .sys_geteuid + .llong .sys_getegid /* 50 */ + .llong .sys_acct + .llong .sys32_umount /* recycled never used phys() */ + .llong .sys_ni_syscall /* old lock syscall holder */ + .llong .sys32_ioctl + .llong .sys32_fcntl /* 55 */ + .llong .sys_ni_syscall /* old mpx syscall holder */ + .llong .sys32_setpgid + .llong .sys_ni_syscall /* old ulimit syscall holder */ + .llong .sys_olduname + .llong .sys32_umask /* 60 */ + .llong .sys_chroot + .llong .sys_ustat + .llong .sys_dup2 + .llong .sys_getppid + .llong .sys_getpgrp /* 65 */ + .llong .sys_setsid + .llong .sys32_sigaction + .llong .sys_sgetmask + .llong .sys32_ssetmask + .llong .sys_setreuid /* 70 */ + .llong .sys_setregid + .llong .sys_sigsuspend + .llong .sys32_sigpending + .llong .sys32_sethostname + .llong .sys32_setrlimit /* 75 */ + .llong .sys32_old_getrlimit + .llong .sys32_getrusage + .llong .sys32_gettimeofday + .llong .sys32_settimeofday + .llong .sys32_getgroups /* 80 */ + .llong .sys32_setgroups + .llong .ppc32_select + .llong .sys_symlink + .llong .sys32_lstat + .llong .sys32_readlink /* 85 */ + .llong .sys_uselib + .llong .sys32_swapon + .llong .sys32_reboot + .llong .old32_readdir + .llong .sys32_mmap /* 90 */ + .llong .sys_munmap + .llong .sys_truncate + .llong .sys_ftruncate + .llong .sys_fchmod + .llong .sys_fchown /* 95 */ + .llong .sys32_getpriority + .llong .sys32_setpriority + .llong .sys_ni_syscall /* old profil syscall holder */ + .llong .sys32_statfs + .llong .sys32_fstatfs /* 100 */ + .llong .sys32_ioperm + .llong .sys32_socketcall + .llong .sys32_syslog + .llong .sys32_setitimer + .llong .sys32_getitimer /* 105 */ + .llong .sys32_newstat + .llong .sys32_newlstat + .llong .sys32_newfstat + .llong .sys_uname + .llong .sys32_iopl /* 110 */ + .llong .sys_vhangup + .llong .sys_ni_syscall /* old 'idle' syscall */ + .llong .sys32_vm86 + .llong .sys32_wait4 + .llong .sys_swapoff /* 115 */ + .llong .sys32_sysinfo + .llong .sys32_ipc + .llong .sys_fsync + .llong .ppc32_sigreturn + .llong .sys32_clone /* 120 */ + .llong .sys32_setdomainname + .llong .ppc64_newuname + .llong .sys32_modify_ldt + .llong .sys32_adjtimex + .llong .sys_mprotect /* 125 */ + .llong .sys32_sigprocmask + .llong .sys32_create_module + .llong .sys32_init_module + .llong .sys32_delete_module + .llong .sys32_get_kernel_syms /* 130 */ + .llong .sys32_quotactl + .llong .sys32_getpgid + .llong .sys_fchdir + .llong .sys32_bdflush + .llong .sys32_sysfs /* 135 */ + .llong .sys32_personality + .llong .sys_ni_syscall /* for afs_syscall */ + .llong .sys_setfsuid + .llong .sys_setfsgid + .llong .sys_llseek /* 140 */ + .llong .sys32_getdents + .llong .ppc32_select + .llong .sys_flock + .llong .sys32_msync + .llong .sys32_readv /* 145 */ + .llong .sys32_writev + .llong .sys32_getsid + .llong .sys_fdatasync + .llong .sys32_sysctl + .llong .sys_mlock /* 150 */ + .llong .sys_munlock + .llong .sys32_mlockall + .llong .sys_munlockall + .llong .sys32_sched_setparam + .llong .sys32_sched_getparam /* 155 */ + .llong .sys32_sched_setscheduler + .llong .sys32_sched_getscheduler + .llong .sys_sched_yield + .llong .sys32_sched_get_priority_max + .llong .sys32_sched_get_priority_min /* 160 */ + .llong .sys32_sched_rr_get_interval + .llong .sys32_nanosleep + .llong .sys32_mremap + .llong .sys_setresuid + .llong .sys_getresuid /* 165 */ + .llong .sys32_query_module + .llong .sys_poll + .llong .sys32_nfsservctl + .llong .sys_setresgid + .llong .sys_getresgid /* 170 */ + .llong .sys32_prctl + .llong .ppc32_rt_sigreturn + .llong .sys32_rt_sigaction + .llong .sys32_rt_sigprocmask + .llong .sys32_rt_sigpending /* 175 */ + .llong .sys32_rt_sigtimedwait + .llong .sys32_rt_sigqueueinfo + .llong .sys32_rt_sigsuspend + .llong .sys32_pread + .llong .sys32_pwrite /* 180 */ + .llong .sys_chown + .llong .sys_getcwd + .llong .sys_capget + .llong .sys_capset + .llong .sys32_sigaltstack /* 185 */ + .llong .sys32_sendfile + .llong .sys_ni_syscall /* streams1 */ + .llong .sys_ni_syscall /* streams2 */ + .llong .sys32_vfork + .llong .sys32_getrlimit /* 190 */ + .llong .sys_ni_syscall /* 191 */ /* Unused */ + .llong .sys_ni_syscall /* 192 - reserved - mmap2 */ + .llong .sys32_truncate64 /* 193 - truncate64 */ + .llong .sys32_ftruncate64 /* 194 - ftruncate64 */ + .llong .sys_stat64 /* 195 - stat64 */ + .llong .sys_lstat64 /* 196 - lstat64 */ + .llong .sys_fstat64 /* 197 - fstat64 */ + .llong .sys32_pciconfig_read /* 198 */ + .llong .sys32_pciconfig_write /* 199 */ + .llong .sys_pciconfig_iobase /* 200 */ + .llong .sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ + .llong .sys_getdents64 /* 202 */ + .llong .sys_pivot_root /* 203 */ + .llong .sys32_fcntl64 /* 204 */ + .llong .sys_madvise /* 205 */ + .llong .sys_mincore /* 206 */ + .rept NR_syscalls-206 + .llong .sys_ni_syscall + .endr +#endif + .data + .align 8 +_GLOBAL(sys_call_table) + .llong .sys_ni_syscall /* 0 - old "setup()" system call */ + .llong .sys_exit + .llong .sys_fork + .llong .sys_read + .llong .sys_write + .llong .sys_open /* 5 */ + .llong .sys_close + .llong .sys_waitpid + .llong .sys_creat + .llong .sys_link + .llong .sys_unlink /* 10 */ + .llong .sys_execve + .llong .sys_chdir + .llong .sys64_time + .llong .sys_mknod + .llong .sys_chmod /* 15 */ + .llong .sys_lchown + .llong .sys_ni_syscall /* old break syscall holder */ + .llong .sys_stat + .llong .sys_lseek + .llong .sys_getpid /* 20 */ + .llong .sys_mount + .llong .sys_oldumount + .llong .sys_setuid + .llong .sys_getuid + .llong .ppc64_sys_stime /* 25 */ + .llong .sys_ptrace + .llong .sys_alarm + .llong .sys_fstat + .llong .sys_pause + .llong .sys_utime /* 30 */ + .llong .sys_ni_syscall /* old stty syscall holder */ + .llong .sys_ni_syscall /* old gtty syscall holder */ + .llong .sys_access + .llong .sys_nice + .llong .sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .llong .sys_sync + .llong .sys_kill + .llong .sys_rename + .llong .sys_mkdir + .llong .sys_rmdir /* 40 */ + .llong .sys_dup + .llong .sys_pipe + .llong .sys_times + .llong .sys_ni_syscall /* old prof syscall holder */ + .llong .sys_brk /* 45 */ + .llong .sys_setgid + .llong .sys_getgid + .llong .sys_signal + .llong .sys_geteuid + .llong .sys_getegid /* 50 */ + .llong .sys_acct + .llong .sys_umount /* recycled never used phys() */ + .llong .sys_ni_syscall /* old lock syscall holder */ + .llong .sys_ioctl + .llong .sys_fcntl /* 55 */ + .llong .sys_ni_syscall /* old mpx syscall holder */ + .llong .sys_setpgid + .llong .sys_ni_syscall /* old ulimit syscall holder */ + .llong .sys_olduname + .llong .sys_umask /* 60 */ + .llong .sys_chroot + .llong .sys_ustat + .llong .sys_dup2 + .llong .sys_getppid + .llong .sys_getpgrp /* 65 */ + .llong .sys_setsid + .llong .sys_sigaction + .llong .sys_sgetmask + .llong .sys_ssetmask + .llong .sys_setreuid /* 70 */ + .llong .sys_setregid + .llong .sys_sigsuspend + .llong .sys_sigpending + .llong .sys_sethostname + .llong .sys_setrlimit /* 75 */ + .llong .sys_old_getrlimit + .llong .sys_getrusage + .llong .sys_gettimeofday + .llong .sys_settimeofday + .llong .sys_getgroups /* 80 */ + .llong .sys_setgroups + .llong .sys_select + .llong .sys_symlink + .llong .sys_lstat + .llong .sys_readlink /* 85 */ + .llong .sys_uselib + .llong .sys_swapon + .llong .sys_reboot + .llong .old_readdir + .llong .sys_mmap /* 90 */ + .llong .sys_munmap + .llong .sys_truncate + .llong .sys_ftruncate + .llong .sys_fchmod + .llong .sys_fchown /* 95 */ + .llong .sys_getpriority + .llong .sys_setpriority + .llong .sys_ni_syscall /* old profil syscall holder */ + .llong .sys_statfs + .llong .sys_fstatfs /* 100 */ + .llong .sys_ioperm + .llong .sys_socketcall + .llong .sys_syslog + .llong .sys_setitimer + .llong .sys_getitimer /* 105 */ + .llong .sys_newstat + .llong .sys_newlstat + .llong .sys_newfstat + .llong .sys_uname + .llong .sys_iopl /* 110 */ + .llong .sys_vhangup + .llong .sys_ni_syscall /* old 'idle' syscall */ + .llong .sys_vm86 + .llong .sys_wait4 + .llong .sys_swapoff /* 115 */ + .llong .sys_sysinfo + .llong .sys_ipc + .llong .sys_fsync + .llong .ppc64_sigreturn + .llong .sys_clone /* 120 */ + .llong .sys_setdomainname + .llong .ppc64_newuname + .llong .sys_modify_ldt + .llong .sys_adjtimex + .llong .sys_mprotect /* 125 */ + .llong .sys_sigprocmask + .llong .sys_create_module + .llong .sys_init_module + .llong .sys_delete_module + .llong .sys_get_kernel_syms /* 130 */ + .llong .sys_quotactl + .llong .sys_getpgid + .llong .sys_fchdir + .llong .sys_bdflush + .llong .sys_sysfs /* 135 */ + .llong .sys_personality + .llong .sys_ni_syscall /* for afs_syscall */ + .llong .sys_setfsuid + .llong .sys_setfsgid + .llong .sys_llseek /* 140 */ + .llong .sys_getdents + .llong .sys_select + .llong .sys_flock + .llong .sys_msync + .llong .sys_readv /* 145 */ + .llong .sys_writev + .llong .sys_getsid + .llong .sys_fdatasync + .llong .sys_sysctl + .llong .sys_mlock /* 150 */ + .llong .sys_munlock + .llong .sys_mlockall + .llong .sys_munlockall + .llong .sys_sched_setparam + .llong .sys_sched_getparam /* 155 */ + .llong .sys_sched_setscheduler + .llong .sys_sched_getscheduler + .llong .sys_sched_yield + .llong .sys_sched_get_priority_max + .llong .sys_sched_get_priority_min /* 160 */ + .llong .sys_sched_rr_get_interval + .llong .sys_nanosleep + .llong .sys_mremap + .llong .sys_setresuid + .llong .sys_getresuid /* 165 */ + .llong .sys_query_module + .llong .sys_poll + .llong .sys_nfsservctl + .llong .sys_setresgid + .llong .sys_getresgid /* 170 */ + .llong .sys_prctl + .llong .ppc64_rt_sigreturn + .llong .sys_rt_sigaction + .llong .sys_rt_sigprocmask + .llong .sys_rt_sigpending /* 175 */ + .llong .sys_rt_sigtimedwait + .llong .sys_rt_sigqueueinfo + .llong .sys_rt_sigsuspend + .llong .sys_pread + .llong .sys_pwrite /* 180 */ + .llong .sys_chown + .llong .sys_getcwd + .llong .sys_capget + .llong .sys_capset + .llong .sys_sigaltstack /* 185 */ + .llong .sys_sendfile + .llong .sys_ni_syscall /* streams1 */ + .llong .sys_ni_syscall /* streams2 */ + .llong .sys_vfork + .llong .sys_getrlimit /* 190 */ + .llong .sys_ni_syscall /* 191 */ /* Unused */ + .llong .sys_ni_syscall /* 192 - reserved - mmap2 */ + .llong .sys_ni_syscall /* 193 - reserved - truncate64 */ + .llong .sys_ni_syscall /* 194 - reserved - ftruncate64 */ + .llong .sys_ni_syscall /* 195 - reserved - stat64 */ + .llong .sys_ni_syscall /* 196 - reserved - lstat64 */ + .llong .sys_ni_syscall /* 197 - reserved - fstat64 */ + .llong .sys_pciconfig_read /* 198 */ + .llong .sys_pciconfig_write /* 199 */ + .llong .sys_pciconfig_iobase /* 200 */ + .llong .sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ + .llong .sys_getdents64 /* 202 */ + .llong .sys_pivot_root /* 203 */ + .llong .sys_ni_syscall /* 204 */ + .llong .sys_madvise /* 205 */ + .llong .sys_mincore /* 206 */ + .rept NR_syscalls-206 + .llong .sys_ni_syscall + .endr diff -urN linux-2.4.18/arch/ppc64/kernel/mk_defs.c linux-2.4.19-pre5/arch/ppc64/kernel/mk_defs.c --- linux-2.4.18/arch/ppc64/kernel/mk_defs.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/mk_defs.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,159 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n#define\t" #sym "\t%0" : : "i" (val)) + +int +main(void) +{ + DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); + DEFINE(THREAD, offsetof(struct task_struct, thread)); + DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); + DEFINE(KSP, offsetof(struct thread_struct, ksp)); + + DEFINE(PACA, offsetof(struct Naca, paca)); + DEFINE(PACA_SIZE, sizeof(struct Paca)); + + DEFINE(DCACHEL1LINESIZE, offsetof(struct Naca, dCacheL1LineSize)); + DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct Naca, dCacheL1LogLineSize)); + DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct Naca, dCacheL1LinesPerPage)); + + DEFINE(ICACHEL1LINESIZE, offsetof(struct Naca, iCacheL1LineSize)); + DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct Naca, iCacheL1LogLineSize)); + DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct Naca, iCacheL1LinesPerPage)); + DEFINE(SLBSIZE, offsetof(struct Naca, slb_size)); + + DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex)); + DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart)); + DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave)); + DEFINE(PACACURRENT, offsetof(struct Paca, xCurrent)); + DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr)); + DEFINE(PACASTABREAL, offsetof(struct Paca, xStab_data.real)); + DEFINE(PACASTABVIRT, offsetof(struct Paca, xStab_data.virt)); + DEFINE(PACASTABRR, offsetof(struct Paca, xStab_data.next_round_robin)); + DEFINE(PACAR1, offsetof(struct Paca, xR1)); + DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr)); + DEFINE(PACATOC, offsetof(struct Paca, xTOC)); + DEFINE(PACAEXCSP, offsetof(struct Paca, exception_sp)); + DEFINE(PACAHRDWINTSTACK, offsetof(struct Paca, xHrdIntStack)); + DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled)); + DEFINE(PACAHRDWINTCOUNT, offsetof(struct Paca, xHrdIntCount)); + DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr)); + DEFINE(PACAPROFENABLED, offsetof(struct Paca, prof_enabled)); + DEFINE(PACAPROFLEN, offsetof(struct Paca, prof_len)); + DEFINE(PACAPROFSHIFT, offsetof(struct Paca, prof_shift)); + DEFINE(PACAPROFBUFFER, offsetof(struct Paca, prof_buffer)); + DEFINE(PACAPROFSTEXT, offsetof(struct Paca, prof_stext)); + DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca)); + DEFINE(LPPACA, offsetof(struct Paca, xLpPaca)); + DEFINE(PACAREGSAV, offsetof(struct Paca, xRegSav)); + DEFINE(PACAEXC, offsetof(struct Paca, exception_stack)); + DEFINE(PACAGUARD, offsetof(struct Paca, guard)); + DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); + DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); + DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); + DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); + DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); + DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); + DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); + DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); + + DEFINE(RTASBASE, offsetof(struct rtas_t, base)); + DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); + DEFINE(RTASSIZE, offsetof(struct rtas_t, size)); + + DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); + DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); + DEFINE(PT_TRACESYS, PT_TRACESYS); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); + DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); + DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); + DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags)); + DEFINE(PPC_FLAG_32BIT, PPC_FLAG_32BIT); + /* Interrupt register frame */ + DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); + DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); + /* 288 = # of volatile regs, int & fp, for leaf routines */ + /* which do not stack a frame. See the PPC64 ABI. */ + DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); + /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ + DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288); + DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288); + DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); + DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); + DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); + DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); + DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); + DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); + DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); + DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); + DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); + DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); + DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); + DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); + DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); + DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); + /* Note: these symbols include _ because they overlap with special + * register names + */ + DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); + DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); + DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); + DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); + DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); + DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); + DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); + DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); + DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); + DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); + DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); + + /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ + DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); + DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); + + DEFINE(CLONE_VM, CLONE_VM); + + return 0; +} diff -urN linux-2.4.18/arch/ppc64/kernel/open_pic.c linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.c --- linux-2.4.18/arch/ppc64/kernel/open_pic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,828 @@ +/* + * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "local_irq.h" +#include "open_pic.h" +#include "open_pic_defs.h" +#include "i8259.h" +#include + +void* OpenPIC_Addr; +static volatile struct OpenPIC *OpenPIC = NULL; +u_int OpenPIC_NumInitSenses __initdata = 0; +u_char *OpenPIC_InitSenses __initdata = NULL; +extern int use_of_interrupt_tree; + +void find_ISUs(void); + +static u_int NumProcessors; +static u_int NumSources; +static int NumISUs; +static int open_pic_irq_offset; +static volatile unsigned char* chrp_int_ack_special; +static int broken_ipi_registers; + +OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU]; + +static void openpic_end_irq(unsigned int irq_nr); +static void openpic_ack_irq(unsigned int irq_nr); +static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask); + +struct hw_interrupt_type open_pic = { + " OpenPIC ", + NULL, + NULL, + openpic_enable_irq, + openpic_disable_irq, + openpic_ack_irq, + openpic_end_irq, + openpic_set_affinity +}; + +#ifdef CONFIG_SMP +static void openpic_end_ipi(unsigned int irq_nr); +static void openpic_ack_ipi(unsigned int irq_nr); +static void openpic_enable_ipi(unsigned int irq_nr); +static void openpic_disable_ipi(unsigned int irq_nr); + +struct hw_interrupt_type open_pic_ipi = { + " OpenPIC ", + NULL, + NULL, + openpic_enable_ipi, + openpic_disable_ipi, + openpic_ack_ipi, + openpic_end_ipi, + 0 +}; +#endif /* CONFIG_SMP */ + +unsigned int openpic_vec_ipi; +unsigned int openpic_vec_timer; +unsigned int openpic_vec_spurious; + +/* + * Accesses to the current processor's openpic registers + */ +#ifdef CONFIG_SMP +#define THIS_CPU Processor[cpu] +#define DECL_THIS_CPU int cpu = hard_smp_processor_id() +#define CHECK_THIS_CPU check_arg_cpu(cpu) +#else +#define THIS_CPU Processor[hard_smp_processor_id()] +#define DECL_THIS_CPU +#define CHECK_THIS_CPU +#endif /* CONFIG_SMP */ + +#if 1 +#define check_arg_ipi(ipi) \ + if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ + printk(KERN_ERR "open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi); +#define check_arg_timer(timer) \ + if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ + printk(KERN_ERR "open_pic.c:%d: illegal timer %d\n", __LINE__, timer); +#define check_arg_vec(vec) \ + if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ + printk(KERN_ERR "open_pic.c:%d: illegal vector %d\n", __LINE__, vec); +#define check_arg_pri(pri) \ + if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ + printk(KERN_ERR "open_pic.c:%d: illegal priority %d\n", __LINE__, pri); +/* + * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's + * data has probably been corrupted and we're going to panic or deadlock later + * anyway --Troy + */ +extern unsigned long* _get_SP(void); +#define check_arg_irq(irq) \ + if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \ + printk(KERN_ERR "open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \ + print_backtrace(_get_SP()); } +#define check_arg_cpu(cpu) \ + if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ \ + printk(KERN_ERR "open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \ + print_backtrace(_get_SP()); } +#else +#define check_arg_ipi(ipi) do {} while (0) +#define check_arg_timer(timer) do {} while (0) +#define check_arg_vec(vec) do {} while (0) +#define check_arg_pri(pri) do {} while (0) +#define check_arg_irq(irq) do {} while (0) +#define check_arg_cpu(cpu) do {} while (0) +#endif + +#define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf] + +void __init openpic_init_IRQ(void) +{ + struct device_node *np; + int i; + unsigned int *addrp; + unsigned char* chrp_int_ack_special = 0; + unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; + int nmi_irq = -1; +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON) + struct device_node *kbd; +#endif + + if (!(np = find_devices("pci")) + || !(addrp = (unsigned int *) + get_property(np, "8259-interrupt-acknowledge", NULL))) + printk(KERN_ERR "Cannot find pci to get ack address\n"); + else + chrp_int_ack_special = (unsigned char *) + __ioremap(addrp[prom_n_addr_cells(np)-1], 1, _PAGE_NO_CACHE); + /* hydra still sets OpenPIC_InitSenses to a static set of values */ + if (OpenPIC_InitSenses == NULL) { + prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); + OpenPIC_InitSenses = init_senses; + OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; + } + openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); + for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) + irq_desc[i].handler = &i8259_pic; + i8259_init(); +} + +static inline u_int openpic_read(volatile u_int *addr) +{ + u_int val; + + val = in_le32(addr); + return val; +} + +static inline void openpic_write(volatile u_int *addr, u_int val) +{ + out_le32(addr, val); +} + +static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) +{ + u_int val = openpic_read(addr); + return val & mask; +} + +static inline void openpic_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + u_int val = openpic_read(addr); + openpic_write(addr, (val & ~mask) | (field & mask)); +} + +static inline void openpic_clearfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, 0); +} + +static inline void openpic_setfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, mask); +} + +static void openpic_safe_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + unsigned int loops = 100000; + + openpic_setfield(addr, OPENPIC_MASK); + while (openpic_read(addr) & OPENPIC_ACTIVITY) { + if (!loops--) { + printk(KERN_ERR "openpic_safe_writefield timeout\n"); + break; + } + } + openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); +} + +#ifdef CONFIG_SMP +static u_int openpic_read_IPI(volatile u_int* addr) +{ + u_int val = 0; + + if (broken_ipi_registers) + /* yes this is right ... bug, feature, you decide! -- tgall */ + val = in_be32(addr); + else + val = in_le32(addr); + + return val; +} + +static void openpic_test_broken_IPI(void) +{ + u_int t; + + openpic_write(&OpenPIC->Global.IPI_Vector_Priority(0), OPENPIC_MASK); + t = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(0)); + if (t == le32_to_cpu(OPENPIC_MASK)) { + printk(KERN_INFO "OpenPIC reversed IPI registers detected\n"); + broken_ipi_registers = 1; + } +} + +/* because of the power3 be / le above, this is needed */ +static inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field) +{ + u_int val = openpic_read_IPI(addr); + openpic_write(addr, (val & ~mask) | (field & mask)); +} + +static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask) +{ + openpic_writefield_IPI(addr, mask, 0); +} + +static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask) +{ + openpic_writefield_IPI(addr, mask, mask); +} + +static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field) +{ + unsigned int loops = 100000; + + openpic_setfield_IPI(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_IPI(addr) & OPENPIC_ACTIVITY) { + if (!loops--) { + printk(KERN_ERR "openpic_safe_writefield timeout\n"); + break; + } + } + + openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK); +} +#endif /* CONFIG_SMP */ + +void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, + int programmer_switch_irq) +{ + u_int t, i; + u_int timerfreq; + const char *version; + + if (!OpenPIC_Addr) { + printk(KERN_INFO "No OpenPIC found !\n"); + return; + } + OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr; + + ppc_md.progress("openpic enter",0x122); + + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + switch (t & OPENPIC_FEATURE_VERSION_MASK) { + case 1: + version = "1.0"; + break; + case 2: + version = "1.2"; + break; + case 3: + version = "1.3"; + break; + default: + version = "?"; + break; + } + NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> + OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; + NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + printk(KERN_INFO "OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", + version, NumProcessors, NumSources, OpenPIC); + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); + if (timerfreq) + printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n", + timerfreq / 1000000, timerfreq % 1000000); + + if (!main_pic) + return; + + open_pic_irq_offset = offset; + chrp_int_ack_special = (volatile unsigned char*)chrp_ack; + + find_ISUs(); + + /* Initialize timer interrupts */ + ppc_md.progress("openpic timer",0x3ba); + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, openpic_vec_timer+i); + /* No processor */ + openpic_maptimer(i, 0); + } + +#ifdef CONFIG_SMP + /* Initialize IPI interrupts */ + ppc_md.progress("openpic ipi",0x3bb); + openpic_test_broken_IPI(); + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 10..13 */ + openpic_initipi(i, 10+i, openpic_vec_ipi+i); + /* IPIs are per-CPU */ + irq_desc[openpic_vec_ipi+i].status |= IRQ_PER_CPU; + irq_desc[openpic_vec_ipi+i].handler = &open_pic_ipi; + } +#endif + + /* Initialize external interrupts */ + ppc_md.progress("openpic ext",0x3bc); + + openpic_set_priority(0xf); + + /* SIOint (8259 cascade) is special */ + if (offset) { + openpic_initirq(0, 8, offset, 1, 1); + openpic_mapirq(0, 1<= OPENPIC_MAX_ISU) + return; + ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE); + if (isu_num >= NumISUs) + NumISUs = isu_num + 1; +} + +void find_ISUs(void) +{ + /* Use /interrupt-controller/reg and + * /interrupt-controller/interrupt-ranges from OF device tree + * the ISU array is setup in chrp_pci.c in ibm_add_bridges + * as a result + * -- tgall + */ + + /* basically each ISU is a bus, and this assumes that + * open_pic_isu_count interrupts per bus are possible + * ISU == Interrupt Source + */ + NumSources = NumISUs * 0x10; + openpic_vec_ipi = NumSources + open_pic_irq_offset; + openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI; + openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS; +} + +static inline void openpic_reset(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET); +} + +static inline void openpic_enable_8259_pass_through(void) +{ + openpic_clearfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +static void openpic_disable_8259_pass_through(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +/* + * Find out the current interrupt + */ +static u_int openpic_irq(void) +{ + u_int vec; + DECL_THIS_CPU; + + CHECK_THIS_CPU; + vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, + OPENPIC_VECTOR_MASK); + return vec; +} + +static void openpic_eoi(void) +{ + DECL_THIS_CPU; + + CHECK_THIS_CPU; + openpic_write(&OpenPIC->THIS_CPU.EOI, 0); + /* Handle PCI write posting */ + (void)openpic_read(&OpenPIC->THIS_CPU.EOI); +} + + +static inline u_int openpic_get_priority(void) +{ + DECL_THIS_CPU; + + CHECK_THIS_CPU; + return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK); +} + +static void openpic_set_priority(u_int pri) +{ + DECL_THIS_CPU; + + CHECK_THIS_CPU; + check_arg_pri(pri); + openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); +} + +/* + * Get/set the spurious vector + */ +static inline u_int openpic_get_spurious(void) +{ + return openpic_readfield(&OpenPIC->Global.Spurious_Vector, + OPENPIC_VECTOR_MASK); +} + +static void openpic_set_spurious(u_int vec) +{ + check_arg_vec(vec); + openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, + vec); +} + +/* + * Convert a cpu mask from logical to physical cpu numbers. + */ +static inline u32 physmask(u32 cpumask) +{ + int i; + u32 mask = 0; + + for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1) + mask |= (cpumask & 1) << get_hard_smp_processor_id(i); + return mask; +} + +void openpic_init_processor(u_int cpumask) +{ + openpic_write(&OpenPIC->Global.Processor_Initialization, + physmask(cpumask)); +} + +#ifdef CONFIG_SMP +/* + * Initialize an interprocessor interrupt (and disable it) + * + * ipi: OpenPIC interprocessor interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + */ +static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec) +{ + check_arg_ipi(ipi); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi), + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Send an IPI to one or more CPUs + * + * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI) + * and not a system-wide interrupt number + */ +void openpic_cause_IPI(u_int ipi, u_int cpumask) +{ + DECL_THIS_CPU; + + CHECK_THIS_CPU; + check_arg_ipi(ipi); + openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), + physmask(cpumask)); +} + +void openpic_request_IPIs(void) +{ + int i; + + /* + * Make sure this matches what is defined in smp.c for + * smp_message_{pass|recv}() or what shows up in + * /proc/interrupts will be wrong!!! --Troy */ + + if (OpenPIC == NULL) + return; + + request_irq(openpic_vec_ipi, + openpic_ipi_action, 0, "IPI0 (call function)", 0); + request_irq(openpic_vec_ipi+1, + openpic_ipi_action, 0, "IPI1 (reschedule)", 0); + request_irq(openpic_vec_ipi+2, + openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0); + request_irq(openpic_vec_ipi+3, + openpic_ipi_action, 0, "IPI3 (xmon break)", 0); + + for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) + openpic_enable_ipi(openpic_vec_ipi+i); +} + +/* + * Do per-cpu setup for SMP systems. + * + * Get IPI's working and start taking interrupts. + * -- Cort + */ +static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED; + +void __init do_openpic_setup_cpu(void) +{ +#ifdef CONFIG_IRQ_ALL_CPUS + int i; + u32 msk = 1 << hard_smp_processor_id(); +#endif + + spin_lock(&openpic_setup_lock); + +#ifdef CONFIG_IRQ_ALL_CPUS + /* let the openpic know we want intrs. default affinity + * is 0xffffffff until changed via /proc + * That's how it's done on x86. If we want it differently, then + * we should make sure we also change the default values of irq_affinity + * in irq.c. + */ + for (i = 0; i < NumSources ; i++) + openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk); +#endif /* CONFIG_IRQ_ALL_CPUS */ + openpic_set_priority(0); + + spin_unlock(&openpic_setup_lock); +} +#endif /* CONFIG_SMP */ + +/* + * Initialize a timer interrupt (and disable it) + * + * timer: OpenPIC timer number + * pri: interrupt source priority + * vec: the vector it will produce + */ +static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec) +{ + check_arg_timer(timer); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Map a timer interrupt to one or more CPUs + */ +static void __init openpic_maptimer(u_int timer, u_int cpumask) +{ + check_arg_timer(timer); + openpic_write(&OpenPIC->Global.Timer[timer].Destination, + physmask(cpumask)); +} + + +/* + * + * All functions below take an offset'ed irq argument + * + */ + + +/* + * Enable/disable an external interrupt source + * + * Externally called, irq is an offseted system-wide interrupt number + */ +static void openpic_enable_irq(u_int irq) +{ + unsigned int loops = 100000; + check_arg_irq(irq); + + openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); + /* make sure mask gets to controller before we return to user */ + do { + if (!loops--) { + printk(KERN_ERR "openpic_enable_irq timeout\n"); + break; + } + + mb(); /* sync is probably useless here */ + } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, + OPENPIC_MASK)); +} + +static void openpic_disable_irq(u_int irq) +{ + u32 vp; + unsigned int loops = 100000; + + check_arg_irq(irq); + + openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); + /* make sure mask gets to controller before we return to user */ + do { + if (!loops--) { + printk(KERN_ERR "openpic_disable_irq timeout\n"); + break; + } + + mb(); /* sync is probably useless here */ + vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, + OPENPIC_MASK | OPENPIC_ACTIVITY); + } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); +} + +#ifdef CONFIG_SMP +/* + * Enable/disable an IPI interrupt source + * + * Externally called, irq is an offseted system-wide interrupt number + */ +void openpic_enable_ipi(u_int irq) +{ + irq -= openpic_vec_ipi; + check_arg_ipi(irq); + openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); + +} +void openpic_disable_ipi(u_int irq) +{ + /* NEVER disable an IPI... that's just plain wrong! */ +} + +#endif + +/* + * Initialize an interrupt source (and disable it!) + * + * irq: OpenPIC interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + * pol: polarity (1 for positive, 0 for negative) + * sense: 1 for level, 0 for edge + */ +static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) +{ + openpic_safe_writefield(&GET_ISU(irq).Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | + OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec | + (pol ? OPENPIC_POLARITY_POSITIVE : + OPENPIC_POLARITY_NEGATIVE) | + (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); +} + +/* + * Map an interrupt source to one or more CPUs + */ +static void openpic_mapirq(u_int irq, u_int physmask) +{ + openpic_write(&GET_ISU(irq).Destination, physmask); +} + +/* + * Set the sense for an interrupt source (and disable it!) + * + * sense: 1 for level, 0 for edge + */ +static inline void openpic_set_sense(u_int irq, int sense) +{ + openpic_safe_writefield(&GET_ISU(irq).Vector_Priority, + OPENPIC_SENSE_LEVEL, + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} + +/* No spinlocks, should not be necessary with the OpenPIC + * (1 register = 1 interrupt and we have the desc lock). + */ +static void openpic_ack_irq(unsigned int irq_nr) +{ +} + +static void openpic_end_irq(unsigned int irq_nr) +{ + if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0) + openpic_eoi(); +} + +static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask) +{ + openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask)); +} + +#ifdef CONFIG_SMP +static void openpic_ack_ipi(unsigned int irq_nr) +{ +} + +static void openpic_end_ipi(unsigned int irq_nr) +{ + /* IPIs are marked IRQ_PER_CPU. This has the side effect of + * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from + * applying to them. We EOI them late to avoid re-entering. + * however, I'm wondering if we could simply let them have the + * SA_INTERRUPT flag and let them execute with all interrupts OFF. + * This would have the side effect of either running cross-CPU + * functions with interrupts off, or we can re-enable them explicitely + * with a __sti() in smp_call_function_interrupt(), since + * smp_call_function() is protected by a spinlock. + * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU + * function calls IPI at all but that would make a special case. + */ + openpic_eoi(); +} + +static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + smp_message_recv(cpl-openpic_vec_ipi, regs); +} + +#endif /* CONFIG_SMP */ + +int openpic_get_irq(struct pt_regs *regs) +{ + extern int i8259_irq(int cpu); + + int irq = openpic_irq(); + + /* Management of the cascade should be moved out of here */ + if (open_pic_irq_offset && irq == open_pic_irq_offset) + { + /* + * This magic address generates a PCI IACK cycle. + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; + else + irq = i8259_irq( smp_processor_id() ); + openpic_eoi(); + } + if (irq == openpic_vec_spurious) + irq = -1; + return irq; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/open_pic.h linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.h --- linux-2.4.18/arch/ppc64/kernel/open_pic.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,45 @@ +/* + * arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + +#ifndef _PPC64_KERNEL_OPEN_PIC_H +#define _PPC64_KERNEL_OPEN_PIC_H + +#include + +#define OPENPIC_SIZE 0x40000 + +/* OpenPIC IRQ controller structure */ +extern struct hw_interrupt_type open_pic; + +/* OpenPIC IPI controller structure */ +#ifdef CONFIG_SMP +extern struct hw_interrupt_type open_pic_ipi; +#endif /* CONFIG_SMP */ + +extern u_int OpenPIC_NumInitSenses; +extern u_char *OpenPIC_InitSenses; +extern void* OpenPIC_Addr; + +/* Exported functions */ +extern void openpic_init(int, int, unsigned char *, int); +extern void openpic_request_IPIs(void); +extern void do_openpic_setup_cpu(void); +extern int openpic_get_irq(struct pt_regs *regs); +extern void openpic_init_processor(u_int cpumask); +extern void openpic_setup_ISU(int isu_num, unsigned long addr); +extern void openpic_cause_IPI(u_int ipi, u_int cpumask); + +extern inline int openpic_to_irq(int irq) +{ + return irq += NUM_8259_INTERRUPTS; +} +/*extern int open_pic_irq_offset;*/ +#endif /* _PPC64_KERNEL_OPEN_PIC_H */ diff -urN linux-2.4.18/arch/ppc64/kernel/open_pic_defs.h linux-2.4.19-pre5/arch/ppc64/kernel/open_pic_defs.h --- linux-2.4.18/arch/ppc64/kernel/open_pic_defs.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic_defs.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,318 @@ +/* + * linux/openpic.h -- OpenPIC definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * The Open Programmable Interrupt Controller (PIC) + * Register Interface Specification Revision 1.2 + * + * Issue Date: October 1995 + * + * Issued jointly by Advanced Micro Devices and Cyrix Corporation + * + * AMD is a registered trademark of Advanced Micro Devices, Inc. + * Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc. + * All Rights Reserved. + * + * To receive a copy of this documentation, send an email to openpic@amd.com. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _LINUX_OPENPIC_H +#define _LINUX_OPENPIC_H + +#ifdef __KERNEL__ + +#include + +/* + * OpenPIC supports up to 2048 interrupt sources and up to 32 processors + */ + +#define OPENPIC_MAX_SOURCES 2048 +#define OPENPIC_MAX_PROCESSORS 32 +#define OPENPIC_MAX_ISU 32 + +#define OPENPIC_NUM_TIMERS 4 +#define OPENPIC_NUM_IPI 4 +#define OPENPIC_NUM_PRI 16 +#define OPENPIC_NUM_VECTORS OPENPIC_MAX_SOURCES + +/* + * OpenPIC Registers are 32 bits and aligned on 128 bit boundaries + */ + +typedef struct _OpenPIC_Reg { + u_int Reg; /* Little endian! */ + char Pad[0xc]; +} OpenPIC_Reg; + + +/* + * Per Processor Registers + */ + +typedef struct _OpenPIC_Processor { + /* + * Private Shadow Registers (for SLiC backwards compatibility) + */ + u_int IPI0_Dispatch_Shadow; /* Write Only */ + char Pad1[0x4]; + u_int IPI0_Vector_Priority_Shadow; /* Read/Write */ + char Pad2[0x34]; + /* + * Interprocessor Interrupt Command Ports + */ + OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */ + /* + * Current Task Priority Register + */ + OpenPIC_Reg _Current_Task_Priority; /* Read/Write */ + char Pad3[0x10]; + /* + * Interrupt Acknowledge Register + */ + OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */ + /* + * End of Interrupt (EOI) Register + */ + OpenPIC_Reg _EOI; /* Read/Write */ + char Pad5[0xf40]; +} OpenPIC_Processor; + + + /* + * Timer Registers + */ + +typedef struct _OpenPIC_Timer { + OpenPIC_Reg _Current_Count; /* Read Only */ + OpenPIC_Reg _Base_Count; /* Read/Write */ + OpenPIC_Reg _Vector_Priority; /* Read/Write */ + OpenPIC_Reg _Destination; /* Read/Write */ +} OpenPIC_Timer; + + + /* + * Global Registers + */ + +typedef struct _OpenPIC_Global { + /* + * Feature Reporting Registers + */ + OpenPIC_Reg _Feature_Reporting0; /* Read Only */ + OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */ + /* + * Global Configuration Registers + */ + OpenPIC_Reg _Global_Configuration0; /* Read/Write */ + OpenPIC_Reg _Global_Configuration1; /* Future Expansion */ + /* + * Vendor Specific Registers + */ + OpenPIC_Reg _Vendor_Specific[4]; + /* + * Vendor Identification Register + */ + OpenPIC_Reg _Vendor_Identification; /* Read Only */ + /* + * Processor Initialization Register + */ + OpenPIC_Reg _Processor_Initialization; /* Read/Write */ + /* + * IPI Vector/Priority Registers + */ + OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */ + /* + * Spurious Vector Register + */ + OpenPIC_Reg _Spurious_Vector; /* Read/Write */ + /* + * Global Timer Registers + */ + OpenPIC_Reg _Timer_Frequency; /* Read/Write */ + OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS]; + char Pad1[0xee00]; +} OpenPIC_Global; + + + /* + * Interrupt Source Registers + */ + +typedef struct _OpenPIC_Source { + OpenPIC_Reg _Vector_Priority; /* Read/Write */ + OpenPIC_Reg _Destination; /* Read/Write */ +} OpenPIC_Source, *OpenPIC_SourcePtr; + + + /* + * OpenPIC Register Map + */ + +struct OpenPIC { + char Pad1[0x1000]; + /* + * Global Registers + */ + OpenPIC_Global Global; + /* + * Interrupt Source Configuration Registers + */ + OpenPIC_Source Source[OPENPIC_MAX_SOURCES]; + /* + * Per Processor Registers + */ + OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS]; +}; + +extern volatile struct OpenPIC *OpenPIC; + + +/* + * Current Task Priority Register + */ + +#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f + +/* + * Who Am I Register + */ + +#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f + +/* + * Feature Reporting Register 0 + */ + +#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000 +#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16 +#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00 +#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8 +#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff + +/* + * Global Configuration Register 0 + */ + +#define OPENPIC_CONFIG_RESET 0x80000000 +#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000 +#define OPENPIC_CONFIG_BASE_MASK 0x000fffff + +/* + * Vendor Identification Register + */ + +#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000 +#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16 +#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00 +#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8 +#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff + +/* + * Vector/Priority Registers + */ + +#define OPENPIC_MASK 0x80000000 +#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */ +#define OPENPIC_PRIORITY_MASK 0x000f0000 +#define OPENPIC_PRIORITY_SHIFT 16 +#define OPENPIC_VECTOR_MASK 0x000007ff + + +/* + * Interrupt Source Registers + */ + +#define OPENPIC_POLARITY_POSITIVE 0x00800000 +#define OPENPIC_POLARITY_NEGATIVE 0x00000000 +#define OPENPIC_POLARITY_MASK 0x00800000 +#define OPENPIC_SENSE_LEVEL 0x00400000 +#define OPENPIC_SENSE_EDGE 0x00000000 +#define OPENPIC_SENSE_MASK 0x00400000 + + +/* + * Timer Registers + */ + +#define OPENPIC_COUNT_MASK 0x7fffffff +#define OPENPIC_TIMER_TOGGLE 0x80000000 +#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000 + + +/* + * Aliases to make life simpler + */ + +/* Per Processor Registers */ +#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg +#define Current_Task_Priority _Current_Task_Priority.Reg +#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg +#define EOI _EOI.Reg + +/* Global Registers */ +#define Feature_Reporting0 _Feature_Reporting0.Reg +#define Feature_Reporting1 _Feature_Reporting1.Reg +#define Global_Configuration0 _Global_Configuration0.Reg +#define Global_Configuration1 _Global_Configuration1.Reg +#define Vendor_Specific(i) _Vendor_Specific[i].Reg +#define Vendor_Identification _Vendor_Identification.Reg +#define Processor_Initialization _Processor_Initialization.Reg +#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg +#define Spurious_Vector _Spurious_Vector.Reg +#define Timer_Frequency _Timer_Frequency.Reg + +/* Timer Registers */ +#define Current_Count _Current_Count.Reg +#define Base_Count _Base_Count.Reg +#define Vector_Priority _Vector_Priority.Reg +#define Destination _Destination.Reg + +/* Interrupt Source Registers */ +#define Vector_Priority _Vector_Priority.Reg +#define Destination _Destination.Reg + +/* + * Local (static) OpenPIC Operations + */ + + +/* Global Operations */ +static void openpic_reset(void); +static void openpic_enable_8259_pass_through(void); +static void openpic_disable_8259_pass_through(void); +static u_int openpic_irq(void); +static void openpic_eoi(void); +static u_int openpic_get_priority(void); +static void openpic_set_priority(u_int pri); +static u_int openpic_get_spurious(void); +static void openpic_set_spurious(u_int vector); + +#ifdef CONFIG_SMP +/* Interprocessor Interrupts */ +static void openpic_initipi(u_int ipi, u_int pri, u_int vector); +static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); +#endif + +/* Timer Interrupts */ +static void openpic_inittimer(u_int timer, u_int pri, u_int vector); +static void openpic_maptimer(u_int timer, u_int cpumask); + +/* Interrupt Sources */ +static void openpic_enable_irq(u_int irq); +static void openpic_disable_irq(u_int irq); +static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, + int is_level); +static void openpic_mapirq(u_int irq, u_int cpumask); +static void openpic_set_sense(u_int irq, int sense); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_OPENPIC_H */ diff -urN linux-2.4.18/arch/ppc64/kernel/pSeries_hvCall.S linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_hvCall.S --- linux-2.4.18/arch/ppc64/kernel/pSeries_hvCall.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_hvCall.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,70 @@ +/* + * arch/ppc64/kernel/pSeries_hvCall.S + * + * + * This file contains the generic code to perform a call to the + * pSeries LPAR hypervisor. + * NOTE: this file will go away when we move to inline this work. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include "ppc_asm.h" + +/* + * hcall interface to pSeries LPAR + */ +#define HSC .long 0x44000022 + +/* long plpar_hcall(unsigned long opcode, R3 + unsigned long arg1, R4 + unsigned long arg2, R5 + unsigned long arg3, R6 + unsigned long arg4, R7 + unsigned long *out1, R8 + unsigned long *out2, R9 + unsigned long *out3); R10 + */ + + .text +_GLOBAL(plpar_hcall) + mfcr r0 + std r0,-8(r1) + stdu r1,-32(r1) + + std r8,-8(r1) /* Save out ptrs. */ + std r9,-16(r1) + std r10,-24(r1) + + HSC /* invoke the hypervisor */ + + ld r10,-8(r1) /* Fetch r4-r7 ret args. */ + std r4,0(r10) + ld r10,-16(r1) + std r5,0(r10) + ld r10,-24(r1) + std r6,0(r10) + + ld r1,0(r1) + ld r0,-8(r1) + mtcrf 0xff,r0 + blr /* return r3 = status */ + + +/* Simple interface with no output values (other than status) */ +_GLOBAL(plpar_hcall_norets) + mfcr r0 + std r0,-8(r1) + HSC /* invoke the hypervisor */ + ld r0,-8(r1) + mtcrf 0xff,r0 + blr /* return r3 = status */ diff -urN linux-2.4.18/arch/ppc64/kernel/pSeries_lpar.c linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_lpar.c --- linux-2.4.18/arch/ppc64/kernel/pSeries_lpar.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_lpar.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,905 @@ +/* + * pSeries_lpar.c + * Copyright (C) 2001 Todd Inglett, IBM Corporation + * + * pSeries LPAR support. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Status return values */ +#define H_Success 0 +#define H_Busy 1 /* Hardware busy -- retry later */ +#define H_Hardware -1 /* Hardware error */ +#define H_Function -2 /* Function not supported */ +#define H_Privilege -3 /* Caller not privileged */ +#define H_Parameter -4 /* Parameter invalid, out-of-range or conflicting */ +#define H_Bad_Mode -5 /* Illegal msr value */ +#define H_PTEG_Full -6 /* PTEG is full */ +#define H_Not_Found -7 /* PTE was not found" */ +#define H_Reserved_DABR -8 /* DABR address is reserved by the hypervisor on this processor" */ + +/* Flags */ +#define H_LARGE_PAGE (1UL<<(63-16)) +#define H_EXACT (1UL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */ +#define H_R_XLATE (1UL<<(63-25)) /* include a valid logical page num in the pte if the valid bit is set */ +#define H_READ_4 (1UL<<(63-26)) /* Return 4 PTEs */ +#define H_AVPN (1UL<<(63-32)) /* An avpn is provided as a sanity test */ +#define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ +#define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ +#define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ +#define H_COPY_PAGE (1UL<<(63-49)) +#define H_N (1UL<<(63-61)) +#define H_PP1 (1UL<<(63-62)) +#define H_PP2 (1UL<<(63-63)) + + + +/* pSeries hypervisor opcodes */ +#define H_REMOVE 0x04 +#define H_ENTER 0x08 +#define H_READ 0x0c +#define H_CLEAR_MOD 0x10 +#define H_CLEAR_REF 0x14 +#define H_PROTECT 0x18 +#define H_GET_TCE 0x1c +#define H_PUT_TCE 0x20 +#define H_SET_SPRG0 0x24 +#define H_SET_DABR 0x28 +#define H_PAGE_INIT 0x2c +#define H_SET_ASR 0x30 +#define H_ASR_ON 0x34 +#define H_ASR_OFF 0x38 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_LOGICAL_CACHE_LOAD 0x44 +#define H_LOGICAL_CACHE_STORE 0x48 +#define H_LOGICAL_ICBI 0x4c +#define H_LOGICAL_DCBF 0x50 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REAL_TO_LOGICAL 0x5c +#define H_HYPERVISOR_DATA 0x60 +#define H_EOI 0x64 +#define H_CPPR 0x68 +#define H_IPI 0x6c +#define H_IPOLL 0x70 +#define H_XIRR 0x74 + +#define HSC ".long 0x44000022\n" +#define H_ENTER_r3 "li 3, 0x08\n" + +/* plpar_hcall() -- Generic call interface using above opcodes + * + * The actual call interface is a hypervisor call instruction with + * the opcode in R3 and input args in R4-R7. + * Status is returned in R3 with variable output values in R4-R11. + * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now + * and return only two out args which MUST ALWAYS BE PROVIDED. + */ +long plpar_hcall(unsigned long opcode, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long *out1, + unsigned long *out2, + unsigned long *out3); + +/* Same as plpar_hcall but for those opcodes that return no values + * other than status. Slightly more efficient. + */ +long plpar_hcall_norets(unsigned long opcode, ...); + + +long plpar_pte_enter(unsigned long flags, + unsigned long ptex, + unsigned long new_pteh, unsigned long new_ptel, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + unsigned long dummy, ret; + ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel, + old_pteh_ret, old_ptel_ret, &dummy); + return(ret); +} + +long plpar_pte_remove(unsigned long flags, + unsigned long ptex, + unsigned long avpn, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + unsigned long dummy; + return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, + old_pteh_ret, old_ptel_ret, &dummy); +} + +long plpar_pte_read(unsigned long flags, + unsigned long ptex, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + unsigned long dummy; + return plpar_hcall(H_READ, flags, ptex, 0, 0, + old_pteh_ret, old_ptel_ret, &dummy); +} + +long plpar_pte_protect(unsigned long flags, + unsigned long ptex, + unsigned long avpn) +{ + return plpar_hcall_norets(H_PROTECT, flags, ptex); +} + +long plpar_tce_get(unsigned long liobn, + unsigned long ioba, + unsigned long *tce_ret) +{ + unsigned long dummy; + return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0, + tce_ret, &dummy, &dummy); +} + + +long plpar_tce_put(unsigned long liobn, + unsigned long ioba, + unsigned long tceval) +{ + return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); +} + +long plpar_get_term_char(unsigned long termno, + unsigned long *len_ret, + char *buf_ret) +{ + unsigned long *lbuf = (unsigned long *)buf_ret; /* ToDo: alignment? */ + return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, + len_ret, lbuf+0, lbuf+1); +} + +long plpar_put_term_char(unsigned long termno, + unsigned long len, + const char *buffer) +{ + unsigned long dummy; + unsigned long *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */ + return plpar_hcall(H_PUT_TERM_CHAR, termno, len, + lbuf[0], lbuf[1], &dummy, &dummy, &dummy); +} + +long plpar_eoi(unsigned long xirr) +{ + return plpar_hcall_norets(H_EOI, xirr); +} + +long plpar_cppr(unsigned long cppr) +{ + return plpar_hcall_norets(H_CPPR, cppr); +} + +long plpar_ipi(unsigned long servernum, + unsigned long mfrr) +{ + return plpar_hcall_norets(H_IPI, servernum, mfrr); +} + +long plpar_xirr(unsigned long *xirr_ret) +{ + unsigned long dummy; + return plpar_hcall(H_XIRR, 0, 0, 0, 0, + xirr_ret, &dummy, &dummy); +} + +long plpar_ipoll(unsigned long servernum, unsigned long* xirr_ret, unsigned long* mfrr_ret) +{ + unsigned long dummy; + return plpar_hcall(H_IPOLL, servernum, 0, 0, 0, + xirr_ret, mfrr_ret, &dummy); +} + +/* + * The following section contains code that ultimately should + * be put in the relavent file (htab.c, xics.c, etc). It has + * been put here for the time being in order to ease maintainence + * of the pSeries LPAR code until it can all be put into CVS. + */ +static void hpte_invalidate_pSeriesLP(unsigned long slot) +{ + HPTE old_pte; + unsigned long lpar_rc; + unsigned long flags = 0; + + lpar_rc = plpar_pte_remove(flags, + slot, + 0, + &old_pte.dw0.dword0, + &old_pte.dw1.dword1); + if (lpar_rc != H_Success) BUG(); +} + +/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and + * the low 3 bits of flags happen to line up. So no transform is needed. + * We can probably optimize here and assume the high bits of newpp are + * already zero. For now I am paranoid. + */ +static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va) +{ + unsigned long lpar_rc; + unsigned long flags; + flags = newpp & 3; + lpar_rc = plpar_pte_protect( flags, + slot, + 0); + if (lpar_rc != H_Success) { + udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); + for (;;); + } +} + +static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea) +{ + unsigned long lpar_rc; + unsigned long vsid,va,vpn,flags; + long slot; + + vsid = get_kernel_vsid( ea ); + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + vpn = va >> PAGE_SHIFT; + + slot = ppc_md.hpte_find( vpn ); + flags = newpp & 3; + lpar_rc = plpar_pte_protect( flags, + slot, + 0); + if (lpar_rc != H_Success) { + udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); + for (;;); + } +} + + +static unsigned long hpte_getword0_pSeriesLP(unsigned long slot) +{ + unsigned long dword0; + unsigned long lpar_rc; + unsigned long dummy_word1; + unsigned long flags; + /* Read 1 pte at a time */ + /* Do not need RPN to logical page translation */ + /* No cross CEC PFT access */ + flags = 0; + + lpar_rc = plpar_pte_read(flags, + slot, + &dword0, &dummy_word1); + if (lpar_rc != H_Success) { + udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc); + for (;;); + } + + return(dword0); +} + +static long hpte_selectslot_pSeriesLP(unsigned long vpn) +{ + unsigned long primary_hash; + unsigned long hpteg_slot; + unsigned i, k; + unsigned long flags; + HPTE pte_read; + unsigned long lpar_rc; + + /* Search the primary group for an available slot */ + primary_hash = hpt_hash(vpn, 0); + + hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + + /* Read 1 pte at a time */ + /* Do not need RPN to logical page translation */ + /* No cross CEC PFT access */ + flags = 0; + for (i=0; i> 11; + unsigned long arpn = physRpn_to_absRpn( prpn ); + + unsigned long lpar_rc; + unsigned long flags; + HPTE ret_hpte; + + /* Fill in the local HPTE with absolute rpn, avpn and flags */ + lhpte.dw1.d = 0; + lhpte.dw1.h.rpn = arpn; + lhpte.dw1.f.flags = hpteflags; + + lhpte.dw0.d = 0; + lhpte.dw0.h.avpn = avpn; + lhpte.dw0.h.h = hash; + lhpte.dw0.h.bolted = bolted; + lhpte.dw0.h.v = 1; + + /* Now fill in the actual HPTE */ + /* Set CEC cookie to 0 */ + /* Large page = 0 */ + /* Zero page = 0 */ + /* I-cache Invalidate = 0 */ + /* I-cache synchronize = 0 */ + /* Exact = 1 - only modify exact entry */ + flags = H_EXACT; + + if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + lhpte.dw1.f.flags &= ~_PAGE_COHERENT; +#if 1 + __asm__ __volatile__ ( + H_ENTER_r3 + "mr 4, %1\n" + "mr 5, %2\n" + "mr 6, %3\n" + "mr 7, %4\n" + HSC + "mr %0, 3\n" + : "=r" (lpar_rc) + : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d) + : "r3", "r4", "r5", "r6", "r7", "cc"); +#else + lpar_rc = plpar_pte_enter(flags, + slot, + lhpte.dw0.d, + lhpte.dw1.d, + &ret_hpte.dw0.dword0, + &ret_hpte.dw1.dword1); +#endif + if (lpar_rc != H_Success) { + udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc); + udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d); + /* xmon_backtrace("backtrace"); */ + for (;;); + } +} + +static long hpte_find_pSeriesLP(unsigned long vpn) +{ + union { + unsigned long d; + Hpte_dword0 h; + } hpte_dw0; + long slot; + unsigned long hash; + unsigned long i,j; + + hash = hpt_hash(vpn, 0); + for ( j=0; j<2; ++j ) { + slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; + for ( i=0; i> 11 ) ) && + ( hpte_dw0.h.v ) && + ( hpte_dw0.h.h == j ) ) { + /* HPTE matches */ + if ( j ) + slot = -slot; + return slot; + } + ++slot; + } + hash = ~hash; + } + return -1; +} + +/* + * Create a pte - LPAR . Used during initialization only. + * We assume the PTE will fit in the primary PTEG. + */ +void make_pte_LPAR(HPTE *htab, + unsigned long va, unsigned long pa, int mode, + unsigned long hash_mask, int large) +{ + HPTE local_hpte, ret_hpte; + unsigned long hash, slot, flags,lpar_rc, vpn; + + if (large) + vpn = va >> 24; + else + vpn = va >> 12; + + hash = hpt_hash(vpn, large); + + slot = ((hash & hash_mask)*HPTES_PER_GROUP); + + local_hpte.dw1.dword1 = pa | mode; + local_hpte.dw0.dword0 = 0; + local_hpte.dw0.dw0.avpn = va >> 23; + local_hpte.dw0.dw0.bolted = 1; /* bolted */ + if (large) + local_hpte.dw0.dw0.l = 1; /* large page */ + local_hpte.dw0.dw0.v = 1; + + /* Set CEC cookie to 0 */ + /* Zero page = 0 */ + /* I-cache Invalidate = 0 */ + /* I-cache synchronize = 0 */ + /* Exact = 0 - modify any entry in group */ + flags = 0; +#if 1 + __asm__ __volatile__ ( + H_ENTER_r3 + "mr 4, %1\n" + "mr 5, %2\n" + "mr 6, %3\n" + "mr 7, %4\n" + HSC + "mr %0, 3\n" + : "=r" (lpar_rc) + : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1) + : "r3", "r4", "r5", "r6", "r7", "cc"); +#else + lpar_rc = plpar_pte_enter(flags, + slot, + local_hpte.dw0.dword0, + local_hpte.dw1.dword1, + &ret_hpte.dw0.dword0, + &ret_hpte.dw1.dword1); +#endif +#if 0 /* NOTE: we explicitly do not check return status here because it is + * "normal" for early boot code to map io regions for which a partition + * has no access. However, we will die if we actually fault on these + * "permission denied" pages. + */ + if (lpar_rc != H_Success) { + /* pSeriesLP_init_early(); */ + udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc); + BUG(); + } +#endif +} + +static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, + unsigned long uaddr, int direction ) +{ + u64 setTceRc; + union Tce tce; + + PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", + tcenum, tbl, tbl->index); + + tce.wholeTce = 0; + tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT; + + tce.tceBits.readWrite = 1; + if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1; + + setTceRc = plpar_tce_put((u64)tbl->index, + (u64)tcenum << 12, + tce.wholeTce ); + /* Make sure the update is visible to hardware. + * ToDo: sync after setting *all* the tce's. + */ + __asm__ __volatile__ ("sync" : : : "memory"); + + if(setTceRc) { + PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc); + PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", (u64)tcenum); + PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce ); + } +} + +static inline void free_tce_range(struct TceTable *tbl, + long tcenum, unsigned order ) +{ + unsigned long flags; + + /* Lock the tce allocation bitmap */ + spin_lock_irqsave( &(tbl->lock), flags ); + + /* Do the actual work */ + free_tce_range_nolock( tbl, tcenum, order ); + + /* Unlock the tce allocation bitmap */ + spin_unlock_irqrestore( &(tbl->lock), flags ); + +} + +static void tce_free_pSeriesLP(struct TceTable *tbl, dma_addr_t dma_addr, + unsigned order, unsigned numPages) +{ + u64 setTceRc; + long tcenum, freeTce, maxTcenum; + unsigned i; + union Tce tce; + + maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1; + + tcenum = dma_addr >> PAGE_SHIFT; + + freeTce = tcenum - tbl->startOffset; + + if ( freeTce > maxTcenum ) { + printk("free_tces: tcenum > maxTcenum\n"); + printk("\ttcenum = 0x%lx\n", tcenum); + printk("\tfreeTce = 0x%lx\n", freeTce); + printk("\tmaxTcenum = 0x%lx\n", maxTcenum); + printk("\tTCE Table = 0x%lx\n", (u64)tbl); + printk("\tbus# = 0x%lx\n", + (u64)tbl->busNumber ); + printk("\tsize = 0x%lx\n", (u64)tbl->size); + printk("\tstartOff = 0x%lx\n", + (u64)tbl->startOffset ); + printk("\tindex = 0x%lx\n", (u64)tbl->index); + return; + } + + for (i=0; iindex, + (u64)tcenum << 12, /* note: not freeTce */ + tce.wholeTce ); + if ( setTceRc ) { + printk("tce_free: setTce failed\n"); + printk("\trc = %ld\n", setTceRc); + printk("\tindex = 0x%lx\n", + (u64)tbl->index); + printk("\ttcenum = 0x%lx\n", (u64)tcenum); + printk("\tfreeTce = 0x%lx\n", (u64)freeTce); + printk("\ttce val = 0x%lx\n", + tce.wholeTce ); + } + + ++tcenum; + } + + /* Make sure the update is visible to hardware. */ + __asm__ __volatile__ ("sync" : : : "memory"); + + free_tce_range( tbl, freeTce, order ); +} + +/* PowerPC Interrupts for lpar. */ +/* NOTE: this typedef is duplicated (for now) from xics.c! */ +typedef struct { + int (*xirr_info_get)(int cpu); + void (*xirr_info_set)(int cpu, int val); + void (*cppr_info)(int cpu, u8 val); + void (*qirr_info)(int cpu, u8 val); +} xics_ops; +static int pSeriesLP_xirr_info_get(int n_cpu) +{ + unsigned long lpar_rc; + unsigned long return_value; + + lpar_rc = plpar_xirr(&return_value); + if (lpar_rc != H_Success) { + panic(" bad return code xirr - rc = %lx \n", lpar_rc); + } + return ((int)(return_value)); +} + +static void pSeriesLP_xirr_info_set(int n_cpu, int value) +{ + unsigned long lpar_rc; + unsigned long val64 = value & 0xffffffff; + + lpar_rc = plpar_eoi(val64); + if (lpar_rc != H_Success) { + panic(" bad return code EOI - rc = %ld, value=%lx \n", lpar_rc, val64); + } +} + +static void pSeriesLP_cppr_info(int n_cpu, u8 value) +{ + unsigned long lpar_rc; + + lpar_rc = plpar_cppr(value); + if (lpar_rc != H_Success) { + panic(" bad return code cppr - rc = %lx \n", lpar_rc); + } +} + +static void pSeriesLP_qirr_info(int n_cpu , u8 value) +{ + unsigned long lpar_rc; + + lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu),value); + if (lpar_rc != H_Success) { + udbg_printf("pSeriesLP_qirr_info - plpar_ipi failed!!!!!!!! \n"); + panic(" bad return code qirr -ipi - rc = %lx \n", lpar_rc); + } +} + +xics_ops pSeriesLP_ops = { + pSeriesLP_xirr_info_get, + pSeriesLP_xirr_info_set, + pSeriesLP_cppr_info, + pSeriesLP_qirr_info +}; +/* end TAI-LPAR */ + + +int vtermno; /* virtual terminal# for udbg */ + +static void udbg_putcLP(unsigned char c) +{ + char buf[16]; + unsigned long rc; + + if (c == '\n') + udbg_putcLP('\r'); + + buf[0] = c; + do { + rc = plpar_put_term_char(vtermno, 1, buf); + } while(rc == H_Busy); +} + +/* Buffered chars getc */ +static long inbuflen; +static long inbuf[2]; /* must be 2 longs */ + +static int udbg_getc_pollLP(void) +{ + /* The interface is tricky because it may return up to 16 chars. + * We save them statically for future calls to udbg_getc(). + */ + char ch, *buf = (char *)inbuf; + int i; + long rc; + if (inbuflen == 0) { + /* get some more chars. */ + inbuflen = 0; + rc = plpar_get_term_char(vtermno, &inbuflen, buf); + if (inbuflen == 0 && rc == H_Success) + return -1; + } + ch = buf[0]; + for (i = 1; i < inbuflen; i++) /* shuffle them down. */ + buf[i-1] = buf[i]; + inbuflen--; + return ch; +} + +static unsigned char udbg_getcLP(void) +{ + int ch; + for (;;) { + ch = udbg_getc_pollLP(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; + } + } +} + + +/* This is called early in setup.c. + * Use it to setup page table ppc_md stuff as well as udbg. + */ +void pSeriesLP_init_early(void) +{ + ppc_md.hpte_invalidate = hpte_invalidate_pSeriesLP; + ppc_md.hpte_updatepp = hpte_updatepp_pSeriesLP; + ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeriesLP; + ppc_md.hpte_getword0 = hpte_getword0_pSeriesLP; + ppc_md.hpte_selectslot = hpte_selectslot_pSeriesLP; + ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP; + ppc_md.hpte_find = hpte_find_pSeriesLP; + + ppc_md.tce_build = tce_build_pSeriesLP; + ppc_md.tce_free = tce_free_pSeriesLP; + +#ifdef CONFIG_SMP + smp_init_pSeries(); +#endif + pSeries_pcibios_init_early(); + + /* The keyboard is not useful in the LPAR environment. + * Leave all the interfaces NULL. + */ + + if (naca->serialPortAddr) { + void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); + udbg_init_uart(comport); + ppc_md.udbg_putc = udbg_putc; + ppc_md.udbg_getc = udbg_getc; + ppc_md.udbg_getc_poll = udbg_getc_poll; + } else { + /* lookup the first virtual terminal number in case we don't have a com port. + * Zero is probably correct in case someone calls udbg before the init. + * The property is a pair of numbers. The first is the starting termno (the + * one we use) and the second is the number of terminals. + */ + u32 *termno; + struct device_node *np = find_path_device("/rtas"); + if (np) { + termno = (u32 *)get_property(np, "ibm,termno", 0); + if (termno) + vtermno = termno[0]; + } + ppc_md.udbg_putc = udbg_putcLP; + ppc_md.udbg_getc = udbg_getcLP; + ppc_md.udbg_getc_poll = udbg_getc_pollLP; + } +} + +/* Confidential code for hvc_console. Should move it back eventually. */ + +int hvc_get_chars(int index, char *buf, int count) +{ + unsigned long got; + + if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, + (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { + /* + * Work around a HV bug where it gives us a null + * after every \r. -- paulus + */ + if (got > 0) { + int i; + for (i = 1; i < got; ++i) { + if (buf[i] == 0 && buf[i-1] == '\r') { + --got; + if (i < got) + memmove(&buf[i], &buf[i+1], + got - i); + } + } + } + return got; + } + return 0; +} + +int hvc_put_chars(int index, const char *buf, int count) +{ + unsigned long dummy; + unsigned long *lbuf = (unsigned long *) buf; + long ret; + + ret = plpar_hcall(H_PUT_TERM_CHAR, index, count, lbuf[0], lbuf[1], + &dummy, &dummy, &dummy); + if (ret == H_Success) + return count; + if (ret == H_Busy) + return 0; + return -1; +} + +int hvc_count(int *start_termno) +{ + u32 *termno; + struct device_node *dn; + + if ((dn = find_path_device("/rtas")) != NULL) { + if ((termno = (u32 *)get_property(dn, "ibm,termno", 0)) != NULL) { + if (start_termno) + *start_termno = termno[0]; + return termno[1]; + } + } + return 0; +} diff -urN linux-2.4.18/arch/ppc64/kernel/pSeries_pci.c linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_pci.c --- linux-2.4.18/arch/ppc64/kernel/pSeries_pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_pci.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,813 @@ +/* + * pSeries_pci.c + * + * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation + * + * pSeries specific routines for PCI. + * + * Based on code from pci.c and chrp_pci.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC_EEH +#include +#endif + +#include "xics.h" +#include "open_pic.h" +#include "pci.h" + +extern struct device_node *allnodes; + +/******************************************************************* + * Forward declares of prototypes. + *******************************************************************/ +unsigned long find_and_init_phbs(void); +struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ; +void pSeries_pcibios_fixup(void); +static int rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval); + +/* RTAS tokens */ +static int read_pci_config; +static int write_pci_config; +static int ibm_read_pci_config; +static int ibm_write_pci_config; + +static int s7a_workaround; + +/****************************************************************************** + * + * pSeries I/O Operations to access the PCI configuration space. + * + *****************************************************************************/ +#define RTAS_PCI_READ_OP(size, type, nbytes) \ +int __chrp \ +rtas_read_config_##size(struct device_node *dn, int offset, type val) { \ + unsigned long returnval = ~0L; \ + unsigned long buid; \ + unsigned int addr; \ + int ret; \ + \ + if (dn == NULL) { \ + ret = -2; \ + } else if (dn->status) { \ + ret = -1; \ + } else { \ + addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \ + buid = dn->phb->buid; \ + if (buid) { \ + ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \ + if (ret < 0) \ + ret = rtas_fake_read(dn, offset, nbytes, &returnval); \ + } else { \ + ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \ + } \ + } \ + *val = returnval; \ + return ret; \ +} \ +int __chrp \ +rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) { \ + struct device_node *dn = pci_device_to_OF_node(dev); \ + int ret = rtas_read_config_##size(dn, offset, val); \ + /* udbg_printf("read bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \ + return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \ +} + +#define RTAS_PCI_WRITE_OP(size, type, nbytes) \ +int __chrp \ +rtas_write_config_##size(struct device_node *dn, int offset, type val) { \ + unsigned long buid; \ + unsigned int addr; \ + int ret; \ + \ + if (dn == NULL) { \ + ret = -2; \ + } else if (dn->status) { \ + ret = -1; \ + } else { \ + buid = dn->phb->buid; \ + addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \ + if (buid) { \ + ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \ + } else { \ + ret = rtas_call(write_pci_config, 3, 1, NULL, addr, nbytes, (ulong)val); \ + } \ + } \ + return ret; \ +} \ +int __chrp \ +rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \ + return rtas_write_config_##size(pci_device_to_OF_node(dev), offset, val); \ +} + +RTAS_PCI_READ_OP(byte, u8 *, 1) +RTAS_PCI_READ_OP(word, u16 *, 2) +RTAS_PCI_READ_OP(dword, u32 *, 4) +RTAS_PCI_WRITE_OP(byte, u8, 1) +RTAS_PCI_WRITE_OP(word, u16, 2) +RTAS_PCI_WRITE_OP(dword, u32, 4) + +struct pci_ops rtas_pci_ops = { + rtas_pci_read_config_byte, + rtas_pci_read_config_word, + rtas_pci_read_config_dword, + rtas_pci_write_config_byte, + rtas_pci_write_config_word, + rtas_pci_write_config_dword, +}; + +/* + * Handle the case where rtas refuses to do a pci config read. + * This currently only happens with some PHBs in which case we totally fake + * out the values (and call it a speedwagaon -- something we could look up + * in the device tree). + */ +static int +rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval) +{ + char *device_type = (char *)get_property(dn, "device_type", 0); + u32 *class_code = (u32 *)get_property(dn, "class-code", 0); + + *returnval = ~0; /* float by default */ + + /* udbg_printf("rtas_fake_read dn=%p, offset=0x%02x, nbytes=%d, device_type=%s\n", dn, offset, nbytes, device_type ? device_type : ""); */ + if (device_type && strcmp(device_type, "pci") != 0) + return -3; /* Not a phb or bridge */ + + /* NOTE: class_code != NULL => EADS pci bridge. Else a PHB */ + if (nbytes == 1) { + if (offset == PCI_HEADER_TYPE) + *returnval = 0x80; /* multifunction */ + else if (offset == PCI_INTERRUPT_PIN || offset == PCI_INTERRUPT_LINE) + *returnval = 0; + } else if (nbytes == 2) { + if (offset == PCI_SUBSYSTEM_VENDOR_ID || offset == PCI_SUBSYSTEM_ID) + *returnval = 0; + else if (offset == PCI_COMMAND) + *returnval = PCI_COMMAND_PARITY|PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY; + } else if (nbytes == 4) { + if (offset == PCI_VENDOR_ID) + *returnval = 0x1014 | ((class_code ? 0x8b : 0x102) << 16); /* a phb */ + else if (offset == PCI_REVISION_ID) + *returnval = (class_code ? PCI_CLASS_BRIDGE_PCI : PCI_CLASS_BRIDGE_HOST) << 16; /* revs are zero */ + else if ((offset >= PCI_BASE_ADDRESS_0 && offset <= PCI_BASE_ADDRESS_5) || offset == PCI_ROM_ADDRESS) + *returnval = 0; + } + + /* printk("fake: %s nbytes=%d, offset=%lx ret=%lx\n", class_code ? "EADS" : "PHB", nbytes, offset, *returnval); */ + return 0; +} + +/****************************************************************** + * pci_read_irq_line + * + * Reads the Interrupt Pin to determine if interrupt is use by card. + * If the interrupt is used, then gets the interrupt line from the + * openfirmware and sets it in the pci_dev and pci_config line. + * + ******************************************************************/ +int +pci_read_irq_line(struct pci_dev *Pci_Dev) +{ + u8 InterruptPin; + struct device_node *Node; + + pci_read_config_byte(Pci_Dev, PCI_INTERRUPT_PIN, &InterruptPin); + if (InterruptPin == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n",Pci_Dev->slot_name); + return 0; + } + Node = pci_device_to_OF_node(Pci_Dev); + if ( Node == NULL) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n",Pci_Dev->slot_name); + return -1; + } + if (Node->n_intrs == 0) { + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n",Pci_Dev->slot_name); + return -1; + } + Pci_Dev->irq = Node->intrs[0].line; + + if (s7a_workaround) { + if (Pci_Dev->irq > 16) + Pci_Dev->irq -= 3; + } + + pci_write_config_byte(Pci_Dev, PCI_INTERRUPT_LINE, Pci_Dev->irq); + + PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n",Pci_Dev->slot_name,Pci_Dev->irq); + return 0; +} + +/****************************************************************** + * Find all PHBs in the system and initialize a set of data + * structures to represent them. + ******************************************************************/ +unsigned long __init +find_and_init_phbs(void) +{ + struct device_node *Pci_Node; + struct pci_controller *phb; + unsigned int root_addr_size_words = 0, this_addr_size_words = 0; + unsigned int this_addr_count = 0, range_stride; + unsigned int *ui_ptr = NULL, *ranges; + char *model; + struct pci_range64 range; + struct resource *res; + unsigned int memno, rlen, i, index; + unsigned int *opprop; + int has_isa = 0; + PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n"); + + read_pci_config = rtas_token("read-pci-config"); + write_pci_config = rtas_token("write-pci-config"); + ibm_read_pci_config = rtas_token("ibm,read-pci-config"); + ibm_write_pci_config = rtas_token("ibm,write-pci-config"); +#ifdef CONFIG_PPC_EEH + eeh_init(); +#endif + + if (naca->interrupt_controller == IC_OPEN_PIC) { + opprop = (unsigned int *)get_property(find_path_device("/"), + "platform-open-pic", NULL); + } + + /* Get the root address word size. */ + ui_ptr = (unsigned int *) get_property(find_path_device("/"), + "#size-cells", NULL); + if (ui_ptr) { + root_addr_size_words = *ui_ptr; + } else { + PPCDBG(PPCDBG_PHBINIT, "\tget #size-cells failed.\n"); + return(-1); + } + + if (find_type_devices("isa")) { + has_isa = 1; + PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n"); + } + + index = 0; + + /****************************************************************** + * Find all PHB devices and create an object for them. + ******************************************************************/ + for (Pci_Node = find_devices("pci"); Pci_Node != NULL; Pci_Node = Pci_Node->next) { + model = (char *) get_property(Pci_Node, "model", NULL); + if (model != NULL) { + phb = alloc_phb(Pci_Node, model, root_addr_size_words); + if (phb == NULL) return(-1); + } + else { + continue; + } + + /* Get this node's address word size. */ + ui_ptr = (unsigned int *) get_property(Pci_Node, "#size-cells", NULL); + if (ui_ptr) + this_addr_size_words = *ui_ptr; + else + this_addr_size_words = 1; + /* Get this node's address word count. */ + ui_ptr = (unsigned int *) get_property(Pci_Node, "#address-cells", NULL); + if (ui_ptr) + this_addr_count = *ui_ptr; + else + this_addr_count = 3; + + range_stride = this_addr_count + root_addr_size_words + this_addr_size_words; + + memno = 0; + phb->io_base_phys = 0; + + ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen); + PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen); + + for (i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) { + /* Put the PCI addr part of the current element into a + * '64' struct. + */ + range = *((struct pci_range64 *)(ranges + i)); + + /* If this is a '32' element, map into a 64 struct. */ + if ((range_stride * sizeof(int)) == + sizeof(struct pci_range32)) { + range.parent_addr = + (unsigned long)(*(ranges + i + 3)); + range.size = + (((unsigned long)(*(ranges + i + 4)))<<32) | + (*(ranges + i + 5)); + } else { + range.parent_addr = + (((unsigned long)(*(ranges + i + 3)))<<32) | + (*(ranges + i + 4)); + range.size = + (((unsigned long)(*(ranges + i + 5)))<<32) | + (*(ranges + i + 6)); + } + + PPCDBG(PPCDBG_PHBINIT, "\trange.parent_addr = 0x%lx\n", + range.parent_addr); + PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.hi = 0x%lx\n", + range.child_addr.a_hi); + PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.mid = 0x%lx\n", + range.child_addr.a_mid); + PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.lo = 0x%lx\n", + range.child_addr.a_lo); + PPCDBG(PPCDBG_PHBINIT, "\trange.size = 0x%lx\n", + range.size); + + res = NULL; + switch ((range.child_addr.a_hi >> 24) & 0x3) { + case 1: /* I/O space */ + PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n"); + phb->io_base_phys = range.parent_addr; + res = &phb->io_resource; + res->name = Pci_Node->full_name; + res->flags = IORESOURCE_IO; +#ifdef CONFIG_PPC_EEH + if (!isa_io_base && has_isa) { + /* map a page for ISA ports. Not EEH protected. */ + isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE); + } + res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0); + res->end = eeh_token(index, 0xff, 0xff, 0xffffffff); +#else + phb->io_base_virt = ioremap(phb->io_base_phys, range.size); + if (!pci_io_base) { + pci_io_base = (unsigned long)phb->io_base_virt; + if (has_isa) + isa_io_base = pci_io_base; + } + res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); + res->start += (unsigned long)phb->io_base_virt; + res->end = res->start + range.size - 1; +#endif + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + phb->pci_io_offset = range.parent_addr - + ((((unsigned long) + range.child_addr.a_mid) << 32) | + (range.child_addr.a_lo)); + PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset = 0x%lx\n", + phb->pci_io_offset); + break; + case 2: /* mem space */ + PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n"); + phb->pci_mem_offset = range.parent_addr - + ((((unsigned long) + range.child_addr.a_mid) << 32) | + (range.child_addr.a_lo)); + PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n", + phb->pci_mem_offset); + if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) { + res = &(phb->mem_resources[memno]); + ++memno; + res->name = Pci_Node->full_name; + res->flags = IORESOURCE_MEM; +#ifdef CONFIG_PPC_EEH + res->start = eeh_token(index, 0, 0, 0); + res->end = eeh_token(index, 0xff, 0xff, 0xffffffff); +#else + res->start = range.parent_addr; + res->end = range.parent_addr + range.size - 1; +#endif + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; + } + break; + } + } + PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n", + phb->io_base_phys); + PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", + phb->pci_mem_offset); + + if (naca->interrupt_controller == IC_OPEN_PIC) { + int addr = root_addr_size_words * (index + 2) - 1; + openpic_setup_ISU(index, opprop[addr]); + } + index++; + } + pci_devs_phb_init(); + return 0; /*Success */ +} + +/****************************************************************** + * + * Allocate and partially initialize a structure to represent a PHB. + * + ******************************************************************/ +struct pci_controller * +alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) +{ + struct pci_controller *phb; + unsigned int *ui_ptr = NULL, len; + struct reg_property64 reg_struct; + int *bus_range; + int *buid_vals; + + PPCDBG(PPCDBG_PHBINIT, "alloc_phb: %s\n", dev->full_name); + PPCDBG(PPCDBG_PHBINIT, "\tdev = 0x%lx\n", dev); + PPCDBG(PPCDBG_PHBINIT, "\tmodel = 0x%lx\n", model); + PPCDBG(PPCDBG_PHBINIT, "\taddr_size_words = 0x%lx\n", addr_size_words); + + /* Found a PHB, now figure out where his registers are mapped. */ + ui_ptr = (unsigned int *) get_property(dev, "reg", &len); + if (ui_ptr == NULL) { + PPCDBG(PPCDBG_PHBINIT, "\tget reg failed.\n"); + return(NULL); + } + + if (addr_size_words == 1) { + reg_struct.address = ((struct reg_property32 *)ui_ptr)->address; + reg_struct.size = ((struct reg_property32 *)ui_ptr)->size; + } else { + reg_struct = *((struct reg_property64 *)ui_ptr); + } + + PPCDBG(PPCDBG_PHBINIT, "\treg_struct.address = 0x%lx\n", reg_struct.address); + PPCDBG(PPCDBG_PHBINIT, "\treg_struct.size = 0x%lx\n", reg_struct.size); + + /*************************************************************** + * Set chip specific data in the phb, including types & + * register pointers. + ***************************************************************/ + + /**************************************************************** + * Python + ***************************************************************/ + if (strstr(model, "Python")) { + PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n"); + phb = pci_alloc_pci_controller("PHB PY",phb_type_python); + if (phb == NULL) return NULL; + + phb->cfg_addr = (volatile unsigned long *) + ioremap(reg_struct.address + 0xf8000, PAGE_SIZE); + PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", + reg_struct.address + 0xf8000); + PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", + phb->cfg_addr); + phb->cfg_data = (char*)(phb->cfg_addr + 0x02); + phb->phb_regs = (volatile unsigned long *) + ioremap(reg_struct.address + 0xf7000, PAGE_SIZE); + /* Python's register file is 1 MB in size. */ + phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), + 0x100000); + + /* + * Firmware doesnt always clear this bit which is critical + * for good performance - Anton + */ + { + volatile u32 *tmp, i; + +#define PRG_CL_RESET_VALID 0x00010000 + + tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030); + + if (*tmp & PRG_CL_RESET_VALID) { + printk("Python workaround: "); + *tmp &= ~PRG_CL_RESET_VALID; + /* + * We must read it back for changes to + * take effect + */ + i = *tmp; + printk("reg0: %x\n", i); + } + } + + /*************************************************************** + * Speedwagon + ***************************************************************/ + } else if (strstr(model, "Speedwagon")) { + PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n"); + phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon); + if (phb == NULL) return NULL; + + if (_machine == _MACH_pSeries) { + phb->cfg_addr = (volatile unsigned long *) + ioremap(reg_struct.address + 0x140, PAGE_SIZE); + phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */ + phb->phb_regs = (volatile unsigned long *) + ioremap(reg_struct.address, PAGE_SIZE); + /* Speedwagon's register file is 1 MB in size. */ + phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), + 0x100000); + PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", + reg_struct.address & 0xfffff, phb->chip_regs); + } else { + phb->cfg_addr = NULL; + phb->cfg_data = NULL; + phb->phb_regs = NULL; + phb->chip_regs = NULL; + } + + phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8; + /*************************************************************** + * Trying to build a known just gets the code in trouble. + ***************************************************************/ + } else { + PPCDBG(PPCDBG_PHBINIT, "\tUnknown PHB Type!\n"); + printk("PCI: Unknown Phb Type!\n"); + return NULL; + } + + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name); + kfree(phb); + return(NULL); + } + + /*************************************************************** + * Finished with the initialization + ***************************************************************/ + phb->first_busno = bus_range[0]; + phb->last_busno = bus_range[1]; + + phb->arch_data = dev; + phb->ops = &rtas_pci_ops; + + buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len); + + if (buid_vals == NULL) { + phb->buid = 0; + } + else { + struct pci_bus check; + if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 || + sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) { + udbg_printf("pSeries_pci: this system has large bus numbers and the kernel was not\n" + "built with the patch that fixes include/linux/pci.h struct pci_bus so\n" + "number, primary, secondary and subordinate are ints.\n"); + panic("pSeries_pci: this system has large bus numbers and the kernel was not\n" + "built with the patch that fixes include/linux/pci.h struct pci_bus so\n" + "number, primary, secondary and subordinate are ints.\n"); + } + + if (len < 2 * sizeof(int)) + phb->buid = (unsigned long)buid_vals[0]; // Support for new OF that only has 1 integer for buid. + else + phb->buid = (((unsigned long)buid_vals[0]) << 32UL) | + (((unsigned long)buid_vals[1]) & 0xffffffff); + + phb->first_busno += (phb->global_number << 8); + phb->last_busno += (phb->global_number << 8); + } + + /* Dump PHB information for Debug */ + PPCDBGCALL(PPCDBG_PHBINIT,dumpPci_Controller(phb) ); + + return phb; +} + +void +fixup_resources(struct pci_dev *dev) +{ + int i; + struct pci_controller *phb = PCI_GET_PHB_PTR(dev); +#ifdef CONFIG_PPC_EEH + struct device_node *dn; + unsigned long eeh_disable_bit; + + /* Add IBM loc code (slot) as a prefix to the device names for service */ + dn = pci_device_to_OF_node(dev); + if (dn) { + char *loc_code = get_property(dn, "ibm,loc-code", 0); + if (loc_code) { + int loc_len = strlen(loc_code); + if (loc_len < sizeof(dev->name)) { + memmove(dev->name+loc_len+1, dev->name, sizeof(dev->name)-loc_len-1); + memcpy(dev->name, loc_code, loc_len); + dev->name[loc_len] = ' '; + dev->name[sizeof(dev->name)-1] = '\0'; + } + } + } + + if (is_eeh_configured(dev)) { + eeh_disable_bit = 0; + printk("PCI: eeh configured for %s %s\n", dev->slot_name, dev->name); + if (eeh_set_option(dev, EEH_ENABLE) != 0) { + printk("PCI: failed to enable eeh for %s %s\n", dev->slot_name, dev->name); + eeh_disable_bit = EEH_TOKEN_DISABLED; + } + } else { + /* Assume device is by default EEH_DISABLE'd */ + printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name); + eeh_disable_bit = EEH_TOKEN_DISABLED; + } +#endif + + PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); + PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb); + PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset = 0x%016LX\n", phb->pci_io_offset); + PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%016LX\n", phb->pci_mem_offset); + + PPCDBG(PPCDBG_PHBINIT, "\tdev->name = %s\n", dev->name); + PPCDBG(PPCDBG_PHBINIT, "\tdev->vendor:device = 0x%04X : 0x%04X\n", dev->vendor, dev->device); + + if (phb == NULL) + return; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { + PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n", + dev->bus->number, dev->devfn, i, + dev->resource[i].flags, + dev->resource[i].start, + dev->resource[i].end); + + if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) { + continue; + } + + if (dev->resource[i].flags & IORESOURCE_IO) { +#ifdef CONFIG_PPC_EEH + unsigned int busno = dev->bus ? dev->bus->number : 0; + unsigned long size = dev->resource[i].end - dev->resource[i].start; + unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE); + if (!addr) + panic("fixup_resources: ioremap failed!\n"); + dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; + dev->resource[i].end = dev->resource[i].start + size; +#else + unsigned long offset = (unsigned long)phb->io_base_virt; + dev->resource[i].start += offset; + dev->resource[i].end += offset; +#endif + PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n", + dev->resource[i].start, dev->resource[i].end); + } else if (dev->resource[i].flags & IORESOURCE_MEM) { + if (dev->resource[i].start == 0) { + /* Bogus. Probably an unused bridge. */ + dev->resource[i].end = 0; + } else { +#ifdef CONFIG_PPC_EEH + unsigned int busno = dev->bus ? dev->bus->number : 0; + unsigned long size = dev->resource[i].end - dev->resource[i].start; + unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE); + if (!addr) + panic("fixup_resources: ioremap failed!\n"); + dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; + dev->resource[i].end = dev->resource[i].start + size; +#else + dev->resource[i].start += phb->pci_mem_offset; + dev->resource[i].end += phb->pci_mem_offset; +#endif + } + PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n", + dev->resource[i].start, dev->resource[i].end); + + } else { + continue; + } + + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +} + +static void check_s7a(void) +{ + struct device_node *root; + char *model; + + root = find_path_device("/"); + if (root) { + model = get_property(root, "model", NULL); + if (model && !strcmp(model, "IBM,7013-S7A")) + s7a_workaround = 1; + } +} + +void __init +pSeries_pcibios_fixup(void) +{ + struct pci_dev *dev; + + PPCDBG(PPCDBG_PHBINIT, "pSeries_pcibios_fixup: start\n"); + pci_assign_all_busses = 0; + + check_s7a(); + + pci_for_each_dev(dev) { + pci_read_irq_line(dev); + PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) ); + } + + if (naca->interrupt_controller == IC_PPC_XIC) { + xics_isa_init(); + } +} + +/*********************************************************************** + * pci_find_hose_for_OF_device + * + * This function finds the PHB that matching device_node in the + * OpenFirmware by scanning all the pci_controllers. + * + ***********************************************************************/ +struct pci_controller* +pci_find_hose_for_OF_device(struct device_node *node) +{ + while (node) { + struct pci_controller *hose; + for (hose=hose_head;hose;hose=hose->next) + if (hose->arch_data == node) + return hose; + node=node->parent; + } + return NULL; +} + +/*********************************************************************** + * ppc64_pcibios_init + * + * Chance to initialize and structures or variable before PCI Bus walk. + * + ***********************************************************************/ +void +pSeries_pcibios_init(void) +{ + PPCDBG(PPCDBG_PHBINIT, "\tppc64_pcibios_init Entry.\n"); + + if (get_property(find_path_device("/rtas"),"ibm,fw-phb-id",NULL) != NULL) { + PPCDBG(PPCDBG_PHBINIT, "\tFound: ibm,fw-phb-id\n"); + Pci_Large_Bus_System = 1; + } +} + +/* + * This is called very early before the page table is setup. + */ +void +pSeries_pcibios_init_early(void) +{ + ppc_md.pcibios_read_config_byte = rtas_read_config_byte; + ppc_md.pcibios_read_config_word = rtas_read_config_word; + ppc_md.pcibios_read_config_dword = rtas_read_config_dword; + ppc_md.pcibios_write_config_byte = rtas_write_config_byte; + ppc_md.pcibios_write_config_word = rtas_write_config_word; + ppc_md.pcibios_write_config_dword = rtas_write_config_dword; +} +/************************************************************************/ +/* Get a char* of the device physical location(U0.3-P1-I8) */ +/* See the Product Topology in the RS/6000 Architecture. */ +/************************************************************************/ +int device_Location(struct pci_dev *PciDev, char *BufPtr) +{ + struct device_node *DevNode = (struct device_node *)PciDev->sysdata; + return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %-12s", + PciDev->bus->number, + PCI_SLOT(PciDev->devfn), + PciDev->vendor, + (char*)get_property(DevNode,"ibm,loc-code",0)); +} +/************************************************************************/ +/* Set the slot reset line to the state passed in. */ +/* This is the platform specific for code for the pci_reset_device */ +/* function. */ +/************************************************************************/ +int pci_set_reset(struct pci_dev *PciDev, int state) +{ + return -1; +} diff -urN linux-2.4.18/arch/ppc64/kernel/pacaData.c linux-2.4.19-pre5/arch/ppc64/kernel/pacaData.c --- linux-2.4.18/arch/ppc64/kernel/pacaData.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pacaData.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,118 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * 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. + */ + +#define __KERNEL__ 1 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* The Paca is an array with one entry per processor. Each contains an + * ItLpPaca, which contains the information shared between the + * hypervisor and Linux. Each also contains an ItLpRegSave area which + * is used by the hypervisor to save registers. + * On systems with hardware multi-threading, there are two threads + * per processor. The Paca array must contain an entry for each thread. + * The VPD Areas will give a max logical processors = 2 * max physical + * processors. The processor VPD array needs one entry per physical + * processor (not thread). + */ +#define PACAINITDATA(number,start,lpq,asrr,asrv) \ +{ \ + xLpPacaPtr: &xPaca[number].xLpPaca, \ + xLpRegSavePtr: &xPaca[number].xRegSav, \ + xPacaIndex: (number), /* Paca Index */ \ + default_decr: 0x00ff0000, /* Initial Decr */ \ + xStab_data: { \ + real: (asrr), /* Real pointer to segment table */ \ + virt: (asrv), /* Virt pointer to segment table */ \ + next_round_robin: 1 /* Round robin index */ \ + }, \ + lpQueuePtr: (lpq), /* &xItLpQueue, */ \ + xRtas: { \ + lock: SPIN_LOCK_UNLOCKED \ + }, \ + xProcStart: (start), /* Processor start */ \ + xLpPaca: { \ + xDesc: 0xd397d781, /* "LpPa" */ \ + xSize: sizeof(struct ItLpPaca), \ + xFPRegsInUse: 1, \ + xDynProcStatus: 2, \ + xDecrVal: 0x00ff0000, \ + xEndOfQuantum: 0xffffffffffffffff \ + }, \ + xRegSav: { \ + xDesc: 0xd397d9e2, /* "LpRS" */ \ + xSize: sizeof(struct ItLpRegSave) \ + }, \ + exception_sp: \ + (&xPaca[number].exception_stack[0]) - EXC_FRAME_SIZE, \ +} + +struct Paca xPaca[maxPacas] __page_aligned = { +#ifdef CONFIG_PPC_ISERIES + PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000), +#else + PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000), +#endif + PACAINITDATA( 1, 0, 0, 0, 0), + PACAINITDATA( 2, 0, 0, 0, 0), + PACAINITDATA( 3, 0, 0, 0, 0), + PACAINITDATA( 4, 0, 0, 0, 0), + PACAINITDATA( 5, 0, 0, 0, 0), + PACAINITDATA( 6, 0, 0, 0, 0), + PACAINITDATA( 7, 0, 0, 0, 0), + PACAINITDATA( 8, 0, 0, 0, 0), + PACAINITDATA( 9, 0, 0, 0, 0), + PACAINITDATA(10, 0, 0, 0, 0), + PACAINITDATA(11, 0, 0, 0, 0), + PACAINITDATA(12, 0, 0, 0, 0), + PACAINITDATA(13, 0, 0, 0, 0), + PACAINITDATA(14, 0, 0, 0, 0), + PACAINITDATA(15, 0, 0, 0, 0), + PACAINITDATA(16, 0, 0, 0, 0), + PACAINITDATA(17, 0, 0, 0, 0), + PACAINITDATA(18, 0, 0, 0, 0), + PACAINITDATA(19, 0, 0, 0, 0), + PACAINITDATA(20, 0, 0, 0, 0), + PACAINITDATA(21, 0, 0, 0, 0), + PACAINITDATA(22, 0, 0, 0, 0), + PACAINITDATA(23, 0, 0, 0, 0), + PACAINITDATA(24, 0, 0, 0, 0), + PACAINITDATA(25, 0, 0, 0, 0), + PACAINITDATA(26, 0, 0, 0, 0), + PACAINITDATA(27, 0, 0, 0, 0), + PACAINITDATA(28, 0, 0, 0, 0), + PACAINITDATA(29, 0, 0, 0, 0), + PACAINITDATA(30, 0, 0, 0, 0), + PACAINITDATA(31, 0, 0, 0, 0), + PACAINITDATA(32, 0, 0, 0, 0), + PACAINITDATA(33, 0, 0, 0, 0), + PACAINITDATA(34, 0, 0, 0, 0), + PACAINITDATA(35, 0, 0, 0, 0), + PACAINITDATA(36, 0, 0, 0, 0), + PACAINITDATA(37, 0, 0, 0, 0), + PACAINITDATA(38, 0, 0, 0, 0), + PACAINITDATA(39, 0, 0, 0, 0), + PACAINITDATA(40, 0, 0, 0, 0), + PACAINITDATA(41, 0, 0, 0, 0), + PACAINITDATA(42, 0, 0, 0, 0), + PACAINITDATA(43, 0, 0, 0, 0), + PACAINITDATA(44, 0, 0, 0, 0), + PACAINITDATA(45, 0, 0, 0, 0), + PACAINITDATA(46, 0, 0, 0, 0), + PACAINITDATA(47, 0, 0, 0, 0) +}; diff -urN linux-2.4.18/arch/ppc64/kernel/pci.c linux-2.4.19-pre5/arch/ppc64/kernel/pci.c --- linux-2.4.18/arch/ppc64/kernel/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pci.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1062 @@ +/* + * + * + * Port for PPC64 David Engebretsen, IBM Corp. + * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC_EEH +#include +#endif + +#include "pci.h" + +/* pci_io_base -- the base address from which io bars are offsets. + * This is the lowest I/O base address (so bar values are always positive), + * and it *must* be the start of ISA space if an ISA bus exists because + * ISA drivers use hard coded offsets. If no ISA bus exists a dummy + * page is mapped and isa_io_limit prevents access to it. + */ +unsigned long isa_io_base = 0; /* NULL if no ISA bus */ +unsigned long pci_io_base = 0; +unsigned long isa_mem_base = 0; +unsigned long pci_dram_offset = 0; + +/****************************************************************** + * Forward declare of prototypes + ******************************************************************/ +static void pcibios_fixup_resources(struct pci_dev* dev); +static void fixup_broken_pcnet32(struct pci_dev* dev); +static void fixup_windbond_82c105(struct pci_dev* dev); +void fixup_resources(struct pci_dev* dev); + +void iSeries_pcibios_init(void); +void pSeries_pcibios_init(void); + + +extern struct Naca *naca; + +int pci_assign_all_busses = 0; + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +LIST_HEAD(iSeries_Global_Device_List); + +/******************************************************************* + * Counters and control flags. + *******************************************************************/ +long Pci_Io_Read_Count = 0; +long Pci_Io_Write_Count = 0; +long Pci_Cfg_Read_Count = 0; +long Pci_Cfg_Write_Count= 0; +long Pci_Error_Count = 0; + +int Pci_Retry_Max = 3; /* Only retry 3 times */ +int Pci_Error_Flag = 1; /* Set Retry Error on. */ +int Pci_Trace_Flag = 0; + +/****************************************************************** + * + ******************************************************************/ +int global_phb_number = 0; /* Global phb counter */ +int Pci_Large_Bus_System = 0; +int Pci_Set_IOA_Address = 0; +int Pci_Manage_Phb_Space = 0; +struct pci_controller *phbtab[PCI_MAX_PHB]; + +static int pci_bus_count; + +/* Cached ISA bridge dev. */ +struct pci_dev *ppc64_isabridge_dev = NULL; + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 }, + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, + { 0 } +}; + +static void fixup_broken_pcnet32(struct pci_dev* dev) +{ + if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { + dev->vendor = PCI_VENDOR_ID_AMD; + pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); + pci_name_device(dev); + } +} + +static void fixup_windbond_82c105(struct pci_dev* dev) +{ + /* Assume the windbond 82c105 is the IDE controller on a + * p610. We should probably be more careful in case + * someone tries to plug in a similar adapter. + */ + unsigned int reg; + + printk("Using INTC for W82c105 IDE controller.\n"); + pci_read_config_dword(dev, 0x40, ®); + /* Enable LEGIRQ to use INTC instead of ISA interrupts */ + pci_write_config_dword(dev, 0x40, reg | (1<<11)); +} + + +void pcibios_fixup_pbus_ranges(struct pci_bus *pbus, + struct pbus_set_ranges_data *pranges) +{ +} + + +void +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + struct pci_controller* hose = PCI_GET_PHB_PTR(dev); + + new = res->start; + if (hose && res->flags & IORESOURCE_MEM) + new -= hose->pci_mem_offset; + new |= (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +static void +pcibios_fixup_resources(struct pci_dev* dev) +{ + fixup_resources(dev); +} + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (size > 0x100) { + printk(KERN_ERR "PCI: Can not align I/O Region %s %s because size %ld is too large.\n", + dev->slot_name, res->name, size); + } + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +} + + +/* + * Handle resources of PCI devices. If the world were perfect, we could + * just allocate all the resource regions and do nothing more. It isn't. + * On the other hand, we cannot just re-allocate all devices, as it would + * require us to know lots of host bridge internals. So we attempt to + * keep as much of the original configuration as possible, but tweak it + * when it's found to be wrong. + * + * Known BIOS problems we have to work around: + * - I/O or memory regions not configured + * - regions configured, but not enabled in the command register + * - bogus I/O addresses above 64K used + * - expansion ROMs left enabled (this may sound harmless, but given + * the fact the PCI specs explicitly allow address decoders to be + * shared between expansion ROMs and other resource regions, it's + * at least dangerous) + * + * Our solution: + * (1) Allocate resources for all buses behind PCI-to-PCI bridges. + * This gives us fixed barriers on where we can allocate. + * (2) Allocate resources for all enabled devices. If there is + * a collision, just mark the resource as unallocated. Also + * disable expansion ROMs during this step. + * (3) Try to allocate resources for disabled devices. If the + * resources were assigned correctly, everything goes well, + * if they weren't, they won't disturb allocation of other + * resources. + * (4) Assign new addresses to resources which were either + * not configured at all or misconfigured. If explicitly + * requested by the user, configure expansion ROM address + * as well. + */ + +static void __init +pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + int i; + struct resource *res, *pr; + + /* Depth-First Search on bus tree */ + for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr == res) + continue; /* transparent bus or undefined */ + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Cannot allocate resource region " + "%d of PCI bridge %x\n", i, bus->number); + printk(KERN_ERR "PCI: resource is %lx..%lx (%lx), parent %p\n", + res->start, res->end, res->flags, pr); + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +static void __init +pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + pci_for_each_dev(dev) { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (r->parent) /* Already allocated */ + continue; + if (!r->start) /* Address not assigned at all */ + continue; + + if (r->flags & IORESOURCE_IO) + disabled = !(command & PCI_COMMAND_IO); + else + disabled = !(command & PCI_COMMAND_MEMORY); + if (pass == disabled) { + PPCDBG(PPCDBG_PHBINIT, + "PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", + r->start, r->end, r->flags, disabled, pass); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + PPCDBG(PPCDBG_PHBINIT, + "PCI: Cannot allocate resource region %d of device %s, pr = 0x%lx\n", idx, dev->slot_name, pr); + if(pr) { + PPCDBG(PPCDBG_PHBINIT, + "PCI: Cannot allocate resource 0x%lx\n", request_resource(pr,r)); + } + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; + } + } + } + if (!pass) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + /* Turn the ROM off, leave the resource region, but keep it unregistered. */ + u32 reg; + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); + } + } + } +} + +static void __init +pcibios_assign_resources(void) +{ + struct pci_dev *dev; + int idx; + struct resource *r; + + pci_for_each_dev(dev) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + continue; + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end && ppc_md.pcibios_enable_device_hook && + !ppc_md.pcibios_enable_device_hook(dev, 1)) + pci_assign_resource(dev, idx); + } + + if (0) { /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + } + } +} + + +int +pcibios_enable_resources(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 (dev->resource[PCI_ROM_RESOURCE].start) + 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; +} + +/* + * Allocate pci_controller(phb) initialized common variables. + */ +struct pci_controller * __init +pci_alloc_pci_controller(char *model, enum phb_types controller_type) +{ + struct pci_controller *hose; + PPCDBG(PPCDBG_PHBINIT, "PCI: Allocate pci_controller for %s\n",model); + hose = (struct pci_controller *)alloc_bootmem(sizeof(struct pci_controller)); + if(hose == NULL) { + printk(KERN_ERR "PCI: Allocate pci_controller failed.\n"); + return NULL; + } + memset(hose, 0, sizeof(struct pci_controller)); + if(strlen(model) < 8) strcpy(hose->what,model); + else memcpy(hose->what,model,7); + hose->type = controller_type; + hose->global_number = global_phb_number; + phbtab[global_phb_number++] = hose; + + *hose_tail = hose; + hose_tail = &hose->next; + return hose; +} + +/* + * This fixup is arch independent and probably should go somewhere else. + */ +void __init +pcibios_generic_fixup(void) +{ + struct pci_dev *dev; + + /* Fix miss-identified vendor AMD pcnet32 adapters. */ + dev = NULL; + while ((dev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, dev)) != NULL && + dev->class == (PCI_CLASS_NETWORK_ETHERNET << 8)) + dev->vendor = PCI_VENDOR_ID_AMD; +} + + + +/*********************************************************************** + * + * + * + ***********************************************************************/ +void __init +pcibios_init(void) +{ + struct pci_controller *hose; + struct pci_bus *bus; + int next_busno; + +#ifndef CONFIG_PPC_ISERIES + pSeries_pcibios_init(); +#else + iSeries_pcibios_init(); +#endif + + printk("PCI: Probing PCI hardware\n"); + PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n"); + + + /* Scan all of the recorded PCI controllers. */ + for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { + hose->last_busno = 0xff; + bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data); + hose->bus = bus; + hose->last_busno = bus->subordinate; + if (pci_assign_all_busses || next_busno <= hose->last_busno) + next_busno = hose->last_busno+1; + } + pci_bus_count = next_busno; + + /* Call machine dependant fixup */ + if (ppc_md.pcibios_fixup) { + ppc_md.pcibios_fixup(); + } + + /* Generic fixups */ + pcibios_generic_fixup(); + + /* Allocate and assign resources */ + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); + pcibios_assign_resources(); + +#ifndef CONFIG_PPC_ISERIES + pci_fix_bus_sysdata(); + + create_tce_tables(); + PPCDBG(PPCDBG_BUSWALK,"pSeries create_tce_tables()\n"); +#endif + + /* Cache the location of the ISA bridge (if we have one) */ + if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL)) + printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name); + + printk("PCI: Probing PCI hardware done\n"); + PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n"); + +} + +int __init +pcibios_assign_all_busses(void) +{ + return pci_assign_all_busses; +} + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_controller *phb = PCI_GET_PHB_PTR(bus); + struct resource *res; + int i; + +#ifndef CONFIG_PPC_ISERIES + if (bus->parent == NULL) { + /* This is a host bridge - fill in its resources */ + phb->bus = bus; + bus->resource[0] = res = &phb->io_resource; + if (!res->flags) + BUG(); /* No I/O resource for this PHB? */ + + for (i = 0; i < 3; ++i) { + res = &phb->mem_resources[i]; + if (!res->flags) { + if (i == 0) + BUG(); /* No memory resource for this PHB? */ + } + bus->resource[i+1] = res; + } + } else { + /* This is a subordinate bridge */ + pci_read_bridge_bases(bus); + + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL) + continue; + if (!res->flags) + continue; + if (res == pci_find_parent_resource(bus->self, res)) { + /* Transparent resource -- don't try to "fix" it. */ + continue; + } +#ifdef CONFIG_PPC_EEH + if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) { + res->start = eeh_token(phb->global_number, bus->number, 0, 0); + res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff); + } +#else + if (res->flags & IORESOURCE_IO) { + res->start += (unsigned long)phb->io_base_virt; + res->end += (unsigned long)phb->io_base_virt; + } else if (phb->pci_mem_offset + && (res->flags & IORESOURCE_MEM)) { + if (res->start < phb->pci_mem_offset) { + res->start += phb->pci_mem_offset; + res->end += phb->pci_mem_offset; + } + } +#endif + } + } +#endif + if ( ppc_md.pcibios_fixup_bus ) + ppc_md.pcibios_fixup_bus(bus); +} + +char __init *pcibios_setup(char *str) +{ + return str; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n",__FUNCTION__,dev->slot_name); + if (ppc_md.pcibios_enable_device_hook) + if (ppc_md.pcibios_enable_device_hook(dev, 0)) + return -EINVAL; + + 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); + PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",dev->slot_name); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +struct pci_controller* +pci_bus_to_hose(int bus) +{ + struct pci_controller* hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +void* +pci_bus_io_base(unsigned int bus) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + if (!hose) + return NULL; + return hose->io_base_virt; +} + +unsigned long +pci_bus_io_base_phys(unsigned int bus) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + if (!hose) + return 0; + return hose->io_base_phys; +} + +unsigned long +pci_bus_mem_base_phys(unsigned int bus) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + if (!hose) + return 0; + return hose->pci_mem_offset; +} + +/* + * Return the index of the PCI controller for device pdev. + */ +int pci_controller_num(struct pci_dev *dev) +{ + struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + + return hose->global_number; +} + +/* + * Platform support for /proc/bus/pci/X/Y mmap()s, + * modelled on the sparc64 implementation by Dave Miller. + * -- paulus. + */ + +/* + * Adjust vm_pgoff of VMA such that it is the physical page offset + * corresponding to the 32-bit pci bus offset for DEV requested by the user. + * + * Basically, the user finds the base address for his device which he wishes + * to mmap. They read the 32-bit value from the config space base register, + * add whatever PAGE_SIZE multiple offset they wish, and feed this into the + * offset parameter of mmap on /proc/bus/pci/XXX for that device. + * + * Returns negative error code on failure, zero on success. + */ +static __inline__ int +__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long io_offset = 0; + int i, res_bit; + + if (hose == 0) + return -EINVAL; /* should never happen */ + + /* If memory, add on the PCI bridge address offset */ + if (mmap_state == pci_mmap_mem) { + offset += hose->pci_mem_offset; + res_bit = IORESOURCE_MEM; + } else { + io_offset = (unsigned long)hose->io_base_virt; + offset += io_offset; + res_bit = IORESOURCE_IO; + } + + /* + * Check that the offset requested corresponds to one of the + * resources of the device. + */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *rp = &dev->resource[i]; + int flags = rp->flags; + + /* treat ROM as memory (should be already) */ + if (i == PCI_ROM_RESOURCE) + flags |= IORESOURCE_MEM; + + /* Active and same type? */ + if ((flags & res_bit) == 0) + continue; + + /* In the range of this resource? */ + if (offset < (rp->start & PAGE_MASK) || offset > rp->end) + continue; + + /* found it! construct the final physical address */ + if (mmap_state == pci_mmap_io) + offset += hose->io_base_phys - io_offset; + + vma->vm_pgoff = offset >> PAGE_SHIFT; + return 0; + } + + return -EINVAL; +} + +/* + * Set vm_flags of VMA, as appropriate for this architecture, for a pci device + * mapping. + */ +static __inline__ void +__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state) +{ + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; +} + +/* + * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci + * device mapping. + */ +static __inline__ void +__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + long prot = pgprot_val(vma->vm_page_prot); + + /* XXX would be nice to have a way to ask for write-through */ + prot |= _PAGE_NO_CACHE; + if (!write_combine) + prot |= _PAGE_GUARDED; + vma->vm_page_prot = __pgprot(prot); +} + +/* + * Perform the actual remap of the pages for a PCI device mapping, as + * appropriate for this architecture. The region in the process to map + * is described by vm_start and vm_end members of VMA, the base physical + * address is found in vm_pgoff. + * The pci device structure is provided so that architectures may make mapping + * decisions on a per-device or per-bus basis. + * + * Returns a negative error code on failure, zero on success. + */ +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine) +{ + int ret; + + ret = __pci_mmap_make_offset(dev, vma, mmap_state); + if (ret < 0) + return ret; + + __pci_mmap_set_flags(dev, vma, mmap_state); + __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine); + + ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + + return ret; +} + +/* Provide information on locations of various I/O regions in physical + * memory. Do this on a per-card basis so that we choose the right + * root bridge. + * Note that the returned IO or memory base is a physical address + */ + +long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) +{ + struct pci_controller* hose = pci_bus_to_hose(bus); + long result = -EOPNOTSUPP; + + if (!hose) + return -ENODEV; + + switch (which) { + case IOBASE_BRIDGE_NUMBER: + return (long)hose->first_busno; + case IOBASE_MEMORY: + return (long)hose->pci_mem_offset; + case IOBASE_IO: + return (long)hose->io_base_phys; + case IOBASE_ISA_IO: + return (long)isa_io_base; + case IOBASE_ISA_MEM: + return (long)isa_mem_base; + } + + return result; +} +/************************************************************************/ +/* Formats the device information and location for service. */ +/* - Pass in pci_dev* pointer to the device. */ +/* - Pass in buffer to place the data. Danger here is the buffer must */ +/* be as big as the client says it is. Should be at least 128 bytes.*/ +/* Return will the length of the string data put in the buffer. */ +/* The brand specific method device_Location is called. */ +/* Format: */ +/* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet */ +/* PCI: Bus 0, Device 26, Vendor 0x12AE Location U0.3-P1-I8 Ethernet */ +/* For pSeries, see the Product Topology in the RS/6000 Architecture. */ +/* For iSeries, see the Service Manuals. */ +/************************************************************************/ +int format_device_location(struct pci_dev* PciDev,char* BufPtr, int BufferSize) +{ + struct device_node* DevNode = (struct device_node*)PciDev->sysdata; + int LineLen = 0; + if (DevNode != NULL && BufferSize >= 128) { + LineLen += device_Location(PciDev,BufPtr+LineLen); + LineLen += sprintf(BufPtr+LineLen," %12s",pci_class_name(PciDev->class >> 8) ); + } + return LineLen; +} +/************************************************************************ + * Saves the config registers for a device. * + ************************************************************************ + * Note: This does byte reads so the data may appear byte swapped, * + * The data returned in the pci_config_reg_save_area structure can be * + * used to the restore of the data. If the save failed, the data * + * will not be restore. Yes I know, you are most likey toast. * + ************************************************************************/ +int pci_save_config_regs(struct pci_dev* PciDev,struct pci_config_reg_save_area* SaveArea) +{ + memset(SaveArea,0x00,sizeof(struct pci_config_reg_save_area) ); + SaveArea->PciDev = PciDev; + SaveArea->RCode = 0; + SaveArea->Register = 0; + /****************************************************************** + * Save All the Regs, NOTE: restore skips the first 16 bytes. * + ******************************************************************/ + while (SaveArea->Register < REG_SAVE_SIZE && SaveArea->RCode == 0) { + SaveArea->RCode = pci_read_config_byte(PciDev, SaveArea->Register, &SaveArea->Regs[SaveArea->Register]); + ++SaveArea->Register; + } + if (SaveArea->RCode != 0) { /* Ouch */ + SaveArea->Flags = 0x80; + printk("PCI: pci_restore_save_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode); + PCIFR( "pci_restore_save_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode); + } + else { + SaveArea->Flags = 0x01; + } + return SaveArea->RCode; +} + +/************************************************************************ + * Restores the registers saved via the save function. See the save * + * function for details. * + ************************************************************************/ +int pci_restore_config_regs(struct pci_dev* PciDev,struct pci_config_reg_save_area* SaveArea) +{ + if (SaveArea->PciDev != PciDev || SaveArea->Flags == 0x80 || SaveArea->RCode != 0) { + printk("PCI: pci_restore_config_regs failed! %p\n",PciDev); + return -1; + } + /****************************************************************** + * Don't touch the Cmd or BIST regs, user must restore those. * + * Restore PCI_VENDOR_ID & PCI_DEVICE_ID * + * Restore PCI_CACHE_LINE_SIZE & PCI_LATENCY_TIMER * + * Restore Saved Regs from 0x10 to 0x3F * + ******************************************************************/ + SaveArea->Register = 0; + while(SaveArea->Register < REG_SAVE_SIZE && SaveArea->RCode == 0) { + SaveArea->RCode = pci_write_config_byte(PciDev,SaveArea->Register,SaveArea->Regs[SaveArea->Register]); + ++SaveArea->Register; + if ( SaveArea->Register == PCI_COMMAND) SaveArea->Register = PCI_CACHE_LINE_SIZE; + else if (SaveArea->Register == PCI_HEADER_TYPE) SaveArea->Register = PCI_BASE_ADDRESS_0; + } + if (SaveArea->RCode != 0) { + printk("PCI: pci_restore_config_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode); + PCIFR( "pci_restore_config_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode); + } + return SaveArea->RCode; +} + +/************************************************************************/ +/* Interface to toggle the reset line */ +/* Time is in .1 seconds, need for seconds. */ +/************************************************************************/ +int pci_reset_device(struct pci_dev* PciDev, int AssertTime, int DelayTime) +{ + unsigned long AssertDelay, WaitDelay; + int RtnCode; + /******************************************************************** + * Set defaults, Assert is .5 second, Wait is 3 seconds. + ********************************************************************/ + if (AssertTime == 0) AssertDelay = ( 5 * HZ)/10; + else AssertDelay = (AssertTime*HZ)/10; + if (WaitDelay == 0) WaitDelay = (30 * HZ)/10; + else WaitDelay = (DelayTime* HZ)/10; + + /******************************************************************** + * Assert reset, wait, de-assert reset, wait for IOA to reset. + * - Don't waste the CPU time on jiffies. + ********************************************************************/ + RtnCode = pci_set_reset(PciDev,1); + if (RtnCode == 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(AssertDelay); /* Sleep for the time */ + RtnCode = pci_set_reset(PciDev,0); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(WaitDelay); + } + if (RtnCode == 0) { + PCIFR( "Bus%3d, Device%3d, Reset\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn) ); + } + else { + printk("PCI: Bus%3d, Device%3d, Reset Failed:0x%04X\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn),RtnCode ); + PCIFR( "Bus%3d, Device%3d, Reset Failed:0x%04X\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn),RtnCode ); + } + return RtnCode; +} + +/***************************************************** + * Dump Resource information + *****************************************************/ +void dumpResources(struct resource* Resource) +{ + if(Resource != NULL) { + int Flags = 0x00000F00 & Resource->flags; + if(Resource->start == 0 && Resource->end == 0) return; + else if(Resource->start == Resource->end ) return; + else { + if (Flags == IORESOURCE_IO) udbg_printf("IO.:"); + else if(Flags == IORESOURCE_MEM) udbg_printf("MEM:"); + else if(Flags == IORESOURCE_IRQ) udbg_printf("IRQ:"); + else udbg_printf("0x%02X:",Resource->flags); + + } + udbg_printf("0x%016LX / 0x%016LX (0x%08X)\n", + Resource->start, Resource->end, Resource->end - Resource->start); + } +} + +int resourceSize(struct resource* Resource) +{ + if(Resource->start == 0 && Resource->end == 0) return 0; + else if(Resource->start == Resource->end ) return 0; + else return (Resource->end-1)-Resource->start; +} + + +/***************************************************** + * Dump PHB information for Debug + *****************************************************/ +void dumpPci_Controller(struct pci_controller* phb) +{ + udbg_printf("\tpci_controller= 0x%016LX\n", phb); + if (phb != NULL) { + udbg_printf("\twhat & type = %s 0x%02X\n ",phb->what,phb->type); + udbg_printf("\tbus = "); + if (phb->bus != NULL) udbg_printf("0x%02X\n", phb->bus->number); + else udbg_printf("\n"); + udbg_printf("\tarch_data = 0x%016LX\n", phb->arch_data); + udbg_printf("\tfirst_busno = 0x%02X\n", phb->first_busno); + udbg_printf("\tlast_busno = 0x%02X\n", phb->last_busno); + udbg_printf("\tio_base_virt* = 0x%016LX\n", phb->io_base_virt); + udbg_printf("\tio_base_phys = 0x%016LX\n", phb->io_base_phys); + udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset); + udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset); + + udbg_printf("\tcfg_addr = 0x%016LX\n", phb->cfg_addr); + udbg_printf("\tcfg_data = 0x%016LX\n", phb->cfg_data); + udbg_printf("\tphb_regs = 0x%016LX\n", phb->phb_regs); + udbg_printf("\tchip_regs = 0x%016LX\n", phb->chip_regs); + + + udbg_printf("\tResources\n"); + dumpResources(&phb->io_resource); + if (phb->mem_resource_count > 0) dumpResources(&phb->mem_resources[0]); + if (phb->mem_resource_count > 1) dumpResources(&phb->mem_resources[1]); + if (phb->mem_resource_count > 2) dumpResources(&phb->mem_resources[2]); + + udbg_printf("\tglobal_num = 0x%02X\n", phb->global_number); + udbg_printf("\tlocal_num = 0x%02X\n", phb->local_number); + } +} + +/***************************************************** + * Dump PHB information for Debug + *****************************************************/ +void dumpPci_Bus(struct pci_bus* Pci_Bus) +{ + int i; + udbg_printf("\tpci_bus = 0x%016LX \n",Pci_Bus); + if (Pci_Bus != NULL) { + + udbg_printf("\tnumber = 0x%02X \n",Pci_Bus->number); + udbg_printf("\tprimary = 0x%02X \n",Pci_Bus->primary); + udbg_printf("\tsecondary = 0x%02X \n",Pci_Bus->secondary); + udbg_printf("\tsubordinate = 0x%02X \n",Pci_Bus->subordinate); + + for (i=0;i<4;++i) { + if(Pci_Bus->resource[i] == NULL) continue; + if(Pci_Bus->resource[i]->start == 0 && Pci_Bus->resource[i]->end == 0) break; + udbg_printf("\tResources[%d]",i); + dumpResources(Pci_Bus->resource[i]); + } + } +} + +/***************************************************** + * Dump Device information for Debug + *****************************************************/ +void dumpPci_Dev(struct pci_dev* Pci_Dev) +{ + int i; + udbg_printf("\tpci_dev* = 0x%p\n",Pci_Dev); + if ( Pci_Dev == NULL ) return; + udbg_printf("\tname = %s \n",Pci_Dev->name); + udbg_printf("\tbus* = 0x%p\n",Pci_Dev->bus); + udbg_printf("\tsysdata* = 0x%p\n",Pci_Dev->sysdata); + udbg_printf("\tDevice = 0x%4X%02X:%02X.%02X 0x%04X:%04X\n", + PCI_GET_PHB_NUMBER(Pci_Dev), + PCI_GET_BUS_NUMBER(Pci_Dev), + PCI_SLOT(Pci_Dev->devfn), + PCI_FUNC(Pci_Dev->devfn), + Pci_Dev->vendor, + Pci_Dev->device); + udbg_printf("\tHdr/Irq = 0x%02X/0x%02X \n",Pci_Dev->hdr_type,Pci_Dev->irq); + for (i=0;iresource[i].start == 0 && Pci_Dev->resource[i].end == 0) continue; + udbg_printf("\tResources[%d] ",i); + dumpResources(&Pci_Dev->resource[i]); + } + dumpResources(&Pci_Dev->resource[i]); +} diff -urN linux-2.4.18/arch/ppc64/kernel/pci.h linux-2.4.19-pre5/arch/ppc64/kernel/pci.h --- linux-2.4.18/arch/ppc64/kernel/pci.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pci.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,119 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef __PPC_KERNEL_PCI_H__ +#define __PPC_KERNEL_PCI_H__ + +#include +#include + +extern unsigned long isa_io_base; +extern unsigned long isa_mem_base; +extern unsigned long pci_dram_offset; + +/******************************************************************* + * Platform independant variables referenced. + ******************************************************************* + * Set pci_assign_all_busses to 1 if you want the kernel to re-assign + * all PCI bus numbers. + *******************************************************************/ +extern int pci_assign_all_busses; + +extern struct pci_controller* pci_alloc_pci_controller(char *model, enum phb_types controller_type); +extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node); + +extern struct pci_controller* hose_head; +extern struct pci_controller** hose_tail; +/* PHB's are also in a table. */ +#define PCI_MAX_PHB 64 +extern int global_phb_number; +extern struct pci_controller *phbtab[]; + +/******************************************************************* + * Platform functions that are brand specific implementation. + *******************************************************************/ +extern unsigned long find_and_init_phbs(void); + +extern void fixup_resources(struct pci_dev *dev); +extern void ppc64_pcibios_init(void); + +extern int pci_set_reset(struct pci_dev*,int); +extern int device_Location(struct pci_dev*,char*); +extern int format_device_location(struct pci_dev*,char*, int ); + +extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ + +/******************************************************************* + * PCI device_node operations + *******************************************************************/ +struct device_node; +typedef void *(*traverse_func)(struct device_node *me, void *data); +void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data); +void *traverse_all_pci_devices(traverse_func pre); + +void pci_devs_phb_init(void); +void pci_fix_bus_sysdata(void); +struct device_node *fetch_dev_dn(struct pci_dev *dev); + +void iSeries_pcibios_init_early(void); +void pSeries_pcibios_init_early(void); +void pSeries_pcibios_init(void); + +/* Get a device_node from a pci_dev. This code must be fast except in the case + * where the sysdata is incorrect and needs to be fixed up (hopefully just once) + */ +static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev) +{ + struct device_node *dn = (struct device_node *)(dev->sysdata); + if (dn->devfn == dev->devfn && dn->busno == dev->bus->number) + return dn; /* fast path. sysdata is good */ + else + return fetch_dev_dn(dev); +} +/* Use this macro after the PCI bus walk for max performance when it + * is known that sysdata is correct. + */ +#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata)) + + +/******************************************************************* + * Platform configuration flags.. (Live in pci.c) + *******************************************************************/ +extern int Pci_Large_Bus_System; /* System has > 256 buses */ +extern int Pci_Manage_Phb_Space; /* Manage Phb Space for IOAs*/ + +/******************************************************************* + * Helper macros for extracting data from pci structures. + * PCI_GET_PHB_PTR(struct pci_dev*) returns the Phb pointer. + * PCI_GET_PHB_NUMBER(struct pci_dev*) returns the Phb number. + * PCI_GET_BUS_NUMBER(struct pci_dev*) returns the bus number. + *******************************************************************/ +#define PCI_GET_PHB_PTR(dev) (((struct device_node *)(dev)->sysdata)->phb) +#define PCI_GET_PHB_NUMBER(dev) (((dev)->bus->number&0x00FFFF00)>>8) +#define PCI_GET_BUS_NUMBER(dev) ((dev)->bus->number&0x0000FF) + +/******************************************************************* + * Pci Flight Recorder support. + *******************************************************************/ +#define PCIFR(...) fr_Log_Entry(PciFr,__VA_ARGS__); +extern struct flightRecorder* PciFr; +extern int Pci_Trace_Flag; + +/******************************************************************* + * Debugging Routines. + *******************************************************************/ +extern void dumpResources(struct resource* Resource); +extern void dumpPci_Controller(struct pci_controller* phb); +extern void dumpPci_Bus(struct pci_bus* Pci_Bus); +extern void dumpPci_Dev(struct pci_dev* Pci_Dev); + +extern void dump_Phb_tree(void); +extern void dump_Bus_tree(void); +extern void dump_Dev_tree(void); + +#endif /* __PPC_KERNEL_PCI_H__ */ diff -urN linux-2.4.18/arch/ppc64/kernel/pci_dma.c linux-2.4.19-pre5/arch/ppc64/kernel/pci_dma.c --- linux-2.4.18/arch/ppc64/kernel/pci_dma.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pci_dma.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1474 @@ +/* + * pci_dma.c + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * + * Dynamic DMA mapping support. + * + * Manages the TCE space assigned to this partition. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "pci.h" + +/* #define DEBUG_TCE 1 */ +/* #define MONITOR_TCE 1 */ /* Turn on to sanity check TCE generation. */ + + +/* Initialize so this guy does not end up in the BSS section. + * Only used to pass OF initialization data set in prom.c into the main + * kernel code -- data ultimately copied into tceTables[]. + */ +extern struct _of_tce_table of_tce_table[]; + +extern struct pci_controller* hose_head; +extern struct pci_controller** hose_tail; +extern struct list_head iSeries_Global_Device_List; + +struct TceTable virtBusVethTceTable; /* Tce table for virtual ethernet */ +struct TceTable virtBusVioTceTable; /* Tce table for virtual I/O */ + +struct iSeries_Device_Node iSeries_veth_dev_node = { LogicalSlot: 0xFF, DevTceTable: &virtBusVethTceTable }; +struct iSeries_Device_Node iSeries_vio_dev_node = { LogicalSlot: 0xFF, DevTceTable: &virtBusVioTceTable }; + +struct pci_dev iSeries_veth_dev_st = { sysdata: &iSeries_veth_dev_node }; +struct pci_dev iSeries_vio_dev_st = { sysdata: &iSeries_vio_dev_node }; + +struct pci_dev * iSeries_veth_dev = &iSeries_veth_dev_st; +struct pci_dev * iSeries_vio_dev = &iSeries_vio_dev_st; + +/* Device TceTable is stored in Device Node */ +/* struct TceTable * tceTables[256]; */ /* Tce tables for 256 busses + * Bus 255 is the virtual bus + * zero indicates no bus defined + */ +/* allocates a contiguous range of tces (power-of-2 size) */ +static inline long alloc_tce_range(struct TceTable *, + unsigned order ); + +/* allocates a contiguous range of tces (power-of-2 size) + * assumes lock already held + */ +static long alloc_tce_range_nolock(struct TceTable *, + unsigned order ); + +/* frees a contiguous range of tces (power-of-2 size) */ +static inline void free_tce_range(struct TceTable *, + long tcenum, + unsigned order ); + +/* frees a contiguous rnage of tces (power-of-2 size) + * assumes lock already held + */ +void free_tce_range_nolock(struct TceTable *, + long tcenum, + unsigned order ); + +/* allocates a range of tces and sets them to the pages */ +static inline dma_addr_t get_tces( struct TceTable *, + unsigned order, + void *page, + unsigned numPages, + int direction ); + +static long test_tce_range( struct TceTable *, + long tcenum, + unsigned order ); + +static unsigned fill_scatterlist_sg(struct scatterlist *sg, int nents, + dma_addr_t dma_addr, + unsigned long numTces ); + +static unsigned long num_tces_sg( struct scatterlist *sg, + int nents ); + +static dma_addr_t create_tces_sg( struct TceTable *tbl, + struct scatterlist *sg, + int nents, + unsigned numTces, + int direction ); + +static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode, + struct TceTable *tce_table_parms ); + +static void getTceTableParmsPSeries( struct pci_controller *phb, + struct device_node *dn, + struct TceTable *tce_table_parms ); + +static void getTceTableParmsPSeriesLP(struct pci_controller *phb, + struct device_node *dn, + struct TceTable *newTceTable ); + +static struct TceTable* findHwTceTable(struct TceTable * newTceTable ); + +void create_pci_bus_tce_table( unsigned long token ); + +u8 iSeries_Get_Bus( struct pci_dev * dv ) +{ + return 0; +} + +static inline struct TceTable *get_tce_table(struct pci_dev *dev) +{ + if (!dev) + dev = ppc64_isabridge_dev; + if (!dev) + return NULL; + if ( _machine == _MACH_iSeries ) { + return ISERIES_DEVNODE(dev)->DevTceTable; + } else { + return PCI_GET_DN(dev)->tce_table; + } +} + +static unsigned long __inline__ count_leading_zeros64( unsigned long x ) +{ + unsigned long lz; + asm("cntlzd %0,%1" : "=r"(lz) : "r"(x)); + return lz; +} + +static void tce_build_iSeries(struct TceTable *tbl, long tcenum, + unsigned long uaddr, int direction ) +{ + u64 setTceRc; + union Tce tce; + + PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", + tcenum, tbl, tbl->index); + + tce.wholeTce = 0; + tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT; + + /* If for virtual bus */ + if ( tbl->tceType == TCE_VB ) { + tce.tceBits.valid = 1; + tce.tceBits.allIo = 1; + if ( direction != PCI_DMA_TODEVICE ) + tce.tceBits.readWrite = 1; + } else { + /* If for PCI bus */ + tce.tceBits.readWrite = 1; // Read allowed + if ( direction != PCI_DMA_TODEVICE ) + tce.tceBits.pciWrite = 1; + } + + setTceRc = HvCallXm_setTce((u64)tbl->index, + (u64)tcenum, + tce.wholeTce ); + if(setTceRc) { + panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", setTceRc); + } +} + +static void tce_build_pSeries(struct TceTable *tbl, long tcenum, + unsigned long uaddr, int direction ) +{ + union Tce tce; + union Tce *tce_addr; + + PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", + tcenum, tbl, tbl->index); + + tce.wholeTce = 0; + tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT; + + tce.tceBits.readWrite = 1; // Read allowed + if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1; + + tce_addr = ((union Tce *)tbl->base) + tcenum; + *tce_addr = (union Tce)tce.wholeTce; + + /* Make sure the update is visible to hardware. */ + __asm__ __volatile__ ("sync" : : : "memory"); +} + +/* + * Build a TceTable structure. This contains a multi-level bit map which + * is used to manage allocation of the tce space. + */ +static struct TceTable *build_tce_table( struct TceTable * tbl ) +{ + unsigned long bits, bytes, totalBytes; + unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS]; + unsigned i, k, m; + unsigned char * pos, * p, b; + + PPCDBG(PPCDBG_TCEINIT, "build_tce_table: tbl = 0x%lx\n", tbl); + spin_lock_init( &(tbl->lock) ); + + tbl->mlbm.maxLevel = 0; + + /* Compute number of bits and bytes for each level of the + * multi-level bit map + */ + totalBytes = 0; + bits = tbl->size * (PAGE_SIZE / sizeof( union Tce )); + + for ( i=0; imlbm.level[i].map = pos; + tbl->mlbm.maxLevel = i; + + if ( numBits[i] & 1 ) { + p = pos + numBytes[i] - 1; + m = (( numBits[i] % 8) - 1) & 7; + *p = 0x80 >> m; + PPCDBG(PPCDBG_TCEINIT, "build_tce_table: level %d last bit %x\n", i, 0x80>>m ); + } + } + else + tbl->mlbm.level[i].map = 0; + pos += numBytes[i]; + tbl->mlbm.level[i].numBits = numBits[i]; + tbl->mlbm.level[i].numBytes = numBytes[i]; + } + + /* For the highest level, turn on all the bits */ + + i = tbl->mlbm.maxLevel; + p = tbl->mlbm.level[i].map; + m = numBits[i]; + PPCDBG(PPCDBG_TCEINIT, "build_tce_table: highest level (%d) has all bits set\n", i); + for (k=0; k= 8 ) { + /* handle full bytes */ + *p++ = 0xff; + m -= 8; + } + else if(m>0) { + /* handle the last partial byte */ + b = 0x80; + *p = 0; + while (m) { + *p |= b; + b >>= 1; + --m; + } + } else { + break; + } + } + + return tbl; +} + +static inline long alloc_tce_range( struct TceTable *tbl, unsigned order ) +{ + long retval; + unsigned long flags; + + /* Lock the tce allocation bitmap */ + spin_lock_irqsave( &(tbl->lock), flags ); + + /* Do the actual work */ + retval = alloc_tce_range_nolock( tbl, order ); + + /* Unlock the tce allocation bitmap */ + spin_unlock_irqrestore( &(tbl->lock), flags ); + + return retval; +} + +static long alloc_tce_range_nolock( struct TceTable *tbl, unsigned order ) +{ + unsigned long numBits, numBytes; + unsigned long i, bit, block, mask; + long tcenum; + u64 * map; + + /* If the order (power of 2 size) requested is larger than our + * biggest, indicate failure + */ + if(order >= NUM_TCE_LEVELS) { + /* This can happen if block of TCE's are not found. This code */ + /* maybe in a recursive loop looking up the bit map for the range.*/ + panic("PCI_DMA: alloc_tce_range_nolock: invalid order: %d\n",order); + } + + numBits = tbl->mlbm.level[order].numBits; + numBytes = tbl->mlbm.level[order].numBytes; + map = (u64 *)tbl->mlbm.level[order].map; + + /* Initialize return value to -1 (failure) */ + tcenum = -1; + + /* Loop through the bytes of the bitmap */ + for (i=0; imlbm.maxLevel ) { + PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: trying next bigger size\n" ); + } + else { + panic("PCI_DMA: alloc_tce_range_nolock: maximum size reached...failing\n"); + } + } +#endif + + /* If no block of the requested size was found, try the next + * size bigger. If one of those is found, return the second + * half of the block to freespace and keep the first half + */ + if((tcenum == -1) && (order < (NUM_TCE_LEVELS - 1))) { + tcenum = alloc_tce_range_nolock( tbl, order+1 ); + if ( tcenum != -1 ) { + free_tce_range_nolock( tbl, tcenum+(1<lock), flags ); + + /* Do the actual work */ + free_tce_range_nolock( tbl, tcenum, order ); + + /* Unlock the tce allocation bitmap */ + spin_unlock_irqrestore( &(tbl->lock), flags ); + +} + +void free_tce_range_nolock(struct TceTable *tbl, + long tcenum, unsigned order ) +{ + unsigned long block; + unsigned byte, bit, mask, b; + unsigned char * map, * bytep; + + if (order >= NUM_TCE_LEVELS) { + panic("PCI_DMA: free_tce_range: invalid order: %d\n",order); + return; + } + + block = tcenum >> order; + +#ifdef MONITOR_TCE + if ( tcenum != (block << order ) ) { + printk("PCI_DMA: Free_tce_range: tcenum %lx misaligned for order %x\n",tcenum, order); + return; + } + if ( block >= tbl->mlbm.level[order].numBits ) { + printk("PCI_DMA: Free_tce_range: tcenum %lx is outside the range of this map (order %x, numBits %lx\n", + tcenum, order, tbl->mlbm.level[order].numBits ); + return; + } + if ( test_tce_range( tbl, tcenum, order ) ) { + printk("PCI_DMA: Freeing range not allocated: tTceTable %p, tcenum %lx, order %x\n",tbl, tcenum, order ); + return; + } +#endif + + map = tbl->mlbm.level[order].map; + byte = block / 8; + bit = block % 8; + mask = 0x80 >> bit; + bytep = map + byte; + +#ifdef DEBUG_TCE + PPCDBG(PPCDBG_TCE,"free_tce_range_nolock: freeing block %ld (byte=%d, bit=%d) of order %d\n", + block, byte, bit, order); +#endif + +#ifdef MONITOR_TCE + if ( *bytep & mask ) { + panic("PCI_DMA: Tce already free: TceTable %p, tcenum %lx, order %x\n",tbl,tcenum,order); + } +#endif + + *bytep |= mask; + + /* If there is a higher level in the bit map than this we may be + * able to buddy up this block with its partner. + * If this is the highest level we can't buddy up + * If this level has an odd number of bits and + * we are freeing the last block we can't buddy up + * Don't buddy up if it's in the first 1/4 of the level + */ + if (( block > (tbl->mlbm.level[order].numBits/4) ) && + (( block < tbl->mlbm.level[order].numBits-1 ) || + ( 0 == ( tbl->mlbm.level[order].numBits & 1)))) { + /* See if we can buddy up the block we just freed */ + bit &= 6; /* get to the first of the buddy bits */ + mask = 0xc0 >> bit; /* build two bit mask */ + b = *bytep & mask; /* Get the two bits */ + if ( 0 == (b ^ mask) ) { /* If both bits are on */ + /* both of the buddy blocks are free we can combine them */ + *bytep ^= mask; /* turn off the two bits */ + block = ( byte * 8 ) + bit; /* block of first of buddies */ + tcenum = block << order; + /* free the buddied block */ + PPCDBG(PPCDBG_TCE, + "free_tce_range: buddying blocks %ld & %ld\n", + block, block+1); + free_tce_range_nolock( tbl, tcenum, order+1 ); + } + } +} + +static long test_tce_range( struct TceTable *tbl, long tcenum, unsigned order ) +{ + unsigned long block; + unsigned byte, bit, mask, b; + long retval, retLeft, retRight; + unsigned char * map; + + map = tbl->mlbm.level[order].map; + block = tcenum >> order; + byte = block / 8; /* Byte within bitmap */ + bit = block % 8; /* Bit within byte */ + mask = 0x80 >> bit; + b = (*(map+byte) & mask ); /* 0 if block is allocated, else free */ + if ( b ) + retval = 1; /* 1 == block is free */ + else + retval = 0; /* 0 == block is allocated */ + /* Test bits at all levels below this to ensure that all agree */ + + if (order) { + retLeft = test_tce_range( tbl, tcenum, order-1 ); + retRight = test_tce_range( tbl, tcenum+(1<<(order-1)), order-1 ); + if ( retLeft || retRight ) { + retval = 2; + } + } + + /* Test bits at all levels above this to ensure that all agree */ + + return retval; +} + +static inline dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int direction ) +{ + long tcenum; + unsigned long uaddr; + unsigned i; + dma_addr_t retTce = NO_TCE; + + uaddr = (unsigned long)page & PAGE_MASK; + + /* Allocate a range of tces */ + tcenum = alloc_tce_range( tbl, order ); + if ( tcenum != -1 ) { + /* We got the tces we wanted */ + tcenum += tbl->startOffset; /* Offset into real TCE table */ + retTce = tcenum << PAGE_SHIFT; /* Set the return dma address */ + /* Setup a tce for each page */ + for (i=0; isize * (PAGE_SIZE / sizeof(union Tce))) - 1; + + tcenum = dma_addr >> PAGE_SHIFT; + + freeTce = tcenum - tbl->startOffset; + + if ( freeTce > maxTcenum ) { + PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n"); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", tcenum); + PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); + PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl); + PPCDBG(PPCDBG_TCE, "\tbus# = 0x%lx\n", (u64)tbl->busNumber ); + PPCDBG(PPCDBG_TCE, "\tsize = 0x%lx\n", (u64)tbl->size); + PPCDBG(PPCDBG_TCE, "\tstartOff = 0x%lx\n", (u64)tbl->startOffset ); + PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index); + return; + } + + for (i=0; iindex, + (u64)tcenum, + tce.wholeTce ); + + if ( setTceRc ) { + panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", setTceRc); + } + ++tcenum; + } + free_tce_range( tbl, freeTce, order ); +} + +static void tce_free_pSeries(struct TceTable *tbl, dma_addr_t dma_addr, + unsigned order, unsigned numPages) +{ + long tcenum, freeTce, maxTcenum; + unsigned i; + union Tce tce; + union Tce *tce_addr; + + maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1; + + tcenum = dma_addr >> PAGE_SHIFT; + // tcenum -= tbl->startOffset; + + freeTce = tcenum - tbl->startOffset; + + if ( freeTce > maxTcenum ) { + PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n"); + PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", tcenum); + PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); + PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl); + PPCDBG(PPCDBG_TCE, "\tbus# = 0x%lx\n", + (u64)tbl->busNumber ); + PPCDBG(PPCDBG_TCE, "\tsize = 0x%lx\n", (u64)tbl->size); + PPCDBG(PPCDBG_TCE, "\tstartOff = 0x%lx\n", + (u64)tbl->startOffset ); + PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index); + return; + } + + for (i=0; ibase) + tcenum; + *tce_addr = (union Tce)tce.wholeTce; + + ++tcenum; + } + + /* Make sure the update is visible to hardware. */ + __asm__ __volatile__ ("sync" : : : "memory"); + + free_tce_range( tbl, freeTce, order ); +} + +void __init create_virtual_bus_tce_table(void) +{ + struct TceTable *t; + struct TceTableManagerCB virtBusTceTableParms; + u64 absParmsPtr; + + virtBusTceTableParms.busNumber = 255; /* Bus 255 is the virtual bus */ + virtBusTceTableParms.virtualBusFlag = 0xff; /* Ask for virtual bus */ + + absParmsPtr = virt_to_absolute( (u64)&virtBusTceTableParms ); + HvCallXm_getTceTableParms( absParmsPtr ); + + virtBusVethTceTable.size = virtBusTceTableParms.size / 2; + virtBusVethTceTable.busNumber = virtBusTceTableParms.busNumber; + virtBusVethTceTable.startOffset = virtBusTceTableParms.startOffset; + virtBusVethTceTable.index = virtBusTceTableParms.index; + virtBusVethTceTable.tceType = TCE_VB; + + virtBusVioTceTable.size = virtBusTceTableParms.size - virtBusVethTceTable.size; + virtBusVioTceTable.busNumber = virtBusTceTableParms.busNumber; + virtBusVioTceTable.startOffset = virtBusTceTableParms.startOffset + + virtBusVethTceTable.size * (PAGE_SIZE/sizeof(union Tce)); + virtBusVioTceTable.index = virtBusTceTableParms.index; + virtBusVioTceTable.tceType = TCE_VB; + + t = build_tce_table( &virtBusVethTceTable ); + if ( t ) { + /* tceTables[255] = t; */ + //VirtBusVethTceTable = t; + printk( "Virtual Bus VETH TCE table built successfully.\n"); + printk( " TCE table size = %ld entries\n", + (unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) ); + printk( " TCE table token = %d\n", + (unsigned)t->index ); + printk( " TCE table start entry = 0x%lx\n", + (unsigned long)t->startOffset ); + } + else printk( "Virtual Bus VETH TCE table failed.\n"); + + t = build_tce_table( &virtBusVioTceTable ); + if ( t ) { + //VirtBusVioTceTable = t; + printk( "Virtual Bus VIO TCE table built successfully.\n"); + printk( " TCE table size = %ld entries\n", + (unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) ); + printk( " TCE table token = %d\n", + (unsigned)t->index ); + printk( " TCE table start entry = 0x%lx\n", + (unsigned long)t->startOffset ); + } + else printk( "Virtual Bus VIO TCE table failed.\n"); +} + +void create_tce_tables_for_buses(struct list_head *bus_list) +{ + struct pci_controller* phb; + struct device_node *dn, *first_dn; + int num_slots, num_slots_ilog2; + int first_phb = 1; + + for (phb=hose_head;phb;phb=phb->next) { + first_dn = ((struct device_node *)phb->arch_data)->child; + /* Carve 2GB into the largest dma_window_size possible */ + for (dn = first_dn, num_slots = 0; dn != NULL; dn = dn->sibling) + num_slots++; + num_slots_ilog2 = __ilog2(num_slots); + if ((1<dma_window_size = 1 << (22 - num_slots_ilog2); + /* Reserve 16MB of DMA space on the first PHB. + * We should probably be more careful and use firmware props. + * In reality this space is remapped, not lost. But we don't + * want to get that smart to handle it -- too much work. + */ + phb->dma_window_base_cur = first_phb ? (1 << 12) : 0; + first_phb = 0; + for (dn = first_dn, num_slots = 0; dn != NULL; dn = dn->sibling) { + create_pci_bus_tce_table((unsigned long)dn); + } + } +} + +void create_tce_tables_for_busesLP(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + struct device_node *busdn; + u32 *dma_window; + for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + busdn = PCI_GET_DN(bus); + /* NOTE: there should never be a window declared on a bus when + * child devices also have a window. If this should ever be + * architected, we probably want children to have priority. + * In reality, the PHB containing ISA has the property, but otherwise + * it is the pci-bridges that have the property. + */ + dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0); + if (dma_window) { + /* Busno hasn't been copied yet. + * Do it now because getTceTableParmsPSeriesLP needs it. + */ + busdn->busno = bus->number; + create_pci_bus_tce_table((unsigned long)busdn); + } else + create_tce_tables_for_busesLP(&bus->children); + } +} + +void create_tce_tables(void) { + struct pci_dev *dev; + struct device_node *dn, *mydn; + + if (_machine == _MACH_pSeriesLP) { + create_tce_tables_for_busesLP(&pci_root_buses); + } + else { + create_tce_tables_for_buses(&pci_root_buses); + } + /* Now copy the tce_table ptr from the bus devices down to every + * pci device_node. This means get_tce_table() won't need to search + * up the device tree to find it. + */ + pci_for_each_dev(dev) { + mydn = dn = PCI_GET_DN(dev); + while (dn && dn->tce_table == NULL) + dn = dn->parent; + if (dn) { + mydn->tce_table = dn->tce_table; + } + } +} + + +/* + * iSeries token = iSeries_device_Node* + * pSeries token = pci_controller* + * + */ +void create_pci_bus_tce_table( unsigned long token ) { + struct TceTable * newTceTable; + + PPCDBG(PPCDBG_TCE, "Entering create_pci_bus_tce_table.\n"); + PPCDBG(PPCDBG_TCE, "\ttoken = 0x%lx\n", token); + + newTceTable = (struct TceTable *)kmalloc( sizeof(struct TceTable), GFP_KERNEL ); + + /*****************************************************************/ + /* For the iSeries machines, the HvTce Table can be one of three */ + /* flavors, */ + /* - Single bus TCE table, */ + /* - Tce Table Share between buses, */ + /* - Tce Table per logical slot. */ + /*****************************************************************/ + if(_machine == _MACH_iSeries) { + + struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token; + getTceTableParmsiSeries(DevNode,newTceTable); + + /* Look for existing TCE table for this device. */ + DevNode->DevTceTable = findHwTceTable(newTceTable ); + if( DevNode->DevTceTable == NULL) { + DevNode->DevTceTable = build_tce_table( newTceTable ); + } + else { + /* We're using a shared table, free this new one. */ + kfree(newTceTable); + } + printk("Pci Device 0x%p TceTable: %p\n",DevNode,DevNode->DevTceTable); + return; + } + /* pSeries Leg */ + else { + struct device_node *dn; + struct pci_controller *phb; + + dn = (struct device_node *)token; + phb = dn->phb; + if (_machine == _MACH_pSeries) + getTceTableParmsPSeries(phb, dn, newTceTable); + else + getTceTableParmsPSeriesLP(phb, dn, newTceTable); + + dn->tce_table = build_tce_table( newTceTable ); + } +} + +/***********************************************************************/ +/* This function compares the known Tce tables to find a TceTable that */ +/* has already been built for hardware TCEs. */ +/* Search the complete(all devices) for a TCE table assigned. If the */ +/* startOffset, index, and size match, then the TCE for this device has*/ +/* already been built and it should be shared with this device */ +/***********************************************************************/ +static struct TceTable* findHwTceTable(struct TceTable * newTceTable ) +{ + struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next; + /* Cache the compare values. */ + u64 startOffset = newTceTable->startOffset; + u64 index = newTceTable->index; + u64 size = newTceTable->size; + + while(Device_Node_Ptr != &iSeries_Global_Device_List) { + struct iSeries_Device_Node* CmprNode = (struct iSeries_Device_Node*)Device_Node_Ptr; + if( CmprNode->DevTceTable != NULL && + CmprNode->DevTceTable->tceType == TCE_PCI) { + if( CmprNode->DevTceTable->startOffset == startOffset && + CmprNode->DevTceTable->index == index && + CmprNode->DevTceTable->size == size ) { + printk("PCI TCE table matches 0x%p \n",CmprNode->DevTceTable); + return CmprNode->DevTceTable; + } + } + /* Get next Device Node in List */ + Device_Node_Ptr = Device_Node_Ptr->next; + } + return NULL; +} + +/***********************************************************************/ +/* Call Hv with the architected data structure to get TCE table info. */ +/* info. Put the returned data into the Linux representation of the */ +/* TCE table data. */ +/* The Hardware Tce table comes in three flavors. */ +/* 1. TCE table shared between Buses. */ +/* 2. TCE table per Bus. */ +/* 3. TCE Table per IOA. */ +/***********************************************************************/ +static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode, + struct TceTable* newTceTable ) +{ + struct TceTableManagerCB* pciBusTceTableParms = (struct TceTableManagerCB*)kmalloc( sizeof(struct TceTableManagerCB), GFP_KERNEL ); + if(pciBusTceTableParms == NULL) panic("PCI_DMA: TCE Table Allocation failed."); + + memset( (void*)pciBusTceTableParms,0,sizeof(struct TceTableManagerCB) ); + pciBusTceTableParms->busNumber = ISERIES_BUS(DevNode); + pciBusTceTableParms->logicalSlot = DevNode->LogicalSlot; + pciBusTceTableParms->virtualBusFlag = 0; + + HvCallXm_getTceTableParms( REALADDR(pciBusTceTableParms) ); + + /* PciTceTableParms Bus:0x18 Slot:0x04 Start:0x000000 Offset:0x04c000 Size:0x0020 */ + printk("PciTceTableParms Bus:0x%02lx Slot:0x%02x Start:0x%06lx Offset:0x%06lx Size:0x%04lx\n", + pciBusTceTableParms->busNumber, + pciBusTceTableParms->logicalSlot, + pciBusTceTableParms->start, + pciBusTceTableParms->startOffset, + pciBusTceTableParms->size); + + newTceTable->size = pciBusTceTableParms->size; + newTceTable->busNumber = pciBusTceTableParms->busNumber; + newTceTable->startOffset = pciBusTceTableParms->startOffset; + newTceTable->index = pciBusTceTableParms->index; + newTceTable->tceType = TCE_PCI; + + kfree(pciBusTceTableParms); +} + +static void getTceTableParmsPSeries(struct pci_controller *phb, + struct device_node *dn, + struct TceTable *newTceTable ) { + phandle node; + unsigned long i; + + node = ((struct device_node *)(phb->arch_data))->node; + + PPCDBG(PPCDBG_TCEINIT, "getTceTableParms: start\n"); + PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table = 0x%lx\n", of_tce_table); + PPCDBG(PPCDBG_TCEINIT, "\tphb = 0x%lx\n", phb); + PPCDBG(PPCDBG_TCEINIT, "\tdn = 0x%lx\n", dn); + PPCDBG(PPCDBG_TCEINIT, "\tdn->name = %s\n", dn->name); + PPCDBG(PPCDBG_TCEINIT, "\tdn->full_name= %s\n", dn->full_name); + PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable = 0x%lx\n", newTceTable); + PPCDBG(PPCDBG_TCEINIT, "\tdma_window_size = 0x%lx\n", phb->dma_window_size); + + i = 0; + while(of_tce_table[i].node) { + PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].node = 0x%lx\n", + i, of_tce_table[i].node); + PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].base = 0x%lx\n", + i, of_tce_table[i].base); + PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].size = 0x%lx\n", + i, of_tce_table[i].size >> PAGE_SHIFT); + PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data->node = 0x%lx\n", + node); + + if(of_tce_table[i].node == node) { + memset((void *)of_tce_table[i].base, + 0, of_tce_table[i].size); + newTceTable->busNumber = phb->bus->number; + + /* Units of tce entries. */ + newTceTable->startOffset = phb->dma_window_base_cur; + + /* Adjust the current table offset to the next */ + /* region. Measured in TCE entries. Force an */ + /* alignment to the size alloted per IOA. This */ + /* makes it easier to remove the 1st 16MB. */ + phb->dma_window_base_cur += (phb->dma_window_size>>3); + phb->dma_window_base_cur &= + ~((phb->dma_window_size>>3)-1); + + /* Set the tce table size - measured in units */ + /* of pages of tce table. */ + newTceTable->size = ((phb->dma_window_base_cur - + newTceTable->startOffset) << 3) + >> PAGE_SHIFT; + + /* Test if we are going over 2GB of DMA space. */ + if(phb->dma_window_base_cur > (1 << 19)) { + panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); + } + + newTceTable->base = of_tce_table[i].base; + newTceTable->index = 0; + + PPCDBG(PPCDBG_TCEINIT, + "\tnewTceTable->base = 0x%lx\n", + newTceTable->base); + PPCDBG(PPCDBG_TCEINIT, + "\tnewTceTable->startOffset = 0x%lx" + "(# tce entries)\n", + newTceTable->startOffset); + PPCDBG(PPCDBG_TCEINIT, + "\tnewTceTable->size = 0x%lx" + "(# pages of tce table)\n", + newTceTable->size); + } + i++; + } +} + +/* + * getTceTableParmsPSeriesLP + * + * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. + * + * ToDo: properly interpret the ibm,dma-window property. The definition is: + * logical-bus-number (1 word) + * phys-address (#address-cells words) + * size (#cell-size words) + * + * Currently we hard code these sizes (more or less). + */ +static void getTceTableParmsPSeriesLP(struct pci_controller *phb, + struct device_node *dn, + struct TceTable *newTceTable ) { + u32 *dma_window = (u32 *)get_property(dn, "ibm,dma-window", 0); + if (!dma_window) { + panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name); + } + + newTceTable->busNumber = dn->busno; + newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT; + newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12); + newTceTable->base = 0; + newTceTable->index = dma_window[0]; + PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->busno); + PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name); + PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index = 0x%lx\n", newTceTable->index); + PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset); + PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->size = 0x%lx\n", newTceTable->size); +} + +/* Allocates a contiguous real buffer and creates TCEs over it. + * Returns the virtual address of the buffer and sets dma_handle + * to the dma address (tce) of the first page. + */ +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + struct TceTable * tbl; + void *ret = NULL; + unsigned order, nPages; + dma_addr_t tce; + + PPCDBG(PPCDBG_TCE, "pci_alloc_consistent:\n"); + PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx\n", hwdev); + PPCDBG(PPCDBG_TCE, "\tsize = 0x%16.16lx\n", size); + PPCDBG(PPCDBG_TCE, "\tdma_handle = 0x%16.16lx\n", dma_handle); + + size = PAGE_ALIGN(size); + order = get_order(size); + nPages = 1 << order; + + tbl = get_tce_table(hwdev); + + if ( tbl ) { + /* Alloc enough pages (and possibly more) */ + ret = (void *)__get_free_pages( GFP_ATOMIC, order ); + if ( ret ) { + /* Page allocation succeeded */ + memset(ret, 0, nPages << PAGE_SHIFT); + /* Set up tces to cover the allocated range */ + tce = get_tces( tbl, order, ret, nPages, PCI_DMA_BIDIRECTIONAL ); + if ( tce == NO_TCE ) { + PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tces failed\n" ); + free_pages( (unsigned long)ret, order ); + ret = NULL; + } + else + { + *dma_handle = tce; + } + } + else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order); + } + else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tce_table failed for 0x%016lx\n", hwdev); + + PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle); + PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: return = 0x%16.16lx\n", ret); + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + struct TceTable * tbl; + unsigned order, nPages; + + PPCDBG(PPCDBG_TCE, "pci_free_consistent:\n"); + PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, dma_handle = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, dma_handle, vaddr); + + size = PAGE_ALIGN(size); + order = get_order(size); + nPages = 1 << order; + + if ( order > 10 ) + PPCDBG(PPCDBG_TCE, "pci_free_consistent: order=%d, size=%d, nPages=%d, dma_handle=%016lx, vaddr=%016lx\n", + order, size, nPages, (unsigned long)dma_handle, (unsigned long)vaddr ); + + tbl = get_tce_table(hwdev); + + if ( tbl ) { + ppc_md.tce_free(tbl, dma_handle, order, nPages); + free_pages( (unsigned long)vaddr, order ); + } +} + +/* Creates TCEs for a user provided buffer. The user buffer must be + * contiguous real kernel storage (not vmalloc). The address of the buffer + * passed here is the kernel (virtual) address of the buffer. The buffer + * need not be page aligned, the dma_addr_t returned will point to the same + * byte within the page as vaddr. + */ +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr, + size_t size, int direction ) +{ + struct TceTable * tbl; + dma_addr_t dma_handle = NO_TCE; + unsigned long uaddr; + unsigned order, nPages; + + PPCDBG(PPCDBG_TCE, "pci_map_single:\n"); + PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, direction, vaddr); + if ( direction == PCI_DMA_NONE ) + BUG(); + + uaddr = (unsigned long)vaddr; + nPages = PAGE_ALIGN( uaddr + size ) - ( uaddr & PAGE_MASK ); + order = get_order( nPages & PAGE_MASK ); + nPages >>= PAGE_SHIFT; + + tbl = get_tce_table(hwdev); + + if ( tbl ) { + dma_handle = get_tces( tbl, order, vaddr, nPages, direction ); + dma_handle |= ( uaddr & ~PAGE_MASK ); + } + + return dma_handle; +} + +void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction ) +{ + struct TceTable * tbl; + unsigned order, nPages; + + PPCDBG(PPCDBG_TCE, "pci_unmap_single:\n"); + PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, dma_handle = 0x%16.16lx\n", hwdev, size, direction, dma_handle); + if ( direction == PCI_DMA_NONE ) + BUG(); + + nPages = PAGE_ALIGN( dma_handle + size ) - ( dma_handle & PAGE_MASK ); + order = get_order( nPages & PAGE_MASK ); + nPages >>= PAGE_SHIFT; + + if ( order > 10 ) + PPCDBG(PPCDBG_TCE, "pci_unmap_single: order=%d, size=%d, nPages=%d, dma_handle=%016lx\n", + order, size, nPages, (unsigned long)dma_handle ); + + tbl = get_tce_table(hwdev); + + if ( tbl ) + ppc_md.tce_free(tbl, dma_handle, order, nPages); + +} + +/* Figure out how many TCEs are actually going to be required + * to map this scatterlist. This code is not optimal. It + * takes into account the case where entry n ends in the same + * page in which entry n+1 starts. It does not handle the + * general case of entry n ending in the same page in which + * entry m starts. + */ +static unsigned long num_tces_sg( struct scatterlist *sg, int nents ) +{ + unsigned long nTces, numPages, startPage, endPage, prevEndPage; + unsigned i; + + prevEndPage = 0; + nTces = 0; + + for (i=0; iaddress >> PAGE_SHIFT; + endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT; + numPages = endPage - startPage + 1; + /* Simple optimization: if the previous entry ended + * in the same page in which this entry starts + * then we can reduce the required pages by one. + * This matches assumptions in fill_scatterlist_sg and + * create_tces_sg + */ + if ( startPage == prevEndPage ) + --numPages; + nTces += numPages; + prevEndPage = endPage; + sg++; + } + return nTces; +} + +/* Fill in the dma data in the scatterlist + * return the number of dma sg entries created + */ +static unsigned fill_scatterlist_sg( struct scatterlist *sg, int nents, + dma_addr_t dma_addr , unsigned long numTces) +{ + struct scatterlist *dma_sg; + u32 cur_start_dma; + unsigned long cur_len_dma, cur_end_virt, uaddr; + unsigned num_dma_ents; + + dma_sg = sg; + num_dma_ents = 1; + + /* Process the first sg entry */ + cur_start_dma = dma_addr + ((unsigned long)sg->address & (~PAGE_MASK)); + cur_len_dma = sg->length; + /* cur_end_virt holds the address of the byte immediately after the + * end of the current buffer. + */ + cur_end_virt = (unsigned long)sg->address + cur_len_dma; + /* Later code assumes that unused sg->dma_address and sg->dma_length + * fields will be zero. Other archs seem to assume that the user + * (device driver) guarantees that...I don't want to depend on that + */ + sg->dma_address = sg->dma_length = 0; + + /* Process the rest of the sg entries */ + while (--nents) { + ++sg; + /* Clear possibly unused fields. Note: sg >= dma_sg so + * this can't be clearing a field we've already set + */ + sg->dma_address = sg->dma_length = 0; + + /* Check if it is possible to make this next entry + * contiguous (in dma space) with the previous entry. + */ + + /* The entries can be contiguous in dma space if + * the previous entry ends immediately before the + * start of the current entry (in virtual space) + * or if the previous entry ends at a page boundary + * and the current entry starts at a page boundary. + */ + uaddr = (unsigned long)sg->address; + if ( ( uaddr != cur_end_virt ) && + ( ( ( uaddr | cur_end_virt ) & (~PAGE_MASK) ) || + ( ( uaddr & PAGE_MASK ) == ( ( cur_end_virt-1 ) & PAGE_MASK ) ) ) ) { + /* This entry can not be contiguous in dma space. + * save the previous dma entry and start a new one + */ + dma_sg->dma_address = cur_start_dma; + dma_sg->dma_length = cur_len_dma; + + ++dma_sg; + ++num_dma_ents; + + cur_start_dma += cur_len_dma-1; + /* If the previous entry ends and this entry starts + * in the same page then they share a tce. In that + * case don't bump cur_start_dma to the next page + * in dma space. This matches assumptions made in + * num_tces_sg and create_tces_sg. + */ + if ((uaddr & PAGE_MASK) == ((cur_end_virt-1) & PAGE_MASK)) + cur_start_dma &= PAGE_MASK; + else + cur_start_dma = PAGE_ALIGN(cur_start_dma+1); + cur_start_dma += ( uaddr & (~PAGE_MASK) ); + cur_len_dma = 0; + } + /* Accumulate the length of this entry for the next + * dma entry + */ + cur_len_dma += sg->length; + cur_end_virt = uaddr + sg->length; + } + /* Fill in the last dma entry */ + dma_sg->dma_address = cur_start_dma; + dma_sg->dma_length = cur_len_dma; + + if ((((cur_start_dma +cur_len_dma - 1)>> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1) != numTces) + { + PPCDBG(PPCDBG_TCE, "fill_scatterlist_sg: numTces %ld, used tces %d\n", + numTces, + (unsigned)(((cur_start_dma + cur_len_dma - 1) >> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1)); + } + + + return num_dma_ents; +} + +/* Call the hypervisor to create the TCE entries. + * return the number of TCEs created + */ +static dma_addr_t create_tces_sg( struct TceTable *tbl, struct scatterlist *sg, + int nents, unsigned numTces, int direction ) +{ + unsigned order, i, j; + unsigned long startPage, endPage, prevEndPage, numPages, uaddr; + long tcenum, starttcenum; + dma_addr_t dmaAddr; + + dmaAddr = NO_TCE; + + order = get_order( numTces << PAGE_SHIFT ); + /* allocate a block of tces */ + tcenum = alloc_tce_range( tbl, order ); + if ( tcenum != -1 ) { + tcenum += tbl->startOffset; + starttcenum = tcenum; + dmaAddr = tcenum << PAGE_SHIFT; + prevEndPage = 0; + for (j=0; jaddress >> PAGE_SHIFT; + endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT; + numPages = endPage - startPage + 1; + + uaddr = (unsigned long)sg->address; + + /* If the previous entry ended in the same page that + * the current page starts then they share that + * tce and we reduce the number of tces we need + * by one. This matches assumptions made in + * num_tces_sg and fill_scatterlist_sg + */ + if ( startPage == prevEndPage ) { + --numPages; + uaddr += PAGE_SIZE; + } + + for (i=0; idma_address = pci_map_single( hwdev, sg->address, + sg->length, direction ); + sg->dma_length = sg->length; + return 1; + } + + if ( direction == PCI_DMA_NONE ) + BUG(); + + tbl = get_tce_table(hwdev); + + if ( tbl ) { + /* Compute the number of tces required */ + numTces = num_tces_sg( sg, nents ); + /* Create the tces and get the dma address */ + dma_handle = create_tces_sg( tbl, sg, nents, numTces, direction ); + + /* Fill in the dma scatterlist */ + num_dma = fill_scatterlist_sg( sg, nents, dma_handle, numTces ); + } + + return num_dma; +} + +void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction ) +{ + struct TceTable * tbl; + unsigned order, numTces, i; + dma_addr_t dma_end_page, dma_start_page; + + PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n"); + PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms); + + if ( direction == PCI_DMA_NONE ) + BUG(); + + dma_start_page = sg->dma_address & PAGE_MASK; + for ( i=nelms; i>0; --i ) { + unsigned k = i - 1; + if ( sg[k].dma_length ) { + dma_end_page = ( sg[k].dma_address + + sg[k].dma_length - 1 ) & PAGE_MASK; + break; + } + } + + numTces = ((dma_end_page - dma_start_page ) >> PAGE_SHIFT) + 1; + order = get_order( numTces << PAGE_SHIFT ); + + if ( order > 10 ) + PPCDBG(PPCDBG_TCE, "pci_unmap_sg: order=%d, numTces=%d, nelms=%d, dma_start_page=%016lx, dma_end_page=%016lx\n", + order, numTces, nelms, (unsigned long)dma_start_page, (unsigned long)dma_end_page ); + + tbl = get_tce_table(hwdev); + + if ( tbl ) + ppc_md.tce_free( tbl, dma_start_page, order, numTces ); + +} + +/* + * phb_tce_table_init + * + * Function: Display TCE config registers. Could be easily changed + * to initialize the hardware to use TCEs. + */ +unsigned long phb_tce_table_init(struct pci_controller *phb) { + unsigned int r, cfg_rw, i; + unsigned long r64; + phandle node; + + PPCDBG(PPCDBG_TCE, "phb_tce_table_init: start.\n"); + + node = ((struct device_node *)(phb->arch_data))->node; + + PPCDBG(PPCDBG_TCEINIT, "\tphb = 0x%lx\n", phb); + PPCDBG(PPCDBG_TCEINIT, "\tphb->type = 0x%lx\n", phb->type); + PPCDBG(PPCDBG_TCEINIT, "\tphb->phb_regs = 0x%lx\n", phb->phb_regs); + PPCDBG(PPCDBG_TCEINIT, "\tphb->chip_regs = 0x%lx\n", phb->chip_regs); + PPCDBG(PPCDBG_TCEINIT, "\tphb: node = 0x%lx\n", node); + PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data = 0x%lx\n", phb->arch_data); + + i = 0; + while(of_tce_table[i].node) { + if(of_tce_table[i].node == node) { + if(phb->type == phb_type_python) { + r = *(((unsigned int *)phb->phb_regs) + (0xf10>>2)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR(low) = 0x%x\n", r); + r = *(((unsigned int *)phb->phb_regs) + (0xf00>>2)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR(high) = 0x%x\n", r); + r = *(((unsigned int *)phb->phb_regs) + (0xfd0>>2)); + PPCDBG(PPCDBG_TCEINIT, "\tPHB cfg(rw) = 0x%x\n", r); + break; + } else if(phb->type == phb_type_speedwagon) { + r64 = *(((unsigned long *)phb->chip_regs) + + (0x800>>3)); + PPCDBG(PPCDBG_TCEINIT, "\tNCFG = 0x%lx\n", r64); + r64 = *(((unsigned long *)phb->chip_regs) + + (0x580>>3)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR0 = 0x%lx\n", r64); + r64 = *(((unsigned long *)phb->chip_regs) + + (0x588>>3)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR1 = 0x%lx\n", r64); + r64 = *(((unsigned long *)phb->chip_regs) + + (0x590>>3)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR2 = 0x%lx\n", r64); + r64 = *(((unsigned long *)phb->chip_regs) + + (0x598>>3)); + PPCDBG(PPCDBG_TCEINIT, "\tTAR3 = 0x%lx\n", r64); + cfg_rw = *(((unsigned int *)phb->chip_regs) + + ((0x160 + + (((phb->local_number)+8)<<12))>>2)); + PPCDBG(PPCDBG_TCEINIT, "\tcfg_rw = 0x%x\n", cfg_rw); + } + } + i++; + } + + PPCDBG(PPCDBG_TCEINIT, "phb_tce_table_init: done\n"); + + return(0); +} + +/* These are called very early. */ +void tce_init_pSeries(void) +{ + ppc_md.tce_build = tce_build_pSeries; + ppc_md.tce_free = tce_free_pSeries; +} + +void tce_init_iSeries(void) +{ + ppc_md.tce_build = tce_build_iSeries; + ppc_md.tce_free = tce_free_iSeries; +} diff -urN linux-2.4.18/arch/ppc64/kernel/pci_dn.c linux-2.4.19-pre5/arch/ppc64/kernel/pci_dn.c --- linux-2.4.18/arch/ppc64/kernel/pci_dn.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pci_dn.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,386 @@ +/* + * pci_dn.c + * + * Copyright (C) 2001 Todd Inglett, IBM Corporation + * + * PCI manipulation via device_nodes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +/* Traverse_func that inits the PCI fields of the device node. + * NOTE: this *must* be done before read/write config to the device. + */ +static void * __init +update_dn_pci_info(struct device_node *dn, void *data) +{ + struct pci_controller *phb = (struct pci_controller *)data; + u32 *regs; + char *device_type = get_property(dn, "device_type", 0); + + dn->phb = phb; + if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) { + /* special case for PHB's. Sigh. */ + regs = (u32 *)get_property(dn, "bus-range", 0); + dn->busno = regs[0]; + dn->devfn = 0; /* assumption */ + } else { + regs = (u32 *)get_property(dn, "reg", 0); + if (regs) { + /* First register entry is addr (00BBSS00) */ + dn->busno = (regs[0] >> 16) & 0xff; + dn->devfn = (regs[0] >> 8) & 0xff; + } + } + return NULL; +} + +/* + * Hit all the BARs of all the devices with values from OF. + * This is unnecessary on most systems, but also harmless. + */ +static void * __init +write_OF_bars(struct device_node *dn, void *data) +{ + int i; + u32 oldbar, newbar, newbartest; + u8 config_offset; + char *name = get_property(dn, "name", 0); + char *device_type = get_property(dn, "device_type", 0); + char devname[128]; + sprintf(devname, "%04x:%02x.%x %s (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "", device_type ? device_type : ""); + + if (device_type && strcmp(device_type, "pci") == 0 && + get_property(dn, "class-code", 0) == 0) + return NULL; /* This is probably a phb. Skip it. */ + + if (dn->n_addrs == 0) + return NULL; /* This is normal for some adapters or bridges */ + + if (dn->addrs == NULL) { + /* This shouldn't happen. */ + printk(KERN_WARNING "write_OF_bars %s: device has %d BARs, but no addrs recorded\n", devname, dn->n_addrs); + return NULL; + } + +#ifndef CONFIG_PPC_ISERIES + for (i = 0; i < dn->n_addrs; i++) { + newbar = dn->addrs[i].address; + config_offset = dn->addrs[i].space & 0xff; + if (ppc_md.pcibios_read_config_dword(dn, config_offset, &oldbar) != PCIBIOS_SUCCESSFUL) { + printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i); + continue; + } + /* Need to update this BAR. */ + if (ppc_md.pcibios_write_config_dword(dn, config_offset, newbar) != PCIBIOS_SUCCESSFUL) { + printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar); + continue; + } + /* sanity check */ + if (ppc_md.pcibios_read_config_dword(dn, config_offset, &newbartest) != PCIBIOS_SUCCESSFUL) { + printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i); + continue; + } + if ((newbar & PCI_BASE_ADDRESS_MEM_MASK) != (newbartest & PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_WARNING "write_OF_bars %s: oops...BAR%d read back as 0x%08x%s!\n", devname, i, newbartest, (oldbar & PCI_BASE_ADDRESS_MEM_MASK) == (newbartest & PCI_BASE_ADDRESS_MEM_MASK) ? " (original value)" : ""); + continue; + } + } +#endif + return NULL; +} + +#if 0 +/* Traverse_func that starts the BIST (self test) */ +static void * __init +startBIST(struct device_node *dn, void *data) +{ + struct pci_controller *phb = (struct pci_controller *)data; + u8 bist; + + char *name = get_property(dn, "name", 0); + udbg_printf("startBIST: %s phb=%p, device=%p\n", name ? name : "", phb, dn); + + if (ppc_md.pcibios_read_config_byte(dn, PCI_BIST, &bist) == PCIBIOS_SUCCESSFUL) { + if (bist & PCI_BIST_CAPABLE) { + udbg_printf(" -> is BIST capable!\n", phb, dn); + /* Start bist here */ + } + } + return NULL; +} +#endif + + +/****************************************************************** + * Traverse a device tree stopping each PCI device in the tree. + * This is done depth first. As each node is processed, a "pre" + * function is called, the children are processed recursively, and + * then a "post" function is called. + * + * The "pre" and "post" funcs return a value. If non-zero + * is returned from the "pre" func, the traversal stops and this + * value is returned. The return value from "post" is not used. + * This return value is useful when using traverse as + * a method of finding a device. + * + * NOTE: we do not run the funcs for devices that do not appear to + * be PCI except for the start node which we assume (this is good + * because the start node is often a phb which may be missing PCI + * properties). + * We use the class-code as an indicator. If we run into + * one of these nodes we also assume its siblings are non-pci for + * performance. + * + ******************************************************************/ +void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data) +{ + struct device_node *dn, *nextdn; + void *ret; + + if (pre && (ret = pre(start, data)) != NULL) + return ret; + for (dn = start->child; dn; dn = nextdn) { + nextdn = NULL; + if (get_property(dn, "class-code", 0)) { + if (pre && (ret = pre(dn, data)) != NULL) + return ret; + if (dn->child) { + /* Depth first...do children */ + nextdn = dn->child; + } else if (dn->sibling) { + /* ok, try next sibling instead. */ + nextdn = dn->sibling; + } else { + /* no more children or siblings...call "post" */ + if (post) + post(dn, data); + } + } + if (!nextdn) { + /* Walk up to next valid sibling. */ + do { + dn = dn->parent; + if (dn == start) + return NULL; + } while (dn->sibling == NULL); + nextdn = dn->sibling; + } + } + return NULL; +} + +/* Same as traverse_pci_devices except this does it for all phbs. + */ +void *traverse_all_pci_devices(traverse_func pre) +{ + struct pci_controller* phb; + void *ret; + for (phb=hose_head;phb;phb=phb->next) + if ((ret = traverse_pci_devices((struct device_node *)phb->arch_data, pre, NULL, phb)) != NULL) + return ret; + return NULL; +} + + +/* Traversal func that looks for a value. + * If found, the device_node is returned (thus terminating the traversal). + */ +static void * +is_devfn_node(struct device_node *dn, void *data) +{ + int busno = ((unsigned long)data >> 8) & 0xff; + int devfn = ((unsigned long)data) & 0xff; + return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL; +} + +/* Same as is_devfn_node except ignore the "fn" part of the "devfn". + */ +static void * +is_devfn_sub_node(struct device_node *dn, void *data) +{ + int busno = ((unsigned long)data >> 8) & 0xff; + int devfn = ((unsigned long)data) & 0xf8; + return (devfn == (dn->devfn & 0xf8) && busno == dn->busno) ? dn : NULL; +} + +/* Given an existing EADs (pci bridge) device node create a fake one + * that will simulate function zero. Make it a sibling of other_eads. + */ +static struct device_node * +create_eads_node(struct device_node *other_eads) +{ + struct device_node *eads = (struct device_node *)kmalloc(sizeof(struct device_node), GFP_KERNEL); + + if (!eads) return NULL; /* huh? */ + *eads = *other_eads; + eads->devfn &= ~7; /* make it function zero */ + eads->tce_table = NULL; + /* NOTE: share properties. We could copy but for now this should suffice. + * The full_name is also incorrect...but seems harmless. + */ + eads->child = NULL; + eads->next = NULL; + other_eads->allnext = eads; + other_eads->sibling = eads; + return eads; +} + +/* This is the "slow" path for looking up a device_node from a + * pci_dev. It will hunt for the device under it's parent's + * phb and then update sysdata for a future fastpath. + * + * It may also do fixups on the actual device since this happens + * on the first read/write. + * + * Note that it also must deal with devices that don't exist. + * In this case it may probe for real hardware ("just in case") + * and add a device_node to the device tree if necessary. + * + */ +struct device_node *fetch_dev_dn(struct pci_dev *dev) +{ + struct device_node *orig_dn = (struct device_node *)dev->sysdata; + struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */ + struct device_node *phb_dn; + struct device_node *dn; + unsigned long searchval = (dev->bus->number << 8) | dev->devfn; + + phb_dn = (struct device_node *)(phb->arch_data); + dn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_node, NULL, (void *)searchval); + if (dn) { + dev->sysdata = dn; + /* ToDo: call some device init hook here */ + } else { + /* Now it is very possible that we can't find the device because it is + * not the zero'th device of a mutifunction device and we don't have + * permission to read the zero'th device. If this is the case, Linux + * would ordinarily skip all the other functions. + */ + if ((searchval & 0x7) == 0) { + struct device_node *thisdevdn; + /* Ok, we are looking for fn == 0. Let's check for other functions. */ + thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval); + if (thisdevdn) { + /* Ah ha! There does exist a sub function. Now this isn't an exact + * match for searchval, but in order to get Linux to believe the sub + * functions exist we will need to manufacture a fake device_node + * for this zero'th function. To keept this simple for now we only + * handle pci bridges and we just hand back the found node which + * isn't correct, but Linux won't care. + */ + char *device_type = (char *)get_property(thisdevdn, "device_type", 0); + if (device_type && strcmp(device_type, "pci") == 0) { + return create_eads_node(thisdevdn); + } + } + } + /* ToDo: device not found...probe for it anyway with a fake dn? + struct device_node fake_dn; + memset(&fake_dn, 0, sizeof(fake_dn)); + fake_dn.phb = phb; + fake_dn.busno = dev->bus->number; + fake_dn.devfn = dev->devfn; + ... now do ppc_md.pcibios_read_config_dword(&fake_dn.....) + ... if ok, alloc a real device_node and dn = real_dn; + */ + } + return dn; +} + + +/****************************************************************** + * Actually initialize the phbs. + * The buswalk on this phb has not happened yet. + ******************************************************************/ +void __init +pci_devs_phb_init(void) +{ + /* This must be done first so the device nodes have valid pci info! */ + traverse_all_pci_devices(update_dn_pci_info); + + /* Hack for regatta which does not init the bars correctly */ + traverse_all_pci_devices(write_OF_bars); +#if 0 + traverse_all_pci_devices(startBIST); + mdelay(5000); + traverse_all_pci_devices(checkBIST); +#endif +} + + +static void __init +pci_fixup_bus_sysdata_list(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + struct pci_controller *phb; + int newnum; + + for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + if (bus->self) { + bus->sysdata = bus->self->sysdata; + /* Also fixup the bus number on large bus systems to + * include the PHB# in the next byte + */ + phb = PCI_GET_DN(bus)->phb; + if (phb && phb->buid) { + newnum = (phb->global_number << 8) | bus->number; + bus->number = newnum; + sprintf(bus->name, "PCI Bus #%x", bus->number); + } + } + pci_fixup_bus_sysdata_list(&bus->children); + } +} + + +/****************************************************************** + * Fixup the bus->sysdata ptrs to point to the bus' device_node. + * This is done late in pcibios_init(). We do this mostly for + * sanity, but pci_dma.c uses these at DMA time so they must be + * correct. + * To do this we recurse down the bus hierarchy. Note that PHB's + * have bus->self == NULL, but fortunately bus->sysdata is already + * correct in this case. + ******************************************************************/ +void __init +pci_fix_bus_sysdata(void) +{ + pci_fixup_bus_sysdata_list(&pci_root_buses); +} diff -urN linux-2.4.18/arch/ppc64/kernel/pmc.c linux-2.4.19-pre5/arch/ppc64/kernel/pmc.c --- linux-2.4.18/arch/ppc64/kernel/pmc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/pmc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,167 @@ +/* + * pmc.c + * Copyright (C) 2001 Dave Engebretsen & Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Change Activity: + * 2001/06/05 : engebret : Created. + * End Change Activity + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern struct Naca *naca; + +struct _pmc_sw pmc_sw_system = { + 0 +}; + +struct _pmc_sw pmc_sw_cpu[NR_CPUS] = { + {0 }, +}; + +/* + * Provide enough storage for either system level counters or + * one cpu's counters. + */ +struct _pmc_sw_text pmc_sw_text; +struct _pmc_hw_text pmc_hw_text; + +char * +ppc64_pmc_stab(int file) +{ + int n; + unsigned long stab_faults, stab_capacity_castouts, stab_invalidations; + unsigned long i; + + stab_faults = stab_capacity_castouts = stab_invalidations = n = 0; + + if (file == -1) { + for (i = 0; i < smp_num_cpus; i++) { + stab_faults += pmc_sw_cpu[i].stab_faults; + stab_capacity_castouts += pmc_sw_cpu[i].stab_capacity_castouts; + stab_invalidations += pmc_sw_cpu[i].stab_invalidations; + } + n += sprintf(pmc_sw_text.buffer + n, + "Faults 0x%lx\n", stab_faults); + n += sprintf(pmc_sw_text.buffer + n, + "Castouts 0x%lx\n", stab_capacity_castouts); + n += sprintf(pmc_sw_text.buffer + n, + "Invalidations 0x%lx\n", stab_invalidations); + } else { + n += sprintf(pmc_sw_text.buffer + n, + "Faults 0x%lx\n", + pmc_sw_cpu[file].stab_faults); + + n += sprintf(pmc_sw_text.buffer + n, + "Castouts 0x%lx\n", + pmc_sw_cpu[file].stab_capacity_castouts); + + n += sprintf(pmc_sw_text.buffer + n, + "Invalidations 0x%lx\n", + pmc_sw_cpu[file].stab_invalidations); + + for (i = 0; i < STAB_ENTRY_MAX; i++) { + if (pmc_sw_cpu[file].stab_entry_use[i]) { + n += sprintf(pmc_sw_text.buffer + n, + "Entry %02ld 0x%lx\n", i, + pmc_sw_cpu[file].stab_entry_use[i]); + } + } + + } + + return(pmc_sw_text.buffer); +} + +char * +ppc64_pmc_htab(int file) +{ + int n; + unsigned long htab_primary_overflows, htab_capacity_castouts; + unsigned long htab_read_to_write_faults; + + htab_primary_overflows = htab_capacity_castouts = 0; + htab_read_to_write_faults = n = 0; + + if (file == -1) { + n += sprintf(pmc_sw_text.buffer + n, + "Primary Overflows 0x%lx\n", + pmc_sw_system.htab_primary_overflows); + n += sprintf(pmc_sw_text.buffer + n, + "Castouts 0x%lx\n", + pmc_sw_system.htab_capacity_castouts); + } else { + n += sprintf(pmc_sw_text.buffer + n, + "Primary Overflows N/A\n"); + + n += sprintf(pmc_sw_text.buffer + n, + "Castouts N/A\n\n"); + + } + + return(pmc_sw_text.buffer); +} + +char * +ppc64_pmc_hw(int file) +{ + int n; + + n = 0; + if (file == -1) { + n += sprintf(pmc_hw_text.buffer + n, "Not Implemented\n"); + } else { + n += sprintf(pmc_hw_text.buffer + n, + "MMCR0 0x%lx\n", mfspr(MMCR0)); + n += sprintf(pmc_hw_text.buffer + n, + "MMCR1 0x%lx\n", mfspr(MMCR1)); +#if 0 + n += sprintf(pmc_hw_text.buffer + n, + "MMCRA 0x%lx\n", mfspr(MMCRA)); +#endif + + n += sprintf(pmc_hw_text.buffer + n, + "PMC1 0x%lx\n", mfspr(PMC1)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC2 0x%lx\n", mfspr(PMC2)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC3 0x%lx\n", mfspr(PMC3)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC4 0x%lx\n", mfspr(PMC4)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC5 0x%lx\n", mfspr(PMC5)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC6 0x%lx\n", mfspr(PMC6)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC7 0x%lx\n", mfspr(PMC7)); + n += sprintf(pmc_hw_text.buffer + n, + "PMC8 0x%lx\n", mfspr(PMC8)); + } + + return(pmc_hw_text.buffer); +} diff -urN linux-2.4.18/arch/ppc64/kernel/ppc-stub.c linux-2.4.19-pre5/arch/ppc64/kernel/ppc-stub.c --- linux-2.4.18/arch/ppc64/kernel/ppc-stub.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc-stub.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,739 @@ +/* + * ppc-stub.c: KGDB support for the Linux kernel. + * + * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC + * some stuff borrowed from Paul Mackerras' xmon + * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) + * + * Modifications to run under Linux + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * This file originally came from the gdb sources, and the + * copyright notices have been retained below. + */ + +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or its performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * This code has been extensively tested on the Fujitsu SPARClite demo board. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * bBB..BB Set baud rate to BB..BB OK or BNN, then sets + * baud rate + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void breakinst(void); + +/* + * BUFMAX defines the maximum number of characters in inbound/outbound buffers + * at least NUMREGBYTES*2 are needed for register packets + */ +#define BUFMAX 2048 +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +static int initialized = 0; +static int kgdb_active = 0; +static int kgdb_started = 0; +static u_int fault_jmp_buf[100]; +static int kdebug; + +static const char hexchars[]="0123456789abcdef"; + +/* Place where we save old trap entries for restoration - sparc*/ +/* struct tt_entry kgdb_savettable[256]; */ +/* typedef void (*trapfunc_t)(void); */ + +#if 0 +/* Install an exception handler for kgdb */ +static void exceptionHandler(int tnum, unsigned int *tfunc) +{ + /* We are dorking with a live trap table, all irqs off */ +} +#endif + +int +kgdb_setjmp(long *buf) +{ + asm ("mflr 0; stw 0,0(%0);" + "stw 1,4(%0); stw 2,8(%0);" + "mfcr 0; stw 0,12(%0);" + "stmw 13,16(%0)" + : : "r" (buf)); + /* XXX should save fp regs as well */ + return 0; +} +void +kgdb_longjmp(long *buf, int val) +{ + if (val == 0) + val = 1; + asm ("lmw 13,16(%0);" + "lwz 0,12(%0); mtcrf 0x38,0;" + "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" + "mtlr 0; mr 3,%1" + : : "r" (buf), "r" (val)); +} +/* Convert ch from a hex digit to an int */ +static int +hex(unsigned char ch) +{ + if (ch >= 'a' && ch <= 'f') + return ch-'a'+10; + if (ch >= '0' && ch <= '9') + return ch-'0'; + if (ch >= 'A' && ch <= 'F') + return ch-'A'+10; + return -1; +} + +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null), in case of mem fault, + * return 0. + */ +static unsigned char * +mem2hex(char *mem, char *buf, int count) +{ + unsigned char ch; + + if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { + debugger_fault_handler = kgdb_fault_handler; + while (count-- > 0) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + } else { + /* error condition */ + } + debugger_fault_handler = 0; + *buf = 0; + return buf; +} + +/* convert the hex array pointed to by buf into binary to be placed in mem + * return a pointer to the character AFTER the last byte written. +*/ +static char * +hex2mem(char *buf, char *mem, int count) +{ + int i; + unsigned char ch; + + if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { + debugger_fault_handler = kgdb_fault_handler; + for (i=0; i# */ +static void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + do { + /* wait around for the start character, ignore all other + * characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + + if (count >= BUFMAX) + continue; + + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum |= hex(getDebugChar() & 0x7f); + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); +} + +/* send the packet in buffer. */ +static void putpacket(unsigned char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch, recv; + + /* $#. */ + do { + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum & 0xf]); + recv = getDebugChar(); + } while ((recv & 0x7f) != '+'); +} + +static void kgdb_flush_cache_all(void) +{ + flush_instruction_cache(); +} + + +/* Set up exception handlers for tracing and breakpoints + * [could be called kgdb_init()] + */ +void set_debug_traps(void) +{ +#if 0 + unsigned char c; + + save_and_cli(flags); + + /* In case GDB is started before us, ack any packets (presumably + * "$?#xx") sitting there. + * + * I've found this code causes more problems than it solves, + * so that's why it's commented out. GDB seems to work fine + * now starting either before or after the kernel -bwb + */ + + while((c = getDebugChar()) != '$'); + while((c = getDebugChar()) != '#'); + c = getDebugChar(); /* eat first csum byte */ + c = getDebugChar(); /* eat second csum byte */ + putDebugChar('+'); /* ack it */ +#endif + debugger = kgdb; + debugger_bpt = kgdb_bpt; + debugger_sstep = kgdb_sstep; + debugger_iabr_match = kgdb_iabr_match; + debugger_dabr_match = kgdb_dabr_match; + + initialized = 1; +} + +static void kgdb_fault_handler(struct pt_regs *regs) +{ + kgdb_longjmp((long*)fault_jmp_buf, 1); +} + +int kgdb_bpt(struct pt_regs *regs) +{ + handle_exception(regs); + return 1; +} + +int kgdb_sstep(struct pt_regs *regs) +{ + handle_exception(regs); + return 1; +} + +void kgdb(struct pt_regs *regs) +{ + handle_exception(regs); +} + +int kgdb_iabr_match(struct pt_regs *regs) +{ + printk("kgdb doesn't support iabr, what?!?\n"); + handle_exception(regs); + return 1; +} + +int kgdb_dabr_match(struct pt_regs *regs) +{ + printk("kgdb doesn't support dabr, what?!?\n"); + handle_exception(regs); + return 1; +} + +/* Convert the SPARC hardware trap type code to a unix signal number. */ +/* + * This table contains the mapping between PowerPC hardware trap types, and + * signals, which are primarily what GDB understands. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + { 0x200, SIGSEGV }, /* machine check */ + { 0x300, SIGSEGV }, /* address error (store) */ + { 0x400, SIGBUS }, /* instruction bus error */ + { 0x500, SIGINT }, /* interrupt */ + { 0x600, SIGBUS }, /* alingment */ + { 0x700, SIGTRAP }, /* breakpoint trap */ + { 0x800, SIGFPE }, /* fpu unavail */ + { 0x900, SIGALRM }, /* decrementer */ + { 0xa00, SIGILL }, /* reserved */ + { 0xb00, SIGILL }, /* reserved */ + { 0xc00, SIGCHLD }, /* syscall */ + { 0xd00, SIGTRAP }, /* single-step/watch */ + { 0xe00, SIGFPE }, /* fp assist */ + { 0, 0} /* Must be last */ +}; + +static int computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +#define PC_REGNUM 64 +#define SP_REGNUM 1 + +/* + * This function does all command processing for interfacing to gdb. + */ +static void +handle_exception (struct pt_regs *regs) +{ + int sigval; + int addr; + int length; + char *ptr; + unsigned long msr; + + if (debugger_fault_handler) { + debugger_fault_handler(regs); + panic("kgdb longjump failed!\n"); + } + if (kgdb_active) { + printk("interrupt while in kgdb, returning\n"); + return; + } + kgdb_active = 1; + kgdb_started = 1; + +#ifdef KGDB_DEBUG + printk("kgdb: entering handle_exception; trap [0x%x]\n", + (unsigned int)regs->trap); +#endif + + kgdb_interruptible(0); + lock_kernel(); + msr = get_msr(); + set_msr(msr & ~MSR_EE); /* disable interrupts */ + + if (regs->nip == (unsigned long)breakinst) { + /* Skip over breakpoint trap insn */ + regs->nip += 4; + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal(regs->trap); + ptr = remcomOutBuffer; + +#if 0 + *ptr++ = 'S'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; +#else + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + *ptr++ = hexchars[PC_REGNUM >> 4]; + *ptr++ = hexchars[PC_REGNUM & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®s->nip, ptr, 4); + *ptr++ = ';'; + *ptr++ = hexchars[SP_REGNUM >> 4]; + *ptr++ = hexchars[SP_REGNUM & 0xf]; + *ptr++ = ':'; + ptr = mem2hex(((char *)®s) + SP_REGNUM*4, ptr, 4); + *ptr++ = ';'; +#endif + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + /* XXX We may want to add some features dealing with poking the + * XXX page tables, ... (look at sparc-stub.c for more info) + * XXX also required hacking to the gdb sources directly... + */ + + while (1) { + remcomOutBuffer[0] = 0; + + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': /* report most recent signal */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; +#if 0 + case 'q': /* this screws up gdb for some reason...*/ + { + extern long _start, sdata, __bss_start; + + ptr = &remcomInBuffer[1]; + if (strncmp(ptr, "Offsets", 7) != 0) + break; + + ptr = remcomOutBuffer; + sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", + &_start, &sdata, &__bss_start); + break; + } +#endif + case 'd': + /* toggle debug flag */ + kdebug ^= 1; + break; + + case 'g': /* return the value of the CPU registers. + * some of them are non-PowerPC names :( + * they are stored in gdb like: + * struct { + * u32 gpr[32]; + * f64 fpr[32]; + * u32 pc, ps, cnd, lr; (ps=msr) + * u32 cnt, xer, mq; + * } + */ + { + int i; + ptr = remcomOutBuffer; + /* General Purpose Regs */ + ptr = mem2hex((char *)regs, ptr, 32 * 4); + /* Floating Point Regs - FIXME */ + /*ptr = mem2hex((char *), ptr, 32 * 8);*/ + for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ + ptr[i] = '0'; + } + ptr += 32*8*2; + /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ + ptr = mem2hex((char *)®s->nip, ptr, 4); + ptr = mem2hex((char *)®s->msr, ptr, 4); + ptr = mem2hex((char *)®s->ccr, ptr, 4); + ptr = mem2hex((char *)®s->link, ptr, 4); + ptr = mem2hex((char *)®s->ctr, ptr, 4); + ptr = mem2hex((char *)®s->xer, ptr, 4); + } + break; + + case 'G': /* set the value of the CPU registers */ + { + ptr = &remcomInBuffer[1]; + + /* + * If the stack pointer has moved, you should pray. + * (cause only god can help you). + */ + + /* General Purpose Regs */ + hex2mem(ptr, (char *)regs, 32 * 4); + + /* Floating Point Regs - FIXME?? */ + /*ptr = hex2mem(ptr, ??, 32 * 8);*/ + ptr += 32*8*2; + + /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ + ptr = hex2mem(ptr, (char *)®s->nip, 4); + ptr = hex2mem(ptr, (char *)®s->msr, 4); + ptr = hex2mem(ptr, (char *)®s->ccr, 4); + ptr = hex2mem(ptr, (char *)®s->link, 4); + ptr = hex2mem(ptr, (char *)®s->ctr, 4); + ptr = hex2mem(ptr, (char *)®s->xer, 4); + + strcpy(remcomOutBuffer,"OK"); + } + break; + case 'H': + /* don't do anything, yet, just acknowledge */ + hexToInt(&ptr, &addr); + strcpy(remcomOutBuffer,"OK"); + break; + + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length)) { + if (mem2hex((char *)addr, remcomOutBuffer,length)) + break; + strcpy (remcomOutBuffer, "E03"); + } else { + strcpy(remcomOutBuffer,"E01"); + } + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* Try to read '%x,%x:'. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length) + && *ptr++ == ':') { + if (hex2mem(ptr, (char *)addr, length)) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E03"); + } + flush_icache_range(addr, addr+length); + } else { + strcpy(remcomOutBuffer, "E02"); + } + break; + + + case 'k': /* kill the program, actually just continue */ + case 'c': /* cAA..AA Continue; address AA..AA optional */ + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + regs->nip = addr; + } + +/* Need to flush the instruction cache here, as we may have deposited a + * breakpoint, and the icache probably has no way of knowing that a data ref to + * some location may have changed something that is in the instruction cache. + */ + kgdb_flush_cache_all(); + set_msr(msr); + kgdb_interruptible(1); + unlock_kernel(); + kgdb_active = 0; + return; + + case 's': + kgdb_flush_cache_all(); + regs->msr |= MSR_SE; +#if 0 + set_msr(msr | MSR_SE); +#endif + unlock_kernel(); + kgdb_active = 0; + return; + + case 'r': /* Reset (if user process..exit ???)*/ + panic("kgdb reset."); + break; + } /* switch */ + if (remcomOutBuffer[0] && kdebug) { + printk("remcomInBuffer: %s\n", remcomInBuffer); + printk("remcomOutBuffer: %s\n", remcomOutBuffer); + } + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1) */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint(void) +{ + if (!initialized) { + printk("breakpoint() called b4 kgdb init\n"); + return; + } + + asm(" .globl breakinst + breakinst: .long 0x7d821008 + "); +} + +/* Output string in GDB O-packet format if GDB has connected. If nothing + output, returns 0 (caller must then handle output). */ +int +kgdb_output_string (const char* s, unsigned int count) +{ + char buffer[512]; + + if (!kgdb_started) + return 0; + + count = (count <= (sizeof(buffer) / 2 - 2)) + ? count : (sizeof(buffer) / 2 - 2); + + buffer[0] = 'O'; + mem2hex (s, &buffer[1], count); + putpacket(buffer); + + return 1; + } diff -urN linux-2.4.18/arch/ppc64/kernel/ppc_asm.h linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.h --- linux-2.4.18/arch/ppc64/kernel/ppc_asm.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,117 @@ +/* + * arch/ppc/kernel/ppc_asm.h + * + * Definitions used by various bits of low-level assembly code on PowerPC. + * + * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" + +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) +#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) +#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) +#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) +#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) +#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) +#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) +#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) +#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) +#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) +#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) + +#define CHECKANYINT(ra,rb) \ + mfspr rb,SPRG3; /* Get Paca address */\ + ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\ + cmpldi 0,ra,0; + +/* Macros to adjust thread priority for Iseries hardware multithreading */ +#define HMT_LOW or 1,1,1 +#define HMT_MEDIUM or 2,2,2 +#define HMT_HIGH or 3,3,3 + +/* Insert the high 32 bits of the MSR into what will be the new + MSR (via SRR1 and rfid) This preserves the MSR.SF and MSR.ISF + bits. */ + +#define FIX_SRR1(ra, rb) \ + mr rb,ra; \ + mfmsr ra; \ + rldimi ra,rb,0,32 + +#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ + +/* + * LOADADDR( rn, name ) + * loads the address of 'name' into 'rn' + * + * LOADBASE( rn, name ) + * loads the address (less the low 16 bits) of 'name' into 'rn' + * suitable for base+disp addressing + */ +#define LOADADDR(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + +#define LOADBASE(rn,name) \ + lis rn,name@highest; \ + ori rn,rn,name@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name@ha + + +#define SET_REG_TO_CONST(reg, value) \ + lis reg,(((value)>>48)&0xFFFF); \ + ori reg,reg,(((value)>>32)&0xFFFF); \ + rldicr reg,reg,32,31; \ + oris reg,reg,(((value)>>16)&0xFFFF); \ + ori reg,reg,((value)&0xFFFF); + +#define SET_REG_TO_LABEL(reg, label) \ + lis reg,(label)@highest; \ + ori reg,reg,(label)@higher; \ + rldicr reg,reg,32,31; \ + oris reg,reg,(label)@h; \ + ori reg,reg,(label)@l; + + +/* PPPBBB - DRENG If KERNELBASE is always 0xC0..., + * Then we can easily do this with one asm insn. -Peter + */ +#define tophys(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + sub rd,rs,rd + +#define tovirt(rd,rs) \ + lis rd,((KERNELBASE>>48)&0xFFFF); \ + rldicr rd,rd,32,31; \ + add rd,rs,rd + diff -urN linux-2.4.18/arch/ppc64/kernel/ppc_asm.tmpl linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.tmpl --- linux-2.4.18/arch/ppc64/kernel/ppc_asm.tmpl Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.tmpl Sat Mar 30 22:55:39 2002 @@ -0,0 +1,115 @@ +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 diff -urN linux-2.4.18/arch/ppc64/kernel/ppc_defs.head linux-2.4.19-pre5/arch/ppc64/kernel/ppc_defs.head --- linux-2.4.18/arch/ppc64/kernel/ppc_defs.head Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_defs.head Sat Mar 30 22:55:39 2002 @@ -0,0 +1,3 @@ +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ diff -urN linux-2.4.18/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.19-pre5/arch/ppc64/kernel/ppc_ksyms.c --- linux-2.4.18/arch/ppc64/kernel/ppc_ksyms.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_ksyms.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,306 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SMP +#include +#endif /* CONFIG_SMP */ +#ifdef CONFIG_PPC_ISERIES +#include +#include +#include +#include +#include +#endif + +/* Tell string.h we don't want memcpy etc. as cpp defines */ +#define EXPORT_SYMTAB_STROPS + +extern void syscall_trace(void); +extern void do_IRQ(struct pt_regs *regs, int isfake); +extern void SystemResetException(struct pt_regs *regs); +extern void MachineCheckException(struct pt_regs *regs); +extern void AlignmentException(struct pt_regs *regs); +extern void ProgramCheckException(struct pt_regs *regs); +extern void SingleStepException(struct pt_regs *regs); +extern int sys_sigreturn(struct pt_regs *regs); +extern int do_signal(sigset_t *, struct pt_regs *); +extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); +extern int unregister_ioctl32_conversion(unsigned int cmd); + +long long __ashrdi3(long long, int); +long long __ashldi3(long long, int); +long long __lshrdi3(long long, int); +int abs(int); +extern unsigned long ret_to_user_hook; + +extern struct pci_dev * iSeries_veth_dev; +extern struct pci_dev * iSeries_vio_dev; + +EXPORT_SYMBOL(do_signal); +EXPORT_SYMBOL(syscall_trace); +EXPORT_SYMBOL(do_IRQ); +EXPORT_SYMBOL(SystemResetException); +EXPORT_SYMBOL(MachineCheckException); +EXPORT_SYMBOL(AlignmentException); +EXPORT_SYMBOL(ProgramCheckException); +EXPORT_SYMBOL(SingleStepException); +EXPORT_SYMBOL(sys_sigreturn); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(smp_num_cpus); +#endif /* CONFIG_SMP */ + +EXPORT_SYMBOL(register_ioctl32_conversion); +EXPORT_SYMBOL(unregister_ioctl32_conversion); + +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(isa_mem_base); +EXPORT_SYMBOL(pci_io_base); +EXPORT_SYMBOL(pci_dram_offset); + +EXPORT_SYMBOL(find_next_zero_bit); + +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); + +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(naca); +EXPORT_SYMBOL(__down); + +/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */ +EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(ip_fast_csum); +EXPORT_SYMBOL(csum_tcpudp_magic); + +EXPORT_SYMBOL(__copy_tofrom_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__strnlen_user); + +/* +EXPORT_SYMBOL(inb); +EXPORT_SYMBOL(inw); +EXPORT_SYMBOL(inl); +EXPORT_SYMBOL(outb); +EXPORT_SYMBOL(outw); +EXPORT_SYMBOL(outl); +EXPORT_SYMBOL(outsl);*/ + +#ifdef CONFIG_MSCHUNKS +EXPORT_SYMBOL(msChunks); +#endif +EXPORT_SYMBOL(reloc_offset); + +#ifdef CONFIG_PPC_ISERIES +EXPORT_SYMBOL(iSeries_proc_callback); +EXPORT_SYMBOL(HvCall0); +EXPORT_SYMBOL(HvCall1); +EXPORT_SYMBOL(HvCall2); +EXPORT_SYMBOL(HvCall3); +EXPORT_SYMBOL(HvCall4); +EXPORT_SYMBOL(HvCall5); +EXPORT_SYMBOL(HvCall6); +EXPORT_SYMBOL(HvCall7); +EXPORT_SYMBOL(HvLpEvent_unregisterHandler); +EXPORT_SYMBOL(HvLpEvent_registerHandler); +EXPORT_SYMBOL(mf_allocateLpEvents); +EXPORT_SYMBOL(mf_deallocateLpEvents); +EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); +#endif + +EXPORT_SYMBOL(_insb); +EXPORT_SYMBOL(_outsb); +EXPORT_SYMBOL(_insw); +EXPORT_SYMBOL(_outsw); +EXPORT_SYMBOL(_insl); +EXPORT_SYMBOL(_outsl); +EXPORT_SYMBOL(_insw_ns); +EXPORT_SYMBOL(_outsw_ns); +EXPORT_SYMBOL(_insl_ns); +EXPORT_SYMBOL(_outsl_ns); +EXPORT_SYMBOL(ioremap); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +#ifdef CONFIG_PCI +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); +EXPORT_SYMBOL(pci_map_single); +EXPORT_SYMBOL(pci_unmap_single); +EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(pci_unmap_sg); +#ifdef CONFIG_PPC_ISERIES +EXPORT_SYMBOL(iSeries_Write_Long); +EXPORT_SYMBOL(iSeries_GetLocationData); +EXPORT_SYMBOL(iSeries_Read_Long); +EXPORT_SYMBOL(iSeries_Device_ToggleReset); +EXPORT_SYMBOL(iSeries_Write_Word); +EXPORT_SYMBOL(iSeries_memcpy_fromio); +EXPORT_SYMBOL(iSeries_Read_Word); +EXPORT_SYMBOL(iSeries_Read_Byte); +EXPORT_SYMBOL(iSeries_Write_Byte); +#endif /* CONFIG_PPC_ISERIES */ +#ifdef CONFIG_PPC_EEH +EXPORT_SYMBOL(eeh_check_failure); +EXPORT_SYMBOL(eeh_total_mmio_ffs); +EXPORT_SYMBOL(eeh_total_mmio_reads); +#endif /* CONFIG_PPC_EEH */ +#endif /* CONFIG_PCI */ + +EXPORT_SYMBOL(iSeries_veth_dev); +EXPORT_SYMBOL(iSeries_vio_dev); + +EXPORT_SYMBOL(start_thread); +EXPORT_SYMBOL(kernel_thread); + +EXPORT_SYMBOL(flush_instruction_cache); +EXPORT_SYMBOL(_get_PVR); +EXPORT_SYMBOL(giveup_fpu); +EXPORT_SYMBOL(enable_kernel_fp); +EXPORT_SYMBOL(flush_icache_range); +EXPORT_SYMBOL(flush_icache_user_range); +EXPORT_SYMBOL(flush_icache_page); +EXPORT_SYMBOL(flush_dcache_page); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +#ifdef CONFIG_PPC_ISERIES +EXPORT_SYMBOL(__no_use_restore_flags); +EXPORT_SYMBOL(__no_use_save_flags); +EXPORT_SYMBOL(__no_use_sti); +EXPORT_SYMBOL(__no_use_cli); +#endif +#endif + +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL(_machine); +#endif +EXPORT_SYMBOL(ppc_md); + +EXPORT_SYMBOL(find_devices); +EXPORT_SYMBOL(find_type_devices); +EXPORT_SYMBOL(find_compatible_devices); +EXPORT_SYMBOL(find_path_device); +EXPORT_SYMBOL(device_is_compatible); +EXPORT_SYMBOL(machine_is_compatible); +EXPORT_SYMBOL(find_all_nodes); +EXPORT_SYMBOL(get_property); + +#ifndef CONFIG_PPC_ISERIES +EXPORT_SYMBOL(kd_mksound); +EXPORT_SYMBOL_NOVERS(sys_ctrler); /* tibit */ +#endif +#ifdef CONFIG_NVRAM +EXPORT_SYMBOL(nvram_read_byte); +EXPORT_SYMBOL(nvram_write_byte); +#endif /* CONFIG_NVRAM */ + +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__ashldi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(memcmp); + +EXPORT_SYMBOL(abs); + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL(timer_interrupt); +EXPORT_SYMBOL(irq_desc); +void ppc_irq_dispatch_handler(struct pt_regs *, int); +EXPORT_SYMBOL(ppc_irq_dispatch_handler); +EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(console_drivers); +#ifdef CONFIG_XMON +EXPORT_SYMBOL(xmon); +#endif + +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) +extern void (*debugger)(struct pt_regs *regs); +extern int (*debugger_bpt)(struct pt_regs *regs); +extern int (*debugger_sstep)(struct pt_regs *regs); +extern int (*debugger_iabr_match)(struct pt_regs *regs); +extern int (*debugger_dabr_match)(struct pt_regs *regs); +extern void (*debugger_fault_handler)(struct pt_regs *regs); + +EXPORT_SYMBOL(debugger); +EXPORT_SYMBOL(debugger_bpt); +EXPORT_SYMBOL(debugger_sstep); +EXPORT_SYMBOL(debugger_iabr_match); +EXPORT_SYMBOL(debugger_dabr_match); +EXPORT_SYMBOL(debugger_fault_handler); +#endif + +#ifdef CONFIG_SMP +EXPORT_SYMBOL(atomic_dec_and_lock); +#endif + +EXPORT_SYMBOL(ret_to_user_hook); + +EXPORT_SYMBOL(tb_ticks_per_usec); diff -urN linux-2.4.18/arch/ppc64/kernel/proc_pcifr.c linux-2.4.19-pre5/arch/ppc64/kernel/proc_pcifr.c --- linux-2.4.18/arch/ppc64/kernel/proc_pcifr.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/proc_pcifr.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,251 @@ +/************************************************************************/ +/* File pcifr_proc.c created by Allan Trautman on Thu Aug 2 2001. */ +/************************************************************************/ +/* Supports the ../proc/ppc64/pcifr for the pci flight recorder. */ +/* Copyright (C) 20yy */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the: */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, */ +/* Boston, MA 02111-1307 USA */ +/************************************************************************/ +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "pci.h" + +void pci_Fr_TestCode(void); + +static spinlock_t proc_pcifr_lock; +struct flightRecorder* PciFr = NULL; + +extern long Pci_Interrupt_Count; +extern long Pci_Event_Count; +extern long Pci_Io_Read_Count; +extern long Pci_Io_Write_Count; +extern long Pci_Cfg_Read_Count; +extern long Pci_Cfg_Write_Count; +extern long Pci_Error_Count; + +/************************************************************************/ +/* Forward declares. */ +/************************************************************************/ +static struct proc_dir_entry *pciFr_proc_root = NULL; +int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data); + +static struct proc_dir_entry *pciDev_proc_root = NULL; +int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data); + +/************************************************************************/ +/* Create entry ../proc/ppc64/pcifr */ +/************************************************************************/ +void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root) +{ + if (proc_ppc64_root == NULL) return; + + /* Read = User,Group,Other, Write User */ + printk("PCI: Creating ../proc/ppc64/pcifr \n"); + spin_lock(&proc_pcifr_lock); + pciFr_proc_root = create_proc_entry("pcifr", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root); + spin_unlock(&proc_pcifr_lock); + + if (pciFr_proc_root == NULL) return; + + pciFr_proc_root->nlink = 1; + pciFr_proc_root->data = (void *)0; + pciFr_proc_root->read_proc = proc_pciFr_read_proc; + pciFr_proc_root->write_proc = proc_pciFr_write_proc; + + PciFr = alloc_Flight_Recorder(NULL,"PciFr", 4096); + + printk("PCI: Creating ../proc/ppc64/pci \n"); + spin_lock(&proc_pcifr_lock); + pciDev_proc_root = create_proc_entry("pci", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root); + spin_unlock(&proc_pcifr_lock); + + if (pciDev_proc_root == NULL) return; + + pciDev_proc_root->nlink = 1; + pciDev_proc_root->data = (void *)0; + pciDev_proc_root->read_proc = proc_pciDev_read_proc; + pciDev_proc_root->write_proc = proc_pciDev_write_proc; +} + +static char* PciFrBuffer = NULL; +static int PciFrBufLen = 0; +static char* PciFrBufPtr = NULL; +static int PciFileSize = 0; + +/*******************************************************************************/ +/* Read function for ../proc/ppc64/pcifr. */ +/* -> Function grabs a copy of the pcifr(could change) and writes the data to */ +/* the caller. Note, it may not all fit in the buffer. The function */ +/* handles the repeated calls until all the data has been read. */ +/* Tip: */ +/* ./fs/proc/generic.c::proc_file_read is the caller of this routine. */ +/*******************************************************************************/ +int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + /* First call will have offset 0, get snapshot the pcifr */ + if( off == 0) { + spin_lock(&proc_pcifr_lock); + PciFrBuffer = (char*)kmalloc(PciFr->Size, GFP_KERNEL); + PciFrBufLen = fr_Dump(PciFr,PciFrBuffer, PciFr->Size); + PciFrBufPtr = PciFrBuffer; + PciFileSize = 0; + } + /* For the persistant folks, set eof and return zero length. */ + else if( PciFrBuffer == NULL) { + *eof = 1; + return 0; + } + /* - If there is more data than will fit, move what will fit. */ + /* - The rest will get moved on the next call. */ + int MoveSize = PciFrBufLen; + if( MoveSize > count) MoveSize = count; + + /* Move the data info the FileSystem buffer. */ + memcpy(page+off,PciFrBufPtr,MoveSize); + PciFrBufPtr += MoveSize; + PciFileSize += MoveSize; + PciFrBufLen -= MoveSize; + + /* If all the data has been moved, free the buffer and set EOF. */ + if( PciFrBufLen == 0) { + kfree(PciFrBuffer); + PciFrBuffer = NULL; + spin_unlock(&proc_pcifr_lock); + *eof = 1; + } + return PciFileSize; +} +/*******************************************************************************/ +/* Gets called when client writes to ../proc/ppc64/pcifr */ +/*******************************************************************************/ +int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + return count; +} +static spinlock_t ProcBufferLock; +static char* ProcBuffer = NULL; +static int ProcBufSize = 0; +static char* ProcBufPtr = NULL; +static int ProcFileSize = 0; + +/*******************************************************************************/ +/* Build Device Buffer for /proc/ppc64/pci */ +/*******************************************************************************/ +static int build_PciDev_Buffer(int BufferSize) +{ + ProcBuffer = (char*)kmalloc(BufferSize, GFP_KERNEL); + ProcBufPtr = ProcBuffer; + + int BufLen = 0; + + BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Reads. %8ld ",Pci_Io_Read_Count); + BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Writes %8ld\n",Pci_Io_Write_Count); + + BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Reads. %8ld ",Pci_Cfg_Read_Count); + BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Writes %8ld\n",Pci_Cfg_Write_Count); + + BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Errors %8ld\n",Pci_Error_Count); + BufLen += sprintf(ProcBuffer+BufLen,"\n"); + + /***************************************************************************/ + /* List the devices */ + /***************************************************************************/ + struct pci_dev* PciDev; /* Device pointer */ + struct net_device* dev; /* net_device pointer */ + int DeviceCount = 0; + pci_for_each_dev(PciDev) { + if ( BufLen > BufferSize-128) { /* Room for another line? */ + BufLen +=sprintf(ProcBuffer+BufLen,"Buffer Full\n"); + break; + } + if( PCI_SLOT(PciDev->devfn) != 0) { + ++DeviceCount; + BufLen += sprintf(ProcBuffer+BufLen,"%3d. ",DeviceCount); + if ( PciDev->sysdata != NULL ) { + BufLen += format_device_location(PciDev,ProcBuffer+BufLen,128); + } + else { + BufLen += sprintf(ProcBuffer+BufLen,"No Device Node!\n"); + } + BufLen += sprintf(ProcBuffer+BufLen,"\n"); + + /* look for the net devices out */ + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->base_addr == PciDev->resource[0].start ) { + BufLen += sprintf(ProcBuffer+BufLen, " - Net device: %s\n", dev->name); + break; + } /* if */ + } /* for */ + } /* if(PCI_SLOT(PciDev->devfn) != 0) */ + } + return BufLen; +} +/*******************************************************************************/ +/* Get called when client reads the ../proc/ppc64/pcifr. */ +/*******************************************************************************/ +int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + /* First call will have offset 0 */ + if( off == 0) { + spin_lock(&ProcBufferLock); + ProcBufSize = build_PciDev_Buffer(4096); + ProcFileSize = 0; + } + /* For the persistant folks, set eof and return zero length. */ + else if( ProcBuffer == NULL) { + *eof = 1; + return 0; + } + /* How much data can be moved */ + int MoveSize = ProcBufSize; + if( MoveSize > count) MoveSize = count; + + /* Move the data info the FileSystem buffer. */ + memcpy(page+off,ProcBufPtr,MoveSize); + ProcBufPtr += MoveSize; + ProcBufSize -= MoveSize; + ProcFileSize += MoveSize; + + /* If all the data has been moved, free the buffer and set EOF. */ + if( ProcBufSize == 0) { + kfree(ProcBuffer ); + ProcBuffer = NULL; + spin_unlock(&ProcBufferLock); + *eof = 1; + } + return ProcFileSize; +} +/*******************************************************************************/ +/* Gets called when client writes to ../proc/ppc64/pcifr */ +/*******************************************************************************/ +int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + return count; +} diff -urN linux-2.4.18/arch/ppc64/kernel/proc_pmc.c linux-2.4.19-pre5/arch/ppc64/kernel/proc_pmc.c --- linux-2.4.18/arch/ppc64/kernel/proc_pmc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/proc_pmc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,797 @@ +/* + * proc_pmc.c + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* Change Activity: + * 2001 : mikec : Created + * 2001/06/05 : engebret : Software event count support. + * 2001/08/03 : trautman : Added PCI Flight Recorder + * End Change Activity + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* pci Flight Recorder AHT */ +extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root); + +static int proc_pmc_control_mode = 0; + +static struct proc_dir_entry *proc_ppc64_root = NULL; +static struct proc_dir_entry *proc_ppc64_pmc_root = NULL; +static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL; +static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, }; + +static spinlock_t proc_ppc64_lock; + +extern struct Naca *naca; + +int proc_ppc64_pmc_find_file(void *data); +int proc_ppc64_pmc_read(char *page, char **start, off_t off, + int count, int *eof, char *buffer); +int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, + int count, int *eof, void *data); + +static struct proc_dir_entry *pmc_proc_root = NULL; + +int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data); +int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data); + +int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data); + +int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data); + +int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data); +int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data); + + +void proc_ppc64_init(void) +{ + unsigned long i; + struct proc_dir_entry *ent = NULL; + char buf[256]; + + printk("proc_ppc64: Creating /proc/ppc64/pmc\n"); + + /* + * Create the root, system, and cpu directories as follows: + * /proc/ppc64/pmc/system + * /proc/ppc64/pmc/cpu0 + */ + spin_lock(&proc_ppc64_lock); + proc_ppc64_root = proc_mkdir("ppc64", 0); + if (!proc_ppc64_root) return; + spin_unlock(&proc_ppc64_lock); + + /* Create the /proc/ppc64/pcifr for the Pci Flight Recorder. */ + proc_pciFr_init(proc_ppc64_root); + +#ifdef CONFIG_PPC_EEH + eeh_init_proc(proc_ppc64_root); +#endif + + proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root); + + proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root); + for (i = 0; i < naca->processorCount; i++) { + sprintf(buf, "cpu%ld", i); + proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root); + } + + + /* Create directories for the software counters. */ + for (i = 0; i < naca->processorCount; i++) { + ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_cpu_root[i]); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; + ent->read_proc = (void *)proc_ppc64_pmc_stab_read; + ent->write_proc = (void *)proc_ppc64_pmc_stab_read; + } + + ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_cpu_root[i]); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; + ent->read_proc = (void *)proc_ppc64_pmc_htab_read; + ent->write_proc = (void *)proc_ppc64_pmc_htab_read; + } + } + + ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_system_root); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_system_root; + ent->read_proc = (void *)proc_ppc64_pmc_stab_read; + ent->write_proc = (void *)proc_ppc64_pmc_stab_read; + } + + ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_system_root); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_system_root; + ent->read_proc = (void *)proc_ppc64_pmc_htab_read; + ent->write_proc = (void *)proc_ppc64_pmc_htab_read; + } + + /* Create directories for the hardware counters. */ + for (i = 0; i < naca->processorCount; i++) { + ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_cpu_root[i]); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; + ent->read_proc = (void *)proc_ppc64_pmc_hw_read; + ent->write_proc = (void *)proc_ppc64_pmc_hw_read; + } + } + + ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, + proc_ppc64_pmc_system_root); + if (ent) { + ent->nlink = 1; + ent->data = (void *)proc_ppc64_pmc_system_root; + ent->read_proc = (void *)proc_ppc64_pmc_hw_read; + ent->write_proc = (void *)proc_ppc64_pmc_hw_read; + } +} + +/* + * Find the requested 'file' given a proc token. + * + * Inputs: void * data: proc token + * Output: int : (0, ..., +N) = CPU number. + * -1 = System. + */ +int proc_ppc64_pmc_find_file(void *data) +{ + int i; + + if ((unsigned long)data == + (unsigned long) proc_ppc64_pmc_system_root) { + return(-1); + } else { + for (i = 0; i < naca->processorCount; i++) { + if ((unsigned long)data == + (unsigned long)proc_ppc64_pmc_cpu_root[i]) { + return(i); + } + } + } + + /* On error, just default to a type of system. */ + printk("proc_ppc64_pmc_find_file: failed to find file token.\n"); + return(-1); +} + +int +proc_ppc64_pmc_read(char *page, char **start, off_t off, + int count, int *eof, char *buffer) +{ + int buffer_size, n; + + if (count < 0) return 0; + + if (buffer == NULL) { + *eof = 1; + return 0; + } + + /* Check for read beyond EOF */ + buffer_size = n = strlen(buffer); + if (off >= buffer_size) { + *eof = 1; + return 0; + } + if (n > (buffer_size - off)) n = buffer_size - off; + + /* Never return more than was requested */ + if (n > count) { + n = count; + } else { + *eof = 1; + } + + memcpy(page, buffer + off, n); + + *start = page; + + return n; +} + +int +proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int n, file; + char *buffer = NULL; + + if (count < 0) return 0; + spin_lock(&proc_ppc64_lock); + + /* Figure out which file is being request. */ + file = proc_ppc64_pmc_find_file(data); + + /* Update the counters and the text buffer representation. */ + buffer = ppc64_pmc_stab(file); + + /* Put the data into the requestor's buffer. */ + n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); + + spin_unlock(&proc_ppc64_lock); + return n; +} + +int +proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int n, file; + char *buffer = NULL; + + if (count < 0) return 0; + spin_lock(&proc_ppc64_lock); + + /* Figure out which file is being request. */ + file = proc_ppc64_pmc_find_file(data); + + /* Update the counters and the text buffer representation. */ + buffer = ppc64_pmc_htab(file); + + /* Put the data into the requestor's buffer. */ + n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); + + spin_unlock(&proc_ppc64_lock); + return n; +} + +int +proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int n, file; + char *buffer = NULL; + + if (count < 0) return 0; + spin_lock(&proc_ppc64_lock); + + /* Figure out which file is being request. */ + file = proc_ppc64_pmc_find_file(data); + + /* Update the counters and the text buffer representation. */ + buffer = ppc64_pmc_hw(file); + + /* Put the data into the requestor's buffer. */ + n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); + + spin_unlock(&proc_ppc64_lock); + return n; +} + +/* + * DRENG the remainder of these functions still need work ... + */ +void pmc_proc_init(struct proc_dir_entry *iSeries_proc) +{ + struct proc_dir_entry *ent = NULL; + + ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_get_lpevents; + ent->write_proc = proc_reset_lpevents; + + ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_get_titanTod; + ent->write_proc = NULL; + + pmc_proc_root = proc_mkdir("pmc", iSeries_proc); + if (!pmc_proc_root) return; + + ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root); + if (!ent) return; + ent->nlink = 1; + ent->data = (void *)0; + ent->read_proc = proc_pmc_get_control; + ent->write_proc = proc_pmc_set_control; + +} + +static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len) +{ + if ( len <= off+count) + *eof = 1; + *start = page+off; + len -= off; + if ( len > count ) + len = count; + if ( len < 0 ) + len = 0; + return len; +} + +static char * lpEventTypes[9] = { + "Hypervisor\t\t", + "Machine Facilities\t", + "Session Manager\t", + "SPD I/O\t\t", + "Virtual Bus\t\t", + "PCI I/O\t\t", + "RIO I/O\t\t", + "Virtual Lan\t\t", + "Virtual I/O\t\t" + }; + + +int proc_get_lpevents +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + unsigned i; + int len = 0; + + len += sprintf( page+len, "LpEventQueue 0\n" ); + len += sprintf( page+len, " events processed:\t%lu\n", + (unsigned long)xItLpQueue.xLpIntCount ); + for (i=0; i<9; ++i) { + len += sprintf( page+len, " %s %10lu\n", + lpEventTypes[i], + (unsigned long)xItLpQueue.xLpIntCountByType[i] ); + } + len += sprintf( page+len, "\n events processed by processor:\n" ); + for (i=0; iprocessorCount; ++i) { + len += sprintf( page+len, " CPU%02d %10u\n", + i, xPaca[i].lpEvent_count ); + } + + return pmc_calc_metrics( page, start, off, count, eof, len ); + +} + +int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + return count; +} + +static unsigned long startTitan = 0; +static unsigned long startTb = 0; + + +int proc_get_titanTod +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + unsigned long tb0, titan_tod; + + tb0 = get_tb(); + titan_tod = HvCallXm_loadTod(); + + len += sprintf( page+len, "Titan\n" ); + len += sprintf( page+len, " time base = %016lx\n", tb0 ); + len += sprintf( page+len, " titan tod = %016lx\n", titan_tod ); + len += sprintf( page+len, " xProcFreq = %016x\n", xIoHriProcessorVpd[0].xProcFreq ); + len += sprintf( page+len, " xTimeBaseFreq = %016x\n", xIoHriProcessorVpd[0].xTimeBaseFreq ); + len += sprintf( page+len, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy ); + len += sprintf( page+len, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec ); + + if ( !startTitan ) { + startTitan = titan_tod; + startTb = tb0; + } + else { + unsigned long titan_usec = (titan_tod - startTitan) >> 12; + unsigned long tb_ticks = (tb0 - startTb); + unsigned long titan_jiffies = titan_usec / (1000000/HZ); + unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); + unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec; + unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; + unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; + unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; + unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec; + unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec; + + len += sprintf( page+len, " titan elapsed = %lu uSec\n", titan_usec); + len += sprintf( page+len, " tb elapsed = %lu ticks\n", tb_ticks); + len += sprintf( page+len, " titan jiffies = %lu.%04lu \n", titan_jiffies, titan_jiff_rem_usec ); + len += sprintf( page+len, " tb jiffies = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec ); + len += sprintf( page+len, " new tb_ticks_per_jiffy = %lu\n", new_tb_ticks_per_jiffy ); + + } + + return pmc_calc_metrics( page, start, off, count, eof, len ); +} + +int proc_pmc_get_control +(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) { + unsigned long mach_cycles = mfspr( PMC5 ); + unsigned long inst_complete = mfspr( PMC4 ); + unsigned long inst_dispatch = mfspr( PMC3 ); + unsigned long thread_active_run = mfspr( PMC1 ); + unsigned long thread_active = mfspr( PMC2 ); + unsigned long cpi = 0; + unsigned long cpithou = 0; + unsigned long remain; + + if ( inst_complete ) { + cpi = thread_active_run / inst_complete; + remain = thread_active_run % inst_complete; + if ( inst_complete > 1000000 ) + cpithou = remain / ( inst_complete / 1000 ); + else + cpithou = ( remain * 1000 ) / inst_complete; + } + len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" ); + len += sprintf( page+len, "machine cycles : %12lu\n", mach_cycles ); + len += sprintf( page+len, "thread active cycles : %12lu\n\n", thread_active ); + + len += sprintf( page+len, "instructions completed : %12lu\n", inst_complete ); + len += sprintf( page+len, "instructions dispatched : %12lu\n", inst_dispatch ); + len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run ); + + len += sprintf( page+len, "thread active run cycles/instructions completed\n" ); + len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou ); + + } + else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) { + len += sprintf( page+len, "PMC TLB Mode\n" ); + len += sprintf( page+len, "I-miss count : %12lu\n", mfspr( PMC1 ) ); + len += sprintf( page+len, "I-miss latency : %12lu\n", mfspr( PMC2 ) ); + len += sprintf( page+len, "D-miss count : %12lu\n", mfspr( PMC3 ) ); + len += sprintf( page+len, "D-miss latency : %12lu\n", mfspr( PMC4 ) ); + len += sprintf( page+len, "IERAT miss count : %12lu\n", mfspr( PMC5 ) ); + len += sprintf( page+len, "D-reference count : %12lu\n", mfspr( PMC6 ) ); + len += sprintf( page+len, "miss PTEs searched : %12lu\n", mfspr( PMC7 ) ); + len += sprintf( page+len, "miss >8 PTEs searched : %12lu\n", mfspr( PMC8 ) ); + } + /* IMPLEMENT ME */ + return pmc_calc_metrics( page, start, off, count, eof, len ); +} + +unsigned long proc_pmc_conv_int( const char *buf, unsigned count ) +{ + const char * p; + char b0, b1; + unsigned v, multiplier, mult, i; + unsigned long val; + multiplier = 10; + p = buf; + if ( count >= 3 ) { + b0 = buf[0]; + b1 = buf[1]; + if ( ( b0 == '0' ) && + ( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) { + p = buf + 2; + count -= 2; + multiplier = 16; + } + + } + val = 0; + for ( i=0; i= '0' ) && ( b0 <= '9' ) ) + v = b0 - '0'; + else if ( multiplier == 16 ) { + if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) ) + v = b0 - 'a' + 10; + else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) ) + v = b0 - 'A' + 10; + else + mult = 1; + } + else + mult = 1; + val *= mult; + val += v; + } + + return val; + +} + +static inline void proc_pmc_stop(void) +{ + /* Freeze all counters, leave everything else alone */ + mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 ); +} + +static inline void proc_pmc_start(void) +{ + /* Unfreeze all counters, leave everything else alone */ + mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 ); + +} + +static inline void proc_pmc_reset(void) +{ + /* Clear all the PMCs to zeros + * Assume a "stop" has already frozen the counters + * Clear all the PMCs + */ + mtspr( PMC1, 0 ); + mtspr( PMC2, 0 ); + mtspr( PMC3, 0 ); + mtspr( PMC4, 0 ); + mtspr( PMC5, 0 ); + mtspr( PMC6, 0 ); + mtspr( PMC7, 0 ); + mtspr( PMC8, 0 ); + +} + +static inline void proc_pmc_cpi(void) +{ + /* Configure the PMC registers to count cycles and instructions */ + /* so we can compute cpi */ + /* + * MMCRA[30] = 1 Don't count in wait state (CTRL[31]=0) + * MMCR0[6] = 1 Freeze counters when any overflow + * MMCR0[19:25] = 0x01 PMC1 counts Thread Active Run Cycles + * MMCR0[26:31] = 0x05 PMC2 counts Thread Active Cycles + * MMCR1[0:4] = 0x07 PMC3 counts Instructions Dispatched + * MMCR1[5:9] = 0x03 PMC4 counts Instructions Completed + * MMCR1[10:14] = 0x06 PMC5 counts Machine Cycles + * + */ + + proc_pmc_control_mode = PMC_CONTROL_CPI; + + /* Indicate to hypervisor that we are using the PMCs */ + ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1; + + /* Freeze all counters */ + mtspr( MMCR0, 0x80000000 ); + mtspr( MMCR1, 0x00000000 ); + + /* Clear all the PMCs */ + mtspr( PMC1, 0 ); + mtspr( PMC2, 0 ); + mtspr( PMC3, 0 ); + mtspr( PMC4, 0 ); + mtspr( PMC5, 0 ); + mtspr( PMC6, 0 ); + mtspr( PMC7, 0 ); + mtspr( PMC8, 0 ); + + /* Freeze counters in Wait State (CTRL[31]=0) */ + mtspr( MMCRA, 0x00000002 ); + + /* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */ + mtspr( MMCR1, 0x38cc0000 ); + + mb(); + + /* PMC1<-0x01, PMC2<-0x05 + * Start all counters + */ + mtspr( MMCR0, 0x02000045 ); + +} + +static inline void proc_pmc_tlb(void) +{ + /* Configure the PMC registers to count tlb misses */ + /* + * MMCR0[6] = 1 Freeze counters when any overflow + * MMCR0[19:25] = 0x55 Group count + * PMC1 counts I misses + * PMC2 counts I miss duration (latency) + * PMC3 counts D misses + * PMC4 counts D miss duration (latency) + * PMC5 counts IERAT misses + * PMC6 counts D references (including PMC7) + * PMC7 counts miss PTEs searched + * PMC8 counts miss >8 PTEs searched + * + */ + + proc_pmc_control_mode = PMC_CONTROL_TLB; + + /* Indicate to hypervisor that we are using the PMCs */ + ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1; + + /* Freeze all counters */ + mtspr( MMCR0, 0x80000000 ); + mtspr( MMCR1, 0x00000000 ); + + /* Clear all the PMCs */ + mtspr( PMC1, 0 ); + mtspr( PMC2, 0 ); + mtspr( PMC3, 0 ); + mtspr( PMC4, 0 ); + mtspr( PMC5, 0 ); + mtspr( PMC6, 0 ); + mtspr( PMC7, 0 ); + mtspr( PMC8, 0 ); + + mtspr( MMCRA, 0x00000000 ); + + mb(); + + /* PMC1<-0x55 + * Start all counters + */ + mtspr( MMCR0, 0x02001540 ); + +} + +int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + if ( ! strncmp( buffer, "stop", 4 ) ) + proc_pmc_stop(); + else if ( ! strncmp( buffer, "start", 5 ) ) + proc_pmc_start(); + else if ( ! strncmp( buffer, "reset", 5 ) ) + proc_pmc_reset(); + else if ( ! strncmp( buffer, "cpi", 3 ) ) + proc_pmc_cpi(); + else if ( ! strncmp( buffer, "tlb", 3 ) ) + proc_pmc_tlb(); + + /* IMPLEMENT ME */ + return count; +} + +int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + v = v & ~0x04000000; /* Don't allow interrupts for now */ + if ( v & ~0x80000000 ) /* Inform hypervisor we are using PMCs */ + ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1; + else + ((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 0; + mtspr( MMCR0, v ); + + return count; +} + +int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( MMCR1, v ); + + return count; +} + +int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + v = v & ~0x00008000; /* Don't allow interrupts for now */ + mtspr( MMCRA, v ); + + return count; +} + + +int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC1, v ); + + return count; +} + +int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC2, v ); + + return count; +} + +int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC3, v ); + + return count; +} + +int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC4, v ); + + return count; +} + +int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC5, v ); + + return count; +} + +int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC6, v ); + + return count; +} + +int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC7, v ); + + return count; +} + +int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data ) +{ + unsigned long v; + v = proc_pmc_conv_int( buffer, count ); + mtspr( PMC8, v ); + + return count; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/process.c linux-2.4.19-pre5/arch/ppc64/kernel/process.c --- linux-2.4.18/arch/ppc64/kernel/process.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/process.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,621 @@ +/* + * + * + * linux/arch/ppc/kernel/process.c + * + * Derived from "arch/i386/kernel/process.c" + * Copyright (C) 1995 Linus Torvalds + * + * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and + * Paul Mackerras (paulus@cs.anu.edu.au) + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#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 + +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs); +extern unsigned long _get_SP(void); + +struct task_struct *last_task_used_math = NULL; +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); + +struct mm_struct ioremap_mm = { pgd : ioremap_dir + ,page_table_lock : SPIN_LOCK_UNLOCKED }; + +/* this is 16-byte aligned because it has a stack in it */ +union task_union __attribute((aligned(16))) init_task_union = { + INIT_TASK(init_task_union.task) +}; + +#ifdef CONFIG_SMP +struct current_set_struct current_set[NR_CPUS] = {{&init_task, 0}, }; +#endif + +char *sysmap = NULL; +unsigned long sysmap_size = 0; + +extern char __toc_start; + +#undef SHOW_TASK_SWITCHES +#undef CHECK_STACK + +#if defined(CHECK_STACK) +unsigned long +kernel_stack_top(struct task_struct *tsk) +{ + return ((unsigned long)tsk) + sizeof(union task_union); +} + +unsigned long +task_top(struct task_struct *tsk) +{ + return ((unsigned long)tsk) + sizeof(struct task_struct); +} + +/* check to make sure the kernel stack is healthy */ +int check_stack(struct task_struct *tsk) +{ + unsigned long stack_top = kernel_stack_top(tsk); + unsigned long tsk_top = task_top(tsk); + int ret = 0; + +#if 0 + /* check thread magic */ + if ( tsk->thread.magic != THREAD_MAGIC ) + { + ret |= 1; + printk("thread.magic bad: %08x\n", tsk->thread.magic); + } +#endif + + if ( !tsk ) + printk("check_stack(): tsk bad tsk %p\n",tsk); + + /* check if stored ksp is bad */ + if ( (tsk->thread.ksp > stack_top) || (tsk->thread.ksp < tsk_top) ) + { + printk("stack out of bounds: %s/%d\n" + " tsk_top %08lx ksp %08lx stack_top %08lx\n", + tsk->comm,tsk->pid, + tsk_top, tsk->thread.ksp, stack_top); + ret |= 2; + } + + /* check if stack ptr RIGHT NOW is bad */ + if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) ) + { + printk("current stack ptr out of bounds: %s/%d\n" + " tsk_top %08lx sp %08lx stack_top %08lx\n", + current->comm,current->pid, + tsk_top, _get_SP(), stack_top); + ret |= 4; + } + +#if 0 + /* check amount of free stack */ + for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ ) + { + if ( !i ) + printk("check_stack(): i = %p\n", i); + if ( *i != 0 ) + { + /* only notify if it's less than 900 bytes */ + if ( (i - (unsigned long *)task_top(tsk)) < 900 ) + printk("%d bytes free on stack\n", + i - task_top(tsk)); + break; + } + } +#endif + + if (ret) + { + panic("bad kernel stack"); + } + return(ret); +} +#endif /* defined(CHECK_STACK) */ + +void +enable_kernel_fp(void) +{ +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) + giveup_fpu(current); + else + giveup_fpu(NULL); /* just enables FP for kernel */ +#else + giveup_fpu(last_task_used_math); +#endif /* CONFIG_SMP */ +} + +int +dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +{ + if (regs->msr & MSR_FP) + giveup_fpu(current); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + return 1; +} + +void +_switch_to(struct task_struct *prev, struct task_struct *new, + struct task_struct **last) +{ + struct thread_struct *new_thread, *old_thread; + unsigned long s; + + __save_flags(s); + __cli(); +#if CHECK_STACK + check_stack(prev); + check_stack(new); +#endif + +#ifdef SHOW_TASK_SWITCHES + printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n", + prev->comm,prev->pid, + new->comm,new->pid,new->thread.regs->nip,new->processor, + new->fs->root,prev->fs->root); +#endif +#ifdef CONFIG_SMP + /* avoid complexity of lazy save/restore of fpu + * by just saving it every time we switch out if + * this task used the fpu during the last quantum. + * + * If it tries to use the fpu again, it'll trap and + * reload its fp regs. So we don't have to do a restore + * every switch, just a save. + * -- Cort + */ + if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) ) + giveup_fpu(prev); + + /* prev->last_processor = prev->processor; */ + current_set[smp_processor_id()].task = new; +#endif /* CONFIG_SMP */ + new_thread = &new->thread; + old_thread = ¤t->thread; + *last = _switch(old_thread, new_thread); + __restore_flags(s); +} + +void show_regs(struct pt_regs * regs) +{ + int i; + + printk("NIP: %016lX XER: %016lX LR: %016lX REGS: %p TRAP: %04lx %s\n", + regs->nip, regs->xer, regs->link, regs,regs->trap, print_tainted()); + printk("MSR: %016lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + printk("TASK = %p[%d] '%s' ", + current, current->pid, current->comm); + printk("Last syscall: %ld ", current->thread.last_syscall); + printk("\nlast math %p ", last_task_used_math); + +#ifdef CONFIG_SMP + /* printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); */ +#endif /* CONFIG_SMP */ + + printk("\n"); + for (i = 0; i < 32; i++) + { + long r; + if ((i % 4) == 0) + { + printk("GPR%02d: ", i); + } + + if ( __get_user(r, &(regs->gpr[i])) ) + return; + + printk("%016lX ", r); + if ((i % 4) == 3) + { + printk("\n"); + } + } +} + +void exit_thread(void) +{ + if (last_task_used_math == current) + last_task_used_math = NULL; +} + +void flush_thread(void) +{ + if (last_task_used_math == current) + last_task_used_math = NULL; +} + +void +release_thread(struct task_struct *t) +{ +} + +/* + * Copy a thread.. + */ +int +copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + unsigned long msr; + struct pt_regs * childregs, *kregs; + extern void ret_from_fork(void); + + /* Copy registers */ + childregs = ((struct pt_regs *) + ((unsigned long)p + sizeof(union task_union) + - STACK_FRAME_OVERHEAD)) - 2; + *childregs = *regs; + childregs->gpr[3] = 0; /* Result from fork() */ + p->thread.regs = childregs; + p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; + p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; + kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD); + /* The PPC64 compiler makes use of a TOC to contain function + * pointers. The function (ret_from_except) is actually a pointer + * to the TOC entry. The first entry is a pointer to the actual + * function. + */ + kregs->nip = *((unsigned long *)ret_from_fork); + asm volatile("mfmsr %0" : "=r" (msr):); + kregs->msr = msr; + kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD; + kregs->gpr[2] = (((unsigned long)&__toc_start) + 0x8000); + + if (usp >= (unsigned long) regs) { + /* Stack is in kernel space - must adjust */ + childregs->gpr[1] = (unsigned long)(childregs + 1); + *((unsigned long *) childregs->gpr[1]) = 0; + childregs->gpr[13] = (unsigned long) p; + } else { + /* Provided stack is in user space */ + childregs->gpr[1] = usp; + } + p->thread.last_syscall = -1; + + /* + * copy fpu info - assume lazy fpu switch now always + * -- Cort + */ + if (regs->msr & MSR_FP) { + giveup_fpu(current); + childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); + } + memcpy(&p->thread.fpr, ¤t->thread.fpr, sizeof(p->thread.fpr)); + p->thread.fpscr = current->thread.fpscr; + + return 0; +} + +/* + * Set up a thread for executing a new program + */ +void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp) +{ + unsigned long entry, toc, load_addr = regs->gpr[2]; + + /* fdptr is a relocated pointer to the function descriptor for + * the elf _start routine. The first entry in the function + * descriptor is the entry address of _start and the second + * entry is the TOC value we need to use. + */ + set_fs(USER_DS); + __get_user(entry, (unsigned long *)fdptr); + __get_user(toc, (unsigned long *)fdptr+1); + + /* Check whether the e_entry function descriptor entries + * need to be relocated before we can use them. + */ + if ( load_addr != 0 ) { + entry += load_addr; + toc += load_addr; + } + + regs->nip = entry; + regs->gpr[1] = sp; + regs->gpr[2] = toc; + regs->msr = MSR_USER64; + if (last_task_used_math == current) + last_task_used_math = 0; + current->thread.fpscr = 0; +} + +asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) +{ + unsigned long clone_flags = p1; + int res; + + PPCDBG(PPCDBG_SYS64, "sys_clone - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + res = do_fork(clone_flags, regs->gpr[1], regs, 0); +#ifdef CONFIG_SMP + /* When we clone the idle task we keep the same pid but + * the return value of 0 for both causes problems. + * -- Cort + */ + if ((current->pid == 0) && (current == &init_task)) + res = 1; +#endif /* CONFIG_SMP */ + + PPCDBG(PPCDBG_SYS64, "sys_clone - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return res; +} + +asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) +{ + int res; + + PPCDBG(PPCDBG_SYS64, "sys_fork - entered - pid=%ld comm=%s \n", current->pid, current->comm); + + res = do_fork(SIGCHLD, regs->gpr[1], regs, 0); + +#ifdef CONFIG_SMP + /* When we clone the idle task we keep the same pid but + * the return value of 0 for both causes problems. + * -- Cort + */ + if ((current->pid == 0) && (current == &init_task)) + res = 1; +#endif /* CONFIG_SMP */ + + PPCDBG(PPCDBG_SYS64, "sys_fork - exited - pid=%ld comm=%s \n", current->pid, current->comm); + + return res; +} + +asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) +{ + PPCDBG(PPCDBG_SYS64, "sys_vfork - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); +} + +asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs *regs) +{ + int error; + char * filename; + + PPCDBG(PPCDBG_SYS64, "sys_execve - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + filename = getname((char *) a0); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + if (regs->msr & MSR_FP) + giveup_fpu(current); + + PPCDBG(PPCDBG_SYS64, "sys_execve - before do_execve : filename = %s\n", filename); + + error = do_execve(filename, (char **) a1, (char **) a2, regs); + + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); + + out: + PPCDBG(PPCDBG_SYS64, "sys_execve - exited - pid=%ld current=%lx comm=%s error = %lx\n", current->pid, current, current->comm, error); + + return error; +} + +struct task_struct * alloc_task_struct(void) +{ + struct task_struct * new_task_ptr; + + new_task_ptr = ((struct task_struct *) + __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE))); + + return new_task_ptr; +} + +void free_task_struct(struct task_struct * task_ptr) +{ + free_pages((unsigned long)(task_ptr), get_order(THREAD_SIZE)); +} + +void initialize_paca_hardware_interrupt_stack(void) +{ + extern struct Naca *naca; + + int i; + unsigned long stack; + unsigned long end_of_stack =0; + + for (i=1; i < naca->processorCount; i++) { + /* Carve out storage for the hardware interrupt stack */ + stack = __get_free_pages(GFP_KERNEL, get_order(8*PAGE_SIZE)); + + if ( !stack ) { + printk("ERROR, cannot find space for hardware stack.\n"); + panic(" no hardware stack "); + } + + + /* Store the stack value in the PACA for the processor */ + xPaca[i].xHrdIntStack = stack + (8*PAGE_SIZE) - STACK_FRAME_OVERHEAD; + xPaca[i].xHrdIntCount = 0; + + } + + /* + * __get_free_pages() might give us a page > KERNBASE+256M which + * is mapped with large ptes so we can't set up the guard page. + */ + if (__is_processor(PV_POWER4)) + return; + + for (i=0; i < naca->processorCount; i++) { + /* set page at the top of stack to be protected - prevent overflow */ + end_of_stack = xPaca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD); + ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack); + } +} + +extern char _stext[], _etext[]; + +char * ppc_find_proc_name( unsigned * p, char * buf, unsigned buflen ) +{ + unsigned long tb_flags; + unsigned short name_len; + unsigned long tb_start, code_start, code_ptr, code_offset; + unsigned code_len; + strcpy( buf, "Unknown" ); + code_ptr = (unsigned long)p; + code_offset = 0; + if ( ( (unsigned long)p >= (unsigned long)_stext ) && ( (unsigned long)p <= (unsigned long)_etext ) ) { + while ( (unsigned long)p <= (unsigned long)_etext ) { + if ( *p == 0 ) { + tb_start = (unsigned long)p; + ++p; /* Point to traceback flags */ + tb_flags = *((unsigned long *)p); + p += 2; /* Skip over traceback flags */ + if ( tb_flags & TB_NAME_PRESENT ) { + if ( tb_flags & TB_PARMINFO ) + ++p; /* skip over parminfo data */ + if ( tb_flags & TB_HAS_TBOFF ) { + code_len = *p; /* get code length */ + code_start = tb_start - code_len; + code_offset = code_ptr - code_start + 1; + if ( code_offset > 0x100000 ) + break; + ++p; /* skip over code size */ + } + name_len = *((unsigned short *)p); + if ( name_len > (buflen-20) ) + name_len = buflen-20; + memcpy( buf, ((char *)p)+2, name_len ); + buf[name_len] = 0; + if ( code_offset ) + sprintf( buf+name_len, "+0x%lx", code_offset-1 ); + } + break; + } + ++p; + } + } + return buf; +} + +void +print_backtrace(unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + char name_buf[256]; + + printk("Call backtrace: \n"); + while (sp) { + if (__get_user( i, &sp[2] )) + break; + printk("%016lX ", i); + printk("%s\n", ppc_find_proc_name( (unsigned *)i, name_buf, 256 )); + if (cnt > 32) break; + if (__get_user(sp, (unsigned long **)sp)) + break; + } + printk("\n"); +} + +/* + * 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) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ip, sp; + unsigned long stack_page = (unsigned long)p; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + sp = p->thread.ksp; + do { + sp = *(unsigned long *)sp; + if (sp < (stack_page + (2 * PAGE_SIZE)) || + sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE))) + return 0; + if (count > 0) { + ip = *(unsigned long *)(sp + 16); + if (ip < first_sched || ip >= last_sched) + return (ip & 0xFFFFFFFF); + } + } while (count++ < 16); + return 0; +} + +void show_trace_task(struct task_struct *p) +{ + unsigned long ip, sp; + unsigned long stack_page = (unsigned long)p; + int count = 0; + + if (!p) + return; + + printk("Call Trace: "); + sp = p->thread.ksp; + do { + sp = *(unsigned long *)sp; + if (sp < (stack_page + (2 * PAGE_SIZE)) || + sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE))) + break; + if (count > 0) { + ip = *(unsigned long *)(sp + 16); + printk("[%016lx] ", ip); + } + } while (count++ < 16); + printk("\n"); +} diff -urN linux-2.4.18/arch/ppc64/kernel/prom.c linux-2.4.19-pre5/arch/ppc64/kernel/prom.c --- linux-2.4.18/arch/ppc64/kernel/prom.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/prom.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2351 @@ +/* + * + * + * Procedures for interfacing to Open Firmware. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.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. + */ + +#if 0 +#define DEBUG_YABOOT +#endif + +#if 0 +#define DEBUG_PROM +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_YABOOT +#define call_yaboot(FUNC,...) \ + do { \ + if (FUNC) { \ + struct prom_t *_prom = PTRRELOC(&prom); \ + unsigned long prom_entry = _prom->entry;\ + _prom->entry = (unsigned long)(FUNC); \ + enter_prom(__VA_ARGS__); \ + _prom->entry = prom_entry; \ + } \ + } while (0) +#else +#define call_yaboot(FUNC,...) do { ; } while (0) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "open_pic.h" +#include +#include + +#ifdef CONFIG_FB +#include +#endif + +extern char _end[]; + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ + + +#define PROM_BUG() do { \ + prom_print(RELOC("kernel BUG at ")); \ + prom_print(RELOC(__FILE__)); \ + prom_print(RELOC(":")); \ + prom_print_hex(__LINE__); \ + prom_print(RELOC("!\n")); \ + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ +} while (0) + + + +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + + +struct isa_reg_property { + u32 space; + u32 address; + u32 size; +}; + +struct pci_intr_map { + struct pci_address addr; + u32 dunno; + phandle int_ctrler; + u32 intr; +}; + + +typedef unsigned long interpret_func(struct device_node *, unsigned long, + int, int); +#if 0 +static interpret_func interpret_pci_props; +#endif +static unsigned long interpret_pci_props(struct device_node *, unsigned long, + int, int); + +static interpret_func interpret_isa_props; +static interpret_func interpret_root_props; + +#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ +#define FB_MAX 8 +#endif + + +struct prom_t prom = { + 0, /* entry */ + 0, /* chosen */ + 0, /* cpu */ + 0, /* stdout */ + 0, /* disp_node */ + {0,0,0,{0},NULL}, /* args */ + 0, /* version */ + 32, /* encode_phys_size */ + 0 /* bi_rec pointer */ +#ifdef DEBUG_YABOOT + ,NULL /* yaboot */ +#endif +}; + + +char *prom_display_paths[FB_MAX] __initdata = { 0, }; +unsigned int prom_num_displays = 0; +char *of_stdout_device = 0; + +extern struct rtas_t rtas; +extern unsigned long klimit; +extern unsigned long embedded_sysmap_end; +extern struct Naca *naca; +extern struct lmb lmb; +#ifdef CONFIG_MSCHUNKS +extern struct msChunks msChunks; +#endif /* CONFIG_MSCHUNKS */ + +#define MAX_PHB 16 * 3 // 16 Towers * 3 PHBs/tower +struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}}; + +char *bootpath = 0; +char *bootdevice = 0; + +struct device_node *allnodes = 0; + +#define UNDEFINED_IRQ 0xffff +unsigned short real_irq_to_virt_map[NR_HW_IRQS]; +unsigned short virt_irq_to_real_map[NR_IRQS]; +int last_virt_irq = 2; /* index of last virt_irq. Skip through IPI */ + +static unsigned long call_prom(const char *service, int nargs, int nret, ...); +static void prom_exit(void); +static unsigned long copy_device_tree(unsigned long); +static unsigned long inspect_node(phandle, struct device_node *, unsigned long, + unsigned long, struct device_node ***); +static unsigned long finish_node(struct device_node *, unsigned long, + interpret_func *, int, int); +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 struct bi_record * prom_bi_rec_verify(struct bi_record *); +static unsigned long prom_bi_rec_reserve(unsigned long); +static struct device_node *find_phandle(phandle); + +#ifdef CONFIG_MSCHUNKS +static unsigned long prom_initialize_mschunks(unsigned long); +#ifdef DEBUG_PROM +void prom_dump_mschunks_mapping(void); +#endif /* DEBUG_PROM */ +#endif /* CONFIG_MSCHUNKS */ +#ifdef DEBUG_PROM +void prom_dump_lmb(void); +#endif + +extern unsigned long reloc_offset(void); + +extern void enter_prom(void *dummy,...); + +void cacheable_memzero(void *, unsigned int); + +extern char cmd_line[512]; /* XXX */ +unsigned long dev_tree_size; + +#ifdef CONFIG_HMT +struct { + unsigned int pir; + unsigned int threadid; +} hmt_thread_data[NR_CPUS] = {0}; +#endif /* CONFIG_HMT */ + +char testString[] = "LINUX\n"; + + +/* This is the one and *ONLY* place where we actually call open + * firmware from, since we need to make sure we're running in 32b + * mode when we do. We switch back to 64b mode upon return. + */ + +static unsigned long __init +call_prom(const char *service, int nargs, int nret, ...) +{ + int i; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + va_list list; + + _prom->args.service = (u32)LONG_LSW(service); + _prom->args.nargs = nargs; + _prom->args.nret = nret; + _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); + + va_start(list, nret); + for (i=0; i < nargs ;i++) + _prom->args.args[i] = (prom_arg_t)LONG_LSW(va_arg(list, unsigned long)); + va_end(list); + + for (i=0; i < nret ;i++) + _prom->args.rets[i] = 0; + + enter_prom(&_prom->args); + + return (unsigned long)((nret > 0) ? _prom->args.rets[0] : 0); +} + + +static void __init +prom_exit() +{ + unsigned long offset = reloc_offset(); + + call_prom(RELOC("exit"), 0, 0); + + for (;;) /* should never get here */ + ; +} + +void __init +prom_enter(void) +{ + unsigned long offset = reloc_offset(); + + call_prom(RELOC("enter"), 0, 0); +} + + +void __init +prom_print(const char *msg) +{ + const char *p, *q; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if (_prom->stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom(RELOC("write"), 3, 1, _prom->stdout, + p, q - p); + if (*q != 0) { + ++q; + call_prom(RELOC("write"), 3, 1, _prom->stdout, + RELOC("\r\n"), 2); + } + } +} + +void +prom_print_hex(unsigned long val) +{ + int i, nibbles = sizeof(val)*2; + char buf[sizeof(val)*2+1]; + + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + prom_print(buf); +} + +void +prom_print_nl(void) +{ + unsigned long offset = reloc_offset(); + prom_print(RELOC("\n")); +} + + +static unsigned long +prom_initialize_naca(unsigned long mem) +{ + phandle node; + char type[64]; + unsigned long num_cpus = 0; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + struct Naca *_naca = RELOC(naca); + +#ifdef DEBUG_PROM + prom_print(RELOC("prom_initialize_naca: start...\n")); +#endif + + _naca->pftSize = 0; /* ilog2 of htab size. computed below. */ + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + + if (!strcmp(type, RELOC("cpu"))) { + num_cpus += 1; + + /* We're assuming *all* of the CPUs have the same + * d-cache and i-cache sizes... -Peter + */ + if ( num_cpus == 1 ) { + u32 size; + + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("d-cache-line-size"), + &size, sizeof(size)); + + _naca->dCacheL1LineSize = size; + _naca->dCacheL1LogLineSize = __ilog2(size); + _naca->dCacheL1LinesPerPage = PAGE_SIZE / size; + + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("i-cache-line-size"), + &size, sizeof(size)); + + _naca->iCacheL1LineSize = size; + _naca->iCacheL1LogLineSize = __ilog2(size); + _naca->iCacheL1LinesPerPage = PAGE_SIZE / size; + + if (RELOC(_machine) == _MACH_pSeriesLP) { + u32 pft_size[2]; + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("ibm,pft-size"), + &pft_size, sizeof(pft_size)); + /* pft_size[0] is the NUMA CEC cookie */ + _naca->pftSize = pft_size[1]; + } + } + } else if (!strcmp(type, RELOC("serial"))) { + phandle isa, pci; + struct isa_reg_property reg; + union pci_range ranges; + + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("ibm,aix-loc"), type, sizeof(type)); + + if (strcmp(type, RELOC("S1"))) + continue; + + call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), + ®, sizeof(reg)); + + isa = call_prom(RELOC("parent"), 1, 1, node); + if (!isa) + PROM_BUG(); + pci = call_prom(RELOC("parent"), 1, 1, isa); + if (!pci) + PROM_BUG(); + + call_prom(RELOC("getprop"), 4, 1, pci, RELOC("ranges"), + &ranges, sizeof(ranges)); + + if ( _prom->encode_phys_size == 32 ) + _naca->serialPortAddr = ranges.pci32.phys+reg.address; + else { + _naca->serialPortAddr = + ((((unsigned long)ranges.pci64.phys_hi) << 32) | + (ranges.pci64.phys_lo)) + reg.address; + } + } + } + + _naca->interrupt_controller = IC_INVALID; + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), + type, sizeof(type)); + if (strcmp(type, RELOC("interrupt-controller"))) { + continue; + } + call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"), + type, sizeof(type)); + if (strstr(type, RELOC("open-pic"))) { + _naca->interrupt_controller = IC_OPEN_PIC; + } else if (strstr(type, RELOC("ppc-xicp"))) { + _naca->interrupt_controller = IC_PPC_XIC; + } else { + prom_print(RELOC("prom: failed to recognize interrupt-controller\n")); + } + break; + } + + if (_naca->interrupt_controller == IC_INVALID) { + prom_print(RELOC("prom: failed to find interrupt-controller\n")); + PROM_BUG(); + } + + /* We gotta have at least 1 cpu... */ + if ( (_naca->processorCount = num_cpus) < 1 ) + PROM_BUG(); + + _naca->physicalMemorySize = lmb_phys_mem_size(); + + if (RELOC(_machine) == _MACH_pSeries) { + unsigned long rnd_mem_size, pteg_count; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize); + if (rnd_mem_size < _naca->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = (rnd_mem_size >> (12 + 1)); + + _naca->pftSize = __ilog2(pteg_count << 7); + } + + if (_naca->pftSize == 0) { + prom_print(RELOC("prom: failed to compute pftSize!\n")); + PROM_BUG(); + } + + /* + * Hardcode to GP size. I am not sure where to get this info + * in general, as there does not appear to be a slb-size OF + * entry. At least in Condor and earlier. DRENG + */ + _naca->slb_size = 64; + +#ifdef DEBUG_PROM + prom_print(RELOC("naca->processorCount = 0x")); + prom_print_hex(_naca->processorCount); + prom_print_nl(); + + prom_print(RELOC("naca->physicalMemorySize = 0x")); + prom_print_hex(_naca->physicalMemorySize); + prom_print_nl(); + + prom_print(RELOC("naca->pftSize = 0x")); + prom_print_hex(_naca->pftSize); + prom_print_nl(); + + prom_print(RELOC("naca->dCacheL1LineSize = 0x")); + prom_print_hex(_naca->dCacheL1LineSize); + prom_print_nl(); + + prom_print(RELOC("naca->dCacheL1LogLineSize = 0x")); + prom_print_hex(_naca->dCacheL1LogLineSize); + prom_print_nl(); + + prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x")); + prom_print_hex(_naca->dCacheL1LinesPerPage); + prom_print_nl(); + + prom_print(RELOC("naca->iCacheL1LineSize = 0x")); + prom_print_hex(_naca->iCacheL1LineSize); + prom_print_nl(); + + prom_print(RELOC("naca->iCacheL1LogLineSize = 0x")); + prom_print_hex(_naca->iCacheL1LogLineSize); + prom_print_nl(); + + prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x")); + prom_print_hex(_naca->iCacheL1LinesPerPage); + prom_print_nl(); + + prom_print(RELOC("naca->serialPortAddr = 0x")); + prom_print_hex(_naca->serialPortAddr); + prom_print_nl(); + + prom_print(RELOC("naca->interrupt_controller = 0x")); + prom_print_hex(_naca->interrupt_controller); + prom_print_nl(); + + prom_print(RELOC("_machine = 0x")); + prom_print_hex(RELOC(_machine)); + prom_print_nl(); + + prom_print(RELOC("prom_initialize_naca: end...\n")); +#endif + + return mem; +} + + +static unsigned long __init +prom_initialize_lmb(unsigned long mem) +{ + phandle node; + char type[64]; + unsigned long i, offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + union lmb_reg_property reg; + unsigned long lmb_base, lmb_size; + unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8; + +#ifdef CONFIG_MSCHUNKS + unsigned long max_addr = 0; +#if 1 + /* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */ + unsigned long io_base = 3UL<<30; + unsigned long io_size = 1UL<<30; + unsigned long have_630 = 1; /* assume we have a 630 */ + +#else + unsigned long io_base = ; + unsigned long io_size = ; +#endif +#endif /* CONFIG_MSCHUNKS */ + + lmb_init(); + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + + if (strcmp(type, RELOC("memory"))) + continue; + + num_regs = call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), + ®, sizeof(reg)) / bytes_per_reg; + + for (i=0; i < num_regs ;i++) { + if (_prom->encode_phys_size == 32) { + lmb_base = reg.addr32[i].address; + lmb_size = reg.addr32[i].size; + } else { + lmb_base = reg.addr64[i].address; + lmb_size = reg.addr64[i].size; + } + +#ifdef CONFIG_MSCHUNKS + if ( lmb_addrs_overlap(lmb_base,lmb_size, + io_base,io_size) ) { + /* If we really have dram here, then we don't + * have a 630! -Peter + */ + have_630 = 0; + } +#endif /* CONFIG_MSCHUNKS */ + if ( lmb_add(lmb_base, lmb_size) < 0 ) + prom_print(RELOC("Too many LMB's, discarding this one...\n")); +#ifdef CONFIG_MSCHUNKS + else if ( max_addr < (lmb_base+lmb_size-1) ) + max_addr = lmb_base+lmb_size-1; +#endif /* CONFIG_MSCHUNKS */ + } + + } + +#ifdef CONFIG_MSCHUNKS + if ( have_630 && lmb_addrs_overlap(0,max_addr,io_base,io_size) ) + lmb_add_io(io_base, io_size); +#endif /* CONFIG_MSCHUNKS */ + + lmb_analyze(); +#ifdef DEBUG_PROM + prom_dump_lmb(); +#endif /* DEBUG_PROM */ + +#ifdef CONFIG_MSCHUNKS + mem = prom_initialize_mschunks(mem); +#ifdef DEBUG_PROM + prom_dump_mschunks_mapping(); +#endif /* DEBUG_PROM */ +#endif /* CONFIG_MSCHUNKS */ + + return mem; +} + + +static unsigned long __init +prom_instantiate_rtas(unsigned long mem) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + struct rtas_t *_rtas = PTRRELOC(&rtas); + ihandle prom_rtas; + u32 getprop_rval; + +#ifdef DEBUG_PROM + prom_print(RELOC("prom_instantiate_rtas: start...\n")); +#endif + prom_rtas = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); + if (prom_rtas != (ihandle) -1) { + char hypertas_funcs[1024]; + int rc; + + if ((rc = call_prom(RELOC("getprop"), + 4, 1, prom_rtas, + RELOC("ibm,hypertas-functions"), + hypertas_funcs, + sizeof(hypertas_funcs))) > 0) { + RELOC(_machine) = _MACH_pSeriesLP; + } + + call_prom(RELOC("getprop"), + 4, 1, prom_rtas, + RELOC("rtas-size"), + &getprop_rval, + sizeof(getprop_rval)); + _rtas->size = getprop_rval; + prom_print(RELOC("instantiating rtas")); + if (_rtas->size != 0) { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + // The new code... + mem = PAGE_ALIGN(mem); + _rtas->base = mem + offset - KERNELBASE; + + mem += _rtas->size; + prom_print(RELOC(" at 0x")); + prom_print_hex(_rtas->base); + + prom_rtas = (ihandle)call_prom(RELOC("open"), + 1, 1, RELOC("/rtas")); + prom_print(RELOC("...")); + + if ((long)call_prom(RELOC("call-method"), 3, 2, + RELOC("instantiate-rtas"), + prom_rtas, + _rtas->base) >= 0) { + _rtas->entry = (long)_prom->args.rets[1]; + } + } + + if (_rtas->entry <= 0) { + prom_print(RELOC(" failed\n")); + } else { + prom_print(RELOC(" done\n")); + } + +#ifdef DEBUG_PROM + prom_print(RELOC("rtas->base = 0x")); + prom_print_hex(_rtas->base); + prom_print_nl(); + prom_print(RELOC("rtas->entry = 0x")); + prom_print_hex(_rtas->entry); + prom_print_nl(); + prom_print(RELOC("rtas->size = 0x")); + prom_print_hex(_rtas->size); + prom_print_nl(); +#endif + } +#ifdef DEBUG_PROM + prom_print(RELOC("prom_instantiate_rtas: end...\n")); +#endif + + return mem; +} + +unsigned long prom_strtoul(const char *cp) +{ + unsigned long result = 0,value; + + while (*cp) { + value = *cp-'0'; + result = result*10 + value; + cp++; + } + + return result; +} + + +#ifdef CONFIG_MSCHUNKS +static unsigned long +prom_initialize_mschunks(unsigned long mem) +{ + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + struct msChunks *_msChunks = PTRRELOC(&msChunks); + unsigned long i, pchunk = 0; + unsigned long addr_range = _lmb->memory.size + _lmb->memory.iosize; + unsigned long chunk_size = _lmb->memory.lcd_size; + + + mem = msChunks_alloc(mem, addr_range / chunk_size, chunk_size); + + /* First create phys -> abs mapping for memory/dram */ + for (i=0; i < _lmb->memory.cnt ;i++) { + unsigned long base = _lmb->memory.region[i].base; + unsigned long size = _lmb->memory.region[i].size; + unsigned long achunk = addr_to_chunk(base); + unsigned long end_achunk = addr_to_chunk(base+size); + + if(_lmb->memory.region[i].type != LMB_MEMORY_AREA) + continue; + + _lmb->memory.region[i].physbase = chunk_to_addr(pchunk); + for (; achunk < end_achunk ;) { + PTRRELOC(_msChunks->abs)[pchunk++] = achunk++; + } + } + + /* Now create phys -> abs mapping for IO */ + for (i=0; i < _lmb->memory.cnt ;i++) { + unsigned long base = _lmb->memory.region[i].base; + unsigned long size = _lmb->memory.region[i].size; + unsigned long achunk = addr_to_chunk(base); + unsigned long end_achunk = addr_to_chunk(base+size); + + if(_lmb->memory.region[i].type != LMB_IO_AREA) + continue; + + _lmb->memory.region[i].physbase = chunk_to_addr(pchunk); + for (; achunk < end_achunk ;) { + PTRRELOC(_msChunks->abs)[pchunk++] = achunk++; + } + } + + return mem; +} + +#ifdef DEBUG_PROM +void +prom_dump_mschunks_mapping(void) +{ + unsigned long offset = reloc_offset(); + struct msChunks *_msChunks = PTRRELOC(&msChunks); + unsigned long chunk; + + prom_print(RELOC("\nprom_dump_mschunks_mapping:\n")); + prom_print(RELOC(" msChunks.num_chunks = 0x")); + prom_print_hex(_msChunks->num_chunks); + prom_print_nl(); + prom_print(RELOC(" msChunks.chunk_size = 0x")); + prom_print_hex(_msChunks->chunk_size); + prom_print_nl(); + prom_print(RELOC(" msChunks.chunk_shift = 0x")); + prom_print_hex(_msChunks->chunk_shift); + prom_print_nl(); + prom_print(RELOC(" msChunks.chunk_mask = 0x")); + prom_print_hex(_msChunks->chunk_mask); + prom_print_nl(); + prom_print(RELOC(" msChunks.abs = 0x")); + prom_print_hex(_msChunks->abs); + prom_print_nl(); + + prom_print(RELOC(" msChunks mapping:\n")); + for(chunk=0; chunk < _msChunks->num_chunks ;chunk++) { + prom_print(RELOC(" phys 0x")); + prom_print_hex(chunk); + prom_print(RELOC(" -> abs 0x")); + prom_print_hex(PTRRELOC(_msChunks->abs)[chunk]); + prom_print_nl(); + } + +} +#endif /* DEBUG_PROM */ +#endif /* CONFIG_MSCHUNKS */ + +#ifdef DEBUG_PROM +void +prom_dump_lmb(void) +{ + unsigned long i; + unsigned long offset = reloc_offset(); + struct lmb *_lmb = PTRRELOC(&lmb); + + prom_print(RELOC("\nprom_dump_lmb:\n")); + prom_print(RELOC(" memory.cnt = 0x")); + prom_print_hex(_lmb->memory.cnt); + prom_print_nl(); + prom_print(RELOC(" memory.size = 0x")); + prom_print_hex(_lmb->memory.size); + prom_print_nl(); + prom_print(RELOC(" memory.lcd_size = 0x")); + prom_print_hex(_lmb->memory.lcd_size); + prom_print_nl(); + for (i=0; i < _lmb->memory.cnt ;i++) { + prom_print(RELOC(" memory.region[0x")); + prom_print_hex(i); + prom_print(RELOC("].base = 0x")); + prom_print_hex(_lmb->memory.region[i].base); + prom_print_nl(); + prom_print(RELOC(" .physbase = 0x")); + prom_print_hex(_lmb->memory.region[i].physbase); + prom_print_nl(); + prom_print(RELOC(" .size = 0x")); + prom_print_hex(_lmb->memory.region[i].size); + prom_print_nl(); + prom_print(RELOC(" .type = 0x")); + prom_print_hex(_lmb->memory.region[i].type); + prom_print_nl(); + } + + prom_print_nl(); + prom_print(RELOC(" reserved.cnt = 0x")); + prom_print_hex(_lmb->reserved.cnt); + prom_print_nl(); + prom_print(RELOC(" reserved.size = 0x")); + prom_print_hex(_lmb->reserved.size); + prom_print_nl(); + prom_print(RELOC(" reserved.lcd_size = 0x")); + prom_print_hex(_lmb->reserved.lcd_size); + prom_print_nl(); + for (i=0; i < _lmb->reserved.cnt ;i++) { + prom_print(RELOC(" reserved.region[0x")); + prom_print_hex(i); + prom_print(RELOC("].base = 0x")); + prom_print_hex(_lmb->reserved.region[i].base); + prom_print_nl(); + prom_print(RELOC(" .physbase = 0x")); + prom_print_hex(_lmb->reserved.region[i].physbase); + prom_print_nl(); + prom_print(RELOC(" .size = 0x")); + prom_print_hex(_lmb->reserved.region[i].size); + prom_print_nl(); + prom_print(RELOC(" .type = 0x")); + prom_print_hex(_lmb->reserved.region[i].type); + prom_print_nl(); + } +} +#endif /* DEBUG_PROM */ + + +void +prom_initialize_tce_table(void) +{ + phandle node; + ihandle phb_node; + unsigned long offset = reloc_offset(); + char compatible[64], path[64], type[64]; + unsigned long i, table = 0; + unsigned long base, vbase, align; + unsigned int minalign, minsize; + struct _of_tce_table *prom_tce_table = RELOC(of_tce_table); + unsigned long tce_entry, *tce_entryp; + +#ifdef DEBUG_PROM + prom_print(RELOC("starting prom_initialize_tce_table\n")); +#endif + + /* Search all nodes looking for PHBs. */ + for (node = 0; prom_next_node(&node); ) { + compatible[0] = 0; + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"), + compatible, sizeof(compatible)); + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + + if ((compatible[0] == 0) || + ((strstr(compatible, RELOC("python")) == NULL) && + (strstr(compatible, RELOC("Speedwagon")) == NULL))) { + continue; + } + if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) { + continue; + } + + if (call_prom(RELOC("getprop"), 4, 1, node, + RELOC("tce-table-minalign"), &minalign, + sizeof(minalign)) < 0) { + minalign = 0; + } + + if (call_prom(RELOC("getprop"), 4, 1, node, + RELOC("tce-table-minsize"), &minsize, + sizeof(minsize)) < 0) { + minsize = 4UL << 20; + } + + /* Even though we read what OF wants, we just set the table + * size to 4 MB. This is enough to map 2GB of PCI DMA space. + * By doing this, we avoid the pitfalls of trying to DMA to + * MMIO space and the DMA alias hole. + */ + minsize = 4UL << 20; + + /* Align to the greater of the align or size */ + align = (minalign < minsize) ? minsize : minalign; + + /* Carve out storage for the TCE table. */ + base = lmb_alloc(minsize, align); + + if ( !base ) { + prom_print(RELOC("ERROR, cannot find space for TCE table.\n")); + prom_exit(); + } + + vbase = absolute_to_virt(base); + + /* Save away the TCE table attributes for later use. */ + prom_tce_table[table].node = node; + prom_tce_table[table].base = vbase; + prom_tce_table[table].size = minsize; + +#ifdef DEBUG_PROM + prom_print(RELOC("TCE table: 0x")); + prom_print_hex(table); + prom_print_nl(); + + prom_print(RELOC("\tnode = 0x")); + prom_print_hex(node); + prom_print_nl(); + + prom_print(RELOC("\tbase = 0x")); + prom_print_hex(vbase); + prom_print_nl(); + + prom_print(RELOC("\tsize = 0x")); + prom_print_hex(minsize); + prom_print_nl(); +#endif + + /* Initialize the table to have a one-to-one mapping + * over the allocated size. + */ + tce_entryp = (unsigned long *)base; + for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { + tce_entry = (i << PAGE_SHIFT); + tce_entry |= 0x3; + *tce_entryp = tce_entry; + } + + /* Call OF to setup the TCE hardware */ + if (call_prom(RELOC("package-to-path"), 3, 1, node, + path, 255) <= 0) { + prom_print(RELOC("package-to-path failed\n")); + } else { + prom_print(RELOC("opened ")); + prom_print(path); + prom_print_nl(); + } + + phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path); + if ( (long)phb_node <= 0) { + prom_print(RELOC("open failed\n")); + } else { + prom_print(RELOC("open success\n")); + } + call_prom(RELOC("call-method"), 6, 0, + RELOC("set-64-bit-addressing"), + phb_node, + -1, + minsize, + base & 0xffffffff, + (base >> 32) & 0xffffffff); + call_prom(RELOC("close"), 1, 0, phb_node); + + table++; + } + + /* Flag the first invalid entry */ + prom_tce_table[table].node = 0; +#ifdef DEBUG_PROM + prom_print(RELOC("ending prom_initialize_tce_table\n")); +#endif +} + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of low memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. The holding pattern + * checks that address until its cpu # is there, when it is that + * cpu jumps to __secondary_start(). smp_boot_cpus() takes care + * of setting those values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * Fixup comment... DRENG / PPPBBB - Peter + * + * -- Cort + */ +static void +prom_hold_cpus(unsigned long mem) +{ + unsigned long i; + unsigned int reg; + phandle node; + unsigned long offset = reloc_offset(); + char type[64], *path; + int cpuid = 0; + extern void __secondary_hold(void); + extern unsigned long __secondary_hold_spinloop; + extern unsigned long __secondary_hold_acknowledge; + unsigned long *spinloop = __v2a(&__secondary_hold_spinloop); + unsigned long *acknowledge = __v2a(&__secondary_hold_acknowledge); + unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold)); + struct Naca *_naca = RELOC(naca); + struct Paca *_xPaca = PTRRELOC(&xPaca[0]); + struct prom_t *_prom = PTRRELOC(&prom); + + /* Initially, we must have one active CPU. */ + _naca->processorCount = 1; + +#ifdef DEBUG_PROM + prom_print(RELOC("prom_hold_cpus: start...\n")); + prom_print(RELOC(" 1) spinloop = 0x")); + prom_print_hex(spinloop); + prom_print_nl(); + prom_print(RELOC(" 1) *spinloop = 0x")); + prom_print_hex(*spinloop); + prom_print_nl(); + prom_print(RELOC(" 1) acknowledge = 0x")); + prom_print_hex(acknowledge); + prom_print_nl(); + prom_print(RELOC(" 1) *acknowledge = 0x")); + prom_print_hex(*acknowledge); + prom_print_nl(); + prom_print(RELOC(" 1) secondary_hold = 0x")); + prom_print_hex(secondary_hold); + prom_print_nl(); +#endif + + /* Set the common spinloop variable, so all of the secondary cpus + * will block when they are awakened from their OF spinloop. + * This must occur for both SMP and non SMP kernels, since OF will + * be trashed when we move the kernel. + */ + *spinloop = 0; + +#ifdef CONFIG_HMT + for (i=0; i < NR_CPUS; i++) { + RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; + } +#endif + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + call_prom(RELOC("getprop"), 4, 1, node, RELOC("status"), + type, sizeof(type)); + if (strcmp(type, RELOC("okay")) != 0) + continue; + + reg = -1; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), + ®, sizeof(reg)); + + /* Only need to start secondary procs, not ourself. */ + if ( reg == _prom->cpu ) + continue; + + path = (char *) mem; + memset(path, 0, 256); + if ((long) call_prom(RELOC("package-to-path"), 3, 1, + node, path, 255) < 0) + continue; + + cpuid++; + +#ifdef DEBUG_PROM + prom_print_nl(); + prom_print(RELOC("cpuid = 0x")); + prom_print_hex(cpuid); + prom_print_nl(); + prom_print(RELOC("cpu hw idx = 0x")); + prom_print_hex(reg); + prom_print_nl(); +#endif + _xPaca[cpuid].xHwProcNum = reg; + + prom_print(RELOC("starting cpu ")); + prom_print(path); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + *acknowledge = (unsigned long)-1; + +#ifdef DEBUG_PROM + prom_print(RELOC(" 3) spinloop = 0x")); + prom_print_hex(spinloop); + prom_print_nl(); + prom_print(RELOC(" 3) *spinloop = 0x")); + prom_print_hex(*spinloop); + prom_print_nl(); + prom_print(RELOC(" 3) acknowledge = 0x")); + prom_print_hex(acknowledge); + prom_print_nl(); + prom_print(RELOC(" 3) *acknowledge = 0x")); + prom_print_hex(*acknowledge); + prom_print_nl(); + prom_print(RELOC(" 3) secondary_hold = 0x")); + prom_print_hex(secondary_hold); + prom_print_nl(); + prom_print(RELOC(" 3) cpuid = 0x")); + prom_print_hex(cpuid); + prom_print_nl(); +#endif + call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid); + prom_print(RELOC("...")); + for ( i = 0 ; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) ; +#ifdef DEBUG_PROM + { + unsigned long *p = 0x0; + prom_print(RELOC(" 4) 0x0 = 0x")); + prom_print_hex(*p); + prom_print_nl(); + } +#endif + if (*acknowledge == cpuid) { + prom_print(RELOC("ok\n")); + /* Set the number of active processors. */ + _naca->processorCount++; + } else { + prom_print(RELOC("failed: ")); + prom_print_hex(*acknowledge); + prom_print_nl(); + } + } +#ifdef CONFIG_HMT + /* Only enable HMT on processors that provide support. */ + if (__is_processor(PV_PULSAR) || + __is_processor(PV_ICESTAR) || + __is_processor(PV_SSTAR)) { + prom_print(RELOC(" starting secondary threads\n")); + + for (i=0; i < _naca->processorCount ;i++) { + unsigned long threadid = _naca->processorCount*2-1-i; + + if (i == 0) { + unsigned long pir = _get_PIR(); + if (__is_processor(PV_PULSAR)) { + RELOC(hmt_thread_data)[i].pir = + pir & 0x1f; + } else { + RELOC(hmt_thread_data)[i].pir = + pir & 0x3ff; + } + } + + RELOC(hmt_thread_data)[i].threadid = threadid; +#ifdef DEBUG_PROM + prom_print(RELOC(" cpuid 0x")); + prom_print_hex(i); + prom_print(RELOC(" maps to threadid 0x")); + prom_print_hex(threadid); + prom_print_nl(); + prom_print(RELOC(" pir 0x")); + prom_print_hex(RELOC(hmt_thread_data)[i].pir); + prom_print_nl(); +#endif + _xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1; + } + _naca->processorCount *= 2; + } else { + prom_print(RELOC("Processor is not HMT capable\n")); + } +#endif + +#ifdef DEBUG_PROM + prom_print(RELOC("prom_hold_cpus: end...\n")); +#endif +} + + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ + +unsigned long __init +prom_init(unsigned long r3, unsigned long r4, unsigned long pp, + unsigned long r6, unsigned long r7, yaboot_debug_t *yaboot) +{ + int chrp = 0; + unsigned long mem; + ihandle prom_mmu, prom_op, prom_root, prom_cpu; + phandle cpu_pkg; + unsigned long offset = reloc_offset(); + long l; + char *p, *d; + unsigned long phys; + u32 getprop_rval; + struct Naca *_naca = RELOC(naca); + struct Paca *_xPaca = PTRRELOC(&xPaca[0]); + struct prom_t *_prom = PTRRELOC(&prom); + + /* Default machine type. */ + RELOC(_machine) = _MACH_pSeries; + /* Reset klimit to take into account the embedded system map */ + if (RELOC(embedded_sysmap_end)) + RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end))); + + /* Get a handle to the prom entry point before anything else */ + _prom->entry = pp; + _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6); + if ( _prom->bi_recs != NULL ) { + RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + _prom->bi_recs->data[1]); + } + +#ifdef DEBUG_YABOOT + call_yaboot(yaboot->dummy,offset>>32,offset&0xffffffff); + call_yaboot(yaboot->printf, RELOC("offset = 0x%08x%08x\n"), LONG_MSW(offset), LONG_LSW(offset)); +#endif + + /* Default */ + phys = KERNELBASE - offset; + +#ifdef DEBUG_YABOOT + call_yaboot(yaboot->printf, RELOC("phys = 0x%08x%08x\n"), LONG_MSW(phys), LONG_LSW(phys)); +#endif + + +#ifdef DEBUG_YABOOT + _prom->yaboot = yaboot; + call_yaboot(yaboot->printf, RELOC("pp = 0x%08x%08x\n"), LONG_MSW(pp), LONG_LSW(pp)); + call_yaboot(yaboot->printf, RELOC("prom = 0x%08x%08x\n"), LONG_MSW(_prom->entry), LONG_LSW(_prom->entry)); +#endif + + /* First get a handle for the stdout device */ + _prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1, + RELOC("/chosen")); + +#ifdef DEBUG_YABOOT + call_yaboot(yaboot->printf, RELOC("prom->chosen = 0x%08x%08x\n"), LONG_MSW(_prom->chosen), LONG_LSW(_prom->chosen)); +#endif + + if ((long)_prom->chosen <= 0) + prom_exit(); + + if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen, + RELOC("stdout"), &getprop_rval, + sizeof(getprop_rval)) <= 0) + prom_exit(); + + _prom->stdout = (ihandle)(unsigned long)getprop_rval; + +#ifdef DEBUG_YABOOT + if (_prom->stdout == 0) { + call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout)); + } + + call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout)); +#endif + +#ifdef DEBUG_YABOOT + call_yaboot(yaboot->printf, RELOC("Location: 0x11\n")); +#endif + + mem = RELOC(klimit) - offset; +#ifdef DEBUG_YABOOT + call_yaboot(yaboot->printf, RELOC("Location: 0x11b\n")); +#endif + + /* Get the full OF pathname of the stdout device */ + p = (char *) mem; + memset(p, 0, 256); + call_prom(RELOC("instance-to-path"), 3, 1, _prom->stdout, p, 255); + RELOC(of_stdout_device) = PTRUNRELOC(p); + mem += strlen(p) + 1; + + getprop_rval = 1; + prom_root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); + if (prom_root != (ihandle)-1) { + call_prom(RELOC("getprop"), 4, 1, + prom_root, RELOC("#size-cells"), + &getprop_rval, sizeof(getprop_rval)); + } + _prom->encode_phys_size = (getprop_rval==1) ? 32 : 64; + +#ifdef DEBUG_PROM + prom_print(RELOC("DRENG: Detect OF version...\n")); +#endif + /* Find the OF version */ + prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom")); + if (prom_op != (ihandle)-1) { + char model[64]; + long sz; + sz = (long)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")); + + + /* Determine which cpu is actually running right _now_ */ + if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen, + RELOC("cpu"), &getprop_rval, + sizeof(getprop_rval)) <= 0) + prom_exit(); + + prom_cpu = (ihandle)(unsigned long)getprop_rval; + cpu_pkg = call_prom(RELOC("instance-to-package"), 1, 1, prom_cpu); + call_prom(RELOC("getprop"), 4, 1, + cpu_pkg, RELOC("reg"), + &getprop_rval, sizeof(getprop_rval)); + _prom->cpu = (int)(unsigned long)getprop_rval; + _xPaca[0].xHwProcNum = _prom->cpu; + +#ifdef DEBUG_PROM + prom_print(RELOC("Booting CPU hw index = 0x")); + prom_print_hex(_prom->cpu); + prom_print_nl(); +#endif + + /* Get the boot device and translate it to a full OF pathname. */ + p = (char *) mem; + l = (long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen, + RELOC("bootpath"), p, 1<<20); + if (l > 0) { + p[l] = 0; /* should already be null-terminated */ + RELOC(bootpath) = PTRUNRELOC(p); + mem += l + 1; + d = (char *) mem; + *d = 0; + call_prom(RELOC("canon"), 3, 1, p, d, 1<<20); + RELOC(bootdevice) = PTRUNRELOC(d); + mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); + } + + mem = prom_initialize_lmb(mem); + + mem = prom_bi_rec_reserve(mem); + + mem = prom_instantiate_rtas(mem); + + /* Initialize some system info into the Naca early... */ + mem = prom_initialize_naca(mem); + + /* If we are on an SMP machine, then we *MUST* do the + * following, regardless of whether we have an SMP + * kernel or not. + */ + if ( _naca->processorCount > 1 ) + prom_hold_cpus(mem); + + mem = check_display(mem); + +#ifdef DEBUG_PROM + prom_print(RELOC("copying OF device tree...\n")); +#endif + mem = copy_device_tree(mem); + + RELOC(klimit) = mem + offset; + + lmb_reserve(0, __pa(RELOC(klimit))); + + if (RELOC(_machine) == _MACH_pSeries) + prom_initialize_tce_table(); + + if ((long) call_prom(RELOC("getprop"), 4, 1, + _prom->chosen, + RELOC("mmu"), + &getprop_rval, + sizeof(getprop_rval)) <= 0) { + prom_print(RELOC(" no MMU found\n")); + prom_exit(); + } + + /* We assume the phys. address size is 3 cells */ + RELOC(prom_mmu) = (ihandle)(unsigned long)getprop_rval; + + if ((long)call_prom(RELOC("call-method"), 4, 4, + RELOC("translate"), + prom_mmu, + (void *)(KERNELBASE - offset), + (void *)1) != 0) { + prom_print(RELOC(" (translate failed) ")); + } else { + prom_print(RELOC(" (translate ok) ")); + phys = (unsigned long)_prom->args.rets[3]; + } + + /* If OpenFirmware version >= 3, then use quiesce call */ + if (_prom->version >= 3) { + prom_print(RELOC("Calling quiesce ...\n")); + call_prom(RELOC("quiesce"), 0, 0); + phys = KERNELBASE - offset; + } + + prom_print(RELOC("returning from prom_init\n")); + return phys; +} + + +static int +prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + unsigned long offset = reloc_offset(); + + return (int)(long)call_prom(RELOC("call-method"), 6, 1, + RELOC("color!"), + ih, + (void *)(long) i, + (void *)(long) b, + (void *)(long) g, + (void *)(long) r ); +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init +check_display(unsigned long mem) +{ + phandle node; + ihandle ih; + int i; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char type[64], *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 + }; + + _prom->disp_node = 0; + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) + continue; + /* It seems OF doesn't null-terminate the path :-( */ + path = (char *) mem; + memset(path, 0, 256); + if ((long) call_prom(RELOC("package-to-path"), 3, 1, + node, path, 255) < 0) + continue; + prom_print(RELOC("opening display ")); + prom_print(path); + ih = (ihandle)call_prom(RELOC("open"), 1, 1, path); + if (ih == (ihandle)0 || ih == (ihandle)-1) { + prom_print(RELOC("... failed\n")); + continue; + } + prom_print(RELOC("... ok\n")); + + if (_prom->disp_node == 0) + _prom->disp_node = (ihandle)(unsigned long)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. + */ + mem += strlen(path) + 1; + i = RELOC(prom_num_displays)++; + if (RELOC(of_stdout_device) != 0 && i > 0 + && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { + for (; i > 0; --i) + RELOC(prom_display_paths[i]) = RELOC(prom_display_paths[i-1]); + } + RELOC(prom_display_paths[i]) = PTRUNRELOC(path); + if (RELOC(prom_num_displays) >= FB_MAX) + break; + } + return DOUBLEWORD_ALIGN(mem); +} + +void +virt_irq_init(void) +{ + int i; + for (i = 0; i < NR_IRQS; i++) + virt_irq_to_real_map[i] = UNDEFINED_IRQ; + for (i = 0; i < NR_HW_IRQS; i++) + real_irq_to_virt_map[i] = UNDEFINED_IRQ; +} + +/* Create a mapping for a real_irq if it doesn't already exist. + * Return the virtual irq as a convenience. + */ +unsigned long +virt_irq_create_mapping(unsigned long real_irq) +{ + unsigned long virq; + if (naca->interrupt_controller == IC_OPEN_PIC) + return real_irq; /* no mapping for openpic (for now) */ + virq = real_irq_to_virt(real_irq); + if (virq == UNDEFINED_IRQ) { + /* Assign a virtual IRQ number */ + if (real_irq < NR_IRQS && virt_irq_to_real(real_irq) == UNDEFINED_IRQ) { + /* A 1-1 mapping will work. */ + virq = real_irq; + } else { + while (last_virt_irq < NR_IRQS && + virt_irq_to_real(++last_virt_irq) != UNDEFINED_IRQ) + /* skip irq's in use */; + if (last_virt_irq >= NR_IRQS) + panic("Too many IRQs are required on this system. NR_IRQS=%d\n", NR_IRQS); + virq = last_virt_irq; + } + virt_irq_to_real_map[virq] = real_irq; + real_irq_to_virt_map[real_irq] = virq; + } + return virq; +} + + +static int __init +prom_next_node(phandle *nodep) +{ + phandle node; + unsigned long offset = reloc_offset(); + + if ((node = *nodep) != 0 + && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) + return 1; + } +} + +/* + * Make a copy of the device tree from the PROM. + */ +static unsigned long __init +copy_device_tree(unsigned long mem_start) +{ + phandle root; + unsigned long new_start; + struct device_node **allnextp; + unsigned long offset = reloc_offset(); + unsigned long mem_end = mem_start + (8<<20); + + root = call_prom(RELOC("peer"), 1, 1, (phandle)0); + if (root == (phandle)0) { + prom_print(RELOC("couldn't get device tree root\n")); + prom_exit(); + } + allnextp = &RELOC(allnodes); + mem_start = DOUBLEWORD_ALIGN(mem_start); + new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); + *allnextp = 0; + return new_start; +} + +__init +static unsigned long +inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp) +{ + int l; + phandle child; + struct device_node *np; + struct property *pp, **prev_propp; + char *prev_name, *namep; + unsigned char *valp; + unsigned long offset = reloc_offset(); + + np = (struct device_node *) mem_start; + mem_start += sizeof(struct device_node); + memset(np, 0, sizeof(*np)); + np->node = node; + **allnextpp = PTRUNRELOC(np); + *allnextpp = &np->allnext; + if (dad != 0) { + np->parent = PTRUNRELOC(dad); + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = PTRUNRELOC(np); + else + dad->next->sibling = PTRUNRELOC(np); + dad->next = np; + } + + /* get and store all properties */ + prev_propp = &np->properties; + prev_name = RELOC(""); + for (;;) { + pp = (struct property *) mem_start; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + if ((long) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, + namep) <= 0) + break; + mem_start = DOUBLEWORD_ALIGN((unsigned long)namep + strlen(namep) + 1); + prev_name = namep; + valp = (unsigned char *) mem_start; + pp->value = PTRUNRELOC(valp); + pp->length = (int)(long) + call_prom(RELOC("getprop"), 4, 1, node, namep, + valp, mem_end - mem_start); + if (pp->length < 0) + continue; + mem_start = DOUBLEWORD_ALIGN(mem_start + pp->length); + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + } + *prev_propp = 0; + + /* get the node's full name */ + l = (long) call_prom(RELOC("package-to-path"), 3, 1, node, + (char *) mem_start, mem_end - mem_start); + if (l >= 0) { + np->full_name = PTRUNRELOC((char *) mem_start); + *(char *)(mem_start + l) = 0; + mem_start = DOUBLEWORD_ALIGN(mem_start + l + 1); + } + + /* do all our children */ + child = call_prom(RELOC("child"), 1, 1, node); + while (child != (phandle)0) { + mem_start = inspect_node(child, np, mem_start, mem_end, + allnextpp); + child = call_prom(RELOC("peer"), 1, 1, child); + } + + return mem_start; +} + +/* + * finish_device_tree is called once things are running normally + * (i.e. with text and data mapped to the address they were linked at). + * It traverses the device tree and fills in the name, type, + * {n_}addrs and {n_}intrs fields of each node. + */ +void __init +finish_device_tree(void) +{ + unsigned long mem = klimit; + + virt_irq_init(); + + mem = finish_node(allnodes, mem, NULL, 0, 0); + dev_tree_size = mem - (unsigned long) allnodes; + + mem = _ALIGN(mem, PAGE_SIZE); + lmb_reserve(__pa(klimit), mem-klimit); + + klimit = mem; + + rtas.dev = find_devices("rtas"); +} + +static unsigned long __init +finish_node(struct device_node *np, unsigned long mem_start, + interpret_func *ifunc, int naddrc, int nsizec) +{ + struct device_node *child; + int *ip; + + np->name = get_property(np, "name", 0); + np->type = get_property(np, "device_type", 0); + + /* get the device addresses and interrupts */ + if (ifunc != NULL) { + mem_start = ifunc(np, mem_start, naddrc, nsizec); + } + mem_start = finish_node_interrupts(np, mem_start); + + /* Look for #address-cells and #size-cells properties. */ + ip = (int *) get_property(np, "#address-cells", 0); + if (ip != NULL) + naddrc = *ip; + ip = (int *) get_property(np, "#size-cells", 0); + if (ip != NULL) + nsizec = *ip; + + /* the f50 sets the name to 'display' and 'compatible' to what we + * expect for the name -- Cort + */ + ifunc = NULL; + if (!strcmp(np->name, "display")) + np->name = get_property(np, "compatible", 0); + + if (!strcmp(np->name, "device-tree") || np->parent == NULL) + ifunc = interpret_root_props; + else if (np->type == 0) + ifunc = NULL; + else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) + ifunc = interpret_pci_props; + else if (!strcmp(np->type, "isa")) + ifunc = interpret_isa_props; + + for (child = np->child; child != NULL; child = child->sibling) + mem_start = finish_node(child, mem_start, ifunc, + naddrc, nsizec); + + 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, map_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 = openpic_to_irq(virt_irq_create_mapping(*interrupts++)); + np->intrs[i].sense = 1; + 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; +} + +int +prom_n_addr_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#address-cells", 0); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 1 */ + return 1; +} + +int +prom_n_size_cells(struct device_node* np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = (int *) get_property(np, "#size-cells", 0); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} + +static unsigned long __init +interpret_pci_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) +{ + struct address_range *adr; + struct pci_reg_property *pci_addrs; + int i, l; + + pci_addrs = (struct pci_reg_property *) + get_property(np, "assigned-addresses", &l); + if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) { + i = 0; + adr = (struct address_range *) mem_start; + while ((l -= sizeof(struct pci_reg_property)) >= 0) { + adr[i].space = pci_addrs[i].addr.a_hi; + adr[i].address = pci_addrs[i].addr.a_lo; + adr[i].size = pci_addrs[i].size_lo; + ++i; + } + np->addrs = adr; + np->n_addrs = i; + mem_start += i * sizeof(struct address_range); + } + return mem_start; +} + +static unsigned long __init +interpret_isa_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) +{ + struct isa_reg_property *rp; + struct address_range *adr; + int i, l; + + rp = (struct isa_reg_property *) get_property(np, "reg", &l); + if (rp != 0 && l >= sizeof(struct isa_reg_property)) { + i = 0; + adr = (struct address_range *) mem_start; + while ((l -= sizeof(struct reg_property)) >= 0) { + adr[i].space = rp[i].space; + adr[i].address = rp[i].address + + (adr[i].space? 0: _ISA_MEM_BASE); + adr[i].size = rp[i].size; + ++i; + } + np->addrs = adr; + np->n_addrs = i; + mem_start += i * sizeof(struct address_range); + } + + return mem_start; +} + +static unsigned long __init +interpret_root_props(struct device_node *np, unsigned long mem_start, + int naddrc, int nsizec) +{ + struct address_range *adr; + int i, l; + unsigned int *rp; + int rpsize = (naddrc + nsizec) * sizeof(unsigned int); + + rp = (unsigned int *) get_property(np, "reg", &l); + if (rp != 0 && l >= rpsize) { + i = 0; + adr = (struct address_range *) mem_start; + while ((l -= rpsize) >= 0) { + adr[i].space = 0; + adr[i].address = rp[naddrc - 1]; + adr[i].size = rp[naddrc + nsizec - 1]; + ++i; + rp += naddrc + nsizec; + } + np->addrs = adr; + np->n_addrs = i; + mem_start += i * sizeof(struct address_range); + } + + return mem_start; +} + +/* + * Work out the sense (active-low level / active-high edge) + * of each interrupt from the device tree. + */ +void __init +prom_get_irq_senses(unsigned char *senses, int off, int max) +{ + struct device_node *np; + int i, j; + + /* default to level-triggered */ + memset(senses, 1, max - off); + + for (np = allnodes; np != 0; np = np->allnext) { + for (j = 0; j < np->n_intrs; j++) { + i = np->intrs[j].line; + if (i >= off && i < max) + senses[i-off] = np->intrs[j].sense; + } + } +} + +/* + * Construct and return a list of the device_nodes with a given name. + */ +struct device_node * +find_devices(const char *name) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->name != 0 && strcasecmp(np->name, name) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = 0; + return head; +} + +/* + * Construct and return a list of the device_nodes with a given type. + */ +struct device_node * +find_type_devices(const char *type) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->type != 0 && strcasecmp(np->type, type) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = 0; + return head; +} + +/* + * Returns all nodes linked together + */ +struct device_node * __openfirmware +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 + */ +int +device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncasecmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + + +/* + * Indicates whether the root node has a given value in its + * compatible property. + */ +int +machine_is_compatible(const char *compat) +{ + struct device_node *root; + + root = find_path_device("/"); + if (root == 0) + return 0; + return device_is_compatible(root, compat); +} + +/* + * Construct and return a list of the device_nodes with a given type + * and compatible property. + */ +struct device_node * +find_compatible_devices(const char *type, const char *compat) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcasecmp(np->type, type) == 0)) + continue; + if (device_is_compatible(np, compat)) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = 0; + return head; +} + +/* + * Find the device_node with a given full_name. + */ +struct device_node * +find_path_device(const char *path) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) + return np; + return NULL; +} + +/* + * Find the device_node with a given phandle. + */ +static struct device_node * __init +find_phandle(phandle ph) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->node == ph) + return np; + return NULL; +} + +/* + * Find a property with a given name for a given node + * and return the value. + */ +unsigned char * +get_property(struct device_node *np, const char *name, int *lenp) +{ + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) + if (strcmp(pp->name, name) == 0) { + if (lenp != 0) + *lenp = pp->length; + return pp->value; + } + return 0; +} + +/* + * Add a property to a node + */ +void __openfirmware +prom_add_property(struct device_node* np, struct property* prop) +{ + struct property **next = &np->properties; + + prop->next = NULL; + while (*next) + next = &(*next)->next; + *next = prop; +} + +#if 0 +void __openfirmware +print_properties(struct device_node *np) +{ + struct property *pp; + char *cp; + int i, n; + + for (pp = np->properties; pp != 0; pp = pp->next) { + printk(KERN_INFO "%s", pp->name); + for (i = strlen(pp->name); i < 16; ++i) + printk(" "); + cp = (char *) pp->value; + for (i = pp->length; i > 0; --i, ++cp) + if ((i > 1 && (*cp < 0x20 || *cp > 0x7e)) + || (i == 1 && *cp != 0)) + break; + if (i == 0 && pp->length > 1) { + /* looks like a string */ + printk(" %s\n", (char *) pp->value); + } else { + /* dump it in hex */ + n = pp->length; + if (n > 64) + n = 64; + if (pp->length % 4 == 0) { + unsigned int *p = (unsigned int *) pp->value; + + n /= 4; + for (i = 0; i < n; ++i) { + if (i != 0 && (i % 4) == 0) + printk("\n "); + printk(" %08x", *p++); + } + } else { + unsigned char *bp = pp->value; + + for (i = 0; i < n; ++i) { + if (i != 0 && (i % 16) == 0) + printk("\n "); + printk(" %02x", *bp++); + } + } + printk("\n"); + if (pp->length > 64) + printk(" ... (length = %d)\n", + pp->length); + } + } +} +#endif + + +void __init +abort() +{ +#ifdef CONFIG_XMON + xmon(NULL); +#endif + for (;;) + prom_exit(); +} + + +/* Verify bi_recs are good */ +static struct bi_record * +prom_bi_rec_verify(struct bi_record *bi_recs) +{ + struct bi_record *first, *last; + + if ( bi_recs == NULL || bi_recs->tag != BI_FIRST ) + return NULL; + + last = (struct bi_record *)bi_recs->data[0]; + if ( last == NULL || last->tag != BI_LAST ) + return NULL; + + first = (struct bi_record *)last->data[0]; + if ( first == NULL || first != bi_recs ) + return NULL; + + return bi_recs; +} + +static unsigned long +prom_bi_rec_reserve(unsigned long mem) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + struct bi_record *rec; + + if ( _prom->bi_recs != NULL) { + + for ( rec=_prom->bi_recs; + rec->tag != BI_LAST; + rec=bi_rec_next(rec) ) { + switch (rec->tag) { +#ifdef CONFIG_BLK_DEV_INITRD + case BI_INITRD: + lmb_reserve(rec->data[0], rec->data[1]); + break; +#endif /* CONFIG_BLK_DEV_INITRD */ + } + } + /* The next use of this field will be after relocation + * is enabled, so convert this physical address into a + * virtual address. + */ + _prom->bi_recs = PTRUNRELOC(_prom->bi_recs); + } + + return mem; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/ptrace.c linux-2.4.19-pre5/arch/ppc64/kernel/ptrace.c --- linux-2.4.18/arch/ppc64/kernel/ptrace.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ptrace.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,341 @@ +/* + * linux/arch/ppc/kernel/ptrace.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/m68k/kernel/ptrace.c" + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * Modified by Cort Dougan (cort@hq.fsmlabs.com) + * and Paul Mackerras (paulus@linuxcare.com.au). + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file README.legal in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Set of msr bits that gdb can change on behalf of a process. + */ +#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* + * Get contents of register REGNO in task TASK. + */ +static inline unsigned long get_reg(struct task_struct *task, int regno) +{ + if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) + return ((unsigned long *)task->thread.regs)[regno]; + return (0); +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + if (regno < PT_SOFTE) { + if (regno == PT_MSR) + data = (data & MSR_DEBUGCHANGE) + | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; + return 0; + } + return -EIO; +} + +static inline void +set_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr |= MSR_SE; +} + +static inline void +clear_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr &= ~MSR_SE; +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* make sure the single step bit is not set. */ + clear_single_step(child); +} + +int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret = -EPERM; + + lock_kernel(); + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->p_pptr != current) + goto out_tsk; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long index, tmp; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 3; + if ((addr & 7) || index > PT_FPSCR) + break; + + if (index < PT_FPR0) { + tmp = get_reg(child, (int) index); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; + } + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* If I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + /* write the word at location addr in the USER area */ + case PTRACE_POKEUSR: { + unsigned long index; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 3; + if ((addr & 7) || index > PT_FPSCR) + break; + + if (index == PT_ORIG_R3) + break; + if (index < PT_FPR0) { + ret = put_reg(child, index, data); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; + ret = 0; + } + break; + } + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->ptrace |= PT_TRACESYS; + else + child->ptrace &= ~PT_TRACESYS; + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } + +/* + * 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. + */ + case PTRACE_KILL: { + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~PT_TRACESYS; + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + case PPC_PTRACE_GETREGS: + { /* Get GPRs 0 - 31. */ + u64 tmp; + u64 cntr; + ret = 0; + for (cntr=0; cntr<32 && ret==0; ++cntr) + { + tmp = ((u64*)child->thread.regs)[cntr]; + ret = put_user(tmp, (u64*)(data+cntr)); + } + break; + } + + case PPC_PTRACE_SETREGS: + { /* Set GPRs 0 - 31. */ + u64 cntr; + ret = 0; + for (cntr=0; cntr<32 && ret==0; ++cntr) + { + ret = put_reg(child, cntr, *(u64*)(data+cntr)); + } + break; + } + + case PPC_PTRACE_GETFPREGS: + { /* Get FPRs 0 - 31. */ + u64 tmp; + u64 cntr; + ret = -EIO; + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + ret = 0; + for (cntr=0; cntr<32 && ret==0; ++cntr) + { + tmp = ((u64*)child->thread.fpr)[cntr]; + ret = put_user(tmp, (u64*)(data+cntr)); + } + break; + } + + case PPC_PTRACE_SETFPREGS: + { /* Get FPRs 0 - 31. */ + u64 cntr; + ret = -EIO; + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + for (cntr=0; cntr<32; ++cntr) + { + ((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr); + } + ret = 0; + break; + } + + default: + ret = -EIO; + break; + } +out_tsk: + free_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +void syscall_trace(void) +{ + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) + return; + current->exit_code = SIGTRAP; + 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 -urN linux-2.4.18/arch/ppc64/kernel/ptrace32.c linux-2.4.19-pre5/arch/ppc64/kernel/ptrace32.c --- linux-2.4.18/arch/ppc64/kernel/ptrace32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ptrace32.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,401 @@ +/* + * linux/arch/ppc/kernel/ptrace32.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/m68k/kernel/ptrace.c" + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * Modified by Cort Dougan (cort@hq.fsmlabs.com) + * and Paul Mackerras (paulus@linuxcare.com.au). + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file README.legal in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Set of msr bits that gdb can change on behalf of a process. + */ +#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* + * Get contents of register REGNO in task TASK. + */ +static inline unsigned long get_reg(struct task_struct *task, int regno) +{ + if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) + return ((unsigned long *)task->thread.regs)[regno]; + return (0); +} + +/* + * Write contents of register REGNO in task TASK. + * (Put DATA into task TASK's register REGNO.) + */ +static inline int put_reg(struct task_struct *task, int regno, unsigned long data) +{ + if (regno < PT_SOFTE) + { + if (regno == PT_MSR) + data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; + return 0; + } + return -EIO; +} + +static inline void +set_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr |= MSR_SE; +} + +static inline void +clear_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr &= ~MSR_SE; +} + +int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) +{ + struct task_struct *child; + int ret = -EPERM; + + lock_kernel(); + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->p_pptr != current) + goto out_tsk; + + switch (request) + { + /* Read word at location ADDR */ + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + { + unsigned int tmp_mem_value; + int copied; + + copied = access_process_vm(child, addr, &tmp_mem_value, sizeof(tmp_mem_value), 0); + ret = -EIO; + if (copied != sizeof(tmp_mem_value)) + break; + ret = put_user(tmp_mem_value, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". + break; + } + + /* Read 4 bytes of the other process' storage */ + /* data is a pointer specifying where the user wants the 4 bytes copied into */ + /* addr is a pointer in the user's storage that contains an 8 byte address in the other process of the 4 bytes that is to be read */ + /* (this is run in a 32-bit process looking at a 64-bit process) */ + /* when I and D space are separate, these will need to be fixed. */ + case PPC_PTRACE_PEEKTEXT_3264: + case PPC_PTRACE_PEEKDATA_3264: + { + u32 tmp_mem_value; + int copied; + u32* addrOthers; + + ret = -EIO; + + /* Get the addr in the other process that we want to read */ + if (get_user(addrOthers,(u32**)addr) != 0) + break; + + copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0); + if (copied != sizeof(tmp_mem_value)) + break; + ret = put_user(tmp_mem_value, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". + break; + } + + /* Read a register (specified by ADDR) out of the "user area" */ + case PTRACE_PEEKUSR: { + int index; + unsigned int reg32bits; + unsigned long tmp_reg_value; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || index > PT_FPSCR32) + break; + + if (index < PT_FPR0) { + tmp_reg_value = get_reg(child, index); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + /* the user space code considers the floating point to be + * an array of unsigned int (32 bits) - the index passed + * in is based on this assumption. + */ + tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0]; + } + reg32bits = tmp_reg_value; + ret = put_user(reg32bits, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". + break; + } + + /* Read 4 bytes out of the other process' pt_regs area */ + /* data is a pointer specifying where the user wants the 4 bytes copied into */ + /* addr is the offset into the other process' pt_regs structure that is to be read */ + /* (this is run in a 32-bit process looking at a 64-bit process) */ + case PPC_PTRACE_PEEKUSR_3264: + { + u32 index; + u32 reg32bits; + u64 tmp_reg_value; + u32 numReg; + u32 part; + + ret = -EIO; + /* Determine which register the user wants */ + index = (u64)addr >> 2; /* Divide addr by 4 */ + numReg = index / 2; + /* Determine which part of the register the user wants */ + if (index % 2) + part = 1; /* want the 2nd half of the register (right-most). */ + else + part = 0; /* want the 1st half of the register (left-most). */ + + /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ + if ((addr & 3) || numReg > PT_FPSCR) + break; + + if (numReg >= PT_FPR0) + { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + } + tmp_reg_value = get_reg(child, numReg); + reg32bits = ((u32*)&tmp_reg_value)[part]; + ret = put_user(reg32bits, (u32*)data); /* copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". */ + break; + } + + /* Write the word at location ADDR */ + /* If I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + unsigned int tmp_value_to_write; + tmp_value_to_write = data; + ret = 0; + if (access_process_vm(child, addr, &tmp_value_to_write, sizeof(tmp_value_to_write), 1) == sizeof(tmp_value_to_write)) + break; + ret = -EIO; + break; + } + + /* Write 4 bytes into the other process' storage */ + /* data is the 4 bytes that the user wants written */ + /* addr is a pointer in the user's storage that contains an 8 byte address in the other process where the 4 bytes that is to be written */ + /* (this is run in a 32-bit process looking at a 64-bit process) */ + /* when I and D space are separate, these will need to be fixed. */ + case PPC_PTRACE_POKETEXT_3264: + case PPC_PTRACE_POKEDATA_3264: + { + u32 tmp_value_to_write = data; + u32* addrOthers; + int bytesWritten; + + /* Get the addr in the other process that we want to write into */ + ret = -EIO; + if (get_user(addrOthers,(u32**)addr) != 0) + break; + + ret = 0; + bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1); + if (bytesWritten == sizeof(tmp_value_to_write)) + break; + ret = -EIO; + break; + } + + /* Write DATA into location ADDR within the USER area */ + case PTRACE_POKEUSR: { + unsigned long index; + + ret = -EIO; + + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || index > PT_FPSCR32) + break; + + if (index == PT_ORIG_R3) + break; + + + if (index < PT_FPR0) { + ret = put_reg(child, index, data); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + /* the user space code considers the floating point to be + * an array of unsigned int (32 bits) - the index passed + * in is based on this assumption. + */ + + ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data; + ret = 0; + } + break; + } + + /* Write 4 bytes into the other process' pt_regs area */ + /* data is the 4 bytes that the user wants written */ + /* addr is the offset into the other process' pt_regs structure that is to be written into */ + /* (this is run in a 32-bit process looking at a 64-bit process) */ + case PPC_PTRACE_POKEUSR_3264: + { + u32 index; + u32 numReg; + + ret = -EIO; + + /* Determine which register the user wants */ + index = (u64)addr >> 2; /* Divide addr by 4 */ + numReg = index / 2; + + /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ + if ((addr & 3) || numReg > PT_FPSCR) + break; + /* Insure it is a register we let them change */ + if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0))) + break; + + if (numReg >= PT_FPR0) + { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + } + + if (numReg == PT_MSR) + data = (data & MSR_DEBUGCHANGE) | (child->thread.regs->msr & ~MSR_DEBUGCHANGE); + + ((u32*)child->thread.regs)[index] = data; + ret = 0; + break; + } + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->ptrace |= PT_TRACESYS; + else + child->ptrace &= ~PT_TRACESYS; + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } + + /* + * 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. + */ + case PTRACE_KILL: { + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~PT_TRACESYS; + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + default: + ret = -EIO; + break; + } +out_tsk: + free_task_struct(child); +out: + unlock_kernel(); + return ret; +} + diff -urN linux-2.4.18/arch/ppc64/kernel/ras.c linux-2.4.19-pre5/arch/ppc64/kernel/ras.c --- linux-2.4.18/arch/ppc64/kernel/ras.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/ras.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,165 @@ + +/* + * ras.c + * Copyright (C) 2001 Dave Engebretsen IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Change Activity: + * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support. + * End Change Activity + */ + +#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 + +static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs); +void init_ras_IRQ(void); + +/* #define DEBUG */ + +/* + * Initialize handlers for the set of interrupts caused by hardware errors + * and power system events. + */ +void init_ras_IRQ(void) { + struct device_node *np; + unsigned int *ireg, len, i; + + if((np = find_path_device("/event-sources/internal-errors")) && + (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", + &len))) { + for(i=0; i<(len / sizeof(*ireg)); i++) { + request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, + &ras_error_interrupt, 0, + "RAS_ERROR", NULL); + ireg++; + } + } + + if((np = find_path_device("/event-sources/epow-events")) && + (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", + &len))) { + for(i=0; i<(len / sizeof(*ireg)); i++) { + request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, + &ras_epow_interrupt, 0, + "RAS_EPOW", NULL); + ireg++; + } + } +} + +/* + * Handle power subsystem events (EPOW). + * + * Presently we just log the event has occured. This should be fixed + * to examine the type of power failure and take appropriate action where + * the time horizon permits something useful to be done. + */ +static void +ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct rtas_error_log log_entry; + unsigned int size = sizeof(log_entry); + long status = 0xdeadbeef; + + status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, + 0x500, irq, + EPOW_WARNING | POWERMGM_EVENTS, + 1, /* Time Critical */ + __pa(&log_entry), size); + + udbg_printf("EPOW <0x%lx 0x%lx>\n", + *((unsigned long *)&log_entry), status); + printk(KERN_WARNING + "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); +} + +/* + * Handle hardware error interrupts. + * + * RTAS check-exception is called to collect data on the exception. If + * the error is deemed recoverable, we log a warning and return. + * For nonrecoverable errors, an error is logged and we stop all processing + * as quickly as possible in order to prevent propagation of the failure. + */ +static void +ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct rtas_error_log log_entry; + unsigned int size = sizeof(log_entry); + long status = 0xdeadbeef; + + status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, + 0x500, irq, + INTERNAL_ERROR, + 1, /* Time Critical */ + __pa(&log_entry), size); + + if((status != 1) && + (log_entry.severity >= SEVERITY_ERROR_SYNC)) { + udbg_printf("HW Error <0x%lx 0x%lx>\n", + *((unsigned long *)&log_entry), status); + printk(KERN_EMERG + "Error: Fatal hardware error <0x%lx 0x%lx>\n", + *((unsigned long *)&log_entry), status); + +#ifndef DEBUG + /* Don't actually power off when debugging so we can test + * without actually failing while injecting errors. + */ + ppc_md.power_off(); +#endif + } else { + udbg_printf("Recoverable HW Error <0x%lx 0x%lx>\n", + *((unsigned long *)&log_entry), status); + printk(KERN_WARNING + "Warning: Recoverable hardware error <0x%lx 0x%lx>\n", + *((unsigned long *)&log_entry), status); + + return; + } +} diff -urN linux-2.4.18/arch/ppc64/kernel/rtas-proc.c linux-2.4.19-pre5/arch/ppc64/kernel/rtas-proc.c --- linux-2.4.18/arch/ppc64/kernel/rtas-proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/rtas-proc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,796 @@ +/* + * arch/ppc64/kernel/rtas-proc.c + * Copyright (C) 2000 Tilmann Bitterberg + * (tilmann@bitterberg.de) + * + * RTAS (Runtime Abstraction Services) stuff + * Intention is to provide a clean user interface + * to use the RTAS. + * + * TODO: + * Split off a header file and maybe move it to a different + * location. Write Documentation on what the /proc/rtas/ entries + * actually do. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* for ppc_md */ +#include + +/* Token for Sensors */ +#define KEY_SWITCH 0x0001 +#define ENCLOSURE_SWITCH 0x0002 +#define THERMAL_SENSOR 0x0003 +#define LID_STATUS 0x0004 +#define POWER_SOURCE 0x0005 +#define BATTERY_VOLTAGE 0x0006 +#define BATTERY_REMAINING 0x0007 +#define BATTERY_PERCENTAGE 0x0008 +#define EPOW_SENSOR 0x0009 +#define BATTERY_CYCLESTATE 0x000a +#define BATTERY_CHARGING 0x000b + +/* IBM specific sensors */ +#define IBM_SURVEILLANCE 0x2328 /* 9000 */ +#define IBM_FANRPM 0x2329 /* 9001 */ +#define IBM_VOLTAGE 0x232a /* 9002 */ +#define IBM_DRCONNECTOR 0x232b /* 9003 */ +#define IBM_POWERSUPPLY 0x232c /* 9004 */ +#define IBM_INTQUEUE 0x232d /* 9005 */ + +/* Status return values */ +#define SENSOR_CRITICAL_HIGH 13 +#define SENSOR_WARNING_HIGH 12 +#define SENSOR_NORMAL 11 +#define SENSOR_WARNING_LOW 10 +#define SENSOR_CRITICAL_LOW 9 +#define SENSOR_SUCCESS 0 +#define SENSOR_HW_ERROR -1 +#define SENSOR_BUSY -2 +#define SENSOR_NOT_EXIST -3 +#define SENSOR_DR_ENTITY -9000 + +/* Location Codes */ +#define LOC_SCSI_DEV_ADDR 'A' +#define LOC_SCSI_DEV_LOC 'B' +#define LOC_CPU 'C' +#define LOC_DISKETTE 'D' +#define LOC_ETHERNET 'E' +#define LOC_FAN 'F' +#define LOC_GRAPHICS 'G' +/* reserved / not used 'H' */ +#define LOC_IO_ADAPTER 'I' +/* reserved / not used 'J' */ +#define LOC_KEYBOARD 'K' +#define LOC_LCD 'L' +#define LOC_MEMORY 'M' +#define LOC_NV_MEMORY 'N' +#define LOC_MOUSE 'O' +#define LOC_PLANAR 'P' +#define LOC_OTHER_IO 'Q' +#define LOC_PARALLEL 'R' +#define LOC_SERIAL 'S' +#define LOC_DEAD_RING 'T' +#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ +#define LOC_VOLTAGE 'V' +#define LOC_SWITCH_ADAPTER 'W' +#define LOC_OTHER 'X' +#define LOC_FIRMWARE 'Y' +#define LOC_SCSI 'Z' + +/* Tokens for indicators */ +#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ +#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ +#define SYSTEM_POWER_STATE 0x0003 +#define WARNING_LIGHT 0x0004 +#define DISK_ACTIVITY_LIGHT 0x0005 +#define HEX_DISPLAY_UNIT 0x0006 +#define BATTERY_WARNING_TIME 0x0007 +#define CONDITION_CYCLE_REQUEST 0x0008 +#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ +#define DR_ACTION 0x2329 /* 9001 */ +#define DR_INDICATOR 0x232a /* 9002 */ +/* 9003 - 9004: Vendor specific */ +#define GLOBAL_INTERRUPT_QUEUE 0x232d /* 9005 */ +/* 9006 - 9999: Vendor specific */ + +/* other */ +#define MAX_SENSORS 17 /* I only know of 17 sensors */ +#define MAX_LINELENGTH 256 +#define SENSOR_PREFIX "ibm,sensor-" +#define cel_to_fahr(x) ((x*9/5)+32) + + +/* Globals */ +static struct proc_dir_entry *proc_rtas; +static struct rtas_sensors sensors; +static struct device_node *rtas_node; +static unsigned long power_on_time = 0; /* Save the time the user set */ +static char progress_led[MAX_LINELENGTH]; + +static unsigned long rtas_tone_frequency = 1000; +static unsigned long rtas_tone_volume = 0; + +/* ****************STRUCTS******************************************* */ +struct individual_sensor { + unsigned int token; + unsigned int quant; +}; + +struct rtas_sensors { + struct individual_sensor sensor[MAX_SENSORS]; + unsigned int quant; +}; + +/* ****************************************************************** */ +/* Declarations */ +static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, + int count, int *eof, void *data); +static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); + +static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, + size_t count, loff_t *ppos); +static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, + size_t count, loff_t *ppos); + +struct file_operations ppc_rtas_poweron_operations = { + read: ppc_rtas_poweron_read, + write: ppc_rtas_poweron_write +}; +struct file_operations ppc_rtas_progress_operations = { + read: ppc_rtas_progress_read, + write: ppc_rtas_progress_write +}; + +struct file_operations ppc_rtas_clock_operations = { + read: ppc_rtas_clock_read, + write: ppc_rtas_clock_write +}; + +struct file_operations ppc_rtas_tone_freq_operations = { + read: ppc_rtas_tone_freq_read, + write: ppc_rtas_tone_freq_write +}; +struct file_operations ppc_rtas_tone_volume_operations = { + read: ppc_rtas_tone_volume_read, + write: ppc_rtas_tone_volume_write +}; + +int ppc_rtas_find_all_sensors (void); +int ppc_rtas_process_sensor(struct individual_sensor s, int state, + int error, char * buf); +char * ppc_rtas_process_error(int error); +int get_location_code(struct individual_sensor s, char * buf); +int check_location_string (char *c, char * buf); +int check_location (char *c, int idx, char * buf); + +/* ****************************************************************** */ +/* MAIN */ +/* ****************************************************************** */ +void proc_rtas_init(void) +{ + struct proc_dir_entry *entry; + + rtas_node = find_devices("rtas"); + if ((rtas_node == 0) || (_machine == _MACH_iSeries)) { + return; + } + + proc_rtas = proc_mkdir("rtas", 0); + if (proc_rtas == 0) + return; + + /* /proc/rtas entries */ + + entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas); + if (entry) entry->proc_fops = &ppc_rtas_progress_operations; + + entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); + if (entry) entry->proc_fops = &ppc_rtas_clock_operations; + + entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); + if (entry) entry->proc_fops = &ppc_rtas_poweron_operations; + + create_proc_read_entry("sensors", S_IRUGO, proc_rtas, + ppc_rtas_sensor_read, NULL); + + entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); + if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations; + + entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); + if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations; +} + +/* ****************************************************************** */ +/* POWER-ON-TIME */ +/* ****************************************************************** */ +static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + struct rtc_time tm; + unsigned long nowtime; + char *dest; + int error; + + nowtime = simple_strtoul(buf, &dest, 10); + if (*dest != '\0' && *dest != '\n') { + printk("ppc_rtas_poweron_write: Invalid time\n"); + return count; + } + power_on_time = nowtime; /* save the time */ + + to_tm(nowtime, &tm); + + error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); + if (error != 0) + printk(KERN_WARNING "error: setting poweron time returned: %s\n", + ppc_rtas_process_error(error)); + return count; +} +/* ****************************************************************** */ +static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int n; + if (power_on_time == 0) + n = sprintf(buf, "Power on time not set\n"); + else + n = sprintf(buf, "%lu\n", power_on_time); + + if (*ppos >= strlen(buf)) + return 0; + if (n > strlen(buf) - *ppos) + n = strlen(buf) - *ppos; + if (n > count) + n = count; + *ppos += n; + return n; +} + +/* ****************************************************************** */ +/* PROGRESS */ +/* ****************************************************************** */ +static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + unsigned long hex; + + strcpy(progress_led, buf); /* save the string */ + /* Lets see if the user passed hexdigits */ + hex = simple_strtoul(buf, NULL, 10); + + ppc_md.progress ((char *)buf, hex); + return count; + + /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/ +} +/* ****************************************************************** */ +static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int n = 0; + if (progress_led != NULL) + n = sprintf (buf, "%s\n", progress_led); + if (*ppos >= strlen(buf)) + return 0; + if (n > strlen(buf) - *ppos) + n = strlen(buf) - *ppos; + if (n > count) + n = count; + *ppos += n; + return n; +} + +/* ****************************************************************** */ +/* CLOCK */ +/* ****************************************************************** */ +static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + struct rtc_time tm; + unsigned long nowtime; + char *dest; + int error; + + nowtime = simple_strtoul(buf, &dest, 10); + if (*dest != '\0' && *dest != '\n') { + printk("ppc_rtas_clock_write: Invalid time\n"); + return count; + } + + to_tm(nowtime, &tm); + error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, 0); + if (error != 0) + printk(KERN_WARNING "error: setting the clock returned: %s\n", + ppc_rtas_process_error(error)); + return count; +} +/* ****************************************************************** */ +static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned long *ret = kmalloc(4*8, GFP_KERNEL); + int n, error; + + error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); + + year = ret[0]; mon = ret[1]; day = ret[2]; + hour = ret[3]; min = ret[4]; sec = ret[5]; + + if (error != 0){ + printk(KERN_WARNING "error: reading the clock returned: %s\n", + ppc_rtas_process_error(error)); + n = sprintf (buf, "0"); + } else { + n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec)); + } + kfree(ret); + + if (*ppos >= strlen(buf)) + return 0; + if (n > strlen(buf) - *ppos) + n = strlen(buf) - *ppos; + if (n > count) + n = count; + *ppos += n; + return n; +} + +/* ****************************************************************** */ +/* SENSOR STUFF */ +/* ****************************************************************** */ +static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, + int count, int *eof, void *data) +{ + int i,j,n; + unsigned long ret; + int state, error; + char *buffer; + int get_sensor_state = rtas_token("get-sensor-state"); + + if (count < 0) + return -EINVAL; + + /* May not be enough */ + buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL); + + if (!buffer) + return -ENOMEM; + + memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS); + + n = sprintf ( buffer , "RTAS (RunTime Abstraction Services) Sensor Information\n"); + n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n"); + n += sprintf ( buffer+n, "********************************************************\n"); + + if (ppc_rtas_find_all_sensors() != 0) { + n += sprintf ( buffer+n, "\nNo sensors are available\n"); + goto return_string; + } + + for (i=0; i= 0) { + error = rtas_call(get_sensor_state, 2, 2, &ret, + sensors.sensor[i].token, sensors.sensor[i].quant-j); + state = (int) ret; + n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n ); + n += sprintf (buffer+n, "\n"); + j--; + } /* while */ + } /* for */ + +return_string: + if (off >= strlen(buffer)) { + *eof = 1; + kfree(buffer); + return 0; + } + if (n > strlen(buffer) - off) + n = strlen(buffer) - off; + if (n > count) + n = count; + else + *eof = 1; + memcpy(buf, buffer + off, n); + *start = buf; + kfree(buffer); + return n; +} + +/* ****************************************************************** */ + +int ppc_rtas_find_all_sensors (void) +{ + unsigned long *utmp; + int len, i, j; + + utmp = (unsigned long *) get_property(rtas_node, "rtas-sensors", &len); + if (utmp == NULL) { + printk (KERN_ERR "error: could not get rtas-sensors\n"); + return 1; + } + + sensors.quant = len / 8; /* int + int */ + + for (i=0, j=0; j= llen) pos=0; + } + return n; +} +/* ****************************************************************** */ +/* INDICATORS - Tone Frequency */ +/* ****************************************************************** */ +static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + unsigned long freq; + char *dest; + int error; + freq = simple_strtoul(buf, &dest, 10); + if (*dest != '\0' && *dest != '\n') { + printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n"); + return count; + } + if (freq < 0) freq = 0; + rtas_tone_frequency = freq; /* save it for later */ + error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, + TONE_FREQUENCY, 0, freq); + if (error != 0) + printk(KERN_WARNING "error: setting tone frequency returned: %s\n", + ppc_rtas_process_error(error)); + return count; +} +/* ****************************************************************** */ +static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int n; + n = sprintf(buf, "%lu\n", rtas_tone_frequency); + + if (*ppos >= strlen(buf)) + return 0; + if (n > strlen(buf) - *ppos) + n = strlen(buf) - *ppos; + if (n > count) + n = count; + *ppos += n; + return n; +} +/* ****************************************************************** */ +/* INDICATORS - Tone Volume */ +/* ****************************************************************** */ +static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + unsigned long volume; + char *dest; + int error; + volume = simple_strtoul(buf, &dest, 10); + if (*dest != '\0' && *dest != '\n') { + printk("ppc_rtas_tone_volume_write: Invalid tone volume\n"); + return count; + } + if (volume < 0) volume = 0; + if (volume > 100) volume = 100; + + rtas_tone_volume = volume; /* save it for later */ + error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, + TONE_VOLUME, 0, volume); + if (error != 0) + printk(KERN_WARNING "error: setting tone volume returned: %s\n", + ppc_rtas_process_error(error)); + return count; +} +/* ****************************************************************** */ +static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int n; + n = sprintf(buf, "%lu\n", rtas_tone_volume); + + if (*ppos >= strlen(buf)) + return 0; + if (n > strlen(buf) - *ppos) + n = strlen(buf) - *ppos; + if (n > count) + n = count; + *ppos += n; + return n; +} diff -urN linux-2.4.18/arch/ppc64/kernel/rtas.c linux-2.4.19-pre5/arch/ppc64/kernel/rtas.c --- linux-2.4.18/arch/ppc64/kernel/rtas.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/rtas.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,209 @@ +/* + * + * Procedures for interfacing to the RTAS on CHRP machines. + * + * Peter Bergner, IBM March 2001. + * Copyright (C) 2001 IBM. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ + +struct rtas_t rtas = { + lock: SPIN_LOCK_UNLOCKED +}; + +extern unsigned long reloc_offset(void); + +void +phys_call_rtas(int token, int nargs, int nret, ...) +{ + va_list list; + unsigned long offset = reloc_offset(); + struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas)); + int i; + + rtas->token = token; + rtas->nargs = nargs; + rtas->nret = nret; + rtas->rets = (rtas_arg_t *)PTRRELOC(&(rtas->args[nargs])); + + va_start(list, nret); + for (i = 0; i < nargs; i++) + rtas->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); + va_end(list); + + enter_rtas(rtas); +} + +void +phys_call_rtas_display_status(char c) +{ + unsigned long offset = reloc_offset(); + struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas)); + + rtas->token = 10; + rtas->nargs = 1; + rtas->nret = 1; + rtas->rets = (rtas_arg_t *)PTRRELOC(&(rtas->args[1])); + rtas->args[0] = (int)c; + + enter_rtas(rtas); +} + +void +call_rtas_display_status(char c) +{ + struct rtas_args *rtas = &(get_paca()->xRtas); + + rtas->token = 10; + rtas->nargs = 1; + rtas->nret = 1; + rtas->rets = (rtas_arg_t *)&(rtas->args[1]); + rtas->args[0] = (int)c; + + enter_rtas((void *)__pa((unsigned long)rtas)); +} + +#if 0 +#define DEBUG_RTAS +#endif +__openfirmware +int +rtas_token(const char *service) +{ + int *tokp; + if (rtas.dev == NULL) { +#ifdef DEBUG_RTAS + udbg_printf("\tNo rtas device in device-tree...\n"); +#endif /* DEBUG_RTAS */ + return RTAS_UNKNOWN_SERVICE; + } + tokp = (int *) get_property(rtas.dev, service, NULL); + return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; +} + +__openfirmware +long +rtas_call(int token, int nargs, int nret, + unsigned long *outputs, ...) +{ + va_list list; + int i; + unsigned long s; + struct rtas_args *rtas_args = &(get_paca()->xRtas); + +#ifdef DEBUG_RTAS + udbg_printf("Entering rtas_call\n"); + udbg_printf("\ttoken = 0x%x\n", token); + udbg_printf("\tnargs = %d\n", nargs); + udbg_printf("\tnret = %d\n", nret); + udbg_printf("\t&outputs = 0x%lx\n", outputs); +#endif /* DEBUG_RTAS */ + if (token == RTAS_UNKNOWN_SERVICE) + return -1; + + rtas_args->token = token; + rtas_args->nargs = nargs; + rtas_args->nret = nret; + rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); + va_start(list, outputs); + for (i = 0; i < nargs; ++i) { + rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); +#ifdef DEBUG_RTAS + udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); +#endif /* DEBUG_RTAS */ + } + va_end(list); + + for (i = 0; i < nret; ++i) + rtas_args->rets[i] = 0; + +#if 0 /* Gotta do something different here, use global lock for now... */ + spin_lock_irqsave(&rtas_args->lock, s); +#else + spin_lock_irqsave(&rtas.lock, s); +#endif +#ifdef DEBUG_RTAS + udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); +#endif /* DEBUG_RTAS */ + enter_rtas((void *)__pa((unsigned long)rtas_args)); +#ifdef DEBUG_RTAS + udbg_printf("\treturned from rtas ...\n"); +#endif /* DEBUG_RTAS */ +#if 0 /* Gotta do something different here, use global lock for now... */ + spin_unlock_irqrestore(&rtas_args->lock, s); +#else + spin_unlock_irqrestore(&rtas.lock, s); +#endif +#ifdef DEBUG_RTAS + for(i=0; i < nret ;i++) + udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); +#endif /* DEBUG_RTAS */ + + if (nret > 1 && outputs != NULL) + for (i = 0; i < nret-1; ++i) + outputs[i] = rtas_args->rets[i+1]; + return (ulong)((nret > 0) ? rtas_args->rets[0] : 0); +} + +void __chrp +rtas_restart(char *cmd) +{ + printk("RTAS system-reboot returned %ld\n", + rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); + for (;;); +} + +void __chrp +rtas_power_off(void) +{ + /* allow power on only with power button press */ + printk("RTAS power-off returned %ld\n", + rtas_call(rtas_token("power-off"), 2, 1, NULL,0xffffffff,0xffffffff)); + for (;;); +} + +void __chrp +rtas_halt(void) +{ + rtas_power_off(); +} diff -urN linux-2.4.18/arch/ppc64/kernel/rtasd.c linux-2.4.19-pre5/arch/ppc64/kernel/rtasd.c --- linux-2.4.18/arch/ppc64/kernel/rtasd.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/rtasd.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2001 Anton Blanchard , IBM + * + * 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. + * + * Communication to userspace based on kernel/printk.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUG(A...) printk(KERN_ERR A) +#else +#define DEBUG(A...) +#endif + +static spinlock_t rtas_log_lock = SPIN_LOCK_UNLOCKED; + +DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait); + +#define LOG_NUMBER 64 /* must be a power of two */ +#define LOG_NUMBER_MASK (LOG_NUMBER-1) + +static char *rtas_log_buf; +static unsigned long rtas_log_start; +static unsigned long rtas_log_size; + +static int surveillance_requested; +static unsigned int rtas_event_scan_rate; +static unsigned int rtas_error_log_max; + +#define EVENT_SCAN_ALL_EVENTS 0xf0000000 +#define SURVEILLANCE_TOKEN 9000 +#define SURVEILLANCE_TIMEOUT 1 +#define SURVEILLANCE_SCANRATE 1 + +/* + * Since we use 32 bit RTAS, the physical address of this must be below + * 4G or else bad things happen. Allocate this in the kernel data and + * make it big enough. + */ +#define RTAS_ERROR_LOG_MAX 1024 +static unsigned char logdata[RTAS_ERROR_LOG_MAX]; + +static int rtas_log_open(struct inode * inode, struct file * file) +{ + return 0; +} + +static int rtas_log_release(struct inode * inode, struct file * file) +{ + return 0; +} + +static ssize_t rtas_log_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int error; + char *tmp; + unsigned long offset; + + if (!buf || count < rtas_error_log_max) + return -EINVAL; + + count = rtas_error_log_max; + + error = verify_area(VERIFY_WRITE, buf, count); + if (error) + return -EINVAL; + + tmp = kmalloc(rtas_error_log_max, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + error = wait_event_interruptible(rtas_log_wait, rtas_log_size); + if (error) + goto out; + + spin_lock(&rtas_log_lock); + offset = rtas_error_log_max * (rtas_log_start & LOG_NUMBER_MASK); + memcpy(tmp, &rtas_log_buf[offset], count); + rtas_log_start += 1; + rtas_log_size -= 1; + spin_unlock(&rtas_log_lock); + + copy_to_user(buf, tmp, count); + error = count; + +out: + kfree(tmp); + return error; +} + +static unsigned int rtas_log_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &rtas_log_wait, wait); + if (rtas_log_size) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations proc_rtas_log_operations = { + read: rtas_log_read, + poll: rtas_log_poll, + open: rtas_log_open, + release: rtas_log_release, +}; + +static void log_rtas(char *buf) +{ + unsigned long offset; + + DEBUG("logging rtas event\n"); + + spin_lock(&rtas_log_lock); + + offset = rtas_error_log_max * + ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); + + memcpy(&rtas_log_buf[offset], buf, rtas_error_log_max); + + if (rtas_log_size < LOG_NUMBER) + rtas_log_size += 1; + else + rtas_log_start += 1; + + spin_unlock(&rtas_log_lock); + wake_up_interruptible(&rtas_log_wait); +} + +static int enable_surveillance(void) +{ + int error; + + error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, SURVEILLANCE_TOKEN, + 0, SURVEILLANCE_TIMEOUT); + + if (error) { + printk(KERN_ERR "rtasd: could not enable surveillance\n"); + return -1; + } + + rtas_event_scan_rate = SURVEILLANCE_SCANRATE; + + return 0; +} + +static int get_eventscan_parms(void) +{ + struct device_node *node; + int *ip; + + node = find_path_device("/rtas"); + + ip = (int *)get_property(node, "rtas-event-scan-rate", NULL); + if (ip == NULL) { + printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); + return -1; + } + rtas_event_scan_rate = *ip; + DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); + + ip = (int *)get_property(node, "rtas-error-log-max", NULL); + if (ip == NULL) { + printk(KERN_ERR "rtasd: no rtas-error-log-max\n"); + return -1; + } + rtas_error_log_max = *ip; + DEBUG("rtas-error-log-max %d\n", rtas_error_log_max); + + if (rtas_error_log_max > RTAS_ERROR_LOG_MAX) { + printk(KERN_ERR "rtasd: truncated error log from %d to %d bytes\n", rtas_error_log_max, RTAS_ERROR_LOG_MAX); + rtas_error_log_max = RTAS_ERROR_LOG_MAX; + } + + return 0; +} + +extern long sys_sched_get_priority_max(int policy); + +static int rtasd(void *unused) +{ + int cpu = 0; + int error; + int first_pass = 1; + int event_scan = rtas_token("event-scan"); + + if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) + goto error; + + rtas_log_buf = vmalloc(rtas_error_log_max*LOG_NUMBER); + if (!rtas_log_buf) { + printk(KERN_ERR "rtasd: no memory\n"); + goto error; + } + + DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); + + daemonize(); + sigfillset(¤t->blocked); + sprintf(current->comm, "rtasd"); + + /* Rusty unreal time task */ + current->policy = SCHED_FIFO; + current->nice = sys_sched_get_priority_max(SCHED_FIFO) + 1; + + cpu = 0; + current->cpus_allowed = 1UL << cpu_logical_map(cpu); + schedule(); + + while(1) { + do { + memset(logdata, 0, rtas_error_log_max); + error = rtas_call(event_scan, 4, 1, NULL, + EVENT_SCAN_ALL_EVENTS, 0, + __pa(logdata), rtas_error_log_max); + if (error == -1) { + printk(KERN_ERR "event-scan failed\n"); + break; + } + + if (error == 0) + log_rtas(logdata); + + } while(error == 0); + + DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id()); + + cpu++; + if (cpu >= smp_num_cpus) { + + if (first_pass && surveillance_requested) { + DEBUG("enabling surveillance\n"); + if (enable_surveillance()) + goto error_vfree; + DEBUG("surveillance enabled\n"); + } + + first_pass = 0; + cpu = 0; + } + + current->cpus_allowed = 1UL << cpu_logical_map(cpu); + + /* Check all cpus for pending events before sleeping*/ + if (first_pass) { + schedule(); + } else { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((HZ*60/rtas_event_scan_rate) / 2); + } + } + +error_vfree: + vfree(rtas_log_buf); +error: + /* Should delete proc entries */ + return -EINVAL; +} + +static void __init rtas_init(void) +{ + struct proc_dir_entry *rtas_dir, *entry; + + rtas_dir = proc_mkdir("rtas", 0); + if (!rtas_dir) { + printk(KERN_ERR "Failed to create rtas proc directory\n"); + } else { + entry = create_proc_entry("error_log", S_IRUSR, rtas_dir); + if (entry) + entry->proc_fops = &proc_rtas_log_operations; + else + printk(KERN_ERR "Failed to create rtas/error_log proc entry\n"); + } + + if (kernel_thread(rtasd, 0, CLONE_FS) < 0) + printk(KERN_ERR "Failed to start RTAS daemon\n"); + + printk(KERN_ERR "RTAS daemon started\n"); +} + +static int __init surveillance_setup(char *str) +{ + int i; + + if (get_option(&str,&i)) { + if (i == 1) + surveillance_requested = 1; + } + + return 1; +} + +__initcall(rtas_init); +__setup("surveillance=", surveillance_setup); diff -urN linux-2.4.18/arch/ppc64/kernel/rtc.c linux-2.4.19-pre5/arch/ppc64/kernel/rtc.c --- linux-2.4.18/arch/ppc64/kernel/rtc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/rtc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,382 @@ +/* + * Real Time Clock interface for PPC64. + * + * Based on rtc.c by Paul Gortmaker + * + * This driver allows use of the real time clock + * from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the + * /proc/driver/rtc pseudo-file for status information. + * + * Interface does not support RTC interrupts nor an alarm. + * + * 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. + * + * 1.0 Mike Corrigan: IBM iSeries rtc support + * 1.1 Dave Engebretsen: IBM pSeries rtc support + */ + +#define RTC_VERSION "1.1" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +extern int piranha_simulator; + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin); + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos); + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Now all the various file operations that we export. + */ + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return -EIO; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time wtime; + + switch (cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + ppc_md.get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 70) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ( yrs > 169 ) + return -EINVAL; + + ppc_md.set_rtc_time(&rtc_tm); + + return 0; + } + case RTC_EPOCH_READ: /* Read the epoch. */ + { + return put_user (epoch, (unsigned long *)arg); + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { + /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) + return -EINVAL; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + epoch = arg; + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/* + * The various file operations we support. + */ +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_llseek, + read: rtc_read, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int __init rtc_init(void) +{ + misc_register(&rtc_dev); + create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + + printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n"); + + return 0; +} + +static void __exit rtc_exit (void) +{ + remove_proc_entry ("driver/rtc", NULL); + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); +EXPORT_NO_SYMBOLS; + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_output (char *buf) +{ + + char *p; + struct rtc_time tm; + + p = buf; + + ppc_md.get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + p += sprintf(p, + "DST_enable\t: no\n" + "BCD\t\t: yes\n" + "24hr\t\t: yes\n" ); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_proc_output (page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +/* + * Get the RTC from the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +void iSeries_get_rtc_time(struct rtc_time *rtc_tm) +{ + if (piranha_simulator) + return; + + mf_getRtc(rtc_tm); + rtc_tm->tm_mon--; +} + + +void pSeries_get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long ret[8]; + int error; + int count; + + /* + * error -2 is clock busy, we keep retrying a few times to see + * if it will come good -- paulus + */ + count = 0; + do { + error = rtas_call(rtas_token("get-time-of-day"), 0, 8, (void *)&ret); + } while (error == -2 && ++count < 1000); + + if (error != 0) { + printk(KERN_WARNING "error: reading the clock failed (%d)\n", + error); + return; + } + + rtc_tm->tm_sec = ret[5]; + rtc_tm->tm_min = ret[4]; + rtc_tm->tm_hour = ret[3]; + rtc_tm->tm_mday = ret[2]; + rtc_tm->tm_mon = ret[1] - 1; + rtc_tm->tm_year = ret[0] - 1900; +} + +int pSeries_set_rtc_time(struct rtc_time *tm) +{ + int error; + int count; + + /* + * error -2 is clock busy, we keep retrying a few times to see + * if it will come good -- paulus + */ + count = 0; + do { + error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, + tm->tm_year + 1900, tm->tm_mon + 1, + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec, 0); + } while (error == -2 && ++count < 1000); + + if (error != 0) + printk(KERN_WARNING "error: setting the clock failed (%d)\n", + error); + + return 0; +} + +/* + * Set the RTC in the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +int iSeries_set_rtc_time(struct rtc_time *tm) +{ + mf_setRtc(tm); + return 0; +} + +void iSeries_get_boot_time(struct rtc_time *tm) +{ + unsigned long time; + static unsigned long lastsec = 1; + + u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart)); + u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1); + int year = 1970; + int year1 = ( dataWord1 >> 24 ) & 0x000000FF; + int year2 = ( dataWord1 >> 16 ) & 0x000000FF; + int sec = ( dataWord1 >> 8 ) & 0x000000FF; + int min = dataWord1 & 0x000000FF; + int hour = ( dataWord2 >> 24 ) & 0x000000FF; + int day = ( dataWord2 >> 8 ) & 0x000000FF; + int mon = dataWord2 & 0x000000FF; + + if ( piranha_simulator ) + return; + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year1); + BCD_TO_BIN(year2); + year = year1 * 100 + year2; + + time = mktime(year, mon, day, hour, min, sec); + time += ( jiffies / HZ ); + + /* Now THIS is a nasty hack! + * It ensures that the first two calls get different answers. + * That way the loop in init_time (time.c) will not think + * the clock is stuck. + */ + if ( lastsec ) { + time -= lastsec; + --lastsec; + } + + to_tm(time, tm); + tm->tm_year -= 1900; + tm->tm_mon -= 1; +} diff -urN linux-2.4.18/arch/ppc64/kernel/semaphore.c linux-2.4.19-pre5/arch/ppc64/kernel/semaphore.c --- linux-2.4.18/arch/ppc64/kernel/semaphore.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/semaphore.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,130 @@ +/* + * + * + * PowerPC-specific semaphore code. + * + * Copyright (C) 1999 Cort Dougan + * + * 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. + * + * April 2001 - Reworked by Paul Mackerras + * to eliminate the SMP races in the old version between the updates + * of `count' and `waking'. Now we use negative `count' values to + * indicate that some process(es) are waiting for the semaphore. + */ + +#include +#include +#include + +/* + * Atomically update sem->count. + * This does the equivalent of the following: + * + * old_count = sem->count; + * tmp = MAX(old_count, 0) + incr; + * sem->count = tmp; + * return old_count; + */ +static inline int __sem_update_count(struct semaphore *sem, int incr) +{ + int old_count, tmp; + + __asm__ __volatile__("\n" +"1: lwarx %0,0,%3\n" +" srawi %1,%0,31\n" +" andc %1,%0,%1\n" +" add %1,%1,%4\n" +" stwcx. %1,0,%3\n" +" bne 1b" + : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) + : "r" (&sem->count), "r" (incr), "m" (sem->count) + : "cc"); + + return old_count; +} + +void __up(struct semaphore *sem) +{ + /* + * Note that we incremented count in up() before we came here, + * but that was ineffective since the result was <= 0, and + * any negative value of count is equivalent to 0. + * This ends up setting count to 1, unless count is now > 0 + * (i.e. because some other cpu has called up() in the meantime), + * in which case we just increment count. + */ + __sem_update_count(sem, 1); + wake_up(&sem->wait); +} + +/* + * Note that when we come in to __down or __down_interruptible, + * we have already decremented count, but that decrement was + * ineffective since the result was < 0, and any negative value + * of count is equivalent to 0. + * Thus it is only when we decrement count from some value > 0 + * that we have actually got the semaphore. + */ +void __down(struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + /* + * Try to get the semaphore. If the count is > 0, then we've + * got the semaphore; we decrement count and exit the loop. + * If the count is 0 or negative, we set it to -1, indicating + * that we are asleep, and then sleep. + */ + while (__sem_update_count(sem, -1) <= 0) { + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + } + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + /* + * If there are any more sleepers, wake one of them up so + * that it can either get the semaphore, or set count to -1 + * indicating that there are still processes sleeping. + */ + 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; + add_wait_queue_exclusive(&sem->wait, &wait); + smp_wmb(); + + while (__sem_update_count(sem, -1) <= 0) { + if (signal_pending(current)) { + /* + * A signal is pending - give up trying. + * Set sem->count to 0 if it is negative, + * since we are no longer sleeping. + */ + __sem_update_count(sem, 0); + retval = -EINTR; + break; + } + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + } + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; +} diff -urN linux-2.4.18/arch/ppc64/kernel/setup.c linux-2.4.19-pre5/arch/ppc64/kernel/setup.c --- linux-2.4.18/arch/ppc64/kernel/setup.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/setup.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,731 @@ +/* + * + * Common boot and setup code. + * + * Copyright (C) 2001 PPC64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long klimit; +/* extern void *stab; */ +extern HTAB htab_data; +extern unsigned long loops_per_jiffy; + +extern unsigned long embedded_sysmap_start; +extern unsigned long embedded_sysmap_end; + +int have_of = 1; + +extern void chrp_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void chrp_init_map_io_space( void ); +extern void iSeries_init( void ); +extern void iSeries_init_early( void ); +extern void pSeries_init_early( void ); +extern void pSeriesLP_init_early(void); +extern void mm_init_ppc64( void ); + +unsigned long decr_overclock = 1; +unsigned long decr_overclock_proc0 = 1; +unsigned long decr_overclock_set = 0; +unsigned long decr_overclock_proc0_set = 0; + +#ifdef CONFIG_XMON +extern void xmon_map_scc(void); +#endif + +char saved_command_line[256]; +unsigned char aux_device_present; + +void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7); +int parse_bootinfo(void); + +unsigned long DMA_MODE_READ, DMA_MODE_WRITE; +int _machine = _MACH_unknown; + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned long SYSRQ_KEY; +#endif /* CONFIG_MAGIC_SYSRQ */ + +struct machdep_calls ppc_md; +struct Naca *naca; + +/* + * Perhaps we can put the pmac screen_info[] here + * on pmac as well so we don't need the ifdef's. + * Until we get multiple-console support in here + * that is. -- Cort + * Maybe tie it to serial consoles, since this is really what + * these processors use on existing boards. -- Dan + */ +struct screen_info screen_info = { + 0, 25, /* orig-x, orig-y */ + 0, /* unused */ + 0, /* orig-video-page */ + 0, /* orig-video-mode */ + 80, /* orig-video-cols */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 25, /* orig-video-lines */ + 1, /* orig-video-isVGA */ + 16 /* orig-video-points */ +}; + +/* + * These are used in binfmt_elf.c to put aux entries on the stack + * for each elf executable being started. + */ +int dcache_bsize; +int icache_bsize; +int ucache_bsize; + +/* + * Initialize the PPCDBG state. Called before relocation has been enabled. + */ +void ppcdbg_initialize(void) { + unsigned long offset = reloc_offset(); + struct Naca *_naca = RELOC(naca); + + _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; +} + +/* + * Initialize a set of PACA's, one for each processor. + * + * At this point, relocation is on, but we have not done any other + * setup of the mm subsystem. + */ +void paca_init(void) { +#if 0 + int processorCount = naca->processorCount, i; + struct Paca *paca[]; + + /* Put the array of paca's on a page boundary & allocate 1/2 page of */ + /* storage for each. */ + klimit += (PAGE_SIZE-1) & PAGE_MASK; + naca->xPaca = paca[0] = klimit; + klimit += ((PAGE_SIZE>>1) * processorCount); + + for(i=0; ixPacaIndex = i; + } +#endif +} + +/* + * Do some initial setup of the system. The paramters are those which + * were passed in from the bootloader. + */ +void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* This should be fixed properly in kernel/resource.c */ + iomem_resource.end = MEM_SPACE_LIMIT; + + /* pSeries systems are identified in prom.c via OF. */ + if ( itLpNaca.xLparInstalled == 1 ) + _machine = _MACH_iSeries; + switch (_machine) { + case _MACH_iSeries: + iSeries_init_early(); + break; + +#ifdef CONFIG_PPC_PSERIES + case _MACH_pSeries: + pSeries_init_early(); +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = initrd_end = 0; +#endif + parse_bootinfo(); + break; + + case _MACH_pSeriesLP: + pSeriesLP_init_early(); +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = initrd_end = 0; +#endif + parse_bootinfo(); + break; +#endif + } + + udbg_puts("\n-----------------------------------------------------\n"); + udbg_puts("Naca Info...\n\n"); + udbg_puts("naca = 0x"); + udbg_puthex((unsigned long)naca); + udbg_putc('\n'); + + udbg_puts("naca->processorCount = 0x"); + udbg_puthex(naca->processorCount); + udbg_putc('\n'); + + udbg_puts("naca->physicalMemorySize = 0x"); + udbg_puthex(naca->physicalMemorySize); + udbg_putc('\n'); + + udbg_puts("naca->dCacheL1LineSize = 0x"); + udbg_puthex(naca->dCacheL1LineSize); + udbg_putc('\n'); + + udbg_puts("naca->dCacheL1LogLineSize = 0x"); + udbg_puthex(naca->dCacheL1LogLineSize); + udbg_putc('\n'); + + udbg_puts("naca->dCacheL1LinesPerPage = 0x"); + udbg_puthex(naca->dCacheL1LinesPerPage); + udbg_putc('\n'); + + udbg_puts("naca->iCacheL1LineSize = 0x"); + udbg_puthex(naca->iCacheL1LineSize); + udbg_putc('\n'); + + udbg_puts("naca->iCacheL1LogLineSize = 0x"); + udbg_puthex(naca->iCacheL1LogLineSize); + udbg_putc('\n'); + + udbg_puts("naca->iCacheL1LinesPerPage = 0x"); + udbg_puthex(naca->iCacheL1LinesPerPage); + udbg_putc('\n'); + + udbg_puts("naca->pftSize = 0x"); + udbg_puthex(naca->pftSize); + udbg_putc('\n'); + + udbg_puts("naca->serialPortAddr = 0x"); + udbg_puthex(naca->serialPortAddr); + udbg_putc('\n'); + + udbg_puts("naca->interrupt_controller = 0x"); + udbg_puthex(naca->interrupt_controller); + udbg_putc('\n'); + + udbg_printf("\nHTAB Info ...\n\n"); + udbg_puts("htab_data.htab = 0x"); + udbg_puthex((unsigned long)htab_data.htab); + udbg_putc('\n'); + udbg_puts("htab_data.num_ptegs = 0x"); + udbg_puthex(htab_data.htab_num_ptegs); + udbg_putc('\n'); + + udbg_puts("\n-----------------------------------------------------\n"); + + + if ( _machine & _MACH_pSeries ) { + finish_device_tree(); + chrp_init(r3, r4, r5, r6, r7); + } + + mm_init_ppc64(); + + switch (_machine) { + case _MACH_iSeries: + iSeries_init(); + break; + default: + /* The following relies on the device tree being */ + /* fully configured. */ + parse_cmd_line(r3, r4, r5, r6, r7); + } +} + +void machine_restart(char *cmd) +{ + ppc_md.restart(cmd); +} + +void machine_power_off(void) +{ + ppc_md.power_off(); +} + +void machine_halt(void) +{ + ppc_md.halt(); +} + +unsigned long ppc_proc_freq; +unsigned long ppc_tb_freq; + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long cpu_id = (unsigned long)v - 1; + unsigned int pvr; + unsigned short maj; + unsigned short min; + +#ifdef CONFIG_SMP + if (cpu_id == NR_CPUS) { + + if (ppc_md.get_cpuinfo != NULL) + ppc_md.get_cpuinfo(m); + + return 0; + } + + if (!(cpu_online_map & (1<> 8) & 0xFF; + min = pvr & 0xFF; + + seq_printf(m, "processor\t: %lu\n", cpu_id); + seq_printf(m, "cpu\t\t: "); + + pvr = xPaca[cpu_id].pvr; + + switch (PVR_VER(pvr)) { + case PV_PULSAR: + seq_printf(m, "RS64-III (pulsar)\n"); + break; + case PV_POWER4: + seq_printf(m, "POWER4 (gp)\n"); + break; + case PV_ICESTAR: + seq_printf(m, "RS64-III (icestar)\n"); + break; + case PV_SSTAR: + seq_printf(m, "RS64-IV (sstar)\n"); + break; + case PV_630: + seq_printf(m, "POWER3 (630)\n"); + break; + case PV_630p: + seq_printf(m, "POWER3 (630+)\n"); + break; + default: + seq_printf(m, "Unknown (%08x)\n", pvr); + break; + } + + /* + * Assume here that all clock rates are the same in a + * smp system. -- Cort + */ + if (_machine != _MACH_iSeries) { + struct device_node *cpu_node; + int *fp; + + cpu_node = find_type_devices("cpu"); + if (cpu_node) { + fp = (int *) get_property(cpu_node, "clock-frequency", + NULL); + if (fp) + seq_printf(m, "clock\t\t: %dMHz\n", + *fp / 1000000); + } + } + + if (ppc_md.setup_residual != NULL) + ppc_md.setup_residual(m, cpu_id); + + seq_printf(m, "revision\t: %hd.%hd\n", maj, min); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} +static void c_stop(struct seq_file *m, void *v) +{ +} +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; + +/* + * Fetch the cmd_line from open firmware. */ +void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + struct device_node *chosen; + char *p; + +#ifdef CONFIG_BLK_DEV_INITRD + if ((initrd_start == 0) && r3 && r4 && r4 != 0xdeadbeef) { + initrd_start = (r3 >= KERNELBASE) ? r3 : (unsigned long)__va(r3); + initrd_end = initrd_start + r4; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; + } +#endif + + cmd_line[0] = 0; + chosen = find_devices("chosen"); + if (chosen != NULL) { + p = get_property(chosen, "bootargs", NULL); + if (p != NULL) + strncpy(cmd_line, p, sizeof(cmd_line)); + } + cmd_line[sizeof(cmd_line) - 1] = 0; + + /* Look for mem= option on command line */ + if (strstr(cmd_line, "mem=")) { + char *p, *q; + unsigned long maxmem = 0; + extern unsigned long __max_memory; + + for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { + q = p + 4; + if (p > cmd_line && p[-1] != ' ') + continue; + maxmem = simple_strtoul(q, &q, 0); + if (*q == 'k' || *q == 'K') { + maxmem <<= 10; + ++q; + } else if (*q == 'm' || *q == 'M') { + maxmem <<= 20; + ++q; + } + } + __max_memory = maxmem; + } + ppc_md.progress("id mach: done", 0x200); +} + + +char *bi_tag2str(unsigned long tag) +{ + switch (tag) { + case BI_FIRST: + return "BI_FIRST"; + case BI_LAST: + return "BI_LAST"; + case BI_CMD_LINE: + return "BI_CMD_LINE"; + case BI_BOOTLOADER_ID: + return "BI_BOOTLOADER_ID"; + case BI_INITRD: + return "BI_INITRD"; + case BI_SYSMAP: + return "BI_SYSMAP"; + case BI_MACHTYPE: + return "BI_MACHTYPE"; + default: + return "BI_UNKNOWN"; + } +} + +int parse_bootinfo(void) +{ + struct bi_record *rec; + extern char *sysmap; + extern unsigned long sysmap_size; + + rec = prom.bi_recs; + + if ( rec == NULL || rec->tag != BI_FIRST ) + return -1; + + for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) { + switch (rec->tag) { + case BI_CMD_LINE: + memcpy(cmd_line, (void *)rec->data, rec->size); + break; + case BI_SYSMAP: + sysmap = (char *)((rec->data[0] >= (KERNELBASE)) + ? rec->data[0] : (unsigned long)__va(rec->data[0])); + sysmap_size = rec->data[1]; + break; +#ifdef CONFIG_BLK_DEV_INITRD + case BI_INITRD: + initrd_start = (unsigned long)__va(rec->data[0]); + initrd_end = initrd_start + rec->data[1]; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; + break; +#endif /* CONFIG_BLK_DEV_INITRD */ + } + } + + return 0; +} + +void __init ppc_init(void) +{ + /* clear the progress line */ + ppc_md.progress(" ", 0xffff); + + if (ppc_md.init != NULL) { + ppc_md.init(); + } +} + +void __init ppc64_calibrate_delay(void) +{ + loops_per_jiffy = tb_ticks_per_jiffy; + + printk("Calibrating delay loop... %lu.%02lu BogoMips\n", + loops_per_jiffy/(500000/HZ), + loops_per_jiffy/(5000/HZ) % 100); + +} + +extern void (*calibrate_delay)(void); + +/* + * Called into from start_kernel, after lock_kernel has been called. + * Initializes bootmem, which is unsed to manage page allocation until + * mem_init is called. + */ +void __init setup_arch(char **cmdline_p) +{ + extern int panic_timeout; + extern char _etext[], _edata[]; + extern void do_init_bootmem(void); + + calibrate_delay = ppc64_calibrate_delay; + +#ifdef CONFIG_XMON + xmon_map_scc(); + if (strstr(cmd_line, "xmon")) + xmon(0); +#endif /* CONFIG_XMON */ +#ifdef CONFIG_KDB + xmon_map_scc(); /* in kdb/start.c --need to rename TAI */ +#endif + ppc_md.progress("setup_arch:enter", 0x3eab); + +#if defined(CONFIG_KGDB) + kgdb_map_scc(); + set_debug_traps(); + breakpoint(); +#endif + /* + * Set cache line size based on type of cpu as a default. + * Systems with OF can look in the properties on the cpu node(s) + * for a possibly more accurate value. + */ + dcache_bsize = naca->dCacheL1LineSize; + icache_bsize = naca->iCacheL1LineSize; + + /* reboot on panic */ + panic_timeout = 180; + + init_mm.start_code = PAGE_OFFSET; + 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(); + ppc_md.progress("setup_arch:bootmem", 0x3eab); + + ppc_md.setup_arch(); + + paging_init(); + ppc_md.progress("setup_arch: exit", 0x3eab); +} + +/* Convert the shorts/longs in hd_driveid from little to big endian; + * chars are endian independant, of course, but strings need to be flipped. + * (Despite what it says in drivers/block/ide.h, they come up as little + * endian...) + * + * Changes to linux/hdreg.h may require changes here. */ +void ppc64_ide_fix_driveid(struct hd_driveid *id) +{ + int i; + unsigned short *stringcast; + + id->config = __le16_to_cpu(id->config); + id->cyls = __le16_to_cpu(id->cyls); + id->reserved2 = __le16_to_cpu(id->reserved2); + id->heads = __le16_to_cpu(id->heads); + id->track_bytes = __le16_to_cpu(id->track_bytes); + id->sector_bytes = __le16_to_cpu(id->sector_bytes); + id->sectors = __le16_to_cpu(id->sectors); + id->vendor0 = __le16_to_cpu(id->vendor0); + id->vendor1 = __le16_to_cpu(id->vendor1); + id->vendor2 = __le16_to_cpu(id->vendor2); + stringcast = (unsigned short *)&id->serial_no[0]; + for (i = 0; i < (20/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + id->buf_type = __le16_to_cpu(id->buf_type); + id->buf_size = __le16_to_cpu(id->buf_size); + id->ecc_bytes = __le16_to_cpu(id->ecc_bytes); + stringcast = (unsigned short *)&id->fw_rev[0]; + for (i = 0; i < (8/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + stringcast = (unsigned short *)&id->model[0]; + for (i = 0; i < (40/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + id->dword_io = __le16_to_cpu(id->dword_io); + id->reserved50 = __le16_to_cpu(id->reserved50); + id->field_valid = __le16_to_cpu(id->field_valid); + id->cur_cyls = __le16_to_cpu(id->cur_cyls); + id->cur_heads = __le16_to_cpu(id->cur_heads); + id->cur_sectors = __le16_to_cpu(id->cur_sectors); + id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0); + id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1); + id->lba_capacity = __le32_to_cpu(id->lba_capacity); + id->dma_1word = __le16_to_cpu(id->dma_1word); + id->dma_mword = __le16_to_cpu(id->dma_mword); + id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes); + id->eide_dma_min = __le16_to_cpu(id->eide_dma_min); + id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); + id->eide_pio = __le16_to_cpu(id->eide_pio); + id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); + for (i = 0; i < 2; i++) + id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); + for (i = 0; i < 4; i++) + id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); + id->queue_depth = __le16_to_cpu(id->queue_depth); + for (i = 0; i < 4; i++) + id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); + id->major_rev_num = __le16_to_cpu(id->major_rev_num); + id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); + id->command_set_1 = __le16_to_cpu(id->command_set_1); + id->command_set_2 = __le16_to_cpu(id->command_set_2); + id->cfsse = __le16_to_cpu(id->cfsse); + id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1); + id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); + id->csf_default = __le16_to_cpu(id->csf_default); + id->dma_ultra = __le16_to_cpu(id->dma_ultra); + id->word89 = __le16_to_cpu(id->word89); + id->word90 = __le16_to_cpu(id->word90); + id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); + id->word92 = __le16_to_cpu(id->word92); + id->hw_config = __le16_to_cpu(id->hw_config); + for (i = 0; i < 32; i++) + id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); + id->last_lun = __le16_to_cpu(id->last_lun); + id->word127 = __le16_to_cpu(id->word127); + id->dlf = __le16_to_cpu(id->dlf); + id->csfo = __le16_to_cpu(id->csfo); + for (i = 0; i < 26; i++) + id->words130_155[i] = __le16_to_cpu(id->words130_155[i]); + id->word156 = __le16_to_cpu(id->word156); + for (i = 0; i < 3; i++) + id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); + for (i = 0; i < 96; i++) + id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); +} + + +void exception_trace(unsigned long trap) +{ + unsigned long x, srr0, srr1, reg20, reg1, reg21; + + asm("mflr %0" : "=r" (x) :); + asm("mfspr %0,0x1a" : "=r" (srr0) :); + asm("mfspr %0,0x1b" : "=r" (srr1) :); + asm("mr %0,1" : "=r" (reg1) :); + asm("mr %0,20" : "=r" (reg20) :); + asm("mr %0,21" : "=r" (reg21) :); + + udbg_puts("\n"); + udbg_puts("Took an exception : "); udbg_puthex(x); udbg_puts("\n"); + udbg_puts(" "); udbg_puthex(reg1); udbg_puts("\n"); + udbg_puts(" "); udbg_puthex(reg20); udbg_puts("\n"); + udbg_puts(" "); udbg_puthex(reg21); udbg_puts("\n"); + udbg_puts(" "); udbg_puthex(srr0); udbg_puts("\n"); + udbg_puts(" "); udbg_puthex(srr1); udbg_puts("\n"); +} + +int set_spread_lpevents( char * str ) +{ + /* The parameter is the number of processors to share in processing lp events */ + unsigned long i; + unsigned long val = simple_strtoul( str, NULL, 0 ); + if ( ( val > 0 ) && ( val <= maxPacas ) ) { + for ( i=1; idefault_decr = tb_ticks_per_jiffy / decr_overclock_proc0; + paca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; +} + +int set_decr_overclock_proc0( char * str ) +{ + unsigned long val = simple_strtoul( str, NULL, 0 ); + if ( ( val >= 1 ) && ( val <= 48 ) ) { + decr_overclock_proc0_set = 1; + decr_overclock_proc0 = val; + printk("proc 0 decrementer overclock factor of %ld\n", val); + } + else + printk("invalid proc 0 decrementer overclock factor of %ld\n", val); + return 1; +} + +int set_decr_overclock( char * str ) +{ + unsigned long val = simple_strtoul( str, NULL, 0 ); + if ( ( val >= 1 ) && ( val <= 48 ) ) { + decr_overclock_set = 1; + decr_overclock = val; + printk("decrementer overclock factor of %ld\n", val); + } + else + printk("invalid decrementer overclock factor of %ld\n", val); + return 1; + +} + +__setup("spread_lpevents=", set_spread_lpevents ); +__setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); +__setup("decr_overclock=", set_decr_overclock ); diff -urN linux-2.4.18/arch/ppc64/kernel/signal.c linux-2.4.19-pre5/arch/ppc64/kernel/signal.c --- linux-2.4.18/arch/ppc64/kernel/signal.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/signal.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,794 @@ +/* + * linux/arch/ppc64/kernel/signal.c + * + * + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/i386/kernel/signal.c" + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs)) + +/* + * These are the flags in the MSR that the user is allowed to change + * by modifying the saved value of the MSR on the stack. SE and BE + * should not be in this list since gdb may want to change these. I.e, + * you should be able to step out of a signal handler to see what + * instruction executes next after the signal handler completes. + * Alternately, if you stepped into a signal handler, you should be + * able to continue 'til the next breakpoint from within the signal + * handler, even if the handler returns. + */ +#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) + +int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern long sys_wait4(pid_t pid, unsigned int *stat_addr, + int options, /*unsigned long*/ struct rusage *ru); + +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, + struct pt_regs *regs) +{ + sigset_t saveset; + + PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->gpr[3] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + /* + * If a signal handler needs to be called, + * do_signal() has set R3 to the signal number (the + * first argument of the signal handler), so don't + * overwrite that with EINTR ! + * In the other cases, do_signal() doesn't touch + * R3, so it's still set to -EINTR (see above). + */ + return regs->gpr[3]; + } +} + +long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, + int p7, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + + PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->gpr[3] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return regs->gpr[3]; + } +} + + + +asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + struct pt_regs *regs = (struct pt_regs *) &uss; + + PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + return do_sigaltstack(uss, uoss, regs->gpr[1]); +} + +long sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + + + + return ret; +} + +/* + * When we have signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one or more sigcontext structs + * a gap of __SIGNAL_FRAMESIZE bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * + * XXX ultimately we will have to stack up a siginfo and ucontext + * for each rt signal. + */ +struct sigregs { + elf_gregset_t gp_regs; + double fp_regs[ELF_NFPREG]; + unsigned int tramp[2]; + /* 64 bit API allows for 288 bytes below sp before + decrementing it. */ + int abigap[72]; +}; + + + +struct rt_sigframe +{ + unsigned long _unused[2]; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; +}; + + +/* + * When we have rt signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one rt_sigframe struct (siginfo + ucontext) + * a gap of __SIGNAL_FRAMESIZE bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * + */ + +int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs *regs) +{ + struct rt_sigframe *rt_sf; + struct sigcontext_struct sigctx; + struct sigregs *sr; + int ret; + elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + sigset_t set; + stack_t st; + unsigned long prevsp; + + rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) + || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) + || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) + goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + rt_sf++; /* Look at next rt_sigframe */ + if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) { + /* Last stacked signal - restore registers - + * sigctx is initialized to point to the + * preamble frame (where registers are stored) + * see handle_signal() + */ + sr = (struct sigregs *) sigctx.regs; + if (regs->msr & MSR_FP ) + giveup_fpu(current); + if (copy_from_user(saved_regs, &sr->gp_regs, + sizeof(sr->gp_regs))) + goto badframe; + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + saved_regs[PT_SOFTE] = regs->softe; + memcpy(regs, saved_regs, GP_REGS_SIZE); + if (copy_from_user(current->thread.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) + goto badframe; + /* This function sets back the stack flags into + the current task structure. */ + sys_sigaltstack(&st, NULL); + + ret = regs->result; + } else { + /* More signals to go */ + /* Set up registers for next signal handler */ + regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE; + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))) + goto badframe; + sr = (struct sigregs *) sigctx.regs; + regs->gpr[3] = ret = sigctx.signal; + /* Get the siginfo */ + get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo); + /* Get the ucontext */ + get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc); + regs->gpr[6] = (unsigned long) rt_sf; + + regs->link = (unsigned long) &sr->tramp; + regs->nip = sigctx.handler; + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned long *) regs->gpr[1])) + goto badframe; + } + return ret; + +badframe: + do_exit(SIGSEGV); +} + +static void +setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, + signed long newsp) +{ + struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp; + /* Handler is *really* a pointer to the function descriptor for + * the signal routine. The first entry in the function + * descriptor is the entry address of signal and the second + * entry is the TOC value we need to use. + */ + struct funct_descr_entry { + unsigned long entry; + unsigned long toc; + }; + + struct funct_descr_entry * funct_desc_ptr; + unsigned long temp_ptr; + + /* Set up preamble frame */ + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->fp_regs, current->thread.fpr, + ELF_NFPREG * sizeof(double)) + || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0]) /* li r0, __NR_rt_sigreturn */ + || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + goto badframe; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + /* Retrieve rt_sigframe from stack and + set up registers for signal handler + */ + newsp -= __SIGNAL_FRAMESIZE; + + if ( get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) { + goto badframe; + } + + funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr; + + if (put_user(regs->gpr[1], (unsigned long *)newsp) + || get_user(regs->nip, &funct_desc_ptr->entry) + || get_user(regs->gpr[2], &funct_desc_ptr->toc) + || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) + || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) + || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) + goto badframe; + + regs->gpr[1] = newsp; + regs->gpr[6] = (unsigned long) rt_sf; + regs->link = (unsigned long) frame->tramp; + + + return; + +badframe: +#if DEBUG_SIG + printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + do_exit(SIGSEGV); +} + +/* + * Do a signal return; undo the signal stack. + */ +long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs *regs) +{ + struct sigcontext_struct *sc, sigctx; + struct sigregs *sr; + long ret; + elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + sigset_t set; + unsigned long prevsp; + + sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + goto badframe; + + set.sig[0] = sigctx.oldmask; +#if _NSIG_WORDS > 1 + set.sig[1] = sigctx._unused[3]; +#endif + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + sc++; /* Look at next sigcontext */ + if (sc == (struct sigcontext_struct *)(sigctx.regs)) { + /* Last stacked signal - restore registers */ + sr = (struct sigregs *) sigctx.regs; + if (regs->msr & MSR_FP ) + giveup_fpu(current); + if (copy_from_user(saved_regs, &sr->gp_regs, + sizeof(sr->gp_regs))) + goto badframe; + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + saved_regs[PT_SOFTE] = regs->softe; + memcpy(regs, saved_regs, GP_REGS_SIZE); + + if (copy_from_user(current->thread.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) + goto badframe; + + ret = regs->result; + + } else { + /* More signals to go */ + regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE; + if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + goto badframe; + sr = (struct sigregs *) sigctx.regs; + regs->gpr[3] = ret = sigctx.signal; + regs->gpr[4] = (unsigned long) sc; + regs->link = (unsigned long) &sr->tramp; + regs->nip = sigctx.handler; + + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned long *) regs->gpr[1])) + goto badframe; + } + return ret; + +badframe: + do_exit(SIGSEGV); +} + +/* + * Set up a signal frame. + */ +static void +setup_frame(struct pt_regs *regs, struct sigregs *frame, + unsigned long newsp) +{ + + /* Handler is *really* a pointer to the function descriptor for + * the signal routine. The first entry in the function + * descriptor is the entry address of signal and the second + * entry is the TOC value we need to use. + */ + struct funct_descr_entry { + unsigned long entry; + unsigned long toc; + }; + + struct funct_descr_entry * funct_desc_ptr; + unsigned long temp_ptr; + + struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp; + + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->fp_regs, current->thread.fpr, + ELF_NFPREG * sizeof(double)) + || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0]) /* li r0, __NR_sigreturn */ + || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + goto badframe; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + newsp -= __SIGNAL_FRAMESIZE; + if ( get_user(temp_ptr, &sc->handler)) + goto badframe; + + funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr; + + if (put_user(regs->gpr[1], (unsigned long *)newsp) + || get_user(regs->nip, & funct_desc_ptr ->entry) + || get_user(regs->gpr[2],& funct_desc_ptr->toc) + || get_user(regs->gpr[3], &sc->signal)) + goto badframe; + regs->gpr[1] = newsp; + regs->gpr[4] = (unsigned long) sc; + regs->link = (unsigned long) frame->tramp; + + + PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n", + regs->gpr[1], regs->gpr[4], regs->link); + + return; + + badframe: + PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); +#if DEBUG_SIG + printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + do_exit(SIGSEGV); +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, + unsigned long *newspp, unsigned long frame) +{ + struct sigcontext_struct *sc; + struct rt_sigframe *rt_sf; + + if (regs->trap == 0x0C00 /* System Call! */ + && ((int)regs->result == -ERESTARTNOHAND || + ((int)regs->result == -ERESTARTSYS && + !(ka->sa.sa_flags & SA_RESTART)))) + regs->result = -EINTR; + /* Set up Signal Frame */ + + if (ka->sa.sa_flags & SA_SIGINFO) { + /* Put a Real Time Context onto stack */ + *newspp -= sizeof(*rt_sf); + rt_sf = (struct rt_sigframe *) *newspp; + if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) + goto badframe; + + + if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler) + || __put_user(&rt_sf->info, &rt_sf->pinfo) + || __put_user(&rt_sf->uc, &rt_sf->puc) + /* Put the siginfo */ + || __copy_to_user(&rt_sf->info, info, sizeof(*info)) + /* Create the ucontext */ + || __put_user(0, &rt_sf->uc.uc_flags) + || __put_user(0, &rt_sf->uc.uc_link) + || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) + || __put_user(sas_ss_flags(regs->gpr[1]), + &rt_sf->uc.uc_stack.ss_flags) + || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) + || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)) + /* mcontext.regs points to preamble register frame */ + || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) + || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) + goto badframe; + + } else { + /* Put another sigcontext on the stack */ + *newspp -= sizeof(*sc); + sc = (struct sigcontext_struct *) *newspp; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + goto badframe; + + if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) +#if _NSIG_WORDS > 1 + || __put_user(oldset->sig[1], &sc->_unused[3]) +#endif + || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user(sig, &sc->signal)) + goto badframe; + } + + 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; + +badframe: +#if DEBUG_SIG + printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n", + regs, frame, *newspp); + printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); +#endif + do_exit(SIGSEGV); +} + +/* + * 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. + */ +extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); +int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction *ka; + unsigned long frame, newsp; + + /* + * If the current thread is 32 bit - invoke the + * 32 bit signal handling code + */ + if (current->thread.flags & PPC_FLAG_32BIT) + return do_signal32(oldset, regs); + + PPCDBG(PPCDBG_SIGNAL, "do_signal - running - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + + + if (!oldset) + oldset = ¤t->blocked; + + newsp = frame = 0; + + for (;;) { + unsigned long signr; + + PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm); + + if (!signr) + break; + + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) + 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]; + + + PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler); + + if (ka->sa.sa_handler == SIG_IGN) { + PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n"); + 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; + PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n"); + + /* 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: + 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, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + sigaddset(¤t->pending.signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + if ( (ka->sa.sa_flags & SA_ONSTACK) + && (! on_sig_stack(regs->gpr[1]))) + newsp = (current->sas_ss_sp + current->sas_ss_size); + else + newsp = regs->gpr[1]; + newsp = frame = newsp - sizeof(struct sigregs); + + /* Whee! Actually deliver the signal. */ + + PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); + PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + break; + } + + if (regs->trap == 0x0C00 /* System Call! */ && + ((int)regs->result == -ERESTARTNOHAND || + (int)regs->result == -ERESTARTSYS || + (int)regs->result == -ERESTARTNOINTR)) { + PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n"); + regs->gpr[3] = regs->orig_gpr3; + regs->nip -= 4; /* Back up & retry system call */ + regs->result = 0; + } + + if (newsp == frame) + { + PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n"); + return 0; /* no signals delivered */ + } + + + + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(regs, (struct sigregs *) frame, newsp); + else + setup_frame(regs, (struct sigregs *) frame, newsp); + PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n"); + return 1; +} + + + + + diff -urN linux-2.4.18/arch/ppc64/kernel/signal32.c linux-2.4.19-pre5/arch/ppc64/kernel/signal32.c --- linux-2.4.18/arch/ppc64/kernel/signal32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/signal32.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1512 @@ +/* + * signal32.c: Support 32bit signal syscalls. + * + * Copyright (C) 2001 IBM + * 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +/* + * These are the flags in the MSR that the user is allowed to change + * by modifying the saved value of the MSR on the stack. SE and BE + * should not be in this list since gdb may want to change these. I.e, + * you should be able to step out of a signal handler to see what + * instruction executes next after the signal handler completes. + * Alternately, if you stepped into a signal handler, you should be + * able to continue 'til the next breakpoint from within the signal + * handler, even if the handler returns. + */ +#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) + + + + +/* Use this to get at 32-bit user passed pointers. */ +/* Things to consider: the low-level assembly stub does + srl x, 0, x for first four arguments, so if you have + pointer to something in the first four arguments, just + declare it as a pointer, not u32. On the other side, + arguments from 5th onwards should be declared as u32 + for pointers, and need AA() around each usage. + A() macro should be used for places where you e.g. + have some internal variable u32 and just want to get + rid of a compiler warning. AA() has to be used in + places where you want to convert a function argument + to 32bit pointer or when you e.g. access pt_regs + structure and want to consider 32bit registers only. + - + */ +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) \ +({ unsigned long __ret; \ + __asm__ ("clrldi %0, %0, 32" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) + + + +struct timespec32 { + s32 tv_sec; + s32 tv_nsec; +}; + +struct sigregs32 { + /***********************************************************************/ + /* the gp_regs array is 32 bit representation of the pt_regs structure */ + /* that was stored on the kernle stack during the system call that */ + /* was interrupted for the signal. */ + /* */ + /* Note that the entire pt_regs regs structure will fit in the gp_regs */ + /* structure because the ELF_NREG value is 48 for PPC and the pt_regs*/ + /* structure contains 44 registers */ + /* */ + /***********************************************************************/ + elf_gregset_t32 gp_regs; + double fp_regs[ELF_NFPREG]; + unsigned int tramp[2]; + /* Programs using the rs6000/xcoff abi can save up to 19 gp regs + and 18 fp regs below sp before decrementing it. */ + int abigap[56]; +}; + + +struct rt_sigframe_32 { + /* Unused space at start of frame to allow for storing of stack pointers */ + unsigned long _unused; + /* This is a 32 bit pointer in user address space + * it is a pointer to the siginfo stucture in the rt stack frame + */ + u32 pinfo; + /* This is a 32 bit pointer in user address space */ + /* it is a pointer to the user context in the rt stack frame */ + u32 puc; + struct siginfo32 info; + struct ucontext32 uc; +}; + + + + + +extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); + + +/****************************************************************************/ +/* Start of nonRT signal support */ +/* */ +/* sigset_t is 32 bits for non-rt signals */ +/* */ +/* System Calls */ +/* sigaction sys32_sigaction */ +/* sigpending sys32_sigpending */ +/* sigprocmask sys32_sigprocmask */ +/* sigreturn sys32_sigreturn */ +/* */ +/* Note sigsuspend has no special 32 bit routine - uses the 64 bit routine */ +/* */ +/* Other routines */ +/* setup_frame32 */ +/* */ +/****************************************************************************/ + + +asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + if (sig < 0) + { + sig = -sig; + } + + if (act) + { + old_sigset_t32 mask; + + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer); + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user(mask, &act->sa_mask); + if (ret) + return ret; + PPCDBG(PPCDBG_SIGNAL, "sys32_sigaction flags =%lx \n", new_ka.sa.sa_flags); + + 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((long)old_ka.sa.sa_restorer, &oact->sa_restorer); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + + PPCDBG(PPCDBG_SYS32, "sys32_sigaction - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return ret; +} + + + + +extern asmlinkage long sys_sigpending(old_sigset_t *set); + +asmlinkage long sys32_sigpending(old_sigset_t32 *set) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); + + PPCDBG(PPCDBG_SYS32, "sys32_sigpending - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + set_fs (KERNEL_DS); + ret = sys_sigpending(&s); + set_fs (old_fs); + if (put_user (s, set)) return -EFAULT; + + PPCDBG(PPCDBG_SYS32, "sys32_sigpending - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return ret; +} + + + + +extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); + +/* Note: it is necessary to treat how as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sigprocmask(u32 how, old_sigset_t32 *set, old_sigset_t32 *oset) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); + + PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + if (set && get_user (s, set)) return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL); + set_fs (old_fs); + if (ret) return ret; + if (oset && put_user (s, oset)) return -EFAULT; + + PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return 0; +} + + + +/* + * When we have signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one or more sigcontext structs + * a gap of __SIGNAL_FRAMESIZE32 bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * +*/ + + +/* + * Do a signal return; undo the signal stack. + */ +long sys32_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs *regs) +{ + struct sigcontext32_struct *sc, sigctx; + struct sigregs32 *sr; + int ret; + elf_gregset_t32 saved_regs; /* an array of ELF_NGREG unsigned ints (32 bits) */ + sigset_t set; + unsigned int prevsp; + + PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + sc = (struct sigcontext32_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32); + if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + goto badframe; + + /* Note that PPC32 puts the upper 32 bits of the sigmask in the */ + /* unused part of the signal stackframe */ + set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3])<< 32); + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + sc++; /* Look at next sigcontext */ + /* If the next sigcontext is actually the sigregs (frame) */ + /* - then no more sigcontexts on the user stack */ + if (sc == (struct sigcontext32_struct*)(u64)sigctx.regs) + { + /* Last stacked signal - restore registers */ + sr = (struct sigregs32*)(u64)sigctx.regs; + if (regs->msr & MSR_FP ) + giveup_fpu(current); + /* copy the 32 bit register values off the user stack */ + /* into the 32 bit register area */ + if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs))) + goto badframe; + /**********************************************************************/ + /* The saved reg structure in the frame is an elf_grepset_t32, it is */ + /* a 32 bit register save of the registers in the pt_regs structure */ + /* that was stored on the kernel stack during the system call */ + /* when the system call was interrupted for the signal. Only 32 bits*/ + /* are saved because the sigcontext contains a pointer to the regs */ + /* and the sig context address is passed as a pointer to the signal */ + /* handler. */ + /* */ + /* The entries in the elf_grepset have the same index as the elements */ + /* in the pt_regs structure. */ + /* */ + /**********************************************************************/ + + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF; + regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF; + /**********************************************************************/ + /* Register 2 is the kernel toc - should be reset on any calls into */ + /* the kernel */ + /**********************************************************************/ + regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF; + + regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF; + regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF; + regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF; + regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF; + regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF; + regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF; + regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF; + regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF; + regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF; + regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF; + regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF; + regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF; + regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF; + regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF; + regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF; + regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF; + regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF; + regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF; + regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF; + regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF; + regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF; + regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF; + regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF; + regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF; + regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF; + regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF; + regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF; + regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF; + regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF; + /****************************************************/ + /* restore the non gpr registers */ + /****************************************************/ + regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF; + /* Insure that the interrupt mode is 64 bit, during 32 bit execution. + * (This is necessary because we only saved lower 32 bits of msr.) + */ + regs->msr = regs->msr | MSR_ISF; /* When this thread is interrupted it should run in 64 bit mode. */ + + regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF; + regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; + regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; + regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; + regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; + regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF; + /* regs->softe is left unchanged (like the MSR.EE bit) */ + /******************************************************/ + /* the DAR and the DSISR are only relevant during a */ + /* data or instruction storage interrupt. The value */ + /* will be set to zero. */ + /******************************************************/ + regs->dar = 0; + regs->dsisr = 0; + regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF; + + if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs))) + goto badframe; + + ret = regs->result; + } else { + /* More signals to go */ + regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE32; + if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + goto badframe; + sr = (struct sigregs32*)(u64)sigctx.regs; + regs->gpr[3] = ret = sigctx.signal; + regs->gpr[4] = (unsigned long) sc; + regs->link = (unsigned long) &sr->tramp; + regs->nip = sigctx.handler; + + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned int*) regs->gpr[1])) + goto badframe; + } + + PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm); + return ret; + +badframe: + PPCDBG(PPCDBG_SYS32NI, "sys32_sigreturn - badframe - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + do_exit(SIGSEGV); +} + +/* + * Set up a signal frame. + */ +static void +setup_frame32(struct pt_regs *regs, struct sigregs32 *frame, + unsigned int newsp) +{ + struct sigcontext32_struct *sc = (struct sigcontext32_struct *)(u64)newsp; + + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + + /***************************************************************/ + /* */ + /* Copy the register contents for the pt_regs structure on the */ + /* kernel stack to the elf_gregset_t32 structure on the user */ + /* stack. This is a copy of 64 bit register values to 32 bit */ + /* register values. The high order 32 bits of the 64 bit */ + /* registers are not needed since a 32 bit application is */ + /* running and the saved registers are the contents of the */ + /* user registers at the time of a system call. */ + /* */ + /* The values saved on the user stack will be restored into */ + /* the registers during the signal return processing */ + /* */ + /* Note the +1 is needed in order to get the lower 32 bits */ + /* of 64 bit register */ + /***************************************************************/ + if (__copy_to_user(&frame->gp_regs[0], (u32*)(®s->gpr[0])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[1], (u32*)(®s->gpr[1])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[2], (u32*)(®s->gpr[2])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[3], (u32*)(®s->gpr[3])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[4], (u32*)(®s->gpr[4])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[5], (u32*)(®s->gpr[5])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[6], (u32*)(®s->gpr[6])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[7], (u32*)(®s->gpr[7])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[8], (u32*)(®s->gpr[8])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[9], (u32*)(®s->gpr[9])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[10], (u32*)(®s->gpr[10])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[11], (u32*)(®s->gpr[11])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[12], (u32*)(®s->gpr[12])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[13], (u32*)(®s->gpr[13])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[14], (u32*)(®s->gpr[14])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[15], (u32*)(®s->gpr[15])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[16], (u32*)(®s->gpr[16])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[17], (u32*)(®s->gpr[17])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[18], (u32*)(®s->gpr[18])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[19], (u32*)(®s->gpr[19])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[20], (u32*)(®s->gpr[20])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[21], (u32*)(®s->gpr[21])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[22], (u32*)(®s->gpr[22])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[23], (u32*)(®s->gpr[23])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[24], (u32*)(®s->gpr[24])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[25], (u32*)(®s->gpr[25])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[26], (u32*)(®s->gpr[26])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[27], (u32*)(®s->gpr[27])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[28], (u32*)(®s->gpr[28])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[29], (u32*)(®s->gpr[29])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[30], (u32*)(®s->gpr[30])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[31], (u32*)(®s->gpr[31])+1, sizeof(u32))) + goto badframe; + + /*****************************************************************************/ + /* Copy the non gpr registers to the user stack */ + /*****************************************************************************/ + + if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(®s->gpr[PT_NIP])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(®s->gpr[PT_MSR])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(®s->gpr[PT_ORIG_R3])+1, + sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(®s->gpr[PT_CTR])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(®s->gpr[PT_LNK])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(®s->gpr[PT_XER])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(®s->gpr[PT_CCR])+1, sizeof(u32)) +# if 0 + || __copy_to_user(&frame->gp_regs[PT_MQ], (u32*)(®s->gpr[PT_MQ])+1, sizeof(u32)) +#endif + || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(®s->gpr[PT_RESULT])+1, + sizeof(u32))) + goto badframe; + + + /*****************************************************************************/ + /* Now copy the floating point registers onto the user stack */ + /* */ + /* Also set up so on the completion of the signal handler, the sys_sigreturn */ + /* will get control to reset the stack */ + /*****************************************************************************/ + if (__copy_to_user(&frame->fp_regs, current->thread.fpr, + ELF_NFPREG * sizeof(double)) + || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0]) /* li r0, __NR_sigreturn */ + || __put_user(0x44000002U, &frame->tramp[1])) /* sc */ + goto badframe; + + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + newsp -= __SIGNAL_FRAMESIZE32; + if (put_user(regs->gpr[1], (u32*)(u64)newsp) + || get_user(regs->nip, &sc->handler) + || get_user(regs->gpr[3], &sc->signal)) + goto badframe; + + regs->gpr[1] = newsp & 0xFFFFFFFF; + /**************************************************************/ + /* first parameter to the signal handler is the signal number */ + /* - the value is in gpr3 */ + /* second parameter to the signal handler is the sigcontext */ + /* - set the value into gpr4 */ + /**************************************************************/ + regs->gpr[4] = (unsigned long) sc; + regs->link = (unsigned long) frame->tramp; + return; + + badframe: + udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); +#if DEBUG_SIG + printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + do_exit(SIGSEGV); +} + + +/****************************************************************************/ +/* Start of RT signal support */ +/* */ +/* sigset_t is 64 bits for rt signals */ +/* */ +/* System Calls */ +/* sigaction sys32_rt_sigaction */ +/* sigpending sys32_rt_sigpending */ +/* sigprocmask sys32_rt_sigprocmask */ +/* sigreturn sys32_rt_sigreturn */ +/* sigtimedwait sys32_rt_sigtimedwait */ +/* sigqueueinfo sys32_rt_sigqueueinfo */ +/* sigsuspend sys32_rt_sigsuspend */ +/* */ +/* Other routines */ +/* setup_rt_frame32 */ +/* siginfo64to32 */ +/* siginfo32to64 */ +/* */ +/* */ +/****************************************************************************/ + + +// This code executes after the rt signal handler in 32 bit mode has completed and +// returned +long sys32_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs * regs) +{ + struct rt_sigframe_32 *rt_stack_frame; + struct sigcontext32_struct sigctx; + struct sigregs32 *signalregs; + + int ret; + elf_gregset_t32 saved_regs; /* an array of 32 bit register values */ + sigset_t signal_set; + stack_t stack; + unsigned int previous_stack; + + ret = 0; + /* Adjust the inputted reg1 to point to the first rt signal frame */ + rt_stack_frame = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32); + /* Copy the information from the user stack */ + if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx)) + || copy_from_user(&signal_set, &rt_stack_frame->uc.uc_sigmask,sizeof(signal_set)) + || copy_from_user(&stack,&rt_stack_frame->uc.uc_stack,sizeof(stack))) + { + /* unable to copy from user storage */ + goto badframe; + } + + /* Unblock the signal that was processed + * After a signal handler runs - + * if the signal is blockable - the signal will be unblocked + * ( sigkill and sigstop are not blockable) + */ + sigdelsetmask(&signal_set, ~_BLOCKABLE); + /* update the current based on the sigmask found in the rt_stackframe */ + spin_lock_irq(¤t->sigmask_lock); + current->blocked = signal_set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + /* Set to point to the next rt_sigframe - this is used to determine whether this + * is the last signal to process + */ + rt_stack_frame ++; + + if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs)) + { + signalregs = (struct sigregs32 *) (u64)sigctx.regs; + /* If currently owning the floating point - give them up */ + if (regs->msr & MSR_FP) + { + giveup_fpu(current); + } + if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) + { + goto badframe; + } + /**********************************************************************/ + /* The saved reg structure in the frame is an elf_grepset_t32, it is */ + /* a 32 bit register save of the registers in the pt_regs structure */ + /* that was stored on the kernel stack during the system call */ + /* when the system call was interrupted for the signal. Only 32 bits*/ + /* are saved because the sigcontext contains a pointer to the regs */ + /* and the sig context address is passed as a pointer to the signal */ + /* handler. */ + /* */ + /* The entries in the elf_grepset have the same index as the elements */ + /* in the pt_regs structure. */ + /* */ + /**********************************************************************/ + + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF; + regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF; + /**********************************************************************/ + /* Register 2 is the kernel toc - should be reset on any calls into */ + /* the kernel */ + /**********************************************************************/ + regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF; + + regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF; + regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF; + regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF; + regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF; + regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF; + regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF; + regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF; + regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF; + regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF; + regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF; + regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF; + regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF; + regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF; + regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF; + regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF; + regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF; + regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF; + regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF; + regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF; + regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF; + regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF; + regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF; + regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF; + regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF; + regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF; + regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF; + regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF; + regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF; + regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF; + /****************************************************/ + /* restore the non gpr registers */ + /****************************************************/ + regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF; + + regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF; + regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; + regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; + regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; + regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; + regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF; + /* regs->softe is left unchanged (like MSR.EE) */ + /******************************************************/ + /* the DAR and the DSISR are only relevant during a */ + /* data or instruction storage interrupt. The value */ + /* will be set to zero. */ + /******************************************************/ + regs->dar = 0; + regs->dsisr = 0; + regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF; + ret = regs->result; + } + else /* more signals to go */ + { + regs->gpr[1] = (u64)rt_stack_frame - __SIGNAL_FRAMESIZE32; + if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))) + { + goto badframe; + } + signalregs = (struct sigregs32 *) (u64)sigctx.regs; + /* first parm to signal handler is the signal number */ + regs->gpr[3] = ret = sigctx.signal; + /* second parm is a pointer to sig info */ + get_user(regs->gpr[4], &rt_stack_frame->pinfo); + /* third parm is a pointer to the ucontext */ + get_user(regs->gpr[5], &rt_stack_frame->puc); + /* fourth parm is the stack frame */ + regs->gpr[6] = (u64)rt_stack_frame; + /* Set up link register to return to sigreturn when the */ + /* signal handler completes */ + regs->link = (u64)&signalregs->tramp; + /* Set next instruction to the start fo the signal handler */ + regs->nip = sigctx.handler; + /* Set the reg1 to look like a call to the signal handler */ + if (get_user(previous_stack,&signalregs->gp_regs[PT_R1]) + || put_user(previous_stack, (unsigned long *)regs->gpr[1])) + { + goto badframe; + } + + } + + return ret; + + badframe: + do_exit(SIGSEGV); +} + + + +asmlinkage long sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact, size_t sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + sigset32_t set32; + + PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - entered - sig=%x \n", sig); + + /* 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); + } + + + PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - exiting - sig=%x \n", sig); + return ret; +} + + +extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); + +/* Note: it is necessary to treat how as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_rt_sigprocmask(u32 how, sigset32_t *set, sigset32_t *oset, size_t sigsetsize) +{ + sigset_t s; + sigset32_t s32; + int ret; + mm_segment_t old_fs = get_fs(); + + PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigprocmask - entered how=%x \n", (int)how); + + 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((int)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; +} + + +extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); + + + +asmlinkage long sys32_rt_sigpending(sigset32_t *set, __kernel_size_t32 sigsetsize) +{ + + sigset_t s; + sigset32_t 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(sigset32_t))) + 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; + + 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); + 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 long +sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize); + +asmlinkage long +sys32_rt_sigtimedwait(sigset32_t *uthese, siginfo_t32 *uinfo, + struct timespec32 *uts, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset32_t 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(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); + } + 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); + if (uts) + { + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + } else { + ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts, sigsetsize); + } + + set_fs (old_fs); + if (ret >= 0 && uinfo) { + if (copy_to_user (uinfo, siginfo64to32(&info32, &info), + sizeof(siginfo_t32))) + return -EFAULT; + } + return ret; +} + + + +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; + 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); + 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 long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); + +/* Note: it is necessary to treat pid and sig as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_rt_sigqueueinfo(u32 pid, u32 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((int)pid, (int)sig, &info); + set_fs (old_fs); + return ret; +} + + +int do_signal(sigset_t *oldset, struct pt_regs *regs); +int sys32_rt_sigsuspend(sigset32_t* unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + sigset32_t s32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&s32, unewset, sizeof(s32))) + return -EFAULT; + + /* Swap the 2 words of the 64-bit sigset_t (they are stored in the "wrong" endian in 32-bit user storage). */ + switch (_NSIG_WORDS) + { + case 4: newset.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: newset.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: newset.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: newset.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->gpr[3] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return regs->gpr[3]; + } +} + + + + + + + + +/* + * Set up a rt signal frame. + */ +static void +setup_rt_frame32(struct pt_regs *regs, struct sigregs32 *frame, + unsigned int newsp) +{ + unsigned int copyreg4,copyreg5; + struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp; + + + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + /***************************************************************/ + /* */ + /* Copy the register contents for the pt_regs structure on the */ + /* kernel stack to the elf_gregset_t32 structure on the user */ + /* stack. This is a copy of 64 bit register values to 32 bit */ + /* register values. The high order 32 bits of the 64 bit */ + /* registers are not needed since a 32 bit application is */ + /* running and the saved registers are the contents of the */ + /* user registers at the time of a system call. */ + /* */ + /* The values saved on the user stack will be restored into */ + /* the registers during the signal return processing */ + /* */ + /* Note the +1 is needed in order to get the lower 32 bits */ + /* of 64 bit register */ + /***************************************************************/ + if (__copy_to_user(&frame->gp_regs[0], (u32*)(®s->gpr[0])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[1], (u32*)(®s->gpr[1])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[2], (u32*)(®s->gpr[2])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[3], (u32*)(®s->gpr[3])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[4], (u32*)(®s->gpr[4])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[5], (u32*)(®s->gpr[5])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[6], (u32*)(®s->gpr[6])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[7], (u32*)(®s->gpr[7])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[8], (u32*)(®s->gpr[8])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[9], (u32*)(®s->gpr[9])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[10], (u32*)(®s->gpr[10])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[11], (u32*)(®s->gpr[11])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[12], (u32*)(®s->gpr[12])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[13], (u32*)(®s->gpr[13])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[14], (u32*)(®s->gpr[14])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[15], (u32*)(®s->gpr[15])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[16], (u32*)(®s->gpr[16])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[17], (u32*)(®s->gpr[17])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[18], (u32*)(®s->gpr[18])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[19], (u32*)(®s->gpr[19])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[20], (u32*)(®s->gpr[20])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[21], (u32*)(®s->gpr[21])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[22], (u32*)(®s->gpr[22])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[23], (u32*)(®s->gpr[23])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[24], (u32*)(®s->gpr[24])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[25], (u32*)(®s->gpr[25])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[26], (u32*)(®s->gpr[26])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[27], (u32*)(®s->gpr[27])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[28], (u32*)(®s->gpr[28])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[29], (u32*)(®s->gpr[29])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[30], (u32*)(®s->gpr[30])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[31], (u32*)(®s->gpr[31])+1, sizeof(u32))) + goto badframe; + + /*****************************************************************************/ + /* Copy the non gpr registers to the user stack */ + /*****************************************************************************/ + + if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(®s->gpr[PT_NIP])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(®s->gpr[PT_MSR])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(®s->gpr[PT_ORIG_R3])+1, + sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(®s->gpr[PT_CTR])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(®s->gpr[PT_LNK])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(®s->gpr[PT_XER])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(®s->gpr[PT_CCR])+1, sizeof(u32)) + || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(®s->gpr[PT_RESULT])+1, + sizeof(u32))) + goto badframe; + + + /*****************************************************************************/ + /* Now copy the floating point registers onto the user stack */ + /* */ + /* Also set up so on the completion of the signal handler, the sys_sigreturn */ + /* will get control to reset the stack */ + /*****************************************************************************/ + + + if (__copy_to_user(&frame->fp_regs, current->thread.fpr, + ELF_NFPREG * sizeof(double)) + || __put_user(0x38000000U + __NR_rt_sigreturn, &frame->tramp[0]) /* li r0, __NR_rt_sigreturn */ + || __put_user(0x44000002U, &frame->tramp[1])) /* sc */ + goto badframe; + + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + + /* Retrieve rt_sigframe from stack and + set up registers for signal handler + */ + newsp -= __SIGNAL_FRAMESIZE32; + + + if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp) + || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) + || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) + || get_user(copyreg4, &rt_sf->pinfo) + || get_user(copyreg5, &rt_sf->puc)) + goto badframe; + + regs->gpr[4] = copyreg4; + regs->gpr[5] = copyreg5; + + + regs->gpr[1] = newsp; + regs->gpr[6] = (unsigned long) rt_sf; + + + regs->link = (unsigned long) frame->tramp; + + return; + + + badframe: + udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); +#if DEBUG_SIG + printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + do_exit(SIGSEGV); +} + + +/* + * OK, we're invoking a handler + */ +static void +handle_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, + unsigned int *newspp, unsigned int frame) +{ + struct sigcontext32_struct *sc; + struct rt_sigframe_32 *rt_stack_frame; + siginfo_t32 siginfo32bit; + + if (regs->trap == 0x0C00 /* System Call! */ + && ((int)regs->result == -ERESTARTNOHAND || + ((int)regs->result == -ERESTARTSYS && + !(ka->sa.sa_flags & SA_RESTART)))) + regs->result = -EINTR; + + /* Set up the signal frame */ + /* Determine if an real time frame - siginfo required */ + if (ka->sa.sa_flags & SA_SIGINFO) + { + siginfo64to32(&siginfo32bit,info); + *newspp -= sizeof(*rt_stack_frame); + rt_stack_frame = (struct rt_sigframe_32 *) (u64)(*newspp) ; + + if (verify_area(VERIFY_WRITE, rt_stack_frame, sizeof(*rt_stack_frame))) + { + goto badframe; + } + if (__put_user((u32)(u64)ka->sa.sa_handler, &rt_stack_frame->uc.uc_mcontext.handler) + || __put_user((u32)(u64)&rt_stack_frame->info, &rt_stack_frame->pinfo) + || __put_user((u32)(u64)&rt_stack_frame->uc, &rt_stack_frame->puc) + /* put the siginfo on the user stack */ + || __copy_to_user(&rt_stack_frame->info,&siginfo32bit,sizeof(siginfo32bit)) + /* set the ucontext on the user stack */ + || __put_user(0,&rt_stack_frame->uc.uc_flags) + || __put_user(0,&rt_stack_frame->uc.uc_link) + || __put_user(current->sas_ss_sp, &rt_stack_frame->uc.uc_stack.ss_sp) + || __put_user(sas_ss_flags(regs->gpr[1]), + &rt_stack_frame->uc.uc_stack.ss_flags) + || __put_user(current->sas_ss_size, &rt_stack_frame->uc.uc_stack.ss_size) + || __copy_to_user(&rt_stack_frame->uc.uc_sigmask, oldset,sizeof(*oldset)) + /* point the mcontext.regs to the pramble register frame */ + || __put_user(frame, &rt_stack_frame->uc.uc_mcontext.regs) + || __put_user(sig,&rt_stack_frame->uc.uc_mcontext.signal)) + { + goto badframe; + } + } else { + /* Put another sigcontext on the stack */ + *newspp -= sizeof(*sc); + sc = (struct sigcontext32_struct *)(u64)*newspp; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + goto badframe; + + /* Note the upper 32 bits of the signal mask are stored in the */ + /* unused part of the signal stack frame */ + if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) + || __put_user((oldset->sig[0] >> 32), &sc->_unused[3]) + || __put_user((unsigned int)frame, &sc->regs) + || __put_user(sig, &sc->signal)) + goto badframe; + } + + 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; + +badframe: +#if DEBUG_SIG + printk("badframe in handle_signal32, regs=%p frame=%lx newsp=%lx\n", + regs, frame, *newspp); + printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); +#endif + do_exit(SIGSEGV); +} + + +/****************************************************************************/ +/* Start Alternate signal stack support */ +/* */ +/* */ +/* */ +/* System Calls */ +/* sigaltatck sys32_sigaltstack */ +/* */ +/****************************************************************************/ + + +asmlinkage int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, int p4, int p6, + int p7, struct pt_regs *regs) +{ + stack_t uss, uoss; + int ret; + mm_segment_t old_fs; + unsigned long sp; + + /* set sp to the user stack on entry to the system call */ + /* the system call router sets R9 to the saved registers */ + sp = regs->gpr[1]; + + /* Put new stack info in local 64 bit stack struct */ + if (newstack && (get_user((long)uss.ss_sp, &((stack_32_t *)(long)newstack)->ss_sp) || + __get_user(uss.ss_flags, &((stack_32_t *)(long)newstack)->ss_flags) || + __get_user(uss.ss_size, &((stack_32_t *)(long)newstack)->ss_size))) + return -EFAULT; + + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = do_sigaltstack(newstack ? &uss : NULL, oldstack ? &uoss : NULL, sp); + set_fs(old_fs); + /* Copy the stack information to the user output buffer */ + if (!ret && oldstack && (put_user((long)uoss.ss_sp, &((stack_32_t *)(long)oldstack)->ss_sp) || + __put_user(uoss.ss_flags, &((stack_32_t *)(long)oldstack)->ss_flags) || + __put_user(uoss.ss_size, &((stack_32_t *)(long)oldstack)->ss_size))) + return -EFAULT; + return ret; +} + + + +/****************************************************************************/ +/* Start of do_signal32 routine */ +/* */ +/* This routine gets control when a pemding signal needs to be processed */ +/* in the 32 bit target thread - */ +/* */ +/* It handles both rt and non-rt signals */ +/* */ +/****************************************************************************/ + +/* + * 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. + */ + +int do_signal32(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction *ka; + unsigned int frame, newsp; + + if (!oldset) + oldset = ¤t->blocked; + + newsp = frame = 0; + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + ifppcdebug(PPCDBG_SYS32) { + if (signr) + udbg_printf("do_signal32 - processing signal=%2lx - pid=%ld, comm=%s \n", signr, current->pid, current->comm); + } + + if (!signr) + break; + + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) + 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: + 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, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + sigaddset(¤t->pending.signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + PPCDBG(PPCDBG_SIGNAL, " do signal :sigaction flags = %lx \n" ,ka->sa.sa_flags); + PPCDBG(PPCDBG_SIGNAL, " do signal :on sig stack = %lx \n" ,on_sig_stack(regs->gpr[1])); + PPCDBG(PPCDBG_SIGNAL, " do signal :reg1 = %lx \n" ,regs->gpr[1]); + PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack = %lx \n" ,current->sas_ss_sp); + PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack size = %lx \n" ,current->sas_ss_size); + + + + if ( (ka->sa.sa_flags & SA_ONSTACK) + && (! on_sig_stack(regs->gpr[1]))) + { + newsp = (current->sas_ss_sp + current->sas_ss_size); + } else + newsp = regs->gpr[1]; + newsp = frame = newsp - sizeof(struct sigregs32); + + /* Whee! Actually deliver the signal. */ + handle_signal32(signr, ka, &info, oldset, regs, &newsp, frame); + break; + } + + if (regs->trap == 0x0C00 /* System Call! */ && + ((int)regs->result == -ERESTARTNOHAND || + (int)regs->result == -ERESTARTSYS || + (int)regs->result == -ERESTARTNOINTR)) { + regs->gpr[3] = regs->orig_gpr3; + regs->nip -= 4; /* Back up & retry system call */ + regs->result = 0; + } + + if (newsp == frame) + { + return 0; /* no signals delivered */ + } + // Invoke correct stack setup routine + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp); + else + setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp); + + return 1; + +} diff -urN linux-2.4.18/arch/ppc64/kernel/smp.c linux-2.4.19-pre5/arch/ppc64/kernel/smp.c --- linux-2.4.18/arch/ppc64/kernel/smp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/smp.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,765 @@ +/* + * + * + * SMP support for ppc. + * + * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great + * deal of code from the sparc and intel versions. + * + * Copyright (C) 1999 Cort Dougan + * + * PowerPC-64 Support added by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikec}@us.ibm.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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#define __KERNEL_SYSCALLS__ +#include +#include +/* #include */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "open_pic.h" +#include + +int smp_threads_ready = 0; +volatile int smp_commenced = 0; +int smp_num_cpus = 1; +int smp_tb_synchronized = 0; +extern atomic_t ipi_recv; +extern atomic_t ipi_sent; +spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; +cycles_t cacheflush_time; +static int max_cpus __initdata = NR_CPUS; + +unsigned long cpu_online_map; + +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; + +#define TB_SYNC_PASSES 4 +volatile unsigned long __initdata tb_sync_flag = 0; +volatile unsigned long __initdata tb_offset = 0; + +extern unsigned char stab_array[]; + +int start_secondary(void *); +extern int cpu_idle(void *unused); +void smp_call_function_interrupt(void); +void smp_message_pass(int target, int msg, unsigned long data, int wait); +static unsigned long iSeries_smp_message[NR_CPUS]; +extern struct Naca *naca; +extern struct Paca xPaca[]; + +void xics_setup_cpu(void); +void xics_cause_IPI(int cpu); + +/* + * XICS only has a single IPI, so encode the messages per CPU + */ +volatile unsigned long xics_ipi_message[NR_CPUS] = {0}; + +#define smp_message_pass(t,m,d,w) \ + do { atomic_inc(&ipi_sent); \ + ppc_md.smp_message_pass((t),(m),(d),(w)); \ + } while(0) + +#ifdef CONFIG_KDB +void smp_kdb_stop(void) +{ +} +#endif + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, upper); + mtspr(SPRN_TBWL, lower); +} + +void iSeries_smp_message_recv( struct pt_regs * regs ) +{ + int cpu = smp_processor_id(); + int msg; + + if ( smp_num_cpus < 2 ) + return; + + for ( msg = 0; msg < 4; ++msg ) + if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) ) + smp_message_recv( msg, regs ); + +} + +static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait) +{ + int i; + for (i = 0; i < smp_num_cpus; ++i) { + if ( (target == MSG_ALL) || + (target == i) || + ((target == MSG_ALL_BUT_SELF) && (i != smp_processor_id())) ) { + set_bit( msg, &iSeries_smp_message[i] ); + HvCall_sendIPI(&(xPaca[i])); + } + } +} + +static int smp_iSeries_numProcs(void) +{ + unsigned np, i; + struct ItLpPaca * lpPaca; + + np = 0; + for (i=0; i < maxPacas; ++i) { + lpPaca = xPaca[i].xLpPacaPtr; + if ( lpPaca->xDynProcStatus < 2 ) { + ++np; + } + } + return np; +} + +static int smp_iSeries_probe(void) +{ + unsigned i; + unsigned np; + struct ItLpPaca * lpPaca; + + np = 0; + for (i=0; i < maxPacas; ++i) { + lpPaca = xPaca[i].xLpPacaPtr; + if ( lpPaca->xDynProcStatus < 2 ) { + ++np; + xPaca[i].next_jiffy_update_tb = xPaca[0].next_jiffy_update_tb; + } + } + + smp_tb_synchronized = 1; + return np; +} + +static void smp_iSeries_kick_cpu(int nr) +{ + struct ItLpPaca * lpPaca; + /* Verify we have a Paca for processor nr */ + if ( ( nr <= 0 ) || + ( nr >= maxPacas ) ) + return; + /* Verify that our partition has a processor nr */ + lpPaca = xPaca[nr].xLpPacaPtr; + if ( lpPaca->xDynProcStatus >= 2 ) + return; + /* The processor is currently spinning, waiting + * for the xProcStart field to become non-zero + * After we set xProcStart, the processor will + * continue on to secondary_start in iSeries_head.S + */ + xPaca[nr].xProcStart = 1; +} + +static void smp_iSeries_setup_cpu(int nr) +{ +} + +/* This is called very early. */ +void smp_init_iSeries(void) +{ + ppc_md.smp_message_pass = smp_iSeries_message_pass; + ppc_md.smp_probe = smp_iSeries_probe; + ppc_md.smp_kick_cpu = smp_iSeries_kick_cpu; + ppc_md.smp_setup_cpu = smp_iSeries_setup_cpu; + + naca->processorCount = smp_iSeries_numProcs(); +} + + +static void +smp_openpic_message_pass(int target, int msg, unsigned long data, int wait) +{ + /* make sure we're sending something that translates to an IPI */ + if ( msg > 0x3 ){ + printk("SMP %d: smp_message_pass: unknown msg %d\n", + smp_processor_id(), msg); + return; + } + switch ( target ) + { + case MSG_ALL: + openpic_cause_IPI(msg, 0xffffffff); + break; + case MSG_ALL_BUT_SELF: + openpic_cause_IPI(msg, + 0xffffffff & ~(1 << smp_processor_id())); + break; + default: + openpic_cause_IPI(msg, 1<processorCount > 1) + openpic_request_IPIs(); + + return naca->processorCount; +} + +static void +smp_kick_cpu(int nr) +{ + /* Verify we have a Paca for processor nr */ + if ( ( nr <= 0 ) || + ( nr >= maxPacas ) ) + return; + + /* The processor is currently spinning, waiting + * for the xProcStart field to become non-zero + * After we set xProcStart, the processor will + * continue on to secondary_start in iSeries_head.S + */ + xPaca[nr].xProcStart = 1; +} + +extern struct gettimeofday_struct do_gtod; + +static void +smp_chrp_setup_cpu(int cpu_nr) +{ + static atomic_t ready = ATOMIC_INIT(1); + static volatile int frozen = 0; + + if (_machine == _MACH_pSeriesLP) { + /* timebases already synced under the hypervisor. */ + xPaca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb(); + if (cpu_nr == 0) { + do_gtod.tb_orig_stamp = tb_last_stamp; + /* Should update do_gtod.stamp_xsec. + * For now we leave it which means the time can be some + * number of msecs off until someone does a settimeofday() + */ + } + smp_tb_synchronized = 1; + } else { + if (cpu_nr == 0) { + /* wait for all the others */ + while (atomic_read(&ready) < smp_num_cpus) + barrier(); + atomic_set(&ready, 1); + /* freeze the timebase */ + rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL); + mb(); + frozen = 1; + set_tb(0, 0); + xPaca[0].next_jiffy_update_tb = 0; + smp_space_timers(smp_num_cpus); + while (atomic_read(&ready) < smp_num_cpus) + barrier(); + /* thaw the timebase again */ + rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL); + mb(); + frozen = 0; + tb_last_stamp = get_tb(); + do_gtod.tb_orig_stamp = tb_last_stamp; + smp_tb_synchronized = 1; + } else { + atomic_inc(&ready); + while (!frozen) + barrier(); + set_tb(0, 0); + mb(); + atomic_inc(&ready); + while (frozen) + barrier(); + } + } + + if (OpenPIC_Addr) { + do_openpic_setup_cpu(); + } else { + if (cpu_nr > 0) + xics_setup_cpu(); + } +} + +static void +smp_xics_message_pass(int target, int msg, unsigned long data, int wait) +{ + int i; + + for (i = 0; i < smp_num_cpus; ++i) { + if (target == MSG_ALL || target == i + || (target == MSG_ALL_BUT_SELF + && i != smp_processor_id())) { + set_bit(msg, &xics_ipi_message[i]); + mb(); + xics_cause_IPI(i); + } + } +} + +static int +smp_xics_probe(void) +{ + return naca->processorCount; +} + +/* This is called very early */ +void smp_init_pSeries(void) +{ + if(naca->interrupt_controller == IC_OPEN_PIC) { + ppc_md.smp_message_pass = smp_openpic_message_pass; + ppc_md.smp_probe = smp_chrp_probe; + ppc_md.smp_kick_cpu = smp_kick_cpu; + ppc_md.smp_setup_cpu = smp_chrp_setup_cpu; + } else { + ppc_md.smp_message_pass = smp_xics_message_pass; + ppc_md.smp_probe = smp_xics_probe; + ppc_md.smp_kick_cpu = smp_kick_cpu; + ppc_md.smp_setup_cpu = smp_chrp_setup_cpu; + } +} + + +void smp_local_timer_interrupt(struct pt_regs * regs) +{ + if (!--(get_paca()->prof_counter)) { + update_process_times(user_mode(regs)); + (get_paca()->prof_counter)=get_paca()->prof_multiplier; + } +} + +void smp_message_recv(int msg, struct pt_regs *regs) +{ + atomic_inc(&ipi_recv); + + switch( msg ) { + case PPC_MSG_CALL_FUNCTION: + smp_call_function_interrupt(); + break; + case PPC_MSG_RESCHEDULE: + current->need_resched = 1; + break; +#ifdef CONFIG_XMON + case PPC_MSG_XMON_BREAK: + xmon(regs); + break; +#endif /* CONFIG_XMON */ +#ifdef CONFIG_KDB + case PPC_MSG_XMON_BREAK: + /* This isn't finished yet, obviously -TAI */ + kdb(KDB_REASON_KEYBOARD,0, (kdb_eframe_t) regs); + break; +#endif + default: + printk("SMP %d: smp_message_recv(): unknown msg %d\n", + smp_processor_id(), msg); + break; + } +} + +void smp_send_reschedule(int cpu) +{ + /* + * This is only used if `cpu' is running an idle task, + * so it will reschedule itself anyway... + * + * This isn't the case anymore since the other CPU could be + * sleeping and won't reschedule until the next interrupt (such + * as the timer). + * -- Cort + */ + /* This is only used if `cpu' is running an idle task, + so it will reschedule itself anyway... */ + smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); +} + +#ifdef CONFIG_XMON +void smp_send_xmon_break(int cpu) +{ + smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0); +} +#endif /* CONFIG_XMON */ + +static void stop_this_cpu(void *dummy) +{ + __cli(); + while (1) + ; +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + * Stolen from the i386 version. + */ +static spinlock_t call_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; + +static struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} *call_data; + +/* + * This function sends a 'generic call function' IPI to all other CPUs + * in the system. + * + * [SUMMARY] 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. + * currently unused. + * If true, wait (atomically) 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. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) + +{ + struct call_data_struct data; + int ret = -1, cpus = smp_num_cpus-1; + int timeout; + + if (!cpus) + return 0; + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + /* Send a message to all other CPUs and wait for them to respond */ + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0); + + /* Wait for response */ + timeout = 8000000; + while (atomic_read(&data.started) != cpus) { + HMT_low(); + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", + smp_processor_id(), atomic_read(&data.started)); +#ifdef CONFIG_XMON + xmon(0); +#endif +#ifdef CONFIG_PPC_ISERIES + HvCall_terminateMachineSrc(); +#endif + goto out; + } + barrier(); + udelay(1); + } + + if (wait) { + timeout = 1000000; + while (atomic_read(&data.finished) != cpus) { + HMT_low(); + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", + smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); +#ifdef CONFIG_PPC_ISERIES + HvCall_terminateMachineSrc(); +#endif + goto out; + } + barrier(); + udelay(1); + } + } + ret = 0; + + out: + HMT_medium(); + spin_unlock_bh(&call_lock); + return ret; +} + +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + atomic_inc(&call_data->started); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); +} + +static void smp_space_timers( unsigned nr ) +{ + unsigned long offset, i; + + offset = tb_ticks_per_jiffy / nr; + for ( i=1; iprocessor = 0; + + init_idle(); + + for (i = 0; i < NR_CPUS; i++) { + paca = &xPaca[i]; + paca->prof_counter=1; + paca->prof_multiplier = 1; + if(i != 0) { + /* + * Processor 0's segment table is statically + * initialized to real address 0x5000. The + * Other processor's tables are created and + * initialized here. + */ + paca->xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)]; + memset((void *)paca->xStab_data.virt, 0, PAGE_SIZE); + paca->xStab_data.real = __v2a(paca->xStab_data.virt); + paca->default_decr = tb_ticks_per_jiffy / decr_overclock; + } + } + + /* + * XXX very rough, assumes 20 bus cycles to read a cache line, + * timebase increments every 4 bus cycles, 32kB L1 data cache. + */ + cacheflush_time = 5 * 1024; + + /* Probe arch for CPUs */ + cpu_nr = ppc_md.smp_probe(); + + printk("Probe found %d CPUs\n", cpu_nr); + + /* + * only check for cpus we know exist. We keep the callin map + * with cpus at the bottom -- Cort + */ + if (cpu_nr > max_cpus) + cpu_nr = max_cpus; + +#ifdef CONFIG_ISERIES + smp_space_timers( cpu_nr ); +#endif + + printk("Waiting for %d CPUs\n", cpu_nr-1); + + for ( i = 1 ; i < cpu_nr; i++ ) { + int c; + struct pt_regs regs; + + /* create a process for the processor */ + /* we don't care about the values in regs since we'll + never reschedule the forked task. */ + /* We DO care about one bit in the pt_regs we + pass to do_fork. That is the MSR_FP bit in + regs.msr. If that bit is on, then do_fork + (via copy_thread) will call giveup_fpu. + giveup_fpu will get a pointer to our (current's) + last register savearea via current->thread.regs + and using that pointer will turn off the MSR_FP, + MSR_FE0 and MSR_FE1 bits. At this point, this + pointer is pointing to some arbitrary point within + our stack */ + + memset(®s, 0, sizeof(struct pt_regs)); + + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) + panic("failed fork for CPU %d", i); + p = init_task.prev_task; + if (!p) + panic("No idle task for CPU %d", i); + + PPCDBG(PPCDBG_SMP,"\tProcessor %d, task = 0x%lx\n", i, p); + + del_from_runqueue(p); + unhash_process(p); + init_tasks[i] = p; + + p->processor = i; + p->cpus_runnable = 1 << i; /* we schedule the first task manually */ + current_set[i].task = p; + sp = ((unsigned long)p) + sizeof(union task_union) + - STACK_FRAME_OVERHEAD; + current_set[i].sp_real = (void *)__v2a(sp); + + /* wake up cpus */ + ppc_md.smp_kick_cpu(i); + + /* + * wait to see if the cpu made a callin (is actually up). + * use this value that I found through experimentation. + * -- Cort + */ + for ( c = 5000; c && !cpu_callin_map[i] ; c-- ) { + udelay(100); + } + + if ( cpu_callin_map[i] ) + { + printk("Processor %d found.\n", i); + PPCDBG(PPCDBG_SMP, "\tProcessor %d found.\n", i); + /* this sync's the decr's -- Cort */ + smp_num_cpus++; + } else { + printk("Processor %d is stuck.\n", i); + PPCDBG(PPCDBG_SMP, "\tProcessor %d is stuck.\n", i); + } + } + + /* Setup CPU 0 last (important) */ + ppc_md.smp_setup_cpu(0); + + if (smp_num_cpus < 2) { + tb_last_stamp = get_tb(); + smp_tb_synchronized = 1; + } +} + +void __init smp_commence(void) +{ + /* + * Lets the callin's below out of their loop. + */ + PPCDBG(PPCDBG_SMP, "smp_commence: start\n"); + wmb(); + smp_commenced = 1; +} + +void __init smp_callin(void) +{ + int cpu = current->processor; + + smp_store_cpu_info(cpu); + set_dec(xPaca[cpu].default_decr); + cpu_callin_map[cpu] = 1; + + ppc_md.smp_setup_cpu(cpu); + + init_idle(); + + set_bit(smp_processor_id(), &cpu_online_map); + + while(!smp_commenced) { + barrier(); + } + __sti(); +} + +/* intel needs this */ +void __init initialize_secondary(void) +{ +} + +/* Activate a secondary processor. */ +int start_secondary(void *unused) +{ + int cpu; + + cpu = current->processor; + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + smp_callin(); + + /* Go into the idle loop. */ + return cpu_idle(NULL); +} + +void __init smp_setup(char *str, int *ints) +{ +} + +int __init setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + +/* this function is called for each processor + */ +void __init smp_store_cpu_info(int id) +{ + xPaca[id].pvr = _get_PVR(); +} + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); diff -urN linux-2.4.18/arch/ppc64/kernel/stab.c linux-2.4.19-pre5/arch/ppc64/kernel/stab.c --- linux-2.4.18/arch/ppc64/kernel/stab.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/stab.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,360 @@ +/* + * PowerPC64 Segment Translation Support. + * + * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com + * Copyright (c) 2001 Dave Engebretsen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +inline int make_ste(unsigned long stab, + unsigned long esid, unsigned long vsid); +inline void make_slbe(unsigned long esid, unsigned long vsid, + int large); +extern struct Naca *naca; + +/* + * Build an entry for the base kernel segment and put it into + * the segment table or SLB. All other segment table or SLB + * entries are faulted in. + */ +void stab_initialize(unsigned long stab) +{ + unsigned long esid, vsid; + + esid = GET_ESID(KERNELBASE); + vsid = get_kernel_vsid(esid << SID_SHIFT); + + if (!__is_processor(PV_POWER4)) { + __asm__ __volatile__("isync; slbia; isync":::"memory"); + make_ste(stab, esid, vsid); + } else { + /* Invalidate the entire SLB & all the ERATS */ + __asm__ __volatile__("isync" : : : "memory"); +#ifndef CONFIG_PPC_ISERIES + __asm__ __volatile__("slbmte %0,%0" + : : "r" (0) : "memory"); + __asm__ __volatile__("isync; slbia; isync":::"memory"); + make_slbe(esid, vsid, 0); +#else + __asm__ __volatile__("isync; slbia; isync":::"memory"); +#endif + } +} + +/* + * Create a segment table entry for the given esid/vsid pair. + */ +inline int +make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) +{ + unsigned long entry, group, old_esid, castout_entry, i; + unsigned int global_entry; + STE *ste, *castout_ste; + + /* Search the primary group first. */ + global_entry = (esid & 0x1f) << 3; + ste = (STE *)(stab | ((esid & 0x1f) << 7)); + + /* + * Find an empty entry, if one exists. + */ + for(group = 0; group < 2; group++) { + for(entry = 0; entry < 8; entry++, ste++) { + if(!(ste->dw0.dw0.v)) { + ste->dw1.dw1.vsid = vsid; + /* Order VSID updte */ + __asm__ __volatile__ ("eieio" : : : "memory"); + ste->dw0.dw0.esid = esid; + ste->dw0.dw0.v = 1; + ste->dw0.dw0.kp = 1; + /* Order update */ + __asm__ __volatile__ ("sync" : : : "memory"); + + return(global_entry | entry); + } + } + /* Now search the secondary group. */ + global_entry = ((~esid) & 0x1f) << 3; + ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); + } + + /* + * Could not find empty entry, pick one with a round robin selection. + * Search all entries in the two groups. Note that the first time + * we get here, we start with entry 1 so the initializer + * can be common with the SLB castout code. + */ + + /* This assumes we never castout when initializing the stab. */ + PMC_SW_PROCESSOR(stab_capacity_castouts); + + castout_entry = get_paca()->xStab_data.next_round_robin; + for(i = 0; i < 16; i++) { + if(castout_entry < 8) { + global_entry = (esid & 0x1f) << 3; + ste = (STE *)(stab | ((esid & 0x1f) << 7)); + castout_ste = ste + castout_entry; + } else { + global_entry = ((~esid) & 0x1f) << 3; + ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); + castout_ste = ste + (castout_entry - 8); + } + + if((((castout_ste->dw0.dw0.esid) >> 32) == 0) || + (((castout_ste->dw0.dw0.esid) & 0xffffffff) > 0)) { + /* Found an entry to castout. It is either a user */ + /* region, or a secondary kernel segment. */ + break; + } + + castout_entry = (castout_entry + 1) & 0xf; + } + + get_paca()->xStab_data.next_round_robin = (castout_entry + 1) & 0xf; + + /* Modify the old entry to the new value. */ + + /* Force previous translations to complete. DRENG */ + __asm__ __volatile__ ("isync" : : : "memory" ); + + castout_ste->dw0.dw0.v = 0; + __asm__ __volatile__ ("sync" : : : "memory" ); /* Order update */ + castout_ste->dw1.dw1.vsid = vsid; + __asm__ __volatile__ ("eieio" : : : "memory" ); /* Order update */ + old_esid = castout_ste->dw0.dw0.esid; + castout_ste->dw0.dw0.esid = esid; + castout_ste->dw0.dw0.v = 1; + castout_ste->dw0.dw0.kp = 1; + __asm__ __volatile__ ("slbie %0" : : "r" (old_esid << SID_SHIFT)); + /* Ensure completion of slbie */ + __asm__ __volatile__ ("sync" : : : "memory" ); + + return(global_entry | (castout_entry & 0x7)); +} + +/* + * Create a segment buffer entry for the given esid/vsid pair. + */ +inline void make_slbe(unsigned long esid, unsigned long vsid, int large) +{ + unsigned long entry, castout_entry; + slb_dword0 castout_esid_data; + union { + unsigned long word0; + slb_dword0 data; + } esid_data; + union { + unsigned long word0; + slb_dword1 data; + } vsid_data; + + /* + * Find an empty entry, if one exists. + */ + for(entry = 0; entry < naca->slb_size; entry++) { + __asm__ __volatile__("slbmfee %0,%1" + : "=r" (esid_data) : "r" (entry)); + if(!esid_data.data.v) { + /* + * Write the new SLB entry. + */ + vsid_data.word0 = 0; + vsid_data.data.vsid = vsid; + vsid_data.data.kp = 1; + if (large) + vsid_data.data.l = 1; + + esid_data.word0 = 0; + esid_data.data.esid = esid; + esid_data.data.v = 1; + esid_data.data.index = entry; + + /* slbie not needed as no previous mapping existed. */ + /* Order update */ + __asm__ __volatile__ ("isync" : : : "memory"); + __asm__ __volatile__ ("slbmte %0,%1" + : : "r" (vsid_data), + "r" (esid_data)); + /* Order update */ + __asm__ __volatile__ ("isync" : : : "memory"); + return; + } + } + + /* + * Could not find empty entry, pick one with a round robin selection. + */ + + PMC_SW_PROCESSOR(stab_capacity_castouts); + + castout_entry = get_paca()->xStab_data.next_round_robin; + __asm__ __volatile__("slbmfee %0,%1" + : "=r" (castout_esid_data) + : "r" (castout_entry)); + + entry = castout_entry; + castout_entry++; + if(castout_entry >= naca->slb_size) { + castout_entry = 1; + } + get_paca()->xStab_data.next_round_robin = castout_entry; + + /* Invalidate the old entry. */ + castout_esid_data.v = 0; /* Set the class to 0 */ + /* slbie not needed as the previous mapping is still valid. */ + __asm__ __volatile__("slbie %0" : : "r" (castout_esid_data)); + + /* + * Write the new SLB entry. + */ + vsid_data.word0 = 0; + vsid_data.data.vsid = vsid; + vsid_data.data.kp = 1; + if (large) + vsid_data.data.l = 1; + + esid_data.word0 = 0; + esid_data.data.esid = esid; + esid_data.data.v = 1; + esid_data.data.index = entry; + + __asm__ __volatile__ ("isync" : : : "memory"); /* Order update */ + __asm__ __volatile__ ("slbmte %0,%1" + : : "r" (vsid_data), "r" (esid_data)); + __asm__ __volatile__ ("isync" : : : "memory" ); /* Order update */ +} + +/* + * Allocate a segment table entry for the given ea. + */ +int ste_allocate ( unsigned long ea, + unsigned long trap) +{ + unsigned long vsid, esid; + int kernel_segment = 0; + + PMC_SW_PROCESSOR(stab_faults); + + /* Check for invalid effective addresses. */ + if (!IS_VALID_EA(ea)) { + return 1; + } + + /* Kernel or user address? */ + if (REGION_ID(ea) >= KERNEL_REGION_ID) { + kernel_segment = 1; + vsid = get_kernel_vsid( ea ); + } else { + struct mm_struct *mm = current->mm; + if ( mm ) { + vsid = get_vsid(mm->context, ea ); + } else { + return 1; + } + } + + esid = GET_ESID(ea); + if (trap == 0x380 || trap == 0x480) { +#ifndef CONFIG_PPC_ISERIES + if (REGION_ID(ea) == KERNEL_REGION_ID) + make_slbe(esid, vsid, 1); + else +#endif + make_slbe(esid, vsid, 0); + } else { + unsigned char top_entry, stab_entry, *segments; + + stab_entry = make_ste(get_paca()->xStab_data.virt, esid, vsid); + PMC_SW_PROCESSOR_A(stab_entry_use, stab_entry & 0xf); + + segments = get_paca()->xSegments; + top_entry = segments[0]; + if(!kernel_segment && top_entry < (STAB_CACHE_SIZE - 1)) { + top_entry++; + segments[top_entry] = stab_entry; + if(top_entry == STAB_CACHE_SIZE - 1) top_entry = 0xff; + segments[0] = top_entry; + } + } + + return(0); +} + +/* + * Flush all entries from the segment table of the current processor. + * Kernel and Bolted entries are not removed as we cannot tolerate + * faults on those addresses. + */ + +#define STAB_PRESSURE 0 + +void flush_stab(void) +{ + STE *stab = (STE *) get_paca()->xStab_data.virt; + unsigned char *segments = get_paca()->xSegments; + unsigned long flags, i; + + if(!__is_processor(PV_POWER4)) { + unsigned long entry; + STE *ste; + + /* Force previous translations to complete. DRENG */ + __asm__ __volatile__ ("isync" : : : "memory"); + + __save_and_cli(flags); + if(segments[0] != 0xff && !STAB_PRESSURE) { + for(i = 1; i <= segments[0]; i++) { + ste = stab + segments[i]; + ste->dw0.dw0.v = 0; + PMC_SW_PROCESSOR(stab_invalidations); + } + } else { + /* Invalidate all entries. */ + ste = stab; + + /* Never flush the first entry. */ + ste += 1; + for(entry = 1; + entry < (PAGE_SIZE / sizeof(STE)); + entry++, ste++) { + unsigned long ea; + ea = ste->dw0.dw0.esid << SID_SHIFT; + if (STAB_PRESSURE || ea < KERNELBASE) { + ste->dw0.dw0.v = 0; + PMC_SW_PROCESSOR(stab_invalidations); + } + } + } + + *((unsigned long *)segments) = 0; + __restore_flags(flags); + + /* Invalidate the SLB. */ + /* Force invals to complete. */ + __asm__ __volatile__ ("sync" : : : "memory"); + /* Flush the SLB. */ + __asm__ __volatile__ ("slbia" : : : "memory"); + /* Force flush to complete. */ + __asm__ __volatile__ ("sync" : : : "memory"); + } else { + unsigned long flags; + + PMC_SW_PROCESSOR(stab_invalidations); + + __save_and_cli(flags); + __asm__ __volatile__("isync; slbia; isync":::"memory"); + __restore_flags(flags); + } +} diff -urN linux-2.4.18/arch/ppc64/kernel/sys32.S linux-2.4.19-pre5/arch/ppc64/kernel/sys32.S --- linux-2.4.18/arch/ppc64/kernel/sys32.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/sys32.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,243 @@ +/* + * sys32.S: I-cache tricks for 32-bit compatability layer simple + * conversions. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com) + * For PPC ABI convention is parms in Regs 3-10. + * The router in entry.S clears the high 32 bits in the first + * 4 arguments (R3-R6). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "ppc_asm.h" +#include +#include + +/* NOTE: call as jump breaks return stack, we have to avoid that */ + + .text + +_GLOBAL(sys32_mmap) + clrldi r7, r7, 32 /* int fd parm */ + clrldi r8, r8, 32 /* off_t offset parm */ + b .sys_mmap + +_GLOBAL(sys32_lseek) + extsw r4,r4 /* sign extend off_t offset parm */ + b .sys_lseek + +_GLOBAL(sys32_chmod) +/* Ken Aaker.. hmmm maybe I don't need to do anything here */ + b .sys_chmod + +_GLOBAL(sys32_mknod) +/* Ken Aaker.. hmmm maybe I don't need to do anything here */ + b .sys_mknod + +_GLOBAL(sys32_sendto) + clrldi r7, r7, 32 /* struct sockaddr *addr parm */ + clrldi r8, r8, 32 /* int addr_len parm */ + b .sys_sendto + +_GLOBAL(sys32_recvfrom) + clrldi r7, r7, 32 /* struct sockaddr *addr parm */ + clrldi r8, r8, 32 /* int *addr_len parm */ + b .sys_recvfrom + +_GLOBAL(sys32_getsockopt) + clrldi r7, r7, 32 /* int *optlen parm */ + b .sys_getsockopt + +_GLOBAL(sys32_bdflush) + extsw r4,r4 /* sign extend long data parm */ + b .sys_bdflush + +_GLOBAL(sys32_mmap2) + clrldi r7, r7, 32 /* unsigned long fd parm */ + extsw r8, r8 /* off_t offset */ + b .sys_mmap + +_GLOBAL(sys32_socketcall) /* r3=call, r4=args */ + cmpwi r3, 1 + blt- .do_einval + cmpwi r3, 17 + bgt- .do_einval + subi r3, r3, 1 /* index into socketcall_table vectors and jmp */ + sldi r3, r3, 3 /* each entry is 8 bytes */ + LOADADDR(r10,.socketcall_table_begin) + ldx r10, r10, r3 + mtctr r10 + bctr + +/* Socket function vectored fix ups for 32 bit */ +_STATIC(do_sys_socket) /* sys_socket(int, int, int) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + lwa r5,8(r10) + b .sys_socket + +_STATIC(do_sys_bind) /* sys_bind(int fd, struct sockaddr *, int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwa r5,8(r10) + b .sys_bind + +_STATIC(do_sys_connect) /* sys_connect(int, struct sockaddr *, int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwa r5,8(r10) + b .sys_connect + +_STATIC(do_sys_listen) /* sys_listen(int, int) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + b .sys_listen + +_STATIC(do_sys_accept) /* sys_accept(int, struct sockaddr *, int *) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + b .sys_accept + +_STATIC(do_sys_getsockname) /* sys_getsockname(int, struct sockaddr *, int *) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + b .sys_getsockname + +_STATIC(do_sys_getpeername) /* sys_getpeername(int, struct sockaddr *, int *) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + b .sys_getpeername + +_STATIC(do_sys_socketpair) /* sys_socketpair(int, int, int, int *) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + lwa r5,8(r10) + lwz r6,12(r10) + b .sys_socketpair + +_STATIC(do_sys_send) /* sys_send(int, void *, size_t, unsigned int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + lwz r6,12(r10) + b .sys_send + +_STATIC(do_sys_recv) /* sys_recv(int, void *, size_t, unsigned int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + lwz r6,12(r10) + b .sys_recv + +_STATIC(do_sys_sendto) /* sys32_sendto(int, u32, __kernel_size_t32, unsigned int, u32, int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + lwz r6,12(r10) + lwz r7,16(r10) + lwa r8,20(r10) + b .sys32_sendto + +_STATIC(do_sys_recvfrom) /* sys32_recvfrom(int, u32, __kernel_size_t32, unsigned int, u32, u32) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwz r5,8(r10) + lwz r6,12(r10) + lwz r7,16(r10) + lwz r8,20(r10) + b .sys32_recvfrom + +_STATIC(do_sys_shutdown) /* sys_shutdown(int, int) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + b .sys_shutdown + +_STATIC(do_sys_setsockopt) /* sys32_setsockopt(int, int, int, char *, int) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + lwa r5,8(r10) + lwz r6,12(r10) + lwa r7,16(r10) + b .sys32_setsockopt + +_STATIC(do_sys_getsockopt) /* sys32_getsockopt(int, int, int, u32, u32) */ + mr r10,r4 + lwa r3,0(r10) + lwa r4,4(r10) + lwa r5,8(r10) + lwz r6,12(r10) + lwz r7,16(r10) + b .sys32_getsockopt + +_STATIC(do_sys_sendmsg) /* sys32_sendmsg(int, struct msghdr32 *, unsigned int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwa r5,8(r10) + b .sys32_sendmsg + +_STATIC(do_sys_recvmsg) /* sys32_recvmsg(int, struct msghdr32 *, unsigned int) */ + mr r10,r4 + lwa r3,0(r10) + lwz r4,4(r10) + lwa r5,8(r10) + b .sys32_recvmsg + +_STATIC(do_einval) + li r3,-EINVAL + b .ret_from_syscall_1 +_STATIC(do_efault) + li r3,-EFAULT + b .ret_from_syscall_1 + + .data + .align 8 +_GLOBAL(socketcall_table_begin) + .llong .do_sys_socket + .llong .do_sys_bind + .llong .do_sys_connect + .llong .do_sys_listen + .llong .do_sys_accept + .llong .do_sys_getsockname + .llong .do_sys_getpeername + .llong .do_sys_socketpair + .llong .do_sys_send + .llong .do_sys_recv + .llong .do_sys_sendto + .llong .do_sys_recvfrom + .llong .do_sys_shutdown + .llong .do_sys_setsockopt + .llong .do_sys_getsockopt + .llong .do_sys_sendmsg + .llong .do_sys_recvmsg +_GLOBAL(socketcall_table_end) + .section __ex_table,"a" + .align 3 + .llong .socketcall_table_begin + .llong 0 + .llong .socketcall_table_end + .llong .do_efault + .previous diff -urN linux-2.4.18/arch/ppc64/kernel/sys_ppc32.c linux-2.4.19-pre5/arch/ppc64/kernel/sys_ppc32.c --- linux-2.4.18/arch/ppc64/kernel/sys_ppc32.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/sys_ppc32.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,4831 @@ +/* + * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls. + * + * Copyright (C) 2001 IBM + * 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +extern unsigned long wall_jiffies; +#define USEC_PER_SEC (1000000) + +/* + * These are the flags in the MSR that the user is allowed to change + * by modifying the saved value of the MSR on the stack. SE and BE + * should not be in this list since gdb may want to change these. I.e, + * you should be able to step out of a signal handler to see what + * instruction executes next after the signal handler completes. + * Alternately, if you stepped into a signal handler, you should be + * able to continue 'til the next breakpoint from within the signal + * handler, even if the handler returns. + */ +#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) + +/* Use this to get at 32-bit user passed pointers. */ +/* Things to consider: the low-level assembly stub does + srl x, 0, x for first four arguments, so if you have + pointer to something in the first four arguments, just + declare it as a pointer, not u32. On the other side, + arguments from 5th onwards should be declared as u32 + for pointers, and need AA() around each usage. + A() macro should be used for places where you e.g. + have some internal variable u32 and just want to get + rid of a compiler warning. AA() has to be used in + places where you want to convert a function argument + to 32bit pointer or when you e.g. access pt_regs + structure and want to consider 32bit registers only. + - + */ +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) \ +({ unsigned long __ret; \ + __asm__ ("clrldi %0, %0, 32" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) + + + +/* 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 = __getname(); + if (tmp) { + int retval = do_getname32(filename, tmp); + + result = tmp; + if (retval < 0) { + putname(tmp); + result = ERR_PTR(retval); + } + } + return result; +} + + + +extern asmlinkage long sys_utime(char * filename, struct utimbuf * times); + +struct utimbuf32 { + __kernel_time_t32 actime, modtime; +}; + +asmlinkage long sys32_utime(char * filename, struct utimbuf32 *times) +{ + struct utimbuf t; + mm_segment_t old_fs; + int ret; + char *filenam; + + PPCDBG(PPCDBG_SYS32NI, "sys32_utime - running - filename=%s, times=%p - pid=%ld, comm=%s \n", filename, times, current->pid, current->comm); + + 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; +} + + + +struct iovec32 { u32 iov_base; __kernel_size_t32 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(u32 fd, struct iovec32 *vector, u32 count) +{ + struct file *file; + long ret = -EBADF; + + PPCDBG(PPCDBG_SYS32, "sys32_readv - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + file = fget(fd); + if(!file) + goto bad_file; + + if (file->f_op && (file->f_mode & FMODE_READ) && + (file->f_op->readv || file->f_op->read)) + ret = do_readv_writev32(VERIFY_WRITE, file, vector, count); + fput(file); + +bad_file: + PPCDBG(PPCDBG_SYS32, "sys32_readv - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return ret; +} + +asmlinkage long sys32_writev(u32 fd, struct iovec32 *vector, u32 count) +{ + struct file *file; + int ret = -EBADF; + + PPCDBG(PPCDBG_SYS32, "sys32_writev - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + file = fget(fd); + if(!file) + goto bad_file; + if (file->f_op && (file->f_mode & FMODE_WRITE) && + (file->f_op->writev || file->f_op->write)) + ret = do_readv_writev32(VERIFY_READ, file, vector, count); + fput(file); + +bad_file: + PPCDBG(PPCDBG_SYS32, "sys32_writev - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return ret; +} + + + +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 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; +} + +#define SMBFS_NAME "smbfs" +#define NCPFS_NAME "ncpfs" + +asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data) +{ + unsigned long type_page = 0; + unsigned long data_page = 0; + unsigned long dev_page = 0; + unsigned long dir_page = 0; + int err, is_smb, is_ncp; + + PPCDBG(PPCDBG_SYS32, "sys32_mount - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + is_smb = is_ncp = 0; + + err = copy_mount_stuff_to_kernel((const void *)type, &type_page); + if (err) + goto out; + + if (!type_page) { + err = -EINVAL; + goto out; + } + + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + + err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); + if (err) + goto type_out; + + err = copy_mount_stuff_to_kernel(dev_name, &dev_page); + if (err) + goto data_out; + + err = copy_mount_stuff_to_kernel(dir_name, &dir_page); + if (err) + goto dev_out; + + if (!is_smb && !is_ncp) { + lock_kernel(); + err = do_mount((char*)dev_page, (char*)dir_page, + (char*)type_page, new_flags, (char*)data_page); + unlock_kernel(); + } else { + if (is_ncp) + do_ncp_super_data_conv((void *)data_page); + else + do_smb_super_data_conv((void *)data_page); + + lock_kernel(); + err = do_mount((char*)dev_page, (char*)dir_page, + (char*)type_page, new_flags, (char*)data_page); + unlock_kernel(); + } + free_page(dir_page); + +dev_out: + free_page(dev_page); + +data_out: + free_page(data_page); + +type_out: + free_page(type_page); + +out: + + PPCDBG(PPCDBG_SYS32, "sys32_mount - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return err; +} + +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 long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); + +/* Note: it is necessary to treat cmd and id as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, unsigned long addr) +{ + int cmd = (int)cmd_parm; + int id = (int)id_parm; + int cmds = cmd >> SUBCMDSHIFT; + int err; + struct dqblk d; + mm_segment_t old_fs; + char *spec; + + PPCDBG(PPCDBG_SYS32, "sys32_quotactl - entered - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + 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; + } + + PPCDBG(PPCDBG_SYS32, "sys32_quotactl - exited - pid=%ld current=%lx comm=%s \n", + current->pid, current, current->comm); + + return err; +} + + + +/* readdir & getdents */ +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) + +struct old_linux_dirent32 { + u32 d_ino; + u32 d_offset; + unsigned short d_namlen; + /* unsigned char d_type; */ + char d_name[1]; +}; + +struct readdir_callback32 { + struct old_linux_dirent32 * dirent; + int count; +}; + +static int fillonedir(void * __buf, const char * name, int namlen, + off_t offset, ino_t ino, unsigned int d_type) +{ + struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; + struct old_linux_dirent32 * dirent; + + if (buf->count) + return -EINVAL; + buf->count++; + dirent = buf->dirent; + put_user(ino, &dirent->d_ino); + put_user(offset, &dirent->d_offset); + put_user(namlen, &dirent->d_namlen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + return 0; +} + +asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count) +{ + int error = -EBADF; + struct file * file; + struct readdir_callback32 buf; + + file = fget(fd); + if (!file) + goto out; + + buf.count = 0; + buf.dirent = dirent; + + error = vfs_readdir(file, (filldir_t)fillonedir, &buf); + if (error < 0) + goto out_putf; + error = buf.count; + +out_putf: + fput(file); +out: + return error; +} + +#if 0 +struct linux_dirent32 { + u32 d_ino; + u32 d_off; + unsigned short d_reclen; + char d_name[1]; +}; +#else +struct linux_dirent32 { + u32 d_ino; + u32 d_off; + unsigned short d_reclen; + /* unsigned char d_type; */ + char d_name[256]; +}; +#endif + +struct getdents_callback32 { + struct linux_dirent32 * current_dir; + struct linux_dirent32 * previous; + int count; + int error; +}; + +static int +filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino, + unsigned int d_type) +{ + struct linux_dirent32 * dirent; + struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + put_user(offset, &dirent->d_off); + dirent = buf->current_dir; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user(reclen, &dirent->d_reclen); + /* put_user(d_type, &dirent->d_type); */ + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count) +{ + struct file * file; + struct linux_dirent32 * lastdirent; + struct getdents_callback32 buf; + int error = -EBADF; + + PPCDBG(PPCDBG_SYS32NI, "sys32_getdents - running - fd=%x, pid=%ld, comm=%s \n", fd, current->pid, current->comm); + + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, (filldir_t)filldir, &buf); + if (error < 0) + goto out_putf; + lastdirent = buf.previous; + error = buf.error; + if(lastdirent) { + put_user(file->f_pos, &lastdirent->d_off); + error = count - buf.count; + } + out_putf: + fput(file); + + out: + return error; +} +/* end of readdir & getdents */ + + + +/* 32-bit timeval and related flotsam. */ + +struct timeval32 +{ + int tv_sec, tv_usec; +}; + +struct itimerval32 +{ + struct timeval32 it_interval; + struct timeval32 it_value; +}; + + + + +/* + * 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); +} + + + +#define MAX_SELECT_SECONDS ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) + +asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) +{ + fd_set_bits fds; + struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x); + char *bits; + unsigned long nn; + long timeout; + int ret, size; + + PPCDBG(PPCDBG_SYS32X, "sys32_select - entered - n=%x, inp=%p, outp=%p - pid=%ld comm=%s \n", n, inp, outp, current->pid, current->comm); + + timeout = MAX_SCHEDULE_TIMEOUT; + if (tvp) { + time_t sec, usec; + if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp))) + || (ret = __get_user(sec, &tvp->tv_sec)) + || (ret = __get_user(usec, &tvp->tv_usec))) + goto out_nofds; + + ret = -EINVAL; + if(sec < 0 || usec < 0) + goto out_nofds; + + if ((unsigned long) sec < MAX_SELECT_SECONDS) { + timeout = (usec + 1000000/HZ - 1) / (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); + + nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); + if ((ret = get_fd_set32(nn, fds.in, inp)) || + (ret = get_fd_set32(nn, fds.out, outp)) || + (ret = get_fd_set32(nn, fds.ex, exp))) + 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 (tvp && !(current->personality & STICKY_TIMEOUTS)) { + time_t sec = 0, usec = 0; + if (timeout) { + sec = timeout / HZ; + usec = timeout % HZ; + usec *= (1000000/HZ); + } + put_user(sec, &tvp->tv_sec); + put_user(usec, &tvp->tv_usec); + } + + if (ret < 0) + goto out; + if (!ret) { + ret = -ERESTARTNOHAND; + if (signal_pending(current)) + goto out; + ret = 0; + } + + set_fd_set32(nn, inp, fds.res_in); + set_fd_set32(nn, outp, fds.res_out); + set_fd_set32(nn, exp, fds.res_ex); + +out: + kfree(bits); + +out_nofds: + PPCDBG(PPCDBG_SYS32X, "sys32_select - exited - pid=%ld, comm=%s \n", current->pid, current->comm); + return ret; +} + + + + +/* + * Due to some executables calling the wrong select we sometimes + * get wrong args. This determines how the args are being passed + * (a single ptr to them all args passed) then calls + * sys_select() with the appropriate args. -- Cort + */ +/* Note: it is necessary to treat n as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x) +{ + if ((unsigned int)n >= 4096) + panic("ppc32_select - wrong arguments were passed in \n"); + + return sys32_select((int)n, inp, outp, exp, tvp_x); +} + + + +static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf) +{ + unsigned long ino, blksize, blocks; + kdev_t dev, rdev; + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + off_t size; + time_t atime, mtime, ctime; + int err; + + /* Stream the loads of inode data into the load buffer, + * then we push it all into the store buffer below. This + * should give optimal cache performance. + */ + ino = inode->i_ino; + dev = inode->i_dev; + mode = inode->i_mode; + nlink = inode->i_nlink; + uid = inode->i_uid; + gid = inode->i_gid; + rdev = inode->i_rdev; + size = inode->i_size; + atime = inode->i_atime; + mtime = inode->i_mtime; + ctime = inode->i_ctime; + blksize = inode->i_blksize; + blocks = inode->i_blocks; + + err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev); + err |= put_user(ino, &statbuf->st_ino); + err |= put_user(mode, &statbuf->st_mode); + err |= put_user(nlink, &statbuf->st_nlink); + err |= put_user(uid, &statbuf->st_uid); + err |= put_user(gid, &statbuf->st_gid); + err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev); + err |= put_user(size, &statbuf->st_size); + err |= put_user(atime, &statbuf->st_atime); + err |= put_user(0, &statbuf->__unused1); + err |= put_user(mtime, &statbuf->st_mtime); + err |= put_user(0, &statbuf->__unused2); + err |= put_user(ctime, &statbuf->st_ctime); + err |= put_user(0, &statbuf->__unused3); + if (blksize) { + err |= put_user(blksize, &statbuf->st_blksize); + err |= put_user(blocks, &statbuf->st_blocks); + } else { + unsigned int tmp_blocks; + +#define D_B 7 +#define I_B (BLOCK_SIZE / sizeof(unsigned short)) + tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE; + if (tmp_blocks > D_B) { + unsigned int indirect; + + indirect = (tmp_blocks - D_B + I_B - 1) / I_B; + tmp_blocks += indirect; + if (indirect > 1) { + indirect = (indirect - 1 + I_B - 1) / I_B; + tmp_blocks += indirect; + if (indirect > 1) + tmp_blocks++; + } + } + err |= put_user(BLOCK_SIZE, &statbuf->st_blksize); + err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks); +#undef D_B +#undef I_B + } + err |= put_user(0, &statbuf->__unused4[0]); + err |= put_user(0, &statbuf->__unused4[1]); + + return err; +} + +static __inline__ int +do_revalidate(struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + +asmlinkage long sys32_newstat(char* filename, struct stat32* statbuf) +{ + struct nameidata nd; + int error; + + PPCDBG(PPCDBG_SYS32X, "sys32_newstat - running - filename=%s, statbuf=%p, pid=%ld, comm=%s\n", filename, statbuf, current->pid, current->comm); + + error = user_path_walk(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_new_stat32(nd.dentry->d_inode, statbuf); + path_release(&nd); + } + return error; +} + +asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf) +{ + struct nameidata nd; + int error; + + PPCDBG(PPCDBG_SYS32X, "sys32_newlstat - running - fn=%s, pid=%ld, comm=%s\n", filename, current->pid, current->comm); + + error = user_path_walk_link(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_new_stat32(nd.dentry->d_inode, statbuf); + + path_release(&nd); + } + return error; +} + +asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf) +{ + struct file *f; + int err = -EBADF; + + PPCDBG(PPCDBG_SYS32X, "sys32_newfstat - running - fd=%x, pid=%ld, comm=%s\n", fd, current->pid, current->comm); + + f = fget(fd); + if (f) { + struct dentry * dentry = f->f_dentry; + + err = do_revalidate(dentry); + if (!err) + err = cp_new_stat32(dentry->d_inode, statbuf); + fput(f); + } + return err; +} + +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 long sys32_statfs(const char * path, struct statfs32 *buf) +{ + int ret; + struct statfs s; + mm_segment_t old_fs = get_fs(); + char *pth; + + PPCDBG(PPCDBG_SYS32X, "sys32_statfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + pth = getname32 (path); + ret = PTR_ERR(pth); + if (!IS_ERR(pth)) { + set_fs (KERNEL_DS); + ret = sys_statfs((const char *)pth, &s); + set_fs (old_fs); + putname (pth); + if (put_statfs(buf, &s)) + return -EFAULT; + } + + PPCDBG(PPCDBG_SYS32X, "sys32_statfs - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return ret; +} + +extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf); + +asmlinkage long sys32_fstatfs(unsigned int fd, struct statfs32 *buf) +{ + int ret; + struct statfs s; + mm_segment_t old_fs = get_fs(); + + PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + set_fs (KERNEL_DS); + ret = sys_fstatfs(fd, &s); + set_fs (old_fs); + if (put_statfs(buf, &s)) + return -EFAULT; + + PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return ret; +} + + + +extern asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2); + +/* Note: it is necessary to treat option as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2) +{ + PPCDBG(PPCDBG_SYS32, "sys32_sysfs - running - pid=%ld, comm=%s\n", current->pid, current->comm); + return sys_sysfs((int)option, arg1, arg2); +} + + + + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys32_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, + unsigned long flags, u32 __new_addr) +{ + unsigned long ret = -EINVAL; + unsigned long new_addr = AA(__new_addr); + + PPCDBG(PPCDBG_SYS32, "sys32_mremap - entered - pid=%ld current=%lx comm=%s\n", + current->pid, current, current->comm); + + + if (old_len > 0xf0000000UL || new_len > 0xf0000000UL) + goto out; + if (addr > 0xf0000000UL - old_len) + goto out; + down_write(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr > 0xf0000000UL - new_len) + goto out_sem; + } else if (addr > 0xf0000000UL - new_len) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (NULL, addr, new_len, 0, 0); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up_write(¤t->mm->mmap_sem); +out: + + PPCDBG(PPCDBG_SYS32, "sys32_mremap - exited - pid=%ld current=%lx comm=%s\n", + current->pid, current, current->comm); + + 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 *); +extern void ppc_adjtimex(void); + +asmlinkage long sys32_adjtimex(struct timex32 *utp) +{ + struct timex txc; + int ret; + + PPCDBG(PPCDBG_SYS32, "sys32_adjtimex - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + 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); + + /* adjust the conversion of TB to time of day to track adjtimex */ + ppc_adjtimex(); + + 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; +} + + + +#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) +{ + + PPCDBG(PPCDBG_SYS32M, "sys32_create_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return sys_create_module(name_user, (size_t)size); +} + + + +extern asmlinkage long sys_init_module(const char *name_user, struct module *mod_user); + +asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return sys_init_module(name_user, mod_user); +} + + + +extern asmlinkage long sys_delete_module(const char *name_user); + +asmlinkage long sys32_delete_module(const char *name_user) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + 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_CAN_QUERY(mod)) + return put_user(0, ret); + + 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; + } + + return put_user(i, ret); + +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_CAN_QUERY(mod)) + 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_CAN_QUERY(mod)) + 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; +} + +/* Note: it is necessary to treat which as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_query_module(char *name_user, u32 which, char *buf, __kernel_size_t32 bufsize, u32 ret) +{ + struct module *mod; + int err; + + PPCDBG(PPCDBG_SYS32M, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n", + current->pid, current, current->comm); + + 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 ((int)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(); + + PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return err; +} + + + +struct kernel_sym32 { + u32 value; + char name[60]; +}; + +extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); + +asmlinkage long sys32_get_kernel_syms(struct kernel_sym32 *table) +{ + int len, i; + struct kernel_sym *tbl; + mm_segment_t old_fs; + + PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + + 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); + + PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return i; +} + +#else /* CONFIG_MODULES */ + +asmlinkage unsigned long sys32_create_module(const char *name_user, size_t size) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_create_module - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + return -ENOSYS; +} + +asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user) +{ + PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + return -ENOSYS; +} + +asmlinkage long sys32_delete_module(const char *name_user) +{ + PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + return -ENOSYS; +} + +/* Note: it is necessary to treat which as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_query_module(const char *name_user, u32 which, char *buf, size_t bufsize, size_t *ret) +{ + PPCDBG(PPCDBG_SYS32, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + /* Let the program know about the new interface. Not that it'll do them much good. */ + if ((int)which == 0) + return 0; + + PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + return -ENOSYS; +} + +asmlinkage long sys32_get_kernel_syms(struct kernel_sym *table) +{ + PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + 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_fdparm32 { + struct sockaddr gd32_addr; + s8 gd32_path[NFS_MAXPATHLEN+1]; + s32 gd32_version; +}; + +struct nfsctl_fsparm32 { + struct sockaddr gd32_addr; + s8 gd32_path[NFS_MAXPATHLEN+1]; + s32 gd32_maxlen; +}; + +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; + struct nfsctl_fdparm32 u32_getfd; + struct nfsctl_fsparm32 u32_getfs; + } 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_getfd u.u32_getfd +#define ca32_getfs u.u32_getfs +#define ca32_authd u.u32_authd +}; + +union nfsctl_res32 { + __u8 cr32_getfh[NFS_FHSIZE]; + struct knfsd_fh cr32_getfs; +}; + +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); + + if(err) return -EFAULT; + return 0; +} + +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); + karg->ca_export.ex_anon_uid = karg->ca_export.ex_anon_uid; + karg->ca_export.ex_anon_gid = karg->ca_export.ex_anon_gid; + + if(err) return -EFAULT; + return 0; +} + +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); + + if(err) return -EFAULT; + return 0; +} + +static int nfs_getfd32_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_getfd.gd_addr, + &arg32->ca32_getfd.gd32_addr, + (sizeof(struct sockaddr))); + err |= copy_from_user(&karg->ca_getfd.gd_path, + &arg32->ca32_getfd.gd32_path, + (NFS_MAXPATHLEN+1)); + err |= __get_user(karg->ca_getfd.gd_version, + &arg32->ca32_getfd.gd32_version); + + if(err) return -EFAULT; + return 0; +} + +static int nfs_getfs32_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_getfs.gd_addr, + &arg32->ca32_getfs.gd32_addr, + (sizeof(struct sockaddr))); + err |= copy_from_user(&karg->ca_getfs.gd_path, + &arg32->ca32_getfs.gd32_path, + (NFS_MAXPATHLEN+1)); + err |= __get_user(karg->ca_getfs.gd_maxlen, + &arg32->ca32_getfs.gd32_maxlen); + + if(err) return -EFAULT; + return 0; +} + +/* This really doesn't need translations, we are only passing + * back a union which contains opaque nfs file handle data. + */ +static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) +{ + int err; + + err = copy_to_user(res32, kres, sizeof(*res32)); + + if(err) return -EFAULT; + return 0; +} + +/* Note: it is necessary to treat cmd_parm as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +int asmlinkage sys32_nfsservctl(u32 cmd_parm, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32) +{ + int cmd = (int)cmd_parm; + 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: + case NFSCTL_UNEXPORT: + 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; + case NFSCTL_GETFD: + err = nfs_getfd32_trans(karg, arg32); + break; + case NFSCTL_GETFS: + err = nfs_getfs32_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) + goto done; + + if((cmd == NFSCTL_GETFH) || + (cmd == NFSCTL_GETFD) || + (cmd == NFSCTL_GETFS)) + 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; +} + + + +struct timespec32 { + s32 tv_sec; + s32 tv_nsec; +}; + +extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); + +asmlinkage long sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) +{ + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs (); + + PPCDBG(PPCDBG_SYS32NI, "sys32_nanosleep - running - pid=%ld, comm=%s \n", current->pid, current->comm); + + 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; +} + + + + +/* These are here just in case some old sparc32 binary calls it. */ +asmlinkage long sys32_pause(void) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_pause - running - pid=%ld, comm=%s \n", current->pid, current->comm); + + current->state = TASK_INTERRUPTIBLE; + schedule(); + + return -ERESTARTNOHAND; +} + + + +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))); +} + +static inline long put_it32(struct itimerval32 *o, struct itimerval *i) +{ + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || + (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | + __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | + __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | + __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); +} + +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))); +} + +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))); +} + + + + +extern int do_getitimer(int which, struct itimerval *value); + +/* Note: it is necessary to treat which as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getitimer(u32 which, struct itimerval32 *it) +{ + struct itimerval kit; + int error; + + PPCDBG(PPCDBG_SYS32, "sys32_getitimer - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + error = do_getitimer((int)which, &kit); + if (!error && put_it32(it, &kit)) + error = -EFAULT; + + + PPCDBG(PPCDBG_SYS32, "sys32_getitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + return error; +} + + + +extern int do_setitimer(int which, struct itimerval *, struct itimerval *); + +/* Note: it is necessary to treat which as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_setitimer(u32 which, struct itimerval32 *in, struct itimerval32 *out) +{ + struct itimerval kin, kout; + int error; + + PPCDBG(PPCDBG_SYS32, "sys32_setitimer - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + if (in) { + if (get_it32(&kin, in)) + return -EFAULT; + } else + memset(&kin, 0, sizeof(kin)); + + error = do_setitimer((int)which, &kin, out ? &kout : NULL); + if (error || !out) + return error; + if (put_it32(out, &kout)) + return -EFAULT; + + + PPCDBG(PPCDBG_SYS32, "sys32_setitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + return 0; +} + +#define RLIM_INFINITY32 0xffffffff +#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) + +struct rlimit32 { + u32 rlim_cur; + u32 rlim_max; +}; + +extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim); +asmlinkage long 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; +} + +/* Back compatibility for getrlimit. Needed for some apps. */ +asmlinkage long sys32_old_getrlimit(unsigned int resource, struct rlimit32* rlim) +{ + struct rlimit x; // 64-bit version of the resource limits. + struct rlimit32 x32; // 32-bit version of the resource limits. + long rc = 0; + + if (resource >= RLIM_NLIMITS) { + PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - specified resource is too large (%x) - pid=%ld, comm=%s\n", resource, current->pid, current->comm); + return -EINVAL; + } + + memcpy(&x, current->rlim+resource, sizeof(struct rlimit)); + + if(x.rlim_cur > RLIM_INFINITY32) + x32.rlim_cur = RLIM_INFINITY32; + else + x32.rlim_cur = x.rlim_cur; + + if(x.rlim_max > RLIM_INFINITY32) + x32.rlim_max = RLIM_INFINITY32; + else + x32.rlim_max = x.rlim_max; + + rc = (copy_to_user(rlim, &x32, sizeof(x32))) ? (-EFAULT) : 0; + if (rc == 0) { + PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - current=%x, maximum=%x - pid=%ld, comm=%s\n", x32.rlim_cur, x32.rlim_max, current->pid, current->comm); + } else { + PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - unable to copy into user's storage - pid=%ld, comm=%s\n", current->pid, current->comm); + } + return rc; +} + +extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim); +asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r; + long ret; + mm_segment_t old_fs = get_fs (); + + PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - entered - resource=%x, rlim=%p - pid=%ld, comm=%s\n", resource, rlim, current->pid, current->comm); + + 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); + + PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - exited w/ ret=%x - pid=%ld, comm=%s\n", ret, current->pid, current->comm); + return ret; +} + + +struct rusage32 { + struct timeval32 ru_utime; + struct timeval32 ru_stime; + s32 ru_maxrss; + s32 ru_ixrss; + s32 ru_idrss; + s32 ru_isrss; + s32 ru_minflt; + s32 ru_majflt; + s32 ru_nswap; + s32 ru_inblock; + s32 ru_oublock; + s32 ru_msgsnd; + s32 ru_msgrcv; + s32 ru_nsignals; + s32 ru_nvcsw; + s32 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 long sys_getrusage(int who, struct rusage *ru); + +/* Note: it is necessary to treat who as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getrusage(u32 who, struct rusage32 *ru) +{ + struct rusage r; + int ret; + mm_segment_t old_fs = get_fs(); + + PPCDBG(PPCDBG_SYS32X, "sys32_getrusage - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + set_fs (KERNEL_DS); + ret = sys_getrusage((int)who, &r); + set_fs (old_fs); + if (put_rusage (ru, &r)) + return -EFAULT; + + return ret; +} + + + + +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 long sys_sysinfo(struct sysinfo *info); + +asmlinkage long sys32_sysinfo(struct sysinfo32 *info) +{ + struct sysinfo s; + int ret, err; + mm_segment_t old_fs = get_fs (); + + PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + 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; + + PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return ret; +} + + + + +/* 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 long sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) +{ + + PPCDBG(PPCDBG_SYS32X, "sys32_gettimeofday - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + 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 long sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) +{ + struct timeval ktv; + struct timezone ktz; + + PPCDBG(PPCDBG_SYS32, "sys32_settimeofday - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + 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 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; + + PPCDBG(PPCDBG_SYS32, "sys32_times - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + 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; + } + + PPCDBG(PPCDBG_SYS32, "sys32_times - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return ret; +} + +struct msgbuf32 { s32 mtype; char mtext[1]; }; + +struct semid_ds32 { + struct ipc_perm sem_perm; + __kernel_time_t32 sem_otime; + __kernel_time_t32 sem_ctime; + u32 sem_base; + u32 sem_pending; + u32 sem_pending_last; + u32 undo; + unsigned short sem_nsems; +}; + +struct semid64_ds32 { + struct ipc64_perm sem_perm; + unsigned int __unused1; + __kernel_time_t32 sem_otime; + unsigned int __unused2; + __kernel_time_t32 sem_ctime; + u32 sem_nsems; + u32 __unused3; + u32 __unused4; +}; + +struct msqid_ds32 +{ + struct ipc_perm msg_perm; + u32 msg_first; + u32 msg_last; + __kernel_time_t32 msg_stime; + __kernel_time_t32 msg_rtime; + __kernel_time_t32 msg_ctime; + u32 msg_lcbytes; + u32 msg_lqbytes; + 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 msqid64_ds32 { + struct ipc64_perm msg_perm; + unsigned int __unused1; + __kernel_time_t32 msg_stime; + unsigned int __unused2; + __kernel_time_t32 msg_rtime; + unsigned int __unused3; + __kernel_time_t32 msg_ctime; + unsigned int msg_cbytes; + unsigned int msg_qnum; + unsigned int msg_qbytes; + __kernel_pid_t32 msg_lspid; + __kernel_pid_t32 msg_lrpid; + unsigned int __unused4; + unsigned int __unused5; +}; + +struct shmid_ds32 { + struct ipc_perm 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; + unsigned short __unused; + unsigned int __unused2; + unsigned int __unused3; +}; + +struct shmid64_ds32 { + struct ipc64_perm shm_perm; + unsigned int __unused1; + __kernel_time_t32 shm_atime; + unsigned int __unused2; + __kernel_time_t32 shm_dtime; + unsigned int __unused3; + __kernel_time_t32 shm_ctime; + unsigned int __unused4; + __kernel_size_t32 shm_segsz; + __kernel_pid_t32 shm_cpid; + __kernel_pid_t32 shm_lpid; + unsigned int shm_nattch; + unsigned int __unused5; + unsigned int __unused6; +}; + +/* + * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit + * emulation.. + * + * This is really horribly ugly. + */ +static long do_sys32_semctl(int first, int second, int third, void *uptr) +{ + union semun fourth; + u32 pad; + int err, err2; + mm_segment_t old_fs; + + if (!uptr) + return -EINVAL; + err = -EFAULT; + if (get_user(pad, (u32 *)uptr)) + return err; + if (third == SETVAL) + fourth.val = (int)pad; + else + fourth.__pad = (void *)A(pad); + switch (third & (~IPC_64)) { + + case IPC_INFO: + case IPC_RMID: + case SEM_INFO: + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + case SETALL: + case SETVAL: + err = sys_semctl(first, second, third, fourth); + break; + + case IPC_STAT: + case SEM_STAT: + if (third & IPC_64) { + struct semid64_ds s64; + struct semid64_ds32 *usp; + + usp = (struct semid64_ds32 *)A(pad); + fourth.__pad = &s64; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm, + sizeof(struct ipc64_perm)); + err2 |= __put_user(s64.sem_otime, &usp->sem_otime); + err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime); + err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems); + if (err2) + err = -EFAULT; + } else { + struct semid_ds s; + struct semid_ds32 *usp; + + usp = (struct semid_ds32 *)A(pad); + fourth.__pad = &s; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + err2 = copy_to_user(&usp->sem_perm, &s.sem_perm, + sizeof(struct ipc_perm)); + 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; + } + break; + + case IPC_SET: + if (third & IPC_64) { + struct semid64_ds s64; + struct semid64_ds32 *usp; + + usp = (struct semid64_ds32 *)A(pad); + + err = get_user(s64.sem_perm.uid, &usp->sem_perm.uid); + err |= __get_user(s64.sem_perm.gid, + &usp->sem_perm.gid); + err |= __get_user(s64.sem_perm.mode, + &usp->sem_perm.mode); + if (err) + goto out; + fourth.__pad = &s64; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + + } else { + struct semid_ds s; + struct semid_ds32 *usp; + + usp = (struct semid_ds32 *)A(pad); + + 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; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + } + break; + } +out: + return err; +} + +static int +do_sys32_msgsnd(int first, int second, int third, void *uptr) +{ + struct msgbuf *p; + struct msgbuf32 *up = (struct msgbuf32 *)uptr; + mm_segment_t old_fs; + int err; + + if (second < 0) + return -EINVAL; + + p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); + if (!p) + return -ENOMEM; + err = get_user(p->mtype, &up->mtype); + err |= __copy_from_user(p->mtext, &up->mtext, second); + if (err) { + err = -EFAULT; + 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 (second < 0) + return -EINVAL; + + 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 = -EINVAL, err2; + mm_segment_t old_fs; + + switch (second & (~IPC_64)) { + + case IPC_INFO: + case IPC_RMID: + case MSG_INFO: + err = sys_msgctl(first, second, (struct msqid_ds *)uptr); + break; + + case IPC_SET: + if (second & IPC_64) { + struct msqid64_ds m64; + struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr; + + err2 = copy_from_user(&m64.msg_perm, &up->msg_perm, + sizeof(struct ipc64_perm)); + err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes); + if (err2) { + err = -EFAULT; + break; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, + (struct msqid_ds *)&m64); + set_fs(old_fs); + } else { + struct msqid_ds m; + struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + + err2 = copy_from_user(&m.msg_perm, &up->msg_perm, + sizeof(struct ipc_perm)); + err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes); + if (err2) { + err = -EFAULT; + break; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, &m); + set_fs(old_fs); + } + break; + + case IPC_STAT: + case MSG_STAT: + if (second & IPC_64) { + struct msqid64_ds m64; + struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, + (struct msqid_ds *)&m64); + set_fs(old_fs); + + err2 = copy_to_user(&up->msg_perm, &m64.msg_perm, + sizeof(struct ipc64_perm)); + err2 |= __put_user(m64.msg_stime, &up->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid); + if (err2) + err = -EFAULT; + } else { + struct msqid64_ds m; + struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, (struct msqid_ds *)&m); + set_fs(old_fs); + + err2 = copy_to_user(&up->msg_perm, &m.msg_perm, + sizeof(struct ipc_perm)); + 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; + } + break; + } +#if 0 + udbg_printf(" err3 = 0x%lx\n", err); +#endif + 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) + return err; + err = sys_shmat(first, uptr, second, &raddr); + if (err) + return err; + err = put_user(raddr, uaddr); + return err; +} + +static int +do_sys32_shmctl(int first, int second, void *uptr) +{ + int err = -EFAULT, err2; + mm_segment_t old_fs; + + switch (second & (~IPC_64)) { + + case IPC_INFO: + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + err = sys_shmctl(first, second, (struct shmid_ds *)uptr); + break; + case IPC_SET: + if (second & IPC_64) { + struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr; + struct shmid64_ds s64; + + err = get_user(s64.shm_perm.uid, &up->shm_perm.uid); + err |= __get_user(s64.shm_perm.gid, &up->shm_perm.gid); + err |= __get_user(s64.shm_perm.mode, + &up->shm_perm.mode); + if (err) + break; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, + (struct shmid_ds *)&s64); + set_fs(old_fs); + } else { + struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + struct shmid_ds s; + + 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) + break; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, &s); + set_fs(old_fs); + } + break; + + case IPC_STAT: + case SHM_STAT: + if (second & IPC_64) { + struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr; + struct shmid64_ds s64; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, + (struct shmid_ds *)&s64); + set_fs(old_fs); + if (err < 0) + break; + + err2 = copy_to_user(&up->shm_perm, &s64.shm_perm, + sizeof(struct ipc64_perm)); + err2 |= __put_user(s64.shm_atime, &up->shm_atime); + err2 |= __put_user(s64.shm_dtime, &up->shm_dtime); + err2 |= __put_user(s64.shm_ctime, &up->shm_ctime); + err2 |= __put_user(s64.shm_segsz, &up->shm_segsz); + err2 |= __put_user(s64.shm_nattch, &up->shm_nattch); + err2 |= __put_user(s64.shm_cpid, &up->shm_cpid); + err2 |= __put_user(s64.shm_lpid, &up->shm_lpid); + if (err2) + err = -EFAULT; + } else { + struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + struct shmid_ds s; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, &s); + set_fs(old_fs); + if (err < 0) + break; + + err2 = copy_to_user(&up->shm_perm, &s.shm_perm, + sizeof(struct ipc_perm)); + 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; + } + break; + + case SHM_INFO: { + struct shm_info si; + struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; + } *uip = (struct shm_info32 *)uptr; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (struct shmid_ds *)&si); + set_fs(old_fs); + if (err < 0) + break; + err2 = put_user(si.used_ids, &uip->used_ids); + err2 |= __put_user(si.shm_tot, &uip->shm_tot); + err2 |= __put_user(si.shm_rss, &uip->shm_rss); + err2 |= __put_user(si.shm_swp, &uip->shm_swp); + err2 |= __put_user(si.swap_attempts, &uip->swap_attempts); + err2 |= __put_user(si.swap_successes, &uip->swap_successes); + if (err2) + err = -EFAULT; + break; + } + } + return err; +} + +/* + * Note: it is necessary to treat first_parm, second_parm, and + * third_parm as unsigned ints, with the corresponding cast to a + * signed int to insure that the proper conversion (sign extension) + * between the register representation of a signed int (msr in 32-bit + * mode) and the register representation of a signed int (msr in + * 64-bit mode) is performed. + */ +asmlinkage long sys32_ipc(u32 call, u32 first_parm, u32 second_parm, u32 third_parm, u32 ptr, u32 fifth) +{ + int first = (int)first_parm; + int second = (int)second_parm; + int third = (int)third_parm; + int version, err; + + PPCDBG(PPCDBG_SYS32, "sys32_ipc - entered - call=%x, parm1=%x, parm2=%x, parm3=%x, parm4=%x, parm5=%x \n", + call, first_parm, second_parm, third_parm, ptr, fifth); + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + err = sys_semop(first, (struct sembuf *)AA(ptr), + second); + break; + case SEMGET: + err = sys_semget(first, second, third); + break; + case SEMCTL: + err = do_sys32_semctl(first, second, third, + (void *)AA(ptr)); + break; + + case MSGSND: + err = do_sys32_msgsnd(first, second, third, + (void *)AA(ptr)); + break; + case MSGRCV: + err = do_sys32_msgrcv(first, second, fifth, third, + version, (void *)AA(ptr)); + break; + case MSGGET: + err = sys_msgget((key_t)first, second); + break; + case MSGCTL: + err = do_sys32_msgctl(first, second, (void *)AA(ptr)); + break; + + case SHMAT: + err = do_sys32_shmat(first, second, third, + version, (void *)AA(ptr)); + break; + case SHMDT: + err = sys_shmdt((char *)AA(ptr)); + break; + case SHMGET: + err = sys_shmget(first, second, third); + break; + case SHMCTL: + err = do_sys32_shmctl(first, second, (void *)AA(ptr)); + break; + default: + err = -EINVAL; + break; + } + + + PPCDBG(PPCDBG_SYS32, "sys32_ipc - exited w/ %d/0x%x \n", err, err); + return err; +} + +/* stat syscall methods. */ +extern asmlinkage int sys_stat(char* filename, struct __old_kernel_stat* statbuf); + +static int cp_old_stat32(struct inode* inode, struct __old_kernel_stat32* statbuf) +{ + static int warncount = 5; + struct __old_kernel_stat32 tmp; + + if (warncount) { + warncount--; + printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n", + current->comm); + } + + tmp.st_dev = kdev_t_to_nr(inode->i_dev); + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + SET_OLDSTAT_UID(tmp, inode->i_uid); + SET_OLDSTAT_GID(tmp, inode->i_gid); + tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; +} + +asmlinkage long sys32_stat(char* filename, struct __old_kernel_stat32* statbuf) +{ + struct nameidata nd; + int error; + + PPCDBG(PPCDBG_SYS32X, "sys32_stat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + error = user_path_walk(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_old_stat32(nd.dentry->d_inode, statbuf); + path_release(&nd); + } + + PPCDBG(PPCDBG_SYS32X, "sys32_stat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return error; +} + +asmlinkage long sys32_fstat(unsigned int fd, struct __old_kernel_stat32* statbuf) +{ + struct file *f; + int err = -EBADF; + + PPCDBG(PPCDBG_SYS32X, "sys32_fstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + f = fget(fd); + if (f) { + struct dentry * dentry = f->f_dentry; + + err = do_revalidate(dentry); + if (!err) + err = cp_old_stat32(dentry->d_inode, statbuf); + fput(f); + } + + PPCDBG(PPCDBG_SYS32X, "sys32_fstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return err; +} + +asmlinkage long sys32_lstat(char* filename, struct __old_kernel_stat32* statbuf) +{ + struct nameidata nd; + int error; + + PPCDBG(PPCDBG_SYS32X, "sys32_lstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + error = user_path_walk_link(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_old_stat32(nd.dentry->d_inode, statbuf); + + path_release(&nd); + } + + PPCDBG(PPCDBG_SYS32X, "sys32_lstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return error; +} + +extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t* offset, size_t count); + +/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, __kernel_off_t32* offset, u32 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((int)out_fd, (int)in_fd, offset ? &of : NULL, count); + set_fs(old_fs); + + if (offset && put_user(of, offset)) + return -EFAULT; + + return ret; +} + +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen); + +asmlinkage long sys32_setsockopt(int fd, int level, int optname, char* optval, int optlen) +{ + + PPCDBG(PPCDBG_SYS32,"sys32_setsockopt - running - pid=%ld, comm=%s\n", current->pid, current->comm); + + if (optname == SO_ATTACH_FILTER) { + struct sock_fprog32 { + __u16 len; + __u32 filter; + } *fprog32 = (struct sock_fprog32 *)optval; + struct sock_fprog kfprog; + struct sock_filter *kfilter; + unsigned int fsize; + mm_segment_t old_fs; + __u32 uptr; + int ret; + + if (get_user(kfprog.len, &fprog32->len) || + __get_user(uptr, &fprog32->filter)) + return -EFAULT; + kfprog.filter = (struct sock_filter *)A(uptr); + fsize = kfprog.len * sizeof(struct sock_filter); + kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); + if (kfilter == NULL) + return -ENOMEM; + if (copy_from_user(kfilter, kfprog.filter, fsize)) { + kfree(kfilter); + return -EFAULT; + } + kfprog.filter = kfilter; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *)&kfprog, sizeof(kfprog)); + set_fs(old_fs); + kfree(kfilter); + return ret; + } + return sys_setsockopt(fd, level, optname, optval, optlen); +} + + + + +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */ +#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) + +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; +}; + +__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); +} + +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); +} + +extern __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file); +} + +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; +} + +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; +} + +/* 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; +} + +asmlinkage long sys32_sendmsg(int fd, struct msghdr32* user_msg, unsigned int 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; + + PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags); + + 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; + + 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); + } + + /* 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: + + PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - exited w/ %lx \n", err); + return err; +} + +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. */ + get_file(fp[i]); + fd_install(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) - sizeof(struct cmsghdr))) { + 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; + + switch (kcmsg32->cmsg_type) { + /* + * The timestamp type's data needs to be converted + * from 64-bit time values to 32-bit time values + */ + case SO_TIMESTAMP: { + __kernel_time_t32* ptr_time32 = CMSG32_DATA(kcmsg32); + __kernel_time_t* ptr_time = CMSG_DATA(ucmsg); + *ptr_time32 = *ptr_time; + *(ptr_time32+1) = *(ptr_time+1); + kcmsg32->cmsg_len -= 2*(sizeof(__kernel_time_t) - + sizeof(__kernel_time_t32)); + } + default:; + } + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(kcmsg32->cmsg_len)); + } + + /* 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 long 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; + + PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags); + + 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; + + 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); + } + + if (uaddr != NULL && err >= 0 && kern_msg.msg_namelen) + 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; + + PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - exited w/ %lx \n", len); + return len; +} + +/* + * count32() counts the number of arguments/envelopes + */ +static int count32(u32 * argv, int max) +{ + int i = 0; + + if (argv != NULL) { + for (;;) { + u32 p; int error; + + error = get_user(p,argv); + if (error) + return error; + if (!p) + break; + argv++; + if (++i > max) + return -E2BIG; + } + } + return i; +} + +/* + * 'copy_string32()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + */ +static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) +{ + while (argc-- > 0) { + u32 str; + int len; + unsigned long pos; + + if (get_user(str, argv + argc) || + !str || + !(len = strnlen_user((char *)A(str), bprm->p))) + return -EFAULT; + + if (bprm->p < len) + return -E2BIG; + + bprm->p -= len; + + pos = bprm->p; + while (len) { + char *kaddr; + struct page *page; + int offset, bytes_to_copy, new, err; + + offset = pos % PAGE_SIZE; + page = bprm->page[pos / PAGE_SIZE]; + new = 0; + if (!page) { + page = alloc_page(GFP_USER); + bprm->page[pos / PAGE_SIZE] = page; + if (!page) + return -ENOMEM; + new = 1; + } + kaddr = (char *)kmap(page); + + if (new && offset) + memset(kaddr, 0, offset); + bytes_to_copy = PAGE_SIZE - offset; + if (bytes_to_copy > len) { + bytes_to_copy = len; + if (new) + memset(kaddr+offset+len, 0, + PAGE_SIZE-offset-len); + } + + err = copy_from_user(kaddr + offset, (char *)A(str), + bytes_to_copy); + flush_page_to_ram(page); + kunmap((unsigned long)kaddr); + + if (err) + return -EFAULT; + + pos += bytes_to_copy; + str += bytes_to_copy; + len -= bytes_to_copy; + } + } + return 0; +} + +/* + * sys32_execve() executes a new program. + */ +static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) +{ + struct linux_binprm bprm; + struct file * file; + int retval; + int i; + + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); + + file = open_exec(filename); + + retval = PTR_ERR(file); + if (IS_ERR(file)) + return retval; + + bprm.file = file; + bprm.filename = filename; + bprm.sh_bang = 0; + bprm.loader = 0; + bprm.exec = 0; + if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) { + allow_write_access(file); + fput(file); + return bprm.argc; + } + if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) { + allow_write_access(file); + fput(file); + return bprm.argc; + } + + retval = prepare_binprm(&bprm); + if (retval < 0) + goto out; + + retval = copy_strings_kernel(1, &bprm.filename, &bprm); + if (retval < 0) + goto out; + + bprm.exec = bprm.p; + retval = copy_strings32(bprm.envc, envp, &bprm); + if (retval < 0) + goto out; + + retval = copy_strings32(bprm.argc, argv, &bprm); + if (retval < 0) + goto out; + + retval = search_binary_handler(&bprm, regs); + if (retval >= 0) + /* execve success */ + return retval; + +out: + /* Something went wrong, return the inode and free the argument pages*/ + allow_write_access(bprm.file); + if (bprm.file) + fput(bprm.file); + + for (i=0 ; ipid, current->comm); + //PPCDBG(PPCDBG_SYS32NI, " a0=%lx, a1=%lx, a2=%lx, a3=%lx, a4=%lx, a5=%lx, regs=%p \n", a0, a1, a2, a3, a4, a5, regs); + } + + filename = getname((char *) a0); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + if (regs->msr & MSR_FP) + giveup_fpu(current); + + error = do_execve32(filename, (u32*) a1, (u32*) a2, regs); + + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); + +out: + ifppcdebug(PPCDBG_SYS32) { + udbg_printf("sys32_execve - exited - returning %x - pid=%ld \n", error, current->pid); + //udbg_printf("sys32_execve - at exit - regs->gpr[1]=%lx, gpr[3]=%lx, gpr[4]=%lx, gpr[5]=%lx, gpr[6]=%lx \n", regs->gpr[1], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); + } + return error; +} + +/* Set up a thread for executing a new program. */ +void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp) +{ + set_fs(USER_DS); + memset(regs->gpr, 0, sizeof(regs->gpr)); + memset(®s->ctr, 0, 4 * sizeof(regs->ctr)); + regs->nip = nip; + regs->gpr[1] = sp; + regs->msr = MSR_USER32; + if (last_task_used_math == current) + last_task_used_math = 0; + current->thread.fpscr = 0; +} + +extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5); + +/* Note: it is necessary to treat option as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +{ + PPCDBG(PPCDBG_SYS32, "sys32_prctl - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return sys_prctl((int)option, + (unsigned long) arg2, + (unsigned long) arg3, + (unsigned long) arg4, + (unsigned long) arg5); +} + +extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_sched_rr_get_interval(u32 pid, struct timespec32 *interval) +{ + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs (); + + PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + set_fs (KERNEL_DS); + ret = sys_sched_rr_get_interval((int)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; + + PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return ret; +} + +extern asmlinkage int sys_pciconfig_read(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) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_read - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm); + + return sys_pciconfig_read((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)AA(ubuf)); +} + + + + +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_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + + PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_write - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + return sys_pciconfig_write((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)AA(ubuf)); +} + +extern asmlinkage int sys_newuname(struct new_utsname * name); + +asmlinkage int ppc64_newuname(struct new_utsname * name) +{ + int errno = sys_newuname(name); + + if (current->personality == PER_LINUX32 && !errno) { + if(copy_to_user(name->machine, "ppc\0\0", 8)) { + errno = -EFAULT; + } + } + return errno; +} + +extern asmlinkage long sys_personality(unsigned long); + +asmlinkage int sys32_personality(unsigned long personality) +{ + int ret; + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + if (ret == PER_LINUX32) + ret = PER_LINUX; + return ret; +} + + + +extern asmlinkage long sys_access(const char * filename, int mode); + +/* Note: it is necessary to treat mode as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_access(const char * filename, u32 mode) +{ + return sys_access(filename, (int)mode); +} + + +extern asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs); + +/* Note: it is necessary to treat p1, p2, p3, p4, p5, p7, and regs as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_clone(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs) +{ + return sys_clone((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs); +} + + +extern asmlinkage long sys_creat(const char * pathname, int mode); + +/* Note: it is necessary to treat mode as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_creat(const char * pathname, u32 mode) +{ + return sys_creat(pathname, (int)mode); +} + + +extern asmlinkage long sys_exit(int error_code); + +/* Note: it is necessary to treat error_code as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_exit(u32 error_code) +{ + return sys_exit((int)error_code); +} + + +extern asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, struct rusage * ru); + +/* Note: it is necessary to treat pid and options as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_wait4(u32 pid, unsigned int * stat_addr, u32 options, struct rusage * ru) +{ + PPCDBG(PPCDBG_SYS32, "sys32_wait4 - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + if (!ru) + return sys_wait4((int)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((int)pid, stat_addr ? &status : NULL, options, &r); + set_fs (old_fs); + if (put_rusage ((struct rusage32 *)ru, &r)) return -EFAULT; + if (stat_addr && put_user (status, stat_addr)) + return -EFAULT; + return ret; + } + +} + + +extern asmlinkage long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options); + +/* Note: it is necessary to treat pid and options as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_waitpid(u32 pid, unsigned int * stat_addr, u32 options) +{ + return sys_waitpid((int)pid, stat_addr, (int)options); +} + + +extern asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs); + +/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_fork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs) +{ + return sys_fork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs); +} + + +extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); + +/* Note: it is necessary to treat gidsetsize as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t *grouplist) +{ + return sys_getgroups((int)gidsetsize, grouplist); +} + + +extern asmlinkage long sys_getpgid(pid_t pid); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getpgid(u32 pid) +{ + return sys_getpgid((int)pid); +} + + +extern asmlinkage long sys_getpriority(int which, int who); + +/* Note: it is necessary to treat which and who as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getpriority(u32 which, u32 who) +{ + return sys_getpriority((int)which, (int)who); +} + + +extern asmlinkage long sys_getsid(pid_t pid); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_getsid(u32 pid) +{ + return sys_getsid((int)pid); +} + + +extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); + +/* Note: it is necessary to treat on as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on) +{ + return sys_ioperm(from, num, (int)on); +} + + +extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4); + +/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4) +{ + return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4); +} + + +extern asmlinkage long sys_kill(int pid, int sig); + +/* Note: it is necessary to treat pid and sig as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_kill(u32 pid, u32 sig) +{ + return sys_kill((int)pid, (int)sig); +} + + +extern asmlinkage long sys_mkdir(const char * pathname, int mode); + +/* Note: it is necessary to treat mode as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_mkdir(const char * pathname, u32 mode) +{ + return sys_mkdir(pathname, (int)mode); +} + + +extern asmlinkage long sys_mlockall(int flags); + +/* Note: it is necessary to treat flags as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_mlockall(u32 flags) +{ + return sys_mlockall((int)flags); +} + + +extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4); + +/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4) +{ + return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4); +} + + +extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags); + +/* Note: it is necessary to treat flags as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_msync(unsigned long start, size_t len, u32 flags) +{ + return sys_msync(start, len, (int)flags); +} + + +extern asmlinkage long sys_nice(int increment); + +/* Note: it is necessary to treat increment as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_nice(u32 increment) +{ + return sys_nice((int)increment); +} + + +extern asmlinkage long sys_open(const char * filename, int flags, int mode); + +/* Note: it is necessary to treat flags and mode as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_open(const char * filename, int flags, int mode) +{ + return sys_open(filename, (int)flags, (int)mode); +} + + +extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz); + +/* Note: it is necessary to treat bufsiz as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_readlink(const char * path, char * buf, u32 bufsiz) +{ + return sys_readlink(path, buf, (int)bufsiz); +} + + +extern asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg); + +/* Note: it is necessary to treat magic1 and magic2 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_reboot(u32 magic1, u32 magic2, unsigned int cmd, void * arg) +{ + return sys_reboot((int)magic1, (int)magic2, cmd, arg); +} + + +extern asmlinkage long sys_sched_get_priority_max(int policy); + +/* Note: it is necessary to treat option as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_get_priority_max(u32 policy) +{ + return sys_sched_get_priority_max((int)policy); +} + + +extern asmlinkage long sys_sched_get_priority_min(int policy); + +/* Note: it is necessary to treat policy as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_get_priority_min(u32 policy) +{ + return sys_sched_get_priority_min((int)policy); +} + + +extern asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param *param) +{ + return sys_sched_getparam((int)pid, param); +} + + +extern asmlinkage long sys_sched_getscheduler(pid_t pid); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_getscheduler(u32 pid) +{ + return sys_sched_getscheduler((int)pid); +} + + +extern asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param *param); + +/* Note: it is necessary to treat pid as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param *param) +{ + return sys_sched_setparam((int)pid, param); +} + + +extern asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param); + +/* Note: it is necessary to treat pid and policy as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param *param) +{ + return sys_sched_setscheduler((int)pid, (int)policy, param); +} + + +extern asmlinkage long sys_setdomainname(char *name, int len); + +/* Note: it is necessary to treat len as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_setdomainname(char *name, u32 len) +{ + return sys_setdomainname(name, (int)len); +} + + +extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); + +/* Note: it is necessary to treat gidsetsize as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t *grouplist) +{ + return sys_setgroups((int)gidsetsize, grouplist); +} + + +extern asmlinkage long sys_sethostname(char *name, int len); + +/* Note: it is necessary to treat len as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_sethostname(char *name, u32 len) +{ + return sys_sethostname(name, (int)len); +} + + +extern asmlinkage long sys_setpgid(pid_t pid, pid_t pgid); + +/* Note: it is necessary to treat pid and pgid as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_setpgid(u32 pid, u32 pgid) +{ + return sys_setpgid((int)pid, (int)pgid); +} + + +extern asmlinkage long sys_setpriority(int which, int who, int niceval); + +/* Note: it is necessary to treat which, who, and niceval as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_setpriority(u32 which, u32 who, u32 niceval) +{ + return sys_setpriority((int)which, (int)who, (int)niceval); +} + + +extern asmlinkage long sys_ssetmask(int newmask); + +/* Note: it is necessary to treat newmask as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_ssetmask(u32 newmask) +{ + return sys_ssetmask((int) newmask); +} + + +extern asmlinkage long sys_swapon(const char * specialfile, int swap_flags); + +/* Note: it is necessary to treat swap_flags as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_swapon(const char * specialfile, u32 swap_flags) +{ + return sys_swapon(specialfile, (int)swap_flags); +} + + +extern asmlinkage long sys_syslog(int type, char * buf, int len); + +/* Note: it is necessary to treat type and len as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_syslog(u32 type, char * buf, u32 len) +{ + return sys_syslog((int)type, buf, (int)len); +} + + +extern asmlinkage long sys_umask(int mask); + +/* Note: it is necessary to treat mask as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_umask(u32 mask) +{ + return sys_umask((int)mask); +} + + +extern asmlinkage long sys_umount(char * name, int flags); + +/* Note: it is necessary to treat flags as an unsigned int, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long sys32_umount(char * name, u32 flags) +{ + return sys_umount(name, (int)flags); +} + + +extern asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs); + +/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_vfork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs) +{ + return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs); +} + + +extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4); + +/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints, + * with the corresponding cast to a signed int to insure that the + * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) + * and the register representation of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4) +{ + return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4); +} + + + + + +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 reg6, 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 reg6 ,u32 poshi, u32 poslo) +{ + return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); +} + + +extern asmlinkage long sys_truncate(const char * path, unsigned long length); +extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length); + +asmlinkage int sys32_truncate64(const char * path, u32 reg4, unsigned long high, unsigned long low) +{ + if ((int)high < 0) + return -EINVAL; + else + return sys_truncate(path, (high << 32) | low); +} + +asmlinkage int sys32_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, unsigned long low) +{ + if ((int)high < 0) + return -EINVAL; + else + return sys_ftruncate(fd, (high << 32) | low); +} + + + +asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + if (cmd >= F_GETLK64 && cmd <= F_SETLKW64) + return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg); + return sys32_fcntl(fd, cmd, arg); +} + + + + +struct __sysctl_args32 { + u32 name; + int nlen; + u32 oldval; + u32 oldlenp; + u32 newval; + u32 newlen; + u32 __unused[4]; +}; + +extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) +{ + struct __sysctl_args32 tmp; + int error; + size_t oldlen, *oldlenp = NULL; + unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; + + if (copy_from_user(&tmp, args, sizeof(tmp))) + return -EFAULT; + + if (tmp.oldval && tmp.oldlenp) { + /* Duh, this is ugly and might not work if sysctl_args + is in read-only memory, but do_sysctl does indirectly + a lot of uaccess in both directions and we'd have to + basically copy the whole sysctl.c here, and + glibc's __sysctl uses rw memory for the structure + anyway. */ + if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) || + put_user(oldlen, (size_t *)addr)) + return -EFAULT; + oldlenp = (size_t *)addr; + } + + lock_kernel(); + error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval), + oldlenp, (void *)A(tmp.newval), tmp.newlen); + unlock_kernel(); + if (oldlenp) { + if (!error) { + if (get_user(oldlen, (size_t *)addr) || + put_user(oldlen, (u32 *)A(tmp.oldlenp))) + error = -EFAULT; + } + copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); + } + return error; +} + +asmlinkage long sys32_time(__kernel_time_t32* tloc) +{ + __kernel_time_t32 secs; + + struct timeval tv; + + do_gettimeofday( &tv ); + secs = tv.tv_sec; + + if (tloc) { + if (put_user(secs,tloc)) + secs = -EFAULT; + } + + return secs; +} diff -urN linux-2.4.18/arch/ppc64/kernel/syscalls.c linux-2.4.19-pre5/arch/ppc64/kernel/syscalls.c --- linux-2.4.18/arch/ppc64/kernel/syscalls.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/syscalls.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,316 @@ +/* + * linux/arch/ppc/kernel/sys_ppc.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/i386/kernel/sys_i386.c" + * Adapted from the i386 version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au). + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/PPC + * platform. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern unsigned long wall_jiffies; +#define USEC_PER_SEC (1000000) + +void +check_bugs(void) +{ +} + +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +{ + printk(KERN_ERR "sys_ioperm()\n"); + return -EIO; +} + +int sys_iopl(int a1, int a2, int a3, int a4) +{ + printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4); + return (-ENOSYS); +} + +int sys_vm86(int a1, int a2, int a3, int a4) +{ + printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4); + return (-ENOSYS); +} + +int sys_modify_ldt(int a1, int a2, int a3, int a4) +{ + printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4); + return (-ENOSYS); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int +sys_ipc (uint call, int first, int second, long third, void *ptr, long fifth) +{ + int version, ret; + + PPCDBG(PPCDBG_SYS64X, "sys_ipc - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + ret = -EINVAL; + switch (call) { + case SEMOP: + ret = sys_semop (first, (struct sembuf *)ptr, second); + break; + case SEMGET: + ret = sys_semget (first, second, third); + break; + case SEMCTL: { + union semun fourth; + + if (!ptr) + break; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))) + || (ret = get_user(fourth.__pad, (void **)ptr))) + break; + ret = sys_semctl (first, second, third, fourth); + break; + } + case MSGSND: + ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third); + break; + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + + if (!ptr) + break; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))) + || (ret = copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp)))) + break; + ret = sys_msgrcv (first, (struct msgbuf *)(unsigned long)tmp.msgp, + second, tmp.msgtyp, third); + break; + } + default: + ret = sys_msgrcv (first, (struct msgbuf *) ptr, + second, fifth, third); + break; + } + break; + case MSGGET: + ret = sys_msgget ((key_t) first, second); + break; + case MSGCTL: + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + break; + case SHMAT: + switch (version) { + default: { + ulong raddr; + + if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, + sizeof(ulong)))) + break; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + break; + ret = put_user (raddr, (ulong *) third); + break; + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + break; + ret = sys_shmat (first, (char *) ptr, second, + (ulong *) third); + break; + } + break; + case SHMDT: + ret = sys_shmdt ((char *)ptr); + break; + case SHMGET: + ret = sys_shmget (first, second, third); + break; + case SHMCTL: + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + break; + } + + PPCDBG(PPCDBG_SYS64X, "sys_ipc - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return ret; +} + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(int *fildes) +{ + int fd[2]; + int error; + + PPCDBG(PPCDBG_SYS64X, "sys_pipe - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + + PPCDBG(PPCDBG_SYS64X, "sys_pipe - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return error; +} + +asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + struct file * file = NULL; + unsigned long ret = -EBADF; + + PPCDBG(PPCDBG_SYS64X, "sys_mmap - entered - addr=%lx, len=%lx - pid=%ld, comm=%s \n", addr, len, current->pid, current->comm); + + if (!(flags & MAP_ANONYMOUS)) { + if (!(file = fget(fd))) + goto out; + } + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down_write(¤t->mm->mmap_sem); + ret = do_mmap(file, addr, len, prot, flags, offset); + up_write(¤t->mm->mmap_sem); + if (file) + fput(file); + +out: + + PPCDBG(PPCDBG_SYS64X, "sys_mmap - exited - ret=%x \n", ret); + + return ret; +} + +asmlinkage int sys_pause(void) +{ + + PPCDBG(PPCDBG_SYS64X, "sys_pause - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + current->state = TASK_INTERRUPTIBLE; + schedule(); + + PPCDBG(PPCDBG_SYS64X, "sys_pause - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return -ERESTARTNOHAND; +} + +static int __init set_fakeppc(char *str) +{ + if (*str) + return 0; + init_task.personality = PER_LINUX32; + return 1; +} +__setup("fakeppc", set_fakeppc); + +asmlinkage int sys_uname(struct old_utsname * name) +{ + int err = -EFAULT; + + PPCDBG(PPCDBG_SYS64X, "sys_uname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + down_read(&uts_sem); + if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + err = 0; + up_read(&uts_sem); + + PPCDBG(PPCDBG_SYS64X, "sys_uname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return err; +} + +asmlinkage int sys_olduname(struct oldold_utsname * name) +{ + int error; + + PPCDBG(PPCDBG_SYS64X, "sys_olduname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + + if (!name) + return -EFAULT; + 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); + error -= __put_user(0,name->nodename+__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __put_user(0,name->release+__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __put_user(0,name->version+__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error = __put_user(0,name->machine+__OLD_UTS_LEN); + up_read(&uts_sem); + + error = error ? -EFAULT : 0; + + PPCDBG(PPCDBG_SYS64X, "sys_olduname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + return error; +} + +asmlinkage time_t sys64_time(time_t* tloc) +{ + time_t secs; + time_t usecs; + + long tb_delta = tb_ticks_since(tb_last_stamp); + tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; + + secs = xtime.tv_sec; + usecs = xtime.tv_usec + tb_delta / tb_ticks_per_usec; + while (usecs >= USEC_PER_SEC) { + ++secs; + usecs -= USEC_PER_SEC; + } + + if (tloc) { + if (put_user(secs,tloc)) + secs = -EFAULT; + } + + return secs; +} diff -urN linux-2.4.18/arch/ppc64/kernel/time.c linux-2.4.19-pre5/arch/ppc64/kernel/time.c --- linux-2.4.18/arch/ppc64/kernel/time.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/time.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,686 @@ +/* + * + * Common time routines among all ppc machines. + * + * Written by Cort Dougan (cort@cs.nmt.edu) to merge + * Paul Mackerras' version and mine for PReP and Pmac. + * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). + * Converted for 64-bit by Mike Corrigan (mikejc@us.ibm.com) + * + * First round of bugfixes by Gabriel Paubert (paubert@iram.es) + * to make clock more stable (2.4.0-test5). The only thing + * that this code assumes is that the timebases have been synchronized + * by firmware on SMP and are never stopped (never do sleep + * on SMP then, nap and doze are OK). + * + * Speeded up do_gettimeofday by getting rid of references to + * xtime (which required locks for consistency). (mikejc@us.ibm.com) + * + * TODO (not necessarily in this file): + * - improve precision and reproducibility of timebase frequency + * measurement at boot time. (for iSeries, we calibrate the timebase + * against the Titan chip's clock.) + * - for astronomical applications: add a new function to get + * non ambiguous timestamps even around leap seconds. This needs + * a new timestamp format and a good name. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC_ISERIES +#include +#endif +#include + +#include +#include + +void smp_local_timer_interrupt(struct pt_regs *); + +/* keep track of when we need to update the rtc */ +time_t last_rtc_update; +extern rwlock_t xtime_lock; +extern int piranha_simulator; +#ifdef CONFIG_PPC_ISERIES +unsigned long iSeries_recal_titan = 0; +unsigned long iSeries_recal_tb = 0; +static unsigned long first_settimeofday = 1; +#endif + +#define XSEC_PER_SEC (1024*1024) +#define USEC_PER_SEC (1000000) + +unsigned long tb_ticks_per_jiffy; +unsigned long tb_ticks_per_usec; +unsigned long tb_ticks_per_sec; +unsigned long next_xtime_sync_tb; +unsigned long xtime_sync_interval; +unsigned long tb_to_xs; +unsigned tb_to_us; +unsigned long processor_freq; +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +struct gettimeofday_struct do_gtod; + +extern unsigned long wall_jiffies; +extern unsigned long lpEvent_count; +extern int smp_tb_synchronized; + +extern unsigned long prof_cpu_mask; +extern unsigned int * prof_buffer; +extern unsigned long prof_len; +extern unsigned long prof_shift; +extern char _stext; + +static inline void ppc_do_profile (unsigned long nip) +{ + if (!prof_buffer) + return; + + /* + * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. + * (default is all CPUs.) + */ + if (!((1<>= prof_shift; + /* + * Don't ignore out-of-bounds EIP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (nip > prof_len-1) + nip = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[nip]); +} + + +static __inline__ void timer_check_rtc(void) +{ + /* + * update the rtc when needed, this should be performed on the + * right fraction of a second. Half or full second ? + * Full second works on mk48t59 clocks, others need testing. + * Note that this update is basically only used through + * the adjtimex system calls. Setting the HW clock in + * any other way is a /dev/rtc and userland business. + * This is still wrong by -0.5/+1.5 jiffies because of the + * timer interrupt resolution and possible delay, but here we + * hit a quantization limit which can only be solved by higher + * resolution timers and decoupling time management from timer + * interrupts. This is also wrong on the clocks + * which require being written at the half second boundary. + * We should have an rtc call that only sets the minutes and + * seconds like on Intel to avoid problems with non UTC clocks. + */ + if ( (time_status & STA_UNSYNC) == 0 && + xtime.tv_sec - last_rtc_update >= 659 && + abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && + jiffies - wall_jiffies == 1) { + struct rtc_time tm; + to_tm(xtime.tv_sec+1, &tm); + tm.tm_year -= 1900; + tm.tm_mon -= 1; + if (ppc_md.set_rtc_time(&tm) == 0) + last_rtc_update = xtime.tv_sec+1; + else + /* Try again one minute later */ + last_rtc_update += 60; + } +} + +/* Synchronize xtime with do_gettimeofday */ + +static __inline__ void timer_sync_xtime( unsigned long cur_tb ) +{ + struct timeval my_tv; + + if ( cur_tb > next_xtime_sync_tb ) { + next_xtime_sync_tb = cur_tb + xtime_sync_interval; + do_gettimeofday( &my_tv ); + if ( xtime.tv_sec <= my_tv.tv_sec ) { + xtime.tv_sec = my_tv.tv_sec; + xtime.tv_usec = my_tv.tv_usec; + } + } +} + +#ifdef CONFIG_PPC_ISERIES + +/* + * This function recalibrates the timebase based on the 49-bit time-of-day value in the Titan chip. + * The Titan is much more accurate than the value returned by the service processor for the + * timebase frequency. + */ + +static void iSeries_tb_recal(void) +{ + struct div_result divres; + unsigned long titan, tb; + tb = get_tb(); + titan = HvCallXm_loadTod(); + if ( iSeries_recal_titan ) { + unsigned long tb_ticks = tb - iSeries_recal_tb; + unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; + unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; + unsigned long new_tb_ticks_per_jiffy = (new_tb_ticks_per_sec+(HZ/2))/HZ; + long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; + char sign = '+'; + /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ + new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; + + if ( tick_diff < 0 ) { + tick_diff = -tick_diff; + sign = '-'; + } + if ( tick_diff ) { + if ( tick_diff < tb_ticks_per_jiffy/25 ) { + printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", + new_tb_ticks_per_jiffy, sign, tick_diff ); + tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; + tb_ticks_per_sec = new_tb_ticks_per_sec; + div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres ); + do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; + tb_to_xs = divres.result_low; + do_gtod.varp->tb_to_xs = tb_to_xs; + } + else { + printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" + " new tb_ticks_per_jiffy = %lu\n" + " old tb_ticks_per_jiffy = %lu\n", + new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); + } + } + } + iSeries_recal_titan = titan; + iSeries_recal_tb = tb; +} +#endif + +/* + * For iSeries shared processors, we have to let the hypervisor + * set the hardware decrementer. We set a virtual decrementer + * in the ItLpPaca and call the hypervisor if the virtual + * decrementer is less than the current value in the hardware + * decrementer. (almost always the new decrementer value will + * be greater than the current hardware decementer so the hypervisor + * call will not be needed) + */ + +unsigned long tb_last_stamp=0; + +/* + * timer_interrupt - gets called when the decrementer overflows, + * with interrupts disabled. + */ +int timer_interrupt(struct pt_regs * regs) +{ + int next_dec; + unsigned long cur_tb; + struct Paca * paca = (struct Paca *)mfspr(SPRG3); + unsigned long cpu = paca->xPacaIndex; + struct ItLpQueue * lpq; + + irq_enter(cpu); + +#ifndef CONFIG_PPC_ISERIES + if (!user_mode(regs)) + ppc_do_profile(instruction_pointer(regs)); +#endif + + paca->xLpPaca.xIntDword.xFields.xDecrInt = 0; + + while (paca->next_jiffy_update_tb <= (cur_tb = get_tb())) { + +#ifdef CONFIG_SMP + smp_local_timer_interrupt(regs); +#endif + if (cpu == 0) { + write_lock(&xtime_lock); + tb_last_stamp = paca->next_jiffy_update_tb; + do_timer(regs); + timer_sync_xtime( cur_tb ); + timer_check_rtc(); + write_unlock(&xtime_lock); + } + paca->next_jiffy_update_tb += tb_ticks_per_jiffy; + } + + next_dec = paca->next_jiffy_update_tb - cur_tb; + if (next_dec > paca->default_decr) + next_dec = paca->default_decr; + set_dec(next_dec); + + lpq = paca->lpQueuePtr; + if (lpq && ItLpQueue_isLpIntPending(lpq)) + lpEvent_count += ItLpQueue_process(lpq, regs); + + irq_exit(cpu); + + if (softirq_pending(cpu)) + do_softirq(); + + return 1; +} + + +/* + * This version of gettimeofday has microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long sec, usec, tb_ticks; + unsigned long xsec, tb_xsec; + struct gettimeofday_vars * temp_varp; + unsigned long temp_tb_to_xs, temp_stamp_xsec; + + /* These calculations are faster (gets rid of divides) + * if done in units of 1/2^20 rather than microseconds. + * The conversion to microseconds at the end is done + * without a divide (and in fact, without a multiply) */ + tb_ticks = get_tb() - do_gtod.tb_orig_stamp; + temp_varp = do_gtod.varp; + temp_tb_to_xs = temp_varp->tb_to_xs; + temp_stamp_xsec = temp_varp->stamp_xsec; + tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs ); + xsec = temp_stamp_xsec + tb_xsec; + sec = xsec / XSEC_PER_SEC; + xsec -= sec * XSEC_PER_SEC; + usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC; + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void do_settimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long delta_xsec; + long int tb_delta, new_usec, new_sec; + unsigned long new_xsec; + + write_lock_irqsave(&xtime_lock, flags); + /* Updating the RTC is not the job of this code. If the time is + * stepped under NTP, the RTC will be update after STA_UNSYNC + * is cleared. Tool like clock/hwclock either copy the RTC + * to the system time, in which case there is no point in writing + * to the RTC again, or write to the RTC but then they don't call + * settimeofday to perform this operation. + */ +#ifdef CONFIG_PPC_ISERIES + if ( first_settimeofday ) { + iSeries_tb_recal(); + first_settimeofday = 0; + } +#endif + tb_delta = tb_ticks_since(tb_last_stamp); + tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; + + new_sec = tv->tv_sec; + new_usec = tv->tv_usec - tb_delta / tb_ticks_per_usec; + while (new_usec <0) { + new_sec--; + new_usec += USEC_PER_SEC; + } + xtime.tv_usec = new_usec; + xtime.tv_sec = new_sec; + + /* In case of a large backwards jump in time with NTP, we want the + * clock to be updated as soon as the PLL is again in lock. + */ + last_rtc_update = new_sec - 658; + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + delta_xsec = mulhdu( (tb_last_stamp-do_gtod.tb_orig_stamp), do_gtod.varp->tb_to_xs ); + new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC; + new_xsec += new_sec * XSEC_PER_SEC; + if ( new_xsec > delta_xsec ) { + do_gtod.varp->stamp_xsec = new_xsec - delta_xsec; + } + else { + /* This is only for the case where the user is setting the time + * way back to a time such that the boot time would have been + * before 1970 ... eg. we booted ten days ago, and we are setting + * the time to Jan 5, 1970 */ + do_gtod.varp->stamp_xsec = new_xsec; + do_gtod.tb_orig_stamp = tb_last_stamp; + } + + write_unlock_irqrestore(&xtime_lock, flags); +} + +/* + * This function is a copy of the architecture independent function + * but which calls do_settimeofday rather than setting the xtime + * fields itself. This way, the fields which are used for + * do_settimeofday get updated too. + */ +long ppc64_sys32_stime(int* tptr) +{ + int value; + struct timeval myTimeval; + + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (get_user(value, tptr)) + return -EFAULT; + + myTimeval.tv_sec = value; + myTimeval.tv_usec = 0; + + do_settimeofday(&myTimeval); + + return 0; +} + +/* + * This function is a copy of the architecture independent function + * but which calls do_settimeofday rather than setting the xtime + * fields itself. This way, the fields which are used for + * do_settimeofday get updated too. + */ +long ppc64_sys_stime(long* tptr) +{ + long value; + struct timeval myTimeval; + + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (get_user(value, tptr)) + return -EFAULT; + + myTimeval.tv_sec = value; + myTimeval.tv_usec = 0; + + do_settimeofday(&myTimeval); + + return 0; +} + +void __init time_init(void) +{ + /* This function is only called on the boot processor */ + unsigned long flags; + struct rtc_time tm; + + ppc_md.calibrate_decr(); + + if ( ! piranha_simulator ) { + ppc_md.get_boot_time(&tm); + } + write_lock_irqsave(&xtime_lock, flags); + xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + tb_last_stamp = get_tb(); + do_gtod.tb_orig_stamp = tb_last_stamp; + do_gtod.varp = &do_gtod.vars[0]; + do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; + do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; + do_gtod.varp->tb_to_xs = tb_to_xs; + do_gtod.tb_to_us = tb_to_us; + + xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8); + next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval; + + xtime.tv_usec = 0; + last_rtc_update = xtime.tv_sec; + write_unlock_irqrestore(&xtime_lock, flags); + +#ifdef CONFIG_PPC_ISERIES + /* HACK HACK This allows the iSeries profiling to use /proc/profile */ + prof_shift = 0; +#endif + + /* Not exact, but the timer interrupt takes care of this */ + set_dec(tb_ticks_per_jiffy); +} + +/* + * After adjtimex is called, adjust the conversion of tb ticks + * to microseconds to keep do_gettimeofday synchronized + * with ntpd. + + * Use the time_freq and time_offset computed by adjtimex to + * adjust the frequency. +*/ + +void ppc_adjtimex(void) +{ + unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec; + unsigned long tb_ticks_per_sec_delta; + long delta_freq, ltemp; + struct div_result divres; + unsigned long flags; + struct gettimeofday_vars * temp_varp; + + if ( time_offset < 0 ) { + ltemp = -time_offset; + ltemp <<= SHIFT_USEC - SHIFT_UPDATE; + ltemp >>= SHIFT_KG + time_constant; + ltemp = -ltemp; + } + else { + ltemp = time_offset; + ltemp <<= SHIFT_USEC - SHIFT_UPDATE; + ltemp >>= SHIFT_KG + time_constant; + } + delta_freq = time_freq + ltemp; + + den = 1000000 * (1 << (SHIFT_USEC - 8)); + if ( delta_freq < 0 ) { + tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den; + new_tb_ticks_per_sec = tb_ticks_per_sec + tb_ticks_per_sec_delta; + } + else { + tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( delta_freq >> (SHIFT_USEC - 8))) / den; + new_tb_ticks_per_sec = tb_ticks_per_sec - tb_ticks_per_sec_delta; + } + tb_ticks = get_tb() - do_gtod.tb_orig_stamp; + div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres ); + new_tb_to_xs = divres.result_low; + new_xsec = mulhdu( tb_ticks, new_tb_to_xs ); + + write_lock_irqsave( &xtime_lock, flags ); + old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs ); + new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec; + + if (do_gtod.varp == &do_gtod.vars[0]) + temp_varp = &do_gtod.vars[1]; + else + temp_varp = &do_gtod.vars[0]; + temp_varp->tb_to_xs = new_tb_to_xs; + temp_varp->stamp_xsec = new_stamp_xsec; + mb(); + do_gtod.varp = temp_varp; + + write_unlock_irqrestore( &xtime_lock, flags ); + +} + + +#define TICK_SIZE tick +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +void GregorianDay(struct rtc_time * tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + lastYear=tm->tm_year-1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + */ + if((tm->tm_year%4==0) && + ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && + (tm->tm_mon>2)) + { + /* + * We are past Feb. 29 in a leap year + */ + day=1; + } + else + { + day=0; + } + + day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + + tm->tm_mday; + + tm->tm_wday=day%7; +} + +void to_tm(int tim, struct rtc_time * tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + GregorianDay(tm); +} + +/* Auxiliary function to compute scaling factors */ +/* Actually the choice of a timebase running at 1/4 the of the bus + * frequency giving resolution of a few tens of nanoseconds is quite nice. + * It makes this computation very precise (27-28 bits typically) which + * is optimistic considering the stability of most processor clock + * oscillators and the precision with which the timebase frequency + * is measured but does not harm. + */ +unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { + unsigned mlt=0, tmp, err; + /* No concern for performance, it's done once: use a stupid + * but safe and compact method to find the multiplier. + */ + + for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { + if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; + } + + /* We might still be off by 1 for the best approximation. + * A side effect of this is that if outscale is too large + * the returned value will be zero. + * Many corner cases have been checked and seem to work, + * some might have been forgotten in the test however. + */ + + err = inscale*(mlt+1); + if (err <= inscale/2) mlt++; + return mlt; + } + +/* + * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit + * result. + */ + +void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, + unsigned divisor, struct div_result *dr ) +{ + unsigned long a,b,c,d, w,x,y,z, ra,rb,rc; + + a = dividend_high >> 32; + b = dividend_high & 0xffffffff; + c = dividend_low >> 32; + d = dividend_low & 0xffffffff; + + w = a/divisor; + ra = (a - (w * divisor)) << 32; + + x = (ra + b)/divisor; + rb = ((ra + b) - (x * divisor)) << 32; + + y = (rb + c)/divisor; + rc = ((rb + b) - (y * divisor)) << 32; + + z = (rc + d)/divisor; + + dr->result_high = (w << 32) + x; + dr->result_low = (y << 32) + z; + +} + diff -urN linux-2.4.18/arch/ppc64/kernel/traps.c linux-2.4.19-pre5/arch/ppc64/kernel/traps.c --- linux-2.4.18/arch/ppc64/kernel/traps.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/traps.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,257 @@ +/* + * linux/arch/ppc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KDB +#include +#endif + +#include +#include +#include +#include +#include +#include + +extern int fix_alignment(struct pt_regs *); +extern void bad_page_fault(struct pt_regs *, unsigned long); + +#ifdef CONFIG_XMON +extern void xmon(struct pt_regs *regs); +extern int xmon_bpt(struct pt_regs *regs); +extern int xmon_sstep(struct pt_regs *regs); +extern int xmon_iabr_match(struct pt_regs *regs); +extern int xmon_dabr_match(struct pt_regs *regs); +extern void (*xmon_fault_handler)(struct pt_regs *regs); +#endif + +#ifdef CONFIG_XMON +void (*debugger)(struct pt_regs *regs) = xmon; +int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; +int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; +int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match; +int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match; +void (*debugger_fault_handler)(struct pt_regs *regs); +#else +#ifdef CONFIG_KGDB +void (*debugger)(struct pt_regs *regs); +int (*debugger_bpt)(struct pt_regs *regs); +int (*debugger_sstep)(struct pt_regs *regs); +int (*debugger_iabr_match)(struct pt_regs *regs); +int (*debugger_dabr_match)(struct pt_regs *regs); +void (*debugger_fault_handler)(struct pt_regs *regs); +#endif +#endif +/* + * Trap & Exception support + */ + +void +_exception(int signr, struct pt_regs *regs) +{ + if (!user_mode(regs)) + { + show_regs(regs); +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + debugger(regs); +#endif +#if defined(CONFIG_KDB) + kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs); +#endif + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Exception in kernel pc %lx signal %d",regs->nip,signr); +#if defined(CONFIG_PPCDBG) && (defined(CONFIG_XMON) || defined(CONFIG_KGDB)) + /* Allow us to catch SIGILLs for 64-bit app/glibc debugging. -Peter */ + } else if (signr == SIGILL) { + ifppcdebug(PPCDBG_SIGNALXMON) + debugger(regs); +#endif + } + force_sig(signr, current); +} + +void +SystemResetException(struct pt_regs *regs) +{ + udbg_printf("System Reset in kernel mode.\n"); + printk("System Reset in kernel mode.\n"); +#if defined(CONFIG_XMON) + xmon(regs); +#endif + for(;;); +} + + +void +MachineCheckException(struct pt_regs *regs) +{ + if ( !user_mode(regs) ) + { +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_fault_handler) { + debugger_fault_handler(regs); + return; + } +#endif +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_FAULT, 0, regs)) + return; +#endif + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", regs->msr); + show_regs(regs); +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + debugger(regs); +#endif +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_FAULT, 0, regs)) + return ; +#endif + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); + } + _exception(SIGSEGV, regs); +} + +void +SMIException(struct pt_regs *regs) +{ +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + { + debugger(regs); + return; + } +#endif +#ifdef CONFIG_KDB + { + kdb(KDB_REASON_OOPS, 0, regs); + return; + } +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("System Management Interrupt"); +} + +void +UnknownException(struct pt_regs *regs) +{ + printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception(SIGTRAP, regs); +} + +void +InstructionBreakpointException(struct pt_regs *regs) +{ +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_iabr_match(regs)) + return; +#endif +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_BREAK, 0, regs)) + return ; +#endif + _exception(SIGTRAP, regs); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ + if (regs->msr & 0x100000) { + /* IEEE FP exception */ + _exception(SIGFPE, regs); + } else if (regs->msr & 0x20000) { + /* trap exception */ +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_bpt(regs)) + return; +#endif +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_BREAK, 0, regs)) + return; +#endif + _exception(SIGTRAP, regs); + } else { + _exception(SIGILL, regs); + } +} + +void +SingleStepException(struct pt_regs *regs) +{ + regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_sstep(regs)) + return; +#endif +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_DEBUG, 0, regs)) + return; +#endif + _exception(SIGTRAP, regs); +} + +/* Dummy handler for Performance Monitor */ + +void +PerformanceMonitorException(struct pt_regs *regs) +{ + _exception(SIGTRAP, regs); +} + +void +AlignmentException(struct pt_regs *regs) +{ + int fixed; + + fixed = fix_alignment(regs); + if (fixed == 1) { + ifppcdebug(PPCDBG_ALIGNFIXUP) + if (!user_mode(regs)) + PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lx\n", regs->nip); + regs->nip += 4; /* skip over emulated instruction */ + return; + } + if (fixed == -EFAULT) { + /* fixed == -EFAULT means the operand address was bad */ + if (user_mode(regs)) + force_sig(SIGSEGV, current); + else + bad_page_fault(regs, regs->dar); + return; + } + _exception(SIGBUS, regs); +} + +void __init trap_init(void) +{ +} diff -urN linux-2.4.18/arch/ppc64/kernel/udbg.c linux-2.4.19-pre5/arch/ppc64/kernel/udbg.c --- linux-2.4.18/arch/ppc64/kernel/udbg.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/udbg.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,253 @@ +/* + * NS16550 Serial Port (uart) debugging stuff. + * + * c 2001 PPC 64 Team, IBM Corp + * + * NOTE: I am trying to make this code avoid any static data references to + * simplify debugging early boot. We'll see how that goes... + * + * To use this call udbg_init() first. It will init the uart to 9600 8N1. + * You may need to update the COM1 define if your uart is at a different addr. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#define WANT_PPCDBG_TAB /* Only defined here */ +#include +#include +#include +#include +#include + +extern struct Naca *naca; +extern int _machine; + +struct NS16550 { + /* this struct must be packed */ + unsigned char rbr; /* 0 */ + unsigned char ier; /* 1 */ + unsigned char fcr; /* 2 */ + unsigned char lcr; /* 3 */ + unsigned char mcr; /* 4 */ + unsigned char lsr; /* 5 */ + unsigned char msr; /* 6 */ + unsigned char scr; /* 7 */ +}; + +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier +#define dlab lcr + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +volatile struct NS16550 *udbg_comport; + +spinlock_t udbg_lock = SPIN_LOCK_UNLOCKED; + +void +udbg_init_uart(void *comport) +{ + if (comport) { + udbg_comport = (struct NS16550 *)comport; + udbg_comport->lcr = 0x00; eieio(); + udbg_comport->ier = 0xFF; eieio(); + udbg_comport->ier = 0x00; eieio(); + udbg_comport->lcr = 0x80; eieio(); /* Access baud rate */ + udbg_comport->dll = 12; eieio(); /* 1 = 115200, 2 = 57600, 3 = 38400, 12 = 9600 baud */ + udbg_comport->dlm = 0; eieio(); /* dll >> 8 which should be zero for fast rates; */ + udbg_comport->lcr = 0x03; eieio(); /* 8 data, 1 stop, no parity */ + udbg_comport->mcr = 0x03; eieio(); /* RTS/DTR */ + udbg_comport->fcr = 0x07; eieio(); /* Clear & enable FIFOs */ + } +} + +void +udbg_putc(unsigned char c) +{ + if ( udbg_comport ) { + while ((udbg_comport->lsr & LSR_THRE) == 0) + /* wait for idle */; + udbg_comport->thr = c; eieio(); + if (c == '\n') { + /* Also put a CR. This is for convenience. */ + while ((udbg_comport->lsr & LSR_THRE) == 0) + /* wait for idle */; + udbg_comport->thr = '\r'; eieio(); + } + } else if ( _machine == _MACH_iSeries ) { + /* ToDo: switch this via ppc_md */ + printk("%c", c); + } +} + +int udbg_getc_poll(void) +{ + if (udbg_comport) { + if ((udbg_comport->lsr & LSR_DR) != 0) + return udbg_comport->rbr; + else + return -1; + } + return -1; +} + +unsigned char +udbg_getc(void) +{ + if ( udbg_comport ) { + while ((udbg_comport->lsr & LSR_DR) == 0) + /* wait for char */; + return udbg_comport->rbr; + } + return 0; +} + +void +udbg_puts(const char *s) +{ + if (ppc_md.udbg_putc) { + char c; + + if (s && *s != '\0') { + while ((c = *s++) != '\0') + ppc_md.udbg_putc(c); + } else { + udbg_puts("NULL"); + } + } else { + printk("%s", s); + } +} + +int +udbg_write(const char *s, int n) +{ + int remain = n; + char c; + if (!ppc_md.udbg_putc) + for (;;); /* stop here for cpuctl */ + if ( s && *s != '\0' ) { + while ( (( c = *s++ ) != '\0') && (remain-- > 0)) { + ppc_md.udbg_putc(c); + } + } else + udbg_puts("NULL"); + return n - remain; +} + +int +udbg_read(char *buf, int buflen) { + char c, *p = buf; + int i; + if (!ppc_md.udbg_putc) + for (;;); /* stop here for cpuctl */ + for (i = 0; i < buflen; ++i) { + do { + c = ppc_md.udbg_getc(); + } while (c == 0x11 || c == 0x13); + *p++ = c; + } + return i; +} + +void +udbg_puthex(unsigned long val) +{ + int i, nibbles = sizeof(val)*2; + unsigned char buf[sizeof(val)*2+1]; + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + udbg_puts(buf); +} + +void +udbg_printSP(const char *s) +{ + if (_machine == _MACH_pSeries) { + unsigned long sp; + asm("mr %0,1" : "=r" (sp) :); + if (s) + udbg_puts(s); + udbg_puthex(sp); + } +} + +void +udbg_printf(const char *fmt, ...) +{ + unsigned long flags; + unsigned char buf[256]; + + va_list args; + va_start(args, fmt); + + spin_lock_irqsave(&udbg_lock, flags); + vsprintf(buf, fmt, args); + udbg_puts(buf); + spin_unlock_irqrestore(&udbg_lock, flags); + + va_end(args); +} + +/* Special print used by PPCDBG() macro */ +void +udbg_ppcdbg(unsigned long flags, const char *fmt, ...) +{ + unsigned long flags; + unsigned long active_debugs = flags & naca->debug_switch; + + if ( active_debugs ) { + va_list ap; + unsigned char buf[256]; + unsigned long i, len = 0; + + spin_lock_irqsave(&udbg_lock, flags); + for(i=0; i < PPCDBG_NUM_FLAGS ;i++) { + if (((1U << i) & active_debugs) && + trace_names[i]) { + len += strlen(trace_names[i]); + udbg_puts(trace_names[i]); + break; + } + } + sprintf(buf, " [%s]: ", current->comm); + len += strlen(buf); + udbg_puts(buf); + + while(len < 18) { + udbg_puts(" "); + len++; + } + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + udbg_puts(buf); + spin_unlock_irqrestore(&udbg_lock, flags); + + va_end(ap); + } +} + +unsigned long +udbg_ifdebug(unsigned long flags) +{ + return (flags & naca->debug_switch); +} diff -urN linux-2.4.18/arch/ppc64/kernel/xics.c linux-2.4.19-pre5/arch/ppc64/kernel/xics.c --- linux-2.4.18/arch/ppc64/kernel/xics.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/xics.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,467 @@ +/* + * arch/ppc/kernel/xics.c + * + * Copyright 2000 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i8259.h" +#include "xics.h" +#include + +extern struct Naca *naca; + +void xics_enable_irq(u_int irq); +void xics_disable_irq(u_int irq); +void xics_mask_and_ack_irq(u_int irq); +void xics_end_irq(u_int irq); +void xics_set_affinity(unsigned int irq_nr, unsigned long cpumask); + +struct hw_interrupt_type xics_pic = { + " XICS ", + NULL, + NULL, + xics_enable_irq, + xics_disable_irq, + xics_mask_and_ack_irq, + xics_end_irq, + xics_set_affinity +}; + +struct hw_interrupt_type xics_8259_pic = { + " XICS/8259", + NULL, + NULL, + NULL, + NULL, + xics_mask_and_ack_irq, + NULL +}; + +#define XICS_IPI 2 +#define XICS_IRQ_OFFSET 0x10 +#define XICS_IRQ_SPURIOUS 0 + +/* Want a priority other than 0. Various HW issues require this. */ +#define DEFAULT_PRIORITY 5 + +struct xics_ipl { + union { + u32 word; + u8 bytes[4]; + } xirr_poll; + union { + u32 word; + u8 bytes[4]; + } xirr; + u32 dummy; + union { + u32 word; + u8 bytes[4]; + } qirr; +}; + +struct xics_info { + volatile struct xics_ipl * per_cpu[NR_CPUS]; +}; + +struct xics_info xics_info; + +unsigned long long intr_base = 0; +int xics_irq_8259_cascade = 0; +int xics_irq_8259_cascade_real = 0; +unsigned int default_server = 0xFF; +unsigned int default_distrib_server = 0; + +/* RTAS service tokens */ +int ibm_get_xive; +int ibm_set_xive; +int ibm_int_off; + +struct xics_interrupt_node { + unsigned long long addr; + unsigned long long size; +} inodes[NR_CPUS*2]; + +typedef struct { + int (*xirr_info_get)(int cpu); + void (*xirr_info_set)(int cpu, int val); + void (*cppr_info)(int cpu, u8 val); + void (*qirr_info)(int cpu, u8 val); +} xics_ops; + + +static int pSeries_xirr_info_get(int n_cpu) +{ + return (xics_info.per_cpu[n_cpu]->xirr.word); +} + +static void pSeries_xirr_info_set(int n_cpu, int value) +{ + xics_info.per_cpu[n_cpu]->xirr.word = value; +} + +static void pSeries_cppr_info(int n_cpu, u8 value) +{ + xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value; +} + +static void pSeries_qirr_info(int n_cpu , u8 value) +{ + xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value; +} + +static xics_ops pSeries_ops = { + pSeries_xirr_info_get, + pSeries_xirr_info_set, + pSeries_cppr_info, + pSeries_qirr_info +}; + +static xics_ops *ops = &pSeries_ops; +extern xics_ops pSeriesLP_ops; + + +void +xics_enable_irq( + u_int virq + ) +{ + u_int irq; + unsigned long status; + long call_status; + + virq -= XICS_IRQ_OFFSET; + irq = virt_irq_to_real(virq); + if (irq == XICS_IPI) + return; +#ifdef CONFIG_IRQ_ALL_CPUS + call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status, + irq, smp_threads_ready ? default_distrib_server : default_server, DEFAULT_PRIORITY); +#else + call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status, + irq, default_server, DEFAULT_PRIORITY); +#endif + if( call_status != 0 ) { + printk("xics_enable_irq: irq=%x: rtas_call failed; retn=%lx, status=%lx\n", + irq, call_status, status); + return; + } +} + +void +xics_disable_irq( + u_int virq + ) +{ + u_int irq; + unsigned long status; + long call_status; + + virq -= XICS_IRQ_OFFSET; + irq = virt_irq_to_real(virq); + call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, + irq); + if( call_status != 0 ) { + printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n", + irq, call_status); + return; + } +} + +void +xics_end_irq( + u_int irq + ) +{ + int cpu = smp_processor_id(); + + ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */ + iosync(); + ops->xirr_info_set(cpu, ((0xff<<24) | (virt_irq_to_real(irq-XICS_IRQ_OFFSET)))); + iosync(); +} + +void +xics_mask_and_ack_irq(u_int irq) +{ + int cpu = smp_processor_id(); + + if( irq < XICS_IRQ_OFFSET ) { + i8259_pic.ack(irq); + iosync(); + ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade_real)); + iosync(); + } + else { + ops->cppr_info(cpu, 0xff); + iosync(); + } +} + +int +xics_get_irq(struct pt_regs *regs) +{ + u_int cpu = smp_processor_id(); + u_int vec; + int irq; + + vec = ops->xirr_info_get(cpu); + /* (vec >> 24) == old priority */ + vec &= 0x00ffffff; + /* for sanity, this had better be < NR_IRQS - 16 */ + if( vec == xics_irq_8259_cascade_real ) { + irq = i8259_irq(cpu); + if(irq == -1) { + /* Spurious cascaded interrupt. Still must ack xics */ + xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade); + irq = -1; + } + } else if( vec == XICS_IRQ_SPURIOUS ) { + irq = -1; + printk("spurious PPC interrupt!\n"); + } else + irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET; + return irq; +} + + +#ifdef CONFIG_SMP +void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +{ + extern volatile unsigned long xics_ipi_message[]; + int cpu = smp_processor_id(); + + ops->qirr_info(cpu, 0xff); + while (xics_ipi_message[cpu]) { + if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu])) { + mb(); + smp_message_recv(PPC_MSG_CALL_FUNCTION, regs); + } + if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu])) { + mb(); + smp_message_recv(PPC_MSG_RESCHEDULE, regs); + } + } +} + +void xics_cause_IPI(int cpu) +{ + ops->qirr_info(cpu,0) ; +} + +void xics_setup_cpu(void) +{ + int cpu = smp_processor_id(); + + ops->cppr_info(cpu, 0xff); + iosync(); +} +#endif /* CONFIG_SMP */ + +void +xics_init_IRQ( void ) +{ + int i; + unsigned long intr_size = 0; + struct device_node *np; + uint *ireg, ilen, indx=0; + + ibm_get_xive = rtas_token("ibm,get-xive"); + ibm_set_xive = rtas_token("ibm,set-xive"); + ibm_int_off = rtas_token("ibm,int-off"); + + np = find_type_devices("PowerPC-External-Interrupt-Presentation"); + if (!np) { + printk(KERN_WARNING "Can't find Interrupt Presentation\n"); + udbg_printf("Can't find Interrupt Presentation\n"); + while (1); + } +nextnode: + ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0); + if (ireg) { + /* + * set node starting index for this node + */ + indx = *ireg; + } + + ireg = (uint *)get_property(np, "reg", &ilen); + if (!ireg) { + printk(KERN_WARNING "Can't find Interrupt Reg Property\n"); + udbg_printf("Can't find Interrupt Reg Property\n"); + while (1); + } + + while (ilen) { + inodes[indx].addr = (unsigned long long)*ireg++ << 32; + ilen -= sizeof(uint); + inodes[indx].addr |= *ireg++; + ilen -= sizeof(uint); + inodes[indx].size = (unsigned long long)*ireg++ << 32; + ilen -= sizeof(uint); + inodes[indx].size |= *ireg++; + ilen -= sizeof(uint); + indx++; + if (indx >= NR_CPUS) break; + } + + np = np->next; + if ((indx < NR_CPUS) && np) goto nextnode; + + /* Find the server numbers for the boot cpu. */ + for (np = find_type_devices("cpu"); np; np = np->next) { + ireg = (uint *)get_property(np, "reg", &ilen); + if (ireg && ireg[0] == hard_smp_processor_id()) { + ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + i = ilen / sizeof(int); + if (ireg && i > 0) { + default_server = ireg[0]; + default_distrib_server = ireg[i-1]; /* take last element */ + } + break; + } + } + + intr_base = inodes[0].addr; + intr_size = (ulong)inodes[0].size; + + np = find_type_devices("interrupt-controller"); + if (!np) { + printk(KERN_WARNING "xics: no ISA Interrupt Controller\n"); + xics_irq_8259_cascade = -1; + } else { + ireg = (uint *) get_property(np, "interrupts", 0); + if (!ireg) { + printk(KERN_WARNING "Can't find ISA Interrupts Property\n"); + udbg_printf("Can't find ISA Interrupts Property\n"); + while (1); + } + xics_irq_8259_cascade_real = *ireg; + xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real); + } + + if (_machine == _MACH_pSeries) { +#ifdef CONFIG_SMP + for (i = 0; i < naca->processorCount; ++i) { + xics_info.per_cpu[i] = + __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, + (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE); + } +#else + xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE); +#endif /* CONFIG_SMP */ +#ifdef CONFIG_PPC_PSERIES + /* actually iSeries does not use any of xics...but it has link dependencies + * for now, except this new one... + */ + } else if (_machine == _MACH_pSeriesLP) { + ops = &pSeriesLP_ops; +#endif + } + + xics_8259_pic.enable = i8259_pic.enable; + xics_8259_pic.disable = i8259_pic.disable; + for (i = 0; i < 16; ++i) + irq_desc[i].handler = &xics_8259_pic; + for (; i < NR_IRQS; ++i) + irq_desc[i].handler = &xics_pic; + + ops->cppr_info(0, 0xff); + iosync(); + if (xics_irq_8259_cascade != -1) { + if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action, + 0, "8259 cascade", 0)) + printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); + i8259_init(); + } + +#ifdef CONFIG_SMP + real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] = XICS_IPI; + request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0); + irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU; +#endif +} + +void xics_isa_init(void) +{ + return; + if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action, + 0, "8259 cascade", 0)) + printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); + i8259_init(); +} + +/* + * Find first logical cpu and return its physical cpu number + */ +static inline u32 physmask(u32 cpumask) +{ + int i; + + for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1) { + if (cpumask & 1) + return get_hard_smp_processor_id(i); + } + + printk(KERN_ERR "xics_set_affinity: invalid irq mask\n"); + + return default_distrib_server; +} + +void xics_set_affinity(unsigned int virq, unsigned long cpumask) +{ + irq_desc_t *desc = irq_desc + virq; + unsigned int irq; + unsigned long flags; + long status; + unsigned long xics_status[2]; + u32 newmask; + + virq -= XICS_IRQ_OFFSET; + irq = virt_irq_to_real(virq); + if (irq == XICS_IPI) + return; + + spin_lock_irqsave(&desc->lock, flags); + + status = rtas_call(ibm_get_xive, 1, 3, (void *)&xics_status, irq); + + if (status) { + printk("xics_set_affinity: irq=%d ibm,get-xive returns %ld\n", + irq, status); + goto out; + } + + /* For the moment only implement delivery to all cpus or one cpu */ + if (cpumask == 0xffffffff) + newmask = default_distrib_server; + else + newmask = physmask(cpumask); + + status = rtas_call(ibm_set_xive, 3, 1, NULL, + irq, newmask, xics_status[1]); + + if (status) { + printk("xics_set_affinity irq=%d ibm,set-xive returns %ld\n", + irq, status); + goto out; + } + +out: + spin_unlock_irqrestore(&desc->lock, flags); +} diff -urN linux-2.4.18/arch/ppc64/kernel/xics.h linux-2.4.19-pre5/arch/ppc64/kernel/xics.h --- linux-2.4.18/arch/ppc64/kernel/xics.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/kernel/xics.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,24 @@ +/* + * arch/ppc/kernel/xics.h + * + * Copyright 2000 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PPC_KERNEL_XICS_H +#define _PPC_KERNEL_XICS_H + +#include "local_irq.h" + +extern struct hw_interrupt_type xics_pic; +extern struct hw_interrupt_type xics_8259_pic; + +void xics_init_IRQ(void); +int xics_get_irq(struct pt_regs *); +void xics_isa_init(void); + +#endif /* _PPC_KERNEL_XICS_H */ diff -urN linux-2.4.18/arch/ppc64/lib/Makefile linux-2.4.19-pre5/arch/ppc64/lib/Makefile --- linux-2.4.18/arch/ppc64/lib/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/lib/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,11 @@ +# +# Makefile for ppc64-specific library files.. +# + +USE_STANDARD_AS_RULE := true + +O_TARGET = lib.o + +obj-y := checksum.o dec_and_lock.o string.o strcase.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc64/lib/checksum.S linux-2.4.19-pre5/arch/ppc64/lib/checksum.S --- linux-2.4.18/arch/ppc64/lib/checksum.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/lib/checksum.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,231 @@ +/* + * This file contains assembly-language implementations + * of IP-style 1's complement checksum routines. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). + */ + +#include +#include +#include +#include "../kernel/ppc_asm.tmpl" + + .text + +/* + * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header + * len is in words and is always >= 5. + * + * In practice len == 5, but this is not guaranteed. So this code does not + * attempt to use doubleword instructions. + */ +_GLOBAL(ip_fast_csum) + lwz r0,0(r3) + lwzu r5,4(r3) + addic. r4,r4,-2 + addc r0,r0,r5 + mtctr r4 + blelr- +1: lwzu r4,4(r3) + adde r0,r0,r4 + bdnz 1b + addze r0,r0 /* add in final carry */ + rldicl r4,r0,32,0 /* fold two 32-bit halves together */ + add r0,r0,r4 + srdi r0,r0,32 + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * Compute checksum of TCP or UDP pseudo-header: + * csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum) + * No real gain trying to do this specially for 64 bit, but + * the 32 bit addition may spill into the upper bits of + * the doubleword so we still must fold it down from 64. + */ +_GLOBAL(csum_tcpudp_magic) + rlwimi r5,r6,16,0,15 /* put proto in upper half of len */ + addc r0,r3,r4 /* add 4 32-bit words together */ + adde r0,r0,r5 + adde r0,r0,r7 + rldicl r4,r0,32,0 /* fold 64 bit value */ + add r0,r4,r0 + srdi r0,r0,32 + rlwinm r3,r0,16,0,31 /* fold two halves together */ + add r3,r0,r3 + not r3,r3 + srwi r3,r3,16 + blr + +/* + * Computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit). + * + * This code assumes at least halfword alignment, though the length + * can be any number of bytes. The sum is accumulated in r5. + * + * csum_partial(r3=buff, r4=len, r5=sum) + */ +_GLOBAL(csum_partial) + subi r3,r3,8 /* we'll offset by 8 for the loads */ + srdi. r6,r4,3 /* divide by 8 for doubleword count */ + addic r5,r5,0 /* clear carry */ + beq 3f /* if we're doing < 8 bytes */ + andi. r0,r3,2 /* aligned on a word boundary already? */ + beq+ 1f + lhz r6,8(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r4,r4,2 + addc r5,r5,r6 + srdi. r6,r4,3 /* recompute number of doublewords */ + beq 3f /* any left? */ +1: mtctr r6 +2: ldu r6,8(r3) /* main sum loop */ + adde r5,r5,r6 + bdnz 2b + andi. r4,r4,7 /* compute bytes left to sum after doublewords */ +3: cmpi 0,r4,4 /* is at least a full word left? */ + blt 4f + lwz r6,8(r3) /* sum this word */ + addi r3,r3,4 + subi r4,r4,4 + adde r5,r5,r6 +4: cmpi 0,r4,2 /* is at least a halfword left? */ + blt+ 5f + lhz r6,8(r3) /* sum this halfword */ + addi r3,r3,2 + subi r4,r4,2 + adde r5,r5,r6 +5: cmpi 0,r4,1 /* is at least a byte left? */ + bne+ 6f + lbz r6,8(r3) /* sum this byte */ + slwi r6,r6,8 /* this byte is assumed to be the upper byte of a halfword */ + adde r5,r5,r6 +6: addze r5,r5 /* add in final carry */ + rldicl r4,r5,32,0 /* fold two 32-bit halves together */ + add r3,r4,r5 + srdi r3,r3,32 + blr + +/* + * Computes the checksum of a memory block at src, length len, + * and adds in "sum" (32-bit), while copying the block to dst. + * If an access exception occurs on src or dst, it stores -EFAULT + * to *src_err or *dst_err respectively, and (for an error on + * src) zeroes the rest of dst. + * + * This code needs to be reworked to take advantage of 64 bit sum+copy. + * However, due to tokenring halfword alignment problems this will be very + * tricky. For now we'll leave it until we instrument it somehow. + * + * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err) + */ +_GLOBAL(csum_partial_copy_generic) + addic r0,r6,0 + subi r3,r3,4 + subi r4,r4,4 + srwi. r6,r5,2 + beq 3f /* if we're doing < 4 bytes */ + andi. r9,r4,2 /* Align dst to longword boundary */ + beq+ 1f +81: lhz r6,4(r3) /* do 2 bytes to get aligned */ + addi r3,r3,2 + subi r5,r5,2 +91: sth r6,4(r4) + addi r4,r4,2 + addc r0,r0,r6 + srwi. r6,r5,2 /* # words to do */ + beq 3f +1: mtctr r6 +82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */ +92: stwu r6,4(r4) /* be unnecessary to unroll this loop */ + adde r0,r0,r6 + bdnz 82b + andi. r5,r5,3 +3: cmpi 0,r5,2 + blt+ 4f +83: lhz r6,4(r3) + addi r3,r3,2 + subi r5,r5,2 +93: sth r6,4(r4) + addi r4,r4,2 + adde r0,r0,r6 +4: cmpi 0,r5,1 + bne+ 5f +84: lbz r6,4(r3) +94: stb r6,4(r4) + slwi r6,r6,8 /* Upper byte of word */ + adde r0,r0,r6 +5: addze r3,r0 /* add in final carry (unlikely with 64-bit regs) */ + rldicl r4,r3,32,0 /* fold 64 bit value */ + add r3,r4,r3 + srdi r3,r3,32 + blr + +/* These shouldn't go in the fixup section, since that would + cause the ex_table addresses to get out of order. */ + + .globl src_error_1 +src_error_1: + li r6,0 + subi r5,r5,2 +95: sth r6,4(r4) + addi r4,r4,2 + srwi. r6,r5,2 + beq 3f + mtctr r6 + .globl src_error_2 +src_error_2: + li r6,0 +96: stwu r6,4(r4) + bdnz 96b +3: andi. r5,r5,3 + beq src_error + .globl src_error_3 +src_error_3: + li r6,0 + mtctr r5 + addi r4,r4,3 +97: stbu r6,1(r4) + bdnz 97b + .globl src_error +src_error: + cmpi 0,r7,0 + beq 1f + li r6,-EFAULT + stw r6,0(r7) +1: addze r3,r0 + blr + + .globl dst_error +dst_error: + cmpi 0,r8,0 + beq 1f + li r6,-EFAULT + stw r6,0(r8) +1: addze r3,r0 + blr + +.section __ex_table,"a" + .align 3 + .llong 81b,src_error_1 + .llong 91b,dst_error + .llong 82b,src_error_2 + .llong 92b,dst_error + .llong 83b,src_error_3 + .llong 93b,dst_error + .llong 84b,src_error_3 + .llong 94b,dst_error + .llong 95b,dst_error + .llong 96b,dst_error + .llong 97b,dst_error diff -urN linux-2.4.18/arch/ppc64/lib/dec_and_lock.c linux-2.4.19-pre5/arch/ppc64/lib/dec_and_lock.c --- linux-2.4.18/arch/ppc64/lib/dec_and_lock.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/lib/dec_and_lock.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,38 @@ +/* + * ppc64 version of atomic_dec_and_lock() using cmpxchg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + int counter; + int newcount; + +repeat: + counter = atomic_read(atomic); + newcount = counter-1; + + if (!newcount) + goto slow_path; + + newcount = cmpxchg(&atomic->counter, counter, newcount); + + if (newcount != counter) + goto repeat; + return 0; + +slow_path: + spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + spin_unlock(lock); + return 0; +} diff -urN linux-2.4.18/arch/ppc64/lib/strcase.c linux-2.4.19-pre5/arch/ppc64/lib/strcase.c --- linux-2.4.18/arch/ppc64/lib/strcase.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/lib/strcase.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,31 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include + +int strcasecmp(const char *s1, const char *s2) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 == c2 && c1 != 0); + return c1 - c2; +} + +int strncasecmp(const char *s1, const char *s2, int n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} diff -urN linux-2.4.18/arch/ppc64/lib/string.S linux-2.4.19-pre5/arch/ppc64/lib/string.S --- linux-2.4.18/arch/ppc64/lib/string.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/lib/string.S Sat Mar 30 22:55:39 2002 @@ -0,0 +1,660 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "../kernel/ppc_asm.tmpl" +#include +#include + +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 3; \ + .llong 8 ## n ## 0b,9 ## n ## 0b; \ + .llong 8 ## n ## 1b,9 ## n ## 0b; \ + .llong 8 ## n ## 2b,9 ## n ## 0b; \ + .llong 8 ## n ## 3b,9 ## n ## 0b; \ + .llong 8 ## n ## 4b,9 ## n ## 1b; \ + .llong 8 ## n ## 5b,9 ## n ## 1b; \ + .llong 8 ## n ## 6b,9 ## n ## 1b; \ + .llong 8 ## n ## 7b,9 ## n ## 1b; \ +.text + +CACHELINE_BYTES = CACHE_LINE_SIZE +LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE +CACHELINE_MASK = (CACHE_LINE_SIZE-1) + +_GLOBAL(strcpy) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + +_GLOBAL(strncpy) + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + blr + +_GLOBAL(strcat) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + +_GLOBAL(strcmp) + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + +_GLOBAL(strlen) + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + +/* + * Use dcbz on the complete cache lines in the destination + * to set them to zero. This requires that the destination + * area is cacheable. -- paulus + */ +_GLOBAL(cacheable_memzero) + mr r5,r4 + li r4,0 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + clrlwi r7,r6,32-LG_CACHELINE_BYTES + add r8,r7,r5 + srwi r9,r8,LG_CACHELINE_BYTES + addic. r9,r9,-1 /* total number of complete cachelines */ + ble 2f + xori r0,r7,CACHELINE_MASK & ~3 + srwi. r0,r0,2 + beq 3f + mtctr r0 +4: stwu r4,4(r6) + bdnz 4b +3: mtctr r9 + li r7,4 +10: dcbz r7,r6 + addi r6,r6,CACHELINE_BYTES + bdnz 10b + clrlwi r5,r8,32-LG_CACHELINE_BYTES + addi r5,r5,4 +2: srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + +_GLOBAL(memset) + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + +_GLOBAL(bcopy) + mr r6,r3 + mr r3,r4 + mr r4,r6 + b .memcpy + +/* + * This version uses dcbz on the complete cache lines in the + * destination area to reduce memory traffic. This requires that + * the destination area is cacheable. + * We only use this version if the source and dest don't overlap. + * -- paulus. + */ +_GLOBAL(cacheable_memcpy) + add r7,r3,r5 /* test if the src & dst overlap */ + add r8,r4,r5 + cmplw 0,r4,r7 + cmplw 1,r3,r8 + crand 0,0,4 /* cr0.lt &= cr1.lt */ + blt .memcpy /* if regions overlap */ + + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + subf r5,r0,r5 + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ + stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ + stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: + dcbz r11,r6 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) + stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) + stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: blr + +_GLOBAL(memmove) + cmplw 0,r3,r4 + bgt .backwards_memcpy + /* fall through */ + +_GLOBAL(memcpy) + srwi. r7,r5,3 + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + +_GLOBAL(backwards_memcpy) + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + +_GLOBAL(memcmp) + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + blr +2: li r3,0 + blr + +_GLOBAL(memchr) + cmpwi 0,r5,0 + ble- 2f + mtctr r5 + addi r3,r3,-1 +1: lbzu r0,1(r3) + cmpw 0,r0,r4 + bdnzf 2,1b + beqlr +2: li r3,0 + blr + +_GLOBAL(__copy_tofrom_user) + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ +71: stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: subf r5,r0,r5 + srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ +73: stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + beq 63f + + /* Here we decide how far ahead to prefetch the source */ +#if MAX_COPY_PREFETCH > 1 + /* Heuristically, for large transfers we prefetch + MAX_COPY_PREFETCH cachelines ahead. For small transfers + we prefetch 1 cacheline ahead. */ + cmpwi r0,MAX_COPY_PREFETCH + li r7,1 + li r3,4 + ble 111f + li r7,MAX_COPY_PREFETCH +111: mtctr r7 +112: dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES + bdnz 112b +#else /* MAX_COPY_PREFETCH == 1 */ + li r3,CACHELINE_BYTES + 4 + dcbt r11,r4 +#endif /* MAX_COPY_PREFETCH */ + + mtctr r0 +53: + dcbt r3,r4 + dcbz r11,r6 +/* had to move these to keep extable in order */ + .section __ex_table,"a" + .align 3 + .llong 70b,100f + .llong 71b,101f + .llong 72b,102f + .llong 73b,103f + .llong 53b,105f + .text +/* the main body of the cacheline loop */ + COPY_16_BYTES_WITHEX(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_WITHEX(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_WITHEX(2) + COPY_16_BYTES_WITHEX(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_WITHEX(4) + COPY_16_BYTES_WITHEX(5) + COPY_16_BYTES_WITHEX(6) + COPY_16_BYTES_WITHEX(7) +#endif +#endif +#endif + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) +31: stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) +41: stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: li r3,0 + blr + +/* read fault, initial single-byte copy */ +100: li r4,0 + b 90f +/* write fault, initial single-byte copy */ +101: li r4,1 +90: subf r5,r8,r5 + li r3,0 + b 99f +/* read fault, initial word copy */ +102: li r4,0 + b 91f +/* write fault, initial word copy */ +103: li r4,1 +91: li r3,2 + b 99f + +/* + * this stuff handles faults in the cacheline loop and branches to either + * 104f (if in read part) or 105f (if in write part), after updating r5 + */ + COPY_16_BYTES_EXCODE(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_EXCODE(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_EXCODE(2) + COPY_16_BYTES_EXCODE(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_EXCODE(4) + COPY_16_BYTES_EXCODE(5) + COPY_16_BYTES_EXCODE(6) + COPY_16_BYTES_EXCODE(7) +#endif +#endif +#endif + +/* read fault in cacheline loop */ +104: li r4,0 + b 92f +/* fault on dcbz (effectively a write fault) */ +/* or write fault in cacheline loop */ +105: li r4,1 +92: li r3,LG_CACHELINE_BYTES + b 99f +/* read fault in final word loop */ +108: li r4,0 + b 93f +/* write fault in final word loop */ +109: li r4,1 +93: andi. r5,r5,3 + li r3,2 + b 99f +/* read fault in final byte loop */ +110: li r4,0 + b 94f +/* write fault in final byte loop */ +111: li r4,1 +94: li r5,0 + li r3,0 +/* + * At this stage the number of bytes not copied is + * r5 + (ctr << r3), and r4 is 0 for read or 1 for write. + */ +99: mfctr r0 + slw r3,r0,r3 + add r3,r3,r5 + cmpwi 0,r4,0 + bne 120f +/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */ + srwi. r0,r3,2 + li r9,0 + mtctr r0 + beq 113f +112: stwu r9,4(r6) + bdnz 112b +113: andi. r0,r3,3 + mtctr r0 + beq 120f +114: stb r9,4(r6) + addi r6,r6,1 + bdnz 114b +120: blr + + .section __ex_table,"a" + .align 3 + .llong 30b,108b + .llong 31b,109b + .llong 40b,110b + .llong 41b,111b + .llong 112b,120b + .llong 114b,120b + .text + +_GLOBAL(__clear_user) + addi r6,r3,-4 + li r3,0 + li r5,0 + cmplwi 0,r4,4 + blt 7f + /* clear a single word */ +11: stwu r5,4(r6) + beqlr + /* clear word sized chunks */ + andi. r0,r6,3 + add r4,r0,r4 + subf r6,r0,r6 + srwi r0,r4,2 + mtctr r0 + bdz 6f +1: stwu r5,4(r6) + bdnz 1b +6: andi. r4,r4,3 + /* clear byte sized chunks */ +7: cmpwi 0,r4,0 + beqlr + mtctr r4 + addi r6,r6,3 +8: stbu r5,1(r6) + bdnz 8b + blr +99: li r3,-EFAULT + blr + + .section __ex_table,"a" + .align 3 + .llong 11b,99b + .llong 1b,99b + .llong 8b,99b + .text + +_GLOBAL(__strncpy_from_user) + addi r6,r3,-1 + addi r4,r4,-1 + cmpwi 0,r5,0 + beq 2f + mtctr r5 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + beq 3f +2: addi r6,r6,1 +3: subf r3,r3,r6 + blr +99: li r3,-EFAULT + blr + + .section __ex_table,"a" + .align 3 + .llong 1b,99b + .text + +/* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ +_GLOBAL(__strnlen_user) + addi r7,r3,-1 + subf r6,r7,r5 /* top+1 - str */ + cmplw 0,r4,r6 + bge 0f + mr r6,r4 +0: mtctr r6 /* ctr = min(len, top - str) */ +1: lbzu r0,1(r7) /* get next byte */ + cmpwi 0,r0,0 + bdnzf 2,1b /* loop if --ctr != 0 && byte != 0 */ + addi r7,r7,1 + subf r3,r3,r7 /* number of bytes we have looked at */ + beqlr /* return if we found a 0 byte */ + cmpw 0,r3,r4 /* did we look at all len bytes? */ + blt 99f /* if not, must have hit top */ + addi r3,r4,1 /* return len + 1 to indicate no null found */ + blr +99: li r3,0 /* bad address, return 0 */ + blr + + .section __ex_table,"a" + .align 3 + .llong 1b,99b diff -urN linux-2.4.18/arch/ppc64/mm/Makefile linux-2.4.19-pre5/arch/ppc64/mm/Makefile --- linux-2.4.18/arch/ppc64/mm/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/mm/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,16 @@ +# +# Makefile for the linux ppc-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... + +EXTRA_CFLAGS = -mno-minimal-toc + +O_TARGET := mm.o + +obj-y := fault.o init.o extable.o imalloc.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc64/mm/extable.c linux-2.4.19-pre5/arch/ppc64/mm/extable.c --- linux-2.4.18/arch/ppc64/mm/extable.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/mm/extable.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,48 @@ +/* + * linux/arch/ppc/mm/extable.c + * + * from linux/arch/i386/mm/extable.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline unsigned long +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid->fixup; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + + ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); + if (ret) return ret; + + return 0; +} diff -urN linux-2.4.18/arch/ppc64/mm/fault.c linux-2.4.19-pre5/arch/ppc64/mm/fault.c --- linux-2.4.18/arch/ppc64/mm/fault.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/mm/fault.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,231 @@ +/* + * arch/ppc/mm/fault.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/i386/mm/fault.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Modified by Cort Dougan and Paul Mackerras. + * + * Modified for PPC64 by Dave Engebretsen (engebret@ibm.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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) +extern void (*debugger)(struct pt_regs *); +extern void (*debugger_fault_handler)(struct pt_regs *); +extern int (*debugger_dabr_match)(struct pt_regs *); +int debugger_kernel_faults = 1; +#endif + +extern void die_if_kernel(char *, struct pt_regs *, long); +void bad_page_fault(struct pt_regs *, unsigned long); +void do_page_fault(struct pt_regs *, unsigned long, unsigned long); + +#ifdef CONFIG_PPCDBG +extern unsigned long get_srr0(void); +extern unsigned long get_srr1(void); +#endif + +/* + * For 600- and 800-family processors, the error_code parameter is DSISR + * for a data fault, SRR1 for an instruction fault. + */ +void do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ + struct vm_area_struct * vma; + struct mm_struct *mm = current->mm; + siginfo_t info; + unsigned long code = SEGV_MAPERR; + unsigned long is_write = error_code & 0x02000000; + unsigned long mm_fault_return; + + PPCDBG(PPCDBG_MM, "Entering do_page_fault: addr = 0x%16.16lx, error_code = %lx\n\tregs_trap = %lx, srr0 = %lx, srr1 = %lx\n", address, error_code, regs->trap, get_srr0(), get_srr1()); + /* + * Fortunately the bit assignments in SRR1 for an instruction + * fault and DSISR for a data fault are mostly the same for the + * bits we are interested in. But there are some bits which + * indicate errors in DSISR but can validly be set in SRR1. + */ + if (regs->trap == 0x400) + error_code &= 0x48200000; + +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_fault_handler && (regs->trap == 0x300 || + regs->trap == 0x380)) { + debugger_fault_handler(regs); + return; + } + + if (error_code & 0x00400000) { + /* DABR match */ + if (debugger_dabr_match(regs)) + return; + } +#endif /* CONFIG_XMON || CONFIG_KGDB */ + + if (in_interrupt() || mm == NULL) { + bad_page_fault(regs, address); + return; + } + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma = 0x%16.16lx\n", vma); + if (!vma) { + PPCDBG(PPCDBG_MM, "\tdo_page_fault: !vma\n"); + goto bad_area; + } + PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_start = 0x%16.16lx, vma->vm_flags = 0x%16.16lx\n", vma->vm_start, vma->vm_flags); + if (vma->vm_start <= address) { + goto good_area; + } + if (!(vma->vm_flags & VM_GROWSDOWN)) { + PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_flags = %lx, %lx\n", vma->vm_flags, VM_GROWSDOWN); + goto bad_area; + } + if (expand_stack(vma, address)) { + PPCDBG(PPCDBG_MM, "\tdo_page_fault: expand_stack\n"); + goto bad_area; + } + +good_area: + code = SEGV_ACCERR; + + /* a write */ + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + /* a read */ + } else { + /* protection fault */ + if (error_code & 0x08000000) + goto bad_area; + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + 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. + */ + PPCDBG(PPCDBG_MM, "\tdo_page_fault: calling handle_mm_fault\n"); + mm_fault_return = handle_mm_fault(mm, vma, address, is_write); + PPCDBG(PPCDBG_MM, "\tdo_page_fault: handle_mm_fault = 0x%lx\n", + mm_fault_return); + switch(mm_fault_return) { + case 1: + current->min_flt++; + break; + case 2: + current->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } + + up_read(&mm->mmap_sem); + return; + +bad_area: + up_read(&mm->mmap_sem); + + /* User mode accesses cause a SIGSEGV */ + if (user_mode(regs)) { + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = code; + info.si_addr = (void *) address; + PPCDBG(PPCDBG_SIGNAL, "Bad addr in user: 0x%lx\n", address); +#ifdef CONFIG_XMON + ifppcdebug(PPCDBG_SIGNALXMON) + PPCDBG_ENTER_DEBUGGER_REGS(regs); +#endif + + force_sig_info(SIGSEGV, &info, current); + return; + } + + bad_page_fault(regs, address); + return; + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + bad_page_fault(regs, address); + return; + +do_sigbus: + up_read(&mm->mmap_sem); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info (SIGBUS, &info, current); + if (!user_mode(regs)) + bad_page_fault(regs, address); +} + +/* + * bad_page_fault is called when we have a bad access from the kernel. + * It is called from do_page_fault above and from some of the procedures + * in traps.c. + */ +void +bad_page_fault(struct pt_regs *regs, unsigned long address) +{ + unsigned long fixup; + + /* Are we prepared to handle this fault? */ + if ((fixup = search_exception_table(regs->nip)) != 0) { + regs->nip = fixup; + return; + } + + /* kernel has accessed a bad area */ + show_regs(regs); +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_kernel_faults) + debugger(regs); +#endif + print_backtrace( (unsigned long *)regs->gpr[1] ); + panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d", + regs->nip,regs->link,address,current->comm,current->pid); +} + diff -urN linux-2.4.18/arch/ppc64/mm/imalloc.c linux-2.4.19-pre5/arch/ppc64/mm/imalloc.c --- linux-2.4.18/arch/ppc64/mm/imalloc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/mm/imalloc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,71 @@ +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +#include +#include + +rwlock_t imlist_lock = RW_LOCK_UNLOCKED; +struct vm_struct * imlist = NULL; + +struct vm_struct *get_im_area(unsigned long size) +{ + unsigned long addr; + struct vm_struct **p, *tmp, *area; + + area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL); + if (!area) + return NULL; + addr = IMALLOC_START; + write_lock(&imlist_lock); + for (p = &imlist; (tmp = *p) ; p = &tmp->next) { + if (size + addr < (unsigned long) tmp->addr) + break; + addr = tmp->size + (unsigned long) tmp->addr; + if (addr > IMALLOC_END-size) { + write_unlock(&imlist_lock); + kfree(area); + return NULL; + } + } + area->flags = 0; + area->addr = (void *)addr; + area->size = size; + area->next = *p; + *p = area; + write_unlock(&imlist_lock); + return area; +} + +void ifree(void * addr) +{ + struct vm_struct **p, *tmp; + + if (!addr) + return; + if ((PAGE_SIZE-1) & (unsigned long) addr) { + printk(KERN_ERR "Trying to ifree() bad address (%p)\n", addr); + return; + } + write_lock(&imlist_lock); + for (p = &imlist ; (tmp = *p) ; p = &tmp->next) { + if (tmp->addr == addr) { + *p = tmp->next; + kfree(tmp); + write_unlock(&imlist_lock); + return; + } + } + write_unlock(&imlist_lock); + printk(KERN_ERR "Trying to ifree() nonexistent area (%p)\n", addr); +} + diff -urN linux-2.4.18/arch/ppc64/mm/init.c linux-2.4.19-pre5/arch/ppc64/mm/init.c --- linux-2.4.18/arch/ppc64/mm/init.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/mm/init.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,715 @@ +/* + * + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Dave Engebretsen + * Rework for PPC64 port. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include /* for initrd_* */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC_EEH +#include +#endif + +#include + +#define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) + +#ifdef CONFIG_PPC_ISERIES +#include +#endif + +struct mmu_context_queue_t mmu_context_queue; +int mem_init_done; +unsigned long ioremap_bot = IMALLOC_BASE; + +static int boot_mapsize; +static unsigned long totalram_pages; + +extern pgd_t swapper_pg_dir[]; +extern char __init_begin, __init_end; +extern char __chrp_begin, __chrp_end; +extern char __openfirmware_begin, __openfirmware_end; +extern struct _of_tce_table of_tce_table[]; +extern char _start[], _end[]; +extern char _stext[], etext[]; +extern struct task_struct *current_set[NR_CPUS]; +extern struct Naca *naca; + +void mm_init_ppc64(void); + +unsigned long *pmac_find_end_of_memory(void); +extern unsigned long *find_end_of_memory(void); + +extern pgd_t ioremap_dir[]; +pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir; + +static void map_io_page(unsigned long va, unsigned long pa, int flags); +extern void die_if_kernel(char *,struct pt_regs *,long); + +unsigned long klimit = (unsigned long)_end; + +HPTE *Hash=0; +unsigned long Hash_size=0; +unsigned long _SDR1=0; +unsigned long _ASR=0; + +/* max amount of RAM to use */ +unsigned long __max_memory; + +/* This is declared as we are using the more or less generic + * include/asm-ppc64/tlb.h file -- tgall + */ +mmu_gather_t mmu_gathers[NR_CPUS]; + +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)pgd_alloc_one_fast(0)), ++freed; + if (pmd_quicklist) + free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; + if (pte_quicklist) + free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed; + } while (pgtable_cache_size > low); + } + return freed; +} + +void show_mem(void) +{ + int i,free = 0,total = 0,reserved = 0; + int shared = 0, cached = 0; + struct task_struct *p; + + 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 (!atomic_read(&mem_map[i].count)) + free++; + else + shared += atomic_read(&mem_map[i].count) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + printk("%d pages in page table cache\n",(int)pgtable_cache_size); + show_buffers(); + printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid", + "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); +#ifdef CONFIG_SMP + printk(" %3s", "CPU"); +#endif /* CONFIG_SMP */ + printk("\n"); + for_each_task(p) + { + printk("%-8.8s %3d %8ld %8ld %8ld %c%08lx %08lx ", + p->comm,p->pid, + (p->mm)?p->mm->context:0, + (p->mm)?(p->mm->context<<4):0, + p->thread.last_syscall, + (p->thread.regs)?user_mode(p->thread.regs) ? 'u' : 'k' : '?', + (p->thread.regs)?p->thread.regs->nip:0, + (ulong)p); + { + int iscur = 0; +#ifdef CONFIG_SMP + printk("%3d ", p->processor); + if ( (p->processor != NO_PROC_ID) && + (p == current_set[p->processor]) ) + { + iscur = 1; + printk("current"); + } +#else + if ( p == current ) + { + iscur = 1; + printk("current"); + } + + if ( p == last_task_used_math ) + { + if ( iscur ) + printk(","); + printk("last math"); + } +#endif /* CONFIG_SMP */ + printk("\n"); + } + } +} + +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; +} + +void * +ioremap(unsigned long addr, unsigned long size) +{ +#ifdef CONFIG_PPC_ISERIES + return (void*)addr; +#else +#ifdef CONFIG_PPC_EEH + if(mem_init_done && (addr >> 60UL)) { + if (IS_EEH_TOKEN_DISABLED(addr)) + return IO_TOKEN_TO_ADDR(addr); + return (void*)addr; /* already mapped address or EEH token. */ + } +#endif + return __ioremap(addr, size, _PAGE_NO_CACHE); +#endif +} + +extern struct vm_struct * get_im_area( unsigned long size ); + +void * +__ioremap(unsigned long addr, unsigned long size, unsigned long flags) +{ + unsigned long pa, ea, i; + + /* + * Choose an address to map it to. + * Once the imalloc system is running, we use it. + * Before that, we map using addresses going + * up from ioremap_bot. imalloc will use + * the addresses from ioremap_bot through + * IMALLOC_END (0xE000001fffffffff) + * + */ + pa = addr & PAGE_MASK; + size = PAGE_ALIGN(addr + size) - pa; + + if (size == 0) + return NULL; + + if (mem_init_done) { + struct vm_struct *area; + area = get_im_area(size); + if (area == 0) + return NULL; + ea = (unsigned long)(area->addr); + } + else { + ea = ioremap_bot; + ioremap_bot += size; + } + + if ((flags & _PAGE_PRESENT) == 0) + flags |= pgprot_val(PAGE_KERNEL); + if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU)) + flags |= _PAGE_GUARDED; + + for (i = 0; i < size; i += PAGE_SIZE) { + map_io_page(ea+i, pa+i, flags); + } + + return (void *) (ea + (addr & ~PAGE_MASK)); +} + +void iounmap(void *addr) +{ +#ifdef CONFIG_PPC_ISERIES + /* iSeries I/O Remap is a noop */ + return; +#else + /* DRENG / PPPBBB todo */ + return; +#endif +} + +/* + * map_io_page currently only called by __ioremap + * map_io_page adds an entry to the ioremap page table + * and adds an entry to the HPT, possibly bolting it + */ +static void map_io_page(unsigned long ea, unsigned long pa, int flags) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long vsid; + + if (mem_init_done) { + spin_lock(&ioremap_mm.page_table_lock); + pgdp = pgd_offset_i(ea); + pmdp = pmd_alloc(&ioremap_mm, pgdp, ea); + ptep = pte_alloc(&ioremap_mm, pmdp, ea); + + pa = absolute_to_phys(pa); + set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); + spin_unlock(&ioremap_mm.page_table_lock); + } else { + /* If the mm subsystem is not fully up, we cannot create a + * linux page table entry for this mapping. Simply bolt an + * entry in the hardware page table. + */ + vsid = get_kernel_vsid(ea); + make_pte(htab_data.htab, + (vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea) + pa, + _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX, + htab_data.htab_hash_mask, 0); + } +} + +#if 0 +void +local_flush_tlb_all(void) +{ + /* Implemented to just flush the vmalloc area. + * vmalloc is the only user of flush_tlb_all. + */ + local_flush_tlb_range( NULL, VMALLOC_START, VMALLOC_END ); +} +#endif + +void +local_flush_tlb_mm(struct mm_struct *mm) +{ + if ( mm->map_count ) { + struct vm_area_struct *mp; + for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next ) + local_flush_tlb_range( mm, mp->vm_start, mp->vm_end ); + } + else /* MIKEC: It is not clear why this is needed */ + /* paulus: it is needed to clear out stale HPTEs + * when an address space (represented by an mm_struct) + * is being destroyed. */ + local_flush_tlb_range( mm, USER_START, USER_END ); +} + + +/* + * Callers should hold the mm->page_table_lock + */ +void +local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + unsigned long context = 0; + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep; + pte_t pte; + + switch( REGION_ID(vmaddr) ) { + case VMALLOC_REGION_ID: + pgd = pgd_offset_k( vmaddr ); + break; + case IO_REGION_ID: + pgd = pgd_offset_i( vmaddr ); + break; + case USER_REGION_ID: + pgd = pgd_offset( vma->vm_mm, vmaddr ); + context = vma->vm_mm->context; + break; + default: + panic("local_flush_tlb_page: invalid region 0x%016lx", vmaddr); + + } + + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, vmaddr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, vmaddr); + /* Check if HPTE might exist and flush it if so */ + pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0)); + if ( pte_val(pte) & _PAGE_HASHPTE ) { + flush_hash_page(context, vmaddr, pte); + } + } + } +} + +void +local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep; + pte_t pte; + unsigned long pgd_end, pmd_end; + unsigned long context; + + if ( start >= end ) + panic("flush_tlb_range: start (%016lx) greater than end (%016lx)\n", start, end ); + + if ( REGION_ID(start) != REGION_ID(end) ) + panic("flush_tlb_range: start (%016lx) and end (%016lx) not in same region\n", start, end ); + + context = 0; + + switch( REGION_ID(start) ) { + case VMALLOC_REGION_ID: + pgd = pgd_offset_k( start ); + break; + case IO_REGION_ID: + pgd = pgd_offset_i( start ); + break; + case USER_REGION_ID: + pgd = pgd_offset( mm, start ); + context = mm->context; + break; + default: + panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end); + + } + + do { + pgd_end = (start + PGDIR_SIZE) & PGDIR_MASK; + if ( pgd_end > end ) + pgd_end = end; + if ( !pgd_none( *pgd ) ) { + pmd = pmd_offset( pgd, start ); + do { + pmd_end = ( start + PMD_SIZE ) & PMD_MASK; + if ( pmd_end > end ) + pmd_end = end; + if ( !pmd_none( *pmd ) ) { + ptep = pte_offset( pmd, start ); + do { + if ( pte_val(*ptep) & _PAGE_HASHPTE ) { + pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0)); + if ( pte_val(pte) & _PAGE_HASHPTE ) + flush_hash_page( context, start, pte ); + } + start += PAGE_SIZE; + ++ptep; + } while ( start < pmd_end ); + } + else + start = pmd_end; + ++pmd; + } while ( start < pgd_end ); + } + else + start = pgd_end; + ++pgd; + } while ( start < end ); +} + + +void __init free_initmem(void) +{ + unsigned long a; + unsigned long num_freed_pages = 0; +#define FREESEC(START,END,CNT) do { \ + a = (unsigned long)(&START); \ + for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ + clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); \ + set_page_count(mem_map+MAP_NR(a), 1); \ + free_page(a); \ + CNT++; \ + } \ +} while (0) + + FREESEC(__init_begin,__init_end,num_freed_pages); + + printk ("Freeing unused kernel memory: %ldk init\n", + PGTOKB(num_freed_pages)); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long xstart = start; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(start)); + set_page_count(mem_map+MAP_NR(start), 1); + free_page(start); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - xstart) >> 10); +} +#endif + + + +/* + * Do very early mm setup. + */ +void __init mm_init_ppc64(void) { + struct Paca *paca; + unsigned long guard_page, index; + + ppc_md.progress("MM:init", 0); + + /* Reserve all contexts < FIRST_USER_CONTEXT for kernel use. + * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT) + * are stored on a stack/queue for easy allocation and deallocation. + */ + mmu_context_queue.lock = SPIN_LOCK_UNLOCKED; + mmu_context_queue.head = 0; + mmu_context_queue.tail = NUM_USER_CONTEXT-1; + mmu_context_queue.size = NUM_USER_CONTEXT; + for(index=0; index < NUM_USER_CONTEXT ;index++) { + mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT; + } + + /* Setup guard pages for the Paca's */ + for (index = 0; index < NR_CPUS; index++) { + paca = &xPaca[index]; + guard_page = ((unsigned long)paca) + 0x1000; + ppc_md.hpte_updateboltedpp(PP_RXRX, guard_page); + } + + ppc_md.progress("MM:exit", 0x211); +} + + + +/* + * Initialize the bootmem system and give it all the memory we + * have available. + */ +void __init do_init_bootmem(void) +{ + unsigned long i; + unsigned long start, bootmap_pages; + unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; + + PPCDBG(PPCDBG_MMINIT, "do_init_bootmem: start\n"); + /* + * Find an area to use for the bootmem bitmap. Calculate the size of + * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE. + * Add 1 additional page in case the address isn't page-aligned. + */ + bootmap_pages = bootmem_bootmap_pages(total_pages); + + start = (unsigned long)__a2p(lmb_alloc(bootmap_pages<physicalMemorySize); + + boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages); + PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize = 0x%lx\n", boot_mapsize); + + /* add all physical memory to the bootmem map */ + for (i=0; i < lmb.memory.cnt ;i++) { + unsigned long physbase, size; + unsigned long type = lmb.memory.region[i].type; + + if ( type != LMB_MEMORY_AREA ) + continue; + + physbase = lmb.memory.region[i].physbase; + size = lmb.memory.region[i].size; + free_bootmem(physbase, size); + } + /* reserve the sections we're already using */ + for (i=0; i < lmb.reserved.cnt ;i++) { + unsigned long physbase = lmb.reserved.region[i].physbase; + unsigned long size = lmb.reserved.region[i].size; +#if 0 /* PPPBBB */ + if ( (physbase == 0) && (size < (16<<20)) ) { + size = 16 << 20; + } +#endif + reserve_bootmem(physbase, size); + } + + PPCDBG(PPCDBG_MMINIT, "do_init_bootmem: end\n"); +} + +/* + * paging_init() sets up the page tables - in fact we've already done this. + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES], i; + + /* + * All pages are DMA-able so we put them all in the DMA zone. + */ + zones_size[0] = lmb_end_of_DRAM() >> PAGE_SHIFT; + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + free_area_init(zones_size); +} + +extern unsigned long prof_shift; +extern unsigned long prof_len; +extern unsigned int * prof_buffer; +extern unsigned long dprof_shift; +extern unsigned long dprof_len; +extern unsigned int * dprof_buffer; + +void __init mem_init(void) +{ + extern char *sysmap; + extern unsigned long sysmap_size; + unsigned long addr; + int codepages = 0; + int datapages = 0; + int initpages = 0; + unsigned long va_rtas_base = (unsigned long)__va(rtas.base); + max_mapnr = max_low_pfn; + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); + num_physpages = max_mapnr; /* RAM is assumed contiguous */ + + totalram_pages += free_all_bootmem(); + + ifppcdebug(PPCDBG_MMINIT) { + udbg_printf("mem_init: totalram_pages = 0x%lx\n", totalram_pages); + udbg_printf("mem_init: va_rtas_base = 0x%lx\n", va_rtas_base); + udbg_printf("mem_init: va_rtas_end = 0x%lx\n", PAGE_ALIGN(va_rtas_base+rtas.size)); + udbg_printf("mem_init: pinned start = 0x%lx\n", __va(0)); + udbg_printf("mem_init: pinned end = 0x%lx\n", PAGE_ALIGN(klimit)); + } + + 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 = KERNELBASE; addr <= (unsigned long)__va(lmb_end_of_DRAM()); + addr += PAGE_SIZE) { + if (!PageReserved(mem_map + MAP_NR(addr))) + continue; + if (addr < (ulong) etext) + codepages++; + + else if (addr >= (unsigned long)&__init_begin + && addr < (unsigned long)&__init_end) + initpages++; + else if (addr < klimit) + datapages++; + } + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", + (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), + codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), + initpages<< (PAGE_SHIFT-10), + PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); + mem_init_done = 1; + + /* set the last page of each hardware interrupt stack to be protected */ + initialize_paca_hardware_interrupt_stack(); + +#ifdef CONFIG_PPC_ISERIES + create_virtual_bus_tce_table(); + /* HACK HACK This allows the iSeries profiling to use /proc/profile */ + prof_shift = dprof_shift; + prof_len = dprof_len; + prof_buffer = dprof_buffer; +#endif +} + + + +/* + * This is called when a page has been modified by the kernel. + * It just marks the page as not i-cache clean. We do the i-cache + * flush later when the page is given to a user process, if necessary. + */ +void flush_dcache_page(struct page *page) +{ + clear_bit(PG_arch_1, &page->flags); +} + +void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (page->mapping && !PageReserved(page) + && !test_bit(PG_arch_1, &page->flags)) { + __flush_dcache_icache(page_address(page)); + set_bit(PG_arch_1, &page->flags); + } +} + +void clear_user_page(void *page, unsigned long vaddr) +{ + clear_page(page); +} + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr) +{ + copy_page(vto, vfrom); + __flush_dcache_icache(vto); +} + +void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + unsigned long maddr; + + maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK); + flush_icache_range(maddr, maddr + len); +} diff -urN linux-2.4.18/arch/ppc64/vmlinux.lds linux-2.4.19-pre5/arch/ppc64/vmlinux.lds --- linux-2.4.18/arch/ppc64/vmlinux.lds Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/vmlinux.lds Sat Mar 30 22:55:39 2002 @@ -0,0 +1,140 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } +/* .init : { *(.init) } =0*/ + .plt : { *(.plt) } + .text : + { + *(.text) + *(.fixup) + *(.got1) + } + . = ALIGN(4096); + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFFFFFFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + . = ALIGN(4096); + _edata = .; + PROVIDE (edata = .); + + .fixup : { *(.fixup) } + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + + + . = ALIGN(4096); + .data.page_aligned : { *(.data.page_aligned) } + + . = ALIGN(128); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { + *(.data.init); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + + + . = ALIGN(4096); + __init_end = .; + + __chrp_begin = .; + .text.chrp : { *(.text.chrp) } + .data.chrp : { *(.data.chrp) } + . = ALIGN(4096); + __chrp_end = .; + + . = ALIGN(4096); + __openfirmware_begin = .; + .text.openfirmware : { *(.text.openfirmware) } + .data.openfirmware : { *(.data.openfirmware) } + . = ALIGN(4096); + __openfirmware_end = .; + + __toc_start = .; + .toc : + { + *(.toc) + } + . = ALIGN(4096); + __toc_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + + . = ALIGN(4096); + _end = . ; + PROVIDE (end = .); +} diff -urN linux-2.4.18/arch/ppc64/xmon/Makefile linux-2.4.19-pre5/arch/ppc64/xmon/Makefile --- linux-2.4.18/arch/ppc64/xmon/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/Makefile Sat Mar 30 22:55:39 2002 @@ -0,0 +1,9 @@ +# Makefile for xmon + +EXTRA_CFLAGS = -mno-minimal-toc + +O_TARGET = x.o + +obj-y := start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/ppc64/xmon/adb.c linux-2.4.19-pre5/arch/ppc64/xmon/adb.c --- linux-2.4.18/arch/ppc64/xmon/adb.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/adb.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,217 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "nonstdio.h" +#include "privinst.h" + +#define scanhex xmon_scanhex +#define skipbl xmon_skipbl + +#define ADB_B (*(volatile unsigned char *)0xf3016000) +#define ADB_SR (*(volatile unsigned char *)0xf3017400) +#define ADB_ACR (*(volatile unsigned char *)0xf3017600) +#define ADB_IFR (*(volatile unsigned char *)0xf3017a00) + +static inline void eieio(void) { asm volatile ("eieio" : :); } + +#define N_ADB_LOG 1000 +struct adb_log { + unsigned char b; + unsigned char ifr; + unsigned char acr; + unsigned int time; +} adb_log[N_ADB_LOG]; +int n_adb_log; + +void +init_adb_log(void) +{ + adb_log[0].b = ADB_B; + adb_log[0].ifr = ADB_IFR; + adb_log[0].acr = ADB_ACR; + adb_log[0].time = get_dec(); + n_adb_log = 0; +} + +void +dump_adb_log(void) +{ + unsigned t, t0; + struct adb_log *ap; + int i; + + ap = adb_log; + t0 = ap->time; + for (i = 0; i <= n_adb_log; ++i, ++ap) { + t = t0 - ap->time; + printf("b=%x ifr=%x acr=%x at %d.%.7d\n", ap->b, ap->ifr, ap->acr, + t / 1000000000, (t % 1000000000) / 100); + } +} + +void +adb_chklog(void) +{ + struct adb_log *ap = &adb_log[n_adb_log + 1]; + + ap->b = ADB_B; + ap->ifr = ADB_IFR; + ap->acr = ADB_ACR; + if (ap->b != ap[-1].b || (ap->ifr & 4) != (ap[-1].ifr & 4) + || ap->acr != ap[-1].acr) { + ap->time = get_dec(); + ++n_adb_log; + } +} + +int +adb_bitwait(int bmask, int bval, int fmask, int fval) +{ + int i; + struct adb_log *ap; + + for (i = 10000; i > 0; --i) { + adb_chklog(); + ap = &adb_log[n_adb_log]; + if ((ap->b & bmask) == bval && (ap->ifr & fmask) == fval) + return 0; + } + return -1; +} + +int +adb_wait(void) +{ + if (adb_bitwait(0, 0, 4, 4) < 0) { + printf("adb: ready wait timeout\n"); + return -1; + } + return 0; +} + +void +adb_readin(void) +{ + int i, j; + unsigned char d[64]; + + if (ADB_B & 8) { + printf("ADB_B: %x\n", ADB_B); + return; + } + i = 0; + adb_wait(); + j = ADB_SR; + eieio(); + ADB_B &= ~0x20; + eieio(); + for (;;) { + if (adb_wait() < 0) + break; + d[i++] = ADB_SR; + eieio(); + if (ADB_B & 8) + break; + ADB_B ^= 0x10; + eieio(); + } + ADB_B |= 0x30; + if (adb_wait() == 0) + j = ADB_SR; + for (j = 0; j < i; ++j) + printf("%.2x ", d[j]); + printf("\n"); +} + +int +adb_write(unsigned char *d, int i) +{ + int j; + unsigned x; + + if ((ADB_B & 8) == 0) { + printf("r: "); + adb_readin(); + } + for (;;) { + ADB_ACR = 0x1c; + eieio(); + ADB_SR = d[0]; + eieio(); + ADB_B &= ~0x20; + eieio(); + if (ADB_B & 8) + break; + ADB_ACR = 0xc; + eieio(); + ADB_B |= 0x20; + eieio(); + adb_readin(); + } + adb_wait(); + for (j = 1; j < i; ++j) { + ADB_SR = d[j]; + eieio(); + ADB_B ^= 0x10; + eieio(); + if (adb_wait() < 0) + break; + } + ADB_ACR = 0xc; + eieio(); + x = ADB_SR; + eieio(); + ADB_B |= 0x30; + return j; +} + +void +adbcmds(void) +{ + char cmd; + unsigned rtcu, rtcl, dec, pdec, x; + int i, j; + unsigned char d[64]; + + cmd = skipbl(); + switch (cmd) { + case 't': + for (;;) { + rtcl = get_rtcl(); + rtcu = get_rtcu(); + dec = get_dec(); + printf("rtc u=%u l=%u dec=%x (%d = %d.%.7d)\n", + rtcu, rtcl, dec, pdec - dec, (pdec - dec) / 1000000000, + ((pdec - dec) % 1000000000) / 100); + pdec = dec; + if (cmd == 'x') + break; + while (xmon_read(stdin, &cmd, 1) != 1) + ; + } + break; + case 'r': + init_adb_log(); + while (adb_bitwait(8, 0, 0, 0) == 0) + adb_readin(); + break; + case 'w': + i = 0; + while (scanhex(&x)) + d[i++] = x; + init_adb_log(); + j = adb_write(d, i); + printf("sent %d bytes\n", j); + while (adb_bitwait(8, 0, 0, 0) == 0) + adb_readin(); + break; + case 'l': + dump_adb_log(); + break; + } +} diff -urN linux-2.4.18/arch/ppc64/xmon/ansidecl.h linux-2.4.19-pre5/arch/ppc64/xmon/ansidecl.h --- linux-2.4.18/arch/ppc64/xmon/ansidecl.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/ansidecl.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,141 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +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. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + LONG_DOUBLE `long double' `double' + VOLATILE `volatile' `' + SIGNED `signed' `' + PTRCONST `void *const' `char *' + ANSI_PROTOTYPES 1 not defined + + CONST is also defined, but is obsolete. Just use const. + + DEFUN (name, arglist, args) + + Defines function NAME. + + ARGLIST lists the arguments, separated by commas and enclosed in + parentheses. ARGLIST becomes the argument list in traditional C. + + ARGS list the arguments with their types. It becomes a prototype in + ANSI C, and the type declarations in traditional C. Arguments should + be separated with `AND'. For functions with a variable number of + arguments, the last thing listed should be `DOTS'. + + DEFUN_VOID (name) + + Defines a function NAME, which takes no arguments. + + obsolete -- EXFUN (name, (prototype)) -- obsolete. + + Replaced by PARAMS. Do not use; will disappear someday soon. + Was used in external function declarations. + In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in + parentheses). In traditional C it is `NAME()'. + For a function that takes no arguments, PROTOTYPE should be `(void)'. + + PARAMS ((args)) + + We could use the EXFUN macro to handle prototype declarations, but + the name is misleading and the result is ugly. So we just define a + simple macro to handle the parameter lists, as in: + + static int foo PARAMS ((int, char)); + + This produces: `static int foo();' or `static int foo (int, char);' + + EXFUN would have done it like this: + + static int EXFUN (foo, (int, char)); + + but the function is not external...and it's hard to visually parse + the function name out of the mess. EXFUN should be considered + obsolete; new code should be written to use PARAMS. + + For example: + extern int printf PARAMS ((CONST char *format DOTS)); + int DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) { ... } + void DEFUN_VOID(abort) { ... } +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#define AND , +#define NOARGS void +#define CONST const +#define VOLATILE volatile +#define SIGNED signed +#define DOTS , ... + +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) + +#define PROTO(type, name, arglist) type name arglist +#define PARAMS(paramlist) paramlist +#define ANSI_PROTOTYPES 1 + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define AND ; +#define NOARGS +#define CONST +#ifndef const /* some systems define it in header files for non-ansi mode */ +#define const +#endif +#define VOLATILE +#define SIGNED +#define DOTS + +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#define PROTO(type, name, arglist) type name () +#define PARAMS(paramlist) () + +#endif /* ANSI C. */ + +#endif /* ansidecl.h */ diff -urN linux-2.4.18/arch/ppc64/xmon/nonstdio.h linux-2.4.19-pre5/arch/ppc64/xmon/nonstdio.h --- linux-2.4.18/arch/ppc64/xmon/nonstdio.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/nonstdio.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,22 @@ +typedef int FILE; +extern FILE *xmon_stdin, *xmon_stdout; +#define EOF (-1) +#define stdin xmon_stdin +#define stdout xmon_stdout +#define printf xmon_printf +#define fprintf xmon_fprintf +#define fputs xmon_fputs +#define fgets xmon_fgets +#define putchar xmon_putchar +#define getchar xmon_getchar +#define putc xmon_putc +#define getc xmon_getc +#define fopen(n, m) NULL +#define fflush(f) do {} while (0) +#define fclose(f) do {} while (0) +extern char *fgets(char *, int, void *); +extern void xmon_printf(const char *, ...); +extern void xmon_fprintf(void *, const char *, ...); +extern void xmon_sprintf(char *, const char *, ...); + +#define perror(s) printf("%s: no files!\n", (s)) diff -urN linux-2.4.18/arch/ppc64/xmon/ppc-dis.c linux-2.4.19-pre5/arch/ppc64/xmon/ppc-dis.c --- linux-2.4.18/arch/ppc64/xmon/ppc-dis.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc-dis.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,190 @@ +/* ppc-dis.c -- Disassemble PowerPC instructions + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "nonstdio.h" +#include "ansidecl.h" +#include "ppc.h" + +static int print_insn_powerpc PARAMS ((FILE *, unsigned long insn, + unsigned long memaddr, int dialect)); + +extern void print_address PARAMS((unsigned long memaddr)); + +/* Print a big endian PowerPC instruction. For convenience, also + disassemble instructions supported by the Motorola PowerPC 601. */ + +int +print_insn_big_powerpc (FILE *out, unsigned long insn, unsigned long memaddr) +{ + return print_insn_powerpc (out, insn, memaddr, + PPC_OPCODE_PPC | PPC_OPCODE_601); +} + +/* Print a PowerPC or POWER instruction. */ + +static int +print_insn_powerpc (FILE *out, unsigned long insn, unsigned long memaddr, + int dialect) +{ + const struct powerpc_opcode *opcode; + const struct powerpc_opcode *opcode_end; + unsigned long op; + + /* Get the major opcode of the instruction. */ + op = PPC_OP (insn); + + /* Find the first match in the opcode table. We could speed this up + a bit by doing a binary search on the major opcode. */ + opcode_end = powerpc_opcodes + powerpc_num_opcodes; + for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + { + unsigned long table_op; + const unsigned char *opindex; + const struct powerpc_operand *operand; + int invalid; + int need_comma; + int need_paren; + + table_op = PPC_OP (opcode->opcode); + if (op < table_op) + break; + if (op > table_op) + continue; + + if ((insn & opcode->mask) != opcode->opcode + || (opcode->flags & dialect) == 0) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + operand = powerpc_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, &invalid); + } + if (invalid) + continue; + + /* The instruction is valid. */ + fprintf(out, "%s", opcode->name); + if (opcode->operands[0] != 0) + fprintf(out, "\t"); + + /* Now extract and print the operands. */ + need_comma = 0; + need_paren = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + long value; + + operand = powerpc_operands + *opindex; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & PPC_OPERAND_FAKE) != 0) + continue; + + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, (int *) 0); + else + { + value = (insn >> operand->shift) & ((1 << operand->bits) - 1); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0 + && (value & (1 << (operand->bits - 1))) != 0) + value -= 1 << operand->bits; + } + + /* If the operand is optional, and the value is zero, don't + print anything. */ + if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 + && (operand->flags & PPC_OPERAND_NEXT) == 0 + && value == 0) + continue; + + if (need_comma) + { + fprintf(out, ","); + need_comma = 0; + } + + /* Print the operand as directed by the flags. */ + if ((operand->flags & PPC_OPERAND_GPR) != 0) + fprintf(out, "r%ld", value); + else if ((operand->flags & PPC_OPERAND_FPR) != 0) + fprintf(out, "f%ld", value); + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) + print_address (memaddr + value); + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) + print_address (value & 0xffffffff); + else if ((operand->flags & PPC_OPERAND_CR) == 0 + || (dialect & PPC_OPCODE_PPC) == 0) + fprintf(out, "%ld", value); + else + { + if (operand->bits == 3) + fprintf(out, "cr%d", value); + else + { + static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; + int cr; + int cc; + + cr = value >> 2; + if (cr != 0) + fprintf(out, "4*cr%d", cr); + cc = value & 3; + if (cc != 0) + { + if (cr != 0) + fprintf(out, "+"); + fprintf(out, "%s", cbnames[cc]); + } + } + } + + if (need_paren) + { + fprintf(out, ")"); + need_paren = 0; + } + + if ((operand->flags & PPC_OPERAND_PARENS) == 0) + need_comma = 1; + else + { + fprintf(out, "("); + need_paren = 1; + } + } + + /* We have found and printed an instruction; return. */ + return 4; + } + + /* We could not find a match. */ + fprintf(out, ".long 0x%lx", insn); + + return 4; +} diff -urN linux-2.4.18/arch/ppc64/xmon/ppc-opc.c linux-2.4.19-pre5/arch/ppc64/xmon/ppc-opc.c --- linux-2.4.18/arch/ppc64/xmon/ppc-opc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc-opc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2816 @@ +/* ppc-opc.c -- PowerPC opcode list + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +2, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "ansidecl.h" +#include "ppc.h" + +/* This file holds the PowerPC opcode table. The opcode table + includes almost all of the extended instruction mnemonics. This + permits the disassembler to use them, and simplifies the assembler + logic, at the cost of increasing the table size. The table is + strictly constant data, so the compiler should be able to put it in + the .text section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* Local insertion and extraction functions. */ + +static unsigned long insert_bat PARAMS ((unsigned long, long, const char **)); +static long extract_bat PARAMS ((unsigned long, int *)); +static unsigned long insert_bba PARAMS ((unsigned long, long, const char **)); +static long extract_bba PARAMS ((unsigned long, int *)); +static unsigned long insert_bd PARAMS ((unsigned long, long, const char **)); +static long extract_bd PARAMS ((unsigned long, int *)); +static unsigned long insert_bdm PARAMS ((unsigned long, long, const char **)); +static long extract_bdm PARAMS ((unsigned long, int *)); +static unsigned long insert_bdp PARAMS ((unsigned long, long, const char **)); +static long extract_bdp PARAMS ((unsigned long, int *)); +static unsigned long insert_bo PARAMS ((unsigned long, long, const char **)); +static long extract_bo PARAMS ((unsigned long, int *)); +static unsigned long insert_boe PARAMS ((unsigned long, long, const char **)); +static long extract_boe PARAMS ((unsigned long, int *)); +static unsigned long insert_ds PARAMS ((unsigned long, long, const char **)); +static long extract_ds PARAMS ((unsigned long, int *)); +static unsigned long insert_li PARAMS ((unsigned long, long, const char **)); +static long extract_li PARAMS ((unsigned long, int *)); +static unsigned long insert_mbe PARAMS ((unsigned long, long, const char **)); +static long extract_mbe PARAMS ((unsigned long, int *)); +static unsigned long insert_mb6 PARAMS ((unsigned long, long, const char **)); +static long extract_mb6 PARAMS ((unsigned long, int *)); +static unsigned long insert_nb PARAMS ((unsigned long, long, const char **)); +static long extract_nb PARAMS ((unsigned long, int *)); +static unsigned long insert_nsi PARAMS ((unsigned long, long, const char **)); +static long extract_nsi PARAMS ((unsigned long, int *)); +static unsigned long insert_ral PARAMS ((unsigned long, long, const char **)); +static unsigned long insert_ram PARAMS ((unsigned long, long, const char **)); +static unsigned long insert_ras PARAMS ((unsigned long, long, const char **)); +static unsigned long insert_rbs PARAMS ((unsigned long, long, const char **)); +static long extract_rbs PARAMS ((unsigned long, int *)); +static unsigned long insert_sh6 PARAMS ((unsigned long, long, const char **)); +static long extract_sh6 PARAMS ((unsigned long, int *)); +static unsigned long insert_spr PARAMS ((unsigned long, long, const char **)); +static long extract_spr PARAMS ((unsigned long, int *)); +static unsigned long insert_tbr PARAMS ((unsigned long, long, const char **)); +static long extract_tbr PARAMS ((unsigned long, int *)); + +/* The operands table. + + The fields are bits, shift, signed, insert, extract, flags. */ + +const struct powerpc_operand powerpc_operands[] = +{ + /* The zero index is used to indicate the end of the list of + operands. */ +#define UNUSED (0) + { 0, 0, 0, 0, 0 }, + + /* The BA field in an XL form instruction. */ +#define BA (1) +#define BA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_CR }, + + /* The BA field in an XL form instruction when it must be the same + as the BT field in the same instruction. */ +#define BAT (2) + { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, + + /* The BB field in an XL form instruction. */ +#define BB (3) +#define BB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_CR }, + + /* The BB field in an XL form instruction when it must be the same + as the BA field in the same instruction. */ +#define BBA (4) + { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, + + /* The BD field in a B form instruction. The lower two bits are + forced to zero. */ +#define BD (5) + { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when absolute addressing is + used. */ +#define BDA (6) + { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDM (7) + { 16, 0, insert_bdm, extract_bdm, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used + and absolute address is used. */ +#define BDMA (8) + { 16, 0, insert_bdm, extract_bdm, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDP (9) + { 16, 0, insert_bdp, extract_bdp, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used + and absolute addressing is used. */ +#define BDPA (10) + { 16, 0, insert_bdp, extract_bdp, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BF field in an X or XL form instruction. */ +#define BF (11) + { 3, 23, 0, 0, PPC_OPERAND_CR }, + + /* An optional BF field. This is used for comparison instructions, + in which an omitted BF field is taken as zero. */ +#define OBF (12) + { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The BFA field in an X or XL form instruction. */ +#define BFA (13) + { 3, 18, 0, 0, PPC_OPERAND_CR }, + + /* The BI field in a B form or XL form instruction. */ +#define BI (14) +#define BI_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_CR }, + + /* The BO field in a B form instruction. Certain values are + illegal. */ +#define BO (15) +#define BO_MASK (0x1f << 21) + { 5, 21, insert_bo, extract_bo, 0 }, + + /* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. */ +#define BOE (16) + { 5, 21, insert_boe, extract_boe, 0 }, + + /* The BT field in an X or XL form instruction. */ +#define BT (17) + { 5, 21, 0, 0, PPC_OPERAND_CR }, + + /* The condition register number portion of the BI field in a B form + or XL form instruction. This is used for the extended + conditional branch mnemonics, which set the lower two bits of the + BI field. This field is optional. */ +#define CR (18) + { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The D field in a D form instruction. This is a displacement off + a register, and implies that the next operand is a register in + parentheses. */ +#define D (19) + { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ +#define DS (20) + { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The FL1 field in a POWER SC form instruction. */ +#define FL1 (21) + { 4, 12, 0, 0, 0 }, + + /* The FL2 field in a POWER SC form instruction. */ +#define FL2 (22) + { 3, 2, 0, 0, 0 }, + + /* The FLM field in an XFL form instruction. */ +#define FLM (23) + { 8, 17, 0, 0, 0 }, + + /* The FRA field in an X or A form instruction. */ +#define FRA (24) +#define FRA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_FPR }, + + /* The FRB field in an X or A form instruction. */ +#define FRB (25) +#define FRB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_FPR }, + + /* The FRC field in an A form instruction. */ +#define FRC (26) +#define FRC_MASK (0x1f << 6) + { 5, 6, 0, 0, PPC_OPERAND_FPR }, + + /* The FRS field in an X form instruction or the FRT field in a D, X + or A form instruction. */ +#define FRS (27) +#define FRT (FRS) + { 5, 21, 0, 0, PPC_OPERAND_FPR }, + + /* The FXM field in an XFX instruction. */ +#define FXM (28) +#define FXM_MASK (0xff << 12) + { 8, 12, 0, 0, 0 }, + + /* The L field in a D or X form instruction. */ +#define L (29) + { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL }, + + /* The LEV field in a POWER SC form instruction. */ +#define LEV (30) + { 7, 5, 0, 0, 0 }, + + /* The LI field in an I form instruction. The lower two bits are + forced to zero. */ +#define LI (31) + { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The LI field in an I form instruction when used as an absolute + address. */ +#define LIA (32) + { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The MB field in an M form instruction. */ +#define MB (33) +#define MB_MASK (0x1f << 6) + { 5, 6, 0, 0, 0 }, + + /* The ME field in an M form instruction. */ +#define ME (34) +#define ME_MASK (0x1f << 1) + { 5, 1, 0, 0, 0 }, + + /* The MB and ME fields in an M form instruction expressed a single + operand which is a bitmask indicating which bits to select. This + is a two operand form using PPC_OPERAND_NEXT. See the + description in opcode/ppc.h for what this means. */ +#define MBE (35) + { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, + { 32, 0, insert_mbe, extract_mbe, 0 }, + + /* The MB or ME field in an MD or MDS form instruction. The high + bit is wrapped to the low end. */ +#define MB6 (37) +#define ME6 (MB6) +#define MB6_MASK (0x3f << 5) + { 6, 5, insert_mb6, extract_mb6, 0 }, + + /* The NB field in an X form instruction. The value 32 is stored as + 0. */ +#define NB (38) + { 6, 11, insert_nb, extract_nb, 0 }, + + /* The NSI field in a D form instruction. This is the same as the + SI field, only negated. */ +#define NSI (39) + { 16, 0, insert_nsi, extract_nsi, + PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, + + /* The RA field in an D, DS, X, XO, M, or MDS form instruction. */ +#define RA (40) +#define RA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_GPR }, + + /* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ +#define RAL (41) + { 5, 16, insert_ral, 0, PPC_OPERAND_GPR }, + + /* The RA field in an lmw instruction, which has special value + restrictions. */ +#define RAM (42) + { 5, 16, insert_ram, 0, PPC_OPERAND_GPR }, + + /* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ +#define RAS (43) + { 5, 16, insert_ras, 0, PPC_OPERAND_GPR }, + + /* The RB field in an X, XO, M, or MDS form instruction. */ +#define RB (44) +#define RB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_GPR }, + + /* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. */ +#define RBS (45) + { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, + + /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form + instruction or the RT field in a D, DS, X, XFX or XO form + instruction. */ +#define RS (46) +#define RT (RS) +#define RT_MASK (0x1f << 21) + { 5, 21, 0, 0, PPC_OPERAND_GPR }, + + /* The SH field in an X or M form instruction. */ +#define SH (47) +#define SH_MASK (0x1f << 11) + { 5, 11, 0, 0, 0 }, + + /* The SH field in an MD form instruction. This is split. */ +#define SH6 (48) +#define SH6_MASK ((0x1f << 11) | (1 << 1)) + { 6, 1, insert_sh6, extract_sh6, 0 }, + + /* The SI field in a D form instruction. */ +#define SI (49) + { 16, 0, 0, 0, PPC_OPERAND_SIGNED }, + + /* The SI field in a D form instruction when we accept a wide range + of positive values. */ +#define SISIGNOPT (50) + { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, + + /* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ +#define SPR (51) +#define SPR_MASK (0x3ff << 11) + { 10, 11, insert_spr, extract_spr, 0 }, + + /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ +#define SPRBAT (52) +#define SPRBAT_MASK (0x3 << 17) + { 2, 17, 0, 0, 0 }, + + /* The SPRG register number in an XFX form m[ft]sprg instruction. */ +#define SPRG (53) +#define SPRG_MASK (0x3 << 16) + { 2, 16, 0, 0, 0 }, + + /* The SR field in an X form instruction. */ +#define SR (54) + { 4, 16, 0, 0, 0 }, + + /* The SV field in a POWER SC form instruction. */ +#define SV (55) + { 14, 2, 0, 0, 0 }, + + /* The TBR field in an XFX form instruction. This is like the SPR + field, but it is optional. */ +#define TBR (56) + { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, + + /* The TO field in a D or X form instruction. */ +#define TO (57) +#define TO_MASK (0x1f << 21) + { 5, 21, 0, 0, 0 }, + + /* The U field in an X form instruction. */ +#define U (58) + { 4, 12, 0, 0, 0 }, + + /* The UI field in a D form instruction. */ +#define UI (59) + { 16, 0, 0, 0, 0 }, +}; + +/* The functions used to insert and extract complicated operands. */ + +/* The BA field in an XL form instruction when it must be the same as + the BT field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BT field into the BA field, + and the extraction function just checks that the fields are the + same. */ + +/*ARGSUSED*/ +static unsigned long +insert_bat (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static long +extract_bat (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BB field in an XL form instruction when it must be the same as + the BA field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BA field into the BB field, + and the extraction function just checks that the fields are the + same. */ + +/*ARGSUSED*/ +static unsigned long +insert_bba (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 16) & 0x1f) << 11); +} + +static long +extract_bba (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BD field in a B form instruction. The lower two bits are + forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_bd (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0xfffc); +} + +/*ARGSUSED*/ +static long +extract_bd (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The BD field in a B form instruction when the - modifier is used. + This modifier means that the branch is not expected to be taken. + We must set the y bit of the BO field to 1 if the offset is + negative. When extracting, we require that the y bit be 1 and that + the offset be positive, since if the y bit is 0 we just want to + print the normal form of the instruction. */ + +/*ARGSUSED*/ +static unsigned long +insert_bdm (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if ((value & 0x8000) != 0) + insn |= 1 << 21; + return insn | (value & 0xfffc); +} + +static long +extract_bdm (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn & (1 << 21)) == 0 + || (insn & (1 << 15)) == 0)) + *invalid = 1; + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The BD field in a B form instruction when the + modifier is used. + This is like BDM, above, except that the branch is expected to be + taken. */ + +/*ARGSUSED*/ +static unsigned long +insert_bdp (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if ((value & 0x8000) == 0) + insn |= 1 << 21; + return insn | (value & 0xfffc); +} + +static long +extract_bdp (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn & (1 << 21)) == 0 + || (insn & (1 << 15)) != 0)) + *invalid = 1; + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* Check for legal values of a BO field. */ + +static int +valid_bo (long value) +{ + /* Certain encodings have bits that are required to be zero. These + are (z must be zero, y may be anything): + 001zy + 011zy + 1z00y + 1z01y + 1z1zz + */ + switch (value & 0x14) + { + default: + case 0: + return 1; + case 0x4: + return (value & 0x2) == 0; + case 0x10: + return (value & 0x8) == 0; + case 0x14: + return value == 0x14; + } +} + +/* The BO field in a B form instruction. Warn about attempts to set + the field to an illegal value. */ + +static unsigned long +insert_bo (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (errmsg != (const char **) NULL + && ! valid_bo (value)) + *errmsg = "invalid conditional option"; + return insn | ((value & 0x1f) << 21); +} + +static long +extract_bo (insn, invalid) + unsigned long insn; + int *invalid; +{ + long value; + + value = (insn >> 21) & 0x1f; + if (invalid != (int *) NULL + && ! valid_bo (value)) + *invalid = 1; + return value; +} + +/* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. When + extracting it, we force it to be even. */ + +static unsigned long +insert_boe (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (errmsg != (const char **) NULL) + { + if (! valid_bo (value)) + *errmsg = "invalid conditional option"; + else if ((value & 1) != 0) + *errmsg = "attempt to set y bit when using + or - modifier"; + } + return insn | ((value & 0x1f) << 21); +} + +static long +extract_boe (insn, invalid) + unsigned long insn; + int *invalid; +{ + long value; + + value = (insn >> 21) & 0x1f; + if (invalid != (int *) NULL + && ! valid_bo (value)) + *invalid = 1; + return value & 0x1e; +} + +/* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_ds (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0xfffc); +} + +/*ARGSUSED*/ +static long +extract_ds (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The LI field in an I form instruction. The lower two bits are + forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_li (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0x3fffffc); +} + +/*ARGSUSED*/ +static long +extract_li (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x2000000) != 0) + return (insn & 0x3fffffc) - 0x4000000; + else + return insn & 0x3fffffc; +} + +/* The MB and ME fields in an M form instruction expressed as a single + operand which is itself a bitmask. The extraction function always + marks it as invalid, since we never want to recognize an + instruction which uses a field of this type. */ + +static unsigned long +insert_mbe (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + unsigned long uval; + int mb, me; + + uval = value; + + if (uval == 0) + { + if (errmsg != (const char **) NULL) + *errmsg = "illegal bitmask"; + return insn; + } + + me = 31; + while ((uval & 1) == 0) + { + uval >>= 1; + --me; + } + + mb = me; + uval >>= 1; + while ((uval & 1) != 0) + { + uval >>= 1; + --mb; + } + + if (uval != 0) + { + if (errmsg != (const char **) NULL) + *errmsg = "illegal bitmask"; + } + + return insn | (mb << 6) | (me << 1); +} + +static long +extract_mbe (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + int mb, me; + int i; + + if (invalid != (int *) NULL) + *invalid = 1; + + ret = 0; + mb = (insn >> 6) & 0x1f; + me = (insn >> 1) & 0x1f; + for (i = mb; i < me; i++) + ret |= 1 << (31 - i); + return ret; +} + +/* The MB or ME field in an MD or MDS form instruction. The high bit + is wrapped to the low end. */ + +/*ARGSUSED*/ +static unsigned long +insert_mb6 (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 6) | (value & 0x20); +} + +/*ARGSUSED*/ +static long +extract_mb6 (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 6) & 0x1f) | (insn & 0x20); +} + +/* The NB field in an X form instruction. The value 32 is stored as + 0. */ + +static unsigned long +insert_nb (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value < 0 || value > 32) + *errmsg = "value out of range"; + if (value == 32) + value = 0; + return insn | ((value & 0x1f) << 11); +} + +/*ARGSUSED*/ +static long +extract_nb (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + + ret = (insn >> 11) & 0x1f; + if (ret == 0) + ret = 32; + return ret; +} + +/* The NSI field in a D form instruction. This is the same as the SI + field, only negated. The extraction function always marks it as + invalid, since we never want to recognize an instruction which uses + a field of this type. */ + +/*ARGSUSED*/ +static unsigned long +insert_nsi (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((- value) & 0xffff); +} + +static long +extract_nsi (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL) + *invalid = 1; + if ((insn & 0x8000) != 0) + return - ((insn & 0xffff) - 0x10000); + else + return - (insn & 0xffff); +} + +/* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ + +static unsigned long +insert_ral (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0 + || value == ((insn >> 21) & 0x1f)) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in an lmw instruction, which has special value + restrictions. */ + +static unsigned long +insert_ram (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value >= ((insn >> 21) & 0x1f)) + *errmsg = "index register in load range"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ + +static unsigned long +insert_ras (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. This operand is marked FAKE. The insertion + function just copies the BT field into the BA field, and the + extraction function just checks that the fields are the same. */ + +/*ARGSUSED*/ +static unsigned long +insert_rbs (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 21) & 0x1f) << 11); +} + +static long +extract_rbs (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The SH field in an MD form instruction. This is split. */ + +/*ARGSUSED*/ +static unsigned long +insert_sh6 (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); +} + +/*ARGSUSED*/ +static long +extract_sh6 (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); +} + +/* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ + +static unsigned long +insert_spr (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_spr (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); +} + +/* The TBR field in an XFX instruction. This is just like SPR, but it + is optional. When TBR is omitted, it must be inserted as 268 (the + magic number of the TB register). These functions treat 0 + (indicating an omitted optional operand) as 268. This means that + ``mftb 4,0'' is not handled correctly. This does not matter very + much, since the architecture manual does not define mftb as + accepting any values other than 268 or 269. */ + +#define TB (268) + +static unsigned long +insert_tbr (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0) + value = TB; + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_tbr (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + + ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); + if (ret == TB) + ret = 0; + return ret; +} + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) (((x) & 0x3f) << 26) +#define OP_MASK OP (0x3f) + +/* The main opcode combined with a trap code in the TO field of a D + form instruction. Used for extended mnemonics for the trap + instructions. */ +#define OPTO(x,to) (OP (x) | (((to) & 0x1f) << 21)) +#define OPTO_MASK (OP_MASK | TO_MASK) + +/* The main opcode combined with a comparison size bit in the L field + of a D form or X form instruction. Used for extended mnemonics for + the comparison instructions. */ +#define OPL(x,l) (OP (x) | (((l) & 1) << 21)) +#define OPL_MASK OPL (0x3f,1) + +/* An A form instruction. */ +#define A(op, xop, rc) (OP (op) | (((xop) & 0x1f) << 1) | ((rc) & 1)) +#define A_MASK A (0x3f, 0x1f, 1) + +/* An A_MASK with the FRB field fixed. */ +#define AFRB_MASK (A_MASK | FRB_MASK) + +/* An A_MASK with the FRC field fixed. */ +#define AFRC_MASK (A_MASK | FRC_MASK) + +/* An A_MASK with the FRA and FRC fields fixed. */ +#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) + +/* A B form instruction. */ +#define B(op, aa, lk) (OP (op) | (((aa) & 1) << 1) | ((lk) & 1)) +#define B_MASK B (0x3f, 1, 1) + +/* A B form instruction setting the BO field. */ +#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | (((bo) & 0x1f) << 21)) +#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) + +/* A BBO_MASK with the y bit of the BO field removed. This permits + matching a conditional branch regardless of the setting of the y + bit. */ +#define Y_MASK (1 << 21) +#define BBOY_MASK (BBO_MASK &~ Y_MASK) + +/* A B form instruction setting the BO field and the condition bits of + the BI field. */ +#define BBOCB(op, bo, cb, aa, lk) \ + (BBO ((op), (bo), (aa), (lk)) | (((cb) & 0x3) << 16)) +#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) + +/* A BBOCB_MASK with the y bit of the BO field removed. */ +#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) + +/* A BBOYCB_MASK in which the BI field is fixed. */ +#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) + +/* The main opcode mask with the RA field clear. */ +#define DRA_MASK (OP_MASK | RA_MASK) + +/* A DS form instruction. */ +#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) +#define DS_MASK DSO (0x3f, 3) + +/* An M form instruction. */ +#define M(op, rc) (OP (op) | ((rc) & 1)) +#define M_MASK M (0x3f, 1) + +/* An M form instruction with the ME field specified. */ +#define MME(op, me, rc) (M ((op), (rc)) | (((me) & 0x1f) << 1)) + +/* An M_MASK with the MB and ME fields fixed. */ +#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) + +/* An M_MASK with the SH and ME fields fixed. */ +#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) + +/* An MD form instruction. */ +#define MD(op, xop, rc) (OP (op) | (((xop) & 0x7) << 2) | ((rc) & 1)) +#define MD_MASK MD (0x3f, 0x7, 1) + +/* An MD_MASK with the MB field fixed. */ +#define MDMB_MASK (MD_MASK | MB6_MASK) + +/* An MD_MASK with the SH field fixed. */ +#define MDSH_MASK (MD_MASK | SH6_MASK) + +/* An MDS form instruction. */ +#define MDS(op, xop, rc) (OP (op) | (((xop) & 0xf) << 1) | ((rc) & 1)) +#define MDS_MASK MDS (0x3f, 0xf, 1) + +/* An MDS_MASK with the MB field fixed. */ +#define MDSMB_MASK (MDS_MASK | MB6_MASK) + +/* An SC form instruction. */ +#define SC(op, sa, lk) (OP (op) | (((sa) & 1) << 1) | ((lk) & 1)) +#define SC_MASK (OP_MASK | (0x3ff << 16) | (1 << 1) | 1) + +/* An X form instruction. */ +#define X(op, xop) (OP (op) | (((xop) & 0x3ff) << 1)) + +/* An X form instruction with the RC bit specified. */ +#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) + +/* The mask for an X form instruction. */ +#define X_MASK XRC (0x3f, 0x3ff, 1) + +/* An X_MASK with the RA field fixed. */ +#define XRA_MASK (X_MASK | RA_MASK) + +/* An X_MASK with the RB field fixed. */ +#define XRB_MASK (X_MASK | RB_MASK) + +/* An X_MASK with the RT field fixed. */ +#define XRT_MASK (X_MASK | RT_MASK) + +/* An X_MASK with the RA and RB fields fixed. */ +#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) + +/* An X_MASK with the RT and RA fields fixed. */ +#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) + +/* An X form comparison instruction. */ +#define XCMPL(op, xop, l) (X ((op), (xop)) | (((l) & 1) << 21)) + +/* The mask for an X form comparison instruction. */ +#define XCMP_MASK (X_MASK | (1 << 22)) + +/* The mask for an X form comparison instruction with the L field + fixed. */ +#define XCMPL_MASK (XCMP_MASK | (1 << 21)) + +/* An X form trap instruction with the TO field specified. */ +#define XTO(op, xop, to) (X ((op), (xop)) | (((to) & 0x1f) << 21)) +#define XTO_MASK (X_MASK | TO_MASK) + +/* An XFL form instruction. */ +#define XFL(op, xop, rc) (OP (op) | (((xop) & 0x3ff) << 1) | ((rc) & 1)) +#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (1 << 25) | (1 << 16)) + +/* An XL form instruction with the LK field set to 0. */ +#define XL(op, xop) (OP (op) | (((xop) & 0x3ff) << 1)) + +/* An XL form instruction which uses the LK field. */ +#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) + +/* The mask for an XL form instruction. */ +#define XL_MASK XLLK (0x3f, 0x3ff, 1) + +/* An XL form instruction which explicitly sets the BO field. */ +#define XLO(op, bo, xop, lk) \ + (XLLK ((op), (xop), (lk)) | (((bo) & 0x1f) << 21)) +#define XLO_MASK (XL_MASK | BO_MASK) + +/* An XL form instruction which explicitly sets the y bit of the BO + field. */ +#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | (((y) & 1) << 21)) +#define XLYLK_MASK (XL_MASK | Y_MASK) + +/* An XL form instruction which sets the BO field and the condition + bits of the BI field. */ +#define XLOCB(op, bo, cb, xop, lk) \ + (XLO ((op), (bo), (xop), (lk)) | (((cb) & 3) << 16)) +#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) + +/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ +#define XLBB_MASK (XL_MASK | BB_MASK) +#define XLYBB_MASK (XLYLK_MASK | BB_MASK) +#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) + +/* An XL_MASK with the BO and BB fields fixed. */ +#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) + +/* An XL_MASK with the BO, BI and BB fields fixed. */ +#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) + +/* An XO form instruction. */ +#define XO(op, xop, oe, rc) \ + (OP (op) | (((xop) & 0x1ff) << 1) | (((oe) & 1) << 10) | ((rc) & 1)) +#define XO_MASK XO (0x3f, 0x1ff, 1, 1) + +/* An XO_MASK with the RB field fixed. */ +#define XORB_MASK (XO_MASK | RB_MASK) + +/* An XS form instruction. */ +#define XS(op, xop, rc) (OP (op) | (((xop) & 0x1ff) << 2) | ((rc) & 1)) +#define XS_MASK XS (0x3f, 0x1ff, 1) + +/* A mask for the FXM version of an XFX form instruction. */ +#define XFXFXM_MASK (X_MASK | (1 << 20) | (1 << 11)) + +/* An XFX form instruction with the FXM field filled in. */ +#define XFXM(op, xop, fxm) \ + (X ((op), (xop)) | (((fxm) & 0xff) << 12)) + +/* An XFX form instruction with the SPR field filled in. */ +#define XSPR(op, xop, spr) \ + (X ((op), (xop)) | (((spr) & 0x1f) << 16) | (((spr) & 0x3e0) << 6)) +#define XSPR_MASK (X_MASK | SPR_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRBAT field. */ +#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRG field. */ +#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK) + +/* The BO encodings used in extended conditional branch mnemonics. */ +#define BODNZF (0x0) +#define BODNZFP (0x1) +#define BODZF (0x2) +#define BODZFP (0x3) +#define BOF (0x4) +#define BOFP (0x5) +#define BODNZT (0x8) +#define BODNZTP (0x9) +#define BODZT (0xa) +#define BODZTP (0xb) +#define BOT (0xc) +#define BOTP (0xd) +#define BODNZ (0x10) +#define BODNZP (0x11) +#define BODZ (0x12) +#define BODZP (0x13) +#define BOU (0x14) + +/* The BI condition bit encodings used in extended conditional branch + mnemonics. */ +#define CBLT (0) +#define CBGT (1) +#define CBEQ (2) +#define CBSO (3) + +/* The TO encodings used in extended trap mnemonics. */ +#define TOLGT (0x1) +#define TOLLT (0x2) +#define TOEQ (0x4) +#define TOLGE (0x5) +#define TOLNL (0x5) +#define TOLLE (0x6) +#define TOLNG (0x6) +#define TOGT (0x8) +#define TOGE (0xc) +#define TONL (0xc) +#define TOLT (0x10) +#define TOLE (0x14) +#define TONG (0x14) +#define TONE (0x18) +#define TOU (0x1f) + +/* Smaller names for the flags so each entry in the opcodes table will + fit on a single line. */ +#undef PPC +#define PPC PPC_OPCODE_PPC +#define POWER PPC_OPCODE_POWER +#define POWER2 PPC_OPCODE_POWER2 +#define B32 PPC_OPCODE_32 +#define B64 PPC_OPCODE_64 +#define M601 PPC_OPCODE_601 + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK FLAGS { OPERANDS } + + NAME is the name of the instruction. + OPCODE is the instruction opcode. + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + FLAGS are flags indicated what processors support the instruction. + OPERANDS is the list of operands. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. It is also + sorted by major opcode. */ + +const struct powerpc_opcode powerpc_opcodes[] = { +{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdi", OP(2), OP_MASK, PPC|B64, { TO, RA, SI } }, + +{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPC, { RA, SI } }, +{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, POWER, { RA, SI } }, +{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPC, { RA, SI } }, +{ "tllti", OPTO(3,TOLLT), OPTO_MASK, POWER, { RA, SI } }, +{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPC, { RA, SI } }, +{ "teqi", OPTO(3,TOEQ), OPTO_MASK, POWER, { RA, SI } }, +{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPC, { RA, SI } }, +{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, POWER, { RA, SI } }, +{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPC, { RA, SI } }, +{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, POWER, { RA, SI } }, +{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPC, { RA, SI } }, +{ "tllei", OPTO(3,TOLLE), OPTO_MASK, POWER, { RA, SI } }, +{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPC, { RA, SI } }, +{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, POWER, { RA, SI } }, +{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPC, { RA, SI } }, +{ "tgti", OPTO(3,TOGT), OPTO_MASK, POWER, { RA, SI } }, +{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPC, { RA, SI } }, +{ "tgei", OPTO(3,TOGE), OPTO_MASK, POWER, { RA, SI } }, +{ "twnli", OPTO(3,TONL), OPTO_MASK, PPC, { RA, SI } }, +{ "tnli", OPTO(3,TONL), OPTO_MASK, POWER, { RA, SI } }, +{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPC, { RA, SI } }, +{ "tlti", OPTO(3,TOLT), OPTO_MASK, POWER, { RA, SI } }, +{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPC, { RA, SI } }, +{ "tlei", OPTO(3,TOLE), OPTO_MASK, POWER, { RA, SI } }, +{ "twngi", OPTO(3,TONG), OPTO_MASK, PPC, { RA, SI } }, +{ "tngi", OPTO(3,TONG), OPTO_MASK, POWER, { RA, SI } }, +{ "twnei", OPTO(3,TONE), OPTO_MASK, PPC, { RA, SI } }, +{ "tnei", OPTO(3,TONE), OPTO_MASK, POWER, { RA, SI } }, +{ "twi", OP(3), OP_MASK, PPC, { TO, RA, SI } }, +{ "ti", OP(3), OP_MASK, POWER, { TO, RA, SI } }, + +{ "mulli", OP(7), OP_MASK, PPC, { RT, RA, SI } }, +{ "muli", OP(7), OP_MASK, POWER, { RT, RA, SI } }, + +{ "subfic", OP(8), OP_MASK, PPC, { RT, RA, SI } }, +{ "sfi", OP(8), OP_MASK, POWER, { RT, RA, SI } }, + +{ "dozi", OP(9), OP_MASK, POWER|M601, { RT, RA, SI } }, + +{ "cmplwi", OPL(10,0), OPL_MASK, PPC, { OBF, RA, UI } }, +{ "cmpldi", OPL(10,1), OPL_MASK, PPC|B64, { OBF, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, POWER, { BF, RA, UI } }, + +{ "cmpwi", OPL(11,0), OPL_MASK, PPC, { OBF, RA, SI } }, +{ "cmpdi", OPL(11,1), OPL_MASK, PPC|B64, { OBF, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, POWER, { BF, RA, SI } }, + +{ "addic", OP(12), OP_MASK, PPC, { RT, RA, SI } }, +{ "ai", OP(12), OP_MASK, POWER, { RT, RA, SI } }, +{ "subic", OP(12), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "addic.", OP(13), OP_MASK, PPC, { RT, RA, SI } }, +{ "ai.", OP(13), OP_MASK, POWER, { RT, RA, SI } }, +{ "subic.", OP(13), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "li", OP(14), DRA_MASK, PPC, { RT, SI } }, +{ "lil", OP(14), DRA_MASK, POWER, { RT, SI } }, +{ "addi", OP(14), OP_MASK, PPC, { RT, RA, SI } }, +{ "cal", OP(14), OP_MASK, POWER, { RT, D, RA } }, +{ "subi", OP(14), OP_MASK, PPC, { RT, RA, NSI } }, +{ "la", OP(14), OP_MASK, PPC, { RT, D, RA } }, + +{ "lis", OP(15), DRA_MASK, PPC, { RT, SISIGNOPT } }, +{ "liu", OP(15), DRA_MASK, POWER, { RT, SISIGNOPT } }, +{ "addis", OP(15), OP_MASK, PPC, { RT,RA,SISIGNOPT } }, +{ "cau", OP(15), OP_MASK, POWER, { RT,RA,SISIGNOPT } }, +{ "subis", OP(15), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "bdnz-", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BDM } }, +{ "bdnz+", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BDP } }, +{ "bdnz", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BD } }, +{ "bdn", BBO(16,BODNZ,0,0), BBOYBI_MASK, POWER, { BD } }, +{ "bdnzl-", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BDM } }, +{ "bdnzl+", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BDP } }, +{ "bdnzl", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BD } }, +{ "bdnl", BBO(16,BODNZ,0,1), BBOYBI_MASK, POWER, { BD } }, +{ "bdnza-", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdnza+", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdnza", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDA } }, +{ "bdna", BBO(16,BODNZ,1,0), BBOYBI_MASK, POWER, { BDA } }, +{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdnzla", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDA } }, +{ "bdnla", BBO(16,BODNZ,1,1), BBOYBI_MASK, POWER, { BDA } }, +{ "bdz-", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC, { BDM } }, +{ "bdz+", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC, { BDP } }, +{ "bdz", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC|POWER, { BD } }, +{ "bdzl-", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC, { BDM } }, +{ "bdzl+", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC, { BDP } }, +{ "bdzl", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC|POWER, { BD } }, +{ "bdza-", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdza+", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdza", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC|POWER, { BDA } }, +{ "bdzla-", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdzla+", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdzla", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC|POWER, { BDA } }, +{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } }, +{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bt-", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bt+", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bt", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bbt", BBO(16,BOT,0,0), BBOY_MASK, POWER, { BI, BD } }, +{ "btl-", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "btl+", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "btl", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bbtl", BBO(16,BOT,0,1), BBOY_MASK, POWER, { BI, BD } }, +{ "bta-", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bta+", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bta", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbta", BBO(16,BOT,1,0), BBOY_MASK, POWER, { BI, BDA } }, +{ "btla-", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "btla+", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "btla", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbtla", BBO(16,BOT,1,1), BBOY_MASK, POWER, { BI, BDA } }, +{ "bf-", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bf+", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bf", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bbf", BBO(16,BOF,0,0), BBOY_MASK, POWER, { BI, BD } }, +{ "bfl-", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bfl+", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bfl", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bbfl", BBO(16,BOF,0,1), BBOY_MASK, POWER, { BI, BD } }, +{ "bfa-", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bfa+", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bfa", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbfa", BBO(16,BOF,1,0), BBOY_MASK, POWER, { BI, BDA } }, +{ "bfla-", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bfla+", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bfla", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbfla", BBO(16,BOF,1,1), BBOY_MASK, POWER, { BI, BDA } }, +{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bc-", B(16,0,0), B_MASK, PPC, { BOE, BI, BDM } }, +{ "bc+", B(16,0,0), B_MASK, PPC, { BOE, BI, BDP } }, +{ "bc", B(16,0,0), B_MASK, PPC|POWER, { BO, BI, BD } }, +{ "bcl-", B(16,0,1), B_MASK, PPC, { BOE, BI, BDM } }, +{ "bcl+", B(16,0,1), B_MASK, PPC, { BOE, BI, BDP } }, +{ "bcl", B(16,0,1), B_MASK, PPC|POWER, { BO, BI, BD } }, +{ "bca-", B(16,1,0), B_MASK, PPC, { BOE, BI, BDMA } }, +{ "bca+", B(16,1,0), B_MASK, PPC, { BOE, BI, BDPA } }, +{ "bca", B(16,1,0), B_MASK, PPC|POWER, { BO, BI, BDA } }, +{ "bcla-", B(16,1,1), B_MASK, PPC, { BOE, BI, BDMA } }, +{ "bcla+", B(16,1,1), B_MASK, PPC, { BOE, BI, BDPA } }, +{ "bcla", B(16,1,1), B_MASK, PPC|POWER, { BO, BI, BDA } }, + +{ "sc", SC(17,1,0), 0xffffffff, PPC, { 0 } }, +{ "svc", SC(17,0,0), SC_MASK, POWER, { LEV, FL1, FL2 } }, +{ "svcl", SC(17,0,1), SC_MASK, POWER, { LEV, FL1, FL2 } }, +{ "svca", SC(17,1,0), SC_MASK, POWER, { SV } }, +{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, + +{ "b", B(18,0,0), B_MASK, PPC|POWER, { LI } }, +{ "bl", B(18,0,1), B_MASK, PPC|POWER, { LI } }, +{ "ba", B(18,1,0), B_MASK, PPC|POWER, { LIA } }, +{ "bla", B(18,1,1), B_MASK, PPC|POWER, { LIA } }, + +{ "mcrf", XL(19,0), XLBB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } }, + +{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, POWER, { 0 } }, +{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, POWER, { 0 } }, +{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, POWER, { BI } }, +{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, POWER, { BI } }, +{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, POWER, { BI } }, +{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, POWER, { BI } }, +{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bclr", XLLK(19,16,0), XLYBB_MASK, PPC, { BO, BI } }, +{ "bclrl", XLLK(19,16,1), XLYBB_MASK, PPC, { BO, BI } }, +{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcr", XLLK(19,16,0), XLBB_MASK, POWER, { BO, BI } }, +{ "bcrl", XLLK(19,16,1), XLBB_MASK, POWER, { BO, BI } }, + +{ "crnot", XL(19,33), XL_MASK, PPC, { BT, BA, BBA } }, +{ "crnor", XL(19,33), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "rfi", XL(19,50), 0xffffffff, PPC|POWER, { 0 } }, +{ "rfci", XL(19,51), 0xffffffff, PPC, { 0 } }, + +{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, + +{ "crandc", XL(19,129), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "isync", XL(19,150), 0xffffffff, PPC, { 0 } }, +{ "ics", XL(19,150), 0xffffffff, POWER, { 0 } }, + +{ "crclr", XL(19,193), XL_MASK, PPC, { BT, BAT, BBA } }, +{ "crxor", XL(19,193), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crnand", XL(19,225), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crand", XL(19,257), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crset", XL(19,289), XL_MASK, PPC, { BT, BAT, BBA } }, +{ "creqv", XL(19,289), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crorc", XL(19,417), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crmove", XL(19,449), XL_MASK, PPC, { BT, BA, BBA } }, +{ "cror", XL(19,449), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, PPC|POWER, { 0 } }, +{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, PPC|POWER, { 0 } }, +{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bcctr", XLLK(19,528,0), XLYBB_MASK, PPC, { BO, BI } }, +{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctrl", XLLK(19,528,1), XLYBB_MASK, PPC, { BO, BI } }, +{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcc", XLLK(19,528,0), XLBB_MASK, POWER, { BO, BI } }, +{ "bccl", XLLK(19,528,1), XLBB_MASK, POWER, { BO, BI } }, + +{ "rlwimi", M(20,0), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlimi", M(20,0), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rlwimi.", M(20,1), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlimi.", M(20,1), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rotlwi", MME(21,31,0), MMBME_MASK, PPC, { RA, RS, SH } }, +{ "clrlwi", MME(21,31,0), MSHME_MASK, PPC, { RA, RS, MB } }, +{ "rlwinm", M(21,0), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlinm", M(21,0), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, +{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPC, { RA,RS,SH } }, +{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPC, { RA, RS, MB } }, +{ "rlwinm.", M(21,1), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlinm.", M(21,1), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rlmi", M(22,0), M_MASK, POWER|M601, { RA,RS,RB,MBE,ME } }, +{ "rlmi.", M(22,1), M_MASK, POWER|M601, { RA,RS,RB,MBE,ME } }, + +{ "rotlw", MME(23,31,0), MMBME_MASK, PPC, { RA, RS, RB } }, +{ "rlwnm", M(23,0), M_MASK, PPC, { RA,RS,RB,MBE,ME } }, +{ "rlnm", M(23,0), M_MASK, POWER, { RA,RS,RB,MBE,ME } }, +{ "rotlw.", MME(23,31,1), MMBME_MASK, PPC, { RA, RS, RB } }, +{ "rlwnm.", M(23,1), M_MASK, PPC, { RA,RS,RB,MBE,ME } }, +{ "rlnm.", M(23,1), M_MASK, POWER, { RA,RS,RB,MBE,ME } }, + +{ "nop", OP(24), 0xffffffff, PPC, { 0 } }, +{ "ori", OP(24), OP_MASK, PPC, { RA, RS, UI } }, +{ "oril", OP(24), OP_MASK, POWER, { RA, RS, UI } }, + +{ "oris", OP(25), OP_MASK, PPC, { RA, RS, UI } }, +{ "oriu", OP(25), OP_MASK, POWER, { RA, RS, UI } }, + +{ "xori", OP(26), OP_MASK, PPC, { RA, RS, UI } }, +{ "xoril", OP(26), OP_MASK, POWER, { RA, RS, UI } }, + +{ "xoris", OP(27), OP_MASK, PPC, { RA, RS, UI } }, +{ "xoriu", OP(27), OP_MASK, POWER, { RA, RS, UI } }, + +{ "andi.", OP(28), OP_MASK, PPC, { RA, RS, UI } }, +{ "andil.", OP(28), OP_MASK, POWER, { RA, RS, UI } }, + +{ "andis.", OP(29), OP_MASK, PPC, { RA, RS, UI } }, +{ "andiu.", OP(29), OP_MASK, POWER, { RA, RS, UI } }, + +{ "rotldi", MD(30,0,0), MDMB_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "clrldi", MD(30,0,0), MDSH_MASK, PPC|B64, { RA, RS, MB6 } }, +{ "rldicl", MD(30,0,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC|B64, { RA, RS, MB6 } }, +{ "rldicl.", MD(30,0,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rldicr", MD(30,1,0), MD_MASK, PPC|B64, { RA, RS, SH6, ME6 } }, +{ "rldicr.", MD(30,1,1), MD_MASK, PPC|B64, { RA, RS, SH6, ME6 } }, + +{ "rldic", MD(30,2,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rldic.", MD(30,2,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rldimi", MD(30,3,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rldimi.", MD(30,3,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC|B64, { RA, RS, RB } }, +{ "rldcl", MDS(30,8,0), MDS_MASK, PPC|B64, { RA, RS, RB, MB6 } }, +{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC|B64, { RA, RS, RB } }, +{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC|B64, { RA, RS, RB, MB6 } }, + +{ "rldcr", MDS(30,9,0), MDS_MASK, PPC|B64, { RA, RS, RB, ME6 } }, +{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC|B64, { RA, RS, RB, ME6 } }, + +{ "cmpw", XCMPL(31,0,0), XCMPL_MASK, PPC, { OBF, RA, RB } }, +{ "cmpd", XCMPL(31,0,1), XCMPL_MASK, PPC|B64, { OBF, RA, RB } }, +{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmp", X(31,0), XCMPL_MASK, POWER, { BF, RA, RB } }, + +{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPC, { RA, RB } }, +{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, POWER, { RA, RB } }, +{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPC, { RA, RB } }, +{ "tllt", XTO(31,4,TOLLT), XTO_MASK, POWER, { RA, RB } }, +{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPC, { RA, RB } }, +{ "teq", XTO(31,4,TOEQ), XTO_MASK, POWER, { RA, RB } }, +{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPC, { RA, RB } }, +{ "tlge", XTO(31,4,TOLGE), XTO_MASK, POWER, { RA, RB } }, +{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPC, { RA, RB } }, +{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, POWER, { RA, RB } }, +{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPC, { RA, RB } }, +{ "tlle", XTO(31,4,TOLLE), XTO_MASK, POWER, { RA, RB } }, +{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPC, { RA, RB } }, +{ "tlng", XTO(31,4,TOLNG), XTO_MASK, POWER, { RA, RB } }, +{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPC, { RA, RB } }, +{ "tgt", XTO(31,4,TOGT), XTO_MASK, POWER, { RA, RB } }, +{ "twge", XTO(31,4,TOGE), XTO_MASK, PPC, { RA, RB } }, +{ "tge", XTO(31,4,TOGE), XTO_MASK, POWER, { RA, RB } }, +{ "twnl", XTO(31,4,TONL), XTO_MASK, PPC, { RA, RB } }, +{ "tnl", XTO(31,4,TONL), XTO_MASK, POWER, { RA, RB } }, +{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPC, { RA, RB } }, +{ "tlt", XTO(31,4,TOLT), XTO_MASK, POWER, { RA, RB } }, +{ "twle", XTO(31,4,TOLE), XTO_MASK, PPC, { RA, RB } }, +{ "tle", XTO(31,4,TOLE), XTO_MASK, POWER, { RA, RB } }, +{ "twng", XTO(31,4,TONG), XTO_MASK, PPC, { RA, RB } }, +{ "tng", XTO(31,4,TONG), XTO_MASK, POWER, { RA, RB } }, +{ "twne", XTO(31,4,TONE), XTO_MASK, PPC, { RA, RB } }, +{ "tne", XTO(31,4,TONE), XTO_MASK, POWER, { RA, RB } }, +{ "trap", XTO(31,4,TOU), 0xffffffff, PPC, { 0 } }, +{ "tw", X(31,4), X_MASK, PPC, { TO, RA, RB } }, +{ "t", X(31,4), X_MASK, POWER, { TO, RA, RB } }, + +{ "subfc", XO(31,8,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sf", XO(31,8,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfc.", XO(31,8,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sf.", XO(31,8,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subc.", XO(31,8,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco", XO(31,8,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfo", XO(31,8,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfo.", XO(31,8,1,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "addc", XO(31,10,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "a", XO(31,10,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addc.", XO(31,10,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "a.", XO(31,10,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addco", XO(31,10,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "ao", XO(31,10,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addco.", XO(31,10,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "ao.", XO(31,10,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mfcr", X(31,19), XRARB_MASK, POWER|PPC, { RT } }, + +{ "lwarx", X(31,20), X_MASK, PPC, { RT, RA, RB } }, + +{ "ldx", X(31,21), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "lwzx", X(31,23), X_MASK, PPC, { RT, RA, RB } }, +{ "lx", X(31,23), X_MASK, POWER, { RT, RA, RB } }, + +{ "slw", XRC(31,24,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sl", XRC(31,24,0), X_MASK, POWER, { RA, RS, RB } }, +{ "slw.", XRC(31,24,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sl.", XRC(31,24,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "cntlzw", XRC(31,26,0), XRB_MASK, PPC, { RA, RS } }, +{ "cntlz", XRC(31,26,0), XRB_MASK, POWER, { RA, RS } }, +{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPC, { RA, RS } }, +{ "cntlz.", XRC(31,26,1), XRB_MASK, POWER, { RA, RS } }, + +{ "sld", XRC(31,27,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "sld.", XRC(31,27,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "and", XRC(31,28,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "and.", XRC(31,28,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "maskg", XRC(31,29,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "maskg.", XRC(31,29,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "cmplw", XCMPL(31,32,0), XCMPL_MASK, PPC, { OBF, RA, RB } }, +{ "cmpld", XCMPL(31,32,1), XCMPL_MASK, PPC|B64, { OBF, RA, RB } }, +{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmpl", X(31,32), XCMPL_MASK, POWER, { BF, RA, RB } }, + +{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "ldux", X(31,53), X_MASK, PPC|B64, { RT, RAL, RB } }, + +{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, + +{ "lwzux", X(31,55), X_MASK, PPC, { RT, RAL, RB } }, +{ "lux", X(31,55), X_MASK, POWER, { RT, RA, RB } }, + +{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC|B64, { RA, RS } }, +{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC|B64, { RA, RS } }, + +{ "andc", XRC(31,60,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "andc.", XRC(31,60,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "td", X(31,68), X_MASK, PPC|B64, { TO, RA, RB } }, + +{ "mulhd", XO(31,73,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mfmsr", X(31,83), XRARB_MASK, PPC|POWER, { RT } }, + +{ "ldarx", X(31,84), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "dcbf", X(31,86), XRT_MASK, PPC, { RA, RB } }, + +{ "lbzx", X(31,87), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "neg", XO(31,104,0,0), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "neg.", XO(31,104,0,1), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "nego", XO(31,104,1,0), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "nego.", XO(31,104,1,1), XORB_MASK, PPC|POWER, { RT, RA } }, + +{ "mul", XO(31,107,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mul.", XO(31,107,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mulo", XO(31,107,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mulo.", XO(31,107,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "clf", X(31,118), XRB_MASK, POWER, { RT, RA } }, + +{ "lbzux", X(31,119), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "not", XRC(31,124,0), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "nor", XRC(31,124,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "not.", XRC(31,124,1), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "nor.", XRC(31,124,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "subfe", XO(31,136,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfe", XO(31,136,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfe.", XO(31,136,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfe.", XO(31,136,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfeo", XO(31,136,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfeo", XO(31,136,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfeo.", XO(31,136,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfeo.", XO(31,136,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "adde", XO(31,138,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "ae", XO(31,138,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "adde.", XO(31,138,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "ae.", XO(31,138,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addeo", XO(31,138,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "aeo", XO(31,138,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addeo.", XO(31,138,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "aeo.", XO(31,138,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mtcr", XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, PPC|POWER, { RS }}, +{ "mtcrf", X(31,144), XFXFXM_MASK, PPC|POWER, { FXM, RS } }, + +{ "mtmsr", X(31,146), XRARB_MASK, PPC|POWER, { RS } }, +{ "mtmsrd", X(31,178), XRARB_MASK, PPC|POWER, { RS } }, + +{ "stdx", X(31,149), X_MASK, PPC|B64, { RS, RA, RB } }, + +{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA, RB } }, + +{ "stwx", X(31,151), X_MASK, PPC, { RS, RA, RB } }, +{ "stx", X(31,151), X_MASK, POWER, { RS, RA, RB } }, + +{ "slq", XRC(31,152,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "slq.", XRC(31,152,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sle", XRC(31,153,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sle.", XRC(31,153,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stdux", X(31,181), X_MASK, PPC|B64, { RS, RAS, RB } }, + +{ "stwux", X(31,183), X_MASK, PPC, { RS, RAS, RB } }, +{ "stux", X(31,183), X_MASK, POWER, { RS, RA, RB } }, + +{ "sliq", XRC(31,184,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sliq.", XRC(31,184,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "subfze", XO(31,200,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfze", XO(31,200,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfze.", XO(31,200,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfze.", XO(31,200,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfzeo", XO(31,200,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfzeo.", XO(31,200,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "addze", XO(31,202,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "aze", XO(31,202,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "addze.", XO(31,202,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "aze.", XO(31,202,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "addzeo", XO(31,202,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "azeo", XO(31,202,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "azeo.", XO(31,202,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mtsr", X(31,210), XRB_MASK|(1<<20), PPC|POWER|B32, { SR, RS } }, + +{ "stdcx.", XRC(31,214,1), X_MASK, PPC|B64, { RS, RA, RB } }, + +{ "stbx", X(31,215), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "sllq", XRC(31,216,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sllq.", XRC(31,216,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sleq", XRC(31,217,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sleq.", XRC(31,217,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "subfme", XO(31,232,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfme", XO(31,232,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfme.", XO(31,232,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfme.", XO(31,232,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfmeo", XO(31,232,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfmeo.", XO(31,232,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mulld", XO(31,233,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulld.", XO(31,233,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulldo", XO(31,233,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "addme", XO(31,234,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "ame", XO(31,234,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "addme.", XO(31,234,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "ame.", XO(31,234,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "addmeo", XO(31,234,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "ameo", XO(31,234,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "ameo.", XO(31,234,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mullw", XO(31,235,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "muls", XO(31,235,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullw.", XO(31,235,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "muls.", XO(31,235,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullwo", XO(31,235,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulso", XO(31,235,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullwo.", XO(31,235,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulso.", XO(31,235,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mtsrin", X(31,242), XRA_MASK, PPC|B32, { RS, RB } }, +{ "mtsri", X(31,242), XRA_MASK, POWER|B32, { RS, RB } }, + +{ "dcbtst", X(31,246), XRT_MASK, PPC, { RA, RB } }, + +{ "stbux", X(31,247), X_MASK, PPC|POWER, { RS, RAS, RB } }, + +{ "slliq", XRC(31,248,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "slliq.", XRC(31,248,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "doz", XO(31,264,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "doz.", XO(31,264,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "dozo", XO(31,264,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "dozo.", XO(31,264,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "add", XO(31,266,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "cax", XO(31,266,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "add.", XO(31,266,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "cax.", XO(31,266,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addo", XO(31,266,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "caxo", XO(31,266,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addo.", XO(31,266,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "caxo.", XO(31,266,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "lscbx", XRC(31,277,0), X_MASK, POWER|M601, { RT, RA, RB } }, +{ "lscbx.", XRC(31,277,1), X_MASK, POWER|M601, { RT, RA, RB } }, + +{ "dcbt", X(31,278), XRT_MASK, PPC, { RA, RB } }, + +{ "lhzx", X(31,279), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "icbt", X(31,262), XRT_MASK, PPC, { RA, RB } }, + +{ "eqv", XRC(31,284,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "eqv.", XRC(31,284,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "tlbie", X(31,306), XRTRA_MASK, PPC, { RB } }, +{ "tlbi", X(31,306), XRTRA_MASK, POWER, { RB } }, + +{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, + +{ "lhzux", X(31,311), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "xor", XRC(31,316,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "xor.", XRC(31,316,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "mfdcr", X(31,323), X_MASK, PPC, { RT, SPR } }, + +{ "div", XO(31,331,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "div.", XO(31,331,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divo", XO(31,331,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divo.", XO(31,331,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "mfmq", XSPR(31,339,0), XSPR_MASK, POWER|M601, { RT } }, +{ "mfxer", XSPR(31,339,1), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdec", XSPR(31,339,6), XSPR_MASK, POWER|M601, { RT } }, +{ "mflr", XSPR(31,339,8), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfctr", XSPR(31,339,9), XSPR_MASK, PPC|POWER, { RT } }, +{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, +{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdar", XSPR(31,339,19), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdec", XSPR(31,339,22), XSPR_MASK, PPC, { RT } }, +{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, +{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsprg", XSPR(31,339,272), XSPRG_MASK, PPC, { RT, SPRG } }, +{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC|B64, { RT } }, +{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, +{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, +{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfspr", X(31,339), X_MASK, PPC|POWER, { RT, SPR } }, + +{ "lwax", X(31,341), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "lhax", X(31,343), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "dccci", X(31,454), XRT_MASK, PPC, { RA, RB } }, + +{ "abs", XO(31,360,0,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abs.", XO(31,360,0,1), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abso", XO(31,360,1,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abso.", XO(31,360,1,1), XORB_MASK, POWER|M601, { RT, RA } }, + +{ "divs", XO(31,363,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divs.", XO(31,363,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divso", XO(31,363,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divso.", XO(31,363,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, + +{ "mftbu", XSPR(31,371,269), XSPR_MASK, PPC, { RT } }, +{ "mftb", X(31,371), X_MASK, PPC, { RT, TBR } }, + +{ "lwaux", X(31,373), X_MASK, PPC|B64, { RT, RAL, RB } }, + +{ "lhaux", X(31,375), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "sthx", X(31,407), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "orc", XRC(31,412,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "orc.", XRC(31,412,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "sradi", XS(31,413,0), XS_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "sradi.", XS(31,413,1), XS_MASK, PPC|B64, { RA, RS, SH6 } }, + +{ "slbie", X(31,434), XRTRA_MASK, PPC|B64, { RB } }, + +{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, + +{ "sthux", X(31,439), X_MASK, PPC|POWER, { RS, RAS, RB } }, + +{ "mr", XRC(31,444,0), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "or", XRC(31,444,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "mr.", XRC(31,444,1), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "or.", XRC(31,444,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "mtdcr", X(31,451), X_MASK, PPC, { SPR, RS } }, + +{ "divdu", XO(31,457,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdu.", XO(31,457,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divduo", XO(31,457,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divduo.", XO(31,457,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mtmq", XSPR(31,467,0), XSPR_MASK, POWER|M601, { RS } }, +{ "mtxer", XSPR(31,467,1), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtlr", XSPR(31,467,8), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtctr", XSPR(31,467,9), XSPR_MASK, PPC|POWER, { RS } }, +{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, +{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtdar", XSPR(31,467,19), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtdec", XSPR(31,467,22), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, +{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsprg", XSPR(31,467,272), XSPRG_MASK, PPC, { SPRG, RS } }, +{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC|B64, { RS } }, +{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, +{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, +{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, +{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtspr", X(31,467), X_MASK, PPC|POWER, { SPR, RS } }, + +{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, + +{ "nand", XRC(31,476,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "nand.", XRC(31,476,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "nabs", XO(31,488,0,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabs.", XO(31,488,0,1), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabso", XO(31,488,1,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabso.", XO(31,488,1,1), XORB_MASK, POWER|M601, { RT, RA } }, + +{ "divd", XO(31,489,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divd.", XO(31,489,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdo", XO(31,489,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdo.", XO(31,489,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "slbia", X(31,498), 0xffffffff, PPC|B64, { 0 } }, + +{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, + +{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), PPC|POWER, { BF } }, + +{ "clcs", X(31,531), XRB_MASK, POWER|M601, { RT, RA } }, + +{ "lswx", X(31,533), X_MASK, PPC, { RT, RA, RB } }, +{ "lsx", X(31,533), X_MASK, POWER, { RT, RA, RB } }, + +{ "lwbrx", X(31,534), X_MASK, PPC, { RT, RA, RB } }, +{ "lbrx", X(31,534), X_MASK, POWER, { RT, RA, RB } }, + +{ "lfsx", X(31,535), X_MASK, PPC|POWER, { FRT, RA, RB } }, + +{ "srw", XRC(31,536,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sr", XRC(31,536,0), X_MASK, POWER, { RA, RS, RB } }, +{ "srw.", XRC(31,536,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sr.", XRC(31,536,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "rrib", XRC(31,537,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "rrib.", XRC(31,537,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "srd", XRC(31,539,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "srd.", XRC(31,539,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "maskir", XRC(31,541,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "maskir.", XRC(31,541,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, + +{ "lfsux", X(31,567), X_MASK, PPC|POWER, { FRT, RAS, RB } }, + +{ "mfsr", X(31,595), XRB_MASK|(1<<20), PPC|POWER|B32, { RT, SR } }, + +{ "lswi", X(31,597), X_MASK, PPC, { RT, RA, NB } }, +{ "lsi", X(31,597), X_MASK, POWER, { RT, RA, NB } }, + +{ "sync", X(31,598), 0xffffffff, PPC, { 0 } }, +{ "dcs", X(31,598), 0xffffffff, POWER, { 0 } }, + +{ "lfdx", X(31,599), X_MASK, PPC|POWER, { FRT, RA, RB } }, + +{ "mfsri", X(31,627), X_MASK, POWER, { RT, RA, RB } }, + +{ "dclst", X(31,630), XRB_MASK, POWER, { RS, RA } }, + +{ "lfdux", X(31,631), X_MASK, PPC|POWER, { FRT, RAS, RB } }, + +{ "mfsrin", X(31,659), XRA_MASK, PPC|B32, { RT, RB } }, + +{ "stswx", X(31,661), X_MASK, PPC, { RS, RA, RB } }, +{ "stsx", X(31,661), X_MASK, POWER, { RS, RA, RB } }, + +{ "stwbrx", X(31,662), X_MASK, PPC, { RS, RA, RB } }, +{ "stbrx", X(31,662), X_MASK, POWER, { RS, RA, RB } }, + +{ "stfsx", X(31,663), X_MASK, PPC|POWER, { FRS, RA, RB } }, + +{ "srq", XRC(31,664,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srq.", XRC(31,664,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sre", XRC(31,665,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sre.", XRC(31,665,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stfsux", X(31,695), X_MASK, PPC|POWER, { FRS, RAS, RB } }, + +{ "sriq", XRC(31,696,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sriq.", XRC(31,696,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "stswi", X(31,725), X_MASK, PPC, { RS, RA, NB } }, +{ "stsi", X(31,725), X_MASK, POWER, { RS, RA, NB } }, + +{ "stfdx", X(31,727), X_MASK, PPC|POWER, { FRS, RA, RB } }, + +{ "srlq", XRC(31,728,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srlq.", XRC(31,728,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sreq", XRC(31,729,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sreq.", XRC(31,729,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stfdux", X(31,759), X_MASK, PPC|POWER, { FRS, RAS, RB } }, + +{ "srliq", XRC(31,760,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "srliq.", XRC(31,760,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "lhbrx", X(31,790), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "sraw", XRC(31,792,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sra", XRC(31,792,0), X_MASK, POWER, { RA, RS, RB } }, +{ "sraw.", XRC(31,792,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sra.", XRC(31,792,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "srad", XRC(31,794,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "srad.", XRC(31,794,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "rac", X(31,818), X_MASK, POWER, { RT, RA, RB } }, + +{ "srawi", XRC(31,824,0), X_MASK, PPC, { RA, RS, SH } }, +{ "srai", XRC(31,824,0), X_MASK, POWER, { RA, RS, SH } }, +{ "srawi.", XRC(31,824,1), X_MASK, PPC, { RA, RS, SH } }, +{ "srai.", XRC(31,824,1), X_MASK, POWER, { RA, RS, SH } }, + +{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, + +{ "sthbrx", X(31,918), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "sraq", XRC(31,920,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sraq.", XRC(31,920,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "srea", XRC(31,921,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srea.", XRC(31,921,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "extsh", XRC(31,922,0), XRB_MASK, PPC, { RA, RS } }, +{ "exts", XRC(31,922,0), XRB_MASK, POWER, { RA, RS } }, +{ "extsh.", XRC(31,922,1), XRB_MASK, PPC, { RA, RS } }, +{ "exts.", XRC(31,922,1), XRB_MASK, POWER, { RA, RS } }, + +{ "sraiq", XRC(31,952,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sraiq.", XRC(31,952,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, +{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, + +{ "iccci", X(31,966), XRT_MASK, PPC, { RA, RB } }, + +{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, + +{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA, RB } }, + +{ "extsw", XRC(31,986,0), XRB_MASK, PPC, { RA, RS } }, +{ "extsw.", XRC(31,986,1), XRB_MASK, PPC, { RA, RS } }, + +{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, +{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, + +{ "lwz", OP(32), OP_MASK, PPC, { RT, D, RA } }, +{ "l", OP(32), OP_MASK, POWER, { RT, D, RA } }, + +{ "lwzu", OP(33), OP_MASK, PPC, { RT, D, RAL } }, +{ "lu", OP(33), OP_MASK, POWER, { RT, D, RA } }, + +{ "lbz", OP(34), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lbzu", OP(35), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "stw", OP(36), OP_MASK, PPC, { RS, D, RA } }, +{ "st", OP(36), OP_MASK, POWER, { RS, D, RA } }, + +{ "stwu", OP(37), OP_MASK, PPC, { RS, D, RAS } }, +{ "stu", OP(37), OP_MASK, POWER, { RS, D, RA } }, + +{ "stb", OP(38), OP_MASK, PPC|POWER, { RS, D, RA } }, + +{ "stbu", OP(39), OP_MASK, PPC|POWER, { RS, D, RAS } }, + +{ "lhz", OP(40), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lhzu", OP(41), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "lha", OP(42), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lhau", OP(43), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "sth", OP(44), OP_MASK, PPC|POWER, { RS, D, RA } }, + +{ "sthu", OP(45), OP_MASK, PPC|POWER, { RS, D, RAS } }, + +{ "lmw", OP(46), OP_MASK, PPC, { RT, D, RAM } }, +{ "lm", OP(46), OP_MASK, POWER, { RT, D, RA } }, + +{ "stmw", OP(47), OP_MASK, PPC, { RS, D, RA } }, +{ "stm", OP(47), OP_MASK, POWER, { RS, D, RA } }, + +{ "lfs", OP(48), OP_MASK, PPC|POWER, { FRT, D, RA } }, + +{ "lfsu", OP(49), OP_MASK, PPC|POWER, { FRT, D, RAS } }, + +{ "lfd", OP(50), OP_MASK, PPC|POWER, { FRT, D, RA } }, + +{ "lfdu", OP(51), OP_MASK, PPC|POWER, { FRT, D, RAS } }, + +{ "stfs", OP(52), OP_MASK, PPC|POWER, { FRS, D, RA } }, + +{ "stfsu", OP(53), OP_MASK, PPC|POWER, { FRS, D, RAS } }, + +{ "stfd", OP(54), OP_MASK, PPC|POWER, { FRS, D, RA } }, + +{ "stfdu", OP(55), OP_MASK, PPC|POWER, { FRS, D, RAS } }, + +{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA } }, + +{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA } }, + +{ "ld", DSO(58,0), DS_MASK, PPC|B64, { RT, DS, RA } }, + +{ "ldu", DSO(58,1), DS_MASK, PPC|B64, { RT, DS, RAL } }, + +{ "lwa", DSO(58,2), DS_MASK, PPC|B64, { RT, DS, RA } }, + +{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fres", A(59,24,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fres.", A(59,24,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, + +{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "std", DSO(62,0), DS_MASK, PPC|B64, { RS, DS, RA } }, + +{ "stdu", DSO(62,1), DS_MASK, PPC|B64, { RS, DS, RAS } }, + +{ "fcmpu", X(63,0), X_MASK|(3<<21), PPC|POWER, { BF, FRA, FRB } }, + +{ "frsp", XRC(63,12,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "frsp.", XRC(63,12,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "fctiw", XRC(63,14,0), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiw.", XRC(63,14,1), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fctiwz", XRC(63,15,0), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fdiv", A(63,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fd", A(63,18,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fdiv.", A(63,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fd.", A(63,18,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fsub", A(63,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fs", A(63,20,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fsub.", A(63,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fs.", A(63,20,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fadd", A(63,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fa", A(63,21,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fadd.", A(63,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fa.", A(63,21,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPC|POWER2, { FRT, FRB } }, +{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPC|POWER2, { FRT, FRB } }, + +{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmul", A(63,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fm", A(63,25,0), AFRB_MASK, POWER, { FRT, FRA, FRC } }, +{ "fmul.", A(63,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fm.", A(63,25,1), AFRB_MASK, POWER, { FRT, FRA, FRC } }, + +{ "frsqrte", A(63,26,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "frsqrte.",A(63,26,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fmsub", A(63,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fms", A(63,28,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fmsub.", A(63,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fms.", A(63,28,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fmadd", A(63,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fma", A(63,29,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fmadd.", A(63,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fma.", A(63,29,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fnmsub", A(63,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnms", A(63,30,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fnmsub.", A(63,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnms.", A(63,30,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fnmadd", A(63,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnma", A(63,31,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fnmadd.", A(63,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnma.", A(63,31,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fcmpo", X(63,30), X_MASK|(3<<21), PPC|POWER, { BF, FRA, FRB } }, + +{ "mtfsb1", XRC(63,38,0), XRARB_MASK, PPC|POWER, { BT } }, +{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, PPC|POWER, { BT } }, + +{ "fneg", XRC(63,40,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fneg.", XRC(63,40,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } }, + +{ "mtfsb0", XRC(63,70,0), XRARB_MASK, PPC|POWER, { BT } }, +{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, PPC|POWER, { BT } }, + +{ "fmr", XRC(63,72,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fmr.", XRC(63,72,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mtfsfi", XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } }, +{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } }, + +{ "fnabs", XRC(63,136,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fnabs.", XRC(63,136,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "fabs", XRC(63,264,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fabs.", XRC(63,264,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mffs", XRC(63,583,0), XRARB_MASK, PPC|POWER, { FRT } }, +{ "mffs.", XRC(63,583,1), XRARB_MASK, PPC|POWER, { FRT } }, + +{ "mtfsf", XFL(63,711,0), XFL_MASK, PPC|POWER, { FLM, FRB } }, +{ "mtfsf.", XFL(63,711,1), XFL_MASK, PPC|POWER, { FLM, FRB } }, + +{ "fctid", XRC(63,814,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fctid.", XRC(63,814,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +{ "fctidz", XRC(63,815,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +{ "fcfid", XRC(63,846,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +}; + +const int powerpc_num_opcodes = + sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); + +/* The macro table. This is only used by the assembler. */ + +const struct powerpc_macro powerpc_macros[] = { +{ "extldi", 4, PPC|B64, "rldicr %0,%1,%3,(%2)-1" }, +{ "extldi.", 4, PPC|B64, "rldicr. %0,%1,%3,(%2)-1" }, +{ "extrdi", 4, PPC|B64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, +{ "extrdi.", 4, PPC|B64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, +{ "insrdi", 4, PPC|B64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, +{ "insrdi.", 4, PPC|B64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, +{ "rotrdi", 3, PPC|B64, "rldicl %0,%1,64-(%2),0" }, +{ "rotrdi.", 3, PPC|B64, "rldicl. %0,%1,64-(%2),0" }, +{ "sldi", 3, PPC|B64, "rldicr %0,%1,%2,63-(%2)" }, +{ "sldi.", 3, PPC|B64, "rldicr. %0,%1,%2,63-(%2)" }, +{ "srdi", 3, PPC|B64, "rldicl %0,%1,64-(%2),%2" }, +{ "srdi.", 3, PPC|B64, "rldicl. %0,%1,64-(%2),%2" }, +{ "clrrdi", 3, PPC|B64, "rldicr %0,%1,0,63-(%2)" }, +{ "clrrdi.", 3, PPC|B64, "rldicr. %0,%1,0,63-(%2)" }, +{ "clrlsldi",4, PPC|B64, "rldic %0,%1,%3,(%2)-(%3)" }, +{ "clrlsldi.",4, PPC|B64, "rldic. %0,%1,%3,(%2)-(%3)" }, + +{ "extlwi", 4, PPC, "rlwinm %0,%1,%3,0,(%2)-1" }, +{ "extlwi.", 4, PPC, "rlwinm. %0,%1,%3,0,(%2)-1" }, +{ "extrwi", 4, PPC, "rlwinm %0,%1,(%2)+(%3),32-(%2),31" }, +{ "extrwi.", 4, PPC, "rlwinm. %0,%1,(%2)+(%3),32-(%2),31" }, +{ "inslwi", 4, PPC, "rlwimi %0,%1,32-(%3),%3,(%2)+(%3)-1" }, +{ "inslwi.", 4, PPC, "rlwimi. %0,%1,32-(%3),%3,(%2)+(%3)-1" }, +{ "insrwi", 4, PPC, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, +{ "insrwi.", 4, PPC, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, +{ "rotrwi", 3, PPC, "rlwinm %0,%1,32-(%2),0,31" }, +{ "rotrwi.", 3, PPC, "rlwinm. %0,%1,32-(%2),0,31" }, +{ "slwi", 3, PPC, "rlwinm %0,%1,%2,0,31-(%2)" }, +{ "sli", 3, POWER, "rlinm %0,%1,%2,0,31-(%2)" }, +{ "slwi.", 3, PPC, "rlwinm. %0,%1,%2,0,31-(%2)" }, +{ "sli.", 3, POWER, "rlinm. %0,%1,%2,0,31-(%2)" }, +{ "srwi", 3, PPC, "rlwinm %0,%1,32-(%2),%2,31" }, +{ "sri", 3, POWER, "rlinm %0,%1,32-(%2),%2,31" }, +{ "srwi.", 3, PPC, "rlwinm. %0,%1,32-(%2),%2,31" }, +{ "sri.", 3, POWER, "rlinm. %0,%1,32-(%2),%2,31" }, +{ "clrrwi", 3, PPC, "rlwinm %0,%1,0,0,31-(%2)" }, +{ "clrrwi.", 3, PPC, "rlwinm. %0,%1,0,0,31-(%2)" }, +{ "clrlslwi",4, PPC, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, +{ "clrlslwi.",4, PPC, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, + +}; + +const int powerpc_num_macros = + sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); diff -urN linux-2.4.18/arch/ppc64/xmon/ppc.h linux-2.4.19-pre5/arch/ppc64/xmon/ppc.h --- linux-2.4.18/arch/ppc64/xmon/ppc.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,240 @@ +/* ppc.h -- Header file for PowerPC opcode table + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef PPC_H +#define PPC_H + +/* The opcode table is an array of struct powerpc_opcode. */ + +struct powerpc_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned long opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned long mask; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The defined values + are listed below. */ + unsigned long flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[8]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct powerpc_opcode powerpc_opcodes[]; +extern const int powerpc_num_opcodes; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* Opcode is defined for the PowerPC architecture. */ +#define PPC_OPCODE_PPC (01) + +/* Opcode is defined for the POWER (RS/6000) architecture. */ +#define PPC_OPCODE_POWER (02) + +/* Opcode is defined for the POWER2 (Rios 2) architecture. */ +#define PPC_OPCODE_POWER2 (04) + +/* Opcode is only defined on 32 bit architectures. */ +#define PPC_OPCODE_32 (010) + +/* Opcode is only defined on 64 bit architectures. */ +#define PPC_OPCODE_64 (020) + +/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 + is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, + but it also supports many additional POWER instructions. */ +#define PPC_OPCODE_601 (040) + +/* A macro to extract the major opcode from an instruction. */ +#define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* The operands table is an array of struct powerpc_operand. */ + +struct powerpc_operand +{ + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned long (*insert) PARAMS ((unsigned long instruction, long op, + const char **errmsg)); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & PPC_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + long (*extract) PARAMS ((unsigned long instruction, int *invalid)); + + /* One bit syntax flags. */ + unsigned long flags; +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct powerpc_operand powerpc_operands[]; + +/* Values defined for the flags field of a struct powerpc_operand. */ + +/* This operand takes signed values. */ +#define PPC_OPERAND_SIGNED (01) + +/* This operand takes signed values, but also accepts a full positive + range of values when running in 32 bit mode. That is, if bits is + 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, + this flag is ignored. */ +#define PPC_OPERAND_SIGNOPT (02) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics such as mr, for which two + operands fields are identical. The assembler should call the + insert function with any op value. The disassembler should call + the extract function, ignore the return value, and check the value + placed in the valid argument. */ +#define PPC_OPERAND_FAKE (04) + +/* The next operand should be wrapped in parentheses rather than + separated from this one by a comma. This is used for the load and + store instructions which want their operands to look like + reg,displacement(reg) + */ +#define PPC_OPERAND_PARENS (010) + +/* This operand may use the symbolic names for the CR fields, which + are + lt 0 gt 1 eq 2 so 3 un 3 + cr0 0 cr1 1 cr2 2 cr3 3 + cr4 4 cr5 5 cr6 6 cr7 7 + These may be combined arithmetically, as in cr2*4+gt. These are + only supported on the PowerPC, not the POWER. */ +#define PPC_OPERAND_CR (020) + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define PPC_OPERAND_GPR (040) + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define PPC_OPERAND_FPR (0100) + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_RELATIVE (0200) + +/* This operand is an absolute branch address. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_ABSOLUTE (0400) + +/* This operand is optional, and is zero if omitted. This is used for + the optional BF and L fields in the comparison instructions. The + assembler must count the number of operands remaining on the line, + and the number of operands remaining for the opcode, and decide + whether this operand is present or not. The disassembler should + print this operand out only if it is not zero. */ +#define PPC_OPERAND_OPTIONAL (01000) + +/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand + is omitted, then for the next operand use this operand value plus + 1, ignoring the next operand field for the opcode. This wretched + hack is needed because the Power rotate instructions can take + either 4 or 5 operands. The disassembler should print this operand + out regardless of the PPC_OPERAND_OPTIONAL field. */ +#define PPC_OPERAND_NEXT (02000) + +/* This operand should be regarded as a negative number for the + purposes of overflow checking (i.e., the normal most negative + number is disallowed and one more than the normal most positive + number is allowed). This flag will only be set for a signed + operand. */ +#define PPC_OPERAND_NEGATIVE (04000) + +/* The POWER and PowerPC assemblers use a few macros. We keep them + with the operands table for simplicity. The macro table is an + array of struct powerpc_macro. */ + +struct powerpc_macro +{ + /* The macro name. */ + const char *name; + + /* The number of operands the macro takes. */ + unsigned int operands; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The values are the + same as those for the struct powerpc_opcode flags field. */ + unsigned long flags; + + /* A format string to turn the macro into a normal instruction. + Each %N in the string is replaced with operand number N (zero + based). */ + const char *format; +}; + +extern const struct powerpc_macro powerpc_macros[]; +extern const int powerpc_num_macros; + +#endif /* PPC_H */ diff -urN linux-2.4.18/arch/ppc64/xmon/privinst.h linux-2.4.19-pre5/arch/ppc64/xmon/privinst.h --- linux-2.4.18/arch/ppc64/xmon/privinst.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/privinst.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,94 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include + +#define GETREG(reg) \ + static inline unsigned long get_ ## reg (void) \ + { unsigned long ret; asm volatile ("mf" #reg " %0" : "=r" (ret) :); return ret; } + +#define SETREG(reg) \ + static inline void set_ ## reg (unsigned long val) \ + { asm volatile ("mt" #reg " %0" : : "r" (val)); } + +GETREG(msr) +SETREG(msrd) +GETREG(cr) + +#define GSETSPR(n, name) \ + static inline long get_ ## name (void) \ + { long ret; asm volatile ("mfspr %0," #n : "=r" (ret) : ); return ret; } \ + static inline void set_ ## name (long val) \ + { asm volatile ("mtspr " #n ",%0" : : "r" (val)); } + +GSETSPR(0, mq) +GSETSPR(1, xer) +GSETSPR(4, rtcu) +GSETSPR(5, rtcl) +GSETSPR(8, lr) +GSETSPR(9, ctr) +GSETSPR(18, dsisr) +GSETSPR(19, dar) +GSETSPR(22, dec) +GSETSPR(25, sdr1) +GSETSPR(26, srr0) +GSETSPR(27, srr1) +GSETSPR(272, sprg0) +GSETSPR(273, sprg1) +GSETSPR(274, sprg2) +GSETSPR(275, sprg3) +GSETSPR(282, ear) +GSETSPR(287, pvr) +GSETSPR(528, bat0u) +GSETSPR(529, bat0l) +GSETSPR(530, bat1u) +GSETSPR(531, bat1l) +GSETSPR(532, bat2u) +GSETSPR(533, bat2l) +GSETSPR(534, bat3u) +GSETSPR(535, bat3l) +GSETSPR(1008, hid0) +GSETSPR(1009, hid1) +GSETSPR(1010, iabr) +GSETSPR(1013, dabr) +GSETSPR(1023, pir) + +static inline int get_sr(int n) +{ + int ret; + +#if 0 + // DRENG does not assemble + asm (" mfsrin %0,%1" : "=r" (ret) : "r" (n << 28)); +#endif + return ret; +} + +static inline void set_sr(int n, int val) +{ +#if 0 + // DRENG does not assemble + asm ("mtsrin %0,%1" : : "r" (val), "r" (n << 28)); +#endif +} + +static inline void store_inst(void *p) +{ + asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); +} + +static inline void cflush(void *p) +{ + asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); +} + +static inline void cinval(void *p) +{ + asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); +} + diff -urN linux-2.4.18/arch/ppc64/xmon/setjmp.c linux-2.4.19-pre5/arch/ppc64/xmon/setjmp.c --- linux-2.4.18/arch/ppc64/xmon/setjmp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/setjmp.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * NB this file must be compiled with -O2. + */ + +int +xmon_setjmp(long *buf) /* NOTE: assert(sizeof(buf) > 184) */ +{ + /* XXX should save fp regs as well */ + asm volatile ( + "mflr 0; std 0,0(%0)\n\ + std 1,8(%0)\n\ + std 2,16(%0)\n\ + mfcr 0; std 0,24(%0)\n\ + std 13,32(%0)\n\ + std 14,40(%0)\n\ + std 15,48(%0)\n\ + std 16,56(%0)\n\ + std 17,64(%0)\n\ + std 18,72(%0)\n\ + std 19,80(%0)\n\ + std 20,88(%0)\n\ + std 21,96(%0)\n\ + std 22,104(%0)\n\ + std 23,112(%0)\n\ + std 24,120(%0)\n\ + std 25,128(%0)\n\ + std 26,136(%0)\n\ + std 27,144(%0)\n\ + std 28,152(%0)\n\ + std 29,160(%0)\n\ + std 30,168(%0)\n\ + std 31,176(%0)\n\ + " : : "r" (buf)); + return 0; +} + +void +xmon_longjmp(long *buf, int val) +{ + if (val == 0) + val = 1; + asm volatile ( + "ld 13,32(%0)\n\ + ld 14,40(%0)\n\ + ld 15,48(%0)\n\ + ld 16,56(%0)\n\ + ld 17,64(%0)\n\ + ld 18,72(%0)\n\ + ld 19,80(%0)\n\ + ld 20,88(%0)\n\ + ld 21,96(%0)\n\ + ld 22,104(%0)\n\ + ld 23,112(%0)\n\ + ld 24,120(%0)\n\ + ld 25,128(%0)\n\ + ld 26,136(%0)\n\ + ld 27,144(%0)\n\ + ld 28,152(%0)\n\ + ld 29,160(%0)\n\ + ld 30,168(%0)\n\ + ld 31,176(%0)\n\ + ld 0,24(%0)\n\ + mtcrf 0x38,0\n\ + ld 0,0(%0)\n\ + ld 1,8(%0)\n\ + ld 2,16(%0)\n\ + mtlr 0\n\ + mr 3,%1\n\ + " : : "r" (buf), "r" (val)); +} diff -urN linux-2.4.18/arch/ppc64/xmon/start.c linux-2.4.19-pre5/arch/ppc64/xmon/start.c --- linux-2.4.18/arch/ppc64/xmon/start.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/start.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,340 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Transition to udbg isn't quite done yet...but very close. */ +#define USE_UDBG +#ifdef USE_UDBG +#include +#endif + +#ifndef USE_UDBG +static volatile unsigned char *sccc, *sccd; +#endif +unsigned long TXRDY, RXRDY; +extern void xmon_printf(const char *fmt, ...); +static int xmon_expect(const char *str, unsigned int timeout); + +#ifndef USE_UDBG +static int console = 0; +#endif +static int via_modem = 0; +/* static int xmon_use_sccb = 0; --Unused */ + +#define TB_SPEED 25000000 + +extern void *comport1; +static inline unsigned int readtb(void) +{ + unsigned int ret; + + asm volatile("mftb %0" : "=r" (ret) :); + return ret; +} + +#ifndef USE_UDBG +void buf_access(void) +{ + sccd[3] &= ~0x80; /* reset DLAB */ +} +#endif + +extern int adb_init(void); + +static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) +{ + xmon(pt_regs); +} +static struct sysrq_key_op sysrq_xmon_op = +{ + handler: sysrq_handle_xmon, + help_msg: "xmon", + action_msg: "Entering xmon\n", +}; + +void +xmon_map_scc(void) +{ + /* This maybe isn't the best place to register sysrq 'x' */ + __sysrq_put_key_op('x', &sysrq_xmon_op); +#ifndef USE_UDBG + /* should already be mapped by the kernel boot */ + sccd = (volatile unsigned char *) (((unsigned long)comport1)); + sccc = (volatile unsigned char *) (((unsigned long)comport1)+5); + TXRDY = 0x20; + RXRDY = 1; +#endif +} + +static int scc_initialized = 0; + +void xmon_init_scc(void); +extern void pmu_poll(void); + +int +xmon_write(void *handle, void *ptr, int nb) +{ +#ifdef USE_UDBG + return udbg_write(ptr, nb); +#else + char *p = ptr; + int i, c, ct; + + if (!scc_initialized) + xmon_init_scc(); + ct = 0; + for (i = 0; i < nb; ++i) { + while ((*sccc & TXRDY) == 0) { + } + c = p[i]; + if (c == '\n' && !ct) { + c = '\r'; + ct = 1; + --i; + } else { + if (console) + printk("%c", c); + ct = 0; + } + buf_access(); + *sccd = c; + } + return i; +#endif +} + +int xmon_wants_key; +int xmon_adb_keycode; + +int +xmon_read(void *handle, void *ptr, int nb) +{ +#ifdef USE_UDBG + return udbg_read(ptr, nb); +#else + char *p = ptr; + int i, c; + + if (!scc_initialized) + xmon_init_scc(); + for (i = 0; i < nb; ++i) { + do { + while ((*sccc & RXRDY) == 0) + ; + buf_access(); + c = *sccd; + } while (c == 0x11 || c == 0x13); + *p++ = c; + } + return i; +#endif +} + +int +xmon_read_poll(void) +{ +#ifdef USE_UDBG + return udbg_getc_poll(); +#else + if ((*sccc & RXRDY) == 0) { + return -1; + } + buf_access(); + return *sccd; +#endif +} + +void +xmon_init_scc() +{ +#ifndef USE_UDBG + sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ + sccd[0] = 12; eieio(); /* DLL = 9600 baud */ + sccd[1] = 0; eieio(); + sccd[2] = 0; eieio(); /* FCR = 0 */ + sccd[3] = 3; eieio(); /* LCR = 8N1 */ + sccd[1] = 0; eieio(); /* IER = 0 */ +#endif + + 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); + } + } +} + +void *xmon_stdin; +void *xmon_stdout; +void *xmon_stderr; + +void +xmon_init(void) +{ +} + +int +xmon_putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + xmon_putc('\r', f); + return xmon_write(f, &ch, 1) == 1? c: -1; +} + +int +xmon_putchar(int c) +{ + return xmon_putc(c, xmon_stdout); +} + +int +xmon_fputs(char *str, void *f) +{ + int n = strlen(str); + + return xmon_write(f, str, n) == n? 0: -1; +} + +int +xmon_readchar(void) +{ + char ch; + + for (;;) { + switch (xmon_read(xmon_stdin, &ch, 1)) { + case 1: + return ch; + case -1: + xmon_printf("read(stdin) returned -1\r\n", 0, 0); + return -1; + } + } +} + +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) + return 0; + continue; + } + if (c == '\n') + break; + if (c != '\r' && lineptr < &line[sizeof(line) - 1]) + *lineptr++ = c; + } + *lineptr = 0; + } while (strstr(line, str) == NULL); + return 1; +} + +int +xmon_getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = xmon_readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + xmon_putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + xmon_putchar('\b'); + xmon_putchar(' '); + xmon_putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + xmon_putchar('\a'); + else { + xmon_putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +char * +xmon_fgets(char *str, int nb, void *f) +{ + char *p; + int c; + + for (p = str; p < str + nb - 1; ) { + c = xmon_getchar(); + if (c == -1) { + if (p == str) + return 0; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = 0; + return str; +} diff -urN linux-2.4.18/arch/ppc64/xmon/subr_prf.c linux-2.4.19-pre5/arch/ppc64/xmon/subr_prf.c --- linux-2.4.18/arch/ppc64/xmon/subr_prf.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/subr_prf.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,55 @@ +/* + * Written by Cort Dougan to replace the version originally used + * by Paul Mackerras, which came from NetBSD and thus had copyright + * conflicts with Linux. + * + * This file makes liberal use of the standard linux utility + * routines to reduce the size of the binary. We assume we can + * trust some parts of Linux inside the debugger. + * -- Cort (cort@cs.nmt.edu) + * + * Copyright (C) 1999 Cort Dougan. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include "nonstdio.h" + +extern int xmon_write(void *, void *, int); + +void +xmon_vfprintf(void *f, const char *fmt, va_list ap) +{ + static char xmon_buf[2048]; + int n; + + n = vsprintf(xmon_buf, fmt, ap); + xmon_write(f, xmon_buf, n); +} + +void +xmon_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xmon_vfprintf(stdout, fmt, ap); + va_end(ap); +} + +void +xmon_fprintf(void *f, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xmon_vfprintf(f, fmt, ap); + va_end(ap); +} + diff -urN linux-2.4.18/arch/ppc64/xmon/xmon.c linux-2.4.19-pre5/arch/ppc64/xmon/xmon.c --- linux-2.4.18/arch/ppc64/xmon/xmon.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/ppc64/xmon/xmon.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2945 @@ +/* + * Routines providing a simple monitor for use on the PowerMac. + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nonstdio.h" +#include "privinst.h" +#include + +#include + +#include + +#define scanhex xmon_scanhex +#define skipbl xmon_skipbl + +#ifdef CONFIG_SMP +static unsigned long cpus_in_xmon = 0; +static unsigned long got_xmon = 0; +static volatile int take_xmon = -1; +#endif /* CONFIG_SMP */ + +static unsigned long adrs; +static int size = 1; +static unsigned long ndump = 64; +static unsigned long nidump = 16; +static unsigned long ncsum = 4096; +static int termch; + +static u_int bus_error_jmp[100]; +#define setjmp xmon_setjmp +#define longjmp xmon_longjmp + +#define memlist_entry list_entry +#define memlist_next(x) ((x)->next) +#define memlist_prev(x) ((x)->prev) + + +/* Max number of stack frames we are willing to produce on a backtrace. */ +#define MAXFRAMECOUNT 50 + +/* Breakpoint stuff */ +struct bpt { + unsigned long address; + unsigned instr; + unsigned long count; + unsigned char enabled; + char funcname[64]; /* function name for humans */ +}; + +#define NBPTS 16 +static struct bpt bpts[NBPTS]; +static struct bpt dabr; +static struct bpt iabr; +static unsigned bpinstr = 0x7fe00008; /* trap */ + +/* Prototypes */ +extern void (*debugger_fault_handler)(struct pt_regs *); +static int cmds(struct pt_regs *); +static int mread(unsigned long, void *, int); +static int mwrite(unsigned long, void *, int); +static void handle_fault(struct pt_regs *); +static void byterev(unsigned char *, int); +static void memex(void); +static int bsesc(void); +static void dump(void); +static void prdump(unsigned long, long); +#ifdef __MWERKS__ +static void prndump(unsigned, int); +static int nvreadb(unsigned); +#endif +static int ppc_inst_dump(unsigned long, long); +void print_address(unsigned long); +static int getsp(void); +static void dump_hash_table(void); +static void backtrace(struct pt_regs *); +static void excprint(struct pt_regs *); +static void prregs(struct pt_regs *); +static void memops(int); +static void memlocate(void); +static void memzcan(void); +static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); +int skipbl(void); +int scanhex(unsigned long *valp); +static void scannl(void); +static int hexdigit(int); +void getstring(char *, int); +static void flush_input(void); +static int inchar(void); +static void take_input(char *); +/* static void openforth(void); */ +static unsigned long read_spr(int); +static void write_spr(int, unsigned long); +static void super_regs(void); +static void print_sysmap(void); +static void remove_bpts(void); +static void insert_bpts(void); +static struct bpt *at_breakpoint(unsigned long pc); +static void bpt_cmds(void); +static void cacheflush(void); +#ifdef CONFIG_SMP +static void cpu_cmd(void); +#endif /* CONFIG_SMP */ +static void csum(void); +static void mem_translate(void); +static void mem_check(void); +static void mem_find_real(void); +static void mem_find_vsid(void); +static void mem_check_full_group(void); +static void mem_check_pagetable_vsids (void); + +static void mem_map_check_slab(void); +static void mem_map_lock_pages(void); +static void mem_map_check_hash(void); +static void mem_check_dup_rpn (void); +static void show_task(struct task_struct * p); +static void xmon_show_state(void); +static void debug_trace(void); + +extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long); +extern void printf(const char *fmt, ...); +extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); +extern int xmon_putc(int c, void *f); +extern int putchar(int ch); +extern int xmon_read_poll(void); +extern int setjmp(u_int *); +extern void longjmp(u_int *, int); +extern unsigned long _ASR; +extern struct Naca *naca; + +pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va); /* from htab.c */ + +#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) + +static char *help_string = "\ +Commands:\n\ + b show breakpoints\n\ + bd set data breakpoint\n\ + bi set instruction breakpoint\n\ + bc clear breakpoint\n\ + d dump bytes\n\ + di dump instructions\n\ + df dump float values\n\ + dd dump double values\n\ + e print exception information\n\ + f flush cache\n\ + h dump hash table\n\ + m examine/change memory\n\ + mm move a block of memory\n\ + ms set a block of memory\n\ + md compare two blocks of memory\n\ + ml locate a block of memory\n\ + mz zero a block of memory\n\ + mx translation information for an effective address\n\ + mi show information about memory allocation\n\ + M print System.map\n\ + p show the task list\n\ + r print registers\n\ + s single step\n\ + S print special registers\n\ + t print backtrace\n\ + T Enable/Disable PPCDBG flags\n\ + x exit monitor\n\ + z reboot\n\ +"; + +static int xmon_trace[NR_CPUS]; +#define SSTEP 1 /* stepping because of 's' command */ +#define BRSTEP 2 /* stepping over breakpoint */ + +/* + * Stuff for reading and writing memory safely + */ +extern inline void sync(void) +{ + asm volatile("sync; isync"); +} + +extern inline void __delay(unsigned int loops) +{ + if (loops != 0) + __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : : + "r" (loops) : "ctr"); +} + +/* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs). + A PPC stack frame looks like this: + + High Address + Back Chain + FP reg save area + GP reg save area + Local var space + Parameter save area (SP+48) + TOC save area (SP+40) + link editor doubleword (SP+32) + compiler doubleword (SP+24) + LR save (SP+16) + CR save (SP+8) + Back Chain (SP+0) + + Note that the LR (ret addr) may not be saved in the current frame if + no functions have been called from the current function. + */ + +/* + A traceback table typically follows each function. + The find_tb_table() func will fill in this struct. Note that the struct + is not an exact match with the encoded table defined by the ABI. It is + defined here more for programming convenience. + */ +struct tbtable { + unsigned long flags; /* flags: */ +#define TBTAB_FLAGSGLOBALLINK (1L<<47) +#define TBTAB_FLAGSISEPROL (1L<<46) +#define TBTAB_FLAGSHASTBOFF (1L<<45) +#define TBTAB_FLAGSINTPROC (1L<<44) +#define TBTAB_FLAGSHASCTL (1L<<43) +#define TBTAB_FLAGSTOCLESS (1L<<42) +#define TBTAB_FLAGSFPPRESENT (1L<<41) +#define TBTAB_FLAGSNAMEPRESENT (1L<<38) +#define TBTAB_FLAGSUSESALLOCA (1L<<37) +#define TBTAB_FLAGSSAVESCR (1L<<33) +#define TBTAB_FLAGSSAVESLR (1L<<32) +#define TBTAB_FLAGSSTORESBC (1L<<31) +#define TBTAB_FLAGSFIXUP (1L<<30) +#define TBTAB_FLAGSPARMSONSTK (1L<<0) + unsigned char fp_saved; /* num fp regs saved f(32-n)..f31 */ + unsigned char gpr_saved; /* num gpr's saved */ + unsigned char fixedparms; /* num fixed point parms */ + unsigned char floatparms; /* num float parms */ + unsigned char parminfo[32]; /* types of args. null terminated */ +#define TBTAB_PARMFIXED 1 +#define TBTAB_PARMSFLOAT 2 +#define TBTAB_PARMDFLOAT 3 + unsigned int tb_offset; /* offset from start of func */ + unsigned long funcstart; /* addr of start of function */ + char name[64]; /* name of function (null terminated)*/ +}; +static int find_tb_table(unsigned long codeaddr, struct tbtable *tab); + +void +xmon(struct pt_regs *excp) +{ + struct pt_regs regs; + int cmd; + unsigned long msr; + + if (excp == NULL) { + /* Ok, grab regs as they are now. + This won't do a particularily good job because the + prologue has already been executed. + ToDo: We could reach back into the callers save + area to do a better job of representing the + caller's state. + */ + asm volatile ("std 0,0(%0)\n\ + std 1,8(%0)\n\ + std 2,16(%0)\n\ + std 3,24(%0)\n\ + std 4,32(%0)\n\ + std 5,40(%0)\n\ + std 6,48(%0)\n\ + std 7,56(%0)\n\ + std 8,64(%0)\n\ + std 9,72(%0)\n\ + std 10,80(%0)\n\ + std 11,88(%0)\n\ + std 12,96(%0)\n\ + std 13,104(%0)\n\ + std 14,112(%0)\n\ + std 15,120(%0)\n\ + std 16,128(%0)\n\ + std 17,136(%0)\n\ + std 18,144(%0)\n\ + std 19,152(%0)\n\ + std 20,160(%0)\n\ + std 21,168(%0)\n\ + std 22,176(%0)\n\ + std 23,184(%0)\n\ + std 24,192(%0)\n\ + std 25,200(%0)\n\ + std 26,208(%0)\n\ + std 27,216(%0)\n\ + std 28,224(%0)\n\ + std 29,232(%0)\n\ + std 30,240(%0)\n\ + std 31,248(%0)" : : "b" (®s)); + printf("xmon called\n"); + /* Fetch the link reg for this stack frame. + NOTE: the prev printf fills in the lr. */ + regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2]; + regs.msr = get_msr(); + regs.ctr = get_ctr(); + regs.xer = get_xer(); + regs.ccr = get_cr(); + regs.trap = 0; + excp = ®s; + } + + msr = get_msr(); + set_msrd(msr & ~MSR_EE); /* disable interrupts */ + excprint(excp); +#ifdef CONFIG_SMP + if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) + for (;;) + ; + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; + } + } + /* + * XXX: breakpoints are removed while any cpu is in xmon + */ +#endif /* CONFIG_SMP */ + remove_bpts(); + cmd = cmds(excp); + if (cmd == 's') { + xmon_trace[smp_processor_id()] = SSTEP; + excp->msr |= 0x400; + } else if (at_breakpoint(excp->nip)) { + xmon_trace[smp_processor_id()] = BRSTEP; + excp->msr |= 0x400; + } else { + xmon_trace[smp_processor_id()] = 0; + insert_bpts(); + } +#ifdef CONFIG_SMP + clear_bit(0, &got_xmon); + clear_bit(smp_processor_id(), &cpus_in_xmon); +#endif /* CONFIG_SMP */ + set_msrd(msr); /* restore interrupt enable */ +} + +/* Code can call this to get a backtrace and continue. */ +void +xmon_backtrace(const char *fmt, ...) +{ + va_list ap; + struct pt_regs regs; + + + /* Ok, grab regs as they are now. + This won't do a particularily good job because the + prologue has already been executed. + ToDo: We could reach back into the callers save + area to do a better job of representing the + caller's state. + */ + asm volatile ("std 0,0(%0)\n\ + std 1,8(%0)\n\ + std 2,16(%0)\n\ + std 3,24(%0)\n\ + std 4,32(%0)\n\ + std 5,40(%0)\n\ + std 6,48(%0)\n\ + std 7,56(%0)\n\ + std 8,64(%0)\n\ + std 9,72(%0)\n\ + std 10,80(%0)\n\ + std 11,88(%0)\n\ + std 12,96(%0)\n\ + std 13,104(%0)\n\ + std 14,112(%0)\n\ + std 15,120(%0)\n\ + std 16,128(%0)\n\ + std 17,136(%0)\n\ + std 18,144(%0)\n\ + std 19,152(%0)\n\ + std 20,160(%0)\n\ + std 21,168(%0)\n\ + std 22,176(%0)\n\ + std 23,184(%0)\n\ + std 24,192(%0)\n\ + std 25,200(%0)\n\ + std 26,208(%0)\n\ + std 27,216(%0)\n\ + std 28,224(%0)\n\ + std 29,232(%0)\n\ + std 30,240(%0)\n\ + std 31,248(%0)" : : "b" (®s)); + /* Fetch the link reg for this stack frame. + NOTE: the prev printf fills in the lr. */ + regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2]; + regs.msr = get_msr(); + regs.ctr = get_ctr(); + regs.xer = get_xer(); + regs.ccr = get_cr(); + regs.trap = 0; + + va_start(ap, fmt); + xmon_vfprintf(stdout, fmt, ap); + xmon_putc('\n', stdout); + va_end(ap); + take_input("\n"); + backtrace(®s); +} + +/* Call this to poll for ^C during busy operations. + * Returns true if the user has hit ^C. + */ +int +xmon_interrupted(void) +{ + int ret = xmon_read_poll(); + if (ret == 3) { + printf("\n^C interrupted.\n"); + return 1; + } + return 0; +} + + +void +xmon_irq(int irq, void *d, struct pt_regs *regs) +{ + unsigned long flags; + __save_flags(flags); + __cli(); + printf("Keyboard interrupt\n"); + xmon(regs); + __restore_flags(flags); +} + +int +xmon_bpt(struct pt_regs *regs) +{ + struct bpt *bp; + + bp = at_breakpoint(regs->nip); + if (!bp) + return 0; + if (bp->count) { + --bp->count; + remove_bpts(); + excprint(regs); + xmon_trace[smp_processor_id()] = BRSTEP; + regs->msr |= 0x400; + } else { + printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname); + xmon(regs); + } + return 1; +} + +int +xmon_sstep(struct pt_regs *regs) +{ + if (!xmon_trace[smp_processor_id()]) + return 0; + if (xmon_trace[smp_processor_id()] == BRSTEP) { + xmon_trace[smp_processor_id()] = 0; + insert_bpts(); + } else { + xmon(regs); + } + return 1; +} + +int +xmon_dabr_match(struct pt_regs *regs) +{ + if (dabr.enabled && dabr.count) { + --dabr.count; + remove_bpts(); + excprint(regs); + xmon_trace[smp_processor_id()] = BRSTEP; + regs->msr |= 0x400; + } else { + dabr.instr = regs->nip; + xmon(regs); + } + return 1; +} + +int +xmon_iabr_match(struct pt_regs *regs) +{ + if (iabr.enabled && iabr.count) { + --iabr.count; + remove_bpts(); + excprint(regs); + xmon_trace[smp_processor_id()] = BRSTEP; + regs->msr |= 0x400; + } else { + xmon(regs); + } + return 1; +} + +static struct bpt * +at_breakpoint(unsigned long pc) +{ + int i; + struct bpt *bp; + + if (dabr.enabled && pc == dabr.instr) + return &dabr; + if (iabr.enabled && pc == iabr.address) + return &iabr; + bp = bpts; + for (i = 0; i < NBPTS; ++i, ++bp) + if (bp->enabled && pc == bp->address) + return bp; + return 0; +} + +static void +insert_bpts() +{ + int i; + struct bpt *bp; + + if (_machine != _MACH_pSeries) + return; + bp = bpts; + for (i = 0; i < NBPTS; ++i, ++bp) { + if (!bp->enabled) + continue; + if (mread(bp->address, &bp->instr, 4) != 4 + || mwrite(bp->address, &bpinstr, 4) != 4) { + printf("Couldn't insert breakpoint at %x, disabling\n", + bp->address); + bp->enabled = 0; + } else { + store_inst((void *)bp->address); + } + } + + if (!__is_processor(PV_POWER4)) { + if (dabr.enabled) + set_dabr(dabr.address); + if (iabr.enabled) + set_iabr(iabr.address); + } +} + +static void +remove_bpts() +{ + int i; + struct bpt *bp; + unsigned instr; + + if (_machine != _MACH_pSeries) + return; + if (!__is_processor(PV_POWER4)) { + set_dabr(0); + set_iabr(0); + } + + bp = bpts; + for (i = 0; i < NBPTS; ++i, ++bp) { + if (!bp->enabled) + continue; + if (mread(bp->address, &instr, 4) == 4 + && instr == bpinstr + && mwrite(bp->address, &bp->instr, 4) != 4) + printf("Couldn't remove breakpoint at %x\n", + bp->address); + else + store_inst((void *)bp->address); + } +} + +static char *last_cmd; + +/* Command interpreting routine */ +static int +cmds(struct pt_regs *excp) +{ + int cmd; + + last_cmd = NULL; + for(;;) { +#ifdef CONFIG_SMP + printf("%d:", smp_processor_id()); +#endif /* CONFIG_SMP */ + printf("mon> "); + fflush(stdout); + flush_input(); + termch = 0; + cmd = skipbl(); + if( cmd == '\n' ) { + if (last_cmd == NULL) + continue; + take_input(last_cmd); + last_cmd = NULL; + cmd = inchar(); + } + switch (cmd) { + case 'z': + machine_restart(NULL); + break; + case 'm': + cmd = inchar(); + switch (cmd) { + case 'm': + case 's': + case 'd': + memops(cmd); + break; + case 'l': + memlocate(); + break; + case 'z': + memzcan(); + break; + case 'x': + mem_translate(); + break; + case 'c': + mem_check(); + break; + case 'g': + mem_check_full_group(); + break; + case 'j': + mem_map_check_slab(); + break; + case 'h': + mem_map_check_hash(); + break; + case 'f': + mem_find_real(); + break; + case 'e': + mem_find_vsid(); + break; + case 'r': + mem_check_dup_rpn(); + break; + case 'i': + show_mem(); + break; + case 'o': + mem_check_pagetable_vsids (); + break; + case 'q': + mem_map_lock_pages() ; + break; + default: + termch = cmd; + memex(); + } + break; + case 'd': + dump(); + break; + case 'r': + if (excp != NULL) + prregs(excp); /* print regs */ + break; + case 'e': + if (excp == NULL) + printf("No exception information\n"); + else + excprint(excp); + break; + case 'M': + print_sysmap(); + break; + case 'S': + super_regs(); + break; + case 't': + backtrace(excp); + break; + case 'f': + cacheflush(); + break; + case 'h': + dump_hash_table(); + break; + case 's': + case 'x': + case EOF: + return cmd; + case '?': + printf(help_string); + break; + case 'p': + xmon_show_state(); + break; + case 'b': + bpt_cmds(); + break; + case 'C': + csum(); + break; +#ifdef CONFIG_SMP + case 'c': + cpu_cmd(); + break; +#endif /* CONFIG_SMP */ + case 'T': + debug_trace(); + break; + default: + printf("Unrecognized command: "); + do { + if( ' ' < cmd && cmd <= '~' ) + putchar(cmd); + else + printf("\\x%x", cmd); + cmd = inchar(); + } while (cmd != '\n'); + printf(" (type ? for help)\n"); + break; + } + } +} + +#ifdef CONFIG_SMP +static void cpu_cmd(void) +{ + unsigned long cpu; + int timeout; + int cmd; + + cmd = inchar(); + if (cmd == 'i') { + printf("stopping all cpus\n"); + /* interrupt other cpu(s) */ + cpu = MSG_ALL_BUT_SELF; + smp_send_xmon_break(cpu); + return; + } + termch = cmd; + if (!scanhex(&cpu)) { + /* print cpus waiting or in xmon */ + printf("cpus stopped:"); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (test_bit(cpu, &cpus_in_xmon)) { + printf(" %d", cpu); + if (cpu == smp_processor_id()) + printf("*", cpu); + } + } + printf("\n"); + return; + } + /* try to switch to cpu specified */ + take_xmon = cpu; + timeout = 10000000; + while (take_xmon >= 0) { + if (--timeout == 0) { + /* yes there's a race here */ + take_xmon = -1; + printf("cpu %u didn't take control\n", cpu); + return; + } + } + /* now have to wait to be given control back */ + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; + } + } +} +#endif /* CONFIG_SMP */ + +static unsigned short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +static void +csum(void) +{ + unsigned int i; + unsigned short fcs; + unsigned char v; + + if (!scanhex(&adrs)) + return; + if (!scanhex(&ncsum)) + return; + fcs = 0xffff; + for (i = 0; i < ncsum; ++i) { + if (mread(adrs+i, &v, 1) == 0) { + printf("csum stopped at %x\n", adrs+i); + break; + } + fcs = FCS(fcs, v); + } + printf("%x\n", fcs); +} + +static char *breakpoint_help_string = + "Breakpoint command usage:\n" + "b show breakpoints\n" + "b [cnt] set breakpoint at given instr addr\n" + "bc clear all breakpoints\n" + "bc clear breakpoint number n or at addr\n" + "bi [cnt] set hardware instr breakpoint (broken?)\n" + "bd [cnt] set hardware data breakpoint (broken?)\n" + ""; + +static void +bpt_cmds(void) +{ + int cmd; + unsigned long a; + int mode, i; + struct bpt *bp; + struct tbtable tab; + + cmd = inchar(); + switch (cmd) { + case 'd': /* bd - hardware data breakpoint */ + if (__is_processor(PV_POWER4)) { + printf("Not implemented on POWER4\n"); + break; + } + mode = 7; + cmd = inchar(); + if (cmd == 'r') + mode = 5; + else if (cmd == 'w') + mode = 6; + else + termch = cmd; + dabr.address = 0; + dabr.count = 0; + dabr.enabled = scanhex(&dabr.address); + scanhex(&dabr.count); + if (dabr.enabled) + dabr.address = (dabr.address & ~7) | mode; + break; + case 'i': /* bi - hardware instr breakpoint */ + if (__is_processor(PV_POWER4)) { + printf("Not implemented on POWER4\n"); + break; + } + iabr.address = 0; + iabr.count = 0; + iabr.enabled = scanhex(&iabr.address); + if (iabr.enabled) + iabr.address |= 3; + scanhex(&iabr.count); + break; + case 'c': + if (!scanhex(&a)) { + /* clear all breakpoints */ + for (i = 0; i < NBPTS; ++i) + bpts[i].enabled = 0; + iabr.enabled = 0; + dabr.enabled = 0; + printf("All breakpoints cleared\n"); + } else { + if (a <= NBPTS && a >= 1) { + /* assume a breakpoint number */ + --a; /* bp nums are 1 based */ + bp = &bpts[a]; + } else { + /* assume a breakpoint address */ + bp = at_breakpoint(a); + } + if (bp == 0) { + printf("No breakpoint at %x\n", a); + } else { + printf("Cleared breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname); + bp->enabled = 0; + } + } + break; + case '?': + printf(breakpoint_help_string); + break; + default: + termch = cmd; + cmd = skipbl(); + if (cmd == '?') { + printf(breakpoint_help_string); + break; + } + termch = cmd; + if (!scanhex(&a)) { + /* print all breakpoints */ + int bpnum; + + printf(" type address count\n"); + if (dabr.enabled) { + printf(" data %.16lx %8x [", dabr.address & ~7, + dabr.count); + if (dabr.address & 1) + printf("r"); + if (dabr.address & 2) + printf("w"); + printf("]\n"); + } + if (iabr.enabled) + printf(" inst %.16lx %8x\n", iabr.address & ~3, + iabr.count); + for (bp = bpts, bpnum = 1; bp < &bpts[NBPTS]; ++bp, ++bpnum) + if (bp->enabled) + printf("%2x trap %.16lx %8x %s\n", bpnum, bp->address, bp->count, bp->funcname); + break; + } + bp = at_breakpoint(a); + if (bp == 0) { + for (bp = bpts; bp < &bpts[NBPTS]; ++bp) + if (!bp->enabled) + break; + if (bp >= &bpts[NBPTS]) { + printf("Sorry, no free breakpoints. Please clear one first.\n"); + break; + } + } + bp->enabled = 1; + bp->address = a; + bp->count = 0; + scanhex(&bp->count); + /* Find the function name just once. */ + bp->funcname[0] = '\0'; + if (find_tb_table(bp->address, &tab) && tab.name[0]) { + /* Got a nice name for it. */ + int delta = bp->address - tab.funcstart; + sprintf(bp->funcname, "%s+0x%x", tab.name, delta); + } + printf("Set breakpoint %2x trap %.16lx %8x %s\n", (bp-bpts)+1, bp->address, bp->count, bp->funcname); + break; + } +} + +/* Very cheap human name for vector lookup. */ +static +const char *getvecname(unsigned long vec) +{ + char *ret; + switch (vec) { + case 0x100: ret = "(System Reset)"; break; + case 0x200: ret = "(Machine Check)"; break; + case 0x300: ret = "(Data Access)"; break; + case 0x400: ret = "(Instruction Access)"; break; + case 0x500: ret = "(Hardware Interrupt)"; break; + case 0x600: ret = "(Alignment)"; break; + case 0x700: ret = "(Program Check)"; break; + case 0x800: ret = "(FPU Unavailable)"; break; + case 0x900: ret = "(Decrementer)"; break; + case 0xc00: ret = "(System Call)"; break; + case 0xd00: ret = "(Single Step)"; break; + case 0xf00: ret = "(Performance Monitor)"; break; + default: ret = ""; + } + return ret; +} + +static void +backtrace(struct pt_regs *excp) +{ + unsigned long sp; + unsigned long lr; + unsigned long stack[3]; + struct pt_regs regs; + struct tbtable tab; + int framecount; + char *funcname; + /* declare these as raw ptrs so we don't get func descriptors */ + extern void *ret_from_except, *ret_from_syscall_1; + + if (excp != NULL) { + lr = excp->link; + sp = excp->gpr[1]; + } else { + /* Use care not to call any function before this point + so the saved lr has a chance of being good. */ + asm volatile ("mflr %0" : "=r" (lr) :); + sp = getsp(); + } + scanhex(&sp); + scannl(); + for (framecount = 0; + sp != 0 && framecount < MAXFRAMECOUNT; + sp = stack[0], framecount++) { + if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) + break; +#if 0 + if (lr != 0) { + stack[2] = lr; /* fake out the first saved lr. It may not be saved yet. */ + lr = 0; + } +#endif + printf("%.16lx %.16lx", sp, stack[2]); + /* TAI -- for now only the ones cast to unsigned long will match. + * Need to test the rest... + */ + if ((stack[2] == (unsigned long)ret_from_except && + (funcname = "ret_from_except")) + || (stack[2] == (unsigned long)ret_from_syscall_1 && + (funcname = "ret_from_syscall_1")) +#if 0 + || stack[2] == (unsigned) &ret_from_syscall_2 + || stack[2] == (unsigned) &do_bottom_half_ret + || stack[2] == (unsigned) &do_signal_ret +#endif + ) { + printf(" %s\n", funcname); + if (mread(sp+112, ®s, sizeof(regs)) != sizeof(regs)) + break; + printf("exception: %lx %s regs %lx\n", regs.trap, getvecname(regs.trap), sp+112); + printf(" %.16lx", regs.nip); + if ((regs.nip & 0xffffffff00000000UL) && + find_tb_table(regs.nip, &tab)) { + int delta = regs.nip-tab.funcstart; + if (delta < 0) + printf(" "); + else + printf(" %s+0x%x", tab.name, delta); + } + printf("\n"); + if (regs.gpr[1] < sp) { + printf("\n", regs.gpr[1]); + break; + } + + sp = regs.gpr[1]; + if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) + break; + } else { + if (stack[2] && find_tb_table(stack[2], &tab)) { + int delta = stack[2]-tab.funcstart; + if (delta < 0) + printf(" "); + else + printf(" %s+0x%x", tab.name, delta); + } + printf("\n"); + } + if (stack[0] && stack[0] <= sp) { + if ((stack[0] & 0xffffffff00000000UL) == 0) + printf("\n", stack[0]); + else + printf("\n", stack[0]); + break; + } + } + if (framecount >= MAXFRAMECOUNT) + printf("\n"); +} + +int +getsp() +{ + int x; + + asm("mr %0,1" : "=r" (x) :); + return x; +} + +spinlock_t exception_print_lock = SPIN_LOCK_UNLOCKED; + +void +excprint(struct pt_regs *fp) +{ + struct task_struct *c; + struct tbtable tab; + unsigned long flags; + + spin_lock_irqsave(&exception_print_lock, flags); + +#ifdef CONFIG_SMP + printf("cpu %d: ", smp_processor_id()); +#endif /* CONFIG_SMP */ + + printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(fp->trap), fp); + printf(" pc: %lx", fp->nip); + if (find_tb_table(fp->nip, &tab) && tab.name[0]) { + /* Got a nice name for it */ + int delta = fp->nip - tab.funcstart; + printf(" (%s+0x%x)", tab.name, delta); + } + printf("\n"); + printf(" lr: %lx", fp->link); + if (find_tb_table(fp->link, &tab) && tab.name[0]) { + /* Got a nice name for it */ + int delta = fp->link - tab.funcstart; + printf(" (%s+0x%x)", tab.name, delta); + } + printf("\n"); + printf(" sp: %lx\n", fp->gpr[1]); + printf(" msr: %lx\n", fp->msr); + + if (fp->trap == 0x300 || fp->trap == 0x600) { + printf(" dar: %lx\n", fp->dar); + printf(" dsisr: %lx\n", fp->dsisr); + } + + /* XXX: need to copy current or we die. Why? */ + c = current; + printf(" current = 0x%lx\n", c); + printf(" paca = 0x%lx\n", get_paca()); + if (c) { + printf(" current = %lx, pid = %ld, comm = %s\n", + c, c->pid, c->comm); + } + + spin_unlock_irqrestore(&exception_print_lock, flags); +} + +void +prregs(struct pt_regs *fp) +{ + int n; + unsigned long base; + + if (scanhex((void *)&base)) + fp = (struct pt_regs *) base; + for (n = 0; n < 16; ++n) + printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", n, fp->gpr[n], + n+16, fp->gpr[n+16]); + printf("pc = %.16lx msr = %.16lx\nlr = %.16lx cr = %.16lx\n", + fp->nip, fp->msr, fp->link, fp->ccr); + printf("ctr = %.16lx xer = %.16lx trap = %8lx\n", + fp->ctr, fp->xer, fp->trap); +} + +void +cacheflush(void) +{ + int cmd; + unsigned long nflush; + + cmd = inchar(); + if (cmd != 'i') + termch = cmd; + scanhex((void *)&adrs); + if (termch != '\n') + termch = 0; + nflush = 1; + scanhex(&nflush); + nflush = (nflush + 31) / 32; + if (cmd != 'i') { + for (; nflush > 0; --nflush, adrs += 0x20) + cflush((void *) adrs); + } else { + for (; nflush > 0; --nflush, adrs += 0x20) + cinval((void *) adrs); + } +} + +unsigned long +read_spr(int n) +{ + unsigned int instrs[2]; + unsigned long (*code)(void); + unsigned long opd[3]; + + instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); + instrs[1] = 0x4e800020; + opd[0] = instrs; + opd[1] = 0; + opd[2] = 0; + store_inst(instrs); + store_inst(instrs+1); + code = (unsigned long (*)(void)) opd; + + return code(); +} + +void +write_spr(int n, unsigned long val) +{ + unsigned int instrs[2]; + unsigned long (*code)(unsigned long); + unsigned long opd[3]; + + instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); + instrs[1] = 0x4e800020; + opd[0] = instrs; + opd[1] = 0; + opd[2] = 0; + store_inst(instrs); + store_inst(instrs+1); + code = (unsigned long (*)(unsigned long)) opd; + + code(val); +} + +static unsigned long regno; +extern char exc_prolog; +extern char dec_exc; + +void +print_sysmap(void) +{ + extern char *sysmap; + if ( sysmap ) + printf("System.map: \n%s", sysmap); +} + +void +super_regs() +{ + int i, cmd; + unsigned long val; + struct Paca* ptrPaca = NULL; + struct ItLpPaca* ptrLpPaca = NULL; + struct ItLpRegSave* ptrLpRegSave = NULL; + + cmd = skipbl(); + if (cmd == '\n') { + unsigned long sp, toc; + asm("mr %0,1" : "=r" (sp) :); + asm("mr %0,2" : "=r" (toc) :); + + printf("msr = %.16lx sprg0= %.16lx\n", get_msr(), get_sprg0()); + printf("pvr = %.16lx sprg1= %.16lx\n", get_pvr(), get_sprg1()); + printf("dec = %.16lx sprg2= %.16lx\n", get_dec(), get_sprg2()); + printf("sp = %.16lx sprg3= %.16lx\n", sp, get_sprg3()); + printf("toc = %.16lx dar = %.16lx\n", toc, get_dar()); + printf("srr0 = %.16lx srr1 = %.16lx\n", get_srr0(), get_srr1()); + printf("asr = %.16lx\n", mfasr()); + for (i = 0; i < 8; ++i) + printf("sr%.2ld = %.16lx sr%.2ld = %.16lx\n", i, get_sr(i), i+8, get_sr(i+8)); + + // Dump out relevant Paca data areas. + printf("Paca: \n"); + ptrPaca = (struct Paca*)get_sprg3(); + + printf(" Local Processor Control Area (LpPaca): \n"); + ptrLpPaca = ptrPaca->xLpPacaPtr; + printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", ptrLpPaca->xSavedSrr0, ptrLpPaca->xSavedSrr1); + printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", ptrLpPaca->xSavedGpr3, ptrLpPaca->xSavedGpr4); + printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->xSavedGpr5); + + printf(" Local Processor Register Save Area (LpRegSave): \n"); + ptrLpRegSave = ptrPaca->xLpRegSavePtr; + printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0); + printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3); + printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA); + + return; + } + + scanhex(®no); + switch (cmd) { + case 'w': + val = read_spr(regno); + scanhex(&val); + write_spr(regno, val); + /* fall through */ + case 'r': + printf("spr %lx = %lx\n", regno, read_spr(regno)); + break; + case 's': + val = get_sr(regno); + scanhex(&val); + set_sr(regno, val); + break; + case 'm': + val = get_msr(); + scanhex(&val); + set_msrd(val); + break; + } + scannl(); +} + +#if 0 +static void +openforth() +{ + int c; + char *p; + char cmd[1024]; + int args[5]; + extern int (*prom_entry)(int *); + + p = cmd; + c = skipbl(); + while (c != '\n') { + *p++ = c; + c = inchar(); + } + *p = 0; + args[0] = (int) "interpret"; + args[1] = 1; + args[2] = 1; + args[3] = (int) cmd; + (*prom_entry)(args); + printf("\n"); + if (args[4] != 0) + printf("error %x\n", args[4]); +} +#endif + +#ifndef CONFIG_PPC64BRIDGE +static void +dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) +{ + extern void *Hash; + extern unsigned long Hash_size; + unsigned *htab = Hash; + unsigned hsize = Hash_size; + unsigned v, hmask, va, last_va; + int found, last_found, i; + unsigned *hg, w1, last_w2, last_va0; + + last_found = 0; + hmask = hsize / 64 - 1; + va = start; + start = (start >> 12) & 0xffff; + end = (end >> 12) & 0xffff; + for (v = start; v < end; ++v) { + found = 0; + hg = htab + (((v ^ seg) & hmask) * 16); + w1 = 0x80000000 | (seg << 7) | (v >> 10); + for (i = 0; i < 8; ++i, hg += 2) { + if (*hg == w1) { + found = 1; + break; + } + } + if (!found) { + w1 ^= 0x40; + hg = htab + ((~(v ^ seg) & hmask) * 16); + for (i = 0; i < 8; ++i, hg += 2) { + if (*hg == w1) { + found = 1; + break; + } + } + } + if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) { + if (last_found) { + if (last_va != last_va0) + printf(" ... %x", last_va); + printf("\n"); + } + if (found) { + printf("%x to %x", va, hg[1]); + last_va0 = va; + } + last_found = found; + } + if (found) { + last_w2 = hg[1] & ~0x180; + last_va = va; + } + va += 4096; + } + if (last_found) + printf(" ... %x\n", last_va); +} + +#else /* CONFIG_PPC64BRIDGE */ +static void +dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) +{ + extern void *Hash; + extern unsigned long Hash_size; + unsigned *htab = Hash; + unsigned hsize = Hash_size; + unsigned v, hmask, va, last_va; + int found, last_found, i; + unsigned *hg, w1, last_w2, last_va0; + + last_found = 0; + hmask = hsize / 128 - 1; + va = start; + start = (start >> 12) & 0xffff; + end = (end >> 12) & 0xffff; + for (v = start; v < end; ++v) { + found = 0; + hg = htab + (((v ^ seg) & hmask) * 32); + w1 = 1 | (seg << 12) | ((v & 0xf800) >> 4); + for (i = 0; i < 8; ++i, hg += 4) { + if (hg[1] == w1) { + found = 1; + break; + } + } + if (!found) { + w1 ^= 2; + hg = htab + ((~(v ^ seg) & hmask) * 32); + for (i = 0; i < 8; ++i, hg += 4) { + if (hg[1] == w1) { + found = 1; + break; + } + } + } + if (!(last_found && found && (hg[3] & ~0x180) == last_w2 + 4096)) { + if (last_found) { + if (last_va != last_va0) + printf(" ... %x", last_va); + printf("\n"); + } + if (found) { + printf("%x to %x", va, hg[3]); + last_va0 = va; + } + last_found = found; + } + if (found) { + last_w2 = hg[3] & ~0x180; + last_va = va; + } + va += 4096; + } + if (last_found) + printf(" ... %x\n", last_va); +} +#endif /* CONFIG_PPC64BRIDGE */ + +static unsigned long hash_ctx; +static unsigned long hash_start; +static unsigned long hash_end; + +static void +dump_hash_table() +{ + int seg; + unsigned seg_start, seg_end; + + hash_ctx = 0; + hash_start = 0; + hash_end = 0xfffff000; + scanhex(&hash_ctx); + scanhex(&hash_start); + scanhex(&hash_end); + printf("Mappings for context %x\n", hash_ctx); + seg_start = hash_start; + for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) { + seg_end = (seg << 28) | 0x0ffff000; + if (seg_end > hash_end) + seg_end = hash_end; + dump_hash_table_seg((hash_ctx << 4) + seg, seg_start, seg_end); + seg_start = seg_end + 0x1000; + } +} + +int +mread(unsigned long adrs, void *buf, int size) +{ + volatile int n; + char *p, *q; + + n = 0; + if( setjmp(bus_error_jmp) == 0 ){ + debugger_fault_handler = handle_fault; + sync(); + p = (char *) adrs; + q = (char *) buf; + switch (size) { + case 2: *(short *)q = *(short *)p; break; + case 4: *(int *)q = *(int *)p; break; + default: + for( ; n < size; ++n ) { + *q++ = *p++; + sync(); + } + } + sync(); + /* wait a little while to see if we get a machine check */ + __delay(200); + n = size; + } + debugger_fault_handler = 0; + return n; +} + +int +mwrite(unsigned long adrs, void *buf, int size) +{ + volatile int n; + char *p, *q; + + n = 0; + if( setjmp(bus_error_jmp) == 0 ){ + debugger_fault_handler = handle_fault; + sync(); + p = (char *) adrs; + q = (char *) buf; + switch (size) { + case 2: *(short *)p = *(short *)q; break; + case 4: *(int *)p = *(int *)q; break; + default: + for( ; n < size; ++n ) { + *p++ = *q++; + sync(); + } + } + sync(); + /* wait a little while to see if we get a machine check */ + __delay(200); + n = size; + } else { + printf("*** Error writing address %x\n", adrs + n); + } + debugger_fault_handler = 0; + return n; +} + +static int fault_type; +static char *fault_chars[] = { "--", "**", "##" }; + +static void +handle_fault(struct pt_regs *regs) +{ + fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2; + longjmp(bus_error_jmp, 1); +} + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +void +byterev(unsigned char *val, int size) +{ + int t; + + switch (size) { + case 2: + SWAP(val[0], val[1], t); + break; + case 4: + SWAP(val[0], val[3], t); + SWAP(val[1], val[2], t); + break; + case 8: /* is there really any use for this? */ + SWAP(val[0], val[7], t); + SWAP(val[1], val[6], t); + SWAP(val[2], val[5], t); + SWAP(val[3], val[4], t); + break; + } +} + +static int brev; +static int mnoread; + +static char *memex_help_string = + "Memory examine command usage:\n" + "m [addr] [flags] examine/change memory\n" + " addr is optional. will start where left off.\n" + " flags may include chars from this set:\n" + " b modify by bytes (default)\n" + " w modify by words (2 byte)\n" + " l modify by longs (4 byte)\n" + " d modify by doubleword (8 byte)\n" + " r toggle reverse byte order mode\n" + " n do not read memory (for i/o spaces)\n" + " . ok to read (default)\n" + "NOTE: flags are saved as defaults\n" + ""; + +static char *memex_subcmd_help_string = + "Memory examine subcommands:\n" + " hexval write this val to current location\n" + " 'string' write chars from string to this location\n" + " ' increment address\n" + " ^ decrement address\n" + " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n" + " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n" + " ` clear no-read flag\n" + " ; stay at this addr\n" + " v change to byte mode\n" + " w change to word (2 byte) mode\n" + " l change to long (4 byte) mode\n" + " u change to doubleword (8 byte) mode\n" + " m addr change current addr\n" + " n toggle no-read flag\n" + " r toggle byte reverse flag\n" + " < count back up count bytes\n" + " > count skip forward count bytes\n" + " x exit this mode\n" + ""; + +void +memex() +{ + int cmd, inc, i, nslash; + unsigned long n; + unsigned char val[16]; + + scanhex((void *)&adrs); + cmd = skipbl(); + if (cmd == '?') { + printf(memex_help_string); + return; + } else { + termch = cmd; + } + last_cmd = "m\n"; + while ((cmd = skipbl()) != '\n') { + switch( cmd ){ + case 'b': size = 1; break; + case 'w': size = 2; break; + case 'l': size = 4; break; + case 'd': size = 8; break; + case 'r': brev = !brev; break; + case 'n': mnoread = 1; break; + case '.': mnoread = 0; break; + } + } + if( size <= 0 ) + size = 1; + else if( size > 8 ) + size = 8; + for(;;){ + if (!mnoread) + n = mread(adrs, val, size); + printf("%.16x%c", adrs, brev? 'r': ' '); + if (!mnoread) { + if (brev) + byterev(val, size); + putchar(' '); + for (i = 0; i < n; ++i) + printf("%.2x", val[i]); + for (; i < size; ++i) + printf("%s", fault_chars[fault_type]); + } + putchar(' '); + inc = size; + nslash = 0; + for(;;){ + if( scanhex(&n) ){ + for (i = 0; i < size; ++i) + val[i] = n >> (i * 8); + if (!brev) + byterev(val, size); + mwrite(adrs, val, size); + inc = size; + } + cmd = skipbl(); + if (cmd == '\n') + break; + inc = 0; + switch (cmd) { + case '\'': + for(;;){ + n = inchar(); + if( n == '\\' ) + n = bsesc(); + else if( n == '\'' ) + break; + for (i = 0; i < size; ++i) + val[i] = n >> (i * 8); + if (!brev) + byterev(val, size); + mwrite(adrs, val, size); + adrs += size; + } + adrs -= size; + inc = size; + break; + case ',': + adrs += size; + break; + case '.': + mnoread = 0; + break; + case ';': + break; + case 'x': + case EOF: + scannl(); + return; + case 'b': + case 'v': + size = 1; + break; + case 'w': + size = 2; + break; + case 'l': + size = 4; + break; + case 'u': + size = 8; + break; + case '^': + adrs -= size; + break; + break; + case '/': + if (nslash > 0) + adrs -= 1 << nslash; + else + nslash = 0; + nslash += 4; + adrs += 1 << nslash; + break; + case '\\': + if (nslash < 0) + adrs += 1 << -nslash; + else + nslash = 0; + nslash -= 4; + adrs -= 1 << -nslash; + break; + case 'm': + scanhex((void *)&adrs); + break; + case 'n': + mnoread = 1; + break; + case 'r': + brev = !brev; + break; + case '<': + n = size; + scanhex(&n); + adrs -= n; + break; + case '>': + n = size; + scanhex(&n); + adrs += n; + break; + case '?': + printf(memex_subcmd_help_string); + break; + } + } + adrs += inc; + } +} + +int +bsesc() +{ + int c; + + c = inchar(); + switch( c ){ + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 'b': c = '\b'; break; + case 't': c = '\t'; break; + } + return c; +} + +#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'f') \ + || ('A' <= (c) && (c) <= 'F')) +void +dump() +{ + int c; + + c = inchar(); + if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') + termch = c; + scanhex((void *)&adrs); + if( termch != '\n') + termch = 0; + if( c == 'i' ){ + scanhex(&nidump); + if( nidump == 0 ) + nidump = 16; + adrs += ppc_inst_dump(adrs, nidump); + last_cmd = "di\n"; + } else { + scanhex(&ndump); + if( ndump == 0 ) + ndump = 64; + prdump(adrs, ndump); + adrs += ndump; + last_cmd = "d\n"; + } +} + +void +prdump(unsigned long adrs, long ndump) +{ + long n, m, c, r, nr; + unsigned char temp[16]; + + for( n = ndump; n > 0; ){ + printf("%.16lx", adrs); + putchar(' '); + r = n < 16? n: 16; + nr = mread(adrs, temp, r); + adrs += nr; + for( m = 0; m < r; ++m ){ + if ((m & 7) == 0 && m > 0) + putchar(' '); + if( m < nr ) + printf("%.2x", temp[m]); + else + printf("%s", fault_chars[fault_type]); + } + for(; m < 16; ++m ) + printf(" "); + printf(" |"); + for( m = 0; m < r; ++m ){ + if( m < nr ){ + c = temp[m]; + putchar(' ' <= c && c <= '~'? c: '.'); + } else + putchar(' '); + } + n -= r; + for(; m < 16; ++m ) + putchar(' '); + printf("|\n"); + if( nr < r ) + break; + } +} + +int +ppc_inst_dump(unsigned long adr, long count) +{ + int nr, dotted; + unsigned long first_adr; + unsigned long inst, last_inst; + unsigned char val[4]; + + dotted = 0; + for (first_adr = adr; count > 0; --count, adr += 4){ + nr = mread(adr, val, 4); + if( nr == 0 ){ + const char *x = fault_chars[fault_type]; + printf("%.16lx %s%s%s%s\n", adr, x, x, x, x); + break; + } + inst = GETWORD(val); + if (adr > first_adr && inst == last_inst) { + if (!dotted) { + printf(" ...\n"); + dotted = 1; + } + continue; + } + dotted = 0; + last_inst = inst; + printf("%.16lx ", adr); + printf("%.8x\t", inst); + print_insn_big_powerpc(stdout, inst, adr); /* always returns 4 */ + printf("\n"); + } + return adr - first_adr; +} + +void +print_address(unsigned long addr) +{ + printf("0x%lx", addr); +} + +/* + * Memory operations - move, set, print differences + */ +static unsigned long mdest; /* destination address */ +static unsigned long msrc; /* source address */ +static unsigned long mval; /* byte value to set memory to */ +static unsigned long mcount; /* # bytes to affect */ +static unsigned long mdiffs; /* max # differences to print */ + +void +memops(int cmd) +{ + scanhex((void *)&mdest); + if( termch != '\n' ) + termch = 0; + scanhex((void *)(cmd == 's'? &mval: &msrc)); + if( termch != '\n' ) + termch = 0; + scanhex((void *)&mcount); + switch( cmd ){ + case 'm': + memmove((void *)mdest, (void *)msrc, mcount); + break; + case 's': + memset((void *)mdest, mval, mcount); + break; + case 'd': + if( termch != '\n' ) + termch = 0; + scanhex((void *)&mdiffs); + memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); + break; + } +} + +void +memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr) +{ + unsigned n, prt; + + prt = 0; + for( n = nb; n > 0; --n ) + if( *p1++ != *p2++ ) + if( ++prt <= maxpr ) + printf("%.16x %.2x # %.16x %.2x\n", p1 - 1, + p1[-1], p2 - 1, p2[-1]); + if( prt > maxpr ) + printf("Total of %d differences\n", prt); +} + +static unsigned mend; +static unsigned mask; + +void +memlocate() +{ + unsigned a, n; + unsigned char val[4]; + + last_cmd = "ml"; + scanhex((void *)&mdest); + if (termch != '\n') { + termch = 0; + scanhex((void *)&mend); + if (termch != '\n') { + termch = 0; + scanhex((void *)&mval); + mask = ~0; + if (termch != '\n') termch = 0; + scanhex((void *)&mask); + } + } + n = 0; + for (a = mdest; a < mend; a += 4) { + if (mread(a, val, 4) == 4 + && ((GETWORD(val) ^ mval) & mask) == 0) { + printf("%.16x: %.16x\n", a, GETWORD(val)); + if (++n >= 10) + break; + } + } +} + +static unsigned long mskip = 0x1000; +static unsigned long mlim = 0xffffffff; + +void +memzcan() +{ + unsigned char v; + unsigned a; + int ok, ook; + + scanhex(&mdest); + if (termch != '\n') termch = 0; + scanhex(&mskip); + if (termch != '\n') termch = 0; + scanhex(&mlim); + ook = 0; + for (a = mdest; a < mlim; a += mskip) { + ok = mread(a, &v, 1); + if (ok && !ook) { + printf("%.8x .. ", a); + fflush(stdout); + } else if (!ok && ook) + printf("%.8x\n", a - mskip); + ook = ok; + if (a + mskip < a) + break; + } + if (ook) + printf("%.8x\n", a - mskip); +} + +/* Input scanning routines */ +int +skipbl() +{ + int c; + + if( termch != 0 ){ + c = termch; + termch = 0; + } else + c = inchar(); + while( c == ' ' || c == '\t' ) + c = inchar(); + return c; +} + +int +scanhex(vp) +unsigned long *vp; +{ + int c, d; + unsigned long v; + + c = skipbl(); + d = hexdigit(c); + if( d == EOF ){ + termch = c; + return 0; + } + v = 0; + do { + v = (v << 4) + d; + c = inchar(); + d = hexdigit(c); + } while( d != EOF ); + termch = c; + *vp = v; + return 1; +} + +void +scannl() +{ + int c; + + c = termch; + termch = 0; + while( c != '\n' ) + c = inchar(); +} + +int +hexdigit(int c) +{ + if( '0' <= c && c <= '9' ) + return c - '0'; + if( 'A' <= c && c <= 'F' ) + return c - ('A' - 10); + if( 'a' <= c && c <= 'f' ) + return c - ('a' - 10); + return EOF; +} + +void +getstring(char *s, int size) +{ + int c; + + c = skipbl(); + do { + if( size > 1 ){ + *s++ = c; + --size; + } + c = inchar(); + } while( c != ' ' && c != '\t' && c != '\n' ); + termch = c; + *s = 0; +} + +static char line[256]; +static char *lineptr; + +void +flush_input() +{ + lineptr = NULL; +} + +int +inchar() +{ + if (lineptr == NULL || *lineptr == 0) { + if (fgets(line, sizeof(line), stdin) == NULL) { + lineptr = NULL; + return EOF; + } + lineptr = line; + } + return *lineptr++; +} + +void +take_input(str) +char *str; +{ + lineptr = str; +} + + +/* Starting at codeaddr scan forward for a tbtable and fill in the + given table. Return non-zero if successful at doing something. + */ +static int +find_tb_table(unsigned long codeaddr, struct tbtable *tab) +{ + unsigned long codeaddr_max; + unsigned long tbtab_start; + int nr; + int instr; + int num_parms; + + if (tab == NULL) + return 0; + memset(tab, 0, sizeof(tab)); + + /* Scan instructions starting at codeaddr for 128k max */ + for (codeaddr_max = codeaddr + 128*1024*4; + codeaddr < codeaddr_max; + codeaddr += 4) { + nr = mread(codeaddr, &instr, 4); + if (nr != 4) + return 0; /* Bad read. Give up promptly. */ + if (instr == 0) { + /* table should follow. */ + int version; + unsigned long flags; + tbtab_start = codeaddr; /* save it to compute func start addr */ + codeaddr += 4; + nr = mread(codeaddr, &flags, 8); + if (nr != 8) + return 0; /* Bad read or no tb table. */ + tab->flags = flags; + version = (flags >> 56) & 0xff; + if (version != 0) + continue; /* No tb table here. */ + /* Now, like the version, some of the flags are values + that are more conveniently extracted... */ + tab->fp_saved = (flags >> 24) & 0x3f; + tab->gpr_saved = (flags >> 16) & 0x3f; + tab->fixedparms = (flags >> 8) & 0xff; + tab->floatparms = (flags >> 1) & 0x7f; + codeaddr += 8; + num_parms = tab->fixedparms + tab->floatparms; + if (num_parms) { + unsigned int parminfo; + int parm; + if (num_parms > 32) + return 1; /* incomplete */ + nr = mread(codeaddr, &parminfo, 4); + if (nr != 4) + return 1; /* incomplete */ + /* decode parminfo...32 bits. + A zero means fixed. A one means float and the + following bit determines single (0) or double (1). + */ + for (parm = 0; parm < num_parms; parm++) { + if (parminfo & 0x80000000) { + parminfo <<= 1; + if (parminfo & 0x80000000) + tab->parminfo[parm] = TBTAB_PARMDFLOAT; + else + tab->parminfo[parm] = TBTAB_PARMSFLOAT; + } else { + tab->parminfo[parm] = TBTAB_PARMFIXED; + } + parminfo <<= 1; + } + codeaddr += 4; + } + if (flags & TBTAB_FLAGSHASTBOFF) { + nr = mread(codeaddr, &tab->tb_offset, 4); + if (nr != 4) + return 1; /* incomplete */ + if (tab->tb_offset > 0) { + tab->funcstart = tbtab_start - tab->tb_offset; + } + codeaddr += 4; + } + /* hand_mask appears to be always be omitted. */ + if (flags & TBTAB_FLAGSHASCTL) { + /* Assume this will never happen for C or asm */ + return 1; /* incomplete */ + } + if (flags & TBTAB_FLAGSNAMEPRESENT) { + short namlen; + nr = mread(codeaddr, &namlen, 2); + if (nr != 2) + return 1; /* incomplete */ + if (namlen >= sizeof(tab->name)) + namlen = sizeof(tab->name)-1; + codeaddr += 2; + nr = mread(codeaddr, tab->name, namlen); + tab->name[namlen] = '\0'; + codeaddr += namlen; + } + return 1; + } + } + return 0; /* hit max...sorry. */ +} + +void +mem_translate() +{ + int c; + unsigned long ea, va, vsid, vpn, page, hpteg_slot_primary, hpteg_slot_secondary, primary_hash, i, *steg, esid, stabl; + HPTE * hpte; + struct mm_struct * mm; + pte_t *ptep = NULL; + void * pgdir; + + c = inchar(); + if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') + termch = c; + scanhex((void *)&ea); + + if ((ea >= KRANGE_START) && (ea <= (KRANGE_START + (1UL<<60)))) { + ptep = 0; + vsid = get_kernel_vsid(ea); + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + } else { + // if in vmalloc range, use the vmalloc page directory + if ( ( ea >= VMALLOC_START ) && ( ea <= VMALLOC_END ) ) { + mm = &init_mm; + vsid = get_kernel_vsid( ea ); + } + // if in ioremap range, use the ioremap page directory + else if ( ( ea >= IMALLOC_START ) && ( ea <= IMALLOC_END ) ) { + mm = &ioremap_mm; + vsid = get_kernel_vsid( ea ); + } + // if in user range, use the current task's page directory + else if ( ( ea >= USER_START ) && ( ea <= USER_END ) ) { + mm = current->mm; + vsid = get_vsid(mm->context, ea ); + } + pgdir = mm->pgd; + va = ( vsid << 28 ) | ( ea & 0x0fffffff ); + ptep = find_linux_pte( pgdir, ea ); + } + + vpn = ((vsid << 28) | (((ea) & 0xFFFF000))) >> 12; + page = vpn & 0xffff; + esid = (ea >> 28) & 0xFFFFFFFFF; + + // Search the primary group for an available slot + primary_hash = ( vsid & 0x7fffffffff ) ^ page; + hpteg_slot_primary = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + hpteg_slot_secondary = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP; + + printf("ea : %.16lx\n", ea); + printf("esid : %.16lx\n", esid); + printf("vsid : %.16lx\n", vsid); + + printf("\nSoftware Page Table\n-------------------\n"); + printf("ptep : %.16lx\n", ((unsigned long *)ptep)); + if(ptep) { + printf("*ptep : %.16lx\n", *((unsigned long *)ptep)); + } + + hpte = htab_data.htab + hpteg_slot_primary; + printf("\nHardware Page Table\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("slot primary : %.16lx\n", hpteg_slot_primary); + printf("slot secondary : %.16lx\n", hpteg_slot_secondary); + printf("\nPrimary Group\n"); + for (i=0; i<8; ++i) { + if ( hpte->dw0.dw0.v != 0 ) { + printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1); + printf(" vsid: %.13lx api: %.2lx hash: %.1lx\n", + (hpte->dw0.dw0.avpn)>>5, + (hpte->dw0.dw0.avpn) & 0x1f, + (hpte->dw0.dw0.h)); + printf(" rpn: %.13lx \n", (hpte->dw1.dw1.rpn)); + printf(" pp: %.1lx \n", + ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp)); + printf(" wimgn: %.2lx reference: %.1lx change: %.1lx\n", + ((hpte->dw1.dw1.w)<<4)| + ((hpte->dw1.dw1.i)<<3)| + ((hpte->dw1.dw1.m)<<2)| + ((hpte->dw1.dw1.g)<<1)| + ((hpte->dw1.dw1.n)<<0), + hpte->dw1.dw1.r, hpte->dw1.dw1.c); + } + hpte++; + } + + printf("\nSecondary Group\n"); + // Search the secondary group + hpte = htab_data.htab + hpteg_slot_secondary; + for (i=0; i<8; ++i) { + if(hpte->dw0.dw0.v) { + printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1); + printf(" vsid: %.13lx api: %.2lx hash: %.1lx\n", + (hpte->dw0.dw0.avpn)>>5, + (hpte->dw0.dw0.avpn) & 0x1f, + (hpte->dw0.dw0.h)); + printf(" rpn: %.13lx \n", (hpte->dw1.dw1.rpn)); + printf(" pp: %.1lx \n", + ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp)); + printf(" wimgn: %.2lx reference: %.1lx change: %.1lx\n", + ((hpte->dw1.dw1.w)<<4)| + ((hpte->dw1.dw1.i)<<3)| + ((hpte->dw1.dw1.m)<<2)| + ((hpte->dw1.dw1.g)<<1)| + ((hpte->dw1.dw1.n)<<0), + hpte->dw1.dw1.r, hpte->dw1.dw1.c); + } + hpte++; + } + + printf("\nHardware Segment Table\n-----------------------\n"); + stabl = (unsigned long)(KERNELBASE+(_ASR&0xFFFFFFFFFFFFFFFE)); + steg = (unsigned long *)((stabl) | ((esid & 0x1f) << 7)); + + printf("stab base : %.16lx\n", stabl); + printf("slot : %.16lx\n", steg); + + for (i=0; i<8; ++i) { + printf("%d: (ste) %.16lx %.16lx\n", i, + *((unsigned long *)(steg+i*2)),*((unsigned long *)(steg+i*2+1)) ); + } +} + +void mem_check() +{ + unsigned long htab_size_bytes; + unsigned long htab_end; + unsigned long last_rpn; + HPTE *hpte1, *hpte2; + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT; + last_rpn = 0xfffff; + + printf("\nHardware Page Table Check\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + +#if 1 + for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) { + if ( hpte1->dw0.dw0.v != 0 ) { + if ( hpte1->dw1.dw1.rpn <= last_rpn ) { + for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) { + if ( hpte2->dw0.dw0.v != 0 ) { + if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) { + printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn)); + printf(" hpte1: %16.16lx *hpte1: %16.16lx %16.16lx\n", + hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1); + printf(" hpte2: %16.16lx *hpte2: %16.16lx %16.16lx\n", + hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1); + } + } + } + } else { + printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn)); + printf(" hpte: %16.16lx *hpte: %16.16lx %16.16lx\n", + hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1); + } + } + } +#endif + printf("\nDone -------------------\n"); +} + +void mem_find_real() +{ + unsigned long htab_size_bytes; + unsigned long htab_end; + unsigned long last_rpn; + HPTE *hpte1; + unsigned long pa, rpn; + int c; + + c = inchar(); + if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') + termch = c; + scanhex((void *)&pa); + rpn = pa >> 12; + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT; + last_rpn = 0xfffff; + + printf("\nMem Find RPN\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + + for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) { + if ( hpte1->dw0.dw0.v != 0 ) { + if ( hpte1->dw1.dw1.rpn == rpn ) { + printf(" Found rpn: %.13lx \n", (hpte1->dw1.dw1.rpn)); + printf(" hpte: %16.16lx *hpte1: %16.16lx %16.16lx\n", + hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1); + } + } + } + printf("\nDone -------------------\n"); +} + +void mem_find_vsid() +{ + unsigned long htab_size_bytes; + unsigned long htab_end; + HPTE *hpte1; + unsigned long vsid; + int c; + + c = inchar(); + if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') + termch = c; + scanhex((void *)&vsid); + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + + printf("\nMem Find VSID\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + + for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) { + if ( hpte1->dw0.dw0.v != 0 ) { + if ( ((hpte1->dw0.dw0.avpn)>>5) == vsid ) { + printf(" Found vsid: %.16lx \n", ((hpte1->dw0.dw0.avpn) >> 5)); + printf(" hpte: %16.16lx *hpte1: %16.16lx %16.16lx\n", + hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1); + } + } + } + printf("\nDone -------------------\n"); +} + +void mem_map_check_slab() +{ + int i, slab_count; + + i = max_mapnr; + slab_count = 0; + + while (i-- > 0) { + if (PageSlab(mem_map+i)){ + printf(" slab entry - mem_map entry =%p \n", mem_map+i); + slab_count ++; + } + } + + printf(" count of pages for slab = %d \n", slab_count); +} + +void mem_map_lock_pages() +{ + int i, lock_count; + + i = max_mapnr; + lock_count = 0; + + while (i-- > 0) { + if (PageLocked(mem_map+i)){ + printf(" locked entry - mem_map entry =%p \n", mem_map+i); + lock_count ++; + } + } + + printf(" count of locked pages = %d \n", lock_count); +} + + + +void mem_map_check_hash() +{ + int i = max_mapnr; + + while (i-- > 0) { + /* skip the reserved */ + if (!PageReserved(mem_map+i)) { + if (((mem_map+i)->next_hash) != NULL) { + if ( REGION_ID((mem_map+i)->next_hash) != KERNEL_REGION_ID ) { + printf(" mem_map check hash - non c0 entry - " + "address/value = %p %lx\n", mem_map+i,(mem_map+i)->next_hash); + } + if ((unsigned long)((mem_map+i)->next_hash) == KERNELBASE){ + printf(" mem_map check hash - 0x%lx entry = %p \n", + KERNELBASE, mem_map+i); + } + } + } else { + if (page_count(mem_map+i) < 0) { + printf(" reserved page with negative count- entry = %lx \n", mem_map+i); + } + } + } + printf(" mem_map check hash completed \n"); +} + +void mem_check_dup_rpn () +{ + unsigned long htab_size_bytes; + unsigned long htab_end; + unsigned long last_rpn; + HPTE *hpte1, *hpte2; + int dup_count; + struct task_struct *p; + unsigned long kernel_vsid_c0,kernel_vsid_c1,kernel_vsid_c2,kernel_vsid_c3; + unsigned long kernel_vsid_c4,kernel_vsid_c5,kernel_vsid_d,kernel_vsid_e; + unsigned long kernel_vsid_f; + unsigned long vsid0,vsid1,vsidB,vsid2; + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT; + last_rpn = 0xfffff; + + printf("\nHardware Page Table Check\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + + + for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) { + if ( hpte1->dw0.dw0.v != 0 ) { + if ( hpte1->dw1.dw1.rpn <= last_rpn ) { + dup_count = 0; + for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) { + if ( hpte2->dw0.dw0.v != 0 ) { + if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) { + dup_count++; + } + } + } + if(dup_count > 5) { + printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn)); + printf(" mem map array entry %p count = %d \n", + (mem_map+(hpte1->dw1.dw1.rpn)), (mem_map+(hpte1->dw1.dw1.rpn))->count); + for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) { + if ( hpte2->dw0.dw0.v != 0 ) { + if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) { + printf(" hpte2: %16.16lx *hpte2: %16.16lx %16.16lx\n", + hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1); + } + } + } + } + } else { + printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn)); + printf(" hpte: %16.16lx *hpte: %16.16lx %16.16lx\n", + hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1); + } + } + if (xmon_interrupted()) + return; + } + + + + // print the kernel vsids + kernel_vsid_c0 = get_kernel_vsid(0xC000000000000000); + kernel_vsid_c1 = get_kernel_vsid(0xC000000010000000); + kernel_vsid_c2 = get_kernel_vsid(0xC000000020000000); + kernel_vsid_c3 = get_kernel_vsid(0xC000000030000000); + kernel_vsid_c4 = get_kernel_vsid(0xC000000040000000); + kernel_vsid_c5 = get_kernel_vsid(0xC000000050000000); + kernel_vsid_d = get_kernel_vsid(0xD000000000000000); + kernel_vsid_e = get_kernel_vsid(0xE000000000000000); + kernel_vsid_f = get_kernel_vsid(0xF000000000000000); + + printf(" kernel vsid - seg c0 = %lx\n", kernel_vsid_c0 ); + printf(" kernel vsid - seg c1 = %lx\n", kernel_vsid_c1 ); + printf(" kernel vsid - seg c2 = %lx\n", kernel_vsid_c2 ); + printf(" kernel vsid - seg c3 = %lx\n", kernel_vsid_c3 ); + printf(" kernel vsid - seg c4 = %lx\n", kernel_vsid_c4 ); + printf(" kernel vsid - seg c5 = %lx\n", kernel_vsid_c5 ); + printf(" kernel vsid - seg d = %lx\n", kernel_vsid_d ); + printf(" kernel vsid - seg e = %lx\n", kernel_vsid_e ); + printf(" kernel vsid - seg f = %lx\n", kernel_vsid_f ); + + + // print a list of valid vsids for the tasks + read_lock(&tasklist_lock); + for_each_task(p) + if(p->mm) { + struct mm_struct *mm = p->mm; + printf(" task = %p mm = %lx pgd %lx\n", + p, mm, mm->pgd); + vsid0 = get_vsid( mm->context, 0 ); + vsid1 = get_vsid( mm->context, 0x10000000 ); + vsid2 = get_vsid( mm->context, 0x20000000 ); + vsidB = get_vsid( mm->context, 0xB0000000 ); + printf(" context = %lx vsid seg 0 = %lx\n", mm->context, vsid0 ); + printf(" vsid seg 1 = %lx\n", vsid1 ); + printf(" vsid seg 2 = %lx\n", vsid2 ); + printf(" vsid seg 2 = %lx\n", vsidB ); + + printf("\n"); + }; + read_unlock(&tasklist_lock); + + printf("\nDone -------------------\n"); +} + + + +void mem_check_pagetable_vsids () +{ + unsigned long htab_size_bytes; + unsigned long htab_end; + unsigned long last_rpn; + struct task_struct *p; + unsigned long valid_table_count,invalid_table_count,bogus_rpn_count; + int found; + unsigned long user_address_table_count,kernel_page_table_count; + unsigned long pt_vsid; + HPTE *hpte1; + + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT; + last_rpn = 0xfffff; + + printf("\nHardware Page Table Check\n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + + valid_table_count = 0; + invalid_table_count = 0; + bogus_rpn_count = 0; + user_address_table_count = 0; + kernel_page_table_count = 0; + for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) { + if ( hpte1->dw0.dw0.v != 0 ) { + valid_table_count++; + if ( hpte1->dw1.dw1.rpn <= last_rpn ) { + pt_vsid = (hpte1->dw0.dw0.avpn) >> 5; + if ((pt_vsid == get_kernel_vsid(0xC000000000000000)) | + (pt_vsid == get_kernel_vsid(0xC000000010000000)) | + (pt_vsid == get_kernel_vsid(0xC000000020000000)) | + (pt_vsid == get_kernel_vsid(0xC000000030000000)) | + (pt_vsid == get_kernel_vsid(0xC000000040000000)) | + (pt_vsid == get_kernel_vsid(0xC000000050000000)) | + (pt_vsid == get_kernel_vsid(0xD000000000000000)) | + (pt_vsid == get_kernel_vsid(0xE000000000000000)) | + (pt_vsid == get_kernel_vsid(0xF000000000000000)) ) { + kernel_page_table_count ++; + } else { + read_lock(&tasklist_lock); + found = 0; + for_each_task(p) { + if(p->mm && (found == 0)) { + struct mm_struct *mm = p->mm; + + if ((pt_vsid == get_vsid( mm->context, 0 )) | + (pt_vsid == get_vsid( mm->context, 0x10000000 )) | + (pt_vsid == get_vsid( mm->context, 0x20000000 )) | + (pt_vsid == get_vsid( mm->context, 0x30000000 )) | + (pt_vsid == get_vsid( mm->context, 0x40000000 )) | + (pt_vsid == get_vsid( mm->context, 0x50000000 )) | + (pt_vsid == get_vsid( mm->context, 0x60000000 )) | + (pt_vsid == get_vsid( mm->context, 0x70000000 )) | + (pt_vsid == get_vsid( mm->context, 0x80000000 )) | + (pt_vsid == get_vsid( mm->context, 0x90000000 )) | + (pt_vsid == get_vsid( mm->context, 0xA0000000 )) | + (pt_vsid == get_vsid( mm->context, 0xB0000000 ))) { + user_address_table_count ++; + found = 1; + } + } + } + read_unlock(&tasklist_lock); + if (found == 0) + { + printf(" vsid not found vsid = %lx, hpte = %p \n", + pt_vsid,hpte1); + printf(" rpn in entry = %lx \n", hpte1->dw1.dw1.rpn); + printf(" mem map address = %lx \n", mem_map + (hpte1->dw1.dw1.rpn)); + + } else // found + { + } + + } // good rpn + + } else { + bogus_rpn_count ++; + } + } else { + invalid_table_count++; + } + } + + + printf(" page table valid counts - valid entries = %lx invalid entries = %lx \n", + valid_table_count, invalid_table_count); + + printf(" bogus rpn entries ( probably io) = %lx \n", bogus_rpn_count); + + + + printf(" page table counts - kernel entries = %lx user entries = %lx \n", + kernel_page_table_count, user_address_table_count); + + printf("\nDone -------------------\n"); + +} + + +void mem_check_full_group() +{ + unsigned long htab_size_bytes; + unsigned count; + unsigned count_array[] = {0,0,0,0,0,0,0,0,0}; + unsigned i; + unsigned long htab_end; + HPTE *hpte1, *hpte2, *hpte3; + u64 rpn = 0; + + htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG + htab_end = (unsigned long)htab_data.htab + htab_size_bytes; + + printf("\nHardware Page Find full groups \n-------------------\n"); + printf("htab base : %.16lx\n", htab_data.htab); + printf("htab size : %.16lx\n", htab_size_bytes); + + for (hpte1 = htab_data.htab; (unsigned long)hpte1 < htab_end; hpte1= hpte1 + 8) + { + count = 0; + hpte2 = hpte1; + for (i=0; i<8; ++i) + { + if ( hpte2->dw0.dw0.v != 0 ) + { + count++; + } + hpte2++; + } + if (count == 8 ) + { + printf(" full group starting with entry %lx \n", hpte1); + hpte3 = hpte1; + for (i=0; i<8; ++i) + { + if ( hpte3->dw0.dw0.v != 0 ) + { + printf(" entry number %d \n",i); + printf(" vsid: %.13lx api: %.2lx hash: %.1lx\n", + (hpte3->dw0.dw0.avpn)>>5, + (hpte3->dw0.dw0.avpn) & 0x1f, + (hpte3->dw0.dw0.h)); + printf(" rpn: %.13lx \n", (hpte3->dw1.dw1.rpn)); + // Dump out the memmap array entry address, corresponding virtual address, and reference count. + rpn = hpte3->dw1.dw1.rpn; + printf(" mem_map+rpn=%p, virtual@=%p, count=%lx \n", mem_map+rpn, (mem_map+rpn)->virtual, (mem_map+rpn)->count); + } + hpte3++; + } + if (xmon_interrupted()) + return; + } + + count_array[count]++; + } + for (i=1; i<9; ++i) + { + printf(" group count for size %i = %lx \n", i, count_array[i]); + } + + printf("\nDone -------------------\n"); +} + + + +static void show_task(struct task_struct * p) +{ + /* unsigned long free = 0; --Unused */ + int state; + static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; + + printf("--------------------------------------------------------------------------\n"); + printf("%-11.11s pid: %5.5lx ppid: %5.5lx state: ", + p->comm, p->pid, p->p_pptr->pid); + state = p->state ? ffz(~p->state) + 1 : 0; + if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *)) + printf(stat_nam[state]); + else + printf(" "); + if (p == current) + printf(" pc: current task "); + else + printf(" pc: 0x%16.16lx ", thread_saved_pc(&p->thread)); + + if (p->p_cptr) + printf("%5d ", p->p_cptr->pid); + else + printf(" "); + if (!p->mm) + printf(" (L-TLB) "); + else + printf(" (NOTLB) "); + if (p->p_ysptr) + printf("%7d", p->p_ysptr->pid); + else + printf(" "); + if (p->p_osptr) + printf(" %5d\n", p->p_osptr->pid); + else + printf("\n"); + + { + struct sigqueue *q; + char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; + + render_sigset_t(&p->pending.signal, s); + render_sigset_t(&p->blocked, b); + printf(" sig: %d %s %s :", signal_pending(p), s, b); + for (q = p->pending.head; q ; q = q->next) + printf(" %d", q->info.si_signo); + printf(" X\n"); + } + + printf(" pers : %lx current : %lx", + p->personality, p); + printf("\n"); + + printf(" thread : 0x%16.16lx ksp : 0x%16.16lx\n", + &(p->thread), (p->thread.ksp)); + printf(" pgdir : 0x%16.16lx\n", (p->thread.pgdir)); + printf(" regs : 0x%16.16lx sysc : 0x%16.16lx\n", + (p->thread.regs), (p->thread.last_syscall)); + if(p->thread.regs) { + printf(" nip : 0x%16.16lx msr : 0x%16.16lx\n", + ((p->thread.regs)->nip), ((p->thread.regs)->msr)); + printf(" ctr : 0x%16.16lx link : 0x%16.16lx\n", + ((p->thread.regs)->ctr), ((p->thread.regs)->link)); + printf(" xer : 0x%16.16lx ccr : 0x%16.16lx\n", + ((p->thread.regs)->xer), ((p->thread.regs)->ccr)); + printf(" trap : 0x%16.16lx\n", + ((p->thread.regs)->trap)); + printf(" dar : 0x%16.16lx dsis : 0x%16.16lx\n", + ((p->thread.regs)->dar), ((p->thread.regs)->dsisr)); + printf(" rslt : 0x%16.16lx org3 : 0x%16.16lx\n", + ((p->thread.regs)->result), (p->thread.regs->orig_gpr3)); + } + + if(p->mm) { + struct mm_struct *mm = p->mm; + printf(" mm : 0x%16.16lx pgd : 0x%16.16lx\n", + mm, mm->pgd); + printf(" context: 0x%16.16lx mmap : 0x%16.16lx\n", + mm->context, mm->mmap); + + printf("\n"); + } + +} + +static void xmon_show_state(void) +{ + struct task_struct *p; + +#if (BITS_PER_LONG == 32) + printf("\n" + " free sibling\n"); + printf("task name st PC stack pid father child younger older\n"); +#else + printf("\n" + " free sibling\n"); + printf(" task PC stack pid father child younger older\n"); +#endif + read_lock(&tasklist_lock); + for_each_task(p) + show_task(p); + read_unlock(&tasklist_lock); +} + +static void debug_trace(void) { + unsigned long val, cmd, on; + + cmd = skipbl(); + if (cmd == '\n') { + /* show current state */ + unsigned long i; + printf("naca->debug_switch = 0x%lx\n", naca->debug_switch); + for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) { + on = PPCDBG_BITVAL(i) & naca->debug_switch; + printf("%02x %s %12s ", i, on ? "on " : "off", trace_names[i] ? trace_names[i] : ""); + if (((i+1) % 3) == 0) + printf("\n"); + } + printf("\n"); + return; + } + while (cmd != '\n') { + on = 1; /* default if no sign given */ + while (cmd == '+' || cmd == '-') { + on = (cmd == '+'); + cmd = inchar(); + if (cmd == ' ' || cmd == '\n') { /* Turn on or off based on + or - */ + naca->debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE; + printf("Setting all values to %s...\n", on ? "on" : "off"); + if (cmd == '\n') return; + else cmd = skipbl(); + } + else + termch = cmd; + } + termch = cmd; /* not +/- ... let scanhex see it */ + scanhex((void *)&val); + if (val >= 64) { + printf("Value %x out of range:\n", val); + return; + } + if (on) { + naca->debug_switch |= PPCDBG_BITVAL(val); + printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); + } else { + naca->debug_switch &= ~PPCDBG_BITVAL(val); + printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); + } + cmd = skipbl(); + } +} diff -urN linux-2.4.18/arch/s390/Makefile linux-2.4.19-pre5/arch/s390/Makefile --- linux-2.4.18/arch/s390/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/Makefile Sat Mar 30 22:55:33 2002 @@ -60,6 +60,7 @@ archclean: @$(MAKEBOOT) clean + $(MAKE) -C arch/$(ARCH)/kernel clean archmrproper: diff -urN linux-2.4.18/arch/s390/boot/install.sh linux-2.4.19-pre5/arch/s390/boot/install.sh --- linux-2.4.18/arch/s390/boot/install.sh Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/s390/boot/install.sh Sat Mar 30 22:55:33 2002 @@ -0,0 +1,38 @@ +#!/bin/sh +# +# arch/s390x/boot/install.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# +# "make install" script for s390 architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi +if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi + +# Default install - same as make zlilo + +if [ -f $4/vmlinuz ]; then + mv $4/vmlinuz $4/vmlinuz.old +fi + +if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old +fi + +cat $2 > $4/vmlinuz +cp $3 $4/System.map diff -urN linux-2.4.18/arch/s390/config.in linux-2.4.19-pre5/arch/s390/config.in --- linux-2.4.18/arch/s390/config.in Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/config.in Sat Mar 30 22:55:33 2002 @@ -7,8 +7,8 @@ define_bool CONFIG_EISA n define_bool CONFIG_MCA n define_bool CONFIG_UID16 y -define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y -define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y define_bool CONFIG_GENERIC_BUST_SPINLOCK n mainmenu_name "Linux Kernel Configuration" @@ -37,6 +37,8 @@ mainmenu_option next_comment comment 'General setup' bool 'Fast IRQ handling' CONFIG_FAST_IRQ +bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING +bool 'Use chscs for Common I/O' CONFIG_CHSC bool 'Builtin IPL record support' CONFIG_IPL if [ "$CONFIG_IPL" = "y" ]; then choice 'IPL method generated into head.S' \ diff -urN linux-2.4.18/arch/s390/defconfig linux-2.4.19-pre5/arch/s390/defconfig --- linux-2.4.18/arch/s390/defconfig Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/defconfig Sat Mar 30 22:55:33 2002 @@ -5,8 +5,8 @@ # CONFIG_EISA is not set # CONFIG_MCA is not set CONFIG_UID16=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_GENERIC_BUST_SPINLOCK is not set CONFIG_ARCH_S390=y @@ -131,8 +131,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -144,10 +142,10 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m -# CONFIG_IPV6_NETLINK is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -165,7 +163,7 @@ # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set +CONFIG_NET_FASTROUTE=y # CONFIG_NET_HW_FLOWCONTROL is not set # diff -urN linux-2.4.18/arch/s390/kernel/Makefile linux-2.4.19-pre5/arch/s390/kernel/Makefile --- linux-2.4.18/arch/s390/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390/kernel/Makefile Sat Mar 30 22:55:33 2002 @@ -10,7 +10,7 @@ .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o -all: kernel.o head.o init_task.o +all: asm-offsets.h kernel.o head.o init_task.o O_TARGET := kernel.o @@ -26,6 +26,30 @@ # Kernel debugging # obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o + +.PHONY: asm-offsets.h + +entry.S: asm-offsets.h + +# +# Automatic offset generation for assembler files. +# +asm-offsets.h: asm-offsets.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \ + (echo "#ifndef __ASM_OFFSETS_H__"; \ + echo "#define __ASM_OFFSETS_H__"; \ + echo "/*"; \ + echo " * DO NOT MODIFY"; \ + echo " *"; \ + echo " * This file was generated by arch/s390/kernel/Makefile"; \ + echo " */"; \ + sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \ + -e "s:->::"; \ + echo "#endif" \ + ) > asm-offsets.h + +clean: + rm -f asm-offsets.h include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/s390/kernel/asm-offsets.c linux-2.4.19-pre5/arch/s390/kernel/asm-offsets.c --- linux-2.4.18/arch/s390/kernel/asm-offsets.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/s390/kernel/asm-offsets.c Sat Mar 30 22:55:33 2002 @@ -0,0 +1,32 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + */ + +#include +#include + +/* Use marker if you need to separate the values later */ + +#define DEFINE(sym, val, marker) \ + asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),); + DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),); + DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),); + DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),); + BLANK(); + DEFINE(__TASK_state, offsetof(struct task_struct, state),); + DEFINE(__TASK_sigpending, offsetof(struct task_struct, sigpending),); + DEFINE(__TASK_need_resched, + offsetof(struct task_struct, need_resched),); + DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),); + DEFINE(__TASK_processor, offsetof(struct task_struct, processor),); + + return 0; +} diff -urN linux-2.4.18/arch/s390/kernel/entry.S linux-2.4.19-pre5/arch/s390/kernel/entry.S --- linux-2.4.18/arch/s390/kernel/entry.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -18,6 +18,8 @@ #include #include +#include "asm-offsets.h" + /* * Stack layout for the system_call stack entry. * The first few entries are identical to the user_regs_struct. @@ -44,42 +46,7 @@ SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2 /* Now the additional entries */ SP_TRAP = (SP_ORIG_R2+GPR_SIZE) -#if CONFIG_REMOTE_DEBUG -SP_CRREGS = (SP_TRAP+4) -/* fpu registers are saved & restored by the gdb stub itself */ -SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE)) -SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE) -SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE)) -#else -SP_PGM_OLD_ILC= (SP_TRAP+4) -#endif -SP_SIZE = (SP_PGM_OLD_ILC+4) -/* - * these defines are offsets into the thread_struct - */ -_TSS_PTREGS = 0 -_TSS_FPRS = (_TSS_PTREGS+8) -_TSS_AR2 = (_TSS_FPRS+136) -_TSS_AR4 = (_TSS_AR2+4) -_TSS_KSP = (_TSS_AR4+4) -_TSS_USERSEG = (_TSS_KSP+4) -_TSS_ERROR = (_TSS_USERSEG+4) -_TSS_PROT = (_TSS_ERROR+4) -_TSS_TRAP = (_TSS_PROT+4) -_TSS_MM = (_TSS_TRAP+4) -_TSS_PER = (_TSS_MM+8) -_TSS_IEEE = (_TSS_PER+36) -_TSS_FLAGS = (_TSS_IEEE+4) - -/* - * these are offsets into the task-struct. - */ -state = 0 -flags = 4 -sigpending = 8 -need_resched = 24 -tsk_ptrace = 28 -processor = 52 +SP_SIZE = (SP_TRAP+4) /* * Base Address of this Module --- saved in __LC_ENTRY_BASE @@ -97,12 +64,15 @@ * R15 - kernel stack pointer */ - .macro SAVE_ALL psworg,sync # system entry macro + .macro SAVE_ALL_BASE stm %r13,%r15,__LC_SAVE_AREA basr %r13,0 # temp base pointer - l %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 +0: stam %a2,%a4,__LC_SAVE_AREA+12 + l %r13,.Lentry_base-0b(%r13)# load &entry_base to %r13 + .endm + + .macro SAVE_ALL psworg,sync # system entry macro tm \psworg+1,0x01 # test problem state bit - stam %a2,%a4,__LC_SAVE_AREA+12 .if \sync bz BASED(1f) # skip stack setup save .else @@ -146,8 +116,8 @@ /* * Scheduler resume function, called by switch_to - * grp2 = (thread_struct *) prev->tss - * grp3 = (thread_struct *) next->tss + * gpr2 = (task_struct *) prev + * gpr3 = (task_struct *) next * Returns: * gpr2 = prev */ @@ -155,30 +125,24 @@ resume: basr %r1,0 resume_base: - l %r4,_TSS_PTREGS(%r3) - tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? - bz resume_noper-resume_base(%r1) # if not we're fine - stctl %c9,%c11,24(%r15) # We are using per stuff - clc _TSS_PER(12,%r3),24(%r15) - be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's - lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't + tm __THREAD_per(%r3),0xe8 # new process is using per ? + bz resume_noper-resume_base(%r1) # if not we're fine + stctl %c9,%c11,24(%r15) # We are using per stuff + clc __THREAD_per(12,%r3),24(%r15) + be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's + lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't resume_noper: stm %r6,%r15,24(%r15) # store resume registers of prev task - st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp - lr %r0,%r15 - n %r0,.Lc0xffffe000-resume_base(%r1) - l %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp - l %r1,.Lc8191-resume_base(%r1) - or %r1,%r15 - la %r1,1(%r1) - st %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack - stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2 - stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4 - lam %a2,%a2,_TSS_AR2(%r3) # load kernel access reg. 2 - lam %a4,%a4,_TSS_AR4(%r3) # load kernel access reg. 4 - lr %r2,%r0 # return task_struct of last task - lm %r6,%r15,24(%r15) # load resume registers of next task - br %r14 + st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp + l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp + stam %a2,%a2,__THREAD_ar2(%r2) # store kernel access reg. 2 + stam %a4,%a4,__THREAD_ar4(%r2) # store kernel access reg. 4 + lam %a2,%a2,__THREAD_ar2(%r3) # load kernel access reg. 2 + lam %a4,%a4,__THREAD_ar4(%r3) # load kernel access reg. 4 + lm %r6,%r15,24(%r15) # load resume registers of next task + ahi %r3,8192 + st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack + br %r14 /* * do_softirq calling function. We want to run the softirq functions on the @@ -209,16 +173,14 @@ .globl system_call system_call: + SAVE_ALL_BASE SAVE_ALL __LC_SVC_OLD_PSW,1 - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid -pgm_system_call: + lh %r8,0x8a # get svc number from lowcore + sll %r8,2 GET_CURRENT # load pointer to task_struct to R9 - slr %r8,%r8 # gpr 8 is call save (-> tracesys) - ic %r8,0x8B # get svc number from lowcore stosm 24(%r15),0x03 # reenable interrupts - sll %r8,2 - l %r8,sys_call_table-entry_base(8,%r13) # get address of system call - tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS + l %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr. + tm __TASK_ptrace+3(%r9),0x02 # PT_TRACESYS bnz BASED(sysc_tracesys) basr %r14,%r8 # call sys_xxxx st %r2,SP_R2(%r15) # store return value (change R2 on stack) @@ -231,14 +193,12 @@ # # check, if reschedule is needed # - icm %r0,15,need_resched(%r9) # get need_resched from task_struct + icm %r0,15,__TASK_need_resched(%r9) bnz BASED(sysc_reschedule) - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,__TASK_sigpending(%r9) bnz BASED(sysc_signal_return) sysc_leave: - tm SP_PGM_OLD_ILC(%r15),0xff - bz BASED(pgm_svcret) - stnsm 24(%r15),0xfc # disable I/O and ext. interrupts + stnsm 24(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL 1 # @@ -250,39 +210,42 @@ l %r1,BASED(.Ldo_signal) la %r14,BASED(sysc_leave) br %r1 # return point is sysc_leave - +# +# call schedule with sysc_return as return-address +# +sysc_reschedule: + l %r1,BASED(.Lschedule) + la %r14,BASED(sysc_return) + br %r1 # call scheduler, return to sysc_return # # call trace before and after sys_call # sysc_tracesys: + la %r12,BASED(sysc_return) + +# +# call syscall_trace before and after system call +# special linkage: %r12 contains the return address for trace_svc +# +trace_svc: l %r1,BASED(.Ltrace) l %r7,BASED(.Lc_ENOSYS) st %r7,SP_R2(%r15) # give sysc_trace an -ENOSYS retval basr %r14,%r1 l %r2,SP_R2(%r15) - cr %r2,%r7 # compare with saved -ENOSYS - be BASED(sysc_tracesys_dn1) - # strace wants to change the syscall + cr %r2,%r7 # compare with saved -ENOSYS + be BASED(trace_svc_go) # strace changed the syscall ? sll %r2,24 srl %r2,22 - l %r8,sys_call_table-entry_base(2,%r13) # get address of system call -sysc_tracesys_dn1: + l %r8,sys_call_table-entry_base(%r2,%r13) # get system call addr. +trace_svc_go: lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx st %r2,SP_R2(%r15) # store return value l %r1,BASED(.Ltrace) - la %r14,BASED(sysc_return) - br %r1 # return point is sysc_return - - -# -# call schedule with sysc_return as return-address -# -sysc_reschedule: - l %r1,BASED(.Lschedule) - la %r14,BASED(sysc_return) - br %r1 # call scheduler, return to sysc_return + lr %r14,%r12 # return point is in %r12 + br %r1 # # a new process exits the kernel with ret_from_fork @@ -295,13 +258,9 @@ stosm 24(%r15),0x03 # reenable interrupts sr %r0,%r0 # child returns 0 st %r0,SP_R2(%r15) # store return value (change R2 on stack) -#ifdef CONFIG_SMP l %r1,BASED(.Lschedtail) la %r14,BASED(sysc_return) br %r1 # call schedule_tail, return to sysc_return -#else - b BASED(sysc_return) -#endif # # clone, fork, vfork, exec and sigreturn need glue, @@ -597,11 +556,24 @@ .long sys_madvise .long sys_getdents64 /* 220 */ .long sys_fcntl64 - .long sys_ni_syscall /* 222 - reserved for posix_acl */ - .long sys_ni_syscall /* 223 - reserved for posix_acl */ - .long sys_ni_syscall /* 224 - reserved for posix_acl */ - .rept 255-224 + .long sys_ni_syscall /* 222 - reserved for gettid */ + .long sys_ni_syscall /* 223 - reserved for tkill */ + .long sys_ni_syscall /* 224 - reserved for setxattr */ + .long sys_ni_syscall /* 225 - reserved for lsetxattr */ + .long sys_ni_syscall /* 226 - reserved for fsetxattr */ + .long sys_ni_syscall /* 227 - reserved for getxattr */ + .long sys_ni_syscall /* 228 - reserved for lgetxattr */ + .long sys_ni_syscall /* 229 - reserved for fgetxattr */ + .long sys_ni_syscall /* 230 - reserved for listxattr */ + .long sys_ni_syscall /* 231 - reserved for llistxattr */ + .long sys_ni_syscall /* 232 - reserved for flistxattr */ + .long sys_ni_syscall /* 233 - reserved for removexattr */ + .long sys_ni_syscall /* 234 - reserved for lremovexattr */ + .long sys_ni_syscall /* 235 - reserved for fremovexattr */ + .rept 255-235 .long sys_ni_syscall + .long sys_gettid /* 226 */ + .long sys_tkill /* 227 */ .endr /* @@ -623,93 +595,91 @@ * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ - stm %r13,%r15,__LC_SAVE_AREA - basr %r13,0 # temp base pointer - l %r13,.Lentry_base-.(%r13)# load &entry_base to %r13 + SAVE_ALL_BASE tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - stam %a2,%a4,__LC_SAVE_AREA+12 - bz BASED(pgm_sv) # skip if not + bnz BASED(pgm_per) # got per exception -> special case + SAVE_ALL __LC_PGM_OLD_PSW,1 + l %r7,BASED(.Ljump_table) + lh %r8,__LC_PGM_INT_CODE + sll %r8,2 + GET_CURRENT + l %r7,0(%r8,%r7) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + l %r3,__LC_PGM_ILC # load program interruption code + la %r14,BASED(sysc_return) + br %r7 # branch to interrupt-handler + +# +# handle per exception +# +pgm_per: tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - bnz BASED(pgm_sv) # skip if it is + bnz BASED(pgm_per_std) # ok, normal per event from user space # ok its one of the special cases, now we need to find out which one clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW be BASED(pgm_svcper) # no interesting special case, ignore PER event lm %r13,%r15,__LC_SAVE_AREA lpsw 0x28 -# it was a single stepped SVC that is causing all the trouble -pgm_svcper: - tm 0x21,0x01 # test problem state bit - bz BASED(.+12) # skip stack & access regs setup - l %r15,__LC_KERNEL_STACK # problem state -> load ksp - lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space - # and access reg. 4 to home space - s %r15,BASED(.Lc_spsize) # make room for registers & psw - n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 - stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack - st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack - stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs - mvc SP_PSW(8,%r15),0x20 # move user PSW to stack - la %r0,0x20 # store trap indication - st %r0,SP_TRAP(%r15) - xc 0(4,%r15),0(%r15) # clear back chain - mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information - b BASED(pgm_system_call) # now do the svc -pgm_svcret: - mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk - lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid - b BASED(pgm_no_sv) -pgm_sv: - tm 0x29,0x01 # test problem state bit - bz BASED(.+12) # skip stack & access regs setup - l %r15,__LC_KERNEL_STACK # problem state -> load ksp - lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space - # and access reg. 4 to home space - s %r15,BASED(.Lc_spsize) # make room for registers & psw - n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 - stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack - st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack - stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs - mvc SP_PSW(8,%r15),0x28 # move user PSW to stack - la %r0,0x28 # store trap indication - st %r0,SP_TRAP(%r15) - xc 0(4,%r15),0(%r15) # clear back chain - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid - lh %r7,__LC_PGM_ILC # load instruction length + +# +# Normal per exception +# +pgm_per_std: + SAVE_ALL __LC_PGM_OLD_PSW,1 GET_CURRENT -pgm_no_sv: - la %r3,0x7f - lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - nr %r3,%r8 # reload & clear per-event-bit - be BASED(pgm_dn) # none of Martins exceptions occurred bypass + la %r4,0x7f + l %r3,__LC_PGM_ILC # load program interruption code + nr %r4,%r3 # clear per-event-bit and ilc + be BASED(pgm_per_only) # only per or per+check ? l %r1,BASED(.Ljump_table) - sll %r3,2 - l %r1,0(%r3,%r1) # load address of handler routine - la %r2,SP_PTREGS(%r15) # address of register-save area - srl %r3,2 - cl %r3,BASED(.Lc4) # protection-exception ? - bne BASED(pgm_per) # if not, - l %r5,SP_PSW+4(15) # load psw addr - sr %r5,%r7 # substract ilc from psw - st %r5,SP_PSW+4(15) # store corrected psw addr -pgm_per:basr %r14,%r1 # branch to interrupt-handler -pgm_dn: n %r8,BASED(.Lc128) # check for per excepton - be BASED(pgm_return) - la %r2,SP_PTREGS(15) # address of register-save area - l %r1,BASED(.Lhandle_per) # load adr. of per handler - la %r14,BASED(sysc_return) # load adr. of system return - br %r1 # branch to handle_per_exception + sll %r4,2 + l %r1,0(%r4,%r1) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + basr %r14,%r1 # branch to interrupt-handler +pgm_per_only: + la %r2,SP_PTREGS(15) # address of register-save area + l %r1,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_return) # load adr. of system return + br %r1 # branch to handle_per_exception # -# the backend code is the same as for sys-call +# it was a single stepped SVC that is causing all the trouble # -pgm_return: - b BASED(sysc_return) +pgm_svcper: + SAVE_ALL __LC_SVC_OLD_PSW,1 + GET_CURRENT # load pointer to task_struct to R9 + lh %r8,0x8a # get svc number from lowcore + sll %r8,2 + stosm 24(%r15),0x03 # reenable interrupts + l %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr. + tm __TASK_ptrace+3(%r9),0x02 # PT_TRACESYS + bnz BASED(pgm_tracesys) + basr %r14,%r8 # call sys_xxxx + st %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! + +pgm_svcret: + icm %r0,15,__TASK_sigpending(%r9) + bz BASED(pgm_svcper_nosig) + la %r2,SP_PTREGS(%r15) # load pt_regs + sr %r3,%r3 # clear *oldset + l %r1,BASED(.Ldo_signal) + basr %r4,%r1 # call do_signal + +pgm_svcper_nosig: + mvi SP_TRAP+3(%r15),0x28 # set trap indication to pgm check + la %r2,SP_PTREGS(15) # address of register-save area + l %r1,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_return) # load adr. of system return + br %r1 # branch to handle_per_exception +# +# call trace before and after sys_call +# +pgm_tracesys: + la %r12,BASED(pgm_svcret) + b BASED(trace_svc) /* * IO interrupt handler routine @@ -717,21 +687,22 @@ .globl io_int_handler io_int_handler: + SAVE_ALL_BASE SAVE_ALL __LC_IO_OLD_PSW,0 GET_CURRENT # load pointer to task_struct to R9 + l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 - icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int + icm %r3,3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int l %r4,__LC_IO_INT_PARM # load interuption parm l %r5,__LC_IO_INT_WORD # load interuption word - l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ basr %r14,%r1 # branch to standard irq handler io_return: # # check, if bottom-half has to be done # - l %r1,processor(%r9) # get cpu number from task struture + l %r1,__TASK_processor(%r9) sll %r1,L1_CACHE_SHIFT al %r1,BASED(.Lirq_stat) # get address of irq_stat icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending @@ -744,9 +715,9 @@ # # check, if reschedule is needed # - icm %r0,15,need_resched(%r9) # get need_resched from task_struct + icm %r0,15,__TASK_need_resched(%r9) bnz BASED(io_reschedule) - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,__TASK_sigpending(%r9) bnz BASED(io_signal_return) io_leave: stnsm 24(%r15),0xfc # disable I/O and ext. interrupts @@ -784,6 +755,7 @@ .globl ext_int_handler ext_int_handler: + SAVE_ALL_BASE SAVE_ALL __LC_EXT_OLD_PSW,0 GET_CURRENT # load pointer to task_struct to R9 la %r2,SP_PTREGS(%r15) # address of register-save area @@ -812,6 +784,7 @@ .globl mcck_int_handler mcck_int_handler: + SAVE_ALL_BASE SAVE_ALL __LC_MCK_OLD_PSW,0 l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler @@ -894,7 +867,5 @@ .Ltrace: .long syscall_trace .Lvfork: .long sys_vfork -#ifdef CONFIG_SMP .Lschedtail: .long schedule_tail -#endif diff -urN linux-2.4.18/arch/s390/kernel/irq.c linux-2.4.19-pre5/arch/s390/kernel/irq.c --- linux-2.4.18/arch/s390/kernel/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390/kernel/irq.c Sat Mar 30 22:55:33 2002 @@ -59,60 +59,6 @@ BUILD_SMP_INTERRUPT(spurious_interrupt) #endif -#if 0 -int get_irq_list(char *buf) -{ - int i, j; - struct irqaction * action; - char *p = buf; - - p += sprintf(p, " "); - - for (j=0; jirq_desc.action; - - if (!action) - continue; - - p += sprintf(p, "%3d: ",i); -#ifndef CONFIG_SMP - p += sprintf(p, "%10u ", kstat_irqs(i)); -#else - for (j=0; jirq_desc.handler->typename); - p += sprintf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - { - p += sprintf(p, ", %s", action->name); - - } /* endfor */ - - *p++ = '\n'; - - } /* endfor */ - - p += sprintf(p, "NMI: %10u\n", nmi_counter); -#ifdef CONFIG_SMP - p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count)); -#endif - - return p - buf; -} -#endif - /* * Global interrupt locks for SMP. Allow interrupts to come in on any * CPU, yet make cli/sti act globally to protect critical regions.. diff -urN linux-2.4.18/arch/s390/kernel/process.c linux-2.4.19-pre5/arch/s390/kernel/process.c --- linux-2.4.18/arch/s390/kernel/process.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/process.c Sat Mar 30 22:55:33 2002 @@ -50,28 +50,40 @@ * The idle loop on a S390... */ -static psw_t wait_psw; - int cpu_idle(void *unused) { + psw_t wait_psw; + unsigned long reg; + /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; current->counter = -100; - wait_psw.mask = _WAIT_PSW_MASK; - wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L; - while(1) { - if (current->need_resched) { - schedule(); - check_pgt_cache(); - continue; - } - - /* load wait psw */ + while (1) { + if (current->need_resched) { + schedule(); + check_pgt_cache(); + continue; + } + + /* + * Wait for external, I/O or machine check interrupt and + * switch of machine check bit after the wait has ended. + */ + wait_psw.mask = _WAIT_PSW_MASK; asm volatile ( - "lpsw %0" - : : "m" (wait_psw) ); -idle_wakeup: + " basr %0,0\n" + "0: la %0,1f-0b(%0)\n" + " st %0,4(%1)\n" + " oi 4(%1),0x80\n" + " lpsw 0(%1)\n" + "1: la %0,2f-1b(%0)\n" + " st %0,4(%1)\n" + " oi 4(%1),0x80\n" + " ni 1(%1),0xf9\n" + " lpsw 0(%1)\n" + "2:" + : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); } } @@ -166,11 +178,9 @@ /* fake return stack for resume(), don't go back to schedule */ frame->gprs[9] = (unsigned long) frame; - frame->childregs.old_ilc = -1; /* We are not single stepping an svc */ /* save fprs, if used in last task */ save_fp_regs(&p->thread.fp_regs); p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE; - p->thread.fs = USER_DS; /* Don't copy debug registers */ memset(&p->thread.per_info,0,sizeof(p->thread.per_info)); return 0; diff -urN linux-2.4.18/arch/s390/kernel/reipl.S linux-2.4.19-pre5/arch/s390/kernel/reipl.S --- linux-2.4.18/arch/s390/kernel/reipl.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390/kernel/reipl.S Sat Mar 30 22:55:33 2002 @@ -21,8 +21,10 @@ oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 msch .Lschib-.Lpg0(%r13) - ssch .Liplorb-.Lpg0(%r13) - jz .L001 + lhi %r0,5 +.Lssch: ssch .Liplorb-.Lpg0(%r13) + jz .L001 + brct %r0,.Lssch bas %r14,.Ldisab-.Lpg0(%r13) .L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) .Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) diff -urN linux-2.4.18/arch/s390/kernel/s390_ksyms.c linux-2.4.19-pre5/arch/s390/kernel/s390_ksyms.c --- linux-2.4.18/arch/s390/kernel/s390_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/s390_ksyms.c Sat Mar 30 22:55:33 2002 @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include diff -urN linux-2.4.18/arch/s390/kernel/setup.c linux-2.4.19-pre5/arch/s390/kernel/setup.c --- linux-2.4.18/arch/s390/kernel/setup.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/setup.c Sat Mar 30 22:55:33 2002 @@ -48,7 +48,7 @@ unsigned int console_device = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; -struct { unsigned long addr, size, type; } memory_chunk[16]; +struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } }; #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 __u16 boot_cpu_addr; @@ -284,8 +284,8 @@ * print what head.S has found out about the machine */ printk((MACHINE_IS_VM) ? - "We are running under VM\n" : - "We are running native\n"); + "We are running under VM (31 bit mode)\n" : + "We are running native (31 bit mode)\n"); printk((MACHINE_HAS_IEEE) ? "This machine has an IEEE fpu\n" : "This machine has no IEEE fpu\n"); @@ -494,9 +494,9 @@ "bogomips per cpu: %lu.%02lu\n", smp_num_cpus, loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); - } + } if (cpu_online_map & (1 << n)) { - cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; + cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data; seq_printf(m, "processor %i: " "version = %02X, " "identification = %06X, " diff -urN linux-2.4.18/arch/s390/kernel/signal.c linux-2.4.19-pre5/arch/s390/kernel/signal.c --- linux-2.4.18/arch/s390/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -563,10 +563,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/s390/kernel/smp.c linux-2.4.19-pre5/arch/s390/kernel/smp.c --- linux-2.4.18/arch/s390/kernel/smp.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/smp.c Sat Mar 30 22:55:33 2002 @@ -191,7 +191,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_restart); - for (;;); + for (;;) + enabled_wait(); } else do_machine_restart(); } @@ -208,7 +209,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_halt); - for (;;); + for (;;) + enabled_wait(); } else do_machine_halt(); } @@ -225,7 +227,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_power_off); - for (;;); + for (;;) + enabled_wait(); } else do_machine_power_off(); } @@ -267,7 +270,7 @@ */ static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig) { - struct _lowcore *lowcore = &get_cpu_lowcore(cpu); + struct _lowcore *lowcore = get_cpu_lowcore(cpu); sigp_ccode ccode; /* @@ -291,12 +294,13 @@ for (i = 0; i < smp_num_cpus; i++) { if (smp_processor_id() == i) continue; - lowcore = &get_cpu_lowcore(i); + lowcore = get_cpu_lowcore(i); /* * Set signaling bit in lowcore of target cpu and kick it */ atomic_set_mask(1<ext_call_fast); - ccode = signal_processor(i, sigp_external_call); + while (signal_processor(i, sigp_external_call) == sigp_busy) + udelay(10); } } @@ -313,7 +317,7 @@ /* write magic number to zero page (absolute 0) */ - get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC; + get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC; /* stop all processors */ @@ -335,7 +339,7 @@ for (i = 0; i < smp_num_cpus; i++) { if (smp_processor_id() != i) { int ccode; - low_core_addr = (unsigned long)&get_cpu_lowcore(i); + low_core_addr = (unsigned long)get_cpu_lowcore(i); do { ccode = signal_processor_ps( &dummy, @@ -479,7 +483,7 @@ /* Setup the cpu */ cpu_init(); /* Print info about this processor */ - print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data); + print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data); /* Wait for completion of smp startup */ while (!atomic_read(&smp_commenced)) /* nothing */ ; @@ -535,7 +539,7 @@ unhash_process(idle); init_tasks[cpu] = idle; - cpu_lowcore=&get_cpu_lowcore(cpu); + cpu_lowcore = get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; cpu_lowcore->kernel_stack = (__u32) idle + 8192; __asm__ __volatile__("la 1,%0\n\t" @@ -589,7 +593,7 @@ /* * Initialize the logical to physical CPU number mapping */ - print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); + print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data); for(i = 0; i < smp_num_cpus; i++) { @@ -642,3 +646,4 @@ EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(smp_call_function); diff -urN linux-2.4.18/arch/s390/kernel/time.c linux-2.4.19-pre5/arch/s390/kernel/time.c --- linux-2.4.18/arch/s390/kernel/time.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/time.c Sat Mar 30 22:55:33 2002 @@ -82,7 +82,7 @@ { __u64 now; - asm ("STCK %0" : "=m" (now)); + asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); now = (now - init_timer_cc) >> 12; /* We require the offset from the latest update of xtime */ now -= (__u64) wall_jiffies*USECS_PER_JIFFY; @@ -200,9 +200,10 @@ int cc; /* kick the TOD clock */ - asm volatile ("STCK %1\n\t" + asm volatile ("STCK 0(%1)\n\t" "IPM %0\n\t" - "SRL %0,28" : "=r" (cc), "=m" (init_timer_cc)); + "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc) + : "memory", "cc"); switch (cc) { case 0: /* clock in set state: all is fine */ break; diff -urN linux-2.4.18/arch/s390/kernel/traps.c linux-2.4.19-pre5/arch/s390/kernel/traps.c --- linux-2.4.18/arch/s390/kernel/traps.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390/kernel/traps.c Sat Mar 30 22:55:33 2002 @@ -50,7 +50,9 @@ #endif #endif -extern pgm_check_handler_t do_page_fault; +extern pgm_check_handler_t do_protection_exception; +extern pgm_check_handler_t do_segment_exception; +extern pgm_check_handler_t do_page_exception; extern pgm_check_handler_t do_pseudo_page_fault; #ifdef CONFIG_PFAULT extern int pfault_init(void); @@ -269,23 +271,6 @@ do_exit(SIGSEGV); } -#define DO_ERROR(signr, str, name) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ -{ \ - do_trap(interruption_code, signr, str, regs, NULL); \ -} - -#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ -{ \ - siginfo_t info; \ - info.si_signo = signr; \ - info.si_errno = 0; \ - info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ - do_trap(interruption_code, signr, str, regs, &info); \ -} - static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { @@ -299,7 +284,7 @@ if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; - tsk->thread.trap_no = interruption_code; + tsk->thread.trap_no = interruption_code & 0xffff; if (info) force_sig_info(signr, info, tsk); else @@ -326,6 +311,11 @@ } } +static inline void *get_check_address(struct pt_regs *regs) +{ + return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc); +} + int do_debugger_trap(struct pt_regs *regs,int signal) { if(regs->psw.mask&PSW_PROBLEM_STATE) @@ -349,14 +339,68 @@ return 0; } +#define DO_ERROR(signr, str, name) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + do_trap(interruption_code, signr, str, regs, NULL); \ +} + +#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(interruption_code, signr, str, regs, &info); \ +} + DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) -DO_ERROR(SIGILL, "privileged operation", privileged_op) -DO_ERROR(SIGILL, "execute exception", execute_exception) -DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) -DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) -DO_ERROR(SIGILL, "translation exception", translation_exception) -DO_ERROR(SIGILL, "special operand exception", special_op_exception) -DO_ERROR(SIGILL, "operand exception", operand_exception) + +DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception, + BUS_ADRERR, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, + FPE_INTDIV, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, + ILL_PRVOPC, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, + ILL_ILLOPN, get_check_address(regs)) + +static inline void +do_fp_trap(struct pt_regs *regs, void *location, + int fpc, long interruption_code) +{ + siginfo_t si; + + si.si_signo = SIGFPE; + si.si_errno = 0; + si.si_addr = location; + si.si_code = 0; + /* FPC[2] is Data Exception Code */ + if ((fpc & 0x00000300) == 0) { + /* bits 6 and 7 of DXC are 0 iff IEEE exception */ + if (fpc & 0x8000) /* invalid fp operation */ + si.si_code = FPE_FLTINV; + else if (fpc & 0x4000) /* div by 0 */ + si.si_code = FPE_FLTDIV; + else if (fpc & 0x2000) /* overflow */ + si.si_code = FPE_FLTOVF; + else if (fpc & 0x1000) /* underflow */ + si.si_code = FPE_FLTUND; + else if (fpc & 0x0800) /* inexact */ + si.si_code = FPE_FLTRES; + } + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, SIGFPE, + "floating point exception", regs, &si); +} asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { @@ -407,11 +451,10 @@ #endif else signal = SIGILL; - if (signal == SIGFPE) { - current->thread.ieee_instruction_pointer = (addr_t) location; - do_trap(interruption_code, signal, - "floating point exception", regs, NULL); - } else if (signal) + if (signal == SIGFPE) + do_fp_trap(regs, location, + current->thread.fp_regs.fpc, interruption_code); + else if (signal) do_trap(interruption_code, signal, "illegal operation", regs, NULL); } @@ -426,7 +469,7 @@ __u16 *location = NULL; int signal = 0; - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *) get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -466,16 +509,22 @@ } } else signal = SIGILL; - if (signal == SIGFPE) { - current->thread.ieee_instruction_pointer = (addr_t) location; - do_trap(interruption_code, signal, - "floating point exception", regs, NULL); - } else if (signal) - do_trap(interruption_code, signal, - "specification exception", regs, NULL); + if (signal == SIGFPE) + do_fp_trap(regs, location, + current->thread.fp_regs.fpc, interruption_code); + else if (signal) { + siginfo_t info; + info.si_signo = signal; + info.si_errno = 0; + info.si_code = ILL_ILLOPN; + info.si_addr = location; + do_trap(interruption_code, signal, + "specification exception", regs, &info); + } } #else -DO_ERROR(SIGILL, "specification exception", specification_exception) +DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, + ILL_ILLOPN, get_check_address(regs)); #endif asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) @@ -484,7 +533,7 @@ __u16 *location; int signal = 0; - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *) get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -555,13 +604,18 @@ signal = SIGFPE; else signal = SIGILL; - if (signal == SIGFPE) { - current->thread.ieee_instruction_pointer = (addr_t) location; - do_trap(interruption_code, signal, - "floating point exception", regs, NULL); - } else if (signal) - do_trap(interruption_code, signal, - "data exception", regs, NULL); + if (signal == SIGFPE) + do_fp_trap(regs, location, + current->thread.fp_regs.fpc, interruption_code); + else if (signal) { + siginfo_t info; + info.si_signo = signal; + info.si_errno = 0; + info.si_code = ILL_ILLOPN; + info.si_addr = location; + do_trap(interruption_code, signal, + "data exception", regs, &info); + } } @@ -577,13 +631,13 @@ pgm_check_table[1] = &illegal_op; pgm_check_table[2] = &privileged_op; pgm_check_table[3] = &execute_exception; - pgm_check_table[4] = &do_page_fault; + pgm_check_table[4] = &do_protection_exception; pgm_check_table[5] = &addressing_exception; pgm_check_table[6] = &specification_exception; pgm_check_table[7] = &data_exception; pgm_check_table[9] = ÷_exception; - pgm_check_table[0x10] = &do_page_fault; - pgm_check_table[0x11] = &do_page_fault; + pgm_check_table[0x10] = &do_segment_exception; + pgm_check_table[0x11] = &do_page_exception; pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; pgm_check_table[0x14] = &do_pseudo_page_fault; diff -urN linux-2.4.18/arch/s390/mm/fault.c linux-2.4.19-pre5/arch/s390/mm/fault.c --- linux-2.4.18/arch/s390/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390/mm/fault.c Sat Mar 30 22:55:33 2002 @@ -36,7 +36,6 @@ #endif extern void die(const char *,struct pt_regs *,long); -static void force_sigsegv(struct task_struct *tsk, int code, void *address); extern spinlock_t timerlist_lock; @@ -66,25 +65,95 @@ } /* + * Check which address space is addressed by the access + * register in S390_lowcore.exc_access_id. + * Returns 1 for user space and 0 for kernel space. + */ +static int __check_access_register(struct pt_regs *regs, int error_code) +{ + int areg = S390_lowcore.exc_access_id; + + if (areg == 0) + /* Access via access register 0 -> kernel address */ + return 0; + if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1) + /* + * access register contains 0 -> kernel address, + * access register contains 1 -> user space address + */ + return regs->acrs[areg]; + + /* Something unhealthy was done with the access registers... */ + die("page fault via unknown access register", regs, error_code); + do_exit(SIGKILL); + return 0; +} + +/* + * Check which address space the address belongs to. + * Returns 1 for user space and 0 for kernel space. + */ +static inline int check_user_space(struct pt_regs *regs, int error_code) +{ + /* + * The lowest two bits of S390_lowcore.trans_exc_code indicate + * which paging table was used: + * 0: Primary Segment Table Descriptor + * 1: STD determined via access register + * 2: Secondary Segment Table Descriptor + * 3: Home Segment Table Descriptor + */ + int descriptor = S390_lowcore.trans_exc_code & 3; + if (descriptor == 1) + return __check_access_register(regs, error_code); + return descriptor >> 1; +} + +/* + * Send SIGSEGV to task. This is an external routine + * to keep the stack usage of do_page_fault small. + */ +static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, + int si_code, unsigned long address) +{ + struct siginfo si; + +#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) +#if defined(CONFIG_SYSCTL) + if (sysctl_userprocess_debug) +#endif + { + printk("User process fault: interruption code 0x%lX\n", + error_code); + printk("failing address: %lX\n", address); + show_regs(regs); + } +#endif + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, current); +} + +/* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines. * * error_code: - * ****0004 Protection -> Write-Protection (suprression) - * ****0010 Segment translation -> Not present (nullification) - * ****0011 Page translation -> Not present (nullification) + * 04 Protection -> Write-Protection (suprression) + * 10 Segment translation -> Not present (nullification) + * 11 Page translation -> Not present (nullification) */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; unsigned long address; + int user_address; unsigned long fixup; - int write; int si_code = SEGV_MAPERR; - int kernel_address = 0; tsk = current; mm = tsk->mm; @@ -94,13 +163,13 @@ * as a special case because the translation exception code * field is not guaranteed to contain valid data in this case. */ - if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) { + if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) { /* Low-address protection hit in kernel mode means NULL pointer write access in kernel mode. */ if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { address = 0; - kernel_address = 1; + user_address = 0; goto no_context; } @@ -114,52 +183,15 @@ * more specific the segment and page table portion of * the address */ - address = S390_lowcore.trans_exc_code&0x7ffff000; - + user_address = check_user_space(regs, error_code); /* - * Check which address space the address belongs to + * Verify that the fault happened in user space, that + * we are not in an interrupt and that there is a + * user context. */ - switch (S390_lowcore.trans_exc_code & 3) - { - case 0: /* Primary Segment Table Descriptor */ - kernel_address = 1; - goto no_context; - - case 1: /* STD determined via access register */ - if (S390_lowcore.exc_access_id == 0) - { - kernel_address = 1; - goto no_context; - } - if (regs && S390_lowcore.exc_access_id < NUM_ACRS) - { - if (regs->acrs[S390_lowcore.exc_access_id] == 0) - { - kernel_address = 1; - goto no_context; - } - if (regs->acrs[S390_lowcore.exc_access_id] == 1) - { - /* user space address */ - break; - } - } - die("page fault via unknown access register", regs, error_code); - do_exit(SIGKILL); - break; - - case 2: /* Secondary Segment Table Descriptor */ - case 3: /* Home Segment Table Descriptor */ - /* user space address */ - break; - } - - /* - * Check whether we have a user MM in the first place. - */ - if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) + if (user_address == 0 || in_interrupt() || !mm) goto no_context; /* @@ -167,7 +199,6 @@ * task's user address space, so we can switch on the * interrupts again and then search the VMAs */ - __sti(); down_read(&mm->mmap_sem); @@ -186,30 +217,20 @@ * we can handle it.. */ good_area: - write = 0; si_code = SEGV_ACCERR; + if (error_code != 4) { + /* page not present, check vm flags */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) + goto bad_area; + } - switch (error_code & 0xFF) { - case 0x04: /* write, present*/ - write = 1; - break; - case 0x10: /* not present*/ - case 0x11: /* not present*/ - if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) - goto bad_area; - break; - default: - printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF); - goto bad_area; - } - - survive: +survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. */ - switch (handle_mm_fault(mm, vma, address, write)) { + switch (handle_mm_fault(mm, vma, address, error_code == 4)) { case 1: tsk->min_flt++; break; @@ -236,22 +257,7 @@ if (regs->psw.mask & PSW_PROBLEM_STATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; -#ifndef CONFIG_SYSCTL -#ifdef CONFIG_PROCESS_DEBUG - printk("User process fault: interruption code 0x%lX\n",error_code); - printk("failing address: %lX\n",address); - show_regs(regs); -#endif -#else - if (sysctl_userprocess_debug) { - printk("User process fault: interruption code 0x%lX\n", - error_code); - printk("failing address: %lX\n", address); - show_regs(regs); - } -#endif - - force_sigsegv(tsk, si_code, (void *)address); + force_sigsegv(regs, error_code, si_code, address); return; } @@ -266,8 +272,7 @@ * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ - - if (kernel_address) + if (user_address == 0) printk(KERN_ALERT "Unable to handle kernel pointer dereference" " at virtual kernel address %08lx\n", address); else @@ -311,17 +316,20 @@ goto no_context; } -/* - * Send SIGSEGV to task. This is an external routine - * to keep the stack usage of do_page_fault small. - */ -static void force_sigsegv(struct task_struct *tsk, int code, void *address) +void do_protection_exception(struct pt_regs *regs, unsigned long error_code) { - struct siginfo si; - si.si_signo = SIGSEGV; - si.si_code = code; - si.si_addr = address; - force_sig_info(SIGSEGV, &si, tsk); + regs->psw.addr -= (error_code >> 16); + do_exception(regs, 4); +} + +void do_segment_exception(struct pt_regs *regs, unsigned long error_code) +{ + do_exception(regs, 0x10); +} + +void do_page_exception(struct pt_regs *regs, unsigned long error_code) +{ + do_exception(regs, 0x11); } typedef struct _pseudo_wait_t { @@ -343,7 +351,6 @@ pseudo_wait_t wait_struct; pseudo_wait_t *ptr, *last, *next; unsigned long address; - int kernel_address; /* * get the failing address @@ -393,21 +400,7 @@ * while we are running disabled. VM will then swap * in the page synchronously. */ - kernel_address = 0; - switch (S390_lowcore.trans_exc_code & 3) { - case 0: /* Primary Segment Table Descriptor */ - kernel_address = 1; - break; - case 1: /* STD determined via access register */ - if (S390_lowcore.exc_access_id == 0 || - regs->acrs[S390_lowcore.exc_access_id]==0) - kernel_address = 1; - break; - case 2: /* Secondary Segment Table Descriptor */ - case 3: /* Home Segment Table Descriptor */ - break; - } - if (kernel_address) + if (check_user_space(regs, error_code) == 0) /* dereference a virtual kernel address */ __asm__ __volatile__ ( " ic 0,0(%0)" diff -urN linux-2.4.18/arch/s390x/Makefile linux-2.4.19-pre5/arch/s390x/Makefile --- linux-2.4.18/arch/s390x/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/Makefile Sat Mar 30 22:55:33 2002 @@ -60,6 +60,7 @@ archclean: @$(MAKEBOOT) clean + $(MAKE) -C arch/$(ARCH)/kernel clean archmrproper: diff -urN linux-2.4.18/arch/s390x/boot/install.sh linux-2.4.19-pre5/arch/s390x/boot/install.sh --- linux-2.4.18/arch/s390x/boot/install.sh Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/s390x/boot/install.sh Sat Mar 30 22:55:33 2002 @@ -0,0 +1,38 @@ +#!/bin/sh +# +# arch/s390x/boot/install.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# +# "make install" script for s390 architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi +if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi + +# Default install - same as make zlilo + +if [ -f $4/vmlinuz ]; then + mv $4/vmlinuz $4/vmlinuz.old +fi + +if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old +fi + +cat $2 > $4/vmlinuz +cp $3 $4/System.map diff -urN linux-2.4.18/arch/s390x/config.in linux-2.4.19-pre5/arch/s390x/config.in --- linux-2.4.18/arch/s390x/config.in Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/config.in Sat Mar 30 22:55:33 2002 @@ -6,8 +6,8 @@ define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n -define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y -define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y define_bool CONFIG_GENERIC_BUST_SPINLOCK n mainmenu_name "Linux Kernel Configuration" diff -urN linux-2.4.18/arch/s390x/defconfig linux-2.4.19-pre5/arch/s390x/defconfig --- linux-2.4.18/arch/s390x/defconfig Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/defconfig Sat Mar 30 22:55:33 2002 @@ -4,8 +4,8 @@ # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_MCA is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_GENERIC_BUST_SPINLOCK is not set CONFIG_ARCH_S390=y CONFIG_ARCH_S390X=y @@ -131,8 +131,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -144,10 +142,10 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m -# CONFIG_IPV6_NETLINK is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -165,7 +163,7 @@ # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set +CONFIG_NET_FASTROUTE=y # CONFIG_NET_HW_FLOWCONTROL is not set # diff -urN linux-2.4.18/arch/s390x/kernel/Makefile linux-2.4.19-pre5/arch/s390x/kernel/Makefile --- linux-2.4.18/arch/s390x/kernel/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/kernel/Makefile Sat Mar 30 22:55:33 2002 @@ -10,7 +10,7 @@ .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o -all: kernel.o head.o init_task.o +all: asm-offsets.h kernel.o head.o init_task.o O_TARGET := kernel.o @@ -32,9 +32,31 @@ obj-$(CONFIG_S390_SUPPORT) += linux32.o signal32.o ioctl32.o wrapper32.o exec32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o +.PHONY: asm-offsets.h + # # This is just to get the dependencies... # binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c + +# +# Automatic offset generation for assembler files. +# +asm-offsets.h: asm-offsets.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \ + (echo "#ifndef __ASM_OFFSETS_H__"; \ + echo "#define __ASM_OFFSETS_H__"; \ + echo "/*"; \ + echo " * DO NOT MODIFY"; \ + echo " *"; \ + echo " * This file was generated by arch/s390/kernel/Makefile"; \ + echo " */"; \ + sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \ + -e "s:->::"; \ + echo "#endif" \ + ) > asm-offsets.h + +clean: + rm -f asm-offsets.h include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/s390x/kernel/asm-offsets.c linux-2.4.19-pre5/arch/s390x/kernel/asm-offsets.c --- linux-2.4.18/arch/s390x/kernel/asm-offsets.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/s390x/kernel/asm-offsets.c Sat Mar 30 22:55:33 2002 @@ -0,0 +1,32 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + */ + +#include +#include + +/* Use marker if you need to separate the values later */ + +#define DEFINE(sym, val, marker) \ + asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),); + DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),); + DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),); + DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),); + BLANK(); + DEFINE(__TASK_state, offsetof(struct task_struct, state),); + DEFINE(__TASK_sigpending, offsetof(struct task_struct, sigpending),); + DEFINE(__TASK_need_resched, + offsetof(struct task_struct, need_resched),); + DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),); + DEFINE(__TASK_processor, offsetof(struct task_struct, processor),); + + return 0; +} diff -urN linux-2.4.18/arch/s390x/kernel/entry.S linux-2.4.19-pre5/arch/s390x/kernel/entry.S --- linux-2.4.18/arch/s390x/kernel/entry.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -18,6 +18,7 @@ #include #include +#include "asm-offsets.h" /* * Stack layout for the system_call stack entry. @@ -45,41 +46,7 @@ SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2 /* Now the additional entries */ SP_TRAP = (SP_ORIG_R2+GPR_SIZE) -#if CONFIG_REMOTE_DEBUG -SP_CRREGS = (SP_TRAP+4) -/* fpu registers are saved & restored by the gdb stub itself */ -SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE)) -SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE) -SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE)) -#else -SP_PGM_OLD_ILC= (SP_TRAP+4) -#endif -SP_SIZE = (SP_PGM_OLD_ILC+4) -/* - * these defines are offsets into the thread_struct - */ -_TSS_PTREGS = 0 -_TSS_FPRS = (_TSS_PTREGS+8) -_TSS_AR2 = (_TSS_FPRS+136) -_TSS_AR4 = (_TSS_AR2+4) -_TSS_KSP = (_TSS_AR4+4) -_TSS_USERSEG = (_TSS_KSP+8) -_TSS_PROT = (_TSS_USERSEG+8) -_TSS_ERROR = (_TSS_PROT+8) -_TSS_TRAP = (_TSS_ERROR+4) -_TSS_PER = (_TSS_TRAP+4) -_TSS_IEEE = (_TSS_PER+72) -_TSS_FLAGS = (_TSS_IEEE+8) - -/* - * these are offsets into the task-struct. - */ -state = 0 -flags = 8 -sigpending = 16 -need_resched = 32 -tsk_ptrace = 40 -processor = 88 +SP_SIZE = (SP_TRAP+4) /* * Register usage in interrupt handlers: @@ -136,37 +103,31 @@ /* * Scheduler resume function, called by switch_to - * grp2 = (thread_struct *) prev->tss - * grp3 = (thread_struct *) next->tss + * gpr2 = (task_struct *) prev + * gpr3 = (task_struct *) next * Returns: * gpr2 = prev */ .globl resume resume: - lg %r4,_TSS_PTREGS(%r3) - tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? - jz resume_noper # if not we're fine + tm __THREAD_per+4(%r3),0xe8 # is the new process using per ? + jz resume_noper # if not we're fine stctg %c9,%c11,48(%r15) # We are using per stuff - clc _TSS_PER(24,%r3),48(%r15) + clc __THREAD_per(24,%r3),48(%r15) je resume_noper # we got away without bashing TLB's - lctlg %c9,%c11,_TSS_PER(%r3) # Nope we didn't + lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't resume_noper: stmg %r6,%r15,48(%r15) # store resume registers of prev task - stg %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp - lghi %r0,-16384 - ngr %r0,%r15 - lg %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp - lghi %r1,16383 - ogr %r1,%r15 - aghi %r1,1 - stg %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack - stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2 - stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4 - lam %a2,%a2,_TSS_AR2(%r3) # load kernel access reg. 2 - lam %a4,%a4,_TSS_AR4(%r3) # load kernel access reg. 4 - lgr %r2,%r0 # return task_struct of last task + stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp + lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp + stam %a2,%a2,__THREAD_ar2(%r2) # store kernel access reg. 2 + stam %a4,%a4,__THREAD_ar4(%r2) # store kernel access reg. 4 + lam %a2,%a2,__THREAD_ar2(%r3) # load kernel access reg. 2 + lam %a4,%a4,__THREAD_ar4(%r3) # load kernel access reg. 4 lmg %r6,%r15,48(%r15) # load resume registers of next task - br %r14 + aghi %r3,16384 + stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack + br %r14 /* * do_softirq calling function. We want to run the softirq functions on the @@ -195,19 +156,17 @@ .globl system_call system_call: SAVE_ALL __LC_SVC_OLD_PSW,1 - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid -pgm_system_call: - GET_CURRENT # load pointer to task_struct to R9 larl %r7,sys_call_table - llgc %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore - stosm 48(%r15),0x03 # reenable interrupts + llgh %r8,__LC_SVC_INT_CODE # get svc number from lowcore sll %r8,3 + GET_CURRENT # load pointer to task_struct to R9 + stosm 48(%r15),0x03 # reenable interrupts tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? jo sysc_noemu la %r8,4(%r8) # use 31 bit emulation system calls sysc_noemu: lgf %r8,0(%r8,%r7) # load address of system call routine - tm tsk_ptrace+7(%r9),0x02 # PT_TRACESYS + tm __TASK_ptrace+7(%r9),0x02 # PT_TRACESYS jnz sysc_tracesys basr %r14,%r8 # call sys_xxxx stg %r2,SP_R2(%r15) # store return value (change R2 on stack) @@ -220,14 +179,12 @@ # # check, if reschedule is needed # - lg %r0,need_resched(%r9) # get need_resched from task_struct + lg %r0,__TASK_need_resched(%r9) ltgr %r0,%r0 jnz sysc_reschedule - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,__TASK_sigpending(%r9) jnz sysc_signal_return sysc_leave: - tm SP_PGM_OLD_ILC(%r15),0xff - jz pgm_svcret stnsm 48(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL 1 @@ -241,38 +198,44 @@ jg do_signal # return point is sysc_leave # +# call schedule with sysc_return as return-address +# +sysc_reschedule: + larl %r14,sysc_return + jg schedule # return point is sysc_return +# # call trace before and after sys_call # sysc_tracesys: - lghi %r2,-ENOSYS - stg %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval + larl %r12,sysc_return + +# +# call syscall_trace before and after system call +# special linkage: %r12 contains the return address for trace_svc +# +trace_svc: + lghi %r7,-ENOSYS + stg %r7,SP_R2(%r15) # give sysc_trace an -ENOSYS retval brasl %r14,syscall_trace lg %r2,SP_R2(%r15) cghi %r2,-ENOSYS - je sysc_tracesys_dn1 + je trace_svc_go sllg %r2,%r2,56 # strace wants to change the syscall srlg %r2,%r2,53 # zap unused bits & multiply by 8 tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? - jo sysc_tracesys_noemu + jo trace_svc_noemu la %r2,4(%r2) # use 31 bit emulation system calls -sysc_tracesys_noemu: +trace_svc_noemu: lgf %r8,0(%r2,%r7) # load address of system call routine -sysc_tracesys_dn1: +trace_svc_go: lmg %r3,%r6,SP_R3(%r15) lg %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx stg %r2,SP_R2(%r15) # store return value - larl %r14,sysc_return + lgr %r14,%r12 # return point is in %r12 jg syscall_trace # return point is sysc_return # -# call schedule with sysc_return as return-address -# -sysc_reschedule: - larl %r14,sysc_return - jg schedule # return point is sysc_return - -# # a new process exits the kernel with ret_from_fork # .globl ret_from_fork @@ -280,12 +243,8 @@ GET_CURRENT # load pointer to task_struct to R9 stosm 48(%r15),0x03 # reenable interrupts xc SP_R2(8,%r15),SP_R2(%r15) # child returns 0 -#ifdef CONFIG_SMP larl %r14,sysc_return jg schedule_tail # return to sysc_return -#else - j sysc_return -#endif # # clone, fork, vfork, exec and sigreturn need glue, @@ -630,11 +589,24 @@ .long SYSCALL(sys_madvise,sys32_madvise_wrapper) .long SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */ .long SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper) - .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for posix_acl */ - .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for posix_acl */ - .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */ - .rept 255-224 + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for gettid */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for tkill */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 226 - reserved for fsetxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 227 - reserved for getxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 228 - reserved for lgetxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 229 - reserved for fgetxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 230 - reserved for listxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 231 - reserved for llistxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 232 - reserved for flistxattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 233 - reserved for removexattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 234 - reserved for lremovexattr */ + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 235 - reserved for fremovexattr */ + .rept 255-235 .long SYSCALL(sys_ni_syscall,sys_ni_syscall) + .long SYSCALL(sys_gettid,sys_gettid) + .long SYSCALL(sys_tkill,sys_tkill) .endr /* @@ -657,51 +629,91 @@ * for LPSW?). */ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - jz pgm_sv # skip if not + jnz pgm_per # got per exception -> special case + SAVE_ALL __LC_PGM_OLD_PSW,1 + llgh %r8,__LC_PGM_INT_CODE + sll %r8,3 + GET_CURRENT + larl %r1,pgm_check_table + lg %r1,0(%r8,%r1) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + lgf %r3,__LC_PGM_ILC # load program interruption code + larl %r14,sysc_return + br %r1 # branch to interrupt-handler + +# +# handle per exception +# +pgm_per: tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - jnz pgm_sv # skip if it is + jnz pgm_per_std # ok, normal per event from user space # ok its one of the special cases, now we need to find out which one clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW je pgm_svcper # no interesting special case, ignore PER event lpswe __LC_PGM_OLD_PSW + +# +# Normal per exception +# +pgm_per_std: + SAVE_ALL __LC_PGM_OLD_PSW,1 + GET_CURRENT + lghi %r4,0x7f + lgf %r3,__LC_PGM_ILC # load program interruption code + nr %r4,%r3 # clear per-event-bit and ilc + je pgm_per_only # only per of per+check ? + sll %r4,3 + larl %r1,pgm_check_table + lg %r1,0(%r4,%r1) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + basr %r14,%r1 # branch to interrupt-handler +pgm_per_only: + la %r2,SP_PTREGS(15) # address of register-save area + larl %r14,sysc_return # load adr. of system return + jg handle_per_exception + +# # it was a single stepped SVC that is causing all the trouble +# pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,1 - mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information - j pgm_system_call # now do the svc + larl %r7,sys_call_table + llgh %r8,__LC_SVC_INT_CODE # get svc number from lowcore + sll %r8,3 + GET_CURRENT # load pointer to task_struct to R9 + stosm 48(%r15),0x03 # reenable interrupts + tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? + jo pgm_svcper_noemu + la %r8,4(%r8) # use 31 bit emulation system calls +pgm_svcper_noemu: + lgf %r8,0(%r8,%r7) # load address of system call routine + tm __TASK_ptrace+7(%r9),0x02 # PT_TRACESYS + jnz pgm_tracesys + basr %r14,%r8 # call sys_xxxx + stg %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! + pgm_svcret: + icm %r0,15,__TASK_sigpending(%r9) + jz pgm_svcper_nosig + la %r2,SP_PTREGS(%r15) # load pt_regs + sgr %r3,%r3 # clear *oldset + brasl %r14,do_signal + +pgm_svcper_nosig: lhi %r0,__LC_PGM_OLD_PSW # set trap indication back to pgm_chk st %r0,SP_TRAP(%r15) - llgh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid - j pgm_no_sv -pgm_sv: - SAVE_ALL __LC_PGM_OLD_PSW,1 - mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid - llgh %r7,__LC_PGM_ILC # load instruction length - GET_CURRENT -pgm_no_sv: - llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - lghi %r3,0x7f - nr %r3,%r8 # clear per-event-bit & move to r3 - je pgm_dn # none of Martins exceptions occurred bypass - sll %r3,3 - larl %r1,pgm_check_table - lg %r1,0(%r3,%r1) # load address of handler routine - srl %r3,3 - la %r2,SP_PTREGS(%r15) # address of register-save area - chi %r3,0x4 # protection-exception ? - jne pgm_go # if not, - lg %r5,SP_PSW+8(15) # load psw addr - slgr %r5,%r7 # substract ilc from psw - stg %r5,SP_PSW+8(15) # store corrected psw addr -pgm_go: basr %r14,%r1 # branch to interrupt-handler -pgm_dn: nill %r8,0x80 # check for per exception - je sysc_return la %r2,SP_PTREGS(15) # address of register-save area larl %r14,sysc_return # load adr. of system return jg handle_per_exception +# +# call trace before and after sys_call +# +pgm_tracesys: + larl %r12,pgm_svcret + j trace_svc /* * IO interrupt handler routine @@ -720,7 +732,7 @@ # # check, if bottom-half has to be done # - lgf %r1,processor(%r9) # get cpu number from task struture + lgf %r1,__TASK_processor(%r9) larl %r2,irq_stat sll %r1,L1_CACHE_SHIFT la %r1,0(%r1,%r2) @@ -734,10 +746,10 @@ # # check, if reschedule is needed # - lg %r0,need_resched(%r9) # get need_resched from task_struct + lg %r0,__TASK_need_resched(%r9) ltgr %r0,%r0 jnz io_reschedule - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,__TASK_sigpending(%r9) jnz io_signal_return io_leave: stnsm 48(%r15),0xfc # disable I/O and ext. interrupts diff -urN linux-2.4.18/arch/s390x/kernel/irq.c linux-2.4.19-pre5/arch/s390x/kernel/irq.c --- linux-2.4.18/arch/s390x/kernel/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/kernel/irq.c Sat Mar 30 22:55:33 2002 @@ -59,60 +59,6 @@ BUILD_SMP_INTERRUPT(spurious_interrupt) #endif -#if 0 -int get_irq_list(char *buf) -{ - int i, j; - struct irqaction * action; - char *p = buf; - - p += sprintf(p, " "); - - for (j=0; jirq_desc.action; - - if (!action) - continue; - - p += sprintf(p, "%3d: ",i); -#ifndef CONFIG_SMP - p += sprintf(p, "%10u ", kstat_irqs(i)); -#else - for (j=0; jirq_desc.handler->typename); - p += sprintf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - { - p += sprintf(p, ", %s", action->name); - - } /* endfor */ - - *p++ = '\n'; - - } /* endfor */ - - p += sprintf(p, "NMI: %10u\n", nmi_counter); -#ifdef CONFIG_SMP - p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count)); -#endif - - return p - buf; -} -#endif - /* * Global interrupt locks for SMP. Allow interrupts to come in on any * CPU, yet make cli/sti act globally to protect critical regions.. diff -urN linux-2.4.18/arch/s390x/kernel/linux32.c linux-2.4.19-pre5/arch/s390x/kernel/linux32.c --- linux-2.4.18/arch/s390x/kernel/linux32.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/linux32.c Sat Mar 30 22:55:33 2002 @@ -288,6 +288,21 @@ struct msgbuf32 { s32 mtype; char mtext[1]; }; +struct ipc64_perm_ds32 +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t32 mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned int __unused1; + unsigned int __unused2; +}; + struct ipc_perm32 { key_t key; @@ -311,7 +326,7 @@ }; struct semid64_ds32 { - struct ipc64_perm sem_perm; /* this structure is the same on sparc32 and sparc64 */ + struct ipc64_perm_ds32 sem_perm; unsigned int __pad1; __kernel_time_t32 sem_otime; unsigned int __pad2; @@ -339,7 +354,7 @@ }; struct msqid64_ds32 { - struct ipc64_perm msg_perm; + struct ipc64_perm_ds32 msg_perm; unsigned int __pad1; __kernel_time_t32 msg_stime; unsigned int __pad2; @@ -368,7 +383,7 @@ }; struct shmid64_ds32 { - struct ipc64_perm shm_perm; + struct ipc64_perm_ds32 shm_perm; unsigned int __pad1; __kernel_time_t32 shm_atime; unsigned int __pad2; @@ -1390,7 +1405,7 @@ timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { - time_t sec, usec; + int sec, usec; if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp))) || (ret = __get_user(sec, &tvp->tv_sec)) @@ -1442,7 +1457,7 @@ ret = do_select(n, &fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { - time_t sec = 0, usec = 0; + int sec = 0, usec = 0; if (timeout) { sec = timeout / HZ; usec = timeout % HZ; diff -urN linux-2.4.18/arch/s390x/kernel/process.c linux-2.4.19-pre5/arch/s390x/kernel/process.c --- linux-2.4.18/arch/s390x/kernel/process.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/process.c Sat Mar 30 22:55:33 2002 @@ -50,28 +50,37 @@ * The idle loop on a S390... */ -static psw_t wait_psw; - int cpu_idle(void *unused) { + psw_t wait_psw; + unsigned long reg; + /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; current->counter = -100; - wait_psw.mask = _WAIT_PSW_MASK; - wait_psw.addr = (unsigned long) &&idle_wakeup; - while(1) { - if (current->need_resched) { - schedule(); - check_pgt_cache(); - continue; - } - - /* load wait psw */ + while (1) { + if (current->need_resched) { + schedule(); + check_pgt_cache(); + continue; + } + + /* + * Wait for external, I/O or machine check interrupt and + * switch of machine check bit after the wait has ended. + */ + wait_psw.mask = _WAIT_PSW_MASK; asm volatile ( - "lpswe %0" - : : "m" (wait_psw) ); -idle_wakeup: + " larl %0,0f\n" + " stg %0,8(%1)\n" + " lpswe 0(%1)\n" + "0: larl %0,1f\n" + " stg %0,8(%1)\n" + " ni 1(%1),0xf9\n" + " lpswe 0(%1)\n" + "1:" + : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); } } @@ -165,8 +174,7 @@ frame->gprs[8] = (unsigned long) &ret_from_fork; /* fake return stack for resume(), don't go back to schedule */ - frame->gprs[9] = (unsigned long) frame; - frame->childregs.old_ilc = -1; /* We are not single stepping an svc */ + frame->gprs[9] = (unsigned long) frame; /* save fprs, if used in last task */ save_fp_regs(&p->thread.fp_regs); p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE; diff -urN linux-2.4.18/arch/s390x/kernel/reipl.S linux-2.4.19-pre5/arch/s390x/kernel/reipl.S --- linux-2.4.18/arch/s390x/kernel/reipl.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/kernel/reipl.S Sat Mar 30 22:55:33 2002 @@ -21,8 +21,10 @@ oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 msch .Lschib-.Lpg0(%r13) - ssch .Liplorb-.Lpg0(%r13) - jz .L001 + lghi %r0,5 +.Lssch: ssch .Liplorb-.Lpg0(%r13) + jz .L001 + brct %r0,.Lssch bas %r14,.Ldisab-.Lpg0(%r13) .L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13) .Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13) diff -urN linux-2.4.18/arch/s390x/kernel/s390_ksyms.c linux-2.4.19-pre5/arch/s390x/kernel/s390_ksyms.c --- linux-2.4.18/arch/s390x/kernel/s390_ksyms.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/s390_ksyms.c Sat Mar 30 22:55:33 2002 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.4.18/arch/s390x/kernel/setup.c linux-2.4.19-pre5/arch/s390x/kernel/setup.c --- linux-2.4.18/arch/s390x/kernel/setup.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/setup.c Sat Mar 30 22:55:33 2002 @@ -48,7 +48,7 @@ unsigned int console_device = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; -struct { unsigned long addr, size, type; } memory_chunk[16]; +struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } }; #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 __u16 boot_cpu_addr; @@ -283,8 +283,8 @@ * print what head.S has found out about the machine */ printk((MACHINE_IS_VM) ? - "We are running under VM\n" : - "We are running native\n"); + "We are running under VM (64 bit mode)\n" : + "We are running native (64 bit mode)\n"); ROOT_DEV = to_kdev_t(0x0100); memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ @@ -485,7 +485,7 @@ (loops_per_jiffy/(5000/HZ))%100); } if (cpu_online_map & (1 << n)) { - cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; + cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data; seq_printf(m, "processor %i: " "version = %02X, " "identification = %06X, " diff -urN linux-2.4.18/arch/s390x/kernel/signal.c linux-2.4.19-pre5/arch/s390x/kernel/signal.c --- linux-2.4.18/arch/s390x/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -66,17 +66,15 @@ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ + /* First 64bits of unions are always present. */ err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); default: - err |= __put_user(from->si_uid, &to->si_uid); break; /* case __SI_RT: This is not generated by the kernel as of now. */ } @@ -569,10 +567,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/s390x/kernel/signal32.c linux-2.4.19-pre5/arch/s390x/kernel/signal32.c --- linux-2.4.18/arch/s390x/kernel/signal32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/kernel/signal32.c Sat Mar 30 22:55:33 2002 @@ -30,7 +30,7 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -#define _USER_PSW_MASK32 0x0701C00080000000 +#define _USER_PSW_MASK32 0x0705C00080000000 typedef struct { @@ -699,10 +699,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/s390x/kernel/smp.c linux-2.4.19-pre5/arch/s390x/kernel/smp.c --- linux-2.4.18/arch/s390x/kernel/smp.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/smp.c Sat Mar 30 22:55:33 2002 @@ -191,7 +191,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_restart); - for (;;); + for (;;) + enabled_wait(); } else do_machine_restart(); } @@ -208,7 +209,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_halt); - for (;;); + for (;;) + enabled_wait(); } else do_machine_halt(); } @@ -225,7 +227,8 @@ { if (smp_processor_id() != 0) { smp_ext_bitcall(0, ec_power_off); - for (;;); + for (;;) + enabled_wait(); } else do_machine_power_off(); } @@ -270,7 +273,7 @@ /* * Set signaling bit in lowcore of target cpu and kick it */ - set_bit(sig, &(get_cpu_lowcore(cpu).ext_call_fast)); + set_bit(sig, &(get_cpu_lowcore(cpu)->ext_call_fast)); ccode = signal_processor(cpu, sigp_external_call); return ccode; } @@ -290,8 +293,9 @@ /* * Set signaling bit in lowcore of target cpu and kick it */ - set_bit(sig, &(get_cpu_lowcore(i).ext_call_fast)); - ccode = signal_processor(i, sigp_external_call); + set_bit(sig, &(get_cpu_lowcore(i)->ext_call_fast)); + while (signal_processor(i, sigp_external_call) == sigp_busy) + udelay(10); } } @@ -308,7 +312,7 @@ /* write magic number to zero page (absolute 0) */ - get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC; + get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC; /* stop all processors */ @@ -330,7 +334,7 @@ for (i = 0; i < smp_num_cpus; i++) { if (smp_processor_id() != i) { int ccode; - low_core_addr = (unsigned long)&get_cpu_lowcore(i); + low_core_addr = (unsigned long)get_cpu_lowcore(i); do { ccode = signal_processor_ps( &dummy, @@ -432,6 +436,7 @@ current->processor = 0; smp_num_cpus = 1; + cpu_online_map = 1; for (curr_cpu = 0; curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) { if ((__u16) curr_cpu == boot_cpu_addr) @@ -458,7 +463,7 @@ /* Setup the cpu */ cpu_init(); /* Print info about this processor */ - print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data); + print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data); /* Wait for completion of smp startup */ while (!atomic_read(&smp_commenced)) /* nothing */ ; @@ -514,7 +519,7 @@ unhash_process(idle); init_tasks[cpu] = idle; - cpu_lowcore=&get_cpu_lowcore(cpu); + cpu_lowcore = get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; cpu_lowcore->kernel_stack = (__u64) idle + 16384; __asm__ __volatile__("la 1,%0\n\t" @@ -569,7 +574,7 @@ /* * Initialize the logical to physical CPU number mapping */ - print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); + print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data); for(i = 0; i < smp_num_cpus; i++) { @@ -627,3 +632,4 @@ EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(smp_call_function); diff -urN linux-2.4.18/arch/s390x/kernel/time.c linux-2.4.19-pre5/arch/s390x/kernel/time.c --- linux-2.4.18/arch/s390x/kernel/time.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/time.c Sat Mar 30 22:55:33 2002 @@ -55,7 +55,7 @@ { __u64 now; - asm ("STCK %0" : "=m" (now)); + asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); now = (now - init_timer_cc) >> 12; /* We require the offset from the latest update of xtime */ now -= (__u64) wall_jiffies*USECS_PER_JIFFY; @@ -173,9 +173,10 @@ int cc; /* kick the TOD clock */ - asm volatile ("STCK %1\n\t" + asm volatile ("STCK 0(%1)\n\t" "IPM %0\n\t" - "SRL %0,28" : "=r" (cc), "=m" (init_timer_cc)); + "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc) + : "memory", "cc"); switch (cc) { case 0: /* clock in set state: all is fine */ break; diff -urN linux-2.4.18/arch/s390x/kernel/traps.c linux-2.4.19-pre5/arch/s390x/kernel/traps.c --- linux-2.4.18/arch/s390x/kernel/traps.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/s390x/kernel/traps.c Sat Mar 30 22:55:33 2002 @@ -52,7 +52,10 @@ #endif #endif -extern pgm_check_handler_t do_page_fault; +extern pgm_check_handler_t do_protection_exception; +extern pgm_check_handler_t do_segment_exception; +extern pgm_check_handler_t do_region_exception; +extern pgm_check_handler_t do_page_exception; #ifdef CONFIG_PFAULT extern int pfault_init(void); extern void pfault_fini(void); @@ -270,23 +273,6 @@ do_exit(SIGSEGV); } -#define DO_ERROR(signr, str, name) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ -{ \ - do_trap(interruption_code, signr, str, regs, NULL); \ -} - -#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ -{ \ - siginfo_t info; \ - info.si_signo = signr; \ - info.si_errno = 0; \ - info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ - do_trap(interruption_code, signr, str, regs, &info); \ -} - static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { @@ -299,7 +285,7 @@ if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; - tsk->thread.trap_no = interruption_code; + tsk->thread.trap_no = interruption_code & 0xffff; if (info) force_sig_info(signr, info, tsk); else @@ -326,6 +312,11 @@ } } +static inline void *get_check_address(struct pt_regs *regs) +{ + return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc); +} + int do_debugger_trap(struct pt_regs *regs,int signal) { if(regs->psw.mask&PSW_PROBLEM_STATE) @@ -349,15 +340,70 @@ return 0; } +#define DO_ERROR(signr, str, name) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + do_trap(interruption_code, signr, str, regs, NULL); \ +} + +#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(interruption_code, signr, str, regs, &info); \ +} + DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) -DO_ERROR(SIGILL, "privileged operation", privileged_op) -DO_ERROR(SIGILL, "execute exception", execute_exception) -DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) -DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) -DO_ERROR(SIGILL, "translation exception", translation_exception) -DO_ERROR(SIGILL, "special operand exception", special_op_exception) -DO_ERROR(SIGILL, "operand exception", operand_exception) -DO_ERROR(SIGILL, "specification exception", specification_exception); + +DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception, + BUS_ADRERR, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, + FPE_INTDIV, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, + ILL_PRVOPC, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, + ILL_ILLOPN, get_check_address(regs)) +DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, + ILL_ILLOPN, get_check_address(regs)) + +static inline void +do_fp_trap(struct pt_regs *regs, void *location, + int fpc, long interruption_code) +{ + siginfo_t si; + + si.si_signo = SIGFPE; + si.si_errno = 0; + si.si_addr = location; + si.si_code = 0; + /* FPC[2] is Data Exception Code */ + if ((fpc & 0x00000300) == 0) { + /* bits 6 and 7 of DXC are 0 iff IEEE exception */ + if (fpc & 0x8000) /* invalid fp operation */ + si.si_code = FPE_FLTINV; + else if (fpc & 0x4000) /* div by 0 */ + si.si_code = FPE_FLTDIV; + else if (fpc & 0x2000) /* overflow */ + si.si_code = FPE_FLTOVF; + else if (fpc & 0x1000) /* underflow */ + si.si_code = FPE_FLTUND; + else if (fpc & 0x0800) /* inexact */ + si.si_code = FPE_FLTRES; + } + current->thread.ieee_instruction_pointer = (addr_t) location; + do_trap(interruption_code, SIGFPE, + "floating point exception", regs, &si); +} asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { @@ -365,7 +411,7 @@ __u16 *location; int do_sig = 0; - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *) get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -390,15 +436,15 @@ else do_sig = 1; if (do_sig) - do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL); + do_trap(interruption_code, SIGILL, + "illegal operation", regs, NULL); } asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { __u16 *location; - int do_sig = 0; - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *) get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -409,17 +455,19 @@ __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); - /* Same code should work when we implement fpu emulation */ - /* provided we call data exception from the fpu emulator */ - if(current->thread.fp_regs.fpc&FPC_DXC_MASK) - { - current->thread.ieee_instruction_pointer=(addr_t)location; - force_sig(SIGFPE, current); + + if (current->thread.fp_regs.fpc & FPC_DXC_MASK) + do_fp_trap(regs, location, + current->thread.fp_regs.fpc, interruption_code); + else { + siginfo_t info; + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPN; + info.si_addr = location; + do_trap(interruption_code, SIGILL, + "data exception", regs, &info); } - else - do_sig = 1; - if (do_sig) - do_trap(interruption_code, SIGILL, "data exception", regs, NULL); } @@ -435,6 +483,7 @@ pgm_check_table[1] = &illegal_op; pgm_check_table[2] = &privileged_op; pgm_check_table[3] = &execute_exception; + pgm_check_table[4] = &do_protection_exception; pgm_check_table[5] = &addressing_exception; pgm_check_table[6] = &specification_exception; pgm_check_table[7] = &data_exception; @@ -442,12 +491,11 @@ pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; pgm_check_table[0x15] = &operand_exception; - pgm_check_table[4] = &do_page_fault; - pgm_check_table[0x10] = &do_page_fault; - pgm_check_table[0x11] = &do_page_fault; + pgm_check_table[0x10] = &do_segment_exception; + pgm_check_table[0x11] = &do_page_exception; pgm_check_table[0x1C] = &privileged_op; pgm_check_table[0x38] = &addressing_exception; - pgm_check_table[0x3B] = &do_page_fault; + pgm_check_table[0x3B] = &do_region_exception; #ifdef CONFIG_PFAULT if (MACHINE_IS_VM) { /* request the 0x2603 external interrupt */ diff -urN linux-2.4.18/arch/s390x/mm/fault.c linux-2.4.19-pre5/arch/s390x/mm/fault.c --- linux-2.4.18/arch/s390x/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/s390x/mm/fault.c Sat Mar 30 22:55:33 2002 @@ -35,7 +35,6 @@ #endif extern void die(const char *,struct pt_regs *,long); -static void force_sigsegv(struct task_struct *tsk, int code, void *address); extern spinlock_t timerlist_lock; @@ -65,26 +64,96 @@ } /* + * Check which address space is addressed by the access + * register in S390_lowcore.exc_access_id. + * Returns 1 for user space and 0 for kernel space. + */ +static int __check_access_register(struct pt_regs *regs, int error_code) +{ + int areg = S390_lowcore.exc_access_id; + + if (areg == 0) + /* Access via access register 0 -> kernel address */ + return 0; + if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1) + /* + * access register contains 0 -> kernel address, + * access register contains 1 -> user space address + */ + return regs->acrs[areg]; + + /* Something unhealthy was done with the access registers... */ + die("page fault via unknown access register", regs, error_code); + do_exit(SIGKILL); + return 0; +} + +/* + * Check which address space the address belongs to. + * Returns 1 for user space and 0 for kernel space. + */ +static inline int check_user_space(struct pt_regs *regs, int error_code) +{ + /* + * The lowest two bits of S390_lowcore.trans_exc_code indicate + * which paging table was used: + * 0: Primary Segment Table Descriptor + * 1: STD determined via access register + * 2: Secondary Segment Table Descriptor + * 3: Home Segment Table Descriptor + */ + int descriptor = S390_lowcore.trans_exc_code & 3; + if (descriptor == 1) + return __check_access_register(regs, error_code); + return descriptor >> 1; +} + +/* + * Send SIGSEGV to task. This is an external routine + * to keep the stack usage of do_page_fault small. + */ +static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, + int si_code, unsigned long address) +{ + struct siginfo si; + +#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) +#if defined(CONFIG_SYSCTL) + if (sysctl_userprocess_debug) +#endif + { + printk("User process fault: interruption code 0x%lX\n", + error_code); + printk("failing address: %lX\n", address); + show_regs(regs); + } +#endif + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, current); +} + +/* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines. * * error_code: - * ****0004 Protection -> Write-Protection (suprression) - * ****0010 Segment translation -> Not present (nullification) - * ****0011 Page translation -> Not present (nullification) - * ****003B Region third exception -> Not present (nullification) + * 04 Protection -> Write-Protection (suprression) + * 10 Segment translation -> Not present (nullification) + * 11 Page translation -> Not present (nullification) + * 3b Region third trans. -> Not present (nullification) */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; unsigned long address; + int user_address; unsigned long fixup; - int write; int si_code = SEGV_MAPERR; - int kernel_address = 0; tsk = current; mm = tsk->mm; @@ -94,13 +163,13 @@ * as a special case because the translation exception code * field is not guaranteed to contain valid data in this case. */ - if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) { + if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) { /* Low-address protection hit in kernel mode means NULL pointer write access in kernel mode. */ if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { address = 0; - kernel_address = 1; + user_address = 0; goto no_context; } @@ -114,52 +183,15 @@ * more specific the segment and page table portion of * the address */ - - address = S390_lowcore.trans_exc_code&-4096L; - - - /* - * Check which address space the address belongs to - */ - switch (S390_lowcore.trans_exc_code & 3) - { - case 0: /* Primary Segment Table Descriptor */ - kernel_address = 1; - goto no_context; - - case 1: /* STD determined via access register */ - if (S390_lowcore.exc_access_id == 0) - { - kernel_address = 1; - goto no_context; - } - if (regs && S390_lowcore.exc_access_id < NUM_ACRS) - { - if (regs->acrs[S390_lowcore.exc_access_id] == 0) - { - kernel_address = 1; - goto no_context; - } - if (regs->acrs[S390_lowcore.exc_access_id] == 1) - { - /* user space address */ - break; - } - } - die("page fault via unknown access register", regs, error_code); - do_exit(SIGKILL); - break; - - case 2: /* Secondary Segment Table Descriptor */ - case 3: /* Home Segment Table Descriptor */ - /* user space address */ - break; - } + address = S390_lowcore.trans_exc_code & -4096L; + user_address = check_user_space(regs, error_code); /* - * Check whether we have a user MM in the first place. + * Verify that the fault happened in user space, that + * we are not in an interrupt and that there is a + * user context. */ - if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) + if (user_address == 0 || in_interrupt() || !mm) goto no_context; /* @@ -167,7 +199,6 @@ * task's user address space, so we can switch on the * interrupts again and then search the VMAs */ - __sti(); down_read(&mm->mmap_sem); @@ -186,31 +217,20 @@ * we can handle it.. */ good_area: - write = 0; si_code = SEGV_ACCERR; + if (error_code != 4) { + /* page not present, check vm flags */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) + goto bad_area; + } - switch (error_code & 0xFF) { - case 0x04: /* write, present*/ - write = 1; - break; - case 0x10: /* not present*/ - case 0x11: /* not present*/ - case 0x3B: /* not present*/ - if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) - goto bad_area; - break; - default: - printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF); - goto bad_area; - } - - survive: +survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. */ - switch (handle_mm_fault(mm, vma, address, write)) { + switch (handle_mm_fault(mm, vma, address, error_code == 4)) { case 1: tsk->min_flt++; break; @@ -237,22 +257,7 @@ if (regs->psw.mask & PSW_PROBLEM_STATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; -#ifndef CONFIG_SYSCTL -#ifdef CONFIG_PROCESS_DEBUG - printk("User process fault: interruption code 0x%lX\n",error_code); - printk("failing address: %lX\n",address); - show_regs(regs); -#endif -#else - if (sysctl_userprocess_debug) { - printk("User process fault: interruption code 0x%lX\n", - error_code); - printk("failing address: %lX\n", address); - show_regs(regs); - } -#endif - - force_sigsegv(tsk, si_code, (void *)address); + force_sigsegv(regs, error_code, si_code, address); return; } @@ -267,8 +272,7 @@ * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ - - if (kernel_address) + if (user_address == 0) printk(KERN_ALERT "Unable to handle kernel pointer dereference" " at virtual kernel address %016lx\n", address); else @@ -312,19 +316,26 @@ goto no_context; } -/* - * Send SIGSEGV to task. This is an external routine - * to keep the stack usage of do_page_fault small. - */ -static void force_sigsegv(struct task_struct *tsk, int code, void *address) +void do_protection_exception(struct pt_regs *regs, unsigned long error_code) { - struct siginfo si; - si.si_signo = SIGSEGV; - si.si_code = code; - si.si_addr = address; - force_sig_info(SIGSEGV, &si, tsk); + regs->psw.addr -= (error_code >> 16); + do_exception(regs, 4); } +void do_segment_exception(struct pt_regs *regs, unsigned long error_code) +{ + do_exception(regs, 0x10); +} + +void do_page_exception(struct pt_regs *regs, unsigned long error_code) +{ + do_exception(regs, 0x11); +} + +void do_region_exception(struct pt_regs *regs, unsigned long error_code) +{ + do_exception(regs, 0x3b); +} #ifdef CONFIG_PFAULT /* diff -urN linux-2.4.18/arch/sh/kernel/entry.S linux-2.4.19-pre5/arch/sh/kernel/entry.S --- linux-2.4.18/arch/sh/kernel/entry.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sh/kernel/entry.S Sat Mar 30 22:55:33 2002 @@ -1298,6 +1298,8 @@ .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_gettid) + .long SYMBOL_NAME(sys_tkill) /* * NOTE!! This doesn't have to be exact - we just have diff -urN linux-2.4.18/arch/sh/kernel/signal.c linux-2.4.19-pre5/arch/sh/kernel/signal.c --- linux-2.4.18/arch/sh/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sh/kernel/signal.c Sat Mar 30 22:55:33 2002 @@ -671,10 +671,7 @@ /* FALLTHRU */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } diff -urN linux-2.4.18/arch/sparc/kernel/ioport.c linux-2.4.19-pre5/arch/sparc/kernel/ioport.c --- linux-2.4.18/arch/sparc/kernel/ioport.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/ioport.c Sat Mar 30 22:55:39 2002 @@ -161,7 +161,7 @@ static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, unsigned long size, char *name) { - static int printed_full = 0; + static int printed_full; struct xresource *xres; struct resource *res; char *tack; diff -urN linux-2.4.18/arch/sparc/kernel/irq.c linux-2.4.19-pre5/arch/sparc/kernel/irq.c --- linux-2.4.18/arch/sparc/kernel/irq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/irq.c Sat Mar 30 22:55:39 2002 @@ -90,7 +90,7 @@ */ #define MAX_STATIC_ALLOC 4 struct irqaction static_irqaction[MAX_STATIC_ALLOC]; -int static_irq_count = 0; +int static_irq_count; struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, diff -urN linux-2.4.18/arch/sparc/kernel/pcic.c linux-2.4.19-pre5/arch/sparc/kernel/pcic.c --- linux-2.4.18/arch/sparc/kernel/pcic.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc/kernel/pcic.c Sat Mar 30 22:55:39 2002 @@ -185,7 +185,7 @@ * Only one PCIC per IIep, * and since we have no SMP IIep, only one per system. */ -static int pcic0_up = 0; +static int pcic0_up; static struct linux_pcic pcic0; unsigned int pcic_regs; diff -urN linux-2.4.18/arch/sparc/kernel/process.c linux-2.4.19-pre5/arch/sparc/kernel/process.c --- linux-2.4.18/arch/sparc/kernel/process.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/process.c Sat Mar 30 22:55:39 2002 @@ -67,9 +67,9 @@ for (;;) { if (ARCH_SUN4C_SUN4) { static int count = HZ; - static unsigned long last_jiffies = 0; - static unsigned long last_faults = 0; - static unsigned long fps = 0; + static unsigned long last_jiffies; + static unsigned long last_faults; + static unsigned long fps; unsigned long now; unsigned long faults; unsigned long flags; @@ -87,7 +87,7 @@ fps = (fps + (faults - last_faults)) >> 1; last_faults = faults; #if 0 - printk("kernel faults / second = %d\n", fps); + printk("kernel faults / second = %ld\n", fps); #endif if (fps >= SUN4C_FAULT_HIGH) { sun4c_grow_kernel_ring(); diff -urN linux-2.4.18/arch/sparc/kernel/setup.c linux-2.4.19-pre5/arch/sparc/kernel/setup.c --- linux-2.4.18/arch/sparc/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/setup.c Sat Mar 30 22:55:39 2002 @@ -47,8 +47,6 @@ #include #include -#undef PROM_DEBUG_CONSOLE - struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ 0, /* unused */ @@ -134,6 +132,19 @@ } } +static void +prom_console_write(struct console *con, const char *s, unsigned n) +{ + prom_printf("%s", s); +} + +static struct console prom_debug_console = { + name: "debug", + write: prom_console_write, + flags: CON_PRINTBUFFER, + index: -1, +}; + int obp_system_intr(void) { if (boot_flags & BOOTME_KGDB) { @@ -166,6 +177,10 @@ prom_printf("boot_flags_init: Halt!\n"); prom_halt(); break; + case 'p': + /* Use PROM debug console. */ + register_console(&prom_debug_console); + break; default: printk("Unknown boot switch (-%c)\n", c); break; @@ -280,21 +295,6 @@ struct pt_regs fake_swapper_regs; -#ifdef PROM_DEBUG_CONSOLE -static void -prom_console_write(struct console *con, const char *s, unsigned n) -{ - prom_printf("%s", s); -} - -static struct console prom_console = { - name: "debug", - write: prom_console_write, - flags: CON_PRINTBUFFER, - index: -1, -}; -#endif - extern void paging_init(void); void __init setup_arch(char **cmdline_p) @@ -348,9 +348,6 @@ printk("UNKNOWN!\n"); break; }; -#ifdef PROM_DEBUG_CONSOLE - register_console(&prom_console); -#endif #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -381,7 +378,7 @@ if (!root_flags) root_mountflags &= ~MS_RDONLY; ROOT_DEV = to_kdev_t(root_dev); -#ifdef CONFIG_BLK_DEV_RAM +#ifdef CONFIG_BLK_DEV_INITRD rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); diff -urN linux-2.4.18/arch/sparc/kernel/sun4d_smp.c linux-2.4.19-pre5/arch/sparc/kernel/sun4d_smp.c --- linux-2.4.18/arch/sparc/kernel/sun4d_smp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/sun4d_smp.c Sat Mar 30 22:55:39 2002 @@ -47,7 +47,7 @@ extern volatile int smp_processors_ready; extern unsigned long cpu_present_map; extern int smp_num_cpus; -static int smp_highest_cpu = 0; +static int smp_highest_cpu; extern int smp_threads_ready; extern unsigned char mid_xlate[NR_CPUS]; extern volatile unsigned long cpu_callin_map[NR_CPUS]; diff -urN linux-2.4.18/arch/sparc/kernel/systbls.S linux-2.4.19-pre5/arch/sparc/kernel/systbls.S --- linux-2.4.18/arch/sparc/kernel/systbls.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/systbls.S Sat Mar 30 22:55:33 2002 @@ -70,7 +70,7 @@ /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -/*255*/ .long sys_nis_syscall, sys_nis_syscall +/*255*/ .long sys_nis_syscall, sys_nis_syscall, sys_tkill #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ diff -urN linux-2.4.18/arch/sparc/kernel/time.c linux-2.4.19-pre5/arch/sparc/kernel/time.c --- linux-2.4.18/arch/sparc/kernel/time.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc/kernel/time.c Sat Mar 30 22:55:39 2002 @@ -115,7 +115,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { /* last time the cmos clock got updated */ - static long last_rtc_update=0; + static long last_rtc_update; #ifndef CONFIG_SMP if(!user_mode(regs)) diff -urN linux-2.4.18/arch/sparc/kernel/traps.c linux-2.4.19-pre5/arch/sparc/kernel/traps.c --- linux-2.4.18/arch/sparc/kernel/traps.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/kernel/traps.c Sat Mar 30 22:55:39 2002 @@ -272,7 +272,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - static int calls = 0; + static int calls; siginfo_t info; unsigned long fsr; int ret = 0; diff -urN linux-2.4.18/arch/sparc/mm/iommu.c linux-2.4.19-pre5/arch/sparc/mm/iommu.c --- linux-2.4.18/arch/sparc/mm/iommu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/mm/iommu.c Sat Mar 30 22:55:39 2002 @@ -25,7 +25,7 @@ BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long) #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page) extern int flush_page_for_dma_global; -static int viking_flush = 0; +static int viking_flush; /* viking.S */ extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); diff -urN linux-2.4.18/arch/sparc/mm/srmmu.c linux-2.4.19-pre5/arch/sparc/mm/srmmu.c --- linux-2.4.18/arch/sparc/mm/srmmu.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/mm/srmmu.c Sat Mar 30 22:55:39 2002 @@ -1733,7 +1733,7 @@ static void __init poke_viking(void) { unsigned long mreg = srmmu_get_mmureg(); - static int smp_catch = 0; + static int smp_catch; if(viking_mxcc_present) { unsigned long mxcc_control = mxcc_get_creg(); diff -urN linux-2.4.18/arch/sparc/mm/swift.S linux-2.4.19-pre5/arch/sparc/mm/swift.S --- linux-2.4.18/arch/sparc/mm/swift.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/mm/swift.S Sat Mar 30 22:55:39 2002 @@ -53,11 +53,9 @@ .globl swift_flush_cache_mm swift_flush_cache_mm: -#ifndef CONFIG_SMP ld [%o0 + AOFF_mm_context], %g2 cmp %g2, -1 be swift_flush_cache_mm_out -#endif WINDOW_FLUSH(%g4, %g5) rd %psr, %g1 andn %g1, PSR_ET, %g3 @@ -120,11 +118,9 @@ swift_flush_cache_page: ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */ 70: -#ifndef CONFIG_SMP ld [%o0 + AOFF_mm_context], %g2 cmp %g2, -1 be swift_flush_cache_page_out -#endif WINDOW_FLUSH(%g4, %g5) rd %psr, %g1 andn %g1, PSR_ET, %g3 @@ -224,11 +220,9 @@ .globl swift_flush_tlb_all swift_flush_tlb_mm: swift_flush_tlb_range: -#ifndef CONFIG_SMP ld [%o0 + AOFF_mm_context], %g2 cmp %g2, -1 be swift_flush_tlb_all_out -#endif swift_flush_tlb_all: mov 0x400, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE @@ -242,11 +236,9 @@ mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o3 andn %o1, (PAGE_SIZE - 1), %o1 -#ifndef CONFIG_SMP cmp %o3, -1 be swift_flush_tlb_page_out nop -#endif #if 1 mov 0x400, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE diff -urN linux-2.4.18/arch/sparc/mm/tsunami.S linux-2.4.19-pre5/arch/sparc/mm/tsunami.S --- linux-2.4.18/arch/sparc/mm/tsunami.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc/mm/tsunami.S Sat Mar 30 22:55:39 2002 @@ -27,10 +27,8 @@ tsunami_flush_cache_mm: tsunami_flush_cache_range: ld [%o0 + AOFF_mm_context], %g2 -#ifndef CONFIG_SMP cmp %g2, -1 be tsunami_flush_cache_out -#endif tsunami_flush_cache_all: WINDOW_FLUSH(%g4, %g5) tsunami_flush_page_for_dma: @@ -49,11 +47,9 @@ /* More slick stuff... */ tsunami_flush_tlb_mm: tsunami_flush_tlb_range: -#ifndef CONFIG_SMP ld [%o0 + AOFF_mm_context], %g2 cmp %g2, -1 be tsunami_flush_tlb_out -#endif tsunami_flush_tlb_all: mov 0x400, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE @@ -72,10 +68,8 @@ mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o3 andn %o1, (PAGE_SIZE - 1), %o1 -#ifndef CONFIG_SMP cmp %o3, -1 be tsunami_flush_tlb_page_out -#endif lda [%g1] ASI_M_MMUREGS, %g5 sta %o3, [%g1] ASI_M_MMUREGS sta %g0, [%o1] ASI_M_FLUSH_PROBE diff -urN linux-2.4.18/arch/sparc64/Makefile linux-2.4.19-pre5/arch/sparc64/Makefile --- linux-2.4.18/arch/sparc64/Makefile Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/sparc64/Makefile Sat Mar 30 22:55:33 2002 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $ +# $Id: Makefile,v 1.51.2.1 2002/03/14 01:26:21 kanoj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -46,6 +46,11 @@ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \ $(CC_UNDECL) AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL) +endif + +ifeq ($(CONFIG_MCOUNT),y) + CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) + CFLAGS := $(CFLAGS) -pg endif LINKFLAGS = -T arch/sparc64/vmlinux.lds diff -urN linux-2.4.18/arch/sparc64/config.in linux-2.4.19-pre5/arch/sparc64/config.in --- linux-2.4.18/arch/sparc64/config.in Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/sparc64/config.in Sat Mar 30 22:55:33 2002 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $ +# $Id: config.in,v 1.156.2.2 2002/03/14 01:26:21 kanoj Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -303,6 +303,10 @@ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE bool ' D-cache flush debugging' CONFIG_DEBUG_DCFLUSH +fi +bool 'Stack Overflow Detection Support' CONFIG_STACK_DEBUG +if [ "$CONFIG_STACK_DEBUG" = "y" ] ; then + define_bool CONFIG_MCOUNT y fi endmenu diff -urN linux-2.4.18/arch/sparc64/defconfig linux-2.4.19-pre5/arch/sparc64/defconfig --- linux-2.4.18/arch/sparc64/defconfig Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/defconfig Sat Mar 30 22:55:39 2002 @@ -96,6 +96,7 @@ CONFIG_FB_PM2=y # CONFIG_FB_PM2_FIFO_DISCONNECT is not set CONFIG_FB_PM2_PCI=y +# CONFIG_FB_PM3 is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y @@ -106,6 +107,7 @@ # CONFIG_FB_SIS is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -238,6 +240,11 @@ CONFIG_NET_CLS_POLICE=y # +# Network testing +# +CONFIG_NET_PKTGEN=m + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -254,6 +261,7 @@ # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set # CONFIG_BLK_DEV_IDEDISK_IBM is not set @@ -268,6 +276,7 @@ CONFIG_BLK_DEV_IDETAPE=m CONFIG_BLK_DEV_IDEFLOPPY=m # CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set # # IDE chipset support/bugfixes @@ -279,12 +288,15 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_AEC62XX_TUNING is not set CONFIG_BLK_DEV_ALI15X3=y @@ -292,6 +304,7 @@ # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_CMD680 is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set @@ -299,6 +312,7 @@ # CONFIG_BLK_DEV_HPT366 is not set CONFIG_BLK_DEV_NS87415=y # CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC_ADMA is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set # CONFIG_PDC202XX_FORCE is not set @@ -308,6 +322,7 @@ # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_ELEVATOR_NOOP is not set CONFIG_IDEDMA_AUTO=y # CONFIG_IDEDMA_IVB is not set # CONFIG_DMA_NONPCI is not set @@ -348,6 +363,7 @@ CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=5000 +# CONFIG_AIC7XXX_PROBE_EISA_VL is not set # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y @@ -445,7 +461,6 @@ CONFIG_HAPPYMEAL=y CONFIG_SUNBMAC=m CONFIG_SUNQE=m -CONFIG_SUNLANCE=y CONFIG_SUNGEM=y CONFIG_NET_VENDOR_3COM=y # CONFIG_EL1 is not set @@ -466,6 +481,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=m +# CONFIG_TC35815 is not set # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set CONFIG_DE4X5=m @@ -475,6 +491,7 @@ # CONFIG_LNE390 is not set CONFIG_FEALNX=m CONFIG_NATSEMI=m +# CONFIG_NATSEMI_CABLE_MAGIC is not set CONFIG_NE2K_PCI=m # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set @@ -504,7 +521,7 @@ CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_SK98LIN=m -# CONFIG_TIGON3 is not set +CONFIG_TIGON3=m CONFIG_FDDI=y # CONFIG_DEFXX is not set CONFIG_SKFP=m @@ -741,8 +758,9 @@ # CONFIG_USB_LONG_TIMEOUT is not set # -# USB Controllers +# USB Host Controller Drivers # +# CONFIG_USB_EHCI_HCD is not set CONFIG_USB_UHCI=y # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y @@ -751,6 +769,7 @@ # USB Device Class drivers # # CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set CONFIG_USB_BLUETOOTH=m CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set @@ -841,6 +860,7 @@ # USB Miscellaneous drivers # CONFIG_USB_RIO500=m +# CONFIG_USB_AUERSWALD is not set # # Bluetooth support @@ -869,3 +889,4 @@ # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_DCFLUSH is not set +# CONFIG_STACK_DEBUG is not set diff -urN linux-2.4.18/arch/sparc64/kernel/binfmt_elf32.c linux-2.4.19-pre5/arch/sparc64/kernel/binfmt_elf32.c --- linux-2.4.18/arch/sparc64/kernel/binfmt_elf32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/binfmt_elf32.c Sat Mar 30 22:55:33 2002 @@ -43,7 +43,7 @@ dest[34] = (unsigned int) src->tnpc; \ dest[35] = src->y; \ dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); +} while (0); typedef struct { union { diff -urN linux-2.4.18/arch/sparc64/kernel/central.c linux-2.4.19-pre5/arch/sparc64/kernel/central.c --- linux-2.4.18/arch/sparc64/kernel/central.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/central.c Sat Mar 30 22:55:33 2002 @@ -1,4 +1,4 @@ -/* $Id: central.c,v 1.14.2.1 2001/12/19 00:16:21 davem Exp $ +/* $Id: central.c,v 1.14.2.2 2002/03/01 01:26:50 davem Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com) @@ -247,6 +247,55 @@ (central->clkver ? upa_readb(central->clkver) : 0x00)); } +static void init_all_fhc_hw(void) +{ + struct linux_fhc *fhc; + + for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) { + u32 tmp; + + /* Clear all of the interrupt mapping registers + * just in case OBP left them in a foul state. + */ +#define ZAP(ICLR, IMAP) \ +do { u32 imap_tmp; \ + upa_writel(0, (ICLR)); \ + upa_readl(ICLR); \ + imap_tmp = upa_readl(IMAP); \ + imap_tmp &= ~(0x80000000); \ + upa_writel(imap_tmp, (IMAP)); \ + upa_readl(IMAP); \ +} while (0) + + ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, + fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); + ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, + fhc->fhc_regs.sregs + FHC_SREGS_IMAP); + ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, + fhc->fhc_regs.uregs + FHC_UREGS_IMAP); + ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, + fhc->fhc_regs.tregs + FHC_TREGS_IMAP); + +#undef ZAP + + /* Setup FHC control register. */ + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + + /* All non-central boards have this bit set. */ + if(! IS_CENTRAL_FHC(fhc)) + tmp |= FHC_CONTROL_IXIST; + + /* For all FHCs, clear the firmware synchronization + * line and both low power mode enables. + */ + tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); + + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + } + +} + void central_probe(void) { struct linux_prom_registers fpregs[6]; @@ -341,6 +390,8 @@ ((err & FHC_ID_MANUF) >> 1)); probe_other_fhcs(); + + init_all_fhc_hw(); } static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on) @@ -398,55 +449,11 @@ void firetruck_init(void) { struct linux_central *central = central_bus; - struct linux_fhc *fhc; u8 ctrl; /* No central bus, nothing to do. */ if (central == NULL) return; - - for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) { - u32 tmp; - - /* Clear all of the interrupt mapping registers - * just in case OBP left them in a foul state. - */ -#define ZAP(ICLR, IMAP) \ -do { u32 imap_tmp; \ - upa_writel(0, (ICLR)); \ - upa_readl(ICLR); \ - imap_tmp = upa_readl(IMAP); \ - imap_tmp &= ~(0x80000000); \ - upa_writel(imap_tmp, (IMAP)); \ - upa_readl(IMAP); \ -} while (0) - - ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, - fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); - ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, - fhc->fhc_regs.sregs + FHC_SREGS_IMAP); - ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, - fhc->fhc_regs.uregs + FHC_UREGS_IMAP); - ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, - fhc->fhc_regs.tregs + FHC_TREGS_IMAP); - -#undef ZAP - - /* Setup FHC control register. */ - tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); - - /* All non-central boards have this bit set. */ - if(! IS_CENTRAL_FHC(fhc)) - tmp |= FHC_CONTROL_IXIST; - - /* For all FHCs, clear the firmware synchronization - * line and both low power mode enables. - */ - tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - - upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); - upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); - } /* OBP leaves it on, turn it off so clock board timer LED * is in sync with FHC ones. diff -urN linux-2.4.18/arch/sparc64/kernel/ebus.c linux-2.4.19-pre5/arch/sparc64/kernel/ebus.c --- linux-2.4.18/arch/sparc64/kernel/ebus.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/ebus.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.64 2001/11/08 04:41:33 davem Exp $ +/* $Id: ebus.c,v 1.64.2.1 2002/03/12 18:46:14 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -208,7 +208,8 @@ dev->num_addrs = len / sizeof(struct linux_prom_registers); for (i = 0; i < dev->num_addrs; i++) { - if (dev->bus->is_rio == 0) + /* XXX Learn how to interpret ebus ranges... -DaveM */ + if (regs[i].which_io >= 0x10) n = (regs[i].which_io - 0x10) >> 2; else n = regs[i].which_io; @@ -274,6 +275,25 @@ printk("]"); } +static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p) +{ + struct pci_dev *pdev = start; + + do { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev); + if (pdev && + (pdev->device == PCI_DEVICE_ID_SUN_EBUS || + pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)) + break; + } while (pdev != NULL); + + if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)) + *is_rio_p = 1; + else + *is_rio_p = 0; + + return pdev; +} void __init ebus_init(void) { @@ -288,12 +308,7 @@ if (!pci_present()) return; - is_rio = 0; - pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); - if (!pdev) { - pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0); - is_rio = 1; - } + pdev = find_next_ebus(NULL, &is_rio); if (!pdev) { printk("ebus: No EBus's found.\n"); return; @@ -314,16 +329,7 @@ we'd have to tweak with the ebus_chain in the runtime after initialization. -jj */ if (!prom_getchild (ebusnd)) { - struct pci_dev *orig_pdev = pdev; - - is_rio = 0; - pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_EBUS, orig_pdev); - if (!pdev) { - pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev); - is_rio = 1; - } + pdev = find_next_ebus(pdev, &is_rio); if (!pdev) { if (ebus == ebus_chain) { ebus_chain = NULL; @@ -373,20 +379,9 @@ next_ebus: printk("\n"); - { - struct pci_dev *orig_pdev = pdev; - - is_rio = 0; - pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_EBUS, orig_pdev); - if (!pdev) { - pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev); - is_rio = 1; - } - if (!pdev) - break; - } + pdev = find_next_ebus(pdev, &is_rio); + if (!pdev) + break; cookie = pdev->sysdata; ebusnd = cookie->prom_node; diff -urN linux-2.4.18/arch/sparc64/kernel/head.S linux-2.4.19-pre5/arch/sparc64/kernel/head.S --- linux-2.4.18/arch/sparc64/kernel/head.S Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/head.S Sat Mar 30 22:55:39 2002 @@ -567,13 +567,6 @@ #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 -#if 1 -#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE -#else -#define VPTE_BASE_CHEETAH 0xffe0000000000000 -#endif - mov TSB_REG, %g1 stxa %g0, [%g1] ASI_DMMU membar #Sync @@ -604,8 +597,6 @@ clr %g7 #undef KERN_HIGHBITS #undef KERN_LOWBITS -#undef VPTE_BASE_SPITFIRE -#undef VPTE_BASE_CHEETAH /* Setup Interrupt globals */ wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate diff -urN linux-2.4.18/arch/sparc64/kernel/ioctl32.c linux-2.4.19-pre5/arch/sparc64/kernel/ioctl32.c --- linux-2.4.18/arch/sparc64/kernel/ioctl32.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/ioctl32.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.133.2.2 2002/01/14 09:49:29 davem Exp $ +/* $Id: ioctl32.c,v 1.133.2.5 2002/03/01 08:52:38 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,7 @@ #include #include #include +#include /* Use this to get at 32-bit user passed pointers. See sys_sparc32.c for description about these. */ @@ -1059,7 +1061,7 @@ break; default: do { - static int count = 0; + static int count; if (++count <= 20) printk("%s: Unknown fb ioctl cmd fd(%d) " "cmd(%08x) arg(%08lx)\n", @@ -1712,7 +1714,7 @@ break; default: do { - static int count = 0; + static int count; if (++count <= 20) printk("ppp_ioctl: Unknown cmd fd(%d) " "cmd(%08x) arg(%08x)\n", @@ -1822,7 +1824,7 @@ break; default: do { - static int count = 0; + static int count; if (++count <= 20) printk("mt_ioctl: Unknown cmd fd(%d) " "cmd(%08x) arg(%08x)\n", @@ -1940,7 +1942,7 @@ break; default: do { - static int count = 0; + static int count; if (++count <= 20) printk("cdrom_ioctl: Unknown cmd fd(%d) " "cmd(%08x) arg(%08x)\n", @@ -2027,7 +2029,7 @@ } break; default: { - static int count = 0; + static int count; if (++count <= 20) printk("%s: Unknown loop ioctl cmd, fd(%d) " "cmd(%08x) arg(%08lx)\n", @@ -4078,6 +4080,12 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE) COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER) COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) +/* Big T */ +COMPATIBLE_IOCTL(TUNSETNOCSUM); +COMPATIBLE_IOCTL(TUNSETDEBUG); +COMPATIBLE_IOCTL(TUNSETIFF); +COMPATIBLE_IOCTL(TUNSETPERSIST); +COMPATIBLE_IOCTL(TUNSETOWNER); /* Big V */ COMPATIBLE_IOCTL(VT_SETMODE) COMPATIBLE_IOCTL(VT_GETMODE) @@ -4191,6 +4199,8 @@ COMPATIBLE_IOCTL(SIOCGMIIPHY) COMPATIBLE_IOCTL(SIOCGMIIREG) COMPATIBLE_IOCTL(SIOCSMIIREG) +COMPATIBLE_IOCTL(SIOCGIFVLAN) +COMPATIBLE_IOCTL(SIOCSIFVLAN) /* SG stuff */ COMPATIBLE_IOCTL(SG_SET_TIMEOUT) COMPATIBLE_IOCTL(SG_GET_TIMEOUT) @@ -4529,6 +4539,13 @@ COMPATIBLE_IOCTL(WIOCSTART) COMPATIBLE_IOCTL(WIOCSTOP) COMPATIBLE_IOCTL(WIOCGSTAT) +/* Big R */ +COMPATIBLE_IOCTL(RNDGETENTCNT) +COMPATIBLE_IOCTL(RNDADDTOENTCNT) +COMPATIBLE_IOCTL(RNDGETPOOL) +COMPATIBLE_IOCTL(RNDADDENTROPY) +COMPATIBLE_IOCTL(RNDZAPENTCNT) +COMPATIBLE_IOCTL(RNDCLEARPOOL) /* Bluetooth ioctls */ COMPATIBLE_IOCTL(HCIDEVUP) COMPATIBLE_IOCTL(HCIDEVDOWN) @@ -4870,7 +4887,7 @@ handler = (void *)(long)t->handler; error = handler(fd, cmd, arg, filp); } else { - static int count = 0; + static int count; if (++count <= 20) printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) " "cmd(%08x) arg(%08x)\n", diff -urN linux-2.4.18/arch/sparc64/kernel/irq.c linux-2.4.19-pre5/arch/sparc64/kernel/irq.c --- linux-2.4.18/arch/sparc64/kernel/irq.c Sun Dec 23 16:23:36 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/irq.c Sat Mar 30 22:55:39 2002 @@ -81,7 +81,7 @@ */ #define MAX_STATIC_ALLOC 4 static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; -static int static_irq_count = 0; +static int static_irq_count; /* This is exported so that fast IRQ handlers can get at it... -DaveM */ struct irqaction *irq_action[NR_IRQS+1] = { diff -urN linux-2.4.18/arch/sparc64/kernel/pci.c linux-2.4.19-pre5/arch/sparc64/kernel/pci.c --- linux-2.4.18/arch/sparc64/kernel/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/pci.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.36 2001/10/06 00:38:25 davem Exp $ +/* $Id: pci.c,v 1.36.2.4 2002/02/10 15:06:48 ecd Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -234,33 +234,63 @@ return request_resource(root, res); } +/* + * Given the PCI bus a device resides on, try to + * find an acceptable resource allocation for a + * specific device resource.. + */ +static int pci_assign_bus_resource(const struct pci_bus *bus, + struct pci_dev *dev, + struct resource *res, + unsigned long size, + unsigned long min, + int resno) +{ + unsigned int type_mask; + int i; + + type_mask = IORESOURCE_IO | IORESOURCE_MEM; + for (i = 0 ; i < 4; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + + /* type_mask must match */ + if ((res->flags ^ r->flags) & type_mask) + continue; + + /* Ok, try it out.. */ + if (allocate_resource(r, res, size, min, -1, size, NULL, NULL) < 0) + continue; + + /* PCI config space updated by caller. */ + return 0; + } + return -EBUSY; +} + int pci_assign_resource(struct pci_dev *pdev, int resource) { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct resource *res = &pdev->resource[resource]; - struct resource *root; - unsigned long min, max, size, align; + unsigned long min, size; int err; - if (res->flags & IORESOURCE_IO) { - root = &pbm->io_space; - min = root->start + 0x400UL; - max = root->end; - } else { - root = &pbm->mem_space; - min = root->start; - max = min + 0x80000000UL; - } + if (res->flags & IORESOURCE_IO) + min = pbm->io_space.start + 0x400UL; + else + min = pbm->mem_space.start; + + size = res->end - res->start + 1; - size = res->end - res->start; - align = size + 1; + err = pci_assign_bus_resource(pdev->bus, pdev, res, size, min, resource); - err = allocate_resource(root, res, size + 1, min, max, align, NULL, NULL); if (err < 0) { printk("PCI: Failed to allocate resource %d for %s\n", resource, pdev->name); } else { + /* Update PCI config space. */ pbm->parent->base_address_update(pdev, resource); } @@ -418,7 +448,7 @@ enum pci_mmap_state mmap_state) { unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long user32 = user_offset & 0xffffffffUL; + unsigned long user32 = user_offset & pci_memspace_mask; unsigned long largest_base, this_base, addr32; int i; @@ -448,7 +478,7 @@ this_base = rp->start; - addr32 = (this_base & PAGE_MASK) & 0xffffffffUL; + addr32 = (this_base & PAGE_MASK) & pci_memspace_mask; if (mmap_state == pci_mmap_io) addr32 &= 0xffffff; @@ -464,7 +494,7 @@ if (mmap_state == pci_mmap_io) vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT); else - vma->vm_pgoff = (((largest_base & ~0xffffffffUL) | user32) >> PAGE_SHIFT); + vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT); return 0; } diff -urN linux-2.4.18/arch/sparc64/kernel/pci_common.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_common.c --- linux-2.4.18/arch/sparc64/kernel/pci_common.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_common.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.27.2.2 2002/02/01 00:56:44 davem Exp $ +/* $Id: pci_common.c,v 1.27.2.5 2002/03/10 05:21:26 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -571,33 +571,55 @@ struct pci_pbm_info *pbm = dev_pcp->pbm; struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs; unsigned int hi, mid, lo, irq; - int i, num_intmap; - - if (pbm->num_pbm_intmap == 0) - return 0; + int i, num_intmap, map_slot; intmap = &pbm->pbm_intmap[0]; intmask = &pbm->pbm_intmask; num_intmap = pbm->num_pbm_intmap; + map_slot = 0; /* If we are underneath a PCI bridge, use PROM register * property of the parent bridge which is closest to * the PBM. + * + * However if that parent bridge has interrupt map/mask + * properties of it's own we use the PROM register property + * of the next child device on the path to PDEV. + * + * In detail the two cases are (note that the 'X' below is the + * 'next child on the path to PDEV' mentioned above): + * + * 1) PBM --> PCI bus lacking int{map,mask} --> X ... PDEV + * + * Here we use regs of 'PCI bus' device. + * + * 2) PBM --> PCI bus with int{map,mask} --> X ... PDEV + * + * Here we use regs of 'X'. Note that X can be PDEV. */ if (pdev->bus->number != pbm->pci_first_busno) { - struct pcidev_cookie *bus_pcp; - struct pci_dev *pwalk; - int offset, plen; - - pwalk = pdev->bus->self; - while (pwalk->bus && - pwalk->bus->number != pbm->pci_first_busno) - pwalk = pwalk->bus->self; + struct pcidev_cookie *bus_pcp, *regs_pcp; + struct pci_dev *bus_dev, *regs_dev; + int plen; - bus_pcp = pwalk->sysdata; + bus_dev = pdev->bus->self; + regs_dev = pdev; + + while (bus_dev->bus && + bus_dev->bus->number != pbm->pci_first_busno) { + regs_dev = bus_dev; + bus_dev = bus_dev->bus->self; + } + + regs_pcp = regs_dev->sysdata; + pregs = regs_pcp->prom_regs; + + bus_pcp = bus_dev->sysdata; /* But if the PCI bridge has it's own interrupt map - * and mask properties, use that and the device regs. + * and mask properties, use that and the regs of the + * PCI entity at the next level down on the path to the + * device. */ plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map", (char *) &bridge_local_intmap[0], @@ -605,38 +627,31 @@ if (plen != -1) { intmap = &bridge_local_intmap[0]; num_intmap = plen / sizeof(struct linux_prom_pci_intmap); - plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map-mask", + plen = prom_getproperty(bus_pcp->prom_node, + "interrupt-map-mask", (char *) &bridge_local_intmask, sizeof(bridge_local_intmask)); if (plen == -1) { - prom_printf("pbm_intmap_match: Bridge has intmap but " - "no intmask.\n"); - prom_halt(); + printk("pci_intmap_match: Warning! Bridge has intmap " + "but no intmask.\n"); + printk("pci_intmap_match: Trying to recover.\n"); + return 0; } - goto check_intmap; - } - - pregs = bus_pcp->prom_regs; - - offset = prom_getint(dev_pcp->prom_node, - "fcode-rom-offset"); - /* Did PROM know better and assign an interrupt other - * than #INTA to the device? - We test here for presence of - * FCODE on the card, in this case we assume PROM has set - * correct 'interrupts' property, unless it is quadhme. - */ - if (offset == -1 || - !strcmp(dev_pcp->prom_name, "SUNW,qfe") || - !strcmp(dev_pcp->prom_name, "qfe")) { - /* - * No, use low slot number bits of child as IRQ line. - */ - *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; + if (pdev->bus->self != bus_dev) + map_slot = 1; + } else { + pregs = bus_pcp->prom_regs; + map_slot = 1; } } -check_intmap: + if (map_slot) { + *interrupt = ((*interrupt + - 1 + + PCI_SLOT(pdev->devfn)) & 0x3) + 1; + } + hi = pregs->phys_hi & intmask->phys_hi; mid = pregs->phys_mid & intmask->phys_mid; lo = pregs->phys_lo & intmask->phys_lo; @@ -648,16 +663,35 @@ intmap[i].phys_lo == lo && intmap[i].interrupt == irq) { *interrupt = intmap[i].cinterrupt; + printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + map_slot, *interrupt); return 1; } } - prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ", - pdev->bus->number, pdev->devfn); - prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", - pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); - prom_printf("Please email this information to davem@redhat.com\n"); - prom_halt(); + /* We will run this code even if pbm->num_pbm_intmap is zero, just so + * we can apply the slot mapping to the PROM interrupt property value. + * So do not spit out these warnings in that case. + */ + if (num_intmap != 0) { + /* Print it both to OBP console and kernel one so that if bootup + * hangs here the user has the information to report. + */ + prom_printf("pci_intmap_match: bus %02x, devfn %02x: ", + pdev->bus->number, pdev->devfn); + prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", + pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); + prom_printf("Please email this information to davem@redhat.com\n"); + + printk("pci_intmap_match: bus %02x, devfn %02x: ", + pdev->bus->number, pdev->devfn); + printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", + pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); + printk("Please email this information to davem@redhat.com\n"); + } + + return 0; } static void __init pdev_fixup_irq(struct pci_dev *pdev) @@ -738,12 +772,19 @@ * ranges. -DaveM */ if (pdev->bus->number == pbm->pci_first_busno) { - slot = (pdev->devfn >> 3) - pbm->pci_first_slot; + slot = PCI_SLOT(pdev->devfn) - pbm->pci_first_slot; } else { + struct pci_dev *bus_dev; + /* Underneath a bridge, use slot number of parent - * bridge. + * bridge which is closest to the PBM. */ - slot = (pdev->bus->self->devfn >> 3) - pbm->pci_first_slot; + bus_dev = pdev->bus->self; + while (bus_dev->bus && + bus_dev->bus->number != pbm->pci_first_busno) + bus_dev = bus_dev->bus->self; + + slot = PCI_SLOT(bus_dev->devfn) - pbm->pci_first_slot; } slot = slot << 2; diff -urN linux-2.4.18/arch/sparc64/kernel/pci_psycho.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_psycho.c --- linux-2.4.18/arch/sparc64/kernel/pci_psycho.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_psycho.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.30.2.2 2002/02/01 00:57:47 davem Exp $ +/* $Id: pci_psycho.c,v 1.30.2.3 2002/03/03 10:31:56 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -326,15 +326,15 @@ /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/3, /* SCSI */ +/*0x20*/4, /* SCSI */ /*0x21*/5, /* Ethernet */ /*0x22*/8, /* Parallel Port */ /*0x23*/13, /* Audio Record */ /*0x24*/14, /* Audio Playback */ /*0x25*/15, /* PowerFail */ -/*0x26*/3, /* second SCSI */ +/*0x26*/4, /* second SCSI */ /*0x27*/11, /* Floppy */ -/*0x28*/2, /* Spare Hardware */ +/*0x28*/4, /* Spare Hardware */ /*0x29*/9, /* Keyboard */ /*0x2a*/4, /* Mouse */ /*0x2b*/12, /* Serial */ @@ -344,7 +344,7 @@ /*0x2f*/15, /* Correctable ECC */ /*0x30*/15, /* PCI Bus A Error */ /*0x31*/15, /* PCI Bus B Error */ -/*0x32*/1, /* Power Management */ +/*0x32*/15, /* Power Management */ }; static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) @@ -353,7 +353,7 @@ ret = psycho_pil_table[ino]; if (ret == 0 && pdev == NULL) { - ret = 1; + ret = 4; } else if (ret == 0) { switch ((pdev->class >> 16) & 0xff) { case PCI_BASE_CLASS_STORAGE: @@ -376,7 +376,7 @@ break; default: - ret = 1; + ret = 4; break; }; } @@ -409,6 +409,10 @@ /* Now build the IRQ bucket. */ pil = psycho_ino_to_pil(pdev, ino); + + if (PIL_RESERVED(pil)) + BUG(); + imap = p->controller_regs + imap_off; imap += 4; @@ -1097,7 +1101,14 @@ int where, size, is_64bit; res = &pdev->resource[resource]; - where = PCI_BASE_ADDRESS_0 + (resource * 4); + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } is_64bit = 0; if (res->flags & IORESOURCE_IO) @@ -1113,6 +1124,10 @@ pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - root->start)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= PCI_ROM_ADDRESS_ENABLE; + } pci_write_config_dword(pdev, where, reg); /* This knows that the upper 32-bits of the address diff -urN linux-2.4.18/arch/sparc64/kernel/pci_sabre.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_sabre.c --- linux-2.4.18/arch/sparc64/kernel/pci_sabre.c Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_sabre.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $ +/* $Id: pci_sabre.c,v 1.41.2.1 2002/03/03 10:31:56 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -564,15 +564,15 @@ /*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ /*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ /*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/3, /* SCSI */ +/*0x20*/4, /* SCSI */ /*0x21*/5, /* Ethernet */ /*0x22*/8, /* Parallel Port */ /*0x23*/13, /* Audio Record */ /*0x24*/14, /* Audio Playback */ /*0x25*/15, /* PowerFail */ -/*0x26*/3, /* second SCSI */ +/*0x26*/4, /* second SCSI */ /*0x27*/11, /* Floppy */ -/*0x28*/2, /* Spare Hardware */ +/*0x28*/4, /* Spare Hardware */ /*0x29*/9, /* Keyboard */ /*0x2a*/4, /* Mouse */ /*0x2b*/12, /* Serial */ @@ -582,7 +582,7 @@ /*0x2f*/15, /* Correctable ECC */ /*0x30*/15, /* PCI Bus A Error */ /*0x31*/15, /* PCI Bus B Error */ -/*0x32*/1, /* Power Management */ +/*0x32*/15, /* Power Management */ }; static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) @@ -596,7 +596,7 @@ ret = sabre_pil_table[ino]; if (ret == 0 && pdev == NULL) { - ret = 1; + ret = 4; } else if (ret == 0) { switch ((pdev->class >> 16) & 0xff) { case PCI_BASE_CLASS_STORAGE: @@ -619,7 +619,7 @@ break; default: - ret = 1; + ret = 4; break; }; } @@ -651,6 +651,10 @@ /* Now build the IRQ bucket. */ pil = sabre_ino_to_pil(pdev, ino); + + if (PIL_RESERVED(pil)) + BUG(); + imap = p->controller_regs + imap_off; imap += 4; @@ -1063,7 +1067,14 @@ int where, size, is_64bit; res = &pdev->resource[resource]; - where = PCI_BASE_ADDRESS_0 + (resource * 4); + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } is_64bit = 0; if (res->flags & IORESOURCE_IO) @@ -1079,6 +1090,10 @@ pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - base)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= PCI_ROM_ADDRESS_ENABLE; + } pci_write_config_dword(pdev, where, reg); /* This knows that the upper 32-bits of the address @@ -1144,7 +1159,7 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) { - static int once = 0; + static int once; struct pci_bus *sabre_bus; struct pci_pbm_info *pbm; struct pcidev_cookie *cookie; diff -urN linux-2.4.18/arch/sparc64/kernel/pci_schizo.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_schizo.c --- linux-2.4.18/arch/sparc64/kernel/pci_schizo.c Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_schizo.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $ +/* $Id: pci_schizo.c,v 1.23.2.2 2002/03/11 07:55:24 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -291,8 +291,8 @@ /*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ /*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ /*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ -/*0x18*/3, /* SCSI */ -/*0x19*/3, /* second SCSI */ +/*0x18*/4, /* SCSI */ +/*0x19*/4, /* second SCSI */ /*0x1a*/0, /* UNKNOWN */ /*0x1b*/0, /* UNKNOWN */ /*0x1c*/8, /* Parallel */ @@ -302,7 +302,7 @@ /*0x20*/13, /* Audio Record */ /*0x21*/14, /* Audio Playback */ /*0x22*/12, /* Serial */ -/*0x23*/2, /* EBUS I2C */ +/*0x23*/4, /* EBUS I2C */ /*0x24*/10, /* RTC Clock */ /*0x25*/11, /* Floppy */ /*0x26*/0, /* UNKNOWN */ @@ -344,7 +344,7 @@ ret = schizo_pil_table[ino]; if (ret == 0 && pdev == NULL) { - ret = 1; + ret = 4; } else if (ret == 0) { switch ((pdev->class >> 16) & 0xff) { case PCI_BASE_CLASS_STORAGE: @@ -367,7 +367,7 @@ break; default: - ret = 1; + ret = 4; break; }; } @@ -383,7 +383,7 @@ struct ino_bucket *bucket; unsigned long imap, iclr, pbm_off; unsigned long imap_off, iclr_off; - int pil, inofixup = 0; + int pil; if (pbm == &p->pbm_A) pbm_off = SCHIZO_PBM_A_REGS_OFF; @@ -395,6 +395,10 @@ /* Now build the IRQ bucket. */ pil = schizo_ino_to_pil(pdev, ino); + + if (PIL_RESERVED(pil)) + BUG(); + imap = p->controller_regs + pbm_off + imap_off; imap += 4; @@ -402,10 +406,13 @@ iclr = p->controller_regs + pbm_off + iclr_off; iclr += 4; - if (ino < 0x18) - inofixup = ino & 0x03; - - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + /* On Schizo, no inofixup occurs. This is because each + * INO has it's own IMAP register. On Psycho and Sabre + * there is only one IMAP register for each PCI slot even + * though four different INOs can be generated by each + * PCI slot. + */ + bucket = __bucket(build_irq(pil, 0, iclr, imap)); bucket->flags |= IBF_PCI; return __irq(bucket); @@ -1078,15 +1085,22 @@ #define SCHIZO_PCIA_CTRL (SCHIZO_PBM_A_REGS_OFF + 0x2000UL) #define SCHIZO_PCIB_CTRL (SCHIZO_PBM_B_REGS_OFF + 0x2000UL) -#define SCHIZO_PCICTRL_BUNUS (1UL << 63UL) +#define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) #define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) +#define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) #define SCHIZO_PCICTRL_TTO_ERR (1UL << 38UL) #define SCHIZO_PCICTRL_RTRY_ERR (1UL << 37UL) #define SCHIZO_PCICTRL_DTO_ERR (1UL << 36UL) #define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL) #define SCHIZO_PCICTRL_SERR (1UL << 34UL) +#define SCHIZO_PCICTRL_PCISPD (1UL << 33UL) +#define SCHIZO_PCICTRL_PTO (3UL << 24UL) +#define SCHIZO_PCICTRL_DTO_INT (1UL << 19UL) #define SCHIZO_PCICTRL_SBH_INT (1UL << 18UL) #define SCHIZO_PCICTRL_EEN (1UL << 17UL) +#define SCHIZO_PCICTRL_PARK (1UL << 16UL) +#define SCHIZO_PCICTRL_PCIRST (1UL << 8UL) +#define SCHIZO_PCICTRL_ARB (0x3fUL << 0UL) static void __init schizo_register_error_handlers(struct pci_controller_info *p) { @@ -1163,7 +1177,7 @@ * bits for each PBM. */ tmp = schizo_read(base + SCHIZO_PCIA_CTRL); - tmp |= (SCHIZO_PCICTRL_BUNUS | + tmp |= (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_ESLCK | SCHIZO_PCICTRL_TTO_ERR | SCHIZO_PCICTRL_RTRY_ERR | @@ -1175,7 +1189,7 @@ schizo_write(base + SCHIZO_PCIA_CTRL, tmp); tmp = schizo_read(base + SCHIZO_PCIB_CTRL); - tmp |= (SCHIZO_PCICTRL_BUNUS | + tmp |= (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_ESLCK | SCHIZO_PCICTRL_TTO_ERR | SCHIZO_PCICTRL_RTRY_ERR | @@ -1412,7 +1426,14 @@ int where, size, is_64bit; res = &pdev->resource[resource]; - where = PCI_BASE_ADDRESS_0 + (resource * 4); + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } is_64bit = 0; if (res->flags & IORESOURCE_IO) @@ -1428,6 +1449,10 @@ pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - root->start)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= PCI_ROM_ADDRESS_ENABLE; + } pci_write_config_dword(pdev, where, reg); /* This knows that the upper 32-bits of the address @@ -1458,24 +1483,12 @@ #define SCHIZO_PCI_B_IO_MATCH 0x00070UL #define SCHIZO_PCI_B_IO_MASK 0x00078UL -/* VAL must be non-zero. */ -static unsigned long strip_to_lowest_bit_set(unsigned long val) -{ - unsigned long tmp; - - tmp = 1UL; - while (!(tmp & val)) - tmp <<= 1UL; - - return tmp; -} - static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm, int is_pbm_a, unsigned long reg_base) { u64 mem_match, mem_mask; u64 io_match; - u64 long a, b; + u64 a; if (is_pbm_a) { mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH; @@ -1487,11 +1500,12 @@ mem_mask = mem_match + 0x8UL; a = schizo_read(mem_match) & ~0x8000000000000000UL; - b = strip_to_lowest_bit_set(schizo_read(mem_mask)); - /* It should be 2GB in size. */ + /* It should be 2GB in size but the decode is set for the full + * 4GB so we have to add the 2G by hand. + */ pbm->mem_space.start = a; - pbm->mem_space.end = a + (b - 1UL); + pbm->mem_space.end = a + 0x80000000; pbm->mem_space.flags = IORESOURCE_MEM; /* This 32MB area is divided into two pieces. The first @@ -1738,6 +1752,22 @@ schizo_pbm_strbuf_init(p, pbm, is_pbm_a); } +#define SCHIZO_PCIA_IRQ_RETRY (SCHIZO_PBM_A_REGS_OFF + 0x1a00UL) +#define SCHIZO_PCIB_IRQ_RETRY (SCHIZO_PBM_B_REGS_OFF + 0x1a00UL) +#define SCHIZO_IRQ_RETRY_INF 0xffUL + +#define SCHIZO_PCIA_DIAG (SCHIZO_PBM_A_REGS_OFF + 0x2020UL) +#define SCHIZO_PCIB_DIAG (SCHIZO_PBM_B_REGS_OFF + 0x2020UL) +#define SCHIZO_PCIDIAG_D_BADECC (1UL << 10UL) /* Disable BAD ECC errors */ +#define SCHIZO_PCIDIAG_D_BYPASS (1UL << 9UL) /* Disable MMU bypass mode */ +#define SCHIZO_PCIDIAG_D_TTO (1UL << 8UL) /* Disable TTO errors */ +#define SCHIZO_PCIDIAG_D_RTRYARB (1UL << 7UL) /* Disable retry arbitration */ +#define SCHIZO_PCIDIAG_D_RETRY (1UL << 6UL) /* Disable retry limit */ +#define SCHIZO_PCIDIAG_D_INTSYNC (1UL << 5UL) /* Disable interrupt/DMA synch */ +#define SCHIZO_PCIDIAG_I_DMA_PARITY (1UL << 3UL) /* Invert DMA parity */ +#define SCHIZO_PCIDIAG_I_PIOD_PARITY (1UL << 2UL) /* Invert PIO data parity */ +#define SCHIZO_PCIDIAG_I_PIOA_PARITY (1UL << 1U)L /* Invert PIO address parity */ + static void schizo_controller_hwinit(struct pci_controller_info *p) { unsigned long pbm_a_base, pbm_b_base; @@ -1747,17 +1777,37 @@ pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF; /* Set IRQ retry to infinity. */ - schizo_write(pbm_a_base + 0x1a00UL, 0xff); - schizo_write(pbm_b_base + 0x1a00UL, 0xff); + schizo_write(p->controller_regs + SCHIZO_PCIA_IRQ_RETRY, + SCHIZO_IRQ_RETRY_INF); + schizo_write(p->controller_regs + SCHIZO_PCIB_IRQ_RETRY, + SCHIZO_IRQ_RETRY_INF); + + /* Enable arbiter for all PCI slots. Also, disable PCI interval + * timer so that DTO (Discard TimeOuts) are not reported because + * some Schizo revisions report them erroneously. + */ - /* Enable arbiter for all PCI slots. */ - tmp = schizo_read(pbm_a_base + 0x2000UL); - tmp |= 0x3fUL; - schizo_write(pbm_a_base + 0x2000UL, tmp); - - tmp = schizo_read(pbm_b_base + 0x2000UL); - tmp |= 0x3fUL; - schizo_write(pbm_b_base + 0x2000UL, tmp); + tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_CTRL); + tmp |= SCHIZO_PCICTRL_ARB; + tmp &= ~SCHIZO_PCICTRL_PTO; + schizo_write(p->controller_regs + SCHIZO_PCIA_CTRL, tmp); + + tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_CTRL); + tmp |= SCHIZO_PCICTRL_ARB; + tmp &= ~SCHIZO_PCICTRL_PTO; + schizo_write(p->controller_regs + SCHIZO_PCIB_CTRL, tmp); + + /* Disable TTO error reporting (won't happen anyway since we + * disabled the PCI interval timer above) and retry arbitration + * (can cause hangs in some Schizo revisions). + */ + tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_DIAG); + tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); + schizo_write(p->controller_regs + SCHIZO_PCIA_DIAG, tmp); + + tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_DIAG); + tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); + schizo_write(p->controller_regs + SCHIZO_PCIB_DIAG, tmp); } void __init schizo_init(int node, char *model_name) diff -urN linux-2.4.18/arch/sparc64/kernel/power.c linux-2.4.19-pre5/arch/sparc64/kernel/power.c --- linux-2.4.18/arch/sparc64/kernel/power.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/power.c Sat Mar 30 22:55:39 2002 @@ -22,7 +22,7 @@ #define POWER_COURTESY_OFF (1 << 1) static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); -static int button_pressed = 0; +static int button_pressed; static void power_handler(int irq, void *dev_id, struct pt_regs *regs) { @@ -81,7 +81,7 @@ { struct linux_ebus *ebus; struct linux_ebus_device *edev; - static int invoked = 0; + static int invoked; if (invoked) return; diff -urN linux-2.4.18/arch/sparc64/kernel/rtrap.S linux-2.4.19-pre5/arch/sparc64/kernel/rtrap.S --- linux-2.4.18/arch/sparc64/kernel/rtrap.S Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/rtrap.S Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.57.2.1 2001/12/24 04:32:33 davem Exp $ +/* $Id: rtrap.S,v 1.57.2.2 2002/03/03 10:31:56 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -13,7 +13,6 @@ #include #include -#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) #define RTRAP_PSTATE (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE) #define RTRAP_PSTATE_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV) #define RTRAP_PSTATE_AG_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) @@ -139,7 +138,7 @@ andn %l1, %l4, %l1 .align 64 - .globl rtrap_clr_l6, rtrap, irqsz_patchme + .globl rtrap_clr_l6, rtrap, irqsz_patchme, rtrap_xcall rtrap_clr_l6: clr %l6 rtrap: lduw [%g6 + AOFF_task_processor], %l0 sethi %hi(irq_stat), %l2 ! &softirq_active @@ -148,9 +147,12 @@ lduw [%l2 + %l0], %l1 ! softirq_pending cmp %l1, 0 + /* mm/ultra.S:xcall_report_regs KNOWS about this load. */ bne,pn %icc, __handle_softirq ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 + __handle_softirq_continue: +rtrap_xcall: sethi %hi(0xf << 20), %l4 andcc %l1, TSTATE_PRIV, %l3 and %l1, %l4, %l4 @@ -296,5 +298,3 @@ wr %g0, FPRS_DU, %fprs ba,pt %xcc, rt_continue stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] - -#undef PTREGS_OFF diff -urN linux-2.4.18/arch/sparc64/kernel/sbus.c linux-2.4.19-pre5/arch/sparc64/kernel/sbus.c --- linux-2.4.18/arch/sparc64/kernel/sbus.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/sbus.c Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.17 2001/10/09 02:24:33 davem Exp $ +/* $Id: sbus.c,v 1.17.2.1 2002/03/03 10:31:56 davem Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -632,11 +632,11 @@ /* SBUS SYSIO INO number to Sparc PIL level. */ static unsigned char sysio_ino_to_pil[] = { - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */ - 3, /* Onboard SCSI */ + 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 0 */ + 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 1 */ + 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 2 */ + 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 3 */ + 4, /* Onboard SCSI */ 5, /* Onboard Ethernet */ /*XXX*/ 8, /* Onboard BPP */ 0, /* Bogon */ @@ -758,6 +758,10 @@ printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); panic("Bad SYSIO IRQ translations..."); } + + if (PIL_RESERVED(pil)) + BUG(); + imap = sysio_irq_offsets[ino]; if (imap == ((unsigned long)-1)) { prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", diff -urN linux-2.4.18/arch/sparc64/kernel/setup.c linux-2.4.19-pre5/arch/sparc64/kernel/setup.c --- linux-2.4.18/arch/sparc64/kernel/setup.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/setup.c Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.71 2001/11/13 00:49:28 davem Exp $ +/* $Id: setup.c,v 1.71.2.1 2002/02/27 21:31:38 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -530,7 +530,7 @@ if (!root_flags) root_mountflags &= ~MS_RDONLY; ROOT_DEV = to_kdev_t(root_dev); -#ifdef CONFIG_BLK_DEV_RAM +#ifdef CONFIG_BLK_DEV_INITRD rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); diff -urN linux-2.4.18/arch/sparc64/kernel/signal.c linux-2.4.19-pre5/arch/sparc64/kernel/signal.c --- linux-2.4.18/arch/sparc64/kernel/signal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/signal.c Sat Mar 30 22:55:34 2002 @@ -806,10 +806,7 @@ #endif /* fall through */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOT REACHED */ } } diff -urN linux-2.4.18/arch/sparc64/kernel/signal32.c linux-2.4.19-pre5/arch/sparc64/kernel/signal32.c --- linux-2.4.18/arch/sparc64/kernel/signal32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/signal32.c Sat Mar 30 22:55:34 2002 @@ -1478,10 +1478,7 @@ #endif /* fall through */ default: - sigaddset(¤t->pending.signal, signr); - recalc_sigpending(current); - current->flags |= PF_SIGNALED; - do_exit(exit_code); + sig_exit(signr, exit_code, &info); /* NOT REACHED */ } } diff -urN linux-2.4.18/arch/sparc64/kernel/smp.c linux-2.4.19-pre5/arch/sparc64/kernel/smp.c --- linux-2.4.18/arch/sparc64/kernel/smp.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/smp.c Sat Mar 30 22:55:39 2002 @@ -46,8 +46,8 @@ volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES))); /* Please don't make this stuff initdata!!! --DaveM */ -static unsigned char boot_cpu_id = 0; -static int smp_activated = 0; +static unsigned char boot_cpu_id; +static int smp_activated; /* Kernel spinlock */ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; @@ -602,11 +602,12 @@ return 0; } -void smp_call_function_client(void) +void smp_call_function_client(int irq, struct pt_regs *regs) { void (*func) (void *info) = call_data->func; void *info = call_data->info; + clear_softint(1 << irq); if (call_data->wait) { /* let initiator proceed only after completion */ func(info); @@ -730,6 +731,12 @@ } } +void smp_receive_signal_client(int irq, struct pt_regs *regs) +{ + /* Just return, rtrap takes care of the rest. */ + clear_softint(1 << irq); +} + void smp_report_regs(void) { smp_cross_call(&xcall_report_regs, 0, 0, 0); @@ -897,7 +904,7 @@ static atomic_t smp_capture_depth = ATOMIC_INIT(0); static atomic_t smp_capture_registry = ATOMIC_INIT(0); -static unsigned long penguins_are_doing_time = 0; +static unsigned long penguins_are_doing_time; void smp_capture(void) { @@ -946,9 +953,11 @@ extern void prom_world(int); extern void save_alternate_globals(unsigned long *); extern void restore_alternate_globals(unsigned long *); -void smp_penguin_jailcell(void) +void smp_penguin_jailcell(int irq, struct pt_regs *regs) { unsigned long global_save[24]; + + clear_softint(1 << irq); __asm__ __volatile__("flushw"); save_alternate_globals(global_save); diff -urN linux-2.4.18/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.19-pre5/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.4.18/arch/sparc64/kernel/sparc64_ksyms.c Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/sparc64_ksyms.c Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.119 2001/11/30 01:04:10 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.119.2.2 2002/03/14 01:26:21 kanoj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -133,6 +133,11 @@ EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); + +#if defined(CONFIG_MCOUNT) +extern void mcount(void); +EXPORT_SYMBOL(mcount); +#endif /* Per-CPU information table */ EXPORT_SYMBOL(cpu_data); diff -urN linux-2.4.18/arch/sparc64/kernel/sys_sparc.c linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc.c --- linux-2.4.18/arch/sparc64/kernel/sys_sparc.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc.c Sat Mar 30 22:55:39 2002 @@ -380,7 +380,7 @@ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) { - static int count=0; + static int count; /* Don't make the system unusable, if someone goes stuck */ if (count++ > 5) @@ -450,7 +450,7 @@ asmlinkage int solaris_syscall(struct pt_regs *regs) { - static int count = 0; + static int count; regs->tpc = regs->tnpc; regs->tnpc += 4; @@ -470,7 +470,7 @@ #ifndef CONFIG_SUNOS_EMUL asmlinkage int sunos_syscall(struct pt_regs *regs) { - static int count = 0; + static int count; regs->tpc = regs->tnpc; regs->tnpc += 4; diff -urN linux-2.4.18/arch/sparc64/kernel/sys_sparc32.c linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.18/arch/sparc64/kernel/sys_sparc32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc32.c Sat Mar 30 22:55:27 2002 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.182 2001/10/18 09:06:36 davem Exp $ +/* $Id: sys_sparc32.c,v 1.182.2.1 2002/02/20 08:49:24 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -1066,16 +1067,20 @@ /* First get the "struct iovec" from user memory and * verify all the pointers */ + retval = 0; if (!count) - return 0; + goto out_nofree; + retval = -EFAULT; if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) - return -EFAULT; + goto out_nofree; + retval = -EINVAL; if (count > UIO_MAXIOV) - return -EINVAL; + goto out_nofree; if (count > UIO_FASTIOV) { + retval = -ENOMEM; iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return -ENOMEM; + goto out_nofree; } tot_len = 0; @@ -1135,6 +1140,11 @@ out: if (iov != iovstack) kfree(iov); +out_nofree: + /* VERIFY_WRITE actually means a read, as we write to user space */ + if ((retval + (type == VERIFY_WRITE)) > 0) + dnotify_parent(file->f_dentry, + (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS); return retval; } diff -urN linux-2.4.18/arch/sparc64/kernel/sys_sunos32.c linux-2.4.19-pre5/arch/sparc64/kernel/sys_sunos32.c --- linux-2.4.18/arch/sparc64/kernel/sys_sunos32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/sys_sunos32.c Sat Mar 30 22:55:39 2002 @@ -210,7 +210,7 @@ asmlinkage void sunos_vadvise(u32 strategy) { - static int count = 0; + static int count; /* I wanna see who uses this... */ if (count++ < 5) diff -urN linux-2.4.18/arch/sparc64/kernel/systbls.S linux-2.4.19-pre5/arch/sparc64/kernel/systbls.S --- linux-2.4.18/arch/sparc64/kernel/systbls.S Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/systbls.S Sat Mar 30 22:55:34 2002 @@ -70,7 +70,7 @@ /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep /*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_aplib + .word sys_aplib, sys_tkill /* Now the 64-bit native Linux syscall table. */ @@ -129,7 +129,7 @@ /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_aplib + .word sys_aplib, sys_tkill #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) diff -urN linux-2.4.18/arch/sparc64/kernel/time.c linux-2.4.19-pre5/arch/sparc64/kernel/time.c --- linux-2.4.18/arch/sparc64/kernel/time.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/kernel/time.c Sat Mar 30 22:55:39 2002 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.41.2.1 2002/01/23 14:35:45 davem Exp $ +/* $Id: time.c,v 1.41.2.2 2002/03/03 04:08:10 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -62,7 +62,7 @@ static __inline__ void timer_check_rtc(void) { /* last time the cmos clock got updated */ - static long last_rtc_update=0; + static long last_rtc_update; /* Determine when to update the Mostek clock. */ if ((time_status & STA_UNSYNC) == 0 && @@ -405,11 +405,12 @@ char model[128]; int node, busnd = -1, err; unsigned long flags; + struct linux_central *cbus; #ifdef CONFIG_PCI struct linux_ebus *ebus = NULL; struct isa_bridge *isa_br = NULL; #endif - static int invoked = 0; + static int invoked; if (invoked) return; @@ -431,21 +432,30 @@ __save_and_cli(flags); - if(central_bus != NULL) { + cbus = central_bus; + if (cbus != NULL) busnd = central_bus->child->prom_node; - } + + /* Check FHC Central then EBUSs then ISA bridges then SBUSs. + * That way we handle the presence of multiple properly. + * + * As a special case, machines with Central must provide the + * timer chip there. + */ #ifdef CONFIG_PCI - else if (ebus_chain != NULL) { + if (ebus_chain != NULL) { ebus = ebus_chain; - busnd = ebus->prom_node; - } else if (isa_chain != NULL) { + if (busnd == -1) + busnd = ebus->prom_node; + } + if (isa_chain != NULL) { isa_br = isa_chain; - busnd = isa_br->prom_node; + if (busnd == -1) + busnd = isa_br->prom_node; } #endif - else if (sbus_root != NULL) { + if (sbus_root != NULL && busnd == -1) busnd = sbus_root->prom_node; - } if (busnd == -1) { prom_printf("clock_probe: problem, cannot find bus to search.\n"); @@ -464,7 +474,12 @@ strcmp(model, "mk48t59") && strcmp(model, "m5819") && strcmp(model, "ds1287")) { - if (node) + if (cbus != NULL) { + prom_printf("clock_probe: Central bus lacks timer chip.\n"); + prom_halt(); + } + + if (node != 0) node = prom_getsibling(node); #ifdef CONFIG_PCI while ((node == 0) && ebus != NULL) { @@ -496,12 +511,12 @@ prom_halt(); } - if(central_bus) { + if (cbus != NULL) { apply_fhc_ranges(central_bus->child, clk_reg, 1); apply_central_ranges(central_bus, clk_reg, 1); } #ifdef CONFIG_PCI - else if (ebus_chain != NULL) { + else if (ebus != NULL) { struct linux_ebus_device *edev; for_each_ebusdev(edev, ebus) @@ -523,7 +538,8 @@ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; - } else if (isa_chain != NULL) { + } + else if (isa_br != NULL) { struct isa_device *isadev; try_isa_clock: diff -urN linux-2.4.18/arch/sparc64/kernel/trampoline.S linux-2.4.19-pre5/arch/sparc64/kernel/trampoline.S --- linux-2.4.18/arch/sparc64/kernel/trampoline.S Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/trampoline.S Sat Mar 30 22:55:39 2002 @@ -218,13 +218,6 @@ #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 -#if 1 -#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE -#else -#define VPTE_BASE_CHEETAH 0xffe0000000000000 -#endif - mov TSB_REG, %g1 stxa %g0, [%g1] ASI_DMMU membar #Sync @@ -255,8 +248,6 @@ clr %g7 #undef KERN_HIGHBITS #undef KERN_LOWBITS -#undef VPTE_BASE_SPITFIRE -#undef VPTE_BASE_CHEETAH /* Setup interrupt globals, we are always SMP. */ wrpr %o1, PSTATE_IG, %pstate diff -urN linux-2.4.18/arch/sparc64/kernel/ttable.S linux-2.4.19-pre5/arch/sparc64/kernel/ttable.S --- linux-2.4.18/arch/sparc64/kernel/ttable.S Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/kernel/ttable.S Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $ +/* $Id: ttable.S,v 1.36.2.1 2002/03/03 10:31:56 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. * * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) @@ -44,8 +44,16 @@ tl0_privact: TRAP_NOSAVE(__do_privact) tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) -tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2) -tl0_irq3: TRAP_IRQ(handler_irq, 3) TRAP_IRQ(handler_irq, 4) +#ifdef CONFIG_SMP +tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) +tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) +tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) +#else +tl0_irq1: BTRAP(0x41) +tl0_irq2: BTRAP(0x42) +tl0_irq3: BTRAP(0x43) +#endif +tl0_irq4: TRAP_IRQ(handler_irq, 4) tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) diff -urN linux-2.4.18/arch/sparc64/lib/Makefile linux-2.4.19-pre5/arch/sparc64/lib/Makefile --- linux-2.4.18/arch/sparc64/lib/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/lib/Makefile Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.25 2000/12/14 22:57:25 davem Exp $ +# $Id: Makefile,v 1.25.2.1 2002/03/14 01:26:21 kanoj Exp $ # Makefile for Sparc64 library files.. # @@ -16,6 +16,6 @@ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o + U3copy_in_user.o mcount.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/arch/sparc64/lib/mcount.S linux-2.4.19-pre5/arch/sparc64/lib/mcount.S --- linux-2.4.18/arch/sparc64/lib/mcount.S Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/arch/sparc64/lib/mcount.S Sat Mar 30 22:55:34 2002 @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * + * This file implements mcount(), which is used to collect profiling data. + * This can also be tweaked for kernel stack overflow detection. + */ + +#include +#include + +#include +#include + +/* + * This is the main variant and is called by C code. GCC's -pg option + * automatically instruments every C function with a call to this. + */ + +#ifdef CONFIG_STACK_DEBUG + +#define OVSTACKSIZE 4096 /* lets hope this is enough */ + + .data + .align 8 +panicstring: + .asciz "Stack overflow\n" + .align 8 +ovstack: + .skip OVSTACKSIZE +#endif + .text + .align 32 + .globl mcount +mcount: +#ifdef CONFIG_STACK_DEBUG + /* + * Check whether %sp is dangerously low. + */ + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1 + srl %g1, 1, %g5 + add %g5, 1, %g5 + sllx %g5, 8, %g5 ! each fpregs frame is 256b + add %g5, 192, %g5 + add %g6, %g5, %g5 ! where does task_struct+frame end? + sub %g5, STACK_BIAS, %g5 + cmp %sp, %g5 + bg,pt %xcc, 1f + sethi %hi(panicstring), %g5 + sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough + or %g7, %lo(ovstack), %g7 + add %g7, OVSTACKSIZE, %g7 + sub %g7, STACK_BIAS, %g7 + mov %g7, %sp + call prom_printf + or %g5, %lo(panicstring), %o0 + call prom_halt + nop +#endif +1: retl + nop diff -urN linux-2.4.18/arch/sparc64/mm/fault.c linux-2.4.19-pre5/arch/sparc64/mm/fault.c --- linux-2.4.18/arch/sparc64/mm/fault.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/mm/fault.c Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.58 2001/09/01 00:11:16 kanoj Exp $ +/* $Id: fault.c,v 1.58.2.2 2002/03/12 12:25:15 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -55,13 +55,21 @@ */ void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode) { - unsigned long lsubits = LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM; + unsigned long lsubits; + + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (lsubits) + : "i" (ASI_LSU_CONTROL)); + lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM | + LSU_CONTROL_PR | LSU_CONTROL_VR | + LSU_CONTROL_PW | LSU_CONTROL_VW); __asm__ __volatile__("stxa %0, [%1] %2\n\t" "membar #Sync" : /* no outputs */ : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT), "i" (ASI_DMMU)); + lsubits |= ((unsigned long)mask << (mode ? 25 : 33)); if (flags & VM_READ) lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR); @@ -340,6 +348,20 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; + if (!(fault_code & FAULT_CODE_WRITE)) { + /* Non-faulting loads shouldn't expand stack. */ + insn = get_fault_insn(regs, insn); + if ((insn & 0xc0800000) == 0xc0800000) { + unsigned char asi; + + if (insn & 0x2000) + asi = (regs->tstate >> 24); + else + asi = (insn >> 5); + if ((asi & 0xf2) == 0x82) + goto bad_area; + } + } if (expand_stack(vma, address)) goto bad_area; /* diff -urN linux-2.4.18/arch/sparc64/mm/init.c linux-2.4.19-pre5/arch/sparc64/mm/init.c --- linux-2.4.18/arch/sparc64/mm/init.c Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/mm/init.c Sat Mar 30 22:55:39 2002 @@ -616,7 +616,7 @@ } } -static int prom_ditlb_set = 0; +static int prom_ditlb_set; struct prom_tlb_entry { int tlb_ent; unsigned long tlb_tag; diff -urN linux-2.4.18/arch/sparc64/mm/ultra.S linux-2.4.19-pre5/arch/sparc64/mm/ultra.S --- linux-2.4.18/arch/sparc64/mm/ultra.S Sun Dec 23 16:23:37 2001 +++ linux-2.4.19-pre5/arch/sparc64/mm/ultra.S Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $ +/* $Id: ultra.S,v 1.70.2.1 2002/03/03 10:31:56 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com) @@ -10,6 +10,8 @@ #include #include #include +#include +#include /* Basically, all this madness has to do with the * fact that Cheetah does not support IMMU flushes @@ -489,6 +491,15 @@ nop nop + /* NOTE: This is SPECIAL!! We do etrap/rtrap however + * we choose to deal with the "BH's run with + * %pil==15" problem (described in asm/pil.h) + * by just invoking rtrap directly past where + * BH's are checked for. + * + * We do it like this because we do not want %pil==15 + * lockups to prevent regs being reported. + */ .globl xcall_report_regs xcall_report_regs: rdpr %pstate, %g2 @@ -500,8 +511,10 @@ 109: or %g7, %lo(109b), %g7 call __show_regs add %sp, STACK_BIAS + REGWIN_SZ, %o0 - b,pt %xcc, rtrap - clr %l6 + clr %l6 + /* Has to be a non-v9 branch due to the large distance. */ + b rtrap_xcall + ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 .align 32 .globl xcall_flush_dcache_page_cheetah @@ -550,20 +563,6 @@ nop nop - .globl xcall_capture -xcall_capture: - rdpr %pstate, %g2 - wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate - rdpr %pil, %g2 - wrpr %g0, 15, %pil - sethi %hi(109f), %g7 - b,pt %xcc, etrap_irq -109: or %g7, %lo(109b), %g7 - call smp_penguin_jailcell - nop - b,pt %xcc, rtrap - clr %l6 - .globl xcall_promstop xcall_promstop: rdpr %pstate, %g2 @@ -580,21 +579,6 @@ 1: b,a,pt %xcc, 1b nop - .globl xcall_receive_signal -xcall_receive_signal: - rdpr %pstate, %g2 - wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate - rdpr %tstate, %g1 - andcc %g1, TSTATE_PRIV, %g0 - /* If we did not trap from user space, just ignore. */ - bne,pn %xcc, 99f - sethi %hi(109f), %g7 - b,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - b,pt %xcc, rtrap - clr %l6 -99: retry - .data errata32_hwbug: @@ -677,18 +661,20 @@ __cheetah_xcall_flush_cache_all: retry + /* These just get rescheduled to PIL vectors. */ .globl xcall_call_function xcall_call_function: - rdpr %pstate, %g2 - wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate - rdpr %pil, %g2 - wrpr %g0, 15, %pil - sethi %hi(109f), %g7 - b,pt %xcc, etrap_irq -109: or %g7, %lo(109b), %g7 - call smp_call_function_client - nop - b,pt %xcc, rtrap - clr %l6 + wr %g0, (1 << PIL_SMP_CALL_FUNC), %set_softint + retry + + .globl xcall_receive_signal +xcall_receive_signal: + wr %g0, (1 << PIL_SMP_RECEIVE_SIGNAL), %set_softint + retry + + .globl xcall_capture +xcall_capture: + wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint + retry #endif /* CONFIG_SMP */ diff -urN linux-2.4.18/arch/sparc64/prom/Makefile linux-2.4.19-pre5/arch/sparc64/prom/Makefile --- linux-2.4.18/arch/sparc64/prom/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/prom/Makefile Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 2000/12/14 22:57:25 davem Exp $ +# $Id: Makefile,v 1.7.2.1 2002/03/14 01:26:21 kanoj Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # @@ -19,3 +19,6 @@ $(CC) $(AFLAGS) -ansi -c $< -o $*.o include $(TOPDIR)/Rules.make + +%.o: %.c + $(CC) $(subst -pg,,$(CFLAGS)) -c $< diff -urN linux-2.4.18/arch/sparc64/prom/bootstr.c linux-2.4.19-pre5/arch/sparc64/prom/bootstr.c --- linux-2.4.18/arch/sparc64/prom/bootstr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/prom/bootstr.c Sat Mar 30 22:55:39 2002 @@ -9,6 +9,11 @@ #include #include +/* WARNING: The boot loader knows that these next three variables come one right + * after another in the .data section. Do not move this stuff into + * the .bss section or it will break things. + */ + #define BARG_LEN 256 int bootstr_len = BARG_LEN; static int bootstr_valid = 0; diff -urN linux-2.4.18/arch/sparc64/prom/misc.c linux-2.4.19-pre5/arch/sparc64/prom/misc.c --- linux-2.4.18/arch/sparc64/prom/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/prom/misc.c Sat Mar 30 22:55:39 2002 @@ -171,7 +171,7 @@ static int prom_get_memory_ihandle(void) { - static int memory_ihandle_cache = 0; + static int memory_ihandle_cache; int node, ret; if (memory_ihandle_cache != 0) diff -urN linux-2.4.18/arch/sparc64/solaris/ioctl.c linux-2.4.19-pre5/arch/sparc64/solaris/ioctl.c --- linux-2.4.18/arch/sparc64/solaris/ioctl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/solaris/ioctl.c Sat Mar 30 22:55:34 2002 @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.16 2000/11/18 02:10:59 davem Exp $ +/* $Id: ioctl.c,v 1.16.2.1 2002/03/03 23:41:26 davem Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -289,11 +289,15 @@ { struct inode *ino; /* I wonder which of these tests are superfluous... --patrik */ + read_lock(¤t->files->file_lock); if (! current->files->fd[fd] || ! current->files->fd[fd]->f_dentry || ! (ino = current->files->fd[fd]->f_dentry->d_inode) || - ! ino->i_sock) + ! ino->i_sock) { + read_unlock(¤t->files->file_lock); return TBADF; + } + read_unlock(¤t->files->file_lock); switch (cmd & 0xff) { case 109: /* SI_SOCKPARAMS */ diff -urN linux-2.4.18/arch/sparc64/solaris/misc.c linux-2.4.19-pre5/arch/sparc64/solaris/misc.c --- linux-2.4.18/arch/sparc64/solaris/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/arch/sparc64/solaris/misc.c Sat Mar 30 22:55:39 2002 @@ -56,7 +56,7 @@ /* Do we need it here? */ set_personality(PER_SVR4); if (flags & MAP_NORESERVE) { - static int cnt = 0; + static int cnt; if (cnt < 5) { printk("%s: unimplemented Solaris MAP_NORESERVE mmap() flag\n", diff -urN linux-2.4.18/arch/sparc64/solaris/timod.c linux-2.4.19-pre5/arch/sparc64/solaris/timod.c --- linux-2.4.18/arch/sparc64/solaris/timod.c Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/arch/sparc64/solaris/timod.c Sat Mar 30 22:55:39 2002 @@ -46,7 +46,7 @@ void * mykmalloc(size_t s, int gfp) { static char * page; - static size_t free = 0; + static size_t free; void * r; s = ((s + 63) & ~63); if( s > PAGE_SIZE ) { diff -urN linux-2.4.18/drivers/Makefile linux-2.4.19-pre5/drivers/Makefile --- linux-2.4.18/drivers/Makefile Sun Mar 3 17:17:05 2002 +++ linux-2.4.19-pre5/drivers/Makefile Sat Mar 30 22:55:34 2002 @@ -36,7 +36,7 @@ subdir-$(CONFIG_MD) += md subdir-$(CONFIG_IEEE1394) += ieee1394 subdir-$(CONFIG_PNP) += pnp -subdir-$(CONFIG_ISDN) += isdn +subdir-$(CONFIG_ISDN_BOOL) += isdn subdir-$(CONFIG_ATM) += atm subdir-$(CONFIG_FC4) += fc4 diff -urN linux-2.4.18/drivers/acorn/char/mouse_ps2.c linux-2.4.19-pre5/drivers/acorn/char/mouse_ps2.c --- linux-2.4.18/drivers/acorn/char/mouse_ps2.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/acorn/char/mouse_ps2.c Sat Mar 30 22:55:34 2002 @@ -273,7 +273,8 @@ iomd_writeb(0, IOMD_MSECTL); iomd_writeb(8, IOMD_MSECTL); - misc_register(&psaux_mouse); + if (misc_register(&psaux_mouse)) + return -ENODEV; queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; diff -urN linux-2.4.18/drivers/acorn/scsi/ecoscsi.c linux-2.4.19-pre5/drivers/acorn/scsi/ecoscsi.c --- linux-2.4.18/drivers/acorn/scsi/ecoscsi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/acorn/scsi/ecoscsi.c Sat Mar 30 22:55:34 2002 @@ -125,7 +125,10 @@ } NCR5380_init(instance, 0); - request_region (instance->io_port, instance->n_io_port, "ecoscsi"); + if (request_region (instance->io_port, instance->n_io_port, "ecoscsi") == NULL) { + scsi_unregister(instance); + return 0; + } if (instance->irq != IRQ_NONE) if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) { diff -urN linux-2.4.18/drivers/acpi/executer/exresnte.c linux-2.4.19-pre5/drivers/acpi/executer/exresnte.c --- linux-2.4.18/drivers/acpi/executer/exresnte.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/acpi/executer/exresnte.c Sat Mar 30 22:55:27 2002 @@ -44,7 +44,7 @@ * FUNCTION: Acpi_ex_resolve_node_to_value * * PARAMETERS: Object_ptr - Pointer to a location that contains - * a pointer to a NS node, and will recieve a + * a pointer to a NS node, and will receive a * pointer to the resolved object. * Walk_state - Current state. Valid only if executing AML * code. NULL if simply resolving an object diff -urN linux-2.4.18/drivers/atm/fore200e.c linux-2.4.19-pre5/drivers/atm/fore200e.c --- linux-2.4.18/drivers/atm/fore200e.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/atm/fore200e.c Sat Mar 30 22:55:34 2002 @@ -252,7 +252,7 @@ fore200e_spin(int msecs) { unsigned long timeout = jiffies + MSECS(msecs); - while (jiffies < timeout); + while (time_before(jiffies, timeout)); } @@ -267,7 +267,7 @@ if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) break; - } while (jiffies < timeout); + } while (time_before(jiffies, timeout)); #if 1 if (!ok) { @@ -290,7 +290,7 @@ if ((ok = (fore200e->bus->read(addr) == val))) break; - } while (jiffies < timeout); + } while (time_before(jiffies, timeout)); #if 1 if (!ok) { @@ -2417,7 +2417,7 @@ unsigned long timeout = jiffies + MSECS(50); int c; - while (jiffies < timeout) { + while (time_before(jiffies, timeout)) { c = (int) fore200e->bus->read(&monitor->soft_uart.recv); diff -urN linux-2.4.18/drivers/block/Config.in linux-2.4.19-pre5/drivers/block/Config.in --- linux-2.4.18/drivers/block/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/Config.in Sat Mar 30 22:55:27 2002 @@ -35,6 +35,7 @@ fi dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI +dep_mbool ' SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP diff -urN linux-2.4.18/drivers/block/DAC960.c linux-2.4.19-pre5/drivers/block/DAC960.c --- linux-2.4.18/drivers/block/DAC960.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/DAC960.c Sat Mar 30 22:55:27 2002 @@ -7013,3 +7013,5 @@ module_init(DAC960_Initialize); module_exit(DAC960_Finalize); + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/block/amiflop.c linux-2.4.19-pre5/drivers/block/amiflop.c --- linux-2.4.18/drivers/block/amiflop.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/amiflop.c Sat Mar 30 22:55:34 2002 @@ -1491,7 +1491,6 @@ { int drive = inode->i_rdev & 3; static struct floppy_struct getprm; - struct super_block * sb; switch(cmd){ case HDIO_GETGEO: @@ -1678,9 +1677,6 @@ static int floppy_release(struct inode * inode, struct file * filp) { -#ifdef DEBUG - struct super_block * sb; -#endif int drive = MINOR(inode->i_rdev) & 3; if (unit[drive].dirty == 1) { diff -urN linux-2.4.18/drivers/block/cciss.c linux-2.4.19-pre5/drivers/block/cciss.c --- linux-2.4.18/drivers/block/cciss.c Sun Dec 23 16:23:38 2001 +++ linux-2.4.19-pre5/drivers/block/cciss.c Sat Mar 30 22:55:34 2002 @@ -64,6 +64,8 @@ 0x0E11, 0x4080, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082, 0, 0, 0}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, + 0x0E11, 0x4083, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -78,6 +80,7 @@ { 0x40700E11, "Smart Array 5300", &SA5_access }, { 0x40800E11, "Smart Array 5i", &SA5B_access}, { 0x40820E11, "Smart Array 532", &SA5B_access}, + { 0x40830E11, "Smart Array 5312", &SA5B_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -99,7 +102,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); -static int revalidate_allvol(kdev_t dev); static int revalidate_logvol(kdev_t dev, int maxusage); static int frevalidate_logvol(kdev_t dev); @@ -126,6 +128,8 @@ revalidate: frevalidate_logvol, }; +#include "cciss_scsi.c" /* For SCSI tape support */ + /* * Report information about this controller. */ @@ -162,6 +166,7 @@ h->maxQsinceinit, h->max_outstanding, h->maxSG); pos += size; len += size; + cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; inum_luns; i++) { drv = &h->drv[i]; size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n", @@ -181,20 +186,53 @@ return len; } +static int +cciss_proc_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned char cmd[80]; + int len; +#ifdef CONFIG_CISS_SCSI_TAPE + ctlr_info_t *h = (ctlr_info_t *) data; + int rc; +#endif + + if (count > sizeof(cmd)-1) return -EINVAL; + if (copy_from_user(cmd, buffer, count)) return -EFAULT; + cmd[count] = '\0'; + len = strlen(cmd); // safe??? + if (cmd[len-1] == '\n') + cmd[--len] = '\0'; +# ifdef CONFIG_CISS_SCSI_TAPE + if (strcmp("engage scsi", cmd)==0) { + rc = cciss_engage_scsi(h->ctlr); + if (rc != 0) return -rc; + return count; + } + /* might be nice to have "disengage" too, but it's not + safely possible. (only 1 module use count, lock issues.) */ +# endif + return -EINVAL; +} + /* * Get us a file in /proc/cciss that says something about each controller. * Create /proc/cciss if it doesn't exist yet. */ static void __init cciss_procinit(int i) { - if (proc_cciss == NULL) { - proc_cciss = proc_mkdir("cciss", proc_root_driver); - if (!proc_cciss) + struct proc_dir_entry *pde; + + if (proc_cciss == NULL) { + proc_cciss = proc_mkdir("cciss", proc_root_driver); + if (!proc_cciss) return; - } + } - create_proc_read_entry(hba[i]->devname, 0, proc_cciss, - cciss_proc_get_info, hba[i]); + pde = create_proc_read_entry(hba[i]->devname, + S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, + proc_cciss, cciss_proc_get_info, hba[i]); + pde->write_proc = cciss_proc_write; } #endif /* CONFIG_PROC_FS */ @@ -331,20 +369,18 @@ if (ctlr > MAX_CTLR || hba[ctlr] == NULL) return -ENXIO; - - if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0) - return -ENXIO; - /* * Root is allowed to open raw volume zero even if its not configured - * so array config can still work. I don't think I really like this, + * so array config can still work. I don't think I really like this, * but I'm already using way to many device nodes to claim another one * for "raw controller". */ - if (suser() - && (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) - && (MINOR(inode->i_rdev)!= 0)) - return -ENXIO; + if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) { /* not online? */ + if (MINOR(inode->i_rdev) != 0) /* not node 0? */ + return -ENXIO; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + } hba[ctlr]->drv[dsk].usage_count++; hba[ctlr]->usage_count++; @@ -377,8 +413,6 @@ { int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; - int diskinfo[4]; - struct hd_geometry *geo = (struct hd_geometry *)arg; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg); @@ -386,19 +420,45 @@ switch(cmd) { case HDIO_GETGEO: + { + struct hd_geometry driver_geo; if (hba[ctlr]->drv[dsk].cylinders) { - diskinfo[0] = hba[ctlr]->drv[dsk].heads; - diskinfo[1] = hba[ctlr]->drv[dsk].sectors; - diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; + driver_geo.heads = hba[ctlr]->drv[dsk].heads; + driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; + driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; } else { - diskinfo[0] = 0xff; - diskinfo[1] = 0x3f; - diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); } - put_user(diskinfo[0], &geo->heads); - put_user(diskinfo[1], &geo->sectors); - put_user(diskinfo[2], &geo->cylinders); - put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect, &geo->start); - return 0; + driver_geo.heads = 0xff; + driver_geo.sectors = 0x3f; + driver_geo.cylinders = + hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); + } + driver_geo.start= + hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect; + if (copy_to_user((void *) arg, &driver_geo, + sizeof( struct hd_geometry))) + return -EFAULT; + return(0); + } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry driver_geo; + if (hba[ctlr]->drv[dsk].cylinders) { + driver_geo.heads = hba[ctlr]->drv[dsk].heads; + driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; + driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; + } else { + driver_geo.heads = 0xff; + driver_geo.sectors = 0x3f; + driver_geo.cylinders = + hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); + } + driver_geo.start= + hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect; + if (copy_to_user((void *) arg, &driver_geo, + sizeof( struct hd_big_geometry))) + return -EFAULT; + return(0); + } case BLKGETSIZE: put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg); return 0; @@ -406,6 +466,8 @@ put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg); return 0; case BLKRRPART: + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; return revalidate_logvol(inode->i_rdev, 1); case BLKFLSBUF: case BLKBSZSET: @@ -581,9 +643,28 @@ return(0); } - case CCISS_REVALIDVOLS: - return( revalidate_allvol(inode->i_rdev)); - + case CCISS_GETLUNINFO: + { + LogvolInfo_struct luninfo; + int num_parts = 0; + int i, start; + + luninfo.LunID = hba[ctlr]->drv[dsk].LunID; + luninfo.num_opens = hba[ctlr]->drv[dsk].usage_count; + + /* count partitions 1 to 15 with sizes > 0 */ + start = (dsk << NWD_SHIFT); + for(i=1; i sizes[minor] != 0) + num_parts++; + } + luninfo.num_parts = num_parts; + if (copy_to_user((void *) arg, &luninfo, + sizeof( LogvolInfo_struct) )) + return -EFAULT; + return(0); + } case CCISS_PASSTHRU: { IOCTL_Command_struct iocommand; @@ -592,6 +673,7 @@ char *buff = NULL; u64bit temp64; unsigned long flags; + DECLARE_COMPLETION(wait); if (!arg) return -EINVAL; @@ -657,6 +739,8 @@ c->SG[0].Len = iocommand.buf_size; c->SG[0].Ext = 0; // we are not chaining } + c->waiting = &wait; + /* Put the request on the tail of the request queue */ spin_lock_irqsave(&io_request_lock, flags); addQ(&h->reqQ, c); @@ -664,9 +748,7 @@ start_io(h); spin_unlock_irqrestore(&io_request_lock, flags); - /* Wait for completion */ - while(c->cmd_type != CMD_IOCTL_DONE) - schedule_timeout(1); + wait_for_completion(&wait); /* unlock the buffers from DMA */ temp64.val32.lower = c->SG[0].Addr.lower; @@ -755,69 +837,6 @@ #endif /* CCISS_DEBUG */ return revalidate_logvol(dev, 0); } - -/* - * revalidate_allvol is for online array config utilities. After a - * utility reconfigures the drives in the array, it can use this function - * (through an ioctl) to make the driver zap any previous disk structs for - * that controller and get new ones. - * - * Right now I'm using the getgeometry() function to do this, but this - * function should probably be finer grained and allow you to revalidate one - * particualar logical volume (instead of all of them on a particular - * controller). - */ -static int revalidate_allvol(kdev_t dev) -{ - int ctlr, i; - unsigned long flags; - - ctlr = MAJOR(dev) - MAJOR_NR; - if (MINOR(dev) != 0) - return -ENXIO; - - spin_lock_irqsave(&io_request_lock, flags); - if (hba[ctlr]->usage_count > 1) { - spin_unlock_irqrestore(&io_request_lock, flags); - printk(KERN_WARNING "cciss: Device busy for volume" - " revalidation (usage=%d)\n", hba[ctlr]->usage_count); - return -EBUSY; - } - spin_unlock_irqrestore(&io_request_lock, flags); - hba[ctlr]->usage_count++; - - /* - * Set the partition and block size structures for all volumes - * on this controller to zero. We will reread all of this data - */ - memset(hba[ctlr]->hd, 0, sizeof(struct hd_struct) * 256); - memset(hba[ctlr]->sizes, 0, sizeof(int) * 256); - memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256); - memset(hba[ctlr]->hardsizes, 0, sizeof(int) * 256); - memset(hba[ctlr]->drv, 0, sizeof(drive_info_struct) - * CISS_MAX_LUN); - hba[ctlr]->gendisk.nr_real = 0; - - /* - * Tell the array controller not to give us any interrupts while - * we check the new geometry. Then turn interrupts back on when - * we're done. - */ - hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_OFF); - cciss_getgeometry(ctlr); - hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON); - - cciss_geninit(ctlr); - for(i=0; isizes[ i<usage_count--; - return 0; -} - - - /* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. @@ -849,9 +868,12 @@ int ctlr, void *buff, size_t size, - unsigned int use_unit_num, + unsigned int use_unit_num, /* 0: address the controller, + 1: address logical volume log_unit, + 2: periph device address is scsi3addr */ unsigned int log_unit, - __u8 page_code ) + __u8 page_code, + unsigned char *scsi3addr) { CommandList_struct *c; int i; @@ -885,15 +907,23 @@ to controller so It's a physical command mode = 0 target = 0. So we have nothing to write. - Otherwise - mode = 1 target = LUNID + otherwise, if use_unit_num == 1, + mode = 1(volume set addressing) target = LUNID + otherwise, if use_unit_num == 2, + mode = 0(periph dev addr) target = scsi3addr */ - if(use_unit_num != 0) + if(use_unit_num == 1) { c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; } + else if (use_unit_num == 2) + { + memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8); + c->Header.LUN.LogDev.Mode = 0; // phys dev addr + } + /* are we trying to read a vital product page */ if(page_code != 0) { @@ -909,6 +939,7 @@ c->Request.CDB[4] = size & 0xFF; break; case CISS_REPORT_LOG: + case CISS_REPORT_PHYS: /* Talking to controller so It's a physical command mode = 00 target = 0. So we have nothing to write. @@ -918,7 +949,7 @@ c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out - c->Request.CDB[0] = CISS_REPORT_LOG; + c->Request.CDB[0] = cmd; c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; @@ -936,6 +967,15 @@ c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CCISS_READ_CAPACITY; break; + case CCISS_CACHE_FLUSH: + c->Request.CDBLen = 12; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_WRITE; // No data + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = BMIC_WRITE; // BMIC Passthru + c->Request.CDB[6] = BMIC_CACHE_FLUSH; + break; default: printk(KERN_WARNING "cciss: Unknown Command 0x%c sent attempted\n", @@ -996,6 +1036,7 @@ ignore it */ if (((c->Request.CDB[0] == CISS_REPORT_LOG) || + (c->Request.CDB[0] == CISS_REPORT_PHYS) || (c->Request.CDB[0] == CISS_INQUIRY)) && ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || @@ -1145,17 +1186,27 @@ { /* an error has occurred */ switch(cmd->err_info->CommandStatus) { + unsigned char sense_key; case CMD_TARGET_STATUS: - printk(KERN_WARNING "cciss: cmd %p has " - " completed with errors\n", cmd); - if( cmd->err_info->ScsiStatus) - { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status = %x\n", - cmd, - cmd->err_info->ScsiStatus); - } - + status = 0; + + if( cmd->err_info->ScsiStatus == 0x02) { + printk(KERN_WARNING "cciss: cmd %p " + "has CHECK CONDITION," + " sense key = 0x%x\n", cmd, + cmd->err_info->SenseInfo[2]); + /* check the sense key */ + sense_key = 0xf & + cmd->err_info->SenseInfo[2]; + /* no status or recovered error */ + if ((sense_key == 0x0) || + (sense_key == 0x1)) + status = 1; + } else { + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status 0x%x\n", + cmd, cmd->err_info->ScsiStatus); + } break; case CMD_DATA_UNDERRUN: printk(KERN_WARNING "cciss: cmd %p has" @@ -1441,8 +1492,13 @@ complete_command(c, 0); cmd_free(h, c, 1); } else if (c->cmd_type == CMD_IOCTL_PEND) { - c->cmd_type = CMD_IOCTL_DONE; + complete(c->waiting); + } +# ifdef CONFIG_CISS_SCSI_TAPE + else if (c->cmd_type == CMD_SCSI) { + complete_scsi_command(c, 0, a1); } +# endif continue; } } @@ -1493,6 +1549,15 @@ } #endif /* CCISS_DEBUG */ +static void release_io_mem(ctlr_info_t *c) +{ + /* if IO mem was not protected do nothing */ + if( c->io_mem_addr == 0) + return; + release_region(c->io_mem_addr, c->io_mem_length); + c->io_mem_addr = 0; + c->io_mem_length = 0; +} static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort vendor_id, device_id, command; @@ -1533,6 +1598,36 @@ (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, &board_id); + /* check to see if controller has been disabled */ + if (!(command & 0x02)) { + printk(KERN_WARNING "cciss: controller appears to be disabled\n"); + return(-1); + } + /* search for our IO range so we can protect it */ + for (i=0; i<6; i++) { + /* is this an IO range */ + if (pdev->resource[i].flags & 0x01) { + c->io_mem_addr = pdev->resource[i].start; + c->io_mem_length = pdev->resource[i].end - + pdev->resource[i].start +1; +#ifdef CCISS_DEBUG + printk("IO value found base_addr[%d] %lx %lx\n", i, + c->io_mem_addr, c->io_mem_length); +#endif /* CCISS_DEBUG */ + /* register the IO range */ + if (!request_region( c->io_mem_addr, + c->io_mem_length, "cciss")) { + printk(KERN_WARNING + "cciss I/O memory range already in " + "use addr=%lx length=%ld\n", + c->io_mem_addr, c->io_mem_length); + c->io_mem_addr= 0; + c->io_mem_length = 0; + } + break; + } + } + #ifdef CCISS_DEBUG printk("vendor_id = %x\n", vendor_id); printk("device_id = %x\n", device_id); @@ -1553,7 +1648,7 @@ * table */ - c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */ + c->paddr = addr[0] ; /* addressing mode bits already removed */ #ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr); #endif /* CCISS_DEBUG */ @@ -1650,7 +1745,7 @@ int return_code; int i; int listlength = 0; - int lunid = 0; + __u32 lunid = 0; int block_size; int total_size; @@ -1678,7 +1773,7 @@ } /* Get the firmware version */ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, - sizeof(InquiryData_struct), 0, 0 ,0 ); + sizeof(InquiryData_struct), 0, 0 ,0, NULL); if (return_code == IO_OK) { hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32]; @@ -1692,7 +1787,7 @@ } /* Get the number of logical volumes */ return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, - sizeof(ReportLunData_struct), 0, 0, 0 ); + sizeof(ReportLunData_struct), 0, 0, 0, NULL); if( return_code == IO_OK) { @@ -1738,7 +1833,7 @@ memset(size_buff, 0, sizeof(ReadCapdata_struct)); return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, - sizeof( ReadCapdata_struct), 1, i, 0 ); + sizeof( ReadCapdata_struct), 1, i, 0, NULL); if (return_code == IO_OK) { total_size = (0xff & @@ -1770,7 +1865,7 @@ /* Execute the command to read the disk geometry */ memset(inq_buff, 0, sizeof(InquiryData_struct)); return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, - sizeof(InquiryData_struct), 1, i ,0xC1 ); + sizeof(InquiryData_struct), 1, i, 0xC1, NULL ); if (return_code == IO_OK) { if(inq_buff->data_byte[8] == 0xFF) @@ -1814,6 +1909,7 @@ } kfree(ld_buff); kfree(size_buff); + kfree(inq_buff); } /* Function to find the first free pointer into our hba[] array */ @@ -1878,17 +1974,20 @@ { printk(KERN_ERR "cciss: Unable to get major number " "%d for %s\n", MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); return(-1); } /* make sure the board interrupts are off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); if( request_irq(hba[i]->intr, do_cciss_intr, - SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) + SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + hba[i]->devname, hba[i])) { printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", hba[i]->intr, hba[i]->devname); unregister_blkdev( MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); return(-1); } @@ -1917,6 +2016,7 @@ hba[i]->errinfo_pool_dhandle); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); printk( KERN_ERR "cciss: out of memory"); return(-1); @@ -1935,6 +2035,8 @@ cciss_getgeometry(i); + cciss_find_non_disk_devices(i); /* find our tape drives, if any */ + /* Turn the interrupts on so we can service requests */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); @@ -1975,6 +2077,8 @@ MAX_PART, &cciss_fops, hba[i]->drv[j].nr_blocks); + cciss_register_scsi(i, 1); /* hook ourself into SCSI subsystem */ + return(1); } @@ -1982,6 +2086,8 @@ { ctlr_info_t *tmp_ptr; int i; + char flush_buf[4]; + int return_code; if (pci_get_drvdata(pdev) == NULL) { @@ -1996,11 +2102,19 @@ "already be removed \n"); return; } - /* Turn board interrupts off */ - hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + /* Turn board interrupts off and send the flush cache command */ + /* sendcmd will turn off interrupt, and send the flush... + * To write all data in the battery backed cache to disks */ + memset(flush_buf, 0, 4); + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4,0,0,0, NULL); + if (return_code != IO_OK) { + printk(KERN_WARNING + "Error Flushing cache on controller %d\n", i); + } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); iounmap((void*)hba[i]->vaddr); + cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ unregister_blkdev(MAJOR_NR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); @@ -2013,6 +2127,7 @@ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); kfree(hba[i]->cmd_pool_bits); + release_io_mem(hba[i]); free_hba(i); } diff -urN linux-2.4.18/drivers/block/cciss.h linux-2.4.19-pre5/drivers/block/cciss.h --- linux-2.4.18/drivers/block/cciss.h Mon Feb 18 06:25:35 2002 +++ linux-2.4.19-pre5/drivers/block/cciss.h Sat Mar 30 22:55:27 2002 @@ -51,6 +51,8 @@ __u32 board_id; ulong vaddr; __u32 paddr; + unsigned long io_mem_addr; + unsigned long io_mem_length; CfgTable_struct *cfgtable; int intr; @@ -88,6 +90,9 @@ int sizes[256]; int blocksizes[256]; int hardsizes[256]; +#ifdef CONFIG_CISS_SCSI_TAPE + void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ +#endif }; /* Defining the diffent access_menthods */ diff -urN linux-2.4.18/drivers/block/cciss_cmd.h linux-2.4.19-pre5/drivers/block/cciss_cmd.h --- linux-2.4.18/drivers/block/cciss_cmd.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/cciss_cmd.h Sat Mar 30 22:55:34 2002 @@ -89,6 +89,7 @@ //STRUCTURES //########################################################################### #define CISS_MAX_LUN 16 +#define CISS_MAX_PHYS_LUN 1024 // SCSI-3 Cmmands #pragma pack(1) @@ -101,6 +102,7 @@ } InquiryData_struct; #define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */ +#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */ // Data returned typedef struct _ReportLUNdata_struct { @@ -122,6 +124,12 @@ #define CCISS_READ 0x28 // Read(10) #define CCISS_WRITE 0x2a // Write(10) +// BMIC commands +#define BMIC_READ 0x26 +#define BMIC_WRITE 0x27 +#define BMIC_CACHE_FLUSH 0xc2 +#define CCISS_CACHE_FLUSH 0x01 //C2 was already being used by CCISS + //Command List Structure typedef union _SCSI3Addr_struct { struct { @@ -214,7 +222,9 @@ /* Command types */ #define CMD_RWREQ 0x00 #define CMD_IOCTL_PEND 0x01 -#define CMD_IOCTL_DONE 0x02 +#define CMD_SCSI 0x03 +#define CMD_MSG_DONE 0x04 +#define CMD_MSG_TIMEOUT 0x05 typedef struct _CommandList_struct { CommandListHeader_struct Header; @@ -229,6 +239,10 @@ struct _CommandList_struct *prev; struct _CommandList_struct *next; struct request * rq; + struct completion *waiting; +#ifdef CONFIG_CISS_SCSI_TAPE + void * scsi_cmd; +#endif } CommandList_struct; //Configuration Table Structure diff -urN linux-2.4.18/drivers/block/cciss_scsi.c linux-2.4.19-pre5/drivers/block/cciss_scsi.c --- linux-2.4.18/drivers/block/cciss_scsi.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/block/cciss_scsi.c Sat Mar 30 22:55:34 2002 @@ -0,0 +1,1602 @@ +/* + * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module + * Copyright 2001 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * Author: Stephen M. Cameron + */ +#ifdef CONFIG_CISS_SCSI_TAPE + +/* Here we have code to present the driver as a scsi driver + as it is simultaneously presented as a block driver. The + reason for doing this is to allow access to SCSI tape drives + through the array controller. Note in particular, neither + physical nor logical disks are presented through the scsi layer. */ + +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include +#include + +#include "cciss_scsi.h" + +/* some prototypes... */ +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int use_unit_num, /* 0: address the controller, + 1: address logical volume log_unit, + 2: address is in scsi3addr */ + unsigned int log_unit, + __u8 page_code, + unsigned char *scsi3addr ); + + +int __init cciss_scsi_detect(Scsi_Host_Template *tpnt); +int cciss_scsi_release(struct Scsi_Host *sh); +const char *cciss_scsi_info(struct Scsi_Host *sa); + +int cciss_scsi_proc_info( + char *buffer, /* data buffer */ + char **start, /* where data in buffer starts */ + off_t offset, /* offset from start of imaginary file */ + int length, /* length of data in buffer */ + int hostnum, /* which host adapter (always zero for me) */ + int func); /* 0 == read, 1 == write */ + +int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)); +#if 0 +int cciss_scsi_abort(Scsi_Cmnd *cmd); +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS +int cciss_scsi_reset(Scsi_Cmnd *cmd, unsigned int reset_flags); +#else +int cciss_scsi_reset(Scsi_Cmnd *cmd); +#endif +#endif + +static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = { + { name: "cciss0", ndevices: 0 }, + { name: "cciss1", ndevices: 0 }, + { name: "cciss2", ndevices: 0 }, + { name: "cciss3", ndevices: 0 }, + { name: "cciss4", ndevices: 0 }, + { name: "cciss5", ndevices: 0 }, + { name: "cciss6", ndevices: 0 }, + { name: "cciss7", ndevices: 0 }, +}; + +/* We need one Scsi_Host_Template *per controller* instead of + the usual one Scsi_Host_Template per controller *type*. This + is so PCI hot plug could have a remote possibility of still + working even with the SCSI system. It's so + scsi_unregister_module will differentiate the controllers. + When register_scsi_module is called, each host template is + customized (name change) in cciss_register_scsi() + (that's called from cciss.c:cciss_init_one()) */ + +static +Scsi_Host_Template driver_template[MAX_CTLR] = +{ + CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, + CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, +}; + +#pragma pack(1) +struct cciss_scsi_cmd_stack_elem_t { + CommandList_struct cmd; + ErrorInfo_struct Err; + __u32 busaddr; // 32 bits always, must fit through cmd register. +}; + +#pragma pack() + +#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \ + CCISS_MAX_SCSI_DEVS_PER_HBA + 2) + // plus two for init time usage + +#pragma pack(1) +struct cciss_scsi_cmd_stack_t { + struct cciss_scsi_cmd_stack_elem_t *pool; + struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE]; + dma_addr_t cmd_pool_handle; + int top; +}; +#pragma pack() + +struct cciss_scsi_adapter_data_t { + struct Scsi_Host *scsi_host; + struct cciss_scsi_cmd_stack_t cmd_stack; + int registered; + spinlock_t lock; // to protect ccissscsi[ctlr]; +}; +#if 1 +#define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \ + &(((struct cciss_scsi_adapter_data_t *) \ + hba[ctlr]->scsi_ctlr)->lock), flags); +#define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \ + &(((struct cciss_scsi_adapter_data_t *) \ + hba[ctlr]->scsi_ctlr)->lock), flags); +#else +#define CPQ_TAPE_LOCK(x,y) +#define CPQ_TAPE_UNLOCK(x,y) +#endif + +static CommandList_struct * +scsi_cmd_alloc(ctlr_info_t *h) +{ + /* assume only one process in here at a time, locking done by caller. */ + + /* take the top memory chunk off the stack and return it, if any. */ + struct cciss_scsi_cmd_stack_elem_t *c; + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + u64bit temp64; + + sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr; + stk = &sa->cmd_stack; + + if (stk->top < 0) + return NULL; + c = stk->elem[stk->top]; + memset(&c->cmd, 0, sizeof(c->cmd)); + memset(&c->Err, 0, sizeof(c->Err)); + /* set physical addr of cmd and addr of scsi parameters */ + c->cmd.busaddr = c->busaddr; + + temp64.val = (__u64) (c->busaddr + sizeof(CommandList_struct)); + stk->top--; + c->cmd.ErrDesc.Addr.lower = temp64.val32.lower; + c->cmd.ErrDesc.Addr.upper = temp64.val32.upper; + c->cmd.ErrDesc.Len = sizeof(ErrorInfo_struct); + + c->cmd.ctlr = h->ctlr; + c->cmd.err_info = &c->Err; + + return (CommandList_struct *) c; +} + +static void +scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd) +{ + /* assume only one process in here at a time, locking done by caller. */ + /* drop the free memory chunk on top of the stack. */ + + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + + sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr; + stk = &sa->cmd_stack; + if (stk->top >= CMD_STACK_SIZE) { + printk("cciss: scsi_cmd_free called too many times.\n"); + BUG(); + } + stk->top++; + stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd; +} + +static int +scsi_cmd_stack_setup(int ctlr) +{ + int i; + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + size_t size; + + sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; + stk = &sa->cmd_stack; + size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE; + + stk->pool = (struct cciss_scsi_cmd_stack_elem_t *) + pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle); + + if (stk->pool == NULL) { + printk("stk->pool is null\n"); + return -1; + } + + for (i=0; ielem[i] = &stk->pool[i]; + stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + + (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i)); + } + stk->top = CMD_STACK_SIZE-1; + return 0; +} + +static void +scsi_cmd_stack_free(int ctlr) +{ + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + size_t size; + + sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; + stk = &sa->cmd_stack; + if (stk->top != CMD_STACK_SIZE-1) { + printk( "cciss: %d scsi commands are still outstanding.\n", + CMD_STACK_SIZE - stk->top); + // BUG(); + printk("WE HAVE A BUG HERE!!! stk=0x%08x\n", + (unsigned int) stk); + } + size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE; + + pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle); + stk->pool = NULL; +} + +/* scsi_device_types comes from scsi.h */ +#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \ + "Unknown" : scsi_device_types[n] + +#if 0 +static int xmargin=8; +static int amargin=60; + +static void +print_bytes (unsigned char *c, int len, int hex, int ascii) +{ + + int i; + unsigned char *x; + + if (hex) + { + x = c; + for (i=0;i0) printk("\n"); + if ((i % xmargin) == 0) printk("0x%04x:", i); + printk(" %02x", *x); + x++; + } + printk("\n"); + } + if (ascii) + { + x = c; + for (i=0;i0) printk("\n"); + if ((i % amargin) == 0) printk("0x%04x:", i); + if (*x > 26 && *x < 128) printk("%c", *x); + else printk("."); + x++; + } + printk("\n"); + } +} + +static void +print_cmd(CommandList_struct *cp) +{ + printk("queue:%d\n", cp->Header.ReplyQueue); + printk("sglist:%d\n", cp->Header.SGList); + printk("sgtot:%d\n", cp->Header.SGTotal); + printk("Tag:0x%08x/0x%08x\n", cp->Header.Tag.upper, + cp->Header.Tag.lower); + printk("LUN:0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + cp->Header.LUN.LunAddrBytes[0], + cp->Header.LUN.LunAddrBytes[1], + cp->Header.LUN.LunAddrBytes[2], + cp->Header.LUN.LunAddrBytes[3], + cp->Header.LUN.LunAddrBytes[4], + cp->Header.LUN.LunAddrBytes[5], + cp->Header.LUN.LunAddrBytes[6], + cp->Header.LUN.LunAddrBytes[7]); + printk("CDBLen:%d\n", cp->Request.CDBLen); + printk("Type:%d\n",cp->Request.Type.Type); + printk("Attr:%d\n",cp->Request.Type.Attribute); + printk(" Dir:%d\n",cp->Request.Type.Direction); + printk("Timeout:%d\n",cp->Request.Timeout); + printk( "CDB: %02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x %02x %02x %02x %02x\n", + cp->Request.CDB[0], cp->Request.CDB[1], + cp->Request.CDB[2], cp->Request.CDB[3], + cp->Request.CDB[4], cp->Request.CDB[5], + cp->Request.CDB[6], cp->Request.CDB[7], + cp->Request.CDB[8], cp->Request.CDB[9], + cp->Request.CDB[10], cp->Request.CDB[11], + cp->Request.CDB[12], cp->Request.CDB[13], + cp->Request.CDB[14], cp->Request.CDB[15]), + printk("edesc.Addr: 0x%08x/0%08x, Len = %d\n", + cp->ErrDesc.Addr.upper, cp->ErrDesc.Addr.lower, + cp->ErrDesc.Len); + printk("sgs..........Errorinfo:\n"); + printk("scsistatus:%d\n", cp->err_info->ScsiStatus); + printk("senselen:%d\n", cp->err_info->SenseLen); + printk("cmd status:%d\n", cp->err_info->CommandStatus); + printk("resid cnt:%d\n", cp->err_info->ResidualCnt); + printk("offense size:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_size); + printk("offense byte:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_num); + printk("offense value:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_value); + +} + +#endif + +static int +find_bus_target_lun(int ctlr, int *bus, int *target, int *lun) +{ + /* finds an unused bus, target, lun for a new device */ + /* assumes hba[ctlr]->scsi_ctlr->lock is held */ + int i, found=0; + unsigned char target_taken[CCISS_MAX_SCSI_DEVS_PER_HBA]; + + memset(&target_taken[0], 0, CCISS_MAX_SCSI_DEVS_PER_HBA); + +# if SELF_SCSI_ID >= 0 + target_taken[SELF_SCSI_ID] = 1; +# endif + for (i=0;iscsi_ctlr->lock is held */ + int n = ccissscsi[ctlr].ndevices; + struct cciss_scsi_dev_t *sd; + + if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { + printk("cciss%d: Too many devices, " + "some will be inaccessible.\n", ctlr); + return -1; + } + sd = &ccissscsi[ctlr].dev[n]; + if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) + return -1; + memcpy(&sd->scsi3addr[0], scsi3addr, 8); + sd->devtype = devtype; + ccissscsi[ctlr].ndevices++; + + /* initially, (before registering with scsi layer) we don't + know our hostno and we don't want to print anything first + time anyway (the scsi layer's inquiries will show that info) */ + if (hostno != -1) + printk("cciss%d: %s device c%db%dt%dl%d added.\n", + ctlr, DEVICETYPE(sd->devtype), hostno, + sd->bus, sd->target, sd->lun); + return 0; +} + +static void +cciss_scsi_remove_entry(int ctlr, int hostno, int entry) +{ + /* assumes hba[ctlr]->scsi_ctlr->lock is held */ + int i; + struct cciss_scsi_dev_t sd; + + if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; + sd = ccissscsi[ctlr].dev[entry]; + for (i=entry;iscsi3addr)) { + if (sd[j].devtype == csd->devtype) + found=2; + else + found=1; + break; + } + } + + if (found == 0) { /* device no longer present. */ + changes++; + /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", + ctlr, DEVICETYPE(csd->devtype), hostno, + csd->bus, csd->target, csd->lun); */ + cciss_scsi_remove_entry(ctlr, hostno, i); + /* note, i not incremented */ + } + else if (found == 1) { /* device is different kind */ + changes++; + printk("cciss%d: device c%db%dt%dl%d type changed " + "(device type now %s).\n", + ctlr, hostno, csd->bus, csd->target, csd->lun, + DEVICETYPE(csd->devtype)); + csd->devtype = sd[j].devtype; + i++; /* so just move along. */ + } else /* device is same as it ever was, */ + i++; /* so just move along. */ + } + + /* Now, make sure every device listed in sd[] is also + listed in ccissscsi[], adding them if they aren't found */ + + for (i=0;iscsi3addr)) { + if (sd[i].devtype == csd->devtype) + found=2; /* found device */ + else + found=1; /* found a bug. */ + break; + } + } + if (!found) { + changes++; + if (cciss_scsi_add_entry(ctlr, hostno, + &sd[i].scsi3addr[0], sd[i].devtype) != 0) + break; + } else if (found == 1) { + /* should never happen... */ + changes++; + printk("cciss%d: device unexpectedly changed type\n", + ctlr); + /* but if it does happen, we just ignore that device */ + } + } + CPQ_TAPE_UNLOCK(ctlr, flags); + + if (!changes) + printk("cciss%d: No device changes detected.\n", ctlr); + + return 0; +} + +static int +lookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr) +{ + int i; + struct cciss_scsi_dev_t *sd; + unsigned long flags; + + CPQ_TAPE_LOCK(ctlr, flags); + for (i=0;ibus == bus && + sd->target == target && + sd->lun == lun) { + memcpy(scsi3addr, &sd->scsi3addr[0], 8); + CPQ_TAPE_UNLOCK(ctlr, flags); + return 0; + } + } + CPQ_TAPE_UNLOCK(ctlr, flags); + return -1; +} + + +static void +cciss_find_non_disk_devices(int cntl_num) +{ + ReportLunData_struct *ld_buff; + InquiryData_struct *inq_buff; + int return_code; + int i; + int listlength = 0; + int num_luns; + unsigned char scsi3addr[8]; + unsigned long flags; + int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8; + + hba[cntl_num]->scsi_ctlr = (void *) + kmalloc(sizeof(struct cciss_scsi_adapter_data_t), + GFP_KERNEL); + if (hba[cntl_num]->scsi_ctlr == NULL) + return; + + ((struct cciss_scsi_adapter_data_t *) + hba[cntl_num]->scsi_ctlr)->scsi_host = NULL; + ((struct cciss_scsi_adapter_data_t *) + hba[cntl_num]->scsi_ctlr)->lock = SPIN_LOCK_UNLOCKED; + ((struct cciss_scsi_adapter_data_t *) + hba[cntl_num]->scsi_ctlr)->registered = 0; + + if (scsi_cmd_stack_setup(cntl_num) != 0) { + printk("Trouble, returned non-zero!\n"); + return; + } + + ld_buff = kmalloc(reportlunsize, GFP_KERNEL); + if (ld_buff == NULL) { + printk(KERN_ERR "cciss: out of memory\n"); + return; + } + memset(ld_buff, 0, sizeof(ReportLunData_struct)); + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + return; + } + + /* Get the physical luns */ + return_code = sendcmd(CISS_REPORT_PHYS, cntl_num, ld_buff, + reportlunsize, 0, 0, 0, NULL ); + + if( return_code == IO_OK) { + unsigned char *c = &ld_buff->LUNListLength[0]; + listlength = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + } + else { /* getting report of physical luns failed */ + printk(KERN_WARNING "cciss: report physical luns" + " command failed\n"); + listlength = 0; + } + + CPQ_TAPE_LOCK(cntl_num, flags); + ccissscsi[cntl_num].ndevices = 0; + num_luns = listlength / 8; // 8 bytes pre entry + /* printk("Found %d LUNs\n", num_luns); */ + + if (num_luns > CISS_MAX_PHYS_LUN) + { + printk(KERN_WARNING + "cciss: Maximum physical LUNs (%d) exceeded. " + "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, + num_luns - CISS_MAX_PHYS_LUN); + num_luns = CISS_MAX_PHYS_LUN; + } + + for(i=0; iLUN[i], 8); /* ugly... */ + return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, + sizeof(InquiryData_struct), 2, 0 ,0, scsi3addr ); + if (return_code == IO_OK) { + if(inq_buff->data_byte[8] == 0xFF) + { + printk(KERN_WARNING "cciss: inquiry failed\n"); + } else { + int devtype; + + /* printk("Inquiry...\n"); + print_bytes((unsigned char *) inq_buff, 36, 1, 1); */ + devtype = (inq_buff->data_byte[0] & 0x1f); + + switch (devtype) + { + case 0x01: /* sequential access, (tape) */ + case 0x08: /* medium changer */ + /* this is the only kind of dev */ + /* we want to expose here. */ + if (cciss_scsi_add_entry(cntl_num, -1, + (unsigned char *) ld_buff->LUN[i], + devtype) != 0) + i=num_luns; // leave loop + break; + default: + break; + } + + } + } + else printk("cciss: inquiry failed.\n"); + } +#if 0 + for (i=0;ierr_info; + + /* First, see if it was a message rather than a command */ + if (cp->Request.Type.Type == TYPE_MSG) { + cp->cmd_type = CMD_MSG_DONE; + return; + } + + /* we stored ptr to scsi cmd in the buffer head pointer */ + cmd = (Scsi_Cmnd *) cp->scsi_cmd; + ctlr = hba[cp->ctlr]; + + /* undo the DMA mappings */ + + if (cmd->use_sg) { + pci_unmap_sg(ctlr->pdev, + cmd->buffer, cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + else if (cmd->request_bufflen) { + addr64.val32.lower = cp->SG[0].Addr.lower; + addr64.val32.upper = cp->SG[0].Addr.upper; + pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + + cmd->result = (DID_OK << 16); /* host byte */ + cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + /* cmd->result |= (GOOD < 1); */ /* status byte */ + + cmd->result |= (ei->ScsiStatus); + /* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus); */ + + /* copy the sense data whether we need to or not. */ + + memcpy(cmd->sense_buffer, ei->SenseInfo, + ei->SenseLen > SCSI_SENSE_BUFFERSIZE ? + SCSI_SENSE_BUFFERSIZE : + ei->SenseLen); + cmd->resid = ei->ResidualCnt; + + if(ei->CommandStatus != 0) + { /* an error has occurred */ + switch(ei->CommandStatus) + { + case CMD_TARGET_STATUS: + /* Pass it up to the upper layers... */ + if( ei->ScsiStatus) + cmd->result |= (ei->ScsiStatus < 1); + else { /* scsi status is zero??? How??? */ + + /* Ordinarily, this case should never happen, but there is a bug + in some released firmware revisions that allows it to happen + if, for example, a 4100 backplane loses power and the tape + drive is in it. We assume that it's a fatal error of some + kind because we can't show that it wasn't. We will make it + look like selection timeout since that is the most common + reason for this to occur, and it's severe enough. */ + + cmd->result = DID_NO_CONNECT << 16; + } + break; + case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ + break; + case CMD_DATA_OVERRUN: + printk(KERN_WARNING "cciss: cp %p has" + " completed with data overrun " + "reported\n", cp); + break; + case CMD_INVALID: { + /* print_bytes(cp, sizeof(*cp), 1, 0); + print_cmd(cp); */ + /* We get CMD_INVALID if you address a non-existent tape drive instead + of a selection timeout (no response). You will see this if you yank + out a tape drive, then try to access it. This is kind of a shame + because it means that any other CMD_INVALID (e.g. driver bug) will + get interpreted as a missing target. */ + cmd->result = DID_NO_CONNECT << 16; + } + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cp %p has " + "protocol error \n", cp); + break; + case CMD_HARDWARE_ERR: + cmd->result = DID_ERROR << 16; + printk(KERN_WARNING "cciss: cp %p had " + " hardware error\n", cp); + break; + case CMD_CONNECTION_LOST: + cmd->result = DID_ERROR << 16; + printk(KERN_WARNING "cciss: cp %p had " + "connection lost\n", cp); + break; + case CMD_ABORTED: + cmd->result = DID_ABORT << 16; + printk(KERN_WARNING "cciss: cp %p was " + "aborted\n", cp); + break; + case CMD_ABORT_FAILED: + cmd->result = DID_ERROR << 16; + printk(KERN_WARNING "cciss: cp %p reports " + "abort failed\n", cp); + break; + case CMD_UNSOLICITED_ABORT: + cmd->result = DID_ABORT << 16; + printk(KERN_WARNING "cciss: cp %p aborted " + "do to an unsolicited abort\n", cp); + break; + case CMD_TIMEOUT: + cmd->result = DID_TIME_OUT << 16; + printk(KERN_WARNING "cciss: cp %p timedout\n", + cp); + break; + default: + cmd->result = DID_ERROR << 16; + printk(KERN_WARNING "cciss: cp %p returned " + "unknown status %x\n", cp, + ei->CommandStatus); + } + } + cmd->scsi_done(cmd); + scsi_cmd_free(ctlr, cp); +} + +/* cciss_scsi_detect is called from the scsi mid layer. + The scsi mid layer (scsi_register_module) is + called from cciss.c:cciss_init_one(). */ + +int __init +cciss_scsi_detect(Scsi_Host_Template *tpnt) +{ + int i; + struct Scsi_Host *sh; + + /* Tell the kernel we want to be a SCSI driver... */ + sh = scsi_register(tpnt, sizeof(struct ctlr_info *)); + if (sh == NULL) return 0; + + sh->io_port = 0; // good enough? FIXME, + sh->n_io_port = 0; // I don't think we use these two... + + sh->this_id = SELF_SCSI_ID; + + /* This is a bit kludgey, using the adapter name to figure out */ + /* which scsi host template we've got, won't scale beyond 9 ctlrs. */ + i = tpnt->name[5] - '0'; + +# if MAX_CTLR > 9 +# error "cciss_scsi.c: MAX_CTLR > 9, code maintenance needed." +# endif + + if (i<0 || i>=MAX_CTLR || hba[i] == NULL) { + /* we didn't find ourself... we shouldn't get here. */ + printk("cciss_scsi_detect: could not find ourself in hba[]\n"); + return 0; + } + + ((struct cciss_scsi_adapter_data_t *) + hba[i]->scsi_ctlr)->scsi_host = (void *) sh; + sh->hostdata[0] = (unsigned long) hba[i]; + sh->irq = hba[i]->intr; + sh->unique_id = sh->irq; + scsi_set_pci_device(sh, hba[i]->pdev); + + return 1; /* Say we have 1 scsi adapter, this will be */ + /* called multiple times, once for each adapter */ + /* from cciss.c:cciss_init_one(). We do it this */ + /* way for PCI-hot plug reasons. (we don't know how */ + /* many adapters we have total, so we say we have */ + /* 1, each of a unique type.) */ +} + +static void __exit cleanup_cciss_module(void); +int +cciss_scsi_release(struct Scsi_Host *sh) +{ + return 0; +} + +static void +cciss_unmap_one(struct pci_dev *pdev, + CommandList_struct *cp, + size_t buflen, + int data_direction) +{ + u64bit addr64; + + addr64.val32.lower = cp->SG[0].Addr.lower; + addr64.val32.upper = cp->SG[0].Addr.upper; + pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction); +} + +static void +cciss_map_one(struct pci_dev *pdev, + CommandList_struct *cp, + unsigned char *buf, + size_t buflen, + int data_direction) +{ + __u64 addr64; + + addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction); + cp->SG[0].Addr.lower = + (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); + cp->SG[0].Addr.upper = + (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); + cp->SG[0].Len = buflen; + cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */ + cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */ +} + +static int +cciss_scsi_do_simple_cmd(ctlr_info_t *c, + CommandList_struct *cp, + unsigned char *scsi3addr, + unsigned char *cdb, + unsigned char cdblen, + unsigned char *buf, int bufsize, + int direction) +{ + unsigned long flags; + DECLARE_COMPLETION(wait); + + cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl + cp->scsi_cmd = NULL; + cp->Header.ReplyQueue = 0; // unused in simple mode + memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN)); + cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag + // Fill in the request block... + + /* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n", + scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3], + scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */ + + memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB)); + memcpy(cp->Request.CDB, cdb, cdblen); + cp->Request.Timeout = 1000; // guarantee completion. + cp->Request.CDBLen = cdblen; + cp->Request.Type.Type = TYPE_CMD; + cp->Request.Type.Attribute = ATTR_SIMPLE; + cp->Request.Type.Direction = direction; + + /* Fill in the SG list and do dma mapping */ + cciss_map_one(c->pdev, cp, + (unsigned char *) buf, bufsize, + scsi_to_pci_dma_dir(SCSI_DATA_READ)); + + cp->waiting = &wait; + + /* Put the request on the tail of the request queue */ + spin_lock_irqsave(&io_request_lock, flags); + addQ(&c->reqQ, cp); + c->Qdepth++; + start_io(c); + spin_unlock_irqrestore(&io_request_lock, flags); + + wait_for_completion(&wait); + + /* undo the dma mapping */ + cciss_unmap_one(c->pdev, cp, bufsize, + scsi_to_pci_dma_dir(SCSI_DATA_READ)); + + return(0); +} + +static void +cciss_scsi_interpret_error(CommandList_struct *cp) +{ + ErrorInfo_struct *ei; + + ei = cp->err_info; + switch(ei->CommandStatus) + { + case CMD_TARGET_STATUS: + printk(KERN_WARNING "cciss: cmd %p has " + "completed with errors\n", cp); + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status = %x\n", + cp, + ei->ScsiStatus); + if (ei->ScsiStatus == 0) + printk(KERN_WARNING + "cciss:SCSI status is abnormally zero. " + "(probably indicates selection timeout " + "reported incorrectly due to a known " + "firmware bug, circa July, 2001.)\n"); + break; + case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ + printk("UNDERRUN\n"); + break; + case CMD_DATA_OVERRUN: + printk(KERN_WARNING "cciss: cp %p has" + " completed with data overrun " + "reported\n", cp); + break; + case CMD_INVALID: { + /* controller unfortunately reports SCSI passthru's */ + /* to non-existent targets as invalid commands. */ + printk(KERN_WARNING "cciss: cp %p is " + "reported invalid (probably means " "target device no longer present)\n", + cp); + /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0); + print_cmd(cp); */ + } + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cp %p has " + "protocol error \n", cp); + break; + case CMD_HARDWARE_ERR: + /* cmd->result = DID_ERROR << 16; */ + printk(KERN_WARNING "cciss: cp %p had " + " hardware error\n", cp); + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cp %p had " + "connection lost\n", cp); + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cp %p was " + "aborted\n", cp); + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cp %p reports " + "abort failed\n", cp); + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss: cp %p aborted " + "do to an unsolicited abort\n", cp); + break; + case CMD_TIMEOUT: + printk(KERN_WARNING "cciss: cp %p timedout\n", + cp); + break; + default: + printk(KERN_WARNING "cciss: cp %p returned " + "unknown status %x\n", cp, + ei->CommandStatus); + } +} + +static int +cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, + InquiryData_struct *buf) +{ + int rc; + CommandList_struct *cp; + char cdb[6]; + ErrorInfo_struct *ei; + + cp = scsi_cmd_alloc(c); + ei = cp->err_info; + + if (cp == NULL) { /* trouble... */ + printk("cmd_alloc returned NULL!\n"); + return -1; + } + + cdb[0] = CISS_INQUIRY; + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = sizeof(*buf) & 0xff; + cdb[5] = 0; + rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, + 6, (unsigned char *) buf, + sizeof(*buf), XFER_READ); + + if (rc != 0) return rc; /* something went wrong */ + + if (ei->CommandStatus != 0 && + ei->CommandStatus != CMD_DATA_UNDERRUN) { + cciss_scsi_interpret_error(cp); + scsi_cmd_free(c, cp); + return -1; + } + scsi_cmd_free(c, cp); + return 0; +} + +static int +cciss_scsi_do_report_phys_luns(ctlr_info_t *c, + ReportLunData_struct *buf, int bufsize) +{ + int rc; + CommandList_struct *cp; + unsigned char cdb[12]; + unsigned char scsi3addr[8]; + ErrorInfo_struct *ei; + + cp = scsi_cmd_alloc(c); + if (cp == NULL) { /* trouble... */ + printk("cmd_alloc returned NULL!\n"); + return -1; + } + + memset(&scsi3addr[0], 0, 8); /* address the controller */ + cdb[0] = CISS_REPORT_PHYS; + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = 0; + cdb[5] = 0; + cdb[6] = (bufsize >> 24) & 0xFF; //MSB + cdb[7] = (bufsize >> 16) & 0xFF; + cdb[8] = (bufsize >> 8) & 0xFF; + cdb[9] = bufsize & 0xFF; + cdb[10] = 0; + cdb[11] = 0; + + rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, + cdb, 12, + (unsigned char *) buf, + bufsize, XFER_READ); + + if (rc != 0) return rc; /* something went wrong */ + + ei = cp->err_info; + if (ei->CommandStatus != 0 && + ei->CommandStatus != CMD_DATA_UNDERRUN) { + cciss_scsi_interpret_error(cp); + scsi_cmd_free(c, cp); + return -1; + } + scsi_cmd_free(c, cp); + return 0; +} + +static void +cciss_update_non_disk_devices(int cntl_num, int hostno) +{ + /* the idea here is we could get notified from /proc + that some devices have changed, so we do a report + physical luns cmd, and adjust our list of devices + accordingly. (We can't rely on the scsi-mid layer just + doing inquiries, because the "busses" that the scsi + mid-layer probes are totally fabricated by this driver, + so new devices wouldn't show up. + + the scsi3addr's of devices won't change so long as the + adapter is not reset. That means we can rescan and + tell which devices we already know about, vs. new + devices, vs. disappearing devices. + + Also, if you yank out a tape drive, then put in a disk + in it's place, (say, a configured volume from another + array controller for instance) _don't_ poke this driver + (so it thinks it's still a tape, but _do_ poke the scsi + mid layer, so it does an inquiry... the scsi mid layer + could see the physical disk. This would be bad. Need to + think about how to prevent that. One idea would be to + snoop all scsi responses and if an inquiry repsonse comes + back that reports a disk, chuck it an return selection + timeout instead and adjust our table... Not sure i like + that though. + + */ + + ReportLunData_struct *ld_buff; + InquiryData_struct *inq_buff; + unsigned char scsi3addr[8]; + ctlr_info_t *c; + __u32 num_luns=0; + unsigned char *ch; + /* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */ + struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA]; + int ncurrent=0; + int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8; + int i; + + c = (ctlr_info_t *) hba[cntl_num]; + ld_buff = kmalloc(reportlunsize, GFP_KERNEL); + if (ld_buff == NULL) { + printk(KERN_ERR "cciss: out of memory\n"); + return; + } + memset(ld_buff, 0, reportlunsize); + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + return; + } + + if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) { + ch = &ld_buff->LUNListLength[0]; + num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8; + if (num_luns > CISS_MAX_PHYS_LUN) { + printk(KERN_WARNING + "cciss: Maximum physical LUNs (%d) exceeded. " + "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, + num_luns - CISS_MAX_PHYS_LUN); + num_luns = CISS_MAX_PHYS_LUN; + } + } + else { + printk(KERN_ERR "cciss: Report physical LUNs failed.\n"); + return; + } + + + /* adjust our table of devices */ + for(i=0; iLUN[i][0], 8); + + if (cciss_scsi_do_inquiry(hba[cntl_num], + scsi3addr, inq_buff) != 0) + { + /* Inquiry failed (msg printed already) */ + devtype = 0; /* so we will skip this device. */ + } else /* what kind of device is this? */ + devtype = (inq_buff->data_byte[0] & 0x1f); + + switch (devtype) + { + case 0x01: /* sequential access, (tape) */ + case 0x08: /* medium changer */ + memcpy(¤tsd[ncurrent].scsi3addr[0], + &scsi3addr[0], 8); + currentsd[ncurrent].devtype = devtype; + currentsd[ncurrent].bus = -1; + currentsd[ncurrent].target = -1; + currentsd[ncurrent].lun = -1; + ncurrent++; + break; + default: + break; + } + } + + adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent); + + kfree(inq_buff); + kfree(ld_buff); + return; +} + +static int +is_keyword(char *ptr, int len, char *verb) // Thanks to ncr53c8xx.c +{ + int verb_len = strlen(verb); + if (len >= verb_len && !memcmp(verb,ptr,verb_len)) + return verb_len; + else + return 0; +} + +static int +cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length) +{ + int arg_len; + + if ((arg_len = is_keyword(buffer, length, "rescan")) != 0) + cciss_update_non_disk_devices(ctlr, hostno); + else + return -EINVAL; + return length; +} + +/* It's a pity that we need this, but, we do... */ +extern struct Scsi_Host *scsi_hostlist; /* from ../scsi/hosts.c */ + +int +cciss_scsi_proc_info(char *buffer, /* data buffer */ + char **start, /* where data in buffer starts */ + off_t offset, /* offset from start of imaginary file */ + int length, /* length of data in buffer */ + int hostnum, /* which host adapter (always zero for me) */ + int func) /* 0 == read, 1 == write */ +{ + + int buflen, datalen; + struct Scsi_Host *sh; + int found; + ctlr_info_t *ci; + int cntl_num; + + /* Lets see if we can find our Scsi_Host... + this might be kind of "bad", searching scis_hostlist this way + but how else can we find the scsi host? I think I've seen + this coded both ways, (circular list and null terminated list) + I coded it to work either way, since I wasn't sure. */ + + sh = scsi_hostlist; + found=0; + do { + if (sh == NULL) break; + if (sh->host_no == hostnum) { + found++; + break; + } + sh = sh->next; + } while (sh != scsi_hostlist && sh != NULL); + + if (sh == NULL || found == 0) /* This really shouldn't ever happen. */ + return -EINVAL; + + ci = (ctlr_info_t *) sh->hostdata[0]; + if (ci == NULL) /* This really shouldn't ever happen. */ + return -EINVAL; + + cntl_num = ci->ctlr; /* Get our index into the hba[] array */ + + if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */ + buflen = sprintf(buffer, "hostnum=%d\n", hostnum); + + datalen = buflen - offset; + if (datalen < 0) { /* they're reading past EOF. */ + datalen = 0; + *start = buffer+buflen; + } else + *start = buffer + offset; + return(datalen); + } else /* User is writing to /proc/scsi/cciss*?/?* ... */ + return cciss_scsi_user_command(cntl_num, hostnum, + buffer, length); +} + +/* this is via the generic proc support */ +const char * +cciss_scsi_info(struct Scsi_Host *sa) +{ + static char buf[300]; + ctlr_info_t *ci; + + /* probably need to work on putting a bit more info in here... */ + /* this is output via the /proc filesystem. */ + + ci = (ctlr_info_t *) sa->hostdata[0]; + + sprintf(buf, "%s %c%c%c%c\n", + ci->product_name, + ci->firm_ver[0], + ci->firm_ver[1], + ci->firm_ver[2], + ci->firm_ver[3]); + + return buf; +} + + +/* cciss_scatter_gather takes a Scsi_Cmnd, (cmd), and does the pci + dma mapping and fills in the scatter gather entries of the + cciss command, cp. */ + +static void +cciss_scatter_gather(struct pci_dev *pdev, + CommandList_struct *cp, + Scsi_Cmnd *cmd) +{ + unsigned int use_sg, nsegs=0, len; + struct scatterlist *scatter = (struct scatterlist *) cmd->buffer; + __u64 addr64; + + /* is it just one virtual address? */ + if (!cmd->use_sg) { + if (cmd->request_bufflen) { /* anything to xfer? */ + + addr64 = (__u64) pci_map_single(pdev, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + + cp->SG[0].Addr.lower = + (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); + cp->SG[0].Addr.upper = + (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); + cp->SG[0].Len = cmd->request_bufflen; + nsegs=1; + } + } /* else, must be a list of virtual addresses.... */ + else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */ + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + + for (nsegs=0; nsegs < use_sg; nsegs++) { + addr64 = (__u64) sg_dma_address(&scatter[nsegs]); + len = sg_dma_len(&scatter[nsegs]); + cp->SG[nsegs].Addr.lower = + (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); + cp->SG[nsegs].Addr.upper = + (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); + cp->SG[nsegs].Len = len; + cp->SG[nsegs].Ext = 0; // we are not chaining + } + } else BUG(); + + cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */ + cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */ + return; +} + + +int +cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + ctlr_info_t **c; + int ctlr, rc; + unsigned char scsi3addr[8]; + CommandList_struct *cp; + + // Get the ptr to our adapter structure (hba[i]) out of cmd->host. + // We violate cmd->host privacy here. (Is there another way?) + c = (ctlr_info_t **) &cmd->host->hostdata[0]; + ctlr = (*c)->ctlr; + + rc = lookup_scsi3addr(ctlr, cmd->channel, cmd->target, cmd->lun, + scsi3addr); + if (rc != 0) { + /* the scsi nexus does not match any that we presented... */ + /* pretend to mid layer that we got selection timeout */ + cmd->result = DID_NO_CONNECT << 16; + done(cmd); + /* we might want to think about registering controller itself + as a processor device on the bus so sg binds to it. */ + return 0; + } + + // printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n", + // cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun); + + /* Ok, we have a reasonable scsi nexus, so send the cmd down, and + see what the device thinks of it. */ + + cp = scsi_cmd_alloc(*c); + if (cp == NULL) { /* trouble... */ + printk("scsi_cmd_alloc returned NULL!\n"); + /* FIXME: next 3 lines are -> BAD! <- */ + cmd->result = DID_NO_CONNECT << 16; + done(cmd); + return 0; + } + + // Fill in the command list header + + cmd->scsi_done = done; // save this for use by completion code + + // save cp in case we have to abort it + cmd->host_scribble = (unsigned char *) cp; + + cp->cmd_type = CMD_SCSI; + cp->scsi_cmd = cmd; + cp->Header.ReplyQueue = 0; // unused in simple mode + memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); + cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag + + // Fill in the request block... + + cp->Request.Timeout = 1000; // guarantee completion + memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB)); + if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG(); + cp->Request.CDBLen = cmd->cmd_len; + memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len); + cp->Request.Type.Type = TYPE_CMD; + cp->Request.Type.Attribute = ATTR_SIMPLE; + switch(cmd->sc_data_direction) + { + case SCSI_DATA_WRITE: cp->Request.Type.Direction = XFER_WRITE; break; + case SCSI_DATA_READ: cp->Request.Type.Direction = XFER_READ; break; + case SCSI_DATA_NONE: cp->Request.Type.Direction = XFER_NONE; break; + + case SCSI_DATA_UNKNOWN: + // This can happen if a buggy application does a scsi passthru + // and sets both inlen and outlen to non-zero. ( see + // ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() ) + + cp->Request.Type.Direction = XFER_RSVD; + // This is technically wrong, and cciss controllers should + // reject it with CMD_INVALID, which is the most correct + // response, but non-fibre backends appear to let it + // slide by, and give the same results as if this field + // were set correctly. Either way is acceptable for + // our purposes here. + + break; + + default: + printk("cciss: unknown data direction: %d\n", + cmd->sc_data_direction); + BUG(); + break; + } + + cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list + + /* Put the request on the tail of the request queue */ + + addQ(&(*c)->reqQ, cp); + (*c)->Qdepth++; + start_io(*c); + + /* the cmd'll come back via intr handler in complete_scsi_command() */ + return 0; +} + +static void +init_driver_template(int ctlr) +{ + memset(&driver_template[ctlr], 0, sizeof(driver_template[ctlr])); + driver_template[ctlr].name = ccissscsi[ctlr].name; + driver_template[ctlr].proc_name = ccissscsi[ctlr].name; + driver_template[ctlr].detect = cciss_scsi_detect; + driver_template[ctlr].release = cciss_scsi_release; + driver_template[ctlr].proc_info = cciss_scsi_proc_info; + driver_template[ctlr].queuecommand = cciss_scsi_queue_command; + driver_template[ctlr].eh_abort_handler = NULL; + driver_template[ctlr].eh_device_reset_handler = NULL; + driver_template[ctlr].bios_param = scsicam_bios_param; + driver_template[ctlr].can_queue = SCSI_CCISS_CAN_QUEUE; + driver_template[ctlr].this_id = SELF_SCSI_ID; + driver_template[ctlr].sg_tablesize = MAXSGENTRIES; + driver_template[ctlr].cmd_per_lun = 1; + driver_template[ctlr].use_new_eh_code = 1; + driver_template[ctlr].use_clustering = DISABLE_CLUSTERING; + driver_template[ctlr].module = THIS_MODULE; + + /* set scsi_host to NULL so our detect routine will + find us on register */ + + ((struct cciss_scsi_adapter_data_t *) + hba[ctlr]->scsi_ctlr)->scsi_host = NULL; + +} + +static void +cciss_unregister_scsi(int ctlr) +{ + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + unsigned long flags; + + /* we are being forcibly unloaded, and may not refuse. */ + + spin_lock_irqsave(&io_request_lock, flags); + sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; + stk = &sa->cmd_stack; + + /* if we weren't ever actually registered, don't unregister */ + if (((struct cciss_scsi_adapter_data_t *) + hba[ctlr]->scsi_ctlr)->registered) { + spin_unlock_irqrestore(&io_request_lock, flags); + scsi_unregister_module(MODULE_SCSI_HA, &driver_template[ctlr]); + spin_lock_irqsave(&io_request_lock, flags); + } + init_driver_template(ctlr); + scsi_cmd_stack_free(ctlr); + kfree(hba[ctlr]->scsi_ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +static int +cciss_register_scsi(int ctlr, int this_is_init_time) +{ + unsigned long flags; + + CPQ_TAPE_LOCK(ctlr, flags); + driver_template[ctlr].name = ccissscsi[ctlr].name; + driver_template[ctlr].proc_name = ccissscsi[ctlr].name; + driver_template[ctlr].module = THIS_MODULE;; + + /* Since this is really a block driver, the SCSI core may not be + initialized yet, in which case, calling scsi_register_module + would hang. instead, we will do it later, via /proc filesystem + and rc scripts, when we know SCSI core is good to go. */ + + if (this_is_init_time) { + CPQ_TAPE_UNLOCK(ctlr, flags); + return 0; + } + + /* Only register if SCSI devices are detected. */ + if (ccissscsi[ctlr].ndevices != 0) { + ((struct cciss_scsi_adapter_data_t *) + hba[ctlr]->scsi_ctlr)->registered = 1; + CPQ_TAPE_UNLOCK(ctlr, flags); + return scsi_register_module(MODULE_SCSI_HA, + &driver_template[ctlr]); + } + CPQ_TAPE_UNLOCK(ctlr, flags); + printk(KERN_INFO + "cciss%d: No appropriate SCSI device detected, " + "SCSI subsystem not engaged.\n", ctlr); + return 0; +} + +static int +cciss_engage_scsi(int ctlr) +{ + struct cciss_scsi_adapter_data_t *sa; + struct cciss_scsi_cmd_stack_t *stk; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; + stk = &sa->cmd_stack; + + if (((struct cciss_scsi_adapter_data_t *) + hba[ctlr]->scsi_ctlr)->registered) { + printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); + return ENXIO; + } + spin_unlock_irqrestore(&io_request_lock, flags); + cciss_update_non_disk_devices(ctlr, -1); + cciss_register_scsi(ctlr, 0); + return 0; +} + +static void +cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) +{ + int size; + unsigned int flags; + + *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline + + CPQ_TAPE_LOCK(ctlr, flags); + size = sprintf(buffer + *len, + " Sequential access devices: %d\n\n", + ccissscsi[ctlr].ndevices); + CPQ_TAPE_UNLOCK(ctlr, flags); + *pos += size; *len += size; +} + +#else /* no CONFIG_CISS_SCSI_TAPE */ + +/* If no tape support, then these become defined out of existence */ + +#define cciss_find_non_disk_devices(cntl_num) +#define cciss_unregister_scsi(ctlr) +#define cciss_register_scsi(ctlr, this_is_init_time) +#define cciss_proc_tape_report(ctlr, buffer, pos, len) + +#endif /* CONFIG_CISS_SCSI_TAPE */ diff -urN linux-2.4.18/drivers/block/cciss_scsi.h linux-2.4.19-pre5/drivers/block/cciss_scsi.h --- linux-2.4.18/drivers/block/cciss_scsi.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/block/cciss_scsi.h Sat Mar 30 22:55:27 2002 @@ -0,0 +1,99 @@ +/* + * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module + * Copyright 2001 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + */ +#ifdef CONFIG_CISS_SCSI_TAPE +#ifndef _CCISS_SCSI_H_ +#define _CCISS_SCSI_H_ + +#include /* possibly irrelevant, since we don't show disks */ + + // the scsi id of the adapter... +#define SELF_SCSI_ID -1 + // In case we ever want to present controller so sg will + // bind to it. The scsi bus that's presented by the + // driver to the OS is fabricated. The "real" scsi-3 + // bus the hardware presents is fabricated too. + // The actual, honest-to-goodness physical + // bus that the devices are attached to is not + // addressible natively, and may in fact turn + // out to be not scsi at all. + +#define SCSI_CCISS_CAN_QUEUE 2 + +/* this notation works fine for static initializations (as is the usual + case for linux scsi drivers), but not so well for dynamic settings, + so, if you change this, you also have to change cciss_unregister_scsi() + in cciss_scsi.c */ +#define CCISS_SCSI { \ + name: "", \ + detect: cciss_scsi_detect, \ + release: cciss_scsi_release, \ + proc_info: cciss_scsi_proc_info, \ + queuecommand: cciss_scsi_queue_command, \ + bios_param: scsicam_bios_param, \ + can_queue: SCSI_CCISS_CAN_QUEUE, \ + this_id: SELF_SCSI_ID, \ + sg_tablesize: MAXSGENTRIES, \ + cmd_per_lun: 1, \ + use_new_eh_code: 1, \ + use_clustering: DISABLE_CLUSTERING,\ +} + +/* + info: cciss_scsi_info, \ + +Note, cmd_per_lun could give us some trouble, so I'm setting it very low. +Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively. + +If the upper scsi layer tries to track how many commands we have +outstanding, it will be operating under the misapprehension that it is +the only one sending us requests. We also have the block interface, +which is where most requests must surely come from, so the upper layer's +notion of how many requests we have outstanding will be wrong most or +all of the time. + +Note, the normal SCSI mid-layer error handling doesn't work well +for this driver because 1) it takes the io_request_lock before +calling error handlers and uses a local variable to store flags, +so the io_request_lock cannot be released and interrupts enabled +inside the error handlers, and, the error handlers cannot poll +for command completion because they might get commands from the +block half of the driver completing, and not know what to do +with them. That's what we get for making a hybrid scsi/block +driver, I suppose. + +*/ + +struct cciss_scsi_dev_t { + int devtype; + int bus, target, lun; /* as presented to the OS */ + unsigned char scsi3addr[8]; /* as presented to the HW */ +}; + +struct cciss_scsi_hba_t { + char *name; + int ndevices; +#define CCISS_MAX_SCSI_DEVS_PER_HBA 16 + struct cciss_scsi_dev_t dev[CCISS_MAX_SCSI_DEVS_PER_HBA]; +}; + +#endif /* _CCISS_SCSI_H_ */ +#endif /* CONFIG_CISS_SCSI_TAPE */ diff -urN linux-2.4.18/drivers/block/floppy.c linux-2.4.19-pre5/drivers/block/floppy.c --- linux-2.4.18/drivers/block/floppy.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/block/floppy.c Sat Mar 30 22:55:34 2002 @@ -129,6 +129,12 @@ * floppy controller (lingering task on list after module is gone... boom.) */ +/* + * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range + * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix + * requires many non-obvious changes in arch dependent code. + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -4181,9 +4187,12 @@ CLEARSTRUCT(FDCS); FDCS->dtr = -1; FDCS->dor = 0x4; -#ifdef __sparc__ - /*sparcs don't have a DOR reset which we can fall back on to*/ - FDCS->version = FDC_82072A; +#if defined(__sparc__) || defined(__mc68000__) + /*sparcs/sun3x don't have a DOR reset which we can fall back on to*/ +#ifdef __mc68000__ + if(MACH_IS_SUN3X) +#endif + FDCS->version = FDC_82072A; #endif } @@ -4229,7 +4238,7 @@ FDCS->rawcmd = 2; if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; FDCS->version = FDC_NONE; @@ -4239,7 +4248,7 @@ FDCS->version = get_fdc_version(); if (FDCS->version == FDC_NONE){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; continue; @@ -4318,11 +4327,11 @@ for (fdc=0; fdc< N_FDC; fdc++){ if (FDCS->address != -1){ - if (!request_region(FDCS->address, 6, "floppy")) { - DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address); + if (!request_region(FDCS->address+2, 4, "floppy")) { + DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 2); goto cleanup1; } - if (!request_region(FDCS->address + 7, 1, "floppy DIR")) { + if (!request_region(FDCS->address+7, 1, "floppy DIR")) { DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 7); goto cleanup2; } @@ -4350,12 +4359,12 @@ irqdma_allocated = 1; return 0; cleanup2: - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); cleanup1: fd_free_irq(); fd_free_dma(); while(--fdc >= 0) { - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); release_region(FDCS->address + 7, 1); } MOD_DEC_USE_COUNT; @@ -4422,7 +4431,7 @@ old_fdc = fdc; for (fdc = 0; fdc < N_FDC; fdc++) if (FDCS->address != -1) { - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); } fdc = old_fdc; diff -urN linux-2.4.18/drivers/block/ll_rw_blk.c linux-2.4.19-pre5/drivers/block/ll_rw_blk.c --- linux-2.4.18/drivers/block/ll_rw_blk.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/block/ll_rw_blk.c Sat Mar 30 22:55:39 2002 @@ -117,12 +117,6 @@ */ int * max_sectors[MAX_BLKDEV]; -/* - * How many reqeusts do we allocate per queue, - * and how many do we "batch" on freeing them? - */ -static int queue_nr_requests, batch_requests; - static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -176,7 +170,7 @@ **/ void blk_cleanup_queue(request_queue_t * q) { - int count = queue_nr_requests; + int count = q->nr_requests; count -= __blk_cleanup_queue(&q->rq[READ]); count -= __blk_cleanup_queue(&q->rq[WRITE]); @@ -326,33 +320,67 @@ spin_unlock_irqrestore(&io_request_lock, flags); } +/** blk_grow_request_list + * @q: The &request_queue_t + * @nr_requests: how many requests are desired + * + * More free requests are added to the queue's free lists, bringing + * the total number of requests to @nr_requests. + * + * The requests are added equally to the request queue's read + * and write freelists. + * + * This function can sleep. + * + * Returns the (new) number of requests which the queue has available. + */ +int blk_grow_request_list(request_queue_t *q, int nr_requests) +{ + spin_lock_irq(&io_request_lock); + while (q->nr_requests < nr_requests) { + struct request *rq; + int rw; + + spin_unlock_irq(&io_request_lock); + rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); + spin_lock_irq(&io_request_lock); + if (rq == NULL) + break; + memset(rq, 0, sizeof(*rq)); + rq->rq_status = RQ_INACTIVE; + rw = q->nr_requests & 1; + list_add(&rq->queue, &q->rq[rw].free); + q->rq[rw].count++; + q->nr_requests++; + } + q->batch_requests = q->nr_requests / 4; + if (q->batch_requests > 32) + q->batch_requests = 32; + spin_unlock_irq(&io_request_lock); + return q->nr_requests; +} + static void blk_init_free_list(request_queue_t *q) { - struct request *rq; - int i; + struct sysinfo si; + int megs; /* Total memory, in megabytes */ + int nr_requests; INIT_LIST_HEAD(&q->rq[READ].free); INIT_LIST_HEAD(&q->rq[WRITE].free); q->rq[READ].count = 0; q->rq[WRITE].count = 0; + q->nr_requests = 0; - /* - * Divide requests in half between read and write - */ - for (i = 0; i < queue_nr_requests; i++) { - rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); - if (rq == NULL) { - /* We'll get a `leaked requests' message from blk_cleanup_queue */ - printk(KERN_EMERG "blk_init_free_list: error allocating requests\n"); - break; - } - memset(rq, 0, sizeof(struct request)); - rq->rq_status = RQ_INACTIVE; - list_add(&rq->queue, &q->rq[i&1].free); - q->rq[i&1].count++; - } + si_meminfo(&si); + megs = si.totalram >> (20 - PAGE_SHIFT); + nr_requests = 128; + if (megs < 32) + nr_requests /= 2; + blk_grow_request_list(q, nr_requests); - init_waitqueue_head(&q->wait_for_request); + init_waitqueue_head(&q->wait_for_requests[0]); + init_waitqueue_head(&q->wait_for_requests[1]); spin_lock_init(&q->queue_lock); } @@ -418,9 +446,9 @@ #define blkdev_free_rq(list) list_entry((list)->next, struct request, queue); /* * Get a free request. io_request_lock must be held and interrupts - * disabled on the way in. + * disabled on the way in. Returns NULL if there are no free requests. */ -static inline struct request *get_request(request_queue_t *q, int rw) +static struct request *get_request(request_queue_t *q, int rw) { struct request *rq = NULL; struct request_list *rl = q->rq + rw; @@ -430,6 +458,7 @@ list_del(&rq->queue); rl->count--; rq->rq_status = RQ_ACTIVE; + rq->cmd = rw; rq->special = NULL; rq->q = q; } @@ -438,40 +467,84 @@ } /* - * No available requests for this queue, unplug the device. + * Here's the request allocation design: + * + * 1: Blocking on request exhaustion is a key part of I/O throttling. + * + * 2: We want to be `fair' to all requesters. We must avoid starvation, and + * attempt to ensure that all requesters sleep for a similar duration. Hence + * no stealing requests when there are other processes waiting. + * + * 3: We also wish to support `batching' of requests. So when a process is + * woken, we want to allow it to allocate a decent number of requests + * before it blocks again, so they can be nicely merged (this only really + * matters if the process happens to be adding requests near the head of + * the queue). + * + * 4: We want to avoid scheduling storms. This isn't really important, because + * the system will be I/O bound anyway. But it's easy. + * + * There is tension between requirements 2 and 3. Once a task has woken, + * we don't want to allow it to sleep as soon as it takes its second request. + * But we don't want currently-running tasks to steal all the requests + * from the sleepers. We handle this with wakeup hysteresis around + * 0 .. batch_requests and with the assumption that request taking is much, + * much faster than request freeing. + * + * So here's what we do: + * + * a) A READA requester fails if free_requests < batch_requests + * + * We don't want READA requests to prevent sleepers from ever + * waking. Note that READA is used extremely rarely - a few + * filesystems use it for directory readahead. + * + * When a process wants a new request: + * + * b) If free_requests == 0, the requester sleeps in FIFO manner. + * + * b) If 0 < free_requests < batch_requests and there are waiters, + * we still take a request non-blockingly. This provides batching. + * + * c) If free_requests >= batch_requests, the caller is immediately + * granted a new request. + * + * When a request is released: + * + * d) If free_requests < batch_requests, do nothing. + * + * f) If free_requests >= batch_requests, wake up a single waiter. + * + * The net effect is that when a process is woken at the batch_requests level, + * it will be able to take approximately (batch_requests) requests before + * blocking again (at the tail of the queue). + * + * This all assumes that the rate of taking requests is much, much higher + * than the rate of releasing them. Which is very true. + * + * -akpm, Feb 2002. */ + static struct request *__get_request_wait(request_queue_t *q, int rw) { register struct request *rq; DECLARE_WAITQUEUE(wait, current); generic_unplug_device(q); - add_wait_queue(&q->wait_for_request, &wait); + add_wait_queue_exclusive(&q->wait_for_requests[rw], &wait); do { set_current_state(TASK_UNINTERRUPTIBLE); - if (q->rq[rw].count < batch_requests) + if (q->rq[rw].count == 0) schedule(); spin_lock_irq(&io_request_lock); rq = get_request(q,rw); spin_unlock_irq(&io_request_lock); } while (rq == NULL); - remove_wait_queue(&q->wait_for_request, &wait); + remove_wait_queue(&q->wait_for_requests[rw], &wait); current->state = TASK_RUNNING; return rq; } -static inline struct request *get_request_wait(request_queue_t *q, int rw) -{ - register struct request *rq; - - spin_lock_irq(&io_request_lock); - rq = get_request(q, rw); - spin_unlock_irq(&io_request_lock); - if (rq) - return rq; - return __get_request_wait(q, rw); -} - /* RO fail safe mechanism */ static long ro_bits[MAX_BLKDEV][8]; @@ -546,7 +619,7 @@ /* * Must be called with io_request_lock held and interrupts disabled */ -inline void blkdev_release_request(struct request *req) +void blkdev_release_request(struct request *req) { request_queue_t *q = req->q; int rw = req->cmd; @@ -560,8 +633,9 @@ */ if (q) { list_add(&req->queue, &q->rq[rw].free); - if (++q->rq[rw].count >= batch_requests && waitqueue_active(&q->wait_for_request)) - wake_up(&q->wait_for_request); + if (++q->rq[rw].count >= q->batch_requests && + waitqueue_active(&q->wait_for_requests[rw])) + wake_up(&q->wait_for_requests[rw]); } } @@ -742,22 +816,30 @@ BUG(); } - /* - * Grab a free request from the freelist - if that is empty, check - * if we are doing read ahead and abort instead of blocking for - * a free slot. - */ get_rq: if (freereq) { req = freereq; freereq = NULL; - } else if ((req = get_request(q, rw)) == NULL) { - spin_unlock_irq(&io_request_lock); - if (rw_ahead) - goto end_io; - - freereq = __get_request_wait(q, rw); - goto again; + } else { + /* + * See description above __get_request_wait() + */ + if (rw_ahead) { + if (q->rq[rw].count < q->batch_requests) { + spin_unlock_irq(&io_request_lock); + goto end_io; + } + req = get_request(q, rw); + if (req == NULL) + BUG(); + } else { + req = get_request(q, rw); + if (req == NULL) { + spin_unlock_irq(&io_request_lock); + freereq = __get_request_wait(q, rw); + goto again; + } + } } /* fill up the request-info, and add it to the queue */ @@ -899,6 +981,7 @@ BUG(); set_bit(BH_Req, &bh->b_state); + set_bit(BH_Launder, &bh->b_state); /* * First step, 'identity mapping' - RAID or LVM might @@ -1090,12 +1173,9 @@ blkdev_release_request(req); } -#define MB(kb) ((kb) << 10) - int __init blk_dev_init(void) { struct blk_dev_struct *dev; - int total_ram; request_cachep = kmem_cache_create("blkdev_requests", sizeof(struct request), @@ -1111,22 +1191,6 @@ memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); - total_ram = nr_free_pages() << (PAGE_SHIFT - 10); - - /* - * Free request slots per queue. - * (Half for reads, half for writes) - */ - queue_nr_requests = 64; - if (total_ram > MB(32)) - queue_nr_requests = 128; - - /* - * Batch frees according to queue length - */ - batch_requests = queue_nr_requests/4; - printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); - #ifdef CONFIG_AMIGA_Z2RAM z2_init(); #endif @@ -1237,6 +1301,7 @@ EXPORT_SYMBOL(io_request_lock); EXPORT_SYMBOL(end_that_request_first); EXPORT_SYMBOL(end_that_request_last); +EXPORT_SYMBOL(blk_grow_request_list); EXPORT_SYMBOL(blk_init_queue); EXPORT_SYMBOL(blk_get_queue); EXPORT_SYMBOL(blk_cleanup_queue); diff -urN linux-2.4.18/drivers/block/loop.c linux-2.4.19-pre5/drivers/block/loop.c --- linux-2.4.18/drivers/block/loop.c Sun Dec 23 16:23:38 2001 +++ linux-2.4.19-pre5/drivers/block/loop.c Sat Mar 30 22:55:27 2002 @@ -36,6 +36,9 @@ * Al Viro too. * Jens Axboe , Nov 2000 * + * Support up to 256 loop devices + * Heinz Mauelshagen , Feb 2002 + * * Still To Fix: * - Advisory locking is ignored here. * - Should use an own CAP_* category instead of CAP_SYS_ADMIN @@ -965,7 +968,7 @@ * And now the modules code and kernel interface. */ MODULE_PARM(max_loop, "i"); -MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)"); +MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)"); MODULE_LICENSE("GPL"); int loop_register_transfer(struct loop_func_table *funcs) @@ -1001,9 +1004,9 @@ { int i; - if ((max_loop < 1) || (max_loop > 255)) { + if ((max_loop < 1) || (max_loop > 256)) { printk(KERN_WARNING "loop: invalid max_loop (must be between" - " 1 and 255), using default (8)\n"); + " 1 and 256), using default (8)\n"); max_loop = 8; } diff -urN linux-2.4.18/drivers/block/nbd.c linux-2.4.19-pre5/drivers/block/nbd.c --- linux-2.4.18/drivers/block/nbd.c Sun Dec 23 16:23:38 2001 +++ linux-2.4.19-pre5/drivers/block/nbd.c Sat Mar 30 22:55:27 2002 @@ -24,6 +24,8 @@ * 01-3-11 Make nbd work with new Linux block layer code. It now supports * plugging like all the other block devices. Also added in MSG_MORE to * reduce number of partial TCP segments sent. + * 01-12-6 Fix deadlock condition by making queue locks independant of + * the transmit lock. * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another @@ -146,11 +148,12 @@ #define FAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); goto error_out; } -void nbd_send_req(struct socket *sock, struct request *req) +void nbd_send_req(struct nbd_device *lo, struct request *req) { int result; struct nbd_request request; unsigned long size = req->nr_sectors << 9; + struct socket *sock = lo->sock; DEBUG("NBD: sending control, "); request.magic = htonl(NBD_REQUEST_MAGIC); @@ -159,6 +162,8 @@ request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); + down(&lo->tx_lock); + result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0); if (result <= 0) FAIL("Sendmsg failed for control."); @@ -173,30 +178,51 @@ bh = bh->b_reqnext; } while(bh); } + up(&lo->tx_lock); return; - error_out: +error_out: + up(&lo->tx_lock); req->errors++; } +static struct request *nbd_find_request(struct nbd_device *lo, char *handle) +{ + struct request *req; + struct list_head *tmp; + struct request *xreq; + + memcpy(&xreq, handle, sizeof(xreq)); + + spin_lock(&lo->queue_lock); + list_for_each(tmp, &lo->queue_head) { + req = list_entry(tmp, struct request, queue); + if (req != xreq) + continue; + list_del(&req->queue); + spin_unlock(&lo->queue_lock); + return req; + } + spin_unlock(&lo->queue_lock); + return NULL; +} + #define HARDFAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); lo->harderror = result; return NULL; } struct request *nbd_read_stat(struct nbd_device *lo) /* NULL returned = something went wrong, inform userspace */ { int result; struct nbd_reply reply; - struct request *xreq, *req; + struct request *req; DEBUG("reading control, "); reply.magic = 0; result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply), MSG_WAITALL); if (result <= 0) HARDFAIL("Recv control failed."); - memcpy(&xreq, reply.handle, sizeof(xreq)); - req = blkdev_entry_prev_request(&lo->queue_head); - - if (xreq != req) - FAIL("Unexpected handle received.\n"); + req = nbd_find_request(lo, reply.handle); + if (req == NULL) + HARDFAIL("Unexpected reply"); DEBUG("ok, "); if (ntohl(reply.magic) != NBD_REPLY_MAGIC) @@ -226,20 +252,14 @@ { struct request *req; - down (&lo->queue_lock); while (1) { - up (&lo->queue_lock); req = nbd_read_stat(lo); - down (&lo->queue_lock); if (!req) { printk(KERN_ALERT "req should never be null\n" ); goto out; } #ifdef PARANOIA - if (req != blkdev_entry_prev_request(&lo->queue_head)) { - printk(KERN_ALERT "NBD: I have problem...\n"); - } if (lo != &nbd_dev[MINOR(req->rq_dev)]) { printk(KERN_ALERT "NBD: request corrupted!\n"); continue; @@ -249,15 +269,11 @@ goto out; } #endif - list_del(&req->queue); - up (&lo->queue_lock); nbd_end_request(req); - down (&lo->queue_lock); } out: - up (&lo->queue_lock); } void nbd_clear_que(struct nbd_device *lo) @@ -270,27 +286,20 @@ return; } #endif - - while (!list_empty(&lo->queue_head)) { - req = blkdev_entry_prev_request(&lo->queue_head); -#ifdef PARANOIA - if (!req) { - printk( KERN_ALERT "NBD: panic, panic, panic\n" ); - break; + do { + req = NULL; + spin_lock(&lo->queue_lock); + if (!list_empty(&lo->queue_head)) { + req = list_entry(lo->queue_head.next, struct request, queue); + list_del(&req->queue); } - if (lo != &nbd_dev[MINOR(req->rq_dev)]) { - printk(KERN_ALERT "NBD: request corrupted when clearing!\n"); - continue; + spin_unlock(&lo->queue_lock); + if (req) { + req->errors++; + nbd_end_request(req); } -#endif - req->errors++; - list_del(&req->queue); - up(&lo->queue_lock); + } while(req); - nbd_end_request(req); - - down(&lo->queue_lock); - } } /* @@ -334,10 +343,11 @@ blkdev_dequeue_request(req); spin_unlock_irq(&io_request_lock); - down (&lo->queue_lock); - list_add(&req->queue, &lo->queue_head); - nbd_send_req(lo->sock, req); /* Why does this block? */ - up (&lo->queue_lock); + spin_lock(&lo->queue_lock); + list_add_tail(&req->queue, &lo->queue_head); + spin_unlock(&lo->queue_lock); + + nbd_send_req(lo, req); spin_lock_irq(&io_request_lock); continue; @@ -372,21 +382,21 @@ lo = &nbd_dev[dev]; switch (cmd) { case NBD_DISCONNECT: - printk("NBD_DISCONNECT\n") ; + printk("NBD_DISCONNECT\n"); sreq.cmd=2 ; /* shutdown command */ - if (!lo->sock) return -EINVAL ; - nbd_send_req(lo->sock,&sreq) ; + if (!lo->sock) return -EINVAL; + nbd_send_req(lo, &sreq); return 0 ; case NBD_CLEAR_SOCK: - down(&lo->queue_lock); nbd_clear_que(lo); + spin_lock(&lo->queue_lock); if (!list_empty(&lo->queue_head)) { - up(&lo->queue_lock); + spin_unlock(&lo->queue_lock); printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n"); return -EBUSY; } - up(&lo->queue_lock); + spin_unlock(&lo->queue_lock); file = lo->file; if (!file) return -EINVAL; @@ -507,8 +517,9 @@ nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; + spin_lock_init(&nbd_dev[i].queue_lock); INIT_LIST_HEAD(&nbd_dev[i].queue_head); - init_MUTEX(&nbd_dev[i].queue_lock); + init_MUTEX(&nbd_dev[i].tx_lock); nbd_blksizes[i] = 1024; nbd_blksize_bits[i] = 10; nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ diff -urN linux-2.4.18/drivers/block/rd.c linux-2.4.19-pre5/drivers/block/rd.c --- linux-2.4.18/drivers/block/rd.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/block/rd.c Sat Mar 30 22:55:39 2002 @@ -44,9 +44,6 @@ #include #include -#include -#include -#include #include #include #include @@ -79,18 +76,9 @@ /* The RAM disk size is now a parameter */ #define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ -#ifndef MODULE -/* We don't have to load RAM disks or gunzip them in a module. */ -#define RD_LOADER -#define BUILD_CRAMDISK - -void rd_load(void); -static int crd_load(struct file *fp, struct file *outfp); - #ifdef CONFIG_BLK_DEV_INITRD static int initrd_users; #endif -#endif /* Various static variables go here. Most are used only in the RAM disk code. */ @@ -354,7 +342,7 @@ sbh->b_end_io(sbh,1); return 0; fail: - sbh->b_end_io(sbh,0); + buffer_IO_error(sbh); return 0; } @@ -382,6 +370,7 @@ error = 0; } up(&inode->i_bdev->bd_sem); + invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ if (!arg) @@ -535,6 +524,8 @@ #ifdef CONFIG_BLK_DEV_INITRD /* We ought to separate initrd operations here */ register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &rd_bd_op, rd_size<<1); + devfs_register(devfs_handle, "initrd", DEVFS_FL_DEFAULT, MAJOR_NR, + INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL); #endif hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */ @@ -561,462 +552,3 @@ MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); MODULE_LICENSE("GPL"); - -/* End of non-loading portions of the RAM disk driver */ - -#ifdef RD_LOADER -/* - * This routine tries to find a RAM disk image to load, and returns the - * number of blocks to read for a non-compressed image, 0 if the image - * is a compressed image, and -1 if an image with the right magic - * numbers could not be found. - * - * We currently check for the following magic numbers: - * minix - * ext2 - * romfs - * gzip - */ -static int __init -identify_ramdisk_image(kdev_t device, struct file *fp, int start_block) -{ - const int size = 512; - struct minix_super_block *minixsb; - struct ext2_super_block *ext2sb; - struct romfs_super_block *romfsb; - int nblocks = -1; - unsigned char *buf; - - buf = kmalloc(size, GFP_KERNEL); - if (buf == 0) - return -1; - - minixsb = (struct minix_super_block *) buf; - ext2sb = (struct ext2_super_block *) buf; - romfsb = (struct romfs_super_block *) buf; - memset(buf, 0xe5, size); - - /* - * Read block 0 to test for gzipped kernel - */ - if (fp->f_op->llseek) - fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); - fp->f_pos = start_block * BLOCK_SIZE; - - fp->f_op->read(fp, buf, size, &fp->f_pos); - - /* - * If it matches the gzip magic numbers, return -1 - */ - if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { - printk(KERN_NOTICE - "RAMDISK: Compressed image found at block %d\n", - start_block); - nblocks = 0; - goto done; - } - - /* romfs is at block zero too */ - if (romfsb->word0 == ROMSB_WORD0 && - romfsb->word1 == ROMSB_WORD1) { - printk(KERN_NOTICE - "RAMDISK: romfs filesystem found at block %d\n", - start_block); - nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; - goto done; - } - - /* - * Read block 1 to test for minix and ext2 superblock - */ - if (fp->f_op->llseek) - fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0); - fp->f_pos = (start_block+1) * BLOCK_SIZE; - - fp->f_op->read(fp, buf, size, &fp->f_pos); - - /* Try minix */ - if (minixsb->s_magic == MINIX_SUPER_MAGIC || - minixsb->s_magic == MINIX_SUPER_MAGIC2) { - printk(KERN_NOTICE - "RAMDISK: Minix filesystem found at block %d\n", - start_block); - nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; - goto done; - } - - /* Try ext2 */ - if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { - printk(KERN_NOTICE - "RAMDISK: ext2 filesystem found at block %d\n", - start_block); - nblocks = le32_to_cpu(ext2sb->s_blocks_count); - goto done; - } - - printk(KERN_NOTICE - "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", - start_block); - -done: - if (fp->f_op->llseek) - fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); - fp->f_pos = start_block * BLOCK_SIZE; - - kfree(buf); - return nblocks; -} - -/* - * This routine loads in the RAM disk image. - */ -static void __init rd_load_image(kdev_t device, int offset, int unit) -{ - struct inode *inode, *out_inode; - struct file infile, outfile; - struct dentry in_dentry, out_dentry; - mm_segment_t fs; - kdev_t ram_device; - int nblocks, i; - char *buf; - unsigned short rotate = 0; - unsigned short devblocks = 0; -#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) - char rotator[4] = { '|' , '/' , '-' , '\\' }; -#endif - ram_device = MKDEV(MAJOR_NR, unit); - - if ((inode = get_empty_inode()) == NULL) - return; - memset(&infile, 0, sizeof(infile)); - memset(&in_dentry, 0, sizeof(in_dentry)); - infile.f_mode = 1; /* read only */ - infile.f_dentry = &in_dentry; - in_dentry.d_inode = inode; - infile.f_op = &def_blk_fops; - init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device)); - - if ((out_inode = get_empty_inode()) == NULL) - goto free_inode; - memset(&outfile, 0, sizeof(outfile)); - memset(&out_dentry, 0, sizeof(out_dentry)); - outfile.f_mode = 3; /* read/write */ - outfile.f_dentry = &out_dentry; - out_dentry.d_inode = out_inode; - outfile.f_op = &def_blk_fops; - init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device)); - - if (blkdev_open(inode, &infile) != 0) { - iput(out_inode); - goto free_inode; - } - if (blkdev_open(out_inode, &outfile) != 0) - goto free_inodes; - - fs = get_fs(); - set_fs(KERNEL_DS); - - nblocks = identify_ramdisk_image(device, &infile, offset); - if (nblocks < 0) - goto done; - - if (nblocks == 0) { -#ifdef BUILD_CRAMDISK - if (crd_load(&infile, &outfile) == 0) - goto successful_load; -#else - printk(KERN_NOTICE - "RAMDISK: Kernel does not support compressed " - "RAM disk images\n"); -#endif - goto done; - } - - /* - * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so - * rd_load_image will work only with filesystem BLOCK_SIZE wide! - * So make sure to use 1k blocksize while generating ext2fs - * ramdisk-images. - */ - if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) { - printk("RAMDISK: image too big! (%d/%ld blocks)\n", - nblocks, rd_length[unit] >> BLOCK_SIZE_BITS); - goto done; - } - - /* - * OK, time to copy in the data - */ - buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); - if (buf == 0) { - printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); - goto done; - } - - if (blk_size[MAJOR(device)]) - devblocks = blk_size[MAJOR(device)][MINOR(device)]; - -#ifdef CONFIG_BLK_DEV_INITRD - if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR) - devblocks = nblocks; -#endif - - if (devblocks == 0) { - printk(KERN_ERR "RAMDISK: could not determine device size\n"); - goto done; - } - - printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", - nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); - for (i=0; i < nblocks; i++) { - if (i && (i % devblocks == 0)) { - printk("done disk #%d.\n", i/devblocks); - rotate = 0; - if (infile.f_op->release(inode, &infile) != 0) { - printk("Error closing the disk.\n"); - goto noclose_input; - } - printk("Please insert disk #%d and press ENTER\n", i/devblocks+1); - wait_for_keypress(); - if (blkdev_open(inode, &infile) != 0) { - printk("Error opening disk.\n"); - goto noclose_input; - } - infile.f_pos = 0; - printk("Loading disk #%d... ", i/devblocks+1); - } - infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); - outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); -#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) - if (!(i % 16)) { - printk("%c\b", rotator[rotate & 0x3]); - rotate++; - } -#endif - } - printk("done.\n"); - kfree(buf); - -successful_load: - ROOT_DEV = MKDEV(MAJOR_NR, unit); - if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0"); - -done: - infile.f_op->release(inode, &infile); -noclose_input: - blkdev_close(out_inode, &outfile); - iput(inode); - iput(out_inode); - set_fs(fs); - return; -free_inodes: /* free inodes on error */ - iput(out_inode); - infile.f_op->release(inode, &infile); -free_inode: - iput(inode); -} - -#ifdef CONFIG_MAC_FLOPPY -int swim3_fd_eject(int devnum); -#endif - -static void __init rd_load_disk(int n) -{ - - if (rd_doload == 0) - return; - - if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR -#ifdef CONFIG_BLK_DEV_INITRD - && MAJOR(real_root_dev) != FLOPPY_MAJOR -#endif - ) - return; - - if (rd_prompt) { -#ifdef CONFIG_BLK_DEV_FD - floppy_eject(); -#endif -#ifdef CONFIG_MAC_FLOPPY - if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) - swim3_fd_eject(MINOR(ROOT_DEV)); - else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) - swim3_fd_eject(MINOR(real_root_dev)); -#endif - printk(KERN_NOTICE - "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); - wait_for_keypress(); - } - - rd_load_image(ROOT_DEV,rd_image_start, n); - -} - -void __init rd_load(void) -{ - rd_load_disk(0); -} - -void __init rd_load_secondary(void) -{ - rd_load_disk(1); -} - -#ifdef CONFIG_BLK_DEV_INITRD -void __init initrd_load(void) -{ - rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0); -} -#endif - -#endif /* RD_LOADER */ - -#ifdef BUILD_CRAMDISK - -/* - * gzip declarations - */ - -#define OF(args) args - -#ifndef memzero -#define memzero(s, n) memset ((s), 0, (n)) -#endif - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -#define INBUFSIZ 4096 -#define WSIZE 0x8000 /* window size--must be a power of two, and */ - /* at least 32K for zip's deflate method */ - -static uch *inbuf; -static uch *window; - -static unsigned insize; /* valid bytes in inbuf */ -static unsigned inptr; /* index of next byte to be processed in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ -static int exit_code; -static long bytes_out; -static struct file *crd_infp, *crd_outfp; - -#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) - -/* Diagnostic functions (stubbed out) */ -#define Assert(cond,msg) -#define Trace(x) -#define Tracev(x) -#define Tracevv(x) -#define Tracec(c,x) -#define Tracecv(c,x) - -#define STATIC static - -static int fill_inbuf(void); -static void flush_window(void); -static void *malloc(int size); -static void free(void *where); -static void error(char *m); -static void gzip_mark(void **); -static void gzip_release(void **); - -#include "../../lib/inflate.c" - -static void __init *malloc(int size) -{ - return kmalloc(size, GFP_KERNEL); -} - -static void __init free(void *where) -{ - kfree(where); -} - -static void __init gzip_mark(void **ptr) -{ -} - -static void __init gzip_release(void **ptr) -{ -} - - -/* =========================================================================== - * Fill the input buffer. This is called only when the buffer is empty - * and at least one byte is really needed. - */ -static int __init fill_inbuf(void) -{ - if (exit_code) return -1; - - insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ, - &crd_infp->f_pos); - if (insize == 0) return -1; - - inptr = 1; - - return inbuf[0]; -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void __init flush_window(void) -{ - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, ch; - - crd_outfp->f_op->write(crd_outfp, window, outcnt, &crd_outfp->f_pos); - in = window; - for (n = 0; n < outcnt; n++) { - ch = *in++; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - outcnt = 0; -} - -static void __init error(char *x) -{ - printk(KERN_ERR "%s", x); - exit_code = 1; -} - -static int __init -crd_load(struct file * fp, struct file *outfp) -{ - int result; - - insize = 0; /* valid bytes in inbuf */ - inptr = 0; /* index of next byte to be processed in inbuf */ - outcnt = 0; /* bytes in output buffer */ - exit_code = 0; - bytes_out = 0; - crc = (ulg)0xffffffffL; /* shift register contents */ - - crd_infp = fp; - crd_outfp = outfp; - inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); - if (inbuf == 0) { - printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); - return -1; - } - window = kmalloc(WSIZE, GFP_KERNEL); - if (window == 0) { - printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); - kfree(inbuf); - return -1; - } - makecrc(); - result = gunzip(); - kfree(inbuf); - kfree(window); - return result; -} - -#endif /* BUILD_CRAMDISK */ - diff -urN linux-2.4.18/drivers/block/xd.c linux-2.4.19-pre5/drivers/block/xd.c --- linux-2.4.18/drivers/block/xd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/xd.c Sat Mar 30 22:55:39 2002 @@ -107,6 +107,8 @@ { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */ + { 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" }, + { 0x0008,"(C) Copyright 1986 Western Digital Corporation", xd_wd_init_controller, xd_wd_init_drive," 1986 Western Digital" }, /* jfree@sovereign.org */ }; static unsigned int xd_bases[] __initdata = diff -urN linux-2.4.18/drivers/block/z2ram.c linux-2.4.19-pre5/drivers/block/z2ram.c --- linux-2.4.18/drivers/block/z2ram.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/block/z2ram.c Sat Mar 30 22:55:34 2002 @@ -38,7 +38,7 @@ #include #include #include -#include + #include @@ -207,7 +207,7 @@ _PAGE_WRITETHRU); #else - vaddr = (unsigned long)ioremap(paddr, size); + vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); #endif z2ram_map = kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.c linux-2.4.19-pre5/drivers/bluetooth/hci_vhci.c --- linux-2.4.18/drivers/bluetooth/hci_vhci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/bluetooth/hci_vhci.c Sat Mar 30 22:55:34 2002 @@ -221,11 +221,6 @@ return ret; } -static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin) -{ - return -ESPIPE; -} - static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -296,7 +291,7 @@ static struct file_operations hci_vhci_fops = { owner: THIS_MODULE, - llseek: hci_vhci_chr_lseek, + llseek: no_llseek, read: hci_vhci_chr_read, write: hci_vhci_chr_write, poll: hci_vhci_chr_poll, diff -urN linux-2.4.18/drivers/char/Config.in linux-2.4.19-pre5/drivers/char/Config.in --- linux-2.4.18/drivers/char/Config.in Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/Config.in Sat Mar 30 22:55:39 2002 @@ -63,6 +63,41 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi if [ "$CONFIG_MIPS" = "y" ]; then + bool ' TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 + dep_bool ' Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 + bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART + if [ "$CONFIG_AU1000_UART" = "y" ]; then + bool ' Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE + fi + bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL + if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then + bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE + fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART + if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then + bool ' Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE + if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + fi + int ' Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024 + bool ' Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + fi + fi + fi +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then + tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 +fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi + if [ "$CONFIG_MIPS" = "y" ]; then bool ' TMPTX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 dep_bool ' Console on TMPTX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART @@ -71,7 +106,7 @@ fi fi fi -if [ "$CONFIG_IT8712" = "y" ]; then +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then define_bool CONFIG_IT8172_CIR y @@ -81,17 +116,12 @@ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 fi -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then - tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 -fi -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'DC21285 serial port support' CONFIG_SERIAL_21285 - if [ "$CONFIG_SERIAL_21285" = "y" ]; then - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD - fi - bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE +if [ "$CONFIG_MIPS_IVR" = "y" ]; then + bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y fi + bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -124,6 +154,7 @@ bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD + tristate ' MK712 touch screen support' CONFIG_MK712_MOUSE fi endmenu @@ -171,6 +202,9 @@ tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT + if [ "$CONFIG_SGI_IP22" = "y" ]; then + tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG + fi fi endmenu @@ -183,6 +217,7 @@ tristate 'NetWinder flash support' CONFIG_NWFLASH fi +dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC @@ -210,7 +245,7 @@ dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP if [ "$CONFIG_AGP" != "n" ]; then - bool ' Intel 440LX/BX/GX and I815/I830M/I840/I850 support' CONFIG_AGP_INTEL + bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810 bool ' VIA chipset support' CONFIG_AGP_VIA bool ' AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD @@ -235,9 +270,11 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/char/pcmcia/Config.in fi - -if [ "$CONFIG_X86" = "y" ]; then - tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then + tristate ' Alchemy Au1000 GPIO device support' CONFIG_AU1000_GPIO + tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1000_ADS7846 +fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + tristate ' ITE GPIO' CONFIG_ITE_GPIO fi - endmenu diff -urN linux-2.4.18/drivers/char/Makefile linux-2.4.19-pre5/drivers/char/Makefile --- linux-2.4.18/drivers/char/Makefile Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/Makefile Sat Mar 30 22:55:39 2002 @@ -23,7 +23,8 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - sonypi.o tty_io.o tty_ioctl.o generic_serial.o + sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ + au1000_gpio.o mod-subdirs := joystick ftape drm drm-4.0 pcmcia @@ -58,11 +59,18 @@ ifdef CONFIG_AMIGA KEYBD = amikeyb.o else - KEYBD = + ifndef CONFIG_MAC + KEYBD = + endif endif SERIAL = endif +ifdef CONFIG_Q40 + KEYBD += q40_keyb.o + SERIAL = serial.o +endif + ifeq ($(ARCH),arm) ifneq ($(CONFIG_PC_KEYMAP),y) KEYMAP = @@ -124,12 +132,17 @@ KEYMAP = qtronixmap.o endif +ifeq ($(CONFIG_DUMMY_KEYB),y) + KEYBD = dummy_keyb.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_ACPI) += acpi_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +obj-$(CONFIG_TS_AU1000_ADS7846) += au1000_ts.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) @@ -147,6 +160,7 @@ obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o @@ -164,6 +178,7 @@ obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o subdir-$(CONFIG_RIO) += rio subdir-$(CONFIG_INPUT) += joystick @@ -187,6 +202,7 @@ obj-$(CONFIG_ATARIMOUSE) += atarimouse.o obj-$(CONFIG_ADBMOUSE) += adbmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o +obj-$(CONFIG_MK712_MOUSE) += mk712.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) @@ -196,6 +212,11 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o +obj-$(CONFIG_AMD_RNG) += amd768_rng.o + +obj-$(CONFIG_ITE_GPIO) += ite_gpio.o +obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o +obj-$(CONFIG_COBALT_LCD) += lcd.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o @@ -226,6 +247,8 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_WDTPCI) += wdt_pci.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o @@ -234,6 +257,10 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o subdir-$(CONFIG_MWAVE) += mwave diff -urN linux-2.4.18/drivers/char/acquirewdt.c linux-2.4.19-pre5/drivers/char/acquirewdt.c --- linux-2.4.18/drivers/char/acquirewdt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/acquirewdt.c Sat Mar 30 22:55:34 2002 @@ -209,7 +209,8 @@ printk("WDT driver for Acquire single board computer initialising.\n"); spin_lock_init(&acq_lock); - misc_register(&acq_miscdev); + if (misc_register(&acq_miscdev)) + return -ENODEV; request_region(WDT_STOP, 1, "Acquire WDT"); request_region(WDT_START, 1, "Acquire WDT"); register_reboot_notifier(&acq_notifier); diff -urN linux-2.4.18/drivers/char/agp/agpgart_be.c linux-2.4.19-pre5/drivers/char/agp/agpgart_be.c --- linux-2.4.18/drivers/char/agp/agpgart_be.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/agp/agpgart_be.c Sat Mar 30 22:55:27 2002 @@ -410,34 +410,8 @@ */ - pci_for_each_dev(device) - { - /* - * Enable AGP devices. Most will be VGA display but - * some may be coprocessors on non VGA devices too - */ - - if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && - (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) - continue; - - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) { /* * Ok, here we have a AGP device. Disable impossible @@ -506,25 +480,8 @@ * command registers. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) pci_write_config_dword(device, cap_ptr + 8, command); } @@ -622,7 +579,7 @@ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - set_bit(PG_reserved, &page->flags); + SetPageReserved(page); agp_bridge.gatt_table_real = (unsigned long *) table; CACHE_FLUSH(); @@ -632,7 +589,7 @@ if (agp_bridge.gatt_table == NULL) { for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - clear_bit(PG_reserved, &page->flags); + ClearPageReserved(page); free_pages((unsigned long) table, page_order); @@ -699,7 +656,7 @@ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - clear_bit(PG_reserved, &page->flags); + ClearPageReserved(page); free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); return 0; @@ -812,8 +769,8 @@ if (page == NULL) { return 0; } - atomic_inc(&page->count); - set_bit(PG_locked, &page->flags); + get_page(page); + LockPage(page); atomic_inc(&agp_bridge.current_memory_agp); return (unsigned long)page_address(page); } @@ -828,9 +785,8 @@ } page = virt_to_page(pt); - atomic_dec(&page->count); - clear_bit(PG_locked, &page->flags); - wake_up(&page->wait); + put_page(page); + UnlockPage(page); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -2285,13 +2241,12 @@ if (page_map->real == NULL) { return -ENOMEM; } - set_bit(PG_reserved, &virt_to_page(page_map->real)->flags); + SetPageReserved(virt_to_page(page_map->real)); CACHE_FLUSH(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); page_map->real = NULL; return -ENOMEM; @@ -2308,8 +2263,7 @@ static void amd_free_page_map(amd_page_map *page_map) { iounmap(page_map->remapped); - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); } @@ -2797,8 +2751,8 @@ if (page == NULL) return 0; - atomic_inc(&page->count); - set_bit(PG_locked, &page->flags); + get_page(page); + LockPage(page); atomic_inc(&agp_bridge.current_memory_agp); global_cache_flush(); @@ -2833,9 +2787,8 @@ } page = virt_to_page(pt); - atomic_dec(&page->count); - clear_bit(PG_locked, &page->flags); - wake_up(&page->wait); + put_page(page); + UnlockPage(page); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -2917,13 +2870,12 @@ if (page_map->real == NULL) { return -ENOMEM; } - set_bit(PG_reserved, &virt_to_page(page_map->real)->flags); + SetPageReserved(virt_to_page(page_map->real)); CACHE_FLUSH(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); page_map->real = NULL; return -ENOMEM; @@ -2940,8 +2892,7 @@ static void serverworks_free_page_map(serverworks_page_map *page_map) { iounmap(page_map->remapped); - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); } @@ -3331,24 +3282,8 @@ */ - pci_for_each_dev(device) - { - /* - * Enable AGP devices. Most will be VGA display but - * some may be coprocessors on non VGA devices too - */ - - if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && - (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) - continue; - - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) { do { pci_read_config_dword(device, @@ -3426,25 +3361,8 @@ * command registers. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) pci_write_config_dword(device, cap_ptr + 8, command); } @@ -4042,20 +3960,7 @@ #endif /* CONFIG_AGP_SWORKS */ /* find capndx */ - pci_read_config_dword(dev, 0x04, &scratch); - if (!(scratch & 0x00100000)) - return -ENODEV; - - pci_read_config_byte(dev, 0x34, &cap_ptr); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(dev, cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); if (cap_ptr == 0x00) return -ENODEV; agp_bridge.capndx = cap_ptr; diff -urN linux-2.4.18/drivers/char/alim7101_wdt.c linux-2.4.19-pre5/drivers/char/alim7101_wdt.c --- linux-2.4.18/drivers/char/alim7101_wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/alim7101_wdt.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,335 @@ +/* + * ALi M7101 PMU Computer Watchdog Timer driver for Linux 2.4.x + * + * Based on w83877f_wdt.c by Scott Jennings + * and the Cobalt kernel WDT timer driver by Tim Hockin + * + * + * (c)2002 Steve Hill + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "alim7101_wdt" + +#define WDT_ENABLE 0x9C +#define WDT_DISABLE 0x8C + +#define ALI_7101_WDT 0x92 +#define ALI_WDT_ARM 0x01 + +/* + * We're going to use a 1 second timeout. + * If we reset the watchdog every ~250ms we should be safe. */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static int wdt_expect_close; +static struct pci_dev *alim7101_pmu; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + char tmp; + + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT (this is actually a disarm/arm sequence) */ + pci_read_config_byte(alim7101_pmu, 0x92, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); +} + +/* + * Utility routines + */ + +static void wdt_change(int writeval) +{ + char tmp; + + pci_read_config_byte(alim7101_pmu, 0x92, &tmp); + if (writeval == WDT_ENABLE) + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + else + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* We must enable before we kick off the timer in case the timer + occurs as we ping it */ + + wdt_change(WDT_ENABLE); + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer_sync(&timer); + wdt_change(WDT_DISABLE); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* someone wrote to us, we should restart timer */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + }; + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + /* Good, fire up the show */ + wdt_startup(); + return 0; +} + +static int fop_close(struct inode * inode, struct file * file) +{ +#ifdef CONFIG_WDT_NOWAYOUT + if(wdt_expect_close) + wdt_turnoff(); + else { + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } +#else + wdt_turnoff(); +#endif + clear_bit(0, &wdt_is_open); + return 0; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "ALiM7101" + }; + + switch(cmd) + { + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + default: + return -ENOTTY; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: fop_read, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) wdt_turnoff(); + if (code==SYS_RESTART) { + /* + * Cobalt devices have no way of rebooting themselves other than + * getting the watchdog to pull reset, so we restart the watchdog on + * reboot with no heartbeat + */ + wdt_change(WDT_ENABLE); + printk(OUR_NAME ": Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n"); + }; + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit alim7101_wdt_unload(void) +{ + wdt_turnoff(); + /* Deregister */ + misc_deregister(&wdt_miscdev); + unregister_reboot_notifier(&wdt_notifier); +} + +static int __init alim7101_wdt_init(void) +{ + int rc = -EBUSY; + struct pci_dev *ali1543_south; + char tmp; + + printk(KERN_INFO OUR_NAME ": Steve Hill .\n"); + alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL); + if (!alim7101_pmu) { + printk(KERN_INFO OUR_NAME ": ALi M7101 PMU not present - WDT not set\n"); + return -EBUSY; + }; + + /* Set the WDT in the PMU to 1 second */ + pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02); + + ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + if (!ali1543_south) { + printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge not present - WDT not set\n"); + return -EBUSY; + }; + pci_read_config_byte(ali1543_south, 0x5e, &tmp); + if ((tmp & 0x1e) != 0x12) { + printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); + return -EBUSY; + }; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 1; + + rc = misc_register(&wdt_miscdev); + if (rc) + return rc; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) { + misc_deregister(&wdt_miscdev); + return rc; + }; + + printk(KERN_INFO OUR_NAME ": WDT driver for ALi M7101 initialised.\n"); + return 0; +} + +module_init(alim7101_wdt_init); +module_exit(alim7101_wdt_unload); + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Steve Hill"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/char/amd768_rng.c linux-2.4.19-pre5/drivers/char/amd768_rng.c --- linux-2.4.18/drivers/char/amd768_rng.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/amd768_rng.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,295 @@ +/* + Hardware driver for the AMD 768 Random Number Generator (RNG) + (c) Copyright 2001 Red Hat Inc + + derived from + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + + Please read Documentation/i810_rng.txt for details on use. + + ---------------------------------------------------------- + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "0.1.0" +#define RNG_MODULE_NAME "amd768_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#undef RNG_NDEBUG /* define to disable lightweight runtime checks */ +#ifdef RNG_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 RNG_MISCDEV_MINOR 183 /* official */ + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ + +static u32 pmbase; /* PMxx I/O base */ +static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ + + +/* + * inlined helper functions for accessing RNG registers + */ + +static inline int rng_data_present (void) +{ + return inl(pmbase+0xF4) & 1; +} + + +static inline int rng_data_read (void) +{ + return inl(pmbase+0xF0); +} + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + if ((filp->f_mode & FMODE_READ) == 0) + return -EINVAL; + if (filp->f_mode & FMODE_WRITE) + return -EINVAL; + + /* wait for device to become free */ + if (filp->f_flags & O_NONBLOCK) { + if (down_trylock (&rng_open_sem)) + return -EAGAIN; + } else { + if (down_interruptible (&rng_open_sem)) + return -ERESTARTSYS; + } + return 0; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + up(&rng_open_sem); + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, + loff_t * offp) +{ + static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; + int have_data; + u32 data = 0; + ssize_t ret = 0; + + while (size) { + spin_lock(&rng_lock); + + have_data = 0; + if (rng_data_present()) { + data = rng_data_read(); + have_data = 4; + } + + spin_unlock (&rng_lock); + + while (have_data > 0) { + if (put_user((u8)data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data>>=8; + } + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + if(current->need_resched) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + else + udelay(200); /* FIXME: We could poll for 250uS ?? */ + + if (signal_pending (current)) + return ret ? : -ERESTARTSYS; + } + return ret; +} + + +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev) +{ + int rc; + u8 rnen; + + DPRINTK ("ENTER\n"); + + rc = misc_register (&rng_miscdev); + if (rc) { + printk (KERN_ERR PFX "cannot register misc device\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out; + } + + pci_read_config_dword(dev, 0x58, &pmbase); + + pmbase&=0x0000FF00; + + if(pmbase == 0) + { + printk (KERN_ERR PFX "power management base not set\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out_free_miscdev; + } + + pci_read_config_byte(dev, 0x40, &rnen); + rnen|=(1<<7); /* RNG on */ + pci_write_config_byte(dev, 0x40, rnen); + + pci_read_config_byte(dev, 0x41, &rnen); + rnen|=(1<<7); /* PMIO enable */ + pci_write_config_byte(dev, 0x41, rnen); + + printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase); + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out_free_miscdev: + misc_deregister (&rng_miscdev); +err_out: + return rc; +} + + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + + +MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek"); +MODULE_DESCRIPTION("AMD 768 Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL"); + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + init_MUTEX (&rng_open_sem); + + pci_for_each_dev(pdev) { + if (pci_match_device (rng_pci_tbl, pdev) != NULL) + goto match; + } + + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + +match: + rc = rng_init_one (pdev); + if (rc) + return rc; + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + DPRINTK ("ENTER\n"); + misc_deregister (&rng_miscdev); + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); diff -urN linux-2.4.18/drivers/char/amiserial.c linux-2.4.19-pre5/drivers/char/amiserial.c --- linux-2.4.18/drivers/char/amiserial.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/amiserial.c Sat Mar 30 22:55:34 2002 @@ -89,7 +89,7 @@ #include #include -#include + #include #include diff -urN linux-2.4.18/drivers/char/applicom.c linux-2.4.19-pre5/drivers/char/applicom.c --- linux-2.4.18/drivers/char/applicom.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/applicom.c Sat Mar 30 22:55:27 2002 @@ -36,7 +36,7 @@ #if LINUX_VERSION_CODE < 0x20300 /* These probably want adding to */ -#define init_waitqueue_head(x) do { *(x) = NULL; } while (0); +#define init_waitqueue_head(x) do { *(x) = NULL; } while (0) #define PCI_BASE_ADDRESS(dev) (dev->base_address[0]) #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x #define __setup(x,y) /* */ diff -urN linux-2.4.18/drivers/char/au1000_gpio.c linux-2.4.19-pre5/drivers/char/au1000_gpio.c --- linux-2.4.18/drivers/char/au1000_gpio.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/au1000_gpio.c Sat Mar 30 22:55:27 2002 @@ -0,0 +1,270 @@ +/* + * FILE NAME au1000_gpio.c + * + * BRIEF MODULE DESCRIPTION + * Driver for Alchemy Au1000 GPIO. + * + * Author: MontaVista Software, Inc. + * Steve Longerbeam + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.01" + +static const struct { + u32 active_hi; + u32 avail_mask; +} pinfunc_to_avail[15] = { + {1, 0x7<<16}, // 0 = SSI0 / GPIO[18:16] + {-1, 0}, // 1 = AC97 / SSI1 + {1, 1<<19}, // 2 = IRDA / GPIO19 + {1, 1<<20}, // 3 = UART0 / GPIO20 + {1, 0x1f<<24}, // 4 = NIC2 / GPIO[28:24] + {1, 0x7<<29}, // 5 = I2S / GPIO[31:29] + {0, 1<<8}, // 6 = I2SDI / GPIO8 + {0, 0x3f<<9}, // 7 = UART3 / GPIO[14:9] + {0, 1<<15}, // 8 = IRFIRSEL / GPIO15 + {0, 1<<2}, // 9 = EXTCLK0 or OSC / GPIO2 + {0, 1<<3}, // 10 = EXTCLK1 / GPIO3 + {0, 1<<6}, // 11 = SMROMCKE / GPIO6 + {1, 1<<21}, // 12 = UART1 / GPIO21 + {1, 1<<22}, // 13 = UART2 / GPIO22 + {1, 1<<23} // 14 = UART3 / GPIO23 +}; + + +u32 get_au1000_avail_gpio_mask(void) +{ + int i; + u32 pinfunc = inl(SYS_PINFUNC); + u32 avail_mask = 0; // start with no gpio available + + // first, check for GPIO's reprogrammed as peripheral pins + for (i=0; i<15; i++) { + if (pinfunc_to_avail[i].active_hi < 0) + continue; + if (!(pinfunc_to_avail[i].active_hi ^ + ((pinfunc & (1< +#include + +#include +#include +#include +#include +#include +#include /* request_region */ +#include /* mark_bh */ +#include /* get_user,copy_to_user */ +#include +#include + +#define TS_NAME "au1000-ts" +#define TS_MAJOR 11 + +#define PFX TS_NAME +#define AU1000_TS_DEBUG 1 + +#ifdef AU1000_TS_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) + + +// SSI Status register bit defines +#define SSISTAT_BF (1<<4) +#define SSISTAT_OF (1<<3) +#define SSISTAT_UF (1<<2) +#define SSISTAT_DONE (1<<1) +#define SSISTAT_BUSY (1<<0) + +// SSI Interrupt Pending and Enable register bit defines +#define SSIINT_OI (1<<3) +#define SSIINT_UI (1<<2) +#define SSIINT_DI (1<<1) + +// SSI Address/Data register bit defines +#define SSIADAT_D (1<<24) +#define SSIADAT_ADDR_BIT 16 +#define SSIADAT_ADDR_MASK (0xff<pressure_eqn == PRESSURE_EQN_2) { + Rt = (ts->x_plate_ohms * ts->x_raw * + (4096 - ts->z1_raw)) / ts->z1_raw; + Rt -= (ts->y_plate_ohms * ts->y_raw); + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } else { + Rt = (ts->x_plate_ohms * ts->x_raw * + (ts->z2_raw - ts->z1_raw)) / ts->z1_raw; + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } + + // hysteresis + if (!ts->pendown && Rt > ts->pendown_thresh_ohms) + ts->pendown = 1; + else if (ts->pendown && Rt < ts->penup_thresh_ohms) + ts->pendown = 0; + + if (ts->pendown) { + // Pen is down + // Calculate calibrated X,Y + Xcal = ((ts->cal.xscale * ts->x_raw) >> 8) + ts->cal.xtrans; + Ycal = ((ts->cal.yscale * ts->y_raw) >> 8) + ts->cal.ytrans; + + event.x = (unsigned short)Xcal; + event.y = (unsigned short)Ycal; + event.pressure = (unsigned short)Rt; + + // add this event to the event queue + spin_lock_irqsave(&ts->lock, flags); + ts->event_buf[ts->nextIn++] = event; + if (ts->nextIn == EVENT_BUFSIZE) + ts->nextIn = 0; + if (ts->event_count < EVENT_BUFSIZE) { + ts->event_count++; + } else { + // throw out the oldest event + if (++ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + } + spin_unlock_irqrestore(&ts->lock, flags); + + // async notify + if (ts->fasync) + kill_fasync(&ts->fasync, SIGIO, POLL_IN); + // wake up any read call + if (waitqueue_active(&ts->wait)) + wake_up_interruptible(&ts->wait); + } +} + + +/* + * Raw X,Y,pressure acquisition timer function. This triggers + * the start of a new acquisition. Its duration between calls + * is the touch screen polling rate. + */ +static void +au1000_acq_timer(unsigned long data) +{ + au1000_ts_t* ts = (au1000_ts_t*)data; + unsigned long flags; + + spin_lock_irqsave(&ts->lock, flags); + + // start acquisition with X coordinate + ts->acq_state = ACQ_X; + // start me up + outl(SSIADAT_D | (MEASURE_12BIT_X << SSIADAT_ADDR_BIT), SSI0_ADATA); + + // schedule next acquire + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); +} + +static void +ssi0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + au1000_ts_t *ts = (au1000_ts_t*)dev_id; + u32 stat, int_stat, data; + + spin_lock(&ts->lock); + + stat = inl(SSI0_STATUS); + // clear sticky status bits + outl(stat & (SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE), SSI0_STATUS); + + int_stat = inl(SSI0_INT); + // clear sticky intr status bits + outl(int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI), SSI0_INT); + + if ((int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI)) != SSIINT_DI) { + if (int_stat & SSIINT_OI) + err("overflow"); + if (int_stat & SSIINT_UI) + err("underflow"); + spin_unlock(&ts->lock); + return; + } + + data = inl(SSI0_ADATA) & SSIADAT_DATA_MASK; + + switch (ts->acq_state) { + case IDLE: + break; + case ACQ_X: + ts->x_raw = data; + ts->acq_state = ACQ_Y; + // trigger Y acq + outl(SSIADAT_D | (MEASURE_12BIT_Y << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Y: + ts->y_raw = data; + ts->acq_state = ACQ_Z1; + // trigger Z1 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z1 << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Z1: + ts->z1_raw = data; + if (ts->pressure_eqn == PRESSURE_EQN_2) { + // don't acq Z2, using 2nd eqn for touch pressure + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } else { + ts->acq_state = ACQ_Z2; + // trigger Z2 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z2<z2_raw = data; + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + break; + } + + spin_unlock(&ts->lock); +} + + +/* +++++++++++++ File operations ++++++++++++++*/ + +static int +au1000_fasync(int fd, struct file *filp, int mode) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + return fasync_helper(fd, filp, mode, &ts->fasync); +} + +static int +au1000_ioctl(struct inode * inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + + switch(cmd) { + case TS_GET_RATE: /* TODO: what is this? */ + break; + case TS_SET_RATE: /* TODO: what is this? */ + break; + case TS_GET_CAL: + copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL)); + break; + case TS_SET_CAL: + copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL)); + break; + default: + err("unknown cmd %04x", cmd); + return -EINVAL; + } + + return 0; +} + +static unsigned int +au1000_poll(struct file * filp, poll_table * wait) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + poll_wait(filp, &ts->wait, wait); + if (ts->event_count) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t +au1000_read(struct file * filp, char * buf, size_t count, loff_t * l) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + TS_EVENT event; + int i; + + if (ts->event_count == 0) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&ts->wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + for (i = count; + i >= sizeof(TS_EVENT); + i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) { + if (ts->event_count == 0) + break; + spin_lock_irqsave(&ts->lock, flags); + event = ts->event_buf[ts->nextOut++]; + if (ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + if (ts->event_count) + ts->event_count--; + spin_unlock_irqrestore(&ts->lock, flags); + copy_to_user(buf, &event, sizeof(TS_EVENT)); + } + + return count - i; +} + + +static int +au1000_open(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts; + unsigned long flags; + + filp->private_data = ts = &au1000_ts; + + spin_lock_irqsave(&ts->lock, flags); + + // setup SSI0 config + outl(DEFAULT_SSI_CONFIG, SSI0_CONFIG); + + // clear out SSI0 status bits + outl(SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE, SSI0_STATUS); + // clear out SSI0 interrupt pending bits + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT); + + // enable SSI0 interrupts + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT_ENABLE); + + /* + * init bh handler that chugs the raw data (calibrates and + * calculates touch pressure). + */ + ts->chug_tq.routine = chug_raw_data; + ts->chug_tq.data = ts; + ts->pendown = 0; // pen up + + // flush event queue + ts->nextIn = ts->nextOut = ts->event_count = 0; + + // Start acquisition timer function + init_timer(&ts->acq_timer); + ts->acq_timer.function = au1000_acq_timer; + ts->acq_timer.data = (unsigned long)ts; + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); + MOD_INC_USE_COUNT; + return 0; +} + +static int +au1000_release(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + + au1000_fasync(-1, filp, 0); + del_timer_sync(&ts->acq_timer); + + spin_lock_irqsave(&ts->lock, flags); + // disable SSI0 interrupts + outl(0, SSI0_INT_ENABLE); + spin_unlock_irqrestore(&ts->lock, flags); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct file_operations ts_fops = { + read: au1000_read, + poll: au1000_poll, + ioctl: au1000_ioctl, + fasync: au1000_fasync, + open: au1000_open, + release: au1000_release, +}; + +/* +++++++++++++ End File operations ++++++++++++++*/ + + +int __init +au1000ts_init_module(void) +{ + au1000_ts_t* ts = &au1000_ts; + int ret; + + /* register our character device */ + if ((ret = register_chrdev(TS_MAJOR, TS_NAME, &ts_fops)) < 0) { + err("can't get major number"); + return ret; + } + info("registered"); + + memset(ts, 0, sizeof(au1000_ts_t)); + init_waitqueue_head(&ts->wait); + spin_lock_init(&ts->lock); + + if (!request_region(virt_to_phys((void*)SSI0_STATUS), 0x100, TS_NAME)) { + err("SSI0 ports in use"); + return -ENXIO; + } + + if ((ret = request_irq(AU1000_SSI0_INT, ssi0_interrupt, + SA_SHIRQ | SA_INTERRUPT, TS_NAME, ts))) { + err("could not get IRQ"); + return ret; + } + + // initial calibration values + ts->cal.xscale = -93; + ts->cal.xtrans = 346; + ts->cal.yscale = -64; + ts->cal.ytrans = 251; + + // init pen up/down hysteresis points + ts->pendown_thresh_ohms = DEFAULT_PENDOWN_THRESH_OHMS; + ts->penup_thresh_ohms = DEFAULT_PENUP_THRESH_OHMS; + ts->pressure_eqn = PRESSURE_EQN_2; + // init X and Y plate resistances + ts->x_plate_ohms = DEFAULT_X_PLATE_OHMS; + ts->y_plate_ohms = DEFAULT_Y_PLATE_OHMS; + + // set GPIO to SSI0 function + outl(inl(PIN_FUNCTION) & ~1, PIN_FUNCTION); + + // enable SSI0 clock and bring SSI0 out of reset + outl(0, SSI0_CONTROL); + udelay(1000); + outl(SSIEN_E, SSI0_CONTROL); + udelay(100); + + // FIXME: is this a working baudrate? + ts->clkdiv = 0; + ts->baudrate = calc_baudrate(ts->clkdiv); + outl(ts->clkdiv, SSI0_CLKDIV); + + info("baudrate = %d Hz", ts->baudrate); + + return 0; +} + +void +au1000ts_cleanup_module(void) +{ + // disable clocks and hold in reset + outl(SSIEN_CD, SSI0_CONTROL); + free_irq(AU1000_SSI0_INT, &au1000_ts); + release_region(virt_to_phys((void*)SSI0_STATUS), 0x100); + unregister_chrdev(TS_MAJOR, TS_NAME); +} + +/* Module information */ +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com"); +MODULE_DESCRIPTION("Au1000/ADS7846 Touch Screen Driver"); + +module_init(au1000ts_init_module); +module_exit(au1000ts_cleanup_module); diff -urN linux-2.4.18/drivers/char/drm/i810_dma.c linux-2.4.19-pre5/drivers/char/drm/i810_dma.c --- linux-2.4.18/drivers/char/drm/i810_dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/drm/i810_dma.c Sat Mar 30 22:55:28 2002 @@ -286,22 +286,20 @@ if(address == 0UL) return 0; - atomic_inc(&virt_to_page(address)->count); - set_bit(PG_locked, &virt_to_page(address)->flags); + get_page(virt_to_page(address)); + LockPage(virt_to_page(address)); return address; } static void i810_free_page(drm_device_t *dev, unsigned long page) { - if(page == 0UL) - return; - - atomic_dec(&virt_to_page(page)->count); - clear_bit(PG_locked, &virt_to_page(page)->flags); - wake_up(&virt_to_page(page)->wait); - free_page(page); - return; + if (page) { + struct page *p = virt_to_page(page); + put_page(p); + UnlockPage(p); + free_page(page); + } } static int i810_dma_cleanup(drm_device_t *dev) diff -urN linux-2.4.18/drivers/char/drm/sis_ds.c linux-2.4.19-pre5/drivers/char/drm/sis_ds.c --- linux-2.4.18/drivers/char/drm/sis_ds.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.19-pre5/drivers/char/drm/sis_ds.c Sat Mar 30 22:55:39 2002 @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff -urN linux-2.4.18/drivers/char/drm-4.0/i810_dma.c linux-2.4.19-pre5/drivers/char/drm-4.0/i810_dma.c --- linux-2.4.18/drivers/char/drm-4.0/i810_dma.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/drm-4.0/i810_dma.c Sat Mar 30 22:55:28 2002 @@ -280,20 +280,20 @@ if(address == 0UL) return 0; - atomic_inc(&virt_to_page(address)->count); - set_bit(PG_locked, &virt_to_page(address)->flags); + get_page(virt_to_page(address)); + LockPage(virt_to_page(address)); return address; } static void i810_free_page(drm_device_t *dev, unsigned long page) { + struct page * p = virt_to_page(page); if(page == 0UL) return; - atomic_dec(&virt_to_page(page)->count); - clear_bit(PG_locked, &virt_to_page(page)->flags); - wake_up(&virt_to_page(page)->wait); + put_page(p); + UnlockPage(p); free_page(page); return; } diff -urN linux-2.4.18/drivers/char/dummy_keyb.c linux-2.4.19-pre5/drivers/char/dummy_keyb.c --- linux-2.4.18/drivers/char/dummy_keyb.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/dummy_keyb.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,60 @@ +/* + * linux/drivers/char/dummy_keyb.c + * + * Allows CONFIG_VT on hardware without keyboards. + * + * Copyright (C) 1999, 2001 Bradley D. LaRonde + * + * 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. + * + * What is this for? + * + * Not all systems have keyboards. Some don't even have a keyboard + * port. However, some of those systems have video support and can + * use the virtual terminal support for display. However, the virtual + * terminal code expects a keyboard of some kind. This driver keeps + * the virtual terminal code happy by providing it a "keyboard", albeit + * a very quiet one. + * + * If you want to use the virtual terminal support but your system + * does not support a keyboard, define CONFIG_DUMMY_KEYB along with + * CONFIG_VT. + * + */ +#include +#include +#include + +void kbd_leds(unsigned char leds) +{ +} + +int kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return (scancode == keycode) ? 0 : -EINVAL; +} + +int kbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + +int kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + *keycode = scancode; + + return 1; +} + +char kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +void __init kbd_init_hw(void) +{ + printk("Dummy keyboard driver installed.\n"); +} diff -urN linux-2.4.18/drivers/char/dz.c linux-2.4.19-pre5/drivers/char/dz.c --- linux-2.4.18/drivers/char/dz.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/dz.c Sat Mar 30 22:55:28 2002 @@ -14,41 +14,31 @@ * after patches by harald to irq code. * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout * field from "current" - somewhere between 2.1.121 and 2.1.131 -Qua Jun 27 15:02:26 BRT 2001 + Qua Jun 27 15:02:26 BRT 2001 * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups * * Parts (C) 1999 David Airlie, airlied@linux.ie * [07-SEP-99] Bugfixes */ -/* #define DEBUG_DZ 1 */ - -#include -#include +#define DEBUG_DZ 1 #include +#include #include #include -#include +#include #include #include #include +#include #include #include #include -#include -#include #include -#include /* for definition of SERIAL */ +#include -/* for definition of struct console */ -#ifdef CONFIG_SERIAL_CONSOLE -#define CONSOLE_LINE (3) -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ -#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) #include -#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ - #include #include #include @@ -59,15 +49,13 @@ #include #include -#ifdef DEBUG_DZ #include #include #include -extern int (*prom_printf) (char *,...); -#endif - +#define CONSOLE_LINE (3) /* for definition of struct console */ +extern int (*prom_printf) (char *,...); #include "dz.h" @@ -75,17 +63,15 @@ DECLARE_TASK_QUEUE(tq_serial); -extern wait_queue_head_t keypress_wait; +extern wait_queue_head_t keypress_wait; static struct dz_serial *lines[4]; static unsigned char tmp_buffer[256]; - - #ifdef DEBUG_DZ /* * debugging code to send out chars via prom */ -static void debug_console( const char *s,int count) +static void debug_console(const char *s, int count) { unsigned i; @@ -106,17 +92,19 @@ * ------------------------------------------------------------ */ -static inline unsigned short dz_in (struct dz_serial *info, unsigned offset) +static inline unsigned short dz_in(struct dz_serial *info, unsigned offset) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); - + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); return *addr; } -static inline void dz_out (struct dz_serial *info, unsigned offset, - unsigned short value) +static inline void dz_out(struct dz_serial *info, unsigned offset, + unsigned short value) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); + + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); *addr = value; } @@ -130,33 +118,34 @@ * ------------------------------------------------------------ */ -static void dz_stop (struct tty_struct *tty) +static void dz_stop(struct tty_struct *tty) { - struct dz_serial *info; + struct dz_serial *info; unsigned short mask, tmp; - if (!tty) - return; - - info = (struct dz_serial *)tty->driver_data; + if (tty == 0) + return; + + info = (struct dz_serial *) tty->driver_data; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ - tmp &= ~mask; /* clear the TX flag */ - dz_out (info, DZ_TCR, tmp); + tmp &= ~mask; /* clear the TX flag */ + dz_out(info, DZ_TCR, tmp); } -static void dz_start (struct tty_struct *tty) +static void dz_start(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned short mask, tmp; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ + + tmp |= mask; /* set the TX flag */ + dz_out(info, DZ_TCR, tmp); - tmp |= mask; /* set the TX flag */ - dz_out (info, DZ_TCR, tmp); } /* @@ -187,7 +176,7 @@ * processing in the software interrupt portion of the driver. * ------------------------------------------------------------ */ -static inline void dz_sched_event (struct dz_serial *info, int event) +static inline void dz_sched_event(struct dz_serial *info, int event) { info->event |= 1 << event; queue_task(&info->tqueue, &tq_serial); @@ -201,8 +190,9 @@ * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ -static inline void receive_chars (struct dz_serial *info_in) +static inline void receive_chars(struct dz_serial *info_in) { + struct dz_serial *info; struct tty_struct *tty = 0; struct async_icount *icount; @@ -210,26 +200,28 @@ unsigned short status, tmp; unsigned char ch; - /* - * This code is going to be a problem... the call to tty_flip_buffer - * is going to need to be rethought... + /* this code is going to be a problem... + the call to tty_flip_buffer is going to need + to be rethought... */ do { - status = dz_in (info_in, DZ_RBUF); + status = dz_in(info_in, DZ_RBUF); info = lines[LINE(status)]; /* punt so we don't get duplicate characters */ if (!(status & DZ_DVAL)) goto ignore_char; - ch = UCHAR(status); /* grab the char */ + + ch = UCHAR(status); /* grab the char */ #if 0 if (info->is_console) { if (ch == 0) - return; /* it's a break ... */ + return; /* it's a break ... */ - wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */ + /* It is a 'keyboard interrupt' ;-) */ + wake_up(&keypress_wait); } #endif @@ -238,7 +230,8 @@ if (!tty) break; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; @@ -246,16 +239,15 @@ /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { - if (status & DZ_PERR) /* parity error */ + if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; - if (status & DZ_OERR) /* overrun error */ + if (status & DZ_OERR) /* overrun error */ icount->overrun++; - /* - * Check to see if we should ignore the character and - * mask off conditions that should be ignored + /* check to see if we should ignore the character + and mask off conditions that should be ignored */ if (status & info->ignore_status_mask) { @@ -263,24 +255,18 @@ break; goto ignore_char; } - /* mask off the error conditions we want to ignore */ tmp = status & info->read_status_mask; if (tmp & DZ_PERR) { *tty->flip.flag_buf_ptr = TTY_PARITY; -#ifdef DEBUG_DZ - debug_console("PERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("PERR\n", 5); } else if (tmp & DZ_FERR) { *tty->flip.flag_buf_ptr = TTY_FRAME; -#ifdef DEBUG_DZ - debug_console("FERR\n",5); -#endif /* DEBUG_DZ */ - } if (tmp & DZ_OERR) { -#ifdef DEBUG_DZ - debug_console("OERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("FERR\n", 5); + } + if (tmp & DZ_OERR) { + debug_console("OERR\n", 5); if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; @@ -289,11 +275,10 @@ } } } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; -ignore_char: - ; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: } while (status & DZ_DVAL); if (tty) @@ -307,26 +292,25 @@ * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ -static inline void transmit_chars (struct dz_serial *info) +static inline void transmit_chars(struct dz_serial *info) { unsigned char tmp; - if (info->x_char) { /* XON/XOFF chars */ + + + if (info->x_char) { /* XON/XOFF chars */ dz_out(info, DZ_TDR, info->x_char); info->icount.tx++; info->x_char = 0; return; } - /* if nothing to do or stopped or hardware stopped */ - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { dz_stop(info->tty); return; } - /* - * If something to do ... (rember the dz has no output fifo so we go + * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = (unsigned short) info->xmit_buf[info->xmit_tail++]; @@ -335,7 +319,8 @@ info->icount.tx++; if (--info->xmit_cnt < WAKEUP_CHARS) - dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + /* Are we done */ if (info->xmit_cnt <= 0) @@ -349,7 +334,7 @@ * Only valid for the MODEM line duh ! * ------------------------------------------------------------ */ -static inline void check_modem_status (struct dz_serial *info) +static inline void check_modem_status(struct dz_serial *info) { unsigned short status; @@ -358,7 +343,7 @@ return; status = dz_in(info, DZ_MSR); - + /* it's easy, since DSR2 is the only bit in the register */ if (status) info->icount.dsr++; @@ -372,20 +357,20 @@ * It deals with the multiple ports. * ------------------------------------------------------------ */ -static void dz_interrupt (int irq, void *dev, struct pt_regs *regs) +static void dz_interrupt(int irq, void *dev, struct pt_regs *regs) { struct dz_serial *info; unsigned short status; - /* get the reason why we just got an irq */ - status = dz_in((struct dz_serial *)dev, DZ_CSR); - info = lines[LINE(status)]; /* re-arrange info the proper port */ + /* get the reason why we just got an irq */ + status = dz_in((struct dz_serial *) dev, DZ_CSR); + info = lines[LINE(status)]; /* re-arrange info the proper port */ - if (status & DZ_RDONE) + if (status & DZ_RDONE) receive_chars(info); /* the receive function */ - if (status & DZ_TRDY) - transmit_chars (info); + if (status & DZ_TRDY) + transmit_chars(info); } /* @@ -403,12 +388,12 @@ * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_serial_bh (void) +static void do_serial_bh(void) { - run_task_queue (&tq_serial); + run_task_queue(&tq_serial); } -static void do_softint (void *private_data) +static void do_softint(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty; @@ -417,10 +402,9 @@ return; if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); } } @@ -434,11 +418,11 @@ * do_serial_hangup() -> tty->hangup() -> rs_hangup() * ------------------------------------------------------------------- */ -static void do_serial_hangup (void *private_data) +static void do_serial_hangup(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty;; - + if (!tty) return; @@ -452,31 +436,31 @@ * various initialization tasks * ------------------------------------------------------------------- */ -static int startup (struct dz_serial *info) +static int startup(struct dz_serial *info) { unsigned long page, flags; unsigned short tmp; if (info->is_initialized) return 0; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (!info->port) { - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); restore_flags(flags); return -ENODEV; } - if (!info->xmit_buf) { page = get_free_page(GFP_KERNEL); if (!page) { - restore_flags (flags); - return -ENOMEM; + restore_flags(flags); + return -ENOMEM; } - info->xmit_buf = (unsigned char *)page; + info->xmit_buf = (unsigned char *) page; } - if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -487,18 +471,24 @@ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - change_speed(info); /* set up the speed */ + /* set up the speed */ + change_speed(info); - /* - * Clear the line transmitter buffer I can't figure out why I need to - * do this - but its necessary - in order for the console portion and - * the interrupt portion to live happily side by side. + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. + */ + + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. */ info->is_initialized = 1; restore_flags(flags); - return 0; } @@ -510,7 +500,7 @@ * DTR is dropped if the hangup on close termio flag is on. * ------------------------------------------------------------------- */ -static void shutdown (struct dz_serial *info) +static void shutdown(struct dz_serial *info) { unsigned long flags; unsigned short tmp; @@ -518,18 +508,20 @@ if (!info->is_initialized) return; - save_and_cli(flags); + save_flags(flags); + cli(); + + dz_stop(info->tty); + - dz_stop (info->tty); info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ dz_out(info, DZ_LPR, info->cflags); - if (info->xmit_buf) { /* free Tx buffer */ - free_page((unsigned long)info->xmit_buf); + if (info->xmit_buf) { /* free Tx buffer */ + free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { tmp = dz_in(info, DZ_TCR); if (tmp & DZ_MODEM_DTR) { @@ -537,13 +529,11 @@ dz_out(info, DZ_TCR, tmp); } } - if (info->tty) - set_bit (TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); info->is_initialized = 0; - - restore_flags (flags); + restore_flags(flags); } /* @@ -553,7 +543,7 @@ * set the baud rate. * ------------------------------------------------------------------- */ -static void change_speed (struct dz_serial *info) +static void change_speed(struct dz_serial *info) { unsigned long flags; unsigned cflag; @@ -561,26 +551,27 @@ if (!info->tty || !info->tty->termios) return; - - save_and_cli(flags); - + + save_flags(flags); + cli(); + info->cflags = info->line; cflag = info->tty->termios->c_cflag; switch (cflag & CSIZE) { - case CS5: - info->cflags |= DZ_CS5; - break; - case CS6: - info->cflags |= DZ_CS6; - break; - case CS7: - info->cflags |= DZ_CS7; - break; - case CS8: - default: - info->cflags |= DZ_CS8; + case CS5: + info->cflags |= DZ_CS5; + break; + case CS6: + info->cflags |= DZ_CS6; + break; + case CS7: + info->cflags |= DZ_CS7; + break; + case CS8: + default: + info->cflags |= DZ_CS8; } if (cflag & CSTOPB) @@ -589,7 +580,7 @@ info->cflags |= DZ_PARENB; if (cflag & PARODD) info->cflags |= DZ_PARODD; - + baud = tty_get_baud_rate(info->tty); switch (baud) { case 50: @@ -603,19 +594,19 @@ break; case 134: info->cflags |= DZ_B134; - break; + break; case 150: info->cflags |= DZ_B150; break; case 300: info->cflags |= DZ_B300; - break; + break; case 600: info->cflags |= DZ_B600; break; case 1200: info->cflags |= DZ_B1200; - break; + break; case 1800: info->cflags |= DZ_B1800; break; @@ -627,16 +618,16 @@ break; case 3600: info->cflags |= DZ_B3600; - break; + break; case 4800: info->cflags |= DZ_B4800; break; case 7200: info->cflags |= DZ_B7200; - break; - case 9600: + break; + case 9600: default: - info->cflags |= DZ_B9600; + info->cflags |= DZ_B9600; } info->cflags |= DZ_RXENAB; @@ -645,8 +636,8 @@ /* setup accept flag */ info->read_status_mask = DZ_OERR; if (I_INPCK(info->tty)) - info->read_status_mask |= (DZ_FERR | DZ_PERR); - + info->read_status_mask |= (DZ_FERR | DZ_PERR); + /* characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) @@ -662,17 +653,19 @@ * Flush the buffer. * ------------------------------------------------------------------- */ -static void dz_flush_chars (struct tty_struct *tty) +static void dz_flush_chars(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) return; - save_and_cli(flags); - dz_start (info->tty); + save_flags(flags); + cli(); + + dz_start(info->tty); + restore_flags(flags); } @@ -684,64 +677,67 @@ * main output routine. * ------------------------------------------------------------------- */ -static int dz_write (struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static int dz_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; int c, ret = 0; - if (!tty ) + if (!tty) return ret; if (!info->xmit_buf) return ret; if (!tmp_buf) tmp_buf = tmp_buffer; + + if (from_user) { - down (&tmp_buf_sem); + + down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; - c -= copy_from_user (tmp_buf, buf, c); + c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) ret = -EFAULT; break; } + save_flags(flags); + cli(); - save_and_cli(flags); - - c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE - 1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; count -= c; ret += c; } + up(&tmp_buf_sem); } else { + + while (1) { - save_and_cli(flags); + save_flags(flags); + cli(); - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) { - restore_flags (flags); + restore_flags(flags); break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE-1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; @@ -750,14 +746,14 @@ } } + if (info->xmit_cnt) { if (!tty->stopped) { if (!tty->hw_stopped) { - dz_start (info->tty); + dz_start(info->tty); } } } - return ret; } @@ -768,15 +764,14 @@ * compute the amount of space available for writing. * ------------------------------------------------------------------- */ -static int dz_write_room (struct tty_struct *tty) +static int dz_write_room(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int ret; ret = DZ_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; - return ret; } @@ -787,10 +782,10 @@ * compute the amount of char left to be transmitted * ------------------------------------------------------------------- */ -static int dz_chars_in_buffer (struct tty_struct *tty) +static int dz_chars_in_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + return info->xmit_cnt; } @@ -801,19 +796,18 @@ * Empty the output buffer * ------------------------------------------------------------------- */ -static void dz_flush_buffer (struct tty_struct *tty) +static void dz_flush_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); } /* @@ -824,17 +818,17 @@ * incoming characters should be throttled (or not). * ------------------------------------------------------------ */ -static void dz_throttle (struct tty_struct *tty) +static void dz_throttle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); } -static void dz_unthrottle (struct tty_struct *tty) +static void dz_unthrottle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) { if (info->x_char) @@ -844,9 +838,9 @@ } } -static void dz_send_xchar (struct tty_struct *tty, char ch) +static void dz_send_xchar(struct tty_struct *tty, char ch) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; info->x_char = ch; @@ -863,11 +857,11 @@ struct serial_struct *retinfo) { struct serial_struct tmp; - + if (!retinfo) return -EFAULT; - memset (&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; @@ -881,8 +875,8 @@ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } -static int set_serial_info (struct dz_serial *info, - struct serial_struct *new_info) +static int set_serial_info(struct dz_serial *info, + struct serial_struct *new_info) { struct serial_struct new_serial; struct dz_serial old_info; @@ -913,7 +907,6 @@ info->closing_wait = new_serial.closing_wait; retval = startup(info); - return retval; } @@ -927,17 +920,17 @@ * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int get_lsr_info (struct dz_serial *info, unsigned int *value) +static int get_lsr_info(struct dz_serial *info, unsigned int *value) { - unsigned short status = dz_in (info, DZ_LPR); + unsigned short status = dz_in(info, DZ_LPR); - return put_user (status, value); + return put_user(status, value); } /* * This routine sends a break character out the serial port. */ -static void send_break (struct dz_serial *info, int duration) +static void send_break(struct dz_serial *info, int duration) { unsigned long flags; unsigned short tmp, mask; @@ -946,33 +939,36 @@ return; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); + tmp = dz_in(info, DZ_TCR); tmp |= mask; current->state = TASK_INTERRUPTIBLE; - save_and_cli(flags); + save_flags(flags); + cli(); + dz_out(info, DZ_TCR, tmp); + schedule_timeout(duration); + tmp &= ~mask; dz_out(info, DZ_TCR, tmp); + restore_flags(flags); } static int dz_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int error; - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int retval; - if (cmd != TIOCGSERIAL && cmd != TIOCSSERIAL && - cmd != TIOCSERCONFIG && cmd != TIOCSERGWILD && - cmd != TIOCSERSWILD && cmd != TIOCSERGSTRUCT) { + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } - switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); @@ -980,7 +976,7 @@ return retval; tty_wait_until_sent(tty, 0); if (!arg) - send_break(info, HZ/4); /* 1/4 second */ + send_break(info, HZ / 4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ @@ -988,41 +984,32 @@ if (retval) return retval; tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return 0; case TIOCGSOFTCAR: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long)); - if (error) - return error; - put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: - if (get_user (arg, (unsigned long *)arg)) + if (get_user(arg, (unsigned long *) arg)) return -EFAULT; - - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0); + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *)arg, - sizeof(struct serial_struct)); - if (error) - return error; - return get_serial_info(info, (struct serial_struct *)arg); + return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info (info, (unsigned int *)arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - return copy_to_user((struct dz_serial *)arg, info, - sizeof(struct dz_serial)) ? -EFAULT : 0; - + return copy_to_user((struct dz_serial *) arg, info, + sizeof(struct dz_serial)) ? -EFAULT : 0; + default: return -ENOIOCTLCMD; } @@ -1030,15 +1017,15 @@ return 0; } -static void dz_set_termios (struct tty_struct *tty, - struct termios *old_termios) +static void dz_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; - change_speed (info); + change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1058,37 +1045,36 @@ */ static void dz_close(struct tty_struct *tty, struct file *filp) { - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; if (!info) return; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } - if ((tty->count == 1) && (info->count != 1)) { /* - * Uh, oh. tty->count is 1, which means that the tty structure - * will be freed. Info->count should always be one in these - * conditions. If it's greater than one, we've got real - * problems, since it means the serial port won't be shutdown. + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. */ printk("dz_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } - if (--info->count < 0) { printk("ds_close: bad serial port count for ttyS%02d: %d\n", info->line, info->count); info->count = 0; } - if (info->count) { restore_flags(flags); return; @@ -1103,8 +1089,8 @@ if (info->flags & DZ_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; /* - * Now we wait for the transmit buffer to clear; and we notify the line - * discipline to only process XON/XOFF characters. + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1112,26 +1098,27 @@ tty_wait_until_sent(tty, info->closing_wait); /* - * At this point we stop accepting input. To do this, we disable the - * receive line status interrupts. + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts. */ + shutdown(info); if (tty->driver.flush_buffer) - tty->driver.flush_buffer (tty); + tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) - tty->ldisc.close(tty); + (tty->ldisc.close) (tty); tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) - tty->ldisc.open(tty); + (tty->ldisc.open) (tty); } if (info->blocked_open) { if (info->close_delay) { @@ -1140,7 +1127,6 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); wake_up_interruptible(&info->close_wait); @@ -1150,10 +1136,10 @@ /* * dz_hangup () --- called by tty_hangup() when a hangup is signaled. */ -static void dz_hangup (struct tty_struct *tty) +static void dz_hangup(struct tty_struct *tty) { struct dz_serial *info = (struct dz_serial *) tty->driver_data; - + dz_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1168,10 +1154,9 @@ * rs_open() and friends * ------------------------------------------------------------ */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct dz_serial *info) +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct dz_serial *info) { - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -1183,7 +1168,6 @@ interruptible_sleep_on(&info->close_wait); return -EAGAIN; } - /* * If this is a callout device, then just make sure the normal * device isn't being used. @@ -1191,47 +1175,44 @@ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & DZ_NORMAL_ACTIVE) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; - info->flags |= DZ_CALLOUT_ACTIVE; return 0; } - /* - * If non-blocking mode is set, or the port is not enabled, then make - * the check up front and then exit. + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & DZ_CALLOUT_ACTIVE) return -EBUSY; info->flags |= DZ_NORMAL_ACTIVE; - return 0; } - if (info->flags & DZ_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = 1; } /* - * Block waiting for the carrier detect and the line to become free - * (i.e., not in use by the callout). While we are in this loop, - * info->count is dropped by one, so that dz_close() knows when to free - * things. We restore it upon exit, either normal or abnormal. + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * dz_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); @@ -1240,7 +1221,7 @@ info->blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p (filp) || !(info->is_initialized)) { + if (tty_hung_up_p(filp) || !(info->is_initialized)) { retval = -EAGAIN; break; } @@ -1253,9 +1234,9 @@ } schedule(); } - + current->state = TASK_RUNNING; - remove_wait_queue (&info->open_wait, &wait); + remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; @@ -1271,16 +1252,15 @@ * enables interrupts for a serial port. It also performs the * serial-specific initialization for the tty structure. */ -static int dz_open (struct tty_struct *tty, struct file *filp) +static int dz_open(struct tty_struct *tty, struct file *filp) { struct dz_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; - /* - * The dz lines for the mouse/keyboard must be opened using their - * respective drivers. + /* The dz lines for the mouse/keyboard must be + * opened using their respective drivers. */ if ((line < 0) || (line >= DZ_NB_PORT)) return -ENODEV; @@ -1297,37 +1277,36 @@ /* * Start up serial port */ - retval = startup (info); + retval = startup(info); if (retval) return retval; - retval = block_til_ready (tty, filp, info); + retval = block_til_ready(tty, filp, info); if (retval) return retval; if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; - else + else *tty->termios = info->callout_termios; change_speed(info); - } + } info->session = current->session; info->pgrp = current->pgrp; - return 0; } -static void show_serial_version (void) +static void show_serial_version(void) { printk("%s%s\n", dz_name, dz_version); } - int __init dz_init(void) { - int i, flags; + int i, tmp; + long flags; struct dz_serial *info; /* Setup base handler, and timer table. */ @@ -1374,8 +1353,8 @@ serial_driver.hangup = dz_hangup; /* - * The callout device is just like normal device except for major - * number and the subtype code. + * The callout device is just like normal device except for + * major number and the subtype code. */ callout_driver = serial_driver; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) @@ -1386,21 +1365,22 @@ callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver (&serial_driver)) - panic("Couldn't register serial driver\n"); - if (tty_register_driver (&callout_driver)) - panic("Couldn't register callout driver\n"); - - save_flags(flags); cli(); - for (i=0; i < DZ_NB_PORT; i++) { - info = &multi[i]; + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver"); + save_flags(flags); + cli(); + + for (i = 0; i < DZ_NB_PORT; i++) { + info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; - if ((mips_machtype == MACH_DS23100) || - (mips_machtype == MACH_DS5100)) + if (mips_machtype == MACH_DS23100 || + mips_machtype == MACH_DS5100) info->port = (unsigned long) KN01_DZ11_BASE; - else + else info->port = (unsigned long) KN02_DZ11_BASE; info->line = i; @@ -1417,76 +1397,71 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); /* * If we are pointing to address zero then punt - not correctly * set up in setup.c to handle this. */ - if (! info->port) + if (!info->port) return 0; printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, SERIAL); tty_register_devfs(&serial_driver, 0, - serial_driver.minor_start + info->line); + serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, - callout_driver.minor_start + info->line); + callout_driver.minor_start + info->line); } - /* Reset the chip */ + /* reset the chip */ #ifndef CONFIG_SERIAL_CONSOLE - { - int tmp; - dz_out(info, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR); - wbflush(); - - /* Enable scanning */ - dz_out(info, DZ_CSR, DZ_MSE); - } + dz_out(info, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(info, DZ_CSR)) & DZ_CLR); + wbflush(); + + /* enable scanning */ + dz_out(info, DZ_CSR, DZ_MSE); #endif - - /* - * Order matters here... the trick is that flags is updated... in - * request_irq - to immediatedly obliterate it is unwise. - */ + + /* order matters here... the trick is that flags + is updated... in request_irq - to immediatedly obliterate + it is unwise. */ restore_flags(flags); + if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) - panic("Unable to register DZ interrupt\n"); - + panic("Unable to register DZ interrupt"); + return 0; } #ifdef CONFIG_SERIAL_CONSOLE -static void dz_console_put_char (unsigned char ch) +static void dz_console_put_char(unsigned char ch) { unsigned long flags; - int loops = 2500; + int loops = 2500; unsigned short tmp = ch; - /* - * this code sends stuff out to serial device - spinning its wheels and - * waiting. - */ + /* this code sends stuff out to serial device - spinning its + wheels and waiting. */ - /* force the issue - point it at lines[3]*/ + /* force the issue - point it at lines[3] */ dz_console = &multi[CONSOLE_LINE]; - save_and_cli(flags); + save_flags(flags); + cli(); + /* spin our wheels */ - while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) - ; - + while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--); + /* Actually transmit the character. */ dz_out(dz_console, DZ_TDR, tmp); - restore_flags(flags); + restore_flags(flags); } - /* * ------------------------------------------------------------------- * dz_console_print () @@ -1495,12 +1470,12 @@ * The console must be locked when we get here. * ------------------------------------------------------------------- */ -static void dz_console_print (struct console *cons, - const char *str, - unsigned int count) +static void dz_console_print(struct console *cons, + const char *str, + unsigned int count) { #ifdef DEBUG_DZ - prom_printf((char *)str); + prom_printf((char *) str); #endif while (count--) { if (*str == '\n') @@ -1526,7 +1501,7 @@ int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; - unsigned short mask,tmp; + unsigned short mask, tmp; if (options) { baud = simple_strtoul(options, NULL, 10); @@ -1536,11 +1511,10 @@ if (*s) parity = *s++; if (*s) - bits = *s - '0'; + bits = *s - '0'; } - /* - * Now construct a cflag setting. + * Now construct a cflag setting. */ switch (baud) { case 1200: @@ -1580,18 +1554,17 @@ /* TOFIX: force to console line */ dz_console = &multi[CONSOLE_LINE]; - if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) dz_console->port = KN01_DZ11_BASE; - else - dz_console->port = KN02_DZ11_BASE; + else + dz_console->port = KN02_DZ11_BASE; dz_console->line = CONSOLE_LINE; dz_out(dz_console, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) - ; + while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR); /* enable scanning */ - dz_out(dz_console, DZ_CSR, DZ_MSE); + dz_out(dz_console, DZ_CSR, DZ_MSE); /* Set up flags... */ dz_console->cflags = 0; @@ -1601,16 +1574,16 @@ dz_out(dz_console, DZ_LPR, dz_console->cflags); mask = 1 << dz_console->line; - tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ + tmp = dz_in(dz_console, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { - tmp |= mask; /* set the TX flag */ - dz_out (dz_console, DZ_TCR, tmp); + tmp |= mask; /* set the TX flag */ + dz_out(dz_console, DZ_TCR, tmp); } - return 0; } -static struct console dz_sercons = { +static struct console dz_sercons = +{ name: "ttyS", write: dz_console_print, device: dz_console_device, @@ -1625,6 +1598,6 @@ register_console(&dz_sercons); } -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#endif /* CONFIG_SERIAL_CONSOLE */ MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/char/dz.h linux-2.4.19-pre5/drivers/char/dz.h --- linux-2.4.18/drivers/char/dz.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/dz.h Sat Mar 30 22:55:28 2002 @@ -10,6 +10,8 @@ #ifndef DZ_SERIAL_H #define DZ_SERIAL_H +#define SERIAL_MAGIC 0x5301 + /* * Definitions for the Control and Status Received. */ diff -urN linux-2.4.18/drivers/char/efirtc.c linux-2.4.19-pre5/drivers/char/efirtc.c --- linux-2.4.18/drivers/char/efirtc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/efirtc.c Sat Mar 30 22:55:28 2002 @@ -40,7 +40,7 @@ #include #include -#define EFI_RTC_VERSION "0.2" +#define EFI_RTC_VERSION "0.3" #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) /* @@ -315,56 +315,45 @@ 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); + "Time : %u:%u:%u.%09u\n" + "Date : %u-%u-%u\n" + "Daylight : %u\n", + eft.hour, eft.minute, eft.second, eft.nanosecond, + eft.year, eft.month, eft.day, + eft.daylight); if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - p += sprintf(p, "Timezone : unspecified\n"); + p += sprintf(p, "Timezone : unspecified\n"); else /* XXX fixme: convert to string? */ - p += sprintf(p, "Timezone : %u\n", eft.timezone); + 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); + "Alarm Time : %u:%u:%u.%09u\n" + "Alarm Date : %u-%u-%u\n" + "Alarm Daylight : %u\n" + "Enabled : %s\n" + "Pending : %s\n", + alm.hour, alm.minute, alm.second, alm.nanosecond, + alm.year, alm.month, alm.day, + alm.daylight, + enabled == 1 ? "yes" : "no", + pending == 1 ? "yes" : "no"); if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - p += sprintf(p, "Timezone : unspecified\n"); + p += sprintf(p, "Timezone : unspecified\n"); else /* XXX fixme: convert to string? */ - p += sprintf(p, "Timezone : %u\n", eft.timezone); + p += sprintf(p, "Timezone : %u\n", alm.timezone); /* * now prints the capabilities */ p += sprintf(p, - "\nClock Cap :\n" - "Resolution: %u\n" - "Accuracy : %u\n" - "SetstoZero: %u\n", + "Resolution : %u\n" + "Accuracy : %u\n" + "SetstoZero : %u\n", cap.resolution, cap.accuracy, cap.sets_to_zero); return p - buf; @@ -390,7 +379,7 @@ misc_register(&efi_rtc_dev); - create_proc_read_entry ("efirtc", 0, NULL, efi_rtc_read_proc, NULL); + create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL); return 0; } diff -urN linux-2.4.18/drivers/char/esp.c linux-2.4.19-pre5/drivers/char/esp.c --- linux-2.4.18/drivers/char/esp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/esp.c Sat Mar 30 22:55:34 2002 @@ -2162,7 +2162,7 @@ if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); diff -urN linux-2.4.18/drivers/char/indydog.c linux-2.4.19-pre5/drivers/char/indydog.c --- linux-2.4.18/drivers/char/indydog.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/indydog.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,158 @@ +/* + * IndyDog 0.2 A Hardware Watchdog Device for SGI IP22 + * + * (c) Copyright 2002 Guido Guenther , All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * based on softdog.c by Alan Cox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int indydog_alive; +static struct sgimc_misc_ctrl *mcmisc_regs; + +static void indydog_ping() +{ + mcmisc_regs->watchdogt = 0; +} + + +/* + * Allow only one person to hold it open + */ + +static int indydog_open(struct inode *inode, struct file *file) +{ + u32 mc_ctrl0; + + if(indydog_alive) + return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + /* + * Activate timer + */ + mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); + + mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + indydog_ping(); + + indydog_alive=1; + printk("Started watchdog timer.\n"); + return 0; +} + +static int indydog_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ + lock_kernel(); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + { + u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; + mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + printk("Stopped watchdog timer.\n"); + } +#endif + indydog_alive=0; + unlock_kernel(); + return 0; +} + +static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) { + indydog_ping(); + return 1; + } + return 0; +} + +static int indydog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + identity: "Hardware Watchdog for SGI IP22", + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + indydog_ping(); + return 0; + } +} + +static struct file_operations indydog_fops = { + owner: THIS_MODULE, + write: indydog_write, + ioctl: indydog_ioctl, + open: indydog_open, + release: indydog_release, +}; + +static struct miscdevice indydog_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &indydog_fops, +}; + +static const char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n"; + +static int __init watchdog_init(void) +{ + int ret; + + ret = misc_register(&indydog_miscdev); + + if (ret) + return ret; + + printk(banner); + + return 0; +} + +static void __exit watchdog_exit(void) +{ + misc_deregister(&indydog_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/char/ip2/i2lib.c linux-2.4.19-pre5/drivers/char/ip2/i2lib.c --- linux-2.4.18/drivers/char/ip2/i2lib.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/ip2/i2lib.c Sat Mar 30 22:55:28 2002 @@ -1330,7 +1330,7 @@ // if expires == 0 then timer poped, then do not need to del_timer if ((timeout > 0) && pCh->BookmarkTimer.expires && - (pCh->BookmarkTimer.expires > jiffies)) { + time_before(jiffies, pCh->BookmarkTimer.expires)) { del_timer( &(pCh->BookmarkTimer) ); pCh->BookmarkTimer.expires = 0; diff -urN linux-2.4.18/drivers/char/keyboard.c linux-2.4.19-pre5/drivers/char/keyboard.c --- linux-2.4.18/drivers/char/keyboard.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/keyboard.c Sat Mar 30 22:55:28 2002 @@ -331,15 +331,31 @@ schedule_console_callback(); } +#ifdef CONFIG_FORWARD_KEYBOARD +extern int forward_chars; void put_queue(int ch) { + if (forward_chars == fg_console+1){ + kbd_forward_char (ch); + } else { + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } + } +} +#else +void put_queue(int ch) +{ wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } +#endif static void puts_queue(char *cp) { diff -urN linux-2.4.18/drivers/char/lcd.c linux-2.4.19-pre5/drivers/char/lcd.c --- linux-2.4.18/drivers/char/lcd.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/lcd.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,632 @@ +/* + * LCD, LED and Button interface for Cobalt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +#define RTC_IO_EXTENT 0x10 /*Only really two ports, but... */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lcd.h" + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); + +static int lcd_present = 1; + +int led_state = 0; + +#if defined(CONFIG_TULIP) && 0 + +#define MAX_INTERFACES 8 +static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES]; +static void *linkcheck_cookies[MAX_INTERFACES]; + +int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie) +{ + if (iface_num < 0 || + iface_num >= MAX_INTERFACES || + linkcheck_callbacks[iface_num] != NULL) + return -1; + linkcheck_callbacks[iface_num] = (linkcheck_func_t) func; + linkcheck_cookies[iface_num] = cookie; + return 0; +} +#endif + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct lcd_display button_display; + unsigned long address, a; + int index; + + switch (cmd) { + case LCD_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x08); + break; + + case LCD_Reset: + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x01); + udelay(150); + LCDWriteInst(0x06); + break; + + case LCD_Clear: + udelay(150); + BusyCheck(); + LCDWriteInst(0x01); + break; + + case LCD_Cursor_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + break; + + case LCD_Cursor_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x14); + break; + + case LCD_Cursor_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0C); + break; + + case LCD_Cursor_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Blink_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0E); + break; + + case LCD_Get_Cursor_Pos:{ + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.cursor_address = ( LCDReadInst ); + display.cursor_address = ( display.cursor_address & 0x07F ); + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + + break; + } + + + case LCD_Set_Cursor_Pos: { + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + a = (display.cursor_address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + break; + } + + case LCD_Get_Cursor: { + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.character = LCDReadData; + + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + case LCD_Set_Cursor:{ + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteData( display.character ); + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + + case LCD_Disp_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x18); + break; + + case LCD_Disp_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x1C); + break; + + case LCD_Home: + udelay(150); + BusyCheck(); + LCDWriteInst(0x02); + break; + + case LCD_Write: { + struct lcd_display display; + + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteInst(0x80); + udelay(150); + BusyCheck(); + + for (index = 0; index < (display.size1); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line1[index]); + BusyCheck(); + } + + udelay(150); + BusyCheck(); + LCDWriteInst(0xC0); + udelay(150); + BusyCheck(); + for (index = 0; index < (display.size2); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line2[index]); + } + + break; + } + + case LCD_Read: { + struct lcd_display display; + + BusyCheck(); + for (address = kDD_R00; address <= kDD_R01; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + udelay(150); + BusyCheck(); + display.line1[address] = LCDReadData; + } + + display.line1[ 0x27 ] = '\0'; + + for (address = kDD_R10; address <= kDD_R11; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + udelay(150); + BusyCheck(); + display.line2[address - 0x40 ] = LCDReadData; + } + + display.line2[ 0x27 ] = '\0'; + + if(copy_to_user((struct lcd_display*)arg, &display, + sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// set all GPIO leds to led_display.leds + + case LED_Set: { + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + led_state = led_display.leds; + LEDSet(led_state); + + break; + } + + +// set only bit led_display.leds + + case LED_Bit_Set: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state | bit; + LEDSet(led_state); + break; + } + +// clear only bit led_display.leds + + case LED_Bit_Clear: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state & ~bit; + LEDSet(led_state); + break; + } + + + case BUTTON_Read: { + button_display.buttons = GPIRead; + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check: { + button_display.buttons = *((volatile unsigned long *) (0xB0100060) ); + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check_2: { + int iface_num; + + /* panel-utils should pass in the desired interface status is wanted for + * in "buttons" of the structure. We will set this to non-zero if the + * link is in fact up for the requested interface. --DaveM + */ + if(copy_from_user(&button_display, (struct lcd_display *)arg, sizeof(button_display))) + return -EFAULT; + iface_num = button_display.buttons; +#if defined(CONFIG_TULIP) && 0 + if (iface_num >= 0 && + iface_num < MAX_INTERFACES && + linkcheck_callbacks[iface_num] != NULL) { + button_display.buttons = + linkcheck_callbacks[iface_num](linkcheck_cookies[iface_num]); + } else +#endif + button_display.buttons = 0; + + if(__copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// Erase the flash + + case FLASH_Erase: { + + int ctr=0; + + // Chip Erase Sequence + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase3 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase6 ); + + printk( "Erasing Flash.\n"); + + while ( (!dqpoll(0x00000000,0xFF)) && (!timeout(0x00000000)) ) { + ctr++; + } + + printk("\n"); + printk("\n"); + printk("\n"); + + if (READ_FLASH(0x07FFF0)==0xFF) { printk("Erase Successful\r\n"); } + else if (timeout) { printk("Erase Timed Out\r\n"); } + + break; + } + +// burn the flash + + case FLASH_Burn: { + + volatile unsigned long burn_addr; + unsigned long flags; + int i; + unsigned char *rom; + + + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + rom = (unsigned char *) kmalloc((128),GFP_ATOMIC); + if ( rom == NULL ) { + printk ("broken\n"); + return 1; + } + + printk("Churning and Burning -"); + save_flags(flags); + for (i=0; iRomImage[0]); + + if(!access_ok(VERIFY_WRITE, user_bytes, FLASH_SIZE)) + return -EFAULT; + + printk("Reading Flash"); + for (i=0; i 0) + return -EINVAL; + + lcd_waiters++; + while(((buttons_now = (long)button_pressed()) == 0) && + !(signal_pending(current))) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2 * HZ); + } + lcd_waiters--; + + if(signal_pending(current)) + return -ERESTARTSYS; + return buttons_now; +} + +/* + * The various file operations we support. + */ + +static struct file_operations lcd_fops = { + read: lcd_read, + ioctl: lcd_ioctl, + open: lcd_open, +}; + +static struct miscdevice lcd_dev= +{ + LCD_MINOR, + "lcd", + &lcd_fops +}; + +int lcd_init(void) +{ +unsigned long data; + + printk("%s\n", LCD_DRIVER); + misc_register(&lcd_dev); + + /* Check region? Naaah! Just snarf it up. */ +/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ + + udelay(150); + data = LCDReadData; + if ( (data & 0x000000FF) == (0x00) ) { + lcd_present = 0; + printk("LCD Not Present\n"); + } + else { + lcd_present = 1; + WRITE_GAL( kGal_DevBank2PReg, kGal_DevBank2Cfg ); + WRITE_GAL( kGal_DevBank3PReg, kGal_DevBank3Cfg ); + } + + return 0; +} + + +// +// Function: dqpoll +// +// Description: Polls the data lines to see if the flash is busy +// +// In: address, byte data +// +// Out: 0 = busy, 1 = write or erase complete +// +// + +int dqpoll( volatile unsigned long address, volatile unsigned char data ) { + +volatile unsigned char dq7; + +dq7 = data & 0x80; + +return ( (READ_FLASH(address) & 0x80) == dq7 ); + +} + + +// +// Function: timeout +// +// Description: Checks to see if erase or write has timed out +// By polling dq5 +// +// In: address +// +// +// Out: 0 = not timed out, 1 = timed out + +int timeout( volatile unsigned long address ) { + + +return ( (READ_FLASH(address) & 0x20) == 0x20 ); + +} + + + diff -urN linux-2.4.18/drivers/char/lcd.h linux-2.4.19-pre5/drivers/char/lcd.h --- linux-2.4.18/drivers/char/lcd.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/lcd.h Sat Mar 30 22:55:28 2002 @@ -0,0 +1,184 @@ +/* + * LED, LCD and Button panel driver for Cobalt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +// function headers + +int dqpoll( volatile unsigned long, volatile unsigned char ); +int timeout( volatile unsigned long ); + +#define LCD_CHARS_PER_LINE 40 +#define FLASH_SIZE 524288 +#define MAX_IDLE_TIME 120 + +struct lcd_display { + unsigned long buttons; + int size1; + int size2; + unsigned char line1[LCD_CHARS_PER_LINE]; + unsigned char line2[LCD_CHARS_PER_LINE]; + unsigned char cursor_address; + unsigned char character; + unsigned char leds; + unsigned char *RomImage; +}; + + + +#define LCD_DRIVER "Cobalt LCD Driver v2.10" + +#define kLCD_IR 0xBF000000 +#define kLCD_DR 0xBF000010 +#define kGPI 0xBD000000 +#define kLED 0xBC000000 + +#define kDD_R00 0x00 +#define kDD_R01 0x27 +#define kDD_R10 0x40 +#define kDD_R11 0x67 + +#define kLCD_Addr 0x00000080 + +#define LCDTimeoutValue 0xfff + + +// Flash definitions AMD 29F040 +#define kFlashBase 0xBFC00000 + +#define kFlash_Addr1 0x5555 +#define kFlash_Addr2 0x2AAA +#define kFlash_Data1 0xAA +#define kFlash_Data2 0x55 +#define kFlash_Prog 0xA0 +#define kFlash_Erase3 0x80 +#define kFlash_Erase6 0x10 +#define kFlash_Read 0xF0 + +#define kFlash_ID 0x90 +#define kFlash_VenAddr 0x00 +#define kFlash_DevAddr 0x01 +#define kFlash_VenID 0x01 +#define kFlash_DevID 0xA4 // 29F040 +//#define kFlash_DevID 0xAD // 29F016 + + +// Macros + +#define LCDWriteData(x) (*(volatile unsigned long *) kLCD_DR) = (x << 24) +#define LCDWriteInst(x) (*(volatile unsigned long *) kLCD_IR) = (x << 24) + +#define LCDReadData (((*(volatile unsigned long *) kLCD_DR) >> 24)) +#define LCDReadInst (((*(volatile unsigned long *) kLCD_IR) >> 24)) + +#define GPIRead (( (*(volatile unsigned long *) kGPI) >> 24)) + +#define LEDSet(x) (*(volatile unsigned char *) kLED) = ((char)x) + +#define WRITE_GAL(x,y) (*((volatile unsigned long *) (0xB4000000 | (x)) ) =y) +#define BusyCheck() while ((LCDReadInst & 0x80) == 0x80) + +#define WRITE_FLASH(x,y) (*((volatile unsigned char *) (kFlashBase | (x)) ) = y) +#define READ_FLASH(x) *((volatile unsigned char *) (kFlashBase | (x)) ) + + + +/* + * Function command codes for io_ctl. + */ +#define LCD_On 1 +#define LCD_Off 2 +#define LCD_Clear 3 +#define LCD_Reset 4 +#define LCD_Cursor_Left 5 +#define LCD_Cursor_Right 6 +#define LCD_Disp_Left 7 +#define LCD_Disp_Right 8 +#define LCD_Get_Cursor 9 +#define LCD_Set_Cursor 10 +#define LCD_Home 11 +#define LCD_Read 12 +#define LCD_Write 13 +#define LCD_Cursor_Off 14 +#define LCD_Cursor_On 15 +#define LCD_Get_Cursor_Pos 16 +#define LCD_Set_Cursor_Pos 17 +#define LCD_Blink_Off 18 + +#define LED_Set 40 +#define LED_Bit_Set 41 +#define LED_Bit_Clear 42 + + +// Button defs +#define BUTTON_Read 50 + +// Flash command codes +#define FLASH_Erase 60 +#define FLASH_Burn 61 +#define FLASH_Read 62 + + +// Ethernet LINK check hackaroo +#define LINK_Check 90 +#define LINK_Check_2 91 + +// Button patterns _B - single layer lcd boards + +#define BUTTON_NONE 0x3F +#define BUTTON_NONE_B 0xFE + +#define BUTTON_Left 0x3B +#define BUTTON_Left_B 0xFA + +#define BUTTON_Right 0x37 +#define BUTTON_Right_B 0xDE + +#define BUTTON_Up 0x2F +#define BUTTON_Up_B 0xF6 + +#define BUTTON_Down 0x1F +#define BUTTON_Down_B 0xEE + +#define BUTTON_Next 0x3D +#define BUTTON_Next_B 0x7E + +#define BUTTON_Enter 0x3E +#define BUTTON_Enter_B 0xBE + +#define BUTTON_Reset_B 0xFC + + +// debounce constants + +#define BUTTON_SENSE 160000 +#define BUTTON_DEBOUNCE 5000 + + +// Galileo register stuff + +#define kGal_DevBank2Cfg 0x1466DB33 +#define kGal_DevBank2PReg 0x464 +#define kGal_DevBank3Cfg 0x146FDFFB +#define kGal_DevBank3PReg 0x468 + +// Network + +#define kIPADDR 1 +#define kNETMASK 2 +#define kGATEWAY 3 +#define kDNS 4 + +#define kClassA 5 +#define kClassB 6 +#define kClassC 7 + diff -urN linux-2.4.18/drivers/char/lp.c linux-2.4.19-pre5/drivers/char/lp.c --- linux-2.4.18/drivers/char/lp.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/lp.c Sat Mar 30 22:55:28 2002 @@ -270,7 +270,7 @@ return error; } -static int lp_wait_ready(int minor) +static int lp_wait_ready(int minor, int nonblock) { int error = 0; @@ -281,7 +281,7 @@ do { error = lp_check_status (minor); - if (error && (LP_F(minor) & LP_ABORT)) + if (error && (nonblock || (LP_F(minor) & LP_ABORT))) break; if (signal_pending (current)) { error = -EINTR; @@ -300,6 +300,8 @@ ssize_t retv = 0; ssize_t written; size_t copy_size = count; + int nonblock = ((file->f_flags & O_NONBLOCK) || + (LP_F(minor) & LP_ABORT)); #ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) @@ -326,9 +328,10 @@ lp_table[minor].best_mode); parport_set_timeout (lp_table[minor].dev, - lp_table[minor].timeout); + (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK + : lp_table[minor].timeout)); - if ((retv = lp_wait_ready (minor)) == 0) + if ((retv = lp_wait_ready (minor, nonblock)) == 0) do { /* Write the data. */ written = parport_write (port, kbuf, copy_size); @@ -354,12 +357,16 @@ IEEE1284_MODE_COMPAT); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; - error = lp_wait_ready (minor); + error = lp_wait_ready (minor, nonblock); if (error) { if (retv == 0) retv = error; break; + } else if (nonblock) { + if (retv == 0) + retv = -EAGAIN; + break; } parport_yield_blocking (lp_table[minor].dev); @@ -407,6 +414,8 @@ struct parport *port = lp_table[minor].dev->port; ssize_t retval = 0; char *kbuf = lp_table[minor].lp_buffer; + int nonblock = ((file->f_flags & O_NONBLOCK) || + (LP_F(minor) & LP_ABORT)); if (count > LP_BUFFER_SIZE) count = LP_BUFFER_SIZE; @@ -415,7 +424,54 @@ return -EINTR; lp_claim_parport_or_block (&lp_table[minor]); - retval = parport_read (port, kbuf, count); + + parport_set_timeout (lp_table[minor].dev, + (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK + : lp_table[minor].timeout)); + + parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); + if (parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_NIBBLE)) { + retval = -EIO; + goto out; + } + + while (retval == 0) { + retval = parport_read (port, kbuf, count); + + if (retval > 0) + break; + + if (nonblock) { + retval = -EAGAIN; + break; + } + + /* Wait for data. */ + + if (lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE) { + parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_COMPAT); + lp_error (minor); + if (parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_NIBBLE)) { + retval = -EIO; + goto out; + } + } else + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + + if (signal_pending (current)) { + retval = -ERESTARTSYS; + break; + } + + if (current->need_resched) + schedule (); + } + parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); + out: lp_release_parport (&lp_table[minor]); if (retval > 0 && copy_to_user (buf, kbuf, retval)) @@ -476,7 +532,6 @@ printk (KERN_INFO "lp%d: ECP mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_ECP; } else { - printk (KERN_INFO "lp%d: compatibility mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_COMPAT; } /* Leave peripheral in compatibility mode */ diff -urN linux-2.4.18/drivers/char/mem.c linux-2.4.19-pre5/drivers/char/mem.c --- linux-2.4.18/drivers/char/mem.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.19-pre5/drivers/char/mem.c Sat Mar 30 22:55:34 2002 @@ -323,7 +323,7 @@ return virtr + wrote; } -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -550,7 +550,7 @@ write: write_null, }; -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) static struct file_operations port_fops = { llseek: memory_lseek, read: read_port, @@ -584,7 +584,7 @@ case 3: filp->f_op = &null_fops; break; -#if !defined(__mc68000__) +#if defined(CONFIG_ISA) || !defined(__mc68000__) case 4: filp->f_op = &port_fops; break; @@ -621,7 +621,9 @@ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, +#if defined(CONFIG_ISA) || !defined(__mc68000__) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, +#endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, {7, "full", S_IRUGO | S_IWUGO, &full_fops}, {8, "random", S_IRUGO | S_IWUSR, &random_fops}, diff -urN linux-2.4.18/drivers/char/misc.c linux-2.4.19-pre5/drivers/char/misc.c --- linux-2.4.18/drivers/char/misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/misc.c Sat Mar 30 22:55:28 2002 @@ -76,6 +76,7 @@ extern int pmu_device_init(void); extern int tosh_init(void); extern int i8k_init(void); +extern int lcd_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -276,6 +277,9 @@ #endif #ifdef CONFIG_TOSHIBA tosh_init(); +#endif +#ifdef CONFIG_COBALT_LCD + lcd_init(); #endif #ifdef CONFIG_I8K i8k_init(); diff -urN linux-2.4.18/drivers/char/mk712.c linux-2.4.19-pre5/drivers/char/mk712.c --- linux-2.4.18/drivers/char/mk712.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/mk712.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,505 @@ +/* -*- c -*- --------------------------------------------------------- * + * + * linux/drivers/char/mk712.c + * + * Copyright 1999-2002 Transmeta Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver supports the MK712 touch screen. + * based on busmouse.c, pc_keyb.c, and other mouse drivers + * + * 1999-12-18: original version, Daniel Quinlan + * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll + * to use queue_empty, Nathan Laredo + * 1999-12-20: improved random point rejection, Nathan Laredo + * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed + * queue code, added module options, other fixes, Daniel Quinlan + * 2002-03-15: Clean up for kernel merge + * Fixed multi open race, fixed memory checks, fixed resource + * allocation, fixed close/powerdown bug, switched to new init + * + * ------------------------------------------------------------------------- */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DEBUG(x) x +#define SQUARE(x) ((x)*(x)) + +#define MK712_DEFAULT_IO 0x260 /* demo board: 0x200, 0x208, 0x300 */ +#define MK712_DEFAULT_IRQ 10 /* demo board: 10, 12, 14 or 15 */ + +/* eight 8-bit registers */ +#define MK712_STATUS_LOW 0 /* READ */ +#define MK712_STATUS_HIGH 1 /* READ */ +#define MK712_X_LOW 2 /* READ */ +#define MK712_X_HIGH 3 /* READ */ +#define MK712_Y_LOW 4 /* READ */ +#define MK712_Y_HIGH 5 /* READ */ +#define MK712_CONTROL 6 /* R/W */ +#define MK712_RATE 7 /* R/W */ + +/* status */ +#define MK712_STATUS_TOUCH 0x10 +#define MK712_CONVERSION_COMPLETE 0x80 + +#define MK712_ENABLE_INT 0x01 /* enable interrupts */ +#define MK712_INT_ON_CONVERSION_COMPLETE 0x02 /* if bit 0 = 1 */ +#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_A 0x04 /* if bit 0 = 1 */ +#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B 0x08 /* if bit 0 = 1 */ +#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10 +#define MK712_READ_ONE_POINT 0x20 +#define MK712_POWERDOWN_A 0x40 +#define MK712_POWERDOWN_B 0x80 + +#define MK712_BUF_SIZE 256 /* a page */ + +struct mk712_packet { + unsigned int header; + unsigned int x; + unsigned int y; + unsigned int reserved; +}; + +struct mk712_queue { + unsigned long head; + unsigned long tail; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + struct mk712_packet buf[256]; +}; + +#ifdef MODULE +static int io = 0; +static int irq = 0; +#endif +static int mk712_io = MK712_DEFAULT_IO; +static int mk712_irq = MK712_DEFAULT_IRQ; +static int mk712_users = 0; +static spinlock_t mk712_lock = SPIN_LOCK_UNLOCKED; +static struct mk712_queue *queue; /* mouse data buffer */ + +static struct mk712_packet get_from_queue(void) +{ + struct mk712_packet result; + unsigned long flags; + + spin_lock_irqsave(&mk712_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (MK712_BUF_SIZE-1); + spin_unlock_irqrestore(&mk712_lock, flags); + return result; +} + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int mk712_fasync(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + +static void mk712_output_packet(struct mk712_packet data) +{ + int head = queue->head; + + queue->buf[head] = data; + head = (head + 1) & (MK712_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } +} + +static int points = 0; /* number of stored points */ +static int output_point = 0; /* did I output a point since last release? */ + +static void mk712_output_point(int x, int y) +{ + struct mk712_packet t; + + t.header = 0; + t.x = x; + t.y = y; + t.reserved = 0; + + mk712_output_packet(t); + output_point = 1; +} + +static void mk712_store_point(int x_new, int y_new) +{ + static int x[3], y[3]; + int x_out, y_out; + + x[points] = x_new; + y[points] = y_new; + + if (points == 1 && abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88) + { + x_out = (x[0] + x[1]) >> 1; + y_out = (y[0] + y[1]) >> 1; + mk712_output_point(x_out, y_out); + } + + if (points == 2) { + if ((abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88) && + (abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88)) + { + x_out = (x[0] + x[1] + x[2]) / 3; + y_out = (y[0] + y[1] + y[2]) / 3; + mk712_output_point(x_out, y_out); + } + else if (abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88) + { + x_out = (x[1] + x[2]) >> 1; + y_out = (y[1] + y[2]) >> 1; + mk712_output_point(x_out, y_out); + } + else + { + int x_avg, y_avg, d0, d1, d2; + + x_avg = (x[0] + x[1] + x[2]) / 3; + y_avg = (y[0] + y[1] + y[2]) / 3; + + d0 = SQUARE(x[0] - x_avg) + SQUARE(y[0] - y_avg); + d1 = SQUARE(x[1] - x_avg) + SQUARE(y[1] - y_avg); + d2 = SQUARE(x[2] - x_avg) + SQUARE(y[2] - y_avg); + + if (d2 > d1 && d2 > d0) + { + x_out = (x[0] + x[1]) >> 1; + y_out = (y[0] + y[1]) >> 1; + } + if (d1 > d0 && d1 > d2) + { + x_out = (x[0] + x[2]) >> 1; + y_out = (y[0] + y[2]) >> 1; + } + else + { + x_out = (x[1] + x[2]) >> 1; + y_out = (y[1] + y[2]) >> 1; + } + + mk712_output_point(x_out, y_out); + + x[0] = x[1]; + x[1] = x[2]; + y[0] = y[1]; + y[1] = y[2]; + } + } + else + { + points++; + } +} + +static void mk712_release_event(void) +{ + struct mk712_packet t; + + if (!output_point) { + points = 0; + return; + } + output_point = 0; + + t.header = 1; + t.x = t.y = t.reserved = 0; + + mk712_output_packet(t); + points = 0; +} + +#define MK712_FILTER +static void mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned short x; + unsigned short y; + unsigned char status; + unsigned long flags; +#ifdef MK712_FILTER + static int drop_next = 1; +#endif + + spin_lock_irqsave(&mk712_lock, flags); + + status = inb(mk712_io + MK712_STATUS_LOW); + + if (!(status & MK712_CONVERSION_COMPLETE)) { +#ifdef MK712_FILTER + drop_next = 1; +#endif + return; + } + if (!(status & MK712_STATUS_TOUCH)) /* release event */ + { +#ifdef MK712_FILTER + drop_next = 1; +#endif + mk712_release_event(); + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); + + return; + } + + x = inw(mk712_io + MK712_X_LOW) & 0x0fff; + y = inw(mk712_io + MK712_Y_LOW) & 0x0fff; + +#ifdef MK712_FILTER + if (drop_next) + { + drop_next = 0; + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); + + return; + } +#endif + + x = inw(mk712_io + MK712_X_LOW) & 0x0fff; + y = inw(mk712_io + MK712_Y_LOW) & 0x0fff; + + mk712_store_point(x, y); + + spin_unlock_irqrestore(&mk712_lock, flags); + wake_up_interruptible(&queue->proc_list); +} + +static int mk712_open(struct inode *inode, struct file *file) +{ + unsigned char control; + unsigned long flags; + + control = 0; + + spin_lock_irqsave(&mk712_lock, flags); + if(!mk712_users++) + { + outb(0, mk712_io + MK712_CONTROL); + + control |= (MK712_ENABLE_INT | + MK712_INT_ON_CONVERSION_COMPLETE | + MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B | + MK712_ENABLE_PERIODIC_CONVERSIONS | + MK712_POWERDOWN_A); + outb(control, mk712_io + MK712_CONTROL); + + outb(10, mk712_io + MK712_RATE); /* default count = 10 */ + + queue->head = queue->tail = 0; /* Flush input queue */ + } + spin_unlock_irqrestore(&mk712_lock, flags); + return 0; +} + +static int mk712_close(struct inode * inode, struct file * file) { + /* power down controller */ + unsigned long flags; + spin_lock_irqsave(&mk712_lock, flags); + if(--mk712_users==0) + outb(0, mk712_io + MK712_CONTROL); + spin_unlock_irqrestore(&mk712_lock, flags); + return 0; +} + +static unsigned int mk712_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &queue->proc_list, wait); + if(!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +static int mk712_ioctl(struct inode *inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + if (!inode) + BUG(); + return -ENOTTY; +} + + +static ssize_t mk712_read(struct file *file, char *buffer, + size_t count, loff_t *pos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t bytes_read = 0; + struct mk712_packet p; + + /* wait for an event */ + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + + while (bytes_read < count && !queue_empty()) { + p = get_from_queue(); + if (copy_to_user (buffer+bytes_read, (void *) &p, sizeof(p))) + { + bytes_read = -EFAULT; + break; + } + bytes_read += sizeof(p); + } + + if (bytes_read > 0) + { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return bytes_read; + } + + if (signal_pending(current)) + return -ERESTARTSYS; + + return bytes_read; +} + +static ssize_t mk712_write(struct file *file, const char *buffer, size_t count, + loff_t *ppos) +{ + return -EINVAL; +} + +struct file_operations mk712_fops = { + owner: THIS_MODULE, + read: mk712_read, + write: mk712_write, + poll: mk712_poll, + ioctl: mk712_ioctl, + open: mk712_open, + release: mk712_close, + fasync: mk712_fasync, +}; + +static struct miscdevice mk712_touchscreen = { + MK712_MINOR, "mk712_touchscreen", &mk712_fops +}; + +int __init mk712_init(void) +{ +#ifdef MODULE + if (io) + mk712_io = io; + if (irq) + mk712_irq = irq; +#endif + + if(request_region(mk712_io, 8, "mk712_touchscreen")) + { + printk("mk712: unable to get IO region\n"); + return -ENODEV; + } + + /* set up wait queue */ + queue = (struct mk712_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if(queue == NULL) + { + release_region(mk712_io, 8); + return -ENOMEM; + } + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + /* The MK712 is ISA and hard-coded to a particular IRQ, so the + driver should keep the IRQ as long as it is loaded. */ + if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712_touchscreen", + queue)) + { + printk("mk712: unable to get IRQ\n"); + release_region(mk712_io, 8); + kfree(queue); + return -EBUSY; + } + + /* register misc device */ + if(misc_register(&mk712_touchscreen)<0) + { + release_region(mk712_io, 8); + kfree(queue); + free_irq(mk712_irq, queue); + return -ENODEV; + } + return 0; +} + +static void __exit mk712_exit(void) +{ + misc_deregister(&mk712_touchscreen); + release_region(mk712_io, 8); + free_irq(mk712_irq, queue); + kfree(queue); + printk(KERN_INFO "mk712 touchscreen uninstalled\n"); +} + +MODULE_AUTHOR("Daniel Quinlan"); +MODULE_DESCRIPTION("MK712 touch screen driver"); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O base address of MK712 touch screen controller"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ of MK712 touch screen controller"); +MODULE_LICENSE("GPL"); + +module_init(mk712_init); +module_exit(mk712_exit); + +/* + * Local variables: + * c-file-style: "linux" + * End: + */ diff -urN linux-2.4.18/drivers/char/mxser.c linux-2.4.19-pre5/drivers/char/mxser.c --- linux-2.4.18/drivers/char/mxser.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/mxser.c Sat Mar 30 22:55:28 2002 @@ -32,6 +32,9 @@ * version : 1.2 * * Fixes for C104H/PCI by Tim Hockin + * Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards + * by Damian Wrobel + * */ #include @@ -62,7 +65,7 @@ #include #include -#define MXSER_VERSION "1.2" +#define MXSER_VERSION "1.2.1" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -115,10 +118,22 @@ #ifndef PCI_DEVICE_ID_C104 #define PCI_DEVICE_ID_C104 0x1040 #endif +#ifndef PCI_DEVICE_ID_CP132 +#define PCI_DEVICE_ID_CP132 0x1320 +#endif +#ifndef PCI_DEVICE_ID_CP114 +#define PCI_DEVICE_ID_CP114 0x1141 +#endif +#ifndef PCI_DEVICE_ID_CT114 +#define PCI_DEVICE_ID_CT114 0x1140 +#endif #define C168_ASIC_ID 1 #define C104_ASIC_ID 2 +#define CI134_ASIC_ID 3 +#define CI132_ASIC_ID 4 #define CI104J_ASIC_ID 5 +#define C102_ASIC_ID 0xB enum { MXSER_BOARD_C168_ISA = 0, @@ -126,6 +141,12 @@ MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, MXSER_BOARD_C104_PCI, + MXSER_BOARD_C102_ISA, + MXSER_BOARD_CI132, + MXSER_BOARD_CI134, + MXSER_BOARD_CP132_PCI, + MXSER_BOARD_CP114_PCI, + MXSER_BOARD_CT114_PCI }; static char *mxser_brdname[] = @@ -135,6 +156,12 @@ "CI-104J series", "C168H/PCI series", "C104H/PCI series", + "C102 series", + "CI-132 series", + "CI-134 series", + "CP-132 series", + "CP-114 series", + "CT-114 series" }; static int mxser_numports[] = @@ -144,6 +171,12 @@ 4, 8, 4, + 2, + 2, + 4, + 2, + 4, + 4 }; /* @@ -164,6 +197,12 @@ MXSER_BOARD_C168_PCI }, { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CP132_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CP114_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CT114_PCI }, { 0 } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); @@ -2304,6 +2343,12 @@ hwconf->board_type = MXSER_BOARD_C168_ISA; else if (id == C104_ASIC_ID) hwconf->board_type = MXSER_BOARD_C104_ISA; + else if (id == C102_ASIC_ID) + hwconf->board_type = MXSER_BOARD_C102_ISA; + else if (id == CI132_ASIC_ID) + hwconf->board_type = MXSER_BOARD_CI132; + else if (id == CI134_ASIC_ID) + hwconf->board_type = MXSER_BOARD_CI134; else if (id == CI104J_ASIC_ID) hwconf->board_type = MXSER_BOARD_CI104J; else @@ -2415,7 +2460,8 @@ (void) inb(port); restore_flags(flags); id = inb(port + 1) & 0x1F; - if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID)) + if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID) && + (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID)) return (-1); for (i = 0, j = 0; i < 4; i++) { n = inb(port + 2); diff -urN linux-2.4.18/drivers/char/nvram.c linux-2.4.19-pre5/drivers/char/nvram.c --- linux-2.4.18/drivers/char/nvram.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/nvram.c Sat Mar 30 22:55:34 2002 @@ -320,7 +320,7 @@ return( 0 ); default: - return( -EINVAL ); + return( -ENOTTY ); } } diff -urN linux-2.4.18/drivers/char/pc_keyb.c linux-2.4.19-pre5/drivers/char/pc_keyb.c --- linux-2.4.18/drivers/char/pc_keyb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/pc_keyb.c Sat Mar 30 22:55:34 2002 @@ -1215,3 +1215,26 @@ } #endif /* CONFIG_PSMOUSE */ + + +/* Tell the user who may be running in X and not see the console that we have + panic'ed. This is to distingush panics from "real" lockups. + Could in theory send the panic message as morse, but that is left as an + exercise for the reader. */ +void panic_blink(void) +{ + static unsigned long last_jiffie; + static char led; + /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is + different. */ + if (jiffies - last_jiffie > HZ/2) { + led ^= 0x01 | 0x04; + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + kbd_write_output(KBD_CMD_SET_LEDS); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + mdelay(1); + kbd_write_output(led); + last_jiffie = jiffies; + } +} diff -urN linux-2.4.18/drivers/char/pcwd.c linux-2.4.19-pre5/drivers/char/pcwd.c --- linux-2.4.18/drivers/char/pcwd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/pcwd.c Sat Mar 30 22:55:28 2002 @@ -40,6 +40,8 @@ * fairly useless proc entry. * 990610 removed said useless proc code for the merge * 000403 Removed last traces of proc code. + * 020210 Backported 2.5 open_allowed changes, and got rid of a useless + * variable */ #include @@ -100,7 +102,8 @@ #define WD_SRLY2 0x80 /* Software external relay triggered */ static int current_readport, revision, temp_panic; -static int is_open, initial_status, supports_temp, mode_debug; +static atomic_t open_allowed = ATOMIC_INIT(1); +static int initial_status, supports_temp, mode_debug; static spinlock_t io_lock; /* @@ -237,7 +240,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int i, cdat, rv; + int cdat, rv; static struct watchdog_info ident= { WDIOF_OVERHEAT|WDIOF_CARDRESET, @@ -250,8 +253,9 @@ return -ENOTTY; case WDIOC_GETSUPPORT: - i = copy_to_user((void*)arg, &ident, sizeof(ident)); - return i ? -EFAULT : 0; + if(copy_to_user((void*)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; case WDIOC_GETSTATUS: spin_lock(&io_lock); @@ -402,8 +406,10 @@ switch (MINOR(ino->i_rdev)) { case WATCHDOG_MINOR: - if (is_open) + if (!atomic_dec_and_test(&open_allowed)){ + atomic_inc(&open_allowed); return -EBUSY; + } MOD_INC_USE_COUNT; /* Enable the port */ if (revision == PCWD_REVISION_C) @@ -412,7 +418,6 @@ outb_p(0x00, current_readport + 3); spin_unlock(&io_lock); } - is_open = 1; return(0); case TEMP_MINOR: return(0); @@ -452,8 +457,6 @@ { if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) { - lock_kernel(); - is_open = 0; #ifndef CONFIG_WATCHDOG_NOWAYOUT /* Disable the board */ if (revision == PCWD_REVISION_C) { @@ -463,7 +466,7 @@ spin_unlock(&io_lock); } #endif - unlock_kernel(); + atomic_inc(&open_allowed); } return 0; } @@ -574,7 +577,6 @@ printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); /* Initial variables */ - is_open = 0; supports_temp = 0; mode_debug = 0; temp_panic = 0; diff -urN linux-2.4.18/drivers/char/ppdev.c linux-2.4.19-pre5/drivers/char/ppdev.c --- linux-2.4.18/drivers/char/ppdev.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/ppdev.c Sat Mar 30 22:55:28 2002 @@ -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-2000 Tim Waugh + * Copyright (C) 1998-2000, 2002 Tim Waugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -80,6 +80,7 @@ unsigned char irqctl; struct ieee1284_info state; struct ieee1284_info saved_state; + long default_inactivity; }; /* pp_struct.flags bitfields */ @@ -107,7 +108,6 @@ struct pp_struct *pp = file->private_data; char * kbuffer; ssize_t bytes_read = 0; - ssize_t got = 0; struct parport *pport; int mode; @@ -125,8 +125,13 @@ pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - while (bytes_read < count) { - ssize_t need = min_t(unsigned long, count - bytes_read, PP_BUFFER_SIZE); + parport_set_timeout (pp->pdev, + (file->f_flags & O_NONBLOCK) ? + PARPORT_INACTIVITY_O_NONBLOCK : + pp->default_inactivity); + + while (bytes_read == 0) { + ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE); if (mode == IEEE1284_MODE_EPP) { /* various specials for EPP mode */ @@ -144,37 +149,33 @@ } else { fn = pport->ops->epp_read_data; } - got = (*fn)(pport, kbuffer, need, flags); + bytes_read = (*fn)(pport, kbuffer, need, flags); } else { - got = parport_read (pport, kbuffer, need); + bytes_read = parport_read (pport, kbuffer, need); } - if (got <= 0) { - if (!bytes_read) { - bytes_read = got; - } + if (bytes_read != 0) break; - } - if (copy_to_user (buf + bytes_read, kbuffer, got)) { - bytes_read = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + bytes_read = -EAGAIN; break; } - bytes_read += got; - if (signal_pending (current)) { - if (!bytes_read) { - bytes_read = -EINTR; - } + bytes_read = -ERESTARTSYS; break; } - if (current->need_resched) { + if (current->need_resched) schedule (); - } } + parport_set_timeout (pp->pdev, pp->default_inactivity); + + if (bytes_read > 0 && copy_to_user (buf, kbuffer, bytes_read)) + bytes_read = -EFAULT; + kfree (kbuffer); pp_enable_irq (pp); return bytes_read; @@ -205,6 +206,11 @@ pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); + parport_set_timeout (pp->pdev, + (file->f_flags & O_NONBLOCK) ? + PARPORT_INACTIVITY_O_NONBLOCK : + pp->default_inactivity); + while (bytes_written < count) { ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE); @@ -235,6 +241,12 @@ bytes_written += wrote; + if (file->f_flags & O_NONBLOCK) { + if (!bytes_written) + bytes_written = -EAGAIN; + break; + } + if (signal_pending (current)) { if (!bytes_written) { bytes_written = -EINTR; @@ -247,6 +259,8 @@ } } + parport_set_timeout (pp->pdev, pp->default_inactivity); + kfree (kbuffer); pp_enable_irq (pp); return bytes_written; @@ -356,6 +370,8 @@ pp->saved_state.phase = info->phase; info->mode = pp->state.mode; info->phase = pp->state.phase; + pp->default_inactivity = parport_set_timeout (pp->pdev, 0); + parport_set_timeout (pp->pdev, pp->default_inactivity); return 0; } diff -urN linux-2.4.18/drivers/char/qtronix.c linux-2.4.19-pre5/drivers/char/qtronix.c --- linux-2.4.18/drivers/char/qtronix.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/qtronix.c Sat Mar 30 22:55:28 2002 @@ -51,6 +51,7 @@ #ifdef CONFIG_QTRONIX_KEYBOARD +#include #include #include #include @@ -121,7 +122,7 @@ }; -void init_qtronix_990P_kbd(void) +void __init init_qtronix_990P_kbd(void) { int retval; @@ -594,4 +595,5 @@ return 0; } +module_init(init_qtronix_990P_kbd); #endif diff -urN linux-2.4.18/drivers/char/qtronixmap.c linux-2.4.19-pre5/drivers/char/qtronixmap.c --- linux-2.4.18/drivers/char/qtronixmap.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/qtronixmap.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,265 @@ + +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f, + 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, + 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61, + 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, + 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f, + 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, + 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41, + 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, + 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200, + 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, + 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111, + 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, + 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, + 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61, + 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, + 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008, + 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, + 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001, + 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, + 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, + 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001, + 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f, + 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, + 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861, + 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b, + 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, + 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, + 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801, + 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, + 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', 'À'}, {'`', 'a', 'à'}, + {'\'', 'A', 'Á'}, {'\'', 'a', 'á'}, + {'^', 'A', 'Â'}, {'^', 'a', 'â'}, + {'~', 'A', 'Ã'}, {'~', 'a', 'ã'}, + {'"', 'A', 'Ä'}, {'"', 'a', 'ä'}, + {'O', 'A', 'Å'}, {'o', 'a', 'å'}, + {'0', 'A', 'Å'}, {'0', 'a', 'å'}, + {'A', 'A', 'Å'}, {'a', 'a', 'å'}, + {'A', 'E', 'Æ'}, {'a', 'e', 'æ'}, + {',', 'C', 'Ç'}, {',', 'c', 'ç'}, + {'`', 'E', 'È'}, {'`', 'e', 'è'}, + {'\'', 'E', 'É'}, {'\'', 'e', 'é'}, + {'^', 'E', 'Ê'}, {'^', 'e', 'ê'}, + {'"', 'E', 'Ë'}, {'"', 'e', 'ë'}, + {'`', 'I', 'Ì'}, {'`', 'i', 'ì'}, + {'\'', 'I', 'Í'}, {'\'', 'i', 'í'}, + {'^', 'I', 'Î'}, {'^', 'i', 'î'}, + {'"', 'I', 'Ï'}, {'"', 'i', 'ï'}, + {'-', 'D', 'Ð'}, {'-', 'd', 'ð'}, + {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'}, + {'`', 'O', 'Ò'}, {'`', 'o', 'ò'}, + {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'}, + {'^', 'O', 'Ô'}, {'^', 'o', 'ô'}, + {'~', 'O', 'Õ'}, {'~', 'o', 'õ'}, + {'"', 'O', 'Ö'}, {'"', 'o', 'ö'}, + {'/', 'O', 'Ø'}, {'/', 'o', 'ø'}, + {'`', 'U', 'Ù'}, {'`', 'u', 'ù'}, + {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'}, + {'^', 'U', 'Û'}, {'^', 'u', 'û'}, + {'"', 'U', 'Ü'}, {'"', 'u', 'ü'}, + {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'}, + {'T', 'H', 'Þ'}, {'t', 'h', 'þ'}, + {'s', 's', 'ß'}, {'"', 'y', 'ÿ'}, + {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'}, +}; + +unsigned int accent_table_size = 68; diff -urN linux-2.4.18/drivers/char/rocket_int.h linux-2.4.19-pre5/drivers/char/rocket_int.h --- linux-2.4.18/drivers/char/rocket_int.h Sun Feb 17 11:37:11 2002 +++ linux-2.4.19-pre5/drivers/char/rocket_int.h Sat Mar 30 22:55:39 2002 @@ -185,7 +185,7 @@ /* Old clock prescale definition and baud rates associated with it */ -#define CLOCK_PRESC 0x19 */ /* mod 9 (divide by 10) prescale */ +#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ #define BRD50 4607 #define BRD75 3071 #define BRD110 2094 diff -urN linux-2.4.18/drivers/char/rtc.c linux-2.4.19-pre5/drivers/char/rtc.c --- linux-2.4.18/drivers/char/rtc.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.19-pre5/drivers/char/rtc.c Sat Mar 30 22:55:34 2002 @@ -534,7 +534,7 @@ return 0; } default: - return -EINVAL; + return -ENOTTY; } return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } diff -urN linux-2.4.18/drivers/char/sb1250_duart.c linux-2.4.19-pre5/drivers/char/sb1250_duart.c --- linux-2.4.18/drivers/char/sb1250_duart.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/sb1250_duart.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,805 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* + * Driver support for the on-chip sb1250 dual-channel serial port, + * running in asynchronous mode. Also, support for doing a serial console + * on one of those ports + * + * The non-console part of this code is based heavily on the serial_21285.c + * driver also in this directory. See tty_driver.h for a description of some + * of the driver functions, though it (like most of the inline code documentation :) + * is a bit out of date. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Toggle spewing of debugging output */ +#undef DUART_SPEW + +#define DEFAULT_CFLAGS (CS8 | B115200) + + +/* + Still not sure what the termios structures set up here are for, + but we have to supply pointers to them to register the tty driver +*/ + +static struct tty_driver sb1250_duart_driver, sb1250_duart_callout_driver; +static int ref_count; +static struct tty_struct *duart_table[2]; +static struct termios *duart_termios[2]; +static struct termios *duart_termios_locked[2]; + +/* This lock protects both the open flags for all the uart states as + well as the reference count for the module */ +static spinlock_t open_lock = SPIN_LOCK_UNLOCKED; + +/* Protect the writing stuff from contention */ +//static spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + +/* Bit fields of flags in the flags field below */ + +#define SD_WRITE_WAKE 0x000000001 + + +typedef struct { + struct tty_struct *tty; + unsigned char outp_buf[CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE]; + unsigned int outp_head; + unsigned int outp_tail; + unsigned int outp_count; + spinlock_t outp_lock; + unsigned int outp_stopped; + unsigned int open; + unsigned long flags; + unsigned int last_cflags; +} uart_state_t; + +static uart_state_t uart_states[2] = { [0 ... 1] = { + tty: 0, + outp_head: 0, + outp_tail: 0, + outp_lock: SPIN_LOCK_UNLOCKED, + outp_count: 0, + open: 0, + flags: 0, + last_cflags: 0, +}}; + +/* + * Inline functions local to this module + */ + + +/* + * Mask out the passed interrupt lines at the duart level. This should be + * called while holding the associated outp_lock. + */ +static inline void duart_mask_ints(unsigned int line, unsigned int mask) +{ + u64 tmp; + tmp = in64(IO_SPACE_BASE | A_DUART_IMRREG(line)); + tmp &= ~mask; + out64(tmp, IO_SPACE_BASE | A_DUART_IMRREG(line)); +} + + +/* Unmask the passed interrupt lines at the duart level */ +static inline void duart_unmask_ints(unsigned int line, unsigned int mask) +{ + u64 tmp; + tmp = in64(IO_SPACE_BASE | A_DUART_IMRREG(line)); + tmp |= mask; + out64(tmp, IO_SPACE_BASE | A_DUART_IMRREG(line)); +} + +static inline unsigned long get_status_reg(unsigned int line) +{ + return in64(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_STATUS)); +} + +/* Derive which uart a call is for from the passed tty line. */ +static inline unsigned int get_line(struct tty_struct *tty) +{ + unsigned int line = MINOR(tty->device) - 64; + if (line > 1) + printk(KERN_CRIT "Invalid line\n"); + + return line; +} + + + +#define MIN(a, b) (((a)<(b))?(a):(b)) + +/* + * Generic interrupt handler for both channels. dev_id is a pointer + * to the proper uart_states structure, so from that we can derive + * which port interrupted + */ + +static void duart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int line; + uart_state_t *us = (uart_state_t *)dev_id; + line = us-uart_states; +#ifdef DUART_SPEW +// setleds("INT!"); + printk("DUART INT\n"); +#endif + /* We could query the ISR to figure out why we are here, but since + we are here, we may as well just take care of both rx and tx */ + spin_lock(&us->outp_lock); + if (get_status_reg(line) & M_DUART_RX_RDY) { + do { + unsigned int status = get_status_reg(line); + unsigned int ch = in64(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_RX_HOLD)); + unsigned int flag = 0; + if (status & 0x10) { + tty_insert_flip_char(us->tty, 0, TTY_OVERRUN); } + if (status & 0x20) { + printk("Parity error!\n"); + flag = TTY_PARITY; + } else if (status & 0x40) { + printk("Frame error!\n"); + flag = TTY_FRAME; + } + tty_insert_flip_char(us->tty, ch, flag); + } while (get_status_reg(line) & M_DUART_RX_RDY); + tty_flip_buffer_push(us->tty); + } + if ((get_status_reg(line) & M_DUART_TX_RDY) && us->outp_count) { + do { + out64(us->outp_buf[us->outp_head], IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_TX_HOLD)); + us->outp_head = (us->outp_head + 1) & (CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + us->outp_count--; + } while ((get_status_reg(line) & M_DUART_TX_RDY) && us->outp_count); + + if (us->open && (us->flags & SD_WRITE_WAKE) && + (us->outp_count < (CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE/2))) { + /* We told the discipline at one point that we had no space, so it went + to sleep. Wake it up when we hit half empty */ + wake_up_interruptible(&us->tty->write_wait); + } + if (!us->outp_count) { + duart_mask_ints(line, M_DUART_IMR_TX); + } + } + spin_unlock(&us->outp_lock); +} + +/* + * Actual driver functions + */ + +/* Return the number of characters we can accomodate in a write at this instant */ +static int duart_write_room(struct tty_struct *tty) +{ + unsigned long flags; + int retval; + uart_state_t *us = &uart_states[get_line(tty)]; + + spin_lock_irqsave(&us->outp_lock, flags); + retval = CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE - uart_states[get_line(tty)].outp_count; + if (!retval) { + us->flags |= SD_WRITE_WAKE; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +#ifdef DUART_SPEW + printk("duart_write_room called, returning %i\n", retval); +#endif + return retval; +} + +/* memcpy the data from src to destination, but take extra care if the + data is coming from user space */ +static inline int copy_buf(char *dest, const char *src, int size, int from_user) +{ + if (from_user) { + (void) copy_from_user(dest, src, size); + } else { + memcpy(dest, src, size); + } + return size; +} + +/* Buffer up to count characters from buf to be written. If we don't have other + characters buffered, enable the tx interrupt to start sending */ +static int duart_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + uart_state_t *us; + unsigned long flags; + unsigned int line; + int chars_written = 0; + if (from_user && verify_area(VERIFY_READ, buf, count)) { + return -EINVAL; + } +#ifdef DUART_SPEW + printk("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm); +#endif + line = get_line(tty); + us = &uart_states[line]; + spin_lock_irqsave(&us->outp_lock, flags); + if (!count || (us->outp_count == CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE)) { + spin_unlock_irqrestore(&us->outp_lock, flags); + return 0; + } + if (us->outp_tail < us->outp_head) { + /* Straightforward case; copy from tail to head */ + chars_written += copy_buf(us->outp_buf + us->outp_tail, buf, + MIN(count, us->outp_head - us->outp_tail), from_user); + } else { + /* Copy from tail to end of buffer, wrap around and then + copy to head */ + chars_written += copy_buf(us->outp_buf + us->outp_tail, buf, + MIN(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE - us->outp_tail, count), + from_user); + if (chars_written < count) { + chars_written += copy_buf(us->outp_buf, buf + chars_written, + MIN(us->outp_head, count - chars_written), from_user); + } + } + us->outp_tail = (us->outp_tail + chars_written) &(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + if (!(us->outp_count || us->outp_stopped)) { + duart_unmask_ints(line, M_DUART_IMR_TX); + } + us->outp_count += chars_written; + spin_unlock_irqrestore(&us->outp_lock, flags); + return chars_written; +} + + +/* Buffer one character to be written. If there's not room for it, just drop + it on the floor. This is used for echo, among other things */ +static void duart_put_char(struct tty_struct *tty, u_char ch) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_put_char called. Char is %x (%c)\n", (int)ch, ch); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + if (us->outp_count != CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE) { + us->outp_buf[us->outp_tail] = ch; + us->outp_tail = (us->outp_tail + 1) &(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + if (!(us->outp_count || us->outp_stopped)) { + duart_unmask_ints(line, M_DUART_IMR_TX); + } + us->outp_count++; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +/* Return the number of characters in the output buffer that have yet to be + written */ +static int duart_chars_in_buffer(struct tty_struct *tty) +{ + int retval; + unsigned long flags; + uart_state_t *us = &uart_states[get_line(tty)]; + spin_lock_irqsave(&us->outp_lock, flags); + retval = us->outp_count; + if (retval) { + us->flags |= SD_WRITE_WAKE; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +#ifdef DUART_SPEW + printk("duart_chars_in_buffer returning %i\n", retval); +#endif + return retval; +} + +/* Kill everything we haven't yet shoved into the FIFO. Turn off the + transmit interrupt since we've nothing more to transmit */ +static void duart_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[get_line(tty)]; +#ifdef DUART_SPEW + printk("duart_flush_buffer called\n"); +#endif + duart_mask_ints(line, M_DUART_IMR_TX); + spin_lock_irqsave(&us->outp_lock, flags); + us->outp_head = us->outp_tail = us->outp_count = 0; + if (us->flags & SD_WRITE_WAKE) { + wake_up_interruptible(&us->tty->write_wait); + } + spin_unlock_irqrestore(&us->outp_lock, flags); +} + + +/* See sb1250 user manual for details on these registers */ +static inline void duart_set_cflag(unsigned int line, unsigned int cflag) +{ + unsigned int mode_reg1 = 0, mode_reg2 = 0; + unsigned int clk_divisor; + switch (cflag & CSIZE) { + case CS7: + mode_reg1 |= V_DUART_BITS_PER_CHAR_7; + + default: + /* We don't handle CS5 or CS6...is there a way we're supposed to flag this? + right now we just force them to CS8 */ + mode_reg1 |= 0x0; + break; + } + if (cflag & CSTOPB) { + mode_reg2 |= M_DUART_STOP_BIT_LEN_2; /* XXX was: 0x4; */ + } + if (!(cflag & PARENB)) { + mode_reg1 |= V_DUART_PARITY_MODE_NONE; /* XXX was: 0x8; */ + } + if (cflag & PARODD) { + mode_reg1 |= M_DUART_PARITY_TYPE_ODD; + } + + /* Formula for this is (5000000/baud)-1, but we saturate + at 12 bits, which means we can't actually do anything less + that 1200 baud */ + switch (cflag & CBAUD) { + case B200: + case B300: + case B1200: clk_divisor = 4095; break; + case B1800: clk_divisor = 2776; break; + case B2400: clk_divisor = 2082; break; + case B4800: clk_divisor = 1040; break; + default: + case B9600: clk_divisor = 519; break; + case B19200: clk_divisor = 259; break; + case B38400: clk_divisor = 129; break; + case B57600: clk_divisor = 85; break; + case B115200: clk_divisor = 42; break; + } + out64(mode_reg1, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_1)); + out64(mode_reg2, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_2)); + out64(clk_divisor, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CLK_SEL)); + uart_states[line].last_cflags = cflag; +} + + +/* Handle notification of a termios change. */ +static void duart_set_termios(struct tty_struct *tty, struct termios *old) +{ +#ifdef DUART_SPEW + printk("duart_set_termios called by %i (%s)\n", current->pid, current->comm); +#endif + if (old && tty->termios->c_cflag == old->c_cflag) + return; + duart_set_cflag(get_line(tty), tty->termios->c_cflag); +} + +/* Stop pushing stuff into the fifo, now. Do the mask under the + outp_lock to avoid races involving turning the interrupt line on/off */ +static void duart_stop(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_stop called\n"); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + duart_mask_ints(get_line(tty), M_DUART_IMR_TX); + us->outp_stopped = 1; + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +static int duart_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ +/* if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV;*/ + switch (cmd) { + case TIOCMGET: + printk("Ignoring TIOCMGET\n"); + break; + case TIOCMBIS: + printk("Ignoring TIOCMBIS\n"); + break; + case TIOCMBIC: + printk("Ignoring TIOCMBIC\n"); + break; + case TIOCMSET: + printk("Ignoring TIOCMSET\n"); + break; + case TIOCGSERIAL: + printk("Ignoring TIOCGSERIAL\n"); + break; + case TIOCSSERIAL: + printk("Ignoring TIOCSSERIAL\n"); + break; + case TIOCSERCONFIG: + printk("Ignoring TIOCSERCONFIG\n"); + break; + case TIOCSERGETLSR: /* Get line status register */ + printk("Ignoring TIOCSERGETLSR\n"); + break; + case TIOCSERGSTRUCT: + printk("Ignoring TIOCSERGSTRUCT\n"); + break; + case TIOCMIWAIT: + printk("Ignoring TIOCMIWAIT\n"); + break; + case TIOCGICOUNT: + printk("Ignoring TIOCGICOUNT\n"); + break; + case TIOCSERGWILD: + printk("Ignoring TIOCSERGWILD\n"); + break; + case TIOCSERSWILD: + printk("Ignoring TIOCSERSWILD\n"); + break; + default: + break; + } +// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm); + return -ENOIOCTLCMD; +#if 0 + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + case TIOCGSERIAL: + case TIOCSSERIAL: + case TIOCSERCONFIG: + case TIOCSERGETLSR: /* Get line status register */ + case TIOCSERGSTRUCT: + case TIOCMIWAIT: + case TIOCGICOUNT: + case TIOCSERGWILD: + case TIOCSERSWILD: + /* XXX Implement me! */ + printk("IOCTL needs implementing: %x\n", cmd); + + default: + printk("Unknown ioctl: %x\n", cmd); + } +#endif + return 0; +} + +/* Stop pushing stuff into the fifo, now. Do the mask under the + outp_lock to avoid races involving turning the interrupt line on/off */ +static void duart_start(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_start called\n"); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + if (us->outp_count) { + duart_unmask_ints(get_line(tty), M_DUART_IMR_TX); + } + us->outp_stopped = 0; + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +/* Not sure on the semantics of this; are we supposed to wait until the stuff + already in the hardware FIFO drains, or are we supposed to wait until + we've drained the output buffer, too? I'm assuming the former, 'cause thats + what the other drivers seem to assume +*/ + +static void duart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long target_time; + unsigned int line; + uart_state_t *us; +#ifdef DUART_SPEW + printk("duart_wait_until_sent(%d)+\n", timeout); +#endif + target_time = jiffies + timeout; + line = get_line(tty); + us = &uart_states[line]; + while (!(get_status_reg(line) & M_DUART_TX_EMT) && (jiffies < target_time)) { + schedule_timeout(1); + } +#ifdef DUART_SPEW + printk("duart_wait_until_sent()-\n"); +#endif +} + +/* + * Open a tty line. Note that this can be called multiple times, so ->open can + * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was + * zero + */ +static int duart_open(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + unsigned int line; + uart_state_t *us; + + MOD_INC_USE_COUNT; +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + if (get_line(tty) > 1) +#else + if (get_line(tty) > 0) +#endif + { + MOD_DEC_USE_COUNT; + return -ENODEV; + } +#ifdef DUART_SPEW + printk("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n", current->pid, current->comm, tty, + tty->read_wait, tty->write_wait); +#endif + line = get_line(tty); + tty->driver_data = NULL; + us = &uart_states[line]; + + spin_lock_irqsave(&open_lock, flags); + if (!us->open) { + us->tty = tty; + us->tty->termios->c_cflag = us->last_cflags; + } + us->open++; +#ifdef FORCED_INPUT + if (!line && (us->open == 1)) { + next_inp = inp_cmds; + init_timer(&inp_timer); + inp_timer.expires = jiffies + 20; + inp_timer.data = 0; + inp_timer.function = stuff_char; + stuff_char_tty = tty; + add_timer(&inp_timer); + } +#endif + duart_unmask_ints(line, M_DUART_IMR_RX); + spin_unlock_irqrestore(&open_lock, flags); + return 0; +} + + +/* + * Close a reference count out. If reference count hits zero, null the + * tty, kill the interrupts. The tty_io driver is responsible for making + * sure we've cleared out our internal buffers before calling close() + */ +static void duart_close(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_close called by %i (%s)\n", current->pid, current->comm); +#endif + spin_lock_irqsave(&open_lock, flags); + us->open--; +#if 0 + if (!us->open) { + /* Flushing TX stuff here is conservative */ + duart_mask_ints(line, M_DUART_IMR_IN | M_DUART_IMR_BRK | M_DUART_IMR_RX | M_DUART_IMR_TX); + spin_lock(&us->outp_lock); + us->outp_head = us->outp_tail = us->outp_count = us->outp_stopped = 0; + us->tty = NULL; + spin_unlock(&us->outp_lock); + } +#endif + ref_count--; + spin_unlock_irqrestore(&open_lock, flags); + MOD_DEC_USE_COUNT; +} + + +/* Set up the driver and register it, register the 2 1250 UART interrupts. This + is called from tty_init, or as a part of the module init */ +static int __init sb1250_duart_init(void) +{ + sb1250_duart_driver.magic = TTY_DRIVER_MAGIC; + sb1250_duart_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS + sb1250_duart_driver.name = "tts/%d"; +#else + sb1250_duart_driver.name = "ttyS"; +#endif + sb1250_duart_driver.major = TTY_MAJOR; + sb1250_duart_driver.minor_start = 64; + sb1250_duart_driver.num = 2; + sb1250_duart_driver.type = TTY_DRIVER_TYPE_SERIAL; + sb1250_duart_driver.subtype = SERIAL_TYPE_NORMAL; + sb1250_duart_driver.init_termios = tty_std_termios; + sb1250_duart_driver.flags = TTY_DRIVER_REAL_RAW; + sb1250_duart_driver.refcount = &ref_count; + sb1250_duart_driver.table = duart_table; + sb1250_duart_driver.termios = duart_termios; + sb1250_duart_driver.termios_locked = duart_termios_locked; + + sb1250_duart_driver.open = duart_open; + sb1250_duart_driver.close = duart_close; + sb1250_duart_driver.write = duart_write; + sb1250_duart_driver.put_char = duart_put_char; + sb1250_duart_driver.write_room = duart_write_room; + sb1250_duart_driver.chars_in_buffer = duart_chars_in_buffer; + sb1250_duart_driver.flush_buffer = duart_flush_buffer; + sb1250_duart_driver.ioctl = duart_ioctl; + sb1250_duart_driver.set_termios = duart_set_termios; + sb1250_duart_driver.stop = duart_stop; + sb1250_duart_driver.start = duart_start; + sb1250_duart_driver.wait_until_sent = duart_wait_until_sent; + + sb1250_duart_callout_driver = sb1250_duart_driver; +#ifdef CONFIG_DEVFS_FS + sb1250_duart_callout_driver.name = "cua/%d"; +#else + sb1250_duart_callout_driver.name = "cua"; +#endif + sb1250_duart_callout_driver.major = TTYAUX_MAJOR; + sb1250_duart_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + duart_mask_ints(0, 0xf); + if (request_irq(K_INT_UART_0, duart_int, 0, "uart0", &uart_states[0])) { + panic("Couldn't get uart0 interrupt line"); + } +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + duart_mask_ints(1, 0xf); + if (request_irq(K_INT_UART_1, duart_int, 0, "uart1", &uart_states[1])) { + panic("Couldn't get uart1 interrupt line"); + } +#endif + + /* Interrupts are now active, our ISR can be called. */ + + if (tty_register_driver(&sb1250_duart_driver)) { + printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n"); + } + if (tty_register_driver(&sb1250_duart_callout_driver)) { + printk(KERN_ERR "Couldn't register sb1250 duart callout driver\n"); + } + duart_set_cflag(0, DEFAULT_CFLAGS); +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + duart_set_cflag(1, DEFAULT_CFLAGS); +#endif + return 0; +} + +/* Unload the driver. Unregister stuff, get ready to go away */ +static void __exit sb1250_duart_fini(void) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = tty_unregister_driver(&sb1250_duart_callout_driver); + if (ret) { + printk(KERN_ERR "Unable to unregister sb1250 duart callout driver (%d)\n", ret); + } + ret = tty_unregister_driver(&sb1250_duart_driver); + if (ret) { + printk(KERN_ERR "Unable to unregister sb1250 duart serial driver (%d)\n", ret); + } + free_irq(K_INT_UART_0, &uart_states[0]); + free_irq(K_INT_UART_1, &uart_states[1]); + + /* mask lines in the scd */ + disable_irq(K_INT_UART_0); + disable_irq(K_INT_UART_1); + + restore_flags(flags); +} + +module_init(sb1250_duart_init); +module_exit(sb1250_duart_fini); +MODULE_DESCRIPTION("SB1250 Duart serial driver"); +MODULE_AUTHOR("Justin Carlson "); + +#ifdef CONFIG_SERIAL_CONSOLE + +/* + * Serial console stuff. + * Very basic, polling driver for doing serial console output. + * FIXME; there is a race here; we can't be sure that + * the tx is still empty without holding outp_lock for this line. + * Worst that can happen for now, though, is dropped characters. + */ + +static void ser_console_write(struct console *cons, const char *str, + unsigned int count) +{ + unsigned int i; + unsigned long flags; + spin_lock_irqsave(&uart_states[0].outp_lock, flags); + + for (i = 0; i < count; i++) { + if (str[i] == '\n') { + /* Expand LF -> CRLF */ + while (!(get_status_reg(0) & M_DUART_TX_RDY)) { + /* Spin, doing nothing. */ + } + out64('\r', IO_SPACE_BASE | A_DUART_CHANREG(0, R_DUART_TX_HOLD)); + } + while (!(get_status_reg(0) & M_DUART_TX_RDY)) { + /* Spin, doing nothing. */ + } + out64(str[i], IO_SPACE_BASE | A_DUART_CHANREG(0, R_DUART_TX_HOLD)); + } + spin_unlock_irqrestore(&uart_states[0].outp_lock, flags); +} + +static kdev_t ser_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int ser_console_wait_key(struct console *cons) +{ + panic("ser_console_wait_key called"); +} + +static int ser_console_setup(struct console *cons, char *str) +{ + /* Initialize the transmitter */ + + duart_set_cflag(0, DEFAULT_CFLAGS); + return 0; +} + +static struct console sb1250_ser_cons = { + name: "ttyS", + write: ser_console_write, + device: ser_console_device, + wait_key: ser_console_wait_key, + setup: ser_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init sb1250_serial_console_init(void) +{ + register_console(&sb1250_ser_cons); +} + +#endif /* CONFIG_SERIAL_CONSOLE */ diff -urN linux-2.4.18/drivers/char/sc1200wdt.c linux-2.4.19-pre5/drivers/char/sc1200wdt.c --- linux-2.4.18/drivers/char/sc1200wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/sc1200wdt.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,432 @@ +/* + * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver + * (c) Copyright 2002 Zwane Mwaikambo , + * All Rights Reserved. + * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Changelog: + * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. + * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. + * 20020222 Zwane Mwaikambo Added probing. + * 20020225 Zwane Mwaikambo Added ISAPNP support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SC1200_MODULE_VER "build 20020303" +#define SC1200_MODULE_NAME "sc1200wdt" +#define PFX SC1200_MODULE_NAME ": " + +#define MAX_TIMEOUT 255 /* 255 minutes */ +#define PMIR (io) /* Power Management Index Register */ +#define PMDR (io+1) /* Power Management Data Register */ + +/* Data Register indexes */ +#define FER1 0x00 /* Function enable register 1 */ +#define FER2 0x01 /* Function enable register 2 */ +#define PMC1 0x02 /* Power Management Ctrl 1 */ +#define PMC2 0x03 /* Power Management Ctrl 2 */ +#define PMC3 0x04 /* Power Management Ctrl 3 */ +#define WDTO 0x05 /* Watchdog timeout register */ +#define WDCF 0x06 /* Watchdog config register */ +#define WDST 0x07 /* Watchdog status register */ + +/* WDO Status */ +#define WDO_ENABLED 0x00 +#define WDO_DISABLED 0x01 + +/* WDCF bitfields - which devices assert WDO */ +#define KBC_IRQ 0x01 /* Keyboard Controller */ +#define MSE_IRQ 0x02 /* Mouse */ +#define UART1_IRQ 0x03 /* Serial0 */ +#define UART2_IRQ 0x04 /* Serial1 */ +/* 5 -7 are reserved */ + +static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER; +static int timeout = 1; +static int io = -1; +static int io_len = 2; /* for non plug and play */ +struct semaphore open_sem; +static int expect_close = 0; +spinlock_t sc1200wdt_lock; /* io port access serialisation */ + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int isapnp = 1; +static struct pci_dev *wdt_dev; +#endif + +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "io port"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +MODULE_PARM(isapnp, "i"); +MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); +#endif + + +/* Read from Data Register */ +static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data) +{ + spin_lock(&sc1200wdt_lock); + outb_p(index, PMIR); + *data = inb(PMDR); + spin_unlock(&sc1200wdt_lock); +} + + +/* Write to Data Register */ +static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) +{ + spin_lock(&sc1200wdt_lock); + outb_p(index, PMIR); + outb(data, PMDR); + spin_unlock(&sc1200wdt_lock); +} + + +/* This returns the status of the WDO signal, inactive high. + * returns WDO_ENABLED or WDO_DISABLED + */ +static inline int sc1200wdt_status(void) +{ + unsigned char ret; + + sc1200wdt_read_data(WDST, &ret); + return (ret & 0x01); /* bits 1 - 7 are undefined */ +} + + +static int sc1200wdt_open(struct inode *inode, struct file *file) +{ + unsigned char reg; + + /* allow one at a time */ + if (down_trylock(&open_sem)) + return -EBUSY; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + sc1200wdt_read_data(WDCF, ®); + /* assert WDO when any of the following interrupts are triggered too */ + reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); + sc1200wdt_write_data(WDCF, reg); + /* set the timeout and get the ball rolling */ + sc1200wdt_write_data(WDTO, timeout); + printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout); + + return 0; +} + + +static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int new_timeout; + static struct watchdog_info ident = { + options: WDIOF_SETTIMEOUT, + identity: "PC87307/PC97307" + }; + + switch (cmd) { + default: + return -ENOTTY; /* Keep Pavel Machek amused ;) */ + + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + return put_user(sc1200wdt_status(), (int *)arg); + + case WDIOC_KEEPALIVE: + sc1200wdt_write_data(WDTO, timeout); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) + return -EFAULT; + + /* the API states this is given in secs */ + new_timeout /= 60; + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + + timeout = new_timeout; + sc1200wdt_write_data(WDTO, timeout); + /* fall through and return the new timeout */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout * 60, (int *)arg); + } +} + + +static int sc1200wdt_release(struct inode *inode, struct file *file) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + if (expect_close) { + sc1200wdt_write_data(WDTO, 0); + printk(KERN_INFO PFX "Watchdog disabled\n"); + } else { + sc1200wdt_write_data(WDTO, timeout); + printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout); + } +#endif + up(&open_sem); + + return 0; +} + + +static ssize_t sc1200wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + size_t i; + + expect_close = 0; + + for (i = 0; i != len; i++) + { + if (data[i] == 'V') + expect_close = 1; + } +#endif + sc1200wdt_write_data(WDTO, timeout); + return len; + } + + return 0; +} + + +static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + sc1200wdt_write_data(WDTO, 0); + + return NOTIFY_DONE; +} + + +static struct notifier_block sc1200wdt_notifier = +{ + notifier_call: sc1200wdt_notify_sys +}; + +static struct file_operations sc1200wdt_fops = +{ + owner: THIS_MODULE, + write: sc1200wdt_write, + ioctl: sc1200wdt_ioctl, + open: sc1200wdt_open, + release: sc1200wdt_release +}; + +static struct miscdevice sc1200wdt_miscdev = +{ + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &sc1200wdt_fops +}; + + +static int __init sc1200wdt_probe(void) +{ + /* The probe works by reading the PMC3 register's default value of 0x0e + * there is one caveat, if the device disables the parallel port or any + * of the UARTs we won't be able to detect it. + * Nb. This could be done with accuracy by reading the SID registers, but + * we don't have access to those io regions. + */ + + unsigned char reg; + + sc1200wdt_read_data(PMC3, ®); + reg &= 0x0f; /* we don't want the UART busy bits */ + return (reg == 0x0e) ? 0 : -ENODEV; +} + + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + +static int __init sc1200wdt_isapnp_probe(void) +{ + int ret; + + /* The WDT is logical device 8 on the main device */ + wdt_dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('N','S','C'), ISAPNP_FUNCTION(0x08), NULL); + if (!wdt_dev) + return -ENODEV; + + if (wdt_dev->prepare(wdt_dev) < 0) { + printk(KERN_ERR PFX "ISA PnP found device that could not be autoconfigured\n"); + return -EAGAIN; + } + + if (!(pci_resource_flags(wdt_dev, 0) & IORESOURCE_IO)) { + printk(KERN_ERR PFX "ISA PnP could not find io ports\n"); + return -ENODEV; + } + + ret = wdt_dev->activate(wdt_dev); + if (ret && (ret != -EBUSY)) + return -ENOMEM; + + /* io port resource overriding support? */ + io = pci_resource_start(wdt_dev, 0); + io_len = pci_resource_len(wdt_dev, 0); + + printk(KERN_DEBUG PFX "ISA PnP found device at io port %#x/%d\n", io, io_len); + return 0; +} + +#endif /* CONFIG_ISAPNP */ + + +static int __init sc1200wdt_init(void) +{ + int ret; + + printk(banner); + + spin_lock_init(&sc1200wdt_lock); + sema_init(&open_sem, 1); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp) { + ret = sc1200wdt_isapnp_probe(); + if (ret) + goto out_clean; + } +#endif + + if (io == -1) { + printk(KERN_ERR PFX "io parameter must be specified\n"); + ret = -EINVAL; + goto out_clean; + } + + if (!request_region(io, io_len, SC1200_MODULE_NAME)) { + printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); + ret = -EBUSY; + goto out_pnp; + } + + ret = sc1200wdt_probe(); + if (ret) + goto out_io; + + ret = register_reboot_notifier(&sc1200wdt_notifier); + if (ret) { + printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); + goto out_io; + } + + ret = misc_register(&sc1200wdt_miscdev); + if (ret) { + printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + goto out_rbt; + } + + /* ret = 0 */ + +out_clean: + return ret; + +out_rbt: + unregister_reboot_notifier(&sc1200wdt_notifier); + +out_io: + release_region(io, io_len); + +out_pnp: +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp && wdt_dev) + wdt_dev->deactivate(wdt_dev); +#endif + goto out_clean; +} + + +static void __exit sc1200wdt_exit(void) +{ + misc_deregister(&sc1200wdt_miscdev); + unregister_reboot_notifier(&sc1200wdt_notifier); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if(isapnp && wdt_dev) + wdt_dev->deactivate(wdt_dev); +#endif + + release_region(io, io_len); +} + + +#ifndef MODULE +static int __init sc1200wdt_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + io = ints[1]; + if (ints[0] > 1) + timeout = ints[2]; + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (ints[0] > 2) + isapnp = ints[3]; +#endif + } + + return 1; +} + +__setup("sc1200wdt=", sc1200wdt_setup); +#endif /* MODULE */ + + +module_init(sc1200wdt_init); +module_exit(sc1200wdt_exit); + +MODULE_AUTHOR("Zwane Mwaikambo "); +MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -urN linux-2.4.18/drivers/char/sc520_wdt.c linux-2.4.19-pre5/drivers/char/sc520_wdt.c --- linux-2.4.18/drivers/char/sc520_wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/sc520_wdt.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,381 @@ +/* + * AMD Elan SC520 processor Watchdog Timer driver for Linux 2.4.x + * + * Based on acquirewdt.c by Alan Cox, + * and sbc60xxwdt.c by Jakob Oestergaard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2001 Scott Jennings + * 9/27 - 2001 [Initial release] + * + * Additional fixes Alan Cox + * - Fixed formatting + * - Removed debug printks + * - Fixed SMP built kernel deadlock + * - Switched to private locks not lock_kernel + * - Used ioremap/writew/readw + * - Added NOWAYOUT support + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + * + * This driver uses memory mapped IO, and spinlock. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The SC520 can timeout anywhere from 492us to 32.21s. + * If we reset the watchdog every ~250ms we should be safe. + */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +/* + * AMD Elan SC520 timeout value is 492us times a power of 2 (0-7) + * + * 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s + * 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s + */ + +#define TIMEOUT_EXPONENT ( 1 << 3 ) /* 0x08 = 2.01s */ + +/* #define MMCR_BASE_DEFAULT 0xfffef000 */ +#define MMCR_BASE_DEFAULT ((__u16 *)0xffffe) +#define OFFS_WDTMRCTL ((unsigned int)0xcb0) +#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */ +#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */ + +#define OUR_NAME "sc520_wdt" + +#define WRT_DOG(data) *wdtmrctl=data + +static __u16 *wdtmrctl; + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static int wdt_expect_close; + +static spinlock_t wdt_spinlock; +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT */ + spin_lock(&wdt_spinlock); + writew(0xAAAA, wdtmrctl); + writew(0x5555, wdtmrctl); + spin_unlock(&wdt_spinlock); + + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_config(int writeval) +{ + __u16 dummy; + unsigned long flags; + + /* buy some time (ping) */ + spin_lock_irqsave(&wdt_spinlock, flags); + dummy=readw(wdtmrctl); /* ensure write synchronization */ + writew(0xAAAA, wdtmrctl); + writew(0x5555, wdtmrctl); + /* make WDT configuration register writable one time */ + writew(0x3333, wdtmrctl); + writew(0xCCCC, wdtmrctl); + /* write WDT configuration register */ + writew(writeval, wdtmrctl); + spin_unlock_irqrestore(&wdt_spinlock, flags); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + wdt_config(WDT_ENB | WDT_WRST_ENB | TIMEOUT_EXPONENT); + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + /* Stop the timer */ + del_timer(&timer); + wdt_config(0); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +#endif +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + } + return 0; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + /* Good, fire up the show */ + wdt_startup(); +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + return 0; + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + clear_bit(0, &wdt_is_open); + return 0; +} + +static long long fop_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "SC520" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: fop_llseek, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit sc520_wdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + iounmap(wdtmrctl); + unregister_reboot_notifier(&wdt_notifier); +} + +static int __init sc520_wdt_init(void) +{ + int rc = -EBUSY; + unsigned long cbar; + + spin_lock_init(&wdt_spinlock); + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + /* get the Base Address Register */ + cbar = inl_p(0xfffc); + printk(OUR_NAME ": CBAR: 0x%08lx\n", cbar); + /* check if MMCR aliasing bit is set */ + if (cbar & 0x80000000) { + printk(OUR_NAME ": MMCR Aliasing enabled.\n"); + wdtmrctl = (__u16 *)(cbar & 0x3fffffff); + } else { + printk(OUR_NAME "!!! WARNING !!!\n" + "\t MMCR Aliasing found NOT enabled!\n" + "\t Using default value of: %p\n" + "\t This has not been tested!\n" + "\t Please email Scott Jennings \n" + "\t and Bill Jennings if it works!\n" + , MMCR_BASE_DEFAULT + ); + wdtmrctl = MMCR_BASE_DEFAULT; + } + + wdtmrctl = (__u16 *)((char *)wdtmrctl + OFFS_WDTMRCTL); + wdtmrctl = ioremap((unsigned long)wdtmrctl, 2); + printk(KERN_INFO OUR_NAME ": WDT driver for SC520 initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + return rc; +} + +module_init(sc520_wdt_init); +module_exit(sc520_wdt_unload); + +MODULE_AUTHOR("Scott and Bill Jennings"); +MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.18/drivers/char/serial.c linux-2.4.19-pre5/drivers/char/serial.c --- linux-2.4.18/drivers/char/serial.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/serial.c Sat Mar 30 22:55:28 2002 @@ -57,6 +57,11 @@ * 10/00: add in optional software flow control for serial console. * Kanoj Sarcar (Modified by Theodore Ts'o) * + * 02/02: Fix for AMD Elan bug in transmit irq routine, by + * Christer Weinigel , + * Robert Schwebel , + * Juergen Beisert , + * Theodore Ts'o */ static char *serial_version = "5.05c"; @@ -801,7 +806,7 @@ */ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; struct async_struct * info; int pass_counter = 0; struct async_struct *end_mark = 0; @@ -826,7 +831,7 @@ do { if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -845,7 +850,9 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* for buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); next: @@ -879,7 +886,7 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT @@ -901,6 +908,7 @@ first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -909,18 +917,21 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* For buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 +#if SERIAL_DEBUG_INTR printk("rs_single loop break.\n"); #endif break; } + iir = serial_in(info, UART_IIR); #ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); + printk("IIR = %x...", iir); #endif - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + } while ((iir & UART_IIR_NO_INT) == 0); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor) diff -urN linux-2.4.18/drivers/char/serial167.c linux-2.4.19-pre5/drivers/char/serial167.c --- linux-2.4.18/drivers/char/serial167.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/serial167.c Sat Mar 30 22:55:34 2002 @@ -1262,7 +1262,7 @@ break; } - cli(); + save_flags(flags); cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); @@ -1277,7 +1277,7 @@ up(&tmp_buf_sem); } else { while (1) { - cli(); + save_flags(flags); cli(); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { @@ -1377,7 +1377,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_throttle ttyS%d\n", info->line); #endif @@ -1413,7 +1413,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); printk("cy_unthrottle ttyS%d\n", info->line); #endif @@ -2395,7 +2395,11 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; +#ifdef CONFIG_DEVFS_FS + cy_serial_driver.name = "tts/%d"; +#else cy_serial_driver.name = "ttyS"; +#endif cy_serial_driver.major = TTY_MAJOR; cy_serial_driver.minor_start = 64; cy_serial_driver.num = NR_PORTS; @@ -2430,7 +2434,11 @@ * major number and the subtype code. */ cy_callout_driver = cy_serial_driver; +#ifdef CONFIG_DEVFS_FS + cy_callout_driver.name = "cua/%d"; +#else cy_callout_driver.name = "cua"; +#endif cy_callout_driver.major = TTYAUX_MAJOR; cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; diff -urN linux-2.4.18/drivers/char/serial_tx3912.c linux-2.4.19-pre5/drivers/char/serial_tx3912.c --- linux-2.4.18/drivers/char/serial_tx3912.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/serial_tx3912.c Sat Mar 30 22:55:28 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.c * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -15,19 +13,13 @@ #include #include #include -#include -#include #include -#include -#include #include #include -#include -#include +#include #include #include #include -#include #include #include "serial_tx3912.h" @@ -62,35 +54,19 @@ }; /* - * Structures and such for TTY sessions and usage counts + * Structures and usage counts */ static struct tty_driver rs_driver, rs_callout_driver; -static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, }; -static struct termios ** rs_termios; -static struct termios ** rs_termios_locked; -struct rs_port *rs_ports; -int rs_refcount; -int rs_initialized = 0; - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- +static struct tty_struct **rs_tty; +static struct termios **rs_termios; +static struct termios **rs_termios_locked; +static struct rs_port *rs_port; +static int rs_refcount; +static int rs_initialized; + + +/* + * Receive a character */ static inline void receive_char_pio(struct rs_port *port) { @@ -98,83 +74,34 @@ unsigned char ch; int counter = 2048; - /* While there are characters, get them ... */ - while (counter>0) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL)) + /* While there are characters */ + while (counter > 0) { + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL)) break; - ch = inb(port->base + TX3912_UART_DATA); + ch = inb(TX3912_UARTA_DATA); if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr++ = ch; *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } - udelay(1); /* Allow things to happen - it take a while */ + udelay(1); counter--; } - if (!counter) - printk( "Ugh, looped in receive_char_pio!\n" ); - - tty_flip_buffer_push(tty); - -#if 0 - /* Now handle error conditions */ - if (*status & (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_BREAK_INT))) { - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - */ - if (*status & port->ignore_status_mask) { - goto ignore_char; - } - *status &= port->read_status_mask; - - if (*status & INTTYPE(UART_BREAK_INT)) { - rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break...."); - *tty->flip.flag_buf_ptr = TTY_BREAK; - } - else if (*status & INTTYPE(UART_PARITYERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_PARITY; - } - else if (*status & INTTYPE(UART_FRAMEERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_FRAME; - } - if (*status & INTTYPE(UART_RXOVERRUN_INT)) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } - } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - -ignore_char: tty_flip_buffer_push(tty); -#endif } +/* + * Transmit a character + */ static inline void transmit_char_pio(struct rs_port *port) { - /* While I'm able to transmit ... */ + /* TX while bytes available */ for (;;) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_TX_EMPTY)) + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY)) break; else if (port->x_char) { - outb(port->x_char, port->base + TX3912_UART_DATA); + outb(port->x_char, TX3912_UARTA_DATA); port->icount.tx++; port->x_char = 0; } @@ -184,14 +111,14 @@ } else { outb(port->gs.xmit_buf[port->gs.xmit_tail++], - port->base + TX3912_UART_DATA); + TX3912_UARTA_DATA); port->icount.tx++; port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1; if (--port->gs.xmit_cnt <= 0) { break; } } - udelay(10); /* Allow things to happen - it take a while */ + udelay(10); } if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped || @@ -203,519 +130,418 @@ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); wake_up_interruptible(&port->gs.tty->write_wait); } } - - +/* + * We don't have MSR + */ static inline void check_modem_status(struct rs_port *port) { - /* We don't have a carrier detect line - but just respond - like we had one anyways so that open() becomes unblocked */ wake_up_interruptible(&port->gs.open_wait); } -int count = 0; - /* - * This is the serial driver's interrupt routine (inlined, because - * there are two different versions of this, one for each serial port, - * differing only by the bits used in interrupt status 2 register) + * RX interrupt handler */ - -static inline void rs_rx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); - - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_rx_interrupt..."); - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_RX_INT)) << intshift); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } /* RX Receiver Holding Register Overrun */ - if (ints & INTTYPE(UART_RXOVERRUN_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun"); - port->icount.overrun++; + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "overrun"); + rs_port->icount.overrun++; } /* RX Frame Error */ - if (ints & INTTYPE(UART_FRAMEERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error"); - port->icount.frame++; + if(status & TX3912_INT2_UARTAFRAMEERRINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "frame error"); + rs_port->icount.frame++; } /* Break signal received */ - if (ints & INTTYPE(UART_BREAK_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break"); - port->icount.brk++; + if(status & TX3912_INT2_UARTABREAKINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "break"); + rs_port->icount.brk++; } /* RX Parity Error */ - if (ints & INTTYPE(UART_PARITYERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error"); - port->icount.parity++; + if(status & TX3912_INT2_UARTAPARITYINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "parity error"); + rs_port->icount.parity++; } - /* Receive byte (non-DMA) */ - if (ints & INTTYPE(UART_RX_INT)) { - receive_char_pio(port); + /* Byte received */ + if(status & TX3912_INT2_UARTARXINT) { + receive_char_pio(rs_port); } restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } -static inline void rs_tx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +/* + * TX interrupt handler + */ +static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_tx_interrupt..."); - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Clear interrupts */ + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << intshift); - - /* TX holding register empty, so transmit byte (non-DMA) */ - if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) { - transmit_char_pio(port); + /* TX holding register empty - transmit a byte */ + if(status & TX3912_INT2_UARTAEMPTYINT) { + transmit_char_pio(rs_port); } /* TX Transmit Holding Register Overrun (shouldn't happen) */ - if (ints & INTTYPE(UART_TXOVERRUN_INT)) { - printk ( "rs: TX overrun\n"); + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + printk( "rs_tx_interrupt: TX overrun\n"); } - /* - check_modem_status(); - */ - restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); -} - -static void rs_rx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_rx_interrupt(irq, dev_id, regs, UARTA_SHIFT); -} - -static void rs_tx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_tx_interrupt(irq, dev_id, regs, UARTA_SHIFT); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } /* - *********************************************************************** - * Here are the routines that actually * - * interface with the generic_serial driver * - *********************************************************************** + * Here are the routines that actually interface with the generic driver */ static void rs_disable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - port->gs.flags &= ~GS_TX_INTEN; - IntEnable2 &= ~((INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - IntEnable2 |= (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - /* Send a char to start TX interrupts happening */ - transmit_char_pio(port); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + transmit_char_pio(rs_port); restore_flags(flags); } static void rs_disable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 &= ~((INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 |= (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; - - /* Empty the input buffer - apparently this is *vital* */ - while (inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL) { - inb(port->base + TX3912_UART_DATA); - } - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + while (inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL) + inb(TX3912_UARTA_DATA); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } - +/* + * We have no CD + */ static int rs_get_CD (void * ptr) { - /* No Carried Detect in Hardware - just return true */ - func_exit(); - return (1); + return 1; } +/* + * Shut down the port + */ static void rs_shutdown_port (void * ptr) { - struct rs_port *port = ptr; - func_enter(); - - port->gs.flags &= ~GS_ACTIVE; - + rs_port->gs.flags &= ~GS_ACTIVE; func_exit(); } static int rs_set_real_termios (void *ptr) { - struct rs_port *port = ptr; - int t; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; - switch (port->gs.baud) { - /* Save some typing work... */ -#define e(x) case x:t= TX3912_UART_CTRL2_B ## x ; break - e(300);e(600);e(1200);e(2400);e(4800);e(9600); - e(19200);e(38400);e(57600);e(76800);e(115200);e(230400); - case 0 :t = -1; - break; - default: - /* Can I return "invalid"? */ - t = TX3912_UART_CTRL2_B9600; - printk (KERN_INFO "rs: unsupported baud rate: %d.\n", port->gs.baud); - break; - } -#undef e - if (t >= 0) { - /* Jim: Set Hardware Baud rate - there is some good - code in drivers/char/serial.c */ - - /* Program hardware for parity, data bits, stop bits (note: these are hardcoded to 8N1 */ - UartA_Ctrl1 &= 0xf000000f; - UartA_Ctrl1 &= ~(UART_DIS_TXD | SER_SEVEN_BIT | SER_EVEN_PARITY | SER_TWO_STOP); - -#define CFLAG port->gs.tty->termios->c_cflag - if (C_PARENB(port->gs.tty)) { - if (!C_PARODD(port->gs.tty)) - UartA_Ctrl1 |= SER_EVEN_PARITY; - else - UartA_Ctrl1 |= SER_ODD_PARITY; - } - if ((CFLAG & CSIZE)==CS6) - printk(KERN_ERR "6 bits not supported\n"); - if ((CFLAG & CSIZE)==CS5) - printk(KERN_ERR "5 bits not supported\n"); - if ((CFLAG & CSIZE)==CS7) - UartA_Ctrl1 |= SER_SEVEN_BIT; - if (C_CSTOPB(port->gs.tty)) - UartA_Ctrl1 |= SER_TWO_STOP; - - outl(t, port->base + TX3912_UART_CTRL2); - outl(0, port->base + TX3912_UART_DMA_CTRL1); - outl(0, port->base + TX3912_UART_DMA_CTRL2); - UartA_Ctrl1 |= TX3912_UART_CTRL1_UARTON; + /* Set baud rate */ + switch (rs_port->gs.baud) { + case 0: + goto done; + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + /* Clear current UARTA settings */ + ctrl1 = inl(TX3912_UARTA_CTRL1) & 0xf000000f; - /* wait until UARTA is stable */ - while (~UartA_Ctrl1 & TX3912_UART_CTRL1_UARTON); + /* Set parity */ + if(C_PARENB(rs_port->gs.tty)) { + if (!C_PARODD(rs_port->gs.tty)) + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + else + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; } - func_exit (); - return 0; + /* Set data size */ + switch(rs_port->gs.tty->termios->c_cflag & CSIZE) { + case CS7: + ctrl1 |= TX3912_UART_CTRL1_BIT_7; + break; + case CS5: + case CS6: + printk(KERN_ERR "Data byte size unsupported. Defaulting to CS8\n"); + case CS8: + default: + ctrl1 &= ~TX3912_UART_CTRL1_BIT_7; + } + + /* Set stop bits */ + if(C_CSTOPB(rs_port->gs.tty)) + ctrl1 |= TX3912_UART_CTRL1_TWOSTOP; + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0, TX3912_UARTA_DMA_CTRL1); + outl(0, TX3912_UARTA_DMA_CTRL2); + outl(ctrl1, TX3912_UARTA_CTRL1); + + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); + +done: + func_exit(); + return 0; } +/* + * Anyone in the buffer? + */ static int rs_chars_in_buffer (void * ptr) { - struct rs_port *port = ptr; - int scratch; - - scratch = inl(port->base + TX3912_UART_CTRL1); - - return ((scratch & UART_TX_EMPTY) ? 0 : 1); + return ((inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY) ? 0 : 1); } -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ -static int rs_open (struct tty_struct * tty, struct file * filp) +/* + * Open the serial port + */ +static int rs_open(struct tty_struct * tty, struct file * filp) { - struct rs_port *port; - int retval, line; + int retval; func_enter(); - if (!rs_initialized) { + if(!rs_initialized) { return -EIO; } - line = MINOR(tty->device) - tty->driver.minor_start; - rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", - (int) current->pid, line, tty, current->tty); - - if ((line < 0) || (line >= TX3912_UART_NPORTS)) + if(MINOR(tty->device) - tty->driver.minor_start) { return -ENODEV; + } - /* Pre-initialized already */ - port = & rs_ports[line]; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port); - - tty->driver_data = port; - port->gs.tty = tty; - port->gs.count++; + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Serial opening...\n"); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n"); + tty->driver_data = rs_port; + rs_port->gs.tty = tty; + rs_port->gs.count++; /* * Start up serial port */ - retval = gs_init_port(&port->gs); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n"); - if (retval) { - port->gs.count--; + retval = gs_init_port(&rs_port->gs); + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Finished gs_init...\n"); + if(retval) { + rs_port->gs.count--; return retval; } - port->gs.flags |= GS_ACTIVE; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", - port->gs.count); - if (port->gs.count == 1) { + rs_port->gs.flags |= GS_ACTIVE; + if(rs_port->gs.count == 1) { MOD_INC_USE_COUNT; } - rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n"); - - /* Jim: Initialize port hardware here */ - /* Enable high-priority interrupts for UARTA */ - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); + rs_enable_rx_interrupts(rs_port); + rs_enable_tx_interrupts(rs_port); - retval = gs_block_til_ready(&port->gs, filp); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", - retval, port->gs.count); - - if (retval) { + retval = gs_block_til_ready(&rs_port->gs, filp); + if(retval) { MOD_DEC_USE_COUNT; - port->gs.count--; + rs_port->gs.count--; return retval; } - /* tty->low_latency = 1; */ - if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if((rs_port->gs.count == 1) && + (rs_port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; + *tty->termios = rs_port->gs.normal_termios; else - *tty->termios = port->gs.callout_termios; - rs_set_real_termios (port); + *tty->termios = rs_port->gs.callout_termios; + rs_set_real_termios(rs_port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; + rs_port->gs.session = current->session; + rs_port->gs.pgrp = current->pgrp; func_exit(); - /* Jim */ -/* cli(); */ - return 0; - } - - -static void rs_close (void *ptr) +/* + * Close the serial port + */ +static void rs_close(void *ptr) { - func_enter (); - - /* Anything to do here? */ - + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } - -/* I haven't the foggiest why the decrement use count has to happen - here. The whole linux serial drivers stuff needs to be redesigned. - My guess is that this is a hack to minimize the impact of a bug - elsewhere. Thinking about it some more. (try it sometime) Try - running minicom on a serial port that is driven by a modularized - driver. Have the modem hangup. Then remove the driver module. Then - exit minicom. I expect an "oops". -- REW */ -static void rs_hungup (void *ptr) +/* + * Hang up the serial port + */ +static void rs_hungup(void *ptr) { - func_enter (); + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } -static int rs_ioctl (struct tty_struct * tty, struct file * filp, +/* + * Serial ioctl call + */ +static int rs_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { - int rc; - struct rs_port *port = tty->driver_data; - int ival; + int ival, rc; rc = 0; switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + case TIOCGSOFTCAR: + rc = put_user((tty->termios->c_cflag & CLOCAL) ? 1 : 0, (unsigned int *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(int))) == 0) { - get_user(ival, (unsigned int *) arg); - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_getserial(&port->gs, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, (struct serial_struct *) arg); - break; - default: - rc = -ENOIOCTLCMD; - break; + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_getserial(&rs_port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&rs_port->gs, (struct serial_struct *) arg); + break; + default: + rc = -ENOIOCTLCMD; + break; } - /* func_exit(); */ return rc; } - /* - * This function is used to send a high-priority XON/XOFF character to - * the device + * Send xchar */ static void rs_send_xchar(struct tty_struct * tty, char ch) { - struct rs_port *port = (struct rs_port *)tty->driver_data; - func_enter (); + func_enter(); - port->x_char = ch; + rs_port->x_char = ch; if (ch) { - /* Make sure transmit interrupts are on */ rs_enable_tx_interrupts(tty); } func_exit(); } - /* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ + * Throttle characters as directed by upper tty layer */ static void rs_throttle(struct tty_struct * tty) { @@ -726,17 +552,19 @@ tty->ldisc.chars_in_buffer(tty)); #endif - func_enter (); + func_enter(); if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - func_exit (); + func_exit(); } +/* + * Un-throttle characters as directed by upper tty layer + */ static void rs_unthrottle(struct tty_struct * tty) { - struct rs_port *port = (struct rs_port *)tty->driver_data; #ifdef TX3912_UART_DEBUG_THROTTLE char buf[64]; @@ -747,8 +575,8 @@ func_enter(); if (I_IXOFF(tty)) { - if (port->x_char) - port->x_char = 0; + if (rs_port->x_char) + rs_port->x_char = 0; else rs_send_xchar(tty, START_CHAR(tty)); } @@ -756,105 +584,72 @@ func_exit(); } - - - - -/* ********************************************************************** * - * Here are the initialization routines. * - * ********************************************************************** */ - -void * ckmalloc (int size) -{ - void *p; - - p = kmalloc(size, GFP_KERNEL); - if (p) - memset(p, 0, size); - return p; -} - - - -static int rs_init_portstructs(void) +/* + * Initialize the serial port + */ +void __init tx3912_rs_init(void) { - struct rs_port *port; - int i; - - /* Debugging */ func_enter(); + rs_dprintk(TX3912_UART_DEBUG_INIT, "Initializing serial...\n"); - rs_ports = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port)); - if (!rs_ports) - return -ENOMEM; - - rs_termios = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios) { - kfree (rs_ports); - return -ENOMEM; + /* Allocate critical structures */ + if(!(rs_tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL))) { + return; } - - rs_termios_locked = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios_locked) { - kfree (rs_ports); - kfree (rs_termios); - return -ENOMEM; + if(!(rs_port = kmalloc(sizeof(struct rs_port), GFP_KERNEL))) { + kfree(rs_tty); + return; + } + if(!(rs_termios = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_port); + kfree(rs_tty); + return; + } + if(!(rs_termios_locked = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); + return; } - /* Adjust the values in the "driver" */ - rs_driver.termios = rs_termios; - rs_driver.termios_locked = rs_termios_locked; + /* Zero out the structures */ + memset(rs_tty, 0, sizeof(struct tty_struct)); + memset(rs_port, 0, sizeof(struct rs_port)); + memset(rs_termios, 0, sizeof(struct termios)); + memset(rs_termios_locked, 0, sizeof(struct termios)); + memset(&rs_driver, 0, sizeof(rs_driver)); + memset(&rs_callout_driver, 0, sizeof(rs_callout_driver)); - port = rs_ports; - for (i=0; i < TX3912_UART_NPORTS;i++) { - rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i); - port->gs.callout_termios = tty_std_termios; - port->gs.normal_termios = tty_std_termios; - port->gs.magic = SERIAL_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &rs_real_driver; + /* Fill in hardware specific port structure */ + rs_port->gs.callout_termios = tty_std_termios; + rs_port->gs.normal_termios = tty_std_termios; + rs_port->gs.magic = SERIAL_MAGIC; + rs_port->gs.close_delay = HZ/2; + rs_port->gs.closing_wait = 30 * HZ; + rs_port->gs.rd = &rs_real_driver; #ifdef NEW_WRITE_LOCKING - port->gs.port_write_sem = MUTEX; + rs_port->gs.port_write_sem = MUTEX; #endif #ifdef DECLARE_WAITQUEUE - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); + init_waitqueue_head(&rs_port->gs.open_wait); + init_waitqueue_head(&rs_port->gs.close_wait); #endif - port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE; - port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT; - rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n", - port->base, port->intshift); - port++; - } - - func_exit(); - return 0; -} -static int rs_init_drivers(void) -{ - int error; - - func_enter(); - - memset(&rs_driver, 0, sizeof(rs_driver)); + /* Fill in generic serial driver structures */ rs_driver.magic = TTY_DRIVER_MAGIC; rs_driver.driver_name = "serial"; rs_driver.name = "ttyS"; rs_driver.major = TTY_MAJOR; rs_driver.minor_start = 64; - rs_driver.num = TX3912_UART_NPORTS; + rs_driver.num = 1; rs_driver.type = TTY_DRIVER_TYPE_SERIAL; rs_driver.subtype = SERIAL_TYPE_NORMAL; rs_driver.init_termios = tty_std_termios; - rs_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; + rs_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; rs_driver.refcount = &rs_refcount; - rs_driver.table = rs_table; + rs_driver.table = rs_tty; rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; - rs_driver.open = rs_open; rs_driver.close = gs_close; rs_driver.write = gs_write; @@ -870,92 +665,59 @@ rs_driver.stop = gs_stop; rs_driver.start = gs_start; rs_driver.hangup = gs_hangup; - rs_callout_driver = rs_driver; rs_callout_driver.name = "cua"; rs_callout_driver.major = TTYAUX_MAJOR; rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if ((error = tty_register_driver(&rs_driver))) { - printk(KERN_ERR "Couldn't register serial driver, error = %d\n", - error); - return 1; + /* Register serial and callout drivers */ + if(tty_register_driver(&rs_driver)) { + printk(KERN_ERR "Unable to register serial driver\n"); + goto error; } - if ((error = tty_register_driver(&rs_callout_driver))) { + if(tty_register_driver(&rs_callout_driver)) { tty_unregister_driver(&rs_driver); - printk(KERN_ERR "Couldn't register callout driver, error = %d\n", - error); - return 1; + printk(KERN_ERR "Unable to register callout driver\n"); + goto error; } - func_exit(); - return 0; -} - - -void __init tx3912_rs_init(void) -{ - int rc; - - - func_enter(); - rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug); + /* Assign IRQs */ + if(request_irq(2, rs_tx_interrupt, SA_SHIRQ, + "uarta_tx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_TX.\n"); + goto error; + } - rc = rs_init_portstructs (); - rs_init_drivers (); - if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; - } - if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; + if(request_irq(3, rs_rx_interrupt, SA_SHIRQ, + "uarta_rx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_RX.\n"); + goto error; } - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); + /* Enable the serial receive interrupt */ + rs_enable_rx_interrupts(rs_port); #ifndef CONFIG_SERIAL_TX3912_CONSOLE -{ - unsigned int scratch = 0; + /* Write the control registers */ + outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl(inl(TX3912_UARTA_CTRL1) | TX3912_UART_CTRL1_ENUART, + TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); -} + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); #endif - /* Note: I didn't do anything to enable the second UART */ - if (rc >= 0) - rs_initialized++; + rs_initialized = 1; + func_exit(); + return; +error: + kfree(rs_termios_locked); + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); func_exit(); } @@ -963,55 +725,52 @@ * Begin serial console routines */ #ifdef CONFIG_SERIAL_TX3912_CONSOLE - void serial_outc(unsigned char c) { int i; unsigned long int2; - #define BUSY_WAIT 10000 - - /* - * Turn UARTA interrupts off - */ - int2 = IntEnable2; - IntEnable2 &= - ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY); - - /* - * The UART_TX_EMPTY bit in UartA_Ctrl1 seems - * not to be very reliable :-( - * - * Wait for the Tx register to become empty - */ - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; - UartA_Data = c; - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; + /* Disable UARTA_TX interrupts */ + int2 = inl(TX3912_INT2_ENABLE); + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + + /* Send the character */ + outl(c, TX3912_UARTA_DATA); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - IntEnable2 = int2; + /* Enable UARTA_TX interrupts */ + outl(int2, TX3912_INT2_ENABLE); } static int serial_console_wait_key(struct console *co) { unsigned int int2, res; - int2 = IntEnable2; - IntEnable2 = 0; + int2 = inl(TX3912_INT2_ENABLE); + outl(0, TX3912_INT2_ENABLE); - while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL)); - res = UartA_Data; + while (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL)); + res = inl(TX3912_UARTA_DATA); udelay(10); - IntEnable2 = int2; + outl(int2, TX3912_INT2_ENABLE); return res; } static void serial_console_write(struct console *co, const char *s, - unsigned count) + unsigned count) { - unsigned int i; + unsigned int i; for (i = 0; i < count; i++) { if (*s == '\n') @@ -1027,36 +786,78 @@ static __init int serial_console_setup(struct console *co, char *options) { - unsigned int scratch = 0; + int baud = 115200; + int bits = 8; + int parity = 'n'; + char *s; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s++ - '0'; + } + + switch(baud) { + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + switch(bits) { + case 7: + ctrl1 = TX3912_UART_CTRL1_BIT_7; + break; + default: + break; + } + + switch(parity) { + case 'o': case 'O': + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; + break; + case 'e': case 'E': + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + break; + default: + break; + } + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl((ctrl1 | TX3912_UART_CTRL1_ENUART), TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); return 0; } @@ -1075,5 +876,4 @@ { register_console(&sercons); } - #endif diff -urN linux-2.4.18/drivers/char/serial_tx3912.h linux-2.4.19-pre5/drivers/char/serial_tx3912.h --- linux-2.4.18/drivers/char/serial_tx3912.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/serial_tx3912.h Sat Mar 30 22:55:28 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.h * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -14,27 +12,6 @@ #include #include -/* UART Interrupt (Interrupt 2) bits (UARTA,UARTB) */ -#define UART_RX_INT 9 /* receiver holding register full (31, 21) */ -#define UART_RXOVERRUN_INT 8 /* receiver overrun error (30, 20) */ -#define UART_FRAMEERR_INT 7 /* receiver frame error (29, 19) */ -#define UART_BREAK_INT 6 /* received break signal (28, 18) */ -#define UART_PARITYERR_INT 5 /* receiver parity error (27, 17) */ -#define UART_TX_INT 4 /* transmit holding register empty (26, 16) */ -#define UART_TXOVERRUN_INT 3 /* transmit overrun error (25, 15) */ -#define UART_EMPTY_INT 2 /* both trans/recv regs empty (24, 14) */ -#define UART_DMAFULL_INT 1 /* DMA at end of buffer (23, 13) */ -#define UART_DMAHALF_INT 0 /* DMA halfway through buffer */ (22, 12) */ - -#define UARTA_SHIFT 22 -#define UARTB_SHIFT 12 - -#define INTTYPE(interrupttype) (1 << interrupttype) - -/* - * This driver can spew a whole lot of debugging output at you. If you - * need maximum performance, you should disable the DEBUG define. - */ #undef TX3912_UART_DEBUG #ifdef TX3912_UART_DEBUG @@ -53,39 +30,28 @@ #define TX3912_UART_DEBUG_FIRMWARE 0x00001000 #define TX3912_UART_DEBUG_MEMTEST 0x00002000 #define TX3912_UART_DEBUG_THROTTLE 0x00004000 +#define TX3912_UART_DEBUG_NO_TX 0xffffffdf #define TX3912_UART_DEBUG_ALL 0xffffffff -int rs_debug = TX3912_UART_DEBUG_ALL & ~TX3912_UART_DEBUG_TRANSMIT; - -#define rs_dprintk(f, str...) if (rs_debug & f) printk (str) -#define func_enter() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define rs_dprintk(f, str...) if(TX3912_UART_DEBUG_NO_TX & f) printk(str) +#define func_enter() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: enter " __FUNCTION__ "\n") -#define func_exit() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define func_exit() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: exit " __FUNCTION__ "\n") - #else #define rs_dprintk(f, str...) #define func_enter() #define func_exit() - -#endif /* TX3912_UART_DEBUG */ - -/* - * Number of serial ports - */ -#define TX3912_UART_NPORTS 2 +#endif /* * Hardware specific serial port structure */ struct rs_port { struct gs_port gs; /* Must be first field! */ - - unsigned long base; - int intshift; /* Register shift */ struct wait_queue *shutdown_wait; int stat_flags; - struct async_icount icount; /* Counters for 4 input IRQs */ + struct async_icount icount; /* Counters for 4 input IRQs */ int read_status_mask; int ignore_status_mask; int x_char; /* XON/XOFF character */ diff -urN linux-2.4.18/drivers/char/serial_txx927.c linux-2.4.19-pre5/drivers/char/serial_txx927.c --- linux-2.4.18/drivers/char/serial_txx927.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/serial_txx927.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,2359 @@ +/* + * drivers/char/serial_txx927.c + * driver for TX[34]927 SIO + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on drivers/char/serial.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +#ifdef MODULE +#undef CONFIG_TXX927_SERIAL_CONSOLE +#endif + +#define CONFIG_SERIAL_RSA + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +/* + * End of serial driver configuration section. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +#include +#endif +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TOSHIBA_JMR3927 +#include +#endif + +#define _INLINE_ inline + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +static char *serial_name = "TXx927 Serial driver"; +static char *serial_version = "0.02"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +static struct timer_list serial_timer; + +extern unsigned long get_txx927_uart_baud(void); + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +static struct console sercons; +#endif +#if defined(CONFIG_TXX927_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static unsigned long break_pressed; /* break, really ... */ +#endif + +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +#ifndef PREPARE_FUNC +#define PREPARE_FUNC(dev) (dev->prepare) +#define ACTIVATE_FUNC(dev) (dev->activate) +#define DEACTIVATE_FUNC(dev) (dev->deactivate) +#endif + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +#define SERIAL_DRIVER_NAME "TXx927SIO" + +#ifdef CONFIG_SERIAL +/* "ttyS","cua" is used for standard serial driver */ +#define TXX927_TTY_NAME "ttySC" +#define TXX927_TTY_MINOR_START (64 + 16) /* ttySC0(80), ttySC1(81) */ +#define TXX927_CU_NAME "cuac" +#define TXX927_SERIAL_BH TXX927SERIAL_BH +#else +/* acts like standard serial driver */ +#define TXX927_TTY_NAME "ttyS" +#define TXX927_TTY_MINOR_START 64 +#define TXX927_CU_NAME "cua" +#define TXX927_SERIAL_BH SERIAL_BH +#endif +#define TXX927_TTY_MAJOR TTY_MAJOR +#define TXX927_TTYAUX_MAJOR TTYAUX_MAJOR + +#define ASYNC_HAVE_CTS_LINE ASYNC_BOOT_AUTOCONF /* reuse */ + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static inline struct txx927_sio_reg *sio_reg(struct async_struct *info) +{ + return (struct txx927_sio_reg *)info->port; +} + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + unsigned int tmout = 1000000; + + do { + if (--tmout == 0) break; + } while (!(sio_reg(info)->cisr & TXx927_SICISR_TXALS)); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit.head != info->xmit.tail + && info->xmit.buf + && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(TXX927_SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = sio_reg(info)->rfifo; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (TXx927_SIDISR_UBRK | TXx927_SIDISR_UPER | + TXx927_SIDISR_UFER | TXx927_SIDISR_UOER)) { + /* + * For statistics only + */ + if (*status & TXx927_SIDISR_UBRK) { + *status &= ~(TXx927_SIDISR_UFER | TXx927_SIDISR_UPER); + icount->brk++; + } else if (*status & TXx927_SIDISR_UPER) + icount->parity++; + else if (*status & TXx927_SIDISR_UFER) + icount->frame++; + if (*status & TXx927_SIDISR_UOER) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (TXx927_SIDISR_UBRK)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & TXx927_SIDISR_UPER) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & TXx927_SIDISR_UFER) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & TXx927_SIDISR_UOER) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = sio_reg(info)->disr; + } while (!(*status & TXx927_SIDISR_UVALID)); + + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + wait_for_xmitr(info); + + if (info->x_char) { + sio_reg(info)->tfifo = info->x_char; + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + return; + } + + count = info->xmit_fifo_size; + do { + sio_reg(info)->tfifo = info->xmit.buf[info->xmit.tail++]; + info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (--count > 0); + + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit.head == info->xmit.tail) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + /* RTS/CTS are controled by HW. (if possible) */ +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + + do { + status = sio_reg(info)->disr; +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (!(sio_reg(info)->dicr & TXx927_SIDICR_TIE)) + status &= ~TXx927_SIDISR_TDIS; + if (!(status & (TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT))) + break; + + if (status & TXx927_SIDISR_RDIS) + receive_chars(info, &status); + check_modem_status(info); + if (status & TXx927_SIDISR_TDIS) + transmit_chars(info, 0); + /* Clear TX/RX Int. Status */ + sio_reg(info)->disr &= ~(TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT); + + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#ifdef SERIAL_DEBUG_INTR + printk("rs_single loop break.\n"); +#endif + break; + } + } while (1); + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(unsigned long dummy) +{ + static unsigned long last_strobe; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=0; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + +#if 0 + if (IRQ_ports[0]) { + save_flags(flags); cli(); + rs_interrupt_single(0, NULL, NULL); + restore_flags(flags); + + mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); + } +#endif +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + struct serial_state *state= info->state; + unsigned long page; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!state->port) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + retval = -EBUSY; + goto errout; + } + + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, + "txx927serial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Clear the interrupt registers. + */ + sio_reg(info)->disr = 0; + + /* + * Now, initialize the UART + */ + /* HW RTS/CTS control */ + if (state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + /* + * Finally, enable interrupts + */ + sio_reg(info)->dicr = TXx927_SIDICR_RIE; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, "txx927serial", NULL); + + if (retval) + printk(KERN_WARNING "txx927serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = 0; + } + + sio_reg(info)->dicr = 0; /* disable all intrs */ + + /* disable break condition */ + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + /* TXx927-SIO can not control DTR... */ + } + + /* reset FIFO's */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* DON'T disable Rx/Tx here, ie. DON'T set either + * TXx927_SIFLCR_RSDE or TXx927_SIFLCR_TSDE in flcr + */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!info->port) + return; + + cval = sio_reg(info)->lcr; + /* byte size and parity */ + cval &= ~TXx927_SILCR_UMODE_MASK; + switch (cflag & CSIZE) { + case CS7: + cval |= TXx927_SILCR_UMODE_7BIT; + bits = 9; + break; + case CS5: /* not supported */ + case CS6: /* not supported */ + case CS8: + default: + cval |= TXx927_SILCR_UMODE_8BIT; + bits = 10; + break; + } + cval &= ~TXx927_SILCR_USBL_MASK; + if (cflag & CSTOPB) { + cval |= TXx927_SILCR_USBL_2BIT; + bits++; + } else { + cval |= TXx927_SILCR_USBL_1BIT; + } + + cval &= ~(TXx927_SILCR_UPEN|TXx927_SILCR_UEPS); + if (cflag & PARENB) { + cval |= TXx927_SILCR_UPEN; + bits++; + } + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + quot = (baud_base + baud / 2) / baud; + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + quot = (baud_base + baud / 2) / baud; + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = (baud_base + 9600 / 2) / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* CTS flow control flag */ + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + if (info->state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + } else { + info->flags &= ~ASYNC_CTS_FLOW; + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + } + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = TXx927_SIDISR_UOER | + TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS; + if (I_INPCK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UFER | TXx927_SIDISR_UPER; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UBRK; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UPER | TXx927_SIDISR_UFER; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= TXx927_SIDISR_UBRK; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UOER; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= TXx927_SIDISR_RDIS; + save_flags(flags); cli(); + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit.buf) + return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + + info->xmit.buf[info->xmit.head++] = ch; + info->xmit.head &= SERIAL_XMIT_SIZE-1; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + + save_flags(flags); cli(); + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + + save_flags(flags); + + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped + && !(info->IER & UART_IER_THRI)) + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + result = ((sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) + | ((sio_reg(info)->cisr & TXx927_SICISR_CTSS) ? 0 : TIOCM_CTS); + restore_flags(flags); + return put_user(result,value); +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + error = get_user(arg, value); + if (error) + return error; + save_flags(flags); cli(); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + break; + case TIOCMSET: + sio_reg(info)->flcr = + (sio_reg(info)->flcr & ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE)) | + ((arg & TIOCM_RTS) ? 0 : TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + default: + error = -EINVAL; + } + restore_flags(flags); + return error; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!info->port) + return; + save_flags(flags); cli(); + if (break_state == -1) + sio_reg(info)->flcr |= TXx927_SIFLCR_TBRK; + else + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + return 0; + case TIOCGSERIAL: + printk("TIOCGSERIAL\n"); + return 0; + case TIOCSSERIAL: + printk("TIOCSSERIAL\n"); + return 0; + case TIOCSERCONFIG: + printk("TIOCSERCONFIG\n"); + return 0; + + case TIOCSERGETLSR: /* Get line status register */ + printk("TIOCSERGETLSR\n"); + return 0; + + case TIOCSERGSTRUCT: + printk("TIOCSERGSTRUCT\n"); + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + printk("TIOCMIWAIT\n"); + return 0; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + printk("TIOCGICOUNT\n"); + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + save_flags(flags); cli(); + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_WARNING "rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk(KERN_WARNING "rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~TXx927_SIDISR_RDIS; + if (info->flags & ASYNC_INITIALIZED) { +#if 0 + sio_reg(info)->dicr &= ~TXx927_SIDICR_RIE; +#endif + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int cisr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((cisr = sio_reg(info)->cisr) & TXx927_SICISR_TXALS)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...", cisr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...done\n", cisr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING)) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + +#ifdef REMOTE_DEBUG + if (kdb_port_info.state && line == kdb_port_info.line) + return -ENODEV; +#endif + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + return retval; + } + tty->driver_data = info; + info->tty = tty; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info, 0); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", + state->line, SERIAL_DRIVER_NAME, + state->port, state->irq); + + if (!state->port) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + + stat_buf[0] = 0; + stat_buf[1] = 0; + save_flags(flags); cli(); + if (!(sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC)) + strcat(stat_buf, "|RTS"); + if (!(sio_reg(info)->cisr & TXx927_SICISR_CTSS)) + strcat(stat_buf, "|CTS"); + restore_flags(flags); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init rs_init(void) +{ + int i; + struct serial_state * state; + + if (rs_table[0].port == 0) + return -ENODEV; + + init_bh(TXX927_SERIAL_BH, do_serial_bh); + init_timer(&serial_timer); + serial_timer.function = rs_timer; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "txx927serial"; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif + serial_driver.major = TXX927_TTY_MAJOR; + serial_driver.minor_start = TXX927_TTY_MINOR_START + SERIAL_DEV_OFFSET; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + callout_driver.name = "cua/%d"; +#else + callout_driver.name = "cua"; +#endif + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)){ + panic("Couldn't register serial driver\n"); + } + if (tty_register_driver(&callout_driver)) { + panic("Couldn't register callout driver\n"); + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + state->xmit_fifo_size = TXx927_SIO_TX_FIFO; + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; + if (state->port) { + continue; + } + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) { + continue; + } + printk(KERN_INFO "%s%02d at 0x%04lx (irq = %d) is a %s\n", + TXX927_TTY_NAME, + state->line, + state->port, state->irq, + SERIAL_DRIVER_NAME); + tty_register_devfs(&serial_driver, 0, + serial_driver.minor_start + state->line); + tty_register_devfs(&callout_driver, 0, + callout_driver.minor_start + state->line); + } + return 0; +} + +static void __exit rs_fini(void) +{ + unsigned long flags; + int e1, e2; + int i; + struct async_struct *info; + + del_timer_sync(&serial_timer); + save_flags(flags); cli(); + remove_bh(TXX927_SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk(KERN_WARNING "serial: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk(KERN_WARNING "serial: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree(info); + } + } + if (tmp_buf) { + unsigned long pg = (unsigned long) tmp_buf; + tmp_buf = NULL; + free_page(pg); + } +} + +module_init(rs_init); +module_exit(rs_fini); +MODULE_DESCRIPTION("TXX927 serial driver"); + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + +static struct async_struct async_sercons; + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + static struct async_struct *info = &async_sercons; + int ier; + unsigned i; + + /* + * First save the IER then disable the interrupts + */ + ier = sio_reg(info)->dicr; + sio_reg(info)->dicr = 0; + + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + sio_reg(info)->tfifo = *s; + if (*s == 10) { + wait_for_xmitr(info); + sio_reg(info)->tfifo = 13; + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + sio_reg(info)->dicr = ier; +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + static struct async_struct *info = &async_sercons; + int ier; + int c; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = sio_reg(info)->dicr; + sio_reg(info)->dicr = 0; + + while (sio_reg(info)->disr & TXx927_SIDISR_UVALID) + ; + c = sio_reg(info)->rfifo; + + /* + * Restore the interrupts + */ + sio_reg(info)->dicr = ier; + + return c; +} + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TXX927_TTY_MAJOR, TXX927_TTY_MINOR_START + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (co->index < 0 || co->index >= NR_PORTS) { + return -1; + } + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; + quot = state->baud_base / baud; + + switch (cflag & CSIZE) { + case CS7: cval = TXx927_SILCR_UMODE_7BIT; break; + default: + case CS8: cval = TXx927_SILCR_UMODE_8BIT; break; + } + if (cflag & CSTOPB) + cval |= TXx927_SILCR_USBL_2BIT; + else + cval |= TXx927_SILCR_USBL_1BIT; + if (cflag & PARENB) + cval |= TXx927_SILCR_UPEN; + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + sio_reg(info)->dicr = 0; + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + /* HW RTS/CTS control */ + if (info->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + return 0; +} + +static struct console sercons = { + name: TXX927_TTY_NAME, + write: serial_console_write, + device: serial_console_device, + wait_key: serial_console_wait_key, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +/* + * Register console. + */ +void __init txx927_console_init(void) +{ + register_console(&sercons); +} +#endif diff -urN linux-2.4.18/drivers/char/softdog.c linux-2.4.19-pre5/drivers/char/softdog.c --- linux-2.4.18/drivers/char/softdog.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/softdog.c Sat Mar 30 22:55:28 2002 @@ -68,7 +68,7 @@ static struct timer_list watchdog_ticktock = { function: watchdog_fire, }; -static int timer_alive; +static unsigned long timer_alive; /* @@ -93,7 +93,7 @@ static int softdog_open(struct inode *inode, struct file *file) { - if(timer_alive) + if(test_and_set_bit(0, &timer_alive)) return -EBUSY; #ifdef CONFIG_WATCHDOG_NOWAYOUT MOD_INC_USE_COUNT; @@ -102,7 +102,6 @@ * Activate timer */ mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); - timer_alive=1; return 0; } @@ -112,12 +111,10 @@ * Shut off the timer. * Lock it in if it's a module and we defined ...NOWAYOUT */ - lock_kernel(); #ifndef CONFIG_WATCHDOG_NOWAYOUT del_timer(&watchdog_ticktock); #endif - timer_alive=0; - unlock_kernel(); + clear_bit(0, &timer_alive); return 0; } diff -urN linux-2.4.18/drivers/char/synclink.c linux-2.4.19-pre5/drivers/char/synclink.c --- linux-2.4.18/drivers/char/synclink.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/synclink.c Sat Mar 30 22:55:28 2002 @@ -1811,7 +1811,7 @@ /* Allocate and claim adapter resources */ retval = mgsl_claim_resources(info); - /* perform existance check and diagnostics */ + /* perform existence check and diagnostics */ if ( !retval ) retval = mgsl_adapter_test(info); diff -urN linux-2.4.18/drivers/char/sysrq.c linux-2.4.19-pre5/drivers/char/sysrq.c --- linux-2.4.18/drivers/char/sysrq.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.19-pre5/drivers/char/sysrq.c Sat Mar 30 22:55:34 2002 @@ -284,24 +284,20 @@ /* signal sysrq helper function * Sends a signal to all user processes */ -static void send_sig_all(int sig, int even_init) +static void send_sig_all(int sig) { struct task_struct *p; for_each_task(p) { - if (p->mm) { /* Not swapper nor kernel thread */ - if (p->pid == 1 && even_init) - /* Ugly hack to kill init */ - p->pid = 0x8000; - if (p->pid != 1) - force_sig(sig, p); - } + if (p->mm && p->pid != 1) + /* Not swapper, init nor kernel thread */ + force_sig(sig, p); } } static void sysrq_handle_term(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) { - send_sig_all(SIGTERM, 0); + send_sig_all(SIGTERM); console_loglevel = 8; } static struct sysrq_key_op sysrq_term_op = { @@ -312,7 +308,7 @@ static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) { - send_sig_all(SIGKILL, 0); + send_sig_all(SIGKILL); console_loglevel = 8; } static struct sysrq_key_op sysrq_kill_op = { @@ -321,17 +317,6 @@ action_msg: "Kill All Tasks", }; -static void sysrq_handle_killall(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { - send_sig_all(SIGKILL, 1); - console_loglevel = 8; -} -static struct sysrq_key_op sysrq_killall_op = { - handler: sysrq_handle_killall, - help_msg: "killalL", - action_msg: "Kill All Tasks (even init)", -}; - /* END SIGNAL SYSRQ HANDLERS BLOCK */ @@ -366,7 +351,7 @@ #else /* k */ NULL, #endif -/* l */ &sysrq_killall_op, +/* l */ NULL, /* m */ &sysrq_showmem_op, /* n */ NULL, /* o */ NULL, /* This will often be registered diff -urN linux-2.4.18/drivers/char/tpqic02.c linux-2.4.19-pre5/drivers/char/tpqic02.c --- linux-2.4.18/drivers/char/tpqic02.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/tpqic02.c Sat Mar 30 22:55:28 2002 @@ -2750,7 +2750,9 @@ * the config parameters have been set using MTSETCONFIG. */ - if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE)) { + /* Grab the IO region. */ + if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, + TPQIC02_NAME)) { printk(TPQIC02_NAME ": IO space at 0x%x [%d ports] already reserved\n", QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); @@ -2764,6 +2766,7 @@ printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n", QIC02_TAPE_IRQ); + release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); return -EBUSY; } @@ -2773,12 +2776,9 @@ ": can't allocate DMA%d for QIC-02 tape\n", QIC02_TAPE_DMA); free_irq(QIC02_TAPE_IRQ, NULL); + release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); return -EBUSY; } - - /* Grab the IO region. We already made sure it's available. */ - request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, - TPQIC02_NAME); /* Setup the page-address for the dma transfer. */ buffaddr = diff -urN linux-2.4.18/drivers/char/tty_io.c linux-2.4.19-pre5/drivers/char/tty_io.c --- linux-2.4.18/drivers/char/tty_io.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/tty_io.c Sat Mar 30 22:55:39 2002 @@ -160,6 +160,8 @@ extern void sci_console_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_init(void); +extern void txx927_console_init(void); +extern void sb1250_serial_console_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -1847,6 +1849,9 @@ for_each_task(p) { if ((p->tty == tty) || ((session > 0) && (p->session == session))) { + printk(KERN_NOTICE "SAK: killed process %d" + " (%s): p->session==tty->session\n", + p->pid, p->comm); send_sig(SIGKILL, p, 1); continue; } @@ -1857,6 +1862,9 @@ filp = fcheck_files(p->files, i); if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { + printk(KERN_NOTICE "SAK: killed process %d" + " (%s): fd#%d opened to the tty\n", + p->pid, p->comm, i); send_sig(SIGKILL, p, 1); break; } @@ -2248,6 +2256,12 @@ #endif #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); +#endif +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + txx927_console_init(); +#endif +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE + sb1250_serial_console_init(); #endif } diff -urN linux-2.4.18/drivers/char/vme_scc.c linux-2.4.19-pre5/drivers/char/vme_scc.c --- linux-2.4.18/drivers/char/vme_scc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/vme_scc.c Sat Mar 30 22:55:34 2002 @@ -131,7 +131,11 @@ memset(&scc_driver, 0, sizeof(scc_driver)); scc_driver.magic = TTY_DRIVER_MAGIC; scc_driver.driver_name = "scc"; +#ifdef CONFIG_DEVFS_FS + scc_driver.name = "tts/%d"; +#else scc_driver.name = "ttyS"; +#endif scc_driver.major = TTY_MAJOR; scc_driver.minor_start = SCC_MINOR_BASE; scc_driver.num = 2; @@ -164,7 +168,11 @@ scc_driver.break_ctl = scc_break_ctl; scc_callout_driver = scc_driver; +#ifdef CONFIG_DEVFS_FS + scc_callout_driver.name = "cua/%d"; +#else scc_callout_driver.name = "cua"; +#endif scc_callout_driver.major = TTYAUX_MAJOR; scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT; @@ -214,7 +222,7 @@ { struct scc_port *port; - printk("SCC: MVME147 Serial Driver\n"); + printk(KERN_INFO "SCC: MVME147 Serial Driver\n"); /* Init channel A */ port = &scc_ports[0]; port->channel = CHANNEL_A; @@ -284,7 +292,7 @@ if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) return (-ENODEV); - printk("SCC: MVME162 Serial Driver\n"); + printk(KERN_INFO "SCC: MVME162 Serial Driver\n"); /* Init channel A */ port = &scc_ports[0]; port->channel = CHANNEL_A; @@ -352,7 +360,7 @@ { struct scc_port *port; - printk("SCC: BVME6000 Serial Driver\n"); + printk(KERN_INFO "SCC: BVME6000 Serial Driver\n"); /* Init channel A */ port = &scc_ports[0]; port->channel = CHANNEL_A; @@ -449,7 +457,7 @@ ch = SCCread_NB(RX_DATA_REG); if (!tty) { - printk ("scc_rx_int with NULL tty!\n"); + printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return; } @@ -487,7 +495,7 @@ SCC_ACCESS_INIT(port); if (!tty) { - printk ("scc_spcond_int with NULL tty!\n"); + printk(KERN_WARNING "scc_spcond_int with NULL tty!\n"); SCCwrite(COMMAND_REG, CR_ERROR_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return; @@ -533,7 +541,7 @@ SCC_ACCESS_INIT(port); if (!port->gs.tty) { - printk ("scc_tx_int with NULL tty!\n"); + printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); @@ -719,7 +727,7 @@ else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) || (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) { - printk("SCC: Bad speed requested, %d\n", baud); + printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud); return 0; } @@ -731,12 +739,10 @@ #ifdef CONFIG_MVME147_SCC if (MACH_IS_MVME147) brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; - else #endif #ifdef CONFIG_MVME162_SCC if (MACH_IS_MVME16x) brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; - else #endif #ifdef CONFIG_BVME6000_SCC if (MACH_IS_BVME6000) @@ -783,6 +789,15 @@ } +/* Comment taken from sx.c (2.4.0): + I haven't the foggiest why the decrement use count has to happen + here. The whole linux serial drivers stuff needs to be redesigned. + My guess is that this is a hack to minimize the impact of a bug + elsewhere. Thinking about it some more. (try it sometime) Try + running minicom on a serial port that is driven by a modularized + driver. Have the modem hangup. Then remove the driver module. Then + exit minicom. I expect an "oops". -- REW */ + static void scc_hungup(void *ptr) { scc_disable_tx_interrupts(ptr); @@ -795,6 +810,7 @@ { scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr); + MOD_DEC_USE_COUNT; } @@ -809,6 +825,7 @@ SCC_ACCESS_INIT(port); save_flags(flags); + cli(); t = SCCread(TX_CTRL_REG); if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); @@ -933,7 +950,7 @@ if (port->gs.count == 1) { MOD_INC_USE_COUNT; } - retval = block_til_ready(port, filp); + retval = gs_block_til_ready(port, filp); if (retval) { MOD_DEC_USE_COUNT; diff -urN linux-2.4.18/drivers/char/w83877f_wdt.c linux-2.4.19-pre5/drivers/char/w83877f_wdt.c --- linux-2.4.18/drivers/char/w83877f_wdt.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/char/w83877f_wdt.c Sat Mar 30 22:55:39 2002 @@ -13,9 +13,10 @@ * any of this software. This material is provided "AS-IS" in * the hope that it may be useful for others. * - * (c) Copyright 2001 Scott Jennings + * (c) Copyright 2001 Scott Jennings * * 4/19 - 2001 [Initial revision] + * 9/27 - 2001 Added spinlocking * * * Theory of operation: @@ -88,8 +89,9 @@ static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; -static int wdt_is_open; +static unsigned long wdt_is_open; static int wdt_expect_close; +static spinlock_t wdt_spinlock; /* * Whack the dog @@ -102,11 +104,18 @@ */ if(time_before(jiffies, next_heartbeat)) { + /* Ping the WDT */ + spin_lock(&wdt_spinlock); + /* Ping the WDT by reading from WDT_PING */ inb_p(WDT_PING); + /* Re-set the timer interval */ timer.expires = jiffies + WDT_INTERVAL; add_timer(&timer); + + spin_unlock(&wdt_spinlock); + } else { printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); } @@ -118,19 +127,24 @@ static void wdt_change(int writeval) { + unsigned long flags; + spin_lock_irqsave(&wdt_spinlock, flags); + /* buy some time */ inb_p(WDT_PING); /* make W83877F available */ - outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); - outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); /* enable watchdog */ - outb_p(WDT_REGISTER,ENABLE_W83877F_PORT); - outb_p(writeval,ENABLE_W83877F_PORT+1); + outb_p(WDT_REGISTER, ENABLE_W83877F_PORT); + outb_p(writeval, ENABLE_W83877F_PORT+1); /* lock the W8387FF away */ - outb_p(DISABLE_W83877F,ENABLE_W83877F_PORT); + outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT); + + spin_unlock_irqrestore(&wdt_spinlock, flags); } static void wdt_startup(void) @@ -178,7 +192,7 @@ /* now scan */ for(ofs = 0; ofs != count; ofs++) - if(buf[ofs] == 'V') + if(buf[ofs] == 'V') wdt_expect_close = 1; /* someone wrote to us, we should restart timer */ @@ -200,10 +214,11 @@ { case WATCHDOG_MINOR: /* Just in case we're already talking to someone... */ - if(wdt_is_open) + if(test_and_set_bit(0, &wdt_is_open)) { + spin_unlock(&fop_spinlock); return -EBUSY; + } /* Good, fire up the show */ - wdt_is_open = 1; wdt_startup(); return 0; @@ -214,7 +229,6 @@ static int fop_close(struct inode * inode, struct file * file) { - lock_kernel(); if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) { if(wdt_expect_close) @@ -224,13 +238,11 @@ printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); } } - wdt_is_open = 0; - unlock_kernel(); + clear_bit(0, &wdt_is_open); return 0; } -static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static struct watchdog_info ident= { @@ -307,6 +319,9 @@ { int rc = -EBUSY; + spin_lock_init(&wdt_spinlock); + spin_lock_init(&fop_spinlock); + if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) goto err_out; if (!request_region(WDT_PING, 1, "W8387FF WDT")) @@ -341,4 +356,7 @@ module_init(w83877f_wdt_init); module_exit(w83877f_wdt_unload); +MODULE_AUTHOR("Scott and Bill Jennings"); +MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip"); MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.18/drivers/char/wafer5823wdt.c linux-2.4.19-pre5/drivers/char/wafer5823wdt.c --- linux-2.4.18/drivers/char/wafer5823wdt.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/char/wafer5823wdt.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,220 @@ +/* + * ICP Wafer 5823 Single Board Computer WDT driver for Linux 2.4.x + * http://www.icpamerica.com/wafer_5823.php + * May also work on other similar models + * + * (c) Copyright 2002 Justin Cormack + * + * Release 0.02 + * + * Based on advantechwdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long wafwdt_is_open; +static spinlock_t wafwdt_lock; + +/* + * You must set these - there is no sane way to probe for this board. + * + * To enable, write the timeout value in seconds (1 to 255) to I/O + * port WDT_START, then read the port to start the watchdog. To pat + * the dog, read port WDT_STOP to stop the timer, then read WDT_START + * to restart it again. + */ + +#define WDT_START 0x443 +#define WDT_STOP 0x843 + +#define WD_TIMO 60 /* 1 minute */ + +static void wafwdt_ping(void) +{ + /* pat watchdog */ + spin_lock(&wafwdt_lock); + inb_p(WDT_STOP); + inb_p(WDT_START); + spin_unlock(&wafwdt_lock); +} + +static void wafwdt_start(void) +{ + /* start up watchdog */ + outb_p(WD_TIMO, WDT_START); + inb_p(WDT_START); +} + +static void +wafwdt_stop(void) +{ + /* stop watchdog */ + inb_p(WDT_STOP); +} + +static ssize_t wafwdt_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + wafwdt_ping(); + return 1; + } + return 0; +} + +static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "Wafer 5823 WDT" + }; + int one=1; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *) arg, &one, sizeof (int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + wafwdt_ping(); + break; + + default: + return -ENOTTY; + } + return 0; +} + +static int wafwdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &wafwdt_is_open)) + return -EBUSY; + wafwdt_start(); + return 0; +} + +static int +wafwdt_close(struct inode *inode, struct file *file) +{ + clear_bit(0, &wafwdt_is_open); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + wafwdt_stop(); +#endif + return 0; +} + +/* + * Notifier for system down + */ + +static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + wafwdt_stop(); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations wafwdt_fops = { + owner:THIS_MODULE, + write:wafwdt_write, + ioctl:wafwdt_ioctl, + open:wafwdt_open, + release:wafwdt_close, +}; + +static struct miscdevice wafwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wafwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wafwdt_notifier = { + wafwdt_notify_sys, + NULL, + 0 +}; + +static int __init wafwdt_init(void) +{ + printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n"); + + spin_lock_init(&wafwdt_lock); + if(!request_region(WDT_STOP, 1, "Wafer 5823 WDT")) + goto error; + if(!request_region(WDT_START, 1, "Wafer 5823 WDT")) + goto error2; + if(misc_register(&wafwdt_miscdev)<0) + goto error3; + register_reboot_notifier(&wafwdt_notifier); + return 0; +error3: + release_region(WDT_START, 1); +error2: + release_region(WDT_STOP, 1); +error: + return -ENODEV; +} + +static void __exit wafwdt_exit(void) +{ + misc_deregister(&wafwdt_miscdev); + unregister_reboot_notifier(&wafwdt_notifier); + release_region(WDT_STOP, 1); + release_region(WDT_START, 1); +} + +module_init(wafwdt_init); +module_exit(wafwdt_exit); + +MODULE_AUTHOR("Justin Cormack"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +/* end of wafer5823wdt.c */ diff -urN linux-2.4.18/drivers/char/wdt.c linux-2.4.19-pre5/drivers/char/wdt.c --- linux-2.4.18/drivers/char/wdt.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/wdt.c Sat Mar 30 22:55:39 2002 @@ -51,7 +51,7 @@ #include #include -static int wdt_is_open; +static unsigned long wdt_is_open; /* * You must set these - there is no sane way to probe for this board. @@ -355,7 +355,7 @@ switch(MINOR(inode->i_rdev)) { case WATCHDOG_MINOR: - if(wdt_is_open) + if(test_and_set_bit(0, &wdt_is_open)) return -EBUSY; /* * Activate @@ -392,16 +392,14 @@ static int wdt_release(struct inode *inode, struct file *file) { - lock_kernel(); if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) { #ifndef CONFIG_WATCHDOG_NOWAYOUT inb_p(WDT_DC); /* Disable counters */ wdt_ctr_load(2,0); /* 0 length reset pulses now */ #endif - wdt_is_open=0; + clear_bit(0, &wdt_is_open); } - unlock_kernel(); return 0; } diff -urN linux-2.4.18/drivers/char/wdt_pci.c linux-2.4.19-pre5/drivers/char/wdt_pci.c --- linux-2.4.18/drivers/char/wdt_pci.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/char/wdt_pci.c Sat Mar 30 22:55:39 2002 @@ -31,6 +31,7 @@ * Jeff Garzik : PCI cleanups * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures * Joel Becker : Added WDIOC_GET/SETTIMEOUT + * Zwane Mwaikambo : Magic char closing, locking changes, cleanups */ #include @@ -53,7 +54,8 @@ #include #include #include -#include +#include +#include #include @@ -72,52 +74,19 @@ #define PCI_DEVICE_ID_WDG_CSM 0x22c0 #endif -static int wdt_is_open; +static struct semaphore open_sem; +static spinlock_t wdtpci_lock; +static int expect_close = 0; -/* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. - */ - -static int io=0x240; -static int irq=11; +static int io; +static int irq; /* Default timeout */ #define WD_TIMO (100*60) /* 1 minute */ +#define WD_TIMO_MAX (WD_TIMO*60) /* 1 hour(?) */ static int wd_margin = WD_TIMO; -#ifndef MODULE - -/** - * wdtpci_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 wdtpci_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - { - io = ints[1]; - if(ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("wdt=", wdtpci_setup); - -#endif /* !MODULE */ - /* * Programming support */ @@ -233,11 +202,15 @@ static void wdtpci_ping(void) { + unsigned long flags; + /* Write a watchdog value */ + spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); wdtpci_ctr_mode(1,2); wdtpci_ctr_load(1,wd_margin); /* Timeout */ outb_p(0, WDT_DC); + spin_unlock_irqrestore(&wdtpci_lock, flags); } /** @@ -257,12 +230,21 @@ if (ppos != &file->f_pos) return -ESPIPE; - if(count) - { + if (count) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + size_t i; + + expect_close = 0; + + for (i = 0; i != count; i++) { + if (buf[i] == 'V') + expect_close = 1; + } +#endif wdtpci_ping(); - return 1; } - return 0; + + return count; } /** @@ -343,13 +325,14 @@ if (get_user(new_margin, (int *)arg)) return -EFAULT; /* Arbitrary, can't find the card's limits */ - if ((new_margin < 0) || (new_margin > 60)) + new_margin *= 100; + if ((new_margin < 0) || (new_margin > WD_TIMO_MAX)) return -EINVAL; - wd_margin = new_margin * 100; + wd_margin = new_margin; wdtpci_ping(); /* Fall */ case WDIOC_GETTIMEOUT: - return put_user(wd_margin, (int *)arg); + return put_user(wd_margin / 100, (int *)arg); } } @@ -367,20 +350,22 @@ static int wdtpci_open(struct inode *inode, struct file *file) { + unsigned long flags; + switch(MINOR(inode->i_rdev)) { case WATCHDOG_MINOR: - if(wdt_is_open) - return -EBUSY; + if (down_trylock(&open_sem)) + return -EBUSY; + #ifdef CONFIG_WATCHDOG_NOWAYOUT MOD_INC_USE_COUNT; #endif /* * Activate */ - - wdt_is_open=1; - + spin_lock_irqsave(&wdtpci_lock, flags); + inb_p(WDT_DC); /* Disable */ /* @@ -405,6 +390,7 @@ wdtpci_ctr_load(1,wd_margin);/* Timeout 60 seconds */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ outb_p(0, WDT_DC); /* Enable */ + spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; case TEMP_MINOR: return 0; @@ -427,15 +413,21 @@ static int wdtpci_release(struct inode *inode, struct file *file) { - if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) - { - lock_kernel(); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_DC); /* Disable counters */ - wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + + if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + unsigned long flags; + if (expect_close) { + spin_lock_irqsave(&wdtpci_lock, flags); + inb_p(WDT_DC); /* Disable counters */ + wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + spin_unlock_irqrestore(&wdtpci_lock, flags); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping timer!"); + wdtpci_ping(); + } #endif - wdt_is_open=0; - unlock_kernel(); + up(&open_sem); } return 0; } @@ -455,11 +447,14 @@ static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if(code==SYS_DOWN || code==SYS_HALT) - { + unsigned long flags; + + if (code==SYS_DOWN || code==SYS_HALT) { /* Turn the card off */ + spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); wdtpci_ctr_load(2,0); + spin_unlock_irqrestore(&wdtpci_lock, flags); } return NOTIFY_DONE; } @@ -520,6 +515,9 @@ "this driver only supports 1 device\n"); return -ENODEV; } + + sema_init(&open_sem, 1); + spin_lock_init(&wdtpci_lock); irq = dev->irq; io = pci_resource_start (dev, 2); @@ -577,7 +575,7 @@ } -static void __exit wdtpci_remove_one (struct pci_dev *pdev) +static void __devexit wdtpci_remove_one (struct pci_dev *pdev) { /* here we assume only one device will ever have * been picked up and registered by probe function */ @@ -602,7 +600,7 @@ name: "wdt-pci", id_table: wdtpci_pci_tbl, probe: wdtpci_init_one, - remove: wdtpci_remove_one, + remove: __devexit_p(wdtpci_remove_one), }; diff -urN linux-2.4.18/drivers/fc4/soc.c linux-2.4.19-pre5/drivers/fc4/soc.c --- linux-2.4.18/drivers/fc4/soc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/fc4/soc.c Sat Mar 30 22:55:39 2002 @@ -741,7 +741,6 @@ for_each_soc(s) { irq = s->port[0].fc.irq; - disable_irq (irq); free_irq (irq, s); fcp_release(&(s->port[0].fc), 2); diff -urN linux-2.4.18/drivers/fc4/socal.c linux-2.4.19-pre5/drivers/fc4/socal.c --- linux-2.4.18/drivers/fc4/socal.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/fc4/socal.c Sat Mar 30 22:55:39 2002 @@ -880,7 +880,6 @@ for_each_socal(s) { irq = s->port[0].fc.irq; - disable_irq (irq); free_irq (irq, s); fcp_release(&(s->port[0].fc), 2); diff -urN linux-2.4.18/drivers/hotplug/Config.in linux-2.4.19-pre5/drivers/hotplug/Config.in --- linux-2.4.18/drivers/hotplug/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/hotplug/Config.in Sat Mar 30 22:55:28 2002 @@ -4,9 +4,11 @@ mainmenu_option next_comment comment 'PCI Hotplug Support' -dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_DDFS $CONFIG_EXPERIMENTAL +dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL -dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI +dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86 dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ +dep_tristate ' IBM PCI Hotplug driver' CONFIG_HOTPLUG_PCI_IBM $CONFIG_HOTPLUG_PCI $CONFIG_X86_IO_APIC $CONFIG_X86 +dep_tristate ' ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_ACPI $CONFIG_HOTPLUG_PCI endmenu diff -urN linux-2.4.18/drivers/hotplug/Makefile linux-2.4.19-pre5/drivers/hotplug/Makefile --- linux-2.4.18/drivers/hotplug/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/hotplug/Makefile Sat Mar 30 22:55:28 2002 @@ -4,12 +4,14 @@ O_TARGET := vmlinux-obj.o -list-multi := cpqphp.o pci_hotplug.o +list-multi := cpqphp.o pci_hotplug.o ibmphp.o pcihpacpi.o export-objs := pci_hotplug_core.o pci_hotplug_util.o obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o +obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += pcihpacpi.o pci_hotplug-objs := pci_hotplug_core.o \ pci_hotplug_util.o @@ -19,6 +21,22 @@ cpqphp_proc.o \ cpqphp_pci.o +ibmphp-objs := ibmphp_core.o \ + ibmphp_ebda.o \ + ibmphp_pci.o \ + ibmphp_res.o \ + ibmphp_hpc.o + +ifdef CONFIG_HOTPLUG_PCI_ACPI + EXTRA_CFLAGS += -D_LINUX -I$(CURDIR)/../acpi + ifdef CONFIG_ACPI_DEBUG + EXTRA_CFLAGS += -DACPI_DEBUG -Wno-unused + endif +endif + +pcihp_acpi_objs := pcihp_acpi.o \ + pcihp_acpi_glue.o + ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) cpqphp-objs += cpqphp_nvram.o endif @@ -32,3 +50,8 @@ cpqphp.o: $(cpqphp-objs) $(LD) -r -o $@ $(cpqphp-objs) +ibmphp.o: $(ibmphp-objs) + $(LD) -r -o $@ $(ibmphp-objs) + +pcihpacpi.o: $(pcihp_acpi_objs) + $(LD) -r -o $@ $(pcihp_acpi_objs) diff -urN linux-2.4.18/drivers/hotplug/cpqphp_ctrl.c linux-2.4.19-pre5/drivers/hotplug/cpqphp_ctrl.c --- linux-2.4.18/drivers/hotplug/cpqphp_ctrl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/hotplug/cpqphp_ctrl.c Sat Mar 30 22:55:28 2002 @@ -1707,6 +1707,7 @@ struct controller *ctrl; lock_kernel(); daemonize(); + reparent_to_init(); // New name strcpy(current->comm, "phpd_event"); diff -urN linux-2.4.18/drivers/hotplug/cpqphp_proc.c linux-2.4.19-pre5/drivers/hotplug/cpqphp_proc.c --- linux-2.4.18/drivers/hotplug/cpqphp_proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/hotplug/cpqphp_proc.c Sat Mar 30 22:55:28 2002 @@ -177,7 +177,7 @@ int cpqhp_proc_init_ctrl (void) { - ctrl_proc_root = proc_mkdir("driver/hpc", NULL); + ctrl_proc_root = proc_mkdir("hpc", proc_root_driver); if (!ctrl_proc_root) return -ENOMEM; ctrl_proc_root->owner = THIS_MODULE; diff -urN linux-2.4.18/drivers/hotplug/ibmphp.h linux-2.4.19-pre5/drivers/hotplug/ibmphp.h --- linux-2.4.18/drivers/hotplug/ibmphp.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp.h Sat Mar 30 22:55:28 2002 @@ -0,0 +1,745 @@ +#ifndef __IBMPHP_H +#define __IBMPHP_H + +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include "pci_hotplug.h" + +extern int ibmphp_debug; + +#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) + #define MY_NAME "ibmphpd" +#else + #define MY_NAME THIS_MODULE->name +#endif +#define debug(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* EBDA stuff */ + +/*********************************************************** +* SLOT CAPABILITY * +***********************************************************/ + +#define EBDA_SLOT_133_MAX 0x20 +#define EBDA_SLOT_100_MAX 0x10 +#define EBDA_SLOT_66_MAX 0x02 +#define EBDA_SLOT_PCIX_CAP 0x08 + + +/************************************************************ +* RESOURE TYPE * +************************************************************/ + +#define EBDA_RSRC_TYPE_MASK 0x03 +#define EBDA_IO_RSRC_TYPE 0x00 +#define EBDA_MEM_RSRC_TYPE 0x01 +#define EBDA_PFM_RSRC_TYPE 0x03 +#define EBDA_RES_RSRC_TYPE 0x02 + + +/************************************************************* +* IO RESTRICTION TYPE * +*************************************************************/ + +#define EBDA_IO_RESTRI_MASK 0x0c +#define EBDA_NO_RESTRI 0x00 +#define EBDA_AVO_VGA_ADDR 0x04 +#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 +#define EBDA_AVO_ISA_ADDR 0x0c + + +/************************************************************** +* DEVICE TYPE DEF * +**************************************************************/ + +#define EBDA_DEV_TYPE_MASK 0x10 +#define EBDA_PCI_DEV 0x10 +#define EBDA_NON_PCI_DEV 0x00 + + +/*************************************************************** +* PRIMARY DEF DEFINITION * +***************************************************************/ + +#define EBDA_PRI_DEF_MASK 0x20 +#define EBDA_PRI_PCI_BUS_INFO 0x20 +#define EBDA_NORM_DEV_RSRC_INFO 0x00 + + +//-------------------------------------------------------------- +// RIO TABLE DATA STRUCTURE +//-------------------------------------------------------------- + +struct rio_table_hdr { + u8 ver_num; + u8 scal_count; + u8 riodev_count; + u16 offset; +}; + +//------------------------------------------------------------- +// SCALABILITY DETAIL +//------------------------------------------------------------- + +struct scal_detail { + u8 node_id; + u32 cbar; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 port2_node_connect; + u8 port2_port_connect; +// struct list_head scal_detail_list; +}; + +//-------------------------------------------------------------- +// RIO DETAIL +//-------------------------------------------------------------- + +struct rio_detail { + u8 rio_node_id; + u32 bbar; + u8 rio_type; + u8 owner_id; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 first_slot_num; + u8 status; +// struct list_head rio_detail_list; +}; + + +/**************************************************************** +* HPC DESCRIPTOR NODE * +****************************************************************/ + +struct ebda_hpc_list { + u8 format; + u16 num_ctlrs; + short phys_addr; +// struct list_head ebda_hpc_list; +}; + +/***************************************************************** +* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * +* STRUCTURE * +*****************************************************************/ + +struct ebda_hpc_slot { + u8 slot_num; + u32 slot_bus_num; + u8 ctl_index; + u8 slot_cap; +}; + +struct ebda_hpc_bus { + u32 bus_num; +/* + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; +*/ +}; + + +/******************************************************************** +* THREE TYPE OF HOT PLUG CONTROLER * +********************************************************************/ + +struct isa_ctlr_access { + u16 io_start; + u16 io_end; +}; + +struct pci_ctlr_access { + u8 bus; + u8 dev_fun; +}; + +struct wpeg_i2c_ctlr_access { + ulong wpegbbar; + u8 i2c_addr; +}; + +/************************************************************************* +* RSTC DESCRIPTOR NODE * +*************************************************************************/ + +struct ebda_rsrc_list { + u8 format; + u16 num_entries; + u16 phys_addr; + struct ebda_rsrc_list *next; +}; + + +/*************************************************************************** +* PCI RSRC NODE * +***************************************************************************/ + +struct ebda_pci_rsrc { + u8 rsrc_type; + u8 bus_num; + u8 dev_fun; + ulong start_addr; + ulong end_addr; + struct list_head ebda_pci_rsrc_list; +}; + + +/*********************************************************** +* BUS_INFO DATE STRUCTURE * +***********************************************************/ + +struct bus_info { + u8 slot_min; + u8 slot_max; + u8 slot_count; + u8 busno; + u8 current_speed; + u8 supported_speed; + u8 controller_id; + u8 supported_bus_mode; + u8 current_bus_mode; + u8 index; + struct list_head bus_info_list; +}; + + +/*********************************************************** +* GLOBAL VARIABLES * +***********************************************************/ +extern struct list_head ibmphp_ebda_pci_rsrc_head; +extern struct list_head ibmphp_slot_head; + +/*********************************************************** +* FUNCTION PROTOTYPES * +***********************************************************/ + +extern void ibmphp_free_ebda_hpc_queue (void); +extern int ibmphp_access_ebda (void); +extern struct slot *ibmphp_get_slot_from_physical_num (u8); +extern int ibmphp_get_total_hp_slots (void); +extern void ibmphp_free_ibm_slot (struct slot *); +extern void ibmphp_free_bus_info_queue (void); +extern void ibmphp_free_ebda_pci_rsrc_queue (void); +extern struct bus_info *ibmphp_find_same_bus_num (u32); +extern int ibmphp_get_bus_index (u8); +extern u16 ibmphp_get_total_controllers (void); + +/* passed parameters */ +#define MEM 0 +#define IO 1 +#define PFMEM 2 + +/* bit masks */ +#define RESTYPE 0x03 +#define IOMASK 0x00 /* will need to take its complement */ +#define MMASK 0x01 +#define PFMASK 0x03 +#define PCIDEVMASK 0x10 /* we should always have PCI devices */ +#define PRIMARYBUSMASK 0x20 + +/* pci specific defines */ +#define PCI_VENDOR_ID_NOTVALID 0xFFFF +#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 +#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 + +#define LATENCY 0x64 +#define CACHE 64 +#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ + +#define IOBRIDGE 0x1000 /* 4k */ +#define MEMBRIDGE 0x100000 /* 1M */ + +/* irqs */ +#define SCSI_IRQ 0x09 +#define LAN_IRQ 0x0A +#define OTHER_IRQ 0x0B + +/* Data Structures */ + +/* type is of the form x x xx xx + * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory + * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid + * | | VGA and their aliases, 11 - Avoid ISA + * | - 1 - PCI device, 0 - non pci device + * - 1 - Primary PCI Bus Information (0 if Normal device) + * the IO restrictions [2:3] are only for primary buses + */ + + +/* we need this struct because there could be several resource blocks + * allocated per primary bus in the EBDA + */ +struct range_node { + int rangeno; + u32 start; + u32 end; + struct range_node *next; +}; + +struct bus_node { + u8 busno; + int noIORanges; + struct range_node *rangeIO; + int noMemRanges; + struct range_node *rangeMem; + int noPFMemRanges; + struct range_node *rangePFMem; + int needIOUpdate; + int needMemUpdate; + int needPFMemUpdate; + struct resource_node *firstIO; /* first IO resource on the Bus */ + struct resource_node *firstMem; /* first memory resource on the Bus */ + struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ + struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ + struct list_head bus_list; +}; + +struct resource_node { + int rangeno; + u8 busno; + u8 devfunc; + u32 start; + u32 end; + u32 len; + int type; /* MEM, IO, PFMEM */ + u8 fromMem; /* this is to indicate that the range is from + * from the Memory bucket rather than from PFMem */ + struct resource_node *next; + struct resource_node *nextRange; /* for the other mem range on bus */ +}; + +struct res_needed { + u32 mem; + u32 pfmem; + u32 io; + u8 not_correct; /* needed for return */ + int devices[32]; /* for device numbers behind this bridge */ +}; + +/* functions */ + +extern int ibmphp_rsrc_init (void); +extern int ibmphp_add_resource (struct resource_node *); +extern int ibmphp_remove_resource (struct resource_node *); +extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); +extern int ibmphp_check_resource (struct resource_node *, u8); +extern int ibmphp_remove_bus (struct bus_node *, u8); +extern void ibmphp_free_resources (void); +extern int ibmphp_add_pfmem_from_mem (struct resource_node *); +extern struct bus_node *ibmphp_find_res_bus (u8); +extern void ibmphp_print_test (void); /* for debugging purposes */ + +extern void ibmphp_hpc_initvars (void); +extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); +extern int ibmphp_hpc_writeslot (struct slot *, u8); +extern void ibmphp_lock_operations (void); +extern void ibmphp_unlock_operations (void); +extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); +extern int ibmphp_hpc_start_poll_thread (void); +extern void ibmphp_hpc_stop_poll_thread (void); + +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// HPC return codes +//---------------------------------------------------------------------------- +#define FALSE 0x00 +#define TRUE 0x01 +#define HPC_ERROR 0xFF + +//----------------------------------------------------------------------------- +// BUS INFO +//----------------------------------------------------------------------------- +#define BUS_SPEED 0x30 +#define BUS_MODE 0x40 +#define BUS_MODE_PCIX 0x01 +#define BUS_MODE_PCI 0x00 +#define BUS_SPEED_2 0x20 +#define BUS_SPEED_1 0x10 +#define BUS_SPEED_33 0x00 +#define BUS_SPEED_66 0x01 +#define BUS_SPEED_100 0x02 +#define BUS_SPEED_133 0x03 +#define BUS_SPEED_66PCIX 0x04 +#define BUS_SPEED_66UNKNOWN 0x05 +#define BUS_STATUS_AVAILABLE 0x01 +#define BUS_CONTROL_AVAILABLE 0x02 +#define SLOT_LATCH_REGS_SUPPORTED 0x10 + +#define PRGM_MODEL_REV_LEVEL 0xF0 +#define MAX_ADAPTER_NONE 0x09 + +//---------------------------------------------------------------------------- +// HPC 'write' operations/commands +//---------------------------------------------------------------------------- +// Command Code State Write to reg +// Machine at index +//------------------------- ---- ------- ------------ +#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 +#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 +#define HPC_SLOT_OFF 0x02 // Y 0-14 +#define HPC_SLOT_ON 0x03 // Y 0-14 +#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 +#define HPC_SLOT_ATTNON 0x05 // N 0-14 +#define HPC_CTLR_CLEARIRQ 0x06 // N 15 +#define HPC_CTLR_RESET 0x07 // Y 15 +#define HPC_CTLR_IRQSTEER 0x08 // N 15 +#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 +#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 +#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 +#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 +#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 +#define HPC_ALLSLOT_OFF 0x11 // Y 15 +#define HPC_ALLSLOT_ON 0x12 // Y 15 +#define HPC_SLOT_BLINKLED 0x13 // N 0-14 + +//---------------------------------------------------------------------------- +// read commands +//---------------------------------------------------------------------------- +#define READ_SLOTSTATUS 0x01 +#define READ_EXTSLOTSTATUS 0x02 +#define READ_BUSSTATUS 0x03 +#define READ_CTLRSTATUS 0x04 +#define READ_ALLSTAT 0x05 +#define READ_ALLSLOT 0x06 +#define READ_SLOTLATCHLOWREG 0x07 +#define READ_REVLEVEL 0x08 +#define READ_HPCOPTIONS 0x09 +//---------------------------------------------------------------------------- +// slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER 0x01 +#define HPC_SLOT_CONNECT 0x02 +#define HPC_SLOT_ATTN 0x04 +#define HPC_SLOT_PRSNT2 0x08 +#define HPC_SLOT_PRSNT1 0x10 +#define HPC_SLOT_PWRGD 0x20 +#define HPC_SLOT_BUS_SPEED 0x40 +#define HPC_SLOT_LATCH 0x80 + +//---------------------------------------------------------------------------- +// HPC_SLOT_POWER status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER_OFF 0x00 +#define HPC_SLOT_POWER_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_CONNECT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_CONNECTED 0x00 +#define HPC_SLOT_DISCONNECTED 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_ATTN status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_OFF 0x00 +#define HPC_SLOT_ATTN_ON 0x01 +#define HPC_SLOT_ATTN_BLINK 0x02 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PRSNT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_EMPTY 0x00 +#define HPC_SLOT_PRSNT_7 0x01 +#define HPC_SLOT_PRSNT_15 0x02 +#define HPC_SLOT_PRSNT_25 0x03 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PWRGD status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 +#define HPC_SLOT_PWRGD_GOOD 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_BUS_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_SPEED_OK 0x00 +#define HPC_SLOT_BUS_SPEED_MISM 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_LATCH status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open +#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed + + +//---------------------------------------------------------------------------- +// extended slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX 0x01 +#define HPC_SLOT_SPEED1 0x02 +#define HPC_SLOT_SPEED2 0x04 +#define HPC_SLOT_BLINK_ATTN 0x08 +#define HPC_SLOT_RSRVD1 0x10 +#define HPC_SLOT_RSRVD2 0x20 +#define HPC_SLOT_BUS_MODE 0x40 +#define HPC_SLOT_RSRVD3 0x80 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_PCIX_CAP status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX_NO 0x00 +#define HPC_SLOT_PCIX_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_SPEED_33 0x00 +#define HPC_SLOT_SPEED_66 0x01 +#define HPC_SLOT_SPEED_133 0x02 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_ATTN_BLINK status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_BLINK_OFF 0x00 +#define HPC_SLOT_ATTN_BLINK_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_BUS_MODE status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_MODE_OK 0x00 +#define HPC_SLOT_BUS_MODE_MISM 0x01 + +//---------------------------------------------------------------------------- +// Controller status +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING 0x01 +#define HPC_CTLR_FINISHED 0x02 +#define HPC_CTLR_RESULT0 0x04 +#define HPC_CTLR_RESULT1 0x08 +#define HPC_CTLR_RESULE2 0x10 +#define HPC_CTLR_RESULT3 0x20 +#define HPC_CTLR_IRQ_ROUTG 0x40 +#define HPC_CTLR_IRQ_PENDG 0x80 + +//---------------------------------------------------------------------------- +// HPC_CTLR_WROKING status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING_NO 0x00 +#define HPC_CTLR_WORKING_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_FINISHED status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_FINISHED_NO 0x00 +#define HPC_CTLR_FINISHED_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_RESULT status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_RESULT_SUCCESS 0x00 +#define HPC_CTLR_RESULT_FAILED 0x01 +#define HPC_CTLR_RESULT_RSVD 0x02 +#define HPC_CTLR_RESULT_NORESP 0x03 + + +//---------------------------------------------------------------------------- +// macro for slot info +//---------------------------------------------------------------------------- +#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ + ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) + +#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ + ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) + +#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ + ? HPC_SLOT_ATTN_BLINK \ + : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) + +#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ + ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ + : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) + +#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ + ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) + +#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ + ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) + +#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ + ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) + +#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ + ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) + +#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ + ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ + : HPC_SLOT_SPEED_66) \ + : HPC_SLOT_SPEED_33)) + +#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ + ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) + +//-------------------------------------------------------------------------- +// macro for bus info +//--------------------------------------------------------------------------- +#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ + ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ + : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) + +#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) + +#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) + +#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) + +#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) + +#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) + +//---------------------------------------------------------------------------- +// macro for controller info +//---------------------------------------------------------------------------- +#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ + ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) +#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ + ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) +#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ + ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ + : HPC_CTLR_RESULT_RSVD) \ + : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ + : HPC_CTLR_RESULT_SUCCESS))) + +// command that affect the state machine of HPC +#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ + (c == HPC_SLOT_ON) || \ + (c == HPC_CTLR_RESET) || \ + (c == HPC_BUS_33CONVMODE) || \ + (c == HPC_BUS_66CONVMODE) || \ + (c == HPC_BUS_66PCIXMODE) || \ + (c == HPC_BUS_100PCIXMODE) || \ + (c == HPC_BUS_133PCIXMODE) || \ + (c == HPC_ALLSLOT_OFF) || \ + (c == HPC_ALLSLOT_ON)) + + +/* Core part of the driver */ + +#define ENABLE 1 +#define DISABLE 0 + +#define ADD 0 +#define REMOVE 1 +#define DETAIL 2 + +#define MAX_OPS 3 +#define CARD_INFO 0x07 +#define PCIX133 0x07 +#define PCIX66 0x05 +#define PCI66 0x04 + +extern struct pci_ops *ibmphp_pci_root_ops; + +/* Variables */ + +struct pci_func { + struct pci_dev *dev; /* from the OS */ + u8 busno; + u8 device; + u8 function; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *pfmem[6]; + struct pci_func *next; + int devices[32]; /* for bridge config */ + u8 irq[4]; /* for interrupt config */ + u8 bus; /* flag for unconfiguring, to say if PPB */ +}; + +struct slot { + u8 bus; + u8 device; + u8 number; + char name[100]; + u32 capabilities; + struct hotplug_slot *hotplug_slot; + struct controller *ctrl; + struct pci_func *func; + u8 irq[4]; + u8 flag; /* this is for disable slot and polling */ + int bit_mode; /* 0 = 32, 1 = 64 */ + u8 ctlr_index; + struct bus_info *bus_on; + struct list_head ibm_slot_list; + u8 status; + u8 ext_status; + u8 busstatus; +}; + +struct controller { + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + u8 revision; + u8 options; /* which options HPC supports */ + u8 status; + u8 ctlr_id; /* TONI */ + u8 slot_count; + u8 bus_count; + u8 ctlr_relative_id; + u32 irq; + union { + struct isa_ctlr_access isa_ctlr; + struct pci_ctlr_access pci_ctlr; + struct wpeg_i2c_ctlr_access wpeg_ctlr; + } u; + u8 ctlr_type; + struct list_head ebda_hpc_list; +}; + +/* Functions */ + +extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ +extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ +extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ +extern int ibmphp_configure_card (struct pci_func *, u8); +extern int ibmphp_unconfigure_card (struct slot **, int); +extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; + +static inline void long_delay (int delay) +{ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (delay); +} + +#endif //__IBMPHP_H + diff -urN linux-2.4.18/drivers/hotplug/ibmphp_core.c linux-2.4.19-pre5/drivers/hotplug/ibmphp_core.c --- linux-2.4.18/drivers/hotplug/ibmphp_core.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp_core.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,1480 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../arch/i386/kernel/pci-i386.h" /* for struct irq_routing_table */ +#include "ibmphp.h" + +#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) +#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) +#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) +#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) +#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) + +#define DRIVER_VERSION "0.1" +#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" + +int ibmphp_debug; + +static int debug; +MODULE_PARM (debug, "i"); +MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); +MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION (DRIVER_DESC); + +static int *ops[MAX_OPS + 1]; +static struct pci_ops *ibmphp_pci_root_ops; +static int max_slots; + +static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ + +static int init_flag; + +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); + +static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) +{ + return get_max_adapter_speed_1 (hs, value, 1); +} +*/ +static inline int get_cur_bus_info (struct slot **sl) +{ + int rc = 1; + struct slot * slot_cur = *sl; + + debug ("options = %x\n", slot_cur->ctrl->options); + debug ("revision = %x\n", slot_cur->ctrl->revision); + + if (READ_BUS_STATUS (slot_cur->ctrl)) + rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); + + if (rc) + return rc; + + slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); + if (READ_BUS_MODE (slot_cur->ctrl)) + slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); + + debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); + + *sl = slot_cur; + return 0; +} + +static inline int slot_update (struct slot **sl) +{ + int rc; + rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); + if (rc) + return rc; + if (!init_flag) + return get_cur_bus_info (sl); + return rc; +} + +static int get_max_slots (void) +{ + struct list_head * tmp; + int slot_count = 0; + + list_for_each (tmp, &ibmphp_slot_head) + ++slot_count; + return slot_count; +} + +/* This routine will put the correct slot->device information per slot. It's + * called from initialization of the slot structures. It will also assign + * interrupt numbers per each slot. + * Parameters: struct slot + * Returns 0 or errors + */ +int ibmphp_init_devno (struct slot **cur_slot) +{ + struct irq_routing_table *rtable; + int len; + int loop; + int i; + + rtable = pcibios_get_irq_routing_table (); + if (!rtable) { + err ("no BIOS routing table...\n"); + return -ENOMEM; + } + + len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); + + if (!len) + return -1; + for (loop = 0; loop < len; loop++) { + if ((*cur_slot)->number == rtable->slots[loop].slot) { + if ((*cur_slot)->bus == rtable->slots[loop].bus) { + (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); + for (i = 0; i < 4; i++) + (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); + + debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); + debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); + debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); + debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); + + debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); + debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); + debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); + debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); + debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); + + debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); + debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); + debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); + debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); + debug ("end of init_devno\n"); + return 0; + } + } + } + + return -1; +} + +static inline int power_on (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_ON; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power on failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_on \n"); + return -EIO; + } + long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + return 0; +} + +static inline int power_off (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_OFF; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power off failed \n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_off \n"); + return -EIO; + } + return 0; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) +{ + int rc = 0; + struct slot *pslot; + u8 cmd; + int hpcrc = 0; + + debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); + ibmphp_lock_operations (); + cmd = 0x00; // avoid compiler warning + + if (hotplug_slot) { + switch (value) { + case HPC_SLOT_ATTN_OFF: + cmd = HPC_SLOT_ATTNOFF; + break; + case HPC_SLOT_ATTN_ON: + cmd = HPC_SLOT_ATTNON; + break; + case HPC_SLOT_ATTN_BLINK: + cmd = HPC_SLOT_BLINKLED; + break; + default: + rc = -ENODEV; + err ("set_attention_status - Error : invalid input [%x]\n", value); + break; + } + if (rc == 0) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) + hpcrc = ibmphp_hpc_writeslot (pslot, cmd); + else + rc = -ENODEV; + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + + debug ("set_attention_status - Exit rc[%d]\n", rc); + return rc; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_ATTN (myslot.status, myslot.ext_status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_LATCH (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_POWER (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 present; + int hpcrc = 0; + struct slot myslot; + + debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + present = SLOT_PRESENT (myslot.status); + if (present == HPC_SLOT_EMPTY) + *value = 0; + else + *value = 1; + rc = 0; + } + } + } else + rc = -ENODEV; + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} +/* +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + mode = pslot->bus_on->supported_bus_mode; + *value = pslot->bus_on->supported_speed; + *value &= 0x0f; + + if (mode == BUS_MODE_PCIX) + *value |= 0x80; + else if (mode == BUS_MODE_PCI) + *value |= 0x40; + else + *value |= 0x20; + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = get_cur_bus_info (&pslot); + if (!rc) { + mode = pslot->bus_on->current_bus_mode; + *value = pslot->bus_on->current_speed; + *value &= 0x0f; + + if (mode == BUS_MODE_PCIX) + *value |= 0x80; + else if (mode == BUS_MODE_PCI) + *value |= 0x40; + else + *value |= 0x20; + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + if (flag) + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + + if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_SPEED (myslot.ext_status); + rc = 0; + } + } else { + *value = MAX_ADAPTER_NONE; + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + if (flag) + ibmphp_unlock_operations (); + + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value) +{ + int rc = -ENODEV; + struct slot *pslot = NULL; + struct pci_dev * dev = NULL; + + debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); + + ibmphp_lock_operations (); + + if (hotplug_slot) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + if (pslot->func) + dev = pslot->func->dev; + else + dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7)); + if (dev) + snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name); + else + snprintf (value, 100, "Bus %d", pslot->bus); + + + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +*/ +/******************************************************************************* + * This routine will initialize the ops data structure used in the validate + * function. It will also power off empty slots that are powered on since BIOS + * leaves those on, albeit disconnected + ******************************************************************************/ +static int init_ops (void) +{ + struct slot *slot_cur; + int retval; + int j; + int rc; + + for (j = 0; j < MAX_OPS; j++) { + ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL); + if (!ops[j]) { + err ("out of system memory \n"); + return -ENOMEM; + } + } + + ops[ADD][0] = 0; + ops[REMOVE][0] = 0; + ops[DETAIL][0] = 0; + + for (j = 1; j <= max_slots; j++) { + + slot_cur = ibmphp_get_slot_from_physical_num (j); + + debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); + + if (slot_cur->ctrl->revision == 0xFF) + if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) + return -1; + + if (slot_cur->bus_on->current_speed == 0xFF) + if (get_cur_bus_info (&slot_cur)) + return -1; + + if (slot_cur->ctrl->options == 0xFF) + if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) + return -1; + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status); + debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status)); + + if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) + /* No power, adapter, and latch closed */ + ops[ADD][j] = 1; + else + ops[ADD][j] = 0; + + ops[DETAIL][j] = 1; + + if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) + /*Power,adapter,latch closed */ + ops[REMOVE][j] = 1; + else + ops[REMOVE][j] = 0; + + if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) { + debug ("BEFORE POWER OFF COMMAND\n"); + rc = power_off (slot_cur); + if (rc) + return rc; + + /* retval = slot_update (&slot_cur); + * if (retval) + * return retval; + * ibmphp_update_slot_info (slot_cur); + */ + } + } + init_flag = 0; + return 0; +} + +/* This operation will check whether the slot is within the bounds and + * the operation is valid to perform on that slot + * Parameters: slot, operation + * Returns: 0 or error codes + */ +static int validate (struct slot *slot_cur, int opn) +{ + int number; + int retval; + + if (!slot_cur) + return -ENODEV; + number = slot_cur->number; + if ((number > max_slots) || (number < 0)) + return -EBADSLT; + debug ("slot_number in validate is %d\n", slot_cur->number); + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) + && !(SLOT_LATCH (slot_cur->status))) + ops[ADD][number] = 1; + else + ops[ADD][number] = 0; + + ops[DETAIL][number] = 1; + + if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) + && !(SLOT_LATCH (slot_cur->status))) + ops[REMOVE][number] = 1; + else + ops[REMOVE][number] = 0; + + switch (opn) { + case ENABLE: + if (ops[ADD][number]) + return 0; + break; + case DISABLE: + if (ops[REMOVE][number]) + return 0; + break; + case DETAIL: + if (ops[DETAIL][number]) + return 0; + break; + default: + return -EINVAL; + break; + } + err ("validate failed....\n"); + return -EINVAL; +} + +/******************************************************************************** + * This routine is for updating the data structures in the hotplug core + * Parameters: struct slot + * Returns: 0 or error + *******************************************************************************/ +int ibmphp_update_slot_info (struct slot *slot_cur) +{ + struct hotplug_slot_info *info; + char buffer[10]; + int rc; +// u8 bus_speed; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + err ("out of system memory \n"); + return -ENOMEM; + } + + snprintf (buffer, 10, "%d", slot_cur->number); + info->power_status = SLOT_POWER (slot_cur->status); + info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); + info->latch_status = SLOT_LATCH (slot_cur->status); + if (!SLOT_PRESENT (slot_cur->status)) { + info->adapter_status = 0; +// info->max_adapter_speed_status = MAX_ADAPTER_NONE; + } else { + info->adapter_status = 1; +// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); + } +/* + bus_speed = slot_cur->bus_on->current_speed; + bus_speed &= 0x0f; + + if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) + bus_speed |= 0x80; + else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI) + bus_speed |= 0x40; + else + bus_speed |= 0x20; + + info->cur_bus_speed_status = bus_speed; + info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status; + // To do: card_bus_names +*/ + rc = pci_hp_change_slot_info (buffer, info); + kfree (info); + return rc; +} + + +/****************************************************************************** + * This function will return the pci_func, given bus and devfunc, or NULL. It + * is called from visit routines + ******************************************************************************/ + +static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) +{ + struct pci_func *func_cur; + struct slot *slot_cur; + struct list_head * tmp; + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + if (slot_cur->func) { + func_cur = slot_cur->func; + while (func_cur) { + if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) + return func_cur; + func_cur = func_cur->next; + } + } + } + return NULL; +} + +/* This routine is to find the pci_bus from kernel structures. + * Parameters: bus number + * Returns : pci_bus * or NULL if not found + */ +static struct pci_bus *find_bus (u8 busno) +{ + const struct list_head *tmp; + struct pci_bus *bus; + debug ("inside find_bus, busno = %x \n", busno); + + list_for_each (tmp, &pci_root_buses) { + bus = (struct pci_bus *) pci_bus_b (tmp); + if (bus) + if (bus->number == busno) + return bus; + } + return NULL; +} + +/****************************************************************** + * This function is here because we can no longer use pci_root_ops + ******************************************************************/ +static struct pci_ops *get_root_pci_ops (void) +{ + struct pci_bus * bus; + + if ((bus = find_bus (0))) + return bus->ops; + return NULL; +} + +/************************************************************* + * This routine frees up memory used by struct slot, including + * the pointers to pci_func, bus, hotplug_slot, controller, + * and deregistering from the hotplug core + *************************************************************/ +static void free_slots (void) +{ + struct slot *slot_cur; + struct list_head * tmp; + struct list_head * next; + + list_for_each_safe (tmp, next, &ibmphp_slot_head) { + + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + pci_hp_deregister (slot_cur->hotplug_slot); + + if (slot_cur->hotplug_slot) { + kfree (slot_cur->hotplug_slot); + slot_cur->hotplug_slot = NULL; + } + + if (slot_cur->ctrl) + slot_cur->ctrl = NULL; + + if (slot_cur->bus_on) + slot_cur->bus_on = NULL; + + ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ + + kfree (slot_cur); + } +} + +static int ibm_is_pci_dev_in_use (struct pci_dev *dev) +{ + int i = 0; + int inuse = 0; + + if (dev->driver) + return 1; + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + + if (!pci_resource_start (dev, i)) + continue; + + if (pci_resource_flags (dev, i) & IORESOURCE_IO) + inuse = check_region (pci_resource_start (dev, i), pci_resource_len (dev, i)); + + else if (pci_resource_flags (dev, i) & IORESOURCE_MEM) + inuse = check_mem_region (pci_resource_start (dev, i), pci_resource_len (dev, i)); + } + + return inuse; +} + +static int ibm_pci_hp_remove_device (struct pci_dev *dev) +{ + if (ibm_is_pci_dev_in_use (dev)) { + err ("***Cannot safely power down device -- it appears to be in use***\n"); + return -EBUSY; + } + pci_remove_device (dev); + return 0; +} + +static int ibm_unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i = 0; + + do { + temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (dev) { + if (ibm_pci_hp_remove_device (dev) == 0) + kfree (dev); /* Now, remove */ + else + return -1; + } + + if (temp_func) + temp_func->dev = NULL; + else + err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + + return 0; +} + +static int ibm_unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus *bus = wrapped_bus->bus; + + pci_proc_detach_bus (bus); + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + /* unlink from parent bus */ + list_del (&bus->node); + + /* Now, remove */ + if (bus) + kfree (bus); + + return 0; +} + +static int ibm_unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + + debug ("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); + + /* Now, remove the Linux Driver Representation */ + if (dev->driver) { + debug ("is there a driver?\n"); + if (dev->driver->remove) { + dev->driver->remove (dev); + debug ("driver was properly removed\n"); + } + dev->driver = NULL; + } + + return ibm_is_pci_dev_in_use (dev); +} + +static struct pci_visit ibm_unconfigure_functions_phase1 = { + post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase1, +}; + +static struct pci_visit ibm_unconfigure_functions_phase2 = { + post_visit_pci_bus: ibm_unconfigure_visit_pci_bus_phase2, + post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase2, +}; + +static int ibm_unconfigure_device (struct pci_func *func) +{ + int rc = 0; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + struct pci_dev *temp; + u8 j; + + memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + debug ("inside ibm_unconfigure_device\n"); + debug ("func->device = %x, func->function = %x\n", func->device, func->function); + debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); + + for (j = 0; j < 0x08; j++) { + temp = pci_find_slot (func->busno, (func->device << 3) | j); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev (&ibm_unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev (&ibm_unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + debug ("rc in ibm_unconfigure_device b4 returning is %d \n", rc); + return rc; +} + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + // struct pci_bus *bus = wrapped_bus->bus; /* We don't need this, since we don't create in the else statement */ + struct pci_dev *dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i = 0; + + do { + temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) + temp_func->dev = dev; + else { + /* This should not really happen, since we create functions + first and then call to configure */ + debug (" We shouldn't come here \n"); + } + + if (temp_func->dev) { + pci_proc_attach_device (temp_func->dev); + pci_announce_device_to_drivers (temp_func->dev); + } + + return 0; +} + +static struct pci_visit configure_functions = { + visit_pci_dev: configure_visit_pci_dev, +}; + +static int ibm_configure_device (struct pci_func *func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev *temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + memset (&dev0, 0, sizeof (struct pci_dev)); + + if (func->dev == NULL) + func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7)); + + if (func->dev == NULL) { + dev0.bus = find_bus (func->busno); + dev0.devfn = ((func->device << 3) + (func->function & 0x7)); + dev0.sysdata = dev0.bus->sysdata; + + func->dev = pci_scan_slot (&dev0); + + if (func->dev == NULL) { + err ("ERROR... : pci_dev still NULL \n"); + return 0; + } + } + if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); + pci_do_scan_bus (child); + } + + temp = func->dev; + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev (&configure_functions, &wrapped_dev, &wrapped_bus); + } + return rc; +} +/******************************************************* + * Returns whether the bus is empty or not + *******************************************************/ +static int is_bus_empty (struct slot * slot_cur) +{ + int rc; + struct slot * tmp_slot; + u8 i = slot_cur->bus_on->slot_min; + + while (i <= slot_cur->bus_on->slot_max) { + if (i == slot_cur->number) { + i++; + continue; + } + tmp_slot = ibmphp_get_slot_from_physical_num (i); + rc = slot_update (&tmp_slot); + if (rc) + return 0; + if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status)) + return 0; + i++; + } + return 1; +} + +/*********************************************************** + * If the HPC permits and the bus currently empty, tries to set the + * bus speed and mode at the maximum card capability + ***********************************************************/ +static int set_bus (struct slot * slot_cur) +{ + int rc; + u8 speed; + u8 cmd = 0x0; + + debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); + if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { + rc = slot_update (&slot_cur); + if (rc) + return rc; + speed = SLOT_SPEED (slot_cur->ext_status); + debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); + switch (speed) { + case HPC_SLOT_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case HPC_SLOT_SPEED_66: + if (SLOT_PCIX (slot_cur->ext_status)) + cmd = HPC_BUS_66PCIXMODE; + else + cmd = HPC_BUS_66CONVMODE; + break; + case HPC_SLOT_SPEED_133: + if (slot_cur->bus_on->slot_count > 1) + cmd = HPC_BUS_100PCIXMODE; + else + cmd = HPC_BUS_133PCIXMODE; + break; + default: + err ("wrong slot speed \n"); + return -ENODEV; + } + debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); + rc = ibmphp_hpc_writeslot (slot_cur, cmd); + if (rc) + return rc; + } + debug ("%s -Exit \n", __FUNCTION__); + return 0; +} + +static inline void print_card_capability (struct slot *slot_cur) +{ + info ("capability of the card is "); + if ((slot_cur->ext_status & CARD_INFO) == PCIX133) + info (" 133 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) + info (" 66 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCI66) + info (" 66 MHz PCI \n"); + else + info (" 33 MHz PCI \n"); + +} + +/* This routine will power on the slot, configure the device(s) and find the + * drivers for them. + * Parameters: hotplug_slot + * Returns: 0 or failure codes + */ +static int enable_slot (struct hotplug_slot *hs) +{ + int rc, i, rcpr; + struct slot *slot_cur; + u8 function; + u8 faulted = 0; + struct pci_func *tmp_func; + + ibmphp_lock_operations (); + + debug ("ENABLING SLOT........ \n"); + slot_cur = (struct slot *) hs->private; + + if ((rc = validate (slot_cur, ENABLE))) { + err ("validate function failed \n"); + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + rc = slot_update (&slot_cur); + if (rc) { + ibmphp_unlock_operations(); + return rc; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + + attn_LED_blink (slot_cur); + + rc = set_bus (slot_cur); + if (rc) { + err ("was not able to set the bus \n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENODEV; + } + + rc = power_on (slot_cur); + + if (rc) { + err ("something wrong when powering up... please see below for details\n"); + /* need to turn off before on, otherwise, blinking overwrites */ + attn_off(slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENODEV; + } + /* Check to see the error of why it failed */ + if (!(SLOT_PWRGD (slot_cur->status))) + err ("power fault occured trying to power up \n"); + else if (SLOT_BUS_SPEED (slot_cur->status)) { + err ("bus speed mismatch occured. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } else if (SLOT_BUS_MODE (slot_cur->ext_status)) + err ("bus mode mismatch occured. please check current bus mode and card capability \n"); + + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + debug ("after power_on\n"); + + rc = slot_update (&slot_cur); + if (rc) { + attn_off (slot_cur); + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + ibmphp_unlock_operations (); + return rc; + } + + if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { + faulted = 1; + err ("power fault occured trying to power up...\n"); + } else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { + faulted = 1; + err ("bus speed mismatch occured. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } + /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ + else if (!(SLOT_POWER (slot_cur->status))) { + err ("power on failed... \n"); + faulted = 1; + } + if (faulted) { + attn_off (slot_cur); /* need to turn off b4 on */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -ENODEV; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return -EINVAL; + } + + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { /* We cannot do update_slot_info here, since no memory for kmalloc n.e.ways, and update_slot_info allocates some */ + err ("out of system memory \n"); + attn_off (slot_cur); + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + ibmphp_unlock_operations (); + return -ENOMEM; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + for (i = 0; i < 4; i++) + slot_cur->func->irq[i] = slot_cur->irq[i]; + + debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); + + if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { + err ("configure_card was unsuccessful... \n"); + ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ + debug ("after unconfigure_card\n"); + slot_cur->func = NULL; + attn_off (slot_cur); /* need to turn off in case was blinking */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations(); + return -ENODEV; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return -ENOMEM; + } + function = 0x00; + do { + tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); + if (tmp_func && !(tmp_func->dev)) + ibm_configure_device (tmp_func); + } while (tmp_func); + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + ibmphp_print_test (); + rc = ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations(); + return rc; +} + +/************************************************************** +* HOT REMOVING ADAPTER CARD * +* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * +* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * + DISABLE POWER , * +**************************************************************/ +int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) +{ + int rc; + struct slot *slot_cur = (struct slot *) hotplug_slot->private; + u8 flag = slot_cur->flag; + + slot_cur->flag = TRUE; + debug ("DISABLING SLOT... \n"); + + ibmphp_lock_operations (); + if (slot_cur == NULL) { + ibmphp_unlock_operations (); + return -ENODEV; + } + if (slot_cur->ctrl == NULL) { + ibmphp_unlock_operations (); + return -ENODEV; + } + if (flag == TRUE) { + rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ + if (rc) { + /* Need to turn off if was blinking b4 */ + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + } + attn_LED_blink (slot_cur); + + if (slot_cur->func == NULL) { + /* We need this for fncs's that were there on bootup */ + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + err ("out of system memory \n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENOMEM; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + } + + if ((rc = ibm_unconfigure_device (slot_cur->func))) { + err ("removing from kernel failed... \n"); + err ("Please check to see if it was statically linked or is in use otherwise. (perhaps the driver is not 'hot-removable')\n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + + rc = ibmphp_unconfigure_card (&slot_cur, 0); + slot_cur->func = NULL; + debug ("in disable_slot. after unconfigure_card \n"); + if (rc) { + err ("could not unconfigure card.\n"); + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + if (flag) + ibmphp_update_slot_info (slot_cur); + + ibmphp_unlock_operations (); + return -EFAULT; + } + + rc = ibmphp_hpc_writeslot (hotplug_slot->private, HPC_SLOT_OFF); + if (rc) { + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + if (flag) + ibmphp_update_slot_info (slot_cur); + + ibmphp_unlock_operations (); + return rc; + } + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + if (flag) + rc = ibmphp_update_slot_info (slot_cur); + else + rc = 0; + + ibmphp_print_test (); + ibmphp_unlock_operations(); + return rc; +} + +struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { + owner: THIS_MODULE, + set_attention_status: set_attention_status, + enable_slot: enable_slot, + disable_slot: ibmphp_disable_slot, + hardware_test: NULL, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_present, +/* get_max_bus_speed_status: get_max_bus_speed, + get_max_adapter_speed_status: get_max_adapter_speed, + get_cur_bus_speed_status: get_cur_bus_speed, + get_card_bus_names_status: get_card_bus_names, +*/ +}; + +static void ibmphp_unload (void) +{ + free_slots (); + debug ("after slots \n"); + ibmphp_free_resources (); + debug ("after resources \n"); + ibmphp_free_bus_info_queue (); + debug ("after bus info \n"); + ibmphp_free_ebda_hpc_queue (); + debug ("after ebda hpc \n"); + ibmphp_free_ebda_pci_rsrc_queue (); + debug ("after ebda pci rsrc \n"); +} + +static int __init ibmphp_init (void) +{ + int i = 0; + int rc = 0; + + init_flag = 1; + ibmphp_pci_root_ops = get_root_pci_ops (); + if (ibmphp_pci_root_ops == NULL) { + err ("cannot read bus operations... will not be able to read the cards. Please check your system \n"); + return -ENODEV; + } + + ibmphp_debug = debug; + + ibmphp_hpc_initvars (); + + for (i = 0; i < 16; i++) + irqs[i] = 0; + + if ((rc = ibmphp_access_ebda ())) { + ibmphp_unload (); + return rc; + } + debug ("after ibmphp_access_ebda () \n"); + + if ((rc = ibmphp_rsrc_init ())) { + ibmphp_unload (); + return rc; + } + debug ("AFTER Resource & EBDA INITIALIZATIONS \n"); + + max_slots = get_max_slots (); + + if (init_ops ()) { + ibmphp_unload (); + return -ENODEV; + } + ibmphp_print_test (); + if ((rc = ibmphp_hpc_start_poll_thread ())) { + ibmphp_unload (); + return -ENODEV; + } + + /* lock ourselves into memory with a module count of -1 + * so that no one can unload us. */ + MOD_DEC_USE_COUNT; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + return 0; +} + +static void __exit ibmphp_exit (void) +{ + ibmphp_hpc_stop_poll_thread (); + debug ("after polling \n"); + ibmphp_unload (); + debug ("done \n"); +} + +module_init (ibmphp_init); +module_exit (ibmphp_exit); diff -urN linux-2.4.18/drivers/hotplug/ibmphp_ebda.c linux-2.4.19-pre5/drivers/hotplug/ibmphp_ebda.c --- linux-2.4.18/drivers/hotplug/ibmphp_ebda.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp_ebda.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,851 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Tong Yu, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +/* + * POST builds data blocks(in this data block definition, a char-1 + * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended + * BIOS Data Area which describe the configuration of the hot-plug + * controllers and resources used by the PCI Hot-Plug devices. + * + * This file walks EBDA, maps data block from physical addr, + * reconstruct linked lists about all system resource(MEM, PFM, IO) + * already assigned by POST, as well as linked lists about hot plug + * controllers (ctlr#, slot#, bus&slot features...) + */ + +/* Global lists */ +LIST_HEAD (ibmphp_ebda_pci_rsrc_head); +LIST_HEAD (ibmphp_slot_head); + +/* Local variables */ +static struct ebda_hpc_list *hpc_list_ptr; +static struct ebda_rsrc_list *rsrc_list_ptr; +static struct rio_table_hdr *rio_table_ptr; +static LIST_HEAD (ebda_hpc_head); +static LIST_HEAD (bus_info_head); +static void *io_mem; + +/* Local functions */ +static int ebda_rsrc_controller (void); +static int ebda_rsrc_rsrc (void); +static int ebda_rio_table (void); + +static struct slot *alloc_ibm_slot (void) +{ + struct slot *slot; + + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return NULL; + memset (slot, 0, sizeof (*slot)); + return slot; +} + +static struct ebda_hpc_list *alloc_ebda_hpc_list (void) +{ + struct ebda_hpc_list *list; + + list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) +{ + struct controller *controller; + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + + controller = kmalloc (sizeof (struct controller), GFP_KERNEL); + if (!controller) + return NULL; + memset (controller, 0, sizeof (*controller)); + + slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); + if (!slots) { + kfree (controller); + return NULL; + } + memset (slots, 0, sizeof (*slots) * slot_count); + controller->slots = slots; + + buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); + if (!buses) { + kfree (controller->slots); + kfree (controller); + return NULL; + } + memset (buses, 0, sizeof (*buses) * bus_count); + controller->buses = buses; + + return controller; +} + +static void free_ebda_hpc (struct controller *controller) +{ + kfree (controller->slots); + controller->slots = NULL; + kfree (controller->buses); + controller->buses = NULL; + kfree (controller); +} + +static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void) +{ + struct ebda_rsrc_list *list; + + list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *resource; + + resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); + if (!resource) + return NULL; + memset (resource, 0, sizeof (*resource)); + return resource; +} + +static void print_bus_info (void) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); + debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); + debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); + debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); + debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); + debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed); + debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); + debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode); + } +} + +static void print_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { + ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); + } +} + +static void print_ebda_hpc (void) +{ + struct controller *hpc_ptr; + struct list_head *ptr1; + u16 index; + + list_for_each (ptr1, &ebda_hpc_head) { + + hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); + + for (index = 0; index < hpc_ptr->slot_count; index++) { + debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); + debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); + debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); + debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); + } + + for (index = 0; index < hpc_ptr->bus_count; index++) { + debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); + } + + debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); + switch (hpc_ptr->ctlr_type) { + case 1: + debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); + debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 0: + debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); + debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 2: + debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); + debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + } + } +} + +int ibmphp_access_ebda (void) +{ + u8 format, num_ctlrs, rio_complete, hs_complete; + u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; + + + rio_complete = 0; + hs_complete = 0; + + io_mem = ioremap ((0x40 << 4) + 0x0e, 2); + if (!io_mem ) + return -ENOMEM; + ebda_seg = readw (io_mem); + iounmap (io_mem); + debug ("returned ebda segment: %x\n", ebda_seg); + + io_mem = ioremap (ebda_seg<<4, 65000); + if (!io_mem ) + return -ENOMEM; + next_offset = 0x180; + + for (;;) { + offset = next_offset; + next_offset = readw (io_mem + offset); /* offset of next blk */ + + offset += 2; + if (next_offset == 0) /* 0 indicate it's last blk */ + break; + blk_id = readw (io_mem + offset); /* this blk id */ + + offset += 2; + /* check if it is hot swap block or rio block */ + if (blk_id != 0x4853 && blk_id != 0x4752) + continue; + /* found hs table */ + if (blk_id == 0x4853) { + debug ("now enter hot swap block---\n"); + debug ("hot blk id: %x\n", blk_id); + format = readb (io_mem + offset); + + offset += 1; + if (format != 4) { + iounmap (io_mem); + return -ENODEV; + } + debug ("hot blk format: %x\n", format); + /* hot swap sub blk */ + base = offset; + + sub_addr = base; + re = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + rc_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (rc_id != 0x5243) { + iounmap (io_mem); + return -ENODEV; + } + /* rc sub blk signature */ + num_ctlrs = readb (io_mem + sub_addr); + + sub_addr += 1; + hpc_list_ptr = alloc_ebda_hpc_list (); + if (!hpc_list_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_list_ptr->format = format; + hpc_list_ptr->num_ctlrs = num_ctlrs; + hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ + debug ("info about hpc descriptor---\n"); + debug ("hot blk format: %x\n", format); + debug ("num of controller: %x\n", num_ctlrs); + debug ("offset of hpc data structure enteries: %x\n ", sub_addr); + + sub_addr = base + re; /* re sub blk */ + rc = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + re_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (re_id != 0x5245) { + iounmap (io_mem); + return -ENODEV; + } + + /* signature of re */ + num_entries = readw (io_mem + sub_addr); + + sub_addr += 2; /* offset of RSRC_ENTRIES blk */ + rsrc_list_ptr = alloc_ebda_rsrc_list (); + if (!rsrc_list_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_list_ptr->format = format; + rsrc_list_ptr->num_entries = num_entries; + rsrc_list_ptr->phys_addr = sub_addr; + + debug ("info about rsrc descriptor---\n"); + debug ("format: %x\n", format); + debug ("num of rsrc: %x\n", num_entries); + debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); + + hs_complete = 1; + } + /* found rio table */ + else if (blk_id == 0x4752) { + debug ("now enter io table ---\n"); + debug ("rio blk id: %x\n", blk_id); + + rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); + if (!rio_table_ptr) + return -ENOMEM; + memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); + rio_table_ptr->ver_num = readb (io_mem + offset); + rio_table_ptr->scal_count = readb (io_mem + offset + 1); + rio_table_ptr->riodev_count = readb (io_mem + offset + 2); + rio_table_ptr->offset = offset +3 ; + + debug ("info about rio table hdr ---\n"); + debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); + + rio_complete = 1; + } + + if (hs_complete && rio_complete) { + rc = ebda_rsrc_controller (); + if (rc) { + iounmap(io_mem); + return rc; + } + rc = ebda_rsrc_rsrc (); + if (rc) { + iounmap(io_mem); + return rc; + } + rc = ebda_rio_table (); + if (rc) { + iounmap(io_mem); + return rc; + } + iounmap (io_mem); + return 0; + } + } + iounmap (io_mem); + return -ENODEV; +} + + +/* + * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of + * each hpc from physical address to a list of hot plug controllers based on + * hpc descriptors. + */ +static int ebda_rsrc_controller (void) +{ + u16 addr, addr_slot, addr_bus; + u8 ctlr_id, temp, bus_index; + u16 ctlr, slot, bus; + u16 slot_num, bus_num, index; + struct hotplug_slot *hp_slot_ptr; + struct controller *hpc_ptr; + struct ebda_hpc_bus *bus_ptr; + struct ebda_hpc_slot *slot_ptr; + struct bus_info *bus_info_ptr1, *bus_info_ptr2; + int rc; + + addr = hpc_list_ptr->phys_addr; + for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { + bus_index = 1; + ctlr_id = readb (io_mem + addr); + addr += 1; + slot_num = readb (io_mem + addr); + + addr += 1; + addr_slot = addr; /* offset of slot structure */ + addr += (slot_num * 4); + + bus_num = readb (io_mem + addr); + + addr += 1; + addr_bus = addr; /* offset of bus */ + addr += (bus_num * 9); /* offset of ctlr_type */ + temp = readb (io_mem + addr); + + addr += 1; + /* init hpc structure */ + hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); + if (!hpc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_ptr->ctlr_id = ctlr_id; + hpc_ptr->ctlr_relative_id = ctlr; + hpc_ptr->slot_count = slot_num; + hpc_ptr->bus_count = bus_num; + debug ("now enter ctlr data struture ---\n"); + debug ("ctlr id: %x\n", ctlr_id); + debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); + debug ("count of slots controlled by this ctlr: %x\n", slot_num); + debug ("count of buses controlled by this ctlr: %x\n", bus_num); + + /* init slot structure, fetch slot, bus, cap... */ + slot_ptr = hpc_ptr->slots; + for (slot = 0; slot < slot_num; slot++) { + slot_ptr->slot_num = readb (io_mem + addr_slot); + slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); + slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); + slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); + + // create bus_info lined list --- if only one slot per bus: slot_min = slot_max + + bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); + if (!bus_info_ptr2) { + bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); + if (!bus_info_ptr1) { + iounmap (io_mem); + return -ENOMEM; + } + memset (bus_info_ptr1, 0, sizeof (struct bus_info)); + bus_info_ptr1->slot_min = slot_ptr->slot_num; + bus_info_ptr1->slot_max = slot_ptr->slot_num; + bus_info_ptr1->slot_count += 1; + bus_info_ptr1->busno = slot_ptr->slot_bus_num; + bus_info_ptr1->index = bus_index++; + bus_info_ptr1->current_speed = 0xff; + bus_info_ptr1->current_bus_mode = 0xff; + if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX ) + bus_info_ptr1->supported_speed = 3; + else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX ) + bus_info_ptr1->supported_speed = 2; + else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX ) + bus_info_ptr1->supported_speed = 1; + bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; + if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP ) + bus_info_ptr1->supported_bus_mode = 1; + else + bus_info_ptr1->supported_bus_mode =0; + + + list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); + + } else { + bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); + bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); + bus_info_ptr2->slot_count += 1; + + } + + // end of creating the bus_info linked list + + slot_ptr++; + addr_slot += 1; + } + + /* init bus structure */ + bus_ptr = hpc_ptr->buses; + for (bus = 0; bus < bus_num; bus++) { + bus_ptr->bus_num = readb (io_mem + addr_bus); + bus_ptr++; + addr_bus += 1; + } + + hpc_ptr->ctlr_type = temp; + + switch (hpc_ptr->ctlr_type) { + case 1: + hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); + hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); + hpc_ptr->irq = readb (io_mem + addr + 2); + addr += 3; + break; + + case 0: + hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); + hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); + hpc_ptr->irq = readb (io_mem + addr + 4); + addr += 5; + break; + + case 2: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + /* following 2 lines for testing purpose */ + if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) + hpc_ptr->ctlr_type = 4; + + + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + case 4: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + default: + iounmap (io_mem); + return -ENODEV; + } + /* following 3 line: Now our driver only supports I2c ctlrType */ + if ((hpc_ptr->ctlr_type != 2) && (hpc_ptr->ctlr_type != 4)) { + err ("Please run this driver on ibm xseries440\n "); + return -ENODEV; + } + + hpc_ptr->revision = 0xff; + hpc_ptr->options = 0xff; + + // register slots with hpc core as well as create linked list of ibm slot + for (index = 0; index < hpc_ptr->slot_count; index++) { + + hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hp_slot_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); + + hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!hp_slot_ptr->info) { + iounmap (io_mem); + kfree (hp_slot_ptr); + return -ENOMEM; + } + memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); + + hp_slot_ptr->name = (char *) kmalloc (10, GFP_KERNEL); + if (!hp_slot_ptr->name) { + iounmap (io_mem); + kfree (hp_slot_ptr->info); + kfree (hp_slot_ptr); + return -ENOMEM; + } + + hp_slot_ptr->private = alloc_ibm_slot (); + if (!hp_slot_ptr->private) { + iounmap (io_mem); + kfree (hp_slot_ptr->name); + kfree (hp_slot_ptr->info); + kfree (hp_slot_ptr); + return -ENOMEM; + } + + ((struct slot *)hp_slot_ptr->private)->flag = TRUE; + snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num); + + ((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap; + ((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num; + + bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); + if (!bus_info_ptr1) { + iounmap (io_mem); + return -ENODEV; + } + ((struct slot *) hp_slot_ptr->private)->bus_on = bus_info_ptr1; + bus_info_ptr1 = NULL; + ((struct slot *) hp_slot_ptr->private)->ctrl = hpc_ptr; + + + ((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index; + ((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num; + + ((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr; + + rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); + if (rc) { + iounmap (io_mem); + return rc; + } + + rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); + if (rc) { + iounmap (io_mem); + return rc; + } + hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; + + pci_hp_register (hp_slot_ptr); + + // end of registering ibm slot with hotplug core + + list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); + } + + print_bus_info (); + list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); + + } /* each hpc */ + print_ebda_hpc (); + return 0; +} + +/* + * map info (bus, devfun, start addr, end addr..) of i/o, memory, + * pfm from the physical addr to a list of resource. + */ +static int ebda_rsrc_rsrc (void) +{ + u16 addr; + short rsrc; + u8 type, rsrc_type; + struct ebda_pci_rsrc *rsrc_ptr; + + addr = rsrc_list_ptr->phys_addr; + debug ("now entering rsrc land\n"); + debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); + + for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { + type = readb (io_mem + addr); + + addr += 1; + rsrc_type = type & EBDA_RSRC_TYPE_MASK; + + if (rsrc_type == EBDA_IO_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readw (io_mem + addr + 2); + rsrc_ptr->end_addr = readw (io_mem + addr + 4); + addr += 6; + + debug ("rsrc from io type ----\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + + if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readl (io_mem + addr + 2); + rsrc_ptr->end_addr = readl (io_mem + addr + 6); + addr += 10; + + debug ("rsrc from mem or pfm ---\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + } + kfree (rsrc_list_ptr); + rsrc_list_ptr = NULL; + print_ebda_pci_rsrc (); + return 0; +} + +/* + * map info of scalability details and rio details from physical address + */ +static int ebda_rio_table(void) +{ + u16 offset; + u8 i; + struct scal_detail *scal_detail_ptr; + struct rio_detail *rio_detail_ptr; + + offset = rio_table_ptr->offset; + for (i = 0; i < rio_table_ptr->scal_count; i++) { + + scal_detail_ptr = kmalloc (sizeof (struct scal_detail), GFP_KERNEL ); + if (!scal_detail_ptr ) + return -ENOMEM; + memset (scal_detail_ptr, 0, sizeof (struct scal_detail) ); + scal_detail_ptr->node_id = readb (io_mem + offset); + scal_detail_ptr->cbar = readl (io_mem+ offset + 1); + scal_detail_ptr->port0_node_connect = readb (io_mem + 5); + scal_detail_ptr->port0_port_connect = readb (io_mem + 6); + scal_detail_ptr->port1_node_connect = readb (io_mem + 7); + scal_detail_ptr->port1_port_connect = readb (io_mem + 8); + scal_detail_ptr->port2_node_connect = readb (io_mem + 9); + scal_detail_ptr->port2_port_connect = readb (io_mem + 10); + debug ("node_id: %x\ncbar: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nport2_node: %x\nport2_port: %x\n", scal_detail_ptr->node_id, scal_detail_ptr->cbar, scal_detail_ptr->port0_node_connect, scal_detail_ptr->port0_port_connect, scal_detail_ptr->port1_node_connect, scal_detail_ptr->port1_port_connect, scal_detail_ptr->port2_node_connect, scal_detail_ptr->port2_port_connect); +// list_add (&scal_detail_ptr->scal_detail_list, &scal_detail_head); + offset += 11; + } + for (i=0; i < rio_table_ptr->riodev_count; i++) { + rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL ); + if (!rio_detail_ptr ) + return -ENOMEM; + memset (rio_detail_ptr, 0, sizeof (struct rio_detail) ); + rio_detail_ptr->rio_node_id = readb (io_mem + offset ); + rio_detail_ptr->bbar = readl (io_mem + offset + 1); + rio_detail_ptr->rio_type = readb (io_mem + offset + 5); + rio_detail_ptr->owner_id = readb (io_mem + offset + 6); + rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); + rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); + rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); + rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); + rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); + rio_detail_ptr->status = readb (io_mem + offset + 12); + debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); + offset += 13; + } + return 0; +} + +u16 ibmphp_get_total_controllers (void) +{ + return hpc_list_ptr->num_ctlrs; +} + +struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) +{ + struct slot *slot; + struct list_head *list; + + list_for_each (list, &ibmphp_slot_head) { + slot = list_entry (list, struct slot, ibm_slot_list); + if (slot->number == physical_num) + return slot; + } + return NULL; +} + +/* To find: + * - the smallest slot number + * - the largest slot number + * - the total number of the slots based on each bus + * (if only one slot per bus slot_min = slot_max ) + */ +struct bus_info *ibmphp_find_same_bus_num (u32 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr; + } + return NULL; +} + +/* Finding relative bus number, in order to map corresponding + * bus register + */ +int ibmphp_get_bus_index (u8 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr->index; + } + return -ENODEV; +} + +void ibmphp_free_bus_info_queue (void) +{ + struct bus_info *bus_info; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &bus_info_head ) { + bus_info = list_entry (list, struct bus_info, bus_info_list); + kfree (bus_info); + } +} + +/* + * Calculate the total hot pluggable slots controlled by total hpcs + */ +/* +int ibmphp_get_total_hp_slots (void) +{ + struct ebda_hpc *ptr; + int slot_num = 0; + + ptr = ebda_hpc_head; + while (ptr != NULL) { + slot_num += ptr->slot_count; + ptr = ptr->next; + } + return slot_num; +} +*/ + +void ibmphp_free_ebda_hpc_queue (void) +{ + struct controller *controller; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ebda_hpc_head) { + controller = list_entry (list, struct controller, ebda_hpc_list); + free_ebda_hpc (controller); + } +} + +void ibmphp_free_ebda_pci_rsrc_queue (void) +{ + struct ebda_pci_rsrc *resource; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { + resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + kfree (resource); + resource = NULL; + } +} + diff -urN linux-2.4.18/drivers/hotplug/ibmphp_hpc.c linux-2.4.19-pre5/drivers/hotplug/ibmphp_hpc.c --- linux-2.4.18/drivers/hotplug/ibmphp_hpc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp_hpc.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,1135 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, IBM Corporation + * + * Copyright (c) 2001,2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + * + */ + +//#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +#define POLL_NO 0x01 +#define POLL_YES 0x00 + +static int to_debug = FALSE; +#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) + +//---------------------------------------------------------------------------- +// timeout values +//---------------------------------------------------------------------------- +#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd +#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd +#define HPC_GETACCESS_TIMEOUT 60 // seconds +#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds +#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots + +//---------------------------------------------------------------------------- +// Winnipeg Architected Register Offsets +//---------------------------------------------------------------------------- +#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low +#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg +#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register +#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register +#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register + +//---------------------------------------------------------------------------- +// Winnipeg Store Type commands (Add this commands to the register offset) +//---------------------------------------------------------------------------- +#define WPG_I2C_AND 0x1000 // I2C AND operation +#define WPG_I2C_OR 0x2000 // I2C OR operation + +//---------------------------------------------------------------------------- +// Command set for I2C Master Operation Setup Regisetr +//---------------------------------------------------------------------------- +#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index +#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index +#define WPG_READDIRECT_MASK 0x10010000 +#define WPG_WRITEDIRECT_MASK 0x60010000 + + +//---------------------------------------------------------------------------- +// bit masks for I2C Master Control Register +//---------------------------------------------------------------------------- +#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- +#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval +#define WPG_CTLR_MAX 0x01 // max controllers +#define WPG_SLOT_MAX 0x06 // max slots +#define WPG_CTLR_SLOT_MAX 0x06 // max slots per controller +#define WPG_FIRST_CTLR 0x00 // index of the controller + +//---------------------------------------------------------------------------- +// command index +//---------------------------------------------------------------------------- +#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr +#define WPG_CTLR_INDEX 0x0F // index - ctlr +#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr +#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr + +//---------------------------------------------------------------------------- +// macro utilities +//---------------------------------------------------------------------------- +// if bits 20,22,25,26,27,29,30 are OFF return TRUE +#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) + +// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register +#define INCREMENT_POLLCNT(i) ((i < POLL_LATCH_CNT) ? i++ : (i=0)) +//---------------------------------------------------------------------------- +// global variables +//---------------------------------------------------------------------------- +static int ibmphp_shutdown; +static int tid_poll; +static int stop_polling; // 2 values: poll, don't poll +static struct semaphore sem_hpcaccess; // lock access to HPC +static struct semaphore semOperations; // lock all operations and + // access to data structures +static struct semaphore sem_exit; // make sure polling thread goes away +static struct semaphore sem_poll; // make sure poll is idle +//---------------------------------------------------------------------------- +// local function prototypes +//---------------------------------------------------------------------------- +static u8 ctrl_read (struct controller *, void *, u8); +static u8 ctrl_write (struct controller *, void *, u8, u8); +static u8 hpc_writecmdtoindex (u8, u8); +static u8 hpc_readcmdtoindex (u8, u8); +static void get_hpc_access (void); +static void free_hpc_access (void); +static void poll_hpc (void); +static int update_slot (struct slot *, u8); +static int process_changeinstatus (struct slot *, struct slot *); +static int process_changeinlatch (u8, u8); +static int hpc_poll_thread (void *); +static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); +//---------------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_initvars +* +* Action: initialize semaphores and variables +*---------------------------------------------------------------------*/ +void ibmphp_hpc_initvars (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + init_MUTEX (&sem_hpcaccess); + init_MUTEX (&semOperations); + init_MUTEX_LOCKED (&sem_exit); + init_MUTEX_LOCKED (&sem_poll); + stop_polling = POLL_YES; + to_debug = FALSE; + ibmphp_shutdown = FALSE; + tid_poll = 0; + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: ctrl_read +* +* Action: read from HPC over I2C +* +*---------------------------------------------------------------------*/ +static u8 ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) +{ + u8 status; + int i; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); + + //-------------------------------------------------------------------- + // READ - step 1 + // read at address, byte length, I2C address (shifted), index + // or read direct, byte length, index + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_READATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_READDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 2 : clear the message buffer + data = 0x00000000; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 3 : issue start operation, I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Error : WPG timeout\n", __FUNCTION__); + return HPC_ERROR; + } + //-------------------------------------------------------------------- + // READ - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Exit Error:I2C timeout\n"); + return HPC_ERROR; + } + + //-------------------------------------------------------------------- + // READ - step 6 : get DATA + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + + status = (u8) data; + + debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); + + return (status); +} + +/*---------------------------------------------------------------------- +* Name: ctrl_write +* +* Action: write to HPC over I2C +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +static u8 ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) +{ + u8 rc; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + int i; + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", + __FUNCTION__, (ulong) WPGBbar, index, cmd); + + rc = 0; + //-------------------------------------------------------------------- + // WRITE - step 1 + // write at address, byte length, I2C address (shifted), index + // or write direct, byte length, index + data = 0x00000000; + + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_WRITEATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_WRITEDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 2 : clear the message buffer + data = 0x00000000 | (ulong) cmd; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 3 : issue start operation,I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); + rc = HPC_ERROR; + } + + //-------------------------------------------------------------------- + // WRITE - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Error : I2C timeout\n"); + rc = HPC_ERROR; + } + + debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); + return (rc); +} + +/*---------------------------------------------------------------------- +* Name: hpc_writecmdtoindex() +* +* Action: convert a write command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_writecmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 + case HPC_CTLR_CLEARIRQ: // 0x06.N.15 + case HPC_CTLR_RESET: // 0x07.N.15 + case HPC_CTLR_IRQSTEER: // 0x08.N.15 + case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 + case HPC_ALLSLOT_ON: // 0x11.N.15 + case HPC_ALLSLOT_OFF: // 0x12.N.15 + rc = 0x0F; + break; + + case HPC_SLOT_OFF: // 0x02.Y.0-14 + case HPC_SLOT_ON: // 0x03.Y.0-14 + case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 + case HPC_SLOT_ATTNON: // 0x05.N.0-14 + case HPC_SLOT_BLINKLED: // 0x13.N.0-14 + rc = index; + break; + + case HPC_BUS_33CONVMODE: + case HPC_BUS_66CONVMODE: + case HPC_BUS_66PCIXMODE: + case HPC_BUS_100PCIXMODE: + case HPC_BUS_133PCIXMODE: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + + default: + err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); + rc = HPC_ERROR; + } + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_readcmdtoindex() +* +* Action: convert a read command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_readcmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case READ_CTLRSTATUS: + rc = 0x0F; + break; + case READ_SLOTSTATUS: + case READ_ALLSTAT: + rc = index; + break; + case READ_EXTSLOTSTATUS: + rc = index + WPG_1ST_EXTSLOT_INDEX; + break; + case READ_BUSSTATUS: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + case READ_SLOTLATCHLOWREG: + rc = 0x28; + break; + case READ_REVLEVEL: + rc = 0x25; + break; + case READ_HPCOPTIONS: + rc = 0x27; + break; + default: + rc = HPC_ERROR; + } + return rc; +} + +/*---------------------------------------------------------------------- +* Name: HPCreadslot() +* +* Action: issue a READ command to HPC +* +* Input: pslot - can not be NULL for READ_ALLSTAT +* pstatus - can be NULL for READ_ALLSTAT +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +{ + void *wpg_bbar; + struct controller *ctlr_ptr; + struct list_head *pslotlist; + u8 index, status; + int rc = 0; + int busindex; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", + __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); + + if ((pslot == NULL) + || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { + rc = -EINVAL; + err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if (cmd == READ_BUSSTATUS) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_readcmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + //-------------------------------------------------------------------- + // check controller status before reading + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + switch (cmd) { + case READ_ALLSTAT: + // update the slot structure + pslot->ctrl->status = status; + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) + pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); + + break; + + case READ_SLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_EXTSLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_CTLRSTATUS: + // DO NOT update the slot structure + *pstatus = status; + break; + + case READ_BUSSTATUS: + pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_REVLEVEL: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_HPCOPTIONS: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_SLOTLATCHLOWREG: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + // Not used + case READ_ALLSLOT: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + index = pslot->ctlr_index; + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, + wpg_bbar, &status); + if (!rc) { + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, + ctlr_ptr, wpg_bbar, &status); + if (!rc) + pslot->ext_status = + ctrl_read (ctlr_ptr, wpg_bbar, + index + WPG_1ST_EXTSLOT_INDEX); + } else { + err ("%s - Error ctrl_read failed\n", __FUNCTION__); + rc = -EINVAL; + break; + } + } + break; + default: + rc = -EINVAL; + break; + } + } + //-------------------------------------------------------------------- + // cleanup + //-------------------------------------------------------------------- + iounmap (wpg_bbar); // remove physical to logical address mapping + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_writeslot() +* +* Action: issue a WRITE command to HPC +*---------------------------------------------------------------------*/ +int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +{ + void *wpg_bbar; + struct controller *ctlr_ptr; + u8 index, status; + int busindex; + u8 done; + int rc = 0; + int timeout; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); + if (pslot == NULL) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || + (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || + (cmd == HPC_BUS_133PCIXMODE)) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_writecmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, + ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, + ctlr_ptr->u.wpeg_ctlr.i2c_addr); + + //-------------------------------------------------------------------- + // check controller status before writing + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + + ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); + + //-------------------------------------------------------------------- + // check controller is still not working on the command + //-------------------------------------------------------------------- + timeout = CMD_COMPLETE_TOUT_SEC; + done = FALSE; + while (!done) { + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) { + if (NEEDTOCHECK_CMDSTATUS (cmd)) { + if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) + done = TRUE; + } else + done = TRUE; + } + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("%s - Error command complete timeout\n", __FUNCTION__); + rc = -EFAULT; + } else + timeout--; + } + } + ctlr_ptr->status = status; + } + // cleanup + iounmap (wpg_bbar); // remove physical to logical address mapping + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: get_hpc_access() +* +* Action: make sure only one process can access HPC at one time +*---------------------------------------------------------------------*/ +static void get_hpc_access (void) +{ + down (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: free_hpc_access() +*---------------------------------------------------------------------*/ +void free_hpc_access (void) +{ + up (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_lock_operations() +* +* Action: make sure only one process can change the data structure +*---------------------------------------------------------------------*/ +void ibmphp_lock_operations (void) +{ + down (&semOperations); + stop_polling = POLL_NO; + to_debug = TRUE; + + /* waiting for polling to actually stop */ + down (&sem_poll); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_unlock_operations() +*---------------------------------------------------------------------*/ +void ibmphp_unlock_operations (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + stop_polling = POLL_YES; + to_debug = FALSE; + up (&semOperations); + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: poll_hpc() +*---------------------------------------------------------------------*/ +static void poll_hpc (void) +{ + struct slot myslot, *pslot = NULL; + struct list_head *pslotlist; + int rc; + u8 oldlatchlow = 0x00; + u8 curlatchlow = 0x00; + int pollcnt = 0; + u8 ctrl_count = 0x00; + + debug ("poll_hpc - Entry\n"); + + while (!ibmphp_shutdown) { + if (stop_polling) { + debug ("poll_hpc - stop_polling\n"); + up (&sem_poll); + /* to prevent deadlock */ + if (ibmphp_shutdown) + break; + /* to make the thread sleep */ + down (&semOperations); + up (&semOperations); + debug ("poll_hpc - after stop_polling sleep\n"); + } else { + if (pollcnt) { + // only poll the latch register + oldlatchlow = curlatchlow; + + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) { + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + if (oldlatchlow != curlatchlow) + process_changeinlatch (oldlatchlow, + curlatchlow); + } + } + } + } else { + list_for_each (pslotlist, &ibmphp_slot_head) { + if (stop_polling) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + // make a copy of the old status + memcpy ((void *) &myslot, (void *) pslot, + sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + if ((myslot.status != pslot->status) + || (myslot.ext_status != pslot->ext_status)) + process_changeinstatus (pslot, &myslot); + } + + if (!stop_polling) { + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = + list_entry (pslotlist, struct slot, + ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + } + } + } + } + INCREMENT_POLLCNT (pollcnt); + long_delay (POLL_INTERVAL_SEC * HZ); // snooze + } + } + up (&sem_poll); + up (&sem_exit); + debug ("poll_hpc - Exit\n"); +} + + +/* ---------------------------------------------------------------------- + * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) + * + * Action: fill out the hotplug_slot info + * + * Input: pointer to hotplug_slot + * + * Return + * Value: 0 or error codes + *-----------------------------------------------------------------------*/ +int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) +{ + int rc = 0; + struct slot *pslot; + + if (phpslot && phpslot->private) { + pslot = (struct slot *) phpslot->private; + rc = update_slot (pslot, (u8) TRUE); + if (!rc) { + + // power - enabled:1 not:0 + phpslot->info->power_status = SLOT_POWER (pslot->status); + + // attention - off:0, on:1, blinking:2 + phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); + + // latch - open:1 closed:0 + phpslot->info->latch_status = SLOT_LATCH (pslot->status); + + // pci board - present:1 not:0 + if (SLOT_PRESENT (pslot->status)) + phpslot->info->adapter_status = 1; + else + phpslot->info->adapter_status = 0; +/* + if (pslot->bus_on->supported_bus_mode + && (pslot->bus_on->supported_speed == BUS_SPEED_66)) + phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; + else + phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; +*/ } else + rc = -EINVAL; + } else + rc = -EINVAL; + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: update_slot +* +* Action: fill out slot status and extended status, controller status +* +* Input: pointer to slot struct +*---------------------------------------------------------------------*/ +static int update_slot (struct slot *pslot, u8 update) +{ + int rc = 0; + + debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinstatus +* +* Action: compare old and new slot status, process the change in status +* +* Input: pointer to slot struct, old slot struct +* +* Return 0 or error codes +* Value: +* +* Side +* Effects: None. +* +* Notes: +*---------------------------------------------------------------------*/ +static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) +{ + u8 status; + int rc = 0; + u8 disable = FALSE; + u8 update = FALSE; + + debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, + (ulong) poldslot); + + // bit 0 - HPC_SLOT_POWER + if ((pslot->status & 0x01) != (poldslot->status & 0x01)) + /* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */ + update = TRUE; + + // bit 1 - HPC_SLOT_CONNECT + // ignore + + // bit 2 - HPC_SLOT_ATTN + if ((pslot->status & 0x04) != (poldslot->status & 0x04)) + update = TRUE; + + // bit 3 - HPC_SLOT_PRSNT2 + // bit 4 - HPC_SLOT_PRSNT1 + if (((pslot->status & 0x08) != (poldslot->status & 0x08)) + || ((pslot->status & 0x10) != (poldslot->status & 0x10))) + update = TRUE; + + // bit 5 - HPC_SLOT_PWRGD + if ((pslot->status & 0x20) != (poldslot->status & 0x20)) + // OFF -> ON: ignore, ON -> OFF: disable slot + if (poldslot->status & 0x20) + disable = TRUE; + + // bit 6 - HPC_SLOT_BUS_SPEED + // ignore + + // bit 7 - HPC_SLOT_LATCH + if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { + update = TRUE; + // OPEN -> CLOSE + if (pslot->status & 0x80) { + if (SLOT_POWER (pslot->status)) { + // power goes on and off after closing latch + // check again to make sure power is still ON + long_delay (1 * HZ); + rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); + if (SLOT_POWER (status)) + update = TRUE; + else // overwrite power in pslot to OFF + pslot->status &= ~HPC_SLOT_POWER; + } + } + // CLOSE -> OPEN + else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON) + || (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) { + disable = TRUE; + } + // else - ignore + } + // bit 4 - HPC_SLOT_BLINK_ATTN + if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) + update = TRUE; + + if (disable) { + debug ("process_changeinstatus - disable slot\n"); + pslot->flag = FALSE; + rc = ibmphp_disable_slot (pslot->hotplug_slot); + } + + if (update || disable) { + ibmphp_update_slot_info (pslot); + } + + debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinlatch +* +* Action: compare old and new latch reg status, process the change +* +* Input: old and current latch register status +* +* Return 0 or error codes +* Value: +*---------------------------------------------------------------------*/ +static int process_changeinlatch (u8 old, u8 new) +{ + struct slot myslot, *pslot; + u8 i; + u8 mask; + int rc = 0; + + debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); + // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots + + for (i = 1; i <= 6; i++) { + mask = 0x01 << i; + if ((mask & old) != (mask & new)) { + pslot = ibmphp_get_slot_from_physical_num (i); + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); + process_changeinstatus (pslot, &myslot); + } else { + rc = -EINVAL; + err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); + } + } + } + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_poll_thread +* +* Action: polling +* +* Return 0 +* Value: +*---------------------------------------------------------------------*/ +static int hpc_poll_thread (void *data) +{ + debug ("%s - Entry\n", __FUNCTION__); + lock_kernel (); + daemonize (); + reparent_to_init (); + + // New name + strcpy (current->comm, "hpc_poll"); + + unlock_kernel (); + + poll_hpc (); + + tid_poll = 0; + debug ("%s - Exit\n", __FUNCTION__); + return 0; +} + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_start_poll_thread +* +* Action: start polling thread +*---------------------------------------------------------------------*/ +int ibmphp_hpc_start_poll_thread (void) +{ + int rc = 0; + + debug ("ibmphp_hpc_start_poll_thread - Entry\n"); + + tid_poll = kernel_thread (hpc_poll_thread, 0, 0); + if (tid_poll < 0) { + err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n"); + rc = -1; + } + + debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_stop_poll_thread +* +* Action: stop polling thread and cleanup +*---------------------------------------------------------------------*/ +void ibmphp_hpc_stop_poll_thread (void) +{ + debug ("ibmphp_hpc_stop_poll_thread - Entry\n"); + + ibmphp_shutdown = TRUE; + ibmphp_lock_operations (); + + // wait for poll thread to exit + down (&sem_exit); + + // cleanup + free_hpc_access (); + ibmphp_unlock_operations (); + up (&sem_poll); + up (&sem_exit); + + debug ("ibmphp_hpc_stop_poll_thread - Exit\n"); +} + +/*---------------------------------------------------------------------- +* Name: hpc_wait_ctlr_notworking +* +* Action: wait until the controller is in a not working state +* +* Return 0, HPC_ERROR +* Value: +*---------------------------------------------------------------------*/ +static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, + u8 * pstatus) +{ + int rc = 0; + u8 done = FALSE; + + debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); + + while (!done) { + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); + if (*pstatus == HPC_ERROR) { + rc = HPC_ERROR; + done = TRUE; + } + if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) + done = TRUE; + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("HPCreadslot - Error ctlr timeout\n"); + rc = HPC_ERROR; + } else + timeout--; + } + } + debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); + return rc; +} diff -urN linux-2.4.18/drivers/hotplug/ibmphp_pci.c linux-2.4.19-pre5/drivers/hotplug/ibmphp_pci.c --- linux-2.4.18/drivers/hotplug/ibmphp_pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp_pci.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,1719 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include "ibmphp.h" + + +static int configure_device(struct pci_func *); +static int configure_bridge(struct pci_func **, u8); +static struct res_needed *scan_behind_bridge(struct pci_func *, u8); +static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); +static u8 find_sec_number (u8 primary_busno, u8 slotno); + +/* + * NOTE..... If BIOS doesn't provide default routing, we assign: + * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. + * If adapter is bridged, then we assign 11 to it and devices behind it. + * We also assign the same irq numbers for multi function devices. + * These are PIC mode, so shouldn't matter n.e.ways (hopefully) + */ +static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +{ + int j = 0; + for (j = 0; j < 4; j++) { + if (cur_func->irq[j] == 0xff) { + switch (class_code) { + case PCI_BASE_CLASS_STORAGE: + cur_func->irq[j] = SCSI_IRQ; + break; + case PCI_BASE_CLASS_NETWORK: + cur_func->irq[j] = LAN_IRQ; + break; + default: + cur_func->irq[j] = OTHER_IRQ; + break; + } + } + } +} + +/* + * Configures the device to be added (will allocate needed resources if it + * can), the device can be a bridge or a regular pci device, can also be + * multi-functional + * + * Input: function to be added + * + * TO DO: The error case with Multifunction device or multi function bridge, + * if there is an error, will need to go through all previous functions and + * unconfigure....or can add some code into unconfigure_card.... + */ +int ibmphp_configure_card (struct pci_func *func, u8 slotno) +{ + u16 vendor_id; + u32 class; + u8 class_code; + u8 hdr_type, device, sec_number; + u8 function; + struct pci_func *newfunc; /* for multi devices */ + struct pci_func *cur_func, *prev_func; + int rc, i, j; + int cleanup_count; + u8 flag; + u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ + + debug ("inside configure_card, func->busno = %x \n", func->busno); + + device = func->device; + cur_func = func; + + /* We only get bus and device from IRQ routing table. So at this point, + * func->busno is correct, and func->device contains only device (at the 5 + * highest bits) + */ + + /* For every function on the card */ + for (function = 0x00; function < 0x08; function++) { + cur_func->function = function; + + debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", cur_func->busno, device, function); + + pci_read_config_word_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_VENDOR_ID, &vendor_id); + + debug ("vendor_id is %x\n", vendor_id); + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + debug ("found valid device, vendor_id = %x\n", vendor_id); + + ++valid_device; + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_CLASS_REVISION, &class); + + class_code = class >> 24; + debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x. \n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + cur_func->next = NULL; + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x...bailing out\n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + cur_func->next = newfunc; + cur_func = newfunc; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + assign_alt_irq (cur_func, class_code); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to hot-add PPB properly.\n"); + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + /* This could only happen if kmalloc failed */ + if (rc) { + /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + cur_func = newfunc; + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + debug ("class now is %x\n", class); + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + + assign_alt_irq (cur_func, class_code); + + debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + err ("was not able to hot-add PPB properly.\n"); + cleanup_count = 2; + goto error; + } + debug ("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("after configuring bridge..., sec_number = %x\n", sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + debug ("inside for loop, device is %x\n", i); + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err (" out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + + /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + function = 0x8; + break; + default: + err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); + return -ENXIO; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); + return -ENODEV; + } + + return 0; + +error: + for (i = 0; i < cleanup_count; i++) { + if (cur_func->io[i]) { + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } else if (cur_func->pfmem[i]) { + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } else if (cur_func->mem[i]) { + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + } + return rc; +} + +/* + * This function configures the pci BARs of a single device. + * Input: pointer to the pci_func + * Output: configured PCI, 0, or error + */ +static int configure_device (struct pci_func *func) +{ + u32 bar[6]; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + u8 irq; + int count; + int len[6]; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *mem_tmp; + struct resource_node *pfmem[6]; + u8 device; + u8 function; + + debug ("%s - inside\n", __FUNCTION__); + + device = func->device; + function = func->function; + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + + /* not sure if i need this. per scott, said maybe need smth like this + if devices don't adhere 100% to the spec, so don't want to write + to the reserved bits + + pcibios_read_config_byte(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, &tmp); + if (tmp & 0x01) // IO + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); + else // Memory + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); + */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + debug ("inside IO SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO %x, count %d\n", len[count], count); + + io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io[count], 0, sizeof (struct resource_node)); + io[count]->type = IO; + io[count]->busno = func->busno; + io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + io[count]->len = len[count]; + if (ibmphp_check_resource(io[count], 0) == 0) { + ibmphp_add_resource (io[count]); + func->io[count] = io[count]; + } else { + err ("cannot allocate requested io for bus %x device %x function %x len %x\n", + func->busno, func->device, func->function, len[count]); + kfree (io[count]); + return -EIO; + } + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start); + + /* _______________This is for debugging purposes only_____________________ */ + debug ("b4 writing, the IO address is %x\n", func->io[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing.... the start address is %x\n", bar[count]); + /* _________________________________________________________________________*/ + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + debug ("PFMEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM %x, count %d\n", len[count], count); + + pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem[count], 0, sizeof (struct resource_node)); + pfmem[count]->type = PFMEM; + pfmem[count]->busno = func->busno; + pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem[count]->len = len[count]; + pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (pfmem[count], 0) == 0) { + ibmphp_add_resource (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + kfree (pfmem[count]); + return -ENOMEM; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem[count]->busno; + mem_tmp->devfunc = pfmem[count]->devfunc; + mem_tmp->len = pfmem[count]->len; + debug ("there's no pfmem... going into mem.\n"); + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem[count]->fromMem = TRUE; + pfmem[count]->rangeno = mem_tmp->rangeno; + pfmem[count]->start = mem_tmp->start; + pfmem[count]->end = mem_tmp->end; + ibmphp_add_pfmem_from_mem (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (pfmem[count]); + return -EIO; + } + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start); + + /*_______________This if for debugging purposes only______________________________*/ + debug ("b4 writing, start addres is %x\n", func->pfmem[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing, start address is %x\n", bar[count]); + /*_________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + debug ("inside the mem 64 case, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + } + } else { + /* regular memory */ + debug ("REGULAR MEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Mem %x, count %d\n", len[count], count); + + mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem[count], 0, sizeof (struct resource_node)); + mem[count]->type = MEM; + mem[count]->busno = func->busno; + mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem[count]->len = len[count]; + if (ibmphp_check_resource (mem[count], 0) == 0) { + ibmphp_add_resource (mem[count]); + func->mem[count] = mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem[count]); + return -EIO; + } + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start); + /* _______________________This is for debugging purposes only _______________________*/ + debug ("b4 writing, start address is %x\n", func->mem[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing, the address is %x\n", bar[count]); + /* __________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + debug ("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + } + } + } /* end of mem */ + } /* end of for */ + + func->bus = 0; /* To indicate that this is not a PPB */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY); + + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_ROM_ADDRESS, 0x00L); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE); + + return 0; +} + +/****************************************************************************** + * This routine configures a PCI-2-PCI bridge and the functions behind it + * Parameters: pci_func + * Returns: + ******************************************************************************/ +static int configure_bridge (struct pci_func **func_passed, u8 slotno) +{ + int count; + int i; + int rc; + u8 sec_number; + u8 io_base; + u16 pfmem_base; + u32 bar[2]; + u32 len[2]; + u8 flag_io = FALSE; + u8 flag_mem = FALSE; + u8 flag_pfmem = FALSE; + u8 need_io_upper = FALSE; + u8 need_pfmem_upper = FALSE; + struct res_needed *amount_needed = NULL; + struct resource_node *io = NULL; + struct resource_node *bus_io[2] = {NULL, NULL}; + struct resource_node *mem = NULL; + struct resource_node *bus_mem[2] = {NULL, NULL}; + struct resource_node *mem_tmp = NULL; + struct resource_node *pfmem = NULL; + struct resource_node *bus_pfmem[2] = {NULL, NULL}; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + struct pci_func *func = *func_passed; + u8 function; + u8 device; + u8 irq; + int retval; + + debug ("%s - enter\n", __FUNCTION__); + + function = func->function; + device = func->device; + + /* Configuring necessary info for the bridge so that we could see the devices + * behind it + */ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, func->busno); + + /* _____________________For debugging purposes only __________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, &pri_number); + debug ("primary # written into the bridge is %x\n", pri_number); + ___________________________________________________________________________*/ + + /* in EBDA, only get allocated 1 additional bus # per slot */ + sec_number = find_sec_number (func->busno, slotno); + if (sec_number == 0xff) { + err ("cannot allocate secondary bus number for the bridged device \n"); + return -EINVAL; + } + + debug ("after find_sec_number, the number we got is %x\n", sec_number); + debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, sec_number); + + /* __________________For debugging purposes only __________________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number after write/read is %x\n", sec_number); + ________________________________________________________________________________*/ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, sec_number); + + /* __________________For debugging purposes only ____________________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, &sec_number); + debug ("subordinate number after write/read is %x\n", sec_number); + __________________________________________________________________________________*/ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SEC_LATENCY_TIMER, LATENCY); + + debug ("func->busno is %x\n", func->busno); + debug ("sec_number after writing is %x\n", sec_number); + + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + /* First we need to allocate mem/io for the bridge itself in case it needs it */ + for (count = 0; address[count]; count++) { /* for 2 BARs */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + + if (!bar[count]) { + /* This BAR is not implemented */ + debug ("so we come here then, eh?, count = %d\n", count); + continue; + } + // tmp_bar = bar[count]; + + debug ("Bar %d wants %x\n", count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO = %x\n", len[count]); + + bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!bus_io[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_io[count], 0, sizeof (struct resource_node)); + bus_io[count]->type = IO; + bus_io[count]->busno = func->busno; + bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_io[count]->len = len[count]; + if (ibmphp_check_resource (bus_io[count], 0) == 0) { + ibmphp_add_resource (bus_io[count]); + func->io[count] = bus_io[count]; + } else { + err ("cannot allocate requested io for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_io[count]); + return -EIO; + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start); + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM = %x\n", len[count]); + + bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_pfmem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_pfmem[count], 0, sizeof (struct resource_node)); + bus_pfmem[count]->type = PFMEM; + bus_pfmem[count]->busno = func->busno; + bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_pfmem[count]->len = len[count]; + bus_pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { + ibmphp_add_resource (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = bus_pfmem[count]->busno; + mem_tmp->devfunc = bus_pfmem[count]->devfunc; + mem_tmp->len = bus_pfmem[count]->len; + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + bus_pfmem[count]->fromMem = TRUE; + bus_pfmem[count]->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (bus_pfmem[count]); + return -EIO; + } + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + + } + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Memory is %x\n", len[count]); + + bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_mem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_mem[count], 0, sizeof (struct resource_node)); + bus_mem[count]->type = MEM; + bus_mem[count]->busno = func->busno; + bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_mem[count]->len = len[count]; + if (ibmphp_check_resource (bus_mem[count], 0) == 0) { + ibmphp_add_resource (bus_mem[count]); + func->mem[count] = bus_mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_mem[count]); + return -EIO; + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + + } + } + } /* end of mem */ + } /* end of for */ + + /* Now need to see how much space the devices behind the bridge needed */ + amount_needed = scan_behind_bridge (func, sec_number); + if (amount_needed == NULL) + return -ENOMEM; + + debug ("after coming back from scan_behind_bridge\n"); + debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); + debug ("amount_needed->io = %x\n", amount_needed->io); + debug ("amount_needed->mem = %x\n", amount_needed->mem); + debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); + + if (amount_needed->not_correct) { + debug ("amount_needed is not correct \n"); + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + if (bus_io[count]) { + ibmphp_remove_resource (bus_io[count]); + func->io[count] = NULL; + } else if (bus_pfmem[count]) { + ibmphp_remove_resource (bus_pfmem[count]); + func->pfmem[count] = NULL; + } else if (bus_mem[count]) { + ibmphp_remove_resource (bus_mem[count]); + func->mem[count] = NULL; + } + } + kfree (amount_needed); + return -ENODEV; + } + + if (!amount_needed->io) { + debug ("it doesn't want IO?\n"); + flag_io = TRUE; + } else { + debug ("it wants %x IO behind the bridge \n", amount_needed->io); + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = func->busno; + io->devfunc = ((func->device << 3) | (func->function & 0x7)); + io->len = amount_needed->io; + if (ibmphp_check_resource (io, 1) == 0) { + debug ("were we able to add io\n"); + ibmphp_add_resource (io); + flag_io = TRUE; + } + } + + if (!amount_needed->mem) { + debug ("it doesn't want n.e.memory?\n"); + flag_mem = TRUE; + } else { + debug ("it wants %x memory behind the bridge\n", amount_needed->mem); + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = func->busno; + mem->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem->len = amount_needed->mem; + if (ibmphp_check_resource (mem, 1) == 0) { + ibmphp_add_resource (mem); + flag_mem = TRUE; + debug ("were we able to add mem\n"); + } + } + + if (!amount_needed->pfmem) { + debug ("it doesn't want n.e.pfmem mem?\n"); + flag_pfmem = TRUE; + } else { + debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = func->busno; + pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem->len = amount_needed->pfmem; + pfmem->fromMem = FALSE; + if (ibmphp_check_resource (pfmem, 1) == 0) { + ibmphp_add_resource (pfmem); + flag_pfmem = TRUE; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem->busno; + mem_tmp->devfunc = pfmem->devfunc; + mem_tmp->len = pfmem->len; + if (ibmphp_check_resource (mem_tmp, 1) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem->fromMem = TRUE; + pfmem->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (pfmem); + flag_pfmem = TRUE; + } + } + } + + debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); + debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); + + if (flag_io && flag_mem && flag_pfmem) { + bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!bus) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus, 0, sizeof (struct bus_node)); + bus->busno = sec_number; + debug ("b4 adding new bus\n"); + rc = add_new_bus (bus, io, mem, pfmem, func->busno); + if (rc) { + if (rc == -ENOMEM) { + ibmphp_remove_bus (bus, func->busno); + return rc; + } + retval = rc; + goto error; + } + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &io_base); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &pfmem_base); + + if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + debug ("io 32\n"); + need_io_upper = TRUE; + } + if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + debug ("pfmem 64\n"); + need_pfmem_upper = TRUE; + } + + if (bus->noIORanges) { + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); + + /* _______________This is for debugging purposes only ____________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &temp); + debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, &temp); + debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + ________________________________________________________________________*/ + + if (need_io_upper) { /* since can't support n.e.ways */ + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE_UPPER16, 0x0000); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT_UPPER16, 0x0000); + } + } else { + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00); + } + + if (bus->noMemRanges) { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); + + /* ____________________This is for debugging purposes only ________________________ + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, &temp); + debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, &temp); + debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + __________________________________________________________________________________*/ + + } else { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0xffff); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000); + } + if (bus->noPFMemRanges) { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); + + /* __________________________This is for debugging purposes only _______________________ + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &temp); + debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, &temp); + debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + ______________________________________________________________________________________*/ + + if (need_pfmem_upper) { /* since can't support n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_BASE_UPPER32, 0x00000000); + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_LIMIT_UPPER32, 0x00000000); + } + } else { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0xffff); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000); + } + + debug ("b4 writing control information\n"); + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + /* + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, ctrl); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); + */ + + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, 0x07); + for (i = 0; i < 32; i++) { + if (amount_needed->devices[i]) { + debug ("device where devices[i] is 1 = %x\n", i); + func->devices[i] = 1; + } + } + func->bus = 1; /* For unconfiguring, to indicate it's PPB */ + func_passed = &func; + debug ("func->busno b4 returning is %x\n", func->busno); + debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); + kfree (amount_needed); + return 0; + } else { + err ("Configuring bridge was unsuccessful... \n"); + mem_tmp = NULL; + retval = -EIO; + goto error; + } + +error: + if (amount_needed) + kfree (amount_needed); + if (pfmem) + ibmphp_remove_resource (pfmem); + if (io) + ibmphp_remove_resource (io); + if (mem) + ibmphp_remove_resource (mem); + for (i = 0; i < 2; i++) { /* for 2 BARs */ + if (bus_io[i]) { + ibmphp_remove_resource (bus_io[i]); + func->io[i] = NULL; + } else if (bus_pfmem[i]) { + ibmphp_remove_resource (bus_pfmem[i]); + func->pfmem[i] = NULL; + } else if (bus_mem[i]) { + ibmphp_remove_resource (bus_mem[i]); + func->mem[i] = NULL; + } + } + return retval; +} + +/***************************************************************************** + * This function adds up the amount of resources needed behind the PPB bridge + * and passes it to the configure_bridge function + * Input: bridge function + * Ouput: amount of resources needed + *****************************************************************************/ +static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +{ + int count, len[6]; + u16 vendor_id; + u8 hdr_type; + u8 device, function; + int howmany = 0; /*this is to see if there are any devices behind the bridge */ + + u32 bar[6], class; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + struct res_needed *amount; + + amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); + if (amount == NULL) + return NULL; + memset (amount, 0, sizeof (struct res_needed)); + + debug ("the bus_no behind the bridge is %x\n", busno); + debug ("scanning devices behind the bridge...\n"); + for (device = 0; device < 32; device++) { + amount->devices[device] = 0; + for (function = 0; function < 8; function++) { + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + howmany++; + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class); + + debug ("hdr_type behind the bridge is %x\n", hdr_type); + if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { + err ("embedded bridges not supported for hot-plugging.\n"); + amount->not_correct = TRUE; + return amount; + } + + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } + + amount->devices[device] = 1; + + for (count = 0; address[count]; count++) { + /* for 6 BARs */ + /* + pci_read_config_byte_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], &tmp); + if (tmp & 0x01) // IO + pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFD); + else // MEMORY + pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &bar[count]); + + debug ("what is bar[count]? %x, count = %d\n", bar[count], count); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + //tmp_bar = bar[count]; + + debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + amount->io += len[count]; + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->pfmem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) + /* takes up another dword */ + count += 1; + + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->mem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } + } /* end for */ + } /* end if (valid) */ + } /* end for */ + } /* end for */ + + if (!howmany) + amount->not_correct = TRUE; + else + amount->not_correct = FALSE; + if ((amount->io) && (amount->io < IOBRIDGE)) + amount->io = IOBRIDGE; + if ((amount->mem) && (amount->mem < MEMBRIDGE)) + amount->mem = MEMBRIDGE; + if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) + amount->pfmem = MEMBRIDGE; + return amount; +} + +/* The following 3 unconfigure_boot_ routines deal with the case when we had the card + * upon bootup in the system, since we don't allocate func to such case, we need to read + * the start addresses from pci config space and then find the corresponding entries in + * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) + * Change: we also call these functions even if we configured the card ourselves (i.e., not + * the bootup case), since it should work same way + */ +static int unconfigure_boot_device (u8 busno, u8 device, u8 function) +{ + u32 start_address; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct bus_node *bus; + u32 end_address; + u32 temp_end; + u32 size; + u32 tmp_address; + + debug ("%s - enter\n", __FUNCTION__); + + bus = ibmphp_find_res_bus (busno); + if (!bus) { + debug ("cannot find corresponding bus.\n"); + return -EINVAL; + } + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address); + + /* We can do this here, b/c by that time the device driver of the card has been stopped */ + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &size); + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], start_address); + + debug ("start_address is %x\n", start_address); + debug ("busno, device, function %x %x %x\n", busno, device, function); + if (!size) { + /* This BAR is not implemented */ + debug ("is this bar no implemented?, count = %d\n", count); + continue; + } + tmp_address = start_address; + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + size = size & 0xFFFFFFFC; + size = ~size + 1; + end_address = start_address + size - 1; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + /* This is needed b/c of the old I/O restrictions in the BIOS */ + while (temp_end < end_address) { + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + } + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of pfmem is %x\n", start_address); + + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EIO; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of mem is %x\n", start_address); + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EIO; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + + return 0; +} + +static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) +{ + int count; + int bus_no, pri_no, sub_no, sec_no = 0; + u32 start_address, tmp_address; + u8 sec_number, sub_number, pri_number; + struct resource_node *io = NULL; + struct resource_node *mem = NULL; + struct resource_node *pfmem = NULL; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + + bus_no = (int) busno; + debug ("busno is %x\n", busno); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PRIMARY_BUS, &pri_number); + debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number is %x\n", sec_number); + sec_no = (int) sec_number; + pri_no = (int) pri_number; + if (pri_no != bus_no) { + err ("primary numbers in our structures and pci config space don't match.\n"); + return -EINVAL; + } + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number); + sec_no = (int) sec_no; + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SUBORDINATE_BUS, &sub_number); + sub_no = (int) sub_number; + debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); + if (sec_no != sub_number) { + err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); + return -ENODEV; + } + + bus = ibmphp_find_res_bus (sec_number); + debug ("bus->busno is %x\n", bus->busno); + debug ("sec_number is %x\n", sec_number); + if (!bus) { + err ("cannot find Bus structure for the bridged device\n"); + return -EINVAL; + } + + ibmphp_remove_bus (bus, busno); + + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address); + + if (!start_address) { + /* This BAR is not implemented */ + continue; + } + + tmp_address = start_address; + + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + if (io) + debug ("io->start = %x\n", io->start); + + ibmphp_remove_resource (io); + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EINVAL; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EINVAL; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + debug ("%s - exiting, returning success\n", __FUNCTION__); + return 0; +} + +static int unconfigure_boot_card (struct slot *slot_cur) +{ + u16 vendor_id; + u32 class; + u8 hdr_type; + u8 device; + u8 busno; + u8 function; + int rc; + u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ + + debug ("%s - enter\n", __FUNCTION__); + + device = slot_cur->device; + busno = slot_cur->bus; + + debug ("b4 for loop, device is %x\n", device); + /* For every function on the card */ + for (function = 0x0; function < 0x08; function++) { + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + ++valid_device; + + debug ("%s - found correct device\n", __FUNCTION__); + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class); + + debug ("hdr_type %x, class %x\n", hdr_type, class); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x function %x is VGA compatible and is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x function %x is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + break; + default: + err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); + return -1; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Could not find device to unconfigure. Or could not read the card. \n"); + return -1; + } + return 0; +} + +/* + * free the resources of the card (multi, single, or bridged) + * Parameters: slot, flag to say if this is for removing entire module or just + * unconfiguring the device + * TO DO: will probably need to add some code in case there was some resource, + * to remove it... this is from when we have errors in the configure_card... + * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! + * Returns: 0, -1, -ENODEV + */ +int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) +{ + int i; + int count; + int rc; + struct slot *sl = *slot_cur; + struct pci_func *cur_func = NULL; + struct pci_func *temp_func; + + debug ("%s - enter\n", __FUNCTION__); + + if (!the_end) { + /* Need to unconfigure the card */ + rc = unconfigure_boot_card (sl); + if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { + /* In all other cases, will still need to get rid of func structure if it exists */ + return rc; + } + } + + if (sl->func) { + debug ("do we come in here? \n"); + cur_func = sl->func; + while (cur_func) { + /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ + if (cur_func->bus) { + /* in other words, it's a PPB */ + count = 2; + } else { + count = 6; + } + + for (i = 0; i < count; i++) { + if (cur_func->io[count]) { + debug ("io[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->io[count]); + cur_func->io[count] = NULL; + } + if (cur_func->mem[count]) { + debug ("mem[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->mem[count]); + cur_func->mem[count] = NULL; + } + if (cur_func->pfmem[count]) { + debug ("pfmem[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->pfmem[count]); + cur_func->pfmem[count] = NULL; + } + } + + temp_func = cur_func->next; + kfree (cur_func); + cur_func = temp_func; + } + } + + sl->func = NULL; + *slot_cur = sl; + return 0; +} + +/* + * add a new bus resulting from hot-plugging a PPB bridge with devices + * + * Input: bus and the amount of resources needed (we know we can assign those, + * since they've been checked already + * Output: bus added to the correct spot + * 0, -1, error + */ +static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) +{ + struct range_node *io_range = NULL; + struct range_node *mem_range = NULL; + struct range_node *pfmem_range = NULL; + struct bus_node *cur_bus = NULL; + + /* Trying to find the parent bus number */ + cur_bus = ibmphp_find_res_bus (parent_busno); + if (!cur_bus) { + err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); + return -ENODEV; + } + + list_add (&bus->bus_list, &cur_bus->bus_list); + + if (io) { + io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!io_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io_range, 0, sizeof (struct range_node)); + io_range->start = io->start; + io_range->end = io->end; + io_range->rangeno = 1; + bus->noIORanges = 1; + bus->rangeIO = io_range; + } + if (mem) { + mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!mem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem_range, 0, sizeof (struct range_node)); + mem_range->start = mem->start; + mem_range->end = mem->end; + mem_range->rangeno = 1; + bus->noMemRanges = 1; + bus->rangeMem = mem_range; + } + if (pfmem) { + pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!pfmem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem_range, 0, sizeof (struct range_node)); + pfmem_range->start = pfmem->start; + pfmem_range->end = pfmem->end; + pfmem_range->rangeno = 1; + bus->noPFMemRanges = 1; + bus->rangePFMem = pfmem_range; + } + return 0; +} + +/* + * find the 1st available bus number for PPB to set as its secondary bus + * Parameters: bus_number of the primary bus + * Returns: bus_number of the secondary bus or 0xff in case of failure + */ +static u8 find_sec_number (u8 primary_busno, u8 slotno) +{ + int min, max; + u8 busno; + struct bus_info *bus; + + bus = ibmphp_find_same_bus_num (primary_busno); + if (!bus) { + err ("cannot get slot range of the bus from the BIOS\n"); + return 0xff; + } + max = bus->slot_max; + min = bus->slot_min; + if ((slotno > max) || (slotno < min)) { + err ("got the wrong range\n"); + return 0xff; + } + busno = (u8) (slotno - (u8) min); + busno += primary_busno + 0x01; + if (!ibmphp_find_res_bus (busno)) + return busno; + return 0xff; +} + diff -urN linux-2.4.18/drivers/hotplug/ibmphp_res.c linux-2.4.19-pre5/drivers/hotplug/ibmphp_res.c --- linux-2.4.18/drivers/hotplug/ibmphp_res.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/ibmphp_res.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,2067 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include "ibmphp.h" + +static int flags = 0; /* for testing */ + +static void update_resources (struct bus_node *bus_cur, int type, int rangeno); +static int once_over (void); +static int remove_ranges (struct bus_node *, struct bus_node *); +static int update_bridge_ranges (struct bus_node **); +static int add_range (int type, struct range_node *, struct bus_node *); +static void fix_resources (struct bus_node *); +static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); + +static LIST_HEAD(gbuses); + +static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) +{ + struct bus_node * newbus; + + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory \n"); + return NULL; + } + + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + list_add_tail (&newbus->bus_list, &gbuses); + return newbus; +} + +static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) +{ + struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!rs) { + err ("out of system memory \n"); + return NULL; + } + memset (rs, 0, sizeof (struct resource_node)); + rs->busno = curr->bus_num; + rs->devfunc = curr->dev_fun; + rs->start = curr->start_addr; + rs->end = curr->end_addr; + rs->len = curr->end_addr - curr->start_addr + 1; + return rs; +} + +static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) +{ + struct bus_node * newbus; + struct range_node *newrange; + u8 num_ranges = 0; + + if (first_bus) { + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory. \n"); + return -ENOMEM; + } + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + } else { + newbus = *new_bus; + switch (flag) { + case MEM: + num_ranges = newbus->noMemRanges; + break; + case PFMEM: + num_ranges = newbus->noPFMemRanges; + break; + case IO: + num_ranges = newbus->noIORanges; + break; + } + } + + newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!newrange) { + if (first_bus) + kfree (newbus); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newrange, 0, sizeof (struct range_node)); + newrange->start = curr->start_addr; + newrange->end = curr->end_addr; + + if (first_bus || (!num_ranges)) + newrange->rangeno = 1; + else { + /* need to insert our range */ + add_range (flag, newrange, newbus); + debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); + } + + switch (flag) { + case MEM: + newbus->rangeMem = newrange; + if (first_bus) + newbus->noMemRanges = 1; + else { + debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noMemRanges; + fix_resources (newbus); + } + break; + case IO: + newbus->rangeIO = newrange; + if (first_bus) + newbus->noIORanges = 1; + else { + debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noIORanges; + fix_resources (newbus); + } + break; + case PFMEM: + newbus->rangePFMem = newrange; + if (first_bus) + newbus->noPFMemRanges = 1; + else { + debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noPFMemRanges; + fix_resources (newbus); + } + + break; + } + + *new_bus = newbus; + *new_range = newrange; + return 0; +} + + +/* Notes: + * 1. The ranges are ordered. The buses are not ordered. (First come) + * + * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem + * are not sorted. (no need since use mem node). To not change the entire code, we + * also add mem node whenever this case happens so as not to change + * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) + */ + +/***************************************************************************** + * This is the Resource Management initialization function. It will go through + * the Resource list taken from EBDA and fill in this module's data structures + * + * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, + * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW + * + * Input: ptr to the head of the resource list from EBDA + * Output: 0, -1 or error codes + ***************************************************************************/ +int ibmphp_rsrc_init (void) +{ + struct ebda_pci_rsrc *curr; + struct range_node *newrange = NULL; + struct bus_node *newbus = NULL; + struct bus_node *bus_cur; + struct bus_node *bus_prev; + struct list_head *tmp; + struct resource_node *new_io = NULL; + struct resource_node *new_mem = NULL; + struct resource_node *new_pfmem = NULL; + int rc; + struct list_head *tmp_ebda; + + list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { + curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + if (!(curr->rsrc_type & PCIDEVMASK)) { + /* EBDA still lists non PCI devices, so ignore... */ + debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); + // continue; + } + + /* this is a primary bus resource */ + if (curr->rsrc_type & PRIMARYBUSMASK) { + /* memory */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* no bus structure exists in place yet */ + if (list_empty (&gbuses)) { + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + /* found our bus */ + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + + list_add_tail (&newbus->bus_list, &gbuses); + debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* prefetchable memory */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + /* found our bus */ + rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + + } else { + ; /* type is reserved WHAT TO DO IN THIS CASE??? + NOTHING TO DO??? */ + } + } else { + /* regular pci device resource */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* Memory resource */ + new_mem = alloc_resources (curr); + if (!new_mem) + return -ENOMEM; + new_mem->type = MEM; + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * assign a -1 and then update once the range + * actually appears... + */ + if (ibmphp_add_resource (new_mem) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstMem = new_mem; + ++newbus->needMemUpdate; + new_mem->rangeno = -1; + } + debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); + + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* PFMemory resource */ + new_pfmem = alloc_resources (curr); + if (!new_pfmem) + return -ENOMEM; + new_pfmem->type = PFMEM; + new_pfmem->fromMem = FALSE; + if (ibmphp_add_resource (new_pfmem) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstPFMem = new_pfmem; + ++newbus->needPFMemUpdate; + new_pfmem->rangeno = -1; + } + + debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO resource */ + new_io = alloc_resources (curr); + if (!new_io) + return -ENOMEM; + new_io->type = IO; + + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * Can assign a -1 and then update once the + * range actually appears... + */ + if (ibmphp_add_resource (new_io) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstIO = new_io; + ++newbus->needIOUpdate; + new_io->rangeno = -1; + } + debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); + } + } + } + + debug ("after the while loop in rsrc_init \n"); + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ + rc = update_bridge_ranges (&bus_cur); + if (rc) + return rc; + } + debug ("b4 once_over in rsrc_init \n"); + rc = once_over (); /* This is to align ranges (so no -1) */ + if (rc) + return rc; + debug ("after once_over in rsrc_init \n"); + return 0; +} + +/******************************************************************************** + * This function adds a range into a sorted list of ranges per bus for a particular + * range type, it then calls another routine to update the range numbers on the + * pci devices' resources for the appropriate resource + * + * Input: type of the resource, range to add, current bus + * Output: 0 or -1, bus and range ptrs + ********************************************************************************/ +static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +{ + struct range_node *range_cur = NULL; + struct range_node *range_prev; + int count = 0, i_init; + int noRanges = 0; + + switch (type) { + case MEM: + range_cur = bus_cur->rangeMem; + noRanges = bus_cur->noMemRanges; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + noRanges = bus_cur->noPFMemRanges; + break; + case IO: + range_cur = bus_cur->rangeIO; + noRanges = bus_cur->noIORanges; + break; + } + + range_prev = NULL; + while (range_cur) { + if (range->start < range_cur->start) + break; + range_prev = range_cur; + range_cur = range_cur->next; + count = count + 1; + } + if (!count) { + /* our range will go at the beginning of the list */ + switch (type) { + case MEM: + bus_cur->rangeMem = range; + break; + case PFMEM: + bus_cur->rangePFMem = range; + break; + case IO: + bus_cur->rangeIO = range; + break; + } + range->next = range_cur; + range->rangeno = 1; + i_init = 0; + } else if (!range_cur) { + /* our range will go at the end of the list */ + range->next = NULL; + range_prev->next = range; + range->rangeno = range_prev->rangeno + 1; + return 0; + } else { + /* the range is in the middle */ + range_prev->next = range; + range->next = range_cur; + range->rangeno = range_cur->rangeno; + i_init = range_prev->rangeno; + } + + for (count = i_init; count < noRanges; ++count) { + ++range_cur->rangeno; + range_cur = range_cur->next; + } + + update_resources (bus_cur, type, i_init + 1); + return 0; +} + +/******************************************************************************* + * This routine goes through the list of resources of type 'type' and updates + * the range numbers that they correspond to. It was called from add_range fnc + * + * Input: bus, type of the resource, the rangeno starting from which to update + ******************************************************************************/ +static void update_resources (struct bus_node *bus_cur, int type, int rangeno) +{ + struct resource_node *res = NULL; + u8 eol = FALSE; /* end of list indicator */ + + switch (type) { + case MEM: + if (bus_cur->firstMem) + res = bus_cur->firstMem; + break; + case PFMEM: + if (bus_cur->firstPFMem) + res = bus_cur->firstPFMem; + break; + case IO: + if (bus_cur->firstIO) + res = bus_cur->firstIO; + break; + } + + if (res) { + while (res) { + if (res->rangeno == rangeno) + break; + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else { + eol = TRUE; + break; + } + } + + if (!eol) { + /* found the range */ + while (res) { + ++res->rangeno; + res = res->next; + } + } + } +} + +static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) +{ + char * str = ""; + switch (res->type) { + case IO: + str = "io"; + break; + case MEM: + str = "mem"; + break; + case PFMEM: + str = "pfmem"; + break; + } + + while (res) { + if (res->rangeno == -1) { + while (range) { + if ((res->start >= range->start) && (res->end <= range->end)) { + res->rangeno = range->rangeno; + debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); + switch (res->type) { + case IO: + --bus_cur->needIOUpdate; + break; + case MEM: + --bus_cur->needMemUpdate; + break; + case PFMEM: + --bus_cur->needPFMemUpdate; + break; + } + break; + } + range = range->next; + } + } + if (res->next) + res = res->next; + else + res = res->nextRange; + } + +} + +/***************************************************************************** + * This routine reassigns the range numbers to the resources that had a -1 + * This case can happen only if upon initialization, resources taken by pci dev + * appear in EBDA before the resources allocated for that bus, since we don't + * know the range, we assign -1, and this routine is called after a new range + * is assigned to see the resources with unknown range belong to the added range + * + * Input: current bus + * Output: none, list of resources for that bus are fixed if can be + *******************************************************************************/ +static void fix_resources (struct bus_node *bus_cur) +{ + struct range_node *range; + struct resource_node *res; + + debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); + + if (bus_cur->needIOUpdate) { + res = bus_cur->firstIO; + range = bus_cur->rangeIO; + fix_me (res, bus_cur, range); + } + if (bus_cur->needMemUpdate) { + res = bus_cur->firstMem; + range = bus_cur->rangeMem; + fix_me (res, bus_cur, range); + } + if (bus_cur->needPFMemUpdate) { + res = bus_cur->firstPFMem; + range = bus_cur->rangePFMem; + fix_me (res, bus_cur, range); + } +} + +/******************************************************************************* + * This routine adds a resource to the list of resources to the appropriate bus + * based on their resource type and sorted by their starting addresses. It assigns + * the ptrs to next and nextRange if needed. + * + * Input: 3 diff. resources (nulled out if not needed) + * Output: ptrs assigned (to the node) + * 0 or -1 + *******************************************************************************/ +int ibmphp_add_resource (struct resource_node *res) +{ + struct resource_node *res_cur; + struct resource_node *res_prev; + struct bus_node *bus_cur; + struct range_node *range_cur = NULL; + struct resource_node *res_start = NULL; + + debug ("%s - enter\n", __FUNCTION__); + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + err ("no bus in the system, either pci_dev's wrong or allocation failed\n"); + return -ENODEV; + } + + /* Normal case */ + switch (res->type) { + case IO: + range_cur = bus_cur->rangeIO; + res_start = bus_cur->firstIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + res_start = bus_cur->firstMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + res_start = bus_cur->firstPFMem; + break; + default: + err ("cannot read the type of the resource to add... problem \n"); + return -EINVAL; + } + while (range_cur) { + if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { + res->rangeno = range_cur->rangeno; + break; + } + range_cur = range_cur->next; + } + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * this is again the case of rangeno = -1 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + + if (!range_cur) { + switch (res->type) { + case IO: + ++bus_cur->needIOUpdate; + break; + case MEM: + ++bus_cur->needMemUpdate; + break; + case PFMEM: + ++bus_cur->needPFMemUpdate; + break; + } + res->rangeno = -1; + } + + debug ("The range is %d\n", res->rangeno); + if (!res_start) { + /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + res->next = NULL; + res->nextRange = NULL; + } else { + res_cur = res_start; + res_prev = NULL; + + debug ("res_cur->rangeno is %d\n", res_cur->rangeno); + + while (res_cur) { + if (res_cur->rangeno >= res->rangeno) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + /* at the end of the resource list */ + debug ("i should be here, [%x - %x]\n", res->start, res->end); + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = NULL; + } else if (res_cur->rangeno == res->rangeno) { + /* in the same range */ + while (res_cur) { + if (res->start < res_cur->start) + break; + res_prev = res_cur; + res_cur = res_cur->next; + } + if (!res_cur) { + /* the last resource in this range */ + res_prev->next = res; + res->next = NULL; + res->nextRange = res_prev->nextRange; + res_prev->nextRange = NULL; + } else if (res->start < res_cur->start) { + /* at the beginning or middle of the range */ + if (!res_prev) { + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + } else if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res; + else + res_prev->nextRange = res; + + res->next = res_cur; + res->nextRange = NULL; + } + } else { + /* this is the case where it is 1st occurence of the range */ + if (!res_prev) { + /* at the beginning of the resource list */ + res->next = NULL; + switch (res->type) { + case IO: + res->nextRange = bus_cur->firstIO; + bus_cur->firstIO = res; + break; + case MEM: + res->nextRange = bus_cur->firstMem; + bus_cur->firstMem = res; + break; + case PFMEM: + res->nextRange = bus_cur->firstPFMem; + bus_cur->firstPFMem = res; + break; + } + } else if (res_cur->rangeno > res->rangeno) { + /* in the middle of the resource list */ + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = res_cur; + } + } + } + + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/**************************************************************************** + * This routine will remove the resource from the list of resources + * + * Input: io, mem, and/or pfmem resource to be deleted + * Ouput: modified resource list + * 0 or error code + ****************************************************************************/ +int ibmphp_remove_resource (struct resource_node *res) +{ + struct bus_node *bus_cur; + struct resource_node *res_cur = NULL; + struct resource_node *res_prev; + struct resource_node *mem_cur; + char * type = ""; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find corresponding bus of the io resource to remove " + "bailing out...\n"); + return -ENODEV; + } + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus_cur->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + type = "pfmem"; + break; + default: + err ("unknown type for resource to remove \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + /* ???????????DO WE _NEED_ TO BE CHECKING FOR END AS WELL?????????? */ + if ((res_cur->start == res->start) && (res_cur->end == res->end)) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (res->type == PFMEM) { + /* + * case where pfmem might be in the PFMemFromMem list + * so will also need to remove the corresponding mem + * entry + */ + res_cur = bus_cur->firstPFMemFromMem; + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) { + mem_cur = bus_cur->firstMem; + while (mem_cur) { + if ((mem_cur->start == res_cur->start) + && (mem_cur->end == res_cur->end)) + break; + if (mem_cur->next) + mem_cur = mem_cur->next; + else + mem_cur = mem_cur->nextRange; + } + if (!mem_cur) { + err ("cannot find corresponding mem node for pfmem...\n"); + return -EINVAL; + } + + ibmphp_remove_resource (mem_cur); + if (!res_prev) + bus_cur->firstPFMemFromMem = res_cur->next; + else + res_prev->next = res_cur->next; + kfree (res_cur); + return 0; + } + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + if (!res_cur) { + err ("cannot find pfmem to delete...\n"); + return -EINVAL; + } + } else { + err ("the %s resource is not in the list to be deleted...\n", type); + return -EINVAL; + } + } + if (!res_prev) { + /* first device to be deleted */ + if (res_cur->next) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->next; + break; + case MEM: + bus_cur->firstMem = res_cur->next; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->next; + break; + } + } else if (res_cur->nextRange) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->nextRange; + break; + case MEM: + bus_cur->firstMem = res_cur->nextRange; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->nextRange; + break; + } + } else { + switch (res->type) { + case IO: + bus_cur->firstIO = NULL; + break; + case MEM: + bus_cur->firstMem = NULL; + break; + case PFMEM: + bus_cur->firstPFMem = NULL; + break; + } + } + kfree (res_cur); + return 0; + } else { + if (res_cur->next) { + if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res_cur->next; + else + res_prev->nextRange = res_cur->next; + } else if (res_cur->nextRange) { + res_prev->next = NULL; + res_prev->nextRange = res_cur->nextRange; + } else { + res_prev->next = NULL; + res_prev->nextRange = NULL; + } + kfree (res_cur); + return 0; + } + + return 0; +} + +static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +{ + struct range_node * range = NULL; + + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + default: + err ("cannot read resource type in find_range \n"); + } + + while (range) { + if (res->rangeno == range->rangeno) + break; + range = range->next; + } + return range; +} + +/***************************************************************************** + * This routine will check to make sure the io/mem/pfmem->len that the device asked for + * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, + * otherwise, returns 0 + * + * Input: resource + * Ouput: the correct start and end address are inputted into the resource node, + * 0 or -EINVAL + *****************************************************************************/ +int ibmphp_check_resource (struct resource_node *res, u8 bridge) +{ + struct bus_node *bus_cur; + struct range_node *range = NULL; + struct resource_node *res_prev; + struct resource_node *res_cur = NULL; + u32 len_cur = 0, start_cur = 0, len_tmp = 0; + int noranges = 0; + u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ + u32 tmp_divide; + u8 flag = FALSE; + + if (!res) + return -EINVAL; + + if (bridge) { + /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ + if (res->type == IO) + tmp_divide = IOBRIDGE; + else + tmp_divide = MEMBRIDGE; + } else + tmp_divide = res->len; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + err ("no bus in the system, either pci_dev's wrong or allocation failed \n"); + return -EINVAL; + } + + debug ("%s - enter\n", __FUNCTION__); + debug ("bus_cur->busno is %d\n", bus_cur->busno); + + /* This is a quick fix to not mess up with the code very much. i.e., + * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ + res->len -= 1; + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + noranges = bus_cur->noIORanges; + break; + case MEM: + res_cur = bus_cur->firstMem; + noranges = bus_cur->noMemRanges; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + noranges = bus_cur->noPFMemRanges; + break; + default: + err ("wrong type of resource to check \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + range = find_range (bus_cur, res_cur); + debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); + + if (!range) { + err ("no range for the device exists... bailing out...\n"); + return -EINVAL; + } + + /* found our range */ + if (!res_prev) { + /* first time in the loop */ + if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + debug ("but we are not here, right?\n"); + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + if (!res_cur->next) { + /* last device on the range */ + if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if (((res_cur->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_cur->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_cur->end + 1; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + + if (res_prev) { + if (res_prev->rangeno != res_cur->rangeno) { + /* 1st device on this range */ + if ((res_cur->start != range->start) && + ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } else { + /* in the same range */ + if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if (((res_prev->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_prev->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_prev->end + 1; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + } + /* end if (res_prev) */ + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } /* end of while */ + + + if (!res_prev) { + /* 1st device ever */ + /* need to find appropriate range */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + + if (!res_cur) { + debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); + if (res_prev->rangeno < noranges) { + /* if there're more ranges out there to check */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } else { + /* no more ranges to check on */ + if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } else { + /* have gone through the list of devices and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } + } + } /* end if(!res_cur) */ + return -EINVAL; +} + +/******************************************************************************** + * This routine is called from remove_card if the card contained PPB. + * It will remove all the resources on the bus as well as the bus itself + * Input: Bus + * Ouput: 0, -ENODEV + ********************************************************************************/ +int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) +{ + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct bus_node *prev_bus; + int rc; + + prev_bus = find_bus_wprev (parent_busno, NULL, 0); + + if (!prev_bus) { + err ("something terribly wrong. Cannot find parent bus to the one to remove\n"); + return -ENODEV; + } + + debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); + + rc = remove_ranges (bus, prev_bus); + if (rc) + return rc; + + if (bus->firstIO) { + res_cur = bus->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstIO = NULL; + } + if (bus->firstMem) { + res_cur = bus->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstMem = NULL; + } + if (bus->firstPFMem) { + res_cur = bus->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMem = NULL; + } + + if (bus->firstPFMemFromMem) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMemFromMem = NULL; + } + + list_del (&bus->bus_list); + kfree (bus); + return 0; +} + +/****************************************************************************** + * This routine deletes the ranges from a given bus, and the entries from the + * parent's bus in the resources + * Input: current bus, previous bus + * Output: 0, -EINVAL + ******************************************************************************/ +static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) +{ + struct range_node *range_cur; + struct range_node *range_tmp; + int i; + struct resource_node *res = NULL; + + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) + return -EINVAL; + ibmphp_remove_resource (res); + + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeIO = NULL; + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeMem = NULL; + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangePFMem = NULL; + } + return 0; +} + +/* + * find the resource node in the bus + * Input: Resource needed, start address of the resource, type or resource + */ +int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) +{ + struct resource_node *res_cur = NULL; + char * type = ""; + + switch (flag) { + case IO: + res_cur = bus->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus->firstPFMem; + type = "pfmem"; + break; + default: + err ("wrong type of flag \n"); + return -EINVAL; + } + + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (flag == PFMEM) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + res_cur = res_cur->next; + } + if (!res_cur) { + err ("SOS...cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } else { + err ("SOS... cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } + + if (*res) + debug ("*res->start = %x \n", (*res)->start); + + return 0; +} + +/*********************************************************************** + * This routine will free the resource structures used by the + * system. It is called from cleanup routine for the module + * Parameters: none + * Returns: none + ***********************************************************************/ +void ibmphp_free_resources (void) +{ + struct bus_node *bus_cur = NULL; + struct bus_node *bus_tmp; + struct range_node *range_cur; + struct range_node *range_tmp; + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct list_head *tmp; + struct list_head *next; + int i = 0; + flags = 1; + + list_for_each_safe (tmp, next, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + + if (bus_cur->firstIO) { + res_cur = bus_cur->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstIO = NULL; + } + if (bus_cur->firstMem) { + res_cur = bus_cur->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstMem = NULL; + } + if (bus_cur->firstPFMem) { + res_cur = bus_cur->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMem = NULL; + } + + if (bus_cur->firstPFMemFromMem) { + res_cur = bus_cur->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMemFromMem = NULL; + } + + bus_tmp = bus_cur; + list_del (&bus_cur->bus_list); + kfree (bus_tmp); + bus_tmp = NULL; + } +} + +/********************************************************************************* + * This function will go over the PFmem resources to check if the EBDA allocated + * pfmem out of memory buckets of the bus. If so, it will change the range numbers + * and a flag to indicate that this resource is out of memory. It will also move the + * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create + * a new Mem node + * This routine is called right after initialization + *******************************************************************************/ +static int once_over (void) +{ + struct resource_node *pfmem_cur; + struct resource_node *pfmem_prev; + struct resource_node *mem; + struct bus_node *bus_cur; + struct list_head *tmp; + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { + for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { + pfmem_cur->fromMem = TRUE; + if (pfmem_prev) + pfmem_prev->next = pfmem_cur->next; + else + bus_cur->firstPFMem = pfmem_cur->next; + + if (!bus_cur->firstPFMemFromMem) + pfmem_cur->next = NULL; + else + /* we don't need to sort PFMemFromMem since we're using mem node for + all the real work anyways, so just insert at the beginning of the + list + */ + pfmem_cur->next = bus_cur->firstPFMemFromMem; + + bus_cur->firstPFMemFromMem = pfmem_cur; + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = pfmem_cur->busno; + mem->devfunc = pfmem_cur->devfunc; + mem->start = pfmem_cur->start; + mem->end = pfmem_cur->end; + mem->len = pfmem_cur->len; + if (ibmphp_add_resource (mem) < 0) + err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); + pfmem_cur->rangeno = mem->rangeno; + } /* end for pfmem */ + } /* end if */ + } /* end list_for_each bus */ + return 0; +} + +int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) +{ + struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find bus of pfmem to add...\n"); + return -ENODEV; + } + + if (bus_cur->firstPFMemFromMem) + pfmem->next = bus_cur->firstPFMemFromMem; + else + pfmem->next = NULL; + + bus_cur->firstPFMemFromMem = pfmem; + + return 0; +} + +/* This routine just goes through the buses to see if the bus already exists. + * It is called from ibmphp_find_sec_number, to find out a secondary bus number for + * bridged cards + * Parameters: bus_number + * Returns: Bus pointer or NULL + */ +struct bus_node *ibmphp_find_res_bus (u8 bus_number) +{ + return find_bus_wprev (bus_number, NULL, 0); +} + +static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) +{ + struct bus_node *bus_cur; + struct list_head *tmp; + struct list_head *tmp_prev; + + list_for_each (tmp, &gbuses) { + tmp_prev = tmp->prev; + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (flag) + *prev = list_entry (tmp_prev, struct bus_node, bus_list); + if (bus_cur->busno == bus_number) + return bus_cur; + } + + return NULL; +} + +void ibmphp_print_test (void) +{ + int i = 0; + struct bus_node *bus_cur = NULL; + struct range_node *range; + struct resource_node *res; + struct list_head *tmp; + + if ((!list_empty(&gbuses)) && flags) { + err ("The GBUSES is not NULL?!?!?!?!?\n"); + return; + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + debug ("This is bus # %d. There are \n", bus_cur->busno); + debug ("IORanges = %d\t", bus_cur->noIORanges); + debug ("MemRanges = %d\t", bus_cur->noMemRanges); + debug ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); + debug ("The IO Ranges are as follows:\n"); + if (bus_cur->rangeIO) { + range = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The Mem Ranges are as follows:\n"); + if (bus_cur->rangeMem) { + range = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The PFMem Ranges are as follows:\n"); + + if (bus_cur->rangePFMem) { + range = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The resources on this bus are as follows\n"); + + debug ("IO...\n"); + if (bus_cur->firstIO) { + res = bus_cur->firstIO; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug ("Mem...\n"); + if (bus_cur->firstMem) { + res = bus_cur->firstMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug ("PFMem...\n"); + if (bus_cur->firstPFMem) { + res = bus_cur->firstPFMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + + debug ("PFMemFromMem...\n"); + if (bus_cur->firstPFMemFromMem) { + res = bus_cur->firstPFMemFromMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + res = res->next; + } + } + } +} + +/* This routine will read the windows for any PPB we have and update the + * range info for the secondary bus, and will also input this info into + * primary bus, since BIOS doesn't. This is for PPB that are in the system + * on bootup + * Input: primary busno + * Returns: none + * Note: this function doesn't take into account IO restrictions etc, + * so will only work for bridges with no video/ISA devices behind them It + * also will not work for onboard PPB's that can have more than 1 *bus + * behind them All these are TO DO. + * Also need to add more error checkings... (from fnc returns etc) + */ +static int update_bridge_ranges (struct bus_node **bus) +{ + u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address; + u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; + u32 start_address, end_address, upper_start, upper_end; + struct bus_node *bus_sec; + struct bus_node *bus_cur; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct range_node *range; + bus_cur = *bus; + busno = bus_cur->busno; + + debug ("inside update_bridge_ranges \n"); + debug ("bus_cur->busno = %x\n", bus_cur->busno); + + for (device = 0; device < 32; device++) { + for (function = 0x00; function < 0x08; function++) { + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + break; + case PCI_HEADER_TYPE_BRIDGE: + function = 0x8; + case PCI_HEADER_TYPE_MULTIBRIDGE: + /* We assume here that only 1 bus behind the bridge + TO DO: add functionality for several: + temp = secondary; + while (temp < subordinate) { + ... + temp++; + } + */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_busno); + bus_sec = find_bus_wprev (sec_busno, NULL, 0); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE, &start_io_address); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT, &end_io_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE_UPPER16, &upper_io_start); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT_UPPER16, &upper_io_end); + start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; + start_address |= (upper_io_start << 16); + end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; + end_address |= (upper_io_end << 16); + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfff; + + if (bus_sec->noIORanges > 0) + add_range (IO, range, bus_sec); + else { + /* 1st IO Range on the bus */ + range->rangeno = 1; + bus_sec->rangeIO = range; + } + + ++bus_sec->noIORanges; + fix_resources (bus_sec); + + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!io) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = bus_cur->busno; + io->devfunc = ((device << 3) | (function & 0x7)); + io->start = start_address; + io->end = end_address + 0xfff; + io->len = io->end - io->start + 1; + + ibmphp_add_resource (io); + } + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_BASE, &start_mem_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_LIMIT, &end_mem_address); + + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noMemRanges > 0) + add_range (MEM, range, bus_sec); + else { + /* 1st Mem Range on the bus */ + range->rangeno = 1; + bus_sec->rangeMem = range; + } + + ++bus_sec->noMemRanges; + fix_resources (bus_sec); + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = bus_cur->busno; + mem->devfunc = ((device << 3) | (function & 0x7)); + mem->start = start_address; + mem->end = end_address + 0xfffff; + mem->len = mem->end - mem->start + 1; + ibmphp_add_resource (mem); + } + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_BASE, &start_mem_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_LIMIT, &end_mem_address); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_BASE_UPPER32, &upper_start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_LIMIT_UPPER32, &upper_end); + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; +#if BITS_PER_LONG == 64 + start_address |= ((long) upper_start) << 32; + end_address |= ((long) upper_end) << 32; +#endif + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noPFMemRanges > 0) + add_range (PFMEM, range, bus_sec); + else { + /* 1st PFMem Range on the bus */ + range->rangeno = 1; + bus_sec->rangePFMem = range; + } + + ++bus_sec->noPFMemRanges; + fix_resources (bus_sec); + + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = bus_cur->busno; + pfmem->devfunc = ((device << 3) | (function & 0x7)); + pfmem->start = start_address; + pfmem->end = end_address + 0xfffff; + pfmem->len = pfmem->end - pfmem->start + 1; + pfmem->fromMem = FALSE; + ibmphp_add_resource (pfmem); + } + break; + } /* end of switch */ + } /* end if vendor */ + } /* end for function */ + } /* end for device */ + + bus = &bus_cur; + return 0; +} diff -urN linux-2.4.18/drivers/hotplug/pci_hotplug_core.c linux-2.4.19-pre5/drivers/hotplug/pci_hotplug_core.c --- linux-2.4.18/drivers/hotplug/pci_hotplug_core.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/hotplug/pci_hotplug_core.c Sat Mar 30 22:55:28 2002 @@ -1,8 +1,8 @@ /* * PCI HotPlug Controller Core * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. * * All rights reserved. * @@ -23,6 +23,8 @@ * * Send feedback to * + * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * */ #include @@ -54,7 +56,7 @@ /* local variables */ static int debug; -#define DRIVER_VERSION "0.3" +#define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "PCI Hot Plug PCI Core" @@ -74,7 +76,6 @@ }; static struct super_operations pcihpfs_ops; -static struct address_space_operations pcihpfs_aops; static struct file_operations pcihpfs_dir_operations; static struct file_operations default_file_operations; static struct inode_operations pcihpfs_dir_inode_operations; @@ -111,7 +112,6 @@ inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; - inode->i_mapping->a_ops = &pcihpfs_aops; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: @@ -152,21 +152,6 @@ return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0); } -static int pcihpfs_link (struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = old_dentry->d_inode; - - if(S_ISDIR(inode->i_mode)) - return -EPERM; - - inode->i_nlink++; - atomic_inc(&inode->i_count); - dget(dentry); - d_instantiate(dentry, inode); - return 0; -} - static inline int pcihpfs_positive (struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); @@ -204,22 +189,6 @@ return error; } -static int pcihpfs_rename (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - int error = -ENOTEMPTY; - - if (pcihpfs_empty(new_dentry)) { - struct inode *inode = new_dentry->d_inode; - if (inode) { - inode->i_nlink--; - dput(new_dentry); - } - error = 0; - } - return error; -} - #define pcihpfs_rmdir pcihpfs_unlink /* default file operations */ @@ -266,18 +235,9 @@ return 0; } -static int default_sync_file (struct file *file, struct dentry *dentry, int datasync) -{ - return 0; -} - -static struct address_space_operations pcihpfs_aops = { -}; - static struct file_operations pcihpfs_dir_operations = { read: generic_read_dir, readdir: dcache_readdir, - fsync: default_sync_file, }; static struct file_operations default_file_operations = { @@ -285,8 +245,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "power" files */ @@ -297,8 +255,6 @@ write: power_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "attention" files */ @@ -309,8 +265,6 @@ write: attention_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "latch" files */ @@ -320,8 +274,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "presence" files */ @@ -331,8 +283,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "test" files */ @@ -342,19 +292,15 @@ write: test_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; static struct inode_operations pcihpfs_dir_inode_operations = { create: pcihpfs_create, lookup: pcihpfs_lookup, - link: pcihpfs_link, unlink: pcihpfs_unlink, mkdir: pcihpfs_mkdir, rmdir: pcihpfs_rmdir, mknod: pcihpfs_mknod, - rename: pcihpfs_rename, }; static struct super_operations pcihpfs_ops = { @@ -475,7 +421,7 @@ if (!parent) { dbg("Ah! can not find a parent!\n"); - return -EFAULT; + return -EINVAL; } *dentry = NULL; @@ -676,7 +622,7 @@ default: err ("Illegal value specified for power\n"); - retval = -EFAULT; + retval = -EINVAL; } exit: @@ -1009,7 +955,7 @@ if (slot == NULL) return -ENODEV; if ((slot->info == NULL) || (slot->ops == NULL)) - return -EFAULT; + return -EINVAL; core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL); if (!core) @@ -1020,7 +966,7 @@ if (get_slot_from_name (slot->name) != NULL) { spin_unlock (&list_lock); kfree (core); - return -EFAULT; + return -EINVAL; } slot->core_priv = core; @@ -1066,6 +1012,12 @@ return 0; } +static inline void update_inode_time (struct inode *inode) +{ + if (inode) + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + /** * pci_hp_change_slot_info - changes the slot's information structure in the core * @name: the name of the slot whose info has changed @@ -1079,6 +1031,7 @@ int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info) { struct hotplug_slot *temp; + struct hotplug_slot_core *core; if (info == NULL) return -ENODEV; @@ -1089,6 +1042,24 @@ spin_unlock (&list_lock); return -ENODEV; } + + /* + * check all fields in the info structure, and update timestamps + * for the files referring to the fields that have now changed. + */ + core = temp->core_priv; + if ((core->power_dentry) && + (temp->info->power_status != info->power_status)) + update_inode_time (core->power_dentry->d_inode); + if ((core->attention_dentry) && + (temp->info->attention_status != info->attention_status)) + update_inode_time (core->attention_dentry->d_inode); + if ((core->latch_dentry) && + (temp->info->latch_status != info->latch_status)) + update_inode_time (core->latch_dentry->d_inode); + if ((core->adapter_dentry) && + (temp->info->adapter_status != info->adapter_status)) + update_inode_time (core->adapter_dentry->d_inode); memcpy (temp->info, info, sizeof (struct hotplug_slot_info)); spin_unlock (&list_lock); diff -urN linux-2.4.18/drivers/hotplug/pcihp_acpi.c linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi.c --- linux-2.4.18/drivers/hotplug/pcihp_acpi.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,397 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" +#include "pcihp_acpi.h" + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) + #define MY_NAME "pcihp_acpi" +#else + #define MY_NAME THIS_MODULE->name +#endif + +/* local variables */ +static int debug = 1; /* XXX */ +static int num_slots; + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops acpi_hotplug_slot_ops = { + owner: THIS_MODULE, + enable_slot: enable_slot, + disable_slot: disable_slot, + set_attention_status: set_attention_status, + hardware_test: hardware_test, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_status, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + retval = pcihp_acpi_enable_slot (slot->acpi_slot); + + return retval; +} + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* disable the specified slot */ + retval = pcihp_acpi_disable_slot (slot->acpi_slot); + + return retval; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* TBD + * ACPI doesn't have known method to manipulate + * attention status LED + */ + switch (status) { + case 0: + /* FIXME turn light off */ + slot->attention_status = 0; + break; + + case 1: + default: + /* FIXME turn light on */ + slot->attention_status = 1; + break; + } + + return retval; +} + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + err ("No hardware tests are defined for this driver"); + retval = -ENODEV; + + return retval; +} + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_power_status (slot->acpi_slot); + + return retval; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = slot->attention_status; + + return retval; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_latch_status (slot->acpi_slot); + + return retval; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_adapter_status (slot->acpi_slot); + + return retval; +} + +static int init_acpi (void) +{ + int retval; + + dbg("init_acpi"); /* XXX */ + /* initialize internal data structure etc. */ + retval = pcihp_acpi_glue_init(); + + /* read initial number of slots */ + if (!retval) { + num_slots = pcihp_acpi_get_num_slots(); + if (num_slots == 0) + retval = -ENODEV; + } + + return retval; +} + +static void exit_acpi (void) +{ + /* deallocate internal data structures etc. */ + pcihp_acpi_glue_exit(); +} + +#define SLOT_NAME_SIZE 10 +static void make_slot_name (struct slot *slot) +{ + /* FIXME - get this from the ACPI representation of the slot */ + snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d", slot->number); +} + +static int init_slots (void) +{ + struct slot *slot; + int retval = 0; + int i; + + for (i = 0; i < num_slots; ++i) { + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) { + kfree (slot); + return -ENOMEM; + } + memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!slot->hotplug_slot->info) { + kfree (slot->hotplug_slot); + kfree (slot); + return -ENOMEM; + } + memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + + slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!slot->hotplug_slot->name) { + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot); + kfree (slot); + return -ENOMEM; + } + + slot->magic = SLOT_MAGIC; + slot->number = i; + + slot->hotplug_slot->private = slot; + make_slot_name (slot); + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + + slot->acpi_slot = get_slot_from_id (i); + slot->hotplug_slot->info->power_status = pcihp_acpi_get_power_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = pcihp_acpi_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->latch_status = pcihp_acpi_get_latch_status(slot->acpi_slot); + slot->hotplug_slot->info->adapter_status = pcihp_acpi_get_adapter_status(slot->acpi_slot); + + dbg ("registering slot %d", i); + retval = pci_hp_register (slot->hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d", retval); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + return retval; + } + + /* add slot to our internal list */ + list_add (&slot->slot_list, &slot_list); + } + + return retval; +} + +static void cleanup_slots (void) +{ + struct list_head *tmp; + struct slot *slot; + + list_for_each (tmp, &slot_list) { + slot = list_entry (tmp, struct slot, slot_list); + list_del (&slot->slot_list); + pci_hp_deregister (slot->hotplug_slot); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + } + + return; +} + +static int __init pcihp_acpi_init(void) +{ + int retval; + + /* read all the ACPI info from the system */ + retval = init_acpi(); + if (retval) + return retval; + + retval = init_slots(); + if (retval) + return retval; + + info (DRIVER_DESC " version: " DRIVER_VERSION); + return 0; +} + +static void __exit pcihp_acpi_exit(void) +{ + cleanup_slots(); + exit_acpi(); +} + +module_init(pcihp_acpi_init); +module_exit(pcihp_acpi_exit); diff -urN linux-2.4.18/drivers/hotplug/pcihp_acpi.h linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi.h --- linux-2.4.18/drivers/hotplug/pcihp_acpi.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi.h Sat Mar 30 22:55:28 2002 @@ -0,0 +1,231 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#ifndef _PCIHP_ACPI_H +#define _PCIHP_ACPI_H + +#include "include/acpi.h" + +#if ACPI_CA_VERSION < 0x20020201 +/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */ +#define acpi_util_eval_error(h,p,s) + +static acpi_status +acpi_evaluate_integer ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + unsigned long *data) +{ + acpi_status status = AE_OK; + acpi_object element; + acpi_buffer buffer = {sizeof(acpi_object), &element}; + + if (!data) + return AE_BAD_PARAMETER; + + status = acpi_evaluate_object(handle, pathname, arguments, &buffer); + if (ACPI_FAILURE(status)) { + acpi_util_eval_error(handle, pathname, status); + return status; + } + + if (element.type != ACPI_TYPE_INTEGER) { + acpi_util_eval_error(handle, pathname, AE_BAD_DATA); + return AE_BAD_DATA; + } + + *data = element.integer.value; + + return AE_OK; +} +#else /* ACPI_CA_VERSION < 0x20020201 */ +#include "acpi_bus.h" +#endif /* ACPI_CA_VERSION < 0x20020201 */ + +/* compatibility stuff */ +#ifndef ACPI_MEMORY_RANGE +#define ACPI_MEMORY_RANGE MEMORY_RANGE +#endif + +#ifndef ACPI_IO_RANGE +#define ACPI_IO_RANGE IO_RANGE +#endif + +#ifndef ACPI_BUS_NUMBER_RANGE +#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE +#endif + +#ifndef ACPI_PREFETCHABLE_MEMORY +#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY +#endif + +#ifndef ACPI_PRODUCER +#define ACPI_PRODUCER PRODUCER +#endif + + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* + * types and constants + */ + +#define SLOT_MAGIC 0x67267322 + +struct pcihp_acpi_bridge; +struct pcihp_acpi_slot; + +/* slot information for each *physical* slot */ + +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; + + int attention_status; + + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + + /* if there are multiple corresponding slot objects, + this point to one of them */ + struct pcihp_acpi_slot *acpi_slot; + + struct pci_dev *pci_dev; +}; + +#define RESOURCE_TYPE_IO (1) +#define RESOURCE_TYPE_MEM (2) +#define RESOURCE_TYPE_PREFETCH (3) +#define RESOURCE_TYPE_BUS (4) + +/* TBD 64bit resource support */ +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +/* bridge information for each bridge device in ACPI namespace */ + +struct pcihp_acpi_bridge { + struct list_head list; + acpi_handle handle; + struct pcihp_acpi_slot *slots; + int nr_slots; + u8 seg; + u8 bus; + u8 sub; + u32 status; + u32 flags; + + /* resources on this bus (free resources) */ + struct pci_resource *free_io; + struct pci_resource *free_mem; + struct pci_resource *free_prefetch; + struct pci_resource *free_bus; + + /* used resources (embedded or owned resources) */ + struct pci_resource *used_io; + struct pci_resource *used_mem; + struct pci_resource *used_prefetch; + struct pci_resource *used_bus; +}; + +/* + * slot information for each slot object in ACPI namespace + * usually 8 objects per slot (for each PCI function) + */ + +struct pcihp_acpi_slot { + struct pcihp_acpi_slot *next; + struct pcihp_acpi_bridge *bridge; /* this slot located on */ + struct list_head sibling; /* one slot may have different + objects (i.e. for each function) */ + acpi_handle handle; + u32 id; /* slot id (this driver specific) */ + u8 device; /* pci device# */ + u8 function; /* pci function# */ + u8 pin; /* pci interrupt pin */ + u32 sun; /* _SUN */ + u32 flags; /* see below */ + u32 status; /* _STA */ +}; + +/* PCI bus bridge HID */ +#define ACPI_PCI_ROOT_HID "PNP0A03" + +/* ACPI _STA method value (ignore bit 4; battery present) */ +#define ACPI_STA_PRESENT (0x00000001) +#define ACPI_STA_ENABLED (0x00000002) +#define ACPI_STA_SHOW_IN_UI (0x00000004) +#define ACPI_STA_FUNCTIONAL (0x00000008) +#define ACPI_STA_ALL (0x0000000f) + +/* bridge flags */ +#define BRIDGE_HAS_STA (0x00000001) + +/* slot flags */ + +#define SLOT_HAS_EJ0 (0x00000001) +#define SLOT_HAS_PS0 (0x00000002) +#define SLOT_HAS_PS3 (0x00000004) + +/* function prototypes */ + +/* pcihp_acpi_glue.c */ +extern int pcihp_acpi_glue_init (void); +extern void pcihp_acpi_glue_exit (void); +extern int pcihp_acpi_get_num_slots (void); +extern struct pcihp_acpi_slot *get_slot_from_id (int id); + +extern int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot); +extern int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot); + +#endif /* _PCIHP_ACPI_H */ diff -urN linux-2.4.18/drivers/hotplug/pcihp_acpi_ctrl.c linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi_ctrl.c --- linux-2.4.18/drivers/hotplug/pcihp_acpi_ctrl.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi_ctrl.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,642 @@ +/* + * ACPI PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define _LINUX /* for acpi subcomponent */ + +#include "include/acpi.h" + +#include "pci_hotplug.h" +#include "pchihp_acpi.h" + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_WARNING "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug = 0; + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +struct pci_resource *hotplug_get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (hotplug_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n", + size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg(__FUNCTION__": not aligned\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg(__FUNCTION__": too big\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(__FUNCTION__": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + +/* + * get_resource_with_base + * + * this function + * returns the first node of "size" length located at specified base address. + * If it finds a node larger than "size" it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_resource_with_base (struct pci_resource **head, u32 base, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + base, size, node, node->base, node->length); + if (node->base > base) + continue; + + if ((node->base + node->length) < (base + size)) + continue; + + if (node->base < base) { + dbg(": split 1\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = base; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } + + dbg(": 2st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + base, size, node, node->base, node->length); + + // Don't need to check if too small since we already did + if (node->length >= size) { + dbg(": split 2\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + +/* + * hotplug_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int hotplug_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + +/* +EXPORT_SYMBOL(hotplug_get_io_resource); +EXPORT_SYMBOL(hotplug_get_max_resource); +EXPORT_SYMBOL(hotplug_get_resource); +EXPORT_SYMBOL(hotplug_resource_sort_and_combine); +*/ diff -urN linux-2.4.18/drivers/hotplug/pcihp_acpi_glue.c linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi_glue.c --- linux-2.4.18/drivers/hotplug/pcihp_acpi_glue.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/hotplug/pcihp_acpi_glue.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,757 @@ +/* + * ACPI PCI HotPlug glue functions to ACPI CA subsystem + * + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include "pcihp_acpi.h" + +/* + * TODO: + * resource management + * irq related interface? (_PRT) + * consider locking + */ + +static LIST_HEAD(bridge_list); + +static int debug = 1; /* XXX set 0 after debug */ +#define MY_NAME "pcihp_acpi_glue" + +static void handle_hotplug_event (acpi_handle, u32, void *); + +/* + * initialization & terminatation routines + */ + +/* + * Ejectable slot satisfies at least these conditions: + * 1. has _ADR method + * 2. has _STA method + * 3. has _EJ0 method + * + * optionally + * 1. has _PS0 method + * 2. has _PS3 method + * 3. TBD... + */ + +/* callback routine to check the existence of ejectable slots */ +static acpi_status +is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle tmp; + int *count = (int *)context; + + status = acpi_get_handle(handle, "_ADR", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_STA", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + (*count)++; + + /* only one ejectable slot is enough */ + return AE_CTRL_TERMINATE; +} + + +/* callback routine to register each ACPI PCI slot object */ +static acpi_status +register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct pcihp_acpi_bridge *bridge = (struct pcihp_acpi_bridge *)context; + struct pcihp_acpi_slot *slot, *newslot; + acpi_handle tmp; + acpi_status status = AE_OK; + static int num_slots = 0; /* XXX */ + unsigned long adr, sun, sta; + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) { + dbg("This slot doesn't have _EJ0"); + //return AE_OK; + } + + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + + if (ACPI_FAILURE(status)) { + dbg("This slot doesn't have _STA"); + //return AE_OK; + } + + newslot = kmalloc(sizeof(struct pcihp_acpi_slot), GFP_KERNEL); + if (!newslot) { + return AE_NO_MEMORY; + } + + memset(newslot, 0, sizeof(struct pcihp_acpi_slot)); + + INIT_LIST_HEAD(&newslot->sibling); + newslot->bridge = bridge; + newslot->handle = handle; + newslot->device = (adr >> 16) & 0xffff; + newslot->function = adr & 0xffff; + newslot->status = sta; + newslot->sun = -1; + newslot->flags = SLOT_HAS_EJ0; + newslot->id = num_slots++; + bridge->nr_slots++; + + dbg("new slot id=%d device=0x%d function=0x%x", newslot->id, newslot->device, newslot->function); + + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_SUCCESS(status)) { + newslot->sun = sun; + } + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) { + newslot->flags |= SLOT_HAS_PS0; + } + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) { + newslot->flags |= SLOT_HAS_PS3; + } + + /* search for objects that share the same slot */ + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->device == newslot->device) { + dbg("found a sibling slot!"); + list_add(&slot->sibling, &newslot->sibling); + newslot->id = slot->id; + num_slots --; + bridge->nr_slots --; + break; + } + + /* link myself to bridge's slot list */ + newslot->next = bridge->slots; + bridge->slots = newslot; + + return AE_OK; +} + +/* see if it's worth managing this brige */ +static int +detect_ejectable_slots (acpi_handle *root) +{ + acpi_status status; + int count; + + count = 0; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root, ACPI_UINT32_MAX, + is_ejectable_slot, (void *)&count, NULL); + + dbg("%s: count=%d", __FUNCTION__, count); + return count; +} + + +/* + * push one resource to resource list + * + * TBD: use hotplug_resource_sort_and_combine + * TBD: 64bit resource handling (is it really used?) + */ +static void +push_resource (u32 base, u32 length, struct pci_resource **resource) +{ + struct pci_resource *resp, *newres; + int coalesced = 0; + + if (length == 0) { + dbg("zero sized resource. ignored."); + return; + } + + for (resp = *resource; resp; resp = resp->next) { + + /* coalesce contiguous region */ + + if (resp->base + resp->length == base) { + resp->length += length; + coalesced = 1; + break; + } + } + + if (!coalesced) { + newres = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!newres) { + /* TBD panic? */ + return; + } + newres->base = base; + newres->length = length; + newres->next = (*resource); + *resource = newres; + } +} + + +/* decode ACPI _CRS data and convert into our internal resource list */ +static void +decode_acpi_resource (acpi_resource *resource, struct pcihp_acpi_bridge *bridge) +{ + acpi_resource_address16 *address16_data; + acpi_resource_address32 *address32_data; + //acpi_resource_address64 *address64_data; + + u32 resource_type, producer_consumer, min_address_range, max_address_range, address_length; + u16 cache_attribute = 0; + + int done = 0, found; + + /* shut up gcc */ + resource_type = producer_consumer = min_address_range = max_address_range = address_length = 0; + + while (!done) { + found = 0; + + switch (resource->id) { + case ACPI_RSTYPE_ADDRESS16: + address16_data = (acpi_resource_address16 *)&resource->data; + resource_type = address16_data->resource_type; + producer_consumer = address16_data->producer_consumer; + min_address_range = address16_data->min_address_range; + max_address_range = address16_data->max_address_range; + address_length = address16_data->address_length; + if (resource_type == ACPI_MEMORY_RANGE) + cache_attribute = address16_data->attribute.memory.cache_attribute; + found = 1; + break; + + case ACPI_RSTYPE_ADDRESS32: + address32_data = (acpi_resource_address32 *)&resource->data; + resource_type = address32_data->resource_type; + producer_consumer = address32_data->producer_consumer; + min_address_range = address32_data->min_address_range; + max_address_range = address32_data->max_address_range; + address_length = address32_data->address_length; + if (resource_type == ACPI_MEMORY_RANGE) + cache_attribute = address32_data->attribute.memory.cache_attribute; + found = 1; + break; +/* + case ACPI_RSTYPE_ADDRESS64: + address64_data = (acpi_resource_address64 *)&resource->data; + resource_type = address64_data->resource_type; + break; +*/ + case ACPI_RSTYPE_END_TAG: + done = 1; + break; + + default: + /* ignore */ + break; + } + + resource = (acpi_resource *)((char*)resource + resource->length); + if (found && producer_consumer == ACPI_PRODUCER) { + switch (resource_type) { + case ACPI_MEMORY_RANGE: + if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) { + dbg("resource type: prefetchable memory 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_prefetch); + } else { + dbg("resource type: memory 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_mem); + } + break; + case ACPI_IO_RANGE: + dbg("resource type: io 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_io); + break; + case ACPI_BUS_NUMBER_RANGE: + dbg("resource type: bus number %d - %d", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_bus); + break; + default: + /* invalid type */ + break; + } + } + } +} + + +/* allocate and initialize bridge data structure */ +static int add_bridge (acpi_handle *handle) +{ + struct pcihp_acpi_bridge *bridge; + acpi_status status; + acpi_buffer buffer; + unsigned long tmp; + acpi_handle dummy_handle; + int sta = -1; + + status = acpi_get_handle(handle, "_STA", &dummy_handle); + if (ACPI_SUCCESS(status)) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _STA evaluation failure", __FUNCTION__); + return 0; + } + sta = tmp; + } + + if (sta >= 0 && !(sta & ACPI_STA_PRESENT)) + /* don't register this object */ + return 0; + + dbg("%s: _STA: 0x%x", __FUNCTION__, (unsigned int)sta); + + /* check if this bridge has ejectable slots */ + + detect_ejectable_slots(handle); + //if (detect_ejectable_slots(handle) == 0) + //return 0; + + /* allocate per-bridge data structure and fill in */ + + bridge = kmalloc(sizeof(struct pcihp_acpi_bridge), GFP_KERNEL); + if (bridge == NULL) + return -ENOMEM; + + memset(bridge, 0, sizeof(struct pcihp_acpi_bridge)); + + if (sta >= 0) + bridge->flags |= BRIDGE_HAS_STA; + + /* get PCI segment number */ + status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bridge->seg = tmp; + } else { + bridge->seg = 0; + } + + /* get PCI bus number */ + status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bridge->bus = tmp; + } else { + bridge->bus = 0; + } + + /* to be overridden when we decode _CRS */ + bridge->sub = bridge->bus; + + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, + register_slot, bridge, NULL); + + /* decode resources */ + buffer.length = 0; + buffer.pointer = NULL; + + + /* TBD use new ACPI_ALLOCATE_BUFFER */ + status = acpi_get_current_resources(handle, &buffer); + if (status != AE_BUFFER_OVERFLOW) { + return -1; + } + + buffer.pointer = kmalloc(buffer.length, GFP_KERNEL); + if (!buffer.pointer) { + return -1; + } + + status = acpi_get_current_resources(handle, &buffer); + if (ACPI_FAILURE(status)) { + return -1; + } + + decode_acpi_resource(buffer.pointer, bridge); + + /* TBD decode _HPP (hot plug parameters) */ + // decode_hpp(bridge); + + kfree(buffer.pointer); + + /* check already allocated resources */ + /* TBD */ + + /* install notify handler */ + dbg("installing notify handler"); + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, NULL); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler"); + } + + list_add(&bridge->list, &bridge_list); + + return 0; +} + + +/* callback routine to enumerate all the bridges in ACPI namespace */ +static acpi_status +check_pci_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_device_info info; + char objname[5]; + acpi_buffer buffer = { sizeof(objname), objname }; + + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) { + dbg("%s: failed to get bridge information", __FUNCTION__); + return AE_OK; /* continue */ + } + + info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; + + if (strcmp(info.hardware_id, ACPI_PCI_ROOT_HID) == 0) { + + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + dbg("%s: found PCI root bridge[%s]", __FUNCTION__, objname); + + add_bridge(handle); + } + return AE_OK; +} + + +/* interrupt handler */ +static void handle_hotplug_event (acpi_handle handle, u32 type, void *data) +{ + char objname[5]; + acpi_buffer buffer = { sizeof(objname), objname }; + + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* hot insertion/surprise removal */ + /* TBD */ + dbg("%s: Bus check notify on %s", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* TBD */ + dbg("%s: Device check notify on %s", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* eject button pushed */ + /* TBD */ + dbg("%s: Device eject notify on %s", __FUNCTION__, objname); + break; + + default: + warn("notify_handler: unknown event type 0x%x", type); + break; + } +} + + +/* + * external interfaces + */ + +int pcihp_acpi_glue_init (void) +{ + acpi_status status; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, check_pci_bridge, + NULL, NULL); + + if (ACPI_FAILURE(status)) { + dbg("%s: acpi_walk_namespace() failed", __FUNCTION__); + } + + return 0; +} + +static void free_all_resources (struct pcihp_acpi_bridge *bridge) +{ + struct pci_resource *res, *next;; + + for (res = bridge->free_io; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_mem; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_prefetch; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_bus; res; ) { + next = res->next; + kfree(res); + res = next; + } +} + + +void pcihp_acpi_glue_exit (void) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + struct pcihp_acpi_slot *slot, *next; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + slot = bridge->slots; + while (slot) { + next = slot->next; + kfree(slot); + slot = next; + } + free_all_resources(bridge); + kfree(bridge); + } +} + + +int pcihp_acpi_get_num_slots (void) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + int num_slots; + + num_slots = 0; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + dbg("Bus:%d num_slots:%d", bridge->bus, bridge->nr_slots); + num_slots += bridge->nr_slots; + } + + dbg("num_slots = %d", num_slots); + return num_slots; +} + + +/* TBD: improve performance */ +struct pcihp_acpi_slot *get_slot_from_id (int id) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + struct pcihp_acpi_slot *slot; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->id == id) + return slot; + } + + /* should never happen! */ + dbg("%s: no object for id %d",__FUNCTION__, id); + return 0; +} + + +/* power on slot */ +int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot) +{ + acpi_status status; + + if (slot->flags & SLOT_HAS_PS0) { + dbg("%s: powering on bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_PS0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: powering on bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + return 0; +} + + +/* power off slot */ +int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot) +{ + acpi_status status; + + if (slot->flags & SLOT_HAS_PS3) { + dbg("%s: powering off bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS3 on bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + if (slot->flags & SLOT_HAS_EJ0) { + dbg("%s: eject bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_EJ0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + /* TBD + * evaluate _STA to check if state is successfully changed + * and update status + */ + + return 0; +} + + +static unsigned int get_slot_status(struct pcihp_acpi_slot *slot) +{ + acpi_status status; + unsigned long sta; + + status = acpi_evaluate_integer(slot->handle, "_STA", NULL, &sta); + + if (ACPI_FAILURE(status)) { + err("%s: _STA evaluation failed", __FUNCTION__); + return 0; + } + + return (int)sta; +} + + +/* + * slot enabled: 1 + * slot disabled: 0 + */ +u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * . guarantee check _STA on function# 0 + * . check configuration space before _STA? + */ + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_ENABLED) ? 1 : 0; +} + + +/* XXX this function is not used */ +/* + * attention LED ON: 1 + * OFF: 0 + */ +u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot) +{ + /* TBD + * no direct attention led status information via ACPI + */ + + return 0; +} + + +/* + * latch closed: 1 + * latch open: 0 + */ +u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * no direct latch information via ACPI + */ + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; +} + + +/* + * adapter presence : 2 + * absence : 0 + */ +u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * is this information correct? + */ + + sta = get_slot_status(slot); + + return (sta == 0) ? 0 : 2; +} diff -urN linux-2.4.18/drivers/i2c/i2c-adap-ite.c linux-2.4.19-pre5/drivers/i2c/i2c-adap-ite.c --- linux-2.4.18/drivers/i2c/i2c-adap-ite.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/i2c/i2c-adap-ite.c Sat Mar 30 22:55:28 2002 @@ -241,7 +241,7 @@ }; /* Called when the module is loaded. This function starts the - * cascade of calls up through the heirarchy of i2c modules (i.e. up to the + * cascade of calls up through the hierarchy of i2c modules (i.e. up to the * algorithm layer and into to the core layer) */ static int __init iic_ite_init(void) diff -urN linux-2.4.18/drivers/i2c/i2c-algo-bit.c linux-2.4.19-pre5/drivers/i2c/i2c-algo-bit.c --- linux-2.4.18/drivers/i2c/i2c-algo-bit.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/i2c/i2c-algo-bit.c Sat Mar 30 22:55:34 2002 @@ -49,7 +49,7 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ +#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ if (need_resched) schedule(); */ @@ -117,7 +117,7 @@ * while they are processing data internally. */ setscl(adap,1); - if (start+adap->timeout <= jiffies) { + if (time_after_eq(jiffies, start+adap->timeout)) { return -ETIMEDOUT; } if (current->need_resched) diff -urN linux-2.4.18/drivers/ide/Config.in linux-2.4.19-pre5/drivers/ide/Config.in --- linux-2.4.18/drivers/ide/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/Config.in Sat Mar 30 22:55:39 2002 @@ -14,6 +14,7 @@ dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK + dep_mbool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n dep_mbool ' Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR @@ -32,6 +33,9 @@ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI + bool ' IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL +# bool ' IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO + comment 'IDE chipset support/bugfixes' if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86 @@ -43,14 +47,17 @@ if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI -# bool ' Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI - define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD + dep_bool ' Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL -# dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP + dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP +# dep_bool ' Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL + define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI +# dep_bool ' Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX @@ -59,6 +66,7 @@ dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X dep_bool ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI @@ -72,20 +80,19 @@ dep_mbool ' IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO fi - dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL - dep_bool ' PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI +# dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL + dep_bool ' PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX dep_bool ' Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX dep_bool ' ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 - dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI fi -# dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP - if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi @@ -101,6 +108,9 @@ define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC fi fi + if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + bool ' SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM + fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN dep_bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE @@ -113,7 +123,7 @@ dep_mbool ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL fi if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_mbool ' Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL + dep_mbool ' Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL fi if [ "$CONFIG_ATARI" = "y" ]; then dep_bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI @@ -173,6 +183,7 @@ else define_bool CONFIG_DMA_NONPCI n fi + if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \ "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ diff -urN linux-2.4.18/drivers/ide/Makefile linux-2.4.19-pre5/drivers/ide/Makefile --- linux-2.4.18/drivers/ide/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/Makefile Sat Mar 30 22:55:34 2002 @@ -10,7 +10,7 @@ O_TARGET := idedriver.o -export-objs := ide.o ide-features.o ataraid.o +export-objs := ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o list-multi := ide-mod.o ide-probe-mod.o obj-y := @@ -24,6 +24,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o + obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o ide-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o @@ -48,6 +49,7 @@ ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o +ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM) += ide-swarm.o ide-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o ide-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o ide-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o @@ -69,13 +71,13 @@ # The virtualised raid layers MUST come after the ide itself or bad stuff # will happen. -obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o +obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o obj-$(CONFIG_BLK_DEV_ATARAID_PDC) += pdcraid.o obj-$(CONFIG_BLK_DEV_ATARAID_HPT) += hptraid.o ide-obj-$(CONFIG_PROC_FS) += ide-proc.o -ide-mod-objs := ide.o ide-features.o $(ide-obj-y) +ide-mod-objs := ide.o ide-features.o ide-taskfile.o $(ide-obj-y) ide-probe-mod-objs := ide-probe.o ide-geometry.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/ide/alim15x3.c linux-2.4.19-pre5/drivers/ide/alim15x3.c --- linux-2.4.18/drivers/ide/alim15x3.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/alim15x3.c Sat Mar 30 22:55:34 2002 @@ -453,7 +453,7 @@ } dma_func = ide_dma_off_quietly; if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, can_ultra_dma); if ((id->field_valid & 2) && diff -urN linux-2.4.18/drivers/ide/amd74xx.c linux-2.4.19-pre5/drivers/ide/amd74xx.c --- linux-2.4.18/drivers/ide/amd74xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/amd74xx.c Sat Mar 30 22:55:34 2002 @@ -75,7 +75,8 @@ { unsigned int class_rev; - if (dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) + if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) || + (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441)) return 0; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); @@ -122,8 +123,8 @@ pci_read_config_byte(dev, 0x4c, &pio_timing); #ifdef DEBUG - printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", - drive->name, ultra_timing, dma_pio_timing, pio_timing); + printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing); #endif ultra_timing &= ~0xC7; @@ -131,22 +132,19 @@ pio_timing &= ~(0x03 << drive->dn); #ifdef DEBUG - printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", - ultra_timing, dma_pio_timing, pio_timing); + printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + drive->name, ultra_timing, dma_pio_timing, pio_timing); #endif switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_7: + case XFER_UDMA_6: + speed = XFER_UDMA_5; case XFER_UDMA_5: -#undef __CAN_MODE_5 -#ifdef __CAN_MODE_5 ultra_timing |= 0x46; dma_pio_timing |= 0x20; break; -#else - printk("%s: setting to mode 4, driver problems in mode 5.\n", drive->name); - speed = XFER_UDMA_4; -#endif /* __CAN_MODE_5 */ case XFER_UDMA_4: ultra_timing |= 0x45; dma_pio_timing |= 0x20; @@ -164,7 +162,7 @@ dma_pio_timing |= 0x20; break; case XFER_UDMA_0: - ultra_timing |= 0x42; + ultra_timing |= 0x42; dma_pio_timing |= 0x20; break; case XFER_MW_DMA_2: @@ -222,8 +220,8 @@ pci_write_config_byte(dev, 0x4c, pio_timing); #ifdef DEBUG - printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", - ultra_timing, dma_pio_timing, pio_timing); + printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + drive->name, ultra_timing, dma_pio_timing, pio_timing); #endif #ifdef CONFIG_BLK_DEV_IDEDMA @@ -303,11 +301,15 @@ struct pci_dev *dev = hwif->pci_dev; struct hd_driveid *id = drive->id; byte udma_66 = eighty_ninty_three(drive); - byte udma_100 = (dev->device==PCI_DEVICE_ID_AMD_VIPER_7411) ? 1 : 0; + byte udma_100 = ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)|| + (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0; byte speed = 0x00; int rval; - if ((id->dma_ultra & 0x0020) && (udma_66)&& (udma_100)) { + if (udma_100) + udma_66 = eighty_ninty_three(drive); + + if ((id->dma_ultra & 0x0020) && (udma_66) && (udma_100)) { speed = XFER_UDMA_5; } else if ((id->dma_ultra & 0x0010) && (udma_66)) { speed = XFER_UDMA_4; @@ -331,7 +333,7 @@ (void) amd74xx_tune_chipset(drive, speed); - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); @@ -352,7 +354,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -442,17 +444,43 @@ unsigned int __init ata66_amd74xx (ide_hwif_t *hwif) { + struct pci_dev *dev = hwif->pci_dev; + byte cable_80_pin[2] = { 0, 0 }; + byte ata66 = 0; + byte tmpbyte; + + /* + * Ultra66 cable detection (from Host View) + * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin + */ + pci_read_config_byte(dev, 0x42, &tmpbyte); + + /* + * 0x42, bit0 is 1 => primary channel + * has 80-pin (from host view) + */ + if (tmpbyte & 0x01) cable_80_pin[0] = 1; + + /* + * 0x42, bit2 is 1 => secondary channel + * has 80-pin (from host view) + */ + if (tmpbyte & 0x04) cable_80_pin[1] = 1; + + switch(dev->device) { + case PCI_DEVICE_ID_AMD_VIPER_7441: + case PCI_DEVICE_ID_AMD_VIPER_7411: + ata66 = (hwif->channel) ? + cable_80_pin[1] : + cable_80_pin[0]; + default: + break; + } #ifdef CONFIG_AMD74XX_OVERRIDE - byte ata66 = 1; + return(1); #else - byte ata66 = 0; + return (unsigned int) ata66; #endif /* CONFIG_AMD74XX_OVERRIDE */ - -#if 0 - pci_read_config_byte(hwif->pci_dev, 0x48, &ata66); - return ((ata66 & 0x02) ? 0 : 1); -#endif - return ata66; } void __init ide_init_amd74xx (ide_hwif_t *hwif) diff -urN linux-2.4.18/drivers/ide/buddha.c linux-2.4.19-pre5/drivers/ide/buddha.c --- linux-2.4.18/drivers/ide/buddha.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/buddha.c Sat Mar 30 22:55:34 2002 @@ -1,10 +1,10 @@ /* * linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver * - * Copyright (C) 1997 by Geert Uytterhoeven + * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others * - * This driver was written by based on the specifications in README.buddha and - * the X-Surf info from Inside_XSurf.txt available at + * This driver was written based on the specifications in README.buddha and + * the X-Surf info from Inside_XSurf.txt available at * http://www.jschoenfeld.com * * This file is subject to the terms and conditions of the GNU General Public @@ -52,7 +52,7 @@ BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 }; -static const u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = { +static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = { XSURF_BASE1, XSURF_BASE2 }; @@ -97,7 +97,7 @@ BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 }; -static const int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = { +static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = { XSURF_IRQ1, XSURF_IRQ2 }; @@ -108,8 +108,9 @@ * Board information */ -enum BuddhaType_Enum {BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF}; -typedef enum BuddhaType_Enum BuddhaType; +typedef enum BuddhaType_Enum { + BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF +} BuddhaType; /* @@ -175,15 +176,20 @@ if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE")) continue; if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE")) + goto fail_base2; + if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) { + release_mem_region(board+XSURF_BASE2, 0x1000); +fail_base2: + release_mem_region(board+XSURF_BASE1, 0x1000); continue; - if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) - continue; + } } buddha_board = ZTWO_VADDR(board); /* write to BUDDHA_IRQ_MR to enable the board IRQ */ /* X-Surf doesn't have this. IRQs are always on */ - if(type != BOARD_XSURF) *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0; + if (type != BOARD_XSURF) + z_writeb(0, buddha_board+BUDDHA_IRQ_MR); for(i=0;i static int cmd64x_get_info(char *, char **, off_t, int); +static int cmd680_get_info(char *, char **, off_t, int); extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; @@ -180,24 +181,21 @@ return p-buffer; /* => must be less than 4k! */ } -#if 0 -static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev) -{ - char *p = buf; - p += sprintf(p, "thingy stuff\n"); - return (char *)p; -} -static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - p = cmd64x_chipset_data(buffer, bmide_dev); - return p-buffer; /* hoping it is less than 4K... */ + p += sprintf(p, "\n CMD680 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "PIO Mode: %s %s %s %s\n", + "?", "?", "?", "?"); + return p-buffer; /* => must be less than 4k! */ } -#endif #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ byte cmd64x_proc = 0; +byte cmd680_proc = 0; /* * Registers and masks for easy access by drive index: @@ -345,10 +343,58 @@ setup_count, active_count, recovery_count); } -static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +static byte cmd680_taskfile_timing (ide_hwif_t *hwif) { - byte speed= 0x00; - byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL); + struct pci_dev *dev = hwif->pci_dev; + byte addr_mask = (hwif->channel) ? 0xB2 : 0xA2; + unsigned short timing; + + pci_read_config_word(dev, addr_mask, &timing); + + switch (timing) { + case 0x10c1: return 4; + case 0x10c3: return 3; + case 0x1281: return 2; + case 0x2283: return 1; + case 0x328a: + default: return 0; + } +} + +static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte drive_pci; + unsigned short speedt; + + switch (drive->dn) { + case 0: drive_pci = 0xA4; break; + case 1: drive_pci = 0xA6; break; + case 2: drive_pci = 0xB4; break; + case 3: drive_pci = 0xB6; break; + default: return; + } + + pci_read_config_word(dev, drive_pci, &speedt); + + /* cheat for now and use the docs */ +// switch(cmd680_taskfile_timing(hwif)) { + switch(mode_wanted) { + case 4: speedt = 0x10c1; break; + case 3: speedt = 0x10C3; break; + case 2: speedt = 0x1104; break; + case 1: speedt = 0x2283; break; + case 0: + default: speedt = 0x328A; break; + } + pci_write_config_word(dev, drive_pci, speedt); +} + +static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + byte speed = 0x00; + byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); cmd64x_tuneproc(drive, set_pio); speed = XFER_PIO_0 + set_pio; @@ -356,6 +402,41 @@ (void) ide_config_drive_speed(drive, speed); } +static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u8 unit = (drive->select.b.unit & 0x01); + u8 addr_mask = (hwif->channel) ? 0x84 : 0x80; + u8 speed = 0x00; + u8 mode_pci = 0x00; + u8 channel_timings = cmd680_taskfile_timing(hwif); + u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); + + pci_read_config_byte(dev, addr_mask, &mode_pci); + mode_pci &= ~((unit) ? 0x30 : 0x03); + + /* WARNING PIO timing mess is going to happen b/w devices, argh */ + if ((channel_timings != set_pio) && (set_pio > channel_timings)) + set_pio = channel_timings; + + cmd680_tuneproc(drive, set_pio); + speed = XFER_PIO_0 + set_pio; + if (set_speed) { + (void) ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + } +} + +static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) { + config_cmd680_chipset_for_pio(drive, set_speed); + } else { + config_cmd64x_chipset_for_pio(drive, set_speed); + } +} + static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed) { #ifdef CONFIG_BLK_DEV_IDEDMA @@ -363,7 +444,7 @@ struct pci_dev *dev = hwif->pci_dev; int err = 0; - byte unit = (drive->select.b.unit & 0x01); + u8 unit = (drive->select.b.unit & 0x01); u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; u8 regU = 0; @@ -424,8 +505,123 @@ return err; } +static int cmd680_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u8 addr_mask = (hwif->channel) ? 0x84 : 0x80; + u8 unit = (drive->select.b.unit & 0x01); + u8 dma_pci = 0; + u8 udma_pci = 0; + u8 mode_pci = 0; + u8 scsc = 0; + u16 ultra = 0; + u16 multi = 0; + int err = 0; + + pci_read_config_byte(dev, addr_mask, &mode_pci); + pci_read_config_byte(dev, 0x8A, &scsc); + + switch (drive->dn) { + case 0: dma_pci = 0xA8; udma_pci = 0xAC; break; + case 1: dma_pci = 0xAA; udma_pci = 0xAE; break; + case 2: dma_pci = 0xB8; udma_pci = 0xBC; break; + case 3: dma_pci = 0xBA; udma_pci = 0xBE; break; + default: return 1; + } + + pci_read_config_byte(dev, addr_mask, &mode_pci); + mode_pci &= ~((unit) ? 0x30 : 0x03); + pci_read_config_word(dev, dma_pci, &multi); + pci_read_config_word(dev, udma_pci, &ultra); + + if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) { + pci_write_config_byte(dev, 0x8A, scsc|0x01); + pci_read_config_byte(dev, 0x8A, &scsc); + } + + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_6: + if ((scsc & 0x30) == 0x00) + goto speed_break; + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= 0x01; + break; +speed_break : + speed = XFER_UDMA_5; + case XFER_UDMA_5: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02); + break; + case XFER_UDMA_4: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03); + break; + case XFER_UDMA_3: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05); + break; + case XFER_UDMA_2: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07); + break; + case XFER_UDMA_1: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B); + break; + case XFER_UDMA_0: + multi = 0x10C1; + ultra &= ~0x3F; + ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F); + break; + case XFER_MW_DMA_2: + multi = 0x10C1; + break; + case XFER_MW_DMA_1: + multi = 0x10C2; + break; + case XFER_MW_DMA_0: + multi = 0x2208; + break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: cmd680_tuneproc(drive, 4); break; + case XFER_PIO_3: cmd680_tuneproc(drive, 3); break; + case XFER_PIO_2: cmd680_tuneproc(drive, 2); break; + case XFER_PIO_1: cmd680_tuneproc(drive, 1); break; + case XFER_PIO_0: cmd680_tuneproc(drive, 0); break; + default: + return 1; + } + + + if (speed >= XFER_MW_DMA_0) + config_cmd680_chipset_for_pio(drive, 0); + + if (speed >= XFER_UDMA_0) + mode_pci |= ((unit) ? 0x30 : 0x03); + else if (speed >= XFER_MW_DMA_0) + mode_pci |= ((unit) ? 0x20 : 0x02); + else + mode_pci |= ((unit) ? 0x10 : 0x01); + + pci_write_config_byte(dev, addr_mask, mode_pci); + pci_write_config_word(dev, dma_pci, multi); + pci_write_config_word(dev, udma_pci, ultra); + + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + return err; +} + #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); @@ -510,6 +706,55 @@ return rval; } +static int config_cmd680_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte udma_66 = eighty_ninty_three(drive); + byte speed = 0x00; + byte set_pio = 0x00; + int rval; + + if ((id->dma_ultra & 0x0040) && (udma_66)) speed = XFER_UDMA_6; + else if ((id->dma_ultra & 0x0020) && (udma_66)) speed = XFER_UDMA_5; + else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4; + else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3; + else if (id->dma_ultra & 0x0004) speed = XFER_UDMA_2; + else if (id->dma_ultra & 0x0002) speed = XFER_UDMA_1; + else if (id->dma_ultra & 0x0001) speed = XFER_UDMA_0; + else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; + else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; + else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; + else { + set_pio = 1; + } + + if (!drive->init_speed) + drive->init_speed = speed; + + config_chipset_for_pio(drive, set_pio); + + if (set_pio) + return ((int) ide_dma_off_quietly); + + if (cmd680_tune_chipset(drive, speed)) + return ((int) ide_dma_off); + + rval = (int)( ((id->dma_ultra >> 14) & 3) ? ide_dma_on : + ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); + return rval; +} + +static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +{ + if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) + return (config_cmd680_chipset_for_dma(drive)); + return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66)); +} + static int cmd64x_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -519,12 +764,15 @@ byte can_ultra_33 = 0; byte can_ultra_66 = 0; byte can_ultra_100 = 0; + byte can_ultra_133 = 0; ide_dma_action_t dma_func = ide_dma_on; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; switch(dev->device) { + case PCI_DEVICE_ID_CMD_680: + can_ultra_133 = 1; case PCI_DEVICE_ID_CMD_649: can_ultra_100 = 1; case PCI_DEVICE_ID_CMD_648: @@ -550,7 +798,7 @@ } dma_func = ide_dma_off_quietly; if ((id->field_valid & 4) && (can_ultra_33)) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66); if ((id->field_valid & 2) && @@ -586,6 +834,18 @@ return HWIF(drive)->dmaproc(dma_func, drive); } +static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return cmd64x_config_drive_for_dma(drive); + default: + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); +} + static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte dma_stat = 0; @@ -663,7 +923,78 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) +static int cmd680_busproc (ide_drive_t * drive, int state) +{ +#if 0 + ide_hwif_t *hwif = HWIF(drive); + u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0; + u32 stat_config = 0; + + pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config); + + if (!hwif) + return -EINVAL; + + switch (state) { + case BUSSTATE_ON: + hwif->drives[0].failures = 0; + hwif->drives[1].failures = 0; + break; + case BUSSTATE_OFF: + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + break; + case BUSSTATE_TRISTATE: + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + break; + default: + return 0; + } + hwif->bus_state = state; +#endif + return 0; +} + +void cmd680_reset (ide_drive_t *drive) +{ +#if 0 + ide_hwif_t *hwif = HWIF(drive); + u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0; + byte reset = 0; + + pci_read_config_byte(hwif->pci_dev, addr_mask, &reset); + pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03); +#endif +} + +unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name) +{ + u8 tmpbyte = 0; + pci_write_config_byte(dev, 0x80, 0x00); + pci_write_config_byte(dev, 0x84, 0x00); + pci_read_config_byte(dev, 0x8A, &tmpbyte); + pci_write_config_byte(dev, 0x8A, tmpbyte|0x01); + pci_write_config_word(dev, 0xA2, 0x328A); + pci_write_config_dword(dev, 0xA4, 0x328A); + pci_write_config_dword(dev, 0xA8, 0x4392); + pci_write_config_dword(dev, 0xAC, 0x4009); + pci_write_config_word(dev, 0xB2, 0x328A); + pci_write_config_dword(dev, 0xB4, 0x328A); + pci_write_config_dword(dev, 0xB8, 0x4392); + pci_write_config_dword(dev, 0xBC, 0x4009); + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) + if (!cmd64x_proc) { + cmd64x_proc = 1; + bmide_dev = dev; + cmd64x_display_info = &cmd680_get_info; + } +#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name) { unsigned char mrdmode; unsigned int class_rev; @@ -752,7 +1083,23 @@ return 0; } -unsigned int __init ata66_cmd64x (ide_hwif_t *hwif) +unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) +{ + if (dev->device == PCI_DEVICE_ID_CMD_680) + return cmd680_pci_init (dev, name); + return cmd64x_pci_init (dev, name); +} + +unsigned int cmd680_ata66 (ide_hwif_t *hwif) +{ + byte ata66 = 0; + byte addr_mask = (hwif->channel) ? 0xB0 : 0xA0; + + pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66); + return (ata66 & 0x01) ? 1 : 0; +} + +unsigned int cmd64x_ata66 (ide_hwif_t *hwif) { byte ata66 = 0; byte mask = (hwif->channel) ? 0x02 : 0x01; @@ -761,6 +1108,14 @@ return (ata66 & mask) ? 1 : 0; } +unsigned int __init ata66_cmd64x (ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + if (dev->device == PCI_DEVICE_ID_CMD_680) + return cmd680_ata66(hwif); + return cmd64x_ata66(hwif); +} + void __init ide_init_cmd64x (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; @@ -769,8 +1124,6 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - hwif->tuneproc = &cmd64x_tuneproc; - hwif->speedproc = &cmd64x_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; @@ -779,10 +1132,19 @@ #ifdef CONFIG_BLK_DEV_IDEDMA switch(dev->device) { + case PCI_DEVICE_ID_CMD_680: + hwif->busproc = &cmd680_busproc; + hwif->dmaproc = &cmd680_dmaproc; + hwif->resetproc = &cmd680_reset; + hwif->speedproc = &cmd680_tune_chipset; + hwif->tuneproc = &cmd680_tuneproc; + break; case PCI_DEVICE_ID_CMD_649: case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_643: - hwif->dmaproc = &cmd64x_dmaproc; + hwif->dmaproc = &cmd64x_dmaproc; + hwif->tuneproc = &cmd64x_tuneproc; + hwif->speedproc = &cmd64x_tune_chipset; break; case PCI_DEVICE_ID_CMD_646: hwif->chipset = ide_cmd646; @@ -791,6 +1153,8 @@ } else { hwif->dmaproc = &cmd64x_dmaproc; } + hwif->tuneproc = &cmd64x_tuneproc; + hwif->speedproc = &cmd64x_tune_chipset; break; default: break; diff -urN linux-2.4.18/drivers/ide/falconide.c linux-2.4.19-pre5/drivers/ide/falconide.c --- linux-2.4.18/drivers/ide/falconide.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/falconide.c Sat Mar 30 22:55:34 2002 @@ -7,7 +7,7 @@ * License. See the file COPYING in the main directory of this archive for * more details. */ -#include + #include #include #include diff -urN linux-2.4.18/drivers/ide/hpt366.c linux-2.4.19-pre5/drivers/ide/hpt366.c --- linux-2.4.18/drivers/ide/hpt366.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/hpt366.c Sat Mar 30 22:55:34 2002 @@ -1,7 +1,8 @@ /* - * linux/drivers/ide/hpt366.c Version 0.18 June. 9, 2000 + * linux/drivers/ide/hpt366.c Version 0.22 20 Sep 2001 * * Copyright (C) 1999-2000 Andre Hedrick + * Portions Copyright (C) 2001 Sun Microsystems, Inc. * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. @@ -11,6 +12,34 @@ * * Note that final HPT370 support was done by force extraction of GPL. * + * - add function for getting/setting power status of drive + * - the HPT370's state machine can get confused. reset it before each dma + * xfer to prevent that from happening. + * - reset state engine whenever we get an error. + * - check for busmaster state at end of dma. + * - use new highpoint timings. + * - detect bus speed using highpoint register. + * - use pll if we don't have a clock table. added a 66MHz table that's + * just 2x the 33MHz table. + * - removed turnaround. NOTE: we never want to switch between pll and + * pci clocks as the chip can glitch in those cases. the highpoint + * approved workaround slows everything down too much to be useful. in + * addition, we would have to serialize access to each chip. + * Adrian Sun + * + * add drive timings for 66MHz PCI bus, + * fix ATA Cable signal detection, fix incorrect /proc info + * add /proc display for per-drive PIO/DMA/UDMA mode and + * per-channel ATA-33/66 Cable detect. + * Duncan Laurie + * + * fixup /proc output for multiple controllers + * Tim Hockin + * + * On hpt366: + * Reset the hpt366 on error, reset on dma + * Fix disabling Fast Interrupt hpt366. + * Mike Waychison */ #include @@ -28,6 +57,7 @@ #include #include +#include #include #include @@ -35,6 +65,11 @@ #define DISPLAY_HPT366_TIMINGS +/* various tuning parameters */ +#define HPT_RESET_STATE_ENGINE +/*#define HPT_DELAY_INTERRUPT*/ +/*#define HPT_SERIALIZE_IO*/ + #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) #include #include @@ -106,146 +141,302 @@ struct chipset_bus_clock_list_entry { byte xfer_speed; - unsigned int chipset_settings_write; - unsigned int chipset_settings_read; + unsigned int chipset_settings; }; +/* key for bus clock timings + * bit + * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW + * DMA. cycles = value + 1 + * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW + * DMA. cycles = value + 1 + * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file + * register access. + * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file + * register access. + * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer. + * during task file register access. + * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA + * xfer. + * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task + * register access. + * 28 UDMA enable + * 29 DMA enable + * 30 PIO_MST enable. if set, the chip is in bus master mode during + * PIO. + * 31 FIFO enable. + */ struct chipset_bus_clock_list_entry forty_base [] = { - { XFER_UDMA_4, 0x900fd943, 0x900fd943 }, - { XFER_UDMA_3, 0x900ad943, 0x900ad943 }, - { XFER_UDMA_2, 0x900bd943, 0x900bd943 }, - { XFER_UDMA_1, 0x9008d943, 0x9008d943 }, - { XFER_UDMA_0, 0x9008d943, 0x9008d943 }, - - { XFER_MW_DMA_2, 0xa008d943, 0xa008d943 }, - { XFER_MW_DMA_1, 0xa010d955, 0xa010d955 }, - { XFER_MW_DMA_0, 0xa010d9fc, 0xa010d9fc }, - - { XFER_PIO_4, 0xc008d963, 0xc008d963 }, - { XFER_PIO_3, 0xc010d974, 0xc010d974 }, - { XFER_PIO_2, 0xc010d997, 0xc010d997 }, - { XFER_PIO_1, 0xc010d9c7, 0xc010d9c7 }, - { XFER_PIO_0, 0xc018d9d9, 0xc018d9d9 }, - { 0, 0x0120d9d9, 0x0120d9d9 } + { XFER_UDMA_4, 0x900fd943 }, + { XFER_UDMA_3, 0x900ad943 }, + { XFER_UDMA_2, 0x900bd943 }, + { XFER_UDMA_1, 0x9008d943 }, + { XFER_UDMA_0, 0x9008d943 }, + + { XFER_MW_DMA_2, 0xa008d943 }, + { XFER_MW_DMA_1, 0xa010d955 }, + { XFER_MW_DMA_0, 0xa010d9fc }, + + { XFER_PIO_4, 0xc008d963 }, + { XFER_PIO_3, 0xc010d974 }, + { XFER_PIO_2, 0xc010d997 }, + { XFER_PIO_1, 0xc010d9c7 }, + { XFER_PIO_0, 0xc018d9d9 }, + { 0, 0x0120d9d9 } }; struct chipset_bus_clock_list_entry thirty_three_base [] = { - { XFER_UDMA_4, 0x90c9a731, 0x90c9a731 }, - { XFER_UDMA_3, 0x90cfa731, 0x90cfa731 }, - { XFER_UDMA_2, 0x90caa731, 0x90caa731 }, - { XFER_UDMA_1, 0x90cba731, 0x90cba731 }, - { XFER_UDMA_0, 0x90c8a731, 0x90c8a731 }, - - { XFER_MW_DMA_2, 0xa0c8a731, 0xa0c8a731 }, - { XFER_MW_DMA_1, 0xa0c8a732, 0xa0c8a732 }, /* 0xa0c8a733 */ - { XFER_MW_DMA_0, 0xa0c8a797, 0xa0c8a797 }, - - { XFER_PIO_4, 0xc0c8a731, 0xc0c8a731 }, - { XFER_PIO_3, 0xc0c8a742, 0xc0c8a742 }, - { XFER_PIO_2, 0xc0d0a753, 0xc0d0a753 }, - { XFER_PIO_1, 0xc0d0a7a3, 0xc0d0a7a3 }, /* 0xc0d0a793 */ - { XFER_PIO_0, 0xc0d0a7aa, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ - { 0, 0x0120a7a7, 0x0120a7a7 } + { XFER_UDMA_4, 0x90c9a731 }, + { XFER_UDMA_3, 0x90cfa731 }, + { XFER_UDMA_2, 0x90caa731 }, + { XFER_UDMA_1, 0x90cba731 }, + { XFER_UDMA_0, 0x90c8a731 }, + + { XFER_MW_DMA_2, 0xa0c8a731 }, + { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */ + { XFER_MW_DMA_0, 0xa0c8a797 }, + + { XFER_PIO_4, 0xc0c8a731 }, + { XFER_PIO_3, 0xc0c8a742 }, + { XFER_PIO_2, 0xc0d0a753 }, + { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */ + { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ + { 0, 0x0120a7a7 } }; struct chipset_bus_clock_list_entry twenty_five_base [] = { - { XFER_UDMA_4, 0x90c98521, 0x90c98521 }, - { XFER_UDMA_3, 0x90cf8521, 0x90cf8521 }, - { XFER_UDMA_2, 0x90cf8521, 0x90cf8521 }, - { XFER_UDMA_1, 0x90cb8521, 0x90cb8521 }, - { XFER_UDMA_0, 0x90cb8521, 0x90cb8521 }, - - { XFER_MW_DMA_2, 0xa0ca8521, 0xa0ca8521 }, - { XFER_MW_DMA_1, 0xa0ca8532, 0xa0ca8532 }, - { XFER_MW_DMA_0, 0xa0ca8575, 0xa0ca8575 }, - - { XFER_PIO_4, 0xc0ca8521, 0xc0ca8521 }, - { XFER_PIO_3, 0xc0ca8532, 0xc0ca8532 }, - { XFER_PIO_2, 0xc0ca8542, 0xc0ca8542 }, - { XFER_PIO_1, 0xc0d08572, 0xc0d08572 }, - { XFER_PIO_0, 0xc0d08585, 0xc0d08585 }, - { 0, 0x01208585, 0x01208585 } + { XFER_UDMA_4, 0x90c98521 }, + { XFER_UDMA_3, 0x90cf8521 }, + { XFER_UDMA_2, 0x90cf8521 }, + { XFER_UDMA_1, 0x90cb8521 }, + { XFER_UDMA_0, 0x90cb8521 }, + + { XFER_MW_DMA_2, 0xa0ca8521 }, + { XFER_MW_DMA_1, 0xa0ca8532 }, + { XFER_MW_DMA_0, 0xa0ca8575 }, + + { XFER_PIO_4, 0xc0ca8521 }, + { XFER_PIO_3, 0xc0ca8532 }, + { XFER_PIO_2, 0xc0ca8542 }, + { XFER_PIO_1, 0xc0d08572 }, + { XFER_PIO_0, 0xc0d08585 }, + { 0, 0x01208585 } }; +#if 1 +/* these are the current (4 sep 2001) timings from highpoint */ struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { - { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, - { XFER_UDMA_4, 0x16454e31, 0x16454e31 }, - { XFER_UDMA_3, 0x166d4e31, 0x166d4e31 }, - { XFER_UDMA_2, 0x16494e31, 0x16494e31 }, - { XFER_UDMA_1, 0x164d4e31, 0x164d4e31 }, - { XFER_UDMA_0, 0x16514e31, 0x16514e31 }, - - { XFER_MW_DMA_2, 0x26514e21, 0x26514e21 }, - { XFER_MW_DMA_1, 0x26514e33, 0x26514e33 }, - { XFER_MW_DMA_0, 0x26514e97, 0x26514e97 }, - - { XFER_PIO_4, 0x06514e21, 0x06514e21 }, - { XFER_PIO_3, 0x06514e22, 0x06514e22 }, - { XFER_PIO_2, 0x06514e33, 0x06514e33 }, - { XFER_PIO_1, 0x06914e43, 0x06914e43 }, - { XFER_PIO_0, 0x06914e57, 0x06914e57 }, - { 0, 0x06514e57, 0x06514e57 } + { XFER_UDMA_5, 0x12446231 }, + { XFER_UDMA_4, 0x12446231 }, + { XFER_UDMA_3, 0x126c6231 }, + { XFER_UDMA_2, 0x12486231 }, + { XFER_UDMA_1, 0x124c6233 }, + { XFER_UDMA_0, 0x12506297 }, + + { XFER_MW_DMA_2, 0x22406c31 }, + { XFER_MW_DMA_1, 0x22406c33 }, + { XFER_MW_DMA_0, 0x22406c97 }, + + { XFER_PIO_4, 0x06414e31 }, + { XFER_PIO_3, 0x06414e42 }, + { XFER_PIO_2, 0x06414e53 }, + { XFER_PIO_1, 0x06814e93 }, + { XFER_PIO_0, 0x06814ea7 }, + { 0, 0x06814ea7 } +}; + +/* 2x 33MHz timings */ +struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = { + { XFER_UDMA_5, 0x1488e673 }, + { XFER_UDMA_4, 0x1488e673 }, + { XFER_UDMA_3, 0x1498e673 }, + { XFER_UDMA_2, 0x1490e673 }, + { XFER_UDMA_1, 0x1498e677 }, + { XFER_UDMA_0, 0x14a0e73f }, + + { XFER_MW_DMA_2, 0x2480fa73 }, + { XFER_MW_DMA_1, 0x2480fa77 }, + { XFER_MW_DMA_0, 0x2480fb3f }, + + { XFER_PIO_4, 0x0c82be73 }, + { XFER_PIO_3, 0x0c82be95 }, + { XFER_PIO_2, 0x0c82beb7 }, + { XFER_PIO_1, 0x0d02bf37 }, + { XFER_PIO_0, 0x0d02bf5f }, + { 0, 0x0d02bf5f } +}; +#else +/* from highpoint documentation. these are old values */ +struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { + { XFER_UDMA_5, 0x16454e31 }, + { XFER_UDMA_4, 0x16454e31 }, + { XFER_UDMA_3, 0x166d4e31 }, + { XFER_UDMA_2, 0x16494e31 }, + { XFER_UDMA_1, 0x164d4e31 }, + { XFER_UDMA_0, 0x16514e31 }, + + { XFER_MW_DMA_2, 0x26514e21 }, + { XFER_MW_DMA_1, 0x26514e33 }, + { XFER_MW_DMA_0, 0x26514e97 }, + + { XFER_PIO_4, 0x06514e21 }, + { XFER_PIO_3, 0x06514e22 }, + { XFER_PIO_2, 0x06514e33 }, + { XFER_PIO_1, 0x06914e43 }, + { XFER_PIO_0, 0x06914e57 }, + { 0, 0x06514e57 } +}; + +struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = { + { XFER_UDMA_5, 0x14846231 }, + { XFER_UDMA_4, 0x14886231 }, + { XFER_UDMA_3, 0x148c6231 }, + { XFER_UDMA_2, 0x148c6231 }, + { XFER_UDMA_1, 0x14906231 }, + { XFER_UDMA_0, 0x14986231 }, + + { XFER_MW_DMA_2, 0x26514e21 }, + { XFER_MW_DMA_1, 0x26514e33 }, + { XFER_MW_DMA_0, 0x26514e97 }, + + { XFER_PIO_4, 0x06514e21 }, + { XFER_PIO_3, 0x06514e22 }, + { XFER_PIO_2, 0x06514e33 }, + { XFER_PIO_1, 0x06914e43 }, + { XFER_PIO_0, 0x06914e57 }, + { 0, 0x06514e57 } +}; +#endif + +struct chipset_bus_clock_list_entry fifty_base_hpt370[] = { + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x0ac1f48a } }; #define HPT366_DEBUG_DRIVE_INFO 0 #define HPT370_ALLOW_ATA100_5 1 #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 +#define HPT366_MAX_DEVS 8 + +#define F_LOW_PCI_33 0x23 +#define F_LOW_PCI_40 0x29 +#define F_LOW_PCI_50 0x2d +#define F_LOW_PCI_66 0x42 + +static struct pci_dev *hpt_devs[HPT366_MAX_DEVS]; +static int n_hpt_devs; + +static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev); +static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev); +byte hpt366_proc = 0; +byte hpt363_shared_irq; +byte hpt363_shared_pin; +extern char *ide_xfer_verbose (byte xfer_rate); #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) static int hpt366_get_info(char *, char **, off_t, int); extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; -static struct pci_dev *bmide2_dev; static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) { - char *p = buffer; - u32 bibma = bmide_dev->resource[4].start; - u32 bibma2 = bmide2_dev->resource[4].start; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"}; - u8 c0 = 0, c1 = 0; - u32 class_rev; - - pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - if (bmide2_dev) - c1 = inb_p((unsigned short)bibma2 + 0x02); - - p += sprintf(p, "\n %s Chipset.\n", chipset_names[class_rev]); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); + char *p = buffer; + char *chipset_nums[] = {"366", "366", "368", "370", "370A"}; + int i; + + p += sprintf(p, "\n " + "HighPoint HPT366/368/370\n"); + for (i = 0; i < n_hpt_devs; i++) { + struct pci_dev *dev = hpt_devs[i]; + unsigned long iobase = dev->resource[4].start; + u32 class_rev; + u8 c0, c1; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + p += sprintf(p, "\nController: %d\n", i); + p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]); + p += sprintf(p, "--------------- Primary Channel " + "--------------- Secondary Channel " + "--------------\n"); + + /* get the bus master status registers */ + c0 = inb_p(iobase + 0x2); + c1 = inb_p(iobase + 0xa); + p += sprintf(p, "Enabled: %s" + " %s\n", + (c0 & 0x80) ? "no" : "yes", + (c1 & 0x80) ? "no" : "yes"); + + if (pci_rev_check_hpt3xx(dev)) { + u8 cbl; + cbl = inb_p(iobase + 0x7b); + outb_p(cbl | 1, iobase + 0x7b); + outb_p(cbl & ~1, iobase + 0x7b); + cbl = inb_p(iobase + 0x7a); + p += sprintf(p, "Cable: ATA-%d" + " ATA-%d\n", + (cbl & 0x02) ? 33 : 66, + (cbl & 0x01) ? 33 : 66); + p += sprintf(p, "\n"); + } + p += sprintf(p, "--------------- drive0 --------- drive1 " + "------- drive0 ---------- drive1 -------\n"); + p += sprintf(p, "DMA capable: %s %s" + " %s %s\n", + (c0 & 0x20) ? "yes" : "no ", + (c0 & 0x40) ? "yes" : "no ", + (c1 & 0x20) ? "yes" : "no ", + (c1 & 0x40) ? "yes" : "no "); + + { + u8 c2, c3; + /* older revs don't have these registers mapped + * into io space */ + pci_read_config_byte(dev, 0x43, &c0); + pci_read_config_byte(dev, 0x47, &c1); + pci_read_config_byte(dev, 0x4b, &c2); + pci_read_config_byte(dev, 0x4f, &c3); + + p += sprintf(p, "Mode: %s %s" + " %s %s\n", + (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : + (c0 & 0x80) ? "PIO " : "off ", + (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " : + (c1 & 0x80) ? "PIO " : "off ", + (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " : + (c2 & 0x80) ? "PIO " : "off ", + (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " : + (c3 & 0x80) ? "PIO " : "off "); + } + } + p += sprintf(p, "\n"); + return p-buffer;/* => must be less than 4k! */ } #endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ -byte hpt366_proc = 0; - -extern char *ide_xfer_verbose (byte xfer_rate); -byte hpt363_shared_irq; -byte hpt363_shared_pin; - static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev) { unsigned int class_rev; @@ -282,16 +473,16 @@ return 0; } -static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table) +static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read; + return chipset_table->chipset_settings; } - return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read; + return chipset_table->chipset_settings; } -static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction) +static void hpt366_tune_chipset (ide_drive_t *drive, byte speed) { byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; @@ -304,7 +495,7 @@ byte drive_fast = 0; /* - * Disable the "fast interrupt" prediction. + * Disable the "fast interrupt" prediction. */ pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast); if (drive_fast & 0x02) @@ -314,16 +505,22 @@ /* detect bus speed by looking at control reg timing: */ switch((reg1 >> 8) & 7) { case 5: - reg2 = pci_bus_clock_list(speed, direction, forty_base); + reg2 = pci_bus_clock_list(speed, forty_base); break; case 9: - reg2 = pci_bus_clock_list(speed, direction, twenty_five_base); + reg2 = pci_bus_clock_list(speed, twenty_five_base); break; default: case 7: - reg2 = pci_bus_clock_list(speed, direction, thirty_three_base); + reg2 = pci_bus_clock_list(speed, thirty_three_base); break; } +#if 0 + /* this is a nice idea ... */ + list_conf = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) + dev->sysdata); +#endif /* * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later) */ @@ -337,40 +534,47 @@ pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); } -static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction) +static void hpt370_tune_chipset (ide_drive_t *drive, byte speed) { byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; - byte reg5bh = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22; - unsigned int list_conf = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370); + unsigned int list_conf = 0; unsigned int drive_conf = 0; unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; - byte drive_pci = 0; - byte drive_fast = 0; + byte drive_pci = 0x40 + (drive->dn * 4); + byte new_fast, drive_fast = 0; + struct pci_dev *dev = HWIF(drive)->pci_dev; - switch (drive->dn) { - case 0: drive_pci = 0x40; break; - case 1: drive_pci = 0x44; break; - case 2: drive_pci = 0x48; break; - case 3: drive_pci = 0x4c; break; - default: return; - } /* * Disable the "fast interrupt" prediction. + * don't holdoff on interrupts. (== 0x01 despite what the docs say) */ - pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80); + pci_read_config_byte(dev, regfast, &drive_fast); + new_fast = drive_fast; + if (new_fast & 0x02) + new_fast &= ~0x02; + +#ifdef HPT_DELAY_INTERRUPT + if (new_fast & 0x01) + new_fast &= ~0x01; +#else + if ((new_fast & 0x01) == 0) + new_fast |= 0x01; +#endif + if (new_fast != drive_fast) + pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast); - pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh); + list_conf = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) + dev->sysdata); + pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - /* - * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later) - */ - list_conf &= ~0x80000000; + + if (speed < XFER_MW_DMA_0) { + list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ + } - pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf); + pci_write_config_dword(dev, drive_pci, list_conf); } static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed) @@ -382,9 +586,9 @@ drive->init_speed = speed; if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) { - hpt370_tune_chipset(drive, speed, 0); + hpt370_tune_chipset(drive, speed); } else { - hpt366_tune_chipset(drive, speed, 0); + hpt366_tune_chipset(drive, speed); } drive->current_speed = speed; return ((int) ide_config_drive_speed(drive, speed)); @@ -541,13 +745,6 @@ } } -void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func) -{ - if ((func != ide_dma_write) || (func != ide_dma_read)) - return; - hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write)); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -624,6 +821,13 @@ reg50h, reg52h, reg5ah); if (reg5ah & 0x10) pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10); + /* fall through to a reset */ +#if 0 + case ide_dma_begin: + case ide_dma_end: + /* reset the chips state over and over.. */ + pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13); +#endif break; case ide_dma_timeout: default: @@ -634,9 +838,52 @@ int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte regstate = hwif->channel ? 0x54 : 0x50; + byte reginfo = hwif->channel ? 0x56 : 0x52; + byte dma_stat; + switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); + case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = inb(dma_base+2); + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + + case ide_dma_end: + dma_stat = inb(dma_base + 2); + if (dma_stat & 0x01) { + udelay(20); /* wait a little */ + dma_stat = inb(dma_base + 2); + } + if ((dma_stat & 0x01) == 0) + break; + + func = ide_dma_timeout; + /* fallthrough */ + + case ide_dma_timeout: + case ide_dma_lostirq: + pci_read_config_byte(hwif->pci_dev, reginfo, + &dma_stat); + printk("%s: %d bytes in FIFO\n", drive->name, + dma_stat); + pci_write_config_byte(hwif->pci_dev, regstate, 0x37); + udelay(10); + dma_stat = inb(dma_base); + outb(dma_stat & ~0x1, dma_base); /* stop dma */ + dma_stat = inb(dma_base + 2); + outb(dma_stat | 0x6, dma_base+2); /* clear errors */ + /* fallthrough */ + +#ifdef HPT_RESET_STATE_ENGINE + case ide_dma_begin: +#endif + pci_write_config_byte(hwif->pci_dev, regstate, 0x37); + udelay(10); + break; + default: break; } @@ -644,6 +891,210 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ +/* + * Since SUN Cobalt is attempting to do this operation, I should disclose + * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date + * HOTSWAP ATA Infrastructure. + */ +void hpt3xx_reset (ide_drive_t *drive) +{ +#if 0 + unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); + byte reset = (HWIF(drive)->channel) ? 0x80 : 0x40; + byte reg59h = 0; + + pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, ®59h); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h); +#endif +} + +static int hpt3xx_tristate (ide_drive_t * drive, int state) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte reset = (hwif->channel) ? 0x80 : 0x40; + byte state_reg = (hwif->channel) ? 0x57 : 0x53; + byte reg59h = 0; + byte regXXh = 0; + + if (!hwif) + return -EINVAL; + +// hwif->bus_state = state; + + pci_read_config_byte(dev, 0x59, ®59h); + pci_read_config_byte(dev, state_reg, ®XXh); + + if (state) { + (void) ide_do_reset(drive); + pci_write_config_byte(dev, state_reg, regXXh|0x80); + pci_write_config_byte(dev, 0x59, reg59h|reset); + } else { + pci_write_config_byte(dev, 0x59, reg59h & ~(reset)); + pci_write_config_byte(dev, state_reg, regXXh & ~(0x80)); + (void) ide_do_reset(drive); + } + return 0; +} + +/* + * set/get power state for a drive. + * turning the power off does the following things: + * 1) soft-reset the drive + * 2) tri-states the ide bus + * + * when we turn things back on, we need to re-initialize things. + */ +#define TRISTATE_BIT 0x8000 +static int hpt370_busproc(ide_drive_t * drive, int state) +{ + ide_hwif_t *hwif = HWIF(drive); + byte tristate, resetmask, bus_reg; + u16 tri_reg; + + if (!hwif) + return -EINVAL; + + hwif->bus_state = state; + + if (hwif->channel) { + /* secondary channel */ + tristate = 0x56; + resetmask = 0x80; + } else { + /* primary channel */ + tristate = 0x52; + resetmask = 0x40; + } + + /* grab status */ + pci_read_config_word(hwif->pci_dev, tristate, &tri_reg); + pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg); + + /* set the state. we don't set it if we don't need to do so. + * make sure that the drive knows that it has failed if it's off */ + switch (state) { + case BUSSTATE_ON: + hwif->drives[0].failures = 0; + hwif->drives[1].failures = 0; + if ((bus_reg & resetmask) == 0) + return 0; + tri_reg &= ~TRISTATE_BIT; + bus_reg &= ~resetmask; + break; + case BUSSTATE_OFF: + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask)) + return 0; + tri_reg &= ~TRISTATE_BIT; + bus_reg |= resetmask; + break; + case BUSSTATE_TRISTATE: + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask)) + return 0; + tri_reg |= TRISTATE_BIT; + bus_reg |= resetmask; + break; + } + pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg); + pci_write_config_word(hwif->pci_dev, tristate, tri_reg); + + return 0; +} + +static void __init init_hpt370(struct pci_dev *dev) +{ + int adjust, i; + u16 freq; + u32 pll; + byte reg5bh; + + /* + * default to pci clock. make sure MA15/16 are set to output + * to prevent drives having problems with 40-pin cables. + */ + pci_write_config_byte(dev, 0x5b, 0x23); + + /* + * set up the PLL. we need to adjust it so that it's stable. + * freq = Tpll * 192 / Tpci + */ + pci_read_config_word(dev, 0x78, &freq); + freq &= 0x1FF; + if (freq < 0x9c) { + pll = F_LOW_PCI_33; + dev->sysdata = (void *) thirty_three_base_hpt370; + printk("HPT370: using 33MHz PCI clock\n"); + } else if (freq < 0xb0) { + pll = F_LOW_PCI_40; + } else if (freq < 0xc8) { + pll = F_LOW_PCI_50; + dev->sysdata = (void *) fifty_base_hpt370; + printk("HPT370: using 50MHz PCI clock\n"); + } else { + pll = F_LOW_PCI_66; + dev->sysdata = (void *) sixty_six_base_hpt370; + printk("HPT370: using 66MHz PCI clock\n"); + } + + /* + * only try the pll if we don't have a table for the clock + * speed that we're running at. NOTE: the internal PLL will + * result in slow reads when using a 33MHz PCI clock. we also + * don't like to use the PLL because it will cause glitches + * on PRST/SRST when the HPT state engine gets reset. + */ + if (dev->sysdata) + goto init_hpt370_done; + + /* + * adjust PLL based upon PCI clock, enable it, and wait for + * stabilization. + */ + adjust = 0; + freq = (pll < F_LOW_PCI_50) ? 2 : 4; + while (adjust++ < 6) { + pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 | + pll | 0x100); + + /* wait for clock stabilization */ + for (i = 0; i < 0x50000; i++) { + pci_read_config_byte(dev, 0x5b, ®5bh); + if (reg5bh & 0x80) { + /* spin looking for the clock to destabilize */ + for (i = 0; i < 0x1000; ++i) { + pci_read_config_byte(dev, 0x5b, + ®5bh); + if ((reg5bh & 0x80) == 0) + goto pll_recal; + } + pci_read_config_dword(dev, 0x5c, &pll); + pci_write_config_dword(dev, 0x5c, + pll & ~0x100); + pci_write_config_byte(dev, 0x5b, 0x21); + dev->sysdata = (void *) fifty_base_hpt370; + printk("HPT370: using 50MHz internal PLL\n"); + goto init_hpt370_done; + } + } +pll_recal: + if (adjust & 1) + pll -= (adjust >> 1); + else + pll += (adjust >> 1); + } + +init_hpt370_done: + /* reset state engine */ + pci_write_config_byte(dev, 0x50, 0x37); + pci_write_config_byte(dev, 0x54, 0x37); + udelay(100); +} + unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) { byte test = 0; @@ -652,14 +1103,8 @@ pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test); - -#if 0 - if (test != 0x08) - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08); -#else if (test != (L1_CACHE_BYTES / 4)) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); -#endif pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test); if (test != 0x78) @@ -673,17 +1118,18 @@ if (test != 0x08) pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + if (pci_rev_check_hpt3xx(dev)) { + init_hpt370(dev); + hpt_devs[n_hpt_devs++] = dev; + } else { + hpt_devs[n_hpt_devs++] = dev; + } + #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) if (!hpt366_proc) { hpt366_proc = 1; - bmide_dev = dev; - if (pci_rev_check_hpt3xx(dev)) - bmide2_dev = dev; hpt366_display_info = &hpt366_get_info; } - if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) { - bmide2_dev = dev; - } #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */ return dev->irq; @@ -691,38 +1137,58 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) { - byte ata66 = 0; + byte ata66 = 0; + byte regmask = (hwif->channel) ? 0x01 : 0x02; pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); #ifdef DEBUG printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n", - ata66, (ata66 & 0x02) ? "33" : "66", + ata66, (ata66 & regmask) ? "33" : "66", PCI_FUNC(hwif->pci_dev->devfn)); #endif /* DEBUG */ - return ((ata66 & 0x02) ? 0 : 1); + return ((ata66 & regmask) ? 0 : 1); } void __init ide_init_hpt366 (ide_hwif_t *hwif) { + int hpt_rev; + hwif->tuneproc = &hpt3xx_tune_drive; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; +#ifdef HPT_SERIALIZE_IO + /* serialize access to this device */ + if (hwif->mate) + hwif->serialized = hwif->mate->serialized = 1; +#endif + + hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev); + if (hpt_rev) { + /* set up ioctl for power status. note: power affects both + * drives on each channel */ + hwif->busproc = &hpt370_busproc; + } + if (pci_rev2_check_hpt3xx(hwif->pci_dev)) { /* do nothing now but will split device types */ + hwif->resetproc = &hpt3xx_reset; +/* + * don't do until we can parse out the cobalt box argh ... + * hwif->busproc = &hpt3xx_tristate; + */ } #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { - if (pci_rev_check_hpt3xx(hwif->pci_dev)) { + if (hpt_rev) { byte reg5ah = 0; pci_read_config_byte(hwif->pci_dev, 0x5a, ®5ah); if (reg5ah & 0x10) /* interrupt force enable */ pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10); hwif->dmaproc = &hpt370_dmaproc; - hwif->rwproc = &hpt370_rw_proc; } else { hwif->dmaproc = &hpt366_dmaproc; } diff -urN linux-2.4.18/drivers/ide/ide-cd.c linux-2.4.19-pre5/drivers/ide/ide-cd.c --- linux-2.4.18/drivers/ide/ide-cd.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/ide/ide-cd.c Sat Mar 30 22:55:34 2002 @@ -2961,11 +2961,7 @@ return 0; } -static -int ide_cdrom_reinit (ide_drive_t *drive) -{ - return 0; -} +int ide_cdrom_reinit (ide_drive_t *drive); static ide_driver_t ide_cdrom_driver = { name: "ide-cdrom", @@ -2975,6 +2971,8 @@ supports_dma: 1, supports_dsc_overlap: 1, cleanup: ide_cdrom_cleanup, + standby: NULL, + flushcache: NULL, do_request: ide_do_rw_cdrom, end_request: NULL, ioctl: ide_cdrom_ioctl, @@ -2986,7 +2984,9 @@ capacity: ide_cdrom_capacity, special: NULL, proc: NULL, - driver_reinit: ide_cdrom_reinit, + reinit: ide_cdrom_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, }; int ide_cdrom_init(void); @@ -3002,6 +3002,39 @@ MODULE_PARM(ignore, "s"); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); + +int ide_cdrom_reinit (ide_drive_t *drive) +{ + struct cdrom_info *info; + int failed = 0; + + MOD_INC_USE_COUNT; + info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); + if (info == NULL) { + printk ("%s: Can't allocate a cdrom structure\n", drive->name); + return 1; + } + if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) { + printk ("%s: Failed to register the driver with ide.c\n", drive->name); + kfree (info); + return 1; + } + memset (info, 0, sizeof (struct cdrom_info)); + drive->driver_data = info; + DRIVER(drive)->busy++; + if (ide_cdrom_setup (drive)) { + DRIVER(drive)->busy--; + if (ide_cdrom_cleanup (drive)) + printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); + return 1; + } + DRIVER(drive)->busy--; + failed--; + + ide_register_module(&ide_cdrom_module); + MOD_DEC_USE_COUNT; + return 0; +} static void __exit ide_cdrom_exit(void) { diff -urN linux-2.4.18/drivers/ide/ide-cd.h linux-2.4.19-pre5/drivers/ide/ide-cd.h --- linux-2.4.18/drivers/ide/ide-cd.h Sat Feb 16 22:46:45 2002 +++ linux-2.4.19-pre5/drivers/ide/ide-cd.h Sat Mar 30 22:55:34 2002 @@ -38,7 +38,9 @@ /************************************************************************/ #define SECTOR_BITS 9 +#ifndef SECTOR_SIZE #define SECTOR_SIZE (1 << SECTOR_BITS) +#endif #define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS) #define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) #define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS) diff -urN linux-2.4.18/drivers/ide/ide-cs.c linux-2.4.19-pre5/drivers/ide/ide-cs.c --- linux-2.4.18/drivers/ide/ide-cs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-cs.c Sat Mar 30 22:55:34 2002 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,15 @@ #define CFG_CHECK(fn, args...) \ if (CardServices(fn, args) != 0) goto next_entry +int idecs_register (int arg1, int arg2, int irq) +{ + hw_regs_t hw; + ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); + hw.irq = irq; + hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */ + return ide_register_hw(&hw, NULL); +} + void ide_config(dev_link_t *link) { client_handle_t handle = link->handle; @@ -329,10 +339,14 @@ /* retry registration in case device is still spinning up */ for (i = 0; i < 10; i++) { - hd = ide_register(io_base, ctl_base, link->irq.AssignedIRQ); + if (ctl_base) + outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */ + hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { - hd = ide_register(io_base+0x10, ctl_base+0x10, + if (ctl_base) + outb(0x02, ctl_base+0x10); + hd = idecs_register(io_base+0x10, ctl_base+0x10, link->irq.AssignedIRQ); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; diff -urN linux-2.4.18/drivers/ide/ide-disk.c linux-2.4.19-pre5/drivers/ide/ide-disk.c --- linux-2.4.18/drivers/ide/ide-disk.c Sun Dec 23 16:23:39 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-disk.c Sat Mar 30 22:55:34 2002 @@ -27,9 +27,11 @@ * Version 1.09 added increment of rq->sector in ide_multwrite * added UDMA 3/4 reporting * Version 1.10 request queue changes, Ultra DMA 100 + * Version 1.11 added 48-bit lba + * Version 1.12 adding taskfile io access method */ -#define IDEDISK_VERSION "1.10" +#define IDEDISK_VERSION "1.12" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -59,6 +61,14 @@ #define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ #endif +#ifdef CONFIG_IDE_TASKFILE_IO +# undef __TASKFILE__IO /* define __TASKFILE__IO */ +#else /* CONFIG_IDE_TASKFILE_IO */ +# undef __TASKFILE__IO +#endif /* CONFIG_IDE_TASKFILE_IO */ + +#ifndef __TASKFILE__IO + static void idedisk_bswap_data (void *buffer, int wcount) { u16 *p = buffer; @@ -86,6 +96,8 @@ ide_output_data(drive, buffer, wcount); } +#endif /* __TASKFILE__IO */ + /* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" * value for this drive (from its reported identification information). @@ -99,6 +111,11 @@ { unsigned long lba_sects, chs_sects, head, tail; + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + printk("48-bit Drive: %llu \n", id->lba_capacity_2); + return 1; + } + /* * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. @@ -131,6 +148,8 @@ return 0; /* lba_capacity value may be bad */ } +#ifndef __TASKFILE__IO + /* * read_intr() is the handler for disk read/multread interrupts */ @@ -313,53 +332,218 @@ } return ide_error(drive, "multwrite_intr", stat); } +#endif /* __TASKFILE__IO */ + +#ifdef __TASKFILE__IO + +static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block); /* - * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. + * do_rw_disk() issues READ and WRITE commands to a disk, + * using LBA if supported, or CHS otherwise, to address sectors. + * It also takes care of issuing special DRIVE_CMDs. */ -static ide_startstop_t set_multmode_intr (ide_drive_t *drive) +static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - byte stat; + if (rq->cmd == READ) + goto good_command; + if (rq->cmd == WRITE) + goto good_command; - if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) { - drive->mult_count = drive->mult_req; - } else { - drive->mult_req = drive->mult_count = 0; - drive->special.b.recalibrate = 1; - (void) ide_dump_status(drive, "set_multmode", stat); - } + printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); return ide_stopped; + +good_command: + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (IS_PDC4030_DRIVE) { + extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long); + return promise_rw_disk(drive, rq, block); + } +#endif /* CONFIG_BLK_DEV_PDC4030 */ + + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) /* 48-bit LBA */ + return lba_48_rw_disk(drive, rq, (unsigned long long) block); + if (drive->select.b.lba) /* 28-bit LBA */ + return lba_28_rw_disk(drive, rq, (unsigned long) block); + + /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */ + return chs_rw_disk(drive, rq, (unsigned long) block); } -/* - * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. - */ -static ide_startstop_t set_geometry_intr (ide_drive_t *drive) +static task_ioreg_t get_command (ide_drive_t *drive, int cmd) { - byte stat; + int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; - if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) - return ide_stopped; +#if 1 + lba48bit = drive->addressing; +#endif - if (stat & (ERR_STAT|DRQ_STAT)) - return ide_error(drive, "set_geometry_intr", stat); + if ((cmd == READ) && (drive->using_dma)) + return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA; + else if ((cmd == READ) && (drive->mult_count)) + return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD; + else if (cmd == READ) + return (lba48bit) ? WIN_READ_EXT : WIN_READ; + else if ((cmd == WRITE) && (drive->using_dma)) + return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + else if ((cmd == WRITE) && (drive->mult_count)) + return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; + else if (cmd == WRITE) + return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE; + else + return WIN_NOP; +} + +static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + unsigned int track = (block / drive->sect); + unsigned int sect = (block % drive->sect) + 1; + unsigned int head = (track % drive->head); + unsigned int cyl = (track / drive->head); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + taskfile.sector_number = sect; + taskfile.low_cylinder = cyl; + taskfile.high_cylinder = (cyl>>8); + taskfile.device_head = head; + taskfile.device_head |= drive->select.all; + taskfile.command = command; + +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); +} + +static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + taskfile.sector_number = block; + taskfile.low_cylinder = (block>>=8); + taskfile.high_cylinder = (block>>=8); + taskfile.device_head = ((block>>8)&0x0f); + taskfile.device_head |= drive->select.all; + taskfile.command = command; + + +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif - ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL); - return ide_started; + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); } /* - * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. + * 268435455 == 137439 MB or 28bit limit + * 320173056 == 163929 MB or 48bit addressing + * 1073741822 == 549756 MB or 48bit addressing fake drive */ -static ide_startstop_t recal_intr (ide_drive_t *drive) + +static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block) { - byte stat = GET_STAT(); + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_task_t args; + + task_ioreg_t command = get_command(drive, rq->cmd); + + memset(&taskfile, 0, sizeof(task_struct_t)); + memset(&hobfile, 0, sizeof(hob_struct_t)); + + taskfile.sector_count = rq->nr_sectors; + hobfile.sector_count = (rq->nr_sectors>>8); + + if (rq->nr_sectors == 65536) { + taskfile.sector_count = 0x00; + hobfile.sector_count = 0x00; + } + + taskfile.sector_number = block; /* low lba */ + taskfile.low_cylinder = (block>>=8); /* mid lba */ + taskfile.high_cylinder = (block>>=8); /* hi lba */ + hobfile.sector_number = (block>>=8); /* low lba */ + hobfile.low_cylinder = (block>>=8); /* mid lba */ + hobfile.high_cylinder = (block>>=8); /* hi lba */ + taskfile.device_head = drive->select.all; + hobfile.device_head = taskfile.device_head; + hobfile.control = (drive->ctl|0x80); + taskfile.command = command; - if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - return ide_error(drive, "recal_intr", stat); - return ide_stopped; +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); + if (lba) printk("LBAsect=%lld, ", block); + else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); + args.handler = ide_handler_parser(&taskfile, &hobfile); + args.posthandler = NULL; + args.rq = (struct request *) rq; + args.block = block; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_rw_taskfile(drive, &args); } +#else /* !__TASKFILE__IO */ /* * do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. @@ -369,22 +553,70 @@ { if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - OUT_BYTE(0x00, IDE_FEATURE_REG); - OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); + #ifdef CONFIG_BLK_DEV_PDC4030 if (drive->select.b.lba || IS_PDC4030_DRIVE) { #else /* !CONFIG_BLK_DEV_PDC4030 */ if (drive->select.b.lba) { #endif /* CONFIG_BLK_DEV_PDC4030 */ + + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + task_ioreg_t tasklets[10]; + + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = rq->nr_sectors; + tasklets[3] = (rq->nr_sectors>>8); + if (rq->nr_sectors == 65536) { + tasklets[2] = 0x00; + tasklets[3] = 0x00; + } + tasklets[4] = (task_ioreg_t) block; + tasklets[5] = (task_ioreg_t) (block>>8); + tasklets[6] = (task_ioreg_t) (block>>16); + tasklets[7] = (task_ioreg_t) (block>>24); + tasklets[8] = (task_ioreg_t) 0; + tasklets[9] = (task_ioreg_t) 0; +// tasklets[8] = (task_ioreg_t) (block>>32); +// tasklets[9] = (task_ioreg_t) (block>>40); #ifdef DEBUG - printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", - drive->name, (rq->cmd==READ)?"read":"writ", - block, rq->nr_sectors, (unsigned long) rq->buffer); -#endif - OUT_BYTE(block,IDE_SECTOR_REG); - OUT_BYTE(block>>=8,IDE_LCYL_REG); - OUT_BYTE(block>>=8,IDE_HCYL_REG); - OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n", + drive->name, + (rq->cmd==READ)?"read":"writ", + block, + rq->nr_sectors, + (unsigned long) rq->buffer, + block); + printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", + drive->name, tasklets[3], tasklets[2], + tasklets[9], tasklets[8], tasklets[7], + tasklets[6], tasklets[5], tasklets[4]); +#endif + OUT_BYTE(tasklets[1], IDE_FEATURE_REG); + OUT_BYTE(tasklets[3], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[7], IDE_SECTOR_REG); + OUT_BYTE(tasklets[8], IDE_LCYL_REG); + OUT_BYTE(tasklets[9], IDE_HCYL_REG); + + OUT_BYTE(tasklets[0], IDE_FEATURE_REG); + OUT_BYTE(tasklets[2], IDE_NSECTOR_REG); + OUT_BYTE(tasklets[4], IDE_SECTOR_REG); + OUT_BYTE(tasklets[5], IDE_LCYL_REG); + OUT_BYTE(tasklets[6], IDE_HCYL_REG); + OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG); + } else { +#ifdef DEBUG + printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", + drive->name, (rq->cmd==READ)?"read":"writ", + block, rq->nr_sectors, (unsigned long) rq->buffer); +#endif + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); + OUT_BYTE(block,IDE_SECTOR_REG); + OUT_BYTE(block>>=8,IDE_LCYL_REG); + OUT_BYTE(block>>=8,IDE_HCYL_REG); + OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + } } else { unsigned int sect,head,cyl,track; track = block / drive->sect; @@ -392,6 +624,9 @@ OUT_BYTE(sect,IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; + + OUT_BYTE(0x00, IDE_FEATURE_REG); + OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG); OUT_BYTE(cyl,IDE_LCYL_REG); OUT_BYTE(cyl>>8,IDE_HCYL_REG); OUT_BYTE(head|drive->select.all,IDE_SELECT_REG); @@ -413,7 +648,11 @@ return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); - OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); + } return ide_started; } if (rq->cmd == WRITE) { @@ -422,7 +661,11 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ - OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); + if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); + } if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE"); @@ -432,17 +675,17 @@ __cli(); /* local CPU only */ if (drive->mult_count) { ide_hwgroup_t *hwgroup = HWGROUP(drive); - /* - * Ugh.. this part looks ugly because we MUST set up - * the interrupt handler before outputting the first block - * of data to be written. If we hit an error (corrupted buffer list) - * in ide_multwrite(), then we need to remove the handler/timer - * before returning. Fortunately, this NEVER happens (right?). - * - * Except when you get an error it seems... - */ + /* + * Ugh.. this part looks ugly because we MUST set up + * the interrupt handler before outputting the first block + * of data to be written. If we hit an error (corrupted buffer list) + * in ide_multwrite(), then we need to remove the handler/timer + * before returning. Fortunately, this NEVER happens (right?). + * + * Except when you get an error it seems... + */ hwgroup->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); + ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); if (ide_multwrite(drive, drive->mult_count)) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); @@ -462,29 +705,47 @@ return ide_stopped; } +#endif /* __TASKFILE__IO */ + static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive) { MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_DOORLOCK; check_disk_change(inode->i_rdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL)) + if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) drive->doorlocking = 0; } return 0; } +static int do_idedisk_flushcache(ide_drive_t *drive); + static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { if (drive->removable && !drive->usage) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_DOORUNLOCK; invalidate_bdev(inode->i_bdev, 0); - if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL)) + if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) drive->doorlocking = 0; } + if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) + if (do_idedisk_flushcache(drive)) + printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", + drive->name); MOD_DEC_USE_COUNT; } @@ -501,27 +762,234 @@ } /* + * Queries for true maximum capacity of the drive. + * Returns maximum LBA address (> 0) of the drive, 0 if failed. + */ +static unsigned long idedisk_read_native_max_address(ide_drive_t *drive) +{ + ide_task_t args; + unsigned long addr = 0; + + if (!(drive->id->command_set_1 & 0x0400) && + !(drive->id->cfs_enable_2 & 0x0100)) + return addr; + + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; + args.handler = task_no_data_intr; + + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + } + addr++; /* since the return value is (maxlba - 1), we add 1 */ + return addr; +} + +static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive) +{ + ide_task_t args; + unsigned long long addr = 0; + + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; + args.handler = task_no_data_intr; + + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) | + ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | + (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr = ((__u64)high << 24) | low; + } + addr++; /* since the return value is (maxlba - 1), we add 1 */ + return addr; +} + +#ifdef CONFIG_IDEDISK_STROKE +/* + * Sets maximum virtual LBA address of the drive. + * Returns new maximum virtual LBA address (> 0) or 0 on failure. + */ +static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req) +{ + ide_task_t args; + unsigned long addr_set = 0; + + addr_req--; + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; + args.handler = task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + /* if OK, read new maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + } + addr_set++; + return addr_set; +} + +static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req) +{ + ide_task_t args; + unsigned long long addr_set = 0; + + addr_req--; + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT; + args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); + args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40; + args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); + args.handler = task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) | + ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | + (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr_set = ((__u64)high << 24) | low; + } + return addr_set; +} + +/* + * Tests if the drive supports Host Protected Area feature. + * Returns true if supported, false otherwise. + */ +static inline int idedisk_supports_host_protected_area(ide_drive_t *drive) +{ + int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0; + printk("%s: host protected area => %d\n", drive->name, flag); + return flag; +} + +#endif /* CONFIG_IDEDISK_STROKE */ + +/* * Compute drive->capacity, the full capacity of the drive * Called with drive->id != NULL. + * + * To compute capacity, this uses either of + * + * 1. CHS value set by user (whatever user sets will be trusted) + * 2. LBA value from target drive (require new ATA feature) + * 3. LBA value from system BIOS (new one is OK, old one may break) + * 4. CHS value from system BIOS (traditional style) + * + * in above order (i.e., if value of higher priority is available, + * reset will be ignored). */ static void init_idedisk_capacity (ide_drive_t *drive) { struct hd_driveid *id = drive->id; unsigned long capacity = drive->cyl * drive->head * drive->sect; + unsigned long set_max = idedisk_read_native_max_address(drive); + unsigned long long capacity_2 = capacity; + unsigned long long set_max_ext; + drive->capacity48 = 0; drive->select.b.lba = 0; + if (id->cfs_enable_2 & 0x0400) { + capacity_2 = id->lba_capacity_2; + drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect); + drive->head = drive->bios_head = 255; + drive->sect = drive->bios_sect = 63; + drive->select.b.lba = 1; + set_max_ext = idedisk_read_native_max_address_ext(drive); + if (set_max_ext > capacity_2) { +#ifdef CONFIG_IDEDISK_STROKE + set_max_ext = idedisk_read_native_max_address_ext(drive); + set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext); + if (set_max_ext) { + drive->capacity48 = capacity_2 = set_max_ext; + drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect); + drive->select.b.lba = 1; + drive->id->lba_capacity_2 = capacity_2; + } +#else /* !CONFIG_IDEDISK_STROKE */ + printk("%s: setmax_ext LBA %llu, native %llu\n", + drive->name, set_max_ext, capacity_2); +#endif /* CONFIG_IDEDISK_STROKE */ + } + drive->bios_cyl = drive->cyl; + drive->capacity48 = capacity_2; + drive->capacity = (unsigned long) capacity_2; + return; /* Determine capacity, and use LBA if the drive properly supports it */ - if ((id->capability & 2) && lba_capacity_is_ok(id)) { + } else if ((id->capability & 2) && lba_capacity_is_ok(id)) { capacity = id->lba_capacity; drive->cyl = capacity / (drive->head * drive->sect); drive->select.b.lba = 1; } + + if (set_max > capacity) { +#ifdef CONFIG_IDEDISK_STROKE + set_max = idedisk_read_native_max_address(drive); + set_max = idedisk_set_max_address(drive, set_max); + if (set_max) { + drive->capacity = capacity = set_max; + drive->cyl = set_max / (drive->head * drive->sect); + drive->select.b.lba = 1; + drive->id->lba_capacity = capacity; + } +#else /* !CONFIG_IDEDISK_STROKE */ + printk("%s: setmax LBA %lu, native %lu\n", + drive->name, set_max, capacity); +#endif /* CONFIG_IDEDISK_STROKE */ + } + drive->capacity = capacity; + + if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { + drive->capacity48 = id->lba_capacity_2; + drive->head = 255; + drive->sect = 63; + drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect); + } } -static unsigned long idedisk_capacity (ide_drive_t *drive) +static unsigned long idedisk_capacity (ide_drive_t *drive) { + if (drive->id->cfs_enable_2 & 0x0400) + return (drive->capacity48 - drive->sect0); return (drive->capacity - drive->sect0); } @@ -530,23 +998,48 @@ special_t *s = &drive->special; if (s->b.set_geometry) { - s->b.set_geometry = 0; - OUT_BYTE(drive->sect,IDE_SECTOR_REG); - OUT_BYTE(drive->cyl,IDE_LCYL_REG); - OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG); - OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG); - if (!IS_PDC4030_DRIVE) - ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr); + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + ide_handler_t *handler = NULL; + + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + + s->b.set_geometry = 0; + taskfile.sector_number = drive->sect; + taskfile.low_cylinder = drive->cyl; + taskfile.high_cylinder = drive->cyl>>8; + taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF; + if (!IS_PDC4030_DRIVE) { + taskfile.sector_count = drive->sect; + taskfile.command = WIN_SPECIFY; + handler = ide_handler_parser(&taskfile, &hobfile); + } + do_taskfile(drive, &taskfile, &hobfile, handler); } else if (s->b.recalibrate) { s->b.recalibrate = 0; - if (!IS_PDC4030_DRIVE) - ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); + if (!IS_PDC4030_DRIVE) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->sect; + taskfile.command = WIN_RESTORE; + do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + } } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->id && drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; - if (!IS_PDC4030_DRIVE) - ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); + if (!IS_PDC4030_DRIVE) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->mult_req; + taskfile.command = WIN_SETMULT; + do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + } } else if (s->all) { int special = s->all; s->all = 0; @@ -558,9 +1051,11 @@ static void idedisk_pre_reset (ide_drive_t *drive) { + int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1; + drive->special.all = 0; - drive->special.b.set_geometry = 1; - drive->special.b.recalibrate = 1; + drive->special.b.set_geometry = legacy; + drive->special.b.recalibrate = legacy; if (OK_TO_RESET_CONTROLLER) drive->mult_count = 0; if (!drive->keep_settings && !drive->using_dma) @@ -573,19 +1068,45 @@ static int smart_enable(ide_drive_t *drive) { - return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL); + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_ENABLE; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); } static int get_smart_values(ide_drive_t *drive, byte *buf) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_READ_VALUES; + taskfile.sector_count = 0x01; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; (void) smart_enable(drive); - return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf); + return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); } static int get_smart_thresholds(ide_drive_t *drive, byte *buf) { + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = SMART_READ_THRESHOLDS; + taskfile.sector_count = 0x01; + taskfile.low_cylinder = SMART_LCYL_PASS; + taskfile.high_cylinder = SMART_HCYL_PASS; + taskfile.command = WIN_SMART; (void) smart_enable(drive); - return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf); + return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); } static int proc_idedisk_read_cache @@ -609,7 +1130,7 @@ int len = 0, i = 0; if (!get_smart_thresholds(drive, page)) { - unsigned short *val = ((unsigned short *)page) + 2; + unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; do { @@ -628,7 +1149,7 @@ int len = 0, i = 0; if (!get_smart_values(drive, page)) { - unsigned short *val = ((unsigned short *)page) + 2; + unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; do { @@ -656,14 +1177,31 @@ static int set_multcount(ide_drive_t *drive, int arg) { +#ifdef __TASKFILE__IO + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + + if (drive->special.b.set_multmode) + return -EBUSY; + + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.sector_count = drive->mult_req; + taskfile.command = WIN_SETMULT; + drive->mult_req = arg; + drive->special.b.set_multmode = 1; + ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +#else /* !__TASKFILE__IO */ struct request rq; if (drive->special.b.set_multmode) return -EBUSY; ide_init_drive_cmd (&rq); + rq.cmd = IDE_DRIVE_CMD; drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); +#endif /* __TASKFILE__IO */ return (drive->mult_count == arg) ? 0 : -EIO; } @@ -677,6 +1215,79 @@ return 0; } +static int write_cache (ide_drive_t *drive, int arg) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; + taskfile.command = WIN_SETFEATURES; + + if (!(drive->id->cfs_enable_2 & 0x3000)) + return 1; + + (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + drive->wcache = arg; + return 0; +} + +static int do_idedisk_standby (ide_drive_t *drive) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + taskfile.command = WIN_STANDBYNOW1; + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +} + +static int do_idedisk_flushcache (ide_drive_t *drive) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + if (drive->id->cfs_enable_2 & 0x2400) { + taskfile.command = WIN_FLUSH_CACHE_EXT; + } else { + taskfile.command = WIN_FLUSH_CACHE; + } + return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); +} + +static int set_acoustic (ide_drive_t *drive, int arg) +{ + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + + taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM; + taskfile.sector_count = arg; + + taskfile.command = WIN_SETFEATURES; + (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + drive->acoustic = arg; + return 0; +} + +static int probe_lba_addressing (ide_drive_t *drive, int arg) +{ + drive->addressing = 0; + + if (!(drive->id->cfs_enable_2 & 0x0400)) + return -EIO; + + drive->addressing = arg; + return 0; +} + +static int set_lba_addressing (ide_drive_t *drive, int arg) +{ + return (probe_lba_addressing(drive, arg)); +} + static void idedisk_add_settings(ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -686,15 +1297,18 @@ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "address", SETTING_RW, HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, TYPE_INTA, 0, 2, 1, 1, &drive->addressing, set_lba_addressing); ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); - ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 2, &drive->mult_count, set_multcount); + ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 1, &drive->mult_count, set_multcount); ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); - ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, 4096, PAGE_SIZE, 1024, &max_readahead[major][minor], NULL); - ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 1, &max_sectors[major][minor], NULL); ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL); - ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); - ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); + ide_add_setting(drive, "wcache", SETTING_RW, HDIO_GET_WCACHE, HDIO_SET_WCACHE, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache); + ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); + ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); + ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); } static void idedisk_setup (ide_drive_t *drive) @@ -764,7 +1378,6 @@ if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) && (!drive->forced_geom) && drive->bios_sect && drive->bios_head) drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head; - printk (KERN_INFO "%s: %ld sectors", drive->name, capacity); /* Give size in megabytes (MB), not mebibytes (MiB). */ @@ -796,21 +1409,25 @@ drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) drive->special.b.set_multmode = 1; -#endif +#endif /* CONFIG_IDEDISK_MULTI_MODE */ } drive->no_io_32bit = id->dword_io ? 1 : 0; -} - -static int idedisk_reinit (ide_drive_t *drive) -{ - return 0; + if (drive->id->cfs_enable_2 & 0x3000) + write_cache(drive, (id->cfs_enable_2 & 0x3000)); + (void) probe_lba_addressing(drive, 1); } static int idedisk_cleanup (ide_drive_t *drive) { + if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) + if (do_idedisk_flushcache(drive)) + printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", + drive->name); return ide_unregister_subdriver(drive); } +int idedisk_reinit(ide_drive_t *drive); + /* * IDE subdriver functions, registered with ide.c */ @@ -822,6 +1439,8 @@ supports_dma: 1, supports_dsc_overlap: 0, cleanup: idedisk_cleanup, + standby: do_idedisk_standby, + flushcache: do_idedisk_flushcache, do_request: do_rw_disk, end_request: NULL, ioctl: NULL, @@ -833,7 +1452,9 @@ capacity: idedisk_capacity, special: idedisk_special, proc: idedisk_proc, - driver_reinit: idedisk_reinit, + reinit: idedisk_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, }; int idedisk_init (void); @@ -846,6 +1467,32 @@ MODULE_DESCRIPTION("ATA DISK Driver"); +int idedisk_reinit (ide_drive_t *drive) +{ + int failed = 0; + + MOD_INC_USE_COUNT; + + if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + return 1; + } + DRIVER(drive)->busy++; + idedisk_setup(drive); + if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { + printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); + (void) idedisk_cleanup(drive); + DRIVER(drive)->busy--; + return 1; + } + DRIVER(drive)->busy--; + failed--; + + ide_register_module(&idedisk_module); + MOD_DEC_USE_COUNT; + return 0; +} + static void __exit idedisk_exit (void) { ide_drive_t *drive; @@ -877,12 +1524,15 @@ printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); continue; } + DRIVER(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); (void) idedisk_cleanup(drive); + DRIVER(drive)->busy--; continue; } + DRIVER(drive)->busy--; failed--; } ide_register_module(&idedisk_module); diff -urN linux-2.4.18/drivers/ide/ide-dma.c linux-2.4.19-pre5/drivers/ide/ide-dma.c --- linux-2.4.18/drivers/ide/ide-dma.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-dma.c Sat Mar 30 22:55:34 2002 @@ -123,6 +123,7 @@ { "WDC AC11000H" , "ALL" }, { "WDC AC22100H" , "ALL" }, + { "WDC AC31000H" , "ALL" }, { "WDC AC32500H" , "ALL" }, { "WDC AC33100H" , "ALL" }, { "WDC AC31600H" , "ALL" }, @@ -282,6 +283,37 @@ return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } +static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq) +{ + struct scatterlist *sg = hwif->sg_table; + int nents = 0; + ide_task_t *args = rq->special; + unsigned char *virt_addr = rq->buffer; + int sector_count = rq->nr_sectors; + +// if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) || +// (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT)) + if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) + hwif->sg_dma_direction = PCI_DMA_TODEVICE; + else + hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; + + if (sector_count > 128) { + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = 128 * SECTOR_SIZE; + nents++; + virt_addr = virt_addr + (128 * SECTOR_SIZE); + sector_count -= 128; + } + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = sector_count * SECTOR_SIZE; + nents++; + + return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); +} + /* * ide_build_dmatable() prepares a dma request. * Returns 0 if all went okay, returns 1 otherwise. @@ -299,7 +331,10 @@ int i; struct scatterlist *sg; - HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) + HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq); + else + HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); if (!i) return 0; @@ -429,7 +464,14 @@ struct hd_driveid *id = drive->id; if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && - (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { + (id->dma_ultra & (id->dma_ultra >> 14) & 3)) { + if ((id->dma_ultra >> 15) & 1) { + printk(", UDMA(mode 7)"); /* UDMA BIOS-enabled! */ + } else { + printk(", UDMA(133)"); /* UDMA BIOS-enabled! */ + } + } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) && + (id->dma_ultra & (id->dma_ultra >> 11) & 7)) { if ((id->dma_ultra >> 13) & 1) { printk(", UDMA(100)"); /* UDMA BIOS-enabled! */ } else if ((id->dma_ultra >> 12) & 1) { @@ -456,14 +498,24 @@ static int config_drive_for_dma (ide_drive_t *drive) { + int config_allows_dma = 1; struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - if (id && (id->capability & 1) && hwif->autodma) { +#ifdef CONFIG_IDEDMA_ONLYDISK + if (drive->media != ide_disk) + config_allows_dma = 0; +#endif + + if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); + /* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */ + if ((id->field_valid & 4) && (eighty_ninty_three(drive))) + if ((id->dma_ultra & (id->dma_ultra >> 14) & 2)) + return hwif->dmaproc(ide_dma_on, drive); /* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */ if ((id->field_valid & 4) && (eighty_ninty_three(drive))) if ((id->dma_ultra & (id->dma_ultra >> 11) & 7)) @@ -495,7 +547,7 @@ printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); #endif /* DEBUG */ -#if 1 +#if 0 HWGROUP(drive)->expiry = NULL; /* one free ride for now */ #endif @@ -550,7 +602,7 @@ */ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { -// ide_hwgroup_t *hwgroup = HWGROUP(drive); +// ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); @@ -582,11 +634,20 @@ if (drive->media != ide_disk) return 0; #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL); /* issue cmd to drive */ #else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && + (drive->addressing == 1)) { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing) { + OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + } + return HWIF(drive)->dmaproc(ide_dma_begin, drive); case ide_dma_begin: /* Note that this is done *after* the cmd has * been issued to the drive, as per the BM-IDE spec. @@ -604,7 +665,7 @@ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ dma_stat = inb(dma_base+2); -#if 0 /* do not set unless you know what you are doing */ +#if 0 /* do not set unless you know what you are doing */ if (dma_stat & 4) { byte stat = GET_STAT(); outb(dma_base+2, dma_stat & 0xE4); @@ -649,6 +710,8 @@ GET_STAT(), dma_stat); return restart_request(drive); // BUG: return types do not match!! +//#else +// return HWGROUP(drive)->handler(drive); #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ case ide_dma_retune: case ide_dma_lostirq: diff -urN linux-2.4.18/drivers/ide/ide-features.c linux-2.4.19-pre5/drivers/ide/ide-features.c --- linux-2.4.18/drivers/ide/ide-features.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-features.c Sat Mar 30 22:55:34 2002 @@ -127,30 +127,14 @@ case XFER_UDMA_3: return XFER_UDMA_2; case XFER_UDMA_2: return XFER_UDMA_1; case XFER_UDMA_1: return XFER_UDMA_0; + /* + * OOPS we do not goto non Ultra DMA modes + * without iCRC's available we force + * the system to PIO and make the user + * invoke the ATA-1 ATA-2 DMA modes. + */ case XFER_UDMA_0: - if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2; - else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1; - else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0; - else return XFER_PIO_4; - case XFER_MW_DMA_2: return XFER_MW_DMA_1; - case XFER_MW_DMA_1: return XFER_MW_DMA_0; - case XFER_MW_DMA_0: - if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2; - else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1; - else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0; - else return XFER_PIO_4; - case XFER_SW_DMA_2: return XFER_SW_DMA_1; - case XFER_SW_DMA_1: return XFER_SW_DMA_0; - case XFER_SW_DMA_0: - { - return XFER_PIO_4; - } - case XFER_PIO_4: return XFER_PIO_3; - case XFER_PIO_3: return XFER_PIO_2; - case XFER_PIO_2: return XFER_PIO_1; - case XFER_PIO_1: return XFER_PIO_0; - case XFER_PIO_0: - default: return XFER_PIO_SLOW; + default: return XFER_PIO_4; } } @@ -216,11 +200,11 @@ * in combination with the device (usually a disk) properly detect * and acknowledge each end of the ribbon. */ -int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature) +int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) { - if ((cmd == WIN_SETFEATURES) && - (nsect > XFER_UDMA_2) && - (feature == SETFEATURES_XFER)) { + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) { if (!HWIF(drive)->udma_four) { printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name); return 1; @@ -243,11 +227,11 @@ * 1 : Safe to update drive->id DMA registers. * 0 : OOPs not allowed. */ -int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature) +int set_transfer (ide_drive_t *drive, ide_task_t *args) { - if ((cmd == WIN_SETFEATURES) && - (nsect >= XFER_SW_DMA_0) && - (feature == SETFEATURES_XFER) && + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) && (drive->id->dma_ultra || drive->id->dma_mword || drive->id->dma_1word)) @@ -389,3 +373,4 @@ EXPORT_SYMBOL(set_transfer); EXPORT_SYMBOL(eighty_ninty_three); EXPORT_SYMBOL(ide_config_drive_speed); + diff -urN linux-2.4.18/drivers/ide/ide-floppy.c linux-2.4.19-pre5/drivers/ide/ide-floppy.c --- linux-2.4.18/drivers/ide/ide-floppy.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-floppy.c Sat Mar 30 22:55:34 2002 @@ -1,8 +1,8 @@ /* - * linux/drivers/ide/ide-floppy.c Version 0.97.sv Jan 14 2001 + * linux/drivers/ide/ide-floppy.c Version 0.99 Feb 24 2002 * * Copyright (C) 1996 - 1999 Gadi Oxman - * Copyright (C) 2000 - 2001 Paul Bristow + * Copyright (C) 2000 - 2002 Paul Bristow */ /* @@ -13,7 +13,7 @@ * * This driver supports the following IDE floppy drives: * - * LS-120 SuperDisk + * LS-120/240 SuperDisk * Iomega Zip 100/250 * Iomega PC Card Clik!/PocketZip * @@ -71,9 +71,16 @@ * including set_bit patch from Rusty Russel * Ver 0.97 Jul 22 01 Merge 0.91-0.96 onto 0.9.sv for ac series * Ver 0.97.sv Aug 3 01 Backported from 2.4.7-ac3 + * Ver 0.98 Oct 26 01 Split idefloppy_transfer_pc into two pieces to + * fix a lost interrupt problem. It appears the busy + * bit was being deasserted by my IOMEGA ATAPI ZIP 100 + * drive before the drive was actually ready. + * Ver 0.98a Oct 29 01 Expose delay value so we can play. + * Ver 0.99 Feb 24 02 Remove duplicate code, modify clik! detection code + * to support new PocketZip drives */ -#define IDEFLOPPY_VERSION "0.97.sv" +#define IDEFLOPPY_VERSION "0.99.newide" #include #include @@ -276,6 +283,7 @@ * Last error information */ byte sense_key, asc, ascq; + byte ticks; /* delay this long before sending packet command */ int progress_indication; /* @@ -289,6 +297,8 @@ unsigned long flags; /* Status/Action flags */ } idefloppy_floppy_t; +#define IDEFLOPPY_TICKS_DELAY 3 /* default delay for ZIP 100 */ + /* * Floppy flag bits values. */ @@ -297,7 +307,7 @@ #define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */ #define IDEFLOPPY_FORMAT_IN_PROGRESS 3 /* Format in progress */ #define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */ - +#define IDEFLOPPY_ZIP_DRIVE 5 /* Requires BH algorithm for packets */ /* * ATAPI floppy drive packet commands @@ -1001,6 +1011,11 @@ return ide_started; } +/* + * This is the original routine that did the packet transfer. + * It fails at high speeds on the Iomega ZIP drive, so there's a slower version + * for that drive below. The algorithm is chosen based on drive type + */ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive) { ide_startstop_t startstop; @@ -1021,6 +1036,56 @@ return ide_started; } + +/* + * What we have here is a classic case of a top half / bottom half + * interrupt service routine. In interrupt mode, the device sends + * an interrupt to signal it's ready to receive a packet. However, + * we need to delay about 2-3 ticks before issuing the packet or we + * gets in trouble. + * + * So, follow carefully. transfer_pc1 is called as an interrupt (or + * directly). In either case, when the device says it's ready for a + * packet, we schedule the packet transfer to occur about 2-3 ticks + * later in transfer_pc2. + */ +static int idefloppy_transfer_pc2 (ide_drive_t *drive) +{ + idefloppy_floppy_t *floppy = drive->driver_data; + + atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ + return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */ +} + +static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive) +{ + idefloppy_floppy_t *floppy = drive->driver_data; + ide_startstop_t startstop; + idefloppy_ireason_reg_t ireason; + + if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n"); + return startstop; + } + ireason.all=IN_BYTE (IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { + printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); + return ide_do_reset (drive); + } + /* + * The following delay solves a problem with ATAPI Zip 100 drives where the + * Busy flag was apparently being deasserted before the unit was ready to + * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01 + * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will + * not be actually used until after the packet is moved in about 50 msec. + */ + ide_set_handler (drive, + &idefloppy_pc_intr, /* service routine for packet command */ + floppy->ticks, /* wait this long before "failing" */ + &idefloppy_transfer_pc2); /* fail == transfer_pc2 */ + return ide_started; +} + /* * Issue a packet command */ @@ -1029,6 +1094,7 @@ idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_bcount_reg_t bcount; int dma_ok = 0; + ide_handler_t *pkt_xfer_routine; #if IDEFLOPPY_DEBUG_BUGS if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { @@ -1088,13 +1154,20 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ + /* Can we transfer the packet when we get the interrupt or wait? */ + if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) { + pkt_xfer_routine = &idefloppy_transfer_pc1; /* wait */ + } else { + pkt_xfer_routine = &idefloppy_transfer_pc; /* immediate */ + } + if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL); + ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); - return idefloppy_transfer_pc (drive); + return (*pkt_xfer_routine) (drive); } } @@ -1914,13 +1987,18 @@ { int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; + idefloppy_floppy_t *floppy = drive->driver_data; +/* + * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function + */ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + ide_add_setting(drive, "ticks", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &floppy->ticks, NULL); } @@ -1954,27 +2032,19 @@ if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) { + set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags); + /* This value will be visible in the /proc/ide/hdx/settings */ + floppy->ticks = IDEFLOPPY_TICKS_DELAY; for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; } - /* - * Guess what? The IOMEGA Clik! drive also needs the - * above fix. It makes nasty clicking noises without - * it, so please don't remove this. - */ - if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) - { - for (i = 0; i < 1 << PARTN_BITS; i++) - max_sectors[major][minor + i] = 64; - set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags); - } /* * Guess what? The IOMEGA Clik! drive also needs the * above fix. It makes nasty clicking noises without * it, so please don't remove this. */ - if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) + if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) { for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; @@ -2019,10 +2089,7 @@ #endif /* CONFIG_PROC_FS */ -static int idefloppy_reinit (ide_drive_t *drive) -{ - return 0; -} +int idefloppy_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c @@ -2035,6 +2102,8 @@ supports_dma: 1, supports_dsc_overlap: 0, cleanup: idefloppy_cleanup, + standby: NULL, + flushcache: NULL, do_request: idefloppy_do_request, end_request: idefloppy_end_request, ioctl: idefloppy_ioctl, @@ -2046,7 +2115,9 @@ capacity: idefloppy_capacity, special: NULL, proc: idefloppy_proc, - driver_reinit: idefloppy_reinit, + reinit: idefloppy_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, }; int idefloppy_init (void); @@ -2057,6 +2128,40 @@ NULL }; +int idefloppy_reinit (ide_drive_t *drive) +{ + idefloppy_floppy_t *floppy; + int failed = 0; + + MOD_INC_USE_COUNT; + while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { + if (!idefloppy_identify_device (drive, drive->id)) { + printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); + continue; + } + if (drive->scsi) { + printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); + continue; + } + if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { + printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); + continue; + } + if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); + kfree (floppy); + continue; + } + DRIVER(drive)->busy++; + idefloppy_setup (drive, floppy); + DRIVER(drive)->busy--; + failed--; + } + ide_register_module(&idefloppy_module); + MOD_DEC_USE_COUNT; + return 0; +} + MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); static void __exit idefloppy_exit (void) @@ -2108,7 +2213,9 @@ kfree (floppy); continue; } + DRIVER(drive)->busy++; idefloppy_setup (drive, floppy); + DRIVER(drive)->busy--; failed--; } ide_register_module(&idefloppy_module); diff -urN linux-2.4.18/drivers/ide/ide-geometry.c linux-2.4.19-pre5/drivers/ide/ide-geometry.c --- linux-2.4.18/drivers/ide/ide-geometry.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-geometry.c Sat Mar 30 22:55:34 2002 @@ -6,6 +6,8 @@ #include #include +#ifdef CONFIG_BLK_DEV_IDE + /* * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc * controller that is BIOS compatible with ST-506, and thus showing up in our @@ -40,7 +42,11 @@ * Consequently, also the former "drive->present = 1" below was a mistake. * * Eventually the entire routine below should be removed. + * + * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS + * chip. */ + void probe_cmos_for_drives (ide_hwif_t *hwif) { #ifdef __i386__ @@ -80,9 +86,10 @@ } #endif } +#endif /* CONFIG_BLK_DEV_IDE */ -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) extern ide_drive_t * get_info_ptr(kdev_t); extern unsigned long current_capacity (ide_drive_t *); @@ -214,4 +221,4 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ diff -urN linux-2.4.18/drivers/ide/ide-pci.c linux-2.4.19-pre5/drivers/ide/ide-pci.c --- linux-2.4.18/drivers/ide/ide-pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-pci.c Sat Mar 30 22:55:39 2002 @@ -12,6 +12,13 @@ * configuration of all PCI IDE interfaces present in a system. */ +/* + * Chipsets that are on the IDE_IGNORE list because of problems of not being + * set at compile time. + * + * CONFIG_BLK_DEV_PDC202XX + */ + #include #include #include @@ -47,6 +54,9 @@ #define DEVID_PDC20267 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267}) #define DEVID_PDC20268 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268}) #define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R}) +#define DEVID_PDC20269 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269}) +#define DEVID_PDC20275 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275}) +#define DEVID_PDC20276 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276}) #define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) #define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) #define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE}) @@ -55,6 +65,7 @@ #define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) #define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648}) #define DEVID_CMD649 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649}) +#define DEVID_CMD680 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680}) #define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) #define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) #define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) @@ -79,6 +90,7 @@ #define DEVID_AMD7401 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401}) #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define DEVID_AMD7411 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411}) +#define DEVID_AMD7441 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7441}) #define DEVID_PDCADMA ((ide_pci_devid_t){PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841}) #define DEVID_SLC90E66 ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1}) #define DEVID_OSB4 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE}) @@ -86,6 +98,7 @@ #define DEVID_ITE8172G ((ide_pci_devid_t){PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G}) #define IDE_IGNORE ((void *)-1) +#define IDE_NO_DRIVER ((void *)-2) #ifdef CONFIG_BLK_DEV_AEC62XX extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *); @@ -99,7 +112,7 @@ #else #define PCI_AEC62XX NULL #define ATA66_AEC62XX NULL -#define INIT_AEC62XX NULL +#define INIT_AEC62XX IDE_NO_DRIVER #define DMA_AEC62XX NULL #endif @@ -115,7 +128,7 @@ #else #define PCI_ALI15X3 NULL #define ATA66_ALI15X3 NULL -#define INIT_ALI15X3 NULL +#define INIT_ALI15X3 IDE_NO_DRIVER #define DMA_ALI15X3 NULL #endif @@ -131,7 +144,7 @@ #else #define PCI_AMD74XX NULL #define ATA66_AMD74XX NULL -#define INIT_AMD74XX NULL +#define INIT_AMD74XX IDE_NO_DRIVER #define DMA_AMD74XX NULL #endif @@ -149,7 +162,7 @@ #ifdef __sparc_v9__ #define INIT_CMD64X IDE_IGNORE #else -#define INIT_CMD64X NULL +#define INIT_CMD64X IDE_NO_DRIVER #endif #endif @@ -160,7 +173,7 @@ #define INIT_CY82C693 &ide_init_cy82c693 #else #define PCI_CY82C693 NULL -#define INIT_CY82C693 NULL +#define INIT_CY82C693 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_CS5530 @@ -170,7 +183,7 @@ #define INIT_CS5530 &ide_init_cs5530 #else #define PCI_CS5530 NULL -#define INIT_CS5530 NULL +#define INIT_CS5530 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_HPT34X @@ -199,7 +212,7 @@ static byte hpt363_shared_pin; #define PCI_HPT366 NULL #define ATA66_HPT366 NULL -#define INIT_HPT366 NULL +#define INIT_HPT366 IDE_NO_DRIVER #define DMA_HPT366 NULL #endif @@ -214,7 +227,7 @@ extern void ide_init_opti621(ide_hwif_t *); #define INIT_OPTI621 &ide_init_opti621 #else -#define INIT_OPTI621 NULL +#define INIT_OPTI621 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_PDC_ADMA @@ -241,9 +254,9 @@ #define ATA66_PDC202XX &ata66_pdc202xx #define INIT_PDC202XX &ide_init_pdc202xx #else -#define PCI_PDC202XX NULL -#define ATA66_PDC202XX NULL -#define INIT_PDC202XX NULL +#define PCI_PDC202XX IDE_IGNORE +#define ATA66_PDC202XX IDE_IGNORE +#define INIT_PDC202XX IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_PIIX @@ -256,7 +269,7 @@ #else #define PCI_PIIX NULL #define ATA66_PIIX NULL -#define INIT_PIIX NULL +#define INIT_PIIX IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_IT8172 @@ -290,7 +303,7 @@ #else #define PCI_SVWKS NULL #define ATA66_SVWKS NULL -#define INIT_SVWKS NULL +#define INIT_SVWKS IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SIS5513 @@ -303,7 +316,7 @@ #else #define PCI_SIS5513 NULL #define ATA66_SIS5513 NULL -#define INIT_SIS5513 NULL +#define INIT_SIS5513 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SLC90E66 @@ -316,7 +329,7 @@ #else #define PCI_SLC90E66 NULL #define ATA66_SLC90E66 NULL -#define INIT_SLC90E66 NULL +#define INIT_SLC90E66 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SL82C105 @@ -351,7 +364,7 @@ #else #define PCI_VIA82CXXX NULL #define ATA66_VIA82CXXX NULL -#define INIT_VIA82CXXX NULL +#define INIT_VIA82CXXX IDE_NO_DRIVER #define DMA_VIA82CXXX NULL #endif @@ -393,7 +406,7 @@ #ifdef CONFIG_PDC202XX_FORCE {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, + {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 }, {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, #else /* !CONFIG_PDC202XX_FORCE */ {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -401,11 +414,14 @@ {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, #endif - {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, + {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, /* Promise used a different PCI ident for the raid card apparently to try and prevent Linux detecting it and using our own raid code. We want to detect it for the ataraid drivers, so we have to list both here.. */ - {DEVID_PDC20268R,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, + {DEVID_PDC20268R,"PDC20270", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20269,"PDC20269", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20275,"PDC20275", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20276,"PDC20276", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -416,6 +432,11 @@ {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CMD649, "CMD649", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, +#ifndef CONFIG_BLK_DEV_CMD680 + {DEVID_CMD680, "CMD680", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, +#else /* CONFIG_BLK_DEV_CMD680 */ + {DEVID_CMD680, "CMD680", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, +#endif /* !CONFIG_BLK_DEV_CMD680 */ {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, @@ -434,9 +455,10 @@ {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {DEVID_AMD7409, "AMD7409", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {DEVID_AMD7411, "AMD7411", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7441, "AMD7441", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {DEVID_PDCADMA, "PDCADMA", PCI_PDCADMA, ATA66_PDCADMA, INIT_PDCADMA, DMA_PDCADMA, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, {DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_OSB4, "ServerWorks OSB4", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -458,6 +480,10 @@ case PCI_DEVICE_ID_PROMISE_20265: case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20268R: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_ARTOP_ATP850UF: case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: @@ -592,7 +618,15 @@ autodma = 1; #endif - pci_enable_device(dev); + if (d->init_hwif == IDE_NO_DRIVER) { + printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name); + d->init_hwif = NULL; + } + + if (pci_enable_device(dev)) { + printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name); + return; + } check_if_enabled: if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) { @@ -752,7 +786,8 @@ } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX)) goto bypass_piix_dma; - + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA)) + goto bypass_legacy_dma; if (hwif->udma_four) { printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); } else { @@ -769,12 +804,16 @@ autodma = 0; if (autodma) hwif->autodma = 1; + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || @@ -785,6 +824,7 @@ IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) || IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) || ((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); @@ -811,6 +851,7 @@ } } #endif /* CONFIG_BLK_DEV_IDEDMA */ +bypass_legacy_dma: bypass_piix_dma: bypass_umc_dma: if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ @@ -822,20 +863,60 @@ printk("%s: neither IDE port enabled (BIOS)\n", d->name); } +static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +{ + struct pci_dev *dev2 = NULL, *findev; + ide_pci_device_t *d2; + + if ((dev->bus->self && + dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && + (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { + if (PCI_SLOT(dev->devfn) & 2) { + return; + } + d->extra = 0; + pci_for_each_dev(findev) { + if ((findev->vendor == dev->vendor) && + (findev->device == dev->device) && + (PCI_SLOT(findev->devfn) & 2)) { + byte irq = 0, irq2 = 0; + dev2 = findev; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); + if (irq != irq2) { + dev2->irq = dev->irq; + pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq); + } + + } + } + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + if (!dev2) + return; + d2 = d; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); +} + static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *dev2 = NULL, *findev; ide_pci_device_t *d2; unsigned char pin1 = 0, pin2 = 0; unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"}; + char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"}; if (PCI_FUNC(dev->devfn) & 1) return; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - + if (class_rev > 5) + class_rev = 5; + strcpy(d->name, chipset_names[class_rev]); switch(class_rev) { @@ -902,6 +983,8 @@ return; /* UM8886A/BF pair */ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) hpt366_device_order_fixup(dev, d); + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R)) + pdc20270_device_order_fixup(dev, d); else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", diff -urN linux-2.4.18/drivers/ide/ide-probe.c linux-2.4.19-pre5/drivers/ide/ide-probe.c --- linux-2.4.18/drivers/ide/ide-probe.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-probe.c Sat Mar 30 22:55:34 2002 @@ -58,6 +58,11 @@ struct hd_driveid *id; id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC); /* called with interrupts disabled! */ + if (!id) { + printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n"); + goto err_kmalloc; + } + ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); @@ -76,8 +81,7 @@ if ((id->model[0] == 'P' && id->model[1] == 'M') || (id->model[0] == 'S' && id->model[1] == 'K')) { printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model); - drive->present = 0; - return; + goto err_misc; } #endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */ @@ -96,7 +100,7 @@ ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); if (strstr(id->model, "E X A B Y T E N E S T")) - return; + goto err_misc; id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */ printk("%s: %s, ", drive->name, id->model); @@ -111,8 +115,7 @@ #ifdef CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) { printk(" -- not supported on 2nd Promise port\n"); - drive->present = 0; - return; + goto err_misc; } #endif /* CONFIG_BLK_DEV_PDC4030 */ switch (type) { @@ -174,6 +177,12 @@ printk("ATA DISK drive\n"); QUIRK_LIST(HWIF(drive),drive); return; + +err_misc: + kfree(id); +err_kmalloc: + drive->present = 0; + return; } /* @@ -370,7 +379,7 @@ OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; do { - if (jiffies > timeout) { + if (time_after(jiffies, timeout)) { printk("failed (timeout)\n"); return; } @@ -597,6 +606,12 @@ q->queuedata = HWGROUP(drive); blk_init_queue(q, do_ide_request); + + if (drive->media == ide_disk) { +#ifdef CONFIG_BLK_DEV_ELEVATOR_NOOP + elevator_init(&q->elevator, ELEVATOR_NOOP); +#endif + } } /* @@ -685,6 +700,10 @@ #else /* !CONFIG_IDEPCI_SHARE_IRQ */ int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; #endif /* CONFIG_IDEPCI_SHARE_IRQ */ + + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */ + if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); @@ -752,18 +771,35 @@ int *bs, *max_sect, *max_ra; extern devfs_handle_t ide_devfs_handle; +#if 1 + units = MAX_DRIVES; +#else /* figure out maximum drive number on the interface */ for (units = MAX_DRIVES; units > 0; --units) { if (hwif->drives[units-1].present) break; } +#endif + minors = units * (1<sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); + if (!gd->sizes) + goto err_kmalloc_gd_sizes; gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); + if (!gd->part) + goto err_kmalloc_gd_part; bs = kmalloc (minors*sizeof(int), GFP_KERNEL); + if (!bs) + goto err_kmalloc_bs; max_sect = kmalloc (minors*sizeof(int), GFP_KERNEL); + if (!max_sect) + goto err_kmalloc_max_sect; max_ra = kmalloc (minors*sizeof(int), GFP_KERNEL); + if (!max_ra) + goto err_kmalloc_max_ra; memset(gd->part, 0, minors * sizeof(struct hd_struct)); @@ -773,12 +809,10 @@ max_readahead[hwif->major] = max_ra; for (unit = 0; unit < minors; ++unit) { *bs++ = BLOCK_SIZE; -#ifdef CONFIG_BLK_DEV_PDC4030 - *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 255); -#else - /* IDE can do up to 128K per request. */ - *max_sect++ = 255; -#endif + /* + * IDE can do up to 128K per request == 256 + */ + *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128); *max_ra++ = vm_max_readahead; } @@ -804,6 +838,17 @@ add_gendisk(gd); for (unit = 0; unit < units; ++unit) { +#if 1 + char name[64]; + ide_add_generic_settings(hwif->drives + unit); + hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); + sprintf (name, "host%d/bus%d/target%d/lun%d", + (hwif->channel && hwif->mate) ? + hwif->mate->index : hwif->index, + hwif->channel, unit, hwif->drives[unit].lun); + if (hwif->drives[unit].present) + hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); +#else if (hwif->drives[unit].present) { char name[64]; @@ -815,7 +860,23 @@ hwif->drives[unit].de = devfs_mk_dir (ide_devfs_handle, name, NULL); } +#endif } + return; + +err_kmalloc_max_ra: + kfree(max_sect); +err_kmalloc_max_sect: + kfree(bs); +err_kmalloc_bs: + kfree(gd->part); +err_kmalloc_gd_part: + kfree(gd->sizes); +err_kmalloc_gd_sizes: + kfree(gd); +err_kmalloc_gd: + printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n"); + return; } static int hwif_init (ide_hwif_t *hwif) @@ -880,6 +941,19 @@ return hwif->present; } +void export_ide_init_queue (ide_drive_t *drive) +{ + ide_init_queue(drive); +} + +byte export_probe_for_drive (ide_drive_t *drive) +{ + return probe_for_drive(drive); +} + +EXPORT_SYMBOL(export_ide_init_queue); +EXPORT_SYMBOL(export_probe_for_drive); + int ideprobe_init (void); static ide_module_t ideprobe_module = { IDE_PROBE_MODULE, @@ -913,6 +987,8 @@ } #ifdef MODULE +extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *); + int init_module (void) { unsigned int index; @@ -921,12 +997,14 @@ ide_unregister(index); ideprobe_init(); create_proc_ide_interfaces(); + ide_xlate_1024_hook = ide_xlate_1024; return 0; } void cleanup_module (void) { ide_probe = NULL; + ide_xlate_1024_hook = 0; } MODULE_LICENSE("GPL"); #endif /* MODULE */ diff -urN linux-2.4.18/drivers/ide/ide-proc.c linux-2.4.19-pre5/drivers/ide/ide-proc.c --- linux-2.4.18/drivers/ide/ide-proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-proc.c Sat Mar 30 22:55:34 2002 @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -447,7 +448,15 @@ static int proc_ide_get_identify(ide_drive_t *drive, byte *buf) { - return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf); + struct hd_drive_task_hdr taskfile; + struct hd_drive_hob_hdr hobfile; + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); + + taskfile.sector_count = 0x01; + taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ; + + return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); } static int proc_ide_read_identify @@ -457,7 +466,7 @@ int len = 0, i = 0; if (drive && !proc_ide_get_identify(drive, page)) { - unsigned short *val = ((unsigned short *)page) + 2; + unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; do { @@ -588,7 +597,7 @@ if (!driver) len = sprintf(page, "(none)\n"); else - len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive)); + len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive)); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -732,22 +741,57 @@ } } -void destroy_proc_ide_drives(ide_hwif_t *hwif) +void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) { - int d; + struct proc_dir_entry *ent; + struct proc_dir_entry *parent = hwif->proc; + char name[64]; +// ide_driver_t *driver = drive->driver; - for (d = 0; d < MAX_DRIVES; d++) { - ide_drive_t *drive = &hwif->drives[d]; - ide_driver_t *driver = drive->driver; + if (drive->present && !drive->proc) { + drive->proc = proc_mkdir(drive->name, parent); + if (drive->proc) + ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - if (!drive->proc) - continue; +/* + * assume that we have these already, however, should test FIXME! + * if (driver) { + * ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); + * ide_add_proc_entries(drive->proc, driver->proc, drive); + * } + * + */ + sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); + ent = proc_symlink(drive->name, proc_ide_root, name); + if (!ent) + return; + } +} + +void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) +{ + ide_driver_t *driver = drive->driver; + + if (drive->proc) { if (driver) ide_remove_proc_entries(drive->proc, driver->proc); ide_remove_proc_entries(drive->proc, generic_drive_entries); remove_proc_entry(drive->name, proc_ide_root); remove_proc_entry(drive->name, hwif->proc); drive->proc = NULL; + } +} + +void destroy_proc_ide_drives(ide_hwif_t *hwif) +{ + int d; + + for (d = 0; d < MAX_DRIVES; d++) { + ide_drive_t *drive = &hwif->drives[d]; +// ide_driver_t *driver = drive->driver; + + if (drive->proc) + destroy_proc_ide_device(hwif, drive); } } diff -urN linux-2.4.18/drivers/ide/ide-swarm.c linux-2.4.19-pre5/drivers/ide/ide-swarm.c --- linux-2.4.18/drivers/ide/ide-swarm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ide/ide-swarm.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Derived loosely from ide-pmac.c, so: + * + * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1995-1998 Mark Lord + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void __init swarm_ide_probe(void) +{ + int i; + ide_hwif_t *hwif; + /* + * Find the first untaken slot in hwifs + */ + for (i = 0; i < MAX_HWIFS; i++) { + if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) { + break; + } + } + if (i == MAX_HWIFS) { + printk("No space for SWARM onboard IDE driver in ide_hwifs[]. Not enabled.\n"); + return; + } + + /* Set up our stuff */ + hwif = &ide_hwifs[i]; + hwif->hw.io_ports[IDE_DATA_OFFSET] = SWARM_IDE_REG(0x1f0); + hwif->hw.io_ports[IDE_ERROR_OFFSET] = SWARM_IDE_REG(0x1f1); + hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2); + hwif->hw.io_ports[IDE_SECTOR_OFFSET] = SWARM_IDE_REG(0x1f3); + hwif->hw.io_ports[IDE_LCYL_OFFSET] = SWARM_IDE_REG(0x1f4); + hwif->hw.io_ports[IDE_HCYL_OFFSET] = SWARM_IDE_REG(0x1f5); + hwif->hw.io_ports[IDE_SELECT_OFFSET] = SWARM_IDE_REG(0x1f6); + hwif->hw.io_ports[IDE_STATUS_OFFSET] = SWARM_IDE_REG(0x1f7); + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6); + hwif->hw.io_ports[IDE_IRQ_OFFSET] = SWARM_IDE_REG(0x3f7); +// hwif->hw->ack_intr = swarm_ide_ack_intr; + hwif->hw.irq = SWARM_IDE_INT; + hwif->ideproc = swarm_ideproc; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->irq = hwif->hw.irq; + printk("SWARM onboard IDE configured as device %i\n", i); +} + diff -urN linux-2.4.18/drivers/ide/ide-tape.c linux-2.4.19-pre5/drivers/ide/ide-tape.c --- linux-2.4.18/drivers/ide/ide-tape.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ide/ide-tape.c Sat Mar 30 22:55:39 2002 @@ -2418,26 +2418,26 @@ idetape_tape_t *tape = drive->driver_data; int full = 125, empty = 75; - if (jiffies > tape->controlled_pipeline_head_time + 120 * HZ) { + if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) { tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head; tape->controlled_previous_head_time = tape->controlled_pipeline_head_time; tape->controlled_last_pipeline_head = tape->pipeline_head; tape->controlled_pipeline_head_time = jiffies; } - if (jiffies > tape->controlled_pipeline_head_time + 60 * HZ) + if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ)) tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time); - else if (jiffies > tape->controlled_previous_head_time) + else if (time_after(jiffies, tape->controlled_previous_head_time)) tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time); if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */ - if (jiffies > tape->uncontrolled_previous_head_time + 10 * HZ) { + if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) { tape->uncontrolled_pipeline_head_time = jiffies; tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time); } } else { tape->uncontrolled_previous_head_time = jiffies; tape->uncontrolled_previous_pipeline_head = tape->pipeline_head; - if (jiffies > tape->uncontrolled_pipeline_head_time + 30 * HZ) { + if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) { tape->uncontrolled_pipeline_head_time = jiffies; } } @@ -2500,7 +2500,7 @@ tape->insert_time = jiffies; tape->insert_size = 0; } - if (jiffies > tape->insert_time) + if (time_after(jiffies, tape->insert_time)) tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); if (jiffies - tape->avg_time >= HZ) { tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024; @@ -2680,11 +2680,11 @@ tape->reads_since_buffer_fill = 0; tape->last_buffer_fill = jiffies; idetape_queue_onstream_buffer_fill(drive); - if (jiffies > tape->insert_time) + if (time_after(jiffies, tape->insert_time)) tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); return ide_stopped; } - if (jiffies > tape->insert_time) + if (time_after(jiffies, tape->insert_time)) tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (tape->onstream && tape->max_frames && @@ -2740,7 +2740,7 @@ if (tape->onstream) { if (tape->cur_frames - tape->reads_since_buffer_fill <= 0) tape->req_buffer_fill = 1; - if (jiffies > tape->last_buffer_fill + 5 * HZ / 100) + if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100)) tape->req_buffer_fill = 1; } pc = idetape_next_pc_storage (drive); @@ -2756,7 +2756,7 @@ if (tape->onstream) { if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames) tape->req_buffer_fill = 1; - if (jiffies > tape->last_buffer_fill + 5 * HZ / 100) + if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100)) tape->req_buffer_fill = 1; calculate_speeds(drive); } @@ -3096,10 +3096,10 @@ idetape_tape_t *tape = drive->driver_data; idetape_read_position_result_t *result; -//#if IDETAPE_DEBUG_LOG -// if (tape->debug_level >= 4) +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n"); -//#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_LOG */ if (!tape->pc->error) { result = (idetape_read_position_result_t *) tape->pc->buffer; @@ -3214,7 +3214,7 @@ * Wait for the tape to become ready */ timeout += jiffies; - while (jiffies < timeout) { + while (time_before(jiffies, timeout)) { idetape_create_test_unit_ready_cmd(&pc); if (!__idetape_queue_pc_tail(drive, &pc)) return 0; @@ -3273,10 +3273,10 @@ idetape_pc_t pc; int position; -//#if IDETAPE_DEBUG_LOG -// if (tape->debug_level >= 4) +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) printk (KERN_INFO "ide-tape: Reached idetape_read_position\n"); -//#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_LOG */ #ifdef NO_LONGER_REQUIRED idetape_flush_tape_buffers(drive); @@ -6132,10 +6132,7 @@ #endif -static int idetape_reinit (ide_drive_t *drive) -{ - return 0; -} +int idetape_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c @@ -6148,6 +6145,8 @@ supports_dma: 1, supports_dsc_overlap: 1, cleanup: idetape_cleanup, + standby: NULL, + flushcache: NULL, do_request: idetape_do_request, end_request: idetape_end_request, ioctl: idetape_blkdev_ioctl, @@ -6158,7 +6157,9 @@ pre_reset: idetape_pre_reset, capacity: NULL, proc: idetape_proc, - driver_reinit: idetape_reinit, + reinit: idetape_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, }; int idetape_init (void); @@ -6181,6 +6182,92 @@ release: idetape_chrdev_release, }; +int idetape_reinit (ide_drive_t *drive) +{ +#if 0 + idetape_tape_t *tape; + int minor, failed = 0, supported = 0; +/* DRIVER(drive)->busy++; */ + MOD_INC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); +#endif + if (!idetape_chrdev_present) + for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) + idetape_chrdevs[minor].drive = NULL; + + if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { + ide_register_module (&idetape_module); + MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif + return 0; + } + if (!idetape_chrdev_present && + devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) { + printk (KERN_ERR "ide-tape: Failed to register character device interface\n"); + MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif + return -EBUSY; + } + do { + if (!idetape_identify_device (drive, drive->id)) { + printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); + continue; + } + if (drive->scsi) { + if (strstr(drive->id->model, "OnStream DI-30")) { + printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); + } else { + printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); + continue; + } + } + tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); + if (tape == NULL) { + printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); + continue; + } + if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); + kfree (tape); + continue; + } + for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++); + idetape_setup (drive, tape, minor); + idetape_chrdevs[minor].drive = drive; + tape->de_r = + devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor, + S_IFCHR | S_IRUGO | S_IWUGO, + &idetape_fops, NULL); + tape->de_n = + devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor + 128, + S_IFCHR | S_IRUGO | S_IWUGO, + &idetape_fops, NULL); + devfs_register_tape (tape->de_r); + supported++; failed--; + } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL); + if (!idetape_chrdev_present && !supported) { + devfs_unregister_chrdev (IDETAPE_MAJOR, "ht"); + } else + idetape_chrdev_present = 1; + ide_register_module (&idetape_module); + MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif + + return 0; +#else + return 1; +#endif +} + MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); MODULE_LICENSE("GPL"); @@ -6205,7 +6292,7 @@ ide_drive_t *drive; idetape_tape_t *tape; int minor, failed = 0, supported = 0; - +/* DRIVER(drive)->busy++; */ MOD_INC_USE_COUNT; #if ONSTREAM_DEBUG printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); diff -urN linux-2.4.18/drivers/ide/ide-taskfile.c linux-2.4.19-pre5/drivers/ide/ide-taskfile.c --- linux-2.4.18/drivers/ide/ide-taskfile.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ide/ide-taskfile.c Sat Mar 30 22:55:34 2002 @@ -0,0 +1,1723 @@ +/* + * linux/drivers/ide/ide-taskfile.c Version 0.20 Oct 11, 2000 + * + * Copyright (C) 2000 Michael Cornwell + * Copyright (C) 2000 Andre Hedrick + * + * May be copied or modified under the terms of the GNU General Public License + * + * IDE_DEBUG(__LINE__); + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_IDE_TASKFILE_IO +# define __TASKFILE__IO +#else /* CONFIG_IDE_TASKFILE_IO */ +# undef __TASKFILE__IO +#endif /* CONFIG_IDE_TASKFILE_IO */ + +#define DEBUG_TASKFILE 0 /* unset when fixed */ + +#if DEBUG_TASKFILE +#define DTF(x...) printk(##x) +#else +#define DTF(x...) +#endif + +inline u32 task_read_24 (ide_drive_t *drive) +{ + return (IN_BYTE(IDE_HCYL_REG)<<16) | + (IN_BYTE(IDE_LCYL_REG)<<8) | + IN_BYTE(IDE_SECTOR_REG); +} + +static void ata_bswap_data (void *buffer, int wcount) +{ + u16 *p = buffer; + + while (wcount--) { + *p = *p << 8 | *p >> 8; p++; + *p = *p << 8 | *p >> 8; p++; + } +} + +#if SUPPORT_VLB_SYNC +/* + * Some localbus EIDE interfaces require a special access sequence + * when using 32-bit I/O instructions to transfer data. We call this + * the "vlb_sync" sequence, which consists of three successive reads + * of the sector count register location, with interrupts disabled + * to ensure that the reads all happen together. + */ +static inline void task_vlb_sync (ide_ioreg_t port) { + (void) inb (port); + (void) inb (port); + (void) inb (port); +} +#endif /* SUPPORT_VLB_SYNC */ + +/* + * This is used for most PIO data transfers *from* the IDE interface + */ +void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + byte io_32bit = drive->io_32bit; + + if (io_32bit) { +#if SUPPORT_VLB_SYNC + if (io_32bit & 2) { + unsigned long flags; + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + task_vlb_sync(IDE_NSECTOR_REG); + insl(IDE_DATA_REG, buffer, wcount); + __restore_flags(flags); /* local CPU only */ + } else +#endif /* SUPPORT_VLB_SYNC */ + insl(IDE_DATA_REG, buffer, wcount); + } else { +#if SUPPORT_SLOW_DATA_PORTS + if (drive->slow) { + unsigned short *ptr = (unsigned short *) buffer; + while (wcount--) { + *ptr++ = inw_p(IDE_DATA_REG); + *ptr++ = inw_p(IDE_DATA_REG); + } + } else +#endif /* SUPPORT_SLOW_DATA_PORTS */ + insw(IDE_DATA_REG, buffer, wcount<<1); + } +} + +/* + * This is used for most PIO data transfers *to* the IDE interface + */ +void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + byte io_32bit = drive->io_32bit; + + if (io_32bit) { +#if SUPPORT_VLB_SYNC + if (io_32bit & 2) { + unsigned long flags; + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + task_vlb_sync(IDE_NSECTOR_REG); + outsl(IDE_DATA_REG, buffer, wcount); + __restore_flags(flags); /* local CPU only */ + } else +#endif /* SUPPORT_VLB_SYNC */ + outsl(IDE_DATA_REG, buffer, wcount); + } else { +#if SUPPORT_SLOW_DATA_PORTS + if (drive->slow) { + unsigned short *ptr = (unsigned short *) buffer; + while (wcount--) { + outw_p(*ptr++, IDE_DATA_REG); + outw_p(*ptr++, IDE_DATA_REG); + } + } else +#endif /* SUPPORT_SLOW_DATA_PORTS */ + outsw(IDE_DATA_REG, buffer, wcount<<1); + } +} + + +static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + ata_input_data(drive, buffer, wcount); + if (drive->bswap) + ata_bswap_data(buffer, wcount); +} + +static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + if (drive->bswap) { + ata_bswap_data(buffer, wcount); + ata_output_data(drive, buffer, wcount); + ata_bswap_data(buffer, wcount); + } else { + ata_output_data(drive, buffer, wcount); + } +} + +ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +{ + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; + struct hd_driveid *id = drive->id; + byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; + + /* (ks/hs): Moved to start, do not use for multiple out commands */ + if (task->handler != task_mulout_intr) { + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); + } + + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + OUT_BYTE(hobfile->feature, IDE_FEATURE_REG); + OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); + OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); + OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); + OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); + } + + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); + OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to number of sectors to transfer */ + OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); + /* refers to sector offset or start sector */ + OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); + OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); + + OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); + if (task->handler != NULL) { +#if 0 + ide_set_handler (drive, task->handler, WAIT_CMD, NULL); + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + /* + * warning check for race between handler and prehandler for + * writing first block of data. however since we are well + * inside the boundaries of the seek, we should be okay. + */ + if (task->prehandler != NULL) { + return task->prehandler(drive, task->rq); + } +#else + ide_startstop_t startstop; + + ide_set_handler (drive, task->handler, WAIT_CMD, NULL); + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", + drive->name, + drive->mult_count ? "MULTWRITE" : "WRITE"); + return startstop; + } + /* (ks/hs): Fixed Multi Write */ + if ((taskfile->command != WIN_MULTWRITE) && + (taskfile->command != WIN_MULTWRITE_EXT)) { + struct request *rq = HWGROUP(drive)->rq; + /* For Write_sectors we need to stuff the first sector */ + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + rq->current_nr_sectors--; + } else { + /* Stuff first sector(s) by implicitly calling the handler */ + if (!(drive_is_ready(drive))) { + /* FIXME: Replace hard-coded 100, error handling? */ + int i; + for (i=0; i<100; i++) { + if (drive_is_ready(drive)) + break; + } + } + return task->handler(drive); + } +#endif + } else { + /* for dma commands we down set the handler */ + if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); + } + + return ide_started; +} + +void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler) +{ + struct hd_driveid *id = drive->id; + byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; + + /* (ks/hs): Moved to start, do not use for multiple out commands */ + if (*handler != task_mulout_intr) { + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); + } + + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + OUT_BYTE(hobfile->feature, IDE_FEATURE_REG); + OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); + OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); + OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); + OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); + } + + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); + OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to number of sectors to transfer */ + OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); + /* refers to sector offset or start sector */ + OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); + OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); + + OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); + if (handler != NULL) { + ide_set_handler (drive, handler, WAIT_CMD, NULL); + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + } else { + /* for dma commands we down set the handler */ + if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); + } +} + +#if 0 +ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) +{ + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; + struct hd_driveid *id = drive->id; + + /* + * (KS) Check taskfile in/out flags. + * If set, then execute as it is defined. + * If not set, then define default settings. + * The default values are: + * write and read all taskfile registers (except data) + * write and read the hob registers (sector,nsector,lcyl,hcyl) + */ + if (task->tf_out_flags.all == 0) { + task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS; + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8); + } + } + + if (task->tf_in_flags.all == 0) { + task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + task->tf_in_flags.all != (IDE_HOB_STD_IN_FLAGS << 8); + } + } + + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); + + if (task->tf_out_flags.b.data) { + unsigned short data = taskfile->data + (hobfile->data << 8); + OUT_WORD (data, IDE_DATA_REG); + } + + /* (KS) send hob registers first */ + if (task->tf_out_flags.b.nsector_hob) + OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); + if (task->tf_out_flags.b.sector_hob) + OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl_hob) + OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl_hob) + OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); + + + /* (KS) Send now the standard registers */ + if (task->tf_out_flags.b.error_feature) + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); + /* refers to number of sectors to transfer */ + if (task->tf_out_flags.b.nsector) + OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to sector offset or start sector */ + if (task->tf_out_flags.b.sector) + OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl) + OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl) + OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); + + /* + * (KS) Do not modify the specified taskfile. We want to have a + * universal pass through, so we must execute ALL specified values. + * + * (KS) The drive head register is mandatory. + * Don't care about the out flags ! + */ + OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG); + if (task->handler != NULL) { +#if 0 + ide_set_handler (drive, task->handler, WAIT_CMD, NULL); + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + /* + * warning check for race between handler and prehandler for + * writing first block of data. however since we are well + * inside the boundaries of the seek, we should be okay. + */ + if (task->prehandler != NULL) { + return task->prehandler(drive, task->rq); + } +#else + ide_startstop_t startstop; + + ide_set_handler (drive, task->handler, WAIT_CMD, NULL); + + /* + * (KS) The drive command register is also mandatory. + * Don't care about the out flags ! + */ + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", + drive->name, + drive->mult_count ? "MULTWRITE" : "WRITE"); + return startstop; + } + /* (ks/hs): Fixed Multi Write */ + if ((taskfile->command != WIN_MULTWRITE) && + (taskfile->command != WIN_MULTWRITE_EXT)) { + struct request *rq = HWGROUP(drive)->rq; + /* For Write_sectors we need to stuff the first sector */ + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + rq->current_nr_sectors--; + } else { + /* Stuff first sector(s) by implicitly calling the handler */ + if (!(drive_is_ready(drive))) { + /* FIXME: Replace hard-coded 100, error handling? */ + int i; + for (i=0; i<100; i++) { + if (drive_is_ready(drive)) + break; + } + } + return task->handler(drive); + } +#endif + } else { + /* for dma commands we down set the handler */ + if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); + } + + return ide_started; +} +#endif + +#if 0 +/* + * Error reporting, in human readable form (luxurious, but a memory hog). + */ +byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat) +{ + unsigned long flags; + byte err = 0; + + __save_flags (flags); /* local CPU only */ + ide__sti(); /* local CPU only */ + printk("%s: %s: status=0x%02x", drive->name, msg, stat); +#if FANCY_STATUS_DUMPS + printk(" { "); + if (stat & BUSY_STAT) + printk("Busy "); + else { + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); + } + printk("}"); +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = GET_ERR(); + printk("%s: %s: error=0x%02x", drive->name, msg, err); +#if FANCY_STATUS_DUMPS + if (drive->media == ide_disk) { + printk(" { "); + if (err & ABRT_ERR) printk("DriveStatusError "); + if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector "); + if (err & ECC_ERR) printk("UncorrectableError "); + if (err & ID_ERR) printk("SectorIdNotFound "); + if (err & TRK0_ERR) printk("TrackZeroNotFound "); + if (err & MARK_ERR) printk("AddrMarkNotFound "); + printk("}"); + if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) { + if ((drive->id->command_set_2 & 0x0400) && + (drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + __u64 sectors = 0; + u32 low = 0, high = 0; + low = task_read_24(drive); + OUT_BYTE(0x80, IDE_CONTROL_REG); + high = task_read_24(drive); + sectors = ((__u64)high << 24) | low; + printk(", LBAsect=%lld", sectors); + } else { + byte cur = IN_BYTE(IDE_SELECT_REG); + if (cur & 0x40) { /* using LBA? */ + printk(", LBAsect=%ld", (unsigned long) + ((cur&0xf)<<24) + |(IN_BYTE(IDE_HCYL_REG)<<16) + |(IN_BYTE(IDE_LCYL_REG)<<8) + | IN_BYTE(IDE_SECTOR_REG)); + } else { + printk(", CHS=%d/%d/%d", + (IN_BYTE(IDE_HCYL_REG)<<8) + + IN_BYTE(IDE_LCYL_REG), + cur & 0xf, + IN_BYTE(IDE_SECTOR_REG)); + } + } + if (HWGROUP(drive)->rq) + printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector); + } + } +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + } + __restore_flags (flags); /* local CPU only */ + return err; +} + +/* + * Clean up after success/failure of an explicit taskfile operation. + */ +void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err) +{ + unsigned long flags; + struct request *rq; + ide_task_t *args; + task_ioreg_t command; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + spin_unlock_irqrestore(&io_request_lock, flags); + args = (ide_task_t *) rq->special; + + command = args->tfRegister[IDE_COMMAND_OFFSET]; + + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + + args->tfRegister[IDE_ERROR_OFFSET] = err; + args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG); + args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG); + args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG); + args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG); + args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG); + args->tfRegister[IDE_STATUS_OFFSET] = stat; + if ((drive->id->command_set_2 & 0x0400) && + (drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB); + args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG); + args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG); + args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG); + args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG); + args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG); + } + +/* taskfile_settings_update(drive, args, command); */ + + spin_lock_irqsave(&io_request_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +/* + * try_to_flush_leftover_data() is invoked in response to a drive + * unexpectedly having its DRQ_STAT bit set. As an alternative to + * resetting the drive, this routine tries to clear the condition + * by read a sector's worth of data from the drive. Of course, + * this may not help if the drive is *waiting* for data from *us*. + */ +void task_try_to_flush_leftover_data (ide_drive_t *drive) +{ + int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; + + if (drive->media != ide_disk) + return; + while (i > 0) { + u32 buffer[16]; + unsigned int wcount = (i > 16) ? 16 : i; + i -= wcount; + taskfile_input_data (drive, buffer, wcount); + } +} + +/* + * taskfile_error() takes action based on the error returned by the drive. + */ +ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat) +{ + struct request *rq; + byte err; + + err = taskfile_dump_status(drive, msg, stat); + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + /* retry only "normal" I/O: */ + if (rq->cmd == IDE_DRIVE_TASKFILE) { + rq->errors = 1; + ide_end_taskfile(drive, stat, err); + return ide_stopped; + } + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else { + if (drive->media == ide_disk && (stat & ERR_STAT)) { + /* err has different meaning on cdrom and tape */ + if (err == ABRT_ERR) { + if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) + return ide_stopped; /* some newer drives don't support WIN_SPECIFY */ + } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) { + drive->crc_count++; /* UDMA crc error -- just retry the operation */ + } else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ + rq->errors = ERROR_MAX; + else if (err & TRK0_ERR) /* help it find track zero */ + rq->errors |= ERROR_RECAL; + } + if ((stat & DRQ_STAT) && rq->cmd != WRITE) + task_try_to_flush_leftover_data(drive); + } + if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) + OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ + + if (rq->errors >= ERROR_MAX) { + if (drive->driver != NULL) + DRIVER(drive)->end_request(0, HWGROUP(drive)); + else + ide_end_request(0, HWGROUP(drive)); + } else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) + drive->special.b.recalibrate = 1; + ++rq->errors; + } + return ide_stopped; +} +#endif + +/* + * Handler for special commands without a data phase from ide-disk + */ + +/* + * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. + */ +ide_startstop_t set_multmode_intr (ide_drive_t *drive) +{ + byte stat; + + if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) { + drive->mult_count = drive->mult_req; + } else { + drive->mult_req = drive->mult_count = 0; + drive->special.b.recalibrate = 1; + (void) ide_dump_status(drive, "set_multmode", stat); + } + return ide_stopped; +} + +/* + * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. + */ +ide_startstop_t set_geometry_intr (ide_drive_t *drive) +{ + byte stat; + + if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) + return ide_stopped; + + if (stat & (ERR_STAT|DRQ_STAT)) + return ide_error(drive, "set_geometry_intr", stat); + + ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL); + return ide_started; +} + +/* + * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. + */ +ide_startstop_t recal_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + + if (!OK_STAT(stat,READY_STAT,BAD_STAT)) + return ide_error(drive, "recal_intr", stat); + return ide_stopped; +} + +/* + * Handler for commands without a data phase + */ +ide_startstop_t task_no_data_intr (ide_drive_t *drive) +{ + ide_task_t *args = HWGROUP(drive)->rq->special; + byte stat = GET_STAT(); + + ide__sti(); /* local CPU only */ + + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) + return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ + + if (args) + ide_end_drive_cmd (drive, stat, GET_ERR()); + + return ide_stopped; +} + +/* + * Handler for command with PIO data-in phase + */ +ide_startstop_t task_in_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + byte io_32bit = drive->io_32bit; + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + + if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + return ide_error(drive, "task_in_intr", stat); + } + if (!(stat & BUSY_STAT)) { + DTF("task_in_intr to Soon wait for next interrupt\n"); + ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); + return ide_started; + } + } + DTF("stat: %02x\n", stat); + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); + + drive->io_32bit = 0; + taskfile_input_data(drive, pBuf, SECTOR_WORDS); + drive->io_32bit = io_32bit; + + if (--rq->current_nr_sectors <= 0) { + /* (hs): swapped next 2 lines */ + DTF("Request Ended stat: %02x\n", GET_STAT()); + ide_end_request(1, HWGROUP(drive)); + } else { + ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); + return ide_started; + } + return ide_stopped; +} + +#undef ALTSTAT_SCREW_UP + +#ifdef ALTSTAT_SCREW_UP +/* + * (ks/hs): Poll Alternate Status Register to ensure + * that drive is not busy. + */ +byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg) +{ + int i; + + DTF("multi%s: ASR = %x\n", msg, stat); + if (stat & BUSY_STAT) { + /* (ks/hs): FIXME: Replace hard-coded 100, error handling? */ + for (i=0; i<100; i++) { + stat = GET_ALTSTAT(); + if ((stat & BUSY_STAT) == 0) + break; + } + } + /* + * (ks/hs): Read Status AFTER Alternate Status Register + */ + return(GET_STAT()); +} + +/* + * (ks/hs): Poll Alternate status register to wait for drive + * to become ready for next transfer + */ +byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg) +{ + /* (ks/hs): FIXME: Error handling, time-out? */ + while (stat & BUSY_STAT) + stat = GET_ALTSTAT(); + DTF("multi%s: nsect=1, ASR = %x\n", msg, stat); + return(GET_STAT()); /* (ks/hs): Clear pending IRQ */ +} +#endif /* ALTSTAT_SCREW_UP */ + +/* + * Handler for command with Read Multiple + */ +ide_startstop_t task_mulin_intr (ide_drive_t *drive) +{ + unsigned int msect, nsect; + +#ifdef ALTSTAT_SCREW_UP + byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "read"); +#else + byte stat = GET_STAT(); +#endif /* ALTSTAT_SCREW_UP */ + + byte io_32bit = drive->io_32bit; + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + + if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + return ide_error(drive, "task_mulin_intr", stat); + } + /* no data yet, so wait for another interrupt */ + ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); + return ide_started; + } + + /* (ks/hs): Fixed Multi-Sector transfer */ + msect = drive->mult_count; + +#ifdef ALTSTAT_SCREW_UP + /* + * Screw the request we do not support bad data-phase setups! + * Either read and learn the ATA standard or crash yourself! + */ + if (!msect) { + /* + * (ks/hs): Drive supports multi-sector transfer, + * drive->mult_count was not set + */ + nsect = 1; + while (rq->current_nr_sectors) { + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors -= nsect; + stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read"); + } + ide_end_request(1, HWGROUP(drive)); + return ide_stopped; + } +#endif /* ALTSTAT_SCREW_UP */ + + nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + + DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors -= nsect; + if (rq->current_nr_sectors != 0) { + ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); + return ide_started; + } + ide_end_request(1, HWGROUP(drive)); + return ide_stopped; +} + +ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) +{ + ide_task_t *args = rq->special; + ide_startstop_t startstop; + + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE"); + return startstop; + } + + /* (ks/hs): Fixed Multi Write */ + if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) && + (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) { + /* For Write_sectors we need to stuff the first sector */ + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + rq->current_nr_sectors--; + return ide_started; + } else { + /* + * (ks/hs): Stuff the first sector(s) + * by implicitly calling the handler + */ + if (!(drive_is_ready(drive))) { + int i; + /* + * (ks/hs): FIXME: Replace hard-coded + * 100, error handling? + */ + for (i=0; i<100; i++) { + if (drive_is_ready(drive)) + break; + } + } + return args->handler(drive); + } + return ide_started; +} + +/* + * Handler for command with PIO data-out phase + */ +ide_startstop_t task_out_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + byte io_32bit = drive->io_32bit; + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + + if (!rq->current_nr_sectors) { + ide_end_request(1, HWGROUP(drive)); + return ide_stopped; + } + + if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { + return ide_error(drive, "task_out_intr", stat); + } + if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { + rq = HWGROUP(drive)->rq; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_output_data(drive, pBuf, SECTOR_WORDS); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors--; + } + + if (rq->current_nr_sectors <= 0) { + ide_end_request(1, HWGROUP(drive)); + } else { + ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL); + return ide_started; + } + return ide_stopped; +} + +/* + * Handler for command write multiple + * Called directly from execute_drive_cmd for the first bunch of sectors, + * afterwards only by the ISR + */ +ide_startstop_t task_mulout_intr (ide_drive_t *drive) +{ + unsigned int msect, nsect; + +#ifdef ALTSTAT_SCREW_UP + byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "write"); +#else + byte stat = GET_STAT(); +#endif /* ALTSTAT_SCREW_UP */ + + byte io_32bit = drive->io_32bit; + struct request *rq = HWGROUP(drive)->rq; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + char *pBuf = NULL; + + /* + * (ks/hs): Handle last IRQ on multi-sector transfer, + * occurs after all data was sent + */ + if (rq->current_nr_sectors == 0) { + if (stat & (ERR_STAT|DRQ_STAT)) + return ide_error(drive, "task_mulout_intr", stat); + ide_end_request(1, HWGROUP(drive)); + return ide_stopped; + } + + if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + return ide_error(drive, "task_mulout_intr", stat); + } + /* no data yet, so wait for another interrupt */ + if (hwgroup->handler == NULL) + ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); + return ide_started; + } + + /* (ks/hs): See task_mulin_intr */ + msect = drive->mult_count; + +#ifdef ALTSTAT_SCREW_UP + /* + * Screw the request we do not support bad data-phase setups! + * Either read and learn the ATA standard or crash yourself! + */ + if (!msect) { + nsect = 1; + while (rq->current_nr_sectors) { + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors -= nsect; + stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write"); + } + ide_end_request(1, HWGROUP(drive)); + return ide_stopped; + } +#endif /* ALTSTAT_SCREW_UP */ + + nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors -= nsect; + if (hwgroup->handler == NULL) + ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); + return ide_started; +} + +/* Called by internal to feature out type of command being called */ +ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) +{ + switch(taskfile->command) { + /* IDE_DRIVE_TASK_RAW_WRITE */ + case CFA_WRITE_MULTI_WO_ERASE: + case WIN_MULTWRITE: + case WIN_MULTWRITE_EXT: +// case WIN_WRITEDMA: +// case WIN_WRITEDMA_QUEUED: +// case WIN_WRITEDMA_EXT: +// case WIN_WRITEDMA_QUEUED_EXT: + /* IDE_DRIVE_TASK_OUT */ + case WIN_WRITE: + case WIN_WRITE_VERIFY: + case WIN_WRITE_BUFFER: + case CFA_WRITE_SECT_WO_ERASE: + case WIN_DOWNLOAD_MICROCODE: + return &pre_task_out_intr; + /* IDE_DRIVE_TASK_OUT */ + case WIN_SMART: + if (taskfile->feature == SMART_WRITE_LOG_SECTOR) + return &pre_task_out_intr; + default: + break; + } + return(NULL); +} + +/* Called by internal to feature out type of command being called */ +ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) +{ + switch(taskfile->command) { + case WIN_IDENTIFY: + case WIN_PIDENTIFY: + case CFA_TRANSLATE_SECTOR: + case WIN_READ_BUFFER: + case WIN_READ: + case WIN_READ_EXT: + return &task_in_intr; + case WIN_SECURITY_DISABLE: + case WIN_SECURITY_ERASE_UNIT: + case WIN_SECURITY_SET_PASS: + case WIN_SECURITY_UNLOCK: + case WIN_DOWNLOAD_MICROCODE: + case CFA_WRITE_SECT_WO_ERASE: + case WIN_WRITE_BUFFER: + case WIN_WRITE_VERIFY: + case WIN_WRITE: + case WIN_WRITE_EXT: + return &task_out_intr; + case WIN_MULTREAD: + case WIN_MULTREAD_EXT: + return &task_mulin_intr; + case CFA_WRITE_MULTI_WO_ERASE: + case WIN_MULTWRITE: + case WIN_MULTWRITE_EXT: + return &task_mulout_intr; + case WIN_SMART: + switch(taskfile->feature) { + case SMART_READ_VALUES: + case SMART_READ_THRESHOLDS: + case SMART_READ_LOG_SECTOR: + return &task_in_intr; + case SMART_WRITE_LOG_SECTOR: + return &task_out_intr; + default: + return &task_no_data_intr; + } + case CFA_REQ_EXT_ERROR_CODE: + case CFA_ERASE_SECTORS: + case WIN_VERIFY: + case WIN_VERIFY_EXT: + case WIN_SEEK: + return &task_no_data_intr; + case WIN_SPECIFY: + return &set_geometry_intr; + case WIN_RESTORE: + return &recal_intr; + case WIN_DIAGNOSE: + case WIN_FLUSH_CACHE: + case WIN_FLUSH_CACHE_EXT: + case WIN_STANDBYNOW1: + case WIN_STANDBYNOW2: + case WIN_SLEEPNOW1: + case WIN_SLEEPNOW2: + case WIN_SETIDLE1: + case WIN_CHECKPOWERMODE1: + case WIN_CHECKPOWERMODE2: + case WIN_GETMEDIASTATUS: + case WIN_MEDIAEJECT: + return &task_no_data_intr; + case WIN_SETMULT: + return &set_multmode_intr; + case WIN_READ_NATIVE_MAX: + case WIN_SET_MAX: + case WIN_READ_NATIVE_MAX_EXT: + case WIN_SET_MAX_EXT: + case WIN_SECURITY_ERASE_PREPARE: + case WIN_SECURITY_FREEZE_LOCK: + case WIN_DOORLOCK: + case WIN_DOORUNLOCK: + case WIN_SETFEATURES: + return &task_no_data_intr; + case DISABLE_SEAGATE: + case EXABYTE_ENABLE_NEST: + return &task_no_data_intr; +#ifdef CONFIG_BLK_DEV_IDEDMA + case WIN_READDMA: + case WIN_IDENTIFY_DMA: + case WIN_READDMA_QUEUED: + case WIN_READDMA_EXT: + case WIN_READDMA_QUEUED_EXT: + case WIN_WRITEDMA: + case WIN_WRITEDMA_QUEUED: + case WIN_WRITEDMA_EXT: + case WIN_WRITEDMA_QUEUED_EXT: +#endif + case WIN_FORMAT: + case WIN_INIT: + case WIN_DEVICE_RESET: + case WIN_QUEUED_SERVICE: + case WIN_PACKETCMD: + default: + return(NULL); + } +} + +/* Called by ioctl to feature out type of command being called */ +int ide_cmd_type_parser (ide_task_t *args) +{ + struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister; + struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister; + + args->prehandler = ide_pre_handler_parser(taskfile, hobfile); + args->handler = ide_handler_parser(taskfile, hobfile); + + switch(args->tfRegister[IDE_COMMAND_OFFSET]) { + case WIN_IDENTIFY: + case WIN_PIDENTIFY: + return IDE_DRIVE_TASK_IN; + case CFA_TRANSLATE_SECTOR: + case WIN_READ: + case WIN_READ_BUFFER: + return IDE_DRIVE_TASK_IN; + case WIN_WRITE: + case WIN_WRITE_VERIFY: + case WIN_WRITE_BUFFER: + case CFA_WRITE_SECT_WO_ERASE: + case WIN_DOWNLOAD_MICROCODE: + return IDE_DRIVE_TASK_RAW_WRITE; + case WIN_MULTREAD: + return IDE_DRIVE_TASK_IN; + case CFA_WRITE_MULTI_WO_ERASE: + case WIN_MULTWRITE: + return IDE_DRIVE_TASK_RAW_WRITE; + case WIN_SECURITY_DISABLE: + case WIN_SECURITY_ERASE_UNIT: + case WIN_SECURITY_SET_PASS: + case WIN_SECURITY_UNLOCK: + return IDE_DRIVE_TASK_OUT; + case WIN_SMART: + args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + switch(args->tfRegister[IDE_FEATURE_OFFSET]) { + case SMART_READ_VALUES: + case SMART_READ_THRESHOLDS: + case SMART_READ_LOG_SECTOR: + return IDE_DRIVE_TASK_IN; + case SMART_WRITE_LOG_SECTOR: + return IDE_DRIVE_TASK_OUT; + default: + return IDE_DRIVE_TASK_NO_DATA; + } +#ifdef CONFIG_BLK_DEV_IDEDMA + case WIN_READDMA: + case WIN_IDENTIFY_DMA: + case WIN_READDMA_QUEUED: + case WIN_READDMA_EXT: + case WIN_READDMA_QUEUED_EXT: + return IDE_DRIVE_TASK_IN; + case WIN_WRITEDMA: + case WIN_WRITEDMA_QUEUED: + case WIN_WRITEDMA_EXT: + case WIN_WRITEDMA_QUEUED_EXT: + return IDE_DRIVE_TASK_RAW_WRITE; +#endif + case WIN_SETFEATURES: + switch(args->tfRegister[IDE_FEATURE_OFFSET]) { + case SETFEATURES_XFER: + return IDE_DRIVE_TASK_SET_XFER; + case SETFEATURES_DIS_DEFECT: + case SETFEATURES_EN_APM: + case SETFEATURES_DIS_MSN: + case SETFEATURES_EN_RI: + case SETFEATURES_EN_SI: + case SETFEATURES_DIS_RPOD: + case SETFEATURES_DIS_WCACHE: + case SETFEATURES_EN_DEFECT: + case SETFEATURES_DIS_APM: + case SETFEATURES_EN_MSN: + case SETFEATURES_EN_RLA: + case SETFEATURES_PREFETCH: + case SETFEATURES_EN_RPOD: + case SETFEATURES_DIS_RI: + case SETFEATURES_DIS_SI: + default: + return IDE_DRIVE_TASK_NO_DATA; + } + case WIN_NOP: + case CFA_REQ_EXT_ERROR_CODE: + case CFA_ERASE_SECTORS: + case WIN_VERIFY: + case WIN_VERIFY_EXT: + case WIN_SEEK: + case WIN_SPECIFY: + case WIN_RESTORE: + case WIN_DIAGNOSE: + case WIN_FLUSH_CACHE: + case WIN_FLUSH_CACHE_EXT: + case WIN_STANDBYNOW1: + case WIN_STANDBYNOW2: + case WIN_SLEEPNOW1: + case WIN_SLEEPNOW2: + case WIN_SETIDLE1: + case DISABLE_SEAGATE: + case WIN_CHECKPOWERMODE1: + case WIN_CHECKPOWERMODE2: + case WIN_GETMEDIASTATUS: + case WIN_MEDIAEJECT: + case WIN_SETMULT: + case WIN_READ_NATIVE_MAX: + case WIN_SET_MAX: + case WIN_READ_NATIVE_MAX_EXT: + case WIN_SET_MAX_EXT: + case WIN_SECURITY_ERASE_PREPARE: + case WIN_SECURITY_FREEZE_LOCK: + case EXABYTE_ENABLE_NEST: + case WIN_DOORLOCK: + case WIN_DOORUNLOCK: + return IDE_DRIVE_TASK_NO_DATA; + case WIN_FORMAT: + case WIN_INIT: + case WIN_DEVICE_RESET: + case WIN_QUEUED_SERVICE: + case WIN_PACKETCMD: + default: + return IDE_DRIVE_TASK_INVALID; + } +} + +/* + * This function is intended to be used prior to invoking ide_do_drive_cmd(). + */ +void ide_init_drive_taskfile (struct request *rq) +{ + memset(rq, 0, sizeof(*rq)); + rq->cmd = IDE_DRIVE_TASK_NO_DATA; +} + +/* + * This is kept for internal use only !!! + * This is an internal call and nobody in user-space has a damn + * reason to call this taskfile. + * + * ide_raw_taskfile is the one that user-space executes. + */ +int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf) +{ + struct request rq; + ide_task_t args; + + memset(&args, 0, sizeof(ide_task_t)); + + args.tfRegister[IDE_DATA_OFFSET] = taskfile->data; + args.tfRegister[IDE_FEATURE_OFFSET] = taskfile->feature; + args.tfRegister[IDE_NSECTOR_OFFSET] = taskfile->sector_count; + args.tfRegister[IDE_SECTOR_OFFSET] = taskfile->sector_number; + args.tfRegister[IDE_LCYL_OFFSET] = taskfile->low_cylinder; + args.tfRegister[IDE_HCYL_OFFSET] = taskfile->high_cylinder; + args.tfRegister[IDE_SELECT_OFFSET] = taskfile->device_head; + args.tfRegister[IDE_COMMAND_OFFSET] = taskfile->command; + + args.hobRegister[IDE_DATA_OFFSET_HOB] = hobfile->data; + args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature; + args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count; + args.hobRegister[IDE_SECTOR_OFFSET_HOB] = hobfile->sector_number; + args.hobRegister[IDE_LCYL_OFFSET_HOB] = hobfile->low_cylinder; + args.hobRegister[IDE_HCYL_OFFSET_HOB] = hobfile->high_cylinder; + args.hobRegister[IDE_SELECT_OFFSET_HOB] = hobfile->device_head; + args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control; + + ide_init_drive_taskfile(&rq); + /* This is kept for internal use only !!! */ + args.command_type = ide_cmd_type_parser (&args); + if (args.command_type != IDE_DRIVE_TASK_NO_DATA) + rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count; + + rq.cmd = IDE_DRIVE_TASKFILE; + rq.buffer = buf; + rq.special = &args; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + +int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf) +{ + struct request rq; + ide_init_drive_taskfile(&rq); + rq.cmd = IDE_DRIVE_TASKFILE; + rq.buffer = buf; + + if (args->command_type != IDE_DRIVE_TASK_NO_DATA) + rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; + + rq.special = args; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + + +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG +char * ide_ioctl_verbose (unsigned int cmd) +{ + return("unknown"); +} + +char * ide_task_cmd_verbose (byte task) +{ + return("unknown"); +} +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + +/* + * The taskfile glue table + * + * reqtask.data_phase reqtask.req_cmd + * args.command_type args.handler + * + * TASKFILE_P_OUT_DMAQ ?? ?? + * TASKFILE_P_IN_DMAQ ?? ?? + * TASKFILE_P_OUT_DMA ?? ?? + * TASKFILE_P_IN_DMA ?? ?? + * TASKFILE_P_OUT ?? ?? + * TASKFILE_P_IN ?? ?? + * + * TASKFILE_OUT_DMAQ IDE_DRIVE_TASK_RAW_WRITE NULL + * TASKFILE_IN_DMAQ IDE_DRIVE_TASK_IN NULL + * + * TASKFILE_OUT_DMA IDE_DRIVE_TASK_RAW_WRITE NULL + * TASKFILE_IN_DMA IDE_DRIVE_TASK_IN NULL + * + * TASKFILE_IN_OUT ?? ?? + * + * TASKFILE_MULTI_OUT IDE_DRIVE_TASK_RAW_WRITE task_mulout_intr + * TASKFILE_MULTI_IN IDE_DRIVE_TASK_IN task_mulin_intr + * + * TASKFILE_OUT IDE_DRIVE_TASK_RAW_WRITE task_out_intr + * TASKFILE_OUT IDE_DRIVE_TASK_OUT task_out_intr + * + * TASKFILE_IN IDE_DRIVE_TASK_IN task_in_intr + * TASKFILE_NO_DATA IDE_DRIVE_TASK_NO_DATA task_no_data_intr + * + * IDE_DRIVE_TASK_SET_XFER task_no_data_intr + * IDE_DRIVE_TASK_INVALID + * + */ + +#define MAX_DMA (256*SECTOR_WORDS) + +int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + ide_task_request_t *req_task; + ide_task_t args; + + byte *outbuf = NULL; + byte *inbuf = NULL; + task_ioreg_t *argsptr = args.tfRegister; + task_ioreg_t *hobsptr = args.hobRegister; + int err = 0; + int tasksize = sizeof(struct ide_task_request_s); + int taskin = 0; + int taskout = 0; + + req_task = kmalloc(tasksize, GFP_KERNEL); + if (req_task == NULL) return -ENOMEM; + memset(req_task, 0, tasksize); + if (copy_from_user(req_task, (void *) arg, tasksize)) { + kfree(req_task); + return -EFAULT; + } + + taskout = (int) req_task->out_size; + taskin = (int) req_task->in_size; + + if (taskout) { + int outtotal = tasksize; + outbuf = kmalloc(taskout, GFP_KERNEL); + if (outbuf == NULL) { + err = -ENOMEM; + goto abort; + } + memset(outbuf, 0, taskout); + if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) { + err = -EFAULT; + goto abort; + } + } + + if (taskin) { + int intotal = tasksize + taskout; + inbuf = kmalloc(taskin, GFP_KERNEL); + if (inbuf == NULL) { + err = -ENOMEM; + goto abort; + } + memset(inbuf, 0, taskin); + if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) { + err = -EFAULT; + goto abort; + } + } + + memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE); + memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE); + memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); + memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE); + + args.tf_in_flags = req_task->in_flags; + args.tf_out_flags = req_task->out_flags; + args.data_phase = req_task->data_phase; + args.command_type = req_task->req_cmd; + +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG + DTF("%s: ide_ioctl_cmd %s: ide_task_cmd %s\n", + drive->name, + ide_ioctl_verbose(cmd), + ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET])); +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + + switch(req_task->data_phase) { + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + args.prehandler = NULL; + args.handler = NULL; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, outbuf); + break; + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + args.prehandler = NULL; + args.handler = NULL; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, inbuf); + break; + case TASKFILE_IN_OUT: +#if 0 + args.prehandler = &pre_task_out_intr; + args.handler = &task_out_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, outbuf); + args.prehandler = NULL; + args.handler = &task_in_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, inbuf); + break; +#else + err = -EFAULT; + goto abort; +#endif + case TASKFILE_MULTI_OUT: + if (drive->mult_count) { + args.prehandler = &pre_task_out_intr; + args.handler = &task_mulout_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, outbuf); + } else { + /* (hs): give up if multcount is not set */ + printk("%s: %s Multimode Write " \ + "multcount is not set\n", + drive->name, __FUNCTION__); + err = -EPERM; + goto abort; + } + break; + case TASKFILE_OUT: + args.prehandler = &pre_task_out_intr; + args.handler = &task_out_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, outbuf); + break; + case TASKFILE_MULTI_IN: + if (drive->mult_count) { + args.prehandler = NULL; + args.handler = &task_mulin_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, inbuf); + } else { + /* (hs): give up if multcount is not set */ + printk("%s: %s Multimode Read failure " \ + "multcount is not set\n", + drive->name, __FUNCTION__); + err = -EPERM; + goto abort; + } + break; + case TASKFILE_IN: + args.prehandler = NULL; + args.handler = &task_in_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, inbuf); + break; + case TASKFILE_NO_DATA: + args.prehandler = NULL; + args.handler = &task_no_data_intr; + args.posthandler = NULL; + err = ide_raw_taskfile(drive, &args, NULL); + break; + default: + args.prehandler = NULL; + args.handler = NULL; + args.posthandler = NULL; + err = -EFAULT; + goto abort; + } + + memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE); + memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE); + req_task->in_flags = args.tf_in_flags; + req_task->out_flags = args.tf_out_flags; + + if (copy_to_user((void *)arg, req_task, tasksize)) { + err = -EFAULT; + goto abort; + } + if (taskout) { + int outtotal = tasksize; + if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) { + err = -EFAULT; + goto abort; + } + } + if (taskin) { + int intotal = tasksize + taskout; + if (copy_to_user((void *)arg+intotal, inbuf, taskin)) { + err = -EFAULT; + goto abort; + } + } +abort: + kfree(req_task); + if (outbuf != NULL) + kfree(outbuf); + if (inbuf != NULL) + kfree(inbuf); + return err; +} + +EXPORT_SYMBOL(task_read_24); +EXPORT_SYMBOL(do_rw_taskfile); +EXPORT_SYMBOL(do_taskfile); +// EXPORT_SYMBOL(flagged_taskfile); + +//EXPORT_SYMBOL(ide_end_taskfile); + +EXPORT_SYMBOL(set_multmode_intr); +EXPORT_SYMBOL(set_geometry_intr); +EXPORT_SYMBOL(recal_intr); + +EXPORT_SYMBOL(task_no_data_intr); +EXPORT_SYMBOL(task_in_intr); +EXPORT_SYMBOL(task_mulin_intr); +EXPORT_SYMBOL(pre_task_out_intr); +EXPORT_SYMBOL(task_out_intr); +EXPORT_SYMBOL(task_mulout_intr); + +EXPORT_SYMBOL(ide_init_drive_taskfile); +EXPORT_SYMBOL(ide_wait_taskfile); +EXPORT_SYMBOL(ide_raw_taskfile); +EXPORT_SYMBOL(ide_pre_handler_parser); +EXPORT_SYMBOL(ide_handler_parser); +EXPORT_SYMBOL(ide_cmd_type_parser); +EXPORT_SYMBOL(ide_taskfile_ioctl); + +#ifdef CONFIG_PKT_TASK_IOCTL + +#if 0 +{ + +{ /* start cdrom */ + + struct cdrom_info *info = drive->driver_data; + + if (info->dma) { + if (info->cmd == READ) { + info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); + } else if (info->cmd == WRITE) { + info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive); + } else { + printk("ide-cd: DMA set, but not allowed\n"); + } + } + + /* Set up the controller registers. */ + OUT_BYTE (info->dma, IDE_FEATURE_REG); + OUT_BYTE (0, IDE_NSECTOR_REG); + OUT_BYTE (0, IDE_SECTOR_REG); + + OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG); + OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl, IDE_CONTROL_REG); + + if (info->dma) + (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); + + if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); + OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ + return ide_started; + } else { + OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ + return (*handler) (drive); + } + +} /* end cdrom */ + +{ /* start floppy */ + + idefloppy_floppy_t *floppy = drive->driver_data; + idefloppy_bcount_reg_t bcount; + int dma_ok = 0; + + floppy->pc=pc; /* Set the current packet command */ + + pc->retries++; + pc->actually_transferred=0; /* We haven't transferred any data yet */ + pc->current_position=pc->buffer; + bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); + } + if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) + dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl,IDE_CONTROL_REG); + OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ + OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); + OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); + OUT_BYTE (drive->select.all,IDE_SELECT_REG); + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (dma_ok) { /* Begin DMA, if necessary */ + set_bit (PC_DMA_IN_PROGRESS, &pc->flags); + (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + +} /* end floppy */ + +{ /* start tape */ + + idetape_tape_t *tape = drive->driver_data; + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { + printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); + } + if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) + dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl,IDE_CONTROL_REG); + OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ + OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); + OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); + OUT_BYTE (drive->select.all,IDE_SELECT_REG); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (dma_ok) { /* Begin DMA, if necessary */ + set_bit (PC_DMA_IN_PROGRESS, &pc->flags); + (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { + ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + return ide_started; + } else { + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + return idetape_transfer_pc(drive); + } + +} /* end tape */ + +} +#endif + +int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ +#if 0 + switch(req_task->data_phase) { + case TASKFILE_P_OUT_DMAQ: + case TASKFILE_P_IN_DMAQ: + case TASKFILE_P_OUT_DMA: + case TASKFILE_P_IN_DMA: + case TASKFILE_P_OUT: + case TASKFILE_P_IN: + } +#endif + return -ENOMSG; +} + +EXPORT_SYMBOL(pkt_taskfile_ioctl); + +#endif /* CONFIG_PKT_TASK_IOCTL */ diff -urN linux-2.4.18/drivers/ide/ide-timing.h linux-2.4.19-pre5/drivers/ide/ide-timing.h --- linux-2.4.18/drivers/ide/ide-timing.h Sat Mar 30 20:23:51 2002 +++ linux-2.4.19-pre5/drivers/ide/ide-timing.h Sat Mar 30 22:55:39 2002 @@ -2,11 +2,9 @@ #define _IDE_TIMING_H /* - * $Id: ide-timing.h,v 1.5 2001/01/15 21:48:56 vojtech Exp $ + * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -25,16 +23,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include -#ifndef XFER_PIO_5 #define XFER_PIO_5 0x0d #define XFER_UDMA_SLOW 0x4f -#endif struct ide_timing { short mode; @@ -49,13 +45,15 @@ }; /* - * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). * These were taken from ATA/ATAPI-6 standard, rev 0a, except - * for PIO 5, which is a nonstandard extension. + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. */ static struct ide_timing ide_timing[] = { + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, @@ -105,6 +103,7 @@ #define EZ(v,unit) ((v)?ENOUGH(v,unit):0) #define XFER_MODE 0xf0 +#define XFER_UDMA_133 0x48 #define XFER_UDMA_100 0x44 #define XFER_UDMA_66 0x42 #define XFER_UDMA 0x40 @@ -123,6 +122,9 @@ if ((map & XFER_UDMA) && (id->field_valid & 4)) { /* Want UDMA and UDMA bitmap valid */ + if ((map & XFER_UDMA_133) == XFER_UDMA_133) + if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best; + if ((map & XFER_UDMA_100) == XFER_UDMA_100) if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best; @@ -174,14 +176,14 @@ static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT) { - q->setup = EZ(t->setup, T); - q->act8b = EZ(t->act8b, T); - q->rec8b = EZ(t->rec8b, T); - q->cyc8b = EZ(t->cyc8b, T); - q->active = EZ(t->active, T); - q->recover = EZ(t->recover, T); - q->cycle = EZ(t->cycle, T); - q->udma = EZ(t->udma, UT); + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); } static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what) diff -urN linux-2.4.18/drivers/ide/ide.c linux-2.4.19-pre5/drivers/ide/ide.c --- linux-2.4.18/drivers/ide/ide.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/ide/ide.c Sat Mar 30 22:55:34 2002 @@ -149,6 +149,7 @@ #include #include #include +#include #include #include @@ -162,6 +163,16 @@ #include #endif /* CONFIG_KMOD */ +#ifdef CONFIG_IDE_TASKFILE_IO +# define __TASKFILE__IO +#else /* CONFIG_IDE_TASKFILE_IO */ +# undef __TASKFILE__IO +#endif /* CONFIG_IDE_TASKFILE_IO */ + +#ifdef __TASKFILE__IO +#else /* !__TASKFILE__IO */ +#endif /* __TASKFILE__IO */ + /* default maximum number of failures */ #define IDE_DEFAULT_MAX_FAILURES 1 @@ -515,7 +526,8 @@ /* * Needed for PCI irq sharing */ -static inline int drive_is_ready (ide_drive_t *drive) +//static inline +int drive_is_ready (ide_drive_t *drive) { byte stat = 0; if (drive->waiting_for_dma) @@ -809,7 +821,11 @@ */ OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */ udelay(10); /* more than enough time */ - OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ + if (drive->quirk_list == 2) { + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear SRST and nIEN */ + } else { + OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ + } udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); @@ -836,6 +852,13 @@ return do_reset1 (drive, 0); } +static inline u32 read_24 (ide_drive_t *drive) +{ + return (IN_BYTE(IDE_HCYL_REG)<<16) | + (IN_BYTE(IDE_LCYL_REG)<<8) | + IN_BYTE(IDE_SECTOR_REG); +} + /* * Clean up after success/failure of an explicit drive cmd */ @@ -848,26 +871,66 @@ rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&io_request_lock, flags); - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - if (args) { - args[0] = stat; - args[1] = err; - args[2] = IN_BYTE(IDE_NSECTOR_REG); - } - } else if (rq->cmd == IDE_DRIVE_TASK) { - byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - if (args) { - args[0] = stat; - args[1] = err; - args[2] = IN_BYTE(IDE_NSECTOR_REG); - args[3] = IN_BYTE(IDE_SECTOR_REG); - args[4] = IN_BYTE(IDE_LCYL_REG); - args[5] = IN_BYTE(IDE_HCYL_REG); - args[6] = IN_BYTE(IDE_SELECT_REG); + switch(rq->cmd) { + case IDE_DRIVE_CMD: + { + byte *args = (byte *) rq->buffer; + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { + args[0] = stat; + args[1] = err; + args[2] = IN_BYTE(IDE_NSECTOR_REG); + } + break; } + case IDE_DRIVE_TASK: + { + byte *args = (byte *) rq->buffer; + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { + args[0] = stat; + args[1] = err; + args[2] = IN_BYTE(IDE_NSECTOR_REG); + args[3] = IN_BYTE(IDE_SECTOR_REG); + args[4] = IN_BYTE(IDE_LCYL_REG); + args[5] = IN_BYTE(IDE_HCYL_REG); + args[6] = IN_BYTE(IDE_SELECT_REG); + } + break; + } + case IDE_DRIVE_TASKFILE: + { + ide_task_t *args = (ide_task_t *) rq->special; + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { + if (args->tf_in_flags.b.data) { + unsigned short data = IN_WORD(IDE_DATA_REG); + args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; + args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; + } + args->tfRegister[IDE_ERROR_OFFSET] = err; + args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG); + args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG); + args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG); + args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG); + args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG); + args->tfRegister[IDE_STATUS_OFFSET] = stat; + + if ((drive->id->command_set_2 & 0x0400) && + (drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB); + args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG); + args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG); + args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG); + args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG); + args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG); + } + } + break; + } + default: + break; } spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); @@ -917,19 +980,32 @@ if (err & MARK_ERR) printk("AddrMarkNotFound "); printk("}"); if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) { - byte cur = IN_BYTE(IDE_SELECT_REG); - if (cur & 0x40) { /* using LBA? */ - printk(", LBAsect=%ld", (unsigned long) - ((cur&0xf)<<24) - |(IN_BYTE(IDE_HCYL_REG)<<16) - |(IN_BYTE(IDE_LCYL_REG)<<8) - | IN_BYTE(IDE_SECTOR_REG)); + if ((drive->id->command_set_2 & 0x0400) && + (drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + __u64 sectors = 0; + u32 low = 0, high = 0; + low = read_24(drive); + OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG); + high = read_24(drive); + + sectors = ((__u64)high << 24) | low; + printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low); } else { - printk(", CHS=%d/%d/%d", - (IN_BYTE(IDE_HCYL_REG)<<8) + - IN_BYTE(IDE_LCYL_REG), - cur & 0xf, - IN_BYTE(IDE_SECTOR_REG)); + byte cur = IN_BYTE(IDE_SELECT_REG); + if (cur & 0x40) { /* using LBA? */ + printk(", LBAsect=%ld", (unsigned long) + ((cur&0xf)<<24) + |(IN_BYTE(IDE_HCYL_REG)<<16) + |(IN_BYTE(IDE_LCYL_REG)<<8) + | IN_BYTE(IDE_SECTOR_REG)); + } else { + printk(", CHS=%d/%d/%d", + (IN_BYTE(IDE_HCYL_REG)<<8) + + IN_BYTE(IDE_LCYL_REG), + cur & 0xf, + IN_BYTE(IDE_SECTOR_REG)); + } } if (HWGROUP(drive) && HWGROUP(drive)->rq) printk(", sector=%ld", HWGROUP(drive)->rq->sector); @@ -980,6 +1056,13 @@ ide_end_drive_cmd(drive, stat, err); return ide_stopped; } + if (rq->cmd == IDE_DRIVE_TASKFILE) { + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); +// ide_end_taskfile(drive, stat, err); + return ide_stopped; + } + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { @@ -1141,62 +1224,125 @@ */ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { - byte *args = rq->buffer; - if (args && rq->cmd == IDE_DRIVE_TASK) { - byte sel; + switch(rq->cmd) { + case IDE_DRIVE_TASKFILE: + { + ide_task_t *args = rq->special; + + if (!(args)) break; + +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG + { + printk(KERN_INFO "%s: ", drive->name); +// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]); + printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]); + printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]); + printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]); + printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]); + printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]); + printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]); + printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]); + printk(KERN_INFO "%s: ", drive->name); +// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]); + printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]); + printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]); + printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]); + printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]); + printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]); + printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]); + printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]); + } +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + +// if (args->tf_out_flags.all == 0) { + do_taskfile(drive, + (struct hd_drive_task_hdr *)&args->tfRegister, + (struct hd_drive_hob_hdr *)&args->hobRegister, + args->handler); +// } else { +// return flagged_taskfile(drive, args); +// } + + if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) || + (args->command_type == IDE_DRIVE_TASK_OUT)) && + args->prehandler && args->handler) + return args->prehandler(drive, rq); + return ide_started; + } + case IDE_DRIVE_TASK: + { + byte *args = rq->buffer; + byte sel; + + if (!(args)) break; #ifdef DEBUG - printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n", - drive->name, - args[0], args[1], args[2], args[3], - args[4], args[5], args[6], args[7]); + printk("%s: DRIVE_TASK_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("fr=0x%02x ", args[1]); + printk("ns=0x%02x ", args[2]); + printk("sc=0x%02x ", args[3]); + printk("lcyl=0x%02x ", args[4]); + printk("hcyl=0x%02x ", args[5]); + printk("sel=0x%02x\n", args[6]); #endif - OUT_BYTE(args[1], IDE_FEATURE_REG); - OUT_BYTE(args[3], IDE_SECTOR_REG); - OUT_BYTE(args[4], IDE_LCYL_REG); - OUT_BYTE(args[5], IDE_HCYL_REG); - sel = (args[6] & ~0x10); - if (drive->select.b.unit) - sel |= 0x10; - OUT_BYTE(sel, IDE_SELECT_REG); - ide_cmd(drive, args[0], args[2], &drive_cmd_intr); - return ide_started; - } else if (args) { + OUT_BYTE(args[1], IDE_FEATURE_REG); + OUT_BYTE(args[3], IDE_SECTOR_REG); + OUT_BYTE(args[4], IDE_LCYL_REG); + OUT_BYTE(args[5], IDE_HCYL_REG); + sel = (args[6] & ~0x10); + if (drive->select.b.unit) + sel |= 0x10; + OUT_BYTE(sel, IDE_SELECT_REG); + ide_cmd(drive, args[0], args[2], &drive_cmd_intr); + return ide_started; + } + case IDE_DRIVE_CMD: + { + byte *args = rq->buffer; + + if (!(args)) break; #ifdef DEBUG - printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n", - drive->name, args[0], args[1], args[2], args[3]); + printk("%s: DRIVE_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("sc=0x%02x ", args[1]); + printk("fr=0x%02x ", args[2]); + printk("xx=0x%02x\n", args[3]); #endif - if (args[0] == WIN_SMART) { - OUT_BYTE(0x4f, IDE_LCYL_REG); - OUT_BYTE(0xc2, IDE_HCYL_REG); - OUT_BYTE(args[2],IDE_FEATURE_REG); - OUT_BYTE(args[1],IDE_SECTOR_REG); - ide_cmd(drive, args[0], args[3], &drive_cmd_intr); - return ide_started; - } - OUT_BYTE(args[2],IDE_FEATURE_REG); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return ide_started; - } else { - /* - * NULL is actually a valid way of waiting for - * all current requests to be flushed from the queue. - */ + if (args[0] == WIN_SMART) { + OUT_BYTE(0x4f, IDE_LCYL_REG); + OUT_BYTE(0xc2, IDE_HCYL_REG); + OUT_BYTE(args[2],IDE_FEATURE_REG); + OUT_BYTE(args[1],IDE_SECTOR_REG); + ide_cmd(drive, args[0], args[3], &drive_cmd_intr); + return ide_started; + } + OUT_BYTE(args[2],IDE_FEATURE_REG); + ide_cmd(drive, args[0], args[1], &drive_cmd_intr); + return ide_started; + } + default: + break; + } + /* + * NULL is actually a valid way of waiting for + * all current requests to be flushed from the queue. + */ #ifdef DEBUG - printk("%s: DRIVE_CMD (null)\n", drive->name); + printk("%s: DRIVE_CMD (null)\n", drive->name); #endif - ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); - return ide_stopped; - } + ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); + return ide_stopped; } /* * start_request() initiates handling of a new I/O request + * needed to reverse the perverted changes anonymously made back + * 2.3.99-pre6 */ -static ide_startstop_t start_request (ide_drive_t *drive) +static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; unsigned long block, blockend; - struct request *rq = blkdev_entry_next_request(&drive->queue.queue_head); unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; ide_hwif_t *hwif = HWIF(drive); @@ -1245,8 +1391,13 @@ return startstop; } if (!drive->special.all) { - if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { - return execute_drive_cmd(drive, rq); + switch(rq->cmd) { + case IDE_DRIVE_CMD: + case IDE_DRIVE_TASK: + case IDE_DRIVE_TASKFILE: + return execute_drive_cmd(drive, rq); + default: + break; } if (drive->driver != NULL) { return (DRIVER(drive)->do_request(drive, rq, block)); @@ -1267,13 +1418,15 @@ { ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long flags; + struct request *rq; spin_lock_irqsave(&io_request_lock, flags); hwgroup->handler = NULL; del_timer(&hwgroup->timer); + rq = hwgroup->rq; spin_unlock_irqrestore(&io_request_lock, flags); - return start_request(drive); + return start_request(drive, rq); } /* @@ -1370,10 +1523,11 @@ /* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back * into life on wakeup from machine sleep. */ -void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq) +void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) { ide_drive_t *drive; ide_hwif_t *hwif; + struct request *rq; ide_startstop_t startstop; ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only: POSSIBLY BROKEN HERE(?) */ @@ -1426,7 +1580,8 @@ if ( drive->queue.plugged ) /* paranoia */ printk("%s: Huh? nuking plugged queue\n", drive->name); - hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head); + + rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head); /* * Some systems have trouble with IDE IRQs arriving while * the driver is still setting things up. So, here we disable @@ -1439,7 +1594,7 @@ disable_irq_nosync(hwif->irq); spin_unlock(&io_request_lock); ide__sti(); /* allow other IRQs while we start this request */ - startstop = start_request(drive); + startstop = start_request(drive, rq); spin_lock_irq(&io_request_lock); if (masked_irq && hwif->irq != masked_irq) enable_irq(hwif->irq); @@ -1619,7 +1774,7 @@ * drive is ready to accept one, in which case we know the drive is not * trying to interrupt us. And ide_set_handler() is always invoked before * completing the issuance of any new drive command, so we will not be - * accidently invoked as a result of any valid command completion interrupt. + * accidentally invoked as a result of any valid command completion interrupt. * */ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) @@ -1867,7 +2022,7 @@ ide_drive_t *drive; ide_hwgroup_t *hwgroup; unsigned int p, major, minor; - long flags; + unsigned long flags; if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; @@ -1967,6 +2122,10 @@ (void) request_module("ide-tape"); if (drive->media == ide_floppy) (void) request_module("ide-floppy"); +#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) + if (drive->media == ide_scsi) + (void) request_module("ide-scsi"); +#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */ } #endif /* CONFIG_KMOD */ while (drive->busy) @@ -2295,6 +2454,7 @@ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); hwif->irq = hw->irq; hwif->noprobe = 0; + hwif->chipset = hw->chipset; if (!initializing) { ide_probe_module(); @@ -2590,6 +2750,61 @@ return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); } +int ide_reinit_drive (ide_drive_t *drive) +{ + switch (drive->media) { +#ifdef CONFIG_BLK_DEV_IDECD + case ide_cdrom: + { + extern int ide_cdrom_reinit(ide_drive_t *drive); + if (ide_cdrom_reinit(drive)) + return 1; + break; + } +#endif /* CONFIG_BLK_DEV_IDECD */ +#ifdef CONFIG_BLK_DEV_IDEDISK + case ide_disk: + { + extern int idedisk_reinit(ide_drive_t *drive); + if (idedisk_reinit(drive)) + return 1; + break; + } +#endif /* CONFIG_BLK_DEV_IDEDISK */ +#ifdef CONFIG_BLK_DEV_IDEFLOPPY + case ide_floppy: + { + extern int idefloppy_reinit(ide_drive_t *drive); + if (idefloppy_reinit(drive)) + return 1; + break; + } +#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ +#ifdef CONFIG_BLK_DEV_IDETAPE + case ide_tape: + { + extern int idetape_reinit(ide_drive_t *drive); + if (idetape_reinit(drive)) + return 1; + break; + } +#endif /* CONFIG_BLK_DEV_IDETAPE */ +#ifdef CONFIG_BLK_DEV_IDESCSI +/* + * { + * extern int idescsi_reinit(ide_drive_t *drive); + * if (idescsi_reinit(drive)) + * return 1; + * break; + * } + */ +#endif /* CONFIG_BLK_DEV_IDESCSI */ + default: + return 1; + } + return 0; +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2681,16 +2896,47 @@ drive->nice1 << IDE_NICE_1 | drive->nice2 << IDE_NICE_2, (long *) arg); + +#ifdef CONFIG_IDE_TASK_IOCTL + case HDIO_DRIVE_TASKFILE: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + switch(drive->media) { + case ide_disk: + return ide_taskfile_ioctl(drive, inode, file, cmd, arg); +#ifdef CONFIG_PKT_TASK_IOCTL + case ide_cdrom: + case ide_tape: + case ide_floppy: + return pkt_taskfile_ioctl(drive, inode, file, cmd, arg); +#endif /* CONFIG_PKT_TASK_IOCTL */ + default: + return -ENOMSG; + } +#endif /* CONFIG_IDE_TASK_IOCTL */ + case HDIO_DRIVE_CMD: { byte args[4], *argbuf = args; byte xfer_rate = 0; int argsize = 4; - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; + ide_task_t tfargs; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; if (NULL == (void *) arg) return ide_do_drive_cmd(drive, &rq, ide_wait); if (copy_from_user(args, (void *)arg, 4)) return -EFAULT; + + tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; + tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; + tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; + tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; + tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; + if (args[3]) { argsize = 4 + (SECTOR_WORDS * 4 * args[3]); argbuf = kmalloc(argsize, GFP_KERNEL); @@ -2699,9 +2945,9 @@ memcpy(argbuf, args, 4); } - if (set_transfer(drive, args[0], args[1], args[2])) { + if (set_transfer(drive, &tfargs)) { xfer_rate = args[1]; - if (ide_ata66_check(drive, args[0], args[1], args[2])) + if (ide_ata66_check(drive, &tfargs)) goto abort; } @@ -2761,7 +3007,24 @@ drive->nice1 = (arg >> IDE_NICE_1) & 1; return 0; case HDIO_DRIVE_RESET: + { + unsigned long flags; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + if (!capable(CAP_SYS_ADMIN)) return -EACCES; +#if 1 + spin_lock_irqsave(&io_request_lock, flags); + if (hwgroup->handler != NULL) { + printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler); + (void) hwgroup->handler(drive); +// hwgroup->handler = NULL; +// hwgroup->expiry = NULL; + hwgroup->timer.expires = jiffies + 0;; + del_timer(&hwgroup->timer); + } + spin_unlock_irqrestore(&io_request_lock, flags); + +#endif (void) ide_do_reset(drive); if (drive->suspend_reset) { /* @@ -2776,7 +3039,7 @@ return ide_revalidate_disk(inode->i_rdev); } return 0; - + } case BLKROSET: case BLKROGET: case BLKFLSBUF: @@ -2799,7 +3062,7 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (HWIF(drive)->busproc) - HWIF(drive)->busproc(HWIF(drive), arg); + HWIF(drive)->busproc(drive, (int)arg); return 0; default: @@ -3351,6 +3614,12 @@ pmac_ide_probe(); } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#ifdef CONFIG_BLK_DEV_IDE_SWARM + { + extern void swarm_ide_probe(void); + swarm_ide_probe(); + } +#endif /* CONFIG_BLK_DEV_IDE_SWARM */ #ifdef CONFIG_BLK_DEV_IDE_ICSIDE { extern void icside_init(void); @@ -3460,6 +3729,16 @@ return ide_unregister_subdriver(drive); } +static int default_standby (ide_drive_t *drive) +{ + return 0; +} + +static int default_flushcache (ide_drive_t *drive) +{ + return 0; +} + static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) { ide_end_request(0, HWGROUP(drive)); @@ -3510,7 +3789,7 @@ return ide_stopped; } -static int default_driver_reinit (ide_drive_t *drive) +static int default_reinit (ide_drive_t *drive) { printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name); @@ -3522,6 +3801,8 @@ ide_driver_t *d = drive->driver; if (d->cleanup == NULL) d->cleanup = default_cleanup; + if (d->standby == NULL) d->standby = default_standby; + if (d->flushcache == NULL) d->flushcache = default_flushcache; if (d->do_request == NULL) d->do_request = default_do_request; if (d->end_request == NULL) d->end_request = default_end_request; if (d->ioctl == NULL) d->ioctl = default_ioctl; @@ -3531,7 +3812,7 @@ if (d->pre_reset == NULL) d->pre_reset = default_pre_reset; if (d->capacity == NULL) d->capacity = default_capacity; if (d->special == NULL) d->special = default_special; - if (d->driver_reinit == NULL) d->driver_reinit = default_driver_reinit; + if (d->reinit == NULL) d->reinit = default_reinit; } ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n) @@ -3676,6 +3957,7 @@ EXPORT_SYMBOL(ide_output_data); EXPORT_SYMBOL(atapi_input_bytes); EXPORT_SYMBOL(atapi_output_bytes); +EXPORT_SYMBOL(drive_is_ready); EXPORT_SYMBOL(ide_set_handler); EXPORT_SYMBOL(ide_dump_status); EXPORT_SYMBOL(ide_error); @@ -3698,6 +3980,8 @@ EXPORT_SYMBOL(ide_remove_proc_entries); EXPORT_SYMBOL(proc_ide_read_geometry); EXPORT_SYMBOL(create_proc_ide_interfaces); +EXPORT_SYMBOL(recreate_proc_ide_device); +EXPORT_SYMBOL(destroy_proc_ide_device); #endif EXPORT_SYMBOL(ide_add_setting); EXPORT_SYMBOL(ide_remove_setting); @@ -3712,6 +3996,54 @@ EXPORT_SYMBOL(system_bus_clock); +EXPORT_SYMBOL(ide_reinit_drive); + +static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x) +{ + ide_hwif_t *hwif; + ide_drive_t *drive; + int i, unit; + + switch (event) { + case SYS_HALT: + case SYS_POWER_OFF: + case SYS_RESTART: + break; + default: + return NOTIFY_DONE; + } + + printk("flushing ide devices: "); + + for (i = 0; i < MAX_HWIFS; i++) { + hwif = &ide_hwifs[i]; + if (!hwif->present) + continue; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + drive = &hwif->drives[unit]; + if (!drive->present) + continue; + + /* set the drive to standby */ + printk("%s ", drive->name); + if (event != SYS_RESTART) + if (drive->driver != NULL && DRIVER(drive)->standby(drive)) + continue; + + if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + continue; + } + } + printk("\n"); + return NOTIFY_DONE; +} + +static struct notifier_block ide_notifier = { + ide_notify_reboot, + NULL, + 5 +}; + /* * This is gets invoked once during initialization, to set *everything* up */ @@ -3739,6 +4071,7 @@ ide_geninit(hwif); } + register_reboot_notifier(&ide_notifier); return 0; } @@ -3771,6 +4104,7 @@ { int index; + unregister_reboot_notifier(&ide_notifier); for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) diff -urN linux-2.4.18/drivers/ide/it8172.c linux-2.4.19-pre5/drivers/ide/it8172.c --- linux-2.4.18/drivers/ide/it8172.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/it8172.c Sat Mar 30 22:55:28 2002 @@ -50,7 +50,7 @@ #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) static byte it8172_dma_2_pio (byte xfer_rate); static int it8172_tune_chipset (ide_drive_t *drive, byte speed); -static int it8172_config_drive_for_dma (ide_drive_t *drive); +static int it8172_config_chipset_for_dma (ide_drive_t *drive); static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive); #endif unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name); @@ -60,38 +60,44 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio) { unsigned long flags; - u16 master_data; - u32 slave_data; + u16 drive_enables; + u32 drive_timing; int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = 0x40; - int slave_port = 0x44; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); - pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing); /* * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 * are being left at the default values of 8 PCI clocks (242 nsec * for a 33 MHz clock). These can be safely shortened at higher - * PIO modes. + * PIO modes. The DIOR/DIOW pulse width and recovery times only + * apply to PIO modes, not to the DMA modes. */ + /* + * Enable port 0x44. The IT8172G spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + if (is_slave) { - master_data |= 0x4000; + drive_enables &= 0xc006; if (pio > 1) - /* enable PPE and IE */ - master_data |= 0x0060; + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0060; } else { - master_data &= 0xc060; + drive_enables &= 0xc060; if (pio > 1) - /* enable PPE and IE */ - master_data |= 0x0006; + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0006; } save_flags(flags); cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables); restore_flags(flags); } @@ -160,6 +166,7 @@ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: + case XFER_MW_DMA_0: case XFER_SW_DMA_2: break; default: return -1; } @@ -182,7 +189,7 @@ return err; } -static int it8172_config_drive_for_dma (ide_drive_t *drive) +static int it8172_config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; byte speed; @@ -201,10 +208,12 @@ speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; } else if (id->dma_1word & 0x0004) { speed = XFER_SW_DMA_2; } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL); } (void) it8172_tune_chipset(drive, speed); @@ -220,7 +229,7 @@ { switch (func) { case ide_dma_check: - return ide_dmaproc((ide_dma_action_t)it8172_config_drive_for_dma(drive), + return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive), drive); default : break; diff -urN linux-2.4.18/drivers/ide/pdc202xx.c linux-2.4.19-pre5/drivers/ide/pdc202xx.c --- linux-2.4.18/drivers/ide/pdc202xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/pdc202xx.c Sat Mar 30 22:55:39 2002 @@ -108,7 +108,7 @@ u32 bibma = pci_resource_start(dev, 4); u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); - u8 hi = 0, lo = 0, invalid_data_set = 0; + u8 hi = 0, lo = 0; /* * at that point bibma+0x2 et bibma+0xa are byte registers @@ -132,11 +132,6 @@ pci_read_config_dword(dev, 0x6c, ®6ch); switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20268R: - p += sprintf(p, "\n PDC20268 TX2 Chipset.\n"); - invalid_data_set = 1; - break; case PCI_DEVICE_ID_PROMISE_20267: p += sprintf(p, "\n PDC20267 Chipset.\n"); break; @@ -180,45 +175,81 @@ p += sprintf(p, " Mode %s Mode %s\n", (sc1a & 0x01) ? "MASTER" : "PCI ", (sc1b & 0x01) ? "MASTER" : "PCI "); - if (!(invalid_data_set)) - p += sprintf(p, " %s %s\n", - (sc1d & 0x08) ? "Error " : - ((sc1d & 0x05) == 0x05) ? "Not My INTR " : - (sc1d & 0x04) ? "Interrupting" : - (sc1d & 0x02) ? "FIFO Full " : - (sc1d & 0x01) ? "FIFO Empty " : "????????????", - (sc1d & 0x80) ? "Error " : - ((sc1d & 0x50) == 0x50) ? "Not My INTR " : - (sc1d & 0x40) ? "Interrupting" : - (sc1d & 0x20) ? "FIFO Full " : - (sc1d & 0x10) ? "FIFO Empty " : "????????????"); + p += sprintf(p, " %s %s\n", + (sc1d & 0x08) ? "Error " : + ((sc1d & 0x05) == 0x05) ? "Not My INTR " : + (sc1d & 0x04) ? "Interrupting" : + (sc1d & 0x02) ? "FIFO Full " : + (sc1d & 0x01) ? "FIFO Empty " : "????????????", + (sc1d & 0x80) ? "Error " : + ((sc1d & 0x50) == 0x50) ? "Not My INTR " : + (sc1d & 0x40) ? "Interrupting" : + (sc1d & 0x20) ? "FIFO Full " : + (sc1d & 0x10) ? "FIFO Empty " : "????????????"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); p += sprintf(p, "DMA enabled: %s %s %s %s\n", (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); - if (!(invalid_data_set)) - p += sprintf(p, "DMA Mode: %s %s %s %s\n", - pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), - pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), - pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), - pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); - if (!(invalid_data_set)) - p += sprintf(p, "PIO Mode: %s %s %s %s\n", - pdc202xx_pio_verbose(reg60h), - pdc202xx_pio_verbose(reg64h), - pdc202xx_pio_verbose(reg68h), - pdc202xx_pio_verbose(reg6ch)); + p += sprintf(p, "DMA Mode: %s %s %s %s\n", + pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), + pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); + p += sprintf(p, "PIO Mode: %s %s %s %s\n", + pdc202xx_pio_verbose(reg60h), + pdc202xx_pio_verbose(reg64h), + pdc202xx_pio_verbose(reg68h), + pdc202xx_pio_verbose(reg6ch)); #if 0 p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n"); #endif - if (invalid_data_set) - p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n"); + return (char *)p; +} + +static char * pdc202xx_info_new (char *buf, struct pci_dev *dev) +{ + char *p = buf; +// u32 bibma = pci_resource_start(dev, 4); + +// u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; +// u16 reg50h = 0, word88 = 0; +// int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0; + + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + p += sprintf(p, "\n PDC20276 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20275: + p += sprintf(p, "\n PDC20275 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20269: + p += sprintf(p, "\n PDC20269 TX2 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20268R: + p += sprintf(p, "\n PDC20268 TX2 Chipset.\n"); + break; +default: + p += sprintf(p, "\n PDC202XX Chipset.\n"); + break; + } return (char *)p; } static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - p = pdc202xx_info(buffer, bmide_dev); + switch(bmide_dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20268R: + p = pdc202xx_info_new(buffer, bmide_dev); + break; + default: + p = pdc202xx_info(buffer, bmide_dev); + break; + } return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ @@ -387,9 +418,6 @@ if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1; - if (dev->device == PCI_DEVICE_ID_PROMISE_20268) - goto skip_register_hell; - pci_read_config_dword(dev, drive_pci, &drive_conf); pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); @@ -432,6 +460,7 @@ switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA + /* case XFER_UDMA_6: */ case XFER_UDMA_5: case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */ case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */ @@ -477,8 +506,6 @@ decode_registers(REG_D, DP); #endif /* PDC202XX_DECODE_REGISTER_INFO */ -skip_register_hell: - if (!drive->init_speed) drive->init_speed = speed; err = ide_config_drive_speed(drive, speed); @@ -494,6 +521,159 @@ return err; } +static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); +#ifdef CONFIG_BLK_DEV_IDEDMA + unsigned long indexreg = (hwif->dma_base + 1); + unsigned long datareg = (hwif->dma_base + 3); +#else + struct pci_dev *dev = hwif->pci_dev; + unsigned long high_16 = pci_resource_start(dev, 4); + unsigned long indexreg = high_16 + (hwif->channel ? 0x09 : 0x01); + unsigned long datareg = (indexreg + 2); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + byte thold = 0x10; + byte adj = (drive->dn%2) ? 0x08 : 0x00; + + int err; + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (speed == XFER_UDMA_2) { + OUT_BYTE((thold + adj), indexreg); + OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg); + } + switch (speed) { + case XFER_UDMA_7: + speed = XFER_UDMA_6; + case XFER_UDMA_6: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x01, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcb, datareg); + break; + case XFER_UDMA_5: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x02, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcb, datareg); + break; + case XFER_UDMA_4: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x03, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_3: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x05, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_2: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x2a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x07, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_1: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x3a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x0a, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xd0, datareg); + break; + case XFER_UDMA_0: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x4a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x0f, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xd5, datareg); + break; + case XFER_MW_DMA_2: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0x69, datareg); + OUT_BYTE((0x0f + adj), indexreg); + OUT_BYTE(0x25, datareg); + break; + case XFER_MW_DMA_1: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0x6b, datareg); + OUT_BYTE((0x0f+ adj), indexreg); + OUT_BYTE(0x27, datareg); + break; + case XFER_MW_DMA_0: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0xdf, datareg); + OUT_BYTE((0x0f + adj), indexreg); + OUT_BYTE(0x5f, datareg); + break; +#else + switch (speed) { +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x23, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x09, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x25, datareg); + break; + case XFER_PIO_3: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x27, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x0d, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x35, datareg); + break; + case XFER_PIO_2: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x23, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x26, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x64, datareg); + break; + case XFER_PIO_1: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x46, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x29, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0xa4, datareg); + break; + case XFER_PIO_0: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0xfb, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x2b, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0xac, datareg); + break; + default: + } + + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + + return err; +} + /* 0 1 2 3 4 5 6 7 8 * 960, 480, 390, 300, 240, 180, 120, 90, 60 * 180, 150, 120, 90, 60 @@ -524,18 +704,76 @@ struct pci_dev *dev = hwif->pci_dev; unsigned long high_16 = pci_resource_start(dev, 4); unsigned long dma_base = hwif->dma_base; + unsigned long indexreg = dma_base + 1; + unsigned long datareg = dma_base + 3; + byte iordy = 0x13; + byte adj = (drive->dn%2) ? 0x08 : 0x00; + byte cable = 0; + byte jumpbit = 0; byte unit = (drive->select.b.unit & 0x01); - unsigned int drive_conf; - byte drive_pci; + byte drive_pci = 0; byte test1, test2, speed = -1; byte AP; unsigned short EP; - byte CLKSPD = IN_BYTE(high_16 + 0x11); - byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; + byte CLKSPD = 0; + byte udma_33 = ultra; +// byte udma_33 = ultra ? (IN_BYTE(high_16 + 0x001f) & 1) : 0; byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0; - byte udma_100 = (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0; + byte udma_100 = 0; + byte udma_133 = 0; + byte mask = hwif->channel ? 0x08 : 0x02; + unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); + + byte ultra_66 = ((id->dma_ultra & 0x0010) || + (id->dma_ultra & 0x0008)) ? 1 : 0; + byte ultra_100 = ((id->dma_ultra & 0x0020) || + (ultra_66)) ? 1 : 0; + byte ultra_133 = ((id->dma_ultra & 0x0040) || + (ultra_100)) ? 1 : 0; + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + udma_133 = (udma_66) ? 1 : 0; + udma_100 = (udma_66) ? 1 : 0; + OUT_BYTE(0x0b, (hwif->dma_base + 1)); + cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); + jumpbit = 1; + break; + case PCI_DEVICE_ID_PROMISE_20268R: + udma_100 = 1; + udma_66 = 1; + OUT_BYTE(0x0b, (hwif->dma_base + 1)); + cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); + jumpbit = 1; + break; + case PCI_DEVICE_ID_PROMISE_20268: + udma_100 = (udma_66) ? 1 : 0; + OUT_BYTE(0x0b, (hwif->dma_base + 1)); + cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); + jumpbit = 1; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + udma_100 = (udma_66) ? 1 : 0; + pci_read_config_word(dev, 0x50, &EP); + cable = (EP & c_mask); + jumpbit = 0; + break; + case PCI_DEVICE_ID_PROMISE_20262: + pci_read_config_word(dev, 0x50, &EP); + cable = (EP & c_mask); + jumpbit = 0; + break; + default: + udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0; + break; + } + + if (!jumpbit) + CLKSPD = IN_BYTE(high_16 + 0x11); /* * Set the control register to use the 66Mhz system * clock for UDMA 3/4 mode operation. If one drive on @@ -549,47 +787,52 @@ * parameters. */ - byte mask = hwif->channel ? 0x08 : 0x02; - unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); - byte ultra_66 = ((id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008)) ? 1 : 0; - byte ultra_100 = ((id->dma_ultra & 0x0020) || - (id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008)) ? 1 : 0; - - if (dev->device == PCI_DEVICE_ID_PROMISE_20268) - goto jump_pci_mucking; - - pci_read_config_word(dev, 0x50, &EP); - - if (((ultra_66) || (ultra_100)) && (EP & c_mask)) { + if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) { #ifdef DEBUG printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary"); printk(" Switching to Ultra33 mode.\n"); #endif /* DEBUG */ /* Primary : zero out second bit */ /* Secondary : zero out fourth bit */ - OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); + printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); + printk("%s reduced to Ultra33 mode.\n", drive->name); + udma_66 = 0; udma_100 = 0; udma_133 = 0; } else { - if ((ultra_66) || (ultra_100)) { + if ((ultra_66) || (ultra_100) || (ultra_133)) { /* * check to make sure drive on same channel * is u66 capable */ if (hwif->drives[!(drive->dn%2)].id) { - if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) || + if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) || + (hwif->drives[!(drive->dn%2)].id->dma_ultra +& 0x0020) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { - OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { - OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } } else { /* udma4 drive by itself */ - OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } } } + if (jumpbit) { + if (drive->media != ide_disk) return ide_dma_off_quietly; + if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ + OUT_BYTE((iordy + adj), indexreg); + OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); + } + goto jumpbit_is_set; + } + switch(drive->dn) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); @@ -640,31 +883,33 @@ if (drive->media == ide_disk) /* PREFETCH_EN */ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); -jump_pci_mucking: +jumpbit_is_set: - if ((id->dma_ultra & 0x0020) && (udma_100)) speed = XFER_UDMA_5; - else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3; - else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2; - else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1; - else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0; + if ((id->dma_ultra & 0x0040)&&(udma_133)) speed = XFER_UDMA_6; + else if ((id->dma_ultra & 0x0020)&&(udma_100)) speed = XFER_UDMA_5; + else if ((id->dma_ultra & 0x0010)&&(udma_66)) speed = XFER_UDMA_4; + else if ((id->dma_ultra & 0x0008)&&(udma_66)) speed = XFER_UDMA_3; + else if ((id->dma_ultra & 0x0004)&&(udma_33)) speed = XFER_UDMA_2; + else if ((id->dma_ultra & 0x0002)&&(udma_33)) speed = XFER_UDMA_1; + else if ((id->dma_ultra & 0x0001)&&(udma_33)) speed = XFER_UDMA_0; else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; - else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; - else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; + else if ((id->dma_1word & 0x0004)&&(!jumpbit)) speed = XFER_SW_DMA_2; + else if ((id->dma_1word & 0x0002)&&(!jumpbit)) speed = XFER_SW_DMA_1; + else if ((id->dma_1word & 0x0001)&&(!jumpbit)) speed = XFER_SW_DMA_0; else { /* restore original pci-config space */ - if (dev->device != PCI_DEVICE_ID_PROMISE_20268) + if (!jumpbit) pci_write_config_dword(dev, drive_pci, drive_conf); return ide_dma_off_quietly; } outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - (void) pdc202xx_tune_chipset(drive, speed); + (void) hwif->speedproc(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : + ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : @@ -685,7 +930,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && @@ -732,16 +977,66 @@ */ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { - byte dma_stat = 0, sc1d = 0; - unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); - unsigned long dma_base = HWIF(drive)->dma_base; + byte dma_stat = 0; + byte sc1d = 0; + byte newchip = 0; + byte clock = 0; + byte hardware48hack = 0; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned long high_16 = pci_resource_start(dev, 4); + unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00); + unsigned long dma_base = hwif->dma_base; + + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268R: + case PCI_DEVICE_ID_PROMISE_20268: + newchip = 1; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20262: + hardware48hack = 1; + clock = IN_BYTE(high_16 + 0x11); + default: + break; + } switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); + case ide_dma_begin: + /* Note that this is done *after* the cmd has + * been issued to the drive, as per the BM-IDE spec. + * The Promise Ultra33 doesn't work correctly when + * we do this part before issuing the drive cmd. + */ + if ((drive->addressing) && (hardware48hack)) { + struct request *rq = HWGROUP(drive)->rq; + unsigned long word_count = 0; + + outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11); + word_count = (rq->nr_sectors << 8); + word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000; + outl(word_count, atapi_reg); + } + break; + case ide_dma_end: + if ((drive->addressing) && (hardware48hack)) { + outl(0, atapi_reg); /* zero out extra */ + clock = IN_BYTE(high_16 + 0x11); + OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); + } + break; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - sc1d = inb(high_16 + 0x001d); + dma_stat = IN_BYTE(dma_base+2); + if (newchip) + return (dma_stat & 4) == 4; + + sc1d = IN_BYTE(high_16 + 0x001d); if (HWIF(drive)->channel) { if ((sc1d & 0x50) == 0x50) goto somebody_else; else if ((sc1d & 0x40) == 0x40) @@ -764,61 +1059,114 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ +void pdc202xx_new_reset (ide_drive_t *drive) +{ + OUT_BYTE(0x04,IDE_CONTROL_REG); + mdelay(1000); + OUT_BYTE(0x00,IDE_CONTROL_REG); + mdelay(1000); + printk("PDC202XX: %s channel reset.\n", + HWIF(drive)->channel ? "Secondary" : "Primary"); +} + void pdc202xx_reset (ide_drive_t *drive) { unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); - byte udma_speed_flag = inb(high_16 + 0x001f); + byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); mdelay(100); OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); mdelay(2000); /* 2 seconds ?! */ + printk("PDC202XX: %s channel reset.\n", + HWIF(drive)->channel ? "Secondary" : "Primary"); } -unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) +/* + * Since SUN Cobalt is attempting to do this operation, I should disclose + * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date + * HOTSWAP ATA Infrastructure. + */ +static int pdc202xx_tristate (ide_drive_t * drive, int state) { - unsigned long high_16 = pci_resource_start(dev, 4); - byte udma_speed_flag = inb(high_16 + 0x001f); - byte primary_mode = inb(high_16 + 0x001a); - byte secondary_mode = inb(high_16 + 0x001b); - - if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) || - (dev->device == PCI_DEVICE_ID_PROMISE_20265) || - (dev->device == PCI_DEVICE_ID_PROMISE_20267)) { - /* - * software reset - this is required because the bios - * will set UDMA timing on if the hdd supports it. The - * user may want to turn udma off. A bug in the pdc20262 - * is that it cannot handle a downgrade in timing from UDMA - * to DMA. Disk accesses after issuing a set feature command - * will result in errors. A software reset leaves the timing - * registers intact, but resets the drives. - */ - - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ +#if 0 + ide_hwif_t *hwif = HWIF(drive); + unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); + byte sc1f = inb(high_16 + 0x001f); + + if (!hwif) + return -EINVAL; + +// hwif->bus_state = state; + + if (state) { + outb(sc1f | 0x08, high_16 + 0x001f); + } else { + outb(sc1f & ~0x08, high_16 + 0x001f); } +#endif + return 0; +} + +unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) +{ + unsigned long high_16 = pci_resource_start(dev, 4); + byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); + byte primary_mode = IN_BYTE(high_16 + 0x001a); + byte secondary_mode = IN_BYTE(high_16 + 0x001b); + byte newchip = 0; if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { - byte irq = 0, irq2 = 0; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ - if ((irq != irq2) && - (dev->device != PCI_DEVICE_ID_PROMISE_20265) && - (dev->device != PCI_DEVICE_ID_PROMISE_20267) && - (dev->device != PCI_DEVICE_ID_PROMISE_20268)) { - pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ - printk("%s: pci-config space interrupt mirror fixed.\n", name); - } + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268R: + case PCI_DEVICE_ID_PROMISE_20268: + newchip = 1; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + mdelay(100); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + mdelay(2000); /* 2 seconds ?! */ + break; + case PCI_DEVICE_ID_PROMISE_20262: + /* + * software reset - this is required because the bios + * will set UDMA timing on if the hdd supports it. The + * user may want to turn udma off. A bug in the pdc20262 + * is that it cannot handle a downgrade in timing from + * UDMA to DMA. Disk accesses after issuing a set + * feature command will result in errors. A software + * reset leaves the timing registers intact, + * but resets the drives. + */ + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + mdelay(100); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + mdelay(2000); /* 2 seconds ?! */ + default: + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { + byte irq = 0, irq2 = 0; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ + if (irq != irq2) { + pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ + printk("%s: pci-config space interrupt mirror fixed.\n", name); + } + } + break; } + if (newchip) + goto fttk_tx_series; + printk("%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", @@ -830,8 +1178,8 @@ #ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); - outb(udma_speed_flag|1, high_16 + 0x001f); - printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); + OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f); + printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA"); } #endif /* CONFIG_PDC202XX_BURST */ @@ -839,18 +1187,20 @@ if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); - outb(primary_mode|1, high_16 + 0x001a); - printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); + OUT_BYTE(primary_mode|1, high_16 + 0x001a); + printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); } if (!(secondary_mode & 1)) { printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", name, secondary_mode, (secondary_mode|1)); - outb(secondary_mode|1, high_16 + 0x001b); - printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); + OUT_BYTE(secondary_mode|1, high_16 + 0x001b); + printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } #endif /* CONFIG_PDC202XX_MASTER */ +fttk_tx_series: + #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) if (!pdc202xx_proc) { pdc202xx_proc = 1; @@ -866,20 +1216,43 @@ unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10); unsigned short CIS; - pci_read_config_word(hwif->pci_dev, 0x50, &CIS); - return ((CIS & mask) ? 0 : 1); + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20268R: + OUT_BYTE(0x0b, (hwif->dma_base + 1)); + return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04)); + default: + pci_read_config_word(hwif->pci_dev, 0x50, &CIS); + return (!(CIS & mask)); + } } void __init ide_init_pdc202xx (ide_hwif_t *hwif) { - hwif->tuneproc = &pdc202xx_tune_drive; - hwif->speedproc = &pdc202xx_tune_chipset; - hwif->quirkproc = &pdc202xx_quirkproc; - - if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) || - (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) || - (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) { - hwif->resetproc = &pdc202xx_reset; + hwif->tuneproc = &pdc202xx_tune_drive; + hwif->quirkproc = &pdc202xx_quirkproc; + + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20268R: + hwif->speedproc = &pdc202xx_new_tune_chipset; + hwif->resetproc = &pdc202xx_new_reset; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20262: + hwif->busproc = &pdc202xx_tristate; + hwif->resetproc = &pdc202xx_reset; + case PCI_DEVICE_ID_PROMISE_20246: + hwif->speedproc = &pdc202xx_tune_chipset; + default: + break; } #undef CONFIG_PDC202XX_32_UNMASK diff -urN linux-2.4.18/drivers/ide/pdc4030.c linux-2.4.19-pre5/drivers/ide/pdc4030.c --- linux-2.4.18/drivers/ide/pdc4030.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/pdc4030.c Sat Mar 30 22:55:34 2002 @@ -89,6 +89,12 @@ #include "pdc4030.h" +#ifdef CONFIG_IDE_TASKFILE_IO +# define __TASKFILE__IO +#else /* CONFIG_IDE_TASKFILE_IO */ +# undef __TASKFILE__IO +#endif /* CONFIG_IDE_TASKFILE_IO */ + /* * promise_selectproc() is invoked by ide.c * in preparation for access to the specified drive. @@ -298,8 +304,6 @@ } } - - /* * promise_read_intr() is the handler for disk read/multread interrupts */ @@ -495,11 +499,15 @@ */ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { + ide_startstop_t startstop; unsigned long timeout; byte stat; - if (rq->cmd == READ) { - OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); + switch(rq->cmd) { + case READ: +#ifndef __TASKFILE__IO + OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); +#endif /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -510,44 +518,61 @@ * If neither of these is the case, we wait for up to 50ms (badly I'm * afraid!) until one of them is. */ - timeout = jiffies + HZ/20; /* 50ms wait */ - do { - stat=GET_STAT(); - if (stat & DRQ_STAT) { - udelay(1); - return promise_read_intr(drive); - } - if (IN_BYTE(IDE_SELECT_REG) & 0x01) { + timeout = jiffies + HZ/20; /* 50ms wait */ + do { + stat=GET_STAT(); + if (stat & DRQ_STAT) { + udelay(1); + return promise_read_intr(drive); + } + if (IN_BYTE(IDE_SELECT_REG) & 0x01) { #ifdef DEBUG_READ - printk(KERN_DEBUG "%s: read: waiting for " - "interrupt\n", drive->name); + printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name); #endif - ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); - return ide_started; - } - udelay(1); - } while (time_before(jiffies, timeout)); - - printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", - drive->name); - return ide_stopped; - } else if (rq->cmd == WRITE) { - ide_startstop_t startstop; - OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing " - "PROMISE_WRITE\n", drive->name); - return startstop; - } - if (!drive->unmask) - __cli(); /* local CPU only */ - HWGROUP(drive)->wrq = *rq; /* scratchpad */ - return promise_write(drive); + ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); + return ide_started; + } + udelay(1); + } while (time_before(jiffies, timeout)); - } else { - printk("KERN_WARNING %s: bad command: %d\n", - drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); - return ide_stopped; + printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name); + return ide_stopped; + case WRITE: +#ifndef __TASKFILE__IO + OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); +#endif + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name); + return startstop; + } + if (!drive->unmask) + __cli(); /* local CPU only */ + HWGROUP(drive)->wrq = *rq; /* scratchpad */ + return promise_write(drive); + default: + printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); + return ide_stopped; } } + +#ifdef __TASKFILE__IO + +ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +{ + struct hd_drive_task_hdr taskfile; + + memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + + taskfile.sector_count = rq->nr_sectors; + taskfile.sector_number = block; + taskfile.low_cylinder = (block>>=8); + taskfile.high_cylinder = (block>>=8); + taskfile.device_head = ((block>>8)&0x0f)|drive->select.all; + taskfile.command = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE; + + do_taskfile(drive, &taskfile, NULL, NULL); + return do_pdc4030_io(drive, rq); +} +#endif + diff -urN linux-2.4.18/drivers/ide/piix.c linux-2.4.19-pre5/drivers/ide/piix.c --- linux-2.4.18/drivers/ide/piix.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/piix.c Sat Mar 30 22:55:34 2002 @@ -258,8 +258,8 @@ master_data = master_data | 0x0070; pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1] - << (HWIF(drive)->index ? 4 : 0))); + slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) + << (HWIF(drive)->index ? 4 : 0)); } else { master_data = master_data & 0xccf8; if (pio > 1) @@ -425,7 +425,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ dma_func = piix_config_drive_for_dma(drive); if ((id->field_valid & 2) && diff -urN linux-2.4.18/drivers/ide/qd65xx.c linux-2.4.19-pre5/drivers/ide/qd65xx.c --- linux-2.4.18/drivers/ide/qd65xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/qd65xx.c Sat Mar 30 22:55:34 2002 @@ -1,14 +1,15 @@ /* - * linux/drivers/ide/qd65xx.c Version 0.06 Aug 3, 2000 + * linux/drivers/ide/qd65xx.c Version 0.07 Sep 30, 2001 * - * Copyright (C) 1996-2000 Linus Torvalds & author (see below) + * Copyright (C) 1996-2001 Linus Torvalds & author (see below) */ /* * Version 0.03 Cleaned auto-tune, added probe * Version 0.04 Added second channel tuning * Version 0.05 Enhanced tuning ; added qd6500 support - * Version 0.06 added dos driver's list + * Version 0.06 Added dos driver's list + * Version 0.07 Second channel bug fix * * QDI QD6500/QD6580 EIDE controller fast support * @@ -67,6 +68,7 @@ * qd6500: 1100 * qd6580: either 1010 or 0101 * + * * base+0x02: Timer2 (qd6580 only) * * @@ -137,12 +139,12 @@ { byte active_cycle,recovery_cycle; - if (system_bus_clock()<=33) { - active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9); - recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15); + if (ide_system_bus_speed()<=33) { + active_cycle = 9 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 9); + recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15); } else { - active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8); - recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18); + active_cycle = 8 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 1, 8); + recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18); } return((recovery_cycle<<4) | 0x08 | active_cycle); @@ -156,8 +158,8 @@ static byte qd6580_compute_timing (int active_time, int recovery_time) { - byte active_cycle = 17-IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17); - byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15); + byte active_cycle = 17-IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 17); + byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15); return((recovery_cycle<<4) | active_cycle); } @@ -427,7 +429,8 @@ ide_hwifs[i].tuneproc = &qd6580_tune_drive; for (j=0;j<2;j++) { - ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA; + ide_hwifs[i].drives[j].drive_data = + i?QD6580_DEF_DATA2:QD6580_DEF_DATA; ide_hwifs[i].drives[j].io_32bit = 1; } } diff -urN linux-2.4.18/drivers/ide/qd65xx.h linux-2.4.19-pre5/drivers/ide/qd65xx.h --- linux-2.4.18/drivers/ide/qd65xx.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/qd65xx.h Sat Mar 30 22:55:34 2002 @@ -29,7 +29,7 @@ #define QD_CONTR_SEC_DISABLED 0x01 -#define QD_ID3 (config & QD_CONFIG_ID3) +#define QD_ID3 ((config & QD_CONFIG_ID3)!=0) #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) #define QD_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8) @@ -39,6 +39,7 @@ #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) +#define QD6580_DEF_DATA2 ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) #define QD_DEF_CONTR (0x40 | ((control & 0x02) ? 0x9f : 0x1f)) #define QD_TESTVAL 0x19 /* safe value */ diff -urN linux-2.4.18/drivers/ide/serverworks.c linux-2.4.19-pre5/drivers/ide/serverworks.c --- linux-2.4.18/drivers/ide/serverworks.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/serverworks.c Sat Mar 30 22:55:34 2002 @@ -1,16 +1,26 @@ /* - * linux/drivers/ide/serverworks.c Version 0.2 17 Oct 2000 + * linux/drivers/ide/serverworks.c Version 0.3 26 Oct 2001 * - * Copyright (C) 2000 Cobalt Networks, Inc. - * May be copied or modified under the terms of the GNU General Public License + * May be copied or modified under the terms of the GNU General Public License * - * interface borrowed from alim15x3.c: - * Copyright (C) 1998-2000 Michel Aubry, Maintainer - * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1998-2000 Michel Aubry + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz + * Copyright (C) 1998-2000 Andre Hedrick + * Portions copyright (c) 2001 Sun Microsystems * - * Copyright (C) 1998-2000 Andre Hedrick * - * IDE support for the ServerWorks OSB4 IDE chipset + * RCC/ServerWorks IDE driver for Linux + * + * OSB4: `Open South Bridge' IDE Interface (fn 1) + * supports UDMA mode 2 (33 MB/s) + * + * CSB5: `Champion South Bridge' IDE Interface (fn 1) + * all revisions support UDMA mode 4 (66 MB/s) + * revision A2.0 and up support UDMA mode 5 (100 MB/s) + * + * *** The CSB5 does not provide ANY register *** + * *** to detect 80-conductor cable presence. *** + * * * here's the default lspci: * @@ -83,15 +93,15 @@ #include "ide_modes.h" -#define SVWKS_DEBUG_DRIVE_INFO 0 - -#define DISPLAY_SVWKS_TIMINGS +#define DISPLAY_SVWKS_TIMINGS 1 +#undef SVWKS_DEBUG_DRIVE_INFO #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) #include #include static struct pci_dev *bmide_dev; +static byte svwks_revision = 0; static int svwks_get_info(char *, char **, off_t, int); extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */ @@ -103,7 +113,7 @@ u32 bibma = pci_resource_start(bmide_dev, 4); u32 reg40, reg44; u16 reg48, reg56; - u8 c0 = 0, c1 = 0, reg54; + u8 reg54, c0=0, c1=0; pci_read_config_dword(bmide_dev, 0x40, ®40); pci_read_config_dword(bmide_dev, 0x44, ®44); @@ -120,20 +130,23 @@ switch(bmide_dev->device) { case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - p += sprintf(p, "\n ServerWorks CSB5 Chipset.\n"); + p += sprintf(p, "\n " + "ServerWorks CSB5 Chipset (rev %02x)\n", + svwks_revision); break; - case PCI_DEVICE_ID_SERVERWORKS_OSB4: - p += sprintf(p, "\n ServerWorks OSB4 Chipset.\n"); + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + p += sprintf(p, "\n " + "ServerWorks OSB4 Chipset (rev %02x)\n", + svwks_revision); break; default: - p += sprintf(p, "\n ServerWorks 0x%04x Chipset.\n", bmide_dev->device); + p += sprintf(p, "\n " + "ServerWorks %04x Chipset (rev %02x)\n", + bmide_dev->device, svwks_revision); break; } p += sprintf(p, "------------------------------- General Status ---------------------------------\n"); -#if 0 - p += sprintf(p, " : %s\n", "str"); -#endif p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); p += sprintf(p, " %sabled %sabled\n", (c0&0x80) ? "dis" : " en", @@ -191,11 +204,7 @@ ((reg44&0x00210000)==0x00210000)?"1": ((reg44&0x00770000)==0x00770000)?"0": ((reg44&0x00FF0000)==0x00FF0000)?"X":"?"); -#if 0 - if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) - p += sprintf(p, "PIO enabled: %s %s %s %s\n", - if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4) -#endif + p += sprintf(p, "PIO enabled: %s %s %s %s\n", ((reg40&0x00002000)==0x00002000)?"4": ((reg40&0x00002200)==0x00002200)?"3": @@ -221,7 +230,7 @@ } #endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */ -static byte svwks_revision = 0; +#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ byte svwks_proc = 0; @@ -292,6 +301,7 @@ pio_timing |= pio_modes[speed - XFER_PIO_0]; csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn)); break; + #ifdef CONFIG_BLK_DEV_IDEDMA case XFER_MW_DMA_2: case XFER_MW_DMA_1: @@ -307,9 +317,9 @@ case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: - pio_timing |= pio_modes[pio]; - csb5_pio |= (pio << (4*drive->dn)); - dma_timing |= dma_modes[2]; + pio_timing |= pio_modes[pio]; + csb5_pio |= (pio << (4*drive->dn)); + dma_timing |= dma_modes[2]; ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit)); ultra_enable |= (0x01 << drive->dn); #endif @@ -322,9 +332,9 @@ drive->name, ultra_timing, dma_timing, pio_timing); #endif -#if OSB4_DEBUG_DRIVE_INFO +#if SVWKS_DEBUG_DRIVE_INFO printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* OSB4_DEBUG_DRIVE_INFO */ +#endif /* SVWKS_DEBUG_DRIVE_INFO */ if (!drive->init_speed) drive->init_speed = speed; @@ -338,11 +348,10 @@ pci_write_config_byte(dev, drive_pci3, ultra_timing); pci_write_config_byte(dev, 0x54, ultra_enable); - if (speed > XFER_PIO_4) { + if (speed > XFER_PIO_4) outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - } else { + else outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - } #endif /* CONFIG_BLK_DEV_IDEDMA */ err = ide_config_drive_speed(drive, speed); @@ -354,25 +363,24 @@ { unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; unsigned short xfer_pio = drive->id->eide_pio_modes; - byte timing, speed, pio; + byte timing, speed, pio; pio = ide_get_best_pio_mode(drive, 255, 5, NULL); if (xfer_pio> 4) xfer_pio = 0; - if (drive->id->eide_pio_iordy > 0) { + if (drive->id->eide_pio_iordy > 0) for (xfer_pio = 5; xfer_pio>0 && drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; xfer_pio--); - } else { + else xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : (drive->id->eide_pio_modes & 2) ? 0x04 : (drive->id->eide_pio_modes & 1) ? 0x03 : (drive->id->tPIO & 2) ? 0x02 : (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - } timing = (xfer_pio >= pio) ? xfer_pio : pio; @@ -407,12 +415,10 @@ { struct hd_driveid *id = drive->id; struct pci_dev *dev = HWIF(drive)->pci_dev; - byte udma_66 = eighty_ninty_three(drive); - byte speed; - - int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0; - /* need specs to figure out if osb4 is capable of ata/66/100 */ - int ultra100 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0; + byte udma_66 = eighty_ninty_three(drive); + int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0; + int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0; + byte speed; if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) { speed = XFER_UDMA_5; @@ -458,7 +464,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -499,7 +505,41 @@ switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); - default : + case ide_dma_end: + { + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + + if(inb(dma_base+0x02)&1) + { +#if 0 + int i; + printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n"); + for(i=0;i<10;i++) + { + if(!(inb(dma_base+0x02)&1)) + { + printk(KERN_ERR "OSB4 now finished.\n"); + break; + } + udelay(5); + } +#endif + printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n"); + printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n"); + printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n"); +#if 0 + /* Panic might sys_sync -> death by corrupt disk */ + panic("OSB4: continuing might cause disk corruption.\n"); +#else + printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n"); + while(1) + cpu_relax(); +#endif + } + /* and drop through */ + } + default: break; } /* Other cases are done by generic IDE-DMA code. */ @@ -509,30 +549,43 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) { - unsigned int reg64; + unsigned int reg; + byte btr; + /* save revision id to determine DMA capability */ pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { - isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + /* force Master Latency Timer value to 64 PCICLKs */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - pci_read_config_dword(isa_dev, 0x64, ®64); -#ifdef DEBUG - printk("%s: reg64 == 0x%08x\n", name, reg64); -#endif + /* OSB4 : South Bridge and IDE */ + if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + if (isa_dev) { + pci_read_config_dword(isa_dev, 0x64, ®); + reg &= ~0x00002000; /* disable 600ns interrupt mask */ + reg |= 0x00004000; /* enable UDMA/33 support */ + pci_write_config_dword(isa_dev, 0x64, reg); + } + } -// reg64 &= ~0x0000A000; -//#ifdef CONFIG_SMP -// reg64 |= 0x00008000; -//#endif - /* Assume the APIC was set up properly by the BIOS for now . If it - wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control - APIC enable, routing and decode */ - - reg64 &= ~0x00002000; - pci_write_config_dword(isa_dev, 0x64, reg64); + /* setup CSB5 : South Bridge and IDE */ + else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) { + /* setup the UDMA Control register + * + * 1. clear bit 6 to enable DMA + * 2. enable DMA modes with bits 0-1 + * 00 : legacy + * 01 : udma2 + * 10 : udma2/udma4 + * 11 : udma2/udma4/udma5 + */ + pci_read_config_byte(dev, 0x5A, &btr); + btr &= ~0x40; + btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; + pci_write_config_byte(dev, 0x5A, btr); } - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) if (!svwks_proc) { @@ -551,26 +604,46 @@ * Bit 14 clear = primary IDE channel does not have 80-pin cable. * Bit 14 set = primary IDE channel has 80-pin cable. */ - static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; - if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && - dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) + struct pci_dev *dev = hwif->pci_dev; + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && + dev->vendor == PCI_VENDOR_ID_SERVERWORKS && + dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) return ((1 << (hwif->channel + 14)) & dev->subsystem_device) ? 1 : 0; - return 0; +} +/* Sun Cobalt Alpine hardware avoids the 80-pin cable + * detect issue by attaching the drives directly to the board. + * This check follows the Dell precedent (how scary is that?!) + * + * WARNING: this only works on Alpine hardware! + */ +static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && + dev->vendor == PCI_VENDOR_ID_SERVERWORKS && + dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) + return ((1 << (hwif->channel + 14)) & + dev->subsystem_device) ? 1 : 0; + return 0; } unsigned int __init ata66_svwks (ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = hwif->pci_dev; + + /* Dell PowerEdge */ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) return ata66_svwks_dell (hwif); - + + /* Cobalt Alpine */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN) + return ata66_svwks_cobalt (hwif); + return 0; } @@ -586,12 +659,12 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; - return; #else /* CONFIG_BLK_DEV_IDEDMA */ - if (hwif->dma_base) { +#ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; +#endif hwif->dmaproc = &svwks_dmaproc; } else { hwif->autodma = 0; diff -urN linux-2.4.18/drivers/ide/sis5513.c linux-2.4.19-pre5/drivers/ide/sis5513.c --- linux-2.4.18/drivers/ide/sis5513.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/sis5513.c Sat Mar 30 22:55:34 2002 @@ -1,11 +1,28 @@ /* - * linux/drivers/ide/sis5513.c Version 0.11 June 9, 2000 + * linux/drivers/ide/sis5513.c Version 0.13 February 14, 2002 * * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 2002 Lionel Bouton , Maintainer * May be copied or modified under the terms of the GNU General Public License * * Thanks to SIS Taiwan for direct support and hardware. - * Tested and designed on the SiS620/5513 chipset. + * Thanks to Daniela Engert for ATA100 support advice. + * Original tests and design on the SiS620/5513 chipset. + * ATA100 tests and design on the SiS735/5513 chipset. + * ATA16/33 design from specs + */ + +/* + * TODO: + * - Are there pre-ATA_16 SiS chips ? -> tune init code for them + * or remove ATA_00 defines + * - Get ridden of SisHostChipInfo[] completness dependancy. + * - Get ATA-133 datasheets, implement ATA-133 init code. + * - Check latency timer init correctness. + * - More checks in the config registers (force values instead of + * relying on the BIOS setting them correctly). + * - Further optimisations ? + * . for example ATA66+ regs 0x48 & 0x4A */ #include @@ -28,88 +45,181 @@ #include "ide_modes.h" +#define DEBUG +/* if BROKEN_LEVEL is defined it limits the DMA mode + at boot time to its value */ +// #define BROKEN_LEVEL XFER_SW_DMA_0 #define DISPLAY_SIS_TIMINGS -#define SIS5513_DEBUG_DRIVE_INFO 0 -static struct pci_dev *host_dev = NULL; +/* Miscellaneaous flags */ +#define SIS5513_LATENCY 0x01 +/* ATA transfer mode capabilities */ +#define ATA_00 0x00 +#define ATA_16 0x01 +#define ATA_33 0x02 +#define ATA_66 0x03 +#define ATA_100 0x04 +#define ATA_133 0x05 + +static unsigned char dma_capability = 0x00; + + +/* + * Debug code: following IDE config registers' changes + */ +#ifdef DEBUG +/* Copy of IDE Config registers 0x00 -> 0x58 + Fewer might be used depending on the actual chipset */ +static unsigned char ide_regs_copy[] = { + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0 +}; + +static byte sis5513_max_config_register(void) { + switch(dma_capability) { + case ATA_00: + case ATA_16: return 0x4f; + case ATA_33: return 0x52; + case ATA_66: + case ATA_100: + case ATA_133: + default: return 0x57; + } +} + +/* Read config registers, print differences from previous read */ +static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { + int i; + byte reg_val; + byte changed=0; + byte max = sis5513_max_config_register(); + + printk("SIS5513: %s, changed registers:\n", info); + for(i=0; i<=max; i++) { + pci_read_config_byte(dev, i, ®_val); + if (reg_val != ide_regs_copy[i]) { + printk("%0#x: %0#x -> %0#x\n", + i, ide_regs_copy[i], reg_val); + ide_regs_copy[i]=reg_val; + changed=1; + } + } + + if (!changed) { + printk("none\n"); + } +} + +/* Load config registers, no printing */ +static void sis5513_load_registers(struct pci_dev* dev) { + int i; + byte max = sis5513_max_config_register(); + + for(i=0; i<=max; i++) { + pci_read_config_byte(dev, i, &(ide_regs_copy[i])); + } +} + +/* Print a register */ +static void sis5513_print_register(int reg) { + printk(" %0#x:%0#x", reg, ide_regs_copy[reg]); +} + +/* Print valuable registers (for ATA100) */ +static void sis5513_print_registers(struct pci_dev* dev, char* marker) { + int i; + byte max = sis5513_max_config_register(); + + sis5513_load_registers(dev); + printk("SIS5513 %s\n", marker); + printk("SIS5513 dump:"); + for(i=0x00; i<0x40; i++) { + if ((i % 0x10)==0) printk("\n "); + sis5513_print_register(i); + } + for(; i<49; i++) { + sis5513_print_register(i); + } + printk("\n "); + + for(; i<=max; i++) { + sis5513_print_register(i); + } + printk("\n"); +} +#endif -#define SIS5513_FLAG_ATA_00 0x00000000 -#define SIS5513_FLAG_ATA_16 0x00000001 -#define SIS5513_FLAG_ATA_33 0x00000002 -#define SIS5513_FLAG_ATA_66 0x00000004 -#define SIS5513_FLAG_LATENCY 0x00000010 +/* + * Devices supported + */ static const struct { const char *name; unsigned short host_id; - unsigned int flags; + unsigned char dma_capability; + unsigned char flags; } SiSHostChipInfo[] = { - { "SiS530", PCI_DEVICE_ID_SI_530, SIS5513_FLAG_ATA_66, }, - { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, - { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS635", PCI_DEVICE_ID_SI_635, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS640", PCI_DEVICE_ID_SI_640, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS645", PCI_DEVICE_ID_SI_645, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS650", PCI_DEVICE_ID_SI_650, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS730", PCI_DEVICE_ID_SI_730, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS735", PCI_DEVICE_ID_SI_735, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS740", PCI_DEVICE_ID_SI_740, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS745", PCI_DEVICE_ID_SI_745, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS750", PCI_DEVICE_ID_SI_750, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, - { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, }, - { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, - { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, - { "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, }, + { "SiS750", PCI_DEVICE_ID_SI_750, ATA_100, SIS5513_LATENCY }, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100, SIS5513_LATENCY }, + { "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, SIS5513_LATENCY }, + { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY }, + { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100, SIS5513_LATENCY }, + { "SiS650", PCI_DEVICE_ID_SI_650, ATA_100, SIS5513_LATENCY }, + { "SiS645", PCI_DEVICE_ID_SI_645, ATA_100, SIS5513_LATENCY }, + { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY }, + { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY }, + { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY }, + { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY }, + { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0}, + { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0}, + { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0}, + { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33, 0}, + { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33, 0}, + { "SiS5591", PCI_DEVICE_ID_SI_5591, ATA_33, 0}, + { "SiS5513", PCI_DEVICE_ID_SI_5513, ATA_16, 0}, + { "SiS5511", PCI_DEVICE_ID_SI_5511, ATA_16, 0}, }; -#if 0 - -static struct _pio_mode_mapping { - byte data_active; - byte recovery; - byte pio_mode; -} pio_mode_mapping[] = { - { 8, 12, 0 }, - { 6, 7, 1 }, - { 4, 4, 2 }, - { 3, 3, 3 }, - { 3, 1, 4 } -}; - -static struct _dma_mode_mapping { - byte data_active; - byte recovery; - byte dma_mode; -} dma_mode_mapping[] = { - { 8, 8, 0 }, - { 3, 2, 1 }, - { 3, 1, 2 } +/* Cycle time bits and values vary accross chip dma capabilities + These three arrays hold the register layout and the values to set. + Indexed by dma_capability and (dma_mode - XFER_UDMA_0) */ +static byte cycle_time_offset[] = {0,0,5,4,0,0}; +static byte cycle_time_range[] = {0,0,2,3,4,4}; +static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = { + {0,0,0,0,0,0}, /* no udma */ + {0,0,0,0,0,0}, /* no udma */ + {3,2,1,0,0,0}, + {7,5,3,2,1,0}, + {11,7,5,4,2,1}, + {0,0,0,0,0,0} /* not yet known, ask SiS */ }; -static struct _udma_mode_mapping { - byte cycle_time; - char * udma_mode; -} udma_mode_mapping[] = { - { 8, "Mode 0" }, - { 6, "Mode 1" }, - { 4, "Mode 2" }, - { 3, "Mode 3" }, - { 2, "Mode 4" }, - { 0, "Mode 5" } -}; +static struct pci_dev *host_dev = NULL; -static __inline__ char * find_udma_mode (byte cycle_time) -{ - int n; - - for (n = 0; n <= 4; n++) - if (udma_mode_mapping[n].cycle_time <= cycle_time) - return udma_mode_mapping[n].udma_mode; - return udma_mode_mapping[4].udma_mode; -} -#endif +/* + * Printing configuration + */ #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) #include #include @@ -118,12 +228,12 @@ extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */ static struct pci_dev *bmide_dev; -static char *cable_type[] = { +static char* cable_type[] = { "80 pins", "40 pins" }; -static char *recovery_time [] ={ +static char* recovery_time[] ={ "12 PCICLK", "1 PCICLK", "2 PCICLK", "3 PCICLK", "4 PCICLK", "5 PCICLCK", @@ -134,101 +244,179 @@ "15 PCICLK", "15 PCICLK" }; -static char * cycle_time [] = { - "2 CLK", "2 CLK", - "3 CLK", "4 CLK", - "5 CLK", "6 CLK", - "7 CLK", "8 CLK" -}; - -static char * active_time [] = { +static char* active_time[] = { "8 PCICLK", "1 PCICLCK", - "2 PCICLK", "2 PCICLK", + "2 PCICLK", "3 PCICLK", "4 PCICLK", "5 PCICLK", "6 PCICLK", "12 PCICLK" }; +static char* cycle_time[] = { + "Reserved", "2 CLK", + "3 CLK", "4 CLK", + "5 CLK", "6 CLK", + "7 CLK", "8 CLK", + "9 CLK", "10 CLK", + "11 CLK", "12 CLK", + "Reserved", "Reserved", + "Reserved", "Reserved" +}; + +/* Generic add master or slave info function */ +static char* get_drives_info (char *buffer, byte pos) +{ + byte reg00, reg01, reg10, reg11; /* timing registers */ + char* p = buffer; + +/* Postwrite/Prefetch */ + pci_read_config_byte(bmide_dev, 0x4b, ®00); + p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n", + pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled", + (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled"); + p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", + (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled", + (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled"); + + pci_read_config_byte(bmide_dev, 0x40+2*pos, ®00); + pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01); + pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10); + pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11); + +/* UDMA */ + if (dma_capability >= ATA_33) { + p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", + (reg01 & 0x80) ? "Enabled" : "Disabled", + (reg11 & 0x80) ? "Enabled" : "Disabled"); + + p += sprintf(p, " UDMA Cycle Time "); + switch(dma_capability) { + case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break; + case ATA_66: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break; + case ATA_100: p += sprintf(p, cycle_time[reg01 & 0x0F]); break; + case ATA_133: + default: p += sprintf(p, "133+ ?"); break; + } + p += sprintf(p, " \t UDMA Cycle Time "); + switch(dma_capability) { + case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break; + case ATA_66: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break; + case ATA_100: p += sprintf(p, cycle_time[reg11 & 0x0F]); break; + case ATA_133: + default: p += sprintf(p, "133+ ?"); break; + } + p += sprintf(p, "\n"); + } + +/* Data Active */ + p += sprintf(p, " Data Active Time "); + switch(dma_capability) { + case ATA_00: + case ATA_16: /* confirmed */ + case ATA_33: + case ATA_66: p += sprintf(p, active_time[reg01 & 0x07]); break; + case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; + case ATA_133: + default: p += sprintf(p, "133+ ?"); break; + } + p += sprintf(p, " \t Data Active Time "); + switch(dma_capability) { + case ATA_00: + case ATA_16: + case ATA_33: + case ATA_66: p += sprintf(p, active_time[reg11 & 0x07]); break; + case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; + case ATA_133: + default: p += sprintf(p, "133+ ?"); break; + } + p += sprintf(p, "\n"); + +/* Data Recovery */ + /* warning: may need (reg&0x07) for pre ATA66 chips */ + p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", + recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]); + + return p; +} + +static char* get_masters_info(char* buffer) +{ + return get_drives_info(buffer, 0); +} + +static char* get_slaves_info(char* buffer) +{ + return get_drives_info(buffer, 1); +} + +/* Main get_info, called on /proc/ide/sis reads */ static int sis_get_info (char *buffer, char **addr, off_t offset, int count) { - int rc; char *p = buffer; - byte reg,reg1; + byte reg; u16 reg2, reg3; + p += sprintf(p, "\nSiS 5513 "); + switch(dma_capability) { + case ATA_00: p += sprintf(p, "Unknown???"); break; + case ATA_16: p += sprintf(p, "DMA 16"); break; + case ATA_33: p += sprintf(p, "Ultra 33"); break; + case ATA_66: p += sprintf(p, "Ultra 66"); break; + case ATA_100: p += sprintf(p, "Ultra 100"); break; + case ATA_133: + default: p+= sprintf(p, "Ultra 133+"); break; + } + p += sprintf(p, " chipset\n"); p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - rc = pci_read_config_byte(bmide_dev, 0x4a, ®); - p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n", - (reg & 0x02) ? "On" : "Off", - (reg & 0x04) ? "On" : "Off"); - - rc = pci_read_config_byte(bmide_dev, 0x09, ®); + +/* Status */ + pci_read_config_byte(bmide_dev, 0x4a, ®); + p += sprintf(p, "Channel Status: "); + if (dma_capability < ATA_66) { + p += sprintf(p, "%s \t \t \t \t %s\n", + (reg & 0x04) ? "On" : "Off", + (reg & 0x02) ? "On" : "Off"); + } else { + p += sprintf(p, "%s \t \t \t \t %s \n", + (reg & 0x02) ? "On" : "Off", + (reg & 0x04) ? "On" : "Off"); + } + +/* Operation Mode */ + pci_read_config_byte(bmide_dev, 0x09, ®); p += sprintf(p, "Operation Mode: %s \t \t \t %s \n", (reg & 0x01) ? "Native" : "Compatible", (reg & 0x04) ? "Native" : "Compatible"); - - rc = pci_read_config_byte(bmide_dev, 0x48, ®); - p += sprintf(p, "Cable Type: %s \t \t \t %s\n", - (reg & 0x10) ? cable_type[1] : cable_type[0], - (reg & 0x20) ? cable_type[1] : cable_type[0]); - - rc = pci_read_config_word(bmide_dev, 0x4c, ®2); - rc = pci_read_config_word(bmide_dev, 0x4e, ®3); - p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", - reg2, reg3); - - rc = pci_read_config_byte(bmide_dev, 0x4b, ®); - p += sprintf(p, "Drive 0: Postwrite %s \t \t Postwrite %s\n", - (reg & 0x10) ? "Enabled" : "Disabled", - (reg & 0x40) ? "Enabled" : "Disabled"); - p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", - (reg & 0x01) ? "Enabled" : "Disabled", - (reg & 0x04) ? "Enabled" : "Disabled"); - - rc = pci_read_config_byte(bmide_dev, 0x41, ®); - rc = pci_read_config_byte(bmide_dev, 0x45, ®1); - p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", - (reg & 0x80) ? "Enabled" : "Disabled", - (reg1 & 0x80) ? "Enabled" : "Disabled"); - p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", - cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); - p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", - active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); - - rc = pci_read_config_byte(bmide_dev, 0x40, ®); - rc = pci_read_config_byte(bmide_dev, 0x44, ®1); - p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", - recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]); +/* 80-pin cable ? */ + if (dma_capability > ATA_33) { + pci_read_config_byte(bmide_dev, 0x48, ®); + p += sprintf(p, "Cable Type: %s \t \t \t %s\n", + (reg & 0x10) ? cable_type[1] : cable_type[0], + (reg & 0x20) ? cable_type[1] : cable_type[0]); + } - rc = pci_read_config_byte(bmide_dev, 0x4b, ®); - p += sprintf(p, "Drive 1: Postwrite %s \t \t Postwrite %s\n", - (reg & 0x20) ? "Enabled" : "Disabled", - (reg & 0x80) ? "Enabled" : "Disabled"); - p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", - (reg & 0x02) ? "Enabled" : "Disabled", - (reg & 0x08) ? "Enabled" : "Disabled"); +/* Prefetch Count */ + pci_read_config_word(bmide_dev, 0x4c, ®2); + pci_read_config_word(bmide_dev, 0x4e, ®3); + p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", + reg2, reg3); - rc = pci_read_config_byte(bmide_dev, 0x43, ®); - rc = pci_read_config_byte(bmide_dev, 0x47, ®1); - p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", - (reg & 0x80) ? "Enabled" : "Disabled", - (reg1 & 0x80) ? "Enabled" : "Disabled"); - p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", - cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); - p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", - active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); + p = get_masters_info(p); + p = get_slaves_info(p); - rc = pci_read_config_byte(bmide_dev, 0x42, ®); - rc = pci_read_config_byte(bmide_dev, 0x46, ®1); - p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", - recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]); return p-buffer; } #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ + byte sis_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); + +/* + * Configuration functions + */ +/* Enables per-drive prefetch and postwrite */ static void config_drive_art_rwp (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -237,14 +425,24 @@ byte reg4bh = 0; byte rw_prefetch = (0x11 << drive->dn); - pci_read_config_byte(dev, 0x4b, ®4bh); +#ifdef DEBUG + printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn); + sis5513_load_verify_registers(dev, "config_drive_art_rwp start"); +#endif + if (drive->media != ide_disk) return; - + pci_read_config_byte(dev, 0x4b, ®4bh); + if ((reg4bh & rw_prefetch) != rw_prefetch) pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); +#ifdef DEBUG + sis5513_load_verify_registers(dev, "config_drive_art_rwp end"); +#endif } + +/* Set per-drive active and recovery time */ static void config_art_rwp_pio (ide_drive_t *drive, byte pio) { ide_hwif_t *hwif = HWIF(drive); @@ -255,6 +453,10 @@ unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; unsigned short xfer_pio = drive->id->eide_pio_modes; +#ifdef DEBUG + sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); +#endif + config_drive_art_rwp(drive); pio = ide_get_best_pio_mode(drive, 255, pio, NULL); @@ -263,8 +465,8 @@ if (drive->id->eide_pio_iordy > 0) { for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + (xfer_pio > 0) && + (drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]); xfer_pio--); } else { xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : @@ -274,14 +476,10 @@ timing = (xfer_pio >= pio) ? xfer_pio : pio; -/* - * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4 - * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns) - * 0x41 2:0 bits 000 110 100 011 011 - * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns) - * 0x40 3:0 bits 0000 0111 0100 0011 0001 - * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) - */ +#ifdef DEBUG + printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n", + drive->dn, pio, timing); +#endif switch(drive->dn) { case 0: drive_pci = 0x40; break; @@ -291,31 +489,43 @@ default: return; } - pci_read_config_byte(dev, drive_pci, &test1); - pci_read_config_byte(dev, drive_pci|0x01, &test2); - - /* - * Do a blanket clear of active and recovery timings. - */ - - test1 &= ~0x07; - test2 &= ~0x0F; - - switch(timing) { - case 4: test1 |= 0x01; test2 |= 0x03; break; - case 3: test1 |= 0x03; test2 |= 0x03; break; - case 2: test1 |= 0x04; test2 |= 0x04; break; - case 1: test1 |= 0x07; test2 |= 0x06; break; - default: break; + /* register layout changed with ATA100 chips */ + if (dma_capability < ATA_100) { + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci+1, &test2); + + /* Clear active and recovery timings */ + test1 &= ~0x0F; + test2 &= ~0x07; + + switch(timing) { + case 4: test1 |= 0x01; test2 |= 0x03; break; + case 3: test1 |= 0x03; test2 |= 0x03; break; + case 2: test1 |= 0x04; test2 |= 0x04; break; + case 1: test1 |= 0x07; test2 |= 0x06; break; + default: break; + } + pci_write_config_byte(dev, drive_pci, test1); + pci_write_config_byte(dev, drive_pci+1, test2); + } else { + switch(timing) { /* active recovery + v v */ + case 4: test1 = 0x30|0x01; break; + case 3: test1 = 0x30|0x03; break; + case 2: test1 = 0x40|0x04; break; + case 1: test1 = 0x60|0x07; break; + default: break; + } + pci_write_config_byte(dev, drive_pci, test1); } - pci_write_config_byte(dev, drive_pci, test1); - pci_write_config_byte(dev, drive_pci|0x01, test2); +#ifdef DEBUG + sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); +#endif } static int config_chipset_for_pio (ide_drive_t *drive, byte pio) { - int err; byte speed; switch(pio) { @@ -328,8 +538,7 @@ config_art_rwp_pio(drive, pio); drive->current_speed = speed; - err = ide_config_drive_speed(drive, speed); - return err; + return ide_config_drive_speed(drive, speed); } static int sis5513_tune_chipset (ide_drive_t *drive, byte speed) @@ -337,82 +546,71 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, test1, test2; - byte unmask, four_two, mask = 0; - - if (host_dev) { - switch(host_dev->device) { - case PCI_DEVICE_ID_SI_530: - case PCI_DEVICE_ID_SI_540: - case PCI_DEVICE_ID_SI_620: - case PCI_DEVICE_ID_SI_630: - case PCI_DEVICE_ID_SI_635: - case PCI_DEVICE_ID_SI_640: - case PCI_DEVICE_ID_SI_645: - case PCI_DEVICE_ID_SI_650: - case PCI_DEVICE_ID_SI_730: - case PCI_DEVICE_ID_SI_735: - case PCI_DEVICE_ID_SI_740: - case PCI_DEVICE_ID_SI_745: - case PCI_DEVICE_ID_SI_750: - unmask = 0xF0; - four_two = 0x01; - break; - default: - unmask = 0xE0; - four_two = 0x00; - break; - } - } else { - unmask = 0xE0; - four_two = 0x00; - } + byte drive_pci, reg; +#ifdef DEBUG + sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); + printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n", + drive->dn, speed); +#endif switch(drive->dn) { - case 0: drive_pci = 0x40;break; - case 1: drive_pci = 0x42;break; - case 2: drive_pci = 0x44;break; - case 3: drive_pci = 0x46;break; + case 0: drive_pci = 0x40; break; + case 1: drive_pci = 0x42; break; + case 2: drive_pci = 0x44; break; + case 3: drive_pci = 0x46; break; default: return ide_dma_off; } - pci_read_config_byte(dev, drive_pci, &test1); - pci_read_config_byte(dev, drive_pci|0x01, &test2); +#ifdef BROKEN_LEVEL +#ifdef DEBUG + printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL); +#endif + if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL; +#endif - if ((speed <= XFER_MW_DMA_2) && (test2 & 0x80)) { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80); - pci_read_config_byte(dev, drive_pci|0x01, &test2); - } else { - pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_read_config_byte(dev, drive_pci+1, ®); + /* Disable UDMA bit for non UDMA modes on UDMA chips */ + if ((speed < XFER_UDMA_0) && (dma_capability > ATA_16)) { + reg &= 0x7F; + pci_write_config_byte(dev, drive_pci+1, reg); } + /* Config chip for mode */ switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA - case XFER_UDMA_5: mask = 0x80; break; - case XFER_UDMA_4: mask = 0x90; break; - case XFER_UDMA_3: mask = 0xA0; break; - case XFER_UDMA_2: mask = (four_two) ? 0xB0 : 0xA0; break; - case XFER_UDMA_1: mask = (four_two) ? 0xD0 : 0xC0; break; - case XFER_UDMA_0: mask = unmask; break; + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + /* clean reg cycle time bits */ + reg &= ~((0xFF >> (8 - cycle_time_range[dma_capability])) + << cycle_time_offset[dma_capability]); + /* set reg cycle time bits */ + reg |= cycle_time_value[dma_capability-ATA_00][speed-XFER_UDMA_0] + << cycle_time_offset[dma_capability]; + pci_write_config_byte(dev, drive_pci+1, reg); + break; 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: break; + case XFER_SW_DMA_0: + break; #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1)); case XFER_PIO_0: - default: return((int) config_chipset_for_pio(drive, 0)); + default: return((int) config_chipset_for_pio(drive, 0)); } - - if (speed > XFER_MW_DMA_2) - pci_write_config_byte(dev, drive_pci|0x01, test2|mask); - drive->current_speed = speed; +#ifdef DEBUG + sis5513_load_verify_registers(dev, "sis5513_tune_chipset end"); +#endif return ((int) ide_config_drive_speed(drive, speed)); } @@ -430,47 +628,27 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - byte four_two = 0, speed = 0; - int err; + byte speed = 0; byte unit = (drive->select.b.unit & 0x01); byte udma_66 = eighty_ninty_three(drive); - byte ultra_100 = 0; - if (host_dev) { - switch(host_dev->device) { - case PCI_DEVICE_ID_SI_635: - case PCI_DEVICE_ID_SI_640: - case PCI_DEVICE_ID_SI_645: - case PCI_DEVICE_ID_SI_650: - case PCI_DEVICE_ID_SI_730: - case PCI_DEVICE_ID_SI_735: - case PCI_DEVICE_ID_SI_740: - case PCI_DEVICE_ID_SI_745: - case PCI_DEVICE_ID_SI_750: - ultra_100 = 1; - case PCI_DEVICE_ID_SI_530: - case PCI_DEVICE_ID_SI_540: - case PCI_DEVICE_ID_SI_620: - case PCI_DEVICE_ID_SI_630: - four_two = 0x01; - break; - default: - four_two = 0x00; break; - } - } +#ifdef DEBUG + printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n", + drive->dn, ultra); +#endif - if ((id->dma_ultra & 0x0020) && (ultra) && (udma_66) && (four_two) && (ultra_100)) + if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (dma_capability >= ATA_100)) speed = XFER_UDMA_5; - else if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) + else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (dma_capability >= ATA_66)) speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) + else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (dma_capability >= ATA_66)) speed = XFER_UDMA_3; - else if ((id->dma_ultra & 0x0004) && (ultra)) + else if ((id->dma_ultra & 0x0004) && ultra && (dma_capability >= ATA_33)) speed = XFER_UDMA_2; - else if ((id->dma_ultra & 0x0002) && (ultra)) + else if ((id->dma_ultra & 0x0002) && ultra && (dma_capability >= ATA_33)) speed = XFER_UDMA_1; - else if ((id->dma_ultra & 0x0001) && (ultra)) + else if ((id->dma_ultra & 0x0001) && ultra && (dma_capability >= ATA_33)) speed = XFER_UDMA_0; else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; @@ -489,11 +667,7 @@ outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); - err = sis5513_tune_chipset(drive, speed); - -#if SIS5513_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* SIS5513_DEBUG_DRIVE_INFO */ + sis5513_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : @@ -550,9 +724,7 @@ return HWIF(drive)->dmaproc(dma_func, drive); } -/* - * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - */ +/* initiates/aborts (U)DMA read/write operations on a drive. */ int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { switch (func) { @@ -567,15 +739,18 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ +/* Chip detection and general config */ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) { struct pci_dev *host; int i = 0; - byte latency = 0; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); +#ifdef DEBUG + sis5513_print_registers(dev, "pci_init_sis5513 start"); +#endif - for (i = 0; i < ARRAY_SIZE (SiSHostChipInfo) && !host_dev; i++) { + /* Find the chip */ + for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) { host = pci_find_device (PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); @@ -583,30 +758,66 @@ continue; host_dev = host; + dma_capability = SiSHostChipInfo[i].dma_capability; printk(SiSHostChipInfo[i].name); printk("\n"); - if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) { - if (latency != 0x10) - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + + if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) { + byte latency = (dma_capability == ATA_100)? 0x80 : 0x10; /* Lacking specs */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); } } + /* Make general config ops here + 1/ tell IDE channels to operate in Compabitility mode only + 2/ tell old chips to allow per drive IDE timings */ if (host_dev) { - byte reg52h = 0; - - pci_read_config_byte(dev, 0x52, ®52h); - if (!(reg52h & 0x04)) { - /* set IDE controller to operate in Compabitility mode only */ - pci_write_config_byte(dev, 0x52, reg52h|0x04); + byte reg; + switch(dma_capability) { + case ATA_133: + case ATA_100: + /* Set compatibility bit */ + pci_read_config_byte(dev, 0x49, ®); + if (!(reg & 0x01)) { + pci_write_config_byte(dev, 0x49, reg|0x01); + } + break; + case ATA_66: + /* On ATA_66 chips the bit was elsewhere */ + pci_read_config_byte(dev, 0x52, ®); + if (!(reg & 0x04)) { + pci_write_config_byte(dev, 0x52, reg|0x04); + } + break; + case ATA_33: + /* On ATA_33 we didn't have a single bit to set */ + pci_read_config_byte(dev, 0x09, ®); + if ((reg & 0x0f) != 0x00) { + pci_write_config_byte(dev, 0x09, reg&0xf0); + } + case ATA_16: + /* force per drive recovery and active timings + needed on ATA_33 and below chips */ + pci_read_config_byte(dev, 0x52, ®); + if (!(reg & 0x08)) { + pci_write_config_byte(dev, 0x52, reg|0x08); + } + break; + case ATA_00: + default: break; } + #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) if (!sis_proc) { sis_proc = 1; bmide_dev = dev; sis_display_info = &sis_get_info; } -#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ +#endif } +#ifdef DEBUG + sis5513_load_verify_registers(dev, "pci_init_sis5513 end"); +#endif return 0; } @@ -616,27 +827,10 @@ byte mask = hwif->channel ? 0x20 : 0x10; pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); - if (host_dev) { - switch(host_dev->device) { - case PCI_DEVICE_ID_SI_530: - case PCI_DEVICE_ID_SI_540: - case PCI_DEVICE_ID_SI_620: - case PCI_DEVICE_ID_SI_630: - case PCI_DEVICE_ID_SI_635: - case PCI_DEVICE_ID_SI_640: - case PCI_DEVICE_ID_SI_645: - case PCI_DEVICE_ID_SI_650: - case PCI_DEVICE_ID_SI_730: - case PCI_DEVICE_ID_SI_735: - case PCI_DEVICE_ID_SI_740: - case PCI_DEVICE_ID_SI_745: - case PCI_DEVICE_ID_SI_750: - ata66 = (reg48h & mask) ? 0 : 1; - default: - break; - } + if (dma_capability >= ATA_66) { + ata66 = (reg48h & mask) ? 0 : 1; } - return (ata66); + return ata66; } void __init ide_init_sis5513 (ide_hwif_t *hwif) @@ -651,33 +845,16 @@ return; if (host_dev) { - switch(host_dev->device) { #ifdef CONFIG_BLK_DEV_IDEDMA - case PCI_DEVICE_ID_SI_530: - case PCI_DEVICE_ID_SI_540: - case PCI_DEVICE_ID_SI_620: - case PCI_DEVICE_ID_SI_630: - case PCI_DEVICE_ID_SI_635: - case PCI_DEVICE_ID_SI_640: - case PCI_DEVICE_ID_SI_645: - case PCI_DEVICE_ID_SI_650: - case PCI_DEVICE_ID_SI_730: - case PCI_DEVICE_ID_SI_735: - case PCI_DEVICE_ID_SI_740: - case PCI_DEVICE_ID_SI_745: - case PCI_DEVICE_ID_SI_750: - case PCI_DEVICE_ID_SI_5600: - case PCI_DEVICE_ID_SI_5597: - case PCI_DEVICE_ID_SI_5591: - if (!noautodma) - hwif->autodma = 1; - hwif->dmaproc = &sis5513_dmaproc; - break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ - default: - hwif->autodma = 0; - break; + if (dma_capability > ATA_16) { + hwif->autodma = noautodma ? 0 : 1; + hwif->dmaproc = &sis5513_dmaproc; + } else { +#endif + hwif->autodma = 0; +#ifdef CONFIG_BLK_DEV_IDEDMA } +#endif } return; } diff -urN linux-2.4.18/drivers/ide/slc90e66.c linux-2.4.19-pre5/drivers/ide/slc90e66.c --- linux-2.4.18/drivers/ide/slc90e66.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/slc90e66.c Sat Mar 30 22:55:34 2002 @@ -86,8 +86,13 @@ * at that point bibma+0x2 et bibma+0xa are byte registers * to investigate: */ +#ifdef __mips__ /* only for mips? */ + c0 = inb_p(bibma + 0x02); + c1 = inb_p(bibma + 0x0a); +#else c0 = inb_p((unsigned short)bibma + 0x02); c1 = inb_p((unsigned short)bibma + 0x0a); +#endif p += sprintf(p, " SLC90E66 Chipset.\n"); p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); @@ -253,7 +258,9 @@ case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; +#if 0 /* allow PIO modes */ default: return -1; +#endif } if (speed >= XFER_UDMA_0) { @@ -291,6 +298,13 @@ byte speed = 0; byte udma_66 = eighty_ninty_three(drive); +#if 1 /* allow PIO modes */ + if (!HWIF(drive)->autodma) { + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + (void) slc90e66_tune_chipset(drive, speed); + return ((int) ide_dma_off_quietly); + } +#endif if ((id->dma_ultra & 0x0010) && (ultra)) { speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2; } else if ((id->dma_ultra & 0x0008) && (ultra)) { diff -urN linux-2.4.18/drivers/ide/via82cxxx.c linux-2.4.19-pre5/drivers/ide/via82cxxx.c --- linux-2.4.18/drivers/ide/via82cxxx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ide/via82cxxx.c Sat Mar 30 22:55:39 2002 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 3.29 2001/09/10 10:06:00 vojtech Exp $ + * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * @@ -7,23 +7,21 @@ * Michel Aubry * Jeff Garzik * Andre Hedrick - * - * Sponsored by SuSE */ /* * VIA IDE driver for Linux. Supports * * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, - * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233 + * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a * * southbridges, which can be found in * * VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro, * ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z, * PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T, - * PX266, PM266, KX133, KT133, KT133A, KLE133, KT266, KX266, KM133, KM133A, - * KL133, KN133, KM266 + * PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133, + * KM133A, KL133, KN133, KM266 * PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo, * BXTel, BXpert * AMD 640, 640 AGP, 750 IronGate, 760, 760MP @@ -32,9 +30,9 @@ * * chipsets. Supports * - * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5 + * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6 * - * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are + * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore * the BIOS data and assume the cable is present, use 'ide0=ata66' or * 'ide1=ata66' on the kernel command line. @@ -56,8 +54,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -87,10 +85,12 @@ #define VIA_UDMA_33 0x001 #define VIA_UDMA_66 0x002 #define VIA_UDMA_100 0x003 +#define VIA_UDMA_133 0x004 #define VIA_BAD_PREQ 0x010 /* Crashes if PREQ# till DDACK# set */ #define VIA_BAD_CLK66 0x020 /* 66 MHz clock doesn't work correctly */ #define VIA_SET_FIFO 0x040 /* Needs to have FIFO split set */ #define VIA_NO_UNMASK 0x080 /* Doesn't work with IRQ unmasking on */ +#define VIA_BAD_ID 0x100 /* Has wrong vendor ID (0x1107) */ /* * VIA SouthBridge chips. @@ -104,10 +104,11 @@ unsigned short flags; } via_isa_bridges[] = { #ifdef FUTURE_BRIDGES - { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8233c", PCI_DEVICE_ID_VIA_8233C, 0x00, 0x2f, VIA_UDMA_100 }, + { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 }, + { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 }, #endif + { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 }, + { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 }, { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, @@ -121,6 +122,7 @@ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, + { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, { NULL } }; @@ -128,7 +130,7 @@ static unsigned char via_enabled; static unsigned int via_80w; static unsigned int via_clock; -static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" }; +static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" }; /* * VIA /proc entry. @@ -151,7 +153,7 @@ static int via_get_info(char *buffer, char **addr, off_t offset, int count) { - short speed[4], cycle[4], setup[4], active[4], recover[4], den[4], + int speed[4], cycle[4], setup[4], active[4], recover[4], den[4], uen[4], udma[4], umul[4], active8b[4], recover8b[4]; struct pci_dev *dev = bmide_dev; unsigned int v, u, i; @@ -161,7 +163,7 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 3.29"); + via_print("Driver Version: 3.34"); via_print("South Bridge: VIA %s", via_config->name); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); @@ -170,7 +172,7 @@ via_print("Highest DMA rate: %s", via_dma[via_config->flags & VIA_UDMA]); via_print("BM-DMA base: %#x", via_base); - via_print("PCI clock: %dMHz", via_clock); + via_print("PCI clock: %d.%dMHz", via_clock / 1000, via_clock / 100 % 10); pci_read_config_byte(dev, VIA_MISC_1, &t); via_print("Master Read Cycle IRDY: %dws", (t & 64) >> 6); @@ -218,40 +220,45 @@ uen[i] = ((u >> ((3 - i) << 3)) & 0x20); den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)); - speed[i] = 20 * via_clock / (active[i] + recover[i]); - cycle[i] = 1000 / via_clock * (active[i] + recover[i]); + speed[i] = 2 * via_clock / (active[i] + recover[i]); + cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock; if (!uen[i] || !den[i]) continue; switch (via_config->flags & VIA_UDMA) { - - case VIA_UDMA_100: - speed[i] = 60 * via_clock / udma[i]; - cycle[i] = 333 / via_clock * udma[i]; + + case VIA_UDMA_33: + speed[i] = 2 * via_clock / udma[i]; + cycle[i] = 1000000 * udma[i] / via_clock; break; case VIA_UDMA_66: - speed[i] = 40 * via_clock / (udma[i] * umul[i]); - cycle[i] = 500 / via_clock * (udma[i] * umul[i]); + speed[i] = 4 * via_clock / (udma[i] * umul[i]); + cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock; break; - case VIA_UDMA_33: - speed[i] = 20 * via_clock / udma[i]; - cycle[i] = 1000 / via_clock * udma[i]; + case VIA_UDMA_100: + speed[i] = 6 * via_clock / udma[i]; + cycle[i] = 333333 * udma[i] / via_clock; + break; + + case VIA_UDMA_133: + speed[i] = 8 * via_clock / udma[i]; + cycle[i] = 250000 * udma[i] / via_clock; break; } } via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO"); - via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]); - via_print_drive("Cmd Active: ", "%8dns", (1000 / via_clock) * active8b[i]); - via_print_drive("Cmd Recovery: ", "%8dns", (1000 / via_clock) * recover8b[i]); - via_print_drive("Data Active: ", "%8dns", (1000 / via_clock) * active[i]); - via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]); + via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock); + via_print_drive("Cmd Active: ", "%8dns", 1000000 * active8b[i] / via_clock); + via_print_drive("Cmd Recovery: ", "%8dns", 1000000 * recover8b[i] / via_clock); + via_print_drive("Data Active: ", "%8dns", 1000000 * active[i] / via_clock); + via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock); via_print_drive("Cycle Time: ", "%8dns", cycle[i]); - via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10); + via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10); return p - buffer; /* hoping it is less than 4K... */ } @@ -280,6 +287,7 @@ case VIA_UDMA_33: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; case VIA_UDMA_66: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break; case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; + case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; default: return; } @@ -296,20 +304,21 @@ { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct ide_timing t, p; - int T, UT; + unsigned int T, UT; if (speed != XFER_PIO_SLOW && speed != drive->current_speed) if (ide_config_drive_speed(drive, speed)) printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n", drive->dn >> 1, drive->dn & 1); - T = 1000 / via_clock; + T = 1000000000 / via_clock; switch (via_config->flags & VIA_UDMA) { case VIA_UDMA_33: UT = T; break; case VIA_UDMA_66: UT = T/2; break; case VIA_UDMA_100: UT = T/3; break; - default: UT = T; break; + case VIA_UDMA_133: UT = T/4; break; + default: UT = T; } ide_timing_compute(drive, speed, &t, T, UT); @@ -365,7 +374,8 @@ XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) | (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) | - (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0)); + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) | + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0)); via_set_drive(drive, speed); @@ -395,14 +405,16 @@ */ for (via_config = via_isa_bridges; via_config->id; via_config++) - if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) { + if ((isa = pci_find_device(PCI_VENDOR_ID_VIA + + !!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); if (t >= via_config->rev_min && t <= via_config->rev_max) break; } if (!via_config->id) { - printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik \n"); + printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik \n"); return -ENODEV; } @@ -412,22 +424,28 @@ switch (via_config->flags & VIA_UDMA) { - case VIA_UDMA_100: - - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3))) - via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */ - break; - case VIA_UDMA_66: - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); /* Enable Clk66 */ pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); for (i = 24; i >= 0; i -= 8) if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2)) via_80w |= (1 << (1 - (i >> 4))); /* 2x PCI clock and UDMA w/ < 3T/cycle */ break; + + case VIA_UDMA_100: + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4))) + via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */ + break; + + case VIA_UDMA_133: + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8))) + via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */ + break; + } if (via_config->flags & VIA_BAD_CLK66) { /* Disable Clk66 */ @@ -466,11 +484,18 @@ * Determine system bus clock. */ - via_clock = system_bus_clock(); - if (via_clock < 20 || via_clock > 50) { + via_clock = system_bus_clock() * 1000; + + switch (via_clock) { + case 33000: via_clock = 33333; break; + case 37000: via_clock = 37500; break; + case 41000: via_clock = 41666; break; + } + + if (via_clock < 20000 || via_clock > 50000) { printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock); - printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n"); - via_clock = 33; + printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n"); + via_clock = 33333; } /* diff -urN linux-2.4.18/drivers/ieee1394/Config.in linux-2.4.19-pre5/drivers/ieee1394/Config.in --- linux-2.4.18/drivers/ieee1394/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/Config.in Sat Mar 30 22:55:39 2002 @@ -19,7 +19,14 @@ comment "Protocol Drivers" dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 + dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394 + dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 + dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394 + + if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then + dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP + fi bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG fi diff -urN linux-2.4.18/drivers/ieee1394/Makefile linux-2.4.19-pre5/drivers/ieee1394/Makefile --- linux-2.4.18/drivers/ieee1394/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/Makefile Sat Mar 30 22:55:39 2002 @@ -4,7 +4,7 @@ O_TARGET := ieee1394drv.o -export-objs := ieee1394_core.o ohci1394.o +export-objs := ieee1394_core.o ohci1394.o cmp.o list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ @@ -16,6 +16,10 @@ obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o +obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o +obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o +obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o +obj-$(CONFIG_IEEE1394_CMP) += cmp.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/ieee1394/amdtp.c linux-2.4.19-pre5/drivers/ieee1394/amdtp.c --- linux-2.4.18/drivers/ieee1394/amdtp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/amdtp.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,1141 @@ +/* -*- c-basic-offset: 8 -*- + * + * amdtp.c - Audio and Music Data Transmission Protocol Driver + * Copyright (C) 2001 Kristian Høgsberg + * + * 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. + */ + +/* OVERVIEW + * -------- + * + * The AMDTP driver is designed to expose the IEEE1394 bus as a + * regular OSS soundcard, i.e. you can link /dev/dsp to /dev/amdtp and + * then your favourite MP3 player, game or whatever sound program will + * output to an IEEE1394 isochronous channel. The signal destination + * could be a set of IEEE1394 loudspeakers (if and when such things + * become available) or an amplifier with IEEE1394 input (like the + * Sony STR-LSA1). The driver only handles the actual streaming, some + * connection management is also required for this to actually work. + * That is outside the scope of this driver, and furthermore it is not + * really standardized yet. + * + * The Audio and Music Data Tranmission Protocol is avaiable at + * + * http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf + * + * + * TODO + * ---- + * + * - We should be able to change input sample format between LE/BE, as + * we already shift the bytes around when we construct the iso + * packets. + * + * - Fix DMA stop after bus reset! + * + * - Implement poll. + * + * - Clean up iso context handling in ohci1394. + * + * + * MAYBE TODO + * ---------- + * + * - Receive data for local playback or recording. Playback requires + * soft syncing with the sound card. + * + * - Signal processing, i.e. receive packets, do some processing, and + * transmit them again using the same packet structure and timestamps + * offset by processing time. + * + * - Maybe make an ALSA interface, that is, create a file_ops + * implementation that recognizes ALSA ioctls and uses defaults for + * things that can't be controlled through ALSA (iso channel). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394.h" +#include "ieee1394_core.h" +#include "ohci1394.h" + +#include "amdtp.h" +#include "cmp.h" + +#define FMT_AMDTP 0x10 +#define FDF_AM824 0x00 +#define FDF_SFC_32KHZ 0x00 /* 32kHz */ +#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */ +#define FDF_SFC_48KHZ 0x02 /* 44.1kHz */ + +struct descriptor_block { + struct output_more_immediate { + u32 control; + u32 pad0; + u32 skip; + u32 pad1; + u32 header[4]; + } header_desc; + + struct output_last { + u32 control; + u32 data_address; + u32 branch; + u32 status; + } payload_desc; +}; + +struct packet { + struct descriptor_block *db; + dma_addr_t db_bus; + quadlet_t *payload; + dma_addr_t payload_bus; +}; + +struct fraction { + int integer; + int numerator; + int denominator; + int counter; +}; + +#define PACKET_LIST_SIZE 256 +#define MAX_PACKET_LISTS 4 + +struct packet_list { + struct list_head link; + int last_cycle_count; + struct packet packets[PACKET_LIST_SIZE]; +}; + +#define BUFFER_SIZE 128 + +/* This implements a circular buffer for incoming samples. */ + +struct buffer { + int head, tail, length, size; + unsigned char data[0]; +}; + +struct stream { + int iso_channel; + int format; + int rate; + int dimension; + int fdf; + struct cmp_pcr *opcr; + + /* Input samples are copied here. */ + struct buffer *input; + + /* ISO Packer state */ + unsigned char dbc; + struct packet_list *current_packet_list; + int current_packet; + struct fraction packet_size_fraction; + + /* We use these to generate control bits when we are packing + * iec958 data. + */ + int iec958_frame_count; + int iec958_rate_code; + + /* The cycle_count and cycle_offset fields are used for the + * synchronization timestamps (syt) in the cip header. They + * are incremented by at least a cycle every time we put a + * time stamp in a packet. As we dont time stamp all + * packages, cycle_count isn't updated in every cycle, and + * sometimes it's incremented by 2. Thus, we have + * cycle_count2, which is simply incremented by one with each + * packet, so we can compare it to the transmission time + * written back in the dma programs. + */ + atomic_t cycle_count, cycle_count2; + int cycle_offset; + struct fraction syt_fraction; + int syt_interval; + int stale_count; + + /* Theses fields control the sample output to the DMA engine. + * The dma_packet_lists list holds packet lists currently + * queued for dma; the head of the list is currently being + * processed. The last program in a packet list generates an + * interrupt, which removes the head from dma_packet_lists and + * puts it back on the free list. + */ + struct list_head dma_packet_lists; + struct list_head free_packet_lists; + wait_queue_head_t packet_list_wait; + spinlock_t packet_list_lock; + int iso_context; + struct pci_pool *descriptor_pool, *packet_pool; + + /* Streams at a host controller are chained through this field. */ + struct list_head link; + struct amdtp_host *host; +}; + +struct amdtp_host { + struct hpsb_host *host; + struct ti_ohci *ohci; + struct list_head stream_list; + spinlock_t stream_list_lock; + struct list_head link; +}; + +static struct hpsb_highlevel *amdtp_highlevel; +static LIST_HEAD(host_list); +static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED; + +/* FIXME: This doesn't belong here... */ + +#define OHCI1394_CONTEXT_CYCLE_MATCH 0x80000000 +#define OHCI1394_CONTEXT_RUN 0x00008000 +#define OHCI1394_CONTEXT_WAKE 0x00001000 +#define OHCI1394_CONTEXT_DEAD 0x00000800 +#define OHCI1394_CONTEXT_ACTIVE 0x00000400 + +static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci) +{ + int i; + + for (i = 0; i < ohci->nb_iso_xmit_ctx; i++) + if (!test_and_set_bit(i, &ohci->it_ctx_usage)) + return i; + + return -EBUSY; +} + +static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx) +{ + clear_bit(ctx, &ohci->it_ctx_usage); +} + + +void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx, + dma_addr_t first_cmd, int z, int cycle_match) +{ + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx); + reg_write(ohci, OHCI1394_IsoXmitCommandPtr + ctx * 16, first_cmd | z); + reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, ~0); + wmb(); + reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16, + OHCI1394_CONTEXT_CYCLE_MATCH | (cycle_match << 16) | + OHCI1394_CONTEXT_RUN); +} + +void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx) +{ + reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16, + OHCI1394_CONTEXT_WAKE); +} + +void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx) +{ + u32 control; + int wait; + + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << ctx); + reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, + OHCI1394_CONTEXT_RUN); + wmb(); + + for (wait = 0; wait < 5; wait++) { + control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); + if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) + break; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } +} + +/* Note: we can test if free_packet_lists is empty without aquiring + * the packet_list_lock. The interrupt handler only adds to the free + * list, there is no race condition between testing the list non-empty + * and acquiring the lock. + */ + +static struct packet_list *stream_get_free_packet_list(struct stream *s) +{ + struct packet_list *pl; + unsigned long flags; + + if (list_empty(&s->free_packet_lists)) + return NULL; + + spin_lock_irqsave(&s->packet_list_lock, flags); + pl = list_entry(s->free_packet_lists.next, struct packet_list, link); + list_del(&pl->link); + spin_unlock_irqrestore(&s->packet_list_lock, flags); + + return pl; +} + +static void stream_put_dma_packet_list(struct stream *s, + struct packet_list *pl) +{ + unsigned long flags; + struct packet_list *prev; + + /* Remember the cycle_count used for timestamping the last packet. */ + pl->last_cycle_count = atomic_read(&s->cycle_count2) - 1; + pl->packets[PACKET_LIST_SIZE - 1].db->payload_desc.branch = 0; + + spin_lock_irqsave(&s->packet_list_lock, flags); + list_add_tail(&pl->link, &s->dma_packet_lists); + spin_unlock_irqrestore(&s->packet_list_lock, flags); + + prev = list_entry(pl->link.prev, struct packet_list, link); + if (pl->link.prev != &s->dma_packet_lists) { + struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1]; + last->db->payload_desc.branch = pl->packets[0].db_bus | 3; + ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); + } + else { + u32 syt, cycle_count; + + cycle_count = reg_read(s->host->host->hostdata, + OHCI1394_IsochronousCycleTimer) >> 12; + syt = (pl->packets[0].payload[1] >> 12) & 0x0f; + cycle_count = (cycle_count & ~0x0f) + 32 + syt; + if ((cycle_count & 0x1fff) >= 8000) + cycle_count = cycle_count - 8000 + 0x2000; + + ohci1394_start_it_ctx(s->host->ohci, s->iso_context, + pl->packets[0].db_bus, 3, + cycle_count & 0x7fff); + } +} + +static void stream_shift_packet_lists(struct stream *s) +{ + struct packet_list *pl; + struct packet *last; + int diff; + + if (list_empty(&s->dma_packet_lists)) { + HPSB_ERR("empty dma_packet_lists in %s", __FUNCTION__); + return; + } + + /* Now that we know the list is non-empty, we can get the head + * of the list without locking, because the process context + * only adds to the tail. + */ + pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); + last = &pl->packets[PACKET_LIST_SIZE - 1]; + + /* This is weird... if we stop dma processing in the middle of + * a packet list, the dma context immediately generates an + * interrupt if we enable it again later. This only happens + * when amdtp_release is interrupted while waiting for dma to + * complete, though. Anyway, we detect this by seeing that + * the status of the dma descriptor that we expected an + * interrupt from is still 0. + */ + if (last->db->payload_desc.status == 0) { + HPSB_INFO("weird interrupt..."); + return; + } + + /* If the last descriptor block does not specify a branch + * address, we have a sample underflow. + */ + if (last->db->payload_desc.branch == 0) + HPSB_INFO("FIXME: sample underflow..."); + + /* Here we check when (which cycle) the last packet was sent + * and compare it to what the iso packer was using at the + * time. If there is a mismatch, we adjust the cycle count in + * the iso packer. However, there are still up to + * MAX_PACKET_LISTS packet lists queued with bad time stamps, + * so we disable time stamp monitoring for the next + * MAX_PACKET_LISTS packet lists. + */ + diff = (last->db->payload_desc.status - pl->last_cycle_count) & 0xf; + if (diff > 0 && s->stale_count == 0) { + atomic_add(diff, &s->cycle_count); + atomic_add(diff, &s->cycle_count2); + s->stale_count = MAX_PACKET_LISTS; + } + + if (s->stale_count > 0) + s->stale_count--; + + /* Finally, we move the packet list that was just processed + * back to the free list, and notify any waiters. + */ + spin_lock(&s->packet_list_lock); + list_del(&pl->link); + list_add_tail(&pl->link, &s->free_packet_lists); + spin_unlock(&s->packet_list_lock); + + wake_up_interruptible(&s->packet_list_wait); +} + +static struct packet *stream_current_packet(struct stream *s) +{ + if (s->current_packet_list == NULL && + (s->current_packet_list = stream_get_free_packet_list(s)) == NULL) + return NULL; + + return &s->current_packet_list->packets[s->current_packet]; +} + +static void stream_queue_packet(struct stream *s) +{ + s->current_packet++; + if (s->current_packet == PACKET_LIST_SIZE) { + stream_put_dma_packet_list(s, s->current_packet_list); + s->current_packet_list = NULL; + s->current_packet = 0; + } +} + +/* Integer fractional math. When we transmit a 44k1Hz signal we must + * send 5 41/80 samples per isochronous cycle, as these occur 8000 + * times a second. Of course, we must send an integral number of + * samples in a packet, so we use the integer math to alternate + * between sending 5 and 6 samples per packet. + */ + +static void fraction_init(struct fraction *f, int numerator, int denominator) +{ + f->integer = numerator / denominator; + f->numerator = numerator % denominator; + f->denominator = denominator; + f->counter = 0; +} + +static int fraction_next_size(struct fraction *f) +{ + return f->integer + ((f->counter + f->numerator) / f->denominator); +} + +static void fraction_inc(struct fraction *f) +{ + f->counter = (f->counter + f->numerator) % f->denominator; +} + +static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, + quadlet_t isoXmitIntEvent, void *data) +{ + struct amdtp_host *host = data; + struct list_head *lh; + struct stream *s = NULL; + + spin_lock(&host->stream_list_lock); + list_for_each(lh, &host->stream_list) { + s = list_entry(lh, struct stream, link); + if (isoXmitIntEvent & (1 << s->iso_context)) + break; + } + spin_unlock(&host->stream_list_lock); + + if (s != NULL) + stream_shift_packet_lists(s); +} + +void packet_initialize(struct packet *p, struct packet *next) +{ + /* Here we initialize the dma descriptor block for + * transferring one iso packet. We use two descriptors per + * packet: an OUTPUT_MORE_IMMMEDIATE descriptor for the + * IEEE1394 iso packet header and an OUTPUT_LAST descriptor + * for the payload. + */ + + p->db->header_desc.control = + DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8; + p->db->header_desc.skip = 0; + + if (next) { + p->db->payload_desc.control = + DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + p->db->payload_desc.branch = next->db_bus | 3; + } + else { + p->db->payload_desc.control = + DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH | + DMA_CTL_UPDATE | DMA_CTL_IRQ; + p->db->payload_desc.branch = 0; + } + p->db->payload_desc.data_address = p->payload_bus; + p->db->payload_desc.status = 0; +} + +struct packet_list *packet_list_alloc(struct stream *s) +{ + int i; + struct packet_list *pl; + struct packet *next; + + pl = kmalloc(sizeof *pl, SLAB_KERNEL); + if (pl == NULL) + return NULL; + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + struct packet *p = &pl->packets[i]; + p->db = pci_pool_alloc(s->descriptor_pool, SLAB_KERNEL, + &p->db_bus); + p->payload = pci_pool_alloc(s->packet_pool, SLAB_KERNEL, + &p->payload_bus); + } + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + if (i < PACKET_LIST_SIZE - 1) + next = &pl->packets[i + 1]; + else + next = NULL; + packet_initialize(&pl->packets[i], next); + } + + return pl; +} + +void packet_list_free(struct packet_list *pl, struct stream *s) +{ + int i; + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + struct packet *p = &pl->packets[i]; + pci_pool_free(s->descriptor_pool, p->db, p->db_bus); + pci_pool_free(s->packet_pool, p->payload, p->payload_bus); + } + kfree(pl); +} + +static struct buffer *buffer_alloc(int size) +{ + struct buffer *b; + + b = kmalloc(sizeof *b + size, SLAB_KERNEL); + b->head = 0; + b->tail = 0; + b->length = 0; + b->size = size; + + return b; +} + +static unsigned char *buffer_get_bytes(struct buffer *buffer, int size) +{ + unsigned char *p; + + if (buffer->head + size > buffer->size) + BUG(); + + p = &buffer->data[buffer->head]; + buffer->head += size; + if (buffer->head == buffer->size) + buffer->head = 0; + buffer->length -= size; + + return p; +} + +static unsigned char *buffer_put_bytes(struct buffer *buffer, + int max, int *actual) +{ + int length; + unsigned char *p; + + p = &buffer->data[buffer->tail]; + length = min(buffer->size - buffer->length, max); + if (buffer->tail + length < buffer->size) { + *actual = length; + buffer->tail += length; + } + else { + *actual = buffer->size - buffer->tail; + buffer->tail = 0; + } + + buffer->length += *actual; + return p; +} + +static u32 get_iec958_header_bits(struct stream *s, int sub_frame, u32 sample) +{ + int csi, parity, shift; + int block_start; + u32 bits; + + switch (s->iec958_frame_count) { + case 1: + csi = s->format == AMDTP_FORMAT_IEC958_AC3; + break; + case 2: + case 9: + csi = 1; + break; + case 24 ... 27: + csi = (s->iec958_rate_code >> (27 - s->iec958_frame_count)) & 0x01; + break; + default: + csi = 0; + break; + } + + block_start = (s->iec958_frame_count == 0 && sub_frame == 0); + + /* The parity bit is the xor of the sample bits and the + * channel status info bit. */ + for (shift = 16, parity = sample ^ csi; shift > 0; shift >>= 1) + parity ^= (parity >> shift); + + bits = (block_start << 5) | /* Block start bit */ + ((sub_frame == 0) << 4) | /* Subframe bit */ + ((parity & 1) << 3) | /* Parity bit */ + (csi << 2); /* Channel status info bit */ + + return bits; +} + +static u32 get_header_bits(struct stream *s, int sub_frame, u32 sample) +{ + switch (s->format) { + case AMDTP_FORMAT_IEC958_PCM: + case AMDTP_FORMAT_IEC958_AC3: + return get_iec958_header_bits(s, sub_frame, sample); + + case AMDTP_FORMAT_RAW: + return 0x40000000; + + default: + return 0; + } +} + + +static void fill_packet(struct stream *s, struct packet *packet, int nevents) +{ + int size, node_id, i, j; + quadlet_t *event; + unsigned char *p; + u32 control, sample, bits; + int syt_index, syt, next; + + size = (nevents * s->dimension + 2) * sizeof(quadlet_t); + node_id = s->host->host->node_id & 0x3f; + + /* Update DMA descriptors */ + packet->db->payload_desc.status = 0; + control = packet->db->payload_desc.control & 0xffff0000; + packet->db->payload_desc.control = control | size; + + /* Fill IEEE1394 headers */ + packet->db->header_desc.header[0] = + (SPEED_100 << 16) | (0x01 << 14) | + (s->iso_channel << 8) | (TCODE_ISO_DATA << 4); + packet->db->header_desc.header[1] = size << 16; + + /* Fill cip header */ + syt_index = s->dbc & (s->syt_interval - 1); + if (syt_index == 0 || syt_index + nevents > s->syt_interval) { + syt = ((atomic_read(&s->cycle_count) << 12) | + s->cycle_offset) & 0xffff; + next = fraction_next_size(&s->syt_fraction) + s->cycle_offset; + /* This next addition should be modulo 8000 (0x1f40), + * but we only use the lower 4 bits of cycle_count, so + * we dont need the modulo. */ + atomic_add(next / 3072, &s->cycle_count); + s->cycle_offset = next % 3072; + fraction_inc(&s->syt_fraction); + } + else { + syt = 0xffff; + next = 0; + } + atomic_inc(&s->cycle_count2); + + packet->payload[0] = cpu_to_be32((node_id << 24) | (s->dimension << 16) | s->dbc); + packet->payload[1] = cpu_to_be32((1 << 31) | (FMT_AMDTP << 24) | (s->fdf << 16) | syt); + + /* Fill payload */ + for (i = 0, event = &packet->payload[2]; i < nevents; i++) { + + for (j = 0; j < s->dimension; j++) { + p = buffer_get_bytes(s->input, 2); + sample = (p[1] << 16) | (p[0] << 8); + bits = get_header_bits(s, j, sample); + event[j] = cpu_to_be32((bits << 24) | sample); + } + + event += s->dimension; + if (++s->iec958_frame_count == 192) + s->iec958_frame_count = 0; + } + + s->dbc += nevents; +} + +static void stream_flush(struct stream *s) +{ + struct packet *p; + int nevents; + + while (nevents = fraction_next_size(&s->packet_size_fraction), + p = stream_current_packet(s), + nevents * s->dimension * 2 <= s->input->length && p != NULL) { + fill_packet(s, p, nevents); + fraction_inc(&s->packet_size_fraction); + stream_queue_packet(s); + } +} + +static int stream_alloc_packet_lists(struct stream *s) +{ + int max_nevents, max_packet_size, i; + + max_nevents = s->packet_size_fraction.integer; + if (s->packet_size_fraction.numerator > 0) + max_nevents++; + + max_packet_size = max_nevents * s->dimension * 4 + 8; + s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev, + max_packet_size, 0, 0, SLAB_KERNEL); + if (s->packet_pool == NULL) + return -1; + + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + for (i = 0; i < MAX_PACKET_LISTS; i++) { + struct packet_list *pl = packet_list_alloc(s); + if (pl == NULL) + break; + list_add_tail(&pl->link, &s->free_packet_lists); + } + + return i < MAX_PACKET_LISTS ? -1 : 0; +} + +static void stream_free_packet_lists(struct stream *s) +{ + struct list_head *lh, *next; + + if (s->current_packet_list != NULL) + packet_list_free(s->current_packet_list, s); + list_for_each_safe(lh, next, &s->dma_packet_lists) + packet_list_free(list_entry(lh, struct packet_list, link), s); + list_for_each_safe(lh, next, &s->free_packet_lists) + packet_list_free(list_entry(lh, struct packet_list, link), s); + if (s->packet_pool != NULL) + pci_pool_destroy(s->packet_pool); + + s->current_packet_list = NULL; + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + s->packet_pool = NULL; +} + +static void plug_update(struct cmp_pcr *plug, void *data) +{ + struct stream *s = data; + + HPSB_INFO("plug update: p2p_count=%d, channel=%d", + plug->p2p_count, plug->channel); + s->iso_channel = plug->channel; + if (plug->p2p_count > 0) { + /* start streaming */ + } + else { + /* stop streaming */ + } +} + +static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) +{ + if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) + s->format = cfg->format; + else + return -EINVAL; + + switch (cfg->rate) { + case 32000: + s->syt_interval = 8; + s->fdf = FDF_SFC_32KHZ; + s->iec958_rate_code = 0x0c; + s->rate = cfg->rate; + break; + case 44100: + s->syt_interval = 8; + s->fdf = FDF_SFC_44K1HZ; + s->iec958_rate_code = 0x00; + s->rate = cfg->rate; + break; + case 48000: + s->syt_interval = 8; + s->fdf = FDF_SFC_48KHZ; + s->iec958_rate_code = 0x04; + s->rate = cfg->rate; + break; + default: + return -EINVAL; + } + + fraction_init(&s->packet_size_fraction, s->rate, 8000); + + /* The syt_fraction is initialized to the number of ticks + * between syt_interval events. The number of ticks per + * second is 24.576e6, so the number of ticks between + * syt_interval events is 24.576e6 * syt_interval / rate. + */ + fraction_init(&s->syt_fraction, 24576000 * s->syt_interval, s->rate); + + /* When using the AM824 raw subformat we can stream signals of + * any dimension. The IEC958 subformat, however, only + * supports 2 channels. + */ + if (s->format == AMDTP_FORMAT_RAW || cfg->dimension == 2) + s->dimension = cfg->dimension; + else + return -EINVAL; + + if (s->opcr != NULL) { + cmp_unregister_opcr(s->host->host, s->opcr); + s->opcr = NULL; + } + + switch(cmd) { + case AMDTP_IOC_PLUG: + s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, + /*payload*/ 12, plug_update, s); + if (s->opcr == NULL) + return -EINVAL; + s->iso_channel = s->opcr->channel; + break; + + case AMDTP_IOC_CHANNEL: + if (cfg->u.channel >= 0 && cfg->u.channel < 64) + s->iso_channel = cfg->u.channel; + else + return -EINVAL; + break; + } + + /* The ioctl settings were all valid, so we realloc the packet + * lists to make sure the packet size is big enough. + */ + if (s->packet_pool != NULL) + stream_free_packet_lists(s); + + if (stream_alloc_packet_lists(s) < 0) { + stream_free_packet_lists(s); + return -ENOMEM; + } + + return 0; +} + +struct stream *stream_alloc(struct amdtp_host *host) +{ + struct stream *s; + unsigned long flags; + const int transfer_delay = 8651; /* approx 352 us */ + + s = kmalloc(sizeof(struct stream), SLAB_KERNEL); + if (s == NULL) + return NULL; + + memset(s, 0, sizeof(struct stream)); + s->host = host; + + s->input = buffer_alloc(BUFFER_SIZE); + if (s->input == NULL) { + kfree(s); + return NULL; + } + + s->cycle_offset = transfer_delay % 3072; + atomic_set(&s->cycle_count, transfer_delay / 3072); + atomic_set(&s->cycle_count2, 0); + + s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev, + sizeof(struct descriptor_block), + 16, 0, SLAB_KERNEL); + if (s->descriptor_pool == NULL) { + kfree(s->input); + kfree(s); + return NULL; + } + + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + + init_waitqueue_head(&s->packet_list_wait); + spin_lock_init(&s->packet_list_lock); + + s->iso_context = ohci1394_alloc_it_ctx(host->ohci); + if (s->iso_context < 0) { + pci_pool_destroy(s->descriptor_pool); + kfree(s->input); + kfree(s); + return NULL; + } + + spin_lock_irqsave(&host->stream_list_lock, flags); + list_add_tail(&s->link, &host->stream_list); + spin_unlock_irqrestore(&host->stream_list_lock, flags); + + return s; +} + +void stream_free(struct stream *s) +{ + unsigned long flags; + + /* Stop the DMA. We wait for the dma packet list to become + * empty and let the dma controller run out of programs. This + * seems to be more reliable than stopping it directly, since + * that sometimes generates an it transmit interrupt if we + * later re-enable the context. + */ + wait_event_interruptible(s->packet_list_wait, + list_empty(&s->dma_packet_lists)); + + ohci1394_stop_it_ctx(s->host->ohci, s->iso_context); + ohci1394_free_it_ctx(s->host->ohci, s->iso_context); + + if (s->opcr != NULL) + cmp_unregister_opcr(s->host->host, s->opcr); + + spin_lock_irqsave(&s->host->stream_list_lock, flags); + list_del(&s->link); + spin_unlock_irqrestore(&s->host->stream_list_lock, flags); + + kfree(s->input); + + stream_free_packet_lists(s); + pci_pool_destroy(s->descriptor_pool); + + kfree(s); +} + +/* File operations */ + +static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count, + loff_t *offset_is_ignored) +{ + struct stream *s = file->private_data; + unsigned char *p; + int i, length; + + if (s->packet_pool == NULL) + return -EBADFD; + + /* Fill the circular buffer from the input buffer and call the + * iso packer when the buffer is full. The iso packer may + * leave bytes in the buffer for two reasons: either the + * remaining bytes wasn't enough to build a new packet, or + * there were no free packet lists. In the first case we + * re-fill the buffer and call the iso packer again or return + * if we used all the data from userspace. In the second + * case, the wait_event_interruptible will block until the irq + * handler frees a packet list. + */ + + for (i = 0; i < count; i += length) { + p = buffer_put_bytes(s->input, count, &length); + copy_from_user(p, buffer + i, length); + if (s->input->length < s->input->size) + continue; + + stream_flush(s); + + if (s->current_packet_list == NULL && + wait_event_interruptible(s->packet_list_wait, + !list_empty(&s->free_packet_lists))) + return -EINTR; + } + + return count; +} + +static int amdtp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct stream *s = file->private_data; + struct amdtp_ioctl cfg; + int new; + + switch(cmd) + { + case AMDTP_IOC_PLUG: + case AMDTP_IOC_CHANNEL: + if (copy_from_user(&cfg, (struct amdtp_ioctl *) arg, sizeof cfg)) + return -EFAULT; + else + return stream_configure(s, cmd, &cfg); + + case AMDTP_IOC_PING: + HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg); + new = s->cycle_offset + arg; + s->cycle_offset = new % 3072; + atomic_add(new / 3072, &s->cycle_count); + return 0; + + case AMDTP_IOC_ZAP: + while (MOD_IN_USE) + MOD_DEC_USE_COUNT; + return 0; + + default: + return -EINVAL; + } +} + +static int amdtp_open(struct inode *inode, struct file *file) +{ + struct amdtp_host *host; + + /* FIXME: We just grab the first registered host */ + spin_lock(&host_list_lock); + if (!list_empty(&host_list)) + host = list_entry(host_list.next, struct amdtp_host, link); + else + host = NULL; + spin_unlock(&host_list_lock); + + if (host == NULL) + return -ENODEV; + + file->private_data = stream_alloc(host); + if (file->private_data == NULL) + return -ENOMEM; + + return 0; +} + +static int amdtp_release(struct inode *inode, struct file *file) +{ + struct stream *s = file->private_data; + + stream_free(s); + + return 0; +} + +static struct file_operations amdtp_fops = +{ + owner: THIS_MODULE, + write: amdtp_write, + ioctl: amdtp_ioctl, + open: amdtp_open, + release: amdtp_release +}; + +/* IEEE1394 Subsystem functions */ + +static void amdtp_add_host(struct hpsb_host *host) +{ + struct amdtp_host *ah; + + /* FIXME: check it's an ohci host. */ + + ah = kmalloc(sizeof *ah, SLAB_KERNEL); + ah->host = host; + ah->ohci = host->hostdata; + INIT_LIST_HEAD(&ah->stream_list); + spin_lock_init(&ah->stream_list_lock); + + spin_lock_irq(&host_list_lock); + list_add_tail(&ah->link, &host_list); + spin_unlock_irq(&host_list_lock); + + ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah); +} + +static void amdtp_remove_host(struct hpsb_host *host) +{ + struct list_head *lh; + struct amdtp_host *ah; + + spin_lock_irq(&host_list_lock); + list_for_each(lh, &host_list) { + if (list_entry(lh, struct amdtp_host, link)->host == host) { + list_del(lh); + break; + } + } + spin_unlock_irq(&host_list_lock); + + if (lh != &host_list) { + ah = list_entry(lh, struct amdtp_host, link); + ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah); + kfree(ah); + } + else + HPSB_ERR("remove_host: bogus ohci host: %p", host); +} + +static struct hpsb_highlevel_ops amdtp_highlevel_ops = { + add_host: amdtp_add_host, + remove_host: amdtp_remove_host, +}; + +/* Module interface */ + +MODULE_AUTHOR("Kristian Hogsberg "); +MODULE_DESCRIPTION("Driver for Audio & Music Data Transmission Protocol " + "on OHCI boards."); +MODULE_SUPPORTED_DEVICE("amdtp"); +MODULE_LICENSE("GPL"); + +static int __init amdtp_init_module (void) +{ + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL, + THIS_MODULE, &amdtp_fops)) { + HPSB_ERR("amdtp: unable to get minor device block"); + return -EIO; + } + + amdtp_highlevel = hpsb_register_highlevel ("amdtp", + &amdtp_highlevel_ops); + if (amdtp_highlevel == NULL) { + HPSB_ERR("amdtp: unable to register highlevel ops"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL); + return -EIO; + } + + HPSB_INFO("Loaded AMDTP driver"); + + return 0; +} + +static void __exit amdtp_exit_module (void) +{ + hpsb_unregister_highlevel(amdtp_highlevel); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL); + + HPSB_INFO("Unloaded AMDTP driver"); +} + +module_init(amdtp_init_module); +module_exit(amdtp_exit_module); diff -urN linux-2.4.18/drivers/ieee1394/amdtp.h linux-2.4.19-pre5/drivers/ieee1394/amdtp.h --- linux-2.4.18/drivers/ieee1394/amdtp.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/amdtp.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,75 @@ +/* -*- c-basic-offset: 8 -*- */ + +#ifndef __AMDTP_H +#define __AMDTP_H + +#include +#include + +/* The userspace interface for the Audio & Music Data Transmission + * Protocol driver is really simple. First, open /dev/amdtp, use the + * ioctl to configure format, rate, dimension and either plug or + * channel, then start writing samples. + * + * The formats supported by the driver are listed below. + * AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can + * carry any number of channels, so use this if you're streaming + * multichannel audio. The AMDTP_FORMAT_IEC958_PCM corresponds to the + * AM824 IEC958 encapsulation without the IEC958 data bit set, using + * AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit + * set, suitable for transmitting compressed AC-3 audio. + * + * The rate field specifies the transmission rate; supported values are + * AMDTP_RATE_32KHZ, AMDTP_RATE_44K1HZ and AMDTP_RATE_48KHZ. + * + * The dimension field specifies the dimension of the signal, that is, + * the number of audio channels. Only AMDTP_FORMAT_RAW supports + * settings greater than 2. + * + * The last thing to specify is either the isochronous channel to use + * or the output plug to connect to. If you know what channel the + * destination device will listen on, you can specify the channel + * directly and use the AMDTP_IOC_CHANNEL ioctl. However, if the + * destination device chooses the channel and uses the IEC61883-1 plug + * mechanism, you can specify an output plug to connect to. The + * driver will pick up the channel number from the plug once the + * destination device locks the output plug control register. In this + * case set the plug field and use the AMDTP_IOC_PLUG ioctl. + * + * Having configured the interface, the driver now accepts writes of + * regular 16 bit signed little endian samples, with the channels + * interleaved. For example, 4 channels would look like: + * + * | sample 0 | sample 1 ... + * | ch. 0 | ch. 1 | ch. 2 | ch. 3 | ch. 0 | ... + * | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ... + * + */ + +/* We use '#' for our ioctl magic number because it's cool. */ + +#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl)) +#define AMDTP_IOC_PLUG _IOW('#', 1, sizeof (struct amdtp_ioctl)) +#define AMDTP_IOC_PING _IOW('#', 2, sizeof (struct amdtp_ioctl)) +#define AMDTP_IOC_ZAP _IO('#', 3) + +enum { + AMDTP_FORMAT_RAW, + AMDTP_FORMAT_IEC958_PCM, + AMDTP_FORMAT_IEC958_AC3 +}; + +enum { + AMDTP_RATE_32KHZ, + AMDTP_RATE_44K1HZ, + AMDTP_RATE_48KHZ, +}; + +struct amdtp_ioctl { + __u32 format; + __u32 rate; + __u32 dimension; + union { __u32 channel; __u32 plug; } u; +}; + +#endif /* __AMDTP_H */ diff -urN linux-2.4.18/drivers/ieee1394/cmp.c linux-2.4.19-pre5/drivers/ieee1394/cmp.c --- linux-2.4.18/drivers/ieee1394/cmp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/cmp.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,348 @@ +/* -*- c-basic-offset: 8 -*- + * + * cmp.c - Connection Management Procedures + * Copyright (C) 2001 Kristian Høgsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* TODO + * ---- + * + * - Implement IEC61883-1 output plugs and connection management. + * This should probably be part of the general subsystem, as it could + * be shared with dv1394. + * + * - Add IEC61883 unit directory when loading this module. This + * requires a run-time changeable config rom. + */ + +#include +#include +#include +#include +#include + +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394.h" +#include "ieee1394_core.h" +#include "cmp.h" + +struct plug { + union { + struct cmp_pcr pcr; + quadlet_t quadlet; + } u; + void (*update)(struct cmp_pcr *plug, void *data); + void *data; +}; + +struct cmp_host { + struct hpsb_host *host; + + union { + struct cmp_mpr ompr; + quadlet_t ompr_quadlet; + } u; + struct plug opcr[2]; + + union { + struct cmp_mpr impr; + quadlet_t impr_quadlet; + } v; + struct plug ipcr[2]; + + struct list_head link; +}; + +enum { + CMP_P2P_CONNECTION, + CMP_BC_CONNECTION +}; + +#define CSR_PCR_MAP 0x900 +#define CSR_PCR_MAP_END 0x9fc + +static struct hpsb_highlevel *cmp_highlevel; + +static LIST_HEAD(host_list); +static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED; + +static struct cmp_host * +lookup_cmp_host(struct hpsb_host *host) +{ + struct cmp_host *ch; + struct list_head *lh; + unsigned long flags; + + ch = NULL; + spin_lock_irqsave(&host_list_lock, flags); + list_for_each(lh, &host_list) { + ch = list_entry(lh, struct cmp_host, link); + if (ch->host == host) + break; + } + spin_unlock_irqrestore(&host_list_lock, flags); + + if (lh == &host_list) + return NULL; + else + return ch; +} + +struct cmp_pcr * +cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload, + void (*update)(struct cmp_pcr *pcr, void *data), + void *data) +{ + struct cmp_host *ch; + struct plug *plug; + + ch = lookup_cmp_host(host); + + if (opcr_number >= ch->u.ompr.nplugs || + ch->opcr[opcr_number].update != NULL) + return NULL; + + plug = &ch->opcr[opcr_number]; + plug->u.pcr.online = 1; + plug->u.pcr.bcast_count = 0; + plug->u.pcr.p2p_count = 0; + plug->u.pcr.overhead = 0; + plug->u.pcr.payload = payload; + plug->update = update; + plug->data = data; + + return &plug->u.pcr; +} + +void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr) +{ + struct cmp_host *ch; + struct plug *plug; + + ch = lookup_cmp_host(host); + plug = (struct plug *)opcr; + if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG(); + + plug->u.pcr.online = 0; + plug->update = NULL; +} + +static void reset_plugs(struct cmp_host *ch) +{ + int i; + + ch->u.ompr.non_persistent_ext = 0xff; + for (i = 0; i < ch->u.ompr.nplugs; i++) { + ch->opcr[i].u.pcr.bcast_count = 0; + ch->opcr[i].u.pcr.p2p_count = 0; + ch->opcr[i].u.pcr.overhead = 0; + } +} + +static void cmp_add_host(struct hpsb_host *host) +{ + struct cmp_host *ch; + + ch = kmalloc(sizeof *ch, SLAB_KERNEL); + if (ch == NULL) { + HPSB_ERR("Failed to allocate cmp_host"); + return; + } + memset(ch, 0, sizeof *ch); + ch->host = host; + ch->u.ompr.rate = SPEED_100; + ch->u.ompr.bcast_channel_base = 63; + ch->u.ompr.nplugs = 2; + reset_plugs(ch); + + spin_lock_irq(&host_list_lock); + list_add_tail(&ch->link, &host_list); + spin_unlock_irq(&host_list_lock); +} + +static void cmp_host_reset(struct hpsb_host *host) +{ + struct cmp_host *ch; + + ch = lookup_cmp_host(host); + if (ch == NULL) BUG(); + reset_plugs(ch); +} + +static void cmp_remove_host(struct hpsb_host *host) +{ + struct cmp_host *ch; + + ch = lookup_cmp_host(host); + if (ch == NULL) BUG(); + + spin_lock_irq(&host_list_lock); + list_del(&ch->link); + spin_unlock_irq(&host_list_lock); + + kfree(ch); +} + +static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf, + u64 addr, unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int plug; + struct cmp_host *ch; + + if (length != 4) + return RCODE_TYPE_ERROR; + + ch = lookup_cmp_host(host); + if (csraddr == 0x900) { + *buf = cpu_to_be32(ch->u.ompr_quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) { + plug = (csraddr - 0x904) / 4; + *buf = cpu_to_be32(ch->opcr[plug].u.quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x980) { + return RCODE_ADDRESS_ERROR; + } + else if (csraddr == 0x980) { + *buf = cpu_to_be32(ch->v.impr_quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) { + plug = (csraddr - 0x984) / 4; + *buf = cpu_to_be32(ch->ipcr[plug].u.quadlet); + return RCODE_COMPLETE; + } + else + return RCODE_ADDRESS_ERROR; +} + +static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int extcode) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int plug; + struct cmp_host *ch; + + ch = lookup_cmp_host(host); + + if (extcode != EXTCODE_COMPARE_SWAP) + return RCODE_TYPE_ERROR; + + if (csraddr == 0x900) { + /* FIXME: Ignore writes to bits 30-31 and 0-7 */ + *store = cpu_to_be32(ch->u.ompr_quadlet); + if (arg == cpu_to_be32(ch->u.ompr_quadlet)) + ch->u.ompr_quadlet = be32_to_cpu(data); + + return RCODE_COMPLETE; + } + if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) { + plug = (csraddr - 0x904) / 4; + *store = cpu_to_be32(ch->opcr[plug].u.quadlet); + + if (arg == *store) + ch->opcr[plug].u.quadlet = be32_to_cpu(data); + + if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet && + ch->opcr[plug].update != NULL) + ch->opcr[plug].update(&ch->opcr[plug].u.pcr, + ch->opcr[plug].data); + + return RCODE_COMPLETE; + } + else if (csraddr < 0x980) { + return RCODE_ADDRESS_ERROR; + } + else if (csraddr == 0x980) { + /* FIXME: Ignore writes to bits 24-31 and 0-7 */ + *store = cpu_to_be32(ch->u.ompr_quadlet); + if (arg == cpu_to_be32(ch->u.ompr_quadlet)) + ch->u.ompr_quadlet = be32_to_cpu(data); + + return RCODE_COMPLETE; + } + else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) { + plug = (csraddr - 0x984) / 4; + *store = cpu_to_be32(ch->ipcr[plug].u.quadlet); + + if (arg == *store) + ch->ipcr[plug].u.quadlet = be32_to_cpu(data); + + if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet && + ch->ipcr[plug].update != NULL) + ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr, + ch->ipcr[plug].data); + + return RCODE_COMPLETE; + } + else + return RCODE_ADDRESS_ERROR; +} + + +static struct hpsb_highlevel_ops cmp_highlevel_ops = { + add_host: cmp_add_host, + remove_host: cmp_remove_host, + host_reset: cmp_host_reset, +}; + +static struct hpsb_address_ops pcr_ops = { + read: pcr_read, + lock: pcr_lock, +}; + +/* Module interface */ + +MODULE_AUTHOR("Kristian Hogsberg "); +MODULE_DESCRIPTION("Connection Management Procedures (CMP)"); +MODULE_SUPPORTED_DEVICE("cmp"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cmp_register_opcr); +EXPORT_SYMBOL(cmp_unregister_opcr); + +static int __init cmp_init_module (void) +{ + cmp_highlevel = hpsb_register_highlevel ("cmp", + &cmp_highlevel_ops); + if (cmp_highlevel == NULL) { + HPSB_ERR("cmp: unable to register highlevel ops"); + return -EIO; + } + + hpsb_register_addrspace(cmp_highlevel, &pcr_ops, + CSR_REGISTER_BASE + CSR_PCR_MAP, + CSR_REGISTER_BASE + CSR_PCR_MAP_END); + + HPSB_INFO("Loaded CMP driver"); + + return 0; +} + +static void __exit cmp_exit_module (void) +{ + hpsb_unregister_highlevel(cmp_highlevel); + + HPSB_INFO("Unloaded CMP driver"); +} + +module_init(cmp_init_module); +module_exit(cmp_exit_module); diff -urN linux-2.4.18/drivers/ieee1394/cmp.h linux-2.4.19-pre5/drivers/ieee1394/cmp.h --- linux-2.4.18/drivers/ieee1394/cmp.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/cmp.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,31 @@ +#ifndef __CMP_H +#define __CMP_H + +struct cmp_mpr { + u32 nplugs:5; + u32 reserved:3; + u32 persistent_ext:8; + u32 non_persistent_ext:8; + u32 bcast_channel_base:6; + u32 rate:2; +} __attribute__((packed)); + +struct cmp_pcr { + u32 payload:10; + u32 overhead:4; + u32 speed:2; + u32 channel:6; + u32 reserved:2; + u32 p2p_count:6; + u32 bcast_count:1; + u32 online:1; +} __attribute__((packed)); + +struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug, + int payload, + void (*update)(struct cmp_pcr *plug, + void *data), + void *data); +void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug); + +#endif /* __CMP_H */ diff -urN linux-2.4.18/drivers/ieee1394/csr.c linux-2.4.19-pre5/drivers/ieee1394/csr.c --- linux-2.4.18/drivers/ieee1394/csr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/csr.c Sat Mar 30 22:55:39 2002 @@ -70,7 +70,7 @@ { host->csr.lock = SPIN_LOCK_UNLOCKED; - host->csr.rom_size = host->template->get_rom(host, &host->csr.rom); + host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom); host->csr.state = 0; host->csr.node_ids = 0; @@ -152,7 +152,7 @@ case CSR_CYCLE_TIME: oldcycle = host->csr.cycle_time; host->csr.cycle_time = - host->template->devctl(host, GET_CYCLE_COUNTER, 0); + host->ops->devctl(host, GET_CYCLE_COUNTER, 0); if (oldcycle > host->csr.cycle_time) { /* cycle time wrapped around */ @@ -163,7 +163,7 @@ case CSR_BUS_TIME: oldcycle = host->csr.cycle_time; host->csr.cycle_time = - host->template->devctl(host, GET_CYCLE_COUNTER, 0); + host->ops->devctl(host, GET_CYCLE_COUNTER, 0); if (oldcycle > host->csr.cycle_time) { /* cycle time wrapped around */ @@ -181,32 +181,32 @@ return RCODE_ADDRESS_ERROR; case CSR_BUS_MANAGER_ID: - if (host->template->hw_csr_reg) - ret = host->template->hw_csr_reg(host, 0, 0, 0); + if (host->ops->hw_csr_reg) + ret = host->ops->hw_csr_reg(host, 0, 0, 0); else ret = host->csr.bus_manager_id; *(buf++) = cpu_to_be32(ret); out; case CSR_BANDWIDTH_AVAILABLE: - if (host->template->hw_csr_reg) - ret = host->template->hw_csr_reg(host, 1, 0, 0); + if (host->ops->hw_csr_reg) + ret = host->ops->hw_csr_reg(host, 1, 0, 0); else ret = host->csr.bandwidth_available; *(buf++) = cpu_to_be32(ret); out; case CSR_CHANNELS_AVAILABLE_HI: - if (host->template->hw_csr_reg) - ret = host->template->hw_csr_reg(host, 2, 0, 0); + if (host->ops->hw_csr_reg) + ret = host->ops->hw_csr_reg(host, 2, 0, 0); else ret = host->csr.channels_available_hi; *(buf++) = cpu_to_be32(ret); out; case CSR_CHANNELS_AVAILABLE_LO: - if (host->template->hw_csr_reg) - ret = host->template->hw_csr_reg(host, 3, 0, 0); + if (host->ops->hw_csr_reg) + ret = host->ops->hw_csr_reg(host, 3, 0, 0); else ret = host->csr.channels_available_lo; @@ -244,7 +244,7 @@ host->csr.node_ids &= NODE_MASK << 16; host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16); host->node_id = host->csr.node_ids >> 16; - host->template->devctl(host, SET_BUS_ID, host->node_id >> 6); + host->ops->devctl(host, SET_BUS_ID, host->node_id >> 6); out; case CSR_RESET_START: @@ -269,7 +269,7 @@ case CSR_CYCLE_TIME: /* should only be set by cycle start packet, automatically */ host->csr.cycle_time = be32_to_cpu(*data); - host->template->devctl(host, SET_CYCLE_COUNTER, + host->ops->devctl(host, SET_CYCLE_COUNTER, be32_to_cpu(*(data++))); out; case CSR_BUS_TIME: @@ -318,10 +318,10 @@ data = be32_to_cpu(data); arg = be32_to_cpu(arg); - if (host->template->hw_csr_reg) { + if (host->ops->hw_csr_reg) { quadlet_t old; - old = host->template-> + old = host->ops-> hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2, data, arg); diff -urN linux-2.4.18/drivers/ieee1394/dv1394-private.h linux-2.4.19-pre5/drivers/ieee1394/dv1394-private.h --- linux-2.4.18/drivers/ieee1394/dv1394-private.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/dv1394-private.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,611 @@ +/* + * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DV_1394_PRIVATE_H +#define _DV_1394_PRIVATE_H + +#include "ieee1394.h" +#include +#include + +/* data structures private to the dv1394 driver */ +/* none of this is exposed to user-space */ + + +/* + the 8-byte CIP (Common Isochronous Packet) header that precedes + each packet of DV data. + + See the IEC 61883 standard. +*/ + +struct CIP_header { unsigned char b[8]; }; + +static inline void fill_cip_header(struct CIP_header *cip, + unsigned char source_node_id, + unsigned long counter, + enum pal_or_ntsc format, + unsigned long timestamp) +{ + cip->b[0] = source_node_id; + cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */ + cip->b[2] = 0x00; + cip->b[3] = counter; + + cip->b[4] = 0x80; /* const */ + + switch(format) { + case DV1394_PAL: + cip->b[5] = 0x80; + break; + case DV1394_NTSC: + cip->b[5] = 0x00; + break; + } + + cip->b[6] = timestamp >> 8; + cip->b[7] = timestamp & 0xFF; +} + + + +/* + DMA commands used to program the OHCI's DMA engine + + See the Texas Instruments OHCI 1394 chipset documentation. +*/ + +struct output_more_immediate { u32 q[8]; }; +struct output_more { u32 q[4]; }; +struct output_last { u32 q[4]; }; +struct input_more { u32 q[4]; }; +struct input_last { u32 q[4]; }; + +/* outputs */ + +static inline void fill_output_more_immediate(struct output_more_immediate *omi, + unsigned char tag, + unsigned char channel, + unsigned char sync_tag, + unsigned int payload_size) +{ + omi->q[0] = 0x02000000 | 8 ; /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */ + omi->q[1] = 0; + omi->q[2] = 0; + omi->q[3] = 0; + + /* IT packet header */ + omi->q[4] = (0x0 << 16) /* DMA_SPEED_100 */ + | (tag << 14) + | (channel << 8) + | (TCODE_ISO_DATA << 4) + | (sync_tag); + + omi->q[5] = payload_size << 16; + omi->q[5] |= (0x7F << 8) | 0xA0; /* reserved field; mimic behavior of my Sony DSR-40 */ + + omi->q[6] = 0; + omi->q[7] = 0; +} + +static inline void fill_output_more(struct output_more *om, + unsigned int data_size, + unsigned long data_phys_addr) +{ + om->q[0] = 0; /* OUTPUT_MORE */ + om->q[0] |= data_size; + + om->q[1] = data_phys_addr; + om->q[2] = 0; + om->q[3] = 0; +} + +static inline void fill_output_last(struct output_last *ol, + int want_timestamp, + int want_interrupt, + unsigned int data_size, + unsigned long data_phys_addr) +{ + ol->q[0] = 0; + ol->q[0] |= 1 << 28; /* OUTPUT_LAST */ + + if(want_timestamp) /* controller will update timestamp at DMA time */ + ol->q[0] |= 1 << 27; + + if(want_interrupt) + ol->q[0] |= 3 << 20; + + ol->q[0] |= 3 << 18; /* must take branch */ + ol->q[0] |= data_size; + + ol->q[1] = data_phys_addr; + ol->q[2] = 0; + ol->q[3] = 0; +} + +/* inputs */ + +static inline void fill_input_more(struct input_more *im, + int want_interrupt, + unsigned int data_size, + unsigned long data_phys_addr) +{ + im->q[0] = 2 << 28; /* INPUT_MORE */ + im->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */ + if (want_interrupt) + im->q[0] |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */ + im->q[0] |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */ + /* disable wait on sync field, not used in DV :-( */ + im->q[0] |= data_size; + + im->q[1] = data_phys_addr; + im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */ + im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */ +} + +static inline void fill_input_last(struct input_last *il, + unsigned int data_size, + unsigned long data_phys_addr) +{ + il->q[0] = 3 << 28; /* INPUT_LAST */ + il->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */ + il->q[0] |= 3 << 20; /* enable interrupts */ + il->q[0] |= 0xC << 16; /* enable branch to address */ + /* disable wait on sync field, not used in DV :-( */ + il->q[0] |= data_size; + + il->q[1] = data_phys_addr; + il->q[2] = 1; /* branchAddress (filled in later) and Z = 1 descriptor in next block */ + il->q[3] = data_size; /* xferStatus & resCount, resCount must be initialize to data_size */ +} + + + +/* + A "DMA descriptor block" consists of several contiguous DMA commands. + struct DMA_descriptor_block encapsulates all of the commands necessary + to send one packet of DV data. + + There are three different types of these blocks: + + 1) command to send an empty packet (CIP header only, no DV data): + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_LAST <-- points to the CIP header + + 2) command to send a full packet when the DV data payload does NOT + cross a page boundary: + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_MORE <-- points to the CIP header + OUTPUT_LAST <-- points to entire DV data payload + + 3) command to send a full packet when the DV payload DOES cross + a page boundary: + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_MORE <-- points to the CIP header + OUTPUT_MORE <-- points to first part of DV data payload + OUTPUT_LAST <-- points to second part of DV data payload + + This struct describes all three block types using unions. + + !!! It is vital that an even number of these descriptor blocks fit on one + page of memory, since a block cannot cross a page boundary !!! + + */ + +struct DMA_descriptor_block { + + union { + struct { + /* iso header, common to all output block types */ + struct output_more_immediate omi; + + union { + /* empty packet */ + struct { + struct output_last ol; /* CIP header */ + } empty; + + /* full packet */ + struct { + struct output_more om; /* CIP header */ + + union { + /* payload does not cross page boundary */ + struct { + struct output_last ol; /* data payload */ + } nocross; + + /* payload crosses page boundary */ + struct { + struct output_more om; /* data payload */ + struct output_last ol; /* data payload */ + } cross; + } u; + + } full; + } u; + } out; + + struct { + struct input_last il; + } in; + + } u; + + /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0 + by padding out to 128 bytes */ + u32 __pad__[12]; +}; + + +/* struct frame contains all data associated with one frame in the + ringbuffer these are allocated when the DMA context is initialized + do_dv1394_init(). They are re-used after the card finishes + transmitting the frame. */ + +struct video_card; /* forward declaration */ + +struct frame { + + /* points to the struct video_card that owns this frame */ + struct video_card *video; + + /* index of this frame in video_card->frames[] */ + unsigned int frame_num; + + /* FRAME_CLEAR - DMA program not set up, waiting for data + FRAME_READY - DMA program written, ready to transmit + + Changes to these should be locked against the interrupt + */ + enum { + FRAME_CLEAR = 0, + FRAME_READY + } state; + + /* whether this frame has been DMA'ed already; used only from + the IRQ handler to determine whether the frame can be reset */ + int done; + + + /* kernel virtual pointer to the start of this frame's data in + the user ringbuffer. Use only for CPU access; to get the DMA + bus address you must go through the video->user_dma mapping */ + unsigned long data; + + /* Max # of packets per frame */ + #define MAX_PACKETS 320 + + + /* a PAGE_SIZE memory pool for allocating CIP headers + !header_pool must be aligned to PAGE_SIZE! */ + struct CIP_header *header_pool; + dma_addr_t header_pool_dma; + + + /* a physically contiguous memory pool for allocating DMA + descriptor blocks; usually around 64KB in size + !descriptor_pool must be aligned to PAGE_SIZE! */ + struct DMA_descriptor_block *descriptor_pool; + dma_addr_t descriptor_pool_dma; + unsigned long descriptor_pool_size; + + + /* # of packets allocated for this frame */ + unsigned int n_packets; + + + /* below are several pointers (kernel virtual addresses, not + DMA bus addresses) to parts of the DMA program. These are + set each time the DMA program is written in + frame_prepare(). They are used later on, e.g. from the + interrupt handler, to check the status of the frame */ + + /* points to status/timestamp field of first DMA packet */ + /* (we'll check it later to monitor timestamp accuracy) */ + u32 *frame_begin_timestamp; + + /* the timestamp we assigned to the first packet in the frame */ + u32 assigned_timestamp; + + /* pointer to the first packet's CIP header (where the timestamp goes) */ + struct CIP_header *cip_syt1; + + /* pointer to the second packet's CIP header + (only set if the first packet was empty) */ + struct CIP_header *cip_syt2; + + /* in order to figure out what caused an interrupt, + store pointers to the status fields of the two packets + that can cause interrupts. We'll check these from the + interrupt handler. + */ + u32 *mid_frame_timestamp; + u32 *frame_end_timestamp; + + /* branch address field of final packet. This is effectively + the "tail" in the chain of DMA descriptor blocks. + We will fill it with the address of the first DMA descriptor + block in the subsequent frame, once it is ready. + */ + u32 *frame_end_branch; + + /* the number of descriptors in the first descriptor block + of the frame. Needed to start DMA */ + int first_n_descriptors; +}; + + +struct packet { + u16 timestamp; + u16 invalid; + u16 iso_header; + u16 data_length; + u32 cip_h1; + u32 cip_h2; + unsigned char data[480]; + unsigned char padding[16]; /* force struct size =512 for page alignment */ +}; + + +/* allocate/free a frame */ +static struct frame* frame_new(unsigned int frame_num, struct video_card *video); +static void frame_delete(struct frame *f); + +/* reset f so that it can be used again */ +static void frame_reset(struct frame *f); + + +/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */ + +struct dma_region { + unsigned int n_pages; + unsigned int n_dma_pages; + struct scatterlist *sglist; +}; + +/* return the DMA bus address of the byte with the given offset + relative to the beginning of the dma_region */ + +static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset) +{ + int i; + struct scatterlist *sg; + + for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) { + if(offset < sg_dma_len(sg)) { + return sg_dma_address(sg) + offset; + } + offset -= sg_dma_len(sg); + } + + printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset); + return 0; +} + + +/* struct video_card contains all data associated with one instance + of the dv1394 driver +*/ +enum modes { + MODE_RECEIVE, + MODE_TRANSMIT +}; + +struct video_card { + + /* ohci card to which this instance corresponds */ + struct ti_ohci *ohci; + + /* OHCI card id; the link between the VFS inode and a specific video_card + (essentially the device minor number) */ + int id; + + /* entry in dv1394_cards */ + struct list_head list; + + /* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */ + devfs_handle_t devfs_handle; + + /* OHCI card IT DMA context number, -1 if not in use */ + int ohci_it_ctx; + + /* register offsets for current IT DMA context, 0 if not in use */ + u32 ohci_IsoXmitContextControlSet; + u32 ohci_IsoXmitContextControlClear; + u32 ohci_IsoXmitCommandPtr; + + /* OHCI card IR DMA context number, -1 if not in use */ + int ohci_ir_ctx; + + /* register offsets for current IR DMA context, 0 if not in use */ + u32 ohci_IsoRcvContextControlSet; + u32 ohci_IsoRcvContextControlClear; + u32 ohci_IsoRcvCommandPtr; + u32 ohci_IsoRcvContextMatch; + + + /* CONCURRENCY CONTROL */ + + /* there are THREE levels of locking associated with video_card. */ + + /* + 1) the 'open' flag - this prevents more than one process from + opening the device. (the driver currently assumes only one opener). + This is a regular int, but use test_and_set_bit() (on bit zero) + for atomicity. + */ + int open; + + /* + 2) the spinlock - this provides mutual exclusion between the interrupt + handler and process-context operations. Generally you must take the + spinlock under the following conditions: + 1) DMA (and hence the interrupt handler) may be running + AND + 2) you need to operate on the video_card, especially active_frame + + It is OK to play with video_card without taking the spinlock if + you are certain that DMA is not running. Even if DMA is running, + it is OK to *read* active_frame with the lock, then drop it + immediately. This is safe because the interrupt handler will never + advance active_frame onto a frame that is not READY (and the spinlock + must be held while marking a frame READY). + */ + spinlock_t spinlock; + + /* + 3) the sleeping semaphore 'sem' - this is used from process context only, + to serialize various operations on the video_card. Even though only one + open() is allowed, we still need to prevent multiple threads of execution + from entering calls like read, write, ioctl, etc. + + I honestly can't think of a good reason to use dv1394 from several threads + at once, but we need to serialize anyway to prevent oopses =). + + NOTE: if you need both spinlock and sem, take sem first to avoid deadlock! + */ + struct semaphore sem; + + /* people waiting for buffer space, please form a line here... */ + wait_queue_head_t waitq; + + /* support asynchronous I/O signals (SIGIO) */ + struct fasync_struct *fasync; + + /* the large, non-contiguous (rvmalloc()) ringbuffer for DV + data, exposed to user-space via mmap() */ + unsigned char *user_buf; + unsigned long user_buf_size; + struct dma_region user_dma; + + /* next byte in the ringbuffer that a write() call will fill */ + size_t write_off; + + struct frame *frames[DV1394_MAX_FRAMES]; + + /* n_frames also serves as an indicator that this struct video_card is + intialized and ready to run DMA buffers */ + + int n_frames; + + /* this is the frame that is currently "owned" by the OHCI DMA controller + (set to -1 iff DMA is not running) + + ! must lock against the interrupt handler when accessing it ! + + RULES: + + Only the interrupt handler may change active_frame if DMA + is running; if not, process may change it + + If the next frame is READY, the interrupt handler will advance + active_frame when the current frame is finished. + + If the next frame is CLEAR, the interrupt handler will re-transmit + the current frame, and the dropped_frames counter will be incremented. + + The interrupt handler will NEVER advance active_frame to a + frame that is not READY. + + */ + int active_frame; + int first_run; + + /* the same locking rules apply to these three fields also: */ + + /* altered ONLY from process context. Must check first_clear_frame->state; + if it's READY, that means the ringbuffer is full with READY frames; + if it's CLEAR, that means one or more ringbuffer frames are CLEAR */ + unsigned int first_clear_frame; + + /* altered both by process and interrupt */ + unsigned int n_clear_frames; + + /* only altered by the interrupt */ + unsigned int dropped_frames; + + + + /* the CIP accumulator and continuity counter are properties + of the DMA stream as a whole (not a single frame), so they + are stored here in the video_card */ + + unsigned long cip_accum; + unsigned long cip_n, cip_d; + unsigned int syt_offset; + unsigned int continuity_counter; + + enum pal_or_ntsc pal_or_ntsc; + + /* redundant, but simplifies the code somewhat */ + unsigned int frame_size; /* in bytes */ + + /* the isochronous channel to use, -1 if video card is inactive */ + int channel; + + + /* physically contiguous packet ringbuffer for receive */ +#define MAX_PACKET_BUFFER 30 + struct packet *packet_buffer; + dma_addr_t packet_buffer_dma; + unsigned long packet_buffer_size; + + unsigned int current_packet; + int first_frame; /* received first start frame marker? */ + enum modes mode; +}; + +/* + if the video_card is not initialized, then the ONLY fields that are valid are: + ohci + open + n_frames +*/ + +static inline int video_card_initialized(struct video_card *v) +{ + return v->n_frames > 0; +} + +static int do_dv1394_init(struct video_card *video, struct dv1394_init *init); +static int do_dv1394_init_default(struct video_card *video); +static int do_dv1394_shutdown(struct video_card *video, int free_user_buf); + + +/* NTSC empty packet rate accurate to within 0.01%, + calibrated against a Sony DSR-40 DVCAM deck */ + +#define CIP_N_NTSC 68000000 +#define CIP_D_NTSC 1000000000 + +#define CIP_N_PAL 1 +#define CIP_D_PAL 16 + +#endif /* _DV_1394_PRIVATE_H */ + diff -urN linux-2.4.18/drivers/ieee1394/dv1394.c linux-2.4.19-pre5/drivers/ieee1394/dv1394.c --- linux-2.4.18/drivers/ieee1394/dv1394.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/dv1394.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,3002 @@ +/* + * dv1394.c - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.c - video driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * + * 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. + */ + +/* + OVERVIEW + + I designed dv1394 as a "pipe" that you can use to shoot DV onto a + FireWire bus. In transmission mode, dv1394 does the following: + + 1. accepts contiguous frames of DV data from user-space, via write() + or mmap() (see dv1394.h for the complete API) + 2. wraps IEC 61883 packets around the DV data, inserting + empty synchronization packets as necessary + 3. assigns accurate SYT timestamps to the outgoing packets + 4. shoots them out using the OHCI card's IT DMA engine + + Thanks to Dan Dennedy, we now have a receive mode that does the following: + + 1. accepts raw IEC 61883 packets from the OHCI card + 2. re-assembles the DV data payloads into contiguous frames, + discarding empty packets + 3. sends the DV data to user-space via read() or mmap() +*/ + +/* + TODO: + + - tunable frame-drop behavior: either loop last frame, or halt transmission + + - use a scatter/gather buffer for DMA programs (f->descriptor_pool) + so that we don't rely on allocating 64KB of contiguous kernel memory + via pci_alloc_consistent() + + DONE: + - safely obtain and release ISO Tx channels in cooperation with OHCI driver + - map received DIF blocks to their proper location in DV frame (ensure + recovery if dropped packet) + - handle bus resets gracefully (OHCI card seems to take care of this itself(!)) + - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings + - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk + - added wmb() and mb() to places where PCI read/write ordering needs to be enforced + - set video->id correctly + - store video_cards in an array indexed by OHCI card ID, rather than a list + - implement DMA context allocation to cooperate with other users of the OHCI + - fix all XXX showstoppers + - disable IR/IT DMA interrupts on shutdown + - flush pci writes to the card by issuing a read + - devfs and character device dispatching (* needs testing with Linux 2.2.x) + - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!) + - keep all video_cards in a list (for open() via chardev), set file->private_data = video + - dv1394_poll should indicate POLLIN when receiving buffers are available + - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal + - expose xmit and recv as separate devices (not exclusive) + - expose NTSC and PAL as separate devices (can be overridden) + - read/edit channel in procfs + +*/ + +#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 "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "dv1394.h" +#include "dv1394-private.h" + +#include "ohci1394.h" + +#ifndef virt_to_page +#define virt_to_page(x) MAP_NR(x) +#endif + +#ifndef vmalloc_32 +#define vmalloc_32(x) vmalloc(x) +#endif + + +/* DEBUG LEVELS: + 0 - no debugging messages + 1 - some debugging messages, but none during DMA frame transmission + 2 - lots of messages, including during DMA frame transmission + (will cause undeflows if your machine is too slow!) +*/ + +#define DV1394_DEBUG_LEVEL 0 + +/* for debugging use ONLY: allow more than one open() of the device */ +/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ + +#if DV1394_DEBUG_LEVEL >= 2 +#define irq_printk( args... ) printk( args ) +#else +#define irq_printk( args... ) +#endif + +#if DV1394_DEBUG_LEVEL >= 1 +#define debug_printk( args... ) printk( args) +#else +#define debug_printk( args... ) +#endif + +/* issue a dummy PCI read to force the preceding write + to be posted to the PCI bus immediately */ + +static inline void flush_pci_write(struct ti_ohci *ohci) +{ + mb(); + reg_read(ohci, OHCI1394_IsochronousCycleTimer); +} + +static void irq_handler(int card, quadlet_t isoRecvIntEvent, + quadlet_t isoXmitIntEvent, void *data); + + +/* GLOBAL DATA */ + +/* list of all video_cards */ +static LIST_HEAD(dv1394_cards); +static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED; + +static struct hpsb_highlevel *hl_handle; /* = NULL; */ + +static LIST_HEAD(dv1394_devfs); +struct dv1394_devfs_entry { + struct list_head list; + devfs_handle_t devfs; + char name[32]; + struct dv1394_devfs_entry *parent; +}; +static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED; + +/* translate from a struct file* to the corresponding struct video_card* */ + +static inline struct video_card* file_to_video_card(struct file *file) +{ + return (struct video_card*) file->private_data; +} + + +/* Taken from bttv.c */ +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr) +{ + pmd_t *pmd; + pte_t *ptep, pte; + struct page *ret = NULL; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = pte_page(pte); + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved, and for + * handling page faults on the rvmalloc()ed buffer + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) { + memset(mem, 0, size); /* Clear the ram out, + no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) { + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +/***********************************/ +/* END Memory management functions */ +/***********************************/ + + +/*** FRAME METHODS *********************************************************/ + +static void frame_reset(struct frame *f) +{ + f->state = FRAME_CLEAR; + f->done = 0; + f->n_packets = 0; + f->frame_begin_timestamp = NULL; + f->assigned_timestamp = 0; + f->cip_syt1 = NULL; + f->cip_syt2 = NULL; + f->mid_frame_timestamp = NULL; + f->frame_end_timestamp = NULL; + f->frame_end_branch = NULL; +} + +static struct frame* frame_new(unsigned int frame_num, struct video_card *video) +{ + struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL); + if(!f) + return NULL; + + f->video = video; + f->frame_num = frame_num; + + f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma); + if(!f->header_pool) { + printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n"); + kfree(f); + return NULL; + } + + debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", + (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE); + + f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block); + /* make it an even # of pages */ + f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE); + + f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev, + f->descriptor_pool_size, + &f->descriptor_pool_dma); + if(!f->descriptor_pool) { + pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); + kfree(f); + return NULL; + } + + debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", + (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size); + + f->data = 0; + frame_reset(f); + + return f; +} + +static void frame_delete(struct frame *f) +{ + pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); + pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma); + kfree(f); +} + + + + +/* + frame_prepare() - build the DMA program for transmitting + + Frame_prepare() must be called OUTSIDE the video->spinlock. + However, frame_prepare() must still be serialized, so + it should be called WITH the video->sem taken. + */ + +static void frame_prepare(struct video_card *video, unsigned int this_frame) +{ + struct frame *f = video->frames[this_frame]; + int last_frame; + + struct DMA_descriptor_block *block; + dma_addr_t block_dma; + struct CIP_header *cip; + dma_addr_t cip_dma; + + unsigned int n_descriptors, full_packets, packets_per_frame, payload_size; + + /* these flags denote packets that need special attention */ + int empty_packet, first_packet, last_packet, mid_packet; + + u32 *branch_address, *last_branch_address = NULL; + unsigned long data_p; + int first_packet_empty = 0; + u32 cycleTimer, ct_sec, ct_cyc, ct_off; + unsigned long irq_flags; + + irq_printk("frame_prepare( %d ) ---------------------\n", this_frame); + + full_packets = 0; + + + + if(video->pal_or_ntsc == DV1394_PAL) + packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME; + else + packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME; + + while( full_packets < packets_per_frame ) { + empty_packet = first_packet = last_packet = mid_packet = 0; + + data_p = f->data + full_packets * 480; + + /************************************************/ + /* allocate a descriptor block and a CIP header */ + /************************************************/ + + /* note: these should NOT cross a page boundary (DMA restriction) */ + + if(f->n_packets >= MAX_PACKETS) { + printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n"); + return; + } + + /* the block surely won't cross a page boundary, + since an even number of descriptor_blocks fit on a page */ + block = &(f->descriptor_pool[f->n_packets]); + + /* DMA address of the block = offset of block relative + to the kernel base address of the descriptor pool + + DMA base address of the descriptor pool */ + block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + + + /* the whole CIP pool fits on one page, so no worries about boundaries */ + if( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool) + > PAGE_SIZE) { + printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n"); + return; + } + + cip = &(f->header_pool[f->n_packets]); + + /* DMA address of the CIP header = offset of cip + relative to kernel base address of the header pool + + DMA base address of the header pool */ + cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma; + + /* is this an empty packet? */ + + if(video->cip_accum > video->cip_d) { + empty_packet = 1; + payload_size = 8; + video->cip_accum -= video->cip_d; + } else { + payload_size = 488; + video->cip_accum += video->cip_n; + } + + /* there are three important packets each frame: + + the first packet in the frame - we ask the card to record the timestamp when + this packet is actually sent, so we can monitor + how accurate our timestamps are. Also, the first + packet serves as a semaphore to let us know that + it's OK to free the *previous* frame's DMA buffer + + the last packet in the frame - this packet is used to detect buffer underflows. + if this is the last ready frame, the last DMA block + will have a branch back to the beginning of the frame + (so that the card will re-send the frame on underflow). + if this branch gets taken, we know that at least one + frame has been dropped. When the next frame is ready, + the branch is pointed to its first packet, and the + semaphore is disabled. + + a "mid" packet slightly before the end of the frame - this packet should trigger + an interrupt so we can go and assign a timestamp to the first packet + in the next frame. We don't use the very last packet in the frame + for this purpose, because that would leave very little time to set + the timestamp before DMA starts on the next frame. + */ + + if(f->n_packets == 0) { + first_packet = 1; + } else if ( full_packets == (packets_per_frame-1) ) { + last_packet = 1; + } else if (f->n_packets == packets_per_frame) { + mid_packet = 1; + } + + + /********************/ + /* setup CIP header */ + /********************/ + + /* the timestamp will be written later from the + mid-frame interrupt handler. For now we just + store the address of the CIP header(s) that + need a timestamp. */ + + /* first packet in the frame needs a timestamp */ + if(first_packet) { + f->cip_syt1 = cip; + if(empty_packet) + first_packet_empty = 1; + + } else if(first_packet_empty && (f->n_packets == 1) ) { + /* if the first packet was empty, the second + packet's CIP header also needs a timestamp */ + f->cip_syt2 = cip; + } + + fill_cip_header(cip, + /* the node ID number of the OHCI card */ + reg_read(video->ohci, OHCI1394_NodeID) & 0x3F, + video->continuity_counter, + video->pal_or_ntsc, + 0xFFFF /* the timestamp is filled in later */); + + /* advance counter, only for full packets */ + if( ! empty_packet ) + video->continuity_counter++; + + /******************************/ + /* setup DMA descriptor block */ + /******************************/ + + /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */ + fill_output_more_immediate( &(block->u.out.omi), + /* tag - what is this??? */ 1, + video->channel, + /* sync tag - what is this??? */ 0, + payload_size); + + if(empty_packet) { + /* second descriptor - OUTPUT_LAST for CIP header */ + fill_output_last( &(block->u.out.u.empty.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupts on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + sizeof(struct CIP_header), /* data size */ + cip_dma); + + if(first_packet) + f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]); + else if(mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]); + else if(last_packet) { + f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]); + } + + branch_address = &(block->u.out.u.empty.ol.q[2]); + n_descriptors = 3; + if(first_packet) + f->first_n_descriptors = n_descriptors; + + } else { /* full packet */ + + /* second descriptor - OUTPUT_MORE for CIP header */ + fill_output_more( &(block->u.out.u.full.om), + sizeof(struct CIP_header), /* data size */ + cip_dma); + + + /* third (and possibly fourth) descriptor - for DV data */ + /* the 480-byte payload can cross a page boundary; if so, + we need to split it into two DMA descriptors */ + + /* does the 480-byte data payload cross a page boundary? */ + if( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) { + + /* page boundary crossed */ + + fill_output_more( &(block->u.out.u.full.u.cross.om), + /* data size - how much of data_p fits on the first page */ + PAGE_SIZE - (data_p % PAGE_SIZE), + + /* DMA address of data_p */ + dma_offset_to_bus(&f->video->user_dma, + data_p - (unsigned long) f->video->user_buf)); + + fill_output_last( &(block->u.out.u.full.u.cross.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupt on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* data size - remaining portion of data_p */ + 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)), + + /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */ + dma_offset_to_bus(&f->video->user_dma, + data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf)); + + if(first_packet) + f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + else if(mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + else if(last_packet) { + f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]); + } + + branch_address = &(block->u.out.u.full.u.cross.ol.q[2]); + + n_descriptors = 5; + if(first_packet) + f->first_n_descriptors = n_descriptors; + + full_packets++; + + } else { + /* fits on one page */ + + fill_output_last( &(block->u.out.u.full.u.nocross.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupt on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + 480, /* data size (480 bytes of DV data) */ + + + /* DMA address of data_p */ + dma_offset_to_bus(&f->video->user_dma, + data_p - (unsigned long) f->video->user_buf)); + + if(first_packet) + f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + else if(mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + else if(last_packet) { + f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]); + } + + branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]); + + n_descriptors = 4; + if(first_packet) + f->first_n_descriptors = n_descriptors; + + full_packets++; + } + } + + /* link this descriptor block into the DMA program by filling in + the branch address of the previous block */ + + /* note: we are not linked into the active DMA chain yet */ + + if(last_branch_address) { + *(last_branch_address) = block_dma | n_descriptors; + } + + last_branch_address = branch_address; + + + f->n_packets++; + + } + + /* when we first assemble a new frame, set the final branch + to loop back up to the top */ + *(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; + + + /* make the latest version of the frame buffer visible to the PCI card */ + /* could optimize this by only syncing the pages associated with this frame */ + pci_dma_sync_sg(video->ohci->dev, + &video->user_dma.sglist[0], + video->user_dma.n_dma_pages, + PCI_DMA_TODEVICE); + + /* lock against DMA interrupt */ + spin_lock_irqsave(&video->spinlock, irq_flags); + + f->state = FRAME_READY; + + video->n_clear_frames--; + + last_frame = video->first_clear_frame - 1; + if(last_frame == -1) + last_frame = video->n_frames-1; + + video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; + + irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n", + this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame); + + irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n", + (unsigned long) f->frame_begin_timestamp, + (unsigned long) f->mid_frame_timestamp, + (unsigned long) f->frame_end_timestamp, + (unsigned long) f->frame_end_branch); + + if(video->active_frame != -1) { + + /* if DMA is already active, we are almost done */ + /* just link us onto the active DMA chain */ + if(video->frames[last_frame]->frame_end_branch) { + + /* point the previous frame's tail to this frame's head */ + *(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; + + /* this write MUST precede the next one, or we could silently drop frames */ + wmb(); + + /* disable the want_status semaphore on the last packet */ + *(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF; + + /* flush these writes to memory ASAP */ + flush_pci_write(video->ohci); + + /* NOTE: + ideally the writes should be "atomic": if + the OHCI card reads the want_status flag in + between them, we'll falsely report a + dropped frame. Hopefully this window is too + small to really matter, and the consequence + is rather harmless. */ + + + irq_printk(" new frame %d linked onto DMA chain\n", this_frame); + + } else { + printk(KERN_ERR "dv1394: last frame not ready???\n"); + } + + } else { + + u32 transmit_sec, transmit_cyc; + u32 ts_cyc, ts_off; + + /* DMA is stopped, so this is the very first frame */ + video->active_frame = this_frame; + + /* set CommandPtr to address and size of first descriptor block */ + reg_write(video->ohci, video->ohci_IsoXmitCommandPtr, + video->frames[video->active_frame]->descriptor_pool_dma | + f->first_n_descriptors); + + /* assign a timestamp based on the current cycle time... + We'll tell the card to begin DMA 100 cycles from now, + and assign a timestamp 103 cycles from now */ + + cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer); + + ct_sec = cycleTimer >> 25; + ct_cyc = (cycleTimer >> 12) & 0x1FFF; + ct_off = cycleTimer & 0xFFF; + + transmit_sec = ct_sec; + transmit_cyc = ct_cyc + 100; + + transmit_sec += transmit_cyc/8000; + transmit_cyc %= 8000; + + ts_off = ct_off; + ts_cyc = transmit_cyc + 3; + ts_cyc %= 8000; + + f->assigned_timestamp = (ts_cyc&0xF) << 12; + + /* now actually write the timestamp into the appropriate CIP headers */ + if(f->cip_syt1) { + f->cip_syt1->b[6] = f->assigned_timestamp >> 8; + f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF; + } + if(f->cip_syt2) { + f->cip_syt2->b[6] = f->assigned_timestamp >> 8; + f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF; + } + + /* --- start DMA --- */ + + /* clear all bits in ContextControl register */ + + reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF); + wmb(); + + /* the OHCI card has the ability to start ISO transmission on a + particular cycle (start-on-cycle). This way we can ensure that + the first DV frame will have an accurate timestamp. + + However, start-on-cycle only appears to work if the OHCI card + is cycle master! Since the consequences of messing up the first + timestamp are minimal*, just disable start-on-cycle for now. + + * my DV deck drops the first few frames before it "locks in;" + so the first frame having an incorrect timestamp is inconsequential. + */ + +#if 0 + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, + (1 << 31) /* enable start-on-cycle */ + | ( (transmit_sec & 0x3) << 29) + | (transmit_cyc << 16)); + wmb(); +#endif + + + + /* set the 'run' bit */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + /* --- DMA should be running now --- */ + + debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n", + (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF, + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); + + debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n", + ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF); + +#if DV1394_DEBUG_LEVEL >= 2 + { + /* check if DMA is really running */ + int i = 0; + while(i < 20) { + mb(); + mdelay(1); + if(reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) { + printk("DMA ACTIVE after %d msec\n", i); + break; + } + i++; + } + + printk("set = %08x, cmdPtr = %08x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) + ); + + if( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { + printk("DMA did NOT go active after 20ms, event = %x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F); + } else + printk("DMA is RUNNING!\n"); + } +#endif + + } + + + spin_unlock_irqrestore(&video->spinlock, irq_flags); +} + + + +/*** RECEIVE FUNCTIONS *****************************************************/ + +/* + frame method put_packet + + map and copy the packet data to its location in the frame + based upon DIF section and sequence +*/ + +static void inline +frame_put_packet (struct frame *f, struct packet *p) +{ + int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */ + int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */ + int dif_block = p->data[2]; + + switch (section_type) { + case 0: /* 1 Header block */ + memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480); + break; + + case 1: /* 2 Subcode blocks */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480); + break; + + case 2: /* 3 VAUX blocks */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480); + break; + + case 3: /* 9 Audio blocks interleaved with video */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480); + break; + + case 4: /* 135 Video blocks interleaved with audio */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480); + break; + + default: /* we can not handle any other data */ + break; + } +} + + +static void start_dma_receive(struct video_card *video, struct frame *frame) +{ + /* reset iso recv control register */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF); + wmb(); + + /* clear bufferFill, set isochHeader and speed (0=100) */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000); + + /* match on all tags, listen on channel */ + reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel); + + /* address and first descriptor block + Z=1 */ + reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, + frame->descriptor_pool_dma | 1); /* Z=1 */ + wmb(); + + /* run */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + debug_printk("dv1394: DMA started\n"); + +#if DV1394_DEBUG_LEVEL >= 2 + { + int i; + + for(i = 0; i < 1000; ++i) { + mdelay(1); + if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) { + printk("DMA ACTIVE after %d msec\n", i); + break; + } + } + if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + } else + printk("RUNNING!\n"); + } +#endif +} + + +/* + receive_packets() - build the DMA program for receiving +*/ + +static void receive_packets(struct video_card *video, struct frame *f) +{ + struct DMA_descriptor_block *block = NULL; + dma_addr_t block_dma = 0; + struct packet *data = NULL; + dma_addr_t data_dma = 0; + u32 *last_branch_address = NULL; + unsigned long irq_flags; + + spin_lock_irqsave(&video->spinlock, irq_flags); + + video->n_clear_frames = 0; + video->first_clear_frame = -1; + + for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) { + /* locate a descriptor block and packet from the buffer */ + block = &(f->descriptor_pool[video->current_packet]); + block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + + data = &(video->packet_buffer[video->current_packet]); + data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma; + + /* setup DMA descriptor block */ + fill_input_last( &(block->u.in.il), 512, data_dma); + + /* link descriptors */ + last_branch_address = f->frame_end_branch; + + if (last_branch_address) + *(last_branch_address) = block_dma | 1; /* set Z=1 */ + + f->frame_end_branch = &(block->u.in.il.q[2]); + } + + /* loop tail to head */ + if (f->frame_end_branch) + *(f->frame_end_branch) = f->descriptor_pool_dma | 1; /* set Z=1 */ + + spin_unlock_irqrestore(&video->spinlock, irq_flags); + + if (video->first_run) { + /* start DMA once all of the frames are READY */ + video->first_run = 0; + video->current_packet = 0; + video->active_frame = f->frame_num; + start_dma_receive(video, f); + } + else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + debug_printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + + /* wake */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); + } +} + + + +/*** MANAGEMENT FUNCTIONS **************************************************/ + +static int do_dv1394_init(struct video_card *video, struct dv1394_init *init) +{ + unsigned long flags, new_buf_size; + int i; + u64 chan_mask; + int retval = -EINVAL; + + if(init->api_version != DV1394_API_VERSION) + goto err; + + /* first sanitize all the parameters */ + if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) ) + goto err; + + if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) ) + goto err; + + if( (init->syt_offset == 0) || (init->syt_offset > 50) ) + /* default SYT offset is 3 cycles */ + init->syt_offset = 3; + + if( (init->channel > 63) || (init->channel < 0) ) + init->channel = 63; + + chan_mask = (u64)1 << init->channel; + + /* calculate what size DMA buffer is needed */ + if(init->format == DV1394_NTSC) + new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames; + else + new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames; + + /* round up to PAGE_SIZE */ + if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE); + + /* don't allow the user to allocate the DMA buffer more than once */ + if( (video->user_buf) && + (video->user_buf_size != new_buf_size) ) { + goto err; + } + + /* shutdown the card if it's currently active */ + /* (the card should not be reset if the parameters are screwy) */ + if( video_card_initialized(video) ) + do_dv1394_shutdown(video, 0); + + + /* try to claim the ISO channel */ + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + if(video->ohci->ISO_channel_usage & chan_mask) { + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + retval = -EBUSY; + goto err; + } + video->ohci->ISO_channel_usage |= chan_mask; + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + + video->channel = init->channel; + + + /* find and claim DMA contexts on the OHCI card */ + + if(video->ohci_it_ctx == -1) { + + for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) { + + if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) { + video->ohci_it_ctx = i; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + break; + } + } + + if(i == video->ohci->nb_iso_xmit_ctx) { + printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); + retval = -EBUSY; + goto err_ctx; + } + } + + + if(video->ohci_ir_ctx == -1) { + for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) { + + if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) { + video->ohci_ir_ctx = i; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + break; + } + } + + if(i == video->ohci->nb_iso_rcv_ctx) { + printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); + retval = -EBUSY; + goto err_ctx; + } + } + + + /* allocate struct frames */ + for(i = 0; i < init->n_frames; i++) { + video->frames[i] = frame_new(i, video); + + if(!video->frames[i]) { + printk(KERN_ERR "dv1394: Cannot allocate frame structs\n"); + retval = -ENOMEM; + goto err_frames; + } + } + + /* initialize misc. fields of video */ + video->n_frames = init->n_frames; + video->pal_or_ntsc = init->format; + + + video->cip_accum = 0; + video->continuity_counter = 0; + + video->active_frame = -1; + video->first_clear_frame = 0; + video->n_clear_frames = video->n_frames; + video->dropped_frames = 0; + + video->write_off = 0; + + video->first_run = 1; + video->current_packet = -1; + video->first_frame = 0; + + + if(video->pal_or_ntsc == DV1394_NTSC) { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; + video->frame_size = DV1394_NTSC_FRAME_SIZE; + } else { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL; + video->frame_size = DV1394_PAL_FRAME_SIZE; + } + + video->syt_offset = init->syt_offset; + + if(video->user_buf == NULL) { + unsigned int i; + + /* allocate the ringbuffer */ + video->user_buf = rvmalloc(new_buf_size); + if(!video->user_buf) { + printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n"); + goto err_frames; + } + video->user_buf_size = new_buf_size; + + /* allocate the sglist to hold the DMA addresses */ + video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE; + video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL); + if(!video->user_dma.sglist) { + printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n"); + goto err_user_buf; + } + + /* initialize all fields of all sglist entries to zero + (new requirement due to PCI changes in 2.4.13) */ + + memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist)); + + + /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */ + for(i = 0; i < video->user_dma.n_pages; i++) { + unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE ); + + video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va); + video->user_dma.sglist[i].length = PAGE_SIZE; + } + + /* map the buffer in the IOMMU */ + /* the user_data buffer only allows DMA *to* the card for transmission; + incoming DV data comes through the packet_buffer first, and then is copied to user_data */ + video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev, + &video->user_dma.sglist[0], + video->user_dma.n_pages, + PCI_DMA_TODEVICE); + if(video->user_dma.n_dma_pages == 0) { + printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n"); + goto err_user_buf; + } + + debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", + video->n_frames, video->user_dma.n_pages, + video->user_dma.n_dma_pages, video->user_buf_size); + } + + /* set up the frame->data pointers */ + for(i = 0; i < video->n_frames; i++) + video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size; + + /* allocate packet buffers */ + video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER; + if (video->packet_buffer_size % PAGE_SIZE) + video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE); + + + video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL); + + if(!video->packet_buffer) { + printk(KERN_ERR "dv1394: Cannot allocate packet buffers"); + retval = -ENOMEM; + goto err_user_buf; + } + + /* map the packet buffer into the IOMMU */ + video->packet_buffer_dma = pci_map_single(video->ohci->dev, + video->packet_buffer, + video->packet_buffer_size, + PCI_DMA_FROMDEVICE); + if(!video->packet_buffer_dma) { + printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU"); + kfree(video->packet_buffer); + video->packet_buffer = NULL; + retval = -ENOMEM; + goto err_user_buf; + } + + debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", + MAX_PACKET_BUFFER, video->packet_buffer_size); + + + /* set up register offsets for IT context */ + /* IT DMA context registers are spaced 16 bytes apart */ + video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx; + video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx; + video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx; + + /* enable interrupts for IT context */ + reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx)); + debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx); + + /* set up register offsets for IR context */ + /* IR DMA context registers are spaced 32 bytes apart */ + video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx; + video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx; + video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx; + video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx; + + /* enable interrupts for IR context */ + reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) ); + debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx); + + return 0; + + err_user_buf: + if(video->user_buf) { + if(video->user_dma.sglist) { + if(video->user_dma.n_dma_pages > 0) { + /* unmap it from the IOMMU */ + pci_unmap_sg(video->ohci->dev, + video->user_dma.sglist, + video->user_dma.n_pages, + PCI_DMA_TODEVICE); + video->user_dma.n_dma_pages = 0; + } + kfree(video->user_dma.sglist); + video->user_dma.sglist = NULL; + video->user_dma.n_pages = 0; + } + rvfree(video->user_buf, video->user_buf_size); + video->user_buf = NULL; + video->user_buf_size = 0; + } + + err_frames: + for(i = 0; i < DV1394_MAX_FRAMES; i++) { + if(video->frames[i]) + frame_delete(video->frames[i]); + } + video->n_frames = 0; + + err_ctx: + if(video->ohci_it_ctx != -1) { + clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage); + video->ohci_it_ctx = -1; + } + if(video->ohci_ir_ctx != -1) { + clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage); + video->ohci_ir_ctx = -1; + } + + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + video->ohci->ISO_channel_usage &= ~chan_mask; + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + err: + return retval; +} + +/* if the user doesn't bother to call ioctl(INIT) before starting + mmap() or read()/write(), just give him some default values */ + +static int do_dv1394_init_default(struct video_card *video) +{ + struct dv1394_init init; + + init.api_version = DV1394_API_VERSION; + init.n_frames = 2; + /* the following are now set via proc_fs or devfs */ + init.channel = video->channel; + init.format = video->pal_or_ntsc; + init.cip_n = video->cip_n; + init.cip_d = video->cip_d; + init.syt_offset = video->syt_offset; + + return do_dv1394_init(video, &init); +} + +/* do NOT call from interrupt context */ +static void stop_dma(struct video_card *video) +{ + unsigned long flags; + int i; + + /* no interrupts */ + spin_lock_irqsave(&video->spinlock, flags); + + /* stop DMA if in progress */ + if( (video->active_frame != -1) || + (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || + (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { + + /* clear the .run bits */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15)); + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15)); + flush_pci_write(video->ohci); + + video->active_frame = -1; + video->first_run = 1; + + + /* wait until DMA really stops */ + i = 0; + while(i < 1000) { + + /* wait 0.1 millisecond */ + udelay(100); + + if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || + (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { + /* still active */ + mb(); + } else { + debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10); + break; + } + + i++; + } + + if(i == 1000) { + printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10); + } + } + + spin_unlock_irqrestore(&video->spinlock, flags); +} + + + +static int do_dv1394_shutdown(struct video_card *video, int free_user_buf) +{ + int i; + + debug_printk("dv1394: shutdown...\n"); + + /* stop DMA if in progress */ + stop_dma(video); + + /* release the ISO channel */ + if(video->channel != -1) { + u64 chan_mask; + unsigned long flags; + + chan_mask = (u64)1 << video->channel; + + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + video->ohci->ISO_channel_usage &= ~(chan_mask); + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + + video->channel = -1; + } + + /* release the DMA contexts */ + if(video->ohci_it_ctx != -1) { + video->ohci_IsoXmitContextControlSet = 0; + video->ohci_IsoXmitContextControlClear = 0; + video->ohci_IsoXmitCommandPtr = 0; + + /* disable interrupts for IT context */ + reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx)); + + clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage); + debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx); + video->ohci_it_ctx = -1; + } + + if(video->ohci_ir_ctx != -1) { + video->ohci_IsoRcvContextControlSet = 0; + video->ohci_IsoRcvContextControlClear = 0; + video->ohci_IsoRcvCommandPtr = 0; + video->ohci_IsoRcvContextMatch = 0; + + /* disable interrupts for IR context */ + reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx)); + + clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage); + debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx); + video->ohci_ir_ctx = -1; + } + + /* free the frame structs */ + for(i = 0; i < DV1394_MAX_FRAMES; i++) { + if(video->frames[i]) + frame_delete(video->frames[i]); + video->frames[i] = NULL; + } + + video->n_frames = 0; + + /* we can't free the DMA buffer unless it is guaranteed that + no more user-space mappings exist */ + + if(free_user_buf && video->user_buf) { + if(video->user_dma.sglist) { + if(video->user_dma.n_dma_pages > 0) { + /* unmap it from the IOMMU */ + pci_unmap_sg(video->ohci->dev, + video->user_dma.sglist, + video->user_dma.n_pages, + PCI_DMA_TODEVICE); + video->user_dma.n_dma_pages = 0; + } + kfree(video->user_dma.sglist); + video->user_dma.sglist = NULL; + video->user_dma.n_pages = 0; + } + rvfree(video->user_buf, video->user_buf_size); + video->user_buf = NULL; + video->user_buf_size = 0; + } + + if (video->packet_buffer) { + pci_unmap_single(video->ohci->dev, + video->packet_buffer_dma, + video->packet_buffer_size, + PCI_DMA_FROMDEVICE); + kfree(video->packet_buffer); + video->packet_buffer = NULL; + video->packet_buffer_size = 0; + } + + debug_printk("dv1394: shutdown complete\n"); + + return 0; +} + + + +/* + ********************************** + *** MMAP() THEORY OF OPERATION *** + ********************************** + + The ringbuffer cannot be re-allocated or freed while + a user program maintains a mapping of it. (note that a mapping + can persist even after the device fd is closed!) + + So, only let the user process allocate the DMA buffer once. + To resize or deallocate it, you must close the device file + and open it again. + + Previously Dan M. hacked out a scheme that allowed the DMA + buffer to change by forcefully unmapping it from the user's + address space. It was prone to error because it's very hard to + track all the places the buffer could have been mapped (we + would have had to walk the vma list of every process in the + system to be sure we found all the mappings!). Instead, we + force the user to choose one buffer size and stick with + it. This small sacrifice is worth the huge reduction in + error-prone code in dv1394. + + Note: dv1394_mmap does no page table manipulation. The page + table entries are created by the dv1394_nopage() handler as + page faults are taken by the user. +*/ + +static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access) +{ + unsigned long offset; + unsigned long page, kernel_virt_addr; + struct page *ret = NOPAGE_SIGBUS; + + struct video_card *video = (struct video_card*) area->vm_private_data; + + /* guard against process-context operations and the interrupt */ + /* (by definition page faults are taken in interrupt context) */ + spin_lock(&video->spinlock); + + if(!video->user_buf) + goto out; + + if( (address < (unsigned long) area->vm_start) || + (address > (unsigned long) area->vm_start + video->user_buf_size) ) + goto out; + + offset = address - area->vm_start; + kernel_virt_addr = (unsigned long) video->user_buf + offset; + + page = kvirt_to_pa(kernel_virt_addr); + + ret = virt_to_page(__va(page)); + get_page(ret); + + out: + spin_unlock(&video->spinlock); + return ret; +} + +static struct vm_operations_struct dv1394_vm_ops = { + nopage: dv1394_nopage +}; + +/* + dv1394_mmap does no page table manipulation. The page table entries + are created by the dv1394_nopage() handler as page faults are taken + by the user. +*/ + +int dv1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_card *video = file_to_video_card(file); + unsigned long size; + int res = -EINVAL; + + /* serialize mmap */ + down(&video->sem); + + if( ! video_card_initialized(video) ) { + res = do_dv1394_init_default(video); + if(res) + goto err; + } + + /* region must be page-aligned */ + if(vma->vm_pgoff != 0) + goto err; + + /* check the size the user is trying to map */ + size = vma->vm_end - vma->vm_start; + if(size > video->user_buf_size) + goto err; + + /* + we don't actually mess with the page tables here. + (nopage() takes care of that from the page fault handler) + Just set up the vma->vm_ops. + */ + + vma->vm_ops = &dv1394_vm_ops; + vma->vm_private_data = video; + vma->vm_file = file; + + /* don't try to swap this out =) */ + vma->vm_flags |= VM_RESERVED; + + up(&video->sem); + return 0; + err: + up(&video->sem); + return res; +} + + +/*** DEVICE FILE INTERFACE *************************************************/ + +/* no need to serialize, multiple threads OK */ +static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait) +{ + struct video_card *video = file_to_video_card(file); + unsigned int mask = 0; + unsigned long flags; + + poll_wait(file, &video->waitq, wait); + + spin_lock_irqsave(&video->spinlock, flags); + if( video->n_frames == 0 ) { + + } else if( video->active_frame == -1 ) { + /* nothing going on */ + mask |= POLLOUT; + } else { + /* any clear/ready buffers? */ + if(video->n_clear_frames >0) + mask |= POLLOUT | POLLIN; + } + spin_unlock_irqrestore(&video->spinlock, flags); + + return mask; +} + +static int dv1394_fasync(int fd, struct file *file, int on) +{ + /* I just copied this code verbatim from Alan Cox's mouse driver example + (linux/Documentation/DocBook/) */ + + struct video_card *video = file_to_video_card(file); + + int retval = fasync_helper(fd, file, on, &video->fasync); + + if (retval < 0) + return retval; + return 0; +} + +static ssize_t dv1394_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct video_card *video = file_to_video_card(file); + DECLARE_WAITQUEUE(wait, current); + ssize_t ret; + size_t cnt; + unsigned long flags; + int target_frame; + + /* serialize this to prevent multi-threaded mayhem */ + if(file->f_flags & O_NONBLOCK) { + if(down_trylock(&video->sem)) + return -EAGAIN; + } else { + if(down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + if( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if(ret) { + up(&video->sem); + return ret; + } + } + + ret = 0; + add_wait_queue(&video->waitq, &wait); + + while(count > 0) { + + /* must set TASK_INTERRUPTIBLE *before* checking for free + buffers; otherwise we could miss a wakeup if the interrupt + fires between the check and the schedule() */ + + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + target_frame = video->first_clear_frame; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if(video->frames[target_frame]->state == FRAME_CLEAR) { + + /* how much room is left in the target frame buffer */ + cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); + + } else { + /* buffer is already used */ + cnt = 0; + } + + if(cnt > count) + cnt = count; + + if (cnt <= 0) { + /* no room left, gotta wait */ + if(file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + + schedule(); + + continue; /* start over from 'while(count > 0)...' */ + } + + if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) { + if(!ret) + ret = -EFAULT; + break; + } + + video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) + frame_prepare(video, target_frame); + } + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + up(&video->sem); + return ret; +} + + +static ssize_t dv1394_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct video_card *video = file_to_video_card(file); + DECLARE_WAITQUEUE(wait, current); + ssize_t ret; + size_t cnt; + unsigned long flags; + int target_frame; + + /* serialize this to prevent multi-threaded mayhem */ + if(file->f_flags & O_NONBLOCK) { + if(down_trylock(&video->sem)) + return -EAGAIN; + } else { + if(down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + if( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if(ret) { + up(&video->sem); + return ret; + } + receive_packets(video, video->frames[video->first_clear_frame]); + } + + ret = 0; + add_wait_queue(&video->waitq, &wait); + + while(count > 0) { + + /* must set TASK_INTERRUPTIBLE *before* checking for free + buffers; otherwise we could miss a wakeup if the interrupt + fires between the check and the schedule() */ + + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + target_frame = video->first_clear_frame; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if(target_frame >= 0 && + video->n_clear_frames > 0 && + video->frames[target_frame]->state == FRAME_CLEAR) { + + /* how much room is left in the target frame buffer */ + cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); + + } else { + /* buffer is already used */ + cnt = 0; + } + + if(cnt > count) + cnt = count; + + if (cnt <= 0) { + /* no room left, gotta wait */ + if(file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + + schedule(); + + continue; /* start over from 'while(count > 0)...' */ + } + + if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) { + if(!ret) + ret = -EFAULT; + break; + } + + video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) { + spin_lock_irqsave(&video->spinlock, flags); + video->n_clear_frames--; + video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; + spin_unlock_irqrestore(&video->spinlock, flags); + } + } + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + up(&video->sem); + return ret; +} + + +/*** DEVICE IOCTL INTERFACE ************************************************/ + +/* I *think* the VFS serializes ioctl() for us, so we don't have to worry + about situations like having two threads in here at once... */ + +static int dv1394_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_card *video = file_to_video_card(file); + unsigned long flags; + int ret = -EINVAL; + + DECLARE_WAITQUEUE(wait, current); + + /* serialize this to prevent multi-threaded mayhem */ + if(file->f_flags & O_NONBLOCK) { + if(down_trylock(&video->sem)) + return -EAGAIN; + } else { + if(down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + switch(cmd) + { + case DV1394_SUBMIT_FRAMES: { + unsigned int n_submit; + + if( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if(ret) + goto out; + } + + n_submit = (unsigned int) arg; + + if(n_submit > video->n_frames) { + ret = -EINVAL; + goto out; + } + + while(n_submit > 0) { + + add_wait_queue(&video->waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + /* wait until video->first_clear_frame is really CLEAR */ + while(video->frames[video->first_clear_frame]->state != FRAME_CLEAR) { + + spin_unlock_irqrestore(&video->spinlock, flags); + + if(signal_pending(current)) { + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = -EINTR; + goto out; + } + + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + } + spin_unlock_irqrestore(&video->spinlock, flags); + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + + frame_prepare(video, video->first_clear_frame); + + n_submit--; + } + + ret = 0; + break; + } + + case DV1394_WAIT_FRAMES: { + unsigned int n_wait; + + if( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + n_wait = (unsigned int) arg; + + /* since we re-run the last frame on underflow, we will + never actually have n_frames clear frames; at most only + n_frames - 1 */ + + if(n_wait > (video->n_frames-1) ) { + ret = -EINVAL; + goto out; + } + + add_wait_queue(&video->waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + while(video->n_clear_frames < n_wait) { + + spin_unlock_irqrestore(&video->spinlock, flags); + + if(signal_pending(current)) { + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = -EINTR; + goto out; + } + + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + } + + spin_unlock_irqrestore(&video->spinlock, flags); + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = 0; + break; + } + + case DV1394_RECEIVE_FRAMES: { + unsigned int n_recv; + + if( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + n_recv = (unsigned int) arg; + + /* at least one frame must be active */ + if(n_recv > (video->n_frames-1) ) { + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&video->spinlock, flags); + + /* release the clear frames */ + video->n_clear_frames -= n_recv; + + /* advance the clear frame cursor */ + video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames; + + /* reset dropped_frames */ + video->dropped_frames = 0; + + spin_unlock_irqrestore(&video->spinlock, flags); + + ret = 0; + break; + } + + case DV1394_START_RECEIVE: { + + if( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if(ret) + goto out; + } + + receive_packets(video, video->frames[video->first_clear_frame]); + + ret = 0; + break; + } + + case DV1394_INIT: { + struct dv1394_init init; + if(arg == (unsigned long) NULL) { + ret = do_dv1394_init_default(video); + } else { + if(copy_from_user(&init, (void*)arg, sizeof(init))) { + ret = -EFAULT; + goto out; + } + ret = do_dv1394_init(video, &init); + } + break; + } + + case DV1394_SHUTDOWN: + ret = do_dv1394_shutdown(video, 0); + break; + + + case DV1394_GET_STATUS: { + struct dv1394_status status; + + if( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + status.init.api_version = DV1394_API_VERSION; + status.init.channel = video->channel; + status.init.n_frames = video->n_frames; + status.init.format = video->pal_or_ntsc; + status.init.cip_n = video->cip_n; + status.init.cip_d = video->cip_d; + status.init.syt_offset = video->syt_offset; + + status.first_clear_frame = video->first_clear_frame; + + /* the rest of the fields need to be locked against the interrupt */ + spin_lock_irqsave(&video->spinlock, flags); + + status.active_frame = video->active_frame; + status.n_clear_frames = video->n_clear_frames; + + status.dropped_frames = video->dropped_frames; + + /* reset dropped_frames */ + video->dropped_frames = 0; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if(copy_to_user((void*)arg, &status, sizeof(status))) { + ret = -EFAULT; + goto out; + } + + ret = 0; + break; + } + + default: + break; + } + + out: + up(&video->sem); + return ret; +} + + + +/*** DEVICE FILE INTERFACE CONTINUED ***************************************/ + +static int dv1394_open(struct inode *inode, struct file *file) +{ + struct video_card *video = NULL; + + /* if the device was opened through devfs, then file->private_data + has already been set to video by devfs */ + if(file->private_data) { + video = (struct video_card*) file->private_data; + + } else { + /* look up the card by ID */ + + struct list_head *lh; + unsigned long flags; + + spin_lock_irqsave(&dv1394_cards_lock, flags); + if(!list_empty(&dv1394_cards)) { + struct video_card *p; + list_for_each(lh, &dv1394_cards) { + p = list_entry(lh, struct video_card, list); + if((p->id >> 2) == ieee1394_file_to_instance(file)) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + if(!video) { + debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file)); + return -ENODEV; + } + + file->private_data = (void*) video; + } + +#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN + + if( test_and_set_bit(0, &video->open) ) { + /* video is already open by someone else */ + return -EBUSY; + } + +#endif + + return 0; +} + + +static int dv1394_release(struct inode *inode, struct file *file) +{ + struct video_card *video = file_to_video_card(file); + + /* OK to free the DMA buffer, no more mappings can exist */ + do_dv1394_shutdown(video, 1); + + /* clean up async I/O users */ + dv1394_fasync(-1, file, 0); + + /* give someone else a turn */ + clear_bit(0, &video->open); + + return 0; +} + + +/*** PROC_FS INTERFACE ******************************************************/ +#ifdef CONFIG_PROC_FS +static LIST_HEAD(dv1394_procfs); +struct dv1394_procfs_entry { + struct list_head list; + struct proc_dir_entry *procfs; + char name[32]; + struct dv1394_procfs_entry *parent; +}; +static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED; + +static int dv1394_procfs_read( char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct video_card *video = (struct video_card*) data; + + snprintf( page, count, + "\ +format=%s\n\ +channel=%d\n\ +cip_n=%lu\n\ +cip_d=%lu\n\ +syt_offset=%u\n", + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), + video->channel, + video->cip_n, video->cip_d, video->syt_offset ); + return strlen(page); +} + +/* lifted from the stallion.c driver */ +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) +static unsigned long atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +static int dv1394_procfs_write( struct file *file, + const char *buffer, unsigned long count, void *data) +{ + int len = 0; + char new_value[64]; + char *pos; + struct video_card *video = (struct video_card*) data; + + if (count > 64) + len = 64; + else + len = count; + + if (copy_from_user( new_value, buffer, len)) + return -EFAULT; + + pos = strchr(new_value, '='); + if (pos != NULL) { + int val_len = len - (pos-new_value) - 1; + char buf[64]; + memset(buf, 0, 64); + strncpy(buf, pos+1, val_len); + if (buf[val_len-1] == '\n') buf[val_len-1] = 0; + + if (strnicmp( new_value, "format", (pos-new_value)) == 0) { + if (strnicmp( buf, "NTSC", val_len) == 0) + video->pal_or_ntsc = DV1394_NTSC; + else if (strnicmp( buf, "PAL", val_len) == 0) + video->pal_or_ntsc = DV1394_PAL; + + } else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) { + video->cip_n = atol(buf); + } else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) { + video->cip_d = atol(buf); + } else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) { + video->syt_offset = atol(buf); + } else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) { + video->channel = atol(buf); + } + } + + return len; +} + +struct dv1394_procfs_entry * +dv1394_procfs_find( char *name) +{ + struct list_head *lh; + struct dv1394_procfs_entry *p; + + spin_lock( &dv1394_procfs_lock); + if(!list_empty(&dv1394_procfs)) { + list_for_each(lh, &dv1394_procfs) { + p = list_entry(lh, struct dv1394_procfs_entry, list); + if(!strncmp(p->name, name, sizeof(p->name))) { + spin_unlock( &dv1394_procfs_lock); + return p; + } + } + } + spin_unlock( &dv1394_procfs_lock); + return NULL; +} + +static int dv1394_procfs_add_entry(struct video_card *video) +{ + char buf[32]; + struct dv1394_procfs_entry *p; + struct dv1394_procfs_entry *parent; + + p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_procfs_entry)); + + snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); + + parent = dv1394_procfs_find(buf); + if (parent == NULL) { + printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf); + goto err_free; + } + + p->procfs = create_proc_entry( + (video->mode == MODE_RECEIVE ? "in" : "out"), + 0666, parent->procfs); + + if (p->procfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n", + parent->name, + (video->mode == MODE_RECEIVE ? "in" : "out")); + goto err_free; + } + + p->procfs->owner = THIS_MODULE; + p->procfs->data = video; + p->procfs->read_proc = dv1394_procfs_read; + p->procfs->write_proc = dv1394_procfs_write; + + spin_lock( &dv1394_procfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_procfs); + spin_unlock( &dv1394_procfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +static int +dv1394_procfs_add_dir( char *name, + struct dv1394_procfs_entry *parent, + struct dv1394_procfs_entry **out) +{ + struct dv1394_procfs_entry *p; + + p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_procfs_entry)); + + if (parent == NULL) { + snprintf(p->name, sizeof(p->name), "%s", name); + p->procfs = proc_mkdir( name, ieee1394_procfs_entry); + } else { + snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); + p->procfs = proc_mkdir( name, parent->procfs); + } + if (p->procfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name); + goto err_free; + } + + p->procfs->owner = THIS_MODULE; + p->parent = parent; + if (out != NULL) *out = p; + + spin_lock( &dv1394_procfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_procfs); + spin_unlock( &dv1394_procfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +void dv1394_procfs_del( char *name) +{ + struct dv1394_procfs_entry *p = dv1394_procfs_find(name); + if (p != NULL) { + if (p->parent == NULL) + remove_proc_entry(p->name, ieee1394_procfs_entry); + else + remove_proc_entry(p->name, p->parent->procfs); + + spin_lock( &dv1394_procfs_lock); + list_del(&p->list); + spin_unlock( &dv1394_procfs_lock); + kfree(p); + } +} +#endif /* CONFIG_PROC_FS */ + +/*** DEVICE DRIVER HANDLERS ************************************************/ + +static void irq_handler(int card, quadlet_t isoRecvIntEvent, + quadlet_t isoXmitIntEvent, void *data) +{ + int wake = 0; + struct video_card *video = (struct video_card*) data; + + irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n", + (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent); + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) + ); + + + if( (video->ohci_it_ctx != -1) && + (isoXmitIntEvent & (1 << video->ohci_it_ctx)) && + (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { + + struct frame *f; + unsigned int frame, i; + + spin_lock(&video->spinlock); + if(video->active_frame == -1) + frame = 0; + else + frame = video->active_frame; + + /* check all the DMA-able frames */ + for(i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) { + + irq_printk("IRQ checking frame %d...", frame); + f = video->frames[frame]; + if(f->state != FRAME_READY) { + irq_printk("clear, skipping\n"); + /* we don't own this frame */ + continue; + } + + irq_printk("DMA\n"); + + /* check the frame begin semaphore to see if we can free the previous frame */ + if( *(f->frame_begin_timestamp) ) { + int prev_frame; + struct frame *prev_f; + + + + /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */ + irq_printk(" BEGIN\n"); + + prev_frame = frame - 1; + if(prev_frame == -1) + prev_frame += video->n_frames; + prev_f = video->frames[prev_frame]; + + /* make sure we can actually garbage collect + this frame */ + if( (prev_f->state == FRAME_READY) && + prev_f->done && (!f->done) ) + { + frame_reset(prev_f); + video->n_clear_frames++; + wake = 1; + video->active_frame = frame; + + irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame); + } else { + irq_printk(" BEGIN - can't free yet\n"); + } + + f->done = 1; + } + + + /* see if we need to set the timestamp for the next frame */ + if( *(f->mid_frame_timestamp) ) { + struct frame *next_frame; + u32 ts_cyc, ts_off; + + *(f->mid_frame_timestamp) = 0; + + irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n", + *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF, + f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF); + + /* prepare next frame and assign timestamp */ + next_frame = video->frames[ (frame+1) % video->n_frames ]; + + if(next_frame->state == FRAME_READY) { + irq_printk(" MIDDLE - next frame is ready, good\n"); + } else { + debug_printk("dv1394: Underflow! At least one frame has been dropped.\n"); + next_frame = f; + } + + /* set the timestamp to the timestamp of the last frame sent, + plus the length of the last frame sent, plus the syt latency */ + ts_cyc = *(f->frame_begin_timestamp) & 0xF; + /* advance one frame, plus syt latency (typically 2-3) */ + ts_cyc += f->n_packets + video->syt_offset ; + + ts_off = 0; + + ts_cyc += ts_off/3072; + ts_off %= 3072; + + next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off; + if(next_frame->cip_syt1) { + next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8; + next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF; + } + if(next_frame->cip_syt2) { + next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8; + next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF; + } + + } + + /* see if the frame looped */ + if( *(f->frame_end_timestamp) ) { + + *(f->frame_end_timestamp) = 0; + + debug_printk(" END - the frame looped at least once\n"); + + video->dropped_frames++; + } + + + + } /* for(each frame) */ + + spin_unlock(&video->spinlock); + + } /* end XMIT portion */ + + /***** RECEIVE INTERRUPT and DMA ACTIVE *****/ + + else if( (video->ohci_ir_ctx != -1) && + (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { + + int sof=0; /* start-of-frame flag */ + struct frame *f; + + spin_lock(&video->spinlock); + + irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet, + video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length, + video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]); + + f = video->frames[video->active_frame]; + + /* exclude empty packet */ + if (video->packet_buffer[video->current_packet].data_length > 8) { + + /* check for start of frame */ + sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f && + video->packet_buffer[video->current_packet].data[1] == 0x07); + + if (!video->first_frame) { + if (sof) { + video->first_frame = 1; + } + + } else if (sof) { + /* close current frame */ + frame_reset(f); /* f->state = STATE_CLEAR */ + video->n_clear_frames++; + if (video->n_clear_frames > video->n_frames) { + video->n_clear_frames = video->n_frames; + video->dropped_frames++; + } + if (video->first_clear_frame == -1) + video->first_clear_frame = video->active_frame; + + /* get the next frame */ + video->active_frame = (video->active_frame + 1) % video->n_frames; + f = video->frames[video->active_frame]; + + irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n", + video->active_frame, video->n_clear_frames, video->first_clear_frame); + } + if (video->first_frame) { + if (sof) { + /* open next frame */ + f->state = FRAME_READY; + } + + /* copy to buffer */ + if (f->n_packets > (video->frame_size / 480)) { + printk(KERN_ERR "frame buffer overflow during receive\n"); + } + + /* make sure we are seeing the latest changes to packet_buffer */ + pci_dma_sync_single(video->ohci->dev, + video->packet_buffer_dma, + video->packet_buffer_size, + PCI_DMA_FROMDEVICE); + + frame_put_packet( f, &video->packet_buffer[video->current_packet]); + + } /* first_frame */ + + } /* not empty packet */ + + /* advance packet_buffer cursor */ + video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER; + + spin_unlock(&video->spinlock); + + wake = 1; /* why the hell not? */ + + } /* receive interrupt */ + + if(wake) { + + /* send SIGIO */ + + if(isoRecvIntEvent & (1)) + kill_fasync(&video->fasync, SIGIO, POLL_IN); + + if(isoXmitIntEvent & (1)) + kill_fasync(&video->fasync, SIGIO, POLL_OUT); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); + } +} + +static struct file_operations dv1394_fops= +{ + owner: THIS_MODULE, + poll: dv1394_poll, + ioctl: dv1394_ioctl, + mmap: dv1394_mmap, + open: dv1394_open, + write: dv1394_write, + read: dv1394_read, + release: dv1394_release, + fasync: dv1394_fasync, +}; + + +/*** DEVFS HELPERS *********************************************************/ + +struct dv1394_devfs_entry * +dv1394_devfs_find( char *name) +{ + struct list_head *lh; + struct dv1394_devfs_entry *p; + + spin_lock( &dv1394_devfs_lock); + if(!list_empty(&dv1394_devfs)) { + list_for_each(lh, &dv1394_devfs) { + p = list_entry(lh, struct dv1394_devfs_entry, list); + if(!strncmp(p->name, name, sizeof(p->name))) { + spin_unlock( &dv1394_devfs_lock); + return p; + } + } + } + return NULL; +} + +static int dv1394_devfs_add_entry(struct video_card *video) +{ + char buf[32]; + struct dv1394_devfs_entry *p; + struct dv1394_devfs_entry *parent; + + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); + + parent = dv1394_devfs_find(buf); + if (parent == NULL) { + printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf); + goto err_free; + } + + video->devfs_handle = devfs_register( + parent->devfs, + (video->mode == MODE_RECEIVE ? "in" : "out"), + DEVFS_FL_NONE, + IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_DV1394*16 + video->id, + S_IFCHR | S_IRUGO | S_IWUGO, + &dv1394_fops, + (void*) video); + p->devfs = video->devfs_handle; + + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n", + parent->name, + (video->mode == MODE_RECEIVE ? "in" : "out")); + goto err_free; + } + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +static int +dv1394_devfs_add_dir( char *name, + struct dv1394_devfs_entry *parent, + struct dv1394_devfs_entry **out) +{ + struct dv1394_devfs_entry *p; + + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + if (parent == NULL) { + snprintf(p->name, sizeof(p->name), "%s", name); + p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL); + } else { + snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); + p->devfs = devfs_mk_dir(parent->devfs, name, NULL); + } + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name); + goto err_free; + } + + p->parent = parent; + if (out != NULL) *out = p; + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +void dv1394_devfs_del( char *name) +{ + struct dv1394_devfs_entry *p = dv1394_devfs_find(name); + if (p != NULL) { + devfs_unregister(p->devfs); + + spin_lock( &dv1394_devfs_lock); + list_del(&p->list); + spin_unlock( &dv1394_devfs_lock); + kfree(p); + } +} + +/*** IEEE1394 HPSB CALLBACKS ***********************************************/ + +static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode) +{ + struct video_card *video; + unsigned long flags; + int i; + + video = kmalloc(sizeof(struct video_card), GFP_KERNEL); + if(!video) { + printk(KERN_ERR "dv1394: cannot allocate video_card\n"); + goto err; + } + + memset(video, 0, sizeof(struct video_card)); + + if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) { + printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n"); + goto err_free; + } + + + video->ohci = ohci; + /* lower 2 bits of id indicate which of four "plugs" + per host */ + video->id = ohci->id << 2; + + video->ohci_it_ctx = -1; + video->ohci_ir_ctx = -1; + + video->ohci_IsoXmitContextControlSet = 0; + video->ohci_IsoXmitContextControlClear = 0; + video->ohci_IsoXmitCommandPtr = 0; + + video->ohci_IsoRcvContextControlSet = 0; + video->ohci_IsoRcvContextControlClear = 0; + video->ohci_IsoRcvCommandPtr = 0; + video->ohci_IsoRcvContextMatch = 0; + + video->n_frames = 0; /* flag that video is not initialized */ + video->channel = 63; /* default to broadcast channel */ + video->active_frame = -1; + + /* initialize the following for proc_fs */ + video->pal_or_ntsc = format; + video->cip_n = 0; /* 0 = use builtin default */ + video->cip_d = 0; + video->syt_offset = 0; + video->mode = mode; + +#ifdef CONFIG_PROC_FS + if ( dv1394_procfs_add_entry(video) < 0 ) + goto err_free; +#endif + + for(i = 0; i < DV1394_MAX_FRAMES; i++) + video->frames[i] = NULL; + + video->user_buf = NULL; + video->user_buf_size = 0; + + clear_bit(0, &video->open); + spin_lock_init(&video->spinlock); + init_MUTEX(&video->sem); + init_waitqueue_head(&video->waitq); + video->fasync = NULL; + + spin_lock_irqsave(&dv1394_cards_lock, flags); + INIT_LIST_HEAD(&video->list); + list_add_tail(&video->list, &dv1394_cards); + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + if (format == DV1394_NTSC) + video->id |= mode; + else video->id |= 2 + mode; + + if (dv1394_devfs_add_entry(video) < 0) + goto err_free; + + debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id); + + return 0; + + err_free: + kfree(video); + err: + return -1; +} + +static void dv1394_un_init(struct video_card *video) +{ + char buf[32]; + + /* obviously nobody has the driver open at this point */ + do_dv1394_shutdown(video, 1); + ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video); + snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), + (video->mode == MODE_RECEIVE ? "in" : "out") + ); + dv1394_devfs_del(buf); +#ifdef CONFIG_PROC_FS + dv1394_procfs_del(buf); +#endif + list_del(&video->list); + kfree(video); +} + + +static void dv1394_remove_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + struct video_card *video = NULL; + unsigned long flags; + struct list_head *lh; + char buf[32]; + int n; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + + + /* find the corresponding video_cards */ + spin_lock_irqsave(&dv1394_cards_lock, flags); + if(!list_empty(&dv1394_cards)) { + list_for_each(lh, &dv1394_cards) { + video = list_entry(lh, struct video_card, list); + if((video->id >> 2) == ohci->id) + dv1394_un_init(video); + } + } + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + n = (video->id >> 2); + snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); + dv1394_devfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d/PAL", n); + dv1394_devfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d", n); + dv1394_devfs_del(buf); + +#ifdef CONFIG_PROC_FS + snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); + dv1394_procfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d/PAL", n); + dv1394_procfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d", n); + dv1394_procfs_del(buf); +#endif +} + +static void dv1394_add_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + char buf[16]; + struct dv1394_devfs_entry *devfs_entry; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + +#ifdef CONFIG_PROC_FS +{ + struct dv1394_procfs_entry *p; + p = dv1394_procfs_find("dv"); + if (p != NULL) { + snprintf(buf, sizeof(buf), "host%d", ohci->id); + dv1394_procfs_add_dir(buf, p, &p); + dv1394_procfs_add_dir("NTSC", p, NULL); + dv1394_procfs_add_dir("PAL", p, NULL); + } +} +#endif + + devfs_entry = dv1394_devfs_find("dv"); + if (devfs_entry != NULL) { + snprintf(buf, sizeof(buf), "host%d", ohci->id); + dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry); + dv1394_devfs_add_dir("NTSC", devfs_entry, NULL); + dv1394_devfs_add_dir("PAL", devfs_entry, NULL); + } + + dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); + dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT); + dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE); + dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT); +} + +static struct hpsb_highlevel_ops hl_ops = { + add_host: dv1394_add_host, + remove_host: dv1394_remove_host, +}; + + +/*** KERNEL MODULE HANDLERS ************************************************/ + +MODULE_AUTHOR("Dan Maas , Dan Dennedy "); +MODULE_DESCRIPTION("driver for DV input/output on OHCI board"); +MODULE_SUPPORTED_DEVICE("dv1394"); +MODULE_LICENSE("GPL"); + +static void __exit dv1394_exit_module(void) +{ + hpsb_unregister_highlevel (hl_handle); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + dv1394_devfs_del("dv"); +#ifdef CONFIG_PROC_FS + dv1394_procfs_del("dv"); +#endif +} + +static int __init dv1394_init_module(void) +{ + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394, + THIS_MODULE, &dv1394_fops)) { + printk(KERN_ERR "dv1394: unable to register character device\n"); + return -EIO; + } + + if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + return -ENOMEM; + } + +#ifdef CONFIG_PROC_FS + if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + dv1394_devfs_del("dv"); + return -ENOMEM; + } +#endif + + hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops); + if (hl_handle == NULL) { + printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + dv1394_devfs_del("dv"); +#ifdef CONFIG_PROC_FS + dv1394_procfs_del("dv"); +#endif + return -ENOMEM; + } + + return 0; +} + +module_init(dv1394_init_module); +module_exit(dv1394_exit_module); + diff -urN linux-2.4.18/drivers/ieee1394/dv1394.h linux-2.4.19-pre5/drivers/ieee1394/dv1394.h --- linux-2.4.18/drivers/ieee1394/dv1394.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/dv1394.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,277 @@ +/* + * dv1394.h - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DV_1394_H +#define _DV_1394_H + +/* This is the public user-space interface. Try not to break it. */ + +#define DV1394_API_VERSION 0x20011127 + +/* ******************** + ** ** + ** DV1394 API ** + ** ** + ******************** + + There are two methods of operating the DV1394 DV output device. + + 1) + + The simplest is an interface based on write(): simply write + full DV frames of data to the device, and they will be transmitted + as quickly as possible. The FD may be set for non-blocking I/O, + in which case you can use select() or poll() to wait for output + buffer space. + + To set the DV output parameters (e.g. whether you want NTSC or PAL + video), use the DV1394_INIT ioctl, passing in the parameters you + want in a struct dv1394_init. + + Example 1: + To play a raw .DV file: cat foo.DV > /dev/dv1394 + (cat will use write() internally) + + Example 2: + static struct dv1394_init init = { + 0x63, (broadcast channel) + 4, (four-frame ringbuffer) + DV1394_NTSC, (send NTSC video) + 0, 0 (default empty packet rate) + } + + ioctl(fd, DV1394_INIT, &init); + + while(1) { + read( , buf, DV1394_NTSC_FRAME_SIZE ); + write( , buf, DV1394_NTSC_FRAME_SIZE ); + } + + 2) + + For more control over buffering, and to avoid unnecessary copies + of the DV data, you can use the more sophisticated the mmap() interface. + First, call the DV1394_INIT ioctl to specify your parameters, + including the number of frames in the ringbuffer. Then, calling mmap() + on the dv1394 device will give you direct access to the ringbuffer + from which the DV card reads your frame data. + + The ringbuffer is simply one large, contiguous region of memory + containing two or more frames of packed DV data. Each frame of DV data + is 120000 bytes (NTSC) or 144000 bytes (PAL). + + Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES + ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl + or select()/poll() to wait until the frames are transmitted. Next, you'll + need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer + frames are clear (ready to be filled with new DV data). Finally, use + DV1394_SUBMIT_FRAMES again to send the new data to the DV output. + + + Example: here is what a four-frame ringbuffer might look like + during DV transmission: + + + frame 0 frame 1 frame 2 frame 3 + + *--------------------------------------* + | CLEAR | DV data | DV data | CLEAR | + *--------------------------------------* + + + transmission goes in this direction --->>> + + + The DV hardware is currently transmitting the data in frame 1. + Once frame 1 is finished, it will automatically transmit frame 2. + (if frame 2 finishes before frame 3 is submitted, the device + will continue to transmit frame 2, and will increase the dropped_frames + counter each time it repeats the transmission). + + + If you called DV1394_GET_STATUS at this instant, you would + receive the following values: + + n_frames = 4 + active_frame = 1 + first_clear_frame = 3 + n_clear_frames = 2 + + At this point, you should write new DV data into frame 3 and optionally + frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that + it may transmit the new frames. + +*/ + + +/* maximum number of frames in the ringbuffer */ +#define DV1394_MAX_FRAMES 32 + +/* number of *full* isochronous packets per DV frame */ +#define DV1394_NTSC_PACKETS_PER_FRAME 250 +#define DV1394_PAL_PACKETS_PER_FRAME 300 + +/* size of one frame's worth of DV data, in bytes */ +#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME) +#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME) + + +/* ioctl() commands */ + +enum { + /* I don't like using 0 as a valid ioctl() */ + DV1394_INVALID = 0, + + + /* get the driver ready to transmit video. + pass a struct dv1394_init* as the parameter (see below), + or NULL to get default parameters */ + DV1394_INIT, + + + /* stop transmitting video and free the ringbuffer */ + DV1394_SHUTDOWN, + + + /* submit N new frames to be transmitted, where + the index of the first new frame is first_clear_buffer, + and the index of the last new frame is + (first_clear_buffer + N) % n_frames */ + DV1394_SUBMIT_FRAMES, + + + /* block until N buffers are clear (pass N as the parameter) + Because we re-transmit the last frame on underrun, there + will at most be n_frames - 1 clear frames at any time */ + DV1394_WAIT_FRAMES, + + /* capture new frames that have been received, where + the index of the first new frame is first_clear_buffer, + and the index of the last new frame is + (first_clear_buffer + N) % n_frames */ + DV1394_RECEIVE_FRAMES, + + + DV1394_START_RECEIVE, + + + /* pass a struct dv1394_status* as the parameter (see below) */ + DV1394_GET_STATUS, +}; + + + +enum pal_or_ntsc { + DV1394_NTSC = 0, + DV1394_PAL +}; + + + + +/* this is the argument to DV1394_INIT */ +struct dv1394_init { + /* DV1394_API_VERSION */ + unsigned int api_version; + + /* isochronous transmission channel to use */ + unsigned int channel; + + /* number of frames in the ringbuffer. Must be at least 2 + and at most DV1394_MAX_FRAMES. */ + unsigned int n_frames; + + /* send/receive PAL or NTSC video format */ + enum pal_or_ntsc format; + + /* the following are used only for transmission */ + + /* set these to zero unless you want a + non-default empty packet rate (see below) */ + unsigned long cip_n; + unsigned long cip_d; + + /* set this to zero unless you want a + non-default SYT cycle offset (default = 3 cycles) */ + unsigned int syt_offset; +}; + +/* Q: What are cip_n and cip_d? */ + +/* + A: DV video streams do not utilize 100% of the potential bandwidth offered + by IEEE 1394 (FireWire). To achieve the correct rate of data transmission, + DV devices must periodically insert empty packets into the 1394 data stream. + Typically there is one empty packet per 14-16 data-carrying packets. + + Some DV devices will accept a wide range of empty packet rates, while others + require a precise rate. If the dv1394 driver produces empty packets at + a rate that your device does not accept, you may see ugly patterns on the + DV output, or even no output at all. + + The default empty packet insertion rate seems to work for many people; if + your DV output is stable, you can simply ignore this discussion. However, + we have exposed the empty packet rate as a parameter to support devices that + do not work with the default rate. + + The decision to insert an empty packet is made with a numerator/denominator + algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D. + You can alter the empty packet rate by passing non-zero values for cip_n + and cip_d to the INIT ioctl. + + */ + + + +struct dv1394_status { + /* this embedded init struct returns the current dv1394 + parameters in use */ + struct dv1394_init init; + + /* the ringbuffer frame that is currently being + displayed. (-1 if the device is not transmitting anything) */ + int active_frame; + + /* index of the first buffer (ahead of active_frame) that + is ready to be filled with data */ + unsigned int first_clear_frame; + + /* how many buffers, including first_clear_buffer, are + ready to be filled with data */ + unsigned int n_clear_frames; + + /* how many times the DV output has underflowed + since the last call to DV1394_GET_STATUS */ + unsigned int dropped_frames; + + /* N.B. The dropped_frames counter is only a lower bound on the actual + number of dropped frames, with the special case that if dropped_frames + is zero, then it is guaranteed that NO frames have been dropped + since the last call to DV1394_GET_STATUS. + */ +}; + + +#endif /* _DV_1394_H */ diff -urN linux-2.4.18/drivers/ieee1394/eth1394.c linux-2.4.19-pre5/drivers/ieee1394/eth1394.c --- linux-2.4.18/drivers/ieee1394/eth1394.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/eth1394.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,741 @@ +/* + * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem + * + * Copyright (C) 2001 Ben Collins + * 2000 Bonin Franck + * + * Mainly based on work by Emanuel Pirker and Andreas E. Bombe + * + * 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. + */ + +/* State of this driver: + * + * This driver intends to support RFC 2734, which describes a method for + * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver + * will ultimately support that method, but currently falls short in + * several areas. A few issues are: + * + * - Does not support send/recv over Async streams using GASP + * packet formats, as per the RFC for ARP requests. + * - Does not yet support fragmented packets. + * - Relies on hardware address being equal to the nodeid for some things. + * - Does not support multicast + * - Hardcoded address for sending packets, instead of using discovery + * (ARP, see first item) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "ieee1394_core.h" +#include "ieee1394_transactions.h" +#include "ieee1394.h" +#include "highlevel.h" +#include "eth1394.h" + +#define ETH1394_PRINT_G(level, fmt, args...) \ + printk(level ETHER1394_DRIVER_NAME": "fmt, ## args) + +#define ETH1394_PRINT(level, dev_name, fmt, args...) \ + printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args) + +#define DEBUG(fmt, args...) \ + printk(KERN_ERR fmt, ## args) + +static char version[] __devinitdata = + "eth1394.c:v0.50 15/Jul/01 Ben Collins "; + +/* Our ieee1394 highlevel driver */ +#define ETHER1394_DRIVER_NAME "ether1394" + +static kmem_cache_t *packet_task_cache; +static struct hpsb_highlevel *hl_handle = NULL; + +/* Card handling */ +static LIST_HEAD (host_info_list); +static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED; + +/* Use common.lf to determine header len */ +static int hdr_type_len[] = { + sizeof (struct eth1394_uf_hdr), + sizeof (struct eth1394_ff_hdr), + sizeof (struct eth1394_sf_hdr), + sizeof (struct eth1394_sf_hdr) +}; + +MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); +MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); + +/* Find our host_info struct for a given host pointer. Must be called + * under spinlock. */ +static inline struct host_info *find_host_info (struct hpsb_host *host) +{ + struct list_head *lh; + struct host_info *hi; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry (lh, struct host_info, list); + + if (hi->host == host) + return hi; + + lh = lh->next; + } + return NULL; +} + +/* Find the network device for our host */ +static inline struct net_device *ether1394_find_dev (struct hpsb_host *host) +{ + struct host_info *hi; + + spin_lock_irq (&host_info_lock); + hi = find_host_info (host); + spin_unlock_irq (&host_info_lock); + + if (hi == NULL) + return NULL; + + return hi->dev; +} + +/* This is called after an "ifup" */ +static int ether1394_open (struct net_device *dev) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + + /* Set the spinlock before grabbing IRQ! */ + priv->lock = SPIN_LOCK_UNLOCKED; + + netif_start_queue (dev); + return 0; +} + +/* This is called after an "ifdown" */ +static int ether1394_stop (struct net_device *dev) +{ + netif_stop_queue (dev); + return 0; +} + +/* Return statistics to the caller */ +static struct net_device_stats *ether1394_stats (struct net_device *dev) +{ + return &(((struct eth1394_priv *)dev->priv)->stats); +} + +/* What to do if we timeout. I think a host reset is probably in order, so + * that's what we do. Should we increment the stat counters too? */ +static void ether1394_tx_timeout (struct net_device *dev) +{ + ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", + ((struct eth1394_priv *)(dev->priv))->host->driver->name); + + highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host); + + netif_wake_queue (dev); +} + +/* We need to encapsulate the standard header with our own. We use the + * ethernet header's proto for our own. + * + * XXX: This is where we need to create a list of skb's for fragmented + * packets. */ +static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev, + int proto) +{ + union eth1394_hdr *hdr = + (union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]); + + hdr->common.lf = ETH1394_HDR_LF_UF; + hdr->words.word1 = htons(hdr->words.word1); + hdr->uf.ether_type = proto; + + return; +} + +/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the + * entire arphdr) is the same format as the ip1394 header, so they + * overlap. The rest needs to be munged a bit. The remainder of the + * arphdr is formatted based on hwaddr len and ipaddr len. We know what + * they'll be, so it's easy to judge. */ +static inline void ether1394_arp_to_1394arp (struct sk_buff *skb, struct net_device *dev) +{ + struct eth1394_priv *priv = + (struct eth1394_priv *)(dev->priv); + u16 phy_id = priv->host->node_id & NODE_MASK; + + unsigned char *arp_ptr = (unsigned char *)skb->data; + struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; + unsigned char arp_data[2*(dev->addr_len+4)]; + + /* Copy the main data that we need */ + arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); + + /* Extend the buffer enough for our new header */ + skb_put (skb, sizeof (struct eth1394_arp) - + (sizeof (arp_data) + sizeof (struct arphdr))); + +#define PROCESS_MEMBER(ptr,val,len) \ + memcpy (val, ptr, len); ptr += len + arp_ptr += arp1394->hw_addr_len; + PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len); + arp_ptr += arp1394->hw_addr_len; + PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len); +#undef PROCESS_MEMBER + + /* Now add our own flavor of arp header fields to the orig one */ + arp1394->hw_addr_len = IP1394_HW_ADDR_LEN; + arp1394->hw_type = __constant_htons (ARPHRD_IEEE1394); + arp1394->s_uniq_id = cpu_to_le64 (priv->eui[phy_id]); + arp1394->max_rec = priv->max_rec[phy_id]; + arp1394->sspd = priv->sspd[phy_id]; + arp1394->fifo_hi = htons (priv->fifo_hi[phy_id]); + arp1394->fifo_lo = htonl (priv->fifo_lo[phy_id]); + + return; +} + +static int ether1394_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > ETHER1394_REGION_ADDR_LEN)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static inline void ether1394_register_limits (int nodeid, unsigned char max_rec, + unsigned char sspd, u64 eui, u16 fifo_hi, + u32 fifo_lo, struct eth1394_priv *priv) +{ + int i; + + if (nodeid < 0 || nodeid >= ALL_NODES) { + ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid); + return; + } + + priv->max_rec[nodeid] = max_rec; + priv->sspd[nodeid] = sspd; + priv->fifo_hi[nodeid] = fifo_hi; + priv->fifo_lo[nodeid] = fifo_lo; + priv->eui[nodeid] = eui; + + /* 63 is used for broadcasts to all hosts. It is equal to the + * minimum of all registered nodes. A registered node is one with + * a nonzero offset. Set the values rediculously high to start. We + * know we have atleast one to change the default to. */ + sspd = 0xff; + max_rec = 0xff; + for (i = 0; i < ALL_NODES; i++) { + if (!priv->fifo_hi && !priv->fifo_lo) continue; /* Unregistered */ + if (priv->max_rec[i] < max_rec) max_rec = priv->max_rec[i]; + if (priv->sspd[i] < sspd) sspd = priv->sspd[i]; + } + + priv->max_rec[ALL_NODES] = max_rec; + priv->sspd[ALL_NODES] = sspd; + + return; +} + +static void ether1394_reset_priv (struct net_device *dev, int set_mtu) +{ + int flags; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int phy_id = priv->host->node_id & NODE_MASK; + + spin_lock_irqsave (&priv->lock, flags); + + /* Clear the speed/payload/offset tables */ + memset (priv->max_rec, 0, sizeof (priv->max_rec)); + memset (priv->sspd, 0, sizeof (priv->sspd)); + memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); + memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + + /* Register our limits now */ + ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf, + priv->host->speed_map[(phy_id << 6) + phy_id], + (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) | + be32_to_cpu(priv->host->csr.rom[4])), + ETHER1394_REGION_ADDR >> 32, + ETHER1394_REGION_ADDR & 0xffffffff, priv); + + /* We'll use our max_rec as the default mtu */ + if (set_mtu) + dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr); + + /* Set our hardware address while we're at it */ + *(nodeid_t *)dev->dev_addr = htons (priv->host->node_id); + + spin_unlock_irqrestore (&priv->lock, flags); +} + +static int ether1394_tx (struct sk_buff *skb, struct net_device *dev); + +/* This function is called by register_netdev */ +static int ether1394_init_dev (struct net_device *dev) +{ + /* Our functions */ + dev->open = ether1394_open; + dev->stop = ether1394_stop; + dev->hard_start_xmit = ether1394_tx; + dev->get_stats = ether1394_stats; + dev->tx_timeout = ether1394_tx_timeout; + dev->change_mtu = ether1394_change_mtu; + + /* Some constants */ + dev->watchdog_timeo = ETHER1394_TIMEOUT; + dev->flags = IFF_BROADCAST; /* TODO: Support MCAP */ + dev->features = NETIF_F_NO_CSUM|NETIF_F_SG|NETIF_F_HIGHDMA|NETIF_F_FRAGLIST; + dev->addr_len = 2; + + ether1394_reset_priv (dev, 1); + + return 0; +} + +/* + * This function is called every time a card is found. It is generally called + * when the module is installed. This is where we add all of our ethernet + * devices. One for each host. + */ +static void ether1394_add_host (struct hpsb_host *host) +{ + struct host_info *hi = NULL; + struct net_device *dev = NULL; + struct eth1394_priv *priv; + static int version_printed = 0; + + if (version_printed++ == 0) + ETH1394_PRINT_G (KERN_INFO, "%s\n", version); + + dev = alloc_etherdev(sizeof (struct eth1394_priv)); + + if (dev == NULL) + goto out; + + SET_MODULE_OWNER(dev); + + dev->init = ether1394_init_dev; + + priv = (struct eth1394_priv *)dev->priv; + + priv->host = host; + + hi = (struct host_info *)kmalloc (sizeof (struct host_info), + GFP_KERNEL); + + if (hi == NULL) + goto out; + + if (register_netdev (dev)) { + ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); + kfree (dev); + return; + } + + ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n", + host->driver->name); + + INIT_LIST_HEAD (&hi->list); + hi->host = host; + hi->dev = dev; + + spin_lock_irq (&host_info_lock); + list_add_tail (&hi->list, &host_info_list); + spin_unlock_irq (&host_info_lock); + + return; + +out: + if (dev != NULL) + kfree (dev); + ETH1394_PRINT_G (KERN_ERR, "Out of memory\n"); + + return; +} + +/* Remove a card from our list */ +static void ether1394_remove_host (struct hpsb_host *host) +{ + struct host_info *hi; + + spin_lock_irq (&host_info_lock); + hi = find_host_info (host); + if (hi != NULL) { + unregister_netdev (hi->dev); + kfree (hi->dev); + list_del (&hi->list); + kfree (hi); + } + spin_unlock_irq (&host_info_lock); + + return; +} + +/* A reset has just arisen */ +static void ether1394_host_reset (struct hpsb_host *host) +{ + struct net_device *dev = ether1394_find_dev(host); + + /* This can happen for hosts that we don't use */ + if (dev == NULL) + return; + + /* Reset our private host data, but not our mtu */ + netif_stop_queue (dev); + ether1394_reset_priv (dev, 0); + netif_wake_queue (dev); +} + +/* Copied from net/ethernet/eth.c */ +static inline unsigned short ether1394_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + + skb->mac.raw = skb->data; + skb_pull (skb, ETH_HLEN); + eth = skb->mac.ethernet; +#if 0 + if(*eth->h_dest & 1) { + if(memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } else { + if(memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) + skb->pkt_type = PACKET_OTHERHOST; + } +#endif + if (ntohs (eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + if (*(unsigned short *)rawp == 0xFFFF) + return htons (ETH_P_802_3); + + return htons (ETH_P_802_2); +} + +/* Parse an encapsulated IP1394 header into an ethernet frame packet. + * We also perform ARP translation here, if need be. */ +static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct net_device *dev, + nodeid_t srcid, nodeid_t destid) +{ + union eth1394_hdr *hdr = (union eth1394_hdr *)skb->data; + unsigned char src_hw[ETH_ALEN], dest_hw[ETH_ALEN]; + unsigned short ret = 0; + + /* Setup our hw addresses. We use these to build the + * ethernet header. */ + *(u16 *)dest_hw = htons(destid); + *(u16 *)src_hw = htons(srcid); + + /* Remove the encapsulation header */ + hdr->words.word1 = ntohs(hdr->words.word1); + skb_pull (skb, hdr_type_len[hdr->common.lf]); + + /* If this is an ARP packet, convert it. First, we want to make + * use of some of the fields, since they tell us a little bit + * about the sending machine. */ + if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) { + int flags; + u16 phy_id = srcid & NODE_MASK; + struct eth1394_priv *priv = + (struct eth1394_priv *)dev->priv; + struct eth1394_arp arp1394; + struct arphdr *arp = (struct arphdr *)skb->data; + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + + memcpy (&arp1394, arp, sizeof (struct eth1394_arp)); + + /* Update our speed/payload/fifo_offset table */ + spin_lock_irqsave (&priv->lock, flags); + ether1394_register_limits (phy_id, arp1394.max_rec, arp1394.sspd, + le64_to_cpu (arp1394.s_uniq_id), + ntohs (arp1394.fifo_hi), + ntohl (arp1394.fifo_lo), priv); + spin_unlock_irqrestore (&priv->lock, flags); + +#define PROCESS_MEMBER(ptr,val,len) \ + ptr = memcpy (ptr, val, len) + len + PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len); + PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4); + PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len); + PROCESS_MEMBER (arp_ptr, &arp1394.tip, 4); +#undef PROCESS_MEMBER + + arp->ar_hln = dev->addr_len; + arp->ar_hrd = __constant_htons (ARPHRD_ETHER); + + skb_trim (skb, sizeof (struct arphdr) + 2*(dev->addr_len+4)); + } + + /* Now add the ethernet header. */ + if (dev->hard_header (skb, dev, __constant_ntohs (hdr->uf.ether_type), + dest_hw, src_hw, skb->len) >= 0) + ret = ether1394_type_trans(skb, dev); + + return ret; +} + +/* Packet reception. We convert the IP1394 encapsulation header to an + * ethernet header, and fill it with some of our other fields. This is + * an incoming packet from the 1394 bus. */ +static int ether1394_write (struct hpsb_host *host, int srcid, int destid, + quadlet_t *data, u64 addr, unsigned int len) +{ + struct sk_buff *skb; + char *buf = (char *)data; + int flags; + struct net_device *dev = ether1394_find_dev (host); + struct eth1394_priv *priv; + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n", + host); + return RCODE_ADDRESS_ERROR; + } + + priv = (struct eth1394_priv *)dev->priv; + + /* A packet has been received by the ieee1394 bus. Build an skbuff + * around it so we can pass it to the high level network layer. */ + + skb = dev_alloc_skb (len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + return RCODE_ADDRESS_ERROR; + } + + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + + memcpy (skb_put (skb, len), buf, len); + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, aswell as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. */ + skb->protocol = ether1394_parse_encap (skb, dev, srcid, destid); + + spin_lock_irqsave (&priv->lock, flags); + if (!skb->protocol) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto bad_proto; + } + + netif_stop_queue(dev); + if (netif_rx (skb) == NET_RX_DROP) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + goto bad_proto; + } + + /* Statistics */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + +bad_proto: + netif_start_queue(dev); + spin_unlock_irqrestore (&priv->lock, flags); + + dev->last_rx = jiffies; + + return RCODE_COMPLETE; +} + +/* This function is our scheduled write */ +static void hpsb_write_sched (void *__ptask) +{ + struct packet_task *ptask = (struct packet_task *)__ptask; + struct sk_buff *skb = ptask->skb; + struct net_device *dev = ptask->skb->dev; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int flags; + + /* Statistics */ + spin_lock_irqsave (&priv->lock, flags); + if (!hpsb_write(priv->host, ptask->dest_node, + get_hpsb_generation(priv->host), + ptask->addr, (quadlet_t *)skb->data, skb->len)) { + priv->stats.tx_bytes += skb->len; + priv->stats.tx_packets++; + } else { + //printk("Failed in hpsb_write_sched\n"); + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + if (netif_queue_stopped (dev)) + netif_wake_queue (dev); + } + spin_unlock_irqrestore (&priv->lock, flags); + + dev->trans_start = jiffies; + dev_kfree_skb(skb); + kmem_cache_free(packet_task_cache, ptask); + + return; +} + +/* Transmit a packet (called by kernel) */ +static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) +{ + int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; + struct ethhdr *eth; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int proto, flags; + nodeid_t dest_node; + u64 addr; + struct packet_task *ptask = NULL; + int ret = 0; + + if ((skb = skb_share_check (skb, kmflags)) == NULL) { + ret = -ENOMEM; + goto fail; + } + + /* Get rid of the ethernet header, but save a pointer */ + eth = (struct ethhdr *)skb->data; + skb_pull (skb, ETH_HLEN); + + /* Save the destination id, and proto for our encapsulation, then + * toss the ethernet header aside like the cheap whore it is. */ + dest_node = ntohs (*(nodeid_t *)(eth->h_dest)); + proto = eth->h_proto; + + /* If this is an ARP packet, convert it */ + if (proto == __constant_htons (ETH_P_ARP)) + ether1394_arp_to_1394arp (skb, dev); + + /* Now add our encapsulation header */ + ether1394_encapsulate (skb, dev, proto); + + /* TODO: The above encapsulate function needs to recognize when a + * packet needs to be split for a specified node. It should create + * a list of skb's that we could then iterate over for the below + * call to schedule our writes. */ + + /* XXX: Right now we accept that we don't exactly follow RFC. When + * we do, we will send ARP requests via GASP format, and so we wont + * need this hack. */ + + spin_lock_irqsave (&priv->lock, flags); + addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 | + priv->fifo_lo[dest_node & NODE_MASK]; + spin_unlock_irqrestore (&priv->lock, flags); + + if (!addr) + addr = ETHER1394_REGION_ADDR; + + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; + goto fail; + } + + ptask->skb = skb; + ptask->addr = addr; + ptask->dest_node = dest_node; + INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask); + schedule_task(&ptask->tq); + + return 0; +fail: + printk("Failed in ether1394_tx\n"); + + if (skb != NULL) + dev_kfree_skb (skb); + + spin_lock_irqsave (&priv->lock, flags); + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + if (netif_queue_stopped (dev)) + netif_wake_queue (dev); + spin_unlock_irqrestore (&priv->lock, flags); + + return ret; +} + +/* Function for incoming 1394 packets */ +static struct hpsb_address_ops addr_ops = { + write: ether1394_write, +}; + +/* Ieee1394 highlevel driver functions */ +static struct hpsb_highlevel_ops hl_ops = { + add_host: ether1394_add_host, + remove_host: ether1394_remove_host, + host_reset: ether1394_host_reset, +}; + +static int __init ether1394_init_module (void) +{ + packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), + 0, 0, NULL, NULL); + + /* Register ourselves as a highlevel driver */ + hl_handle = hpsb_register_highlevel (ETHER1394_DRIVER_NAME, &hl_ops); + + if (hl_handle == NULL) { + ETH1394_PRINT_G (KERN_ERR, "No more memory for driver\n"); + return -ENOMEM; + } + + hpsb_register_addrspace (hl_handle, &addr_ops, ETHER1394_REGION_ADDR, + ETHER1394_REGION_ADDR_END); + + return 0; +} + +static void __exit ether1394_exit_module (void) +{ + hpsb_unregister_highlevel (hl_handle); + kmem_cache_destroy(packet_task_cache); +} + +module_init(ether1394_init_module); +module_exit(ether1394_exit_module); diff -urN linux-2.4.18/drivers/ieee1394/eth1394.h linux-2.4.19-pre5/drivers/ieee1394/eth1394.h --- linux-2.4.18/drivers/ieee1394/eth1394.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/ieee1394/eth1394.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,190 @@ +/* + * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem + * + * Copyright (C) 2000 Bonin Franck + * (C) 2001 Ben Collins + * + * Mainly based on work by Emanuel Pirker and Andreas E. Bombe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ETH1394_H +#define __ETH1394_H + +/* Register for incoming packets. This is 8192 bytes, which supports up to + * 1600mbs. We'll need to change this if that ever becomes "small" :) */ +#define ETHER1394_REGION_ADDR_LEN 8192 +#define ETHER1394_REGION_ADDR 0xfffff0200000ULL +#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN) + +/* Node set == 64 */ +#define NODE_SET (ALL_NODES + 1) + +/* Private structure for our ethernet driver */ +struct eth1394_priv { + struct net_device_stats stats; /* Device stats */ + struct hpsb_host *host; /* The card for this dev */ + unsigned char max_rec[NODE_SET];/* Max payload per node */ + unsigned char sspd[NODE_SET]; /* Max speed per node */ + u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */ + u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */ + u64 eui[ALL_NODES]; /* EUI-64 per node */ + spinlock_t lock; /* Private lock */ +}; + +struct host_info { + struct list_head list; + struct hpsb_host *host; + struct net_device *dev; +}; + +/* This is our task struct. It's used for the complete_tq callback. */ +struct packet_task { + struct sk_buff *skb; /* Socket buffer we are sending */ + nodeid_t dest_node; /* Destination of the packet */ + u64 addr; /* Address */ + struct tq_struct tq; /* The task */ +}; + +/* IP1394 headers */ +#include + +/* Unfragmented */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_uf_hdr { + u8 lf:2; + u16 res:14; + u16 ether_type; /* Ethernet packet type */ +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_uf_hdr { + u16 res:14; + u8 lf:2; + u16 ether_type; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +/* First fragment */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_ff_hdr { + u8 lf:2; + u8 res1:2; + u16 dg_size:12; /* Datagram size */ + u16 ether_type; /* Ethernet packet type */ + u16 dgl; /* Datagram label */ + u16 res2; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_ff_hdr { + u16 dg_size:12; + u8 res1:2; + u8 lf:2; + u16 ether_type; + u16 dgl; + u16 res2; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +/* XXX: Subsequent fragments, including last */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_sf_hdr { + u8 lf:2; + u8 res1:2; + u16 dg_size:12; /* Datagram size */ + u8 res2:6; + u16 fg_off:10; /* Fragment offset */ + u16 dgl; /* Datagram label */ + u16 res3; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_sf_hdr { + u16 dg_size:12; + u8 res1:2; + u8 lf:2; + u16 fg_off:10; + u8 res2:6; + u16 dgl; + u16 res3; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_common_hdr { + u8 lf:2; + u16 pad1:14; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_common_hdr { + u16 pad1:14; + u8 lf:2; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +struct eth1394_hdr_words { + u16 word1; + u16 word2; + u16 word3; + u16 word4; +}; + +union eth1394_hdr { + struct eth1394_common_hdr common; + struct eth1394_uf_hdr uf; + struct eth1394_ff_hdr ff; + struct eth1394_sf_hdr sf; + struct eth1394_hdr_words words; +}; + +/* End of IP1394 headers */ + +/* Fragment types */ +#define ETH1394_HDR_LF_UF 0 /* unfragmented */ +#define ETH1394_HDR_LF_FF 1 /* first fragment */ +#define ETH1394_HDR_LF_LF 2 /* last fragment */ +#define ETH1394_HDR_LF_IF 3 /* interior fragment */ + +#define IP1394_HW_ADDR_LEN 16 /* As per RFC */ + +/* Our arp packet (ARPHRD_IEEE1394) */ +struct eth1394_arp { + u16 hw_type; /* 0x0018 */ + u16 proto_type; /* 0x0806 */ + u8 hw_addr_len; /* 16 */ + u8 ip_addr_len; /* 4 */ + u16 opcode; /* ARP Opcode */ + /* Above is exactly the same format as struct arphdr */ + + u64 s_uniq_id; /* Sender's 64bit EUI */ + u8 max_rec; /* Sender's max packet size */ + u8 sspd; /* Sender's max speed */ + u16 fifo_hi; /* hi 16bits of sender's FIFO addr */ + u32 fifo_lo; /* lo 32bits of sender's FIFO addr */ + u32 sip; /* Sender's IP Address */ + u32 tip; /* IP Address of requested hw addr */ +}; + +/* Network timeout */ +#define ETHER1394_TIMEOUT 100000 + +#endif /* __ETH1394_H */ diff -urN linux-2.4.18/drivers/ieee1394/highlevel.c linux-2.4.19-pre5/drivers/ieee1394/highlevel.c --- linux-2.4.18/drivers/ieee1394/highlevel.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/highlevel.c Sat Mar 30 22:55:39 2002 @@ -44,10 +44,11 @@ hl->op = ops; write_lock_irq(&hl_drivers_lock); - hl_all_hosts(hl, 1); list_add_tail(&hl->hl_list, &hl_drivers); write_unlock_irq(&hl_drivers_lock); + hl_all_hosts(hl->op->add_host); + return hl; } @@ -73,9 +74,11 @@ write_lock_irq(&hl_drivers_lock); list_del(&hl->hl_list); - hl_all_hosts(hl, 0); write_unlock_irq(&hl_drivers_lock); + if (hl->op->remove_host) + hl_all_hosts(hl->op->remove_host); + kfree(hl); } @@ -87,7 +90,7 @@ int retval = 0; if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) { - HPSB_ERR(__FUNCTION__ " called with invalid addresses"); + HPSB_ERR("%s called with invalid addresses", __FUNCTION__); return 0; } @@ -131,12 +134,12 @@ unsigned int channel) { if (channel > 63) { - HPSB_ERR(__FUNCTION__ " called with invalid channel"); + HPSB_ERR("%s called with invalid channel", __FUNCTION__); return; } if (host->iso_listen_count[channel]++ == 0) { - host->template->devctl(host, ISO_LISTEN_CHANNEL, channel); + host->ops->devctl(host, ISO_LISTEN_CHANNEL, channel); } } @@ -144,46 +147,58 @@ unsigned int channel) { if (channel > 63) { - HPSB_ERR(__FUNCTION__ " called with invalid channel"); + HPSB_ERR("%s called with invalid channel", __FUNCTION__); return; } if (--host->iso_listen_count[channel] == 0) { - host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel); + host->ops->devctl(host, ISO_UNLISTEN_CHANNEL, channel); } } -#define DEFINE_MULTIPLEXER(Function) \ -void highlevel_##Function(struct hpsb_host *host) \ -{ \ - struct list_head *lh; \ - void (*funcptr)(struct hpsb_host*); \ - read_lock(&hl_drivers_lock); \ - list_for_each(lh, &hl_drivers) { \ - funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \ - ->op->Function; \ - if (funcptr) funcptr(host); \ - } \ - read_unlock(&hl_drivers_lock); \ -} - -DEFINE_MULTIPLEXER(add_host) -DEFINE_MULTIPLEXER(remove_host) -DEFINE_MULTIPLEXER(host_reset) -#undef DEFINE_MULTIPLEXER - -/* Add one host to our list */ -void highlevel_add_one_host (struct hpsb_host *host) -{ - if (host->template->initialize_host) - if (!host->template->initialize_host(host)) - goto fail; - host->initialized = 1; - highlevel_add_host (host); - hpsb_reset_bus (host, LONG_RESET); -fail: - host->template->number_of_hosts++; +void highlevel_add_host(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + read_lock(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + + hl->op->add_host(host); + } + read_unlock(&hl_drivers_lock); +} + +void highlevel_remove_host(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + write_lock_irq(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + + if (hl->op->remove_host) + hl->op->remove_host(host); + } + write_unlock_irq(&hl_drivers_lock); +} + +void highlevel_host_reset(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + read_lock(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + + if (hl->op->host_reset) + hl->op->host_reset(host); + } + read_unlock(&hl_drivers_lock); } void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, @@ -242,12 +257,11 @@ while (as->start <= addr) { if (as->end > addr) { - partlength = MIN((unsigned int)(as->end - addr), - length); + partlength = min(as->end - addr, (u64) length); if (as->op->read != NULL) { - rcode = as->op->read(host, nodeid, buffer, addr, - partlength); + rcode = as->op->read(host, nodeid, buffer, + addr, partlength); } else { rcode = RCODE_TYPE_ERROR; } @@ -288,12 +302,11 @@ while (as->start <= addr) { if (as->end > addr) { - partlength = MIN((unsigned int)(as->end - addr), - length); + partlength = min(as->end - addr, (u64) length); if (as->op->write != NULL) { - rcode = as->op->write(host, nodeid, destid, data, - addr, partlength); + rcode = as->op->write(host, nodeid, destid, + data, addr, partlength); } else { rcode = RCODE_TYPE_ERROR; } diff -urN linux-2.4.18/drivers/ieee1394/highlevel.h linux-2.4.19-pre5/drivers/ieee1394/highlevel.h --- linux-2.4.18/drivers/ieee1394/highlevel.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/highlevel.h Sat Mar 30 22:55:39 2002 @@ -91,7 +91,6 @@ void init_hpsb_highlevel(void); void highlevel_add_host(struct hpsb_host *host); -void highlevel_add_one_host(struct hpsb_host *host); void highlevel_remove_host(struct hpsb_host *host); void highlevel_host_reset(struct hpsb_host *host); diff -urN linux-2.4.18/drivers/ieee1394/hosts.c linux-2.4.19-pre5/drivers/ieee1394/hosts.c --- linux-2.4.18/drivers/ieee1394/hosts.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/hosts.c Sat Mar 30 22:55:39 2002 @@ -11,101 +11,125 @@ */ #include - #include +#include #include -#include -#include +#include #include "ieee1394_types.h" #include "hosts.h" #include "ieee1394_core.h" #include "highlevel.h" +static struct list_head hosts = LIST_HEAD_INIT(hosts); +static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers); -static LIST_HEAD(templates); -static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; - -/* - * This function calls the add_host/remove_host hooks for every host currently - * registered. Init == TRUE means add_host. - */ -void hl_all_hosts(struct hpsb_highlevel *hl, int init) -{ - struct list_head *tlh, *hlh; - struct hpsb_host_template *tmpl; - struct hpsb_host *host; +spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED; +spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED; - spin_lock(&templates_lock); - list_for_each(tlh, &templates) { - tmpl = list_entry(tlh, struct hpsb_host_template, list); - list_for_each(hlh, &tmpl->hosts) { - host = list_entry(hlh, struct hpsb_host, list); - if (host->initialized) { - if (init) { - if (hl->op->add_host) { - hl->op->add_host(host); - } - } else { - if (hl->op->remove_host) { - hl->op->remove_host(host); - } - } - } - } - } +static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p) +{ + return 0; +} - spin_unlock(&templates_lock); +static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg) +{ + return -1; } -int hpsb_inc_host_usage(struct hpsb_host *host) +static struct hpsb_host_operations dummy_ops = { + transmit_packet: dummy_transmit_packet, + devctl: dummy_devctl +}; + +/** + * hpsb_ref_host - increase reference count for host controller. + * @host: the host controller + * + * Increase the reference count for the specified host controller. + * When holding a reference to a host, the memory allocated for the + * host struct will not be freed and the host is guaranteed to be in a + * consistent state. The driver may be unloaded or the controller may + * be removed (PCMCIA), but the host struct will remain valid. + */ + +int hpsb_ref_host(struct hpsb_host *host) { - struct list_head *tlh, *hlh; - struct hpsb_host_template *tmpl; - int retval = 0; + struct list_head *lh; unsigned long flags; + int retval = 0; - spin_lock_irqsave(&templates_lock, flags); - - list_for_each(tlh, &templates) { - tmpl = list_entry(tlh, struct hpsb_host_template, list); - list_for_each(hlh, &tmpl->hosts) { - if (host == list_entry(hlh, struct hpsb_host, list)) { - tmpl->devctl(host, MODIFY_USAGE, 1); - retval = 1; - break; - } - } - if (retval) + spin_lock_irqsave(&hosts_lock, flags); + list_for_each(lh, &hosts) { + if (host == list_entry(lh, struct hpsb_host, host_list)) { + host->ops->devctl(host, MODIFY_USAGE, 1); + host->refcount++; + retval = 1; break; + } } - - spin_unlock_irqrestore(&templates_lock, flags); + spin_unlock_irqrestore(&hosts_lock, flags); return retval; } -void hpsb_dec_host_usage(struct hpsb_host *host) +/** + * hpsb_unref_host - decrease reference count for host controller. + * @host: the host controller + * + * Decrease the reference count for the specified host controller. + * When the reference count reaches zero, the memory allocated for the + * &hpsb_host will be freed. + */ + +void hpsb_unref_host(struct hpsb_host *host) { - host->template->devctl(host, MODIFY_USAGE, 0); -} + unsigned long flags; -/* - * The following function is exported for module usage. It will be called from - * the detect function of a adapter driver. + host->ops->devctl(host, MODIFY_USAGE, 0); + + spin_lock_irqsave(&hosts_lock, flags); + host->refcount--; + + if (!host->refcount && host->is_shutdown) + kfree(host); + spin_unlock_irqrestore(&hosts_lock, flags); +} + +/** + * hpsb_alloc_host - allocate a new host controller. + * @drv: the driver that will manage the host controller + * @extra: number of extra bytes to allocate for the driver + * + * Allocate a &hpsb_host and initialize the general subsystem specific + * fields. If the driver needs to store per host data, as drivers + * usually do, the amount of memory required can be specified by the + * @extra parameter. Once allocated, the driver should initialize the + * driver specific parts, enable the controller and make it available + * to the general subsystem using hpsb_add_host(). + * + * The &hpsb_host is allocated with an single initial reference + * belonging to the driver. Once the driver is done with the struct, + * for example, when the driver is unloaded, it should release this + * reference using hpsb_unref_host(). + * + * Return Value: a pointer to the &hpsb_host if succesful, %NULL if + * no memory was available. */ -struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, - size_t hd_size) + +struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra) { struct hpsb_host *h; - h = vmalloc(sizeof(struct hpsb_host) + hd_size); + h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL); if (!h) return NULL; + memset(h, 0, sizeof(struct hpsb_host)); - memset(h, 0, sizeof(struct hpsb_host) + hd_size); - - atomic_set(&h->generation, 0); + h->hostdata = h + 1; + h->driver = drv; + h->ops = drv->ops; + h->refcount = 1; INIT_LIST_HEAD(&h->pending_packets); spin_lock_init(&h->pending_pkt_lock); @@ -113,113 +137,90 @@ sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); + atomic_set(&h->generation, 0); + INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); h->topology_map = h->csr.topology_map + 3; h->speed_map = (u8 *)(h->csr.speed_map + 2); - h->template = tmpl; - if (hd_size) - h->hostdata = &h->embedded_hostdata[0]; + return h; +} + +void hpsb_add_host(struct hpsb_host *host) +{ + unsigned long flags; - list_add_tail(&h->list, &tmpl->hosts); + spin_lock_irqsave(&hosts_lock, flags); + host->driver->number_of_hosts++; + list_add_tail(&host->driver_list, &host->driver->hosts); + list_add_tail(&host->host_list, &hosts); + spin_unlock_irqrestore(&hosts_lock, flags); - return h; + highlevel_add_host(host); + host->ops->devctl(host, RESET_BUS, 0); } -static void free_all_hosts(struct hpsb_host_template *tmpl) +void hpsb_remove_host(struct hpsb_host *host) { - struct list_head *hlh, *next; - struct hpsb_host *host; + struct hpsb_host_driver *drv = host->driver; + unsigned long flags; - list_for_each_safe(hlh, next, &tmpl->hosts) { - host = list_entry(hlh, struct hpsb_host, list); - vfree(host); - } + host->is_shutdown = 1; + host->ops = &dummy_ops; + highlevel_remove_host(host); + + spin_lock_irqsave(&hosts_lock, flags); + list_del(&host->driver_list); + list_del(&host->host_list); + drv->number_of_hosts--; + spin_unlock_irqrestore(&hosts_lock, flags); } -static void init_hosts(struct hpsb_host_template *tmpl) +struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op, + const char *name) { - int count; - struct list_head *hlh; - struct hpsb_host *host; + struct hpsb_host_driver *drv; - count = tmpl->detect_hosts(tmpl); + drv = kmalloc(sizeof(struct hpsb_host_driver), SLAB_KERNEL); + if (!drv) return NULL; - list_for_each(hlh, &tmpl->hosts) { - host = list_entry(hlh, struct hpsb_host, list); - if (tmpl->initialize_host(host)) { - host->initialized = 1; - - highlevel_add_host(host); - hpsb_reset_bus(host, LONG_RESET); - } - } + INIT_LIST_HEAD(&drv->list); + INIT_LIST_HEAD(&drv->hosts); + drv->number_of_hosts = 0; + drv->name = name; + drv->ops = op; + + spin_lock(&host_drivers_lock); + list_add_tail(&drv->list, &host_drivers); + spin_unlock(&host_drivers_lock); - tmpl->number_of_hosts = count; - HPSB_INFO("detected %d %s adapter%s", count, tmpl->name, - (count != 1 ? "s" : "")); + return drv; } -static void shutdown_hosts(struct hpsb_host_template *tmpl) +void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv) { - struct list_head *hlh; - struct hpsb_host *host; - - list_for_each(hlh, &tmpl->hosts) { - host = list_entry(hlh, struct hpsb_host, list); - if (host->initialized) { - highlevel_remove_host(host); - - host->initialized = 0; - abort_requests(host); - - tmpl->release_host(host); - while (test_bit(0, &host->timeout_tq.sync)) { - schedule(); - } - } - } - free_all_hosts(tmpl); - tmpl->release_host(NULL); + spin_lock(&host_drivers_lock); + list_del(&drv->list); + spin_unlock(&host_drivers_lock); - tmpl->number_of_hosts = 0; + kfree(drv); } /* - * The following two functions are exported symbols for module usage. + * This function calls the given function for every host currently registered. */ -int hpsb_register_lowlevel(struct hpsb_host_template *tmpl) +void hl_all_hosts(void (*function)(struct hpsb_host*)) { - INIT_LIST_HEAD(&tmpl->hosts); - tmpl->number_of_hosts = 0; - - spin_lock(&templates_lock); - list_add_tail(&tmpl->list, &templates); - spin_unlock(&templates_lock); - - /* PCI cards should be smart and use the PCI detection layer, and - * not this one shot deal. detect_hosts() will be obsoleted soon. */ - if (tmpl->detect_hosts != NULL) { - HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name); - init_hosts(tmpl); - } - - return 0; -} - -void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl) -{ - shutdown_hosts(tmpl); + struct list_head *lh; + struct hpsb_host *host; - if (tmpl->number_of_hosts) - HPSB_PANIC("attempted to remove busy host template " - "of %s at address 0x%p", tmpl->name, tmpl); - else { - spin_lock(&templates_lock); - list_del(&tmpl->list); - spin_unlock(&templates_lock); + spin_lock_irq(&hosts_lock); + list_for_each (lh, &hosts) { + host = list_entry(lh, struct hpsb_host, host_list); + function(host); } + spin_unlock_irq(&hosts_lock); } diff -urN linux-2.4.18/drivers/ieee1394/hosts.h linux-2.4.19-pre5/drivers/ieee1394/hosts.h --- linux-2.4.18/drivers/ieee1394/hosts.h Sun Feb 17 11:38:52 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/hosts.h Sat Mar 30 22:55:39 2002 @@ -13,11 +13,15 @@ struct hpsb_packet; struct hpsb_host { -/* private fields (hosts, do not use them) */ - struct list_head list; + struct list_head host_list; + + struct hpsb_host_operations *ops; + void *hostdata; atomic_t generation; + int refcount; + struct list_head pending_packets; spinlock_t pending_pkt_lock; struct tq_struct timeout_tq; @@ -28,26 +32,19 @@ struct semaphore tlabel_count; spinlock_t tlabel_lock; - int reset_retries; - quadlet_t *topology_map; - u8 *speed_map; - struct csr_control csr; - unsigned char iso_listen_count[64]; -/* readonly fields for hosts */ - struct hpsb_host_template *template; - int node_count; /* number of identified nodes on this bus */ int selfid_count; /* total number of SelfIDs received */ + int nodes_active; /* number of nodes that are actually active */ nodeid_t node_id; /* node ID of this host */ nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ nodeid_t busmgr_id; /* ID of this bus' bus manager */ - unsigned initialized:1; /* initialized and usable */ - unsigned in_bus_reset:1; /* in bus reset / SelfID stage */ - unsigned attempt_root:1; /* attempt to become root during next reset */ + /* this nodes state */ + unsigned in_bus_reset:1; + unsigned is_shutdown:1; /* this nodes' duties on the bus */ unsigned is_root:1; @@ -55,11 +52,15 @@ unsigned is_irm:1; unsigned is_busmgr:1; -/* fields readable and writeable by the hosts */ + int reset_retries; + quadlet_t *topology_map; + u8 *speed_map; + struct csr_control csr; + + struct hpsb_host_driver *driver; + struct list_head driver_list; - void *hostdata; struct pci_dev *pdev; - int embedded_hostdata[0]; }; @@ -88,8 +89,10 @@ * Return void. */ CANCEL_REQUESTS, - /* Decrease module usage count if arg == 0, increase otherwise. Return - * void. */ + /* Decrease host usage count if arg == 0, increase otherwise. Return + * 1 for success, 0 for failure. Increase usage may fail if the driver + * is in the process of shutting itself down. Decrease usage can not + * fail. */ MODIFY_USAGE, /* Start or stop receiving isochronous channel in arg. Return void. @@ -109,37 +112,7 @@ SHORT_RESET }; -struct hpsb_host_template { - struct list_head list; - - struct list_head hosts; - int number_of_hosts; - - /* fields above will be ignored and overwritten after registering */ - - /* This should be the name of the driver (single word) and must not be - * NULL. */ - const char *name; - - /* This function shall detect all available adapters of this type and - * call hpsb_get_host for each one. The initialize_host function will - * be called to actually set up these adapters. The number of detected - * adapters or zero if there are none must be returned. - */ - int (*detect_hosts) (struct hpsb_host_template *template); - - /* After detecting and registering hosts, this function will be called - * for every registered host. It shall set up the host to be fully - * functional for bus operations and return 0 for failure. - */ - int (*initialize_host) (struct hpsb_host *host); - - /* To unload modules, this function is provided. It shall free all - * resources this host is using (if host is not NULL) or free all - * resources globally allocated by the driver (if host is NULL). - */ - void (*release_host) (struct hpsb_host *host); - +struct hpsb_host_operations { /* This function must store a pointer to the configuration ROM into the * location referenced to by pointer and return the size of the ROM. It * may not fail. If any allocation is required, it must be done @@ -175,34 +148,43 @@ quadlet_t data, quadlet_t compare); }; +struct hpsb_host_driver { + struct list_head list; + struct list_head hosts; -/* mid level internal use */ + int number_of_hosts; + const char *name; + + struct hpsb_host_operations *ops; +}; + + +/* core internal use */ void register_builtin_lowlevels(void); /* high level internal use */ struct hpsb_highlevel; -void hl_all_hosts(struct hpsb_highlevel *hl, int init); +void hl_all_hosts(void (*function)(struct hpsb_host*)); -/* - * These functions are for lowlevel (host) driver use. - */ -int hpsb_register_lowlevel(struct hpsb_host_template *tmpl); -void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl); /* - * Get a initialized host structure with hostdata_size bytes allocated in - * embedded_hostdata for free usage. Returns NULL for failure. + * In order to prevent hosts from unloading, use hpsb_ref_host(). This prevents + * the host from going away (e.g. makes module unloading of the driver + * impossible), but still can not guarantee it (e.g. PC-Card being pulled by the + * user). hpsb_ref_host() returns false if host could not be locked. If it is + * successful, host is valid as a pointer until hpsb_unref_host() (not just + * until after remove_host). */ -struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, - size_t hostdata_size); +int hpsb_ref_host(struct hpsb_host *host); +void hpsb_unref_host(struct hpsb_host *host); -/* - * Increase / decrease host usage counter. Increase function will return true - * only if successful (host still existed). Decrease function expects host to - * exist. - */ -int hpsb_inc_host_usage(struct hpsb_host *host); -void hpsb_dec_host_usage(struct hpsb_host *host); +struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra); +void hpsb_add_host(struct hpsb_host *host); +void hpsb_remove_host(struct hpsb_host *h); + +struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op, + const char *name); +void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv); #endif /* _IEEE1394_HOSTS_H */ diff -urN linux-2.4.18/drivers/ieee1394/ieee1394.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394.h --- linux-2.4.18/drivers/ieee1394/ieee1394.h Sun Feb 17 01:21:24 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394.h Sat Mar 30 22:55:39 2002 @@ -39,10 +39,10 @@ #define ACK_TYPE_ERROR 0xe /* Non-standard "ACK codes" for internal use */ -#define ACKX_NONE -1 -#define ACKX_SEND_ERROR -2 -#define ACKX_ABORTED -3 -#define ACKX_TIMEOUT -4 +#define ACKX_NONE (-1) +#define ACKX_SEND_ERROR (-2) +#define ACKX_ABORTED (-3) +#define ACKX_TIMEOUT (-4) #define SPEED_100 0x0 @@ -116,7 +116,7 @@ /* * Note: these mean to be bit fields of a big endian SelfID as seen on a little - * endian machine. + * endian machine. Without swapping. */ struct selfid { diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_core.c linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.c --- linux-2.4.18/drivers/ieee1394/ieee1394_core.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.c Sat Mar 30 22:55:39 2002 @@ -18,9 +18,11 @@ #include #include #include +#include #include #include #include +#include #include "ieee1394_types.h" #include "ieee1394.h" @@ -39,6 +41,10 @@ MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); static int disable_nodemgr = 0; +MODULE_PARM(disable_hotplug, "i"); +MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes."); +static int disable_hotplug = 0; + /* We are GPL, so treat us special */ MODULE_LICENSE("GPL"); @@ -106,7 +112,7 @@ packet->data_size = data_size; } - INIT_TQ_HEAD(packet->complete_tq); + INIT_LIST_HEAD(&packet->complete_tq); INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = hpsb_unused; @@ -135,12 +141,8 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) { - if (!host->initialized) { - return 1; - } - if (!host->in_bus_reset) { - host->template->devctl(host, RESET_BUS, type); + host->ops->devctl(host, RESET_BUS, type); return 0; } else { return 1; @@ -151,8 +153,8 @@ int hpsb_bus_reset(struct hpsb_host *host) { if (host->in_bus_reset) { - HPSB_NOTICE(__FUNCTION__ - " called while bus reset already in progress"); + HPSB_NOTICE("%s called while bus reset already in progress", + __FUNCTION__); return 1; } @@ -171,14 +173,16 @@ * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in * case verification failed. */ -static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids) +static int check_selfids(struct hpsb_host *host) { int nodeid = -1; - int rest_of_selfids = num_of_selfids; + int rest_of_selfids = host->selfid_count; struct selfid *sid = (struct selfid *)host->topology_map; struct ext_selfid *esid; int esid_seq = 23; + host->nodes_active = 0; + while (rest_of_selfids--) { if (!sid->extended) { nodeid++; @@ -190,9 +194,11 @@ return 0; } - if (sid->contender && sid->link_active) { - host->irm_id = LOCAL_BUS | sid->phy_id; - } + if (sid->link_active) { + host->nodes_active++; + if (sid->contender) + host->irm_id = LOCAL_BUS | sid->phy_id; + } } else { esid = (struct ext_selfid *)sid; @@ -226,7 +232,8 @@ return 0; } - return nodeid + 1; + host->node_count = nodeid + 1; + return 1; } static void build_speed_map(struct hpsb_host *host, int nodecount) @@ -318,15 +325,17 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) { + if (!host->in_bus_reset) + HPSB_NOTICE("SelfID completion called outside of bus reset!"); + host->node_id = LOCAL_BUS | phyid; - host->in_bus_reset = 0; host->is_root = isroot; - host->node_count = check_selfids(host, host->selfid_count); - if (!host->node_count) { + if (!check_selfids(host)) { if (host->reset_retries++ < 20) { /* selfid stage did not complete without error */ HPSB_NOTICE("Error in SelfID stage, resetting"); + host->in_bus_reset = 0; hpsb_reset_bus(host, LONG_RESET); return; } else { @@ -346,8 +355,9 @@ } host->reset_retries = 0; - atomic_inc(&host->generation); - if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1); + atomic_inc(&host->generation); + host->in_bus_reset = 0; highlevel_host_reset(host); } @@ -402,7 +412,7 @@ { struct hpsb_host *host = packet->host; - if (!host->initialized || host->in_bus_reset + if (host->is_shutdown || host->in_bus_reset || (packet->generation != get_hpsb_generation(host))) { return 0; } @@ -431,7 +441,7 @@ } #endif - return host->template->transmit_packet(host, packet); + return host->ops->transmit_packet(host, packet); } static void send_packet_nocare(struct hpsb_packet *packet) @@ -727,7 +737,7 @@ struct list_head *lh; LIST_HEAD(llist); - host->template->devctl(host, CANCEL_REQUESTS, 0); + host->ops->devctl(host, CANCEL_REQUESTS, 0); spin_lock_irqsave(&host->pending_pkt_lock, flags); list_splice(&host->pending_packets, &llist); @@ -786,14 +796,216 @@ } +/* + * character device dispatching (see ieee1394_core.h) + * Dan Maas + */ + +static struct { + struct file_operations *file_ops; + struct module *module; +} ieee1394_chardevs[16]; + +static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED; + +static int ieee1394_dispatch_open(struct inode *inode, struct file *file); + +static struct file_operations ieee1394_chardev_ops = { + owner: THIS_MODULE, + open: ieee1394_dispatch_open, +}; + +devfs_handle_t ieee1394_devfs_handle; + + +/* claim a block of minor numbers */ +int ieee1394_register_chardev(int blocknum, + struct module *module, + struct file_operations *file_ops) +{ + int retval; + + if( (blocknum < 0) || (blocknum > 15) ) + return -EINVAL; + + write_lock(&ieee1394_chardevs_lock); + + if(ieee1394_chardevs[blocknum].file_ops == NULL) { + /* grab the minor block */ + ieee1394_chardevs[blocknum].file_ops = file_ops; + ieee1394_chardevs[blocknum].module = module; + + retval = 0; + } else { + /* block already taken */ + retval = -EBUSY; + } + + write_unlock(&ieee1394_chardevs_lock); + + return retval; +} + +/* release a block of minor numbers */ +void ieee1394_unregister_chardev(int blocknum) +{ + if( (blocknum < 0) || (blocknum > 15) ) + return; + + write_lock(&ieee1394_chardevs_lock); + + if(ieee1394_chardevs[blocknum].file_ops) { + ieee1394_chardevs[blocknum].file_ops = NULL; + ieee1394_chardevs[blocknum].module = NULL; + } + + write_unlock(&ieee1394_chardevs_lock); +} + +/* the point of entry for open() on any ieee1394 character device */ +static int ieee1394_dispatch_open(struct inode *inode, struct file *file) +{ + struct file_operations *file_ops; + struct module *module; + int blocknum; + int retval = -ENODEV; + + /* + Maintaining correct module reference counts is tricky here! + + For Linux v2.4 and later: + + The key thing to remember is that the VFS increments the + reference count of ieee1394 before it calls + ieee1394_dispatch_open(). + + If the open() succeeds, then we need to transfer this extra + reference to the task-specific driver module (e.g. raw1394). + The VFS will deref the driver module automatically when the + file is later released. + + If the open() fails, then the VFS will drop the + reference count of whatever module file->f_op->owner points + to, immediately after this function returns. + + The comments below refer to the 2.4 case, since the 2.2 + case is trivial. + + */ + +#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \ + if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0) +#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \ + if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0) + + /* shift away lower four bits of the minor + to get the index of the ieee1394_driver + we want */ + + blocknum = (minor(inode->i_rdev) >> 4) & 0xF; + + /* printk("ieee1394_dispatch_open(%d)", blocknum); */ + + /* lock the whole kernel here, to prevent a driver from + being unloaded between the file_ops lookup and the open */ + + lock_kernel(); + + read_lock(&ieee1394_chardevs_lock); + file_ops = ieee1394_chardevs[blocknum].file_ops; + module = ieee1394_chardevs[blocknum].module; + read_unlock(&ieee1394_chardevs_lock); + + if(file_ops == NULL) { + goto out_fail; + } + + /* redirect all subsequent requests to the driver's + own file_operations */ + file->f_op = file_ops; + + /* bump the reference count of the driver that + will receive the open() */ + INCREF(module); + + /* at this point BOTH ieee1394 and the task-specific driver have + an extra reference */ + + /* follow through with the open() */ + retval = file_ops->open(inode, file); + + if(retval) { + + /* if the open() failed, then we need to drop the + extra reference we gave to the task-specific + driver */ + + DECREF(module); + goto out_fail; + + } else { + + /* if the open() succeeded, then ieee1394 will be left + with an extra module reference, so we discard it here.*/ + + DECREF(THIS_MODULE); + + /* the task-specific driver still has the extra + reference we gave it. This extra reference prevents + the module from unloading while the file is open, + and will be dropped by the VFS when the file is + released. */ + + unlock_kernel(); + return 0; + } + +out_fail: + /* point the file's f_ops back to ieee1394. The VFS will then + decrement ieee1394's reference count immediately after this + function returns. */ + + file->f_op = &ieee1394_chardev_ops; + unlock_kernel(); + return retval; + +#undef INCREF +#undef DECREF + +} + +struct proc_dir_entry *ieee1394_procfs_entry; + static int __init ieee1394_init(void) { hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet), 0, 0, NULL, NULL); + + ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL); + + if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) { + HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR); + devfs_unregister(ieee1394_devfs_handle); + return -ENODEV; + } + +#ifdef CONFIG_PROC_FS + /* Must be done before we start everything else, since the drivers + * may use it. */ + ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus); + if (ieee1394_procfs_entry == NULL) { + HPSB_ERR("unable to create /proc/bus/ieee1394\n"); + unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); + devfs_unregister(ieee1394_devfs_handle); + return -ENOMEM; + } + ieee1394_procfs_entry->owner = THIS_MODULE; +#endif + init_hpsb_highlevel(); init_csr(); if (!disable_nodemgr) - init_ieee1394_nodemgr(); + init_ieee1394_nodemgr(disable_hotplug); else HPSB_INFO("nodemgr functionality disabled"); @@ -807,6 +1019,13 @@ cleanup_csr(); kmem_cache_destroy(hpsb_packet_cache); + + unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); + + /* it's ok to pass a NULL devfs_handle to devfs_unregister */ + devfs_unregister(ieee1394_devfs_handle); + + remove_proc_entry("ieee1394", proc_bus); } module_init(ieee1394_init); @@ -815,9 +1034,11 @@ /* Exported symbols */ EXPORT_SYMBOL(hpsb_register_lowlevel); EXPORT_SYMBOL(hpsb_unregister_lowlevel); -EXPORT_SYMBOL(hpsb_get_host); -EXPORT_SYMBOL(hpsb_inc_host_usage); -EXPORT_SYMBOL(hpsb_dec_host_usage); +EXPORT_SYMBOL(hpsb_alloc_host); +EXPORT_SYMBOL(hpsb_add_host); +EXPORT_SYMBOL(hpsb_remove_host); +EXPORT_SYMBOL(hpsb_ref_host); +EXPORT_SYMBOL(hpsb_unref_host); EXPORT_SYMBOL(hpsb_speedto_str); EXPORT_SYMBOL(alloc_hpsb_packet); @@ -867,12 +1088,19 @@ EXPORT_SYMBOL(highlevel_add_host); EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); -EXPORT_SYMBOL(highlevel_add_one_host); EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry); -EXPORT_SYMBOL(hpsb_get_host_by_ne); -EXPORT_SYMBOL(hpsb_guid_fill_packet); +EXPORT_SYMBOL(hpsb_node_fill_packet); +EXPORT_SYMBOL(hpsb_node_read); +EXPORT_SYMBOL(hpsb_node_write); +EXPORT_SYMBOL(hpsb_node_lock); EXPORT_SYMBOL(hpsb_register_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_release_unit_directory); + +EXPORT_SYMBOL(ieee1394_register_chardev); +EXPORT_SYMBOL(ieee1394_unregister_chardev); +EXPORT_SYMBOL(ieee1394_devfs_handle); + +EXPORT_SYMBOL(ieee1394_procfs_entry); diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_core.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.h --- linux-2.4.18/drivers/ieee1394/ieee1394_core.h Sun Feb 17 11:38:52 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.h Sat Mar 30 22:55:39 2002 @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include "hosts.h" @@ -96,7 +98,6 @@ return atomic_read(&host->generation); } - /* * Queue packet for transmitting, return 0 for failure. */ @@ -151,5 +152,66 @@ */ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, int write_acked); + + +/* + * CHARACTER DEVICE DISPATCHING + * + * All ieee1394 character device drivers share the same major number + * (major 171). The 256 minor numbers are allocated to the various + * task-specific interfaces (raw1394, video1394, dv1394, etc) in + * blocks of 16. + * + * The core ieee1394.o modules handles the initial open() for all + * character devices on major 171; it then dispatches to the + * appropriate task-specific driver. + * + * Minor device number block allocations: + * + * Block 0 ( 0- 15) raw1394 + * Block 1 ( 16- 31) video1394 + * Block 2 ( 32- 47) dv1394 + * + * Blocks 3-14 free for future allocation + * + * Block 15 (240-255) reserved for drivers under development, etc. + */ + +#define IEEE1394_MAJOR 171 + +#define IEEE1394_MINOR_BLOCK_RAW1394 0 +#define IEEE1394_MINOR_BLOCK_VIDEO1394 1 +#define IEEE1394_MINOR_BLOCK_DV1394 2 +#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15 + +/* return the index (within a minor number block) of a file */ +static inline unsigned char ieee1394_file_to_instance(struct file *file) +{ + unsigned char minor = minor(file->f_dentry->d_inode->i_rdev); + + /* return lower 4 bits */ + return minor & 0xF; +} + +/* + * Task-specific drivers should call ieee1394_register_chardev() to + * request a block of 16 minor numbers. + * + * Returns 0 if the request was successful, -EBUSY if the block was + * already taken. + */ + +int ieee1394_register_chardev(int blocknum, /* 0-15 */ + struct module *module, /* THIS_MODULE */ + struct file_operations *file_ops); + +/* release a block of minor numbers */ +void ieee1394_unregister_chardev(int blocknum); + +/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */ +extern devfs_handle_t ieee1394_devfs_handle; + +/* the proc_fs entry for /proc/ieee1394 */ +extern struct proc_dir_entry *ieee1394_procfs_entry; #endif /* _IEEE1394_CORE_H */ diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_transactions.c linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.c --- linux-2.4.18/drivers/ieee1394/ieee1394_transactions.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.c Sat Mar 30 22:55:39 2002 @@ -246,7 +246,7 @@ packet->node_id); return -EAGAIN; } - HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__); + HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__); case ACK_BUSY_X: case ACK_BUSY_A: @@ -290,7 +290,7 @@ return -EAGAIN; } - HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__); + HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__); } @@ -415,8 +415,8 @@ * avoid in kernel buffers for user space callers */ -int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length) +int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length) { struct hpsb_packet *packet; int retval = 0; @@ -447,7 +447,7 @@ return -ENOMEM; } - packet->generation = get_hpsb_generation(host); + packet->generation = generation; if (!hpsb_send_packet(packet)) { retval = -EINVAL; goto hpsb_read_fail; @@ -496,8 +496,8 @@ return packet; } -int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length) +int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length) { struct hpsb_packet *packet; int retval; @@ -522,7 +522,7 @@ if (!packet) return -ENOMEM; - packet->generation = get_hpsb_generation(host); + packet->generation = generation; if (!hpsb_send_packet(packet)) { retval = -EINVAL; goto hpsb_write_fail; @@ -541,8 +541,8 @@ /* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */ -int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, - quadlet_t *data, quadlet_t arg) +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg) { struct hpsb_packet *packet; int retval = 0, length; @@ -588,7 +588,7 @@ } fill_async_lock(packet, addr, extcode, length); - packet->generation = get_hpsb_generation(host); + packet->generation = generation; if (!hpsb_send_packet(packet)) { retval = -EINVAL; goto hpsb_lock_fail; diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_transactions.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.h --- linux-2.4.18/drivers/ieee1394/ieee1394_transactions.h Sun Feb 17 11:38:58 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.h Sat Mar 30 22:55:39 2002 @@ -63,14 +63,16 @@ * The generic read, write and lock functions. All recognize the local node ID * and act accordingly. Read and write automatically use quadlet commands if * length == 4 and and block commands otherwise (however, they do not yet - * support lengths that are not a multiple of 4). + * support lengths that are not a multiple of 4). You must explicitly specifiy + * the generation for which the node ID is valid, to avoid sending packets to + * the wrong nodes when we race with a bus reset. */ -int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length); -int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length); -int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, - quadlet_t *data, quadlet_t arg); +int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length); +int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length); +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg); /* Generic packet creation. Used by hpsb_write. Also useful for protocol * drivers that want to implement their own hpsb_write replacement. */ diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_types.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_types.h --- linux-2.4.18/drivers/ieee1394/ieee1394_types.h Sun Feb 17 11:38:52 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_types.h Sat Mar 30 22:55:39 2002 @@ -6,18 +6,18 @@ #include #include #include +#include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#include "linux22compat.h" -#else -#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0) -#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0) -#define OWNER_THIS_MODULE owner: THIS_MODULE, +/* The great kdev_t changeover in 2.5.x */ +#include +#ifndef minor +#define minor(dev) MINOR(dev) +#endif -#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list) -#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq)) +#ifndef __devexit_p +#define __devexit_p(x) x #endif /* This showed up around this time */ @@ -37,11 +37,7 @@ #endif /* Linux version < 2.4.12 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) -#include -#else #include -#endif #ifndef list_for_each_safe #define list_for_each_safe(pos, n, head) \ @@ -67,7 +63,8 @@ #define LOCAL_BUS 0xffc0 #define ALL_NODES 0x003f -#define NODE_BUS_FMT "%d:%d" +/* Can be used to consistently print a node/bus ID. */ +#define NODE_BUS_FMT "%02d:%04d" #define NODE_BUS_ARGS(nodeid) \ (nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6) diff -urN linux-2.4.18/drivers/ieee1394/nodemgr.c linux-2.4.19-pre5/drivers/ieee1394/nodemgr.c --- linux-2.4.18/drivers/ieee1394/nodemgr.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/nodemgr.c Sat Mar 30 22:55:39 2002 @@ -12,10 +12,14 @@ #include #include #include -#include #include #include #include +#include +#include +#ifdef CONFIG_PROC_FS +#include +#endif #include "ieee1394_types.h" #include "ieee1394.h" @@ -57,23 +61,254 @@ static LIST_HEAD(host_info_list); static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED; +/* Disables use of the hotplug calls. */ +static int nodemgr_disable_hotplug = 0; + struct host_info { struct hpsb_host *host; - struct tq_struct task; struct list_head list; + struct completion exited; + struct semaphore reset_sem; + int pid; }; +#ifdef CONFIG_PROC_FS + +#define PUTF(fmt, args...) out += sprintf(out, fmt, ## args) + +static int raw1394_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *lh; + struct node_entry *ne; + int len; + char *out = page; + + list_for_each(lh, &node_list) { + struct list_head *l; + int ud_count = 0; + + ne = list_entry(lh, struct node_entry, list); + if (!ne) + continue; + + PUTF("Node[" NODE_BUS_FMT "] GUID[%016Lx]:\n", + NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid); + + /* Generic Node information */ + PUTF(" Vendor ID: `%s' [0x%06x]\n", + ne->vendor_name ?: "Unknown", ne->vendor_id); + PUTF(" Capabilities: 0x%06x\n", ne->capabilities); + PUTF(" Bus Options:\n"); + PUTF(" IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n" + " LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n", + ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc, + ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd, + ne->busopt.max_rec, ne->busopt.cyc_clk_acc); + + /* If this is the host entry, output some info about it aswell */ + if (ne->host != NULL && ne->host->node_id == ne->nodeid) { + PUTF(" Host Node Status:\n"); + PUTF(" Host Driver : %s\n", ne->host->driver->name); + PUTF(" Nodes connected : %d\n", ne->host->node_count); + PUTF(" Nodes active : %d\n", ne->host->nodes_active); + PUTF(" SelfIDs received: %d\n", ne->host->selfid_count); + PUTF(" Irm ID : [" NODE_BUS_FMT "]\n", + NODE_BUS_ARGS(ne->host->irm_id)); + PUTF(" BusMgr ID : [" NODE_BUS_FMT "]\n", + NODE_BUS_ARGS(ne->host->busmgr_id)); + PUTF(" In Bus Reset : %s\n", ne->host->in_bus_reset ? "yes" : "no"); + PUTF(" Root : %s\n", ne->host->is_root ? "yes" : "no"); + PUTF(" Cycle Master : %s\n", ne->host->is_cycmst ? "yes" : "no"); + PUTF(" IRM : %s\n", ne->host->is_irm ? "yes" : "no"); + PUTF(" Bus Manager : %s\n", ne->host->is_busmgr ? "yes" : "no"); + } + + /* Now the unit directories */ + list_for_each (l, &ne->unit_directories) { + struct unit_directory *ud = list_entry (l, struct unit_directory, node_list); + PUTF(" Unit Directory %d:\n", ud_count++); + if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) + PUTF(" Vendor/Model ID: %s [%06x]", + ud->vendor_name ?: "Unknown", ud->vendor_id); + else if (ud->flags & UNIT_DIRECTORY_MODEL_ID) /* Have to put something */ + PUTF(" Vendor/Model ID: %s [%06x]", + ne->vendor_name ?: "Unknown", ne->vendor_id); + if (ud->flags & UNIT_DIRECTORY_MODEL_ID) + PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id); + PUTF("\n"); + if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) + PUTF(" Software Specifier ID: %06x\n", ud->specifier_id); + if (ud->flags & UNIT_DIRECTORY_VERSION) + PUTF(" Software Version: %06x\n", ud->version); + if (ud->driver) + PUTF(" Driver: %s\n", ud->driver->name); + PUTF(" Length (in quads): %d\n", ud->count); + } + + } + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + + return len; +} + +#undef PUTF +#endif /* CONFIG_PROC_FS */ + static void nodemgr_process_config_rom(struct node_entry *ne, quadlet_t busoptions); +static int nodemgr_read_quadlet(struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation, + octlet_t address, quadlet_t *quad) +{ + int i; + int ret = 0; + + for (i = 0; i < 3; i++) { + ret = hpsb_read(host, nodeid, generation, address, quad, 4); + if (ret != -EAGAIN) + break; + } + *quad = be32_to_cpu(*quad); + + return ret; +} + +static int nodemgr_size_text_leaf(struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation, + octlet_t address) +{ + quadlet_t quad; + int size = 0; + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return -1; + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { + /* This is the offset. */ + address += 4 * CONFIG_ROM_VALUE(quad); + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return -1; + /* Now we got the size of the text descriptor leaf. */ + size = CONFIG_ROM_LEAF_LENGTH(quad); + } + return size; +} + +static int nodemgr_read_text_leaf(struct node_entry *ne, + octlet_t address, + quadlet_t *quadp) +{ + quadlet_t quad; + int i, size, ret; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) + && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + return -1; + + /* This is the offset. */ + address += 4 * CONFIG_ROM_VALUE(quad); + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) + return -1; + + /* Now we got the size of the text descriptor leaf. */ + size = CONFIG_ROM_LEAF_LENGTH(quad) - 2; + if (size <= 0) + return -1; + + address += 4; + for (i = 0; i < 2; i++, address += 4, quadp++) { + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp)) + return -1; + } + + /* Now read the text string. */ + ret = -ENXIO; + for (; size > 0; size--, address += 4, quadp++) { + for (i = 0; i < 3; i++) { + ret = hpsb_read(ne->host, ne->nodeid, ne->generation, address, quadp, 4); + if (ret != -EAGAIN) + break; + } + if (ret) + break; + } + + return ret; +} + +static struct node_entry *nodemgr_scan_root_directory + (struct hpsb_host *host, nodeid_t nodeid, unsigned int generation) +{ + octlet_t address; + quadlet_t quad; + int length; + int code, size, total_size; + struct node_entry *ne; + + address = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; + + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + length = CONFIG_ROM_ROOT_LENGTH(quad); + address += 4; + + size = 0; + total_size = sizeof(struct node_entry); + for (; length > 0; length--, address += 4) { + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + code = CONFIG_ROM_KEY(quad); + + if (code == CONFIG_ROM_VENDOR_ID && length > 0) { + /* Check if there is a text descriptor leaf + immediately after this. */ + size = nodemgr_size_text_leaf(host, nodeid, generation, + address + 4); + if (size > 0) { + address += 4; + length--; + total_size += (size + 1) * sizeof (quadlet_t); + } + else if (size < 0) + return NULL; + } + } + ne = kmalloc(total_size, SLAB_ATOMIC); + if (ne != NULL) { + if (size != 0) { + ne->vendor_name + = (const char *) &(ne->quadlets[2]); + ne->quadlets[size] = 0; + } + else { + ne->vendor_name = NULL; + } + } + return ne; +} static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions, - struct hpsb_host *host, nodeid_t nodeid) + struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation) { struct node_entry *ne; unsigned long flags; - ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC); + ne = nodemgr_scan_root_directory (host, nodeid, generation); if (!ne) return NULL; INIT_LIST_HEAD(&ne->list); @@ -81,7 +316,7 @@ ne->host = host; ne->nodeid = nodeid; ne->guid = guid; - atomic_set(&ne->generation, get_hpsb_generation(ne->host)); + ne->generation = generation; write_lock_irqsave(&node_lock, flags); list_add_tail(&ne->list, &node_list); @@ -89,9 +324,10 @@ nodemgr_process_config_rom (ne, busoptions); - HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx", - (host->node_id == nodeid) ? "Local host" : "Device", - NODE_BUS_ARGS(nodeid), (unsigned long long)guid); + HPSB_DEBUG("%s added: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]", + (host->node_id == nodeid) ? "Host" : "Device", + NODE_BUS_ARGS(nodeid), (unsigned long long)guid, + ne->vendor_name ?: "Unknown"); return ne; } @@ -122,30 +358,102 @@ return NULL; } -int nodemgr_read_quadlet(struct node_entry *ne, - octlet_t address, quadlet_t *quad) +static struct unit_directory *nodemgr_scan_unit_directory + (struct node_entry *ne, octlet_t address) { - int i; - int ret = 0; + struct unit_directory *ud; + quadlet_t quad; + u8 flags, todo; + int length, size, total_size, count; + int vendor_name_size, model_name_size; - for (i = 0; i < 3; i++) { - ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4); - if (ret != -EAGAIN) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) + return NULL; + length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ; + address += 4; + + size = 0; + total_size = sizeof (struct unit_directory); + flags = 0; + count = 0; + vendor_name_size = 0; + model_name_size = 0; + for (; length > 0; length--, address += 4) { + int code; + quadlet_t value; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + return NULL; + code = CONFIG_ROM_KEY(quad); + value = CONFIG_ROM_VALUE(quad); + + todo = 0; + switch (code) { + case CONFIG_ROM_VENDOR_ID: + todo = UNIT_DIRECTORY_VENDOR_TEXT; break; - } - *quad = be32_to_cpu(*quad); - return ret; -} + case CONFIG_ROM_MODEL_ID: + todo = UNIT_DIRECTORY_MODEL_TEXT; + break; -#define CONFIG_ROM_VENDOR_ID 0x03 -#define CONFIG_ROM_MODEL_ID 0x17 -#define CONFIG_ROM_NODE_CAPABILITES 0x0C -#define CONFIG_ROM_UNIT_DIRECTORY 0xd1 -#define CONFIG_ROM_SPECIFIER_ID 0x12 -#define CONFIG_ROM_VERSION 0x13 -#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81 -#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1 + case CONFIG_ROM_SPECIFIER_ID: + case CONFIG_ROM_UNIT_SW_VERSION: + break; + + case CONFIG_ROM_DESCRIPTOR_LEAF: + case CONFIG_ROM_DESCRIPTOR_DIRECTORY: + /* TODO: read strings... icons? */ + break; + + default: + /* Which types of quadlets do we want to + store? Only count immediate values and + CSR offsets for now. */ + code &= CONFIG_ROM_KEY_TYPE_MASK; + if ((code & 0x80) == 0) + count++; + break; + } + + if (todo && length > 0) { + /* Check if there is a text descriptor leaf + immediately after this. */ + size = nodemgr_size_text_leaf(ne->host, + ne->nodeid, + ne->generation, + address + 4); + + if (todo == UNIT_DIRECTORY_VENDOR_TEXT) + vendor_name_size = size; + else + model_name_size = size; + + if (size > 0) { + address += 4; + length--; + flags |= todo; + total_size += (size + 1) * sizeof (quadlet_t); + } + else if (size < 0) + return NULL; + } + } + total_size += count * sizeof (quadlet_t); + ud = kmalloc (total_size, GFP_KERNEL); + if (ud != NULL) { + memset (ud, 0, sizeof *ud); + ud->flags = flags; + ud->count = count; + ud->vendor_name_size = vendor_name_size; + ud->model_name_size = model_name_size; + /* If there is no vendor name in the unit directory, + use the one in the root directory. */ + ud->vendor_name = ne->vendor_name; + } + return ud; +} /* This implementation currently only scans the config rom and its * immediate unit directories looking for software_id and @@ -156,41 +464,73 @@ octlet_t address) { struct unit_directory *ud; - octlet_t a; quadlet_t quad; - int length, i; + quadlet_t *infop; + int length; - if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL))) + if (!(ud = nodemgr_scan_unit_directory(ne, address))) goto unit_directory_error; - memset (ud, 0, sizeof *ud); ud->ne = ne; ud->address = address; - ud->arb_count = 0; - if (nodemgr_read_quadlet(ne, address, &quad)) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) goto unit_directory_error; - length = quad >> 16; - a = address + 4; + length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ; + address += 4; - for (i = 0; i < length; i++, a += 4) { + infop = (quadlet_t *) ud->quadlets; + for (; length > 0; length--, address += 4, infop++) { int code; quadlet_t value; + quadlet_t *quadp; - if (nodemgr_read_quadlet(ne, a, &quad)) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) goto unit_directory_error; - code = quad >> 24; - value = quad & 0xffffff; + code = CONFIG_ROM_KEY(quad) ; + value = CONFIG_ROM_VALUE(quad); switch (code) { case CONFIG_ROM_VENDOR_ID: ud->vendor_id = value; ud->flags |= UNIT_DIRECTORY_VENDOR_ID; + if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) { + length--; + address += 4; + quadp = &(ud->quadlets[ud->count]); + if (nodemgr_read_text_leaf(ne, address, + quadp) == 0 + && quadp[0] == 0 + && quadp[1] == 0) { + /* We only support minimal + ASCII and English. */ + quadp[ud->vendor_name_size] = 0; + ud->vendor_name + = (const char *) &(quadp[2]); + } + } break; case CONFIG_ROM_MODEL_ID: ud->model_id = value; ud->flags |= UNIT_DIRECTORY_MODEL_ID; + if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) { + length--; + address += 4; + quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]); + if (nodemgr_read_text_leaf(ne, address, + quadp) == 0 + && quadp[0] == 0 + && quadp[1] == 0) { + /* We only support minimal + ASCII and English. */ + quadp[ud->model_name_size] = 0; + ud->model_name + = (const char *) &(quadp[2]); + } + } break; case CONFIG_ROM_SPECIFIER_ID: @@ -198,7 +538,7 @@ ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID; break; - case CONFIG_ROM_VERSION: + case CONFIG_ROM_UNIT_SW_VERSION: ud->version = value; ud->flags |= UNIT_DIRECTORY_VERSION; break; @@ -209,12 +549,13 @@ break; default: - if (ud->arb_count < 16) { - /* Place them in the arbitrary pairs */ - ud->arb_keys[ud->arb_count] = code; - ud->arb_values[ud->arb_count] = value; - ud->arb_count++; - } + /* Which types of quadlets do we want to + store? Only count immediate values and + CSR offsets for now. */ + code &= CONFIG_ROM_KEY_TYPE_MASK; + if ((code & 0x80) == 0) + *infop = quad; + break; } } @@ -233,53 +574,74 @@ #ifdef CONFIG_IEEE1394_VERBOSEDEBUG struct list_head *l; - HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x", - ne->vendor_id, ne->capabilities); + HPSB_DEBUG("vendor_id=0x%06x [%s], capabilities=0x%06x", + ne->vendor_id, ne->vendor_name ?: "Unknown", + ne->capabilities); list_for_each (l, &ne->unit_directories) { struct unit_directory *ud = list_entry (l, struct unit_directory, node_list); HPSB_DEBUG("unit directory:"); if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) - HPSB_DEBUG(" vendor_id=0x%06x ", ud->vendor_id); + HPSB_DEBUG(" vendor_id=0x%06x [%s]", + ud->vendor_id, + ud->vendor_name ?: "Unknown"); if (ud->flags & UNIT_DIRECTORY_MODEL_ID) - HPSB_DEBUG(" model_id=0x%06x ", ud->model_id); + HPSB_DEBUG(" model_id=0x%06x [%s]", + ud->model_id, + ud->model_name ?: "Unknown"); if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) HPSB_DEBUG(" sw_specifier_id=0x%06x ", ud->specifier_id); if (ud->flags & UNIT_DIRECTORY_VERSION) HPSB_DEBUG(" sw_version=0x%06x ", ud->version); } -#else - return; #endif + return; } static void nodemgr_process_root_directory(struct node_entry *ne) { octlet_t address; quadlet_t quad; - int length, i; + int length; address = CSR_REGISTER_BASE + CSR_CONFIG_ROM; - if (nodemgr_read_quadlet(ne, address, &quad)) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) return; - address += 4 + (quad >> 24) * 4; + address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; - if (nodemgr_read_quadlet(ne, address, &quad)) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) return; - length = quad >> 16; + length = CONFIG_ROM_ROOT_LENGTH(quad); address += 4; - for (i = 0; i < length; i++, address += 4) { + for (; length > 0; length--, address += 4) { int code, value; - if (nodemgr_read_quadlet(ne, address, &quad)) + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) return; - code = quad >> 24; - value = quad & 0xffffff; + code = CONFIG_ROM_KEY(quad); + value = CONFIG_ROM_VALUE(quad); switch (code) { case CONFIG_ROM_VENDOR_ID: ne->vendor_id = value; + /* Now check if there is a vendor name text + string. */ + if (ne->vendor_name != NULL) { + length--; + address += 4; + if (nodemgr_read_text_leaf(ne, address, + ne->quadlets) + != 0 + || ne->quadlets [0] != 0 + || ne->quadlets [1] != 0) + /* We only support minimal + ASCII and English. */ + ne->vendor_name = NULL; + } break; case CONFIG_ROM_NODE_CAPABILITES: @@ -307,6 +669,10 @@ char *argv [3], **envp, *buf, *scratch; int i = 0, value; + /* User requested to disable hotplug when module was loaded. */ + if (nodemgr_disable_hotplug) + return; + if (!hotplug_path [0]) return; if (!current->fs->root) @@ -578,7 +944,8 @@ * the to take whatever actions required. */ static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions, - struct hpsb_host *host, nodeid_t nodeid) + struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation) { struct list_head *lh; struct unit_directory *ud; @@ -593,7 +960,7 @@ nodemgr_process_config_rom (ne, busoptions); /* Since that's done, we can declare this record current */ - atomic_set(&ne->generation, get_hpsb_generation(ne->host)); + ne->generation = generation; list_for_each (lh, &ne->unit_directories) { ud = list_entry (lh, struct unit_directory, node_list); @@ -602,70 +969,61 @@ } } -static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, +static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation, quadlet_t *buffer, int buffer_length) { - octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM; - int retries = 3; - int header_count; + octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM; unsigned header_size; - quadlet_t quad; - -retry_configrom: - - if (!retries--) { - HPSB_ERR("Giving up on node " NODE_BUS_FMT - " for ConfigROM probe, too many errors", - NODE_BUS_ARGS(nodeid)); - return -1; - } + int i; - header_count = 0; - header_size = 0; + /* IEEE P1212 says that devices should support 64byte block + * reads, aligned on 64byte boundaries. That doesn't seem to + * work though, and we are forced to doing quadlet sized + * reads. */ #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); #endif - /* Now, P1212 says that devices should support 64byte block - * reads, aligned on 64byte boundaries. That doesn't seem - * to work though, and we are forced to doing quadlet - * sized reads. */ - - if (hpsb_read(host, nodeid, base, &quad, 4)) { - HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT, - NODE_BUS_ARGS(nodeid)); - goto retry_configrom; + if (nodemgr_read_quadlet(host, nodeid, generation, + addr, &buffer[0]) < 0) { + HPSB_ERR("ConfigROM quadlet transaction error for node " + NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); + return -1; } - buffer[header_count++] = be32_to_cpu(quad); header_size = buffer[0] >> 24; + addr += 4; if (header_size < 4) { - HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), " - "cannot parse", NODE_BUS_ARGS(nodeid), header_size); + HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM " + "format (%d quads), cannot parse", + NODE_BUS_ARGS(nodeid), header_size); return -1; } - while (header_count <= header_size && header_count < buffer_length) { - if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) { - HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT, + for (i = 1; i < buffer_length; i++, addr += 4) { + if (nodemgr_read_quadlet(host, nodeid, generation, + addr, &buffer[i]) < 0) { + HPSB_ERR("ConfigROM quadlet transaction " + "error for node " NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); - goto retry_configrom; + return -1; } - buffer[header_count++] = be32_to_cpu(quad); } return 0; -} +} static void nodemgr_remove_node(struct node_entry *ne) { unsigned long flags; - HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx", - NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid); + HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]", + (ne->host->node_id == ne->nodeid) ? "Host" : "Device", + NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid, + ne->vendor_name ?: "Unknown"); write_lock_irqsave(&unit_directory_lock, flags); nodemgr_free_unit_directories(ne); @@ -676,19 +1034,11 @@ return; } -/* Used to schedule each nodes config rom probe */ -struct node_probe_task { - nodeid_t nodeid; - struct hpsb_host *host; - atomic_t *count; - struct tq_struct task; -}; - /* This is where we probe the nodes for their information and provided * features. */ -static void nodemgr_node_probe_one(void *__npt) +static void nodemgr_node_probe_one(struct hpsb_host *host, + nodeid_t nodeid, int generation) { - struct node_probe_task *npt = (struct node_probe_task *)__npt; struct node_entry *ne; quadlet_t buffer[5]; octlet_t guid; @@ -696,130 +1046,121 @@ /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ - if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2)) - goto probe_complete; + if (read_businfo_block (host, nodeid, generation, + buffer, sizeof(buffer) >> 2)) + return; if (buffer[1] != IEEE1394_BUSID_MAGIC) { /* This isn't a 1394 device */ HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device", - NODE_BUS_ARGS(npt->nodeid)); - goto probe_complete; + NODE_BUS_ARGS(nodeid)); + return; } guid = ((u64)buffer[3] << 32) | buffer[4]; ne = hpsb_guid_get_entry(guid); if (!ne) - nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid); + nodemgr_create_node(guid, buffer[2], host, nodeid, generation); else - nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid); - -probe_complete: - atomic_dec(npt->count); - - kfree(npt); + nodemgr_update_node(ne, buffer[2], host, nodeid, generation); return; } -static void nodemgr_node_probe_cleanup(void *__npt) +static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation) { - struct node_probe_task *npt = (struct node_probe_task *)__npt; unsigned long flags; struct list_head *lh, *next; struct node_entry *ne; - /* If things aren't done yet, reschedule ourselves. */ - if (atomic_read(npt->count)) { - schedule_task(&npt->task); - return; - } - - kfree(npt->count); - /* Now check to see if we have any nodes that aren't referenced * any longer. */ write_lock_irqsave(&node_lock, flags); - for (lh = node_list.next; lh != &node_list; lh = next) { + list_for_each_safe(lh, next, &node_list) { ne = list_entry(lh, struct node_entry, list); - next = lh->next; /* Only checking this host */ - if (ne->host != npt->host) + if (ne->host != host) continue; /* If the generation didn't get updated, then either the * node was removed, or it failed the above probe. Either * way, we remove references to it, since they are * invalid. */ - if (!hpsb_node_entry_valid(ne)) + if (ne->generation != generation) nodemgr_remove_node(ne); } write_unlock_irqrestore(&node_lock, flags); - kfree(npt); - return; } -static void nodemgr_node_probe(void *__host) +static void nodemgr_node_probe(struct hpsb_host *host) { - struct hpsb_host *host = (struct hpsb_host *)__host; - int nodecount = host->node_count; + int count; struct selfid *sid = (struct selfid *)host->topology_map; nodeid_t nodeid = LOCAL_BUS; - struct node_probe_task *npt; - atomic_t *count; + unsigned int generation; - count = kmalloc(sizeof (*count), GFP_KERNEL); - - if (count == NULL) { - HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); + /* Pause for 1 second, to make sure things settle down. If + * schedule_timeout returns non-zero, it means we caught a signal + * and need to return. */ + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ)) return; - } - atomic_set(count, 0); - - for (; nodecount; nodecount--, nodeid++, sid++) { - while (sid->extended) - sid++; - if (!sid->link_active || nodeid == host->node_id) + /* Now get the generation in which the node ID's we collect + * are valid. During the bus scan we will use this generation + * for the read transactions, so that if another reset occurs + * during the scan the transactions will fail instead of + * returning bogus data. */ + generation = get_hpsb_generation(host); + + /* Scan each node on the bus */ + for (count = host->selfid_count; count; count--, sid++) { + if (sid->extended) continue; - npt = kmalloc(sizeof (*npt), GFP_KERNEL); - - if (npt == NULL) { - HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); - break; + if (!sid->link_active) { + nodeid++; + continue; } - INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt); - npt->host = host; - npt->nodeid = nodeid; - npt->count = count; + nodemgr_node_probe_one(host, nodeid++, generation); + } - atomic_inc(count); + /* If we had a bus reset while we were scanning the bus, it is + * possible that we did not probe all nodes. In that case, we + * skip the clean up for now, since we could remove nodes that + * were still on the bus. The bus reset increased + * hi->reset_sem, so there's a bus scan pending which will do + * the clean up eventually. */ + if (generation == get_hpsb_generation(host)) + nodemgr_node_probe_cleanup(host, generation); - schedule_task(&npt->task); - } + return; +} + +static int nodemgr_host_thread(void *__hi) +{ + struct host_info *hi = (struct host_info *)__hi; - /* Now schedule a task to clean things up after the node probes - * are done. */ - npt = kmalloc (sizeof (*npt), GFP_KERNEL); + /* No userlevel access needed */ + daemonize(); - if (npt == NULL) { - HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); - return; - } + strcpy(current->comm, "knodemgrd"); - INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt); - npt->host = host; - npt->nodeid = 0; - npt->count = count; + /* Sit and wait for a signal to probe the nodes on the bus. This + * happens when we get a bus reset. */ + while (!down_interruptible(&hi->reset_sem)) + nodemgr_node_probe(hi->host); - schedule_task(&npt->task); +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name); +#endif - return; + complete_and_exit(&hi->exited, 0); } struct node_entry *hpsb_guid_get_entry(u64 guid) @@ -846,23 +1187,57 @@ return ne; } -struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne) +/* The following four convenience functions use a struct node_entry + * for addressing a node on the bus. They are intended for use by any + * process context, not just the nodemgr thread, so we need to be a + * little careful when reading out the node ID and generation. The + * thing that can go wrong is that we get the node ID, then a bus + * reset occurs, and then we read the generation. The node ID is + * possibly invalid, but the generation is current, and we end up + * sending a packet to a the wrong node. + * + * The solution is to make sure we read the generation first, so that + * if a reset occurs in the process, we end up with a stale generation + * and the transactions will fail instead of silently using wrong node + * ID's. + */ + +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) { - if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host)) - return NULL; - if (ne->nodeid == ne->host->node_id) return ne->host; - return NULL; + pkt->host = ne->host; + pkt->generation = ne->generation; + barrier(); + pkt->node_id = ne->nodeid; } -int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) +int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length) { - if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host)) - return 0; + unsigned int generation = ne->generation; - pkt->host = ne->host; - pkt->node_id = ne->nodeid; - pkt->generation = atomic_read(&ne->generation); - return 1; + barrier(); + return hpsb_read(ne->host, ne->nodeid, generation, + addr, buffer, length); +} + +int hpsb_node_write(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length) +{ + unsigned int generation = ne->generation; + + barrier(); + return hpsb_write(ne->host, ne->nodeid, generation, + addr, buffer, length); +} + +int hpsb_node_lock(struct node_entry *ne, u64 addr, + int extcode, quadlet_t *data, quadlet_t arg) +{ + unsigned int generation = ne->generation; + + barrier(); + return hpsb_lock(ne->host, ne->nodeid, generation, + addr, extcode, data, arg); } static void nodemgr_add_host(struct hpsb_host *host) @@ -875,11 +1250,23 @@ return; } - /* We simply initialize the struct here. We don't start the thread - * until the first bus reset. */ + /* Initialize the hostinfo here and start the thread. The + * thread blocks on the reset semaphore until a bus reset + * happens. */ hi->host = host; INIT_LIST_HEAD(&hi->list); - INIT_TQUEUE(&hi->task, nodemgr_node_probe, host); + init_completion(&hi->exited); + sema_init(&hi->reset_sem, 0); + + hi->pid = kernel_thread(nodemgr_host_thread, hi, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + if (hi->pid < 0) { + HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s", + host->driver->name); + kfree(hi); + return; + } spin_lock_irqsave (&host_info_lock, flags); list_add_tail (&hi->list, &host_info_list); @@ -908,7 +1295,10 @@ goto done_reset_host; } - schedule_task(&hi->task); +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name); +#endif + up(&hi->reset_sem); done_reset_host: spin_unlock_irqrestore (&host_info_lock, flags); @@ -921,40 +1311,42 @@ struct list_head *lh, *next; struct node_entry *ne; unsigned long flags; + struct host_info *hi = NULL; + + spin_lock_irqsave (&host_info_lock, flags); + list_for_each_safe(lh, next, &host_info_list) { + struct host_info *myhi = list_entry(lh, struct host_info, list); + if (myhi->host == host) { + list_del(&myhi->list); + hi = myhi; + break; + } + } - /* Make sure we have no active scans */ - flush_scheduled_tasks(); + if (!hi) + HPSB_ERR ("NodeMgr: host %s does not exist, cannot remove", + host->driver->name); + spin_unlock_irqrestore (&host_info_lock, flags); - /* First remove all node entries for this host */ + /* Even if we fail the host_info part, remove all the node + * entries. */ write_lock_irqsave(&node_lock, flags); - - for (lh = node_list.next; lh != &node_list; lh = next) { + list_for_each_safe(lh, next, &node_list) { ne = list_entry(lh, struct node_entry, list); - next = lh->next; - /* Only checking this host */ - if (ne->host != host) - continue; - - nodemgr_remove_node(ne); + if (ne->host == host) + nodemgr_remove_node(ne); } write_unlock_irqrestore(&node_lock, flags); - spin_lock_irqsave (&host_info_lock, flags); - list_for_each_safe(lh, next, &host_info_list) { - struct host_info *hi = list_entry(lh, struct host_info, list); - if (hi->host == host) { - list_del(&hi->list); - kfree (hi); - break; + if (hi) { + if (hi->pid >= 0) { + kill_proc(hi->pid, SIGTERM, 1); + wait_for_completion(&hi->exited); } + kfree(hi); } - if (lh == host_info_list.next) - HPSB_ERR ("NodeMgr: could not remove non-existent host"); - - spin_unlock_irqrestore (&host_info_lock, flags); - return; } @@ -966,8 +1358,15 @@ static struct hpsb_highlevel *hl; -void init_ieee1394_nodemgr(void) +#define PROC_ENTRY "devices" + +void init_ieee1394_nodemgr(int disable_hotplug) { + nodemgr_disable_hotplug = disable_hotplug; +#ifdef CONFIG_PROC_FS + if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL)) + HPSB_ERR("Can't create devices procfs entry"); +#endif hl = hpsb_register_highlevel("Node manager", &nodemgr_ops); if (!hl) { HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization"); @@ -977,4 +1376,7 @@ void cleanup_ieee1394_nodemgr(void) { hpsb_unregister_highlevel(hl); +#ifdef CONFIG_PROC_FS + remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry); +#endif } diff -urN linux-2.4.18/drivers/ieee1394/nodemgr.h linux-2.4.19-pre5/drivers/ieee1394/nodemgr.h --- linux-2.4.18/drivers/ieee1394/nodemgr.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/nodemgr.h Sat Mar 30 22:55:39 2002 @@ -20,6 +20,44 @@ #ifndef _IEEE1394_NODEMGR_H #define _IEEE1394_NODEMGR_H +#define CONFIG_ROM_BUS_INFO_LENGTH(q) ((q) >> 24) +#define CONFIG_ROM_BUS_CRC_LENGTH(q) (((q) >> 16) & 0xff) +#define CONFIG_ROM_BUS_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_ROOT_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_ROOT_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_DIRECTORY_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_DIRECTORY_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_LEAF_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_LEAF_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_DESCRIPTOR_TYPE(q) ((q) >> 24) +#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q) ((q) & 0xffffff) +#define CONFIG_ROM_DESCRIPTOR_WIDTH(q) ((q) >> 28) +#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q) (((q) >> 16) & 0xfff) +#define CONFIG_ROM_DESCRIPTOR_LANG(q) ((q) & 0xffff) + +#define CONFIG_ROM_KEY_ID_MASK 0x3f +#define CONFIG_ROM_KEY_TYPE_MASK 0xc0 +#define CONFIG_ROM_KEY_TYPE_IMMEDIATE 0x00 +#define CONFIG_ROM_KEY_TYPE_OFFSET 0x40 +#define CONFIG_ROM_KEY_TYPE_LEAF 0x80 +#define CONFIG_ROM_KEY_TYPE_DIRECTORY 0xc0 + +#define CONFIG_ROM_KEY(q) ((q) >> 24) +#define CONFIG_ROM_VALUE(q) ((q) & 0xffffff) + +#define CONFIG_ROM_VENDOR_ID 0x03 +#define CONFIG_ROM_MODEL_ID 0x17 +#define CONFIG_ROM_NODE_CAPABILITES 0x0C +#define CONFIG_ROM_UNIT_DIRECTORY 0xd1 +#define CONFIG_ROM_SPECIFIER_ID 0x12 +#define CONFIG_ROM_UNIT_SW_VERSION 0x13 +#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81 +#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1 + /* '1' '3' '9' '4' in ASCII */ #define IEEE1394_BUSID_MAGIC 0x31333934 @@ -42,6 +80,8 @@ #define UNIT_DIRECTORY_MODEL_ID 0x02 #define UNIT_DIRECTORY_SPECIFIER_ID 0x04 #define UNIT_DIRECTORY_VERSION 0x08 +#define UNIT_DIRECTORY_VENDOR_TEXT 0x10 +#define UNIT_DIRECTORY_MODEL_TEXT 0x20 /* * A unit directory corresponds to a protocol supported by the @@ -58,17 +98,14 @@ octlet_t address; /* Address of the unit directory on the node */ u8 flags; /* Indicates which entries were read */ quadlet_t vendor_id; - char *vendor_name; + const char *vendor_name; + int vendor_name_size; quadlet_t model_id; - char *model_name; + const char *model_name; + int model_name_size; quadlet_t specifier_id; quadlet_t version; - /* Groupings for arbitrary key/value pairs */ - int arb_count; /* Number of arbitrary key/values */ - char arb_keys[16]; /* Up to 16 keys */ - quadlet_t arb_values[16]; /* Same for values */ - struct hpsb_protocol_driver *driver; void *driver_data; @@ -77,6 +114,9 @@ /* For linking directories belonging to a node */ struct list_head node_list; + + int count; /* Number of quadlets */ + quadlet_t quadlets[0]; }; struct node_entry { @@ -85,17 +125,20 @@ struct hpsb_host *host; /* Host this node is attached to */ nodeid_t nodeid; /* NodeID */ struct bus_options busopt; /* Bus Options */ - atomic_t generation; /* Synced with hpsb generation */ + unsigned int generation; /* Synced with hpsb generation */ /* The following is read from the config rom */ u32 vendor_id; u32 capabilities; struct list_head unit_directories; + + const char *vendor_name; + quadlet_t quadlets[0]; }; static inline int hpsb_node_entry_valid(struct node_entry *ne) { - return atomic_read(&ne->generation) == get_hpsb_generation(ne->host); + return ne->generation == get_hpsb_generation(ne->host); } /* @@ -127,10 +170,17 @@ * number). It will at least reliably fail so that you don't accidentally and * unknowingly send your packet to the wrong node. */ -int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt); +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt); + +int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_node_write(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_node_lock(struct node_entry *ne, u64 addr, + int extcode, quadlet_t *data, quadlet_t arg); -void init_ieee1394_nodemgr(void); +void init_ieee1394_nodemgr(int disable_hotplug); void cleanup_ieee1394_nodemgr(void); #endif /* _IEEE1394_NODEMGR_H */ diff -urN linux-2.4.18/drivers/ieee1394/ohci1394.c linux-2.4.19-pre5/drivers/ieee1394/ohci1394.c --- linux-2.4.18/drivers/ieee1394/ohci1394.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/ohci1394.c Sat Mar 30 22:55:39 2002 @@ -77,6 +77,12 @@ * . Config ROM generation */ +/* Issues: + * + * - devctl BUS_RESET should treat arg as reset type + * + */ + #include #include #include @@ -99,7 +105,6 @@ #include #include #include -#include #include #include #include @@ -136,10 +141,10 @@ #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG #define OHCI_DMA_ALLOC(fmt, args...) \ - HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \ + HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \ ++global_outstanding_dmas, ## args) #define OHCI_DMA_FREE(fmt, args...) \ - HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \ + HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \ --global_outstanding_dmas, ## args) u32 global_outstanding_dmas = 0; #else @@ -155,35 +160,23 @@ #define PRINT(level, card, fmt, args...) \ printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) -#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) - -static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { - { - class: PCI_CLASS_FIREWIRE_OHCI, - class_mask: 0x00ffffff, - vendor: PCI_ANY_ID, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); - static char version[] __devinitdata = - "$Revision: 1.80 $ Ben Collins "; + "$Revision: 1.101 $ Ben Collins "; /* Module Parameters */ MODULE_PARM(attempt_root,"i"); MODULE_PARM_DESC(attempt_root, "Attempt to make the host root."); static int attempt_root = 0; -static unsigned int card_id_counter = 0; - static void dma_trm_tasklet(unsigned long data); -static void remove_card(struct ti_ohci *ohci); static void dma_trm_reset(struct dma_trm_ctx *d); +static void __devexit ohci1394_pci_remove(struct pci_dev *pdev); + +static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, + quadlet_t isoRecvEvent, + quadlet_t isoXmitEvent); + #ifndef __LITTLE_ENDIAN /* Swap a series of quads inplace. */ static __inline__ void block_swab32(quadlet_t *data, size_t size) { @@ -311,8 +304,8 @@ if ((self_id_count & 0x80000000) || ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) { PRINT(KERN_ERR, ohci->id, - "Error in reception of SelfID packets [0x%08x/0x%08x]", - self_id_count, q0); + "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)", + self_id_count, q0, ohci->self_id_errors); /* Tip by James Goodwin : * We had an error, generate another bus reset in response. */ @@ -325,6 +318,9 @@ } return; } + + /* SelfID Ok, reset error counter. */ + ohci->self_id_errors = 0; size = ((self_id_count & 0x00001FFC) >> 2) - 1; q++; @@ -358,7 +354,7 @@ return; } -static int ohci_soft_reset(struct ti_ohci *ohci) { +static void ohci_soft_reset(struct ti_ohci *ohci) { int i; reg_write(ohci, OHCI1394_HCControlSet, 0x00010000); @@ -369,9 +365,13 @@ mdelay(1); } - DBGMSG (ohci->id, "Soft reset finished"); + /* Now reenable LPS, since that's usually what we want after a + * softreset anyway. Wait 50msec to make sure we have full link + * enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + mdelay(50); - return 0; + DBGMSG (ohci->id, "Soft reset finished"); } static int run_context(struct ti_ohci *ohci, int reg, char *msg) @@ -412,8 +412,7 @@ for (i=0; inum_desc; i++) { u32 c; - c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH; + c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH; if (generate_irq) c |= DMA_CTL_IRQ; @@ -486,19 +485,13 @@ static void ohci_init_config_rom(struct ti_ohci *ohci); /* Global initialization */ -static int ohci_initialize(struct hpsb_host *host) +static void ohci_initialize(struct ti_ohci *ohci) { - struct ti_ohci *ohci=host->hostdata; - int retval, i; quadlet_t buf; spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); - /* Soft reset */ - if ((retval = ohci_soft_reset(ohci)) < 0) - return retval; - /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); buf |= 0x60000000; /* Enable CMC and ISC */ @@ -506,16 +499,6 @@ buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */ reg_write(ohci, OHCI1394_BusOptions, buf); - /* Set Link Power Status (LPS) */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - - /* After enabling LPS, we need to wait for the connection - * between phy and link to be established. This should be - * signaled by the LPS bit becoming 1, but this happens - * immediately. There seems to be no consistent way to wait - * for this, but 50ms seems to be enough. */ - mdelay(50); - /* Set the bus number */ reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); @@ -551,18 +534,6 @@ /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); - /* Initialize IR dma */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - DBGMSG(ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); - for (i=0;inb_iso_rcv_ctx;i++) { - reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i, - 0xffffffff); - reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0); - reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0); - } - /* Set bufferFill, isochHeader, multichannel for IR context */ reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000); @@ -573,17 +544,6 @@ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); - /* Initialize IT dma */ - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - DBGMSG(ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); - for (i=0;inb_iso_xmit_ctx;i++) { - reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i, - 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0); - } - /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); @@ -640,31 +600,19 @@ OHCI1394_reqTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | - OHCI1394_unrecoverableError - ); + OHCI1394_cycleInconsistent); /* Enable link */ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); buf = reg_read(ohci, OHCI1394_Version); - PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] MMIO=[%lx-%lx]" - " Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), + PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] " + "MMIO=[%lx-%lx] Max Packet=[%d]", + ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0), ohci->max_packet_size); - - return 1; -} - -static void ohci_remove(struct hpsb_host *host) -{ - struct ti_ohci *ohci; - - if (host != NULL) { - ohci = host->hostdata; - remove_card(ohci); - } } /* @@ -686,7 +634,7 @@ d->prg_cpu[idx]->begin.address = 0; d->prg_cpu[idx]->begin.branchAddress = 0; - if (d->ctx==1) { + if (d->type == DMA_CTX_ASYNC_RESP) { /* * For response packets, we need to put a timeout value in * the 16 lower bits of the status... let's try 1 sec timeout @@ -735,9 +683,9 @@ if (cross_bound((unsigned long)packet->data, packet->data_size)>0) { /* FIXME: do something about it */ - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - ": packet data addr: %p size %Zd bytes " - "cross page boundary", + PRINT(KERN_ERR, ohci->id, + "%s: packet data addr: %p size %Zd bytes " + "cross page boundary", __FUNCTION__, packet->data, packet->data_size); } @@ -927,10 +875,8 @@ switch (cmd) { case RESET_BUS: DBGMSG(ohci->id, "devctl: Bus reset requested%s", - ((host->attempt_root || attempt_root) ? - " and attempting to become root" : "")); - set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ? - 0x80 : 0)); + attempt_root ? " and attempting to become root" : ""); + set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0)); break; case GET_CYCLE_COUNTER: @@ -975,6 +921,7 @@ } else { MOD_DEC_USE_COUNT; } + retval = 1; break; case ISO_LISTEN_CHANNEL: @@ -982,9 +929,9 @@ u64 mask; if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0 listen channel %d is out of range", - arg); + PRINT(KERN_ERR, ohci->id, + "%s: IS0 listen channel %d is out of range", + __FUNCTION__, arg); return -EFAULT; } @@ -993,9 +940,9 @@ spin_lock_irqsave(&ohci->IR_channel_lock, flags); if (ohci->ISO_channel_usage & mask) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0 listen channel %d is already used", - arg); + PRINT(KERN_ERR, ohci->id, + "%s: IS0 listen channel %d is already used", + __FUNCTION__, arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; } @@ -1018,9 +965,9 @@ u64 mask; if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0 unlisten channel %d is out of range", - arg); + PRINT(KERN_ERR, ohci->id, + "%s: IS0 unlisten channel %d is out of range", + __FUNCTION__, arg); return -EFAULT; } @@ -1029,9 +976,9 @@ spin_lock_irqsave(&ohci->IR_channel_lock, flags); if (!(ohci->ISO_channel_usage & mask)) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0 unlisten channel %d is not used", - arg); + PRINT(KERN_ERR, ohci->id, + "%s: IS0 unlisten channel %d is not used", + __FUNCTION__, arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; } @@ -1134,10 +1081,17 @@ /* Die right here an now */ if (event & OHCI1394_unrecoverableError) { PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!"); - remove_card(ohci); return; } + if (event & OHCI1394_cycleInconsistent) { + /* We subscribe to the cycleInconsistent event only to + * clear the corresponding event bit... otherwise, + * isochronous cycleMatch DMA wont work. */ + DBGMSG(ohci->id, "OHCI1394_cycleInconsistent"); + event &= ~OHCI1394_cycleInconsistent; + } + if (event & OHCI1394_busReset) { /* The busReset event bit can't be cleared during the * selfID phase, so we disable busReset interrupts, to @@ -1157,8 +1111,8 @@ spin_unlock_irqrestore(&ohci->event_lock, flags); if (!host->in_bus_reset) { DBGMSG(ohci->id, "irq_handler: Bus reset requested%s", - ((host->attempt_root || attempt_root) ? - " and attempting to become root" : "")); + (attempt_root) ? " and attempting to become root" + : ""); /* Subsystem call */ hpsb_bus_reset(ohci->host); @@ -1229,9 +1183,9 @@ else tasklet_schedule(&d->task); } - if (ohci->video_tmpl) - ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent, - 0); + + ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0); + event &= ~OHCI1394_isochRx; } if (event & OHCI1394_isochTx) { @@ -1244,9 +1198,9 @@ DBGMSG(ohci->id, "Got isochTx interrupt " "status=0x%08x isoXmitIntEvent=%08x", reg_read(ohci, d->ctrlSet), isoXmitIntEvent); - if (ohci->video_tmpl) - ohci->video_tmpl->irq_handler(ohci->id, 0, - isoXmitIntEvent); + + ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent); + if (isoXmitIntEvent & 0x1) { if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "isochTx"); @@ -1305,8 +1259,8 @@ /* Finally, we clear the busReset event and reenable * the busReset interrupt. */ spin_lock_irqsave(&ohci->event_lock, flags); - reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); event &= ~OHCI1394_selfIDComplete; } @@ -1353,7 +1307,7 @@ { int length = -1; - if (d->ctx < 2) { /* Async Receive Response/Request */ + if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) { length = TCODE_SIZE[tcode]; if (length == 0) { if (offset + 12 >= d->buf_size) { @@ -1364,7 +1318,7 @@ } length += 20; } - } else if (d->ctx == 2) { /* Iso receive */ + } else if (d->type == DMA_CTX_ISO) { /* Assumption: buffer fill mode with header/trailer */ length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; } @@ -1394,11 +1348,8 @@ offset = d->buf_offset; buf_ptr = d->buf_cpu[idx] + offset/4; - dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status)); rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; - bytes_left = d->buf_size - rescount - offset; - dma_cache_wback_inv(buf_ptr, bytes_left); while (bytes_left > 0) { tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; @@ -1450,7 +1401,6 @@ insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; - dma_cache_wback_inv(buf_ptr, d->buf_size); offset=0; while (split_left >= d->buf_size) { @@ -1460,7 +1410,6 @@ insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; - dma_cache_wback_inv(buf_ptr, d->buf_size); } if (split_left > 0) { @@ -1507,8 +1456,6 @@ d->ctx); #endif - dma_cache_wback_inv(&(d->prg_cpu[idx]->status), - sizeof(d->prg_cpu[idx]->status)); rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; bytes_left = d->buf_size - rescount - offset; @@ -1556,6 +1503,15 @@ /* this packet hasn't been sent yet*/ break; + if (!(ack & 0x10)) { + /* XXX: This is an OHCI evt_* code. We need to handle + * this specially! For right now, we just fake an + * ackx_send_error. */ + PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x", + ack & 0xf); + ack = (ack & 0xffe0) | ACK_BUSY_A; + } + #ifdef OHCI1394_DEBUG if (datasize) DBGMSG(ohci->id, @@ -1647,6 +1603,11 @@ } if ((*d)->spb) kfree((*d)->spb); + /* clear ISO context usage bit */ + if ((*d)->type == DMA_CTX_ISO) { + clear_bit((*d)->ctx, &ohci->ir_ctx_usage); + } + kfree(*d); *d = NULL; @@ -1654,15 +1615,21 @@ } static struct dma_rcv_ctx * -alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc, - int buf_size, int split_buf_size, - int ctrlSet, int ctrlClear, int cmdPtr) +alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc, + int buf_size, int split_buf_size, int context_base) { - struct dma_rcv_ctx *d=NULL; + struct dma_rcv_ctx *d; int i; - d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), - GFP_KERNEL); + if (type == DMA_CTX_ISO) { + /* try to claim the ISO context usage bit */ + if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) { + PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx); + return NULL; + } + } + + d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL); if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx"); @@ -1671,21 +1638,17 @@ memset (d, 0, sizeof (struct dma_rcv_ctx)); - d->ohci = (void *)ohci; + d->ohci = ohci; + d->type = type; d->ctx = ctx; d->num_desc = num_desc; d->buf_size = buf_size; d->split_buf_size = split_buf_size; - d->ctrlSet = ctrlSet; - d->ctrlClear = ctrlClear; - d->cmdPtr = cmdPtr; - - d->buf_cpu = NULL; - d->buf_bus = NULL; - d->prg_cpu = NULL; - d->prg_bus = NULL; - d->spb = NULL; + + d->ctrlSet = context_base + OHCI1394_ContextControlSet; + d->ctrlClear = context_base + OHCI1394_ContextControlClear; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); @@ -1784,36 +1747,47 @@ kfree((*d)->prg_bus); } + /* clear the ISO context usage bit */ + if ((*d)->type == DMA_CTX_ISO) { + clear_bit((*d)->ctx, &ohci->it_ctx_usage); + } + kfree(*d); *d = NULL; return 0; } static struct dma_trm_ctx * -alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc, - int ctrlSet, int ctrlClear, int cmdPtr) +alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc, + int context_base) { - struct dma_trm_ctx *d=NULL; + struct dma_trm_ctx *d; int i; - d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), - GFP_KERNEL); + if (type == DMA_CTX_ISO) { + /* try to claim the ISO context usage bit */ + if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) { + PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx); + return NULL; + } + } + + d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL); - if (d==NULL) { + if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx"); return NULL; } memset (d, 0, sizeof (struct dma_trm_ctx)); - d->ohci = (void *)ohci; + d->ohci = ohci; + d->type = type; d->ctx = ctx; d->num_desc = num_desc; - d->ctrlSet = ctrlSet; - d->ctrlClear = ctrlClear; - d->cmdPtr = cmdPtr; - d->prg_cpu = NULL; - d->prg_bus = NULL; + d->ctrlSet = context_base + OHCI1394_ContextControlSet; + d->ctrlClear = context_base + OHCI1394_ContextControlClear; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), GFP_KERNEL); @@ -1827,7 +1801,7 @@ memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); - for (i=0; inum_desc; i++) { + for (i = 0; i < d->num_desc; i++) { d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, sizeof(struct at_dma_prg), d->prg_bus+i); @@ -1890,6 +1864,21 @@ #define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val))) +static inline void cf_put_str(struct config_rom_ptr *cr, const char *str) +{ + int t; + char fourb[4]; + + while (str[0]) { + memset(fourb, 0, 4); + for (t = 0; t < 4 && str[t]; t++) + fourb[t] = str[t]; + cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]); + str += strlen(str) < 4 ? strlen(str) : 4; + } + return; +} + static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit) { *cr->unitdir[unit].start = @@ -1956,7 +1945,8 @@ /* Root directory */ cf_unit_begin(&cr, 1); - cf_put_keyval(&cr, 0x03, 0x00005e); /* Vendor ID */ + /* Vendor ID */ + cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF); cf_put_refer(&cr, 0x81, 2); /* Textual description unit */ cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */ /* NOTE: Add other unit referers here, and append at bottom */ @@ -1966,9 +1956,7 @@ cf_unit_begin(&cr, 2); cf_put_keyval(&cr, 0, 0); cf_put_1quad(&cr, 0); - cf_put_4bytes(&cr, 'L', 'i', 'n', 'u'); - cf_put_4bytes(&cr, 'x', ' ', '1', '3'); - cf_put_4bytes(&cr, '9', '4', 0x0, 0x0); + cf_put_str(&cr, "Linux OHCI-1394"); cf_unit_end(&cr); ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu; @@ -1986,13 +1974,15 @@ return ohci->csr_config_rom_length * 4; } -int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data, - quadlet_t compare, int sel) +static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, + quadlet_t data, quadlet_t compare) { + struct ti_ohci *ohci = host->hostdata; int i; - reg_write(ohci, OHCI1394_CSRData, *data); + + reg_write(ohci, OHCI1394_CSRData, data); reg_write(ohci, OHCI1394_CSRCompareData, compare); - reg_write(ohci, OHCI1394_CSRControl, sel & 0x3); + reg_write(ohci, OHCI1394_CSRControl, reg & 0x3); for (i = 0; i < OHCI_LOOP_COUNT; i++) { if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) @@ -2001,68 +1991,58 @@ mdelay(1); } - *data = reg_read(ohci, OHCI1394_CSRData); - return 0; -} - -static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, - quadlet_t data, quadlet_t compare) -{ - struct ti_ohci *ohci=host->hostdata; - - ohci_compare_swap (ohci, &data, compare, reg); - - return data; + return reg_read(ohci, OHCI1394_CSRData); } -static struct hpsb_host_template ohci_template = { - name: OHCI1394_DRIVER_NAME, - initialize_host: ohci_initialize, - release_host: ohci_remove, +static struct hpsb_host_operations ohci1394_ops = { get_rom: ohci_get_rom, transmit_packet: ohci_transmit, devctl: ohci_devctl, hw_csr_reg: ohci_hw_csr_reg, }; +static struct hpsb_host_driver *ohci1394_driver; + + + +/*********************************** + * PCI Driver Interface functions * + ***********************************/ -#define FAIL(fmt, args...) \ +#define FAIL(err, fmt, args...) \ do { \ PRINT_G(KERN_ERR, fmt , ## args); \ - remove_card(ohci); \ - return 1; \ + ohci1394_pci_remove(dev); \ + return err; \ } while(0) -static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent) +static int __devinit ohci1394_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - struct ti_ohci *ohci; /* shortcut to currently handled device */ - struct hpsb_host *host; - unsigned long ohci_base, ohci_len; + static unsigned int card_id_counter = 0; static int version_printed = 0; + struct hpsb_host *host; + struct ti_ohci *ohci; /* shortcut to currently handled device */ + unsigned long ohci_base, ohci_len; + int i; + if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); - if (pci_enable_device(dev)) { - /* Skip ID's that fail */ - PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d", - card_id_counter++); - return -ENXIO; - } + if (pci_enable_device(dev)) + FAIL(-ENXIO, "Failed to enable OHCI hardware %d", + card_id_counter++); pci_set_master(dev); - host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci)); - if (!host) { - PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure"); - return -ENOMEM; - } + host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci)); + if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); + ohci = host->hostdata; - ohci->host = host; - INIT_LIST_HEAD(&ohci->list); ohci->id = card_id_counter++; ohci->dev = dev; - host->pdev = dev; ohci->host = host; + host->pdev = dev; pci_set_drvdata(dev, ohci); /* We don't want hardware swapping */ @@ -2090,8 +2070,54 @@ &ohci->csr_config_rom_bus); OHCI_DMA_ALLOC("consistent csr_config_rom"); if (ohci->csr_config_rom_cpu == NULL) - FAIL("Failed to allocate buffer config rom"); + FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + + ohci_base = pci_resource_start(dev, 0); + ohci_len = pci_resource_len(dev, 0); + + if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME)) + FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.", + ohci_base, ohci_len); + + ohci->registers = ioremap(ohci_base, ohci_len); + + if (ohci->registers == NULL) + FAIL(-ENXIO, "Failed to remap registers - card not accessible"); + + DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); + + + /* Start off with a softreset, to clear everything to a sane + * state. This will also set Link Power State (LPS), which we + * need in order to start accessing most of the registers. */ + ohci_soft_reset(ohci); + + /* determinte the number of available IR and IT contexts right away, + because they need to be known for alloc_dma_*_ctx() */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->ir_ctx_usage = 0; + + /* set the usage bits for non-existent contexts so they can't be allocated */ + for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++) + __set_bit(i, &ohci->ir_ctx_usage); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + ohci->it_ctx_usage = 0; + + /* set the usage bits for non-existent contexts so they can't be allocated */ + for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++) + __set_bit(i, &ohci->it_ctx_usage); + + /* * self-id dma buffer allocation */ @@ -2100,103 +2126,101 @@ &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); if (ohci->selfid_buf_cpu == NULL) - FAIL("Failed to allocate DMA buffer for self-id packets"); + FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " "8Kb boundary... may cause problems on some CXD3222 chip", ohci->selfid_buf_cpu); - ohci->it_context = - alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC, - OHCI1394_IsoXmitContextControlSet, - OHCI1394_IsoXmitContextControlClear, - OHCI1394_IsoXmitCommandPtr); - - if (ohci->it_context == NULL) - FAIL("Failed to allocate IT context"); - - ohci_base = pci_resource_start(dev, 0); - ohci_len = pci_resource_len(dev, 0); - - if (!request_mem_region (ohci_base, ohci_len, host->template->name)) - FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.", - ohci_base, ohci_len); - - ohci->registers = ioremap(ohci_base, ohci_len); - - if (ohci->registers == NULL) - FAIL("Failed to remap registers - card not accessible"); - - DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", - ohci->registers); + /* No self-id errors at startup */ + ohci->self_id_errors = 0; + /* AR DMA request context allocation */ ohci->ar_req_context = - alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC, + alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, - OHCI1394_AsReqRcvContextControlSet, - OHCI1394_AsReqRcvContextControlClear, - OHCI1394_AsReqRcvCommandPtr); + OHCI1394_AsReqRcvContextBase); if (ohci->ar_req_context == NULL) - FAIL("Failed to allocate AR Req context"); + FAIL(-ENOMEM, "Failed to allocate AR Req context"); + /* AR DMA response context allocation */ ohci->ar_resp_context = - alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC, + alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, - OHCI1394_AsRspRcvContextControlSet, - OHCI1394_AsRspRcvContextControlClear, - OHCI1394_AsRspRcvCommandPtr); + OHCI1394_AsRspRcvContextBase); if (ohci->ar_resp_context == NULL) - FAIL("Failed to allocate AR Resp context"); + FAIL(-ENOMEM, "Failed to allocate AR Resp context"); + /* AT DMA request context */ ohci->at_req_context = - alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC, - OHCI1394_AsReqTrContextControlSet, - OHCI1394_AsReqTrContextControlClear, - OHCI1394_AsReqTrCommandPtr); + alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, + OHCI1394_AsReqTrContextBase); if (ohci->at_req_context == NULL) - FAIL("Failed to allocate AT Req context"); + FAIL(-ENOMEM, "Failed to allocate AT Req context"); + /* AT DMA response context */ ohci->at_resp_context = - alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC, - OHCI1394_AsRspTrContextControlSet, - OHCI1394_AsRspTrContextControlClear, - OHCI1394_AsRspTrCommandPtr); + alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, + OHCI1394_AsRspTrContextBase); if (ohci->at_resp_context == NULL) - FAIL("Failed to allocate AT Resp context"); + FAIL(-ENOMEM, "Failed to allocate AT Resp context"); + /* IR DMA context */ ohci->ir_context = - alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC, + alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, - OHCI1394_IsoRcvContextControlSet, - OHCI1394_IsoRcvContextControlClear, - OHCI1394_IsoRcvCommandPtr); + OHCI1394_IsoRcvContextBase); if (ohci->ir_context == NULL) - FAIL("Failed to allocate IR context"); + FAIL(-ENOMEM, "Failed to allocate IR context"); + + + /* IT DMA context allocation */ + ohci->it_context = + alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC, + OHCI1394_IsoXmitContextBase); + + if (ohci->it_context == NULL) + FAIL(-ENOMEM, "Failed to allocate IT context"); ohci->ISO_channel_usage = 0; spin_lock_init(&ohci->IR_channel_lock); + for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { + ohci->irq_hooks[i].irq_handler = NULL; + ohci->irq_hooks[i].data = NULL; + } + if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) - FAIL("Failed to allocate shared interrupt %d", dev->irq); + FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); + + ohci_initialize(ohci); /* Tell the highlevel this host is ready */ - highlevel_add_one_host (host); + hpsb_add_host(host); return 0; #undef FAIL } -static void remove_card(struct ti_ohci *ohci) +static void __devexit ohci1394_pci_remove(struct pci_dev *pdev) { + struct ti_ohci *ohci; quadlet_t buf; + ohci = pci_get_drvdata(pdev); + if (!ohci) + return; + + if (ohci->host) + hpsb_remove_host(ohci->host); + /* Soft reset before we start */ ohci_soft_reset(ohci); @@ -2267,8 +2291,41 @@ #endif /* CONFIG_ALL_PPC */ pci_set_drvdata(ohci->dev, NULL); + hpsb_unref_host(ohci->host); } +#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) + +static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { + { + class: PCI_CLASS_FIREWIRE_OHCI, + class_mask: 0x00ffffff, + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); + +static struct pci_driver ohci1394_pci_driver = { + name: OHCI1394_DRIVER_NAME, + id_table: ohci1394_pci_tbl, + probe: ohci1394_pci_probe, + remove: __devexit_p(ohci1394_pci_remove), +}; + + + +/*********************************** + * OHCI1394 Video Interface * + ***********************************/ + +/* essentially the only purpose of this code is to allow another + module to hook into ohci's interrupt handler */ + void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) { int i=0; @@ -2288,111 +2345,96 @@ if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); } -int ohci1394_register_video(struct ti_ohci *ohci, - struct video_template *tmpl) +static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, + quadlet_t isoRecvEvent, + quadlet_t isoXmitEvent) { - if (ohci->video_tmpl) - return -ENFILE; - ohci->video_tmpl = tmpl; - MOD_INC_USE_COUNT; - return 0; + int i; + for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { + if(ohci->irq_hooks[i].irq_handler != NULL) { + ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent, + ohci->irq_hooks[i].data); + } + } } - -void ohci1394_unregister_video(struct ti_ohci *ohci, - struct video_template *tmpl) + +int ohci1394_hook_irq(struct ti_ohci *ohci, + void (*irq_handler) (int, quadlet_t, quadlet_t, void *), + void *data) { - if (ohci->video_tmpl != tmpl) { - PRINT(KERN_ERR, ohci->id, - "Trying to unregister wrong video device"); - } else { - ohci->video_tmpl = NULL; - MOD_DEC_USE_COUNT; + int i; + + /* find a free slot */ + for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { + if(ohci->irq_hooks[i].irq_handler == NULL) + break; } + + if(i >= OHCI1394_MAX_IRQ_HOOKS) + return -EBUSY; + + ohci->irq_hooks[i].irq_handler = irq_handler; + ohci->irq_hooks[i].data = data; + + /* ohci1394 will never be unloaded while an IRQ hook is + in use, because the user must reference this symbol */ + + return 0; } -#if 0 -int ohci1394_request_channel(struct ti_ohci *ohci, int channel) +void ohci1394_unhook_irq(struct ti_ohci *ohci, + void (*irq_handler) (int, quadlet_t, quadlet_t, void *), + void *data) { - int csrSel; - quadlet_t chan, data1=0, data2=0; - int timeout = 32; - - if (channel<32) { - chan = 1<id, "request_channel timeout"); - return -1; + int i; + + for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { + if( (ohci->irq_hooks[i].irq_handler == irq_handler) && + (ohci->irq_hooks[i].data == data) ) + break; } - while (timeout--) { - if (data1 & chan) { - PRINT(KERN_INFO, ohci->id, - "request channel %d failed", channel); - return -1; - } - data2 = data1; - data1 |= chan; - if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) { - PRINT(KERN_INFO, ohci->id, "request_channel timeout"); - return -1; - } - if (data1==data2) { - PRINT(KERN_INFO, ohci->id, - "request channel %d succeded", channel); - return 0; - } + + if(i < OHCI1394_MAX_IRQ_HOOKS) { + ohci->irq_hooks[i].irq_handler = NULL; + ohci->irq_hooks[i].data = NULL; } - PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel); - return -1; } -#endif EXPORT_SYMBOL(ohci1394_stop_context); -EXPORT_SYMBOL(ohci1394_register_video); -EXPORT_SYMBOL(ohci1394_unregister_video); +EXPORT_SYMBOL(ohci1394_hook_irq); +EXPORT_SYMBOL(ohci1394_unhook_irq); -MODULE_AUTHOR("Sebastien Rougeaux "); -MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); -MODULE_LICENSE("GPL"); -static void __devexit ohci1394_remove_one(struct pci_dev *pdev) -{ - struct ti_ohci *ohci = pci_get_drvdata(pdev); - if (ohci) { - remove_card (ohci); - pci_set_drvdata(pdev, NULL); - } -} +/*********************************** + * General module initialization * + ***********************************/ -static struct pci_driver ohci1394_driver = { - name: OHCI1394_DRIVER_NAME, - id_table: ohci1394_pci_tbl, - probe: ohci1394_add_one, - remove: __devexit_p(ohci1394_remove_one), -}; +MODULE_AUTHOR("Sebastien Rougeaux "); +MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); +MODULE_LICENSE("GPL"); static void __exit ohci1394_cleanup (void) { - hpsb_unregister_lowlevel(&ohci_template); - pci_unregister_driver(&ohci1394_driver); + pci_unregister_driver(&ohci1394_pci_driver); + hpsb_unregister_lowlevel(ohci1394_driver); } static int __init ohci1394_init(void) { int ret; - if (hpsb_register_lowlevel(&ohci_template)) { - PRINT_G(KERN_ERR, "Registering failed"); - return -ENXIO; - } - if ((ret = pci_module_init(&ohci1394_driver))) { - PRINT_G(KERN_ERR, "PCI module init failed"); - hpsb_unregister_lowlevel(&ohci_template); + + ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops, + OHCI1394_DRIVER_NAME); + if (!ohci1394_driver) { + PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed"); + return -ENOMEM; + } + + ret = pci_module_init(&ohci1394_pci_driver); + if (ret < 0) { + PRINT_G(KERN_ERR, "pci_module_init failed"); + hpsb_unregister_lowlevel(ohci1394_driver); return ret; } return ret; diff -urN linux-2.4.18/drivers/ieee1394/ohci1394.h linux-2.4.19-pre5/drivers/ieee1394/ohci1394.h --- linux-2.4.18/drivers/ieee1394/ohci1394.h Sun Feb 17 11:38:52 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/ohci1394.h Sat Mar 30 22:55:39 2002 @@ -76,9 +76,13 @@ quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */ }; +/* identify whether a DMA context is asynchronous or isochronous */ +enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO }; + /* DMA receive context */ struct dma_rcv_ctx { - void *ohci; + struct ti_ohci *ohci; + enum context_type type; int ctx; unsigned int num_desc; @@ -105,7 +109,8 @@ /* DMA transmit context */ struct dma_trm_ctx { - void *ohci; + struct ti_ohci *ohci; + enum context_type type; int ctx; unsigned int num_desc; @@ -133,18 +138,9 @@ int cmdPtr; }; -/* video device template */ -struct video_template { - void (*irq_handler) (int card, quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent); -}; - - struct ti_ohci { int id; /* sequential card number */ - struct list_head list; - struct pci_dev *dev; u32 state; @@ -175,11 +171,13 @@ struct dma_rcv_ctx *ir_context; spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; - + unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + /* iso transmit */ struct dma_trm_ctx *it_context; int nb_iso_xmit_ctx; - + unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ + u64 ISO_channel_usage; /* IEEE-1394 part follows */ @@ -192,8 +190,15 @@ int self_id_errors; - /* video device */ - struct video_template *video_tmpl; + /* IRQ hooks, for video1394 and dv1394 */ + +#define OHCI1394_MAX_IRQ_HOOKS 16 + + struct ohci1394_irq_hook { + void (*irq_handler) (int card, quadlet_t isoRecvEvent, + quadlet_t isoXmitEvent, void *data); + void *data; + } irq_hooks[OHCI1394_MAX_IRQ_HOOKS]; /* Swap the selfid buffer? */ unsigned int selfid_swap:1; @@ -230,6 +235,12 @@ /* 2 KiloBytes of register space */ #define OHCI1394_REGISTER_SIZE 0x800 +/* Offsets relative to context bases defined below */ + +#define OHCI1394_ContextControlSet 0x000 +#define OHCI1394_ContextControlClear 0x004 +#define OHCI1394_ContextCommandPtr 0x00C + /* register map */ #define OHCI1394_Version 0x000 #define OHCI1394_GUID_ROM 0x004 @@ -281,27 +292,37 @@ #define OHCI1394_PhyReqFilterLoSet 0x118 #define OHCI1394_PhyReqFilterLoClear 0x11C #define OHCI1394_PhyUpperBound 0x120 + +#define OHCI1394_AsReqTrContextBase 0x180 #define OHCI1394_AsReqTrContextControlSet 0x180 #define OHCI1394_AsReqTrContextControlClear 0x184 #define OHCI1394_AsReqTrCommandPtr 0x18C + +#define OHCI1394_AsRspTrContextBase 0x1A0 #define OHCI1394_AsRspTrContextControlSet 0x1A0 #define OHCI1394_AsRspTrContextControlClear 0x1A4 #define OHCI1394_AsRspTrCommandPtr 0x1AC + +#define OHCI1394_AsReqRcvContextBase 0x1C0 #define OHCI1394_AsReqRcvContextControlSet 0x1C0 #define OHCI1394_AsReqRcvContextControlClear 0x1C4 #define OHCI1394_AsReqRcvCommandPtr 0x1CC + +#define OHCI1394_AsRspRcvContextBase 0x1E0 #define OHCI1394_AsRspRcvContextControlSet 0x1E0 #define OHCI1394_AsRspRcvContextControlClear 0x1E4 #define OHCI1394_AsRspRcvCommandPtr 0x1EC /* Isochronous transmit registers */ -/* Add (32 * n) for context n */ +/* Add (16 * n) for context n */ +#define OHCI1394_IsoXmitContextBase 0x200 #define OHCI1394_IsoXmitContextControlSet 0x200 #define OHCI1394_IsoXmitContextControlClear 0x204 #define OHCI1394_IsoXmitCommandPtr 0x20C /* Isochronous receive registers */ /* Add (32 * n) for context n */ +#define OHCI1394_IsoRcvContextBase 0x400 #define OHCI1394_IsoRcvContextControlSet 0x400 #define OHCI1394_IsoRcvContextControlClear 0x404 #define OHCI1394_IsoRcvCommandPtr 0x40C @@ -342,14 +363,39 @@ #define DMA_CTL_BRANCH 0x000c0000 #define DMA_CTL_WAIT 0x00030000 +/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */ +#define EVT_NO_STATUS 0x0 /* No event status */ +#define EVT_RESERVED 0x1 /* Reserved, not used !!! */ +#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */ +#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack + arrived, or recv'd ack had a parity error */ +#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet + truncated */ +#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO + packet */ +#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occured while host was + reading a descriptor block */ +#define EVT_DATA_READ 0x7 /* An error occured while host controller was + attempting to read from host memory in the data + stage of descriptor processing */ +#define EVT_DATA_WRITE 0x8 /* An error occured while host controller was + attempting to write either during the data stage + of descriptor processing, or when processing a single + 16-bit host memory write */ +#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as + being a synthesized bus reset packet */ + #define OHCI1394_TCODE_PHY 0xE void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg); struct ti_ohci *ohci1394_get_struct(int card_num); -int ohci1394_register_video(struct ti_ohci *ohci, - struct video_template *tmpl); -void ohci1394_unregister_video(struct ti_ohci *ohci, - struct video_template *tmpl); +int ohci1394_hook_irq(struct ti_ohci *ohci, + void (*irq_handler) (int, quadlet_t, quadlet_t, void *), + void *data); + +void ohci1394_unhook_irq(struct ti_ohci *ohci, + void (*irq_handler) (int, quadlet_t, quadlet_t, void *), + void *data); #endif diff -urN linux-2.4.18/drivers/ieee1394/pcilynx.c linux-2.4.19-pre5/drivers/ieee1394/pcilynx.c --- linux-2.4.18/drivers/ieee1394/pcilynx.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/pcilynx.c Sat Mar 30 22:55:39 2002 @@ -42,10 +42,6 @@ #include "pcilynx.h" -#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START -#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work. -#endif - /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) /* print card specific information */ @@ -60,9 +56,8 @@ #endif -static struct ti_lynx cards[MAX_PCILYNX_CARDS]; -static int num_of_cards = 0; -static struct hpsb_host_template lynx_template; +static struct hpsb_host_driver *lynx_driver; +static unsigned int card_id; /* * PCL handling functions. @@ -143,10 +138,6 @@ #endif -static int add_card(struct pci_dev *dev, const struct pci_device_id *devid); -static void remove_card(struct pci_dev *dev); - - /*********************************** * IEEE-1394 functionality section * @@ -161,8 +152,9 @@ unsigned long flags; if (addr > 15) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": PHY register address %d out of range", addr); + PRINT(KERN_ERR, lynx->id, + "%s: PHY register address %d out of range", + __FUNCTION__, addr); return -1; } @@ -173,8 +165,8 @@ retval = reg_read(lynx, LINK_PHY); if (i > 10000) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": runaway loop, aborting"); + PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting", + __FUNCTION__); retval = -1; break; } @@ -196,14 +188,14 @@ unsigned long flags; if (addr > 15) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": PHY register address %d out of range", addr); + PRINT(KERN_ERR, lynx->id, + "%s: PHY register address %d out of range", __FUNCTION__, addr); return -1; } if (val > 0xff) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": PHY register value %d out of range", val); + PRINT(KERN_ERR, lynx->id, + "%s: PHY register value %d out of range", __FUNCTION__, val); return -1; } @@ -222,8 +214,8 @@ int reg; if (page > 7) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": PHY page %d out of range", page); + PRINT(KERN_ERR, lynx->id, + "%s: PHY page %d out of range", __FUNCTION__, page); return -1; } @@ -244,8 +236,8 @@ int reg; if (port > 15) { - PRINT(KERN_ERR, lynx->id, __FUNCTION__ - ": PHY port %d out of range", port); + PRINT(KERN_ERR, lynx->id, + "%s: PHY port %d out of range", __FUNCTION__, port); return -1; } @@ -377,7 +369,7 @@ hpsb_selfid_complete(host, phyid, isroot); - if (host->in_bus_reset) return; + if (host->in_bus_reset) return; /* in bus reset again */ if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); reg_set_bits(lynx, LINK_CONTROL, @@ -440,160 +432,7 @@ } -#if 0 -static int lynx_detect(struct hpsb_host_template *tmpl) -{ - struct hpsb_host *host; - int i; - - init_driver(); - - for (i = 0; i < num_of_cards; i++) { - host = hpsb_get_host(tmpl, 0); - if (host == NULL) { - /* simply don't init more after out of mem */ - return i; - } - host->hostdata = &cards[i]; - cards[i].host = host; - } - - return num_of_cards; -} -#endif - -static int lynx_initialize(struct hpsb_host *host) -{ - struct ti_lynx *lynx = host->hostdata; - struct ti_pcl pcl; - int i; - u32 *pcli; - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - - lynx->async.queue = NULL; - - pcl.next = pcl_bus(lynx, lynx->rcv_pcl); - put_pcl(lynx, lynx->rcv_pcl_start, &pcl); - - pcl.next = PCL_NEXT_INVALID; - pcl.async_error_next = PCL_NEXT_INVALID; -#ifdef __BIG_ENDIAN - pcl.buffer[0].control = PCL_CMD_RCV | 16; - pcl.buffer[1].control = PCL_LAST_BUFF | 4080; -#else - pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16; - pcl.buffer[1].control = PCL_LAST_BUFF | 4080; -#endif - pcl.buffer[0].pointer = lynx->rcv_page_dma; - pcl.buffer[1].pointer = lynx->rcv_page_dma + 16; - put_pcl(lynx, lynx->rcv_pcl, &pcl); - - pcl.next = pcl_bus(lynx, lynx->async.pcl); - pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl); - put_pcl(lynx, lynx->async.pcl_start, &pcl); - - pcl.next = pcl_bus(lynx, lynx->iso_send.pcl); - pcl.async_error_next = PCL_NEXT_INVALID; - put_pcl(lynx, lynx->iso_send.pcl_start, &pcl); - - pcl.next = PCL_NEXT_INVALID; - pcl.async_error_next = PCL_NEXT_INVALID; - pcl.buffer[0].control = PCL_CMD_RCV | 4; -#ifndef __BIG_ENDIAN - pcl.buffer[0].control |= PCL_BIGENDIAN; -#endif - pcl.buffer[1].control = PCL_LAST_BUFF | 2044; - - for (i = 0; i < NUM_ISORCV_PCL; i++) { - int page = i / ISORCV_PER_PAGE; - int sec = i % ISORCV_PER_PAGE; - - pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] - + sec * MAX_ISORCV_SIZE; - pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4; - put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl); - } - - pcli = (u32 *)&pcl; - for (i = 0; i < NUM_ISORCV_PCL; i++) { - pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]); - } - put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); - - /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */ - reg_write(lynx, FIFO_SIZES, 0x003030a0); - /* 20 byte threshold before triggering PCI transfer */ - reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); - /* threshold on both send FIFOs before transmitting: - FIFO size - cache line size - 1 */ - i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff; - i = 0x30 - i - 1; - reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i); - - reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); - - reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT - | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET - | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK - | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC - | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW - | LINK_INT_ATF_UNDERFLOW); - - reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); - reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); - reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), - DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST - | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST - | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); - - run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); - - reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); - reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); - reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0); - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); - - run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV); - - reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID - | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN - | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN - | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX); - - if (!lynx->phyic.reg_1394a) { - /* attempt to enable contender bit -FIXME- would this work - * elsewhere? */ - reg_set_bits(lynx, GPIO_CTRL_A, 0x1); - reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); - } else { - /* set the contender bit in the extended PHY register - * set. (Should check that bis 0,1,2 (=0xE0) is set - * in register 2?) - */ - i = get_phy_reg(lynx, 4); - if (i != -1) set_phy_reg(lynx, 4, i | 0x40); - } - - return 1; -} - -static void lynx_release(struct hpsb_host *host) -{ - struct ti_lynx *lynx; - - if (host != NULL) { - lynx = host->hostdata; - remove_card(lynx->dev); - } else { -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); -#endif - } -} - +/* called from subsystem core */ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) { struct ti_lynx *lynx = host->hostdata; @@ -642,6 +481,8 @@ return 1; } + +/* called from subsystem core */ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) { struct ti_lynx *lynx = host->hostdata; @@ -666,9 +507,7 @@ arg |= (retval == -1 ? 63 : retval); retval = 0; - PRINT(KERN_INFO, lynx->id, "resetting bus on request%s", - (host->attempt_root ? " and attempting to become root" - : "")); + PRINT(KERN_INFO, lynx->id, "resetting bus on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; @@ -721,6 +560,8 @@ } else { MOD_DEC_USE_COUNT; } + + retval = 1; break; case ISO_LISTEN_CHANNEL: @@ -773,7 +614,7 @@ static struct file_operations aux_ops = { - OWNER_THIS_MODULE + owner: THIS_MODULE, read: mem_read, write: mem_write, poll: aux_poll, @@ -794,46 +635,35 @@ static int mem_open(struct inode *inode, struct file *file) { - int cid = MINOR(inode->i_rdev); + int cid = minor(inode->i_rdev); enum { t_rom, t_aux, t_ram } type; struct memdata *md; - V22_COMPAT_MOD_INC_USE_COUNT; - if (cid < PCILYNX_MINOR_AUX_START) { /* just for completeness */ - V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } else if (cid < PCILYNX_MINOR_ROM_START) { cid -= PCILYNX_MINOR_AUX_START; - if (cid >= num_of_cards || !cards[cid].aux_port) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (cid >= num_of_cards || !cards[cid].aux_port) return -ENXIO; - } type = t_aux; } else if (cid < PCILYNX_MINOR_RAM_START) { cid -= PCILYNX_MINOR_ROM_START; - if (cid >= num_of_cards || !cards[cid].local_rom) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (cid >= num_of_cards || !cards[cid].local_rom) return -ENXIO; - } type = t_rom; } else { /* WARNING: Know what you are doing when opening RAM. * It is currently used inside the driver! */ cid -= PCILYNX_MINOR_RAM_START; - if (cid >= num_of_cards || !cards[cid].local_ram) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (cid >= num_of_cards || !cards[cid].local_ram) return -ENXIO; - } type = t_ram; } md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); - if (md == NULL) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (md == NULL) return -ENOMEM; - } md->lynx = &cards[cid]; md->cid = cid; @@ -859,11 +689,7 @@ static int mem_release(struct inode *inode, struct file *file) { - struct memdata *md = (struct memdata *)file->private_data; - - kfree(md); - - V22_COMPAT_MOD_DEC_USE_COUNT; + kfree(file->private_data); return 0; } @@ -1010,8 +836,8 @@ membase = md->lynx->aux_port; break; default: - panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__, - md->lynx->id, md->type); + panic("pcilynx%d: unsupported md->type %d in %s", + md->lynx->id, md->type, __FUNCTION__); } down(&md->lynx->mem_dma_mutex); @@ -1291,6 +1117,7 @@ } } + static void iso_rcv_bh(struct ti_lynx *lynx) { unsigned int idx; @@ -1335,44 +1162,97 @@ } +static void remove_card(struct pci_dev *dev) +{ + struct ti_lynx *lynx; + int i; + + lynx = pci_get_drvdata(dev); + if (!lynx) return; + pci_set_drvdata(dev, NULL); + + switch (lynx->state) { + case is_host: + reg_write(lynx, PCI_INT_ENABLE, 0); + hpsb_remove_host(lynx->host); + case have_intr: + reg_write(lynx, PCI_INT_ENABLE, 0); + free_irq(lynx->dev->irq, lynx); + case have_iomappings: + reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + /* Fix buggy cards with autoboot pin not tied low: */ + reg_write(lynx, DMA0_CHAN_CTRL, 0); + iounmap(lynx->registers); + iounmap(lynx->local_rom); + iounmap(lynx->local_ram); + iounmap(lynx->aux_port); + case have_1394_buffers: + for (i = 0; i < ISORCV_PAGES; i++) { + if (lynx->iso_rcv.page[i]) { + pci_free_consistent(lynx->dev, PAGE_SIZE, + lynx->iso_rcv.page[i], + lynx->iso_rcv.page_dma[i]); + } + } + pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page, + lynx->rcv_page_dma); + case have_aux_buf: +#ifdef CONFIG_IEEE1394_PCILYNX_PORTS + pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, + lynx->mem_dma_buffer_dma); +#endif + case have_pcl_mem: +#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM + pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, + lynx->pcl_mem_dma); +#endif + case clear: + /* do nothing - already freed */ + ; + } + + tasklet_kill(&lynx->iso_rcv.tq); + hpsb_unref_host(lynx->host); +} + + static int __devinit add_card(struct pci_dev *dev, - const struct pci_device_id *devid) + const struct pci_device_id *devid_is_unused) { #define FAIL(fmt, args...) do { \ PRINT_G(KERN_ERR, fmt , ## args); \ - num_of_cards--; \ remove_card(dev); \ - return -1; \ + return error; \ } while (0) + struct hpsb_host *host; struct ti_lynx *lynx; /* shortcut to currently handled device */ - unsigned int i; + struct ti_pcl pcl; + u32 *pcli; + int i; + int error; - if (num_of_cards == MAX_PCILYNX_CARDS) { - PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " - "Adjust MAX_PCILYNX_CARDS in pcilynx.h.", - MAX_PCILYNX_CARDS); - return -1; - } - lynx = &cards[num_of_cards++]; + error = -ENXIO; if (pci_set_dma_mask(dev, 0xffffffff)) - FAIL("DMA address limits not supported for PCILynx hardware %d", - lynx->id); + FAIL("DMA address limits not supported for PCILynx hardware"); if (pci_enable_device(dev)) - FAIL("failed to enable PCILynx hardware %d", lynx->id); + FAIL("failed to enable PCILynx hardware"); pci_set_master(dev); - lynx->host = hpsb_get_host(&lynx_template, 0); - if (!lynx->host) - FAIL("failed to allocate host structure"); - - lynx->state = have_host_struct; - lynx->host->hostdata = lynx; - lynx->id = num_of_cards-1; + error = -ENOMEM; + + host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx)); + if (!host) FAIL("failed to allocate control structure memory"); + + lynx = host->hostdata; + lynx->id = card_id++; lynx->dev = dev; - lynx->host->pdev = dev; + lynx->state = clear; + lynx->host = host; + host->pdev = dev; + pci_set_drvdata(dev, lynx); lynx->lock = SPIN_LOCK_UNLOCKED; lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED; @@ -1435,7 +1315,9 @@ } #endif - reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + /* Fix buggy cards with autoboot pin not tied low: */ + reg_write(lynx, DMA0_CHAN_CTRL, 0); if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, PCILYNX_DRIVER_NAME, lynx)) { @@ -1502,99 +1384,121 @@ PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); } - /* Tell the highlevel this host is ready */ - highlevel_add_one_host (lynx->host); - - return 0; -#undef FAIL -} + lynx->selfid_size = -1; + lynx->phy_reg0 = -1; -static void remove_card(struct pci_dev *dev) -{ - struct ti_lynx *lynx; - int i; + lynx->async.queue = NULL; - lynx = cards; - while (lynx->dev != dev) lynx++; + pcl.next = pcl_bus(lynx, lynx->rcv_pcl); + put_pcl(lynx, lynx->rcv_pcl_start, &pcl); - switch (lynx->state) { - case have_intr: - reg_write(lynx, PCI_INT_ENABLE, 0); - free_irq(lynx->dev->irq, lynx); - case have_iomappings: - reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); - iounmap(lynx->registers); - iounmap(lynx->local_rom); - iounmap(lynx->local_ram); - iounmap(lynx->aux_port); - case have_1394_buffers: - for (i = 0; i < ISORCV_PAGES; i++) { - if (lynx->iso_rcv.page[i]) { - pci_free_consistent(lynx->dev, PAGE_SIZE, - lynx->iso_rcv.page[i], - lynx->iso_rcv.page_dma[i]); - } - } - pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page, - lynx->rcv_page_dma); - case have_aux_buf: -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, - lynx->mem_dma_buffer_dma); + pcl.next = PCL_NEXT_INVALID; + pcl.async_error_next = PCL_NEXT_INVALID; +#ifdef __BIG_ENDIAN + pcl.buffer[0].control = PCL_CMD_RCV | 16; + pcl.buffer[1].control = PCL_LAST_BUFF | 4080; +#else + pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16; + pcl.buffer[1].control = PCL_LAST_BUFF | 4080; #endif - case have_pcl_mem: -#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM - pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, - lynx->pcl_mem_dma); + pcl.buffer[0].pointer = lynx->rcv_page_dma; + pcl.buffer[1].pointer = lynx->rcv_page_dma + 16; + put_pcl(lynx, lynx->rcv_pcl, &pcl); + + pcl.next = pcl_bus(lynx, lynx->async.pcl); + pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl); + put_pcl(lynx, lynx->async.pcl_start, &pcl); + + pcl.next = pcl_bus(lynx, lynx->iso_send.pcl); + pcl.async_error_next = PCL_NEXT_INVALID; + put_pcl(lynx, lynx->iso_send.pcl_start, &pcl); + + pcl.next = PCL_NEXT_INVALID; + pcl.async_error_next = PCL_NEXT_INVALID; + pcl.buffer[0].control = PCL_CMD_RCV | 4; +#ifndef __BIG_ENDIAN + pcl.buffer[0].control |= PCL_BIGENDIAN; #endif - case have_host_struct: - /* FIXME - verify host freeing */ - case clear:; - /* do nothing - already freed */ + pcl.buffer[1].control = PCL_LAST_BUFF | 2044; + + for (i = 0; i < NUM_ISORCV_PCL; i++) { + int page = i / ISORCV_PER_PAGE; + int sec = i % ISORCV_PER_PAGE; + + pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] + + sec * MAX_ISORCV_SIZE; + pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4; + put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl); } - tasklet_kill(&lynx->iso_rcv.tq); + pcli = (u32 *)&pcl; + for (i = 0; i < NUM_ISORCV_PCL; i++) { + pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]); + } + put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); - lynx->state = clear; -} + /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */ + reg_write(lynx, FIFO_SIZES, 0x003030a0); + /* 20 byte threshold before triggering PCI transfer */ + reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); + /* threshold on both send FIFOs before transmitting: + FIFO size - cache line size - 1 */ + i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff; + i = 0x30 - i - 1; + reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i); -#if 0 -static int init_driver() -{ - struct pci_dev *dev = NULL; - int success = 0; + reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); - if (num_of_cards) { - PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); - return 0; - } + reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT + | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET + | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK + | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC + | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW + | LINK_INT_ATF_UNDERFLOW); + + reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), + DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST + | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST + | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); - PRINT_G(KERN_INFO, "looking for PCILynx cards"); + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); - while ((dev = pci_find_device(PCI_VENDOR_ID_TI, - PCI_DEVICE_ID_TI_PCILYNX, dev)) - != NULL) { - if (add_card(dev) == 0) { - success = 1; - } - } + reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); - if (success == 0) { - PRINT_G(KERN_WARNING, "no operable PCILynx cards found"); - return -ENXIO; - } + run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV); -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { - PRINT_G(KERN_ERR, "allocation of char major number %d failed", - PCILYNX_MAJOR); - return -EBUSY; + reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID + | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN + | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN + | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX); + + if (!lynx->phyic.reg_1394a) { + /* attempt to enable contender bit -FIXME- would this work + * elsewhere? */ + reg_set_bits(lynx, GPIO_CTRL_A, 0x1); + reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); + } else { + /* set the contender bit in the extended PHY register + * set. (Should check that bis 0,1,2 (=0xE0) is set + * in register 2?) + */ + i = get_phy_reg(lynx, 4); + if (i != -1) set_phy_reg(lynx, 4, i | 0x40); } -#endif + + hpsb_add_host(host); + lynx->state = is_host; return 0; +#undef FAIL } -#endif + static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr) @@ -1603,15 +1507,6 @@ return sizeof(lynx_csr_rom); } -static struct hpsb_host_template lynx_template = { - name: PCILYNX_DRIVER_NAME, - initialize_host: lynx_initialize, - release_host: lynx_release, - get_rom: get_lynx_rom, - transmit_packet: lynx_transmit, - devctl: lynx_devctl -}; - static struct pci_device_id pci_table[] __devinitdata = { { vendor: PCI_VENDOR_ID_TI, @@ -1622,11 +1517,17 @@ { } /* Terminating entry */ }; -static struct pci_driver lynx_pcidriver = { +static struct pci_driver lynx_pci_driver = { name: PCILYNX_DRIVER_NAME, id_table: pci_table, probe: add_card, - remove: remove_card, + remove: __devexit_p(remove_card), +}; + +static struct hpsb_host_operations lynx_ops = { + get_rom: get_lynx_rom, + transmit_packet: lynx_transmit, + devctl: lynx_devctl, }; MODULE_AUTHOR("Andreas E. Bombe "); @@ -1635,30 +1536,52 @@ MODULE_SUPPORTED_DEVICE("pcilynx"); MODULE_DEVICE_TABLE(pci, pci_table); -static void __exit pcilynx_cleanup(void) -{ - hpsb_unregister_lowlevel(&lynx_template); - pci_unregister_driver(&lynx_pcidriver); - PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module"); -} - static int __init pcilynx_init(void) { int ret; - if (hpsb_register_lowlevel(&lynx_template)) { - PRINT_G(KERN_ERR, "registering failed"); - return -ENXIO; +#ifdef CONFIG_IEEE1394_PCILYNX_PORTS + if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { + PRINT_G(KERN_ERR, "allocation of char major number %d failed", + PCILYNX_MAJOR); + return -EBUSY; + } +#endif + + lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME); + if (!lynx_driver) { + ret = -ENOMEM; + goto free_char_dev; } - ret = pci_module_init(&lynx_pcidriver); + ret = pci_module_init(&lynx_pci_driver); if (ret < 0) { PRINT_G(KERN_ERR, "PCI module init failed"); - hpsb_unregister_lowlevel(&lynx_template); + goto unregister_lowlevel; } + return 0; + + unregister_lowlevel: + hpsb_unregister_lowlevel(lynx_driver); + free_char_dev: +#ifdef CONFIG_IEEE1394_PCILYNX_PORTS + unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); +#endif + return ret; } + +static void __exit pcilynx_cleanup(void) +{ + pci_unregister_driver(&lynx_pci_driver); + hpsb_unregister_lowlevel(lynx_driver); + +#ifdef CONFIG_IEEE1394_PCILYNX_PORTS + unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); +#endif +} + module_init(pcilynx_init); module_exit(pcilynx_cleanup); diff -urN linux-2.4.18/drivers/ieee1394/pcilynx.h linux-2.4.19-pre5/drivers/ieee1394/pcilynx.h --- linux-2.4.18/drivers/ieee1394/pcilynx.h Sun Feb 17 01:21:24 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/pcilynx.h Sat Mar 30 22:55:39 2002 @@ -40,8 +40,8 @@ u32 product; } phyic; - enum { clear, have_host_struct, have_intr, have_aux_buf, have_pcl_mem, - have_1394_buffers, have_iomappings } state; + enum { clear, have_intr, have_aux_buf, have_pcl_mem, + have_1394_buffers, have_iomappings, is_host } state; /* remapped memory spaces */ void *registers; diff -urN linux-2.4.18/drivers/ieee1394/raw1394.c linux-2.4.19-pre5/drivers/ieee1394/raw1394.c --- linux-2.4.18/drivers/ieee1394/raw1394.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/raw1394.c Sat Mar 30 22:55:39 2002 @@ -21,10 +21,7 @@ #include #include #include - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) #include -#endif #include "ieee1394.h" #include "ieee1394_types.h" @@ -467,7 +464,7 @@ hi = list_entry(lh, struct host_info, list); khl->nodes = hi->host->node_count; - strcpy(khl->name, hi->host->template->name); + strcpy(khl->name, hi->host->driver->name); khl++; } @@ -495,7 +492,7 @@ lh = lh->next; } hi = list_entry(lh, struct host_info, list); - hpsb_inc_host_usage(hi->host); + hpsb_ref_host(hi->host); list_add_tail(&fi->list, &hi->file_info_list); fi->host = hi->host; fi->state = connected; @@ -915,17 +912,13 @@ { struct file_info *fi; - if (MINOR(inode->i_rdev)) { + if (ieee1394_file_to_instance(file) > 0) { return -ENXIO; } - V22_COMPAT_MOD_INC_USE_COUNT; - fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); - if (fi == NULL) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (fi == NULL) return -ENOMEM; - } memset(fi, 0, sizeof(struct file_info)); @@ -949,7 +942,6 @@ struct pending_request *req; int done = 0, i; - lock_kernel(); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -984,13 +976,11 @@ list_del(&fi->list); spin_unlock_irq(&host_info_lock); - hpsb_dec_host_usage(fi->host); + hpsb_unref_host(fi->host); } kfree(fi); - V22_COMPAT_MOD_DEC_USE_COUNT; - unlock_kernel(); return 0; } @@ -1003,12 +993,12 @@ }; static struct file_operations file_ops = { - OWNER_THIS_MODULE - read: raw1394_read, - write: raw1394_write, - poll: raw1394_poll, - open: raw1394_open, - release: raw1394_release, + owner: THIS_MODULE, + read: raw1394_read, + write: raw1394_write, + poll: raw1394_poll, + open: raw1394_open, + release: raw1394_release, }; static int __init init_raw1394(void) @@ -1019,14 +1009,18 @@ return -ENOMEM; } - devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE, - RAW1394_DEVICE_MAJOR, 0, + devfs_handle = devfs_register(NULL, + RAW1394_DEVICE_NAME, DEVFS_FL_NONE, + IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_RAW1394 * 16, S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL); - if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME, - &file_ops)) { - HPSB_ERR("raw1394 failed to register /dev/raw1394 device"); + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394, + THIS_MODULE, &file_ops)) { + HPSB_ERR("raw1394 failed to register minor device block"); + devfs_unregister(devfs_handle); + hpsb_unregister_highlevel(hl_handle); return -EBUSY; } printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME); @@ -1035,7 +1029,7 @@ static void __exit cleanup_raw1394(void) { - devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394); devfs_unregister(devfs_handle); hpsb_unregister_highlevel(hl_handle); } diff -urN linux-2.4.18/drivers/ieee1394/sbp2.c linux-2.4.19-pre5/drivers/ieee1394/sbp2.c --- linux-2.4.18/drivers/ieee1394/sbp2.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/sbp2.c Sat Mar 30 22:55:39 2002 @@ -2,7 +2,7 @@ * sbp2.c - SBP-2 protocol driver for IEEE-1394 * * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) - * jamesg@filanet.com + * jamesg@filanet.com (JSG) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ * driver. It also registers as a SCSI lower-level driver in order to accept * SCSI commands for transport using SBP-2. * + * * Driver Loading: * * Currently, the SBP-2 driver is supported only as a module. Because the @@ -45,7 +46,7 @@ * * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the * initial scsi bus scan (when the driver is first loaded). To add or remove - * SBP-2 devices after this initial scan (i.e. if you plug-in or un-plug a + * SBP-2 devices "after" this initial scan (i.e. if you plug-in or un-plug a * device after the SBP-2 driver is loaded), you must either use the scsi procfs * add-single-device, remove-single-device, or a shell script such as * rescan-scsi-bus.sh. @@ -76,14 +77,28 @@ * fdisk, mkfs, etc.). * * + * Module Load Options: + * + * sbp2_max_speed - Force max speed allowed + * (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2) + * sbp2_serialize_io - Serialize all I/O coming down from the scsi drivers + * (0 = deserialized, 1 = serialized, default = 0) + * sbp2_max_sectors, - Change max sectors per I/O supported (default = 255) + * sbp2_max_outstanding_cmds - Change max outstanding concurrent commands (default = 8) + * sbp2_max_cmds_per_lun - Change max concurrent commands per sbp2 device (default = 1) + * + * (e.g. insmod sbp2 sbp2_serialize_io = 1) + * + * * Current Support: * * The SBP-2 driver is still in an early state, but supports a variety of devices. * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen - * performance of more than 16 MBytes/s on individual drives (limit of the media + * performance of more than 25 MBytes/s on individual drives (limit of the media * transfer rate). * - * Following are the devices that have been tested successfully: + * + * Following are a sampling of devices that have been tested successfully: * * - Western Digital IEEE-1394 hard drives * - Maxtor IEEE-1394 hard drives @@ -91,7 +106,7 @@ * - LaCie IEEE-1394 hard drives (several flavors) * - QPS IEEE-1394 CD-RW/DVD drives and hard drives * - BusLink IEEE-1394 hard drives - * - Iomega IEEE-1394 Zip/Jazz drives + * - Iomega IEEE-1394 Zip/Jazz/Peerless drives * - ClubMac IEEE-1394 hard drives * - FirePower IEEE-1394 hard drives * - EzQuest IEEE-1394 hard drives and CD-RW drives @@ -102,9 +117,8 @@ * - APDrives IEEE-1394 hard drives * - Fujitsu IEEE-1394 MO drives * - Sony IEEE-1394 CD-RW drives - * - Epson IEEE-1394 scanner + * - Epson IEEE-1394 scanners * - ADS IEEE-1394 memory stick and compact flash readers - * (e.g. "insmod sbp2 mode_sense_hack=1" for mem stick and flash readers)) * - SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges) * - Various other standard IEEE-1394 hard drives and enclosures * @@ -118,10 +132,6 @@ * * Current Issues: * - * - Currently, all I/O from the scsi stack is serialized by default, as there - * are some stress issues under investigation with deserialized I/O. To enable - * deserialized I/O for testing, do "insmod sbp2 serialize_io=0" - * * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. * @@ -130,10 +140,6 @@ * add some init code to the kernel to support this... and modules are much * more flexible anyway. ;-) * - * - The scsi stack in recent kernels pass down the data transfer - * direction as scsicmd->sc_data_direction, which we should use - * instead of the sbp2scsi_direction_table. - * * * History: * @@ -239,9 +245,42 @@ * upon module unload. Moved much initialization * from sbp2scsi_detect to sbp2_module_init. * Kristian Hogsberg + * 01/06/02 - Misc bug fixes/enhancements: (JSG) + * * Enable use_new_eh_code for scsi stuff. + * * Do not write all ones for NULL ORB high/low fields, but + * rather leave reserved areas zeroed (per SBP2 spec). + * * Use newer scsi transfer direction passed down instead of our + * direction table. + * * Bumped login time-out to 20 seconds, as some devices are slow. + * * Fixed a couple scsi unregister bugs on module unload + * 01/13/02 - Fixed compatibility with certain SBP2 devices, such as Iomega + * 1394 devices (Peerless, Jazz). Also a bit of clean-up of the + * driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack + * module load option, as it's been fixed in the 2.4 scsi stack. + * 02/10/02 - Added support for max_sectors, minor fix for inquiry command, make + * up sbp2 device type from inquiry response data if not part of + * device's 1394 unit directory. (JSG) + * 02/18/02 - Code clean-up and enhancements: (JSG) + * * Finish cleaning out hacked code for dealing with broken sbp2 devices + * which do not support requests of 128KB or greater. Now use + * max_sectors scsi host entry to limit transfer sizes. + * * Change status fifo address from a single address to a set of addresses, + * with each sbp2 device having it's own status fifo address. This makes + * it easier to match the status write to the sbp2 device instance. + * * Minor change to use lun when logging into sbp2 devices. First step in + * supporting multi-lun devices such as CD/DVD changer devices. + * * Added a new module load option for setting max sectors. For use by folk + * who'd like to bump up the max scsi transfer size supported. + * * Enabled deserialized operation by default, allowing for better performance, + * particularily when running with multiple sbp2 devices. For debugging, + * you may enable serialization through use of the sbp2_serialize_io module + * load option (e.g. insmod sbp2 sbp2_serialize_io=1). + * 02/20/02 - Added a couple additional module load options. + * Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW + * drive I have, which doesn't seem to get along with other sbp2 devices + * (or handle linked commands well). */ - /* * Includes @@ -270,6 +309,16 @@ #include #include +#ifdef CONFIG_KBUILD_2_5 +#include +#include +#include +#else +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" +#endif + #include "ieee1394.h" #include "ieee1394_types.h" #include "ieee1394_core.h" @@ -278,9 +327,6 @@ #include "highlevel.h" #include "ieee1394_transactions.h" #include "ieee1394_hotplug.h" -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" #include "sbp2.h" /* @@ -288,17 +334,7 @@ */ /* - * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device, - * like a 1394 memory stick reader, compact flash reader, or MO drive that - * does not support mode sense. Allows you to mount the media rw instead - * of ro. - */ -MODULE_PARM(mode_sense_hack,"i"); -MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers"); -static int mode_sense_hack = 0; - -/* - * Change max_speed on module load if you have a bad IEEE-1394 controller + * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller * that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit @@ -306,31 +342,51 @@ * bump down the speed if you are running into problems. * * Valid values: - * max_speed = 2 (default: max speed 400mb) - * max_speed = 1 (max speed 200mb) - * max_speed = 0 (max speed 100mb) + * sbp2_max_speed = 2 (default: max speed 400mb) + * sbp2_max_speed = 1 (max speed 200mb) + * sbp2_max_speed = 0 (max speed 100mb) + */ +MODULE_PARM(sbp2_max_speed,"i"); +MODULE_PARM_DESC(sbp2_max_speed, "Force max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)"); +static int sbp2_max_speed = SPEED_400; + +/* + * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to + * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices. + */ +MODULE_PARM(sbp2_serialize_io,"i"); +MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); +static int sbp2_serialize_io = 0; /* serialize I/O - available for debugging purposes */ + +/* + * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note + * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB. + * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note + * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes. */ -MODULE_PARM(max_speed,"i"); -MODULE_PARM_DESC(max_speed, "Force down max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)"); -static int max_speed = SPEED_400; +MODULE_PARM(sbp2_max_sectors,"i"); +MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)"); +static int sbp2_max_sectors = SBP2_MAX_SECTORS; /* - * Set serialize_io to 1 if you'd like only one scsi command sent down to - * us at a time (debugging). + * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached + * (or if you need to do some debugging). */ -MODULE_PARM(serialize_io,"i"); -MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)"); -static int serialize_io = 1; /* serialize I/O until stress issues are resolved */ +MODULE_PARM(sbp2_max_outstanding_cmds,"i"); +MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); +static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* - * Set no_large_packets to 1 if you'd like to limit the size of requests - * sent down to us (normally the sbp2 driver will break up any requests to - * any individual devices with 128KB transfer size limits). Sets max s/g - * list elements to 0x1f in size and disables s/g clustering. + * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked + * command per sbp2 device may allow some performance gains, but some older sbp2 devices have + * firmware bugs resulting in problems when linking commands... so, enable this with care. + * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of + * concurrent/linked commands. =) */ -MODULE_PARM(no_large_packets,"i"); -MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)"); -static int no_large_packets = 0; +MODULE_PARM(sbp2_max_cmds_per_lun,"i"); +MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); +static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; + /* * Export information about protocols/devices supported by this driver. @@ -348,11 +404,16 @@ MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); /* - * Debug levels, configured via kernel config. + * Debug levels, configured via kernel config, or enable here. */ +/* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS */ +/* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */ +/* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */ +/* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */ + #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS -#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2("__FUNCTION__"): "fmt, ## args) +#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args) static u32 global_outstanding_command_orbs = 0; #define outstanding_orb_incr global_outstanding_command_orbs++ #define outstanding_orb_decr global_outstanding_command_orbs-- @@ -364,10 +425,10 @@ #ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA #define SBP2_DMA_ALLOC(fmt, args...) \ - HPSB_ERR("sbp2("__FUNCTION__")alloc(%d): "fmt, \ + HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \ ++global_outstanding_dmas, ## args) #define SBP2_DMA_FREE(fmt, args...) \ - HPSB_ERR("sbp2("__FUNCTION__")free(%d): "fmt, \ + HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \ --global_outstanding_dmas, ## args) static u32 global_outstanding_dmas = 0; #else @@ -375,7 +436,6 @@ #define SBP2_DMA_FREE(fmt, args...) #endif - #if CONFIG_IEEE1394_SBP2_DEBUG >= 2 #define SBP2_DEBUG(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) #define SBP2_INFO(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) @@ -388,9 +448,9 @@ #define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args) #else #define SBP2_DEBUG(fmt, args...) -#define SBP2_INFO(fmt, args...) -#define SBP2_NOTICE(fmt, args...) -#define SBP2_WARN(fmt, args...) +#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args) +#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args) +#define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args) #endif #define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) @@ -418,7 +478,6 @@ static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 }; static LIST_HEAD(sbp2_host_info_list); -static int sbp2_host_count = 0; static struct hpsb_highlevel *sbp2_hl_handle = NULL; @@ -489,7 +548,19 @@ struct hpsb_packet *packet; int i; - /* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */ + hi->request_packet = kmalloc(sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS, + GFP_KERNEL); + + if (!hi->request_packet) { + SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!"); + return(-ENOMEM); + } + memset(hi->request_packet, 0, sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS); + + /* + * Create a pool of request packets. Just take the max supported + * concurrent commands and multiply by two to be safe... + */ for (i=0; irequest_packet); sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return; @@ -560,7 +632,7 @@ */ static struct sbp2_request_packet * sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, - nodeid_t node, u64 addr, + struct node_entry *ne, u64 addr, size_t data_size, quadlet_t data) { struct list_head *lh; @@ -589,12 +661,11 @@ INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = hpsb_unused; - packet->generation = get_hpsb_generation(hi->host); packet->data_be = 1; + + hpsb_node_fill_packet(ne, packet); - packet->host = hi->host; - packet->tlabel = get_tlabel(hi->host, node, 1); - packet->node_id = node; + packet->tlabel = get_tlabel(hi->host, packet->node_id, 1); if (!data_size) { fill_async_writequad(packet, addr, data); @@ -716,8 +787,8 @@ } /* - * This functions finds the sbp2_command for a given outstanding command - * orb. Only looks at the inuse list. + * This function finds the sbp2_command for a given outstanding command + * orb.Only looks at the inuse list. */ static struct sbp2_command_info *sbp2util_find_command_for_orb( struct scsi_id_instance_data *scsi_id, dma_addr_t orb) @@ -744,7 +815,7 @@ } /* - * This functions finds the sbp2_command for a given outstanding SCpnt. + * This function finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. */ static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) @@ -787,7 +858,6 @@ command = list_entry(lh, struct sbp2_command_info, list); command->Current_done = Current_done; command->Current_SCpnt = Current_SCpnt; - command->linked = 0; list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse); } else { SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!"); @@ -804,14 +874,26 @@ hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0]; if (hi == NULL) { - printk(KERN_ERR __FUNCTION__": hi == NULL\n"); + printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__); return; } if (command->cmd_dma) { - pci_unmap_single(hi->host->pdev, command->cmd_dma, - command->dma_size, command->dma_dir); - SBP2_DMA_FREE("single bulk"); + if (command->dma_type == CMD_DMA_SINGLE) { + pci_unmap_single(hi->host->pdev, command->cmd_dma, + command->dma_size, command->dma_dir); + SBP2_DMA_FREE("single bulk"); + } else if (command->dma_type == CMD_DMA_PAGE) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) + pci_unmap_single(hi->host->pdev, command->cmd_dma, + command->dma_size, command->dma_dir); +#else + pci_unmap_page(hi->host->pdev, command->cmd_dma, + command->dma_size, command->dma_dir); +#endif /* Linux version < 2.4.13 */ + SBP2_DMA_FREE("single page"); + } /* XXX: Check for CMD_DMA_NONE bug */ + command->dma_type = CMD_DMA_NONE; command->cmd_dma = 0; } @@ -865,7 +947,8 @@ * Register our sbp2 status address space... */ hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, - SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block)); + SBP2_STATUS_FIFO_ADDRESS + + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1)); hpsb_register_protocol(&sbp2_driver); @@ -923,7 +1006,8 @@ if (sbp2_reconnect_device(hi, scsi_id)) { - /* Ok, reconnect has failed. Perhaps we didn't + /* + * Ok, reconnect has failed. Perhaps we didn't * reconnect fast enough. Try doing a regular login. */ if (sbp2_login_device(hi, scsi_id)) { @@ -991,13 +1075,14 @@ sbp2_spin_lock(&sbp2_host_info_lock, flags); list_add_tail(&hi->list, &sbp2_host_info_list); - sbp2_host_count++; sbp2_spin_unlock(&sbp2_host_info_lock, flags); /* Register our host with the SCSI stack. */ hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *)); - if (hi->scsi_host) + if (hi->scsi_host) { hi->scsi_host->hostdata[0] = (unsigned long)hi; + hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS; + } scsi_driver_template.present++; return; @@ -1014,12 +1099,29 @@ list_for_each (lh, &sbp2_host_info_list) { hi = list_entry(lh, struct sbp2scsi_host_info, list); - if (hi->host == host) { + if (hi->host == host) return hi; - } } - return(NULL); + return NULL; +} + +/* + * This function returns a host info structure for a given Scsi_Host + * struct. + */ +static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host) +{ + struct list_head *lh; + struct sbp2scsi_host_info *hi; + + list_for_each (lh, &sbp2_host_info_list) { + hi = list_entry(lh, struct sbp2scsi_host_info, list); + if (hi->scsi_host == host) + return hi; + } + + return NULL; } /* @@ -1037,10 +1139,7 @@ hi = sbp2_find_host_info(host); if (hi != NULL) { sbp2util_remove_request_packet_pool(hi); - sbp2_host_count--; list_del(&hi->list); - scsi_unregister(hi->scsi_host); - scsi_driver_template.present--; kfree(hi); } else @@ -1164,19 +1263,11 @@ /* * Knock the total command orbs down if we are serializing I/O */ - if (serialize_io) { + if (sbp2_serialize_io) { scsi_id->sbp2_total_command_orbs = 2; /* one extra for good measure */ } /* - * Allocate some extra command orb structures for devices with - * 128KB limit. - */ - if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { - scsi_id->sbp2_total_command_orbs *= 4; - } - - /* * Find an empty spot to stick our scsi id instance data. */ for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) { @@ -1322,14 +1413,19 @@ scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1); /* Exclusive access to device */ - scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ + scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ + /* Set the lun if we were able to pull it from the device's unit directory */ + if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) { + scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun); + } SBP2_DEBUG("sbp2_login_device: lun_misc initialized"); scsi_id->login_orb->passwd_resp_lengths = ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized"); - scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id); scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); SBP2_DEBUG("sbp2_login_device: status FIFO initialized"); @@ -1357,7 +1453,7 @@ sbp2util_cpu_to_be32_buffer(data, 8); SBP2_DEBUG("sbp2_login_device: prepared to write"); - hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); SBP2_DEBUG("sbp2_login_device: written"); /* @@ -1367,9 +1463,9 @@ save_flags(flags); cli(); - /* 10 second timeout */ + /* 20 second timeout */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) - sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ); + sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ); restore_flags(flags); SBP2_DEBUG("sbp2_login_device: initial check"); @@ -1446,7 +1542,8 @@ scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); scsi_id->logout_orb->reserved5 = 0x0; - scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id); scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); @@ -1462,7 +1559,7 @@ data[1] = scsi_id->logout_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* Wait for device to logout...1 second. */ sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); @@ -1500,7 +1597,8 @@ scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); scsi_id->reconnect_orb->reserved5 = 0x0; - scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id); scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); @@ -1521,7 +1619,7 @@ data[1] = scsi_id->reconnect_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); - hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* * Wait for reconnect status... but, only if the device has not @@ -1575,7 +1673,7 @@ */ data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); - if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { + if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { SBP2_ERR("sbp2_set_busy_timeout error"); } @@ -1594,16 +1692,24 @@ SBP2_DEBUG("sbp2_parse_unit_directory"); + /* Initialize some fields, in case an entry does not exist */ + scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED; + scsi_id->sbp2_management_agent_addr = 0x0; + scsi_id->sbp2_command_set_spec_id = 0x0; + scsi_id->sbp2_command_set = 0x0; + scsi_id->sbp2_unit_characteristics = 0x0; + scsi_id->sbp2_firmware_revision = 0x0; + ud = scsi_id->ud; /* Handle different fields in the unit directory, based on keys */ - for (i = 0; i < ud->arb_count; i++) { - switch (ud->arb_keys[i]) { + for (i = 0; i < ud->count; i++) { + switch (CONFIG_ROM_KEY(ud->quadlets[i])) { case SBP2_CSR_OFFSET_KEY: /* Save off the management agent address */ scsi_id->sbp2_management_agent_addr = - CONFIG_ROM_INITIAL_MEMORY_SPACE + - (ud->arb_values[i] << 2); + CSR_REGISTER_BASE + + (CONFIG_ROM_VALUE(ud->quadlets[i]) << 2); SBP2_DEBUG("sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr); @@ -1611,14 +1717,16 @@ case SBP2_COMMAND_SET_SPEC_ID_KEY: /* Command spec organization */ - scsi_id->sbp2_command_set_spec_id = ud->arb_values[i]; + scsi_id->sbp2_command_set_spec_id + = CONFIG_ROM_VALUE(ud->quadlets[i]); SBP2_DEBUG("sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id); break; case SBP2_COMMAND_SET_KEY: /* Command set used by sbp2 device */ - scsi_id->sbp2_command_set = ud->arb_values[i]; + scsi_id->sbp2_command_set + = CONFIG_ROM_VALUE(ud->quadlets[i]); SBP2_DEBUG("sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set); break; @@ -1628,7 +1736,8 @@ * Unit characterisitcs (orb related stuff * that I'm not yet paying attention to) */ - scsi_id->sbp2_unit_characteristics = ud->arb_values[i]; + scsi_id->sbp2_unit_characteristics + = CONFIG_ROM_VALUE(ud->quadlets[i]); SBP2_DEBUG("sbp2_unit_characteristics = %x", (unsigned int) scsi_id->sbp2_unit_characteristics); break; @@ -1638,7 +1747,8 @@ * Device type and lun (used for * detemining type of sbp2 device) */ - scsi_id->sbp2_device_type_and_lun = ud->arb_values[i]; + scsi_id->sbp2_device_type_and_lun + = CONFIG_ROM_VALUE(ud->quadlets[i]); SBP2_DEBUG("sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun); break; @@ -1651,8 +1761,11 @@ * bridge with 128KB max transfer size * limitation. */ - scsi_id->sbp2_firmware_revision = ud->arb_values[i]; - if (scsi_id->sbp2_firmware_revision == + scsi_id->sbp2_firmware_revision + = CONFIG_ROM_VALUE(ud->quadlets[i]); + SBP2_DEBUG("sbp2_firmware_revision = %x", + (unsigned int) scsi_id->sbp2_firmware_revision); + if ((scsi_id->sbp2_firmware_revision & 0xffff00) == SBP2_128KB_BROKEN_FIRMWARE) { SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size"); } @@ -1682,8 +1795,8 @@ + (scsi_id->ne->nodeid & NODE_MASK)]; /* Bump down our speed if the user requested it */ - if (scsi_id->speed_code > max_speed) { - scsi_id->speed_code = max_speed; + if (scsi_id->speed_code > sbp2_max_speed) { + scsi_id->speed_code = sbp2_max_speed; SBP2_ERR("Forcing SBP-2 max speed down to %s", hpsb_speedto_str[scsi_id->speed_code]); } @@ -1693,7 +1806,7 @@ scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code], (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); - SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]", + SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]", NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code], 1 << ((u32)scsi_id->max_payload_size + 2)); @@ -1713,7 +1826,7 @@ * Ok, let's write to the target's management agent register */ agent_reset_request_packet = - sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, + sbp2util_allocate_write_request_packet(hi, scsi_id->ne, scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET, 0, ntohl(SBP2_AGENT_RESET_DATA)); @@ -1753,13 +1866,15 @@ unchar *scsi_cmd, unsigned int scsi_use_sg, unsigned int scsi_request_bufflen, - void *scsi_request_buffer, int dma_dir) + void *scsi_request_buffer, + unsigned char scsi_dir) { struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer; struct sbp2_command_orb *command_orb = &command->command_orb; struct sbp2_unrestricted_page_table *scatter_gather_element = &command->scatter_gather_element[0]; - u32 sg_count, sg_len; + int dma_dir = scsi_to_pci_dma_dir (scsi_dir); + u32 sg_count, sg_len, orb_direction; dma_addr_t sg_addr; int i; @@ -1771,25 +1886,49 @@ * that data_size becomes the number of s/g elements, and * page_size should be zero (for unrestricted). */ - command_orb->next_ORB_hi = 0xffffffff; - command_orb->next_ORB_lo = 0xffffffff; + command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1); + command_orb->next_ORB_lo = 0x0; command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size); command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code); command_orb->misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ /* + * Get the direction of the transfer. If the direction is unknown, then use our + * goofy table as a back-up. + */ + switch (scsi_dir) { + case SCSI_DATA_NONE: + orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER; + break; + case SCSI_DATA_WRITE: + orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA; + break; + case SCSI_DATA_READ: + orb_direction = ORB_DIRECTION_READ_FROM_MEDIA; + break; + case SCSI_DATA_UNKNOWN: + default: + SBP2_ERR("SCSI data transfer direction not specified. " + "Update the SBP2 direction table in sbp2.h if " + "necessary for your application"); + print_command (scsi_cmd); + orb_direction = sbp2scsi_direction_table[*scsi_cmd]; + break; + } + + /* * Set-up our pagetable stuff... unfortunately, this has become * messier than I'd like. Need to clean this up a bit. ;-) */ - if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) { + if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) { SBP2_DEBUG("No data transfer"); /* * Handle no data transfer */ - command_orb->data_descriptor_hi = 0xffffffff; - command_orb->data_descriptor_lo = 0xffffffff; + command_orb->data_descriptor_hi = 0x0; + command_orb->data_descriptor_lo = 0x0; command_orb->misc |= ORB_SET_DIRECTION(1); } else if (scsi_use_sg) { @@ -1804,15 +1943,24 @@ SBP2_DEBUG("Only one s/g element"); command->dma_dir = dma_dir; command->dma_size = sgpnt[0].length; + command->dma_type = CMD_DMA_PAGE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address, command->dma_size, command->dma_dir); - SBP2_DMA_ALLOC("single scatter element"); +#else + command->cmd_dma = pci_map_page(hi->host->pdev, + sgpnt[0].page, + sgpnt[0].offset, + command->dma_size, + command->dma_dir); +#endif /* Linux version < 2.4.13 */ + SBP2_DMA_ALLOC("single page scatter element"); command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->cmd_dma; command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size); - command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + command_orb->misc |= ORB_SET_DIRECTION(orb_direction); } else { int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir); @@ -1824,7 +1972,7 @@ /* use page tables (s/g) */ command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); - command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + command_orb->misc |= ORB_SET_DIRECTION(orb_direction); command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->sge_dma; @@ -1869,6 +2017,7 @@ command->dma_dir = dma_dir; command->dma_size = scsi_request_bufflen; + command->dma_type = CMD_DMA_SINGLE; command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer, command->dma_size, command->dma_dir); @@ -1883,15 +2032,15 @@ command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->cmd_dma; command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen); - command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + command_orb->misc |= ORB_SET_DIRECTION(orb_direction); /* * Sanity, in case our direction table is not * up-to-date */ if (!scsi_request_bufflen) { - command_orb->data_descriptor_hi = 0xffffffff; - command_orb->data_descriptor_lo = 0xffffffff; + command_orb->data_descriptor_hi = 0x0; + command_orb->data_descriptor_lo = 0x0; command_orb->misc |= ORB_SET_DIRECTION(1); } @@ -1905,7 +2054,7 @@ /* Use page tables (s/g) */ command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); - command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + command_orb->misc |= ORB_SET_DIRECTION(orb_direction); /* * fill out our sbp-2 page tables (and split up @@ -1967,9 +2116,15 @@ struct sbp2_command_orb *command_orb = &command->command_orb; outstanding_orb_incr; - SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x", - command_orb, command->linked, global_outstanding_command_orbs); + SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x", + command_orb, global_outstanding_command_orbs); + pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); /* * Check to see if there are any previous orbs to use */ @@ -1981,7 +2136,7 @@ if (hpsb_node_entry_valid(scsi_id->ne)) { command_request_packet = - sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, + sbp2util_allocate_write_request_packet(hi, scsi_id->ne, scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET, 8, 0); @@ -2006,6 +2161,7 @@ } scsi_id->last_orb = command_orb; + scsi_id->last_orb_dma = command->command_orb_dma; } else { @@ -2020,15 +2176,17 @@ cpu_to_be32(command->command_orb_dma); /* Tells hardware that this pointer is valid */ scsi_id->last_orb->next_ORB_hi = 0x0; + pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); /* - * Only ring the doorbell if we need to (first parts of - * linked orbs don't need this). + * Ring the doorbell */ - if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) { + if (hpsb_node_entry_valid(scsi_id->ne)) { command_request_packet = sbp2util_allocate_write_request_packet(hi, - LOCAL_BUS | scsi_id->ne->nodeid, + scsi_id->ne, scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET, 0, cpu_to_be32(command->command_orb_dma)); @@ -2047,6 +2205,7 @@ } scsi_id->last_orb = command_orb; + scsi_id->last_orb_dma = command->command_orb_dma; } return(0); @@ -2059,33 +2218,20 @@ Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { unchar *cmd = (unchar *) SCpnt->cmnd; - u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16; + unsigned int request_bufflen = SCpnt->request_bufflen; + u8 device_type + = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); struct sbp2_command_info *command; SBP2_DEBUG("sbp2_send_command"); - SBP2_DEBUG("SCSI command = %02x", *cmd); - SBP2_DEBUG("SCSI transfer size = %x", SCpnt->request_bufflen); + SBP2_DEBUG("SCSI command:"); +#if CONFIG_IEEE1394_SBP2_DEBUG >= 2 + print_command (cmd); +#endif + SBP2_DEBUG("SCSI transfer size = %x", request_bufflen); SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg); /* - * Check for broken devices that can't handle greater than 128K - * transfers, and deal with them in a hacked ugly way. - */ - if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && - (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && - (device_type == TYPE_DISK) && - (SCpnt->use_sg) && - (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) { - - /* - * Darn, a broken device. We'll need to split up the - * transfer ourselves. - */ - sbp2_send_split_command(hi, scsi_id, SCpnt, done); - return(0); - } - - /* * Allocate a command orb and s/g structure */ command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); @@ -2094,14 +2240,24 @@ } /* + * The scsi stack sends down a request_bufflen which does not match the + * length field in the scsi cdb. This causes some sbp2 devices to + * reject this inquiry command. Hack fix is to set both buff length and + * length field in cdb to 36. This gives best compatibility. + */ + if (*cmd == INQUIRY) { + request_bufflen = cmd[4] = 0x24; + } + + /* * Now actually fill in the comamnd orb and sbp2 s/g list */ sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg, - SCpnt->request_bufflen, SCpnt->request_buffer, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + request_bufflen, SCpnt->request_buffer, + SCpnt->sc_data_direction); /* * Update our cdb if necessary (to handle sbp2 RBC command set - * differences). This is where the command set hacks go! =) + * differences). This is where the command set hacks go! =) */ if ((device_type == TYPE_DISK) || (device_type == TYPE_SDAD) || @@ -2122,120 +2278,6 @@ return(0); } -/* - * This function is called for broken sbp2 device, where we have to break - * up large transfers. - */ -static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, - Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) -{ - unchar *cmd = (unchar *) SCpnt->cmnd; - struct scatterlist *sgpnt = (struct scatterlist *) SCpnt->request_buffer; - struct sbp2_command_info *command; - unsigned int i, block_count, block_address, block_size; - unsigned int current_sg = 0; - unsigned int total_transfer = 0; - unsigned int total_sg = 0; - unchar new_cmd[12]; - - memset(new_cmd, 0, 12); - memcpy(new_cmd, cmd, COMMAND_SIZE(*cmd)); - - /* - * Turns command into 10 byte version - */ - sbp2_check_sbp2_command(new_cmd); - - /* - * Pull block size, block address, block count from command sent down - */ - block_count = (cmd[7] << 8) | cmd[8]; - block_address = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5]; - block_size = SCpnt->request_bufflen/block_count; - - /* - * Walk the scsi s/g list to determine how much we can transfer in one pop - */ - for (i=0; iuse_sg; i++) { - - total_transfer+=sgpnt[i].length; - total_sg++; - - if (total_transfer > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) { - - /* - * Back everything up one, so that we're less than 128KB - */ - total_transfer-=sgpnt[i].length; - total_sg--; - i--; - - command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); - if (!command) { - return(-EIO); - } - - /* - * This is not the final piece, so mark it as linked - */ - command->linked = 1; - - block_count = total_transfer/block_size; - new_cmd[2] = (unchar) (block_address >> 24) & 0xff; - new_cmd[3] = (unchar) (block_address >> 16) & 0xff; - new_cmd[4] = (unchar) (block_address >> 8) & 0xff; - new_cmd[5] = (unchar) block_address & 0xff; - new_cmd[7] = (unchar) (block_count >> 8) & 0xff; - new_cmd[8] = (unchar) block_count & 0xff; - block_address+=block_count; - - sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, - total_transfer, &sgpnt[current_sg], - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - - /* - * Link up the orb, and ring the doorbell if needed - */ - memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); - sbp2_link_orb_command(hi, scsi_id, command); - - current_sg += total_sg; - total_sg = 0; - total_transfer = 0; - - } - - } - - /* - * Get the last piece... - */ - command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); - if (!command) { - return(-EIO); - } - - block_count = total_transfer/block_size; - new_cmd[2] = (unchar) (block_address >> 24) & 0xff; - new_cmd[3] = (unchar) (block_address >> 16) & 0xff; - new_cmd[4] = (unchar) (block_address >> 8) & 0xff; - new_cmd[5] = (unchar) block_address & 0xff; - new_cmd[7] = (unchar) (block_count >> 8) & 0xff; - new_cmd[8] = (unchar) block_count & 0xff; - - sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, - total_transfer, &sgpnt[current_sg], - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - - /* - * Link up the orb, and ring the doorbell if needed - */ - memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); - sbp2_link_orb_command(hi, scsi_id, command); - - - return(0); -} /* * This function deals with command set differences between Linux scsi @@ -2367,15 +2409,29 @@ Scsi_Cmnd *SCpnt) { u8 *scsi_buf = SCpnt->request_buffer; - u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16; - + u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); + SBP2_DEBUG("sbp2_check_sbp2_response"); switch (SCpnt->cmnd[0]) { case INQUIRY: - SBP2_DEBUG("Check Inquiry data"); + /* + * If scsi_id->sbp2_device_type_and_lun is uninitialized, then fill + * this information in from the inquiry response data. Lun is set to zero. + */ + if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) { + SBP2_DEBUG("Creating sbp2_device_type_and_lun from scsi inquiry data"); + scsi_id->sbp2_device_type_and_lun = (scsi_buf[0] & 0x1f) << 16; + } + + /* + * Make sure data length is ok. Minimum length is 36 bytes + */ + if (scsi_buf[4] == 0) { + scsi_buf[4] = 36 - 5; + } /* * Check for Simple Direct Access Device and change it to TYPE_DISK @@ -2431,7 +2487,7 @@ { struct sbp2scsi_host_info *hi = NULL; struct scsi_id_instance_data *scsi_id = NULL; - int i; + u32 id; unsigned long flags; Scsi_Cmnd *SCpnt = NULL; u32 scsi_status = SBP2_SCSI_STATUS_GOOD; @@ -2456,17 +2512,11 @@ sbp2_spin_lock(&hi->sbp2_command_lock, flags); /* - * Find our scsi_id structure + * Find our scsi_id structure by looking at the status fifo address written to by + * the sbp2 device. */ - for (i=0; iscsi_id[i]) { - if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) { - scsi_id = hi->scsi_id[i]; - SBP2_DEBUG("SBP-2 status write from node %x", scsi_id->ne->nodeid); - break; - } - } - } + id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS)); + scsi_id = hi->scsi_id[id]; if (!scsi_id) { SBP2_ERR("scsi_id is NULL - device is gone?"); @@ -2491,6 +2541,12 @@ if (command) { SBP2_DEBUG("Found status for command ORB"); + pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb); outstanding_orb_decr; @@ -2501,25 +2557,30 @@ SCpnt = command->Current_SCpnt; sbp2util_mark_command_completed(scsi_id, command); - if (SCpnt && !command->linked) { + if (SCpnt) { /* - * Handle check conditions + * See if the target stored any scsi status information */ - if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { - - SBP2_DEBUG("CHECK CONDITION"); - + if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) { /* * Translate SBP-2 status to SCSI sense data */ scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer); + } + /* + * Handle check conditions. If there is either SBP status or SCSI status + * then we'll do a fetch agent reset and note that a check condition + * occured. + */ + if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) || + scsi_status) { /* * Initiate a fetch agent reset. */ + SBP2_DEBUG("CHECK CONDITION"); sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); - } SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb); @@ -2548,7 +2609,6 @@ return(RCODE_COMPLETE); } - /************************************** * SCSI interface related section @@ -2613,8 +2673,7 @@ } /* - * Check to see if there is a command in progress and just return - * busy (to be queued later) + * Check to see if we are in the middle of a bus reset. */ if (!hpsb_node_entry_valid(scsi_id->ne)) { SBP2_ERR("Bus reset in progress - rejecting command"); @@ -2653,8 +2712,14 @@ SBP2_DEBUG("Found pending command to complete"); lh = scsi_id->sbp2_command_orb_inuse.next; command = list_entry(lh, struct sbp2_command_info, list); + pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(scsi_id, command); - if (command->Current_SCpnt && !command->linked) { + if (command->Current_SCpnt) { void (*done)(Scsi_Cmnd *) = command->Current_done; command->Current_SCpnt->result = status << 16; done (command->Current_SCpnt); @@ -2710,13 +2775,17 @@ /* * Debug stuff */ +#if CONFIG_IEEE1394_SBP2_DEBUG >= 1 + print_command (SCpnt->cmnd); print_sense("bh", SCpnt); +#endif break; case SBP2_SCSI_STATUS_SELECTION_TIMEOUT: SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT"); SCpnt->result = DID_NO_CONNECT << 16; + print_command (SCpnt->cmnd); break; case SBP2_SCSI_STATUS_CONDITION_MET: @@ -2724,6 +2793,7 @@ case SBP2_SCSI_STATUS_COMMAND_TERMINATED: SBP2_ERR("Bad SCSI status = %x", scsi_status); SCpnt->result = DID_ERROR << 16; + print_command (SCpnt->cmnd); break; default: @@ -2739,19 +2809,6 @@ } /* - * One more quick hack (not enabled by default). Some sbp2 devices - * do not support mode sense. Turn-on this hack to allow the - * device to pass the sd driver's write-protect test (so that you - * can mount the device rw). - */ - if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) { - SBP2_INFO("Returning success to mode sense command"); - SCpnt->result = DID_OK; - SCpnt->sense_buffer[0] = 0; - memset (SCpnt->request_buffer, 0, 8); - } - - /* * If a bus reset is in progress and there was an error, complete * the command as busy so that it will get retried. */ @@ -2766,16 +2823,22 @@ * or hot-plug... */ if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { - SBP2_INFO("UNIT ATTENTION - return busy"); + SBP2_DEBUG("UNIT ATTENTION - return busy"); SCpnt->result = DID_BUS_BUSY << 16; } /* * Tell scsi stack that we're done with this command */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) spin_lock_irq(&io_request_lock); done (SCpnt); spin_unlock_irq(&io_request_lock); +#else + spin_lock_irq(&hi->scsi_host->host_lock); + done (SCpnt); + spin_unlock_irq(&hi->scsi_host->host_lock); +#endif return; } @@ -2792,27 +2855,33 @@ unsigned long flags; SBP2_ERR("aborting sbp2 command"); - + print_command (SCpnt->cmnd); + if (scsi_id) { /* * Right now, just return any matching command structures - * to the free pool (there may be more than one because of - * broken up/linked commands). + * to the free pool. */ sbp2_spin_lock(&hi->sbp2_command_lock, flags); - do { - command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); - if (command) { - SBP2_DEBUG("Found command to abort"); - sbp2util_mark_command_completed(scsi_id, command); - if (command->Current_SCpnt && !command->linked) { - void (*done)(Scsi_Cmnd *) = command->Current_done; - command->Current_SCpnt->result = DID_ABORT << 16; - done (command->Current_SCpnt); - } + command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); + if (command) { + SBP2_DEBUG("Found command to abort"); + pci_dma_sync_single(hi->host->pdev, + command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single(hi->host->pdev, + command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); + sbp2util_mark_command_completed(scsi_id, command); + if (command->Current_SCpnt) { + void (*done)(Scsi_Cmnd *) = command->Current_done; + command->Current_SCpnt->result = DID_ABORT << 16; + done (command->Current_SCpnt); } - } while (command); + } /* * Initiate a fetch agent reset. @@ -2822,24 +2891,25 @@ sbp2_spin_unlock(&hi->sbp2_command_lock, flags); } - return(SCSI_ABORT_SUCCESS); + return(SUCCESS); } /* * Called by scsi stack when something has really gone wrong. */ -static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) { struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target]; SBP2_ERR("reset requested"); - if (hi) { + if (scsi_id) { SBP2_ERR("Generating IEEE-1394 bus reset"); - hpsb_reset_bus(hi->host, LONG_RESET); + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); } - return(SCSI_RESET_SUCCESS); + return(SUCCESS); } /* @@ -2868,12 +2938,15 @@ return(0); } +/* + * Called by scsi stack after scsi driver is registered + */ static int sbp2scsi_detect (Scsi_Host_Template *tpnt) { SBP2_DEBUG("sbp2scsi_detect"); /* - * Call sbp2_init to register with the ieee1394 stack. This + * Call sbp2_init to register with the ieee1394 stack. This * results in a callback to sbp2_add_host for each ieee1394 * host controller currently registered, and for each of those * we register a scsi host with the scsi stack. @@ -2881,9 +2954,39 @@ sbp2_init(); /* We return the number of hosts registered. */ - return sbp2_host_count; + return scsi_driver_template.present; +} + + +/* + * Called for contents of procfs + */ +static const char *sbp2scsi_info (struct Scsi_Host *host) +{ + struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host); + static char info[1024]; + + if (!hi) /* shouldn't happen, but... */ + return "IEEE-1394 SBP-2 protocol driver"; + + sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n" + "SBP-2 module load options:\n" + "- Max speed supported: %s\n" + "- Max sectors per I/O supported: %d\n" + "- Max outstanding commands supported: %d\n" + "- Max outstanding commands per lun supported: %d\n" + "- Serialized I/O (debug): %s", + hi->host->driver->name, + hpsb_speedto_str[sbp2_max_speed], + sbp2_max_sectors, + sbp2_max_outstanding_cmds, + sbp2_max_cmds_per_lun, + sbp2_serialize_io ? "yes" : "no"); + + return info; } + MODULE_AUTHOR("James Goodwin "); MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); @@ -2891,24 +2994,23 @@ /* SCSI host template */ static Scsi_Host_Template scsi_driver_template = { - name: "IEEE-1394 SBP-2 protocol driver", - detect: sbp2scsi_detect, - queuecommand: sbp2scsi_queuecommand, - abort: sbp2scsi_abort, - reset: sbp2scsi_reset, - bios_param: sbp2scsi_biosparam, - can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS, - this_id: -1, - sg_tablesize: SBP2_MAX_SG_ELEMENTS, - cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN, - use_clustering: SBP2_CLUSTERING, - emulated: 1, - - module: THIS_MODULE, - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26) - proc_name: SBP2_DEVICE_NAME + name: "IEEE-1394 SBP-2 protocol driver", + info: sbp2scsi_info, + detect: sbp2scsi_detect, + queuecommand: sbp2scsi_queuecommand, + eh_abort_handler: sbp2scsi_abort, + eh_device_reset_handler:sbp2scsi_reset, + eh_bus_reset_handler: sbp2scsi_reset, + eh_host_reset_handler: sbp2scsi_reset, + bios_param: sbp2scsi_biosparam, + this_id: -1, + sg_tablesize: SBP2_MAX_SG_ELEMENTS, + use_clustering: SBP2_CLUSTERING, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + use_new_eh_code: TRUE, #endif + emulated: 1, + proc_name: SBP2_DEVICE_NAME, }; static int sbp2_module_init(void) @@ -2916,38 +3018,32 @@ SBP2_DEBUG("sbp2_module_init"); /* - * Module load option for force one command at a time + * Module load debug option to force one command at a time (serializing I/O) */ - if (serialize_io) { + if (sbp2_serialize_io) { SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)"); scsi_driver_template.can_queue = 1; scsi_driver_template.cmd_per_lun = 1; + } else { + scsi_driver_template.can_queue = sbp2_max_outstanding_cmds; + scsi_driver_template.cmd_per_lun = sbp2_max_cmds_per_lun; } - /* - * Module load option to limit max size of requests from the - * scsi drivers + /* + * Set max sectors (module load option). Default is 255 sectors. */ - if (no_large_packets) { - SBP2_ERR("Driver forced to limit max transfer size " - "(no_large_packets = 1)"); - scsi_driver_template.sg_tablesize = 0x1f; - scsi_driver_template.use_clustering = DISABLE_CLUSTERING; - } - - if (mode_sense_hack) { - SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)"); - } + scsi_driver_template.max_sectors = sbp2_max_sectors; /* * Ideally we would register our scsi_driver_template with the * scsi stack and after that register with the ieee1394 stack - * and process the add_host callbacks. However, the detect + * and process the add_host callbacks. However, the detect * function in the scsi host template requires that we find at * least one host, so we "nest" the registrations by calling * sbp2_init from the detect function. */ - if (scsi_register_module(MODULE_SCSI_HA, &scsi_driver_template) || + scsi_driver_template.module = THIS_MODULE; + if (SCSI_REGISTER_HOST(&scsi_driver_template) || !scsi_driver_template.present) { SBP2_ERR("Please load the lower level IEEE-1394 driver " "(e.g. ohci1394) before sbp2..."); @@ -2970,8 +3066,9 @@ */ sbp2_cleanup(); - if (scsi_unregister_module(MODULE_SCSI_HA, &scsi_driver_template)) + if (SCSI_UNREGISTER_HOST(&scsi_driver_template)) SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver"); + } module_init(sbp2_module_init); diff -urN linux-2.4.18/drivers/ieee1394/sbp2.h linux-2.4.19-pre5/drivers/ieee1394/sbp2.h --- linux-2.4.18/drivers/ieee1394/sbp2.h Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/ieee1394/sbp2.h Sat Mar 30 22:55:39 2002 @@ -22,6 +22,15 @@ #ifndef SBP2_H #define SBP2_H +/* Some compatibility code */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define SCSI_REGISTER_HOST(tmpl) scsi_register_module(MODULE_SCSI_HA, tmpl) +#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_module(MODULE_SCSI_HA, tmpl) +#else +#define SCSI_REGISTER_HOST(tmpl) scsi_register_host(tmpl) +#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_host(tmpl) +#endif + #define SBP2_DEVICE_NAME "sbp2" #define SBP2_DEVICE_NAME_SIZE 4 @@ -36,6 +45,7 @@ #define ORB_DIRECTION_READ_FROM_MEDIA 0x1 #define ORB_DIRECTION_NO_DATA_TRANSFER 0x2 +#define ORB_SET_NULL_PTR(value) ((value & 0x1) << 31) #define ORB_SET_NOTIFY(value) ((value & 0x1) << 31) #define ORB_SET_RQ_FMT(value) ((value & 0x3) << 29) #define ORB_SET_NODE_ID(value) ((value & 0xffff) << 16) @@ -185,10 +195,28 @@ * Miscellaneous SBP2 related config rom defines */ -#define SBP2_STATUS_FIFO_ADDRESS 0xfffe00000000ULL /* for write posting! */ +/* + * The status fifo address definition below is used as a status base, with a chunk + * separately assigned for each sbp2 device detected. For example, 0xfffe00000000ULL + * is used for the first sbp2 device detected, 0xfffe00000020ULL for the next sbp2 + * device, and so on. + * + * Note: We could use a single status fifo address for all sbp2 devices, and figure + * out which sbp2 device the status belongs to by looking at the source node id of + * the status write... but, using separate addresses for each sbp2 device allows for + * better code and the ability to support multiple luns within a single 1394 node. + * + * Also note that we choose the address range below as it is a region specified for + * write posting, where the ohci controller will automatically send an ack_complete + * when the status is written by the sbp2 device... saving a split transaction. =) + */ +#define SBP2_STATUS_FIFO_ADDRESS 0xfffe00000000ULL #define SBP2_STATUS_FIFO_ADDRESS_HI 0xfffe #define SBP2_STATUS_FIFO_ADDRESS_LO 0x0 +#define SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(entry) ((entry) << 5) +#define SBP2_STATUS_FIFO_OFFSET_TO_ENTRY(offset) ((offset) >> 5) + #define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1 #define SBP2_CSR_OFFSET_KEY 0x54 #define SBP2_UNIT_SPEC_ID_KEY 0x12 @@ -199,6 +227,9 @@ #define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14 #define SBP2_FIRMWARE_REVISION_KEY 0x3c +#define SBP2_DEVICE_TYPE(q) (((q) >> 16) & 0x1f) +#define SBP2_DEVICE_LUN(q) ((q) & 0xffff) + #define SBP2_AGENT_STATE_OFFSET 0x00ULL #define SBP2_AGENT_RESET_OFFSET 0x04ULL #define SBP2_ORB_POINTER_OFFSET 0x08ULL @@ -219,18 +250,13 @@ #define SBP2_SW_VERSION_ENTRY 0x00010483 /* - * Miscellaneous general config rom related defines + * Other misc defines */ - -#define CONFIG_ROM_INITIAL_MEMORY_SPACE 0xfffff0000000ULL - -#define CONFIG_ROM_BASE_ADDRESS 0xfffff0000400ULL -#define CONFIG_ROM_ROOT_DIR_BASE 0xfffff0000414ULL -#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET 0xfffff0000424ULL - #define SBP2_128KB_BROKEN_FIRMWARE 0xa0b800 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER 0x20000 +#define SBP2_DEVICE_TYPE_LUN_UNINITIALIZED 0xffffffff + /* * Flags for SBP-2 functions */ @@ -243,16 +269,18 @@ #define SBP2_MAX_SG_ELEMENTS SG_ALL #define SBP2_CLUSTERING ENABLE_CLUSTERING #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 -#define SBP2SCSI_MAX_SCSI_IDS 8 +#define SBP2SCSI_MAX_SCSI_IDS 16 /* Max sbp2 device instances supported */ #define SBP2SCSI_MAX_OUTSTANDING_CMDS 8 /* Max total outstanding sbp2 commands allowed at a time! */ -#define SBP2SCSI_MAX_CMDS_PER_LUN 4 /* Max outstanding sbp2 commands per device - tune as needed */ +#define SBP2SCSI_MAX_CMDS_PER_LUN 1 /* Max outstanding sbp2 commands per device - tune as needed */ +#define SBP2_MAX_SECTORS 255 /* Max sectors supported */ #ifndef TYPE_SDAD #define TYPE_SDAD 0x0e /* simplified direct access device */ #endif /* - * SCSI direction table... since the scsi stack doesn't specify direction... =( + * SCSI direction table... + * (now used as a back-up in case the direction passed down from above is "unknown") * * DIN = IN data direction * DOU = OUT data direction @@ -286,13 +314,8 @@ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN }; - -/* - * Number of request packets available for actual sbp2 I/O requests (these are used - * for sending command and agent reset packets). - */ -#define SBP2_MAX_REQUEST_PACKETS SBP2SCSI_MAX_OUTSTANDING_CMDS /* Per host adapter instance */ -#define SBP2_MAX_COMMAND_ORBS SBP2SCSI_MAX_CMDS_PER_LUN * 2 /* Per sbp2 device instance */ +#define SBP2_MAX_REQUEST_PACKETS (sbp2_max_outstanding_cmds * 2) +#define SBP2_MAX_COMMAND_ORBS (sbp2_max_cmds_per_lun * 2) /* * Request packets structure (used for sending command and agent reset packets) @@ -306,21 +329,26 @@ }; + +/* This is the two dma types we use for cmd_dma below */ +#define CMD_DMA_NONE 0x0 +#define CMD_DMA_PAGE 0x1 +#define CMD_DMA_SINGLE 0x2 + /* * Encapsulates all the info necessary for an outstanding command. */ struct sbp2_command_info { struct list_head list; - struct sbp2_command_orb command_orb; - dma_addr_t command_orb_dma; + struct sbp2_command_orb command_orb ____cacheline_aligned; + dma_addr_t command_orb_dma ____cacheline_aligned; Scsi_Cmnd *Current_SCpnt; void (*Current_done)(Scsi_Cmnd *); - unsigned int linked; /* Also need s/g structure for each sbp2 command */ - struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS]; - dma_addr_t sge_dma; + struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS] ____cacheline_aligned; + dma_addr_t sge_dma ____cacheline_aligned; void *sge_buffer; dma_addr_t cmd_dma; int dma_type; @@ -340,6 +368,7 @@ * Various sbp2 specific structures */ struct sbp2_command_orb *last_orb; + dma_addr_t last_orb_dma; struct sbp2_login_orb *login_orb; dma_addr_t login_orb_dma; struct sbp2_login_response *login_response; @@ -422,7 +451,7 @@ * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions) * are allocated at init and simply re-initialized when needed. */ - struct sbp2_request_packet request_packet[SBP2_MAX_REQUEST_PACKETS]; + struct sbp2_request_packet *request_packet; /* * SCSI ID instance data (one for each sbp2 device instance possible) @@ -441,7 +470,7 @@ static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi); static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi); static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, - nodeid_t node, u64 addr, + struct node_entry *ne, u64 addr, size_t data_size, quadlet_t data); static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet); @@ -487,13 +516,12 @@ unchar *scsi_cmd, unsigned int scsi_use_sg, unsigned int scsi_request_bufflen, - void *scsi_request_buffer, int dma_dir); + void *scsi_request_buffer, + unsigned char scsi_dir); static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command); static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); -static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, - Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data); static void sbp2_check_sbp2_command(unchar *cmd); static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, @@ -506,10 +534,11 @@ * Scsi interface related prototypes */ static int sbp2scsi_detect (Scsi_Host_Template *tpnt); +static const char *sbp2scsi_info (struct Scsi_Host *host); void sbp2scsi_setup(char *str, int *ints); static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); -static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags); +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 status); diff -urN linux-2.4.18/drivers/ieee1394/video1394.c linux-2.4.19-pre5/drivers/ieee1394/video1394.c --- linux-2.4.18/drivers/ieee1394/video1394.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/ieee1394/video1394.c Sat Mar 30 22:55:39 2002 @@ -18,6 +18,9 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* jds -- add private data to file to keep track of iso contexts associated + with each open -- so release won't kill all iso transfers */ + #include #include #include @@ -31,19 +34,12 @@ #include #include #include -#include -#include -#include -#include #include #include #include #include -#include -#include -#include -#include +#include #include #include #include @@ -59,7 +55,6 @@ #include "ohci1394.h" -#define VIDEO1394_MAJOR 172 #define ISO_CHANNELS 64 #define ISO_RECEIVE 0 #define ISO_TRANSMIT 1 @@ -72,6 +67,14 @@ #define vmalloc_32(x) vmalloc(x) #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3)) +#define remap_page_range_1394(vma, start, addr, size, prot) \ + remap_page_range(start, addr, size, prot) +#else +#define remap_page_range_1394(vma, start, addr, size, prot) \ + remap_page_range(vma, start, addr, size, prot) +#endif + struct it_dma_prg { struct dma_cmd begin; quadlet_t data[4]; @@ -81,6 +84,7 @@ struct dma_iso_ctx { struct ti_ohci *ohci; + int type; /* ISO_TRANSMIT or ISO_RECEIVE */ int ctx; int channel; int last_buffer; @@ -108,6 +112,8 @@ spinlock_t lock; unsigned int syt_offset; int flags; + + struct list_head link; }; struct video_card { @@ -115,9 +121,12 @@ struct list_head list; int id; devfs_handle_t devfs; +}; - struct dma_iso_ctx **ir_context; - struct dma_iso_ctx **it_context; + +struct file_ctx { + struct video_card *video; + struct list_head context_list; struct dma_iso_ctx *current_ctx; }; @@ -145,7 +154,7 @@ printk(level "video1394_%d: " fmt "\n" , card , ## args) static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent); + quadlet_t isoXmitIntEvent, void *data); static LIST_HEAD(video1394_cards); static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED; @@ -153,8 +162,6 @@ static devfs_handle_t devfs_handle; static struct hpsb_highlevel *hl_handle = NULL; -static struct video_template video_tmpl = { irq_handler }; - /* Code taken from bttv.c */ /*******************************/ @@ -277,56 +284,75 @@ } /* End of code taken from bttv.c */ -static int free_dma_iso_ctx(struct dma_iso_ctx **d) +static int free_dma_iso_ctx(struct dma_iso_ctx *d) { int i; - struct ti_ohci *ohci; + unsigned long *usage; - if ((*d)==NULL) return -1; + DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx); - ohci = (struct ti_ohci *)(*d)->ohci; + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + ohci1394_unhook_irq(d->ohci, irq_handler, d); - DBGMSG(ohci->id, "Freeing dma_iso_ctx %d", (*d)->ctx); + if (d->buf) + rvfree((void *)d->buf, d->num_desc * d->buf_size); - ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); + if (d->ir_prg) { + for (i=0;inum_desc;i++) + if (d->ir_prg[i]) kfree(d->ir_prg[i]); + kfree(d->ir_prg); + } + + if (d->it_prg) { + for (i=0;inum_desc;i++) + if (d->it_prg[i]) kfree(d->it_prg[i]); + kfree(d->it_prg); + } + + if (d->buffer_status) + kfree(d->buffer_status); + if (d->buffer_time) + kfree(d->buffer_time); + if (d->last_used_cmd) + kfree(d->last_used_cmd); + if (d->next_buffer) + kfree(d->next_buffer); + + usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage : + &d->ohci->it_ctx_usage; + + /* clear the ISO context usage bit */ + clear_bit(d->ctx, usage); + list_del(&d->link); - if ((*d)->buf) rvfree((void *)(*d)->buf, - (*d)->num_desc * (*d)->buf_size); - - if ((*d)->ir_prg) { - for (i=0;i<(*d)->num_desc;i++) - if ((*d)->ir_prg[i]) kfree((*d)->ir_prg[i]); - kfree((*d)->ir_prg); - } - - if ((*d)->it_prg) { - for (i=0;i<(*d)->num_desc;i++) - if ((*d)->it_prg[i]) kfree((*d)->it_prg[i]); - kfree((*d)->it_prg); - } - - if ((*d)->buffer_status) - kfree((*d)->buffer_status); - if ((*d)->buffer_time) - kfree((*d)->buffer_time); - if ((*d)->last_used_cmd) - kfree((*d)->last_used_cmd); - if ((*d)->next_buffer) - kfree((*d)->next_buffer); - - kfree(*d); - *d = NULL; + kfree(d); return 0; } static struct dma_iso_ctx * -alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc, +alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, int buf_size, int channel, unsigned int packet_size) { struct dma_iso_ctx *d=NULL; int i; + unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage : + &ohci->it_ctx_usage; + + /* try to claim the ISO context usage bit */ + for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) { + if (!test_and_set_bit(i, usage)) { + PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i); + break; + } + } + + if (i == ohci->nb_iso_rcv_ctx) { + PRINT(KERN_ERR, ohci->id, "No DMA contexts available"); + return NULL; + } + d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); if (d==NULL) { @@ -337,7 +363,8 @@ memset(d, 0, sizeof(struct dma_iso_ctx)); d->ohci = (void *)ohci; - d->ctx = ctx; + d->type = type; + d->ctx = i; d->channel = channel; d->num_desc = num_desc; d->frame_size = buf_size; @@ -350,11 +377,17 @@ d->ir_prg = NULL; init_waitqueue_head(&d->waitq); + if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) { + PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed"); + free_dma_iso_ctx(d); + return NULL; + } + d->buf = rvmalloc(d->num_desc * d->buf_size); if (d->buf == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } memset(d->buf, 0, d->num_desc * d->buf_size); @@ -371,7 +404,7 @@ if (d->ir_prg == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma ir prg"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *)); @@ -387,7 +420,7 @@ if (d->ir_prg[i] == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma ir prg"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } } @@ -403,7 +436,7 @@ if (d->it_prg == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma it prg"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } memset(d->it_prg, 0, d->num_desc*sizeof(struct it_dma_prg *)); @@ -415,7 +448,7 @@ "Packet size %d (page_size: %ld) " "not yet supported\n", packet_size, PAGE_SIZE); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } @@ -434,7 +467,7 @@ if (d->it_prg[i] == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma it prg"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } } @@ -451,22 +484,22 @@ if (d->buffer_status == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_status"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } if (d->buffer_time == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } if (d->last_used_cmd == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } if (d->next_buffer == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate next_buffer"); - free_dma_iso_ctx(&d); + free_dma_iso_ctx(d); return NULL; } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); @@ -568,38 +601,19 @@ } /* find which context is listening to this channel */ -int ir_ctx_listening(struct video_card *video, int channel) -{ - int i; - struct ti_ohci *ohci = video->ohci; - - for (i=0;inb_iso_rcv_ctx-1;i++) - if (video->ir_context[i]) { - if (video->ir_context[i]->channel==channel) - return i; - } - - PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d", - channel); - - return -1; -} - -int it_ctx_talking(struct video_card *video, int channel) +static struct dma_iso_ctx * +find_ctx(struct list_head *list, int type, int channel) { - int i; - struct ti_ohci *ohci = video->ohci; + struct list_head *lh; - for (i=0;inb_iso_xmit_ctx;i++) - if (video->it_context[i]) { - if (video->it_context[i]->channel==channel) - return i; - } - - PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d", - channel); + list_for_each(lh, list) { + struct dma_iso_ctx *ctx; + ctx = list_entry(lh, struct dma_iso_ctx, link); + if (ctx->type == type && ctx->channel == channel) + return ctx; + } - return -1; + return NULL; } int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) @@ -617,7 +631,11 @@ if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) + get_fast_time(&d->buffer_time[i]); +#else do_gettimeofday(&d->buffer_time[i]); +#endif } } spin_unlock(&d->lock); @@ -822,13 +840,14 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<ctx); } -static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, - const char *adr, unsigned long size) +static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, + struct vm_area_struct *vma) { - unsigned long start=(unsigned long) adr; - unsigned long page,pos; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long page, pos; - if (size>d->num_desc * d->buf_size) { + if (size > d->num_desc * d->buf_size) { PRINT(KERN_ERR, ohci->id, "iso context %d buf size is different from mmap size", d->ctx); @@ -840,14 +859,14 @@ return -EINVAL; } - pos=(unsigned long) d->buf; + pos = (unsigned long) d->buf; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; } return 0; } @@ -855,29 +874,10 @@ static int video1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_card *video = NULL; - struct ti_ohci *ohci = NULL; + struct file_ctx *ctx = (struct file_ctx *)file->private_data; + struct video_card *video = ctx->video; + struct ti_ohci *ohci = video->ohci; unsigned long flags; - struct list_head *lh; - - spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(inode->i_rdev)) { - video = p; - ohci = video->ohci; - break; - } - } - } - spin_unlock_irqrestore(&video1394_cards_lock, flags); - - if (video == NULL) { - PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev)); - return -EFAULT; - } switch(cmd) { @@ -886,6 +886,7 @@ { struct video1394_mmap v; u64 mask; + struct dma_iso_ctx *d; int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) @@ -897,7 +898,7 @@ for (i=0; iISO_channel_usage & mask)) { v.channel = i; - PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i); + PRINT(KERN_INFO, ohci->id, "Found free channel %d", i); break; } mask = mask << 1; @@ -920,7 +921,7 @@ return -EFAULT; } ohci->ISO_channel_usage |= mask; - + if (v.buf_size<=0) { PRINT(KERN_ERR, ohci->id, "Invalid %d length buffer requested",v.buf_size); @@ -941,67 +942,47 @@ } if (cmd == VIDEO1394_LISTEN_CHANNEL) { - /* find a free iso receive context */ - for (i=0;inb_iso_rcv_ctx-1;i++) - if (video->ir_context[i]==NULL) break; - - if (i==(ohci->nb_iso_rcv_ctx-1)) { - PRINT(KERN_ERR, ohci->id, - "No iso context available"); - return -EFAULT; - } + d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE, + v.nb_buffers, v.buf_size, + v.channel, 0); - video->ir_context[i] = - alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1, - v.nb_buffers, v.buf_size, - v.channel, 0); - - if (video->ir_context[i] == NULL) { + if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Couldn't allocate ir context"); return -EFAULT; } - initialize_dma_ir_ctx(video->ir_context[i], - v.sync_tag, v.flags); + initialize_dma_ir_ctx(d, v.sync_tag, v.flags); - video->current_ctx = video->ir_context[i]; + ctx->current_ctx = d; - v.buf_size = video->ir_context[i]->buf_size; + v.buf_size = d->buf_size; + list_add_tail(&d->link, &ctx->context_list); PRINT(KERN_INFO, ohci->id, - "iso context %d listen on channel %d", i+1, - v.channel); + "iso context %d listen on channel %d", + d->ctx, v.channel); } else { - /* find a free iso transmit context */ - for (i=0;inb_iso_xmit_ctx;i++) - if (video->it_context[i]==NULL) break; - - if (i==ohci->nb_iso_xmit_ctx) { - PRINT(KERN_ERR, ohci->id, - "No iso context available"); - return -EFAULT; - } - - video->it_context[i] = - alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i, - v.nb_buffers, v.buf_size, - v.channel, v.packet_size); + d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, + v.nb_buffers, v.buf_size, + v.channel, v.packet_size); - if (video->it_context[i] == NULL) { + if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Couldn't allocate it context"); return -EFAULT; } - initialize_dma_it_ctx(video->it_context[i], - v.sync_tag, v.syt_offset, v.flags); + initialize_dma_it_ctx(d, v.sync_tag, + v.syt_offset, v.flags); + + ctx->current_ctx = d; - video->current_ctx = video->it_context[i]; + v.buf_size = d->buf_size; - v.buf_size = video->it_context[i]->buf_size; + list_add_tail(&d->link, &ctx->context_list); PRINT(KERN_INFO, ohci->id, - "Iso context %d talk on channel %d", i, + "Iso context %d talk on channel %d", d->ctx, v.channel); } @@ -1015,7 +996,7 @@ { int channel; u64 mask; - int i; + struct dma_iso_ctx *d; if(copy_from_user(&channel, (void *)arg, sizeof(int))) return -EFAULT; @@ -1031,28 +1012,19 @@ "Channel %d is not being used", channel); return -EFAULT; } - ohci->ISO_channel_usage &= ~mask; - if (cmd == VIDEO1394_UNLISTEN_CHANNEL) { - i = ir_ctx_listening(video, channel); - if (i<0) return -EFAULT; - - free_dma_iso_ctx(&video->ir_context[i]); - - PRINT(KERN_INFO, ohci->id, - "Iso context %d stop listening on channel %d", - i+1, channel); - } - else { - i = it_ctx_talking(video, channel); - if (i<0) return -EFAULT; + /* Mark this channel as unused */ + ohci->ISO_channel_usage &= ~mask; - free_dma_iso_ctx(&video->it_context[i]); + if (cmd == VIDEO1394_UNLISTEN_CHANNEL) + d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel); + else + d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel); - PRINT(KERN_INFO, ohci->id, - "Iso context %d stop talking on channel %d", - i, channel); - } + if (d == NULL) return -EFAULT; + PRINT(KERN_INFO, ohci->id, "Iso context %d " + "stop talking on channel %d", d->ctx, channel); + free_dma_iso_ctx(d); return 0; } @@ -1060,14 +1032,11 @@ { struct video1394_wait v; struct dma_iso_ctx *d; - int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - i = ir_ctx_listening(video, v.channel); - if (i<0) return -EFAULT; - d = video->ir_context[i]; + d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1129,9 +1098,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - i = ir_ctx_listening(video, v.channel); - if (i<0) return -EFAULT; - d = video->ir_context[i]; + d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1208,14 +1175,11 @@ struct video1394_wait v; struct video1394_queue_variable qv; struct dma_iso_ctx *d; - int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - i = it_ctx_talking(video, v.channel); - if (i<0) return -EFAULT; - d = video->it_context[i]; + d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1300,14 +1264,11 @@ { struct video1394_wait v; struct dma_iso_ctx *d; - int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - i = it_ctx_talking(video, v.channel); - if (i<0) return -EFAULT; - d = video->it_context[i]; + d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1357,60 +1318,36 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_card *video = NULL; - struct ti_ohci *ohci; + struct file_ctx *ctx = (struct file_ctx *)file->private_data; + struct video_card *video = ctx->video; + struct ti_ohci *ohci = video->ohci; int res = -EINVAL; - unsigned long flags; - struct list_head *lh; - - spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) { - video = p; - break; - } - } - } - spin_unlock_irqrestore(&video1394_cards_lock, flags); - - if (video == NULL) { - PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", - MINOR(file->f_dentry->d_inode->i_rdev)); - return -EFAULT; - } lock_kernel(); ohci = video->ohci; - if (video->current_ctx == NULL) { + if (ctx->current_ctx == NULL) { PRINT(KERN_ERR, ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ohci, video->current_ctx, - (char *)vma->vm_start, - (unsigned long)(vma->vm_end-vma->vm_start)); + res = do_iso_mmap(ohci, ctx->current_ctx, vma); unlock_kernel(); return res; } static int video1394_open(struct inode *inode, struct file *file) { - int i = MINOR(inode->i_rdev); + int i = ieee1394_file_to_instance(file); unsigned long flags; struct video_card *video = NULL; struct list_head *lh; + struct file_ctx *ctx; spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p->id == i) { - video = p; - break; - } + list_for_each(lh, &video1394_cards) { + struct video_card *p = list_entry(lh, struct video_card, list); + if (p->id == i) { + video = p; + break; } } spin_unlock_irqrestore(&video1394_cards_lock, flags); @@ -1418,124 +1355,71 @@ if (video == NULL) return -EIO; - V22_COMPAT_MOD_INC_USE_COUNT; + ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL); + if (ctx == NULL) { + PRINT(KERN_ERR, video->ohci->id, "Cannot malloc file_ctx"); + return -ENOMEM; + } + + memset(ctx, 0, sizeof(struct file_ctx)); + ctx->video = video; + INIT_LIST_HEAD(&ctx->context_list); + ctx->current_ctx = NULL; + file->private_data = ctx; return 0; } static int video1394_release(struct inode *inode, struct file *file) { - struct video_card *video = NULL; - struct ti_ohci *ohci; + struct file_ctx *ctx = (struct file_ctx *)file->private_data; + struct video_card *video = ctx->video; + struct ti_ohci *ohci = video->ohci; + struct list_head *lh, *next; u64 mask; - int i; - unsigned long flags; - struct list_head *lh; - - spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(inode->i_rdev)) { - video = p; - break; - } - } - } - spin_unlock_irqrestore(&video1394_cards_lock, flags); - if (video == NULL) { - PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d", - MINOR(inode->i_rdev)); - return 1; + lock_kernel(); + list_for_each_safe(lh, next, &ctx->context_list) { + struct dma_iso_ctx *d; + d = list_entry(lh, struct dma_iso_ctx, link); + mask = (u64) 1 << d->channel; + + if (!(ohci->ISO_channel_usage & mask)) + PRINT(KERN_ERR, ohci->id, "On release: Channel %d " + "is not being used", d->channel); + else + ohci->ISO_channel_usage &= ~mask; + PRINT(KERN_INFO, ohci->id, "On release: Iso %s context " + "%d stop listening on channel %d", + d->type == ISO_RECEIVE ? "receive" : "transmit", + d->ctx, d->channel); + free_dma_iso_ctx(d); } - ohci = video->ohci; - - lock_kernel(); - for (i=0;inb_iso_rcv_ctx-1;i++) - if (video->ir_context[i]) { - mask = (u64)0x1<ir_context[i]->channel; - if (!(ohci->ISO_channel_usage & mask)) - PRINT(KERN_ERR, ohci->id, - "Channel %d is not being used", - video->ir_context[i]->channel); - else - ohci->ISO_channel_usage &= ~mask; - PRINT(KERN_INFO, ohci->id, - "Iso receive context %d stop listening " - "on channel %d", i+1, - video->ir_context[i]->channel); - free_dma_iso_ctx(&video->ir_context[i]); - } + kfree(ctx); + file->private_data = NULL; - for (i=0;inb_iso_xmit_ctx;i++) - if (video->it_context[i]) { - mask = (u64)0x1<it_context[i]->channel; - if (!(ohci->ISO_channel_usage & mask)) - PRINT(KERN_ERR, ohci->id, - "Channel %d is not being used", - video->it_context[i]->channel); - else - ohci->ISO_channel_usage &= ~mask; - PRINT(KERN_INFO, ohci->id, - "Iso transmit context %d stop talking " - "on channel %d", i+1, - video->it_context[i]->channel); - free_dma_iso_ctx(&video->it_context[i]); - } - - V22_COMPAT_MOD_DEC_USE_COUNT; - unlock_kernel(); return 0; } static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent) + quadlet_t isoXmitIntEvent, void *data) { - int i; - unsigned long flags; - struct video_card *video = NULL; - struct list_head *lh; + struct dma_iso_ctx *d = (struct dma_iso_ctx *) data; - spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p->id == card) { - video = p; - break; - } - } - } - spin_unlock_irqrestore(&video1394_cards_lock, flags); - - if (video == NULL) { - PRINT_G(KERN_ERR, __FUNCTION__": Unknown card number %d!!", - card); - return; - } - DBGMSG(card, "Iso event Recv: %08x Xmit: %08x", isoRecvIntEvent, isoXmitIntEvent); - for (i=0;iohci->nb_iso_rcv_ctx-1;i++) - if (isoRecvIntEvent & (1<<(i+1))) - wakeup_dma_ir_ctx(video->ohci, - video->ir_context[i]); - - for (i=0;iohci->nb_iso_xmit_ctx;i++) - if (isoXmitIntEvent & (1<ohci, - video->it_context[i]); + if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx)) + wakeup_dma_ir_ctx(d->ohci, d); + if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx)) + wakeup_dma_it_ctx(d->ohci, d); } static struct file_operations video1394_fops= { - OWNER_THIS_MODULE + owner: THIS_MODULE, ioctl: video1394_ioctl, mmap: video1394_mmap, open: video1394_open, @@ -1544,10 +1428,12 @@ static int video1394_init(struct ti_ohci *ohci) { - struct video_card *video = kmalloc(sizeof(struct video_card), GFP_KERNEL); + struct video_card *video; unsigned long flags; char name[16]; + int minor; + video = kmalloc(sizeof(struct video_card), GFP_KERNEL); if (video == NULL) { PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card"); return -1; @@ -1560,42 +1446,14 @@ list_add_tail(&video->list, &video1394_cards); spin_unlock_irqrestore(&video1394_cards_lock, flags); - if (ohci1394_register_video(ohci, &video_tmpl)<0) { - PRINT(KERN_ERR, ohci->id, "Register_video failed"); - return -1; - } - video->id = ohci->id; video->ohci = ohci; - /* Iso receive dma contexts */ - video->ir_context = (struct dma_iso_ctx **) - kmalloc((ohci->nb_iso_rcv_ctx-1)* - sizeof(struct dma_iso_ctx *), GFP_KERNEL); - if (video->ir_context) - memset(video->ir_context, 0, - (ohci->nb_iso_rcv_ctx-1)*sizeof(struct dma_iso_ctx *)); - else { - PRINT(KERN_ERR, ohci->id, "Cannot allocate ir_context"); - return -1; - } - - /* Iso transmit dma contexts */ - video->it_context = (struct dma_iso_ctx **) - kmalloc(ohci->nb_iso_xmit_ctx * - sizeof(struct dma_iso_ctx *), GFP_KERNEL); - if (video->it_context) - memset(video->it_context, 0, - ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *)); - else { - PRINT(KERN_ERR, ohci->id, "Cannot allocate it_context"); - return -1; - } - sprintf(name, "%d", video->id); + minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id; video->devfs = devfs_register(devfs_handle, name, DEVFS_FL_AUTO_OWNER, - VIDEO1394_MAJOR, 0, + IEEE1394_MAJOR, minor, S_IFCHR | S_IRUSR | S_IWUSR, &video1394_fops, NULL); @@ -1605,27 +1463,7 @@ /* Must be called under spinlock */ static void remove_card(struct video_card *video) { - int i; - - ohci1394_unregister_video(video->ohci, &video_tmpl); - devfs_unregister(video->devfs); - - /* Free the iso receive contexts */ - if (video->ir_context) { - for (i=0;iohci->nb_iso_rcv_ctx-1;i++) { - free_dma_iso_ctx(&video->ir_context[i]); - } - kfree(video->ir_context); - } - - /* Free the iso transmit contexts */ - if (video->it_context) { - for (i=0;iohci->nb_iso_xmit_ctx;i++) { - free_dma_iso_ctx(&video->it_context[i]); - } - kfree(video->it_context); - } list_del(&video->list); kfree(video); @@ -1639,7 +1477,7 @@ struct video_card *p; /* We only work with the OHCI-1394 driver */ - if (strcmp(host->template->name, OHCI1394_DRIVER_NAME)) + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) return; ohci = (struct ti_ohci *)host->hostdata; @@ -1662,7 +1500,7 @@ struct ti_ohci *ohci; /* We only work with the OHCI-1394 driver */ - if (strcmp(host->template->name, OHCI1394_DRIVER_NAME)) + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) return; ohci = (struct ti_ohci *)host->hostdata; @@ -1687,19 +1525,19 @@ hpsb_unregister_highlevel (hl_handle); devfs_unregister(devfs_handle); - devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); - + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394); + PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module"); } static int __init video1394_init_module (void) { - if (devfs_register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME, - &video1394_fops)) { - PRINT_G(KERN_ERR, "video1394: unable to get major %d\n", - VIDEO1394_MAJOR); - return -EIO; - } + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394, + THIS_MODULE, &video1394_fops)) { + PRINT_G(KERN_ERR, "video1394: unable to get minor device block"); + return -EIO; + } + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, strlen(VIDEO1394_DRIVER_NAME), NULL); @@ -1711,7 +1549,7 @@ if (hl_handle == NULL) { PRINT_G(KERN_ERR, "No more memory for driver\n"); devfs_unregister(devfs_handle); - devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394); return -ENOMEM; } diff -urN linux-2.4.18/drivers/isdn/Config.in linux-2.4.19-pre5/drivers/isdn/Config.in --- linux-2.4.18/drivers/isdn/Config.in Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/isdn/Config.in Sat Mar 30 22:55:34 2002 @@ -4,6 +4,7 @@ # only included if CONFIG_ISDN != n +define_bool CONFIG_ISDN_BOOL y if [ "$CONFIG_INET" != "n" ]; then bool ' Support synchronous PPP' CONFIG_ISDN_PPP if [ "$CONFIG_ISDN_PPP" != "n" ]; then @@ -32,6 +33,7 @@ comment 'Passive ISDN cards' dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then + define_bool CONFIG_ISDN_HISAX y comment ' D-channel protocol features' bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO if [ "$CONFIG_HISAX_EURO" != "n" ]; then @@ -79,10 +81,12 @@ fi bool ' HiSax debugging' CONFIG_HISAX_DEBUG - dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA - dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA - dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL - dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL + dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA + dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA + dep_tristate 'AVM A1 PCMCIA cards' CONFIG_HISAX_AVM_A1_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA + dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_ISDN_DRV_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL + fi endmenu diff -urN linux-2.4.18/drivers/isdn/Makefile linux-2.4.19-pre5/drivers/isdn/Makefile --- linux-2.4.18/drivers/isdn/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/isdn/Makefile Sat Mar 30 22:55:34 2002 @@ -2,7 +2,7 @@ # The target object and module list name. -O_TARGET := isdn.a +O_TARGET := vmlinux-obj.o # Objects that export symbols. @@ -32,9 +32,9 @@ # Object files in subdirectories -mod-subdirs := avmb1 eicon +mod-subdirs := avmb1 eicon hisax subdir-$(CONFIG_ISDN_DIVERSION) += divert -subdir-$(CONFIG_ISDN_DRV_HISAX) += hisax +subdir-$(CONFIG_ISDN_HISAX) += hisax subdir-$(CONFIG_ISDN_DRV_ICN) += icn subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit subdir-$(CONFIG_ISDN_DRV_SC) += sc diff -urN linux-2.4.18/drivers/isdn/act2000/act2000_isa.c linux-2.4.19-pre5/drivers/isdn/act2000/act2000_isa.c --- linux-2.4.18/drivers/isdn/act2000/act2000_isa.c Sun Dec 23 16:23:40 2001 +++ linux-2.4.19-pre5/drivers/isdn/act2000/act2000_isa.c Sat Mar 30 22:55:34 2002 @@ -178,7 +178,8 @@ card->flags &= ~ACT2000_FLAGS_PVALID; } if (!check_region(portbase, ISA_REGION)) { - request_region(portbase, ACT2000_PORTLEN, card->regname); + if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL) + return -EIO; card->port = portbase; card->flags |= ACT2000_FLAGS_PVALID; return 0; diff -urN linux-2.4.18/drivers/isdn/avmb1/kcapi.c linux-2.4.19-pre5/drivers/isdn/avmb1/kcapi.c --- linux-2.4.18/drivers/isdn/avmb1/kcapi.c Sun Dec 23 16:23:41 2001 +++ linux-2.4.19-pre5/drivers/isdn/avmb1/kcapi.c Sat Mar 30 22:55:28 2002 @@ -103,8 +103,8 @@ #define APPL(a) (&applications[(a)-1]) #define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a) #define APPL_IS_FREE(a) (APPL(a)->applid == 0) -#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0); -#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0); +#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0) +#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0) #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) diff -urN linux-2.4.18/drivers/isdn/eicon/eicon_mod.c linux-2.4.19-pre5/drivers/isdn/eicon/eicon_mod.c --- linux-2.4.18/drivers/isdn/eicon/eicon_mod.c Sun Dec 23 16:23:41 2001 +++ linux-2.4.19-pre5/drivers/isdn/eicon/eicon_mod.c Sat Mar 30 22:55:34 2002 @@ -665,8 +665,11 @@ else cnt = skb->len; - if (user) + if (user) { + spin_unlock_irqrestore(&eicon_lock, flags); copy_to_user(p, skb->data, cnt); + spin_lock_irqsave(&eicon_lock, flags); + } else memcpy(p, skb->data, cnt); diff -urN linux-2.4.18/drivers/isdn/hisax/Makefile linux-2.4.19-pre5/drivers/isdn/hisax/Makefile --- linux-2.4.18/drivers/isdn/hisax/Makefile Sun Dec 23 16:23:41 2001 +++ linux-2.4.19-pre5/drivers/isdn/hisax/Makefile Sat Mar 30 22:55:34 2002 @@ -61,6 +61,7 @@ obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o +obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o diff -urN linux-2.4.18/drivers/isdn/hisax/avma1_cs.c linux-2.4.19-pre5/drivers/isdn/hisax/avma1_cs.c --- linux-2.4.18/drivers/isdn/hisax/avma1_cs.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/isdn/hisax/avma1_cs.c Sat Mar 30 22:55:34 2002 @@ -0,0 +1,552 @@ +/* + * PCMCIA client driver for AVM A1 / Fritz!PCMCIA + * + * Author Carsten Paeth + * Copyright 1998-2001 by Carsten Paeth + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); +MODULE_AUTHOR("Carsten Paeth"); +MODULE_LICENSE("GPL"); + +int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot); +void HiSax_closecard(int cardnr); + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int default_irq_list[11] = { 15, 13, 12, 11, 10, 9, 7, 5, 4, 3, -1 }; +static int irq_list[11] = { -1 }; +static int isdnprot = 2; + +MODULE_PARM(irq_list, "1-11i"); +MODULE_PARM(isdnprot, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the skeleton event + handler. +*/ + +static void avma1cs_config(dev_link_t *link); +static void avma1cs_release(u_long arg); +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *avma1cs_attach(void); +static void avma1cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "avma1_cs"; + +/* + A linked list of "instances" of the skeleton device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally can't be allocated dynamically. +*/ + +typedef struct local_info_t { + dev_node_t node; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + avma1cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *avma1cs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "avma1cs_attach()\n"); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &avma1cs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] != -1) { + for (i = 0; i < 10 && irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } else { + for (i = 0; i < 10 && default_irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << default_irq_list[i]; + } + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &avma1cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + avma1cs_detach(link); + return NULL; + } + + return link; +} /* avma1cs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void avma1cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "avma1cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree(link->priv); + } + kfree(link); + +} /* avma1cs_detach */ + +/*====================================================================== + + avma1cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void avma1cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + local_info_t *dev; + int i; + u_char buf[64]; + char devname[128]; + int busy = 0; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "avma1cs_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + do { + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if (i != CS_SUCCESS) break; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if (i != CS_SUCCESS) break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if (i != CS_SUCCESS) break; + link->conf.ConfigBase = parse.config.base; + } while (0); + if (i != CS_SUCCESS) { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + + do { + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 254; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + + devname[0] = 0; + if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + strncpy(devname,parse.version_1.str + parse.version_1.ofs[1], + sizeof(devname)); + } + /* + * find IO port + */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if (cf->io.nwin > 0) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; + link->io.NumPorts2 = 0; + printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", + link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1 - 1); + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + i = next_tuple(handle, &tuple, &parse); + } + +found_port: + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * allocate an interrupt line + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + CardServices(ReleaseIO, link->handle, &link->io); + break; + } + + /* + * configure the PCMCIA socket + */ + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + break; + } + + } while (0); + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. */ + + strcpy(dev->node.dev_name, "A1"); + dev->node.major = 45; + dev->node.minor = 0; + link->dev = &dev->node; + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if (i != 0) { + avma1cs_release((u_long)link); + return; + } + + printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", + link->io.BasePort1, link->irq.AssignedIRQ); + + if (avm_a1_init_pcmcia((void *)(int)link->io.BasePort1, + link->irq.AssignedIRQ, + &busy, isdnprot) != 0) { + printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); + return; + } + + i = 0; /* no returncode for cardnr :-( */ + + dev->node.minor = i; + +} /* avma1cs_config */ + +/*====================================================================== + + After a card is removed, avma1cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void avma1cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + local_info_t *local = link->priv; + + DEBUG(0, "avma1cs_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + DEBUG(1, "avma1_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* no unregister function with hisax */ + HiSax_closecard(local->node.minor); + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + avma1cs_detach(link); + +} /* avma1cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int avma1cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "avma1cs_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + avma1cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + return 0; +} /* avma1cs_event */ + +/*====================================================================*/ + +static int __init init_avma1_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "avma1_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &avma1cs_attach, &avma1cs_detach); + return 0; +} + +static void __exit exit_avma1_cs(void) +{ + DEBUG(0, "avma1_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + if (dev_list->state & DEV_CONFIG) + avma1cs_release((u_long)dev_list); + avma1cs_detach(dev_list); +} + +module_init(init_avma1_cs); +module_exit(exit_avma1_cs); diff -urN linux-2.4.18/drivers/isdn/hisax/hisax_fcpcipnp.c linux-2.4.19-pre5/drivers/isdn/hisax/hisax_fcpcipnp.c --- linux-2.4.18/drivers/isdn/hisax/hisax_fcpcipnp.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/isdn/hisax/hisax_fcpcipnp.c Sat Mar 30 22:55:28 2002 @@ -65,6 +65,7 @@ static int protocol = 2; /* EURO-ISDN Default */ MODULE_PARM(protocol, "i"); +MODULE_LICENSE("GPL"); // ---------------------------------------------------------------------- diff -urN linux-2.4.18/drivers/isdn/hisax/hisax_isac.c linux-2.4.19-pre5/drivers/isdn/hisax/hisax_isac.c --- linux-2.4.18/drivers/isdn/hisax/hisax_isac.c Sun Dec 23 16:23:42 2001 +++ linux-2.4.19-pre5/drivers/isdn/hisax/hisax_isac.c Sat Mar 30 22:55:28 2002 @@ -44,6 +44,7 @@ MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); MODULE_DESCRIPTION("ISAC/ISAC-SX driver"); +MODULE_LICENSE("GPL"); #define DBG_WARN 0x0001 #define DBG_IRQ 0x0002 diff -urN linux-2.4.18/drivers/md/lvm-fs.c linux-2.4.19-pre5/drivers/md/lvm-fs.c --- linux-2.4.18/drivers/md/lvm-fs.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/md/lvm-fs.c Sat Mar 30 22:55:28 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 2001 Sistina Software * - * January,February 2001 + * January-April 2001 * * LVM driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -65,7 +64,9 @@ static void _show_uuid(const char *src, char *b, char *e); +#if 0 static devfs_handle_t lvm_devfs_handle; +#endif static devfs_handle_t vg_devfs_handle[MAX_VG]; static devfs_handle_t ch_devfs_handle[MAX_VG]; static devfs_handle_t lv_devfs_handle[MAX_LV]; @@ -79,12 +80,13 @@ void __init lvm_init_fs() { struct proc_dir_entry *pde; - /* Must create device node. Think about "devfs=only" situation */ +/* User-space has already registered this */ +#if 0 lvm_devfs_handle = devfs_register( 0 , "lvm", 0, LVM_CHAR_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_chr_fops, NULL); - +#endif lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root); if (lvm_proc_dir) { lvm_proc_vg_subdir = create_proc_entry(LVM_VG_SUBDIR, S_IFDIR, @@ -95,8 +97,9 @@ } void lvm_fin_fs() { +#if 0 devfs_unregister (lvm_devfs_handle); - +#endif remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); remove_proc_entry(LVM_DIR, &proc_root); @@ -135,13 +138,14 @@ devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); ch_devfs_handle[vg_ptr->vg_number] = NULL; + /* remove pv's */ + for(i = 0; i < vg_ptr->pv_max; i++) + if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]); + /* remove lv's */ for(i = 0; i < vg_ptr->lv_max; i++) if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]); - /* remove pv's */ - for(i = 0; i < vg_ptr->pv_max; i++) - if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]); /* must not remove directory before leaf nodes */ devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]); @@ -276,12 +280,12 @@ sz += sprintf(page + sz, "number: %u\n", lv->lv_number); sz += sprintf(page + sz, "open: %u\n", lv->lv_open); sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); - if(lv->lv_stripes > 1) { - sz += sprintf(page + sz, "stripes: %u\n", - lv->lv_stripes); - sz += sprintf(page + sz, "stripesize: %u\n", - lv->lv_stripesize); - } + if(lv->lv_stripes > 1) { + sz += sprintf(page + sz, "stripes: %u\n", + lv->lv_stripes); + sz += sprintf(page + sz, "stripesize: %u\n", + lv->lv_stripesize); + } sz += sprintf(page + sz, "device: %02u:%02u\n", MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); @@ -620,4 +624,3 @@ } *b = '\0'; } -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/md/lvm-internal.h linux-2.4.19-pre5/drivers/md/lvm-internal.h --- linux-2.4.18/drivers/md/lvm-internal.h Mon Feb 18 06:26:12 2002 +++ linux-2.4.19-pre5/drivers/md/lvm-internal.h Sat Mar 30 22:55:28 2002 @@ -1,5 +1,6 @@ + /* - * kernel/lvm-internal.h + * kernel/lvm_internal.h * * Copyright (C) 2001 Sistina Software * @@ -24,7 +25,9 @@ /* * Changelog * - * 05/01/2001:Joe Thornber - Factored this file out of lvm.c + * 05/01/2001 - Factored this file out of lvm.c (Joe Thornber) + * 11/01/2001 - Renamed lvm_internal and added declarations + * for lvm_fs.c stuff * */ @@ -33,7 +36,7 @@ #include -#define _LVM_INTERNAL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" +#define _LVM_INTERNAL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" /* global variables, defined in lvm.c */ extern char *lvm_version; @@ -42,11 +45,15 @@ extern const char *const lvm_name; +extern uint vg_count; extern vg_t *vg[]; extern struct file_operations lvm_chr_fops; extern struct block_device_operations lvm_blk_dops; +#define lvm_sectsize(dev) get_hardsect_size(dev) + +/* 2.4.8 had no global min/max macros, and 2.4.9's were flawed */ /* debug macros */ #ifdef DEBUG_IOCTL diff -urN linux-2.4.18/drivers/md/lvm-snap.c linux-2.4.19-pre5/drivers/md/lvm-snap.c --- linux-2.4.18/drivers/md/lvm-snap.c Sun Dec 23 16:23:43 2001 +++ linux-2.4.19-pre5/drivers/md/lvm-snap.c Sat Mar 30 22:55:28 2002 @@ -2,22 +2,22 @@ * kernel/lvm-snap.c * * Copyright (C) 2000 Andrea Arcangeli SuSE - * Heinz Mauelshagen, Sistina Software (persistent snapshots) + * 2000 - 2001 Heinz Mauelshagen, Sistina Software * * LVM snapshot driver 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) * any later version. - * + * * LVM snapshot driver 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -28,52 +28,66 @@ * 23/11/2000 - used cpu_to_le64 rather than my own macro * 25/01/2001 - Put LockPage back in * 01/02/2001 - A dropped snapshot is now set as inactive + * 14/02/2001 - tidied debug statements + * 19/02/2001 - changed rawio calls to pass in preallocated buffer_heads + * 26/02/2001 - introduced __brw_kiovec to remove a lot of conditional + * compiles. + * 07/03/2001 - fixed COW exception table not persistent on 2.2 (HM) * 12/03/2001 - lvm_pv_get_number changes: * o made it static * o renamed it to _pv_get_number * o pv number is returned in new uint * arg * o -1 returned on error * lvm_snapshot_fill_COW_table has a return value too. + * 15/10/2001 - fix snapshot alignment problem [CM] + * - fix snapshot full oops (always check lv_block_exception) [CM] * */ #include -#include #include #include #include #include #include #include +#include #include "lvm-internal.h" -static char *lvm_snap_version __attribute__ ((unused)) = - "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n"; +static char *lvm_snap_version __attribute__ ((unused)) = "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n"; extern const char *const lvm_name; extern int lvm_blocksizes[]; void lvm_snapshot_release(lv_t *); + static int _write_COW_table_block(vg_t *vg, lv_t *lv, int idx, - const char **reason); + const char **reason); static void _disable_snapshot(vg_t *vg, lv_t *lv); -static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn) { +static inline int __brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, + lv_t *lv) { + return brw_kiovec(rw, nr, iovec, dev, b, size); +} + + +static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn) +{ uint p; - for(p = 0; p < vg->pv_max; p++) { - if(vg->pv[p] == NULL) + for (p = 0; p < vg->pv_max; p++) { + if (vg->pv[p] == NULL) continue; - if(vg->pv[p]->pv_dev == rdev) + if (vg->pv[p]->pv_dev == rdev) break; - } - if(p >= vg->pv_max) { + if (p >= vg->pv_max) { /* bad news, the snapshot COW table is probably corrupt */ printk(KERN_ERR "%s -- _pv_get_number failed for rdev = %u\n", @@ -85,6 +99,7 @@ return 0; } + #define hashfn(dev,block,mask,chunk_size) \ ((HASHDEV(dev)^((block)/(chunk_size))) & (mask)) @@ -129,10 +144,20 @@ unsigned long mask = lv->lv_snapshot_hash_mask; int chunk_size = lv->lv_chunk_size; + if (!hash_table) + BUG(); hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; list_add(&exception->hash, hash_table); } +/* + * Determine if we already have a snapshot chunk for this block. + * Return: 1 if it the chunk already exists + * 0 if we need to COW this block and allocate a new chunk + * -1 if the snapshot was disabled because it ran out of space + * + * We need to be holding at least a read lock on lv->lv_lock. + */ int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, unsigned long pe_start, lv_t * lv) { @@ -142,6 +167,9 @@ int chunk_size = lv->lv_chunk_size; lv_block_exception_t * exception; + if (!lv->lv_block_exception) + return -1; + pe_off = pe_start % chunk_size; pe_adjustment = (*org_sector-pe_off) % chunk_size; __org_start = *org_sector - pe_adjustment; @@ -166,8 +194,8 @@ or error on this snapshot --> release it */ invalidate_buffers(lv_snap->lv_dev); - /* wipe the snapshot since it's inconsistent now */ - _disable_snapshot(vg, lv_snap); + /* wipe the snapshot since it's inconsistent now */ + _disable_snapshot(vg, lv_snap); for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { @@ -186,15 +214,15 @@ } static inline int lvm_snapshot_prepare_blocks(unsigned long *blocks, - unsigned long start, - int nr_sectors, - int blocksize) + unsigned long start, + int nr_sectors, + int blocksize) { int i, sectors_per_block, nr_blocks; sectors_per_block = blocksize / SECTOR_SIZE; - if(start & (sectors_per_block - 1)) + if (start & (sectors_per_block - 1)) return 0; nr_blocks = nr_sectors / sectors_per_block; @@ -245,49 +273,51 @@ int lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) { - uint pvn; - int id = 0, is = lv_snap->lv_remap_ptr; - ulong blksize_snap; - lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) - page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); + int id = 0, is = lv_snap->lv_remap_ptr; + ulong blksize_snap; + lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) + page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); - if (is == 0) - return 0; + if (is == 0) + return 0; is--; - blksize_snap = - lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); - is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); + blksize_snap = + lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); + is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); memset(lv_COW_table, 0, blksize_snap); for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { /* store new COW_table entry */ - lv_block_exception_t *be = lv_snap->lv_block_exception + is; - if(_pv_get_number(vg, be->rdev_org, &pvn)) - goto bad; + lv_block_exception_t *be = lv_snap->lv_block_exception + is; + uint pvn; - lv_COW_table[id].pv_org_number = cpu_to_le64(pvn); - lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org); - if(_pv_get_number(vg, be->rdev_new, &pvn)) - goto bad; + if (_pv_get_number(vg, be->rdev_org, &pvn)) + goto bad; - lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn); - lv_COW_table[id].pv_snap_rsector = - cpu_to_le64(be->rsector_new); + lv_COW_table[id].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org); + + if (_pv_get_number(vg, be->rdev_new, &pvn)) + goto bad; + + lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_snap_rsector = cpu_to_le64(be->rsector_new); } - return 0; + return 0; bad: - printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name); - return -1; + printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name); + return -1; } /* * writes a COW exception table sector to disk (HM) + * + * We need to hold a write lock on lv_snap->lv_lock. */ - int lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap) { int r; @@ -305,6 +335,10 @@ * if there is no exception storage space free any longer --> release snapshot. * * this routine gets called for each _first_ write to a physical chunk. + * + * We need to hold a write lock on lv_snap->lv_lock. It is assumed that + * lv->lv_block_exception is non-NULL (checked by lvm_snapshot_remap_block()) + * when this function is called. */ int lvm_snapshot_COW(kdev_t org_phys_dev, unsigned long org_phys_sector, @@ -314,8 +348,10 @@ { const char * reason; unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; + unsigned long phys_start; int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; - struct kiobuf * iobuf; + struct kiobuf * iobuf = lv_snap->lv_iobuf; + unsigned long *blocks = iobuf->blocks; int blksize_snap, blksize_org, min_blksize, max_blksize; int max_sectors, nr_sectors; @@ -345,10 +381,8 @@ org_virt_sector); #endif - iobuf = lv_snap->lv_iobuf; - - blksize_org = lvm_get_blksize(org_phys_dev); - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_org = lvm_sectsize(org_phys_dev); + blksize_snap = lvm_sectsize(snap_phys_dev); max_blksize = max(blksize_org, blksize_snap); min_blksize = min(blksize_org, blksize_snap); max_sectors = KIO_MAX_SECTORS * (min_blksize>>9); @@ -356,6 +390,9 @@ if (chunk_size % (max_blksize>>9)) goto fail_blksize; + /* Don't change org_start, we need it to fill in the exception table */ + phys_start = org_start; + while (chunk_size) { nr_sectors = min(chunk_size, max_sectors); @@ -363,21 +400,24 @@ iobuf->length = nr_sectors << 9; - if(!lvm_snapshot_prepare_blocks(iobuf->blocks, org_start, - nr_sectors, blksize_org)) + if (!lvm_snapshot_prepare_blocks(blocks, phys_start, + nr_sectors, blksize_org)) goto fail_prepare; - if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, - iobuf->blocks, blksize_org) != (nr_sectors<<9)) + if (__brw_kiovec(READ, 1, &iobuf, org_phys_dev, blocks, + blksize_org, lv_snap) != (nr_sectors<<9)) goto fail_raw_read; - if(!lvm_snapshot_prepare_blocks(iobuf->blocks, snap_start, - nr_sectors, blksize_snap)) + if (!lvm_snapshot_prepare_blocks(blocks, snap_start, + nr_sectors, blksize_snap)) goto fail_prepare; - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - iobuf->blocks, blksize_snap) != (nr_sectors<<9)) + if (__brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, blocks, + blksize_snap, lv_snap) != (nr_sectors<<9)) goto fail_raw_write; + + phys_start += nr_sectors; + snap_start += nr_sectors; } #ifdef DEBUG_SNAPSHOT @@ -401,24 +441,24 @@ return 0; /* slow path */ - out: +out: lvm_drop_snapshot(vg, lv_snap, reason); return 1; - fail_out_of_space: +fail_out_of_space: reason = "out of space"; goto out; - fail_raw_read: +fail_raw_read: reason = "read error"; goto out; - fail_raw_write: +fail_raw_write: reason = "write error"; goto out; - fail_blksize: +fail_blksize: reason = "blocksize error"; goto out; - fail_prepare: +fail_prepare: reason = "couldn't prepare kiovec blocks " "(start probably isn't block aligned)"; goto out; @@ -441,8 +481,7 @@ struct page * page; page = alloc_page(GFP_KERNEL); - if (!page) - goto out; + if (!page) goto out; iobuf->maplist[i] = page; LockPage(page); @@ -451,7 +490,8 @@ iobuf->offset = 0; err = 0; - out: + +out: return err; } @@ -515,13 +555,12 @@ if (ret) goto out_free_kiovec; ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf, - PAGE_SIZE/SECTOR_SIZE); + PAGE_SIZE/SECTOR_SIZE); if (ret) goto out_free_both_kiovecs; ret = lvm_snapshot_alloc_hash_table(lv_snap); if (ret) goto out_free_both_kiovecs; - out: return ret; @@ -534,8 +573,7 @@ unmap_kiobuf(lv_snap->lv_iobuf); free_kiovec(1, &lv_snap->lv_iobuf); lv_snap->lv_iobuf = NULL; - if (lv_snap->lv_snapshot_hash_table != NULL) - vfree(lv_snap->lv_snapshot_hash_table); + vfree(lv_snap->lv_snapshot_hash_table); lv_snap->lv_snapshot_hash_table = NULL; goto out; } @@ -562,10 +600,10 @@ } if (lv->lv_COW_table_iobuf) { - kiobuf_wait_for_io(lv->lv_COW_table_iobuf); - unmap_kiobuf(lv->lv_COW_table_iobuf); - free_kiovec(1, &lv->lv_COW_table_iobuf); - lv->lv_COW_table_iobuf = NULL; + kiobuf_wait_for_io(lv->lv_COW_table_iobuf); + unmap_kiobuf(lv->lv_COW_table_iobuf); + free_kiovec(1, &lv->lv_COW_table_iobuf); + lv->lv_COW_table_iobuf = NULL; } } @@ -577,11 +615,11 @@ int idx_COW_table; uint pvn; ulong snap_pe_start, COW_table_sector_offset, - COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; + COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; ulong blocks[1]; kdev_t snap_phys_dev; lv_block_exception_t *be; - struct kiobuf * COW_table_iobuf = lv_snap->lv_COW_table_iobuf; + struct kiobuf *COW_table_iobuf = lv_snap->lv_COW_table_iobuf; lv_COW_table_disk_t * lv_COW_table = ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); @@ -592,46 +630,47 @@ snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_snap = lvm_sectsize(snap_phys_dev); COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t); idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block; if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap); - /* sector offset into the on disk COW table */ + /* sector offset into the on disk COW table */ COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t)); /* COW table block to write next */ blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); /* store new COW_table entry */ - be = lv_snap->lv_block_exception + idx; - if(_pv_get_number(vg, be->rdev_org, &pvn)) - goto fail_pv_get_number; - - lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn); - lv_COW_table[idx_COW_table].pv_org_rsector = - cpu_to_le64(be->rsector_org); - if(_pv_get_number(vg, snap_phys_dev, &pvn)) - goto fail_pv_get_number; - - lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn); - lv_COW_table[idx_COW_table].pv_snap_rsector = - cpu_to_le64(be->rsector_new); + be = lv_snap->lv_block_exception + idx; + if(_pv_get_number(vg, be->rdev_org, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_org_rsector = + cpu_to_le64(be->rsector_org); + if(_pv_get_number(vg, snap_phys_dev, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_snap_rsector = + cpu_to_le64(be->rsector_new); COW_table_iobuf->length = blksize_snap; + /* COW_table_iobuf->nr_pages = 1; */ - if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, - blocks, blksize_snap) != blksize_snap) + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != blksize_snap) goto fail_raw_write; - /* initialization of next COW exception table block with zeroes */ + /* initialization of next COW exception table block with zeroes */ end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1; if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) { /* don't go beyond the end */ - if (idx + 1 >= lv_snap->lv_remap_end) goto out; + if (idx + 1 >= lv_snap->lv_remap_end) goto out; memset(lv_COW_table, 0, blksize_snap); @@ -640,24 +679,24 @@ idx++; snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_snap = lvm_sectsize(snap_phys_dev); blocks[0] = snap_pe_start >> (blksize_snap >> 10); } else blocks[0]++; - if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, - blocks, blksize_snap) != + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != blksize_snap) goto fail_raw_write; } - out: +out: return 0; - fail_raw_write: +fail_raw_write: *reason = "write error"; return 1; - fail_pv_get_number: +fail_pv_get_number: *reason = "_pv_get_number failed"; return 1; } @@ -681,5 +720,3 @@ lvm_name, err); } } - -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/md/lvm.c linux-2.4.19-pre5/drivers/md/lvm.c --- linux-2.4.18/drivers/md/lvm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/md/lvm.c Sat Mar 30 22:55:28 2002 @@ -1,13 +1,13 @@ /* * kernel/lvm.c * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software * * February-November 1997 * April-May,July-August,November 1998 * January-March,May,July,September,October 1999 * January,February,July,September-November 2000 - * January 2001 + * January-April 2001 * * * LVM driver is free software; you can redistribute it and/or modify @@ -43,7 +43,8 @@ * support for free (eg. longer) logical volume names * 12/05/1998 - added spin_locks (thanks to Pascal van Dam * ) - * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and + * lvm_chr_ioctl() * 26/05/1998 - reactivated verify_area by access_ok * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go * beyond 128/256 KB max allocation limit per call @@ -125,7 +126,8 @@ * 14/02/2000 - support for 2.3.43 * - integrated Andrea Arcagneli's snapshot code * 25/06/2000 - james (chip) , IKKHAYD! roffl - * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support + * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume + * support * 06/09/2000 - added devfs support * 07/09/2000 - changed IOP version to 9 * - started to add new char ioctl LV_STATUS_BYDEV_T to support @@ -147,15 +149,24 @@ * 08/01/2001 - Removed conditional compiles related to PROC_FS, * procfs is always supported now. (JT) * 12/01/2001 - avoided flushing logical volume in case of shrinking - * because of unnecessary overhead in case of heavy updates + * because of unecessary overhead in case of heavy updates * 25/01/2001 - Allow RO open of an inactive LV so it can be reactivated. - * 31/01/2001 - If you try and BMAP a snapshot you now get an -EPERM - * 01/02/2001 - factored __remap_snapshot out of lvm_map + * 31/01/2001 - removed blk_init_queue/blk_cleanup_queue queueing will be + * handled by the proper devices. + * - If you try and BMAP a snapshot you now get an -EPERM + * 01/01/2001 - lvm_map() now calls buffer_IO_error on error for 2.4 + * - factored __remap_snapshot out of lvm_map * 12/02/2001 - move devfs code to create VG before LVs - * 14/02/2001 - tidied device defines for blk.h + * 13/02/2001 - allow VG_CREATE on /dev/lvm + * 14/02/2001 - removed modversions.h + * - tidied device defines for blk.h * - tidied debug statements + * - bug: vg[] member not set back to NULL if activation fails * - more lvm_map tidying - * 14/02/2001 - bug: vg[] member not set back to NULL if activation fails + * 15/02/2001 - register /dev/lvm with devfs correctly (major/minor + * were swapped) + * 19/02/2001 - preallocated buffer_heads for rawio when using + * snapshots [JT] * 28/02/2001 - introduced the P_DEV macro and changed some internel * functions to be static [AD] * 28/02/2001 - factored lvm_get_snapshot_use_rate out of blk_ioctl [AD] @@ -163,25 +174,50 @@ * where the check for an existing LV takes place right at * the beginning * 01/03/2001 - Add VG_CREATE_OLD for IOP 10 compatibility - * 02/03/2001 - Don't destroy usermode pointers in lv_t structures duing LV_ - * STATUS_BYxxx and remove redundant lv_t variables from same. + * 02/03/2001 - Don't destroy usermode pointers in lv_t structures duing + * LV_STATUS_BYxxx + * and remove redundant lv_t variables from same. + * - avoid compilation of lvm_dummy_device_request in case of + * Linux >= 2.3.0 to avoid a warning + * - added lvm_name argument to printk in buffer allocation + * in order to avoid a warning + * 04/03/2001 - moved linux/version.h above first use of KERNEL_VERSION + * macros * 05/03/2001 - restore copying pe_t array in lvm_do_lv_status_byname. For * lvdisplay -v (PC) * - restore copying pe_t array in lvm_do_lv_status_byindex (HM) * - added copying pe_t array in lvm_do_lv_status_bydev (HM) * - enhanced lvm_do_lv_status_by{name,index,dev} to be capable * to copy the lv_block_exception_t array to userspace (HM) - * 08/03/2001 - factored lvm_do_pv_flush out of lvm_chr_ioctl [HM] + * 08/03/2001 - initialize new lv_ptr->lv_COW_table_iobuf for snapshots; + * removed obsolete lv_ptr->lv_COW_table_page initialization + * - factored lvm_do_pv_flush out of lvm_chr_ioctl (HM) * 09/03/2001 - Added _lock_open_count to ensure we only drop the lock * when the locking process closes. - * 05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it - * destroys stacking devices. call b_end_io on failed maps. - * (Jens Axboe) - * - Defer writes to an extent that is being moved [JT + AD] - * 28/05/2001 - implemented missing BLKSSZGET ioctl [AD] + * 05/04/2001 - Defer writes to an extent that is being moved [JT] + * 05/04/2001 - use b_rdev and b_rsector rather than b_dev and b_blocknr in + * lvm_map() in order to make stacking devices more happy (HM) + * 11/04/2001 - cleaned up the pvmove queue code. I no longer retain the + * rw flag, instead WRITEA's are just dropped [JT] + * 30/04/2001 - added KERNEL_VERSION > 2.4.3 get_hardsect_size() rather + * than get_hardblocksize() call + * 03/05/2001 - Use copy_to/from_user to preserve pointers in + * lvm_do_status_by* + * 11/05/2001 - avoid accesses to inactive snapshot data in + * __update_hardsectsize() and lvm_do_lv_extend_reduce() (JW) + * 28/05/2001 - implemented missing BLKSSZGET ioctl + * 05/06/2001 - Move _pe_lock out of fast path for lvm_map when no PEs + * locked. Make buffer queue flush not need locking. + * Fix lvm_user_bmap() to set b_rsector for new lvm_map(). [AED] + * 30/06/2001 - Speed up __update_hardsectsize() by checking if PVs have + * the same hardsectsize (very likely) before scanning all LEs + * in the LV each time. [AED] + * 12/10/2001 - Use add/del_gendisk() routines in 2.4.10+ + * 01/11/2001 - Backport read_ahead change from Linus kernel [AED] * */ +#include #define MAJOR_NR LVM_BLK_MAJOR #define DEVICE_OFF(device) @@ -191,11 +227,10 @@ /* #define LVM_VFS_ENHANCEMENT */ #include - #include - #include #include + #include #include @@ -206,6 +241,8 @@ #include #include #include + + #include #include #include @@ -224,9 +261,13 @@ #include "lvm-internal.h" -#define LVM_CORRECT_READ_AHEAD( a) \ - if ( a < LVM_MIN_READ_AHEAD || \ - a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; +#define LVM_CORRECT_READ_AHEAD(a) \ +do { \ + if ((a) < LVM_MIN_READ_AHEAD || \ + (a) > LVM_MAX_READ_AHEAD) \ + (a) = LVM_DEFAULT_READ_AHEAD; \ + read_ahead[MAJOR_NR] = (a); \ +} while(0) #ifndef WRITEA # define WRITEA WRITE @@ -236,13 +277,14 @@ /* * External function prototypes */ -static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*); +static int lvm_make_request_fn(request_queue_t *, int, + struct buffer_head *); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); static int lvm_blk_close(struct inode *, struct file *); -static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg); +static int lvm_get_snapshot_use_rate(lv_t * lv_ptr, void *arg); static int lvm_user_bmap(struct inode *, struct lv_bmap *); static int lvm_chr_open(struct inode *, struct file *); @@ -272,13 +314,13 @@ static int lvm_do_lv_extend_reduce(int, char *, lv_t *); static int lvm_do_lv_remove(int, char *, int); static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *); -static int lvm_do_lv_status_byname(vg_t *r, void *); +static int lvm_do_lv_status_byname(vg_t * r, void *); static int lvm_do_lv_status_byindex(vg_t *, void *); static int lvm_do_lv_status_bydev(vg_t *, void *); -static int lvm_do_pe_lock_unlock(vg_t *r, void *); +static int lvm_do_pe_lock_unlock(vg_t * r, void *); -static int lvm_do_pv_change(vg_t*, void*); +static int lvm_do_pv_change(vg_t *, void *); static int lvm_do_pv_status(vg_t *, void *); static int lvm_do_pv_flush(void *); @@ -288,15 +330,15 @@ static int lvm_do_vg_rename(vg_t *, void *); static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); -static void __update_hardsectsize(lv_t *lv); +static void __update_hardsectsize(lv_t * lv); static void _queue_io(struct buffer_head *bh, int rw); static struct buffer_head *_dequeue_io(void); static void _flush_io(struct buffer_head *bh); -static int _open_pv(pv_t *pv); -static void _close_pv(pv_t *pv); +static int _open_pv(pv_t * pv); +static void _close_pv(pv_t * pv); static unsigned long _sectors_to_k(unsigned long sect); @@ -307,7 +349,8 @@ /* variables */ -char *lvm_version = "LVM version "LVM_RELEASE_NAME"("LVM_RELEASE_DATE")"; +char *lvm_version = + "LVM version " LVM_RELEASE_NAME "(" LVM_RELEASE_DATE ")"; ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; int loadtime = 0; const char *const lvm_name = LVM_NAME; @@ -351,18 +394,17 @@ struct file_operations lvm_chr_fops = { - open: lvm_chr_open, - release: lvm_chr_close, - ioctl: lvm_chr_ioctl, + open:lvm_chr_open, + release:lvm_chr_close, + ioctl:lvm_chr_ioctl, }; /* block device operations structure needed for 2.3.38? and above */ -struct block_device_operations lvm_blk_dops = -{ - owner: THIS_MODULE, - open: lvm_blk_open, - release: lvm_blk_close, - ioctl: lvm_blk_ioctl, +struct block_device_operations lvm_blk_dops = { + owner:THIS_MODULE, + open:lvm_blk_open, + release:lvm_blk_close, + ioctl:lvm_blk_ioctl, }; @@ -372,17 +414,17 @@ static int lvm_hardsectsizes[MAX_LV]; static int lvm_size[MAX_LV]; -static struct gendisk lvm_gendisk = -{ - major: MAJOR_NR, - major_name: LVM_NAME, - minor_shift: 0, - max_p: 1, - part: lvm_hd_struct, - sizes: lvm_size, - nr_real: MAX_LV, +static struct gendisk lvm_gendisk = { + major:MAJOR_NR, + major_name:LVM_NAME, + minor_shift:0, + max_p:1, + part:lvm_hd_struct, + sizes:lvm_size, + nr_real:MAX_LV, }; + /* * Driver initialization... */ @@ -394,7 +436,6 @@ lvm_name); return -EIO; } - if (devfs_register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) { printk("%s -- devfs_register_blkdev failed\n", lvm_name); @@ -409,6 +450,7 @@ lvm_init_vars(); lvm_geninit(&lvm_gendisk); + /* insert our gendisk at the corresponding major */ add_gendisk(&lvm_gendisk); #ifdef LVM_HD_NAME @@ -416,7 +458,8 @@ lvm_hd_name_ptr = lvm_hd_name; #endif - blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), + lvm_make_request_fn); /* initialise the pe lock */ @@ -434,12 +477,12 @@ #endif return 0; -} /* lvm_init() */ - +} /* lvm_init() */ /* * cleanup... */ + static void lvm_cleanup(void) { if (devfs_unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) @@ -449,6 +492,9 @@ printk(KERN_ERR "%s -- devfs_unregister_blkdev failed\n", lvm_name); + + + /* delete our gendisk from chain */ del_gendisk(&lvm_gendisk); blk_size[MAJOR_NR] = NULL; @@ -464,11 +510,12 @@ lvm_fin_fs(); #ifdef MODULE - printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); + printk(KERN_INFO "%s -- Module successfully deactivated\n", + lvm_name); #endif return; -} /* lvm_cleanup() */ +} /* lvm_cleanup() */ /* * support function to initialize lvm variables @@ -487,7 +534,8 @@ pe_lock_req.data.pv_offset = 0; /* Initialize VG pointers */ - for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; + for (v = 0; v < ABS_MAX_VG; v++) + vg[v] = NULL; /* Initialize LV -> VG association */ for (v = 0; v < ABS_MAX_LV; v++) { @@ -497,7 +545,7 @@ } return; -} /* lvm_init_vars() */ +} /* lvm_init_vars() */ /******************************************************************** @@ -514,28 +562,30 @@ */ static int lvm_chr_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + int minor = MINOR(inode->i_rdev); P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); /* super user validation */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; /* Group special file open */ - if (VG_CHR(minor) > MAX_VG) return -ENXIO; + if (VG_CHR(minor) > MAX_VG) + return -ENXIO; - spin_lock(&lvm_lock); - if(lock == current->pid) - _lock_open_count++; - spin_unlock(&lvm_lock); + spin_lock(&lvm_lock); + if (lock == current->pid) + _lock_open_count++; + spin_unlock(&lvm_lock); lvm_chr_open_count++; MOD_INC_USE_COUNT; return 0; -} /* lvm_chr_open() */ +} /* lvm_chr_open() */ /* @@ -546,22 +596,25 @@ * */ static int lvm_chr_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) + uint command, ulong a) { int minor = MINOR(inode->i_rdev); uint extendable, l, v; void *arg = (void *) a; lv_t lv; - vg_t* vg_ptr = vg[VG_CHR(minor)]; + vg_t *vg_ptr = vg[VG_CHR(minor)]; /* otherwise cc will complain about unused variables */ (void) lvm_lock; - P_IOCTL("chr MINOR: %d command: 0x%X arg: %p VG#: %d mode: %s%s\n", - minor, command, arg, VG_CHR(minor), MODE_TO_STR(file->f_mode)); + P_IOCTL + ("chr MINOR: %d command: 0x%X arg: %p VG#: %d mode: %s%s\n", + minor, command, arg, VG_CHR(minor), + MODE_TO_STR(file->f_mode)); #ifdef LVM_TOTAL_RESET - if (lvm_reset_spindown > 0) return -EACCES; + if (lvm_reset_spindown > 0) + return -EACCES; #endif /* Main command switch */ @@ -573,8 +626,8 @@ case LVM_GET_IOP_VERSION: /* check lvm version to ensure driver/tools+lib interoperability */ - if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0) - return -EFAULT; + if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != + 0) return -EFAULT; return 0; #ifdef LVM_TOTAL_RESET @@ -582,7 +635,8 @@ /* lock reset function */ lvm_reset_spindown = 1; for (v = 0; v < ABS_MAX_VG; v++) { - if (vg[v] != NULL) lvm_do_vg_remove(v); + if (vg[v] != NULL) + lvm_do_vg_remove(v); } #ifdef MODULE @@ -590,28 +644,28 @@ MOD_INC_USE_COUNT; while (GET_USE_COUNT(&__this_module) > 1) MOD_DEC_USE_COUNT; -#endif /* MODULE */ +#endif /* MODULE */ lock = 0; /* release lock */ wake_up_interruptible(&lvm_wait); return 0; -#endif /* LVM_TOTAL_RESET */ +#endif /* LVM_TOTAL_RESET */ case LE_REMAP: /* remap a logical extent (after moving the physical extent) */ - return lvm_do_le_remap(vg_ptr,arg); + return lvm_do_le_remap(vg_ptr, arg); case PE_LOCK_UNLOCK: /* lock/unlock i/o to a physical extent to move it to another physical volume (move's done in user space's pvmove) */ - return lvm_do_pe_lock_unlock(vg_ptr,arg); + return lvm_do_pe_lock_unlock(vg_ptr, arg); case VG_CREATE_OLD: /* create a VGDA */ return lvm_do_vg_create(arg, minor); - case VG_CREATE: - /* create a VGDA, assume VG number is filled in */ + case VG_CREATE: + /* create a VGDA, assume VG number is filled in */ return lvm_do_vg_create(arg, -1); case VG_EXTEND: @@ -633,9 +687,10 @@ case VG_SET_EXTENDABLE: /* set/clear extendability flag of volume group */ - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0) - return -EFAULT; + if (vg_ptr == NULL) + return -ENXIO; + if (copy_from_user(&extendable, arg, sizeof(extendable)) != + 0) return -EFAULT; if (extendable == VG_EXTENDABLE || extendable == ~VG_EXTENDABLE) { @@ -643,13 +698,15 @@ vg_ptr->vg_status |= VG_EXTENDABLE; else vg_ptr->vg_status &= ~VG_EXTENDABLE; - } else return -EINVAL; + } else + return -EINVAL; return 0; case VG_STATUS: /* get volume group data (only the vg_t struct) */ - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) return -EFAULT; return 0; @@ -682,21 +739,25 @@ case LV_REMOVE: case LV_RENAME: /* create, extend, reduce, remove or rename a logical volume */ - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0) return -EFAULT; if (command != LV_REMOVE) { - if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) - return -EFAULT; + if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != + 0) return -EFAULT; } switch (command) { case LV_CREATE: - return lvm_do_lv_create(minor, lv_req.lv_name, &lv); + return lvm_do_lv_create(minor, lv_req.lv_name, + &lv); case LV_EXTEND: case LV_REDUCE: - return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); + return lvm_do_lv_extend_reduce(minor, + lv_req.lv_name, + &lv); case LV_REMOVE: return lvm_do_lv_remove(minor, lv_req.lv_name, -1); @@ -724,17 +785,17 @@ case PV_CHANGE: /* change a physical volume */ - return lvm_do_pv_change(vg_ptr,arg); + return lvm_do_pv_change(vg_ptr, arg); case PV_STATUS: /* get physical volume data (pv_t structure only) */ - return lvm_do_pv_status(vg_ptr,arg); + return lvm_do_pv_status(vg_ptr, arg); case PV_FLUSH: /* physical volume buffer flush/invalidate */ - return lvm_do_pv_flush(arg); + return lvm_do_pv_flush(arg); default: @@ -745,7 +806,7 @@ } return 0; -} /* lvm_chr_ioctl */ +} /* lvm_chr_ioctl */ /* @@ -763,23 +824,25 @@ } #endif - if (lvm_chr_open_count > 0) lvm_chr_open_count--; + if (lvm_chr_open_count > 0) + lvm_chr_open_count--; - spin_lock(&lvm_lock); - if(lock == current->pid) { - if(!_lock_open_count) { - P_DEV("chr_close: unlocking LVM for pid %d\n", lock); - lock = 0; - wake_up_interruptible(&lvm_wait); - } else - _lock_open_count--; + spin_lock(&lvm_lock); + if (lock == current->pid) { + if (!_lock_open_count) { + P_DEV("chr_close: unlocking LVM for pid %d\n", + lock); + lock = 0; + wake_up_interruptible(&lvm_wait); + } else + _lock_open_count--; } - spin_unlock(&lvm_lock); + spin_unlock(&lvm_lock); MOD_DEC_USE_COUNT; return 0; -} /* lvm_chr_close() */ +} /* lvm_chr_close() */ @@ -799,7 +862,8 @@ vg_t *vg_ptr = vg[VG_BLK(minor)]; P_DEV("blk_open MINOR: %d VG#: %d LV#: %d mode: %s%s\n", - minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode)); + minor, VG_BLK(minor), LV_BLK(minor), + MODE_TO_STR(file->f_mode)); #ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) @@ -809,26 +873,25 @@ if (vg_ptr != NULL && (vg_ptr->vg_status & VG_ACTIVE) && (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL && - LV_BLK(minor) >= 0 && - LV_BLK(minor) < vg_ptr->lv_max) { + LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) { /* Check parallel LV spindown (LV remove) */ - if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; + if (lv_ptr->lv_status & LV_SPINDOWN) + return -EPERM; /* Check inactive LV and open for read/write */ /* We need to be able to "read" an inactive LV to re-activate it again */ if ((file->f_mode & FMODE_WRITE) && - (!(lv_ptr->lv_status & LV_ACTIVE))) - return -EPERM; + (!(lv_ptr->lv_status & LV_ACTIVE))) return -EPERM; if (!(lv_ptr->lv_access & LV_WRITE) && - (file->f_mode & FMODE_WRITE)) - return -EACCES; + (file->f_mode & FMODE_WRITE)) return -EACCES; - /* be sure to increment VG counter */ - if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; + /* be sure to increment VG counter */ + if (lv_ptr->lv_open == 0) + vg_ptr->lv_open++; lv_ptr->lv_open++; MOD_INC_USE_COUNT; @@ -838,7 +901,7 @@ return 0; } return -ENXIO; -} /* lvm_blk_open() */ +} /* lvm_blk_open() */ /* @@ -860,24 +923,26 @@ switch (command) { case BLKSSZGET: /* get block device sector size as needed e.g. by fdisk */ - return put_user(get_hardsect_size(inode->i_rdev), (int *) arg); + return put_user(lvm_sectsize(inode->i_rdev), (int *) arg); case BLKGETSIZE: /* return device size */ P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); - if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) + if (put_user(lv_ptr->lv_size, (unsigned long *) arg)) return -EFAULT; break; +#ifdef BLKGETSIZE64 case BLKGETSIZE64: - if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) + if (put_user((u64) lv_ptr->lv_size << 9, (u64 *) arg)) return -EFAULT; break; - +#endif case BLKFLSBUF: /* flush buffer cache */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; P_IOCTL("BLKFLSBUF\n"); @@ -888,22 +953,24 @@ case BLKRASET: /* set read ahead for block device */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; P_IOCTL("BLKRASET: %ld sectors for %s\n", (long) arg, kdevname(inode->i_rdev)); if ((long) arg < LVM_MIN_READ_AHEAD || - (long) arg > LVM_MAX_READ_AHEAD) - return -EINVAL; + (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; lv_ptr->lv_read_ahead = (long) arg; + LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead; break; case BLKRAGET: /* get current read ahead setting */ P_IOCTL("BLKRAGET %d\n", lv_ptr->lv_read_ahead); - if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) + if (put_user(lv_ptr->lv_read_ahead, (long *) arg)) return -EFAULT; break; @@ -917,16 +984,18 @@ unsigned char heads = 64; unsigned char sectors = 32; long start = 0; - short cylinders = lv_ptr->lv_size / heads / sectors; + short cylinders = + lv_ptr->lv_size / heads / sectors; if (copy_to_user((char *) &hd->heads, &heads, sizeof(heads)) != 0 || copy_to_user((char *) &hd->sectors, §ors, sizeof(sectors)) != 0 || copy_to_user((short *) &hd->cylinders, - &cylinders, sizeof(cylinders)) != 0 || - copy_to_user((long *) &hd->start, &start, - sizeof(start)) != 0) + &cylinders, + sizeof(cylinders)) != 0 + || copy_to_user((long *) &hd->start, &start, + sizeof(start)) != 0) return -EFAULT; P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n", @@ -937,9 +1006,10 @@ case LV_SET_ACCESS: /* set access flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; lv_ptr->lv_access = (ulong) arg; - if ( lv_ptr->lv_access & LV_WRITE) + if (lv_ptr->lv_access & LV_WRITE) set_device_ro(lv_ptr->lv_dev, 0); else set_device_ro(lv_ptr->lv_dev, 1); @@ -948,23 +1018,25 @@ case LV_SET_STATUS: /* set status flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) return -EPERM; lv_ptr->lv_status = (ulong) arg; break; case LV_BMAP: - /* turn logical block into (dev_t, block). non privileged. */ - /* don't bmap a snapshot, since the mapping can change */ - if(lv_ptr->lv_access & LV_SNAPSHOT) + /* turn logical block into (dev_t, block). non privileged. */ + /* don't bmap a snapshot, since the mapping can change */ + if (lv_ptr->lv_access & LV_SNAPSHOT) return -EPERM; return lvm_user_bmap(inode, (struct lv_bmap *) arg); case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; lv_ptr->lv_allocation = (ulong) arg; break; @@ -979,7 +1051,7 @@ } return 0; -} /* lvm_blk_ioctl() */ +} /* lvm_blk_ioctl() */ /* @@ -994,15 +1066,16 @@ P_DEV("blk_close MINOR: %d VG#: %d LV#: %d\n", minor, VG_BLK(minor), LV_BLK(minor)); - if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; + if (lv_ptr->lv_open == 1) + vg_ptr->lv_open--; lv_ptr->lv_open--; MOD_DEC_USE_COUNT; return 0; -} /* lvm_blk_close() */ +} /* lvm_blk_close() */ -static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg) +static int lvm_get_snapshot_use_rate(lv_t * lv, void *arg) { lv_snapshot_use_rate_req_t lv_rate_req; @@ -1020,7 +1093,7 @@ lv->lv_snapshot_use_rate = lv_rate_req.rate; if (lv->lv_remap_ptr * 100 / lv->lv_remap_end < lv->lv_snapshot_use_rate) - interruptible_sleep_on(&lv->lv_snapshot_wait); + interruptible_sleep_on(&lv->lv_snapshot_wait); break; case O_NONBLOCK: @@ -1044,19 +1117,20 @@ if (get_user(block, &user_result->lv_block)) return -EFAULT; - memset(&bh,0,sizeof bh); + memset(&bh, 0, sizeof bh); bh.b_blocknr = block; bh.b_dev = bh.b_rdev = inode->i_rdev; bh.b_size = lvm_get_blksize(bh.b_dev); - bh.b_rsector = block * (bh.b_size >> 9); - if ((err=lvm_map(&bh, READ)) < 0) { + bh.b_rsector = block * (bh.b_size >> 9); + bh.b_end_io = NULL; + if ((err = lvm_map(&bh, READ)) < 0) { printk("lvm map failed: %d\n", err); return -EINVAL; } return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || - put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ? - -EFAULT : 0; + put_user(bh.b_rsector / (bh.b_size >> 9), + &user_result->lv_block) ? -EFAULT : 0; } @@ -1065,7 +1139,8 @@ * (see init_module/lvm_init) */ static void __remap_snapshot(kdev_t rdev, ulong rsector, - ulong pe_start, lv_t *lv, vg_t *vg) { + ulong pe_start, lv_t * lv, vg_t * vg) +{ /* copy a chunk from the origin to a snapshot device */ down_write(&lv->lv_lock); @@ -1080,7 +1155,8 @@ } static inline void _remap_snapshot(kdev_t rdev, ulong rsector, - ulong pe_start, lv_t *lv, vg_t *vg) { + ulong pe_start, lv_t * lv, vg_t * vg) +{ int r; /* check to see if this chunk is already in the snapshot */ @@ -1097,7 +1173,8 @@ /* * extents destined for a pe that is on the move should be deferred */ -static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) { +static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) +{ return ((pe_lock_req.lock == LOCK_PE) && (pv == pe_lock_req.data.pv_dev) && (sector >= pe_lock_req.data.pv_offset) && @@ -1122,6 +1199,7 @@ return 0; } + static int lvm_map(struct buffer_head *bh, int rw) { int minor = MINOR(bh->b_rdev); @@ -1143,34 +1221,32 @@ goto bad; } - if ((rw == WRITE || rw == WRITEA) && - !(lv->lv_access & LV_WRITE)) { + if ((rw == WRITE || rw == WRITEA) && !(lv->lv_access & LV_WRITE)) { printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", lvm_name, lv->lv_name); goto bad; } - P_MAP("%s - lvm_map minor: %d *rdev: %s *rsector: %lu size:%lu\n", - lvm_name, minor, - kdevname(bh->b_rdev), - rsector_org, size); + P_MAP + ("%s - lvm_map minor: %d *rdev: %s *rsector: %lu size:%lu\n", + lvm_name, minor, kdevname(bh->b_rdev), rsector_org, size); if (rsector_org + size > lv->lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " - "%lu or size: %lu wrong for minor: %2d\n", - lvm_name, rsector_org, size, minor); + "%lu or size: %lu wrong for minor: %2d\n", + lvm_name, rsector_org, size, minor); goto bad; } - if (lv->lv_stripes < 2) { /* linear mapping */ + if (lv->lv_stripes < 2) { /* linear mapping */ /* get the index */ index = rsector_org / vg_this->pe_size; pe_start = lv->lv_current_pe[index].pe; rsector_map = lv->lv_current_pe[index].pe + - (rsector_org % vg_this->pe_size); + (rsector_org % vg_this->pe_size); rdev_map = lv->lv_current_pe[index].dev; P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", @@ -1183,22 +1259,23 @@ stripe_length = vg_this->pe_size * lv->lv_stripes; stripe_index = (rsector_org % stripe_length) / - lv->lv_stripesize; + lv->lv_stripesize; index = rsector_org / stripe_length + - (stripe_index % lv->lv_stripes) * - (lv->lv_allocated_le / lv->lv_stripes); + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); pe_start = lv->lv_current_pe[index].pe; rsector_map = lv->lv_current_pe[index].pe + - (rsector_org % stripe_length) - - (stripe_index % lv->lv_stripes) * lv->lv_stripesize - - stripe_index / lv->lv_stripes * - (lv->lv_stripes - 1) * lv->lv_stripesize; + (rsector_org % stripe_length) - + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; rdev_map = lv->lv_current_pe[index].dev; P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", - index, lv->lv_current_pe[index].pe, kdevname(rdev_map), - rsector_map, stripe_length, stripe_index); + index, lv->lv_current_pe[index].pe, + kdevname(rdev_map), rsector_map, stripe_length, + stripe_index); } /* @@ -1207,8 +1284,8 @@ * we need to queue this request, because this is in the fast path. */ if (rw == WRITE || rw == WRITEA) { - if(_defer_extent(bh, rw, rdev_map, - rsector_map, vg_this->pe_size)) { + if (_defer_extent(bh, rw, rdev_map, + rsector_map, vg_this->pe_size)) { up_read(&lv->lv_lock); return 0; @@ -1219,17 +1296,14 @@ lv->lv_current_pe[index].reads++; /* statistic */ /* snapshot volume exception handling on physical device address base */ - if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) + if (!(lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG))) goto out; - if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ - if (lv->lv_block_exception) - lvm_snapshot_remap_block(&rdev_map, &rsector_map, - pe_start, lv); - else - goto bad; - - } else if (rw == WRITE || rw == WRITEA) { /* snapshot origin */ + if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ + if (lvm_snapshot_remap_block + (&rdev_map, &rsector_map, pe_start, lv) < 0) + goto bad; + } else if (rw == WRITE || rw == WRITEA) { /* snapshot origin */ lv_t *snap; /* start with first snapshot and loop through all of @@ -1243,21 +1317,21 @@ /* Serializes the COW with the accesses to the snapshot device */ _remap_snapshot(rdev_map, rsector_map, - pe_start, snap, vg_this); + pe_start, snap, vg_this); } - } + } - out: + out: bh->b_rdev = rdev_map; bh->b_rsector = rsector_map; up_read(&lv->lv_lock); return 1; - bad: - buffer_IO_error(bh); + bad: + if (bh->b_end_io) buffer_IO_error(bh); up_read(&lv->lv_lock); return -1; -} /* lvm_map() */ +} /* lvm_map() */ /* @@ -1284,12 +1358,14 @@ #endif + + /* * make request function */ -static int lvm_make_request_fn(request_queue_t *q, - int rw, - struct buffer_head *bh) { +static int lvm_make_request_fn(request_queue_t * q, + int rw, struct buffer_head *bh) +{ return (lvm_map(bh, rw) <= 0) ? 0 : 1; } @@ -1304,7 +1380,7 @@ */ static int lvm_do_lock_lvm(void) { -lock_try_again: + lock_try_again: spin_lock(&lvm_lock); if (lock != 0 && lock != current->pid) { P_DEV("lvm_do_lock_lvm: locked by pid %d ...\n", lock); @@ -1322,19 +1398,20 @@ P_DEV("lvm_do_lock_lvm: locking LVM for pid %d\n", lock); spin_unlock(&lvm_lock); return 0; -} /* lvm_do_lock_lvm */ +} /* lvm_do_lock_lvm */ /* * character device support function lock/unlock physical extend */ -static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) +static int lvm_do_pe_lock_unlock(vg_t * vg_ptr, void *arg) { pe_lock_req_t new_lock; struct buffer_head *bh; uint p; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&new_lock, arg, sizeof(new_lock)) != 0) return -EFAULT; @@ -1345,7 +1422,8 @@ new_lock.data.pv_dev == vg_ptr->pv[p]->pv_dev) break; } - if (p == vg_ptr->pv_max) return -ENXIO; + if (p == vg_ptr->pv_max) + return -ENXIO; /* * this sync releaves memory pressure to lessen the @@ -1396,21 +1474,20 @@ /* * character device support function logical extend remap */ -static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) +static int lvm_do_le_remap(vg_t * vg_ptr, void *arg) { uint l, le; lv_t *lv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&le_remap_req, arg, - sizeof(le_remap_req_t)) != 0) - return -EFAULT; + sizeof(le_remap_req_t)) != 0) return -EFAULT; for (l = 0; l < vg_ptr->lv_max; l++) { lv_ptr = vg_ptr->lv[l]; if (lv_ptr != NULL && - strcmp(lv_ptr->lv_name, - le_remap_req.lv_name) == 0) { + strcmp(lv_ptr->lv_name, le_remap_req.lv_name) == 0) { for (le = 0; le < lv_ptr->lv_allocated_le; le++) { if (lv_ptr->lv_current_pe[le].dev == le_remap_req.old_dev && @@ -1429,7 +1506,7 @@ } } return -ENXIO; -} /* lvm_do_le_remap() */ +} /* lvm_do_le_remap() */ /* @@ -1443,7 +1520,7 @@ vg_t *vg_ptr; lv_t **snap_lv_ptr; - if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { + if ((vg_ptr = kmalloc(sizeof(vg_t), GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error VG at line %d\n", lvm_name, __LINE__); @@ -1451,20 +1528,22 @@ } /* get the volume group structure */ if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { - P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n", - arg, sizeof(vg_t)); + P_IOCTL + ("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n", + arg, sizeof(vg_t)); kfree(vg_ptr); return -EFAULT; } - /* VG_CREATE now uses minor number in VG structure */ - if (minor == -1) minor = vg_ptr->vg_number; + /* VG_CREATE now uses minor number in VG structure */ + if (minor == -1) + minor = vg_ptr->vg_number; /* Validate it */ - if (vg[VG_CHR(minor)] != NULL) { + if (vg[VG_CHR(minor)] != NULL) { P_IOCTL("lvm_do_vg_create ERROR: VG %d in use\n", minor); kfree(vg_ptr); - return -EPERM; + return -EPERM; } /* we are not that active so far... */ @@ -1481,7 +1560,7 @@ if (vg_ptr->lv_max > ABS_MAX_LV) { printk(KERN_WARNING - "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", + "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", lvm_name, vg_ptr->lv_max); kfree(vg_ptr); return -EPERM; @@ -1499,7 +1578,7 @@ /* user space address */ if ((pvp = vg_ptr->pv[p]) != NULL) { ret = lvm_do_pv_create(pvp, vg_ptr, p); - if ( ret != 0) { + if (ret != 0) { lvm_do_vg_remove(minor); return ret; } @@ -1507,7 +1586,7 @@ } size = vg_ptr->lv_max * sizeof(lv_t *); - if ((snap_lv_ptr = vmalloc ( size)) == NULL) { + if ((snap_lv_ptr = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n", lvm_name, __LINE__); @@ -1523,12 +1602,13 @@ /* user space address */ if ((lvp = vg_ptr->lv[l]) != NULL) { if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { - P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n", - lvp, sizeof(lv_t)); + P_IOCTL + ("ERROR: copying LV ptr %p (%d bytes)\n", + lvp, sizeof(lv_t)); lvm_do_vg_remove(minor); return -EFAULT; } - if ( lv.lv_access & LV_SNAPSHOT) { + if (lv.lv_access & LV_SNAPSHOT) { snap_lv_ptr[ls] = lvp; vg_ptr->lv[l] = NULL; ls++; @@ -1568,24 +1648,26 @@ vg_ptr->vg_status |= VG_ACTIVE; return 0; -} /* lvm_do_vg_create() */ +} /* lvm_do_vg_create() */ /* * character device support function VGDA extend */ -static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_extend(vg_t * vg_ptr, void *arg) { int ret = 0; uint p; pv_t *pv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (vg_ptr->pv_cur < vg_ptr->pv_max) { for (p = 0; p < vg_ptr->pv_max; p++) { - if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) { + if ((pv_ptr = vg_ptr->pv[p]) == NULL) { ret = lvm_do_pv_create(arg, vg_ptr, p); - if ( ret != 0) return ret; + if (ret != 0) + return ret; pv_ptr = vg_ptr->pv[p]; vg_ptr->pe_total += pv_ptr->pe_total; return 0; @@ -1593,26 +1675,28 @@ } } return -EPERM; -} /* lvm_do_vg_extend() */ +} /* lvm_do_vg_extend() */ /* * character device support function VGDA reduce */ -static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) { +static int lvm_do_vg_reduce(vg_t * vg_ptr, void *arg) +{ uint p; pv_t *pv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) return -EFAULT; for (p = 0; p < vg_ptr->pv_max; p++) { pv_ptr = vg_ptr->pv[p]; if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_name) == 0) { - if (pv_ptr->lv_cur > 0) return -EPERM; + strcmp(pv_ptr->pv_name, pv_name) == 0) { + if (pv_ptr->lv_cur > 0) + return -EPERM; lvm_do_pv_remove(vg_ptr, p); /* Make PV pointer array contiguous */ for (; p < vg_ptr->pv_max - 1; p++) @@ -1622,52 +1706,55 @@ } } return -ENXIO; -} /* lvm_do_vg_reduce */ +} /* lvm_do_vg_reduce */ /* * character device support function VG rename */ -static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg) +static int lvm_do_vg_rename(vg_t * vg_ptr, void *arg) { int l = 0, p = 0, len = 0; - char vg_name[NAME_LEN] = { 0,}; - char lv_name[NAME_LEN] = { 0,}; + char vg_name[NAME_LEN] = { 0, }; + char lv_name[NAME_LEN] = { 0, }; char *ptr = NULL; lv_t *lv_ptr = NULL; pv_t *pv_ptr = NULL; - if (vg_ptr == NULL) return -ENXIO; + /* If the VG doesn't exist in the kernel then just exit */ + if (!vg_ptr) + return 0; if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0) return -EFAULT; lvm_fs_remove_vg(vg_ptr); - strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1); - for ( l = 0; l < vg_ptr->lv_max; l++) - { - if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue; - strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name)); + strncpy(vg_ptr->vg_name, vg_name, sizeof(vg_name) - 1); + for (l = 0; l < vg_ptr->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) == NULL) + continue; + strncpy(lv_ptr->vg_name, vg_name, sizeof(vg_name)); ptr = strrchr(lv_ptr->lv_name, '/'); - if (ptr == NULL) ptr = lv_ptr->lv_name; - strncpy(lv_name, ptr, sizeof ( lv_name)); + if (ptr == NULL) + ptr = lv_ptr->lv_name; + strncpy(lv_name, ptr, sizeof(lv_name)); len = sizeof(LVM_DIR_PREFIX); strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX); strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len); - len += strlen ( vg_name); + len += strlen(vg_name); strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len); } - for ( p = 0; p < vg_ptr->pv_max; p++) - { - if ( (pv_ptr = vg_ptr->pv[p]) == NULL) continue; + for (p = 0; p < vg_ptr->pv_max; p++) { + if ((pv_ptr = vg_ptr->pv[p]) == NULL) + continue; strncpy(pv_ptr->vg_name, vg_name, NAME_LEN); } lvm_fs_create_vg(vg_ptr); return 0; -} /* lvm_do_vg_rename */ +} /* lvm_do_vg_rename */ /* @@ -1679,7 +1766,8 @@ vg_t *vg_ptr = vg[VG_CHR(minor)]; pv_t *pv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; #ifdef LVM_TOTAL_RESET if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0) @@ -1730,17 +1818,18 @@ MOD_DEC_USE_COUNT; return 0; -} /* lvm_do_vg_remove() */ +} /* lvm_do_vg_remove() */ /* * character device support function physical volume create */ -static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) { +static int lvm_do_pv_create(pv_t * pvp, vg_t * vg_ptr, ulong p) +{ pv_t *pv; int err; - pv = kmalloc(sizeof(pv_t),GFP_KERNEL); + pv = kmalloc(sizeof(pv_t), GFP_KERNEL); if (pv == NULL) { printk(KERN_CRIT "%s -- PV_CREATE: kmalloc error PV at line %d\n", @@ -1751,8 +1840,9 @@ memset(pv, 0, sizeof(*pv)); if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) { - P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", - pvp, sizeof(pv_t)); + P_IOCTL + ("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n", + pvp, sizeof(pv_t)); kfree(pv); return -EFAULT; } @@ -1773,13 +1863,14 @@ vg_ptr->pv[p] = pv; return 0; -} /* lvm_do_pv_create() */ +} /* lvm_do_pv_create() */ /* * character device support function physical volume remove */ -static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) { +static int lvm_do_pv_remove(vg_t * vg_ptr, ulong p) +{ pv_t *pv = vg_ptr->pv[p]; lvm_fs_remove_pv(vg_ptr, pv); @@ -1797,37 +1888,68 @@ } -static void __update_hardsectsize(lv_t *lv) { - int le, e; - int max_hardsectsize = 0, hardsectsize; - - for (le = 0; le < lv->lv_allocated_le; le++) { - hardsectsize = get_hardsect_size(lv->lv_current_pe[le].dev); - if (hardsectsize == 0) - hardsectsize = 512; - if (hardsectsize > max_hardsectsize) - max_hardsectsize = hardsectsize; - } - - /* only perform this operation on active snapshots */ - if ((lv->lv_access & LV_SNAPSHOT) && - (lv->lv_status & LV_ACTIVE)) { - for (e = 0; e < lv->lv_remap_end; e++) { - hardsectsize = get_hardsect_size( lv->lv_block_exception[e].rdev_new); - if (hardsectsize == 0) - hardsectsize = 512; - if (hardsectsize > max_hardsectsize) +static void __update_hardsectsize(lv_t * lv) +{ + int max_hardsectsize = 0, hardsectsize = 0; + int p; + + /* Check PVs first to see if they all have same sector size */ + for (p = 0; p < lv->vg->pv_cur; p++) { + pv_t *pv = lv->vg->pv[p]; + if (pv && (hardsectsize = lvm_sectsize(pv->pv_dev))) { + if (max_hardsectsize == 0) + max_hardsectsize = hardsectsize; + else if (hardsectsize != max_hardsectsize) { + P_DEV + ("%s PV[%d] (%s) sector size %d, not %d\n", + lv->lv_name, p, kdevname(pv->pv_dev), + hardsectsize, max_hardsectsize); + break; + } + } + } + + /* PVs have different block size, need to check each LE sector size */ + if (hardsectsize != max_hardsectsize) { + int le; + for (le = 0; le < lv->lv_allocated_le; le++) { + hardsectsize = + lvm_sectsize(lv->lv_current_pe[le].dev); + if (hardsectsize > max_hardsectsize) { + P_DEV + ("%s LE[%d] (%s) blocksize %d not %d\n", + lv->lv_name, le, + kdevname(lv->lv_current_pe[le].dev), + hardsectsize, max_hardsectsize); max_hardsectsize = hardsectsize; + } + } + + /* only perform this operation on active snapshots */ + if ((lv->lv_access & LV_SNAPSHOT) && + (lv->lv_status & LV_ACTIVE)) { + int e; + for (e = 0; e < lv->lv_remap_end; e++) { + hardsectsize = + lvm_sectsize(lv->lv_block_exception[e]. + rdev_new); + if (hardsectsize > max_hardsectsize) + max_hardsectsize = hardsectsize; + } } } + if (max_hardsectsize == 0) + max_hardsectsize = SECTOR_SIZE; + P_DEV("hardblocksize for LV %s is %d\n", + kdevname(lv->lv_dev), max_hardsectsize); lvm_hardsectsizes[MINOR(lv->lv_dev)] = max_hardsectsize; } /* * character device support function logical volume create */ -static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) +static int lvm_do_lv_create(int minor, char *lv_name, lv_t * lv) { int e, ret, l, le, l_new, p, size, activate = 1; ulong lv_status_save; @@ -1855,14 +1977,18 @@ else { for (l = 0; l < vg_ptr->lv_max; l++) { if (vg_ptr->lv[l] == NULL) - if (l_new == -1) l_new = l; + if (l_new == -1) + l_new = l; } } - if (l_new == -1) return -EPERM; - else l = l_new; + if (l_new == -1) + return -EPERM; + else + l = l_new; - if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; - printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", + if ((lv_ptr = kmalloc(sizeof(lv_t), GFP_KERNEL)) == NULL) {; + printk(KERN_CRIT + "%s -- LV_CREATE: kmalloc error LV at line %d\n", lvm_name, __LINE__); return -ENOMEM; } @@ -1876,7 +2002,7 @@ lv_ptr->lv_snapshot_next = NULL; lv_ptr->lv_block_exception = NULL; lv_ptr->lv_iobuf = NULL; - lv_ptr->lv_COW_table_iobuf = NULL; + lv_ptr->lv_COW_table_iobuf = NULL; lv_ptr->lv_snapshot_hash_table = NULL; lv_ptr->lv_snapshot_hash_table_size = 0; lv_ptr->lv_snapshot_hash_mask = 0; @@ -1894,8 +2020,7 @@ if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " - "at line %d\n", - lvm_name, size, __LINE__); + "at line %d\n", lvm_name, size, __LINE__); P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(lv_ptr); vg_ptr->lv[l] = NULL; @@ -1924,9 +2049,11 @@ lv_ptr->lv_snapshot_org = vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)]; if (lv_ptr->lv_snapshot_org != NULL) { - size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t); + size = + lv_ptr->lv_remap_end * + sizeof(lv_block_exception_t); - if(!size) { + if (!size) { printk(KERN_WARNING "%s -- zero length exception table requested\n", lvm_name); @@ -1934,34 +2061,37 @@ return -EINVAL; } - if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) { + if ( + (lv_ptr->lv_block_exception = + vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " "of %d byte at line %d\n", lvm_name, size, __LINE__); - P_KFREE("%s -- kfree %d\n", lvm_name, - __LINE__); + P_KFREE("%s -- kfree %d\n", + lvm_name, __LINE__); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -ENOMEM; } - if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { + if (copy_from_user + (lv_ptr->lv_block_exception, lvbe, + size)) { vfree(lv_ptr->lv_block_exception); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -EFAULT; } - if(lv_ptr->lv_block_exception[0].rsector_org == - LVM_SNAPSHOT_DROPPED_SECTOR) - { + if (lv_ptr->lv_block_exception[0]. + rsector_org == + LVM_SNAPSHOT_DROPPED_SECTOR) { printk(KERN_WARNING - "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n", + "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n", lvm_name); activate = 0; } - /* point to the original logical volume */ lv_ptr = lv_ptr->lv_snapshot_org; @@ -1971,36 +2101,54 @@ which can be the original logical volume */ lv_ptr = vg_ptr->lv[l]; /* now lv_ptr points to our new last snapshot logical volume */ - lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; - lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le; - lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; - lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; - lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; - lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; - lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; + lv_ptr->lv_current_pe = + lv_ptr->lv_snapshot_org->lv_current_pe; + lv_ptr->lv_allocated_snapshot_le = + lv_ptr->lv_allocated_le; + lv_ptr->lv_allocated_le = + lv_ptr->lv_snapshot_org-> + lv_allocated_le; + lv_ptr->lv_current_le = + lv_ptr->lv_snapshot_org->lv_current_le; + lv_ptr->lv_size = + lv_ptr->lv_snapshot_org->lv_size; + lv_ptr->lv_stripes = + lv_ptr->lv_snapshot_org->lv_stripes; + lv_ptr->lv_stripesize = + lv_ptr->lv_snapshot_org->lv_stripesize; /* Update the VG PE(s) used by snapshot reserve space. */ - vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le; + vg_ptr->pe_allocated += + lv_ptr->lv_allocated_snapshot_le; - if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0) - { + if ((ret = lvm_snapshot_alloc(lv_ptr)) != + 0) { vfree(lv_ptr->lv_block_exception); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return ret; } - for ( e = 0; e < lv_ptr->lv_remap_ptr; e++) - lvm_hash_link (lv_ptr->lv_block_exception + e, - lv_ptr->lv_block_exception[e].rdev_org, - lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); + for (e = 0; e < lv_ptr->lv_remap_ptr; e++) + lvm_hash_link(lv_ptr-> + lv_block_exception + + e, + lv_ptr-> + lv_block_exception + [e].rdev_org, + lv_ptr-> + lv_block_exception + [e].rsector_org, + lv_ptr); /* need to fill the COW exception table data into the page for disk i/o */ - if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) { - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EINVAL; - } - init_waitqueue_head(&lv_ptr->lv_snapshot_wait); + if (lvm_snapshot_fill_COW_page + (vg_ptr, lv_ptr)) { + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EINVAL; + } + init_waitqueue_head(&lv_ptr-> + lv_snapshot_wait); } else { kfree(lv_ptr); vg_ptr->lv[l] = NULL; @@ -2011,7 +2159,7 @@ vg_ptr->lv[l] = NULL; return -EINVAL; } - } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ + } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ lv_ptr = vg_ptr->lv[l]; lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; @@ -2022,6 +2170,7 @@ LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; + lv_ptr->vg = vg_ptr; __update_hardsectsize(lv_ptr); @@ -2038,22 +2187,24 @@ down_write(&org->lv_lock); org->lv_access |= LV_SNAPSHOT_ORG; - lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ + lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ + /* Link in the list of snapshot volumes */ - for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next); + for (last = org; last->lv_snapshot_next; + last = last->lv_snapshot_next); lv_ptr->lv_snapshot_prev = last; last->lv_snapshot_next = lv_ptr; up_write(&org->lv_lock); } /* activate the logical volume */ - if(activate) + if (activate) lv_ptr->lv_status |= LV_ACTIVE; else lv_ptr->lv_status &= ~LV_ACTIVE; - if ( lv_ptr->lv_access & LV_WRITE) + if (lv_ptr->lv_access & LV_WRITE) set_device_ro(lv_ptr->lv_dev, 0); else set_device_ro(lv_ptr->lv_dev, 1); @@ -2064,13 +2215,10 @@ unlockfs(lv_ptr->lv_snapshot_org->lv_dev); #endif - lv_ptr->vg = vg_ptr; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = - lvm_fs_create_lv(vg_ptr, lv_ptr); - + lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; -} /* lvm_do_lv_create() */ +} /* lvm_do_lv_create() */ /* @@ -2090,7 +2238,8 @@ } } } - if (l == vg_ptr->lv_max) return -ENXIO; + if (l == vg_ptr->lv_max) + return -ENXIO; lv_ptr = vg_ptr->lv[l]; #ifdef LVM_TOTAL_RESET @@ -2113,11 +2262,12 @@ * Atomically make the the snapshot invisible * to the original lv before playing with it. */ - lv_t * org = lv_ptr->lv_snapshot_org; + lv_t *org = lv_ptr->lv_snapshot_org; down_write(&org->lv_lock); /* remove this snapshot logical volume from the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; + lv_ptr->lv_snapshot_prev->lv_snapshot_next = + lv_ptr->lv_snapshot_next; if (lv_ptr->lv_snapshot_next != NULL) { lv_ptr->lv_snapshot_next->lv_snapshot_prev = lv_ptr->lv_snapshot_prev; @@ -2156,7 +2306,7 @@ vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; /* correct the PE count in PVs if this is not a snapshot - logical volume */ + logical volume */ if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { /* only if this is no snapshot logical volume because we share the lv_current_pe[] structs with the @@ -2177,228 +2327,240 @@ vg_ptr->lv[l] = NULL; vg_ptr->lv_cur--; return 0; -} /* lvm_do_lv_remove() */ +} /* lvm_do_lv_remove() */ /* * logical volume extend / reduce */ -static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { - ulong size; - lv_block_exception_t *lvbe; - - if (!new_lv->lv_block_exception) - return -ENXIO; - - size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); - if ((lvbe = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: vmalloc " - "error LV_BLOCK_EXCEPTION of %lu Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - - if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && - (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { - vfree(lvbe); - return -EFAULT; - } - new_lv->lv_block_exception = lvbe; - - if (lvm_snapshot_alloc_hash_table(new_lv)) { - vfree(new_lv->lv_block_exception); - return -ENOMEM; - } +static int __extend_reduce_snapshot(vg_t * vg_ptr, lv_t * old_lv, + lv_t * new_lv) +{ + ulong size; + lv_block_exception_t *lvbe; - return 0; + if (!new_lv->lv_block_exception) + return -ENXIO; + + size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); + if ((lvbe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: vmalloc " + "error LV_BLOCK_EXCEPTION of %lu Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + + if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && + (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { + vfree(lvbe); + return -EFAULT; + } + new_lv->lv_block_exception = lvbe; + + if (lvm_snapshot_alloc_hash_table(new_lv)) { + vfree(new_lv->lv_block_exception); + return -ENOMEM; + } + + return 0; } -static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { - ulong size, l, p, end; - pe_t *pe; - - /* allocate space for new pe structures */ - size = new_lv->lv_current_le * sizeof(pe_t); - if ((pe = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: " - "vmalloc error LV_CURRENT_PE of %lu Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - - /* get the PE structures from user space */ - if (copy_from_user(pe, new_lv->lv_current_pe, size)) { - if(old_lv->lv_access & LV_SNAPSHOT) - vfree(new_lv->lv_snapshot_hash_table); - vfree(pe); - return -EFAULT; - } - - new_lv->lv_current_pe = pe; - - /* reduce allocation counters on PV(s) */ - for (l = 0; l < old_lv->lv_allocated_le; l++) { - vg_ptr->pe_allocated--; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - old_lv->lv_current_pe[l].dev) { - vg_ptr->pv[p]->pe_allocated--; - break; - } - } - } - - /* extend the PE count in PVs */ - for (l = 0; l < new_lv->lv_allocated_le; l++) { - vg_ptr->pe_allocated++; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - new_lv->lv_current_pe[l].dev) { - vg_ptr->pv[p]->pe_allocated++; - break; - } - } - } - - /* save availiable i/o statistic data */ - if (old_lv->lv_stripes < 2) { /* linear logical volume */ - end = min(old_lv->lv_current_le, new_lv->lv_current_le); - for (l = 0; l < end; l++) { - new_lv->lv_current_pe[l].reads += - old_lv->lv_current_pe[l].reads; - - new_lv->lv_current_pe[l].writes += - old_lv->lv_current_pe[l].writes; - } - - } else { /* striped logical volume */ - uint i, j, source, dest, end, old_stripe_size, new_stripe_size; - - old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes; - new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes; - end = min(old_stripe_size, new_stripe_size); - - for (i = source = dest = 0; - i < new_lv->lv_stripes; i++) { - for (j = 0; j < end; j++) { - new_lv->lv_current_pe[dest + j].reads += - old_lv->lv_current_pe[source + j].reads; - new_lv->lv_current_pe[dest + j].writes += - old_lv->lv_current_pe[source + j].writes; - } - source += old_stripe_size; - dest += new_stripe_size; - } - } +static int __extend_reduce(vg_t * vg_ptr, lv_t * old_lv, lv_t * new_lv) +{ + ulong size, l, p, end; + pe_t *pe; + + /* allocate space for new pe structures */ + size = new_lv->lv_current_le * sizeof(pe_t); + if ((pe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: " + "vmalloc error LV_CURRENT_PE of %lu Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + + /* get the PE structures from user space */ + if (copy_from_user(pe, new_lv->lv_current_pe, size)) { + if (old_lv->lv_access & LV_SNAPSHOT) + vfree(new_lv->lv_snapshot_hash_table); + vfree(pe); + return -EFAULT; + } + + new_lv->lv_current_pe = pe; + + /* reduce allocation counters on PV(s) */ + for (l = 0; l < old_lv->lv_allocated_le; l++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + old_lv->lv_current_pe[l].dev) { + vg_ptr->pv[p]->pe_allocated--; + break; + } + } + } + + /* extend the PE count in PVs */ + for (l = 0; l < new_lv->lv_allocated_le; l++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + new_lv->lv_current_pe[l].dev) { + vg_ptr->pv[p]->pe_allocated++; + break; + } + } + } + + /* save availiable i/o statistic data */ + if (old_lv->lv_stripes < 2) { /* linear logical volume */ + end = min(old_lv->lv_current_le, new_lv->lv_current_le); + for (l = 0; l < end; l++) { + new_lv->lv_current_pe[l].reads += + old_lv->lv_current_pe[l].reads; + + new_lv->lv_current_pe[l].writes += + old_lv->lv_current_pe[l].writes; + } + + } else { /* striped logical volume */ + uint i, j, source, dest, end, old_stripe_size, + new_stripe_size; + + old_stripe_size = + old_lv->lv_allocated_le / old_lv->lv_stripes; + new_stripe_size = + new_lv->lv_allocated_le / new_lv->lv_stripes; + end = min(old_stripe_size, new_stripe_size); + + for (i = source = dest = 0; i < new_lv->lv_stripes; i++) { + for (j = 0; j < end; j++) { + new_lv->lv_current_pe[dest + j].reads += + old_lv->lv_current_pe[source + + j].reads; + new_lv->lv_current_pe[dest + j].writes += + old_lv->lv_current_pe[source + + j].writes; + } + source += old_stripe_size; + dest += new_stripe_size; + } + } - return 0; + return 0; } -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv) +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t * new_lv) { - int r; - ulong l, e, size; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *old_lv; - pe_t *pe; + int r; + ulong l, e, size; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *old_lv; + pe_t *pe; - if ((pe = new_lv->lv_current_pe) == NULL) - return -EINVAL; + if ((pe = new_lv->lv_current_pe) == NULL) + return -EINVAL; - for (l = 0; l < vg_ptr->lv_max; l++) - if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) - break; + for (l = 0; l < vg_ptr->lv_max; l++) + if (vg_ptr->lv[l] + && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) break; - if (l == vg_ptr->lv_max) - return -ENXIO; + if (l == vg_ptr->lv_max) + return -ENXIO; - old_lv = vg_ptr->lv[l]; + old_lv = vg_ptr->lv[l]; if (old_lv->lv_access & LV_SNAPSHOT) { /* only perform this operation on active snapshots */ if (old_lv->lv_status & LV_ACTIVE) - r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); - else + r = + __extend_reduce_snapshot(vg_ptr, old_lv, + new_lv); + else r = -EPERM; } else - r = __extend_reduce(vg_ptr, old_lv, new_lv); + r = __extend_reduce(vg_ptr, old_lv, new_lv); - if(r) - return r; + if (r) + return r; - /* copy relevent fields */ + /* copy relevent fields */ down_write(&old_lv->lv_lock); - if(new_lv->lv_access & LV_SNAPSHOT) { - size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? - old_lv->lv_remap_ptr : new_lv->lv_remap_end; - size *= sizeof(lv_block_exception_t); - memcpy(new_lv->lv_block_exception, - old_lv->lv_block_exception, size); - - old_lv->lv_remap_end = new_lv->lv_remap_end; - old_lv->lv_block_exception = new_lv->lv_block_exception; - old_lv->lv_snapshot_hash_table = - new_lv->lv_snapshot_hash_table; - old_lv->lv_snapshot_hash_table_size = - new_lv->lv_snapshot_hash_table_size; - old_lv->lv_snapshot_hash_mask = - new_lv->lv_snapshot_hash_mask; - - for (e = 0; e < new_lv->lv_remap_ptr; e++) - lvm_hash_link(new_lv->lv_block_exception + e, - new_lv->lv_block_exception[e].rdev_org, - new_lv->lv_block_exception[e].rsector_org, - new_lv); - - } else { - - vfree(old_lv->lv_current_pe); - vfree(old_lv->lv_snapshot_hash_table); - - old_lv->lv_size = new_lv->lv_size; - old_lv->lv_allocated_le = new_lv->lv_allocated_le; - old_lv->lv_current_le = new_lv->lv_current_le; - old_lv->lv_current_pe = new_lv->lv_current_pe; - lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = - old_lv->lv_size; - lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; - - if (old_lv->lv_access & LV_SNAPSHOT_ORG) { - lv_t *snap; - for(snap = old_lv->lv_snapshot_next; snap; - snap = snap->lv_snapshot_next) { + if (new_lv->lv_access & LV_SNAPSHOT) { + size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? + old_lv->lv_remap_ptr : new_lv->lv_remap_end; + size *= sizeof(lv_block_exception_t); + memcpy(new_lv->lv_block_exception, + old_lv->lv_block_exception, size); + + old_lv->lv_remap_end = new_lv->lv_remap_end; + old_lv->lv_block_exception = new_lv->lv_block_exception; + old_lv->lv_snapshot_hash_table = + new_lv->lv_snapshot_hash_table; + old_lv->lv_snapshot_hash_table_size = + new_lv->lv_snapshot_hash_table_size; + old_lv->lv_snapshot_hash_mask = + new_lv->lv_snapshot_hash_mask; + + for (e = 0; e < new_lv->lv_remap_ptr; e++) + lvm_hash_link(new_lv->lv_block_exception + e, + new_lv->lv_block_exception[e]. + rdev_org, + new_lv->lv_block_exception[e]. + rsector_org, new_lv); + + } else { + + vfree(old_lv->lv_current_pe); + vfree(old_lv->lv_snapshot_hash_table); + + old_lv->lv_size = new_lv->lv_size; + old_lv->lv_allocated_le = new_lv->lv_allocated_le; + old_lv->lv_current_le = new_lv->lv_current_le; + old_lv->lv_current_pe = new_lv->lv_current_pe; + lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = + old_lv->lv_size; + lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; + + if (old_lv->lv_access & LV_SNAPSHOT_ORG) { + lv_t *snap; + for (snap = old_lv->lv_snapshot_next; snap; + snap = snap->lv_snapshot_next) { down_write(&snap->lv_lock); - snap->lv_current_pe = old_lv->lv_current_pe; - snap->lv_allocated_le = - old_lv->lv_allocated_le; - snap->lv_current_le = old_lv->lv_current_le; - snap->lv_size = old_lv->lv_size; - - lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects - = old_lv->lv_size; - lvm_size[MINOR(snap->lv_dev)] = - old_lv->lv_size >> 1; - __update_hardsectsize(snap); + snap->lv_current_pe = + old_lv->lv_current_pe; + snap->lv_allocated_le = + old_lv->lv_allocated_le; + snap->lv_current_le = + old_lv->lv_current_le; + snap->lv_size = old_lv->lv_size; + + lvm_gendisk.part[MINOR(snap->lv_dev)]. + nr_sects = old_lv->lv_size; + lvm_size[MINOR(snap->lv_dev)] = + old_lv->lv_size >> 1; + __update_hardsectsize(snap); up_write(&snap->lv_lock); - } - } - } + } + } + } - __update_hardsectsize(old_lv); + __update_hardsectsize(old_lv); up_write(&old_lv->lv_lock); - return 0; -} /* lvm_do_lv_extend_reduce() */ + return 0; +} /* lvm_do_lv_extend_reduce() */ /* * character device support function logical volume status by name */ -static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) +static int lvm_do_lv_status_byname(vg_t * vg_ptr, void *arg) { uint l; lv_status_byname_req_t lv_status_byname_req; @@ -2406,184 +2568,206 @@ void *saved_ptr2; lv_t *lv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&lv_status_byname_req, arg, sizeof(lv_status_byname_req_t)) != 0) return -EFAULT; - if (lv_status_byname_req.lv == NULL) return -EINVAL; + if (lv_status_byname_req.lv == NULL) + return -EINVAL; for (l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL && strcmp(lv_ptr->lv_name, lv_status_byname_req.lv_name) == 0) { - /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->lv_current_pe, sizeof(void*)) != 0) + /* Save usermode pointers */ + if (copy_from_user + (&saved_ptr1, + &lv_status_byname_req.lv->lv_current_pe, + sizeof(void *)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->lv_block_exception, sizeof(void*)) != 0) - return -EFAULT; - if (copy_to_user(lv_status_byname_req.lv, - lv_ptr, - sizeof(lv_t)) != 0) + if (copy_from_user + (&saved_ptr2, + &lv_status_byname_req.lv->lv_block_exception, + sizeof(void *)) != 0) + return -EFAULT; + if (copy_to_user(lv_status_byname_req.lv, + lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; - if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, lv_ptr->lv_current_pe, lv_ptr->lv_allocated_le * - sizeof(pe_t)) != 0) + sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) - return -EFAULT; + if (copy_to_user + (&lv_status_byname_req.lv->lv_current_pe, + &saved_ptr1, sizeof(void *)) != 0) + return -EFAULT; return 0; } } return -ENXIO; -} /* lvm_do_lv_status_byname() */ +} /* lvm_do_lv_status_byname() */ /* * character device support function logical volume status by index */ -static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) +static int lvm_do_lv_status_byindex(vg_t * vg_ptr, void *arg) { lv_status_byindex_req_t lv_status_byindex_req; void *saved_ptr1; void *saved_ptr2; lv_t *lv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&lv_status_byindex_req, arg, sizeof(lv_status_byindex_req)) != 0) return -EFAULT; if (lv_status_byindex_req.lv == NULL) return -EINVAL; - if (lv_status_byindex_req.lv_index <0 || - lv_status_byindex_req.lv_index >= MAX_LV) + if (lv_status_byindex_req.lv_index < 0 || + lv_status_byindex_req.lv_index >= MAX_LV) return -EINVAL; - if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) + if ((lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) return -ENXIO; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0) - return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0) - return -EFAULT; - - if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0) + if (copy_from_user + (&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, + sizeof(void *)) != 0) + return -EFAULT; + if (copy_from_user + (&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, + sizeof(void *)) != 0) return -EFAULT; + + if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != + 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, lv_ptr->lv_current_pe, lv_ptr->lv_allocated_le * - sizeof(pe_t)) != 0) - return -EFAULT; + sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) - return -EFAULT; + if (copy_to_user + (&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, + sizeof(void *)) != 0) + return -EFAULT; return 0; -} /* lvm_do_lv_status_byindex() */ +} /* lvm_do_lv_status_byindex() */ /* * character device support function logical volume status by device number */ -static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) { +static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void *arg) +{ int l; lv_status_bydev_req_t lv_status_bydev_req; void *saved_ptr1; void *saved_ptr2; lv_t *lv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&lv_status_bydev_req, arg, sizeof(lv_status_bydev_req)) != 0) return -EFAULT; - for ( l = 0; l < vg_ptr->lv_max; l++) { - if ( vg_ptr->lv[l] == NULL) continue; - if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break; + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] == NULL) + continue; + if (vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) + break; } - if ( l == vg_ptr->lv_max) return -ENXIO; + if (l == vg_ptr->lv_max) + return -ENXIO; lv_ptr = vg_ptr->lv[l]; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0) - return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0) - return -EFAULT; - - if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0) + if (copy_from_user + (&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, + sizeof(void *)) != 0) return -EFAULT; + if (copy_from_user + (&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, + sizeof(void *)) != 0) + return -EFAULT; + + if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != + 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, lv_ptr->lv_current_pe, lv_ptr->lv_allocated_le * - sizeof(pe_t)) != 0) - return -EFAULT; + sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) - return -EFAULT; + if (copy_to_user + (&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, + sizeof(void *)) != 0) + return -EFAULT; return 0; -} /* lvm_do_lv_status_bydev() */ +} /* lvm_do_lv_status_bydev() */ /* * character device support function rename a logical volume */ -static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv) +static int lvm_do_lv_rename(vg_t * vg_ptr, lv_req_t * lv_req, lv_t * lv) { int l = 0; int ret = 0; lv_t *lv_ptr = NULL; - for (l = 0; l < vg_ptr->lv_max; l++) - { - if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; - if (lv_ptr->lv_dev == lv->lv_dev) - { + for (l = 0; l < vg_ptr->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) == NULL) + continue; + if (lv_ptr->lv_dev == lv->lv_dev) { lvm_fs_remove_lv(vg_ptr, lv_ptr); - strncpy(lv_ptr->lv_name, - lv_req->lv_name, + strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); lvm_fs_create_lv(vg_ptr, lv_ptr); break; } } - if (l == vg_ptr->lv_max) ret = -ENODEV; + if (l == vg_ptr->lv_max) + ret = -ENODEV; return ret; -} /* lvm_do_lv_rename */ +} /* lvm_do_lv_rename */ /* * character device support function physical volume change */ -static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_change(vg_t * vg_ptr, void *arg) { uint p; pv_t *pv_ptr; struct block_device *bd; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&pv_change_req, arg, - sizeof(pv_change_req)) != 0) - return -EFAULT; + sizeof(pv_change_req)) != 0) return -EFAULT; for (p = 0; p < vg_ptr->pv_max; p++) { pv_ptr = vg_ptr->pv[p]; if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_change_req.pv_name) == 0) { + strcmp(pv_ptr->pv_name, pv_change_req.pv_name) == 0) { bd = pv_ptr->bd; if (copy_from_user(pv_ptr, @@ -2599,53 +2783,52 @@ } } return -ENXIO; -} /* lvm_do_pv_change() */ +} /* lvm_do_pv_change() */ /* * character device support function get physical volume status */ -static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) +static int lvm_do_pv_status(vg_t * vg_ptr, void *arg) { uint p; pv_t *pv_ptr; - if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr == NULL) + return -ENXIO; if (copy_from_user(&pv_status_req, arg, - sizeof(pv_status_req)) != 0) - return -EFAULT; + sizeof(pv_status_req)) != 0) return -EFAULT; for (p = 0; p < vg_ptr->pv_max; p++) { pv_ptr = vg_ptr->pv[p]; if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_status_req.pv_name) == 0) { + strcmp(pv_ptr->pv_name, pv_status_req.pv_name) == 0) { if (copy_to_user(pv_status_req.pv, - pv_ptr, - sizeof(pv_t)) != 0) + pv_ptr, sizeof(pv_t)) != 0) return -EFAULT; return 0; } } return -ENXIO; -} /* lvm_do_pv_status() */ +} /* lvm_do_pv_status() */ + /* * character device support function flush and invalidate all buffers of a PV */ static int lvm_do_pv_flush(void *arg) { - pv_flush_req_t pv_flush_req; + pv_flush_req_t pv_flush_req; - if (copy_from_user(&pv_flush_req, arg, - sizeof(pv_flush_req)) != 0) - return -EFAULT; + if (copy_from_user(&pv_flush_req, arg, sizeof(pv_flush_req)) != 0) + return -EFAULT; - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + fsync_dev(pv_flush_req.pv_dev); + invalidate_buffers(pv_flush_req.pv_dev); - return 0; + return 0; } + /* * support function initialize gendisk variables */ @@ -2668,13 +2851,15 @@ hardsect_size[MAJOR_NR] = lvm_hardsectsizes; return; -} /* lvm_gen_init() */ +} /* lvm_gen_init() */ /* Must have down_write(_pe_lock) when we enqueue buffers */ -static void _queue_io(struct buffer_head *bh, int rw) { - if (bh->b_reqnext) BUG(); +static void _queue_io(struct buffer_head *bh, int rw) +{ + if (bh->b_reqnext) + BUG(); bh->b_reqnext = _pe_requests; _pe_requests = bh; } @@ -2708,17 +2893,19 @@ } } + /* * we must open the pv's before we use them */ -static int _open_pv(pv_t *pv) { +static int _open_pv(pv_t * pv) +{ int err; struct block_device *bd; if (!(bd = bdget(kdev_t_to_nr(pv->pv_dev)))) return -ENOMEM; - err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE); + err = blkdev_get(bd, FMODE_READ | FMODE_WRITE, 0, BDEV_FILE); if (err) return err; @@ -2726,7 +2913,8 @@ return 0; } -static void _close_pv(pv_t *pv) { +static void _close_pv(pv_t * pv) +{ if (pv) { struct block_device *bdev = pv->bd; pv->bd = NULL; @@ -2735,15 +2923,21 @@ } } + static unsigned long _sectors_to_k(unsigned long sect) { - if(SECTOR_SIZE > 1024) { + if (SECTOR_SIZE > 1024) { return sect * (SECTOR_SIZE / 1024); } return sect / (1024 / SECTOR_SIZE); } +MODULE_AUTHOR("Heinz Mauelshagen, Sistina Software"); +MODULE_DESCRIPTION("Logical Volume Manager"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + module_init(lvm_init); module_exit(lvm_cleanup); -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/media/video/bttv-cards.c linux-2.4.19-pre5/drivers/media/video/bttv-cards.c --- linux-2.4.18/drivers/media/video/bttv-cards.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/bttv-cards.c Sat Mar 30 22:55:28 2002 @@ -39,9 +39,9 @@ #include "tuner.h" /* fwd decl */ +static void boot_msp34xx(struct bttv *btv, int pin); static void hauppauge_eeprom(struct bttv *btv); static void avermedia_eeprom(struct bttv *btv); - static void init_PXC200(struct bttv *btv); #if 0 static void init_tea5757(struct bttv *btv); @@ -55,6 +55,9 @@ static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); +static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); +static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); +static void rv605_muxsel(struct bttv *btv, unsigned int input); /* config variables */ static int triton1=0; @@ -77,7 +80,8 @@ MODULE_PARM_DESC(triton1,"set ETBF pci config bit " "[enable bug compatibility for triton1 + others]"); MODULE_PARM(vsfx,"i"); -MODULE_PARM_DESC(vsfx,"set VSFX pci config bit [yet another chipset flaw workaround]"); +MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " + "[yet another chipset flaw workaround]"); MODULE_PARM(no_overlay,"i"); MODULE_PARM(card,"1-4i"); MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); @@ -151,7 +155,7 @@ { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" }, { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, + { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue" }, @@ -161,6 +165,7 @@ { 0x1127153b, BTTV_TERRATV, "Terratec TV+" }, { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, + { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, @@ -168,12 +173,14 @@ { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, { 0x010115cb, BTTV_GMV1, "AG GMV1" }, - { 0x010114c7, BTTV_MODTEC_205, "Modular Technology PCTV" }, + { 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM205 PCTV" }, { 0x18501851, BTTV_CHRONOS_VS2, "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" }, { 0x18511851, BTTV_FLYVIDEO98EZ, "Flyvideo 98EZ (LR51)/ CyberMail AV" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" }, + { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" }, { 0, -1, NULL } }; @@ -276,8 +283,8 @@ },{ /* ---- card 0x08 ---------------------------------- */ - name: "Fly Video II (Bt848)", - video_inputs: 3, + name: "FlyVideo II (Bt848) LR26", + video_inputs: 4, audio_inputs: 1, tuner: 0, svhs: 2, @@ -285,9 +292,10 @@ muxsel: { 2, 3, 1, 1}, audiomux: { 0, 0xc00, 0x800, 0x400, 0xc00, 0}, needs_tvaudio: 1, + pll: PLL_28, tuner_type: -1, },{ - name: "TurboTV", + name: "IXMicro TurboTV", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -346,14 +354,14 @@ pll: PLL_28, tuner_type: -1, },{ - name: "Aimslab VHX", + name: "Aimslab Video Highway Xtreme (VHX)", video_inputs: 3, audio_inputs: 1, tuner: 0, svhs: 2, gpiomask: 7, muxsel: { 2, 3, 1, 1}, - audiomux: { 0, 1, 2, 3, 4}, + audiomux: { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */ needs_tvaudio: 1, tuner_type: -1, },{ @@ -393,6 +401,7 @@ needs_tvaudio: 1, tuner_type: -1, audio_hook: winview_audio, + has_radio: 1, },{ name: "AVEC Intercapture", video_inputs: 3, @@ -438,7 +447,7 @@ pll: PLL_28, tuner_type: TUNER_PHILIPS_PAL_I, },{ - name: "Phoebe Tv Master + FM", + name: "Phoebe Tv Master + FM (CPH050)", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -752,6 +761,7 @@ gpiomask: 0x1f0000, muxsel: { 2, 3, 1, 1}, audiomux: { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff }, + needs_tvaudio: 1, no_msp34xx: 1, pll: PLL_35, tuner_type: 1, @@ -788,7 +798,7 @@ video_inputs: 4, audio_inputs: 1, tuner: 0, - svhs: 2, + svhs: 3, gpiomask: 0xAA0000, muxsel: { 2,3,1,1 }, audiomux: { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 }, @@ -860,7 +870,7 @@ },{ /* Miguel Angel Alvarez old Easy TV BT848 version (model CPH031) */ - name: "BESTBUY Easy TV", + name: "BESTBUY Easy TV (CPH031)", video_inputs: 4, audio_inputs: 1, tuner: 0, @@ -890,7 +900,7 @@ /* This is the ultimate cheapo capture card * just a BT848A on a small PCB! * Steve Hosgood */ - name: "GrandTec 'Grand Video Capture'", + name: "GrandTec 'Grand Video Capture' (Bt848)", video_inputs: 2, audio_inputs: 0, tuner: -1, @@ -904,7 +914,7 @@ tuner_type: -1, },{ /* Daniel Herrington */ - name: "Phoebe TV Master Only (No FM)", + name: "Phoebe TV Master Only (No FM) CPH060", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -917,7 +927,7 @@ tuner_type: TUNER_TEMIC_4036FY5_NTSC, },{ /* Matti Mottus */ - name: "TV Capturer", + name: "TV Capturer (CPH03X)", video_inputs: 4, audio_inputs: 1, tuner: 0, @@ -931,7 +941,7 @@ /* ---- card 0x3c ---------------------------------- */ /* Philip Blundell */ - name: "MM100PCTV", + name: "Modular Technology MM100PCTV", video_inputs: 2, audio_inputs: 2, gpiomask: 11, @@ -977,7 +987,7 @@ tuner: 0, svhs: 2, gpiomask: 0xf03f, - muxsel: { 2, 3, 0, 1}, + muxsel: { 2, 3, 1, 0 }, audiomux: { 0xbffe, 0, 0xbfff, 0, 0xbffe}, pll: PLL_28, tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL, @@ -1005,7 +1015,13 @@ svhs: 2, gpiomask: 0x18e0, muxsel: { 2, 3, 0, 1}, - audiomux: { 0,0x18e0,0x1000,0x1000,0x1080, 0x1080 }, + /* Radio changed from 1e80 to 0x800 to make + Flyvideo2000S in .hu happy (gm)*/ + /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ + audiomux: { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 }, + audio_hook: fv2000s_audio, + no_msp34xx: 1, + no_tda9875: 1, needs_tvaudio: 1, pll: PLL_28, tuner_type: 5, @@ -1047,11 +1063,12 @@ tuner: 0, svhs: -1, gpiomask: 0x4f8a00, - // 0x100000: 1=MSP enabled (0=disable again) - // 0x010000: somehow influences tuner picture quality (?) - audiomux: {0x947fff, 0x987fff,0x947fff,0x947fff}, - //tvtuner, radio, external,internal,mute,stereo - muxsel: { 2, 3 ,0 ,1}, /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ + // 0x100000: 1=MSP enabled (0=disable again) + // 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) + audiomux: {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, + // tvtuner, radio, external,internal, mute, stereo + /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ + muxsel: { 2, 3 ,0 ,1}, tuner_type: TUNER_MT2032, pll: PLL_28, has_radio: 1, @@ -1106,8 +1123,84 @@ tuner_type: -1, audio_hook: pvbt878p9b_audio, has_radio: 1, -} -}; +},{ + /* Clay Kunz */ + /* you must jumper JP5 for the card to work */ + name: "Sensoray 311", + video_inputs: 5, + audio_inputs: 0, + tuner: -1, + svhs: 4, + gpiomask: 0, + muxsel: { 2, 3, 1, 0, 0}, + audiomux: { 0 }, + needs_tvaudio: 0, + tuner_type: -1, +},{ + /* Miguel Freitas */ + name: "RemoteVision MX (RV605)", + video_inputs: 16, + audio_inputs: 0, + tuner: 0, + svhs: 0, + gpiomask: 0x00, + gpiomask2: 0x07ff, + muxsel: { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03, + 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, + no_msp34xx: 1, + no_tda9875: 1, + tuner_type: -1, + muxsel_hook: rv605_muxsel, +},{ + name: "Powercolor MTV878/ MTV878R/ MTV878F", + video_inputs: 3, + audio_inputs: 2, + svhs: 2, + gpiomask: 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset + muxsel: { 2, 1, 1, }, + audiomux: { 0, 1, 2, 2, 4 }, + needs_tvaudio: 0, + tuner_type: TUNER_PHILIPS_PAL, + pll: PLL_28, + has_radio: 1, +},{ + +/* ---- card 0x4c ---------------------------------- */ + /* Masaki Suzuki */ + name: "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + video_inputs: 3, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0x140007, + muxsel: { 2, 3, 1, 1 }, + audiomux: { 0, 1, 2, 3, 4, 0 }, + tuner_type: TUNER_PHILIPS_NTSC, + audio_hook: windvr_audio, +},{ + name: "GrandTec Multi Capture Card (Bt878)", + video_inputs: 4, + audio_inputs: 0, + tuner: -1, + svhs: -1, + gpiomask: 0, + muxsel: { 2, 3, 1, 0 }, + audiomux: { 0 }, + needs_tvaudio: 0, + no_msp34xx: 1, + pll: PLL_28, + tuner_type: -1, +},{ + /* http://www.aopen.com/products/video/va1000.htm */ + name: "AOPEN VA1000", + video_inputs: 3, /* coax, AV, s-vid */ + audio_inputs: 1, + tuner: 0, + tuner_type: TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */ + audiomux: { 2, 0, 0, 0 }, + muxsel: { 2, 3, 1, 0 }, + pll: PLL_28, +}}; const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); @@ -1195,12 +1288,58 @@ * (most) board specific initialisations goes here */ +static void flyvideo_gpio(struct bttv *btv) +{ + int gpio,outbits; + int tuner=-1,ttype; + + outbits = btread(BT848_GPIO_OUT_EN); + btwrite(0x00, BT848_GPIO_OUT_EN); + udelay(8); // without this we would see the 0x1800 mask + gpio=btread(BT848_GPIO_DATA); + btwrite(outbits, BT848_GPIO_OUT_EN); + // all cards provide GPIO info, some have an additional eeprom + + // lowest 3 bytes are remote control codes (no handshake needed) + ttype=(gpio&0x0f0000)>>16; + switch(ttype) { + case 0: tuner=4; // None + break; + case 4: tuner=5; // Philips PAL + break; + case 6: tuner=37; // LG PAL (newer TAPC series) + break; + case 0xC: tuner=3; // Philips SECAM(+PAL) + break; + default: + printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr); + } + + printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->nr, + gpio&0x400000? "yes":"no", + gpio&0x800000? "yes":"no", tuner, gpio); + + btv->tuner_type = tuner; + btv->has_radio = gpio&0x400000? 1:0; +} + int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0 }; -void __devinit bttv_init_card(struct bttv *btv) +/* initialization part one -- before registering i2c bus */ +void __devinit bttv_init_card1(struct bttv *btv) +{ + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) + boot_msp34xx(btv,5); + if (btv->type == BTTV_VOODOOTV_FM) + boot_msp34xx(btv,20); +} + +/* initialization part one -- after registering i2c bus */ +void __devinit bttv_init_card2(struct bttv *btv) { /* miro/pinnacle */ if (btv->type == BTTV_MIRO || @@ -1246,6 +1385,15 @@ #endif } + if (btv->type == BTTV_FLYVIDEO_98 || + btv->type == BTTV_FLYVIDEO || + btv->type == BTTV_TYPHOON_TVIEW || + btv->type == BTTV_CHRONOS_VS2 || + btv->type == BTTV_FLYVIDEO_98FM || + btv->type == BTTV_FLYVIDEO2000 || + btv->type == BTTV_FLYVIDEO98EZ) + flyvideo_gpio(btv); + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { /* pick up some config infos from the eeprom */ bttv_readee(btv,eeprom_data,0xa0); @@ -1449,22 +1597,24 @@ btv->tuner_type, radio ? "yes" : "no"); } -// AVermedia specific stuff... -// from bktr_card.c + +/* ----------------------------------------------------------------------- */ +/* AVermedia specific stuff, from bktr_card.c */ + int tuner_0_table[] = { TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL}; -/* +#if 0 int tuner_0_fm_table[] = { PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL}; -*/ +#endif int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, @@ -1475,11 +1625,12 @@ static void __devinit avermedia_eeprom(struct bttv *btv) { - int tuner_make,tuner_tv_fm,tuner_format,tuner=0; + int tuner_make,tuner_tv_fm,tuner_format,tuner=0,remote; tuner_make = (eeprom_data[0x41] & 0x7); tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; + remote = (eeprom_data[0x42] & 0x01); if (tuner_make == 0 || tuner_make == 2) if(tuner_format <=9) @@ -1492,11 +1643,32 @@ btv->nr,eeprom_data[0x41],eeprom_data[0x42]); if(tuner) { btv->tuner_type=tuner; - printk("%d\n",tuner); + printk("%d",tuner); } else - printk("Unknown type\n"); + printk("Unknown type"); + printk(" radio:%s remote control:%s\n", + tuner_tv_fm?"yes":"no", + remote?"yes":"no"); } +/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */ +void bttv_tda9880_setnorm(struct bttv *btv, int norm) +{ + // fix up our card entry + if(norm==VIDEO_MODE_NTSC) { + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff; + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff; + dprintk("bttv_tda9880_setnorm to NTSC\n"); + } + else { + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff; + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff; + dprintk("bttv_tda9880_setnorm to PAL\n"); + } + // set GPIO according + btaor(bttv_tvcards[btv->type].audiomux[btv->audio], + ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); +} /* @@ -1506,7 +1678,7 @@ * Hauppauge: pin 5 * Voodoo: pin 20 */ -void __devinit bttv_boot_msp34xx(struct bttv *btv, int pin) +static void __devinit boot_msp34xx(struct bttv *btv, int pin) { int mask = (1 << pin); @@ -1918,9 +2090,115 @@ } } else { v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } } + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +static void +fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0xffff; + +#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) + if (btv->radio_user) + return; +#else + if (btv->radio) + return; +#endif + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x0000; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ... + } + if (val != 0xffff) { + btaor(val, ~0x1800, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +static void +windvr_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) + val = 0x040000; + if (v->mode & VIDEO_SOUND_LANG1) + val = 0; + if (v->mode & VIDEO_SOUND_LANG2) + val = 0x100000; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0; + if (val) { + btaor(val, ~0x140000, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] + * + * This is needed because rv605 don't use a normal multiplex, but a crosspoint + * switch instead (CD22M3494E). This IC can have multiple active connections + * between Xn (input) and Yn (output) pins. We need to clear any existing + * connection prior to establish a new one, pulsing the STROBE pin. + * + * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. + * GPIO pins are wired as: + * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroler) + * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroler) + * GPIO[7] - DATA (xpoint) - P1[7] (microcontroler) + * GPIO[8] - - P3[5] (microcontroler) + * GPIO[9] - RESET (xpoint) - P3[6] (microcontroler) + * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroler) + * GPINTR - - P3[4] (microcontroler) + * + * The microcontroler is a 80C32 like. It should be possible to change xpoint + * configuration either directly (as we are doing) or using the microcontroler + * which is also wired to I2C interface. I have no further info on the + * microcontroler features, one would need to disassembly the firmware. + * note: the vendor refused to give any information on this product, all + * that stuff was found using a multimeter! :) + */ +static void rv605_muxsel(struct bttv *btv, unsigned int input) +{ + /* reset all conections */ + btaor(0x200,~0x200, BT848_GPIO_DATA); + mdelay(1); + btaor(0x000,~0x200, BT848_GPIO_DATA); + mdelay(1); + + /* create a new conection */ + btaor(0x080,~0x480, BT848_GPIO_DATA); + btaor(0x480,~0x480, BT848_GPIO_DATA); + mdelay(1); + btaor(0x080,~0x480, BT848_GPIO_DATA); + mdelay(1); +} + /* ----------------------------------------------------------------------- */ /* motherboard chipset specific stuff */ diff -urN linux-2.4.18/drivers/media/video/bttv-driver.c linux-2.4.19-pre5/drivers/media/video/bttv-driver.c --- linux-2.4.18/drivers/media/video/bttv-driver.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/media/video/bttv-driver.c Sat Mar 30 22:55:28 2002 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -70,6 +69,9 @@ static unsigned int gbufsize = BTTV_MAX_FBUF; static unsigned int combfilter = 0; static unsigned int lumafilter = 0; +static unsigned int automute = 1; +static unsigned int chroma_agc = 0; +static unsigned int adc_crush = 1; static int video_nr = -1; static int radio_nr = -1; static int vbi_nr = -1; @@ -96,8 +98,15 @@ MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)"); MODULE_PARM(gbufsize,"i"); MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); + MODULE_PARM(combfilter,"i"); MODULE_PARM(lumafilter,"i"); +MODULE_PARM(automute,"i"); +MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); +MODULE_PARM(chroma_agc,"i"); +MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); +MODULE_PARM(adc_crush,"i"); +MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); MODULE_PARM(video_nr,"i"); MODULE_PARM(radio_nr,"i"); @@ -279,7 +288,7 @@ static char *audio_modes[] = { "audio: tuner", "audio: radio", "audio: extern", "audio: intern", "audio: off" }; -static void audio(struct bttv *btv, int mode, int no_irq_context) +static void audio(struct bttv *btv, int mode) { btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN); @@ -313,12 +322,12 @@ ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); if (bttv_gpio) bttv_gpio_tracking(btv,audio_modes[mode]); - if (no_irq_context) + if (!in_interrupt()) bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); } -extern inline void bt848_dma(struct bttv *btv, uint state) +static inline void bt848_dma(struct bttv *btv, uint state) { if (state) btor(3, BT848_GPIO_DMA_CTL); @@ -425,18 +434,16 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input) { - -#if 0 /* seems no card uses this ... */ + /* needed by RemoteVideo MX */ btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_OUT_EN); -#endif /* This seems to get rid of some synchronization problems */ btand(~(3<<5), BT848_IFORM); - mdelay(10); - + mdelay(10); + input %= bttv_tvcards[btv->type].video_inputs; - if (input==bttv_tvcards[btv->type].svhs) + if (input==bttv_tvcards[btv->type].svhs) { btor(BT848_CONTROL_COMP, BT848_E_CONTROL); btor(BT848_CONTROL_COMP, BT848_O_CONTROL); @@ -446,20 +453,25 @@ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); } - btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); - audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? - AUDIO_EXTERN : AUDIO_TUNER, 1); -#if 0 /* seems no card uses this ... */ + btaor((bttv_tvcards[btv->type].muxsel[input]&3)<<5, ~(3<<5), BT848_IFORM); + audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? + AUDIO_EXTERN : AUDIO_TUNER); + btaor(bttv_tvcards[btv->type].muxsel[input]>>4, ~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); + + /* card specific hook */ + if( bttv_tvcards[btv->type].muxsel_hook ) + bttv_tvcards[btv->type].muxsel_hook ( btv, input ); + if (bttv_gpio) bttv_gpio_tracking(btv,"muxsel"); -#endif + } -struct tvnorm +struct tvnorm { u32 Fsc; u16 swidth, sheight; /* scaled standard width, height */ @@ -582,7 +594,7 @@ #define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int)) static int make_rawrisctab(struct bttv *btv, unsigned int *ro, - unsigned int *re, unsigned int *vbuf) + unsigned int *re, unsigned int *vbuf) { unsigned long line; unsigned long bpl=1024; /* bytes per line */ @@ -1054,8 +1066,7 @@ } -static void bt848_set_geo(struct bttv *btv, - int no_irq_context) +static void bt848_set_geo(struct bttv *btv) { u16 ewidth, eheight, owidth, oheight; u16 format, bswap; @@ -1070,7 +1081,7 @@ btwrite(1, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; - if (no_irq_context) + if (!in_interrupt()) set_pll(btv); btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; @@ -1162,7 +1173,7 @@ else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv,1); + bt848_set_geo(btv); } /* @@ -1194,7 +1205,7 @@ if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 > gbufsize) return -EINVAL; - if(-1 == palette2fmt[mp->format]) + if (-1 == palette2fmt[mp->format]) return -EINVAL; /* @@ -1352,7 +1363,7 @@ spin_lock_irqsave(&btv->s_lock, irq_flags); btv->errors = 0; btv->needs_restart = 0; - bt848_set_geo(btv,0); + bt848_set_geo(btv); bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); } @@ -1452,17 +1463,17 @@ /* ioctls and supporting functions */ /***********************************/ -extern inline void bt848_bright(struct bttv *btv, uint bright) +static inline void bt848_bright(struct bttv *btv, uint bright) { btwrite(bright&0xff, BT848_BRIGHT); } -extern inline void bt848_hue(struct bttv *btv, uint hue) +static inline void bt848_hue(struct bttv *btv, uint hue) { btwrite(hue&0xff, BT848_HUE); } -extern inline void bt848_contrast(struct bttv *btv, uint cont) +static inline void bt848_contrast(struct bttv *btv, uint cont) { unsigned int conthi; @@ -1472,7 +1483,7 @@ btaor(conthi, ~4, BT848_O_CONTROL); } -extern inline void bt848_sat_u(struct bttv *btv, unsigned long data) +static inline void bt848_sat_u(struct bttv *btv, unsigned long data) { u32 datahi; @@ -1495,7 +1506,6 @@ /* * ioctl routine */ - static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { @@ -1573,6 +1583,8 @@ bt848_muxsel(btv, v.channel); btv->channel=v.channel; if (btv->win.norm != v.norm) { + if(btv->type== BTTV_VOODOOTV_FM) + bttv_tda9880_setnorm(btv,v.norm); btv->win.norm = v.norm; make_vbitab(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); @@ -1638,10 +1650,12 @@ case VIDIOCSPICT: { struct video_picture p; - if(copy_from_user(&p, arg,sizeof(p))) + if (copy_from_user(&p, arg,sizeof(p))) return -EFAULT; if (p.palette > PALETTEFMT_MAX) return -EINVAL; + if (-1 == palette2fmt[p.palette]) + return -EINVAL; down(&btv->lock); /* We want -128 to 127 we get 0-65535 */ bt848_bright(btv, (p.brightness>>8)-128); @@ -1875,7 +1889,7 @@ return -EFAULT; down(&btv->lock); if(v.flags&VIDEO_AUDIO_MUTE) - audio(btv, AUDIO_MUTE, 1); + audio(btv, AUDIO_MUTE); /* One audio source per tuner -- huh? */ if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) { up(&btv->lock); @@ -1883,7 +1897,7 @@ } /* bt848_muxsel(btv,v.audio); */ if(!(v.flags&VIDEO_AUDIO_MUTE)) - audio(btv, AUDIO_UNMUTE, 1); + audio(btv, AUDIO_UNMUTE); bttv_call_i2c_clients(btv,cmd,&v); @@ -2368,6 +2382,12 @@ flags |= 0x03; if (btv->vbi_on) flags |= 0x0c; +#if 0 + /* Hmm ... */ + if ((0 != btv->risc_cap_even) || + (0 != btv->risc_cap_odd)) + flags |= 0x0c; +#endif } if (bttv_debug > 1) @@ -2467,15 +2487,19 @@ static int __devinit init_video_dev(struct bttv *btv) { - audio(btv, AUDIO_MUTE, 1); + audio(btv, AUDIO_MUTE); if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) return -1; + printk(KERN_INFO "bttv%d: registered device video%d\n", + btv->nr,btv->video_dev.minor & 0x1f); if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) { video_unregister_device(&btv->video_dev); return -1; } + printk(KERN_INFO "bttv%d: registered device vbi%d\n", + btv->nr,btv->vbi_dev.minor & 0x1f); if (btv->has_radio) { if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) @@ -2484,13 +2508,15 @@ video_unregister_device(&btv->video_dev); return -1; } + printk(KERN_INFO "bttv%d: registered device radio%d\n", + btv->nr,btv->radio_dev.minor & 0x1f); } return 1; } static int __devinit init_bt848(struct bttv *btv) { - int j; + int j,val; unsigned long irq_flags; btv->user=0; @@ -2592,8 +2618,8 @@ btwrite(0x20, BT848_E_VSCALE_HI); btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(/*BT848_ADC_SYNC_T|*/ - BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); + btwrite(BT848_ADC_RESERVED | (adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); if (lumafilter) { btwrite(0, BT848_E_CONTROL); @@ -2608,8 +2634,9 @@ btv->picture.hue=128<<8; btv->picture.contrast=0xd8<<7; - btwrite(0x00, BT848_E_SCLOOP); - btwrite(0x00, BT848_O_SCLOOP); + val = chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); /* clear interrupt status */ btwrite(0xfffffUL, BT848_INT_STAT); @@ -2633,17 +2660,14 @@ spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* needs to be done before i2c is registered */ - if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) - bttv_boot_msp34xx(btv,5); - if (btv->type == BTTV_VOODOOTV_FM) - bttv_boot_msp34xx(btv,20); + bttv_init_card1(btv); /* register i2c */ btv->tuner_type=-1; init_bttv_i2c(btv); /* some card-specific stuff (needs working i2c) */ - bttv_init_card(btv); + bttv_init_card2(btv); /* * Now add the template and register the device unit. @@ -2722,7 +2746,7 @@ btand(~15, BT848_GPIO_DMA_CTL); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); - bt848_set_geo(btv,0); + bt848_set_geo(btv); bt848_set_risc_jmps(btv,-1); spin_unlock(&btv->s_lock); } else { @@ -2764,14 +2788,14 @@ btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); + bt848_set_geo(btv); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); } else { btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); + bt848_set_geo(btv); btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); } @@ -2790,18 +2814,18 @@ btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); + bt848_set_geo(btv); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); spin_unlock(&btv->s_lock); } } - if (astat&BT848_INT_HLOCK) { + if (automute && (astat&BT848_INT_HLOCK)) { if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) - audio(btv, AUDIO_ON,0); + audio(btv, AUDIO_ON); else - audio(btv, AUDIO_OFF,0); + audio(btv, AUDIO_OFF); } count++; @@ -2869,7 +2893,7 @@ if (btv->vbibuf) vfree((void *) btv->vbibuf); - free_irq(btv->irq,btv); + free_irq(btv->dev->irq,btv); DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); if (btv->bt848_mem) iounmap(btv->bt848_mem); @@ -2904,6 +2928,8 @@ unsigned int cmd; #endif + if (bttv_num == BTTV_MAX) + return -ENOMEM; printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); btv=&bttvs[bttv_num]; @@ -2926,10 +2952,17 @@ memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); btv->id=dev->device; - btv->irq=dev->irq; btv->bt848_adr=pci_resource_start(dev,0); - if (pci_enable_device(dev)) + if (pci_enable_device(dev)) { + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->nr); + return -EIO; + } + if (pci_set_dma_mask(dev, 0xffffffff)) { + printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", + btv->nr); return -EIO; + } if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), "bttv")) { @@ -2946,7 +2979,7 @@ bttv_num,btv->id, btv->revision, dev->bus->number, PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn)); printk("irq: %d, latency: %d, memory: 0x%lx\n", - btv->irq, lat, btv->bt848_adr); + btv->dev->irq, lat, btv->bt848_adr); bttv_idcard(btv); @@ -2967,7 +3000,7 @@ /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); - result = request_irq(btv->irq, bttv_irq, + result = request_irq(btv->dev->irq, bttv_irq, SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); if (result==-EINVAL) { @@ -2977,7 +3010,7 @@ } if (result==-EBUSY) { - printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); + printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->dev->irq); goto fail1; } if (result < 0) @@ -3000,7 +3033,7 @@ return 0; fail2: - free_irq(btv->irq,btv); + free_irq(btv->dev->irq,btv); fail1: release_mem_region(pci_resource_start(btv->dev,0), pci_resource_len(btv->dev,0)); @@ -3028,7 +3061,7 @@ remove: bttv_remove, }; -int bttv_init_module(void) +static int bttv_init_module(void) { bttv_num = 0; @@ -3049,7 +3082,7 @@ return pci_module_init(&bttv_pci_driver); } -void bttv_cleanup_module(void) +static void bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); return; diff -urN linux-2.4.18/drivers/media/video/bttv.h linux-2.4.19-pre5/drivers/media/video/bttv.h --- linux-2.4.18/drivers/media/video/bttv.h Sun Feb 17 11:40:18 2002 +++ linux-2.4.19-pre5/drivers/media/video/bttv.h Sat Mar 30 22:55:28 2002 @@ -87,7 +87,9 @@ #define BTTV_PV_BT878P_PLUS 0x46 #define BTTV_FLYVIDEO98EZ 0x47 #define BTTV_PV_BT878P_9B 0x48 - +#define BTTV_SENSORAY311 0x49 +#define BTTV_RV605 0x4a +#define BTTV_WINDVR 0x4c /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -95,7 +97,7 @@ #define I2C_TDA8425 0x82 #define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ -#define I2C_TDA9874A 0xb0 /* also used by 9875 */ +#define I2C_TDA9874 0xb0 /* also used by 9875 */ #define I2C_TDA9875 0xb0 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae @@ -123,7 +125,7 @@ int tuner; int svhs; u32 gpiomask; - u32 muxsel[8]; + u32 muxsel[16]; u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ u32 gpiomask2; /* GPIO MUX mask */ @@ -141,6 +143,7 @@ int tuner_type; int has_radio; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; extern struct tvcard bttv_tvcards[]; @@ -148,11 +151,12 @@ /* identification / initialization of the card */ extern void bttv_idcard(struct bttv *btv); -extern void bttv_init_card(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); /* card-specific funtions */ extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -extern void bttv_boot_msp34xx(struct bttv *btv, int pin); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); /* kernel cmd line parse helper */ extern int bttv_parse(char *str, int max, int *vals); diff -urN linux-2.4.18/drivers/media/video/bttvp.h linux-2.4.19-pre5/drivers/media/video/bttvp.h --- linux-2.4.18/drivers/media/video/bttvp.h Sun Feb 17 11:40:38 2002 +++ linux-2.4.19-pre5/drivers/media/video/bttvp.h Sat Mar 30 22:55:28 2002 @@ -25,7 +25,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,83) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,91) #include @@ -136,7 +136,6 @@ unsigned int nr; unsigned short id; struct pci_dev *dev; - unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ diff -urN linux-2.4.18/drivers/media/video/id.h linux-2.4.19-pre5/drivers/media/video/id.h --- linux-2.4.18/drivers/media/video/id.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/id.h Sat Mar 30 22:55:28 2002 @@ -24,6 +24,12 @@ #ifndef I2C_DRIVERID_TDA7432 # define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6 #endif -#ifndef I2C_DRIVERID_TDA9874A -# define I2C_DRIVERID_TDA9874A I2C_DRIVERID_EXP0+7 +#ifndef I2C_DRIVERID_TDA9874 +# define I2C_DRIVERID_TDA9874 I2C_DRIVERID_EXP0+7 #endif + +/* algorithms */ +#ifndef I2C_ALGO_SAA7134 +# define I2C_ALGO_SAA7134 0x090000 +#endif + diff -urN linux-2.4.18/drivers/media/video/meye.c linux-2.4.19-pre5/drivers/media/video/meye.c --- linux-2.4.18/drivers/media/video/meye.c Sun Dec 23 16:23:43 2001 +++ linux-2.4.19-pre5/drivers/media/video/meye.c Sat Mar 30 22:55:34 2002 @@ -115,77 +115,29 @@ /* Memory allocation routines (stolen from bttv-driver.c) */ /****************************************************************************/ -#define MDEBUG(x) do {} while (0) -/* #define MDEBUG(x) x */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) { - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long)page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)\n", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) { - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)\n", adr, ret)); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) { - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)\n", adr, ret)); - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)\n", adr, ret)); return ret; } -static void *rvmalloc(signed long size) { +static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long)mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -193,14 +145,13 @@ return mem; } -static void rvfree(void * mem, signed long size) { - unsigned long adr, page; - +static void rvfree(void * mem, unsigned long size) { + unsigned long adr; + if (mem) { adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -209,31 +160,64 @@ } /* return a page table pointing to N pages of locked memory */ -static void *ptable_alloc(int npages, u32 *pt_addr) { +static int ptable_alloc(void) { + u32 *pt; int i; - void *vmem; - u32 *ptable; - unsigned long adr; - vmem = rvmalloc((npages + 1) * PAGE_SIZE); - if (!vmem) - return NULL; + memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); + + meye.mchip_ptable[MCHIP_NB_PAGES] = pci_alloc_consistent(meye.mchip_dev, + PAGE_SIZE, + &meye.mchip_dmahandle); + if (!meye.mchip_ptable[MCHIP_NB_PAGES]) + return -1; - adr = (unsigned long)vmem; - ptable = (u32 *)(vmem + npages * PAGE_SIZE); - for (i = 0; i < npages; i++) { - ptable[i] = (u32) kvirt_to_bus(adr); - adr += PAGE_SIZE; + pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES]; + for (i = 0; i < MCHIP_NB_PAGES; i++) { + meye.mchip_ptable[i] = pci_alloc_consistent(meye.mchip_dev, + PAGE_SIZE, + pt); + if (!meye.mchip_ptable[i]) + return -1; + pt++; } + return 0; +} - *pt_addr = (u32) kvirt_to_bus(adr); - return vmem; +static void ptable_free(void) { + u32 *pt; + int i; + + pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES]; + for (i = 0; i < MCHIP_NB_PAGES; i++) + if (meye.mchip_ptable[i]) + pci_free_consistent(meye.mchip_dev, + PAGE_SIZE, + meye.mchip_ptable[i], *pt); + + if (meye.mchip_ptable[MCHIP_NB_PAGES]) + pci_free_consistent(meye.mchip_dev, + PAGE_SIZE, + meye.mchip_ptable[MCHIP_NB_PAGES], + meye.mchip_dmahandle); + + memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); + meye.mchip_dmahandle = 0; } -static void ptable_free(void *vmem, int npages) { - rvfree(vmem, (npages + 1) * PAGE_SIZE); +/* copy data from ptable into buf */ +static void ptable_copy(u8 *buf, int start, int size, int pt_pages) { + int i; + + for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) { + memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE); + if (start >= pt_pages) + start = 0; + } + memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE); } + /****************************************************************************/ /* JPEG tables at different qualities to load into the VRJ chip */ /****************************************************************************/ @@ -587,29 +571,23 @@ /* setup for DMA transfers - also zeros the framebuffer */ static int mchip_dma_alloc(void) { - if (!meye.mchip_fbuffer) { - meye.mchip_fbuffer = ptable_alloc(MCHIP_NB_PAGES, - &meye.mchip_ptaddr); - if (!meye.mchip_fbuffer) + if (!meye.mchip_dmahandle) + if (ptable_alloc()) return -1; - } return 0; } /* frees the DMA buffer */ static void mchip_dma_free(void) { - if (meye.mchip_fbuffer) { - ptable_free(meye.mchip_fbuffer, MCHIP_NB_PAGES); - meye.mchip_fbuffer = 0; - meye.mchip_ptaddr = 0; - } + if (meye.mchip_dmahandle) + ptable_free(); } /* sets the DMA parameters into the chip */ static void mchip_dma_setup(void) { int i; - mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_ptaddr); + mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_dmahandle); for (i = 0; i < 4; i++) mchip_set(MCHIP_MM_FIR(i), 0); meye.mchip_fnum = 0; @@ -658,60 +636,41 @@ meye.mchip_fnum %= 4; } - /* read one frame from the framebuffer assuming it was captured using a uncompressed transfer */ -static void mchip_cont_read_frame(u32 v, u8 *buf, int size) { +static void mchip_cont_read_frame(u32 v, u8 *buf, int size) { int pt_id; - int avail; pt_id = (v >> 17) & 0x3FF; - avail = MCHIP_NB_PAGES - pt_id; - if (size > avail*PAGE_SIZE) { - memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, - avail * PAGE_SIZE); - memcpy(buf +avail * PAGE_SIZE, meye.mchip_fbuffer, - size - avail * PAGE_SIZE); - } - else - memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, size); + ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES); + } /* read a compressed frame from the framebuffer */ static int mchip_comp_read_frame(u32 v, u8 *buf, int size) { int pt_start, pt_end, trailer; - int fsize, fsize2; + int fsize; int i; pt_start = (v >> 19) & 0xFF; pt_end = (v >> 11) & 0xFF; trailer = (v >> 1) & 0x3FF; - if (pt_end < pt_start) { - fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE; - fsize2 = pt_end * PAGE_SIZE + trailer * 4; - if (fsize + fsize2 > size) { - printk(KERN_WARNING "meye: oversized compressed frame %d %d\n", - fsize, fsize2); - return -1; - } else { - memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, - fsize); - memcpy(buf + fsize, meye.mchip_fbuffer, fsize2); - fsize += fsize2; - } - } else { + if (pt_end < pt_start) + fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE + + pt_end * PAGE_SIZE + trailer * 4; + else fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; - if (fsize > size) { - printk(KERN_WARNING "meye: oversized compressed frame %d\n", - fsize); - return -1; - } else - memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, - fsize); + + if (fsize > size) { + printk(KERN_WARNING "meye: oversized compressed frame %d\n", + fsize); + return -1; } + ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG); + #ifdef MEYE_JPEG_CORRECTION @@ -909,124 +868,108 @@ /* video4linux integration */ /****************************************************************************/ -static int meye_open(struct video_device *dev, int flags) { - int i; +static int meye_open(struct inode *inode, struct file *file) { + int i, err; - down(&meye.lock); - if (meye.open_count) { - up(&meye.lock); - return -EBUSY; - } - meye.open_count++; + err = video_exclusive_open(inode,file); + if (err < 0) + return err; + if (mchip_dma_alloc()) { printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); - up(&meye.lock); + video_exclusive_release(inode,file); return -ENOBUFS; } mchip_hic_stop(); meye_initq(&meye.grabq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - up(&meye.lock); return 0; } -static void meye_close(struct video_device *dev) { - down(&meye.lock); - meye.open_count--; +static int meye_release(struct inode *inode, struct file *file) { mchip_hic_stop(); - up(&meye.lock); + video_exclusive_release(inode,file); + return 0; } -static int meye_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { +static int meye_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { switch (cmd) { case VIDIOCGCAP: { - struct video_capability b; - strcpy(b.name,meye.video_dev.name); - b.type = VID_TYPE_CAPTURE; - b.channels = 1; - b.audios = 0; - b.maxwidth = 640; - b.maxheight = 480; - b.minwidth = 320; - b.minheight = 240; - if(copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; + struct video_capability *b = arg; + strcpy(b->name,meye.video_dev.name); + b->type = VID_TYPE_CAPTURE; + b->channels = 1; + b->audios = 0; + b->maxwidth = 640; + b->maxheight = 480; + b->minwidth = 320; + b->minheight = 240; break; } case VIDIOCGCHAN: { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - if (v.channel != 0) - return -EINVAL; - strcpy(v.name,"Camera"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; + struct video_channel *v = arg; + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + if (v->channel != 0) + return -EINVAL; + strcpy(v->name,"Camera"); break; } case VIDIOCSCHAN: { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if (v.channel != 0) + struct video_channel *v = arg; + if (v->channel != 0) return -EINVAL; break; } case VIDIOCGPICT: { - struct video_picture p = meye.picture; - if(copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; + struct video_picture *p = arg; + *p = meye.picture; break; } case VIDIOCSPICT: { - struct video_picture p; - if(copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - if (p.depth != 2) + struct video_picture *p = arg; + if (p->depth != 2) return -EINVAL; - if (p.palette != VIDEO_PALETTE_YUV422) + if (p->palette != VIDEO_PALETTE_YUV422) return -EINVAL; down(&meye.lock); sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, - p.brightness >> 10); + p->brightness >> 10); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, - p.hue >> 10); + p->hue >> 10); sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, - p.colour >> 10); + p->colour >> 10); sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, - p.contrast >> 10); - memcpy(&meye.picture, &p, sizeof(p)); + p->contrast >> 10); + meye.picture = *p; up(&meye.lock); break; } case VIDIOCSYNC: { - int i; + int *i = arg; DECLARE_WAITQUEUE(wait, current); - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - if (i < 0 || i >= gbuffers) + if (*i < 0 || *i >= gbuffers) return -EINVAL; - switch (meye.grab_buffer[i].state) { + switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: return -EINVAL; case MEYE_BUF_USING: add_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_INTERRUPTIBLE; - while (meye.grab_buffer[i].state == MEYE_BUF_USING) { + while (meye.grab_buffer[*i].state == MEYE_BUF_USING) { schedule(); if(signal_pending(current)) { remove_wait_queue(&meye.grabq.proc_list, &wait); @@ -1038,36 +981,34 @@ current->state = TASK_RUNNING; /* fall through */ case MEYE_BUF_DONE: - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; } break; } case VIDIOCMCAPTURE: { - struct video_mmap vm; + struct video_mmap *vm = arg; int restart = 0; - if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) - return -EFAULT; - if (vm.frame >= gbuffers || vm.frame < 0) + if (vm->frame >= gbuffers || vm->frame < 0) return -EINVAL; - if (vm.format != VIDEO_PALETTE_YUV422) + if (vm->format != VIDEO_PALETTE_YUV422) return -EINVAL; - if (vm.height * vm.width * 2 > gbufsize) + if (vm->height * vm->width * 2 > gbufsize) return -EINVAL; if (!meye.grab_fbuffer) return -EINVAL; - if (meye.grab_buffer[vm.frame].state != MEYE_BUF_UNUSED) + if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); - if (vm.width == 640 && vm.height == 480) { + if (vm->width == 640 && vm->height == 480) { if (meye.params.subsample) { meye.params.subsample = 0; restart = 1; } } - else if (vm.width == 320 && vm.height == 240) { + else if (vm->width == 320 && vm->height == 240) { if (!meye.params.subsample) { meye.params.subsample = 1; restart = 1; @@ -1080,49 +1021,45 @@ if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT) mchip_continuous_start(); - meye.grab_buffer[vm.frame].state = MEYE_BUF_USING; - meye_pushq(&meye.grabq, vm.frame); + meye.grab_buffer[vm->frame].state = MEYE_BUF_USING; + meye_pushq(&meye.grabq, vm->frame); up(&meye.lock); break; } case VIDIOCGMBUF: { - struct video_mbuf vm; + struct video_mbuf *vm = arg; int i; - memset(&vm, 0 , sizeof(vm)); - vm.size = gbufsize * gbuffers; - vm.frames = gbuffers; + memset(vm, 0 , sizeof(*vm)); + vm->size = gbufsize * gbuffers; + vm->frames = gbuffers; for (i = 0; i < gbuffers; i++) - vm.offsets[i] = i * gbufsize; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; + vm->offsets[i] = i * gbufsize; break; } case MEYEIOC_G_PARAMS: { - if (copy_to_user(arg, &meye.params, sizeof(meye.params))) - return -EFAULT; + struct meye_params *p = arg; + *p = meye.params; break; } case MEYEIOC_S_PARAMS: { - struct meye_params jp; - if (copy_from_user(&jp, arg, sizeof(jp))) - return -EFAULT; - if (jp.subsample > 1) + struct meye_params *jp = arg; + if (jp->subsample > 1) return -EINVAL; - if (jp.quality > 10) + if (jp->quality > 10) return -EINVAL; - if (jp.sharpness > 63 || jp.agc > 63 || jp.picture > 63) + if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) return -EINVAL; - if (jp.framerate > 31) + if (jp->framerate > 31) return -EINVAL; down(&meye.lock); - if (meye.params.subsample != jp.subsample || - meye.params.quality != jp.quality) + if (meye.params.subsample != jp->subsample || + meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ - memcpy(&meye.params, &jp, sizeof(jp)); + meye.params = *jp; sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, meye.params.sharpness); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, @@ -1134,48 +1071,43 @@ } case MEYEIOC_QBUF_CAPT: { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) - return -EFAULT; + int *nb = arg; if (!meye.grab_fbuffer) return -EINVAL; - if (nb >= gbuffers) + if (*nb >= gbuffers) return -EINVAL; - if (nb < 0) { + if (*nb < 0) { /* stop capture */ mchip_hic_stop(); return 0; } - if (meye.grab_buffer[nb].state != MEYE_BUF_UNUSED) + if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) return -EBUSY; down(&meye.lock); if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) mchip_cont_compression_start(); - meye.grab_buffer[nb].state = MEYE_BUF_USING; - meye_pushq(&meye.grabq, nb); + meye.grab_buffer[*nb].state = MEYE_BUF_USING; + meye_pushq(&meye.grabq, *nb); up(&meye.lock); break; } case MEYEIOC_SYNC: { - int i; + int *i = arg; DECLARE_WAITQUEUE(wait, current); - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - if (i < 0 || i >= gbuffers) + if (*i < 0 || *i >= gbuffers) return -EINVAL; - switch (meye.grab_buffer[i].state) { + switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: return -EINVAL; case MEYE_BUF_USING: add_wait_queue(&meye.grabq.proc_list, &wait); current->state = TASK_INTERRUPTIBLE; - while (meye.grab_buffer[i].state == MEYE_BUF_USING) { + while (meye.grab_buffer[*i].state == MEYE_BUF_USING) { schedule(); if(signal_pending(current)) { remove_wait_queue(&meye.grabq.proc_list, &wait); @@ -1187,11 +1119,9 @@ current->state = TASK_RUNNING; /* fall through */ case MEYE_BUF_DONE: - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; } - i = meye.grab_buffer[i].size; - if (copy_to_user(arg, (void *)&i, sizeof(int))) - return -EFAULT; + *i = meye.grab_buffer[*i].size; break; } @@ -1213,7 +1143,7 @@ } case MEYEIOC_STILLJCAPT: { - int len = -1; + int *len = arg; if (!meye.grab_fbuffer) return -EINVAL; @@ -1221,14 +1151,13 @@ return -EBUSY; down(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; - while (len == -1) { + *len = -1; + while (*len == -1) { mchip_take_picture(); - len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); + *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); } meye.grab_buffer[0].state = MEYE_BUF_DONE; up(&meye.lock); - if (copy_to_user(arg, (void *)&len, sizeof(int))) - return -EFAULT; break; } @@ -1240,10 +1169,10 @@ return 0; } -static int meye_mmap(struct video_device *dev, const char *adr, - unsigned long size) { - unsigned long start=(unsigned long) adr; - unsigned long page,pos; +static int meye_mmap(struct file *file, struct vm_area_struct *vma) { + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long page, pos; down(&meye.lock); if (size > gbuffers * gbufsize) { @@ -1275,15 +1204,22 @@ return 0; } +static struct file_operations meye_fops = { + owner: THIS_MODULE, + open: meye_open, + release: meye_release, + mmap: meye_mmap, + ioctl: video_generic_ioctl, + llseek: no_llseek, +}; + static struct video_device meye_template = { owner: THIS_MODULE, name: "meye", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_MEYE, - open: meye_open, - close: meye_close, - ioctl: meye_ioctl, - mmap: meye_mmap, + fops: &meye_fops, + kernel_ioctl: meye_ioctl, }; static int __devinit meye_probe(struct pci_dev *pcidev, diff -urN linux-2.4.18/drivers/media/video/meye.h linux-2.4.19-pre5/drivers/media/video/meye.h --- linux-2.4.18/drivers/media/video/meye.h Sun Feb 17 01:21:50 2002 +++ linux-2.4.19-pre5/drivers/media/video/meye.h Sat Mar 30 22:55:34 2002 @@ -29,7 +29,7 @@ #define _MEYE_PRIV_H_ #define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 1 +#define MEYE_DRIVER_MINORVERSION 3 /****************************************************************************/ /* Motion JPEG chip registers */ @@ -292,15 +292,14 @@ u8 mchip_fnum; /* current mchip frame number */ unsigned char *mchip_mmregs; /* mchip: memory mapped registers */ - unsigned char *mchip_fbuffer; /* mchip: framebuffer */ - u32 mchip_ptaddr; /* mchip: pointer to framebuffer */ + u8 *mchip_ptable[MCHIP_NB_PAGES+1];/* mchip: ptable + ptable toc */ + dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ unsigned char *grab_fbuffer; /* capture framebuffer */ /* list of buffers */ struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; /* other */ - unsigned int open_count; /* open() count */ struct semaphore lock; /* semaphore for open/mmap... */ struct meye_queue grabq; /* queue for buffers to be grabbed */ diff -urN linux-2.4.18/drivers/media/video/msp3400.c linux-2.4.19-pre5/drivers/media/video/msp3400.c --- linux-2.4.18/drivers/media/video/msp3400.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/msp3400.c Sat Mar 30 22:55:28 2002 @@ -97,6 +97,7 @@ int nicam_on; int acb; int main, second; /* sound carrier */ + int input; int muted; int left, right; /* volume */ @@ -462,6 +463,8 @@ /* turn on/off nicam + stereo */ static void msp3400c_setstereo(struct i2c_client *client, int mode) { + static char *strmode[] = { "0", "mono", "stereo", "3", + "lang1", "5", "6", "7", "lang2" }; struct msp3400c *msp = client->data; int nicam=0; /* channel source: FM/AM or nicam */ int src=0; @@ -469,7 +472,7 @@ /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: - dprintk("msp3400: FM setstereo: %d\n",mode); + dprintk("msp3400: FM setstereo: %s\n",strmode[mode]); msp3400c_setcarrier(client,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: @@ -483,7 +486,7 @@ } break; case MSP_MODE_FM_SAT: - dprintk("msp3400: SAT setstereo: %d\n",mode); + dprintk("msp3400: SAT setstereo: %s\n",strmode[mode]); switch (mode) { case VIDEO_SOUND_MONO: msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); @@ -502,21 +505,21 @@ case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - dprintk("msp3400: NICAM setstereo: %d\n",mode); + dprintk("msp3400: NICAM setstereo: %s\n",strmode[mode]); msp3400c_setcarrier(client,msp->second,msp->main); if (msp->nicam_on) nicam=0x0100; break; case MSP_MODE_BTSC: - dprintk("msp3400: BTSC setstereo: %d\n",mode); + dprintk("msp3400: BTSC setstereo: %s\n",strmode[mode]); nicam=0x0300; break; case MSP_MODE_EXTERN: - dprintk("msp3400: extern setstereo: %d\n", mode); + dprintk("msp3400: extern setstereo: %s\n",strmode[mode]); nicam = 0x0200; break; case MSP_MODE_FM_RADIO: - dprintk("msp3400: FM-Radio setstereo: %d\n", mode); + dprintk("msp3400: FM-Radio setstereo: %s\n",strmode[mode]); break; default: dprintk("msp3400: mono setstereo\n"); @@ -627,7 +630,7 @@ switch (msp->mode) { case MSP_MODE_FM_TERRA: val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); - if (val > 32768) + if (val > 32767) val -= 65536; dprintk("msp34xx: stereo detect register: %d\n",val); @@ -822,7 +825,7 @@ msp->restart = 0; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) + if (val > 32767) val -= 65536; if (val1 < val) val1 = val, max1 = this; @@ -859,7 +862,7 @@ goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) + if (val > 32767) val -= 65536; if (val2 < val) val2 = val, max2 = this; @@ -1221,6 +1224,7 @@ static struct i2c_client client_template = { name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, driver: &driver, }; @@ -1253,6 +1257,7 @@ msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + msp->input = -1; for (i = 0; i < DFP_COUNT; i++) msp->dfp_regs[i] = -1; @@ -1391,6 +1396,9 @@ - IN1 is often used for external input - Hauppauge uses IN2 for the radio */ dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); + if (*sarg == msp->input) + break; + msp->input = *sarg; switch (*sarg) { case AUDIO_RADIO: msp->mode = MSP_MODE_FM_RADIO; @@ -1420,6 +1428,7 @@ break; case AUDC_SET_RADIO: + dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n"); msp->norm = VIDEO_MODE_RADIO; msp->watch_stereo=0; del_timer(&msp->wake_stereo); @@ -1471,6 +1480,7 @@ { struct video_audio *va = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | @@ -1497,6 +1507,7 @@ { struct video_audio *va = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n"); msp->muted = (va->flags & VIDEO_AUDIO_MUTE); msp->left = (MIN(65536 - va->balance,32768) * va->volume) / 32768; @@ -1520,6 +1531,7 @@ { struct video_channel *vc = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n"); dprintk("msp34xx: switching to TV mode\n"); msp->norm = vc->norm; break; @@ -1527,6 +1539,7 @@ case VIDIOCSFREQ: { /* new channel -- kick audio carrier scan */ + dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n"); msp_wake_thread(client); break; } @@ -1540,13 +1553,13 @@ /* ----------------------------------------------------------------------- */ -int msp3400_init_module(void) +static int msp3400_init_module(void) { i2c_add_driver(&driver); return 0; } -void msp3400_cleanup_module(void) +static void msp3400_cleanup_module(void) { i2c_del_driver(&driver); } diff -urN linux-2.4.18/drivers/media/video/stradis.c linux-2.4.19-pre5/drivers/media/video/stradis.c --- linux-2.4.18/drivers/media/video/stradis.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/stradis.c Sat Mar 30 22:55:39 2002 @@ -1972,7 +1972,9 @@ { struct saa7146 *saa = (struct saa7146 *) dev; - saa->video_dev.busy = 0; + /* FIXME: Don't do it this way, use the video_device->fops + * registration for a sane implementation of multiple opens */ + saa->video_dev.users--; saa->user++; if (saa->user > 1) return 0; /* device open already, don't reset */ @@ -1984,7 +1986,7 @@ { struct saa7146 *saa = (struct saa7146 *) dev; saa->user--; - saa->video_dev.busy = 0; + saa->video_dev.users++; if (saa->user > 0) /* still someone using device */ return; saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */ diff -urN linux-2.4.18/drivers/media/video/tda7432.c linux-2.4.19-pre5/drivers/media/video/tda7432.c --- linux-2.4.18/drivers/media/video/tda7432.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tda7432.c Sat Mar 30 22:55:28 2002 @@ -518,7 +518,7 @@ &driver }; -int tda7432_init(void) +static int tda7432_init(void) { if ( (loudness < 0) || (loudness > 15) ) @@ -531,7 +531,7 @@ return 0; } -void tda7432_fini(void) +static void tda7432_fini(void) { i2c_del_driver(&driver); } diff -urN linux-2.4.18/drivers/media/video/tda9875.c linux-2.4.19-pre5/drivers/media/video/tda9875.c --- linux-2.4.18/drivers/media/video/tda9875.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tda9875.c Sat Mar 30 22:55:28 2002 @@ -147,6 +147,24 @@ } #endif +static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg) +{ + unsigned char write[1]; + unsigned char read[1]; + struct i2c_msg msgs[2] = { + { addr, 0, 1, write }, + { addr, I2C_M_RD, 1, read } + }; + write[0] = reg; + + if (2 != i2c_transfer(adap,msgs,2)) { + printk(KERN_WARNING "tda9875: I/O error (read2)\n"); + return -1; + } + dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]); + return read[0]; +} + static void tda9875_set(struct i2c_client *client) { struct tda9875 *tda = client->data; @@ -215,6 +233,22 @@ * i2c interface functions * * *********************** */ +static int tda9875_checkit(struct i2c_adapter *adap, int addr) +{ + int dic,rev; + + dic=i2c_read_register(adap,addr,254); + rev=i2c_read_register(adap,addr,255); + + if(dic==0 || dic==2) { // tda9875 and tda9875A + printk("tda9875: TDA9875%s Rev.%d detected at 0x%x\n", + dic==0?"":"A", rev,addr<<1); + return 1; + } + printk("tda9875: no such chip at 0x%x (dic=0x%x rev=0x%x)\n",addr<<1,dic,rev); + return(0); +} + static int tda9875_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) { @@ -232,6 +266,11 @@ client->adapter = adap; client->addr = addr; client->data = t; + + if(!tda9875_checkit(adap,addr)) { + kfree(t); + return 1; + } do_tda9875_init(client); MOD_INC_USE_COUNT; @@ -375,22 +414,19 @@ &driver }; -#ifdef MODULE -int init_module(void) -#else -int tda9875_init(void) -#endif +static int tda9875_init(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +static void tda9875_fini(void) { i2c_del_driver(&driver); } -#endif + +module_init(tda9875_init); +module_exit(tda9875_fini); /* * Local variables: diff -urN linux-2.4.18/drivers/media/video/tuner.c linux-2.4.19-pre5/drivers/media/video/tuner.c --- linux-2.4.18/drivers/media/video/tuner.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tuner.c Sat Mar 30 22:55:28 2002 @@ -154,7 +154,7 @@ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, { "Alps TSBE1",TEMIC,PAL, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ @@ -175,7 +175,7 @@ { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL (4009 FR5)", TEMIC, PAL, + { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic NTSC (4039 FR5)", TEMIC, NTSC, 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, @@ -271,7 +271,7 @@ } #endif // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -int mt2032_init(struct i2c_client *c) +static int mt2032_init(struct i2c_client *c) { unsigned char buf[21]; int ret,xogc,xok=0; @@ -345,7 +345,7 @@ // IsSpurInBand()? -int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) +static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) { int n1=1,n2,f; @@ -373,7 +373,7 @@ return 1; } -int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from, +static int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from, int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz { int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, @@ -449,7 +449,7 @@ return 0; } -int mt2032_check_lo_lock(struct i2c_client *c) +static int mt2032_check_lo_lock(struct i2c_client *c) { int try,lock=0; unsigned char buf[2]; @@ -469,7 +469,7 @@ return lock; } -int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) { unsigned char buf[2]; int tad1; @@ -505,7 +505,7 @@ } -void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to) +static void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; @@ -560,7 +560,7 @@ } -void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm) +static void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm) { int if2,from,to; @@ -815,14 +815,27 @@ static int tuner_probe(struct i2c_adapter *adap) { + int rc; + if (0 != addr) { normal_i2c_range[0] = addr; normal_i2c_range[1] = addr; } this_adap = 0; - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_SAA7134: + printk("tuner: probing %s i2c adapter [id=0x%x]\n", + adap->name,adap->id); + rc = i2c_probe(adap, &addr_data, tuner_attach); + break; + default: + printk("tuner: ignoring %s i2c adapter [id=0x%x]\n", + adap->name,adap->id); + rc = 0; + /* nothing */ + } + return rc; } static int tuner_detach(struct i2c_client *client) @@ -948,39 +961,34 @@ /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { - "i2c TV tuner driver", - I2C_DRIVERID_TUNER, - I2C_DF_NOTIFY, - tuner_probe, - tuner_detach, - tuner_command, + name: "i2c TV tuner driver", + id: I2C_DRIVERID_TUNER, + flags: I2C_DF_NOTIFY, + attach_adapter: tuner_probe, + detach_client: tuner_detach, + command: tuner_command, }; - static struct i2c_client client_template = { - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver + name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, + driver: &driver, }; -EXPORT_NO_SYMBOLS; - -int tuner_init_module(void) +static int tuner_init_module(void) { i2c_add_driver(&driver); return 0; } -void tuner_cleanup_module(void) +static void tuner_cleanup_module(void) { i2c_del_driver(&driver); } module_init(tuner_init_module); module_exit(tuner_cleanup_module); +EXPORT_NO_SYMBOLS; /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN linux-2.4.18/drivers/media/video/tuner.h linux-2.4.19-pre5/drivers/media/video/tuner.h --- linux-2.4.18/drivers/media/video/tuner.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tuner.h Sat Mar 30 22:55:28 2002 @@ -22,6 +22,8 @@ #ifndef _TUNER_H #define _TUNER_H +#include "id.h" + #define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ #define TUNER_PHILIPS_PAL_I 1 #define TUNER_PHILIPS_NTSC 2 diff -urN linux-2.4.18/drivers/media/video/tvaudio.c linux-2.4.19-pre5/drivers/media/video/tvaudio.c --- linux-2.4.18/drivers/media/video/tvaudio.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tvaudio.c Sat Mar 30 22:55:28 2002 @@ -120,14 +120,17 @@ /* current settings */ __u16 left,right,treble,bass,mode; int prevmode; + int norm; /* thread */ struct task_struct *thread; struct semaphore *notify; wait_queue_head_t wq; struct timer_list wt; int done; + int watch_stereo; }; +#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ /* i2c addresses */ @@ -139,7 +142,7 @@ I2C_TDA9840 >> 1, I2C_TDA985x_L >> 1, I2C_TDA985x_H >> 1, - I2C_TDA9874A >> 1, + I2C_TDA9874 >> 1, I2C_PIC16C54 >> 1, I2C_CLIENT_END }; static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; @@ -296,9 +299,9 @@ dprintk("%s: thread wakeup\n", chip->c.name); if (chip->done || signal_pending(current)) break; - - if (0 != chip->mode) - /* don't do anything if mode != auto */ + + /* don't do anything for radio or if mode != auto */ + if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0) continue; /* have a look what's going on */ @@ -316,7 +319,7 @@ return 0; } -void generic_checkmode(struct CHIPSTATE *chip) +static void generic_checkmode(struct CHIPSTATE *chip) { struct CHIPDESC *desc = chiplist + chip->type; int mode = desc->getmode(chip); @@ -327,12 +330,12 @@ dprintk("%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; - if (mode & VIDEO_SOUND_LANG1) + if (mode & VIDEO_SOUND_STEREO) + desc->setmode(chip,VIDEO_SOUND_STEREO); + else if (mode & VIDEO_SOUND_LANG1) desc->setmode(chip,VIDEO_SOUND_LANG1); else if (mode & VIDEO_SOUND_LANG2) desc->setmode(chip,VIDEO_SOUND_LANG2); - else if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); else desc->setmode(chip,VIDEO_SOUND_MONO); } @@ -360,7 +363,7 @@ #define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */ #define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */ -int tda9840_getmode(struct CHIPSTATE *chip) +static int tda9840_getmode(struct CHIPSTATE *chip) { int val, mode; @@ -376,7 +379,7 @@ return mode; } -void tda9840_setmode(struct CHIPSTATE *chip, int mode) +static void tda9840_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; @@ -502,11 +505,11 @@ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ #define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ -int tda9855_volume(int val) { return val/0x2e8+0x27; } -int tda9855_bass(int val) { return val/0xccc+0x06; } -int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } +static int tda9855_volume(int val) { return val/0x2e8+0x27; } +static int tda9855_bass(int val) { return val/0xccc+0x06; } +static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } -int tda985x_getmode(struct CHIPSTATE *chip) +static int tda985x_getmode(struct CHIPSTATE *chip) { int mode; @@ -517,7 +520,7 @@ return mode | VIDEO_SOUND_MONO; } -void tda985x_setmode(struct CHIPSTATE *chip, int mode) +static void tda985x_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; @@ -657,7 +660,7 @@ #define TDA9873_STEREO 2 /* Stereo sound is identified */ #define TDA9873_DUAL 4 /* Dual sound is identified */ -int tda9873_getmode(struct CHIPSTATE *chip) +static int tda9873_getmode(struct CHIPSTATE *chip) { int val,mode; @@ -672,7 +675,7 @@ return mode; } -void tda9873_setmode(struct CHIPSTATE *chip, int mode) +static void tda9873_setmode(struct CHIPSTATE *chip, int mode) { int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK; /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ @@ -708,7 +711,7 @@ mode, sw_data); } -int tda9873_checkit(struct CHIPSTATE *chip) +static int tda9873_checkit(struct CHIPSTATE *chip) { int rc; @@ -719,10 +722,10 @@ /* ---------------------------------------------------------------------- */ -/* audio chip description - defines+functions for tda9874a */ +/* audio chip description - defines+functions for tda9874h and tda9874a */ /* Dariusz Kowalewski */ -/* Subaddresses for TDA9874A (slave rx) */ +/* Subaddresses for TDA9874H and TDA9874A (slave rx) */ #define TDA9874A_AGCGR 0x00 /* AGC gain */ #define TDA9874A_GCONR 0x01 /* general config */ #define TDA9874A_MSR 0x02 /* monitor select */ @@ -747,10 +750,10 @@ #define TDA9874A_DAICONR 0x15 /* digital audio interface config */ #define TDA9874A_I2SOSR 0x16 /* I2S-bus output select */ #define TDA9874A_I2SOLAR 0x17 /* I2S-bus output level adj. */ -#define TDA9874A_MDACOSR 0x18 /* mono DAC output select */ -#define TDA9874A_ESP 0xFF /* easy standard progr. */ +#define TDA9874A_MDACOSR 0x18 /* mono DAC output select (tda9874a) */ +#define TDA9874A_ESP 0xFF /* easy standard progr. (tda9874a) */ -/* Subaddresses for TDA9874A (slave tx) */ +/* Subaddresses for TDA9874H and TDA9874A (slave tx) */ #define TDA9874A_DSR 0x00 /* device status */ #define TDA9874A_NSR 0x01 /* NICAM status */ #define TDA9874A_NECR 0x02 /* NICAM error count */ @@ -767,37 +770,91 @@ static int tda9874a_mode = 1; /* 0: A2, 1: NICAM */ static int tda9874a_GCONR = 0xc0; /* default config. input pin: SIFSEL=0 */ +static int tda9874a_NCONR = 0x01; /* default NICAM config.: AMSEL=0,AMUTE=1 */ static int tda9874a_ESP = 0x07; /* default standard: NICAM D/K */ +static int tda9874a_dic = -1; /* device id. code */ /* insmod options for tda9874a */ static int tda9874a_SIF = -1; +static int tda9874a_AMSEL = -1; static int tda9874a_STD = -1; MODULE_PARM(tda9874a_SIF,"i"); +MODULE_PARM(tda9874a_AMSEL,"i"); MODULE_PARM(tda9874a_STD,"i"); +/* + * initialization table for tda9874 decoder: + * - carrier 1 freq. registers (3 bytes) + * - carrier 2 freq. registers (3 bytes) + * - demudulator config register + * - FM de-emphasis register (slow identification mode) + * Note: frequency registers must be written in single i2c transfer. + */ +static struct tda9874a_MODES { + char *name; + audiocmd cmd; +} tda9874a_modelist[9] = { + { "A2, B/G", + { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} }, + { "A2, M (Korea)", + { 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} }, + { "A2, D/K (1)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x82,0x60,0x00, 0x00,0x00 }} }, + { "A2, D/K (2)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x8C,0x75,0x55, 0x00,0x00 }} }, + { "A2, D/K (3)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x77,0xA0,0x00, 0x00,0x00 }} }, + { "NICAM, I", + { 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} }, + { "NICAM, B/G", + { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} }, + { "NICAM, D/K", /* default */ + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} }, + { "NICAM, L", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} } +}; static int tda9874a_setup(struct CHIPSTATE *chip) { chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */ chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR); chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02); - chip_write(chip, TDA9874A_FMMR, 0x80); + if(tda9874a_dic == 0x11) { + chip_write(chip, TDA9874A_FMMR, 0x80); + } else { /* dic == 0x07 */ + chip_cmd(chip,"tda9874_modelist",&tda9874a_modelist[tda9874a_STD].cmd); + chip_write(chip, TDA9874A_FMMR, 0x00); + } chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */ chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_NCONR, 0x00); /* not 0x04 as doc. table 10 says! */ + chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_AMCONR, 0xf9); - chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); /* 0x81 */ - chip_write(chip, TDA9874A_AOSR, 0x80); - chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80); - chip_write(chip, TDA9874A_ESP, tda9874a_ESP); - + /* Note: If signal quality is poor you may want to change NICAM */ + /* error limit registers (NLELR and NUELR) to some greater values. */ + /* Then the sound would remain stereo, but won't be so clear. */ + chip_write(chip, TDA9874A_NLELR, 0x14); /* default */ + chip_write(chip, TDA9874A_NUELR, 0x50); /* default */ + + if(tda9874a_dic == 0x11) { + chip_write(chip, TDA9874A_AMCONR, 0xf9); + chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); + chip_write(chip, TDA9874A_AOSR, 0x80); + chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80); + chip_write(chip, TDA9874A_ESP, tda9874a_ESP); + } else { /* dic == 0x07 */ + chip_write(chip, TDA9874A_AMCONR, 0xfb); + chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); + chip_write(chip, TDA9874A_AOSR, 0x00); // or 0x10 + } + dprintk("tda9874a_setup(): %s [0x%02X].\n", + tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } -int tda9874a_getmode(struct CHIPSTATE *chip) +static int tda9874a_getmode(struct CHIPSTATE *chip) { int dsr,nsr,mode; + int necr; /* just for debugging */ mode = VIDEO_SOUND_MONO; @@ -805,55 +862,125 @@ return mode; if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR))) return mode; + if(-1 == (necr = chip_read2(chip,TDA9874A_NECR))) + return mode; + + /* need to store dsr/nsr somewhere */ + chip->shadow.bytes[MAXREGS-2] = dsr; + chip->shadow.bytes[MAXREGS-1] = nsr; if(tda9874a_mode) { - /* check also DSR.RSSF and DSR.AMSTAT bits? */ - if(nsr & 0x02) /* NSR.S/MB */ + /* Note: DSR.RSSF and DSR.AMSTAT bits are also checked. + * If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates + * that sound has (temporarily) switched from NICAM to + * mono FM (or AM) on 1st sound carrier due to high NICAM bit + * error count. So in fact there is no stereo in this case :-( + * But changing the mode to VIDEO_SOUND_MONO would switch + * external 4052 multiplexer in audio_hook(). + */ +#if 0 + if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */ mode |= VIDEO_SOUND_STEREO; - if(nsr & 0x01) /* NSR.D/SB */ +#else + if(nsr & 0x02) /* NSR.S/MB=1 */ + mode |= VIDEO_SOUND_STEREO; +#endif + if(nsr & 0x01) /* NSR.D/SB=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } else { - if(dsr & 0x02) /* DSR.IDSTE */ + if(dsr & 0x02) /* DSR.IDSTE=1 */ mode |= VIDEO_SOUND_STEREO; - if(dsr & 0x04) /* DSR.IDDUA */ + if(dsr & 0x04) /* DSR.IDDUA=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, return: %d.\n", - dsr, nsr, mode); + dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + dsr, nsr, necr, mode); return mode; } -void tda9874a_setmode(struct CHIPSTATE *chip, int mode) +static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) { - int aosr=0x80,mdacosr=0x82; - - /* note: TDA9874A has auto-select function for audio output */ - switch(mode) { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_STEREO: - break; - case VIDEO_SOUND_LANG1: - aosr = 0x80; /* dual A/A */ - mdacosr = (tda9874a_mode) ? 0x82:0x80; - break; - case VIDEO_SOUND_LANG2: - aosr = 0xa0; /* dual B/B */ - mdacosr = (tda9874a_mode) ? 0x83:0x81; - break; - default: - chip->mode = 0; - return; + /* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */ + /* If auto-muting is disabled, we can hear a signal of degrading quality. */ + if(tda9874a_mode) { + if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */ + tda9874a_NCONR &= 0xfe; /* enable */ + else + tda9874a_NCONR |= 0x01; /* disable */ + chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); } - chip_write(chip, TDA9874A_AOSR, aosr); - chip_write(chip, TDA9874A_MDACOSR, mdacosr); + /* Note: TDA9874A supports automatic FM dematrixing (FMMR register) + * and has auto-select function for audio output (AOSR register). + * Old TDA9874H doesn't support these features. + * TDA9874A also has additional mono output pin (OUTM), which + * on same (all?) tv-cards is not used, anyway (as well as MONOIN). + */ + if(tda9874a_dic == 0x11) { + int aosr = 0x80; + int mdacosr = (tda9874a_mode) ? 0x82:0x80; + + switch(mode) { + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_STEREO: + break; + case VIDEO_SOUND_LANG1: + aosr = 0x80; /* auto-select, dual A/A */ + mdacosr = (tda9874a_mode) ? 0x82:0x80; + break; + case VIDEO_SOUND_LANG2: + aosr = 0xa0; /* auto-select, dual B/B */ + mdacosr = (tda9874a_mode) ? 0x83:0x81; + break; + default: + chip->mode = 0; + return; + } + chip_write(chip, TDA9874A_AOSR, aosr); + chip_write(chip, TDA9874A_MDACOSR, mdacosr); + + dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + mode, aosr, mdacosr); - dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", - mode, aosr, mdacosr); + } else { /* dic == 0x07 */ + int fmmr,aosr; + + switch(mode) { + case VIDEO_SOUND_MONO: + fmmr = 0x00; /* mono */ + aosr = 0x10; /* A/A */ + break; + case VIDEO_SOUND_STEREO: + if(tda9874a_mode) { + fmmr = 0x00; + aosr = 0x00; /* handled by NICAM auto-mute */ + } else { + fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */ + aosr = 0x00; + } + break; + case VIDEO_SOUND_LANG1: + fmmr = 0x02; /* dual */ + aosr = 0x10; /* dual A/A */ + break; + case VIDEO_SOUND_LANG2: + fmmr = 0x02; /* dual */ + aosr = 0x20; /* dual B/B */ + break; + default: + chip->mode = 0; + return; + } + chip_write(chip, TDA9874A_FMMR, fmmr); + chip_write(chip, TDA9874A_AOSR, aosr); + + dprintk("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + mode, fmmr, aosr); + } } -int tda9874a_checkit(struct CHIPSTATE *chip) +static int tda9874a_checkit(struct CHIPSTATE *chip) { int dic,sic; /* device id. and software id. codes */ @@ -864,10 +991,15 @@ dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); - return((dic & 0xff) == 0x11); + if((dic == 0x11)||(dic == 0x07)) { + dprintk("tvaudio: found tda9874%s.\n",(dic == 0x11) ? "a (new)":"h (old)"); + tda9874a_dic = dic; /* remember device id. */ + return 1; + } + return 0; /* not found */ } -int tda9874a_initialize(struct CHIPSTATE *chip) +static int tda9874a_initialize(struct CHIPSTATE *chip) { if(tda9874a_SIF != -1) { if(tda9874a_SIF == 1) @@ -887,6 +1019,15 @@ } } + if(tda9874a_AMSEL != -1) { + if(tda9874a_AMSEL == 0) + tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */ + else if(tda9874a_AMSEL == 1) + tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */ + else + printk(KERN_WARNING "tda9874a: AMSEL parameter must be 0 or 1.\n"); + } + tda9874a_setup(chip); return 0; @@ -915,8 +1056,8 @@ #define TEA6420_S_SE 0x04 /* stereo E */ #define TEA6420_S_GMU 0x05 /* general mute */ -int tea6300_shift10(int val) { return val >> 10; } -int tea6300_shift12(int val) { return val >> 12; } +static int tea6300_shift10(int val) { return val >> 10; } +static int tea6300_shift12(int val) { return val >> 12; } /* ---------------------------------------------------------------------- */ @@ -931,8 +1072,8 @@ #define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ #define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ -int tda8425_shift10(int val) { return val >> 10 | 0xc0; } -int tda8425_shift12(int val) { return val >> 12 | 0xf0; } +static int tda8425_shift10(int val) { return val >> 10 | 0xc0; } +static int tda8425_shift12(int val) { return val >> 12 | 0xf0; } /* ---------------------------------------------------------------------- */ @@ -1015,13 +1156,13 @@ }, { - name: "tda9874a", - id: I2C_DRIVERID_TDA9874A, + name: "tda9874h/a", + id: I2C_DRIVERID_TDA9874, checkit: tda9874a_checkit, initialize: tda9874a_initialize, insmodopt: &tda9874a, - addr_lo: I2C_TDA9874A >> 1, - addr_hi: I2C_TDA9874A >> 1, + addr_lo: I2C_TDA9874 >> 1, + addr_hi: I2C_TDA9874 >> 1, getmode: tda9874a_getmode, setmode: tda9874a_setmode, @@ -1160,7 +1301,7 @@ chip->c.data = chip; /* find description for the chip */ - dprintk("tvaudio: chip @ addr=0x%x\n", addr<<1); + dprintk("tvaudio: chip found @ i2c-addr=0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -1175,7 +1316,8 @@ dprintk("tvaudio: no matching chip description found\n"); return -EIO; } - dprintk("tvaudio: %s matches:%s%s%s\n",desc->name, + printk("tvaudio: found %s\n",desc->name); + dprintk("tvaudio: matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); @@ -1272,6 +1414,14 @@ chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask); } break; + + case AUDC_SET_RADIO: + dprintk(KERN_DEBUG "tvaudio: AUDC_SET_RADIO\n"); + chip->norm = VIDEO_MODE_RADIO; + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ + break; + /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -1290,10 +1440,12 @@ va->bass = chip->bass; va->treble = chip->treble; } - if (desc->getmode) - va->mode = desc->getmode(chip); - else - va->mode = VIDEO_SOUND_MONO; + if (chip->norm != VIDEO_MODE_RADIO) { + if (desc->getmode) + va->mode = desc->getmode(chip); + else + va->mode = VIDEO_SOUND_MONO; + } break; } @@ -1316,11 +1468,21 @@ chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); } if (desc->setmode && va->mode) { + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ chip->mode = va->mode; desc->setmode(chip,va->mode); } break; } + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + dprintk(KERN_DEBUG "tvaudio: VIDIOCSCHAN\n"); + chip->norm = vc->norm; + break; + } case VIDIOCSFREQ: { chip->mode = 0; /* automatic */ @@ -1339,7 +1501,7 @@ static struct i2c_driver driver = { name: "generic i2c audio driver", - id: I2C_DRIVERID_TVAUDIO, /* FIXME */ + id: I2C_DRIVERID_TVAUDIO, flags: I2C_DF_NOTIFY, attach_adapter: chip_probe, detach_client: chip_detach, @@ -1349,10 +1511,11 @@ static struct i2c_client client_template = { name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, driver: &driver, }; -int audiochip_init_module(void) +static int audiochip_init_module(void) { struct CHIPDESC *desc; printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); @@ -1364,7 +1527,7 @@ return 0; } -void audiochip_cleanup_module(void) +static void audiochip_cleanup_module(void) { i2c_del_driver(&driver); } diff -urN linux-2.4.18/drivers/media/video/tvaudio.h linux-2.4.19-pre5/drivers/media/video/tvaudio.h --- linux-2.4.18/drivers/media/video/tvaudio.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tvaudio.h Sat Mar 30 22:55:28 2002 @@ -6,7 +6,7 @@ #define I2C_TDA9840 0x84 #define I2C_TDA985x_L 0xb4 /* also used by 9873 */ #define I2C_TDA985x_H 0xb6 -#define I2C_TDA9874A 0xb0 /* also used by 9875 */ +#define I2C_TDA9874 0xb0 /* also used by 9875 */ #define I2C_TEA6300 0x80 #define I2C_TEA6420 0x98 diff -urN linux-2.4.18/drivers/media/video/tvmixer.c linux-2.4.19-pre5/drivers/media/video/tvmixer.c --- linux-2.4.18/drivers/media/video/tvmixer.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/tvmixer.c Sat Mar 30 22:55:28 2002 @@ -8,8 +8,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -177,7 +178,7 @@ static int tvmixer_open(struct inode *inode, struct file *file) { - int i, minor = MINOR(inode->i_rdev); + int i, minor = minor(inode->i_rdev); struct TVMIXER *mix = NULL; struct i2c_client *client = NULL; @@ -320,7 +321,7 @@ /* ----------------------------------------------------------------------- */ -int tvmixer_init_module(void) +static int tvmixer_init_module(void) { int i; @@ -330,7 +331,7 @@ return 0; } -void tvmixer_cleanup_module(void) +static void tvmixer_cleanup_module(void) { int i; diff -urN linux-2.4.18/drivers/media/video/videodev.c linux-2.4.19-pre5/drivers/media/video/videodev.c --- linux-2.4.18/drivers/media/video/videodev.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/videodev.c Sat Mar 30 22:55:34 2002 @@ -25,15 +25,14 @@ #include #include #include -#include #include - +#include +#include #include #include #include -#include - +#include #define VIDEO_NUM_DEVICES 256 @@ -42,6 +41,7 @@ */ static struct video_device *video_device[VIDEO_NUM_DEVICES]; +static DECLARE_MUTEX(videodev_lock); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) @@ -70,7 +70,7 @@ static ssize_t video_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl = video_devdata(file); if(vfl->read) return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); else @@ -86,13 +86,18 @@ static ssize_t video_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl = video_devdata(file); if(vfl->write) return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); else return 0; } +struct video_device* video_devdata(struct file *file) +{ + return video_device[minor(file->f_dentry->d_inode->i_rdev)]; +} + /* * Poll to see if we're readable, can probably be used for timing on incoming * frames, etc.. @@ -100,7 +105,7 @@ static unsigned int video_poll(struct file *file, poll_table * wait) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl = video_devdata(file); if(vfl->poll) return vfl->poll(vfl, file, wait); else @@ -114,52 +119,66 @@ static int video_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - int err, retval = 0; + unsigned int minor = minor(inode->i_rdev); + int err = 0; struct video_device *vfl; if(minor>=VIDEO_NUM_DEVICES) return -ENODEV; - lock_kernel(); + down(&videodev_lock); vfl=video_device[minor]; if(vfl==NULL) { char modname[20]; + up(&videodev_lock); sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor); request_module(modname); + down(&videodev_lock); vfl=video_device[minor]; if (vfl==NULL) { - retval = -ENODEV; - goto error_out; + err = -ENODEV; + goto unlock_out; } } - if(vfl->busy) { - retval = -EBUSY; - goto error_out; + if (vfl->fops) { + int err = 0; + struct file_operations *old_fops; + + old_fops = file->f_op; + file->f_op = fops_get(vfl->fops); + if(file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + goto unlock_out; + } + if(vfl->users) { + err = -EBUSY; + goto unlock_out; } - vfl->busy=1; /* In case vfl->open sleeps */ + vfl->users++; /* In case vfl->open sleeps */ if(vfl->owner) __MOD_INC_USE_COUNT(vfl->owner); - if(vfl->open) - { + if (vfl->open) { err=vfl->open(vfl,0); /* Tell the device it is open */ - if(err) - { - vfl->busy=0; + if (err) { + vfl->users--; if(vfl->owner) __MOD_DEC_USE_COUNT(vfl->owner); - - unlock_kernel(); - return err; + goto unlock_out; } } - unlock_kernel(); + up(&videodev_lock); return 0; -error_out: - unlock_kernel(); - return retval; + +unlock_out: + up(&videodev_lock); + return err; } /* @@ -169,21 +188,22 @@ static int video_release(struct inode *inode, struct file *file) { struct video_device *vfl; - lock_kernel(); - vfl=video_device[MINOR(inode->i_rdev)]; + + down(&videodev_lock); + vfl = video_devdata(file); if(vfl->close) vfl->close(vfl); - vfl->busy=0; + vfl->users--; if(vfl->owner) __MOD_DEC_USE_COUNT(vfl->owner); - unlock_kernel(); + up(&videodev_lock); return 0; } static int video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + struct video_device *vfl = video_devdata(file); int err=vfl->ioctl(vfl, cmd, (void *)arg); if(err!=-ENOIOCTLCMD) @@ -203,7 +223,7 @@ int video_mmap(struct file *file, struct vm_area_struct *vma) { int ret = -EINVAL; - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl = video_devdata(file); if(vfl->mmap) { lock_kernel(); ret = vfl->mmap(vfl, (char *)vma->vm_start, @@ -214,6 +234,95 @@ } /* + * ioctl helper function -- handles userspace copying + */ +int +video_generic_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vfl = video_devdata(file); + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + if (vfl->kernel_ioctl == NULL) + return -EINVAL; + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = (void *)arg; + break; + case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* call driver */ + err = vfl->kernel_ioctl(inode, file, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + if (mbuf) + kfree(mbuf); + return err; +} + +/* + * open/release helper functions -- handle exclusive opens + */ +extern int video_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *vfl = video_devdata(file); + int retval = 0; + + down(&vfl->lock); + if (vfl->users) { + retval = -EBUSY; + } else { + vfl->users++; + } + up(&vfl->lock); + return retval; +} + +extern int video_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *vfl = video_devdata(file); + + vfl->users--; + return 0; +} + +/* * /proc support */ @@ -392,8 +501,6 @@ * %VFL_TYPE_RADIO - A radio card */ -static DECLARE_MUTEX(videodev_register_lock); - int video_register_device(struct video_device *vfd, int type, int nr) { int i=0; @@ -430,27 +537,27 @@ } /* pick a minor number */ - down(&videodev_register_lock); + down(&videodev_lock); if (-1 == nr) { /* use first free */ for(i=base;iminor=i; - up(&videodev_register_lock); + up(&videodev_lock); /* The init call may sleep so we book the slot out then call */ @@ -474,6 +581,7 @@ S_IFCHR | S_IRUSR | S_IWUSR, &video_fops, NULL); + init_MUTEX(&vfd->lock); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) sprintf (name, "%s%d", name_base, i - base); @@ -492,8 +600,10 @@ void video_unregister_device(struct video_device *vfd) { + down(&videodev_lock); + if(video_device[vfd->minor]!=vfd) - panic("vfd: bad unregister"); + panic("videodev: bad unregister"); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) videodev_proc_destroy_dev (vfd); @@ -502,6 +612,7 @@ devfs_unregister (vfd->devfs_handle); video_device[vfd->minor]=NULL; MOD_DEC_USE_COUNT; + up(&videodev_lock); } @@ -540,12 +651,9 @@ static void __exit videodev_exit(void) { -#ifdef MODULE #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) videodev_proc_destroy (); #endif -#endif - devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture"); } @@ -554,6 +662,10 @@ EXPORT_SYMBOL(video_register_device); EXPORT_SYMBOL(video_unregister_device); +EXPORT_SYMBOL(video_devdata); +EXPORT_SYMBOL(video_generic_ioctl); +EXPORT_SYMBOL(video_exclusive_open); +EXPORT_SYMBOL(video_exclusive_release); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); diff -urN linux-2.4.18/drivers/media/video/vino.c linux-2.4.19-pre5/drivers/media/video/vino.c --- linux-2.4.18/drivers/media/video/vino.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/media/video/vino.c Sat Mar 30 22:55:28 2002 @@ -1,6 +1,4 @@ -/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ - * drivers/char/vino.c - * +/* * (incomplete) Driver for the Vino Video input system found in SGI Indys. * * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) @@ -57,9 +55,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (virt_addr), - "r" (&ret) - :"$1"); + :"r" (virt_addr), "r" (&ret)); restore_flags(flags); return ret; @@ -83,9 +79,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (&value), - "r" (virt_addr) - :"$1"); + :"r" (&value), "r" (virt_addr)); restore_flags(flags); } @@ -93,45 +87,41 @@ unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; - save_and_cli(flags); + __save_and_cli(flags); __asm__ __volatile__( - ".set\tmips3\n\t" + ".set\tmips3\t\t\t# vino_reg_and\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "and\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "and\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); - restore_flags(flags); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); + __restore_flags(flags); } static __inline__ void vino_reg_or(unsigned long long value, unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; save_and_cli(flags); __asm__ __volatile__( ".set\tmips3\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "or\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "or\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); restore_flags(flags); } diff -urN linux-2.4.18/drivers/media/video/w9966.c linux-2.4.19-pre5/drivers/media/video/w9966.c --- linux-2.4.18/drivers/media/video/w9966.c Sun Dec 23 16:23:43 2001 +++ linux-2.4.19-pre5/drivers/media/video/w9966.c Sat Mar 30 22:55:34 2002 @@ -19,18 +19,25 @@ */ /* Supported devices: - * Lifeview FlyCam Supra (using the Philips saa7111a chip) + * Lifeview Flycam Supra (Philips saa7111a chip) + + * Mikrotek Eyestar2 (Sanyo lc99053 chip) + Very rudimentary support, total lack of ccd-control chip settings. + Only green video data and no image properties (brightness, etc..) + If anyone can parse the Japanese data-sheet for the Sanyo lc99053 + chip, feel free to help. + + Thanks to Steven Griffiths and + James Murray for testing. Todo: - * Add a working EPP mode - * Support other ccd-control chips than the saa7111 - (what combinations exists?) + * Add a working EPP mode (Is this a parport or a w9966 issue?) * Add proper probing. IEEE1284 probing of w9966 chips haven't worked since parport drivers changed in 2.4.x. - * Probe for onboard SRAM, port directions etc. (if possible) + * Probe for onboard SRAM, port directions etc. (possible?) Changes: - + Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE and owner support for newer module locks */ @@ -43,112 +50,155 @@ #include #include -//#define DEBUG // Undef me for production +//#define DEBUG // Uncomment for debug output. #ifdef DEBUG -#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a) +# define DPRINTF(f, a...) \ + do { \ + printk ("%s%s, %d (DEBUG) %s(): ", \ + KERN_DEBUG, __FILE__, __LINE__, __func__); \ + printk (f, ##a); \ + } while (0) +# define DASSERT(x) \ + do { \ + if (!x) \ + DPRINTF("Assertion failed at line %d.\n", __LINE__);\ + } while (0) #else -#define DPRINTF(x...) +# define DPRINTF(...) do {} while(0) +# define DASSERT(...) do {} while(0) #endif /* * Defines, simple typedefs etc. */ -#define W9966_DRIVERNAME "W9966CF Webcam" +#define W9966_DRIVERNAME "w9966cf" #define W9966_MAXCAMS 4 // Maximum number of cameras -#define W9966_RBUFFER 2048 // Read buffer (must be an even number) -#define W9966_SRAMSIZE 131072 // 128kb -#define W9966_SRAMID 0x02 // check w9966cf.pdf - -// Empirically determined window limits -#define W9966_WND_MIN_X 16 -#define W9966_WND_MIN_Y 14 -#define W9966_WND_MAX_X 705 -#define W9966_WND_MAX_Y 253 -#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) -#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) +#define W9966_RBUFFER 8096 // Read buffer (must be an even number) + +#define W9966_WND_MIN_W 2 +#define W9966_WND_MIN_H 1 // Keep track of our current state -#define W9966_STATE_PDEV 0x01 -#define W9966_STATE_CLAIMED 0x02 -#define W9966_STATE_VDEV 0x04 +#define W9966_STATE_PDEV 0x01 // pdev registered +#define W9966_STATE_CLAIMED 0x02 // pdev claimed +#define W9966_STATE_VDEV 0x04 // vdev registered +#define W9966_STATE_BUFFER 0x08 // buffer allocated +#define W9966_STATE_DETECTED 0x10 // model identified + +#define W9966_SAA7111_ID 0x24 // I2C device id -#define W9966_I2C_W_ID 0x48 -#define W9966_I2C_R_ID 0x49 +#define W9966_I2C_UDELAY 5 +#define W9966_I2C_TIMEOUT 100 #define W9966_I2C_R_DATA 0x08 #define W9966_I2C_R_CLOCK 0x04 #define W9966_I2C_W_DATA 0x02 #define W9966_I2C_W_CLOCK 0x01 +#define MAX(a, b) ((a > b) ? a : b) +#define MIN(a, b) ((a > b) ? b : a) + struct w9966_dev { - u8 dev_state; - u8 i2c_state; - int ppmode; - struct parport* pport; - struct pardevice* pdev; struct video_device vdev; + struct parport* pport; + struct pardevice* pdev; + int ppmode; + + u8* buffer; + u8 dev_state; + u8 i2c_state; u16 width; u16 height; + + // Image properties u8 brightness; s8 contrast; s8 color; s8 hue; - u8* buffer; + + // Model specific: + const char* name; + u32 sramsize; + u8 sramid; // reg 0x0c, bank layout + u8 cmask; // reg 0x01, for polarity + u16 min_x, max_x; // Capture window limits + u16 min_y, max_y; + int (*image)(struct w9966_dev* cam); }; /* - * Module specific properties + * Module properties */ MODULE_AUTHOR("Jakob Kemi "); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)"); +MODULE_DESCRIPTION("Winbond w9966cf webcam driver (Flycam Supra and others)"); MODULE_LICENSE("GPL"); -static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"}; +static const char* pardev[] = {[0 ... W9966_MAXCAMS-1] = "auto"}; MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s"); MODULE_PARM_DESC(pardev,"\n\ Where to find cameras.\n\ - auto = probe all parports for camera\n\ + auto = probe all parports for camera (default)\n\ name = name of parport (eg parport0)\n\ - none = don't search for this camera\n\ -You can specify all cameras this way, for example: + none = don't use this camera\n\ +You can specify all cameras this way, for example:\n\ pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\ for cam2 on all parports, skip cam3 and search for cam4 on parport0"); -static int parmode = 0; +static int parmode = 1; MODULE_PARM(parmode, "i"); -MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)"); +MODULE_PARM_DESC(parmode, "\n<0|1|2|3> transfer mode (0=auto, 1=ecp(default), 2=epp, 3=forced hw-ecp)"); -static int video_nr = -1; -MODULE_PARM(video_nr, "i"); +static int video_nr[] = {[0 ... W9966_MAXCAMS-1] = -1}; +MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9966_MAXCAMS) "i"); +MODULE_PARM_DESC(video_nr,"\n\ +<-1|n[,...]> Specify V4L minor mode number.\n\ + -1 = use next available (default)\n\ + n = use minor number n (integer >= 0)\n\ +You can specify all cameras this way, for example:\n\ + video_nr=-1,2,-1 would assign minor number 2 for cam2 and use auto for cam1,\n\ + cam3 and cam4"); /* * Private data */ -static struct w9966_dev w9966_cams[W9966_MAXCAMS]; +static struct w9966_dev* w9966_cams; /* - * Private function declares + * Private function declarations */ -static inline void w9966_setState(struct w9966_dev* cam, int mask, int val); -static inline int w9966_getState(struct w9966_dev* cam, int mask, int val); -static inline void w9966_pdev_claim(struct w9966_dev *vdev); +static inline void w9966_flag_set(struct w9966_dev* cam, int flag) { + cam->dev_state |= flag;} + +static inline void w9966_flag_clear(struct w9966_dev* cam, int flag) { + cam->dev_state &= ~flag;} + +static inline int w9966_flag_test(struct w9966_dev* cam, int flag) { + return (cam->dev_state & flag);} + +static inline int w9966_pdev_claim(struct w9966_dev *vdev); static inline void w9966_pdev_release(struct w9966_dev *vdev); -static int w9966_rReg(struct w9966_dev* cam, int reg); -static int w9966_wReg(struct w9966_dev* cam, int reg, int data); -static int w9966_rReg_i2c(struct w9966_dev* cam, int reg); -static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data); -static int w9966_findlen(int near, int size, int maxlen); -static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor); -static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h); +static int w9966_rreg(struct w9966_dev* cam, int reg); +static int w9966_wreg(struct w9966_dev* cam, int reg, int data); -static int w9966_init(struct w9966_dev* cam, struct parport* port); +static int w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr); static void w9966_term(struct w9966_dev* cam); +static int w9966_setup(struct w9966_dev* cam); +static int w9966_findlen(int near, int size, int maxlen); +static int w9966_calcscale(int size, int min, int max, + int* beg, int* end, u8* factor); +static int w9966_window(struct w9966_dev* cam, int x1, int y1, + int x2, int y2, int w, int h); + +static int w9966_saa7111_init(struct w9966_dev* cam); +static int w9966_saa7111_image(struct w9966_dev* cam); +static int w9966_lc99053_init(struct w9966_dev* cam); +static int w9966_lc99053_image(struct w9966_dev* cam); static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state); static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state); @@ -156,116 +206,104 @@ static inline int w9966_i2c_getscl(struct w9966_dev* cam); static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); static int w9966_i2c_rbyte(struct w9966_dev* cam); +static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg); +static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data); static int w9966_v4l_open(struct video_device *vdev, int mode); static void w9966_v4l_close(struct video_device *vdev); -static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); -static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock); +static int w9966_v4l_ioctl(struct video_device *vdev, + unsigned int cmd, void *arg); +static long w9966_v4l_read(struct video_device *vdev, + char *buf, unsigned long count, int noblock); /* - * Private function defines + * Private function definitions */ - -// Set camera phase flags, so we know what to uninit when terminating -static inline void w9966_setState(struct w9966_dev* cam, int mask, int val) -{ - cam->dev_state = (cam->dev_state & ~mask) ^ val; -} - -// Get camera phase flags -static inline int w9966_getState(struct w9966_dev* cam, int mask, int val) -{ - return ((cam->dev_state & mask) == val); -} - // Claim parport for ourself -static inline void w9966_pdev_claim(struct w9966_dev* cam) +// 1 on success, else 0 +static inline int w9966_pdev_claim(struct w9966_dev* cam) { - if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) - return; - parport_claim_or_block(cam->pdev); - w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); + if (w9966_flag_test(cam, W9966_STATE_CLAIMED)) + return 1; + if (parport_claim_or_block(cam->pdev) < 0) + return 0; + w9966_flag_set(cam, W9966_STATE_CLAIMED); + return 1; } // Release parport for others to use static inline void w9966_pdev_release(struct w9966_dev* cam) { - if (w9966_getState(cam, W9966_STATE_CLAIMED, 0)) + if (!w9966_flag_test(cam, W9966_STATE_CLAIMED)) return; parport_release(cam->pdev); - w9966_setState(cam, W9966_STATE_CLAIMED, 0); + w9966_flag_clear(cam, W9966_STATE_CLAIMED); } - -// Read register from W9966 interface-chip + +// Read register from w9966 interface-chip // Expects a claimed pdev // -1 on error, else register data (byte) -static int w9966_rReg(struct w9966_dev* cam, int reg) +static int w9966_rreg(struct w9966_dev* cam, int reg) { // ECP, read, regtransfer, REG, REG, REG, REG, REG - const unsigned char addr = 0x80 | (reg & 0x1f); - unsigned char val; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_read(cam->pport, &val, 1) != 1) + const u8 addr = 0x80 | (reg & 0x1f); + u8 val; + + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 || + parport_write(cam->pport, &addr, 1) != 1 || + parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 || + parport_read(cam->pport, &val, 1) != 1) return -1; return val; } -// Write register to W9966 interface-chip +// Write register to w9966 interface-chip // Expects a claimed pdev -// -1 on error -static int w9966_wReg(struct w9966_dev* cam, int reg, int data) +// 1 on success, else 0 +static int w9966_wreg(struct w9966_dev* cam, int reg, int data) { // ECP, write, regtransfer, REG, REG, REG, REG, REG - const unsigned char addr = 0xc0 | (reg & 0x1f); - const unsigned char val = data; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_write(cam->pport, &val, 1) != 1) - return -1; + const u8 addr = 0xc0 | (reg & 0x1f); + const u8 val = data; - return 0; + if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 || + parport_write(cam->pport, &addr, 1) != 1 || + parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 || + parport_write(cam->pport, &val, 1) != 1) + return 0; + + return 1; } // Initialize camera device. Setup all internal flags, set a // default video mode, setup ccd-chip, register v4l device etc.. // Also used for 'probing' of hardware. -// -1 on error -static int w9966_init(struct w9966_dev* cam, struct parport* port) +// 1 on success, else 0 +static int w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr) { if (cam->dev_state != 0) - return -1; - + return 0; + cam->pport = port; cam->brightness = 128; cam->contrast = 64; cam->color = 64; cam->hue = 0; -// Select requested transfer mode + // Select requested transfer mode switch(parmode) { default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) case 0: if (port->modes & PARPORT_MODE_ECP) cam->ppmode = IEEE1284_MODE_ECP; -/* else if (port->modes & PARPORT_MODE_EPP) - cam->ppmode = IEEE1284_MODE_EPP;*/ + else if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP; else cam->ppmode = IEEE1284_MODE_ECPSWE; - break; + break; case 1: // hw- or sw-ecp if (port->modes & PARPORT_MODE_ECP) cam->ppmode = IEEE1284_MODE_ECP; @@ -278,27 +316,55 @@ else cam->ppmode = IEEE1284_MODE_EPPSWE; break; + case 3: // hw-ecp + cam->ppmode = IEEE1284_MODE_ECP; + break; } - -// Tell the parport driver that we exists - cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); + + // Tell the parport driver that we exists + cam->pdev = parport_register_device( + port, W9966_DRIVERNAME, NULL, NULL, NULL, 0, NULL); + if (cam->pdev == NULL) { - DPRINTF("parport_register_device() failed\n"); - return -1; + DPRINTF("parport_register_device() failed.\n"); + return 0; } - w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); + w9966_flag_set(cam, W9966_STATE_PDEV); - w9966_pdev_claim(cam); - -// Setup a default capture mode - if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { + // Claim parport + if (!w9966_pdev_claim(cam)) { + DPRINTF("w9966_pdev_claim() failed.\n"); + return 0; + } + + // Perform initial w9966 setup + if (!w9966_setup(cam)) { DPRINTF("w9966_setup() failed.\n"); - return -1; + return 0; } + // Detect model + if (!w9966_saa7111_init(cam)) { + DPRINTF("w9966_saa7111_init() failed.\n"); + return 0; + } + if (!w9966_lc99053_init(cam)) { + DPRINTF("w9966_lc99053_init() failed.\n"); + return 0; + } + if (!w9966_flag_test(cam, W9966_STATE_DETECTED)) { + DPRINTF("Camera model not identified.\n"); + return 0; + } + + // Setup w9966 with a default capture mode (QCIF res.) + if (!w9966_window(cam, 0, 0, 1023, 1023, 176, 144)) { + DPRINTF("w9966_window() failed.\n"); + return 0; + } w9966_pdev_release(cam); -// Fill in the video_device struct and register us to v4l + // Fill in the video_device struct and register us to v4l memset(&cam->vdev, 0, sizeof(struct video_device)); strcpy(cam->vdev.name, W9966_DRIVERNAME); cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; @@ -310,51 +376,73 @@ cam->vdev.priv = (void*)cam; cam->vdev.owner = THIS_MODULE; - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) - return -1; - - w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); - - cam->buffer = NULL; - + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, vidnr) == -1) { + DPRINTF("video_register_device() failed (minor: %d).\n", vidnr); + return 0; + } + w9966_flag_set(cam, W9966_STATE_VDEV); + // All ok - printk( - "w9966cf: Found and initialized a webcam on %s.\n", - cam->pport->name - ); - return 0; + printk("w9966: Found and initialized %s on %s.\n", + cam->name, cam->pport->name); + return 1; } - // Terminate everything gracefully static void w9966_term(struct w9966_dev* cam) { -// Delete allocated buffer if needed - if (cam->buffer != NULL) { + // Delete allocated buffer + if (w9966_flag_test(cam, W9966_STATE_BUFFER)) kfree(cam->buffer); - cam->buffer = NULL; - } -// Unregister from v4l - if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { + // Unregister from v4l + if (w9966_flag_test(cam, W9966_STATE_VDEV)) video_unregister_device(&cam->vdev); - w9966_setState(cam, W9966_STATE_VDEV, 0); - } -// Terminate from IEEE1284 mode and release pdev block - if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { - w9966_pdev_claim(cam); - parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); - w9966_pdev_release(cam); - } + // Terminate from IEEE1284 mode and unregister from parport + if (w9966_flag_test(cam, W9966_STATE_PDEV)) { + if (w9966_pdev_claim(cam)) + parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); -// Unregister from parport - if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { + w9966_pdev_release(cam); parport_unregister_device(cam->pdev); - w9966_setState(cam, W9966_STATE_PDEV, 0); } + + cam->dev_state = 0x00; } +// Do initial setup for the w9966 chip, init i2c bus, etc. +// this is generic for all models +// expects a claimed pdev +// 1 on success, else 0 +static int w9966_setup(struct w9966_dev* cam) +{ + const u8 i2c = cam->i2c_state = W9966_I2C_W_DATA | W9966_I2C_W_CLOCK; + const u8 regs[] = { + 0x40, // 0x13 - VEE control (raw 4:2:2) + 0x00, 0x00, 0x00, // 0x14 - 0x16 + 0x00, // 0x17 - ??? + i2c, // 0x18 - Serial bus + 0xff, // 0x19 - I/O port direction control + 0xff, // 0x1a - I/O port data register + 0x10 // 0x1b - ??? + }; + int i; + + DASSERT(w9966_flag_test(cam, W9966_STATE_CLAIMED)); + + // Reset (ECP-fifo & serial-bus) + if (!w9966_wreg(cam, 0x00, 0x03) || + !w9966_wreg(cam, 0x00, 0x00)) + return 0; + + // Write regs to w9966cf chip + for (i = 0x13; i < 0x1c; i++) + if (!w9966_wreg(cam, i, regs[i-0x13])) + return 0; + + return 1; +} // Find a good length for capture window (used both for W and H) // A bit ugly but pretty functional. The capture length @@ -365,7 +453,7 @@ int besterr = abs(near - bestlen); int len; - for(len = size+1;len < maxlen;len++) + for(len = size+1; len < maxlen; len++) { int err; if ( ((64*size) %len) != 0) @@ -376,7 +464,7 @@ // Only continue as long as we keep getting better values if (err > besterr) break; - + besterr = err; bestlen = len; } @@ -384,19 +472,19 @@ return bestlen; } -// Modify capture window (if necessary) +// Modify capture window (if necessary) // and calculate downscaling -// Return -1 on error -static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor) +// 1 on success, else 0 +static int w9966_calcscale(int size, int min, int max, int* beg, int* end, u8* factor) { - int maxlen = max - min; - int len = *end - *beg + 1; - int newlen = w9966_findlen(len, size, maxlen); - int err = newlen - len; + const int maxlen = max - min; + const int len = *end - *beg + 1; + const int newlen = w9966_findlen(len, size, maxlen); + const int err = newlen - len; // Check for bad format if (newlen > maxlen || newlen < size) - return -1; + return 0; // Set factor (6 bit fixed) *factor = (64*size) / newlen; @@ -419,62 +507,49 @@ *end -= *end - max; } - return 0; + return 1; } -// Setup the cameras capture window etc. -// Expects a claimed pdev -// return -1 on error -static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) +// Setup the w9966 capture window and also set SRAM settings +// expects a claimed pdev and detected camera model +// 1 on success, else 0 +static int w9966_window(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) { - unsigned int i; unsigned int enh_s, enh_e; u8 scale_x, scale_y; - u8 regs[0x1c]; - u8 saa7111_regs[] = { - 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, - 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, - 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 - }; - - - if (w*h*2 > W9966_SRAMSIZE) - { - DPRINTF("capture window exceeds SRAM size!.\n"); - w = 200; h = 160; // Pick default values - } + u8 regs[0x13]; + int i; + // Modify width and height to match capture window and SRAM + w = MAX(W9966_WND_MIN_W, w); + h = MAX(W9966_WND_MIN_H, h); + w = MIN(cam->max_x - cam->min_x, w); + h = MIN(cam->max_y - cam->min_y, h); w &= ~0x1; - if (w < 2) w = 2; - if (h < 1) h = 1; - if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W; - if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H; + if (w*h*2 > cam->sramsize) + h = cam->sramsize / (w*2); cam->width = w; cam->height = h; - enh_s = 0; + enh_s = 0; enh_e = w*h*2; - -// Modify capture window if necessary and calculate downscaling - if ( - w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || - w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0 - ) return -1; - - DPRINTF( - "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", - w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80 - ); - -// Setup registers + + // Calculate downscaling + if (!w9966_calcscale(w, cam->min_x, cam->max_x, &x1, &x2, &scale_x) || + !w9966_calcscale(h, cam->min_y, cam->max_y, &y1, &y2, &scale_y)) + return 0; + + DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", + w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80); + + // Setup registers regs[0x00] = 0x00; // Set normal operation - regs[0x01] = 0x18; // Capture mode + regs[0x01] = cam->cmask; // Capture mode regs[0x02] = scale_y; // V-scaling regs[0x03] = scale_x; // H-scaling - - // Capture window + + // Capture window regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits) regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits) regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits) @@ -483,8 +558,8 @@ regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits) regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits) - regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb) - + regs[0x0c] = cam->sramid; // SRAM layout + // Enhancement layer regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7) regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15) @@ -493,35 +568,110 @@ regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15) regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??) - // Misc - regs[0x13] = 0x40; // VEE control (raw 4:2:2) - regs[0x17] = 0x00; // ??? - regs[0x18] = cam->i2c_state = 0x00; // Serial bus - regs[0x19] = 0xff; // I/O port direction control - regs[0x1a] = 0xff; // I/O port data register - regs[0x1b] = 0x10; // ??? - - // SAA7111 chip settings - saa7111_regs[0x0a] = cam->brightness; - saa7111_regs[0x0b] = cam->contrast; - saa7111_regs[0x0c] = cam->color; - saa7111_regs[0x0d] = cam->hue; + // Write regs to w9966cf chip + for (i = 0x01; i < 0x13; i++) + if (!w9966_wreg(cam, i, regs[i])) + return 0; + + return 1; +} + +// Detect and initialize saa7111 ccd-controller chip. +// expects a claimed parport +// expected to always return 1 unless error is _fatal_ +// 1 on success, else 0 +static int w9966_saa7111_init(struct w9966_dev* cam) +{ + // saa7111 regs 0x00 trough 0x12 + const u8 regs[] = { + 0x00, // not written + 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10, + cam->brightness, // 0x0a + cam->contrast, // 0x0b + cam->color, // 0x0c + cam->hue, // 0x0d + 0x01, 0x00, 0x48, 0x0c, 0x00, + }; + int i; -// Reset (ECP-fifo & serial-bus) - if (w9966_wReg(cam, 0x00, 0x03) == -1) - return -1; + if (w9966_flag_test(cam, W9966_STATE_DETECTED)) + return 1; -// Write regs to w9966cf chip - for (i = 0; i < 0x1c; i++) - if (w9966_wReg(cam, i, regs[i]) == -1) - return -1; + // Write regs to saa7111 chip + for (i = 1; i < 0x13; i++) + if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, i, regs[i])) + return 1; + + // Read back regs + for (i = 1; i < 0x13; i++) + if (w9966_i2c_rreg(cam, W9966_SAA7111_ID, i) != regs[i]) + return 1; + + // Fill in model specific data + cam->name = "Lifeview Flycam Supra"; + cam->sramsize = 128 << 10; // 128 kib + cam->sramid = 0x02; // see w9966.pdf + + cam->cmask = 0x18; // normal polarity + cam->min_x = 16; // empirically determined + cam->max_x = 705; + cam->min_y = 14; + cam->max_y = 253; + cam->image = &w9966_saa7111_image; + + DPRINTF("Found and initialized a saa7111 chip.\n"); + w9966_flag_set(cam, W9966_STATE_DETECTED); + + return 1; +} + +// Setup image properties (brightness, hue, etc.) for the saa7111 chip +// expects a claimed parport +// 1 on success, else 0 +static int w9966_saa7111_image(struct w9966_dev* cam) +{ + if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0a, cam->brightness) || + !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0b, cam->contrast) || + !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0c, cam->color) || + !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0d, cam->hue)) + return 0; -// Write regs to saa7111 chip - for (i = 0; i < 0x20; i++) - if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1) - return -1; + return 1; +} - return 0; +// Detect and initialize lc99053 ccd-controller chip. +// expects a claimed parport +// this is currently a hack, no detection is done, we just assume an Eyestar2 +// 1 on success, else 0 +static int w9966_lc99053_init(struct w9966_dev* cam) +{ + if (w9966_flag_test(cam, W9966_STATE_DETECTED)) + return 1; + + // Fill in model specific data + cam->name = "Microtek Eyestar2"; + cam->sramsize = 128 << 10; // 128 kib + cam->sramid = 0x02; // w9966cf.pdf + + cam->cmask = 0x10; // reverse polarity + cam->min_x = 16; // empirically determined + cam->max_x = 705; + cam->min_y = 14; + cam->max_y = 253; + cam->image = &w9966_lc99053_image; + + DPRINTF("Found and initialized a lc99053 chip.\n"); + w9966_flag_set(cam, W9966_STATE_DETECTED); + + return 1; +} + +// Setup image properties (brightness, hue, etc.) for the lc99053 chip +// expects a claimed parport +// 1 on success, else 0 +static int w9966_lc99053_image(struct w9966_dev* cam) +{ + return 1; } /* @@ -536,91 +686,90 @@ cam->i2c_state |= W9966_I2C_W_DATA; else cam->i2c_state &= ~W9966_I2C_W_DATA; - - w9966_wReg(cam, 0x18, cam->i2c_state); - udelay(5); + + w9966_wreg(cam, 0x18, cam->i2c_state); + udelay(W9966_I2C_UDELAY); } // Sets the clock line on the i2c bus. -// Expects a claimed pdev. -1 on error +// Expects a claimed pdev. +// 1 on success, else 0 static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state) { - int timeout; if (state) cam->i2c_state |= W9966_I2C_W_CLOCK; else cam->i2c_state &= ~W9966_I2C_W_CLOCK; - w9966_wReg(cam, 0x18, cam->i2c_state); - udelay(5); - - // we go to high, we also expect the peripheral to ack. + w9966_wreg(cam, 0x18, cam->i2c_state); + udelay(W9966_I2C_UDELAY); + + // when we go to high, we also expect the peripheral to ack. if (state) { - timeout = jiffies + 100; + const int timeout = jiffies + W9966_I2C_TIMEOUT; while (!w9966_i2c_getscl(cam)) { - if (jiffies > timeout) - return -1; + if (time_after(jiffies, timeout)) + return 0; } } - return 0; + return 1; } // Get peripheral data line // Expects a claimed pdev. static inline int w9966_i2c_getsda(struct w9966_dev* cam) { - const unsigned char state = w9966_rReg(cam, 0x18); - return ((state & W9966_I2C_R_DATA) > 0); + const u8 pins = w9966_rreg(cam, 0x18); + return ((pins & W9966_I2C_R_DATA) > 0); } // Get peripheral clock line // Expects a claimed pdev. static inline int w9966_i2c_getscl(struct w9966_dev* cam) { - const unsigned char state = w9966_rReg(cam, 0x18); - return ((state & W9966_I2C_R_CLOCK) > 0); + const u8 pins = w9966_rreg(cam, 0x18); + return ((pins & W9966_I2C_R_CLOCK) > 0); } // Write a byte with ack to the i2c bus. -// Expects a claimed pdev. -1 on error +// Expects a claimed pdev. +// 1 on success, else 0 static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) { int i; - for (i = 7; i >= 0; i--) - { + for (i = 7; i >= 0; i--) { w9966_i2c_setsda(cam, (data >> i) & 0x01); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); + if (!w9966_i2c_setscl(cam, 1) || + !w9966_i2c_setscl(cam, 0)) + return 0; } - w9966_i2c_setsda(cam, 1); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); - - return 0; + + if (!w9966_i2c_setscl(cam, 1) || + !w9966_i2c_setscl(cam, 0)) + return 0; + + return 1; } // Read a data byte with ack from the i2c-bus // Expects a claimed pdev. -1 on error static int w9966_i2c_rbyte(struct w9966_dev* cam) { - unsigned char data = 0x00; - int i; - + u8 data = 0x00; + int i; + w9966_i2c_setsda(cam, 1); for (i = 0; i < 8; i++) { - if (w9966_i2c_setscl(cam, 1) == -1) + if (!w9966_i2c_setscl(cam, 1)) return -1; data = data << 1; if (w9966_i2c_getsda(cam)) data |= 0x01; - + w9966_i2c_setscl(cam, 0); } return data; @@ -628,75 +777,81 @@ // Read a register from the i2c device. // Expects claimed pdev. -1 on error -static int w9966_rReg_i2c(struct w9966_dev* cam, int reg) +static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg) { int data; w9966_i2c_setsda(cam, 0); w9966_i2c_setscl(cam, 0); - if ( - w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1 - ) + if (!w9966_i2c_wbyte(cam, device << 1) || + !w9966_i2c_wbyte(cam, reg)) return -1; w9966_i2c_setsda(cam, 1); - if (w9966_i2c_setscl(cam, 1) == -1) + if (!w9966_i2c_setscl(cam, 1)) return -1; + w9966_i2c_setsda(cam, 0); w9966_i2c_setscl(cam, 0); - if ( - w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 || - (data = w9966_i2c_rbyte(cam)) == -1 - ) + if (!w9966_i2c_wbyte(cam, (device << 1) | 1) || + (data = w9966_i2c_rbyte(cam)) == -1) return -1; w9966_i2c_setsda(cam, 0); - - if (w9966_i2c_setscl(cam, 1) == -1) + + if (!w9966_i2c_setscl(cam, 1)) return -1; + w9966_i2c_setsda(cam, 1); - + return data; } - // Write a register to the i2c device. -// Expects claimed pdev. -1 on error -static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) +// Expects claimed pdev. +// 1 on success, else 0 +static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data) { w9966_i2c_setsda(cam, 0); w9966_i2c_setscl(cam, 0); - if ( - w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1 || - w9966_i2c_wbyte(cam, data) == -1 - ) - return -1; + if (!w9966_i2c_wbyte(cam, device << 1) || + !w9966_i2c_wbyte(cam, reg) || + !w9966_i2c_wbyte(cam, data)) + return 0; w9966_i2c_setsda(cam, 0); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - + if (!w9966_i2c_setscl(cam, 1)) + return 0; + w9966_i2c_setsda(cam, 1); - return 0; + return 1; } /* - * Video4linux interfacing + * Video4linux interface */ static int w9966_v4l_open(struct video_device *vdev, int flags) { struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; - cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL); - - if (cam->buffer == NULL) + + // Claim parport + if (!w9966_pdev_claim(cam)) { + DPRINTF("Unable to claim parport"); return -EFAULT; + } + + // Allocate read buffer + cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL); + if (cam->buffer == NULL) { + w9966_pdev_release(cam); + return -ENOMEM; + } + w9966_flag_set(cam, W9966_STATE_BUFFER); return 0; } @@ -704,17 +859,22 @@ static void w9966_v4l_close(struct video_device *vdev) { struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; - - if (cam->buffer != NULL) { + + // Free read buffer + if (w9966_flag_test(cam, W9966_STATE_BUFFER)) { kfree(cam->buffer); - cam->buffer = NULL; + w9966_flag_clear(cam, W9966_STATE_BUFFER); } + + // release parport + w9966_pdev_release(cam); } +// expects a claimed parport static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; - + switch(cmd) { case VIDIOCGCAP: @@ -723,9 +883,10 @@ W9966_DRIVERNAME, // name VID_TYPE_CAPTURE | VID_TYPE_SCALES, // type 1, 0, // vid, aud channels - W9966_WND_MAX_W, // max w - W9966_WND_MAX_H, // max h - 2, 1 // min w, min h + cam->max_x - cam->min_x, + cam->max_y - cam->min_y, + W9966_WND_MIN_W, + W9966_WND_MIN_H }; if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0) @@ -747,10 +908,10 @@ vch.tuners = 0; vch.type = VIDEO_TYPE_CAMERA; vch.norm = 0; // ??? - + if(copy_to_user(arg, &vch, sizeof(vch)) != 0) return -EFAULT; - + return 0; } case VIDIOCSCHAN: @@ -758,10 +919,10 @@ struct video_channel vch; if(copy_from_user(&vch, arg, sizeof(vch) ) != 0) return -EFAULT; - + if(vch.channel != 0) return -EINVAL; - + return 0; } case VIDIOCGTUNER: @@ -769,20 +930,20 @@ struct video_tuner vtune; if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0) return -EFAULT; - + if(vtune.tuner != 0); return -EINVAL; - + strcpy(vtune.name, "no tuner"); vtune.rangelow = 0; vtune.rangehigh = 0; vtune.flags = VIDEO_TUNER_NORM; vtune.mode = VIDEO_MODE_AUTO; vtune.signal = 0xffff; - + if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0) return -EFAULT; - + return 0; } case VIDIOCSTUNER: @@ -790,13 +951,13 @@ struct video_tuner vtune; if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0) return -EFAULT; - + if (vtune.tuner != 0) return -EINVAL; - + if (vtune.mode != VIDEO_MODE_AUTO) return -EINVAL; - + return 0; } case VIDIOCGPICT: @@ -820,73 +981,58 @@ struct video_picture vpic; if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0) return -EFAULT; - + if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422) return -EINVAL; - + cam->brightness = vpic.brightness >> 8; cam->hue = (vpic.hue >> 8) - 128; cam->color = vpic.colour >> 9; cam->contrast = vpic.contrast >> 9; - w9966_pdev_claim(cam); - - if ( - w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 || - w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 || - w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 || - w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1 - ) { - w9966_pdev_release(cam); + if (!cam->image(cam)) return -EFAULT; - } - - w9966_pdev_release(cam); + return 0; } case VIDIOCSWIN: { - int ret; struct video_window vwin; - + if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0) - return -EFAULT; - if (vwin.flags != 0) - return -EINVAL; - if (vwin.clipcount != 0) + return -EFAULT; + if ( + vwin.flags != 0 || + vwin.clipcount != 0) return -EINVAL; - if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W) - return -EINVAL; - if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H) + + if (vwin.width > cam->max_x - cam->min_x || + vwin.height > cam->max_y - cam->min_y || + vwin.width < W9966_WND_MIN_W || + vwin.height < W9966_WND_MIN_H) return -EINVAL; // Update camera regs - w9966_pdev_claim(cam); - ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height); - w9966_pdev_release(cam); - - if (ret != 0) { - DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); + if (!w9966_window(cam, 0, 0, 1023, 1023, vwin.width, vwin.height)) return -EFAULT; - } - + return 0; } case VIDIOCGWIN: { struct video_window vwin; memset(&vwin, 0, sizeof(vwin)); - + vwin.width = cam->width; vwin.height = cam->height; - + if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0) return -EFAULT; - + return 0; } // Unimplemented - case VIDIOCCAPTURE: + case VIDIOCCAPTURE: case VIDIOCGFBUF: case VIDIOCSFBUF: case VIDIOCKEY: @@ -902,69 +1048,62 @@ } // Capture data +// expects a claimed parport and allocated read buffer static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock) { struct w9966_dev *cam = (struct w9966_dev *)vdev->priv; - unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 - unsigned char* dest = (unsigned char*)buf; + const u8 addr = 0xa0; // ECP, read, CCD-transfer, 00000 + u8* dest = (u8*)buf; unsigned long dleft = count; - + // Why would anyone want more than this?? if (count > cam->width * cam->height * 2) return -EINVAL; - - w9966_pdev_claim(cam); - w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer - w9966_wReg(cam, 0x00, 0x00); // Return to normal operation - w9966_wReg(cam, 0x01, 0x98); // Enable capture - - // write special capture-addr and negotiate into data transfer - if ( - (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )|| - (parport_write(cam->pport, &addr, 1) != 1 )|| - (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 ) - ) { - w9966_pdev_release(cam); + + w9966_wreg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer + w9966_wreg(cam, 0x00, 0x00); // Return to normal operation + w9966_wreg(cam, 0x01, cam->cmask | 0x80); // Enable capture + + // write special capture-addr and negotiate into data transfer + if (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 || + parport_write(cam->pport, &addr, 1) != 1 || + parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0) { + DPRINTF("Unable to write capture-addr.\n"); return -EFAULT; } - + while(dleft > 0) { - unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; - - if (parport_read(cam->pport, cam->buffer, tsize) < tsize) { - w9966_pdev_release(cam); + const size_t tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; + + if (parport_read(cam->pport, cam->buffer, tsize) < tsize) return -EFAULT; - } - if (copy_to_user(dest, cam->buffer, tsize) != 0) { - w9966_pdev_release(cam); + + if (copy_to_user(dest, cam->buffer, tsize) != 0) return -EFAULT; - } + dest += tsize; dleft -= tsize; } - - w9966_wReg(cam, 0x01, 0x18); // Disable capture - w9966_pdev_release(cam); + + w9966_wreg(cam, 0x01, cam->cmask); // Disable capture return count; } - // Called once for every parport on init static void w9966_attach(struct parport *port) { int i; - - for (i = 0; i < W9966_MAXCAMS; i++) - { - if (strcmp(pardev[i], "none") == 0) // Skip if 'none' - continue; - if (w9966_cams[i].dev_state != 0) // Cam is already assigned + + for (i = 0; i < W9966_MAXCAMS; i++) { + if (strcmp(pardev[i], "none") == 0 || // Skip if 'none' or if + w9966_cams[i].dev_state != 0) // cam already assigned continue; + if (strcmp(pardev[i], "auto") == 0 || strcmp(pardev[i], port->name) == 0) { - if (w9966_init(&w9966_cams[i], port) != 0) + if (!w9966_init(&w9966_cams[i], port, video_nr[i])) w9966_term(&w9966_cams[i]); break; // return } @@ -991,16 +1130,33 @@ // Module entry point static int __init w9966_mod_init(void) { - int i; + int i, err; + + w9966_cams = kmalloc( + sizeof(struct w9966_dev) * W9966_MAXCAMS, GFP_KERNEL); + + if (!w9966_cams) + return -ENOMEM; + for (i = 0; i < W9966_MAXCAMS; i++) w9966_cams[i].dev_state = 0; - return parport_register_driver(&w9966_ppd); + // Register parport driver + if ((err = parport_register_driver(&w9966_ppd)) != 0) { + kfree(w9966_cams); + w9966_cams = 0; + return err; + } + + return 0; } // Module cleanup static void __exit w9966_mod_term(void) { + if (w9966_cams) + kfree(w9966_cams); + parport_unregister_driver(&w9966_ppd); } diff -urN linux-2.4.18/drivers/media/video/zr36067.c linux-2.4.19-pre5/drivers/media/video/zr36067.c --- linux-2.4.18/drivers/media/video/zr36067.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/media/video/zr36067.c Sat Mar 30 22:55:39 2002 @@ -3265,7 +3265,10 @@ btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - dev->busy = 0; /* Allow second open */ + /* FIXME: Don't do it this way, use the + * video_device->fops registration for a sane + * implementation of multiple opens */ + dev->users--; /* Allow second open */ } break; @@ -3323,6 +3326,7 @@ } } + dev->users++; zr->user--; MOD_DEC_USE_COUNT; @@ -4205,9 +4209,7 @@ /* sleep 1 second */ - timeout = jiffies + 1 * HZ; - while (jiffies < timeout) - schedule(); + schedule_timeout(HZ); /* Get status of video decoder */ @@ -4397,22 +4399,18 @@ } static struct video_device zoran_template = { - THIS_MODULE, - ZORAN_NAME, - VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - ZORAN_HARDWARE, - zoran_open, - zoran_close, - zoran_read, - zoran_write, - NULL, - zoran_ioctl, - zoran_mmap, - zoran_init_done, - NULL, - 0, - 0 + owner: THIS_MODULE, + name: ZORAN_NAME, + type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + hardware: ZORAN_HARDWARE, + open: zoran_open, + close: zoran_close, + read: zoran_read, + write: zoran_write, + ioctl: zoran_ioctl, + mmap: zoran_mmap, + initialize: zoran_init_done, }; /* diff -urN linux-2.4.18/drivers/message/fusion/Config.in linux-2.4.19-pre5/drivers/message/fusion/Config.in --- linux-2.4.18/drivers/message/fusion/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/Config.in Sat Mar 30 22:55:39 2002 @@ -7,10 +7,8 @@ if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then define_bool CONFIG_FUSION_BOOT y - comment "(ability to boot linux kernel from Fusion device is ENABLED!)" else define_bool CONFIG_FUSION_BOOT n - comment "(ability to boot linux kernel from Fusion device is DISABLED!)" fi if [ "$CONFIG_MODULES" = "y" ]; then diff -urN linux-2.4.18/drivers/message/fusion/Makefile linux-2.4.19-pre5/drivers/message/fusion/Makefile --- linux-2.4.18/drivers/message/fusion/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/Makefile Sat Mar 30 22:55:39 2002 @@ -27,6 +27,7 @@ #EXTRA_CFLAGS += -DDEBUG #EXTRA_CFLAGS += -DMPT_DEBUG #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME +#EXTRA_CFLAGS += -DMPT_DEBUG_SG # # driver/module specifics... # @@ -34,11 +35,13 @@ #CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ # -# For {mptscsih, mptctl}: +# For mptscsih: #CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH #CFLAGS_mptscsih.o += -DMPT_DEBUG_SCANDV -#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG -#CFLAGS_mptctl.o += -DMPT_DEBUG_SG +#CFLAGS_mptscsih.o += -DMPT_DEBUG_RESET +# +# For mptctl: +#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL # # For mptlan: #CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG diff -urN linux-2.4.18/drivers/message/fusion/isense.c linux-2.4.19-pre5/drivers/message/fusion/isense.c --- linux-2.4.18/drivers/message/fusion/isense.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/isense.c Sat Mar 30 22:55:39 2002 @@ -5,12 +5,13 @@ * Error Report logging output. This module implements SCSI-3 * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. * - * Copyright (c) 1991-2001 Steven J. Ralston + * Copyright (c) 1991-2002 Steven J. Ralston * Written By: Steven J. Ralston * (yes I wrote some of the orig. code back in 1991!) - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: isense.c,v 1.28.14.1 2001/08/24 20:07:04 sralston Exp $ + * $Id: isense.c,v 1.33 2002/02/27 18:44:19 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -49,11 +50,15 @@ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#include +#include #include +#include #include #include -#include +#include +#if defined (__sparc__) +#include +#endif /* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) @@ -61,7 +66,7 @@ #endif #define MODULEAUTHOR "Steven J. Ralston" -#define COPYRIGHT "Copyright (c) 2001 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 2001-2002 " MODULEAUTHOR #include "mptbase.h" #include "isense.h" @@ -87,7 +92,6 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); -MODULE_LICENSE("GPL"); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ int __init isense_init(void) diff -urN linux-2.4.18/drivers/message/fusion/linux_compat.h linux-2.4.19-pre5/drivers/message/fusion/linux_compat.h --- linux-2.4.18/drivers/message/fusion/linux_compat.h Sun Feb 17 11:40:27 2002 +++ linux-2.4.19-pre5/drivers/message/fusion/linux_compat.h Sat Mar 30 22:55:39 2002 @@ -11,6 +11,10 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#ifndef rwlock_init +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) # if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) typedef unsigned int dma_addr_t; @@ -58,12 +62,33 @@ extern inline __cleanup_module_func_t __cleanup_module_inline(void) \ { return x; } -#else +#else #define module_init(x) __initcall(x); #define module_exit(x) __exitcall(x); #endif /* } block snipped from lk-2.2.18/include/linux/init.h */ +/* This block snipped from lk-2.2.18/include/linux/sched.h { */ +/* + * Used prior to schedule_timeout calls.. + */ +#define __set_current_state(state_value) do { current->state = state_value; } while (0) +#ifdef __SMP__ +#define set_current_state(state_value) do { __set_current_state(state_value); mb(); } while (0) +#else +#define set_current_state(state_value) __set_current_state(state_value) +#endif +/* } block snipped from lk-2.2.18/include/linux/sched.h */ + +/* procfs compat stuff... */ +#define proc_mkdir(x,y) create_proc_entry(x, S_IFDIR, y) + +/* MUTEX compat stuff... */ +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED + /* Wait queues. */ #define DECLARE_WAIT_QUEUE_HEAD(name) \ struct wait_queue * (name) = NULL @@ -90,6 +115,17 @@ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */ +/* + * Inclined to use: + * #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) + * here, but MODULE_LICENSE defined in 2.4.9-6 and 2.4.9-13 + * breaks the rule:-( + */ +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + + /* PCI/driver subsystem { */ #ifndef pci_for_each_dev #define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next) @@ -120,26 +156,6 @@ #endif /* } ifndef pci_for_each_dev */ -/* procfs compat stuff... */ -#ifdef CONFIG_PROC_FS -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) -#define CREATE_PROCDIR_ENTRY(x,y) create_proc_entry(x, S_IFDIR, y) -/* This is a macro so we don't need to pull all the procfs - * headers into this file. -DaveM - */ -#define create_proc_read_entry(name, mode, base, __read_proc, __data) \ -({ struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \ - if (__res) { \ - __res->read_proc=(__read_proc); \ - __res->data=(__data); \ - } \ - __res; \ -}) -#else -#define CREATE_PROCDIR_ENTRY(x,y) proc_mkdir(x, y) -#endif -#endif - /* Compatability for the 2.3.x PCI DMA API. */ #ifndef PCI_DMA_BIDIRECTIONAL /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -193,6 +209,7 @@ /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* PCI_DMA_BIDIRECTIONAL */ + /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ diff -urN linux-2.4.18/drivers/message/fusion/lsi/fc_log.h linux-2.4.19-pre5/drivers/message/fusion/lsi/fc_log.h --- linux-2.4.18/drivers/message/fusion/lsi/fc_log.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/fc_log.h Sat Mar 30 22:55:39 2002 @@ -7,7 +7,7 @@ * in the IOCLogInfo field of a MPI Default Reply Message. * * CREATION DATE: 6/02/2000 - * ID: $Id: fc_log.h,v 4.5 2001/06/07 19:18:00 sschremm Exp $ + * ID: $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $ */ @@ -62,7 +62,7 @@ MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ - MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound after a logout */ + MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound queue after a logout */ MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI Version: 01.01.07 + * MPI Version: 01.02.03 * * Version History * --------------- @@ -39,6 +39,11 @@ * Added function codes for RAID. * 04-09-01 01.01.07 Added alternate define for MPI_DOORBELL_ACTIVE, * MPI_DOORBELL_USED, to better match the spec. + * 08-08-01 01.02.01 Original release for v1.2 work. + * Changed MPI_VERSION_MINOR from 0x01 to 0x02. + * Added define MPI_FUNCTION_TOOLBOX. + * 09-28-01 01.02.02 New function code MPI_SCSI_ENCLOSURE_PROCESSOR. + * 11-01-01 01.02.03 Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR. * -------------------------------------------------------------------------- */ @@ -53,7 +58,7 @@ *****************************************************************************/ #define MPI_VERSION_MAJOR (0x01) -#define MPI_VERSION_MINOR (0x01) +#define MPI_VERSION_MINOR (0x02) #define MPI_VERSION ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR) /* Note: The major versions of 0xe0 through 0xff are reserved */ @@ -216,8 +221,12 @@ #define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND (0x13) #define MPI_FUNCTION_FC_PRIMITIVE_SEND (0x14) -#define MPI_FUNCTION_RAID_VOLUME (0x15) +#define MPI_FUNCTION_RAID_ACTION (0x15) #define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) + +#define MPI_FUNCTION_TOOLBOX (0x17) + +#define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_cnfg.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_cnfg.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_cnfg.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI Version: 01.01.11 + * MPI Version: 01.02.05 * * Version History * --------------- @@ -72,6 +72,42 @@ * Added IO Unit Page 3. * Modified defines for Scsi Port Page 2. * Modified RAID Volume Pages. + * 08-08-01 01.02.01 Original release for v1.2 work. + * Added SepID and SepBus to RVP2 IMPhysicalDisk struct. + * Added defines for the SEP bits in RVP2 VolumeSettings. + * Modified the DeviceSettings field in RVP2 to use the + * proper structure. + * Added defines for SES, SAF-TE, and cross channel for + * IOCPage2 CapabilitiesFlags. + * Removed define for MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE. + * Removed define for + * MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE. + * Added define for MPI_CONFIG_PAGEATTR_RO_PERSISTENT. + * 08-29-01 01.02.02 Fixed value for MPI_MANUFACTPAGE_DEVID_53C1035. + * Added defines for MPI_FCPORTPAGE1_FLAGS_HARD_ALPA_ONLY + * and MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY. + * Removed MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS, + * MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS, and + * MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS, and + * MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED. + * Added defines for MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED + * and MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED. + * Added OnBusTimerValue to CONFIG_PAGE_SCSI_PORT_1. + * Added rejected bits to SCSI Device Page 0 Information. + * Increased size of ALPA array in FC Port Page 2 by one + * and removed a one byte reserved field. + * 09-28-01 01.02.03 Swapped NegWireSpeedLow and NegWireSpeedLow in + * CONFIG_PAGE_LAN_1 to match preferred 64-bit ordering. + * Added structures for Manufacturing Page 4, IO Unit + * Page 3, IOC Page 3, IOC Page 4, RAID Volume Page 0, and + * RAID PhysDisk Page 0. + * 10-04-01 01.02.04 Added define for MPI_CONFIG_PAGETYPE_RAID_PHYSDISK. + * Modified some of the new defines to make them 32 + * character unique. + * Modified how variable length pages (arrays) are defined. + * Added generic defines for hot spare pools and RAID + * volume types. + * 11-01-01 01.02.05 Added define for MPI_IOUNITPAGE1_DISABLE_IR. * -------------------------------------------------------------------------- */ @@ -104,12 +140,13 @@ fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; -/****************************************************************************/ -/* PageType field values */ -/****************************************************************************/ +/**************************************************************************** +* PageType field values +****************************************************************************/ #define MPI_CONFIG_PAGEATTR_READ_ONLY (0x00) #define MPI_CONFIG_PAGEATTR_CHANGEABLE (0x10) #define MPI_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI_CONFIG_PAGEATTR_RO_PERSISTENT (0x30) #define MPI_CONFIG_PAGEATTR_MASK (0xF0) #define MPI_CONFIG_PAGETYPE_IO_UNIT (0x00) @@ -122,29 +159,21 @@ #define MPI_CONFIG_PAGETYPE_LAN (0x07) #define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) #define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) #define MPI_CONFIG_PAGETYPE_MASK (0x0F) #define MPI_CONFIG_TYPENUM_MASK (0x0FFF) /**************************************************************************** - * PageAddres field values - ****************************************************************************/ +* PageAddress field values +****************************************************************************/ #define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) -#define MPI_SCSI_DEVICE_FORM_MASK (0xF0000000) -#define MPI_SCSI_DEVICE_FORM_TARGETID (0x00000000) -#define MPI_SCSI_DEVICE_FORM_RAID_PHYS_DEV_NUM (0x10000000) #define MPI_SCSI_DEVICE_TARGET_ID_MASK (0x000000FF) #define MPI_SCSI_DEVICE_TARGET_ID_SHIFT (0) #define MPI_SCSI_DEVICE_BUS_MASK (0x0000FF00) #define MPI_SCSI_DEVICE_BUS_SHIFT (8) -#define MPI_SCSI_DEVICE_VOLUME_TARG_ID_MASK (0x000000FF) -#define MPI_SCSI_DEVICE_VOLUME_TARG_ID_SHIFT (0) -#define MPI_SCSI_DEVICE_VOLUME_BUS_MASK (0x0000FF00) -#define MPI_SCSI_DEVICE_VOLUME_BUS_SHIFT (8) -#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_MASK (0x00FF0000) -#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_SHIFT (16) #define MPI_FC_PORT_PGAD_PORT_MASK (0xF0000000) #define MPI_FC_PORT_PGAD_PORT_SHIFT (28) @@ -167,10 +196,14 @@ #define MPI_FC_DEVICE_PGAD_BT_TID_MASK (0x000000FF) #define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT (0) +#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) +#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT (0) + -/****************************************************************************/ -/* Config Request Message */ -/****************************************************************************/ + +/**************************************************************************** +* Config Request Message +****************************************************************************/ typedef struct _MSG_CONFIG { U8 Action; /* 00h */ @@ -181,16 +214,16 @@ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[8]; /* 0Ch */ - fCONFIG_PAGE_HEADER Header; /* 14h */ + fCONFIG_PAGE_HEADER Header; /* 14h */ U32 PageAddress; /* 18h */ SGE_IO_UNION PageBufferSGE; /* 1Ch */ } MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG, Config_t, MPI_POINTER pConfig_t; -/****************************************************************************/ -/* Action field values */ -/****************************************************************************/ +/**************************************************************************** +* Action field values +****************************************************************************/ #define MPI_CONFIG_ACTION_PAGE_HEADER (0x00) #define MPI_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) #define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) @@ -213,7 +246,7 @@ U8 Reserved2[2]; /* 0Ch */ U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ - fCONFIG_PAGE_HEADER Header; /* 14h */ + fCONFIG_PAGE_HEADER Header; /* 14h */ } MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY, ConfigReply_t, MPI_POINTER pConfigReply_t; @@ -225,19 +258,24 @@ * *****************************************************************************/ -/****************************************************************************/ -/* Manufacturing Config pages */ -/****************************************************************************/ +/**************************************************************************** +* Manufacturing Config pages +****************************************************************************/ #define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) #define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) #define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) +#define MPI_MANUFACTPAGE_DEVICEID_FC919X (0x0628) +#define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) -#define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0035) +#define MPI_MANUFACTPAGE_DEVID_1030_53C1035 (0x0032) +#define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035 (0x0033) +#define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0040) +#define MPI_MANUFACTPAGE_DEVID_53C1035ZC (0x0041) typedef struct _CONFIG_PAGE_MANUFACTURING_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U8 ChipName[16]; /* 04h */ U8 ChipRevision[8]; /* 14h */ U8 BoardName[16]; /* 1Ch */ @@ -252,7 +290,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U8 VPD[256]; /* 04h */ } fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1, ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t; @@ -269,35 +307,72 @@ MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t; +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_MAN_PAGE_2_HW_SETTINGS_WORDS +#define MPI_MAN_PAGE_2_HW_SETTINGS_WORDS (1) +#endif + typedef struct _CONFIG_PAGE_MANUFACTURING_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - MPI_CHIP_REVISION_ID ChipId; /* 04h */ - U32 HwSettings[1]; /* 08h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + MPI_CHIP_REVISION_ID ChipId; /* 04h */ + U32 HwSettings[MPI_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 08h */ } fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2, ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t; #define MPI_MANUFACTURING2_PAGEVERSION (0x00) +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_MAN_PAGE_3_INFO_WORDS +#define MPI_MAN_PAGE_3_INFO_WORDS (1) +#endif + typedef struct _CONFIG_PAGE_MANUFACTURING_3 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - MPI_CHIP_REVISION_ID ChipId; /* 04h */ - U32 Info[1]; /* 08h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + MPI_CHIP_REVISION_ID ChipId; /* 04h */ + U32 Info[MPI_MAN_PAGE_3_INFO_WORDS];/* 08h */ } fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3, ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t; #define MPI_MANUFACTURING3_PAGEVERSION (0x00) -/****************************************************************************/ -/* IO Unit Config Pages */ -/****************************************************************************/ +typedef struct _CONFIG_PAGE_MANUFACTURING_4 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 04h */ + U8 InfoOffset0; /* 08h */ + U8 InfoSize0; /* 09h */ + U8 InfoOffset1; /* 0Ah */ + U8 InfoSize1; /* 0Bh */ + U8 InquirySize; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + U8 InquiryData[56]; /* 10h */ + U32 ISVolumeSettings; /* 48h */ + U32 IMEVolumeSettings; /* 4Ch */ + U32 IMVolumeSettings; /* 50h */ +} fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, + ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; + +#define MPI_MANUFACTURING4_PAGEVERSION (0x00) + + +/**************************************************************************** +* IO Unit Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_IO_UNIT_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U64 UniqueValue; /* 04h */ } fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0, IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t; @@ -307,18 +382,20 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Flags; /* 04h */ } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; #define MPI_IOUNITPAGE1_PAGEVERSION (0x00) +/* IO Unit Page 1 Flags defines */ + #define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) #define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) #define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) #define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) - +#define MPI_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) @@ -335,7 +412,7 @@ typedef struct _CONFIG_PAGE_IO_UNIT_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Flags; /* 04h */ U32 BiosVersion; /* 08h */ MPI_ADAPTER_INFO AdapterOrder[4]; /* 0Ch */ @@ -344,38 +421,45 @@ #define MPI_IOUNITPAGE2_PAGEVERSION (0x00) -#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE (0x00000001) #define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR (0x00000002) #define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE (0x00000004) #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX +#define MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) +#endif + typedef struct _CONFIG_PAGE_IO_UNIT_3 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - U32 VolumeSettings; /* 04h */ - U8 InfoOffset0; /* 08h */ - U8 InfoSize0; /* 09h */ - U8 InfoOffset1; /* 0Ah */ - U8 InfoSize1; /* 0Bh */ - U8 InquirySize; /* 0Ch */ - U8 Reserved; /* 0Dh */ - U16 Reserved2; /* 0Eh */ - U8 InquiryData[56]; /* 10h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U8 GPIOCount; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ + U16 GPIOVal[MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX]; /* 08h */ } fCONFIG_PAGE_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_3, IOUnitPage3_t, MPI_POINTER pIOUnitPage3_t; -#define MPI_IOUNITPAGE3_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE3_PAGEVERSION (0x01) + +#define MPI_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFC) +#define MPI_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) +#define MPI_IOUNITPAGE3_GPIO_SETTING_OFF (0x00) +#define MPI_IOUNITPAGE3_GPIO_SETTING_ON (0x01) -/****************************************************************************/ -/* IOC Config Pages */ -/****************************************************************************/ +/**************************************************************************** +* IOC Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_IOC_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 TotalNVStore; /* 04h */ U32 FreeNVStore; /* 08h */ U16 VendorID; /* 0Ch */ @@ -393,7 +477,7 @@ typedef struct _CONFIG_PAGE_IOC_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Flags; /* 04h */ U32 CoalescingTimeout; /* 08h */ U8 CoalescingDepth; /* 0Ch */ @@ -408,53 +492,120 @@ typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL { - U8 VolumeTargetID; /* 00h */ - U8 VolumeBus; /* 01h */ - U16 Reserved; /* 02h */ - U8 VolumeVersionMinor; /* 04h */ - U8 VolumeVersionMajor; /* 05h */ - U8 VolumeRaidType; /* 06h */ - U8 Reserved1; /* 07h */ + U8 VolumeID; /* 00h */ + U8 VolumeBus; /* 01h */ + U8 VolumeIOC; /* 02h */ + U8 VolumePageNumber; /* 03h */ + U8 VolumeType; /* 04h */ + U8 Reserved2; /* 05h */ + U16 Reserved3; /* 06h */ } fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL, ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t; +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_IOC_PAGE_2_RAID_VOLUME_MAX +#define MPI_IOC_PAGE_2_RAID_VOLUME_MAX (1) +#endif + typedef struct _CONFIG_PAGE_IOC_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - U32 CapabilitiesFlags; /* 04h */ - U8 NumActiveVolumes; /* 08h */ - U8 MaxVolumes; /* 09h */ - U16 Reserved; /* 0Ah */ - fCONFIG_PAGE_IOC_2_RAID_VOL RaidVolume[1]; /* 0Ch */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 CapabilitiesFlags; /* 04h */ + U8 NumActiveVolumes; /* 08h */ + U8 MaxVolumes; /* 09h */ + U8 NumActivePhysDisks; /* 0Ah */ + U8 MaxPhysDisks; /* 0Bh */ + fCONFIG_PAGE_IOC_2_RAID_VOL RaidVolume[MPI_IOC_PAGE_2_RAID_VOLUME_MAX];/* 0Ch */ } fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, IOCPage2_t, MPI_POINTER pIOCPage2_t; -#define MPI_IOCPAGE2_PAGEVERSION (0x00) +#define MPI_IOCPAGE2_PAGEVERSION (0x01) /* IOC Page 2 Capabilities flags */ -#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT (0x00000001) -#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT (0x00000002) -#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT (0x00000004) -#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008) -#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000010) - -/* IOC Page 2 Volume RAID Type values */ - -#define MPI_IOCPAGE2_VOL_TYPE_RAID_0 (0x00) -#define MPI_IOCPAGE2_VOL_TYPE_RAID_1 (0x01) -#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR (0x02) -#define MPI_IOCPAGE2_VOL_TYPE_RAID_5 (0x05) -#define MPI_IOCPAGE2_VOL_TYPE_RAID_10 (0x0A) - - -/****************************************************************************/ -/* SCSI Port Config Pages */ -/****************************************************************************/ +#define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT (0x00000001) +#define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT (0x00000002) +#define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT (0x00000004) +#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000) +#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000) +#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000) + +/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */ + +#define MPI_RAID_VOL_TYPE_IS (0x00) +#define MPI_RAID_VOL_TYPE_IME (0x01) +#define MPI_RAID_VOL_TYPE_IM (0x02) + + +typedef struct _IOC_3_PHYS_DISK +{ + U8 PhysDiskID; /* 00h */ + U8 PhysDiskBus; /* 01h */ + U8 PhysDiskIOC; /* 02h */ + U8 PhysDiskNum; /* 03h */ +} IOC_3_PHYS_DISK, MPI_POINTER PTR_IOC_3_PHYS_DISK, + Ioc3PhysDisk_t, MPI_POINTER pIoc3PhysDisk_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_IOC_PAGE_3_PHYSDISK_MAX +#define MPI_IOC_PAGE_3_PHYSDISK_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_IOC_3 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U8 NumPhysDisks; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ + IOC_3_PHYS_DISK PhysDisk[MPI_IOC_PAGE_3_PHYSDISK_MAX]; /* 08h */ +} fCONFIG_PAGE_IOC_3, MPI_POINTER PTR_CONFIG_PAGE_IOC_3, + IOCPage3_t, MPI_POINTER pIOCPage3_t; + +#define MPI_IOCPAGE3_PAGEVERSION (0x00) + + +typedef struct _IOC_4_SEP +{ + U8 SEPTargetID; /* 00h */ + U8 SEPBus; /* 01h */ + U16 Reserved; /* 02h */ +} IOC_4_SEP, MPI_POINTER PTR_IOC_4_SEP, + Ioc4Sep_t, MPI_POINTER pIoc4Sep_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_IOC_PAGE_4_SEP_MAX +#define MPI_IOC_PAGE_4_SEP_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_IOC_4 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U8 ActiveSEP; /* 04h */ + U8 MaxSEP; /* 05h */ + U16 Reserved1; /* 06h */ + IOC_4_SEP SEP[MPI_IOC_PAGE_4_SEP_MAX]; /* 08h */ +} fCONFIG_PAGE_IOC_4, MPI_POINTER PTR_CONFIG_PAGE_IOC_4, + IOCPage4_t, MPI_POINTER pIOCPage4_t; + +#define MPI_IOCPAGE4_PAGEVERSION (0x00) + + +/**************************************************************************** +* SCSI Port Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_SCSI_PORT_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Capabilities; /* 04h */ U32 PhysicalInterface; /* 08h */ } fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0, @@ -465,7 +616,6 @@ #define MPI_SCSIPORTPAGE0_CAP_IU (0x00000001) #define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) #define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) -#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS (0x00000008) #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) #define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) @@ -479,12 +629,13 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Configuration; /* 04h */ + U32 OnBusTimerValue; /* 08h */ } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; -#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x01) +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x02) #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) @@ -500,7 +651,7 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 PortFlags; /* 04h */ U32 PortSettings; /* 08h */ MPI_DEVICE_INFO DeviceSettings[16]; /* 0Ch */ @@ -510,7 +661,6 @@ #define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001) -#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE (0x00000002) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010) @@ -536,47 +686,48 @@ #define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE (0x0020) -/****************************************************************************/ -/* SCSI Target Device Config Pages */ -/****************************************************************************/ +/**************************************************************************** +* SCSI Target Device Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_SCSI_DEVICE_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 NegotiatedParameters; /* 04h */ U32 Information; /* 08h */ } fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0, SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t; -#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x01) +#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x02) #define MPI_SCSIDEVPAGE0_NP_IU (0x00000001) #define MPI_SCSIDEVPAGE0_NP_DT (0x00000002) #define MPI_SCSIDEVPAGE0_NP_QAS (0x00000004) -#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS (0x00000008) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) #define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) #define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED (0x00000001) +#define MPI_SCSIDEVPAGE0_INFO_SDTR_REJECTED (0x00000002) +#define MPI_SCSIDEVPAGE0_INFO_WDTR_REJECTED (0x00000004) +#define MPI_SCSIDEVPAGE0_INFO_PPR_REJECTED (0x00000008) typedef struct _CONFIG_PAGE_SCSI_DEVICE_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 RequestedParameters; /* 04h */ U32 Reserved; /* 08h */ U32 Configuration; /* 0Ch */ } fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1, SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t; -#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x02) +#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x03) #define MPI_SCSIDEVPAGE1_RP_IU (0x00000001) #define MPI_SCSIDEVPAGE1_RP_DT (0x00000002) #define MPI_SCSIDEVPAGE1_RP_QAS (0x00000004) -#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS (0x00000008) #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) #define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) @@ -585,12 +736,13 @@ #define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK (0x00000003) #define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK (0x00000300) -#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED (0x00000001) +#define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED (0x00000002) +#define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED (0x00000004) typedef struct _CONFIG_PAGE_SCSI_DEVICE_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 DomainValidation; /* 04h */ U32 ParityPipeSelect; /* 08h */ U32 DataPipeSelect; /* 0Ch */ @@ -629,13 +781,13 @@ #define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK (0xC0000000) -/****************************************************************************/ -/* FC Port Config Pages */ -/****************************************************************************/ +/**************************************************************************** +* FC Port Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_FC_PORT_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Flags; /* 04h */ U8 MPIPortNumber; /* 08h */ U8 LinkType; /* 09h */ @@ -715,7 +867,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_1 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Flags; /* 04h */ U64 NoSEEPROMWWNN; /* 08h */ U64 NoSEEPROMWWPN; /* 10h */ @@ -726,8 +878,10 @@ } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, FCPortPage1_t, MPI_POINTER pFCPortPage1_t; -#define MPI_FCPORTPAGE1_PAGEVERSION (0x01) +#define MPI_FCPORTPAGE1_PAGEVERSION (0x02) +#define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN (0x08000000) +#define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY (0x04000000) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000) @@ -747,22 +901,21 @@ #define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG (0x03) #define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO (0x0F) -#define MPI_FCPORTPAGE1_TOPOLGY_MASK (0x0F) -#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT (0x01) -#define MPI_FCPORTPAGE1_TOPOLGY_NPORT (0x02) -#define MPI_FCPORTPAGE1_TOPOLGY_AUTO (0x0F) +#define MPI_FCPORTPAGE1_TOPOLOGY_MASK (0x0F) +#define MPI_FCPORTPAGE1_TOPOLOGY_NLPORT (0x01) +#define MPI_FCPORTPAGE1_TOPOLOGY_NPORT (0x02) +#define MPI_FCPORTPAGE1_TOPOLOGY_AUTO (0x0F) typedef struct _CONFIG_PAGE_FC_PORT_2 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U8 NumberActive; /* 04h */ - U8 ALPA[126]; /* 05h */ - U8 Reserved; /* 83h */ + U8 ALPA[127]; /* 05h */ } fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2, FCPortPage2_t, MPI_POINTER pFCPortPage2_t; -#define MPI_FCPORTPAGE2_PAGEVERSION (0x00) +#define MPI_FCPORTPAGE2_PAGEVERSION (0x01) typedef struct _WWN_FORMAT @@ -795,10 +948,18 @@ #define MPI_PERSISTENT_FLAGS_BOOT_DEVICE (0x0008) #define MPI_PERSISTENT_FLAGS_BY_DID (0x0080) +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_FC_PORT_PAGE_3_ENTRY_MAX +#define MPI_FC_PORT_PAGE_3_ENTRY_MAX (1) +#endif + typedef struct _CONFIG_PAGE_FC_PORT_3 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - FC_PORT_PERSISTENT Entry[1]; /* 04h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + FC_PORT_PERSISTENT Entry[MPI_FC_PORT_PAGE_3_ENTRY_MAX]; /* 04h */ } fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3, FCPortPage3_t, MPI_POINTER pFCPortPage3_t; @@ -807,7 +968,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_4 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 PortFlags; /* 04h */ U32 PortSettings; /* 08h */ } fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4, @@ -833,13 +994,22 @@ U16 Reserved; /* 02h */ U64 AliasWWNN; /* 04h */ U64 AliasWWPN; /* 0Ch */ -} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO, +} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, + MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO, FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t; +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_FC_PORT_PAGE_5_ALIAS_MAX +#define MPI_FC_PORT_PAGE_5_ALIAS_MAX (1) +#endif + typedef struct _CONFIG_PAGE_FC_PORT_5 { - fCONFIG_PAGE_HEADER Header; /* 00h */ - fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO AliasInfo[1]; /* 04h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO AliasInfo[MPI_FC_PORT_PAGE_5_ALIAS_MAX];/* 04h */ } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5, FCPortPage5_t, MPI_POINTER pFCPortPage5_t; @@ -851,7 +1021,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_6 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved; /* 04h */ U64 TimeSinceReset; /* 08h */ U64 TxFrames; /* 10h */ @@ -877,7 +1047,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_7 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved; /* 04h */ U8 PortSymbolicName[256]; /* 08h */ } fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7, @@ -888,7 +1058,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_8 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 BitVector[8]; /* 04h */ } fCONFIG_PAGE_FC_PORT_8, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_8, FCPortPage8_t, MPI_POINTER pFCPortPage8_t; @@ -898,7 +1068,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_9 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved; /* 04h */ U64 GlobalWWPN; /* 08h */ U64 GlobalWWNN; /* 10h */ @@ -916,13 +1086,13 @@ #define MPI_FCPORTPAGE9_PAGEVERSION (0x00) -/****************************************************************************/ -/* FC Device Config Pages */ -/****************************************************************************/ +/**************************************************************************** +* FC Device Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_FC_DEVICE_0 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U64 WWNN; /* 04h */ U64 WWPN; /* 0Ch */ U32 PortIdentifier; /* 14h */ @@ -947,112 +1117,191 @@ #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02) #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04) -#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) -#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) -#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) -#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID (MPI_FC_DEVICE_PGAD_FORM_BUS_TID) -#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK (MPI_FC_DEVICE_PGAD_ND_DID_MASK) -#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK (MPI_FC_DEVICE_PGAD_BT_BUS_MASK) -#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) -#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) - - -/****************************************************************************/ -/* RAID Volume Config Pages */ -/****************************************************************************/ - -typedef struct _RAIDVOL2_IM_PHYS_ID -{ - U8 TargetID; /* 00h */ - U8 Bus; /* 01h */ - U8 IocNumber; /* 02h */ - U8 PhysDiskNumber; /* 03h */ - U8 Reserved[8]; /* 04h */ - U8 PhysicalDiskIdentifier[16]; /* 0Ch */ - U8 VendorId[8]; /* 1Ch */ - U8 ProductId[16]; /* 24h */ - U8 ProductRevLevel[4]; /* 34h */ - U32 Reserved1; /* 38h */ - U8 Info[32]; /* 3Ch */ -} RAIDVOL2_IM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_IM_PHYS_ID, - RaidVol2ImPhysicalID_t, MPI_POINTER pRaidVol2ImPhysicalID_t; - -typedef struct _RAIDVOL2_IM_DISK_INFO -{ - U32 DiskStatus; /* 00h */ - U32 DeviceSettings; /* 04h */ - U16 ErrorCount; /* 08h */ - U16 Reserved; /* 0Ah */ - U8 ErrorCdbByte; /* 0Ch */ - U8 ErrorSenseKey; /* 0Dh */ - U8 ErrorASC; /* 0Eh */ - U8 ErrorASCQ; /* 0Fh */ - U16 SmartCount; /* 10h */ - U8 SmartASC; /* 12h */ - U8 SmartASCQ; /* 13h */ -} RAIDVOL2_IM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_IM_DISK_INFO, - RaidVol2ImDiskInfo_t, MPI_POINTER pRaidVol2ImDiskInfo_t; +#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID (MPI_FC_DEVICE_PGAD_FORM_BUS_TID) +#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK (MPI_FC_DEVICE_PGAD_ND_DID_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK (MPI_FC_DEVICE_PGAD_BT_BUS_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) +#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) + + +/**************************************************************************** +* RAID Volume Config Pages +****************************************************************************/ + +typedef struct _RAID_VOL0_PHYS_DISK +{ + U16 Reserved; /* 00h */ + U8 PhysDiskMap; /* 02h */ + U8 PhysDiskNum; /* 03h */ +} RAID_VOL0_PHYS_DISK, MPI_POINTER PTR_RAID_VOL0_PHYS_DISK, + RaidVol0PhysDisk_t, MPI_POINTER pRaidVol0PhysDisk_t; + +#define MPI_RAIDVOL0_PHYSDISK_PRIMARY (0x01) +#define MPI_RAIDVOL0_PHYSDISK_SECONDARY (0x02) + +typedef struct _RAID_VOL0_STATUS +{ + U8 Flags; /* 00h */ + U8 State; /* 01h */ + U16 Reserved; /* 02h */ +} RAID_VOL0_STATUS, MPI_POINTER PTR_RAID_VOL0_STATUS, + RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t; + +/* RAID Volume Page 0 VolumeStatus defines */ + +#define MPI_RAIDVOL0_STATUS_FLAG_ENABLED (0x01) +#define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED (0x02) +#define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x04) + +#define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL (0x00) +#define MPI_RAIDVOL0_STATUS_STATE_DEGRADED (0x01) +#define MPI_RAIDVOL0_STATUS_STATE_FAILED (0x02) + +typedef struct _RAID_VOL0_SETTINGS +{ + U16 Settings; /* 00h */ + U8 HotSparePool; /* 01h */ /* MPI_RAID_HOT_SPARE_POOL_ */ + U8 Reserved; /* 02h */ +} RAID_VOL0_SETTINGS, MPI_POINTER PTR_RAID_VOL0_SETTINGS, + RaidVol0Settings, MPI_POINTER pRaidVol0Settings; + +/* RAID Volume Page 0 VolumeSettings defines */ + +#define MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE (0x0001) +#define MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART (0x0002) +#define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE (0x0004) +#define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC (0x0008) +#define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0010) +#define MPI_RAIDVOL0_SETTING_USE_DEFAULTS (0x8000) + +/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ +#define MPI_RAID_HOT_SPARE_POOL_0 (0x01) +#define MPI_RAID_HOT_SPARE_POOL_1 (0x02) +#define MPI_RAID_HOT_SPARE_POOL_2 (0x04) +#define MPI_RAID_HOT_SPARE_POOL_3 (0x08) +#define MPI_RAID_HOT_SPARE_POOL_4 (0x10) +#define MPI_RAID_HOT_SPARE_POOL_5 (0x20) +#define MPI_RAID_HOT_SPARE_POOL_6 (0x40) +#define MPI_RAID_HOT_SPARE_POOL_7 (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX +#define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_RAID_VOL_0 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U8 VolumeID; /* 04h */ + U8 VolumeBus; /* 05h */ + U8 VolumeIOC; /* 06h */ + U8 VolumeType; /* 07h */ /* MPI_RAID_VOL_TYPE_ */ + RAID_VOL0_STATUS VolumeStatus; /* 08h */ + RAID_VOL0_SETTINGS VolumeSettings; /* 0Ch */ + U32 MaxLBA; /* 10h */ + U32 Reserved1; /* 14h */ + U32 StripeSize; /* 18h */ + U32 Reserved2; /* 1Ch */ + U32 Reserved3; /* 20h */ + U8 NumPhysDisks; /* 24h */ + U8 Reserved4; /* 25h */ + U16 Reserved5; /* 26h */ + RAID_VOL0_PHYS_DISK PhysDisk[MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX];/* 28h */ +} fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, + RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; + +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x00) + + +/**************************************************************************** +* RAID Physical Disk Config Pages +****************************************************************************/ + +typedef struct _RAID_PHYS_DISK0_ERROR_DATA +{ + U8 ErrorCdbByte; /* 00h */ + U8 ErrorSenseKey; /* 01h */ + U16 Reserved; /* 02h */ + U16 ErrorCount; /* 04h */ + U8 ErrorASC; /* 06h */ + U8 ErrorASCQ; /* 07h */ + U16 SmartCount; /* 08h */ + U8 SmartASC; /* 0Ah */ + U8 SmartASCQ; /* 0Bh */ +} RAID_PHYS_DISK0_ERROR_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_ERROR_DATA, + RaidPhysDisk0ErrorData_t, MPI_POINTER pRaidPhysDisk0ErrorData_t; + +typedef struct _RAID_PHYS_DISK_INQUIRY_DATA +{ + U8 VendorID[8]; /* 00h */ + U8 ProductID[16]; /* 08h */ + U8 ProductRevLevel[4]; /* 18h */ + U8 Info[32]; /* 1Ch */ +} RAID_PHYS_DISK0_INQUIRY_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_INQUIRY_DATA, + RaidPhysDisk0InquiryData, MPI_POINTER pRaidPhysDisk0InquiryData; + +typedef struct _RAID_PHYS_DISK0_SETTINGS +{ + U8 SepID; /* 00h */ + U8 SepBus; /* 01h */ + U8 HotSparePool; /* 02h */ /* MPI_RAID_HOT_SPARE_POOL_ */ + U8 PhysDiskSettings; /* 03h */ +} RAID_PHYS_DISK0_SETTINGS, MPI_POINTER PTR_RAID_PHYS_DISK0_SETTINGS, + RaidPhysDiskSettings_t, MPI_POINTER pRaidPhysDiskSettings_t; + +typedef struct _RAID_PHYS_DISK0_STATUS +{ + U8 Flags; /* 00h */ + U8 State; /* 01h */ + U16 Reserved; /* 02h */ +} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS, + RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t; /* RAID Volume 2 IM Physical Disk DiskStatus flags */ -#define MPI_RVP2_PHYS_DISK_PRIMARY (0x00000001) -#define MPI_RVP2_PHYS_DISK_SECONDARY (0x00000002) -#define MPI_RVP2_PHYS_DISK_HOT_SPARE (0x00000004) -#define MPI_RVP2_PHYS_DISK_OUT_OF_SYNC (0x00000008) -#define MPI_RVP2_PHYS_DISK_STATUS_MASK (0x00000F00) -#define MPI_RVP2_PHYS_DISK_STATUS_ONLINE (0x00000000) -#define MPI_RVP2_PHYS_DISK_STATUS_MISSING (0x00000100) -#define MPI_RVP2_PHYS_DISK_STATUS_NOT_COMPATIBLE (0x00000200) -#define MPI_RVP2_PHYS_DISK_STATUS_FAILED (0x00000300) -#define MPI_RVP2_PHYS_DISK_STATUS_INITIALIZING (0x00000400) -#define MPI_RVP2_PHYS_DISK_STATUS_OFFLINE_REQUESTED (0x00000500) -#define MPI_RVP2_PHYS_DISK_STATUS_OTHER_OFFLINE (0x00000F00) - - -typedef struct _RAIDVOL2_IM_PHYSICAL_DISK -{ - RAIDVOL2_IM_PHYS_ID Id; /* 00h */ - RAIDVOL2_IM_DISK_INFO Info; /* 5Ch */ -} RAIDVOL2_IM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_IM_PHYSICAL_DISK, - RaidVol2ImPhysicalDisk_t, MPI_POINTER pRaidVol2ImPhysicalDisk_t; - -#define MPI_RAIDVOLPAGE2_MAX_DISKS (3) - -typedef struct _CONFIG_PAGE_RAID_VOL_2 -{ - fCONFIG_PAGE_HEADER Header; /* 00h */ - U32 VolumeStatus; /* 04h */ - U32 VolumeSettings; /* 08h */ - U32 Reserved; /* 0Ch */ - U64 MaxLba; /* 10h */ - U32 BlockSize; /* 18h */ - U8 Reserved1; /* 1Ch */ - U8 NumPhysicalDisks; /* 1Dh */ - U16 Reserved2; /* 1Eh */ - RAIDVOL2_IM_PHYSICAL_DISK IMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS]; -} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2, - RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t; - -#define MPI_RAIDVOLPAGE2_PAGEVERSION (0x00) - -/* RAID Volume Page 2 VolumeStatus defines */ - -#define MPI_RAIDVOLPAGE2_STATUS_ENABLED (0x00000001) -#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED (0x00000002) -#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS (0x00000004) -#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED (0x00000008) - -/* RAID Volume Page 2 VolumeSettings defines */ - -#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE (0x00000001) -#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART (0x00000002) -#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE (0x00000004) -#define MPI_RAIDVOLPAGE2_SETTING_USE_DEFAULTS (0x80000000) - - -/****************************************************************************/ -/* LAN Config Pages */ -/****************************************************************************/ +#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01) +#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02) + +#define MPI_PHYSDISK0_STATUS_ONLINE (0x00) +#define MPI_PHYSDISK0_STATUS_MISSING (0x01) +#define MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE (0x02) +#define MPI_PHYSDISK0_STATUS_FAILED (0x03) +#define MPI_PHYSDISK0_STATUS_INITIALIZING (0x04) +#define MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED (0x05) +#define MPI_PHYSDISK0_STATUS_FAILED_REQUESTED (0x06) +#define MPI_PHYSDISK0_STATUS_OTHER_OFFLINE (0xFF) + +typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U8 PhysDiskID; /* 04h */ + U8 PhysDiskBus; /* 05h */ + U8 PhysDiskIOC; /* 06h */ + U8 PhysDiskNum; /* 07h */ + RAID_PHYS_DISK0_SETTINGS PhysDiskSettings; /* 08h */ + U32 Reserved1; /* 0Ch */ + U32 Reserved2; /* 10h */ + U32 Reserved3; /* 14h */ + U8 DiskIdentifier[16]; /* 18h */ + RAID_PHYS_DISK0_INQUIRY_DATA InquiryData; /* 28h */ + RAID_PHYS_DISK0_STATUS PhysDiskStatus; /* 64h */ + U32 MaxLBA; /* 68h */ + RAID_PHYS_DISK0_ERROR_DATA ErrorData; /* 6Ch */ +} fCONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0, + RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t; + +#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x00) + + +/**************************************************************************** +* LAN Config Pages +****************************************************************************/ typedef struct _CONFIG_PAGE_LAN_0 { @@ -1083,8 +1332,8 @@ U32 MaxWireSpeedHigh; /* 1Ch */ U32 BucketsRemaining; /* 20h */ U32 MaxReplySize; /* 24h */ - U32 NegWireSpeedHigh; /* 28h */ - U32 NegWireSpeedLow; /* 2Ch */ + U32 NegWireSpeedLow; /* 28h */ + U32 NegWireSpeedHigh; /* 2Ch */ } fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1, LANPage1_t, MPI_POINTER pLANPage1_t; diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_fc.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_fc.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_fc.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_fc.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI Fibre Channel messages and structures * Creation Date: June 12, 2000 * - * MPI Version: 01.01.07 + * MPI Version: 01.02.02 * * Version History * --------------- @@ -32,6 +32,9 @@ * Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define. * Added structure offset comments. * 04-09-01 01.01.07 Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST. + * 08-08-01 01.02.01 Original release for v1.2 work. + * 09-28-01 01.02.02 Change name of reserved field in + * MSG_LINK_SERVICE_RSP_REPLY. * -------------------------------------------------------------------------- */ @@ -172,7 +175,7 @@ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ U16 Reserved1; /* 04h */ - U8 Reserved2; /* 06h */ + U8 Reserved_0100_InitiatorIndex; /* 06h */ /* obsolete InitiatorIndex */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U16 Reserved3; /* 0Ch */ diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_init.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_init.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_init.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_init.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * MPI Version: 01.01.05 + * MPI Version: 01.02.04 * * Version History * --------------- @@ -22,6 +22,13 @@ * 02-20-01 01.01.03 Started using MPI_POINTER. * 03-27-01 01.01.04 Added structure offset comments. * 04-10-01 01.01.05 Added new MsgFlag for MSG_SCSI_TASK_MGMT. + * 08-08-01 01.02.01 Original release for v1.2 work. + * 08-29-01 01.02.02 Added MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET. + * Added MPI_SCSI_STATE_QUEUE_TAG_REJECTED for + * MSG_SCSI_IO_REPLY. + * 09-28-01 01.02.03 Added structures and defines for SCSI Enclosure + * Processor messages. + * 10-04-01 01.02.04 Added defines for SEP request Action field. * -------------------------------------------------------------------------- */ @@ -151,6 +158,7 @@ #define MPI_SCSI_STATE_NO_SCSI_STATUS (0x04) #define MPI_SCSI_STATE_TERMINATED (0x08) #define MPI_SCSI_STATE_RESPONSE_INFO_VALID (0x10) +#define MPI_SCSI_STATE_QUEUE_TAG_REJECTED (0x20) /* SCSIIO Reply ResponseInfo values */ /* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */ @@ -191,6 +199,7 @@ #define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x04) +#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) @@ -215,5 +224,92 @@ U32 TerminationCount; /* 14h */ } MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY, SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t; + + +/****************************************************************************/ +/* SCSI Enclosure Processor messages */ +/****************************************************************************/ + +typedef struct _MSG_SEP_REQUEST +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 Action; /* 04h */ + U8 Reserved1; /* 05h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 SlotStatus; /* 0Ch */ +} MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST, + SEPRequest_t, MPI_POINTER pSEPRequest_t; + +/* Action defines */ +#define MPI_SEP_REQ_ACTION_WRITE_STATUS (0x00) +#define MPI_SEP_REQ_ACTION_READ_STATUS (0x01) + +/* SlotStatus bits for MSG_SEP_REQUEST */ +#define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) +#define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI_SEP_REQ_SLOTSTATUS_PARITY_CHECK (0x00000020) +#define MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) +#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT (0x00080000) +#define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE (0x00400000) +#define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) +#define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS (0x08000000) +#define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF (0x10000000) +#define MPI_SEP_REQ_SLOTSTATUS_SWAP_RESET (0x80000000) + + +typedef struct _MSG_SEP_REPLY +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U8 Action; /* 04h */ + U8 Reserved1; /* 05h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 SlotStatus; /* 14h */ +} MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY, + SEPReply_t, MPI_POINTER pSEPReply_t; + +/* SlotStatus bits for MSG_SEP_REPLY */ +#define MPI_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) +#define MPI_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI_SEP_REPLY_SLOTSTATUS_PARITY_CHECK (0x00000020) +#define MPI_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REPLY_SLOTSTATUS_REPORT (0x00010000) +#define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) +#define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY (0x00080000) +#define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE (0x00400000) +#define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED (0x01000000) +#define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED (0x02000000) +#define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) +#define MPI_SEP_REPLY_SLOTSTATUS_A_ENABLE_BYPASS (0x08000000) +#define MPI_SEP_REPLY_SLOTSTATUS_DEV_OFF (0x10000000) +#define MPI_SEP_REPLY_SLOTSTATUS_FAULT_SENSED (0x40000000) +#define MPI_SEP_REPLY_SLOTSTATUS_SWAPPED (0x80000000) #endif diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_ioc.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_ioc.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_ioc.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * MPI Version: 01.01.07 + * MPI Version: 01.02.04 * * Version History * --------------- @@ -38,6 +38,19 @@ * 03-27-01 01.01.06 Added defines for ProductId field of MPI_FW_HEADER. * Added structure offset comments. * 04-09-01 01.01.07 Added structure EVENT_DATA_EVENT_CHANGE. + * 08-08-01 01.02.01 Original release for v1.2 work. + * New format for FWVersion and ProductId in + * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. + * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and + * related structure and defines. + * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. + * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. + * Replaced a reserved field in MSG_IOC_FACTS_REPLY with + * IOCExceptions and changed DataImageSize to reserved. + * Added MPI_FW_DOWNLOAD_ITYPE_NVSTORE_DATA and + * MPI_FW_UPLOAD_ITYPE_NVDATA. + * 09-28-01 01.02.03 Modified Event Data for Integrated RAID. + * 11-01-01 01.02.04 Added defines for MPI_EXT_IMAGE_HEADER ImageType field. * -------------------------------------------------------------------------- */ @@ -73,6 +86,17 @@ } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, IOCInit_t, MPI_POINTER pIOCInit_t; +/* WhoInit values */ +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) + +/* Flags values */ +#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) + typedef struct _MSG_IOC_INIT_REPLY { U8 WhoInit; /* 00h */ @@ -90,14 +114,6 @@ } MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY, IOCInitReply_t, MPI_POINTER pIOCInitReply_t; -/* WhoInit values */ - -#define MPI_WHOINIT_NO_ONE (0x00) -#define MPI_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI_WHOINIT_ROM_BIOS (0x02) -#define MPI_WHOINIT_PCI_PEER (0x03) -#define MPI_WHOINIT_HOST_DRIVER (0x04) -#define MPI_WHOINIT_MANUFACTURER (0x05) /****************************************************************************/ @@ -115,8 +131,21 @@ } MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS, IOCFacts_t, MPI_POINTER pIOCFacts_t; -/* IOC Facts Reply */ +typedef struct _MPI_FW_VERSION_STRUCT +{ + U8 Dev; /* 00h */ + U8 Unit; /* 01h */ + U8 Minor; /* 02h */ + U8 Major; /* 03h */ +} MPI_FW_VERSION_STRUCT; + +typedef union _MPI_FW_VERSION +{ + MPI_FW_VERSION_STRUCT Struct; + U32 Word; +} MPI_FW_VERSION; +/* IOC Facts Reply */ typedef struct _MSG_IOC_FACTS_REPLY { U16 MsgVersion; /* 00h */ @@ -126,7 +155,7 @@ U8 IOCNumber; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ - U16 Reserved2; /* 0Ch */ + U16 IOCExceptions; /* 0Ch */ U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ U8 MaxChainDepth; /* 14h */ @@ -135,7 +164,7 @@ U8 Flags; /* 17h */ U16 ReplyQueueDepth; /* 18h */ U16 RequestFrameSize; /* 1Ah */ - U16 FWVersion; /* 1Ch */ + U16 Reserved_0101_FWVersion; /* 1Ch */ /* obsolete 16-bit FWVersion */ U16 ProductID; /* 1Eh */ U32 CurrentHostMfaHighAddr; /* 20h */ U16 GlobalCredits; /* 24h */ @@ -146,18 +175,20 @@ U8 MaxDevices; /* 2Eh */ U8 MaxBuses; /* 2Fh */ U32 FWImageSize; /* 30h */ - U32 DataImageSize; /* 34h */ + U32 Reserved4; /* 34h */ + MPI_FW_VERSION FWVersion; /* 38h */ } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; -#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) -#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) + +#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) -#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) -#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD (0x02) +#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) -#define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) -#define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) +#define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) +#define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) @@ -326,7 +357,6 @@ } MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY, EventAckReply_t, MPI_POINTER pEventAckReply_t; - /* Switch */ #define MPI_EVENT_NOTIFICATION_SWITCH_OFF (0x00) @@ -345,7 +375,9 @@ #define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) #define MPI_EVENT_LOGOUT (0x00000009) #define MPI_EVENT_EVENT_CHANGE (0x0000000A) -#define MPI_EVENT_RAID_STATUS_CHANGE (0x0000000B) +#define MPI_EVENT_INTEGRATED_RAID (0x0000000B) +#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) +#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) /* AckRequired field values */ @@ -372,6 +404,27 @@ } EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI, EventDataScsi_t, MPI_POINTER pEventDataScsi_t; +/* SCSI Device Status Change Event data */ + +typedef struct _EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 LUN; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 Reserved; /* 06h */ +} EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE, + MpiEventDataScsiDeviceStatusChange_t, + MPI_POINTER pMpiEventDataScsiDeviceStatusChange_t; + +/* MPI SCSI Device Status Change Event data ReasonCode values */ +#define MPI_EVENT_SCSI_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA (0x05) + /* MPI Link Status Change Event data */ typedef struct _EVENT_DATA_LINK_STATUS @@ -417,29 +470,34 @@ } EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT, EventDataLogout_t, MPI_POINTER pEventDataLogout_t; -/* MPI RAID Status Change Event data */ +/* MPI Integrated RAID Event data */ -typedef struct _EVENT_DATA_RAID_STATUS_CHANGE +typedef struct _EVENT_DATA_RAID { - U8 VolumeTargetID; /* 00h */ + U8 VolumeID; /* 00h */ U8 VolumeBus; /* 01h */ U8 ReasonCode; /* 02h */ U8 PhysDiskNum; /* 03h */ U8 ASC; /* 04h */ U8 ASCQ; /* 05h */ U16 Reserved; /* 06h */ -} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE, - MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t; - - -/* MPI RAID Status Change Event data ReasonCode values */ - -#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL (0x00) -#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED (0x01) -#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC (0x02) -#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED (0x03) -#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING (0x04) -#define MPI_EVENT_RAID_DATA_RC_SMART_DATA (0x05) + U32 SettingsStatus; /* 08h */ +} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID, + MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t; + +/* MPI Integrated RAID Event data ReasonCode values */ +#define MPI_EVENT_RAID_RC_VOLUME_CREATED (0x00) +#define MPI_EVENT_RAID_RC_VOLUME_DELETED (0x01) +#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED (0x02) +#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED (0x03) +#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED (0x04) +#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED (0x05) +#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED (0x06) +#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED (0x07) +#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED (0x08) +#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED (0x09) +#define MPI_EVENT_RAID_RC_SMART_DATA (0x0A) +#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED (0x0B) /***************************************************************************** @@ -468,6 +526,7 @@ #define MPI_FW_DOWNLOAD_ITYPE_RESERVED (0x00) #define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) +#define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) typedef struct _FWDownloadTCSGE @@ -476,7 +535,7 @@ U8 ContextSize; /* 01h */ U8 DetailsLength; /* 02h */ U8 Flags; /* 03h */ - U32 Reserved1; /* 04h */ + U32 Reserved_0100_Checksum; /* 04h */ /* obsolete Checksum */ U32 ImageOffset; /* 08h */ U32 ImageSize; /* 0Ch */ } FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE, @@ -519,7 +578,7 @@ #define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00) #define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM (0x03) +#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) typedef struct _FWUploadTCSGE { @@ -563,11 +622,10 @@ U32 Checksum; /* 1Ch */ U16 VendorId; /* 20h */ U16 ProductId; /* 22h */ - U16 FwVersion; /* 24h */ - U16 Reserved1; /* 26h */ + MPI_FW_VERSION FWVersion; /* 24h */ U32 SeqCodeVersion; /* 28h */ U32 ImageSize; /* 2Ch */ - U32 Reserved2; /* 30h */ + U32 NextImageHeaderOffset; /* 30h */ U32 LoadStartAddress; /* 34h */ U32 IopResetVectorValue; /* 38h */ U32 IopResetRegAddr; /* 3Ch */ @@ -581,30 +639,49 @@ #define MPI_FW_HEADER_WHAT_SIGNATURE (0x29232840) /* defines for using the ProductId field */ -#define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) -#define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) -#define MPI_FW_HEADER_PID_TYPE_FC (0x1000) - -#define MPI_FW_HEADER_PID_FW_VENDOR_MASK (0x0F00) -#define MPI_FW_HEADER_PID_FW_VENDOR_LSI (0x0000) - -#define MPI_FW_HEADER_PID_FAMILY_MASK (0x000F) -#define MPI_FW_HEADER_PID_FAMILY_1030_SCSI (0x0000) -#define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) -#define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) -#define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) - - -typedef struct _MPI_DATA_HEADER -{ - U32 Signature; /* 00h */ - U16 FunctionNumber; /* 04h */ - U16 Length; /* 06h */ - U32 Checksum; /* 08h */ - U32 LoadStartAddress; /* 0Ch */ -} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER, - MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t; +#define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) +#define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) +#define MPI_FW_HEADER_PID_TYPE_FC (0x1000) + +#define MPI_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI (0x0100) +#define MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI_FW_HEADER_PID_PROD_TARGET_SCSI (0x0300) +#define MPI_FW_HEADER_PID_PROD_IM_SCSI (0x0400) +#define MPI_FW_HEADER_PID_PROD_IS_SCSI (0x0500) +#define MPI_FW_HEADER_PID_PROD_CTX_SCSI (0x0600) + +#define MPI_FW_HEADER_PID_FAMILY_MASK (0x00FF) +#define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI (0x0001) +#define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI (0x0003) +#define MPI_FW_HEADER_PID_FAMILY_1030C0_SCSI (0x0004) +#define MPI_FW_HEADER_PID_FAMILY_1020A0_SCSI (0x0005) +#define MPI_FW_HEADER_PID_FAMILY_1020B0_SCSI (0x0006) +#define MPI_FW_HEADER_PID_FAMILY_1020B1_SCSI (0x0007) +#define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI (0x0008) +#define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI (0x0009) +#define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI (0x000A) +#define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) +#define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) +#define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) -#define MPI_DATA_HEADER_SIGNATURE (0x43504147) +typedef struct _MPI_EXT_IMAGE_HEADER +{ + U8 ImageType; /* 00h */ + U8 Reserved; /* 01h */ + U16 Reserved1; /* 02h */ + U32 Checksum; /* 04h */ + U32 ImageSize; /* 08h */ + U32 NextImageHeaderOffset; /* 0Ch */ + U32 LoadStartAddress; /* 10h */ + U32 Reserved2; /* 14h */ +} MPI_EXT_IMAGE_HEADER, MPI_POINTER PTR_MPI_EXT_IMAGE_HEADER, + MpiExtImageHeader_t, MPI_POINTER pMpiExtImageHeader_t; + +/* defines for the ImageType field */ +#define MPI_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI_EXT_IMAGE_TYPE_FW (0x01) +#define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) #endif diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_lan.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_lan.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_lan.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_lan.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI LAN messages and structures * Creation Date: June 30, 2000 * - * MPI Version: 01.01.03 + * MPI Version: 01.02.01 * * Version History * --------------- @@ -27,6 +27,7 @@ * 11-02-00 01.01.01 Original release for post 1.0 work * 02-20-01 01.01.02 Started using MPI_POINTER. * 03-27-01 01.01.03 Added structure offset comments. + * 08-08-01 01.02.01 Original release for v1.2 work. * -------------------------------------------------------------------------- */ diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_raid.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_raid.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_raid.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2001 LSI Logic Corporation. + * + * + * Name: MPI_RAID.H + * Title: MPI RAID message and structures + * Creation Date: February 27, 2001 + * + * MPI Version: 01.02.04 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 02-27-01 01.01.01 Original release for this file. + * 03-27-01 01.01.02 Added structure offset comments. + * 08-08-01 01.02.01 Original release for v1.2 work. + * 09-28-01 01.02.02 Major rework for MPI v1.2 Integrated RAID changes. + * 10-04-01 01.02.03 Added ActionData defines for + * MPI_RAID_ACTION_DELETE_VOLUME action. + * 11-01-01 01.02.04 Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_RAID_H +#define MPI_RAID_H + + +/****************************************************************************** +* +* R A I D M e s s a g e s +* +*******************************************************************************/ + + +/****************************************************************************/ +/* RAID Volume Request */ +/****************************************************************************/ + +typedef struct _MSG_RAID_ACTION +{ + U8 Action; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 VolumeID; /* 04h */ + U8 VolumeBus; /* 05h */ + U8 PhysDiskNum; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved2; /* 0Ch */ + U32 ActionDataWord; /* 10h */ + SGE_SIMPLE_UNION ActionDataSGE; /* 14h */ +} MSG_RAID_ACTION_REQUEST, MPI_POINTER PTR_MSG_RAID_ACTION_REQUEST, + MpiRaidActionRequest_t , MPI_POINTER pMpiRaidActionRequest_t; + + +/* RAID Action request Action values */ + +#define MPI_RAID_ACTION_STATUS (0x00) +#define MPI_RAID_ACTION_INDICATOR_STRUCT (0x01) +#define MPI_RAID_ACTION_CREATE_VOLUME (0x02) +#define MPI_RAID_ACTION_DELETE_VOLUME (0x03) +#define MPI_RAID_ACTION_DISABLE_VOLUME (0x04) +#define MPI_RAID_ACTION_ENABLE_VOLUME (0x05) +#define MPI_RAID_ACTION_QUIESCE_PHYS_IO (0x06) +#define MPI_RAID_ACTION_ENABLE_PHYS_IO (0x07) +#define MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS (0x08) +#define MPI_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) +#define MPI_RAID_ACTION_PHYSDISK_ONLINE (0x0B) +#define MPI_RAID_ACTION_CHANGE_PHYSDISK_SETTINGS (0x0C) +#define MPI_RAID_ACTION_CREATE_PHYSDISK (0x0D) +#define MPI_RAID_ACTION_DELETE_PHYSDISK (0x0E) +#define MPI_RAID_ACTION_FAIL_PHYSDISK (0x0F) +#define MPI_RAID_ACTION_REPLACE_PHYSDISK (0x10) + +/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */ +#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001) + +/* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */ +#define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS (0x00000000) +#define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS (0x00000001) + + +/* RAID Action reply message */ + +typedef struct _MSG_RAID_ACTION_REPLY +{ + U8 Action; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U8 VolumeID; /* 04h */ + U8 VolumeBus; /* 05h */ + U8 PhysDiskNum; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 ActionStatus; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 VolumeStatus; /* 14h */ + U32 ActionData; /* 18h */ +} MSG_RAID_ACTION_REPLY, MPI_POINTER PTR_MSG_RAID_ACTION_REPLY, + MpiRaidActionReply_t, MPI_POINTER pMpiRaidActionReply_t; + + +/* RAID Volume reply ActionStatus values */ + +#define MPI_RAID_ACTION_ASTATUS_SUCCESS (0x0000) +#define MPI_RAID_ACTION_ASTATUS_INVALID_ACTION (0x0001) +#define MPI_RAID_ACTION_ASTATUS_FAILURE (0x0002) +#define MPI_RAID_ACTION_ASTATUS_IN_PROGRESS (0x0003) + + +/* RAID Volume reply RAID Volume Indicator structure */ + +typedef struct _MPI_RAID_VOL_INDICATOR +{ + U64 TotalBlocks; /* 00h */ + U64 BlocksRemaining; /* 08h */ +} MPI_RAID_VOL_INDICATOR, MPI_POINTER PTR_MPI_RAID_VOL_INDICATOR, + MpiRaidVolIndicator_t, MPI_POINTER pMpiRaidVolIndicator_t; + + +/****************************************************************************/ +/* SCSI IO RAID Passthrough Request */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO_RAID_PT_REQUEST +{ + U8 PhysDiskNum; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + U8 CDB[16]; /* 18h */ + U32 DataLength; /* 28h */ + U32 SenseBufferLowAddr; /* 2Ch */ + SGE_IO_UNION SGL; /* 30h */ +} MSG_SCSI_IO_RAID_PT_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REQUEST, + SCSIIORaidPassthroughRequest_t, MPI_POINTER pSCSIIORaidPassthroughRequest_t; + + +/* SCSI IO RAID Passthrough reply structure */ + +typedef struct _MSG_SCSI_IO_RAID_PT_REPLY +{ + U8 PhysDiskNum; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 SCSIStatus; /* 0Ch */ + U8 SCSIState; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferCount; /* 14h */ + U32 SenseCount; /* 18h */ + U32 ResponseInfo; /* 1Ch */ +} MSG_SCSI_IO_RAID_PT_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REPLY, + SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t; + + +#endif + + + diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_targ.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_targ.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_targ.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI Version: 01.01.04 + * MPI Version: 01.02.04 * * Version History * --------------- @@ -26,6 +26,14 @@ * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and * MPI_TARGET_FCP_CMD_BUFFER. * 03-27-01 01.01.04 Added structure offset comments. + * 08-08-01 01.02.01 Original release for v1.2 work. + * 09-28-01 01.02.02 Added structure for MPI_TARGET_SCSI_SPI_STATUS_IU. + * Added PriorityReason field to some replies and + * defined more PriorityReason codes. + * Added some defines for to support previous version + * of MPI. + * 10-04-01 01.02.03 Added PriorityReason to MSG_TARGET_ERROR_REPLY. + * 11-01-01 01.02.04 Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY. * -------------------------------------------------------------------------- */ @@ -78,6 +86,7 @@ #define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR (0x80) #define CMD_BUFFER_POST_IO_INDEX_MASK (0x00003FFF) +#define CMD_BUFFER_POST_IO_INDEX_MASK_0100 (0x000003FF) /* obsolete */ typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY @@ -97,7 +106,7 @@ } MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY, TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t; - +/* the following structure is obsolete as of MPI v1.2 */ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY { U16 Reserved; /* 00h */ @@ -117,6 +126,13 @@ #define PRIORITY_REASON_NO_DISCONNECT (0x00) #define PRIORITY_REASON_SCSI_TASK_MANAGEMENT (0x01) +#define PRIORITY_REASON_CMD_PARITY_ERR (0x02) +#define PRIORITY_REASON_MSG_OUT_PARITY_ERR (0x03) +#define PRIORITY_REASON_LQ_CRC_ERR (0x04) +#define PRIORITY_REASON_CMD_CRC_ERR (0x05) +#define PRIORITY_REASON_PROTOCOL_ERR (0x06) +#define PRIORITY_REASON_DATA_OUT_PARITY_ERR (0x07) +#define PRIORITY_REASON_DATA_OUT_CRC_ERR (0x08) #define PRIORITY_REASON_UNKNOWN (0xFF) @@ -129,7 +145,8 @@ U8 Reserved2; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ - U16 Reserved3; /* 0Ch */ + U8 PriorityReason; /* 0Ch */ + U8 Reserved3; /* 0Dh */ U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ U32 ReplyWord; /* 14h */ @@ -204,7 +221,8 @@ U8 Reserved2; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ - U16 Reserved3; /* 0Ch */ + U8 PriorityReason; /* 0Ch */ + U8 Reserved3; /* 0Dh */ U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ U32 ReplyWord; /* 14h */ @@ -234,8 +252,34 @@ TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t; #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS (0x01) +#define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY (0x04) #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER (0x80) +typedef struct _MPI_TARGET_FCP_RSP_BUFFER +{ + U8 Reserved0[8]; /* 00h */ + U8 FcpStatus; /* 08h */ + U8 FcpFlags; /* 09h */ + U8 Reserved1[2]; /* 0Ah */ + U32 FcpResid; /* 0Ch */ + U32 FcpSenseLength; /* 10h */ + U32 FcpResponseLength; /* 14h */ + U8 FcpResponseData[8]; /* 18h */ + U8 FcpSenseData[32]; /* Pad to 64 bytes */ /* 20h */ +} MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER, + MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer; + +typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU +{ + U8 Reserved0; /* 00h */ + U8 Reserved1; /* 01h */ + U8 Valid; /* 02h */ + U8 Status; /* 03h */ + U32 SenseDataListLength; /* 04h */ + U32 PktFailuresListLength; /* 08h */ + U8 SenseData[52]; /* Pad the IU to 64 bytes */ /* 0Ch */ +} MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU, + TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t; /****************************************************************************/ /* Target Mode Abort Request */ @@ -323,6 +367,41 @@ #define SET_PORT(t, p) ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) | \ (((p) << TARGET_MODE_REPLY_PORT_SHIFT) & \ TARGET_MODE_REPLY_PORT_MASK)) + +/* the following obsolete values are for MPI v1.0 support */ +#define TARGET_MODE_REPLY_0100_MASK_HOST_INDEX (0x000003FF) +#define TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX (0) +#define TARGET_MODE_REPLY_0100_MASK_IOC_INDEX (0x001FF800) +#define TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX (11) +#define TARGET_MODE_REPLY_0100_PORT_MASK (0x00400000) +#define TARGET_MODE_REPLY_0100_PORT_SHIFT (22) +#define TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX (0x1F800000) +#define TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX (23) + +#define GET_HOST_INDEX_0100(x) (((x) & TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) \ + >> TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX) + +#define SET_HOST_INDEX_0100(t, hi) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) | \ + (((hi) << TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX) & \ + TARGET_MODE_REPLY_0100_MASK_HOST_INDEX)) + +#define GET_IOC_INDEX_0100(x) (((x) & TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) \ + >> TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX) + +#define SET_IOC_INDEX_0100(t, ii) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) | \ + (((ii) << TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX) & \ + TARGET_MODE_REPLY_0100_MASK_IOC_INDEX)) + +#define GET_INITIATOR_INDEX_0100(x) \ + (((x) & TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX) \ + >> TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX) + +#define SET_INITIATOR_INDEX_0100(t, ii) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX) | \ + (((ii) << TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX) & \ + TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX)) #endif diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_tool.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_tool.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_tool.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_tool.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001 LSI Logic Corporation. + * + * + * Name: MPI_TOOL.H + * Title: MPI Toolbox structures and definitions + * Creation Date: July 30, 2001 + * + * MPI Version: 01.02.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 08-08-01 01.02.01 Original release. + * 08-29-01 01.02.02 Added DIAG_DATA_UPLOAD_HEADER and related defines. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TOOL_H +#define MPI_TOOL_H + +#define MPI_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) + + +/****************************************************************************/ +/* Toolbox reply */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_REPLY +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY, + ToolboxReply_t, MPI_POINTER pToolboxReply_t; + + +/****************************************************************************/ +/* Toolbox Clean Tool request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ +} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST, + ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t; + +#define MPI_TOOLBOX_CLEAN_NVSRAM (0x00000001) +#define MPI_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI_TOOLBOX_CLEAN_FLASH (0x00000004) + + +/****************************************************************************/ +/* Toolbox Memory Move request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + SGE_SIMPLE_UNION SGL; /* 0Ch */ +} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST, + ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t; + + +/****************************************************************************/ +/* Toolbox Diagnostic Data Upload request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ + U32 Reserved3; /* 10h */ + SGE_SIMPLE_UNION SGL; /* 14h */ +} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t; + +typedef struct _DIAG_DATA_UPLOAD_HEADER +{ + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved; /* 05h */ + U16 Reserved1; /* 06h */ +} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER, + DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t; + +#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1 (0x01) +#define MPI_TB_DIAG_FORMAT_SCSI_2 (0x02) +#define MPI_TB_DIAG_FORMAT_SCSI_3 (0x03) +#define MPI_TB_DIAG_FORMAT_FC_TRACE_1 (0x04) + + +#endif + + diff -urN linux-2.4.18/drivers/message/fusion/lsi/mpi_type.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_type.h --- linux-2.4.18/drivers/message/fusion/lsi/mpi_type.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_type.h Sat Mar 30 22:55:39 2002 @@ -6,7 +6,7 @@ * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * MPI Version: 01.01.02 + * MPI Version: 01.02.01 * * Version History * --------------- @@ -17,6 +17,7 @@ * 06-06-00 01.00.01 Update version number for 1.0 release. * 11-02-00 01.01.01 Original release for post 1.0 work * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. + * 08-08-01 01.02.01 Original release for v1.2 work. * -------------------------------------------------------------------------- */ diff -urN linux-2.4.18/drivers/message/fusion/mptbase.c linux-2.4.19-pre5/drivers/message/fusion/mptbase.c --- linux-2.4.18/drivers/message/fusion/mptbase.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/mptbase.c Sat Mar 30 22:55:39 2002 @@ -20,6 +20,12 @@ * And to Roger Hickerson (LSI Logic) for tirelessly supporting * this driver project. * + * A special thanks to Pamela Delaney (LSI Logic) for tons of work + * and countless enhancements while adding support for the 1030 + * chip family. Pam has been instrumental in the development of + * of the 2.xx.xx series fusion drivers, and her contributions are + * far too numerous to hope to list in one place. + * * All manner of help from Stephen Shirron (LSI Logic): * low-level FC analysis, debug + various fixes in FCxx firmware, * initial port to alpha platform, various driver code optimizations, @@ -38,11 +44,12 @@ * for gobs of hard work fixing and optimizing LAN code. * THANK YOU! * - * Copyright (c) 1999-2001 LSI Logic Corporation + * Copyright (c) 1999-2002 LSI Logic Corporation * Originally By: Steven J. Ralston - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.c,v 1.53.4.3 2001/09/18 03:54:54 sralston Exp $ + * $Id: mptbase.c,v 1.110 2002/02/27 18:44:20 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -93,11 +100,14 @@ #include #include #include -#include +#include /* needed for in_interrupt() proto */ #include #ifdef CONFIG_MTRR #include #endif +#ifdef __sparc__ +#include /* needed for __irq_itoa() proto */ +#endif #include "mptbase.h" @@ -110,27 +120,33 @@ MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); - /* * cmd line parameters */ MODULE_PARM(PortIo, "0-1i"); MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io"); -MODULE_PARM(HardReset, "0-1i"); -MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset"); static int PortIo = 0; -static int HardReset = 1; + +#ifdef MFCNT +static int mfcounter = 0; +#define PRINT_MF_COUNT 20000 +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Public data... */ -int mpt_lan_index = 0; -int mpt_stm_index = 0; +int mpt_lan_index = -1; +int mpt_stm_index = -1; + +struct proc_dir_entry *mpt_proc_root_dir; + +DmpServices_t *DmpService; + +void *mpt_v_ASCQ_TablePtr; +const char **mpt_ScsiOpcodesPtr; +int mpt_ASCQ_TableSz; -void *mpt_v_ASCQ_TablePtr = NULL; -const char **mpt_ScsiOpcodesPtr = NULL; -int mpt_ASCQ_TableSz = 0; #define WHOINIT_UNKNOWN 0xAA @@ -139,12 +155,12 @@ * Private data... */ /* Adapter lookup table */ -static MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS] = {0}; + MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS]; static MPT_ADAPTER_TRACKER MptAdapters; /* Callback lookup table */ static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; /* Protocol driver class lookup table */ -static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; +static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; /* Event handler lookup table */ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; /* Reset handler lookup table */ @@ -152,6 +168,10 @@ static int FusionInitCalled = 0; static int mpt_base_index = -1; +static int last_drv_idx = -1; +static int isense_idx = -1; + +static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -160,49 +180,84 @@ static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); -static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason); -static int mpt_adapter_install(struct pci_dev *pdev); -static void mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); +static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); +static int mpt_adapter_install(struct pci_dev *pdev); +static void mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup); static void mpt_adapter_dispose(MPT_ADAPTER *ioc); static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); -static int MakeIocReady(MPT_ADAPTER *ioc, int force); -static u32 GetIocState(MPT_ADAPTER *ioc, int cooked); -static int GetIocFacts(MPT_ADAPTER *ioc); -static int GetPortFacts(MPT_ADAPTER *ioc, int portnum); -static int SendIocInit(MPT_ADAPTER *ioc); -static int SendPortEnable(MPT_ADAPTER *ioc, int portnum); -static int mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore); -static int KickStart(MPT_ADAPTER *ioc, int ignore); -static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type); +static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag); +//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); +static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason); +static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag); +static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag); +static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag); +static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag); +static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag); +static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag); +static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag); +static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag); static int PrimeIocFifos(MPT_ADAPTER *ioc); -static int HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait); -static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong); -static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong); -static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong); +static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag); +static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag); +static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag); static int GetLanConfigPages(MPT_ADAPTER *ioc); +static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum); +static int GetIoUnitPage2(MPT_ADAPTER *ioc); +static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); +static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); +static int mpt_findImVolumes(MPT_ADAPTER *ioc); +static void mpt_timer_expired(unsigned long data); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); -static int procmpt_create(void); #ifdef CONFIG_PROC_FS +static int procmpt_create(void); static int procmpt_destroy(void); +static int procmpt_summary_read(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int procmpt_version_read(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, + int request, int *eof, void *data); #endif -static int procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data); -static int procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data); -/*static int procmpt_info(char *buf, char **start, off_t offset, int len);*/ +static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); +//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info); -static struct proc_dir_entry *procmpt_root_dir = NULL; - int fusion_init(void); static void fusion_exit(void); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * more Private data... + */ +#ifdef CONFIG_PROC_FS +struct _mpt_proc_list { + const char *name; + int (*f)(char *, char **, off_t, int, int *, void *); +} mpt_proc_list[] = { + { "summary", procmpt_summary_read}, + { "version", procmpt_version_read}, +}; +#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0])) + +struct _mpt_ioc_proc_list { + const char *name; + int (*f)(char *, char **, off_t, int, int *, void *); +} mpt_ioc_proc_list[] = { + { "info", procmpt_iocinfo_read}, + { "summary", procmpt_summary_read}, +}; +#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0])) + +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* 20000207 -sralston * GRRRRR... IOSpace (port i/o) register access (for the 909) is back! * 20000517 -sralston @@ -225,9 +280,18 @@ writel(v, a); } +static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v) +{ + outl(v, (unsigned long)a); +} + +static inline u32 CHIPREG_PIO_READ32(volatile u32 *a) +{ + return inl((unsigned long)a); +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure @@ -252,8 +316,7 @@ MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; u32 pa; - u32 *m; - int req_idx; + int req_idx = -1; int cb_idx; int type; int freeme; @@ -262,6 +325,21 @@ ioc = bus_id; /* + * Verify ioc pointer is ok + */ + { + MPT_ADAPTER *iocCmp; + iocCmp = mpt_adapter_find_first(); + while ((ioc != iocCmp) && iocCmp) + iocCmp = mpt_adapter_find_next(iocCmp); + + if (!iocCmp) { + printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n"); + return; + } + } + + /* * Drain the reply FIFO! * * NOTES: I've seen up to 10 replies processed in this loop, so far... @@ -281,25 +359,27 @@ * Check for non-TURBO reply! */ if (pa & MPI_ADDRESS_REPLY_A_BIT) { - dma_addr_t reply_dma_addr; + u32 reply_dma_low; u16 ioc_stat; /* non-TURBO reply! Hmmm, something may be up... * Newest turbo reply mechanism; get address * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! */ - reply_dma_addr = (pa = (pa << 1)); - /* Map DMA address of reply header to cpu address. */ - m = (u32 *) ((u8 *)ioc->reply_frames + - (reply_dma_addr - ioc->reply_frames_dma)); + /* Map DMA address of reply header to cpu address. + * pa is 32 bits - but the dma address may be 32 or 64 bits + * get offset based only only the low addresses + */ + reply_dma_low = (pa = (pa << 1)); + mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + + (reply_dma_low - ioc->reply_frames_low_dma)); - mr = (MPT_FRAME_HDR *) m; req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n", + dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n", ioc->name, mr)); DBG_DUMP_REPLY_FRAME(mr) @@ -307,7 +387,7 @@ * Check/log IOC log info */ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); - if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { + if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); if ((int)ioc->chip_type <= (int)FC929) mpt_fc_log_info(ioc, log_info); @@ -318,7 +398,7 @@ /* * Process turbo (context) reply... */ - dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa)); + dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa)); type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { cb_idx = mpt_stm_index; @@ -357,6 +437,34 @@ pa = 0; /* No reply flush! */ } + if ((int)ioc->chip_type > (int)FC929) { + /* Verify mf, mf are reasonable. + */ + if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) + || (mf < ioc->req_frames)) ) { + printk(MYIOC_s_WARN_FMT + "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, mf, req_idx); + cb_idx = 0; + pa = 0; + freeme = 0; + } + if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth)) + || (mr < ioc->reply_frames)) ) { + printk(MYIOC_s_WARN_FMT + "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, mr); + cb_idx = 0; + pa = 0; + freeme = 0; + } + if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) { + printk(MYIOC_s_WARN_FMT + "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx); + cb_idx = 0; + pa = 0; + freeme = 0; + } + } + /* Check for (valid) IO callback! */ if (cb_idx) { /* Do the callback! */ @@ -374,15 +482,18 @@ /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); +#ifdef MFCNT + ioc->mfcnt--; +#endif spin_unlock_irqrestore(&ioc->FreeQlock, flags); } count++; - dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count)); + dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count)); mb(); if (count >= MPT_MAX_REPLIES_PER_ISR) { - dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.", + dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.", ioc->name, count)); dirqprintk((" Giving this ISR a break!\n")); return; @@ -409,17 +520,17 @@ int freereq = 1; u8 func; - dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name)); + dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); if ((mf == NULL) || (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n", + printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n", ioc->name, mf); return 1; } if (reply == NULL) { - dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n", + dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n", ioc->name)); return 1; } @@ -430,7 +541,7 @@ } func = reply->u.hdr.Function; - dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n", + dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", ioc->name, func)); if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { @@ -441,30 +552,77 @@ results = ProcessEventNotification(ioc, pEvReply, &evHandlers); if (results != evHandlers) { /* CHECKME! Any special handling needed here? */ - dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n", + dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", ioc->name, evHandlers, results)); } /* - * Hmmm... It seems that EventNotificationReply is an exception - * to the rule of one reply per request. + * Hmmm... It seems that EventNotificationReply is an exception + * to the rule of one reply per request. */ if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) freereq = 0; + #ifdef CONFIG_PROC_FS // LogEvent(ioc, pEvReply); #endif + } else if (func == MPI_FUNCTION_EVENT_ACK) { - dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n", + dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", ioc->name)); + } else if (func == MPI_FUNCTION_CONFIG) { + CONFIGPARMS *pCfg; + unsigned long flags; + + dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n", + ioc->name, mf, reply)); + + pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); + + if (pCfg) { + /* disable timer and remove from linked list */ + del_timer(&pCfg->timer); + + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_DEL_ITEM(&pCfg->linkage); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + /* + * If IOC Status is SUCCESS, save the header + * and set the status code to GOOD. + */ + pCfg->status = MPT_CONFIG_ERROR; + if (reply) { + ConfigReply_t *pReply = (ConfigReply_t *)reply; + u16 status; + + status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + dprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n", + status, le32_to_cpu(pReply->IOCLogInfo))); + + pCfg->status = status; + if (status == MPI_IOCSTATUS_SUCCESS) { + pCfg->hdr->PageVersion = pReply->Header.PageVersion; + pCfg->hdr->PageLength = pReply->Header.PageLength; + pCfg->hdr->PageNumber = pReply->Header.PageNumber; + pCfg->hdr->PageType = pReply->Header.PageType; + } + } + + /* + * Wake up the original calling thread + */ + pCfg->wait_done = 1; + wake_up(&mpt_waitq); + } } else { - printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n", + printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", ioc->name, func); } /* - * Conditionally tell caller to free the original - * EventNotification/EventAck/unexpected request frame! + * Conditionally tell caller to free the original + * EventNotification/EventAck/unexpected request frame! */ return freereq; } @@ -480,21 +638,22 @@ * protocol-specific driver must do this before it will be able to * use any IOC resources, such as obtaining request frames. * - * NOTES: The SCSI protocol driver currently calls this routine twice - * in order to register separate callbacks; one for "normal" SCSI IO - * and another for MptScsiTaskMgmt requests. + * NOTES: The SCSI protocol driver currently calls this routine thrice + * in order to register separate callbacks; one for "normal" SCSI IO; + * one for MptScsiTaskMgmt requests; one for Scan/DV requests. * * Returns a positive integer valued "handle" in the - * range (and S.O.D. order) {7,6,...,1} if successful. + * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful. * Any non-positive return value (including zero!) should be considered * an error by the caller. */ int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) { - int r = -1; int i; + last_drv_idx = -1; + #ifndef MODULE /* * Handle possibility of the mptscsih_detect() routine getting @@ -512,7 +671,7 @@ #endif /* - * Search for empty callback slot in this order: {7,6,...,1} + * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) */ for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { @@ -520,7 +679,7 @@ MptCallbacks[i] = cbfunc; MptDriverClass[i] = dclass; MptEvHandlers[i] = NULL; - r = i; + last_drv_idx = i; if (cbfunc != mpt_base_reply) { MOD_INC_USE_COUNT; } @@ -528,7 +687,7 @@ } } - return r; + return last_drv_idx; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -546,6 +705,11 @@ MptCallbacks[cb_idx] = NULL; MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; MptEvHandlers[cb_idx] = NULL; + + last_drv_idx++; + if (isense_idx != -1 && isense_idx <= cb_idx) + isense_idx++; + if (cb_idx != mpt_base_index) { MOD_DEC_USE_COUNT; } @@ -639,7 +803,8 @@ * @handle: Handle of registered MPT protocol driver * @iocid: IOC unique identifier (integer) * - * Returns pointer to a MPT request frame or %NULL if none are available. + * Returns pointer to a MPT request frame or %NULL if none are available + * or IOC is not active. */ MPT_FRAME_HDR* mpt_get_msg_frame(int handle, int iocid) @@ -650,6 +815,16 @@ /* validate handle and ioc identifier */ iocp = mpt_adapters[iocid]; + +#ifdef MFCNT + if (!iocp->active) + printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); +#endif + + /* If interrupts are not attached, do not return a request frame */ + if (!iocp->active) + return NULL; + spin_lock_irqsave(&iocp->FreeQlock, flags); if (! Q_IS_EMPTY(&iocp->FreeQ)) { int req_offset; @@ -662,8 +837,20 @@ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; +#ifdef MFCNT + iocp->mfcnt++; +#endif } spin_unlock_irqrestore(&iocp->FreeQlock, flags); + +#ifdef MFCNT + if (mf == NULL) + printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth); + mfcounter++; + if (mfcounter == PRINT_MF_COUNT) + printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth); +#endif + dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", iocp->name, handle, iocid, mf)); return mf; @@ -687,7 +874,7 @@ iocp = mpt_adapters[iocid]; if (iocp != NULL) { - dma_addr_t mf_dma_addr; + u32 mf_dma_addr; int req_offset; /* ensure values are reset properly! */ @@ -700,23 +887,23 @@ #ifdef MPT_DEBUG_MSG_FRAME { u32 *m = mf->u.frame.hwhdr.__hdr; - int i, n; + int ii, n; printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", iocp->name, m); n = iocp->req_sz/4 - 1; while (m[n] == 0) n--; - for (i=0; i<=n; i++) { - if (i && ((i%8)==0)) + for (ii=0; ii<=n; ii++) { + if (ii && ((ii%8)==0)) printk("\n" KERN_INFO " "); - printk(" %08x", le32_to_cpu(m[i])); + printk(" %08x", le32_to_cpu(m[ii])); } printk("\n"); } #endif - mf_dma_addr = iocp->req_frames_dma + req_offset; + mf_dma_addr = iocp->req_frames_low_dma + req_offset; CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); } } @@ -742,6 +929,9 @@ /* Put Request back on FreeQ! */ spin_lock_irqsave(&iocp->FreeQlock, flags); Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); +#ifdef MFCNT + iocp->mfcnt--; +#endif spin_unlock_irqrestore(&iocp->FreeQlock, flags); } } @@ -754,8 +944,9 @@ * @iocid: IOC unique identifier (integer) * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame + * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. * - * This routine is used exclusively by mptscsih to send MptScsiTaskMgmt + * This routine is used exclusively to send MptScsiTaskMgmt * requests since they are required to be sent via doorbell handshake. * * NOTE: It is the callers responsibility to byte-swap fields in the @@ -764,41 +955,30 @@ * Returns 0 for success, non-zero for failure. */ int -mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req) +mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag) { MPT_ADAPTER *iocp; int r = 0; iocp = mpt_adapters[iocid]; if (iocp != NULL) { - u8 *req_as_bytes; - u32 ioc_raw_state; - int i; - - /* YIKES! We already know something is amiss. - * Do upfront check on IOC state. - */ - ioc_raw_state = GetIocState(iocp, 0); - if ((ioc_raw_state & MPI_DOORBELL_ACTIVE) || - ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)) { - printk(KERN_WARNING MYNAM ": %s: Bad IOC state (%08x) WARNING!\n", - iocp->name, ioc_raw_state); - if ((r = mpt_do_ioc_recovery(iocp, MPT_HOSTEVENT_IOC_RECOVER)) != 0) { - printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", - r, iocp->name); - return r; - } - } + u8 *req_as_bytes; + int ii; + + /* State is known to be good upon entering + * this function so issue the bus reset + * request. + */ /* * Emulate what mpt_put_msg_frame() does /wrt to sanity * setting cb_idx/req_idx. But ONLY if this request * is in proper (pre-alloc'd) request buffer range... */ - i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); - if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) { + ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) { MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; - mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i); + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; } @@ -810,36 +990,40 @@ ((reqBytes/4)<chip->Doorbell) & MPI_DOORBELL_ACTIVE)) + return -5; + dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", - iocp->name, i)); + iocp->name, ii)); CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); - if ((r = WaitForDoorbellAck(iocp, 1)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { return -2; } /* Send request via doorbell handshake */ req_as_bytes = (u8 *) req; - for (i = 0; i < reqBytes/4; i++) { + for (ii = 0; ii < reqBytes/4; ii++) { u32 word; - word = ((req_as_bytes[(i*4) + 0] << 0) | - (req_as_bytes[(i*4) + 1] << 8) | - (req_as_bytes[(i*4) + 2] << 16) | - (req_as_bytes[(i*4) + 3] << 24)); + word = ((req_as_bytes[(ii*4) + 0] << 0) | + (req_as_bytes[(ii*4) + 1] << 8) | + (req_as_bytes[(ii*4) + 2] << 16) | + (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - if ((r = WaitForDoorbellAck(iocp, 1)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { r = -3; break; } } - if ((r = WaitForDoorbellInt(iocp, 2)) >= 0) + if ((r = WaitForDoorbellInt(iocp, 10, sleepFlag)) >= 0) r = 0; else r = -4; @@ -871,8 +1055,8 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_adapter_find_next - Find next MPT adapter pointer. - * @prev: Pointer to previous MPT adapter + * mpt_adapter_find_next - Find next MPT adapter pointer. + * @prev: Pointer to previous MPT adapter * * Returns next MPT adapter pointer or %NULL if there are no more. */ @@ -888,13 +1072,13 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * mpt_pci_scan - Scan PCI devices for MPT adapters. * * Returns count of MPT adapters found, keying off of PCI vendor and * device_id's. */ -int __init +static int __init mpt_pci_scan(void) { struct pci_dev *pdev; @@ -906,7 +1090,7 @@ dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n")); /* - * NOTE: The 929 (I believe) will appear as 2 separate PCI devices, + * NOTE: The 929 and 1030 will appear as 2 separate PCI devices, * one for each channel. */ pci_for_each_dev(pdev) { @@ -917,9 +1101,9 @@ if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) && + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) && #if 0 /* FIXME! C103x family */ - (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) && (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) && (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) && #endif @@ -929,7 +1113,7 @@ } /* GRRRRR - * 929 dual function devices may be presented in Func 1,0 order, + * dual function devices (929, 1030) may be presented in Func 1,0 order, * but we'd really really rather have them in Func 0,1 order. * Do some kind of look ahead here... */ @@ -937,11 +1121,11 @@ pdev2 = pci_peek_next_dev(pdev); if (pdev2 && (pdev2->vendor == 0x1000) && (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) && - (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && + (pdev2->device == pdev->device) && (pdev2->bus->number == pdev->bus->number) && !(pdev2->devfn & 1)) { dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n", - pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device)); + pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device)); found++; if ((r = mpt_adapter_install(pdev2)) == 0) count++; @@ -969,9 +1153,7 @@ } #ifdef CONFIG_PROC_FS - if (procmpt_create() != 0) - printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n", - MPT_PROCFS_MPTBASEDIR); + (void) procmpt_create(); #endif return count; @@ -1004,7 +1186,7 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * mpt_adapter_install - Install a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure * @@ -1030,7 +1212,7 @@ unsigned long port; u32 msize; u32 psize; - int i; + int ii; int r = -ENODEV; int len; @@ -1040,41 +1222,68 @@ return -ENOMEM; } memset(ioc, 0, sizeof(*ioc)); - ioc->req_sz = MPT_REQ_SIZE; /* avoid div by zero! */ ioc->alloc_total = sizeof(MPT_ADAPTER); + ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ + ioc->reply_sz = ioc->req_sz; ioc->pcidev = pdev; + ioc->diagPending = 0; + spin_lock_init(&ioc->diagLock); + + /* Initialize the event logging. + */ + ioc->eventTypes = 0; /* None */ + ioc->eventContext = 0; + ioc->eventLogSize = 0; + ioc->events = NULL; + +#ifdef MFCNT + ioc->mfcnt = 0; +#endif + + /* Initialize the FW and Data image pointers. + */ + ioc->FWImage = NULL; + ioc->FWImage_dma = 0; + + /* Initilize SCSI Config Data structure + */ + memset(&ioc->spi_data, 0, sizeof(ScsiCfgData)); + + /* Initialize the running configQ head. + */ + Q_INIT(&ioc->configQ, Q_ITEM); /* Find lookup slot. */ - for (i=0; i < MPT_MAX_ADAPTERS; i++) { - if (mpt_adapters[i] == NULL) { - ioc->id = i; /* Assign adapter unique id (lookup) */ + for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) { + if (mpt_adapters[ii] == NULL) { + ioc->id = ii; /* Assign adapter unique id (lookup) */ break; } } - if (i == MPT_MAX_ADAPTERS) { - printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i); + if (ii == MPT_MAX_ADAPTERS) { + printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii); kfree(ioc); return -ENFILE; } mem_phys = msize = 0; port = psize = 0; - for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { - if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) { + for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { + if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) { /* Get I/O space! */ - port = pdev->PCI_BASEADDR_START(i); - psize = PCI_BASEADDR_SIZE(pdev,i); + port = pdev->PCI_BASEADDR_START(ii); + psize = PCI_BASEADDR_SIZE(pdev,ii); } else { /* Get memmap */ - mem_phys = pdev->PCI_BASEADDR_START(i); - msize = PCI_BASEADDR_SIZE(pdev,i); + mem_phys = pdev->PCI_BASEADDR_START(ii); + msize = PCI_BASEADDR_SIZE(pdev,ii); break; } } ioc->mem_size = msize; - if (i == DEVICE_COUNT_RESOURCE) { + if (ii == DEVICE_COUNT_RESOURCE) { printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); kfree(ioc); return -EINVAL; @@ -1098,6 +1307,8 @@ } dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", + &ioc->facts, &ioc->pfacts[0])); if (PortIo) { u8 *pmem = (u8*)port; ioc->mem_phys = port; @@ -1107,6 +1318,13 @@ ioc->chip = (SYSIF_REGS*)mem; } + /* Save Port IO values incase we need to do downloadboot */ + { + u8 *pmem = (u8*)port; + ioc->pio_mem_phys = port; + ioc->pio_chip = (SYSIF_REGS*)pmem; + } + ioc->chip_type = FCUNK; if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { ioc->chip_type = FC909; @@ -1120,12 +1338,19 @@ ioc->chip_type = FC919; ioc->prod_name = "LSIFC919"; } -#if 0 - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) { + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; + { + /* 1030 Chip Fix. Disable Split transactions + * for PCIX. Set bits 4 - 6 to zero. + */ + u16 pcixcmd = 0; + pci_read_config_word(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0xFF8F; + pci_write_config_word(pdev, 0x6a, pcixcmd); + } } -#endif myname = "iocN"; len = strlen(myname); @@ -1145,8 +1370,13 @@ r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); if (r < 0) { - printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n", +#ifndef __sparc__ + printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n", ioc->name, pdev->irq); +#else + printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", + ioc->name, __irq_itoa(pdev->irq)); +#endif iounmap(mem); kfree(ioc); return -EBUSY; @@ -1156,7 +1386,11 @@ pci_set_master(pdev); /* ?? */ +#ifndef __sparc__ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); +#else + dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq))); +#endif } /* tack onto tail of our MPT adapter list */ @@ -1166,12 +1400,12 @@ mpt_adapters[ioc->id] = ioc; /* NEW! 20010220 -sralston - * Check for "929 bound ports" to reduce redundant resets. + * Check for "bound ports" (929, 1030) to reduce redundant resets. */ - if (ioc->chip_type == FC929) - mpt_detect_929_bound_ports(ioc, pdev); + if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)) + mpt_detect_bound_ports(ioc, pdev); - if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); } @@ -1180,10 +1414,11 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * mpt_do_ioc_recovery - Initialize or recover MPT adapter. * @ioc: Pointer to MPT adapter structure * @reason: Event word / reason + * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. * * This routine performs all the steps necessary to bring the IOC * to a OPERATIONAL state. @@ -1191,16 +1426,21 @@ * This routine also pre-fetches the LAN MAC address of a Fibre Channel * MPT adapter. * - * Returns 0 for success. + * Returns: + * 0 for success + * -1 if failed to get board READY + * -2 if READY but IOCFacts Failed + * -3 if READY but PrimeIOCFifos Failed + * -4 if READY but IOCInit Failed */ static int -mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason) +mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) { int hard_reset_done = 0; int alt_ioc_ready = 0; int hard; int r; - int i; + int ii; int handlers; printk(KERN_INFO MYNAM ": Initiating %s %s\n", @@ -1211,156 +1451,106 @@ ioc->active = 0; /* NOTE: Access to IOC's request FreeQ is now blocked! */ -// FIXME? Cleanup all IOC requests here! (or below?) -// But watch out for event associated request? + if (ioc->alt_ioc) { + /* Disable alt-IOC's reply interrupts for a bit ... */ + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); + ioc->alt_ioc->active = 0; + /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */ + } - hard = HardReset; - if (ioc->alt_ioc && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) + hard = 1; + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) hard = 0; - if ((hard_reset_done = MakeIocReady(ioc, hard)) < 0) { + if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", ioc->name); return -1; } -// NEW! -#if 0 // Kiss-of-death!?! - if (ioc->alt_ioc) { -// Grrr... Hold off any alt-IOC interrupts (and events) while -// handshaking to IOC, needed because? - /* Disable alt-IOC's reply interrupts for a bit ... */ - alt_ioc_intmask = CHIPREG_READ32(&ioc->alt_ioc->chip->IntMask); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); - ioc->alt_ioc->active = 0; - /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */ - } -#endif - + /* hard_reset_done = 0 if a soft reset was performed + * and 1 if a hard reset was performed. + */ if (hard_reset_done && ioc->alt_ioc) { - if ((r = MakeIocReady(ioc->alt_ioc, 0)) == 0) + if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else - printk(KERN_WARNING MYNAM ": alt-%s: (%d) Not ready WARNING!\n", + printk(KERN_WARNING MYNAM + ": alt-%s: (%d) Not ready WARNING!\n", ioc->alt_ioc->name, r); } + /* Get IOC facts! */ + if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) + return -2; if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { - /* Get IOC facts! */ - if ((r = GetIocFacts(ioc)) != 0) - return -2; MptDisplayIocCapabilities(ioc); } - /* - * Call each currently registered protocol IOC reset handler - * with pre-reset indication. - * NOTE: If we're doing _IOC_BRINGUP, there can be no - * MptResetHandlers[] registered yet. - */ - if (hard_reset_done) { - r = handlers = 0; - for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { - if (MptResetHandlers[i]) { - dprintk((KERN_INFO MYNAM ": %s: Calling IOC pre_reset handler #%d\n", - ioc->name, i)); - r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_PRE_RESET); - handlers++; - - if (alt_ioc_ready) { - dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC pre_reset handler #%d\n", - ioc->alt_ioc->name, i)); - r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_PRE_RESET); - handlers++; - } - } - } - /* FIXME? Examine results here? */ - } - - // May need to check/upload firmware & data here! - - if ((r = SendIocInit(ioc)) != 0) - return -3; -// NEW! if (alt_ioc_ready) { - if ((r = SendIocInit(ioc->alt_ioc)) != 0) { - alt_ioc_ready = 0; - printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", - ioc->alt_ioc->name, r); - } - } - - /* - * Call each currently registered protocol IOC reset handler - * with post-reset indication. - * NOTE: If we're doing _IOC_BRINGUP, there can be no - * MptResetHandlers[] registered yet. - */ - if (hard_reset_done) { - r = handlers = 0; - for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { - if (MptResetHandlers[i]) { - dprintk((KERN_INFO MYNAM ": %s: Calling IOC post_reset handler #%d\n", - ioc->name, i)); - r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_POST_RESET); - handlers++; - - if (alt_ioc_ready) { - dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC post_reset handler #%d\n", - ioc->alt_ioc->name, i)); - r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } - } + if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) + return -2; + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + MptDisplayIocCapabilities(ioc->alt_ioc); } - /* FIXME? Examine results here? */ } /* * Prime reply & request queues! - * (mucho alloc's) + * (mucho alloc's) Must be done prior to + * init as upper addresses are needed for init. */ if ((r = PrimeIocFifos(ioc)) != 0) + return -3; + + // May need to check/upload firmware & data here! + if ((r = SendIocInit(ioc, sleepFlag)) != 0) return -4; // NEW! if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, r); + alt_ioc_ready = 0; } -// FIXME! Cleanup all IOC (and alt-IOC?) requests here! + if (alt_ioc_ready) { + if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { + alt_ioc_ready = 0; + printk(KERN_WARNING MYNAM + ": alt-%s: (%d) init failure WARNING!\n", + ioc->alt_ioc->name, r); + } + } - if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && - (ioc->lan_cnfg_page0.Header.PageLength == 0)) { - /* - * Pre-fetch the ports LAN MAC address! - * (LANPage1_t stuff) - */ - (void) GetLanConfigPages(ioc); -#ifdef MPT_DEBUG - { - u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; - dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] )); + if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { + dprintk((MYIOC_s_INFO_FMT + "firmware upload required!\n", ioc->name)); + + r = mpt_do_upload(ioc, sleepFlag); + if (r != 0) + printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + /* Handle the alt IOC too */ + if (alt_ioc_ready){ + r = mpt_do_upload(ioc->alt_ioc, sleepFlag); + if (r != 0) + printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + } } -#endif } + /* Enable! (reply interrupt) */ CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); ioc->active = 1; -// NEW! -#if 0 // Kiss-of-death!?! - if (alt_ioc_ready && (r==0)) { + if (ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); ioc->alt_ioc->active = 1; } -#endif /* NEW! 20010120 -sralston * Enable MPT base driver management of EventNotification @@ -1368,19 +1558,95 @@ */ if (!ioc->facts.EventState) (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ -// NEW! -// FIXME!?! -// if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) { -// (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ -// } + + if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) + (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ + + /* (Bugzilla:fibrebugs, #513) + * Bug fix (part 2)! 20010905 -sralston + * Add additional "reason" check before call to GetLanConfigPages + * (combined with GetIoUnitPage2 call). This prevents a somewhat + * recursive scenario; GetLanConfigPages times out, timer expired + * routine calls HardResetHandler, which calls into here again, + * and we try GetLanConfigPages again... + */ + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + if ((int)ioc->chip_type <= (int)FC929) { + /* + * Pre-fetch FC port WWN and stuff... + * (FCPortPage0_t stuff) + */ + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { + (void) GetFcPortPage0(ioc, ii); + } + + if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && + (ioc->lan_cnfg_page0.Header.PageLength == 0)) { + /* + * Pre-fetch the ports LAN MAC address! + * (LANPage1_t stuff) + */ + (void) GetLanConfigPages(ioc); +#ifdef MPT_DEBUG + { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] )); + } +#endif + } + } else { + /* Get NVRAM and adapter maximums from SPP 0 and 2 + */ + mpt_GetScsiPortSettings(ioc, 0); + + /* Get version and length of SDP 1 + */ + mpt_readScsiDevicePageHeaders(ioc, 0); + + /* Find IM volumes + */ + if (ioc->facts.MsgVersion >= 0x0102) + mpt_findImVolumes(ioc); + } + + GetIoUnitPage2(ioc); + } + + /* + * Call each currently registered protocol IOC reset handler + * with post-reset indication. + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ + if (hard_reset_done) { + r = handlers = 0; + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + if (MptResetHandlers[ii]) { + dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", + ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); + handlers++; + + if (alt_ioc_ready) { + dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + handlers++; + } + } + } + /* FIXME? Examine results here? */ + } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mpt_detect_929_bound_ports - Search for PCI bus/dev_function - * which matches PCI bus/dev_function (+/-1) for newly discovered 929. + * mpt_detect_bound_ports - Search for PCI bus/dev_function + * which matches PCI bus/dev_function (+/-1) for newly discovered 929 + * or 1030. * @ioc: Pointer to MPT adapter structure * @pdev: Pointer to (struct pci_dev) structure * @@ -1388,22 +1654,22 @@ * using alt_ioc pointer fields in their %MPT_ADAPTER structures. */ static void -mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) +mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) { MPT_ADAPTER *ioc_srch = mpt_adapter_find_first(); unsigned int match_lo, match_hi; match_lo = pdev->devfn-1; match_hi = pdev->devfn+1; - dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n", + dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n", ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi)); while (ioc_srch != NULL) { struct pci_dev *_pcidev = ioc_srch->pcidev; - if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && - (_pcidev->bus->number == pdev->bus->number) && - (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) { + if ((_pcidev->device == pdev->device) && + (_pcidev->bus->number == pdev->bus->number) && + (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", @@ -1418,8 +1684,6 @@ ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; - ioc->sod_reset = ioc->alt_ioc->sod_reset; - ioc->last_kickstart = ioc->alt_ioc->last_kickstart; break; } ioc_srch = mpt_adapter_find_next(ioc_srch); @@ -1440,10 +1704,10 @@ u32 state; /* Disable the FW */ - state = GetIocState(this, 1); + state = mpt_GetIocState(this, 1); if (state == MPI_IOC_STATE_OPERATIONAL) { - if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) != 0) - (void) KickStart(this, 1); + if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0) + (void) KickStart(this, 1, NO_SLEEP); } /* Disable adapter interrupts! */ @@ -1475,12 +1739,37 @@ } if (freeup && this->sense_buf_pool != NULL) { - sz = (this->req_depth * 256); + sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC); pci_free_consistent(this->pcidev, sz, this->sense_buf_pool, this->sense_buf_pool_dma); this->sense_buf_pool = NULL; this->alloc_total -= sz; } + + if (freeup && this->events != NULL){ + sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + kfree(this->events); + this->events = NULL; + this->alloc_total -= sz; + } + + if (freeup && this->FWImage != NULL) { + sz = this->facts.FWImageSize; + pci_free_consistent(this->pcidev, sz, + this->FWImage, this->FWImage_dma); + this->FWImage = NULL; + this->alloc_total -= sz; + } + + if (freeup && this->spi_data.nvram != NULL) { + kfree(this->spi_data.nvram); + this->spi_data.nvram = NULL; + } + + if (freeup && this->spi_data.pIocPg3 != NULL) { + kfree(this->spi_data.pIocPg3); + this->spi_data.pIocPg3 = NULL; + } } } @@ -1575,23 +1864,30 @@ /* * MakeIocReady - Get IOC to a READY state, using KickStart if needed. * @ioc: Pointer to MPT_ADAPTER structure - * @kick: Force hard KickStart of IOC + * @force: Force hard KickStart of IOC + * @sleepFlag: Specifies whether the process can sleep * - * Returns 0 for already-READY, 1 for hard reset success, - * else negative for failure. + * Returns: + * 1 - DIAG reset and READY + * 0 - READY initially OR soft reset and READY + * -1 - Any failure on KickStart + * -2 - Msg Unit Reset Failed + * -3 - IO Unit Reset Failed + * -4 - IOC owned by a PEER */ static int -MakeIocReady(MPT_ADAPTER *ioc, int force) +MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) { u32 ioc_state; int statefault = 0; - int cntdn; + int cntdn; int hard_reset_done = 0; int r; - int i; + int ii; + int whoinit; /* Get current [raw] IOC state */ - ioc_state = GetIocState(ioc, 0); + ioc_state = mpt_GetIocState(ioc, 0); dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state)); /* @@ -1600,7 +1896,7 @@ */ if (ioc_state & MPI_DOORBELL_ACTIVE) { statefault = 1; - printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n", + printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n", ioc->name); } @@ -1613,7 +1909,7 @@ */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { statefault = 2; - printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n", + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", ioc->name); printk(KERN_WARNING " FAULT code = %04xh\n", ioc_state & MPI_DOORBELL_DATA_MASK); @@ -1623,28 +1919,49 @@ * Hmmm... Did it get left operational? */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { - statefault = 3; - dprintk((KERN_WARNING MYNAM ": %s: Hmmm... IOC operational unexpected\n", + dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n", ioc->name)); + + /* Check WhoInit. + * If PCI Peer, exit. + * Else, if no fault conditions are present, issue a MessageUnitReset + * Else, fall through to KickStart case + */ + whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; + dprintk((KERN_WARNING MYNAM + ": whoinit 0x%x\n statefault %d force %d\n", + whoinit, statefault, force)); + if (whoinit == MPI_WHOINIT_PCI_PEER) + return -4; + else { + if ((statefault == 0 ) && (force == 0)) { + if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) + return 0; + } + statefault = 3; + } } - hard_reset_done = KickStart(ioc, statefault||force); + hard_reset_done = KickStart(ioc, statefault||force, sleepFlag); if (hard_reset_done < 0) return -1; /* * Loop here waiting for IOC to come READY. */ - i = 0; + ii = 0; cntdn = HZ * 15; - while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { + if (sleepFlag != CAN_SLEEP) + cntdn *= 10; /* 1500 iterations @ 1msec per */ + + while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { /* * BIOS or previous driver load left IOC in OP state. * Reset messaging FIFOs. */ - if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) { - printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) { + printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name); return -2; } } else if (ioc_state == MPI_IOC_STATE_RESET) { @@ -1652,25 +1969,30 @@ * Something is wrong. Try to get IOC back * to a known state. */ - if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) { - printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) { + printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name); return -3; } } - i++; cntdn--; + ii++; cntdn--; if (!cntdn) { - printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", - ioc->name, (i+5)/HZ); + printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", + ioc->name, (ii+5)/HZ); return -ETIME; } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } else { + mdelay (1); /* 1 msec delay */ + } + } if (statefault < 3) { - printk(KERN_WARNING MYNAM ": %s: Whew! Recovered from %s\n", + printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT"); } @@ -1680,21 +2002,21 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * GetIocState - Get the current state of a MPT adapter. + * mpt_GetIocState - Get the current state of a MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @cooked: Request raw or cooked IOC state * * Returns all IOC Doorbell register bits if cooked==0, else just the * Doorbell bits in MPI_IOC_STATE_MASK. */ -static u32 -GetIocState(MPT_ADAPTER *ioc, int cooked) +u32 +mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) { u32 s, sc; /* Get! */ s = CHIPREG_READ32(&ioc->chip->Doorbell); - dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s)); +// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s)); sc = s & MPI_IOC_STATE_MASK; /* Save! */ @@ -1707,11 +2029,13 @@ /* * GetIocFacts - Send IOCFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Specifies whether the process can sleep + * @reason: If recovery, only update facts. * * Returns 0 for success, non-zero for failure. */ static int -GetIocFacts(MPT_ADAPTER *ioc) +GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) { IOCFacts_t get_facts; IOCFactsReply_t *facts; @@ -1741,14 +2065,13 @@ get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dprintk((KERN_INFO MYNAM ": %s: Sending get IocFacts request\n", ioc->name)); + dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); /* No non-zero fields in the get_facts request are greater than * 1 byte in size, so we can just fire it off as is. */ - r = HandShakeReqAndReply(ioc, - req_sz, (u32*)&get_facts, - reply_sz, (u16*)facts, 3); + r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, + reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag); if (r != 0) return r; @@ -1761,14 +2084,17 @@ */ /* Did we get a valid reply? */ if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { - /* - * If not been here, done that, save off first WhoInit value - */ - if (ioc->FirstWhoInit == WHOINIT_UNKNOWN) - ioc->FirstWhoInit = facts->WhoInit; + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + /* + * If not been here, done that, save off first WhoInit value + */ + if (ioc->FirstWhoInit == WHOINIT_UNKNOWN) + ioc->FirstWhoInit = facts->WhoInit; + } facts->MsgVersion = le16_to_cpu(facts->MsgVersion); facts->MsgContext = le32_to_cpu(facts->MsgContext); + facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); facts->IOCStatus = le16_to_cpu(facts->IOCStatus); facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); status = facts->IOCStatus & MPI_IOCSTATUS_MASK; @@ -1776,7 +2102,23 @@ facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); - facts->FWVersion = le16_to_cpu(facts->FWVersion); + + /* + * FC f/w version changed between 1.1 and 1.2 + * Old: u16{Major(4),Minor(4),SubMinor(8)} + * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} + */ + if (facts->MsgVersion < 0x0102) { + /* + * Handle old FC f/w style, convert to new... + */ + u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion); + facts->FWVersion.Word = + ((oldv<<12) & 0xFF000000) | + ((oldv<<8) & 0x000FFF00); + } else + facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); + facts->ProductID = le16_to_cpu(facts->ProductID); facts->CurrentHostMfaHighAddr = le32_to_cpu(facts->CurrentHostMfaHighAddr); @@ -1791,52 +2133,42 @@ * Older MPI-1.00.xx struct had 13 dwords, and enlarged * to 14 in MPI-1.01.0x. */ - if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) { + if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && + facts->MsgVersion > 0x0100) { facts->FWImageSize = le32_to_cpu(facts->FWImageSize); - facts->DataImageSize = le32_to_cpu(facts->DataImageSize); } - if (facts->RequestFrameSize) { - /* - * Set values for this IOC's REQUEST queue size & depth... - */ - ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4); - - /* - * Set values for this IOC's REPLY queue size & depth... - * - * BUG? FIX? 20000516 -nromer & sralston - * GRRR... The following did not translate well from MPI v0.09: - * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4); - * to 0.10: - * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4); - * Was trying to minimally optimize to smallest possible reply size - * (and greatly reduce kmalloc size). But LAN may need larger reply? - * - * So for now, just set reply size to request size. FIXME? - */ - ioc->reply_sz = ioc->req_sz; - } else { + if (!facts->RequestFrameSize) { /* Something is wrong! */ - printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n", + printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", ioc->name); - ioc->req_sz = MPT_REQ_SIZE; - ioc->reply_sz = MPT_REPLY_SIZE; return -55; } - ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits); - ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth); - dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n", + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + /* + * Set values for this IOC's request & reply frame sizes, + * and request & reply queue depths... + */ + ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); + ioc->req_depth = MIN(MPT_DEFAULT_REQ_DEPTH, facts->GlobalCredits); + ioc->reply_sz = ioc->req_sz; + ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); + + /* 1030 - should we use a smaller DEFAULT_REPLY_DEPTH? + * FIX + */ + dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dprintk((KERN_INFO MYNAM ": %s: req_sz =%3d, req_depth =%4d\n", + dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", ioc->name, ioc->req_sz, ioc->req_depth)); - /* Get port facts! */ - if ( (r = GetPortFacts(ioc, 0)) != 0 ) - return r; + /* Get port facts! */ + if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 ) + return r; + } } else { - printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n", + printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n", ioc->name); return -66; } @@ -1849,15 +2181,16 @@ * GetPortFacts - Send PortFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number + * @sleepFlag: Specifies whether the process can sleep * * Returns 0 for success, non-zero for failure. */ static int -GetPortFacts(MPT_ADAPTER *ioc, int portnum) +GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { PortFacts_t get_pfacts; PortFactsReply_t *pfacts; - int i; + int ii; int req_sz; int reply_sz; @@ -1883,16 +2216,16 @@ get_pfacts.PortNumber = portnum; /* Assert: All other get_pfacts fields are zero! */ - dprintk((KERN_INFO MYNAM ": %s: Sending get PortFacts(%d) request\n", + dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", ioc->name, portnum)); /* No non-zero fields in the get_pfacts request are greater than * 1 byte in size, so we can just fire it off as is. */ - i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts, - reply_sz, (u16*)pfacts, 3); - if (i != 0) - return i; + ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, + reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag); + if (ii != 0) + return ii; /* Did we get a valid reply? */ @@ -1914,13 +2247,14 @@ /* * SendIocInit - Send IOCInit request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Specifies whether the process can sleep * * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. * * Returns 0 for success, non-zero for failure. */ static int -SendIocInit(MPT_ADAPTER *ioc) +SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) { IOCInit_t ioc_init; MPIDefaultReply_t init_reply; @@ -1937,20 +2271,35 @@ ioc_init.Function = MPI_FUNCTION_IOC_INIT; /* ioc_init.Flags = 0; */ - /*ioc_init.MaxDevices = 16;*/ - ioc_init.MaxDevices = 255; -/* ioc_init.MaxBuses = 16; */ - ioc_init.MaxBuses = 1; + if ((int)ioc->chip_type <= (int)FC929) { + ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; + } + else { + ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES; + } + ioc_init.MaxBuses = MPT_MAX_BUS; /* ioc_init.MsgFlags = 0; */ /* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - ioc_init.HostMfaHighAddr = cpu_to_le32(0); /* Say we 32-bit! for now */ - dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); +#ifdef __ia64__ + /* Save the upper 32-bits of the request + * (reply) and sense buffers. + */ + ioc_init.HostMfaHighAddr = cpu_to_le32((u32)(ioc->req_frames_dma >> 32)); + ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)(ioc->sense_buf_pool_dma >> 32)); +#else + /* Force 32-bit addressing */ + ioc_init.HostMfaHighAddr = cpu_to_le32(0); + ioc_init.SenseBufferHighAddr = cpu_to_le32(0); +#endif - r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, - sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10); + dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", + ioc->name, &ioc_init)); + + r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, + sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); if (r != 0) return r; @@ -1958,7 +2307,7 @@ * since we don't even look at it's contents. */ - if ((r = SendPortEnable(ioc, 0)) != 0) + if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) return r; /* YIKES! SUPER IMPORTANT!!! @@ -1967,21 +2316,27 @@ */ count = 0; cntdn = HZ * 60; /* chg'd from 30 to 60 seconds */ - state = GetIocState(ioc, 1); + if (sleepFlag != CAN_SLEEP) + cntdn *= 10; /* scale for 1msec delays */ + state = mpt_GetIocState(ioc, 1); while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } else { + mdelay(1); + } if (!cntdn) { - printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n", + printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", ioc->name, (count+5)/HZ); return -9; } - state = GetIocState(ioc, 1); + state = mpt_GetIocState(ioc, 1); count++; } - dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", ioc->name, count)); return r; @@ -1992,17 +2347,18 @@ * SendPortEnable - Send PortEnable request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number to enable + * @sleepFlag: Specifies whether the process can sleep * * Send PortEnable to bring IOC to OPERATIONAL state. * * Returns 0 for success, non-zero for failure. */ static int -SendPortEnable(MPT_ADAPTER *ioc, int portnum) +SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { PortEnable_t port_enable; MPIDefaultReply_t reply_buf; - int i; + int ii; int req_sz; int reply_sz; @@ -2019,13 +2375,21 @@ /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n", + dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); - i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable, - reply_sz, (u16*)&reply_buf, 65); - if (i != 0) - return i; + /* RAID FW may take a long time to enable + */ + if ((int)ioc->chip_type <= (int)FC929) { + ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, + reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag); + } else { + ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, + reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag); + } + + if (ii != 0) + return ii; /* We do not even look at the reply, so we need not * swap the multi-byte fields. @@ -2036,19 +2400,341 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Specifies whether the process can sleep + * + * Returns 0 for success, >0 for handshake failure + * <0 for fw upload failure. + * + * Remark: If bound IOC and a successful FWUpload was performed + * on the bound IOC, the second image is discarded + * and memory is free'd. Both channels must upload to prevent + * IOC from running in degraded mode. + */ +static int +mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) +{ + u8 request[sizeof(FWUpload_t) + 24]; + u8 reply[sizeof(FWUploadReply_t)]; + FWUpload_t *prequest; + FWUploadReply_t *preply; + FWUploadTCSGE_t *ptcsge = NULL; + MptSge_t *psge; + u8 *mem; + dma_addr_t dma_addr; + int sgeoffset; + int i, sz, req_sz, reply_sz; + int cmdStatus, freeMem = 0; + + /* If the image size is 0 or if the pointer is + * not NULL (error), we are done. + */ + if (((sz = ioc->facts.FWImageSize) == 0) || ioc->FWImage) + return 0; + + /* Allocate memory + */ + mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->FWImage_dma); + if (mem == NULL) + return -1; + + memset(mem, 0, sz); + ioc->alloc_total += sz; + ioc->FWImage = mem; + dprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d bytes\n", + mem, (void *)(ulong)ioc->FWImage_dma, sz)); + + dma_addr = ioc->FWImage_dma; + + prequest = (FWUpload_t *)&request; + preply = (FWUploadReply_t *)&reply; + + /* Destination... */ + req_sz = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + + sizeof(FWUploadTCSGE_t) + sizeof(MptSge_t); + memset(prequest, 0, req_sz); + + reply_sz = sizeof(reply); + memset(preply, 0, reply_sz); + + prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; + prequest->Function = MPI_FUNCTION_FW_UPLOAD; + prequest->MsgContext = 0; /* anything */ + + ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; + ptcsge->Reserved = 0; + ptcsge->ContextSize = 0; + ptcsge->DetailsLength = 12; + ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; + ptcsge->Reserved1 = 0; + ptcsge->ImageOffset = 0; + ptcsge->ImageSize = cpu_to_le32(sz); + + sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); + psge = (MptSge_t *) &request[sgeoffset]; + psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | (u32) sz); + + cpu_to_leXX(dma_addr, psge->Address); + + dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p)\n", + ioc->name, prequest)); + + i = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)prequest, + reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + + cmdStatus = -EFAULT; + if (i == 0) { + /* Handshake transfer was complete and successful. + * Check the Reply Frame. + */ + int status, transfer_sz; + status = le16_to_cpu(preply->IOCStatus); + if (status == MPI_IOCSTATUS_SUCCESS) { + transfer_sz = le32_to_cpu(preply->ActualImageSize); + if (transfer_sz == sz) + cmdStatus = 0; + } + } + dprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", + ioc->name, cmdStatus)); + + /* Check to see if we have a copy of this image in + * host memory already. + */ + if (cmdStatus == 0) { + if (ioc->alt_ioc && ioc->alt_ioc->FWImage) + freeMem = 1; + } + + /* We already have a copy of this image or + * we had some type of an error - either the handshake + * failed (i != 0) or the command did not complete successfully. + */ + if (cmdStatus || freeMem) { + dprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n", + ioc->name, cmdStatus ? "incomplete" : "duplicate")); + + pci_free_consistent(ioc->pcidev, sz, + ioc->FWImage, ioc->FWImage_dma); + ioc->FWImage = NULL; + ioc->alloc_total -= sz; + } + + return cmdStatus; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_downloadboot - DownloadBoot code + * @ioc: Pointer to MPT_ADAPTER structure + * @flag: Specify which part of IOC memory is to be uploaded. + * @sleepFlag: Specifies whether the process can sleep + * + * FwDownloadBoot requires Programmed IO access. + * + * Returns 0 for success + * -1 FW Image size is 0 + * -2 No valid FWImage Pointer + * <0 for fw upload failure. + */ +static int +mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) +{ + MpiFwHeader_t *FwHdr = NULL; + MpiExtImageHeader_t *ExtHdr; + int fw_sz; + u32 diag0val; +#ifdef MPT_DEBUG + u32 diag1val = 0; +#endif + int count = 0; + u32 *ptru32 = NULL; + u32 diagRwData; + u32 nextImage; + + dprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n", + ioc->name)); +#ifdef MPT_DEBUG + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); +#endif + + dprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n", + ioc->name, ioc->facts.FWImageSize, ioc->FWImage)); + if (ioc->alt_ioc) + dprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n", + ioc->name, ioc->alt_ioc->FWImage)); + + /* Get dma_addr and data transfer size. + */ + if ((fw_sz = ioc->facts.FWImageSize) == 0) + return -1; + + /* Get the DMA from ioc or ioc->alt_ioc */ + if (ioc->FWImage) + FwHdr = (MpiFwHeader_t *)ioc->FWImage; + else if (ioc->alt_ioc && ioc->alt_ioc->FWImage) + FwHdr = (MpiFwHeader_t *)ioc->alt_ioc->FWImage; + + dprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n", + ioc->name, FwHdr)); + + if (!FwHdr) + return -2; + + /* Write magic sequence to WriteSequence register + * until enter diagnostic mode + */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + while ((diag0val & MPI_DIAG_DRWE) == 0) { + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + + /* wait 100 msec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } else { + mdelay (100); + } + + count++; + if (count > 20) { + printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", + ioc->name, diag0val); + return -EFAULT; + + } + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +#ifdef MPT_DEBUG + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); +#endif + dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n", + ioc->name, diag0val)); + } + + /* Set the DiagRwEn and Disable ARM bits */ + diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + +#ifdef MPT_DEBUG + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); +#endif + + /* Write the LoadStartAddress to the DiagRw Address Register + * using Programmed IO + */ + + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress); + dprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n", + ioc->name, FwHdr->LoadStartAddress)); + + nextImage = FwHdr->NextImageHeaderOffset; + + /* round up count to a 32bit alignment */ + ptru32 = (u32 *) FwHdr; + count = (FwHdr->ImageSize + 3)/4; + + dprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n", + ioc->name, count, ptru32)); + while (count-- ) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); + ptru32++; + } + + dprintk((MYIOC_s_INFO_FMT "FW Image done! \n", ioc->name)); + + while (nextImage) { + + /* Set the pointer to the extended image + */ + ExtHdr = (MpiExtImageHeader_t *) ((char *) FwHdr + nextImage); + + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, ExtHdr->LoadStartAddress); + + count = (ExtHdr->ImageSize + 3 )/4; + + ptru32 = (u32 *) ExtHdr; + dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n", + ioc->name, count, ptru32)); + while (count-- ) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); + ptru32++; + } + nextImage = ExtHdr->NextImageHeaderOffset; + } + + + /* Write the IopResetVectorRegAddr */ + dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr); + + /* Write the IopResetVectorValue */ + dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue); + + /* Clear the internal flash bad bit - autoincrementing register, + * so must do two writes. + */ + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); + diagRwData |= 0x4000000; + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + + /* clear the RW enable and DISARM bits */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + + /* Write 0xFF to reset the sequencer */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* * KickStart - Perform hard reset of MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @force: Force hard reset + * @sleepFlag: Specifies whether the process can sleep * * This routine places MPT adapter in diagnostic mode via the * WriteSequence register, and then performs a hard reset of adapter * via the Diagnostic register. * - * Returns 0 for soft reset success, 1 for hard reset success, - * else a negative value for failure. + * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread) + * or NO_SLEEP (interrupt thread, use mdelay) + * force - 1 if doorbell active, board fault state + * board operational, IOC_RECOVERY or + * IOC_BRINGUP and there is an alt_ioc. + * 0 else + * + * Returns: + * 1 - hard reset, READY + * 0 - no reset due to History bit, READY + * -1 - no reset due to History bit but not READY + * OR reset but failed to come READY + * -2 - no reset, could not enter DIAG mode + * -3 - reset but bad FW bit */ static int -KickStart(MPT_ADAPTER *ioc, int force) +KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) { int hard_reset_done = 0; u32 ioc_state; @@ -2056,183 +2742,295 @@ dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); - hard_reset_done = mpt_fc9x9_reset(ioc, force); -#if 0 - if (ioc->chip_type == FC909 || ioc->chip-type == FC919) { - hard_reset_done = mpt_fc9x9_reset(ioc, force); - } else if (ioc->chip_type == FC929) { - unsigned long delta; - - delta = jiffies - ioc->last_kickstart; - dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n", - ioc->name, ioc->last_kickstart, delta)); - if ((ioc->sod_reset == 0) || (delta >= 10*HZ)) - hard_reset_done = mpt_fc9x9_reset(ioc, ignore); - else { - dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n", - ioc->name, delta)); - return 0; - } - /* TODO! Add C1030! - } else if (ioc->chip_type == C1030) { - */ - } else { - printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n", - ioc->name, ioc->chip_type); - return -5; - } -#endif - + hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag); if (hard_reset_done < 0) return hard_reset_done; - dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n", + dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", ioc->name)); for (cnt=0; cntname, cnt)); return hard_reset_done; } - /* udelay(10000) ? */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } else { + mdelay (10); + } } - printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n", + printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n", ioc->name); return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter. + * mpt_diag_reset - Perform hard reset of the adapter. * @ioc: Pointer to MPT_ADAPTER structure - * - * This routine places FC9x9 adapter in diagnostic mode via the - * WriteSequence register, and then performs a hard reset of adapter - * via the Diagnostic register. - * - * Returns 0 for success, non-zero for failure. + * @ignore: Set if to honor and clear to ignore + * the reset history bit + * @sleepflag: CAN_SLEEP if called in a non-interrupt thread, + * else set to NO_SLEEP (use mdelay instead) + * + * This routine places the adapter in diagnostic mode via the + * WriteSequence register and then performs a hard reset of adapter + * via the Diagnostic register. Adapter should be in ready state + * upon successful completion. + * + * Returns: 1 hard reset successful + * 0 no reset performed because reset history bit set + * -2 enabling diagnostic mode failed + * -3 diagnostic reset failed */ static int -mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore) +mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) { u32 diag0val; + u32 doorbell; int hard_reset_done = 0; + int count = 0; +#ifdef MPT_DEBUG + u32 diag1val = 0; +#endif - /* Use "Diagnostic reset" method! (only thing available!) */ + /* Clear any existing interrupts */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + /* Use "Diagnostic reset" method! (only thing available!) */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + #ifdef MPT_DEBUG -{ - u32 diag1val = 0; if (ioc->alt_ioc) diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((KERN_INFO MYNAM ": %s: DBG1: diag0=%08x, diag1=%08x\n", + dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); -} #endif - if (diag0val & MPI_DIAG_DRWE) { - dprintk((KERN_INFO MYNAM ": %s: DiagWriteEn bit already set\n", - ioc->name)); - } else { - /* Write magic sequence to WriteSequence register */ - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#1]\n", - ioc->name)); - } - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + /* Do the reset if we are told to ignore the reset history + * or if the reset history is 0 + */ + if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) { + while ((diag0val & MPI_DIAG_DRWE) == 0) { + /* Write magic sequence to WriteSequence register + * Loop until in diagnostic mode + */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + + /* wait 100 msec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } else { + mdelay (100); + } + + count++; + if (count > 20) { + printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", + ioc->name, diag0val); + return -2; + + } + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + + dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n", + ioc->name, diag0val)); + } + #ifdef MPT_DEBUG -{ - u32 diag1val = 0; - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((KERN_INFO MYNAM ": %s: DbG2: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -} + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); #endif - if (!ignore && (diag0val & MPI_DIAG_RESET_HISTORY)) { - dprintk((KERN_INFO MYNAM ": %s: Skipping due to ResetHistory bit set!\n", - ioc->name)); - } else { + /* Write the PreventIocBoot bit */ + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { + diag0val |= MPI_DIAG_PREVENT_IOC_BOOT; + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + } + + /* + * Disable the ARM (Bug fix) + * + */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); + mdelay (1); + /* * Now hit the reset bit in the Diagnostic register - * (THE BIG HAMMER!) + * (THE BIG HAMMER!) (Clears DRWE bit). */ - CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); hard_reset_done = 1; - dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset performed\n", + dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n", ioc->name)); - /* want udelay(100) */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + /* + * Call each currently registered protocol IOC reset handler + * with pre-reset indication. + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ + { + int ii; + int r = 0; + + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + if (MptResetHandlers[ii]) { + dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n", + ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET); + if (ioc->alt_ioc) { + dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET); + } + } + } + /* FIXME? Examine results here? */ + } + + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { + /* If the DownloadBoot operation fails, the + * IOC will be left unusable. This is a fatal error + * case. _diag_reset will return < 0 + */ + for (count = 0; count < 30; count ++) { + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +#ifdef MPT_DEBUG + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT + "DbG2b: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); +#endif + if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { + break; + } + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } else { + mdelay (1000); + } + } + if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) { + printk(KERN_WARNING MYNAM + ": firmware downloadboot failure (%d)!\n", count); + } + + } else { + /* Wait for FW to reload and for board + * to go to the READY state. + * Maximum wait is 30 seconds. + * If fail, no error will check again + * with calling program. + */ + for (count = 0; count < 30; count ++) { + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; + + if (doorbell == MPI_IOC_STATE_READY) { + break; + } + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } else { + mdelay (1000); + } + } + } + } - /* Write magic sequence to WriteSequence register */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +#ifdef MPT_DEBUG + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); +#endif + + /* Clear RESET_HISTORY bit! Place board in the + * diagnostic mode to update the diag register. + */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + count = 0; + while ((diag0val & MPI_DIAG_DRWE) == 0) { + /* Write magic sequence to WriteSequence register + * Loop until in diagnostic mode + */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#2]\n", - ioc->name)); - } - /* Clear RESET_HISTORY bit! */ - CHIPREG_WRITE32(&ioc->chip->Diagnostic, 0x0); + /* wait 100 msec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } else { + mdelay (100); + } + count++; + if (count > 20) { + printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", + ioc->name, diag0val); + break; + } + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + } + diag0val &= ~MPI_DIAG_RESET_HISTORY; + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG -{ - u32 diag1val = 0; - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((KERN_INFO MYNAM ": %s: DbG3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -} -#endif if (diag0val & MPI_DIAG_RESET_HISTORY) { - printk(KERN_WARNING MYNAM ": %s: WARNING - ResetHistory bit failed to clear!\n", + printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n", ioc->name); } + /* Disable Diagnostic Mode + */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF); + + /* Check FW reload status flags. + */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) { + printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n", + ioc->name, diag0val); + return -3; + } + #ifdef MPT_DEBUG -{ - u32 diag1val = 0; if (ioc->alt_ioc) diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((KERN_INFO MYNAM ": %s: DbG4: diag0=%08x, diag1=%08x\n", + dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); -} #endif - if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) { - printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED! (%02xh)\n", - ioc->name, diag0val); - return -3; - } /* * Reset flag that says we've enabled event notification */ ioc->facts.EventState = 0; - /* NEW! 20010220 -sralston - * Try to avoid redundant resets of the 929. - */ - ioc->sod_reset++; - ioc->last_kickstart = jiffies; - if (ioc->alt_ioc) { - ioc->alt_ioc->sod_reset = ioc->sod_reset; - ioc->alt_ioc->last_kickstart = ioc->last_kickstart; - } + if (ioc->alt_ioc) + ioc->alt_ioc->facts.EventState = 0; return hard_reset_done; } @@ -2249,16 +3047,45 @@ * Returns 0 for success, non-zero for failure. */ static int -SendIocReset(MPT_ADAPTER *ioc, u8 reset_type) +SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) { int r; + u32 state; + int cntdn, count; dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<name, (count+5)/HZ); + return -ETIME; + } + + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } else { + mdelay (1); /* 1 msec delay */ + } + } + /* TODO! * Cleanup all event stuff for this IOC; re-issue EventNotification * request if needed. @@ -2275,7 +3102,8 @@ * @ioc: Pointer to MPT_ADAPTER structure * * This routine allocates memory for the MPT reply and request frame - * pools, and primes the IOC reply FIFO with reply frames. + * pools (if necessary), and primes the IOC reply FIFO with + * reply frames. * * Returns 0 for success, non-zero for failure. */ @@ -2284,6 +3112,7 @@ { MPT_FRAME_HDR *mf; unsigned long b; + unsigned long flags; dma_addr_t aligned_mem_dma; u8 *mem, *aligned_mem; int i, sz; @@ -2299,8 +3128,8 @@ memset(mem, 0, sz); ioc->alloc_total += sz; ioc->reply_alloc = mem; - dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%08x], sz=%d bytes\n", - ioc->name, mem, ioc->reply_alloc_dma, sz)); + dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n", + ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz)); b = (unsigned long) mem; b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ @@ -2308,15 +3137,20 @@ ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; ioc->reply_frames_dma = (ioc->reply_alloc_dma + (aligned_mem - mem)); - aligned_mem_dma = ioc->reply_frames_dma; - dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n", - ioc->name, aligned_mem, aligned_mem_dma)); - - for (i = 0; i < ioc->reply_depth; i++) { - /* Write each address to the IOC! */ - CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); - aligned_mem_dma += ioc->reply_sz; - } + + ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF); + } + + /* Post Reply frames to FIFO + */ + aligned_mem_dma = ioc->reply_frames_dma; + dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); + aligned_mem_dma += ioc->reply_sz; } @@ -2336,8 +3170,8 @@ memset(mem, 0, sz); ioc->alloc_total += sz; ioc->req_alloc = mem; - dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%08x], sz=%d bytes\n", - ioc->name, mem, ioc->req_alloc_dma, sz)); + dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n", + ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz)); b = (unsigned long) mem; b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ @@ -2345,18 +3179,18 @@ ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; ioc->req_frames_dma = (ioc->req_alloc_dma + (aligned_mem - mem)); - aligned_mem_dma = ioc->req_frames_dma; - dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%08x]\n", - ioc->name, aligned_mem, aligned_mem_dma)); + ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF); - for (i = 0; i < ioc->req_depth; i++) { - mf = (MPT_FRAME_HDR *) aligned_mem; - - /* Queue REQUESTs *internally*! */ - Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); - aligned_mem += ioc->req_sz; +#ifdef __ia64__ + /* Check: upper 32-bits of the request and reply frame + * physical addresses must be the same. + * ia64 check only + */ + if ((ioc->req_frames_dma >> 32) != (ioc->reply_frames_dma >> 32)){ + goto out_fail; } +#endif #if defined(CONFIG_MTRR) && 0 /* @@ -2367,20 +3201,38 @@ ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma, sz, MTRR_TYPE_WRCOMB, 1); - dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n", - ioc->name, ioc->req_alloc_dma, - sz )); + dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n", + ioc->name, ioc->req_alloc_dma, sz)); #endif + } + + /* Initialize Request frames linked list + */ + aligned_mem_dma = ioc->req_frames_dma; + aligned_mem = (u8 *) ioc->req_frames; + dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n", + ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) aligned_mem; + + /* Queue REQUESTs *internally*! */ + Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + aligned_mem += ioc->req_sz; } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + if (ioc->sense_buf_pool == NULL) { - sz = (ioc->req_depth * 256); + sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); ioc->sense_buf_pool = pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); if (ioc->sense_buf_pool == NULL) goto out_fail; + ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; } @@ -2408,7 +3260,7 @@ #if defined(CONFIG_MTRR) && 0 if (ioc->mtrr_reg > 0) { mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", + dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name)); } #endif @@ -2417,7 +3269,7 @@ ioc->alloc_total -= sz; } if (ioc->sense_buf_pool != NULL) { - sz = (ioc->req_depth * 256); + sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); pci_free_consistent(ioc->pcidev, sz, ioc->sense_buf_pool, ioc->sense_buf_pool_dma); @@ -2427,8 +3279,8 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * HandShakeReqAndReply - Send MPT request to and receive reply from +/** + * mpt_handshake_req_reply_wait - Send MPT request to and receive reply from * IOC via doorbell handshake method. * @ioc: Pointer to MPT_ADAPTER structure * @reqBytes: Size of the request in bytes @@ -2436,6 +3288,7 @@ * @replyBytes: Expected size of the reply in bytes * @u16reply: Pointer to area where reply should be written * @maxwait: Max wait time for a reply (in seconds) + * @sleepFlag: Specifies whether the process can sleep * * NOTES: It is the callers responsibility to byte-swap fields in the * request which are greater than 1 byte in size. It is also the @@ -2444,8 +3297,9 @@ * * Returns 0 for success, non-zero for failure. */ -static int -HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait) +int +mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, + int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) { MPIDefaultReply_t *mptReply; int failcnt = 0; @@ -2471,57 +3325,61 @@ /* * Wait for IOC's doorbell handshake int */ - if ((t = WaitForDoorbellInt(ioc, 2)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; - dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n", + dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + /* Read doorbell and check for active bit */ + if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) + return -1; + /* * Clear doorbell int (WRITE 0 to IntStatus reg), * then wait for IOC to ACKnowledge that it's ready for * our handshake request. */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if (!failcnt && (t = WaitForDoorbellAck(ioc, 2)) < 0) + if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) failcnt++; if (!failcnt) { - int i; + int ii; u8 *req_as_bytes = (u8 *) req; /* * Stuff request words via doorbell handshake, * with ACK from IOC for each. */ - for (i = 0; !failcnt && i < reqBytes/4; i++) { - u32 word = ((req_as_bytes[(i*4) + 0] << 0) | - (req_as_bytes[(i*4) + 1] << 8) | - (req_as_bytes[(i*4) + 2] << 16) | - (req_as_bytes[(i*4) + 3] << 24)); + for (ii = 0; !failcnt && ii < reqBytes/4; ii++) { + u32 word = ((req_as_bytes[(ii*4) + 0] << 0) | + (req_as_bytes[(ii*4) + 1] << 8) | + (req_as_bytes[(ii*4) + 2] << 16) | + (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&ioc->chip->Doorbell, word); - if ((t = WaitForDoorbellAck(ioc, 2)) < 0) + if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) failcnt++; } dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); DBG_DUMP_REQUEST_FRAME_HDR(req) - dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n", + dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); /* * Wait for completion of doorbell handshake reply from the IOC */ - if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait)) < 0) + if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) failcnt++; /* * Copy out the cached reply... */ - for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++) - u16reply[i] = ioc->hs_reply[i]; + for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++) + u16reply[ii] = ioc->hs_reply[ii]; } else { return -99; } @@ -2535,6 +3393,7 @@ * in it's IntStatus register. * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) + * @sleepFlag: Specifies whether the process can sleep * * This routine waits (up to ~2 seconds max) for IOC doorbell * handshake ACKnowledge. @@ -2542,28 +3401,40 @@ * Returns a negative value on failure, else wait loop count. */ static int -WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong) +WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { int cntdn = HZ * howlong; int count = 0; u32 intstat; - while (--cntdn) { - intstat = CHIPREG_READ32(&ioc->chip->IntStatus); - if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) - break; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - count++; + if (sleepFlag == CAN_SLEEP) { + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + count++; + } + } else { + cntdn *= 10; /* convert to msec */ + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) + break; + mdelay (1); + count++; + } + count /= 10; } if (cntdn) { - dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n", + dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n", ioc->name, count)); return count; } - printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n", + printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n", ioc->name, (count+5)/HZ); return -1; } @@ -2574,34 +3445,47 @@ * in it's IntStatus register. * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) + * @sleepFlag: Specifies whether the process can sleep * * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt. * * Returns a negative value on failure, else wait loop count. */ static int -WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong) +WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { int cntdn = HZ * howlong; int count = 0; u32 intstat; - while (--cntdn) { - intstat = CHIPREG_READ32(&ioc->chip->IntStatus); - if (intstat & MPI_HIS_DOORBELL_INTERRUPT) - break; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - count++; + if (sleepFlag == CAN_SLEEP) { + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + count++; + } + } else { + cntdn *= 10; /* convert to msec */ + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; + mdelay(1); + count++; + } + count /= 10; } if (cntdn) { - dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n", + dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n", ioc->name, count)); return count; } - printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n", + printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n", ioc->name, (count+5)/HZ); return -1; } @@ -2611,6 +3495,7 @@ * WaitForDoorbellReply - Wait for and capture a IOC handshake reply. * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) + * @sleepFlag: Specifies whether the process can sleep * * This routine polls the IOC for a handshake reply, 16 bits at a time. * Reply is cached to IOC private area large enough to hold a maximum @@ -2619,13 +3504,13 @@ * Returns a negative value on failure, else size of reply in WORDS. */ static int -WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong) +WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { int u16cnt = 0; int failcnt = 0; int t; u16 *hs_reply = ioc->hs_reply; - volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; + volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; u16 hword; hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; @@ -2634,12 +3519,12 @@ * Get first two u16's so we can look at IOC's intended reply MsgLength */ u16cnt=0; - if ((t = WaitForDoorbellInt(ioc, howlong)) < 0) { + if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) { failcnt++; } else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if ((t = WaitForDoorbellInt(ioc, 2)) < 0) + if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) failcnt++; else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); @@ -2647,7 +3532,7 @@ } } - dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n", + dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n", ioc->name, le32_to_cpu(*(u32 *)hs_reply), failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); @@ -2656,7 +3541,7 @@ * reply 16 bits at a time. */ for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { - if ((t = WaitForDoorbellInt(ioc, 2)) < 0) + if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) failcnt++; hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); /* don't overflow our IOC hs_reply[] buffer! */ @@ -2665,12 +3550,12 @@ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); } - if (!failcnt && (t = WaitForDoorbellInt(ioc, 2)) < 0) + if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) failcnt++; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if (failcnt) { - printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n", + printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n", ioc->name); return -failcnt; } @@ -2681,130 +3566,631 @@ else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { return -102; } -#endif +#endif + + dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); + DBG_DUMP_REPLY_FRAME(mptReply) + + dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n", + ioc->name, u16cnt/2)); + return u16cnt/2; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetLanConfigPages - Fetch LANConfig pages. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Return: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +static int +GetLanConfigPages(MPT_ADAPTER *ioc) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + LANPage0_t *ppage0_alloc; + dma_addr_t page0_dma; + LANPage1_t *ppage1_alloc; + dma_addr_t page1_dma; + int rc = 0; + int data_sz; + int copy_sz; + + /* Get LAN Page 0 header */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.pageAddr = 0; + cfg.timeout = 0; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + return rc; + + if (hdr.PageLength > 0) { + data_sz = hdr.PageLength * 4; + ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); + rc = -ENOMEM; + if (ppage0_alloc) { + memset((u8 *)ppage0_alloc, 0, data_sz); + cfg.physAddr = page0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) == 0) { + /* save the data */ + copy_sz = MIN(sizeof(LANPage0_t), data_sz); + memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz); + + } + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); + + /* FIXME! + * Normalize endianness of structure data, + * by byte-swapping all > 1 byte fields! + */ + + } + + if (rc) + return rc; + } + + /* Get LAN Page 1 header */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 1; + hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.pageAddr = 0; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + return rc; + + if (hdr.PageLength == 0) + return 0; + + data_sz = hdr.PageLength * 4; + rc = -ENOMEM; + ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma); + if (ppage1_alloc) { + memset((u8 *)ppage1_alloc, 0, data_sz); + cfg.physAddr = page1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) == 0) { + /* save the data */ + copy_sz = MIN(sizeof(LANPage1_t), data_sz); + memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz); + } + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma); + + /* FIXME! + * Normalize endianness of structure data, + * by byte-swapping all > 1 byte fields! + */ + + } + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetFcPortPage0 - Fetch FCPort config Page0. + * @ioc: Pointer to MPT_ADAPTER structure + * @portnum: IOC Port number + * + * Return: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +static int +GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + FCPortPage0_t *ppage0_alloc; + FCPortPage0_t *pp0dest; + dma_addr_t page0_dma; + int data_sz; + int copy_sz; + int rc; + + /* Get FCPort Page 0 header */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.pageAddr = portnum; + cfg.timeout = 0; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + return rc; + + if (hdr.PageLength == 0) + return 0; + + data_sz = hdr.PageLength * 4; + rc = -ENOMEM; + ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); + if (ppage0_alloc) { + memset((u8 *)ppage0_alloc, 0, data_sz); + cfg.physAddr = page0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) == 0) { + /* save the data */ + pp0dest = &ioc->fc_port_page0[portnum]; + copy_sz = MIN(sizeof(FCPortPage0_t), data_sz); + memcpy(pp0dest, ppage0_alloc, copy_sz); + + /* + * Normalize endianness of structure data, + * by byte-swapping all > 1 byte fields! + */ + pp0dest->Flags = le32_to_cpu(pp0dest->Flags); + pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier); + pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low); + pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High); + pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low); + pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High); + pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass); + pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds); + pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed); + pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize); + pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low); + pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High); + pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low); + pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High); + pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount); + pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators); + + } + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); + } + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetIoUnitPage2 - Retrieve BIOS version and boot order information. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +static int +GetIoUnitPage2(MPT_ADAPTER *ioc) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + IOUnitPage2_t *ppage_alloc; + dma_addr_t page_dma; + int data_sz; + int rc; + + /* Get the page header */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 2; + hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.pageAddr = 0; + cfg.timeout = 0; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + return rc; + + if (hdr.PageLength == 0) + return 0; + + /* Read the config page */ + data_sz = hdr.PageLength * 4; + rc = -ENOMEM; + ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma); + if (ppage_alloc) { + memset((u8 *)ppage_alloc, 0, data_sz); + cfg.physAddr = page_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + /* If Good, save data */ + if ((rc = mpt_config(ioc, &cfg)) == 0) + ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion); + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma); + } + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 + * @ioc: Pointer to a Adapter Strucutre + * @portnum: IOC port number + * + * Return: -EFAULT if read of config page header fails + * or if no nvram + * If read of SCSI Port Page 0 fails, + * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) + * Adapter settings: async, narrow + * Return 1 + * If read of SCSI Port Page 2 fails, + * Adapter settings valid + * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) + * Return 1 + * Else + * Both valid + * Return 0 + * CHECK - what type of locking mechanisms should be used???? + */ +static int +mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) +{ + u8 *pbuf = NULL; + dma_addr_t buf_dma; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + int ii; + int data, rc = 0; + + /* Allocate memory + */ + if (!ioc->spi_data.nvram) { + int sz; + u8 *mem; + sz = MPT_MAX_SCSI_DEVICES * sizeof(int); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + return -EFAULT; + + ioc->spi_data.nvram = (int *) mem; + + dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", + ioc->name, ioc->spi_data.nvram, sz)); + } + + /* Invalidate NVRAM information + */ + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID; + } + + /* Read SPP0 header, allocate memory, then read page. + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 0; + header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = portnum; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; /* use default */ + if (mpt_config(ioc, &cfg) != 0) + return -EFAULT; + + if (header.PageLength > 0) { + pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); + if (pbuf) { + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.physAddr = buf_dma; + if (mpt_config(ioc, &cfg) != 0) { + ioc->spi_data.maxBusWidth = MPT_NARROW; + ioc->spi_data.maxSyncOffset = 0; + ioc->spi_data.minSyncFactor = MPT_ASYNC; + ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; + rc = 1; + } else { + /* Save the Port Page 0 data + */ + SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf; + pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); + pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); + + ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; + data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; + if (data) { + ioc->spi_data.maxSyncOffset = (u8) (data >> 16); + data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; + ioc->spi_data.minSyncFactor = (u8) (data >> 8); + } else { + ioc->spi_data.maxSyncOffset = 0; + ioc->spi_data.minSyncFactor = MPT_ASYNC; + } + + ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK; + + /* Update the minSyncFactor based on bus type. + */ + if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || + (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { + + if (ioc->spi_data.minSyncFactor < MPT_ULTRA) + ioc->spi_data.minSyncFactor = MPT_ULTRA; + } + } + if (pbuf) { + pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); + pbuf = NULL; + } + } + } + + /* SCSI Port Page 2 - Read the header then the page. + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 2; + header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = portnum; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + if (mpt_config(ioc, &cfg) != 0) + return -EFAULT; + + if (header.PageLength > 0) { + /* Allocate memory and read SCSI Port Page 2 + */ + pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma); + if (pbuf) { + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM; + cfg.physAddr = buf_dma; + if (mpt_config(ioc, &cfg) != 0) { + /* Nvram data is left with INVALID mark + */ + rc = 1; + } else { + SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; + MpiDeviceInfo_t *pdevice = NULL; + + /* Save the Port Page 2 data + * (reformat into a 32bit quantity) + */ + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + pdevice = &pPP2->DeviceSettings[ii]; + data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | + (pdevice->SyncFactor << 8) | pdevice->Timeout; + ioc->spi_data.nvram[ii] = data; + } + } + + pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); + pbuf = NULL; + } + } - dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name)); - DBG_DUMP_REPLY_FRAME(mptReply) + /* Update Adapter limits with those from NVRAM + * Comment: Don't need to do this. Target performance + * parameters will never exceed the adapters limits. + */ - dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n", - ioc->name, u16cnt/2)); - return u16cnt/2; + return rc; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * GetLanConfigPages - Fetch LANConfig pages. - * @ioc: Pointer to MPT_ADAPTER structure +/* mpt_readScsiDevicePageHeaders - save version and length of SDP1 + * @ioc: Pointer to a Adapter Strucutre + * @portnum: IOC port number * - * Returns 0 for success, non-zero for failure. + * Return: -EFAULT if read of config page header fails + * or 0 if success. */ static int -GetLanConfigPages(MPT_ADAPTER *ioc) +mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) { - Config_t config_req; - ConfigReply_t config_reply; - LANPage0_t *page0; - dma_addr_t page0_dma; - LANPage1_t *page1; - dma_addr_t page1_dma; - int i; - int req_sz; - int reply_sz; - int data_sz; + CONFIGPARMS cfg; + ConfigPageHeader_t header; -/* LANPage0 */ - /* Immediate destination (reply area)... */ - reply_sz = sizeof(config_reply); - memset(&config_reply, 0, reply_sz); - - /* Ultimate destination... */ - page0 = &ioc->lan_cnfg_page0; - data_sz = sizeof(*page0); - memset(page0, 0, data_sz); - - /* Request area (config_req on the stack right now!) */ - req_sz = sizeof(config_req); - memset(&config_req, 0, req_sz); - config_req.Function = MPI_FUNCTION_CONFIG; - config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - /* config_req.Header.PageVersion = 0; */ - /* config_req.Header.PageLength = 0; */ - config_req.Header.PageNumber = 0; - config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; - /* config_req.PageAddress = 0; */ - config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( - ((MPI_SGE_FLAGS_LAST_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_END_OF_LIST | - MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_32_BIT_ADDRESSING | - MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | - (u32)data_sz - ); - page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE); - config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma); + /* Read the SCSI Device Page 1 header + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 1; + header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = portnum; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return -EFAULT; + + ioc->spi_data.sdp1version = cfg.hdr->PageVersion; + ioc->spi_data.sdp1length = cfg.hdr->PageLength; + + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 0; + header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + if (mpt_config(ioc, &cfg) != 0) + return -EFAULT; - dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n", - ioc->name)); + ioc->spi_data.sdp0version = cfg.hdr->PageVersion; + ioc->spi_data.sdp0length = cfg.hdr->PageLength; - i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, - reply_sz, (u16*)&config_reply, 3); - pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE); - if (i != 0) - return i; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes + * @ioc: Pointer to a Adapter Strucutre + * @portnum: IOC port number + * + * Return: + * 0 on success + * -EFAULT if read of config page header fails or data pointer not NULL + * -ENOMEM if pci_alloc failed + */ +static int +mpt_findImVolumes(MPT_ADAPTER *ioc) +{ + IOCPage2_t *pIoc2 = NULL; + IOCPage3_t *pIoc3 = NULL; + ConfigPageIoc2RaidVol_t *pIocRv = NULL; + u8 *mem; + dma_addr_t ioc2_dma; + dma_addr_t ioc3_dma; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + int jj; + int rc = 0; + int iocpage2sz; + int iocpage3sz = 0; + u8 nVols, nPhys; + u8 vid, vbus, vioc; + + if (ioc->spi_data.pIocPg3) + return -EFAULT; + + /* Read IOCP2 header then the page. + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 2; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return -EFAULT; + + if (header.PageLength == 0) + return -EFAULT; + + iocpage2sz = header.PageLength * 4; + pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma); + if (!pIoc2) + return -ENOMEM; + + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.physAddr = ioc2_dma; + if (mpt_config(ioc, &cfg) != 0) + goto done_and_free; + + /* Identify RAID Volume Id's */ + nVols = pIoc2->NumActiveVolumes; + if ( nVols == 0) { + /* No RAID Volumes. Done. + */ + } else { + /* At least 1 RAID Volume + */ + pIocRv = pIoc2->RaidVolume; + ioc->spi_data.isRaid = 0; + for (jj = 0; jj < nVols; jj++, pIocRv++) { + vid = pIocRv->VolumeID; + vbus = pIocRv->VolumeBus; + vioc = pIocRv->VolumeIOC; + + /* find the match + */ + if (vbus == 0) { + ioc->spi_data.isRaid |= (1 << vid); + } else { + /* Error! Always bus 0 + */ + } + } + } - /* Now byte swap the necessary LANPage0 fields */ + /* Identify Hidden Physical Disk Id's */ + nPhys = pIoc2->NumActivePhysDisks; + if (nPhys == 0) { + /* No physical disks. Done. + */ + } else { + /* There is at least one physical disk. + * Read and save IOC Page 3 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 3; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + goto done_and_free; -/* LANPage1 */ - /* Immediate destination (reply area)... */ - reply_sz = sizeof(config_reply); - memset(&config_reply, 0, reply_sz); - - /* Ultimate destination... */ - page1 = &ioc->lan_cnfg_page1; - data_sz = sizeof(*page1); - memset(page1, 0, data_sz); - - /* Request area (config_req on the stack right now!) */ - req_sz = sizeof(config_req); - memset(&config_req, 0, req_sz); - config_req.Function = MPI_FUNCTION_CONFIG; - config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - /* config_req.Header.PageVersion = 0; */ - /* config_req.Header.PageLength = 0; */ - config_req.Header.PageNumber = 1; - config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; - /* config_req.PageAddress = 0; */ - config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( - ((MPI_SGE_FLAGS_LAST_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_END_OF_LIST | - MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_32_BIT_ADDRESSING | - MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | - (u32)data_sz - ); - page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE); - config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma); + if (header.PageLength == 0) + goto done_and_free; - dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n", - ioc->name)); + /* Read Header good, alloc memory + */ + iocpage3sz = header.PageLength * 4; + pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); + if (!pIoc3) + goto done_and_free; - i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, - reply_sz, (u16*)&config_reply, 3); - pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE); - if (i != 0) - return i; + /* Read the Page and save the data + * into malloc'd memory. + */ + cfg.physAddr = ioc3_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + mem = kmalloc(iocpage3sz, GFP_KERNEL); + if (mem) { + memcpy(mem, (u8 *)pIoc3, iocpage3sz); + ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; + } + } + } - /* Now byte swap the necessary LANPage1 fields */ +done_and_free: + if (pIoc2) { + pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); + pIoc2 = NULL; + } - return 0; + if (pIoc3) { + pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); + pIoc3 = NULL; + } + + return rc; } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * SendEventNotification - Send EventNotification (on or off) request * to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -2817,13 +4203,13 @@ evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id); if (evnp == NULL) { - dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n", + dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", ioc->name)); return 0; } memset(evnp, 0, sizeof(*evnp)); - dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch)); + dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch)); evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; evnp->ChainOffset = 0; @@ -2847,13 +4233,13 @@ EventAck_t *pAck; if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { - printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n", + printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n", ioc->name); return -1; } memset(pAck, 0, sizeof(*pAck)); - dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name)); + dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name)); pAck->Function = MPI_FUNCTION_EVENT_ACK; pAck->ChainOffset = 0; @@ -2866,25 +4252,212 @@ return 0; } -#ifdef CONFIG_PROC_FS /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_config - Generic function to issue config message + * @ioc - Pointer to an adapter structure + * @cfg - Pointer to a configuration structure. Struct contains + * action, page address, direction, physical address + * and pointer to a configuration page header + * Page header is updated. + * + * Returns 0 for success + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +int +mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) +{ + Config_t *pReq; + MPT_FRAME_HDR *mf; + MptSge_t *psge; + unsigned long flags; + int ii, rc; + int flagsLength; + int in_isr; + + /* (Bugzilla:fibrebugs, #513) + * Bug fix (part 1)! 20010905 -sralston + * Prevent calling wait_event() (below), if caller happens + * to be in ISR context, because that is fatal! + */ + in_isr = in_interrupt(); + if (in_isr) { + dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", + ioc->name)); + return -EPERM; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + pReq = (Config_t *)mf; + pReq->Action = pCfg->action; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_CONFIG; + pReq->Reserved1[0] = 0; + pReq->Reserved1[1] = 0; + pReq->Reserved1[2] = 0; + pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) + pReq->Reserved2[ii] = 0; + + pReq->Header.PageVersion = pCfg->hdr->PageVersion; + pReq->Header.PageLength = pCfg->hdr->PageLength; + pReq->Header.PageNumber = pCfg->hdr->PageNumber; + pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); + pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); + + /* Add a SGE to the config request. + */ + flagsLength = ((MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPT_SGE_ADDRESS_SIZE ) << MPI_SGE_FLAGS_SHIFT) | + pCfg->hdr->PageLength * 4; + + if (pCfg->dir) + flagsLength |= (MPI_SGE_FLAGS_DIRECTION << MPI_SGE_FLAGS_SHIFT); + + psge = (MptSge_t *) &pReq->PageBufferSGE; + psge->FlagsLength = cpu_to_le32(flagsLength); + cpu_to_leXX(pCfg->physAddr, psge->Address); + + dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + + /* Append pCfg pointer to end of mf + */ + *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; + + /* Initalize the timer + */ + init_timer(&pCfg->timer); + pCfg->timer.data = (unsigned long) ioc; + pCfg->timer.function = mpt_timer_expired; + pCfg->wait_done = 0; + + /* Set the timer; ensure 10 second minimum */ + if (pCfg->timeout < 10) + pCfg->timer.expires = jiffies + HZ*10; + else + pCfg->timer.expires = jiffies + HZ*pCfg->timeout; + + /* Add to end of Q, set timer and then issue this command */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + add_timer(&pCfg->timer); + mpt_put_msg_frame(mpt_base_index, ioc->id, mf); + wait_event(mpt_waitq, pCfg->wait_done); + + /* mf has been freed - do not access */ + + rc = pCfg->status; + + return rc; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... + * mpt_timer_expired - Call back for timer process. + * Used only internal config functionality. + * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long + */ +static void +mpt_timer_expired(unsigned long data) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; + + dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name)); + + /* Perform a FW reload */ + if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) + printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); + + /* No more processing. + * Hard reset clean-up will wake up + * process and free all resources. + */ + dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name)); + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_ioc_reset - Base cleanup for hard reset + * @ioc: Pointer to the adapter structure + * @reset_phase: Indicates pre- or post-reset functionality + * + * Remark: Free's resources with internally generated commands. */ +static int +mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + CONFIGPARMS *pCfg; + unsigned long flags; + + dprintk((KERN_WARNING MYNAM + ": IOC %s_reset routed to MPT base driver!\n", + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + + if (reset_phase == MPT_IOC_PRE_RESET) { + /* If the internal config Q is not empty - + * delete timer. MF resources will be freed when + * the FIFO's are primed. + */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&ioc->configQ)){ + pCfg = (CONFIGPARMS *)ioc->configQ.head; + do { + del_timer(&pCfg->timer); + pCfg = (CONFIGPARMS *) (pCfg->linkage.forw); + } while (pCfg != (CONFIGPARMS *)&ioc->configQ); + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + } else { + CONFIGPARMS *pNext; + + /* Search the configQ for internal commands. + * Flush the Q, and wake up all suspended threads. + */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&ioc->configQ)){ + pCfg = (CONFIGPARMS *)ioc->configQ.head; + do { + pNext = (CONFIGPARMS *) pCfg->linkage.forw; -#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \ -{ \ - len -= off; \ - if (len < count) { \ - *eof = 1; \ - if (len <= 0) \ - return 0; \ - } else \ - len = count; \ - *start = page + off; \ - return len; \ + Q_DEL_ITEM(&pCfg->linkage); + + pCfg->status = MPT_CONFIG_ERROR; + pCfg->wait_done = 1; + wake_up(&mpt_waitq); + + pCfg = pNext; + } while (pCfg != (CONFIGPARMS *)&ioc->configQ); + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + } + + return 1; /* currently means nothing really */ } + +#ifdef CONFIG_PROC_FS /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... + */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. @@ -2894,71 +4467,62 @@ static int procmpt_create(void) { - MPT_ADAPTER *ioc; - struct proc_dir_entry *ent; - int errcnt = 0; + MPT_ADAPTER *ioc; + struct proc_dir_entry *ent; + int ii; /* - * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" - * (single level) to multi level (e.g. "driver/message/fusion") - * something here needs to change. -sralston + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston */ - procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL); - if (procmpt_root_dir == NULL) + mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); + if (mpt_proc_root_dir == NULL) return -ENOTDIR; - if ((ioc = mpt_adapter_find_first()) != NULL) { - ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL); - if (ent == NULL) { - printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n", - MPT_PROCFS_SUMMARY_PATHNAME); - errcnt++; + for (ii=0; ii < MPT_PROC_ENTRIES; ii++) { + ent = create_proc_entry(mpt_proc_list[ii].name, + S_IFREG|S_IRUGO, mpt_proc_root_dir); + if (!ent) { + printk(KERN_WARNING MYNAM + ": WARNING - Could not create /proc/mpt/%s entry\n", + mpt_proc_list[ii].name); + continue; } + ent->read_proc = mpt_proc_list[ii].f; + ent->data = NULL; } + ioc = mpt_adapter_find_first(); while (ioc != NULL) { - char pname[32]; - int namelen; + struct proc_dir_entry *dent; /* * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. */ - namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); - if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) { + if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) { /* - * And populate it with: "summary" and "dbg" file entries. + * And populate it with mpt_ioc_proc_list[] entries. */ - (void) sprintf(pname+namelen, "/summary"); - ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc); - if (ent == NULL) { - errcnt++; - printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", - ioc->name, pname); - } -//#ifdef MPT_DEBUG - /* DEBUG aid! */ - (void) sprintf(pname+namelen, "/dbg"); - ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc); - if (ent == NULL) { - errcnt++; - printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", - ioc->name, pname); + for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) { + ent = create_proc_entry(mpt_ioc_proc_list[ii].name, + S_IFREG|S_IRUGO, dent); + if (!ent) { + printk(KERN_WARNING MYNAM + ": WARNING - Could not create /proc/mpt/%s/%s entry!\n", + ioc->name, + mpt_ioc_proc_list[ii].name); + continue; + } + ent->read_proc = mpt_ioc_proc_list[ii].f; + ent->data = ioc; } -//#endif } else { - errcnt++; - printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", - ioc->name, pname); - + printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n", + ioc->name, mpt_ioc_proc_list[ii].name); } - ioc = mpt_adapter_find_next(ioc); } - if (errcnt) { -// remove_proc_entry("mpt", 0); - return -ENOTDIR; - } - return 0; } @@ -2971,44 +4535,44 @@ static int procmpt_destroy(void) { - MPT_ADAPTER *ioc; + MPT_ADAPTER *ioc; + int ii; - if (!procmpt_root_dir) + if (!mpt_proc_root_dir) return 0; /* - * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" - * (single level) to multi level (e.g. "driver/message/fusion") - * something here needs to change. -sralston + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston */ ioc = mpt_adapter_find_first(); - if (ioc != NULL) { - remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0); - } - while (ioc != NULL) { char pname[32]; int namelen; + + namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + /* * Tear down each "/proc/mpt/iocN" subdirectory. */ - namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); - (void) sprintf(pname+namelen, "/summary"); - remove_proc_entry(pname, 0); -//#ifdef MPT_DEBUG - (void) sprintf(pname+namelen, "/dbg"); - remove_proc_entry(pname, 0); -//#endif - (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); - remove_proc_entry(pname, 0); + for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) { + (void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name); + remove_proc_entry(pname, NULL); + } + + remove_proc_entry(ioc->name, mpt_proc_root_dir); ioc = mpt_adapter_find_next(ioc); } - if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) { - remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0); - procmpt_root_dir = NULL; + for (ii=0; ii < MPT_PROC_ENTRIES; ii++) + remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir); + + if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) { + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); + mpt_proc_root_dir = NULL; return 0; } @@ -3016,23 +4580,23 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * procmpt_read_summary - Handle read request from /proc/mpt/summary +/* + * procmpt_summary_read - Handle read request from /proc/mpt/summary * or from /proc/mpt/iocN/summary. - * @page: Pointer to area to write information + * @buf: Pointer to area to write information * @start: Pointer to start pointer - * @off: Offset to start writing - * @count: + * @offset: Offset to start writing + * @request: * @eof: Pointer to EOF integer - * @data: Pointer + * @data: Pointer * - * Returns numbers of characters written to process performing the read. + * Returns number of characters written to process performing the read. */ static int -procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data) +procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { MPT_ADAPTER *ioc; - char *out = page; + char *out = buf; int len; if (data == NULL) @@ -3040,84 +4604,196 @@ else ioc = data; -// Too verbose! -// out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none"); - while (ioc) { int more = 0; -// Too verbose! -// mpt_print_ioc_facts(ioc, out, &more, 0); mpt_print_ioc_summary(ioc, out, &more, 0, 1); out += more; - if ((out-page) >= count) { + if ((out-buf) >= request) { break; } if (data == NULL) ioc = mpt_adapter_find_next(ioc); else - ioc = NULL; /* force exit for iocN */ + ioc = NULL; /* force exit for iocN */ } - len = out - page; + len = out - buf; - PROC_MPT_READ_RETURN(page,start,off,count,eof,len); + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); } -// debug aid! /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg. - * @page: Pointer to area to write information +/* + * procmpt_version_read - Handle read request from /proc/mpt/version. + * @buf: Pointer to area to write information * @start: Pointer to start pointer - * @off: Offset to start writing - * @count: + * @offset: Offset to start writing + * @request: * @eof: Pointer to EOF integer - * @data: Pointer + * @data: Pointer * - * Returns numbers of characters written to process performing the read. + * Returns number of characters written to process performing the read. */ static int -procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data) +procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - MPT_ADAPTER *ioc; - char *out = page; - int len; + int ii; + int scsi, lan, ctl, targ, dmp; + char *drvname; + int len; + + len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); + len += sprintf(buf+len, " Fusion MPT base driver\n"); + + scsi = lan = ctl = targ = dmp = 0; + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + drvname = NULL; + if (MptCallbacks[ii]) { + switch (MptDriverClass[ii]) { + case MPTSCSIH_DRIVER: + if (!scsi++) drvname = "SCSI host"; + break; + case MPTLAN_DRIVER: + if (!lan++) drvname = "LAN"; + break; + case MPTSTM_DRIVER: + if (!targ++) drvname = "SCSI target"; + break; + case MPTCTL_DRIVER: + if (!ctl++) drvname = "ioctl"; + break; + case MPTDMP_DRIVER: + if (!dmp++) drvname = "DMP"; + break; + } + + if (drvname) + len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); + /* + * Handle isense special case, because it + * doesn't do a formal mpt_register call. + */ + if (isense_idx == ii) + len += sprintf(buf+len, " Fusion MPT isense driver\n"); + } else + break; + } - ioc = data; + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); +} - while (ioc) { - int more = 0; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. + * @buf: Pointer to area to write information + * @start: Pointer to start pointer + * @offset: Offset to start writing + * @request: + * @eof: Pointer to EOF integer + * @data: Pointer + * + * Returns number of characters written to process performing the read. + */ +static int +procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) +{ + MPT_ADAPTER *ioc = data; + int len; + char expVer[32]; + int sz; + int p; - mpt_print_ioc_facts(ioc, out, &more, 0); + mpt_get_fw_exp_ver(expVer, ioc); - out += more; - if ((out-page) >= count) { - break; + len = sprintf(buf, "%s:", ioc->name); + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) + len += sprintf(buf+len, " (f/w download boot flag set)"); +// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL) +// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!"); + + len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n", + ioc->facts.ProductID, + ioc->prod_name); + len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); + if (ioc->facts.FWImageSize) + len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize); + len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); + len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); + len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState); + + len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n", + ioc->facts.CurrentHostMfaHighAddr); + len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n", + ioc->facts.CurrentSenseBufferHighAddr); + + len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); + len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); + + len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", + ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma); + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = (ioc->req_sz * ioc->req_depth) + 128; + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", + ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); + len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", + 4*ioc->facts.RequestFrameSize, + ioc->facts.GlobalCredits); + + len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n", + ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma); + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", + ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); + len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", + ioc->facts.CurReplyFrameSize, + ioc->facts.ReplyQueueDepth); + + len += sprintf(buf+len, " MaxDevices = %d\n", + (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices); + len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses); + + /* per-port info */ + for (p=0; p < ioc->facts.NumberOfPorts; p++) { + len += sprintf(buf+len, " PortNumber = %d (of %d)\n", + p+1, + ioc->facts.NumberOfPorts); + if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n", + ioc->fc_port_page0[p].WWNN.High, + ioc->fc_port_page0[p].WWNN.Low, + ioc->fc_port_page0[p].WWPN.High, + ioc->fc_port_page0[p].WWPN.Low); } - ioc = NULL; } - len = out - page; - PROC_MPT_READ_RETURN(page,start,off,count,eof,len); + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); } + #endif /* CONFIG_PROC_FS } */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) { - if ((ioc->facts.FWVersion & 0xF000) == 0xE000) + buf[0] ='\0'; + if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) { sprintf(buf, " (Exp %02d%02d)", - (ioc->facts.FWVersion & 0x0F00) >> 8, /* Month */ - ioc->facts.FWVersion & 0x001F); /* Day */ - else - buf[0] ='\0'; + (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */ + (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */ - /* insider hack! */ - if (ioc->facts.FWVersion & 0x0080) { - strcat(buf, " [MDBG]"); + /* insider hack! */ + if ((ioc->facts.FWVersion.Word >> 8) & 0x80) + strcat(buf, " [MDBG]"); } } @@ -3130,8 +4806,8 @@ * @len: Offset at which to start writing in buffer * @showlan: Display LAN stuff? * - * This routine writes (english readable) ASCII text, which represents - * a summary of IOC information, to a buffer. + * This routine writes (english readable) ASCII text, which represents + * a summary of IOC information, to a buffer. */ void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) @@ -3144,11 +4820,11 @@ /* * Shorter summary of attached ioc's... */ - y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d", + y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", ioc->name, ioc->prod_name, MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ - ioc->facts.FWVersion, + ioc->facts.FWVersion.Word, expVer, ioc->facts.NumberOfPorts, ioc->req_depth); @@ -3159,8 +4835,11 @@ a[5], a[4], a[3], a[2], a[1], a[0]); } - if (ioc->pci_irq < 100) - y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); +#ifndef __sparc__ + y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); +#else + y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq)); +#endif if (!ioc->active) y += sprintf(buffer+len+y, " (disabled)"); @@ -3171,75 +4850,66 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Reset Handling + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer. + * mpt_HardResetHandler - Generic reset handler, issue SCSI Task + * Management call based on input arg values. If TaskMgmt fails, + * return associated SCSI request. * @ioc: Pointer to MPT_ADAPTER structure - * @buffer: Pointer to buffer where IOC facts should be written - * @size: Pointer to number of bytes we wrote (set by this routine) - * @len: Offset at which to start writing in buffer + * @sleepFlag: Indicates if sleep or schedule must be called. + * + * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) + * or a non-interrupt thread. In the former, must not call schedule(). * - * This routine writes (english readable) ASCII text, which represents - * a summary of the IOC facts, to a buffer. + * Remark: A return of -1 is a FATAL error case, as it means a + * FW reload/initialization failed. + * + * Returns 0 for SUCCESS or -1 if FAILED. */ -void -mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len) +int +mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { - char expVer[32]; - char iocName[16]; - int sz; - int y; - int p; - - mpt_get_fw_exp_ver(expVer, ioc); + int rc; + unsigned long flags; - strcpy(iocName, ioc->name); - y = sprintf(buffer+len, "%s:\n", iocName); + dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); +#ifdef MFCNT + printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); + printk("MF count 0x%x !\n", ioc->mfcnt); +#endif - y += sprintf(buffer+len+y, " ProductID = 0x%04x\n", ioc->facts.ProductID); - for (p=0; p < ioc->facts.NumberOfPorts; p++) { - y += sprintf(buffer+len+y, " PortNumber = %d (of %d)\n", - p+1, - ioc->facts.NumberOfPorts); - if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { - u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; - y += sprintf(buffer+len+y, " LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - a[5], a[4], a[3], a[2], a[1], a[0]); - } - } - y += sprintf(buffer+len+y, " FWVersion = 0x%04x%s\n", ioc->facts.FWVersion, expVer); - y += sprintf(buffer+len+y, " MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); - y += sprintf(buffer+len+y, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); - y += sprintf(buffer+len+y, " EventState = 0x%02x\n", ioc->facts.EventState); - y += sprintf(buffer+len+y, " CurrentHostMfaHighAddr = 0x%08x\n", - ioc->facts.CurrentHostMfaHighAddr); - y += sprintf(buffer+len+y, " CurrentSenseBufferHighAddr = 0x%08x\n", - ioc->facts.CurrentSenseBufferHighAddr); - y += sprintf(buffer+len+y, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); - y += sprintf(buffer+len+y, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); + /* Reset the adapter. Prevent more than 1 call to + * mpt_do_ioc_recovery at any instant in time. + */ + spin_lock_irqsave(&ioc->diagLock, flags); + if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ + spin_unlock_irqrestore(&ioc->diagLock, flags); + return 0; + } else { + ioc->diagPending = 1; + } + spin_unlock_irqrestore(&ioc->diagLock, flags); - y += sprintf(buffer+len+y, " RequestFrames @ 0x%p (Dma @ 0x%08x)\n", - ioc->req_alloc, ioc->req_alloc_dma); - /* - * Rounding UP to nearest 4-kB boundary here... + /* FIXME: If do_ioc_recovery fails, repeat.... */ - sz = (ioc->req_sz * ioc->req_depth) + 128; - sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; - y += sprintf(buffer+len+y, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", - ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); - y += sprintf(buffer+len+y, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", - 4*ioc->facts.RequestFrameSize, - ioc->facts.GlobalCredits); - y += sprintf(buffer+len+y, " ReplyFrames @ 0x%p (Dma @ 0x%08x)\n", - ioc->reply_alloc, ioc->reply_alloc_dma); - sz = (ioc->reply_sz * ioc->reply_depth) + 128; - y += sprintf(buffer+len+y, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", - ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); - y += sprintf(buffer+len+y, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", - ioc->facts.CurReplyFrameSize, - ioc->facts.ReplyQueueDepth); + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { + printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", + rc, ioc->name); + } - *size = y; + spin_lock_irqsave(&ioc->diagLock, flags); + ioc->diagPending = 0; + if (ioc->alt_ioc) + ioc->alt_ioc->diagPending = 0; + spin_unlock_irqrestore(&ioc->diagLock, flags); + + dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + + return rc; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3268,7 +4938,7 @@ ds = "External Bus Reset"; break; case MPI_EVENT_RESCAN: - ds = "Bus Rescan Event"; + ds = "Bus Rescan Event"; /* Ok, do we need to do anything here? As far as I can tell, this is when a new device gets added to the loop. */ @@ -3296,6 +4966,9 @@ else ds = "Events(OFF) Change"; break; + case MPI_EVENT_INTEGRATED_RAID: + ds = "Integrated Raid"; + break; /* * MPT base "custom" events may be added here... */ @@ -3307,7 +4980,7 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * ProcessEventNotification - Route a received EventNotificationReply to * all currently regeistered event handlers. * @ioc: Pointer to MPT_ADAPTER structure @@ -3322,7 +4995,7 @@ u16 evDataLen; u32 evData0 = 0; // u32 evCtx; - int i; + int ii; int r = 0; int handlers = 0; char *evStr; @@ -3339,15 +5012,15 @@ } evStr = EventDescriptionStr(event, evData0); - dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n", + dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", ioc->name, evStr, event)); #if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS) printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO); - for (i = 0; i < evDataLen; i++) - printk(" %08x", le32_to_cpu(pEventReply->Data[i])); + for (ii = 0; ii < evDataLen; ii++) + printk(" %08x", le32_to_cpu(pEventReply->Data[ii])); printk("\n"); #endif @@ -3365,6 +5038,8 @@ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ case MPI_EVENT_LOGOUT: /* 09 */ + case MPI_EVENT_INTEGRATED_RAID: /* 0B */ + case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */ default: break; case MPI_EVENT_EVENT_CHANGE: /* 0A */ @@ -3382,13 +5057,36 @@ } /* + * Should this event be logged? Events are written sequentially. + * When buffer is full, start again at the top. + */ + if (ioc->events && (ioc->eventTypes & ( 1 << event))) { + int idx; + + idx = ioc->eventContext % ioc->eventLogSize; + + ioc->events[idx].event = event; + ioc->events[idx].eventContext = ioc->eventContext; + + for (ii = 0; ii < 2; ii++) { + if (ii < evDataLen) + ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]); + else + ioc->events[idx].data[ii] = 0; + } + + ioc->eventContext++; + } + + + /* * Call each currently registered protocol event handler. */ - for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { - if (MptEvHandlers[i]) { - dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n", - ioc->name, i)); - r += (*(MptEvHandlers[i]))(ioc, pEventReply); + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + if (MptEvHandlers[ii]) { + dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", + ioc->name, ii)); + r += (*(MptEvHandlers[ii]))(ioc, pEventReply); handlers++; } } @@ -3398,7 +5096,9 @@ * If needed, send (a single) EventAck. */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { - if ((i = SendEventAck(ioc, pEventReply)) != 0) { + if ((ii = SendEventAck(ioc, pEventReply)) != 0) { + printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n", + ioc->name, ii); } } @@ -3427,7 +5127,7 @@ switch(log_info) { /* FCP Initiator */ - case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: + case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: desc = "Received an out of order frame - unsupported"; break; case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: @@ -3483,7 +5183,7 @@ desc = "Not sent because login to remote node not validated"; break; case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: - desc = "Cleared from the outbound after a logout"; + desc = "Cleared from the outbound queue after a logout"; break; case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: desc = "Cleared waiting for data after a logout"; @@ -3516,7 +5216,7 @@ break; } - printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}", + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", ioc->name, log_info, subcl_str[subcl]); if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); @@ -3539,7 +5239,7 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) { /* FIXME! */ - printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info); + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3553,7 +5253,7 @@ * Specialized driver registration routine for the isense driver. */ int -mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable) +mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable) { int r = 0; @@ -3562,6 +5262,7 @@ mpt_ASCQ_TableSz = ascqtbl_sz; mpt_ScsiOpcodesPtr = opsTable; printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); + isense_idx = last_drv_idx; r = 1; } MOD_INC_USE_COUNT; @@ -3582,11 +5283,15 @@ mpt_ASCQ_TableSz = 0; mpt_ScsiOpcodesPtr = NULL; printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); + isense_idx = -1; MOD_DEC_USE_COUNT; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +EXPORT_SYMBOL(mpt_adapters); +EXPORT_SYMBOL(mpt_proc_root_dir); +EXPORT_SYMBOL(DmpService); EXPORT_SYMBOL(mpt_register); EXPORT_SYMBOL(mpt_deregister); EXPORT_SYMBOL(mpt_event_register); @@ -3597,12 +5302,16 @@ EXPORT_SYMBOL(mpt_put_msg_frame); EXPORT_SYMBOL(mpt_free_msg_frame); EXPORT_SYMBOL(mpt_send_handshake_request); +EXPORT_SYMBOL(mpt_handshake_req_reply_wait); EXPORT_SYMBOL(mpt_adapter_find_first); EXPORT_SYMBOL(mpt_adapter_find_next); EXPORT_SYMBOL(mpt_verify_adapter); +EXPORT_SYMBOL(mpt_GetIocState); EXPORT_SYMBOL(mpt_print_ioc_summary); EXPORT_SYMBOL(mpt_lan_index); EXPORT_SYMBOL(mpt_stm_index); +EXPORT_SYMBOL(mpt_HardResetHandler); +EXPORT_SYMBOL(mpt_config); EXPORT_SYMBOL(mpt_register_ascqops_strings); EXPORT_SYMBOL(mpt_deregister_ascqops_strings); @@ -3611,12 +5320,13 @@ EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * fusion_init - Fusion MPT base driver initialization routine. * * Returns 0 for success, non-zero for failure. */ -int __init fusion_init(void) +int __init +fusion_init(void) { int i; @@ -3636,12 +5346,22 @@ MptResetHandlers[i] = NULL; } + DmpService = NULL; + /* NEW! 20010120 -sralston * Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + /* Register for hard reset handling callbacks. + */ + if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) { + dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n")); + } else { + /* FIXME! */ + } + if ((i = mpt_pci_scan()) < 0) return i; @@ -3649,13 +5369,14 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** +/* * fusion_exit - Perform driver unload cleanup. * * This routine frees all resources associated with each MPT adapter * and removes all %MPT_PROCFS_MPTBASEDIR entries. */ -static void fusion_exit(void) +static void +fusion_exit(void) { MPT_ADAPTER *this; @@ -3665,7 +5386,7 @@ * Moved this *above* removal of all MptAdapters! */ #ifdef CONFIG_PROC_FS - procmpt_destroy(); + (void) procmpt_destroy(); #endif while (! Q_IS_EMPTY(&MptAdapters)) { @@ -3673,6 +5394,8 @@ Q_DEL_ITEM(this); mpt_adapter_dispose(this); } + + mpt_reset_deregister(mpt_base_index); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -urN linux-2.4.18/drivers/message/fusion/mptbase.h linux-2.4.19-pre5/drivers/message/fusion/mptbase.h --- linux-2.4.18/drivers/message/fusion/mptbase.h Sun Feb 17 11:40:27 2002 +++ linux-2.4.19-pre5/drivers/message/fusion/mptbase.h Sat Mar 30 22:55:39 2002 @@ -8,11 +8,12 @@ * Credits: * (see mptbase.c) * - * Copyright (c) 1999-2001 LSI Logic Corporation + * Copyright (c) 1999-2002 LSI Logic Corporation * Originally By: Steven J. Ralston - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.h,v 1.46.2.2.2.2 2001/09/18 03:22:29 sralston Exp $ + * $Id: mptbase.h,v 1.103 2002/02/27 20:24:38 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -55,6 +56,7 @@ /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #include "linux_compat.h" /* linux-2.2.x (vs. -2.4.x) tweaks */ +#include "scsi3.h" /* SCSI defines */ #include "lsi/mpi_type.h" #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ @@ -62,6 +64,7 @@ #include "lsi/mpi_cnfg.h" /* IOC configuration support */ #include "lsi/mpi_init.h" /* SCSI Host (initiator) protocol support */ #include "lsi/mpi_lan.h" /* LAN over FC protocol support */ +#include "lsi/mpi_raid.h" /* Integrated Mirroring support */ #include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ #include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ @@ -74,11 +77,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2001 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "1.02.02" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-1.02.02" +#define MPT_LINUX_VERSION_COMMON "2.00.11" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.00.11" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -89,39 +92,77 @@ * Fusion MPT(linux) driver configurable stuff... */ #define MPT_MAX_ADAPTERS 16 -#define MPT_MAX_PROTOCOL_DRIVERS 8 +#define MPT_MAX_PROTOCOL_DRIVERS 16 +#define MPT_MAX_BUS 1 #define MPT_MAX_FC_DEVICES 255 +#define MPT_MAX_SCSI_DEVICES 16 +#define MPT_LAST_LUN 31 +#define MPT_SENSE_BUFFER_ALLOC 64 + /* allow for 256 max sense alloc, but only 255 max request */ +#if MPT_SENSE_BUFFER_ALLOC >= 256 +# undef MPT_SENSE_BUFFER_ALLOC +# define MPT_SENSE_BUFFER_ALLOC 256 +# define MPT_SENSE_BUFFER_SIZE 255 +#else +# define MPT_SENSE_BUFFER_SIZE MPT_SENSE_BUFFER_ALLOC +#endif -#define MPT_MISCDEV_BASENAME "mptctl" -#define MPT_MISCDEV_PATHNAME "/dev/" MPT_MISCDEV_BASENAME +#define MPT_NAME_LENGTH 32 #define MPT_PROCFS_MPTBASEDIR "mpt" /* chg it to "driver/fusion" ? */ -#define MPT_PROCFS_SUMMARY_NODE MPT_PROCFS_MPTBASEDIR "/summary" -#define MPT_PROCFS_SUMMARY_PATHNAME "/proc/" MPT_PROCFS_SUMMARY_NODE -#define MPT_FW_REV_MAGIC_ID_STRING "FwRev=" +#define MPT_PROCFS_SUMMARY_ALL_NODE MPT_PROCFS_MPTBASEDIR "/summary" +#define MPT_PROCFS_SUMMARY_ALL_PATHNAME "/proc/" MPT_PROCFS_SUMMARY_ALL_NODE +#define MPT_FW_REV_MAGIC_ID_STRING "FwRev=" -#ifdef __KERNEL__ /* { */ #define MPT_MAX_REQ_DEPTH 1023 -#define MPT_REQ_DEPTH 256 +#define MPT_DEFAULT_REQ_DEPTH 256 #define MPT_MIN_REQ_DEPTH 128 #define MPT_MAX_REPLY_DEPTH MPT_MAX_REQ_DEPTH -#define MPT_REPLY_DEPTH 128 +#define MPT_DEFAULT_REPLY_DEPTH 128 #define MPT_MIN_REPLY_DEPTH 8 #define MPT_MAX_REPLIES_PER_ISR 32 #define MPT_MAX_FRAME_SIZE 128 -#define MPT_REQ_SIZE 128 -#define MPT_REPLY_SIZE 128 +#define MPT_DEFAULT_FRAME_SIZE 128 -#define MPT_SG_BUCKETS_PER_HUNK 1 +#define MPT_SG_REQ_128_SCALE 1 +#define MPT_SG_REQ_96_SCALE 2 +#define MPT_SG_REQ_64_SCALE 4 -#ifdef MODULE -#define MPT_REQ_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH) -#define MPT_REPLY_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH) -#define MPT_REPLY_SIZE_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE) -#endif +#define CAN_SLEEP 1 +#define NO_SLEEP 0 + +/* + * SCSI transfer rate defines. + */ +#define MPT_ULTRA320 0x08 +#define MPT_ULTRA160 0x09 +#define MPT_ULTRA2 0x0A +#define MPT_ULTRA 0x0C +#define MPT_FAST 0x19 +#define MPT_SCSI 0x32 +#define MPT_ASYNC 0xFF + +#define MPT_NARROW 0 +#define MPT_WIDE 1 + +#ifdef __KERNEL__ /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Attempt semi-consistent error & warning msgs across + * MPT drivers. NOTE: Users of these macro defs must + * themselves define their own MYNAM. + */ +#define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: " +#define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: " +#define MYIOC_s_WARN_FMT KERN_WARNING MYNAM ": %s: WARNING - " +#define MYIOC_s_ERR_FMT KERN_ERR MYNAM ": %s: ERROR - " /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -133,6 +174,7 @@ MPTSCSIH_DRIVER, /* MPT SCSI host (initiator) class */ MPTLAN_DRIVER, /* MPT LAN class */ MPTSTM_DRIVER, /* MPT SCSI target mode class */ + MPTDMP_DRIVER, /* MPT Dynamic Multi-pathing class */ MPTUNKNOWN_DRIVER } MPT_DRIVER_CLASS; @@ -145,10 +187,21 @@ struct _MPT_FRAME_HDR *forw; struct _MPT_FRAME_HDR *back; u32 arg1; + u32 pad; void *argp1; +#ifndef MPT_SCSI_USE_NEW_EH + void *argp2; +#endif } linkage; /* - * NOTE: On non-32-bit systems, where pointers are LARGE, + * NOTE: When request frames are free, on the linkage structure + * contets are valid. All other values are invalid. + * In particular, do NOT reply on offset [2] + * (in words) being the * message context. + * The message context must be reset (computed via base address + * + an offset) prior to issuing any command. + * + * NOTE2: On non-32-bit systems, where pointers are LARGE, * using the linkage pointers destroys our sacred MsgContext * field contents. But we don't care anymore because these * are now reset in mpt_put_msg_frame() just prior to sending @@ -169,6 +222,12 @@ } fld; } msgctxu; } hwhdr; + /* + * Remark: 32 bit identifier: + * 31-24: reserved + * 23-16: call back index + * 15-0 : request index + */ } MPT_FRAME_TRACKER; /* @@ -189,6 +248,11 @@ } u; } MPT_FRAME_HDR; +#define MPT_REQ_MSGFLAGS_DROPME 0x80 + +/* Used for tracking the free request frames + * and free reply frames. + */ typedef struct _MPT_Q_TRACKER { MPT_FRAME_HDR *head; MPT_FRAME_HDR *tail; @@ -214,9 +278,20 @@ struct _Q_ITEM *tail; } Q_TRACKER; +typedef struct _MPT_DONE_Q { + struct _MPT_DONE_Q *forw; + struct _MPT_DONE_Q *back; + void *argp; +} MPT_DONE_Q; + +typedef struct _DONE_Q_TRACKER { + MPT_DONE_Q *head; + MPT_DONE_Q *tail; +} DONE_Q_TRACKER; /* - * Chip-specific stuff... + * Chip-specific stuff... FC929 delineates break between + * FC and Parallel SCSI parts. Do NOT re-order. */ typedef enum { @@ -237,7 +312,9 @@ u32 WriteSequence; /* 04 Write Sequence register */ u32 Diagnostic; /* 08 Diagnostic register */ u32 TestBase; /* 0C Test Base Address */ - u32 Reserved1[8]; /* 10-2F reserved for future use */ + u32 DiagRwData; /* 10 Read Write Data (fw download) */ + u32 DiagRwAddress; /* 14 Read Write Address (fw download)*/ + u32 Reserved1[6]; /* 18-2F reserved for future use */ u32 IntStatus; /* 30 Interrupt Status */ u32 IntMask; /* 34 Interrupt Mask */ u32 Reserved2[2]; /* 38-3F reserved for future use */ @@ -256,60 +333,271 @@ */ +/* + * Dynamic Multi-Pathing specific stuff... + */ +#define DMP_MAX_PATHS 8 + +typedef struct _PathInfo { + u8 ioc; + u8 target; + u8 pad; + u8 pflags; +} PathInfo; + +#define PATHINFO_FLAGS_OWNED 0x01 +#define PATHINFO_FLAGS_EXISTS 0x02 +#define PATHINFO_FLAGS_AVAILABLE 0x04 +#define PATHINFO_FLAGS_SECONDARY 0x08 + +#define PFLAGS_EXISTS_AND_AVAIL (PATHINFO_FLAGS_EXISTS|PATHINFO_FLAGS_AVAILABLE) +#define PFLAGS_AVAIL_AND_OWNED (PATHINFO_FLAGS_AVAILABLE|PATHINFO_FLAGS_OWNED) + +typedef struct _ScsiCmndTracker { + void *head; + void *tail; +} ScsiCmndTracker; + + +/* + * VirtDevice - FC LUN device or SCSI target device + * (used to be FCSCSI_TARGET) + */ +typedef struct _VirtDevice { + struct _VirtDevice *forw; + struct _VirtDevice *back; + rwlock_t VdevLock; + int ref_cnt; + u8 tflags; + u8 ioc_id; + u8 target_id; + u8 bus_id; + u8 minSyncFactor; /* 0xFF is async */ + u8 maxOffset; /* 0 if async */ + u8 maxWidth; /* 0 if narrow, 1 if wide*/ + u8 negoFlags; /* 0 if WDTR/SDTR allowed */ + u8 raidVolume; /* set, if RAID Volume */ + u8 rsvd; /* alignment */ + u16 rsvd1raid; + int npaths; + u16 fc_phys_lun; + u16 fc_xlat_lun; + int stall_detected; + PathInfo path[DMP_MAX_PATHS]; + struct timer_list stall_timer; + struct timer_list retry_timer; + struct timer_list gone_timer; + ScsiCmndTracker WaitQ; + ScsiCmndTracker SentQ; + ScsiCmndTracker DoneQ; +//--- LUN split here? + u8 sense[SCSI_STD_SENSE_BYTES]; /* 18 */ + u8 rsvd2[2]; /* alignment */ + u32 luns; /* Max LUNs is 32 */ + u8 inq_data[SCSI_STD_INQUIRY_BYTES]; /* 36 */ + u8 pad0[4]; + u8 uniq_prepad[8]; + u8 inq00_data[20]; + u8 pad1[4]; + /* IEEE Registered Extended Identifier + obtained via INQUIRY VPD page 0x83 */ + u8 uniq_data[20]; + u8 pad2[4]; + u8 inqC3_data[12]; + u8 pad3[4]; + u8 inqC9_data[12]; + u8 pad4[4]; + u8 dev_vol_name[64]; +} VirtDevice; + +/* + * Fibre Channel (SCSI) target device and associated defines... + */ +#define MPT_TARGET_DEFAULT_DV_STATUS 0 +#define MPT_TARGET_FLAGS_VALID_NEGO 0x01 +#define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02 +#define MPT_TARGET_FLAGS_VALID_SENSE 0x04 +#define MPT_TARGET_FLAGS_Q_YES 0x08 + +#define MPT_TARGET_NO_NEGO_WIDE 0x01 +#define MPT_TARGET_NO_NEGO_SYNC 0x02 + +typedef struct _VirtDevTracker { + struct _VirtDevice *head; + struct _VirtDevice *tail; + rwlock_t VlistLock; + int pad; +} VirtDevTracker; + + +/* + * /proc/mpt interface + */ +typedef struct { + const char *name; + mode_t mode; + int pad; + read_proc_t *read_proc; + write_proc_t *write_proc; +} mpt_proc_entry_t; + +#define MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len) \ +do { \ + len -= offset; \ + if (len < request) { \ + *eof = 1; \ + if (len <= 0) \ + return 0; \ + } else \ + len = request; \ + *start = buf + offset; \ + return len; \ +} while (0) + + +/* + * IOCTL structure and associated defines + */ + +#define MPT_IOCTL_STATUS_DID_TIMEOUT 0x01 /* The current IOCTL timed out */ +#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ +#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */ +#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */ +#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ + +typedef struct _MPT_IOCTL { + struct _MPT_ADAPTER *ioc; + struct timer_list timer; /* timer function for this adapter */ + u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ + u8 sense[MPT_SENSE_BUFFER_ALLOC]; + int wait_done; /* wake-up value for this ioc */ + u8 cmd; /* current command */ + u8 status; /* current command status */ + u8 pad[2]; +} MPT_IOCTL; + +/* + * Event Structure and define + */ +#define MPTCTL_EVENT_LOG_SIZE (0x0000000A) +typedef struct _mpt_ioctl_events { + u32 event; /* Specified by define above */ + u32 eventContext; /* Index or counter */ + int data[2]; /* First 8 bytes of Event Data */ +} MPT_IOCTL_EVENTS; + +/* + * CONFIGPARM status defines + */ +#define MPT_CONFIG_GOOD MPI_IOCSTATUS_SUCCESS +#define MPT_CONFIG_ERROR 0x002F + +/* + * Substructure to store SCSI specific configuration page data + */ +#define MPT_SCSICFG_NEGOTIATE 0x01 /* Negotiate on next IO */ +#define MPT_SCSICFG_NEED_DV 0x02 /* Schedule DV */ +#define MPT_SCSICFG_DV_PENDING 0x04 /* DV on this physical id pending */ +#define MPT_SCSICFG_DV_DONE 0x08 /* DV on this physical id complete */ + +#define MPT_SCSICFG_USE_NVRAM 0x01 /* WriteSDP1 using NVRAM */ +#define MPT_SCSICFG_ALL_IDS 0x02 /* WriteSDP1 to all IDS */ + +typedef struct _ScsiCfgData { + int *nvram; /* table of device NVRAM values */ + IOCPage3_t *pIocPg3; /* table of physical disks */ + u8 dvStatus[MPT_MAX_SCSI_DEVICES]; + int isRaid; /* bit field, 1 if RAID */ + u8 minSyncFactor; /* 0xFF if async */ + u8 maxSyncOffset; /* 0 if async */ + u8 maxBusWidth; /* 0 if narrow, 1 if wide */ + u8 busType; /* SE, LVD, HD */ + u8 sdp1version; /* SDP1 version */ + u8 sdp1length; /* SDP1 length */ + u8 sdp0version; /* SDP0 version */ + u8 sdp0length; /* SDP0 length */ + u8 dvScheduled; /* 1 if scheduled */ + u8 forceDv; /* 1 to force DV scheduling */ + u8 rsvd[2]; +} ScsiCfgData; + +/* + * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS + */ typedef struct _MPT_ADAPTER { struct _MPT_ADAPTER *forw; struct _MPT_ADAPTER *back; - int id; /* Unique adapter id {0,1,2,...} */ - int pci_irq; - char name[32]; /* "iocN" */ + int id; /* Unique adapter id N {0,1,2,...} */ + int pci_irq; /* This irq */ + char name[MPT_NAME_LENGTH]; /* "iocN" */ char *prod_name; /* "LSIFC9x9" */ - u32 mem_phys; /* == f4020000 (mmap) */ volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */ - CHIP_TYPE chip_type; - int mem_size; + volatile SYSIF_REGS *pio_chip; /* Programmed IO (downloadboot) */ + u32 mem_phys; /* == f4020000 (mmap) */ + u32 pio_mem_phys; /* Programmed IO (downloadboot) */ + int mem_size; /* mmap memory size */ int alloc_total; u32 last_state; int active; - int sod_reset; - unsigned long last_kickstart; - u8 *reply_alloc; /* Reply frames alloc ptr */ + u8 *reply_alloc; /* Reply frames alloc ptr */ dma_addr_t reply_alloc_dma; - MPT_FRAME_HDR *reply_frames; /* Reply frames - rounded up! */ + MPT_FRAME_HDR *reply_frames; /* Reply msg frames - rounded up! */ dma_addr_t reply_frames_dma; - int reply_depth; - int reply_sz; + u32 reply_frames_low_dma; + int reply_depth; /* Num Allocated reply frames */ + int reply_sz; /* Reply frame size */ + CHIP_TYPE chip_type; /* We (host driver) get to manage our own RequestQueue! */ - u8 *req_alloc; /* Request frames alloc ptr */ + u8 *req_alloc; /* Request frames alloc ptr */ dma_addr_t req_alloc_dma; - MPT_FRAME_HDR *req_frames; /* Request msg frames for PULL mode! */ + MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ dma_addr_t req_frames_dma; - int req_depth; - int req_sz; - MPT_Q_TRACKER FreeQ; + u32 req_frames_low_dma; + int req_depth; /* Number of request frames */ + int req_sz; /* Request frame size (bytes) */ spinlock_t FreeQlock; + MPT_Q_TRACKER FreeQ; /* Pool of SCSI sense buffers for commands coming from * the SCSI mid-layer. We have one 256 byte sense buffer * for each REQ entry. */ u8 *sense_buf_pool; dma_addr_t sense_buf_pool_dma; - struct pci_dev *pcidev; -/* atomic_t userCnt; */ - u8 *memmap; + u32 sense_buf_low_dma; int mtrr_reg; - struct Scsi_Host *sh; + void *pcidev; /* struct pci_dev pointer */ + u8 *memmap; /* mmap address */ + struct Scsi_Host *sh; /* Scsi Host pointer */ + ScsiCfgData spi_data; /* Scsi config. data */ + MPT_IOCTL *ioctl; /* ioctl data pointer */ struct proc_dir_entry *ioc_dentry; - struct _MPT_ADAPTER *alt_ioc; + struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ + spinlock_t diagLock; /* diagnostic reset lock */ + int diagPending; + u32 biosVersion; /* BIOS version from IO Unit Page 2 */ + int eventTypes; /* Event logging parameters */ + int eventContext; /* Next event context */ + int eventLogSize; /* Max number of cached events */ + struct _mpt_ioctl_events *events; /* pointer to event log */ + u8 *FWImage; /* Pointer to FW */ + dma_addr_t FWImage_dma; + Q_TRACKER configQ; /* linked list of config. requests */ int hs_reply_idx; +#ifndef MFCNT + u32 pad0; +#else + u32 mfcnt; +#endif u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; IOCFactsReply_t facts; PortFactsReply_t pfacts[2]; + FCPortPage0_t fc_port_page0[2]; LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; u8 FirstWhoInit; - u8 pad1[3]; + u8 pad1[7]; } MPT_ADAPTER; @@ -324,7 +612,6 @@ * 0 = not Ok ... */ typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); - typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply); typedef int (*MPT_RESETHANDLER)(MPT_ADAPTER *ioc, int reset_phase); /* reset_phase defs */ @@ -344,6 +631,47 @@ #define MPT_HOSTEVENT_IOC_BRINGUP 0x91 #define MPT_HOSTEVENT_IOC_RECOVER 0x92 +/* 32 vs 64 bit SGL code. + * + */ +#if defined(__ia64__) +typedef SGESimple64_t MptSge_t; +typedef SGEChain64_t MptChain_t; + +#define cpu_to_leXX(y, p) { \ + u32 low = (u32) (y & 0xFFFFFFFF); \ + u32 high = (u32) (y >> 32); \ + p.Low = cpu_to_le32(low); \ + p.High = cpu_to_le32(high); \ +} + +#define leXX_to_cpu(y, p) { \ + y = (dma_addr_t) le32_to_cpu(p.High); \ + y = (y << 32); \ + y |= le32_to_cpu(p.Low); \ +} + +#define MPT_SGE_ADDRESS_SIZE MPI_SGE_FLAGS_64_BIT_ADDRESSING +#define MPT_SCSIIO_MSG_FLAGS MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 + + +#else + +typedef SGESimple32_t MptSge_t; +typedef SGEChain32_t MptChain_t; +#define cpu_to_leXX(y,p) { \ + p = cpu_to_le32(y); \ +} + +#define leXX_to_cpu(y,p) { \ + y = le32_to_cpu(p); \ +} + +#define MPT_SGE_ADDRESS_SIZE MPI_SGE_FLAGS_32_BIT_ADDRESSING +#define MPT_SCSIIO_MSG_FLAGS MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 + +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Funky (private) macros... @@ -360,7 +688,8 @@ #define dhsprintk(x) #endif -#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +#if defined(MPT_DEBUG_MSG_FRAME) #define dmfprintk(x) printk x #else #define dmfprintk(x) @@ -372,24 +701,35 @@ #define dirqprintk(x) #endif -#ifdef MPT_DEBUG_EVENTS -#define deventprintk(x) printk x +#ifdef MPT_DEBUG_SG +#define dsgprintk(x) printk x #else -#define deventprintk(x) +#define dsgprintk(x) #endif -#ifdef MPT_DEBUG_SPINLOCK -#define dslprintk(x) printk x +#ifdef MPT_DEBUG_DV +#define ddvprintk(x) printk x #else -#define dslprintk(x) +#define ddvprintk(x) #endif -#ifdef MPT_DEBUG_SG -#define dsgprintk(x) printk x +#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) +#define ddvtprintk(x) printk x #else -#define dsgprintk(x) +#define ddvtprintk(x) #endif +#ifdef MPT_DEBUG_IOCTL +#define dctlprintk(x) printk x +#else +#define dctlprintk(x) +#endif + +#ifdef MPT_DEBUG_RESET +#define dtmprintk(x) printk x +#else +#define dtmprintk(x) +#endif #define MPT_INDEX_2_MFPTR(ioc,idx) \ (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) ) @@ -397,6 +737,9 @@ #define MFPTR_2_MPT_INDEX(ioc,mf) \ (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz ) +#define MPT_INDEX_2_RFPTR(ioc,idx) \ + (MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) ) + #define Q_INIT(q,type) (q)->head = (q)->tail = (type*)(q) #define Q_IS_EMPTY(q) ((Q_ITEM*)(q)->head == (Q_ITEM*)(q)) @@ -425,7 +768,6 @@ _forw->back = _back; \ } - #define SWAB4(value) \ (u32)( (((value) & 0x000000ff) << 24) \ | (((value) & 0x0000ff00) << 8) \ @@ -457,64 +799,143 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#endif /* } __KERNEL__ */ +/* + * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers + * Private to the driver. + */ +/* LOCAL structure and fields used when processing + * internally generated commands. These include: + * bus scan, dv and config requests. + */ +typedef struct _MPT_LOCAL_REPLY { + ConfigPageHeader_t header; + int completion; + u8 sense[SCSI_STD_SENSE_BYTES]; + u8 scsiStatus; + u8 skip; + u32 pad; +} MPT_LOCAL_REPLY; + +#define MPT_HOST_BUS_UNKNOWN (0xFF) +#define MPT_HOST_TOO_MANY_TM (0x05) +#define MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) +#define MPT_HOST_NO_CHAIN (0xFFFFFFFF) +#define MPT_NVRAM_MASK_TIMEOUT (0x000000FF) +#define MPT_NVRAM_SYNC_MASK (0x0000FF00) +#define MPT_NVRAM_SYNC_SHIFT (8) +#define MPT_NVRAM_DISCONNECT_ENABLE (0x00010000) +#define MPT_NVRAM_ID_SCAN_ENABLE (0x00020000) +#define MPT_NVRAM_LUN_SCAN_ENABLE (0x00040000) +#define MPT_NVRAM_TAG_QUEUE_ENABLE (0x00080000) +#define MPT_NVRAM_WIDE_DISABLE (0x00100000) +#define MPT_NVRAM_BOOT_CHOICE (0x00200000) + +typedef struct _MPT_SCSI_HOST { + MPT_ADAPTER *ioc; + int port; + u32 pad0; + struct scsi_cmnd **ScsiLookup; + /* Pool of buffers for chaining. ReqToChain + * and ChainToChain track index of chain buffers. + * ChainBuffer (DMA) virt/phys addresses. + * FreeChainQ (lock) locking mechanisms. + */ + int *ReqToChain; + int *ChainToChain; + u8 *ChainBuffer; + dma_addr_t ChainBufferDMA; + MPT_Q_TRACKER FreeChainQ; + spinlock_t FreeChainQlock; + u32 qtag_tick; + VirtDevice **Targets; + MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ + struct timer_list timer; + struct timer_list TMtimer; /* Timer for TM commands ONLY */ + /* Pool of memory for holding SCpnts before doing + * OS callbacks. freeQ is the free pool. + */ + u8 *memQ; + DONE_Q_TRACKER freeQ; + DONE_Q_TRACKER doneQ; /* Holds Linux formmatted requests */ + DONE_Q_TRACKER pendingQ; /* Holds MPI formmatted requests */ + MPT_Q_TRACKER taskQ; /* TM request Q */ + spinlock_t freedoneQlock; + int taskQcnt; + u8 numTMrequests; + u8 tmPending; + u8 resetPending; + u8 is_spi; /* Parallel SCSI i/f */ + u8 negoNvram; /* DV disabled, nego NVRAM */ + u8 is_multipath; /* Multi-path compatible */ + u8 rsvd[2]; + MPT_FRAME_HDR *tmPtr; /* Ptr to TM request*/ + MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ + struct scsi_cmnd *abortSCpnt; + MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ +} MPT_SCSI_HOST; + +/* + * Structure for overlaying onto scsi_cmnd->SCp area + * NOTE: SCp area is 36 bytes min, 44 bytes max? + */ +typedef struct _scPrivate { + struct scsi_cmnd *forw; + struct scsi_cmnd *back; + void *p1; + void *p2; + u8 io_path_id; /* DMP */ + u8 pad[7]; +} scPrivate; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * More Dynamic Multi-Pathing stuff... + */ + +/* Forward decl, a strange C thing, to prevent gcc compiler warnings */ +struct scsi_cmnd; /* - * MPT Control IOCTLs and structures + * DMP service layer structure / API interface */ -#define MPT_MAGIC_NUMBER 'm' -#define MPTRWPERF _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w) -#define MPTRWPERF_CHK _IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w) -#define MPTRWPERF_RESET _IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w) -#define MPTFWDOWNLOAD _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer) -#define MPTSCSICMD _IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd) - -/* - * Define something *vague* enough that caller doesn't - * really need to know anything about device parameters - * (blk_size, capacity, etc.) - */ -struct mpt_raw_r_w { - unsigned int iocnum; /* IOC unit number */ - unsigned int port; /* IOC port number */ - unsigned int target; /* SCSI Target */ - unsigned int lun; /* SCSI LUN */ - unsigned int iters; /* N iterations */ - unsigned short nblks; /* number of blocks per IO */ - unsigned short qdepth; /* max Q depth on this device */ - unsigned char range; /* 0-100% of FULL disk capacity, 0=use (nblks X iters) */ - unsigned char skip; /* % of disk to skip */ - unsigned char rdwr; /* 0-100%, 0=pure ReaDs, 100=pure WRites */ - unsigned char seqran; /* 0-100%, 0=pure SEQential, 100=pure RANdom */ - unsigned int cache_sz; /* In Kb! Optimize hits to N Kb cache size */ -}; - -struct mpt_fw_xfer { - unsigned int iocnum; /* IOC unit number */ -/* u8 flags;*/ /* Message flags - bit field */ - unsigned int fwlen; - void *bufp; /* Pointer to firmware buffer */ -}; - -struct mpt_scsi_cmd { - unsigned int iocnum; /* IOC unit number */ - unsigned int port; /* IOC port number */ - unsigned int target; /* SCSI Target */ - unsigned int lun; /* SCSI LUN */ - SCSIIORequest_t scsi_req; - SCSIIOReply_t scsi_reply; -}; - -struct mpt_ioctl_sanity { - unsigned int iocnum; -}; +typedef struct _DmpServices { + VirtDevTracker VdevList; + struct semaphore *Daemon; + int (*ScsiPathSelect) + (struct scsi_cmnd *, MPT_SCSI_HOST **hd, int *target, int *lun); + int (*DmpIoDoneChk) + (MPT_SCSI_HOST *, struct scsi_cmnd *, + SCSIIORequest_t *, + SCSIIOReply_t *); + void (*mptscsih_scanVlist) + (MPT_SCSI_HOST *, int portnum); + int (*ScsiAbort) + (struct scsi_cmnd *); + int (*ScsiBusReset) + (struct scsi_cmnd *); +} DmpServices_t; -#ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Generic structure passed to the base mpt_config function. + */ +typedef struct _x_config_parms { + Q_ITEM linkage; /* linked list */ + struct timer_list timer; /* timer function for this request */ + ConfigPageHeader_t *hdr; + dma_addr_t physAddr; + int wait_done; /* wait for this request */ + u32 pageAddr; /* properly formatted */ + u8 action; + u8 dir; + u8 timeout; /* seconds */ + u8 pad1; + u16 status; + u16 pad2; +} CONFIGPARMS; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Public entry points... */ @@ -524,21 +945,28 @@ extern void mpt_event_deregister(int cb_idx); extern int mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func); extern void mpt_reset_deregister(int cb_idx); -extern int mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable); +extern int mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable); extern void mpt_deregister_ascqops_strings(void); extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, int iocid); extern void mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); extern void mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); -extern int mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req); +extern int mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag); +extern int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag); extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); extern MPT_ADAPTER *mpt_adapter_find_first(void); extern MPT_ADAPTER *mpt_adapter_find_next(MPT_ADAPTER *prev); +extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); -extern void mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len); +extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); +extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); /* * Public data decl's... */ +extern MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS]; +extern struct proc_dir_entry *mpt_proc_root_dir; +extern DmpServices_t *DmpService; + extern int mpt_lan_index; /* needed by mptlan.c */ extern int mpt_stm_index; /* needed by mptstm.c */ @@ -563,7 +991,7 @@ #define offsetof(t, m) ((size_t) (&((t *)0)->m)) #endif -#if defined(__alpha__) || defined(__sparc_v9__) +#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) #define CAST_U32_TO_PTR(x) ((void *)(u64)x) #define CAST_PTR_TO_U32(x) ((u32)(u64)x) #else @@ -576,6 +1004,40 @@ ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET) ? 'T' : 't', \ ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN) ? 'L' : 'l', \ ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) ? 'B' : 'b' + +/* + * Shifted SGE Defines - Use in SGE with FlagsLength member. + * Otherwise, use MPI_xxx defines (refer to "lsi/mpi.h" header). + * Defaults: 32 bit SGE, SYSTEM_ADDRESS if direction bit is 0, read + */ +#define MPT_TRANSFER_IOC_TO_HOST (0x00000000) +#define MPT_TRANSFER_HOST_TO_IOC (0x04000000) +#define MPT_SGE_FLAGS_LAST_ELEMENT (0x80000000) +#define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000) +#define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000) +#define MPT_SGE_FLAGS_DIRECTION (0x04000000) +#define MPT_SGE_FLAGS_ADDRESSING (MPT_SGE_ADDRESS_SIZE << MPI_SGE_FLAGS_SHIFT) +#define MPT_SGE_FLAGS_END_OF_LIST (0x01000000) + +#define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000) +#define MPT_SGE_FLAGS_SIMPLE_ELEMENT (0x10000000) +#define MPT_SGE_FLAGS_CHAIN_ELEMENT (0x30000000) +#define MPT_SGE_FLAGS_ELEMENT_MASK (0x30000000) + +#define MPT_SGE_FLAGS_SSIMPLE_READ \ + (MPT_SGE_FLAGS_LAST_ELEMENT | \ + MPT_SGE_FLAGS_END_OF_BUFFER | \ + MPT_SGE_FLAGS_END_OF_LIST | \ + MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ + MPT_SGE_FLAGS_ADDRESSING | \ + MPT_TRANSFER_IOC_TO_HOST) +#define MPT_SGE_FLAGS_SSIMPLE_WRITE \ + (MPT_SGE_FLAGS_LAST_ELEMENT | \ + MPT_SGE_FLAGS_END_OF_BUFFER | \ + MPT_SGE_FLAGS_END_OF_LIST | \ + MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ + MPT_SGE_FLAGS_ADDRESSING | \ + MPT_TRANSFER_HOST_TO_IOC) /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif diff -urN linux-2.4.18/drivers/message/fusion/mptctl.c linux-2.4.19-pre5/drivers/message/fusion/mptctl.c --- linux-2.4.18/drivers/message/fusion/mptctl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/mptctl.c Sat Mar 30 22:55:39 2002 @@ -9,6 +9,12 @@ * This driver would not exist if not for Alan Cox's development * of the linux i2o driver. * + * A special thanks to Pamela Delaney (LSI Logic) for tons of work + * and countless enhancements while adding support for the 1030 + * chip family. Pam has been instrumental in the development of + * of the 2.xx.xx series fusion drivers, and her contributions are + * far too numerous to hope to list in one place. + * * A huge debt of gratitude is owed to David S. Miller (DaveM) * for fixing much of the stupid and broken stuff in the early * driver while porting to sparc64 platform. THANK YOU! @@ -18,16 +24,17 @@ * (plus Eddie's other helpful hints and insights) * * Thanks to Arnaldo Carvalho de Melo for finding and patching - * a potential memory leak in mpt_ioctl_do_fw_download(), + * a potential memory leak in mptctl_do_fw_download(), * and for some kmalloc insight:-) * * (see also mptbase.c) * - * Copyright (c) 1999-2001 LSI Logic Corporation + * Copyright (c) 1999-2002 LSI Logic Corporation * Originally By: Steven J. Ralston, Noah Romer - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.c,v 1.25.4.1 2001/08/24 20:07:06 sralston Exp $ + * $Id: mptctl.c,v 1.52 2002/02/27 18:44:24 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -79,11 +86,16 @@ #include #include -#include +#include /* needed for access to Scsi_Host struct */ +#include +#include /* for io_request_lock (spinlock) decl */ +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" #define COPYRIGHT "Copyright (c) 1999-2001 LSI Logic Corporation" -#define MODULEAUTHOR "Steven J. Ralston, Noah Romer" +#define MODULEAUTHOR "Steven J. Ralston, Noah Romer, Pamela Delaney" #include "mptbase.h" +#include "mptctl.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define my_NAME "Fusion MPT misc device (ioctl) driver" @@ -95,21 +107,59 @@ MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mptctl_id = -1; -static int rwperf_reset = 0; static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS]; +static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int mpt_ioctl_rwperf(unsigned long arg); -static int mpt_ioctl_rwperf_status(unsigned long arg); -static int mpt_ioctl_rwperf_reset(unsigned long arg); -static int mpt_ioctl_fw_download(unsigned long arg); -static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen); -static int mpt_ioctl_scsi_cmd(unsigned long arg); +struct buflist { + u8 *kptr; + int len; +}; + +/* + * Function prototypes. Called from OS entry point mptctl_ioctl. + * arg contents specific to function. + */ +static int mptctl_fw_download(unsigned long arg); +static int mptctl_getiocinfo (unsigned long arg); +static int mptctl_gettargetinfo (unsigned long arg); +static int mptctl_readtest (unsigned long arg); +static int mptctl_mpt_command (unsigned long arg); +static int mptctl_eventquery (unsigned long arg); +static int mptctl_eventenable (unsigned long arg); +static int mptctl_eventreport (unsigned long arg); +static int mptctl_replace_fw (unsigned long arg); + +static int mptctl_do_reset(unsigned long arg); + +static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int mptctl_cpq_getpciinfo(unsigned long arg); +static int mptctl_cpq_getdriver(unsigned long arg); +static int mptctl_cpq_ctlr_status(unsigned long arg); +static int mptctl_cpq_target_address(unsigned long arg); +static int mptctl_cpq_passthru(unsigned long arg); +static int mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass); + +/* + * Private function calls. + */ +static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local); +static int mptctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen); +static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags, + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); +static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma, + struct buflist *buflist, MPT_ADAPTER *ioc); +static void mptctl_timer_expired (unsigned long data); + +/* + * Reset Handler cleanup function + */ +static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -132,26 +182,27 @@ /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */ #define MAX_KMALLOC_SZ (128*1024) -struct buflist { - u8 *kptr; - int len; -}; - -#define myMAX_TARGETS (1<<4) -#define myMAX_LUNS (1<<3) -#define myMAX_T_MASK (myMAX_TARGETS-1) -#define myMAX_L_MASK (myMAX_LUNS-1) -static u8 DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; -static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; +#define MPT_IOCTL_DEFAULT_TIMEOUT 10 /* Default timeout value (seconds) */ static u32 fwReplyBuffer[16]; static pMPIDefaultReply_t ReplyMsg = NULL; -/* some private forw protos */ -static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags, - struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); -static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma, - struct buflist *buflist, MPT_ADAPTER *ioc); +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Function to return 0 if the sge Address member is 0 and + * non-zero else. Used in the mpt_do_fw_download routines. + */ +static inline int +mptctl_test_address(MptSge_t *sge) +{ +#ifdef __ia64__ + if ((sge->Address.Low) || (sge->Address.High)) + return 1; + else + return 0; +#else + return sge->Address; +#endif +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -159,7 +210,7 @@ * @ioc: Pointer to MPT adapter * @nonblock: boolean, non-zero if O_NONBLOCK is set * - * All of the mptctl commands can potentially sleep, which is illegal + * All of the ioctl commands can potentially sleep, which is illegal * with a spinlock held, thus we perform mutual exclusion here. * * Returns negative errno on error, or zero for success. @@ -167,16 +218,27 @@ static inline int mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) { - dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock)); + int rc = 0; + dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock)); +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ + if (!nonblock) { + if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + rc = -ERESTARTSYS; + } else { + rc = -EPERM; + } +#else if (nonblock) { if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id])) - return -EAGAIN; + rc = -EAGAIN; } else { if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) - return -ERESTARTSYS; + rc = -ERESTARTSYS; } - return 0; +#endif + dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); + return rc; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -189,18 +251,150 @@ static int mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - u8 targ; + char *sense_data; + int sz, req_index; + u16 iocStatus; + u8 cmd; + + dctlprintk((MYIOC_s_INFO_FMT ": mptctl_reply()!\n", ioc->name)); + if (req) + cmd = req->u.hdr.Function; + else + return 1; + + if (ioc->ioctl) { + /* If timer is not running, then an error occurred. + * A timeout will call the reset routine to reload the messaging + * queues. + * Main callback will free message and reply frames. + */ + if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) { + /* Delete this timer + */ + del_timer (&ioc->ioctl->timer); + ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; + + /* Set the overall status byte. Good if: + * IOC status is good OR if no reply and a SCSI IO request + */ + if (reply) { + /* Copy the reply frame (which much exist + * for non-SCSI I/O) to the IOC structure. + */ + dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n", + ioc->name, reply)); + memcpy(ioc->ioctl->ReplyFrame, reply, + MIN(ioc->reply_sz, 4*reply->u.reply.MsgLength)); + ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; + + /* Set the command status to GOOD if IOC Status is GOOD + * OR if SCSI I/O cmd and data underrun or recovered error. + */ + iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK; + if (iocStatus == MPI_IOCSTATUS_SUCCESS) + ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; + + if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || + (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { + if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || + (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; + } + } + + /* Copy the sense data - if present + */ + if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && + (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)){ + + sz = req->u.scsireq.SenseBufferLength; + req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); + memcpy(ioc->ioctl->sense, sense_data, sz); + ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; + } + } else if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || + (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; + } + + /* We are done, issue wake up + */ + ioc->ioctl->wait_done = 1; + wake_up (&mptctl_wait); + } else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) { + /* Two paths to FW DOWNLOAD! */ + // NOTE: Expects/requires non-Turbo reply! + dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n", + ioc->name)); + memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength)); + ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer; + } + } + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_timer_expired + * + * Call back for timer process. Used only for ioctl functionality. + * + */ +static void mptctl_timer_expired (unsigned long data) +{ + MPT_IOCTL *ioctl = (MPT_IOCTL *) data; + + dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n", + ioctl->ioc->id)); - //dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n")); + /* Issue a reset for this device. + * The IOC is not responding. + */ + mpt_HardResetHandler(ioctl->ioc, NO_SLEEP); + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_ioc_reset + * + * Clean-up functionality. Used only if there has been a + * reload of the FW due. + * + */ +static int +mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + MPT_IOCTL *ioctl = ioc->ioctl; + dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n", + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + + if (reset_phase == MPT_IOC_PRE_RESET){ + + /* Someone has called the reset handler to + * do a hard reset. No more replies from the FW. + * Delete the timer. + */ + if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){ + + /* Delete this timer + */ + del_timer(&ioctl->timer); + } - if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) { - targ = req->u.scsireq.TargetID & myMAX_T_MASK; - DevIosCount[targ][0]--; - } else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) { - // NOTE: Expects/requires non-Turbo reply! - dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n")); - memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength)); - ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer; + } else { + /* Set the status and continue IOCTL + * processing. All memory will be free'd + * by originating thread after wake_up is + * called. + */ + if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){ + ioctl->status = MPT_IOCTL_STATUS_DID_TIMEOUT; + + /* Wake up the calling process + */ + ioctl->wait_done = 1; + wake_up(&mptctl_wait); + } } return 1; @@ -208,7 +402,7 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * struct file_operations functionality. + * struct file_operations functionality. * Members: * llseek, write, read, ioctl, open, release */ @@ -234,63 +428,93 @@ static ssize_t mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr) { + printk(KERN_ERR MYNAM ": ioctl READ not yet supported\n"); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * MPT ioctl handler + * cmd - specify the particular IOCTL command to be issued + * arg - data specific to the command. Must not be null. */ static int -mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +mptctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct mpt_ioctl_sanity *usanity = (struct mpt_ioctl_sanity *) arg; - struct mpt_ioctl_sanity ksanity; + mpt_ioctl_header *uhdr = (mpt_ioctl_header *) arg; + mpt_ioctl_header khdr; int iocnum; unsigned iocnumX; int nonblock = (file->f_flags & O_NONBLOCK); int ret; MPT_ADAPTER *iocp = NULL; - dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n")); + dctlprintk(("mptctl_ioctl() called\n")); - if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) { - printk(KERN_ERR "%s::mpt_ioctl() @%d - " - "Unable to copy mpt_ioctl_sanity data @ %p\n", - __FILE__, __LINE__, (void*)usanity); + if (copy_from_user(&khdr, uhdr, sizeof(khdr))) { + printk(KERN_ERR "%s::mptctl_ioctl() @%d - " + "Unable to copy mpt_ioctl_header data @ %p\n", + __FILE__, __LINE__, (void*)uhdr); return -EFAULT; } ret = -ENXIO; /* (-6) No such device or address */ - /* Verify intended MPT adapter */ - iocnumX = ksanity.iocnum & 0xFF; + /* Test for Compaq-specific IOCTL's. + */ + if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) || + (cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) || + (cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS)) + return mptctl_compaq_ioctl(file, cmd, arg); + + /* Verify intended MPT adapter - set iocnum and the adapter + * pointer (iocp) + */ + iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n", + printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnumX); return -ENODEV; } + /* Handle those commands that are just returning + * information stored in the driver. + * These commands should never time out and are unaffected + * by TM and FW reloads. + */ + if (cmd == MPTIOCINFO) { + return mptctl_getiocinfo(arg); + } else if (cmd == MPTTARGETINFO) { + return mptctl_gettargetinfo(arg); + } else if (cmd == MPTTEST) { + return mptctl_readtest(arg); + } else if (cmd == MPTEVENTQUERY) { + return mptctl_eventquery(arg); + } else if (cmd == MPTEVENTENABLE) { + return mptctl_eventenable(arg); + } else if (cmd == MPTEVENTREPORT) { + return mptctl_eventreport(arg); + } else if (cmd == MPTFWREPLACE) { + return mptctl_replace_fw(arg); + } + + /* All of these commands require an interrupt or + * are unknown/illegal. + */ if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) return ret; - dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name)); + dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name)); switch(cmd) { - case MPTRWPERF: - ret = mpt_ioctl_rwperf(arg); - break; - case MPTRWPERF_CHK: - ret = mpt_ioctl_rwperf_status(arg); - break; - case MPTRWPERF_RESET: - ret = mpt_ioctl_rwperf_reset(arg); - break; case MPTFWDOWNLOAD: - ret = mpt_ioctl_fw_download(arg); + ret = mptctl_fw_download(arg); + break; + case MPTCOMMAND: + ret = mptctl_mpt_command(arg); break; - case MPTSCSICMD: - ret = mpt_ioctl_scsi_cmd(arg); + case MPTHARDRESET: + ret = mptctl_do_reset(arg); break; default: ret = -EINVAL; @@ -301,6 +525,36 @@ return ret; } +static int mptctl_do_reset(unsigned long arg) +{ + struct mpt_ioctl_diag_reset *urinfo = (struct mpt_ioctl_diag_reset *) arg; + struct mpt_ioctl_diag_reset krinfo; + MPT_ADAPTER *iocp; + + dctlprintk((KERN_INFO "mptctl_do_reset called.\n")); + + if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { + printk(KERN_ERR "%s@%d::mptctl_do_reset - " + "Unable to copy mpt_ioctl_diag_reset struct @ %p\n", + __FILE__, __LINE__, (void*)urinfo); + return -EFAULT; + } + + if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { + printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", + __FILE__, __LINE__, krinfo.hdr.iocnum); + return -ENXIO; /* (-6) No such device or address */ + } + + if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) { + printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", + __FILE__, __LINE__); + return -1; + } + + return 0; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mptctl_open(struct inode *inode, struct file *file) { @@ -317,13 +571,29 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT FW download function. Cast the arg into the mpt_fw_xfer structure. + * This structure contains: iocnum, firmware length (bytes), + * pointer to user space memory where the fw image is stored. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENXIO if no such device + * -EAGAIN if resource problem + * -ENOMEM if no memory for SGE + * -EMLINK if too many chain buffers required + * -EBADRQC if adapter does not support FW download + * -EBUSY if adapter is busy + * -ENOMSG if FW upload returned bad status + */ static int -mpt_ioctl_fw_download(unsigned long arg) +mptctl_fw_download(unsigned long arg) { struct mpt_fw_xfer *ufwdl = (struct mpt_fw_xfer *) arg; struct mpt_fw_xfer kfwdl; - dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc + dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { printk(KERN_ERR "%s@%d::_ioctl_fwdl - " "Unable to copy mpt_fw_xfer struct @ %p\n", @@ -331,44 +601,52 @@ return -EFAULT; } - return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); + return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * MPT FW Download + * FW Download engine. + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENXIO if no such device + * -EAGAIN if resource problem + * -ENOMEM if no memory for SGE + * -EMLINK if too many chain buffers required + * -EBADRQC if adapter does not support FW download + * -EBUSY if adapter is busy + * -ENOMSG if FW upload returned bad status */ static int -mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen) +mptctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen) { FWDownload_t *dlmsg; MPT_FRAME_HDR *mf; MPT_ADAPTER *iocp; -// char *fwbuf; -// dma_addr_t fwbuf_dma; - FWDownloadTCSGE_t *fwVoodoo; -// SGEAllUnion_t *fwSgl; + FWDownloadTCSGE_t *ptsge; + MptSge_t *sgl; + MptSge_t *sgOut, *sgIn; + struct buflist *buflist; + struct buflist *bl; + dma_addr_t sgl_dma; int ret; - - SGESimple32_t *sgl; - SGESimple32_t *sgOut, *sgIn; - dma_addr_t sgl_dma; - struct buflist *buflist = NULL; - struct buflist *bl = NULL; - int numfrags = 0; - int maxfrags; - int n = 0; - u32 sgdir; - u32 nib; - int fw_bytes_copied = 0; - u16 iocstat; - int i; - - dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); - - dprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf)); - dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen)); - dprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); + int numfrags = 0; + int maxfrags; + int n = 0; + u32 sgdir; + u32 nib; + int fw_bytes_copied = 0; + int i; + int cntdn; + int sge_offset = 0; + u16 iocstat; + + dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); + + dctlprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf)); + dctlprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen)); + dctlprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n", @@ -376,11 +654,13 @@ return -ENXIO; /* (-6) No such device or address */ } + /* Valid device. Get a message frame and construct the FW download message. + */ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) return -EAGAIN; dlmsg = (FWDownload_t*) mf; - fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL; - sgOut = (SGESimple32_t *) (fwVoodoo + 1); + ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL; + sgOut = (MptSge_t *) (ptsge + 1); /* * Construct f/w download request @@ -392,27 +672,36 @@ dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0; dlmsg->MsgFlags = 0; - fwVoodoo->Reserved = 0; - fwVoodoo->ContextSize = 0; - fwVoodoo->DetailsLength = 12; - fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; - fwVoodoo->Reserved1 = 0; - fwVoodoo->ImageOffset = 0; - fwVoodoo->ImageSize = cpu_to_le32(fwlen); + /* Set up the Transaction SGE. + */ + ptsge->Reserved = 0; + ptsge->ContextSize = 0; + ptsge->DetailsLength = 12; + ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; + ptsge->Reserved_0100_Checksum = 0; + ptsge->ImageOffset = 0; + ptsge->ImageSize = cpu_to_le32(fwlen); + + /* Add the SGL + */ /* * Need to kmalloc area(s) for holding firmware image bytes. * But we need to do it piece meal, using a proper * scatter gather list (with 128kB MAX hunks). - * + * * A practical limit here might be # of sg hunks that fit into * a single IOC request frame; 12 or 8 (see below), so: * For FC9xx: 12 x 128kB == 1.5 mB (max) * For C1030: 8 x 128kB == 1 mB (max) * We could support chaining, but things get ugly(ier:) + * + * Set the sge_offset to the start of the sgl (bytes). */ sgdir = 0x04000000; /* IOC will READ from sys mem */ - if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) + sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t); + if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset, + &numfrags, &buflist, &sgl_dma, iocp)) == NULL) return -ENOMEM; /* @@ -420,16 +709,19 @@ * for FC9xx f/w image, but calculate max number of sge hunks * we can fit into a request frame, and limit ourselves to that. * (currently no chain support) - * For FC9xx: (128-12-16)/8 = 12.5 = 12 - * For C1030: (96-12-16)/8 = 8.5 = 8 + * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE + * Request maxfrags + * 128 12 + * 96 8 + * 64 4 */ - maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t); + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(MptSge_t); if (numfrags > maxfrags) { ret = -EMLINK; goto fwdl_out; } - dprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); + dctlprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); /* * Parse SG list, copying sgl itself, @@ -439,11 +731,17 @@ sgIn = sgl; bl = buflist; for (i=0; i < numfrags; i++) { - nib = (le32_to_cpu(sgIn->FlagsLength) & 0xF0000000) >> 28; - /* skip ignore/chain. */ + + /* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE + * Skip everything but Simple. If simple, copy from + * user space into kernel space. + * Note: we should not have anything but Simple as + * Chain SGE are illegal. + */ + nib = (le32_to_cpu(sgIn->FlagsLength) & 0x30000000) >> 28; if (nib == 0 || nib == 3) { ; - } else if (sgIn->Address) { + } else if (mptctl_test_address(sgIn)) { *sgOut = *sgIn; n++; if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { @@ -478,26 +776,24 @@ /* * Wait until the reply has been received */ - { - int foo = 0; - - while (ReplyMsg == NULL) { - if (!(foo%1000000)) { - dprintk((KERN_INFO "DbG::_do_fwdl: " - "In ReplyMsg loop - iteration %d\n", - foo)); //tc - } + for (cntdn=HZ*60, i=1; ReplyMsg == NULL; cntdn--, i++) { + if (!cntdn) { ret = -ETIME; - if (++foo > 60000000) - goto fwdl_out; - mb(); - schedule(); - barrier(); + goto fwdl_out; } + + if (!(i%HZ)) { + dctlprintk((KERN_INFO "DbG::_do_fwdl: " + "In ReplyMsg loop - iteration %d\n", + i)); + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); } if (sgl) - kfree_sgl(sgl, sgl_dma, buflist, iocp); + kfree_sgl(sgl, sgl_dma, buflist, iocp); iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { @@ -527,32 +823,46 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * NEW rwperf (read/write performance) stuff starts here... + * SGE Allocation routine + * + * Inputs: bytes - number of bytes to be transferred + * sgdir - data direction + * sge_offset - offset (in bytes) from the start of the request + * frame to the first SGE + * ioc - pointer to the mptadapter + * Outputs: frags - number of scatter gather elements + * blp - point to the buflist pointer + * sglbuf_dma - pointer to the (dma) sgl + * Returns: Null if failes + * pointer to the (virtual) sgl if successful. */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static SGESimple32_t * -kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags, +static MptSge_t * +kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc) { - SGESimple32_t *sglbuf = NULL; - struct buflist *buflist = NULL; + MptSge_t *sglbuf = NULL; /* pointer to array of SGE + * and chain buffers */ + struct buflist *buflist = NULL; /* kernel routine */ + MptSge_t *sgl; + MptChain_t *last_chain = NULL; int numfrags = 0; int fragcnt = 0; int alloc_sz = MIN(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg! int bytes_allocd = 0; int this_alloc; - SGESimple32_t *sgl; - u32 pa; // phys addr - SGEChain32_t *last_chain = NULL; - SGEChain32_t *old_chain = NULL; + dma_addr_t pa; // phys addr int chaincnt = 0; int i, buflist_ent; int sg_spill = MAX_FRAGS_SPILL1; int dir; + /* initialization */ *frags = 0; *blp = NULL; + + /* Allocate and initialize an array of kernel + * structures for the SG elements. + */ i = MAX_SGL_BYTES / 8; buflist = kmalloc(i, GFP_USER); if (buflist == NULL) @@ -560,6 +870,11 @@ memset(buflist, 0, i); buflist_ent = 0; + /* Allocate a single block of memory to store the sg elements and + * the chain buffers. The calling routine is responsible for + * copying the data in this array into the correct place in the + * request and chain buffers. + */ sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma); if (sglbuf == NULL) goto free_and_fail; @@ -569,7 +884,15 @@ else dir = PCI_DMA_FROMDEVICE; + /* At start: + * sgl = sglbuf = point to beginning of sg buffer + * buflist_ent = 0 = first kernel structure + * sg_spill = number of SGE that can be written before the first + * chain element. + * + */ sgl = sglbuf; + sg_spill = ((ioc->req_sz - sge_offset)/ sizeof(MptSge_t)) - 1; while (bytes_allocd < bytes) { this_alloc = MIN(alloc_sz, bytes-bytes_allocd); buflist[buflist_ent].len = this_alloc; @@ -594,7 +917,7 @@ /* Write one SIMPLE sge */ sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc); dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); - sgl->Address = cpu_to_le32(dma_addr); + cpu_to_leXX(dma_addr, sgl->Address); fragcnt++; numfrags++; @@ -609,24 +932,43 @@ if (fragcnt == sg_spill) { dma_addr_t chain_link; - if (last_chain != NULL) - last_chain->NextChainOffset = 0x1E; - - fragcnt = 0; - sg_spill = MAX_FRAGS_SPILL2; + /* If there is a chain element, set the offset + * (in 32 bit words) to the next chain element. + * fragcnt = # sge = 8 bytes = 2 words + * + * Set the length of the chain element (bytes) + * This includes the size of the next chain element. + * + * We are now done with last_chain and the previous + * buffer. + */ + if (last_chain != NULL) { + last_chain->NextChainOffset = fragcnt * 2; + last_chain->Length = cpu_to_le16((fragcnt+1) * 8); + } - /* fixup previous SIMPLE sge */ + /* Finish the current buffer: + * - add the LE bit to last sge + * - add the chain element + */ sgl[-1].FlagsLength |= cpu_to_le32(0x80000000); chain_link = (*sglbuf_dma) + ((u8 *)(sgl+1) - (u8 *)sglbuf); /* Write one CHAIN sge */ - sgl->FlagsLength = cpu_to_le32(0x30000080); - sgl->Address = cpu_to_le32(chain_link); +// sgl->FlagsLength = cpu_to_le32(0x30000080); + sgl->FlagsLength = cpu_to_le32(0x30000000); + cpu_to_leXX(chain_link, sgl->Address); + + /* Reset everything for the next SGE series, + * save a ptr to the chain element in last_chain + */ + fragcnt = 0; +// sg_spill = MAX_FRAGS_SPILL2; + sg_spill = (ioc->req_sz / sizeof(MptSge_t)) - 1; - old_chain = last_chain; - last_chain = (SGEChain32_t*)sgl; + last_chain = (MptChain_t*)sgl; chaincnt++; numfrags++; sgl++; @@ -646,18 +988,19 @@ /* Last sge fixup: set LE+eol+eob bits */ sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000); - /* Chain fixup needed? */ - if (last_chain != NULL && fragcnt < 16) + /* Chain fixup needed? */ /* SteveR CHECKME!!! */ +// if (last_chain != NULL && fragcnt < 16) + if (last_chain != NULL) last_chain->Length = cpu_to_le16(fragcnt * 8); *frags = numfrags; *blp = buflist; - dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " "%d SG frags generated! (%d CHAIN%s)\n", numfrags, chaincnt, chaincnt>1?"s":"")); - dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " "last (big) alloc_sz=%d\n", alloc_sz)); @@ -675,7 +1018,7 @@ if ((le32_to_cpu(sglbuf[i].FlagsLength) >> 24) == 0x30) continue; - dma_addr = le32_to_cpu(sglbuf[i].Address); + leXX_to_cpu(dma_addr, sglbuf[i].Address); kptr = buflist[i].kptr; len = buflist[i].len; @@ -688,16 +1031,19 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Routine to free the SGL elements. + */ static void -kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc) +kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc) { - SGESimple32_t *sg = sgl; + MptSge_t *sg = sgl; struct buflist *bl = buflist; u32 nib; int dir; int n = 0; - if (le32_to_cpu(sg->FlagsLength) & 0x04000000) + if ((le32_to_cpu(sg->FlagsLength) & 0x04000000)) dir = PCI_DMA_TODEVICE; else dir = PCI_DMA_FROMDEVICE; @@ -707,12 +1053,12 @@ /* skip ignore/chain. */ if (nib == 0 || nib == 3) { ; - } else if (sg->Address) { + } else if (mptctl_test_address(sg)) { dma_addr_t dma_addr; void *kptr; int len; - dma_addr = le32_to_cpu(sg->Address); + leXX_to_cpu(dma_addr, sg->Address); kptr = bl->kptr; len = bl->len; pci_unmap_single(ioc->pcidev, dma_addr, len, dir); @@ -725,12 +1071,12 @@ } /* we're at eob! */ - if (sg->Address) { + if (mptctl_test_address(sg)) { dma_addr_t dma_addr; void *kptr; int len; - dma_addr = le32_to_cpu(sg->Address); + leXX_to_cpu(dma_addr, sg->Address); kptr = bl->kptr; len = bl->len; pci_unmap_single(ioc->pcidev, dma_addr, len, dir); @@ -740,392 +1086,1686 @@ pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); kfree(buflist); - dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); + dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_getiocinfo - Query the host adapter for IOC information. + * @arg: User space argument + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ static int -mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src, - char *caller, MPT_ADAPTER **iocpp) +mptctl_getiocinfo (unsigned long arg) { - char *myname = "_rwperf_init()"; - int ioc; + struct mpt_ioctl_iocinfo *uarg = (struct mpt_ioctl_iocinfo *) arg; + struct mpt_ioctl_iocinfo karg; + MPT_ADAPTER *ioc; + struct pci_dev *pdev; + struct Scsi_Host *sh; + MPT_SCSI_HOST *hd; + int iocnum; + int numDevices = 0; + unsigned int max_id; + int ii; + int port; + u8 revision; + + dctlprintk((": mptctl_getiocinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_iocinfo))) { + printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } - /* get copy of structure passed from user space */ - if (copy_from_user(dest, (void*)src, sizeof(*dest))) { - printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n", - myname, __LINE__, (void*)src); - return -EFAULT; /* (-14) Bad address */ - } else { - dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}" - ": %d %d %d %d %d\n", - dest->iocnum, dest->target, - (int)dest->qdepth, dest->iters, dest->nblks )); - dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}" - ": %d %d %d %d %d\n", - dest->cache_sz, dest->skip, dest->range, - dest->rdwr, dest->seqran )); - - /* Get the MPT adapter id. */ - if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) { - printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n", - myname, __LINE__, dest->iocnum); - return -ENXIO; /* (-6) No such device or address */ - } else { - dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n", - caller, dest->iocnum, dest->target)); - } + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; } - return ioc; -} + /* Verify the data transfer size is correct. + * Ignore the port setting. + */ + if (karg.hdr.maxDataSize != sizeof(struct mpt_ioctl_iocinfo)) { + printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + "Structure size mismatch. Command not completed.\n", + __FILE__, __LINE__); + return -EFAULT; + } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* Fill in the data and return the structure to the calling + * program + */ + if (ioc->chip_type == C1030) + karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; + else + karg.adapterType = MPT_IOCTL_INTERFACE_FC; -/* Treat first N blocks of disk as sacred! */ -#define SACRED_BLOCKS 100 - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int -mpt_ioctl_rwperf(unsigned long arg) -{ - struct mpt_raw_r_w kPerfInfo; - /* NOTE: local copy, on stack==KERNEL_SPACE! */ - u8 target, targetM; - u8 lun, lunM; - u8 scsiop; - int qdepth; - int iters; - int cache_sz; - u32 xferbytes; - u32 scsidir; - u32 qtag; - u32 scsictl; - u32 sgdir; - u32 blkno; - u32 sbphys; - SGESimple32_t *sgl; - dma_addr_t sgl_dma; - struct buflist *buflist; - SGESimple32_t *sgOut, *sgIn; - int numfrags; - u32 *msg; - int i; - int ioc; - MPT_FRAME_HDR *mf; - MPT_ADAPTER *iocp; - int sgfragcpycnt; - int blklo, blkhi; - u8 nextchainoffset; - u8 *SenseBuf; - dma_addr_t SenseBufDMA; - char *myname = "_rwperf()"; - - dprintk((KERN_INFO "%s - starting...\n", myname)); - - /* Validate target device */ - if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) - return ioc; - - /* Allocate DMA'able memory for the sense buffer. */ - SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA); - - /* set perf parameters from input */ - target = kPerfInfo.target & 0x0FF; - targetM = target & myMAX_T_MASK; - lun = kPerfInfo.lun & 0x1F; // LUN=31 max - lunM = lun & myMAX_L_MASK; - qdepth = kPerfInfo.qdepth; - iters = kPerfInfo.iters; - xferbytes = ((u32)kPerfInfo.nblks)<<9; - - DevInUse[targetM][lunM] = 1; - DevIosCount[targetM][lunM] = 0; - - cache_sz = kPerfInfo.cache_sz * 1024; // CacheSz in kB! - - /* ToDo: */ - /* get capacity (?) */ - - - // pre-build, one time, everything we can for speed in the loops below... - - scsiop = 0x28; // default to SCSI READ! - scsidir = MPI_SCSIIO_CONTROL_READ; // DATA IN (host<--ioc<--dev) - // 02000000 - qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; // 00000000 - - if (xferbytes == 0) { - // Do 0-byte READ!!! - // IMPORTANT! Need to set no SCSI DIR for this! - scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; - } - - scsictl = scsidir | qtag; - - /* - * Set sgdir for DMA transfer. - */ -// sgdir = 0x04000000; // SCSI WRITE - sgdir = 0x00000000; // SCSI READ - - if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) - return -ENOMEM; - - sgfragcpycnt = MIN(10,numfrags); - nextchainoffset = 0; - if (numfrags > 10) - nextchainoffset = 0x1E; - - sbphys = SenseBufDMA; - - rwperf_reset = 0; - -// do { // target-loop - - blkno = SACRED_BLOCKS; // Treat first N blocks as sacred! - // FIXME! Skip option - blklo = blkno; - blkhi = blkno; - - do { // inner-loop - - while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { - mb(); - schedule(); - barrier(); - } - msg = (u32*)mf; - - /* Start piecing the SCSIIORequest together */ - msg[0] = 0x00000000 | nextchainoffset<<16 | target; - msg[1] = 0x0000FF0A; // 255 sense bytes, 10-byte CDB! - msg[3] = lun << 8; - msg[4] = 0; - msg[5] = scsictl; - - // 16 bytes of CDB @ msg[6,7,8,9] are below... - - msg[6] = ( ((blkno & 0xFF000000) >> 8) - | ((blkno & 0x00FF0000) << 8) - | scsiop ); - msg[7] = ( (((u32)kPerfInfo.nblks & 0x0000FF00) << 16) - | ((blkno & 0x000000FF) << 8) - | ((blkno & 0x0000FF00) >> 8) ); - msg[8] = (kPerfInfo.nblks & 0x00FF); - msg[9] = 0; - - msg[10] = xferbytes; - -// msg[11] = 0xD0000100; -// msg[12] = sbphys; -// msg[13] = 0; - msg[11] = sbphys; - - // Copy the SGL... - if (xferbytes) { - sgOut = (SGESimple32_t*)&msg[12]; - sgIn = sgl; - for (i=0; i < sgfragcpycnt; i++) - *sgOut++ = *sgIn++; - } - - // fubar! QueueDepth issue!!! - while ( !rwperf_reset - && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) ) - { - mb(); - schedule(); - barrier(); - } - -// blkno += kPerfInfo.nblks; -// EXP Stuff! -// Try optimizing to certain cache size for the target! -// by keeping blkno within cache range if at all possible -#if 0 - if ( cache_sz - && ((2 * kPerfInfo.nblks) <= (cache_sz>>9)) - && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) - blkno = SACRED_BLOCKS; - else - blkno += kPerfInfo.nblks; -#endif -// Ok, cheat! - if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) - blkno = SACRED_BLOCKS; - else - blkno += kPerfInfo.nblks; + port = karg.hdr.port; + + karg.port = port; + pdev = (struct pci_dev *) ioc->pcidev; - if (blkno > blkhi) - blkhi = blkno; + karg.pciId = pdev->device; + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + karg.hwRev = revision; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + karg.subSystemDevice = pdev->subsystem_device; + karg.subSystemVendor = pdev->subsystem_vendor; +#endif - DevIosCount[targetM][lunM]++; + /* Get number of devices + */ + if ( (sh = ioc->sh) != NULL) { + + /* sh->max_id = maximum target ID + 1 + */ + max_id = sh->max_id - 1; + hd = (MPT_SCSI_HOST *) sh->hostdata; + + /* Check all of the target structures and + * keep a counter. + */ + if (hd && hd->Targets) { + for (ii = 0; ii <= max_id; ii++) { + if (hd->Targets[ii]) + numDevices++; + } + } + } + karg.numDevices = numDevices; - /* - * Finally, post the request - */ - mpt_put_msg_frame(mptctl_id, ioc, mf); + /* Set the BIOS and FW Version + */ + karg.FWVersion = ioc->facts.FWVersion.Word; + karg.BIOSVersion = ioc->biosVersion; + /* Set the Version Strings. + */ + strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); - /* let linux breath! */ - mb(); - schedule(); - barrier(); + karg.busChangeEvent = 0; + karg.hostId = ioc->pfacts[port].PortSCSIID; + karg.rsvd[0] = karg.rsvd[1] = 0; - //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters)); + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(struct mpt_ioctl_iocinfo))) { + printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } - } while ((--iters > 0) && !rwperf_reset); + return 0; +} - dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi)); - dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target)); +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_gettargetinfo - Query the host adapter for target information. + * @arg: User space argument + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ +static int +mptctl_gettargetinfo (unsigned long arg) +{ + struct mpt_ioctl_targetinfo *uarg = (struct mpt_ioctl_targetinfo *) arg; + struct mpt_ioctl_targetinfo karg; + MPT_ADAPTER *ioc; + struct Scsi_Host *sh; + MPT_SCSI_HOST *hd; + char *pmem; + int *pdata; + int iocnum; + int numDevices = 0; + unsigned int max_id; + int ii, jj, lun; + int maxWordsLeft; + int numBytes; + u8 port; + + dctlprintk(("mptctl_gettargetinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { + printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + "Unable to read in mpt_ioctl_targetinfo struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } -// // TEMPORARY! -// target = 0; + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } -// } while (target); + /* Get the port number and set the maximum number of bytes + * in the returned structure. + * Ignore the port setting. + */ + numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); + maxWordsLeft = numBytes/sizeof(int); + port = karg.hdr.port; + + if (maxWordsLeft <= 0) { + printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + __FILE__, __LINE__); + return -ENOMEM; + } + /* Fill in the data and return the structure to the calling + * program + */ - if (DevIosCount[targetM][lunM]) { - dprintk((KERN_INFO " DbG: DevIosCount[%d][%d]=%d\n", - targetM, lunM, DevIosCount[targetM][lunM])); - } + /* struct mpt_ioctl_targetinfo does not contain sufficient space + * for the target structures so when the IOCTL is called, there is + * not sufficient stack space for the structure. Allocate memory, + * populate the memory, copy back to the user, then free memory. + * targetInfo format: + * bits 31-24: reserved + * 23-16: LUN + * 15- 8: Bus Number + * 7- 0: Target ID + */ + pmem = kmalloc(numBytes, GFP_KERNEL); + if (pmem == NULL) { + printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + __FILE__, __LINE__); + return -ENOMEM; + } + memset(pmem, 0, numBytes); + pdata = (int *) pmem; - while (DevIosCount[targetM][lunM]) { - //dprintk((KERN_DEBUG " DbG: Waiting... DevIosCount[%d][%d]=%d\n", - // targetM, lunM, DevIosCount[targetM][lunM])); - mb(); - schedule(); - barrier(); - } - DevInUse[targetM][lunM] = 0; + /* Get number of devices + */ + if ( (sh = ioc->sh) != NULL) { + + max_id = sh->max_id - 1; + hd = (MPT_SCSI_HOST *) sh->hostdata; + + /* Check all of the target structures. + * Save the Id and increment the counter, + * if ptr non-null. + * sh->max_id = maximum target ID + 1 + */ + if (hd && hd->Targets) { + ii = 0; + while (ii <= max_id) { + if (hd->Targets[ii]) { + for (jj = 0; jj <= MPT_LAST_LUN; jj++) { + lun = (1 << jj); + if (hd->Targets[ii]->luns & lun) { + numDevices++; + *pdata = (jj << 16) | ii; + --maxWordsLeft; + + pdata++; + + if (maxWordsLeft <= 0) { + break; + } + } + } + } + ii++; + } + } + } + karg.numDevices = numDevices; - pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA); + /* Copy part of the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(struct mpt_ioctl_targetinfo))) { + printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + kfree(pmem); + return -EFAULT; + } - if (sgl) - kfree_sgl(sgl, sgl_dma, buflist, iocp); + /* Copy the remaining data from kernel memory to user memory + */ + if (copy_to_user((char *) uarg->targetInfo, pmem, numBytes)) { + printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", + __FILE__, __LINE__, (void*)pdata); + kfree(pmem); + return -EFAULT; + } - dprintk((KERN_INFO " *** done ***\n")); + kfree(pmem); - return 0; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* MPT IOCTL Test function. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ static int -mpt_ioctl_rwperf_status(unsigned long arg) +mptctl_readtest (unsigned long arg) { - struct mpt_raw_r_w kPerfInfo; - /* NOTE: local copy, on stack==KERNEL_SPACE! */ - MPT_ADAPTER *iocp; - int ioc; -// u8 targ; -// u8 lun; - int T, L; - char *myname = "_rwperf_status()"; + struct mpt_ioctl_test *uarg = (struct mpt_ioctl_test *) arg; + struct mpt_ioctl_test karg; + MPT_ADAPTER *ioc; + int iocnum; + dctlprintk(("mptctl_readtest called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { + printk(KERN_ERR "%s@%d::mptctl_readtest - " + "Unable to read in mpt_ioctl_test struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } - dprintk((KERN_INFO "%s - starting...\n", myname)); + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } - /* Get a pointer to the MPT adapter. */ - if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) - return ioc; + /* Fill in the data and return the structure to the calling + * program + */ - /* set perf parameters from input */ -// targ = kPerfInfo.target & 0xFF; -// lun = kPerfInfo.lun & 0x1F; +#ifdef MFCNT + karg.chip_type = ioc->mfcnt; +#else + karg.chip_type = ioc->chip_type; +#endif + strncpy (karg.name, ioc->name, MPT_MAX_NAME); + strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); - for (T=0; T < myMAX_TARGETS; T++) - for (L=0; L < myMAX_LUNS; L++) - if (DevIosCount[T][L]) { - printk(KERN_INFO "%s: ioc%d->00:%02x:%02x" - ", IosCnt=%d\n", - myname, ioc, T, L, DevIosCount[T][L] ); - } + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_test))) { + printk(KERN_ERR "%s@%d::mptctl_readtest - " + "Unable to write out mpt_ioctl_test struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_eventquery - Query the host adapter for the event types + * that are being logged. + * @arg: User space argument + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ static int -mpt_ioctl_rwperf_reset(unsigned long arg) +mptctl_eventquery (unsigned long arg) { - struct mpt_raw_r_w kPerfInfo; - /* NOTE: local copy, on stack==KERNEL_SPACE! */ - MPT_ADAPTER *iocp; - int ioc; -// u8 targ; -// u8 lun; - int T, L; - int i; - char *myname = "_rwperf_reset()"; - - dprintk((KERN_INFO "%s - starting...\n", myname)); - - /* Get MPT adapter id. */ - if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) - return ioc; - - /* set perf parameters from input */ -// targ = kPerfInfo.target & 0xFF; -// lun = kPerfInfo.lun & 0x1F; - - rwperf_reset = 1; - for (i=0; i < 1000000; i++) { - mb(); - schedule(); - barrier(); - } - rwperf_reset = 0; - - for (T=0; T < myMAX_TARGETS; T++) - for (L=0; L < myMAX_LUNS; L++) - if (DevIosCount[T][L]) { - printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, " - "IosCnt RESET! (from %d to 0)\n", - myname, ioc, T, L, DevIosCount[T][L] ); - DevIosCount[T][L] = 0; - DevInUse[T][L] = 0; - } + struct mpt_ioctl_eventquery *uarg = (struct mpt_ioctl_eventquery *) arg; + struct mpt_ioctl_eventquery karg; + MPT_ADAPTER *ioc; + int iocnum; + + dctlprintk(("mptctl_eventquery called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { + printk(KERN_ERR "%s@%d::mptctl_eventquery - " + "Unable to read in mpt_ioctl_eventquery struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + karg.eventEntries = ioc->eventLogSize; + karg.eventTypes = ioc->eventTypes; + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) { + printk(KERN_ERR "%s@%d::mptctl_eventquery - " + "Unable to write out mpt_ioctl_eventquery struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mpt_ioctl_scsi_cmd(unsigned long arg) +mptctl_eventenable (unsigned long arg) { - return -ENOSYS; + struct mpt_ioctl_eventenable *uarg = (struct mpt_ioctl_eventenable *) arg; + struct mpt_ioctl_eventenable karg; + MPT_ADAPTER *ioc; + int iocnum; + + dctlprintk(("mptctl_eventenable called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { + printk(KERN_ERR "%s@%d::mptctl_eventenable - " + "Unable to read in mpt_ioctl_eventenable struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + if (ioc->events == NULL) { + /* Have not yet allocated memory - do so now. + */ + int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + ioc->events = kmalloc(sz, GFP_KERNEL); + if (ioc->events == NULL) { + printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); + return -ENOMEM; + } + memset(ioc->events, 0, sz); + ioc->alloc_total += sz; + + ioc->eventLogSize = MPTCTL_EVENT_LOG_SIZE; + ioc->eventContext = 0; + } + + /* Update the IOC event logging flag. + */ + ioc->eventTypes = karg.eventTypes; + + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptctl_eventreport (unsigned long arg) +{ + struct mpt_ioctl_eventreport *uarg = (struct mpt_ioctl_eventreport *) arg; + struct mpt_ioctl_eventreport karg; + MPT_ADAPTER *ioc; + int iocnum; + int numBytes, maxEvents, max; + + dctlprintk(("mptctl_eventreport called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { + printk(KERN_ERR "%s@%d::mptctl_eventreport - " + "Unable to read in mpt_ioctl_eventreport struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51) -#define owner_THIS_MODULE owner: THIS_MODULE, -#else -#define owner_THIS_MODULE -#endif + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } -static struct file_operations mptctl_fops = { - owner_THIS_MODULE - llseek: no_llseek, - read: mptctl_read, - write: mptctl_write, - ioctl: mpt_ioctl, - open: mptctl_open, - release: mptctl_release, -}; + numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); + maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS); -static struct miscdevice mptctl_miscdev = { - MPT_MINOR, - MYNAM, - &mptctl_fops -}; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + max = ioc->eventLogSize < maxEvents ? ioc->eventLogSize : maxEvents; -#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ + /* If fewer than 1 event is requested, there must have + * been some type of error. + */ + if ((max < 1) || !ioc->events) + return -ENODATA; -/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */ + /* Copy the data from kernel memory to user memory + */ + numBytes = max * sizeof(MPT_IOCTL_EVENTS); + if (copy_to_user((char *) uarg->eventData, ioc->events, numBytes)) { + printk(KERN_ERR "%s@%d::mptctl_eventreport - " + "Unable to write out mpt_ioctl_eventreport struct @ %p\n", + __FILE__, __LINE__, (void*)ioc->events); + return -EFAULT; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptctl_replace_fw (unsigned long arg) +{ + struct mpt_ioctl_replace_fw *uarg = (struct mpt_ioctl_replace_fw *) arg; + struct mpt_ioctl_replace_fw karg; + MPT_ADAPTER *ioc; + int iocnum; + u8 *mem = NULL; + dma_addr_t mem_dma; + int oldFwSize, newFwSize; + + dctlprintk(("mptctl_replace_fw called.\n")); + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { + printk(KERN_ERR "%s@%d::mptctl_replace_fw - " + "Unable to read in mpt_ioctl_replace_fw struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + /* If not caching FW, return 0 + */ + if ((ioc->FWImage == NULL) && (ioc->alt_ioc) && (ioc->alt_ioc->FWImage == NULL)) { + return 0; + } + + + /* Allocate memory for the new FW image + */ + newFwSize = karg.newImageSize; + mem = pci_alloc_consistent(ioc->pcidev, newFwSize, &mem_dma); + if (mem == NULL) + return -ENOMEM; + + ioc->alloc_total += newFwSize; + + /* Copy the data from user memory to kernel space + */ + if (copy_from_user(mem, uarg->newImage, newFwSize)) { + printk(KERN_ERR "%s@%d::mptctl_replace_fw - " + "Unable to read in mpt_ioctl_replace_fw image @ %p\n", + __FILE__, __LINE__, (void*)uarg); + pci_free_consistent(ioc->pcidev, newFwSize, mem, mem_dma); + ioc->alloc_total -= newFwSize; + return -EFAULT; + } + + /* Free the old FW image + */ + oldFwSize = ioc->facts.FWImageSize; + if (ioc->FWImage) { + pci_free_consistent(ioc->pcidev, oldFwSize, ioc->FWImage, ioc->FWImage_dma); + ioc->alloc_total -= oldFwSize; + ioc->FWImage = mem; + ioc->FWImage_dma = mem_dma; + + } else if ((ioc->alt_ioc) && (ioc->alt_ioc->FWImage)) { + pci_free_consistent(ioc->pcidev, oldFwSize, ioc->alt_ioc->FWImage, ioc->alt_ioc->FWImage_dma); + ioc->alloc_total -= oldFwSize; + ioc->alt_ioc->FWImage = mem; + ioc->alt_ioc->FWImage_dma = mem_dma; + } + + /* Update IOCFactsReply + */ + ioc->facts.FWImageSize = newFwSize; + if (ioc->alt_ioc) + ioc->alt_ioc->facts.FWImageSize = newFwSize; + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* MPT IOCTL MPTCOMMAND function. + * Cast the arg into the mpt_ioctl_mpt_command structure. + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_mpt_command (unsigned long arg) +{ + struct mpt_ioctl_command *uarg = (struct mpt_ioctl_command *) arg; + struct mpt_ioctl_command karg; + MPT_ADAPTER *ioc; + int iocnum; + int rc; + + dctlprintk(("mptctl_command called.\n")); + + if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) { + printk(KERN_ERR "%s@%d::mptctl_mpt_command - " + "Unable to read in mpt_ioctl_command struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + rc = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0); + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands. + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local) +{ + MPT_ADAPTER *ioc; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *hdr; + MptSge_t *psge; + MptSge_t *this_sge = NULL; + MptSge_t *sglbuf = NULL; + struct buflist bufIn; /* data In buffer */ + struct buflist bufOut; /* data Out buffer */ + dma_addr_t sglbuf_dma; + dma_addr_t dma_addr; + int dir; /* PCI data direction */ + int sgSize = 0; /* Num SG elements */ + int this_alloc; + int iocnum, flagsLength; + int sz, rc = 0; + int msgContext; + u16 req_idx; + + dctlprintk(("mptctl_do_mpt_command called.\n")); + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + if (!ioc->ioctl) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "No memory available during driver init.\n", + __FILE__, __LINE__); + return -ENOMEM; + } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Busy with IOC Reset \n", __FILE__, __LINE__); + return -EBUSY; + } + + /* Verify that the final request frame will not be too large. + */ + sz = karg.dataSgeOffset * 4; + if (karg.dataInSize > 0) + sz += sizeof (MptSge_t); + if (karg.dataOutSize > 0) + sz += sizeof (MptSge_t); + + if ( sz > ioc->req_sz) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Request frame too large (%d) maximum (%d)\n", + __FILE__, __LINE__, sz, ioc->req_sz); + return -EFAULT; + } + + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc->id)) == NULL) + return -EAGAIN; + + hdr = (MPIHeader_t *) mf; + msgContext = le32_to_cpu(hdr->MsgContext); + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + + /* Copy the request frame + * Reset the saved message context. + */ + if (local) { + /* Request frame in kernel space + */ + memcpy((char *)mf, (char *) mfPtr, karg.dataSgeOffset * 4); + } else { + /* Request frame in user space + */ + if (copy_from_user((char *)mf, (char *) mfPtr, + karg.dataSgeOffset * 4)){ + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Unable to read MF from mpt_ioctl_command struct @ %p\n", + __FILE__, __LINE__, (void*)mfPtr); + rc = -EFAULT; + goto done_free_mem; + } + } + hdr->MsgContext = cpu_to_le32(msgContext); + + + /* Verify that this request is allowed. + */ + switch (hdr->Function) { + case MPI_FUNCTION_IOC_FACTS: + case MPI_FUNCTION_PORT_FACTS: + case MPI_FUNCTION_CONFIG: + case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: + case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: + case MPI_FUNCTION_FW_UPLOAD: + case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: + case MPI_FUNCTION_FW_DOWNLOAD: + break; + + case MPI_FUNCTION_SCSI_IO_REQUEST: + if (ioc->sh) { + SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; + VirtDevice *pTarget = NULL; + MPT_SCSI_HOST *hd = NULL; + int qtag = MPI_SCSIIO_CONTROL_UNTAGGED; + int scsidir = 0; + int target = (int) pScsiReq->TargetID; + int dataSize; + + pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS; + + /* verify that app has not requested + * more sense data than driver + * can provide, if so, reset this parameter + * set the sense buffer pointer low address + * update the control field to specify Q type + */ + if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + + pScsiReq->SenseBufferLowAddr = + cpu_to_le32(ioc->sense_buf_low_dma + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + + if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { + if (hd->Targets) + pTarget = hd->Targets[target]; + } + + if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + + /* Have the IOCTL driver set the direction based + * on the dataOutSize (ordering issue with Sparc). + */ + if (karg.dataOutSize > 0 ) { + scsidir = MPI_SCSIIO_CONTROL_WRITE; + dataSize = karg.dataOutSize; + } + else { + scsidir = MPI_SCSIIO_CONTROL_READ; + dataSize = karg.dataInSize; + } + + pScsiReq->Control = cpu_to_le32(scsidir | qtag); + pScsiReq->DataLength = cpu_to_le32(dataSize); + + } else { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "SCSI driver is not loaded. \n", + __FILE__, __LINE__); + rc = -EFAULT; + goto done_free_mem; + } + break; + + case MPI_FUNCTION_RAID_ACTION: + /* Just add a SGE + */ + break; + + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + if (ioc->sh) { + SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; + int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + int scsidir = MPI_SCSIIO_CONTROL_READ; + int dataSize; + + pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS; + + /* verify that app has not requested + * more sense data than driver + * can provide, if so, reset this parameter + * set the sense buffer pointer low address + * update the control field to specify Q type + */ + if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + + pScsiReq->SenseBufferLowAddr = + cpu_to_le32(ioc->sense_buf_low_dma + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + + /* All commands to physical devices are tagged + */ + + /* Have the IOCTL driver set the direction based + * on the dataOutSize (ordering issue with Sparc). + */ + if (karg.dataOutSize > 0 ) { + scsidir = MPI_SCSIIO_CONTROL_WRITE; + dataSize = karg.dataOutSize; + } + else { + scsidir = MPI_SCSIIO_CONTROL_READ; + dataSize = karg.dataInSize; + } + + pScsiReq->Control = cpu_to_le32(scsidir | qtag); + pScsiReq->DataLength = cpu_to_le32(dataSize); + + } else { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "SCSI driver is not loaded. \n", + __FILE__, __LINE__); + rc = -EFAULT; + goto done_free_mem; + } + break; + + default: + /* + * MPI_FUNCTION_IOC_INIT + * MPI_FUNCTION_PORT_ENABLE + * MPI_FUNCTION_TARGET_CMD_BUFFER_POST + * MPI_FUNCTION_TARGET_ASSIST + * MPI_FUNCTION_TARGET_STATUS_SEND + * MPI_FUNCTION_TARGET_MODE_ABORT + * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET + * MPI_FUNCTION_IO_UNIT_RESET + * MPI_FUNCTION_HANDSHAKE + * MPI_FUNCTION_REPLY_FRAME_REMOVAL + * MPI_FUNCTION_EVENT_NOTIFICATION + * (driver handles event notification) + * MPI_FUNCTION_EVENT_ACK + * MPI_FUNCTION_SCSI_TASK_MGMT + */ + + /* What to do with these??? CHECK ME!!! + MPI_FUNCTION_FC_LINK_SRVC_BUF_POST + MPI_FUNCTION_FC_LINK_SRVC_RSP + MPI_FUNCTION_FC_ABORT + MPI_FUNCTION_FC_PRIMITIVE_SEND + MPI_FUNCTION_LAN_SEND + MPI_FUNCTION_LAN_RECEIVE + MPI_FUNCTION_LAN_RESET + */ + + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Illegal request (function 0x%x) \n", + __FILE__, __LINE__, hdr->Function); + rc = -EFAULT; + goto done_free_mem; + } + + /* Add the SGL ( at most one data in SGE and one data out SGE ) + * In the case of two SGE's - the data out (write) will always + * preceede the data in (read) SGE. psgList is used to free the + * allocated memory. + */ + psge = (MptSge_t *) ( ((int *) mf) + karg.dataSgeOffset); + flagsLength = 0; + + /* bufIn and bufOut are used for user to kernel space transfers + */ + bufIn.kptr = bufOut.kptr = NULL; + bufIn.len = bufOut.len = 0; + + if (karg.dataOutSize > 0 ) + sgSize ++; + + if (karg.dataInSize > 0 ) + sgSize ++; + + if (sgSize > 0) { + + /* Allocate memory for the SGL. + * Used to free kernel memory once + * the MF is freed. + */ + sglbuf = pci_alloc_consistent (ioc->pcidev, + sgSize*sizeof(MptSge_t), &sglbuf_dma); + if (sglbuf == NULL) { + rc = -ENOMEM; + goto done_free_mem; + } + this_sge = sglbuf; + + /* Set up the dataOut memory allocation */ + if (karg.dataOutSize > 0) { + dir = PCI_DMA_TODEVICE; + if (karg.dataInSize > 0 ) { + flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_DIRECTION | + MPT_SGE_ADDRESS_SIZE ) + << MPI_SGE_FLAGS_SHIFT; + } else { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; + } + flagsLength |= karg.dataOutSize; + + this_alloc = karg.dataOutSize; + bufOut.len = this_alloc; + bufOut.kptr = pci_alloc_consistent( + ioc->pcidev, this_alloc, &dma_addr); + + if (bufOut.kptr == NULL) { + rc = -ENOMEM; + goto done_free_mem; + } else { + /* Copy user data to kernel space. + */ + if (copy_from_user(bufOut.kptr, + karg.dataOutBufPtr, + bufOut.len)) { + + printk(KERN_ERR + "%s@%d::mptctl_do_mpt_command - Unable " + "to read user data " + "struct @ %p\n", + __FILE__, __LINE__,(void*)karg.dataOutBufPtr); + rc = -EFAULT; + goto done_free_mem; + } + + /* Set up this SGE. + * Copy to MF and to sglbuf + */ + + psge->FlagsLength = cpu_to_le32 (flagsLength); + cpu_to_leXX(dma_addr, psge->Address); + psge++; + + this_sge->FlagsLength=cpu_to_le32(flagsLength); + cpu_to_leXX(dma_addr, this_sge->Address); + this_sge++; + } + } + + if (karg.dataInSize > 0) { + dir = PCI_DMA_FROMDEVICE; + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; + flagsLength |= karg.dataInSize; + + this_alloc = karg.dataInSize; + bufIn.len = this_alloc; + bufIn.kptr = pci_alloc_consistent(ioc->pcidev, + this_alloc, &dma_addr); + if (bufIn.kptr == NULL) { + rc = -ENOMEM; + goto done_free_mem; + } else { + /* Set up this SGE + * Copy to MF and to sglbuf + */ + psge->FlagsLength = cpu_to_le32 (flagsLength); + cpu_to_leXX(dma_addr, psge->Address); + + this_sge->FlagsLength=cpu_to_le32(flagsLength); + cpu_to_leXX(dma_addr, this_sge->Address); + this_sge++; + } + } + } else { + /* Add a NULL SGE + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; + psge->FlagsLength = cpu_to_le32 (flagsLength); + cpu_to_leXX( (dma_addr_t) -1, psge->Address); + } + + /* The request is complete. Set the timer parameters + * and issue the request. + */ + if (karg.timeout > 0) { + ioc->ioctl->timer.expires = jiffies + HZ*karg.timeout; + } else { + ioc->ioctl->timer.expires = jiffies + HZ*MPT_IOCTL_DEFAULT_TIMEOUT; + } + + ioc->ioctl->wait_done = 0; + ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE; + add_timer(&ioc->ioctl->timer); + + mpt_put_msg_frame(mptctl_id, ioc->id, mf); + wait_event(mptctl_wait, ioc->ioctl->wait_done); + + /* The command is complete. * Return data to the user. + * + * If command completed, mf has been freed so cannot + * use this memory. + * + * If timeout, a recovery mechanism has been called. + * Need to free the mf. + */ + if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) { + + /* A timeout - there is no data to return to the + * the user other than an error. + * The timer callback deleted the + * timer and reset the adapter queues. + */ + printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - " + "Timeout Occurred on IOCTL! Resetting IOC.\n", __FILE__, __LINE__); + rc = -ETIME; + + /* Free memory and return to the calling function + */ + goto done_free_mem; + + } else { + /* Callback freed request frame. + */ + mf = NULL; + + /* If a valid reply frame, copy to the user. + * Offset 2: reply length in U32's + */ + if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { + if (karg.maxReplyBytes < ioc->reply_sz) { + sz = MIN(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); + } else { + sz = MIN(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); + } + + if (sz > 0) { + if (copy_to_user((char *)karg.replyFrameBufPtr, + &ioc->ioctl->ReplyFrame, sz)){ + + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Unable to write out reply frame %p\n", + __FILE__, __LINE__, (void*)karg.replyFrameBufPtr); + rc = -ENODATA; + goto done_free_mem; + } + } + } + + /* If valid sense data, copy to user. + */ + if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { + sz = MIN(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); + if (sz > 0) { + if (copy_to_user((char *)karg.senseDataPtr, ioc->ioctl->sense, sz)) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Unable to write sense data to user %p\n", + __FILE__, __LINE__, + (void*)karg.senseDataPtr); + rc = -ENODATA; + goto done_free_mem; + } + } + } + + /* If the overall status is _GOOD and data in, copy data + * to user. + */ + if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && + (karg.dataInSize > 0) && (bufIn.kptr)) { + + if (copy_to_user((char *)karg.dataInBufPtr, + bufIn.kptr, karg.dataInSize)) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Unable to write data to user %p\n", + __FILE__, __LINE__, + (void*)karg.dataInBufPtr); + rc = -ENODATA; + } + } + } + +done_free_mem: + /* Clear status bits. + */ + ioc->ioctl->status = 0; + + if (sglbuf) { + this_sge = sglbuf; + + /* Free the allocated memory. + */ + if (bufOut.kptr != NULL ) { + + leXX_to_cpu (dma_addr, this_sge->Address); + + this_sge++; /* go to next structure */ + this_alloc = bufOut.len; + pci_free_consistent(ioc->pcidev, + this_alloc, (void *) &bufOut, dma_addr); + } + + if (bufIn.kptr != NULL ) { + leXX_to_cpu (dma_addr, this_sge->Address); + this_alloc = bufIn.len; + + pci_free_consistent(ioc->pcidev, + this_alloc, (void *) &bufIn, dma_addr); + } + + this_alloc = sgSize * sizeof(MptSge_t); + pci_free_consistent(ioc->pcidev, + this_alloc, (void *) sglbuf, sglbuf_dma); + + } + + /* mf will be null if allocation failed OR + * if command completed OK (callback freed) + */ + if (mf) + mpt_free_msg_frame(mptctl_id, ioc->id, mf); + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Routine for the Compaq IOCTL commands. + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int iocnum = 0; + unsigned iocnumX = 0; + int ret; + int nonblock = (file->f_flags & O_NONBLOCK); + MPT_ADAPTER *iocp = NULL; + + if (cmd == CPQFCTS_SCSI_PASSTHRU) { + /* Update the iocnum */ + if (copy_from_user(&iocnumX, (int *)arg, sizeof(int))) { + printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - " + "Unable to read controller number @ %p\n", + __FILE__, __LINE__, (void*)arg); + return -EFAULT; + } + iocnumX &= 0xFF; + } + + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX); + return -ENODEV; + } + + /* All of these commands require an interrupt or + * are unknown/illegal. + */ + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + dctlprintk((MYIOC_s_INFO_FMT ": mptctl_compaq_ioctl()\n", iocp->name)); + + switch(cmd) { + case CPQFCTS_GETPCIINFO: + ret = mptctl_cpq_getpciinfo(arg); + break; + case CPQFCTS_GETDRIVER: + ret = mptctl_cpq_getdriver(arg); + break; + case CPQFCTS_CTLR_STATUS: + ret = mptctl_cpq_ctlr_status(arg); + break; + case CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS: + ret = mptctl_cpq_target_address(arg); + break; + case CPQFCTS_SCSI_PASSTHRU: + ret = mptctl_cpq_passthru(arg); + break; + default: + ret = -EINVAL; + } + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; + +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_cpq_getpciinfo - Get PCI Information in format desired by Compaq + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + */ +static int +mptctl_cpq_getpciinfo(unsigned long arg) +{ + cpqfc_pci_info_struct *uarg = (cpqfc_pci_info_struct *) arg; + cpqfc_pci_info_struct karg; + MPT_ADAPTER *ioc; + struct pci_dev *pdev; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + int iocnum = 0, iocnumX = 0; + dma_addr_t buf_dma; + u8 *pbuf = NULL; + int failed; + + dctlprintk((": mptctl_cpq_pciinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(cpqfc_pci_info_struct))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - " + "Unable to read in cpqfc_pci_info_struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + pdev = (struct pci_dev *) ioc->pcidev; + + /* Populate the structure. */ + karg.bus = pdev->bus->number; + karg.bus_type = 1; /* 1 = PCI; 4 = unknown */ + karg.device_fn = PCI_FUNC(pdev->devfn); + karg.slot_number = PCI_SLOT(pdev->devfn); + karg.vendor_id = pdev->vendor; + karg.device_id = pdev->device; + karg.board_id = (karg.device_id | (karg.vendor_id << 16)); + karg.class_code = pdev->class; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + karg.sub_vendor_id = pdev->subsystem_vendor; + karg.sub_device_id = pdev->subsystem_device; +#endif + + /* Issue a config request to get the device serial number + */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + failed = 1; + + if (mpt_config(ioc, &cfg) == 0) { + if (cfg.hdr->PageLength > 0) { + /* Issue the second config page request */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); + if (pbuf) { + cfg.physAddr = buf_dma; + if (mpt_config(ioc, &cfg) == 0) { + ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; + strncpy(karg.serial_number, pdata->BoardTracerNumber, 17); + failed = 0; + } + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); + pbuf = NULL; + } + } + } + if (failed) + strncpy(karg.serial_number, " ", 17); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(cpqfc_pci_info_struct))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - " + "Unable to write out cpqfc_pci_info_struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_cpq_getdriver - Get Driver Version in format desired by Compaq + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ +static int +mptctl_cpq_getdriver(unsigned long arg) +{ + int *uarg = (int *)arg; + int karg; + MPT_ADAPTER *ioc = NULL; + int iocnum = 0, iocnumX = 0; + int ii, jj; + char version[10]; + char val; + char *vptr = NULL; + char *pptr = NULL; + + dctlprintk((": mptctl_cpq_getdriver called.\n")); + if (copy_from_user(&karg, uarg, sizeof(int))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - " + "Unable to read in struct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + strncpy(version, MPT_LINUX_VERSION_COMMON, 8); + + karg = 0; + vptr = version; + ii = 3; + while (ii > 0) { + pptr = strchr(vptr, '.'); + if (pptr) { + *pptr = '\0'; + val = 0; + for (jj=0; vptr[jj]>='0' && vptr[jj]<='9'; jj++) + val = 10 * val + (vptr[jj] - '0'); + karg |= (val << (8*ii)); + pptr++; + vptr = pptr; + } else + break; + ii--; + } + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(int))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - " + "Unable to write out stuct @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_cpq_ctlr_status - Get controller status in format desired by Compaq + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ +static int +mptctl_cpq_ctlr_status(unsigned long arg) +{ + cpqfc_ctlr_status *uarg = (cpqfc_ctlr_status *) arg; + cpqfc_ctlr_status karg; + MPT_ADAPTER *ioc; + int iocnum = 0, iocnumX = 0; + + dctlprintk((": mptctl_cpq_pciinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(cpqfc_ctlr_status))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - " + "Unable to read in cpqfc_ctlr_status @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + karg.status = ioc->last_state; + karg.offline_reason = 0; + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(cpqfc_ctlr_status))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - " + "Unable to write out cpqfc_ctlr_status @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_cpq_target_address - Get WWN Information in format desired by Compaq + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + */ +static int +mptctl_cpq_target_address(unsigned long arg) +{ + Scsi_FCTargAddress *uarg = (Scsi_FCTargAddress *) arg; + Scsi_FCTargAddress karg; + MPT_ADAPTER *ioc; + int iocnum = 0, iocnumX = 0; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t buf_dma; + u8 *pbuf = NULL; + FCPortPage0_t *ppp0; + int ii, failed; + u32 low, high; + + dctlprintk((": mptctl_cpq_target_address called.\n")); + if (copy_from_user(&karg, uarg, sizeof(Scsi_FCTargAddress))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - " + "Unable to read in Scsi_FCTargAddress @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + karg.host_port_id = 0; + + /* Issue a config request to get the device wwn + */ + hdr.PageVersion = 0; + hdr.PageLength = 0; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT; + cfg.hdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + failed = 1; + + if (mpt_config(ioc, &cfg) == 0) { + if (cfg.hdr->PageLength > 0) { + /* Issue the second config page request */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); + if (pbuf) { + cfg.physAddr = buf_dma; + if (mpt_config(ioc, &cfg) == 0) { + ppp0 = (FCPortPage0_t *) pbuf; + + low = le32_to_cpu(ppp0->WWNN.Low); + high = le32_to_cpu(ppp0->WWNN.High); + + for (ii = 0; ii < 4; ii++) { + karg.host_wwn[7-ii] = low & 0xFF; + karg.host_wwn[3-ii] = high & 0xFF; + low = (low >> 8); + high = (high >> 8); + } + failed = 0; + } + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); + pbuf = NULL; + } + } + } + + if (failed) { + for (ii = 7; ii >= 0; ii--) + karg.host_wwn[ii] = 0; + } + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user((char *)arg, &karg, + sizeof(Scsi_FCTargAddress))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - " + "Unable to write out Scsi_FCTargAddress @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_cpq_passthru - Construct and issue a SCSI IO Passthru + * + * Requires the SCSI host driver to be loaded. + * I386 version. + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + */ +static int +mptctl_cpq_passthru(unsigned long arg) +{ + VENDOR_IOCTL_REQ *uarg = (VENDOR_IOCTL_REQ *) arg; + VENDOR_IOCTL_REQ karg; + cpqfc_passthru_t kpass; + MPT_ADAPTER *ioc; + int iocnum = 0, iocnumX = 0; + int rc; + + dctlprintk((": mptctl_cpq_passthru called.\n")); + if (copy_from_user(&karg, uarg, sizeof(VENDOR_IOCTL_REQ))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - " + "Unable to read in VENDOR_IOCTL_REQ @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + /* Set the IOC number */ + iocnumX = karg.lc & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } + + if (ioc->sh == NULL) { + printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - SCSI Host driver not loaded!\n", + __FILE__, __LINE__); + return -EFAULT; + } + + /* Read in the second buffer */ + if (copy_from_user(&kpass, uarg->argp, sizeof(cpqfc_passthru_t))) { + printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - " + "Unable to read in cpqfc_passthru_t @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + + /* Generate the SCSI IO command and issue */ + rc = mptctl_compaq_scsiio(&karg, &kpass); + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_compaq_scsiio - Reformat Compaq structures into driver structures + * Call the generic _do_mpt_command function. + * + * Requires the SCSI host driver to be loaded. + * I386 version. + * + * Outputs: None. + * Return: 0 if successful + * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires + */ +static int +mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass) +{ + struct mpt_ioctl_command karg; + SCSIIORequest_t request ; + SCSIIORequest_t *pMf; + int ii, rc; + u8 opcode; + + /* Fill in parameters to karg */ + karg.hdr.iocnum = pVenReq->lc; + karg.hdr.port = 0; + karg.hdr.maxDataSize = 0; /* not used */ + karg.timeout = 0; /* use default */ + + karg.replyFrameBufPtr = NULL; /* no reply data */ + karg.maxReplyBytes = 0; + + karg.senseDataPtr = pPass->sense_data; + karg.maxSenseBytes = pPass->sense_len; /* max is 40 */ + + if (pPass->rw_flag == MPT_COMPAQ_WRITE) { + karg.dataOutBufPtr = pPass->bufp; + karg.dataOutSize = pPass->len; + karg.dataInBufPtr = NULL; + karg.dataInSize = 0; + } else { + karg.dataInBufPtr = pPass->bufp; + karg.dataInSize = pPass->len; + karg.dataOutBufPtr = NULL; + karg.dataOutSize = 0; + } + + karg.dataSgeOffset = (sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION))/4; + + /* Construct the Message frame */ + pMf = &request; + + pMf->TargetID = (u8) pVenReq->ld; /* ???? FIXME */ + pMf->Bus = (u8) pPass->bus; + pMf->ChainOffset = 0; + pMf->Function = MPI_FUNCTION_SCSI_IO_REQUEST; + + /* May need some tweaking here */ + opcode = (u8) pPass->cdb[0]; + if (opcode < 0x20) + pMf->CDBLength = 6; + else if (opcode < 0x60) + pMf->CDBLength = 10; + else if ((opcode < 0xC0) && (opcode >= 0xA0)) + pMf->CDBLength = 12; + else + pMf->CDBLength = 16; + + pMf->SenseBufferLength = karg.maxSenseBytes; /* max is 40 */ + pMf->Reserved = 0; + pMf->MsgFlags = 0; /* set later */ + pMf->MsgContext = 0; /* set later */ + + for (ii = 0; ii < 8; ii++) + pMf->LUN[ii] = 0; + pMf->LUN[1] = 0; /* ???? FIXME */ + + /* Tag values set by _do_mpt_command */ + if (pPass->rw_flag == MPT_COMPAQ_WRITE) + pMf->Control = MPI_SCSIIO_CONTROL_WRITE; + else + pMf->Control = MPI_SCSIIO_CONTROL_READ; + + for (ii = 0; ii < 16; ii++) + pMf->CDB[ii] = pPass->cdb[ii]; + + pMf->DataLength = pPass->len; + + /* All remaining fields are set by the next function + */ + rc = mptctl_do_mpt_command (karg, (char *)pMf, 1); + return rc; +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51) +#define owner_THIS_MODULE owner: THIS_MODULE, +#else +#define owner_THIS_MODULE +#endif + +static struct file_operations mptctl_fops = { + owner_THIS_MODULE + llseek: no_llseek, + read: mptctl_read, + write: mptctl_write, + ioctl: mptctl_ioctl, + open: mptctl_open, + release: mptctl_release, +}; + +static struct miscdevice mptctl_miscdev = { + MPT_MINOR, + MYNAM, + &mptctl_fops +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ + +/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, @@ -1133,18 +2773,15 @@ unsigned long, struct file *)); int unregister_ioctl32_conversion(unsigned int cmd); - -struct mpt_fw_xfer32 { - unsigned int iocnum; - unsigned int fwlen; - u32 bufp; -}; - -#define MPTFWDOWNLOAD32 _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32) - extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* sparc32_XXX functions are used to provide a conversion between + * pointers and u32's. If the arg does not contain any pointers, then + * a specialized function (sparc32_XXX) is not needed. If the arg + * does contain pointer(s), then the specialized function is used + * to ensure the structure contents is properly processed by mptctl. + */ static int sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp) @@ -1156,7 +2793,7 @@ int nonblock = (filp->f_flags & O_NONBLOCK); int ret; - dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); + dctlprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32))) return -EFAULT; @@ -1177,13 +2814,131 @@ kfw.fwlen = kfw32.fwlen; kfw.bufp = (void *)(unsigned long)kfw32.bufp; - ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} + +static int +sparc32_mpt_command(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + struct mpt_ioctl_command32 karg32; + struct mpt_ioctl_command32 *uarg = (struct mpt_ioctl_command32 *) arg; + struct mpt_ioctl_command karg; + MPT_ADAPTER *iocp = NULL; + int iocnum, iocnumX; + int nonblock = (filp->f_flags & O_NONBLOCK); + int ret; + + dctlprintk((KERN_INFO MYNAM "::sparc32_mpt_command() called\n")); + + if (copy_from_user(&karg32, (char *)arg, sizeof(karg32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = karg32.hdr.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + /* Copy data to karg */ + karg.hdr.iocnum = karg32.hdr.iocnum; + karg.hdr.port = karg32.hdr.port; + karg.timeout = karg32.timeout; + karg.maxReplyBytes = karg32.maxReplyBytes; + + karg.dataInSize = karg32.dataInSize; + karg.dataOutSize = karg32.dataOutSize; + karg.maxSenseBytes = karg32.maxSenseBytes; + karg.dataSgeOffset = karg32.dataSgeOffset; + + karg.replyFrameBufPtr = (char *)(unsigned long)karg32.replyFrameBufPtr; + karg.dataInBufPtr = (char *)(unsigned long)karg32.dataInBufPtr; + karg.dataOutBufPtr = (char *)(unsigned long)karg32.dataOutBufPtr; + karg.senseDataPtr = (char *)(unsigned long)karg32.senseDataPtr; + + /* Pass new structure to do_mpt_command + */ + ret = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0); up(&mptctl_syscall_sem_ioc[iocp->id]); return ret; } +static int +sparc32_mptctl_cpq_passthru(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + VENDOR_IOCTL_REQ32 *uarg = (VENDOR_IOCTL_REQ32 *) arg; + VENDOR_IOCTL_REQ32 karg32; + VENDOR_IOCTL_REQ karg; + cpqfc_passthru32_t kpass32; + cpqfc_passthru_t kpass; + MPT_ADAPTER *ioc; + int nonblock = (filp->f_flags & O_NONBLOCK); + int iocnum = 0, iocnumX = 0; + int rc; + int ii; + + dctlprintk((KERN_INFO MYNAM "::sparc32_mptctl_cpq_passthru() called\n")); + + if (copy_from_user(&karg32, (char *)arg, sizeof(karg32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = karg32.lc & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((rc = mptctl_syscall_down(ioc, nonblock)) != 0) + return rc; + + /* Copy data to karg */ + karg.ld = karg32.ld; + karg.node = karg32.node; + karg.lc = karg32.lc; + karg.nexus = karg32.nexus; + karg.argp = (void *)(unsigned long)karg32.argp; + + /* Read in the second buffer */ + if (copy_from_user(&kpass32, karg.argp, sizeof(cpqfc_passthru32_t))) { + printk(KERN_ERR "%s@%d::sparc32_mptctl_cpq_passthru - " + "Unable to read in cpqfc_passthru_t @ %p\n", + __FILE__, __LINE__, (void*)uarg); + return -EFAULT; + } + + /* Copy the 32bit buffer to kpass */ + for (ii = 0; ii < 16; ii++) + kpass.cdb[ii] = kpass32.cdb[ii]; + kpass.bus = kpass32.bus; + kpass.pdrive = kpass32.pdrive; + kpass.len = kpass32.len; + kpass.sense_len = kpass32.sense_len; + kpass.bufp = (void *)(unsigned long)kpass32.bufp; + kpass.rw_flag = kpass32.rw_flag; + + /* Generate the SCSI IO command and issue */ + rc = mptctl_compaq_scsiio(&karg, &kpass); + + up(&mptctl_syscall_sem_ioc[ioc->id]); + return rc; +} + #endif /*} linux >= 2.3.x */ #endif /*} sparc */ @@ -1193,26 +2948,76 @@ int err; int i; int where = 1; + int sz; + u8 *mem; + MPT_ADAPTER *ioc = NULL; + int iocnum; show_mptmod_ver(my_NAME, my_VERSION); for (i=0; iioctl = (MPT_IOCTL *) mem; + ioc->ioctl->ioc = ioc; + init_timer (&ioc->ioctl->timer); + ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->timer.function = mptctl_timer_expired; + } } #if defined(__sparc__) && defined(__sparc_v9__) /*{*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ - err = register_ioctl32_conversion(MPTRWPERF, NULL); + err = register_ioctl32_conversion(MPTIOCINFO, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTTARGETINFO, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTTEST, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTEVENTQUERY, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTEVENTENABLE, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTEVENTREPORT, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTHARDRESET, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTCOMMAND32, sparc32_mpt_command); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTFWDOWNLOAD32, + sparc32_mptfwxfer_ioctl); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(CPQFCTS_GETPCIINFO, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL); + err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL); + err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTFWDOWNLOAD32, sparc32_mptfwxfer_ioctl); + err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru); if (++where && err) goto out_fail; #endif /*} linux >= 2.3.x */ #endif /*} sparc */ + /* Register this device */ if (misc_register(&mptctl_miscdev) == -1) { printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR); err = -EBUSY; @@ -1226,13 +3031,19 @@ * Install our handler */ ++where; - if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) <= 0) { + if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); err = -EBUSY; goto out_fail; } + if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) { + dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + } else { + /* FIXME! */ + } + return 0; out_fail: @@ -1241,35 +3052,72 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!" " (%d:err=%d)\n", where, err); - unregister_ioctl32_conversion(MPTRWPERF); - unregister_ioctl32_conversion(MPTRWPERF_CHK); - unregister_ioctl32_conversion(MPTRWPERF_RESET); + unregister_ioctl32_conversion(MPTIOCINFO); + unregister_ioctl32_conversion(MPTTARGETINFO); + unregister_ioctl32_conversion(MPTTEST); + unregister_ioctl32_conversion(MPTEVENTQUERY); + unregister_ioctl32_conversion(MPTEVENTENABLE); + unregister_ioctl32_conversion(MPTEVENTREPORT); + unregister_ioctl32_conversion(MPTHARDRESET); + unregister_ioctl32_conversion(MPTCOMMAND32); unregister_ioctl32_conversion(MPTFWDOWNLOAD32); + unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO); + unregister_ioctl32_conversion(CPQFCTS_GETDRIVER); + unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS); + unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS); + unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32); #endif /*} linux >= 2.3.x */ #endif /*} sparc */ + for (i=0; iioctl) { + kfree ( ioc->ioctl ); + ioc->ioctl = NULL; + } + } + } return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ void mptctl_exit(void) { - -#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ - unregister_ioctl32_conversion(MPTRWPERF); - unregister_ioctl32_conversion(MPTRWPERF_CHK); - unregister_ioctl32_conversion(MPTRWPERF_RESET); - unregister_ioctl32_conversion(MPTFWDOWNLOAD32); -#endif /*} linux >= 2.3.x */ -#endif /*} sparc */ + int i; + MPT_ADAPTER *ioc; + int iocnum; misc_deregister(&mptctl_miscdev); - printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", + printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); - printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + /* De-register reset handler from base module */ + mpt_reset_deregister(mptctl_id); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); + + /* De-register callback handler from base module */ mpt_deregister(mptctl_id); + printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + + /* Free allocated memory */ + for (i=0; iioctl) { + kfree ( ioc->ioctl ); + ioc->ioctl = NULL; + } + } + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -urN linux-2.4.18/drivers/message/fusion/mptctl.h linux-2.4.19-pre5/drivers/message/fusion/mptctl.h --- linux-2.4.18/drivers/message/fusion/mptctl.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/message/fusion/mptctl.h Sat Mar 30 22:55:39 2002 @@ -0,0 +1,395 @@ +/* + * linux/drivers/message/fusion/mptioctl.h + * Fusion MPT misc device (ioctl) driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * (see also mptbase.c) + * + * Copyright (c) 1999-2002 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) + * + * $Id: mptctl.h,v 1.9 2002/02/27 18:44:26 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MPTCTL_H_INCLUDED +#define MPTCTL_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "linux/version.h" + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * + */ +#define MPT_MISCDEV_BASENAME "mptctl" +#define MPT_MISCDEV_PATHNAME "/dev/" MPT_MISCDEV_BASENAME + +#define MPT_PRODUCT_LENGTH 12 + +/* + * Generic MPT Control IOCTLs and structures + */ +#define MPT_MAGIC_NUMBER 'm' + +#define MPTRWPERF _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w) + +#define MPTFWDOWNLOAD _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer) +#define MPTCOMMAND _IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command) + +#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ +#define MPTFWDOWNLOAD32 _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32) +#define MPTCOMMAND32 _IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command32) +#endif /*}*/ + +#define MPTIOCINFO _IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo) +#define MPTTARGETINFO _IOWR(MPT_MAGIC_NUMBER,18,struct mpt_ioctl_targetinfo) +#define MPTTEST _IOWR(MPT_MAGIC_NUMBER,19,struct mpt_ioctl_test) +#define MPTEVENTQUERY _IOWR(MPT_MAGIC_NUMBER,21,struct mpt_ioctl_eventquery) +#define MPTEVENTENABLE _IOWR(MPT_MAGIC_NUMBER,22,struct mpt_ioctl_eventenable) +#define MPTEVENTREPORT _IOWR(MPT_MAGIC_NUMBER,23,struct mpt_ioctl_eventreport) +#define MPTHARDRESET _IOWR(MPT_MAGIC_NUMBER,24,struct mpt_ioctl_diag_reset) +#define MPTFWREPLACE _IOWR(MPT_MAGIC_NUMBER,25,struct mpt_ioctl_replace_fw) + +/* + * SPARC PLATFORM REMARK: + * IOCTL data structures that contain pointers + * will have different sizes in the driver and applications + * (as the app. will not use 8-byte pointers). + * Apps should use MPTFWDOWNLOAD and MPTCOMMAND. + * The driver will convert data from + * mpt_fw_xfer32 (mpt_ioctl_command32) to mpt_fw_xfer (mpt_ioctl_command) + * internally. + */ +struct mpt_fw_xfer { + unsigned int iocnum; /* IOC unit number */ + unsigned int fwlen; + void *bufp; /* Pointer to firmware buffer */ +}; + +#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ +struct mpt_fw_xfer32 { + unsigned int iocnum; + unsigned int fwlen; + u32 bufp; +}; +#endif /*}*/ + + +/* + * IOCTL header structure. + * iocnum - must be defined. + * port - must be defined for all IOCTL commands other than MPTIOCINFO + * maxDataSize - ignored on MPTCOMMAND commands + * - ignored on MPTFWREPLACE commands + * - on query commands, reports the maximum number of bytes to be returned + * to the host driver (count includes the header). + * That is, set to sizeof(struct mpt_ioctl_iocinfo) for fixed sized commands. + * Set to sizeof(struct mpt_ioctl_targetinfo) + datasize for variable + * sized commands. (MPTTARGETINFO, MPTEVENTREPORT) + */ +typedef struct _mpt_ioctl_header { + unsigned int iocnum; /* IOC unit number */ + unsigned int port; /* IOC port number */ + int maxDataSize; /* Maximum Num. bytes to transfer on read */ +} mpt_ioctl_header; + +/* + * Issue a diagnostic reset + */ +struct mpt_ioctl_diag_reset { + mpt_ioctl_header hdr; +}; + + +/* + * Adapter Information Page + * Read only. + * Data starts at offset 0xC + */ +#define MPT_IOCTL_INTERFACE_FC (0x01) +#define MPT_IOCTL_INTERFACE_SCSI (0x00) +#define MPT_IOCTL_VERSION_LENGTH (32) + +struct mpt_ioctl_iocinfo { + mpt_ioctl_header hdr; + int adapterType; /* SCSI or FCP */ + int port; /* port number */ + int pciId; /* PCI Id. */ + int hwRev; /* hardware revision */ + int subSystemDevice; /* PCI subsystem Device ID */ + int subSystemVendor; /* PCI subsystem Vendor ID */ + int numDevices; /* number of devices */ + int FWVersion; /* FW Version (integer) */ + int BIOSVersion; /* BIOS Version (integer) */ + char driverVersion[MPT_IOCTL_VERSION_LENGTH]; /* Driver Version (string) */ + char busChangeEvent; + char hostId; + char rsvd[2]; +}; + +/* + * Device Information Page + * Report the number of, and ids of, all targets + * on this IOC. The ids array is a packed structure + * of the known targetInfo. + * bits 31-24: reserved + * 23-16: LUN + * 15- 8: Bus Number + * 7- 0: Target ID + */ +struct mpt_ioctl_targetinfo { + mpt_ioctl_header hdr; + int numDevices; /* Num targets on this ioc */ + int targetInfo[1]; +}; + + +/* + * Event reporting IOCTL's. These IOCTL's will + * use the following defines: + */ +struct mpt_ioctl_eventquery { + mpt_ioctl_header hdr; + unsigned short eventEntries; + unsigned short reserved; + unsigned int eventTypes; +}; + +struct mpt_ioctl_eventenable { + mpt_ioctl_header hdr; + unsigned int eventTypes; +}; + +#ifndef __KERNEL__ +typedef struct { + uint event; + uint eventContext; + uint data[2]; +} MPT_IOCTL_EVENTS; +#endif + +struct mpt_ioctl_eventreport { + mpt_ioctl_header hdr; + MPT_IOCTL_EVENTS eventData[1]; +}; + +#define MPT_MAX_NAME 32 +struct mpt_ioctl_test { + mpt_ioctl_header hdr; + u8 name[MPT_MAX_NAME]; + int chip_type; + u8 product [MPT_PRODUCT_LENGTH]; +}; + +/* Replace the FW image cached in host driver memory + * newImageSize - image size in bytes + * newImage - first byte of the new image + */ +typedef struct mpt_ioctl_replace_fw { + mpt_ioctl_header hdr; + int newImageSize; + u8 newImage[1]; +} mpt_ioctl_replace_fw_t; + +/* General MPT Pass through data strucutre + * + * iocnum + * timeout - in seconds, command timeout. If 0, set by driver to + * default value. + * replyFrameBufPtr - reply location + * dataInBufPtr - destination for read + * dataOutBufPtr - data source for write + * senseDataPtr - sense data location + * maxReplyBytes - maximum number of reply bytes to be sent to app. + * dataInSize - num bytes for data transfer in (read) + * dataOutSize - num bytes for data transfer out (write) + * dataSgeOffset - offset in words from the start of the request message + * to the first SGL + * MF[1]; + * + * Remark: Some config pages have bi-directional transfer, + * both a read and a write. The basic structure allows for + * a bidirectional set up. Normal messages will have one or + * both of these buffers NULL. + */ +struct mpt_ioctl_command { + mpt_ioctl_header hdr; + int timeout; /* optional (seconds) */ + char *replyFrameBufPtr; + char *dataInBufPtr; + char *dataOutBufPtr; + char *senseDataPtr; + int maxReplyBytes; + int dataInSize; + int dataOutSize; + int maxSenseBytes; + int dataSgeOffset; + char MF[1]; +}; + +/* + * SPARC PLATFORM: See earlier remark. + */ +#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ +struct mpt_ioctl_command32 { + mpt_ioctl_header hdr; + int timeout; + u32 replyFrameBufPtr; + u32 dataInBufPtr; + u32 dataOutBufPtr; + u32 senseDataPtr; + int maxReplyBytes; + int dataInSize; + int dataOutSize; + int maxSenseBytes; + int dataSgeOffset; + char MF[1]; +}; +#endif /*}*/ + + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* + * COMPAQ Specific IOCTL Defines and Structures + */ + +#define CPQFCTS_IOC_MAGIC 'Z' + +#define CPQFCTS_GETPCIINFO _IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct) +#define CPQFCTS_GETDRIVER _IOR(CPQFCTS_IOC_MAGIC, 2, int) +#define CPQFCTS_CTLR_STATUS _IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status) +#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS _IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress) +#define CPQFCTS_SCSI_PASSTHRU _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ) +#if defined(__sparc__) && defined(__sparc_v9__) +#define CPQFCTS_SCSI_PASSTHRU32 _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32) +#endif + +typedef struct { + unsigned short bus; + unsigned short bus_type; + unsigned short device_fn; + u32 board_id; + u32 slot_number; + unsigned short vendor_id; + unsigned short device_id; + unsigned short class_code; + unsigned short sub_vendor_id; + unsigned short sub_device_id; + u8 serial_number[81]; +} cpqfc_pci_info_struct; + + +typedef struct scsi_fctargaddress { + unsigned int host_port_id; + u8 host_wwn[8]; /* WW Network Name */ +} Scsi_FCTargAddress; + +typedef struct _cpqfc_ctlr_status { + u32 status; + u32 offline_reason; +} cpqfc_ctlr_status; + + +/* Compaq SCSI I/O Passthru structures. + */ +#define MPT_COMPAQ_READ 0x26 +#define MPT_COMPAQ_WRITE 0x27 + +typedef struct { + int lc; /* controller number */ + int node; /* node number */ + int ld; /* target logical id */ + u32 nexus; + void *argp; +} VENDOR_IOCTL_REQ; + +#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ +typedef struct { + int lc; /* controller number */ + int node; /* node number */ + int ld; /* target logical id */ + u32 nexus; + u32 argp; +} VENDOR_IOCTL_REQ32; +#endif + +typedef struct { + char cdb[16]; /* cdb */ + unsigned short bus; /* bus number */ + unsigned short pdrive; /* physical drive */ + int len; /* data area size */ + int sense_len; /* sense size */ + char sense_data[40]; /* sense buffer */ + void *bufp; /* data buffer pointer */ + char rw_flag; +} cpqfc_passthru_t; + +#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ +typedef struct { + char cdb[16]; /* cdb */ + unsigned short bus; /* bus number */ + unsigned short pdrive; /* physical drive */ + int len; /* data area size */ + int sense_len; /* sense size */ + char sense_data[40]; /* sense buffer */ + u32 bufp; /* data buffer pointer */ + char rw_flag; +} cpqfc_passthru32_t; +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#endif + diff -urN linux-2.4.18/drivers/message/fusion/mptlan.c linux-2.4.19-pre5/drivers/message/fusion/mptlan.c --- linux-2.4.18/drivers/message/fusion/mptlan.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/mptlan.c Sat Mar 30 22:55:39 2002 @@ -23,10 +23,10 @@ * * (see also mptbase.c) * - * Copyright (c) 2000-2001 LSI Logic Corporation + * Copyright (c) 2000-2002 LSI Logic Corporation * Originally By: Noah Romer * - * $Id: mptlan.c,v 1.32.2.2 2001/07/12 19:43:33 nromer Exp $ + * $Id: mptlan.c,v 1.51 2002/02/11 14:40:55 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -79,6 +79,8 @@ #define MYNAM "mptlan" +MODULE_LICENSE("GPL"); + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * MPT LAN message sizes without variable part. @@ -109,8 +111,8 @@ MPT_ADAPTER *mpt_dev; u8 pnum; /* Port number in the IOC. This is not a Unix network port! */ - atomic_t buckets_out; /* number of unused buckets on IOC */ - int bucketthresh; /* Send more when this many used */ + atomic_t buckets_out; /* number of unused buckets on IOC */ + int bucketthresh; /* Send more when this many left */ int *mpt_txfidx; /* Free Tx Context list */ int mpt_txfidx_tail; @@ -123,8 +125,8 @@ struct BufferControl *RcvCtl; /* Receive BufferControl structs */ struct BufferControl *SendCtl; /* Send BufferControl structs */ - int max_buckets_out; /* Max buckets to send to IOC */ - int tx_max_out; /* IOC's Tx queue len */ + int max_buckets_out; /* Max buckets to send to IOC */ + int tx_max_out; /* IOC's Tx queue len */ u32 total_posted; u32 total_received; @@ -152,7 +154,8 @@ static int mpt_lan_reset(struct net_device *dev); static int mpt_lan_close(struct net_device *dev); static void mpt_lan_post_receive_buckets(void *dev_id); -static void mpt_lan_wake_post_buckets_task(struct net_device *dev); +static void mpt_lan_wake_post_buckets_task(struct net_device *dev, + int priority); static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); static int mpt_lan_receive_post_reply(struct net_device *dev, LANReceivePostReply_t *pRecvRep); @@ -175,8 +178,10 @@ static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; +#ifdef QLOGIC_NAA_WORKAROUND static struct NAA_Hosed *mpt_bad_naa = NULL; rwlock_t bad_naa_lock; +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -229,7 +234,7 @@ case LAN_REPLY_FORM_SEND_SINGLE: // dioprintk((MYNAM "/lan_reply: " // "calling mpt_lan_send_reply (turbo)\n")); - + // Potential BUG here? -sralston // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg); // If/when mpt_lan_send_turbo would return 1 here, @@ -333,7 +338,7 @@ struct net_device *dev = mpt_landev[ioc->id]; struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; - dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", + dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); if (priv->mpt_rxfidx == NULL) @@ -342,9 +347,11 @@ if (reset_phase == MPT_IOC_PRE_RESET) { int i; unsigned long flags; - + netif_stop_queue(dev); + dlprintk ((KERN_INFO "mptlan/ioc_reset: called netif_stop_queue for %s.\n", dev->name)); + atomic_set(&priv->buckets_out, 0); /* Reset Rx Free Tail index and re-populate the queue. */ @@ -365,7 +372,7 @@ static int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { - dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n")); + dlprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n")); switch (le32_to_cpu(pEvReply->Event)) { case MPI_EVENT_NONE: /* 00 */ @@ -403,9 +410,9 @@ if (mpt_lan_reset(dev) != 0) { MPT_ADAPTER *mpt_dev = priv->mpt_dev; - + printk (KERN_WARNING MYNAM "/lan_open: lan_reset failed."); - + if (mpt_dev->active) printk ("The ioc is active. Perhaps it needs to be" " reset?\n"); @@ -429,7 +436,7 @@ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i; } - dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); + dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int), GFP_KERNEL); @@ -447,12 +454,12 @@ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; } -/**/ dprintk((KERN_INFO MYNAM "/lo: txfidx contains - ")); +/**/ dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - ")); /**/ for (i = 0; i < priv->tx_max_out; i++) -/**/ dprintk((" %xh", priv->mpt_txfidx[i])); -/**/ dprintk(("\n")); +/**/ dlprintk((" %xh", priv->mpt_txfidx[i])); +/**/ dlprintk(("\n")); - dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); + dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); mpt_lan_post_receive_buckets(dev); printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", @@ -466,7 +473,7 @@ } netif_start_queue(dev); - dprintk((KERN_INFO MYNAM "/lo: Done.\n")); + dlprintk((KERN_INFO MYNAM "/lo: Done.\n")); return 0; out_mpt_rxfidx: @@ -494,7 +501,7 @@ mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id); if (mf == NULL) { -/* dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! " +/* dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! " "Unable to allocate a request frame.\n")); */ return -1; @@ -523,11 +530,11 @@ unsigned int timeout; int i; - dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); + dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); mpt_event_deregister(LanCtx); - dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets " + dlprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets " "since driver was loaded, %d still out\n", priv->total_posted,atomic_read(&priv->buckets_out))); @@ -537,18 +544,18 @@ timeout = 2 * HZ; while (atomic_read(&priv->buckets_out) && --timeout) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } for (i = 0; i < priv->max_buckets_out; i++) { if (priv->RcvCtl[i].skb != NULL) { -/**/ dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x " +/**/ dlprintk((KERN_INFO MYNAM "/lan_close: bucket %05x " /**/ "is still out\n", i)); pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma, - priv->RcvCtl[i].len, + priv->RcvCtl[i].len, PCI_DMA_FROMDEVICE); - dev_kfree_skb(priv->RcvCtl[i].skb); + dev_kfree_skb(priv->RcvCtl[i].skb); } } @@ -556,11 +563,11 @@ kfree (priv->mpt_rxfidx); for (i = 0; i < priv->tx_max_out; i++) { - if (priv->SendCtl[i].skb != NULL) { + if (priv->SendCtl[i].skb != NULL) { pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma, priv->SendCtl[i].len, PCI_DMA_TODEVICE); - dev_kfree_skb(priv->SendCtl[i].skb); + dev_kfree_skb(priv->SendCtl[i].skb); } } @@ -599,7 +606,13 @@ static void mpt_lan_tx_timeout(struct net_device *dev) { - netif_wake_queue(dev); + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + + if (mpt_dev->active) { + dlprintk (("mptlan/tx_timeout: calling netif_wake_queue for %s.\n", dev->name)); + netif_wake_queue(dev); + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -722,7 +735,6 @@ dma_addr_t dma; unsigned long flags; int ctx; - struct NAA_Hosed *nh; u16 cur_naa = 0x1000; dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", @@ -741,7 +753,6 @@ mf = mpt_get_msg_frame(LanCtx, mpt_dev->id); if (mf == NULL) { netif_stop_queue(dev); - dev_kfree_skb(skb); spin_unlock_irqrestore(&priv->txfidx_lock, flags); printk (KERN_ERR "%s: Unable to alloc request frame\n", @@ -791,6 +802,10 @@ // IOC_AND_NETDEV_NAMES_s_s(dev), // ctx, skb, skb->data)); +#ifdef QLOGIC_NAA_WORKAROUND +{ + struct NAA_Hosed *nh; + /* Munge the NAA for Tx packets to QLogic boards, which don't follow RFC 2625. The longer I look at this, the more my opinion of Qlogic drops. */ @@ -803,12 +818,14 @@ (nh->ieee[4] == skb->mac.raw[4]) && (nh->ieee[5] == skb->mac.raw[5])) { cur_naa = nh->NAA; - dprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " + dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " "= %04x.\n", cur_naa)); break; } } read_unlock_irq(&bad_naa_lock); +} +#endif pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | (skb->mac.raw[0] << 8) | @@ -821,10 +838,10 @@ pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; /* If we ever decide to send more than one Simple SGE per LANSend, then - we will need to make sure that LAST_ELEMENT only gets set on the + we will need to make sure that LAST_ELEMENT only gets set on the last one. Otherwise, bad voodoo and evil funkiness will commence. */ pSimple->FlagsLength = cpu_to_le32( - ((MPI_SGE_FLAGS_LAST_ELEMENT | + ((MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_SYSTEM_ADDRESS | @@ -842,23 +859,32 @@ dev->trans_start = jiffies; dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - le32_to_cpu(pSimple->FlagsLength))); + IOC_AND_NETDEV_NAMES_s_s(dev), + le32_to_cpu(pSimple->FlagsLength))); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static inline void -mpt_lan_wake_post_buckets_task(struct net_device *dev) +mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) +/* + * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue + */ { struct mpt_lan_priv *priv = dev->priv; - + if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { - queue_task(&priv->post_buckets_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); - dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", - IOC_AND_NETDEV_NAMES_s_s(dev) )); + if (priority) { + queue_task(&priv->post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } else { + queue_task(&priv->post_buckets_task, &tq_timer); + dioprintk((KERN_INFO MYNAM ": post_buckets queued on " + "timer.\n")); + } + dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", + IOC_AND_NETDEV_NAMES_s_s(dev) )); } } @@ -870,7 +896,7 @@ skb->protocol = mpt_lan_type_trans(skb, dev); - dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " + dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " "delivered to upper level.\n", IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); @@ -884,7 +910,7 @@ atomic_read(&priv->buckets_out))); if (atomic_read(&priv->buckets_out) < priv->bucketthresh) - mpt_lan_wake_post_buckets_task(dev); + mpt_lan_wake_post_buckets_task(dev, 1); dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets " "remaining, %d received back since sod\n", @@ -956,12 +982,12 @@ unsigned long flags; struct sk_buff *skb; u32 ctx; - u8 count; + int count; int i; count = pRecvRep->NumberOfContexts; -/**/ dprintk((KERN_INFO MYNAM "/receive_post_reply: " +/**/ dlprintk((KERN_INFO MYNAM "/receive_post_reply: " "IOC returned %d buckets, freeing them...\n", count)); spin_lock_irqsave(&priv->rxfidx_lock, flags); @@ -970,11 +996,11 @@ skb = priv->RcvCtl[ctx].skb; -// dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n", +// dlprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n", // IOC_AND_NETDEV_NAMES_s_s(dev))); -// dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p", -// priv, &(priv->buckets_out))); -// dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n")); +// dlprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p", +// priv, &(priv->buckets_out))); +// dlprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n")); priv->RcvCtl[ctx].skb = NULL; pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, @@ -989,13 +1015,13 @@ // for (i = 0; i < priv->max_buckets_out; i++) // if (priv->RcvCtl[i].skb != NULL) -// dprintk((KERN_INFO MYNAM "@rpr: bucket %03x " +// dlprintk((KERN_INFO MYNAM "@rpr: bucket %03x " // "is still out\n", i)); -/* dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n", +/* dlprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n", count)); */ -/**/ dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets " +/**/ dlprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets " /**/ "remaining, %d received back since sod.\n", /**/ atomic_read(&priv->buckets_out), priv->total_received)); return 0; @@ -1010,9 +1036,9 @@ MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; - u32 len, ctx; - u32 offset; - u8 count; + u32 len, ctx, offset; + u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining); + int count; int i, l; dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n")); @@ -1059,7 +1085,7 @@ if (!skb) { printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", IOC_AND_NETDEV_NAMES_s_s(dev), - __FILE__, __LINE__); + __FILE__, __LINE__); return -ENOMEM; } @@ -1096,7 +1122,7 @@ if (!skb) { printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", IOC_AND_NETDEV_NAMES_s_s(dev), - __FILE__, __LINE__); + __FILE__, __LINE__); return -ENOMEM; } @@ -1140,25 +1166,32 @@ "Arrgghh! We've done it again!\n"); } -#if 0 - { - u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining); - if (remaining < priv->bucketthresh) - mpt_lan_wake_post_buckets_task(dev); - - if (remaining == 0) - printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! " - "(priv->buckets_out = %d)\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - atomic_read(&priv->buckets_out)); - else - printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. " - "(priv->buckets_out = %d)\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - remaining, atomic_read(&priv->buckets_out)); + if (remaining == 0) + printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + atomic_read(&priv->buckets_out)); + else if (remaining < 10) + printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + remaining, atomic_read(&priv->buckets_out)); + + if ((remaining < priv->bucketthresh) && + ((atomic_read(&priv->buckets_out) - remaining) > + MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) { + + printk (KERN_WARNING MYNAM " Mismatch between driver's " + "buckets_out count and fw's BucketsRemaining " + "count has crossed the threshold, issuing a " + "LanReset to clear the fw's hashtable. You may " + "want to check your /var/log/messages for \"CRC " + "error\" event notifications.\n"); + + mpt_lan_reset(dev); + mpt_lan_wake_post_buckets_task(dev, 0); } -#endif - + return mpt_lan_receive_skb(dev, skb); } @@ -1242,15 +1275,15 @@ if (skb == NULL) { skb = dev_alloc_skb(len); if (skb == NULL) { -/**/ printk (KERN_WARNING -/**/ MYNAM "/%s: Can't alloc skb\n", -/**/ __FUNCTION__); + printk (KERN_WARNING + MYNAM "/%s: Can't alloc skb\n", + __FUNCTION__); priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); break; } - dma = pci_map_single(mpt_dev->pcidev, skb->data, + dma = pci_map_single(mpt_dev->pcidev, skb->data, len, PCI_DMA_FROMDEVICE); priv->RcvCtl[ctx].skb = skb; @@ -1308,7 +1341,7 @@ dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", - __FUNCTION__, priv->total_posted, priv->total_received)); + __FUNCTION__, priv->total_posted, priv->total_received)); clear_bit(0, &priv->post_buckets_active); } @@ -1336,7 +1369,7 @@ priv->post_buckets_task.data = dev; priv->post_buckets_active = 0; - dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", + dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", __LINE__, dev->mtu + dev->hard_header_len + 4)); atomic_set(&priv->buckets_out, 0); @@ -1346,7 +1379,7 @@ if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out) priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets; - dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n", + dlprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n", __LINE__, mpt_dev->pfacts[0].MaxLanBuckets, max_buckets_out, @@ -1389,7 +1422,7 @@ dev->tx_timeout = mpt_lan_tx_timeout; dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; - dprintk((KERN_INFO MYNAM ": Finished registering dev " + dlprintk((KERN_INFO MYNAM ": Finished registering dev " "and setting initial values\n")); SET_MODULE_OWNER(dev); @@ -1407,9 +1440,11 @@ show_mptmod_ver(LANAME, LANVER); - /* Init the global r/w lock for the bad_naa list. We want to do this +#ifdef QLOGIC_NAA_WORKAROUND + /* Init the global r/w lock for the bad_naa list. We want to do this before any boards are initialized and may be used. */ rwlock_init(&bad_naa_lock); +#endif if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); @@ -1419,10 +1454,10 @@ /* Set the callback index to be used by driver core for turbo replies */ mpt_lan_index = LanCtx; - dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); + dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } else { printk(KERN_ERR MYNAM ": Eieee! unable to register a reset " "handler with mptbase! The world is at an end! " @@ -1458,7 +1493,7 @@ // IOC_AND_NETDEV_NAMES_s_s(dev), // NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); mpt_landev[j] = dev; - dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", + dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", dev, j, mpt_landev[j])); j++; @@ -1508,18 +1543,15 @@ MODULE_PARM(tx_max_out_p, "i"); MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME! -MODULE_LICENSE("GPL"); - module_init(mpt_lan_init); module_exit(mpt_lan_exit); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static unsigned short -mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) +mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) { struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; struct fcllc *fcllc; - u16 source_naa = fch->stype, found = 0; skb->mac.raw = skb->data; skb_pull(skb, sizeof(struct mpt_lan_ohdr)); @@ -1535,7 +1567,7 @@ printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", NETDEV_PTR_TO_IOC_NAME_s(dev)); printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - fch->saddr[0], fch->saddr[1], fch->saddr[2], + fch->saddr[0], fch->saddr[1], fch->saddr[2], fch->saddr[3], fch->saddr[4], fch->saddr[5]); } @@ -1555,6 +1587,10 @@ fcllc = (struct fcllc *)skb->data; +#ifdef QLOGIC_NAA_WORKAROUND +{ + u16 source_naa = fch->stype, found = 0; + /* Workaround for QLogic not following RFC 2625 in regards to the NAA value. */ @@ -1562,15 +1598,15 @@ source_naa = swab16(source_naa); if (fcllc->ethertype == htons(ETH_P_ARP)) - dprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of " + dlprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of " "%04x.\n", source_naa)); - if ((fcllc->ethertype == htons(ETH_P_ARP)) && + if ((fcllc->ethertype == htons(ETH_P_ARP)) && ((source_naa >> 12) != MPT_LAN_NAA_RFC2625)){ struct NAA_Hosed *nh, *prevnh; int i; - dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from " + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from " "system with non-RFC 2625 NAA value (%04x).\n", source_naa)); @@ -1584,17 +1620,17 @@ (nh->ieee[4] == fch->saddr[4]) && (nh->ieee[5] == fch->saddr[5])) { found = 1; - dprintk ((KERN_INFO "mptlan/type_trans: ARP Re" + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Re" "q/Rep w/ bad NAA from system already" " in DB.\n")); break; } } - + if ((!found) && (nh == NULL)) { nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL); - dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/" + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/" " bad NAA from system not yet in DB.\n")); if (nh != NULL) { @@ -1603,11 +1639,11 @@ mpt_bad_naa = nh; if (prevnh) prevnh->next = nh; - + nh->NAA = source_naa; /* Set the S_NAA value. */ for (i = 0; i < FC_ALEN; i++) nh->ieee[i] = fch->saddr[i]; - dprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:" + dlprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:" "%02x:%02x with non-compliant S_NAA value.\n", fch->saddr[0], fch->saddr[1], fch->saddr[2], fch->saddr[3], fch->saddr[4],fch->saddr[5])); @@ -1622,9 +1658,10 @@ } write_unlock_irq(&bad_naa_lock); } - +} +#endif - /* Strip the SNAP header from ARP packets since we don't + /* Strip the SNAP header from ARP packets since we don't * pass them through to the 802.2/SNAP layers. */ if (fcllc->dsap == EXTENDED_SAP && diff -urN linux-2.4.18/drivers/message/fusion/mptlan.h linux-2.4.19-pre5/drivers/message/fusion/mptlan.h --- linux-2.4.18/drivers/message/fusion/mptlan.h Sun Feb 17 11:40:32 2002 +++ linux-2.4.19-pre5/drivers/message/fusion/mptlan.h Sat Mar 30 22:55:39 2002 @@ -21,6 +21,7 @@ #include #include #include +#include // #include #include @@ -43,13 +44,15 @@ #define MPT_LAN_MAX_BUCKETS_OUT 256 #define MPT_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH 10 #define MPT_LAN_RX_COPYBREAK 200 -#define MPT_LAN_TX_TIMEOUT (1*HZ) +#define MPT_LAN_TX_TIMEOUT (1*HZ) #define MPT_TX_MAX_OUT_LIM 127 #define MPT_LAN_MIN_MTU 96 /* RFC2625 */ #define MPT_LAN_MAX_MTU 65280 /* RFC2625 */ -#define MPT_LAN_MTU 16128 /* be nice to slab allocator */ +#define MPT_LAN_MTU 13312 /* Max perf range + lower mem + usage than 16128 */ #define MPT_LAN_NAA_RFC2625 0x1 #define MPT_LAN_NAA_QLOGIC 0x2 @@ -64,6 +67,12 @@ #define dioprintk(x) printk x #else #define dioprintk(x) +#endif + +#ifdef MPT_LAN_DEBUG +#define dlprintk(x) printk x +#else +#define dlprintk(x) #endif #define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) diff -urN linux-2.4.18/drivers/message/fusion/mptscsih.c linux-2.4.19-pre5/drivers/message/fusion/mptscsih.c --- linux-2.4.18/drivers/message/fusion/mptscsih.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/fusion/mptscsih.c Sat Mar 30 22:55:39 2002 @@ -9,17 +9,24 @@ * This driver would not exist if not for Alan Cox's development * of the linux i2o driver. * + * A special thanks to Pamela Delaney (LSI Logic) for tons of work + * and countless enhancements while adding support for the 1030 + * chip family. Pam has been instrumental in the development of + * of the 2.xx.xx series fusion drivers, and her contributions are + * far too numerous to hope to list in one place. + * * A huge debt of gratitude is owed to David S. Miller (DaveM) * for fixing much of the stupid and broken stuff in the early * driver while porting to sparc64 platform. THANK YOU! * * (see mptbase.c) * - * Copyright (c) 1999-2001 LSI Logic Corporation + * Copyright (c) 1999-2002 LSI Logic Corporation * Original author: Steven J. Ralston - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.c,v 1.29.4.1 2001/09/18 03:22:30 sralston Exp $ + * $Id: mptscsih.c,v 1.80 2002/02/27 18:44:27 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -66,6 +73,9 @@ #include #include #include /* for io_request_lock (spinlock) decl */ +#include /* for mdelay */ +#include /* needed for in_interrupt() proto */ +#include /* notifier code */ #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" #include "../../scsi/sd.h" @@ -83,52 +93,131 @@ MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +/* Set string for command line args from insmod */ +#ifdef MODULE +char *mptscsih = 0; +MODULE_PARM(mptscsih, "s"); +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ typedef struct _BIG_SENSE_BUF { - u8 data[256]; + u8 data[MPT_SENSE_BUFFER_ALLOC]; } BIG_SENSE_BUF; -typedef struct _MPT_SCSI_HOST { - MPT_ADAPTER *ioc; - int port; - struct scsi_cmnd **ScsiLookup; - u8 *SgHunks; - dma_addr_t SgHunksDMA; - u32 qtag_tick; -} MPT_SCSI_HOST; - -typedef struct _MPT_SCSI_DEV { - struct _MPT_SCSI_DEV *forw; - struct _MPT_SCSI_DEV *back; - MPT_ADAPTER *ioc; - int sense_sz; - BIG_SENSE_BUF CachedSense; - unsigned long io_cnt; - unsigned long read_cnt; -} MPT_SCSI_DEV; +#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */ +#define MPT_SCANDV_DID_RESET (0x00000001) +#define MPT_SCANDV_SENSE (0x00000002) +#define MPT_SCANDV_SOME_ERROR (0x00000004) +#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) + +#define MPT_SCANDV_MAX_RETRIES (10) + +#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */ +#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */ +#define MPT_ICFLAG_PHYS_DISK 0x04 /* Any SCSI IO but do Phys Disk Format */ +#define MPT_ICFLAG_TAGGED_CMD 0x08 /* Do tagged IO */ +#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occured with this command */ +#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ + +typedef struct _internal_cmd { + char *data; /* data pointer */ + dma_addr_t data_dma; /* data dma address */ + int size; /* transfer size */ + u8 cmd; /* SCSI Op Code */ + u8 bus; /* bus number */ + u8 id; /* SCSI ID (virtual) */ + u8 lun; + u8 flags; /* Bit Field - See above */ + u8 physDiskNum; /* Phys disk number, -1 else */ + u8 rsvd2; + u8 rsvd; +} INTERNAL_CMD; + +typedef struct _negoparms { + u8 width; + u8 offset; + u8 factor; + u8 flags; +} NEGOPARMS; + +typedef struct _dv_parameters { + NEGOPARMS max; + NEGOPARMS now; + u8 cmd; + u8 id; + u16 pad1; +} DVPARAMETERS; + /* * Other private/forward protos... */ - static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static int mptscsih_io_direction(Scsi_Cmnd *cmd); + +static int mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, + SCSIIORequest_t *pReq, int req_idx); +static void mptscsih_AddNullSGE(SCSIIORequest_t *pReq); +static int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex); +static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx); +static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init); + static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); -static u32 SCPNT_TO_MSGCTX(Scsi_Cmnd *sc); +#ifndef MPT_SCSI_USE_NEW_EH +static void search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd); +#endif +static u32 SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc); +static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx); +static void post_pendingQ_commands(MPT_SCSI_HOST *hd); + +static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag); +static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag); static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +static VirtDevice *mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target); +static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); +static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data); +static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); +static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags); +static int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +static void mptscsih_timer_expired(unsigned long data); +static void mptscsih_taskmgmt_timeout(unsigned long data); +static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); +static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum); + +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION +static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io); +static void mptscsih_domainValidation(void *hd); +static void mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target); +static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); +static void mptscsih_fillbuf(char *buffer, int size, int index, int width); +#endif +static int mptscsih_setup(char *str); +static int mptscsih_halt(struct notifier_block *nb, ulong event, void *buf); + +/* + * Reboot Notification + */ +static struct notifier_block mptscsih_notifier = { + mptscsih_halt, NULL, 0 +}; + +/* + * Private data... + */ static int mpt_scsi_hosts = 0; static atomic_t queue_depth; static int ScsiDoneCtx = -1; static int ScsiTaskCtx = -1; +static int ScsiScanDvCtx = -1; /* Used only for bus scan and dv */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) static struct proc_dir_entry proc_mpt_scsihost = @@ -141,23 +230,40 @@ }; #endif -#define SNS_LEN(scp) sizeof((scp)->sense_buffer) +#define SNS_LEN(scp) sizeof((scp)->sense_buffer) #ifndef MPT_SCSI_USE_NEW_EH /* * Stuff to handle single-threading SCSI TaskMgmt * (abort/reset) requests... */ -static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED; -static MPT_Q_TRACKER mpt_scsih_taskQ = { - (MPT_FRAME_HDR*) &mpt_scsih_taskQ, - (MPT_FRAME_HDR*) &mpt_scsih_taskQ -}; -static int mpt_scsih_taskQ_cnt = 0; -static int mpt_scsih_taskQ_bh_active = 0; -static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL; +static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED; +static int mytaskQ_bh_active = 0; +static struct tq_struct mptscsih_ptaskfoo; +static atomic_t mpt_taskQdepth; +#endif + +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION +/* + * Domain Validation task structure + */ +static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED; +static int dvtaskQ_active = 0; +static int dvtaskQ_release = 0; +static struct tq_struct mptscsih_dvTask; #endif +/* + * Wait Queue setup + */ +static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq); +static int scandv_wait_done = 1; + +/* Driver default setup + */ +static struct mptscsih_driver_setup + driver_setup = MPTSCSIH_DRIVER_SETUP; + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_io_done - Main SCSI IO callback routine registered to @@ -174,123 +280,109 @@ * Returns 1 indicating alloc'd request frame ptr should be freed. */ static int -mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { Scsi_Cmnd *sc; MPT_SCSI_HOST *hd; - MPT_SCSI_DEV *mpt_sdev = NULL; + SCSIIORequest_t *pScsiReq; + SCSIIOReply_t *pScsiReply; + unsigned long flags; u16 req_idx; + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if ((mf == NULL) || (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf); - return 1; + printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n", + ioc->name, mf?"BAD":"NULL", mf); + /* return 1; CHECKME SteveR. Don't free. */ + return 0; } - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); sc = hd->ScsiLookup[req_idx]; - hd->ScsiLookup[req_idx] = NULL; + if (sc == NULL) { + MPIHeader_t *hdr = (MPIHeader_t *)mf; - dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + atomic_dec(&queue_depth); - atomic_dec(&queue_depth); + /* writeSDP1 will use the ScsiDoneCtx + * There is no processing for the reply. + * Just return to the calling function. + */ + if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) + printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name); - /* - * Check for {1st} {IO} completion to "new" device. - * How do we know it's a new device? - * If we haven't set SDpnt->hostdata I guess... - */ - if (sc && sc->device) { - mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata; - if (!mpt_sdev) { - dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n", - sc->device->id, sc->device->lun, sc->device->channel)); - if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) { - printk(KERN_ERR MYNAM ": ERROR - kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV)); - } else { - memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV)); - mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata; - mpt_sdev->ioc = ioc; - } - } else { - if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) { - if (++mpt_sdev->read_cnt == 3) { - dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n", - sc->cmnd[0])); - } - } -#if 0 - if (mpt_sdev->sense_sz) { - /* - * Completion of first IO down this path - * *should* invalidate device SenseData... - */ - mpt_sdev->sense_sz = 0; - } -#endif - } + mptscsih_freeChainBuffers(hd, req_idx); + return 1; } -#if 0 -{ - MPT_FRAME_HDR *mf_chk; + dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n", + ioc->name, mf, mr, sc)); - /* This, I imagine, is a costly check, but... - * If abort/reset active, check to see if this is a IO - * that completed while ABORT/RESET for it is waiting - * on our taskQ! - */ - if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { - /* If ABORT for this IO is queued, zap it! */ - mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); - if (mf_chk != NULL) { - sc->result = DID_ABORT << 16; - spin_lock_irqsave(&io_request_lock, flags); - sc->scsi_done(sc); - spin_unlock_irqrestore(&io_request_lock, flags); - return 1; - } - } -} -#endif + atomic_dec(&queue_depth); - if (r != NULL && sc != NULL) { - SCSIIOReply_t *pScsiReply; - SCSIIORequest_t *pScsiReq; - u16 status; + sc->result = DID_OK << 16; /* Set default reply as OK */ + pScsiReq = (SCSIIORequest_t *) mf; + pScsiReply = (SCSIIOReply_t *) mr; + + if (pScsiReply == NULL) { + /* special context reply handling */ + + /* If regular Inquiry cmd - save inquiry data + */ + if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) { + int dlen; - pScsiReply = (SCSIIOReply_t *) r; - pScsiReq = (SCSIIORequest_t *) mf; + dlen = le32_to_cpu(pScsiReq->DataLength); + if (dlen >= SCSI_STD_INQUIRY_BYTES) { + mptscsih_initTarget(hd, + hd->port, + sc->target, + pScsiReq->LUN[1], + sc->buffer, + dlen); + } + } + clear_sense_flag(hd, pScsiReq); + + if (hd->is_spi) + mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); + } else { + u32 xfer_cnt; + u16 status; + u8 scsi_state; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_state = pScsiReply->SCSIState; - dprintk((KERN_NOTICE MYNAM ": Uh-Oh! (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", + ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], + mf, mr, sc)); dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" - ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, pScsiReply->SCSIState, pScsiReply->SCSIStatus, - le32_to_cpu(pScsiReply->IOCLogInfo))); + ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", + status, scsi_state, pScsiReply->SCSIStatus, + le32_to_cpu(pScsiReply->IOCLogInfo))); + + if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) + copy_sense_data(sc, hd, mf, pScsiReply); /* * Look for + dump FCP ResponseInfo[]! */ - if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n", le32_to_cpu(pScsiReply->ResponseInfo))); } switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ - /*sc->result = DID_BUS_BUSY << 16;*/ /* YIKES! - Seems to - * kill linux interrupt - * handler - */ - sc->result = STS_BUSY; /* Try SCSI BUSY! */ - break; - - case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ - /* Not real sure here... */ - sc->result = DID_OK << 16; + /* CHECKME! + * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) + * But not: DID_BUS_BUSY lest one risk + * killing interrupt handler:-( + */ + sc->result = STS_BUSY; break; case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ @@ -299,10 +391,29 @@ break; case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - /* Spoof to SCSI Selection Timeout! */ + /* Spoof to SCSI Selection Timeout! */ sc->result = DID_NO_CONNECT << 16; break; + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ +#ifndef MPT_SCSI_USE_NEW_EH + search_taskQ_for_cmd(sc, hd); +#endif + /* Linux handles an unsolicited DID_RESET better + * than an unsolicited DID_ABORT. + */ + sc->result = DID_RESET << 16; + break; + + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ +#ifndef MPT_SCSI_USE_NEW_EH + search_taskQ_for_cmd(sc, hd); +#endif + sc->result = DID_RESET << 16; + break; + + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ /* * YIKES! I just discovered that SCSI IO which @@ -312,78 +423,148 @@ * Do upfront check for valid SenseData and give it * precedence! */ + sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; + clear_sense_flag(hd, pScsiReq); if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - copy_sense_data(sc, hd, mf, pScsiReply); - sc->result = pScsiReply->SCSIStatus; - break; + /* Have already saved the status and sense data + */ + ; + } else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_RESET << 16; } - dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); - dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount))); + /* Give report and update residual count. + */ + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", + sc->underflow)); + dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount); - dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid)); + sc->resid = sc->request_bufflen - xfer_cnt; + dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); #endif - if (pScsiReq->CDB[0] == INQUIRY) { - sc->result = (DID_OK << 16); - break; - } + /* Report Queue Full + */ + if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) + mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); - /* workaround attempts... */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - if (sc->resid >= 0x200) { - /* GRRRRR... - * //sc->result = DID_SOFT_ERROR << 16; - * Try spoofing to BUSY - */ - sc->result = STS_BUSY; - } else { - sc->result = 0; + /* If regular Inquiry cmd and some data was transferred, + * save inquiry data + */ + if ( pScsiReq->CDB[0] == INQUIRY + && !(pScsiReq->CDB[1] & 0x3) + && xfer_cnt >= SCSI_STD_INQUIRY_BYTES + ) { + mptscsih_initTarget(hd, + hd->port, + sc->target, + pScsiReq->LUN[1], + sc->buffer, + xfer_cnt); } -#else - sc->result = 0; -#endif - break; - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - sc->result = DID_ABORT << 16; - break; - - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - sc->result = DID_RESET << 16; + if (hd->is_spi) + mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); break; + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - sc->result = pScsiReply->SCSIStatus; + sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; + clear_sense_flag(hd, pScsiReq); if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - copy_sense_data(sc, hd, mf, pScsiReply); - - /* If running agains circa 200003dd 909 MPT f/w, - * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL - * (QUEUE_FULL) returned from device! --> get 0x0000?128 - * and with SenseBytes set to 0. + /* + * If running agains circa 200003dd 909 MPT f/w, + * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL + * (QUEUE_FULL) returned from device! --> get 0x0000?128 + * and with SenseBytes set to 0. */ if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + +#ifndef MPT_SCSI_USE_NEW_EH + /* ADDED 20011120 -sralston + * Scsi mid-layer (old_eh) doesn't seem to like it + * when RAID returns SCSIStatus=02 (CHECK CONDITION), + * SenseKey=01 (RECOVERED ERROR), ASC/ASCQ=95/01. + * Seems to be * treating this as a IO error:-( + * + * So just lie about it altogether here. + * + * NOTE: It still gets reported to syslog via + * mpt_ScsiHost_ErrorReport from copy_sense_data + * call far above. + */ + if ( pScsiReply->SCSIStatus == STS_CHECK_CONDITION + && SD_Sense_Key(sc->sense_buffer) == SK_RECOVERED_ERROR + ) { + sc->result = 0; + } +#endif + } - else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + else if (pScsiReply->SCSIState & + (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) + ) { /* - * What to do? + * What to do? */ sc->result = DID_SOFT_ERROR << 16; } else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { /* Not real sure here either... */ - sc->result = DID_ABORT << 16; + sc->result = DID_RESET << 16; + } + else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) { + /* Device Inq. data indicates that it supports + * QTags, but rejects QTag messages. + * This command completed OK. + * + * Not real sure here either so do nothing... */ } if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + /* Add handling of: + * Reservation Conflict, Busy, + * Command Terminated, CHECK + */ + + /* If regular Inquiry cmd - save inquiry data + */ + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + if ( sc->result == (DID_OK << 16) + && pScsiReq->CDB[0] == INQUIRY + && !(pScsiReq->CDB[1] & 0x3) + && xfer_cnt >= SCSI_STD_INQUIRY_BYTES + ) { + mptscsih_initTarget(hd, + hd->port, + sc->target, + pScsiReq->LUN[1], + sc->buffer, + xfer_cnt); + } + + if (hd->is_spi) + mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); + break; + + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_RESET << 16; + } else + sc->result = DID_SOFT_ERROR << 16; break; case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ @@ -395,50 +576,50 @@ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ default: /* - * What to do? + * What to do? */ sc->result = DID_SOFT_ERROR << 16; break; } /* switch(status) */ - dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result)); + dprintk((KERN_NOTICE " sc->result set to %08xh\n", sc->result)); + } /* end of address reply case */ + + /* Unmap the DMA buffers, if any. */ + if (sc->use_sg) { + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, + sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction)); + } else if (sc->request_bufflen) { + scPrivate *my_priv; + + my_priv = (scPrivate *) &sc->SCp; + pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, + sc->request_bufflen, + scsi_to_pci_dma_dir(sc->sc_data_direction)); } - if (sc != NULL) { - unsigned long flags; + hd->ScsiLookup[req_idx] = NULL; - /* Unmap the DMA buffers, if any. */ - if (sc->use_sg) { - pci_unmap_sg(ioc->pcidev, - (struct scatterlist *) sc->request_buffer, - sc->use_sg, - scsi_to_pci_dma_dir(sc->sc_data_direction)); - } else if (sc->request_bufflen) { - pci_unmap_single(ioc->pcidev, - (dma_addr_t)((long)sc->SCp.ptr), - sc->request_bufflen, - scsi_to_pci_dma_dir(sc->sc_data_direction)); - } + sc->host_scribble = NULL; /* CHECKME! - Do we need to clear this??? */ - spin_lock_irqsave(&io_request_lock, flags); - sc->scsi_done(sc); - spin_unlock_irqrestore(&io_request_lock, flags); - } + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); /* Issue the command callback */ + spin_unlock_irqrestore(&io_request_lock, flags); + /* Free Chain buffers */ + mptscsih_freeChainBuffers(hd, req_idx); return 1; } -#ifndef MPT_SCSI_USE_NEW_EH +#ifndef MPT_SCSI_USE_NEW_EH /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * search_taskQ - Search SCSI task mgmt request queue for specific - * request type + * request type. * @remove: (Boolean) Should request be removed if found? * @sc: Pointer to Scsi_Cmnd structure * @task_type: Task type to search for @@ -447,42 +628,55 @@ * was not found. */ static MPT_FRAME_HDR * -search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type) +search_taskQ(int remove, Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, u8 task_type) { MPT_FRAME_HDR *mf = NULL; unsigned long flags; int count = 0; int list_sz; - dslprintk((KERN_INFO MYNAM ": spinlock#1\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - list_sz = mpt_scsih_taskQ_cnt; - if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { - mf = mpt_scsih_taskQ.head; + dprintk((KERN_INFO MYNAM ": search_taskQ(%d,sc=%p,%d) called\n", + remove, sc, task_type)); + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + list_sz = hd->taskQcnt; + if (! Q_IS_EMPTY(&hd->taskQ)) { + mf = hd->taskQ.head; do { count++; if (mf->u.frame.linkage.argp1 == sc && mf->u.frame.linkage.arg1 == task_type) { if (remove) { Q_DEL_ITEM(&mf->u.frame.linkage); - mpt_scsih_taskQ_cnt--; + hd->taskQcnt--; + atomic_dec(&mpt_taskQdepth); + + /* Don't save mf into nextmf because + * exit after command has been deleted. + */ + + /* Place the MF back on the FreeQ */ + Q_ADD_TAIL(&hd->ioc->FreeQ, + &mf->u.frame.linkage, + MPT_FRAME_HDR); +#ifdef MFCNT + hd->ioc->mfcnt--; +#endif } break; } - } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ); - if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) { + } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ); + if (mf == (MPT_FRAME_HDR*)&hd->taskQ) { mf = NULL; } } - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); if (list_sz) { - dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n", - remove, sc, task_type, + dprintk((KERN_INFO " Results=%p (%sFOUND%s)!\n", mf, mf ? "" : "NOT_", (mf && remove) ? "+REMOVED" : "" )); - dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n", + dprintk((KERN_INFO " (searched thru %d of %d items on taskQ)\n", count, list_sz )); } @@ -490,2107 +684,6547 @@ return mf; } -#endif - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -/* - * Hack! I'd like to report if a device is returning QUEUE_FULL - * but maybe not each and every time... - */ -static long last_queue_full = 0; - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_report_queue_full - Report QUEUE_FULL status returned - * from a SCSI target device. - * @sc: Pointer to Scsi_Cmnd structure - * @pScsiReply: Pointer to SCSIIOReply_t - * @pScsiReq: Pointer to original SCSI request + * clean_taskQ - Clean the SCSI task mgmt request for + * this SCSI host instance. + * @hd: MPT_SCSI_HOST pointer * - * This routine periodically reports QUEUE_FULL status returned from a - * SCSI target device. It reports this to the console via kernel - * printk() API call, not more than once every 10 seconds. + * Returns: None. */ static void -mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) +clean_taskQ(MPT_SCSI_HOST *hd) { - long time = jiffies; + MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *nextmf = NULL; + MPT_ADAPTER *ioc = hd->ioc; + unsigned long flags; - if (time - last_queue_full > 10 * HZ) { - printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL! SCSI bus:target:lun = %d:%d:%d\n", - 0, sc->target, sc->lun); - last_queue_full = time; + dprintk((KERN_INFO MYNAM ": clean_taskQ called\n")); + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&hd->taskQ)) { + mf = hd->taskQ.head; + do { + Q_DEL_ITEM(&mf->u.frame.linkage); + hd->taskQcnt--; + atomic_dec(&mpt_taskQdepth); + + nextmf = mf->u.frame.linkage.forw; + + /* Place the MF back on the FreeQ */ + Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, + MPT_FRAME_HDR); +#ifdef MFCNT + hd->ioc->mfcnt--; +#endif + } while ((mf = nextmf) != (MPT_FRAME_HDR*)&hd->taskQ); } -} + spin_unlock_irqrestore(&ioc->FreeQlock, flags); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int BeenHereDoneThat = 0; + return; +} -/* SCSI fops start here... */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with - * linux scsi mid-layer. - * @tpnt: Pointer to Scsi_Host_Template structure - * - * (linux Scsi_Host_Template.detect routine) +/* + * search_taskQ_for_cmd - Search the SCSI task mgmt request queue for + * the specified command. If found, delete + * @hd: MPT_SCSI_HOST pointer * - * Returns number of SCSI host adapters that were successfully - * registered with the linux scsi mid-layer via the scsi_register() - * API call. + * Returns: None. */ -int -mptscsih_detect(Scsi_Host_Template *tpnt) +static void +search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd) { - struct Scsi_Host *sh = NULL; - MPT_SCSI_HOST *hd = NULL; - MPT_ADAPTER *this; - unsigned long flags; - int sz; - u8 *mem; + MPT_FRAME_HDR *mf = NULL; + unsigned long flags; + int count = 0; - if (! BeenHereDoneThat++) { - show_mptmod_ver(my_NAME, my_VERSION); + dprintk((KERN_INFO MYNAM ": search_taskQ_for_cmd(sc=%p) called\n", sc)); + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (! Q_IS_EMPTY(&hd->taskQ)) { + mf = hd->taskQ.head; + do { + count++; + if (mf->u.frame.linkage.argp1 == sc) { + Q_DEL_ITEM(&mf->u.frame.linkage); + hd->taskQcnt--; + atomic_dec(&mpt_taskQdepth); + dprintk((KERN_INFO MYNAM + ": Cmd %p found! Deleting.\n", sc)); - if ((ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER)) <= 0) { - printk(KERN_ERR MYNAM ": Failed to register callback1 with MPT base driver\n"); - return mpt_scsi_hosts; - } - if ((ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER)) <= 0) { - printk(KERN_ERR MYNAM ": Failed to register callback2 with MPT base driver\n"); - return mpt_scsi_hosts; - } + /* Don't save mf into nextmf because + * exit after command has been deleted. + */ -#ifndef MPT_SCSI_USE_NEW_EH - Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); - spin_lock_init(&mpt_scsih_taskQ_lock); + /* Place the MF back on the FreeQ */ + Q_ADD_TAIL(&hd->ioc->FreeQ, + &mf->u.frame.linkage, + MPT_FRAME_HDR); +#ifdef MFCNT + hd->ioc->mfcnt--; #endif + break; + } + } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ); + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { - dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); - } else { - /* FIXME! */ - } + return; +} - if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - } else { - /* FIXME! */ - } - } +#endif /* } MPT_SCSI_USE_NEW_EH */ - dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n")); - this = mpt_adapter_find_first(); - while (this != NULL) { - /* FIXME! Multi-port (aka FC929) support... - * for (i = 0; i < this->facts.NumberOfPorts; i++) - */ +/* + * Flush all commands on the doneQ. + * Lock Q when deleting/adding members + * Lock io_request_lock for OS callback. + */ +static void +flush_doneQ(MPT_SCSI_HOST *hd) +{ + MPT_DONE_Q *buffer; + Scsi_Cmnd *SCpnt; + unsigned long flags; - /* 20010215 -sralston - * Added sanity check on SCSI Initiator-mode enabled - * for this MPT adapter. - */ - if (!(this->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { - printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n", - this->name); - this = mpt_adapter_find_next(this); - continue; + /* Flush the doneQ. + */ + dprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); + while (1) { + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (Q_IS_EMPTY(&hd->doneQ)) { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + break; } - /* 20010202 -sralston - * Added sanity check on readiness of the MPT adapter. + buffer = hd->doneQ.head; + /* Delete from Q */ - if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { - printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n", - this->name); - this = mpt_adapter_find_next(this); - continue; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - tpnt->proc_dir = &proc_mpt_scsihost; -#endif - sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); - if (sh != NULL) { - save_flags(flags); - cli(); - sh->io_port = 0; - sh->n_io_port = 0; - sh->irq = 0; - - /* Yikes! This is important! - * Otherwise, by default, linux only scans target IDs 0-7! - * - * BUG FIX! 20010618 -sralston & pdelaney - * FC919 testing was encountering "duplicate" FC devices, - * as it turns out because the 919 was returning 512 - * for PortFacts.MaxDevices, causing a wraparound effect - * in SCSI IO requests. So instead of using: - * sh->max_id = this->pfacts[0].MaxDevices - 1 - * we'll use a definitive max here. - */ - sh->max_id = MPT_MAX_FC_DEVICES; - - sh->this_id = this->pfacts[0].PortSCSIID; - - restore_flags(flags); - - hd = (MPT_SCSI_HOST *) sh->hostdata; - hd->ioc = this; - hd->port = 0; /* FIXME! */ - - /* SCSI needs Scsi_Cmnd lookup table! - * (with size equal to req_depth*PtrSz!) - */ - sz = hd->ioc->req_depth * sizeof(void *); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) - return mpt_scsi_hosts; - - memset(mem, 0, sz); - hd->ScsiLookup = (struct scsi_cmnd **) mem; - - dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n", - hd->ScsiLookup, sz)); - - /* SCSI also needs SG buckets/hunk management! - * (with size equal to N * req_sz * req_depth!) - * (where N is number of SG buckets per hunk) - */ - sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; - mem = pci_alloc_consistent(hd->ioc->pcidev, sz, - &hd->SgHunksDMA); - if (mem == NULL) - return mpt_scsi_hosts; + Q_DEL_ITEM(buffer); - memset(mem, 0, sz); - hd->SgHunks = (u8*)mem; - - dprintk((KERN_INFO MYNAM ": SgHunks @ %p(%08x), sz=%d\n", - hd->SgHunks, hd->SgHunksDMA, sz)); + /* Set the Scsi_Cmnd pointer + */ + SCpnt = (Scsi_Cmnd *) buffer->argp; + buffer->argp = NULL; - hd->qtag_tick = jiffies; + /* Add to the freeQ + */ + Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); - this->sh = sh; - mpt_scsi_hosts++; - } - this = mpt_adapter_find_next(this); + /* Do the OS callback. + */ + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); } - return mpt_scsi_hosts; + return; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static char *info_kbuf = NULL; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_release - Unregister SCSI host from linux scsi mid-layer - * @host: Pointer to Scsi_Host structure +/* + * Search the doneQ for a specific command. If found, delete from Q. + * Calling function will finish processing. + */ +static void +search_doneQ_for_cmd(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + MPT_DONE_Q *buffer; + + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->doneQ)) { + buffer = hd->doneQ.head; + do { + Scsi_Cmnd *sc = (Scsi_Cmnd *) buffer->argp; + if (SCpnt == sc) { + Q_DEL_ITEM(buffer); + SCpnt->result = sc->result; + + /* Set the Scsi_Cmnd pointer + */ + buffer->argp = NULL; + + /* Add to the freeQ + */ + Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); + break; + } + } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ); + } + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + return; +} + +/* + * mptscsih_flush_running_cmds - For each command found, search + * Scsi_Host instance taskQ and reply to OS. + * Called only if recovering from a FW reload. + * @hd: Pointer to a SCSI HOST structure * - * (linux Scsi_Host_Template.release routine) - * This routine releases all resources associated with the SCSI host - * adapter. + * Returns: None. * - * Returns 0 for success. + * Must be called while new I/Os are being queued. */ -int -mptscsih_release(struct Scsi_Host *host) +static void +mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { - MPT_SCSI_HOST *hd; -#ifndef MPT_SCSI_USE_NEW_EH + Scsi_Cmnd *SCpnt = NULL; + MPT_FRAME_HDR *mf = NULL; + int ii; + int max = hd->ioc->req_depth; unsigned long flags; - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - if (mpt_scsih_taskQ_bh_active) { - int count = 10 * HZ; + dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); + for (ii= 0; ii < max; ii++) { + if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { - dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); + /* Command found. + */ + +#ifndef MPT_SCSI_USE_NEW_EH + /* Search taskQ, if found, delete. + */ + search_taskQ_for_cmd(SCpnt, hd); +#endif + + /* Search pendingQ, if found, + * delete from Q. If found, do not decrement + * queue_depth, command never posted. + */ + if (mptscsih_search_pendingQ(hd, ii) == NULL) + atomic_dec(&queue_depth); - /* Zap the taskQ! */ - Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + /* Null ScsiLookup index + */ + hd->ScsiLookup[ii] = NULL; - while(mpt_scsih_taskQ_bh_active && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + mf = MPT_INDEX_2_MFPTR(hd->ioc, ii); + dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", + mf, SCpnt)); + + /* Set status + * Do OS callback + * Free chain buffers + * Free message frame + */ + SCpnt->result = DID_RESET << 16; + SCpnt->host_scribble = NULL; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); /* Issue the command callback */ + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Free Chain buffers */ + mptscsih_freeChainBuffers(hd, ii); + + /* Free Message frames */ + mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); } - if (!count) - printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n"); } - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); -#endif + return; +} - hd = (MPT_SCSI_HOST *) host->hostdata; - if (hd != NULL) { - int sz1, sz2; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_initChainBuffers - Allocate memory for and initialize + * chain buffers, chain buffer control arrays and spinlock. + * @hd: Pointer to MPT_SCSI_HOST structure + * @init: If set, initialize the spin lock. + */ +static int +mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init) +{ + MPT_FRAME_HDR *chain; + u8 *mem; + unsigned long flags; + int sz, ii, numChain; - sz1 = sz2 = 0; - if (hd->ScsiLookup != NULL) { - sz1 = hd->ioc->req_depth * sizeof(void *); - kfree(hd->ScsiLookup); - hd->ScsiLookup = NULL; - } - if (hd->SgHunks != NULL) { + /* Chain buffer allocations + * Allocate and initialize tracker structures + */ + if (hd->ioc->req_sz <= 64) + numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth; + else if (hd->ioc->req_sz <= 96) + numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth; + else + numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth; - sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; - pci_free_consistent(hd->ioc->pcidev, sz2, - hd->SgHunks, hd->SgHunksDMA); - hd->SgHunks = NULL; - } - dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2)); + sz = numChain * sizeof(int); + + if (hd->ReqToChain == NULL) { + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + return -1; + + hd->ReqToChain = (int *) mem; + } else { + mem = (u8 *) hd->ReqToChain; } + memset(mem, 0xFF, sz); - if (mpt_scsi_hosts) { - if (--mpt_scsi_hosts == 0) { -#if 0 - mptscsih_flush_pending(); -#endif - mpt_reset_deregister(ScsiDoneCtx); - dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); + if (hd->ChainToChain == NULL) { + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + return -1; - mpt_event_deregister(ScsiDoneCtx); - dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); + hd->ChainToChain = (int *) mem; + } else { + mem = (u8 *) hd->ChainToChain; + } + memset(mem, 0xFF, sz); - mpt_deregister(ScsiDoneCtx); - mpt_deregister(ScsiTaskCtx); + if (hd->ChainBuffer == NULL) { + /* Allocate free chain buffer pool + */ + sz = numChain * hd->ioc->req_sz; + mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA); + if (mem == NULL) + return -1; - if (info_kbuf != NULL) - kfree(info_kbuf); - } + hd->ChainBuffer = (u8*)mem; + } else { + mem = (u8 *) hd->ChainBuffer; + } + memset(mem, 0, sz); + + dprintk((KERN_INFO " ChainBuffer @ %p(%p), sz=%d\n", + hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz)); + + /* Initialize the free chain Q. + */ + if (init) { + spin_lock_init(&hd->FreeChainQlock); } + spin_lock_irqsave (&hd->FreeChainQlock, flags); + Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR); + + /* Post the chain buffers to the FreeChainQ. + */ + mem = (u8 *)hd->ChainBuffer; + for (ii=0; ii < numChain; ii++) { + chain = (MPT_FRAME_HDR *) mem; + Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); + mem += hd->ioc->req_sz; + } + spin_unlock_irqrestore(&hd->FreeChainQlock, flags); + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_info - Return information about MPT adapter - * @SChost: Pointer to Scsi_Host structure - * - * (linux Scsi_Host_Template.info routine) +/* + * Hack! It might be nice to report if a device is returning QUEUE_FULL + * but maybe not each and every time... + */ +static long last_queue_full = 0; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_report_queue_full - Report QUEUE_FULL status returned + * from a SCSI target device. + * @sc: Pointer to Scsi_Cmnd structure + * @pScsiReply: Pointer to SCSIIOReply_t + * @pScsiReq: Pointer to original SCSI request * - * Returns pointer to buffer where information was written. + * This routine periodically reports QUEUE_FULL status returned from a + * SCSI target device. It reports this to the console via kernel + * printk() API call, not more than once every 10 seconds. */ -const char * -mptscsih_info(struct Scsi_Host *SChost) +static void +mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) { - MPT_SCSI_HOST *h; - int size = 0; - - if (info_kbuf == NULL) - if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) - return info_kbuf; + long time = jiffies; - h = (MPT_SCSI_HOST *)SChost->hostdata; - info_kbuf[0] = '\0'; - mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); - info_kbuf[size-1] = '\0'; + if (time - last_queue_full > 10 * HZ) { + char *ioc_str = "ioc?"; - return info_kbuf; + if (sc->host && sc->host->hostdata) + ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name; + printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", + ioc_str, 0, sc->target, sc->lun); + last_queue_full = time; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static int max_qd = 1; -#ifdef MPT_DEBUG - static int max_sges = 0; - static int max_xfer = 0; -#endif -#if 0 - static int max_num_sges = 0; - static int max_sgent_len = 0; -#endif -#if 0 -static int index_log[128]; -static int index_ent = 0; -static __inline__ void ADD_INDEX_LOG(int req_ent) -{ - int i = index_ent++; +static int BeenHereDoneThat = 0; - index_log[i & (128 - 1)] = req_ent; -} -#else -#define ADD_INDEX_LOG(req_ent) do { } while(0) -#endif +/* SCSI host fops start here... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. - * @SCpnt: Pointer to Scsi_Cmnd structure - * @done: Pointer SCSI mid-layer IO completion function + * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with + * linux scsi mid-layer. + * @tpnt: Pointer to Scsi_Host_Template structure * - * (linux Scsi_Host_Template.queuecommand routine) - * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest - * from a linux Scsi_Cmnd request and send it to the IOC. + * (linux Scsi_Host_Template.detect routine) * - * Returns 0. (rtn value discarded by linux scsi mid-layer) + * Returns number of SCSI host adapters that were successfully + * registered with the linux scsi mid-layer via the scsi_register() + * API call. */ int -mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +mptscsih_detect(Scsi_Host_Template *tpnt) { - struct Scsi_Host *host; - MPT_SCSI_HOST *hd; - MPT_FRAME_HDR *mf; - SCSIIORequest_t *pScsiReq; - int datadir; - u32 len; - u32 sgdir; - u32 scsictl; - u32 scsidir; - u32 qtag; - u32 *mptr; - int sge_spill1; - int frm_sz; - int sges_left; - u32 chain_offset; - int my_idx; - int i; + struct Scsi_Host *sh = NULL; + MPT_SCSI_HOST *hd = NULL; + MPT_ADAPTER *this; + MPT_DONE_Q *freedoneQ; + unsigned long flags; + int sz, ii; + int numSGE = 0; + int scale; + u8 *mem; - dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n", - SCpnt, done)); + if (! BeenHereDoneThat++) { + show_mptmod_ver(my_NAME, my_VERSION); - host = SCpnt->host; - hd = (MPT_SCSI_HOST *) host->hostdata; - -#if 0 - if (host->host_busy >= 60) { - MPT_ADAPTER *ioc = hd->ioc; - u16 pci_command, pci_status; - - /* The IOC is probably hung, investigate status. */ - printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n", - readl(&ioc->chip.fc9xx->DoorbellValue), - readl(&ioc->chip.fc9xx->IntStatus), - readl(&ioc->chip.fc9xx->ReplyFifo)); - pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command); - pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status); - printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status); - { - /* DUMP req index logger. */ - int begin, end; + ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER); + ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER); + ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER); - begin = (index_ent - 65) & (128 - 1); - end = index_ent & (128 - 1); - printk("MPI: REQ_INDEX_HIST["); - while (begin != end) { - printk("(%04x)", index_log[begin]); - begin = (begin + 1) & (128 - 1); - } - printk("\n"); - } - sti(); - while(1) - barrier(); - } +#ifndef MPT_SCSI_USE_NEW_EH + spin_lock_init(&mytaskQ_lock); #endif - SCpnt->scsi_done = done; + if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { + dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); + } else { + /* FIXME! */ + } - /* 20000617 -sralston - * GRRRRR... Shouldn't have to do this but... - * Do explicit check for REQUEST_SENSE and cached SenseData. - * If yes, return cached SenseData. - */ -#ifdef MPT_SCSI_CACHE_AUTOSENSE - { - MPT_SCSI_DEV *mpt_sdev; + if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) { + dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + } else { + /* FIXME! */ + } + } + dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n")); - mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata; - if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) { - u8 *dest = NULL; +#ifdef MODULE + /* Evaluate the command line arguments, if any */ + if (mptscsih) + mptscsih_setup(mptscsih); +#endif +#ifndef MPT_SCSI_USE_NEW_EH + atomic_set(&mpt_taskQdepth, 0); +#endif - if (!SCpnt->use_sg) - dest = SCpnt->request_buffer; - else { - struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; - if (sg) - dest = (u8 *) (unsigned long)sg_dma_address(sg); + this = mpt_adapter_find_first(); + while (this != NULL) { + int portnum; + for (portnum=0; portnum < this->facts.NumberOfPorts; portnum++) { + + /* 20010215 -sralston + * Added sanity check on SCSI Initiator-mode enabled + * for this MPT adapter. + */ + if (!(this->pfacts[portnum].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { + printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n", + this->name); + continue; } - if (dest && mpt_sdev->sense_sz) { - memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz); -#ifdef MPT_DEBUG - { - int i; - u8 *sb; - - sb = mpt_sdev->CachedSense.data; - if (sb && ((sb[0] & 0x70) == 0x70)) { - printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n"); - printk(KERN_WARNING " "); - for (i = 0; i < (8 + sb[7]); i++) - printk("%s%02x", i == 13 ? "-" : " ", sb[i]); - printk("\n"); - } - } -#endif + /* 20010202 -sralston + * Added sanity check on readiness of the MPT adapter. + */ + if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n", + this->name); + continue; } - SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz; - SCpnt->result = 0; -/* spin_lock(&io_request_lock); */ - SCpnt->scsi_done(SCpnt); -/* spin_unlock(&io_request_lock); */ - return 0; - } - } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + tpnt->proc_dir = &proc_mpt_scsihost; #endif + sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); + if (sh != NULL) { + save_flags(flags); + cli(); + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* Yikes! This is important! + * Otherwise, by default, linux + * only scans target IDs 0-7! + * pfactsN->MaxDevices unreliable + * (not supported in early + * versions of the FW). + * max_id = 1 + actual max id, + * max_lun = 1 + actual last lun, + * see hosts.h :o( + */ + if ((int)this->chip_type > (int)FC929) + sh->max_id = MPT_MAX_SCSI_DEVICES; + else { + /* For FC, increase the queue depth + * from MPT_SCSI_CAN_QUEUE (31) + * to MPT_FC_CAN_QUEUE (63). + */ + sh->can_queue = MPT_FC_CAN_QUEUE; + sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; + } + sh->max_lun = MPT_LAST_LUN + 1; - if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); -/* return 1; */ - return 0; - } - pScsiReq = (SCSIIORequest_t *) mf; + sh->this_id = this->pfacts[portnum].PortSCSIID; - my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + /* OS entry to allow host drivers to force + * a queue depth on a per device basis. + */ + sh->select_queue_depths = mptscsih_select_queue_depths; - ADD_INDEX_LOG(my_idx); + /* Verify that we won't exceed the maximum + * number of chain buffers + * We can optimize: ZZ = req_sz/sizeof(MptSge_t) + * For 32bit SGE's: + * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ + * + (req_sz - 64)/sizeof(MptSge_t) + * A slightly different algorithm is required for + * 64bit SGEs. + */ + scale = this->req_sz/sizeof(MptSge_t); + if (sizeof(MptSge_t) == sizeof(SGESimple32_t)) { + numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale + + (this->req_sz - 64) / (sizeof(MptSge_t)); + } else if (sizeof(MptSge_t) == sizeof(SGESimple64_t)) { + numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale + + (this->req_sz - 60) / (sizeof(MptSge_t)); + } - /* Map the data portion, if any. */ - sges_left = SCpnt->use_sg; - if (sges_left) { - sges_left = pci_map_sg(hd->ioc->pcidev, - (struct scatterlist *) SCpnt->request_buffer, - sges_left, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - } else if (SCpnt->request_bufflen) { - dma_addr_t buf_dma_addr; + if (numSGE < sh->sg_tablesize) { + /* Reset this value */ + dprintk((MYIOC_s_INFO_FMT + "Resetting sg_tablesize to %d from %d\n", + this->name, numSGE, sh->sg_tablesize)); + sh->sg_tablesize = numSGE; + } - buf_dma_addr = pci_map_single(hd->ioc->pcidev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + restore_flags(flags); - /* We hide it here for later unmap. */ - SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr; - } + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = this; - /* - * Put together a MPT SCSI request... - */ + if ((int)this->chip_type > (int)FC929) + hd->is_spi = 1; - /* Assume SimpleQ, NO DATA XFER for now */ + if (DmpService && + (this->chip_type == FC919 || this->chip_type == FC929)) + hd->is_multipath = 1; - len = SCpnt->request_bufflen; - sgdir = 0x00000000; /* SGL IN (host<--ioc) */ - scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; + hd->port = 0; /* FIXME! */ - /* - * The scsi layer should be handling this stuff - * (In 2.3.x it does -DaveM) - */ - - /* BUG FIX! 19991030 -sralston - * TUR's being issued with scsictl=0x02000000 (DATA_IN)! - * Seems we may receive a buffer (len>0) even when there - * will be no data transfer! GRRRRR... - */ - datadir = mptscsih_io_direction(SCpnt); - if (datadir < 0) { - scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ - } else if (datadir > 0) { - sgdir = 0x04000000; /* SGL OUT (host-->ioc) */ - scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ - } else { - len = 0; - } - - qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; - - /* - * Attach tags to the devices - */ - if (SCpnt->device->tagged_supported) { - /* - * Some drives are too stupid to handle fairness issues - * with tagged queueing. We throw in the odd ordered - * tag to stop them starving themselves. - */ - if ((jiffies - hd->qtag_tick) > (5*HZ)) { - qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; - hd->qtag_tick = jiffies; + /* SCSI needs Scsi_Cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = hd->ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + goto done; -#if 0 - /* These are ALWAYS zero! - * (Because this is a place for the device driver to dynamically - * assign tag numbers any way it sees fit. That's why -DaveM) - */ - dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n", - SCpnt->device->current_tag)); - dprintk((KERN_DEBUG MYNAM ": sc->tag = %08x\n", - SCpnt->tag)); -#endif - } -#if 0 - else { - /* Hmmm... I always see value of 0 here, - * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston - * (Because this is a place for the device driver to dynamically - * assign tag numbers any way it sees fit. That's why -DaveM) - * - * if (SCpnt->tag == HEAD_OF_QUEUE_TAG) - */ - if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG) - qtag = MPI_SCSIIO_CONTROL_HEADOFQ; - else if (SCpnt->tag == ORDERED_QUEUE_TAG) - qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; - } -#endif - } + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; - scsictl = scsidir | qtag; + dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", + this->name, hd->ScsiLookup, sz)); - frm_sz = hd->ioc->req_sz; + if (mptscsih_initChainBuffers(hd, 1) < 0) + goto done; - /* Ack! - * sge_spill1 = 9; - */ - sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8; - /* spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9 - * spill1: for req_sz == 96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5 - */ - dsgprintk((KERN_INFO MYNAM ": SG: %x spill1 = %d\n", - my_idx, sge_spill1)); - -#ifdef MPT_DEBUG - if (sges_left > max_sges) { - max_sges = sges_left; - dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges)); - } -#endif -#if 0 - if (sges_left > max_num_sges) { - max_num_sges = sges_left; - printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges); - } -#endif + /* Allocate memory for free and doneQ's + */ + sz = sh->can_queue * sizeof(MPT_DONE_Q); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + goto done; - dsgprintk((KERN_INFO MYNAM ": SG: %x sges_left = %d (initially)\n", - my_idx, sges_left)); + memset(mem, 0xFF, sz); + hd->memQ = mem; - chain_offset = 0; - if (sges_left > (sge_spill1+1)) { -#if 0 - chain_offset = 0x1E; -#endif - chain_offset = (frm_sz - 8) / 4; - } + /* Initialize the free, done and pending Qs. + */ + Q_INIT(&hd->freeQ, MPT_DONE_Q); + Q_INIT(&hd->doneQ, MPT_DONE_Q); + Q_INIT(&hd->pendingQ, MPT_DONE_Q); + spin_lock_init(&hd->freedoneQlock); + + mem = hd->memQ; + for (ii=0; ii < sh->can_queue; ii++) { + freedoneQ = (MPT_DONE_Q *) mem; + Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); + mem += sizeof(MPT_DONE_Q); + } - pScsiReq->TargetID = SCpnt->target; - pScsiReq->Bus = hd->port; - pScsiReq->ChainOffset = chain_offset; - pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; - pScsiReq->CDBLength = SCpnt->cmd_len; + /* Initialize this Scsi_Host + * internal task Q. + */ + Q_INIT(&hd->taskQ, MPT_FRAME_HDR); + hd->taskQcnt = 0; -/* We have 256 bytes alloc'd per IO; let's use it. */ -/* pScsiReq->SenseBufferLength = SNS_LEN(SCpnt); */ - pScsiReq->SenseBufferLength = 255; + /* Allocate memory for the device structures. + * A non-Null pointer at an offset + * indicates a device exists. + * max_id = 1 + maximum id (hosts.h) + */ + sz = sh->max_id * sizeof(void *); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + goto done; - pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = 0; - pScsiReq->LUN[0] = 0; - pScsiReq->LUN[1] = SCpnt->lun; - pScsiReq->LUN[2] = 0; - pScsiReq->LUN[3] = 0; - pScsiReq->LUN[4] = 0; - pScsiReq->LUN[5] = 0; - pScsiReq->LUN[6] = 0; - pScsiReq->LUN[7] = 0; - pScsiReq->Control = cpu_to_le32(scsictl); + memset(mem, 0, sz); + hd->Targets = (VirtDevice **) mem; - /* - * Write SCSI CDB into the message - */ - for (i = 0; i < 12; i++) - pScsiReq->CDB[i] = SCpnt->cmnd[i]; - for (i = 12; i < 16; i++) - pScsiReq->CDB[i] = 0; + dprintk((KERN_INFO " Targets @ %p, sz=%d\n", hd->Targets, sz)); - /* DataLength */ - pScsiReq->DataLength = cpu_to_le32(len); - /* SenseBuffer low address */ - pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256)); + /* Clear the TM flags + */ + hd->tmPending = 0; + hd->resetPending = 0; + hd->abortSCpnt = NULL; + hd->tmPtr = NULL; + hd->numTMrequests = 0; + + /* Clear the pointer used to store + * single-threaded commands, i.e., those + * issued during a bus scan, dv and + * configuration pages. + */ + hd->cmdPtr = NULL; - mptr = (u32 *) &pScsiReq->SGL; + /* Attach the SCSI Host to the IOC structure + */ + this->sh = sh; - /* - * Now fill in the SGList... - * NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's - * in the remaining request frame. We -could- do unlimited chains - * but each chain buffer can only be req_sz bytes in size, and - * we lose one SGE whenever we chain. - * For 128 req_sz, we can hold up to 16 SGE's per chain buffer. - * For practical reasons, limit ourselves to 1 overflow chain buffer; - * giving us 9 + 16 == 25 SGE's max. - * At 4 Kb per SGE, that yields 100 Kb max transfer. - * - * (This code needs to be completely changed when/if 64-bit DMA - * addressing is used, since we will be able to fit much less than - * 10 embedded SG entries. -DaveM) - */ - if (sges_left) { - struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; - u32 v1, v2; - int sge_spill2; - int sge_cur_spill; - int sgCnt; - u8 *pSgBucket; - int chain_sz; - - len = 0; - - /* sge_spill2 = 15; - * spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15 - * spill2: for req_sz == 96 ( 96/8==12 SGEs max, first time!), --> use 11 - */ - sge_spill2 = frm_sz / 8 - 1; - dsgprintk((KERN_INFO MYNAM ": SG: %x spill2 = %d\n", - my_idx, sge_spill2)); - - pSgBucket = NULL; - sgCnt = 0; - sge_cur_spill = sge_spill1; - while (sges_left) { -#if 0 - if (sg_dma_len(sg) > max_sgent_len) { - max_sgent_len = sg_dma_len(sg); - printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len); - } -#endif - /* Write one simple SGE */ - v1 = sgdir | 0x10000000 | sg_dma_len(sg); - len += sg_dma_len(sg); - v2 = sg_dma_address(sg); - dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x, sges_left=%d\n", - my_idx, mptr, v1, v2, sges_left)); - *mptr++ = cpu_to_le32(v1); - *mptr++ = cpu_to_le32(v2); - sg++; - sgCnt++; - - if (--sges_left == 0) { - /* re-write 1st word of previous SGE with SIMPLE, - * LE, EOB, and EOL bits! - */ - v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1); - dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n", - my_idx, mptr-2, v1)); - *(mptr - 2) = cpu_to_le32(v1); - } else { - if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) { - dsgprintk((KERN_INFO MYNAM ": SG: %x SG spill at modulo 0!\n", - my_idx)); - - /* Fixup previous SGE with LE bit! */ - v1 = sgdir | 0x90000000 | sg_dma_len(sg-1); - dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n", - my_idx, mptr-2, v1)); - *(mptr - 2) = cpu_to_le32(v1); - - chain_offset = 0; - /* Going to need another chain? */ - if (sges_left > (sge_spill2+1)) { -#if 0 - chain_offset = 0x1E; + /* Initialize this SCSI Hosts' timers + * To use, set the timer expires field + * and add_timer + */ + init_timer(&hd->timer); + hd->timer.data = (unsigned long) hd; + hd->timer.function = mptscsih_timer_expired; + + init_timer(&hd->TMtimer); + hd->TMtimer.data = (unsigned long) hd; + hd->TMtimer.function = mptscsih_taskmgmt_timeout; + hd->qtag_tick = jiffies; + + /* Moved Earlier Pam D */ + /* this->sh = sh; */ + + if (hd->is_spi) { + /* Update with the driver setup + * values. + */ + if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width) + hd->ioc->spi_data.maxBusWidth = driver_setup.max_width; + if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac) + hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac; + + if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) + hd->ioc->spi_data.maxSyncOffset = 0; + + hd->negoNvram = 0; +#ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; #endif - chain_offset = (frm_sz - 8) / 4; - chain_sz = frm_sz; - } else { - chain_sz = sges_left * 8; - } - - /* write chain SGE at mptr. */ - v1 = 0x30000000 | chain_offset<<16 | chain_sz; - if (pSgBucket == NULL) { - pSgBucket = hd->SgHunks - + (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK); - } else { - pSgBucket += frm_sz; - } - v2 = (hd->SgHunksDMA + - ((u8 *)pSgBucket - (u8 *)hd->SgHunks)); - dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x (CHAIN!)\n", - my_idx, mptr, v1, v2)); - *(mptr++) = cpu_to_le32(v1); - *(mptr) = cpu_to_le32(v2); + if (driver_setup.dv == 0) + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - mptr = (u32 *) pSgBucket; - sgCnt = 0; - sge_cur_spill = sge_spill2; - } - } - } - } else { - dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n", - SCpnt, SCpnt->request_bufflen)); + hd->ioc->spi_data.forceDv = 0; + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; - if (len > 0) { - dma_addr_t buf_dma_addr; - buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr; - *(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen); - *(mptr++) = cpu_to_le32(buf_dma_addr); - } - } + ddvprintk((MYIOC_s_INFO_FMT + "dv %x width %x factor %x \n", + hd->ioc->name, driver_setup.dv, + driver_setup.max_width, + driver_setup.min_sync_fac)); -#ifdef MPT_DEBUG - /* if (SCpnt->request_bufflen > max_xfer) */ - if (len > max_xfer) { - max_xfer = len; - dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer)); - } -#endif + } - hd->ScsiLookup[my_idx] = SCpnt; + mpt_scsi_hosts++; + } - /* Main banana... */ - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + } /* for each adapter port */ - atomic_inc(&queue_depth); - if (atomic_read(&queue_depth) > max_qd) { - max_qd = atomic_read(&queue_depth); - dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); + this = mpt_adapter_find_next(this); } - dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt)); +done: + if (mpt_scsi_hosts > 0) + register_reboot_notifier(&mptscsih_notifier); - return 0; + return mpt_scsi_hosts; } -#ifdef MPT_SCSI_USE_NEW_EH /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - mptscsih_abort - Returns: 0=SUCCESS, else FAILED -*/ + static char *info_kbuf = NULL; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant - * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * mptscsih_release - Unregister SCSI host from linux scsi mid-layer + * @host: Pointer to Scsi_Host structure * - * (linux Scsi_Host_Template.eh_abort_handler routine) + * (linux Scsi_Host_Template.release routine) + * This routine releases all resources associated with the SCSI host + * adapter. * - * Returns SUCCESS or FAILED. + * Returns 0 for success. */ int -mptscsih_abort(Scsi_Cmnd * SCpnt) +mptscsih_release(struct Scsi_Host *host) { - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; MPT_SCSI_HOST *hd; - u32 *msg; - u32 ctx2abort; - int i; + int count; unsigned long flags; - printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt); - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + hd = (MPT_SCSI_HOST *) host->hostdata; - hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; +#ifndef MPT_SCSI_USE_NEW_EH +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + spin_lock_irqsave(&dvtaskQ_lock, flags); + dvtaskQ_release = 1; + spin_unlock_irqrestore(&dvtaskQ_lock, flags); +#endif - if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - return FAILED; + spin_lock_irqsave(&mytaskQ_lock, flags); + if (mytaskQ_bh_active) { + count = 10 * HZ; + + spin_unlock_irqrestore(&mytaskQ_lock, flags); + dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); + clean_taskQ(hd); + + while(mytaskQ_bh_active && --count) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + if (!count) + printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n"); } + spin_unlock_irqrestore(&mytaskQ_lock, flags); +#endif - pScsiTm = (SCSITaskMgmt_t *) mf; - msg = (u32 *) mf; +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + /* Check DV thread active */ + count = 10 * HZ; + spin_lock_irqsave(&dvtaskQ_lock, flags); + while(dvtaskQ_active && --count) { + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + spin_lock_irqsave(&dvtaskQ_lock, flags); + } + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + if (!count) + printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n"); +#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) + else + printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count); +#endif +#endif - pScsiTm->TargetID = SCpnt->target; - pScsiTm->Bus = hd->port; - pScsiTm->ChainOffset = 0; - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + unregister_reboot_notifier(&mptscsih_notifier); - pScsiTm->Reserved = 0; - pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; - pScsiTm->Reserved1 = 0; - pScsiTm->MsgFlags = 0; + if (hd != NULL) { + int sz1, sz2, sz3, sztarget=0; + int szchain = 0; + int szQ = 0; + int scale; - for (i = 0; i < 8; i++) { - u8 val = 0; - if (i == 1) - val = SCpnt->lun; - pScsiTm->LUN[i] = val; - } + /* Synchronize disk caches + */ + (void) mptscsih_synchronize_cache(hd, 0); - for (i = 0; i < 7; i++) - pScsiTm->Reserved2[i] = 0; + sz1 = sz2 = sz3 = 0; - /* Most important! Set TaskMsgContext to SCpnt's MsgContext! - * (the IO to be ABORT'd) - * - * NOTE: Since we do not byteswap MsgContext, we do not - * swap it here either. It is an opaque cookie to - * the controller, so it does not matter. -DaveM - */ - ctx2abort = SCPNT_TO_MSGCTX(SCpnt); - if (ctx2abort == -1) { - printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); - } else { - dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); - pScsiTm->TaskMsgContext = ctx2abort; + if (hd->ioc->req_sz <= 64) + scale = MPT_SG_REQ_64_SCALE; + else if (hd->ioc->req_sz <= 96) + scale = MPT_SG_REQ_96_SCALE; + else + scale = MPT_SG_REQ_128_SCALE; + if (hd->ScsiLookup != NULL) { + sz1 = hd->ioc->req_depth * sizeof(void *); + kfree(hd->ScsiLookup); + hd->ScsiLookup = NULL; + } - /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake - mpt_put_msg_frame(hd->ioc->id, mf); - */ - if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, - sizeof(SCSITaskMgmt_t), msg)) - != 0) { - printk(KERN_WARNING MYNAM - ": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", - i, mf, SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + if (hd->ReqToChain != NULL) { + szchain += scale * hd->ioc->req_depth * sizeof(int); + kfree(hd->ReqToChain); + hd->ReqToChain = NULL; } - } - //return SUCCESS; - return FAILED; -} + if (hd->ChainToChain != NULL) { + szchain += scale * hd->ioc->req_depth * sizeof(int); + kfree(hd->ChainToChain); + hd->ChainToChain = NULL; + } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant - * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to - * - * (linux Scsi_Host_Template.eh_dev_reset_handler routine) - * - * Returns SUCCESS or FAILED. - */ -int -mptscsih_dev_reset(Scsi_Cmnd * SCpnt) -{ - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; - u32 *msg; - int i; - unsigned long flags; + if (hd->ChainBuffer != NULL) { + sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz; + szchain += sz2; - printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt); - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + pci_free_consistent(hd->ioc->pcidev, sz2, + hd->ChainBuffer, hd->ChainBufferDMA); + hd->ChainBuffer = NULL; + } - hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + if (hd->memQ != NULL) { + szQ = host->can_queue * sizeof(MPT_DONE_Q); + kfree(hd->memQ); + hd->memQ = NULL; + } - if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - return FAILED; - } + if (hd->Targets != NULL) { + int max, ii; - pScsiTm = (SCSITaskMgmt_t *) mf; - msg = (u32*)mf; + /* + * Free any target structures that were allocated. + */ + if (hd->is_spi) { + max = MPT_MAX_SCSI_DEVICES; + } else { + max = MPT_MAX_FC_DEVICES; + } + for (ii=0; ii < max; ii++) { + if (hd->Targets[ii]) { + kfree(hd->Targets[ii]); + hd->Targets[ii] = NULL; + sztarget += sizeof(VirtDevice); + } + } - pScsiTm->TargetID = SCpnt->target; - pScsiTm->Bus = hd->port; - pScsiTm->ChainOffset = 0; - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + /* + * Free pointer array. + */ + sz3 = max * sizeof(void *); + kfree(hd->Targets); + hd->Targets = NULL; + } - pScsiTm->Reserved = 0; - pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - pScsiTm->Reserved1 = 0; - pScsiTm->MsgFlags = 0; + dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n", + hd->ioc->name, sz1, szchain, sz3, sztarget)); + dprintk(("Free'd done and free Q (%d) memory\n", szQ)); + } + /* NULL the Scsi_Host pointer + */ + hd->ioc->sh = NULL; + scsi_unregister(host); + + if (mpt_scsi_hosts) { + if (--mpt_scsi_hosts == 0) { + mpt_reset_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); - /* _TARGET_RESET goes to LUN 0 always! */ - for (i = 0; i < 8; i++) - pScsiTm->LUN[i] = 0; - - /* Control: No data direction, set task mgmt bit? */ - for (i = 0; i < 7; i++) - pScsiTm->Reserved2[i] = 0; + mpt_event_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); - pScsiTm->TaskMsgContext = cpu_to_le32(0); + mpt_deregister(ScsiScanDvCtx); + mpt_deregister(ScsiTaskCtx); + mpt_deregister(ScsiDoneCtx); -/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake - mpt_put_msg_frame(hd->ioc->id, mf); -*/ -/* FIXME! Check return status! */ - if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, - sizeof(SCSITaskMgmt_t), msg)) - != 0) { - printk(KERN_WARNING MYNAM - ": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", - i, mf, SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + if (info_kbuf != NULL) + kfree(info_kbuf); + } } - //return SUCCESS; - return FAILED; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant - * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * mptscsih_halt - Process the reboot notification + * @nb: Pointer to a struct notifier_block (ignored) + * @event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF) + * @buf: Pointer to a data buffer (ignored) * - * (linux Scsi_Host_Template.eh_bus_reset_handler routine) + * This routine called if a system shutdown or reboot is to occur. * - * Returns SUCCESS or FAILED. + * Return NOTIFY_DONE if this is something other than a reboot message. + * NOTIFY_OK if this is a reboot message. */ -int -mptscsih_bus_reset(Scsi_Cmnd * SCpnt) +static int +mptscsih_halt(struct notifier_block *nb, ulong event, void *buf) { - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; - u32 *msg; - int i; - unsigned long flags; - - printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt); - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + MPT_ADAPTER *ioc = NULL; + MPT_SCSI_HOST *hd = NULL; - hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + /* Ignore all messages other than reboot message + */ + if ((event != SYS_RESTART) && (event != SYS_HALT) + && (event != SYS_POWER_OFF)) + return (NOTIFY_DONE); - if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - return FAILED; + for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { + /* Flush the cache of this adapter + */ + if (ioc->sh) { + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd) { + mptscsih_synchronize_cache(hd, 0); + } + } } - pScsiTm = (SCSITaskMgmt_t *) mf; - msg = (u32 *) mf; - - pScsiTm->TargetID = SCpnt->target; - pScsiTm->Bus = hd->port; - pScsiTm->ChainOffset = 0; - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + unregister_reboot_notifier(&mptscsih_notifier); + return NOTIFY_OK; +} - pScsiTm->Reserved = 0; - pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; - pScsiTm->Reserved1 = 0; - pScsiTm->MsgFlags = 0; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_info - Return information about MPT adapter + * @SChost: Pointer to Scsi_Host structure + * + * (linux Scsi_Host_Template.info routine) + * + * Returns pointer to buffer where information was written. + */ +const char * +mptscsih_info(struct Scsi_Host *SChost) +{ + MPT_SCSI_HOST *h; + int size = 0; - for (i = 0; i < 8; i++) - pScsiTm->LUN[i] = 0; + if (info_kbuf == NULL) + if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) + return info_kbuf; - /* Control: No data direction, set task mgmt bit? */ - for (i = 0; i < 7; i++) - pScsiTm->Reserved2[i] = 0; + h = (MPT_SCSI_HOST *)SChost->hostdata; + info_kbuf[0] = '\0'; + mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); + info_kbuf[size-1] = '\0'; - pScsiTm->TaskMsgContext = cpu_to_le32(0); + return info_kbuf; +} -/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake - mpt_put_msg_frame(hd->ioc->id, mf); -*/ -/* FIXME! Check return status! */ - if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, - sizeof(SCSITaskMgmt_t), msg)) - != 0) { - printk(KERN_WARNING MYNAM - ": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", - i, mf, SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); - } +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static int max_qd = 1; +#if 0 +static int index_log[128]; +static int index_ent = 0; +static __inline__ void ADD_INDEX_LOG(int req_ent) +{ + int i = index_ent++; - return SUCCESS; + index_log[i & (128 - 1)] = req_ent; } +#else +#define ADD_INDEX_LOG(req_ent) do { } while(0) +#endif + +#ifdef DROP_TEST +#define DROP_IOC 1 /* IOC to force failures */ +#define DROP_TARGET 3 /* Target ID to force failures */ +#define DROP_THIS_CMD 10000 /* iteration to drop command */ +static int dropCounter = 0; +static int dropTestOK = 0; /* num did good */ +static int dropTestBad = 0; /* num did bad */ +static int dropTestNum = 0; /* total = good + bad + incomplete */ +static int numTotCmds = 0; +static MPT_FRAME_HDR *dropMfPtr = NULL; +static int numTMrequested = 0; +#endif -#if 0 /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_host_reset - Perform a SCSI host adapter RESET! - * new_eh variant - * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to +/* + * mptscsih_put_msgframe - Wrapper routine to post message frame to F/W. + * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) + * @id: IOC id number + * @mf: Pointer to message frame * - * (linux Scsi_Host_Template.eh_host_reset_handler routine) + * Handles the call to mptbase for posting request and queue depth + * tracking. * - * Returns SUCCESS or FAILED. + * Returns none. */ -int -mptscsih_host_reset(Scsi_Cmnd * SCpnt) +static void +mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf) { - return FAILED; + /* Main banana... */ + atomic_inc(&queue_depth); + if (atomic_read(&queue_depth) > max_qd) { + max_qd = atomic_read(&queue_depth); + dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); + } + + mpt_put_msg_frame(context, id, mf); + + return; } -#endif /* } */ -#else /* MPT_SCSI old EH stuff... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_old_abort - Abort linux Scsi_Cmnd routine - * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. + * @SCpnt: Pointer to Scsi_Cmnd structure + * @done: Pointer SCSI mid-layer IO completion function * - * (linux Scsi_Host_Template.abort routine) + * (linux Scsi_Host_Template.queuecommand routine) + * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest + * from a linux Scsi_Cmnd request and send it to the IOC. * - * Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}. + * Returns 0. (rtn value discarded by linux scsi mid-layer) */ int -mptscsih_old_abort(Scsi_Cmnd *SCpnt) +mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; - struct tq_struct *ptaskfoo; + SCSIIORequest_t *pScsiReq; + VirtDevice *pTarget; + MPT_DONE_Q *buffer = NULL; unsigned long flags; + int target; + int lun; + int datadir; + u32 datalen; + u32 scsictl; + u32 scsidir; + u32 qtag; + u32 cmd_len; + int my_idx; + int ii; + int rc; + int did_errcode; + int issueCmd; - printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt); - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + did_errcode = 0; + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + target = SCpnt->target; + lun = SCpnt->lun; + SCpnt->scsi_done = done; - if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done(SCpnt); - return SCSI_ABORT_SUCCESS; - } + pTarget = hd->Targets[target]; - /* - * Check to see if there's already an ABORT queued for this guy. + dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); + + /* 20000617 -sralston + * GRRRRR... Shouldn't have to do this but... + * Do explicit check for REQUEST_SENSE and cached SenseData. + * If yes, return cached SenseData. */ - mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); - if (mf != NULL) { - return SCSI_ABORT_PENDING; + if (SCpnt->cmnd[0] == REQUEST_SENSE) { + u8 *dest = NULL; + int sz; + + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) { + pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; //sjr-moved-here + if (!SCpnt->use_sg) { + dest = SCpnt->request_buffer; + } else { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + if (sg) + dest = (u8 *)(ulong)sg_dma_address(sg); + } + + if (dest) { + sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen); + memcpy(dest, pTarget->sense, sz); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + SCpnt->resid = SCpnt->request_bufflen - sz; +#endif + SCpnt->result = 0; + SCpnt->scsi_done(SCpnt); + + //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; + + return 0; + } + } } - if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - return SCSI_ABORT_BUSY; + if (hd->resetPending) { + /* Prevent new commands from being issued + * while reloading the FW. + */ + did_errcode = 1; + goto did_error; } /* - * Add ourselves to (end of) mpt_scsih_taskQ. - * Check to see if our _bh is running. If NOT, schedule it. + * Put together a MPT SCSI request... */ - dslprintk((KERN_INFO MYNAM ": spinlock#2\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); - mpt_scsih_taskQ_cnt++; - /* Yikes - linkage! */ -/* SCpnt->host_scribble = (unsigned char *)mf; */ - mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; - mf->u.frame.linkage.argp1 = SCpnt; - if (! mpt_scsih_taskQ_bh_active) { - mpt_scsih_taskQ_bh_active = 1; - /* - * Oh how cute, no alloc/free/mgmt needed if we use - * (bottom/unused portion of) MPT request frame. - */ - ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); - ptaskfoo->sync = 0; - ptaskfoo->routine = mptscsih_taskmgmt_bh; - ptaskfoo->data = SCpnt; - - SCHEDULE_TASK(ptaskfoo); + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) { + dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", + hd->ioc->name)); + did_errcode = 2; + goto did_error; } - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); - - return SCSI_ABORT_PENDING; -} -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_old_reset - Perform a SCSI BUS_RESET! - * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to - * @reset_flags: (not used?) - * - * (linux Scsi_Host_Template.reset routine) - * - * Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}. - */ -int -mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) -{ - MPT_SCSI_HOST *hd; - MPT_FRAME_HDR *mf; - struct tq_struct *ptaskfoo; - unsigned long flags; + pScsiReq = (SCSIIORequest_t *) mf; - printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt); - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { - SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done(SCpnt); - return SCSI_RESET_SUCCESS; - } + ADD_INDEX_LOG(my_idx); /* - * Check to see if there's already a BUS_RESET queued for this guy. + * The scsi layer should be handling this stuff + * (In 2.3.x it does -DaveM) */ - mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS); - if (mf != NULL) { - return SCSI_RESET_PENDING; - } - if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { -/* SCpnt->result = DID_SOFT_ERROR << 16; */ - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - return SCSI_RESET_PUNT; + /* BUG FIX! 19991030 -sralston + * TUR's being issued with scsictl=0x02000000 (DATA_IN)! + * Seems we may receive a buffer (datalen>0) even when there + * will be no data transfer! GRRRRR... + */ + datadir = mptscsih_io_direction(SCpnt); + if (datadir < 0) { + datalen = SCpnt->request_bufflen; + scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ + } else if (datadir > 0) { + datalen = SCpnt->request_bufflen; + scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ + } else { + datalen = 0; + scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; } - /* - * Add ourselves to (end of) mpt_scsih_taskQ. - * Check to see if our _bh is running. If NOT, schedule it. + /* Default to untagged. Once a target structure has been allocated, + * use the Inquiry data to determine if device supports tagged. */ - dslprintk((KERN_INFO MYNAM ": spinlock#3\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); - mpt_scsih_taskQ_cnt++; - /* Yikes - linkage! */ -/* SCpnt->host_scribble = (unsigned char *)mf; */ - mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; - mf->u.frame.linkage.argp1 = SCpnt; - if (! mpt_scsih_taskQ_bh_active) { - mpt_scsih_taskQ_bh_active = 1; + qtag = MPI_SCSIIO_CONTROL_UNTAGGED; + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) + && (SCpnt->device->tagged_supported)) { /* - * Oh how cute, no alloc/free/mgmt needed if we use - * (bottom/unused portion of) MPT request frame. + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. */ - ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); - ptaskfoo->sync = 0; - ptaskfoo->routine = mptscsih_taskmgmt_bh; - ptaskfoo->data = SCpnt; - - SCHEDULE_TASK(ptaskfoo); + if ((jiffies - hd->qtag_tick) > (5*HZ)) { + qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; + hd->qtag_tick = jiffies; + } + else + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; } - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + scsictl = scsidir | qtag; - return SCSI_RESET_PENDING; -} + /* Use the above information to set up the message frame + */ + pScsiReq->TargetID = target; + pScsiReq->Bus = hd->port; + pScsiReq->ChainOffset = 0; + pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; + pScsiReq->CDBLength = SCpnt->cmd_len; + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + pScsiReq->Reserved = 0; + pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS; + pScsiReq->LUN[0] = 0; + pScsiReq->LUN[1] = lun; + pScsiReq->LUN[2] = 0; + pScsiReq->LUN[3] = 0; + pScsiReq->LUN[4] = 0; + pScsiReq->LUN[5] = 0; + pScsiReq->LUN[6] = 0; + pScsiReq->LUN[7] = 0; + pScsiReq->Control = cpu_to_le32(scsictl); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler - * @sc: (unused) - * - * This routine (thread) is active whenever there are any outstanding - * SCSI task management requests for a SCSI host adapter. - * IMPORTANT! This routine is scheduled therefore should never be - * running in ISR context. i.e., it's safe to sleep here. - */ -void -mptscsih_taskmgmt_bh(void *sc) -{ - Scsi_Cmnd *SCpnt; - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; - u32 ctx2abort = 0; - int i; - unsigned long flags; - u8 task_type; + /* + * Write SCSI CDB into the message + */ + cmd_len = SCpnt->cmd_len; + for (ii=0; ii < cmd_len; ii++) + pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; + for (ii=cmd_len; ii < 16; ii++) + pScsiReq->CDB[ii] = 0; - dslprintk((KERN_INFO MYNAM ": spinlock#4\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - mpt_scsih_taskQ_bh_active = 1; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + /* DataLength */ + pScsiReq->DataLength = cpu_to_le32(datalen); - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/4); + /* SenseBuffer low address */ + pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + + (my_idx * MPT_SENSE_BUFFER_ALLOC)); - /* - * We MUST remove item from taskQ *before* we format the - * frame as a SCSITaskMgmt request and send it down to the IOC. + /* Now add the SG list + * Always have a SGE even if null length. + */ + rc = SUCCESS; + if (datalen == 0) { + /* Add a NULL SGE */ + mptscsih_AddNullSGE(pScsiReq); + } else { + /* Add a 32 or 64 bit SGE */ + rc = mptscsih_Add32BitSGE(hd, SCpnt, pScsiReq, my_idx); + } + + + if (rc == SUCCESS) { + hd->ScsiLookup[my_idx] = SCpnt; + SCpnt->host_scribble = NULL; + +#ifdef DROP_TEST + numTotCmds++; + /* If the IOC number and target match, increment + * counter. If counter matches DROP_THIS, do not + * issue command to FW to force a reset. + * Save the MF pointer so we can free resources + * when task mgmt completes. */ - dslprintk((KERN_INFO MYNAM ": spinlock#5\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - if (Q_IS_EMPTY(&mpt_scsih_taskQ)) { - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); - break; - } - mf = mpt_scsih_taskQ.head; - Q_DEL_ITEM(&mf->u.frame.linkage); - mpt_scsih_taskQ_cnt--; - mpt_scsih_active_taskmgmt_mf = mf; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); - - SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1; - if (SCpnt == NULL) { - printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt); - continue; - } - hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; - pScsiTm = (SCSITaskMgmt_t *) mf; + if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) { + dropCounter++; - for (i = 0; i < 8; i++) { - pScsiTm->LUN[i] = 0; - } + if (dropCounter == DROP_THIS_CMD) { + dropCounter = 0; - task_type = mf->u.frame.linkage.arg1; - if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf=%p:sc=%p)\n", - mf, SCpnt); - - /* Most important! Set TaskMsgContext to SCpnt's MsgContext! - * (the IO to be ABORT'd) - * - * NOTE: Since we do not byteswap MsgContext, we do not - * swap it here either. It is an opaque cookie to - * the controller, so it does not matter. -DaveM - */ - ctx2abort = SCPNT_TO_MSGCTX(SCpnt); - if (ctx2abort == -1) { - printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); - continue; + /* If global is set, then we are already + * doing something - so keep issuing commands. + */ + if (dropMfPtr == NULL) { + dropTestNum++; + dropMfPtr = mf; + atomic_inc(&queue_depth); + printk(MYIOC_s_INFO_FMT + "Dropped SCSI cmd (%p)\n", + hd->ioc->name, SCpnt); + printk("mf (%p) req (%4x) tot cmds (%d)\n", + mf, my_idx, numTotCmds); + + return 0; + } } - pScsiTm->LUN[1] = SCpnt->lun; } - else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) - { - printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf=%p:sc=%p)\n", mf, SCpnt); - } -#if 0 - else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {} - else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {} #endif - printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + /* SCSI specific processing */ + issueCmd = 1; + if (hd->is_spi) { + int dvStatus = hd->ioc->spi_data.dvStatus[target]; + + if (dvStatus || hd->ioc->spi_data.forceDv) { + + /* Write SDP1 on 1st I/O to this target */ + if (dvStatus & MPT_SCSICFG_NEGOTIATE) { + mptscsih_writeSDP1(hd, 0, target, hd->negoNvram); + dvStatus &= ~MPT_SCSICFG_NEGOTIATE; + hd->ioc->spi_data.dvStatus[target] = dvStatus; + } - pScsiTm->TargetID = SCpnt->target; - pScsiTm->Bus = hd->port; - pScsiTm->ChainOffset = 0; - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) { + unsigned long lflags; + /* Schedule DV if necessary */ + spin_lock_irqsave(&dvtaskQ_lock, lflags); + if (!dvtaskQ_active) { + dvtaskQ_active = 1; + mptscsih_dvTask.sync = 0; + mptscsih_dvTask.routine = mptscsih_domainValidation; + mptscsih_dvTask.data = (void *) hd; - pScsiTm->Reserved = 0; - pScsiTm->TaskType = task_type; - pScsiTm->Reserved1 = 0; - pScsiTm->MsgFlags = 0; + SCHEDULE_TASK(&mptscsih_dvTask); + } + hd->ioc->spi_data.forceDv = 0; + spin_unlock_irqrestore(&dvtaskQ_lock, lflags); + } - for (i = 0; i < 7; i++) - pScsiTm->Reserved2[i] = 0; + /* Trying to do DV to this target, extend timeout. + * Wait to issue intil flag is clear + */ + if (dvStatus & MPT_SCSICFG_DV_PENDING) { + mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); + issueCmd = 0; + } +#endif + } + } - dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); - pScsiTm->TaskMsgContext = ctx2abort; + if (issueCmd) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n", + hd->ioc->name, SCpnt)); + } else { + ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n", + hd->ioc->name, SCpnt)); + /* Place this command on the pendingQ if possible */ + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->freeQ)) { + buffer = hd->freeQ.head; + Q_DEL_ITEM(buffer); - /* Control: No data direction, set task mgmt bit? */ + /* Save the mf pointer + */ + buffer->argp = (void *)mf; - /* - * As of MPI v0.10 this request can NOT be sent (normally) - * via FIFOs. So we can't: - * mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); - * SCSITaskMgmt requests MUST be sent ONLY via - * Doorbell/handshake now. :-( - */ - if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, - sizeof(SCSITaskMgmt_t), (u32*) mf)) - != 0) { - printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt); - SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); - } else { - /* Spin-Wait for TaskMgmt complete!!! */ - while (mpt_scsih_active_taskmgmt_mf != NULL) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/4); + /* Add to the pendingQ + */ + Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + } else { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + SCpnt->result = (DID_BUS_BUSY << 16); + SCpnt->scsi_done(SCpnt); } } + } else { + mptscsih_freeChainBuffers(hd, my_idx); + mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + did_errcode = 3; + goto did_error; } - dslprintk((KERN_INFO MYNAM ": spinlock#6\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - mpt_scsih_taskQ_bh_active = 0; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + return 0; - return; -} +did_error: + dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n", + hd->ioc->name, did_errcode, SCpnt)); + /* Just wish OS to issue a retry */ + SCpnt->result = (DID_BUS_BUSY << 16); + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->freeQ)) { + buffer = hd->freeQ.head; + Q_DEL_ITEM(buffer); -#endif /* } */ + /* Set the Scsi_Cmnd pointer + */ + buffer->argp = (void *)SCpnt; + + /* Add to the doneQ + */ + Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + } else { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + SCpnt->scsi_done(SCpnt); + } + + return 0; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_taskmgmt_complete - Callback routine, gets registered to - * Fusion MPT base driver - * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to SCSI task mgmt request frame - * @r: Pointer to SCSI task mgmt reply frame - * - * This routine is called from mptbase.c::mpt_interrupt() at the completion - * of any SCSI task management request. - * This routine is registered with the MPT (base) driver at driver - * load/init time via the mpt_register() API call. +/* + * mptscsih_Add32BitSGE - Add a 32Bit SGE (plus chain buffers) to the + * SCSIIORequest_t Message Frame. + * @hd: Pointer to MPT_SCSI_HOST structure + * @SCpnt: Pointer to Scsi_Cmnd structure + * @pReq: Pointer to SCSIIORequest_t structure * - * Returns 1 indicating alloc'd request frame ptr should be freed. + * Returns ... */ static int -mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, + SCSIIORequest_t *pReq, int req_idx) { - SCSITaskMgmtReply_t *pScsiTmReply; - SCSITaskMgmt_t *pScsiTmReq; - u8 tmType; -#ifndef MPT_SCSI_USE_NEW_EH - unsigned long flags; -#endif + MptSge_t *psge; + MptChain_t *chainSge; + struct scatterlist *sg; + int frm_sz; + int sges_left, sg_done; + int chain_idx = MPT_HOST_NO_CHAIN; + int sgeOffset; + int numSgeSlots, numSgeThisFrame; + u32 sgflags, sgdir, len, thisxfer = 0; + int offset; + int newIndex; + int ii; + dma_addr_t v2; + + sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; + if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { + sgdir = MPT_TRANSFER_HOST_TO_IOC; + } else { + sgdir = MPT_TRANSFER_IOC_TO_HOST; + } - dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n", - mf, r)); + psge = (MptSge_t *) &pReq->SGL; + frm_sz = hd->ioc->req_sz; -#ifndef MPT_SCSI_USE_NEW_EH - dslprintk((KERN_INFO MYNAM ": spinlock#7\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - /* It better be the active one! */ - if (mf != mpt_scsih_active_taskmgmt_mf) { - printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf); - mpt_scsih_active_taskmgmt_mf = NULL; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); - return 1; + /* Map the data portion, if any. + * sges_left = 0 if no data transfer. + */ + sges_left = SCpnt->use_sg; + if (SCpnt->use_sg) { + sges_left = pci_map_sg(hd->ioc->pcidev, + (struct scatterlist *) SCpnt->request_buffer, + SCpnt->use_sg, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else if (SCpnt->request_bufflen) { + dma_addr_t buf_dma_addr; + scPrivate *my_priv; + + buf_dma_addr = pci_map_single(hd->ioc->pcidev, + SCpnt->request_buffer, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* We hide it here for later unmap. */ + my_priv = (scPrivate *) &SCpnt->SCp; + my_priv->p1 = (void *)(ulong) buf_dma_addr; + + dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", + hd->ioc->name, SCpnt, SCpnt->request_bufflen)); + + /* 0xD1000000 = LAST | EOB | SIMPLE | EOL */ + psge->FlagsLength = cpu_to_le32( + 0xD1000000|sgdir|SCpnt->request_bufflen); + cpu_to_leXX(buf_dma_addr, psge->Address); + + return SUCCESS; } -#ifdef MPT_DEBUG - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf); - mpt_scsih_active_taskmgmt_mf = NULL; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); - return 1; + /* Handle the SG case. + */ + sg = (struct scatterlist *) SCpnt->request_buffer; + sg_done = 0; + sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); + chainSge = NULL; + + /* Prior to entering this loop - the following must be set + * current MF: sgeOffset (bytes) + * chainSge (Null if original MF is not a chain buffer) + * sg_done (num SGE done for this MF) + */ + +nextSGEset: + numSgeSlots = ((frm_sz - sgeOffset) / sizeof(MptSge_t)); + numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; + + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; + + /* Get first (num - 1) SG elements + * Skip any SG entries with a length of 0 + * NOTE: at finish, sg and psge pointed to NEXT data/location positions + */ + for (ii=0; ii < (numSgeThisFrame-1); ii++) { + thisxfer = sg_dma_len(sg); + if (thisxfer == 0) { + sg ++; /* Get next SG element from the OS */ + sg_done++; + continue; + } + + len += thisxfer; + psge->FlagsLength = cpu_to_le32( sgflags | thisxfer ); + v2 = sg_dma_address(sg); + cpu_to_leXX(v2, psge->Address); + + sg++; /* Get next SG element from the OS */ + psge++; /* Point to next SG location in this MF */ + sgeOffset += sizeof(MptSge_t); + sg_done++; } -#endif - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); -#endif - if (r != NULL) { - pScsiTmReply = (SCSITaskMgmtReply_t*)r; - pScsiTmReq = (SCSITaskMgmt_t*)mf; + if (numSgeThisFrame == sges_left) { + /* Add last element, end of buffer and end of list flags. + */ + sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT | + MPT_SGE_FLAGS_END_OF_BUFFER | + MPT_SGE_FLAGS_ADDRESSING | + MPT_SGE_FLAGS_END_OF_LIST; - /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ - tmType = pScsiTmReq->TaskType; + /* Add last SGE and set termination flags. + * Note: Last SGE may have a length of 0 - which should be ok. + */ + thisxfer = sg_dma_len(sg); + len += thisxfer; + + psge->FlagsLength = cpu_to_le32( sgflags | thisxfer ); + v2 = sg_dma_address(sg); + cpu_to_leXX(v2, psge->Address); + + sg_done++; + + if (chainSge) { + /* The current buffer is a chain buffer, + * but there is not another one. + * Update the chain element + * Offset and Length fields. + */ + chainSge->NextChainOffset = 0; + sgeOffset += sizeof(MptSge_t); + chainSge->Length = cpu_to_le16(sgeOffset); + } else { + /* The current buffer is the original MF + * and there is no Chain buffer. + */ + pReq->ChainOffset = 0; + } + } else { + /* At least one chain buffer is needed. + * Complete the first MF + * - last SGE element, set the LastElement bit + * - set ChainOffset (words) for orig MF + * (OR finish previous MF chain buffer) + * - update MFStructPtr ChainIndex + * - Populate chain element + * Also + * Loop until done. + */ - dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType)); - dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n", - le32_to_cpu(pScsiTmReply->TerminationCount))); + dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", + hd->ioc->name, sg_done)); - /* Error? (anything non-zero?) */ - if (*(u32 *)&pScsiTmReply->Reserved2[0]) { - dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType)); - dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n", - le16_to_cpu(pScsiTmReply->IOCStatus))); - dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n", - le32_to_cpu(pScsiTmReply->IOCLogInfo))); + /* Set LAST_ELEMENT flag for last non-chain element + * in the buffer. Since psge points at the NEXT + * SGE element, go back one SGE element, update the flags + * and reset the pointer. (Note: sgflags & thisxfer are already + * set properly). + */ + if (sg_done) { + psge--; + sgflags = le32_to_cpu (psge->FlagsLength); + sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; + psge->FlagsLength = cpu_to_le32( sgflags ); + psge++; + } + + if (chainSge) { + /* The current buffer is a chain buffer. + * chainSge points to the previous Chain Element. + * Update its chain element Offset and Length (must + * include chain element size) fields. + * Old chain element is now complete. + */ + chainSge->NextChainOffset = (u8) (sgeOffset >> 2); + sgeOffset += sizeof(MptSge_t); + chainSge->Length = cpu_to_le16(sgeOffset); } else { - dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType)); + /* The original MF buffer requires a chain buffer - + * set the offset. + * Last element in this MF is a chain element. + */ + pReq->ChainOffset = (u8) (sgeOffset >> 2); } - } -#ifndef MPT_SCSI_USE_NEW_EH - /* - * Signal to _bh thread that we finished. - */ - dslprintk((KERN_INFO MYNAM ": spinlock#8\n")); - spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); - mpt_scsih_active_taskmgmt_mf = NULL; - spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); -#endif + sges_left -= sg_done; - return 1; + + /* NOTE: psge points to the beginning of the chain element + * in current buffer. Get a chain buffer. + */ + if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) + return FAILED; + + /* Update the tracking arrays. + * If chainSge == NULL, update ReqToChain, else ChainToChain + */ + if (chainSge) { + hd->ChainToChain[chain_idx] = newIndex; + } else { + hd->ReqToChain[req_idx] = newIndex; + } + chain_idx = newIndex; + offset = hd->ioc->req_sz * chain_idx; + + /* Populate the chainSGE for the current buffer. + * - Set chain buffer pointer to psge and fill + * out the Address and Flags fields. + */ + chainSge = (MptChain_t *) psge; + chainSge->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; + cpu_to_leXX ((hd->ChainBufferDMA + offset), chainSge->Address); + + dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", + psge, req_idx)); + + /* Start the SGE for the next buffer + */ + psge = (MptSge_t *) (hd->ChainBuffer + offset); + sgeOffset = 0; + sg_done = 0; + + dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", + psge, chain_idx)); + + /* Start the SGE for the next buffer + */ + + goto nextSGEset; + } + + return SUCCESS; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * This is anyones guess quite frankly. + * mptscsih_AddNullSGE - Add a NULL SGE to the SCSIIORequest_t + * Message Frame. + * @pReq: Pointer to SCSIIORequest_t structure */ - -int -mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) +static void +mptscsih_AddNullSGE(SCSIIORequest_t *pReq) { - int size; + MptSge_t *psge; - size = disk->capacity; - ip[0] = 64; /* heads */ - ip[1] = 32; /* sectors */ - if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ - ip[0] = 255; /* heads */ - ip[1] = 63; /* sectors */ - ip[2] = size / (255 * 63); /* cylinders */ - } - return 0; + psge = (MptSge_t *) &pReq->SGL; + psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | 0); + + cpu_to_leXX( (dma_addr_t) -1, psge->Address); + + return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * Private routines... - */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* 19991030 -sralston - * Return absolute SCSI data direction: - * 1 = _DATA_OUT - * 0 = _DIR_NONE - * -1 = _DATA_IN + * mptscsih_getFreeChainBuffes - Function to get a free chain + * from the MPT_SCSI_HOST FreeChainQ. + * @hd: Pointer to the MPT_SCSI_HOST instance + * @req_idx: Index of the SCSI IO request frame. (output) + * + * return SUCCESS or FAILED */ static int -mptscsih_io_direction(Scsi_Cmnd *cmd) +mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) { - switch (cmd->cmnd[0]) { - /* _DATA_OUT commands */ - case WRITE_6: case WRITE_10: case WRITE_12: - case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: - case WRITE_VERIFY: case WRITE_VERIFY_12: - case COMPARE: case COPY: case COPY_VERIFY: - case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: - case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: - case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: - case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: - case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: - case REASSIGN_BLOCKS: - case PERSISTENT_RESERVE_OUT: - case 0xea: - return 1; + MPT_FRAME_HDR *chainBuf = NULL; + unsigned long flags; + int rc = FAILED; + int chain_idx = MPT_HOST_NO_CHAIN; - /* No data transfer commands */ - case SEEK_6: case SEEK_10: - case RESERVE: case RELEASE: - case TEST_UNIT_READY: - case START_STOP: - case ALLOW_MEDIUM_REMOVAL: - return 0; + //spin_lock_irqsave(&hd->FreeChainQlock, flags); + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!Q_IS_EMPTY(&hd->FreeChainQ)) { - /* Conditional data transfer commands */ - case FORMAT_UNIT: - if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ - return 1; - else - return 0; + int offset; - case VERIFY: - if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ - return 1; - else - return 0; + chainBuf = hd->FreeChainQ.head; + Q_DEL_ITEM(&chainBuf->u.frame.linkage); + offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; + chain_idx = offset / hd->ioc->req_sz; + rc = SUCCESS; + } + //spin_unlock_irqrestore(&hd->FreeChainQlock, flags); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - case RESERVE_10: - if (cmd->cmnd[1] & 0x03) /* RESERSE:{LongID|Extent} (data out phase)? */ - return 1; - else - return 0; -#if 0 - case REZERO_UNIT: /* (or REWIND) */ - case SPACE: - case ERASE: case ERASE_10: - case SYNCHRONIZE_CACHE: - case LOCK_UNLOCK_CACHE: -#endif + *retIndex = chain_idx; - /* Must be data _IN! */ - default: - return -1; - } + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", + hd->ioc->name, *retIndex, chainBuf)); + + return rc; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_freeChainBuffers - Function to free chain buffers associated + * with a SCSI IO request + * @hd: Pointer to the MPT_SCSI_HOST instance + * @req_idx: Index of the SCSI IO request frame. + * + * Called if SG chain buffer allocation fails and mptscsih callbacks. + * No return. + */ static void -copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) +mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) { - MPT_SCSI_DEV *mpt_sdev = NULL; - u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); - char devFoo[32]; - IO_Info_t thisIo; - - if (sc && sc->device) - mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata; - - if (sense_count) { - u8 *sense_data; - int req_index; + MPT_FRAME_HDR *chain = NULL; + unsigned long flags; + int chain_idx; + int next; - /* Copy the sense received into the scsi command block. */ - req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256)); - memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); - /* Cache SenseData for this SCSI device! */ - if (mpt_sdev) { - memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count); - mpt_sdev->sense_sz = sense_count; - } - } else { - dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n")); - } + /* Get the first chain index and reset + * tracker state. + */ + chain_idx = hd->ReqToChain[req_idx]; + hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; + while (chain_idx != MPT_HOST_NO_CHAIN) { - thisIo.cdbPtr = sc->cmnd; - thisIo.sensePtr = sc->sense_buffer; - thisIo.SCSIStatus = pScsiReply->SCSIStatus; - thisIo.DoDisplay = 1; - sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun); - thisIo.DevIDStr = devFoo; -/* fubar */ - thisIo.dataPtr = NULL; - thisIo.inqPtr = NULL; - if (sc->device) { - thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ - } - (void) mpt_ScsiHost_ErrorReport(&thisIo); + /* Save the next chain buffer index */ + next = hd->ChainToChain[chain_idx]; - return; -} + /* Free this chain buffer and reset + * tracker + */ + hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static u32 -SCPNT_TO_MSGCTX(Scsi_Cmnd *sc) -{ - MPT_SCSI_HOST *hd; - MPT_FRAME_HDR *mf; - int i; + chain = (MPT_FRAME_HDR *) (hd->ChainBuffer + + (chain_idx * hd->ioc->req_sz)); + //spin_lock_irqsave(&hd->FreeChainQlock, flags); + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + Q_ADD_TAIL(&hd->FreeChainQ.head, + &chain->u.frame.linkage, MPT_FRAME_HDR); + //spin_unlock_irqrestore(&hd->FreeChainQlock, flags); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - hd = (MPT_SCSI_HOST *) sc->host->hostdata; + dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n", + hd->ioc->name, chain_idx)); - for (i = 0; i < hd->ioc->req_depth; i++) { - if (hd->ScsiLookup[i] == sc) { - mf = MPT_INDEX_2_MFPTR(hd->ioc, i); - return mf->u.frame.hwhdr.msgctxu.MsgContext; - } + /* handle next */ + chain_idx = next; } - - return -1; + return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Reset Handling + */ -/* see mptscsih.h */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_TMHandler - Generic handler for SCSI Task Management. + * Fall through to mpt_HardResetHandler if: not operational, too many + * failed TM requests or handshake failure. + * + * @ioc: Pointer to MPT_ADAPTER structure + * @type: Task Management type + * @target: Logical Target ID for reset (if appropriate) + * @lun: Logical Unit for reset (if appropriate) + * @ctx2abort: Context for the task to be aborted (if appropriate) + * @sleepFlag: If set, use udelay instead of schedule in handshake code. + * + * Remark: Currently invoked from a non-interrupt thread (_bh). + * + * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC + * will be active. + * + * Returns 0 for SUCCESS or -1 if FAILED. + */ +static int +mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag) +{ + MPT_ADAPTER *ioc = NULL; + int rc = -1; + int doTask = 1; + u32 ioc_raw_state; + unsigned long flags; -#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS - static Scsi_Host_Template driver_template = MPT_SCSIHOST; -# include "../../scsi/scsi_module.c" + /* If FW is being reloaded currently, return success to + * the calling function. + */ + if (!hd) + return 0; + + ioc = hd->ioc; + dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); + + if (ioc == NULL) { + printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n"); + return 0; + } + + // SJR - CHECKME - Can we avoid this here? + // (mpt_HardResetHandler has this check...) + spin_lock_irqsave(&ioc->diagLock, flags); + if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { + spin_unlock_irqrestore(&ioc->diagLock, flags); + return 0; + } + spin_unlock_irqrestore(&ioc->diagLock, flags); + + /* Do not do a Task Management if there are + * too many failed TMs on this adapter. + */ + if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM) + doTask = 0; + + /* Is operational? + */ + ioc_raw_state = mpt_GetIocState(hd->ioc, 0); + +#ifdef MPT_DEBUG_RESET + if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", + hd->ioc->name, ioc_raw_state); + } #endif + if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) + && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) { + + /* Isse the Task Mgmt request. + */ + rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag); + if (rc) { + printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); + } else { + printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name); + } + } +#ifdef DROP_TEST + numTMrequested++; + if (numTMrequested > 5) { + rc = 0; /* set to 1 to force a hard reset */ + numTMrequested = 0; + } +#endif + + if (rc) { + dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n", + hd->ioc->name)); + rc = mpt_HardResetHandler(hd->ioc, sleepFlag); + } + + dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc)); +#ifndef MPT_SCSI_USE_NEW_EH + dtmprintk((MYIOC_s_INFO_FMT "TMHandler: _bh_handler state (%d) taskQ count (%d)\n", + ioc->name, mytaskQ_bh_active, hd->taskQcnt)); +#endif + + return rc; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_IssueTaskMgmt - Generic send Task Management function. + * @hd: Pointer to MPT_SCSI_HOST structure + * @type: Task Management type + * @target: Logical Target ID for reset (if appropriate) + * @lun: Logical Unit for reset (if appropriate) + * @ctx2abort: Context for the task to be aborted (if appropriate) + * @sleepFlag: If set, use udelay instead of schedule in handshake code. + * + * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) + * or a non-interrupt thread. In the former, must not call schedule(). + * + * Not all fields are meaningfull for all task types. + * + * Returns 0 for SUCCESS, -999 for "no msg frames", + * else other non-zero value returned. + */ static int -mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag) { - dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to SCSI host driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + int ii; + int retval = 0; - if (reset_phase == MPT_IOC_PRE_RESET) { - /* FIXME! Do pre-reset cleanup */ - } else { - /* FIXME! Do post-reset cleanup */ + /* Return Fail to calling function if no message frames available. + */ + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { + dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", + hd->ioc->name)); + //return FAILED; + return -999; } + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", + hd->ioc->name, mf)); - return 1; /* currently means nothing really */ + /* Format the Request + */ + pScsiTm = (SCSITaskMgmt_t *) mf; + pScsiTm->TargetID = target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = type; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (ii= 0; ii < 8; ii++) { + pScsiTm->LUN[ii] = 0; + } + pScsiTm->LUN[1] = lun; + + for (ii=0; ii < 7; ii++) + pScsiTm->Reserved2[ii] = 0; + + pScsiTm->TaskMsgContext = ctx2abort; + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n", + hd->ioc->name, ctx2abort, type)); + + /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); + * Save the MF pointer in case the request times out. + */ + hd->tmPtr = mf; + hd->numTMrequests++; + hd->TMtimer.expires = jiffies + HZ*20; /* 20 seconds */ + add_timer(&hd->TMtimer); + + if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag)) + != 0) { + dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!" + " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); + hd->numTMrequests--; + hd->tmPtr = NULL; + del_timer(&hd->TMtimer); + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + return ii; + } + + return retval; } +#ifdef MPT_SCSI_USE_NEW_EH /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int -mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +/** + * mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.eh_abort_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_abort(Scsi_Cmnd * SCpnt) { - u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + unsigned long flags; + u32 ctx2abort; + int scpnt_idx; + u8 type; - dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event)); + printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); - switch (event) { - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - /* FIXME! */ - break; - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - /* FIXME! */ - break; - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - /* FIXME! */ - break; - case MPI_EVENT_LOGOUT: /* 09 */ - /* FIXME! */ - break; + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } - /* - * CHECKME! Don't think we need to do - * anything for these, but... + /* Find this command + */ + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + /* Cmd not found in ScsiLookup. If found in + * doneQ, delete from Q. Do OS callback. */ - case MPI_EVENT_RESCAN: /* 06 */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - /* - * CHECKME! Falling thru... + search_doneQ_for_cmd(hd, SCpnt); + + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } + + /* If this command is pended, then timeout/hang occurred + * during DV. Post command and flush pending Q + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); + ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; + + /* This thread will not exit until tmPending is cleared + * FIXME - must ensure single threaded....DV conflict possible + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 1; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + if (hd->is_spi) + type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + else { + type = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + hd->abortSCpnt = SCpnt; + printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (sc=%p)\n", SCpnt); + } + + if (mptscsih_TMHandler(hd, type, + SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) < 0) { + + /* The TM request failed and the subsequent FW-reload failed! + * Fatal error case. */ + printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n", + hd->ioc->name, SCpnt); - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_EVENT_CHANGE: /* 0A */ - default: - dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event)); - break; + /* If command not found, do not do callback, + * just return failed. CHECKME + */ + if (hd->ScsiLookup[scpnt_idx] != NULL) { + //atomic_dec(&queue_depth); + SCpnt->result = STS_BUSY; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); } - return 1; /* currently means nothing really */ + + /* Spin on tmPending until we get the interrupt for this TM request. + */ + while (1) { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!hd->tmPending) { + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + break; + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + } + + return FAILED; } -#if 0 /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting. +/** + * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to * - * drivers/message/fusion/scsiherr.c + * (linux Scsi_Host_Template.eh_dev_reset_handler routine) + * + * Returns SUCCESS or FAILED. */ +int +mptscsih_dev_reset(Scsi_Cmnd * SCpnt) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + unsigned long flags; + int scpnt_idx; + u8 type; -//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */ -//extern ASCQ_Table_t *mpt_ASCQ_TablePtr; -//extern int mpt_ASCQ_TableSz; + printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); -/* Lie! */ -#define MYNAM "mptscsih" + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } -#endif /* } */ + /* Find this command + */ + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + /* Cmd not found in ScsiLookup. If found in + * doneQ, delete from Q. Do OS callback. + */ + search_doneQ_for_cmd(hd, SCpnt); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - */ -static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } + + /* If this command is pended, then timeout/hang occurred + * during DV. Force bus reset by posting command to F/W + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + + /* This thread will not exit until tmPending is cleared + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 1; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + if (hd->is_spi) + type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + else { + type = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + printk(KERN_WARNING MYNAM ": Attempting Target Reset! (sc=%p)\n", SCpnt); + } + + if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + SCpnt->target, 0, 0, CAN_SLEEP) < 0) { + /* The TM request failed and the subsequent FW-reload failed! + * Fatal error case. + */ + printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n", + hd->ioc->name, SCpnt); + + /* If command not found, do not do callback, + * just returned failed. CHECKME. + */ + if (hd->ScsiLookup[scpnt_idx] != NULL) { + //atomic_dec(&queue_depth); + SCpnt->result = STS_BUSY; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + } + + /* Spin on tmPending until we get the interrupt for this TM request. + */ + while (1) { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!hd->tmPending) { + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + break; + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + } + + //return SUCCESS; + return FAILED; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* old symsense.c stuff... */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Private data... - * To protect ourselves against those that would pass us bogus pointers +/** + * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_bus_reset_handler routine) + * + * Returns SUCCESS or FAILED. */ -static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] - = { 0x1F, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummySenseData[SCSI_STD_SENSE_BYTES] - = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; -static u8 dummyCDB[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u8 dummyScsiData[16] - = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +int +mptscsih_bus_reset(Scsi_Cmnd * SCpnt) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + unsigned long flags; + int scpnt_idx; -#if 0 -static const char *PeripheralDeviceTypeString[32] = { - "Direct-access", /* 00h */ - "Sequential-access", /* 01h */ - "Printer", /* 02h */ - "Processor", /* 03h */ - /*"Write-Once-Read-Multiple",*/ /* 04h */ - "WORM", /* 04h */ - "CD-ROM", /* 05h */ - "Scanner", /* 06h */ - "Optical memory", /* 07h */ - "Media Changer", /* 08h */ - "Communications", /* 09h */ - "(Graphics arts pre-press)", /* 0Ah */ - "(Graphics arts pre-press)", /* 0Bh */ - "Array controller", /* 0Ch */ - "Enclosure services", /* 0Dh */ - "Simplified direct-access", /* 0Eh */ - "Reserved-0Fh", /* 0Fh */ - "Reserved-10h", /* 10h */ - "Reserved-11h", /* 11h */ - "Reserved-12h", /* 12h */ - "Reserved-13h", /* 13h */ - "Reserved-14h", /* 14h */ - "Reserved-15h", /* 15h */ - "Reserved-16h", /* 16h */ - "Reserved-17h", /* 17h */ - "Reserved-18h", /* 18h */ - "Reserved-19h", /* 19h */ - "Reserved-1Ah", /* 1Ah */ - "Reserved-1Bh", /* 1Bh */ - "Reserved-1Ch", /* 1Ch */ - "Reserved-1Dh", /* 1Dh */ - "Reserved-1Eh", /* 1Eh */ - "Unknown" /* 1Fh */ -}; -#endif + printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); -static char *ScsiStatusString[] = { - "GOOD", /* 00h */ - NULL, /* 01h */ - "CHECK CONDITION", /* 02h */ - NULL, /* 03h */ - "CONDITION MET", /* 04h */ - NULL, /* 05h */ - NULL, /* 06h */ - NULL, /* 07h */ - "BUSY", /* 08h */ - NULL, /* 09h */ - NULL, /* 0Ah */ - NULL, /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - NULL, /* 0Fh */ - "INTERMEDIATE", /* 10h */ - NULL, /* 11h */ - NULL, /* 12h */ - NULL, /* 13h */ - "INTERMEDIATE-CONDITION MET", /* 14h */ - NULL, /* 15h */ - NULL, /* 16h */ - NULL, /* 17h */ - "RESERVATION CONFLICT", /* 18h */ - NULL, /* 19h */ - NULL, /* 1Ah */ - NULL, /* 1Bh */ - NULL, /* 1Ch */ - NULL, /* 1Dh */ - NULL, /* 1Eh */ - NULL, /* 1Fh */ - NULL, /* 20h */ - NULL, /* 21h */ - "COMMAND TERMINATED", /* 22h */ - NULL, /* 23h */ - NULL, /* 24h */ - NULL, /* 25h */ - NULL, /* 26h */ - NULL, /* 27h */ - "TASK SET FULL", /* 28h */ - NULL, /* 29h */ - NULL, /* 2Ah */ - NULL, /* 2Bh */ - NULL, /* 2Ch */ - NULL, /* 2Dh */ - NULL, /* 2Eh */ - NULL, /* 2Fh */ - "ACA ACTIVE", /* 30h */ - NULL -}; + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } -static const char *ScsiCommonOpString[] = { - "TEST UNIT READY", /* 00h */ - "REZERO UNIT (REWIND)", /* 01h */ - NULL, /* 02h */ - "REQUEST_SENSE", /* 03h */ - "FORMAT UNIT (MEDIUM)", /* 04h */ - "READ BLOCK LIMITS", /* 05h */ - NULL, /* 06h */ - "REASSIGN BLOCKS", /* 07h */ - "READ(6)", /* 08h */ - NULL, /* 09h */ - "WRITE(6)", /* 0Ah */ - "SEEK(6)", /* 0Bh */ - NULL, /* 0Ch */ - NULL, /* 0Dh */ - NULL, /* 0Eh */ - "READ REVERSE", /* 0Fh */ - "WRITE_FILEMARKS", /* 10h */ - "SPACE(6)", /* 11h */ - "INQUIRY", /* 12h */ - NULL -}; + /* Find this command + */ + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + /* Cmd not found in ScsiLookup. If found in + * doneQ, delete from Q. Do OS callback. + */ + search_doneQ_for_cmd(hd, SCpnt); -static const char *SenseKeyString[] = { - "NO SENSE", /* 0h */ - "RECOVERED ERROR", /* 1h */ - "NOT READY", /* 2h */ - "MEDIUM ERROR", /* 3h */ - "HARDWARE ERROR", /* 4h */ - "ILLEGAL REQUEST", /* 5h */ - "UNIT ATTENTION", /* 6h */ - "DATA PROTECT", /* 7h */ - "BLANK CHECK", /* 8h */ - "VENDOR-SPECIFIC", /* 9h */ - "ABORTED COPY", /* Ah */ - "ABORTED COMMAND", /* Bh */ - "EQUAL (obsolete)", /* Ch */ - "VOLUME OVERFLOW", /* Dh */ - "MISCOMPARE", /* Eh */ - "RESERVED", /* Fh */ - NULL -}; + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } -#define SPECIAL_ASCQ(c,q) \ - (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) + /* If this command is pended, then timeout/hang occurred + * during DV. Force bus reset by posting command to F/W + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + + /* This thread will not exit until tmPending is cleared + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 1; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + 0, 0, 0, CAN_SLEEP) < 0) { + + /* The TM request failed and the subsequent FW-reload failed! + * Fatal error case. + */ + printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n", + hd->ioc->name, SCpnt); + + /* If command not found, do not do callback, + * just returned failed. CHECKME. + */ + if (hd->ScsiLookup[scpnt_idx] != NULL) { + //atomic_dec(&queue_depth); + SCpnt->result = STS_BUSY; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + return FAILED; + } + + /* Spin on tmPending until we get the interrupt for this TM request. + */ + while (1) { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!hd->tmPending) { + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + break; + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + } + + return SUCCESS; +} #if 0 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set, - * then print additional information via - * a call to SDMS_SystemAlert(). +/** + * mptscsih_host_reset - Perform a SCSI host adapter RESET! + * new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to * - * Return: nothing + * (linux Scsi_Host_Template.eh_host_reset_handler routine) + * + * Returns SUCCESS or FAILED. */ -static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1) +int +mptscsih_host_reset(Scsi_Cmnd *SCpnt) { - u8 *sd; - u8 BadValue; - u8 SenseKey; - int Offset; - int len = strlen(msg1); + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; - sd = ioop->sensePtr; - if (SD_Additional_Sense_Length(sd) < 8) - return; + printk(KERN_WARNING MYNAM ": Attempting HOST_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); - SenseKey = SD_Sense_Key(sd); + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + return SUCCESS; + } + + /* If this command is pended, then timeout/hang occurred + * during DV. Force bus reset by posting command to F/W + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + + /* This thread will not exit until tmPending is cleared + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending = 1; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) { + SCpnt->result = STS_BUSY; + spin_lock_irqsave(&io_request_lock, flags); // sjr-added + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); // sjr-added + return FAILED; + } + + /* Spin on tmPending until we get the interrupt for this TM request. + */ + while (1) { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!hd->tmPending) { + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + break; + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + } + + return SUCCESS; +} +#endif + +#else /* MPT_SCSI old EH stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_abort - Abort linux Scsi_Cmnd routine + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.abort routine) + * + * Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}. + */ +int +mptscsih_old_abort(Scsi_Cmnd *SCpnt) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + int scpnt_idx; + + printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", SCpnt); + printk(KERN_WARNING " IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + printk(KERN_WARNING " WARNING - OldAbort, NULL hostdata ptr!!\n"); + SCpnt->result = DID_ERROR << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_NOT_RUNNING; + } + + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + /* Cmd not found in ScsiLookup. + * If found in doneQ, delete from Q. + * Do OS callback. + */ + search_doneQ_for_cmd(hd, SCpnt); + + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_SUCCESS; + } else { + /* If this command is pended, then timeout/hang occurred + * during DV. Force bus reset by posting command to F/W + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + } + + /* + * Check to see if there's already an ABORT queued for this guy. + */ + mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + if (mf != NULL) { + dtmprintk((MYIOC_s_INFO_FMT "OldAbort:Abort Task PENDING cmd (%p) taskQ depth (%d)\n", + hd->ioc->name, SCpnt, hd->taskQcnt)); + return SCSI_ABORT_PENDING; + } + + // SJR - CHECKME - Can we avoid this here? + // (mpt_HardResetHandler has this check...) + /* If IOC is reloading FW, return PENDING. + */ + spin_lock_irqsave(&hd->ioc->diagLock, flags); + if (hd->ioc->diagPending) { + spin_unlock_irqrestore(&hd->ioc->diagLock, flags); + return SCSI_ABORT_PENDING; + } + spin_unlock_irqrestore(&hd->ioc->diagLock, flags); + + /* If there are no message frames what should we do? + */ + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { + printk((KERN_WARNING " WARNING - OldAbort, no msg frames!!\n")); + /* We are out of message frames! + * Call the reset handler to do a FW reload. + */ + printk((KERN_WARNING " Reloading Firmware!!\n")); + if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { + printk((KERN_WARNING " Firmware Reload FAILED!!\n")); + } + return SCSI_ABORT_PENDING; + } + + /* + * Add ourselves to (end of) taskQ . + * Check to see if our _bh is running. If NOT, schedule it. + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + hd->taskQcnt++; + atomic_inc(&mpt_taskQdepth); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + spin_lock_irqsave(&mytaskQ_lock, flags); + + /* Save the original SCpnt mf pointer + */ + SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx); + + /* For the time being, force bus reset on any abort + * requests for the 1030 FW. + */ + if (hd->is_spi) + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + else + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + + mf->u.frame.linkage.argp1 = SCpnt; + mf->u.frame.linkage.argp2 = (void *) hd; + + dtmprintk((MYIOC_s_INFO_FMT "OldAbort:_bh_handler state (%d) taskQ count (%d)\n", + hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt)); + + if (! mytaskQ_bh_active) { + mytaskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo; + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mytaskQ_lock, flags); + + return SCSI_ABORT_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_reset - Perform a SCSI BUS_RESET! + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * @reset_flags: (not used?) + * + * (linux Scsi_Host_Template.reset routine) + * + * Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}. + */ +int +mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + int scpnt_idx; + + printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", SCpnt); + printk(KERN_WARNING " IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_SUCCESS; + } + + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + /* Cmd not found in ScsiLookup. + * If found in doneQ, delete from Q. + * Do OS callback. + */ + search_doneQ_for_cmd(hd, SCpnt); + + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_SUCCESS; + } else { + /* If this command is pended, then timeout/hang occurred + * during DV. Force bus reset by posting command to F/W + * and then following up with the reset request. + */ + if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + post_pendingQ_commands(hd); + } + } + + /* + * Check to see if there's an ABORT_TASK queued for this guy. + * If so, delete. + */ + search_taskQ(1, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + + /* + * Check to see if there's already a BUS_RESET queued for this guy. + */ + mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS); + if (mf != NULL) { + dtmprintk((MYIOC_s_INFO_FMT "OldReset:Reset Task PENDING cmd (%p) taskQ depth (%d)\n", + hd->ioc->name, SCpnt, hd->taskQcnt)); + return SCSI_RESET_PENDING; + } + + // SJR - CHECKME - Can we avoid this here? + // (mpt_HardResetHandler has this check...) + /* If IOC is reloading FW, return PENDING. + */ + spin_lock_irqsave(&hd->ioc->diagLock, flags); + if (hd->ioc->diagPending) { + spin_unlock_irqrestore(&hd->ioc->diagLock, flags); + return SCSI_RESET_PENDING; + } + spin_unlock_irqrestore(&hd->ioc->diagLock, flags); + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { + /* We are out of message frames! + * Call the reset handler to do a FW reload. + */ + printk((KERN_WARNING " Reloading Firmware!!\n")); + if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { + printk((KERN_WARNING " Firmware Reload FAILED!!\n")); + } + return SCSI_RESET_PENDING; + } + + /* + * Add ourselves to (end of) taskQ. + * Check to see if our _bh is running. If NOT, schedule it. + */ + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + hd->taskQcnt++; + atomic_inc(&mpt_taskQdepth); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + spin_lock_irqsave(&mytaskQ_lock, flags); + + /* Save the original SCpnt mf pointer + */ + SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx); + + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + mf->u.frame.linkage.argp1 = SCpnt; + mf->u.frame.linkage.argp2 = (void *) hd; + + dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n", + hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt)); + + if (! mytaskQ_bh_active) { + mytaskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo; + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mytaskQ_lock, flags); + return SCSI_RESET_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler + * @sc: (unused) + * + * This routine (thread) is active whenever there are any outstanding + * SCSI task management requests for a SCSI host adapter. + * IMPORTANT! This routine is scheduled therefore should never be + * running in ISR context. i.e., it's safe to sleep here. + */ +void +mptscsih_taskmgmt_bh(void *sc) +{ + MPT_ADAPTER *ioc; + Scsi_Cmnd *SCpnt; + MPT_FRAME_HDR *mf = NULL; + MPT_SCSI_HOST *hd; + u32 ctx2abort = 0; + unsigned long flags; + int scpnt_idx; + int did; + u8 task_type; + + spin_lock_irqsave(&mytaskQ_lock, flags); + mytaskQ_bh_active = 1; + spin_unlock_irqrestore(&mytaskQ_lock, flags); + + do { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + did = 0; + + for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { + if (ioc->sh) { + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd == NULL) { + printk(KERN_ERR MYNAM + ": ERROR - TaskMgmt NULL SCSI Host!" + "(ioc=%p, sh=%p hd=%p)\n", + ioc, ioc->sh, hd); + continue; + } + + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (Q_IS_EMPTY(&hd->taskQ)) { + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + continue; + } + + /* If we ever find a non-empty queue, + * keep the handler alive + */ + did++; + + /* tmPending is SMP lock-protected */ + if (hd->tmPending || hd->tmPtr) { + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + continue; + } + hd->tmPending = 1; + + /* Process this request + */ + mf = hd->taskQ.head; + Q_DEL_ITEM(&mf->u.frame.linkage); + hd->taskQcnt--; + atomic_dec(&mpt_taskQdepth); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1; + if (SCpnt == NULL) { + printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n", + mf, SCpnt); + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + continue; + } + + /* Get the ScsiLookup index pointer + * from the SC pointer. + */ + if (!SCpnt->host_scribble || ((MPT_SCSI_HOST *)SCpnt->host->hostdata != hd)) { + /* The command associated with the + * abort/reset request must have + * completed and this is a stale + * request. We are done. + * Free the current MF and continue. + */ + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + continue; + } + + scpnt_idx = MFPTR_2_MPT_INDEX(hd->ioc, SCpnt->host_scribble); + if (scpnt_idx != SCPNT_TO_LOOKUP_IDX(SCpnt)) { + /* Error! this should never happen!! + */ + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + continue; + } + + task_type = mf->u.frame.linkage.arg1; + ctx2abort = 0; + if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + MPT_FRAME_HDR *SCpntMf; + + /* + * Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + SCpntMf = (MPT_FRAME_HDR *) SCpnt->host_scribble; + ctx2abort = SCpntMf->u.frame.hwhdr.msgctxu.MsgContext; + + hd->abortSCpnt = SCpnt; + printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n", + mf, SCpnt); + } + + /* The TM handler will allocate a new mf, + * so free the current mf. + */ + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + mf = NULL; + + if (mptscsih_TMHandler(hd, task_type, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) < 0) { + + /* The TM request failed and the subsequent FW-reload failed! + * Fatal error case. + */ + printk(KERN_WARNING MYNAM + ": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", SCpnt); + + if (hd->ScsiLookup[scpnt_idx] != NULL) { + atomic_dec(&queue_depth); + SCpnt->result = DID_SOFT_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + } + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + hd->abortSCpnt = NULL; + } + } + } + if (atomic_read(&mpt_taskQdepth) > 0) + did++; + + } while ( did ); + + spin_lock_irqsave(&mytaskQ_lock, flags); + mytaskQ_bh_active = 0; + spin_unlock_irqrestore(&mytaskQ_lock, flags); + + return; +} +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to SCSI task mgmt request frame + * @mr: Pointer to SCSI task mgmt reply frame + * + * This routine is called from mptbase.c::mpt_interrupt() at the completion + * of any SCSI task management request. + * This routine is registered with the MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + */ +static int +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +{ + SCSITaskMgmtReply_t *pScsiTmReply; + SCSITaskMgmt_t *pScsiTmReq; + MPT_SCSI_HOST *hd = NULL; + unsigned long flags; + u8 tmType = 0; + + dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n", + ioc->name, mf, mr)); + if (ioc->sh) { + /* Depending on the thread, a timer is activated for + * the TM request. Delete this timer on completion of TM. + * Decrement count of outstanding TM requests. + */ + hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + if (hd->tmPtr) { + del_timer(&hd->TMtimer); + } + dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n", + ioc->name, hd->taskQcnt)); + } else { + dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n", + ioc->name)); + return 1; + } + + if (mr == NULL) { + dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n", + ioc->name, mf)); + return 1; + } else { + pScsiTmReply = (SCSITaskMgmtReply_t*)mr; + pScsiTmReq = (SCSITaskMgmt_t*)mf; + + /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ + tmType = pScsiTmReq->TaskType; + + dtmprintk((KERN_INFO " TaskType = %d, TerminationCount=%d\n", + tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); + + /* Error? (anything non-zero?) */ + if (*(u32 *)&pScsiTmReply->Reserved2[0]) { + u16 iocstatus; + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + dtmprintk((KERN_INFO " SCSI TaskMgmt (%d) - Oops!\n", tmType)); + dtmprintk((KERN_INFO " IOCStatus = %04xh\n", iocstatus)); + dtmprintk((KERN_INFO " IOCLogInfo = %08xh\n", + le32_to_cpu(pScsiTmReply->IOCLogInfo))); + + /* clear flags and continue. + */ + if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) + hd->abortSCpnt = NULL; +#ifdef DROP_TEST + if (dropMfPtr) + dropTestBad++; +#endif + /* If an internal command is present + * or the TM failed - reload the FW. + * FC FW may respond FAILED to an ABORT + */ + if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { + if ((hd->cmdPtr) || + (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) { + if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { + printk((KERN_WARNING + " Firmware Reload FAILED!!\n")); + } + } + } + } else { + dtmprintk((KERN_INFO " SCSI TaskMgmt SUCCESS!\n")); + +#ifndef MPT_SCSI_USE_NEW_EH + if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { + /* clean taskQ - remove tasks associated with + * completed commands. + */ + clean_taskQ(hd); + } else if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + /* If taskQ contains another request + * for this SCpnt, delete this request. + */ + search_taskQ_for_cmd(hd->abortSCpnt, hd); + } +#endif + hd->numTMrequests--; + hd->abortSCpnt = NULL; + flush_doneQ(hd); + +#ifdef DROP_TEST + if (dropMfPtr) + dropTestOK++; +#endif + } + } + +#ifdef DROP_TEST + { + Scsi_Cmnd *sc; + unsigned long flags; + u16 req_idx; + + /* Free resources for the drop test MF and chain buffers. + */ + if (dropMfPtr) { + req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx); + sc = hd->ScsiLookup[req_idx]; + if (sc == NULL) { + printk(MYIOC_s_ERR_FMT + "Drop Test: NULL ScsiCmd ptr!\n", + ioc->name); + } else { + sc->host_scribble = NULL; + if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) + sc->result = DID_RESET << 16; + else + sc->result = DID_ABORT << 16; + + hd->ScsiLookup[req_idx] = NULL; + atomic_dec(&queue_depth); + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); /* Issue callback */ + spin_unlock_irqrestore(&io_request_lock, flags); + + mptscsih_freeChainBuffers(hd, req_idx); + mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr); + + printk(MYIOC_s_INFO_FMT + "Free'd Dropped cmd (%p)\n", + hd->ioc->name, sc); + printk(MYIOC_s_INFO_FMT + "mf (%p) reqidx (%4x)\n", + hd->ioc->name, dropMfPtr, + req_idx); + printk(MYIOC_s_INFO_FMT + "Num Tot (%d) Good (%d) Bad (%d) \n", + hd->ioc->name, dropTestNum, + dropTestOK, dropTestBad); + } + dropMfPtr = NULL; + } + } +#endif + +#ifndef MPT_SCSI_USE_NEW_EH + /* + * Signal to _bh thread that we finished. + * This IOC can now process another TM command. + */ + dtmprintk((MYIOC_s_INFO_FMT "taskmgmt_complete: (=%p) done! Num Failed(%d) Task Count (%d)\n", + ioc->name, mf, hd->numTMrequests, hd->taskQcnt)); +#endif + hd->tmPtr = NULL; + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * This is anyones guess quite frankly. + */ + +int +mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * OS entry point to adjust the queue_depths on a per-device basis. + * Called once per device the bus scan. Use it to force the queue_depth + * member to 1 if a device does not support Q tags. + */ +void +mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList) +{ + struct scsi_device *device; + VirtDevice *pTarget; + MPT_SCSI_HOST *hd; + int ii, max; + + for (device = sdList; device; device = device->next) { + + if (device->host != sh) + continue; + + hd = (MPT_SCSI_HOST *) sh->hostdata; + if (!hd) + continue; + + if (hd->Targets) { + if (hd->is_spi) + max = MPT_MAX_SCSI_DEVICES; + else + max = MPT_MAX_FC_DEVICES; + + for (ii=0; ii < max; ii++) { + pTarget = hd->Targets[ii]; + if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { + device->queue_depth = 1; + } + } + } + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private routines... + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 19991030 -sralston + * Return absolute SCSI data direction: + * 1 = _DATA_OUT + * 0 = _DIR_NONE + * -1 = _DATA_IN + */ +static int +mptscsih_io_direction(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + /* _DATA_OUT commands */ + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case REASSIGN_BLOCKS: + case PERSISTENT_RESERVE_OUT: + case 0xea: + case 0xa3: + return 1; + + /* No data transfer commands */ + case SEEK_6: case SEEK_10: + case RESERVE: case RELEASE: + case TEST_UNIT_READY: + case START_STOP: + case ALLOW_MEDIUM_REMOVAL: + return 0; + + /* Conditional data transfer commands */ + case FORMAT_UNIT: + if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ + return 1; + else + return 0; + + case VERIFY: + if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ + return 1; + else + return 0; + + case RESERVE_10: + if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */ + return 1; + else + return 0; + +#if 0 + case REZERO_UNIT: /* (or REWIND) */ + case SPACE: + case ERASE: case ERASE_10: + case SYNCHRONIZE_CACHE: + case LOCK_UNLOCK_CACHE: +#endif + + /* Must be data _IN! */ + default: + return -1; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Utility function to copy sense data from the scsi_cmnd buffer + * to the FC and SCSI target structures. + * + */ +static void +copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) +{ + VirtDevice *target; + SCSIIORequest_t *pReq; + u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); + int index; + char devFoo[96]; + IO_Info_t thisIo; + + /* Get target structure + */ + pReq = (SCSIIORequest_t *) mf; + index = (int) pReq->TargetID; + target = hd->Targets[index]; + if (hd->is_multipath && sc->device->hostdata) + target = (VirtDevice *) sc->device->hostdata; + + if (sense_count) { + u8 *sense_data; + int req_index; + + /* Copy the sense received into the scsi command block. */ + req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); + memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); + + /* save sense data to the target device + */ + if (target) { + int sz; + + sz = MIN(pReq->SenseBufferLength, sense_count); + if (sz > SCSI_STD_SENSE_BYTES) + sz = SCSI_STD_SENSE_BYTES; + memcpy(target->sense, sense_data, sz); + target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE; + } + + /* Log SMART data (asc = 0x5D, non-IM case only) if required. + */ + if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { + if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) { + int idx; + MPT_ADAPTER *ioc = hd->ioc; + + idx = ioc->eventContext % ioc->eventLogSize; + ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE; + ioc->events[idx].eventContext = ioc->eventContext; + + ioc->events[idx].data[0] = (pReq->LUN[1] << 24) || + (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) || + (pReq->Bus << 8) || pReq->TargetID; + + ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12]; + + ioc->eventContext++; + } + } + + /* Print an error report for the user. + */ + thisIo.cdbPtr = sc->cmnd; + thisIo.sensePtr = sc->sense_buffer; + thisIo.SCSIStatus = pScsiReply->SCSIStatus; + thisIo.DoDisplay = 1; + if (hd->is_multipath) + sprintf(devFoo, "%d:%d:%d \"%s\"", + hd->ioc->id, + pReq->TargetID, + pReq->LUN[1], + target->dev_vol_name); + else + sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->target, sc->lun); + thisIo.DevIDStr = devFoo; +/* fubar */ + thisIo.dataPtr = NULL; + thisIo.inqPtr = NULL; + if (sc->device) { + thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ + } + (void) mpt_ScsiHost_ErrorReport(&thisIo); + + } else { + dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n", + hd->ioc->name)); + } + + return; +} + +static u32 +SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc) +{ + MPT_SCSI_HOST *hd; + int i; + + hd = (MPT_SCSI_HOST *) sc->host->hostdata; + + for (i = 0; i < hd->ioc->req_depth; i++) { + if (hd->ScsiLookup[i] == sc) { + return i; + } + } + + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* see mptscsih.h */ + +#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS + static Scsi_Host_Template driver_template = MPT_SCSIHOST; +# include "../../scsi/scsi_module.c" +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Search the pendingQ for a command with specific index. + * If found, delete and return mf pointer + * If not found, return NULL + */ +static MPT_FRAME_HDR * +mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx) +{ + unsigned long flags; + MPT_DONE_Q *buffer; + MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *cmdMfPtr = NULL; + + ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name)); + cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->pendingQ)) { + buffer = hd->pendingQ.head; + do { + mf = (MPT_FRAME_HDR *) buffer->argp; + if (mf == cmdMfPtr) { + Q_DEL_ITEM(buffer); + + /* clear the arg pointer + */ + buffer->argp = NULL; + + /* Add to the freeQ + */ + Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); + break; + } + mf = NULL; + } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ); + } + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + ddvtprintk((" ...return %p\n", mf)); + return mf; +} + +/* Post all commands on the pendingQ to the FW. + * Lock Q when deleting/adding members + * Lock io_request_lock for OS callback. + */ +static void +post_pendingQ_commands(MPT_SCSI_HOST *hd) +{ + MPT_FRAME_HDR *mf; + MPT_DONE_Q *buffer; + unsigned long flags; + + /* Flush the pendingQ. + */ + ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name)); + while (1) { + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (Q_IS_EMPTY(&hd->pendingQ)) { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + break; + } + + buffer = hd->pendingQ.head; + /* Delete from Q + */ + Q_DEL_ITEM(buffer); + + mf = (MPT_FRAME_HDR *) buffer->argp; + if (!mf) { + /* This should never happen */ + printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, mf); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + continue; + } + + mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n", + hd->ioc->name, mf)); + + buffer->argp = NULL; + + /* Add to the freeQ + */ + Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + } + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + MPT_SCSI_HOST *hd = NULL; + unsigned long flags; + + dtmprintk((KERN_WARNING MYNAM + ": IOC %s_reset routed to SCSI host driver!\n", + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + + /* If a FW reload request arrives after base installed but + * before all scsi hosts have been attached, then an alt_ioc + * may have a NULL sh pointer. + */ + if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) + return 0; + else + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + + if (reset_phase == MPT_IOC_PRE_RESET) { + dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n", + ioc->name)); + + /* Clean Up: + * 1. Set Hard Reset Pending Flag + * All new commands go to doneQ + */ + hd->resetPending = 1; + + /* 2. Flush running commands + * Clean drop test code - if compiled + * Clean ScsiLookup (and associated memory) + * AND clean mytaskQ + */ + + /* 2a. Drop Test Command. + */ +#ifdef DROP_TEST + { + Scsi_Cmnd *sc; + unsigned long flags; + u16 req_idx; + + /* Free resources for the drop test MF + * and chain buffers. + */ + if (dropMfPtr) { + req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx); + sc = hd->ScsiLookup[req_idx]; + if (sc == NULL) { + printk(MYIOC_s_ERR_FMT + "Drop Test: NULL ScsiCmd ptr!\n", + ioc->name); + } else { + sc->host_scribble = NULL; + sc->result = DID_RESET << 16; + hd->ScsiLookup[req_idx] = NULL; + atomic_dec(&queue_depth); + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); /* Issue callback */ + spin_unlock_irqrestore(&io_request_lock, flags); + } + + mptscsih_freeChainBuffers(hd, req_idx); + mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr); + printk(MYIOC_s_INFO_FMT + "Free'd: mf (%p) reqidx (%4x)\n", + hd->ioc->name, dropMfPtr, + req_idx); + } + dropMfPtr = NULL; + } +#endif + + /* 2b. Reply to OS all known outstanding I/O commands. + */ + mptscsih_flush_running_cmds(hd); + + /* 2c. If there was an internal command that + * has not completed, configuration or io request, + * free these resources. + */ + if (hd->cmdPtr) { + del_timer(&hd->timer); + mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr); + atomic_dec(&queue_depth); + } + + /* 2d. If a task management has not completed, + * free resources associated with this request. + */ + if (hd->tmPtr) { + del_timer(&hd->TMtimer); + mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr); + } + +#ifndef MPT_SCSI_USE_NEW_EH + /* 2e. Delete all commands on taskQ + * Should be superfluous - as this taskQ should + * be empty. + */ + clean_taskQ(hd); +#endif + dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n", + ioc->name)); + + } else { + dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n", + ioc->name)); + + /* Once a FW reload begins, all new OS commands are + * redirected to the doneQ w/ a reset status. + * Init all control structures. + */ + + /* ScsiLookup initialization + */ + { + int ii; + for (ii=0; ii < hd->ioc->req_depth; ii++) + hd->ScsiLookup[ii] = NULL; + } + + /* 2. Chain Buffer initialization + */ + mptscsih_initChainBuffers(hd, 0); + + /* 3. tmPtr clear + */ + if (hd->tmPtr) { + hd->tmPtr = NULL; + } + + /* 4. Renegotiate to all devices, if SCSI + */ + if (hd->is_spi) + mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM); + + /* 5. Enable new commands to be posted + */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + hd->tmPending = 0; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + hd->resetPending = 0; + hd->numTMrequests = 0; + + /* 6. If there was an internal command, + * wake this process up. + */ + if (hd->cmdPtr) { + /* + * Wake up the original calling thread + */ + hd->pLocal = &hd->localReply; + hd->pLocal->completion = MPT_SCANDV_DID_RESET; + scandv_wait_done = 1; + wake_up(&scandv_waitq); + hd->cmdPtr = NULL; + } + + /* 7. Flush doneQ + */ + flush_doneQ(hd); + + dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n", + ioc->name)); + } + + return 1; /* currently means nothing really */ +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + MPT_SCSI_HOST *hd; + u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + + dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", + ioc->name, event)); + + switch (event) { + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + /* FIXME! */ + break; + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + /* FIXME! */ + break; + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + /* FIXME! */ + break; + case MPI_EVENT_LOGOUT: /* 09 */ + /* FIXME! */ + break; + + /* + * CHECKME! Don't think we need to do + * anything for these, but... + */ + case MPI_EVENT_RESCAN: /* 06 */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + /* + * CHECKME! Falling thru... + */ + + case MPI_EVENT_INTEGRATED_RAID: /* 0B */ +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + /* negoNvram set to 0 if DV enabled and to USE_NVRAM if + * if DV disabled + */ + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd->negoNvram == 0) { + ScsiCfgData *pSpi; + Ioc3PhysDisk_t *pPDisk; + int numPDisk; + u8 reason; + u8 physDiskNum; + + reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; + if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { + /* New or replaced disk. + * Set DV flag and schedule DV. + */ + pSpi = &ioc->spi_data; + physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; + if (pSpi->pIocPg3) { + pPDisk = pSpi->pIocPg3->PhysDisk; + numPDisk =pSpi->pIocPg3->NumPhysDisks; + + while (numPDisk) { + if (physDiskNum == pPDisk->PhysDiskNum) { + pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV; + pSpi->forceDv = MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); + break; + } + pPDisk++; + numPDisk--; + } + } + } + } +#endif + +#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) + printk("Raid Event RF: "); + { + u32 *m = (u32 *)pEvReply; + int ii; + int n = (int)pEvReply->MsgLength; + for (ii=6; ii < n; ii++) + printk(" %08x", le32_to_cpu(m[ii])); + printk("\n"); + } +#endif + break; + + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + default: + dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event)); + break; + } + + return 1; /* currently means nothing really */ +} + +#if 0 /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting. + * + * drivers/message/fusion/scsiherr.c + */ + +//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */ +//extern ASCQ_Table_t *mpt_ASCQ_TablePtr; +//extern int mpt_ASCQ_TableSz; + +#define MYNAM "mptscsih" + +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ +static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* old symsense.c stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + * To protect ourselves against those that would pass us bogus pointers + */ +static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] + = { 0x1F, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummySenseData[SCSI_STD_SENSE_BYTES] + = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; +static u8 dummyCDB[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummyScsiData[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#if 0 +static const char *PeripheralDeviceTypeString[32] = { + "Direct-access", /* 00h */ + "Sequential-access", /* 01h */ + "Printer", /* 02h */ + "Processor", /* 03h */ + /*"Write-Once-Read-Multiple",*/ /* 04h */ + "WORM", /* 04h */ + "CD-ROM", /* 05h */ + "Scanner", /* 06h */ + "Optical memory", /* 07h */ + "Media Changer", /* 08h */ + "Communications", /* 09h */ + "(Graphics arts pre-press)", /* 0Ah */ + "(Graphics arts pre-press)", /* 0Bh */ + "Array controller", /* 0Ch */ + "Enclosure services", /* 0Dh */ + "Simplified direct-access", /* 0Eh */ + "Reserved-0Fh", /* 0Fh */ + "Reserved-10h", /* 10h */ + "Reserved-11h", /* 11h */ + "Reserved-12h", /* 12h */ + "Reserved-13h", /* 13h */ + "Reserved-14h", /* 14h */ + "Reserved-15h", /* 15h */ + "Reserved-16h", /* 16h */ + "Reserved-17h", /* 17h */ + "Reserved-18h", /* 18h */ + "Reserved-19h", /* 19h */ + "Reserved-1Ah", /* 1Ah */ + "Reserved-1Bh", /* 1Bh */ + "Reserved-1Ch", /* 1Ch */ + "Reserved-1Dh", /* 1Dh */ + "Reserved-1Eh", /* 1Eh */ + "Unknown" /* 1Fh */ +}; +#endif + +static char *ScsiStatusString[] = { + "GOOD", /* 00h */ + NULL, /* 01h */ + "CHECK CONDITION", /* 02h */ + NULL, /* 03h */ + "CONDITION MET", /* 04h */ + NULL, /* 05h */ + NULL, /* 06h */ + NULL, /* 07h */ + "BUSY", /* 08h */ + NULL, /* 09h */ + NULL, /* 0Ah */ + NULL, /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + NULL, /* 0Fh */ + "INTERMEDIATE", /* 10h */ + NULL, /* 11h */ + NULL, /* 12h */ + NULL, /* 13h */ + "INTERMEDIATE-CONDITION MET", /* 14h */ + NULL, /* 15h */ + NULL, /* 16h */ + NULL, /* 17h */ + "RESERVATION CONFLICT", /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + NULL, /* 20h */ + NULL, /* 21h */ + "COMMAND TERMINATED", /* 22h */ + NULL, /* 23h */ + NULL, /* 24h */ + NULL, /* 25h */ + NULL, /* 26h */ + NULL, /* 27h */ + "TASK SET FULL", /* 28h */ + NULL, /* 29h */ + NULL, /* 2Ah */ + NULL, /* 2Bh */ + NULL, /* 2Ch */ + NULL, /* 2Dh */ + NULL, /* 2Eh */ + NULL, /* 2Fh */ + "ACA ACTIVE", /* 30h */ + NULL +}; + +static const char *ScsiCommonOpString[] = { + "TEST UNIT READY", /* 00h */ + "REZERO UNIT (REWIND)", /* 01h */ + NULL, /* 02h */ + "REQUEST_SENSE", /* 03h */ + "FORMAT UNIT (MEDIUM)", /* 04h */ + "READ BLOCK LIMITS", /* 05h */ + NULL, /* 06h */ + "REASSIGN BLOCKS", /* 07h */ + "READ(6)", /* 08h */ + NULL, /* 09h */ + "WRITE(6)", /* 0Ah */ + "SEEK(6)", /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + "READ REVERSE", /* 0Fh */ + "WRITE_FILEMARKS", /* 10h */ + "SPACE(6)", /* 11h */ + "INQUIRY", /* 12h */ + NULL +}; + +static const char *SenseKeyString[] = { + "NO SENSE", /* 0h */ + "RECOVERED ERROR", /* 1h */ + "NOT READY", /* 2h */ + "MEDIUM ERROR", /* 3h */ + "HARDWARE ERROR", /* 4h */ + "ILLEGAL REQUEST", /* 5h */ + "UNIT ATTENTION", /* 6h */ + "DATA PROTECT", /* 7h */ + "BLANK CHECK", /* 8h */ + "VENDOR-SPECIFIC", /* 9h */ + "ABORTED COPY", /* Ah */ + "ABORTED COMMAND", /* Bh */ + "EQUAL (obsolete)", /* Ch */ + "VOLUME OVERFLOW", /* Dh */ + "MISCOMPARE", /* Eh */ + "RESERVED", /* Fh */ + NULL +}; + +#define SPECIAL_ASCQ(c,q) \ + (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) + +#if 0 +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set, + * then print additional information via + * a call to SDMS_SystemAlert(). + */ +static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1) +{ + u8 *sd; + u8 BadValue; + u8 SenseKey; + int Offset; + int len = strlen(msg1); + + sd = ioop->sensePtr; + if (SD_Additional_Sense_Length(sd) < 8) + return; + + SenseKey = SD_Sense_Key(sd); + + if (SD_Sense_Key_Specific_Valid(sd)) { + if (SenseKey == SK_ILLEGAL_REQUEST) { + Offset = SD_Bad_Byte(sd); + if (SD_Was_Illegal_Request(sd)) { + BadValue = ioop->cdbPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ", + BadValue); + } else { + BadValue = ioop->dataPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ", + BadValue); + } + len += sprintf(msg1+len, "byte=%02Xh", Offset); + if (SD_SKS_Bit_Pointer_Valid(sd)) + len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd)); + } else if ((SenseKey == SK_RECOVERED_ERROR) || + (SenseKey == SK_HARDWARE_ERROR) || + (SenseKey == SK_MEDIUM_ERROR)) { + len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh", + SD_Actual_Retry_Count(sd)); + } + } +} +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_cdb(char *foo, unsigned char *cdb) +{ + int i, grpCode, cdbLen; + int l = 0; + + grpCode = cdb[0] >> 5; + if (grpCode < 1) + cdbLen = 6; + else if (grpCode < 3) + cdbLen = 10; + else if (grpCode == 5) + cdbLen = 12; + else + cdbLen = 16; + + for (i=0; i < cdbLen; i++) + l += sprintf(foo+l, " %02X", cdb[i]); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_sd(char *foo, unsigned char *sd) +{ + int snsLen = 8 + SD_Additional_Sense_Length(sd); + int l = 0; + int i; + + for (i=0; i < MIN(snsLen,18); i++) + l += sprintf(foo+l, " %02X", sd[i]); + l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : ""); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ +static const char * ascq_set_strings_4max( + u8 ASC, u8 ASCQ, + const char **s1, const char **s2, const char **s3, const char **s4) +{ + static const char *asc_04_part1_string = "LOGICAL UNIT "; + static const char *asc_04_part2a_string = "NOT READY, "; + static const char *asc_04_part2b_string = "IS "; + static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ + "CAUSE NOT REPORTABLE", /* 04 00 */ + "IN PROCESS OF BECOMING READY", /* 04 01 */ + "INITIALIZING CMD. REQUIRED", /* 04 02 */ + "MANUAL INTERVENTION REQUIRED", /* 04 03 */ + /* Add " IN PROGRESS" to all the following... */ + "FORMAT", /* 04 04 */ + "REBUILD", /* 04 05 */ + "RECALCULATION", /* 04 06 */ + "OPERATION", /* 04 07 */ + "LONG WRITE", /* 04 08 */ + "SELF-TEST", /* 04 09 */ + NULL + }; + static char *asc_04_part4_string = " IN PROGRESS"; + + static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ + "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ + "POWER ON OCCURRED", /* 29 01 */ + "SCSI BUS RESET OCCURRED", /* 29 02 */ + "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ + "DEVICE INTERNAL RESET", /* 29 04 */ + "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ + "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ + NULL + }; + static char *ascq_vendor_uniq = "(Vendor Unique)"; + static char *ascq_noone = "(no matching ASC/ASCQ description found)"; + int idx; + + *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ + + /* CHECKME! Need lock/sem? + * Update and examine for isense module presense. + */ + mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; + + if (mptscsih_ASCQ_TablePtr == NULL) { + /* 2nd chances... */ + if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { + *s1 = asc_04_part1_string; + *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; + *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; + /* check for " IN PROGRESS" ones */ + if (ASCQ >= 0x04) + *s4 = asc_04_part4_string; + } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) + *s1 = asc_29_ascq_NN_strings[ASCQ]; + /* + * Else { leave all *s[1-4] values pointing to the empty "" string } + */ + return *s1; + } + + /* + * Need to check ASC here; if it is "special," then + * the ASCQ is variable, and indicates failed component number. + * We must treat the ASCQ as a "dont care" while searching the + * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later + * on when we actually need to identify the failed component. + */ + if (SPECIAL_ASCQ(ASC,ASCQ)) + ASCQ = 0xFF; + + /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ + for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) + if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) { + *s1 = mptscsih_ASCQ_TablePtr[idx].Description; + return *s1; + } + + if ((ASC >= 0x80) || (ASCQ >= 0x80)) + *s1 = ascq_vendor_uniq; + else + *s1 = ascq_noone; + + return *s1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Error Report; desired output format... + *--- +SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) + SCSI_Status=02h (CHECK CONDITION) + Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady + SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 + SenseKey=6h (UNIT ATTENTION); FRU=03h + ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + *--- + */ + +int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) +{ + char foo[512]; + char buf2[32]; + char *statstr; + const char *opstr; + int sk = SD_Sense_Key(ioop->sensePtr); + const char *skstr = SenseKeyString[sk]; + unsigned char asc = SD_ASC(ioop->sensePtr); + unsigned char ascq = SD_ASCQ(ioop->sensePtr); + int l; + + /* + * More quiet mode. + * Filter out common, repetitive, warning-type errors... like: + * POWER ON (06,29/00 or 06,29/01), + * SPINNING UP (02,04/01), + * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. + */ + if (sk == SK_NO_SENSE) { + return 0; + } + if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) + || (sk==SK_NOT_READY && asc==0x04 && ascq==0x01) + || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) + ) + { + /* Do nothing! */ + return 0; + } + + /* + * Protect ourselves... + */ + if (ioop->cdbPtr == NULL) + ioop->cdbPtr = dummyCDB; + if (ioop->sensePtr == NULL) + ioop->sensePtr = dummySenseData; + if (ioop->inqPtr == NULL) + ioop->inqPtr = dummyInqData; + if (ioop->dataPtr == NULL) + ioop->dataPtr = dummyScsiData; + + statstr = NULL; + if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || + ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { + (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); + statstr = buf2; + } + + opstr = NULL; + if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) + opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; + else if (mpt_ScsiOpcodesPtr) + opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; + + l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n" + " SCSI_Status=%02Xh (%s)\n" + " Original_CDB[]:", + ioop->DevIDStr, + ioop->SCSIStatus, + statstr); + l += dump_cdb(foo+l, ioop->cdbPtr); + if (opstr) + l += sprintf(foo+l, " - \"%s\"", opstr); + l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr)); + l += dump_sd(foo+l, ioop->sensePtr); + l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", + sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); + + { + const char *x1, *x2, *x3, *x4; + x1 = x2 = x3 = x4 = ""; + x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); + if (x1 != NULL) { + if (x1[0] != '(') + l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); + else + l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); + } + } + +#if 0 + if (SPECIAL_ASCQ(asc,ascq)) + l += sprintf(foo+l, " (%02Xh)", ascq); +#endif + + PrintF(("%s\n", foo)); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_initTarget - Target, LUN alloc/free functionality. + * @hd: Pointer to MPT_SCSI_HOST structure + * @bus_id: Bus number (?) + * @target_id: SCSI target id + * @lun: SCSI LUN id + * @data: Pointer to data + * @dlen: Number of INQUIRY bytes + * + * NOTE: It's only SAFE to call this routine if data points to + * sane & valid STANDARD INQUIRY data! + * + * Allocate and initialize memory for this target. + * Save inquiry data. + * + * Returns pointer to VirtDevice structure. + */ +static VirtDevice * +mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen) +{ + VirtDevice *vdev; + int sz; + + dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n", + hd->ioc->name, bus_id, target_id, lun, hd)); + + if ((vdev = hd->Targets[target_id]) == NULL) { + if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) { + printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n", + hd->ioc->name, (int)sizeof(VirtDevice)); + } else { + memset(vdev, 0, sizeof(VirtDevice)); + rwlock_init(&vdev->VdevLock); + Q_INIT(&vdev->WaitQ, void); + Q_INIT(&vdev->SentQ, void); + Q_INIT(&vdev->DoneQ, void); + vdev->tflags = 0; + vdev->ioc_id = hd->ioc->id; + vdev->target_id = target_id; + vdev->bus_id = bus_id; + + hd->Targets[target_id] = vdev; + dprintk((KERN_INFO " *NEW* Target structure (id %d) @ %p\n", + target_id, vdev)); + } + } + + if (vdev && data) { + if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { + + /* Copy the inquiry data - if we haven't yet. + */ + sz = MIN(dlen, SCSI_STD_INQUIRY_BYTES); + + memcpy (vdev->inq_data, data, sz); + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + + /* Update the target capabilities + */ + mptscsih_setTargetNegoParms(hd, vdev); + } + + /* Is LUN supported? If so, upper 3 bits will be 0 + * in first byte of inquiry data. + */ + if ((*data & 0xe0) == 0) + vdev->luns |= (1 << lun); + } + + if (vdev) { + if (hd->ioc->spi_data.isRaid & (1 << target_id)) + vdev->raidVolume = 1; + else + vdev->raidVolume = 0; + } + + dprintk((KERN_INFO " target = %p\n", vdev)); + return vdev; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Update the target negotiation parameters based on the + * the Inquiry data, adapter capabilities, and NVRAM settings. + * + */ +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target) +{ + int id = (int) target->target_id; + int nvram; + char canQ = 0; + u8 width = MPT_NARROW; + u8 factor = MPT_ASYNC; + u8 offset = 0; + u8 version, nfactor; + ScsiCfgData *pspi_data = &hd->ioc->spi_data; + + /* Set flags based on Inquiry data + */ + if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + version = target->inq_data[2] & 0x03; + if (version < 2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + } else { + if (target->inq_data[7] & 0x20) { + width = 1; + } + + if (target->inq_data[7] & 0x10) { + if (version == 2) + factor = MPT_ULTRA2; + else + factor = MPT_ULTRA320; + + offset = pspi_data->maxSyncOffset; + } else { + factor = MPT_ASYNC; + offset = 0; + } + } + + if (target->inq_data[7] & 0x02) { + canQ = 1; + } + + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = MAX (factor, nfactor); + if (factor == MPT_ASYNC) + offset = 0; + } else { + offset = 0; + factor = MPT_ASYNC; + } + } else { + factor = MPT_ASYNC; + } + } + + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) { + factor = MPT_ULTRA2; + } + + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; + if (canQ) { + target->tflags |= MPT_TARGET_FLAGS_Q_YES; + } + + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + + /* Disable all wide (sync) extended messages + * if device is narrow (async). + */ + target->negoFlags = 0; + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + } + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Clear sense valid flag. + */ +static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) +{ + VirtDevice *target; + int index = (int) pReq->TargetID; + + if ((target = hd->Targets[index])) { + target->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; + } + + return; +} + +/* + * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. + * Else set the NEED_DV flag after Read Capacity Issued (disks) + * or Mode Sense (cdroms). Tapes, key off of Inquiry command. + */ +static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data) +{ + u8 cmd = pReq->CDB[0]; + + if (pReq->LUN[1] != 0) + return; + + if (hd->negoNvram != 0) + return; + + if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || + ((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) { + u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID]; + if (!(dvStatus & MPT_SCSICFG_DV_DONE)) { + ScsiCfgData *pSpi = &hd->ioc->spi_data; + if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { + /* Set NEED_DV for all hidden disks + */ + Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk; + int numPDisk = pSpi->pIocPg3->NumPhysDisks; + + while (numPDisk) { + pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); + pPDisk++; + numPDisk--; + } + } + pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for visible disk id %d\n", + pReq->TargetID)); + }; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Config Page functionality ... + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags + * based on width, factor and offset parameters. + * @width: bus width + * @factor: sync factor + * @offset: sync offset + * @requestedPtr: pointer to requested values (updated) + * @configurationPtr: pointer to configuration values (updated) + * @flags: flags to block WDTR or SDTR negotiation + * + * Return: None. + * + * Remark: Called by writeSDP1 and _dv_params + */ +static void +mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags) +{ + u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE; + u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC; + + *configurationPtr = 0; + *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0; + *requestedPtr |= (offset << 16) | (factor << 8); + + if (width && offset && !nowide && !nosync) { + if (factor < MPT_ULTRA160) { + *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT + + MPI_SCSIDEVPAGE1_RP_QAS); + } else if (factor < MPT_ULTRA2) { + *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT; + } + } + + if (nowide) + *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED; + + if (nosync) + *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED; + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_writeSDP1 - write SCSI Device Page 1 + * @hd: Pointer to a SCSI Host Strucutre + * @portnum: IOC port number + * @target_id: writeSDP1 for single ID + * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM + * + * Return: -EFAULT if read of config page header fails + * or 0 if success. + * + * Remark: If a target has been found, the settings from the + * target structure are used, else the device is set + * to async/narrow. + * + * Remark: Called during init and after a FW reload. + * Remark: We do not wait for a return, write pages sequentially. + */ +static int +mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) +{ + MPT_ADAPTER *ioc = hd->ioc; + Config_t *pReq = NULL; + SCSIDevicePage1_t *pData = NULL; + VirtDevice *pTarget = NULL; + MPT_FRAME_HDR *mf; + MptSge_t *psge; + dma_addr_t dataDma; + u16 req_idx; + u32 frameOffset; + u32 requested, configuration, flagsLength; + int ii, nvram; + int id = 0, maxid = 0; + u8 width; + u8 factor; + u8 offset; + u8 bus = 0; + u8 negoFlags; + + if (ioc->spi_data.sdp1length == 0) + return 0; + + if (flags & MPT_SCSICFG_ALL_IDS) { + id = 0; + maxid = ioc->sh->max_id - 1; + } else if (ioc->sh) { + id = target_id; + maxid = MIN(id, ioc->sh->max_id - 1); + } + + for (; id <= maxid; id++) { + if (id == ioc->pfacts[portnum].PortSCSIID) + continue; + + if (flags & MPT_SCSICFG_USE_NVRAM) { + /* Use NVRAM, adapter maximums and target settings. + * Data over-riden by target structure information, if present + */ + width = ioc->spi_data.maxBusWidth; + offset = ioc->spi_data.maxSyncOffset; + factor = ioc->spi_data.minSyncFactor; + if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = ioc->spi_data.nvram[id]; + + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (offset > 0) { + factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + if (factor == 0) { + /* Key for async */ + factor = MPT_ASYNC; + offset = 0; + } else if (factor < ioc->spi_data.minSyncFactor) { + factor = ioc->spi_data.minSyncFactor; + } + } else + factor = MPT_ASYNC; + } + + /* Set the negotiation flags. + */ + negoFlags = 0; + if (!width) + negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + } else { + width = 0; + factor = MPT_ASYNC; + offset = 0; + negoFlags = MPT_TARGET_NO_NEGO_SYNC; + } + + /* If id is not a raid volume, get the updated + * transmission settings from the target structure. + */ + if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { + width = pTarget->maxWidth; + factor = pTarget->minSyncFactor; + offset = pTarget->maxOffset; + negoFlags = pTarget->negoFlags; + pTarget = NULL; + } + mptscsih_setDevicePage1Flags(width, factor, offset, + &requested, &configuration, negoFlags); + + + if (negoFlags == (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC)) + continue; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) { + dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + + /* Set the request and the data pointers. + * Request takes: 36 bytes (32 bit SGE) + * SCSI Device Page 1 requires 16 bytes + * 40 + 16 <= size of SCSI IO Request = 56 bytes + * and MF size >= 64 bytes. + * Place data at end of MF. + */ + pReq = (Config_t *)mf; + + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t); + + pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset); + dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset; + + /* Complete the request frame (same for all requests). + */ + pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_CONFIG; + pReq->Reserved1[0] = 0; + pReq->Reserved1[1] = 0; + pReq->Reserved1[2] = 0; + pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) { + pReq->Reserved2[ii] = 0; + } + pReq->Header.PageVersion = ioc->spi_data.sdp1version; + pReq->Header.PageLength = ioc->spi_data.sdp1length; + pReq->Header.PageNumber = 1; + pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + pReq->PageAddress = cpu_to_le32(id | (bus << 8 )); + + /* Add a SGE to the config request. + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4; + + psge = (MptSge_t *) &pReq->PageBufferSGE; + psge->FlagsLength = cpu_to_le32(flagsLength); + cpu_to_leXX(dataDma, psge->Address); + + /* Set up the common data portion + */ + pData->Header.PageVersion = pReq->Header.PageVersion; + pData->Header.PageLength = pReq->Header.PageLength; + pData->Header.PageNumber = pReq->Header.PageNumber; + pData->Header.PageType = pReq->Header.PageType; + pData->RequestedParameters = cpu_to_le32(requested); + pData->Reserved = 0; + pData->Configuration = cpu_to_le32(configuration); + + dprintk((MYIOC_s_INFO_FMT + "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n", + ioc->name, id, (id | (bus<<8)), + requested, configuration)); + + mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_taskmgmt_timeout - Call back for timeout on a + * task management request. + * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long + * + */ +static void mptscsih_taskmgmt_timeout(unsigned long data) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; + + dprintk((MYIOC_s_WARN_FMT "TM request timed out!\n", hd->ioc->name)); + /* Delete the timer that triggered this callback. + * Remark: del_timer checks to make sure timer is active + * before deleting. + */ + del_timer(&hd->TMtimer); + + /* Call the reset handler. Already had a TM request + * timeout - so issue a diagnostic reset + */ + if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { + printk((KERN_WARNING " Firmware Reload FAILED!!\n")); + } + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Bus Scan and Domain Validation functionality ... + */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_scandv_complete - Scan and DV callback routine registered + * to Fustion MPT (base) driver. + * + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame + * @mr: Pointer to MPT reply frame (NULL if TurboReply) + * + * This routine is called from mpt.c::mpt_interrupt() at the completion + * of any SCSI IO request. + * This routine is registered with the Fusion MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + * + * Remark: Sets a completion code and (possibly) saves sense data + * in the IOC member localReply structure. + * Used ONLY for bus scan, DV and other internal commands. + */ +static int +mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +{ + MPT_SCSI_HOST *hd; + SCSIIORequest_t *pReq; + int completionCode; + u16 req_idx; + + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(MYIOC_s_ERR_FMT + "ScanDvComplete, %s req frame ptr! (=%p)\n", + ioc->name, mf?"BAD":"NULL", mf); + goto wakeup; + } + + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + del_timer(&hd->timer); + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + hd->ScsiLookup[req_idx] = NULL; + pReq = (SCSIIORequest_t *) mf; + + if (mf != hd->cmdPtr) { + printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n", + hd->ioc->name, mf, hd->cmdPtr); + } + hd->cmdPtr = NULL; + + ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n", + hd->ioc->name, mf, mr)); + + atomic_dec(&queue_depth); + + hd->pLocal = &hd->localReply; + + /* If target struct exists, clear sense valid flag. + */ + clear_sense_flag(hd, pReq); + + if (mr == NULL) { + completionCode = MPT_SCANDV_GOOD; + } else { + SCSIIOReply_t *pReply; + u16 status; + + pReply = (SCSIIOReply_t *) mr; + + status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + ddvprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", + status, pReply->SCSIState, pReply->SCSIStatus, + le32_to_cpu(pReply->IOCLogInfo))); + + switch(status) { + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + completionCode = MPT_SCANDV_SELECTION_TIMEOUT; + break; + + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + completionCode = MPT_SCANDV_DID_RESET; + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + if (pReply->Function == MPI_FUNCTION_CONFIG) { + ConfigReply_t *pr = (ConfigReply_t *)mr; + completionCode = MPT_SCANDV_GOOD; + hd->pLocal->header.PageVersion = pr->Header.PageVersion; + hd->pLocal->header.PageLength = pr->Header.PageLength; + hd->pLocal->header.PageNumber = pr->Header.PageNumber; + hd->pLocal->header.PageType = pr->Header.PageType; + + } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { + /* If the RAID Volume request is successful, + * return GOOD, else indicate that + * some type of error occurred. + */ + MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; + if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS) + completionCode = MPT_SCANDV_GOOD; + else + completionCode = MPT_SCANDV_SOME_ERROR; + + } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + VirtDevice *target; + u8 *sense_data; + int sz; + + /* save sense data in global & target structure + */ + completionCode = MPT_SCANDV_SENSE; + hd->pLocal->scsiStatus = pReply->SCSIStatus; + sense_data = ((u8 *)hd->ioc->sense_buf_pool + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + + sz = MIN (pReq->SenseBufferLength, + SCSI_STD_SENSE_BYTES); + memcpy(hd->pLocal->sense, sense_data, sz); + + target = hd->Targets[pReq->TargetID]; + if (target) { + memcpy(target->sense, sense_data, sz); + target->tflags + |= MPT_TARGET_FLAGS_VALID_SENSE; + } + + ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", + sense_data)); + } else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | + MPI_SCSI_STATE_NO_SCSI_STATUS)) { + completionCode = MPT_SCANDV_DID_RESET; + } else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + completionCode = MPT_SCANDV_DID_RESET; + } else { + /* If no error, this will be equivalent + * to MPT_SCANDV_GOOD + */ + completionCode = (int) pReply->SCSIStatus; + } + break; + + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completionCode = MPT_SCANDV_DID_RESET; + else + completionCode = MPT_SCANDV_SOME_ERROR; + break; + + default: + completionCode = MPT_SCANDV_SOME_ERROR; + break; + + } /* switch(status) */ + + ddvprintk((KERN_NOTICE " completionCode set to %08xh\n", + completionCode)); + } /* end of address reply case */ + + hd->pLocal->completion = completionCode; + + /* MF and RF are freed in mpt_interrupt + */ +wakeup: + /* Free Chain buffers (will never chain) in scan or dv */ + //mptscsih_freeChainBuffers(hd, req_idx); + + /* + * Wake up the original calling thread + */ + scandv_wait_done = 1; + wake_up(&scandv_waitq); + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_timer_expired - Call back for timer process. + * Used only for dv functionality. + * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long + * + */ +static void mptscsih_timer_expired(unsigned long data) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; +#ifndef MPT_SCSI_USE_NEW_EH + unsigned long flags; +#endif + + + ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr)); + + if (hd->cmdPtr) { + MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; + + if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { + /* Desire to issue a task management request here. + * TM requests MUST be single threaded. + * If old eh code and no TM current, issue request. + * If new eh code, do nothing. Wait for OS cmd timeout + * for bus reset. + */ +#ifndef MPT_SCSI_USE_NEW_EH + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (hd->tmPending) { + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + return; + } else + hd->tmPending = 1; + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + 0, 0, 0, NO_SLEEP) < 0) { + printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name); + } +#else + ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name)); +#endif + } else { + /* Perform a FW reload */ + if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { + printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name); + } + } + } else { + /* This should NEVER happen */ + printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name); + } + + /* No more processing. + * TM call will generate an interrupt for SCSI TM Management. + * The FW will reply to all outstanding commands, callback will finish cleanup. + * Hard reset clean-up will free all resources. + */ + ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name)); + + return; +} + +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_do_raid - Format and Issue a RAID volume request message. + * @hd: Pointer to scsi host structure + * @action: What do be done. + * @id: Logical target id. + * @bus: Target locations bus. + * + * Returns: < 0 on a fatal error + * 0 on success + * + * Remark: Wait to return until reply processed by the ISR. + */ +static int +mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io) +{ + MpiRaidActionRequest_t *pReq; + MPT_FRAME_HDR *mf; + MptSge_t *psge; + int flagsLength; + int in_isr; + + in_isr = in_interrupt(); + if (in_isr) { + dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n", + hd->ioc->name)); + return -EPERM; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) { + ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", + hd->ioc->name)); + return -EAGAIN; + } + pReq = (MpiRaidActionRequest_t *)mf; + pReq->Action = action; + pReq->Reserved1 = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_RAID_ACTION; + pReq->VolumeID = io->id; + pReq->VolumeBus = io->bus; + pReq->PhysDiskNum = io->physDiskNum; + pReq->MsgFlags = 0; + pReq->Reserved2 = 0; + pReq->ActionDataWord = 0; /* Reserved for this action */ + //pReq->ActionDataSGE = 0; + + psge = (MptSge_t *) &pReq->ActionDataSGE; + + /* Add a SGE to the config request. + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 0; + + psge->FlagsLength = cpu_to_le32(flagsLength); + cpu_to_leXX( (dma_addr_t) -1, psge->Address); + + ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", + hd->ioc->name, action, io->id)); + + hd->pLocal = NULL; + hd->timer.expires = jiffies + HZ*2; /* 2 second timeout */ + scandv_wait_done = 0; + + /* Save cmd pointer, for resource free if timeout or + * FW reload occurs + */ + hd->cmdPtr = mf; + + add_timer(&hd->timer); + mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + wait_event(scandv_waitq, scandv_wait_done); + + if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD)) + return -1; + + return 0; +} +#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_do_cmd - Do internal command. + * @hd: MPT_SCSI_HOST pointer + * @io: INTERNAL_CMD pointer. + * + * Issue the specified internally generated command and do command + * specific cleanup. For bus scan / DV only. + * NOTES: If command is Inquiry and status is good, + * initialize a target structure, save the data + * + * Remark: Single threaded access only. + * + * Return: + * < 0 if an illegal command or no resources + * + * 0 if good + * + * > 0 if command complete but some type of completion error. + */ +static int +mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) +{ + MPT_FRAME_HDR *mf; + MptSge_t *mpisge; + SCSIIORequest_t *pScsiReq; + SCSIIORequest_t ReqCopy; + int my_idx, ii, dir; + int rc, cmdTimeout; + int in_isr; + char cmdLen; + char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + char cmd = io->cmd; + + in_isr = in_interrupt(); + if (in_isr) { + dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n", + hd->ioc->name)); + return -EPERM; + } + + + /* Set command specific information + */ + switch (cmd) { + case CMD_Inquiry: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + CDB[4] = io->size; + cmdTimeout = 10; + break; + + case CMD_TestUnitReady: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + cmdTimeout = 10; + break; + + case CMD_StartStopUnit: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + CDB[4] = 1; /*Spin up the disk */ + cmdTimeout = 15; + break; + + case CMD_ReadBuffer: + cmdLen = 10; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + if (io->flags & MPT_ICFLAG_ECHO) { + CDB[1] = 0x0A; + } else { + CDB[1] = 0x02; + } + + if (io->flags & MPT_ICFLAG_BUF_CAP) { + CDB[1] |= 0x01; + } + CDB[6] = (io->size >> 16) & 0xFF; + CDB[7] = (io->size >> 8) & 0xFF; + CDB[8] = io->size & 0xFF; + cmdTimeout = 10; + break; + + case CMD_WriteBuffer: + cmdLen = 10; + dir = MPI_SCSIIO_CONTROL_WRITE; + CDB[0] = cmd; + if (io->flags & MPT_ICFLAG_ECHO) { + CDB[1] = 0x0A; + } else { + CDB[1] = 0x02; + } + CDB[6] = (io->size >> 16) & 0xFF; + CDB[7] = (io->size >> 8) & 0xFF; + CDB[8] = io->size & 0xFF; + cmdTimeout = 10; + break; + + case CMD_Reserve6: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + cmdTimeout = 10; + break; + + case CMD_Release6: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + cmdTimeout = 10; + break; + + case CMD_SynchronizeCache: + cmdLen = 10; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; +// CDB[1] = 0x02; /* set immediate bit */ + cmdTimeout = 10; + break; + + default: + /* Error Case */ + return -EFAULT; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) { + ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n", + hd->ioc->name)); + return -EBUSY; + } + + pScsiReq = (SCSIIORequest_t *) mf; + + /* Get the request index */ + my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + ADD_INDEX_LOG(my_idx); /* for debug */ + + if (io->flags & MPT_ICFLAG_PHYS_DISK) { + pScsiReq->TargetID = io->physDiskNum; + pScsiReq->Bus = 0; + pScsiReq->ChainOffset = 0; + pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; + } else { + pScsiReq->TargetID = io->id; + pScsiReq->Bus = io->bus; + pScsiReq->ChainOffset = 0; + pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; + } + + pScsiReq->CDBLength = cmdLen; + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + + pScsiReq->Reserved = 0; + + pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS; + /* MsgContext set in mpt_get_msg_fram call */ + + for (ii=0; ii < 8; ii++) + pScsiReq->LUN[ii] = 0; + pScsiReq->LUN[1] = io->lun; + + if (io->flags & MPT_ICFLAG_TAGGED_CMD) + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ); + else + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); + + for (ii=0; ii < 16; ii++) + pScsiReq->CDB[ii] = CDB[ii]; + + pScsiReq->DataLength = cpu_to_le32(io->size); + pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + + (my_idx * MPT_SENSE_BUFFER_ALLOC)); + + ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n", + hd->ioc->name, cmd, io->bus, io->id, io->lun)); + + /* 32 bit SG only */ + mpisge = (MptSge_t *) &pScsiReq->SGL; + + if (dir == MPI_SCSIIO_CONTROL_READ) { + mpisge->FlagsLength = cpu_to_le32( + MPT_SGE_FLAGS_SSIMPLE_READ | io->size); + } else { + mpisge->FlagsLength = cpu_to_le32( + MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size); + } + + /* data_dma defaults to -1 + */ + cpu_to_leXX(io->data_dma, mpisge->Address); + + /* The ISR will free the request frame, but we need + * the information to initialize the target. Duplicate. + */ + memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); + + /* Issue this command after: + * finish init + * add timer + * Wait until the reply has been received + * ScsiScanDvCtx callback function will + * set hd->pLocal; + * set scandv_wait_done and call wake_up + */ + hd->pLocal = NULL; + hd->timer.expires = jiffies + HZ*cmdTimeout; + scandv_wait_done = 0; + + /* Save cmd pointer, for resource free if timeout or + * FW reload occurs + */ + hd->cmdPtr = mf; + + add_timer(&hd->timer); + mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + wait_event(scandv_waitq, scandv_wait_done); + + if (hd->pLocal) { + rc = hd->pLocal->completion; + hd->pLocal->skip = 0; + + /* Always set fatal error codes in some cases. + */ + if (rc == MPT_SCANDV_SELECTION_TIMEOUT) + rc = -ENXIO; + else if (rc == MPT_SCANDV_SOME_ERROR) + rc = -rc; + } else { + rc = -EFAULT; + /* This should never happen. */ + ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n", + hd->ioc->name)); + } + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. + * @hd: Pointer to MPT_SCSI_HOST structure + * @portnum: IOC port number + * + * Uses the ISR, but with special processing. + * MUST be single-threaded. + * + * Return: 0 on completion + */ +static int +mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) +{ + MPT_ADAPTER *ioc= hd->ioc; + VirtDevice *pTarget = NULL; + SCSIDevicePage1_t *pcfg1Data = NULL; + INTERNAL_CMD iocmd; + CONFIGPARMS cfg; + dma_addr_t cfg1_dma_addr = -1; + ConfigPageHeader_t header1; + int bus = 0; + int id = 0; + int lun = 0; + int hostId = ioc->pfacts[portnum].PortSCSIID; + int max_id; + int requested, configuration, data; + int doConfig = 0; + u8 flags, factor; + + max_id = ioc->sh->max_id - 1; + + /* Following parameters will not change + * in this routine. + */ + iocmd.cmd = CMD_SynchronizeCache; + iocmd.flags = 0; + iocmd.physDiskNum = -1; + iocmd.data = NULL; + iocmd.data_dma = -1; + iocmd.size = 0; + iocmd.rsvd = iocmd.rsvd2 = 0; + + /* No SCSI hosts + */ + if (hd->Targets == NULL) + return 0; + + /* Skip the host + */ + if (id == hostId) + id++; + + /* Write SDP1 for all SCSI devices + * Alloc memory and set up config buffer + */ + if (hd->is_spi) { + if (ioc->spi_data.sdp1length > 0) { + pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev, + ioc->spi_data.sdp1length * 4, &cfg1_dma_addr); + + if (pcfg1Data != NULL) { + doConfig = 1; + header1.PageVersion = ioc->spi_data.sdp1version; + header1.PageLength = ioc->spi_data.sdp1length; + header1.PageNumber = 1; + header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + cfg.hdr = &header1; + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + cfg.timeout = 0; + } + } + } + + /* loop through all devices on this port + */ + while (bus < MPT_MAX_BUS) { + iocmd.bus = bus; + iocmd.id = id; + pTarget = hd->Targets[(int)id]; + + if (doConfig) { + + /* Set the negotiation flags */ + if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { + flags = pTarget->negoFlags; + } else { + flags = 0; + if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { + data = hd->ioc->spi_data.nvram[id]; + + if (data & MPT_NVRAM_WIDE_DISABLE) + flags |= MPT_TARGET_NO_NEGO_WIDE; + + factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; + if ((factor == 0) || (factor == MPT_ASYNC)) + flags |= MPT_TARGET_NO_NEGO_SYNC; + } + } + + /* Force to async, narrow */ + mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested, + &configuration, flags); + pcfg1Data->RequestedParameters = le32_to_cpu(requested); + pcfg1Data->Reserved = 0; + pcfg1Data->Configuration = le32_to_cpu(configuration); + cfg.pageAddr = (bus<<8) | id; + mpt_config(hd->ioc, &cfg); + } + + /* If target Ptr NULL or if this target is NOT a disk, skip. + */ + // if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) { + if (pTarget) { + for (lun=0; lun <= MPT_LAST_LUN; lun++) { + /* If LUN present, issue the command + */ + if (pTarget->luns & (1< max_id) { + id = 0; + bus++; + } + } + + if (pcfg1Data) { + pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr); + } + + return 0; +} + +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_domainValidation - Top level handler for domain validation. + * @hd: Pointer to MPT_SCSI_HOST structure. + * + * Uses the ISR, but with special processing. + * Called from schedule, should not be in interrupt mode. + * While thread alive, do dv for all devices needing dv + * + * Return: None. + */ +static void +mptscsih_domainValidation(void *arg) +{ + MPT_SCSI_HOST *hd = NULL; + MPT_ADAPTER *ioc = NULL; + unsigned long flags; + int id, maxid, dvStatus, did; + int ii, isPhysDisk; + + spin_lock_irqsave(&dvtaskQ_lock, flags); + dvtaskQ_active = 1; + if (dvtaskQ_release) { + dvtaskQ_active = 0; + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + return; + } + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + + /* For this ioc, loop through all devices and do dv to each device. + * When complete with this ioc, search through the ioc list, and + * for each scsi ioc found, do dv for all devices. Exit when no + * device needs dv. + */ + did = 1; + while (did) { + did = 0; + for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { + spin_lock_irqsave(&dvtaskQ_lock, flags); + if (dvtaskQ_release) { + dvtaskQ_active = 0; + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + return; + } + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + + /* DV only to SCSI adapters */ + if ((int)ioc->chip_type <= (int)FC929) + continue; + + /* Make sure everything looks ok */ + if (ioc->sh == NULL) + continue; + + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd == NULL) + continue; + + maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES); + + for (id = 0; id < maxid; id++) { + spin_lock_irqsave(&dvtaskQ_lock, flags); + if (dvtaskQ_release) { + dvtaskQ_active = 0; + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + return; + } + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + dvStatus = hd->ioc->spi_data.dvStatus[id]; + + if (dvStatus & MPT_SCSICFG_NEED_DV) { + + hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; + hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + + /* If hidden phys disk, block IO's to all + * raid volumes + * else, process normally + */ + isPhysDisk = 0; + if (ioc->spi_data.pIocPg3) { + /* Search IOC page 3 to determine if + * this is hidden physical disk + */ + Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; + int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + + while (numPDisk) { + if (pPDisk->PhysDiskID == id) { + isPhysDisk = 1; + break; + } + pPDisk++; + numPDisk--; + } + } + + if (isPhysDisk) { + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + if (hd->ioc->spi_data.isRaid & (1 << ii)) { + hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING; + } + } + } + + mptscsih_doDv(hd, 0, id); + did++; + hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE; + hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING; + + if (isPhysDisk) { + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + if (hd->ioc->spi_data.isRaid & (1 << ii)) { + hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING; + } + } + } + + /* Post OS IOs that were pended while + * DV running. + */ + post_pendingQ_commands(hd); + } + } + } + } + + spin_lock_irqsave(&dvtaskQ_lock, flags); + dvtaskQ_active = 0; + spin_unlock_irqrestore(&dvtaskQ_lock, flags); + + return; +} + + +#define MPT_GET_NVRAM_VALS 0x01 +#define MPT_UPDATE_MAX 0x02 +#define MPT_SET_MAX 0x04 +#define MPT_SET_MIN 0x08 +#define MPT_FALLBACK 0x10 +#define MPT_SAVE 0x20 + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_doDv - Perform domain validation to a target. + * @hd: Pointer to MPT_SCSI_HOST structure. + * @portnum: IOC port number. + * @target: Physical ID of this target + * + * Uses the ISR, but with special processing. + * MUST be single-threaded. + * Test will exit if target is at async & narrow. + * + * Return: None. + */ +static void +mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) +{ + MPT_ADAPTER *ioc = hd->ioc; + VirtDevice *pTarget = NULL; + u8 *pbuf1 = NULL; + u8 *pbuf2 = NULL; + dma_addr_t buf1_dma = -1; + dma_addr_t buf2_dma = -1; + ConfigPageHeader_t header1; + SCSIDevicePage1_t *pcfg1Data = NULL; + dma_addr_t cfg1_dma_addr = -1; + ConfigPageHeader_t header0; + SCSIDevicePage0_t *pcfg0Data = NULL; + dma_addr_t cfg0_dma_addr = -1; + DVPARAMETERS dv; + INTERNAL_CMD iocmd; + CONFIGPARMS cfg; + int rc, sz = 0; + int bufsize = 0; + int dataBufSize = 0; + int echoBufSize = 0; + int notDone; + int patt; + int repeat; + char firstPass = 1; + char doFallback = 0; + char readPage0; + char bus, lun; + + if (ioc->spi_data.sdp1length == 0) + return; + + if (ioc->spi_data.sdp0length == 0) + return; + + if (id == ioc->pfacts[portnum].PortSCSIID) + return; + + lun = 0; + bus = 0; + ddvtprintk((MYIOC_s_NOTE_FMT + "DV started: numIOs %d bus=%d, id %d dv @ %p\n", + ioc->name, atomic_read(&queue_depth), bus, id, &dv)); + + /* Prep DV structure + */ + memset (&dv, 0, sizeof(DVPARAMETERS)); + dv.id = id; + + /* Populate tmax with the current maximum + * transfer parameters for this target. + * Exit if narrow and async. + */ + dv.cmd = MPT_GET_NVRAM_VALS; + mptscsih_dv_parms(hd, &dv, NULL); + if ((!dv.max.width) && (!dv.max.offset)) + return; + + /* Prep SCSI IO structure + */ + iocmd.id = id; + iocmd.bus = bus; + iocmd.lun = lun; + iocmd.flags = 0; + iocmd.physDiskNum = -1; + iocmd.rsvd = iocmd.rsvd2 = 0; + + /* Use tagged commands if possible. + */ + pTarget = hd->Targets[id]; + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) + iocmd.flags |= MPT_ICFLAG_TAGGED_CMD; + + /* Prep cfg structure + */ + cfg.pageAddr = (bus<<8) | id; + cfg.hdr = NULL; + + /* Prep SDP0 header + */ + header0.PageVersion = ioc->spi_data.sdp0version; + header0.PageLength = ioc->spi_data.sdp0length; + header0.PageNumber = 0; + header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + pcfg0Data = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev, + header0.PageLength * 4, &cfg0_dma_addr); + if (!pcfg0Data) + return; + + /* Prep SDP1 header + */ + header1.PageVersion = ioc->spi_data.sdp1version; + header1.PageLength = ioc->spi_data.sdp1length; + header1.PageNumber = 1; + header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev, + header1.PageLength * 4, &cfg1_dma_addr); + if (!pcfg1Data) + goto target_done; + + /* Skip this ID? Set cfg.hdr to force config page write + */ + if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) && + (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { + + ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", + ioc->name, bus, id, lun)); + + dv.cmd = MPT_SET_MAX; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + cfg.hdr = &header1; + goto target_done; + } + + /* Finish iocmd inititialization - hidden or visible disk? */ + if (ioc->spi_data.pIocPg3) { + /* Searc IOC page 3 for matching id + */ + Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; + int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + + while (numPDisk) { + if (pPDisk->PhysDiskID == id) { + /* match */ + iocmd.flags |= MPT_ICFLAG_PHYS_DISK; + iocmd.physDiskNum = pPDisk->PhysDiskNum; + + /* Quiesce the IM + */ + if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) { + ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name)); + goto target_done; + } + break; + } + pPDisk++; + numPDisk--; + } + } + + /* RAID Volume ID's may double for a physical device. If RAID but + * not a physical ID as well, skip DV. + */ + if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK)) + goto target_done; + + + /* Basic Test. + * Async & Narrow - Inquiry + * Async & Narrow - Inquiry + * Maximum transfer rate - Inquiry + * Compare buffers: + * If compare, test complete. + * If miscompare and first pass, repeat + * If miscompare and not first pass, fall back and repeat + */ + hd->pLocal = NULL; + readPage0 = 0; + sz = SCSI_STD_INQUIRY_BYTES; + pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma); + pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma); + if (!pbuf1 || !pbuf2) + goto target_done; + + while (1) { + ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name)); + dv.cmd = MPT_SET_MIN; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + + cfg.hdr = &header1; + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + iocmd.cmd = CMD_Inquiry; + iocmd.data_dma = buf1_dma; + iocmd.data = pbuf1; + iocmd.size = sz; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + + /* Another GEM workaround. Check peripheral device type, + * if PROCESSOR, quit DV. + */ + if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08)) + goto target_done; + + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + + if (doFallback) + dv.cmd = MPT_FALLBACK; + else + dv.cmd = MPT_SET_MAX; + + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + if ((!dv.now.width) && (!dv.now.offset)) + goto target_done; + + iocmd.cmd = CMD_Inquiry; + iocmd.data_dma = buf2_dma; + iocmd.data = pbuf2; + iocmd.size = sz; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + /* Save the return code. + * If this is the first pass, + * read SCSI Device Page 0 + * and update the target max parameters. + */ + rc = hd->pLocal->completion; + doFallback = 0; + if (rc == MPT_SCANDV_GOOD) { + if (!readPage0) { + u32 sdp0_info; + u32 sdp0_nego; + + cfg.hdr = &header0; + cfg.physAddr = cfg0_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.dir = 0; + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E; + sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8; + + /* Quantum and Fujitsu workarounds. + * Quantum: PPR U320 -> PPR reply with Ultra2 and wide + * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide + * Resetart with a request for U160. + */ + if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { + doFallback = 1; + } else { + dv.cmd = MPT_UPDATE_MAX; + mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data); + /* Update the SCSI device page 1 area + */ + pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters; + readPage0 = 1; + } + } + + /* Quantum workaround. Restart this test will the fallback + * flag set. + */ + if (doFallback == 0) { + if (memcmp(pbuf1, pbuf2, sz) != 0) { + if (!firstPass) + doFallback = 1; + } else + break; /* test complete */ + } + + + } else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE)) + doFallback = 1; /* set fallback flag */ + else + goto target_done; + + firstPass = 0; + } + } + /* Free pbuf2, but use pbuf1 for + * acquiring the (echo) buffer size. + */ + pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma); + pbuf2 = NULL; + ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name)); + + /* Start the Enhanced Test. + * 0) issue TUR to clear out check conditions + * 1) read capacity of echo (regular) buffer + * 2) reserve device + * 3) do write-read-compare data pattern test + * 4) release + * 5) update nego parms to target struct + */ + cfg.hdr = &header1; + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + + iocmd.cmd = CMD_TestUnitReady; + iocmd.data_dma = -1; + iocmd.data = NULL; + iocmd.size = 0; + notDone = 1; + while (notDone) { + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + + if (hd->pLocal == NULL) + goto target_done; + + rc = hd->pLocal->completion; + if (rc == MPT_SCANDV_GOOD) + notDone = 0; + else if (rc == MPT_SCANDV_SENSE) { + u8 skey = hd->pLocal->sense[2] & 0x0F; + u8 asc = hd->pLocal->sense[12]; + u8 ascq = hd->pLocal->sense[13]; + ddvprintk((MYIOC_s_INFO_FMT + "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", + ioc->name, skey, asc, ascq)); + + if (skey == SK_UNIT_ATTENTION) + notDone++; /* repeat */ + else if ((skey == SK_NOT_READY) && + (asc == 0x04)&&(ascq == 0x01)) { + /* wait then repeat */ + mdelay (2000); + notDone++; + } else if ((skey == SK_NOT_READY) && (asc == 0x3A)) { + /* no medium, try read test anyway */ + notDone = 0; + } else { + /* All other errors are fatal. + */ + ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.", + ioc->name)); + goto target_done; + } + } else + goto target_done; + } + + iocmd.cmd = CMD_ReadBuffer; + iocmd.data_dma = buf1_dma; + iocmd.data = pbuf1; + iocmd.size = 4; + iocmd.flags |= MPT_ICFLAG_BUF_CAP; + + dataBufSize = 0; + echoBufSize = 0; + for (patt = 0; patt < 2; patt++) { + if (patt == 0) + iocmd.flags |= MPT_ICFLAG_ECHO; + else + iocmd.flags &= ~MPT_ICFLAG_ECHO; + + notDone = 1; + while (notDone) { + bufsize = 0; + + /* If not ready after 8 trials, + * give up on this device. + */ + if (notDone > 8) + goto target_done; + + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + rc = hd->pLocal->completion; + ddvprintk(("ReadBuffer Comp Code %d", rc)); + ddvprintk((" buff: %0x %0x %0x %0x\n", + pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3])); + + if (rc == MPT_SCANDV_GOOD) { + notDone = 0; + if (iocmd.flags & MPT_ICFLAG_ECHO) { + bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3]; + } else { + bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3]; + } + } else if (rc == MPT_SCANDV_SENSE) { + u8 skey = hd->pLocal->sense[2] & 0x0F; + u8 asc = hd->pLocal->sense[12]; + u8 ascq = hd->pLocal->sense[13]; + ddvprintk((MYIOC_s_INFO_FMT + "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", + ioc->name, skey, asc, ascq)); + if (skey == SK_ILLEGAL_REQUEST) { + notDone = 0; + } else if (skey == SK_UNIT_ATTENTION) { + notDone++; /* repeat */ + } else if ((skey == SK_NOT_READY) && + (asc == 0x04)&&(ascq == 0x01)) { + /* wait then repeat */ + mdelay (2000); + notDone++; + } else { + /* All other errors are fatal. + */ + ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.", + ioc->name)); + goto target_done; + } + } else { + /* All other errors are fatal + */ + goto target_done; + } + } + } + + if (iocmd.flags & MPT_ICFLAG_ECHO) + echoBufSize = bufsize; + else + dataBufSize = bufsize; + } + pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma); + pbuf1 = NULL; + sz = 0; + iocmd.flags &= ~MPT_ICFLAG_BUF_CAP; + + /* Use echo buffers if possible, + * Exit if both buffers are 0. + */ + if (echoBufSize > 0) { + iocmd.flags |= MPT_ICFLAG_ECHO; + if (dataBufSize > 0) + bufsize = MIN(echoBufSize, dataBufSize); + else + bufsize = echoBufSize; + } else if (dataBufSize == 0) + goto target_done; + + ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name, + (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize)); + + /* Allocate data buffers for write-read-compare test. + */ + sz = MIN(bufsize, 1024); + pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma); + pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma); + if (!pbuf1 || !pbuf2) + goto target_done; + + /* --- loop ---- + * On first pass, always issue a reserve. + * On additional loops, only if a reset has occurred. + * iocmd.flags indicates if echo or regular buffer + */ + for (patt = 0; patt < 4; patt++) { + ddvprintk(("Pattern %d\n", patt)); + if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) { + iocmd.cmd = CMD_TestUnitReady; + iocmd.data_dma = -1; + iocmd.data = NULL; + iocmd.size = 0; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + + iocmd.cmd = CMD_Release6; + iocmd.data_dma = -1; + iocmd.data = NULL; + iocmd.size = 0; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + rc = hd->pLocal->completion; + ddvprintk(("Release rc %d\n", rc)); + if (rc == MPT_SCANDV_GOOD) + iocmd.flags &= ~MPT_ICFLAG_RESERVED; + else + goto target_done; + } + iocmd.flags &= ~MPT_ICFLAG_RESERVED; + } + iocmd.flags &= ~MPT_ICFLAG_DID_RESET; + + repeat = 5; + while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) { + iocmd.cmd = CMD_Reserve6; + iocmd.data_dma = -1; + iocmd.data = NULL; + iocmd.size = 0; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + rc = hd->pLocal->completion; + if (rc == MPT_SCANDV_GOOD) { + iocmd.flags |= MPT_ICFLAG_RESERVED; + } else if (rc == MPT_SCANDV_SENSE) { + /* Wait if coming ready + */ + u8 skey = hd->pLocal->sense[2] & 0x0F; + u8 asc = hd->pLocal->sense[12]; + u8 ascq = hd->pLocal->sense[13]; + ddvprintk((MYIOC_s_INFO_FMT + "DV: Reserve Failed: ", ioc->name)); + ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", + skey, asc, ascq)); + + if ((skey == SK_NOT_READY) && (asc == 0x04)&& + (ascq == 0x01)) { + /* wait then repeat */ + mdelay (2000); + notDone++; + } else { + ddvprintk((MYIOC_s_INFO_FMT + "DV: Reserved Failed.", ioc->name)); + goto target_done; + } + } else { + ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.", + ioc->name)); + goto target_done; + } + } + } + + mptscsih_fillbuf(pbuf1, sz, patt, 1); + iocmd.cmd = CMD_WriteBuffer; + iocmd.data_dma = buf1_dma; + iocmd.data = pbuf1; + iocmd.size = sz; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + rc = hd->pLocal->completion; + if (rc == MPT_SCANDV_GOOD) + ; /* Issue read buffer */ + else if (rc == MPT_SCANDV_DID_RESET) { + /* If using echo buffers, reset to data buffers. + * Else do Fallback and restart + * this test (re-issue reserve + * because of bus reset). + */ + if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) { + iocmd.flags &= ~MPT_ICFLAG_ECHO; + } else { + dv.cmd = MPT_FALLBACK; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + if ((!dv.now.width) && (!dv.now.offset)) + goto target_done; + } + + iocmd.flags |= MPT_ICFLAG_DID_RESET; + patt = -1; + continue; + } else if (rc == MPT_SCANDV_SENSE) { + /* Restart data test if UA, else quit. + */ + u8 skey = hd->pLocal->sense[2] & 0x0F; + ddvprintk((MYIOC_s_INFO_FMT + "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, + hd->pLocal->sense[12], hd->pLocal->sense[13])); + if (skey == SK_UNIT_ATTENTION) { + patt = -1; + continue; + } else if (skey == SK_ILLEGAL_REQUEST) { + if (iocmd.flags & MPT_ICFLAG_ECHO) { + if (dataBufSize >= bufsize) { + iocmd.flags &= ~MPT_ICFLAG_ECHO; + patt = -1; + continue; + } + } + goto target_done; + } + else + goto target_done; + } else { + /* fatal error */ + goto target_done; + } + } + + iocmd.cmd = CMD_ReadBuffer; + iocmd.data_dma = buf2_dma; + iocmd.data = pbuf2; + iocmd.size = sz; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + goto target_done; + else if (hd->pLocal == NULL) + goto target_done; + else { + rc = hd->pLocal->completion; + if (rc == MPT_SCANDV_GOOD) { + /* If buffers compare, + * go to next pattern, + * else, do a fallback and restart + * data transfer test. + */ + if (memcmp (pbuf1, pbuf2, sz) == 0) { + ; /* goto next pattern */ + } else { + /* Miscompare with Echo buffer, go to data buffer, + * if that buffer exists. + * Miscompare with Data buffer, check first 4 bytes, + * some devices return capacity. Exit in this case. + */ + if (iocmd.flags & MPT_ICFLAG_ECHO) { + if (dataBufSize >= bufsize) + iocmd.flags &= ~MPT_ICFLAG_ECHO; + else + goto target_done; + } else { + if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) { + /* Argh. Device returning wrong data. + * Quit DV for this device. + */ + goto target_done; + } + + /* Had an actual miscompare. Slow down.*/ + dv.cmd = MPT_FALLBACK; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + if ((!dv.now.width) && (!dv.now.offset)) + goto target_done; + } + + patt = -1; + continue; + } + } else if (rc == MPT_SCANDV_DID_RESET) { + /* Do Fallback and restart + * this test (re-issue reserve + * because of bus reset). + */ + dv.cmd = MPT_FALLBACK; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + + if (mpt_config(hd->ioc, &cfg) != 0) + goto target_done; + + if ((!dv.now.width) && (!dv.now.offset)) + goto target_done; + + iocmd.flags |= MPT_ICFLAG_DID_RESET; + patt = -1; + continue; + } else if (rc == MPT_SCANDV_SENSE) { + /* Restart data test if UA, else quit. + */ + u8 skey = hd->pLocal->sense[2] & 0x0F; + ddvprintk((MYIOC_s_INFO_FMT + "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey, + hd->pLocal->sense[12], hd->pLocal->sense[13])); + if (skey == SK_UNIT_ATTENTION) { + patt = -1; + continue; + } + else + goto target_done; + } else { + /* fatal error */ + goto target_done; + } + } + + } /* --- end of patt loop ---- */ + +target_done: + if (iocmd.flags & MPT_ICFLAG_RESERVED) { + iocmd.cmd = CMD_Release6; + iocmd.data_dma = -1; + iocmd.data = NULL; + iocmd.size = 0; + if (mptscsih_do_cmd(hd, &iocmd) < 0) + printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", + ioc->name, id); + else if (hd->pLocal) { + if (hd->pLocal->completion == MPT_SCANDV_GOOD) + iocmd.flags &= ~MPT_ICFLAG_RESERVED; + } else { + printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", + ioc->name, id); + } + } + + + /* Set if cfg1_dma_addr contents is valid + */ + if (cfg.hdr != NULL) { + dv.cmd = MPT_SAVE; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + + /* Save the final negotiated settings to + * SCSI device page 1. + */ + cfg.hdr = &header1; + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + mpt_config(hd->ioc, &cfg); + } + + /* If this is a RAID Passthrough, enable internal IOs + */ + if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) { + if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0) + ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name)); + } + + /* Done with the DV scan of the current target + */ + if (pcfg0Data) { + pci_free_consistent(ioc->pcidev, header0.PageLength * 4, + pcfg0Data, cfg0_dma_addr); + } + + if (pcfg1Data) { + pci_free_consistent(ioc->pcidev, header1.PageLength * 4, + pcfg1Data, cfg1_dma_addr); + } + + if (pbuf1) { + pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma); + pbuf1 = NULL; + } + + if (pbuf2) { + pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma); + pbuf2 = NULL; + } + + ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n", + ioc->name, atomic_read(&queue_depth))); + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_dv_parms - perform a variety of operations on the + * parameters used for negotiation. + * @hd: Pointer to a SCSI host. + * @dv: Pointer to a structure that contains the maximum and current + * negotiated parameters. + */ +static void +mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) +{ + VirtDevice *pTarget = NULL; + SCSIDevicePage0_t *pPage0 = NULL; + SCSIDevicePage1_t *pPage1 = NULL; + int val = 0, data, configuration; + u8 width = 0; + u8 offset = 0; + u8 factor = 0; + u8 negoFlags = 0; + u8 cmd = dv->cmd; + u8 id = dv->id; + + switch (cmd) { + case MPT_GET_NVRAM_VALS: + ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ", + hd->ioc->name)); + /* Get the NVRAM values and save in tmax + * If not an LVD bus, the adapter minSyncFactor has been + * already throttled back. + */ + if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) { + width = pTarget->maxWidth; + offset = pTarget->maxOffset; + factor = pTarget->minSyncFactor; + negoFlags = pTarget->negoFlags; + } else { + if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { + data = hd->ioc->spi_data.nvram[id]; + width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0) + factor = MPT_ASYNC; + else { + factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; + if ((factor == 0) || (factor == MPT_ASYNC)){ + factor = MPT_ASYNC; + offset = 0; + } + } + } else { + width = MPT_NARROW; + offset = 0; + factor = MPT_ASYNC; + } + + /* Set the negotiation flags */ + negoFlags = 0; + if (!width) + negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + } + + /* limit by adapter capabilities */ + width = MIN(width, hd->ioc->spi_data.maxBusWidth); + offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset); + factor = MAX(factor, hd->ioc->spi_data.minSyncFactor); + + /* Check Consistency */ + if (offset && (factor < MPT_ULTRA2) && !width) + factor = MPT_ULTRA2; + + dv->max.width = width; + dv->max.offset = offset; + dv->max.factor = factor; + dv->max.flags = negoFlags; + ddvprintk((" width %d, factor %x, offset %x flags %x\n", + width, factor, offset, negoFlags)); + break; + + case MPT_UPDATE_MAX: + ddvprintk((MYIOC_s_NOTE_FMT + "Updating with SDP0 Data: ", hd->ioc->name)); + /* Update tmax values with those from Device Page 0.*/ + pPage0 = (SCSIDevicePage0_t *) pPage; + if (pPage0) { + val = cpu_to_le32(pPage0->NegotiatedParameters); + dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0; + dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16; + dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8; + } + + dv->now.width = dv->max.width; + dv->now.offset = dv->max.offset; + dv->now.factor = dv->max.factor; + ddvprintk(("width %d, factor %x, offset %x, flags %x\n", + dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags)); + break; + + case MPT_SET_MAX: + ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ", + hd->ioc->name)); + /* Set current to the max values. Update the config page.*/ + dv->now.width = dv->max.width; + dv->now.offset = dv->max.offset; + dv->now.factor = dv->max.factor; + dv->now.flags = dv->max.flags; + + pPage1 = (SCSIDevicePage1_t *)pPage; + if (pPage1) { + mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor, + dv->now.offset, &val, &configuration, dv->now.flags); + pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->Reserved = 0; + pPage1->Configuration = le32_to_cpu(configuration); + + } + + ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n", + dv->now.width, dv->now.factor, dv->now.offset, val, configuration)); + break; + + case MPT_SET_MIN: + ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ", + hd->ioc->name)); + /* Set page to asynchronous and narrow + * Do not update now, breaks fallback routine. */ + width = MPT_NARROW; + offset = 0; + factor = MPT_ASYNC; + negoFlags = dv->max.flags; + + pPage1 = (SCSIDevicePage1_t *)pPage; + if (pPage1) { + mptscsih_setDevicePage1Flags (width, factor, + offset, &val, &configuration, negoFlags); + pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->Reserved = 0; + pPage1->Configuration = le32_to_cpu(configuration); + } + ddvprintk(("width %d, factor %x, offset %x request %x config %x\n", + dv->now.width, dv->now.factor, + dv->now.offset, val, configuration)); + break; + + case MPT_FALLBACK: + ddvprintk((MYIOC_s_NOTE_FMT + "Fallback: Start: offset %d, factor %x, width %d \n", + hd->ioc->name, dv->now.offset, + dv->now.factor, dv->now.width)); + width = dv->now.width; + offset = dv->now.offset; + factor = dv->now.factor; + if ((offset) && (dv->max.width)) { + if (factor < MPT_ULTRA160) + factor = MPT_ULTRA160; + else if (factor < MPT_ULTRA2) { + factor = MPT_ULTRA2; + width = MPT_WIDE; + } else if ((factor == MPT_ULTRA2) && width) { + factor = MPT_ULTRA2; + width = MPT_NARROW; + } else if (factor < MPT_ULTRA) { + factor = MPT_ULTRA; + width = MPT_WIDE; + } else if ((factor == MPT_ULTRA) && width) { + factor = MPT_ULTRA; + width = MPT_NARROW; + } else if (factor < MPT_FAST) { + factor = MPT_FAST; + width = MPT_WIDE; + } else if ((factor == MPT_FAST) && width) { + factor = MPT_FAST; + width = MPT_NARROW; + } else if (factor < MPT_SCSI) { + factor = MPT_SCSI; + width = MPT_WIDE; + } else if ((factor == MPT_SCSI) && width) { + factor = MPT_SCSI; + width = MPT_NARROW; + } else { + factor = MPT_ASYNC; + offset = 0; + } + + } else if (offset) { + width = MPT_NARROW; + if (factor < MPT_ULTRA) + factor = MPT_ULTRA; + else if (factor < MPT_FAST) + factor = MPT_FAST; + else if (factor < MPT_SCSI) + factor = MPT_SCSI; + else { + factor = MPT_ASYNC; + offset = 0; + } - if (SD_Sense_Key_Specific_Valid(sd)) { - if (SenseKey == SK_ILLEGAL_REQUEST) { - Offset = SD_Bad_Byte(sd); - if (SD_Was_Illegal_Request(sd)) { - BadValue = ioop->cdbPtr[Offset]; - len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ", - BadValue); } else { - BadValue = ioop->dataPtr[Offset]; - len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ", - BadValue); + width = MPT_NARROW; + factor = MPT_ASYNC; } - len += sprintf(msg1+len, "byte=%02Xh", Offset); - if (SD_SKS_Bit_Pointer_Valid(sd)) - len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd)); - } else if ((SenseKey == SK_RECOVERED_ERROR) || - (SenseKey == SK_HARDWARE_ERROR) || - (SenseKey == SK_MEDIUM_ERROR)) { - len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh", - SD_Actual_Retry_Count(sd)); + + dv->now.width = width; + dv->now.offset = offset; + dv->now.factor = factor; + dv->now.flags = dv->max.flags; + + pPage1 = (SCSIDevicePage1_t *)pPage; + if (pPage1) { + mptscsih_setDevicePage1Flags (width, factor, offset, &val, + &configuration, dv->now.flags); + + pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->Reserved = 0; + pPage1->Configuration = le32_to_cpu(configuration); } - } -} -#endif -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int dump_cdb(char *foo, unsigned char *cdb) -{ - int i, grpCode, cdbLen; - int l = 0; + ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n", + dv->now.offset, dv->now.factor, dv->now.width, val, configuration)); + break; - grpCode = cdb[0] >> 5; - if (grpCode < 1) - cdbLen = 6; - else if (grpCode < 3) - cdbLen = 10; - else if (grpCode == 5) - cdbLen = 12; - else - cdbLen = 16; + case MPT_SAVE: + ddvprintk((MYIOC_s_NOTE_FMT + "Saving to Target structure: ", hd->ioc->name)); + ddvprintk(("offset %d, factor %x, width %d \n", + dv->now.offset, dv->now.factor, dv->now.width)); - for (i=0; i < cdbLen; i++) - l += sprintf(foo+l, " %02X", cdb[i]); + /* Save these values to target structures + * or overwrite nvram (phys disks only). + */ - return l; -} + if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) { + pTarget->maxWidth = dv->now.width; + pTarget->maxOffset = dv->now.offset; + pTarget->minSyncFactor = dv->now.factor; + } else { + /* Preserv all flags, use + * read-modify-write algorithm + */ + data = hd->ioc->spi_data.nvram[id]; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int dump_sd(char *foo, unsigned char *sd) -{ - int snsLen = 8 + SD_Additional_Sense_Length(sd); - int l = 0; - int i; + if (dv->now.width) + data &= ~MPT_NVRAM_WIDE_DISABLE; + else + data |= MPT_NVRAM_WIDE_DISABLE; - for (i=0; i < MIN(snsLen,18); i++) - l += sprintf(foo+l, " %02X", sd[i]); - l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : ""); + if (!dv->now.offset) + factor = MPT_ASYNC; - return l; + data &= ~MPT_NVRAM_SYNC_MASK; + data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK; + + hd->ioc->spi_data.nvram[id] = data; + } + break; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ -static const char * ascq_set_strings_4max( - u8 ASC, u8 ASCQ, - const char **s1, const char **s2, const char **s3, const char **s4) +/* mptscsih_fillbuf - fill a buffer with a special data pattern + * cleanup. For bus scan only. + * + * @buffer: Pointer to data buffer to be filled. + * @size: Number of bytes to fill + * @index: Pattern index + * @width: bus width, 0 (8 bits) or 1 (16 bits) + */ +static void +mptscsih_fillbuf(char *buffer, int size, int index, int width) { - static const char *asc_04_part1_string = "LOGICAL UNIT "; - static const char *asc_04_part2a_string = "NOT READY, "; - static const char *asc_04_part2b_string = "IS "; - static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ - "CAUSE NOT REPORTABLE", /* 04 00 */ - "IN PROCESS OF BECOMING READY", /* 04 01 */ - "INITIALIZING CMD. REQUIRED", /* 04 02 */ - "MANUAL INTERVENTION REQUIRED", /* 04 03 */ - /* Add " IN PROGRESS" to all the following... */ - "FORMAT", /* 04 04 */ - "REBUILD", /* 04 05 */ - "RECALCULATION", /* 04 06 */ - "OPERATION", /* 04 07 */ - "LONG WRITE", /* 04 08 */ - "SELF-TEST", /* 04 09 */ - NULL - }; - static char *asc_04_part4_string = " IN PROGRESS"; + char *ptr = buffer; + int ii; + char byte; + short val; - static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ - "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ - "POWER ON OCCURRED", /* 29 01 */ - "SCSI BUS RESET OCCURRED", /* 29 02 */ - "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ - "DEVICE INTERNAL RESET", /* 29 04 */ - "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ - "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ - NULL - }; - static char *ascq_vendor_uniq = "(Vendor Unique)"; - static char *ascq_noone = "(no matching ASC/ASCQ description found)"; - int idx; + switch (index) { + case 0: - *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ + if (width) { + /* Pattern: 0000 FFFF 0000 FFFF + */ + for (ii=0; ii < size; ii++, ptr++) { + if (ii & 0x02) + *ptr = 0xFF; + else + *ptr = 0x00; + } + } else { + /* Pattern: 00 FF 00 FF + */ + for (ii=0; ii < size; ii++, ptr++) { + if (ii & 0x01) + *ptr = 0xFF; + else + *ptr = 0x00; + } + } + break; - /* CHECKME! Need lock/sem? - * Update and examine for isense module presense. - */ - mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; + case 1: + if (width) { + /* Pattern: 5555 AAAA 5555 AAAA 5555 + */ + for (ii=0; ii < size; ii++, ptr++) { + if (ii & 0x02) + *ptr = 0xAA; + else + *ptr = 0x55; + } + } else { + /* Pattern: 55 AA 55 AA 55 + */ + for (ii=0; ii < size; ii++, ptr++) { + if (ii & 0x01) + *ptr = 0xAA; + else + *ptr = 0x55; + } + } + break; - if (mptscsih_ASCQ_TablePtr == NULL) { - /* 2nd chances... */ - if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { - *s1 = asc_04_part1_string; - *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; - *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; - /* check for " IN PROGRESS" ones */ - if (ASCQ >= 0x04) - *s4 = asc_04_part4_string; - } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) - *s1 = asc_29_ascq_NN_strings[ASCQ]; - /* - * else { leave all *s[1-4] values pointing to the empty "" string } + case 2: + /* Pattern: 00 01 02 03 04 05 + * ... FE FF 00 01.. */ - return *s1; - } + for (ii=0; ii < size; ii++, ptr++) + *ptr = (char) ii; + break; - /* - * Need to check ASC here; if it is "special," then - * the ASCQ is variable, and indicates failed component number. - * We must treat the ASCQ as a "don't care" while searching the - * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later - * on when we actually need to identify the failed component. - */ - if (SPECIAL_ASCQ(ASC,ASCQ)) - ASCQ = 0xFF; + case 3: + if (width) { + /* Wide Pattern: FFFE 0001 FFFD 0002 + * ... 4000 DFFF 8000 EFFF + */ + byte = 0; + for (ii=0; ii < size/2; ii++) { + /* Create the base pattern + */ + val = (1 << byte); + /* every 64 (0x40) bytes flip the pattern + * since we fill 2 bytes / iteration, + * test for ii = 0x20 + */ + if (ii & 0x20) + val = ~(val); - /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ - for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) - if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) - return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description); + if (ii & 0x01) { + *ptr = (char)( (val & 0xFF00) >> 8); + ptr++; + *ptr = (char)(val & 0xFF); + byte++; + byte &= 0x0F; + } else { + val = ~val; + *ptr = (char)( (val & 0xFF00) >> 8); + ptr++; + *ptr = (char)(val & 0xFF); + } - if ((ASC >= 0x80) || (ASCQ >= 0x80)) - *s1 = ascq_vendor_uniq; - else - *s1 = ascq_noone; + ptr++; + } + } else { + /* Narrow Pattern: FE 01 FD 02 FB 04 + * .. 7F 80 01 FE 02 FD ... 80 7F + */ + byte = 0; + for (ii=0; ii < size; ii++, ptr++) { + /* Base pattern - first 32 bytes + */ + if (ii & 0x01) { + *ptr = (1 << byte); + byte++; + byte &= 0x07; + } else { + *ptr = (char) (~(1 << byte)); + } - return *s1; + /* Flip the pattern every 32 bytes + */ + if (ii & 0x20) + *ptr = ~(*ptr); + } + } + break; + } } +#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SCSI Error Report; desired output format... - *--- -SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) - SCSI_Status=02h (CHECK CONDITION) - Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady - SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 - SenseKey=6h (UNIT ATTENTION); FRU=03h - ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" - *--- +/* Commandline Parsing routines and defines. + * + * insmod format: + * insmod mptscsih mptscsih="width:1 dv:n factor:0x09" + * boot format: + * mptscsih=width:1,dv:n,factor:0x8 + * */ +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif -int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) -{ - char foo[512]; - char buf2[32]; - char *statstr; - const char *opstr; - int sk = SD_Sense_Key(ioop->sensePtr); - const char *skstr = SenseKeyString[sk]; - unsigned char asc = SD_ASC(ioop->sensePtr); - unsigned char ascq = SD_ASCQ(ioop->sensePtr); - int l; +static char setup_token[] __initdata = + "dv:" + "width:" + "factor:" + ; /* DONNOT REMOVE THIS ';' */ + +#define OPT_DV 1 +#define OPT_MAX_WIDTH 2 +#define OPT_MIN_SYNC_FACTOR 3 - /* - * More quiet mode. - * Filter out common, repetitive, warning-type errors... like: - * POWER ON (06,29/00 or 06,29/01), - * SPINNING UP (02,04/01), - * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. - */ - if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) - || (sk==SK_NOT_READY && asc==0x04 && ascq==0x01) - || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) - ) - { - /* Do nothing! */ - return 0; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +__init get_setup_token(char *p) +{ + char *cur = setup_token; + char *pc; + int i = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + ++pc; + ++i; + if (!strncmp(p, cur, pc - cur)) + return i; + cur = pc; } + return 0; +} - /* - * Protect ourselves... - */ - if (ioop->cdbPtr == NULL) - ioop->cdbPtr = dummyCDB; - if (ioop->sensePtr == NULL) - ioop->sensePtr = dummySenseData; - if (ioop->inqPtr == NULL) - ioop->inqPtr = dummyInqData; - if (ioop->dataPtr == NULL) - ioop->dataPtr = dummyScsiData; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +__init mptscsih_setup(char *str) +{ + char *cur = str; + char *pc, *pv; + unsigned long val; + int c; + + printk("KERN_WARNING: mptscsih_setup arg %s\n", str); + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + char *pe; + + val = 0; + pv = pc; + c = *++pv; + + if (c == 'n') + val = 0; + else if (c == 'y') + val = 1; + else + val = (int) simple_strtoul(pv, &pe, 0); - statstr = NULL; - if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || - ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { - (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); - statstr = buf2; - } + printk("Found Token: %s, value %x\n", cur, (int)val); + switch (get_setup_token(cur)) { + case OPT_DV: + driver_setup.dv = val; + break; - opstr = NULL; - if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) - opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; - else if (mpt_ScsiOpcodesPtr) - opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; + case OPT_MAX_WIDTH: + driver_setup.max_width = val; + break; - l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n" - " SCSI_Status=%02Xh (%s)\n" - " Original_CDB[]:", - ioop->DevIDStr, - ioop->SCSIStatus, - statstr); - l += dump_cdb(foo+l, ioop->cdbPtr); - if (opstr) - l += sprintf(foo+l, " - \"%s\"", opstr); - l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr)); - l += dump_sd(foo+l, ioop->sensePtr); - l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", - sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); + case OPT_MIN_SYNC_FACTOR: + driver_setup.min_sync_fac = val; + break; - { - const char *x1, *x2, *x3, *x4; - x1 = x2 = x3 = x4 = ""; - x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); - if (x1 != NULL) { - if (x1[0] != '(') - l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); - else - l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); + default: + printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); + break; } - } - -#if 0 - if (SPECIAL_ASCQ(asc,ascq)) - l += sprintf(foo+l, " (%02Xh)", ascq); -#endif - - PrintF(("%s\n", foo)); - return l; + if ((cur = strchr(cur, ARG_SEP)) != NULL) + ++cur; + } + return 1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -urN linux-2.4.18/drivers/message/fusion/mptscsih.h linux-2.4.19-pre5/drivers/message/fusion/mptscsih.h --- linux-2.4.18/drivers/message/fusion/mptscsih.h Sun Feb 17 11:40:27 2002 +++ linux-2.4.19-pre5/drivers/message/fusion/mptscsih.h Sat Mar 30 22:55:39 2002 @@ -15,11 +15,12 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2001 LSI Logic Corporation + * Copyright (c) 1999-2002 LSI Logic Corporation * Originally By: Steven J. Ralston - * (mailto:Steve.Ralston@lsil.com) + * (mailto:netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $ + * $Id: mptscsih.h,v 1.16 2002/02/27 18:44:30 sralston Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -68,14 +69,47 @@ * SCSI Public stuff... */ -#ifdef __sparc__ -#define MPT_SCSI_CAN_QUEUE 63 -#define MPT_SCSI_CMD_PER_LUN 63 - /* FIXME! Still investigating qd=64 hang on sparc64... */ -#else -#define MPT_SCSI_CAN_QUEUE 64 -#define MPT_SCSI_CMD_PER_LUN 64 -#endif +/* + * Try to keep these at 2^N-1 + */ +#define MPT_FC_CAN_QUEUE 63 +#define MPT_SCSI_CAN_QUEUE 31 +#define MPT_SCSI_CMD_PER_LUN 7 + +#define MPT_SCSI_SG_DEPTH 40 + +/* To disable domain validation, uncomment the + * following line. No effect for FC devices. + * For SCSI devices, driver will negotiate to + * NVRAM settings (if available) or to maximum adapter + * capabilities. + */ +/* #define MPTSCSIH_DISABLE_DOMAIN_VALIDATION */ + + +/* SCSI driver setup structure. Settings can be overridden + * by command line options. + */ +#define MPTSCSIH_DOMAIN_VALIDATION 1 +#define MPTSCSIH_MAX_WIDTH 1 +#define MPTSCSIH_MIN_SYNC 0x08 + +struct mptscsih_driver_setup +{ + u8 dv; + u8 max_width; + u8 min_sync_fac; +}; + + +#define MPTSCSIH_DRIVER_SETUP \ +{ \ + MPTSCSIH_DOMAIN_VALIDATION, \ + MPTSCSIH_MAX_WIDTH, \ + MPTSCSIH_MIN_SYNC, \ +} + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -143,6 +177,7 @@ #define x_scsi_dev_reset mptscsih_dev_reset #define x_scsi_host_reset mptscsih_host_reset #define x_scsi_bios_param mptscsih_bios_param +#define x_scsi_select_queue_depths mptscsih_select_queue_depths #define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh #define x_scsi_old_abort mptscsih_old_abort @@ -155,7 +190,6 @@ extern int x_scsi_detect(Scsi_Host_Template *); extern int x_scsi_release(struct Scsi_Host *host); extern const char *x_scsi_info(struct Scsi_Host *); -/*extern int x_scsi_command(Scsi_Cmnd *);*/ extern int x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); #ifdef MPT_SCSI_USE_NEW_EH extern int x_scsi_abort(Scsi_Cmnd *); @@ -167,6 +201,7 @@ extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int); #endif extern int x_scsi_bios_param(Disk *, kdev_t, int *); +extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *); extern void x_scsi_taskmgmt_bh(void *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) @@ -194,7 +229,7 @@ bios_param: x_scsi_bios_param, \ can_queue: MPT_SCSI_CAN_QUEUE, \ this_id: -1, \ - sg_tablesize: 25, \ + sg_tablesize: MPT_SCSI_SG_DEPTH, \ cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ unchecked_isa_dma: 0, \ use_clustering: ENABLE_CLUSTERING, \ @@ -217,7 +252,7 @@ bios_param: x_scsi_bios_param, \ can_queue: MPT_SCSI_CAN_QUEUE, \ this_id: -1, \ - sg_tablesize: 25, \ + sg_tablesize: MPT_SCSI_SG_DEPTH, \ cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ unchecked_isa_dma: 0, \ use_clustering: ENABLE_CLUSTERING \ diff -urN linux-2.4.18/drivers/message/fusion/scsi3.h linux-2.4.19-pre5/drivers/message/fusion/scsi3.h --- linux-2.4.18/drivers/message/fusion/scsi3.h Sun Feb 17 01:21:42 2002 +++ linux-2.4.19-pre5/drivers/message/fusion/scsi3.h Sat Mar 30 22:55:39 2002 @@ -4,11 +4,12 @@ * (Ultimately) SCSI-3 definitions; for now, inheriting * SCSI-2 definitions. * - * Copyright (c) 1996-2001 Steven J. Ralston + * Copyright (c) 1996-2002 Steven J. Ralston * Written By: Steven J. Ralston (19960517) - * (mailto:Steve.Ralston@lsil.com) + * (mailto:sjralston1@netscape.net) + * (mailto:Pam.Delaney@lsil.com) * - * $Id: scsi3.h,v 1.5 2001/04/06 14:31:32 sralston Exp $ + * $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $ */ #ifndef SCSI3_H_INCLUDED @@ -63,7 +64,10 @@ #define CMD_Write10 0x2A #define CMD_WriteVerify 0x2E #define CMD_Verify 0x2F +#define CMD_SynchronizeCache 0x35 #define CMD_ReadDefectData 0x37 +#define CMD_WriteBuffer 0x3B +#define CMD_ReadBuffer 0x3C #define CMD_ReadLong 0x3E #define CMD_LogSelect 0x4C #define CMD_LogSense 0x4D diff -urN linux-2.4.18/drivers/message/i2o/README linux-2.4.19-pre5/drivers/message/i2o/README --- linux-2.4.18/drivers/message/i2o/README Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/message/i2o/README Sat Mar 30 22:55:28 2002 @@ -39,6 +39,9 @@ Taneli Vähäkangas, University of Helsinki Finland Fixes to i2o_config +Boji T Kannanthanam + Intel i2o controller work, extending proc/config stuff + CREDITS This work was made possible by @@ -62,32 +65,38 @@ ASUSTeK Loan of I2O motherboard +Promise + Providing a Supertrak 100 board and support info + +DPT + Providing a DPT smartraid I2O card (use dpt_i2o for this + board however) + STATUS: +o Should be stable for x86 32bit -o The core setup works within limits. -o The scsi layer seems to almost work. - I'm still chasing down the hang bug. -o The block OSM is mostly functional -o LAN OSM works with FDDI and Ethernet cards. +KNOWN ISSUES: +o Reports that intel boards die if you load i2o_block and i2o_scsi +o Some promise cards need firmware updates TO DO: General: +o Finish 64bit and big endian cleanup +o Switch to new PCI mapping layer throughout +o Hotswap of controllers o Provide hidden address space if asked o Long term message flow control o PCI IOP's without interrupts are not supported yet o Push FAIL handling into the core o DDM control interfaces for module load etc -o Add I2O 2.0 support (Deffered to 2.5 kernel) Block: -o Multiple major numbers -o Read ahead and cache handling stuff. Talk to Ingo and people +o Multiple major numbers (problem goes away in 2.5) o Power management o Finish Media changers SCSI: -o Find the right way to associate drives/luns/busses Lan: o Performance tuning @@ -95,4 +104,3 @@ Tape: o Anyone seen anything implementing this ? - (D.S: Will attempt to do so if spare cycles permit) diff -urN linux-2.4.18/drivers/mtd/Config.in linux-2.4.19-pre5/drivers/mtd/Config.in --- linux-2.4.18/drivers/mtd/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/Config.in Sat Mar 30 22:55:39 2002 @@ -1,5 +1,5 @@ -# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $ +# $Id: Config.in,v 1.73 2002/03/08 16:34:35 rkaiser Exp $ mainmenu_option next_comment comment 'Memory Technology Devices (MTD)' @@ -12,6 +12,7 @@ int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0 fi dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD + dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS diff -urN linux-2.4.18/drivers/mtd/Makefile linux-2.4.19-pre5/drivers/mtd/Makefile --- linux-2.4.18/drivers/mtd/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/Makefile Sat Mar 30 22:55:39 2002 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now inherited from the # parent makes.. # -# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $ +# $Id: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $ obj-y += chips/chipslink.o maps/mapslink.o \ @@ -19,7 +19,7 @@ O_TARGET := mtdlink.o -export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o +export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o list-multi := nftl.o mod-subdirs := @@ -44,6 +44,7 @@ # Core functionality. obj-$(CONFIG_MTD) += mtdcore.o +obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o diff -urN linux-2.4.18/drivers/mtd/afs.c linux-2.4.19-pre5/drivers/mtd/afs.c --- linux-2.4.18/drivers/mtd/afs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/afs.c Sat Mar 30 22:55:39 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $ + $Id: afs.c,v 1.7 2001/11/01 20:04:54 rmk Exp $ ======================================================================*/ @@ -80,6 +80,12 @@ * Does it contain the magic number? */ if (fs.signature != 0xa0ffff9f) + ret = 1; + + /* + * Don't touch the SIB. + */ + if (fs.type == 2) ret = 1; *iis_start = fs.image_info_base & mask; diff -urN linux-2.4.18/drivers/mtd/chips/Makefile linux-2.4.19-pre5/drivers/mtd/chips/Makefile --- linux-2.4.18/drivers/mtd/chips/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/chips/Makefile Sat Mar 30 22:55:39 2002 @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $ +# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ O_TARGET := chipslink.o @@ -20,7 +20,6 @@ obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o -obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -urN linux-2.4.18/drivers/mtd/chips/amd_flash.c linux-2.4.19-pre5/drivers/mtd/chips/amd_flash.c --- linux-2.4.18/drivers/mtd/chips/amd_flash.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/chips/amd_flash.c Sat Mar 30 22:55:39 2002 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -52,6 +52,7 @@ /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_SST 0x00BF @@ -67,6 +68,9 @@ #define AM29BDS323D 0x22D1 #define AM29BDS643D 0x227E +/* Atmel */ +#define AT49xV16x 0x00C0 +#define AT49xV16xT 0x00C2 /* Fujitsu */ #define MBM29LV160TE 0x22C4 @@ -612,6 +616,26 @@ { offset: 0x000000, erasesize: 0x10000, numblocks: 96 }, { offset: 0x600000, erasesize: 0x10000, numblocks: 31 }, { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 }, + } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16x, + name: "Atmel AT49xV16x", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x02000, numblocks: 8 }, + { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16xT, + name: "Atmel AT49xV16xT", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, + { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 } } } }; diff -urN linux-2.4.18/drivers/mtd/chips/jedec.c linux-2.4.19-pre5/drivers/mtd/chips/jedec.c --- linux-2.4.18/drivers/mtd/chips/jedec.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/chips/jedec.c Sat Mar 30 22:55:39 2002 @@ -11,7 +11,7 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ + * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $ */ #include @@ -738,6 +738,7 @@ } //printk("done\n"); + instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); return 0; diff -urN linux-2.4.18/drivers/mtd/chips/sharp.c linux-2.4.19-pre5/drivers/mtd/chips/sharp.c --- linux-2.4.18/drivers/mtd/chips/sharp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/chips/sharp.c Sat Mar 30 22:55:39 2002 @@ -4,7 +4,7 @@ * Copyright 2000,2001 David A. Schleef * 2000,2001 Lineo, Inc. * - * $Id: sharp.c,v 1.6 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: sharp.c,v 1.7 2002/02/13 15:49:07 dwmw2 Exp $ * * Devices supported: * LH28F016SCT Symmetrical block flash memory, 2Mx8 @@ -440,7 +440,7 @@ timeo = jiffies + HZ; - while(jiffieswrite32(map,CMD_READ_STATUS,adr); status = map->read32(map,adr); if((status & SR_READY)==SR_READY){ diff -urN linux-2.4.18/drivers/mtd/devices/doc1000.c linux-2.4.19-pre5/drivers/mtd/devices/doc1000.c --- linux-2.4.18/drivers/mtd/devices/doc1000.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/devices/doc1000.c Sat Mar 30 22:55:39 2002 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: doc1000.c,v 1.15 2001/10/02 15:05:13 dwmw2 Exp $ + $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $ ======================================================================*/ @@ -483,7 +483,7 @@ else priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING; } - else if (erase->time + erase_timeout < jiffies) + else if (time_after(jiffies, erase->time + erase_timeout)) { printk("Flash erase timed out. The world is broken.\n"); diff -urN linux-2.4.18/drivers/mtd/devices/mtdram.c linux-2.4.19-pre5/drivers/mtd/devices/mtdram.c --- linux-2.4.18/drivers/mtd/devices/mtdram.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/devices/mtdram.c Sat Mar 30 22:55:39 2002 @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $ * Author: Alexander Larsson * * Copyright (c) 1999 Alexander Larsson @@ -123,7 +123,7 @@ // Allocate some memory mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); if (!mtd_info) - return 0; + return -ENOMEM; memset(mtd_info, 0, sizeof(*mtd_info)); diff -urN linux-2.4.18/drivers/mtd/devices/pmc551.c linux-2.4.19-pre5/drivers/mtd/devices/pmc551.c --- linux-2.4.18/drivers/mtd/devices/pmc551.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/devices/pmc551.c Sat Mar 30 22:55:39 2002 @@ -1,5 +1,5 @@ /* - * $Id: pmc551.c,v 1.19 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: pmc551.c,v 1.20 2002/03/05 13:47:08 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -716,7 +716,7 @@ } /* - * This is needed untill the driver is capable of reading the + * This is needed until the driver is capable of reading the * onboard I2C SROM to discover the "real" memory size. */ if(msize) { diff -urN linux-2.4.18/drivers/mtd/ftl.c linux-2.4.19-pre5/drivers/mtd/ftl.c --- linux-2.4.18/drivers/mtd/ftl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/ftl.c Sat Mar 30 22:55:39 2002 @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -87,7 +87,7 @@ #define register_disk(dev, drive, minors, ops, size) \ do { (dev)->part[(drive)*(minors)].nr_sects = size; \ if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \ - resetup_one_dev(dev, drive); } while (0); + resetup_one_dev(dev, drive); } while (0) #endif #if (LINUX_VERSION_CODE < 0x20320) @@ -99,6 +99,13 @@ #define request_arg_t request_queue_t *q #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif /*====================================================================*/ @@ -235,7 +242,9 @@ }; #else static struct block_device_operations ftl_blk_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: ftl_open, release: ftl_close, ioctl: ftl_ioctl, @@ -895,11 +904,16 @@ if (ftl_gendisk.part[minor].nr_sects == 0) return -ENXIO; - if (!get_mtd_device(partition->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; + BLK_INC_USE_COUNT; + if (!get_mtd_device(partition->mtd, -1)) { + BLK_DEC_USE_COUNT; + return -ENXIO; + } + if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { put_mtd_device(partition->mtd); + BLK_DEC_USE_COUNT; return -EROFS; } @@ -920,9 +934,6 @@ DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); - /* Flush all writes */ - invalidate_device(inode->i_rdev, 1); - /* Wait for any pending erase operations to complete */ if (part->mtd->sync) part->mtd->sync(part->mtd); @@ -935,6 +946,7 @@ atomic_dec(&part->open); put_mtd_device(part->mtd); + BLK_DEC_USE_COUNT; release_return(0); } /* ftl_close */ @@ -1171,9 +1183,11 @@ case BLKGETSIZE: ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg); break; +#ifdef BLKGETSIZE64 case BLKGETSIZE64: ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg); break; +#endif case BLKRRPART: ret = ftl_reread_partitions(minor); break; @@ -1401,7 +1415,7 @@ memset(myparts, 0, sizeof(myparts)); - DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $\n"); if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { printk(KERN_NOTICE "ftl_cs: unable to grab major " diff -urN linux-2.4.18/drivers/mtd/maps/Config.in linux-2.4.19-pre5/drivers/mtd/maps/Config.in --- linux-2.4.18/drivers/mtd/maps/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/Config.in Sat Mar 30 22:55:39 2002 @@ -1,12 +1,12 @@ # drivers/mtd/maps/Config.in -# $Id: Config.in,v 1.16 2001/09/19 18:28:37 dwmw2 Exp $ +# $Id: Config.in,v 1.28 2002/03/08 16:34:35 rkaiser Exp $ mainmenu_option next_comment comment 'Mapping drivers for chip access' -dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI +dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 @@ -23,20 +23,33 @@ dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT + if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then + hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000 + fi dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC - dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_I386 $CONFIG_MTD_JEDEC + dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE + dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE + dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE fi if [ "$CONFIG_PPC" = "y" ]; then - dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL $CONFIG_PPC - dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI $CONFIG_PPC - dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI_INTELSTD $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI_AMDSTD + dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL + dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI + dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI fi if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate ' Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 + dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 + if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" ]; then + bool ' Pb1500 boot flash device' CONFIG_MTD_PB1500_BOOT + bool ' Pb1500 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER + fi dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000 @@ -46,8 +59,12 @@ dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT fi -if [ "$CONFIG_SH" = "y" ]; then - dep_tristate ' CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SH $CONFIG_MTD_REDBOOT_PARTS +if [ "$CONFIG_SUPERH" = "y" ]; then + dep_tristate ' CFI Flash device mapped on Hitachi SolutionEngine' \ + CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CFI + if [ "$CONFIG_MTD_SOLUTIONENGINE" != "n" ]; then + hex ' Default reserved Flash size' CONFIG_MTD_SUPERH_RESERVE 0x00010000 + fi fi if [ "$CONFIG_ARM" = "y" ]; then @@ -57,6 +74,14 @@ dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 + dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT + dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 fi +if [ "$CONFIG_ALPHA" = "y" ]; then + dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE +fi + +# This needs CFI or JEDEC, depending on the cards found. +dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI endmenu diff -urN linux-2.4.18/drivers/mtd/maps/Makefile linux-2.4.19-pre5/drivers/mtd/maps/Makefile --- linux-2.4.18/drivers/mtd/maps/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/Makefile Sat Mar 30 22:55:39 2002 @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $ +# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $ O_TARGET := mapslink.o @@ -11,9 +11,15 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o +obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o +obj-$(CONFIG_MTD_AMD766ROM) += amd766rom.o +obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o +obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_NORA) += nora.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o @@ -29,5 +35,9 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o +obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o +obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/mtd/maps/amd766rom.c linux-2.4.19-pre5/drivers/mtd/maps/amd766rom.c --- linux-2.4.18/drivers/mtd/maps/amd766rom.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/amd766rom.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,245 @@ +/* + * amd766rom.c + * + * Normal mappings of chips in physical memory + * $Id: amd766rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct amd766rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; + u32 window_start, window_size; + struct pci_dev *pdev; +}; + +static __u8 amd766rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 amd766rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 amd766rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void amd766rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +static void amd766rom_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->map_priv_1 + to, from, len); +} + +static struct amd766rom_map_info amd766rom_map = { + map: { + name: "AMD766 rom", + size: 0, + buswidth: 1, + read8: amd766rom_read8, + read16: amd766rom_read16, + read32: amd766rom_read32, + copy_from: amd766rom_copy_from, + write8: amd766rom_write8, + write16: amd766rom_write16, + write32: amd766rom_write32, + copy_to: amd766rom_copy_to, + /* The standard rom socket is for single power supply chips + * that don't have an extra vpp. + */ + }, + mtd: 0, + window_addr: 0, +}; + +static int __devinit amd766rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct rom_window { + u32 start; + u32 size; + u8 segen_bits; + }; + static struct rom_window rom_window[] = { + { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, + { 0xffc00000, 4*1024*1024, (1<<7), }, + { 0xffff0000, 64*1024, 0 }, + { 0 , 0, 0 }, + }; + static const u32 rom_probe_sizes[] = { + 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, + 256*1024, 128*1024, 64*1024, 0}; + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 }; + u8 byte; + struct amd766rom_map_info *info = &amd766rom_map; + struct rom_window *window; + int i; + u32 rom_size; + + window = &rom_window[0]; + while(window->size) { + if (request_mem_region(window->start, window->size, "amd766rom")) { + break; + } + window++; + } + if (!window->size) { + printk(KERN_ERR "amd766rom: cannot reserve rom window"); + goto err_out_none; + } + + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + printk(KERN_NOTICE "amd766rom window : %x at %x\n", + window->size, window->start); + /* For write accesses caches are useless */ + info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); + + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + info->mtd = 0; + for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { + char **chip_type; + if (rom_size > window->size) { + continue; + } + info->map.map_priv_1 = + info->window_addr + window->size - rom_size; + info->map.size = rom_size; + chip_type = rom_probe_types; + for(; !info->mtd && *chip_type; chip_type++) { + info->mtd = do_map_probe(*chip_type, &amd766rom_map.map); + } + if (info->mtd) { + break; + } + } + if (!info->mtd) { + goto err_out_iounmap; + } + printk(KERN_NOTICE "amd766rom chip at offset: %x\n", + window->size - rom_size); + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + info->window_start = window->start; + info->window_size = window->size; + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: + release_mem_region(window->start, window->size); +err_out_none: + return -ENODEV; +} + + +static void __devexit amd766rom_remove_one (struct pci_dev *pdev) +{ + struct amd766rom_map_info *info = &amd766rom_map; + u8 byte; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte & ~1); + + release_mem_region(info->window_start, info->window_size); +} + +static struct pci_device_id amd766rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, amd766rom_pci_tbl); + +#if 0 +static struct pci_driver amd766rom_driver = { + name: "amd766rom", + id_table: amd766rom_pci_tbl, + probe: amd766rom_init_one, + remove: amd766rom_remove_one, +}; +#endif + +int __init init_amd766rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0); + if (pdev) { + amd766rom_map.pdev = pdev; + return amd766rom_init_one(pdev, &amd766rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&amd766rom_driver); +#endif +} + +static void __exit cleanup_amd766rom(void) +{ + amd766rom_remove_one(amd766rom_map.pdev); +} + +module_init(init_amd766rom); +module_exit(cleanup_amd766rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD766 southbridge"); + diff -urN linux-2.4.18/drivers/mtd/maps/autcpu12-nvram.c linux-2.4.19-pre5/drivers/mtd/maps/autcpu12-nvram.c --- linux-2.4.18/drivers/mtd/maps/autcpu12-nvram.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/autcpu12-nvram.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,179 @@ +/* + * NV-RAM memory access on autcpu12 + * (C) 2002 Thomas Gleixner (gleixner@autronix.de) + * + * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + while(len) { + __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); + from++; + to++; + len--; + } +} + +static struct mtd_info *sram_mtd; + +struct map_info autcpu12_sram_map = { + name: "SRAM", + size: 32768, + buswidth: 8, + read8: autcpu12_read8, + read16: autcpu12_read16, + read32: autcpu12_read32, + copy_from: autcpu12_copy_from, + write8: autcpu12_write8, + write16: autcpu12_write16, + write32: autcpu12_write32, + copy_to: autcpu12_copy_to +}; + +static int __init init_autcpu12_sram (void) +{ + int err, save0, save1; + + autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); + if (!autcpu12_sram_map.map_priv_1) { + printk("Failed to ioremap autcpu12 NV-RAM space\n"); + err = -EIO; + goto out; + } + + /* + * Check for 32K/128K + * read ofs 0 + * read ofs 0x10000 + * Write complement to ofs 0x100000 + * Read and check result on ofs 0x0 + * Restore contents + */ + save0 = autcpu12_read32(&autcpu12_sram_map,0); + save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); + autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); + /* if we find this pattern on 0x0, we have 32K size + * restore contents and exit + */ + if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { + autcpu12_write32(&autcpu12_sram_map,save0,0x0); + goto map; + } + /* We have a 128K found, restore 0x10000 and set size + * to 128K + */ + autcpu12_write32(&autcpu12_sram_map,save1,0x10000); + autcpu12_sram_map.size = SZ_128K; + +map: + sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map); + if (!sram_mtd) { + printk("NV-RAM probe failed\n"); + err = -ENXIO; + goto out_ioremap; + } + + sram_mtd->module = THIS_MODULE; + sram_mtd->erasesize = 16; + + if (add_mtd_device(sram_mtd)) { + printk("NV-RAM device addition failed\n"); + err = -ENOMEM; + goto out_probe; + } + + printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); + + return 0; + +out_probe: + map_destroy(sram_mtd); + sram_mtd = 0; + +out_ioremap: + iounmap((void *)autcpu12_sram_map.map_priv_1); +out: + return err; +} + +static void __exit cleanup_autcpu12_maps(void) +{ + if (sram_mtd) { + del_mtd_device(sram_mtd); + map_destroy(sram_mtd); + iounmap((void *)autcpu12_sram_map.map_priv_1); + } +} + +module_init(init_autcpu12_sram); +module_exit(cleanup_autcpu12_maps); + +MODULE_AUTHOR("Thomas Gleixner"); +MODULE_DESCRIPTION("autcpu12 NV-RAM map driver"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/mtd/maps/dc21285.c linux-2.4.19-pre5/drivers/mtd/maps/dc21285.c --- linux-2.4.18/drivers/mtd/maps/dc21285.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/dc21285.c Sat Mar 30 22:55:39 2002 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: dc21285.c,v 1.7 2001/10/11 16:17:51 nico Exp $ */ #include @@ -44,15 +44,15 @@ void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; + *CSR_ROMWRITEREG = adr & 3; adr &= ~3; *(__u8*)(map->map_priv_1 + adr) = d; } void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; - adr &= ~1; + *CSR_ROMWRITEREG = adr & 3; + adr &= ~3; *(__u16*)(map->map_priv_1 + adr) = d; } diff -urN linux-2.4.18/drivers/mtd/maps/dilnetpc.c linux-2.4.19-pre5/drivers/mtd/maps/dilnetpc.c --- linux-2.4.18/drivers/mtd/maps/dilnetpc.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/dilnetpc.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,540 @@ +/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP" + * + * 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 + * + * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $ + * + * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems + * featuring the AMD Elan SC410 processor. There are two variants of this + * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash + * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs + * flash and 16 megs of RAM. + * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + * and http://www.ssv-embedded.de/ssv/pc104/p170.htm + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +** The DIL/NetPC keeps it's BIOS in two distinct flash blocks. +** Destroying any of these blocks transforms the DNPC into +** a paperweight (albeit not a very useful one, considering +** it only weighs a few grams). +** +** Therefore, the BIOS blocks must never be erased or written to +** except by people who know exactly what they are doing (e.g. +** to install a BIOS update). These partitions are marked read-only +** by default, but can be made read/write by undefining +** DNPC_BIOS_BLOCKS_WRITEPROTECTED: +*/ +#define DNPC_BIOS_BLOCKS_WRITEPROTECTED + +/* +** The ID string (in ROM) is checked to determine whether we +** are running on a DNP/1486 or ADNP/1486 +*/ +#define BIOSID_BASE 0x000fe100 + +#define ID_DNPC "DNP1486" +#define ID_ADNP "ADNP1486" + +/* +** Address where the flash should appear in CPU space +*/ +#define FLASH_BASE 0x2000000 + +/* +** Chip Setup and Control (CSC) indexed register space +*/ +#define CSC_INDEX 0x22 +#define CSC_DATA 0x23 + +#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */ +#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */ + +#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */ + +#define CSC_CR 0xd0 /* internal I/O device disable/Echo */ + /* Z-bus/configuration register */ + +#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */ + + +/* +** PC Card indexed register space: +*/ + +#define PCC_INDEX 0x3e0 +#define PCC_DATA 0x3e1 + +#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */ +#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */ +#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */ +#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */ +#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */ +#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */ +#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */ + + +/* +** Access to SC4x0's Chip Setup and Control (CSC) +** and PC Card (PCC) indexed registers: +*/ +static inline void setcsc(int reg, unsigned char data) +{ + outb(reg, CSC_INDEX); + outb(data, CSC_DATA); +} + +static inline unsigned char getcsc(int reg) +{ + outb(reg, CSC_INDEX); + return(inb(CSC_DATA)); +} + +static inline void setpcc(int reg, unsigned char data) +{ + outb(reg, PCC_INDEX); + outb(data, PCC_DATA); +} + +static inline unsigned char getpcc(int reg) +{ + outb(reg, PCC_INDEX); + return(inb(PCC_DATA)); +} + + +/* +************************************************************ +** Enable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size) +{ + unsigned long flash_end = flash_base + flash_size - 1; + + /* + ** enable setup of MMS windows C-F: + */ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + /* - set PC Card controller to operate in standard mode */ + setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1); + + /* + ** Program base address and end address of window + ** where the flash ROM should appear in CPU address space + */ + setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff); + setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f); + setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff); + setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f); + + /* program offset of first flash location to appear in this window (0) */ + setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff); + setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f); + + /* set attributes for MMS window C: non-cacheable, write-enabled */ + setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11); + + /* select physical device ROMCS0 (i.e. flash) for MMS Window C */ + setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03); + + /* enable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +/* +************************************************************ +** Disable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_unmap_flash(void) +{ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + + /* disable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +static __u8 dnpc_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +static __u16 dnpc_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +static __u32 dnpc_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +/* +************************************************************ +** Enable/Disable VPP to write to flash +************************************************************ +*/ + +static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED; +static int vpp_counter = 0; +/* +** This is what has to be done for the DNP board .. +*/ +static void dnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + +/* +** .. and this the ADNP version: +*/ +static void adnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + + + +#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ +#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ +#define WINDOW_ADDR FLASH_BASE + +static struct map_info dnpc_map = { + name: "ADNP Flash Bank", + size: ADNP_WINDOW_SIZE, + buswidth: 1, + read8: dnpc_read8, + read16: dnpc_read16, + read32: dnpc_read32, + copy_from: dnpc_copy_from, + write8: dnpc_write8, + write16: dnpc_write16, + write32: dnpc_write32, + copy_to: dnpc_copy_to, + set_vpp: adnp_set_vpp, + map_priv_2: WINDOW_ADDR +}; + +/* +** The layout of the flash is somewhat "strange": +** +** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data +** 2. 64 KiB (1 block) : System BIOS +** 3. 960 KiB (15 blocks) : User Data (DNP model) or +** 3. 3008 KiB (47 blocks) : User Data (ADNP model) +** 4. 64 KiB (1 block) : System BIOS Entry +*/ + +static struct mtd_partition partition_info[]= +{ + { + name: "ADNP boot", + offset: 0, + size: 0xf0000, + }, + { + name: "ADNP system BIOS", + offset: MTDPART_OFS_NXTBLK, + size: 0x10000, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, + { + name: "ADNP file system", + offset: MTDPART_OFS_NXTBLK, + size: 0x2f0000, + }, + { + name: "ADNP system BIOS entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) + +static struct mtd_info *mymtd; +static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; +static struct mtd_info *merged_mtd; + +/* +** "Highlevel" partition info: +** +** Using the MTD concat layer, we can re-arrange partitions to our +** liking: we construct a virtual MTD device by concatenating the +** partitions, specifying the sequence such that the boot block +** is immediately followed by the filesystem block (i.e. the stupid +** system BIOS block is mapped to a different place). When re-partitioning +** this concatenated MTD device, we can set the boot block size to +** an arbitrary (though erase block aligned) value i.e. not one that +** is dictated by the flash's physical layout. We can thus set the +** boot block to be e.g. 64 KB (which is fully sufficient if we want +** to boot an etherboot image) or to -say- 1.5 MB if we want to boot +** a large kernel image. In all cases, the remainder of the flash +** is available as file system space. +*/ + +static struct mtd_partition higlvl_partition_info[]= +{ + { + name: "ADNP boot block", + offset: 0, + size: CONFIG_MTD_DILNETPC_BOOTSIZE, + }, + { + name: "ADNP file system space", + offset: MTDPART_OFS_NXTBLK, + size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + }, + { + name: "ADNP system BIOS + BIOS Entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0])) + + +static int dnp_adnp_probe(void) +{ + char *biosid, rc = -1; + + biosid = (char*)ioremap(BIOSID_BASE, 16); + if(biosid) + { + if(!strcmp(biosid, ID_DNPC)) + rc = 1; /* this is a DNPC */ + else if(!strcmp(biosid, ID_ADNP)) + rc = 0; /* this is a ADNPC */ + } + iounmap((void *)biosid); + return(rc); +} + + +static int __init init_dnpc(void) +{ + int is_dnp; + + /* + ** determine hardware (DNP/ADNP/invalid) + */ + if((is_dnp = dnp_adnp_probe()) < 0) + return -ENXIO; + + /* + ** Things are set up for ADNP by default + ** -> modify all that needs to be different for DNP + */ + if(is_dnp) + { /* + ** Adjust window size, select correct set_vpp function. + ** The partitioning scheme is identical on both DNP + ** and ADNP except for the size of the third partition. + */ + int i; + dnpc_map.size = DNP_WINDOW_SIZE; + dnpc_map.set_vpp = dnp_set_vpp; + partition_info[2].size = 0xf0000; + + /* + ** increment all string pointers so the leading 'A' gets skipped, + ** thus turning all occurrences of "ADNP ..." into "DNP ..." + */ + ++dnpc_map.name; + for(i = 0; i < NUM_PARTITIONS; i++) + ++partition_info[i].name; + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; + for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) + ++higlvl_partition_info[i].name; + } + + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2); + + dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size); + + dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size); + + if (!dnpc_map.map_priv_1) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + + printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1); + + mymtd = do_map_probe("jedec_probe", &dnpc_map); + + if (!mymtd) + mymtd = do_map_probe("cfi_probe", &dnpc_map); + + /* + ** If flash probes fail, try to make flashes accessible + ** at least as ROM. Ajust erasesize in this case since + ** the default one (128M) will break our partitioning + */ + if (!mymtd) + if((mymtd = do_map_probe("map_rom", &dnpc_map))) + mymtd->erasesize = 0x10000; + + if (!mymtd) { + iounmap((void *)dnpc_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* + ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() + ** -> add_mtd_partitions() will _not_ register MTD devices for + ** the partitions, but will instead store pointers to the MTD + ** objects it creates into our lowlvl_parts[] array. + ** NOTE: we arrange the pointers such that the sequence of the + ** partitions gets re-arranged: partition #2 follows + ** partition #0. + */ + partition_info[0].mtdp = &lowlvl_parts[0]; + partition_info[1].mtdp = &lowlvl_parts[2]; + partition_info[2].mtdp = &lowlvl_parts[1]; + partition_info[3].mtdp = &lowlvl_parts[3]; + + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + + /* + ** now create a virtual MTD device by concatenating the for partitions + ** (in the sequence given by the lowlvl_parts[] array. + */ + merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated"); + if(merged_mtd) + { /* + ** now partition the new device the way we want it. This time, + ** we do not supply mtd pointers in higlvl_partition_info, so + ** add_mtd_partitions() will register the devices. + */ + add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS); + } + + return 0; +} + +static void __exit cleanup_dnpc(void) +{ + if(merged_mtd) { + del_mtd_partitions(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (dnpc_map.map_priv_1) { + iounmap((void *)dnpc_map.map_priv_1); + dnpc_unmap_flash(); + dnpc_map.map_priv_1 = 0; + } +} + +module_init(init_dnpc); +module_exit(cleanup_dnpc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); +MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP"); diff -urN linux-2.4.18/drivers/mtd/maps/elan-104nc.c linux-2.4.19-pre5/drivers/mtd/maps/elan-104nc.c --- linux-2.4.18/drivers/mtd/maps/elan-104nc.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/mtd/maps/elan-104nc.c Sat Mar 30 22:55:39 2002 @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.13 2002/02/13 15:30:20 dwmw2 Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. diff -urN linux-2.4.18/drivers/mtd/maps/epxa10db-flash.c linux-2.4.19-pre5/drivers/mtd/maps/epxa10db-flash.c --- linux-2.4.18/drivers/mtd/maps/epxa10db-flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/epxa10db-flash.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,219 @@ +/* + * Flash memory access on EPXA based devices + * + * (C) 2000 Nicolas Pitre + * Copyright (C) 2001 Altera Corporation + * Copyright (C) 2001 Red Hat, Inc. + * + * $Id: epxa10db-flash.c,v 1.2 2001/12/19 13:00:19 jskov Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int nr_parts = 0; +static struct mtd_partition *parts; + +static struct mtd_info *mymtd; + +extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); +static int epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +static __u8 epxa10db_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 epxa10db_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 epxa10db_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void epxa10db_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void epxa10db_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa10db_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + + + +static struct map_info epxa10db_map = { + name: "EPXA10DB flash", + size: FLASH_SIZE, + buswidth: 2, + read8: epxa10db_read8, + read16: epxa10db_read16, + read32: epxa10db_read32, + copy_from: epxa10db_copy_from, + write8: epxa10db_write8, + write16: epxa10db_write16, + write32: epxa10db_write32, + copy_to: epxa10db_copy_to +}; + + +static int __init epxa10db_mtd_init(void) +{ + int i; + printk(KERN_NOTICE "Epxa10db flash device: %x at %x\n", FLASH_SIZE, FLASH_START); + epxa10db_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!epxa10db_map.map_priv_1) { + printk("Failed to ioremap Epxa10db flash\n"); + return -EIO; + } + + mymtd = do_map_probe("cfi_probe", &epxa10db_map); + if (!mymtd) { + iounmap((void *)epxa10db_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* Unlock the flash device. */ + for (i=0; inumeraseregions;i++){ + int j; + for(j=0;jeraseregions[i].numblocks;j++){ + mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,4); + } + } + +#ifdef CONFIG_MTD_REDBOOT_PARTS + nr_parts = parse_redboot_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif +#ifdef CONFIG_MTD_AFS_PARTS + nr_parts = parse_afs_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif + + /* No recognised partitioning schemes found - use defaults */ + nr_parts = epxa10db_default_partitions(mymtd, &parts); + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } + + /* If all else fails... */ + add_mtd_device(mymtd); + return 0; +} + +static void __exit epxa10db_mtd_cleanup(void) +{ + if (mymtd) { + if (nr_parts) + del_mtd_partitions(mymtd); + else + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (epxa10db_map.map_priv_1) { + iounmap((void *)epxa10db_map.map_priv_1); + epxa10db_map.map_priv_1 = 0; + } +} + + +/* + * This will do for now, once we decide which bootldr we're finally + * going to use then we'll remove this function and do it properly + * + * Partions are currently (as offsets from base of flash): + * 0x00000000 - 0x003FFFFF - bootloader (!) + * 0x00400000 - 0x00FFFFFF - Flashdisk + */ + +static int __init epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) +{ + struct mtd_partition *parts; + int ret, i; + int npartitions = 0; + char *names; + const char *name = "jffs"; + + printk("Using default partitions for epxa10db\n"); + npartitions=1; + parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); + if (!parts) { + ret = -ENOMEM; + goto out; + } + i=0; + names = (char *)&parts[npartitions]; + parts[i].name = names; + names += strlen(name) + 1; + strcpy(parts[i].name, name); + + parts[i].size = FLASH_SIZE-0x00400000; + parts[i].offset = 0x00400000; + parts[i].mask_flags = 0; + + out: + *pparts = parts; + return npartitions; +} + +module_init(epxa10db_mtd_init); +module_exit(epxa10db_mtd_cleanup); + +MODULE_AUTHOR("Clive Davies"); +MODULE_DESCRIPTION("Altera epxa10db mtd flash map"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/mtd/maps/ich2rom.c linux-2.4.19-pre5/drivers/mtd/maps/ich2rom.c --- linux-2.4.18/drivers/mtd/maps/ich2rom.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/ich2rom.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,302 @@ +/* + * ich2rom.c + * + * Normal mappings of chips in physical memory + * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESERVE_MEM_REGION 0 + +#define ICH2_FWH_REGION_START 0xFF000000UL +#define ICH2_FWH_REGION_SIZE 0x01000000UL +#define BIOS_CNTL 0x4e +#define FWH_DEC_EN1 0xE3 +#define FWH_DEC_EN2 0xF0 +#define FWH_SEL1 0xE8 +#define FWH_SEL2 0xEE + +struct ich2rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; +}; + +static inline unsigned long addr(struct map_info *map, unsigned long ofs) +{ + unsigned long offset; + offset = ((8*1024*1024) - map->size) + ofs; + if (offset >= (4*1024*1024)) { + offset += 0x400000; + } + return map->map_priv_1 + 0x400000 + offset; +} + +static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) +{ + return addr - map->map_priv_1 + ICH2_FWH_REGION_START; +} + +static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(addr(map, ofs)); +} + +static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(addr(map, ofs)); +} + +static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(addr(map, ofs)); +} + +static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, addr(map, from), len); +} + +static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + __raw_writeb(d, addr(map,ofs)); + mb(); +} + +static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs) +{ + __raw_writew(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs) +{ + __raw_writel(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(addr(map, to), from, len); +} + +static struct ich2rom_map_info ich2rom_map = { + map: { + name: "ICH2 rom", + size: 0, + buswidth: 1, + read8: ich2rom_read8, + read16: ich2rom_read16, + read32: ich2rom_read32, + copy_from: ich2rom_copy_from, + write8: ich2rom_write8, + write16: ich2rom_write16, + write32: ich2rom_write32, + copy_to: ich2rom_copy_to, + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in place programming + * needs to use a different method. + */ + }, + mtd: 0, + window_addr: 0, +}; + +enum fwh_lock_state { + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, + enum fwh_lock_state state) +{ + struct map_info *map = mtd->priv; + unsigned long start = ofs; + unsigned long end = start + len -1; + + /* FIXME do I need to guard against concurrency here? */ + /* round down to 64K boundaries */ + start = start & ~0xFFFF; + end = end & ~0xFFFF; + while (start <= end) { + unsigned long ctrl_addr; + ctrl_addr = addr(map, start) - 0x400000 + 2; + writeb(state, ctrl_addr); + start = start + 0x10000; + } + return 0; +} + +static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); +} + +static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, 0); +} + +static int __devinit ich2rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u16 word; + struct ich2rom_map_info *info = &ich2rom_map; + unsigned long map_size; + + /* For now I just handle the ich2 and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MB but it is very painful. Also since + * you can only really attach a FWH to an ICH2 there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MB window isn't enough + * but don't currently handle that case either. + */ + +#if RESERVE_MEM_REGION + /* Some boards have this reserved and I haven't found a good work + * around to say I know what I'm doing! + */ + if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) { + printk(KERN_ERR "ich2rom: cannot reserve rom window\n"); + goto err_out_none; + } +#endif /* RESERVE_MEM_REGION */ + + /* Enable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + if (!(word & 1) && (word & (1<<1))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n"); + goto err_out_none; + } + pci_write_config_word(pdev, BIOS_CNTL, word | 1); + + + /* Map the firmware hub into my address space. */ + /* Does this use to much virtual address space? */ + info->window_addr = (unsigned long)ioremap( + ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + + /* For now assume the firmware has setup all relavent firmware + * windows. We don't have enough information to handle this case + * intelligently. + */ + + /* FIXME select the firmware hub and enable a window to it. */ + + info->mtd = 0; + info->map.map_priv_1 = info->window_addr; + + map_size = ICH2_FWH_REGION_SIZE; + while(!info->mtd && (map_size > 0)) { + info->map.size = map_size; + info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map); + map_size -= 512*1024; + } + if (!info->mtd) { + goto err_out_iounmap; + } + /* I know I can only be a firmware hub here so put + * in the special lock and unlock routines. + */ + info->mtd->lock = ich2rom_lock; + info->mtd->unlock = ich2rom_unlock; + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +err_out_none: + return -ENODEV; +} + + +static void __devexit ich2rom_remove_one (struct pci_dev *pdev) +{ + struct ich2rom_map_info *info = &ich2rom_map; + u16 word; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + pci_write_config_word(pdev, BIOS_CNTL, word & ~1); + +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +} + +static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl); + +#if 0 +static struct pci_driver ich2rom_driver = { + name: "ich2rom", + id_table: ich2rom_pci_tbl, + probe: ich2rom_init_one, + remove: ich2rom_remove_one, +}; +#endif + +static struct pci_dev *mydev; +int __init init_ich2rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0); + if (pdev) { + mydev = pdev; + return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&ich2rom_driver); +#endif +} + +static void __exit cleanup_ich2rom(void) +{ + ich2rom_remove_one(mydev); +} + +module_init(init_ich2rom); +module_exit(cleanup_ich2rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge"); diff -urN linux-2.4.18/drivers/mtd/maps/integrator-flash.c linux-2.4.19-pre5/drivers/mtd/maps/integrator-flash.c --- linux-2.4.18/drivers/mtd/maps/integrator-flash.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/integrator-flash.c Sat Mar 30 22:55:39 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $ + $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ ======================================================================*/ @@ -208,10 +208,10 @@ }; static struct mtd_info *mtd; +static struct mtd_partition *parts; static int __init armflash_cfi_init(void *base, u_int size) { - struct mtd_partition *parts; int ret; armflash_flash_init(); @@ -238,8 +238,6 @@ ret = parse_afs_partitions(mtd, &parts); if (ret > 0) { ret = add_mtd_partitions(mtd, parts, ret); - /* we don't need the partition info any longer */ - kfree(parts); if (ret) printk(KERN_ERR "mtd partition registration " "failed: %d\n", ret); @@ -262,6 +260,8 @@ del_mtd_partitions(mtd); map_destroy(mtd); } + if (parts) + kfree(parts); } static int __init armflash_init(void) diff -urN linux-2.4.18/drivers/mtd/maps/iq80310.c linux-2.4.19-pre5/drivers/mtd/maps/iq80310.c --- linux-2.4.18/drivers/mtd/maps/iq80310.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/iq80310.c Sat Mar 30 22:55:39 2002 @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -116,7 +116,7 @@ int parsed_nr_parts = 0; char *part_type = "static"; - iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); + iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!iq80310_map.map_priv_1) { printk("Failed to ioremap\n"); return -EIO; @@ -161,7 +161,6 @@ } if (iq80310_map.map_priv_1) iounmap((void *)iq80310_map.map_priv_1); - return 0; } module_init(init_iq80310); diff -urN linux-2.4.18/drivers/mtd/maps/l440gx.c linux-2.4.19-pre5/drivers/mtd/maps/l440gx.c --- linux-2.4.18/drivers/mtd/maps/l440gx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/l440gx.c Sat Mar 30 22:55:39 2002 @@ -1,7 +1,9 @@ /* - * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $ * * BIOS Flash chip on Intel 440GX board. + * + * Bugs this currently does not work under linuxBIOS. */ #include @@ -12,12 +14,14 @@ #include #include +#define PIIXE_IOBASE_RESOURCE 11 #define WINDOW_ADDR 0xfff00000 #define WINDOW_SIZE 0x00100000 #define BUSWIDTH 1 -#define IOBASE 0xc00 +static u32 iobase; +#define IOBASE iobase #define TRIBUF_PORT (IOBASE+0x37) #define VPP_PORT (IOBASE+0x28) @@ -66,12 +70,17 @@ memcpy_toio(map->map_priv_1 + to, from, len); } +/* Is this really the vpp port? */ void l440gx_set_vpp(struct map_info *map, int vpp) { unsigned long l; l = inl(VPP_PORT); - l = vpp?(l | 1):(l & ~1); + if (vpp) { + l |= 1; + } else { + l &= ~1; + } outl(l, VPP_PORT); } @@ -87,44 +96,86 @@ write16: l440gx_write16, write32: l440gx_write32, copy_to: l440gx_copy_to, +#if 0 + /* FIXME verify that this is the + * appripriate code for vpp enable/disable + */ set_vpp: l440gx_set_vpp +#endif }; static int __init init_l440gx(void) { - struct pci_dev *dev; - unsigned char b; - __u16 w; + struct pci_dev *dev, *pm_dev; + struct resource *pm_iobase; + __u16 word; + + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - NULL); - if (!dev) { + pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + + if (!dev || !pm_dev) { printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n"); return -ENODEV; } - l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); if (!l440gx_map.map_priv_1) { - printk("Failed to ioremap L440GX flash region\n"); + printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); return -ENOMEM; } + printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1); + + /* Setup the pm iobase resource + * This code should move into some kind of generic bridge + * driver but for the moment I'm content with getting the + * allocation correct. + */ + pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; + if (!(pm_iobase->flags & IORESOURCE_IO)) { + pm_iobase->name = "pm iobase"; + pm_iobase->start = 0; + pm_iobase->end = 63; + pm_iobase->flags = IORESOURCE_IO; + + /* Put the current value in the resource */ + pci_read_config_dword(pm_dev, 0x40, &iobase); + iobase &= ~1; + pm_iobase->start += iobase & ~1; + pm_iobase->end += iobase & ~1; + + /* Allocate the resource region */ + if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { + printk(KERN_WARNING "Could not allocate pm iobase resource\n"); + iounmap((void *)l440gx_map.map_priv_1); + return -ENXIO; + } + } + /* Set the iobase */ + iobase = pm_iobase->start; + pci_write_config_dword(pm_dev, 0x40, iobase | 1); + + /* Set XBCS# */ - pci_read_config_word(dev, 0x4e, &w); - w |= 0x4; - pci_write_config_word(dev, 0x4e, w); + pci_read_config_word(dev, 0x4e, &word); + word |= 0x4; + pci_write_config_word(dev, 0x4e, word); + + /* Supply write voltage to the chip */ + l440gx_set_vpp(&l440gx_map, 1); /* Enable the gate on the WE line */ - b = inb(TRIBUF_PORT); - b |= 1; - outb(b, TRIBUF_PORT); + outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); - mymtd = do_map_probe("jedec", &l440gx_map); + mymtd = do_map_probe("jedec_probe", &l440gx_map); if (!mymtd) { printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n"); mymtd = do_map_probe("map_rom", &l440gx_map); diff -urN linux-2.4.18/drivers/mtd/maps/mbx860.c linux-2.4.19-pre5/drivers/mtd/maps/mbx860.c --- linux-2.4.18/drivers/mtd/maps/mbx860.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/mbx860.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,144 @@ +/* + * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $ + * + * Handle mapping of the flash on MBX860 boards + * + * Author: Anton Todorov + * Copyright: (C) 2001 Emness Technology + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x00200000 + +/* Flash / Partition sizing */ +#define MAX_SIZE_KiB 8192 +#define BOOT_PARTITION_SIZE_KiB 512 +#define KERNEL_PARTITION_SIZE_KiB 5632 +#define APP_PARTITION_SIZE_KiB 2048 + +#define NUM_PARTITIONS 3 + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]={ + { name: "MBX flash BOOT partition", + offset: 0, + size: BOOT_PARTITION_SIZE_KiB*1024 }, + { name: "MBX flash DATA partition", + offset: BOOT_PARTITION_SIZE_KiB*1024, + size: (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { name: "MBX flash APPLICATION partition", + offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } +}; + + +static struct mtd_info *mymtd; + +__u8 mbx_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +__u16 mbx_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +__u32 mbx_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +void mbx_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +void mbx_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +void mbx_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +struct map_info mbx_map = { + name: "MBX flash", + size: WINDOW_SIZE, + buswidth: 4, + read8: mbx_read8, + read16: mbx_read16, + read32: mbx_read32, + copy_from: mbx_copy_from, + write8: mbx_write8, + write16: mbx_write16, + write32: mbx_write32, + copy_to: mbx_copy_to +}; + +int __init init_mbx(void) +{ + printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!mbx_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("jedec_probe", &mbx_map); + if (mymtd) { + mymtd->module = THIS_MODULE; + add_mtd_device(mymtd); + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)mbx_map.map_priv_1); + return -ENXIO; +} + +static void __exit cleanup_mbx(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (mbx_map.map_priv_1) { + iounmap((void *)mbx_map.map_priv_1); + mbx_map.map_priv_1 = 0; + } +} + +module_init(init_mbx); +module_exit(cleanup_mbx); + +MODULE_AUTHOR("Anton Todorov "); +MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.19-pre5/drivers/mtd/maps/pb1xxx-flash.c --- linux-2.4.18/drivers/mtd/maps/pb1xxx-flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/pb1xxx-flash.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,253 @@ +/* + * Flash memory access on Alchemy Pb1xxx boards + * + * (C) 2001 Pete Popov + * + * $Id: pb1xxx-flash.c,v 1.2 2002/02/14 19:36:45 ppopov Exp $ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define WINDOW_ADDR 0x1F800000 +#define WINDOW_SIZE 0x800000 +#endif + +__u8 physmap_read8(struct map_info *map, unsigned long ofs) +{ + __u8 ret; + ret = __raw_readb(map->map_priv_1 + ofs); + DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u16 physmap_read16(struct map_info *map, unsigned long ofs) +{ + __u16 ret; + ret = __raw_readw(map->map_priv_1 + ofs); + DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u32 physmap_read32(struct map_info *map, unsigned long ofs) +{ + __u32 ret; + ret = __raw_readl(map->map_priv_1 + ofs); + DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); + memcpy_toio(map->map_priv_1 + to, from, len); +} + + + +static struct map_info pb1xxx_map = { + name: "Pb1xxx flash", + read8: physmap_read8, + read16: physmap_read16, + read32: physmap_read32, + copy_from: physmap_copy_from, + write8: physmap_write8, + write16: physmap_write16, + write32: physmap_write32, + copy_to: physmap_copy_to, +}; + + +#ifdef CONFIG_MIPS_PB1000 + +static unsigned long flash_size = 0x00800000; +static unsigned char flash_buswidth = 4; +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "yamon env", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE + },{ + name: "User FS", + size: 0x003e0000, + offset: 0x20000, + },{ + name: "boot code", + size: 0x100000, + offset: 0x400000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw/kernel", + size: 0x300000, + offset: 0x500000 + } +}; + +#elif defined(CONFIG_MIPS_PB1500) + +static unsigned char flash_buswidth = 4; +#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +/* both 32MB banks will be used. Combine the first 32MB bank and the + * first 28MB of the second bank together into a single jffs/jffs2 + * partition. + */ +static unsigned long flash_size = 0x04000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x4000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x3c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x3c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x3d00000 + } +}; +#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1E000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x1c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x1d00000 + } +}; +#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1e00000, + offset: 0x0000000 + },{ + name: "raw kernel", + size: 0x0200000, + offset: 0x1e00000, + } +}; +#else +#error MTD_PB1500 define combo error /* should never happen */ +#endif +#else +#error Unsupported board +#endif + + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_partition *parsed_parts; +static struct mtd_info *mymtd; + +int __init pb1xxx_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type; + + /* Default flash buswidth */ + pb1xxx_map.buswidth = flash_buswidth; + + /* + * Static partition definition selection + */ + part_type = "static"; + parts = pb1xxx_partitions; + nb_parts = NB_OF(pb1xxx_partitions); + pb1xxx_map.size = flash_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", + pb1xxx_map.buswidth*8); + pb1xxx_map.map_priv_1 = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + mymtd = do_map_probe("cfi_probe", &pb1xxx_map); + if (!mymtd) return -ENXIO; + mymtd->module = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit pb1xxx_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(pb1xxx_mtd_init); +module_exit(pb1xxx_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Pb1xxx CFI map driver"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/mtd/maps/pci.c linux-2.4.19-pre5/drivers/mtd/maps/pci.c --- linux-2.4.18/drivers/mtd/maps/pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/pci.c Sat Mar 30 22:55:39 2002 @@ -0,0 +1,385 @@ +/* + * linux/drivers/mtd/maps/pci.c + * + * Copyright (C) 2001 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $ + * + * Generic PCI memory map driver. We support the following boards: + * - Intel IQ80310 ATU. + * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 + */ +#include +#include +#include +#include + +#include +#include +#include + +struct map_pci_info; + +struct mtd_pci_info { + int (*init)(struct pci_dev *dev, struct map_pci_info *map); + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + const char *map_name; +}; + +struct map_pci_info { + struct map_info map; + void *base; + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + struct pci_dev *dev; +}; + +/* + * Intel IOP80310 Flash driver + */ + +static int +intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 win_base; + + map->map.buswidth = 1; + map->map.size = 0x00800000; + map->base = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); + + if (!map->base) + return -ENOMEM; + + /* + * We want to base the memory window at Xscale + * bus address 0, not 0x1000. + */ + pci_read_config_dword(dev, 0x44, &win_base); + pci_write_config_dword(dev, 0x44, 0); + + map->map.map_priv_2 = win_base; + + return 0; +} + +static void +intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + if (map->base) + iounmap((void *)map->base); + pci_write_config_dword(dev, 0x44, map->map.map_priv_2); +} + +static unsigned long +intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs) +{ + unsigned long page_addr = ofs & 0x00400000; + + /* + * This mundges the flash location so we avoid + * the first 80 bytes (they appear to read nonsense). + */ + if (page_addr) { + writel(0x00000008, map->base + 0x1558); + writel(0x00000000, map->base + 0x1550); + } else { + writel(0x00000007, map->base + 0x1558); + writel(0x00800000, map->base + 0x1550); + ofs += 0x00800000; + } + + return ofs; +} + +static struct mtd_pci_info intel_iq80310_info = { + init: intel_iq80310_init, + exit: intel_iq80310_exit, + translate: intel_iq80310_translate, + map_name: "cfi_probe", +}; + +/* + * Intel DC21285 driver + */ + +static int +intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) +{ + unsigned long base, len; + + base = pci_resource_start(dev, PCI_ROM_RESOURCE); + len = pci_resource_len(dev, PCI_ROM_RESOURCE); + + if (!len || !base) { + /* + * No ROM resource + */ + base = pci_resource_start(dev, 2); + len = pci_resource_len(dev, 2); + + /* + * We need to re-allocate PCI BAR2 address range to the + * PCI ROM BAR, and disable PCI BAR2. + */ + } else { + /* + * Hmm, if an address was allocated to the ROM resource, but + * not enabled, should we be allocating a new resource for it + * or simply enabling it? + */ + if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) & + PCI_ROM_ADDRESS_ENABLE)) { + u32 val; + pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); + printk("%s: enabling expansion ROM\n", dev->slot_name); + } + } + + if (!len || !base) + return -ENXIO; + + map->map.buswidth = 4; + map->map.size = len; + map->base = ioremap_nocache(base, len); + + if (!map->base) + return -ENOMEM; + + return 0; +} + +static void +intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 val; + + if (map->base) + iounmap((void *)map->base); + + /* + * We need to undo the PCI BAR2/PCI ROM BAR address alteration. + */ + pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); +} + +static unsigned long +intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs) +{ + return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5)); +} + +static struct mtd_pci_info intel_dc21285_info = { + init: intel_dc21285_init, + exit: intel_dc21285_exit, + translate: intel_dc21285_translate, + map_name: "jedec_probe", +}; + +/* + * PCI device ID table + */ + +static struct pci_device_id mtd_pci_ids[] __devinitdata = { + { + vendor: PCI_VENDOR_ID_INTEL, + device: 0x530d, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + class: PCI_CLASS_MEMORY_OTHER << 8, + class_mask: 0xffff00, + driver_data: (unsigned long)&intel_iq80310_info, + }, + { + vendor: PCI_VENDOR_ID_DEC, + device: PCI_DEVICE_ID_DEC_21285, + subvendor: 0, /* DC21285 defaults to 0 on reset */ + subdevice: 0, /* DC21285 defaults to 0 on reset */ + class: 0, + class_mask: 0, + driver_data: (unsigned long)&intel_dc21285_info, + }, + { 0, } +}; + +/* + * Generic code follows. + */ + +static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u8 val = readb(map->base + map->translate(map, ofs)); +// printk("read8 : %08lx => %02x\n", ofs, val); + return val; +} + +static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u16 val = readw(map->base + map->translate(map, ofs)); +// printk("read16: %08lx => %04x\n", ofs, val); + return val; +} + +static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u32 val = readl(map->base + map->translate(map, ofs)); +// printk("read32: %08lx => %08x\n", ofs, val); + return val; +} + +static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_fromio(to, map->base + map->translate(map, from), len); +} + +static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write8 : %08lx <= %02x\n", ofs, val); + writeb(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write16: %08lx <= %04x\n", ofs, val); + writew(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write32: %08lx <= %08x\n", ofs, val); + writel(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_toio(map->base + map->translate(map, to), from, len); +} + +static struct map_info mtd_pci_map = { + read8: mtd_pci_read8, + read16: mtd_pci_read16, + read32: mtd_pci_read32, + copy_from: mtd_pci_copyfrom, + write8: mtd_pci_write8, + write16: mtd_pci_write16, + write32: mtd_pci_write32, + copy_to: mtd_pci_copyto, +}; + +static int __devinit +mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; + struct map_pci_info *map = NULL; + struct mtd_info *mtd = NULL; + int err; + + err = pci_enable_device(dev); + if (err) + goto out; + + err = pci_request_regions(dev, "pci mtd"); + if (err) + goto out; + + map = kmalloc(sizeof(*map), GFP_KERNEL); + err = -ENOMEM; + if (!map) + goto release; + + map->map = mtd_pci_map; + map->map.name = dev->slot_name; + map->dev = dev; + map->exit = info->exit; + map->translate = info->translate; + + err = info->init(dev, map); + if (err) + goto release; + + /* tsk - do_map_probe should take const char * */ + mtd = do_map_probe((char *)info->map_name, &map->map); + err = -ENODEV; + if (!mtd) + goto release; + + mtd->module = THIS_MODULE; + add_mtd_device(mtd); + + pci_set_drvdata(dev, mtd); + + return 0; + +release: + if (mtd) + map_destroy(mtd); + + if (map) { + map->exit(dev, map); + kfree(map); + } + + pci_release_regions(dev); +out: + return err; +} + +static void __devexit +mtd_pci_remove(struct pci_dev *dev) +{ + struct mtd_info *mtd = pci_get_drvdata(dev); + struct map_pci_info *map = mtd->priv; + + del_mtd_device(mtd); + map_destroy(mtd); + map->exit(dev, map); + kfree(map); + + pci_set_drvdata(dev, NULL); + pci_release_regions(dev); +} + +static struct pci_driver mtd_pci_driver = { + name: "MTD PCI", + probe: mtd_pci_probe, + remove: mtd_pci_remove, + id_table: mtd_pci_ids, +}; + +static int __init mtd_pci_maps_init(void) +{ + return pci_module_init(&mtd_pci_driver); +} + +static void __exit mtd_pci_maps_exit(void) +{ + pci_unregister_driver(&mtd_pci_driver); +} + +module_init(mtd_pci_maps_init); +module_exit(mtd_pci_maps_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Generic PCI map driver"); +MODULE_DEVICE_TABLE(pci, mtd_pci_ids); + diff -urN linux-2.4.18/drivers/mtd/maps/sa1100-flash.c linux-2.4.19-pre5/drivers/mtd/maps/sa1100-flash.c --- linux-2.4.18/drivers/mtd/maps/sa1100-flash.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/sa1100-flash.c Sat Mar 30 22:55:40 2002 @@ -3,12 +3,13 @@ * * (C) 2000 Nicolas Pitre * - * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $ + * $Id: sa1100-flash.c,v 1.26 2002/03/13 16:30:44 rmk Exp $ */ #include #include #include +#include #include #include @@ -66,32 +67,6 @@ memcpy((void *)(map->map_priv_1 + to), from, len); } - -#ifdef CONFIG_SA1100_H3600 - -static void h3600_set_vpp(struct map_info *map, int vpp) -{ - if (vpp) - set_h3600_egpio(EGPIO_H3600_VPP_ON); - else - clr_h3600_egpio(EGPIO_H3600_VPP_ON); -} - -#endif - -#ifdef CONFIG_SA1100_JORNADA720 - -static void jornada720_set_vpp(int vpp) -{ - if (vpp) - PPSR |= 0x80; - else - PPSR &= ~0x80; - PPDR |= 0x80; -} - -#endif - static struct map_info sa1100_map = { name: "SA1100 flash", read8: sa1100_read8, @@ -104,6 +79,7 @@ copy_to: sa1100_copy_to, map_priv_1: WINDOW_ADDR, + map_priv_2: -1, }; @@ -111,425 +87,687 @@ * Here are partition information for all known SA1100-based devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. - * + * * The *_max_flash_size is the maximum possible mapped flash size which - * is not necessarily the actual flash size. It must correspond to the - * value specified in the mapping definition defined by the - * "struct map_desc *_io_desc" for the corresponding machine. + * is not necessarily the actual flash size. It must be no more than + * the value specified in the "struct map_desc *_io_desc" mapping + * definition for the corresponding machine. + * + * Please keep these in alphabetical order, and formatted as per existing + * entries. Thanks. */ -#ifdef CONFIG_SA1100_ASSABET +#ifdef CONFIG_SA1100_ADSBITSY +#define ADSBITSY_FLASH_SIZE 0x02000000 +static struct mtd_partition adsbitsy_partitions[] = { + { + name: "bootROM", + size: 0x80000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "zImage", + size: 0x100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif +#ifdef CONFIG_SA1100_ASSABET /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ -static unsigned long assabet4_max_flash_size = 0x00400000; +#define ASSABET4_FLASH_SIZE 0x00400000 static struct mtd_partition assabet4_partitions[] = { - { - name: "bootloader", - size: 0x00020000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00020000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00020000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */ -static unsigned long assabet5_max_flash_size = 0x02000000; +#define ASSABET5_FLASH_SIZE 0x02000000 static struct mtd_partition assabet5_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; -#define assabet_max_flash_size assabet5_max_flash_size -#define assabet_partitions assabet5_partitions - +#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE +#define assabet_partitions assabet5_partitions #endif -#ifdef CONFIG_SA1100_FLEXANET +#ifdef CONFIG_SA1100_BADGE4 -/* Flexanet has two 28F128J3A flash parts in bank 0: */ -static unsigned long flexanet_max_flash_size = 0x02000000; -static struct mtd_partition flexanet_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "kernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "altkernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "root", - size: 0x00400000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free1", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free2", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free3", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - } +/* + * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit) + * Eight 4 KiW Parameter Bottom Blocks (64 KiB) + * Sixty-three 32 KiW Main Blocks (4032 Ki b) + */ +#define BADGE4_FLASH_SIZE 0x00400000 +static struct mtd_partition badge4_partitions[] = { + { + name: "BLOB boot loader", + offset: 0, + size: 0x0000A000 + }, { + name: "params", + offset: MTDPART_OFS_APPEND, + size: 0x00006000 + }, { + name: "kernel", + offset: MTDPART_OFS_APPEND, + size: 0x00100000 + }, { + name: "root", + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; #endif -#ifdef CONFIG_SA1100_HUW_WEBPANEL -static unsigned long huw_webpanel_max_flash_size = 0x01000000; -static struct mtd_partition huw_webpanel_partitions[] = { - { - name: "Loader", - size: 0x00040000, - offset: 0, - },{ - name: "Sector 1", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - },{ - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + +#ifdef CONFIG_SA1100_CERF +#ifdef CONFIG_SA1100_CERF_FLASH_32MB +#define CERF_FLASH_SIZE 0x02000000 +static struct mtd_partition cerf_partitions[] = { + { + name: "firmware", + size: 0x00040000, + offset: 0, + }, { + name: "params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "rootdisk", + size: 0x01E80000, + offset: 0x00180000, } }; -#endif /* CONFIG_SA1100_HUW_WEBPANEL */ - - -#ifdef CONFIG_SA1100_H3600 - -static unsigned long h3600_max_flash_size = 0x02000000; -static struct mtd_partition h3600_partitions[] = { +#elif defined CONFIG_SA1100_CERF_FLASH_16MB +#define CERF_FLASH_SIZE 0x01000000 +static struct mtd_partition cerf_partitions[] = { { - name: "H3600 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "H3600 kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "H3600 params", - size: 0x00040000, - offset: 0xC0000 - },{ -#ifdef CONFIG_JFFS2_FS - name: "H3600 root jffs2", - offset: 0x00100000, - size: MTDPART_SIZ_FULL + name: "firmware", + size: 0x00020000, + offset: 0, + }, { + name: "params", + size: 0x00020000, + offset: 0x00020000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00040000, + }, { + name: "rootdisk", + size: 0x00EC0000, + offset: 0x00140000, + } +}; +#elif defined CONFIG_SA1100_CERF_FLASH_8MB +# error "Unwritten type definition" #else - name: "H3600 initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "H3600 root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "H3600 usr cramfs", - size: 0x00800000, - offset: 0x00500000 - },{ - name: "H3600 usr local", - offset: 0x00d00000, - size: MTDPART_SIZ_FULL +# error "Undefined memory orientation for CERF in sa1100-flash.c" #endif +#endif + +#ifdef CONFIG_SA1100_CONSUS +#define CONSUS_FLASH_SIZE 0x02000000 +static struct mtd_partition consus_partitions[] = { + { + name: "Consus boot firmware", + offset: 0, + size: 0x00040000, + mask_flags: MTD_WRITABLE, /* force read-only */ + }, { + name: "Consus kernel", + offset: 0x00040000, + size: 0x00100000, + mask_flags: 0, + }, { + name: "Consus disk", + offset: 0x00140000, + /* The rest (up to 16M) for jffs. We could put 0 and + make it find the size automatically, but right now + i have 32 megs. jffs will use all 32 megs if given + the chance, and this leads to horrible problems + when you try to re-flash the image because blob + won't erase the whole partition. */ + size: 0x01000000 - 0x00140000, + mask_flags: 0, + }, { + /* this disk is a secondary disk, which can be used as + needed, for simplicity, make it the size of the other + consus partition, although realistically it could be + the remainder of the disk (depending on the file + system used) */ + name: "Consus disk2", + offset: 0x01000000, + size: 0x01000000 - 0x00140000, + mask_flags: 0, } }; +#endif +#ifdef CONFIG_SA1100_FLEXANET +/* Flexanet has two 28F128J3A flash parts in bank 0: */ +#define FLEXANET_FLASH_SIZE 0x02000000 +static struct mtd_partition flexanet_partitions[] = { + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "kernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "altkernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "root", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free1", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free2", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free3", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + } +}; #endif + #ifdef CONFIG_SA1100_FREEBIRD -static unsigned long freebird_max_flash_size = 0x02000000; +#define FREEBIRD_FLASH_SIZE 0x02000000 static struct mtd_partition freebird_partitions[] = { #if CONFIG_SA1100_FREEBIRD_NEW - { - name: "firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "params", - size: 0x00040000, - offset: 0xC0000 - },{ - name: "initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "usr cramfs", - size: 0x00C00000, - offset: 0x00500000 - },{ - name: "local", - offset: 0x01100000, - size: MTDPART_SIZ_FULL + { + name: "firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "params", + size: 0x00040000, + offset: 0x000C0000, + }, { + name: "initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "usr cramfs", + size: 0x00C00000, + offset: 0x00500000, + }, { + name: "local", + size: MTDPART_SIZ_FULL, + offset: 0x01100000, } #else - { offset: 0, size: 0x00040000, }, - { offset: MTDPART_OFS_APPEND, size: 0x000c0000, }, - { offset: MTDPART_OFS_APPEND, size: 0x00400000, }, - { offset: MTDPART_OFS_APPEND, size: MTDPART_SIZ_FULL } + { + size: 0x00040000, + offset: 0, + }, { + size: 0x000c0000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } #endif - }; +}; #endif - -#ifdef CONFIG_SA1100_CERF - -static unsigned long cerf_max_flash_size = 0x01000000; -static struct mtd_partition cerf_partitions[] = { - { offset: 0, size: 0x00800000 }, - { offset: MTDPART_OFS_APPEND, size: 0x00800000 } +#ifdef CONFIG_SA1100_FRODO +/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ +#define FRODO_FLASH_SIZE 0x02000000 +static struct mtd_partition frodo_partitions[] = +{ + { + name: "bootloader", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "ramdisk", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "file system", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT - -static unsigned long graphicsclient_max_flash_size = 0x01000000; +#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000 static struct mtd_partition graphicsclient_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 - }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 - }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER - -static unsigned long graphicsmaster_max_flash_size = 0x01000000; +#define GRAPHICSMASTER_FLASH_SIZE 0x01000000 static struct mtd_partition graphicsmaster_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 + { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; +#endif +#ifdef CONFIG_SA1100_H3600 +#define H3600_FLASH_SIZE 0x02000000 +static struct mtd_partition h3600_partitions[] = { + { + name: "H3600 boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "H3600 kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "H3600 params", + size: 0x00040000, + offset: 0x000C0000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "H3600 root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00100000, +#else + name: "H3600 initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "H3600 root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "H3600 usr cramfs", + size: 0x00800000, + offset: 0x00500000, + }, { + name: "H3600 usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d00000, #endif + } +}; -#ifdef CONFIG_SA1100_PANGOLIN +static void h3600_set_vpp(struct map_info *map, int vpp) +{ + assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp); +} +#endif -static unsigned long pangolin_max_flash_size = 0x04000000; -static struct mtd_partition pangolin_partitions[] = { - { - name: "boot firmware", - offset: 0x00000000, - size: 0x00080000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, - { - name: "kernel", - offset: 0x00080000, - size: 0x00100000, - }, +#ifdef CONFIG_SA1100_HUW_WEBPANEL +#define HUW_WEBPANEL_FLASH_SIZE 0x01000000 +static struct mtd_partition huw_webpanel_partitions[] = { { - name: "initrd", - offset: 0x00180000, - size: 0x00280000, - }, + name: "Loader", + size: 0x00040000, + offset: 0, + }, { + name: "Sector 1", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif + +#ifdef CONFIG_SA1100_JORNADA720 +#define JORNADA720_FLASH_SIZE 0x02000000 +static struct mtd_partition jornada720_partitions[] = { { - name: "initrd-test", - offset: 0x00400000, - size: 0x03C00000, + name: "JORNADA720 boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "JORNADA720 kernel", + size: 0x000c0000, + offset: 0x00040000, + }, { + name: "JORNADA720 params", + size: 0x00040000, + offset: 0x00100000, + }, { + name: "JORNADA720 initrd", + size: 0x00100000, + offset: 0x00140000, + }, { + name: "JORNADA720 root cramfs", + size: 0x00300000, + offset: 0x00240000, + }, { + name: "JORNADA720 usr cramfs", + size: 0x00800000, + offset: 0x00540000, + }, { + name: "JORNADA720 usr local", + size: 0 /* will expand to the end of the flash */ + offset: 0x00d00000, } }; +static void jornada720_set_vpp(int vpp) +{ + if (vpp) + PPSR |= 0x80; + else + PPSR &= ~0x80; + PPDR |= 0x80; +} + #endif -#ifdef CONFIG_SA1100_YOPY +#ifdef CONFIG_SA1100_PANGOLIN +#define PANGOLIN_FLASH_SIZE 0x04000000 +static struct mtd_partition pangolin_partitions[] = { + { + name: "boot firmware", + size: 0x00080000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00280000, + offset: 0x00180000, + }, { + name: "initrd-test", + size: 0x03C00000, + offset: 0x00400000, + } +}; +#endif -static unsigned long yopy_max_flash_size = 0x08000000; -static struct mtd_partition yopy_partitions[] = { +#ifdef CONFIG_SA1100_PT_SYSTEM3 +/* erase size is 0x40000 == 256k partitions have to have this boundary */ +#define SYSTEM3_FLASH_SIZE 0x01000000 +static struct mtd_partition system3_partitions[] = { + { + name: "BLOB", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "config", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + }, { + name: "root", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif + +#ifdef CONFIG_SA1100_SHANNON +#define SHANNON_FLASH_SIZE 0x00400000 +static struct mtd_partition shannon_partitions[] = { { - name: "boot firmware", - offset: 0x00000000, - size: 0x00040000, - mask_flags: MTD_WRITEABLE, /* force read-only */ + name: "BLOB boot loader", + offset: 0, + size: 0x20000 }, { name: "kernel", - offset: 0x00080000, - size: 0x00080000, + offset: MTDPART_OFS_APPEND, + size: 0xe0000 }, - { + { name: "initrd", - offset: 0x00100000, - size: 0x00300000, - }, - { - name: "root", - offset: 0x00400000, - size: 0x01000000, - }, + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; #endif -#ifdef CONFIG_SA1100_JORNADA720 - -static unsigned long jornada720_max_flash_size = 0x02000000; -static struct mtd_partition jornada720_partitions[] = { +#ifdef CONFIG_SA1100_SHERMAN +#define SHERMAN_FLASH_SIZE 0x02000000 +static struct mtd_partition sherman_partitions[] = { { - name: "JORNADA720 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "JORNADA720 kernel", - size: 0x000c0000, - offset: 0x40000 - },{ - name: "JORNADA720 params", - size: 0x00040000, - offset: 0x100000 - },{ - name: "JORNADA720 initrd", - size: 0x00100000, - offset: 0x00140000 - },{ - name: "JORNADA720 root cramfs", - size: 0x00300000, - offset: 0x00240000 - },{ - name: "JORNADA720 usr cramfs", - size: 0x00800000, - offset: 0x00540000 - },{ - name: "JORNADA720 usr local", - offset: 0x00d00000, - size: 0 /* will expand to the end of the flash */ + size: 0x50000, + offset: 0, + }, { + size: 0x70000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x600000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0xA0000, + offset: MTDPART_OFS_APPEND, } }; #endif -#ifdef CONFIG_SA1100_SHERMAN - -static unsigned long sherman_max_flash_size = 0x02000000; -static struct mtd_partition sherman_partitions[] = { - { offset: 0, size: 0x50000 }, - { offset: MTDPART_OFS_APPEND, size: 0x70000 }, - { offset: MTDPART_OFS_APPEND, size: 0x600000 }, - { offset: MTDPART_OFS_APPEND, size: 0xA0000 } -}; - +#ifdef CONFIG_SA1100_SIMPAD +#define SIMPAD_FLASH_SIZE 0x02000000 +static struct mtd_partition simpad_partitions[] = { + { + name: "SIMpad boot firmware", + size: 0x00080000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "SIMpad kernel", + size: 0x00100000, + offset: 0x00080000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "SIMpad root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00180000, +#else + name: "SIMpad initrd", + size: 0x00300000, + offset: 0x00180000, + }, { + name: "SIMpad root cramfs", + size: 0x00300000, + offset: 0x00480000, + }, { + name: "SIMpad usr cramfs", + size: 0x005c0000, + offset: 0x00780000, + }, { + name: "SIMpad usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d40000, #endif + } +}; +#endif /* CONFIG_SA1100_SIMPAD */ #ifdef CONFIG_SA1100_STORK - -static unsigned long stork_max_flash_size = 0x02000000; +#define STORK_FLASH_SIZE 0x02000000 static struct mtd_partition stork_partitions[] = { { - name: "STORK boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "STORK params", - size: 0x00040000, - offset: 0x40000 - },{ - name: "STORK kernel", - size: 0x00100000, - offset: 0x80000 - },{ + name: "STORK boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "STORK params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "STORK kernel", + size: 0x00100000, + offset: 0x00080000, + }, { #ifdef CONFIG_JFFS2_FS - name: "STORK root jffs2", - offset: 0x00180000, - size: MTDPART_SIZ_FULL + name: "STORK root jffs2", + offset: 0x00180000, + size: MTDPART_SIZ_FULL, #else - name: "STORK initrd", - size: 0x00100000, - offset: 0x00180000 - },{ - name: "STORK root cramfs", - size: 0x00300000, - offset: 0x00280000 - },{ - name: "STORK usr cramfs", - size: 0x00800000, - offset: 0x00580000 - },{ - name: "STORK usr local", - offset: 0x00d80000, - size: MTDPART_SIZ_FULL + name: "STORK initrd", + size: 0x00100000, + offset: 0x00180000, + }, { + name: "STORK root cramfs", + size: 0x00300000, + offset: 0x00280000, + }, { + name: "STORK usr cramfs", + size: 0x00800000, + offset: 0x00580000, + }, { + name: "STORK usr local", + offset: 0x00d80000, + size: MTDPART_SIZ_FULL, #endif } }; - #endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - +#ifdef CONFIG_SA1100_YOPY +#define YOPY_FLASH_SIZE 0x08000000 +static struct mtd_partition yopy_partitions[] = { + { + name: "boot firmware", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00300000, + offset: 0x00100000, + }, { + name: "root", + size: 0x01000000, + offset: 0x00400000, + } +}; +#endif extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); @@ -540,10 +778,11 @@ int __init sa1100_mtd_init(void) { struct mtd_partition *parts; - int nb_parts = 0; + int nb_parts = 0, ret; int parsed_nr_parts = 0; - char *part_type; - + const char *part_type; + unsigned long base = -1UL; + /* Default flash buswidth */ sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4; @@ -551,103 +790,166 @@ * Static partition definition selection */ part_type = "static"; + +#ifdef CONFIG_SA1100_ADSBITSY + if (machine_is_adsbitsy()) { + parts = adsbitsy_partitions; + nb_parts = ARRAY_SIZE(adsbitsy_partitions); + sa1100_map.size = ADSBITSY_FLASH_SIZE; + sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; + } +#endif #ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) { parts = assabet_partitions; - nb_parts = NB_OF(assabet_partitions); - sa1100_map.size = assabet_max_flash_size; + nb_parts = ARRAY_SIZE(assabet_partitions); + sa1100_map.size = ASSABET_FLASH_SIZE; } #endif - -#ifdef CONFIG_SA1100_HUW_WEBPANEL - if (machine_is_huw_webpanel()) { - parts = huw_webpanel_partitions; - nb_parts = NB_OF(huw_webpanel_partitions); - sa1100_map.size = huw_webpanel_max_flash_size; +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) { + parts = badge4_partitions; + nb_parts = ARRAY_SIZE(badge4_partitions); + sa1100_map.size = BADGE4_FLASH_SIZE; } #endif - -#ifdef CONFIG_SA1100_H3600 - if (machine_is_h3600()) { - parts = h3600_partitions; - nb_parts = NB_OF(h3600_partitions); - sa1100_map.size = h3600_max_flash_size; - sa1100_map.set_vpp = h3600_set_vpp; +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) { + parts = cerf_partitions; + nb_parts = ARRAY_SIZE(cerf_partitions); + sa1100_map.size = CERF_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_CONSUS + if (machine_is_consus()) { + parts = consus_partitions; + nb_parts = ARRAY_SIZE(consus_partitions); + sa1100_map.size = CONSUS_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_FLEXANET + if (machine_is_flexanet()) { + parts = flexanet_partitions; + nb_parts = ARRAY_SIZE(flexanet_partitions); + sa1100_map.size = FLEXANET_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) { parts = freebird_partitions; - nb_parts = NB_OF(freebird_partitions); - sa1100_map.size = freebird_max_flash_size; + nb_parts = ARRAY_SIZE(freebird_partitions); + sa1100_map.size = FREEBIRD_FLASH_SIZE; } #endif -#ifdef CONFIG_SA1100_CERF - if (machine_is_cerf()) { - parts = cerf_partitions; - nb_parts = NB_OF(cerf_partitions); - sa1100_map.size = cerf_max_flash_size; +#ifdef CONFIG_SA1100_FRODO + if (machine_is_frodo()) { + parts = frodo_partitions; + nb_parts = ARRAY_SIZE(frodo_partitions); + sa1100_map.size = FRODO_FLASH_SIZE; + base = 0x00000000; } -#endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT if (machine_is_graphicsclient()) { parts = graphicsclient_partitions; - nb_parts = NB_OF(graphicsclient_partitions); - sa1100_map.size = graphicsclient_max_flash_size; + nb_parts = ARRAY_SIZE(graphicsclient_partitions); + sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE; sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; } #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER if (machine_is_graphicsmaster()) { parts = graphicsmaster_partitions; - nb_parts = NB_OF(graphicsmaster_partitions); - sa1100_map.size = graphicsmaster_max_flash_size; + nb_parts = ARRAY_SIZE(graphicsmaster_partitions); + sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE; sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; } #endif -#ifdef CONFIG_SA1100_PANGOLIN - if (machine_is_pangolin()) { - parts = pangolin_partitions; - nb_parts = NB_OF(pangolin_partitions); - sa1100_map.size = pangolin_max_flash_size; +#ifdef CONFIG_SA1100_H3600 + if (machine_is_h3600()) { + parts = h3600_partitions; + nb_parts = ARRAY_SIZE(h3600_partitions); + sa1100_map.size = H3600_FLASH_SIZE; + sa1100_map.set_vpp = h3600_set_vpp; + } +#endif +#ifdef CONFIG_SA1100_HUW_WEBPANEL + if (machine_is_huw_webpanel()) { + parts = huw_webpanel_partitions; + nb_parts = ARRAY_SIZE(huw_webpanel_partitions); + sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_JORNADA720 if (machine_is_jornada720()) { parts = jornada720_partitions; - nb_parts = NB_OF(jornada720_partitions); - sa1100_map.size = jornada720_max_flash_size; + nb_parts = ARRAY_SIZE(jornada720_partitions); + sa1100_map.size = JORNADA720_FLASH_SIZE; sa1100_map.set_vpp = jornada720_set_vpp; } #endif -#ifdef CONFIG_SA1100_YOPY - if (machine_is_yopy()) { - parts = yopy_partitions; - nb_parts = NB_OF(yopy_partitions); - sa1100_map.size = yopy_max_flash_size; +#ifdef CONFIG_SA1100_PANGOLIN + if (machine_is_pangolin()) { + parts = pangolin_partitions; + nb_parts = ARRAY_SIZE(pangolin_partitions); + sa1100_map.size = PANGOLIN_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_PT_SYSTEM3 + if (machine_is_pt_system3()) { + parts = system3_partitions; + nb_parts = ARRAY_SIZE(system3_partitions); + sa1100_map.size = SYSTEM3_FLASH_SIZE; + } +#endif +#ifdef CONFIG_SA1100_SHANNON + if (machine_is_shannon()) { + parts = shannon_partitions; + nb_parts = ARRAY_SIZE(shannon_partitions); + sa1100_map.size = SHANNON_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_SHERMAN if (machine_is_sherman()) { parts = sherman_partitions; - nb_parts = NB_OF(sherman_partitions); - sa1100_map.size = sherman_max_flash_size; + nb_parts = ARRAY_SIZE(sherman_partitions); + sa1100_map.size = SHERMAN_FLASH_SIZE; } #endif -#ifdef CONFIG_SA1100_FLEXANET - if (machine_is_flexanet()) { - parts = flexanet_partitions; - nb_parts = NB_OF(flexanet_partitions); - sa1100_map.size = flexanet_max_flash_size; +#ifdef CONFIG_SA1100_SIMPAD + if (machine_is_simpad()) { + parts = simpad_partitions; + nb_parts = ARRAY_SIZE(simpad_partitions); + sa1100_map.size = SIMPAD_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_STORK if (machine_is_stork()) { parts = stork_partitions; - nb_parts = NB_OF(stork_partitions); - sa1100_map.size = stork_max_flash_size; + nb_parts = ARRAY_SIZE(stork_partitions); + sa1100_map.size = STORK_FLASH_SIZE; } #endif +#ifdef CONFIG_SA1100_YOPY + if (machine_is_yopy()) { + parts = yopy_partitions; + nb_parts = ARRAY_SIZE(yopy_partitions); + sa1100_map.size = YOPY_FLASH_SIZE; + } +#endif + + /* + * For simple flash devices, use ioremap to map the flash. + */ + if (base != (unsigned long)-1) { + if (!request_mem_region(base, sa1100_map.size, "flash")) + return -EBUSY; + sa1100_map.map_priv_2 = base; + sa1100_map.map_priv_1 = (unsigned long) + ioremap(base, sa1100_map.size); + ret = -ENOMEM; + if (!sa1100_map.map_priv_1) + goto out_err; + } /* * Now let's probe for the actual flash. Do it here since @@ -655,8 +957,9 @@ */ printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); mymtd = do_map_probe("cfi_probe", &sa1100_map); + ret = -ENXIO; if (!mymtd) - return -ENXIO; + goto out_err; mymtd->module = THIS_MODULE; /* @@ -665,7 +968,7 @@ #ifdef CONFIG_MTD_REDBOOT_PARTS if (parsed_nr_parts == 0) { int ret = parse_redboot_partitions(mymtd, &parsed_parts); - + if (ret > 0) { part_type = "RedBoot"; parsed_nr_parts = ret; @@ -695,6 +998,13 @@ add_mtd_partitions(mymtd, parts, nb_parts); } return 0; + + out_err: + if (sa1100_map.map_priv_2 != -1) { + iounmap((void *)sa1100_map.map_priv_1); + release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); + } + return ret; } static void __exit sa1100_mtd_cleanup(void) @@ -704,6 +1014,10 @@ map_destroy(mymtd); if (parsed_parts) kfree(parsed_parts); + } + if (sa1100_map.map_priv_2 != -1) { + iounmap((void *)sa1100_map.map_priv_1); + release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); } } diff -urN linux-2.4.18/drivers/mtd/maps/sbc_gxx.c linux-2.4.19-pre5/drivers/mtd/maps/sbc_gxx.c --- linux-2.4.18/drivers/mtd/maps/sbc_gxx.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/mtd/maps/sbc_gxx.c Sat Mar 30 22:55:40 2002 @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.20 2002/02/13 15:30:20 dwmw2 Exp $ The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. diff -urN linux-2.4.18/drivers/mtd/maps/sc520cdp.c linux-2.4.19-pre5/drivers/mtd/maps/sc520cdp.c --- linux-2.4.18/drivers/mtd/maps/sc520cdp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/sc520cdp.c Sat Mar 30 22:55:40 2002 @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.9 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -25,13 +25,14 @@ * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html */ +#include #include #include #include #include #include #include - +#include /* ** The Embedded Systems BIOS decodes the first FLASH starting at @@ -171,6 +172,7 @@ #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) static struct mtd_info *mymtd[NUM_FLASH_BANKS]; +static struct mtd_info *merged_mtd; #ifdef REPROGRAM_PAR @@ -307,19 +309,26 @@ } mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); if(!mymtd[i]) - mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]); + mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); if(!mymtd[i]) mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); if (mymtd[i]) { mymtd[i]->module = THIS_MODULE; - add_mtd_device(mymtd[i]); ++devices_found; } else { iounmap((void *)sc520cdp_map[i].map_priv_1); } } + if(devices_found >= 2) { + /* Combine the two flash banks into a single MTD device & register it: */ + merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1"); + if(merged_mtd) + add_mtd_device(merged_mtd); + } + if(devices_found == 3) /* register the third (DIL-Flash) device */ + add_mtd_device(mymtd[2]); return(devices_found ? 0 : -ENXIO); } @@ -327,11 +336,16 @@ { int i; + if (merged_mtd) { + del_mtd_device(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + if (mymtd[2]) + del_mtd_device(mymtd[2]); + for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (mymtd[i]) { - del_mtd_device(mymtd[i]); + if (mymtd[i]) map_destroy(mymtd[i]); - } if (sc520cdp_map[i].map_priv_1) { iounmap((void *)sc520cdp_map[i].map_priv_1); sc520cdp_map[i].map_priv_1 = 0; diff -urN linux-2.4.18/drivers/mtd/maps/solutionengine.c linux-2.4.19-pre5/drivers/mtd/maps/solutionengine.c --- linux-2.4.18/drivers/mtd/maps/solutionengine.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/maps/solutionengine.c Sat Mar 30 22:55:40 2002 @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -15,6 +15,7 @@ #include #include #include +#include extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); @@ -57,20 +58,38 @@ write32: soleng_write32, }; +#ifdef CONFIG_MTD_SUPERH_RESERVE +static struct mtd_partition superh_se_partitions[] = { + /* Reserved for boot code, read-only */ + { + name: "flash_boot", + offset: 0x00000000, + size: CONFIG_MTD_SUPERH_RESERVE, + mask_flags: MTD_WRITEABLE, + }, + /* All else is writable (e.g. JFFS) */ + { + name: "Flash FS", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, + } +}; +#endif /* CONFIG_MTD_SUPERH_RESERVE */ + static int __init init_soleng_maps(void) { - int nr_parts; + int nr_parts = 0; /* First probe at offset 0 */ soleng_flash_map.map_priv_1 = P2SEGADDR(0); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000); + soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000); - printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n"); + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Not there. Try swapping */ - printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n"); - soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000); + printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); + soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000); soleng_eprom_map.map_priv_1 = P1SEGADDR(0); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { @@ -90,9 +109,23 @@ add_mtd_device(eprom_mtd); } +#ifdef CONFIG_MTD_REDBOOT_PARTS nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + if (nr_parts > 0) + printk(KERN_NOTICE "Found RedBoot partition table.\n"); + else if (nr_parts < 0) + printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); +#endif /* CONFIG_MTD_REDBOOT_PARTS */ +#if CONFIG_MTD_SUPERH_RESERVE + if (nr_parts == 0) { + printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", + CONFIG_MTD_SUPERH_RESERVE); + parsed_parts = superh_se_partitions; + nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); + } +#endif /* CONFIG_MTD_SUPERH_RESERVE */ - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); diff -urN linux-2.4.18/drivers/mtd/maps/tsunami_flash.c linux-2.4.19-pre5/drivers/mtd/maps/tsunami_flash.c --- linux-2.4.18/drivers/mtd/maps/tsunami_flash.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/maps/tsunami_flash.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,110 @@ +/* + * tsunami_flash.c + * + * flash chip on alpha ds10... + * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ +#include +#include +#include + +#define FLASH_ENABLE_PORT 0x00C00001 +#define FLASH_ENABLE_BYTE 0x01 +#define FLASH_DISABLE_BYTE 0x00 + +#define MAX_TIG_FLASH_SIZE (12*1024*1024) +static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset) +{ + return tsunami_tig_readb(offset); +} + +static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset) +{ + tsunami_tig_writeb(value, offset); +} + +static void tsunami_flash_copy_from( + struct map_info *map, void *addr, unsigned long offset, ssize_t len) +{ + unsigned char *dest; + dest = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + *dest = tsunami_tig_readb(offset); + offset++; + dest++; + len--; + } +} + +static void tsunami_flash_copy_to( + struct map_info *map, unsigned long offset, + const void *addr, ssize_t len) +{ + const unsigned char *src; + src = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + tsunami_tig_writeb(*src, offset); + offset++; + src++; + len--; + } +} + +/* + * Deliberately don't provide operations wider than 8 bits. I don't + * have then and it scares me to think how you could mess up if + * you tried to use them. Buswidth is correctly so I'm safe. + */ +static struct map_info tsunami_flash_map = { + .name = "flash chip on the Tsunami TIG bus", + .size = MAX_TIG_FLASH_SIZE, + .buswidth = 1, + .read8 = tsunami_flash_read8, + .read16 = 0, + .read32 = 0, + .copy_from = tsunami_flash_copy_from, + .write8 = tsunami_flash_write8, + .write16 = 0, + .write32 = 0, + .copy_to = tsunami_flash_copy_to, + .set_vpp = 0, + .map_priv_1 = 0, + +}; + +static struct mtd_info *tsunami_flash_mtd; + +static void __exit cleanup_tsunami_flash(void) +{ + struct mtd_info *mtd; + mtd = tsunami_flash_mtd; + if (mtd) { + del_mtd_device(mtd); + map_destroy(mtd); + } + tsunami_flash_mtd = 0; +} + + +static int __init init_tsunami_flash(void) +{ + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; + char **type; + + tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); + + tsunami_flash_mtd = 0; + type = rom_probe_types; + for(; !tsunami_flash_mtd && *type; type++) { + tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); + } + if (tsunami_flash_mtd) { + tsunami_flash_mtd->module = THIS_MODULE; + add_mtd_device(tsunami_flash_mtd); + return 0; + } + return -ENXIO; +} + +module_init(init_tsunami_flash); +module_exit(cleanup_tsunami_flash); diff -urN linux-2.4.18/drivers/mtd/mtdblock.c linux-2.4.19-pre5/drivers/mtd/mtdblock.c --- linux-2.4.18/drivers/mtd/mtdblock.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/mtdblock.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.47 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $ * * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache */ @@ -60,6 +60,13 @@ static int mtd_sizes[MAX_MTD_DEVICES]; static int mtd_blksizes[MAX_MTD_DEVICES]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif /* * Cache stuff... @@ -287,11 +294,14 @@ if (dev >= MAX_MTD_DEVICES) return -EINVAL; + BLK_INC_USE_COUNT; + mtd = get_mtd_device(NULL, dev); if (!mtd) return -ENODEV; if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); + BLK_DEC_USE_COUNT; return -ENODEV; } @@ -314,6 +324,7 @@ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); if (!mtdblk) { put_mtd_device(mtd); + BLK_DEC_USE_COUNT; return -ENOMEM; } memset(mtdblk, 0, sizeof(*mtdblk)); @@ -329,6 +340,7 @@ if (!mtdblk->cache_data) { put_mtd_device(mtdblk->mtd); kfree(mtdblk); + BLK_DEC_USE_COUNT; return -ENOMEM; } } @@ -371,8 +383,6 @@ if (inode == NULL) release_return(-ENODEV); - invalidate_device(inode->i_rdev, 1); - dev = MINOR(inode->i_rdev); mtdblk = mtdblks[dev]; @@ -396,6 +406,7 @@ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + BLK_DEC_USE_COUNT; release_return(0); } @@ -535,8 +546,11 @@ switch (cmd) { case BLKGETSIZE: /* Return device size */ return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg); + +#ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)mtdblk->mtd->size, (u64 *)arg); +#endif case BLKFLSBUF: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) @@ -569,7 +583,9 @@ #else static struct block_device_operations mtd_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: mtdblock_open, release: mtdblock_release, ioctl: mtdblock_ioctl diff -urN linux-2.4.18/drivers/mtd/mtdblock_ro.c linux-2.4.19-pre5/drivers/mtd/mtdblock_ro.c --- linux-2.4.18/drivers/mtd/mtdblock_ro.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/mtdblock_ro.c Sat Mar 30 22:55:40 2002 @@ -1,5 +1,5 @@ /* - * $Id: mtdblock_ro.c,v 1.9 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $ * * Read-only version of the mtdblock device, without the * read/erase/modify/writeback stuff @@ -37,6 +37,13 @@ MODULE_PARM(debug, "i"); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif static int mtd_sizes[MAX_MTD_DEVICES]; @@ -62,6 +69,8 @@ return -EINVAL; } + BLK_INC_USE_COUNT; + mtd_sizes[dev] = mtd->size>>9; DEBUG(1, "ok\n"); @@ -79,13 +88,12 @@ if (inode == NULL) release_return(-ENODEV); - invalidate_device(inode->i_rdev, 1); - dev = MINOR(inode->i_rdev); mtd = __get_mtd_device(NULL, dev); if (!mtd) { printk(KERN_WARNING "MTD device is absent on mtd_release!\n"); + BLK_DEC_USE_COUNT; release_return(-ENODEV); } @@ -96,6 +104,7 @@ DEBUG(1, "ok\n"); + BLK_DEC_USE_COUNT; release_return(0); } @@ -210,9 +219,12 @@ switch (cmd) { case BLKGETSIZE: /* Return device size */ return put_user((mtd->size >> 9), (unsigned long *) arg); + +#ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)mtd->size, (u64 *)arg); - +#endif + case BLKFLSBUF: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if(!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -240,7 +252,9 @@ #else static struct block_device_operations mtd_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: mtdblock_open, release: mtdblock_release, ioctl: mtdblock_ioctl diff -urN linux-2.4.18/drivers/mtd/mtdconcat.c linux-2.4.19-pre5/drivers/mtd/mtdconcat.c --- linux-2.4.18/drivers/mtd/mtdconcat.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/mtd/mtdconcat.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,672 @@ +/* + * MTD device concatenation layer + * + * (C) 2002 Robert Kaiser + * + * This code is GPL + * + * $Id: mtdconcat.c,v 1.2 2002/03/22 08:45:22 dwmw2 Exp $ + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Our storage structure: + * Subdev points to an array of pointers to struct mtd_info objects + * which is allocated along with this structure + * + */ +struct mtd_concat { + struct mtd_info mtd; + int num_subdev; + struct mtd_info **subdev; +}; + +/* + * how to calculate the size required for the above structure, + * including the pointer array subdev points to: + */ +#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ + ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) + + +/* + * Given a pointer to the MTD object in the mtd_concat structure, + * we can retrieve the pointer to that structure with this macro. + */ +#define CONCAT(x) ((struct mtd_concat *)(x)) + + +/* + * MTD methods which look up the relevant subdevice, translate the + * effective address and pass through to the subdevice. + */ + +static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) + { + size = 0; + from -= subdev->size; + } + else + { + if (from + len > subdev->size) + size = subdev->size - from; + else + size = len; + + err = subdev->read(subdev, from, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + } + return err; +} + +static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) + { + size = 0; + to -= subdev->size; + } + else + { + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else + err = subdev->write(subdev, to, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + } + return err; +} + +static void concat_erase_callback (struct erase_info *instr) +{ + wake_up((wait_queue_head_t *)instr->priv); +} + +static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + int err; + wait_queue_head_t waitq; + DECLARE_WAITQUEUE(wait, current); + + /* + * This code was stol^H^H^H^Hinspired by mtdchar.c + */ + init_waitqueue_head(&waitq); + + erase->mtd = mtd; + erase->callback = concat_erase_callback; + erase->priv = (unsigned long)&waitq; + + /* + * FIXME: Allow INTERRUPTIBLE. Which means + * not having the wait_queue head on the stack. + */ + err = mtd->erase(mtd, erase); + if (!err) + { + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&waitq, &wait); + if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) + schedule(); + remove_wait_queue(&waitq, &wait); + set_current_state(TASK_RUNNING); + + err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0; + } + return err; +} + +static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_info *subdev; + int i, err; + u_int32_t length; + struct erase_info *erase; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + if(instr->addr > concat->mtd.size) + return -EINVAL; + + if(instr->len + instr->addr > concat->mtd.size) + return -EINVAL; + + /* + * Check for proper erase block alignment of the to-be-erased area. + * It is easier to do this based on the super device's erase + * region info rather than looking at each particular sub-device + * in turn. + */ + if (!concat->mtd.numeraseregions) + { /* the easy case: device has uniform erase block size */ + if(instr->addr & (concat->mtd.erasesize - 1)) + return -EINVAL; + if(instr->len & (concat->mtd.erasesize - 1)) + return -EINVAL; + } + else + { /* device has variable erase size */ + struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; + + /* + * Find the erase region where the to-be-erased area begins: + */ + for(i = 0; i < concat->mtd.numeraseregions && + instr->addr >= erase_regions[i].offset; i++) + ; + --i; + + /* + * Now erase_regions[i] is the region in which the + * to-be-erased area begins. Verify that the starting + * offset is aligned to this region's erase size: + */ + if (instr->addr & (erase_regions[i].erasesize-1)) + return -EINVAL; + + /* + * now find the erase region where the to-be-erased area ends: + */ + for(; i < concat->mtd.numeraseregions && + (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) + ; + --i; + /* + * check if the ending offset is aligned to this region's erase size + */ + if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) + return -EINVAL; + } + + /* make a local copy of instr to avoid modifying the caller's struct */ + erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); + + if (!erase) + return -ENOMEM; + + *erase = *instr; + length = instr->len; + + /* + * find the subdevice where the to-be-erased area begins, adjust + * starting offset to be relative to the subdevice start + */ + for(i = 0; i < concat->num_subdev; i++) + { + subdev = concat->subdev[i]; + if(subdev->size <= erase->addr) + erase->addr -= subdev->size; + else + break; + } + if(i >= concat->num_subdev) /* must never happen since size */ + BUG(); /* limit has been verified above */ + + /* now do the erase: */ + err = 0; + for(;length > 0; i++) /* loop for all subevices affected by this request */ + { + subdev = concat->subdev[i]; /* get current subdevice */ + + /* limit length to subdevice's size: */ + if(erase->addr + length > subdev->size) + erase->len = subdev->size - erase->addr; + else + erase->len = length; + + if (!(subdev->flags & MTD_WRITEABLE)) + { + err = -EROFS; + break; + } + length -= erase->len; + if ((err = concat_dev_erase(subdev, erase))) + { + if(err == -EINVAL) /* sanity check: must never happen since */ + BUG(); /* block alignment has been checked above */ + break; + } + /* + * erase->addr specifies the offset of the area to be + * erased *within the current subdevice*. It can be + * non-zero only the first time through this loop, i.e. + * for the first subdevice where blocks need to be erased. + * All the following erases must begin at the start of the + * current subdevice, i.e. at offset zero. + */ + erase->addr = 0; + } + instr->state = MTD_ERASE_DONE; + if (instr->callback) + instr->callback(instr); + kfree(erase); + return err; +} + +static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->lock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = 0; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->unlock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static void concat_sync(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->sync(subdev); + } +} + +static int concat_suspend(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, rc = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + if((rc = subdev->suspend(subdev)) < 0) + return rc; + } + return rc; +} + +static void concat_resume(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->resume(subdev); + } +} + +/* + * This function constructs a virtual MTD device by concatenating + * num_devs MTD devices. A pointer to the new device object is + * stored to *new_dev upon success. This function does _not_ + * register any devices: this is the caller's responsibility. + */ +struct mtd_info *mtd_concat_create( + struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + char *name) /* name for the new device */ +{ + int i; + size_t size; + struct mtd_concat *concat; + u_int32_t max_erasesize, curr_erasesize; + int num_erase_region; + + printk(KERN_NOTICE "Concatenating MTD devices:\n"); + for(i = 0; i < num_devs; i++) + printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); + printk(KERN_NOTICE "into device \"%s\"\n", name); + + /* allocate the device structure */ + size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); + concat = kmalloc (size, GFP_KERNEL); + if(!concat) + { + printk ("memory allocation error while creating concatenated device \"%s\"\n", + name); + return NULL; + } + memset(concat, 0, size); + concat->subdev = (struct mtd_info **)(concat + 1); + + /* + * Set up the new "super" device's MTD object structure, check for + * incompatibilites between the subdevices. + */ + concat->mtd.type = subdev[0]->type; + concat->mtd.flags = subdev[0]->flags; + concat->mtd.size = subdev[0]->size; + concat->mtd.erasesize = subdev[0]->erasesize; + concat->mtd.oobblock = subdev[0]->oobblock; + concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.ecctype = subdev[0]->ecctype; + concat->mtd.eccsize = subdev[0]->eccsize; + + concat->subdev[0] = subdev[0]; + + for(i = 1; i < num_devs; i++) + { + if(concat->mtd.type != subdev[i]->type) + { + kfree(concat); + printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); + return NULL; + } + if(concat->mtd.flags != subdev[i]->flags) + { /* + * Expect all flags except MTD_WRITEABLE to be equal on + * all subdevices. + */ + if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) + { + kfree(concat); + printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); + return NULL; + } + else /* if writeable attribute differs, make super device writeable */ + concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; + } + concat->mtd.size += subdev[i]->size; + if(concat->mtd.oobblock != subdev[i]->oobblock || + concat->mtd.oobsize != subdev[i]->oobsize || + concat->mtd.ecctype != subdev[i]->ecctype || + concat->mtd.eccsize != subdev[i]->eccsize) + { + kfree(concat); + printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); + return NULL; + } + concat->subdev[i] = subdev[i]; + + } + + concat->num_subdev = num_devs; + concat->mtd.name = name; + + /* + * NOTE: for now, we do not provide any readv()/writev() methods + * because they are messy to implement and they are not + * used to a great extent anyway. + */ + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.sync = concat_sync; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; + concat->mtd.suspend = concat_suspend; + concat->mtd.resume = concat_resume; + + + /* + * Combine the erase block size info of the subdevices: + * + * first, walk the map of the new device and see how + * many changes in erase size we have + */ + max_erasesize = curr_erasesize = subdev[0]->erasesize; + num_erase_region = 1; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* if it differs from the last subdevice's erase size, count it */ + ++num_erase_region; + curr_erasesize = subdev[i]->erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + ++num_erase_region; + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + } + } + + if(num_erase_region == 1) + { /* + * All subdevices have the same uniform erase size. + * This is easy: + */ + concat->mtd.erasesize = curr_erasesize; + concat->mtd.numeraseregions = 0; + } + else + { /* + * erase block size varies across the subdevices: allocate + * space to store the data describing the variable erase regions + */ + struct mtd_erase_region_info *erase_region_p; + u_int32_t begin, position; + + concat->mtd.erasesize = max_erasesize; + concat->mtd.numeraseregions = num_erase_region; + concat->mtd.eraseregions = erase_region_p = kmalloc ( + num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); + if(!erase_region_p) + { + kfree(concat); + printk ("memory allocation error while creating erase region list" + " for device \"%s\"\n", name); + return NULL; + } + + /* + * walk the map of the new device once more and fill in + * in erase region info: + */ + curr_erasesize = subdev[0]->erasesize; + begin = position = 0; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* + * fill in an mtd_erase_region_info structure for the area + * we have walked so far: + */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->erasesize; + ++erase_region_p; + } + position += subdev[i]->size; + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + ++erase_region_p; + } + position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; + } + } + } + /* Now write the final entry */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + } + + return &concat->mtd; +} + +/* + * This function destroys an MTD object obtained from concat_mtd_devs() + */ + +void mtd_concat_destroy(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + if(concat->mtd.numeraseregions) + kfree(concat->mtd.eraseregions); + kfree(concat); +} + + +EXPORT_SYMBOL(mtd_concat_create); +EXPORT_SYMBOL(mtd_concat_destroy); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Kaiser "); +MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); diff -urN linux-2.4.18/drivers/mtd/mtdcore.c linux-2.4.19-pre5/drivers/mtd/mtdcore.c --- linux-2.4.18/drivers/mtd/mtdcore.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/mtdcore.c Sat Mar 30 22:55:40 2002 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -296,7 +296,7 @@ up(&mtd_table_mutex); if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -urN linux-2.4.18/drivers/mtd/mtdpart.c linux-2.4.19-pre5/drivers/mtd/mtdpart.c --- linux-2.4.18/drivers/mtd/mtdpart.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/mtdpart.c Sat Mar 30 22:55:40 2002 @@ -5,8 +5,12 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $ - */ + * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $ + * - with protection register access removed until that code is merged in 2.4. + * + * 02-21-2002 Thomas Gleixner + * added support for read_oob, write_oob + */ #include #include @@ -28,6 +32,7 @@ u_int32_t offset; int index; struct list_head list; + int registered; }; /* @@ -54,6 +59,18 @@ len, retlen, buf); } +static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->read_oob (part->master, from + part->offset, + len, retlen, buf); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -68,6 +85,20 @@ len, retlen, buf); } +static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write_oob (part->master, to + part->offset, + len, retlen, buf); +} + static int part_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -148,7 +179,8 @@ if (slave->master == master) { struct list_head *prev = node->prev; __list_del(prev, node->next); - del_mtd_device(&slave->mtd); + if(slave->registered) + del_mtd_device(&slave->mtd); kfree(slave); node = prev; } @@ -198,18 +230,21 @@ slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; - slave->mtd.module = master->module; slave->mtd.read = part_read; slave->mtd.write = part_write; + + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } - if (master->writev) slave->mtd.writev = part_writev; if (master->readv) @@ -225,6 +260,15 @@ if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + u_int32_t emask = master->erasesize-1; + slave->offset = (cur_offset + emask) & ~emask; + if (slave->offset != cur_offset) { + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", i, + cur_offset, slave->offset); + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; cur_offset = slave->offset + slave->mtd.size; @@ -279,8 +323,17 @@ parts[i].name); } - /* register our partition */ - add_mtd_device(&slave->mtd); + if(parts[i].mtdp) + { /* store the object pointer (caller may or may not register it */ + *parts[i].mtdp = &slave->mtd; + slave->registered = 0; + } + else + { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } } return 0; diff -urN linux-2.4.18/drivers/mtd/nand/nand_ecc.c linux-2.4.19-pre5/drivers/mtd/nand/nand_ecc.c --- linux-2.4.18/drivers/mtd/nand/nand_ecc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/nand/nand_ecc.c Sat Mar 30 22:55:40 2002 @@ -4,7 +4,7 @@ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) * Toshiba America Electronics Components, Inc. * - * $Id: nand_ecc.c,v 1.6 2001/06/28 10:52:26 dwmw2 Exp $ + * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -207,3 +207,7 @@ EXPORT_SYMBOL(nand_calculate_ecc); EXPORT_SYMBOL(nand_correct_data); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill "); +MODULE_DESCRIPTION("Generic NAND ECC support"); diff -urN linux-2.4.18/drivers/mtd/nand/spia.c linux-2.4.19-pre5/drivers/mtd/nand/spia.c --- linux-2.4.18/drivers/mtd/nand/spia.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/nand/spia.c Sat Mar 30 22:55:28 2002 @@ -113,7 +113,7 @@ this->ALE = 0x02; this->NCE = 0x04; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan (spia_mtd)) { kfree (spia_mtd); return -ENXIO; diff -urN linux-2.4.18/drivers/mtd/nftlcore.c linux-2.4.19-pre5/drivers/mtd/nftlcore.c --- linux-2.4.18/drivers/mtd/nftlcore.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/mtd/nftlcore.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.85 2001/11/20 11:42:33 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU General @@ -77,6 +77,14 @@ sizes: nftl_sizes, /* block sizes */ }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +#else +#define BLK_INC_USE_COUNT do {} while(0) +#define BLK_DEC_USE_COUNT do {} while(0) +#endif + struct NFTLrecord *NFTLs[MAX_NFTLS]; static void NFTL_setup(struct mtd_info *mtd) @@ -805,9 +813,12 @@ case BLKGETSIZE: /* Return device size */ return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, (unsigned long *) arg); + +#ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *)arg); +#endif case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -984,8 +995,11 @@ #endif /* !CONFIG_NFTL_RW */ thisNFTL->usecount++; - if (!get_mtd_device(thisNFTL->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; + BLK_INC_USE_COUNT; + if (!get_mtd_device(thisNFTL->mtd, -1)) { + BLK_DEC_USE_COUNT; + return -ENXIO; + } return 0; } @@ -998,11 +1012,10 @@ DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - invalidate_device(inode->i_rdev, 1); - if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); thisNFTL->usecount--; + BLK_DEC_USE_COUNT; put_mtd_device(thisNFTL->mtd); @@ -1020,7 +1033,9 @@ #else static struct block_device_operations nftl_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE, +#endif open: nftl_open, release: nftl_release, ioctl: nftl_ioctl @@ -1047,7 +1062,7 @@ int i; #ifdef PRERELEASE - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev); #endif if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ diff -urN linux-2.4.18/drivers/net/3c503.c linux-2.4.19-pre5/drivers/net/3c503.c --- linux-2.4.18/drivers/net/3c503.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/3c503.c Sat Mar 30 22:55:40 2002 @@ -692,9 +692,11 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i"); MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i"); -MODULE_PARM_DESC(io, "EtherLink II I/O base address(es)"); -MODULE_PARM_DESC(irq, "EtherLink II IRQ number(s) (assigned)"); -MODULE_PARM_DESC(xcvr, "EtherLink II tranceiver(s) (0=internal, 1=external)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); +MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)"); +MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver"); +MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ @@ -742,7 +744,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/7990.c linux-2.4.19-pre5/drivers/net/7990.c --- linux-2.4.18/drivers/net/7990.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/7990.c Sat Mar 30 22:55:34 2002 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -569,7 +570,7 @@ struct dev_mc_list *dmi=dev->mc_list; char *addrs; int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + u32 crc; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI){ @@ -590,21 +591,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) - for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1) - { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) - { - crc = crc ^ poly; - } - } - + crc = ether_crc_le(6, addrs); crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); } @@ -643,3 +630,4 @@ netif_start_queue (dev); } +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/7990.h linux-2.4.19-pre5/drivers/net/7990.h --- linux-2.4.18/drivers/net/7990.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/7990.h Sat Mar 30 22:55:34 2002 @@ -132,9 +132,6 @@ char tx_full; }; -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* * Am7990 Control and Status Registers */ diff -urN linux-2.4.18/drivers/net/8139cp.c linux-2.4.19-pre5/drivers/net/8139cp.c --- linux-2.4.18/drivers/net/8139cp.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/8139cp.c Sat Mar 30 22:55:34 2002 @@ -1,7 +1,8 @@ /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */ /* - Copyright 2001 Jeff Garzik + Copyright 2001,2002 Jeff Garzik + Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c] Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c] Copyright 2001 Manfred Spraul [natsemi.c] Copyright 1999-2001 by Donald Becker. [natsemi.c] @@ -29,36 +30,51 @@ * Consider Rx interrupt mitigation using TimerIntr * Implement 8139C+ statistics dump; maybe not... h/w stats can be reset only by software reset - * Rx checksumming * Tx checksumming + * Handle netif_rx return value * ETHTOOL_GREGS, ETHTOOL_[GS]WOL, - * Jumbo frames / dev->change_mtu * Investigate using skb->priority with h/w VLAN priority * Investigate using High Priority Tx Queue with skb->priority * Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error * Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error * Implement Tx software interrupt mitigation via Tx descriptor bit + * The real minimum of CP_MIN_MTU is 4 bytes. However, + for this to be supported, one must(?) turn on packet padding. */ #define DRV_NAME "8139cp" -#define DRV_VERSION "0.0.6" -#define DRV_RELDATE "Nov 19, 2001" +#define DRV_VERSION "0.0.7" +#define DRV_RELDATE "Feb 27, 2002" +#include #include #include +#include #include #include #include #include #include #include +#include #include +#include #include #include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define CP_VLAN_TAG_USED 1 +#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ + do { (tx_desc)->opts2 = (vlan_tag_value); } while (0) +#else +#define CP_VLAN_TAG_USED 0 +#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ + do { (tx_desc)->opts2 = 0; } while (0) +#endif + /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -106,8 +122,11 @@ #define TX_EARLY_THRESH 256 /* Early Tx threshold, in bytes */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (6*HZ) +#define TX_TIMEOUT (6*HZ) +/* hardware minimum and maximum for a single frame's data payload */ +#define CP_MIN_MTU 60 /* TODO: allow lower, but pad */ +#define CP_MAX_MTU 4096 enum { /* NIC register offsets */ @@ -149,12 +168,17 @@ IPCS = (1 << 18), /* Calculate IP checksum */ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ + RxVlanTagged = (1 << 16), /* Rx VLAN tag available */ IPFail = (1 << 15), /* IP checksum failed */ UDPFail = (1 << 14), /* UDP/IP checksum failed */ TCPFail = (1 << 13), /* TCP/IP checksum failed */ NormalTxPoll = (1 << 6), /* One or more normal Tx packets to send */ PID1 = (1 << 17), /* 2 protocol id bits: 0==non-IP, */ PID0 = (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */ + RxProtoTCP = 2, + RxProtoUDP = 1, + RxProtoIP = 3, TxFIFOUnder = (1 << 25), /* Tx FIFO underrun */ TxOWC = (1 << 22), /* Tx Out-of-window collision */ TxLinkFail = (1 << 21), /* Link failed during Tx of packet */ @@ -204,6 +228,7 @@ TxOn = (1 << 2), /* Tx mode enable */ /* C+ mode command register */ + RxVlanOn = (1 << 6), /* Rx VLAN de-tagging enable */ RxChkSum = (1 << 5), /* Rx checksum offload enable */ PCIMulRW = (1 << 3), /* Enable PCI read/write multiple */ CpRxOn = (1 << 1), /* Rx mode enable */ @@ -274,6 +299,10 @@ unsigned rx_buf_sz; dma_addr_t ring_dma; +#if CP_VLAN_TAG_USED + struct vlan_group *vlgrp; +#endif + u32 msg_enable; struct net_device_stats net_stats; @@ -320,14 +349,32 @@ }; MODULE_DEVICE_TABLE(pci, cp_pci_tbl); -static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb) +static inline void cp_set_rxbufsize (struct cp_private *cp) +{ + unsigned int mtu = cp->dev->mtu; + + if (mtu > ETH_DATA_LEN) + /* MTU + ethernet header + FCS + optional VLAN tag */ + cp->rx_buf_sz = mtu + ETH_HLEN + 8; + else + cp->rx_buf_sz = PKT_BUF_SZ; +} + +static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, + struct cp_desc *desc) { skb->protocol = eth_type_trans (skb, cp->dev); cp->net_stats.rx_packets++; cp->net_stats.rx_bytes += skb->len; cp->dev->last_rx = jiffies; - netif_rx (skb); + +#if CP_VLAN_TAG_USED + if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) { + vlan_hwaccel_rx(skb, cp->vlgrp, desc->opts2 & 0xffff); + } else +#endif + netif_rx(skb); } static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, @@ -410,13 +457,26 @@ cp_rx_err_acct(cp, rx_tail, status, len); dev_kfree_skb_irq(copy_skb); } else - cp_rx_skb(cp, copy_skb); + cp_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]); cp->frag_skb = NULL; } else { cp->frag_skb = copy_skb; } } +static inline unsigned int cp_rx_csum_ok (u32 status) +{ + unsigned int protocol = (status >> 16) & 0x3; + + if (likely((protocol == RxProtoTCP) && (!(status & TCPFail)))) + return 1; + else if ((protocol == RxProtoUDP) && (!(status & UDPFail))) + return 1; + else if ((protocol == RxProtoIP) && (!(status & IPFail))) + return 1; + return 0; +} + static void cp_rx (struct cp_private *cp) { unsigned rx_tail = cp->rx_tail; @@ -426,13 +486,15 @@ u32 status, len; dma_addr_t mapping; struct sk_buff *skb, *new_skb; + struct cp_desc *desc; unsigned buflen; skb = cp->rx_skb[rx_tail].skb; if (!skb) BUG(); - rmb(); - status = le32_to_cpu(cp->rx_ring[rx_tail].opts1); + + desc = &cp->rx_ring[rx_tail]; + status = le32_to_cpu(desc->opts1); if (status & DescOwn) break; @@ -465,7 +527,13 @@ pci_unmap_single(cp->pdev, mapping, buflen, PCI_DMA_FROMDEVICE); - skb->ip_summed = CHECKSUM_NONE; + + /* Handle checksum offloading for incoming packets. */ + if (cp_rx_csum_ok(status)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + skb_put(skb, len); mapping = @@ -474,15 +542,14 @@ buflen, PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail].skb = new_skb; - cp_rx_skb(cp, skb); + cp_rx_skb(cp, skb, desc); rx_next: if (rx_tail == (CP_RX_RING_SIZE - 1)) - cp->rx_ring[rx_tail].opts1 = - cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); + desc->opts1 = cpu_to_le32(DescOwn | RingEnd | + cp->rx_buf_sz); else - cp->rx_ring[rx_tail].opts1 = - cpu_to_le32(DescOwn | cp->rx_buf_sz); + desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); cp->rx_ring[rx_tail].opts2 = 0; cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping); rx_tail = NEXT_RX(rx_tail); @@ -582,7 +649,7 @@ cp->tx_tail = tx_tail; - if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > 1)) + if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))) netif_wake_queue(cp->dev); } @@ -591,15 +658,26 @@ struct cp_private *cp = dev->priv; unsigned entry; u32 eor; +#if CP_VLAN_TAG_USED + u32 vlan_tag = 0; +#endif spin_lock_irq(&cp->lock); + /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irq(&cp->lock); + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); return 1; } +#if CP_VLAN_TAG_USED + if (cp->vlgrp && vlan_tx_tag_present(skb)) + vlan_tag = TxVlanTag | vlan_tx_tag_get(skb); +#endif + entry = cp->tx_head; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; if (skb_shinfo(skb)->nr_frags == 0) { @@ -609,7 +687,7 @@ len = skb->len; mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; - txd->opts2 = 0; + CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr_lo = cpu_to_le32(mapping); wmb(); @@ -662,7 +740,7 @@ ctrl |= LastFrag; txd = &cp->tx_ring[entry]; - txd->opts2 = 0; + CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr_lo = cpu_to_le32(mapping); wmb(); @@ -676,7 +754,7 @@ } txd = &cp->tx_ring[first_entry]; - txd->opts2 = 0; + CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr_lo = cpu_to_le32(first_mapping); wmb(); @@ -691,9 +769,7 @@ if (netif_msg_tx_queued(cp)) printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); - if (TX_BUFFS_AVAIL(cp) < 0) - BUG(); - if (TX_BUFFS_AVAIL(cp) == 0) + if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); spin_unlock_irq(&cp->lock); @@ -707,22 +783,6 @@ /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc (int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? - ethernet_polynomial : 0); - } - - return crc; -} - static void __cp_set_rx_mode (struct net_device *dev) { struct cp_private *cp = dev->priv; @@ -827,6 +887,12 @@ printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); } +static inline void cp_start_hw (struct cp_private *cp) +{ + cpw8(Cmd, RxOn | TxOn); + cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn); +} + static void cp_init_hw (struct cp_private *cp) { struct net_device *dev = cp->dev; @@ -839,8 +905,7 @@ cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - cpw8(Cmd, RxOn | TxOn); - cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn); + cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ __cp_set_rx_mode(dev); @@ -972,8 +1037,6 @@ if (netif_msg_ifup(cp)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); - cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - rc = cp_alloc_rings(cp); if (rc) return rc; @@ -1008,6 +1071,38 @@ return 0; } +static int cp_change_mtu(struct net_device *dev, int new_mtu) +{ + struct cp_private *cp = dev->priv; + int rc; + + /* check for invalid MTU, according to hardware limits */ + if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU) + return -EINVAL; + + /* if network interface not up, no need for complexity */ + if (!netif_running(dev)) { + dev->mtu = new_mtu; + cp_set_rxbufsize(cp); /* set new rx buf size */ + return 0; + } + + spin_lock_irq(&cp->lock); + + cp_stop_hw(cp); /* stop h/w and free rings */ + cp_clean_rings(cp); + + dev->mtu = new_mtu; + cp_set_rxbufsize(cp); /* set new rx buf size */ + + rc = cp_init_rings(cp); /* realloc and restart h/w */ + cp_start_hw(cp); + + spin_unlock_irq(&cp->lock); + + return rc; +} + static char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, @@ -1142,7 +1237,28 @@ return rc; } +#if CP_VLAN_TAG_USED +static void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct cp_private *cp = dev->priv; + + spin_lock_irq(&cp->lock); + cp->vlgrp = grp; + cpw16(CpCmd, cpr16(CpCmd) | RxVlanOn); + spin_unlock_irq(&cp->lock); +} + +static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct cp_private *cp = dev->priv; + spin_lock_irq(&cp->lock); + cpw16(CpCmd, cpr16(CpCmd) & ~RxVlanOn); + if (cp->vlgrp) + cp->vlgrp->vlan_devices[vid] = NULL; + spin_unlock_irq(&cp->lock); +} +#endif /* Serial EEPROM section. */ @@ -1246,6 +1362,7 @@ cp->mii_if.mdio_read = mdio_read; cp->mii_if.mdio_write = mdio_write; cp->mii_if.phy_id = CP_INTERNAL_PHY; + cp_set_rxbufsize(cp); rc = pci_enable_device(pdev); if (rc) @@ -1299,12 +1416,18 @@ dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; + dev->change_mtu = cp_change_mtu; #if 0 dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #endif #ifdef CP_TX_CHECKSUM dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; +#endif +#if CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = cp_vlan_rx_register; + dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid; #endif dev->irq = pdev->irq; diff -urN linux-2.4.18/drivers/net/8139too.c linux-2.4.19-pre5/drivers/net/8139too.c --- linux-2.4.18/drivers/net/8139too.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/8139too.c Sat Mar 30 22:55:34 2002 @@ -109,6 +109,7 @@ #include #include #include +#include #include #include @@ -597,7 +598,6 @@ static int rtl8139_close (struct net_device *dev); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); -static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); static void __set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); @@ -2396,23 +2396,6 @@ /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc (int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? - ethernet_polynomial : 0); - } - - return crc; -} - static void __set_rx_mode (struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/8390.c linux-2.4.19-pre5/drivers/net/8390.c --- linux-2.4.18/drivers/net/8390.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/8390.c Sat Mar 30 22:55:34 2002 @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -885,27 +886,6 @@ } /* - * Update the given Autodin II CRC value with another data byte. - */ - -static inline u32 update_crc(u8 byte, u32 current_crc) -{ - int bit; - u8 ah = 0; - for (bit=0; bit<8; bit++) - { - u8 carry = (current_crc>>31); - current_crc <<= 1; - ah = ((ah<<1) | carry) ^ byte; - if (ah&1) - current_crc ^= 0x04C11DB7; /* CRC polynomial */ - ah >>= 1; - byte >>= 1; - } - return current_crc; -} - -/* * Form the 64 bit 8390 multicast table from the linked list of addresses * associated with this dev structure. */ @@ -916,16 +896,13 @@ for (dmi=dev->mc_list; dmi; dmi=dmi->next) { - int i; u32 crc; if (dmi->dmi_addrlen != ETH_ALEN) { printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name); continue; } - crc = 0xffffffff; /* initial CRC value */ - for (i=0; idmi_addr[i], crc); + crc = ether_crc(ETH_ALEN, dmi->dmi_addr); /* * The 8390 uses the 6 most significant bits of the * CRC to index the multicast table. diff -urN linux-2.4.18/drivers/net/8390.h linux-2.4.19-pre5/drivers/net/8390.h --- linux-2.4.18/drivers/net/8390.h Sat Mar 16 21:15:52 2002 +++ linux-2.4.19-pre5/drivers/net/8390.h Sat Mar 30 22:55:34 2002 @@ -112,13 +112,24 @@ /* * Only generate indirect loads given a machine that needs them. + * - removed AMIGA_PCMCIA from this list, handled as ISA io now */ -#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ +#if defined(CONFIG_MAC) || \ defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \ defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \ defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) +#undef inb +#undef inb_p +#undef outb +#undef outb_p + +#define inb(port) in_8(port) +#define outb(val,port) out_8(port,val) +#define inb_p(port) in_8(port) +#define outb_p(val,port) out_8(port,val) + #else #define EI_SHIFT(x) (x) #endif diff -urN linux-2.4.18/drivers/net/Config.in linux-2.4.19-pre5/drivers/net/Config.in --- linux-2.4.18/drivers/net/Config.in Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/Config.in Sat Mar 30 22:55:40 2002 @@ -62,6 +62,9 @@ if [ "$CONFIG_MIPS_AU1000" = "y" ]; then bool ' MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + tristate ' SB1250 Ethernet support' CONFIG_NET_SB1250_MAC + fi if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi @@ -153,7 +156,7 @@ fi if [ "$CONFIG_NET_PCI" = "y" ]; then dep_tristate ' AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI - dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL + dep_tristate ' Adaptec Starfire/DuraLAN support' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then dep_tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL fi @@ -161,6 +164,7 @@ dep_tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI + dep_tristate ' TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then dep_bool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL bool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO @@ -215,10 +219,13 @@ fi if [ "$CONFIG_DECSTATION" = "y" ]; then bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi + fi if [ "$CONFIG_BAGET_MIPS" = "y" ]; then tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE fi + if [ "$CONFIG_NEC_OSPREY" = "y" ]; then + tristate ' Memory-mapped onboard NE2000-compatible ethernet' CONFIG_NE2000 + fi fi endmenu @@ -240,6 +247,7 @@ dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI +dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI endmenu @@ -281,7 +289,7 @@ dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP fi if [ ! "$CONFIG_ATM" = "n" ]; then - dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP $CONFIG_EXPERIMENTAL fi fi diff -urN linux-2.4.18/drivers/net/Makefile linux-2.4.19-pre5/drivers/net/Makefile --- linux-2.4.18/drivers/net/Makefile Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/Makefile Sat Mar 30 22:55:40 2002 @@ -78,6 +78,8 @@ obj-$(CONFIG_NS83820) += ns83820.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o mii.o +obj-$(CONFIG_TC35815) += tc35815.o +obj-$(CONFIG_TIGON3) += tg3.o ifeq ($(CONFIG_SK98LIN),y) obj-y += sk98lin/sk98lin.o @@ -129,6 +131,7 @@ obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o +obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o @@ -149,6 +152,7 @@ obj-$(CONFIG_DE620) += de620.o obj-$(CONFIG_AT1500) += lance.o obj-$(CONFIG_LANCE) += lance.o +obj-$(CONFIG_SUN3_82586) += sun3_82586.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o obj-$(CONFIG_DEFXX) += defxx.o obj-$(CONFIG_SGISEEQ) += sgiseeq.o diff -urN linux-2.4.18/drivers/net/Space.c linux-2.4.19-pre5/drivers/net/Space.c --- linux-2.4.18/drivers/net/Space.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/Space.c Sat Mar 30 22:55:34 2002 @@ -86,6 +86,7 @@ extern int sgiseeq_probe(struct net_device *); extern int atarilance_probe(struct net_device *); extern int sun3lance_probe(struct net_device *); +extern int sun3_82586_probe(struct net_device *); extern int apne_probe(struct net_device *); extern int bionet_probe(struct net_device *); extern int pamsnet_probe(struct net_device *); @@ -331,6 +332,9 @@ #endif #ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ {sun3lance_probe, 0}, +#endif +#ifdef CONFIG_SUN3_82586 /* sun3 onboard Intel 82586 chip */ + {sun3_82586_probe, 0}, #endif #ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */ {apne_probe, 0}, diff -urN linux-2.4.18/drivers/net/a2065.c linux-2.4.19-pre5/drivers/net/a2065.c --- linux-2.4.18/drivers/net/a2065.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/a2065.c Sat Mar 30 22:55:34 2002 @@ -6,6 +6,7 @@ * Fixes and tips by: * - Janos Farkas (CHEXUM@sparta.banki.hu) * - Jes Degn Soerensen (jds@kom.auc.dk) + * - Matt Domsch (Matt_Domsch@dell.com) * * ---------------------------------------------------------------------------- * @@ -47,9 +48,10 @@ #include #include #include +#include #include -#include + #include #include @@ -494,15 +496,15 @@ last_dev = dev; + /* Stop the Lance */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + /* Install the Interrupt handler */ ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ, dev->name, dev); if (ret) return ret; - /* Stop the Lance */ - ll->rap = LE_CSR0; - ll->rdp = LE_C0_STOP; - load_csrs (lp); lance_init_ring (dev); @@ -639,7 +641,7 @@ struct dev_mc_list *dmi=dev->mc_list; char *addrs; int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + u32 crc; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI){ @@ -660,21 +662,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) - for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1) - { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) - { - crc = crc ^ poly; - } - } - + crc = ether_crc_le(6, addrs); crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); } diff -urN linux-2.4.18/drivers/net/a2065.h linux-2.4.19-pre5/drivers/net/a2065.h --- linux-2.4.18/drivers/net/a2065.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/a2065.h Sat Mar 30 22:55:34 2002 @@ -43,9 +43,6 @@ }; -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* * Am7990 Control and Status Registers */ diff -urN linux-2.4.18/drivers/net/ac3200.c linux-2.4.19-pre5/drivers/net/ac3200.c --- linux-2.4.18/drivers/net/ac3200.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ac3200.c Sat Mar 30 22:55:40 2002 @@ -346,9 +346,11 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i"); -MODULE_PARM_DESC(io, "ac3200 I/O base adress(es)"); -MODULE_PARM_DESC(irq, "ac3200 IRQ number(s)"); -MODULE_PARM_DESC(mem, "ac3200 Memory base address(es)"); +MODULE_PARM_DESC(io, "I/O base adress(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(mem, "Memory base address(es)"); +MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver"); +MODULE_LICENSE("GPL"); int init_module(void) @@ -395,7 +397,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/acenic.c linux-2.4.19-pre5/drivers/net/acenic.c --- linux-2.4.18/drivers/net/acenic.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/acenic.c Sat Mar 30 22:55:40 2002 @@ -2,7 +2,7 @@ * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * - * Copyright 1998-2001 by Jes Sorensen, . + * Copyright 1998-2002 by Jes Sorensen, . * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -30,6 +30,7 @@ * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the * driver under Linux/Sparc64 * Matt Domsch : Detect Alteon 1000baseT cards + * ETHTOOL_GDRVINFO support * Chip Salzenberg : Fix race condition between tx * handler and close() cleanup. * Ken Aaker : Correct check for whether @@ -65,6 +66,10 @@ #include #include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#include +#endif + #ifdef SIOCETHTOOL #include #endif @@ -83,8 +88,10 @@ #ifdef CONFIG_ACENIC_OMIT_TIGON_I #define ACE_IS_TIGON_I(ap) 0 +#define ACE_TX_RING_ENTRIES(ap) MAX_TX_RING_ENTRIES #else #define ACE_IS_TIGON_I(ap) (ap->version == 1) +#define ACE_TX_RING_ENTRIES(ap) ap->tx_ring_entries #endif #ifndef PCI_VENDOR_ID_ALTEON @@ -314,6 +321,14 @@ #define BOARD_IDX_STATIC 0 #define BOARD_IDX_OVERFLOW -1 +#if (defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)) && \ + defined(NETIF_F_HW_VLAN_RX) +#define ACENIC_DO_VLAN 1 +#define ACE_RCB_VLAN_FLAG RCB_FLG_VLAN_ASSIST +#else +#define ACENIC_DO_VLAN 0 +#define ACE_RCB_VLAN_FLAG 0 +#endif #include "acenic.h" @@ -553,7 +568,7 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static char version[] __initdata = - "acenic.c: v0.85 11/08/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" + "acenic.c: v0.89 03/15/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev; @@ -620,10 +635,14 @@ ap = dev->priv; ap->pdev = pdev; - dev->irq = pdev->irq; dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; +#if ACENIC_DO_VLAN + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = ace_vlan_rx_register; + dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid; +#endif if (1) { static void ace_watchdog(struct net_device *dev); dev->tx_timeout = &ace_watchdog; @@ -725,9 +744,9 @@ ap->name [sizeof (ap->name) - 1] = '\0'; printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); #ifdef __sparc__ - printk("irq %s\n", __irq_itoa(dev->irq)); + printk("irq %s\n", __irq_itoa(pdev->irq)); #else - printk("irq %i\n", dev->irq); + printk("irq %i\n", pdev->irq); #endif #ifdef CONFIG_ACENIC_OMIT_TIGON_I @@ -960,6 +979,13 @@ ap->evt_ring_dma); ap->evt_ring = NULL; } + if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) { + size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES); + pci_free_consistent(ap->pdev, size, ap->tx_ring, + ap->tx_ring_dma); + } + ap->tx_ring = NULL; + if (ap->evt_prd != NULL) { pci_free_consistent(ap->pdev, sizeof(u32), (void *)ap->evt_prd, ap->evt_prd_dma); @@ -1006,12 +1032,19 @@ if (ap->evt_ring == NULL) goto fail; - size = (sizeof(struct tx_desc) * TX_RING_ENTRIES); + /* + * Only allocate a host TX ring for the Tigon II, the Tigon I + * has to use PCI registers for this ;-( + */ + if (!ACE_IS_TIGON_I(ap)) { + size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES); - ap->tx_ring = pci_alloc_consistent(ap->pdev, size, &ap->tx_ring_dma); + ap->tx_ring = pci_alloc_consistent(ap->pdev, size, + &ap->tx_ring_dma); - if (ap->tx_ring == NULL) - goto fail; + if (ap->tx_ring == NULL) + goto fail; + } ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32), &ap->evt_prd_dma); @@ -1086,6 +1119,7 @@ struct ace_private *ap; struct ace_regs *regs; struct ace_info *info = NULL; + struct pci_dev *pdev; unsigned long myjif; u64 tmp_ptr; u32 tig_ver, mac1, mac2, tmp, pci_state; @@ -1144,6 +1178,7 @@ tigonFwReleaseFix); writel(0, ®s->LocalCtrl); ap->version = 1; + ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES; break; #endif case 6: @@ -1159,6 +1194,7 @@ writel(SRAM_BANK_512K, ®s->LocalCtrl); writel(SYNC_SRAM_TIMING, ®s->MiscCfg); ap->version = 2; + ap->tx_ring_entries = MAX_TX_RING_ENTRIES; break; default: printk(KERN_WARNING " Unsupported Tigon version detected " @@ -1224,7 +1260,8 @@ * Ie. having two NICs in the machine, one will have the cache * line set at boot time, the other will not. */ - pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache_size); + pdev = ap->pdev; + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size); cache_size <<= 2; if (cache_size != SMP_CACHE_BYTES) { printk(KERN_INFO " PCI cache line size set incorrectly " @@ -1233,7 +1270,7 @@ printk("expecting %i\n", SMP_CACHE_BYTES); else { printk("correcting to %i\n", SMP_CACHE_BYTES); - pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, SMP_CACHE_BYTES >> 2); } } @@ -1265,7 +1302,7 @@ dis_pci_mem_inval[board_idx]) { if (ap->pci_command & PCI_COMMAND_INVALIDATE) { ap->pci_command &= ~PCI_COMMAND_INVALIDATE; - pci_write_config_word(ap->pdev, PCI_COMMAND, + pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command); printk(KERN_INFO " Disabling PCI memory " "write and invalidate\n"); @@ -1292,7 +1329,7 @@ "supported, PCI write and invalidate " "disabled\n", SMP_CACHE_BYTES); ap->pci_command &= ~PCI_COMMAND_INVALIDATE; - pci_write_config_word(ap->pdev, PCI_COMMAND, + pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command); } } @@ -1334,16 +1371,16 @@ if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) { printk(KERN_INFO " Enabling PCI Fast Back to Back\n"); ap->pci_command |= PCI_COMMAND_FAST_BACK; - pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); + pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command); } #endif /* * Configure DMA attributes. */ - if (!pci_set_dma_mask(ap->pdev, 0xffffffffffffffffULL)) { + if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { ap->pci_using_dac = 1; - } else if (!pci_set_dma_mask(ap->pdev, 0xffffffffULL)) { + } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) { ap->pci_using_dac = 0; } else { ecode = -ENODEV; @@ -1370,12 +1407,14 @@ goto init_error; } - ecode = request_irq(dev->irq, ace_interrupt, SA_SHIRQ, dev->name, dev); + ecode = request_irq(pdev->irq, ace_interrupt, SA_SHIRQ, + dev->name, dev); if (ecode) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", - dev->name, dev->irq); + dev->name, pdev->irq); goto init_error; - } + } else + dev->irq = pdev->irq; /* * Register the device here to be able to catch allocated @@ -1386,7 +1425,7 @@ #ifdef INDEX_DEBUG spin_lock_init(&ap->debug_lock); - ap->last_tx = TX_RING_ENTRIES - 1; + ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1; ap->last_std_rx = 0; ap->last_mini_rx = 0; #endif @@ -1427,7 +1466,8 @@ set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; - info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; + info->rx_std_ctrl.flags = + RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1442,7 +1482,8 @@ (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES))); info->rx_jumbo_ctrl.max_len = 0; - info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; + info->rx_jumbo_ctrl.flags = + RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1464,7 +1505,7 @@ RX_JUMBO_RING_ENTRIES)))); info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; info->rx_mini_ctrl.flags = - RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; + RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG; for (i = 0; i < RX_MINI_RING_ENTRIES; i++) ap->rx_mini_ring[i].flags = @@ -1494,12 +1535,30 @@ *(ap->rx_ret_prd) = 0; writel(TX_RING_BASE, ®s->WinBase); - memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc)); - set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma); + if (ACE_IS_TIGON_I(ap)) { + ap->tx_ring = (struct tx_desc *)regs->Window; + for (i = 0; i < (TIGON_I_TX_RING_ENTRIES * + sizeof(struct tx_desc) / 4); i++) { + writel(0, (unsigned long)ap->tx_ring + i * 4); + } + + set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE); + } else { + memset(ap->tx_ring, 0, + MAX_TX_RING_ENTRIES * sizeof(struct tx_desc)); - info->tx_ctrl.max_len = TX_RING_ENTRIES; - tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING; + set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma); + } + + info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap); + tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG; + + /* + * The Tigon I does not like having the TX ring in host memory ;-( + */ + if (!ACE_IS_TIGON_I(ap)) + tmp |= RCB_FLG_TX_HOST_RING; #if TX_COAL_INTS_ONLY tmp |= RCB_FLG_COAL_INT_ONLY; #endif @@ -1528,7 +1587,7 @@ ace_set_rxtx_parms(dev, 0); if (board_idx == BOARD_IDX_OVERFLOW) { - printk(KERN_WARNING "%s: more then %i NICs detected, " + printk(KERN_WARNING "%s: more than %i NICs detected, " "ignoring module parameters!\n", dev->name, ACE_MAX_MOD_PARMS); } else if (board_idx >= 0) { @@ -2201,7 +2260,13 @@ skb->ip_summed = CHECKSUM_NONE; } - netif_rx(skb); /* send it up */ + /* send it up */ +#if ACENIC_DO_VLAN + if (ap->vlgrp && (bd_flags & BD_FLG_VLAN_TAG)) { + vlan_hwaccel_rx(skb, ap->vlgrp, retdesc->vlan); + } else +#endif + netif_rx(skb); dev->last_rx = jiffies; ap->stats.rx_packets++; @@ -2260,7 +2325,7 @@ info->skb = NULL; } - idx = (idx + 1) % TX_RING_ENTRIES; + idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); } while (idx != txcsm); if (netif_queue_stopped(dev)) @@ -2353,7 +2418,7 @@ * update releases enough of space, otherwise we just * wait for device to make more work. */ - if (!tx_ring_full(txcsm, ap->tx_prd)) + if (!tx_ring_full(ap, txcsm, ap->tx_prd)) ace_tx_int(dev, txcsm, idx); } @@ -2425,6 +2490,37 @@ } +#if ACENIC_DO_VLAN +static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct ace_private *ap = dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + + ap->vlgrp = grp; + + restore_flags(flags); +} + + +static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct ace_private *ap = dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + + if (ap->vlgrp) + ap->vlgrp->vlan_devices[vid] = NULL; + + restore_flags(flags); +} +#endif /* ACENIC_DO_VLAN */ + + static int ace_open(struct net_device *dev) { struct ace_private *ap; @@ -2527,7 +2623,7 @@ save_flags(flags); cli(); - for (i = 0; i < TX_RING_ENTRIES; i++) { + for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) { struct sk_buff *skb; dma_addr_t mapping; struct tx_ring_info *info; @@ -2537,7 +2633,13 @@ mapping = pci_unmap_addr(info, mapping); if (mapping) { - memset(ap->tx_ring + i, 0, sizeof(struct tx_desc)); + if (ACE_IS_TIGON_I(ap)) { + writel(0, &ap->tx_ring[i].addr.addrhi); + writel(0, &ap->tx_ring[i].addr.addrlo); + writel(0, &ap->tx_ring[i].flagsize); + } else + memset(ap->tx_ring + i, 0, + sizeof(struct tx_desc)); pci_unmap_page(ap->pdev, mapping, pci_unmap_len(info, maplen), PCI_DMA_TODEVICE); @@ -2562,6 +2664,7 @@ return 0; } + static inline dma_addr_t ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb, struct sk_buff *tail, u32 idx) @@ -2582,15 +2685,28 @@ static inline void -ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize) +ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, + u32 flagsize, u32 vlan_tag) { #if !USE_TX_COAL_NOW flagsize &= ~BD_FLG_COAL_NOW; #endif - desc->addr.addrhi = addr >> 32; - desc->addr.addrlo = addr; - desc->flagsize = flagsize; + if (!ACE_IS_TIGON_I(ap)) { + writel(addr >> 32, &desc->addr.addrhi); + writel(addr & 0xffffffff, &desc->addr.addrlo); + writel(flagsize, &desc->flagsize); +#if ACENIC_DO_VLAN + writel(vlan_tag, &desc->vlanres); +#endif + } else { + desc->addr.addrhi = addr >> 32; + desc->addr.addrlo = addr; + desc->flagsize = flagsize; +#if ACENIC_DO_VLAN + desc->vlanres = vlan_tag; +#endif + } } @@ -2607,11 +2723,10 @@ if (early_stop_netif_stop_queue(dev)) return 1; - restart: idx = ap->tx_prd; - if (tx_ring_full(ap->tx_ret_csm, idx)) + if (tx_ring_full(ap, ap->tx_ret_csm, idx)) goto overflow; #if MAX_SKB_FRAGS @@ -2619,33 +2734,47 @@ #endif { dma_addr_t mapping; + u32 vlan_tag = 0; mapping = ace_map_tx_skb(ap, skb, skb, idx); flagsize = (skb->len << 16) | (BD_FLG_END); if (skb->ip_summed == CHECKSUM_HW) flagsize |= BD_FLG_TCP_UDP_SUM; +#if ACENIC_DO_VLAN + if (vlan_tx_tag_present(skb)) { + flagsize |= BD_FLG_VLAN_TAG; + vlan_tag = vlan_tx_tag_get(skb); + } +#endif desc = ap->tx_ring + idx; - idx = (idx + 1) % TX_RING_ENTRIES; + idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); /* Look at ace_tx_int for explanations. */ - if (tx_ring_full(ap->tx_ret_csm, idx)) + if (tx_ring_full(ap, ap->tx_ret_csm, idx)) flagsize |= BD_FLG_COAL_NOW; - ace_load_tx_bd(desc, mapping, flagsize); + ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag); } #if MAX_SKB_FRAGS else { dma_addr_t mapping; + u32 vlan_tag = 0; int i, len = 0; mapping = ace_map_tx_skb(ap, skb, NULL, idx); flagsize = ((skb->len - skb->data_len) << 16); if (skb->ip_summed == CHECKSUM_HW) flagsize |= BD_FLG_TCP_UDP_SUM; +#if ACENIC_DO_VLAN + if (vlan_tx_tag_present(skb)) { + flagsize |= BD_FLG_VLAN_TAG; + vlan_tag = vlan_tx_tag_get(skb); + } +#endif - ace_load_tx_bd(ap->tx_ring + idx, mapping, flagsize); + ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag); - idx = (idx + 1) % TX_RING_ENTRIES; + idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -2662,11 +2791,11 @@ flagsize = (frag->size << 16); if (skb->ip_summed == CHECKSUM_HW) flagsize |= BD_FLG_TCP_UDP_SUM; - idx = (idx + 1) % TX_RING_ENTRIES; + idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); if (i == skb_shinfo(skb)->nr_frags - 1) { flagsize |= BD_FLG_END; - if (tx_ring_full(ap->tx_ret_csm, idx)) + if (tx_ring_full(ap, ap->tx_ret_csm, idx)) flagsize |= BD_FLG_COAL_NOW; /* @@ -2679,7 +2808,7 @@ } pci_unmap_addr_set(info, mapping, mapping); pci_unmap_len_set(info, maplen, frag->size); - ace_load_tx_bd(desc, mapping, flagsize); + ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag); } } #endif @@ -2697,7 +2826,7 @@ * serialized, this is the only situation we have to * re-test. */ - if (!tx_ring_full(ap->tx_ret_csm, idx)) + if (!tx_ring_full(ap, ap->tx_ret_csm, idx)) netif_wake_queue(dev); } @@ -2776,8 +2905,8 @@ return -EOPNOTSUPP; if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GSET) { + switch (ecmd.cmd) { + case ETHTOOL_GSET: ecmd.supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | @@ -2825,7 +2954,8 @@ if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; - } else if (ecmd.cmd == ETHTOOL_SSET) { + + case ETHTOOL_SSET: if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -2882,7 +3012,24 @@ ace_issue_cmd(regs, &cmd); } return 0; + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "acenic", sizeof(info.driver) - 1); + sprintf(info.fw_version, "%i.%i.%i", + tigonFwReleaseMajor, tigonFwReleaseMinor, + tigonFwReleaseFix); + strncpy(info.version, version, sizeof(info.version) - 1); + if (ap && ap->pdev) + strcpy(info.bus_info, ap->pdev->slot_name); + if (copy_to_user(ifr->ifr_data, &info, sizeof(info))) + return -EFAULT; + return 0; } + default: + break; + } + #endif return -EOPNOTSUPP; diff -urN linux-2.4.18/drivers/net/acenic.h linux-2.4.19-pre5/drivers/net/acenic.h --- linux-2.4.18/drivers/net/acenic.h Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/acenic.h Sat Mar 30 22:55:40 2002 @@ -417,7 +417,16 @@ #define BD_FLG_TCP_UDP_SUM 0x01 #define BD_FLG_IP_SUM 0x02 #define BD_FLG_END 0x04 +#define BD_FLG_MORE 0x08 #define BD_FLG_JUMBO 0x10 +#define BD_FLG_UCAST 0x20 +#define BD_FLG_MCAST 0x40 +#define BD_FLG_BCAST 0x60 +#define BD_FLG_TYP_MASK 0x60 +#define BD_FLG_IP_FRAG 0x80 +#define BD_FLG_IP_FRAG_END 0x100 +#define BD_FLG_VLAN_TAG 0x200 +#define BD_FLG_FRAME_ERROR 0x400 #define BD_FLG_COAL_NOW 0x800 #define BD_FLG_MINI 0x1000 @@ -437,11 +446,12 @@ /* - * TX ring + * TX ring - maximum TX ring entries for Tigon I's is 128 */ -#define TX_RING_ENTRIES 256 -#define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) -#define TX_RING_BASE 0x3800 +#define MAX_TX_RING_ENTRIES 256 +#define TIGON_I_TX_RING_ENTRIES 128 +#define TX_RING_SIZE (MAX_TX_RING_ENTRIES * sizeof(struct tx_desc)) +#define TX_RING_BASE 0x3800 struct tx_desc{ aceaddr addr; @@ -608,7 +618,7 @@ */ struct ace_skb { - struct tx_ring_info tx_skbuff[TX_RING_ENTRIES]; + struct tx_ring_info tx_skbuff[MAX_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]; @@ -641,7 +651,7 @@ struct tx_desc *tx_ring; u32 tx_prd; volatile u32 tx_ret_csm; - struct timer_list timer; + int tx_ring_entries; /* * RX elements @@ -660,6 +670,10 @@ struct rx_desc *rx_mini_ring; struct rx_desc *rx_return_ring; +#if ACENIC_DO_VLAN + struct vlan_group *vlgrp; +#endif + int tasklet_pending, jumbo; struct tasklet_struct ace_tasklet; @@ -692,17 +706,17 @@ #define TX_RESERVED MAX_SKB_FRAGS -static inline int tx_space (u32 csm, u32 prd) +static inline int tx_space (struct ace_private *ap, u32 csm, u32 prd) { - return (csm - prd - 1) & (TX_RING_ENTRIES - 1); + return (csm - prd - 1) & (ACE_TX_RING_ENTRIES(ap) - 1); } -#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd) +#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd, ap) #if MAX_SKB_FRAGS -#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) +#define tx_ring_full(ap, csm, prd) (tx_space(ap, csm, prd) <= TX_RESERVED) #else -#define tx_ring_full 0 +#define tx_ring_full 0 #endif @@ -711,7 +725,7 @@ u64 baddr = (u64) addr; aa->addrlo = baddr & 0xffffffff; aa->addrhi = baddr >> 32; - mb(); + wmb(); } @@ -758,5 +772,9 @@ static void ace_init_cleanup(struct net_device *dev); static struct net_device_stats *ace_get_stats(struct net_device *dev); static int read_eeprom_byte(struct net_device *dev, unsigned long offset); +#if ACENIC_DO_VLAN +static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp); +static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid); +#endif #endif /* _ACENIC_H_ */ diff -urN linux-2.4.18/drivers/net/am79c961a.c linux-2.4.19-pre5/drivers/net/am79c961a.c --- linux-2.4.18/drivers/net/am79c961a.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/am79c961a.c Sat Mar 30 22:55:34 2002 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -308,33 +309,13 @@ return &priv->stats; } -static inline u32 update_crc(u32 crc, u8 byte) -{ - int i; - - for (i = 8; i != 0; i--) { - byte ^= crc & 1; - crc >>= 1; - - if (byte & 1) - crc ^= 0xedb88320; - - byte >>= 1; - } - - return crc; -} - static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash) { if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) { - int i, idx, bit; + int idx, bit; u32 crc; - crc = 0xffffffff; - - for (i = 0; i < ETH_ALEN; i++) - crc = update_crc(crc, dmi->dmi_addr[i]); + crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr); idx = crc >> 30; bit = (crc >> 26) & 15; diff -urN linux-2.4.18/drivers/net/apne.c linux-2.4.19-pre5/drivers/net/apne.c --- linux-2.4.18/drivers/net/apne.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/apne.c Sat Mar 30 22:55:34 2002 @@ -54,19 +54,19 @@ #define NE_BASE (dev->base_addr) #define NE_CMD 0x00 #define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ -#define NE_RESET 0x1f+GAYLE_ODD /* Issue a read to reset, a write to clear. */ -#define NE_IO_EXTENT 0x20 +#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ +#define NE_IO_EXTENT 0x20 -#define NE_EN0_ISR 0x07+GAYLE_ODD +#define NE_EN0_ISR 0x07 #define NE_EN0_DCFG 0x0e -#define NE_EN0_RSARLO 0x08 -#define NE_EN0_RSARHI 0x09+GAYLE_ODD -#define NE_EN0_RCNTLO 0x0a +#define NE_EN0_RSARLO 0x08 +#define NE_EN0_RSARHI 0x09 +#define NE_EN0_RCNTLO 0x0a #define NE_EN0_RXCR 0x0c -#define NE_EN0_TXCR 0x0d+GAYLE_ODD -#define NE_EN0_RCNTHI 0x0b+GAYLE_ODD -#define NE_EN0_IMR 0x0f+GAYLE_ODD +#define NE_EN0_TXCR 0x0d +#define NE_EN0_RCNTHI 0x0b +#define NE_EN0_IMR 0x0f #define NE1SM_START_PG 0x20 /* First page of TX buffer */ #define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ @@ -157,7 +157,7 @@ printk("ethernet PCMCIA card inserted\n"); if (init_pcmcia()) - return apne_probe1(dev, IOBASE+GAYLE_IO); + return apne_probe1(dev, IOBASE); else return (-ENODEV); @@ -174,12 +174,7 @@ int neX000, ctron; #endif static unsigned version_printed; - static u32 pcmcia_offsets[16]={ - 0, 1+GAYLE_ODD, 2, 3+GAYLE_ODD, - 4, 5+GAYLE_ODD, 6, 7+GAYLE_ODD, - 8, 9+GAYLE_ODD, 0xa, 0xb+GAYLE_ODD, - 0xc, 0xd+GAYLE_ODD, 0xe, 0xf+GAYLE_ODD }; - + if (ei_debug && version_printed++ == 0) printk(version); @@ -188,15 +183,15 @@ /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; - writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET); + outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); - while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) + while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk(" not found (no reset ack).\n"); return -ENODEV; } - writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ + outb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ } #ifndef MANUAL_HWADDR0 @@ -222,13 +217,13 @@ {E8390_RREAD+E8390_START, NE_CMD}, }; for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { - writeb(program_seq[i].value, ioaddr + program_seq[i].offset); + outb(program_seq[i].value, ioaddr + program_seq[i].offset); } } for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { - SA_prom[i] = readb(ioaddr + NE_DATAPORT); - SA_prom[i+1] = readb(ioaddr + NE_DATAPORT); + SA_prom[i] = inb(ioaddr + NE_DATAPORT); + SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); if (SA_prom[i] != SA_prom[i+1]) wordlength = 1; } @@ -244,7 +239,7 @@ if (wordlength == 2) { /* We must set the 8390 for word mode. */ - writeb(0x49, ioaddr + NE_EN0_DCFG); + outb(0x49, ioaddr + NE_EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; } else { @@ -271,7 +266,7 @@ #else wordlength = 2; /* We must set the 8390 for word mode. */ - writeb(0x49, ioaddr + NE_EN0_DCFG); + outb(0x49, ioaddr + NE_EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; @@ -314,7 +309,6 @@ ei_status.block_input = &apne_block_input; ei_status.block_output = &apne_block_output; ei_status.get_8390_hdr = &apne_get_8390_hdr; - ei_status.reg_offset = pcmcia_offsets; dev->open = &apne_open; dev->stop = &apne_close; NS8390_init(dev, 0); @@ -354,18 +348,18 @@ if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); - writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); ei_status.txing = 0; ei_status.dmaing = 0; /* This check _should_not_ be necessary, omit eventually. */ - while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) + while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; } - writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ + outb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ } /* Grab the 8390 specific header. Similar to the block_input routine, but @@ -390,25 +384,25 @@ } ei_status.dmaing |= 0x01; - writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); - writeb(0, nic_base + NE_EN0_RCNTHI); - writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ - writeb(ring_page, nic_base + NE_EN0_RSARHI); - writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb(ENISR_RDC, nic_base + NE_EN0_ISR); + outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); + outb(0, nic_base + NE_EN0_RCNTHI); + outb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ + outb(ring_page, nic_base + NE_EN0_RSARHI); + outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { ptrs = (short*)hdr; for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++) - *ptrs++ = readw(NE_BASE + NE_DATAPORT); + *ptrs++ = inw(NE_BASE + NE_DATAPORT); } else { ptrc = (char*)hdr; for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++) - *ptrc++ = readb(NE_BASE + NE_DATAPORT); + *ptrc++ = inb(NE_BASE + NE_DATAPORT); } - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ hdr->count = WORDSWAP(hdr->count); @@ -418,7 +412,7 @@ /* Block input and output, similar to the Crynwr packet driver. If you are porting to a new ethercard, look at the packet driver source for hints. The NEx000 doesn't share the on-board packet memory -- you have to put - the packet out through the "remote DMA" dataport using writeb. */ + the packet out through the "remote DMA" dataport using outb. */ static void apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) @@ -437,27 +431,27 @@ return; } ei_status.dmaing |= 0x01; - writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); - writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); - writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb(ENISR_RDC, nic_base + NE_EN0_ISR); + outb(count & 0xff, nic_base + NE_EN0_RCNTLO); + outb(count >> 8, nic_base + NE_EN0_RCNTHI); + outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); + outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); + outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { ptrs = (short*)buf; for (cnt = 0; cnt < (count>>1); cnt++) - *ptrs++ = readw(NE_BASE + NE_DATAPORT); + *ptrs++ = inw(NE_BASE + NE_DATAPORT); if (count & 0x01) { - buf[count-1] = readb(NE_BASE + NE_DATAPORT); + buf[count-1] = inb(NE_BASE + NE_DATAPORT); } } else { ptrc = (char*)buf; for (cnt = 0; cnt < count; cnt++) - *ptrc++ = readb(NE_BASE + NE_DATAPORT); + *ptrc++ = inb(NE_BASE + NE_DATAPORT); } - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; } @@ -486,30 +480,30 @@ } ei_status.dmaing |= 0x01; /* We should already be in page 0, but to be safe... */ - writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Now the normal output. */ - writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - writeb(0x00, nic_base + NE_EN0_RSARLO); - writeb(start_page, nic_base + NE_EN0_RSARHI); + outb(count & 0xff, nic_base + NE_EN0_RCNTLO); + outb(count >> 8, nic_base + NE_EN0_RCNTHI); + outb(0x00, nic_base + NE_EN0_RSARLO); + outb(start_page, nic_base + NE_EN0_RSARHI); - writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { ptrs = (short*)buf; for (cnt = 0; cnt < count>>1; cnt++) - writew(*ptrs++, NE_BASE+NE_DATAPORT); + outw(*ptrs++, NE_BASE+NE_DATAPORT); } else { ptrc = (char*)buf; for (cnt = 0; cnt < count; cnt++) - writeb(*ptrc++, NE_BASE + NE_DATAPORT); + outb(*ptrc++, NE_BASE + NE_DATAPORT); } dma_start = jiffies; - while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) + while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); apne_reset_8390(dev); @@ -517,7 +511,7 @@ break; } - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; return; } @@ -611,7 +605,9 @@ } #endif - writeb(config, GAYLE_ATTRIBUTE+offset); + out_8(GAYLE_ATTRIBUTE+offset, config); return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/arcnet/arc-rawmode.c linux-2.4.19-pre5/drivers/net/arcnet/arc-rawmode.c --- linux-2.4.18/drivers/net/arcnet/arc-rawmode.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/arc-rawmode.c Sat Mar 30 22:55:28 2002 @@ -83,6 +83,7 @@ arcnet_unregister_proto(&rawmode_proto); } +MODULE_LICENSE("GPL"); #endif /* MODULE */ diff -urN linux-2.4.18/drivers/net/arcnet/arc-rimi.c linux-2.4.19-pre5/drivers/net/arcnet/arc-rimi.c --- linux-2.4.18/drivers/net/arcnet/arc-rimi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/arc-rimi.c Sat Mar 30 22:55:28 2002 @@ -297,6 +297,7 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN linux-2.4.18/drivers/net/arcnet/arcnet.c linux-2.4.19-pre5/drivers/net/arcnet/arcnet.c --- linux-2.4.18/drivers/net/arcnet/arcnet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/arcnet.c Sat Mar 30 22:55:28 2002 @@ -163,6 +163,7 @@ static int debug = ARCNET_DEBUG; MODULE_PARM(debug, "i"); +MODULE_LICENSE("GPL"); int __init init_module(void) { diff -urN linux-2.4.18/drivers/net/arcnet/com20020-isa.c linux-2.4.19-pre5/drivers/net/arcnet/com20020-isa.c --- linux-2.4.18/drivers/net/arcnet/com20020-isa.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/com20020-isa.c Sat Mar 30 22:55:28 2002 @@ -133,6 +133,7 @@ MODULE_PARM(backplane, "i"); MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); +MODULE_LICENSE("GPL"); static void com20020isa_open_close(struct net_device *dev, bool open) { diff -urN linux-2.4.18/drivers/net/arcnet/com20020-pci.c linux-2.4.19-pre5/drivers/net/arcnet/com20020-pci.c --- linux-2.4.18/drivers/net/arcnet/com20020-pci.c Sun Dec 23 16:23:43 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/com20020-pci.c Sat Mar 30 22:55:28 2002 @@ -57,6 +57,7 @@ MODULE_PARM(backplane, "i"); MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); +MODULE_LICENSE("GPL"); static void com20020pci_open_close(struct net_device *dev, bool open) { diff -urN linux-2.4.18/drivers/net/arcnet/com20020.c linux-2.4.19-pre5/drivers/net/arcnet/com20020.c --- linux-2.4.18/drivers/net/arcnet/com20020.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/com20020.c Sat Mar 30 22:55:28 2002 @@ -356,6 +356,8 @@ EXPORT_SYMBOL(com20020_found); EXPORT_SYMBOL(com20020_remove); +MODULE_LICENSE("GPL"); + int init_module(void) { BUGLVL(D_NORMAL) printk(VERSION); diff -urN linux-2.4.18/drivers/net/arcnet/com90io.c linux-2.4.19-pre5/drivers/net/arcnet/com90io.c --- linux-2.4.18/drivers/net/arcnet/com90io.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/arcnet/com90io.c Sat Mar 30 22:55:28 2002 @@ -383,6 +383,7 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN linux-2.4.18/drivers/net/arcnet/com90xx.c linux-2.4.19-pre5/drivers/net/arcnet/com90xx.c --- linux-2.4.18/drivers/net/arcnet/com90xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/com90xx.c Sat Mar 30 22:55:28 2002 @@ -619,6 +619,7 @@ MODULE_PARM(irq, "i"); MODULE_PARM(shmem, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN linux-2.4.18/drivers/net/arcnet/rfc1051.c linux-2.4.19-pre5/drivers/net/arcnet/rfc1051.c --- linux-2.4.18/drivers/net/arcnet/rfc1051.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/rfc1051.c Sat Mar 30 22:55:28 2002 @@ -68,6 +68,8 @@ #ifdef MODULE +MODULE_LICENSE("GPL"); + int __init init_module(void) { printk(VERSION); diff -urN linux-2.4.18/drivers/net/arcnet/rfc1201.c linux-2.4.19-pre5/drivers/net/arcnet/rfc1201.c --- linux-2.4.18/drivers/net/arcnet/rfc1201.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arcnet/rfc1201.c Sat Mar 30 22:55:28 2002 @@ -70,6 +70,8 @@ #ifdef MODULE +MODULE_LICENSE("GPL"); + int __init init_module(void) { printk(VERSION); diff -urN linux-2.4.18/drivers/net/ariadne.c linux-2.4.19-pre5/drivers/net/ariadne.c --- linux-2.4.18/drivers/net/ariadne.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ariadne.c Sat Mar 30 22:55:34 2002 @@ -54,7 +54,7 @@ #include #include #include -#include + #include #include "ariadne.h" @@ -847,3 +847,5 @@ module_init(ariadne_probe); module_exit(ariadne_cleanup); + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/ariadne2.c linux-2.4.19-pre5/drivers/net/ariadne2.c --- linux-2.4.18/drivers/net/ariadne2.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ariadne2.c Sat Mar 30 22:55:34 2002 @@ -30,7 +30,7 @@ #include #include -#include + #include #include #include @@ -142,15 +142,15 @@ { unsigned long reset_start_time = jiffies; - writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET); + z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET); - while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) + while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk(" not found (no reset ack).\n"); return -ENODEV; } - writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ + z_writeb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */ } /* Read the 16 bytes of station address PROM. @@ -177,16 +177,16 @@ {E8390_RREAD+E8390_START, NE_CMD}, }; for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { - writeb(program_seq[i].value, ioaddr + program_seq[i].offset); + z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset); } } for (i = 0; i < 16; i++) { - SA_prom[i] = readb(ioaddr + NE_DATAPORT); - (void)readb(ioaddr + NE_DATAPORT); + SA_prom[i] = z_readb(ioaddr + NE_DATAPORT); + (void)z_readb(ioaddr + NE_DATAPORT); } /* We must set the 8390 for word mode. */ - writeb(0x49, ioaddr + NE_EN0_DCFG); + z_writeb(0x49, ioaddr + NE_EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; @@ -260,18 +260,18 @@ if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); - writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); ei_status.txing = 0; ei_status.dmaing = 0; /* This check _should_not_ be necessary, omit eventually. */ - while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) + while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; } - writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ + z_writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */ } /* Grab the 8390 specific header. Similar to the block_input routine, but @@ -294,19 +294,19 @@ } ei_status.dmaing |= 0x01; - writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); - writeb(0, nic_base + NE_EN0_RCNTHI); - writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ - writeb(ring_page, nic_base + NE_EN0_RSARHI); - writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + z_writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO); + z_writeb(0, nic_base + NE_EN0_RCNTHI); + z_writeb(0, nic_base + NE_EN0_RSARLO); /* On page boundary */ + z_writeb(ring_page, nic_base + NE_EN0_RSARHI); + z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); ptrs = (short*)hdr; for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++) - *ptrs++ = readw(NE_BASE + NE_DATAPORT); + *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ hdr->count = WORDSWAP(hdr->count); @@ -316,7 +316,7 @@ /* Block input and output, similar to the Crynwr packet driver. If you are porting to a new ethercard, look at the packet driver source for hints. The NEx000 doesn't share the on-board packet memory -- you have to put - the packet out through the "remote DMA" dataport using writeb. */ + the packet out through the "remote DMA" dataport using z_writeb. */ static void ariadne2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) @@ -334,20 +334,20 @@ return; } ei_status.dmaing |= 0x01; - writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); - writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); - writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); - writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); + z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); + z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); + z_writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO); + z_writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI); + z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD); ptrs = (short*)buf; for (cnt = 0; cnt < (count>>1); cnt++) - *ptrs++ = readw(NE_BASE + NE_DATAPORT); + *ptrs++ = z_readw(NE_BASE + NE_DATAPORT); if (count & 0x01) - buf[count-1] = readb(NE_BASE + NE_DATAPORT); + buf[count-1] = z_readb(NE_BASE + NE_DATAPORT); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; } @@ -375,24 +375,24 @@ } ei_status.dmaing |= 0x01; /* We should already be in page 0, but to be safe... */ - writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + z_writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Now the normal output. */ - writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); - writeb(count >> 8, nic_base + NE_EN0_RCNTHI); - writeb(0x00, nic_base + NE_EN0_RSARLO); - writeb(start_page, nic_base + NE_EN0_RSARHI); + z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO); + z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI); + z_writeb(0x00, nic_base + NE_EN0_RSARLO); + z_writeb(start_page, nic_base + NE_EN0_RSARHI); - writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + z_writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); ptrs = (short*)buf; for (cnt = 0; cnt < count>>1; cnt++) - writew(*ptrs++, NE_BASE+NE_DATAPORT); + z_writew(*ptrs++, NE_BASE+NE_DATAPORT); dma_start = jiffies; - while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) + while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); ariadne2_reset_8390(dev); @@ -400,7 +400,7 @@ break; } - writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ + z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; return; } @@ -423,3 +423,5 @@ module_init(ariadne2_probe); module_exit(ariadne2_cleanup); + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/arlan.c linux-2.4.19-pre5/drivers/net/arlan.c --- linux-2.4.18/drivers/net/arlan.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/arlan.c Sat Mar 30 22:55:40 2002 @@ -677,7 +677,7 @@ arlan_retransmit_now(dev); } if (!registrationBad(dev) && - priv->tx_done_delayed < jiffies && + time_after(jiffies, priv->tx_done_delayed) && priv->tx_done_delayed != 0) { TXLAST(dev).offset = 0; diff -urN linux-2.4.18/drivers/net/at1700.c linux-2.4.19-pre5/drivers/net/at1700.c --- linux-2.4.18/drivers/net/at1700.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/at1700.c Sat Mar 30 22:55:40 2002 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -464,7 +465,7 @@ #define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ /* Delay between EEPROM clock transitions. */ -#define eeprom_delay() do {} while (0); +#define eeprom_delay() do { } while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) @@ -804,27 +805,6 @@ Set the multicast/promiscuous mode for this adaptor. */ -/* The little-endian AUTODIN II ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { @@ -856,6 +836,7 @@ i++, mclist = mclist->next) set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); + outb(0x02, ioaddr + RX_MODE); /* Use normal mode. */ } save_flags(flags); diff -urN linux-2.4.18/drivers/net/atp.c linux-2.4.19-pre5/drivers/net/atp.c --- linux-2.4.18/drivers/net/atp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/atp.c Sat Mar 30 22:55:34 2002 @@ -140,6 +140,7 @@ #include #include #include +#include #include #include @@ -666,7 +667,7 @@ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 - && jiffies > dev->last_rx + HZ) { + && time_after(jiffies, dev->last_rx + HZ)) { if (net_debug > 2) printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and " "%ld jiffies status %02x CMR1 %02x.\n", dev->name, @@ -856,26 +857,6 @@ /* * Set or clear the multicast filter for this adapter. */ - -/* The little-endian AUTODIN32 ethernet CRC calculation. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} static void set_rx_mode_8002(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/au1000_eth.c linux-2.4.19-pre5/drivers/net/au1000_eth.c --- linux-2.4.18/drivers/net/au1000_eth.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/au1000_eth.c Sat Mar 30 22:55:34 2002 @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -64,6 +66,7 @@ static void *dma_alloc(size_t, dma_addr_t *); static void dma_free(void *, size_t); static void hard_stop(struct net_device *); +static void enable_rx_tx(struct net_device *dev); static int __init au1000_probe1(struct net_device *, long, int, int); static int au1000_init(struct net_device *); static int au1000_open(struct net_device *); @@ -78,15 +81,17 @@ static inline void update_tx_stats(struct net_device *, u32, u32); static inline void update_rx_stats(struct net_device *, u32); static void au1000_timer(unsigned long); -static void cleanup_buffers(struct net_device *); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); static void mdio_write(struct net_device *, int, int, u16); -static inline void sync(void); +static void dump_mii(struct net_device *dev, int phy_id); +// externs extern void ack_rise_edge_irq(unsigned int); - -static int next_dev; +extern int get_ethernet_addr(char *ethernet_addr); +extern inline void str2eaddr(unsigned char *ea, unsigned char *str); +extern inline unsigned char str2hexnum(unsigned char c); +extern char * __init prom_getcmdline(void); /* * Theory of operation @@ -105,24 +110,30 @@ /* - * Base address and interupt of the Au1000 ethernet macs + * Base address and interupt of the Au1xxx ethernet macs */ static struct { unsigned int port; int irq; } au1000_iflist[NUM_INTERFACES] = { - {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, - {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} -}; + {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, + {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} + }, + au1500_iflist[NUM_INTERFACES] = { + {AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, + {AU1500_ETH1_BASE, AU1000_ETH1_IRQ} + }; static char version[] __devinitdata = - "au1000eth.c:0.1 ppopov@mvista.com\n"; + "au1000eth.c:1.0 ppopov@mvista.com\n"; -// FIX! Need real Ethernet addresses -static unsigned char au1000_mac_addr[2][6] __devinitdata = { - {0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00}, - {0x00, 0x50, 0xc2, 0x0c, 0x40, 0x00} +/* These addresses are only used if yamon doesn't tell us what + * the mac address is, and the mac address is not passed on the + * command line. + */ +static unsigned char au1000_mac_addr[6] __devinitdata = { + 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00 }; #define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) @@ -132,11 +143,6 @@ #define cpu_to_dma32 cpu_to_be32 #define dma32_to_cpu be32_to_cpu -/* CPU pipeline flush */ -static inline void sync(void) -{ - asm volatile ("sync"); -} /* FIXME * All of the PHY code really should be detached from the MAC @@ -147,7 +153,8 @@ {"unknown", "10Base2", "10BaseT", "AUI", - "100BaseT", "100BaseTX", "100BaseFX"}; + "100BaseT", "100BaseTX", "100BaseFX" + }; int bcm_5201_init(struct net_device *dev, int phy_addr) { @@ -168,7 +175,8 @@ data = mdio_read(dev, phy_addr, MII_CONTROL); data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO; mdio_write(dev, phy_addr, MII_CONTROL, data); - //dump_mii(dev, phy_addr); + + if (au1000_debug > 4) dump_mii(dev, phy_addr); return 0; } @@ -228,10 +236,91 @@ else { *link = 0; *speed = 0; + dev->if_port = IF_PORT_UNKNOWN; + } + return 0; +} + +int lsi_80227_init(struct net_device *dev, int phy_addr) +{ + if (au1000_debug > 4) + printk("lsi_80227_init\n"); + + /* restart auto-negotiation */ + mdio_write(dev, phy_addr, 0, 0x3200); + + /* set up LEDs to correct display */ + mdio_write(dev, phy_addr, 17, 0xffc0); + + if (au1000_debug > 4) + dump_mii(dev, phy_addr); + return 0; +} + +int lsi_80227_reset(struct net_device *dev, int phy_addr) +{ + s16 mii_control, timeout; + + if (au1000_debug > 4) { + printk("lsi_80227_reset\n"); + dump_mii(dev, phy_addr); + } + + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET); + mdelay(1); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + if ((mii_control & MII_CNTL_RESET) == 0) + break; + mdelay(1); + } + if (mii_control & MII_CNTL_RESET) { + printk(KERN_ERR "%s PHY reset timeout !\n", dev->name); + return -1; } return 0; } +int +lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) +{ + u16 mii_data; + struct au1000_private *aup; + + if (!dev) { + printk(KERN_ERR "lsi_80227_status error: NULL dev\n"); + return -1; + } + aup = (struct au1000_private *) dev->priv; + + mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS); + if (mii_data & MII_STAT_LINK) { + *link = 1; + mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT); + if (mii_data & MII_LSI_STAT_SPD) { + if (mii_data & MII_LSI_STAT_FDX) { + *speed = IF_PORT_100BASEFX; + dev->if_port = IF_PORT_100BASEFX; + } + else { + *speed = IF_PORT_100BASETX; + dev->if_port = IF_PORT_100BASETX; + } + } + else { + *speed = IF_PORT_10BASET; + dev->if_port = IF_PORT_10BASET; + } + + } + else { + *link = 0; + *speed = 0; + dev->if_port = IF_PORT_UNKNOWN; + } + return 0; +} int am79c901_init(struct net_device *dev, int phy_addr) { @@ -263,6 +352,12 @@ am79c901_status, }; +struct phy_ops lsi_80227_ops = { + lsi_80227_init, + lsi_80227_reset, + lsi_80227_status, +}; + static struct mii_chip_info { const char * name; u16 phy_id0; @@ -271,6 +366,7 @@ } mii_chip_table[] = { {"Broadcom BCM5201 10/100 BaseT PHY", 0x0040, 0x6212, &bcm_5201_ops }, {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, &am79c901_ops }, + {"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops }, {0,}, }; @@ -283,7 +379,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: read_MII busy timeout!!\n", + dev->name); return -1; } } @@ -297,7 +394,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: mdio_read busy timeout!!\n", + dev->name); return -1; } } @@ -313,7 +411,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_write busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: mdio_write busy timeout!!\n", + dev->name); return; } } @@ -362,25 +461,34 @@ phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1); /* search our mii table for the current mii */ - for (i = 0; mii_chip_table[i].phy_id1; i++) + for (i = 0; mii_chip_table[i].phy_id1; i++) { if (phy_id0 == mii_chip_table[i].phy_id0 && phy_id1 == mii_chip_table[i].phy_id1) { struct mii_phy * mii_phy; - printk(KERN_INFO "%s: %s found at phy address %d\n", - dev->name, mii_chip_table[i].name, phy_addr); - if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { + printk(KERN_INFO "%s: %s at phy address %d\n", + dev->name, mii_chip_table[i].name, + phy_addr); + mii_phy = kmalloc(sizeof(struct mii_phy), + GFP_KERNEL); + if (mii_phy) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; - //mii_phy->status = mdio_read(dev, phy_addr, MII_STATUS); mii_phy->next = aup->mii; - aup->phy_ops = mii_chip_table[i].phy_ops; + aup->phy_ops = + mii_chip_table[i].phy_ops; aup->mii = mii_phy; + aup->phy_ops->phy_init(dev,phy_addr); + } else { + printk(KERN_ERR "%s: out of memory\n", + dev->name); + return -1; } /* the current mii is on our mii_info_table, try next address */ break; } + } } if (aup->mii == NULL) { @@ -390,7 +498,8 @@ /* use last PHY */ aup->phy_addr = aup->mii->phy_addr; - printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name); + printk(KERN_INFO "%s: Using %s as default\n", + dev->name, aup->mii->chip_info->name); return 0; } @@ -437,7 +546,7 @@ if (ret != NULL) { memset(ret, 0, size); *dma_handle = virt_to_bus(ret); - ret = KSEG0ADDR(ret); + ret = (void *)KSEG0ADDR(ret); } return ret; } @@ -445,11 +554,22 @@ static void dma_free(void *vaddr, size_t size) { - vaddr = KSEG0ADDR(vaddr); + vaddr = (void *)KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size)); } +static void enable_rx_tx(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk(KERN_INFO "%s: enable_rx_tx\n", dev->name); + + aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE); + au_sync_delay(10); +} + static void hard_stop(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; @@ -458,8 +578,7 @@ printk(KERN_INFO "%s: hard stop\n", dev->name); aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE); - sync(); - mdelay(10); + au_sync_delay(10); } @@ -468,39 +587,21 @@ u32 flags; struct au1000_private *aup = (struct au1000_private *) dev->priv; - if (au1000_debug > 4) - printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup); + if (au1000_debug > 4) + printk(KERN_INFO "%s: reset mac, aup %x\n", + dev->name, (unsigned)aup); spin_lock_irqsave(&aup->lock, flags); del_timer(&aup->timer); hard_stop(dev); - *aup->enable |= MAC_DMA_RESET; - sync(); - mdelay(10); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = 0; + au_sync_delay(2); aup->tx_full = 0; spin_unlock_irqrestore(&aup->lock, flags); } -static void cleanup_buffers(struct net_device *dev) -{ - int i; - struct au1000_private *aup = (struct au1000_private *) dev->priv; - - for (i=0; irx_db_inuse[i]) { - ReleaseDB(aup, aup->rx_db_inuse[i]); - aup->rx_db_inuse[i] = 0; - } - } - - for (i=0; itx_db_inuse[i]) { - ReleaseDB(aup, aup->tx_db_inuse[i]); - aup->tx_db_inuse[i] = 0; - } - } -} - /* * Setup the receive and transmit "rings". These pointers are the addresses @@ -513,44 +614,40 @@ int i; for (i=0; irx_dma_ring[i] = (volatile rx_dma_t *) ioremap_nocache((unsigned long) - (rx_base + sizeof(rx_dma_t)*i), sizeof(rx_dma_t)); + aup->rx_dma_ring[i] = + (volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i); } for (i=0; itx_dma_ring[i] = (volatile tx_dma_t *)ioremap_nocache((unsigned long) - (tx_base + sizeof(tx_dma_t)*i), sizeof(tx_dma_t)); + aup->tx_dma_ring[i] = + (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i); } } -/* - * Probe for a AU1000 ethernet controller. - */ -int __init au1000_probe(struct net_device *dev) +static int __init au1000_init_module(void) { - int base_addr = au1000_iflist[next_dev].port; - int irq = au1000_iflist[next_dev].irq; - -#ifndef CONFIG_MIPS_AU1000_ENET - return -ENODEV; -#endif - - if (au1000_debug > 4) - printk(KERN_INFO "%s: au1000_probe base_addr %x\n", - dev->name, base_addr); + int i; + int prid; + int base_addr, irq; - if (next_dev >= NUM_INTERFACES) { - return -ENODEV; - } - if (au1000_probe1(dev, base_addr, irq, next_dev) == 0) { - next_dev++; - return 0; + prid = read_32bit_cp0_register(CP0_PRID); + for (i=0; iname, ioaddr, irq); - + printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", + dev->name, ioaddr, irq); /* Initialize our private structure */ if (dev->priv == NULL) { - aup = (struct au1000_private *) kmalloc(sizeof(*aup), GFP_KERNEL); + aup = (struct au1000_private *) + kmalloc(sizeof(*aup), GFP_KERNEL); if (aup == NULL) { retval = -ENOMEM; goto free_region; @@ -597,52 +691,75 @@ /* Allocate the data buffers */ - aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); + aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * + (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); if (!aup->vaddr) { retval = -ENOMEM; goto free_region; } /* aup->mac is the base address of the MAC's registers */ - aup->mac = (volatile mac_reg_t *)ioremap_nocache((unsigned long)ioaddr, sizeof(*aup->mac)); + aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); /* Setup some variables for quick register address access */ - if (ioaddr == AU1000_ETH0_BASE) { - aup->enable = (volatile u32 *) - ioremap_nocache((unsigned long)MAC0_ENABLE, sizeof(*aup->enable)); - memcpy(dev->dev_addr, au1000_mac_addr[0], sizeof(dev->dev_addr)); + switch (ioaddr) { + case AU1000_ETH0_BASE: + case AU1500_ETH0_BASE: + /* check env variables first */ + if (!get_ethernet_addr(ethaddr)) { + memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr)); + } else { + /* Check command line */ + argptr = prom_getcmdline(); + if ((pmac = strstr(argptr, "ethaddr=")) == NULL) { + printk(KERN_INFO "%s: No mac address found\n", + dev->name); + /* use the hard coded mac addresses */ + } else { + str2eaddr(ethaddr, pmac + strlen("ethaddr=")); + memcpy(au1000_mac_addr, ethaddr, + sizeof(dev->dev_addr)); + } + } + if (ioaddr == AU1000_ETH0_BASE) + aup->enable = (volatile u32 *) + ((unsigned long)AU1000_MAC0_ENABLE); + else + aup->enable = (volatile u32 *) + ((unsigned long)AU1500_MAC0_ENABLE); + memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); - } - else if (ioaddr == AU1000_ETH1_BASE) { - aup->enable = (volatile u32 *) - ioremap_nocache((unsigned long)MAC1_ENABLE, sizeof(*aup->enable)); - memcpy(dev->dev_addr, au1000_mac_addr[1], sizeof(dev->dev_addr)); + break; + case AU1000_ETH1_BASE: + case AU1500_ETH1_BASE: + if (ioaddr == AU1000_ETH1_BASE) + aup->enable = (volatile u32 *) + ((unsigned long)AU1000_MAC1_ENABLE); + else + aup->enable = (volatile u32 *) + ((unsigned long)AU1500_MAC1_ENABLE); + memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); + dev->dev_addr[4] += 0x10; setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); - } - else { /* should never happen */ - printk (KERN_ERR "au1000 eth: bad ioaddr %x\n", (unsigned)ioaddr); - retval = -ENODEV; - goto free_region; + break; + default: + printk(KERN_ERR "%s: bad ioaddr\n", dev->name); + break; + } aup->phy_addr = PHY_ADDRESS; + /* bring the device out of reset, otherwise probing the mii * will hang */ - *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | - MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; - sync(); - mdelay(2); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | + MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + if (mii_probe(dev) != 0) { goto free_region; } - aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); - if (!link) { - printk(KERN_INFO "%s: link down resetting...\n", dev->name); - aup->phy_ops->phy_reset(dev, aup->phy_addr); - aup->phy_ops->phy_init(dev, aup->phy_addr); - } - else { - printk(KERN_INFO "%s: link up (%s)\n", dev->name, phy_link[speed]); - } pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ @@ -688,18 +805,18 @@ ether_setup(dev); /* - * The boot code uses the ethernet controller, so reset it to start fresh. - * au1000_init() expects that the device is in reset state. + * The boot code uses the ethernet controller, so reset it to start + * fresh. au1000_init() expects that the device is in reset state. */ reset_mac(dev); - return 0; free_region: release_region(ioaddr, MAC_IOSIZE); unregister_netdev(dev); - if (aup->vaddr) - dma_free((void *)aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); + if (aup->vaddr) + dma_free((void *)aup->vaddr, + MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); if (dev->priv != NULL) kfree(dev->priv); kfree(dev); @@ -723,18 +840,19 @@ struct au1000_private *aup = (struct au1000_private *) dev->priv; u32 flags; int i; - u32 value, control; + u32 control; + u16 link, speed; - if (au1000_debug > 4) printk("%s: au1000_init", dev->name); + if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name); spin_lock_irqsave(&aup->lock, flags); /* bring the device out of reset */ - value = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | - MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; - *aup->enable = value; - sync(); - mdelay(200); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | + MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; + au_sync_delay(20); aup->mac->control = 0; aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2; @@ -748,13 +866,18 @@ for (i=0; irx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE; } + au_sync(); - sync(); + aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE; #ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN; #endif + if (link && (dev->if_port == IF_PORT_100BASEFX)) { + control |= MAC_FULL_DUPLEX; + } aup->mac->control = control; + au_sync(); spin_unlock_irqrestore(&aup->lock, flags); return 0; @@ -764,23 +887,22 @@ { struct net_device *dev = (struct net_device *)data; struct au1000_private *aup = (struct au1000_private *) dev->priv; - u16 mii_data, link, speed; + unsigned char if_port; + u16 link, speed; if (!dev) { /* fatal error, don't restart the timer */ printk(KERN_ERR "au1000_timer error: NULL dev\n"); return; } - if (!(dev->flags & IFF_UP)) { - goto set_timer; - } + if_port = dev->if_port; if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) { if (link) { if (!(dev->flags & IFF_RUNNING)) { netif_carrier_on(dev); dev->flags |= IFF_RUNNING; - printk(KERN_DEBUG "%s: link up\n", dev->name); + printk(KERN_INFO "%s: link up\n", dev->name); } } else { @@ -788,12 +910,27 @@ netif_carrier_off(dev); dev->flags &= ~IFF_RUNNING; dev->if_port = 0; - printk(KERN_DEBUG "%s: link down\n", dev->name); + printk(KERN_INFO "%s: link down\n", dev->name); } } } -set_timer: + if (link && (dev->if_port != if_port) && + (dev->if_port != IF_PORT_UNKNOWN)) { + hard_stop(dev); + if (dev->if_port == IF_PORT_100BASEFX) { + printk(KERN_INFO "%s: going to full duplex\n", + dev->name); + aup->mac->control |= MAC_FULL_DUPLEX; + au_sync_delay(1); + } + else { + aup->mac->control &= ~MAC_FULL_DUPLEX; + au_sync_delay(1); + } + enable_rx_tx(dev); + } + aup->timer.expires = RUN_AT((1*HZ)); aup->timer.data = (unsigned long)dev; aup->timer.function = &au1000_timer; /* timer handler */ @@ -819,8 +956,10 @@ } netif_start_queue(dev); - if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); + if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, + dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); MOD_DEC_USE_COUNT; return retval; } @@ -860,8 +999,13 @@ return 0; } +static void __exit au1000_cleanup_module(void) +{ +} -static inline void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) + +static inline void +update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) { struct au1000_private *aup = (struct au1000_private *) dev->priv; struct net_device_stats *ps = &aup->stats; @@ -870,10 +1014,20 @@ ps->tx_bytes += pkt_len; if (status & TX_FRAME_ABORTED) { - ps->tx_errors++; - ps->tx_aborted_errors++; - if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) - ps->tx_carrier_errors++; + if (dev->if_port == IF_PORT_100BASEFX) { + if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { + /* any other tx errors are only valid + * in half duplex mode */ + ps->tx_errors++; + ps->tx_aborted_errors++; + } + } + else { + ps->tx_errors++; + ps->tx_aborted_errors++; + if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) + ps->tx_carrier_errors++; + } } } @@ -894,7 +1048,7 @@ update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); ptxd->buff_stat &= ~TX_T_DONE; ptxd->len = 0; - sync(); + au_sync(); aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1); ptxd = aup->tx_dma_ring[aup->tx_tail]; @@ -913,26 +1067,22 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - //unsigned long flags; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; int i; if (au1000_debug > 4) - printk("%s: tx: aup %x len=%d, data=%p, head %d\n", - dev->name, (unsigned)aup, skb->len, skb->data, aup->tx_head); + printk("%s: tx: aup %x len=%d, data=%p, head %d\n", + dev->name, (unsigned)aup, skb->len, + skb->data, aup->tx_head); - /* Prevent interrupts from changing the Tx ring */ - //spin_lock_irqsave(&aup->lock, flags); - ptxd = aup->tx_dma_ring[aup->tx_head]; buff_stat = ptxd->buff_stat; if (buff_stat & TX_DMA_ENABLE) { /* We've wrapped around and the transmitter is still busy */ netif_stop_queue(dev); aup->tx_full = 1; - //spin_unlock_irqrestore(&aup->lock, flags); return 1; } else if (buff_stat & TX_T_DONE) { @@ -957,11 +1107,10 @@ ptxd->len = skb->len; ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; - sync(); + au_sync(); dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); dev->trans_start = jiffies; - //spin_unlock_irqrestore(&aup->lock, flags); return 0; } @@ -1026,7 +1175,7 @@ skb_reserve(skb, 2); /* 16 byte IP header align */ eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, status & RX_FRAME_LEN_MASK, 0); - skb_put(skb, status & RX_FRAME_LEN_MASK); /* Make room */ + skb_put(skb, status & RX_FRAME_LEN_MASK); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* pass the packet to upper layers */ } @@ -1056,7 +1205,7 @@ } prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE); aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1); - sync(); + au_sync(); /* next descriptor */ prxd = aup->rx_dma_ring[aup->rx_head]; @@ -1078,8 +1227,8 @@ printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); return; } - au1000_rx(dev); au1000_tx_ack(dev); + au1000_rx(dev); } @@ -1094,29 +1243,12 @@ au1000_init(dev); } - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - /* fixme */ if (au1000_debug > 4) - printk("%s: set_multicast: flags=%x\n", dev->name, dev->flags); + printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; @@ -1134,10 +1266,12 @@ mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, + mc_filter); } aup->mac->multi_hash_high = mc_filter[1]; aup->mac->multi_hash_low = mc_filter[0]; + aup->mac->control &= ~MAC_PROMISCUOUS; aup->mac->control |= MAC_HASH_MODE; } } @@ -1145,27 +1279,27 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - //struct au1000_private *aup = (struct au1000_private *) dev->priv; u16 *data = (u16 *)&rq->ifr_data; /* fixme */ - switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ + switch (cmd) { + case SIOCGMIIPHY: /* Get the address of the PHY in use. */ + case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ data[0] = PHY_ADDRESS; - case SIOCGMIIREG: /* Read the specified MII register. */ - case SIOCDEVPRIVATE+1: /* binary compat, remove in 2.5 */ + case SIOCGMIIREG: /* Read the specified MII register. */ + case SIOCDEVPRIVATE+1: /* binary compat, remove in 2.5 */ //data[3] = mdio_read(ioaddr, data[0], data[1]); return 0; - case SIOCSMIIREG: /* Write the specified MII register */ - case SIOCDEVPRIVATE+2: /* binary compat, remove in 2.5 */ + case SIOCSMIIREG: /* Write the specified MII register */ + case SIOCDEVPRIVATE+2: /* binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; //mdio_write(ioaddr, data[0], data[1], data[2]); return 0; - default: + + default: return -EOPNOTSUPP; } } @@ -1183,7 +1317,8 @@ switch(map->port){ case IF_PORT_UNKNOWN: /* use auto here */ - printk("auto\\n"); + printk(KERN_INFO "%s: config phy for aneg\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ netif_carrier_off(dev); @@ -1193,13 +1328,15 @@ control &= ~(MII_CNTL_FDX | MII_CNTL_F100); /* enable auto negotiation and reset the negotiation */ - mdio_write(dev, aup->phy_addr, - MII_CONTROL, control | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + mdio_write(dev, aup->phy_addr, MII_CONTROL, + control | MII_CNTL_AUTO | + MII_CNTL_RST_AUTO); break; case IF_PORT_10BASET: /* 10BaseT */ - printk("10baseT\n"); + printk(KERN_INFO "%s: config phy for 10BaseT\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1207,8 +1344,8 @@ /* set Speed to 10Mbps, Half Duplex */ control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - printk("read control %x\n", control); - control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_FDX); + control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | + MII_CNTL_FDX); /* disable auto negotiation and force 10M/HD mode*/ mdio_write(dev, aup->phy_addr, MII_CONTROL, control); @@ -1216,7 +1353,8 @@ case IF_PORT_100BASET: /* 100BaseT */ case IF_PORT_100BASETX: /* 100BaseTx */ - printk("100 base T/TX\n"); + printk(KERN_INFO "%s: config phy for 100BaseTX\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1232,7 +1370,8 @@ break; case IF_PORT_100BASEFX: /* 100BaseFx */ - printk("100 Base FX\n"); + printk(KERN_INFO "%s: config phy for 100BaseFX\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1248,12 +1387,14 @@ case IF_PORT_10BASE2: /* 10Base2 */ case IF_PORT_AUI: /* AUI */ /* These Modes are not supported (are they?)*/ - printk(KERN_INFO "Not supported"); + printk(KERN_ERR "%s: 10Base2/AUI not supported", + dev->name); return -EOPNOTSUPP; break; default: - printk("Invalid"); + printk(KERN_ERR "%s: Invalid media selected", + dev->name); return -EINVAL; } return 0; @@ -1271,3 +1412,6 @@ } return 0; } + +module_init(au1000_init_module); +module_exit(au1000_cleanup_module); diff -urN linux-2.4.18/drivers/net/au1000_eth.h linux-2.4.19-pre5/drivers/net/au1000_eth.h --- linux-2.4.18/drivers/net/au1000_eth.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/au1000_eth.h Sat Mar 30 22:55:28 2002 @@ -39,7 +39,7 @@ #define ETH_TX_TIMEOUT HZ/4 #define MAC_MIN_PKT_SIZE 64 -#ifdef CONFIG_MIPS_PB1000 +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1500) #define PHY_ADDRESS 0 #define PHY_CONTROL_DEFAULT 0x3000 #define PHY_CONTROL_REG_ADDR 0 @@ -60,7 +60,9 @@ #define MII_ANLPAR 0x0005 #define MII_AEXP 0x0006 #define MII_ANEXT 0x0007 -#define MII_AUX_CNTRL 0x18 +#define MII_LSI_CONFIG 0x0011 +#define MII_LSI_STAT 0x0012 +#define MII_AUX_CNTRL 0x0018 /* mii registers specific to AMD 79C901 */ #define MII_STATUS_SUMMARY = 0x0018 @@ -123,6 +125,11 @@ #define MII_STSSUM_DPLX 0x0004 #define MII_STSSUM_AUTO 0x0002 #define MII_STSSUM_SPD 0x0001 + +/* lsi status register */ + +#define MII_LSI_STAT_FDX 0x0008 +#define MII_LSI_STAT_SPD 0x0010 /* Auxilliary Control/Status Register */ #define MII_AUX_FDX 0x0001 diff -urN linux-2.4.18/drivers/net/bmac.c linux-2.4.19-pre5/drivers/net/bmac.c --- linux-2.4.18/drivers/net/bmac.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/bmac.c Sat Mar 30 22:55:40 2002 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1048,16 +1049,13 @@ /* The version of set_multicast below was lifted from sunhme.c */ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static void bmac_set_multicast(struct net_device *dev) { struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; unsigned short rx_cfg; - u32 crc, poly = CRC_POLYNOMIAL_LE; + u32 crc; if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { bmwrite(dev, BHASH0, 0xffff); @@ -1084,17 +1082,7 @@ if(!(*addrs & 1)) continue; - crc = 0xffffffffU; - for(byte = 0; byte < 6; byte++) { - for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if(test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } diff -urN linux-2.4.18/drivers/net/bonding.c linux-2.4.19-pre5/drivers/net/bonding.c --- linux-2.4.18/drivers/net/bonding.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/bonding.c Sat Mar 30 22:55:40 2002 @@ -161,6 +161,16 @@ * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface + * + * 2002/1/2 - Chad N. Tindel + * - Restore original slave flags at release time. + * + * 2002/02/18 - Erik Habbinga + * - bond_release(): calling kfree on our_slave after call to + * bond_restore_slave_flags, not before + * - bond_enslave(): saving slave flags into original_flags before + * call to netdev_set_master, so the IFF_SLAVE flag doesn't end + * up in original_flags */ #include @@ -208,11 +218,8 @@ #define MII_ENDOF_NWAY 0x20 #undef MII_LINK_READY -/*#define MII_LINK_READY (MII_LINK_UP | MII_ENDOF_NWAY)*/ #define MII_LINK_READY (MII_LINK_UP) -#define MAX_BOND_ADDR 256 - #ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 #endif @@ -223,7 +230,7 @@ static u32 my_ip = 0; char *arp_target_hw_addr = NULL; -static int max_bonds = MAX_BONDS; +static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int miimon = BOND_LINK_MON_INTERV; static int mode = BOND_MODE_ROUNDROBIN; static int updelay = 0; @@ -234,7 +241,7 @@ static struct bonding *these_bonds = NULL; static struct net_device *dev_bonds = NULL; -MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "i"); +MODULE_PARM(max_bonds, "i"); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); MODULE_PARM(miimon, "i"); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); @@ -260,6 +267,7 @@ static void bond_mii_monitor(struct net_device *dev); static void bond_arp_monitor(struct net_device *dev); static int bond_event(struct notifier_block *this, unsigned long event, void *ptr); +static void bond_restore_slave_flags(slave_t *slave); static void bond_set_slave_inactive_flags(slave_t *slave); static void bond_set_slave_active_flags(slave_t *slave); static int bond_enslave(struct net_device *master, struct net_device *slave); @@ -282,6 +290,11 @@ #define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ (netif_running(dev) && netif_carrier_ok(dev))) +static void bond_restore_slave_flags(slave_t *slave) +{ + slave->dev->flags = slave->original_flags; +} + static void bond_set_slave_inactive_flags(slave_t *slave) { slave->state = BOND_STATE_BACKUP; @@ -513,6 +526,8 @@ } memset(new_slave, 0, sizeof(slave_t)); + /* save flags before call to netdev_set_master */ + new_slave->original_flags = slave_dev->flags; err = netdev_set_master(slave_dev, master_dev); if (err) { @@ -838,7 +853,6 @@ } else { printk(".\n"); } - kfree(our_slave); /* release the slave from its bond */ @@ -854,6 +868,9 @@ dev_close(slave); } + bond_restore_slave_flags(our_slave); + kfree(our_slave); + if (bond->current_slave == NULL) { printk(KERN_INFO "%s: now running without any active interface !\n", @@ -2038,6 +2055,13 @@ /* Find a name for this unit */ static struct net_device *dev_bond = NULL; + if (max_bonds < 1 || max_bonds > INT_MAX) { + printk(KERN_WARNING + "bonding_init(): max_bonds (%d) not in range %d-%d, " + "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); + max_bonds = BOND_DEFAULT_MAX_BONDS; + } dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), GFP_KERNEL); if (dev_bond == NULL) { diff -urN linux-2.4.18/drivers/net/daynaport.c linux-2.4.19-pre5/drivers/net/daynaport.c --- linux-2.4.18/drivers/net/daynaport.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/daynaport.c Sat Mar 30 22:55:34 2002 @@ -919,12 +919,4 @@ #endif } -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" - * version-control: t - * c-basic-offset: 4 - * tab-width: 4 - * kept-new-versions: 5 - * End: - */ +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/de4x5.c linux-2.4.19-pre5/drivers/net/de4x5.c --- linux-2.4.18/drivers/net/de4x5.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/de4x5.c Sat Mar 30 22:55:40 2002 @@ -436,6 +436,7 @@ 'pb' is now only initialized if a de4x5 chip is present. + 0.547 08-Nov-01 Use library crc32 functions by ========================================================================= */ @@ -457,6 +458,7 @@ #include #include #include +#include #include #include @@ -622,9 +624,6 @@ #define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* ** EISA bus defines */ @@ -658,15 +657,15 @@ ** DESC_ALIGN. ALIGN aligns the start address of the private memory area ** and hence the RX descriptor ring's first entry. */ -#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ -#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */ -#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */ -#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */ -#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */ -#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */ +#define DE4X5_ALIGN4 ((u_long)4 - 1) /* 1 longword align */ +#define DE4X5_ALIGN8 ((u_long)8 - 1) /* 2 longword align */ +#define DE4X5_ALIGN16 ((u_long)16 - 1) /* 4 longword align */ +#define DE4X5_ALIGN32 ((u_long)32 - 1) /* 8 longword align */ +#define DE4X5_ALIGN64 ((u_long)64 - 1) /* 16 longword align */ +#define DE4X5_ALIGN128 ((u_long)128 - 1) /* 32 longword align */ -#define ALIGN ALIGN32 /* Keep the DC21040 happy... */ -#define CACHE_ALIGN CAL_16LONG +#define DE4X5_ALIGN DE4X5_ALIGN32 /* Keep the DC21040 happy... */ +#define DE4X5_CACHE_ALIGN CAL_16LONG #define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */ /*#define DESC_ALIGN u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */ #define DESC_ALIGN @@ -1203,7 +1202,7 @@ ** Reserve a section of kernel memory for the adapter ** private area and the TX/RX descriptor rings. */ - dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, + dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + DE4X5_ALIGN, GFP_KERNEL); if (dev->priv == NULL) { return -ENOMEM; @@ -1213,7 +1212,7 @@ ** Align to a longword boundary */ tmp = dev->priv; - dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN); + dev->priv = (void *)(((u_long)dev->priv + DE4X5_ALIGN) & ~DE4X5_ALIGN); lp = (struct de4x5_private *)dev->priv; memset(dev->priv, 0, sizeof(struct de4x5_private)); lp->bus = bus.bus; @@ -1249,7 +1248,7 @@ 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; + lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN; #endif lp->rx_ring = pci_alloc_consistent(pdev, lp->dma_size, &lp->dma_rings); if (lp->rx_ring == NULL) { @@ -1279,9 +1278,9 @@ dma_rx_bufs = lp->dma_rings + (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); - dma_rx_bufs = (dma_rx_bufs + ALIGN) & ~ALIGN; + dma_rx_bufs = (dma_rx_bufs + DE4X5_ALIGN) & ~DE4X5_ALIGN; lp->rx_bufs = (char *)(((long)(lp->rx_ring + NUM_RX_DESC - + NUM_TX_DESC) + ALIGN) & ~ALIGN); + + NUM_TX_DESC) + DE4X5_ALIGN) & ~DE4X5_ALIGN); for (i=0; irx_ring[i].status = 0; lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); @@ -1490,7 +1489,7 @@ ** Fasternet chips and 4 longwords for all others: DMA errors result ** without these values. Cache align 16 long. */ - bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN; + bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | DE4X5_CACHE_ALIGN; bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0); outl(bmr, DE4X5_BMR); @@ -2050,7 +2049,7 @@ u_long iobase = dev->base_addr; int i, j, bit, byte; u16 hashcode; - u32 omr, crc, poly = CRC_POLYNOMIAL_LE; + u32 omr, crc; char *pa; unsigned char *addrs; @@ -2065,13 +2064,7 @@ addrs=dmi->dmi_addr; dmi=dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } + crc = ether_crc_le(ETH_ALEN, addrs); hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ @@ -3645,12 +3638,12 @@ struct sk_buff *ret; u_long i=0, tmp; - p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2); + p = dev_alloc_skb(IEEE802_3_SZ + DE4X5_ALIGN + 2); if (!p) return NULL; p->dev = dev; tmp = virt_to_bus(p->data); - i = ((tmp + ALIGN) & ~ALIGN) - tmp; + i = ((tmp + DE4X5_ALIGN) & ~DE4X5_ALIGN) - tmp; skb_reserve(p, i); lp->rx_ring[index].buf = cpu_to_le32(tmp + i); diff -urN linux-2.4.18/drivers/net/de620.c linux-2.4.19-pre5/drivers/net/de620.c --- linux-2.4.18/drivers/net/de620.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/de620.c Sat Mar 30 22:55:40 2002 @@ -449,11 +449,17 @@ return ret; } - if (adapter_init(dev)) - return -EIO; + if (adapter_init(dev)) { + ret = -EIO; + goto out_free_irq; + } netif_start_queue(dev); return 0; + +out_free_irq: + free_irq(dev->irq, dev); + return ret; } /************************************************ @@ -850,7 +856,10 @@ return -EBUSY; } #endif - request_region(dev->base_addr, 3, "de620"); + if (!request_region(dev->base_addr, 3, "de620")) { + printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr); + return -EBUSY; + } /* else, got it! */ printk(", Ethernet Address: %2.2X", diff -urN linux-2.4.18/drivers/net/declance.c linux-2.4.19-pre5/drivers/net/declance.c --- linux-2.4.18/drivers/net/declance.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/declance.c Sat Mar 30 22:55:34 2002 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include @@ -88,9 +89,6 @@ #endif static int type; -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - #define LE_CSR0 0 #define LE_CSR1 1 #define LE_CSR2 2 @@ -920,7 +918,7 @@ struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_BE; + u32 crc; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { @@ -945,19 +943,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) { - crc = crc ^ poly; - } - } - + crc = ether_crc(6, addrs); crc = crc >> 26; mcast_table[crc >> 3] |= 1 << (crc & 0xf); } diff -urN linux-2.4.18/drivers/net/depca.c linux-2.4.19-pre5/drivers/net/depca.c --- linux-2.4.18/drivers/net/depca.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/depca.c Sat Mar 30 22:55:34 2002 @@ -228,6 +228,8 @@ by 0.53 12-Jan-01 Release resources on failure, bss tidbits by acme@conectiva.com.br + 0.54 08-Nov-01 use library crc32 functions + by Matt_Domsch@dell.com ========================================================================= */ @@ -245,6 +247,7 @@ #include #include #include +#include #include #include #include @@ -296,9 +299,6 @@ #define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */ #define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* ** EISA bus defines */ @@ -1225,7 +1225,7 @@ char *addrs; int i, j, bit, byte; u16 hashcode; - s32 crc, poly = CRC_POLYNOMIAL_BE; + u32 crc; if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */ for (i=0; i<(HASH_TABLE_LEN>>3); i++) { @@ -1240,13 +1240,7 @@ addrs=dmi->dmi_addr; dmi=dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) { - crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0); - } - } + crc = ether_crc(ETH_ALEN, addrs); hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ for (j=0;j<5;j++) { /* ... in reverse order. */ hashcode = (hashcode << 1) | ((crc>>=1) & 1); diff -urN linux-2.4.18/drivers/net/dl2k.c linux-2.4.19-pre5/drivers/net/dl2k.c --- linux-2.4.18/drivers/net/dl2k.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/dl2k.c Sat Mar 30 22:55:40 2002 @@ -1,6 +1,6 @@ /* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ /* - Copyright (c) 2001 by D-Link Corporation + Copyright (c) 2001,2002 by D-Link Corporation Written by Edward Peng. Created 03-May-2001, base on Linux' sundance.c. @@ -27,12 +27,14 @@ Added tx_coalesce paramter. 1.07 2002/01/03 Fixed miscount of RX frame error. 1.08 2002/01/17 Fixed the multicast bug. + 1.09 2002/03/07 Move rx-poll-now to re-fill loop. + Added rio_timer() to watch rx buffers. */ #include "dl2k.h" static char version[] __devinitdata = - KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n"; + KERN_INFO "D-Link DL2000-based linux driver v1.09 2002/03/07\n"; #define MAX_UNITS 8 static int mtu[MAX_UNITS]; @@ -42,9 +44,10 @@ static int tx_flow[MAX_UNITS]; static int rx_flow[MAX_UNITS]; static int copy_thresh; -static int rx_coalesce = DEFAULT_RXC; -static int rx_timeout = DEFAULT_RXT; -static int tx_coalesce = DEFAULT_TXC; +static int rx_coalesce; /* Rx frame count each interrupt */ +static int rx_timeout; /* Rx DMA wait time in 64ns increments */ +static int tx_coalesce = DEFAULT_TXC; /* HW xmit count each TxComplete [1-8] */ + MODULE_AUTHOR ("Edward Peng"); MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter"); @@ -71,6 +74,7 @@ static int multicast_filter_limit = 0x40; static int rio_open (struct net_device *dev); +static void rio_timer (unsigned long data); static void tx_timeout (struct net_device *dev); static void alloc_list (struct net_device *dev); static int start_xmit (struct sk_buff *skb, struct net_device *dev); @@ -86,7 +90,6 @@ static int find_miiphy (struct net_device *dev); static int parse_eeprom (struct net_device *dev); static int read_eeprom (long ioaddr, int eep_addr); -static unsigned get_crc (unsigned char *p, int len); static int mii_wait_link (struct net_device *dev, int wait); static int mii_set_media (struct net_device *dev); static int mii_get_media (struct net_device *dev); @@ -147,6 +150,7 @@ np->chip_id = chip_idx; np->pdev = pdev; spin_lock_init (&np->lock); + spin_lock_init (&np->rx_lock); /* Parse manual configuration */ np->an_enable = 1; @@ -261,6 +265,7 @@ np->an_enable = 1; mii_set_media (dev); } + pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id); /* Reset all logic functions */ writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset, @@ -341,7 +346,7 @@ } /* Check CRC */ - crc = ~get_crc (sromdata, 256 - 4); + crc = ~ether_crc_le(256 - 4, sromdata); if (psrom->crc != crc) { printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); return -1; @@ -422,8 +427,10 @@ ioaddr + RxDMAIntCtrl); } /* Set RIO to poll every N*320nsec. */ - writeb (0xff, ioaddr + RxDMAPollPeriod); + writeb (0x20, ioaddr + RxDMAPollPeriod); writeb (0xff, ioaddr + TxDMAPollPeriod); + writeb (0x30, ioaddr + RxDMABurstThresh); + writeb (0x30, ioaddr + RxDMAUrgentThresh); netif_start_queue (dev); writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl); /* VLAN supported */ @@ -446,9 +453,59 @@ /* clear statistics */ get_stats (dev); + init_timer (&np->timer); + np->timer.expires = jiffies + 1*HZ; + np->timer.data = (unsigned long) dev; + np->timer.function = &rio_timer; + add_timer (&np->timer); return 0; } +static void +rio_timer (unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = dev->priv; + unsigned int entry; + int next_tick = 1*HZ; + unsigned long flags; + /* Recover rx ring exhausted error */ + if (np->cur_rx - np->old_rx >= RX_RING_SIZE) { + printk(KERN_INFO "Try to recover rx ring exhausted...\n"); + spin_lock_irqsave(&np->rx_lock, flags); + /* Re-allocate skbuffs to fill the descriptor ring */ + for (; np->cur_rx - np->old_rx > 0; np->old_rx++) { + struct sk_buff *skb; + entry = np->old_rx % RX_RING_SIZE; + /* Dropped packets don't need to re-allocate */ + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb (np->rx_buf_sz); + if (skb == NULL) { + np->rx_ring[entry].fraginfo = 0; + printk (KERN_INFO + "%s: Still unable to re-allocate Rx skbuff.#%d\n", + dev->name, entry); + break; + } + np->rx_skbuff[entry] = skb; + skb->dev = dev; + /* 16 byte align the IP header */ + skb_reserve (skb, 2); + np->rx_ring[entry].fraginfo = + cpu_to_le64 (pci_map_single + (np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE)); + } + np->rx_ring[entry].fraginfo |= + cpu_to_le64 (np->rx_buf_sz) << 48; + np->rx_ring[entry].status = 0; + } /* end for */ + spin_unlock_irqrestore (&np->rx_lock, flags); + } /* end if */ + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + static void tx_timeout (struct net_device *dev) { @@ -500,16 +557,14 @@ np->tx_ring[i].status = cpu_to_le64 (TFDDone); np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma + ((i+1)%TX_RING_SIZE) * - sizeof (struct - netdev_desc)); + sizeof (struct netdev_desc)); } /* Initialize Rx descriptors */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma + ((i + 1) % RX_RING_SIZE) * - sizeof (struct - netdev_desc)); + sizeof (struct netdev_desc)); np->rx_ring[i].status = 0; np->rx_ring[i].fraginfo = 0; np->rx_skbuff[i] = 0; @@ -530,8 +585,8 @@ skb_reserve (skb, 2); /* 16 byte align the IP header. */ /* Rubicon now supports 40 bits of addressing space. */ np->rx_ring[i].fraginfo = - cpu_to_le64 (pci_map_single - (np->pdev, skb->tail, np->rx_buf_sz, + cpu_to_le64 ( pci_map_single ( + np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48; } @@ -774,6 +829,8 @@ int entry = np->cur_rx % RX_RING_SIZE; int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx; int rx_shift; + + spin_lock (&np->rx_lock); if (np->old_rx > RX_RING_SIZE) { rx_shift = RX_RING_SIZE; np->old_rx -= rx_shift; @@ -829,12 +886,14 @@ skb_put (skb, pkt_len); } skb->protocol = eth_type_trans (skb, dev); -#if 0 +#if 0 /* Checksum done by hw, but csum value unavailable. */ - if (!(frame_status & (TCPError | UDPError | IPError))) { + if (np->pci_rev_id >= 0x0c && + !(frame_status & (TCPError | UDPError | IPError))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - } + } #endif + netif_rx (skb); dev->last_rx = jiffies; } @@ -850,9 +909,10 @@ skb = dev_alloc_skb (np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; - printk (KERN_ERR - "%s: Allocate Rx buffer error!", - dev->name); + printk (KERN_INFO + "%s: receive_packet: " + "Unable to re-allocate Rx skbuff.#%d\n", + dev->name, entry); break; } np->rx_skbuff[entry] = skb; @@ -867,13 +927,12 @@ np->rx_ring[entry].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48; np->rx_ring[entry].status = 0; + /* RxDMAPollNow */ + writel (readl (dev->base_addr + DMACtrl) | 0x00000010, + dev->base_addr + DMACtrl); } - - /* RxDMAPollNow */ - writel (readl (dev->base_addr + DMACtrl) | 0x00000010, - dev->base_addr + DMACtrl); - DEBUG_RFD_DUMP (np, 2); + spin_unlock(&np->rx_lock); return 0; } @@ -993,23 +1052,6 @@ return 0; } -#define CRC_POLY 0xedb88320 -static unsigned -get_crc (unsigned char *p, int len) -{ - int bit; - unsigned char byte; - unsigned crc = 0xffffffff; - - while (--len >= 0) { - byte = *p++; - for (bit = 0; bit < 8; bit++, byte >>= 1) { - crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0); - } - } - return crc; -} - static void set_multicast (struct net_device *dev) { @@ -1024,7 +1066,7 @@ hash_table[0] = hash_table[1] = 0; /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */ - hash_table[1] |= 0x02000000; + hash_table[1] |= cpu_to_le32(0x02000000); if (dev->flags & IFF_PROMISC) { /* Receive all frames promiscuously. */ rx_mode = ReceiveAllFrames; @@ -1038,11 +1080,16 @@ rx_mode = ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast; for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist=mclist->next) { - crc = get_crc (mclist->dmi_addr, ETH_ALEN); - for (index=0, bit=0; bit<6; bit++, crc<<=1) { - if (crc & 0x80000000) index |= 1 << bit; - } + i++, mclist=mclist->next) { + + crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr); + + /* The inverted high significant 6 bits of CRC are + used as an index to hashtable */ + for (index = 0, bit = 0; bit < 6; bit++) + if (test_bit(31 - bit, &crc)) + set_bit(bit, &index); + hash_table[index / 32] |= (1 << (index % 32)); } } else { @@ -1112,6 +1159,7 @@ np->old_rx); break; case SIOCDEVPRIVATE + 8: + printk("TX ring:\n"); for (i = 0; i < TX_RING_SIZE; i++) { desc = &np->tx_ring[i]; printk @@ -1647,7 +1695,8 @@ writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl); synchronize_irq (); free_irq (dev->irq, dev); - + del_timer_sync (&np->timer); + /* Free all the skbuffs in the queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].status = 0; @@ -1697,10 +1746,10 @@ } static struct pci_driver rio_driver = { - name:"dl2k", - id_table:rio_pci_tbl, - probe:rio_probe1, - remove:__devexit_p(rio_remove1), + name: "dl2k", + id_table: rio_pci_tbl, + probe: rio_probe1, + remove: __devexit_p(rio_remove1), }; static int __init diff -urN linux-2.4.18/drivers/net/dl2k.h linux-2.4.19-pre5/drivers/net/dl2k.h --- linux-2.4.18/drivers/net/dl2k.h Sat Mar 16 21:16:27 2002 +++ linux-2.4.19-pre5/drivers/net/dl2k.h Sat Mar 30 22:55:40 2002 @@ -1,6 +1,6 @@ /* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ /* - Copyright (c) 2001 by D-Link Corporation + Copyright (c) 2001, 2002 by D-Link Corporation Written by Edward Peng. Created 03-May-2001, base on Linux' sundance.c. @@ -26,6 +26,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -648,6 +649,7 @@ dma_addr_t rx_ring_dma; struct pci_dev *pdev; spinlock_t lock; + spinlock_t rx_lock; struct net_device_stats stats; unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int speed; /* Operating speed */ @@ -663,9 +665,11 @@ unsigned int tx_flow:1; /* Tx flow control enable */ unsigned int rx_flow:1; /* Rx flow control enable */ unsigned int phy_media:1; /* 1: fiber, 0: copper */ + unsigned char pci_rev_id; /* PCI revision ID */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */ unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */ unsigned long cur_tx, old_tx; + struct timer_list timer; int wake_polarity; char name[256]; /* net device description */ u8 duplex_polarity; diff -urN linux-2.4.18/drivers/net/dmfe.c linux-2.4.19-pre5/drivers/net/dmfe.c --- linux-2.4.18/drivers/net/dmfe.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/dmfe.c Sat Mar 30 22:55:34 2002 @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -287,72 +288,6 @@ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control 4: TX pause packet */ -unsigned long CrcTable[256] = { - 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, - 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, - 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, - 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, - 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, - 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, - 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, - 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, - 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, - 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, - 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, - 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, - 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, - 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, - 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, - 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, - 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, - 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, - 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, - 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, - 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, - 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, - 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, - 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, - 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, - 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, - 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, - 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, - 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, - 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, - 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, - 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, - 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, - 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, - 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, - 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, - 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, - 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, - 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, - 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, - 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, - 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, - 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, - 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, - 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, - 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, - 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, - 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, - 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, - 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, - 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, - 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, - 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, - 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, - 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, - 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, - 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, - 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, - 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, - 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, - 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, - 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, - 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, - 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL -}; /* function declaration ------------------------------------- */ static int dmfe_open(struct DEVICE *); @@ -381,7 +316,7 @@ static void dmfe_dynamic_reset(struct DEVICE *); static void dmfe_free_rxbuffer(struct dmfe_board_info *); static void dmfe_init_dm910x(struct DEVICE *); -static unsigned long cal_CRC(unsigned char *, unsigned int, u8); +static inline u32 cal_CRC(unsigned char *, unsigned int, u8); static void dmfe_parse_srom(struct dmfe_board_info *); static void dmfe_program_DM9801(struct dmfe_board_info *, int); static void dmfe_program_DM9802(struct dmfe_board_info *); @@ -1850,18 +1785,11 @@ * 0 : return the normal CRC (for Hash Table index) */ -unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) +static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) { - unsigned long Crc = 0xffffffff; - - while (Len--) { - Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8); - } - - if (flag) - return ~Crc; - else - return Crc; + u32 crc = ether_crc_le(Len, Data); + if (flag) crc = ~crc; + return crc; } diff -urN linux-2.4.18/drivers/net/e2100.c linux-2.4.19-pre5/drivers/net/e2100.c --- linux-2.4.18/drivers/net/e2100.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/e2100.c Sat Mar 30 22:55:40 2002 @@ -388,10 +388,12 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_E21_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_E21_CARDS) "i"); MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_E21_CARDS) "i"); -MODULE_PARM_DESC(io, "E2100 I/O base address(es)"); -MODULE_PARM_DESC(irq, "E2100 IRQ number(s)"); -MODULE_PARM_DESC(mem, " E2100 memory base address(es)"); -MODULE_PARM_DESC(xcvr, "E2100 tranceiver(s) (0=internal, 1=external)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(mem, " memory base address(es)"); +MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)"); +MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver"); +MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ @@ -440,7 +442,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/eepro100.c linux-2.4.19-pre5/drivers/net/eepro100.c --- linux-2.4.18/drivers/net/eepro100.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/eepro100.c Sat Mar 30 22:55:40 2002 @@ -64,8 +64,8 @@ /* A few values that may be tweaked. */ /* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 32 -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 64 +#define RX_RING_SIZE 64 /* How much slots multicast filter setup may take. Do not descrease without changing set_rx_mode() implementaion. */ #define TX_MULTICAST_SIZE 2 @@ -114,7 +114,6 @@ #include #include #include -#include MODULE_AUTHOR("Maintainer: Andrey V. Savochkin "); MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver"); @@ -130,17 +129,17 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(multicast_filter_limit, "i"); -MODULE_PARM_DESC(debug, "eepro100 debug level (0-6)"); -MODULE_PARM_DESC(options, "eepro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps"); -MODULE_PARM_DESC(full_duplex, "eepro100 full duplex setting(s) (1)"); -MODULE_PARM_DESC(congenb, "eepro100 Enable congestion control (1)"); -MODULE_PARM_DESC(txfifo, "eepro100 Tx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(rxfifo, "eepro100 Rx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(txdmaccount, "eepro100 Tx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rxdmaccount, "eepro100 Rx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rx_copybreak, "eepro100 copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "eepro100 maximum events handled per interrupt"); -MODULE_PARM_DESC(multicast_filter_limit, "eepro100 maximum number of filtered multicast addresses"); +MODULE_PARM_DESC(debug, "debug level (0-6)"); +MODULE_PARM_DESC(options, "Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps"); +MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); +MODULE_PARM_DESC(congenb, "Enable congestion control (1)"); +MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)"); +MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)"); +MODULE_PARM_DESC(txdmaccount, "Tx DMA burst length; 128 - disable (0-128)"); +MODULE_PARM_DESC(rxdmaccount, "Rx DMA burst length; 128 - disable (0-128)"); +MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); +MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses"); #define RUN_AT(x) (jiffies + (x)) @@ -570,6 +569,19 @@ if (speedo_debug > 0 && did_version++ == 0) printk(version); + /* save power state before pci_enable_device overwrites it */ + pm = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm) { + u16 pwr_command; + pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } + + if (pci_enable_device(pdev)) + goto err_out_free_mmio_region; + + pci_set_master(pdev); + if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), "eepro100")) { printk (KERN_ERR "eepro100: cannot reserve I/O ports\n"); @@ -600,18 +612,6 @@ pci_resource_start(pdev, 0), irq); #endif - /* save power state b4 pci_enable_device overwrites it */ - pm = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm) { - u16 pwr_command; - pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); - acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; - } - - if (pci_enable_device(pdev)) - goto err_out_free_mmio_region; - - pci_set_master(pdev); if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0) cards_found++; @@ -1074,6 +1074,51 @@ outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); } +/* + * Sometimes the receiver stops making progress. This routine knows how to + * get it going again, without losing packets or being otherwise nasty like + * a chip reset would be. Previously the driver had a whole sequence + * of if RxSuspended, if it's no buffers do one thing, if it's no resources, + * do another, etc. But those things don't really matter. Separate logic + * in the ISR provides for allocating buffers--the other half of operation + * is just making sure the receiver is active. speedo_rx_soft_reset does that. + * This problem with the old, more involved algorithm is shown up under + * ping floods on the order of 60K packets/second on a 100Mbps fdx network. + */ +static void +speedo_rx_soft_reset(struct net_device *dev) +{ + struct speedo_private *sp = dev->priv; + struct RxFD *rfd; + long ioaddr; + + ioaddr = dev->base_addr; + wait_for_cmd_done(ioaddr + SCBCmd); + if (inb(ioaddr + SCBCmd) != 0) { + printk("%s: previous command stalled\n", dev->name); + return; + } + /* + * Put the hardware into a known state. + */ + outb(RxAbort, ioaddr + SCBCmd); + + rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; + + rfd->rx_buf_addr = 0xffffffff; + + wait_for_cmd_done(ioaddr + SCBCmd); + + if (inb(ioaddr + SCBCmd) != 0) { + printk("%s: RxAbort command stalled\n", dev->name); + return; + } + outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], + ioaddr + SCBPointer); + outb(RxStart, ioaddr + SCBCmd); +} + + /* Media monitoring and control. */ static void speedo_timer(unsigned long data) { @@ -1377,9 +1422,10 @@ /* workaround for hardware bug on 10 mbit half duplex */ - if ((sp->partner == 0) || (sp->chip_id == 1)) { + if ((sp->partner == 0) && (sp->chip_id == 1)) { wait_for_cmd_done(ioaddr + SCBCmd); outb(0 , ioaddr + SCBCmd); + udelay(1); } /* Trigger the command unit resume. */ @@ -1507,82 +1553,39 @@ if ((status & 0xfc00) == 0) break; - /* Always check if all rx buffers are allocated. --SAW */ - speedo_refill_rx_buffers(dev, 0); if ((status & 0x5000) || /* Packet received, or Rx error. */ (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed) /* Need to gather the postponed packet. */ speedo_rx(dev); - if (status & 0x1000) { - spin_lock(&sp->lock); - if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */ - struct RxFD *rxf; - printk(KERN_WARNING "%s: card reports no RX buffers.\n", - dev->name); - rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; - if (rxf == NULL) { - if (speedo_debug > 2) - printk(KERN_DEBUG - "%s: NULL cur_rx in speedo_interrupt().\n", - dev->name); - sp->rx_ring_state |= RrNoMem|RrNoResources; - } else if (rxf == sp->last_rxf) { - if (speedo_debug > 2) - printk(KERN_DEBUG - "%s: cur_rx is last in speedo_interrupt().\n", - dev->name); - sp->rx_ring_state |= RrNoMem|RrNoResources; - } else - outb(RxResumeNoResources, ioaddr + SCBCmd); - } else if ((status & 0x003c) == 0x0008) { /* No resources. */ - struct RxFD *rxf; - printk(KERN_WARNING "%s: card reports no resources.\n", - dev->name); - rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; - if (rxf == NULL) { - if (speedo_debug > 2) - printk(KERN_DEBUG - "%s: NULL cur_rx in speedo_interrupt().\n", - dev->name); - sp->rx_ring_state |= RrNoMem|RrNoResources; - } else if (rxf == sp->last_rxf) { - if (speedo_debug > 2) - printk(KERN_DEBUG - "%s: cur_rx is last in speedo_interrupt().\n", - dev->name); - sp->rx_ring_state |= RrNoMem|RrNoResources; - } else { - /* Restart the receiver. */ - outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - outb(RxStart, ioaddr + SCBCmd); - } - } - sp->stats.rx_errors++; - spin_unlock(&sp->lock); - } - - if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) { - printk(KERN_WARNING - "%s: restart the receiver after a possible hang.\n", - dev->name); - spin_lock(&sp->lock); - /* Restart the receiver. - I'm not sure if it's always right to restart the receiver - here but I don't know another way to prevent receiver hangs. - 1999/12/25 SAW */ - outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - outb(RxStart, ioaddr + SCBCmd); - sp->rx_ring_state &= ~RrNoResources; - spin_unlock(&sp->lock); + /* Always check if all rx buffers are allocated. --SAW */ + speedo_refill_rx_buffers(dev, 0); + + spin_lock(&sp->lock); + /* + * The chip may have suspended reception for various reasons. + * Check for that, and re-prime it should this be the case. + */ + switch ((status >> 2) & 0xf) { + case 0: /* Idle */ + break; + case 1: /* Suspended */ + case 2: /* No resources (RxFDs) */ + case 9: /* Suspended with no more RBDs */ + case 10: /* No resources due to no RBDs */ + case 12: /* Ready with no RBDs */ + speedo_rx_soft_reset(dev); + break; + case 3: case 5: case 6: case 7: case 8: + case 11: case 13: case 14: case 15: + /* these are all reserved values */ + break; } - + + /* User interrupt, Command/Tx unit interrupt or CU not active. */ if (status & 0xA400) { - spin_lock(&sp->lock); speedo_tx_buffer_gc(dev); if (sp->tx_full && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) { @@ -1590,8 +1593,9 @@ sp->tx_full = 0; netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */ } - spin_unlock(&sp->lock); } + + spin_unlock(&sp->lock); if (--boguscnt < 0) { printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", @@ -2205,6 +2209,8 @@ if (!netif_running(dev)) return 0; + + del_timer_sync(&sp->timer); netif_device_detach(dev); outl(PortPartialReset, ioaddr + SCBPort); @@ -2237,6 +2243,8 @@ sp->rx_mode = -1; sp->flow_ctrl = sp->partner = 0; set_rx_mode(dev); + sp->timer.expires = RUN_AT(2*HZ); + add_timer(&sp->timer); return 0; } #endif /* CONFIG_PM */ diff -urN linux-2.4.18/drivers/net/epic100.c linux-2.4.19-pre5/drivers/net/epic100.c --- linux-2.4.18/drivers/net/epic100.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/epic100.c Sat Mar 30 22:55:40 2002 @@ -60,11 +60,14 @@ LK1.1.12: * fix power-up sequence + LK1.1.13: + * revert version 1.1.12, power-up sequence "fix" + */ #define DRV_NAME "epic100" -#define DRV_VERSION "1.11+LK1.1.12" -#define DRV_RELDATE "Jan 18, 2002" +#define DRV_VERSION "1.11+LK1.1.13" +#define DRV_RELDATE "Mar 20, 2002" /* The user-configurable values. @@ -131,6 +134,7 @@ #include #include #include +#include #include #include #include @@ -677,8 +681,9 @@ required by the details of which bits are reset and the transceiver wiring on the Ositech CardBus card. */ - - outl(0x12, ioaddr + MIICfg); +#if 0 + outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); +#endif if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); @@ -1301,27 +1306,6 @@ Note that we only use exclusion around actually queueing the new frame, not around filling ep->setup_frame. This is non-deterministic when re-entered but still correct. */ - -/* The little-endian AUTODIN II ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} static void set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/es3210.c linux-2.4.19-pre5/drivers/net/es3210.c --- linux-2.4.18/drivers/net/es3210.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/es3210.c Sat Mar 30 22:55:40 2002 @@ -383,9 +383,11 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ES_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ES_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_ES_CARDS) "i"); -MODULE_PARM_DESC(io, "ES3210 I/O base address(es)"); -MODULE_PARM_DESC(irq, "ES3210 IRQ number(s)"); -MODULE_PARM_DESC(mem, "ES3210 memory base address(es)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(mem, "memory base address(es)"); +MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver"); +MODULE_LICENSE("GPL"); int init_module(void) @@ -429,5 +431,4 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/ewrk3.c linux-2.4.19-pre5/drivers/net/ewrk3.c --- linux-2.4.18/drivers/net/ewrk3.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ewrk3.c Sat Mar 30 22:55:34 2002 @@ -132,6 +132,7 @@ . 0.42 22-Apr-96 Fix alloc_device() bug 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c + 0.44 08-Nov-01 use library crc32 functions ========================================================================= */ @@ -148,6 +149,7 @@ #include #include #include +#include #include #include #include @@ -207,9 +209,6 @@ #define EISA_SLOT_INC 0x1000 #endif -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - #define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */ /* @@ -1174,10 +1173,10 @@ struct dev_mc_list *dmi = dev->mc_list; u_long iobase = dev->base_addr; int i; - char *addrs, j, bit, byte; + char *addrs, bit, byte; short *p = (short *) lp->mctbl; u16 hashcode; - s32 crc, poly = CRC_POLYNOMIAL_LE; + u32 crc; spin_lock_irq(&lp->hw_lock); @@ -1219,13 +1218,7 @@ addrs = dmi->dmi_addr; dmi = dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ - /* process each address bit */ - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } + crc = ether_crc_le(ETH_ALEN, addrs); hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ diff -urN linux-2.4.18/drivers/net/fc/iph5526.c linux-2.4.19-pre5/drivers/net/fc/iph5526.c --- linux-2.4.18/drivers/net/fc/iph5526.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/fc/iph5526.c Sat Mar 30 22:55:40 2002 @@ -3871,8 +3871,11 @@ /* Wait for the Link to come up and the login process * to complete. */ - for(timeout = jiffies + 10*HZ; (timeout > jiffies) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));) + for(timeout = jiffies + 10*HZ; time_before(jiffies, timeout) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));) + { + cpu_relax(); barrier(); + } count++; no_of_hosts++; diff -urN linux-2.4.18/drivers/net/fealnx.c linux-2.4.19-pre5/drivers/net/fealnx.c --- linux-2.4.18/drivers/net/fealnx.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/fealnx.c Sat Mar 30 22:55:34 2002 @@ -84,6 +84,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -439,7 +440,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_rx(struct net_device *dev); -static inline unsigned ether_crc(int length, unsigned char *data); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -1725,26 +1725,6 @@ return &np->stats; } - - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - - return crc; -} - static void set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/gmac.c linux-2.4.19-pre5/drivers/net/gmac.c --- linux-2.4.18/drivers/net/gmac.c Sun Mar 3 17:17:06 2002 +++ linux-2.4.19-pre5/drivers/net/gmac.c Sat Mar 30 22:55:34 2002 @@ -16,6 +16,8 @@ * - PHY updates * BenH - 08/08/2001 * - Add more PHYs, fixes to sleep code + * Matt Domsch - 11/12/2001 + * - use library crc32 functions */ #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1000,14 +1003,13 @@ * Configure promisc mode and setup multicast hash table * filter */ -#define CRC_POLY 0xedb88320 static void gmac_set_multicast(struct net_device *dev) { struct gmac *gm = (struct gmac *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; int i,j,k,b; - unsigned long crc; + u32 crc; int multicast_hash = 0; int multicast_all = 0; int promisc = 0; @@ -1030,17 +1032,7 @@ hash_table[i] = 0; for (i = 0; i < dev->mc_count; i++) { - crc = ~0; - for (j = 0; j < 6; ++j) { - b = dmi->dmi_addr[j]; - for (k = 0; k < 8; ++k) { - if ((crc ^ b) & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - b >>= 1; - } - } + crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 24; /* bit number in multicast_filter */ hash_table[j >> 4] |= 1 << (15 - (j & 0xf)); dmi = dmi->next; diff -urN linux-2.4.18/drivers/net/gt96100eth.c linux-2.4.19-pre5/drivers/net/gt96100eth.c --- linux-2.4.18/drivers/net/gt96100eth.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/gt96100eth.c Sat Mar 30 22:55:28 2002 @@ -1,5 +1,5 @@ /* - * Copyright 2000 MontaVista Software Inc. + * Copyright 2000, 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. * stevel@mvista.com or source@mvista.com * @@ -22,8 +22,23 @@ * * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. * + * Revision history + * + * 11.11.2001 Moved to 2.4.14, ppopov@mvista.com. Modified driver to add + * proper gt96100A support. + * 12.05.2001 Moved eth port 0 to irq 3 (mapped to GT_SERINT0 on EV96100A) + * in order for both ports to work. Also cleaned up boot + * option support (mac address string parsing), fleshed out + * gt96100_cleanup_module(), and other general code cleanups + * . */ +#ifndef __OPTIMIZE__ +#error You must compile this file with the correct options! +#error See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + #ifndef __mips__ #error This driver only works with MIPS architectures! #endif @@ -45,34 +60,49 @@ #include #include #include +#include #include #include #include -#include "gt96100eth.h" +#define DESC_BE 1 +#define DESC_DATA_BE 1 -#ifdef GT96100_DEBUG -static int gt96100_debug = GT96100_DEBUG; -#else -static int gt96100_debug = 3; -#endif +#define GT96100_DEBUG 2 + +#include "gt96100eth.h" // prototypes -static void *dmaalloc(size_t size, dma_addr_t * dma_handle); +static void* dmaalloc(size_t size, dma_addr_t *dma_handle); static void dmafree(size_t size, void *vaddr); +static void gt96100_delay(int msec); static int gt96100_add_hash_entry(struct net_device *dev, - unsigned char *addr); + unsigned char* addr); static void read_mib_counters(struct gt96100_private *gp); -static int read_MII(struct net_device *dev, u32 reg); -static int write_MII(struct net_device *dev, u32 reg, u16 data); -static void dump_MII(struct net_device *dev); +static int read_MII(int phy_addr, u32 reg); +static int write_MII(int phy_addr, u32 reg, u16 data); +#if 0 +static void dump_tx_ring(struct net_device *dev); +static void dump_rx_ring(struct net_device *dev); +#endif +static int gt96100_init_module(void); +static void gt96100_cleanup_module(void); +static void dump_MII(int dbg_lvl, struct net_device *dev); +static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i); +static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i); +static void dump_skb(int dbg_lvl, struct net_device *dev, + struct sk_buff *skb); +static void dump_hw_addr(int dbg_lvl, struct net_device *dev, + const char* pfx, unsigned char* addr_str); static void update_stats(struct gt96100_private *gp); static void abort(struct net_device *dev, u32 abort_bits); static void hard_stop(struct net_device *dev); static void enable_ether_irq(struct net_device *dev); static void disable_ether_irq(struct net_device *dev); -static int __init gt96100_probe1(struct net_device *dev, long ioaddr, - int irq, int port_num); +static int gt96100_probe1(int port_num); +static void reset_tx(struct net_device *dev); +static void reset_rx(struct net_device *dev); +static int gt96100_check_tx_consistent(struct gt96100_private *gp); static int gt96100_init(struct net_device *dev); static int gt96100_open(struct net_device *dev); static int gt96100_close(struct net_device *dev); @@ -81,134 +111,229 @@ static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void gt96100_tx_timeout(struct net_device *dev); static void gt96100_set_rx_mode(struct net_device *dev); -static struct net_device_stats *gt96100_get_stats(struct net_device *dev); +static struct net_device_stats* gt96100_get_stats(struct net_device *dev); -static char version[] __devinitdata = - "gt96100eth.c:0.1 stevel@mvista.com\n"; +extern char * __init prom_getcmdline(void); -// FIX! Need real Ethernet addresses -static unsigned char gt96100_station_addr[2][6] __devinitdata = - { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, -{0x01, 0x02, 0x03, 0x04, 0x05, 0x07} -}; +static int max_interrupt_work = 32; #define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) #define RUN_AT(x) (jiffies + (x)) -// For reading/writing 32-bit words from/to DMA memory +// For reading/writing 32-bit words and half-words from/to DMA memory +#ifdef DESC_BE #define cpu_to_dma32 cpu_to_be32 #define dma32_to_cpu be32_to_cpu +#define cpu_to_dma16 cpu_to_be16 +#define dma16_to_cpu be16_to_cpu +#else +#define cpu_to_dma32 cpu_to_le32 +#define dma32_to_cpu le32_to_cpu +#define cpu_to_dma16 cpu_to_le16 +#define dma16_to_cpu le16_to_cpu +#endif + +static char mac0[18] = "00.02.03.04.05.06"; +static char mac1[18] = "00.01.02.03.04.05"; +MODULE_PARM(mac0, "c18"); +MODULE_PARM(mac1, "c18"); +MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0"); +MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1"); /* - * Base address and interupt of the GT96100 ethernet controllers + * Info for the GT96100 ethernet controller's ports. */ -static struct { - unsigned int port; - int irq; +static struct gt96100_if_t { + struct net_device *dev; + unsigned int iobase; // IO Base address of this port + int irq; // IRQ number of this port + char *mac_str; } gt96100_iflist[NUM_INTERFACES] = { { - GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, { - GT96100_ETH1_BASE, GT96100_ETHER1_IRQ} + NULL, + GT96100_ETH0_BASE, GT96100_ETHER0_IRQ, + mac0 + }, + { + NULL, + GT96100_ETH1_BASE, GT96100_ETHER1_IRQ, + mac1 + } }; +static inline const char* +chip_name(int chip_rev) +{ + switch (chip_rev) { + case REV_GT96100: + return "GT96100"; + case REV_GT96100A_1: + case REV_GT96100A: + return "GT96100A"; + default: + return "Unknown GT96100"; + } +} + /* DMA memory allocation, derived from pci_alloc_consistent. */ -static void *dmaalloc(size_t size, dma_addr_t * dma_handle) +static void * +dmaalloc(size_t size, dma_addr_t *dma_handle) { void *ret; - - ret = - (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(size)); - + + ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, + get_order(size)); + if (ret != NULL) { - dma_cache_inv((unsigned long) ret, size); + dma_cache_inv((unsigned long)ret, size); if (dma_handle != NULL) *dma_handle = virt_to_phys(ret); /* bump virtual address up to non-cached area */ - ret = KSEG1ADDR(ret); + ret = (void*)KSEG1ADDR(ret); } return ret; } -static void dmafree(size_t size, void *vaddr) +static void +dmafree(size_t size, void *vaddr) { - vaddr = KSEG0ADDR(vaddr); - free_pages((unsigned long) vaddr, get_order(size)); + vaddr = (void*)KSEG0ADDR(vaddr); + free_pages((unsigned long)vaddr, get_order(size)); } -static int read_MII(struct net_device *dev, u32 reg) + +static void +gt96100_delay(int ms) +{ + if (in_interrupt()) + return; + else { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ms*HZ/1000); + } +} + +static int +parse_mac_addr(struct net_device *dev, char* macstr) +{ + int i, j; + unsigned char result, value; + + for (i=0; i<6; i++) { + result = 0; + if (i != 5 && *(macstr+2) != '.') { + err(__FILE__ "invalid mac address format: %d %c\n", + i, *(macstr+2)); + return -EINVAL; + } + + for (j=0; j<2; j++) { + if (isxdigit(*macstr) && + (value = isdigit(*macstr) ? *macstr-'0' : + toupper(*macstr)-'A'+10) < 16) { + result = result*16 + value; + macstr++; + } else { + err(__FILE__ "invalid mac address " + "character: %c\n", *macstr); + return -EINVAL; + } + } + + macstr++; // step over '.' + dev->dev_addr[i] = result; + } + + return 0; +} + + +static int +read_MII(int phy_addr, u32 reg) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; int timedout = 20; - u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) | - (reg << smirRegAdBit); + u32 smir = smirOpCode | (phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit); // wait for last operation to complete while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif + gt96100_delay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII busy timeout!!\n", - dev->name); - return -1; + printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n"); + return -ENODEV; } } - + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); timedout = 20; // wait for read to complete - while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) { + while (!((smir = GT96100_READ(GT96100_ETH_SMI_REG)) & smirReadValid)) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII timeout!!\n", - dev->name); - return -1; + printk(KERN_ERR __FUNCTION__ ": timeout!!\n"); + return -ENODEV; } } - return (int) (smir & smirDataMask); + return (int)(smir & smirDataMask); +} + +static void +dump_tx_desc(int dbg_lvl, struct net_device *dev, int i) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + gt96100_td_t *td = &gp->tx_ring[i]; + + dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td)); + dbg(dbg_lvl, + " cmdstat=%04x, byte_cnt=%04x, buff_ptr=%04x, next=%04x\n", + dma32_to_cpu(td->cmdstat), + dma16_to_cpu(td->byte_cnt), + dma32_to_cpu(td->buff_ptr), + dma32_to_cpu(td->next)); +} + +static void +dump_rx_desc(int dbg_lvl, struct net_device *dev, int i) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + gt96100_rd_t *rd = &gp->rx_ring[i]; + + dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd)); + dbg(dbg_lvl, " cmdstat=%04x, buff_sz=%04x, byte_cnt=%04x, " + "buff_ptr=%04x, next=%04x\n", + dma32_to_cpu(rd->cmdstat), + dma16_to_cpu(rd->buff_sz), + dma16_to_cpu(rd->byte_cnt), + dma32_to_cpu(rd->buff_ptr), + dma32_to_cpu(rd->next)); } -static int write_MII(struct net_device *dev, u32 reg, u16 data) +static int +write_MII(int phy_addr, u32 reg, u16 data) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; int timedout = 20; - u32 smir = - (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data; + u32 smir = (phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit) | data; // wait for last operation to complete while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: write_MII busy timeout!!\n", - dev->name); + printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n"); return -1; } } @@ -217,109 +342,203 @@ return 0; } +#if 0 +// These routines work, just disabled to avoid compile warnings +static void +dump_tx_ring(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int i; + + dbg(0, __FUNCTION__ ": txno/txni/cnt=%d/%d/%d\n", + gp->tx_next_out, gp->tx_next_in, gp->tx_count); -static void dump_MII(struct net_device *dev) + for (i=0; ipriv; + int i; + + dbg(0, __FUNCTION__ ": rxno=%d\n", gp->rx_next_out); + + for (i=0; ipriv; + + if (dbg_lvl <= GT96100_DEBUG) { + for (i=0; i<7; i++) { + if ((val = read_MII(gp->phy_addr, i)) >= 0) + printk("MII Reg %d=%x\n", i, val); + } + for (i=16; i<21; i++) { + if ((val = read_MII(gp->phy_addr, i)) >= 0) + printk("MII Reg %d=%x\n", i, val); + } + } +} - for (i = 0; i < 7; i++) { - if ((val = read_MII(dev, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); - } - for (i = 16; i < 21; i++) { - if ((val = read_MII(dev, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); +static void +dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx, + unsigned char* addr_str) +{ + int i; + char buf[100], octet[5]; + + if (dbg_lvl <= GT96100_DEBUG) { + strcpy(buf, pfx); + for (i = 0; i < 6; i++) { + sprintf(octet, "%2.2x%s", + addr_str[i], i<5 ? ":" : "\n"); + strcat(buf, octet); + } + info("%s", buf); + } +} + + +static void +dump_skb(int dbg_lvl, struct net_device *dev, struct sk_buff *skb) +{ + int i; + unsigned char* skbdata; + + if (dbg_lvl <= GT96100_DEBUG) { + dbg(dbg_lvl, __FUNCTION__ + ": skb=%p, skb->data=%p, skb->len=%d\n", + skb, skb->data, skb->len); + + skbdata = (unsigned char*)KSEG1ADDR(skb->data); + + for (i=0; ilen; i++) { + if (!(i % 16)) + printk(KERN_DEBUG "\n %3.3x: %2.2x,", + i, skbdata[i]); + else + printk(KERN_DEBUG "%2.2x,", skbdata[i]); + } + printk(KERN_DEBUG "\n"); } } static int -gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr) +gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - u16 hashResult, stmp; - unsigned char ctmp, hash_ea[6]; - u32 tblEntry, *tblEntryAddr; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + //u16 hashResult, stmp; + //unsigned char ctmp, hash_ea[6]; + u32 tblEntry1, tblEntry0, *tblEntryAddr; int i; - for (i = 0; i < 6; i++) { + tblEntry1 = hteValid | hteRD; + tblEntry1 |= (u32)addr[5] << 3; + tblEntry1 |= (u32)addr[4] << 11; + tblEntry1 |= (u32)addr[3] << 19; + tblEntry1 |= ((u32)addr[2] & 0x1f) << 27; + dbg(3, __FUNCTION__ ": tblEntry1=%x\n", tblEntry1); + tblEntry0 = ((u32)addr[2] >> 5) & 0x07; + tblEntry0 |= (u32)addr[1] << 3; + tblEntry0 |= (u32)addr[0] << 11; + dbg(3, __FUNCTION__ ": tblEntry0=%x\n", tblEntry0); + +#if 0 + + for (i=0; i<6; i++) { // nibble swap ctmp = nibswap(addr[i]); // invert every nibble - hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) | - ((ctmp & 2) << 1) | ((ctmp & 4) >> 1); - hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) | - ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1); + hash_ea[i] = ((ctmp&1)<<3) | ((ctmp&8)>>3) | + ((ctmp&2)<<1) | ((ctmp&4)>>1); + hash_ea[i] |= ((ctmp&0x10)<<3) | ((ctmp&0x80)>>3) | + ((ctmp&0x20)<<1) | ((ctmp&0x40)>>1); } + dump_hw_addr(3, dev, __FUNCTION__ ": nib swap/invt addr=", hash_ea); + if (gp->hash_mode == 0) { - hashResult = ((u16) hash_ea[0] & 0xfc) << 7; - stmp = - ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f) - << 2); - stmp ^= - (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] << - 1); - stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8); + hashResult = ((u16)hash_ea[0] & 0xfc) << 7; + stmp = ((u16)hash_ea[0] & 0x03) | + (((u16)hash_ea[1] & 0x7f) << 2); + stmp ^= (((u16)hash_ea[1] >> 7) & 0x01) | + ((u16)hash_ea[2] << 1); + stmp ^= (u16)hash_ea[3] | (((u16)hash_ea[4] & 1) << 8); hashResult |= stmp; } else { - return -1; // don't support hash mode 1 + return -1; // don't support hash mode 1 } - tblEntryAddr = - (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]); + dbg(3, __FUNCTION__ ": hashResult=%x\n", hashResult); - for (i = 0; i < HASH_HOP_NUMBER; i++) { - if ((*tblEntryAddr & hteValid) - && !(*tblEntryAddr & hteSkip)) { + tblEntryAddr = + (u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]); + + dbg(3, __FUNCTION__ ": tblEntryAddr=%p\n", tblEntryAddr); + + for (i=0; i> 5) & 0x07; - tblEntry |= (u32) addr[1] << 3; - tblEntry |= (u32) addr[0] << 11; - *tblEntryAddr = cpu_to_dma32(tblEntry); + tblEntryAddr[1] = cpu_to_dma32(tblEntry1); + tblEntryAddr[0] = cpu_to_dma32(tblEntry0); break; } } if (i >= HASH_HOP_NUMBER) { - printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n", - dev->name); - return -1; // Couldn't find an unused entry + err(__FUNCTION__ ": expired!\n"); + return -1; // Couldn't find an unused entry + } + +#else + + tblEntryAddr = (u32 *)gp->hash_table; + for (i=0; imib; + u32* mib_regs = (u32*)&gp->mib; int i; - - for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++) - mib_regs[i] = - GT96100ETH_READ(gp, - GT96100_ETH_MIB_COUNT_BASE + - i * sizeof(u32)); + + for (i=0; imib; struct net_device_stats *stats = &gp->stats; - + read_mib_counters(gp); - + stats->rx_packets = mib->totalFramesReceived; stats->tx_packets = mib->framesSent; stats->rx_bytes = mib->totalByteReceived; @@ -329,8 +548,7 @@ //rx_dropped incremented by gt96100_rx //tx_dropped incremented by gt96100_tx stats->multicast = mib->multicastFramesReceived; - // Tx collisions incremented by ISR, so add in MIB Rx collisions - stats->collisions += mib->collision + mib->lateCollision; + // collisions incremented by gt96100_tx_complete stats->rx_length_errors = mib->oversizeFrames + mib->fragments; // The RxError condition means the Rx DMA encountered a // CPU owned descriptor, which, if things are working as @@ -339,13 +557,13 @@ stats->rx_crc_errors = mib->cRCError; } -static void abort(struct net_device *dev, u32 abort_bits) +static void +abort(struct net_device *dev, u32 abort_bits) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - int timedout = 100; // wait up to 100 msec for hard stop to complete + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int timedout = 100; // wait up to 100 msec for hard stop to complete - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort\n", dev->name); + dbg(3, __FUNCTION__ "\n"); // Return if neither Rx or Tx abort bits are set if (!(abort_bits & (sdcmrAR | sdcmrAT))) @@ -353,48 +571,36 @@ // make sure only the Rx/Tx abort bits are set abort_bits &= (sdcmrAR | sdcmrAT); - + spin_lock(&gp->lock); // abort any Rx/Tx DMA immediately GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits); - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort: SDMA comm = %x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_SDMA_COMM)); + dbg(3, __FUNCTION__ ": SDMA comm = %x\n", + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); // wait for abort to complete while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) { // snooze for 20 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: abort timeout!!\n", - dev->name); + err(__FUNCTION__ ": timeout!!\n"); break; } } - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name, - timedout); - spin_unlock(&gp->lock); } -static void hard_stop(struct net_device *dev) +static void +hard_stop(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; - if (gt96100_debug > 2) - printk(KERN_INFO "%s: hard stop\n", dev->name); + dbg(3, __FUNCTION__ "\n"); disable_ether_irq(dev); @@ -405,207 +611,236 @@ } -static void enable_ether_irq(struct net_device *dev) +static void +enable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; u32 intMask; - + /* + * route ethernet interrupt to GT_SERINT0 for port 0, + * GT_INT0 for port 1. + */ + int intr_mask_reg = (gp->port_num == 0) ? + GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; + + if (gp->chip_rev >= REV_GT96100A_1) { + intMask = icrTxBufferLow | icrTxEndLow | + icrTxErrorLow | icrRxOVR | icrTxUdr | + icrRxBufferQ0 | icrRxErrorQ0 | + icrMIIPhySTC | icrEtherIntSum; + } + else { + intMask = icrTxBufferLow | icrTxEndLow | + icrTxErrorLow | icrRxOVR | icrTxUdr | + icrRxBuffer | icrRxError | + icrMIIPhySTC | icrEtherIntSum; + } + // unmask interrupts - GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, - icrRxBuffer | icrTxBufferLow | icrTxEndLow | - icrRxError | icrTxErrorLow | icrRxOVR | - icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 | - icrMIIPhySTC); - - // now route ethernet interrupts to GT Int0 (eth0 and eth1 will be - // sharing it). - // FIX! The kernel's irq code should do this - intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); - intMask |= 1 << gp->port_num; - GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, intMask); + + intMask = GT96100_READ(intr_mask_reg); + intMask |= 1<port_num; + GT96100_WRITE(intr_mask_reg, intMask); } -static void disable_ether_irq(struct net_device *dev) +static void +disable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; u32 intMask; + int intr_mask_reg = (gp->port_num == 0) ? + GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; - // FIX! The kernel's irq code should do this - intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); - intMask &= ~(1 << gp->port_num); - GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); - + intMask = GT96100_READ(intr_mask_reg); + intMask &= ~(1<port_num); + GT96100_WRITE(intr_mask_reg, intMask); + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0); } /* - * Probe for a GT96100 ethernet controller. + * Init GT96100 ethernet controller driver */ -int __init gt96100_probe(struct net_device *dev) +int gt96100_init_module(void) { - unsigned int base_addr = dev ? dev->base_addr : 0; - int i; + int i, retval=0; + u16 vendor_id, device_id; + u32 cpuConfig; #ifndef CONFIG_MIPS_GT96100ETH return -ENODEV; #endif - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe\n", dev->name); + // probe for GT96100 by reading PCI0 vendor/device ID register + pcibios_read_config_word(0, 0, PCI_VENDOR_ID, &vendor_id); + pcibios_read_config_word(0, 0, PCI_DEVICE_ID, &device_id); + + if (vendor_id != PCI_VENDOR_ID_GALILEO || + (device_id != PCI_DEVICE_ID_GALILEO_GT96100 && + device_id != PCI_DEVICE_ID_GALILEO_GT96100A)) { + printk(KERN_ERR __FILE__ ": GT96100 not found!\n"); + return -ENODEV; + } - if (base_addr >= KSEG0) /* Check a single specified location. */ - return gt96100_probe1(dev, base_addr, dev->irq, 0); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - -// for (i = 0; i= 0; i--) { - int base_addr = gt96100_iflist[i].port; -#if 0 - if (check_region(base_addr, GT96100_ETH_IO_SIZE)) { - printk(KERN_ERR - "%s: gt96100_probe: ioaddr 0x%lx taken?\n", - dev->name, base_addr); - continue; - } -#endif - if (gt96100_probe1 - (dev, base_addr, gt96100_iflist[i].irq, i) == 0) - return 0; + cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); + if (cpuConfig & (1<<12)) { + printk(KERN_ERR __FILE__ + ": must be in Big Endian mode!\n"); + return -ENODEV; } - return -ENODEV; + + for (i=0; i < NUM_INTERFACES; i++) { + retval |= gt96100_probe1(i); + } + + return retval; } static int __init -gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +gt96100_probe1(int port_num) { - static unsigned version_printed = 0; struct gt96100_private *gp = NULL; - int i, retval; - u32 cpuConfig; - - // FIX! probe for GT96100 by reading a suitable register - - if (gt96100_debug > 2) - printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n", - ioaddr, irq); - - request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH"); - - cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); - if (cpuConfig & (1 << 12)) { - printk(KERN_ERR - "gt96100_probe1: must be in Big Endian mode!\n"); - retval = -ENODEV; - goto free_region; - } - - if (gt96100_debug > 2) - printk(KERN_INFO - "gt96100_probe1: chip in Big Endian mode - cool\n"); - - /* Allocate a new 'dev' if needed. */ - if (dev == NULL) - dev = init_etherdev(0, sizeof(struct gt96100_private)); - - if (gt96100_debug && version_printed++ == 0) - printk(version); - - if (irq < 0) { - printk(KERN_ERR - "gt96100_probe1: irq unknown - probing not supported\n"); - retval = -ENODEV; - goto free_region; - } - - printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n", - dev->name, ioaddr, irq); - + struct gt96100_if_t *gtif = >96100_iflist[port_num]; + int phy_addr, phy_id1, phy_id2; + u32 phyAD; + int retval; + unsigned char chip_rev; + struct net_device *dev = NULL; + + if (gtif->irq < 0) { + printk(KERN_ERR __FUNCTION__ + ": irq unknown - probing not supported\n"); + return -ENODEV; + } + + pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev); + + if (chip_rev >= REV_GT96100A_1) { + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phy_addr = (phyAD >> (5*port_num)) & 0x1f; + } else { + /* + * not sure what's this about -- probably + * a gt bug + */ + phy_addr = port_num; + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phyAD &= ~(0x1f << (port_num*5)); + phyAD |= phy_addr << (port_num*5); + GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); + } + + // probe for the external PHY + if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 || + (phy_id2 = read_MII(phy_addr, 3)) <= 0) { + printk(KERN_ERR __FUNCTION__ + ": no PHY found on MII%d\n", port_num); + return -ENODEV; + } + + if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) { + printk(KERN_ERR __FUNCTION__ ": request_region failed\n"); + return -EBUSY; + } + + dev = init_etherdev(0, sizeof(struct gt96100_private)); + gtif->dev = dev; + /* private struct aligned and zeroed by init_etherdev */ /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; - dev->irq = irq; - memcpy(dev->dev_addr, gt96100_station_addr[port_num], - sizeof(dev->dev_addr)); - - printk(KERN_INFO "%s: HW Address ", dev->name); - for (i = 0; i < sizeof(dev->dev_addr); i++) { - printk("%2.2x", dev->dev_addr[i]); - printk(i < 5 ? ":" : "\n"); + dev->base_addr = gtif->iobase; + dev->irq = gtif->irq; + + if ((retval = parse_mac_addr(dev, gtif->mac_str))) { + err(__FUNCTION__ ": MAC address parse failed\n"); + retval = -EINVAL; + goto free_region; } /* Initialize our private structure. */ if (dev->priv == NULL) { - gp = - (struct gt96100_private *) kmalloc(sizeof(*gp), + gp = (struct gt96100_private *)kmalloc(sizeof(*gp), GFP_KERNEL); if (gp == NULL) { retval = -ENOMEM; goto free_region; } - + dev->priv = gp; } gp = dev->priv; - memset(gp, 0, sizeof(*gp)); // clear it + memset(gp, 0, sizeof(*gp)); // clear it gp->port_num = port_num; gp->io_size = GT96100_ETH_IO_SIZE; gp->port_offset = port_num * GT96100_ETH_IO_SIZE; - gp->phy_addr = port_num + 1; + gp->phy_addr = phy_addr; + gp->chip_rev = chip_rev; - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe1, port %d\n", - dev->name, gp->port_num); + info("%s found at 0x%x, irq %d\n", + chip_name(gp->chip_rev), gtif->iobase, gtif->irq); + dump_hw_addr(0, dev, "HW Address ", dev->dev_addr); + info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev); + info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num); + info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2); // Allocate Rx and Tx descriptor rings if (gp->rx_ring == NULL) { // All descriptors in ring must be 16-byte aligned gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE - + - sizeof(gt96100_td_t) * TX_RING_SIZE, + + sizeof(gt96100_td_t) * TX_RING_SIZE, &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; goto free_region; } - - gp->tx_ring = - (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE); + + gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE); gp->tx_ring_dma = - gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; + gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; } - - if (gt96100_debug > 2) - printk(KERN_INFO - "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n", - dev->name, gp->rx_ring, gp->tx_ring); + + // Allocate the Rx Data Buffers + if (gp->rx_buff == NULL) { + gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE, + &gp->rx_buff_dma); + if (gp->rx_buff == NULL) { + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + retval = -ENOMEM; + goto free_region; + } + } + + dbg(3, __FUNCTION__ ": rx_ring=%p, tx_ring=%p\n", + gp->rx_ring, gp->tx_ring); // Allocate Rx Hash Table if (gp->hash_table == NULL) { - gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, - &gp->hash_table_dma); + gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE, + &gp->hash_table_dma); if (gp->hash_table == NULL) { dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + sizeof(gt96100_td_t) * TX_RING_SIZE, gp->rx_ring); + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; goto free_region; } } - - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n", - dev->name, gp->hash_table); + + dbg(3, __FUNCTION__ ": hash=%p\n", gp->hash_table); spin_lock_init(&gp->lock); - + dev->open = gt96100_open; dev->hard_start_xmit = gt96100_tx; dev->stop = gt96100_close; @@ -619,317 +854,358 @@ ether_setup(dev); return 0; - free_region: - release_region(ioaddr, gp->io_size); + free_region: + release_region(gtif->iobase, GT96100_ETH_IO_SIZE); unregister_netdev(dev); if (dev->priv != NULL) - kfree(dev->priv); - kfree(dev); - printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n", - dev->name, retval); + kfree (dev->priv); + kfree (dev); + err(__FUNCTION__ " failed. Returns %d\n", retval); return retval; } -static int gt96100_init(struct net_device *dev) +static void +reset_tx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - unsigned long flags; - u32 phyAD, ciu; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; int i; - if (gt96100_debug > 2) - printk("%s: gt96100_init: dev=%p\n", dev->name, dev); + abort(dev, sdcmrAT); - // Stop and disable Port - hard_stop(dev); - - spin_lock_irqsave(&gp->lock, flags); + for (i=0; itx_skbuff[i]) { + if (in_interrupt()) + dev_kfree_skb_irq(gp->tx_skbuff[i]); + else + dev_kfree_skb(gp->tx_skbuff[i]); + gp->tx_skbuff[i] = NULL; + } - // First things first, set-up hash table - memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it - gp->hash_mode = 0; - // Add a single entry to hash table - our ethernet address - gt96100_add_hash_entry(dev, dev->dev_addr); - // Set-up DMA ptr to hash table - GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); - - // Setup Tx descriptor ring - for (i = 0; i < TX_RING_SIZE; i++) { - gp->tx_ring[i].cmdstat = 0; // CPU owns + gp->tx_ring[i].cmdstat = 0; // CPU owns gp->tx_ring[i].byte_cnt = 0; gp->tx_ring[i].buff_ptr = 0; gp->tx_ring[i].next = - cpu_to_dma32(gp->tx_ring_dma + - sizeof(gt96100_td_t) * (i + 1)); + cpu_to_dma32(gp->tx_ring_dma + + sizeof(gt96100_td_t) * (i+1)); + dump_tx_desc(4, dev, i); } /* Wrap the ring. */ - gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma); - + gp->tx_ring[i-1].next = cpu_to_dma32(gp->tx_ring_dma); + // setup only the lowest priority TxCDP reg - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, - gp->tx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma); GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_CURR_TX_DESC_PTR0)); - - // Setup Rx descriptor ring - for (i = 0; i < RX_RING_SIZE; i++) { - dma_addr_t rx_buff_dma; + + // init Tx indeces and pkt counter + gp->tx_next_in = gp->tx_next_out = 0; + gp->tx_count = 0; + +} + +static void +reset_rx(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int i; + + abort(dev, sdcmrAR); + + for (i=0; irx_ring[i].next = - cpu_to_dma32(gp->rx_ring_dma + - sizeof(gt96100_rd_t) * (i + 1)); - if (gp->rx_buff[i] == NULL) - gp->rx_buff[i] = - dmaalloc(PKT_BUF_SZ, &rx_buff_dma); - else - rx_buff_dma = virt_to_phys(gp->rx_buff[i]); - if (gp->rx_buff[i] == NULL) - break; - gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma); - gp->rx_ring[i].buff_cnt_sz = - cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit); - // Give ownership to device, enable interrupt + cpu_to_dma32(gp->rx_ring_dma + + sizeof(gt96100_rd_t) * (i+1)); + gp->rx_ring[i].buff_ptr = + cpu_to_dma32(gp->rx_buff_dma + i*PKT_BUF_SZ); + gp->rx_ring[i].buff_sz = cpu_to_dma16(PKT_BUF_SZ); + // Give ownership to device, set first and last, enable intr gp->rx_ring[i].cmdstat = - cpu_to_dma32((u32) (rxOwn | rxEI)); + cpu_to_dma32((u32)(rxFirst | rxLast | rxOwn | rxEI)); + dump_rx_desc(4, dev, i); } + /* Wrap the ring. */ + gp->rx_ring[i-1].next = cpu_to_dma32(gp->rx_ring_dma); - if (i != RX_RING_SIZE) { - int j; - for (j = 0; j < RX_RING_SIZE; j++) { - if (gp->rx_buff[j]) { - dmafree(PKT_BUF_SZ, gp->rx_buff[j]); - gp->rx_buff[j] = NULL; - } + // Setup only the lowest priority RxFDP and RxCDP regs + for (i=0; i<4; i++) { + if (i == 0) { + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, + gp->rx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, + gp->rx_ring_dma); + } else { + GT96100ETH_WRITE(gp, + GT96100_ETH_1ST_RX_DESC_PTR0 + i*4, + 0); + GT96100ETH_WRITE(gp, + GT96100_ETH_CURR_RX_DESC_PTR0 + i*4, + 0); } - printk(KERN_ERR "%s: Rx ring allocation failed.\n", - dev->name); - spin_unlock_irqrestore(&gp->lock, flags); - return -ENOMEM; } - /* Wrap the ring. */ - gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma); + // init Rx NextOut index + gp->rx_next_out = 0; +} - // Set our MII PHY device address - phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); - phyAD &= ~(0x1f << (gp->port_num * 5)); - phyAD |= gp->phy_addr << (gp->port_num * 5); - GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); - - if (gt96100_debug > 2) - printk("%s: gt96100_init: PhyAD=%x\n", dev->name, - GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); - - // Clear all the RxFDP and RXCDP regs... - for (i = 0; i < 4; i++) { - GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4, - 0); - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4, - 0); - } - // and setup only the lowest priority RxFDP and RxCDP regs - GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, - gp->rx_ring_dma); - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, - gp->rx_ring_dma); - if (gt96100_debug > 2) - printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_1ST_RX_DESC_PTR0), - GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); - // init Rx/Tx indeces and pkt counters - gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0; - gp->tx_count = 0; +// Returns 1 if the Tx counter and indeces don't gel +static int +gt96100_check_tx_consistent(struct gt96100_private *gp) +{ + int diff = gp->tx_next_in - gp->tx_next_out; - // setup DMA + diff = diff<0 ? TX_RING_SIZE + diff : diff; + diff = gp->tx_count == TX_RING_SIZE ? diff + TX_RING_SIZE : diff; + + return (diff != gp->tx_count); +} + +static int +gt96100_init(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + u32 tmp; + u16 mii_reg; + + dbg(3, __FUNCTION__ ": dev=%p\n", dev); + dbg(3, __FUNCTION__ ": scs10_lo=%4x, scs10_hi=%4x\n", + GT96100_READ(0x8), GT96100_READ(0x10)); + dbg(3, __FUNCTION__ ": scs32_lo=%4x, scs32_hi=%4x\n", + GT96100_READ(0x18), GT96100_READ(0x20)); + + // Stop and disable Port + hard_stop(dev); + + // Setup CIU Arbiter + tmp = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); + tmp |= (0x0c << (gp->port_num*2)); // set Ether DMA req priority to hi +#ifndef DESC_BE + tmp &= ~(1<<31); // set desc endianess to little +#else + tmp |= (1<<31); +#endif + GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp); + dbg(3, __FUNCTION__ ": CIU Config=%x/%x\n", + tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + + // Set routing. + tmp = GT96100_READ(GT96100_ROUTE_MAIN) & (0x3f << 18); + tmp |= (0x07 << (18 + gp->port_num*3)); + GT96100_WRITE(GT96100_ROUTE_MAIN, tmp); + + /* set MII as peripheral func */ + tmp = GT96100_READ(GT96100_GPP_CONFIG2); + tmp |= 0x7fff << (gp->port_num*16); + GT96100_WRITE(GT96100_GPP_CONFIG2, tmp); + + /* Set up MII port pin directions */ + tmp = GT96100_READ(GT96100_GPP_IO2); + tmp |= 0x003d << (gp->port_num*16); + GT96100_WRITE(GT96100_GPP_IO2, tmp); + + // Set-up hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it + gp->hash_mode = 0; + // Add a single entry to hash table - our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + // Set-up DMA ptr to hash table + GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); + dbg(3, __FUNCTION__ ": Hash Tbl Ptr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); + + // Setup Tx + reset_tx(dev); - // FIX! this should be done by Kernel setup code - ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); - ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high - // FIX! setting the following bit causes the EV96100 board to hang!!! - //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset??? - // FIX! endian mode??? - ciu &= ~(1 << 31); // set desc endianess to Big - GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu); - if (gt96100_debug > 2) - printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name, - ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + dbg(3, __FUNCTION__ ": Curr Tx Desc Ptr0=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0)); + + // Setup Rx + reset_rx(dev); + + dbg(3, __FUNCTION__ ": 1st/Curr Rx Desc Ptr0=%x/%x\n", + GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0), + GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); + + // eth port config register + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen); + + mii_reg = read_MII(gp->phy_addr, 0x11); /* int enable register */ + mii_reg |= 2; /* enable mii interrupt */ + write_MII(gp->phy_addr, 0x11, mii_reg); + + dbg(3, __FUNCTION__ ": PhyAD=%x\n", + GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); + + // setup DMA // We want the Rx/Tx DMA to write/read data to/from memory in // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. - // FIX! endian mode??? +#ifdef DESC_DATA_BE + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG, + (0xf< 2) - printk("%s: gt96100_init: SDMA Config=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG)); + sdcrBLMR | sdcrBLMT | + (0xf< 2) - printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); - - // enable interrupts - enable_ether_irq(dev); - + dbg(3, __FUNCTION__ ": SDMA Comm=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); + + // enable this port (set hash size to 1/2K) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); + dbg(3, __FUNCTION__ ": Port Config=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + /* * Disable all Type-of-Service queueing. All Rx packets will be * treated normally and will be sent to the lowest priority * queue. * - * Disable flow-control for now. FIX! support flow control? + * Disable flow-control for now. FIXME: support flow control? */ + // clear all the MIB ctr regs - // Enable reg clear on read. FIX! desc of this bit is inconsistent - // in the GT-96100A datasheet. GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, - pcxrFCTL | pcxrFCTLen | pcxrFLP); + pcxrFCTL | pcxrFCTLen | pcxrFLP | + pcxrPRIOrxOverride); read_mib_counters(gp); GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, - pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode); + pcxrFCTL | pcxrFCTLen | pcxrFLP | + pcxrPRIOrxOverride | pcxrMIBclrMode); + + dbg(3, __FUNCTION__ ": Port Config Ext=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); + netif_start_queue(dev); - // enable this port (set hash size to 1/2K) - GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Port Config=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + dump_MII(4, dev); - // we should now be receiving frames - if (gt96100_debug > 2) - dump_MII(dev); + // enable interrupts + enable_ether_irq(dev); - spin_unlock_irqrestore(&gp->lock, flags); + // we should now be receiving frames return 0; } -static int gt96100_open(struct net_device *dev) +static int +gt96100_open(struct net_device *dev) { int retval; - + MOD_INC_USE_COUNT; - if (gt96100_debug > 2) - printk("%s: gt96100_open: dev=%p\n", dev->name, dev); + dbg(2, __FUNCTION__ ": dev=%p\n", dev); - if ((retval = request_irq(dev->irq, >96100_interrupt, - SA_SHIRQ, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, - dev->irq); - MOD_DEC_USE_COUNT; - return retval; - } // Initialize and startup the GT-96100 ethernet port if ((retval = gt96100_init(dev))) { - printk(KERN_ERR "%s: error in gt96100_init\n", dev->name); + err("error in gt96100_init\n"); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return retval; } - netif_start_queue(dev); - - if (gt96100_debug > 2) - printk("%s: gt96100_open: Initialization done.\n", - dev->name); + if ((retval = request_irq(dev->irq, >96100_interrupt, + SA_SHIRQ, dev->name, dev))) { + err("unable to get IRQ %d\n", dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + dbg(2, __FUNCTION__ ": Initialization done.\n"); return 0; } -static int gt96100_close(struct net_device *dev) +static int +gt96100_close(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - int i; - - if (gt96100_debug > 2) - printk("%s: gt96100_close: dev=%p\n", dev->name, dev); + dbg(3, __FUNCTION__ ": dev=%p\n", dev); // stop the device if (netif_device_present(dev)) { netif_stop_queue(dev); hard_stop(dev); } - // free the Rx DMA buffers - for (i = 0; i < RX_RING_SIZE; i++) { - if (gp->rx_buff[i]) { - dmafree(PKT_BUF_SZ, gp->rx_buff[i]); - gp->rx_buff[i] = NULL; - } - } free_irq(dev->irq, dev); - + MOD_DEC_USE_COUNT; return 0; } -static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) +static int +gt96100_tx(struct sk_buff *skb, struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; int nextIn; - if (gt96100_debug > 2) - printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n", - dev->name, skb->len, skb->data); - spin_lock_irqsave(&gp->lock, flags); + nextIn = gp->tx_next_in; + + dbg(3, __FUNCTION__ ": nextIn=%d\n", nextIn); + if (gp->tx_count >= TX_RING_SIZE) { - printk(KERN_WARNING - "%s: Tx Ring full, refusing to send buffer.\n", - dev->name); + warn("Tx Ring full, pkt dropped.\n"); gp->stats.tx_dropped++; spin_unlock_irqrestore(&gp->lock, flags); return 1; } - // Prepare the Descriptor at tx_next_in - nextIn = gp->tx_next_in; - + + if (!(gp->last_psr & psrLink)) { + err(__FUNCTION__ ": Link down, pkt dropped.\n"); + gp->stats.tx_dropped++; + spin_unlock_irqrestore(&gp->lock, flags); + return 1; + } + if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) { - printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n", - dev->name); + err(__FUNCTION__ ": device owns descriptor, pkt dropped.\n"); + gp->stats.tx_dropped++; + // stop the queue, so Tx timeout can fix it + netif_stop_queue(dev); + spin_unlock_irqrestore(&gp->lock, flags); + return 1; } - + + // Prepare the Descriptor at tx_next_in gp->tx_skbuff[nextIn] = skb; - gp->tx_ring[nextIn].byte_cnt = - cpu_to_dma32(skb->len << tdByteCntBit); - gp->tx_ring[nextIn].buff_ptr = - cpu_to_dma32(virt_to_phys(skb->data)); + gp->tx_ring[nextIn].byte_cnt = cpu_to_dma16(skb->len); + gp->tx_ring[nextIn].buff_ptr = cpu_to_dma32(virt_to_phys(skb->data)); + // make sure packet gets written back to memory + dma_cache_wback_inv((unsigned long)(skb->data), skb->len); // Give ownership to device, set first and last desc, enable interrupt // Setting of ownership bit must be *last*! gp->tx_ring[nextIn].cmdstat = - cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast)); + cpu_to_dma32((u32)(txOwn | txGenCRC | txEI | + txPad | txFirst | txLast)); + + dump_tx_desc(4, dev, nextIn); + dump_skb(4, dev, skb); // increment tx_next_in with wrap gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE; - // If count is zero, DMA should be stopped, so restart - if (gp->tx_count == 0) { - if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & - psrTxLow) printk(KERN_WARNING - "%s: Tx count zero but Tx queue running!\n", - dev->name); + // If DMA is stopped, restart + if (!(GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & psrTxLow)) GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD | sdcmrTXDL); - } + // increment count and stop queue if full - if (++gp->tx_count == TX_RING_SIZE) + if (++gp->tx_count == TX_RING_SIZE) { + gp->tx_full = 1; netif_stop_queue(dev); - + dbg(2, "Tx Ring now full, queue stopped.\n"); + } + dev->trans_start = jiffies; spin_unlock_irqrestore(&gp->lock, flags); @@ -937,317 +1213,438 @@ } -static int gt96100_rx(struct net_device *dev, u32 status) +static int +gt96100_rx(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; struct sk_buff *skb; - int pkt_len, nextOut; + int pkt_len, nextOut, cdp; gt96100_rd_t *rd; u32 cmdstat; + + dbg(3, __FUNCTION__ ": dev=%p, status=%x\n", dev, status); - if (gt96100_debug > 2) - printk("%s: gt96100_rx: dev=%p, status = %x\n", - dev->name, dev, status); + cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0) + - gp->rx_ring_dma) / sizeof(gt96100_rd_t); - // Continue until we reach the current descriptor pointer - for (nextOut = gp->rx_next_out; - nextOut != - (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) - - gp->rx_ring_dma) / sizeof(gt96100_rd_t); + // Continue until we reach 1st descriptor pointer + for (nextOut = gp->rx_next_out; nextOut != cdp; nextOut = (nextOut + 1) % RX_RING_SIZE) { + + if (--gp->intr_work_done == 0) + break; rd = &gp->rx_ring[nextOut]; cmdstat = dma32_to_cpu(rd->cmdstat); + + dbg(4, __FUNCTION__ ": Rx desc cmdstat=%x, nextOut=%d\n", + cmdstat, nextOut); + + if (cmdstat & (u32)rxOwn) { + //err(__FUNCTION__ ": device owns descriptor!\n"); + // DMA is not finished updating descriptor??? + // Leave and come back later to pick-up where + // we left off. + break; + } - if (cmdstat & (u32) rxOwn) { - cmdstat &= ~((u32) rxOwn); + // Drop this received pkt if there were any errors + if (((cmdstat & (u32)(rxErrorSummary)) && + (cmdstat & (u32)(rxFirst))) || (status & icrRxError)) { + // update the detailed rx error counters that + // are not covered by the MIB counters. + if (cmdstat & (u32)rxOverrun) + gp->stats.rx_fifo_errors++; + cmdstat |= (u32)rxOwn; rd->cmdstat = cpu_to_dma32(cmdstat); - printk(KERN_ERR - "%s: gt96100_rx: ownership bit wrong!\n", - dev->name); - } - // must be first and last (ie only) buffer of packet - if (!(cmdstat & (u32) rxFirst) - || !(cmdstat & (u32) rxLast)) { - printk(KERN_ERR - "%s: gt96100_rx: desc not first and last!\n", - dev->name); continue; } - // drop this received pkt if there were any errors - if ((cmdstat & (u32) rxErrorSummary) - || (status & icrRxErrorQ0)) { - // update the detailed rx error counters that are not covered - // by the MIB counters. - if (cmdstat & (u32) rxOverrun) - gp->stats.rx_fifo_errors++; + + /* + * Must be first and last (ie only) descriptor of packet. We + * ignore (drop) any packets that do not fit in one descriptor. + * Every descriptor's receive buffer is large enough to hold + * the maximum 802.3 frame size, so a multi-descriptor packet + * indicates an error. Most if not all corrupted packets will + * have already been dropped by the above check for the + * rxErrorSummary status bit. + */ + if (!(cmdstat & (u32)rxFirst) || !(cmdstat & (u32)rxLast)) { + if (cmdstat & (u32)rxFirst) { + /* + * This is the first descriptor of a + * multi-descriptor packet. It isn't corrupted + * because the above check for rxErrorSummary + * would have dropped it already, so what's + * the deal with this packet? Good question, + * let's dump it out. + */ + err(__FUNCTION__ + ": desc not first and last!\n"); + dump_rx_desc(0, dev, nextOut); + } + cmdstat |= (u32)rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); + // continue to drop every descriptor of this packet continue; } - - pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask; - + + pkt_len = dma16_to_cpu(rd->byte_cnt); + /* Create new skb. */ - skb = dev_alloc_skb(pkt_len + 2); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { - printk(KERN_ERR - "%s: Memory squeeze, dropping packet.\n", - dev->name); + err(__FUNCTION__ + ": Memory squeeze, dropping packet.\n"); gp->stats.rx_dropped++; + cmdstat |= (u32)rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); continue; } skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte IP header align */ - skb_put(skb, pkt_len); /* Make room */ - eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0); + skb_reserve(skb, 2); /* 16 byte IP header align */ + memcpy(skb_put(skb, pkt_len), + &gp->rx_buff[nextOut*PKT_BUF_SZ], pkt_len); skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* pass the packet to upper layers */ + dump_skb(4, dev, skb); + + netif_rx(skb); /* pass the packet to upper layers */ + dev->last_rx = jiffies; // now we can release ownership of this desc back to device - cmdstat |= (u32) rxOwn; + cmdstat |= (u32)rxOwn; rd->cmdstat = cpu_to_dma32(cmdstat); - - dev->last_rx = jiffies; } + + if (nextOut == gp->rx_next_out) + dbg(3, __FUNCTION__ ": RxCDP did not increment?\n"); gp->rx_next_out = nextOut; return 0; } -static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void +gt96100_tx_complete(struct net_device *dev, u32 status) { - struct net_device *dev = (struct net_device *) dev_id; - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - u32 status; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int nextOut, cdp; + gt96100_td_t *td; + u32 cmdstat; - if (dev == NULL) { - printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); - return; + cdp = (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) + - gp->tx_ring_dma) / sizeof(gt96100_td_t); + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->tx_next_out; nextOut != cdp; + nextOut = (nextOut + 1) % TX_RING_SIZE) { + + if (--gp->intr_work_done == 0) + break; + + td = &gp->tx_ring[nextOut]; + cmdstat = dma32_to_cpu(td->cmdstat); + + dbg(3, __FUNCTION__ ": Tx desc cmdstat=%x, nextOut=%d\n", + cmdstat, nextOut); + + if (cmdstat & (u32)txOwn) { + //dump_tx_ring(dev); + // DMA is not finished writing descriptor??? + // Leave and come back later to pick-up where + // we left off. + break; + } + + // increment Tx error stats + if (cmdstat & (u32)txErrorSummary) { + dbg(2, __FUNCTION__ ": Tx error, cmdstat = %x\n", + cmdstat); + gp->stats.tx_errors++; + if (cmdstat & (u32)txReTxLimit) + gp->stats.tx_aborted_errors++; + if (cmdstat & (u32)txUnderrun) + gp->stats.tx_fifo_errors++; + if (cmdstat & (u32)txLateCollision) + gp->stats.tx_window_errors++; + } + + if (cmdstat & (u32)txCollision) + gp->stats.collisions += + (u32)((cmdstat & txReTxCntMask) >> + txReTxCntBit); + + // Wake the queue if the ring was full + if (gp->tx_full) { + gp->tx_full = 0; + if (gp->last_psr & psrLink) { + netif_wake_queue(dev); + dbg(2, __FUNCTION__ + ": Tx Ring was full, queue waked\n"); + } + } + + // decrement tx ring buffer count + if (gp->tx_count) gp->tx_count--; + + // free the skb + if (gp->tx_skbuff[nextOut]) { + dbg(3, __FUNCTION__ ": good Tx, skb=%p\n", + gp->tx_skbuff[nextOut]); + dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); + gp->tx_skbuff[nextOut] = NULL; + } else { + err(__FUNCTION__ ": no skb!\n"); + } } - status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); - // ACK interrupts -#if 0 - GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE, - icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 | - icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh | - icrTxEndHigh | icrTxBufferLow | icrTxEndLow | - icrTxErrorHigh | icrTxErrorLow | icrTxUdr); -#else - GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); -#endif + gp->tx_next_out = nextOut; + + if (gt96100_check_tx_consistent(gp)) { + err(__FUNCTION__ ": Tx queue inconsistent!\n"); + } + + if ((status & icrTxEndLow) && gp->tx_count != 0) { + // we must restart the DMA + dbg(3, __FUNCTION__ ": Restarting Tx DMA\n"); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } +} + - if ((status & icrEtherIntSum) == 0) { - // not our interrupt - //printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n", - // dev->name, status, read_32bit_cp0_register(CP0_CAUSE)); +static void +gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + u32 status; + + if (dev == NULL) { + err(__FUNCTION__ ": null dev ptr\n"); return; } - if (gt96100_debug > 3) - printk("%s: isr: entry, icr=%x\n", dev->name, status); + dbg(3, __FUNCTION__ ": entry, icr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE)); - if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) { - printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n", - dev->name); - } - - if (status & icrRxBufferQ0) { - gt96100_rx(dev, status); - } - - if (status & (icrTxBufferHigh | icrTxEndHigh)) { - printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n", - dev->name); - } - - if (status & icrMIIPhySTC) { - u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); - printk("%s: port status:\n", dev->name); - printk - ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n", - dev->name, psr & psrSpeed ? "100" : "10", - psr & psrDuplex ? "full" : "half", - psr & psrFctl ? "disabled" : "enabled", - psr & psrLink ? "up" : "down"); - printk - ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n", - dev->name, psr & psrTxLow ? "running" : "stopped", - psr & psrTxHigh ? "running" : "stopped", - psr & psrTxInProg ? "on" : "off"); - gp->last_psr = psr; - } - - if (status & (icrTxBufferLow | icrTxEndLow)) { - int nextOut; - gt96100_td_t *td; - u32 cmdstat; - - // Continue until we reach the current descriptor pointer - for (nextOut = gp->tx_next_out; - nextOut != - (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) - - gp->tx_ring_dma) / sizeof(gt96100_td_t); - nextOut = (nextOut + 1) % TX_RING_SIZE) { - - td = &gp->tx_ring[nextOut]; - cmdstat = dma32_to_cpu(td->cmdstat); - - if (gt96100_debug > 2) - printk("%s: isr: Tx desc cmdstat=%x\n", - dev->name, cmdstat); - - if (cmdstat & (u32) txOwn) { - cmdstat &= ~((u32) txOwn); - td->cmdstat = cpu_to_dma32(cmdstat); - printk(KERN_ERR - "%s: isr: Tx ownership bit wrong!\n", - dev->name); - } - // increment Tx error stats - if (cmdstat & (u32) txErrorSummary) { - if (gt96100_debug > 2) - printk - ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n", - dev->name, cmdstat); - gp->stats.tx_errors++; - if (cmdstat & (u32) txReTxLimit) - gp->stats.collisions++; - if (cmdstat & (u32) txUnderrun) - gp->stats.tx_fifo_errors++; - if (cmdstat & (u32) txLateCollision) - gp->stats.tx_window_errors++; - } - // Wake the queue if the ring was full - if (gp->tx_count == TX_RING_SIZE) - netif_wake_queue(dev); + spin_lock(&gp->lock); - // decrement tx ring buffer count - if (gp->tx_count) - gp->tx_count--; - - // free the skb - if (gp->tx_skbuff[nextOut]) { - if (gt96100_debug > 2) - printk - ("%s: isr: good Tx, skb=%p\n", - dev->name, - gp->tx_skbuff[nextOut]); - dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); - gp->tx_skbuff[nextOut] = NULL; - } else { - printk(KERN_ERR "%s: isr: no skb!\n", - dev->name); - } - } + gp->intr_work_done = max_interrupt_work; - if (gp->tx_count == 0 && nextOut != gp->tx_next_in) { - // FIX! this should probably be a panic - printk(KERN_ERR - "%s: isr: warning! Tx queue inconsistent\n", - dev->name); - } + while (gp->intr_work_done > 0) { - gp->tx_next_out = nextOut; + status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); + // ACK interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, ~status); - if ((status & icrTxEndLow) && gp->tx_count != 0) { - // we must restart the DMA - if (gt96100_debug > 2) - printk("%s: isr: Restarting Tx DMA\n", - dev->name); - GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, - sdcmrERD | sdcmrTXDL); - } - } - // Now check TX errors (RX errors were handled in gt96100_rx) + if ((status & icrEtherIntSum) == 0 && + !(status & (icrTxBufferLow|icrTxBufferHigh|icrRxBuffer))) + break; + + if (status & icrMIIPhySTC) { + u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); + if (gp->last_psr != psr) { + dbg(0, "port status:\n"); + dbg(0, " %s MBit/s, %s-duplex, " + "flow-control %s, link is %s,\n", + psr & psrSpeed ? "100":"10", + psr & psrDuplex ? "full":"half", + psr & psrFctl ? "disabled":"enabled", + psr & psrLink ? "up":"down"); + dbg(0, " TxLowQ is %s, TxHighQ is %s, " + "Transmitter is %s\n", + psr & psrTxLow ? "running":"stopped", + psr & psrTxHigh ? "running":"stopped", + psr & psrTxInProg ? "on":"off"); + + if ((psr & psrLink) && !gp->tx_full && + netif_queue_stopped(dev)) { + dbg(0, __FUNCTION__ + ": Link up, waking queue.\n"); + netif_wake_queue(dev); + } else if (!(psr & psrLink) && + !netif_queue_stopped(dev)) { + dbg(0, __FUNCTION__ + "Link down, stopping queue.\n"); + netif_stop_queue(dev); + } - if (status & icrTxErrorHigh) { - printk(KERN_ERR - "%s: isr: Tx resource error in unused queue!?\n", - dev->name); - } + gp->last_psr = psr; + } - if (status & icrTxErrorLow) { - printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name); - } + if (--gp->intr_work_done == 0) + break; + } + + if (status & (icrTxBufferLow | icrTxEndLow)) + gt96100_tx_complete(dev, status); - if (status & icrTxUdr) { - printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name); + if (status & (icrRxBuffer | icrRxError)) { + gt96100_rx(dev, status); + } + + // Now check TX errors (RX errors were handled in gt96100_rx) + if (status & icrTxErrorLow) { + err(__FUNCTION__ ": Tx resource error\n"); + if (--gp->intr_work_done == 0) + break; + } + + if (status & icrTxUdr) { + err(__FUNCTION__ ": Tx underrun error\n"); + if (--gp->intr_work_done == 0) + break; + } } - if (gt96100_debug > 3) - printk("%s: isr: exit, icr=%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_INT_CAUSE)); + if (gp->intr_work_done == 0) { + // ACK any remaining pending interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); + dbg(3, __FUNCTION__ ": hit max work\n"); + } + + dbg(3, __FUNCTION__ ": exit, icr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE)); + + spin_unlock(&gp->lock); } -/* - * The Tx ring has been full longer than the watchdog timeout - * value, meaning that the interrupt routine has not been freeing - * up space in the Tx ring buffer. - */ -static void gt96100_tx_timeout(struct net_device *dev) +static void +gt96100_tx_timeout(struct net_device *dev) { -// struct gt96100_private *gp = (struct gt96100_private *)dev->priv; - - printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name, - dev); + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&gp->lock, flags); + + if (!(gp->last_psr & psrLink)) { + err("tx_timeout: link down.\n"); + spin_unlock_irqrestore(&gp->lock, flags); + } else { + if (gt96100_check_tx_consistent(gp)) + err("tx_timeout: Tx ring error.\n"); - // FIX! do something, like reset the device + disable_ether_irq(dev); + spin_unlock_irqrestore(&gp->lock, flags); + reset_tx(dev); + enable_ether_irq(dev); + + netif_wake_queue(dev); + } } -static void gt96100_set_rx_mode(struct net_device *dev) +static void +gt96100_set_rx_mode(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; - struct dev_mc_list *mcptr; - - if (gt96100_debug > 2) - printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n", - dev->name, dev, dev->flags); + //struct dev_mc_list *mcptr; + + dbg(3, __FUNCTION__ ": dev=%p, flags=%x\n", dev, dev->flags); // stop the Receiver DMA abort(dev, sdcmrAR); spin_lock_irqsave(&gp->lock, flags); - if (dev->flags & IFF_PROMISC) + if (dev->flags & IFF_PROMISC) { GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM); + } - memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table - // Add our ethernet address - gt96100_add_hash_entry(dev, dev->dev_addr); - +#if 0 + /* + FIXME: currently multicast doesn't work - need to get hash table + working first. + */ if (dev->mc_count) { + // clear hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); + // Add our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) { + dump_hw_addr(2, dev, __FUNCTION__ ": addr=", + mcptr->dmi_addr); gt96100_add_hash_entry(dev, mcptr->dmi_addr); } } +#endif + // restart Rx DMA GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); spin_unlock_irqrestore(&gp->lock, flags); } -static struct net_device_stats *gt96100_get_stats(struct net_device *dev) +static struct net_device_stats * +gt96100_get_stats(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; - if (gt96100_debug > 2) - printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev); + dbg(3, __FUNCTION__ ": dev=%p\n", dev); if (netif_device_present(dev)) { - spin_lock_irqsave(&gp->lock, flags); + spin_lock_irqsave (&gp->lock, flags); update_stats(gp); - spin_unlock_irqrestore(&gp->lock, flags); + spin_unlock_irqrestore (&gp->lock, flags); } return &gp->stats; } -module_init(gt96100_probe); -MODULE_LICENSE("GPL"); +static void gt96100_cleanup_module(void) +{ + int i; + for (i=0; idev != NULL) { + struct gt96100_private *gp = + (struct gt96100_private *)gtif->dev->priv; + release_region(gtif->iobase, gp->io_size); + unregister_netdev(gtif->dev); + if (gtif->dev->priv != NULL) + kfree (gtif->dev->priv); + kfree (gtif->dev); + } + } +} + + +#ifndef MODULE + +static int __init gt96100_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for(this_opt=strtok(options, ","); + this_opt; this_opt=strtok(NULL, ",")) { + if (!strncmp(this_opt, "mac0:", 5)) { + memcpy(mac0, this_opt+5, 17); + mac0[17]= '\0'; + } else if (!strncmp(this_opt, "mac1:", 5)) { + memcpy(mac1, this_opt+5, 17); + mac1[17]= '\0'; + } + } + + return 1; +} + +__setup("gt96100eth=", gt96100_setup); + +#endif /* !MODULE */ + + +module_init(gt96100_init_module); +module_exit(gt96100_cleanup_module); + +MODULE_AUTHOR("Steve Longerbeam "); +MODULE_DESCRIPTION("GT96100 Ethernet driver"); diff -urN linux-2.4.18/drivers/net/gt96100eth.h linux-2.4.19-pre5/drivers/net/gt96100eth.h --- linux-2.4.18/drivers/net/gt96100eth.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/gt96100eth.h Sat Mar 30 22:55:28 2002 @@ -29,29 +29,43 @@ #include +#define dbg(lvl, format, arg...) \ + if (lvl <= GT96100_DEBUG) \ + printk(KERN_DEBUG "%s: " format, dev->name , ## arg) +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, dev->name , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, dev->name , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, dev->name , ## arg) + /* Keep the ring sizes a power of two for efficiency. */ #define TX_RING_SIZE 16 #define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ #define RX_HASH_TABLE_SIZE 16384 #define HASH_HOP_NUMBER 12 #define NUM_INTERFACES 2 -#define GT96100ETH_TX_TIMEOUT HZ +#define GT96100ETH_TX_TIMEOUT HZ/4 #define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG) #define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE) #ifdef CONFIG_MIPS_EV96100 -#define GT96100_ETHER0_IRQ 4 +#define GT96100_ETHER0_IRQ 3 #define GT96100_ETHER1_IRQ 4 #else #define GT96100_ETHER0_IRQ -1 #define GT96100_ETHER1_IRQ -1 #endif +#define REV_GT96100 1 +#define REV_GT96100A_1 2 +#define REV_GT96100A 3 + #define GT96100ETH_READ(gp, offset) \ GT96100_READ((gp->port_offset + offset)) @@ -70,13 +84,13 @@ /* Bit definitions of the SMI Reg */ enum { smirDataMask = 0xffff, - smirPhyAdMask = 0x1f << 16, + smirPhyAdMask = 0x1f<<16, smirPhyAdBit = 16, - smirRegAdMask = 0x1f << 21, + smirRegAdMask = 0x1f<<21, smirRegAdBit = 21, - smirOpCode = 1 << 26, - smirReadValid = 1 << 27, - smirBusy = 1 << 28 + smirOpCode = 1<<26, + smirReadValid = 1<<27, + smirBusy = 1<<28 }; /* Bit definitions of the Port Config Reg */ @@ -84,17 +98,17 @@ pcrPM = 1, pcrRBM = 2, pcrPBF = 4, - pcrEN = 1 << 7, - pcrLPBKMask = 0x3 << 8, + pcrEN = 1<<7, + pcrLPBKMask = 0x3<<8, pcrLPBKBit = 8, - pcrFC = 1 << 10, - pcrHS = 1 << 12, - pcrHM = 1 << 13, - pcrHDM = 1 << 14, - pcrHD = 1 << 15, - pcrISLMask = 0x7 << 28, + pcrFC = 1<<10, + pcrHS = 1<<12, + pcrHM = 1<<13, + pcrHDM = 1<<14, + pcrHD = 1<<15, + pcrISLMask = 0x7<<28, pcrISLBit = 28, - pcrACCS = 1 << 31 + pcrACCS = 1<<31 }; /* Bit definitions of the Port Config Extend Reg */ @@ -102,27 +116,27 @@ pcxrIGMP = 1, pcxrSPAN = 2, pcxrPAR = 4, - pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxMask = 0x7<<3, pcxrPRIOtxBit = 3, - pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxMask = 0x3<<6, pcxrPRIOrxBit = 6, - pcxrPRIOrxOverride = 1 << 8, - pcxrDPLXen = 1 << 9, - pcxrFCTLen = 1 << 10, - pcxrFLP = 1 << 11, - pcxrFCTL = 1 << 12, - pcxrMFLMask = 0x3 << 14, + pcxrPRIOrxOverride = 1<<8, + pcxrDPLXen = 1<<9, + pcxrFCTLen = 1<<10, + pcxrFLP = 1<<11, + pcxrFCTL = 1<<12, + pcxrMFLMask = 0x3<<14, pcxrMFLBit = 14, - pcxrMIBclrMode = 1 << 16, - pcxrSpeed = 1 << 18, - pcxrSpeeden = 1 << 19, - pcxrRMIIen = 1 << 20, - pcxrDSCPen = 1 << 21 + pcxrMIBclrMode = 1<<16, + pcxrSpeed = 1<<18, + pcxrSpeeden = 1<<19, + pcxrRMIIen = 1<<20, + pcxrDSCPen = 1<<21 }; /* Bit definitions of the Port Command Reg */ enum pcmr_bits { - pcmrFJ = 1 << 15 + pcmrFJ = 1<<15 }; @@ -132,119 +146,124 @@ psrDuplex = 2, psrFctl = 4, psrLink = 8, - psrPause = 1 << 4, - psrTxLow = 1 << 5, - psrTxHigh = 1 << 6, - psrTxInProg = 1 << 7 + psrPause = 1<<4, + psrTxLow = 1<<5, + psrTxHigh = 1<<6, + psrTxInProg = 1<<7 }; /* Bit definitions of the SDMA Config Reg */ enum sdcr_bits { - sdcrRCMask = 0xf << 2, + sdcrRCMask = 0xf<<2, sdcrRCBit = 2, - sdcrBLMR = 1 << 6, - sdcrBLMT = 1 << 7, - sdcrPOVR = 1 << 8, - sdcrRIFB = 1 << 9, - sdcrBSZMask = 0x3 << 12, + sdcrBLMR = 1<<6, + sdcrBLMT = 1<<7, + sdcrPOVR = 1<<8, + sdcrRIFB = 1<<9, + sdcrBSZMask = 0x3<<12, sdcrBSZBit = 12 }; /* Bit definitions of the SDMA Command Reg */ enum sdcmr_bits { - sdcmrERD = 1 << 7, - sdcmrAR = 1 << 15, - sdcmrSTDH = 1 << 16, - sdcmrSTDL = 1 << 17, - sdcmrTXDH = 1 << 23, - sdcmrTXDL = 1 << 24, - sdcmrAT = 1 << 31 + sdcmrERD = 1<<7, + sdcmrAR = 1<<15, + sdcmrSTDH = 1<<16, + sdcmrSTDL = 1<<17, + sdcmrTXDH = 1<<23, + sdcmrTXDL = 1<<24, + sdcmrAT = 1<<31 }; /* Bit definitions of the Interrupt Cause Reg */ enum icr_bits { icrRxBuffer = 1, - icrTxBufferHigh = 1 << 2, - icrTxBufferLow = 1 << 3, - icrTxEndHigh = 1 << 6, - icrTxEndLow = 1 << 7, - icrRxError = 1 << 8, - icrTxErrorHigh = 1 << 10, - icrTxErrorLow = 1 << 11, - icrRxOVR = 1 << 12, - icrTxUdr = 1 << 13, - icrRxBufferQ0 = 1 << 16, - icrRxBufferQ1 = 1 << 17, - icrRxBufferQ2 = 1 << 18, - icrRxBufferQ3 = 1 << 19, - icrRxErrorQ0 = 1 << 20, - icrRxErrorQ1 = 1 << 21, - icrRxErrorQ2 = 1 << 22, - icrRxErrorQ3 = 1 << 23, - icrMIIPhySTC = 1 << 28, - icrSMIdone = 1 << 29, - icrEtherIntSum = 1 << 31 + icrTxBufferHigh = 1<<2, + icrTxBufferLow = 1<<3, + icrTxEndHigh = 1<<6, + icrTxEndLow = 1<<7, + icrRxError = 1<<8, + icrTxErrorHigh = 1<<10, + icrTxErrorLow = 1<<11, + icrRxOVR = 1<<12, + icrTxUdr = 1<<13, + icrRxBufferQ0 = 1<<16, + icrRxBufferQ1 = 1<<17, + icrRxBufferQ2 = 1<<18, + icrRxBufferQ3 = 1<<19, + icrRxErrorQ0 = 1<<20, + icrRxErrorQ1 = 1<<21, + icrRxErrorQ2 = 1<<22, + icrRxErrorQ3 = 1<<23, + icrMIIPhySTC = 1<<28, + icrSMIdone = 1<<29, + icrEtherIntSum = 1<<31 }; /* The Rx and Tx descriptor lists. */ - typedef struct { +#ifdef DESC_BE + u16 byte_cnt; + u16 reserved; +#else + u16 reserved; + u16 byte_cnt; +#endif u32 cmdstat; - u32 byte_cnt; - u32 buff_ptr; u32 next; -} gt96100_td_t; - -#define tdByteCntBit 16 + u32 buff_ptr; +} gt96100_td_t __attribute__ ((packed)); typedef struct { +#ifdef DESC_BE + u16 buff_sz; + u16 byte_cnt; +#else + u16 byte_cnt; + u16 buff_sz; +#endif u32 cmdstat; - u32 buff_cnt_sz; - u32 buff_ptr; u32 next; -} gt96100_rd_t; - -#define rdBuffSzBit 16 -#define rdByteCntMask 0xffff + u32 buff_ptr; +} gt96100_rd_t __attribute__ ((packed)); /* Values for the Tx command-status descriptor entry. */ enum td_cmdstat { - txOwn = 1 << 31, - txAutoMode = 1 << 30, - txEI = 1 << 23, - txGenCRC = 1 << 22, - txPad = 1 << 18, - txFirst = 1 << 17, - txLast = 1 << 16, - txErrorSummary = 1 << 15, - txReTxCntMask = 0x0f << 10, + txOwn = 1<<31, + txAutoMode = 1<<30, + txEI = 1<<23, + txGenCRC = 1<<22, + txPad = 1<<18, + txFirst = 1<<17, + txLast = 1<<16, + txErrorSummary = 1<<15, + txReTxCntMask = 0x0f<<10, txReTxCntBit = 10, - txCollision = 1 << 9, - txReTxLimit = 1 << 8, - txUnderrun = 1 << 6, - txLateCollision = 1 << 5 + txCollision = 1<<9, + txReTxLimit = 1<<8, + txUnderrun = 1<<6, + txLateCollision = 1<<5 }; -#define TxReTxCntBit 10 /* Values for the Rx command-status descriptor entry. */ enum rd_cmdstat { - rxOwn = 1 << 31, - rxAutoMode = 1 << 30, - rxEI = 1 << 23, - rxFirst = 1 << 17, - rxLast = 1 << 16, - rxErrorSummary = 1 << 15, - rxIGMP = 1 << 14, - rxHashExpired = 1 << 13, - rxMissedFrame = 1 << 12, - rxFrameType = 1 << 11, - rxShortFrame = 1 << 8, - rxMaxFrameLen = 1 << 7, - rxOverrun = 1 << 6, - rxCollision = 1 << 4, + rxOwn = 1<<31, + rxAutoMode = 1<<30, + rxEI = 1<<23, + rxFirst = 1<<17, + rxLast = 1<<16, + rxErrorSummary = 1<<15, + rxIGMP = 1<<14, + rxHashExpired = 1<<13, + rxMissedFrame = 1<<12, + rxFrameType = 1<<11, + rxShortFrame = 1<<8, + rxMaxFrameLen = 1<<7, + rxOverrun = 1<<6, + rxCollision = 1<<4, rxCRCError = 1 }; @@ -286,40 +305,44 @@ struct gt96100_private { - gt96100_rd_t *rx_ring; - gt96100_td_t *tx_ring; + gt96100_rd_t* rx_ring; + gt96100_td_t* tx_ring; // The Rx and Tx rings must be 16-byte aligned dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; - char *hash_table; + char* hash_table; // The Hash Table must be 8-byte aligned dma_addr_t hash_table_dma; int hash_mode; - + // The Rx buffers must be 8-byte aligned - char *rx_buff[RX_RING_SIZE]; + char* rx_buff; + dma_addr_t rx_buff_dma; // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes // of payload must be 8-byte aligned - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - int rx_next_out; /* The next free ring entry to receive */ - int tx_next_in; /* The next free ring entry to send */ - int tx_next_out; /* The last ring entry the ISR processed */ - int tx_count; /* current # of pkts waiting to be sent in Tx ring */ - + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + int intr_work_done; /* number of Rx and Tx pkts processed in the isr */ + int tx_full; /* Tx ring is full */ + mib_counters_t mib; struct net_device_stats stats; int io_size; - int port_num; // 0 or 1 + int port_num; // 0 or 1 + int chip_rev; u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register - int phy_addr; // PHY address - u32 last_psr; // last value of the port status register - - int options; /* User-settable misc. driver options. */ + int options; /* User-settable misc. driver options. */ int drv_flags; - unsigned char phys[2]; /* MII device addresses. */ - spinlock_t lock; /* Serialise access to device */ + struct timer_list timer; + spinlock_t lock; /* Serialise access to device */ }; #endif diff -urN linux-2.4.18/drivers/net/hp-plus.c linux-2.4.19-pre5/drivers/net/hp-plus.c --- linux-2.4.18/drivers/net/hp-plus.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/hp-plus.c Sat Mar 30 22:55:40 2002 @@ -408,8 +408,10 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i"); -MODULE_PARM_DESC(io, "HP PC-LAN+ I/O port address(es)"); -MODULE_PARM_DESC(irq, "HP PC-LAN+ IRQ number(s); ignored if properly detected"); +MODULE_PARM_DESC(io, "I/O port address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected"); +MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver"); +MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ @@ -457,7 +459,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/hp.c linux-2.4.19-pre5/drivers/net/hp.c --- linux-2.4.18/drivers/net/hp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/hp.c Sat Mar 30 22:55:40 2002 @@ -380,8 +380,10 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HP_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HP_CARDS) "i"); -MODULE_PARM_DESC(io, "HP PC-LAN I/O base address(es)"); -MODULE_PARM_DESC(irq, "HP PC-LAN IRQ number(s) (assigned)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); +MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver"); +MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ @@ -429,7 +431,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/hp100.c linux-2.4.19-pre5/drivers/net/hp100.c --- linux-2.4.18/drivers/net/hp100.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/hp100.c Sat Mar 30 22:55:40 2002 @@ -210,8 +210,8 @@ hp100_ring_t rxring[MAX_RX_PDL]; hp100_ring_t txring[MAX_TX_PDL]; - u_int *page_vaddr; /* Virtual address of allocated page */ u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + u_long whatever_offset; /* Offset to bus/phys/dma address */ int rxrcommit; /* # Rx PDLs commited to adapter */ int txrcommit; /* # Tx PDLs commited to adapter */ }; @@ -348,6 +348,18 @@ static void hp100_RegisterDump(struct net_device *dev); #endif +/* Conversion to new PCI API : + * Convert an address in a kernel buffer to a bus/phys/dma address. + * This work *only* for memory fragments part of lp->page_vaddr, + * because it was properly DMA allocated via pci_alloc_consistent(), + * so we just need to "retreive" the original mapping to bus/phys/dma + * address - Jean II */ +static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr) +{ + return ((u_long) ptr) + + ((struct hp100_private *) (dev->priv))->whatever_offset; +} + /* TODO: This function should not really be needed in a good design... */ static void wait(void) { @@ -625,9 +637,20 @@ local_mode = 3; } else if (chip == HP100_CHIPID_LASSEN && (lsw & (HP100_BM_WRITE | HP100_BM_READ)) == (HP100_BM_WRITE | HP100_BM_READ)) { + /* Conversion to new PCI API : + * I don't have the doc, but I assume that the card + * can map the full 32bit address space. + * Also, we can have EISA Busmaster cards (not tested), + * so beware !!! - Jean II */ + if((bus == HP100_BUS_PCI) && + (pci_set_dma_mask(pci_dev, 0xffffffff))) { + /* Gracefully fallback to shared memory */ + goto busmasterfail; + } printk("hp100: %s: Busmaster mode enabled.\n", dev->name); hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); } else { + busmasterfail: #ifdef HP100_DEBUG printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name); printk("hp100: %s: Trying shared memory mode.\n", dev->name); @@ -770,11 +793,14 @@ * in the cards shared memory area. But currently, busmaster has been * implemented/tested only with the lassen chip anyway... */ if (lp->mode == 1) { /* busmaster */ + dma_addr_t page_baddr; /* Get physically continous memory for TX & RX PDLs */ - if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL) + /* Conversion to new PCI API : + * Pages are always aligned and zeroed, no need to it ourself. + * Doc says should be OK for EISA bus as well - Jean II */ + if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) return -ENOMEM; - lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f)); - memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f); + lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); #ifdef HP100_DEBUG_BM printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", dev->name, (u_int) lp->page_vaddr_algn, (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); @@ -1187,7 +1213,7 @@ { struct hp100_private *lp = (struct hp100_private *) dev->priv; hp100_ring_t *ringptr; - u_int *pageptr; + u_int *pageptr; /* Warning : increment by 4 - Jean II */ int i; #ifdef HP100_DEBUG_B @@ -1244,7 +1270,7 @@ dev->name, (unsigned) pdlptr); ringptr->pdl = pdlptr + 1; - ringptr->pdl_paddr = virt_to_bus(pdlptr + 1); + ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1); ringptr->skb = (void *) NULL; /* @@ -1255,7 +1281,7 @@ */ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ - *(pdlptr + 2) = (u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ + *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr); /* Address Frag 1 */ *(pdlptr + 3) = 4; /* Length Frag 1 */ return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); @@ -1270,7 +1296,7 @@ printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n", dev->name, (unsigned) pdlptr); ringptr->pdl = pdlptr; /* +1; */ - ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ + ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */ ringptr->skb = (void *) NULL; return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); @@ -1329,8 +1355,10 @@ (unsigned int) ringptr->skb->data); #endif + /* Conversion to new PCI API : map skbuf data to PCI bus. + * Doc says it's OK for EISA as well - Jean II */ ringptr->pdl[0] = 0x00020000; /* Write PDH */ - ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data)); + ringptr->pdl[3] = ((u_int) pci_map_single(((struct hp100_private *) (dev->priv))->pci_dev, ringptr->skb->data, MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE)); ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ #ifdef HP100_DEBUG_BM @@ -1583,7 +1611,6 @@ ringptr->skb = skb; ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ - ringptr->pdl[1] = (u32) virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ if (lp->chip == HP100_CHIPID_SHASTA) { /* TODO:Could someone who has the EISA card please check if this works? */ ringptr->pdl[2] = i; @@ -1591,6 +1618,9 @@ /* In the PDL, don't use the padded size but the real packet size: */ ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ } + /* Conversion to new PCI API : map skbuf data to PCI bus. + * Doc says it's OK for EISA as well - Jean II */ + ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE)); /* 1st Frag: Adr. of data */ /* Hand this PDL to the card. */ hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ @@ -1639,6 +1669,8 @@ dev->name, (u_int) lp->txrhead->skb->data, lp->txrcommit, hp100_inb(TX_PDL), donecount); #endif + /* Conversion to new PCI API : NOP */ + pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE); dev_kfree_skb_any(lp->txrhead->skb); lp->txrhead->skb = (void *) NULL; lp->txrhead = lp->txrhead->next; @@ -1948,6 +1980,9 @@ header = *(ptr->pdl - 1); pkt_len = (header & HP100_PKT_LEN_MASK); + /* Conversion to new PCI API : NOP */ + pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); + #ifdef HP100_DEBUG_BM printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", dev->name, (u_int) (ptr->pdl - 1), (u_int) header, @@ -2908,7 +2943,7 @@ release_region(d->base_addr, HP100_REGION_SIZE); if (p->mode == 1) /* busmaster */ - kfree(p->page_vaddr); + pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, p->page_vaddr_algn, virt_to_whatever(d, p->page_vaddr_algn)); if (p->mem_ptr_virt) iounmap(p->mem_ptr_virt); kfree(d->priv); diff -urN linux-2.4.18/drivers/net/hydra.c linux-2.4.19-pre5/drivers/net/hydra.c --- linux-2.4.18/drivers/net/hydra.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/hydra.c Sat Mar 30 22:55:34 2002 @@ -121,7 +121,7 @@ dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j)); /* We must set the 8390 for word mode. */ - writeb(0x4b, ioaddr + NE_EN0_DCFG); + z_writeb(0x4b, ioaddr + NE_EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; @@ -196,10 +196,10 @@ ((ring_page - NESM_START_PG)<<8); ptrs = (short *)hdr; - *(ptrs++) = readw(hdr_start); + *(ptrs++) = z_readw(hdr_start); *((short *)hdr) = WORDSWAP(*((short *)hdr)); hdr_start += 2; - *(ptrs++) = readw(hdr_start); + *(ptrs++) = z_readw(hdr_start); *((short *)hdr+1) = WORDSWAP(*((short *)hdr+1)); } @@ -216,11 +216,11 @@ if (xfer_start+count > mem_base + (NESM_STOP_PG<<8)) { int semi_count = (mem_base + (NESM_STOP_PG<<8)) - xfer_start; - memcpy_fromio(skb->data,xfer_start,semi_count); + z_memcpy_fromio(skb->data,xfer_start,semi_count); count -= semi_count; - memcpy_fromio(skb->data+semi_count, mem_base, count); + z_memcpy_fromio(skb->data+semi_count, mem_base, count); } else - memcpy_fromio(skb->data, xfer_start,count); + z_memcpy_fromio(skb->data, xfer_start,count); } @@ -233,7 +233,7 @@ if (count&1) count++; - memcpy_toio(mem_base+((start_page - NESM_START_PG)<<8), buf, count); + z_memcpy_toio(mem_base+((start_page - NESM_START_PG)<<8), buf, count); } static void __exit hydra_cleanup(void) diff -urN linux-2.4.18/drivers/net/ioc3-eth.c linux-2.4.19-pre5/drivers/net/ioc3-eth.c --- linux-2.4.18/drivers/net/ioc3-eth.c Sun Dec 23 16:23:44 2001 +++ linux-2.4.19-pre5/drivers/net/ioc3-eth.c Sat Mar 30 22:55:34 2002 @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_SERIAL #include @@ -340,14 +341,15 @@ } /* - * Read the NIC (Number-In-a-Can) device. + * Read the NIC (Number-In-a-Can) device used to store the MAC address on + * SN0 / SN00 nodeboards and PCI cards. */ -static void ioc3_get_eaddr(struct ioc3_private *ip) +static void ioc3_get_eaddr_nic(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; u8 nic[14]; - int i; int tries = 2; /* There may be some problem with the battery? */ + int i; ioc3_w(gpcr_s, (1 << 21)); @@ -370,16 +372,123 @@ for (i = 13; i >= 0; i--) nic[i] = nic_read_byte(ioc3); - printk("Ethernet address is "); - for (i = 2; i < 8; i++) { + for (i = 2; i < 8; i++) ip->dev->dev_addr[i - 2] = nic[i]; - printk("%02x", nic[i]); +} + +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) +/* + * Get the ether-address on SN1 nodes + */ +static void ioc3_get_eaddr_sn(struct ioc3_private *ip) +{ + int ibrick_mac_addr_get(nasid_t, char *); + struct ioc3 *ioc3 = ip->regs; + nasid_t nasid_of_ioc3; + char io7eaddr[20]; + long mac; + int err_val; + + /* + * err_val = ibrick_mac_addr_get(get_nasid(), io7eaddr ); + * + * BAD!! The above call uses get_nasid() and assumes that + * the ioc3 pointed to by struct ioc3 is hooked up to the + * cbrick that we're running on. The proper way to make this call + * is to figure out which nasid the ioc3 is connected to + * and use that to call ibrick_mac_addr_get. Below is + * a hack to do just that. + */ + + /* + * Get the nasid of the ioc3 from the ioc3's base addr. + * FIXME: the 8 at the end assumes we're in memory mode, + * not node mode (for that, we'd change it to a 9). + * Is there a call to extract this info from a physical + * addr somewhere in an sn header file already? If so, + * we should probably use that, or restructure this routine + * to use pci_dev and generic numa nodeid getting stuff. + */ + nasid_of_ioc3 = (((unsigned long)ioc3 >> 33) & ~(-1 << 8)); + err_val = ibrick_mac_addr_get(nasid_of_ioc3, io7eaddr ); + + + if (err_val) { + /* Couldn't read the eeprom; try OSLoadOptions. */ + printk("WARNING: ibrick_mac_addr_get failed: %d\n", err_val); + + /* this is where we hardwire the mac address + * 1st ibrick had 08:00:69:11:34:75 + * 2nd ibrick had 08:00:69:11:35:35 + * + * Eagan Machines: + * mankato1 08:00:69:11:BE:95 + * warroad 08:00:69:11:bd:60 + * duron 08:00:69:11:34:60 + * + * an easy way to get the mac address is to hook + * up an ip35, then from L1 do 'cti serial' + * and then look for MAC line XXX THIS DOESN"T QUITE WORK!! + */ + printk("ioc3_get_eaddr: setting ethernet address to:\n -----> "); + ip->dev->dev_addr[0] = 0x8; + ip->dev->dev_addr[1] = 0x0; + ip->dev->dev_addr[2] = 0x69; + ip->dev->dev_addr[3] = 0x11; + ip->dev->dev_addr[4] = 0x34; + ip->dev->dev_addr[5] = 0x60; + } + else { + long simple_strtol(const char *,char **,unsigned int); + + mac = simple_strtol(io7eaddr, (char **)0, 16); + ip->dev->dev_addr[0] = (mac >> 40) & 0xff; + ip->dev->dev_addr[1] = (mac >> 32) & 0xff; + ip->dev->dev_addr[2] = (mac >> 24) & 0xff; + ip->dev->dev_addr[3] = (mac >> 16) & 0xff; + ip->dev->dev_addr[4] = (mac >> 8) & 0xff; + ip->dev->dev_addr[5] = mac & 0xff; + } +} +#endif + +/* + * Ok, this is hosed by design. It's necessary to know what machine the + * NIC is in in order to know how to read the NIC address. We also have + * to know if it's a PCI card or a NIC in on the node board ... + */ +static void ioc3_get_eaddr(struct ioc3_private *ip) +{ + void (*do_get_eaddr)(struct ioc3_private *ip) = NULL; + int i; + + /* + * We should also use this code for PCI cards, no matter what host + * machine but how to know that we're a PCI card? + */ +#ifdef CONFIG_SGI_IP27 + do_get_eaddr = ioc3_get_eaddr_nic; +#endif +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) + do_get_eaddr = ioc3_get_eaddr_sn; +#endif + + if (!do_get_eaddr) { + printk(KERN_ERR "Don't know how to read MAC address of this " + "IOC3 NIC\n"); + return; + } + + printk("Ethernet address is "); + for (i = 0; i < 6; i++) { + printk("%02x", ip->dev->dev_addr[i]); if (i < 7) printk(":"); } printk(".\n"); } + /* * Caller must hold the ioc3_lock ever for MII readers. This is also * used to protect the transmitter side but it's low contention. @@ -434,10 +543,10 @@ skb = ip->rx_skbs[rx_entry]; rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = rxb->w0; + w0 = be32_to_cpu(rxb->w0); while (w0 & ERXBUF_V) { - err = rxb->err; /* It's valid ... */ + err = be32_to_cpu(rxb->err); /* It's valid ... */ if (err & ERXBUF_GOODPKT) { len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; skb_trim(skb, len); @@ -478,8 +587,8 @@ ip->stats.rx_frame_errors++; next: ip->rx_skbs[n_entry] = new_skb; - rxr[n_entry] = (0xa5UL << 56) | - ((unsigned long) rxb & TO_PHYS_MASK); + rxr[n_entry] = cpu_to_be32((0xa5UL << 56) | + ((unsigned long) rxb & TO_PHYS_MASK)); rxb->w0 = 0; /* Clear valid flag */ n_entry = (n_entry + 1) & 511; /* Update erpir */ @@ -487,7 +596,7 @@ rx_entry = (rx_entry + 1) & 511; skb = ip->rx_skbs[rx_entry]; rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = rxb->w0; + w0 = be32_to_cpu(rxb->w0); } ioc3->erpir = (n_entry << 3) | ERPIR_ARM; ip->rx_pi = n_entry; @@ -1189,8 +1298,8 @@ /* Because we reserve afterwards. */ skb_put(skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) skb->data; - rxr[i] = (0xa5UL << 56) - | ((unsigned long) rxb & TO_PHYS_MASK); + rxr[i] = cpu_to_be64((0xa5UL << 56) | + ((unsigned long) rxb & TO_PHYS_MASK)); skb_reserve(skb, RX_OFFSET); } ip->rx_ci = 0; @@ -1554,8 +1663,8 @@ memset(desc->data + len, 0, ETH_ZLEN - len); len = ETH_ZLEN; } - desc->cmd = len | ETXD_INTWHENDONE | ETXD_D0V; - desc->bufcnt = len; + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V); + desc->bufcnt = cpu_to_be32(len); } else if ((data ^ (data + len)) & 0x4000) { unsigned long b2, s1, s2; @@ -1563,16 +1672,20 @@ s1 = b2 - data; s2 = data + len - b2; - desc->cmd = len | ETXD_INTWHENDONE | ETXD_B1V | ETXD_B2V; - desc->bufcnt = (s1 << ETXD_B1CNT_SHIFT) | - (s2 << ETXD_B2CNT_SHIFT); - desc->p1 = (0xa5UL << 56) | (data & TO_PHYS_MASK); - desc->p2 = (0xa5UL << 56) | (data & TO_PHYS_MASK); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | + ETXD_B1V | ETXD_B2V); + desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) + | (s2 << ETXD_B2CNT_SHIFT)); + desc->p1 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); + desc->p2 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); } else { /* Normal sized packet that doesn't cross a page boundary. */ - desc->cmd = len | ETXD_INTWHENDONE | ETXD_B1V; - desc->bufcnt = len << ETXD_B1CNT_SHIFT; - desc->p1 = (0xa5UL << 56) | (data & TO_PHYS_MASK); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V); + desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT); + desc->p1 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); } BARRIER(); @@ -1611,27 +1724,16 @@ * Given a multicast ethernet address, this routine calculates the * address's bit index in the logical address filter mask */ -#define CRC_MASK 0xedb88320 static inline unsigned int ioc3_hash(const unsigned char *addr) { unsigned int temp = 0; unsigned char byte; - unsigned int crc; - int bits, len; + u32 crc; + int bits; - len = ETH_ALEN; - for (crc = ~0; --len >= 0; addr++) { - byte = *addr; - for (bits = 8; --bits >= 0; ) { - if ((byte ^ crc) & 1) - crc = (crc >> 1) ^ CRC_MASK; - else - crc >>= 1; - byte >>= 1; - } - } + crc = ether_crc_le(ETH_ALEN, addr); crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */ for (bits = 6; --bits >= 0; ) { diff -urN linux-2.4.18/drivers/net/irda/Config.in linux-2.4.19-pre5/drivers/net/irda/Config.in --- linux-2.4.18/drivers/net/irda/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/irda/Config.in Sat Mar 30 22:55:34 2002 @@ -24,6 +24,9 @@ dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA +fi if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA diff -urN linux-2.4.18/drivers/net/irda/Makefile linux-2.4.19-pre5/drivers/net/irda/Makefile --- linux-2.4.18/drivers/net/irda/Makefile Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/irda/Makefile Sat Mar 30 22:55:28 2002 @@ -28,5 +28,6 @@ obj-$(CONFIG_LITELINK_DONGLE) += litelink.o obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o obj-$(CONFIG_EP7211_IR) += ep7211_ir.o +obj-$(CONFIG_AU1000_FIR) += au1k_ir.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/net/irda/ali-ircc.c linux-2.4.19-pre5/drivers/net/irda/ali-ircc.c --- linux-2.4.18/drivers/net/irda/ali-ircc.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/irda/ali-ircc.c Sat Mar 30 22:55:34 2002 @@ -291,15 +291,13 @@ self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ /* Reserve the ioports that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN linux-2.4.18/drivers/net/irda/au1k_ir.c linux-2.4.19-pre5/drivers/net/irda/au1k_ir.c --- linux-2.4.18/drivers/net/irda/au1k_ir.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/irda/au1k_ir.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,867 @@ +/* + * + * Alchemy Semi Au1000 IrDA driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ + +#ifndef __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "net/irda/au1000_ircc.h" + +static int au1k_irda_net_init(struct net_device *); +static int au1k_irda_start(struct net_device *); +static int au1k_irda_stop(struct net_device *dev); +static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); +static int au1k_irda_rx(struct net_device *); +static void au1k_irda_interrupt(int, void *, struct pt_regs *); +static void au1k_tx_timeout(struct net_device *); +static struct net_device_stats *au1k_irda_stats(struct net_device *); +static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); +static int au1k_irda_set_speed(struct net_device *dev, int speed); + +static void *dma_alloc(size_t, dma_addr_t *); +static void dma_free(void *, size_t); + +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static struct net_device *ir_devs[NUM_IR_IFF]; +static char version[] __devinitdata = + "au1k_ircc:1.0 ppopov@mvista.com\n"; + +#define RUN_AT(x) (jiffies + (x)) + +/* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ +u32 read_ir_reg(u32 addr) +{ + readl(addr); + return readl(addr); +} + + +/* + * Buffer allocation/deallocation routines. The buffer descriptor returned + * has the virtual and dma address of a buffer suitable for + * both, receive and transmit operations. + */ +static db_dest_t *GetFreeDB(struct au1k_private *aup) +{ + db_dest_t *pDB; + pDB = aup->pDBfree; + + if (pDB) { + aup->pDBfree = pDB->pnext; + } + return pDB; +} + +static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB) +{ + db_dest_t *pDBfree = aup->pDBfree; + if (pDBfree) + pDBfree->pnext = pDB; + aup->pDBfree = pDB; +} + + +/* + DMA memory allocation, derived from pci_alloc_consistent. + However, the Au1000 data cache is coherent (when programmed + so), therefore we return KSEG0 address, not KSEG1. +*/ +static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + ret = KSEG0ADDR(ret); + } + return ret; +} + + +static void dma_free(void *vaddr, size_t size) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static void +setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +{ + int i; + for (i=0; irx_ring[i] = (volatile ring_dest_t *) + (rx_base + sizeof(ring_dest_t)*i); + } + for (i=0; itx_ring[i] = (volatile ring_dest_t *) + (tx_base + sizeof(ring_dest_t)*i); + } +} + + +/* + * Device has already been stopped at this point. + */ +static void au1k_irda_net_uninit(struct net_device *dev) +{ + dev->hard_start_xmit = NULL; + dev->open = NULL; + dev->stop = NULL; + dev->do_ioctl = NULL; + dev->get_stats = NULL; + dev->priv = NULL; +} + + +static int au1k_irda_init(void) +{ + static unsigned version_printed = 0; + struct net_device *dev; + int err; + + if (version_printed++ == 0) printk(version); + + rtnl_lock(); + dev = dev_alloc("irda%d", &err); + if (dev) { + dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */ + dev->init = au1k_irda_net_init; + dev->uninit = au1k_irda_net_uninit; + err = register_netdevice(dev); + + if (err) + kfree(dev); + else + ir_devs[0] = dev; + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + } + rtnl_unlock(); + return err; +} + +static int au1k_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = NULL; + int i, retval = 0, err; + db_dest_t *pDB, *pDBfree; + unsigned long temp; + + dev->priv = kmalloc(sizeof(struct au1k_private), GFP_KERNEL); + if (dev->priv == NULL) { + retval = -ENOMEM; + goto out; + } + memset(dev->priv, 0, sizeof(struct au1k_private)); + aup = dev->priv; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out; + + dev->open = au1k_irda_start; + dev->hard_start_xmit = au1k_irda_hard_xmit; + dev->stop = au1k_irda_stop; + dev->get_stats = au1k_irda_stats; + dev->do_ioctl = au1k_irda_ioctl; + dev->tx_timeout = au1k_tx_timeout; + + irda_device_setup(dev); + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000 |(IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (ring_dest_t *) + dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp); + + /* allocate the data buffers */ + aup->db[0].vaddr = + (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr || !aup->rx_ring[0]) { + retval = -ENOMEM; + goto out; + } + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i=0; i<(2*NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i=0; irx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i=0; itx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + return 0; + +out: + if (aup->db[0].vaddr) + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + if (aup->rx_ring[0]) + kfree((void *)aup->rx_ring[0]); + if (aup->rx_buff.head) + kfree(aup->rx_buff.head); + if (dev->priv != NULL) + kfree(dev->priv); + unregister_netdevice(dev); + printk(KERN_ERR "%s: au1k_init_module failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +static int au1k_init(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int i; + u32 control; + u32 ring_address; + + /* bring the device out of reset */ + control = 0xe; /* coherent, clock enable, one half system clock */ + +#ifndef CONFIG_CPU_LITTLE_ENDIAN + control |= 1; +#endif + aup->tx_head = 0; + aup->tx_tail = 0; + aup->rx_head = 0; + + for (i=0; irx_ring[i]->flags = AU_OWN; + } + + writel(control, IR_INTERFACE_CONFIG); + au_sync_delay(10); + + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */ + au_sync_delay(1); + + writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN); + + ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); + writel(ring_address >> 26, IR_RING_BASE_ADDR_H); + writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L); + + writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE); + + writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */ + writel(0, IR_RING_ADDR_CMPR); + + au1k_irda_set_speed(dev, 9600); + return 0; +} + +static int au1k_irda_start(struct net_device *dev) +{ + int retval; + char hwname[32]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + MOD_INC_USE_COUNT; + + if ((retval = au1k_init(dev))) { + printk(KERN_ERR "%s: error in au1k_init\n", dev->name); + MOD_DEC_USE_COUNT; + return retval; + } + + if ((retval = request_irq(AU1000_IRDA_TX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + free_irq(AU1000_IRDA_TX_INT, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + /* Give self a hardware name */ + sprintf(hwname, "Au1000 SIR/FIR"); + aup->irlap = irlap_open(dev, &aup->qos, hwname); + netif_start_queue(dev); + + writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */ + + aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.data = (unsigned long)dev; + return 0; +} + +static int au1k_irda_stop(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + /* disable interrupts */ + writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); + writel(0, IR_CONFIG_1); + writel(0, IR_INTERFACE_CONFIG); /* disable clock */ + au_sync(); + + if (aup->irlap) { + irlap_close(aup->irlap); + aup->irlap = NULL; + } + + netif_stop_queue(dev); + del_timer(&aup->timer); + + /* disable the interrupt */ + free_irq(AU1000_IRDA_TX_INT, dev); + free_irq(AU1000_IRDA_RX_INT, dev); + MOD_DEC_USE_COUNT; + return 0; +} + +static void __exit au1k_irda_exit(void) +{ + struct net_device *dev = ir_devs[0]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + if (!dev) { + printk(KERN_ERR "au1k_ircc no dev found\n"); + return; + } + if (aup->db[0].vaddr) { + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + aup->db[0].vaddr = 0; + } + if (aup->rx_ring[0]) { + dma_free((void *)aup->rx_ring[0], + 2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); + aup->rx_ring[0] = 0; + } + rtnl_lock(); + unregister_netdevice(dev); + rtnl_unlock(); + ir_devs[0] = 0; +} + + +static inline void +update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; + } +} + + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + volatile ring_dest_t *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + ptxd->count_1<<8 | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + au_sync(); + + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + } + + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } + else { + writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, + IR_CONFIG_1); + au_sync(); + writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, + IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + } + } +} + + +/* + * Au1000 transmit routine. + */ +static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int speed = irda_get_next_speed(skb); + volatile ring_dest_t *ptxd; + u32 len; + + u32 flags; + db_dest_t *pDB; + + if (speed != aup->speed && speed != -1) { + aup->newspeed = speed; + } + + if ((skb->len == 0) && (aup->newspeed)) { + if (aup->tx_tail == aup->tx_head) { + au1k_irda_set_speed(dev, speed); + aup->newspeed = 0; + } + dev_kfree_skb(skb); + return 0; + } + + ptxd = aup->tx_ring[aup->tx_head]; + flags = ptxd->flags; + + if (flags & AU_OWN) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + + pDB = aup->tx_db_inuse[aup->tx_head]; + +#if 0 + if (read_ir_reg(IR_RX_BYTE_CNT) != 0) { + printk("tx warning: rx byte cnt %x\n", + read_ir_reg(IR_RX_BYTE_CNT)); + } +#endif + + if (aup->speed == 4000000) { + /* FIR */ + memcpy((void *)pDB->vaddr, skb->data, skb->len); + ptxd->count_0 = skb->len & 0xff; + ptxd->count_1 = (skb->len >> 8) & 0xff; + } + else { + /* SIR */ + len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); + ptxd->count_0 = len & 0xff; + ptxd->count_1 = (len >> 8) & 0xff; + ptxd->flags |= IR_DIS_CRC; + } + ptxd->flags |= AU_OWN; + au_sync(); + + writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + + dev_kfree_skb(skb); + aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); + dev->trans_start = jiffies; + return 0; +} + + +static inline void +update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR|IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } + else + ps->rx_bytes += count; +} + +/* + * Au1000 receive routine. + */ +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct sk_buff *skb; + volatile ring_dest_t *prxd; + u32 flags, count; + db_dest_t *pDB; + + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = prxd->count_1<<8 | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb=alloc_skb(count+1,GFP_ATOMIC); + if (skb == NULL) { + aup->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count-2); + memcpy(skb->data, (void *)pDB->vaddr, count-2); + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + writel(0, IR_RING_PROMPT); + au_sync(); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + dev->last_rx = jiffies; + + } + return 0; +} + + +void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + + writel(0, IR_INT_CLEAR); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value. The transmitter must be hung? + */ +static void au1k_tx_timeout(struct net_device *dev) +{ + u32 speed; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + printk(KERN_ERR "%s: tx timeout\n", dev->name); + speed = aup->speed; + aup->speed = 0; + au1k_irda_set_speed(dev, speed); + aup->tx_full = 0; + netif_wake_queue(dev); +} + + +/* + * Set the IrDA communications speed. + */ +static int +au1k_irda_set_speed(struct net_device *dev, int speed) +{ + unsigned long flags; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + u32 control; + int ret = 0, timeout = 10, i; + volatile ring_dest_t *ptxd; + + if (speed == aup->speed) + return ret; + + save_flags(flags); + cli(); + + /* disable PHY first */ + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); + + /* disable RX/TX */ + writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), + IR_CONFIG_1); + au_sync_delay(1); + while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) { + mdelay(1); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } + + /* disable DMA */ + writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1); + au_sync_delay(1); + + /* + * After we disable tx/rx. the index pointers + * go back to zero. + */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i=0; itx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } + + for (i=0; irx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } + + if (speed == 4000000) + writel(1<<13, CPLD_AUX1); + else + writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); + + switch (speed) { + case 9600: + writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 19200: + writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 38400: + writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 57600: + writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 115200: + writel(12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 4000000: + writel(0xF, IR_WRITE_PHY_CONFIG); + writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } + + aup->speed = speed; + writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE); + au_sync(); + + control = read_ir_reg(IR_ENABLE); + writel(0, IR_RING_PROMPT); + au_sync(); + + if (control & (1<<14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } + else { + if (control & (1<<11)) + printk(KERN_INFO "%s Valid SIR config\n", dev->name); + if (control & (1<<12)) + printk(KERN_INFO "%s Valid MIR config\n", dev->name); + if (control & (1<<13)) + printk(KERN_INFO "%s Valid FIR config\n", dev->name); + if (control & (1<<10)) + printk(KERN_INFO "%s TX enabled\n", dev->name); + if (control & (1<<9)) + printk(KERN_INFO "%s RX enabled\n", dev->name); + } + + restore_flags(flags); + return ret; +} + +static int +au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct au1k_private *aup = dev->priv; + int ret = -EOPNOTSUPP; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (aup->open) + ret = au1k_irda_set_speed(dev, + rq->ifr_baudrate); + else { + printk(KERN_ERR "%s ioctl: !netif_running\n", + dev->name); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = 0; + break; + default: + break; + } + return ret; +} + + +static struct net_device_stats *au1k_irda_stats(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + return &aup->stats; +} + +#ifdef MODULE +MODULE_AUTHOR("Pete Popov "); +MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); + +module_init(au1k_irda_init); +module_exit(au1k_irda_exit); +#endif /* MODULE */ diff -urN linux-2.4.18/drivers/net/irda/irda-usb.c linux-2.4.19-pre5/drivers/net/irda/irda-usb.c --- linux-2.4.18/drivers/net/irda/irda-usb.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/irda/irda-usb.c Sat Mar 30 22:55:34 2002 @@ -378,10 +378,17 @@ return 0; } - /* Make room for IrDA-USB header (note skb->len += USB_IRDA_HEADER) */ - if (skb_cow(skb, USB_IRDA_HEADER)) { - dev_kfree_skb(skb); - return 0; + /* Make sure there is room for IrDA-USB header. The actual + * allocation will be done lower in skb_push(). + * Also, we don't use directly skb_cow(), because it require + * headroom >= 16, which force unnecessary copies - Jean II */ + if (skb_headroom(skb) < USB_IRDA_HEADER) { + IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n"); + if (skb_cow(skb, USB_IRDA_HEADER)) { + WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n"); + dev_kfree_skb(skb); + return 0; + } } spin_lock_irqsave(&self->lock, flags); @@ -432,7 +439,7 @@ #ifdef IU_USB_MIN_RTT /* Factor in USB delays -> Get rid of udelay() that * would be lost in the noise - Jean II */ - diff -= IU_USB_MIN_RTT; + diff += IU_USB_MIN_RTT; #endif /* IU_USB_MIN_RTT */ if (diff < 0) diff += 1000000; @@ -848,8 +855,8 @@ /* Submit the idle URB to replace the URB we've just received */ irda_usb_submit(self, skb, self->idle_rx_urb); /* Recycle Rx URB : Now, the idle URB is the present one */ - self->idle_rx_urb = purb; purb->context = NULL; + self->idle_rx_urb = purb; } /*------------------------------------------------------------------*/ @@ -952,13 +959,17 @@ /* Allow IrLAP to send data to us */ netif_start_queue(netdev); + /* We submit all the Rx URB except for one that we keep idle. + * Need to be initialised before submitting other USBs, because + * in some cases as soon as we submit the URBs the USB layer + * will trigger a dummy receive - Jean II */ + self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]); + self->idle_rx_urb->context = NULL; + /* Now that we can pass data to IrLAP, allow the USB layer * to send us some data... */ for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) irda_usb_submit(self, NULL, &(self->rx_urb[i])); - /* Note : we submit all the Rx URB except for one - Jean II */ - self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]); - self->idle_rx_urb->context = NULL; /* Ready to play !!! */ MOD_INC_USE_COUNT; @@ -1582,3 +1593,4 @@ MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/irda/sa1100_ir.c linux-2.4.19-pre5/drivers/net/irda/sa1100_ir.c --- linux-2.4.18/drivers/net/irda/sa1100_ir.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/irda/sa1100_ir.c Sat Mar 30 22:55:28 2002 @@ -132,7 +132,7 @@ Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; /* - * Enable the DMA, receiver and recieve interrupt. + * Enable the DMA, receiver and receive interrupt. */ sa1100_dma_flush_all(si->rxdma); sa1100_dma_queue_buffer(si->rxdma, NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN); diff -urN linux-2.4.18/drivers/net/lance.c linux-2.4.19-pre5/drivers/net/lance.c --- linux-2.4.18/drivers/net/lance.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/lance.c Sat Mar 30 22:55:40 2002 @@ -354,7 +354,7 @@ board probes now that kmalloc() can allocate ISA DMA-able regions. This also allows the LANCE driver to be used as a module. */ -int lance_probe(struct net_device *dev) +int __init lance_probe(struct net_device *dev) { int *port, result; @@ -383,7 +383,7 @@ return 0; } } - release_resource(r); + release_region(ioaddr, LANCE_TOTAL_SIZE); } } return -ENODEV; diff -urN linux-2.4.18/drivers/net/lne390.c linux-2.4.19-pre5/drivers/net/lne390.c --- linux-2.4.18/drivers/net/lne390.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/lne390.c Sat Mar 30 22:55:40 2002 @@ -381,9 +381,10 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); -MODULE_PARM_DESC(io, "LNE390 I/O base address(es)"); -MODULE_PARM_DESC(irq, "LNE390 IRQ number(s)"); -MODULE_PARM_DESC(mem, "LNE390 memory base address(es)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(mem, "memory base address(es)"); +MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver"); MODULE_LICENSE("GPL"); int init_module(void) diff -urN linux-2.4.18/drivers/net/mace.c linux-2.4.19-pre5/drivers/net/mace.c --- linux-2.4.18/drivers/net/mace.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/mace.c Sat Mar 30 22:55:34 2002 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -549,17 +550,12 @@ return &p->stats; } -/* - * CRC polynomial - used in working out multicast filter bits. - */ -#define CRC_POLY 0xedb88320 - static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; - int i, j, k, b; - unsigned long crc; + int i, j; + u32 crc; mp->maccc &= ~PROM; if (dev->flags & IFF_PROMISC) { @@ -575,17 +571,7 @@ for (i = 0; i < 8; i++) multicast_filter[i] = 0; for (i = 0; i < dev->mc_count; i++) { - crc = ~0; - for (j = 0; j < 6; ++j) { - b = dmi->dmi_addr[j]; - for (k = 0; k < 8; ++k) { - if ((crc ^ b) & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - b >>= 1; - } - } + crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); dmi = dmi->next; diff -urN linux-2.4.18/drivers/net/macmace.c linux-2.4.19-pre5/drivers/net/macmace.c --- linux-2.4.18/drivers/net/macmace.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/macmace.c Sat Mar 30 22:55:34 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -539,17 +540,12 @@ return &p->stats; } -/* - * CRC polynomial - used in working out multicast filter bits. - */ -#define CRC_POLY 0xedb88320 - static void mace68k_set_multicast(struct net_device *dev) { struct mace68k_data *mp = (struct mace68k_data *) dev->priv; volatile struct mace *mb = mp->mace; int i, j, k, b; - unsigned long crc; + u32 crc; mp->maccc &= ~PROM; if (dev->flags & IFF_PROMISC) @@ -570,19 +566,7 @@ multicast_filter[i] = 0; for (i = 0; i < dev->mc_count; i++) { - crc = ~0; - for (j = 0; j < 6; ++j) - { - b = dmi->dmi_addr[j]; - for (k = 0; k < 8; ++k) - { - if ((crc ^ b) & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - b >>= 1; - } - } + crc = ether_crc_le(6, dmi->dmi_addr); j = crc >> 26; /* bit number in multicast_filter */ multicast_filter[j >> 3] |= 1 << (j & 7); dmi = dmi->next; diff -urN linux-2.4.18/drivers/net/myri_sbus.c linux-2.4.19-pre5/drivers/net/myri_sbus.c --- linux-2.4.18/drivers/net/myri_sbus.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/myri_sbus.c Sat Mar 30 22:55:34 2002 @@ -800,9 +800,6 @@ static struct net_device_stats *myri_get_stats(struct net_device *dev) { return &(((struct myri_eth *)dev->priv)->enet_stats); } -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static void myri_set_multicast(struct net_device *dev) { /* Do nothing, all MyriCOM nodes transmit multicast frames diff -urN linux-2.4.18/drivers/net/natsemi.c linux-2.4.19-pre5/drivers/net/natsemi.c --- linux-2.4.18/drivers/net/natsemi.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/natsemi.c Sat Mar 30 22:55:34 2002 @@ -105,6 +105,9 @@ version 1.0.14: * Cleanup some messages and autoneg in ethtool (Tim Hockin) + version 1.0.13: + * crc cleanup (Matt Domsch ) + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY @@ -1731,36 +1734,15 @@ return &np->stats; } -/* The little-endian AUTODIN II ethernet CRC calculations. - A big-endian version is also available. - This is slow but compact code. Do not use this routine for bulk data, - use a table-based routine instead. - This is common code and should be moved to net/core/crc.c. - Chips may use the upper or lower CRC bits, and may reverse and/or invert - them. Select the endian-ness that results in minimal calculations. -*/ -#if 0 -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -#else +/** + * dp83815_crc - computer CRC for hash table entries + * + * Note - this is, for some reason, *not* the same function + * as ether_crc_le() or ether_crc(), though it uses the + * same big-endian polynomial. + */ #define DP_POLYNOMIAL 0x04C11DB7 -/* dp83815_crc - computer CRC for hash table entries */ -static unsigned ether_crc_le(int length, unsigned char *data) +static unsigned dp83815_crc(int length, unsigned char *data) { u32 crc; u8 cur_byte; @@ -1784,7 +1766,7 @@ return (crc); } -#endif + void set_bit_le(int offset, unsigned char * data) { @@ -1814,7 +1796,7 @@ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff, mc_filter); } rx_mode = RxFilterEnable | AcceptBroadcast @@ -1965,6 +1947,8 @@ /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; + /* LSTATUS is latched low until a read - so read twice */ + mdio_read(dev, 1, MII_BMSR); edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; diff -urN linux-2.4.18/drivers/net/ne.c linux-2.4.19-pre5/drivers/net/ne.c --- linux-2.4.18/drivers/net/ne.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ne.c Sat Mar 30 22:55:40 2002 @@ -734,9 +734,11 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); -MODULE_PARM_DESC(io, "NEx000 I/O base address(es),required"); -MODULE_PARM_DESC(irq, "NEx000 IRQ number(s)"); -MODULE_PARM_DESC(bad, "NEx000 accept bad clone(s)"); +MODULE_PARM_DESC(io, "I/O base address(es),required"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); +MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); +MODULE_LICENSE("GPL"); /* This is set up so that no ISA autoprobe takes place. We can't guarantee that the ne2k probe is the last 8390 based probe to take place (as it @@ -788,7 +790,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); /* diff -urN linux-2.4.18/drivers/net/ne2k-pci.c linux-2.4.19-pre5/drivers/net/ne2k-pci.c --- linux-2.4.18/drivers/net/ne2k-pci.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/ne2k-pci.c Sat Mar 30 22:55:40 2002 @@ -82,9 +82,9 @@ MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM_DESC(debug, "PCI NE2000 debug level (1-2)"); -MODULE_PARM_DESC(options, "PCI NE2000: Bit 5: full duplex"); -MODULE_PARM_DESC(full_duplex, "PCI NE2000 full duplex setting(s) (1)"); +MODULE_PARM_DESC(debug, "debug level (1-2)"); +MODULE_PARM_DESC(options, "Bit 5: full duplex"); +MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); /* Some defines that people can play with if so inclined. */ diff -urN linux-2.4.18/drivers/net/ne3210.c linux-2.4.19-pre5/drivers/net/ne3210.c --- linux-2.4.18/drivers/net/ne3210.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ne3210.c Sat Mar 30 22:55:40 2002 @@ -370,9 +370,11 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM_DESC(io, "NE3210 I/O base address(es)"); -MODULE_PARM_DESC(irq, "NE3210 IRQ number(s)"); -MODULE_PARM_DESC(mem, "NE3210 memory base address(es)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(mem, "memory base address(es)"); +MODULE_DESCRIPTION("NE3210 EISA Ethernet driver"); +MODULE_LICENSE("GPL"); int init_module(void) { @@ -415,7 +417,6 @@ } } } -MODULE_LICENSE("GPL"); #endif /* MODULE */ diff -urN linux-2.4.18/drivers/net/ns83820.c linux-2.4.19-pre5/drivers/net/ns83820.c --- linux-2.4.18/drivers/net/ns83820.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/ns83820.c Sat Mar 30 22:55:34 2002 @@ -1,7 +1,7 @@ -#define _VERSION "0.15" +#define _VERSION "0.17" /* ns83820.c by Benjamin LaHaise with contributions. * - * $Revision: 1.34.2.12 $ + * $Revision: 1.34.2.14 $ * * Copyright 2001 Benjamin LaHaise. * Copyright 2001 Red Hat. @@ -51,6 +51,8 @@ * suppress duplicate link status messages * 20011117 0.14 - ethtool GDRVINFO, GLINK support from jgarzik * 20011204 0.15 get ppc (big endian) working + * 20011218 0.16 various cleanups + * 20020310 0.17 speedups * * Driver Overview * =============== @@ -93,8 +95,8 @@ #include /* for IPPROTO_... */ #include #include +#include #include -//#include #include #include @@ -154,10 +156,16 @@ #endif /* tunables */ -#define RX_BUF_SIZE 6144 /* 8192 */ -#define NR_RX_DESC 256 +#define RX_BUF_SIZE 1500 /* 8192 */ -#define NR_TX_DESC 256 +/* Must not exceed ~65000. */ +#define NR_RX_DESC 64 +#define NR_TX_DESC 64 + +/* not tunable */ +#define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14) /* rx/tx mac addr + type */ + +#define MIN_TX_DESC_FREE 8 /* register defines */ #define CFGCS 0x04 @@ -408,7 +416,8 @@ struct sk_buff *skbs[NR_RX_DESC]; - unsigned next_rx, next_empty; + u32 *next_rx_desc; + u16 next_rx, next_empty; u32 *descs; dma_addr_t phy_descs; @@ -423,6 +432,7 @@ struct pci_dev *pci_dev; struct rx_info rx_info; + struct tasklet_struct rx_tasklet; unsigned ihr; struct tq_struct tq_refill; @@ -441,10 +451,11 @@ spinlock_t tx_lock; long tx_idle; - u32 tx_done_idx; - u32 tx_idx; - volatile u32 tx_free_idx; /* idx of free desc chain */ - u32 tx_intr_idx; + + u16 tx_done_idx; + u16 tx_idx; + volatile u16 tx_free_idx; /* idx of free desc chain */ + u16 tx_intr_idx; struct sk_buff *tx_skbs[NR_TX_DESC]; @@ -455,7 +466,7 @@ //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC #define start_tx_okay(dev) \ - (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > NR_TX_DESC/2) + (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE) /* Packet Receiver @@ -509,7 +520,7 @@ next_empty = dev->rx_info.next_empty; /* don't overrun last rx marker */ - if (nr_rx_empty(dev) <= 2) { + if (unlikely(nr_rx_empty(dev) <= 2)) { kfree_skb(skb); return 1; } @@ -523,34 +534,39 @@ #endif sg = dev->rx_info.descs + (next_empty * DESC_SIZE); - if (dev->rx_info.skbs[next_empty]) + if (unlikely(NULL != dev->rx_info.skbs[next_empty])) BUG(); dev->rx_info.skbs[next_empty] = skb; dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC; - cmdsts = RX_BUF_SIZE | CMDSTS_INTR; - buf = pci_map_single(dev->pci_dev, skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + cmdsts = REAL_RX_BUF_SIZE | CMDSTS_INTR; + buf = pci_map_single(dev->pci_dev, skb->tail, + REAL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); build_rx_desc(dev, sg, 0, buf, cmdsts, 0); /* update link of previous rx */ - if (next_empty != dev->rx_info.next_rx) + if (likely(next_empty != dev->rx_info.next_rx)) dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = cpu_to_le32(dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4)); return 0; } -static int rx_refill(struct ns83820 *dev, int gfp) +static inline int rx_refill(struct ns83820 *dev, int gfp) { unsigned i; long flags = 0; + if (unlikely(nr_rx_empty(dev) <= 2)) + return 0; + dprintk("rx_refill(%p)\n", dev); if (gfp == GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); for (i=0; itail & 0xf; @@ -575,6 +591,12 @@ return i ? 0 : -ENOMEM; } +static void FASTCALL(rx_refill_atomic(struct ns83820 *dev)); +static void rx_refill_atomic(struct ns83820 *dev) +{ + rx_refill(dev, GFP_ATOMIC); +} + /* REFILL */ static inline void queue_refill(void *_dev) { @@ -590,6 +612,7 @@ build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0); } +static void FASTCALL(phy_intr(struct ns83820 *dev)); static void phy_intr(struct ns83820 *dev) { static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; @@ -600,7 +623,6 @@ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; if (dev->CFG_cache & CFG_TBI_EN) { - /* we have an optical transceiver */ tbisr = readl(dev->base + TBISR); tanar = readl(dev->base + TANAR); @@ -646,20 +668,24 @@ new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS); if (cfg & CFG_SPDSTS1) - new_cfg |= CFG_MODE_1000 | CFG_SB; + new_cfg |= CFG_MODE_1000; else - new_cfg &= ~CFG_MODE_1000 | CFG_SB; + new_cfg &= ~CFG_MODE_1000; - if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) { + speed = ((cfg / CFG_SPDSTS0) & 3); + fullduplex = (cfg & CFG_DUPSTS); + + if (fullduplex) + new_cfg |= CFG_SB; + + if ((cfg & CFG_LNKSTS) && + ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) { writel(new_cfg, dev->base + CFG); dev->CFG_cache = new_cfg; } dev->CFG_cache &= ~CFG_SPDSTS; dev->CFG_cache |= cfg & CFG_SPDSTS; - - speed = ((cfg / CFG_SPDSTS0) & 3); - fullduplex = (cfg & CFG_DUPSTS); } newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN; @@ -690,6 +716,7 @@ dev->rx_info.idle = 1; dev->rx_info.next_rx = 0; + dev->rx_info.next_rx_desc = dev->rx_info.descs; dev->rx_info.next_empty = 0; for (i=0; iIMR_cache |= ISR_RXDESC; dev->IMR_cache |= ISR_RXIDLE; dev->IMR_cache |= ISR_TXDESC; - //dev->IMR_cache |= ISR_TXIDLE; + dev->IMR_cache |= ISR_TXIDLE; writel(dev->IMR_cache, dev->base + IMR); writel(1, dev->base + IER); @@ -770,6 +797,24 @@ } } +static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev)); +static void ns83820_rx_kick(struct ns83820 *dev) +{ + /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { + if (dev->rx_info.up) { + rx_refill_atomic(dev); + kick_rx(dev); + } + } + + if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4) + schedule_task(&dev->tq_refill); + else + kick_rx(dev); + if (dev->rx_info.idle) + Dprintk("BAD\n"); +} + /* rx_irq * */ @@ -785,10 +830,10 @@ dprintk("rx_irq(%p)\n", dev); dprintk("rxdp: %08x, descs: %08lx next_rx[%d]: %p next_empty[%d]: %p\n", readl(dev->base + RXDP), - (dev->rx_info.phy_descs), - dev->rx_info.next_rx, + (long)(dev->rx_info.phy_descs), + (int)dev->rx_info.next_rx, (dev->rx_info.descs + (DESC_SIZE * dev->rx_info.next_rx)), - dev->rx_info.next_empty, + (int)dev->rx_info.next_empty, (dev->rx_info.descs + (DESC_SIZE * dev->rx_info.next_empty)) ); @@ -798,7 +843,7 @@ dprintk("walking descs\n"); next_rx = info->next_rx; - desc = info->descs + (DESC_SIZE * next_rx); + desc = info->next_rx_desc; while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) && (cmdsts != CMDSTS_OWN)) { struct sk_buff *skb; @@ -813,29 +858,16 @@ info->skbs[next_rx] = NULL; info->next_rx = (next_rx + 1) % NR_RX_DESC; - barrier(); + mb(); clear_rx_desc(dev, next_rx); pci_unmap_single(dev->pci_dev, bufptr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (CMDSTS_OK & cmdsts) { -#if 0 //ndef __i386__ - struct sk_buff *tmp; -#endif + if (likely(CMDSTS_OK & cmdsts)) { int len = cmdsts & 0xffff; - if (!skb) - BUG(); skb_put(skb, len); -#if 0 //ndef __i386__ /* I hate the network stack sometimes */ - tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC); - if (!tmp) - goto done; - tmp->dev = &dev->net_dev; - skb_reserve(tmp, 2); - memcpy(skb_put(tmp, len), skb->data, len); - kfree_skb(skb); - skb = tmp; -#endif + if (unlikely(!skb)) + goto netdev_mangle_me_harder_failed; if (cmdsts & CMDSTS_DEST_MULTI) dev->stats.multicast ++; dev->stats.rx_packets ++; @@ -846,11 +878,10 @@ skb->ip_summed = CHECKSUM_NONE; } skb->protocol = eth_type_trans(skb, &dev->net_dev); - if (NET_RX_DROP == netif_rx(skb)) + if (NET_RX_DROP == netif_rx(skb)) { +netdev_mangle_me_harder_failed: dev->stats.rx_dropped ++; -#if 0 //ndef __i386__ - done:; -#endif + } } else { kfree_skb(skb); } @@ -860,6 +891,7 @@ desc = info->descs + (DESC_SIZE * next_rx); } info->next_rx = next_rx; + info->next_rx_desc = info->descs + (DESC_SIZE * next_rx); out: if (0 && !nr) { @@ -869,6 +901,15 @@ spin_unlock_irqrestore(&info->lock, flags); } +static void rx_action(unsigned long _dev) +{ + struct ns83820 *dev = (void *)_dev; + rx_irq(dev); + writel(0x002, dev->base + IHR); + writel(dev->IMR_cache | ISR_RXDESC, dev->base + IMR); + rx_irq(dev); + ns83820_rx_kick(dev); +} /* Packet Transmit code */ @@ -879,7 +920,9 @@ writel(CR_TXE, dev->base + CR); } -/* no spinlock needed on the transmit irq path as the interrupt handler is serialized */ +/* No spinlock needed on the transmit irq path as the interrupt handler is + * serialized. + */ static void do_tx_done(struct ns83820 *dev) { u32 cmdsts, tx_done_idx, *desc; @@ -917,7 +960,7 @@ tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC; dev->tx_done_idx = tx_done_idx; desc[CMDSTS] = cpu_to_le32(0); - barrier(); + mb(); desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); } @@ -952,7 +995,6 @@ * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -#define MAX_FRAG_LEN 8192 /* disabled for now */ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) { struct ns83820 *dev = (struct ns83820 *)_dev; @@ -970,9 +1012,9 @@ nr_frags = skb_shinfo(skb)->nr_frags; again: - if (__builtin_expect(dev->CFG_cache & CFG_LNKSTS, 0)) { + if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { netif_stop_queue(&dev->net_dev); - if (__builtin_expect(dev->CFG_cache & CFG_LNKSTS, 0)) + if (unlikely(dev->CFG_cache & CFG_LNKSTS)) return 1; netif_start_queue(&dev->net_dev); } @@ -981,7 +1023,7 @@ tx_done_idx = dev->tx_done_idx; nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC; nr_free -= 1; - if ((nr_free <= nr_frags) || (nr_free <= 8192 / MAX_FRAG_LEN)) { + if (nr_free <= nr_frags) { dprintk("stop_queue - not enough(%p)\n", dev); netif_stop_queue(&dev->net_dev); @@ -996,11 +1038,11 @@ if (free_idx == dev->tx_intr_idx) { do_intr = 1; - dev->tx_intr_idx = (dev->tx_intr_idx + NR_TX_DESC/2) % NR_TX_DESC; + dev->tx_intr_idx = (dev->tx_intr_idx + NR_TX_DESC/4) % NR_TX_DESC; } nr_free -= nr_frags; - if (nr_free < 1) { + if (nr_free < MIN_TX_DESC_FREE) { dprintk("stop_queue - last entry(%p)\n", dev); netif_stop_queue(&dev->net_dev); stopped = 1; @@ -1028,14 +1070,6 @@ for (;;) { volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE); u32 residue = 0; -#if 0 - if (len > MAX_FRAG_LEN) { - residue = len; - /* align the start address of the next fragment */ - len = MAX_FRAG_LEN; - residue -= len; - } -#endif dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len, (unsigned long long)buf); @@ -1084,6 +1118,7 @@ { u8 *base = dev->base; + /* the DP83820 will freeze counters, so we need to read all of them */ dev->stats.rx_errors += readl(base + 0x60) & 0xffff; dev->stats.rx_crc_errors += readl(base + 0x64) & 0xffff; dev->stats.rx_missed_errors += readl(base + 0x68) & 0xffff; @@ -1162,54 +1197,54 @@ } } +static void ns83820_mib_isr(struct ns83820 *dev) +{ + spin_lock(&dev->misc_lock); + ns83820_update_stats(dev); + spin_unlock(&dev->misc_lock); +} + static void ns83820_irq(int foo, void *data, struct pt_regs *regs) { struct ns83820 *dev = data; - int count = 0; u32 isr; dprintk("ns83820_irq(%p)\n", dev); dev->ihr = 0; - while (count++ < 32 && (isr = readl(dev->base + ISR))) { - dprintk("irq: %08x\n", isr); + isr = readl(dev->base + ISR); + dprintk("irq: %08x\n", isr); - if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC)) - Dprintk("odd isr? 0x%08x\n", isr); - - if ((ISR_RXEARLY | ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) { - if (ISR_RXIDLE & isr) { - dev->rx_info.idle = 1; - Dprintk("oh dear, we are idle\n"); - } - - if ((ISR_RXDESC) & isr) { - rx_irq(dev); - writel(4, dev->base + IHR); - } - - if (nr_rx_empty(dev) >= NR_RX_DESC/4) { - if (dev->rx_info.up) { - rx_refill(dev, GFP_ATOMIC); - kick_rx(dev); - } - } +#ifdef DEBUG + if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC)) + Dprintk("odd isr? 0x%08x\n", isr); +#endif - if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4) - schedule_task(&dev->tq_refill); - else - kick_rx(dev); - if (dev->rx_info.idle) - Dprintk("BAD\n"); + if (ISR_RXIDLE & isr) { + dev->rx_info.idle = 1; + Dprintk("oh dear, we are idle\n"); + ns83820_rx_kick(dev); + } + + if ((ISR_RXDESC | ISR_RXOK) & isr) { + prefetch(dev->rx_info.next_rx_desc); + writel(dev->IMR_cache & ~(ISR_RXDESC | ISR_RXOK), dev->base + IMR); + tasklet_schedule(&dev->rx_tasklet); + //rx_irq(dev); + //writel(4, dev->base + IHR); } + if ((ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) + ns83820_rx_kick(dev); + if (unlikely(ISR_RXSOVR & isr)) { - Dprintk("overrun: rxsovr\n"); - dev->stats.rx_over_errors ++; + //printk("overrun: rxsovr\n"); + dev->stats.rx_fifo_errors ++; } + if (unlikely(ISR_RXORN & isr)) { - Dprintk("overrun: rxorn\n"); - dev->stats.rx_over_errors ++; + //printk("overrun: rxorn\n"); + dev->stats.rx_fifo_errors ++; } if ((ISR_RXRCMP & isr) && dev->rx_info.up) @@ -1241,15 +1276,11 @@ if ((ISR_TXDESC | ISR_TXIDLE) & isr) do_tx_done(dev); - if (ISR_MIB & isr) { - spin_lock(&dev->misc_lock); - ns83820_update_stats(dev); - spin_unlock(&dev->misc_lock); - } + if (unlikely(ISR_MIB & isr)) + ns83820_mib_isr(dev); - if (ISR_PHY & isr) + if (unlikely(ISR_PHY & isr)) phy_intr(dev); - } #if 0 /* Still working on the interrupt mitigation strategy */ if (dev->ihr) @@ -1412,6 +1443,7 @@ dev->net_dev.owner = THIS_MODULE; PREPARE_TQUEUE(&dev->tq_refill, queue_refill, dev); + tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev); err = pci_enable_device(pci_dev); if (err) { @@ -1430,8 +1462,9 @@ if (!dev->base || !dev->tx_descs || !dev->rx_info.descs) goto out_disable; - dprintk("%p: %08lx %p: %08lx\n", dev->tx_descs, dev->tx_phy_descs, - dev->rx_info.descs, dev->rx_info.phy_descs); + dprintk("%p: %08lx %p: %08lx\n", + dev->tx_descs, (long)dev->tx_phy_descs, + dev->rx_info.descs, (long)dev->rx_info.phy_descs); /* disable interrupts */ writel(0, dev->base + IMR); writel(0, dev->base + IER); @@ -1484,14 +1517,14 @@ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { - printk("%s: enabling 64 bit PCI addressing.\n", + printk("%s: detected 64 bit PCI data bus.\n", dev->net_dev.name); - dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN; -#if defined(USE_64BIT_ADDR) - dev->net_dev.features |= NETIF_F_HIGHDMA; -#endif + /*dev->CFG_cache |= CFG_DATA64_EN;*/ + if (!(dev->CFG_cache & CFG_DATA64_EN)) + printk("%s: EEPROM did not enable 64 bit bus. Disabled.\n", + dev->net_dev.name); } else - dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN); + dev->CFG_cache &= ~(CFG_DATA64_EN); dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS | CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 | @@ -1528,8 +1561,12 @@ writel(dev->CFG_cache, dev->base + CFG); dprintk("CFG: %08x\n", dev->CFG_cache); +#if 1 /* Huh? This sets the PCI latency register. Should be done via + * the PCI layer. FIXME. + */ if (readl(dev->base + SRR)) writel(readl(dev->base+0x20c) | 0xfe00, dev->base + 0x20c); +#endif /* Note! The DMA burst size interacts with packet * transmission, such that the largest packet that @@ -1543,13 +1580,15 @@ /* Flush the interrupt holdoff timer */ writel(0x000, dev->base + IHR); writel(0x100, dev->base + IHR); + writel(0x000, dev->base + IHR); /* Set Rx to full duplex, don't accept runt, errored, long or length - * range errored packets. Set MXDMA to 7 => 512 word burst + * range errored packets. Set MXDMA to 0 => 1024 word burst */ writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD + | RXCFG_STRIPCRC | RXCFG_ALP - | RXCFG_MXDMA | 0, dev->base + RXCFG); + | (RXCFG_MXDMA0 * 0) | 0, dev->base + RXCFG); /* Disable priority queueing */ writel(0, dev->base + PQCR); @@ -1576,7 +1615,11 @@ dev->net_dev.features |= NETIF_F_SG; dev->net_dev.features |= NETIF_F_IP_CSUM; #if defined(USE_64BIT_ADDR) || defined(CONFIG_HIGHMEM4G) - dev->net_dev.features |= NETIF_F_HIGHDMA; + if ((dev->CFG_cache & CFG_T64ADDR)) { + printk(KERN_INFO "%s: using 64 bit addressing.\n", + dev->net_dev.name); + dev->net_dev.features |= NETIF_F_HIGHDMA; + } #endif printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", @@ -1587,7 +1630,7 @@ dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], addr, pci_dev->irq, - (dev->net_dev.features & NETIF_F_HIGHDMA) ? "sg" : "h,sg" + (dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); return 0; diff -urN linux-2.4.18/drivers/net/pci-skeleton.c linux-2.4.19-pre5/drivers/net/pci-skeleton.c --- linux-2.4.18/drivers/net/pci-skeleton.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/pci-skeleton.c Sat Mar 30 22:55:34 2002 @@ -96,6 +96,7 @@ #include #include #include +#include #include #define NETDRV_VERSION "1.0.0" @@ -509,7 +510,6 @@ static int netdrv_close (struct net_device *dev); static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *netdrv_get_stats (struct net_device *dev); -static inline u32 ether_crc (int length, unsigned char *data); static void netdrv_set_rx_mode (struct net_device *dev); static void netdrv_hw_start (struct net_device *dev); @@ -1852,27 +1852,6 @@ /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc (int length, unsigned char *data) -{ - int crc = -1; - - DPRINTK ("ENTER\n"); - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? - ethernet_polynomial : 0); - } - - DPRINTK ("EXIT\n"); - return crc; -} - static void netdrv_set_rx_mode (struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/pcmcia/com20020_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/com20020_cs.c --- linux-2.4.18/drivers/net/pcmcia/com20020_cs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/com20020_cs.c Sat Mar 30 22:55:28 2002 @@ -122,6 +122,7 @@ MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +MODULE_LICENSE("GPL"); /*====================================================================*/ diff -urN linux-2.4.18/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/fmvj18x_cs.c --- linux-2.4.18/drivers/net/pcmcia/fmvj18x_cs.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/pcmcia/fmvj18x_cs.c Sat Mar 30 22:55:34 2002 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -1247,27 +1248,6 @@ /* Set the multicast/promiscuous mode for this adaptor. */ - -/* The little-endian AUTODIN II ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} static void set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/pcmcia/ray_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/ray_cs.c --- linux-2.4.18/drivers/net/pcmcia/ray_cs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/ray_cs.c Sat Mar 30 22:55:34 2002 @@ -999,7 +999,9 @@ /*===========================================================================*/ int ray_dev_init(struct net_device *dev) { +#ifdef RAY_IMMEDIATE_INIT int i; +#endif /* RAY_IMMEDIATE_INIT */ ray_dev_t *local = dev->priv; dev_link_t *link = local->finder; @@ -1008,6 +1010,7 @@ DEBUG(2,"ray_dev_init - device not present\n"); return -1; } +#ifdef RAY_IMMEDIATE_INIT /* Download startup parameters */ if ( (i = dl_startup_params(dev)) < 0) { @@ -1015,7 +1018,14 @@ "returns 0x%x\n",i); return -1; } - +#else /* RAY_IMMEDIATE_INIT */ + /* Postpone the card init so that we can still configure the card, + * for example using the Wireless Extensions. The init will happen + * in ray_open() - Jean II */ + DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n", + local->card_status); +#endif /* RAY_IMMEDIATE_INIT */ + /* copy mac and broadcast addresses to linux device */ memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); @@ -1245,6 +1255,22 @@ wrq->u.freq.e = 0; break; + /* Set frequency/channel */ + case SIOCSIWFREQ: + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* Setting by channel number */ + if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0)) + err = -EOPNOTSUPP; + else + local->sparm.b5.a_hop_pattern = wrq->u.freq.m; + break; + /* Get current network name (ESSID) */ case SIOCGIWESSID: if (wrq->u.data.pointer) @@ -1262,6 +1288,46 @@ } break; + /* Set desired network name (ESSID) */ + case SIOCSIWESSID: + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + if (wrq->u.data.pointer) + { + char card_essid[IW_ESSID_MAX_SIZE + 1]; + + /* Check if we asked for `any' */ + if(wrq->u.data.flags == 0) + { + /* Corey : can you do that ? */ + err = -EOPNOTSUPP; + } + else + { + /* Check the size of the string */ + if(wrq->u.data.length > + IW_ESSID_MAX_SIZE + 1) + { + err = -E2BIG; + break; + } + copy_from_user(card_essid, + wrq->u.data.pointer, + wrq->u.data.length); + card_essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the ESSID in the card */ + memcpy(local->sparm.b5.a_current_ess_id, card_essid, + IW_ESSID_MAX_SIZE); + } + } + break; + /* Get current Access Point (BSSID in our case) */ case SIOCGIWAP: memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN); @@ -1304,6 +1370,34 @@ wrq->u.rts.fixed = 1; break; + /* Set the desired RTS threshold */ + case SIOCSIWRTS: + { + int rthr = wrq->u.rts.value; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* if(wrq->u.rts.fixed == 0) we should complain */ +#if WIRELESS_EXT > 8 + if(wrq->u.rts.disabled) + rthr = 32767; + else +#endif /* WIRELESS_EXT > 8 */ + if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ + { + err = -EINVAL; + break; + } + local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; + local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; + } + break; + /* Get the current fragmentation threshold */ case SIOCGIWFRAG: wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) @@ -1313,6 +1407,35 @@ #endif /* WIRELESS_EXT > 8 */ wrq->u.frag.fixed = 1; break; + + /* Set the desired fragmentation threshold */ + case SIOCSIWFRAG: + { + int fthr = wrq->u.frag.value; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* if(wrq->u.frag.fixed == 0) should complain */ +#if WIRELESS_EXT > 8 + if(wrq->u.frag.disabled) + fthr = 32767; + else +#endif /* WIRELESS_EXT > 8 */ + if((fthr < 256) || (fthr > 2347)) /* To check out ! */ + { + err = -EINVAL; + break; + } + local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; + local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; + } + break; + #endif /* WIRELESS_EXT > 7 */ #if WIRELESS_EXT > 8 @@ -1323,6 +1446,33 @@ else wrq->u.mode = IW_MODE_ADHOC; break; + + /* Set the current mode of operation */ + case SIOCSIWMODE: + { + char card_mode = 1; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + switch (wrq->u.mode) + { + case IW_MODE_ADHOC: + card_mode = 0; + // Fall through + case IW_MODE_INFRA: + local->sparm.b5.a_network_type = card_mode; + break; + default: + err = -EINVAL; + } + } + break; + #endif /* WIRELESS_EXT > 8 */ #if WIRELESS_EXT > 7 /* ------------------ IWSPY SUPPORT ------------------ */ @@ -1549,6 +1699,21 @@ if (link->open == 0) local->num_multi = 0; link->open++; + /* If the card is not started, time to start it ! - Jean II */ + if(local->card_status == CARD_AWAITING_PARAM) { + int i; + + DEBUG(1,"ray_open: doing init now !\n"); + + /* Download startup parameters */ + if ( (i = dl_startup_params(dev)) < 0) + { + printk(KERN_INFO "ray_dev_init dl_startup_params failed - " + "returns 0x%x\n",i); + return -1; + } + } + if (sniffer) netif_stop_queue(dev); else netif_start_queue(dev); @@ -1571,6 +1736,11 @@ netif_stop_queue(dev); if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); + + /* In here, we should stop the hardware (stop card from beeing active) + * and set local->card_status to CARD_AWAITING_PARAM, so that while the + * card is closed we can chage its configuration. + * Probably also need a COR reset to get sane state - Jean II */ MOD_DEC_USE_COUNT; diff -urN linux-2.4.18/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/smc91c92_cs.c --- linux-2.4.18/drivers/net/pcmcia/smc91c92_cs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/smc91c92_cs.c Sat Mar 30 22:55:34 2002 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1740,31 +1741,6 @@ return &smc->stats; } -/*====================================================================== - - Compute the AUTODIN polynomial "CRC32" for ethernet packets. - -======================================================================*/ - -static const u_int ethernet_polynomial = 0x04c11db7U; - -static u_int ether_crc(int length, u_char *data) -{ - int crc = 0xffffffff; /* Initial value. */ - - while (--length >= 0) { - u_char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - /* The hash index is the either the upper or lower bits of the CRC, so - * we return the entire CRC. - */ - return crc; -} /*====================================================================== diff -urN linux-2.4.18/drivers/net/pcmcia/wavelan_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/wavelan_cs.c --- linux-2.4.18/drivers/net/pcmcia/wavelan_cs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/wavelan_cs.c Sat Mar 30 22:55:40 2002 @@ -22,7 +22,7 @@ #ifdef WAVELAN_ROAMING * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) * based on patch by Joe Finney from Lancaster University. -#endif :-) +#endif * * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. diff -urN linux-2.4.18/drivers/net/pcmcia/xircom_cb.c linux-2.4.19-pre5/drivers/net/pcmcia/xircom_cb.c --- linux-2.4.18/drivers/net/pcmcia/xircom_cb.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/xircom_cb.c Sat Mar 30 22:55:40 2002 @@ -1,37 +1,45 @@ /* * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards * - * This software is Copyright 2001 by the respective authors, and licensed under the GPL + * This software is (C) by the respective authors, and licensed under the GPL * License. * * Written by Arjan van de Ven for Red Hat, Inc. - * Based on work by Jeff Garzik, Doug Ledford, Donald Becker and Ion Badulescu + * Based on work by Jeff Garzik, Doug Ledford and Donald Becker * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * - * $Id: xircom_cb.c,v 1.11 2001/06/05 09:50:57 fenrus Exp $ + * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ */ #include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include +#include #include #ifdef DEBUG -#define enter() printk("Enter: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__) -#define leave() printk("Leave: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__) +#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) +#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__) #else -#define enter() do {} while (0) -#define leave() do {} while (0) +#define enter(x) do {} while (0) +#define leave(x) do {} while (0) #endif @@ -66,52 +74,27 @@ /* Offsets of the buffers within the descriptor pages, in bytes */ #define NUMDESCRIPTORS 4 -#define RXTXBUFSIZE 8192 -#define MAX_PACKETSIZE 1536 - -#define DescOwnedCard 0x80000000 -#define DescOwnedDriver 0x00000000 - -#define PromiscBit (1<<6) -#define CollisionBit (1<<8) -#define TxActiveBit (1<<13) -#define RxActiveBit (1<<1) -#define LastDescBit (1<<25) -#define LinkStatusBit (1<<27) - -#define PowerMgmtBits ( (1<<31)|(1<<30) ) - -static const unsigned int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144}; - -/* note: this struct is assumed to be packed as this is the "hardware" layout */ -struct descriptor { - u32 status; - u32 control; - u32 address1; - u32 address2; -}; +static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144}; struct xircom_private { /* Send and receive buffers, kernel-addressable and dma addressable forms */ - unsigned char *rx_buffer; - unsigned char *tx_buffer; - - struct descriptor *rx_desc; - struct descriptor *tx_desc; + unsigned int *rx_buffer; + unsigned int *tx_buffer; dma_addr_t rx_dma_handle; dma_addr_t tx_dma_handle; - struct sk_buff *tx_skb[NUMDESCRIPTORS]; + struct sk_buff *tx_skb[4]; unsigned long io_port; + int open; /* transmit_used is the rotating counter that indicates which transmit descriptor has to be used next */ - unsigned int transmit_used; + int transmit_used; /* Spinlock to serialize register operations. It must be helt while manipulating the following registers: @@ -136,16 +119,16 @@ static void xircom_up(struct xircom_private *card); static struct net_device_stats *xircom_get_stats(struct net_device *dev); -static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset); -static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset); +static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset); +static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset); static void read_mac_address(struct xircom_private *card); static void tranceiver_voodoo(struct xircom_private *card); static void initialize_card(struct xircom_private *card); -static inline void trigger_transmit(struct xircom_private *card); -static inline void trigger_receive(struct xircom_private *card); +static void trigger_transmit(struct xircom_private *card); +static void trigger_receive(struct xircom_private *card); static void setup_descriptors(struct xircom_private *card); -static inline void remove_descriptors(struct xircom_private *card); -static inline unsigned int link_status_changed(struct xircom_private *card); +static void remove_descriptors(struct xircom_private *card); +static int link_status_changed(struct xircom_private *card); static void activate_receiver(struct xircom_private *card); static void deactivate_receiver(struct xircom_private *card); static void activate_transmitter(struct xircom_private *card); @@ -154,9 +137,7 @@ static void enable_receive_interrupt(struct xircom_private *card); static void enable_link_interrupt(struct xircom_private *card); static void disable_all_interrupts(struct xircom_private *card); -static inline unsigned int link_status(struct xircom_private *card); -static int mdio_read(struct xircom_private *card, int phy_id, int location); -static void mdio_write(struct xircom_private *card, int phy_id, int location, int value); +static int link_status(struct xircom_private *card); @@ -170,7 +151,7 @@ name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, - remove: __devexit_p(xircom_remove), + remove: __devexit_p(xircom_remove), }; @@ -204,25 +185,20 @@ { struct net_device *dev = NULL; struct xircom_private *private; - u8 chip_rev; + unsigned char chip_rev; unsigned long flags; - u32 tmp32; - u16 tmp16; - int ret; - enter(); + unsigned short tmp16; + enter("xircom_probe"); /* First do the PCI initialisation */ - ret = pci_enable_device(pdev); - if (ret) - return ret; + if (pci_enable_device(pdev)) + return -ENODEV; /* disable all powermanagement */ - pci_read_config_dword(pdev, PCI_POWERMGMT,&tmp32); - tmp32 &= ~PowerMgmtBits; - pci_write_config_dword(pdev, PCI_POWERMGMT, tmp32); + pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000); - pci_set_master(pdev); + pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/ /* clear PCI status, if any */ pci_read_config_word (pdev,PCI_STATUS, &tmp16); @@ -236,39 +212,38 @@ } - dev = init_etherdev(dev, sizeof(*private)); - if (dev == NULL) { - printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); - return -ENODEV; - } - SET_MODULE_OWNER(dev); - private = dev->priv; - if (private==NULL) { - printk(KERN_ERR "xircom_probe: failed to allocate private device struct\n"); - return -ENODEV; - } - + /* + Before changing the hardware, allocate the memory. + This way, we can fail gracefully if not enough memory + is available. + */ + private = kmalloc(sizeof(*private),GFP_KERNEL); + memset(private, 0, sizeof(struct xircom_private)); + /* Allocate the send/receive buffers */ - private->rx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->rx_dma_handle); + private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); + if (private->rx_buffer == NULL) { printk(KERN_ERR "xircom_probe: no memory for rx buffer \n"); kfree(private); return -ENODEV; } - /* the descriptors are stored in the first bytes of the rx_buffer, hence the ugly cast */ - private->rx_desc = (struct descriptor *)private->rx_buffer; - - private->tx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->tx_dma_handle); + private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle); if (private->tx_buffer == NULL) { printk(KERN_ERR "xircom_probe: no memory for tx buffer \n"); kfree(private->rx_buffer); kfree(private); return -ENODEV; } - /* the descriptors are stored in the first bytes of the tx_buffer, hence the ugly cast */ - private->tx_desc = (struct descriptor *)private->tx_buffer; - - + dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); + kfree(private->rx_buffer); + kfree(private->tx_buffer); + kfree(private); + return -ENODEV; + } + SET_MODULE_OWNER(dev); printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq); private->dev = dev; @@ -288,25 +263,21 @@ dev->stop = &xircom_close; dev->get_stats = &xircom_get_stats; dev->priv = private; - pci_set_drvdata(pdev,dev); + pdev->driver_data = dev; - /* start the transmitter to get a heartbeat; don't do - that when there already is one though; Cisco's - really don't like that. */ - if (!link_status(private)) - tranceiver_voodoo(private); + /* start the transmitter to get a heartbeat */ + /* TODO: send 2 dummy packets here */ + tranceiver_voodoo(private); spin_lock_irqsave(&private->lock,flags); activate_transmitter(private); activate_receiver(private); spin_unlock_irqrestore(&private->lock,flags); - - /* TODO: send 2 dummy packets here */ trigger_receive(private); - leave(); + leave("xircom_probe"); return 0; } @@ -319,138 +290,131 @@ */ static void __devexit xircom_remove(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = pdev->driver_data; struct xircom_private *card; - enter(); - - card=dev->priv; - - if (card->rx_buffer!=NULL) - pci_free_consistent(pdev,RXTXBUFSIZE,card->rx_buffer,card->rx_dma_handle); - card->rx_buffer = NULL; - card->rx_desc = NULL; - if (card->tx_buffer!=NULL) - pci_free_consistent(pdev,RXTXBUFSIZE,card->tx_buffer,card->tx_dma_handle); - card->tx_buffer = NULL; - card->tx_desc = NULL; - + enter("xircom_remove"); + if (dev!=NULL) { + card=dev->priv; + if (card!=NULL) { + if (card->rx_buffer!=NULL) + pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); + card->rx_buffer = NULL; + if (card->tx_buffer!=NULL) + pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); + card->tx_buffer = NULL; + } + kfree(card); + } release_region(dev->base_addr, 128); unregister_netdev(dev); kfree(dev); - pci_set_drvdata(pdev,NULL); - leave(); + leave("xircom_remove"); } static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *dev = dev_instance; - struct xircom_private *card = dev->priv; - u32 status; - unsigned int xmit_free_count; - unsigned int i; - - enter(); + struct net_device *dev = (struct net_device *) dev_instance; + struct xircom_private *card = (struct xircom_private *) dev->priv; + unsigned int status; + int i; + enter("xircom_interrupt\n"); spin_lock(&card->lock); status = inl(card->io_port+CSR5); - if (status==0xffffffff) {/* card has been ejected / powered down */ - spin_unlock(&card->lock); - return; - } - /* Todo: check if there were any events at all; to speed up - returning if we're on a shared interrupt */ +#if DEBUG + print_binary(status); + printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]); + printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]); +#endif if (link_status_changed(card)) { int newlink; printk(KERN_DEBUG "xircom_cb: Link status has changed \n"); newlink = link_status(card); - if (newlink) { - printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); + printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); + if (newlink) netif_carrier_on(dev); - } else { - printk(KERN_INFO "xircom_cb: Link is absent \n"); + else netif_carrier_off(dev); - } + } - /* Clear all remaining interrupt events */ + /* Clear all remaining interrupts */ status |= 0xffffffff; /* FIXME: make this clear only the real existing bits */ outl(status,card->io_port+CSR5); - xmit_free_count = 0; for (i=0;ilock); - leave(); + leave("xircom_interrupt"); } static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xircom_private *card; unsigned long flags; - unsigned int nextdescriptor; - unsigned int desc; - enter(); + int nextdescriptor; + int desc; + enter("xircom_start_xmit"); card = (struct xircom_private*)dev->priv; - spin_lock_irqsave(&card->lock,flags); + /* First see if we can free some descriptors */ + for (desc=0;desctransmit_used +1) % (NUMDESCRIPTORS); desc = card->transmit_used; /* only send the packet if the descriptor is free */ - if (card->tx_desc[desc].status==0) { + if (card->tx_buffer[4*desc]==0) { /* Copy the packet data; zero the memory first as the card sometimes sends more than you ask it to. */ - memset(&card->tx_buffer[bufferoffsets[desc]],0,MAX_PACKETSIZE); - memcpy(&(card->tx_buffer[bufferoffsets[desc]]),skb->data,skb->len); + memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); + memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len); /* FIXME: The specification tells us that the length we send HAS to be a multiple of 4 bytes. */ - card->tx_desc[desc].control = skb->len; + card->tx_buffer[4*desc+1] = skb->len; if (desc == NUMDESCRIPTORS-1) - card->tx_desc[desc].control |= LastDescBit; /* bit 25: last descriptor of the ring */ + card->tx_buffer[4*desc+1] |= (1<<25); /* bit 25: last descriptor of the ring */ - card->tx_desc[desc].control |= 0xF0000000; + card->tx_buffer[4*desc+1] |= 0xF0000000; /* 0xF0... means want interrupts*/ card->tx_skb[desc] = skb; wmb(); /* This gives the descriptor to the card */ - card->tx_desc[desc].status = DescOwnedCard; + card->tx_buffer[4*desc] = 0x80000000; trigger_transmit(card); - if (((int)card->tx_desc[nextdescriptor].status)<0) { /* next descriptor is occupied... */ + if (((int)card->tx_buffer[nextdescriptor*4])<0) { /* next descriptor is occupied... */ netif_stop_queue(dev); } card->transmit_used = nextdescriptor; + leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); - leave(); return 0; } /* Uh oh... no free descriptor... drop the packet */ - /* This should not happen in theory...*/ netif_stop_queue(dev); spin_unlock_irqrestore(&card->lock,flags); trigger_transmit(card); - leave(); return -EIO; } @@ -462,17 +426,17 @@ { struct xircom_private *xp = (struct xircom_private *) dev->priv; int retval; - enter(); - printk(KERN_INFO "Xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); + enter("xircom_open"); + printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { - printk(KERN_ERR "xircom_cb: Unable to aquire IRQ %i, aborting.\n",dev->irq); - leave(); + leave("xircom_open - No IRQ"); return retval; } xircom_up(xp); - leave(); + xp->open = 1; + leave("xircom_open"); return 0; } @@ -481,9 +445,9 @@ struct xircom_private *card; unsigned long flags; - enter(); + enter("xircom_close"); card = dev->priv; - netif_stop_queue(dev); /* we don't want to send new packets */ + netif_stop_queue(dev); /* we don't want new packets */ spin_lock_irqsave(&card->lock,flags); @@ -498,10 +462,11 @@ spin_unlock_irqrestore(&card->lock,flags); + card->open = 0; free_irq(dev->irq,dev); - leave(); - + leave("xircom_close"); + return 0; } @@ -521,7 +486,7 @@ { unsigned int val; unsigned long flags; - enter(); + enter("initialize_card"); spin_lock_irqsave(&card->lock, flags); @@ -549,7 +514,7 @@ spin_unlock_irqrestore(&card->lock, flags); - leave(); + leave("initialize_card"); } /* @@ -558,11 +523,15 @@ claims that the act of writing is sufficient and that the value is ignored; I chose zero. */ -static inline void trigger_transmit(struct xircom_private *card) +static void trigger_transmit(struct xircom_private *card) { - enter(); - outl(0, card->io_port + CSR1); - leave(); + unsigned int val; + enter("trigger_transmit"); + + val = 0; + outl(val, card->io_port + CSR1); + + leave("trigger_transmit"); } /* @@ -572,11 +541,15 @@ claims that the act of writing is sufficient and that the value is ignored; I chose zero. */ -static inline void trigger_receive(struct xircom_private *card) +static void trigger_receive(struct xircom_private *card) { - enter(); - outl(0, card->io_port + CSR2); - leave(); + unsigned int val; + enter("trigger_receive"); + + val = 0; + outl(val, card->io_port + CSR2); + + leave("trigger_receive"); } /* @@ -586,9 +559,9 @@ static void setup_descriptors(struct xircom_private *card) { unsigned int val; - u32 address; - unsigned int i; - enter(); + unsigned int address; + int i; + enter("setup_descriptors"); if (card->rx_buffer == NULL) @@ -597,75 +570,74 @@ BUG(); /* Receive descriptors */ - memset(card->rx_desc, 0, 128); /* clear the descriptors */ + memset(card->rx_buffer, 0, 128); /* clear the descriptors */ for (i=0;i 0x80000000 */ - card->rx_desc[i].status = DescOwnedCard; + card->rx_buffer[i*4 + 0] = 0x80000000; /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ - card->rx_desc[i].control = MAX_PACKETSIZE; + card->rx_buffer[i*4 + 1] = 1536; if (i==NUMDESCRIPTORS-1) - card->rx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */ + card->rx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */ /* Rx Descr2: address of the buffer we store the buffer at the 2nd half of the page */ - address = card->rx_dma_handle; - - card->rx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]); + address = (unsigned long) card->rx_dma_handle; + card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); /* Rx Desc3: address of 2nd buffer -> 0 */ - card->rx_desc[i].address2 = 0; + card->rx_buffer[i*4 + 3] = 0; } wmb(); /* Write the receive descriptor ring address to the card */ - address = card->rx_dma_handle; + address = (unsigned long) card->rx_dma_handle; val = cpu_to_le32(address); outl(val, card->io_port + CSR3); /* Receive descr list address */ /* transmit descriptors */ - memset(card->tx_desc, 0, 128); /* clear the descriptors */ + memset(card->tx_buffer, 0, 128); /* clear the descriptors */ for (i=0;i 0x00000000 */ - card->tx_desc[i].status = DescOwnedDriver; + card->tx_buffer[i*4 + 0] = 0x00000000; /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ - card->tx_desc[i].control = MAX_PACKETSIZE; + card->tx_buffer[i*4 + 1] = 1536; if (i==NUMDESCRIPTORS-1) - card->tx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */ + card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */ /* Tx Descr2: address of the buffer we store the buffer at the 2nd half of the page */ - address = card->tx_dma_handle; - card->tx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]); + address = (unsigned long) card->tx_dma_handle; + card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); /* Tx Desc3: address of 2nd buffer -> 0 */ - card->tx_desc[i].address2 = 0; + card->tx_buffer[i*4 + 3] = 0; } wmb(); /* wite the transmit descriptor ring to the card */ - address = card->tx_dma_handle; + address = (unsigned long) card->tx_dma_handle; val =cpu_to_le32(address); outl(val, card->io_port + CSR4); /* xmit descr list address */ - leave(); + leave("setup_descriptors"); } /* remove_descriptors informs the card the descriptors are no longer valid by setting the address in the card to 0x00. */ -static inline void remove_descriptors(struct xircom_private *card) +static void remove_descriptors(struct xircom_private *card) { unsigned int val; - enter(); + enter("remove_descriptors"); val = 0; outl(val, card->io_port + CSR3); /* Receive descriptor address */ outl(val, card->io_port + CSR4); /* Send descriptor address */ - leave(); + leave("remove_descriptors"); } /* @@ -674,24 +646,24 @@ This function also clears the status-bit. */ -static inline unsigned int link_status_changed(struct xircom_private *card) +static int link_status_changed(struct xircom_private *card) { unsigned int val; - enter(); + enter("link_status_changed"); val = inl(card->io_port + CSR5); /* Status register */ - if ((val & LinkStatusBit) == 0) { /* no change */ - leave(); + if ((val & (1 << 27)) == 0) { /* no change */ + leave("link_status_changed - nochange"); return 0; } /* clear the event by writing a 1 to the bit in the status register. */ - val = LinkStatusBit; + val = (1 << 27); outl(val, card->io_port + CSR5); - leave(); + leave("link_status_changed - changed"); return 1; } @@ -700,19 +672,19 @@ transmit_active returns 1 if the transmitter on the card is in a non-stopped state. */ -static inline int transmit_active(struct xircom_private *card) +static int transmit_active(struct xircom_private *card) { unsigned int val; - enter(); + enter("transmit_active"); val = inl(card->io_port + CSR5); /* Status register */ if ((val & (7 << 20)) == 0) { /* transmitter disabled */ - leave(); + leave("transmit_active - inactive"); return 0; } - leave(); + leave("transmit_active - active"); return 1; } @@ -720,20 +692,20 @@ receive_active returns 1 if the receiver on the card is in a non-stopped state. */ -static inline unsigned int receive_active(struct xircom_private *card) +static int receive_active(struct xircom_private *card) { unsigned int val; - enter(); + enter("receive_active"); val = inl(card->io_port + CSR5); /* Status register */ if ((val & (7 << 17)) == 0) { /* receiver disabled */ - leave(); + leave("receive_active - inactive"); return 0; } - leave(); + leave("receive_active - active"); return 1; } @@ -751,18 +723,18 @@ { unsigned int val; int counter; - enter(); + enter("activate_receiver"); val = inl(card->io_port + CSR6); /* Operation mode */ - /* If the "active" bit (1) is set and the receiver is already + /* If the "active" bit is set and the receiver is already active, no need to do the expensive thing */ - if ((val& RxActiveBit) && (receive_active(card))) + if ((val&2) && (receive_active(card))) return; - val = val & ~RxActiveBit; /* disable the receiver */ + val = val & ~2; /* disable the receiver */ outl(val, card->io_port + CSR6); counter = 10; @@ -778,7 +750,7 @@ /* enable the receiver */ val = inl(card->io_port + CSR6); /* Operation mode */ - val = val | RxActiveBit; /* enable the receiver */ + val = val | 2; /* enable the receiver */ outl(val, card->io_port + CSR6); /* now wait for the card to activate again */ @@ -793,7 +765,7 @@ printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n"); } - leave(); + leave("activate_receiver"); } /* @@ -807,10 +779,10 @@ { unsigned int val; int counter; - enter(); + enter("deactivate_receiver"); val = inl(card->io_port + CSR6); /* Operation mode */ - val = val & ~RxActiveBit; /* disable the receiver */ + val = val & ~2; /* disable the receiver */ outl(val, card->io_port + CSR6); counter = 10; @@ -825,7 +797,7 @@ } - leave(); + leave("deactivate_receiver"); } @@ -843,17 +815,17 @@ { unsigned int val; int counter; - enter(); + enter("activate_transmitter"); val = inl(card->io_port + CSR6); /* Operation mode */ - /* If the "active" bit (13) is set and the receiver is already + /* If the "active" bit is set and the receiver is already active, no need to do the expensive thing */ - if ((val & TxActiveBit) && (transmit_active(card))) + if ((val&(1<<13)) && (transmit_active(card))) return; - val = val & ~TxActiveBit; /* disable the transmitter */ + val = val & ~(1 << 13); /* disable the transmitter */ outl(val, card->io_port + CSR6); counter = 10; @@ -869,7 +841,7 @@ /* enable the transmitter */ val = inl(card->io_port + CSR6); /* Operation mode */ - val = val | TxActiveBit; /* enable the transmitter */ + val = val | (1 << 13); /* enable the transmitter */ outl(val, card->io_port + CSR6); /* now wait for the card to activate again */ @@ -884,7 +856,7 @@ printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n"); } - leave(); + leave("activate_transmitter"); } /* @@ -898,10 +870,10 @@ { unsigned int val; int counter; - enter(); + enter("deactivate_transmitter"); val = inl(card->io_port + CSR6); /* Operation mode */ - val = val & ~TxActiveBit; /* disable the transmitter */ + val = val & ~2; /* disable the transmitter */ outl(val, card->io_port + CSR6); counter = 20; @@ -916,7 +888,7 @@ } - leave(); + leave("deactivate_transmitter"); } @@ -928,13 +900,13 @@ static void enable_transmit_interrupt(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_transmit_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= 1; /* enable the transmit interrupt */ outl(val, card->io_port + CSR7); - leave(); + leave("enable_transmit_interrupt"); } @@ -946,13 +918,13 @@ static void enable_receive_interrupt(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_receive_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 6); /* enable the receive interrupt */ outl(val, card->io_port + CSR7); - leave(); + leave("enable_receive_interrupt"); } /* @@ -963,13 +935,13 @@ static void enable_link_interrupt(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ - val = val | LinkStatusBit; /* enable the link status chage interrupt */ + val = val | (1 << 27); /* enable the link status chage interrupt */ outl(val, card->io_port + CSR7); - leave(); + leave("enable_link_interrupt"); } @@ -982,12 +954,12 @@ static void disable_all_interrupts(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_all_interrupts"); val = 0; /* disable all interrupts */ outl(val, card->io_port + CSR7); - leave(); + leave("disable_all_interrupts"); } /* @@ -998,7 +970,7 @@ static void enable_common_interrupts(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= (1<<16); /* Normal Interrupt Summary */ @@ -1011,7 +983,7 @@ val |= (1<<1); /* Transmit Process Stopped */ outl(val, card->io_port + CSR7); - leave(); + leave("enable_link_interrupt"); } /* @@ -1019,32 +991,31 @@ must be called with the lock held and interrupts disabled. */ -static inline void enable_promisc(struct xircom_private *card) +static int enable_promisc(struct xircom_private *card) { unsigned int val; - enter(); + enter("enable_promisc"); val = inl(card->io_port + CSR6); - val = val | PromiscBit; /* Bit 6 */ + val = val | (1 << 6); outl(val, card->io_port + CSR6); - printk(KERN_INFO "xircom_cb: enabling promiscuous mode \n"); - leave(); + leave("enable_promisc"); + return 1; } /* -link_status() checks the the links status and will return 0 for no link, -10 for 10mbit link and 100 for.. guess what. +link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what. Must be called in locked state with interrupts disabled */ -static inline unsigned int link_status(struct xircom_private *card) +static int link_status(struct xircom_private *card) { unsigned int val; - enter(); + enter("link_status"); val = inb(card->io_port + CSR12); @@ -1055,59 +1026,12 @@ /* If we get here -> no link at all */ - leave(); + leave("link_status"); return 0; } -/* - -set_half_duplex() sets the card to half duplex mode. In order to do this, -set_half_duplex() has to deactivate the transmitter and receiver first. It -will re-enable the transmitter and receiver if those were active from the -beginning. - -Update: the above is not enough. It doesn't touch the MII, in fact it ensures -the main chipset and the MII are never in sync if a full-duplex connection -is negotiated. The proper fix is to tell the MII to force a half-duplex -connection. -Ion - -Must be called in locked state -*/ -static void set_half_duplex(struct xircom_private *card) -{ - unsigned int val; - int rx,tx,tmp; - enter(); - - rx=receive_active(card); - tx=transmit_active(card); - - deactivate_transmitter(card); - deactivate_receiver(card); - - val = inb(card->io_port + CSR6); - val &= ~(1<<9); - outb(val,card->io_port + CSR6); - - /* tell the MII not to advertise 10/100FDX */ - tmp = mdio_read(card, 0, 4); - printk("xircom_cb: capabilities changed from %#x to %#x\n", - tmp, tmp & ~0x140); - tmp &= ~0x140; - mdio_write(card, 0, 4, tmp); - /* restart autonegotiation */ - tmp = mdio_read(card, 0, 0); - mdio_write(card, 0, 0, tmp | 0x1200); - - if (rx) - activate_receiver(card); - if (tx) - activate_transmitter(card); - - leave(); -} /* @@ -1121,7 +1045,7 @@ unsigned long flags; int i; - enter(); + enter("read_mac_address"); spin_lock_irqsave(&card->lock, flags); @@ -1154,92 +1078,7 @@ printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]); printk("\n"); #endif - leave(); -} - - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - -static int mdio_read(struct xircom_private *card, int phy_id, int location) -{ - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - long mdio_addr = card->io_port + CSR9; - - /* Establish sync by sending at least 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct xircom_private *card, int phy_id, int location, int value) -{ - int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - long mdio_addr = card->io_port + CSR9; - - /* Establish sync by sending 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } + leave("read_mac_address"); } @@ -1251,14 +1090,11 @@ static void tranceiver_voodoo(struct xircom_private *card) { unsigned long flags; - u32 tmp32; - enter(); + enter("tranceiver_voodoo"); /* disable all powermanagement */ - pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32); - tmp32 &= ~PowerMgmtBits; - pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32); + pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); setup_descriptors(card); @@ -1274,7 +1110,7 @@ spin_unlock_irqrestore(&card->lock, flags); netif_start_queue(card->dev); - leave(); + leave("tranceiver_voodoo"); } @@ -1282,14 +1118,11 @@ { unsigned long flags; int i; - u32 tmp32; - enter(); + enter("xircom_up"); /* disable all powermanagement */ - pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32); - tmp32 &= ~PowerMgmtBits; - pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32); + pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); setup_descriptors(card); @@ -1304,23 +1137,23 @@ /* The card can have received packets already, read them away now */ for (i=0;idev,card,i,bufferoffsets[i]); + investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]); - set_half_duplex(card); spin_unlock_irqrestore(&card->lock, flags); trigger_receive(card); trigger_transmit(card); netif_start_queue(card->dev); - leave(); + leave("xircom_up"); } -static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset) +/* Bufferoffset is in BYTES */ +static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset) { int status; - enter(); - status = card->rx_desc[descnr].status; + enter("investigate_read_descriptor"); + status = card->rx_buffer[4*descnr]; if ((status > 0)) { /* packet received */ @@ -1341,7 +1174,7 @@ } skb->dev = dev; skb_reserve(skb, 2); - eth_copy_and_sum(skb, &card->rx_buffer[bufferoffset], pkt_len, 0); + eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1351,48 +1184,46 @@ out: /* give the buffer back to the card */ - card->rx_desc[descnr].status = DescOwnedCard; + card->rx_buffer[4*descnr] = 0x80000000; trigger_receive(card); } - leave(); + leave("investigate_read_descriptor"); } -/* Returns 1 if the descriptor is free or became free */ -static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset) +/* Bufferoffset is in BYTES */ +static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset) { - int status,retval = 0; - enter(); - - status = card->tx_desc[descnr].status; + int status; + + enter("investigate_write_descriptor"); - if (status == DescOwnedDriver) - return 1; + status = card->tx_buffer[4*descnr]; #if 0 if (status & 0x8000) { /* Major error */ printk(KERN_ERR "Major transmit error status %x \n", status); - card->tx_desc[descnr].status = 0; + card->tx_buffer[4*descnr] = 0; netif_wake_queue (dev); } #endif if (status > 0) { /* bit 31 is 0 when done */ - card->stats.tx_packets++; if (card->tx_skb[descnr]!=NULL) { card->stats.tx_bytes += card->tx_skb[descnr]->len; dev_kfree_skb_irq(card->tx_skb[descnr]); } card->tx_skb[descnr] = NULL; /* Bit 8 in the status field is 1 if there was a collision */ - if (status & CollisionBit) + if (status&(1<<8)) card->stats.collisions++; - card->tx_desc[descnr].status = DescOwnedDriver; /* descriptor is free again */ - retval = 1; + card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ + netif_wake_queue (dev); + card->stats.tx_packets++; } - leave(); - return retval; + leave("investigate_write_descriptor"); + } @@ -1409,3 +1240,4 @@ module_init(xircom_init) module_exit(xircom_exit) + diff -urN linux-2.4.18/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.4.19-pre5/drivers/net/pcmcia/xircom_tulip_cb.c --- linux-2.4.18/drivers/net/pcmcia/xircom_tulip_cb.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/pcmcia/xircom_tulip_cb.c Sat Mar 30 22:55:34 2002 @@ -101,6 +101,7 @@ #include #include #include +#include #include #include /* Processor type for cache alignment. */ @@ -1517,43 +1518,6 @@ return -EOPNOTSUPP; } - - -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline u32 ether_crc_le(int length, unsigned char *data) -{ - u32 crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - /* Set or clear the multicast filter for this adaptor. Note that we only use exclusion around actually queueing the diff -urN linux-2.4.18/drivers/net/pcnet32.c linux-2.4.19-pre5/drivers/net/pcnet32.c --- linux-2.4.18/drivers/net/pcnet32.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/pcnet32.c Sat Mar 30 22:55:40 2002 @@ -22,8 +22,9 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.25kf" -#define DRV_RELDATE "17.11.2001" +#define DRV_VERSION "1.27a" +#define DRV_RELDATE "10.02.2002" +#define PFX DRV_NAME ": " static const char *version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; @@ -43,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -53,8 +55,6 @@ #include #include -static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0}; - /* * PCI device identifiers for "new style" Linux PCI Device Drivers */ @@ -64,13 +64,26 @@ { 0, } }; +MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); + +int cards_found __initdata; + +/* + * VLB I/O addresses + */ +static unsigned int pcnet32_portlist[] __initdata = + { 0x300, 0x320, 0x340, 0x360, 0 }; + + + static int pcnet32_debug = 1; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ +static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; -static const int max_interrupt_work = 80; -static const int rx_copybreak = 200; +static int max_interrupt_work = 80; +static int rx_copybreak = 200; #define PCNET32_PORT_AUI 0x00 #define PCNET32_PORT_10BT 0x01 @@ -93,21 +106,21 @@ PCNET32_PORT_AUI, /* 1 BNC/AUI */ PCNET32_PORT_AUI, /* 2 AUI/BNC */ PCNET32_PORT_ASEL, /* 3 not supported */ - PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ + PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ PCNET32_PORT_ASEL, /* 5 not supported */ PCNET32_PORT_ASEL, /* 6 not supported */ PCNET32_PORT_ASEL, /* 7 not supported */ PCNET32_PORT_ASEL, /* 8 not supported */ PCNET32_PORT_MII, /* 9 MII 10baseT */ - PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ + PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ PCNET32_PORT_MII, /* 11 MII (autosel) */ PCNET32_PORT_10BT, /* 12 10BaseT */ - PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ + PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */ PCNET32_PORT_ASEL /* 15 not supported */ }; -#define MAX_UNITS 8 +#define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; @@ -186,7 +199,19 @@ * v1.25kf Added No Interrupt on successful Tx for some Tx's * v1.26 Converted to pci_alloc_consistent, Jamey Hicks / George France * - * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker + * - Fixed a few bugs, related to running the controller in 32bit mode. + * 23 Oct, 2000. Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker + * v1.27 improved CSR/PROM address detection, lots of cleanups, + * new pcnet32vlb module option, HP-PARISC support, + * added module parameter descriptions, + * initial ethtool support - Helge Deller + * v1.27a Sun Feb 10 2002 Go Taniguchi + * use alloc_etherdev and register_netdev + * fix pci probe not increment cards_found + * FD auto negotiate error workaround for xSeries250 + * clean up and using new mii module */ @@ -200,13 +225,13 @@ #define PCNET32_LOG_RX_BUFFERS 5 #endif -#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) - -#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) +#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) +#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) + +#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) #define PKT_BUF_SZ 1544 @@ -221,9 +246,7 @@ #define PCNET32_DWIO_RESET 0x18 #define PCNET32_DWIO_BDP 0x1C -#define PCNET32_TOTAL_SIZE 0x20 - -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ +#define PCNET32_TOTAL_SIZE 0x20 /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { @@ -271,37 +294,36 @@ */ struct pcnet32_private { /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; - struct pcnet32_init_block init_block; - dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by pci_alloc_consistent */ - struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ - const char *name; + struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; + struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet32_init_block init_block; + dma_addr_t dma_addr; /* DMA address of beginning of this object, + returned by pci_alloc_consistent */ + struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ + const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t tx_dma_addr[TX_RING_SIZE]; - dma_addr_t rx_dma_addr[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + dma_addr_t tx_dma_addr[TX_RING_SIZE]; + dma_addr_t rx_dma_addr[RX_RING_SIZE]; struct pcnet32_access a; - spinlock_t lock; /* Guard 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. */ + spinlock_t lock; /* Guard 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. */ struct net_device_stats stats; - char tx_full; - int options; - int shared_irq:1, /* shared irq possible */ - ltint:1, -#ifdef DO_DXSUFLO - dxsuflo:1, /* disable transmit stop on uflo */ -#endif - mii:1; /* mii port available */ - struct net_device *next; + char tx_full; + int options; + int shared_irq:1, /* shared irq possible */ + ltint:1, /* enable TxDone-intr inhibitor */ + dxsuflo:1, /* disable transmit stop on uflo */ + mii:1; /* mii port available */ + struct net_device *next; struct mii_if_info mii_if; }; -static int pcnet32_probe_vlbus(int cards_found); +static void pcnet32_probe_vlbus(void); static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); -static int pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *); +static int pcnet32_probe1(unsigned long, unsigned int, int, struct pci_dev *); 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 *); @@ -320,15 +342,6 @@ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pcnet32_pci_id_info { - const char *name; - u16 vendor_id, device_id, svid, sdid, flags; - int io_size; - int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *); -}; - - -MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); static u16 pcnet32_wio_read_csr (unsigned long addr, int index) { @@ -376,13 +389,13 @@ } static struct pcnet32_access pcnet32_wio = { - pcnet32_wio_read_csr, - pcnet32_wio_write_csr, - pcnet32_wio_read_bcr, - pcnet32_wio_write_bcr, - pcnet32_wio_read_rap, - pcnet32_wio_write_rap, - pcnet32_wio_reset + read_csr: pcnet32_wio_read_csr, + write_csr: pcnet32_wio_write_csr, + read_bcr: pcnet32_wio_read_bcr, + write_bcr: pcnet32_wio_write_bcr, + read_rap: pcnet32_wio_read_rap, + write_rap: pcnet32_wio_write_rap, + reset: pcnet32_wio_reset }; static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) @@ -431,82 +444,61 @@ } static struct pcnet32_access pcnet32_dwio = { - pcnet32_dwio_read_csr, - pcnet32_dwio_write_csr, - pcnet32_dwio_read_bcr, - pcnet32_dwio_write_bcr, - pcnet32_dwio_read_rap, - pcnet32_dwio_write_rap, - pcnet32_dwio_reset - + read_csr: pcnet32_dwio_read_csr, + write_csr: pcnet32_dwio_write_csr, + read_bcr: pcnet32_dwio_read_bcr, + write_bcr: pcnet32_dwio_write_bcr, + read_rap: pcnet32_dwio_read_rap, + write_rap: pcnet32_dwio_write_rap, + reset: pcnet32_dwio_reset }; - -/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/ -static int __init pcnet32_probe_vlbus(int cards_found) + +/* only probes for non-PCI devices, the rest are handled by + * pci_register_driver via pcnet32_probe_pci */ + +static void __devinit +pcnet32_probe_vlbus(void) { - unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0; - unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0; - int *port; - - printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found); -#ifndef __powerpc__ - if (ioaddr > 0x1ff) { - if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) - return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL); - else - return -ENODEV; - } else -#endif - if (ioaddr != 0) - return -ENXIO; + unsigned int *port, ioaddr; - /* now look for PCnet32 VLB cards */ - for (port = pcnet32_portlist; *port; port++) { - unsigned long ioaddr = *port; - - if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) { + /* search for PCnet32 VLB cards at known addresses */ + for (port = pcnet32_portlist; (ioaddr = *port); port++) { + if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) { /* check if there is really a pcnet chip on that ioaddr */ - if ((inb(ioaddr + 14) == 0x57) && - (inb(ioaddr + 15) == 0x57) && - (pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0)) - cards_found++; + if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) + pcnet32_probe1(ioaddr, 0, 0, NULL); } } - return cards_found ? 0: -ENODEV; } - static int __devinit pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int card_idx; - long ioaddr; - int err = 0; - - printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device); + unsigned long ioaddr; + int err; - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); + err = pci_enable_device(pdev); + if (err < 0) { + printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err); return err; } pci_set_master(pdev); ioaddr = pci_resource_start (pdev, 0); - printk(KERN_INFO " ioaddr=%#08lx resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0)); if (!ioaddr) { - printk (KERN_ERR "no PCI IO resources, aborting\n"); + printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n"); return -ENODEV; } - + if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { - printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n"); + printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); return -ENODEV; } - return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev); + return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev); } @@ -515,41 +507,44 @@ * pdev will be NULL when called from pcnet32_probe_vlbus. */ static int __devinit -pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev) +pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, + struct pci_dev *pdev) { struct pcnet32_private *lp; struct resource *res; dma_addr_t lp_dma_addr; - int i,media,fdx = 0, mii = 0, fset = 0; -#ifdef DO_DXSUFLO - int dxsuflo = 0; -#endif - int ltint = 0; + int i, media; + int fdx, mii, fset, dxsuflo, ltint; int chip_version; char *chipname; struct net_device *dev; struct pcnet32_access *a = NULL; + u8 promaddr[6]; /* reset the chip */ - pcnet32_dwio_reset(ioaddr); pcnet32_wio_reset(ioaddr); /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ - if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { + if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) { a = &pcnet32_wio; } else { - if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + pcnet32_dwio_reset(ioaddr); + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; } else return -ENODEV; } - chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16); + chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); if (pcnet32_debug > 2) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) return -ENODEV; + + /* initialize variables */ + fdx = mii = fset = dxsuflo = ltint = 0; chip_version = (chip_version >> 12) & 0xffff; + switch (chip_version) { case 0x2420: chipname = "PCnet/PCI 79C970"; /* PCI */ @@ -588,23 +583,24 @@ * mode by which the card should operate */ /* switch to home wiring mode */ - media = a->read_bcr (ioaddr, 49); + media = a->read_bcr(ioaddr, 49); #if 0 if (pcnet32_debug > 2) - printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n", media); + printk(KERN_DEBUG PFX "media value %#x.\n", media); media &= ~3; media |= 1; #endif if (pcnet32_debug > 2) - printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n", media); - a->write_bcr (ioaddr, 49, media); + printk(KERN_DEBUG PFX "media reset to %#x.\n", media); + a->write_bcr(ioaddr, 49, media); break; case 0x2627: chipname = "PCnet/FAST III 79C975"; /* PCI */ fdx = 1; mii = 1; break; default: - printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); + printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", + chip_version); return -ENODEV; } @@ -619,17 +615,15 @@ { a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); -#ifdef DO_DXSUFLO dxsuflo = 1; -#endif ltint = 1; } - dev = init_etherdev(NULL, 0); - if(dev==NULL) + dev = alloc_etherdev(0); + if(!dev) return -ENOMEM; - printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); + printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); /* In most chips, after a chip reset, the ethernet address is read from the * station address PROM at the base address and programmed into the @@ -645,31 +639,28 @@ dev->dev_addr[2*i] = val & 0x0ff; dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; } - { - u8 promaddr[6]; - for (i = 0; i < 6; i++) { - promaddr[i] = inb(ioaddr + i); - } - if( memcmp( promaddr, dev->dev_addr, 6) ) - { - printk(" warning PROM address does not match CSR address\n"); -#if defined(__i386__) - printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name); - memcpy(dev->dev_addr, promaddr, 6); -#elif defined(__powerpc__) - if (!is_valid_ether_addr(dev->dev_addr) - && is_valid_ether_addr(promaddr)) { - printk("\n" KERN_WARNING "%s: using PROM address:", - dev->name); - memcpy(dev->dev_addr, promaddr, 6); - } + + /* read PROM address and compare with CSR address */ + for (i = 0; i < 6; i++) + promaddr[i] = inb(ioaddr + i); + + if( memcmp( promaddr, dev->dev_addr, 6) + || !is_valid_ether_addr(dev->dev_addr) ) { +#ifndef __powerpc__ + if( is_valid_ether_addr(promaddr) ){ +#else + if( !is_valid_ether_addr(dev->dev_addr) + && is_valid_ether_addr(promaddr)) { #endif - } + printk(" warning: CSR address invalid,\n"); + printk(KERN_INFO " using instead PROM address of"); + memcpy(dev->dev_addr, promaddr, 6); + } } + /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ if( !is_valid_ether_addr(dev->dev_addr) ) - for (i = 0; i < 6; i++) - dev->dev_addr[i]=0; + memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] ); @@ -699,7 +690,7 @@ dev->base_addr = ioaddr; res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); - if (res == NULL) + if (!res) return -EBUSY; /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ @@ -711,7 +702,6 @@ memset(lp, 0, sizeof(*lp)); lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; - printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr); spin_lock_init(&lp->lock); @@ -719,24 +709,23 @@ lp->name = chipname; lp->shared_irq = shared; lp->mii_if.full_duplex = fdx; -#ifdef DO_DXSUFLO lp->dxsuflo = dxsuflo; -#endif lp->ltint = ltint; lp->mii = mii; - if (options[card_idx] > sizeof (options_mapping)) + if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else - lp->options = options_mapping[options[card_idx]]; + lp->options = options_mapping[options[cards_found]]; lp->mii_if.dev = dev; lp->mii_if.mdio_read = mdio_read; lp->mii_if.mdio_write = mdio_write; - if (fdx && !(lp->options & PCNET32_PORT_ASEL) && full_duplex[card_idx]) + if (fdx && !(lp->options & PCNET32_PORT_ASEL) && + ((cards_found>=MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; - if (a == NULL) { - printk(KERN_ERR "pcnet32: No access methods\n"); + if (!a) { + printk(KERN_ERR PFX "No access methods\n"); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); release_resource(res); return -ENODEV; @@ -791,8 +780,6 @@ } } - if (pcnet32_debug > 0) - printk(KERN_INFO "%s", version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -802,17 +789,19 @@ dev->set_multicast_list = &pcnet32_set_multicast_list; dev->do_ioctl = &pcnet32_ioctl; dev->tx_timeout = pcnet32_tx_timeout; - dev->watchdog_timeo = (HZ >> 1); + dev->watchdog_timeo = (5*HZ); lp->next = pcnet32_dev; pcnet32_dev = dev; /* Fill in the generic fields of the device structure. */ - ether_setup(dev); + register_netdev(dev); + printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); + cards_found++; return 0; } - + static int pcnet32_open(struct net_device *dev) { @@ -857,6 +846,9 @@ val |= 1; if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI)) val |= 2; + } else if (lp->options & PCNET32_PORT_ASEL) { + /* workaround for xSeries250 */ + val |= 3; } lp->a.write_bcr (ioaddr, 9, val); } @@ -889,6 +881,7 @@ lp->a.write_csr (ioaddr, 3, val); } #endif + if (lp->ltint) { /* Enable TxDone-intr inhibitor */ val = lp->a.read_csr (ioaddr, 5); val |= (1<<14); @@ -923,7 +916,7 @@ if (pcnet32_debug > 2) printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)), - lp->a.read_csr (ioaddr, 0)); + lp->a.read_csr(ioaddr, 0)); MOD_INC_USE_COUNT; @@ -953,7 +946,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { if (lp->tx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - dev_kfree_skb(lp->tx_skbuff[i]); + dev_kfree_skb_any(lp->tx_skbuff[i]); lp->tx_skbuff[i] = NULL; lp->tx_dma_addr[i] = 0; } @@ -1029,11 +1022,12 @@ pcnet32_tx_timeout (struct net_device *dev) { struct pcnet32_private *lp = dev->priv; - unsigned int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr, flags; + spin_lock_irqsave(&lp->lock, flags); /* Transmitter timeout, serious problems. */ printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); + dev->name, lp->a.read_csr(ioaddr, 0)); lp->a.write_csr (ioaddr, 0, 0x0004); lp->stats.tx_errors++; if (pcnet32_debug > 2) { @@ -1055,6 +1049,8 @@ dev->trans_start = jiffies; netif_start_queue(dev); + + spin_unlock_irqrestore(&lp->lock, flags); } @@ -1062,14 +1058,14 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcnet32_private *lp = dev->priv; - unsigned int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; u16 status; int entry; unsigned long flags; if (pcnet32_debug > 3) { printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); + dev->name, lp->a.read_csr(ioaddr, 0)); } spin_lock_irqsave(&lp->lock, flags); @@ -1136,8 +1132,9 @@ int boguscnt = max_interrupt_work; int must_restart; - if (dev == NULL) { - printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq); + if (!dev) { + printk (KERN_DEBUG "%s(): irq %d for unknown device\n", + __FUNCTION__, irq); return; } @@ -1208,7 +1205,8 @@ /* We must free the original skb */ if (lp->tx_skbuff[entry]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); + pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], + lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; lp->tx_dma_addr[entry] = 0; @@ -1216,13 +1214,12 @@ dirty_tx++; } -#ifndef final_version if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dirty_tx, lp->cur_tx, lp->tx_full); + printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; } -#endif + if (lp->tx_full && netif_queue_stopped(dev) && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { @@ -1263,7 +1260,7 @@ /* Clear any other interrupt, and set interrupt enable. */ lp->a.write_csr (ioaddr, 0, 0x7940); - lp->a.write_rap(ioaddr,rap); + lp->a.write_rap (ioaddr,rap); if (pcnet32_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n", @@ -1313,10 +1310,13 @@ if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { skb_reserve (newskb, 2); skb = lp->rx_skbuff[entry]; + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], skb->len, PCI_DMA_FROMDEVICE); skb_put (skb, pkt_len); lp->rx_skbuff[entry] = newskb; newskb->dev = dev; - lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE); + lp->rx_dma_addr[entry] = + pci_map_single(lp->pci_dev, newskb->tail, + newskb->len, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; } else @@ -1350,6 +1350,7 @@ lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; } } @@ -1441,18 +1442,18 @@ volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; char *addrs; - int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 crc; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI){ - ib->filter [0] = 0xffffffff; - ib->filter [1] = 0xffffffff; + ib->filter[0] = 0xffffffff; + ib->filter[1] = 0xffffffff; return; } /* clear the multicast filter */ - ib->filter [0] = 0; - ib->filter [1] = 0; + ib->filter[0] = 0; + ib->filter[1] = 0; /* Add addresses */ for (i = 0; i < dev->mc_count; i++){ @@ -1463,19 +1464,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) { - crc = crc ^ poly; - } - } - + crc = ether_crc_le(6, addrs); crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); } @@ -1488,9 +1477,10 @@ */ static void pcnet32_set_multicast_list(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr, flags; struct pcnet32_private *lp = dev->priv; + spin_lock_irqsave(&lp->lock, flags); if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); @@ -1503,6 +1493,7 @@ lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ pcnet32_restart(dev, 0x0042); /* Resume normal operation */ + spin_unlock_irqrestore(&lp->lock, flags); } static int mdio_read(struct net_device *dev, int phy_id, int reg_num) @@ -1641,17 +1632,14 @@ if (lp->mii) { switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = (phyaddr >> 5) & 0x1f; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); data->val_out = lp->a.read_bcr (ioaddr, 34); lp->a.write_bcr (ioaddr, 33, phyaddr); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); @@ -1664,20 +1652,28 @@ } return -EOPNOTSUPP; } - + static struct pci_driver pcnet32_driver = { - name: DRV_NAME, - probe: pcnet32_probe_pci, - remove: NULL, - id_table: pcnet32_pci_tbl, + name: DRV_NAME, + probe: pcnet32_probe_pci, + id_table: pcnet32_pci_tbl, }; MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)"); MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); MODULE_PARM(tx_start_pt, "i"); +MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); +MODULE_PARM(pcnet32vlb, "i"); +MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)"); + MODULE_AUTHOR("Thomas Bogendoerfer"); MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards"); MODULE_LICENSE("GPL"); @@ -1688,36 +1684,25 @@ static int __init pcnet32_init_module(void) { - int cards_found = 0; - int err; + printk(KERN_INFO "%s", version); if (debug > 0) pcnet32_debug = debug; + if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) tx_start = tx_start_pt; - - pcnet32_dev = NULL; + /* find the PCI devices */ -#define USE_PCI_REGISTER_DRIVER -#ifdef USE_PCI_REGISTER_DRIVER - if ((err = pci_module_init(&pcnet32_driver)) < 0 ) - return err; -#else - { - struct pci_device_id *devid = pcnet32_pci_tbl; - for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) { - struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL); - if (pdev != NULL) { - if (pcnet32_probe_pci(pdev, devid) >= 0) { - cards_found++; - } - } - } - } -#endif - return 0; - /* find any remaining VLbus devices */ - return pcnet32_probe_vlbus(cards_found); + pci_module_init(&pcnet32_driver); + + /* should we find any remaining VLbus devices ? */ + if (pcnet32vlb) + pcnet32_probe_vlbus(); + + if (cards_found) + printk(KERN_INFO PFX "%d cards_found.\n", cards_found); + + return cards_found ? 0 : -ENODEV; } static void __exit pcnet32_cleanup_module(void) @@ -1726,13 +1711,13 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (pcnet32_dev) { - struct pcnet32_private *lp = pcnet32_dev->priv; + struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - if (lp->pci_dev != NULL) + if (lp->pci_dev) pci_unregister_driver(&pcnet32_driver); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); kfree(pcnet32_dev); pcnet32_dev = next_dev; } diff -urN linux-2.4.18/drivers/net/ppp_async.c linux-2.4.19-pre5/drivers/net/ppp_async.c --- linux-2.4.18/drivers/net/ppp_async.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ppp_async.c Sat Mar 30 22:55:34 2002 @@ -17,7 +17,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000227== + * ==FILEVERSION 20020125== */ #include @@ -33,7 +33,7 @@ #include #include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" #define OBUFSIZE 256 @@ -62,6 +62,8 @@ struct sk_buff *rpkt; int lcp_fcs; + atomic_t refcnt; + struct semaphore dead_sem; struct ppp_channel chan; /* interface to generic ppp layer */ unsigned char obuf[OBUFSIZE]; }; @@ -108,6 +110,35 @@ */ /* + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_asynctty_receive while another + * calls ppp_asynctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_asynctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + */ +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct asyncppp *ap_get(struct tty_struct *tty) +{ + struct asyncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void ap_put(struct asyncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + up(&ap->dead_sem); +} + +/* * Called when a tty is put into PPP line discipline. */ static int @@ -135,6 +166,9 @@ ap->olim = ap->obuf; ap->lcp_fcs = -1; + atomic_set(&ap->refcnt, 1); + init_MUTEX_LOCKED(&ap->dead_sem); + ap->chan.private = ap; ap->chan.ops = &async_ops; ap->chan.mtu = PPP_MRU; @@ -155,19 +189,34 @@ /* * Called when the tty is put into another line discipline - * or it hangs up. - * We assume that while we are in this routine, the tty layer - * won't call any of the other line discipline entries for the - * same tty. + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_asynctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the asyncppp struct. This routine must be called from + * process context, not interrupt or softirq context. */ static void ppp_asynctty_close(struct tty_struct *tty) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap; + write_lock(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = 0; + write_unlock(&disc_data_lock); if (ap == 0) return; - tty->disc_data = 0; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_async_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + down(&ap->dead_sem); + ppp_unregister_channel(&ap->chan); if (ap->rpkt != 0) kfree_skb(ap->rpkt); @@ -203,9 +252,11 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); int err, val; + if (ap == 0) + return -ENXIO; err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: @@ -251,6 +302,7 @@ err = -ENOIOCTLCMD; } + ap_put(ap); return err; } @@ -271,13 +323,14 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, char *flags, int count) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); if (ap == 0) return; spin_lock_bh(&ap->recv_lock); ppp_async_input(ap, buf, flags, count); spin_unlock_bh(&ap->recv_lock); + ap_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -286,13 +339,14 @@ static void ppp_asynctty_wakeup(struct tty_struct *tty) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (ap == 0) return; if (ppp_async_push(ap)) ppp_output_wakeup(&ap->chan); + ap_put(ap); } diff -urN linux-2.4.18/drivers/net/ppp_generic.c linux-2.4.19-pre5/drivers/net/ppp_generic.c --- linux-2.4.18/drivers/net/ppp_generic.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/ppp_generic.c Sat Mar 30 22:55:34 2002 @@ -1,7 +1,7 @@ /* * Generic PPP layer for Linux. * - * Copyright 1999-2000 Paul Mackerras. + * Copyright 1999-2002 Paul Mackerras. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000902== + * ==FILEVERSION 20020217== */ #include @@ -43,10 +43,12 @@ #include #include #include +#include +#include #include #include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" /* * Network protocols we support. @@ -75,11 +77,11 @@ wait_queue_head_t rwait; /* for poll on reading /dev/ppp */ atomic_t refcnt; /* # refs (incl /dev/ppp attached) */ int hdrlen; /* space to leave for headers */ - struct list_head list; /* link in all_* list */ int index; /* interface unit / channel number */ + int dead; /* unit/channel has been shut down */ }; -#define PF_TO_X(pf, X) ((X *)((char *)(pf)-(unsigned long)(&((X *)0)->file))) +#define PF_TO_X(pf, X) ((X *)((char *)(pf) - offsetof(X, file))) #define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) #define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) @@ -93,26 +95,27 @@ * It can have 0 or more ppp channels connected to it. */ struct ppp { - struct ppp_file file; /* stuff for read/write/poll */ - struct list_head channels; /* list of attached channels */ - int n_channels; /* how many channels are attached */ - spinlock_t rlock; /* lock for receive side */ - spinlock_t wlock; /* lock for transmit side */ - int mru; /* max receive unit */ - unsigned int flags; /* control bits */ - unsigned int xstate; /* transmit state bits */ - unsigned int rstate; /* receive state bits */ - int debug; /* debug flags */ + struct ppp_file file; /* stuff for read/write/poll 0 */ + struct file *owner; /* file that owns this unit 48 */ + struct list_head channels; /* list of attached channels 4c */ + int n_channels; /* how many channels are attached 54 */ + spinlock_t rlock; /* lock for receive side 58 */ + spinlock_t wlock; /* lock for transmit side 5c */ + int mru; /* max receive unit 60 */ + unsigned int flags; /* control bits 64 */ + unsigned int xstate; /* transmit state bits 68 */ + unsigned int rstate; /* receive state bits 6c */ + int debug; /* debug flags 70 */ struct slcompress *vj; /* state for VJ header compression */ - enum NPmode npmode[NUM_NP]; /* what to do with each net proto */ - struct sk_buff *xmit_pending; /* a packet ready to go out */ - struct compressor *xcomp; /* transmit packet compressor */ - void *xc_state; /* its internal state */ - struct compressor *rcomp; /* receive decompressor */ - void *rc_state; /* its internal state */ - unsigned long last_xmit; /* jiffies when last pkt sent */ - unsigned long last_recv; /* jiffies when last pkt rcvd */ - struct net_device *dev; /* network interface device */ + enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */ + struct sk_buff *xmit_pending; /* a packet ready to go out 88 */ + struct compressor *xcomp; /* transmit packet compressor 8c */ + void *xc_state; /* its internal state 90 */ + struct compressor *rcomp; /* receive decompressor 94 */ + void *rc_state; /* its internal state 98 */ + unsigned long last_xmit; /* jiffies when last pkt sent 9c */ + unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ + struct net_device *dev; /* network interface device a4 */ #ifdef CONFIG_PPP_MULTILINK int nxchan; /* next channel to send something on */ u32 nxseq; /* next sequence number to send */ @@ -144,11 +147,13 @@ */ struct channel { struct ppp_file file; /* stuff for read/write/poll */ + struct list_head list; /* link in all/new_channels list */ struct ppp_channel *chan; /* public channel data structure */ + struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ spinlock_t downl; /* protects `chan', file.xq dequeue */ struct ppp *ppp; /* ppp unit we're connected to */ struct list_head clist; /* link in list of channels per unit */ - rwlock_t upl; /* protects `ppp' and `ulist' */ + rwlock_t upl; /* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK u8 avail; /* flag used in multilink stuff */ u8 had_frag; /* >= 1 fragments have been sent */ @@ -166,12 +171,35 @@ */ /* - * all_ppp_sem protects the all_ppp_units. - * It also ensures that finding a ppp unit in the all_ppp_units list + * A cardmap represents a mapping from unsigned integers to pointers, + * and provides a fast "find lowest unused number" operation. + * It uses a broad (32-way) tree with a bitmap at each level. + * It is designed to be space-efficient for small numbers of entries + * and time-efficient for large numbers of entries. + */ +#define CARDMAP_ORDER 5 +#define CARDMAP_WIDTH (1U << CARDMAP_ORDER) +#define CARDMAP_MASK (CARDMAP_WIDTH - 1) + +struct cardmap { + int shift; + unsigned long inuse; + struct cardmap *parent; + void *ptr[CARDMAP_WIDTH]; +}; +static void *cardmap_get(struct cardmap *map, unsigned int nr); +static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); +static unsigned int cardmap_find_first_free(struct cardmap *map); +static void cardmap_destroy(struct cardmap **map); + +/* + * all_ppp_sem protects the all_ppp_units mapping. + * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ static DECLARE_MUTEX(all_ppp_sem); -static LIST_HEAD(all_ppp_units); +static struct cardmap *all_ppp_units; +static atomic_t ppp_unit_count = ATOMIC_INIT(0); /* * all_channels_lock protects all_channels and last_channel_index, @@ -180,7 +208,9 @@ */ static spinlock_t all_channels_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(all_channels); +static LIST_HEAD(new_channels); static int last_channel_index; +static atomic_t channel_count = ATOMIC_INIT(0); /* Get the PPP protocol number from a skb */ #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) @@ -205,10 +235,6 @@ #define seq_after(a, b) ((s32)((a) - (b)) > 0) /* Prototypes. */ -static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file, - char *buf, size_t count); -static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf, - size_t count); static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static void ppp_xmit_process(struct ppp *ppp); @@ -235,6 +261,7 @@ static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); static struct ppp *ppp_create_interface(int unit, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); +static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(int unit); static struct channel *ppp_find_channel(int unit); @@ -303,7 +330,6 @@ #define ppp_unlock(ppp) do { ppp_recv_unlock(ppp); \ ppp_xmit_unlock(ppp); } while (0) - /* * /dev/ppp device routines. * The /dev/ppp device is used by pppd to control the ppp unit. @@ -323,11 +349,16 @@ static int ppp_release(struct inode *inode, struct file *file) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; + struct ppp *ppp; - lock_kernel(); if (pf != 0) { file->private_data = 0; + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } if (atomic_dec_and_test(&pf->refcnt)) { switch (pf->kind) { case INTERFACE: @@ -339,37 +370,27 @@ } } } - unlock_kernel(); return 0; } static ssize_t ppp_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; - - return ppp_file_read(pf, file, buf, count); -} - -static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file, - char *buf, size_t count) -{ + struct ppp_file *pf = file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; struct sk_buff *skb = 0; - ret = -ENXIO; if (pf == 0) - goto out; /* not currently attached */ - + return -ENXIO; add_wait_queue(&pf->rwait, &wait); - current->state = TASK_INTERRUPTIBLE; for (;;) { + set_current_state(TASK_INTERRUPTIBLE); skb = skb_dequeue(&pf->rq); if (skb) break; ret = 0; - if (pf->kind == CHANNEL && PF_TO_CHANNEL(pf)->chan == 0) + if (pf->dead) break; ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) @@ -379,7 +400,7 @@ break; schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&pf->rwait, &wait); if (skb == 0) @@ -402,21 +423,12 @@ static ssize_t ppp_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; - - return ppp_file_write(pf, buf, count); -} - -static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf, - size_t count) -{ + struct ppp_file *pf = file->private_data; struct sk_buff *skb; ssize_t ret; - ret = -ENXIO; if (pf == 0) - goto out; - + return -ENXIO; ret = -ENOMEM; skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL); if (skb == 0) @@ -448,7 +460,7 @@ /* No kernel lock - fine */ static unsigned int ppp_poll(struct file *file, poll_table *wait) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; unsigned int mask; if (pf == 0) @@ -457,28 +469,52 @@ mask = POLLOUT | POLLWRNORM; if (skb_peek(&pf->rq) != 0) mask |= POLLIN | POLLRDNORM; - if (pf->kind == CHANNEL) { - struct channel *pch = PF_TO_CHANNEL(pf); - if (pch->chan == 0) - mask |= POLLHUP; - } + if (pf->dead) + mask |= POLLHUP; return mask; } static int ppp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; struct ppp *ppp; int err = -EFAULT, val, val2, i; struct ppp_idle idle; struct npioctl npi; - int unit; + int unit, cflags; struct slcompress *vj; if (pf == 0) return ppp_unattached_ioctl(pf, file, cmd, arg); + if (cmd == PPPIOCDETACH) { + /* + * We have to be careful here... if the file descriptor + * has been dup'd, we could have another process in the + * middle of a poll using the same file *, so we had + * better not free the interface data structures - + * instead we fail the ioctl. Even in this case, we + * shut down the interface if we are the owner of it. + * Actually, we should get rid of PPPIOCDETACH, userland + * (i.e. pppd) could achieve the same effect by closing + * this fd and reopening /dev/ppp. + */ + err = -EINVAL; + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } + if (atomic_read(&file->f_count) <= 2) { + ppp_release(inode, file); + err = 0; + } else + printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", + atomic_read(&file->f_count)); + return err; + } + if (pf->kind == CHANNEL) { struct channel *pch = PF_TO_CHANNEL(pf); struct ppp_channel *chan; @@ -494,20 +530,13 @@ err = ppp_disconnect_channel(pch); break; - case PPPIOCDETACH: - file->private_data = 0; - if (atomic_dec_and_test(&pf->refcnt)) - ppp_destroy_channel(pch); - err = 0; - break; - default: - spin_lock_bh(&pch->downl); + down_read(&pch->chan_sem); chan = pch->chan; err = -ENOTTY; if (chan && chan->ops->ioctl) err = chan->ops->ioctl(chan, cmd, arg); - spin_unlock_bh(&pch->downl); + up_read(&pch->chan_sem); } return err; } @@ -520,13 +549,6 @@ ppp = PF_TO_PPP(pf); switch (cmd) { - case PPPIOCDETACH: - file->private_data = 0; - if (atomic_dec_and_test(&pf->refcnt)) - ppp_destroy_interface(ppp); - err = 0; - break; - case PPPIOCSMRU: if (get_user(val, (int *) arg)) break; @@ -538,10 +560,11 @@ if (get_user(val, (int *) arg)) break; ppp_lock(ppp); - if (ppp->flags & ~val & SC_CCP_OPEN) - ppp_ccp_closed(ppp); + cflags = ppp->flags & ~val; ppp->flags = val & SC_FLAG_BITS; ppp_unlock(ppp); + if (cflags & SC_CCP_OPEN) + ppp_ccp_closed(ppp); err = 0; break; @@ -677,6 +700,7 @@ default: err = -ENOTTY; } + return err; } @@ -696,6 +720,7 @@ if (ppp == 0) break; file->private_data = &ppp->file; + ppp->owner = file; err = -EFAULT; if (put_user(ppp->file.index, (int *) arg)) break; @@ -707,30 +732,28 @@ if (get_user(unit, (int *) arg)) break; down(&all_ppp_sem); + err = -ENXIO; ppp = ppp_find_unit(unit); - if (ppp != 0) + if (ppp != 0) { atomic_inc(&ppp->file.refcnt); + file->private_data = &ppp->file; + err = 0; + } up(&all_ppp_sem); - err = -ENXIO; - if (ppp == 0) - break; - file->private_data = &ppp->file; - err = 0; break; case PPPIOCATTCHAN: if (get_user(unit, (int *) arg)) break; spin_lock_bh(&all_channels_lock); + err = -ENXIO; chan = ppp_find_channel(unit); - if (chan != 0) + if (chan != 0) { atomic_inc(&chan->file.refcnt); + file->private_data = &chan->file; + err = 0; + } spin_unlock_bh(&all_channels_lock); - err = -ENXIO; - if (chan == 0) - break; - file->private_data = &chan->file; - err = 0; break; default: @@ -907,15 +930,16 @@ struct sk_buff *skb; ppp_xmit_lock(ppp); - ppp_push(ppp); - while (ppp->xmit_pending == 0 - && (skb = skb_dequeue(&ppp->file.xq)) != 0) - ppp_send_frame(ppp, skb); - /* If there's no work left to do, tell the core net - code that we can accept some more. */ - if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0 - && ppp->dev != 0) - netif_wake_queue(ppp->dev); + if (ppp->dev != 0) { + ppp_push(ppp); + while (ppp->xmit_pending == 0 + && (skb = skb_dequeue(&ppp->file.xq)) != 0) + ppp_send_frame(ppp, skb); + /* If there's no work left to do, tell the core net + code that we can accept some more. */ + if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0) + netif_wake_queue(ppp->dev); + } ppp_xmit_unlock(ppp); } @@ -1800,7 +1824,7 @@ { struct channel *pch; - pch = kmalloc(sizeof(struct channel), GFP_ATOMIC); + pch = kmalloc(sizeof(struct channel), GFP_KERNEL); if (pch == 0) return -ENOMEM; memset(pch, 0, sizeof(struct channel)); @@ -1812,11 +1836,13 @@ #ifdef CONFIG_PPP_MULTILINK pch->lastseq = -1; #endif /* CONFIG_PPP_MULTILINK */ + init_rwsem(&pch->chan_sem); spin_lock_init(&pch->downl); pch->upl = RW_LOCK_UNLOCKED; spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; - list_add(&pch->file.list, &all_channels); + list_add(&pch->list, &new_channels); + atomic_inc(&channel_count); spin_unlock_bh(&all_channels_lock); MOD_INC_USE_COUNT; return 0; @@ -1829,7 +1855,9 @@ { struct channel *pch = chan->ppp; - return pch->file.index; + if (pch != 0) + return pch->file.index; + return -1; } /* @@ -1851,7 +1879,7 @@ /* * Disconnect a channel from the generic layer. - * This can be called from mainline or BH/softirq level. + * This must be called in process context. */ void ppp_unregister_channel(struct ppp_channel *chan) @@ -1866,14 +1894,17 @@ * This ensures that we have returned from any calls into the * the channel's start_xmit or ioctl routine before we proceed. */ + down_write(&pch->chan_sem); spin_lock_bh(&pch->downl); pch->chan = 0; spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); ppp_disconnect_channel(pch); - wake_up_interruptible(&pch->file.rwait); spin_lock_bh(&all_channels_lock); - list_del(&pch->file.list); + list_del(&pch->list); spin_unlock_bh(&all_channels_lock); + pch->file.dead = 1; + wake_up_interruptible(&pch->file.rwait); if (atomic_dec_and_test(&pch->file.refcnt)) ppp_destroy_channel(pch); MOD_DEC_USE_COUNT; @@ -1902,9 +1933,9 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) { int err; - struct compressor *cp; + struct compressor *cp, *ocomp; struct ppp_option_data data; - void *state; + void *state, *ostate; unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; #ifdef CONFIG_KMOD char modname[32]; @@ -1930,41 +1961,39 @@ #endif /* CONFIG_KMOD */ if (cp == 0) goto out; + /* + * XXX race: the compressor module could get unloaded between + * here and when we do the comp_alloc or decomp_alloc call below. + */ err = -ENOBUFS; if (data.transmit) { - ppp_xmit_lock(ppp); - ppp->xstate &= ~SC_COMP_RUN; - if (ppp->xc_state != 0) { - ppp->xcomp->comp_free(ppp->xc_state); - ppp->xc_state = 0; - } - ppp_xmit_unlock(ppp); - state = cp->comp_alloc(ccp_option, data.length); if (state != 0) { ppp_xmit_lock(ppp); + ppp->xstate &= ~SC_COMP_RUN; + ocomp = ppp->xcomp; + ostate = ppp->xc_state; ppp->xcomp = cp; ppp->xc_state = state; ppp_xmit_unlock(ppp); + if (ostate != 0) + ocomp->comp_free(ostate); err = 0; } } else { - ppp_recv_lock(ppp); - ppp->rstate &= ~SC_DECOMP_RUN; - if (ppp->rc_state != 0) { - ppp->rcomp->decomp_free(ppp->rc_state); - ppp->rc_state = 0; - } - ppp_recv_unlock(ppp); - state = cp->decomp_alloc(ccp_option, data.length); if (state != 0) { ppp_recv_lock(ppp); + ppp->rstate &= ~SC_DECOMP_RUN; + ocomp = ppp->rcomp; + ostate = ppp->rc_state; ppp->rcomp = cp; ppp->rc_state = state; ppp_recv_unlock(ppp); + if (ostate != 0) + ocomp->decomp_free(ostate); err = 0; } } @@ -2062,19 +2091,25 @@ static void ppp_ccp_closed(struct ppp *ppp) { - ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); + void *xstate, *rstate; + struct compressor *xcomp, *rcomp; - ppp->xstate &= ~SC_COMP_RUN; - if (ppp->xc_state) { - ppp->xcomp->comp_free(ppp->xc_state); - ppp->xc_state = 0; - } + ppp_lock(ppp); + ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); + ppp->xstate = 0; + xcomp = ppp->xcomp; + xstate = ppp->xc_state; + ppp->xc_state = 0; + ppp->rstate = 0; + rcomp = ppp->rcomp; + rstate = ppp->rc_state; + ppp->rc_state = 0; + ppp_unlock(ppp); - ppp->xstate &= ~SC_DECOMP_RUN; - if (ppp->rc_state) { - ppp->rcomp->decomp_free(ppp->rc_state); - ppp->rc_state = 0; - } + if (xstate) + xcomp->comp_free(xstate); + if (rstate) + rcomp->decomp_free(rstate); } /* List of compressors. */ @@ -2194,39 +2229,27 @@ ppp_create_interface(int unit, int *retp) { struct ppp *ppp; - struct net_device *dev; - struct list_head *list; - int last_unit = -1; - int ret = -EEXIST; + struct net_device *dev = NULL; + int ret = -ENOMEM; int i; - down(&all_ppp_sem); - list = &all_ppp_units; - while ((list = list->next) != &all_ppp_units) { - ppp = list_entry(list, struct ppp, file.list); - if ((unit < 0 && ppp->file.index > last_unit + 1) - || (unit >= 0 && unit < ppp->file.index)) - break; - if (unit == ppp->file.index) - goto out; /* unit already exists */ - last_unit = ppp->file.index; - } - if (unit < 0) - unit = last_unit + 1; - - /* Create a new ppp structure and link it before `list'. */ - ret = -ENOMEM; ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); if (ppp == 0) - goto out; - memset(ppp, 0, sizeof(struct ppp)); + goto err; dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == 0) { - kfree(ppp); - goto out; - } + if (dev == 0) + goto err; + memset(ppp, 0, sizeof(struct ppp)); memset(dev, 0, sizeof(struct net_device)); + ret = -EEXIST; + down(&all_ppp_sem); + if (unit < 0) + unit = cardmap_find_first_free(all_ppp_units); + else if (cardmap_get(all_ppp_units, unit) != NULL) + goto err_unlock; /* unit already exists */ + + /* Initialize the new ppp unit */ ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); @@ -2251,19 +2274,26 @@ ret = register_netdevice(dev); rtnl_unlock(); if (ret != 0) { - printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret); - kfree(dev); - kfree(ppp); - goto out; + printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", + dev->name, ret); + goto err_unlock; } - list_add(&ppp->file.list, list->prev); - out: - up(&all_ppp_sem); - *retp = ret; - if (ret != 0) - ppp = 0; + atomic_inc(&ppp_unit_count); + cardmap_set(&all_ppp_units, unit, ppp); + up(&all_ppp_sem); + *retp = 0; return ppp; + + err_unlock: + up(&all_ppp_sem); + err: + *retp = ret; + if (ppp) + kfree(ppp); + if (dev) + kfree(dev); + return NULL; } /* @@ -2280,19 +2310,48 @@ } /* - * Free up all the resources used by a ppp interface unit. + * Take down a ppp interface unit - called when the owning file + * (the one that created the unit) is closed or detached. */ -static void ppp_destroy_interface(struct ppp *ppp) +static void ppp_shutdown_interface(struct ppp *ppp) { struct net_device *dev; - int n_channels ; down(&all_ppp_sem); - list_del(&ppp->file.list); - - /* Last fd open to this ppp unit is being closed or detached: - mark the interface down, free the ppp unit */ ppp_lock(ppp); + dev = ppp->dev; + ppp->dev = 0; + ppp_unlock(ppp); + if (dev) { + rtnl_lock(); + dev_close(dev); + unregister_netdevice(dev); + rtnl_unlock(); + } + cardmap_set(&all_ppp_units, ppp->file.index, NULL); + ppp->file.dead = 1; + ppp->owner = NULL; + wake_up_interruptible(&ppp->file.rwait); + up(&all_ppp_sem); +} + +/* + * Free the memory used by a ppp unit. This is only called once + * there are no channels connected to the unit and no file structs + * that reference the unit. + */ +static void ppp_destroy_interface(struct ppp *ppp) +{ + atomic_dec(&ppp_unit_count); + + if (!ppp->file.dead || ppp->n_channels) { + /* "can't happen" */ + printk(KERN_ERR "ppp: destroying ppp struct %p but dead=%d " + "n_channels=%d !\n", ppp, ppp->file.dead, + ppp->n_channels); + return; + } + ppp_ccp_closed(ppp); if (ppp->vj) { slhc_free(ppp->vj); @@ -2313,52 +2372,27 @@ ppp->active_filter.filter = 0; } #endif /* CONFIG_PPP_FILTER */ - dev = ppp->dev; - ppp->dev = 0; - n_channels = ppp->n_channels ; - ppp_unlock(ppp); - if (dev) { - rtnl_lock(); - dev_close(dev); - unregister_netdevice(dev); - rtnl_unlock(); - } - - /* - * We can't acquire any new channels (since we have the - * all_ppp_sem) so if n_channels is 0, we can free the - * ppp structure. Otherwise we leave it around until the - * last channel disconnects from it. - */ - if (n_channels == 0) - kfree(ppp); - - up(&all_ppp_sem); + kfree(ppp); } /* * Locate an existing ppp unit. - * The caller must have locked the all_ppp_sem. + * The caller should have locked the all_ppp_sem. */ static struct ppp * ppp_find_unit(int unit) { - struct ppp *ppp; - struct list_head *list; - - list = &all_ppp_units; - while ((list = list->next) != &all_ppp_units) { - ppp = list_entry(list, struct ppp, file.list); - if (ppp->file.index == unit) - return ppp; - } - return 0; + return cardmap_get(all_ppp_units, unit); } /* * Locate an existing ppp channel. * The caller should have locked the all_channels_lock. + * First we look in the new_channels list, then in the + * all_channels list. If found in the new_channels list, + * we move it to the all_channels list. This is for speed + * when we have a lot of channels in use. */ static struct channel * ppp_find_channel(int unit) @@ -2366,9 +2400,18 @@ struct channel *pch; struct list_head *list; + list = &new_channels; + while ((list = list->next) != &new_channels) { + pch = list_entry(list, struct channel, list); + if (pch->file.index == unit) { + list_del(&pch->list); + list_add(&pch->list, &all_channels); + return pch; + } + } list = &all_channels; while ((list = list->next) != &all_channels) { - pch = list_entry(list, struct channel, file.list); + pch = list_entry(list, struct channel, list); if (pch->file.index == unit) return pch; } @@ -2392,12 +2435,9 @@ write_lock_bh(&pch->upl); ret = -EINVAL; if (pch->ppp != 0) - goto outwl; - ppp_lock(ppp); - spin_lock_bh(&pch->downl); - if (pch->chan == 0) /* need to check this?? */ - goto outr; + goto outl; + ppp_lock(ppp); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ @@ -2406,15 +2446,14 @@ list_add_tail(&pch->clist, &ppp->channels); ++ppp->n_channels; pch->ppp = ppp; + atomic_inc(&ppp->file.refcnt); + ppp_unlock(ppp); ret = 0; - outr: - spin_unlock_bh(&pch->downl); - ppp_unlock(ppp); - outwl: + outl: write_unlock_bh(&pch->upl); out: - up(&all_ppp_sem); + up(&all_ppp_sem); return ret; } @@ -2426,25 +2465,21 @@ { struct ppp *ppp; int err = -EINVAL; - int dead; write_lock_bh(&pch->upl); ppp = pch->ppp; + pch->ppp = NULL; + write_unlock_bh(&pch->upl); if (ppp != 0) { /* remove it from the ppp unit's list */ - pch->ppp = NULL; ppp_lock(ppp); list_del(&pch->clist); --ppp->n_channels; - dead = ppp->dev == 0 && ppp->n_channels == 0; ppp_unlock(ppp); - if (dead) - /* Last disconnect from a ppp unit - that is already dead: free it. */ - kfree(ppp); + if (atomic_dec_and_test(&ppp->file.refcnt)) + ppp_destroy_interface(ppp); err = 0; } - write_unlock_bh(&pch->upl); return err; } @@ -2453,6 +2488,14 @@ */ static void ppp_destroy_channel(struct channel *pch) { + atomic_dec(&channel_count); + + if (!pch->file.dead) { + /* "can't happen" */ + printk(KERN_ERR "ppp: destroying undead channel %p !\n", + pch); + return; + } skb_queue_purge(&pch->file.xq); skb_queue_purge(&pch->file.rq); kfree(pch); @@ -2461,12 +2504,123 @@ static void __exit ppp_cleanup(void) { /* should never happen */ - if (!list_empty(&all_ppp_units) || !list_empty(&all_channels)) + if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) printk(KERN_ERR "PPP: removing module but units remain!\n"); + cardmap_destroy(&all_ppp_units); if (devfs_unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); devfs_unregister(devfs_handle); } + +/* + * Cardmap implementation. + */ +static void *cardmap_get(struct cardmap *map, unsigned int nr) +{ + struct cardmap *p; + int i; + + for (p = map; p != NULL; ) { + if ((i = nr >> p->shift) >= CARDMAP_WIDTH) + return NULL; + if (p->shift == 0) + return p->ptr[i]; + nr &= ~(CARDMAP_MASK << p->shift); + p = p->ptr[i]; + } + return NULL; +} + +static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) +{ + struct cardmap *p; + int i; + + p = *pmap; + if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { + do { + /* need a new top level */ + struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); + memset(np, 0, sizeof(*np)); + np->ptr[0] = p; + if (p != NULL) { + np->shift = p->shift + CARDMAP_ORDER; + p->parent = np; + } else + np->shift = 0; + p = np; + } while ((nr >> p->shift) >= CARDMAP_WIDTH); + *pmap = p; + } + while (p->shift > 0) { + i = (nr >> p->shift) & CARDMAP_MASK; + if (p->ptr[i] == NULL) { + struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); + memset(np, 0, sizeof(*np)); + np->shift = p->shift - CARDMAP_ORDER; + np->parent = p; + p->ptr[i] = np; + } + if (ptr == NULL) + clear_bit(i, &p->inuse); + p = p->ptr[i]; + } + i = nr & CARDMAP_MASK; + p->ptr[i] = ptr; + if (ptr != NULL) + set_bit(i, &p->inuse); + else + clear_bit(i, &p->inuse); +} + +static unsigned int cardmap_find_first_free(struct cardmap *map) +{ + struct cardmap *p; + unsigned int nr = 0; + int i; + + if ((p = map) == NULL) + return 0; + for (;;) { + i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); + if (i >= CARDMAP_WIDTH) { + if (p->parent == NULL) + return CARDMAP_WIDTH << p->shift; + p = p->parent; + i = (nr >> p->shift) & CARDMAP_MASK; + set_bit(i, &p->inuse); + continue; + } + nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); + if (p->shift == 0 || p->ptr[i] == NULL) + return nr; + p = p->ptr[i]; + } +} + +static void cardmap_destroy(struct cardmap **pmap) +{ + struct cardmap *p, *np; + int i; + + for (p = *pmap; p != NULL; p = np) { + if (p->shift != 0) { + for (i = 0; i < CARDMAP_WIDTH; ++i) + if (p->ptr[i] != NULL) + break; + if (i < CARDMAP_WIDTH) { + np = p->ptr[i]; + p->ptr[i] = NULL; + continue; + } + } + np = p->parent; + kfree(p); + } + *pmap = NULL; +} + +/* Module/initialization stuff */ module_init(ppp_init); module_exit(ppp_cleanup); diff -urN linux-2.4.18/drivers/net/ppp_synctty.c linux-2.4.19-pre5/drivers/net/ppp_synctty.c --- linux-2.4.18/drivers/net/ppp_synctty.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/ppp_synctty.c Sat Mar 30 22:55:34 2002 @@ -25,11 +25,11 @@ * the generic PPP layer to give it frames to send and to process * received frames. It implements the PPP line discipline. * - * Part of the code in this driver was inspired by the old sync-only + * Part of the code in this driver was inspired by the old async-only * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000322== + * ==FILEVERSION 20020125== */ #include @@ -41,10 +41,12 @@ #include #include #include +#include #include #include +#include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" /* Structure for storing local state. */ struct syncppp { @@ -65,6 +67,8 @@ struct sk_buff *rpkt; + atomic_t refcnt; + struct semaphore dead_sem; struct ppp_channel chan; /* interface to generic ppp layer */ }; @@ -161,7 +165,36 @@ */ /* - * Called when a tty is put into line discipline. + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_synctty_receive while another + * calls ppp_synctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_synctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + */ +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct syncppp *sp_get(struct tty_struct *tty) +{ + struct syncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void sp_put(struct syncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + up(&ap->dead_sem); +} + +/* + * Called when a tty is put into sync-PPP line discipline. */ static int ppp_sync_open(struct tty_struct *tty) @@ -185,6 +218,9 @@ ap->xaccm[3] = 0x60000000U; ap->raccm = ~0U; + atomic_set(&ap->refcnt, 1); + init_MUTEX_LOCKED(&ap->dead_sem); + ap->chan.private = ap; ap->chan.ops = &sync_ops; ap->chan.mtu = PPP_MRU; @@ -206,16 +242,34 @@ /* * Called when the tty is put into another line discipline - * (or it hangs up). + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_synctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the syncppp struct. This routine must be called from + * process context, not interrupt or softirq context. */ static void ppp_sync_close(struct tty_struct *tty) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap; + write_lock(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = 0; + write_unlock(&disc_data_lock); if (ap == 0) return; - tty->disc_data = 0; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_sync_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + down(&ap->dead_sem); + ppp_unregister_channel(&ap->chan); if (ap->rpkt != 0) kfree_skb(ap->rpkt); @@ -251,9 +305,11 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); int err, val; + if (ap == 0) + return -ENXIO; err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: @@ -299,6 +355,7 @@ err = -ENOIOCTLCMD; } + sp_put(ap); return err; } @@ -319,13 +376,14 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, char *flags, int count) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); if (ap == 0) return; spin_lock_bh(&ap->recv_lock); ppp_sync_input(ap, buf, flags, count); spin_unlock_bh(&ap->recv_lock); + sp_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -334,13 +392,14 @@ static void ppp_sync_wakeup(struct tty_struct *tty) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (ap == 0) return; if (ppp_sync_push(ap)) ppp_output_wakeup(&ap->chan); + sp_put(ap); } diff -urN linux-2.4.18/drivers/net/pppoe.c linux-2.4.19-pre5/drivers/net/pppoe.c --- linux-2.4.18/drivers/net/pppoe.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/pppoe.c Sat Mar 30 22:55:34 2002 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.9 + * Version: 0.6.10 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -31,6 +31,9 @@ * a memory leak. * 081001 : Misc. cleanup (licence string, non-blocking, prevent * reference of device on close). + * 121301 : New ppp channels interface; cannot unregister a channel + * from interrupts. Thus, we mark the socket as a ZOMBIE + * and do the unregistration later. * * Author: Michal Ostrowski * Contributors: @@ -86,11 +89,11 @@ #if 0 -#define CHECKPTR(x,y) { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }} -#define DEBUG(s,args...) if( pppoe_debug & (s) ) printk(KERN_CRIT args ); +#define CHECKPTR(x,y) do { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }} while (0) +#define DEBUG(s,args...) do { if( pppoe_debug & (s) ) printk(KERN_CRIT args ); } while (0) #else -#define CHECKPTR(x,y) do {} while (0); -#define DEBUG(s,args...) do { } while (0); +#define CHECKPTR(x,y) do { } while (0) +#define DEBUG(s,args...) do { } while (0) #endif @@ -273,10 +276,10 @@ lock_sock(sk); - if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + if (sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ pppox_unbind_sock(sk); dev_put(dev); - sk->state = PPPOX_DEAD; + sk->state = PPPOX_ZOMBIE; sk->state_change(sk); } @@ -439,8 +442,10 @@ * one socket family type, we cannot (easily) distinguish * what kind of SKB it is during backlog rcv. */ - if (sk->lock.users == 0) + if (sk->lock.users == 0) { + sk->state = PPPOX_ZOMBIE; pppox_unbind_sock(sk); + } bh_unlock_sock(sk); sock_put(sk); @@ -722,7 +727,7 @@ struct pppox_opt *relay_po; err = -EBUSY; - if (sk->state & PPPOX_BOUND) + if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE|PPPOX_DEAD)) break; err = -ENOTCONN; diff -urN linux-2.4.18/drivers/net/rrunner.c linux-2.4.19-pre5/drivers/net/rrunner.c --- linux-2.4.18/drivers/net/rrunner.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/rrunner.c Sat Mar 30 22:55:28 2002 @@ -73,13 +73,13 @@ #define rr_mark_net_bh(foo) mark_bh(foo) #define rr_if_busy(dev) dev->tbusy #define rr_if_running(dev) dev->start /* Currently unused. */ -#define rr_if_down(dev) {do{dev->start = 0;}while (0);} +#define rr_if_down(dev) do { dev->start = 0; } while (0) #else #define NET_BH 0 -#define rr_mark_net_bh(foo) {do{} while(0);} +#define rr_mark_net_bh(foo) do { } while(0) #define rr_if_busy(dev) netif_queue_stopped(dev) #define rr_if_running(dev) netif_running(dev) -#define rr_if_down(dev) {do{} while(0);} +#define rr_if_down(dev) do { } while(0) #endif #include "rrunner.h" @@ -269,6 +269,7 @@ #if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +MODULE_LICENSE("GPL"); #endif int init_module(void) @@ -770,7 +771,7 @@ * Give the FirmWare time to chew on the `get running' command. */ myjif = jiffies + 5 * HZ; - while ((jiffies < myjif) && !rrpriv->fw_running); + while (time_before(jiffies, myjif) && !rrpriv->fw_running); netif_start_queue(dev); diff -urN linux-2.4.18/drivers/net/sb1000.c linux-2.4.19-pre5/drivers/net/sb1000.c --- linux-2.4.18/drivers/net/sb1000.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sb1000.c Sat Mar 30 22:55:28 2002 @@ -204,7 +204,12 @@ /* * Ok set it up. */ - + if (!request_region(ioaddr[0], 16, dev->name)) + continue; + if (!request_region(ioaddr[1], 16, dev->name)) { + release_region(ioaddr[0], 16); + continue; + } dev->base_addr = ioaddr[0]; /* rmem_end holds the second I/O address - fv */ @@ -262,9 +267,6 @@ /* Lock resources */ - request_region(ioaddr[0], 16, dev->name); - request_region(ioaddr[1], 16, dev->name); - return 0; } } @@ -403,7 +405,7 @@ } timeout = jiffies + Sb1000TimeOutJiffies; while (!(inb(ioaddr[1] + 6) & 0x40)) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", name); return -ETIME; @@ -421,7 +423,7 @@ timeout = jiffies + Sb1000TimeOutJiffies; while (inb(ioaddr[1] + 6) & 0x80) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", name); return -ETIME; @@ -429,7 +431,7 @@ } timeout = jiffies + Sb1000TimeOutJiffies; while (inb(ioaddr[1] + 6) & 0x40) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", name); return -ETIME; @@ -962,8 +964,6 @@ /* rmem_end holds the second I/O address - fv */ ioaddr[1] = dev->rmem_end; name = dev->name; - request_region(ioaddr[0], SB1000_IO_EXTENT, "sb1000"); - request_region(ioaddr[1], SB1000_IO_EXTENT, "sb1000"); /* initialize sb1000 */ if ((status = sb1000_reset(ioaddr, name))) diff -urN linux-2.4.18/drivers/net/sb1250-mac.c linux-2.4.19-pre5/drivers/net/sb1250-mac.c --- linux-2.4.18/drivers/net/sb1250-mac.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/sb1250-mac.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,2673 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + This driver is designed for the Broadcom BCM12500 SOC chip's built-in + Ethernet controllers. + + The author may be reached as mpl@broadcom.com +*/ + + +/* A few user-configurable values. + These may be modified when a driver module is loaded. */ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ + +#define MAX_UNITS 3 /* More are supported, limit only on options */ +#ifdef MODULE +static int options[MAX_UNITS] = {-1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1}; +#endif + + +/* Operational parameters that usually are not changed. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + +/* This is only here until the firmware is ready. In that case, + the firmware leaves the ethernet address in the register for us. */ +#ifdef CONFIG_SWARM_STANDALONE +#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00" +#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01" +#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02" +#endif + + +/* These identify the driver base version and may not be removed. */ +#if 0 +static char version1[] __devinitdata = +"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n"; +#endif + + + +MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)"); +MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + + +#include +#include +#include +#include +#include + + +/********************************************************************** + * Simple types + ********************************************************************* */ + + +typedef unsigned long sbmac_port_t; +typedef uint64_t sbmac_physaddr_t; +typedef uint64_t sbmac_enetaddr_t; + +typedef enum { sbmac_speed_auto, sbmac_speed_10, + sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; + +typedef enum { sbmac_duplex_auto, sbmac_duplex_half, + sbmac_duplex_full } sbmac_duplex_t; + +typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, + sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; + +typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, + sbmac_state_broken } sbmac_state_t; + + +/********************************************************************** + * Macros + ********************************************************************* */ + + +#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \ + (d)->sbdma_dscrtable : (d)->f+1) + + +#define CACHELINESIZE 32 +#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE) +#define KMALLOC(x) kmalloc((x),GFP_KERNEL) +#define KFREE(x) kfree(x) +#define KVTOPHYS(x) virt_to_bus((void *)(x)) + + +#define SBMAC_READCSR(t) (in64((unsigned long)(t))) +#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t))) + +#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x)) + +#define SBMAC_MAX_TXDESCR 32 +#define SBMAC_MAX_RXDESCR 32 + +#define ETHER_ALIGN 2 +#define ETHER_ADDR_LEN 6 +#define ENET_PACKET_SIZE 1518 + +/********************************************************************** + * DMA Descriptor structure + ********************************************************************* */ + +typedef struct sbdmadscr_s { + uint64_t dscr_a; + uint64_t dscr_b; +} sbdmadscr_t; + +typedef unsigned long paddr_t; +typedef unsigned long vaddr_t; + +/********************************************************************** + * DMA Controller structure + ********************************************************************* */ + +typedef struct sbmacdma_s { + + /* + * This stuff is used to identify the channel and the registers + * associated with it. + */ + + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ + int sbdma_channel; /* channel number */ + int sbdma_txdir; /* direction (1=transmit) */ + int sbdma_maxdescr; /* total # of descriptors in ring */ + sbmac_port_t sbdma_config0; /* DMA config register 0 */ + sbmac_port_t sbdma_config1; /* DMA config register 1 */ + sbmac_port_t sbdma_dscrbase; /* Descriptor base address */ + sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */ + sbmac_port_t sbdma_curdscr; /* current descriptor address */ + + /* + * This stuff is for maintenance of the ring + */ + + sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ + sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ + + struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ + + paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ + sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ + sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ + +} sbmacdma_t; + + +/********************************************************************** + * Ethernet softc structure + ********************************************************************* */ + +struct sbmac_softc { + + /* + * Linux-specific things + */ + + struct net_device *sbm_dev; /* pointer to linux device */ + spinlock_t sbm_lock; /* spin lock */ + struct timer_list sbm_timer; /* for monitoring MII */ + struct net_device_stats sbm_stats; + int sbm_devflags; /* current device flags */ + + int sbm_phy_oldbmsr; + int sbm_phy_oldanlpar; + int sbm_phy_oldk1stsr; + int sbm_phy_oldlinkstat; + int sbm_buffersize; + + unsigned char sbm_phys[2]; + + /* + * Controller-specific things + */ + + sbmac_port_t sbm_base; /* MAC's base address */ + sbmac_state_t sbm_state; /* current state */ + + sbmac_port_t sbm_macenable; /* MAC Enable Register */ + sbmac_port_t sbm_maccfg; /* MAC Configuration Register */ + sbmac_port_t sbm_fifocfg; /* FIFO configuration register */ + sbmac_port_t sbm_framecfg; /* Frame configuration register */ + sbmac_port_t sbm_rxfilter; /* receive filter register */ + sbmac_port_t sbm_isr; /* Interrupt status register */ + sbmac_port_t sbm_imr; /* Interrupt mask register */ + sbmac_port_t sbm_mdio; /* MDIO register */ + + sbmac_speed_t sbm_speed; /* current speed */ + sbmac_duplex_t sbm_duplex; /* current duplex */ + sbmac_fc_t sbm_fc; /* current flow control setting */ + + u_char sbm_hwaddr[ETHER_ADDR_LEN]; + + sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ + sbmacdma_t sbm_rxdma; + +}; + + +/********************************************************************** + * Externs + ********************************************************************* */ + +/********************************************************************** + * Prototypes + ********************************************************************* */ + +static void sbdma_initctx(sbmacdma_t *d, + struct sbmac_softc *s, + int chan, + int txrx, + int maxdescr); +static void sbdma_channel_start(sbmacdma_t *d); +static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); +static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); +static void sbdma_emptyring(sbmacdma_t *d); +static void sbdma_fillring(sbmacdma_t *d); +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d); +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d); +static int sbmac_initctx(struct sbmac_softc *s); +static void sbmac_channel_start(struct sbmac_softc *s); +static void sbmac_channel_stop(struct sbmac_softc *s); +static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t); +static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff); +/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/ +static uint64_t sbmac_addr2reg(unsigned char *ptr); +static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs); +static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); +static void sbmac_setmulti(struct sbmac_softc *sc); +static int sbmac_init(struct net_device *dev); +static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed); +static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc); + +static int sbmac_open(struct net_device *dev); +static void sbmac_timer(unsigned long data); +static void sbmac_tx_timeout (struct net_device *dev); +static struct net_device_stats *sbmac_get_stats(struct net_device *dev); +static void sbmac_set_rx_mode(struct net_device *dev); +static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int sbmac_close(struct net_device *dev); +static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); + +static void sbmac_mii_sync(struct sbmac_softc *s); +static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); +static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx); +static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, + unsigned int regval); + + +/********************************************************************** + * Globals + ********************************************************************* */ + + +/********************************************************************** + * MDIO constants + ********************************************************************* */ + +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + +#define BMCR_RESET 0x8000 +#define BMCR_LOOPBACK 0x4000 +#define BMCR_SPEED0 0x2000 +#define BMCR_ANENABLE 0x1000 +#define BMCR_POWERDOWN 0x0800 +#define BMCR_ISOLATE 0x0400 +#define BMCR_RESTARTAN 0x0200 +#define BMCR_DUPLEX 0x0100 +#define BMCR_COLTEST 0x0080 +#define BMCR_SPEED1 0x0040 +#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0) +#define BMCR_SPEED100 (BMCR_SPEED0) +#define BMCR_SPEED10 0 + +#define BMSR_100BT4 0x8000 +#define BMSR_100BT_FDX 0x4000 +#define BMSR_100BT_HDX 0x2000 +#define BMSR_10BT_FDX 0x1000 +#define BMSR_10BT_HDX 0x0800 +#define BMSR_100BT2_FDX 0x0400 +#define BMSR_100BT2_HDX 0x0200 +#define BMSR_1000BT_XSR 0x0100 +#define BMSR_PRESUP 0x0040 +#define BMSR_ANCOMPLT 0x0020 +#define BMSR_REMFAULT 0x0010 +#define BMSR_AUTONEG 0x0008 +#define BMSR_LINKSTAT 0x0004 +#define BMSR_JABDETECT 0x0002 +#define BMSR_EXTCAPAB 0x0001 + +#define PHYIDR1 0x2000 +#define PHYIDR2 0x5C60 + +#define ANAR_NP 0x8000 +#define ANAR_RF 0x2000 +#define ANAR_ASYPAUSE 0x0800 +#define ANAR_PAUSE 0x0400 +#define ANAR_T4 0x0200 +#define ANAR_TXFD 0x0100 +#define ANAR_TXHD 0x0080 +#define ANAR_10FD 0x0040 +#define ANAR_10HD 0x0020 +#define ANAR_PSB 0x0001 + +#define ANLPAR_NP 0x8000 +#define ANLPAR_ACK 0x4000 +#define ANLPAR_RF 0x2000 +#define ANLPAR_ASYPAUSE 0x0800 +#define ANLPAR_PAUSE 0x0400 +#define ANLPAR_T4 0x0200 +#define ANLPAR_TXFD 0x0100 +#define ANLPAR_TXHD 0x0080 +#define ANLPAR_10FD 0x0040 +#define ANLPAR_10HD 0x0020 +#define ANLPAR_PSB 0x0001 /* 802.3 */ + +#define ANER_PDF 0x0010 +#define ANER_LPNPABLE 0x0008 +#define ANER_NPABLE 0x0004 +#define ANER_PAGERX 0x0002 +#define ANER_LPANABLE 0x0001 + +#define ANNPTR_NP 0x8000 +#define ANNPTR_MP 0x2000 +#define ANNPTR_ACK2 0x1000 +#define ANNPTR_TOGTX 0x0800 +#define ANNPTR_CODE 0x0008 + +#define ANNPRR_NP 0x8000 +#define ANNPRR_MP 0x2000 +#define ANNPRR_ACK3 0x1000 +#define ANNPRR_TOGTX 0x0800 +#define ANNPRR_CODE 0x0008 + +#define K1TCR_TESTMODE 0x0000 +#define K1TCR_MSMCE 0x1000 +#define K1TCR_MSCV 0x0800 +#define K1TCR_RPTR 0x0400 +#define K1TCR_1000BT_FDX 0x200 +#define K1TCR_1000BT_HDX 0x100 + +#define K1STSR_MSMCFLT 0x8000 +#define K1STSR_MSCFGRES 0x4000 +#define K1STSR_LRSTAT 0x2000 +#define K1STSR_RRSTAT 0x1000 +#define K1STSR_LP1KFD 0x0800 +#define K1STSR_LP1KHD 0x0400 +#define K1STSR_LPASMDIR 0x0200 + +#define K1SCR_1KX_FDX 0x8000 +#define K1SCR_1KX_HDX 0x4000 +#define K1SCR_1KT_FDX 0x2000 +#define K1SCR_1KT_HDX 0x1000 + +#define STRAP_PHY1 0x0800 +#define STRAP_NCMODE 0x0400 +#define STRAP_MANMSCFG 0x0200 +#define STRAP_ANENABLE 0x0100 +#define STRAP_MSVAL 0x0080 +#define STRAP_1KHDXADV 0x0010 +#define STRAP_1KFDXADV 0x0008 +#define STRAP_100ADV 0x0004 +#define STRAP_SPEEDSEL 0x0000 +#define STRAP_SPEED100 0x0001 + +#define PHYSUP_SPEED1000 0x10 +#define PHYSUP_SPEED100 0x08 +#define PHYSUP_SPEED10 0x00 +#define PHYSUP_LINKUP 0x04 +#define PHYSUP_FDX 0x02 + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define MII_K1STSR 0x0A /* 1K Status Register (ro) */ +#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ + + +#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */ + + +/********************************************************************** + * SBMAC_MII_SYNC(s) + * + * Synchronize with the MII - send a pattern of bits to the MII + * that will guarantee that it is ready to accept a command. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_mii_sync(struct sbmac_softc *s) +{ + int cnt; + uint64_t bits; + + bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; + + SBMAC_WRITECSR(s->sbm_mdio,bits); + + for (cnt = 0; cnt < 32; cnt++) { + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,bits); + } +} + +/********************************************************************** + * SBMAC_MII_SENDDATA(s,data,bitcnt) + * + * Send some bits to the MII. The bits to be sent are right- + * justified in the 'data' parameter. + * + * Input parameters: + * s - sbmac structure + * data - data to send + * bitcnt - number of bits to send + ********************************************************************* */ + +static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt) +{ + int i; + uint64_t bits; + unsigned int curmask; + + bits = M_MAC_MDIO_DIR_OUTPUT; + SBMAC_WRITECSR(s->sbm_mdio,bits); + + curmask = 1 << (bitcnt - 1); + + for (i = 0; i < bitcnt; i++) { + if (data & curmask) bits |= M_MAC_MDIO_OUT; + else bits &= ~M_MAC_MDIO_OUT; + SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,bits); + curmask >>= 1; + } +} + + + +/********************************************************************** + * SBMAC_MII_READ(s,phyaddr,regidx) + * + * Read a PHY register. + * + * Input parameters: + * s - sbmac structure + * phyaddr - PHY's address + * regidx = index of register to read + * + * Return value: + * value read, or 0 if an error occured. + ********************************************************************* */ + +static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) +{ + int idx; + int error; + int regval; + + /* + * Synchronize ourselves so that the PHY knows the next + * thing coming down is a command + */ + + sbmac_mii_sync(s); + + /* + * Send the data to the PHY. The sequence is + * a "start" command (2 bits) + * a "read" command (2 bits) + * the PHY addr (5 bits) + * the register index (5 bits) + */ + + sbmac_mii_senddata(s,MII_COMMAND_START, 2); + sbmac_mii_senddata(s,MII_COMMAND_READ, 2); + sbmac_mii_senddata(s,phyaddr, 5); + sbmac_mii_senddata(s,regidx, 5); + + /* + * Switch the port around without a clock transition. + */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + /* + * Send out a clock pulse to signal we want the status + */ + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + /* + * If an error occured, the PHY will signal '1' back + */ + error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN; + + /* + * Issue an 'idle' clock pulse, but keep the direction + * the same. + */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + regval = 0; + + for (idx = 0; idx < 16; idx++) { + regval <<= 1; + + if (error == 0) { + if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; + } + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + } + + /* Switch back to output */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); + + if (error == 0) return regval; + return 0; +} + + +/********************************************************************** + * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) + * + * Write a value to a PHY register. + * + * Input parameters: + * s - sbmac structure + * phyaddr - PHY to use + * regidx - register within the PHY + * regval - data to write to register + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, + unsigned int regval) +{ + + sbmac_mii_sync(s); + + sbmac_mii_senddata(s,MII_COMMAND_START,2); + sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); + sbmac_mii_senddata(s,phyaddr, 5); + sbmac_mii_senddata(s,regidx, 5); + sbmac_mii_senddata(s,MII_COMMAND_ACK,2); + sbmac_mii_senddata(s,regval,16); + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); +} + + + +/********************************************************************** + * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) + * + * Initialize a DMA channel context. Since there are potentially + * eight DMA channels per MAC, it's nice to do this in a standard + * way. + * + * Input parameters: + * d - sbmacdma_t structure (DMA channel context) + * s - sbmac_softc structure (pointer to a MAC) + * chan - channel number (0..1 right now) + * txrx - Identifies DMA_TX or DMA_RX for channel direction + * maxdescr - number of descriptors + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_initctx(sbmacdma_t *d, + struct sbmac_softc *s, + int chan, + int txrx, + int maxdescr) +{ + /* + * Save away interesting stuff in the structure + */ + + d->sbdma_eth = s; + d->sbdma_channel = chan; + d->sbdma_txdir = txrx; + + /* + * initialize register pointers + */ + + d->sbdma_config0 = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0)); + d->sbdma_config1 = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0)); + d->sbdma_dscrbase = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE)); + d->sbdma_dscrcnt = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT)); + d->sbdma_curdscr = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR)); + + /* + * Allocate memory for the ring + */ + + d->sbdma_maxdescr = maxdescr; + + d->sbdma_dscrtable = (sbdmadscr_t *) + KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + + memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + + d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; + + d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable); + + /* + * And context table + */ + + d->sbdma_ctxtable = (struct sk_buff **) + KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *)); + + memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); + +} + +/********************************************************************** + * SBDMA_CHANNEL_START(d) + * + * Initialize the hardware registers for a DMA channel. + * + * Input parameters: + * d - DMA channel to init (context must be previously init'd + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_channel_start(sbmacdma_t *d) +{ + /* + * Turn on the DMA channel + */ + + SBMAC_WRITECSR(d->sbdma_config1,0); + + SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys); + + SBMAC_WRITECSR(d->sbdma_config0, + V_DMA_RINGSZ(d->sbdma_maxdescr) | + 0); + + /* + * Initialize ring pointers + */ + + d->sbdma_addptr = d->sbdma_dscrtable; + d->sbdma_remptr = d->sbdma_dscrtable; +} + + +static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) +{ + unsigned long addr; + unsigned long newaddr; + + addr = (unsigned long) skb->data; + + newaddr = (addr + power2 - 1) & ~(power2 - 1); + + skb_reserve(skb,newaddr-addr+offset); +} + + +/********************************************************************** + * SBDMA_ADD_RCVBUFFER(d,sb) + * + * Add a buffer to the specified DMA channel. For receive channels, + * this queues a buffer for inbound packets. + * + * Input parameters: + * d - DMA channel descriptor + * sb - sk_buff to add, or NULL if we should allocate one + * + * Return value: + * 0 if buffer could not be added (ring is full) + * 1 if buffer added successfully + ********************************************************************* */ + + +static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) +{ + sbdmadscr_t *dsc; + sbdmadscr_t *nextdsc; + struct sk_buff *sb_new = NULL; + int pktsize = ENET_PACKET_SIZE; + + /* get pointer to our current place in the ring */ + + dsc = d->sbdma_addptr; + nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); + + /* + * figure out if the ring is full - if the next descriptor + * is the same as the one that we're going to remove from + * the ring, the ring is full + */ + + if (nextdsc == d->sbdma_remptr) { + return -ENOSPC; + } + + /* + * Allocate a sk_buff if we don't already have one. + * If we do have an sk_buff, reset it so that it's empty. + * + * Note: sk_buffs don't seem to be guaranteed to have any sort + * of alignment when they are allocated. Therefore, allocate enough + * extra space to make sure that: + * + * 1. the data does not start in the middle of a cache line. + * 2. The data does not end in the middle of a cache line + * 3. The buffer can be aligned such that the IP addresses are + * naturally aligned. + * + * Remember, the SB1250's MAC writes whole cache lines at a time, + * without reading the old contents first. So, if the sk_buff's + * data portion starts in the middle of a cache line, the SB1250 + * DMA will trash the beginning (and ending) portions. + */ + + if (sb == NULL) { + sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN); + if (sb_new == NULL) { + printk(KERN_INFO "%s: sk_buff allocation failed\n", + d->sbdma_eth->sbm_dev->name); + return -ENOBUFS; + } + + sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN); + + /* mark skbuff owned by our device */ + sb_new->dev = d->sbdma_eth->sbm_dev; + } + else { + sb_new = sb; + /* + * nothing special to reinit buffer, it's already aligned + * and sb->tail already points to a good place. + */ + } + + /* + * fill in the descriptor + */ + + dsc->dscr_a = KVTOPHYS(sb_new->tail) | + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | + M_DMA_DSCRA_INTERRUPT; + + /* receiving: no options */ + dsc->dscr_b = 0; + + /* + * fill in the context + */ + + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; + + /* + * point at next packet + */ + + d->sbdma_addptr = nextdsc; + + /* + * Give the buffer to the DMA engine. + */ + + SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + + return 0; /* we did it */ +} + +/********************************************************************** + * SBDMA_ADD_TXBUFFER(d,sb) + * + * Add a transmit buffer to the specified DMA channel, causing a + * transmit to start. + * + * Input parameters: + * d - DMA channel descriptor + * sb - sk_buff to add + * + * Return value: + * 0 transmit queued successfully + * otherwise error code + ********************************************************************* */ + + +static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) +{ + sbdmadscr_t *dsc; + sbdmadscr_t *nextdsc; + uint64_t phys; + uint64_t ncb; + int length; + + /* get pointer to our current place in the ring */ + + dsc = d->sbdma_addptr; + nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); + + /* + * figure out if the ring is full - if the next descriptor + * is the same as the one that we're going to remove from + * the ring, the ring is full + */ + + if (nextdsc == d->sbdma_remptr) { + return -ENOSPC; + } + + /* + * Under Linux, it's not necessary to copy/coalesce buffers + * like it is on NetBSD. We think they're all contiguous, + * but that may not be true for GBE. + */ + + length = sb->len; + + /* + * fill in the descriptor. Note that the number of cache + * blocks in the descriptor is the number of blocks + * *spanned*, so we need to add in the offset (if any) + * while doing the calculation. + */ + + phys = KVTOPHYS(sb->data); + ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1))); + + dsc->dscr_a = phys | + V_DMA_DSCRA_A_SIZE(ncb) | + M_DMA_DSCRA_INTERRUPT | + M_DMA_ETHTX_SOP; + + /* transmitting: set outbound options and length */ + + dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | + V_DMA_DSCRB_PKT_SIZE(length); + + /* + * fill in the context + */ + + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; + + /* + * point at next packet + */ + + d->sbdma_addptr = nextdsc; + + /* + * Give the buffer to the DMA engine. + */ + + SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + + return 0; /* we did it */ +} + + + + +/********************************************************************** + * SBDMA_EMPTYRING(d) + * + * Free all allocated sk_buffs on the specified DMA channel; + * + * Input parameters: + * d - DMA channel + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_emptyring(sbmacdma_t *d) +{ + int idx; + struct sk_buff *sb; + + for (idx = 0; idx < d->sbdma_maxdescr; idx++) { + sb = d->sbdma_ctxtable[idx]; + if (sb) { + dev_kfree_skb(sb); + d->sbdma_ctxtable[idx] = NULL; + } + } +} + + +/********************************************************************** + * SBDMA_FILLRING(d) + * + * Fill the specified DMA channel (must be receive channel) + * with sk_buffs + * + * Input parameters: + * d - DMA channel + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_fillring(sbmacdma_t *d) +{ + int idx; + + for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { + if (sbdma_add_rcvbuffer(d,NULL) != 0) break; + } +} + + +/********************************************************************** + * SBDMA_RX_PROCESS(sc,d) + * + * Process "completed" receive buffers on the specified DMA channel. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. + * + * Input parameters: + * sc - softc structure + * d - DMA channel context + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) +{ + int curidx; + int hwidx; + sbdmadscr_t *dsc; + struct sk_buff *sb; + int len; + + for (;;) { + /* + * figure out where we are (as an index) and where + * the hardware is (also as an index) + * + * This could be done faster if (for example) the + * descriptor table was page-aligned and contiguous in + * both virtual and physical memory -- you could then + * just compare the low-order bits of the virtual address + * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) + */ + + curidx = d->sbdma_remptr - d->sbdma_dscrtable; + hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + + /* + * If they're the same, that means we've processed all + * of the descriptors up to (but not including) the one that + * the hardware is working on right now. + */ + + if (curidx == hwidx) break; + + /* + * Otherwise, get the packet's sk_buff ptr back + */ + + dsc = &(d->sbdma_dscrtable[curidx]); + sb = d->sbdma_ctxtable[curidx]; + d->sbdma_ctxtable[curidx] = NULL; + + len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4; + + /* + * Check packet status. If good, process it. + * If not, silently drop it and put it back on the + * receive ring. + */ + + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { + + /* + * Set length into the packet + */ + skb_put(sb,len); + + /* + * Add a new buffer to replace the old one. If we fail + * to allocate a buffer, we're going to drop this + * packet and put it right back on the receive ring. + */ + + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { + sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ + } + else { + /* + * Buffer has been replaced on the receive ring. + * Pass the buffer to the kernel + */ + sc->sbm_stats.rx_bytes += len; + sc->sbm_stats.rx_packets++; + sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); + netif_rx(sb); + } + } + else { + /* + * Packet was mangled somehow. Just drop it and + * put it back on the receive ring. + */ + sbdma_add_rcvbuffer(d,sb); + } + + + /* + * .. and advance to the next buffer. + */ + + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); + + } +} + + + +/********************************************************************** + * SBDMA_TX_PROCESS(sc,d) + * + * Process "completed" transmit buffers on the specified DMA channel. + * This is normally called within the interrupt service routine. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. + * + * Input parameters: + * sc - softc structure + * d - DMA channel context + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) +{ + int curidx; + int hwidx; + sbdmadscr_t *dsc; + struct sk_buff *sb; + unsigned long flags; + + spin_lock_irqsave(&(sc->sbm_lock), flags); + + for (;;) { + /* + * figure out where we are (as an index) and where + * the hardware is (also as an index) + * + * This could be done faster if (for example) the + * descriptor table was page-aligned and contiguous in + * both virtual and physical memory -- you could then + * just compare the low-order bits of the virtual address + * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) + */ + + curidx = d->sbdma_remptr - d->sbdma_dscrtable; + { + /* XXX This is gross, ugly, and only here because justin hacked it + in to fix a problem without really understanding it. + + It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts. + So then the Read below returns zero, making hwidx a negative number, and anti-hilarity + ensues. + + I'm guessing there's a proper fix involving clearing out interrupt state from old packets + before enabling interrupts, but I'm not sure. + + Anyways, this hack seems to work, and is Good Enough for 11 PM. :) + + -Justin + */ + + uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr); + if (!tmp) { + break; + } + hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + } + /* + * If they're the same, that means we've processed all + * of the descriptors up to (but not including) the one that + * the hardware is working on right now. + */ + + if (curidx == hwidx) break; + + /* + * Otherwise, get the packet's sk_buff ptr back + */ + + dsc = &(d->sbdma_dscrtable[curidx]); + sb = d->sbdma_ctxtable[curidx]; + d->sbdma_ctxtable[curidx] = NULL; + + /* + * Stats + */ + + sc->sbm_stats.tx_bytes += sb->len; + sc->sbm_stats.tx_packets++; + + /* + * for transmits, we just free buffers. + */ + + dev_kfree_skb_irq(sb); + + /* + * .. and advance to the next buffer. + */ + + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); + + } + + /* + * Decide if we should wake up the protocol or not. + * Other drivers seem to do this when we reach a low + * watermark on the transmit queue. + */ + + netif_wake_queue(d->sbdma_eth->sbm_dev); + + spin_unlock_irqrestore(&(sc->sbm_lock), flags); + +} + + + +/********************************************************************** + * SBMAC_INITCTX(s) + * + * Initialize an Ethernet context structure - this is called + * once per MAC on the 1250. Memory is allocated here, so don't + * call it again from inside the ioctl routines that bring the + * interface up/down + * + * Input parameters: + * s - sbmac context structure + * + * Return value: + * 0 + ********************************************************************* */ + +static int sbmac_initctx(struct sbmac_softc *s) +{ + + /* + * figure out the addresses of some ports + */ + + s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE); + s->sbm_maccfg = PKSEG1(s->sbm_base + R_MAC_CFG); + s->sbm_fifocfg = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG); + s->sbm_framecfg = PKSEG1(s->sbm_base + R_MAC_FRAMECFG); + s->sbm_rxfilter = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG); + s->sbm_isr = PKSEG1(s->sbm_base + R_MAC_STATUS); + s->sbm_imr = PKSEG1(s->sbm_base + R_MAC_INT_MASK); + s->sbm_mdio = PKSEG1(s->sbm_base + R_MAC_MDIO); + + s->sbm_phys[0] = 1; + s->sbm_phys[1] = 0; + + s->sbm_phy_oldbmsr = 0; + s->sbm_phy_oldanlpar = 0; + s->sbm_phy_oldk1stsr = 0; + s->sbm_phy_oldlinkstat = 0; + + /* + * Initialize the DMA channels. Right now, only one per MAC is used + * Note: Only do this _once_, as it allocates memory from the kernel! + */ + + sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR); + sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR); + + /* + * initial state is OFF + */ + + s->sbm_state = sbmac_state_off; + + /* + * Initial speed is (XXX TEMP) 10MBit/s HDX no FC + */ + + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + + return 0; +} + + +static void sbdma_uninitctx(struct sbmacdma_s *d) +{ + if (d->sbdma_dscrtable) { + KFREE(d->sbdma_dscrtable); + d->sbdma_dscrtable = NULL; + } + + if (d->sbdma_ctxtable) { + KFREE(d->sbdma_ctxtable); + d->sbdma_ctxtable = NULL; + } +} + + +static void sbmac_uninitctx(struct sbmac_softc *sc) +{ + sbdma_uninitctx(&(sc->sbm_txdma)); + sbdma_uninitctx(&(sc->sbm_rxdma)); +} + + +/********************************************************************** + * SBMAC_CHANNEL_START(s) + * + * Start packet processing on this MAC. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_channel_start(struct sbmac_softc *s) +{ + uint64_t reg; + sbmac_port_t port; + uint64_t cfg,fifo,framecfg; + int idx; + + /* + * Don't do this if running + */ + + if (s->sbm_state == sbmac_state_on) return; + + /* + * Bring the controller out of reset, but leave it off. + */ + + SBMAC_WRITECSR(s->sbm_macenable,0); + + /* + * Ignore all received packets + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + + /* + * Calculate values for various control registers. + */ + + cfg = M_MAC_RETRY_EN | + M_MAC_TX_HOLD_SOP_EN | + V_MAC_TX_PAUSE_CNT_16K | + M_MAC_AP_STAT_EN | + M_MAC_FAST_SYNC | + M_MAC_SS_EN | + 0; + + fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ + V_MAC_TX_RD_THRSH(4) | + V_MAC_TX_RL_THRSH(4) | + V_MAC_RX_PL_THRSH(4) | + V_MAC_RX_RD_THRSH(4) | /* Must be '4' */ + V_MAC_RX_PL_THRSH(4) | + V_MAC_RX_RL_THRSH(8) | + 0; + + framecfg = V_MAC_MIN_FRAMESZ_DEFAULT | + V_MAC_MAX_FRAMESZ_DEFAULT | + V_MAC_BACKOFF_SEL(1); + + + /* + * Clear out the hash address map + */ + + port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE); + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Clear out the exact-match table + */ + + port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE); + for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Clear out the DMA Channel mapping table registers + */ + + port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE); + for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + + port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE); + for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Program the hardware address. It goes into the hardware-address + * register as well as the first filter register. + */ + + reg = sbmac_addr2reg(s->sbm_hwaddr); + + port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE); + SBMAC_WRITECSR(port,reg); + port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR); + +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + /* + * Pass1 SB1250s do not receive packets addressed to the + * destination address in the R_MAC_ETHERNET_ADDR register. + * Set the value to zero. + */ + SBMAC_WRITECSR(port,0); +#else + SBMAC_WRITECSR(port,reg); +#endif + + /* + * Set the receive filter for no packets, and write values + * to the various config registers + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + SBMAC_WRITECSR(s->sbm_imr,0); + SBMAC_WRITECSR(s->sbm_framecfg,framecfg); + SBMAC_WRITECSR(s->sbm_fifocfg,fifo); + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + /* + * Initialize DMA channels (rings should be ok now) + */ + + sbdma_channel_start(&(s->sbm_rxdma)); + sbdma_channel_start(&(s->sbm_txdma)); + + /* + * Configure the speed, duplex, and flow control + */ + + sbmac_set_speed(s,s->sbm_speed); + sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc); + + /* + * Fill the receive ring + */ + + sbdma_fillring(&(s->sbm_rxdma)); + + /* + * Turn on the rest of the bits in the enable register + */ + + SBMAC_WRITECSR(s->sbm_macenable, + M_MAC_RXDMA_EN0 | + M_MAC_TXDMA_EN0 | + M_MAC_RX_ENABLE | + M_MAC_TX_ENABLE); + + + + /* + * Accept any kind of interrupt on TX and RX DMA channel 0 + */ + SBMAC_WRITECSR(s->sbm_imr, + (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)); + + /* + * Enable receiving unicasts and broadcasts + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN); + + /* + * we're running now. + */ + + s->sbm_state = sbmac_state_on; + + /* + * Program multicast addresses + */ + + sbmac_setmulti(s); + + /* + * If channel was in promiscuous mode before, turn that on + */ + + if (s->sbm_devflags & IFF_PROMISC) { + sbmac_promiscuous_mode(s,1); + } + +} + + +/********************************************************************** + * SBMAC_CHANNEL_STOP(s) + * + * Stop packet processing on this MAC. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_channel_stop(struct sbmac_softc *s) +{ + uint64_t ctl; + + /* don't do this if already stopped */ + + if (s->sbm_state == sbmac_state_off) return; + + /* don't accept any packets, disable all interrupts */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + SBMAC_WRITECSR(s->sbm_imr,0); + + /* Turn off ticker */ + + /* XXX */ + + /* turn off receiver and transmitter */ + + ctl = SBMAC_READCSR(s->sbm_macenable); + ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0); + SBMAC_WRITECSR(s->sbm_macenable,ctl); + + /* We're stopped now. */ + + s->sbm_state = sbmac_state_off; + + + /* Empty the receive and transmit rings */ + + sbdma_emptyring(&(s->sbm_rxdma)); + sbdma_emptyring(&(s->sbm_txdma)); + +} + +/********************************************************************** + * SBMAC_SET_CHANNEL_STATE(state) + * + * Set the channel's state ON or OFF + * + * Input parameters: + * state - new state + * + * Return value: + * old state + ********************************************************************* */ +static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, + sbmac_state_t state) +{ + sbmac_state_t oldstate = sc->sbm_state; + + /* + * If same as previous state, return + */ + + if (state == oldstate) { + return oldstate; + } + + /* + * If new state is ON, turn channel on + */ + + if (state == sbmac_state_on) { + sbmac_channel_start(sc); + } + else { + sbmac_channel_stop(sc); + } + + /* + * Return previous state + */ + + return oldstate; +} + + +/********************************************************************** + * SBMAC_PROMISCUOUS_MODE(sc,onoff) + * + * Turn on or off promiscuous mode + * + * Input parameters: + * sc - softc + * onoff - 1 to turn on, 0 to turn off + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) +{ + uint64_t reg; + + if (sc->sbm_state != sbmac_state_on) return; + + if (onoff) { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= M_MAC_ALLPKT_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } + else { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg &= ~M_MAC_ALLPKT_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } +} + + + +#if 0 +/********************************************************************** + * SBMAC_INIT_AND_START(sc) + * + * Stop the channel and restart it. This is generally used + * when we have to do something to the channel that requires + * a swift kick. + * + * Input parameters: + * sc - softc + ********************************************************************* */ + +static void sbmac_init_and_start(struct sbmac_softc *sc) +{ + unsigned long flags; + + spin_lock_irqsave(&(sc->sbm_lock),flags); + + sbmac_set_channel_state(sc,sbmac_state_on); + + spin_unlock_irqrestore(&(sc->sbm_lock),flags); +} +#endif + + +/********************************************************************** + * SBMAC_ADDR2REG(ptr) + * + * Convert six bytes into the 64-bit register value that + * we typically write into the SBMAC's address/mcast registers + * + * Input parameters: + * ptr - pointer to 6 bytes + * + * Return value: + * register value + ********************************************************************* */ + +static uint64_t sbmac_addr2reg(unsigned char *ptr) +{ + uint64_t reg = 0; + + ptr += 6; + + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + + return reg; +} + + +/********************************************************************** + * SBMAC_SET_SPEED(s,speed) + * + * Configure LAN speed for the specified MAC. + * Warning: must be called when MAC is off! + * + * Input parameters: + * s - sbmac structure + * speed - speed to set MAC to (see sbmac_speed_t enum) + * + * Return value: + * 1 if successful + * 0 indicates invalid parameters + ********************************************************************* */ + +static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) +{ + uint64_t cfg; + uint64_t framecfg; + + /* + * Save new current values + */ + + s->sbm_speed = speed; + + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ + + /* + * Read current register values + */ + + cfg = SBMAC_READCSR(s->sbm_maccfg); + framecfg = SBMAC_READCSR(s->sbm_framecfg); + + /* + * Mask out the stuff we want to change + */ + + cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL); + framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH | + M_MAC_SLOT_SIZE); + + /* + * Now add in the new bits + */ + + switch (speed) { + case sbmac_speed_10: + framecfg |= V_MAC_IFG_RX_10 | + V_MAC_IFG_TX_10 | + K_MAC_IFG_THRSH_10 | + V_MAC_SLOT_SIZE_10; + cfg |= V_MAC_SPEED_SEL_10MBPS; + break; + + case sbmac_speed_100: + framecfg |= V_MAC_IFG_RX_100 | + V_MAC_IFG_TX_100 | + V_MAC_IFG_THRSH_100 | + V_MAC_SLOT_SIZE_100; + cfg |= V_MAC_SPEED_SEL_100MBPS ; + break; + + case sbmac_speed_1000: + framecfg |= V_MAC_IFG_RX_1000 | + V_MAC_IFG_TX_1000 | + V_MAC_IFG_THRSH_1000 | + V_MAC_SLOT_SIZE_1000; + cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; + break; + + case sbmac_speed_auto: /* XXX not implemented */ + /* fall through */ + default: + return 0; + } + + /* + * Send the bits back to the hardware + */ + + SBMAC_WRITECSR(s->sbm_framecfg,framecfg); + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + return 1; + +} + +/********************************************************************** + * SBMAC_SET_DUPLEX(s,duplex,fc) + * + * Set Ethernet duplex and flow control options for this MAC + * Warning: must be called when MAC is off! + * + * Input parameters: + * s - sbmac structure + * duplex - duplex setting (see sbmac_duplex_t) + * fc - flow control setting (see sbmac_fc_t) + * + * Return value: + * 1 if ok + * 0 if an invalid parameter combination was specified + ********************************************************************* */ + +static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) +{ + uint64_t cfg; + + /* + * Save new current values + */ + + s->sbm_duplex = duplex; + s->sbm_fc = fc; + + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ + + /* + * Read current register values + */ + + cfg = SBMAC_READCSR(s->sbm_maccfg); + + /* + * Mask off the stuff we're about to change + */ + + cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN); + + + switch (duplex) { + case sbmac_duplex_half: + switch (fc) { + case sbmac_fc_disabled: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED; + break; + + case sbmac_fc_collision: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED; + break; + + case sbmac_fc_carrier: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; + break; + + case sbmac_fc_auto: /* XXX not implemented */ + /* fall through */ + case sbmac_fc_frame: /* not valid in half duplex */ + default: /* invalid selection */ + return 0; + } + break; + + case sbmac_duplex_full: + switch (fc) { + case sbmac_fc_disabled: + cfg |= V_MAC_FC_CMD_DISABLED; + break; + + case sbmac_fc_frame: + cfg |= V_MAC_FC_CMD_ENABLED; + break; + + case sbmac_fc_collision: /* not valid in full duplex */ + case sbmac_fc_carrier: /* not valid in full duplex */ + case sbmac_fc_auto: /* XXX not implemented */ + /* fall through */ + default: + return 0; + } + break; + case sbmac_duplex_auto: + /* XXX not implemented */ + break; + } + + /* + * Send the bits back to the hardware + */ + + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + return 1; +} + + + + +/********************************************************************** + * SBMAC_INTR() + * + * Interrupt handler for MAC interrupts + * + * Input parameters: + * MAC structure + * + * Return value: + * nothing + ********************************************************************* */ +static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv); + uint64_t isr; + + for (;;) { + + /* + * Read the ISR (this clears the bits in the real register) + */ + + isr = SBMAC_READCSR(sc->sbm_isr); + + if (isr == 0) break; + + /* + * Transmits on channel 0 + */ + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { + sbdma_tx_process(sc,&(sc->sbm_txdma)); + } + + /* + * Receives on channel 0 + */ + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { + sbdma_rx_process(sc,&(sc->sbm_rxdma)); + } + } + +} + + +/********************************************************************** + * SBMAC_START_TX(skb,dev) + * + * Start output on the specified interface. Basically, we + * queue as many buffers as we can until the ring fills up, or + * we run off the end of the queue, whichever comes first. + * + * Input parameters: + * + * + * Return value: + * nothing + ********************************************************************* */ +static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + /* lock eth irq */ + spin_lock_irq (&sc->sbm_lock); + + /* + * Put the buffer on the transmit ring. If we + * don't have room, stop the queue. + */ + + if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { + /* XXX save skb that we could not send */ + netif_stop_queue(dev); + } + + dev->trans_start = jiffies; + + spin_unlock_irq (&sc->sbm_lock); + + return 0; +} + +/********************************************************************** + * SBMAC_SETMULTI(sc) + * + * Reprogram the multicast table into the hardware, given + * the list of multicasts associated with the interface + * structure. + * + * Input parameters: + * sc - softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_setmulti(struct sbmac_softc *sc) +{ + uint64_t reg; + sbmac_port_t port; + int idx; + struct dev_mc_list *mclist; + struct net_device *dev = sc->sbm_dev; + + /* + * Clear out entire multicast table. We do this by nuking + * the entire hash table and all the direct matches except + * the first one, which is used for our station address + */ + + for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { + port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,0); + } + + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { + port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,0); + } + + /* + * Clear the filter to say we don't want any multicasts. + */ + + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + + if (dev->flags & IFF_ALLMULTI) { + /* + * Enable ALL multicasts. Do this by inverting the + * multicast enable bit. + */ + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + return; + } + + + /* + * Progam new multicast entries. For now, only use the + * perfect filter. In the future we'll need to use the + * hash filter if the perfect filter overflows + */ + + /* XXX only using perfect filter for now, need to use hash + * XXX if the table overflows */ + + idx = 1; /* skip station address */ + mclist = dev->mc_list; + while (mclist && (idx < MAC_ADDR_COUNT)) { + reg = sbmac_addr2reg(mclist->dmi_addr); + port = PKSEG1(sc->sbm_base + + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,reg); + idx++; + mclist = mclist->next; + } + + /* + * Enable the "accept multicast bits" if we programmed at least one + * multicast. + */ + + if (idx > 1) { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= M_MAC_MCAST_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } +} + + + +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +/********************************************************************** + * SBMAC_PARSE_XDIGIT(str) + * + * Parse a hex digit, returning its value + * + * Input parameters: + * str - character + * + * Return value: + * hex value, or -1 if invalid + ********************************************************************* */ + +static int sbmac_parse_xdigit(char str) +{ + int digit; + + if ((str >= '0') && (str <= '9')) digit = str - '0'; + else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10; + else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10; + else return -1; + + return digit; +} + +/********************************************************************** + * SBMAC_PARSE_HWADDR(str,hwaddr) + * + * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte + * Ethernet address. + * + * Input parameters: + * str - string + * hwaddr - pointer to hardware address + * + * Return value: + * 0 if ok, else -1 + ********************************************************************* */ + +static int sbmac_parse_hwaddr(char *str,u_char *hwaddr) +{ + int digit1,digit2; + int idx = 6; + + while (*str && (idx > 0)) { + digit1 = sbmac_parse_xdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = sbmac_parse_xdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if (*str == '-') str++; + if (*str == ':') str++; + } + return 0; +} +#endif + +/********************************************************************** + * SBMAC_INIT(dev) + * + * Attach routine - init hardware and hook ourselves into linux + * + * Input parameters: + * dev - net_device structure + * + * Return value: + * status + ********************************************************************* */ + +static int sbmac_init(struct net_device *dev) +{ + struct sbmac_softc *sc; + u_char *eaddr; + uint64_t ea_reg; + int idx; + + sc = (struct sbmac_softc *)dev->priv; + + /* Determine controller base address */ + + sc->sbm_base = (sbmac_port_t) dev->base_addr; + sc->sbm_dev = dev; + + eaddr = sc->sbm_hwaddr; + + /* + * Read the ethernet address. The firwmare left this programmed + * for us in the ethernet address register for each mac. + */ + + ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR)); + SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0); + for (idx = 0; idx < 6; idx++) { + eaddr[idx] = (uint8_t) (ea_reg & 0xFF); + ea_reg >>= 8; + } + + + for (idx = 0; idx < 6; idx++) { + dev->dev_addr[idx] = eaddr[idx]; + } + + + /* + * Init packet size + */ + + sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN; + + /* + * Initialize context (get pointers to registers and stuff), then + * allocate the memory for the descriptor tables. + */ + + sbmac_initctx(sc); + + + /* + * Display Ethernet address (this is called during the config process + * so we need to finish off the config message that was being displayed) + */ + printk(KERN_INFO + "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + (unsigned long) sc->sbm_base, + eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); + + /* + * Set up Linux device callins + */ + + spin_lock_init(&(sc->sbm_lock)); + + ether_setup(dev); + dev->open = sbmac_open; + dev->hard_start_xmit = sbmac_start_tx; + dev->stop = sbmac_close; + dev->get_stats = sbmac_get_stats; + dev->set_multicast_list = sbmac_set_rx_mode; + dev->do_ioctl = sbmac_mii_ioctl; + dev->tx_timeout = sbmac_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + return 0; + +} + + +static int sbmac_open(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + MOD_INC_USE_COUNT; + + if (debug > 1) { + printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); + } + + /* + * map/route interrupt + */ + + if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + /* + * Configure default speed + */ + + sbmac_mii_poll(sc,1); + + /* + * Turn on the channel + */ + + sbmac_set_channel_state(sc,sbmac_state_on); + + /* + * XXX Station address is in dev->dev_addr + */ + + if (dev->if_port == 0) + dev->if_port = 0; + + netif_start_queue(dev); + + sbmac_set_rx_mode(dev); + + /* Set the timer to check for link beat. */ + init_timer(&sc->sbm_timer); + sc->sbm_timer.expires = jiffies + 2; + sc->sbm_timer.data = (unsigned long)dev; + sc->sbm_timer.function = &sbmac_timer; + add_timer(&sc->sbm_timer); + + return 0; +} + + + +static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) +{ + int bmsr,bmcr,k1stsr,anlpar; + int chg; + char buffer[100]; + char *p = buffer; + + /* Read the mode status and mode control registers. */ + bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR); + bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR); + + /* get the link partner status */ + anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR); + + /* if supported, read the 1000baseT register */ + if (bmsr & BMSR_1000BT_XSR) { + k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR); + } + else { + k1stsr = 0; + } + + chg = 0; + + if ((bmsr & BMSR_LINKSTAT) == 0) { + /* + * If link status is down, clear out old info so that when + * it comes back up it will force us to reconfigure speed + */ + s->sbm_phy_oldbmsr = 0; + s->sbm_phy_oldanlpar = 0; + s->sbm_phy_oldk1stsr = 0; + return 0; + } + + if ((s->sbm_phy_oldbmsr != bmsr) || + (s->sbm_phy_oldanlpar != anlpar) || + (s->sbm_phy_oldk1stsr != k1stsr)) { + if (debug > 1) { + printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n", + s->sbm_dev->name, + s->sbm_phy_oldbmsr,bmsr, + s->sbm_phy_oldanlpar,anlpar, + s->sbm_phy_oldk1stsr,k1stsr); + } + s->sbm_phy_oldbmsr = bmsr; + s->sbm_phy_oldanlpar = anlpar; + s->sbm_phy_oldk1stsr = k1stsr; + chg = 1; + } + + if (chg == 0) return 0; + + p += sprintf(p,"Link speed: "); + + if (k1stsr & K1STSR_LP1KFD) { + s->sbm_speed = sbmac_speed_1000; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = sbmac_fc_frame; + p += sprintf(p,"1000BaseT FDX"); + } + else if (k1stsr & K1STSR_LP1KHD) { + s->sbm_speed = sbmac_speed_1000; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + p += sprintf(p,"1000BaseT HDX"); + } + else if (anlpar & ANLPAR_TXFD) { + s->sbm_speed = sbmac_speed_100; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled; + p += sprintf(p,"100BaseT FDX"); + } + else if (anlpar & ANLPAR_TXHD) { + s->sbm_speed = sbmac_speed_100; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + p += sprintf(p,"100BaseT HDX"); + } + else if (anlpar & ANLPAR_10FD) { + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = sbmac_fc_frame; + p += sprintf(p,"10BaseT FDX"); + } + else if (anlpar & ANLPAR_10HD) { + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_collision; + p += sprintf(p,"10BaseT HDX"); + } + else { + p += sprintf(p,"Unknown"); + } + + if (noisy) { + printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer); + } + + return 1; +} + + + + +static void sbmac_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + int next_tick = HZ; + int mii_status; + + spin_lock_irq (&sc->sbm_lock); + + /* make IFF_RUNNING follow the MII status bit "Link established" */ + mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); + + if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { + sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; + if (mii_status & BMSR_LINKSTAT) { + netif_carrier_on(dev); + } + else { + netif_carrier_off(dev); + } + } + + /* + * Poll the PHY to see what speed we should be running at + */ + + if (sbmac_mii_poll(sc,1)) { + if (sc->sbm_state != sbmac_state_off) { + /* + * something changed, restart the channel + */ + if (debug > 1) { + printk("%s: restarting channel because speed changed\n", + sc->sbm_dev->name); + } + sbmac_channel_stop(sc); + sbmac_channel_start(sc); + } + } + + spin_unlock_irq (&sc->sbm_lock); + + sc->sbm_timer.expires = jiffies + next_tick; + add_timer(&sc->sbm_timer); +} + + +static void sbmac_tx_timeout (struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + + spin_lock_irq (&sc->sbm_lock); + + + dev->trans_start = jiffies; + sc->sbm_stats.tx_errors++; + + spin_unlock_irq (&sc->sbm_lock); + + printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); +} + + + + +static struct net_device_stats *sbmac_get_stats(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&sc->sbm_lock, flags); + + /* XXX update other stats here */ + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + return &sc->sbm_stats; +} + + + +static void sbmac_set_rx_mode(struct net_device *dev) +{ + unsigned long flags; + int msg_flag = 0; + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + spin_lock_irqsave(&sc->sbm_lock, flags); + if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) { + /* + * Promiscuous changed. + */ + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + msg_flag = 1; + sbmac_promiscuous_mode(sc,1); + } + else { + msg_flag = 2; + sbmac_promiscuous_mode(sc,0); + } + } + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + if (msg_flag) { + printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis"); + } + + /* + * Program the multicasts. Do this every time. + */ + + sbmac_setmulti(sc); + +} + +static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + unsigned long flags; + int retval; + + spin_lock_irqsave(&sc->sbm_lock, flags); + retval = 0; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = sc->sbm_phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f); + break; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) { + retval = -EPERM; + break; + } + if (debug > 1) { + printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name, + data[0],data[1],data[2]); + } + sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]); + break; + default: + retval = -EOPNOTSUPP; + } + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + return retval; +} + +static int sbmac_close(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + unsigned long flags; + + sbmac_set_channel_state(sc,sbmac_state_off); + + del_timer_sync(&sc->sbm_timer); + + spin_lock_irqsave(&sc->sbm_lock, flags); + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name); + } + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + /* Make sure there is no irq-handler running on a different CPU. */ + synchronize_irq(); + + free_irq(dev->irq, dev); + + sbdma_emptyring(&(sc->sbm_txdma)); + sbdma_emptyring(&(sc->sbm_rxdma)); + + MOD_DEC_USE_COUNT; + + return 0; +} + + + +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +static void +sbmac_setup_hwaddr(int chan,char *addr) +{ + uint8_t eaddr[6]; + uint64_t val; + sbmac_port_t port; + + port = A_MAC_CHANNEL_BASE(chan); + sbmac_parse_hwaddr(addr,eaddr); + val = sbmac_addr2reg(eaddr); + SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val); + val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)); +} +#endif + +static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0}; + +static int __init +sbmac_init_module(void) +{ + int idx; + int macidx = 0; + struct net_device *dev; + sbmac_port_t port; + + /* + * For bringup when not using the firmware, we can pre-fill + * the MAC addresses using the environment variables + * specified in this file (or maybe from the config file?) + */ +#ifdef SBMAC_ETH0_HWADDR + sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); +#endif +#ifdef SBMAC_ETH1_HWADDR + sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); +#endif +#ifdef SBMAC_ETH2_HWADDR + sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); +#endif + + /* + * Walk through the Ethernet controllers and find + * those who have their MAC addresses set. + */ + + for (idx = 0; idx < MAX_UNITS; idx++) { + + /* + * This is the base address of the MAC. + */ + + port = A_MAC_CHANNEL_BASE(idx); + + /* + * The R_MAC_ETHERNET_ADDR register will be set to some nonzero + * value for us by the firmware if we're going to use this MAC. + * If we find a zero, skip this MAC. + */ + + if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) { + continue; + } + + /* + * Okay, cool. Initialize this MAC. + */ + + dev = init_etherdev(NULL,sizeof(struct sbmac_softc)); + if (!dev) break; /* problems, get out now. */ + dev->irq = K_INT_MAC_0 + idx; + dev->base_addr = port; + dev->mem_end = 0; + /*dev->init = sbmac_init;*/ + sbmac_init(dev); + + dev_sbmac[macidx] = dev; + macidx++; + + } + + /* + * Should we care, 'macidx' is the total number of enabled MACs. + */ + + return 0; +} + + +static void __exit +sbmac_cleanup_module(void) +{ + int idx; + struct net_device *dev; + for (idx = 0; idx < MAX_UNITS; idx++) { + dev = dev_sbmac[idx]; + if (dev == NULL) continue; + if (dev->priv != NULL) { + struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + + unregister_netdev(dev); + + sbmac_uninitctx(sc); + + KFREE(sc); + } + KFREE(dev); + dev_sbmac[idx] = NULL; + } +} + +module_init(sbmac_init_module); +module_exit(sbmac_cleanup_module); diff -urN linux-2.4.18/drivers/net/sgiseeq.c linux-2.4.19-pre5/drivers/net/sgiseeq.c --- linux-2.4.18/drivers/net/sgiseeq.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sgiseeq.c Sat Mar 30 22:55:28 2002 @@ -1,10 +1,10 @@ -/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $ - * +/* * sgiseeq.c: Seeq8003 ethernet driver for SGI machines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include +#include #include #include #include @@ -451,20 +451,22 @@ unsigned long flags; int err; - save_flags(flags); cli(); - if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { + __save_and_cli(flags); + + err = -EAGAIN; + if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { printk("Seeq8003: Can't get irq %d\n", dev->irq); - restore_flags(flags); - return -EAGAIN; + goto out; } - err = init_seeq(dev, sp, sregs); if (err) - return err; + goto out; netif_start_queue(dev); - restore_flags(flags); - return 0; + +out: + __restore_flags(flags); + return err; } static int sgiseeq_close(struct net_device *dev) @@ -721,3 +723,5 @@ (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), &hpc3c0->ethregs, SGI_ENET_IRQ); } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/sis900.c linux-2.4.19-pre5/drivers/net/sis900.c --- linux-2.4.18/drivers/net/sis900.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sis900.c Sat Mar 30 22:55:34 2002 @@ -18,6 +18,7 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.08.03 Feb. 1 2002 Matt Domsch update to use library crc32 function Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix @@ -60,6 +61,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include @@ -69,7 +71,7 @@ #include "sis900.h" #define SIS900_MODULE_NAME "sis900" -#define SIS900_DRV_VERSION "v1.08.02 11/30/2001" +#define SIS900_DRV_VERSION "v1.08.03 2/1/2002" static char version[] __devinitdata = KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n"; @@ -1981,26 +1983,7 @@ static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision) { -/* what is the correct value of the POLYNOMIAL ?? - Donald Becker use 0x04C11DB7U - Joseph Zbiciak im14u2c@primenet.com gives me the - correct answer, thank you Joe !! */ -#define POLYNOMIAL 0x04C11DB7L - u32 crc = 0xffffffff, msb; - int i, j; - u32 byte; - - for (i = 0; i < 6; i++) { - byte = *addr++; - for (j = 0; j < 8; j++) { - msb = crc >> 31; - crc <<= 1; - if (msb ^ (byte & 1)) { - crc ^= POLYNOMIAL; - } - byte >>= 1; - } - } + u32 crc = ether_crc(6, addr); /* leave 8 or 7 most siginifant bits */ if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV)) diff -urN linux-2.4.18/drivers/net/sk98lin/h/skdrv1st.h linux-2.4.19-pre5/drivers/net/sk98lin/h/skdrv1st.h --- linux-2.4.18/drivers/net/sk98lin/h/skdrv1st.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sk98lin/h/skdrv1st.h Sat Mar 30 22:55:34 2002 @@ -116,6 +116,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.4.18/drivers/net/sk98lin/skaddr.c linux-2.4.19-pre5/drivers/net/sk98lin/skaddr.c --- linux-2.4.18/drivers/net/sk98lin/skaddr.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sk98lin/skaddr.c Sat Mar 30 22:55:34 2002 @@ -199,7 +199,6 @@ /* defines ********************************************************************/ -#define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */ #define HASH_BITS 6 /* #bits in hash */ #define SK_MC_BIT 0x01 @@ -534,18 +533,9 @@ unsigned SkCrc32McHash( unsigned char *pMc) /* Multicast address */ { - unsigned Idx; - unsigned Bit; - unsigned Data; - unsigned Crc; - - Crc = 0xFFFFFFFFUL; - for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) { - Data = *pMc++; - for (Bit = 0; Bit < 8; Bit++, Data >>= 1) { - Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0); - } - } + u32 Crc; + + Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc); return (Crc & ((1 << HASH_BITS) - 1)); } /* SkCrc32McHash */ diff -urN linux-2.4.18/drivers/net/sk98lin/skge.c linux-2.4.19-pre5/drivers/net/sk98lin/skge.c --- linux-2.4.18/drivers/net/sk98lin/skge.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sk98lin/skge.c Sat Mar 30 22:55:40 2002 @@ -541,6 +541,48 @@ boards_found++; + /* More then one port found */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + break; + } + + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + + pProcFile = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + pProcFile->read_proc = proc_read; + pProcFile->write_proc = NULL; + pProcFile->nlink = 1; + pProcFile->size = sizeof(dev->name+1); + pProcFile->data = (void*)pProcFile; + + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); + + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + + } + + /* * This is bollocks, but we need to tell the net-init * code that it shall go for the next device. diff -urN linux-2.4.18/drivers/net/smc-ultra.c linux-2.4.19-pre5/drivers/net/smc-ultra.c --- linux-2.4.18/drivers/net/smc-ultra.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/smc-ultra.c Sat Mar 30 22:55:40 2002 @@ -501,8 +501,10 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); -MODULE_PARM_DESC(io, "SMC Ultra I/O base address(es)"); -MODULE_PARM_DESC(irq, "SMC Ultra IRQ number(s) (assigned)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); +MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver"); +MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS; @@ -557,7 +559,6 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/smc-ultra32.c linux-2.4.19-pre5/drivers/net/smc-ultra32.c --- linux-2.4.18/drivers/net/smc-ultra32.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/smc-ultra32.c Sat Mar 30 22:55:40 2002 @@ -379,6 +379,9 @@ #define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ static struct net_device dev_ultra[MAX_ULTRA32_CARDS]; +MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver"); +MODULE_LICENSE("GPL"); + int init_module(void) { int this_dev, found = 0; @@ -415,5 +418,4 @@ } } #endif /* MODULE */ -MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/smc9194.c linux-2.4.19-pre5/drivers/net/smc9194.c --- linux-2.4.18/drivers/net/smc9194.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/smc9194.c Sat Mar 30 22:55:34 2002 @@ -51,6 +51,7 @@ . allocation . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" + . 11/08/01 Matt Domsch Use common crc32 function ----------------------------------------------------------------------------*/ static const char version[] = @@ -69,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -223,10 +225,6 @@ */ static void smc_set_multicast_list(struct net_device *dev); -/* - . CRC compute - */ -static int crc32( char * s, int length ); /*--------------------------------------------------------------- . @@ -436,7 +434,7 @@ continue; /* only use the low order bits */ - position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; + position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= @@ -450,33 +448,6 @@ outb( multicast_table[i], ioaddr + MULTICAST1 + i ); } } - -/* - Finds the CRC32 of a set of bytes. - Again, from Peter Cammaert's code. -*/ -static int crc32( char * s, int length ) { - /* indices */ - int perByte; - int perBit; - /* crc polynomial for Ethernet */ - const unsigned long poly = 0xedb88320; - /* crc value - preinitialized to all 1's */ - unsigned long crc_value = 0xffffffff; - - for ( perByte = 0; perByte < length; perByte ++ ) { - unsigned char c; - - c = *(s++); - for ( perBit = 0; perBit < 8; perBit++ ) { - crc_value = (crc_value>>1)^ - (((crc_value^c)&0x01)?poly:0); - c >>= 1; - } - } - return crc_value; -} - /* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) diff -urN linux-2.4.18/drivers/net/sonic.c linux-2.4.19-pre5/drivers/net/sonic.c --- linux-2.4.18/drivers/net/sonic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sonic.c Sat Mar 30 22:55:28 2002 @@ -620,3 +620,5 @@ return 0; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/starfire.c linux-2.4.19-pre5/drivers/net/starfire.c --- linux-2.4.18/drivers/net/starfire.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/starfire.c Sat Mar 30 22:55:34 2002 @@ -96,13 +96,19 @@ LK1.3.5 (jgarzik) - ethtool NWAY_RST, GLINK, [GS]MSGLVL support + LK1.3.6: + - Sparc64 support and fixes (Ion Badulescu) + - Better stats and error handling (Ion Badulescu) + - Use new pci_set_mwi() PCI API function (jgarzik) + TODO: - implement tx_timeout() properly + - VLAN support */ #define DRV_NAME "starfire" -#define DRV_VERSION "1.03+LK1.3.5" -#define DRV_RELDATE "November 17, 2001" +#define DRV_VERSION "1.03+LK1.3.6" +#define DRV_RELDATE "March 7, 2002" #include #include @@ -112,6 +118,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -127,8 +134,11 @@ * for this driver to really use the firmware. Note that Rx/Tx * hardware TCP checksumming is not possible without the firmware. * - * I'm currently [Feb 2001] talking to Adaptec about this redistribution - * issue. Stay tuned... + * If Adaptec could allow redistribution of the firmware (even in binary + * format), life would become a lot easier. Unfortunately, I've lost my + * Adaptec contacts, so progress on this front is rather unlikely to + * occur. If anybody from Adaptec reads this and can help with this matter, + * please let me know... */ #undef HAS_FIRMWARE /* @@ -608,7 +618,10 @@ long ioaddr; int drv_flags, io_size; int boguscnt; +#ifndef HAVE_PCI_SET_MWI + u16 cmd; u8 cache; +#endif /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -643,14 +656,25 @@ goto err_out_free_netdev; } - ioaddr = (long) ioremap (ioaddr, io_size); + /* ioremap is borken in Linux-2.2.x/sparc64 */ +#if !defined(CONFIG_SPARC64) || LINUX_VERSION_CODE > 0x20300 + ioaddr = (long) ioremap(ioaddr, io_size); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: cannot remap 0x%x @ 0x%lx, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_res; } +#endif /* !CONFIG_SPARC64 || Linux 2.3.0+ */ - pci_set_master (pdev); + pci_set_master(pdev); + +#ifdef HAVE_PCI_SET_MWI + pci_set_mwi(pdev); +#else + /* enable MWI -- it vastly improves Rx performance on sparc64 */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, cmd); /* set PCI cache size */ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache); @@ -661,6 +685,7 @@ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, SMP_CACHE_BYTES >> 2); } +#endif #ifdef ZEROCOPY /* Starfire can do SG and TCP/UDP checksumming */ @@ -669,7 +694,7 @@ /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i); + dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20 - i); #if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) @@ -931,7 +956,7 @@ /* Fill both the unused Tx SA register and the Rx perfect filter. */ for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); + writeb(dev->dev_addr[i], ioaddr + StationAddr + 5 - i); for (i = 0; i < 16; i++) { u16 *eaddrs = (u16 *)dev->dev_addr; long setup_frm = ioaddr + PerfFilterTable + i * 16; @@ -978,9 +1003,9 @@ #ifdef HAS_FIRMWARE /* Load Rx/Tx firmware into the frame processors */ for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++) - writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4); + writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4); for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++) - writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4); + writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4); /* Enable the Rx and Tx units, and the Rx/Tx frame processors. */ writel(0x003F, ioaddr + GenCtrl); #else /* not HAS_FIRMWARE */ @@ -1155,8 +1180,8 @@ np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping); #ifdef ZEROCOPY - np->tx_ring[entry].first_len = cpu_to_le32(skb_first_frag_len(skb)); - np->tx_ring[entry].total_len = cpu_to_le32(skb->len); + np->tx_ring[entry].first_len = cpu_to_le16(skb_first_frag_len(skb)); + np->tx_ring[entry].total_len = cpu_to_le16(skb->len); /* Add "| TxDescIntr" to generate Tx-done interrupts. */ np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn); np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1); @@ -1169,8 +1194,10 @@ np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); #ifdef ZEROCOPY - if (skb->ip_summed == CHECKSUM_HW) + if (skb->ip_summed == CHECKSUM_HW) { np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP); + np->stats.tx_compressed++; + } #endif /* ZEROCOPY */ if (debug > 5) { @@ -1448,6 +1475,7 @@ #if defined(full_rx_status) || defined(csum_rx_status) if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) { skb->ip_summed = CHECKSUM_UNNECESSARY; + np->stats.rx_compressed++; } /* * This feature doesn't seem to be working, at least @@ -1579,12 +1607,17 @@ printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n", dev->name, np->tx_threshold * 16); } - if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug) + if (intr_status & IntrRxGFPDead) { + np->stats.rx_fifo_errors++; + np->stats.rx_errors++; + } + if (intr_status & (IntrNoTxCsum | IntrDMAErr)) { + np->stats.tx_fifo_errors++; + np->stats.tx_errors++; + } + if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); - /* Hmmmmm, it's not clear how to recover from DMA faults. */ - if (intr_status & IntrDMAErr) - np->stats.tx_fifo_errors++; } @@ -1615,32 +1648,9 @@ } -/* The little-endian AUTODIN II ethernet CRC calculations. - A big-endian version is also available. - This is slow but compact code. Do not use this routine for bulk data, - use a table-based routine instead. - This is common code and should be moved to net/core/crc.c. - Chips may use the upper or lower CRC bits, and may reverse and/or invert +/* Chips may use the upper or lower CRC bits, and may reverse and/or invert them. Select the endian-ness that results in minimal calculations. */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/sun3_82586.c linux-2.4.19-pre5/drivers/net/sun3_82586.c --- linux-2.4.18/drivers/net/sun3_82586.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/sun3_82586.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,1206 @@ +/* + * Sun3 i82586 Ethernet driver + * + * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net) + * + * Original copyright follows: + * -------------------------- + * + * net-3-driver for the NI5210 card (i82586 Ethernet chip) + * + * This is an extension to the Linux operating system, and is covered by the + * same Gnu Public License that covers that work. + * + * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later) + * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de) + * -------------------------- + * + * Consult ni52.c for further notes from the original driver. + * + * This incarnation currently supports the OBIO version of the i82586 chip + * used in certain sun3 models. It should be fairly doable to expand this + * to support VME if I should every acquire such a board. + * + */ + +static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */ +static int automatic_resume = 0; /* experimental .. better should be zero */ +static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */ +static int fifo=0x8; /* don't change */ + +/* #define REALLY_SLOW_IO */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sun3_82586.h" + +#define DEBUG /* debug on */ +#define SYSBUSVAL 0 /* 16 Bit */ + +#define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;} +#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;} +#define sun3_disint() {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;} +#define sun3_enaint() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;} +#define sun3_active() {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);} + +#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) ) +#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base)) +#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop ))) + +/******************* how to calculate the buffers ***************************** + + * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works + * --------------- in a different (more stable?) mode. Only in this mode it's + * possible to configure the driver with 'NO_NOPCOMMANDS' + +sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8; +sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT +sizeof(rfd) = 24; sizeof(rbd) = 12; +sizeof(tbd) = 8; sizeof(transmit_cmd) = 16; +sizeof(nop_cmd) = 8; + + * if you don't know the driver, better do not change these values: */ + +#define RECV_BUFF_SIZE 1536 /* slightly oversized */ +#define XMIT_BUFF_SIZE 1536 /* slightly oversized */ +#define NUM_XMIT_BUFFS 1 /* config for 32K shmem */ +#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */ +#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */ +#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */ +#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */ + +/**************************************************************************/ + +/* different DELAYs */ +#define DELAY(x) mdelay(32 * x); +#define DELAY_16(); { udelay(16); } +#define DELAY_18(); { udelay(4); } + +/* wait for command with timeout: */ +#define WAIT_4_SCB_CMD() \ +{ int i; \ + for(i=0;i<16384;i++) { \ + if(!p->scb->cmd_cuc) break; \ + DELAY_18(); \ + if(i == 16383) { \ + printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \ + if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } } + +#define WAIT_4_SCB_CMD_RUC() { int i; \ + for(i=0;i<16384;i++) { \ + if(!p->scb->cmd_ruc) break; \ + DELAY_18(); \ + if(i == 16383) { \ + printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \ + if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } } + +#define WAIT_4_STAT_COMPL(addr) { int i; \ + for(i=0;i<32767;i++) { \ + if(swab16((addr)->cmd_status) & STAT_COMPL) break; \ + DELAY_16(); DELAY_16(); } } + +static int sun3_82586_probe1(struct net_device *dev,int ioaddr); +static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr); +static int sun3_82586_open(struct net_device *dev); +static int sun3_82586_close(struct net_device *dev); +static int sun3_82586_send_packet(struct sk_buff *,struct net_device *); +static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void sun3_82586_timeout(struct net_device *dev); +#if 0 +static void sun3_82586_dump(struct net_device *,void *); +#endif + +/* helper-functions */ +static int init586(struct net_device *dev); +static int check586(struct net_device *dev,char *where,unsigned size); +static void alloc586(struct net_device *dev); +static void startrecv586(struct net_device *dev); +static void *alloc_rfa(struct net_device *dev,void *ptr); +static void sun3_82586_rcv_int(struct net_device *dev); +static void sun3_82586_xmt_int(struct net_device *dev); +static void sun3_82586_rnr_int(struct net_device *dev); + +struct priv +{ + struct net_device_stats stats; + unsigned long base; + char *memtop; + long int lock; + int reseted; + volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; + volatile struct scp_struct *scp; /* volatile is important */ + volatile struct iscp_struct *iscp; /* volatile is important */ + volatile struct scb_struct *scb; /* volatile is important */ + volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; + volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; +#if (NUM_XMIT_BUFFS == 1) + volatile struct nop_cmd_struct *nop_cmds[2]; +#else + volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; +#endif + volatile int nop_point,num_recv_buffs; + volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; + volatile int xmit_count,xmit_last; +}; + +/********************************************** + * close device + */ +static int sun3_82586_close(struct net_device *dev) +{ + free_irq(dev->irq, dev); + + sun3_reset586(); /* the hard way to stop the receiver */ + + netif_stop_queue(dev); + + return 0; +} + +/********************************************** + * open device + */ +static int sun3_82586_open(struct net_device *dev) +{ + int ret; + + sun3_disint(); + alloc586(dev); + init586(dev); + startrecv586(dev); + sun3_enaint(); + + ret = request_irq(dev->irq, &sun3_82586_interrupt,0,dev->name,dev); + if (ret) + { + sun3_reset586(); + return ret; + } + + netif_start_queue(dev); + + return 0; /* most done by init */ +} + +/********************************************** + * Check to see if there's an 82586 out there. + */ +static int check586(struct net_device *dev,char *where,unsigned size) +{ + struct priv pb; + struct priv *p = /* (struct priv *) dev->priv*/ &pb; + char *iscp_addr; + int i; + + p->base = (unsigned long) dvma_btov(0); + p->memtop = (char *)dvma_btov((unsigned long)where); + p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS); + memset((char *)p->scp,0, sizeof(struct scp_struct)); + for(i=0;iscp)[i]) + return 0; + p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ + if(p->scp->sysbus != SYSBUSVAL) + return 0; + + iscp_addr = (char *)dvma_btov((unsigned long)where); + + p->iscp = (struct iscp_struct *) iscp_addr; + memset((char *)p->iscp,0, sizeof(struct iscp_struct)); + + p->scp->iscp = make24(p->iscp); + p->iscp->busy = 1; + + sun3_reset586(); + sun3_attn586(); + DELAY(1); /* wait a while... */ + + if(p->iscp->busy) /* i82586 clears 'busy' after successful init */ + return 0; + + return 1; +} + +/****************************************************************** + * set iscp at the right place, called by sun3_82586_probe1 and open586. + */ +static void alloc586(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + + sun3_reset586(); + DELAY(1); + + p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); + p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start); + p->scb = (struct scb_struct *) ((char *)p->iscp + sizeof(struct iscp_struct)); + + memset((char *) p->iscp,0,sizeof(struct iscp_struct)); + memset((char *) p->scp ,0,sizeof(struct scp_struct)); + + p->scp->iscp = make24(p->iscp); + p->scp->sysbus = SYSBUSVAL; + p->iscp->scb_offset = make16(p->scb); + p->iscp->scb_base = make24(dvma_btov(dev->mem_start)); + + p->iscp->busy = 1; + sun3_reset586(); + sun3_attn586(); + + DELAY(1); + + if(p->iscp->busy) + printk("%s: Init-Problems (alloc).\n",dev->name); + + p->reseted = 0; + + memset((char *)p->scb,0,sizeof(struct scb_struct)); +} + +int __init sun3_82586_probe(struct net_device *dev) +{ + unsigned long ioaddr, iopte; + static int found = 0; + + /* check that this machine has an onboard lance */ + switch(idprom->id_machtype) { + case SM_SUN3|SM_3_160: + case SM_SUN3|SM_3_260: + /* these machines have lance */ + break; + + default: + return(-ENODEV); + } + + if(found) + return -ENODEV; + + for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + + SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) { + + iopte = sun3_get_pte(ioaddr); + if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ + continue; + + if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == + IE_OBIO) { + found = 1; + break; + } + } + + if(!found) + return 0; + + SET_MODULE_OWNER(dev); + + dev->irq = IE_IRQ; + dev->base_addr = ioaddr; + if(sun3_82586_probe1(dev, ioaddr) == 0) + return 0; + + return -ENODEV; +} + +static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) +{ + int i, size, retval; + +// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) +// return -EBUSY; + + /* copy in the ethernet address from the prom */ + for(i = 0; i < 6 ; i++) + dev->dev_addr[i] = idprom->id_ethaddr[i]; + + printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr); + + /* + * check (or search) IO-Memory, 32K + */ + size = 0x8000; + + dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000); + dev->mem_end = dev->mem_start + size; + + if(size != 0x2000 && size != 0x4000 && size != 0x8000) { + printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size); + retval = -ENODEV; + goto out; + } + if(!check586(dev,(char *) dev->mem_start,size)) { + printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size); + retval = -ENODEV; + goto out; + } + + dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); + if(dev->priv == NULL) { + printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); + retval = -ENOMEM; + goto out; + } + + /* warning: we don't free it on errors */ + memset((char *) dev->priv,0,sizeof(struct priv)); + + ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); + ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); + alloc586(dev); + + /* set number of receive-buffs according to memsize */ + if(size == 0x2000) + ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; + else if(size == 0x4000) + ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; + else + ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32; + + printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq); + + dev->open = sun3_82586_open; + dev->stop = sun3_82586_close; + dev->get_stats = sun3_82586_get_stats; + dev->tx_timeout = sun3_82586_timeout; + dev->watchdog_timeo = HZ/20; + dev->hard_start_xmit = sun3_82586_send_packet; + dev->set_multicast_list = set_multicast_list; + + dev->if_port = 0; + + ether_setup(dev); + + return 0; +out: + return retval; +} + + +static int init586(struct net_device *dev) +{ + void *ptr; + int i,result=0; + struct priv *p = (struct priv *) dev->priv; + volatile struct configure_cmd_struct *cfg_cmd; + volatile struct iasetup_cmd_struct *ias_cmd; + volatile struct tdr_cmd_struct *tdr_cmd; + volatile struct mcsetup_cmd_struct *mc_cmd; + struct dev_mc_list *dmi=dev->mc_list; + int num_addrs=dev->mc_count; + + ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); + + cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */ + cfg_cmd->cmd_status = 0; + cfg_cmd->cmd_cmd = swab16(CMD_CONFIGURE | CMD_LAST); + cfg_cmd->cmd_link = 0xffff; + + cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ + cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */ + cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ + cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ + cfg_cmd->priority = 0x00; + cfg_cmd->ifs = 0x60; + cfg_cmd->time_low = 0x00; + cfg_cmd->time_high = 0xf2; + cfg_cmd->promisc = 0; + if(dev->flags & IFF_ALLMULTI) { + int len = ((char *) p->iscp - (char *) ptr - 8) / 6; + if(num_addrs > len) { + printk("%s: switching to promisc. mode\n",dev->name); + dev->flags|=IFF_PROMISC; + } + } + if(dev->flags&IFF_PROMISC) + { + cfg_cmd->promisc=1; + dev->flags|=IFF_PROMISC; + } + cfg_cmd->carr_coll = 0x00; + + p->scb->cbl_offset = make16(cfg_cmd); + p->scb->cmd_ruc = 0; + + p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + sun3_attn586(); + + WAIT_4_STAT_COMPL(cfg_cmd); + + if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK)) + { + printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status)); + return 1; + } + + /* + * individual address setup + */ + + ias_cmd = (struct iasetup_cmd_struct *)ptr; + + ias_cmd->cmd_status = 0; + ias_cmd->cmd_cmd = swab16(CMD_IASETUP | CMD_LAST); + ias_cmd->cmd_link = 0xffff; + + memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN); + + p->scb->cbl_offset = make16(ias_cmd); + + p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + sun3_attn586(); + + WAIT_4_STAT_COMPL(ias_cmd); + + if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) { + printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status)); + return 1; + } + + /* + * TDR, wire check .. e.g. no resistor e.t.c + */ + + tdr_cmd = (struct tdr_cmd_struct *)ptr; + + tdr_cmd->cmd_status = 0; + tdr_cmd->cmd_cmd = swab16(CMD_TDR | CMD_LAST); + tdr_cmd->cmd_link = 0xffff; + tdr_cmd->status = 0; + + p->scb->cbl_offset = make16(tdr_cmd); + p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + sun3_attn586(); + + WAIT_4_STAT_COMPL(tdr_cmd); + + if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL)) + { + printk("%s: Problems while running the TDR.\n",dev->name); + } + else + { + DELAY_16(); /* wait for result */ + result = swab16(tdr_cmd->status); + + p->scb->cmd_cuc = p->scb->cus & STAT_MASK; + sun3_attn586(); /* ack the interrupts */ + + if(result & TDR_LNK_OK) + ; + else if(result & TDR_XCVR_PRB) + printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name); + else if(result & TDR_ET_OPN) + printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK); + else if(result & TDR_ET_SRT) + { + if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ + printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK); + } + else + printk("%s: TDR: Unknown status %04x\n",dev->name,result); + } + + /* + * Multicast setup + */ + if(num_addrs && !(dev->flags & IFF_PROMISC) ) + { + mc_cmd = (struct mcsetup_cmd_struct *) ptr; + mc_cmd->cmd_status = 0; + mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST); + mc_cmd->cmd_link = 0xffff; + mc_cmd->mc_cnt = swab16(num_addrs * 6); + + for(i=0;inext) + memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6); + + p->scb->cbl_offset = make16(mc_cmd); + p->scb->cmd_cuc = CUC_START; + sun3_attn586(); + + WAIT_4_STAT_COMPL(mc_cmd); + + if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) ) + printk("%s: Can't apply multicast-address-list.\n",dev->name); + } + + /* + * alloc nop/xmit-cmds + */ +#if (NUM_XMIT_BUFFS == 1) + for(i=0;i<2;i++) + { + p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; + p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP); + p->nop_cmds[i]->cmd_status = 0; + p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); + ptr = (char *) ptr + sizeof(struct nop_cmd_struct); + } +#else + for(i=0;inop_cmds[i] = (struct nop_cmd_struct *)ptr; + p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP); + p->nop_cmds[i]->cmd_status = 0; + p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); + ptr = (char *) ptr + sizeof(struct nop_cmd_struct); + } +#endif + + ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ + + /* + * alloc xmit-buffs / init xmit_cmds + */ + for(i=0;ixmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/ + ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); + p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */ + ptr = (char *) ptr + XMIT_BUFF_SIZE; + p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */ + ptr = (char *) ptr + sizeof(struct tbd_struct); + if((void *)ptr > (void *)dev->mem_end) + { + printk("%s: not enough shared-mem for your configuration!\n",dev->name); + return 1; + } + memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct)); + memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct)); + p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]); + p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL); + p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT); + p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i])); + p->xmit_buffs[i]->next = 0xffff; + p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i])); + } + + p->xmit_count = 0; + p->xmit_last = 0; +#ifndef NO_NOPCOMMANDS + p->nop_point = 0; +#endif + + /* + * 'start transmitter' + */ +#ifndef NO_NOPCOMMANDS + p->scb->cbl_offset = make16(p->nop_cmds[0]); + p->scb->cmd_cuc = CUC_START; + sun3_attn586(); + WAIT_4_SCB_CMD(); +#else + p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]); + p->xmit_cmds[0]->cmd_cmd = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT); +#endif + + /* + * ack. interrupts + */ + p->scb->cmd_cuc = p->scb->cus & STAT_MASK; + sun3_attn586(); + DELAY_16(); + + sun3_enaint(); + sun3_active(); + + return 0; +} + +/****************************************************** + * This is a helper routine for sun3_82586_rnr_int() and init586(). + * It sets up the Receive Frame Area (RFA). + */ + +static void *alloc_rfa(struct net_device *dev,void *ptr) +{ + volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr; + volatile struct rbd_struct *rbd; + int i; + struct priv *p = (struct priv *) dev->priv; + + memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd)); + p->rfd_first = rfd; + + for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) { + rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) ); + rfd[i].rbd_offset = 0xffff; + } + rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */ + + ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) ); + + rbd = (struct rbd_struct *) ptr; + ptr = (void *) (rbd + p->num_recv_buffs); + + /* clr descriptors */ + memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs)); + + for(i=0;inum_recv_buffs;i++) + { + rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs)); + rbd[i].size = swab16(RECV_BUFF_SIZE); + rbd[i].buffer = make24(ptr); + ptr = (char *) ptr + RECV_BUFF_SIZE; + } + + p->rfd_top = p->rfd_first; + p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd); + + p->scb->rfa_offset = make16(p->rfd_first); + p->rfd_first->rbd_offset = make16(rbd); + + return ptr; +} + + +/************************************************** + * Interrupt Handler ... + */ + +static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr) +{ + struct net_device *dev = dev_id; + unsigned short stat; + int cnt=0; + struct priv *p; + + if (!dev) { + printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq); + return; + } + p = (struct priv *) dev->priv; + + if(debuglevel > 1) + printk("I"); + + WAIT_4_SCB_CMD(); /* wait for last command */ + + while((stat=p->scb->cus & STAT_MASK)) + { + p->scb->cmd_cuc = stat; + sun3_attn586(); + + if(stat & STAT_FR) /* received a frame */ + sun3_82586_rcv_int(dev); + + if(stat & STAT_RNR) /* RU went 'not ready' */ + { + printk("(R)"); + if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */ + { + WAIT_4_SCB_CMD(); + p->scb->cmd_ruc = RUC_RESUME; + sun3_attn586(); + WAIT_4_SCB_CMD_RUC(); + } + else + { + printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus); + sun3_82586_rnr_int(dev); + } + } + + if(stat & STAT_CX) /* command with I-bit set complete */ + sun3_82586_xmt_int(dev); + +#ifndef NO_NOPCOMMANDS + if(stat & STAT_CNA) /* CU went 'not ready' */ + { + if(netif_running(dev)) + printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus); + } +#endif + + if(debuglevel > 1) + printk("%d",cnt++); + + WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */ + if(p->scb->cmd_cuc) /* timed out? */ + { + printk("%s: Acknowledge timed out.\n",dev->name); + sun3_disint(); + break; + } + } + + if(debuglevel > 1) + printk("i"); +} + +/******************************************************* + * receive-interrupt + */ + +static void sun3_82586_rcv_int(struct net_device *dev) +{ + int status,cnt=0; + unsigned short totlen; + struct sk_buff *skb; + struct rbd_struct *rbd; + struct priv *p = (struct priv *) dev->priv; + + if(debuglevel > 0) + printk("R"); + + for(;(status = p->rfd_top->stat_high) & RFD_COMPL;) + { + rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); + + if(status & RFD_OK) /* frame received without error? */ + { + if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */ + { + totlen &= RBD_MASK; /* length of this frame */ + rbd->status = 0; + skb = (struct sk_buff *) dev_alloc_skb(totlen+2); + if(skb != NULL) + { + skb->dev = dev; + skb_reserve(skb,2); + skb_put(skb,totlen); + eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + p->stats.rx_packets++; + } + else + p->stats.rx_dropped++; + } + else + { + int rstat; + /* free all RBD's until RBD_LAST is set */ + totlen = 0; + while(!((rstat=swab16(rbd->status)) & RBD_LAST)) + { + totlen += rstat & RBD_MASK; + if(!rstat) + { + printk("%s: Whoops .. no end mark in RBD list\n",dev->name); + break; + } + rbd->status = 0; + rbd = (struct rbd_struct *) make32(rbd->next); + } + totlen += rstat & RBD_MASK; + rbd->status = 0; + printk("%s: received oversized frame! length: %d\n",dev->name,totlen); + p->stats.rx_dropped++; + } + } + else /* frame !(ok), only with 'save-bad-frames' */ + { + printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); + p->stats.rx_errors++; + } + p->rfd_top->stat_high = 0; + p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */ + p->rfd_top->rbd_offset = 0xffff; + p->rfd_last->last = 0; /* delete RFD_SUSP */ + p->rfd_last = p->rfd_top; + p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ + p->scb->rfa_offset = make16(p->rfd_top); + + if(debuglevel > 0) + printk("%d",cnt++); + } + + if(automatic_resume) + { + WAIT_4_SCB_CMD(); + p->scb->cmd_ruc = RUC_RESUME; + sun3_attn586(); + WAIT_4_SCB_CMD_RUC(); + } + +#ifdef WAIT_4_BUSY + { + int i; + for(i=0;i<1024;i++) + { + if(p->rfd_top->status) + break; + DELAY_16(); + if(i == 1023) + printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name); + } + } +#endif + +#if 0 + if(!at_least_one) + { + int i; + volatile struct rfd_struct *rfds=p->rfd_top; + volatile struct rbd_struct *rbds; + printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least); + for(i=0;i< (p->num_recv_buffs+4);i++) + { + rbds = (struct rbd_struct *) make32(rfds->rbd_offset); + printk("%04x:%04x ",rfds->status,rbds->status); + rfds = (struct rfd_struct *) make32(rfds->next); + } + printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status); + printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus); + } + old_at_least = at_least_one; +#endif + + if(debuglevel > 0) + printk("r"); +} + +/********************************************************** + * handle 'Receiver went not ready'. + */ + +static void sun3_82586_rnr_int(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + + p->stats.rx_errors++; + + WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */ + p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ + sun3_attn586(); + WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */ + + alloc_rfa(dev,(char *)p->rfd_first); +/* maybe add a check here, before restarting the RU */ + startrecv586(dev); /* restart RU */ + + printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus); + +} + +/********************************************************** + * handle xmit - interrupt + */ + +static void sun3_82586_xmt_int(struct net_device *dev) +{ + int status; + struct priv *p = (struct priv *) dev->priv; + + if(debuglevel > 0) + printk("X"); + + status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status); + if(!(status & STAT_COMPL)) + printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name); + + if(status & STAT_OK) + { + p->stats.tx_packets++; + p->stats.collisions += (status & TCMD_MAXCOLLMASK); + } + else + { + p->stats.tx_errors++; + if(status & TCMD_LATECOLL) { + printk("%s: late collision detected.\n",dev->name); + p->stats.collisions++; + } + else if(status & TCMD_NOCARRIER) { + p->stats.tx_carrier_errors++; + printk("%s: no carrier detected.\n",dev->name); + } + else if(status & TCMD_LOSTCTS) + printk("%s: loss of CTS detected.\n",dev->name); + else if(status & TCMD_UNDERRUN) { + p->stats.tx_fifo_errors++; + printk("%s: DMA underrun detected.\n",dev->name); + } + else if(status & TCMD_MAXCOLL) { + printk("%s: Max. collisions exceeded.\n",dev->name); + p->stats.collisions += 16; + } + } + +#if (NUM_XMIT_BUFFS > 1) + if( (++p->xmit_last) == NUM_XMIT_BUFFS) + p->xmit_last = 0; +#endif + netif_wake_queue(dev); +} + +/*********************************************************** + * (re)start the receiver + */ + +static void startrecv586(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + + WAIT_4_SCB_CMD(); + WAIT_4_SCB_CMD_RUC(); + p->scb->rfa_offset = make16(p->rfd_first); + p->scb->cmd_ruc = RUC_START; + sun3_attn586(); /* start cmd. */ + WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */ +} + +static void sun3_82586_timeout(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; +#ifndef NO_NOPCOMMANDS + if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */ + { + netif_wake_queue(dev); +#ifdef DEBUG + printk("%s: strange ... timeout with CU active?!?\n",dev->name); + printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point); +#endif + p->scb->cmd_cuc = CUC_ABORT; + sun3_attn586(); + WAIT_4_SCB_CMD(); + p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); + p->scb->cmd_cuc = CUC_START; + sun3_attn586(); + WAIT_4_SCB_CMD(); + dev->trans_start = jiffies; + return 0; + } +#endif + { +#ifdef DEBUG + printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus); + printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status)); + printk("%s: check, whether you set the right interrupt number!\n",dev->name); +#endif + sun3_82586_close(dev); + sun3_82586_open(dev); + } + dev->trans_start = jiffies; +} + +/****************************************************** + * send frame + */ + +static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + int len,i; +#ifndef NO_NOPCOMMANDS + int next_nop; +#endif + struct priv *p = (struct priv *) dev->priv; + + if(skb->len > XMIT_BUFF_SIZE) + { + printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); + return 0; + } + + netif_stop_queue(dev); + +#if(NUM_XMIT_BUFFS > 1) + if(test_and_set_bit(0,(void *) &p->lock)) { + printk("%s: Queue was locked\n",dev->name); + return 1; + } + else +#endif + { + memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + +#if (NUM_XMIT_BUFFS == 1) +# ifdef NO_NOPCOMMANDS + +#ifdef DEBUG + if(p->scb->cus & CU_ACTIVE) + { + printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name); + printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status)); + } +#endif + + p->xmit_buffs[0]->size = swab16(TBD_LAST | len); + for(i=0;i<16;i++) + { + p->xmit_cmds[0]->cmd_status = 0; + WAIT_4_SCB_CMD(); + if( (p->scb->cus & CU_STATUS) == CU_SUSPEND) + p->scb->cmd_cuc = CUC_RESUME; + else + { + p->scb->cbl_offset = make16(p->xmit_cmds[0]); + p->scb->cmd_cuc = CUC_START; + } + + sun3_attn586(); + dev->trans_start = jiffies; + if(!i) + dev_kfree_skb(skb); + WAIT_4_SCB_CMD(); + if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ + break; + if(p->xmit_cmds[0]->cmd_status) + break; + if(i==15) + printk("%s: Can't start transmit-command.\n",dev->name); + } +# else + next_nop = (p->nop_point + 1) & 0x1; + p->xmit_buffs[0]->size = swab16(TBD_LAST | len); + + p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link + = make16((p->nop_cmds[next_nop])); + p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; + + p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); + dev->trans_start = jiffies; + p->nop_point = next_nop; + dev_kfree_skb(skb); +# endif +#else + p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len); + if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS ) + next_nop = 0; + + p->xmit_cmds[p->xmit_count]->cmd_status = 0; + /* linkpointer of xmit-command already points to next nop cmd */ + p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); + p->nop_cmds[next_nop]->cmd_status = 0; + + p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); + dev->trans_start = jiffies; + p->xmit_count = next_nop; + + { + unsigned long flags; + save_flags(flags); + cli(); + if(p->xmit_count != p->xmit_last) + netif_wake_queue(dev); + p->lock = 0; + restore_flags(flags); + } + dev_kfree_skb(skb); +#endif + } + return 0; +} + +/******************************************* + * Someone wanna have the statistics + */ + +static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + unsigned short crc,aln,rsc,ovrn; + + crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */ + p->scb->crc_errs = 0; + aln = swab16(p->scb->aln_errs); + p->scb->aln_errs = 0; + rsc = swab16(p->scb->rsc_errs); + p->scb->rsc_errs = 0; + ovrn = swab16(p->scb->ovrn_errs); + p->scb->ovrn_errs = 0; + + p->stats.rx_crc_errors += crc; + p->stats.rx_fifo_errors += ovrn; + p->stats.rx_frame_errors += aln; + p->stats.rx_dropped += rsc; + + return &p->stats; +} + +/******************************************************** + * Set MC list .. + */ + +static void set_multicast_list(struct net_device *dev) +{ + netif_stop_queue(dev); + sun3_disint(); + alloc586(dev); + init586(dev); + startrecv586(dev); + sun3_enaint(); + netif_wake_queue(dev); +} + +#ifdef MODULE +#error This code is not currently supported as a module +static struct net_device dev_sun3_82586; + +int init_module(void) +{ + dev_sun3_82586.init = sun3_82586_probe; + if (register_netdev(&dev_sun3_82586) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_sun3_82586); + kfree(dev_sun3_82586.priv); + dev_sun3_82586.priv = NULL; +} +#endif /* MODULE */ + +#if 0 +/* + * DUMP .. we expect a not running CMD unit and enough space + */ +void sun3_82586_dump(struct net_device *dev,void *ptr) +{ + struct priv *p = (struct priv *) dev->priv; + struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr; + int i; + + p->scb->cmd_cuc = CUC_ABORT; + sun3_attn586(); + WAIT_4_SCB_CMD(); + WAIT_4_SCB_CMD_RUC(); + + dump_cmd->cmd_status = 0; + dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST; + dump_cmd->dump_offset = make16((dump_cmd + 1)); + dump_cmd->cmd_link = 0xffff; + + p->scb->cbl_offset = make16(dump_cmd); + p->scb->cmd_cuc = CUC_START; + sun3_attn586(); + WAIT_4_STAT_COMPL(dump_cmd); + + if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) ) + printk("%s: Can't get dump information.\n",dev->name); + + for(i=0;i<170;i++) { + printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]); + if(i % 24 == 23) + printk("\n"); + } + printk("\n"); +} +#endif + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/net/sun3_82586.h linux-2.4.19-pre5/drivers/net/sun3_82586.h --- linux-2.4.18/drivers/net/sun3_82586.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/sun3_82586.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,318 @@ +/* + * Intel i82586 Ethernet definitions + * + * This is an extension to the Linux operating system, and is covered by the + * same Gnu Public License that covers that work. + * + * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de) + * + * I have done a look in the following sources: + * crynwr-packet-driver by Russ Nelson + * Garret A. Wollman's i82586-driver for BSD + */ + +/* + * Cloned from ni52.h, copyright as above. + * + * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net) + */ + + +/* defines for the obio chip (not vme) */ +#define IEOB_NORSET 0x80 /* don't reset the board */ +#define IEOB_ONAIR 0x40 /* put us on the air */ +#define IEOB_ATTEN 0x20 /* attention! */ +#define IEOB_IENAB 0x10 /* interrupt enable */ +#define IEOB_XXXXX 0x08 /* free bit */ +#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */ +#define IEOB_BUSERR 0x02 /* bus error */ +#define IEOB_INT 0x01 /* interrupt */ + +/* where the obio one lives */ +#define IE_OBIO 0xc0000 +#define IE_IRQ 3 + +/* + * where to find the System Configuration Pointer (SCP) + */ +#define SCP_DEFAULT_ADDRESS 0xfffff4 + + +/* + * System Configuration Pointer Struct + */ + +struct scp_struct +{ + unsigned short zero_dum0; /* has to be zero */ + unsigned char sysbus; /* 0=16Bit,1=8Bit */ + unsigned char zero_dum1; /* has to be zero for 586 */ + unsigned short zero_dum2; + unsigned short zero_dum3; + char *iscp; /* pointer to the iscp-block */ +}; + + +/* + * Intermediate System Configuration Pointer (ISCP) + */ +struct iscp_struct +{ + unsigned char busy; /* 586 clears after successful init */ + unsigned char zero_dummy; /* has to be zero */ + unsigned short scb_offset; /* pointeroffset to the scb_base */ + char *scb_base; /* base-address of all 16-bit offsets */ +}; + +/* + * System Control Block (SCB) + */ +struct scb_struct +{ + unsigned char rus; + unsigned char cus; + unsigned char cmd_ruc; /* command word: RU part */ + unsigned char cmd_cuc; /* command word: CU part & ACK */ + unsigned short cbl_offset; /* pointeroffset, command block list */ + unsigned short rfa_offset; /* pointeroffset, receive frame area */ + unsigned short crc_errs; /* CRC-Error counter */ + unsigned short aln_errs; /* allignmenterror counter */ + unsigned short rsc_errs; /* Resourceerror counter */ + unsigned short ovrn_errs; /* OVerrunerror counter */ +}; + +/* + * possible command values for the command word + */ +#define RUC_MASK 0x0070 /* mask for RU commands */ +#define RUC_NOP 0x0000 /* NOP-command */ +#define RUC_START 0x0010 /* start RU */ +#define RUC_RESUME 0x0020 /* resume RU after suspend */ +#define RUC_SUSPEND 0x0030 /* suspend RU */ +#define RUC_ABORT 0x0040 /* abort receiver operation immediately */ + +#define CUC_MASK 0x07 /* mask for CU command */ +#define CUC_NOP 0x00 /* NOP-command */ +#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */ +#define CUC_RESUME 0x02 /* resume after suspend */ +#define CUC_SUSPEND 0x03 /* Suspend CU */ +#define CUC_ABORT 0x04 /* abort command operation immediately */ + +#define ACK_MASK 0xf0 /* mask for ACK command */ +#define ACK_CX 0x80 /* acknowledges STAT_CX */ +#define ACK_FR 0x40 /* ack. STAT_FR */ +#define ACK_CNA 0x20 /* ack. STAT_CNA */ +#define ACK_RNR 0x10 /* ack. STAT_RNR */ + +/* + * possible status values for the status word + */ +#define STAT_MASK 0xf0 /* mask for cause of interrupt */ +#define STAT_CX 0x80 /* CU finished cmd with its I bit set */ +#define STAT_FR 0x40 /* RU finished receiving a frame */ +#define STAT_CNA 0x20 /* CU left active state */ +#define STAT_RNR 0x10 /* RU left ready state */ + +#define CU_STATUS 0x7 /* CU status, 0=idle */ +#define CU_SUSPEND 0x1 /* CU is suspended */ +#define CU_ACTIVE 0x2 /* CU is active */ + +#define RU_STATUS 0x70 /* RU status, 0=idle */ +#define RU_SUSPEND 0x10 /* RU suspended */ +#define RU_NOSPACE 0x20 /* RU no resources */ +#define RU_READY 0x40 /* RU is ready */ + +/* + * Receive Frame Descriptor (RFD) + */ +struct rfd_struct +{ + unsigned char stat_low; /* status word */ + unsigned char stat_high; /* status word */ + unsigned char rfd_sf; /* 82596 mode only */ + unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */ + unsigned short next; /* linkoffset to next RFD */ + unsigned short rbd_offset; /* pointeroffset to RBD-buffer */ + unsigned char dest[6]; /* ethernet-address, destination */ + unsigned char source[6]; /* ethernet-address, source */ + unsigned short length; /* 802.3 frame-length */ + unsigned short zero_dummy; /* dummy */ +}; + +#define RFD_LAST 0x80 /* last: last rfd in the list */ +#define RFD_SUSP 0x40 /* last: suspend RU after */ +#define RFD_COMPL 0x80 +#define RFD_OK 0x20 +#define RFD_BUSY 0x40 +#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */ +#define RFD_ERR_CRC 0x08 /* CRC error */ +#define RFD_ERR_ALGN 0x04 /* Alignment error */ +#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */ +#define RFD_ERR_OVR 0x01 /* DMA Overrun! */ + +#define RFD_ERR_FTS 0x0080 /* Frame to short */ +#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */ +#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */ +#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */ +#define RFD_COLLDET 0x0001 /* Detected collision during reception */ + +/* + * Receive Buffer Descriptor (RBD) + */ +struct rbd_struct +{ + unsigned short status; /* status word,number of used bytes in buff */ + unsigned short next; /* pointeroffset to next RBD */ + char *buffer; /* receive buffer address pointer */ + unsigned short size; /* size of this buffer */ + unsigned short zero_dummy; /* dummy */ +}; + +#define RBD_LAST 0x8000 /* last buffer */ +#define RBD_USED 0x4000 /* this buffer has data */ +#define RBD_MASK 0x3fff /* size-mask for length */ + +/* + * Statusvalues for Commands/RFD + */ +#define STAT_COMPL 0x8000 /* status: frame/command is complete */ +#define STAT_BUSY 0x4000 /* status: frame/command is busy */ +#define STAT_OK 0x2000 /* status: frame/command is ok */ + +/* + * Action-Commands + */ +#define CMD_NOP 0x0000 /* NOP */ +#define CMD_IASETUP 0x0001 /* initial address setup command */ +#define CMD_CONFIGURE 0x0002 /* configure command */ +#define CMD_MCSETUP 0x0003 /* MC setup command */ +#define CMD_XMIT 0x0004 /* transmit command */ +#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */ +#define CMD_DUMP 0x0006 /* dump command */ +#define CMD_DIAGNOSE 0x0007 /* diagnose command */ + +/* + * Action command bits + */ +#define CMD_LAST 0x8000 /* indicates last command in the CBL */ +#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */ +#define CMD_INT 0x2000 /* generate interrupt after execution */ + +/* + * NOP - command + */ +struct nop_cmd_struct +{ + unsigned short cmd_status; /* status of this command */ + unsigned short cmd_cmd; /* the command itself (+bits) */ + unsigned short cmd_link; /* offsetpointer to next command */ +}; + +/* + * IA Setup command + */ +struct iasetup_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned char iaddr[6]; +}; + +/* + * Configure command + */ +struct configure_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned char byte_cnt; /* size of the config-cmd */ + unsigned char fifo; /* fifo/recv monitor */ + unsigned char sav_bf; /* save bad frames (bit7=1)*/ + unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/ + unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */ + unsigned char ifs; /* inter frame spacing */ + unsigned char time_low; /* slot time low */ + unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */ + unsigned char promisc; /* promisc-mode(0) , et al (1-7) */ + unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */ + unsigned char fram_len; /* minimal frame len */ + unsigned char dummy; /* dummy */ +}; + +/* + * Multicast Setup command + */ +struct mcsetup_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned short mc_cnt; /* number of bytes in the MC-List */ + unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */ +}; + +/* + * DUMP command + */ +struct dump_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned short dump_offset; /* pointeroffset to DUMP space */ +}; + +/* + * transmit command + */ +struct transmit_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned short tbd_offset; /* pointeroffset to TBD */ + unsigned char dest[6]; /* destination address of the frame */ + unsigned short length; /* user defined: 802.3 length / Ether type */ +}; + +#define TCMD_ERRMASK 0x0fa0 +#define TCMD_MAXCOLLMASK 0x000f +#define TCMD_MAXCOLL 0x0020 +#define TCMD_HEARTBEAT 0x0040 +#define TCMD_DEFERRED 0x0080 +#define TCMD_UNDERRUN 0x0100 +#define TCMD_LOSTCTS 0x0200 +#define TCMD_NOCARRIER 0x0400 +#define TCMD_LATECOLL 0x0800 + +struct tdr_cmd_struct +{ + unsigned short cmd_status; + unsigned short cmd_cmd; + unsigned short cmd_link; + unsigned short status; +}; + +#define TDR_LNK_OK 0x8000 /* No link problem identified */ +#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */ +#define TDR_ET_OPN 0x2000 /* open, no correct termination */ +#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */ +#define TDR_TIMEMASK 0x07ff /* mask for the time field */ + +/* + * Transmit Buffer Descriptor (TBD) + */ +struct tbd_struct +{ + unsigned short size; /* size + EOF-Flag(15) */ + unsigned short next; /* pointeroffset to next TBD */ + char *buffer; /* pointer to buffer */ +}; + +#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */ + + + + diff -urN linux-2.4.18/drivers/net/sun3lance.c linux-2.4.19-pre5/drivers/net/sun3lance.c --- linux-2.4.18/drivers/net/sun3lance.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sun3lance.c Sat Mar 30 22:55:35 2002 @@ -21,7 +21,7 @@ */ -static char *version = "sun3lance.c: v1.1 11/17/1999 Sam Creasey (sammy@oh.verio.com)\n"; +static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.net)\n"; #include @@ -35,16 +35,24 @@ #include #include #include +#include #include #include #include #include -#include #include -#include +#include #include +#include +#include + +#ifdef CONFIG_SUN3 +#include +#else +#include +#endif #include #include @@ -62,7 +70,7 @@ * 3 = debug, print even more debug infos (packet data) */ -#define LANCE_DEBUG 1 +#define LANCE_DEBUG 0 #ifdef LANCE_DEBUG static int lance_debug = LANCE_DEBUG; @@ -139,7 +147,7 @@ struct lance_tx_head tx_head[TX_RING_SIZE]; struct lance_rx_head rx_head[RX_RING_SIZE]; char rx_data[RX_RING_SIZE][PKT_BUF_SZ]; - char tx_data[RX_RING_SIZE][PKT_BUF_SZ]; + char tx_data[TX_RING_SIZE][PKT_BUF_SZ]; }; /* The driver's private device structure */ @@ -151,8 +159,8 @@ int old_tx, old_rx; /* ring entry to be processed */ struct net_device_stats stats; /* These two must be longs for set_bit() */ - long tx_full; - long lock; + long tx_full; + long lock; }; /* I/O register access macros */ @@ -247,15 +255,27 @@ { static int found; + /* check that this machine has an onboard lance */ + switch(idprom->id_machtype) { + case SM_SUN3|SM_3_50: + case SM_SUN3|SM_3_60: + case SM_SUN3X|SM_3_80: + /* these machines have lance */ + break; + + default: + return(-ENODEV); + } + if(found) - return(ENODEV); + return(-ENODEV); if (lance_probe(dev)) { found = 1; return( 0 ); } - return( ENODEV ); + return( -ENODEV ); } static int __init lance_probe( struct net_device *dev) @@ -269,6 +289,7 @@ volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; +#ifdef CONFIG_SUN3 /* LANCE_OBIO can be found within the IO pmeg with some effort */ for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) { @@ -286,6 +307,9 @@ if(!found) return 0; +#else + ioaddr = SUN3X_LANCE; +#endif /* test to see if there's really a lance here */ /* (CSRO_INIT shouldn't be readable) */ @@ -311,8 +335,9 @@ return 0; } lp = (struct lance_private *)dev->priv; - MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct - lance_memory)); + + MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); + lp->iobase = (volatile unsigned short *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ @@ -331,7 +356,7 @@ /* copy in the ethernet address from the prom */ for(i = 0; i < 6 ; i++) dev->dev_addr[i] = idprom->id_ethaddr[i]; - + /* tell the card it's ether address, bytes swapped */ MEM->init.hwaddr[0] = dev->dev_addr[1]; MEM->init.hwaddr[1] = dev->dev_addr[0]; @@ -346,20 +371,19 @@ MEM->init.mode = 0x0000; MEM->init.filter[0] = 0x00000000; MEM->init.filter[1] = 0x00000000; - MEM->init.rdra = sun3_dvma_vtop(MEM->rx_head); + MEM->init.rdra = dvma_vtob(MEM->rx_head); MEM->init.rlen = (RX_LOG_RING_SIZE << 13) | - (sun3_dvma_vtop(MEM->rx_head) >> 16); - MEM->init.tdra = sun3_dvma_vtop(MEM->tx_head); + (dvma_vtob(MEM->rx_head) >> 16); + MEM->init.tdra = dvma_vtob(MEM->tx_head); MEM->init.tlen = (TX_LOG_RING_SIZE << 13) | - (sun3_dvma_vtop(MEM->tx_head) >> 16); + (dvma_vtob(MEM->tx_head) >> 16); DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n", - sun3_dvma_vtop(&(MEM->init)), sun3_dvma_vtop(MEM->rx_head), - (sun3_dvma_vtop(MEM->tx_head)))); - + dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head), + (dvma_vtob(MEM->tx_head)))); if (did_version++ == 0) - DPRINTK( 1, ( version )); + printk( version ); /* The LANCE-specific entries in the device structure. */ dev->open = &lance_open; @@ -386,16 +410,8 @@ REGA(CSR0) = CSR0_STOP; - /* tell the lance the address of its init block */ - REGA(CSR1) = sun3_dvma_vtop(&(MEM->init)); - REGA(CSR2) = sun3_dvma_vtop(&(MEM->init)) >> 16; - lance_init_ring(dev); - /* Re-initialize the LANCE, and start it when done. */ - - REGA(CSR3) = CSR3_BSWP; - /* From now on, AREG is kept to point to CSR0 */ REGA(CSR0) = CSR0_INIT; @@ -434,23 +450,52 @@ lp->old_rx = lp->old_tx = 0; for( i = 0; i < TX_RING_SIZE; i++ ) { - MEM->tx_head[i].base = sun3_dvma_vtop(MEM->tx_data[i]); + MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]); MEM->tx_head[i].flag = 0; MEM->tx_head[i].base_hi = - (sun3_dvma_vtop(MEM->tx_data[i])) >>16; + (dvma_vtob(MEM->tx_data[i])) >>16; MEM->tx_head[i].length = 0; MEM->tx_head[i].misc = 0; } for( i = 0; i < RX_RING_SIZE; i++ ) { - MEM->rx_head[i].base = sun3_dvma_vtop(MEM->rx_data[i]); - MEM->rx_head[i].flag = TMD1_OWN_CHIP; + MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]); + MEM->rx_head[i].flag = RMD1_OWN_CHIP; MEM->rx_head[i].base_hi = - (sun3_dvma_vtop(MEM->rx_data[i])) >> 16; + (dvma_vtob(MEM->rx_data[i])) >> 16; MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000; MEM->rx_head[i].msg_length = 0; } + /* tell the card it's ether address, bytes swapped */ + MEM->init.hwaddr[0] = dev->dev_addr[1]; + MEM->init.hwaddr[1] = dev->dev_addr[0]; + MEM->init.hwaddr[2] = dev->dev_addr[3]; + MEM->init.hwaddr[3] = dev->dev_addr[2]; + MEM->init.hwaddr[4] = dev->dev_addr[5]; + MEM->init.hwaddr[5] = dev->dev_addr[4]; + + MEM->init.mode = 0x0000; + MEM->init.filter[0] = 0x00000000; + MEM->init.filter[1] = 0x00000000; + MEM->init.rdra = dvma_vtob(MEM->rx_head); + MEM->init.rlen = (RX_LOG_RING_SIZE << 13) | + (dvma_vtob(MEM->rx_head) >> 16); + MEM->init.tdra = dvma_vtob(MEM->tx_head); + MEM->init.tlen = (TX_LOG_RING_SIZE << 13) | + (dvma_vtob(MEM->tx_head) >> 16); + + + /* tell the lance the address of its init block */ + REGA(CSR1) = dvma_vtob(&(MEM->init)); + REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16; + +#ifdef CONFIG_SUN3X + REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON; +#else + REGA(CSR3) = CSR3_BSWP; +#endif + } @@ -512,7 +557,7 @@ stopping the queue for a bit... */ netif_stop_queue(dev); - + if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { printk( "%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ @@ -520,13 +565,22 @@ } AREG = CSR0; -// DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", -// dev->name, DREG )); - + DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", + dev->name, DREG )); + +#ifdef CONFIG_SUN3X + /* this weirdness doesn't appear on sun3... */ + if(!(DREG & CSR0_INIT)) { + DPRINTK( 1, ("INIT not set, reinitializing...\n")); + REGA( CSR0 ) = CSR0_STOP; + lance_init_ring(dev); + REGA( CSR0 ) = CSR0_INIT | CSR0_STRT; + } +#endif /* Fill in a Tx ring entry */ #if 0 - if (lance_debug >= 3) { + if (lance_debug >= 2) { u_char *p; int i; printk( "%s: TX pkt %d type 0x%04x from ", dev->name, @@ -566,7 +620,10 @@ lp->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ - REGA(CSR0) = CSR0_INEA | CSR0_TDMD; + REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT; + AREG = CSR0; + DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n", + dev->name, DREG )); dev->trans_start = jiffies; dev_kfree_skb( skb ); @@ -597,14 +654,15 @@ if (in_interrupt) DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name )); in_interrupt = 1; - + still_more: - + flush_cache_all(); + AREG = CSR0; csr0 = DREG; /* ack interrupts */ - DREG = csr0 & (CSR0_TINT | CSR0_RINT); + DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON); /* clear errors */ if(csr0 & CSR0_ERR) diff -urN linux-2.4.18/drivers/net/sunbmac.c linux-2.4.19-pre5/drivers/net/sunbmac.c --- linux-2.4.18/drivers/net/sunbmac.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sunbmac.c Sat Mar 30 22:55:35 2002 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -979,17 +980,14 @@ return &bp->enet_stats; } -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static void bigmac_set_multicast(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; unsigned long bregs = bp->bregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; - int i, j, bit, byte; - u32 tmp, crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 tmp, crc; /* Disable the receiver. The bit self-clears when * the operation is complete. @@ -1022,17 +1020,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffffU; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } diff -urN linux-2.4.18/drivers/net/sundance.c linux-2.4.19-pre5/drivers/net/sundance.c --- linux-2.4.18/drivers/net/sundance.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sundance.c Sat Mar 30 22:55:35 2002 @@ -107,6 +107,7 @@ #include #include #include +#include #include #include /* Processor type for cache alignment. */ #include @@ -1272,32 +1273,6 @@ np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16; return &np->stats; -} - -/* The little-endian AUTODIN II ethernet CRC calculations. - A big-endian version is also available. - This is slow but compact code. Do not use this routine for bulk data, - use a table-based routine instead. - This is common code and should be moved to net/core/crc.c. - Chips may use the upper or lower CRC bits, and may reverse and/or invert - them. Select the endian-ness that results in minimal calculations. -*/ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; } static void set_rx_mode(struct net_device *dev) diff -urN linux-2.4.18/drivers/net/sungem.c linux-2.4.19-pre5/drivers/net/sungem.c --- linux-2.4.18/drivers/net/sungem.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sungem.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ -/* $Id: sungem.c,v 1.44.2.5 2002/02/01 21:45:52 davem Exp $ +/* $Id: sungem.c,v 1.44.2.22 2002/03/13 01:18:12 davem Exp $ * sungem.c: Sun GEM ethernet driver. * - * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com) * * Support for Apple GMAC and assorted PHYs by * Benjamin Herrenscmidt (benh@kernel.crashing.org) @@ -16,6 +16,8 @@ * I can at least detect gigabit with autoneg. */ +#include + #include #include @@ -37,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -66,8 +70,8 @@ NETIF_MSG_LINK) #define DRV_NAME "sungem" -#define DRV_VERSION "0.96" -#define DRV_RELDATE "11/17/01" +#define DRV_VERSION "0.97" +#define DRV_RELDATE "3/20/02" #define DRV_AUTHOR "David S. Miller (davem@redhat.com)" static char version[] __devinitdata = @@ -287,6 +291,105 @@ return 0; } +/* When we get a RX fifo overflow, the RX unit in GEM is probably hung + * so we do the following. + * + * If any part of the reset goes wrong, we return 1 and that causes the + * whole chip to be reset. + */ +static int gem_rxmac_reset(struct gem *gp) +{ + struct net_device *dev = gp->dev; + int limit, i; + u64 desc_dma; + u32 val; + + /* First, reset MAC RX. */ + writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB, + gp->regs + MAC_RXCFG); + for (limit = 0; limit < 5000; limit++) { + if (!(readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB)) + break; + udelay(10); + } + if (limit == 5000) { + printk(KERN_ERR "%s: RX MAC will not disable, resetting whole " + "chip.\n", dev->name); + return 1; + } + + /* Second, disable RX DMA. */ + writel(0, gp->regs + RXDMA_CFG); + for (limit = 0; limit < 5000; limit++) { + if (!(readl(gp->regs + RXDMA_CFG) & RXDMA_CFG_ENABLE)) + break; + udelay(10); + } + if (limit == 5000) { + printk(KERN_ERR "%s: RX DMA will not disable, resetting whole " + "chip.\n", dev->name); + return 1; + } + + udelay(5000); + + /* Execute RX reset command. */ + writel(gp->swrst_base | GREG_SWRST_RXRST, + gp->regs + GREG_SWRST); + for (limit = 0; limit < 5000; limit++) { + if (!(readl(gp->regs + GREG_SWRST) & GREG_SWRST_RXRST)) + break; + udelay(10); + } + if (limit == 5000) { + printk(KERN_ERR "%s: RX reset command will not execute, resetting " + "whole chip.\n", dev->name); + return 1; + } + + /* Refresh the RX ring. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct gem_rxd *rxd = &gp->init_block->rxd[i]; + + if (gp->rx_skbs[i] == NULL) { + printk(KERN_ERR "%s: Parts of RX ring empty, resetting " + "whole chip.\n", dev->name); + return 1; + } + + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); + } + gp->rx_new = gp->rx_old = 0; + + /* Now we must reprogram the rest of RX unit. */ + desc_dma = (u64) gp->gblock_dvma; + desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd)); + writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); + writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); + writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); + val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + writel(val, gp->regs + RXDMA_CFG); + if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) + writel(((5 & RXDMA_BLANK_IPKTS) | + ((8 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); + else + writel(((5 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); + val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF); + val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON); + writel(val, gp->regs + RXDMA_PTHRESH); + val = readl(gp->regs + RXDMA_CFG); + writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG); + writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK); + val = readl(gp->regs + MAC_RXCFG); + writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); + + return 0; +} + static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) { u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT); @@ -297,19 +400,10 @@ gp->dev->name, rxmac_stat); if (rxmac_stat & MAC_RXSTAT_OFLW) { - u32 smac = readl(gp->regs + MAC_SMACHINE); - - printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n", - dev->name, smac); gp->net_stats.rx_over_errors++; gp->net_stats.rx_fifo_errors++; - if (((smac >> 24) & 0x7) == 0x7) { - /* Due to a bug, the chip is hung in this case - * and a full reset is necessary. - */ - ret = 1; - } + ret = gem_rxmac_reset(gp); } if (rxmac_stat & MAC_RXSTAT_ACE) @@ -546,7 +640,7 @@ gp->tx_old = entry; if (netif_queue_stopped(dev) && - TX_BUFFS_AVAIL(gp) > 0) + TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1)) netif_wake_queue(dev); } @@ -721,7 +815,7 @@ spin_lock_irq(&gp->lock); - gp->reset_task_pending = 1; + gp->reset_task_pending = 2; schedule_task(&gp->reset_task); spin_unlock_irq(&gp->lock); @@ -756,9 +850,12 @@ spin_lock_irq(&gp->lock); + /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irq(&gp->lock); + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); return 1; } @@ -833,7 +930,7 @@ } gp->tx_new = entry; - if (TX_BUFFS_AVAIL(gp) <= 0) + if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); if (netif_msg_tx_queued(gp)) @@ -848,19 +945,28 @@ } /* Jumbo-grams don't seem to work :-( */ +#define GEM_MIN_MTU 68 #if 1 -#define MAX_MTU 1500 +#define GEM_MAX_MTU 1500 #else -#define MAX_MTU 9000 +#define GEM_MAX_MTU 9000 #endif static int gem_change_mtu(struct net_device *dev, int new_mtu) { struct gem *gp = dev->priv; - if (new_mtu < 0 || new_mtu > MAX_MTU) + if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) return -EINVAL; + if (!netif_running(dev) || !netif_device_present(dev)) { + /* We'll just catch it later when the + * device is up'd or resumed. + */ + dev->mtu = new_mtu; + return 0; + } + spin_lock_irq(&gp->lock); dev->mtu = new_mtu; gp->reset_task_pending = 1; @@ -874,6 +980,7 @@ #define STOP_TRIES 32 +/* Must be invoked under gp->lock. */ static void gem_stop(struct gem *gp) { int limit; @@ -883,7 +990,8 @@ writel(0xffffffff, gp->regs + GREG_IMASK); /* Reset the chip */ - writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST); + writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST, + gp->regs + GREG_SWRST); limit = STOP_TRIES; @@ -898,6 +1006,7 @@ printk(KERN_ERR "gem: SW reset is ghetto.\n"); } +/* Must be invoked under gp->lock. */ static void gem_start_dma(struct gem *gp) { unsigned long val; @@ -933,6 +1042,7 @@ { 1, 0, 1 }, /* 1000BT */ }; +/* Must be invoked under gp->lock. */ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { u16 ctl; @@ -958,11 +1068,8 @@ } start_aneg: - spin_lock_irq(&gp->lock); - if (!gp->hw_running) { - spin_unlock_irq(&gp->lock); + if (!gp->hw_running) return; - } /* Configure PHY & start aneg */ ctl = phy_read(gp, MII_BMCR); @@ -977,11 +1084,10 @@ phy_write(gp, MII_BMCR, ctl); gp->timer_ticks = 0; - gp->link_timer.expires = jiffies + ((12 * HZ) / 10); - add_timer(&gp->link_timer); - spin_unlock_irq(&gp->lock); + mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); } +/* Must be invoked under gp->lock. */ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause) { u32 val; @@ -1025,6 +1131,8 @@ /* A link-up condition has occurred, initialize and enable the * rest of the chip. + * + * Must be invoked under gp->lock. */ static void gem_set_link_modes(struct gem *gp) { @@ -1105,6 +1213,20 @@ pause = 1; } + if (netif_msg_link(gp)) { + if (pause) { + printk(KERN_INFO "%s: Pause is enabled " + "(rxfifo: %d off: %d on: %d)\n", + gp->dev->name, + gp->rx_fifo_sz, + gp->rx_pause_off, + gp->rx_pause_on); + } else { + printk(KERN_INFO "%s: Pause is disabled\n", + gp->dev->name); + } + } + if (!full_duplex) writel(512, gp->regs + MAC_STIME); else @@ -1119,6 +1241,7 @@ gem_start_dma(gp); } +/* Must be invoked under gp->lock. */ static int gem_mdio_link_not_up(struct gem *gp) { u16 val; @@ -1162,7 +1285,7 @@ return 0; } -static void gem_init_rings(struct gem *, int); +static void gem_init_rings(struct gem *); static void gem_init_hw(struct gem *, int); static void gem_reset_task(void *data) @@ -1173,25 +1296,27 @@ * DMA stopped. Todo: Use this function for reset * on error as well. */ + + spin_lock_irq(&gp->lock); + if (gp->hw_running && gp->opened) { /* Make sure we don't get interrupts or tx packets */ - spin_lock_irq(&gp->lock); - netif_stop_queue(gp->dev); writel(0xffffffff, gp->regs + GREG_IMASK); - spin_unlock_irq(&gp->lock); - /* Reset the chip & rings */ gem_stop(gp); - gem_init_rings(gp, 0); + gem_init_rings(gp); + gem_init_hw(gp, (gp->reset_task_pending == 2)); netif_wake_queue(gp->dev); } gp->reset_task_pending = 0; + + spin_unlock_irq(&gp->lock); } static void gem_link_timer(unsigned long data) @@ -1201,13 +1326,14 @@ if (!gp->hw_running) return; + spin_lock_irq(&gp->lock); + /* If the link of task is still pending, we just * reschedule the link timer */ if (gp->reset_task_pending) goto restart; - spin_lock_irq(&gp->lock); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { u16 val = phy_read(gp, MII_BMSR); @@ -1252,16 +1378,15 @@ if (netif_msg_link(gp)) printk(KERN_INFO "%s: Link down\n", gp->dev->name); - gp->reset_task_pending = 1; + gp->reset_task_pending = 2; schedule_task(&gp->reset_task); restart = 1; } else if (++gp->timer_ticks > 10) restart = gem_mdio_link_not_up(gp); if (restart) { - spin_unlock_irq(&gp->lock); gem_begin_auto_negotiation(gp, NULL); - return; + goto out_unlock; } } } else { @@ -1278,11 +1403,12 @@ } restart: - gp->link_timer.expires = jiffies + ((12 * HZ) / 10); - add_timer(&gp->link_timer); + mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); +out_unlock: spin_unlock_irq(&gp->lock); } +/* Must be invoked under gp->lock. */ static void gem_clean_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1316,7 +1442,9 @@ gp->tx_skbs[i] = NULL; for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { - txd = &gb->txd[i]; + int ent = i & (TX_RING_SIZE - 1); + + txd = &gb->txd[ent]; dma_addr = le64_to_cpu(txd->buffer); pci_unmap_page(gp->pdev, dma_addr, le64_to_cpu(txd->control_word) & @@ -1330,16 +1458,14 @@ } } -static void gem_init_rings(struct gem *gp, int from_irq) +/* Must be invoked under gp->lock. */ +static void gem_init_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; struct net_device *dev = gp->dev; - int i, gfp_flags = GFP_KERNEL; + int i; dma_addr_t dma_addr; - if (from_irq) - gfp_flags = GFP_ATOMIC; - gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0; gem_clean_rings(gp); @@ -1348,7 +1474,7 @@ struct sk_buff *skb; struct gem_rxd *rxd = &gb->rxd[i]; - skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags); + skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); if (!skb) { rxd->buffer = 0; rxd->status_word = 0; @@ -1377,6 +1503,7 @@ } } +/* Must be invoked under gp->lock. */ static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) { u16 val; @@ -1401,6 +1528,7 @@ return (limit <= 0); } +/* Must be invoked under gp->lock. */ static void gem_init_bcm5201_phy(struct gem *gp) { u16 data; @@ -1410,6 +1538,7 @@ phy_write(gp, MII_BCM5201_MULTIPHY, data); } +/* Must be invoked under gp->lock. */ static void gem_init_bcm5400_phy(struct gem *gp) { u16 data; @@ -1437,6 +1566,7 @@ phy_write(gp, MII_BCM5400_AUXCONTROL, data); } +/* Must be invoked under gp->lock. */ static void gem_init_bcm5401_phy(struct gem *gp) { u16 data; @@ -1451,6 +1581,9 @@ * WARNING ! OF and Darwin don't agree on the * register addresses. OF seem to interpret the * register numbers below as decimal + * + * Note: This should (and does) match tg3_init_5401phy_dsp + * in the tg3.c driver. -DaveM */ phy_write(gp, 0x18, 0x0c20); phy_write(gp, 0x17, 0x0012); @@ -1480,6 +1613,7 @@ __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); } +/* Must be invoked under gp->lock. */ static void gem_init_bcm5411_phy(struct gem *gp) { u16 data; @@ -1506,6 +1640,7 @@ phy_write(gp, MII_BCM5400_GB_CONTROL, data); } +/* Must be invoked under gp->lock. */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; @@ -1654,7 +1789,9 @@ val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); writel(val, gp->regs + PCS_CFG); - /* Advertise all capabilities. */ + /* Advertise all capabilities except assymetric + * pause. + */ val = readl(gp->regs + PCS_MIIADV); val |= (PCS_MIIADV_FD | PCS_MIIADV_HD | PCS_MIIADV_SP | PCS_MIIADV_AP); @@ -1689,9 +1826,9 @@ if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 && gp->phy_mod != phymod_bcm5411) gp->link_cntl &= ~BMCR_SPD2; - } +/* Must be invoked under gp->lock. */ static void gem_init_dma(struct gem *gp) { u64 desc_dma = (u64) gp->gblock_dvma; @@ -1707,7 +1844,7 @@ writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); @@ -1729,8 +1866,7 @@ gp->regs + RXDMA_BLANK); } -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - +/* Must be invoked under gp->lock. */ static u32 gem_setup_multicast(struct gem *gp) { @@ -1746,9 +1882,9 @@ rxcfg |= MAC_RXCFG_PROM; } else { u16 hash_table[16]; - u32 crc, poly = CRC_POLYNOMIAL_LE; + u32 crc; struct dev_mc_list *dmi = gp->dev->mc_list; - int i, j, bit, byte; + int i; for (i = 0; i < 16; i++) hash_table[i] = 0; @@ -1761,17 +1897,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffffU; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 24; hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf)); } @@ -1783,10 +1909,10 @@ return rxcfg; } +/* Must be invoked under gp->lock. */ static void gem_init_mac(struct gem *gp) { unsigned char *e = &gp->dev->dev_addr[0]; - u32 rxcfg; if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) @@ -1797,7 +1923,10 @@ writel(0x04, gp->regs + MAC_IPG2); writel(0x40, gp->regs + MAC_STIME); writel(0x40, gp->regs + MAC_MINFSZ); - writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ); + + /* Ethernet payload + header + FCS + optional VLAN tag. */ + writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ); + writel(0x07, gp->regs + MAC_PASIZE); writel(0x04, gp->regs + MAC_JAMSIZE); writel(0x10, gp->regs + MAC_ATTLIM); @@ -1823,7 +1952,7 @@ writel(0, gp->regs + MAC_AF21MSK); writel(0, gp->regs + MAC_AF0MSK); - rxcfg = gem_setup_multicast(gp); + gp->mac_rx_cfg = gem_setup_multicast(gp); writel(0, gp->regs + MAC_NCOLL); writel(0, gp->regs + MAC_FASUCC); @@ -1841,7 +1970,7 @@ * them once a link is established. */ writel(0, gp->regs + MAC_TXCFG); - writel(rxcfg, gp->regs + MAC_RXCFG); + writel(gp->mac_rx_cfg, gp->regs + MAC_RXCFG); writel(0, gp->regs + MAC_MCCFG); writel(0, gp->regs + MAC_XIFCFG); @@ -1858,6 +1987,7 @@ writel(0xffffffff, gp->regs + MAC_MCMASK); } +/* Must be invoked under gp->lock. */ static void gem_init_pause_thresholds(struct gem *gp) { /* Calculate pause thresholds. Setting the OFF threshold to the @@ -1868,8 +1998,9 @@ if (gp->rx_fifo_sz <= (2 * 1024)) { gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; } else { - int off = (gp->rx_fifo_sz - (5 * 1024)); - int on = off - 1024; + int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63; + int off = (gp->rx_fifo_sz - (max_frame * 2)); + int on = off - max_frame; gp->rx_pause_off = off; gp->rx_pause_on = on; @@ -1878,7 +2009,10 @@ { u32 cfg; - cfg = GREG_CFG_IBURST; + cfg = 0; +#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA) + cfg |= GREG_CFG_IBURST; +#endif cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); cfg |= ((31 << 6) & GREG_CFG_RXDMALIM); writel(cfg, gp->regs + GREG_CFG); @@ -1898,6 +2032,7 @@ gp->phy_type = phy_mii_mdio0; gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; + gp->swrst_base = 0; return 0; } @@ -1960,6 +2095,7 @@ gp->tx_fifo_sz, gp->rx_fifo_sz); return -1; } + gp->swrst_base = 0; } else { if (gp->tx_fifo_sz != (2 * 1024) || gp->rx_fifo_sz != (2 * 1024)) { @@ -1967,12 +2103,14 @@ gp->tx_fifo_sz, gp->rx_fifo_sz); return -1; } + gp->swrst_base = (64 / 4) << GREG_SWRST_CACHE_SHIFT; } } return 0; } +/* Must be invoked under gp->lock. */ static void gem_init_hw(struct gem *gp, int restart_link) { /* On Apple's gmac, I initialize the PHY only after @@ -1987,21 +2125,16 @@ gem_init_mac(gp); gem_init_pause_thresholds(gp); - spin_lock_irq(&gp->lock); if (restart_link) { /* Default aneg parameters */ gp->timer_ticks = 0; gp->lstate = link_down; - spin_unlock_irq(&gp->lock); - /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ gem_begin_auto_negotiation(gp, NULL); } else { if (gp->lstate == link_up) gem_set_link_modes(gp); - - spin_unlock_irq(&gp->lock); } } @@ -2046,6 +2179,7 @@ #endif /* CONFIG_ALL_PPC */ +/* Must be invoked under gp->lock. */ static void gem_stop_phy(struct gem *gp) { u32 mifcfg; @@ -2117,14 +2251,21 @@ schedule(); /* Actually stop the chip */ + spin_lock_irq(&gp->lock); if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { gem_stop_phy(gp); + + spin_unlock_irq(&gp->lock); + #ifdef CONFIG_ALL_PPC /* Power down the chip */ gem_apple_powerdown(gp); #endif /* CONFIG_ALL_PPC */ - } else + } else { gem_stop(gp); + + spin_unlock_irq(&gp->lock); + } } static void gem_pm_task(void *data) @@ -2159,14 +2300,19 @@ static int gem_open(struct net_device *dev) { struct gem *gp = dev->priv; - int hw_was_up = gp->hw_running; + int hw_was_up; down(&gp->pm_sem); + hw_was_up = gp->hw_running; + /* Stop the PM timer/task */ del_timer(&gp->pm_timer); flush_scheduled_tasks(); + /* The power-management semaphore protects the hw_running + * etc. state so it is safe to do this bit without gp->lock + */ if (!gp->hw_running) { #ifdef CONFIG_ALL_PPC /* First, we need to bring up the chip */ @@ -2175,18 +2321,26 @@ gem_check_invariants(gp); } #endif /* CONFIG_ALL_PPC */ + /* Reset the chip */ + spin_lock_irq(&gp->lock); gem_stop(gp); + spin_unlock_irq(&gp->lock); gp->hw_running = 1; } + spin_lock_irq(&gp->lock); + /* We can now request the interrupt as we know it's masked * on the controller */ if (request_irq(gp->pdev->irq, gem_interrupt, SA_SHIRQ, dev->name, (void *)dev)) { + spin_unlock_irq(&gp->lock); + printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); + #ifdef CONFIG_ALL_PPC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); @@ -2200,13 +2354,15 @@ } /* Allocate & setup ring buffers */ - gem_init_rings(gp, 0); + gem_init_rings(gp); /* Init & setup chip hardware */ gem_init_hw(gp, !hw_was_up); gp->opened = 1; + spin_unlock_irq(&gp->lock); + up(&gp->pm_sem); return 0; @@ -2226,8 +2382,6 @@ writel(0xffffffff, gp->regs + GREG_IMASK); netif_stop_queue(dev); - spin_unlock_irq(&gp->lock); - /* Stop chip */ gem_stop(gp); @@ -2237,6 +2391,8 @@ /* Bye, the pm timer will finish the job */ free_irq(gp->pdev->irq, (void *) dev); + spin_unlock_irq(&gp->lock); + /* Fire the PM timer that will shut us down in about 10 seconds */ gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); @@ -2262,21 +2418,21 @@ /* If the driver is opened, we stop the DMA */ if (gp->opened) { + spin_lock_irq(&gp->lock); + /* Stop traffic, mark us closed */ netif_device_detach(dev); - spin_lock_irq(&gp->lock); - writel(0xffffffff, gp->regs + GREG_IMASK); - spin_unlock_irq(&gp->lock); - /* Stop chip */ gem_stop(gp); /* Get rid of ring buffers */ gem_clean_rings(gp); + spin_unlock_irq(&gp->lock); + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) disable_irq(gp->pdev->irq); } @@ -2307,10 +2463,15 @@ gem_check_invariants(gp); } #endif /* CONFIG_ALL_PPC */ + spin_lock_irq(&gp->lock); + gem_stop(gp); gp->hw_running = 1; - gem_init_rings(gp, 0); + gem_init_rings(gp); gem_init_hw(gp, 1); + + spin_unlock_irq(&gp->lock); + netif_device_attach(dev); if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) enable_irq(gp->pdev->irq); @@ -2326,6 +2487,8 @@ struct gem *gp = dev->priv; struct net_device_stats *stats = &gp->net_stats; + spin_lock_irq(&gp->lock); + if (gp->hw_running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_FCSERR); @@ -2343,6 +2506,9 @@ writel(0, gp->regs + MAC_ECOLL); writel(0, gp->regs + MAC_LCOLL); } + + spin_unlock_irq(&gp->lock); + return &gp->net_stats; } @@ -2355,10 +2521,12 @@ if (!gp->hw_running) return; + spin_lock_irq(&gp->lock); + netif_stop_queue(dev); rxcfg = readl(gp->regs + MAC_RXCFG); - rxcfg_new = gem_setup_multicast(gp); + gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp); writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { @@ -2372,8 +2540,9 @@ writel(rxcfg, gp->regs + MAC_RXCFG); - /* Hrm... we may walk on the reset task here... */ netif_wake_queue(dev); + + spin_unlock_irq(&gp->lock); } /* Eventually add support for changing the advertisement @@ -2422,11 +2591,13 @@ ecmd.phy_address = 0; /* XXX fixed PHYAD */ /* Record PHY settings if HW is on. */ + spin_lock_irq(&gp->lock); if (gp->hw_running) { bmcr = phy_read(gp, MII_BMCR); gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); } else bmcr = 0; + spin_unlock_irq(&gp->lock); if (bmcr & BMCR_ANENABLE) { ecmd.autoneg = AUTONEG_ENABLE; ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100); @@ -2460,18 +2631,22 @@ ecmd.duplex != DUPLEX_FULL))) return -EINVAL; - /* Apply settings and restart link process */ - if (gp->hw_running) - del_timer(&gp->link_timer); + /* Apply settings and restart link process. */ + spin_lock_irq(&gp->lock); gem_begin_auto_negotiation(gp, &ecmd); + spin_unlock_irq(&gp->lock); + return 0; case ETHTOOL_NWAY_RST: if ((gp->link_cntl & BMCR_ANENABLE) == 0) return -EINVAL; - if (gp->hw_running) - del_timer(&gp->link_timer); + + /* Restart link process. */ + spin_lock_irq(&gp->lock); gem_begin_auto_negotiation(gp, NULL); + spin_unlock_irq(&gp->lock); + return 0; case ETHTOOL_GWOL: @@ -2587,13 +2762,74 @@ return rc; } +#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC)) +/* Fetch MAC address from vital product data of PCI ROM. */ +static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr) +{ + int this_offset; + + for (this_offset = 0x20; this_offset < len; this_offset++) { + void *p = rom_base + this_offset; + int i; + + if (readb(p + 0) != 0x90 || + readb(p + 1) != 0x00 || + readb(p + 2) != 0x09 || + readb(p + 3) != 0x4e || + readb(p + 4) != 0x41 || + readb(p + 5) != 0x06) + continue; + + this_offset += 6; + p += 6; + + for (i = 0; i < 6; i++) + dev_addr[i] = readb(p + i); + break; + } +} + +static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) +{ + u32 rom_reg_orig; + void *p; + + if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { + if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) + goto use_random; + } + + pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); + pci_write_config_dword(pdev, pdev->rom_base_reg, + rom_reg_orig | PCI_ROM_ADDRESS_ENABLE); + + p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024)); + if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa) + find_eth_addr_in_vpd(p, (64 * 1024), dev_addr); + + if (p != NULL) + iounmap(p); + + pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); + return; + +use_random: + /* Sun MAC prefix then 3 random bytes. */ + dev_addr[0] = 0x08; + dev_addr[1] = 0x00; + dev_addr[2] = 0x20; + get_random_bytes(dev_addr, 3); + return; +} +#endif /* not Sparc and not PPC */ + static int __devinit gem_get_device_address(struct gem *gp) { #if defined(__sparc__) || defined(CONFIG_ALL_PPC) struct net_device *dev = gp->dev; #endif -#ifdef __sparc__ +#if defined(__sparc__) struct pci_dev *pdev = gp->pdev; struct pcidev_cookie *pcp = pdev->sysdata; int node = -1; @@ -2608,8 +2844,7 @@ } if (node == -1) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#endif -#ifdef CONFIG_ALL_PPC +#elif defined(CONFIG_ALL_PPC) unsigned char *addr; addr = get_property(gp->of_node, "local-mac-address", NULL); @@ -2619,6 +2854,8 @@ return -1; } memcpy(dev->dev_addr, addr, MAX_ADDR_LEN); +#else + get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr); #endif return 0; } @@ -2681,21 +2918,21 @@ return -ENODEV; } - dev = init_etherdev(NULL, sizeof(*gp)); + dev = alloc_etherdev(sizeof(*gp)); if (!dev) { - printk(KERN_ERR PFX "Etherdev init failed, aborting.\n"); + printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); - if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) { - printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, " - "aborting.\n", gemreg_base, gemreg_len); + gp = dev->priv; + + if (pci_request_regions(pdev, dev->name)) { + printk(KERN_ERR PFX "Cannot obtain PCI resources, " + "aborting.\n"); goto err_out_free_netdev; } - gp = dev->priv; - gp->pdev = pdev; dev->base_addr = (long) pdev; gp->dev = dev; @@ -2728,7 +2965,7 @@ if (gp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); - goto err_out_free_mmio_res; + goto err_out_free_res; } /* On Apple, we power the chip up now in order for check @@ -2739,12 +2976,18 @@ if (pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerup(gp); #endif + spin_lock_irq(&gp->lock); gem_stop(gp); + spin_unlock_irq(&gp->lock); + if (gem_check_invariants(gp)) goto err_out_iounmap; + + spin_lock_irq(&gp->lock); gp->hw_running = 1; gem_init_phy(gp); gem_begin_auto_negotiation(gp, NULL); + spin_unlock_irq(&gp->lock); /* It is guarenteed that the returned buffer will be at least * PAGE_SIZE aligned. @@ -2758,22 +3001,28 @@ goto err_out_iounmap; } - pci_set_drvdata(pdev, dev); - - printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", - dev->name); - #ifdef CONFIG_ALL_PPC gp->of_node = pci_device_to_OF_node(pdev); #endif if (gem_get_device_address(gp)) - goto err_out_iounmap; + goto err_out_free_consistent; + + if (register_netdev(dev)) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_free_consistent; + } + + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", + dev->name); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); + pci_set_drvdata(pdev, dev); + dev->open = gem_open; dev->stop = gem_close; dev->hard_start_xmit = gem_start_xmit; @@ -2797,6 +3046,12 @@ return 0; +err_out_free_consistent: + pci_free_consistent(pdev, + sizeof(struct gem_init_block), + gp->init_block, + gp->gblock_dvma); + err_out_iounmap: down(&gp->pm_sem); /* Stop the PM timer & task */ @@ -2805,13 +3060,13 @@ if (gp->hw_running) gem_shutdown(gp); up(&gp->pm_sem); + iounmap((void *) gp->regs); -err_out_free_mmio_res: - release_mem_region(gemreg_base, gemreg_len); +err_out_free_res: + pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev(dev); kfree(dev); return -ENODEV; @@ -2840,8 +3095,7 @@ gp->init_block, gp->gblock_dvma); iounmap((void *) gp->regs); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + pci_release_regions(pdev); kfree(dev); pci_set_drvdata(pdev, NULL); diff -urN linux-2.4.18/drivers/net/sungem.h linux-2.4.19-pre5/drivers/net/sungem.h --- linux-2.4.18/drivers/net/sungem.h Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sungem.h Sat Mar 30 22:55:35 2002 @@ -1,4 +1,4 @@ -/* $Id: sungem.h,v 1.10.2.2 2002/01/23 15:40:02 davem Exp $ +/* $Id: sungem.h,v 1.10.2.4 2002/03/11 08:54:48 davem Exp $ * sungem.h: Definitions for Sun GEM ethernet driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -94,6 +94,8 @@ #define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */ #define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */ #define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */ +#define GREG_SWRST_CACHESIZE 0x00ff0000 /* RIO only: cache line size */ +#define GREG_SWRST_CACHE_SHIFT 16 /* TX DMA Registers */ #define TXDMA_KICK 0x2000UL /* TX Kick Register */ @@ -985,6 +987,9 @@ int rx_pause_on; int mii_phy_addr; int gigabit_capable; + + u32 mac_rx_cfg; + u32 swrst_base; /* Autoneg & PHY control */ int link_cntl; diff -urN linux-2.4.18/drivers/net/sunhme.c linux-2.4.19-pre5/drivers/net/sunhme.c --- linux-2.4.18/drivers/net/sunhme.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/sunhme.c Sat Mar 30 22:55:40 2002 @@ -3,7 +3,7 @@ * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. * - * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com) * * Changes : * 2000/11/11 Willy Tarreau @@ -14,7 +14,7 @@ */ static char version[] = - "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n"; + "sunhme.c:v2.00 20/Mar/2002 David S. Miller (davem@redhat.com)\n"; #include @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -1469,9 +1471,6 @@ add_timer(&hp->happy_timer); } -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static int happy_meal_init(struct happy_meal *hp, int from_irq) { unsigned long gregs = hp->gregs; @@ -1583,8 +1582,8 @@ u16 hash_table[4]; struct dev_mc_list *dmi = hp->dev->mc_list; char *addrs; - int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 crc; for (i = 0; i < 4; i++) hash_table[i] = 0; @@ -1596,17 +1595,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffffU; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } @@ -1623,12 +1612,12 @@ /* Set the RX and TX ring ptrs. */ HMD(("ring ptrs rxr[%08x] txr[%08x]\n", - (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), - (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)))); + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)))); hme_write32(hp, erxregs + ERX_RING, - (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); hme_write32(hp, etxregs + ETX_RING, - (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); /* Set the supported burst sizes. */ HMD(("happy_meal_init: old[%08x] bursts<", @@ -2385,8 +2374,8 @@ unsigned long bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; - int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 crc; /* Lock out others. */ netif_stop_queue(dev); @@ -2412,17 +2401,7 @@ if (!(*addrs & 1)) continue; - crc = 0xffffffffU; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } @@ -2665,33 +2644,28 @@ struct happy_meal *hp; struct net_device *dev; int i, qfe_slot = -1; + int err = -ENODEV; if (is_qfe) { qp = quattro_sbus_find(sdev); if (qp == NULL) - return -ENODEV; + goto err_out; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) if (qp->happy_meals[qfe_slot] == NULL) break; if (qfe_slot == 4) - return -ENODEV; + goto err_out; } - dev = init_etherdev(NULL, sizeof(struct happy_meal)); + err = -ENOMEM; + dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) - return -ENOMEM; + goto err_out; SET_MODULE_OWNER(dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); - if (qfe_slot != -1) - printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", - dev->name, qfe_slot); - else - printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", - dev->name); - /* If user did not specify a MAC address specifically, use * the Quattro local-mac-address property... */ @@ -2702,6 +2676,7 @@ if (i < 6) { /* a mac address was given */ for (i = 0; i < 6; i++) dev->dev_addr[i] = macaddr[i]; + macaddr[5]++; } else if (qfe_slot != -1 && prom_getproplen(sdev->prom_node, "local-mac-address") == 6) { @@ -2711,11 +2686,6 @@ memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } - for (i = 0; i < 6; i++) - printk("%2.2x%c", - dev->dev_addr[i], i == 5 ? ' ' : ':'); - printk("\n"); - hp = dev->priv; memset(hp, 0, sizeof(*hp)); @@ -2723,11 +2693,12 @@ spin_lock_init(&hp->happy_lock); + err = -ENODEV; if (sdev->num_registers != 5) { printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n", sdev->num_registers); printk(KERN_ERR "happymeal: Would you like that for here or to go?\n"); - return -ENODEV; + goto err_out_free_netdev; } if (qp != NULL) { @@ -2741,35 +2712,35 @@ GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n"); - return -ENODEV; + goto err_out_free_netdev; } hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n"); - return -ENODEV; + goto err_out_iounmap; } hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n"); - return -ENODEV; + goto err_out_iounmap; } hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n"); - return -ENODEV; + goto err_out_iounmap; } hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n"); - return -ENODEV; + goto err_out_iounmap; } hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff); @@ -2792,6 +2763,11 @@ hp->happy_block = sbus_alloc_consistent(hp->happy_dev, PAGE_SIZE, &hp->hblock_dvma); + err = -ENOMEM; + if (!hp->happy_block) { + printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n"); + goto err_out_iounmap; + } /* Force check of the link first time we are brought up. */ hp->linkcheck = 0; @@ -2834,20 +2810,157 @@ */ happy_meal_set_initial_advertisement(hp); - ether_setup(dev); + if (register_netdev(hp->dev)) { + printk(KERN_ERR "happymeal: Cannot register net device, " + "aborting.\n"); + goto err_out_free_consistent; + } + + if (qfe_slot != -1) + printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", + dev->name, qfe_slot); + else + printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", + dev->name); + + for (i = 0; i < 6; i++) + printk("%2.2x%c", + dev->dev_addr[i], i == 5 ? ' ' : ':'); + printk("\n"); /* We are home free at this point, link us in to the happy * device list. */ - dev->ifindex = dev_new_index(); hp->next_module = root_happy_dev; root_happy_dev = hp; return 0; + +err_out_free_consistent: + sbus_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); + +err_out_iounmap: + if (hp->gregs) + sbus_iounmap(hp->gregs, GREG_REG_SIZE); + if (hp->etxregs) + sbus_iounmap(hp->etxregs, ETX_REG_SIZE); + if (hp->erxregs) + sbus_iounmap(hp->erxregs, ERX_REG_SIZE); + if (hp->bigmacregs) + sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); + if (hp->tcvregs) + sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); + +err_out_free_netdev: + kfree(dev); + +err_out: + return err; } #endif #ifdef CONFIG_PCI +#ifndef __sparc__ +static int is_quattro_p(struct pci_dev *pdev) +{ + struct pci_dev *busdev = pdev->bus->self; + struct list_head *tmp; + int n_hmes; + + if (busdev->vendor != PCI_VENDOR_ID_DEC || + busdev->device != PCI_DEVICE_ID_DEC_21153) + return 0; + + n_hmes = 0; + tmp = pdev->bus->devices.next; + while (tmp != &pdev->bus->devices) { + struct pci_dev *this_pdev = pci_dev_b(tmp); + + if (this_pdev->vendor == PCI_VENDOR_ID_SUN && + this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL) + n_hmes++; + + tmp = tmp->next; + } + + if (n_hmes != 4) + return 0; + + return 1; +} + +/* Fetch MAC address from vital product data of PCI ROM. */ +static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr) +{ + int this_offset; + + for (this_offset = 0x20; this_offset < len; this_offset++) { + void *p = rom_base + this_offset; + + if (readb(p + 0) != 0x90 || + readb(p + 1) != 0x00 || + readb(p + 2) != 0x09 || + readb(p + 3) != 0x4e || + readb(p + 4) != 0x41 || + readb(p + 5) != 0x06) + continue; + + this_offset += 6; + p += 6; + + if (index == 0) { + int i; + + for (i = 0; i < 6; i++) + dev_addr[i] = readb(p + i); + break; + } + index--; + } +} + +static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) +{ + u32 rom_reg_orig; + void *p; + int index; + + index = 0; + if (is_quattro_p(pdev)) + index = PCI_SLOT(pdev->devfn); + + if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { + if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) + goto use_random; + } + + pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); + pci_write_config_dword(pdev, pdev->rom_base_reg, + rom_reg_orig | PCI_ROM_ADDRESS_ENABLE); + + p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024)); + if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa) + find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr); + + if (p != NULL) + iounmap(p); + + pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); + return; + +use_random: + /* Sun MAC prefix then 3 random bytes. */ + dev_addr[0] = 0x08; + dev_addr[1] = 0x00; + dev_addr[2] = 0x20; + get_random_bytes(dev_addr, 3); + return; +} +#endif /* !(__sparc__) */ + static int __init happy_meal_pci_init(struct pci_dev *pdev) { struct quattro *qp = NULL; @@ -2860,6 +2973,7 @@ unsigned long hpreg_base; int i, qfe_slot = -1; char prom_name[64]; + int err; /* Now make sure pci_dev cookie is there. */ #ifdef __sparc__ @@ -2872,52 +2986,33 @@ prom_getstring(node, "name", prom_name, sizeof(prom_name)); #else -/* This needs to be corrected... -DaveM */ - strcpy(prom_name, "qfe"); + if (is_quattro_p(pdev)) + strcpy(prom_name, "SUNW,qfe"); + else + strcpy(prom_name, "SUNW,hme"); #endif + err = -ENODEV; if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { qp = quattro_pci_find(pdev); if (qp == NULL) - return -ENODEV; + goto err_out; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) if (qp->happy_meals[qfe_slot] == NULL) break; if (qfe_slot == 4) - return -ENODEV; + goto err_out; } - dev = init_etherdev(NULL, sizeof(struct happy_meal)); + dev = alloc_etherdev(sizeof(struct happy_meal)); + err = -ENOMEM; if (!dev) - return -ENOMEM; + goto err_out; SET_MODULE_OWNER(dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); - if (!qfe_slot) { - struct pci_dev *qpdev = qp->quattro_dev; - - prom_name[0] = 0; - if (!strncmp(dev->name, "eth", 3)) { - int i = simple_strtoul(dev->name + 3, NULL, 10); - sprintf(prom_name, "-%d", i + 3); - } - printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name); - if (qpdev->vendor == PCI_VENDOR_ID_DEC && - qpdev->device == PCI_DEVICE_ID_DEC_21153) - printk("DEC 21153 PCI Bridge\n"); - else - printk("unknown bridge %04x.%04x\n", - qpdev->vendor, qpdev->device); - } - if (qfe_slot != -1) - printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ", - dev->name, qfe_slot); - else - printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", - dev->name); - dev->base_addr = (long) pdev; hp = (struct happy_meal *)dev->priv; @@ -2934,13 +3029,20 @@ } hpreg_base = pci_resource_start(pdev, 0); + err = -ENODEV; if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); - return -ENODEV; + goto err_out_clear_quattro; + } + if (pci_request_regions(pdev, dev->name)) { + printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, " + "aborting.\n"); + goto err_out_clear_quattro; } + if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) { printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); - return -ENODEV; + goto err_out_free_res; } for (i = 0; i < 6; i++) { @@ -2950,6 +3052,7 @@ if (i < 6) { /* a mac address was given */ for (i = 0; i < 6; i++) dev->dev_addr[i] = macaddr[i]; + macaddr[5]++; } else { #ifdef __sparc__ if (qfe_slot != -1 && @@ -2960,15 +3063,10 @@ memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } #else - memset(dev->dev_addr, 0, 6); + get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]); #endif } - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); - - printk("\n"); - /* Layout registers. */ hp->gregs = (hpreg_base + 0x0000UL); hp->etxregs = (hpreg_base + 0x2000UL); @@ -3005,9 +3103,10 @@ hp->happy_block = (struct hmeal_init_block *) pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma); + err = -ENODEV; if (!hp->happy_block) { printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n"); - return -ENODEV; + goto err_out_iounmap; } hp->linkcheck = 0; @@ -3046,16 +3145,63 @@ */ happy_meal_set_initial_advertisement(hp); - ether_setup(dev); + if (register_netdev(hp->dev)) { + printk(KERN_ERR "happymeal(PCI): Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + if (!qfe_slot) { + struct pci_dev *qpdev = qp->quattro_dev; + + prom_name[0] = 0; + if (!strncmp(dev->name, "eth", 3)) { + int i = simple_strtoul(dev->name + 3, NULL, 10); + sprintf(prom_name, "-%d", i + 3); + } + printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name); + if (qpdev->vendor == PCI_VENDOR_ID_DEC && + qpdev->device == PCI_DEVICE_ID_DEC_21153) + printk("DEC 21153 PCI Bridge\n"); + else + printk("unknown bridge %04x.%04x\n", + qpdev->vendor, qpdev->device); + } + + if (qfe_slot != -1) + printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ", + dev->name, qfe_slot); + else + printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", + dev->name); + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); + + printk("\n"); /* We are home free at this point, link us in to the happy * device list. */ - dev->ifindex = dev_new_index(); hp->next_module = root_happy_dev; root_happy_dev = hp; return 0; + +err_out_iounmap: + iounmap((void *)hp->gregs); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_clear_quattro: + if (qp != NULL) + qp->happy_meals[qfe_slot] = NULL; + + kfree(dev); + +err_out: + return err; } #endif @@ -3102,6 +3248,7 @@ PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) { if (pci_enable_device(pdev)) continue; + pci_set_master(pdev); cards++; happy_meal_pci_init(pdev); } @@ -3142,12 +3289,18 @@ while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; struct happy_meal *next = root_happy_dev->next_module; + struct net_device *dev = hp->dev; + + /* Unregister netdev before unmapping registers as this + * call can end up trying to access those registers. + */ + unregister_netdev(dev); #ifdef CONFIG_SBUS if (!(hp->happy_flags & HFLAG_PCI)) { if (hp->happy_flags & HFLAG_QUATTRO) { if (hp->qfe_parent != last_seen_qfe) { - free_irq(hp->dev->irq, hp->qfe_parent); + free_irq(dev->irq, hp->qfe_parent); last_seen_qfe = hp->qfe_parent; } } @@ -3170,12 +3323,35 @@ hp->happy_block, hp->hblock_dvma); iounmap((void *)hp->gregs); + pci_release_regions(hp->happy_dev); } #endif - unregister_netdev(hp->dev); - kfree(hp->dev); + kfree(dev); + root_happy_dev = next; } + + /* Now cleanup the quattro lists. */ +#ifdef CONFIG_SBUS + while (qfe_sbus_list) { + struct quattro *qfe = qfe_sbus_list; + struct quattro *next = qfe->next; + + kfree(qfe); + + qfe_sbus_list = next; + } +#endif +#ifdef CONFIG_PCI + while (qfe_pci_list) { + struct quattro *qfe = qfe_pci_list; + struct quattro *next = qfe->next; + + kfree(qfe); + + qfe_pci_list = next; + } +#endif } module_init(happy_meal_probe); diff -urN linux-2.4.18/drivers/net/sunhme.h linux-2.4.19-pre5/drivers/net/sunhme.h --- linux-2.4.18/drivers/net/sunhme.h Sat Mar 30 13:52:55 2002 +++ linux-2.4.19-pre5/drivers/net/sunhme.h Sat Mar 30 22:55:40 2002 @@ -431,7 +431,7 @@ unsigned long bigmacregs; /* BIGMAC core regs */ unsigned long tcvregs; /* MIF transceiver regs */ - __u32 hblock_dvma; /* DVMA visible address happy block */ + dma_addr_t hblock_dvma; /* DVMA visible address happy block */ unsigned int happy_flags; /* Driver state flags */ enum happy_transceiver tcvr_type; /* Kind of transceiver in use */ unsigned int happy_bursts; /* Get your mind out of the gutter */ diff -urN linux-2.4.18/drivers/net/sunlance.c linux-2.4.19-pre5/drivers/net/sunlance.c --- linux-2.4.18/drivers/net/sunlance.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sunlance.c Sat Mar 30 22:55:35 2002 @@ -62,12 +62,15 @@ * Anton Blanchard (anton@progsoc.uts.edu.au) * 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces. * David S. Miller (davem@redhat.com) + * 2.01: + * 11/08/01: Use library crc32 functions (Matt_Domsch@dell.com) + * */ #undef DEBUG_DRIVER static char version[] = - "sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + "sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; static char lancestr[] = "LANCE"; @@ -86,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -115,9 +119,6 @@ #define LANCE_LOG_RX_BUFFERS 4 #endif -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - #define LE_CSR0 0 #define LE_CSR1 1 #define LE_CSR2 2 @@ -1180,8 +1181,8 @@ volatile u16 *mcast_table = (u16 *) &ib->filter; struct dev_mc_list *dmi = dev->mc_list; char *addrs; - int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 crc; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { @@ -1211,19 +1212,7 @@ /* multicast address? */ if (!(*addrs & 1)) continue; - - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc = crc >> 26; if (lp->pio_buffer) { u16 tmp = sbus_readw(&mcast_table[crc>>4]); diff -urN linux-2.4.18/drivers/net/sunqe.c linux-2.4.19-pre5/drivers/net/sunqe.c --- linux-2.4.18/drivers/net/sunqe.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/sunqe.c Sat Mar 30 22:55:35 2002 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -622,17 +623,14 @@ return &qep->net_stats; } -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static void qe_set_multicast(struct net_device *dev) { struct sunqe *qep = (struct sunqe *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; u8 new_mconfig = qep->mconfig; char *addrs; - int i, j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; + int i; + u32 crc; /* Lock out others. */ netif_stop_queue(dev); @@ -660,18 +658,7 @@ if (!(*addrs & 1)) continue; - - crc = 0xffffffffU; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - if (test) - crc = crc ^ poly; - } - } + crc = ether_crc_le(6, addrs); crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } diff -urN linux-2.4.18/drivers/net/tc35815.c linux-2.4.19-pre5/drivers/net/tc35815.c --- linux-2.4.18/drivers/net/tc35815.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tc35815.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,1765 @@ +/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on skelton.c by Donald Becker. + * Copyright (C) 2000-2001 Toshiba Corporation + * + * Cleaned up various non portable stuff (save_and_cli etc) and made it + * build on x86 platforms -- Alan Cox 20020302 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * Switch to spin_lock not lock_kernel for scalability. + */ + +static const char *version = + "tc35815.c:v0.00-ac 26/07/2000 by Toshiba Corporation\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ +static const char* cardname = "TC35815CF"; +#define TC35815_PROC_ENTRY "net/tc35815" + +#define TC35815_MODULE_NAME "TC35815CF" +#define TX_TIMEOUT (4*HZ) + +/* First, a few definitions that the brave might change. */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef TC35815_DEBUG +#define TC35815_DEBUG 1 +#endif +static unsigned int tc35815_debug = TC35815_DEBUG; + +#define GATHER_TXINT /* On-Demand Tx Interrupt */ + +#define vtonocache(p) KSEG1ADDR(virt_to_phys(p)) + +/* + * Registers + */ +struct tc35815_regs { + volatile __u32 DMA_Ctl; /* 0x00 */ + volatile __u32 TxFrmPtr; + volatile __u32 TxThrsh; + volatile __u32 TxPollCtr; + volatile __u32 BLFrmPtr; + volatile __u32 RxFragSize; + volatile __u32 Int_En; + volatile __u32 FDA_Bas; + volatile __u32 FDA_Lim; /* 0x20 */ + volatile __u32 Int_Src; + volatile __u32 unused0[2]; + volatile __u32 PauseCnt; + volatile __u32 RemPauCnt; + volatile __u32 TxCtlFrmStat; + volatile __u32 unused1; + volatile __u32 MAC_Ctl; /* 0x40 */ + volatile __u32 CAM_Ctl; + volatile __u32 Tx_Ctl; + volatile __u32 Tx_Stat; + volatile __u32 Rx_Ctl; + volatile __u32 Rx_Stat; + volatile __u32 MD_Data; + volatile __u32 MD_CA; + volatile __u32 CAM_Adr; /* 0x60 */ + volatile __u32 CAM_Data; + volatile __u32 CAM_Ena; + volatile __u32 PROM_Ctl; + volatile __u32 PROM_Data; + volatile __u32 Algn_Cnt; + volatile __u32 CRC_Cnt; + volatile __u32 Miss_Cnt; +}; + +/* + * Bit assignments + */ +/* DMA_Ctl bit asign ------------------------------------------------------- */ +#define DMA_IntMask 0x00040000 /* 1:Interupt mask */ +#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ +#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ +#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */ +#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */ +#define DMA_TestMode 0x00002000 /* 1:Test Mode */ +#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */ +#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */ + +/* RxFragSize bit asign ---------------------------------------------------- */ +#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */ +#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */ + +/* MAC_Ctl bit asign ------------------------------------------------------- */ +#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */ +#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */ +#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */ +#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */ +#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */ +#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/ +#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */ +#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */ +#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */ +#define MAC_Reset 0x00000004 /* 1:Software Reset */ +#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */ +#define MAC_HaltReq 0x00000001 /* 1:Halt request */ + +/* PROM_Ctl bit asign ------------------------------------------------------ */ +#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */ +#define PROM_Read 0x00004000 /*10:Read operation */ +#define PROM_Write 0x00002000 /*01:Write operation */ +#define PROM_Erase 0x00006000 /*11:Erase operation */ + /*00:Enable or Disable Writting, */ + /* as specified in PROM_Addr. */ +#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */ + /*00xxxx: disable */ + +/* CAM_Ctl bit asign ------------------------------------------------------- */ +#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */ +#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/ + /* accept other */ +#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */ +#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */ +#define CAM_StationAcc 0x00000001 /* 1:unicast accept */ + +/* CAM_Ena bit asign ------------------------------------------------------- */ +#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */ +#define CAM_Ena_Mask ((1<= 2 */ +#define RX_FD_NUM 250 /* >= 32 */ +#define TX_FD_NUM 128 + +struct TxFD { + struct FDesc fd; + struct BDesc bd; + struct BDesc unused; +}; + +struct RxFD { + struct FDesc fd; + struct BDesc bd[0]; /* variable length */ +}; + +struct FrFD { + struct FDesc fd; + struct BDesc bd[RX_BUF_PAGES]; +}; + + +#if defined(__mips__) +/* MIPS weirdness */ +extern unsigned long tc_readl(volatile __u32 *addr); +extern void tc_writel(unsigned long data, volatile __u32 *addr); +#else +#define tc_readl readl +#define tc_writel writel +#endif + +dma_addr_t priv_dma_handle; + +/* Information that need to be kept for each board. */ +struct tc35815_local { + struct net_device *next_module; + + /* statistics */ + struct net_device_stats stats; + struct { + int max_tx_qlen; + int tx_ints; + int rx_ints; + } lstats; + + int tbusy; + int option; +#define TC35815_OPT_AUTO 0x00 +#define TC35815_OPT_10M 0x01 +#define TC35815_OPT_100M 0x02 +#define TC35815_OPT_FULLDUP 0x04 + int linkspeed; /* 10 or 100 */ + int fullduplex; + + /* + * Transmitting: Batch Mode. + * 1 BD in 1 TxFD. + * Receiving: Packing Mode. + * 1 circular FD for Free Buffer List. + * RX_BUG_PAGES BD in Free Buffer FD. + * One Free Buffer BD has PAGE_SIZE data buffer. + */ + struct pci_dev *pdev; + dma_addr_t fd_buf_dma_handle; + void * fd_buf; /* for TxFD, TxFD, FrFD */ + struct TxFD *tfd_base; + int tfd_start; + int tfd_end; + struct RxFD *rfd_base; + struct RxFD *rfd_limit; + struct RxFD *rfd_cur; + struct FrFD *fbl_ptr; + unsigned char fbl_curid; + dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; + void * data_buf[RX_BUF_PAGES]; /* packing */ +}; + +/* Index to functions, as function prototypes. */ + +static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq); + +static int tc35815_open(struct net_device *dev); +static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); +static void tc35815_tx_timeout(struct net_device *dev); +static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void tc35815_rx(struct net_device *dev); +static void tc35815_txdone(struct net_device *dev); +static int tc35815_close(struct net_device *dev); +static struct net_device_stats *tc35815_get_stats(struct net_device *dev); +static void tc35815_set_multicast_list(struct net_device *dev); + +static void tc35815_chip_reset(struct net_device *dev); +static void tc35815_chip_init(struct net_device *dev); +static void tc35815_phy_chip_init(struct net_device *dev); + +/* A list of all installed tc35815 devices. */ +static struct net_device *root_tc35815_dev = NULL; + +/* + * PCI device identifiers for "new style" Linux PCI Device Drivers + */ +static struct pci_device_id tc35815_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); + +int +tc35815_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int called = 0; + int err = 0; + int ret; + + if (called) + return -ENODEV; + called++; + + if (!pci_present()) + return -ENODEV; + + if (pdev) { + unsigned long pci_memaddr; + unsigned int pci_irq_line; + + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + + pci_memaddr = pci_resource_start (pdev, 1); + + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + return -ENODEV; + } + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + return -ENODEV; + } + + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + + if (!ret) { + if ((err = pci_enable_device(pdev)) < 0) { + printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err); + return err; + } + pci_set_master(pdev); + } + + return ret; + } + return -ENODEV; +} + +static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) +{ + static unsigned version_printed = 0; + int i; + struct tc35815_local *lp; + struct tc35815_regs *tr; + struct net_device *dev; + + /* Allocate a new 'dev' if needed. */ + dev = init_etherdev(NULL, 0); + if (dev == NULL) + return -ENOMEM; + + if (tc35815_debug && version_printed++ == 0) + printk(KERN_DEBUG "%s", version); + + printk(KERN_INFO "%s: %s found at %#x, irq %d\n", + dev->name, cardname, base_addr, irq); + + /* Fill in the 'dev' fields. */ + dev->irq = irq; + dev->base_addr = (unsigned long)ioremap(base_addr, + sizeof(struct tc35815_regs)); + tr = (struct tc35815_regs*)dev->base_addr; + + tc35815_chip_reset(dev); + + /* Retrieve and print the ethernet address. */ + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + cpu_relax(); + for (i = 0; i < 6; i += 2) { + unsigned short data; + tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + cpu_relax(); + data = tc_readl(&tr->PROM_Data); + dev->dev_addr[i] = data & 0xff; + dev->dev_addr[i+1] = data >> 8; + } + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct tc35815_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENODEV; + } + lp = dev->priv; + + lp->pdev = pdev; + + memset(lp, 0, sizeof(struct tc35815_local)); + + lp->next_module = root_tc35815_dev; + root_tc35815_dev = dev; + + if (dev->mem_start > 0) { + lp->option = dev->mem_start; + if ((lp->option & TC35815_OPT_10M) && + (lp->option & TC35815_OPT_100M)) { + /* if both speed speficied, auto select. */ + lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); + } + } + //XXX fixme + lp->option |= TC35815_OPT_10M; + + /* do auto negotiation */ + tc35815_phy_chip_init(dev); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); + + dev->open = tc35815_open; + dev->stop = tc35815_close; + dev->tx_timeout = tc35815_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->hard_start_xmit = tc35815_send_packet; + dev->get_stats = tc35815_get_stats; + dev->set_multicast_list = tc35815_set_multicast_list; + +#if 0 /* XXX called in init_etherdev */ + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); +#endif + + return 0; +} + + +static int +tc35815_init_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + unsigned long fd_addr; + + if (!lp->fd_buf) { + if (sizeof(struct FDesc) + + sizeof(struct BDesc) * RX_BUF_PAGES + + sizeof(struct FDesc) * RX_FD_NUM + + sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { + printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); + return -ENOMEM; + } + + if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) + return -ENOMEM; + for (i = 0; i < RX_BUF_PAGES; i++) { + if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) { + while (--i >= 0) { + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; + } + free_page((unsigned long)lp->fd_buf); + lp->fd_buf = 0; + return -ENOMEM; + } +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM); +#endif + } +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); +#endif + } else { + clear_page(lp->fd_buf); +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); +#endif + } +#ifdef __mips__ + fd_addr = (unsigned long)vtonocache(lp->fd_buf); +#else + fd_addr = (unsigned long)lp->fd_buf; +#endif + + /* Free Descriptors (for Receive) */ + lp->rfd_base = (struct RxFD *)fd_addr; + fd_addr += sizeof(struct RxFD) * RX_FD_NUM; + for (i = 0; i < RX_FD_NUM; i++) { + lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); + } + lp->rfd_cur = lp->rfd_base; + lp->rfd_limit = (struct RxFD *)(fd_addr - + sizeof(struct FDesc) - + sizeof(struct BDesc) * 30); + + /* Transmit Descriptors */ + lp->tfd_base = (struct TxFD *)fd_addr; + fd_addr += sizeof(struct TxFD) * TX_FD_NUM; + for (i = 0; i < TX_FD_NUM; i++) { + lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); + } + lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); + lp->tfd_start = 0; + lp->tfd_end = 0; + + /* Buffer List (for Receive) */ + lp->fbl_ptr = (struct FrFD *)fd_addr; + lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); + lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); + for (i = 0; i < RX_BUF_PAGES; i++) { + lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); + /* BDID is index of FrFD.bd[] */ + lp->fbl_ptr->bd[i].BDCtl = + cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); + } + lp->fbl_curid = 0; + + return 0; +} + +static void +tc35815_clear_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + for (i = 0; i < TX_FD_NUM; i++) { + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) + dev_kfree_skb_any(skb); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + } + + tc35815_init_queues(dev); +} + +static void +tc35815_free_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + if (lp->tfd_base) { + for (i = 0; i < TX_FD_NUM; i++) { + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) + dev_kfree_skb_any(skb); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + } + } + + lp->rfd_base = NULL; + lp->rfd_base = NULL; + lp->rfd_limit = NULL; + lp->rfd_cur = NULL; + lp->fbl_ptr = NULL; + + for (i = 0; i < RX_BUF_PAGES; i++) { + if (lp->data_buf[i]) + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; + } + if (lp->fd_buf) + __free_pages(lp->fd_buf, FD_PAGE_ORDER); + lp->fd_buf = NULL; +} + +static void +dump_txfd(struct TxFD *fd) +{ + printk("TxFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + printk("BD: "); + printk(" %08x %08x", + le32_to_cpu(fd->bd.BuffData), + le32_to_cpu(fd->bd.BDCtl)); + printk("\n"); +} + +static int +dump_rxfd(struct RxFD *fd) +{ + int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; + if (bd_count > 8) + bd_count = 8; + printk("RxFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD) + return 0; + printk("BD: "); + for (i = 0; i < bd_count; i++) + printk(" %08x %08x", + le32_to_cpu(fd->bd[i].BuffData), + le32_to_cpu(fd->bd[i].BDCtl)); + printk("\n"); + return bd_count; +} + +static void +dump_frfd(struct FrFD *fd) +{ + int i; + printk("FrFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + printk("BD: "); + for (i = 0; i < RX_BUF_PAGES; i++) + printk(" %08x %08x", + le32_to_cpu(fd->bd[i].BuffData), + le32_to_cpu(fd->bd[i].BDCtl)); + printk("\n"); +} + +static void +panic_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + printk("TxFD base %p, start %d, end %d\n", + lp->tfd_base, lp->tfd_start, lp->tfd_end); + printk("RxFD base %p limit %p cur %p\n", + lp->rfd_base, lp->rfd_limit, lp->rfd_cur); + printk("FrFD %p\n", lp->fbl_ptr); + for (i = 0; i < TX_FD_NUM; i++) + dump_txfd(&lp->tfd_base[i]); + for (i = 0; i < RX_FD_NUM; i++) { + int bd_count = dump_rxfd(&lp->rfd_base[i]); + i += (bd_count + 1) / 2; /* skip BDs */ + } + dump_frfd(lp->fbl_ptr); + panic("%s: Illegal queue state.", dev->name); +} + +#if 0 +static void print_buf(char *add, int length) +{ + int i; + int len = length; + + printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); + + if (len > 100) + len = 100; + for (i = 0; i < len; i++) { + printk(" %2.2X", (unsigned char) add[i]); + if (!(i % 16)) + printk("\n"); + } + printk("\n"); +} +#endif + +static void print_eth(char *add) +{ + int i; + + printk("print_eth(%08x)\n", (unsigned int) add); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i + 6]); + printk(" =>"); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i]); + printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int +tc35815_open(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + /* + * This is used if the interrupt line can turned off (shared). + * See 3c503.c for an example of selecting the IRQ at config-time. + */ + + if (dev->irq == 0 || + request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) { + return -EAGAIN; + } + + tc35815_chip_reset(dev); + + if (tc35815_init_queues(dev) != 0) { + free_irq(dev->irq, dev); + return -EAGAIN; + } + + /* Reset the hardware here. Don't forget to set the station address. */ + tc35815_chip_init(dev); + + lp->tbusy = 0; + netif_start_queue(dev); + + MOD_INC_USE_COUNT; + + return 0; +} + +static void tc35815_tx_timeout(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; + int flags; + + save_flags(flags); + cli(); + printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + restore_flags(flags); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; + + if (netif_queue_stopped(dev)) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, lp->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + dev_kfree_skb_any(skb); + } else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; + int flags; + lp->stats.tx_bytes += skb->len; + + +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)buf, length); +#endif + + save_flags(flags); + cli(); + + /* failsafe... */ + if (lp->tfd_start != lp->tfd_end) + tc35815_txdone(dev); + + + txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf)); + + txfd->bd.BDCtl = cpu_to_le32(length); + txfd->fd.FDSystem = cpu_to_le32((__u32)skb); + txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); + + if (lp->tfd_start == lp->tfd_end) { + /* Start DMA Transmitter. */ + txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); +#ifdef GATHER_TXINT + txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); +#endif + if (tc35815_debug > 2) { + printk("%s: starting TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + } else { + txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); + if (tc35815_debug > 2) { + printk("%s: queueing TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } + } + lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; + + dev->trans_start = jiffies; + + if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) { + /* we can send another packet */ + lp->tbusy = 0; + netif_start_queue(dev); + } else { + netif_stop_queue(dev); + if (tc35815_debug > 1) + printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); + } + restore_flags(flags); + } + + return 0; +} + +#define FATAL_ERROR_INT \ + (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) +static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) +{ + static int count; + printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", + dev->name, status); + + if (status & Int_IntPCI) + printk(" IntPCI"); + if (status & Int_DmParErr) + printk(" DmParErr"); + if (status & Int_IntNRAbt) + printk(" IntNRAbt"); + printk("\n"); + if (count++ > 100) + panic("%s: Too many fatal errors.", dev->name); + printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct tc35815_regs *tr; + struct tc35815_local *lp; + int status, boguscount = 0; + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); + return; + } + + tr = (struct tc35815_regs*)dev->base_addr; + lp = (struct tc35815_local *)dev->priv; + + do { + status = tc_readl(&tr->Int_Src); + if (status == 0) + break; + tc_writel(status, &tr->Int_Src); /* write to clear */ + + /* Fatal errors... */ + if (status & FATAL_ERROR_INT) { + tc35815_fatal_error_interrupt(dev, status); + break; + } + /* recoverable errors */ + if (status & Int_IntFDAEx) { + /* disable FDAEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Free Descriptor Area Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntBLEx) { + /* disable BLEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Buffer List Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntExBD) { + printk(KERN_WARNING + "%s: Excessive Buffer Descriptiors (%#x).\n", + dev->name, status); + lp->stats.rx_length_errors++; + } + /* normal notification */ + if (status & Int_IntMacRx) { + /* Got a packet(s). */ + lp->lstats.rx_ints++; + tc35815_rx(dev); + } + if (status & Int_IntMacTx) { + lp->lstats.tx_ints++; + tc35815_txdone(dev); + } + } while (++boguscount < 20) ; + + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +tc35815_rx(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned int fdctl; + int i; + int buf_free_count = 0; + int fd_free_count = 0; + + while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { + int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); + int pkt_len = fdctl & FD_FDLength_MASK; + struct RxFD *next_rfd; + int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; + + if (tc35815_debug > 2) + dump_rxfd(lp->rfd_cur); + if (status & Rx_Good) { + /* Malloc up new buffer. */ + struct sk_buff *skb; + unsigned char *data; + int cur_bd, offset; + + lp->stats.rx_bytes += pkt_len; + + skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + dev->name); + lp->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); /* 16 bit alignment */ + skb->dev = dev; + + data = skb_put(skb, pkt_len); + + /* copy from receive buffer */ + cur_bd = 0; + offset = 0; + while (offset < pkt_len && cur_bd < bd_count) { + int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & + BD_BuffLength_MASK; + void *rxbuf = + bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData)); +#ifdef __mips__ + dma_cache_inv((unsigned long)rxbuf, len); +#endif + memcpy(data + offset, rxbuf, len); + offset += len; + cur_bd++; + } + // print_buf(data,pkt_len); + if (tc35815_debug > 3) + print_eth(data); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + lp->stats.rx_packets++; + } else { + lp->stats.rx_errors++; + /* WORKAROUND: LongErr and CRCErr means Overflow. */ + if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { + status &= ~(Rx_LongErr|Rx_CRCErr); + status |= Rx_Over; + } + if (status & Rx_LongErr) lp->stats.rx_length_errors++; + if (status & Rx_Over) lp->stats.rx_fifo_errors++; + if (status & Rx_CRCErr) lp->stats.rx_crc_errors++; + if (status & Rx_Align) lp->stats.rx_frame_errors++; + } + + if (bd_count > 0) { + /* put Free Buffer back to controller */ + int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); + unsigned char id = + (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; + if (id >= RX_BUF_PAGES) { + printk("%s: invalid BDID.\n", dev->name); + panic_queues(dev); + } + /* free old buffers */ + while (lp->fbl_curid != id) { + bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl); + if (bdctl & BD_CownsBD) { + printk("%s: Freeing invalid BD.\n", + dev->name); + panic_queues(dev); + } + /* pass BD to controler */ + /* Note: BDLength was modified by chip. */ + lp->fbl_ptr->bd[lp->fbl_curid].BDCtl = + cpu_to_le32(BD_CownsBD | + (lp->fbl_curid << BD_RxBDID_SHIFT) | + PAGE_SIZE); + lp->fbl_curid = + (lp->fbl_curid + 1) % RX_BUF_PAGES; + if (tc35815_debug > 2) { + printk("%s: Entering new FBD %d\n", + dev->name, lp->fbl_curid); + dump_frfd(lp->fbl_ptr); + } + buf_free_count++; + } + } + + /* put RxFD back to controller */ + next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext)); +#ifdef __mips__ + next_rfd = (struct RxFD *)vtonocache(next_rfd); +#endif + if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { + printk("%s: RxFD FDNext invalid.\n", dev->name); + panic_queues(dev); + } + for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { + /* pass FD to controler */ + lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */ + lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); + lp->rfd_cur++; + fd_free_count++; + } + + lp->rfd_cur = next_rfd; + } + + /* re-enable BL/FDA Exhaust interupts. */ + if (fd_free_count) { + tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En); + if (buf_free_count) + tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En); + } +} + +#ifdef NO_CHECK_CARRIER +#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) +#else +#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr) +#endif + +static void +tc35815_check_tx_stat(struct net_device *dev, int status) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + const char *msg = NULL; + + /* count collisions */ + if (status & Tx_ExColl) + lp->stats.collisions += 16; + if (status & Tx_TxColl_MASK) + lp->stats.collisions += status & Tx_TxColl_MASK; + + /* WORKAROUND: ignore LostCrS in full duplex operation */ + if (lp->fullduplex) + status &= ~Tx_NCarr; + + if (!(status & TX_STA_ERR)) { + /* no error. */ + lp->stats.tx_packets++; + return; + } + + lp->stats.tx_errors++; + if (status & Tx_ExColl) { + lp->stats.tx_aborted_errors++; + msg = "Excessive Collision."; + } + if (status & Tx_Under) { + lp->stats.tx_fifo_errors++; + msg = "Tx FIFO Underrun."; + } + if (status & Tx_Defer) { + lp->stats.tx_fifo_errors++; + msg = "Excessive Deferral."; + } +#ifndef NO_CHECK_CARRIER + if (status & Tx_NCarr) { + lp->stats.tx_carrier_errors++; + msg = "Lost Carrier Sense."; + } +#endif + if (status & Tx_LateColl) { + lp->stats.tx_aborted_errors++; + msg = "Late Collision."; + } + if (status & Tx_TxPar) { + lp->stats.tx_fifo_errors++; + msg = "Transmit Parity Error."; + } + if (status & Tx_SQErr) { + lp->stats.tx_heartbeat_errors++; + msg = "Signal Quality Error."; + } + if (msg) + printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); +} + +static void +tc35815_txdone(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + struct TxFD *txfd; + unsigned int fdctl; + int num_done = 0; + + txfd = &lp->tfd_base[lp->tfd_end]; + while (lp->tfd_start != lp->tfd_end && + !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) { + int status = le32_to_cpu(txfd->fd.FDStat); + struct sk_buff *skb; + unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); + + if (tc35815_debug > 2) { + printk("%s: complete TxFD.\n", dev->name); + dump_txfd(txfd); + } + tc35815_check_tx_stat(dev, status); + + skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem); + if (skb) { + dev_kfree_skb_any(skb); + } + txfd->fd.FDSystem = cpu_to_le32(0); + + num_done++; + lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; + txfd = &lp->tfd_base[lp->tfd_end]; + if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) { + printk("%s: TxFD FDNext invalid.\n", dev->name); + panic_queues(dev); + } + if (fdnext & FD_Next_EOL) { + /* DMA Transmitter has been stopping... */ + if (lp->tfd_end != lp->tfd_start) { + int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; + struct TxFD* txhead = &lp->tfd_base[head]; + int qlen = (lp->tfd_start + TX_FD_NUM + - lp->tfd_end) % TX_FD_NUM; + + if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { + printk("%s: TxFD FDCtl invalid.\n", dev->name); + panic_queues(dev); + } + /* log max queue length */ + if (lp->lstats.max_tx_qlen < qlen) + lp->lstats.max_tx_qlen = qlen; + + + /* start DMA Transmitter again */ + txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL); +#ifdef GATHER_TXINT + txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); +#endif + if (tc35815_debug > 2) { + printk("%s: start TxFD on queue.\n", + dev->name); + dump_txfd(txfd); + } + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + } + break; + } + } + + if (num_done > 0 && lp->tbusy) { + lp->tbusy = 0; + netif_start_queue(dev); + } +} + +/* The inverse routine to tc35815_open(). */ +static int +tc35815_close(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + + lp->tbusy = 1; + netif_stop_queue(dev); + + /* Flush the Tx and disable Rx here. */ + + tc35815_chip_reset(dev); + free_irq(dev->irq, dev); + + tc35815_free_queues(dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats *tc35815_get_stats(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned long flags; + + if (netif_running(dev)) { + save_flags(flags); + cli(); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); + restore_flags(flags); + } + + return &lp->stats; +} + +static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr) +{ + int cam_index = index * 6; + unsigned long cam_data; + unsigned long saved_addr; + saved_addr = tc_readl(&tr->CAM_Adr); + + if (tc35815_debug > 1) { + int i; + printk(KERN_DEBUG "%s: CAM %d:", cardname, index); + for (i = 0; i < 6; i++) + printk(" %02x", addr[i]); + printk("\n"); + } + if (index & 1) { + /* read modify write */ + tc_writel(cam_index - 2, &tr->CAM_Adr); + cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000; + cam_data |= addr[0] << 8 | addr[1]; + tc_writel(cam_data, &tr->CAM_Data); + /* write whole word */ + tc_writel(cam_index + 2, &tr->CAM_Adr); + cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]; + tc_writel(cam_data, &tr->CAM_Data); + } else { + /* write whole word */ + tc_writel(cam_index, &tr->CAM_Adr); + cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; + tc_writel(cam_data, &tr->CAM_Data); + /* read modify write */ + tc_writel(cam_index + 4, &tr->CAM_Adr); + cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff; + cam_data |= addr[4] << 24 | (addr[5] << 16); + tc_writel(cam_data, &tr->CAM_Data); + } + + if (tc35815_debug > 2) { + int i; + for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { + tc_writel(i * 4, &tr->CAM_Adr); + printk("CAM 0x%x: %08x", + i * 4, tc_readl(&tr->CAM_Data)); + } + } + tc_writel(saved_addr, &tr->CAM_Adr); +} + + +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ +static void +tc35815_set_multicast_list(struct net_device *dev) +{ + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + + if (dev->flags&IFF_PROMISC) + { + /* Enable promiscuous mode */ + tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); + } + else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3) + { + /* CAM 0, 1, 20 are reserved. */ + /* Disable promiscuous mode, use normal mode. */ + tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl); + } + else if(dev->mc_count) + { + struct dev_mc_list* cur_addr = dev->mc_list; + int i; + int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE); + + tc_writel(0, &tr->CAM_Ctl); + /* Walk the address list, and load the filter */ + for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + if (!cur_addr) + break; + /* entry 0,1 is reserved. */ + tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr); + ena_bits |= CAM_Ena_Bit(i + 2); + } + tc_writel(ena_bits, &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + } + else { + tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + } +} + +static unsigned long tc_phy_read(struct tc35815_regs *tr, int phy, int phy_reg) +{ + unsigned long data; + int flags; + save_flags(flags); + cli(); + tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + cpu_relax(); + data = tc_readl(&tr->MD_Data); + restore_flags(flags); + return data; +} + +static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) +{ + int flags; + save_flags(flags); + cli(); + tc_writel(d, &tr->MD_Data); + tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + cpu_relax(); + restore_flags(flags); +} + +static void tc35815_phy_chip_init(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + static int first = 1; + unsigned short ctl; + + if (first) { + unsigned short id0, id1; + int count; + first = 0; + + /* first data written to the PHY will be an ID number */ + tc_phy_write(0, tr, 0, MII_CONTROL); /* ID:0 */ +#if 0 + tc_phy_write(MIICNTL_RESET, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Resetting PHY...", dev->name); + while (tc_phy_read(tr, 0, MII_CONTROL) & MIICNTL_RESET) + ; + printk("\n"); + tc_phy_write(MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0, + MII_CONTROL); +#endif + id0 = tc_phy_read(tr, 0, MII_PHY_ID0); + id1 = tc_phy_read(tr, 0, MII_PHY_ID1); + printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name, + id0, id1); + if (lp->option & TC35815_OPT_10M) { + lp->linkspeed = 10; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + } else if (lp->option & TC35815_OPT_100M) { + lp->linkspeed = 100; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + } else { + /* auto negotiation */ + unsigned long neg_result; + tc_phy_write(MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Auto Negotiation...", dev->name); + count = 0; + while (!(tc_phy_read(tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) { + if (count++ > 5000) { + printk(" failed. Assume 10Mbps\n"); + lp->linkspeed = 10; + lp->fullduplex = 0; + goto done; + } + if (count % 512 == 0) + printk("."); + mdelay(1); + } + printk(" done.\n"); + neg_result = tc_phy_read(tr, 0, MII_ANLPAR); + if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX)) + lp->linkspeed = 100; + else + lp->linkspeed = 10; + if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX)) + lp->fullduplex = 1; + else + lp->fullduplex = 0; + done: + ; + } + } + + ctl = 0; + if (lp->linkspeed == 100) + ctl |= MIICNTL_SPEED; + if (lp->fullduplex) + ctl |= MIICNTL_FDX; + tc_phy_write(ctl, tr, 0, MII_CONTROL); + + if (lp->fullduplex) { + tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); + } +} + +static void tc35815_chip_reset(struct net_device *dev) +{ + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + + /* reset the controller */ + tc_writel(MAC_Reset, &tr->MAC_Ctl); + while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) + cpu_relax(); + + tc_writel(0, &tr->MAC_Ctl); + + /* initialize registers to default value */ + tc_writel(0, &tr->DMA_Ctl); + tc_writel(0, &tr->TxThrsh); + tc_writel(0, &tr->TxPollCtr); + tc_writel(0, &tr->RxFragSize); + tc_writel(0, &tr->Int_En); + tc_writel(0, &tr->FDA_Bas); + tc_writel(0, &tr->FDA_Lim); + tc_writel(0xffffffff, &tr->Int_Src); /* Write 1 to clear */ + tc_writel(0, &tr->CAM_Ctl); + tc_writel(0, &tr->Tx_Ctl); + tc_writel(0, &tr->Rx_Ctl); + tc_writel(0, &tr->CAM_Ena); + (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ + +} + +static void tc35815_chip_init(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + int flags; + unsigned long txctl = TX_CTL_CMD; + + tc35815_phy_chip_init(dev); + + /* load station address to CAM */ + tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr); + + /* Enable CAM (broadcast and unicast) */ + tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + + save_flags(flags); + cli(); + + tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); + + tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ + tc_writel(0, &tr->TxPollCtr); /* Batch mode */ + tc_writel(TX_THRESHOLD, &tr->TxThrsh); + tc_writel(INT_EN_CMD, &tr->Int_En); + + /* set queues */ + tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas); + tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, + &tr->FDA_Lim); + /* + * Activation method: + * First, enable eht MAC Transmitter and the DMA Receive circuits. + * Then enable the DMA Transmitter and the MAC Receive circuits. + */ + tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ + tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ + /* start MAC transmitter */ + /* WORKAROUND: ignore LostCrS in full duplex operation */ + if (lp->fullduplex) + txctl = TX_CTL_CMD & ~Tx_EnLCarr; +#ifdef GATHER_TXINT + txctl &= ~Tx_EnComp; /* disable global tx completion int. */ +#endif + tc_writel(txctl, &tr->Tx_Ctl); +#if 0 /* No need to polling */ + tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ +#endif + restore_flags(flags); +} + + +/* XXX */ +void +tc35815_killall(void) +{ + struct net_device *dev; + + for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { + if (dev->flags&IFF_UP){ + dev->stop(dev); + } + } +} + +static struct pci_driver tc35815_driver = { + name: TC35815_MODULE_NAME, + probe: tc35815_probe, + remove: NULL, + id_table: tc35815_pci_tbl, +}; + +static int __init tc35815_init_module(void) +{ + int err; + + if ((err = pci_module_init(&tc35815_driver)) < 0 ) + return err; + else + return 0; +} + +static void __exit tc35815_cleanup_module(void) +{ + struct net_device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_tc35815_dev) { + struct net_device *dev = root_tc35815_dev; + next_dev = ((struct tc35815_local *)dev->priv)->next_module; + kfree(dev->priv); + iounmap((void *)(dev->base_addr)); + unregister_netdev(dev); + kfree(dev); + root_tc35815_dev = next_dev; + } +} +module_init(tc35815_init_module); +module_exit(tc35815_cleanup_module); diff -urN linux-2.4.18/drivers/net/tg3.c linux-2.4.19-pre5/drivers/net/tg3.c --- linux-2.4.18/drivers/net/tg3.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tg3.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,6403 @@ +/* $Id: tg3.c,v 1.43.2.80 2002/03/14 00:10:04 davem Exp $ + * tg3.c: Broadcom Tigon3 ethernet driver. + * + * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com) + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef PCI_DMA_BUS_IS_PHYS +#define PCI_DMA_BUS_IS_PHYS 1 +#endif + +/* Either I can't figure out how they secretly implemented it (ie. RXD flags + * for mini ring, where it should go in NIC sram, and how many entries the NIC + * firmware expects) or it isn't really fully implemented. Perhaps Broadcom + * wants people to pay for a "performance enhanced" version of their firmware + + * binary-only driver that has the mini ring actually implemented. + * These kids today... -DaveM + */ +#define TG3_MINI_RING_WORKS 0 + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define TG3_VLAN_TAG_USED 1 +#else +#define TG3_VLAN_TAG_USED 0 +#endif + +#include "tg3.h" + +#define DRV_MODULE_NAME "tg3" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "0.97" +#define DRV_MODULE_RELDATE "Mar 13, 2002" + +#define TG3_DEF_MAC_MODE 0 +#define TG3_DEF_RX_MODE 0 +#define TG3_DEF_TX_MODE 0 +#define TG3_DEF_MSG_ENABLE \ + (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | \ + NETIF_MSG_IFUP | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + +/* length of time before we decide the hardware is borked, + * and dev->tx_timeout() should be called to fix the problem + */ +#define TG3_TX_TIMEOUT (5 * HZ) + +/* hardware minimum and maximum for a single frame's data payload */ +#define TG3_MIN_MTU 60 +#define TG3_MAX_MTU 9000 + +/* These numbers seem to be hard coded in the NIC firmware somehow. + * You can't change the ring sizes, but you can change where you place + * them in the NIC onboard memory. + */ +#define TG3_RX_RING_SIZE 512 +#define TG3_DEF_RX_RING_PENDING 200 +#if TG3_MINI_RING_WORKS +#define TG3_RX_MINI_RING_SIZE 256 /* ??? */ +#define TG3_DEF_RX_MINI_RING_PENDING 100 +#endif +#define TG3_RX_JUMBO_RING_SIZE 256 +#define TG3_DEF_RX_JUMBO_RING_PENDING 100 +#define TG3_RX_RCB_RING_SIZE 1024 +#define TG3_TX_RING_SIZE 512 +#define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) + +#define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ + TG3_RX_RING_SIZE) +#if TG3_MINI_RING_WORKS +#define TG3_RX_MINI_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ + TG3_RX_MINI_RING_SIZE) +#endif +#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ + TG3_RX_JUMBO_RING_SIZE) +#define TG3_RX_RCB_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ + TG3_RX_RCB_RING_SIZE) +#define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ + TG3_TX_RING_SIZE) +#define TX_RING_GAP(TP) \ + (TG3_TX_RING_SIZE - (TP)->tx_pending) +#define TX_BUFFS_AVAIL(TP) \ + (((TP)->tx_cons <= (TP)->tx_prod) ? \ + (TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod : \ + (TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP)) +#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) + +#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) +#if TG3_MINI_RING_WORKS +#define RX_MINI_PKT_BUF_SZ (256 + tp->rx_offset + 64) +#endif +#define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) + +/* minimum number of free TX descriptors required to wake up TX process */ +#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4) + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@mandrakesoft.com)"); +MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(tg3_debug, "i"); +MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); + +static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ + +static struct pci_device_id tg3_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); + +static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) +{ + if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { + unsigned long flags; + + spin_lock_irqsave(&tp->indirect_lock, flags); + pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); + spin_unlock_irqrestore(&tp->indirect_lock, flags); + } else { + writel(val, tp->regs + off); + } +} + +#define tw32(reg,val) tg3_write_indirect_reg32(tp,(reg),(val)) +#define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)) +#define tw16(reg,val) writew(((val) & 0xffff), tp->regs + (reg)) +#define tw8(reg,val) writeb(((val) & 0xff), tp->regs + (reg)) +#define tr32(reg) readl(tp->regs + (reg)) +#define tr16(reg) readw(tp->regs + (reg)) +#define tr8(reg) readb(tp->regs + (reg)) + +static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&tp->indirect_lock, flags); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + spin_unlock_irqrestore(&tp->indirect_lock, flags); +} + +static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) +{ + unsigned long flags; + + spin_lock_irqsave(&tp->indirect_lock, flags); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + spin_unlock_irqrestore(&tp->indirect_lock, flags); +} + +static void tg3_disable_ints(struct tg3 *tp) +{ + tw32(TG3PCI_MISC_HOST_CTRL, + (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); +} + +static void tg3_enable_ints(struct tg3 *tp) +{ + tw32(TG3PCI_MISC_HOST_CTRL, + (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + + if (tp->hw_status->status & SD_STATUS_UPDATED) + tw32(GRC_LOCAL_CTRL, + tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); +} + +#define PHY_BUSY_LOOPS 5000 + +static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) +{ + u32 frame_val; + int loops, ret; + + if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { + tw32(MAC_MI_MODE, + (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); + udelay(40); + } + + *val = 0xffffffff; + + frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + MI_COM_PHY_ADDR_MASK); + frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & + MI_COM_REG_ADDR_MASK); + frame_val |= (MI_COM_CMD_READ | MI_COM_START); + + tw32(MAC_MI_COM, frame_val); + + loops = PHY_BUSY_LOOPS; + while (loops-- > 0) { + frame_val = tr32(MAC_MI_COM); + + if ((frame_val & MI_COM_BUSY) == 0) { + udelay(5); + frame_val = tr32(MAC_MI_COM); + break; + } + udelay(10); + } + + ret = -EBUSY; + if (loops > 0) { + *val = frame_val & MI_COM_DATA_MASK; + ret = 0; + } + + if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { + tw32(MAC_MI_MODE, tp->mi_mode); + udelay(40); + } + + return ret; +} + +static int tg3_writephy(struct tg3 *tp, int reg, u32 val) +{ + u32 frame_val; + int loops, ret; + + if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { + tw32(MAC_MI_MODE, + (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); + udelay(40); + } + + frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + MI_COM_PHY_ADDR_MASK); + frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & + MI_COM_REG_ADDR_MASK); + frame_val |= (val & MI_COM_DATA_MASK); + frame_val |= (MI_COM_CMD_WRITE | MI_COM_START); + + tw32(MAC_MI_COM, frame_val); + + loops = PHY_BUSY_LOOPS; + while (loops-- > 0) { + frame_val = tr32(MAC_MI_COM); + if ((frame_val & MI_COM_BUSY) == 0) { + udelay(5); + frame_val = tr32(MAC_MI_COM); + break; + } + udelay(10); + } + + ret = -EBUSY; + if (loops > 0) + ret = 0; + + if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { + tw32(MAC_MI_MODE, tp->mi_mode); + udelay(40); + } + + return ret; +} + +/* This will reset the tigon3 PHY if there is no valid + * link unless the FORCE argument is non-zero. + */ +static int tg3_phy_reset(struct tg3 *tp, int force) +{ + u32 phy_status, phy_control; + int err, limit; + + err = tg3_readphy(tp, MII_BMSR, &phy_status); + err |= tg3_readphy(tp, MII_BMSR, &phy_status); + if (err != 0) + return -EBUSY; + + /* If we have link, and not forcing a reset, then nothing + * to do. + */ + if ((phy_status & BMSR_LSTATUS) != 0 && (force == 0)) + return 0; + + /* OK, reset it, and poll the BMCR_RESET bit until it + * clears or we time out. + */ + phy_control = BMCR_RESET; + err = tg3_writephy(tp, MII_BMCR, phy_control); + if (err != 0) + return -EBUSY; + + limit = 5000; + while (limit--) { + err = tg3_readphy(tp, MII_BMCR, &phy_control); + if (err != 0) + return -EBUSY; + + if ((phy_control & BMCR_RESET) == 0) { + udelay(40); + return 0; + } + udelay(10); + } + + return -EBUSY; +} + +static int tg3_setup_phy(struct tg3 *); +static int tg3_halt(struct tg3 *); + +static int tg3_set_power_state(struct tg3 *tp, int state) +{ + u32 misc_host_ctrl; + u16 power_control, power_caps; + int pm = tp->pm_cap; + + /* Make sure register accesses (indirect or otherwise) + * will function correctly. + */ + pci_write_config_dword(tp->pdev, + TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + + pci_read_config_word(tp->pdev, + pm + PCI_PM_CTRL, + &power_control); + power_control |= PCI_PM_CTRL_PME_STATUS; + power_control &= ~(PCI_PM_CTRL_STATE_MASK); + switch (state) { + case 0: + power_control |= 0; + pci_write_config_word(tp->pdev, + pm + PCI_PM_CTRL, + power_control); + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + return 0; + + case 1: + power_control |= 1; + break; + + case 2: + power_control |= 2; + break; + + case 3: + power_control |= 3; + break; + + default: + printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n", + tp->dev->name, state); + return -EINVAL; + }; + + power_control |= PCI_PM_CTRL_PME_ENABLE; + + misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); + tw32(TG3PCI_MISC_HOST_CTRL, + misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); + + if (tp->link_config.phy_is_low_power == 0) { + tp->link_config.phy_is_low_power = 1; + tp->link_config.orig_speed = tp->link_config.speed; + tp->link_config.orig_duplex = tp->link_config.duplex; + tp->link_config.orig_autoneg = tp->link_config.autoneg; + } + + tp->link_config.speed = SPEED_10; + tp->link_config.autoneg = AUTONEG_ENABLE; + tg3_setup_phy(tp); + + tg3_halt(tp); + + pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); + + if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { + u32 mac_mode; + + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + + mac_mode = MAC_MODE_PORT_MODE_MII | + MAC_MODE_LINK_POLARITY; + + if (((power_caps & PCI_PM_CAP_PME_D3cold) && + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) + mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; + + tw32(MAC_MODE, mac_mode); + tw32(MAC_RX_MODE, RX_MODE_ENABLE); + } + + if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) { + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE | + CLOCK_CTRL_ALTCLK)); + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE | + CLOCK_CTRL_44MHZ_CORE)); + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE | + CLOCK_CTRL_ALTCLK | + CLOCK_CTRL_44MHZ_CORE)); + } else { + tw32(TG3PCI_CLOCK_CTRL, + (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE | + CLOCK_CTRL_ALTCLK | + CLOCK_CTRL_PWRDOWN_PLL133)); + } + + udelay(40); + + if ((power_caps & PCI_PM_CAP_PME_D3cold) && + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + /* Move to auxilliary power. */ + tw32(GRC_LOCAL_CTRL, + (GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1)); + } + + /* Finally, set the new power state. */ + pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); + + return 0; +} + +static void tg3_link_report(struct tg3 *tp) +{ + if (!netif_carrier_ok(tp->dev)) { + printk("%s: Link is down.\n", tp->dev->name); + } else { + printk("%s: Link is up at %d Mbps, %s duplex.\n", + tp->dev->name, + (tp->link_config.active_speed == SPEED_1000 ? + 1000 : + (tp->link_config.active_speed == SPEED_100 ? + 100 : 10)), + (tp->link_config.active_duplex == DUPLEX_FULL ? + "full" : "half")); + + printk("%s: Flow control is %s for TX and %s for RX.\n", + tp->dev->name, + (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off", + (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off"); + } +} + +static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) +{ + u32 new_tg3_flags = 0; + + if (local_adv & ADVERTISE_PAUSE_CAP) { + if (local_adv & ADVERTISE_PAUSE_ASYM) { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + else if (remote_adv & LPA_PAUSE_ASYM) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE); + } else { + if (remote_adv & LPA_PAUSE_CAP) + new_tg3_flags |= + (TG3_FLAG_RX_PAUSE | + TG3_FLAG_TX_PAUSE); + } + } else if (local_adv & ADVERTISE_PAUSE_ASYM) { + if ((remote_adv & LPA_PAUSE_CAP) && + (remote_adv & LPA_PAUSE_ASYM)) + new_tg3_flags |= TG3_FLAG_TX_PAUSE; + } + + tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); + tp->tg3_flags |= new_tg3_flags; + + if (new_tg3_flags & TG3_FLAG_RX_PAUSE) + tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; + else + tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; + + if (new_tg3_flags & TG3_FLAG_TX_PAUSE) + tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; + else + tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; +} + +static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex) +{ + switch (val & MII_TG3_AUX_STAT_SPDMASK) { + case MII_TG3_AUX_STAT_10HALF: + *speed = SPEED_10; + *duplex = DUPLEX_HALF; + break; + + case MII_TG3_AUX_STAT_10FULL: + *speed = SPEED_10; + *duplex = DUPLEX_FULL; + break; + + case MII_TG3_AUX_STAT_100HALF: + *speed = SPEED_100; + *duplex = DUPLEX_HALF; + break; + + case MII_TG3_AUX_STAT_100FULL: + *speed = SPEED_100; + *duplex = DUPLEX_FULL; + break; + + case MII_TG3_AUX_STAT_1000HALF: + *speed = SPEED_1000; + *duplex = DUPLEX_HALF; + break; + + case MII_TG3_AUX_STAT_1000FULL: + *speed = SPEED_1000; + *duplex = DUPLEX_FULL; + break; + + default: + *speed = SPEED_INVALID; + *duplex = DUPLEX_INVALID; + break; + }; +} + +static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link) +{ + u32 new_adv; + int i; + + if (tp->link_config.phy_is_low_power) { + /* Entering low power mode. Disable gigabit and + * 100baseT advertisements. + */ + tg3_writephy(tp, MII_TG3_CTRL, 0); + + new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + + tg3_writephy(tp, MII_ADVERTISE, new_adv); + } else if (tp->link_config.speed == SPEED_INVALID) { + tp->link_config.advertising = + (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_MII); + + if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) + tp->link_config.advertising &= + ~(ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + if (tp->link_config.advertising & ADVERTISED_10baseT_Half) + new_adv |= ADVERTISE_10HALF; + if (tp->link_config.advertising & ADVERTISED_10baseT_Full) + new_adv |= ADVERTISE_10FULL; + if (tp->link_config.advertising & ADVERTISED_100baseT_Half) + new_adv |= ADVERTISE_100HALF; + if (tp->link_config.advertising & ADVERTISED_100baseT_Full) + new_adv |= ADVERTISE_100FULL; + tg3_writephy(tp, MII_ADVERTISE, new_adv); + + if (tp->link_config.advertising & + (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { + new_adv = 0; + if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) + new_adv |= MII_TG3_CTRL_ADV_1000_HALF; + if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) + new_adv |= MII_TG3_CTRL_ADV_1000_FULL; + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + new_adv |= (MII_TG3_CTRL_AS_MASTER | + MII_TG3_CTRL_ENABLE_AS_MASTER); + tg3_writephy(tp, MII_TG3_CTRL, new_adv); + } else { + tg3_writephy(tp, MII_TG3_CTRL, 0); + } + } else { + /* Asking for a specific link mode. */ + if (tp->link_config.speed == SPEED_1000) { + new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; + tg3_writephy(tp, MII_ADVERTISE, new_adv); + + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = MII_TG3_CTRL_ADV_1000_FULL; + else + new_adv = MII_TG3_CTRL_ADV_1000_HALF; + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + new_adv |= (MII_TG3_CTRL_AS_MASTER | + MII_TG3_CTRL_ENABLE_AS_MASTER); + tg3_writephy(tp, MII_TG3_CTRL, new_adv); + } else { + tg3_writephy(tp, MII_TG3_CTRL, 0); + + new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; + if (tp->link_config.speed == SPEED_100) { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv |= ADVERTISE_100FULL; + else + new_adv |= ADVERTISE_100HALF; + } else { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv |= ADVERTISE_10FULL; + else + new_adv |= ADVERTISE_10HALF; + } + tg3_writephy(tp, MII_ADVERTISE, new_adv); + } + } + + if (tp->link_config.autoneg == AUTONEG_DISABLE && + tp->link_config.speed != SPEED_INVALID) { + u32 bmcr, orig_bmcr; + + tp->link_config.active_speed = tp->link_config.speed; + tp->link_config.active_duplex = tp->link_config.duplex; + + bmcr = 0; + switch (tp->link_config.speed) { + default: + case SPEED_10: + break; + + case SPEED_100: + bmcr |= BMCR_SPEED100; + break; + + case SPEED_1000: + bmcr |= TG3_BMCR_SPEED1000; + break; + }; + + if (tp->link_config.duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + + tg3_readphy(tp, MII_BMCR, &orig_bmcr); + if (bmcr != orig_bmcr) { + tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK); + for (i = 0; i < 15000; i++) { + u32 tmp; + + udelay(10); + tg3_readphy(tp, MII_BMSR, &tmp); + tg3_readphy(tp, MII_BMSR, &tmp); + if (!(tmp & BMSR_LSTATUS)) { + udelay(40); + break; + } + } + tg3_writephy(tp, MII_BMCR, bmcr); + udelay(40); + } + } else { + tg3_writephy(tp, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART); + } + + if (wait_for_link) { + tp->link_config.active_speed = SPEED_INVALID; + tp->link_config.active_duplex = DUPLEX_INVALID; + for (i = 0; i < 300000; i++) { + u32 tmp; + + udelay(10); + tg3_readphy(tp, MII_BMSR, &tmp); + tg3_readphy(tp, MII_BMSR, &tmp); + if (!(tmp & BMSR_LSTATUS)) + continue; + + tg3_readphy(tp, MII_TG3_AUX_STAT, &tmp); + tg3_aux_stat_to_speed_duplex(tp, tmp, + &tp->link_config.active_speed, + &tp->link_config.active_duplex); + } + if (tp->link_config.active_speed == SPEED_INVALID) + return -EINVAL; + } + + return 0; +} + +static int tg3_init_5401phy_dsp(struct tg3 *tp) +{ + int err; + + /* Turn off tap power management. */ + err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20); + + err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0012); + err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1804); + + err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0013); + err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1204); + + err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006); + err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0132); + + err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006); + err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0232); + + err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f); + err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0a20); + + udelay(40); + + return err; +} + +static int tg3_setup_copper_phy(struct tg3 *tp) +{ + int current_link_up; + u32 bmsr, dummy; + u16 current_speed; + u8 current_duplex; + int i, err; + + tw32(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + + tp->mi_mode = MAC_MI_MODE_BASE; + tw32(MAC_MI_MODE, tp->mi_mode); + udelay(40); + + if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { + tg3_readphy(tp, MII_BMSR, &bmsr); + tg3_readphy(tp, MII_BMSR, &bmsr); + + if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) + bmsr = 0; + + if (!(bmsr & BMSR_LSTATUS)) { + err = tg3_init_5401phy_dsp(tp); + if (err) + return err; + + tg3_readphy(tp, MII_BMSR, &bmsr); + for (i = 0; i < 1000; i++) { + udelay(10); + tg3_readphy(tp, MII_BMSR, &bmsr); + if (bmsr & BMSR_LSTATUS) { + udelay(40); + break; + } + } + + if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 && + !(bmsr & BMSR_LSTATUS) && + tp->link_config.active_speed == SPEED_1000) { + err = tg3_phy_reset(tp, 1); + if (!err) + err = tg3_init_5401phy_dsp(tp); + if (err) + return err; + } + } + } else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) { + /* 5701 {A0,B0} CRC bug workaround */ + tg3_writephy(tp, 0x15, 0x0a75); + tg3_writephy(tp, 0x1c, 0x8c68); + tg3_writephy(tp, 0x1c, 0x8d68); + tg3_writephy(tp, 0x1c, 0x8c68); + } + + /* Clear pending interrupts... */ + tg3_readphy(tp, MII_TG3_ISTAT, &dummy); + tg3_readphy(tp, MII_TG3_ISTAT, &dummy); + + if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) + tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG); + else + tg3_writephy(tp, MII_TG3_IMASK, ~0); + + if (tp->led_mode == led_mode_three_link) + tg3_writephy(tp, MII_TG3_EXT_CTRL, + MII_TG3_EXT_CTRL_LNK3_LED_MODE); + else + tg3_writephy(tp, MII_TG3_EXT_CTRL, 0); + + current_link_up = 0; + current_speed = SPEED_INVALID; + current_duplex = DUPLEX_INVALID; + + tg3_readphy(tp, MII_BMSR, &bmsr); + tg3_readphy(tp, MII_BMSR, &bmsr); + + if (bmsr & BMSR_LSTATUS) { + u32 aux_stat, bmcr; + + tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat); + for (i = 0; i < 2000; i++) { + udelay(10); + tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat); + if (aux_stat) + break; + } + + tg3_aux_stat_to_speed_duplex(tp, aux_stat, + ¤t_speed, + ¤t_duplex); + tg3_readphy(tp, MII_BMCR, &bmcr); + tg3_readphy(tp, MII_BMCR, &bmcr); + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + if (bmcr & BMCR_ANENABLE) { + u32 gig_ctrl; + + current_link_up = 1; + + /* Force autoneg restart if we are exiting + * low power mode. + */ + tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl); + if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF | + MII_TG3_CTRL_ADV_1000_FULL))) { + current_link_up = 0; + } + } else { + current_link_up = 0; + } + } else { + if (!(bmcr & BMCR_ANENABLE) && + tp->link_config.speed == current_speed && + tp->link_config.duplex == current_duplex) { + current_link_up = 1; + } else { + current_link_up = 0; + } + } + + tp->link_config.active_speed = current_speed; + tp->link_config.active_duplex = current_duplex; + } + + if (current_link_up == 1 && + (tp->link_config.active_duplex == DUPLEX_FULL) && + (tp->link_config.autoneg == AUTONEG_ENABLE)) { + u32 local_adv, remote_adv; + + tg3_readphy(tp, MII_ADVERTISE, &local_adv); + local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + + tg3_readphy(tp, MII_LPA, &remote_adv); + remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM); + + /* If we are not advertising full pause capability, + * something is wrong. Bring the link down and reconfigure. + */ + if (local_adv != ADVERTISE_PAUSE_CAP) { + current_link_up = 0; + } else { + tg3_setup_flow_control(tp, local_adv, remote_adv); + } + } + + if (current_link_up == 0) { + u32 tmp; + + tg3_phy_copper_begin(tp, 0); + + tg3_readphy(tp, MII_BMSR, &tmp); + tg3_readphy(tp, MII_BMSR, &tmp); + if (tmp & BMSR_LSTATUS) + current_link_up = 1; + } + + tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK; + if (current_link_up == 1) { + if (tp->link_config.active_speed == SPEED_100 || + tp->link_config.active_speed == SPEED_10) + tp->mac_mode |= MAC_MODE_PORT_MODE_MII; + else + tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; + } else + tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; + + tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; + if (tp->link_config.active_duplex == DUPLEX_HALF) + tp->mac_mode |= MAC_MODE_HALF_DUPLEX; + + tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { + if (current_link_up == 1) + tp->mac_mode |= MAC_MODE_LINK_POLARITY; + tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1); + } else { + if ((tp->led_mode == led_mode_link10) || + (current_link_up == 1 && + tp->link_config.active_speed == SPEED_10)) + tp->mac_mode |= MAC_MODE_LINK_POLARITY; + } + tw32(MAC_MODE, tp->mac_mode); + + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + /* Polled via timer. */ + tw32(MAC_EVENT, 0); + } else { + tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && + current_link_up == 1 && + tp->link_config.active_speed == SPEED_1000 && + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || + (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { + udelay(120); + tw32(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + tg3_write_mem(tp, + NIC_SRAM_FIRMWARE_MBOX, + NIC_SRAM_FIRMWARE_MBOX_MAGIC2); + } + + if (current_link_up != netif_carrier_ok(tp->dev)) { + if (current_link_up) + netif_carrier_on(tp->dev); + else + netif_carrier_off(tp->dev); + tg3_link_report(tp); + } + + return 0; +} + +struct tg3_fiber_aneginfo { + int state; +#define ANEG_STATE_UNKNOWN 0 +#define ANEG_STATE_AN_ENABLE 1 +#define ANEG_STATE_RESTART_INIT 2 +#define ANEG_STATE_RESTART 3 +#define ANEG_STATE_DISABLE_LINK_OK 4 +#define ANEG_STATE_ABILITY_DETECT_INIT 5 +#define ANEG_STATE_ABILITY_DETECT 6 +#define ANEG_STATE_ACK_DETECT_INIT 7 +#define ANEG_STATE_ACK_DETECT 8 +#define ANEG_STATE_COMPLETE_ACK_INIT 9 +#define ANEG_STATE_COMPLETE_ACK 10 +#define ANEG_STATE_IDLE_DETECT_INIT 11 +#define ANEG_STATE_IDLE_DETECT 12 +#define ANEG_STATE_LINK_OK 13 +#define ANEG_STATE_NEXT_PAGE_WAIT_INIT 14 +#define ANEG_STATE_NEXT_PAGE_WAIT 15 + + u32 flags; +#define MR_AN_ENABLE 0x00000001 +#define MR_RESTART_AN 0x00000002 +#define MR_AN_COMPLETE 0x00000004 +#define MR_PAGE_RX 0x00000008 +#define MR_NP_LOADED 0x00000010 +#define MR_TOGGLE_TX 0x00000020 +#define MR_LP_ADV_FULL_DUPLEX 0x00000040 +#define MR_LP_ADV_HALF_DUPLEX 0x00000080 +#define MR_LP_ADV_SYM_PAUSE 0x00000100 +#define MR_LP_ADV_ASYM_PAUSE 0x00000200 +#define MR_LP_ADV_REMOTE_FAULT1 0x00000400 +#define MR_LP_ADV_REMOTE_FAULT2 0x00000800 +#define MR_LP_ADV_NEXT_PAGE 0x00001000 +#define MR_TOGGLE_RX 0x00002000 +#define MR_NP_RX 0x00004000 + +#define MR_LINK_OK 0x80000000 + + unsigned long link_time, cur_time; + + u32 ability_match_cfg; + int ability_match_count; + + char ability_match, idle_match, ack_match; + + u32 txconfig, rxconfig; +#define ANEG_CFG_NP 0x00000080 +#define ANEG_CFG_ACK 0x00000040 +#define ANEG_CFG_RF2 0x00000020 +#define ANEG_CFG_RF1 0x00000010 +#define ANEG_CFG_PS2 0x00000001 +#define ANEG_CFG_PS1 0x00008000 +#define ANEG_CFG_HD 0x00004000 +#define ANEG_CFG_FD 0x00002000 +#define ANEG_CFG_INVAL 0x00001f06 + +}; +#define ANEG_OK 0 +#define ANEG_DONE 1 +#define ANEG_TIMER_ENAB 2 +#define ANEG_FAILED -1 + + +static int tg3_fiber_aneg_smachine(struct tg3 *tp, + struct tg3_fiber_aneginfo *ap) +{ + unsigned long delta; + u32 rx_cfg_reg; + int ret; + + if (ap->state == ANEG_STATE_UNKNOWN) { + ap->rxconfig = 0; + ap->link_time = 0; + ap->cur_time = 0; + ap->ability_match_cfg = 0; + ap->ability_match_count = 0; + ap->ability_match = 0; + ap->idle_match = 0; + ap->ack_match = 0; + } + ap->cur_time++; + + if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) { + rx_cfg_reg = tr32(MAC_RX_AUTO_NEG); + + if (rx_cfg_reg != ap->ability_match_cfg) { + ap->ability_match_cfg = rx_cfg_reg; + ap->ability_match = 0; + ap->ability_match_count = 0; + } else { + if (++ap->ability_match_count > 1) + ap->ability_match = 1; + } + if (rx_cfg_reg & ANEG_CFG_ACK) + ap->ack_match = 1; + else + ap->ack_match = 0; + + ap->idle_match = 0; + } else { + ap->idle_match = 1; + ap->ability_match_cfg = 0; + ap->ability_match_count = 0; + ap->ability_match = 0; + ap->ack_match = 0; + + rx_cfg_reg = 0; + } + + ap->rxconfig = rx_cfg_reg; + ret = ANEG_OK; + + switch(ap->state) { + case ANEG_STATE_UNKNOWN: + if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN)) + ap->state = ANEG_STATE_AN_ENABLE; + + /* fallthru */ + case ANEG_STATE_AN_ENABLE: + ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX); + if (ap->flags & MR_AN_ENABLE) { + ap->link_time = 0; + ap->cur_time = 0; + ap->ability_match_cfg = 0; + ap->ability_match_count = 0; + ap->ability_match = 0; + ap->idle_match = 0; + ap->ack_match = 0; + + ap->state = ANEG_STATE_RESTART_INIT; + } else { + ap->state = ANEG_STATE_DISABLE_LINK_OK; + } + break; + + case ANEG_STATE_RESTART_INIT: + ap->link_time = ap->cur_time; + ap->flags &= ~(MR_NP_LOADED); + ap->txconfig = 0; + tw32(MAC_TX_AUTO_NEG, 0); + tp->mac_mode |= MAC_MODE_SEND_CONFIGS; + tw32(MAC_MODE, tp->mac_mode); + ret = ANEG_TIMER_ENAB; + ap->state = ANEG_STATE_RESTART; + + /* fallthru */ + case ANEG_STATE_RESTART: + delta = ap->cur_time - ap->link_time; + if (delta > 100000) + ap->state = ANEG_STATE_ABILITY_DETECT_INIT; + else + ret = ANEG_TIMER_ENAB; + break; + + case ANEG_STATE_DISABLE_LINK_OK: + ret = ANEG_DONE; + break; + + case ANEG_STATE_ABILITY_DETECT_INIT: + ap->flags &= ~(MR_TOGGLE_TX); + ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1); + tw32(MAC_TX_AUTO_NEG, ap->txconfig); + tp->mac_mode |= MAC_MODE_SEND_CONFIGS; + tw32(MAC_MODE, tp->mac_mode); + ap->state = ANEG_STATE_ABILITY_DETECT; + break; + + case ANEG_STATE_ABILITY_DETECT: + if (ap->ability_match != 0 && ap->rxconfig != 0) + ap->state = ANEG_STATE_ACK_DETECT_INIT; + break; + + case ANEG_STATE_ACK_DETECT_INIT: + ap->txconfig |= ANEG_CFG_ACK; + tw32(MAC_TX_AUTO_NEG, ap->txconfig); + tp->mac_mode |= MAC_MODE_SEND_CONFIGS; + tw32(MAC_MODE, tp->mac_mode); + ap->state = ANEG_STATE_ACK_DETECT; + + /* fallthru */ + case ANEG_STATE_ACK_DETECT: + if (ap->ack_match != 0) { + if ((ap->rxconfig & ~ANEG_CFG_ACK) == + (ap->ability_match_cfg & ~ANEG_CFG_ACK)) + ap->state = ANEG_STATE_COMPLETE_ACK_INIT; + else + ap->state = ANEG_STATE_AN_ENABLE; + } else if (ap->ability_match != 0 && + ap->rxconfig == 0) { + ap->state = ANEG_STATE_AN_ENABLE; + } + break; + + case ANEG_STATE_COMPLETE_ACK_INIT: + if (ap->rxconfig & ANEG_CFG_INVAL) { + ret = ANEG_FAILED; + break; + } + ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX | + MR_LP_ADV_HALF_DUPLEX | + MR_LP_ADV_SYM_PAUSE | + MR_LP_ADV_ASYM_PAUSE | + MR_LP_ADV_REMOTE_FAULT1 | + MR_LP_ADV_REMOTE_FAULT2 | + MR_LP_ADV_NEXT_PAGE | + MR_TOGGLE_RX | + MR_NP_RX); + if (ap->rxconfig & ANEG_CFG_FD) + ap->flags |= MR_LP_ADV_FULL_DUPLEX; + if (ap->rxconfig & ANEG_CFG_HD) + ap->flags |= MR_LP_ADV_FULL_DUPLEX; + if (ap->rxconfig & ANEG_CFG_PS1) + ap->flags |= MR_LP_ADV_SYM_PAUSE; + if (ap->rxconfig & ANEG_CFG_PS2) + ap->flags |= MR_LP_ADV_ASYM_PAUSE; + if (ap->rxconfig & ANEG_CFG_RF1) + ap->flags |= MR_LP_ADV_REMOTE_FAULT1; + if (ap->rxconfig & ANEG_CFG_RF2) + ap->flags |= MR_LP_ADV_REMOTE_FAULT2; + if (ap->rxconfig & ANEG_CFG_NP) + ap->flags |= MR_LP_ADV_NEXT_PAGE; + + ap->link_time = ap->cur_time; + + ap->flags ^= (MR_TOGGLE_TX); + if (ap->rxconfig & 0x0008) + ap->flags |= MR_TOGGLE_RX; + if (ap->rxconfig & ANEG_CFG_NP) + ap->flags |= MR_NP_RX; + ap->flags |= MR_PAGE_RX; + + ap->state = ANEG_STATE_COMPLETE_ACK; + ret = ANEG_TIMER_ENAB; + break; + + case ANEG_STATE_COMPLETE_ACK: + if (ap->ability_match != 0 && + ap->rxconfig == 0) { + ap->state = ANEG_STATE_AN_ENABLE; + break; + } + delta = ap->cur_time - ap->link_time; + if (delta > 100000) { + if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) { + ap->state = ANEG_STATE_IDLE_DETECT_INIT; + } else { + if ((ap->txconfig & 0x0080) == 0 && + !(ap->flags & MR_NP_RX)) + ap->state = ANEG_STATE_IDLE_DETECT_INIT; + else + ret = ANEG_FAILED; + } + } + break; + + case ANEG_STATE_IDLE_DETECT_INIT: + ap->link_time = ap->cur_time; + tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; + tw32(MAC_MODE, tp->mac_mode); + ap->state = ANEG_STATE_IDLE_DETECT; + ret = ANEG_TIMER_ENAB; + break; + + case ANEG_STATE_IDLE_DETECT: + if (ap->ability_match != 0 && + ap->rxconfig == 0) { + ap->state = ANEG_STATE_AN_ENABLE; + break; + } + delta = ap->cur_time - ap->link_time; + if (delta > 100000) { + /* XXX another gem from the Broadcom driver :( */ + ap->state = ANEG_STATE_LINK_OK; + } + break; + + case ANEG_STATE_LINK_OK: + ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK); + ret = ANEG_DONE; + break; + + case ANEG_STATE_NEXT_PAGE_WAIT_INIT: + /* ??? unimplemented */ + break; + + case ANEG_STATE_NEXT_PAGE_WAIT: + /* ??? unimplemented */ + break; + + default: + ret = ANEG_FAILED; + break; + }; + + return ret; +} + +static int tg3_setup_fiber_phy(struct tg3 *tp) +{ + int current_link_up; + int i; + + tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); + tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; + tw32(MAC_MODE, tp->mac_mode); + udelay(40); + + /* Reset when initting first time or we have a link. */ + if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || + (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) { + /* Set PLL lock range. */ + tg3_writephy(tp, 0x16, 0x8007); + + /* SW reset */ + tg3_writephy(tp, 0x00, 0x8000); + + /* Wait for reset to complete. */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 500; i++) + udelay(10); + + /* Config mode; select PMA/Ch 1 regs. */ + tg3_writephy(tp, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + tg3_writephy(tp, 0x11, 0x0a10); + + tg3_writephy(tp, 0x18, 0x00a0); + tg3_writephy(tp, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + tg3_writephy(tp, 0x13, 0x0400); + udelay(40); + tg3_writephy(tp, 0x13, 0x0000); + + tg3_writephy(tp, 0x11, 0x0a50); + udelay(40); + tg3_writephy(tp, 0x11, 0x0a10); + + /* Wait for signal to stabilize */ + /* XXX schedule_timeout() ... */ + for (i = 0; i < 15000; i++) + udelay(10); + + /* Deselect the channel register so we can read the PHYID + * later. + */ + tg3_writephy(tp, 0x10, 0x8011); + } + + /* Enable link change interrupt. */ + tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + + current_link_up = 0; + if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + struct tg3_fiber_aneginfo aninfo; + int status = ANEG_FAILED; + + memset(&aninfo, 0, sizeof(aninfo)); + aninfo.flags |= (MR_AN_ENABLE); + + for (i = 0; i < 6; i++) { + unsigned int tick; + u32 tmp; + + tw32(MAC_TX_AUTO_NEG, 0); + + tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; + tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); + udelay(20); + + tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); + + aninfo.state = ANEG_STATE_UNKNOWN; + aninfo.cur_time = 0; + tick = 0; + while (++tick < 95000) { + status = tg3_fiber_aneg_smachine(tp, &aninfo); + if (status == ANEG_DONE || + status == ANEG_FAILED) + break; + + udelay(1); + } + if (status == ANEG_DONE || + status == ANEG_FAILED) + break; + } + + tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; + tw32(MAC_MODE, tp->mac_mode); + + if (status == ANEG_DONE && + (aninfo.flags & MR_AN_COMPLETE) && + (aninfo.flags & MR_LINK_OK) && + (aninfo.flags & MR_LP_ADV_FULL_DUPLEX)) { + u32 local_adv, remote_adv; + + local_adv = ADVERTISE_PAUSE_CAP; + remote_adv = 0; + if (aninfo.flags & MR_LP_ADV_SYM_PAUSE) + remote_adv |= LPA_PAUSE_CAP; + if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE) + remote_adv |= LPA_PAUSE_ASYM; + + tg3_setup_flow_control(tp, local_adv, remote_adv); + + current_link_up = 1; + } + for (i = 0; i < 60; i++) { + udelay(20); + tw32(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + + udelay(20); + if ((tr32(MAC_STATUS) & + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + } else { + /* Forcing 1000FD link up. */ + current_link_up = 1; + } + } + + tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; + tw32(MAC_MODE, tp->mac_mode); + + tp->hw_status->status = + (SD_STATUS_UPDATED | + (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); + + for (i = 0; i < 100; i++) { + tw32(MAC_STATUS, + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)); + udelay(5); + + if ((tr32(MAC_STATUS) & + (MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) + current_link_up = 0; + + if (current_link_up == 1) { + tp->link_config.active_speed = SPEED_1000; + tp->link_config.active_duplex = DUPLEX_FULL; + } else { + tp->link_config.active_speed = SPEED_INVALID; + tp->link_config.active_duplex = DUPLEX_INVALID; + } + + if (current_link_up != netif_carrier_ok(tp->dev)) { + if (current_link_up) + netif_carrier_on(tp->dev); + else + netif_carrier_off(tp->dev); + tg3_link_report(tp); + } + + if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { + tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); + if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { + udelay(1); + tw32(MAC_MODE, tp->mac_mode); + } + } + + return 0; +} + +static int tg3_setup_phy(struct tg3 *tp) +{ + int err; + + if (tp->phy_id == PHY_ID_SERDES) { + err = tg3_setup_fiber_phy(tp); + } else { + err = tg3_setup_copper_phy(tp); + } + + if (tp->link_config.active_speed == SPEED_1000 && + tp->link_config.active_duplex == DUPLEX_HALF) + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + else + tw32(MAC_TX_LENGTHS, + ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + + return err; +} + +/* Tigon3 never reports partial packet sends. So we do not + * need special logic to handle SKBs that have not had all + * of their frags sent yet, like SunGEM does. + */ +static void tg3_tx(struct tg3 *tp) +{ + u32 hw_idx = tp->hw_status->idx[0].tx_consumer; + u32 sw_idx = tp->tx_cons; + + while (sw_idx != hw_idx) { + struct ring_info *ri = &tp->tx_buffers[sw_idx]; + struct sk_buff *skb = ri->skb; + int i; + + if (unlikely(skb == NULL)) + BUG(); + + pci_unmap_single(tp->pdev, ri->mapping, + (skb->len - skb->data_len), + PCI_DMA_TODEVICE); + + ri->skb = NULL; + + sw_idx = NEXT_TX(sw_idx); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + if (unlikely(sw_idx == hw_idx)) + BUG(); + + ri = &tp->tx_buffers[sw_idx]; + if (unlikely(ri->skb != NULL)) + BUG(); + + pci_unmap_page(tp->pdev, + ri->mapping, + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); + + sw_idx = NEXT_TX(sw_idx); + } + + dev_kfree_skb_irq(skb); + } + + tp->tx_cons = sw_idx; + + if (netif_queue_stopped(tp->dev) && + (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)) + netif_wake_queue(tp->dev); +} + +/* Returns size of skb allocated or < 0 on error. + * + * We only need to fill in the address because the other members + * of the RX descriptor are invariant, see tg3_init_rings. + * + * Note the purposeful assymetry of cpu vs. chip accesses. For + * posting buffers we only dirty the first cache line of the RX + * descriptor (containing the address). Whereas for the RX status + * buffers the cpu only reads the last cacheline of the RX descriptor + * (to fetch the error flags, vlan tag, checksum, and opaque cookie). + */ +static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, + int src_idx, u32 dest_idx_unmasked) +{ + struct tg3_rx_buffer_desc *desc; + struct ring_info *map, *src_map; + struct sk_buff *skb; + dma_addr_t mapping; + int skb_size, dest_idx; + + src_map = NULL; + switch (opaque_key) { + case RXD_OPAQUE_RING_STD: + dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; + desc = &tp->rx_std[dest_idx]; + map = &tp->rx_std_buffers[dest_idx]; + if (src_idx >= 0) + src_map = &tp->rx_std_buffers[src_idx]; + skb_size = RX_PKT_BUF_SZ; + break; + + case RXD_OPAQUE_RING_JUMBO: + dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; + desc = &tp->rx_jumbo[dest_idx]; + map = &tp->rx_jumbo_buffers[dest_idx]; + if (src_idx >= 0) + src_map = &tp->rx_jumbo_buffers[src_idx]; + skb_size = RX_JUMBO_PKT_BUF_SZ; + break; +#if TG3_MINI_RING_WORKS + case RXD_OPAQUE_RING_MINI: + dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE; + desc = &tp->rx_mini[dest_idx]; + map = &tp->rx_mini_buffers[dest_idx]; + if (src_idx >= 0) + src_map = &tp->rx_mini_buffers[src_idx]; + skb_size = RX_MINI_PKT_BUF_SZ; + break; +#endif + default: + return -EINVAL; + }; + + /* Do not overwrite any of the map or rp information + * until we are sure we can commit to a new buffer. + * + * Callers depend upon this behavior and assume that + * we leave everything unchanged if we fail. + */ + skb = dev_alloc_skb(skb_size); + if (skb == NULL) + return -ENOMEM; + + skb->dev = tp->dev; + skb_reserve(skb, tp->rx_offset); + + mapping = pci_map_single(tp->pdev, skb->data, + skb_size - tp->rx_offset, + PCI_DMA_FROMDEVICE); + + map->skb = skb; + map->mapping = mapping; + + if (src_map != NULL) + src_map->skb = NULL; + + desc->addr_hi = ((u64)mapping >> 32); + desc->addr_lo = ((u64)mapping & 0xffffffff); + + return skb_size; +} + +/* We only need to move over in the address because the other + * members of the RX descriptor are invariant. See notes above + * tg3_alloc_rx_skb for full details. + */ +static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, + int src_idx, int dest_idx_unmasked) +{ + struct tg3_rx_buffer_desc *src_desc, *dest_desc; + struct ring_info *src_map, *dest_map; + int dest_idx; + + switch (opaque_key) { + case RXD_OPAQUE_RING_STD: + dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; + dest_desc = &tp->rx_std[dest_idx]; + dest_map = &tp->rx_std_buffers[dest_idx]; + src_desc = &tp->rx_std[src_idx]; + src_map = &tp->rx_std_buffers[src_idx]; + break; + + case RXD_OPAQUE_RING_JUMBO: + dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; + dest_desc = &tp->rx_jumbo[dest_idx]; + dest_map = &tp->rx_jumbo_buffers[dest_idx]; + src_desc = &tp->rx_jumbo[src_idx]; + src_map = &tp->rx_jumbo_buffers[src_idx]; + break; +#if TG3_MINI_RING_WORKS + case RXD_OPAQUE_RING_MINI: + dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE; + dest_desc = &tp->rx_mini[dest_idx]; + dest_map = &tp->rx_mini_buffers[dest_idx]; + src_desc = &tp->rx_mini[src_idx]; + src_map = &tp->rx_mini_buffers[src_idx]; + break; +#endif + default: + return; + }; + + dest_map->skb = src_map->skb; + dest_map->mapping = src_map->mapping; + dest_desc->addr_hi = src_desc->addr_hi; + dest_desc->addr_lo = src_desc->addr_lo; + + src_map->skb = NULL; +} + +#if TG3_VLAN_TAG_USED +static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag) +{ + return vlan_hwaccel_rx(skb, tp->vlgrp, vlan_tag); +} +#endif + +/* The RX ring scheme is composed of multiple rings which post fresh + * buffers to the chip, and one special ring the chip uses to report + * status back to the host. + * + * The special ring reports the status of received packets to the + * host. The chip does not write into the original descriptor the + * RX buffer was obtained from. The chip simply takes the original + * descriptor as provided by the host, updates the status and length + * field, then writes this into the next status ring entry. + * + * Each ring the host uses to post buffers to the chip is described + * by a TG3_BDINFO entry in the chips SRAM area. When a packet arrives, + * it is first placed into the on-chip ram. When the packet's length + * is known, it walks down the TG3_BDINFO entries to select the ring. + * Each TG3_BDINFO specifies a MAXLEN field and the first TG3_BDINFO + * which is within the range of the new packet's length is chosen. + * + * The "seperate ring for rx status" scheme may sound queer, but it makes + * sense from a cache coherency perspective. If only the host writes + * to the buffer post rings, and only the chip writes to the rx status + * rings, then cache lines never move beyond shared-modified state. + * If both the host and chip were to write into the same ring, cache line + * eviction could occur since both entities want it in an exclusive state. + */ +static void tg3_rx(struct tg3 *tp) +{ + u32 work_mask; + u32 rx_rcb_ptr = tp->rx_rcb_ptr; + u16 hw_idx, sw_idx; + + hw_idx = tp->hw_status->idx[0].rx_producer; + sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE; + work_mask = 0; + while (sw_idx != hw_idx) { + struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx]; + unsigned int len; + struct sk_buff *skb; + dma_addr_t dma_addr; + u32 opaque_key, desc_idx, *post_ptr; + + desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; + opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; + if (opaque_key == RXD_OPAQUE_RING_STD) { + dma_addr = tp->rx_std_buffers[desc_idx].mapping; + skb = tp->rx_std_buffers[desc_idx].skb; + post_ptr = &tp->rx_std_ptr; + } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { + dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping; + skb = tp->rx_jumbo_buffers[desc_idx].skb; + post_ptr = &tp->rx_jumbo_ptr; + } +#if TG3_MINI_RING_WORKS + else if (opaque_key == RXD_OPAQUE_RING_MINI) { + dma_addr = tp->rx_mini_buffers[desc_idx].mapping; + skb = tp->rx_mini_buffers[desc_idx].skb; + post_ptr = &tp->rx_mini_ptr; + } +#endif + else { + goto next_pkt_nopost; + } + + work_mask |= opaque_key; + + if ((desc->err_vlan & RXD_ERR_MASK) != 0 && + (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) { + drop_it: + tg3_recycle_rx(tp, opaque_key, + desc_idx, *post_ptr); + drop_it_no_recycle: + /* Other statistics kept track of by card. */ + tp->net_stats.rx_dropped++; + goto next_pkt; + } + + len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */ + + /* Kill the copy case if we ever get the mini ring working. */ + if (len > RX_COPY_THRESHOLD) { + int skb_size; + + skb_size = tg3_alloc_rx_skb(tp, opaque_key, + desc_idx, *post_ptr); + if (skb_size < 0) + goto drop_it; + + pci_unmap_single(tp->pdev, dma_addr, + skb_size - tp->rx_offset, + PCI_DMA_FROMDEVICE); + + skb_put(skb, len); + } else { + struct sk_buff *copy_skb; + + tg3_recycle_rx(tp, opaque_key, + desc_idx, *post_ptr); + + copy_skb = dev_alloc_skb(len + 2); + if (copy_skb == NULL) + goto drop_it_no_recycle; + + copy_skb->dev = tp->dev; + skb_reserve(copy_skb, 2); + skb_put(copy_skb, len); + pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + memcpy(copy_skb->data, skb->data, len); + + /* We'll reuse the original ring buffer. */ + skb = copy_skb; + } + + if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) && + (desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) { + skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) + >> RXD_TCPCSUM_SHIFT); + skb->ip_summed = CHECKSUM_HW; + } else { + skb->ip_summed = CHECKSUM_NONE; + } + + skb->protocol = eth_type_trans(skb, tp->dev); +#if TG3_VLAN_TAG_USED + if (tp->vlgrp != NULL && + desc->type_flags & RXD_FLAG_VLAN) { + tg3_vlan_rx(tp, skb, + desc->err_vlan & RXD_VLAN_MASK); + } else +#endif + netif_rx(skb); + + tp->dev->last_rx = jiffies; + +next_pkt: + (*post_ptr)++; +next_pkt_nopost: + rx_rcb_ptr++; + sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE; + } + + /* ACK the status ring. */ + tp->rx_rcb_ptr = rx_rcb_ptr; + tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, + (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE)); + + /* Refill RX ring(s). */ + if (work_mask & RXD_OPAQUE_RING_STD) { + sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE; + tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, + sw_idx); + } + if (work_mask & RXD_OPAQUE_RING_JUMBO) { + sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE; + tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, + sw_idx); + } +#if TG3_MINI_RING_WORKS + if (work_mask & RXD_OPAQUE_RING_MINI) { + sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE; + tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, + sw_idx); + } +#endif +} + +#define PKT_RATE_LOW 22000 +#define PKT_RATE_HIGH 61000 + +static void tg3_rate_sample(struct tg3 *tp, unsigned long ticks) +{ + u32 delta, rx_now, tx_now; + int new_vals, do_tx, do_rx; + + rx_now = tp->hw_stats->rx_ucast_packets.low; + tx_now = tp->hw_stats->COS_out_packets[0].low; + + delta = (rx_now - tp->last_rx_count); + delta += (tx_now - tp->last_tx_count); + delta /= (ticks / tp->coalesce_config.rate_sample_jiffies); + + tp->last_rx_count = rx_now; + tp->last_tx_count = tx_now; + + new_vals = 0; + do_tx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0; + do_rx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0; + if (delta < tp->coalesce_config.pkt_rate_low) { + if (do_rx && + tp->coalesce_config.rx_max_coalesced_frames != + tp->coalesce_config.rx_max_coalesced_frames_low) { + tp->coalesce_config.rx_max_coalesced_frames = + LOW_RXMAX_FRAMES; + tp->coalesce_config.rx_coalesce_ticks = + LOW_RXCOL_TICKS; + new_vals = 1; + } + if (do_tx && + tp->coalesce_config.tx_max_coalesced_frames != + tp->coalesce_config.tx_max_coalesced_frames_low) { + tp->coalesce_config.tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_low; + tp->coalesce_config.tx_coalesce_ticks = + tp->coalesce_config.tx_coalesce_ticks_low; + new_vals = 1; + } + } else if (delta < tp->coalesce_config.pkt_rate_high) { + if (do_rx && + tp->coalesce_config.rx_max_coalesced_frames != + tp->coalesce_config.rx_max_coalesced_frames_def) { + tp->coalesce_config.rx_max_coalesced_frames = + tp->coalesce_config.rx_max_coalesced_frames_def; + tp->coalesce_config.rx_coalesce_ticks = + tp->coalesce_config.rx_coalesce_ticks_def; + new_vals = 1; + } + if (do_tx && + tp->coalesce_config.tx_max_coalesced_frames != + tp->coalesce_config.tx_max_coalesced_frames_def) { + tp->coalesce_config.tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_def; + tp->coalesce_config.tx_coalesce_ticks = + tp->coalesce_config.tx_coalesce_ticks_def; + new_vals = 1; + } + } else { + if (do_rx && + tp->coalesce_config.rx_max_coalesced_frames != + tp->coalesce_config.rx_max_coalesced_frames_high) { + tp->coalesce_config.rx_max_coalesced_frames = + tp->coalesce_config.rx_max_coalesced_frames_high; + tp->coalesce_config.rx_coalesce_ticks = + tp->coalesce_config.rx_coalesce_ticks_high; + new_vals = 1; + } + if (do_tx && + tp->coalesce_config.tx_max_coalesced_frames != + tp->coalesce_config.tx_max_coalesced_frames_high) { + tp->coalesce_config.tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_high; + tp->coalesce_config.tx_coalesce_ticks = + tp->coalesce_config.tx_coalesce_ticks_high; + new_vals = 1; + } + } + + if (new_vals) { + if (do_rx) { + tw32(HOSTCC_RXCOL_TICKS, + tp->coalesce_config.rx_coalesce_ticks); + tw32(HOSTCC_RXMAX_FRAMES, + tp->coalesce_config.rx_max_coalesced_frames); + } + if (do_tx) { + tw32(HOSTCC_TXCOL_TICKS, + tp->coalesce_config.tx_coalesce_ticks); + tw32(HOSTCC_TXMAX_FRAMES, + tp->coalesce_config.tx_max_coalesced_frames); + } + } + + tp->last_rate_sample = jiffies; +} + +static void tg3_interrupt_main_work(struct tg3 *tp) +{ + struct tg3_hw_status *sblk = tp->hw_status; + int did_pkts; + + if (!(tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG)) { + if (sblk->status & SD_STATUS_LINK_CHG) { + sblk->status = SD_STATUS_UPDATED | + (sblk->status & ~SD_STATUS_LINK_CHG); + tg3_setup_phy(tp); + } + } + + did_pkts = 0; + if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) { + tg3_rx(tp); + did_pkts = 1; + } + + if (sblk->idx[0].tx_consumer != tp->tx_cons) { + tg3_tx(tp); + did_pkts = 1; + } + + if (did_pkts && + (tp->tg3_flags & (TG3_FLAG_ADAPTIVE_RX | TG3_FLAG_ADAPTIVE_TX))) { + unsigned long ticks = jiffies - tp->last_rate_sample; + + if (ticks >= tp->coalesce_config.rate_sample_jiffies) + tg3_rate_sample(tp, ticks); + } +} + +static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = dev->priv; + struct tg3_hw_status *sblk = tp->hw_status; + + spin_lock(&tp->lock); + + while (sblk->status & SD_STATUS_UPDATED) { + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000001); + sblk->status &= ~SD_STATUS_UPDATED; + + tg3_interrupt_main_work(tp); + + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000000); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + } + + spin_unlock(&tp->lock); +} + +static void tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = dev->priv; + struct tg3_hw_status *sblk = tp->hw_status; + + spin_lock(&tp->lock); + + if (sblk->status & SD_STATUS_UPDATED) { + u32 oldtag; + + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000001); + oldtag = sblk->status_tag; + + while (1) { + u32 newtag; + + sblk->status &= ~SD_STATUS_UPDATED; + barrier(); + + tg3_interrupt_main_work(tp); + + newtag = sblk->status_tag; + if (newtag == oldtag) { + tw32_mailbox(MAILBOX_INTERRUPT_0 + + TG3_64BIT_REG_LOW, + newtag << 24); + break; + } + oldtag = newtag; + } + } + + spin_unlock(&tp->lock); +} + +static void tg3_init_rings(struct tg3 *); +static int tg3_init_hw(struct tg3 *); + +static void tg3_tx_timeout(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", + dev->name); + + spin_lock_irq(&tp->lock); + + tg3_halt(tp); + tg3_init_rings(tp); + tg3_init_hw(tp); + + spin_unlock_irq(&tp->lock); + + netif_wake_queue(dev); +} + +#if !PCI_DMA_BUS_IS_PHYS +static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping) +{ + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; + + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + } else { + unsigned long txd; + + txd = (tp->regs + + NIC_SRAM_WIN_BASE + + NIC_SRAM_TX_BUFFER_DESC); + txd += (entry * TXD_SIZE); + + writel(((u64) mapping >> 32), + txd + TXD_ADDR + TG3_64BIT_REG_HIGH); + + writel(((u64) mapping & 0xffffffff), + txd + TXD_ADDR + TG3_64BIT_REG_LOW); + } +} +#endif + +static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int); + +static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, + u32 guilty_entry, int guilty_len, + u32 last_plus_one, u32 *start) +{ + dma_addr_t new_addr; + u32 entry = *start; + int i; + +#if !PCI_DMA_BUS_IS_PHYS + /* IOMMU, just map the guilty area again which is guarenteed to + * use different addresses. + */ + + i = 0; + while (entry != guilty_entry) { + entry = NEXT_TX(entry); + i++; + } + if (i == 0) { + new_addr = pci_map_single(tp->pdev, skb->data, guilty_len, + PCI_DMA_TODEVICE); + } else { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; + + new_addr = pci_map_page(tp->pdev, + frag->page, frag->page_offset, + guilty_len, PCI_DMA_TODEVICE); + } + pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping, + guilty_len, PCI_DMA_TODEVICE); + tg3_set_txd_addr(tp, guilty_entry, new_addr); + tp->tx_buffers[guilty_entry].mapping = new_addr; + *start = last_plus_one; +#else + /* Oh well, no IOMMU, have to allocate a whole new SKB. */ + struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC); + + if (!new_skb) { + dev_kfree_skb(skb); + return -1; + } + + /* NOTE: Broadcom's driver botches this case up really bad. + * This is especially true if any of the frag pages + * are in highmem. It will instantly oops in that case. + */ + + /* New SKB is guarenteed to be linear. */ + entry = *start; + new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + tg3_set_txd(tp, entry, new_addr, new_skb->len, + (skb->ip_summed == CHECKSUM_HW) ? + TXD_FLAG_TCPUDP_CSUM : 0, 1); + *start = NEXT_TX(entry); + + /* Now clean up the sw ring entries. */ + i = 0; + while (entry != last_plus_one) { + int len; + + if (i == 0) + len = skb->len - skb->data_len; + else + len = skb_shinfo(skb)->frags[i-1].size; + pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, + len, PCI_DMA_TODEVICE); + if (i == 0) { + tp->tx_buffers[entry].skb = new_skb; + tp->tx_buffers[entry].mapping = new_addr; + } else { + tp->tx_buffers[entry].skb = NULL; + } + entry = NEXT_TX(entry); + } + + dev_kfree_skb(skb); +#endif + + return 0; +} + +static void tg3_set_txd(struct tg3 *tp, int entry, + dma_addr_t mapping, int len, u32 flags, + int is_end) +{ +#if TG3_VLAN_TAG_USED + u16 vlan_tag = 0; +#endif + + if (is_end) + flags |= TXD_FLAG_END; +#if TG3_VLAN_TAG_USED + if (flags & TXD_FLAG_VLAN) { + vlan_tag = flags >> 16; + flags &= 0xffff; + } +#endif + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; + + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + txd->len_flags = (len << TXD_LEN_SHIFT) | flags; +#if TG3_VLAN_TAG_USED + txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; +#endif + } else { + unsigned long txd; + + txd = (tp->regs + + NIC_SRAM_WIN_BASE + + NIC_SRAM_TX_BUFFER_DESC); + txd += (entry * TXD_SIZE); + + /* Save some PIOs */ + if (((u64) tp->tx_buffers[entry].mapping >> 32) != + ((u64) mapping >> 32)) + writel(((u64) mapping >> 32), + txd + TXD_ADDR + TG3_64BIT_REG_HIGH); + + writel(((u64) mapping & 0xffffffff), + txd + TXD_ADDR + TG3_64BIT_REG_LOW); + writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS); +#if TG3_VLAN_TAG_USED + writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); +#endif + } +} + +static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) +{ + u32 base = (u32) mapping & 0xffffffff; + + return ((base > 0xffffdcc0) && + ((u64) mapping >> 32) == 0 && + (base + len + 8 < base)); +} + +static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + dma_addr_t mapping; + unsigned int i; + u32 len, entry, base_flags; + int would_hit_hwbug; + + len = (skb->len - skb->data_len); + + spin_lock_irq(&tp->lock); + + /* This is a hard error, log it. */ + if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + netif_stop_queue(dev); + spin_unlock_irq(&tp->lock); + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + return 1; + } + + entry = tp->tx_prod; + base_flags = 0; + if (skb->ip_summed == CHECKSUM_HW) + base_flags |= TXD_FLAG_TCPUDP_CSUM; +#if TG3_VLAN_TAG_USED + if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) + base_flags |= (TXD_FLAG_VLAN | + (vlan_tx_tag_get(skb) << 16)); +#endif + + /* Queue skb data, a.k.a. the main skb fragment. */ + mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = skb; + tp->tx_buffers[entry].mapping = mapping; + + would_hit_hwbug = tg3_4g_overflow_test(mapping, len); + + tg3_set_txd(tp, entry, mapping, len, base_flags, + (skb_shinfo(skb)->nr_frags == 0)); + + entry = NEXT_TX(entry); + + /* Now loop through additional data fragments, and queue them. */ + if (skb_shinfo(skb)->nr_frags > 0) { + unsigned int i, last; + + last = skb_shinfo(skb)->nr_frags - 1; + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + len = frag->size; + mapping = pci_map_page(tp->pdev, + frag->page, + frag->page_offset, + len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = mapping; + + would_hit_hwbug |= + tg3_4g_overflow_test(mapping, len); + + tg3_set_txd(tp, entry, mapping, len, + base_flags, (i == last)); + + entry = NEXT_TX(entry); + } + } + + if (would_hit_hwbug) { + u32 last_plus_one = entry; + u32 start; + unsigned int len = 0; + + entry = entry - 1 - skb_shinfo(skb)->nr_frags; + entry &= (TG3_TX_RING_SIZE - 1); + start = entry; + i = 0; + while (entry != last_plus_one) { + dma_addr_t mapping = tp->tx_buffers[entry].mapping; + + if (i == 0) + len = skb->len - skb->data_len; + else + len = skb_shinfo(skb)->frags[i-1].size; + + if (tg3_4g_overflow_test(mapping, len)) + break; + + i++; + entry = NEXT_TX(entry); + + } + + /* If the workaround fails due to memory/mapping + * failure, silently drop this packet. + */ + if (tigon3_4gb_hwbug_workaround(tp, skb, + entry, len, + last_plus_one, + &start)) + goto out_unlock; + + entry = start; + } + + /* Packets are ready, update Tx producer idx local and on card. */ + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) + tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + } else { + tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) + tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + } + + tp->tx_prod = entry; + if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) + netif_stop_queue(dev); + +out_unlock: + spin_unlock_irq(&tp->lock); + + dev->trans_start = jiffies; + + return 0; +} + +static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + dma_addr_t mapping; + u32 len, entry, base_flags; + + len = (skb->len - skb->data_len); + + spin_lock_irq(&tp->lock); + + /* This is a hard error, log it. */ + if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + netif_stop_queue(dev); + spin_unlock_irq(&tp->lock); + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + return 1; + } + + entry = tp->tx_prod; + base_flags = 0; + if (skb->ip_summed == CHECKSUM_HW) + base_flags |= TXD_FLAG_TCPUDP_CSUM; +#if TG3_VLAN_TAG_USED + if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) + base_flags |= (TXD_FLAG_VLAN | + (vlan_tx_tag_get(skb) << 16)); +#endif + + /* Queue skb data, a.k.a. the main skb fragment. */ + mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = skb; + tp->tx_buffers[entry].mapping = mapping; + + tg3_set_txd(tp, entry, mapping, len, base_flags, + (skb_shinfo(skb)->nr_frags == 0)); + + entry = NEXT_TX(entry); + + /* Now loop through additional data fragments, and queue them. */ + if (skb_shinfo(skb)->nr_frags > 0) { + unsigned int i, last; + + last = skb_shinfo(skb)->nr_frags - 1; + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + + len = frag->size; + mapping = pci_map_page(tp->pdev, + frag->page, + frag->page_offset, + len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = mapping; + + tg3_set_txd(tp, entry, mapping, len, + base_flags, (i == last)); + + entry = NEXT_TX(entry); + } + } + + /* Packets are ready, update Tx producer idx local and on card. + * We know this is not a 5700 (by virtue of not being a chip + * requiring the 4GB overflow workaround) so we can safely omit + * the double-write bug tests. + */ + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + } else { + tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW), entry); + } + + tp->tx_prod = entry; + if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) + netif_stop_queue(dev); + + spin_unlock_irq(&tp->lock); + + dev->trans_start = jiffies; + + return 0; +} + +static int tg3_change_mtu(struct net_device *dev, int new_mtu) +{ + struct tg3 *tp = dev->priv; + + if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU) + return -EINVAL; + + if (!netif_running(dev)) { + /* We'll just catch it later when the + * device is up'd. + */ + dev->mtu = new_mtu; + return 0; + } + + spin_lock_irq(&tp->lock); + + tg3_halt(tp); + + dev->mtu = new_mtu; + + if (new_mtu > ETH_DATA_LEN) + tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE; + else + tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE; + + tg3_init_rings(tp); + tg3_init_hw(tp); + + spin_unlock_irq(&tp->lock); + + return 0; +} + +/* Free up pending packets in all rx/tx rings. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->lock is not held and we are not + * in an interrupt context and thus may sleep. + */ +static void tg3_free_rings(struct tg3 *tp) +{ + struct ring_info *rxp; + int i; + + for (i = 0; i < TG3_RX_RING_SIZE; i++) { + rxp = &tp->rx_std_buffers[i]; + + if (rxp->skb == NULL) + continue; + pci_unmap_single(tp->pdev, rxp->mapping, + RX_PKT_BUF_SZ - tp->rx_offset, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxp->skb); + rxp->skb = NULL; + } +#if TG3_MINI_RING_WORKS + for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) { + rxp = &tp->rx_mini_buffers[i]; + + if (rxp->skb == NULL) + continue; + pci_unmap_single(tp->pdev, rxp->mapping, + RX_MINI_PKT_BUF_SZ - tp->rx_offset, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxp->skb); + rxp->skb = NULL; + } +#endif + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + rxp = &tp->rx_jumbo_buffers[i]; + + if (rxp->skb == NULL) + continue; + pci_unmap_single(tp->pdev, rxp->mapping, + RX_JUMBO_PKT_BUF_SZ - tp->rx_offset, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxp->skb); + rxp->skb = NULL; + } + + for (i = 0; i < TG3_TX_RING_SIZE; ) { + struct ring_info *txp; + struct sk_buff *skb; + int j; + + txp = &tp->tx_buffers[i]; + skb = txp->skb; + + if (skb == NULL) { + i++; + continue; + } + + pci_unmap_single(tp->pdev, txp->mapping, + (skb->len - skb->data_len), + PCI_DMA_TODEVICE); + txp->skb = NULL; + + i++; + + for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) { + txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)]; + pci_unmap_page(tp->pdev, txp->mapping, + skb_shinfo(skb)->frags[j].size, + PCI_DMA_TODEVICE); + i++; + } + + dev_kfree_skb_any(skb); + } +} + +/* Initialize tx/rx rings for packet processing. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->lock is not held and we are not + * in an interrupt context and thus may sleep. + */ +static void tg3_init_rings(struct tg3 *tp) +{ + unsigned long start, end; + u32 i; + + /* Free up all the SKBs. */ + tg3_free_rings(tp); + + /* Zero out all descriptors. */ + memset(tp->rx_std, 0, TG3_RX_RING_BYTES); +#if TG3_MINI_RING_WORKS + memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES); +#endif + memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); + memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES); + + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + } else { + start = (tp->regs + + NIC_SRAM_WIN_BASE + + NIC_SRAM_TX_BUFFER_DESC); + end = start + TG3_TX_RING_BYTES; + while (start < end) { + writel(0, start); + start += 4; + } + } + + /* Initialize invariants of the rings, we only set this + * stuff once. This works because the card does not + * write into the rx buffer posting rings. + */ + for (i = 0; i < TG3_RX_RING_SIZE; i++) { + struct tg3_rx_buffer_desc *rxd; + + rxd = &tp->rx_std[i]; + rxd->idx_len = (RX_PKT_BUF_SZ - tp->rx_offset - 64) + << RXD_LEN_SHIFT; + rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT); + rxd->opaque = (RXD_OPAQUE_RING_STD | + (i << RXD_OPAQUE_INDEX_SHIFT)); + } +#if TG3_MINI_RING_WORKS + for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) { + struct tg3_rx_buffer_desc *rxd; + + rxd = &tp->rx_mini[i]; + rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64) + << RXD_LEN_SHIFT; + rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | + RXD_FLAG_MINI; + rxd->opaque = (RXD_OPAQUE_RING_MINI | + (i << RXD_OPAQUE_INDEX_SHIFT)); + } +#endif + if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + struct tg3_rx_buffer_desc *rxd; + + rxd = &tp->rx_jumbo[i]; + rxd->idx_len = (RX_JUMBO_PKT_BUF_SZ - tp->rx_offset - 64) + << RXD_LEN_SHIFT; + rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | + RXD_FLAG_JUMBO; + rxd->opaque = (RXD_OPAQUE_RING_JUMBO | + (i << RXD_OPAQUE_INDEX_SHIFT)); + } + } + + /* Now allocate fresh SKBs for each rx ring. */ + for (i = 0; i < tp->rx_pending; i++) { + if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, + -1, i) < 0) + break; + } + +#if TG3_MINI_RING_WORKS + for (i = 0; i < tp->rx_mini_pending; i++) { + if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI, + -1, i) < 0) + break; + } +#endif + + if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { + for (i = 0; i < tp->rx_jumbo_pending; i++) { + if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, + -1, i) < 0) + break; + } + } +} + +/* + * Must not be invoked with interrupt sources disabled and + * the hardware shutdown down. + */ +static void tg3_free_consistent(struct tg3 *tp) +{ + if (tp->rx_std_buffers) { + kfree(tp->rx_std_buffers); + tp->rx_std_buffers = NULL; + } + if (tp->rx_std) { + pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, + tp->rx_std, tp->rx_std_mapping); + tp->rx_std = NULL; + } +#if TG3_MINI_RING_WORKS + if (tp->rx_mini) { + pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES, + tp->rx_mini, tp->rx_mini_mapping); + tp->rx_mini = NULL; + } +#endif + if (tp->rx_jumbo) { + pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, + tp->rx_jumbo, tp->rx_jumbo_mapping); + tp->rx_jumbo = NULL; + } + if (tp->rx_rcb) { + pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES, + tp->rx_rcb, tp->rx_rcb_mapping); + tp->rx_rcb = NULL; + } + if (tp->tx_ring) { + pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, + tp->tx_ring, tp->tx_desc_mapping); + tp->tx_ring = NULL; + } + if (tp->hw_status) { + pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, + tp->hw_status, tp->status_mapping); + tp->hw_status = NULL; + } + if (tp->hw_stats) { + pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats), + tp->hw_stats, tp->stats_mapping); + tp->hw_stats = NULL; + } +} + +/* + * Must not be invoked with interrupt sources disabled and + * the hardware shutdown down. Can sleep. + */ +static int tg3_alloc_consistent(struct tg3 *tp) +{ + tp->rx_std_buffers = kmalloc(sizeof(struct ring_info) * + (TG3_RX_RING_SIZE + +#if TG3_MINI_RING_WORKS + TG3_RX_MINI_RING_SIZE + +#endif + TG3_RX_JUMBO_RING_SIZE + + TG3_TX_RING_SIZE), + GFP_KERNEL); + if (!tp->rx_std_buffers) + return -ENOMEM; + +#if TG3_MINI_RING_WORKS + memset(tp->rx_std_buffers, 0, + (sizeof(struct ring_info) * + (TG3_RX_RING_SIZE + + TG3_RX_MINI_RING_SIZE + + TG3_RX_JUMBO_RING_SIZE + + TG3_TX_RING_SIZE))); +#else + memset(tp->rx_std_buffers, 0, + (sizeof(struct ring_info) * + (TG3_RX_RING_SIZE + + TG3_RX_JUMBO_RING_SIZE + + TG3_TX_RING_SIZE))); +#endif + +#if TG3_MINI_RING_WORKS + tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; + tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE]; +#else + tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; +#endif + tp->tx_buffers = &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; + + tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, + &tp->rx_std_mapping); + if (!tp->rx_std) + goto err_out; + +#if TG3_MINI_RING_WORKS + tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES, + &tp->rx_mini_mapping); + + if (!tp->rx_mini) + goto err_out; +#endif + + tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, + &tp->rx_jumbo_mapping); + + if (!tp->rx_jumbo) + goto err_out; + + tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES, + &tp->rx_rcb_mapping); + if (!tp->rx_rcb) + goto err_out; + + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tp->tx_desc_mapping); + if (!tp->tx_ring) + goto err_out; + } else { + tp->tx_ring = NULL; + tp->tx_desc_mapping = 0; + } + + tp->hw_status = pci_alloc_consistent(tp->pdev, + TG3_HW_STATUS_SIZE, + &tp->status_mapping); + if (!tp->hw_status) + goto err_out; + + tp->hw_stats = pci_alloc_consistent(tp->pdev, + sizeof(struct tg3_hw_stats), + &tp->stats_mapping); + if (!tp->hw_stats) + goto err_out; + + memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); + + return 0; + +err_out: + tg3_free_consistent(tp); + return -ENOMEM; +} + +#define MAX_WAIT_CNT 10000 + +/* To stop a block, clear the enable bit and poll till it + * clears. tp->lock is held. + */ +static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit) +{ + unsigned int i; + u32 val; + + val = tr32(ofs); + val &= ~enable_bit; + tw32(ofs, val); + + for (i = 0; i < MAX_WAIT_CNT; i++) { + val = tr32(ofs); + + if ((val & enable_bit) == 0) + break; + udelay(100); + } + + if (i == MAX_WAIT_CNT) { + printk(KERN_ERR PFX "tg3_stop_block timed out, " + "ofs=%lx enable_bit=%x\n", + ofs, enable_bit); + return -ENODEV; + } + + return 0; +} + +/* tp->lock is held. */ +static int tg3_abort_hw(struct tg3 *tp) +{ + int i, err; + + tg3_disable_ints(tp); + + tp->rx_mode &= ~RX_MODE_ENABLE; + tw32(MAC_RX_MODE, tp->rx_mode); + + err = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE); + err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE); + err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE); + err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE); + err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE); + err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE); + + err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE); + err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE); + err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); + err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE); + err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE); + if (err) + goto out; + + tp->mac_mode &= ~MAC_MODE_TDE_ENABLE; + tw32(MAC_MODE, tp->mac_mode); + + tp->tx_mode &= ~TX_MODE_ENABLE; + tw32(MAC_TX_MODE, tp->tx_mode); + for (i = 0; i < MAX_WAIT_CNT; i++) { + udelay(100); + if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE)) + break; + } + if (i >= MAX_WAIT_CNT) { + printk(KERN_ERR PFX "tg3_abort_hw timed out for %s, " + "TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n", + tp->dev->name, tr32(MAC_TX_MODE)); + return -ENODEV; + } + + err = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE); + err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE); + err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE); + + tw32(FTQ_RESET, 0xffffffff); + tw32(FTQ_RESET, 0x00000000); + + err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE); + err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE); + if (err) + goto out; + + memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + +out: + return err; +} + +/* tp->lock is held. */ +static void tg3_chip_reset(struct tg3 *tp) +{ + u32 val; + + /* Force NVRAM to settle. + * This deals with a chip bug which can result in EEPROM + * corruption. + */ + if (tp->tg3_flags & TG3_FLAG_NVRAM) { + int i; + + tw32(NVRAM_SWARB, SWARB_REQ_SET1); + for (i = 0; i < 100000; i++) { + if (tr32(NVRAM_SWARB) & SWARB_GNT1) + break; + udelay(10); + } + } + + tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET); + udelay(40); + udelay(40); + udelay(40); + + /* Re-enable indirect register accesses. */ + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + + /* Set MAX PCI retry to zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, + (PCISTATE_ROM_ENABLE | + PCISTATE_ROM_RETRY_ENABLE)); + + pci_restore_state(tp->pdev, tp->pci_cfg_state); + + /* Make sure PCI-X relaxed ordering bit is clear. */ + pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); + val &= ~PCIX_CAPS_RELAXED_ORDERING; + pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); + + tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + + tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); +} + +/* tp->lock is held. */ +static int tg3_halt(struct tg3 *tp) +{ + u32 val; + int i; + + tg3_abort_hw(tp); + tg3_chip_reset(tp); + tg3_write_mem(tp, + NIC_SRAM_FIRMWARE_MBOX, + NIC_SRAM_FIRMWARE_MBOX_MAGIC1); + for (i = 0; i < 100000; i++) { + tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val); + if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) + break; + udelay(10); + } + + if (i >= 100000) { + printk(KERN_ERR PFX "tg3_halt timed out for %s, " + "firmware will not restart magic=%08x\n", + tp->dev->name, val); + return -ENODEV; + } + + return 0; +} + +#define TG3_FW_RELEASE_MAJOR 0x0 +#define TG3_FW_RELASE_MINOR 0x0 +#define TG3_FW_RELEASE_FIX 0x0 +#define TG3_FW_START_ADDR 0x08000000 +#define TG3_FW_TEXT_ADDR 0x08000000 +#define TG3_FW_TEXT_LEN 0x9c0 +#define TG3_FW_RODATA_ADDR 0x080009c0 +#define TG3_FW_RODATA_LEN 0x60 +#define TG3_FW_DATA_ADDR 0x08000a40 +#define TG3_FW_DATA_LEN 0x20 +#define TG3_FW_SBSS_ADDR 0x08000a60 +#define TG3_FW_SBSS_LEN 0xc +#define TG3_FW_BSS_ADDR 0x08000a70 +#define TG3_FW_BSS_LEN 0x10 + +static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { + 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, + 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000, + 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034, + 0x0e00021c, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, + 0x27bdffe0, 0x3c1cc000, 0xafbf0018, 0xaf80680c, 0x0e00004c, 0x241b2105, + 0x97850000, 0x97870002, 0x9782002c, 0x9783002e, 0x3c040800, 0x248409c0, + 0xafa00014, 0x00021400, 0x00621825, 0x00052c00, 0xafa30010, 0x8f860010, + 0x00e52825, 0x0e000060, 0x24070102, 0x3c02ac00, 0x34420100, 0x3c03ac01, + 0x34630100, 0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498, 0xaf82049c, + 0x24020001, 0xaf825ce0, 0x0e00003f, 0xaf825d00, 0x0e000140, 0x00000000, + 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x2402ffff, 0xaf825404, 0x8f835400, + 0x34630400, 0xaf835400, 0xaf825404, 0x3c020800, 0x24420034, 0xaf82541c, + 0x03e00008, 0xaf805400, 0x00000000, 0x00000000, 0x3c020800, 0x34423000, + 0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac220a64, + 0x24020040, 0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60, 0xac600000, + 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000, + 0x00804821, 0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800, 0x8c840a68, + 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac230a60, 0x14400003, + 0x00004021, 0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60, 0x3c030800, + 0x8c630a64, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001, + 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c420a60, + 0x3c030800, 0x8c630a64, 0x8f84680c, 0x00021140, 0x00431021, 0xac440008, + 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, + 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, + 0x02000008, 0x00000000, 0x0a0001e3, 0x3c0a0001, 0x0a0001e3, 0x3c0a0002, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x3c0a0007, 0x0a0001e3, 0x3c0a0008, 0x0a0001e3, 0x3c0a0009, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000b, + 0x0a0001e3, 0x3c0a000c, 0x0a0001e3, 0x3c0a000d, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000e, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, + 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a0013, 0x0a0001e3, 0x3c0a0014, + 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, + 0x27bdffe0, 0x00001821, 0x00001021, 0xafbf0018, 0xafb10014, 0xafb00010, + 0x3c010800, 0x00220821, 0xac200a70, 0x3c010800, 0x00220821, 0xac200a74, + 0x3c010800, 0x00220821, 0xac200a78, 0x24630001, 0x1860fff5, 0x2442000c, + 0x24110001, 0x8f906810, 0x32020004, 0x14400005, 0x24040001, 0x3c020800, + 0x8c420a78, 0x18400003, 0x00002021, 0x0e000182, 0x00000000, 0x32020001, + 0x10400003, 0x00000000, 0x0e000169, 0x00000000, 0x0a000153, 0xaf915028, + 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c050800, + 0x8ca50a70, 0x3c060800, 0x8cc60a80, 0x3c070800, 0x8ce70a78, 0x27bdffe0, + 0x3c040800, 0x248409d0, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, + 0x0e00017b, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x24020001, + 0x8f836810, 0x00821004, 0x00021027, 0x00621824, 0x03e00008, 0xaf836810, + 0x27bdffd8, 0xafbf0024, 0x1080002e, 0xafb00020, 0x8f825cec, 0xafa20018, + 0x8f825cec, 0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000, 0xaf825cec, + 0x8e020000, 0x18400016, 0x00000000, 0x3c020800, 0x94420a74, 0x8fa3001c, + 0x000221c0, 0xac830004, 0x8fa2001c, 0x3c010800, 0x0e000201, 0xac220a74, + 0x10400005, 0x00000000, 0x8e020000, 0x24420001, 0x0a0001df, 0xae020000, + 0x3c020800, 0x8c420a70, 0x00021c02, 0x000321c0, 0x0a0001c5, 0xafa2001c, + 0x0e000201, 0x00000000, 0x1040001f, 0x00000000, 0x8e020000, 0x8fa3001c, + 0x24420001, 0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74, 0x0a0001df, + 0xae020000, 0x3c100800, 0x26100a78, 0x8e020000, 0x18400028, 0x00000000, + 0x0e000201, 0x00000000, 0x14400024, 0x00000000, 0x8e020000, 0x3c030800, + 0x8c630a70, 0x2442ffff, 0xafa3001c, 0x18400006, 0xae020000, 0x00031402, + 0x000221c0, 0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e, 0x2442ff00, + 0x2c420300, 0x1440000b, 0x24024000, 0x3c040800, 0x248409dc, 0xafa00010, + 0xafa00014, 0x8fa6001c, 0x24050008, 0x0e000060, 0x00003821, 0x0a0001df, + 0x00000000, 0xaf825cf8, 0x3c020800, 0x8c420a40, 0x8fa3001c, 0x24420001, + 0xaf835cf8, 0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020, 0x03e00008, + 0x27bd0028, 0x27bdffe0, 0x3c040800, 0x248409e8, 0x00002821, 0x00003021, + 0x00003821, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x8fbf0018, + 0x03e00008, 0x27bd0020, 0x8f82680c, 0x8f85680c, 0x00021827, 0x0003182b, + 0x00031823, 0x00431024, 0x00441021, 0x00a2282b, 0x10a00006, 0x00000000, + 0x00401821, 0x8f82680c, 0x0043102b, 0x1440fffd, 0x00000000, 0x03e00008, + 0x00000000, 0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40, 0x0064102b, + 0x54400002, 0x00831023, 0x00641023, 0x2c420008, 0x03e00008, 0x38420001, + 0x27bdffe0, 0x00802821, 0x3c040800, 0x24840a00, 0x00003021, 0x00003821, + 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x0a000216, 0x00000000, + 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000, 0x27bdffe0, 0x3c1cc000, + 0xafbf0018, 0x0e00004c, 0xaf80680c, 0x3c040800, 0x24840a10, 0x03802821, + 0x00003021, 0x00003821, 0xafa00010, 0x0e000060, 0xafa00014, 0x2402ffff, + 0xaf825404, 0x3c0200aa, 0x0e000234, 0xaf825434, 0x8fbf0018, 0x03e00008, + 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe8, 0xafb00010, + 0x24100001, 0xafbf0014, 0x3c01c003, 0xac200000, 0x8f826810, 0x30422000, + 0x10400003, 0x00000000, 0x0e000246, 0x00000000, 0x0a00023a, 0xaf905428, + 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdfff8, 0x8f845d0c, + 0x3c0200ff, 0x3c030800, 0x8c630a50, 0x3442fff8, 0x00821024, 0x1043001e, + 0x3c0500ff, 0x34a5fff8, 0x3c06c003, 0x3c074000, 0x00851824, 0x8c620010, + 0x3c010800, 0xac230a50, 0x30420008, 0x10400005, 0x00871025, 0x8cc20000, + 0x24420001, 0xacc20000, 0x00871025, 0xaf825d0c, 0x8fa20000, 0x24420001, + 0xafa20000, 0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000, 0x8fa20000, + 0x8f845d0c, 0x3c030800, 0x8c630a50, 0x00851024, 0x1443ffe8, 0x00851824, + 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000 +}; + +static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { + 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430, + 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, + 0x00000000, 0x00000000, 0x4d61696e, 0x43707542, 0x00000000, 0x00000000, + 0x00000000 +}; + +#if 0 /* All zeros, dont eat up space with it. */ +u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; +#endif + +#define RX_CPU_SCRATCH_BASE 0x30000 +#define RX_CPU_SCRATCH_SIZE 0x04000 +#define TX_CPU_SCRATCH_BASE 0x34000 +#define TX_CPU_SCRATCH_SIZE 0x04000 + +/* tp->lock is held. */ +static int tg3_reset_cpu(struct tg3 *tp, u32 offset) +{ + int i; + + tw32(offset + CPU_STATE, 0xffffffff); + tw32(offset + CPU_MODE, CPU_MODE_RESET); + if (offset == RX_CPU_BASE) { + for (i = 0; i < 10000; i++) + if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET)) + break; + tw32(offset + CPU_STATE, 0xffffffff); + tw32(offset + CPU_MODE, CPU_MODE_RESET); + udelay(10); + } else { + for (i = 0; i < 10000; i++) { + if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET)) + break; + tw32(offset + CPU_STATE, 0xffffffff); + tw32(offset + CPU_MODE, CPU_MODE_RESET); + udelay(10); + } + } + + if (i >= 10000) { + printk(KERN_ERR PFX "tg3_reset_cpu timed out for %s, " + "and %s CPU\n", + tp->dev->name, + (offset == RX_CPU_BASE ? "RX" : "TX")); + return -ENODEV; + } + return 0; +} + +/* tp->lock is held. */ +static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base, + int cpu_scratch_size) +{ + int err, i; + + err = tg3_reset_cpu(tp, cpu_base); + if (err) + return err; + + for (i = 0; i < cpu_scratch_size; i += sizeof(u32)) + tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0); + tw32(cpu_base + CPU_STATE, 0xffffffff); + tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT); + for (i = 0; i < (TG3_FW_TEXT_LEN / sizeof(u32)); i++) + tg3_write_indirect_reg32(tp, (cpu_scratch_base + + (TG3_FW_TEXT_ADDR & 0xffff) + + (i * sizeof(u32))), + t3FwText[i]); + for (i = 0; i < (TG3_FW_RODATA_LEN / sizeof(u32)); i++) + tg3_write_indirect_reg32(tp, (cpu_scratch_base + + (TG3_FW_RODATA_ADDR & 0xffff) + + (i * sizeof(u32))), + t3FwRodata[i]); + for (i = 0; i < (TG3_FW_DATA_LEN / sizeof(u32)); i++) + tg3_write_indirect_reg32(tp, (cpu_scratch_base + + (TG3_FW_DATA_ADDR & 0xffff) + + (i * sizeof(u32))), + 0); + + return 0; +} + +/* tp->lock is held. */ +static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) +{ + int err, i; + + err = tg3_load_firmware_cpu(tp, RX_CPU_BASE, + RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE); + if (err) + return err; + + err = tg3_load_firmware_cpu(tp, TX_CPU_BASE, + TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE); + if (err) + return err; + + /* Now startup only the RX cpu. */ + tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); + for (i = 0; i < 5; i++) { + if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR) + break; + tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT); + tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); + udelay(1000); + } + if (i >= 5) { + printk(KERN_ERR PFX "tg3_load_firmware fails for %s " + "to set RX CPU PC, is %08x should be %08x\n", + tp->dev->name, tr32(RX_CPU_BASE + CPU_PC), + TG3_FW_TEXT_ADDR); + return -ENODEV; + } + tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(RX_CPU_BASE + CPU_MODE, 0x00000000); + + return 0; +} + +/* tp->lock is held. */ +static void __tg3_set_mac_addr(struct tg3 *tp) +{ + u32 addr_high, addr_low; + int i; + + addr_high = ((tp->dev->dev_addr[0] << 8) | + tp->dev->dev_addr[1]); + addr_low = ((tp->dev->dev_addr[2] << 24) | + (tp->dev->dev_addr[3] << 16) | + (tp->dev->dev_addr[4] << 8) | + (tp->dev->dev_addr[5] << 0)); + for (i = 0; i < 4; i++) { + tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); + tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); + } + + addr_high = (tp->dev->dev_addr[0] + + tp->dev->dev_addr[1] + + tp->dev->dev_addr[2] + + tp->dev->dev_addr[3] + + tp->dev->dev_addr[4] + + tp->dev->dev_addr[5]) & + TX_BACKOFF_SEED_MASK; + tw32(MAC_TX_BACKOFF_SEED, addr_high); +} + +static int tg3_set_mac_addr(struct net_device *dev, void *p) +{ + struct tg3 *tp = dev->priv; + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + spin_lock_irq(&tp->lock); + __tg3_set_mac_addr(tp); + spin_unlock_irq(&tp->lock); + + return 0; +} + +/* tp->lock is held. */ +static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, + dma_addr_t mapping, u32 maxlen_flags, + u32 nic_addr) +{ + tg3_write_mem(tp, + (bdinfo_addr + + TG3_BDINFO_HOST_ADDR + + TG3_64BIT_REG_HIGH), + ((u64) mapping >> 32)); + tg3_write_mem(tp, + (bdinfo_addr + + TG3_BDINFO_HOST_ADDR + + TG3_64BIT_REG_LOW), + ((u64) mapping & 0xffffffff)); + tg3_write_mem(tp, + (bdinfo_addr + + TG3_BDINFO_MAXLEN_FLAGS), + maxlen_flags); + tg3_write_mem(tp, + (bdinfo_addr + + TG3_BDINFO_NIC_ADDR), + nic_addr); +} + +static void __tg3_set_rx_mode(struct net_device *); + +/* tp->lock is held. */ +static int tg3_reset_hw(struct tg3 *tp) +{ + u32 val; + int i, err; + + tg3_disable_ints(tp); + + if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { + err = tg3_abort_hw(tp); + if (err) + return err; + } + + tg3_chip_reset(tp); + + tw32(GRC_MODE, tp->grc_mode); + tg3_write_mem(tp, + NIC_SRAM_FIRMWARE_MBOX, + NIC_SRAM_FIRMWARE_MBOX_MAGIC1); + if (tp->phy_id == PHY_ID_SERDES) { + tp->mac_mode = MAC_MODE_PORT_MODE_TBI; + tw32(MAC_MODE, tp->mac_mode); + } else + tw32(MAC_MODE, 0); + + /* Wait for firmware initialization to complete. */ + for (i = 0; i < 100000; i++) { + tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val); + if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) + break; + udelay(10); + } + if (i >= 100000) { + printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, " + "firmware will not restart magic=%08x\n", + tp->dev->name, val); + return -ENODEV; + } + + /* This works around an issue with Athlon chipsets on + * B3 tigon3 silicon. This bit has no effect on any + * other revision. + */ + val = tr32(TG3PCI_CLOCK_CTRL); + val |= CLOCK_CTRL_DELAY_PCI_GRANT; + tw32(TG3PCI_CLOCK_CTRL, val); + + /* Clear statistics/status block in chip, and status block in ram. */ + for (i = NIC_SRAM_STATS_BLK; + i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; + i += sizeof(u32)) + tg3_write_mem(tp, i, 0); + memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + + /* This value is determined during the probe time DMA + * engine test, tg3_test_dma. + */ + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + + tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS | + GRC_MODE_4X_NIC_SEND_RINGS | + GRC_MODE_NO_TX_PHDR_CSUM | + GRC_MODE_NO_RX_PHDR_CSUM); + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) + tp->grc_mode |= GRC_MODE_HOST_SENDBDS; + else + tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS; + if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) + tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; + if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) + tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM; + + tw32(GRC_MODE, + tp->grc_mode | + (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP)); + + /* Setup the timer prescalar register. Clock is always 66Mhz. */ + tw32(GRC_MISC_CFG, + (65 << GRC_MISC_CFG_PRESCALAR_SHIFT)); + + /* Initialize MBUF/DESC pool. */ + tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); + tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE); + tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); + tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); + + if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) { + tw32(BUFMGR_MB_RDMA_LOW_WATER, + tp->bufmgr_config.mbuf_read_dma_low_water); + tw32(BUFMGR_MB_MACRX_LOW_WATER, + tp->bufmgr_config.mbuf_mac_rx_low_water); + tw32(BUFMGR_MB_HIGH_WATER, + tp->bufmgr_config.mbuf_high_water); + } else { + tw32(BUFMGR_MB_RDMA_LOW_WATER, + tp->bufmgr_config.mbuf_read_dma_low_water_jumbo); + tw32(BUFMGR_MB_MACRX_LOW_WATER, + tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo); + tw32(BUFMGR_MB_HIGH_WATER, + tp->bufmgr_config.mbuf_high_water_jumbo); + } + tw32(BUFMGR_DMA_LOW_WATER, + tp->bufmgr_config.dma_low_water); + tw32(BUFMGR_DMA_HIGH_WATER, + tp->bufmgr_config.dma_high_water); + + tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE); + for (i = 0; i < 2000; i++) { + if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE) + break; + udelay(10); + } + if (i >= 2000) { + printk(KERN_ERR PFX "tg3_reset_hw cannot enable BUFMGR for %s.\n", + tp->dev->name); + return -ENODEV; + } + + tw32(FTQ_RESET, 0xffffffff); + tw32(FTQ_RESET, 0x00000000); + for (i = 0; i < 2000; i++) { + if (tr32(FTQ_RESET) == 0x00000000) + break; + udelay(10); + } + if (i >= 2000) { + printk(KERN_ERR PFX "tg3_reset_hw cannot reset FTQ for %s.\n", + tp->dev->name); + return -ENODEV; + } + + /* Initialize TG3_BDINFO's at: + * RCVDBDI_STD_BD: standard eth size rx ring + * RCVDBDI_JUMBO_BD: jumbo frame rx ring + * RCVDBDI_MINI_BD: small frame rx ring (??? does not work) + * + * like so: + * TG3_BDINFO_HOST_ADDR: high/low parts of DMA address of ring + * TG3_BDINFO_MAXLEN_FLAGS: (rx max buffer size << 16) | + * ring attribute flags + * TG3_BDINFO_NIC_ADDR: location of descriptors in nic SRAM + * + * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries. + * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries. + * + * ??? No space allocated for mini receive ring? :( + * + * The size of each ring is fixed in the firmware, but the location is + * configurable. + */ + tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tp->rx_std_mapping >> 32)); + tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tp->rx_std_mapping & 0xffffffff)); + tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, + RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); + tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, + NIC_SRAM_RX_BUFFER_DESC); + +#if TG3_MINI_RING_WORKS + tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tp->rx_mini_mapping >> 32)); + tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tp->rx_mini_mapping & 0xffffffff)); + tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, + RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); + tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR, + NIC_SRAM_RX_MINI_BUFFER_DESC); +#else + tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); +#endif + + if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { + tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tp->rx_jumbo_mapping >> 32)); + tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tp->rx_jumbo_mapping & 0xffffffff)); + tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, + RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); + tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, + NIC_SRAM_RX_JUMBO_BUFFER_DESC); + } else { + tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + } + + /* Setup replenish thresholds. */ + tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8); +#if TG3_MINI_RING_WORKS + tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8); +#endif + tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); + + /* Clear out send RCB ring in SRAM. */ + for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE) + tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); + + tp->tx_prod = 0; + tp->tx_cons = 0; + tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + + if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, + tp->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + } else { + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, + 0, + BDINFO_FLAGS_DISABLED, + NIC_SRAM_TX_BUFFER_DESC); + } + + for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) { + tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + } + + tp->rx_rcb_ptr = 0; + tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); + + tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, + tp->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + 0); + + tp->rx_std_ptr = tp->rx_pending; + tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, + tp->rx_std_ptr); +#if TG3_MINI_RING_WORKS + tp->rx_mini_ptr = tp->rx_mini_pending; + tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, + tp->rx_mini_ptr); +#endif + + if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) + tp->rx_jumbo_ptr = tp->rx_jumbo_pending; + else + tp->rx_jumbo_ptr = 0; + tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, + tp->rx_jumbo_ptr); + + /* Initialize MAC address and backoff seed. */ + __tg3_set_mac_addr(tp); + + /* MTU + ethernet header + FCS + optional VLAN tag */ + tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8); + + /* The slot time is changed by tg3_setup_phy if we + * run at gigabit with half duplex. + */ + tw32(MAC_TX_LENGTHS, + (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); + + /* Receive rules. */ + tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS); + tw32(RCVLPC_CONFIG, 0x0181); + + /* Receive/send statistics. */ + tw32(RCVLPC_STATS_ENABLE, 0xffffff); + tw32(RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE); + tw32(SNDDATAI_STATSENAB, 0xffffff); + tw32(SNDDATAI_STATSCTRL, + (SNDDATAI_SCTRL_ENABLE | + SNDDATAI_SCTRL_FASTUPD)); + + /* Setup host coalescing engine. */ + tw32(HOSTCC_MODE, 0); + for (i = 0; i < 2000; i++) { + if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE)) + break; + udelay(10); + } + + tw32(HOSTCC_RXCOL_TICKS, + tp->coalesce_config.rx_coalesce_ticks); + tw32(HOSTCC_RXMAX_FRAMES, + tp->coalesce_config.rx_max_coalesced_frames); + tw32(HOSTCC_RXCOAL_TICK_INT, + tp->coalesce_config.rx_coalesce_ticks_during_int); + tw32(HOSTCC_RXCOAL_MAXF_INT, + tp->coalesce_config.rx_max_coalesced_frames_during_int); + tw32(HOSTCC_TXCOL_TICKS, + tp->coalesce_config.tx_coalesce_ticks); + tw32(HOSTCC_TXMAX_FRAMES, + tp->coalesce_config.tx_max_coalesced_frames); + tw32(HOSTCC_TXCOAL_TICK_INT, + tp->coalesce_config.tx_coalesce_ticks_during_int); + tw32(HOSTCC_TXCOAL_MAXF_INT, + tp->coalesce_config.tx_max_coalesced_frames_during_int); + tw32(HOSTCC_STAT_COAL_TICKS, + tp->coalesce_config.stats_coalesce_ticks); + + /* Status/statistics block address. */ + tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tp->stats_mapping >> 32)); + tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tp->stats_mapping & 0xffffffff)); + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tp->status_mapping >> 32)); + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tp->status_mapping & 0xffffffff)); + tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK); + tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK); + + tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode); + + tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE); + tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE); + tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE); + + tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | + MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; + tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); + + tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_AUTO_SEEPROM; + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); + + tw32(DMAC_MODE, DMAC_MODE_ENABLE); + + tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB | + WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB | + WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB | + WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB | + WDMAC_MODE_LNGREAD_ENAB)); + tw32(RDMAC_MODE, (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB | + RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB | + RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB | + RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | + RDMAC_MODE_LNGREAD_ENAB)); + + tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); + tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); + tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); + tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); + tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ); + tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); + tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE); + tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); + + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) { + err = tg3_load_5701_a0_firmware_fix(tp); + if (err) + return err; + } + + tp->tx_mode = TX_MODE_ENABLE; + tw32(MAC_TX_MODE, tp->tx_mode); + tp->rx_mode = RX_MODE_ENABLE; + tw32(MAC_RX_MODE, tp->rx_mode); + + if (tp->link_config.phy_is_low_power) { + tp->link_config.phy_is_low_power = 0; + tp->link_config.speed = tp->link_config.orig_speed; + tp->link_config.duplex = tp->link_config.orig_duplex; + tp->link_config.autoneg = tp->link_config.orig_autoneg; + } + + tp->mi_mode = MAC_MI_MODE_BASE; + tw32(MAC_MI_MODE, tp->mi_mode); + tw32(MAC_LED_CTRL, 0); + tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); + tw32(MAC_RX_MODE, RX_MODE_RESET); + udelay(10); + tw32(MAC_RX_MODE, tp->rx_mode); + + if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) + tw32(MAC_SERDES_CFG, 0x616000); + + err = tg3_setup_phy(tp); + if (err) + return err; + + if (tp->phy_id != PHY_ID_SERDES) { + u32 tmp; + + /* Clear CRC stats. */ + tg3_readphy(tp, 0x1e, &tmp); + tg3_writephy(tp, 0x1e, tmp | 0x8000); + tg3_readphy(tp, 0x14, &tmp); + } + + __tg3_set_rx_mode(tp->dev); + + /* Initialize receive rules. */ + tw32(MAC_RCV_RULE_0, 0xc2000000 & RCV_RULE_DISABLE_MASK); + tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK); + tw32(MAC_RCV_RULE_1, 0x86000004 & RCV_RULE_DISABLE_MASK); + tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); +#if 0 + tw32(MAC_RCV_RULE_2, 0); tw32(MAC_RCV_VALUE_2, 0); + tw32(MAC_RCV_RULE_3, 0); tw32(MAC_RCV_VALUE_3, 0); +#endif + tw32(MAC_RCV_RULE_4, 0); tw32(MAC_RCV_VALUE_4, 0); + tw32(MAC_RCV_RULE_5, 0); tw32(MAC_RCV_VALUE_5, 0); + tw32(MAC_RCV_RULE_6, 0); tw32(MAC_RCV_VALUE_6, 0); + tw32(MAC_RCV_RULE_7, 0); tw32(MAC_RCV_VALUE_7, 0); + tw32(MAC_RCV_RULE_8, 0); tw32(MAC_RCV_VALUE_8, 0); + tw32(MAC_RCV_RULE_9, 0); tw32(MAC_RCV_VALUE_9, 0); + tw32(MAC_RCV_RULE_10, 0); tw32(MAC_RCV_VALUE_10, 0); + tw32(MAC_RCV_RULE_11, 0); tw32(MAC_RCV_VALUE_11, 0); + tw32(MAC_RCV_RULE_12, 0); tw32(MAC_RCV_VALUE_12, 0); + tw32(MAC_RCV_RULE_13, 0); tw32(MAC_RCV_VALUE_13, 0); + tw32(MAC_RCV_RULE_14, 0); tw32(MAC_RCV_VALUE_14, 0); + tw32(MAC_RCV_RULE_15, 0); tw32(MAC_RCV_VALUE_15, 0); + + if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) + tg3_enable_ints(tp); + + return 0; +} + +/* Called at device open time to get the chip ready for + * packet processing. Invoked with tp->lock held. + */ +static int tg3_init_hw(struct tg3 *tp) +{ + int err; + + /* Force the chip into D0. */ + err = tg3_set_power_state(tp, 0); + if (err) + goto out; + + tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); + + err = tg3_reset_hw(tp); + +out: + return err; +} + +static void tg3_timer(unsigned long __opaque) +{ + struct tg3 *tp = (struct tg3 *) __opaque; + + spin_lock_irq(&tp->lock); + + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)) { + /* All of this garbage is because on the 5700 the + * mailbox/status_block protocol the chip uses with + * the cpu is race prone. + */ + if (tp->hw_status->status & SD_STATUS_UPDATED) { + tw32(GRC_LOCAL_CTRL, + tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + } else { + tw32(HOSTCC_MODE, + (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + } + + if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tg3_halt(tp); + tg3_init_rings(tp); + tg3_init_hw(tp); + } + } + + /* This part only runs once per second. */ + if (!--tp->timer_counter) { + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + u32 mac_stat; + int phy_event; + + mac_stat = tr32(MAC_STATUS); + + phy_event = 0; + if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) { + if (mac_stat & MAC_STATUS_MI_INTERRUPT) + phy_event = 1; + } else if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED) + phy_event = 1; + + if (phy_event) + tg3_setup_phy(tp); + } + + tp->timer_counter = tp->timer_multiplier; + } + + spin_unlock_irq(&tp->lock); + + tp->timer.expires = jiffies + tp->timer_offset; + add_timer(&tp->timer); +} + +static int tg3_open(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + int err; + + spin_lock_irq(&tp->lock); + + tg3_disable_ints(tp); + tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + + spin_unlock_irq(&tp->lock); + + /* If you move this call, make sure TG3_FLAG_HOST_TXDS in + * tp->tg3_flags is accurate at that new place. + */ + err = tg3_alloc_consistent(tp); + if (err) + return err; + + if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS) + err = request_irq(dev->irq, tg3_interrupt_tagged, + SA_SHIRQ, dev->name, dev); + else + err = request_irq(dev->irq, tg3_interrupt, + SA_SHIRQ, dev->name, dev); + + if (err) { + tg3_free_consistent(tp); + return err; + } + + spin_lock_irq(&tp->lock); + + tg3_init_rings(tp); + + err = tg3_init_hw(tp); + if (err) { + tg3_halt(tp); + tg3_free_rings(tp); + } else { + if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS) { + tp->timer_offset = HZ; + tp->timer_counter = tp->timer_multiplier = 1; + } else { + tp->timer_offset = HZ / 10; + tp->timer_counter = tp->timer_multiplier = 10; + } + + init_timer(&tp->timer); + tp->timer.expires = jiffies + tp->timer_offset; + tp->timer.data = (unsigned long) tp; + tp->timer.function = tg3_timer; + add_timer(&tp->timer); + + tp->last_rate_sample = jiffies; + tp->last_rx_count = 0; + tp->last_tx_count = 0; + + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + } + + spin_unlock_irq(&tp->lock); + + if (err) { + free_irq(dev->irq, dev); + tg3_free_consistent(tp); + return err; + } + + netif_start_queue(dev); + + spin_lock_irq(&tp->lock); + + tg3_enable_ints(tp); + + spin_unlock_irq(&tp->lock); + + return 0; +} + +#if 0 +/*static*/ void tg3_dump_state(struct tg3 *tp) +{ + u32 val32, val32_2, val32_3, val32_4, val32_5; + u16 val16; + int i; + + pci_read_config_word(tp->pdev, PCI_STATUS, &val16); + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &val32); + printk("DEBUG: PCI status [%04x] TG3PCI state[%08x]\n", + val16, val32); + + /* MAC block */ + printk("DEBUG: MAC_MODE[%08x] MAC_STATUS[%08x]\n", + tr32(MAC_MODE), tr32(MAC_STATUS)); + printk(" MAC_EVENT[%08x] MAC_LED_CTRL[%08x]\n", + tr32(MAC_EVENT), tr32(MAC_LED_CTRL)); + printk("DEBUG: MAC_TX_MODE[%08x] MAC_TX_STATUS[%08x]\n", + tr32(MAC_TX_MODE), tr32(MAC_TX_STATUS)); + printk(" MAC_RX_MODE[%08x] MAC_RX_STATUS[%08x]\n", + tr32(MAC_RX_MODE), tr32(MAC_RX_STATUS)); + + /* Send data initiator control block */ + printk("DEBUG: SNDDATAI_MODE[%08x] SNDDATAI_STATUS[%08x]\n", + tr32(SNDDATAI_MODE), tr32(SNDDATAI_STATUS)); + printk(" SNDDATAI_STATSCTRL[%08x]\n", + tr32(SNDDATAI_STATSCTRL)); + + /* Send data completion control block */ + printk("DEBUG: SNDDATAC_MODE[%08x]\n", tr32(SNDDATAC_MODE)); + + /* Send BD ring selector block */ + printk("DEBUG: SNDBDS_MODE[%08x] SNDBDS_STATUS[%08x]\n", + tr32(SNDBDS_MODE), tr32(SNDBDS_STATUS)); + + /* Send BD initiator control block */ + printk("DEBUG: SNDBDI_MODE[%08x] SNDBDI_STATUS[%08x]\n", + tr32(SNDBDI_MODE), tr32(SNDBDI_STATUS)); + + /* Send BD completion control block */ + printk("DEBUG: SNDBDC_MODE[%08x]\n", tr32(SNDBDC_MODE)); + + /* Receive list placement control block */ + printk("DEBUG: RCVLPC_MODE[%08x] RCVLPC_STATUS[%08x]\n", + tr32(RCVLPC_MODE), tr32(RCVLPC_STATUS)); + printk(" RCVLPC_STATSCTRL[%08x]\n", + tr32(RCVLPC_STATSCTRL)); + + /* Receive data and receive BD initiator control block */ + printk("DEBUG: RCVDBDI_MODE[%08x] RCVDBDI_STATUS[%08x]\n", + tr32(RCVDBDI_MODE), tr32(RCVDBDI_STATUS)); + + /* Receive data completion control block */ + printk("DEBUG: RCVDCC_MODE[%08x]\n", + tr32(RCVDCC_MODE)); + + /* Receive BD initiator control block */ + printk("DEBUG: RCVBDI_MODE[%08x] RCVBDI_STATUS[%08x]\n", + tr32(RCVBDI_MODE), tr32(RCVBDI_STATUS)); + + /* Receive BD completion control block */ + printk("DEBUG: RCVCC_MODE[%08x] RCVCC_STATUS[%08x]\n", + tr32(RCVCC_MODE), tr32(RCVCC_STATUS)); + + /* Receive list selector control block */ + printk("DEBUG: RCVLSC_MODE[%08x] RCVLSC_STATUS[%08x]\n", + tr32(RCVLSC_MODE), tr32(RCVLSC_STATUS)); + + /* Mbuf cluster free block */ + printk("DEBUG: MBFREE_MODE[%08x] MBFREE_STATUS[%08x]\n", + tr32(MBFREE_MODE), tr32(MBFREE_STATUS)); + + /* Host coalescing control block */ + printk("DEBUG: HOSTCC_MODE[%08x] HOSTCC_STATUS[%08x]\n", + tr32(HOSTCC_MODE), tr32(HOSTCC_STATUS)); + printk("DEBUG: HOSTCC_STATS_BLK_HOST_ADDR[%08x%08x]\n", + tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH), + tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW)); + printk("DEBUG: HOSTCC_STATUS_BLK_HOST_ADDR[%08x%08x]\n", + tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH), + tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW)); + printk("DEBUG: HOSTCC_STATS_BLK_NIC_ADDR[%08x]\n", + tr32(HOSTCC_STATS_BLK_NIC_ADDR)); + printk("DEBUG: HOSTCC_STATUS_BLK_NIC_ADDR[%08x]\n", + tr32(HOSTCC_STATUS_BLK_NIC_ADDR)); + + /* Memory arbiter control block */ + printk("DEBUG: MEMARB_MODE[%08x] MEMARB_STATUS[%08x]\n", + tr32(MEMARB_MODE), tr32(MEMARB_STATUS)); + + /* Buffer manager control block */ + printk("DEBUG: BUFMGR_MODE[%08x] BUFMGR_STATUS[%08x]\n", + tr32(BUFMGR_MODE), tr32(BUFMGR_STATUS)); + printk("DEBUG: BUFMGR_MB_POOL_ADDR[%08x] BUFMGR_MB_POOL_SIZE[%08x]\n", + tr32(BUFMGR_MB_POOL_ADDR), tr32(BUFMGR_MB_POOL_SIZE)); + printk("DEBUG: BUFMGR_DMA_DESC_POOL_ADDR[%08x] " + "BUFMGR_DMA_DESC_POOL_SIZE[%08x]\n", + tr32(BUFMGR_DMA_DESC_POOL_ADDR), + tr32(BUFMGR_DMA_DESC_POOL_SIZE)); + + /* Read DMA control block */ + printk("DEBUG: RDMAC_MODE[%08x] RDMAC_STATUS[%08x]\n", + tr32(RDMAC_MODE), tr32(RDMAC_STATUS)); + + /* Write DMA control block */ + printk("DEBUG: WDMAC_MODE[%08x] WDMAC_STATUS[%08x]\n", + tr32(WDMAC_MODE), tr32(WDMAC_STATUS)); + + /* DMA completion block */ + printk("DEBUG: DMAC_MODE[%08x]\n", + tr32(DMAC_MODE)); + + /* GRC block */ + printk("DEBUG: GRC_MODE[%08x] GRC_MISC_CFG[%08x]\n", + tr32(GRC_MODE), tr32(GRC_MISC_CFG)); + printk("DEBUG: GRC_LOCAL_CTRL[%08x]\n", + tr32(GRC_LOCAL_CTRL)); + + /* TG3_BDINFOs */ + printk("DEBUG: RCVDBDI_JUMBO_BD[%08x%08x:%08x:%08x]\n", + tr32(RCVDBDI_JUMBO_BD + 0x0), + tr32(RCVDBDI_JUMBO_BD + 0x4), + tr32(RCVDBDI_JUMBO_BD + 0x8), + tr32(RCVDBDI_JUMBO_BD + 0xc)); + printk("DEBUG: RCVDBDI_STD_BD[%08x%08x:%08x:%08x]\n", + tr32(RCVDBDI_STD_BD + 0x0), + tr32(RCVDBDI_STD_BD + 0x4), + tr32(RCVDBDI_STD_BD + 0x8), + tr32(RCVDBDI_STD_BD + 0xc)); + printk("DEBUG: RCVDBDI_MINI_BD[%08x%08x:%08x:%08x]\n", + tr32(RCVDBDI_MINI_BD + 0x0), + tr32(RCVDBDI_MINI_BD + 0x4), + tr32(RCVDBDI_MINI_BD + 0x8), + tr32(RCVDBDI_MINI_BD + 0xc)); + + tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x0, &val32); + tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x4, &val32_2); + tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x8, &val32_3); + tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0xc, &val32_4); + printk("DEBUG: SRAM_SEND_RCB_0[%08x%08x:%08x:%08x]\n", + val32, val32_2, val32_3, val32_4); + + tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x0, &val32); + tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x4, &val32_2); + tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x8, &val32_3); + tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0xc, &val32_4); + printk("DEBUG: SRAM_RCV_RET_RCB_0[%08x%08x:%08x:%08x]\n", + val32, val32_2, val32_3, val32_4); + + tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x0, &val32); + tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x4, &val32_2); + tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x8, &val32_3); + tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0xc, &val32_4); + tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x10, &val32_5); + printk("DEBUG: SRAM_STATUS_BLK[%08x:%08x:%08x:%08x:%08x]\n", + val32, val32_2, val32_3, val32_4, val32_5); + + /* SW status block */ + printk("DEBUG: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + tp->hw_status->status, + tp->hw_status->status_tag, + tp->hw_status->rx_jumbo_consumer, + tp->hw_status->rx_consumer, + tp->hw_status->rx_mini_consumer, + tp->hw_status->idx[0].rx_producer, + tp->hw_status->idx[0].tx_consumer); + + /* SW statistics block */ + printk("DEBUG: Host statistics block [%08x:%08x:%08x:%08x]\n", + ((u32 *)tp->hw_stats)[0], + ((u32 *)tp->hw_stats)[1], + ((u32 *)tp->hw_stats)[2], + ((u32 *)tp->hw_stats)[3]); + + /* Mailboxes */ + printk("DEBUG: SNDHOST_PROD[%08x%08x] SNDNIC_PROD[%08x%08x]\n", + tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x0), + tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x4), + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x0), + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x4)); + + /* NIC side send descriptors. */ + for (i = 0; i < 6; i++) { + unsigned long txd; + + txd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_TX_BUFFER_DESC + + (i * sizeof(struct tg3_tx_buffer_desc)); + printk("DEBUG: NIC TXD(%d)[%08x:%08x:%08x:%08x]\n", + i, + readl(txd + 0x0), readl(txd + 0x4), + readl(txd + 0x8), readl(txd + 0xc)); + } + + /* NIC side RX descriptors. */ + for (i = 0; i < 6; i++) { + unsigned long rxd; + + rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_BUFFER_DESC + + (i * sizeof(struct tg3_rx_buffer_desc)); + printk("DEBUG: NIC RXD_STD(%d)[0][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + rxd += (4 * sizeof(u32)); + printk("DEBUG: NIC RXD_STD(%d)[1][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + } +#if TG3_MINI_RING_WORKS + for (i = 0; i < 6; i++) { + unsigned long rxd; + + rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC + + (i * sizeof(struct tg3_rx_buffer_desc)); + printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + rxd += (4 * sizeof(u32)); + printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + } +#endif + + for (i = 0; i < 6; i++) { + unsigned long rxd; + + rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_JUMBO_BUFFER_DESC + + (i * sizeof(struct tg3_rx_buffer_desc)); + printk("DEBUG: NIC RXD_JUMBO(%d)[0][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + rxd += (4 * sizeof(u32)); + printk("DEBUG: NIC RXD_JUMBO(%d)[1][%08x:%08x:%08x:%08x]\n", + i, + readl(rxd + 0x0), readl(rxd + 0x4), + readl(rxd + 0x8), readl(rxd + 0xc)); + } +} +#endif + +static struct net_device_stats *tg3_get_stats(struct net_device *); + +static int tg3_close(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + + netif_stop_queue(dev); + + del_timer_sync(&tp->timer); + + spin_lock_irq(&tp->lock); +#if 0 + tg3_dump_state(tp); +#endif + + tg3_disable_ints(tp); + + tg3_halt(tp); + tg3_free_rings(tp); + tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + + spin_unlock_irq(&tp->lock); + + free_irq(dev->irq, dev); + + memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), + sizeof(tp->net_stats_prev)); + + tg3_free_consistent(tp); + + return 0; +} + +static inline unsigned long get_stat64(tg3_stat64_t *val) +{ + unsigned long ret; + +#if (BITS_PER_LONG == 32) + if (val->high != 0) + ret = ~0UL; + else + ret = val->low; +#else + ret = ((u64)val->high << 32) | ((u64)val->low); +#endif + return ret; +} + +static unsigned long calc_crc_errors(struct tg3 *tp) +{ + struct tg3_hw_stats *hw_stats = tp->hw_stats; + + if (tp->phy_id != PHY_ID_SERDES && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { + unsigned long flags; + u32 val; + + spin_lock_irqsave(&tp->lock, flags); + tg3_readphy(tp, 0x1e, &val); + tg3_writephy(tp, 0x1e, val | 0x8000); + tg3_readphy(tp, 0x14, &val); + spin_unlock_irqrestore(&tp->lock, flags); + + tp->phy_crc_errors += val; + + return tp->phy_crc_errors; + } + + return get_stat64(&hw_stats->rx_fcs_errors); +} + +static struct net_device_stats *tg3_get_stats(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + struct net_device_stats *stats = &tp->net_stats; + struct net_device_stats *old_stats = &tp->net_stats_prev; + struct tg3_hw_stats *hw_stats = tp->hw_stats; + + if (!hw_stats) + return old_stats; + + stats->rx_packets = old_stats->rx_packets + + get_stat64(&hw_stats->rx_ucast_packets) + + get_stat64(&hw_stats->rx_mcast_packets) + + get_stat64(&hw_stats->rx_bcast_packets); + + stats->tx_packets = old_stats->tx_packets + + get_stat64(&hw_stats->COS_out_packets[0]); + + stats->rx_bytes = old_stats->rx_bytes + + get_stat64(&hw_stats->rx_octets); + stats->tx_bytes = old_stats->tx_bytes + + get_stat64(&hw_stats->tx_octets); + + stats->rx_errors = old_stats->rx_errors + + get_stat64(&hw_stats->rx_errors); + stats->tx_errors = old_stats->tx_errors + + get_stat64(&hw_stats->tx_errors) + + get_stat64(&hw_stats->tx_mac_errors) + + get_stat64(&hw_stats->tx_carrier_sense_errors) + + get_stat64(&hw_stats->tx_discards); + + stats->multicast = old_stats->multicast + + get_stat64(&hw_stats->rx_mcast_packets); + stats->collisions = old_stats->collisions + + get_stat64(&hw_stats->tx_collisions); + + stats->rx_length_errors = old_stats->rx_length_errors + + get_stat64(&hw_stats->rx_frame_too_long_errors) + + get_stat64(&hw_stats->rx_undersize_packets); + + stats->rx_over_errors = old_stats->rx_over_errors + + get_stat64(&hw_stats->rxbds_empty); + stats->rx_frame_errors = old_stats->rx_frame_errors + + get_stat64(&hw_stats->rx_align_errors); + stats->tx_aborted_errors = old_stats->tx_aborted_errors + + get_stat64(&hw_stats->tx_discards); + stats->tx_carrier_errors = old_stats->tx_carrier_errors + + get_stat64(&hw_stats->tx_carrier_sense_errors); + + stats->rx_crc_errors = old_stats->rx_crc_errors + + calc_crc_errors(tp); + + return stats; +} + +static inline u32 calc_crc(unsigned char *buf, int len) +{ + u32 reg; + u32 tmp; + int j, k; + + reg = 0xffffffff; + + for (j = 0; j < len; j++) { + reg ^= buf[j]; + + for (k = 0; k < 8; k++) { + tmp = reg & 0x01; + + reg >>= 1; + + if (tmp) { + reg ^= 0xedb88320; + } + } + } + + return ~reg; +} + +static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all) +{ + /* accept or reject all multicast frames */ + tw32 (MAC_HASH_REG_0, accept_all ? 0xffffffff : 0); + tw32 (MAC_HASH_REG_1, accept_all ? 0xffffffff : 0); + tw32 (MAC_HASH_REG_2, accept_all ? 0xffffffff : 0); + tw32 (MAC_HASH_REG_3, accept_all ? 0xffffffff : 0); +} + +static void __tg3_set_rx_mode(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + u32 rx_mode; + + rx_mode = tp->rx_mode & ~RX_MODE_PROMISC; + + if (dev->flags & IFF_PROMISC) { + /* Promiscuous mode. */ + rx_mode |= RX_MODE_PROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + /* Accept all multicast. */ + tg3_set_multi (tp, 1); + } else if (dev->mc_count < 1) { + /* Reject all multicast. */ + tg3_set_multi (tp, 0); + } else { + /* Accept one or more multicast(s). */ + struct dev_mc_list *mclist; + unsigned int i; + u32 mc_filter[4] = { 0, }; + u32 regidx; + u32 bit; + u32 crc; + + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + + crc = calc_crc (mclist->dmi_addr, ETH_ALEN); + bit = ~crc & 0x7f; + regidx = (bit & 0x60) >> 5; + bit &= 0x1f; + mc_filter[regidx] |= (1 << bit); + } + + tw32 (MAC_HASH_REG_0, mc_filter[0]); + tw32 (MAC_HASH_REG_1, mc_filter[1]); + tw32 (MAC_HASH_REG_2, mc_filter[2]); + tw32 (MAC_HASH_REG_3, mc_filter[3]); + } + + if (rx_mode != tp->rx_mode) { + tp->rx_mode = rx_mode; + tw32 (MAC_RX_MODE, rx_mode); + } +} + +static void tg3_set_rx_mode(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + + spin_lock_irq(&tp->lock); + __tg3_set_rx_mode(dev); + spin_unlock_irq(&tp->lock); +} + +#define TG3_REGDUMP_LEN (32 * 1024) + +static u8 *tg3_get_regs(struct tg3 *tp) +{ + u8 *orig_p = kmalloc(TG3_REGDUMP_LEN, GFP_KERNEL); + u8 *p; + int i; + + if (orig_p == NULL) + return NULL; + + memset(orig_p, 0, TG3_REGDUMP_LEN); + + spin_lock_irq(&tp->lock); + +#define __GET_REG32(reg) (*((u32 *)(p))++ = tr32(reg)) +#define GET_REG32_LOOP(base,len) \ +do { p = orig_p + (base); \ + for (i = 0; i < len; i += 4) \ + __GET_REG32((base) + i); \ +} while (0) +#define GET_REG32_1(reg) \ +do { p = orig_p + (reg); \ + __GET_REG32((reg)); \ +} while (0) + + GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0); + GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200); + GET_REG32_LOOP(MAC_MODE, 0x4f0); + GET_REG32_LOOP(SNDDATAI_MODE, 0xe0); + GET_REG32_1(SNDDATAC_MODE); + GET_REG32_LOOP(SNDBDS_MODE, 0x80); + GET_REG32_LOOP(SNDBDI_MODE, 0x48); + GET_REG32_1(SNDBDC_MODE); + GET_REG32_LOOP(RCVLPC_MODE, 0x20); + GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c); + GET_REG32_LOOP(RCVDBDI_MODE, 0x0c); + GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c); + GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44); + GET_REG32_1(RCVDCC_MODE); + GET_REG32_LOOP(RCVBDI_MODE, 0x20); + GET_REG32_LOOP(RCVCC_MODE, 0x14); + GET_REG32_LOOP(RCVLSC_MODE, 0x08); + GET_REG32_1(MBFREE_MODE); + GET_REG32_LOOP(HOSTCC_MODE, 0x100); + GET_REG32_LOOP(MEMARB_MODE, 0x10); + GET_REG32_LOOP(BUFMGR_MODE, 0x58); + GET_REG32_LOOP(RDMAC_MODE, 0x08); + GET_REG32_LOOP(WDMAC_MODE, 0x08); + GET_REG32_LOOP(RX_CPU_BASE, 0x280); + GET_REG32_LOOP(TX_CPU_BASE, 0x280); + GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110); + GET_REG32_LOOP(FTQ_RESET, 0x120); + GET_REG32_LOOP(MSGINT_MODE, 0x0c); + GET_REG32_1(DMAC_MODE); + GET_REG32_LOOP(GRC_MODE, 0x4c); + GET_REG32_LOOP(NVRAM_CMD, 0x24); + +#undef __GET_REG32 +#undef GET_REG32_LOOP +#undef GET_REG32_1 + + spin_unlock_irq(&tp->lock); + + return orig_p; +} + +static void tg3_to_ethtool_coal(struct tg3 *tp, + struct ethtool_coalesce *ecoal) +{ + ecoal->rx_coalesce_usecs = + tp->coalesce_config.rx_coalesce_ticks_def; + ecoal->rx_max_coalesced_frames = + tp->coalesce_config.rx_max_coalesced_frames_def; + ecoal->rx_coalesce_usecs_irq = + tp->coalesce_config.rx_coalesce_ticks_during_int_def; + ecoal->rx_max_coalesced_frames_irq = + tp->coalesce_config.rx_max_coalesced_frames_during_int_def; + + ecoal->tx_coalesce_usecs = + tp->coalesce_config.tx_coalesce_ticks_def; + ecoal->tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_def; + ecoal->tx_coalesce_usecs_irq = + tp->coalesce_config.tx_coalesce_ticks_during_int_def; + ecoal->tx_max_coalesced_frames_irq = + tp->coalesce_config.tx_max_coalesced_frames_during_int_def; + + ecoal->stats_block_coalesce_usecs = + tp->coalesce_config.stats_coalesce_ticks_def; + + ecoal->use_adaptive_rx_coalesce = + (tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0; + ecoal->use_adaptive_tx_coalesce = + (tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0; + + ecoal->pkt_rate_low = + tp->coalesce_config.pkt_rate_low; + ecoal->rx_coalesce_usecs_low = + tp->coalesce_config.rx_coalesce_ticks_low; + ecoal->rx_max_coalesced_frames_low = + tp->coalesce_config.rx_max_coalesced_frames_low; + ecoal->tx_coalesce_usecs_low = + tp->coalesce_config.tx_coalesce_ticks_low; + ecoal->tx_max_coalesced_frames_low = + tp->coalesce_config.tx_max_coalesced_frames_low; + + ecoal->pkt_rate_high = + tp->coalesce_config.pkt_rate_high; + ecoal->rx_coalesce_usecs_high = + tp->coalesce_config.rx_coalesce_ticks_high; + ecoal->rx_max_coalesced_frames_high = + tp->coalesce_config.rx_max_coalesced_frames_high; + ecoal->tx_coalesce_usecs_high = + tp->coalesce_config.tx_coalesce_ticks_high; + ecoal->tx_max_coalesced_frames_high = + tp->coalesce_config.tx_max_coalesced_frames_high; + + ecoal->rate_sample_interval = + tp->coalesce_config.rate_sample_jiffies / HZ; +} + +static int tg3_from_ethtool_coal(struct tg3 *tp, + struct ethtool_coalesce *ecoal) +{ + /* Make sure we are not getting garbage. */ + if ((ecoal->rx_coalesce_usecs == 0 && + ecoal->rx_max_coalesced_frames == 0) || + (ecoal->tx_coalesce_usecs == 0 && + ecoal->tx_max_coalesced_frames == 0) || + ecoal->stats_block_coalesce_usecs == 0) + return -EINVAL; + if (ecoal->use_adaptive_rx_coalesce || + ecoal->use_adaptive_tx_coalesce) { + if (ecoal->pkt_rate_low > ecoal->pkt_rate_high) + return -EINVAL; + if (ecoal->rate_sample_interval == 0) + return -EINVAL; + if (ecoal->use_adaptive_rx_coalesce && + ((ecoal->rx_coalesce_usecs_low == 0 && + ecoal->rx_max_coalesced_frames_low == 0) || + (ecoal->rx_coalesce_usecs_high == 0 && + ecoal->rx_max_coalesced_frames_high == 0))) + return -EINVAL; + if (ecoal->use_adaptive_tx_coalesce && + ((ecoal->tx_coalesce_usecs_low == 0 && + ecoal->tx_max_coalesced_frames_low == 0) || + (ecoal->tx_coalesce_usecs_high == 0 && + ecoal->tx_max_coalesced_frames_high == 0))) + return -EINVAL; + } + + /* Looks good, let it rip. */ + spin_lock_irq(&tp->lock); + tp->coalesce_config.rx_coalesce_ticks = + tp->coalesce_config.rx_coalesce_ticks_def = + ecoal->rx_coalesce_usecs; + tp->coalesce_config.rx_max_coalesced_frames = + tp->coalesce_config.rx_max_coalesced_frames_def = + ecoal->rx_max_coalesced_frames; + tp->coalesce_config.rx_coalesce_ticks_during_int = + tp->coalesce_config.rx_coalesce_ticks_during_int_def = + ecoal->rx_coalesce_usecs_irq; + tp->coalesce_config.rx_max_coalesced_frames_during_int = + tp->coalesce_config.rx_max_coalesced_frames_during_int_def = + ecoal->rx_max_coalesced_frames_irq; + tp->coalesce_config.tx_coalesce_ticks = + tp->coalesce_config.tx_coalesce_ticks_def = + ecoal->tx_coalesce_usecs; + tp->coalesce_config.tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_def = + ecoal->tx_max_coalesced_frames; + tp->coalesce_config.tx_coalesce_ticks_during_int = + tp->coalesce_config.tx_coalesce_ticks_during_int_def = + ecoal->tx_coalesce_usecs_irq; + tp->coalesce_config.tx_max_coalesced_frames_during_int = + tp->coalesce_config.tx_max_coalesced_frames_during_int_def = + ecoal->tx_max_coalesced_frames_irq; + tp->coalesce_config.stats_coalesce_ticks = + tp->coalesce_config.stats_coalesce_ticks_def = + ecoal->stats_block_coalesce_usecs; + + if (ecoal->use_adaptive_rx_coalesce) + tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX; + else + tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_RX; + if (ecoal->use_adaptive_tx_coalesce) + tp->tg3_flags |= TG3_FLAG_ADAPTIVE_TX; + else + tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_TX; + + tp->coalesce_config.pkt_rate_low = ecoal->pkt_rate_low; + tp->coalesce_config.pkt_rate_high = ecoal->pkt_rate_high; + tp->coalesce_config.rate_sample_jiffies = + ecoal->rate_sample_interval * HZ; + + tp->coalesce_config.rx_coalesce_ticks_low = + ecoal->rx_coalesce_usecs_low; + tp->coalesce_config.rx_max_coalesced_frames_low = + ecoal->rx_max_coalesced_frames_low; + tp->coalesce_config.tx_coalesce_ticks_low = + ecoal->tx_coalesce_usecs_low; + tp->coalesce_config.tx_max_coalesced_frames_low = + ecoal->tx_max_coalesced_frames_low; + + tp->coalesce_config.rx_coalesce_ticks_high = + ecoal->rx_coalesce_usecs_high; + tp->coalesce_config.rx_max_coalesced_frames_high = + ecoal->rx_max_coalesced_frames_high; + tp->coalesce_config.tx_coalesce_ticks_high = + ecoal->tx_coalesce_usecs_high; + tp->coalesce_config.tx_max_coalesced_frames_high = + ecoal->tx_max_coalesced_frames_high; + + tw32(HOSTCC_RXCOL_TICKS, + tp->coalesce_config.rx_coalesce_ticks_def); + tw32(HOSTCC_RXMAX_FRAMES, + tp->coalesce_config.rx_max_coalesced_frames_def); + tw32(HOSTCC_RXCOAL_TICK_INT, + tp->coalesce_config.rx_coalesce_ticks_during_int_def); + tw32(HOSTCC_RXCOAL_MAXF_INT, + tp->coalesce_config.rx_max_coalesced_frames_during_int_def); + tw32(HOSTCC_TXCOL_TICKS, + tp->coalesce_config.tx_coalesce_ticks_def); + tw32(HOSTCC_TXMAX_FRAMES, + tp->coalesce_config.tx_max_coalesced_frames_def); + tw32(HOSTCC_TXCOAL_TICK_INT, + tp->coalesce_config.tx_coalesce_ticks_during_int_def); + tw32(HOSTCC_TXCOAL_MAXF_INT, + tp->coalesce_config.tx_max_coalesced_frames_during_int_def); + tw32(HOSTCC_STAT_COAL_TICKS, + tp->coalesce_config.stats_coalesce_ticks_def); + + spin_unlock_irq(&tp->lock); + + return 0; +} + +static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + struct tg3 *tp = dev->priv; + struct pci_dev *pci_dev = tp->pdev; + u32 ethcmd; + + if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO:{ + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_MODULE_NAME); + strcpy (info.version, DRV_MODULE_VERSION); + memset(&info.fw_version, 0, sizeof(info.fw_version)); + strcpy (info.bus_info, pci_dev->slot_name); + info.eedump_len = 0; + info.regdump_len = TG3_REGDUMP_LEN; + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + case ETHTOOL_GSET: { + struct ethtool_cmd cmd = { ETHTOOL_GSET }; + + if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || + tp->link_config.phy_is_low_power) + return -EAGAIN; + cmd.supported = (SUPPORTED_Autoneg); + + if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) + cmd.supported |= (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + if (tp->phy_id != PHY_ID_SERDES) + cmd.supported |= (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_MII); + else + cmd.supported |= SUPPORTED_FIBRE; + + cmd.advertising = tp->link_config.advertising; + cmd.speed = tp->link_config.active_speed; + cmd.duplex = tp->link_config.active_duplex; + cmd.port = 0; + cmd.phy_address = PHY_ADDR; + cmd.transceiver = 0; + cmd.autoneg = tp->link_config.autoneg; + cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames_def; + cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames_def; + if (copy_to_user(useraddr, &cmd, sizeof(cmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET: { + struct ethtool_cmd cmd; + + if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || + tp->link_config.phy_is_low_power) + return -EAGAIN; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + /* Fiber PHY only supports 1000 full/half */ + if (cmd.autoneg == AUTONEG_ENABLE) { + if (tp->phy_id == PHY_ID_SERDES && + (cmd.advertising & + (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full))) + return -EINVAL; + if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) && + (cmd.advertising & + (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full))) + return -EINVAL; + } else { + if (tp->phy_id == PHY_ID_SERDES && + (cmd.speed == SPEED_10 || + cmd.speed == SPEED_100)) + return -EINVAL; + if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) && + (cmd.speed == SPEED_10 || + cmd.speed == SPEED_100)) + return -EINVAL; + } + + spin_lock_irq(&tp->lock); + + tp->link_config.autoneg = cmd.autoneg; + if (cmd.autoneg == AUTONEG_ENABLE) { + tp->link_config.advertising = cmd.advertising; + tp->link_config.speed = SPEED_INVALID; + tp->link_config.duplex = DUPLEX_INVALID; + } else { + tp->link_config.speed = cmd.speed; + tp->link_config.duplex = cmd.duplex; + } + + if (cmd.maxtxpkt || cmd.maxrxpkt) { + tp->coalesce_config.tx_max_coalesced_frames_def = + tp->coalesce_config.tx_max_coalesced_frames = + cmd.maxtxpkt; + tp->coalesce_config.rx_max_coalesced_frames_def = + tp->coalesce_config.rx_max_coalesced_frames = + cmd.maxrxpkt; + + /* Coalescing config bits can be updated without + * a full chip reset. + */ + tw32(HOSTCC_TXMAX_FRAMES, + tp->coalesce_config.tx_max_coalesced_frames); + tw32(HOSTCC_RXMAX_FRAMES, + tp->coalesce_config.rx_max_coalesced_frames); + } + tg3_setup_phy(tp); + spin_unlock_irq(&tp->lock); + + return 0; + } + + case ETHTOOL_GREGS: { + struct ethtool_regs regs; + u8 *regbuf; + int ret; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + if (regs.len > TG3_REGDUMP_LEN) + regs.len = TG3_REGDUMP_LEN; + regs.version = 0; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + return -EFAULT; + + regbuf = tg3_get_regs(tp); + if (!regbuf) + return -ENOMEM; + + useraddr += offsetof(struct ethtool_regs, data); + ret = 0; + if (copy_to_user(useraddr, regbuf, regs.len)) + ret = -EFAULT; + kfree(regbuf); + return ret; + } + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; + + wol.supported = WAKE_MAGIC; + wol.wolopts = 0; + if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + wol.wolopts = WAKE_MAGIC; + memset(&wol.sopass, 0, sizeof(wol.sopass)); + if (copy_to_user(useraddr, &wol, sizeof(wol))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + + if (copy_from_user(&wol, useraddr, sizeof(wol))) + return -EFAULT; + if (wol.wolopts & ~WAKE_MAGIC) + return -EINVAL; + spin_lock_irq(&tp->lock); + if (wol.wolopts & WAKE_MAGIC) + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + else + tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + spin_unlock_irq(&tp->lock); + + return 0; + } + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = { ETHTOOL_GMSGLVL }; + edata.data = tp->msg_enable; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + tp->msg_enable = edata.data; + return 0; + } + case ETHTOOL_NWAY_RST: { + u32 bmcr; + int r; + + spin_lock_irq(&tp->lock); + tg3_readphy(tp, MII_BMCR, &bmcr); + tg3_readphy(tp, MII_BMCR, &bmcr); + r = -EINVAL; + if (bmcr & BMCR_ANENABLE) { + tg3_writephy(tp, MII_BMCR, + bmcr | BMCR_ANRESTART); + r = 0; + } + spin_unlock_irq(&tp->lock); + + return r; + } + case ETHTOOL_GLINK: { + struct ethtool_value edata = { ETHTOOL_GLINK }; + edata.data = netif_carrier_ok(tp->dev) ? 1 : 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + } + case ETHTOOL_GCOALESCE: { + struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE }; + + tg3_to_ethtool_coal(tp, &ecoal); + if (copy_to_user(useraddr, &ecoal, sizeof(ecoal))) + return -EFAULT; + return 0; + } + case ETHTOOL_SCOALESCE: { + struct ethtool_coalesce ecoal; + + if (copy_from_user(&ecoal, useraddr, sizeof(ecoal))) + return -EINVAL; + + return tg3_from_ethtool_coal(tp, &ecoal); + } + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; + + ering.rx_max_pending = TG3_RX_RING_SIZE - 1; +#if TG3_MINI_RING_WORKS + ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1; +#else + ering.rx_mini_max_pending = 0; +#endif + ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1; + + ering.rx_pending = tp->rx_pending; +#if TG3_MINI_RING_WORKS + ering.rx_mini_pending = tp->rx_mini_pending; +#else + ering.rx_mini_pending = 0; +#endif + ering.rx_jumbo_pending = tp->rx_jumbo_pending; + ering.tx_pending = tp->tx_pending; + + if (copy_to_user(useraddr, &ering, sizeof(ering))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + + if (copy_from_user(&ering, useraddr, sizeof(ering))) + return -EFAULT; + + if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) || +#if TG3_MINI_RING_WORKS + (ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) || +#endif + (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || + (ering.tx_pending > TG3_TX_RING_SIZE - 1)) + return -EINVAL; + + spin_lock_irq(&tp->lock); + + tp->rx_pending = ering.rx_pending; +#if TG3_MINI_RING_WORKS + tp->rx_mini_pending = ering.rx_mini_pending; +#endif + tp->rx_jumbo_pending = ering.rx_jumbo_pending; + tp->tx_pending = ering.tx_pending; + + tg3_halt(tp); + tg3_init_rings(tp); + tg3_init_hw(tp); + netif_wake_queue(tp->dev); + spin_unlock_irq(&tp->lock); + + return 0; + } + case ETHTOOL_GPAUSEPARAM: { + struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM }; + + epause.autoneg = + (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; + epause.rx_pause = + (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0; + epause.tx_pause = + (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0; + if (copy_to_user(useraddr, &epause, sizeof(epause))) + return -EFAULT; + return 0; + } + case ETHTOOL_SPAUSEPARAM: { + struct ethtool_pauseparam epause; + + if (copy_from_user(&epause, useraddr, sizeof(epause))) + return -EFAULT; + + spin_lock_irq(&tp->lock); + if (epause.autoneg) + tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + else + tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + if (epause.rx_pause) + tp->tg3_flags |= TG3_FLAG_PAUSE_RX; + else + tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX; + if (epause.tx_pause) + tp->tg3_flags |= TG3_FLAG_PAUSE_TX; + else + tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX; + tg3_halt(tp); + tg3_init_rings(tp); + tg3_init_hw(tp); + spin_unlock_irq(&tp->lock); + + return 0; + } + case ETHTOOL_GRXCSUM: { + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + edata.data = + (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRXCSUM: { + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { + if (edata.data != 0) + return -EINVAL; + return 0; + } + + spin_lock_irq(&tp->lock); + if (edata.data) + tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; + else + tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; + spin_unlock_irq(&tp->lock); + + return 0; + } + case ETHTOOL_GTXCSUM: { + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + edata.data = + (tp->dev->features & NETIF_F_IP_CSUM) != 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_STXCSUM: { + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { + if (edata.data != 0) + return -EINVAL; + return 0; + } + + if (edata.data) + tp->dev->features |= NETIF_F_IP_CSUM; + else + tp->dev->features &= ~NETIF_F_IP_CSUM; + + return 0; + } + case ETHTOOL_GSG: { + struct ethtool_value edata = { ETHTOOL_GSG }; + + edata.data = + (tp->dev->features & NETIF_F_SG) != 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSG: { + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (edata.data) + tp->dev->features |= NETIF_F_SG; + else + tp->dev->features &= ~NETIF_F_SG; + + return 0; + } + }; + + return -EOPNOTSUPP; +} + +static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct tg3 *tp = dev->priv; + int err; + + switch(cmd) { + case SIOCETHTOOL: + return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data); + case SIOCGMIIPHY: + data->phy_id = PHY_ADDR; + + /* fallthru */ + case SIOCGMIIREG: { + u32 mii_regval; + + spin_lock_irq(&tp->lock); + err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval); + spin_unlock_irq(&tp->lock); + + data->val_out = mii_regval; + + return err; + } + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irq(&tp->lock); + err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in); + spin_unlock_irq(&tp->lock); + + return err; + + default: + /* do nothing */ + break; + } + return -EOPNOTSUPP; +} + +#if TG3_VLAN_TAG_USED +static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct tg3 *tp = dev->priv; + + spin_lock_irq(&tp->lock); + tp->vlgrp = grp; + spin_unlock_irq(&tp->lock); +} + +static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct tg3 *tp = dev->priv; + + spin_lock_irq(&tp->lock); + if (tp->vlgrp) + tp->vlgrp->vlan_devices[vid] = NULL; + spin_unlock_irq(&tp->lock); +} +#endif + +/* Chips other than 5700/5701 use the NVRAM for fetching info. */ +static void __devinit tg3_nvram_init(struct tg3 *tp) +{ + int j; + + tw32(GRC_EEPROM_ADDR, + (EEPROM_ADDR_FSM_RESET | + (EEPROM_DEFAULT_CLOCK_PERIOD << + EEPROM_ADDR_CLKPERD_SHIFT))); + + /* XXX schedule_timeout() ... */ + for (j = 0; j < 100; j++) + udelay(10); + + /* Enable seeprom accesses. */ + tw32(GRC_LOCAL_CTRL, + tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM); + udelay(100); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { + u32 nvcfg1 = tr32(NVRAM_CFG1); + + tp->tg3_flags |= TG3_FLAG_NVRAM; + if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { + if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE) + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + } else { + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + } + + } else { + tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); + } +} + +static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp, + u32 offset, u32 *val) +{ + u32 tmp; + int i; + + if (offset > EEPROM_ADDR_ADDR_MASK || + (offset % 4) != 0) + return -EINVAL; + + tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK | + EEPROM_ADDR_DEVID_MASK | + EEPROM_ADDR_READ); + tw32(GRC_EEPROM_ADDR, + tmp | + (0 << EEPROM_ADDR_DEVID_SHIFT) | + ((offset << EEPROM_ADDR_ADDR_SHIFT) & + EEPROM_ADDR_ADDR_MASK) | + EEPROM_ADDR_READ | EEPROM_ADDR_START); + + for (i = 0; i < 10000; i++) { + tmp = tr32(GRC_EEPROM_ADDR); + + if (tmp & EEPROM_ADDR_COMPLETE) + break; + udelay(100); + } + if (!(tmp & EEPROM_ADDR_COMPLETE)) + return -EBUSY; + + *val = tr32(GRC_EEPROM_DATA); + return 0; +} + +static int __devinit tg3_nvram_read(struct tg3 *tp, + u32 offset, u32 *val) +{ + int i, saw_done_clear; + + if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) + return tg3_nvram_read_using_eeprom(tp, offset, val); + + if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) + offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) << + NVRAM_BUFFERED_PAGE_POS) + + (offset % NVRAM_BUFFERED_PAGE_SIZE); + + if (offset > NVRAM_ADDR_MSK) + return -EINVAL; + + tw32(NVRAM_SWARB, SWARB_REQ_SET1); + for (i = 0; i < 1000; i++) { + if (tr32(NVRAM_SWARB) & SWARB_GNT1) + break; + udelay(20); + } + + tw32(NVRAM_ADDR, offset); + tw32(NVRAM_CMD, + NVRAM_CMD_RD | NVRAM_CMD_GO | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE); + + /* Wait for done bit to clear then set again. */ + saw_done_clear = 0; + for (i = 0; i < 1000; i++) { + udelay(10); + if (!saw_done_clear && + !(tr32(NVRAM_CMD) & NVRAM_CMD_DONE)) + saw_done_clear = 1; + else if (saw_done_clear && + (tr32(NVRAM_CMD) & NVRAM_CMD_DONE)) + break; + } + if (i >= 1000) { + tw32(NVRAM_SWARB, SWARB_REQ_CLR1); + return -EBUSY; + } + + *val = swab32(tr32(NVRAM_RDDATA)); + tw32(NVRAM_SWARB, 0x20); + + return 0; +} + +struct subsys_tbl_ent { + u16 subsys_vendor, subsys_devid; + u32 phy_id; +}; + +static struct subsys_tbl_ent subsys_id_to_phy_id[] = { + /* Broadcom boards. */ + { 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */ + { 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */ + { 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */ + { 0x14e4, 0x0003, PHY_ID_SERDES }, /* BCM95700A9 */ + { 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */ + { 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */ + { 0x14e4, 0x0007, PHY_ID_SERDES }, /* BCM95701A7 */ + { 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */ + { 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */ + { 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */ + { 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */ + + /* 3com boards. */ + { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */ + { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */ + /* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX }, 3C996CT */ + /* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX }, 3C997T */ + { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES }, /* 3C996SX */ + /* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX }, 3C997SZ */ + { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */ + { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */ + + /* DELL boards. */ + { PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */ + { PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */ + { PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */ + { PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */ + + /* Compaq boards. */ + { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */ + { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */ + { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES }, /* CHANGELING */ + { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */ + { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 } /* NC7780_2 */ +}; + +static int __devinit tg3_phy_probe(struct tg3 *tp) +{ + u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2; + u32 hw_phy_id, hw_phy_id_masked; + enum phy_led_mode eeprom_led_mode; + u32 val; + int i, eeprom_signature_found, err; + + tp->phy_id = PHY_ID_INVALID; + for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) { + if ((subsys_id_to_phy_id[i].subsys_vendor == + tp->pdev->subsystem_vendor) && + (subsys_id_to_phy_id[i].subsys_devid == + tp->pdev->subsystem_device)) { + tp->phy_id = subsys_id_to_phy_id[i].phy_id; + break; + } + } + + eeprom_phy_id = PHY_ID_INVALID; + eeprom_led_mode = led_mode_auto; + eeprom_signature_found = 0; + tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); + if (val == NIC_SRAM_DATA_SIG_MAGIC) { + u32 nic_cfg; + + tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); + + eeprom_signature_found = 1; + + if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) == + NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) { + eeprom_phy_id = PHY_ID_SERDES; + } else { + u32 nic_phy_id; + + tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id); + if (nic_phy_id != 0) { + u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK; + u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK; + + eeprom_phy_id = (id1 >> 16) << 10; + eeprom_phy_id |= (id2 & 0xfc00) << 16; + eeprom_phy_id |= (id2 & 0x03ff) << 0; + } + } + + switch (nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK) { + case NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD: + eeprom_led_mode = led_mode_three_link; + break; + + case NIC_SRAM_DATA_CFG_LED_LINK_SPD: + eeprom_led_mode = led_mode_link10; + break; + + default: + eeprom_led_mode = led_mode_auto; + break; + }; + } + + err = tg3_phy_reset(tp, 0); + if (err) + return err; + + /* Now read the physical PHY_ID from the chip and verify + * that it is sane. If it doesn't look good, we fall back + * to either the hard-coded table based PHY_ID and failing + * that the value found in the eeprom area. + */ + err = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1); + err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2); + + hw_phy_id = (hw_phy_id_1 & 0xffff) << 10; + hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16; + hw_phy_id |= (hw_phy_id_2 & 0x03ff) << 0; + + hw_phy_id_masked = hw_phy_id & PHY_ID_MASK; + + if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) { + tp->phy_id = hw_phy_id; + } else { + /* phy_id currently holds the value found in the + * subsys_id_to_phy_id[] table or PHY_ID_INVALID + * if a match was not found there. + */ + if (tp->phy_id == PHY_ID_INVALID) { + if (!eeprom_signature_found || + !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK)) + return -ENODEV; + tp->phy_id = eeprom_phy_id; + } + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f); + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa); + } + + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + tp->tg3_flags |= TG3_FLAG_PHY_RESET_ON_INIT; + + if (tp->tg3_flags & TG3_FLAG_PHY_RESET_ON_INIT) { + u32 mii_tg3_ctrl; + + err = tg3_phy_reset(tp, 1); + if (err) + return err; + + /* These chips, when reset, only advertise 10Mb capabilities. + * Fix that. + */ + err = tg3_writephy(tp, MII_ADVERTISE, + (ADVERTISE_CSMA | + ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL)); + mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF | + MII_TG3_CTRL_ADV_1000_FULL | + MII_TG3_CTRL_AS_MASTER | + MII_TG3_CTRL_ENABLE_AS_MASTER); + if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) + mii_tg3_ctrl = 0; + + err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl); + err |= tg3_writephy(tp, MII_BMCR, + (BMCR_ANRESTART | BMCR_ANENABLE)); + } + + if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) { + err = tg3_init_5401phy_dsp(tp); + } + + /* Determine the PHY led mode. */ + if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) { + tp->led_mode = led_mode_link10; + } else { + tp->led_mode = led_mode_three_link; + if (eeprom_signature_found && + eeprom_led_mode != led_mode_auto) + tp->led_mode = eeprom_led_mode; + } + + if (tp->phy_id == PHY_ID_SERDES) + tp->link_config.advertising = + (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | + ADVERTISED_FIBRE); + if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) + tp->link_config.advertising &= + ~(ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + return err; +} + +static void __devinit tg3_read_partno(struct tg3 *tp) +{ + unsigned char vpd_data[256]; + int i; + + for (i = 0; i < 256; i += 4) { + u32 tmp; + + if (tg3_nvram_read(tp, 0x100 + i, &tmp)) + goto out_not_found; + + vpd_data[i + 0] = ((tmp >> 0) & 0xff); + vpd_data[i + 1] = ((tmp >> 8) & 0xff); + vpd_data[i + 2] = ((tmp >> 16) & 0xff); + vpd_data[i + 3] = ((tmp >> 24) & 0xff); + } + + /* Now parse and find the part number. */ + for (i = 0; i < 256; ) { + unsigned char val = vpd_data[i]; + int block_end; + + if (val == 0x82 || val == 0x91) { + i = (i + 3 + + (vpd_data[i + 1] + + (vpd_data[i + 2] << 8))); + continue; + } + + if (val != 0x90) + goto out_not_found; + + block_end = (i + 3 + + (vpd_data[i + 1] + + (vpd_data[i + 2] << 8))); + i += 3; + while (i < block_end) { + if (vpd_data[i + 0] == 'P' && + vpd_data[i + 1] == 'N') { + int partno_len = vpd_data[i + 2]; + + if (partno_len > 24) + goto out_not_found; + + memcpy(tp->board_part_number, + &vpd_data[i + 3], + partno_len); + + /* Success. */ + return; + } + } + + /* Part number not found. */ + goto out_not_found; + } + +out_not_found: + strcpy(tp->board_part_number, "none"); +} + +static int __devinit tg3_get_invariants(struct tg3 *tp) +{ + u32 misc_ctrl_reg; + u32 cacheline_sz_reg; + u32 pci_state_reg, grc_misc_cfg; + u16 pci_cmd; + int err; + + /* Force memory write invalidate off. If we leave it on, + * then on 5700_BX chips we have to enable a workaround. + * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry + * to match the cacheline size. The Broadcom driver have this + * workaround but turns MWI off all the times so never uses + * it. This seems to suggest that the workaround is insufficient. + */ + pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); + pci_cmd &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + + pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + &misc_ctrl_reg); + + tp->pci_chip_rev_id = (misc_ctrl_reg >> + MISC_HOST_CTRL_CHIPREV_SHIFT); + + pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ, + &cacheline_sz_reg); + + tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff; + tp->pci_lat_timer = (cacheline_sz_reg >> 16) & 0xff; + tp->pci_hdr_type = (cacheline_sz_reg >> 8) & 0xff; + tp->pci_bist = (cacheline_sz_reg >> 0) & 0xff; + + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, + &pci_state_reg); + + if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { + tp->tg3_flags |= TG3_FLAG_PCIX_MODE; + + /* If this is a 5700 BX chipset, and we are in PCI-X + * mode, enable register write workaround. + * + * The workaround is to use indirect register accesses + * for all chip writes not to mailbox registers. + */ + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { + u32 pm_reg; + u16 pci_cmd; + + tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + + /* The chip can have it's power management PCI config + * space registers clobbered due to this bug. + * So explicitly force the chip into D0 here. + */ + pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + &pm_reg); + pm_reg &= ~PCI_PM_CTRL_STATE_MASK; + pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */; + pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + pm_reg); + + /* Also, force SERR#/PERR# in PCI command. */ + pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); + pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + } + } + if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) + tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; + if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) + tp->tg3_flags |= TG3_FLAG_PCI_32BIT; + + /* Force the chip into D0. */ + err = tg3_set_power_state(tp, 0); + if (err) + return err; + + /* 5700 B0 chips do not support checksumming correctly due + * to hardware bugs. + */ + if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) + tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; + + /* Regardless of whether checksums work or not, we configure + * the StrongARM chips to not compute the pseudo header checksums + * in either direction. Because of the way Linux checksum support + * works we do not need the chips to do this, and taking the load + * off of the TX/RX onboard StrongARM cpus means that they will not be + * the bottleneck. Whoever wrote Broadcom's driver did not + * understand the situation at all. He could have bothered + * to read Jes's Acenic driver because the logic (and this part of + * the Tigon2 hardware/firmware) is pretty much identical. + */ + tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM; + tp->tg3_flags |= TG3_FLAG_NO_RX_PSEUDO_CSUM; + + /* Derive initial jumbo mode from MTU assigned in + * ether_setup() via the alloc_etherdev() call + */ + if (tp->dev->mtu > ETH_DATA_LEN) + tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE; + + /* Determine WakeOnLan speed to use. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) { + tp->tg3_flags &= ~(TG3_FLAG_WOL_SPEED_100MB); + } else { + tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; + } + + /* Only 5701 and later support tagged irq status mode. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) { + tp->tg3_flags |= TG3_FLAG_TAGGED_IRQ_STATUS; + tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS; + + /* ??? Due to a glitch Broadcom's driver ALWAYS sets + * ??? these bits in coalesce_mode. Because MM_GetConfig + * ??? always sets pDevice->UseTaggedStatus correctly + * ??? the following test at tigon3.c:LM_GetAdapterInfo() + * ??? + * ??? pDevice->UseTaggedStatus && + * ??? (pDevice->ChipRevId == T3_CHIP_ID_5700_C0 || + * ??? T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_AX || + * ??? T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + * ??? + * ??? will never pass and thus pDevice->CoalesceMode will never + * ??? get set to zero. For now I'll mirror what I believe is + * ??? the intention of their driver. + * ??? + * ??? Update: This is fixed in Broadcom's 2.2.3 and later + * ??? drivers. All the current 2.0.x drivers still + * ??? have the bug. + */ + tp->coalesce_mode = (HOSTCC_MODE_CLRTICK_RXBD | + HOSTCC_MODE_CLRTICK_TXBD); + } else { + tp->coalesce_mode = 0; + + /* If not using tagged status, set the *_during_int + * coalesce default config values to zero. + */ + tp->coalesce_config.rx_coalesce_ticks_during_int_def = 0; + tp->coalesce_config.rx_max_coalesced_frames_during_int_def = 0; + tp->coalesce_config.tx_coalesce_ticks_during_int_def = 0; + tp->coalesce_config.tx_max_coalesced_frames_during_int_def = 0; + } + + if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) + tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + + /* Initialize misc host control in PCI block. */ + tp->misc_host_ctrl |= (misc_ctrl_reg & + MISC_HOST_CTRL_CHIPREV); + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + + /* Initialize MAC MI mode, polling disabled. */ + tw32(MAC_MI_MODE, tp->mi_mode); + udelay(40); + + /* Initialize data/descriptor byte/word swapping. */ + tw32(GRC_MODE, tp->grc_mode); + + /* Clear these out for sanity. */ + tw32(TG3PCI_CLOCK_CTRL, 0); + tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); + + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, + &pci_state_reg); + if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 && + (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) == 0) { + u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl); + + if (chiprevid == CHIPREV_ID_5701_A0 || + chiprevid == CHIPREV_ID_5701_B0 || + chiprevid == CHIPREV_ID_5701_B2 || + chiprevid == CHIPREV_ID_5701_B5) { + unsigned long sram_base; + + /* Write some dummy words into the SRAM status block + * area, see if it reads back correctly. If the return + * value is bad, force enable the PCIX workaround. + */ + sram_base = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_STATS_BLK; + + writel(0x00000000, sram_base); + writel(0x00000000, sram_base + 4); + writel(0xffffffff, sram_base + 4); + if (readl(sram_base) != 0x00000000) + tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + } + } + + udelay(50); + tg3_nvram_init(tp); + + /* Determine if TX descriptors will reside in + * main memory or in the chip SRAM. + */ + if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) + tp->tg3_flags |= TG3_FLAG_HOST_TXDS; + + /* Quick sanity check. Make sure we see an expected + * value here. + */ + grc_misc_cfg = tr32(GRC_MISC_CFG); + grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; + if (grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5700 && + grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5701 && + grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE && + grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 && + grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S) + return -ENODEV; + + /* ROFL, you should see Broadcom's driver code implementing + * this, stuff like "if (a || b)" where a and b are always + * mutually exclusive. DaveM finds like 6 bugs today, hello! + */ + if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE) + tp->tg3_flags |= TG3_FLAG_10_100_ONLY; + + err = tg3_phy_probe(tp); + + tg3_read_partno(tp); + + if (tp->phy_id == PHY_ID_SERDES) { + tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; + + /* And override led_mode in case Dell ever makes + * a fibre board. + */ + tp->led_mode = led_mode_three_link; + } else { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) + tp->tg3_flags |= TG3_FLAG_USE_MI_INTERRUPT; + else + tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; + } + + /* 5700 {AX,BX} chips have a broken status block link + * change bit implementation, so we must use the + * status register in those cases. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) + tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG; + else + tp->tg3_flags &= ~TG3_FLAG_USE_LINKCHG_REG; + + /* The led_mode is set during tg3_phy_probe, here we might + * have to force the link status polling mechanism based + * upon subsystem IDs. + */ + if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && + tp->phy_id != PHY_ID_SERDES) { + tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT | + TG3_FLAG_USE_LINKCHG_REG); + } + + /* 5700 BX chips need to have their TX producer index mailboxes + * written twice to workaround a bug. + */ + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) + tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; + else + tp->tg3_flags &= ~TG3_FLAG_TXD_MBOX_HWBUG; + + /* 5700 chips can get confused if TX buffers straddle the + * 4GB address boundary in some cases. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { + /* ROFL! Latest Broadcom driver disables NETIF_F_HIGHDMA + * in this case instead of fixing their workaround code. + * + * Like, hey, there is this skb_copy() thing guys, + * use it. Oh I can't stop laughing... + */ + tp->dev->hard_start_xmit = tg3_start_xmit_4gbug; + } else { + tp->dev->hard_start_xmit = tg3_start_xmit; + } + + tp->rx_offset = 2; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && + (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) + tp->rx_offset = 0; + + return err; +} + +static int __devinit tg3_get_device_address(struct tg3 *tp) +{ + struct net_device *dev = tp->dev; + u32 hi, lo; + + /* First try to get it from MAC address mailbox. */ + tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi); + if ((hi >> 16) == 0x484b) { + dev->dev_addr[0] = (hi >> 8) & 0xff; + dev->dev_addr[1] = (hi >> 0) & 0xff; + + tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo); + dev->dev_addr[2] = (lo >> 24) & 0xff; + dev->dev_addr[3] = (lo >> 16) & 0xff; + dev->dev_addr[4] = (lo >> 8) & 0xff; + dev->dev_addr[5] = (lo >> 0) & 0xff; + } + /* Next, try NVRAM. */ + else if (!tg3_nvram_read(tp, 0x7c, &hi) && + !tg3_nvram_read(tp, 0x80, &lo)) { + dev->dev_addr[0] = ((hi >> 16) & 0xff); + dev->dev_addr[1] = ((hi >> 24) & 0xff); + dev->dev_addr[2] = ((lo >> 0) & 0xff); + dev->dev_addr[3] = ((lo >> 8) & 0xff); + dev->dev_addr[4] = ((lo >> 16) & 0xff); + dev->dev_addr[5] = ((lo >> 24) & 0xff); + } + /* Finally just fetch it out of the MAC control regs. */ + else { + hi = tr32(MAC_ADDR_0_HIGH); + lo = tr32(MAC_ADDR_0_LOW); + + dev->dev_addr[5] = lo & 0xff; + dev->dev_addr[4] = (lo >> 8) & 0xff; + dev->dev_addr[3] = (lo >> 16) & 0xff; + dev->dev_addr[2] = (lo >> 24) & 0xff; + dev->dev_addr[1] = hi & 0xff; + dev->dev_addr[0] = (hi >> 8) & 0xff; + } + + if (!is_valid_ether_addr(&dev->dev_addr[0])) + return -EINVAL; + + return 0; +} + +static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma, int size, int to_device) +{ + struct tg3_internal_buffer_desc test_desc; + u32 sram_dma_descs; + int i, ret; + + sram_dma_descs = NIC_SRAM_DMA_DESC_POOL_BASE; + + tw32(FTQ_RCVBD_COMP_FIFO_ENQDEQ, 0); + tw32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ, 0); + tw32(RDMAC_STATUS, 0); + tw32(WDMAC_STATUS, 0); + + tw32(BUFMGR_MODE, 0); + tw32(FTQ_RESET, 0); + + /* pci_alloc_consistent gives only non-DAC addresses */ + test_desc.addr_hi = 0; + test_desc.addr_lo = buf_dma & 0xffffffff; + test_desc.nic_mbuf = 0x00002100; + test_desc.len = size; + if (to_device) { + test_desc.cqid_sqid = (13 << 8) | 2; + tw32(RDMAC_MODE, RDMAC_MODE_RESET); + tw32(RDMAC_MODE, RDMAC_MODE_ENABLE); + } else { + test_desc.cqid_sqid = (16 << 8) | 7; + tw32(WDMAC_MODE, WDMAC_MODE_RESET); + tw32(WDMAC_MODE, WDMAC_MODE_ENABLE); + } + test_desc.flags = 0x00000004; + + for (i = 0; i < (sizeof(test_desc) / sizeof(u32)); i++) { + u32 val; + + val = *(((u32 *)&test_desc) + i); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, + sram_dma_descs + (i * sizeof(u32))); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + } + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + + if (to_device) { + tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs); + } else { + tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs); + } + + ret = -ENODEV; + for (i = 0; i < 40; i++) { + u32 val; + + if (to_device) + val = tr32(FTQ_RCVBD_COMP_FIFO_ENQDEQ); + else + val = tr32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ); + if ((val & 0xffff) == sram_dma_descs) { + ret = 0; + break; + } + + udelay(100); + } + + return ret; +} + +#define TEST_BUFFER_SIZE 0x400 + +static int __devinit tg3_test_dma(struct tg3 *tp) +{ + dma_addr_t buf_dma; + u32 *buf; + int ret; + + buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma); + if (!buf) { + ret = -ENOMEM; + goto out_nofree; + } + + tw32(TG3PCI_CLOCK_CTRL, 0); + + if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) { + tp->dma_rwctrl = + (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | + (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | + (0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) | + (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); + } else { + tp->dma_rwctrl = + (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | + (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | + (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) | + (0x3 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); + + /* Wheee, some more chip bugs... */ + if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 || + tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) + tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; + } + + /* We don't do this on x86 because it seems to hurt performace. + * It does help things on other platforms though. + */ +#ifndef CONFIG_X86 + { + u8 byte; + int cacheline_size; + pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte); + + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + tp->dma_rwctrl &= ~(DMA_RWCTRL_READ_BNDRY_MASK | + DMA_RWCTRL_WRITE_BNDRY_MASK); + + switch (cacheline_size) { + case 16: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_16 | + DMA_RWCTRL_WRITE_BNDRY_16); + break; + + case 32: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_32 | + DMA_RWCTRL_WRITE_BNDRY_32); + break; + + case 64: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_64 | + DMA_RWCTRL_WRITE_BNDRY_64); + break; + + case 128: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_128 | + DMA_RWCTRL_WRITE_BNDRY_128); + break; + + case 256: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_256 | + DMA_RWCTRL_WRITE_BNDRY_256); + break; + + case 512: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_512 | + DMA_RWCTRL_WRITE_BNDRY_512); + break; + + case 1024: + tp->dma_rwctrl |= + (DMA_RWCTRL_READ_BNDRY_1024 | + DMA_RWCTRL_WRITE_BNDRY_1024); + break; + }; + } +#endif + + /* Remove this if it causes problems for some boards. */ + tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT; + + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + + ret = 0; + while (1) { + u32 *p, i; + + p = buf; + for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) + p[i] = i; + + /* Send the buffer to the chip. */ + ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1); + if (ret) + break; + + p = buf; + for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) + p[i] = 0; + + /* Now read it back. */ + ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0); + if (ret) + break; + + /* Verify it. */ + p = buf; + for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) { + if (p[i] == i) + continue; + + if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) == + DMA_RWCTRL_WRITE_BNDRY_DISAB) { + tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16; + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + break; + } else { + ret = -ENODEV; + goto out; + } + } + + if (i == (TEST_BUFFER_SIZE / sizeof(u32))) { + /* Success. */ + ret = 0; + break; + } + } + +out: + pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma); +out_nofree: + return ret; +} + +static void __devinit tg3_init_link_config(struct tg3 *tp) +{ + tp->link_config.advertising = + (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_MII); + tp->link_config.speed = SPEED_INVALID; + tp->link_config.duplex = DUPLEX_INVALID; + tp->link_config.autoneg = AUTONEG_ENABLE; + netif_carrier_off(tp->dev); + tp->link_config.active_speed = SPEED_INVALID; + tp->link_config.active_duplex = DUPLEX_INVALID; + tp->link_config.phy_is_low_power = 0; + tp->link_config.orig_speed = SPEED_INVALID; + tp->link_config.orig_duplex = DUPLEX_INVALID; + tp->link_config.orig_autoneg = AUTONEG_INVALID; +} + +static void __devinit tg3_init_coalesce_config(struct tg3 *tp) +{ + tp->coalesce_config.rx_coalesce_ticks_def = DEFAULT_RXCOL_TICKS; + tp->coalesce_config.rx_max_coalesced_frames_def = DEFAULT_RXMAX_FRAMES; + tp->coalesce_config.rx_coalesce_ticks_during_int_def = + DEFAULT_RXCOAL_TICK_INT; + tp->coalesce_config.rx_max_coalesced_frames_during_int_def = + DEFAULT_RXCOAL_MAXF_INT; + tp->coalesce_config.tx_coalesce_ticks_def = DEFAULT_TXCOL_TICKS; + tp->coalesce_config.tx_max_coalesced_frames_def = DEFAULT_TXMAX_FRAMES; + tp->coalesce_config.tx_coalesce_ticks_during_int_def = + DEFAULT_TXCOAL_TICK_INT; + tp->coalesce_config.tx_max_coalesced_frames_during_int_def = + DEFAULT_TXCOAL_MAXF_INT; + tp->coalesce_config.stats_coalesce_ticks_def = + DEFAULT_STAT_COAL_TICKS; + + tp->coalesce_config.rx_coalesce_ticks_low = + LOW_RXCOL_TICKS; + tp->coalesce_config.rx_max_coalesced_frames_low = + LOW_RXMAX_FRAMES; + tp->coalesce_config.tx_coalesce_ticks_low = + LOW_TXCOL_TICKS; + tp->coalesce_config.tx_max_coalesced_frames_low = + LOW_TXMAX_FRAMES; + + tp->coalesce_config.rx_coalesce_ticks_high = + HIGH_RXCOL_TICKS; + tp->coalesce_config.rx_max_coalesced_frames_high = + HIGH_RXMAX_FRAMES; + tp->coalesce_config.tx_coalesce_ticks_high = + HIGH_TXCOL_TICKS; + tp->coalesce_config.tx_max_coalesced_frames_high = + HIGH_TXMAX_FRAMES; + + /* Active == default */ + tp->coalesce_config.rx_coalesce_ticks = + tp->coalesce_config.rx_coalesce_ticks_def; + tp->coalesce_config.rx_max_coalesced_frames = + tp->coalesce_config.rx_max_coalesced_frames_def; + tp->coalesce_config.tx_coalesce_ticks = + tp->coalesce_config.tx_coalesce_ticks_def; + tp->coalesce_config.tx_max_coalesced_frames = + tp->coalesce_config.tx_max_coalesced_frames_def; + tp->coalesce_config.stats_coalesce_ticks = + tp->coalesce_config.stats_coalesce_ticks_def; + + tp->coalesce_config.rate_sample_jiffies = (1 * HZ); + tp->coalesce_config.pkt_rate_low = 22000; + tp->coalesce_config.pkt_rate_high = 61000; + + tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX; + tp->tg3_flags &= ~(TG3_FLAG_ADAPTIVE_TX); +} + +static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) +{ + tp->bufmgr_config.mbuf_read_dma_low_water = + DEFAULT_MB_RDMA_LOW_WATER; + tp->bufmgr_config.mbuf_mac_rx_low_water = + DEFAULT_MB_MACRX_LOW_WATER; + tp->bufmgr_config.mbuf_high_water = + DEFAULT_MB_HIGH_WATER; + + tp->bufmgr_config.mbuf_read_dma_low_water_jumbo = + DEFAULT_MB_RDMA_LOW_WATER_JUMBO; + tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo = + DEFAULT_MB_MACRX_LOW_WATER_JUMBO; + tp->bufmgr_config.mbuf_high_water_jumbo = + DEFAULT_MB_HIGH_WATER_JUMBO; + + tp->bufmgr_config.dma_low_water = DEFAULT_DMA_LOW_WATER; + tp->bufmgr_config.dma_high_water = DEFAULT_DMA_HIGH_WATER; +} + +static char * __devinit tg3_phy_string(struct tg3 *tp) +{ + switch (tp->phy_id & PHY_ID_MASK) { + case PHY_ID_BCM5400: return "5400"; + case PHY_ID_BCM5401: return "5401"; + case PHY_ID_BCM5411: return "5411"; + case PHY_ID_BCM5701: return "5701"; + case PHY_ID_BCM5703: return "5703"; + case PHY_ID_BCM8002: return "8002"; + case PHY_ID_SERDES: return "serdes"; + default: return "unknown"; + }; +} + +static int __devinit tg3_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int tg3_version_printed = 0; + unsigned long tg3reg_base, tg3reg_len; + struct net_device *dev; + struct tg3 *tp; + int i, err, pci_using_dac, pm_cap; + + if (tg3_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device, " + "aborting.\n"); + return err; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find proper PCI device " + "base address, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + err = pci_request_regions(pdev, DRV_MODULE_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources, " + "aborting.\n"); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + /* Find power-management capability. */ + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap == 0) { + printk(KERN_ERR PFX "Cannot find PowerManagement capability, " + "aborting.\n"); + goto err_out_free_res; + } + + /* Configure DMA attributes. */ + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, (u64) 0xffffffff); + if (err) { + printk(KERN_ERR PFX "No usable DMA configuration, " + "aborting.\n"); + goto err_out_free_res; + } + pci_using_dac = 0; + } + + tg3reg_base = pci_resource_start(pdev, 0); + tg3reg_len = pci_resource_len(pdev, 0); + + dev = alloc_etherdev(sizeof(*tp)); + if (!dev) { + printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + SET_MODULE_OWNER(dev); + + if (pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; +#if TG3_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = tg3_vlan_rx_register; + dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid; +#endif + + tp = dev->priv; + tp->pdev = pdev; + tp->dev = dev; + tp->pm_cap = pm_cap; + tp->mac_mode = TG3_DEF_MAC_MODE; + tp->rx_mode = TG3_DEF_RX_MODE; + tp->tx_mode = TG3_DEF_TX_MODE; + tp->mi_mode = MAC_MI_MODE_BASE; + if (tg3_debug > 0) + tp->msg_enable = tg3_debug; + else + tp->msg_enable = TG3_DEF_MSG_ENABLE; + + /* The word/byte swap controls here control register access byte + * swapping. DMA data byte swapping is controlled in the GRC_MODE + * setting below. + */ + tp->misc_host_ctrl = + MISC_HOST_CTRL_MASK_PCI_INT | + MISC_HOST_CTRL_WORD_SWAP | + MISC_HOST_CTRL_INDIR_ACCESS | + MISC_HOST_CTRL_PCISTATE_RW; + + /* The NONFRM (non-frame) byte/word swap controls take effect + * on descriptor entries, anything which isn't packet data. + * + * The StrongARM chips on the board (one for tx, one for rx) + * are running in big-endian mode. + */ + tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA | + GRC_MODE_WSWAP_NONFRM_DATA); +#ifdef __BIG_ENDIAN + tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA; +#endif + spin_lock_init(&tp->lock); + spin_lock_init(&tp->indirect_lock); + + tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); + if (tp->regs == 0UL) { + printk(KERN_ERR PFX "Cannot map device registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_free_dev; + } + + tg3_init_link_config(tp); + + tg3_init_coalesce_config(tp); + + tg3_init_bufmgr_config(tp); + + tp->rx_pending = TG3_DEF_RX_RING_PENDING; +#if TG3_MINI_RING_WORKS + tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING; +#endif + tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; + tp->tx_pending = TG3_DEF_TX_RING_PENDING; + + dev->open = tg3_open; + dev->stop = tg3_close; + dev->get_stats = tg3_get_stats; + dev->set_multicast_list = tg3_set_rx_mode; + dev->set_mac_address = tg3_set_mac_addr; + dev->do_ioctl = tg3_ioctl; + dev->tx_timeout = tg3_tx_timeout; + dev->watchdog_timeo = TG3_TX_TIMEOUT; + dev->change_mtu = tg3_change_mtu; + dev->irq = pdev->irq; + + err = tg3_get_invariants(tp); + if (err) { + printk(KERN_ERR PFX "Problem fetching invariants of chip, " + "aborting.\n"); + goto err_out_iounmap; + } + + err = tg3_get_device_address(tp); + if (err) { + printk(KERN_ERR PFX "Could not obtain valid ethernet address, " + "aborting.\n"); + goto err_out_iounmap; + } + + err = tg3_test_dma(tp); + if (err) { + printk(KERN_ERR PFX "DMA engine test failed, aborting.\n"); + goto err_out_iounmap; + } + + /* Tigon3 can do ipv4 only... and some chips have buggy + * checksumming. + */ + if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; + } else + tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + pci_set_drvdata(pdev, dev); + + /* Now that we have fully setup the chip, save away a snapshot + * of the PCI config space. We need to restore this after + * GRC_MISC_CFG core clock resets and some resume events. + */ + pci_save_state(tp->pdev, tp->pci_cfg_state); + + printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ", + dev->name, + tp->board_part_number, + tp->pci_chip_rev_id, + tg3_phy_string(tp), + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""), + ((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ? + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") : + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")), + ((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"), + (tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100" : "10/100/1000"); + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? '\n' : ':'); + + return 0; + +err_out_iounmap: + iounmap((void *) tp->regs); + +err_out_free_dev: + kfree(dev); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit tg3_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + unregister_netdev(dev); + iounmap((void *) ((struct tg3 *)(dev->priv))->regs); + kfree(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static int tg3_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct tg3 *tp = dev->priv; + int err; + + if (!netif_running(dev)) + return 0; + + spin_lock_irq(&tp->lock); + tg3_disable_ints(tp); + spin_unlock_irq(&tp->lock); + + netif_device_detach(dev); + + spin_lock_irq(&tp->lock); + tg3_halt(tp); + spin_unlock_irq(&tp->lock); + + err = tg3_set_power_state(tp, state); + if (err) { + spin_lock_irq(&tp->lock); + + tg3_init_rings(tp); + tg3_init_hw(tp); + + spin_unlock_irq(&tp->lock); + + netif_device_attach(dev); + } + + return err; +} + +static int tg3_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct tg3 *tp = dev->priv; + int err; + + if (!netif_running(dev)) + return 0; + + err = tg3_set_power_state(tp, 0); + if (err) + return err; + + netif_device_attach(dev); + + spin_lock_irq(&tp->lock); + + tg3_init_rings(tp); + tg3_init_hw(tp); + tg3_enable_ints(tp); + + spin_unlock_irq(&tp->lock); + + return 0; +} + +static struct pci_driver tg3_driver = { + name: DRV_MODULE_NAME, + id_table: tg3_pci_tbl, + probe: tg3_init_one, + remove: __devexit_p(tg3_remove_one), + suspend: tg3_suspend, + resume: tg3_resume +}; + +static int __init tg3_init(void) +{ + return pci_module_init(&tg3_driver); +} + +static void __exit tg3_cleanup(void) +{ + pci_unregister_driver(&tg3_driver); +} + +module_init(tg3_init); +module_exit(tg3_cleanup); diff -urN linux-2.4.18/drivers/net/tg3.h linux-2.4.19-pre5/drivers/net/tg3.h --- linux-2.4.18/drivers/net/tg3.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tg3.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,1894 @@ +/* $Id: tg3.h,v 1.37.2.32 2002/03/11 12:18:18 davem Exp $ + * tg3.h: Definitions for Broadcom Tigon3 ethernet driver. + * + * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) + * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com) + */ + +#ifndef _T3_H +#define _T3_H + +#define TG3_64BIT_REG_HIGH 0x00UL +#define TG3_64BIT_REG_LOW 0x04UL + +/* Descriptor block info. */ +#define TG3_BDINFO_HOST_ADDR 0x0UL /* 64-bit */ +#define TG3_BDINFO_MAXLEN_FLAGS 0x8UL /* 32-bit */ +#define BDINFO_FLAGS_USE_EXT_RECV 0x00000001 /* ext rx_buffer_desc */ +#define BDINFO_FLAGS_DISABLED 0x00000002 +#define BDINFO_FLAGS_MAXLEN_MASK 0xffff0000 +#define BDINFO_FLAGS_MAXLEN_SHIFT 16 +#define TG3_BDINFO_NIC_ADDR 0xcUL /* 32-bit */ +#define TG3_BDINFO_SIZE 0x10UL + +#define RX_COPY_THRESHOLD 256 + +#define RX_STD_MAX_SIZE 1536 +#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ +#if TG3_MINI_RING_WORKS +#define RX_MINI_MAX_SIZE 256 +#endif + +/* First 256 bytes are a mirror of PCI config space. */ +#define TG3PCI_VENDOR 0x00000000 +#define TG3PCI_VENDOR_BROADCOM 0x14e4 +#define TG3PCI_DEVICE 0x00000002 +#define TG3PCI_DEVICE_TIGON3_1 0x1644 /* BCM5700 */ +#define TG3PCI_DEVICE_TIGON3_2 0x1645 /* BCM5701 */ +#define TG3PCI_DEVICE_TIGON3_3 0x1646 /* BCM5702 */ +#define TG3PCI_DEVICE_TIGON3_4 0x1647 /* BCM5703 */ +#define TG3PCI_COMMAND 0x00000004 +#define TG3PCI_STATUS 0x00000006 +#define TG3PCI_CCREVID 0x00000008 +#define TG3PCI_CACHELINESZ 0x0000000c +#define TG3PCI_LATTIMER 0x0000000d +#define TG3PCI_HEADERTYPE 0x0000000e +#define TG3PCI_BIST 0x0000000f +#define TG3PCI_BASE0_LOW 0x00000010 +#define TG3PCI_BASE0_HIGH 0x00000014 +/* 0x18 --> 0x2c unused */ +#define TG3PCI_SUBSYSVENID 0x0000002c +#define TG3PCI_SUBSYSID 0x0000002e +#define TG3PCI_ROMADDR 0x00000030 +#define TG3PCI_CAPLIST 0x00000034 +/* 0x35 --> 0x3c unused */ +#define TG3PCI_IRQ_LINE 0x0000003c +#define TG3PCI_IRQ_PIN 0x0000003d +#define TG3PCI_MIN_GNT 0x0000003e +#define TG3PCI_MAX_LAT 0x0000003f +#define TG3PCI_X_CAPS 0x00000040 +#define PCIX_CAPS_RELAXED_ORDERING 0x00020000 +#define TG3PCI_PM_CAP_PTR 0x00000041 +#define TG3PCI_X_COMMAND 0x00000042 +#define TG3PCI_X_STATUS 0x00000044 +#define TG3PCI_PM_CAP_ID 0x00000048 +#define TG3PCI_VPD_CAP_PTR 0x00000049 +#define TG3PCI_PM_CAPS 0x0000004a +#define TG3PCI_PM_CTRL_STAT 0x0000004c +#define TG3PCI_BR_SUPP_EXT 0x0000004e +#define TG3PCI_PM_DATA 0x0000004f +#define TG3PCI_VPD_CAP_ID 0x00000050 +#define TG3PCI_MSI_CAP_PTR 0x00000051 +#define TG3PCI_VPD_ADDR_FLAG 0x00000052 +#define VPD_ADDR_FLAG_WRITE 0x00008000 +#define TG3PCI_VPD_DATA 0x00000054 +#define TG3PCI_MSI_CAP_ID 0x00000058 +#define TG3PCI_NXT_CAP_PTR 0x00000059 +#define TG3PCI_MSI_CTRL 0x0000005a +#define TG3PCI_MSI_ADDR_LOW 0x0000005c +#define TG3PCI_MSI_ADDR_HIGH 0x00000060 +#define TG3PCI_MSI_DATA 0x00000064 +/* 0x66 --> 0x68 unused */ +#define TG3PCI_MISC_HOST_CTRL 0x00000068 +#define MISC_HOST_CTRL_CLEAR_INT 0x00000001 +#define MISC_HOST_CTRL_MASK_PCI_INT 0x00000002 +#define MISC_HOST_CTRL_BYTE_SWAP 0x00000004 +#define MISC_HOST_CTRL_WORD_SWAP 0x00000008 +#define MISC_HOST_CTRL_PCISTATE_RW 0x00000010 +#define MISC_HOST_CTRL_CLKREG_RW 0x00000020 +#define MISC_HOST_CTRL_REGWORD_SWAP 0x00000040 +#define MISC_HOST_CTRL_INDIR_ACCESS 0x00000080 +#define MISC_HOST_CTRL_IRQ_MASK_MODE 0x00000100 +#define MISC_HOST_CTRL_TAGGED_STATUS 0x00000200 +#define MISC_HOST_CTRL_CHIPREV 0xffff0000 +#define MISC_HOST_CTRL_CHIPREV_SHIFT 16 +#define GET_CHIP_REV_ID(MISC_HOST_CTRL) \ + (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \ + MISC_HOST_CTRL_CHIPREV_SHIFT) +#define CHIPREV_ID_5700_A0 0x7000 +#define CHIPREV_ID_5700_A1 0x7001 +#define CHIPREV_ID_5700_B0 0x7100 +#define CHIPREV_ID_5700_B1 0x7101 +#define CHIPREV_ID_5700_C0 0x7200 +#define CHIPREV_ID_5701_A0 0x0000 +#define CHIPREV_ID_5701_B0 0x0100 +#define CHIPREV_ID_5701_B2 0x0102 +#define CHIPREV_ID_5701_B5 0x0105 +#define CHIPREV_ID_5703_A0 0x1000 +#define CHIPREV_ID_5703_A1 0x1001 +#define CHIPREV_ID_5703_A2 0x1002 +#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) +#define ASIC_REV_5700 0x07 +#define ASIC_REV_5701 0x00 +#define ASIC_REV_5703 0x01 +#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) +#define CHIPREV_5700_AX 0x70 +#define CHIPREV_5700_BX 0x71 +#define CHIPREV_5700_CX 0x72 +#define CHIPREV_5701_AX 0x00 +#define GET_METAL_REV(CHIP_REV_ID) ((CHIP_REV_ID) & 0xff) +#define METAL_REV_A0 0x00 +#define METAL_REV_A1 0x01 +#define METAL_REV_B0 0x00 +#define METAL_REV_B1 0x01 +#define METAL_REV_B2 0x02 +#define TG3PCI_DMA_RW_CTRL 0x0000006c +#define DMA_RWCTRL_MIN_DMA 0x000000ff +#define DMA_RWCTRL_MIN_DMA_SHIFT 0 +#define DMA_RWCTRL_READ_BNDRY_MASK 0x00000700 +#define DMA_RWCTRL_READ_BNDRY_DISAB 0x00000000 +#define DMA_RWCTRL_READ_BNDRY_16 0x00000100 +#define DMA_RWCTRL_READ_BNDRY_32 0x00000200 +#define DMA_RWCTRL_READ_BNDRY_64 0x00000300 +#define DMA_RWCTRL_READ_BNDRY_128 0x00000400 +#define DMA_RWCTRL_READ_BNDRY_256 0x00000500 +#define DMA_RWCTRL_READ_BNDRY_512 0x00000600 +#define DMA_RWCTRL_READ_BNDRY_1024 0x00000700 +#define DMA_RWCTRL_WRITE_BNDRY_MASK 0x00003800 +#define DMA_RWCTRL_WRITE_BNDRY_DISAB 0x00000000 +#define DMA_RWCTRL_WRITE_BNDRY_16 0x00000800 +#define DMA_RWCTRL_WRITE_BNDRY_32 0x00001000 +#define DMA_RWCTRL_WRITE_BNDRY_64 0x00001800 +#define DMA_RWCTRL_WRITE_BNDRY_128 0x00002000 +#define DMA_RWCTRL_WRITE_BNDRY_256 0x00002800 +#define DMA_RWCTRL_WRITE_BNDRY_512 0x00003000 +#define DMA_RWCTRL_WRITE_BNDRY_1024 0x00003800 +#define DMA_RWCTRL_ONE_DMA 0x00004000 +#define DMA_RWCTRL_READ_WATER 0x00070000 +#define DMA_RWCTRL_READ_WATER_SHIFT 16 +#define DMA_RWCTRL_WRITE_WATER 0x00380000 +#define DMA_RWCTRL_WRITE_WATER_SHIFT 19 +#define DMA_RWCTRL_USE_MEM_READ_MULT 0x00400000 +#define DMA_RWCTRL_ASSERT_ALL_BE 0x00800000 +#define DMA_RWCTRL_PCI_READ_CMD 0x0f000000 +#define DMA_RWCTRL_PCI_READ_CMD_SHIFT 24 +#define DMA_RWCTRL_PCI_WRITE_CMD 0xf0000000 +#define DMA_RWCTRL_PCI_WRITE_CMD_SHIFT 28 +#define TG3PCI_PCISTATE 0x00000070 +#define PCISTATE_FORCE_RESET 0x00000001 +#define PCISTATE_INT_NOT_ACTIVE 0x00000002 +#define PCISTATE_CONV_PCI_MODE 0x00000004 +#define PCISTATE_BUS_SPEED_HIGH 0x00000008 +#define PCISTATE_BUS_32BIT 0x00000010 +#define PCISTATE_ROM_ENABLE 0x00000020 +#define PCISTATE_ROM_RETRY_ENABLE 0x00000040 +#define PCISTATE_FLAT_VIEW 0x00000100 +#define TG3PCI_CLOCK_CTRL 0x00000074 +#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200 +#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400 +#define CLOCK_CTRL_TXCLK_DISABLE 0x00000800 +#define CLOCK_CTRL_ALTCLK 0x00001000 +#define CLOCK_CTRL_PWRDOWN_PLL133 0x00008000 +#define CLOCK_CTRL_44MHZ_CORE 0x00040000 +#define CLOCK_CTRL_DELAY_PCI_GRANT 0x80000000 +#define TG3PCI_REG_BASE_ADDR 0x00000078 +#define TG3PCI_MEM_WIN_BASE_ADDR 0x0000007c +#define TG3PCI_REG_DATA 0x00000080 +#define TG3PCI_MEM_WIN_DATA 0x00000084 +#define TG3PCI_MODE_CTRL 0x00000088 +#define TG3PCI_MISC_CFG 0x0000008c +#define TG3PCI_MISC_LOCAL_CTRL 0x00000090 +/* 0x94 --> 0x98 unused */ +#define TG3PCI_STD_RING_PROD_IDX 0x00000098 /* 64-bit */ +#define TG3PCI_RCV_RET_RING_CON_IDX 0x000000a0 /* 64-bit */ +#define TG3PCI_SND_PROD_IDX 0x000000a8 /* 64-bit */ +/* 0xb0 --> 0x100 unused */ + +/* 0x100 --> 0x200 unused */ + +/* Mailbox registers */ +#define MAILBOX_INTERRUPT_0 0x00000200 /* 64-bit */ +#define MAILBOX_INTERRUPT_1 0x00000208 /* 64-bit */ +#define MAILBOX_INTERRUPT_2 0x00000210 /* 64-bit */ +#define MAILBOX_INTERRUPT_3 0x00000218 /* 64-bit */ +#define MAILBOX_GENERAL_0 0x00000220 /* 64-bit */ +#define MAILBOX_GENERAL_1 0x00000228 /* 64-bit */ +#define MAILBOX_GENERAL_2 0x00000230 /* 64-bit */ +#define MAILBOX_GENERAL_3 0x00000238 /* 64-bit */ +#define MAILBOX_GENERAL_4 0x00000240 /* 64-bit */ +#define MAILBOX_GENERAL_5 0x00000248 /* 64-bit */ +#define MAILBOX_GENERAL_6 0x00000250 /* 64-bit */ +#define MAILBOX_GENERAL_7 0x00000258 /* 64-bit */ +#define MAILBOX_RELOAD_STAT 0x00000260 /* 64-bit */ +#define MAILBOX_RCV_STD_PROD_IDX 0x00000268 /* 64-bit */ +#define MAILBOX_RCV_JUMBO_PROD_IDX 0x00000270 /* 64-bit */ +#define MAILBOX_RCV_MINI_PROD_IDX 0x00000278 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_0 0x00000280 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_1 0x00000288 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_2 0x00000290 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_3 0x00000298 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_4 0x000002a0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_5 0x000002a8 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_6 0x000002b0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_7 0x000002b8 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_8 0x000002c0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_9 0x000002c8 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_10 0x000002d0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_11 0x000002d8 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_12 0x000002e0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_13 0x000002e8 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_14 0x000002f0 /* 64-bit */ +#define MAILBOX_RCVRET_CON_IDX_15 0x000002f8 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_0 0x00000300 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_1 0x00000308 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_2 0x00000310 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_3 0x00000318 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_4 0x00000320 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_5 0x00000328 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_6 0x00000330 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_7 0x00000338 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_8 0x00000340 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_9 0x00000348 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_10 0x00000350 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_11 0x00000358 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_12 0x00000360 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_13 0x00000368 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_14 0x00000370 /* 64-bit */ +#define MAILBOX_SNDHOST_PROD_IDX_15 0x00000378 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_0 0x00000380 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_1 0x00000388 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_2 0x00000390 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_3 0x00000398 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_4 0x000003a0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_5 0x000003a8 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_6 0x000003b0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_7 0x000003b8 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_8 0x000003c0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_9 0x000003c8 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_10 0x000003d0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_11 0x000003d8 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_12 0x000003e0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_13 0x000003e8 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_14 0x000003f0 /* 64-bit */ +#define MAILBOX_SNDNIC_PROD_IDX_15 0x000003f8 /* 64-bit */ + +/* MAC control registers */ +#define MAC_MODE 0x00000400 +#define MAC_MODE_RESET 0x00000001 +#define MAC_MODE_HALF_DUPLEX 0x00000002 +#define MAC_MODE_PORT_MODE_MASK 0x0000000c +#define MAC_MODE_PORT_MODE_TBI 0x0000000c +#define MAC_MODE_PORT_MODE_GMII 0x00000008 +#define MAC_MODE_PORT_MODE_MII 0x00000004 +#define MAC_MODE_PORT_MODE_NONE 0x00000000 +#define MAC_MODE_PORT_INT_LPBACK 0x00000010 +#define MAC_MODE_TAGGED_MAC_CTRL 0x00000080 +#define MAC_MODE_TX_BURSTING 0x00000100 +#define MAC_MODE_MAX_DEFER 0x00000200 +#define MAC_MODE_LINK_POLARITY 0x00000400 +#define MAC_MODE_RXSTAT_ENABLE 0x00000800 +#define MAC_MODE_RXSTAT_CLEAR 0x00001000 +#define MAC_MODE_RXSTAT_FLUSH 0x00002000 +#define MAC_MODE_TXSTAT_ENABLE 0x00004000 +#define MAC_MODE_TXSTAT_CLEAR 0x00008000 +#define MAC_MODE_TXSTAT_FLUSH 0x00010000 +#define MAC_MODE_SEND_CONFIGS 0x00020000 +#define MAC_MODE_MAGIC_PKT_ENABLE 0x00040000 +#define MAC_MODE_ACPI_ENABLE 0x00080000 +#define MAC_MODE_MIP_ENABLE 0x00100000 +#define MAC_MODE_TDE_ENABLE 0x00200000 +#define MAC_MODE_RDE_ENABLE 0x00400000 +#define MAC_MODE_FHDE_ENABLE 0x00800000 +#define MAC_STATUS 0x00000404 +#define MAC_STATUS_PCS_SYNCED 0x00000001 +#define MAC_STATUS_SIGNAL_DET 0x00000002 +#define MAC_STATUS_RCVD_CFG 0x00000004 +#define MAC_STATUS_CFG_CHANGED 0x00000008 +#define MAC_STATUS_SYNC_CHANGED 0x00000010 +#define MAC_STATUS_PORT_DEC_ERR 0x00000400 +#define MAC_STATUS_LNKSTATE_CHANGED 0x00001000 +#define MAC_STATUS_MI_COMPLETION 0x00400000 +#define MAC_STATUS_MI_INTERRUPT 0x00800000 +#define MAC_STATUS_AP_ERROR 0x01000000 +#define MAC_STATUS_ODI_ERROR 0x02000000 +#define MAC_STATUS_RXSTAT_OVERRUN 0x04000000 +#define MAC_STATUS_TXSTAT_OVERRUN 0x08000000 +#define MAC_EVENT 0x00000408 +#define MAC_EVENT_PORT_DECODE_ERR 0x00000400 +#define MAC_EVENT_LNKSTATE_CHANGED 0x00001000 +#define MAC_EVENT_MI_COMPLETION 0x00400000 +#define MAC_EVENT_MI_INTERRUPT 0x00800000 +#define MAC_EVENT_AP_ERROR 0x01000000 +#define MAC_EVENT_ODI_ERROR 0x02000000 +#define MAC_EVENT_RXSTAT_OVERRUN 0x04000000 +#define MAC_EVENT_TXSTAT_OVERRUN 0x08000000 +#define MAC_LED_CTRL 0x0000040c +#define LED_CTRL_LNKLED_OVERRIDE 0x00000001 +#define LED_CTRL_1000MBPS_ON 0x00000002 +#define LED_CTRL_100MBPS_ON 0x00000004 +#define LED_CTRL_10MBPS_ON 0x00000008 +#define LED_CTRL_TRAFFIC_OVERRIDE 0x00000010 +#define LED_CTRL_TRAFFIC_BLINK 0x00000020 +#define LED_CTRL_TRAFFIC_LED 0x00000040 +#define LED_CTRL_1000MBPS_STATUS 0x00000080 +#define LED_CTRL_100MBPS_STATUS 0x00000100 +#define LED_CTRL_10MBPS_STATUS 0x00000200 +#define LED_CTRL_TRAFFIC_STATUS 0x00000400 +#define LED_CTRL_MAC_MODE 0x00000000 +#define LED_CTRL_PHY_MODE_1 0x00000800 +#define LED_CTRL_PHY_MODE_2 0x00001000 +#define LED_CTRL_BLINK_RATE_MASK 0x7ff80000 +#define LED_CTRL_BLINK_RATE_SHIFT 19 +#define LED_CTRL_BLINK_PER_OVERRIDE 0x00080000 +#define LED_CTRL_BLINK_RATE_OVERRIDE 0x80000000 +#define MAC_ADDR_0_HIGH 0x00000410 /* upper 2 bytes */ +#define MAC_ADDR_0_LOW 0x00000414 /* lower 4 bytes */ +#define MAC_ADDR_1_HIGH 0x00000418 /* upper 2 bytes */ +#define MAC_ADDR_1_LOW 0x0000041c /* lower 4 bytes */ +#define MAC_ADDR_2_HIGH 0x00000420 /* upper 2 bytes */ +#define MAC_ADDR_2_LOW 0x00000424 /* lower 4 bytes */ +#define MAC_ADDR_3_HIGH 0x00000428 /* upper 2 bytes */ +#define MAC_ADDR_3_LOW 0x0000042c /* lower 4 bytes */ +#define MAC_ACPI_MBUF_PTR 0x00000430 +#define MAC_ACPI_LEN_OFFSET 0x00000434 +#define ACPI_LENOFF_LEN_MASK 0x0000ffff +#define ACPI_LENOFF_LEN_SHIFT 0 +#define ACPI_LENOFF_OFF_MASK 0x0fff0000 +#define ACPI_LENOFF_OFF_SHIFT 16 +#define MAC_TX_BACKOFF_SEED 0x00000438 +#define TX_BACKOFF_SEED_MASK 0x000003ff +#define MAC_RX_MTU_SIZE 0x0000043c +#define RX_MTU_SIZE_MASK 0x0000ffff +#define MAC_PCS_TEST 0x00000440 +#define PCS_TEST_PATTERN_MASK 0x000fffff +#define PCS_TEST_PATTERN_SHIFT 0 +#define PCS_TEST_ENABLE 0x00100000 +#define MAC_TX_AUTO_NEG 0x00000444 +#define TX_AUTO_NEG_MASK 0x0000ffff +#define TX_AUTO_NEG_SHIFT 0 +#define MAC_RX_AUTO_NEG 0x00000448 +#define RX_AUTO_NEG_MASK 0x0000ffff +#define RX_AUTO_NEG_SHIFT 0 +#define MAC_MI_COM 0x0000044c +#define MI_COM_CMD_MASK 0x0c000000 +#define MI_COM_CMD_WRITE 0x04000000 +#define MI_COM_CMD_READ 0x08000000 +#define MI_COM_READ_FAILED 0x10000000 +#define MI_COM_START 0x20000000 +#define MI_COM_BUSY 0x20000000 +#define MI_COM_PHY_ADDR_MASK 0x03e00000 +#define MI_COM_PHY_ADDR_SHIFT 21 +#define MI_COM_REG_ADDR_MASK 0x001f0000 +#define MI_COM_REG_ADDR_SHIFT 16 +#define MI_COM_DATA_MASK 0x0000ffff +#define MAC_MI_STAT 0x00000450 +#define MAC_MI_STAT_LNKSTAT_ATTN_ENAB 0x00000001 +#define MAC_MI_MODE 0x00000454 +#define MAC_MI_MODE_CLK_10MHZ 0x00000001 +#define MAC_MI_MODE_SHORT_PREAMBLE 0x00000002 +#define MAC_MI_MODE_AUTO_POLL 0x00000010 +#define MAC_MI_MODE_CORE_CLK_62MHZ 0x00008000 +#define MAC_MI_MODE_BASE 0x000c0000 /* XXX magic values XXX */ +#define MAC_AUTO_POLL_STATUS 0x00000458 +#define MAC_AUTO_POLL_ERROR 0x00000001 +#define MAC_TX_MODE 0x0000045c +#define TX_MODE_RESET 0x00000001 +#define TX_MODE_ENABLE 0x00000002 +#define TX_MODE_FLOW_CTRL_ENABLE 0x00000010 +#define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020 +#define TX_MODE_LONG_PAUSE_ENABLE 0x00000040 +#define MAC_TX_STATUS 0x00000460 +#define TX_STATUS_XOFFED 0x00000001 +#define TX_STATUS_SENT_XOFF 0x00000002 +#define TX_STATUS_SENT_XON 0x00000004 +#define TX_STATUS_LINK_UP 0x00000008 +#define TX_STATUS_ODI_UNDERRUN 0x00000010 +#define TX_STATUS_ODI_OVERRUN 0x00000020 +#define MAC_TX_LENGTHS 0x00000464 +#define TX_LENGTHS_SLOT_TIME_MASK 0x000000ff +#define TX_LENGTHS_SLOT_TIME_SHIFT 0 +#define TX_LENGTHS_IPG_MASK 0x00000f00 +#define TX_LENGTHS_IPG_SHIFT 8 +#define TX_LENGTHS_IPG_CRS_MASK 0x00003000 +#define TX_LENGTHS_IPG_CRS_SHIFT 12 +#define MAC_RX_MODE 0x00000468 +#define RX_MODE_RESET 0x00000001 +#define RX_MODE_ENABLE 0x00000002 +#define RX_MODE_FLOW_CTRL_ENABLE 0x00000004 +#define RX_MODE_KEEP_MAC_CTRL 0x00000008 +#define RX_MODE_KEEP_PAUSE 0x00000010 +#define RX_MODE_ACCEPT_OVERSIZED 0x00000020 +#define RX_MODE_ACCEPT_RUNTS 0x00000040 +#define RX_MODE_LEN_CHECK 0x00000080 +#define RX_MODE_PROMISC 0x00000100 +#define RX_MODE_NO_CRC_CHECK 0x00000200 +#define RX_MODE_KEEP_VLAN_TAG 0x00000400 +#define MAC_RX_STATUS 0x0000046c +#define RX_STATUS_REMOTE_TX_XOFFED 0x00000001 +#define RX_STATUS_XOFF_RCVD 0x00000002 +#define RX_STATUS_XON_RCVD 0x00000004 +#define MAC_HASH_REG_0 0x00000470 +#define MAC_HASH_REG_1 0x00000474 +#define MAC_HASH_REG_2 0x00000478 +#define MAC_HASH_REG_3 0x0000047c +#define MAC_RCV_RULE_0 0x00000480 +#define MAC_RCV_VALUE_0 0x00000484 +#define MAC_RCV_RULE_1 0x00000488 +#define MAC_RCV_VALUE_1 0x0000048c +#define MAC_RCV_RULE_2 0x00000490 +#define MAC_RCV_VALUE_2 0x00000494 +#define MAC_RCV_RULE_3 0x00000498 +#define MAC_RCV_VALUE_3 0x0000049c +#define MAC_RCV_RULE_4 0x000004a0 +#define MAC_RCV_VALUE_4 0x000004a4 +#define MAC_RCV_RULE_5 0x000004a8 +#define MAC_RCV_VALUE_5 0x000004ac +#define MAC_RCV_RULE_6 0x000004b0 +#define MAC_RCV_VALUE_6 0x000004b4 +#define MAC_RCV_RULE_7 0x000004b8 +#define MAC_RCV_VALUE_7 0x000004bc +#define MAC_RCV_RULE_8 0x000004c0 +#define MAC_RCV_VALUE_8 0x000004c4 +#define MAC_RCV_RULE_9 0x000004c8 +#define MAC_RCV_VALUE_9 0x000004cc +#define MAC_RCV_RULE_10 0x000004d0 +#define MAC_RCV_VALUE_10 0x000004d4 +#define MAC_RCV_RULE_11 0x000004d8 +#define MAC_RCV_VALUE_11 0x000004dc +#define MAC_RCV_RULE_12 0x000004e0 +#define MAC_RCV_VALUE_12 0x000004e4 +#define MAC_RCV_RULE_13 0x000004e8 +#define MAC_RCV_VALUE_13 0x000004ec +#define MAC_RCV_RULE_14 0x000004f0 +#define MAC_RCV_VALUE_14 0x000004f4 +#define MAC_RCV_RULE_15 0x000004f8 +#define MAC_RCV_VALUE_15 0x000004fc +#define RCV_RULE_DISABLE_MASK 0x7fffffff +#define MAC_RCV_RULE_CFG 0x00000500 +#define RCV_RULE_CFG_DEFAULT_CLASS 0x00000008 +/* 0x504 --> 0x590 unused */ +#define MAC_SERDES_CFG 0x00000590 +#define MAC_SERDES_STAT 0x00000594 +/* 0x598 --> 0x600 unused */ +#define MAC_TX_MAC_STATE_BASE 0x00000600 /* 16 bytes */ +#define MAC_RX_MAC_STATE_BASE 0x00000610 /* 20 bytes */ +/* 0x624 --> 0x800 unused */ +#define MAC_RX_STATS_BASE 0x00000800 /* 26 32-bit words */ +/* 0x868 --> 0x880 unused */ +#define MAC_TX_STATS_BASE 0x00000880 /* 28 32-bit words */ +/* 0x8f0 --> 0xc00 unused */ + +/* Send data initiator control registers */ +#define SNDDATAI_MODE 0x00000c00 +#define SNDDATAI_MODE_RESET 0x00000001 +#define SNDDATAI_MODE_ENABLE 0x00000002 +#define SNDDATAI_MODE_STAT_OFLOW_ENAB 0x00000004 +#define SNDDATAI_STATUS 0x00000c04 +#define SNDDATAI_STATUS_STAT_OFLOW 0x00000004 +#define SNDDATAI_STATSCTRL 0x00000c08 +#define SNDDATAI_SCTRL_ENABLE 0x00000001 +#define SNDDATAI_SCTRL_FASTUPD 0x00000002 +#define SNDDATAI_SCTRL_CLEAR 0x00000004 +#define SNDDATAI_SCTRL_FLUSH 0x00000008 +#define SNDDATAI_SCTRL_FORCE_ZERO 0x00000010 +#define SNDDATAI_STATSENAB 0x00000c0c +#define SNDDATAI_STATSINCMASK 0x00000c10 +/* 0xc14 --> 0xc80 unused */ +#define SNDDATAI_COS_CNT_0 0x00000c80 +#define SNDDATAI_COS_CNT_1 0x00000c84 +#define SNDDATAI_COS_CNT_2 0x00000c88 +#define SNDDATAI_COS_CNT_3 0x00000c8c +#define SNDDATAI_COS_CNT_4 0x00000c90 +#define SNDDATAI_COS_CNT_5 0x00000c94 +#define SNDDATAI_COS_CNT_6 0x00000c98 +#define SNDDATAI_COS_CNT_7 0x00000c9c +#define SNDDATAI_COS_CNT_8 0x00000ca0 +#define SNDDATAI_COS_CNT_9 0x00000ca4 +#define SNDDATAI_COS_CNT_10 0x00000ca8 +#define SNDDATAI_COS_CNT_11 0x00000cac +#define SNDDATAI_COS_CNT_12 0x00000cb0 +#define SNDDATAI_COS_CNT_13 0x00000cb4 +#define SNDDATAI_COS_CNT_14 0x00000cb8 +#define SNDDATAI_COS_CNT_15 0x00000cbc +#define SNDDATAI_DMA_RDQ_FULL_CNT 0x00000cc0 +#define SNDDATAI_DMA_PRIO_RDQ_FULL_CNT 0x00000cc4 +#define SNDDATAI_SDCQ_FULL_CNT 0x00000cc8 +#define SNDDATAI_NICRNG_SSND_PIDX_CNT 0x00000ccc +#define SNDDATAI_STATS_UPDATED_CNT 0x00000cd0 +#define SNDDATAI_INTERRUPTS_CNT 0x00000cd4 +#define SNDDATAI_AVOID_INTERRUPTS_CNT 0x00000cd8 +#define SNDDATAI_SND_THRESH_HIT_CNT 0x00000cdc +/* 0xce0 --> 0x1000 unused */ + +/* Send data completion control registers */ +#define SNDDATAC_MODE 0x00001000 +#define SNDDATAC_MODE_RESET 0x00000001 +#define SNDDATAC_MODE_ENABLE 0x00000002 +/* 0x1004 --> 0x1400 unused */ + +/* Send BD ring selector */ +#define SNDBDS_MODE 0x00001400 +#define SNDBDS_MODE_RESET 0x00000001 +#define SNDBDS_MODE_ENABLE 0x00000002 +#define SNDBDS_MODE_ATTN_ENABLE 0x00000004 +#define SNDBDS_STATUS 0x00001404 +#define SNDBDS_STATUS_ERROR_ATTN 0x00000004 +#define SNDBDS_HWDIAG 0x00001408 +/* 0x140c --> 0x1440 */ +#define SNDBDS_SEL_CON_IDX_0 0x00001440 +#define SNDBDS_SEL_CON_IDX_1 0x00001444 +#define SNDBDS_SEL_CON_IDX_2 0x00001448 +#define SNDBDS_SEL_CON_IDX_3 0x0000144c +#define SNDBDS_SEL_CON_IDX_4 0x00001450 +#define SNDBDS_SEL_CON_IDX_5 0x00001454 +#define SNDBDS_SEL_CON_IDX_6 0x00001458 +#define SNDBDS_SEL_CON_IDX_7 0x0000145c +#define SNDBDS_SEL_CON_IDX_8 0x00001460 +#define SNDBDS_SEL_CON_IDX_9 0x00001464 +#define SNDBDS_SEL_CON_IDX_10 0x00001468 +#define SNDBDS_SEL_CON_IDX_11 0x0000146c +#define SNDBDS_SEL_CON_IDX_12 0x00001470 +#define SNDBDS_SEL_CON_IDX_13 0x00001474 +#define SNDBDS_SEL_CON_IDX_14 0x00001478 +#define SNDBDS_SEL_CON_IDX_15 0x0000147c +/* 0x1480 --> 0x1800 unused */ + +/* Send BD initiator control registers */ +#define SNDBDI_MODE 0x00001800 +#define SNDBDI_MODE_RESET 0x00000001 +#define SNDBDI_MODE_ENABLE 0x00000002 +#define SNDBDI_MODE_ATTN_ENABLE 0x00000004 +#define SNDBDI_STATUS 0x00001804 +#define SNDBDI_STATUS_ERROR_ATTN 0x00000004 +#define SNDBDI_IN_PROD_IDX_0 0x00001808 +#define SNDBDI_IN_PROD_IDX_1 0x0000180c +#define SNDBDI_IN_PROD_IDX_2 0x00001810 +#define SNDBDI_IN_PROD_IDX_3 0x00001814 +#define SNDBDI_IN_PROD_IDX_4 0x00001818 +#define SNDBDI_IN_PROD_IDX_5 0x0000181c +#define SNDBDI_IN_PROD_IDX_6 0x00001820 +#define SNDBDI_IN_PROD_IDX_7 0x00001824 +#define SNDBDI_IN_PROD_IDX_8 0x00001828 +#define SNDBDI_IN_PROD_IDX_9 0x0000182c +#define SNDBDI_IN_PROD_IDX_10 0x00001830 +#define SNDBDI_IN_PROD_IDX_11 0x00001834 +#define SNDBDI_IN_PROD_IDX_12 0x00001838 +#define SNDBDI_IN_PROD_IDX_13 0x0000183c +#define SNDBDI_IN_PROD_IDX_14 0x00001840 +#define SNDBDI_IN_PROD_IDX_15 0x00001844 +/* 0x1848 --> 0x1c00 unused */ + +/* Send BD completion control registers */ +#define SNDBDC_MODE 0x00001c00 +#define SNDBDC_MODE_RESET 0x00000001 +#define SNDBDC_MODE_ENABLE 0x00000002 +#define SNDBDC_MODE_ATTN_ENABLE 0x00000004 +/* 0x1c04 --> 0x2000 unused */ + +/* Receive list placement control registers */ +#define RCVLPC_MODE 0x00002000 +#define RCVLPC_MODE_RESET 0x00000001 +#define RCVLPC_MODE_ENABLE 0x00000002 +#define RCVLPC_MODE_CLASS0_ATTN_ENAB 0x00000004 +#define RCVLPC_MODE_MAPOOR_AATTN_ENAB 0x00000008 +#define RCVLPC_MODE_STAT_OFLOW_ENAB 0x00000010 +#define RCVLPC_STATUS 0x00002004 +#define RCVLPC_STATUS_CLASS0 0x00000004 +#define RCVLPC_STATUS_MAPOOR 0x00000008 +#define RCVLPC_STATUS_STAT_OFLOW 0x00000010 +#define RCVLPC_LOCK 0x00002008 +#define RCVLPC_LOCK_REQ_MASK 0x0000ffff +#define RCVLPC_LOCK_REQ_SHIFT 0 +#define RCVLPC_LOCK_GRANT_MASK 0xffff0000 +#define RCVLPC_LOCK_GRANT_SHIFT 16 +#define RCVLPC_NON_EMPTY_BITS 0x0000200c +#define RCVLPC_NON_EMPTY_BITS_MASK 0x0000ffff +#define RCVLPC_CONFIG 0x00002010 +#define RCVLPC_STATSCTRL 0x00002014 +#define RCVLPC_STATSCTRL_ENABLE 0x00000001 +#define RCVLPC_STATSCTRL_FASTUPD 0x00000002 +#define RCVLPC_STATS_ENABLE 0x00002018 +#define RCVLPC_STATS_INCMASK 0x0000201c +/* 0x2020 --> 0x2100 unused */ +#define RCVLPC_SELLST_BASE 0x00002100 /* 16 16-byte entries */ +#define SELLST_TAIL 0x00000004 +#define SELLST_CONT 0x00000008 +#define SELLST_UNUSED 0x0000000c +#define RCVLPC_COS_CNTL_BASE 0x00002200 /* 16 4-byte entries */ +#define RCVLPC_DROP_FILTER_CNT 0x00002240 +#define RCVLPC_DMA_WQ_FULL_CNT 0x00002244 +#define RCVLPC_DMA_HIPRIO_WQ_FULL_CNT 0x00002248 +#define RCVLPC_NO_RCV_BD_CNT 0x0000224c +#define RCVLPC_IN_DISCARDS_CNT 0x00002250 +#define RCVLPC_IN_ERRORS_CNT 0x00002254 +#define RCVLPC_RCV_THRESH_HIT_CNT 0x00002258 +/* 0x225c --> 0x2400 unused */ + +/* Receive Data and Receive BD Initiator Control */ +#define RCVDBDI_MODE 0x00002400 +#define RCVDBDI_MODE_RESET 0x00000001 +#define RCVDBDI_MODE_ENABLE 0x00000002 +#define RCVDBDI_MODE_JUMBOBD_NEEDED 0x00000004 +#define RCVDBDI_MODE_FRM_TOO_BIG 0x00000008 +#define RCVDBDI_MODE_INV_RING_SZ 0x00000010 +#define RCVDBDI_STATUS 0x00002404 +#define RCVDBDI_STATUS_JUMBOBD_NEEDED 0x00000004 +#define RCVDBDI_STATUS_FRM_TOO_BIG 0x00000008 +#define RCVDBDI_STATUS_INV_RING_SZ 0x00000010 +#define RCVDBDI_SPLIT_FRAME_MINSZ 0x00002408 +/* 0x240c --> 0x2440 unused */ +#define RCVDBDI_JUMBO_BD 0x00002440 /* TG3_BDINFO_... */ +#define RCVDBDI_STD_BD 0x00002450 /* TG3_BDINFO_... */ +#define RCVDBDI_MINI_BD 0x00002460 /* TG3_BDINFO_... */ +#define RCVDBDI_JUMBO_CON_IDX 0x00002470 +#define RCVDBDI_STD_CON_IDX 0x00002474 +#define RCVDBDI_MINI_CON_IDX 0x00002478 +/* 0x247c --> 0x2480 unused */ +#define RCVDBDI_BD_PROD_IDX_0 0x00002480 +#define RCVDBDI_BD_PROD_IDX_1 0x00002484 +#define RCVDBDI_BD_PROD_IDX_2 0x00002488 +#define RCVDBDI_BD_PROD_IDX_3 0x0000248c +#define RCVDBDI_BD_PROD_IDX_4 0x00002490 +#define RCVDBDI_BD_PROD_IDX_5 0x00002494 +#define RCVDBDI_BD_PROD_IDX_6 0x00002498 +#define RCVDBDI_BD_PROD_IDX_7 0x0000249c +#define RCVDBDI_BD_PROD_IDX_8 0x000024a0 +#define RCVDBDI_BD_PROD_IDX_9 0x000024a4 +#define RCVDBDI_BD_PROD_IDX_10 0x000024a8 +#define RCVDBDI_BD_PROD_IDX_11 0x000024ac +#define RCVDBDI_BD_PROD_IDX_12 0x000024b0 +#define RCVDBDI_BD_PROD_IDX_13 0x000024b4 +#define RCVDBDI_BD_PROD_IDX_14 0x000024b8 +#define RCVDBDI_BD_PROD_IDX_15 0x000024bc +#define RCVDBDI_HWDIAG 0x000024c0 +/* 0x24c4 --> 0x2800 unused */ + +/* Receive Data Completion Control */ +#define RCVDCC_MODE 0x00002800 +#define RCVDCC_MODE_RESET 0x00000001 +#define RCVDCC_MODE_ENABLE 0x00000002 +#define RCVDCC_MODE_ATTN_ENABLE 0x00000004 +/* 0x2804 --> 0x2c00 unused */ + +/* Receive BD Initiator Control Registers */ +#define RCVBDI_MODE 0x00002c00 +#define RCVBDI_MODE_RESET 0x00000001 +#define RCVBDI_MODE_ENABLE 0x00000002 +#define RCVBDI_MODE_RCB_ATTN_ENAB 0x00000004 +#define RCVBDI_STATUS 0x00002c04 +#define RCVBDI_STATUS_RCB_ATTN 0x00000004 +#define RCVBDI_JUMBO_PROD_IDX 0x00002c08 +#define RCVBDI_STD_PROD_IDX 0x00002c0c +#define RCVBDI_MINI_PROD_IDX 0x00002c10 +#define RCVBDI_MINI_THRESH 0x00002c14 +#define RCVBDI_STD_THRESH 0x00002c18 +#define RCVBDI_JUMBO_THRESH 0x00002c1c +/* 0x2c20 --> 0x3000 unused */ + +/* Receive BD Completion Control Registers */ +#define RCVCC_MODE 0x00003000 +#define RCVCC_MODE_RESET 0x00000001 +#define RCVCC_MODE_ENABLE 0x00000002 +#define RCVCC_MODE_ATTN_ENABLE 0x00000004 +#define RCVCC_STATUS 0x00003004 +#define RCVCC_STATUS_ERROR_ATTN 0x00000004 +#define RCVCC_JUMP_PROD_IDX 0x00003008 +#define RCVCC_STD_PROD_IDX 0x0000300c +#define RCVCC_MINI_PROD_IDX 0x00003010 +/* 0x3014 --> 0x3400 unused */ + +/* Receive list selector control registers */ +#define RCVLSC_MODE 0x00003400 +#define RCVLSC_MODE_RESET 0x00000001 +#define RCVLSC_MODE_ENABLE 0x00000002 +#define RCVLSC_MODE_ATTN_ENABLE 0x00000004 +#define RCVLSC_STATUS 0x00003404 +#define RCVLSC_STATUS_ERROR_ATTN 0x00000004 +/* 0x3408 --> 0x3800 unused */ + +/* Mbuf cluster free registers */ +#define MBFREE_MODE 0x00003800 +#define MBFREE_MODE_RESET 0x00000001 +#define MBFREE_MODE_ENABLE 0x00000002 +#define MBFREE_STATUS 0x00003804 +/* 0x3808 --> 0x3c00 unused */ + +/* Host coalescing control registers */ +#define HOSTCC_MODE 0x00003c00 +#define HOSTCC_MODE_RESET 0x00000001 +#define HOSTCC_MODE_ENABLE 0x00000002 +#define HOSTCC_MODE_ATTN 0x00000004 +#define HOSTCC_MODE_NOW 0x00000008 +#define HOSTCC_MODE_FULL_STATUS 0x00000000 +#define HOSTCC_MODE_64BYTE 0x00000080 +#define HOSTCC_MODE_32BYTE 0x00000100 +#define HOSTCC_MODE_CLRTICK_RXBD 0x00000200 +#define HOSTCC_MODE_CLRTICK_TXBD 0x00000400 +#define HOSTCC_MODE_NOINT_ON_NOW 0x00000800 +#define HOSTCC_MODE_NOINT_ON_FORCE 0x00001000 +#define HOSTCC_STATUS 0x00003c04 +#define HOSTCC_STATUS_ERROR_ATTN 0x00000004 +#define HOSTCC_RXCOL_TICKS 0x00003c08 +#define LOW_RXCOL_TICKS 0x00000032 +#define DEFAULT_RXCOL_TICKS 0x00000048 +#define HIGH_RXCOL_TICKS 0x00000096 +#define HOSTCC_TXCOL_TICKS 0x00003c0c +#define LOW_TXCOL_TICKS 0x00000096 +#define DEFAULT_TXCOL_TICKS 0x0000012c +#define HIGH_TXCOL_TICKS 0x00000145 +#define HOSTCC_RXMAX_FRAMES 0x00003c10 +#define LOW_RXMAX_FRAMES 0x00000005 +#define DEFAULT_RXMAX_FRAMES 0x00000008 +#define HIGH_RXMAX_FRAMES 0x00000012 +#define HOSTCC_TXMAX_FRAMES 0x00003c14 +#define LOW_TXMAX_FRAMES 0x00000035 +#define DEFAULT_TXMAX_FRAMES 0x0000004b +#define HIGH_TXMAX_FRAMES 0x00000052 +#define HOSTCC_RXCOAL_TICK_INT 0x00003c18 +#define DEFAULT_RXCOAL_TICK_INT 0x00000019 +#define HOSTCC_TXCOAL_TICK_INT 0x00003c1c +#define DEFAULT_TXCOAL_TICK_INT 0x00000019 +#define HOSTCC_RXCOAL_MAXF_INT 0x00003c20 +#define DEFAULT_RXCOAL_MAXF_INT 0x00000005 +#define HOSTCC_TXCOAL_MAXF_INT 0x00003c24 +#define DEFAULT_TXCOAL_MAXF_INT 0x00000005 +#define HOSTCC_STAT_COAL_TICKS 0x00003c28 +#define DEFAULT_STAT_COAL_TICKS 0x000f4240 +/* 0x3c2c --> 0x3c30 unused */ +#define HOSTCC_STATS_BLK_HOST_ADDR 0x00003c30 /* 64-bit */ +#define HOSTCC_STATUS_BLK_HOST_ADDR 0x00003c38 /* 64-bit */ +#define HOSTCC_STATS_BLK_NIC_ADDR 0x00003c40 +#define HOSTCC_STATUS_BLK_NIC_ADDR 0x00003c44 +#define HOSTCC_FLOW_ATTN 0x00003c48 +/* 0x3c4c --> 0x3c50 unused */ +#define HOSTCC_JUMBO_CON_IDX 0x00003c50 +#define HOSTCC_STD_CON_IDX 0x00003c54 +#define HOSTCC_MINI_CON_IDX 0x00003c58 +/* 0x3c5c --> 0x3c80 unused */ +#define HOSTCC_RET_PROD_IDX_0 0x00003c80 +#define HOSTCC_RET_PROD_IDX_1 0x00003c84 +#define HOSTCC_RET_PROD_IDX_2 0x00003c88 +#define HOSTCC_RET_PROD_IDX_3 0x00003c8c +#define HOSTCC_RET_PROD_IDX_4 0x00003c90 +#define HOSTCC_RET_PROD_IDX_5 0x00003c94 +#define HOSTCC_RET_PROD_IDX_6 0x00003c98 +#define HOSTCC_RET_PROD_IDX_7 0x00003c9c +#define HOSTCC_RET_PROD_IDX_8 0x00003ca0 +#define HOSTCC_RET_PROD_IDX_9 0x00003ca4 +#define HOSTCC_RET_PROD_IDX_10 0x00003ca8 +#define HOSTCC_RET_PROD_IDX_11 0x00003cac +#define HOSTCC_RET_PROD_IDX_12 0x00003cb0 +#define HOSTCC_RET_PROD_IDX_13 0x00003cb4 +#define HOSTCC_RET_PROD_IDX_14 0x00003cb8 +#define HOSTCC_RET_PROD_IDX_15 0x00003cbc +#define HOSTCC_SND_CON_IDX_0 0x00003cc0 +#define HOSTCC_SND_CON_IDX_1 0x00003cc4 +#define HOSTCC_SND_CON_IDX_2 0x00003cc8 +#define HOSTCC_SND_CON_IDX_3 0x00003ccc +#define HOSTCC_SND_CON_IDX_4 0x00003cd0 +#define HOSTCC_SND_CON_IDX_5 0x00003cd4 +#define HOSTCC_SND_CON_IDX_6 0x00003cd8 +#define HOSTCC_SND_CON_IDX_7 0x00003cdc +#define HOSTCC_SND_CON_IDX_8 0x00003ce0 +#define HOSTCC_SND_CON_IDX_9 0x00003ce4 +#define HOSTCC_SND_CON_IDX_10 0x00003ce8 +#define HOSTCC_SND_CON_IDX_11 0x00003cec +#define HOSTCC_SND_CON_IDX_12 0x00003cf0 +#define HOSTCC_SND_CON_IDX_13 0x00003cf4 +#define HOSTCC_SND_CON_IDX_14 0x00003cf8 +#define HOSTCC_SND_CON_IDX_15 0x00003cfc +/* 0x3d00 --> 0x4000 unused */ + +/* Memory arbiter control registers */ +#define MEMARB_MODE 0x00004000 +#define MEMARB_MODE_RESET 0x00000001 +#define MEMARB_MODE_ENABLE 0x00000002 +#define MEMARB_STATUS 0x00004004 +#define MEMARB_TRAP_ADDR_LOW 0x00004008 +#define MEMARB_TRAP_ADDR_HIGH 0x0000400c +/* 0x4010 --> 0x4400 unused */ + +/* Buffer manager control registers */ +#define BUFMGR_MODE 0x00004400 +#define BUFMGR_MODE_RESET 0x00000001 +#define BUFMGR_MODE_ENABLE 0x00000002 +#define BUFMGR_MODE_ATTN_ENABLE 0x00000004 +#define BUFMGR_MODE_BM_TEST 0x00000008 +#define BUFMGR_MODE_MBLOW_ATTN_ENAB 0x00000010 +#define BUFMGR_STATUS 0x00004404 +#define BUFMGR_STATUS_ERROR 0x00000004 +#define BUFMGR_STATUS_MBLOW 0x00000010 +#define BUFMGR_MB_POOL_ADDR 0x00004408 +#define BUFMGR_MB_POOL_SIZE 0x0000440c +#define BUFMGR_MB_RDMA_LOW_WATER 0x00004410 +#define DEFAULT_MB_RDMA_LOW_WATER 0x00000040 +#define DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130 +#define BUFMGR_MB_MACRX_LOW_WATER 0x00004414 +#define DEFAULT_MB_MACRX_LOW_WATER 0x00000020 +#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098 +#define BUFMGR_MB_HIGH_WATER 0x00004418 +#define DEFAULT_MB_HIGH_WATER 0x00000060 +#define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c +#define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c +#define BUFMGR_MB_ALLOC_BIT 0x10000000 +#define BUFMGR_RX_MB_ALLOC_RESP 0x00004420 +#define BUFMGR_TX_MB_ALLOC_REQ 0x00004424 +#define BUFMGR_TX_MB_ALLOC_RESP 0x00004428 +#define BUFMGR_DMA_DESC_POOL_ADDR 0x0000442c +#define BUFMGR_DMA_DESC_POOL_SIZE 0x00004430 +#define BUFMGR_DMA_LOW_WATER 0x00004434 +#define DEFAULT_DMA_LOW_WATER 0x00000005 +#define BUFMGR_DMA_HIGH_WATER 0x00004438 +#define DEFAULT_DMA_HIGH_WATER 0x0000000a +#define BUFMGR_RX_DMA_ALLOC_REQ 0x0000443c +#define BUFMGR_RX_DMA_ALLOC_RESP 0x00004440 +#define BUFMGR_TX_DMA_ALLOC_REQ 0x00004444 +#define BUFMGR_TX_DMA_ALLOC_RESP 0x00004448 +#define BUFMGR_HWDIAG_0 0x0000444c +#define BUFMGR_HWDIAG_1 0x00004450 +#define BUFMGR_HWDIAG_2 0x00004454 +/* 0x4458 --> 0x4800 unused */ + +/* Read DMA control registers */ +#define RDMAC_MODE 0x00004800 +#define RDMAC_MODE_RESET 0x00000001 +#define RDMAC_MODE_ENABLE 0x00000002 +#define RDMAC_MODE_TGTABORT_ENAB 0x00000004 +#define RDMAC_MODE_MSTABORT_ENAB 0x00000008 +#define RDMAC_MODE_PARITYERR_ENAB 0x00000010 +#define RDMAC_MODE_ADDROFLOW_ENAB 0x00000020 +#define RDMAC_MODE_FIFOOFLOW_ENAB 0x00000040 +#define RDMAC_MODE_FIFOURUN_ENAB 0x00000080 +#define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100 +#define RDMAC_MODE_LNGREAD_ENAB 0x00000200 +#define RDMAC_STATUS 0x00004804 +#define RDMAC_STATUS_TGTABORT 0x00000004 +#define RDMAC_STATUS_MSTABORT 0x00000008 +#define RDMAC_STATUS_PARITYERR 0x00000010 +#define RDMAC_STATUS_ADDROFLOW 0x00000020 +#define RDMAC_STATUS_FIFOOFLOW 0x00000040 +#define RDMAC_STATUS_FIFOURUN 0x00000080 +#define RDMAC_STATUS_FIFOOREAD 0x00000100 +#define RDMAC_STATUS_LNGREAD 0x00000200 +/* 0x4808 --> 0x4c00 unused */ + +/* Write DMA control registers */ +#define WDMAC_MODE 0x00004c00 +#define WDMAC_MODE_RESET 0x00000001 +#define WDMAC_MODE_ENABLE 0x00000002 +#define WDMAC_MODE_TGTABORT_ENAB 0x00000004 +#define WDMAC_MODE_MSTABORT_ENAB 0x00000008 +#define WDMAC_MODE_PARITYERR_ENAB 0x00000010 +#define WDMAC_MODE_ADDROFLOW_ENAB 0x00000020 +#define WDMAC_MODE_FIFOOFLOW_ENAB 0x00000040 +#define WDMAC_MODE_FIFOURUN_ENAB 0x00000080 +#define WDMAC_MODE_FIFOOREAD_ENAB 0x00000100 +#define WDMAC_MODE_LNGREAD_ENAB 0x00000200 +#define WDMAC_STATUS 0x00004c04 +#define WDMAC_STATUS_TGTABORT 0x00000004 +#define WDMAC_STATUS_MSTABORT 0x00000008 +#define WDMAC_STATUS_PARITYERR 0x00000010 +#define WDMAC_STATUS_ADDROFLOW 0x00000020 +#define WDMAC_STATUS_FIFOOFLOW 0x00000040 +#define WDMAC_STATUS_FIFOURUN 0x00000080 +#define WDMAC_STATUS_FIFOOREAD 0x00000100 +#define WDMAC_STATUS_LNGREAD 0x00000200 +/* 0x4c08 --> 0x5000 unused */ + +/* Per-cpu register offsets (arm9) */ +#define CPU_MODE 0x00000000 +#define CPU_MODE_RESET 0x00000001 +#define CPU_MODE_HALT 0x00000400 +#define CPU_STATE 0x00000004 +#define CPU_EVTMASK 0x00000008 +/* 0xc --> 0x1c reserved */ +#define CPU_PC 0x0000001c +#define CPU_INSN 0x00000020 +#define CPU_SPAD_UFLOW 0x00000024 +#define CPU_WDOG_CLEAR 0x00000028 +#define CPU_WDOG_VECTOR 0x0000002c +#define CPU_WDOG_PC 0x00000030 +#define CPU_HW_BP 0x00000034 +/* 0x38 --> 0x44 unused */ +#define CPU_WDOG_SAVED_STATE 0x00000044 +#define CPU_LAST_BRANCH_ADDR 0x00000048 +#define CPU_SPAD_UFLOW_SET 0x0000004c +/* 0x50 --> 0x200 unused */ +#define CPU_R0 0x00000200 +#define CPU_R1 0x00000204 +#define CPU_R2 0x00000208 +#define CPU_R3 0x0000020c +#define CPU_R4 0x00000210 +#define CPU_R5 0x00000214 +#define CPU_R6 0x00000218 +#define CPU_R7 0x0000021c +#define CPU_R8 0x00000220 +#define CPU_R9 0x00000224 +#define CPU_R10 0x00000228 +#define CPU_R11 0x0000022c +#define CPU_R12 0x00000230 +#define CPU_R13 0x00000234 +#define CPU_R14 0x00000238 +#define CPU_R15 0x0000023c +#define CPU_R16 0x00000240 +#define CPU_R17 0x00000244 +#define CPU_R18 0x00000248 +#define CPU_R19 0x0000024c +#define CPU_R20 0x00000250 +#define CPU_R21 0x00000254 +#define CPU_R22 0x00000258 +#define CPU_R23 0x0000025c +#define CPU_R24 0x00000260 +#define CPU_R25 0x00000264 +#define CPU_R26 0x00000268 +#define CPU_R27 0x0000026c +#define CPU_R28 0x00000270 +#define CPU_R29 0x00000274 +#define CPU_R30 0x00000278 +#define CPU_R31 0x0000027c +/* 0x280 --> 0x400 unused */ + +#define RX_CPU_BASE 0x00005000 +#define TX_CPU_BASE 0x00005400 + +/* Mailboxes */ +#define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */ +#define GRCMBOX_INTERRUPT_1 0x00005808 /* 64-bit */ +#define GRCMBOX_INTERRUPT_2 0x00005810 /* 64-bit */ +#define GRCMBOX_INTERRUPT_3 0x00005818 /* 64-bit */ +#define GRCMBOX_GENERAL_0 0x00005820 /* 64-bit */ +#define GRCMBOX_GENERAL_1 0x00005828 /* 64-bit */ +#define GRCMBOX_GENERAL_2 0x00005830 /* 64-bit */ +#define GRCMBOX_GENERAL_3 0x00005838 /* 64-bit */ +#define GRCMBOX_GENERAL_4 0x00005840 /* 64-bit */ +#define GRCMBOX_GENERAL_5 0x00005848 /* 64-bit */ +#define GRCMBOX_GENERAL_6 0x00005850 /* 64-bit */ +#define GRCMBOX_GENERAL_7 0x00005858 /* 64-bit */ +#define GRCMBOX_RELOAD_STAT 0x00005860 /* 64-bit */ +#define GRCMBOX_RCVSTD_PROD_IDX 0x00005868 /* 64-bit */ +#define GRCMBOX_RCVJUMBO_PROD_IDX 0x00005870 /* 64-bit */ +#define GRCMBOX_RCVMINI_PROD_IDX 0x00005878 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_0 0x00005880 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_1 0x00005888 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_2 0x00005890 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_3 0x00005898 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_4 0x000058a0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_5 0x000058a8 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_6 0x000058b0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_7 0x000058b8 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_8 0x000058c0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_9 0x000058c8 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_10 0x000058d0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_11 0x000058d8 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_12 0x000058e0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_13 0x000058e8 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_14 0x000058f0 /* 64-bit */ +#define GRCMBOX_RCVRET_CON_IDX_15 0x000058f8 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_0 0x00005900 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_1 0x00005908 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_2 0x00005910 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_3 0x00005918 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_4 0x00005920 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_5 0x00005928 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_6 0x00005930 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_7 0x00005938 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_8 0x00005940 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_9 0x00005948 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_10 0x00005950 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_11 0x00005958 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_12 0x00005960 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_13 0x00005968 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_14 0x00005970 /* 64-bit */ +#define GRCMBOX_SNDHOST_PROD_IDX_15 0x00005978 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_0 0x00005980 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_1 0x00005988 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_2 0x00005990 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_3 0x00005998 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_4 0x000059a0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_5 0x000059a8 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_6 0x000059b0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_7 0x000059b8 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_8 0x000059c0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_9 0x000059c8 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_10 0x000059d0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_11 0x000059d8 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_12 0x000059e0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_13 0x000059e8 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_14 0x000059f0 /* 64-bit */ +#define GRCMBOX_SNDNIC_PROD_IDX_15 0x000059f8 /* 64-bit */ +#define GRCMBOX_HIGH_PRIO_EV_VECTOR 0x00005a00 +#define GRCMBOX_HIGH_PRIO_EV_MASK 0x00005a04 +#define GRCMBOX_LOW_PRIO_EV_VEC 0x00005a08 +#define GRCMBOX_LOW_PRIO_EV_MASK 0x00005a0c +/* 0x5a10 --> 0x5c00 */ + +/* Flow Through queues */ +#define FTQ_RESET 0x00005c00 +/* 0x5c04 --> 0x5c10 unused */ +#define FTQ_DMA_NORM_READ_CTL 0x00005c10 +#define FTQ_DMA_NORM_READ_FULL_CNT 0x00005c14 +#define FTQ_DMA_NORM_READ_FIFO_ENQDEQ 0x00005c18 +#define FTQ_DMA_NORM_READ_WRITE_PEEK 0x00005c1c +#define FTQ_DMA_HIGH_READ_CTL 0x00005c20 +#define FTQ_DMA_HIGH_READ_FULL_CNT 0x00005c24 +#define FTQ_DMA_HIGH_READ_FIFO_ENQDEQ 0x00005c28 +#define FTQ_DMA_HIGH_READ_WRITE_PEEK 0x00005c2c +#define FTQ_DMA_COMP_DISC_CTL 0x00005c30 +#define FTQ_DMA_COMP_DISC_FULL_CNT 0x00005c34 +#define FTQ_DMA_COMP_DISC_FIFO_ENQDEQ 0x00005c38 +#define FTQ_DMA_COMP_DISC_WRITE_PEEK 0x00005c3c +#define FTQ_SEND_BD_COMP_CTL 0x00005c40 +#define FTQ_SEND_BD_COMP_FULL_CNT 0x00005c44 +#define FTQ_SEND_BD_COMP_FIFO_ENQDEQ 0x00005c48 +#define FTQ_SEND_BD_COMP_WRITE_PEEK 0x00005c4c +#define FTQ_SEND_DATA_INIT_CTL 0x00005c50 +#define FTQ_SEND_DATA_INIT_FULL_CNT 0x00005c54 +#define FTQ_SEND_DATA_INIT_FIFO_ENQDEQ 0x00005c58 +#define FTQ_SEND_DATA_INIT_WRITE_PEEK 0x00005c5c +#define FTQ_DMA_NORM_WRITE_CTL 0x00005c60 +#define FTQ_DMA_NORM_WRITE_FULL_CNT 0x00005c64 +#define FTQ_DMA_NORM_WRITE_FIFO_ENQDEQ 0x00005c68 +#define FTQ_DMA_NORM_WRITE_WRITE_PEEK 0x00005c6c +#define FTQ_DMA_HIGH_WRITE_CTL 0x00005c70 +#define FTQ_DMA_HIGH_WRITE_FULL_CNT 0x00005c74 +#define FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ 0x00005c78 +#define FTQ_DMA_HIGH_WRITE_WRITE_PEEK 0x00005c7c +#define FTQ_SWTYPE1_CTL 0x00005c80 +#define FTQ_SWTYPE1_FULL_CNT 0x00005c84 +#define FTQ_SWTYPE1_FIFO_ENQDEQ 0x00005c88 +#define FTQ_SWTYPE1_WRITE_PEEK 0x00005c8c +#define FTQ_SEND_DATA_COMP_CTL 0x00005c90 +#define FTQ_SEND_DATA_COMP_FULL_CNT 0x00005c94 +#define FTQ_SEND_DATA_COMP_FIFO_ENQDEQ 0x00005c98 +#define FTQ_SEND_DATA_COMP_WRITE_PEEK 0x00005c9c +#define FTQ_HOST_COAL_CTL 0x00005ca0 +#define FTQ_HOST_COAL_FULL_CNT 0x00005ca4 +#define FTQ_HOST_COAL_FIFO_ENQDEQ 0x00005ca8 +#define FTQ_HOST_COAL_WRITE_PEEK 0x00005cac +#define FTQ_MAC_TX_CTL 0x00005cb0 +#define FTQ_MAC_TX_FULL_CNT 0x00005cb4 +#define FTQ_MAC_TX_FIFO_ENQDEQ 0x00005cb8 +#define FTQ_MAC_TX_WRITE_PEEK 0x00005cbc +#define FTQ_MB_FREE_CTL 0x00005cc0 +#define FTQ_MB_FREE_FULL_CNT 0x00005cc4 +#define FTQ_MB_FREE_FIFO_ENQDEQ 0x00005cc8 +#define FTQ_MB_FREE_WRITE_PEEK 0x00005ccc +#define FTQ_RCVBD_COMP_CTL 0x00005cd0 +#define FTQ_RCVBD_COMP_FULL_CNT 0x00005cd4 +#define FTQ_RCVBD_COMP_FIFO_ENQDEQ 0x00005cd8 +#define FTQ_RCVBD_COMP_WRITE_PEEK 0x00005cdc +#define FTQ_RCVLST_PLMT_CTL 0x00005ce0 +#define FTQ_RCVLST_PLMT_FULL_CNT 0x00005ce4 +#define FTQ_RCVLST_PLMT_FIFO_ENQDEQ 0x00005ce8 +#define FTQ_RCVLST_PLMT_WRITE_PEEK 0x00005cec +#define FTQ_RCVDATA_INI_CTL 0x00005cf0 +#define FTQ_RCVDATA_INI_FULL_CNT 0x00005cf4 +#define FTQ_RCVDATA_INI_FIFO_ENQDEQ 0x00005cf8 +#define FTQ_RCVDATA_INI_WRITE_PEEK 0x00005cfc +#define FTQ_RCVDATA_COMP_CTL 0x00005d00 +#define FTQ_RCVDATA_COMP_FULL_CNT 0x00005d04 +#define FTQ_RCVDATA_COMP_FIFO_ENQDEQ 0x00005d08 +#define FTQ_RCVDATA_COMP_WRITE_PEEK 0x00005d0c +#define FTQ_SWTYPE2_CTL 0x00005d10 +#define FTQ_SWTYPE2_FULL_CNT 0x00005d14 +#define FTQ_SWTYPE2_FIFO_ENQDEQ 0x00005d18 +#define FTQ_SWTYPE2_WRITE_PEEK 0x00005d1c +/* 0x5d20 --> 0x6000 unused */ + +/* Message signaled interrupt registers */ +#define MSGINT_MODE 0x00006000 +#define MSGINT_MODE_RESET 0x00000001 +#define MSGINT_MODE_ENABLE 0x00000002 +#define MSGINT_STATUS 0x00006004 +#define MSGINT_FIFO 0x00006008 +/* 0x600c --> 0x6400 unused */ + +/* DMA completion registers */ +#define DMAC_MODE 0x00006400 +#define DMAC_MODE_RESET 0x00000001 +#define DMAC_MODE_ENABLE 0x00000002 +/* 0x6404 --> 0x6800 unused */ + +/* GRC registers */ +#define GRC_MODE 0x00006800 +#define GRC_MODE_UPD_ON_COAL 0x00000001 +#define GRC_MODE_BSWAP_NONFRM_DATA 0x00000002 +#define GRC_MODE_WSWAP_NONFRM_DATA 0x00000004 +#define GRC_MODE_BSWAP_DATA 0x00000010 +#define GRC_MODE_WSWAP_DATA 0x00000020 +#define GRC_MODE_SPLITHDR 0x00000100 +#define GRC_MODE_NOFRM_CRACKING 0x00000200 +#define GRC_MODE_INCL_CRC 0x00000400 +#define GRC_MODE_ALLOW_BAD_FRMS 0x00000800 +#define GRC_MODE_NOIRQ_ON_SENDS 0x00002000 +#define GRC_MODE_NOIRQ_ON_RCV 0x00004000 +#define GRC_MODE_FORCE_PCI32BIT 0x00008000 +#define GRC_MODE_HOST_STACKUP 0x00010000 +#define GRC_MODE_HOST_SENDBDS 0x00020000 +#define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 +#define GRC_MODE_NO_RX_PHDR_CSUM 0x00800000 +#define GRC_MODE_IRQ_ON_TX_CPU_ATTN 0x01000000 +#define GRC_MODE_IRQ_ON_RX_CPU_ATTN 0x02000000 +#define GRC_MODE_IRQ_ON_MAC_ATTN 0x04000000 +#define GRC_MODE_IRQ_ON_DMA_ATTN 0x08000000 +#define GRC_MODE_IRQ_ON_FLOW_ATTN 0x10000000 +#define GRC_MODE_4X_NIC_SEND_RINGS 0x20000000 +#define GRC_MODE_MCAST_FRM_ENABLE 0x40000000 +#define GRC_MISC_CFG 0x00006804 +#define GRC_MISC_CFG_CORECLK_RESET 0x00000001 +#define GRC_MISC_CFG_PRESCALAR_MASK 0x000000fe +#define GRC_MISC_CFG_PRESCALAR_SHIFT 1 +#define GRC_MISC_CFG_BOARD_ID_MASK 0x0001e000 +#define GRC_MISC_CFG_BOARD_ID_5700 0x0001e000 +#define GRC_MISC_CFG_BOARD_ID_5701 0x00000000 +#define GRC_MISC_CFG_BOARD_ID_5702FE 0x00004000 +#define GRC_MISC_CFG_BOARD_ID_5703 0x00000000 +#define GRC_MISC_CFG_BOARD_ID_5703S 0x00002000 +#define GRC_LOCAL_CTRL 0x00006808 +#define GRC_LCLCTRL_INT_ACTIVE 0x00000001 +#define GRC_LCLCTRL_CLEARINT 0x00000002 +#define GRC_LCLCTRL_SETINT 0x00000004 +#define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_GPIO_INPUT0 0x00000100 +#define GRC_LCLCTRL_GPIO_INPUT1 0x00000200 +#define GRC_LCLCTRL_GPIO_INPUT2 0x00000400 +#define GRC_LCLCTRL_GPIO_OE0 0x00000800 +#define GRC_LCLCTRL_GPIO_OE1 0x00001000 +#define GRC_LCLCTRL_GPIO_OE2 0x00002000 +#define GRC_LCLCTRL_GPIO_OUTPUT0 0x00004000 +#define GRC_LCLCTRL_GPIO_OUTPUT1 0x00008000 +#define GRC_LCLCTRL_GPIO_OUTPUT2 0x00010000 +#define GRC_LCLCTRL_EXTMEM_ENABLE 0x00020000 +#define GRC_LCLCTRL_MEMSZ_MASK 0x001c0000 +#define GRC_LCLCTRL_MEMSZ_256K 0x00000000 +#define GRC_LCLCTRL_MEMSZ_512K 0x00040000 +#define GRC_LCLCTRL_MEMSZ_1M 0x00080000 +#define GRC_LCLCTRL_MEMSZ_2M 0x000c0000 +#define GRC_LCLCTRL_MEMSZ_4M 0x00100000 +#define GRC_LCLCTRL_MEMSZ_8M 0x00140000 +#define GRC_LCLCTRL_MEMSZ_16M 0x00180000 +#define GRC_LCLCTRL_BANK_SELECT 0x00200000 +#define GRC_LCLCTRL_SSRAM_TYPE 0x00400000 +#define GRC_LCLCTRL_AUTO_SEEPROM 0x01000000 +#define GRC_TIMER 0x0000680c +#define GRC_RX_CPU_EVENT 0x00006810 +#define GRC_RX_TIMER_REF 0x00006814 +#define GRC_RX_CPU_SEM 0x00006818 +#define GRC_REMOTE_RX_CPU_ATTN 0x0000681c +#define GRC_TX_CPU_EVENT 0x00006820 +#define GRC_TX_TIMER_REF 0x00006824 +#define GRC_TX_CPU_SEM 0x00006828 +#define GRC_REMOTE_TX_CPU_ATTN 0x0000682c +#define GRC_MEM_POWER_UP 0x00006830 /* 64-bit */ +#define GRC_EEPROM_ADDR 0x00006838 +#define EEPROM_ADDR_WRITE 0x00000000 +#define EEPROM_ADDR_READ 0x80000000 +#define EEPROM_ADDR_COMPLETE 0x40000000 +#define EEPROM_ADDR_FSM_RESET 0x20000000 +#define EEPROM_ADDR_DEVID_MASK 0x1c000000 +#define EEPROM_ADDR_DEVID_SHIFT 26 +#define EEPROM_ADDR_START 0x02000000 +#define EEPROM_ADDR_CLKPERD_SHIFT 16 +#define EEPROM_ADDR_ADDR_MASK 0x0000ffff +#define EEPROM_ADDR_ADDR_SHIFT 0 +#define EEPROM_DEFAULT_CLOCK_PERIOD 0x60 +#define EEPROM_CHIP_SIZE (64 * 1024) +#define GRC_EEPROM_DATA 0x0000683c +#define GRC_EEPROM_CTRL 0x00006840 +#define GRC_MDI_CTRL 0x00006844 +#define GRC_SEEPROM_DELAY 0x00006848 +/* 0x684c --> 0x6c00 unused */ + +/* 0x6c00 --> 0x7000 unused */ + +/* NVRAM Control registers */ +#define NVRAM_CMD 0x00007000 +#define NVRAM_CMD_RESET 0x00000001 +#define NVRAM_CMD_DONE 0x00000008 +#define NVRAM_CMD_GO 0x00000010 +#define NVRAM_CMD_WR 0x00000020 +#define NVRAM_CMD_RD 0x00000000 +#define NVRAM_CMD_ERASE 0x00000040 +#define NVRAM_CMD_FIRST 0x00000080 +#define NVRAM_CMD_LAST 0x00000100 +#define NVRAM_STAT 0x00007004 +#define NVRAM_WRDATA 0x00007008 +#define NVRAM_ADDR 0x0000700c +#define NVRAM_ADDR_MSK 0x00ffffff +#define NVRAM_RDDATA 0x00007010 +#define NVRAM_CFG1 0x00007014 +#define NVRAM_CFG1_FLASHIF_ENAB 0x00000001 +#define NVRAM_CFG1_BUFFERED_MODE 0x00000002 +#define NVRAM_CFG1_PASS_THRU 0x00000004 +#define NVRAM_CFG1_BIT_BANG 0x00000008 +#define NVRAM_CFG1_COMPAT_BYPASS 0x80000000 +#define NVRAM_CFG2 0x00007018 +#define NVRAM_CFG3 0x0000701c +#define NVRAM_SWARB 0x00007020 +#define SWARB_REQ_SET0 0x00000001 +#define SWARB_REQ_SET1 0x00000002 +#define SWARB_REQ_SET2 0x00000004 +#define SWARB_REQ_SET3 0x00000008 +#define SWARB_REQ_CLR0 0x00000010 +#define SWARB_REQ_CLR1 0x00000020 +#define SWARB_REQ_CLR2 0x00000040 +#define SWARB_REQ_CLR3 0x00000080 +#define SWARB_GNT0 0x00000100 +#define SWARB_GNT1 0x00000200 +#define SWARB_GNT2 0x00000400 +#define SWARB_GNT3 0x00000800 +#define SWARB_REQ0 0x00001000 +#define SWARB_REQ1 0x00002000 +#define SWARB_REQ2 0x00004000 +#define SWARB_REQ3 0x00008000 +#define NVRAM_BUFFERED_PAGE_SIZE 264 +#define NVRAM_BUFFERED_PAGE_POS 9 +/* 0x7024 --> 0x7400 unused */ + +/* 0x7400 --> 0x8000 unused */ + +/* 32K Window into NIC internal memory */ +#define NIC_SRAM_WIN_BASE 0x00008000 + +/* Offsets into first 32k of NIC internal memory. */ +#define NIC_SRAM_PAGE_ZERO 0x00000000 +#define NIC_SRAM_SEND_RCB 0x00000100 /* 16 * TG3_BDINFO_... */ +#define NIC_SRAM_RCV_RET_RCB 0x00000200 /* 16 * TG3_BDINFO_... */ +#define NIC_SRAM_STATS_BLK 0x00000300 +#define NIC_SRAM_STATUS_BLK 0x00000b00 + +#define NIC_SRAM_FIRMWARE_MBOX 0x00000b50 +#define NIC_SRAM_FIRMWARE_MBOX_MAGIC1 0x4B657654 +#define NIC_SRAM_FIRMWARE_MBOX_MAGIC2 0x4861764b /* !dma on linkchg */ + +#define NIC_SRAM_DATA_SIG 0x00000b54 +#define NIC_SRAM_DATA_SIG_MAGIC 0x4b657654 /* ascii for 'KevT' */ + +#define NIC_SRAM_DATA_CFG 0x00000b58 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_MASK 0x0000000c +#define NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN 0x00000000 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER 0x00000004 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER 0x00000008 +#define NIC_SRAM_DATA_CFG_LED_MODE_MASK 0x00000030 +#define NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN 0x00000000 +#define NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD 0x00000010 +#define NIC_SRAM_DATA_CFG_LED_LINK_SPD 0x00000020 + +#define NIC_SRAM_DATA_PHY_ID 0x00000b74 +#define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000 +#define NIC_SRAM_DATA_PHY_ID2_MASK 0x0000ffff + +#define NIC_SRAM_FW_CMD_MBOX 0x00000b78 +#define FWCMD_NICDRV_ALIVE 0x00000001 +#define FWCMD_NICDRV_PAUSE_FW 0x00000002 +#define FWCMD_NICDRV_IPV4ADDR_CHG 0x00000003 +#define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004 +#define FWCMD_NICDRV_FIX_DMAR 0x00000005 +#define FWCMD_NICDRV_FIX_DMAW 0x00000006 +#define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c +#define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80 +#define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00 +#define NIC_SRAM_FW_DRV_STATE_MBOX 0x00000c04 +#define DRV_STATE_START 0x00000001 +#define DRV_STATE_UNLOAD 0x00000002 +#define DRV_STATE_WOL 0x00000003 +#define DRV_STATE_SUSPEND 0x00000004 + +#define NIC_SRAM_FW_RESET_TYPE_MBOX 0x00000c08 + +#define NIC_SRAM_MAC_ADDR_HIGH_MBOX 0x00000c14 +#define NIC_SRAM_MAC_ADDR_LOW_MBOX 0x00000c18 + +#if TG3_MINI_RING_WORKS +#define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 +#endif + +#define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 +#define NIC_SRAM_DMA_DESC_POOL_SIZE 0x00002000 +#define NIC_SRAM_TX_BUFFER_DESC 0x00004000 /* 512 entries */ +#define NIC_SRAM_RX_BUFFER_DESC 0x00006000 /* 256 entries */ +#define NIC_SRAM_RX_JUMBO_BUFFER_DESC 0x00007000 /* 256 entries */ +#define NIC_SRAM_MBUF_POOL_BASE 0x00008000 +#define NIC_SRAM_MBUF_POOL_SIZE 0x00018000 + +/* Currently this is fixed. */ +#define PHY_ADDR 0x01 + +/* Tigon3 specific PHY MII registers. */ +#define TG3_BMCR_SPEED1000 0x0040 + +#define MII_TG3_CTRL 0x09 /* 1000-baseT control register */ +#define MII_TG3_CTRL_ADV_1000_HALF 0x0100 +#define MII_TG3_CTRL_ADV_1000_FULL 0x0200 +#define MII_TG3_CTRL_AS_MASTER 0x0800 +#define MII_TG3_CTRL_ENABLE_AS_MASTER 0x1000 + +#define MII_TG3_EXT_CTRL 0x10 /* Extended control register */ +#define MII_TG3_EXT_CTRL_LNK3_LED_MODE 0x0002 +#define MII_TG3_EXT_CTRL_TBI 0x8000 + +#define MII_TG3_EXT_STAT 0x11 /* Extended status register */ +#define MII_TG3_EXT_STAT_LPASS 0x0100 + +#define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */ + +#define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */ + +#define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */ + +#define MII_TG3_AUX_STAT 0x19 /* auxilliary status register */ +#define MII_TG3_AUX_STAT_LPASS 0x0004 +#define MII_TG3_AUX_STAT_SPDMASK 0x0700 +#define MII_TG3_AUX_STAT_10HALF 0x0100 +#define MII_TG3_AUX_STAT_10FULL 0x0200 +#define MII_TG3_AUX_STAT_100HALF 0x0300 +#define MII_TG3_AUX_STAT_100_4 0x0400 +#define MII_TG3_AUX_STAT_100FULL 0x0500 +#define MII_TG3_AUX_STAT_1000HALF 0x0600 +#define MII_TG3_AUX_STAT_1000FULL 0x0700 + +#define MII_TG3_ISTAT 0x1a /* IRQ status register */ +#define MII_TG3_IMASK 0x1b /* IRQ mask register */ + +/* ISTAT/IMASK event bits */ +#define MII_TG3_INT_LINKCHG 0x0002 +#define MII_TG3_INT_SPEEDCHG 0x0004 +#define MII_TG3_INT_DUPLEXCHG 0x0008 +#define MII_TG3_INT_ANEG_PAGE_RX 0x0400 + +/* XXX Add this to mii.h */ +#ifndef ADVERTISE_PAUSE +#define ADVERTISE_PAUSE_CAP 0x0400 +#endif +#ifndef ADVERTISE_PAUSE_ASYM +#define ADVERTISE_PAUSE_ASYM 0x0800 +#endif +#ifndef LPA_PAUSE +#define LPA_PAUSE_CAP 0x0400 +#endif +#ifndef LPA_PAUSE_ASYM +#define LPA_PAUSE_ASYM 0x0800 +#endif + +/* There are two ways to manage the TX descriptors on the tigon3. + * Either the descriptors are in host DMA'able memory, or they + * exist only in the cards on-chip SRAM. All 16 send bds are under + * the same mode, they may not be configured individually. + * + * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags. + * + * To use host memory TX descriptors: + * 1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register. + * Make sure GRC_MODE_4X_NIC_SEND_RINGS is clear. + * 2) Allocate DMA'able memory. + * 3) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM: + * a) Set TG3_BDINFO_HOST_ADDR to DMA address of memory + * obtained in step 2 + * b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC. + * c) Set len field of TG3_BDINFO_MAXLEN_FLAGS to number + * of TX descriptors. Leave flags field clear. + * 4) Access TX descriptors via host memory. The chip + * will refetch into local SRAM as needed when producer + * index mailboxes are updated. + * + * To use on-chip TX descriptors: + * 1) Set GRC_MODE_4X_NIC_SEND_RINGS in GRC_MODE register. + * Make sure GRC_MODE_HOST_SENDBDS is clear. + * 2) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM: + * a) Set TG3_BDINFO_HOST_ADDR to zero. + * b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC + * c) TG3_BDINFO_MAXLEN_FLAGS is don't care. + * 3) Access TX descriptors directly in on-chip SRAM + * using normal {read,write}l(). (and not using + * pointer dereferencing of ioremap()'d memory like + * the broken Broadcom driver does) + * + * Note that BDINFO_FLAGS_DISABLED should be set in the flags field of + * TG3_BDINFO_MAXLEN_FLAGS of all unused SEND_RCB indices. + */ +struct tg3_tx_buffer_desc { + u32 addr_hi; + u32 addr_lo; + + u32 len_flags; +#define TXD_FLAG_TCPUDP_CSUM 0x0001 +#define TXD_FLAG_IP_CSUM 0x0002 +#define TXD_FLAG_END 0x0004 +#define TXD_FLAG_IP_FRAG 0x0008 +#define TXD_FLAG_IP_FRAG_END 0x0010 +#define TXD_FLAG_VLAN 0x0040 +#define TXD_FLAG_COAL_NOW 0x0080 +#define TXD_FLAG_CPU_PRE_DMA 0x0100 +#define TXD_FLAG_CPU_POST_DMA 0x0200 +#define TXD_FLAG_ADD_SRC_ADDR 0x1000 +#define TXD_FLAG_CHOOSE_SRC_ADDR 0x6000 +#define TXD_FLAG_NO_CRC 0x8000 +#define TXD_LEN_SHIFT 16 + + u32 vlan_tag; +#define TXD_VLAN_TAG_SHIFT 0 +}; + +#define TXD_ADDR 0x00UL /* 64-bit */ +#define TXD_LEN_FLAGS 0x08UL /* 32-bit (upper 16-bits are len) */ +#define TXD_VLAN_TAG 0x0cUL /* 32-bit (upper 16-bits are tag) */ +#define TXD_SIZE 0x10UL + +struct tg3_rx_buffer_desc { + u32 addr_hi; + u32 addr_lo; + + u32 idx_len; +#define RXD_IDX_MASK 0xffff0000 +#define RXD_IDX_SHIFT 16 +#define RXD_LEN_MASK 0x0000ffff +#define RXD_LEN_SHIFT 0 + + u32 type_flags; +#define RXD_TYPE_SHIFT 16 +#define RXD_FLAGS_SHIFT 0 + +#define RXD_FLAG_END 0x0004 +#if TG3_MINI_RING_WORKS +#define RXD_FLAG_MINI 0x0800 +#endif +#define RXD_FLAG_JUMBO 0x0020 +#define RXD_FLAG_VLAN 0x0040 +#define RXD_FLAG_ERROR 0x0400 +#define RXD_FLAG_IP_CSUM 0x1000 +#define RXD_FLAG_TCPUDP_CSUM 0x2000 +#define RXD_FLAG_IS_TCP 0x4000 + + u32 ip_tcp_csum; +#define RXD_IPCSUM_MASK 0xffff0000 +#define RXD_IPCSUM_SHIFT 16 +#define RXD_TCPCSUM_MASK 0x0000ffff +#define RXD_TCPCSUM_SHIFT 0 + + u32 err_vlan; + +#define RXD_VLAN_MASK 0x0000ffff + +#define RXD_ERR_BAD_CRC 0x00010000 +#define RXD_ERR_COLLISION 0x00020000 +#define RXD_ERR_LINK_LOST 0x00040000 +#define RXD_ERR_PHY_DECODE 0x00080000 +#define RXD_ERR_ODD_NIBBLE_RCVD_MII 0x00100000 +#define RXD_ERR_MAC_ABRT 0x00200000 +#define RXD_ERR_TOO_SMALL 0x00400000 +#define RXD_ERR_NO_RESOURCES 0x00800000 +#define RXD_ERR_HUGE_FRAME 0x01000000 +#define RXD_ERR_MASK 0xffff0000 + + u32 reserved; + u32 opaque; +#define RXD_OPAQUE_INDEX_MASK 0x0000ffff +#define RXD_OPAQUE_INDEX_SHIFT 0 +#define RXD_OPAQUE_RING_STD 0x00010000 +#define RXD_OPAQUE_RING_JUMBO 0x00020000 +#if TG3_MINI_RING_WORKS +#define RXD_OPAQUE_RING_MINI 0x00040000 +#endif +#define RXD_OPAQUE_RING_MASK 0x00070000 +}; + +struct tg3_ext_rx_buffer_desc { + struct { + u32 addr_hi; + u32 addr_lo; + } addrlist[3]; + u32 len2_len1; + u32 resv_len3; + struct tg3_rx_buffer_desc std; +}; + +/* We only use this when testing out the DMA engine + * at probe time. This is the internal format of buffer + * descriptors used by the chip at NIC_SRAM_DMA_DESCS. + */ +struct tg3_internal_buffer_desc { + u32 addr_hi; + u32 addr_lo; + u32 nic_mbuf; + /* XXX FIX THIS */ +#ifdef __BIG_ENDIAN + u16 cqid_sqid; + u16 len; +#else + u16 len; + u16 cqid_sqid; +#endif + u32 flags; + u32 __cookie1; + u32 __cookie2; + u32 __cookie3; +}; + +#define TG3_HW_STATUS_SIZE 0x80 +struct tg3_hw_status { + u32 status; +#define SD_STATUS_UPDATED 0x00000001 +#define SD_STATUS_LINK_CHG 0x00000002 +#define SD_STATUS_ERROR 0x00000004 + + u32 status_tag; + +#ifdef __BIG_ENDIAN + u16 rx_consumer; + u16 rx_jumbo_consumer; +#else + u16 rx_jumbo_consumer; + u16 rx_consumer; +#endif + +#ifdef __BIG_ENDIAN + u16 reserved; + u16 rx_mini_consumer; +#else + u16 rx_mini_consumer; + u16 reserved; +#endif + struct { +#ifdef __BIG_ENDIAN + u16 tx_consumer; + u16 rx_producer; +#else + u16 rx_producer; + u16 tx_consumer; +#endif + } idx[16]; +}; + +typedef struct { + u32 high, low; +} tg3_stat64_t; + +struct tg3_hw_stats { + u8 __reserved0[0x400-0x300]; + + /* Statistics maintained by Receive MAC. */ + tg3_stat64_t rx_octets; + u64 __reserved1; + tg3_stat64_t rx_fragments; + tg3_stat64_t rx_ucast_packets; + tg3_stat64_t rx_mcast_packets; + tg3_stat64_t rx_bcast_packets; + tg3_stat64_t rx_fcs_errors; + tg3_stat64_t rx_align_errors; + tg3_stat64_t rx_xon_pause_rcvd; + tg3_stat64_t rx_xoff_pause_rcvd; + tg3_stat64_t rx_mac_ctrl_rcvd; + tg3_stat64_t rx_xoff_entered; + tg3_stat64_t rx_frame_too_long_errors; + tg3_stat64_t rx_jabbers; + tg3_stat64_t rx_undersize_packets; + tg3_stat64_t rx_in_length_errors; + tg3_stat64_t rx_out_length_errors; + tg3_stat64_t rx_64_or_less_octet_packets; + tg3_stat64_t rx_65_to_127_octet_packets; + tg3_stat64_t rx_128_to_255_octet_packets; + tg3_stat64_t rx_256_to_511_octet_packets; + tg3_stat64_t rx_512_to_1023_octet_packets; + tg3_stat64_t rx_1024_to_1522_octet_packets; + tg3_stat64_t rx_1523_to_2047_octet_packets; + tg3_stat64_t rx_2048_to_4095_octet_packets; + tg3_stat64_t rx_4096_to_8191_octet_packets; + tg3_stat64_t rx_8192_to_9022_octet_packets; + + u64 __unused0[37]; + + /* Statistics maintained by Transmit MAC. */ + tg3_stat64_t tx_octets; + u64 __reserved2; + tg3_stat64_t tx_collisions; + tg3_stat64_t tx_xon_sent; + tg3_stat64_t tx_xoff_sent; + tg3_stat64_t tx_flow_control; + tg3_stat64_t tx_mac_errors; + tg3_stat64_t tx_single_collisions; + tg3_stat64_t tx_mult_collisions; + tg3_stat64_t tx_deferred; + u64 __reserved3; + tg3_stat64_t tx_excessive_collisions; + tg3_stat64_t tx_late_collisions; + tg3_stat64_t tx_collide_2times; + tg3_stat64_t tx_collide_3times; + tg3_stat64_t tx_collide_4times; + tg3_stat64_t tx_collide_5times; + tg3_stat64_t tx_collide_6times; + tg3_stat64_t tx_collide_7times; + tg3_stat64_t tx_collide_8times; + tg3_stat64_t tx_collide_9times; + tg3_stat64_t tx_collide_10times; + tg3_stat64_t tx_collide_11times; + tg3_stat64_t tx_collide_12times; + tg3_stat64_t tx_collide_13times; + tg3_stat64_t tx_collide_14times; + tg3_stat64_t tx_collide_15times; + tg3_stat64_t tx_ucast_packets; + tg3_stat64_t tx_mcast_packets; + tg3_stat64_t tx_bcast_packets; + tg3_stat64_t tx_carrier_sense_errors; + tg3_stat64_t tx_discards; + tg3_stat64_t tx_errors; + + u64 __unused1[31]; + + /* Statistics maintained by Receive List Placement. */ + tg3_stat64_t COS_rx_packets[16]; + tg3_stat64_t COS_rx_filter_dropped; + tg3_stat64_t dma_writeq_full; + tg3_stat64_t dma_write_prioq_full; + tg3_stat64_t rxbds_empty; + tg3_stat64_t rx_discards; + tg3_stat64_t rx_errors; + tg3_stat64_t rx_threshold_hit; + + u64 __unused2[9]; + + /* Statistics maintained by Send Data Initiator. */ + tg3_stat64_t COS_out_packets[16]; + tg3_stat64_t dma_readq_full; + tg3_stat64_t dma_read_prioq_full; + tg3_stat64_t tx_comp_queue_full; + + /* Statistics maintained by Host Coalescing. */ + tg3_stat64_t ring_set_send_prod_index; + tg3_stat64_t ring_status_update; + tg3_stat64_t nic_irqs; + tg3_stat64_t nic_avoided_irqs; + tg3_stat64_t nic_tx_threshold_hit; + + u8 __reserved4[0xb00-0x9c0]; +}; + +enum phy_led_mode { + led_mode_auto, + led_mode_three_link, + led_mode_link10 +}; + +/* 'mapping' is superfluous as the chip does not write into + * the tx/rx post rings so we could just fetch it from there. + * But the cache behavior is better how we are doing it now. + */ +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct tg3_config_info { + u32 flags; +}; + +struct tg3_link_config { + /* Describes what we're trying to get. */ + u32 advertising; + u16 speed; + u8 duplex; + u8 autoneg; + + /* Describes what we actually have. */ + u16 active_speed; + u8 active_duplex; +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff +#define AUTONEG_INVALID 0xff + + /* When we go in and out of low power mode we need + * to swap with this state. + */ + int phy_is_low_power; + u16 orig_speed; + u8 orig_duplex; + u8 orig_autoneg; +}; + +struct tg3_coalesce_config { + /* Current settings. */ + u32 rx_coalesce_ticks; + u32 rx_max_coalesced_frames; + u32 rx_coalesce_ticks_during_int; + u32 rx_max_coalesced_frames_during_int; + u32 tx_coalesce_ticks; + u32 tx_max_coalesced_frames; + u32 tx_coalesce_ticks_during_int; + u32 tx_max_coalesced_frames_during_int; + u32 stats_coalesce_ticks; + + /* Default settings. */ + u32 rx_coalesce_ticks_def; + u32 rx_max_coalesced_frames_def; + u32 rx_coalesce_ticks_during_int_def; + u32 rx_max_coalesced_frames_during_int_def; + u32 tx_coalesce_ticks_def; + u32 tx_max_coalesced_frames_def; + u32 tx_coalesce_ticks_during_int_def; + u32 tx_max_coalesced_frames_during_int_def; + u32 stats_coalesce_ticks_def; + + /* Adaptive RX/TX coalescing parameters. */ + u32 rate_sample_jiffies; + u32 pkt_rate_low; + u32 pkt_rate_high; + + u32 rx_coalesce_ticks_low; + u32 rx_max_coalesced_frames_low; + u32 tx_coalesce_ticks_low; + u32 tx_max_coalesced_frames_low; + + u32 rx_coalesce_ticks_high; + u32 rx_max_coalesced_frames_high; + u32 tx_coalesce_ticks_high; + u32 tx_max_coalesced_frames_high; +}; + +struct tg3_bufmgr_config { + u32 mbuf_read_dma_low_water; + u32 mbuf_mac_rx_low_water; + u32 mbuf_high_water; + + u32 mbuf_read_dma_low_water_jumbo; + u32 mbuf_mac_rx_low_water_jumbo; + u32 mbuf_high_water_jumbo; + + u32 dma_low_water; + u32 dma_high_water; +}; + +struct tg3 { + spinlock_t lock; + u32 tx_prod; + u32 tx_cons; + u32 rx_rcb_ptr; + u32 rx_std_ptr; + u32 rx_jumbo_ptr; +#if TG3_MINI_RING_WORKS + u32 rx_mini_ptr; +#endif + spinlock_t indirect_lock; + + struct net_device_stats net_stats; + struct net_device_stats net_stats_prev; + unsigned long phy_crc_errors; + + /* Adaptive coalescing engine. */ + unsigned long last_rate_sample; + u32 last_rx_count; + u32 last_tx_count; + + u32 rx_offset; + u32 tg3_flags; +#define TG3_FLAG_HOST_TXDS 0x00000001 +#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 +#define TG3_FLAG_RX_CHECKSUMS 0x00000004 +#define TG3_FLAG_USE_LINKCHG_REG 0x00000008 +#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010 +#define TG3_FLAG_ADAPTIVE_RX 0x00000020 +#define TG3_FLAG_ADAPTIVE_TX 0x00000040 +#define TG3_FLAG_PHY_RESET_ON_INIT 0x00000100 +#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 +#define TG3_FLAG_TAGGED_IRQ_STATUS 0x00000400 +#define TG3_FLAG_WOL_SPEED_100MB 0x00000800 +#define TG3_FLAG_WOL_ENABLE 0x00001000 +#define TG3_FLAG_NVRAM 0x00002000 +#define TG3_FLAG_NVRAM_BUFFERED 0x00004000 +#define TG3_FLAG_RX_PAUSE 0x00008000 +#define TG3_FLAG_TX_PAUSE 0x00010000 +#define TG3_FLAG_PCIX_MODE 0x00020000 +#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 +#define TG3_FLAG_PCI_32BIT 0x00080000 +#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000 +#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000 +#define TG3_FLAG_AUTONEG_DISABLE 0x00400000 +#define TG3_FLAG_JUMBO_ENABLE 0x00800000 +#define TG3_FLAG_10_100_ONLY 0x01000000 +#define TG3_FLAG_PAUSE_AUTONEG 0x02000000 +#define TG3_FLAG_PAUSE_RX 0x04000000 +#define TG3_FLAG_PAUSE_TX 0x08000000 +#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 +#define TG3_FLAG_INIT_COMPLETE 0x80000000 + + u32 msg_enable; + + struct timer_list timer; + u16 timer_counter; + u16 timer_multiplier; + u32 timer_offset; + + struct tg3_link_config link_config; + struct tg3_coalesce_config coalesce_config; + struct tg3_bufmgr_config bufmgr_config; + + u32 rx_pending; +#if TG3_MINI_RING_WORKS + u32 rx_mini_pending; +#endif + u32 rx_jumbo_pending; + u32 tx_pending; + + /* cache h/w values, often passed straight to h/w */ + u32 rx_mode; + u32 tx_mode; + u32 mac_mode; + u32 mi_mode; + u32 misc_host_ctrl; + u32 grc_mode; + u32 grc_local_ctrl; + u32 dma_rwctrl; + u32 coalesce_mode; + + /* PCI block */ + u16 pci_chip_rev_id; + u8 pci_cacheline_sz; + u8 pci_lat_timer; + u8 pci_hdr_type; + u8 pci_bist; + u32 pci_cfg_state[64 / sizeof(u32)]; + + int pm_cap; + + /* PHY info */ + u32 phy_id; +#define PHY_ID_MASK 0xfffffff0 +#define PHY_ID_BCM5400 0x60008040 +#define PHY_ID_BCM5401 0x60008050 +#define PHY_ID_BCM5411 0x60008070 +#define PHY_ID_BCM5701 0x60008110 +#define PHY_ID_BCM5703 0x60008160 +#define PHY_ID_BCM8002 0x60010140 +#define PHY_ID_SERDES 0xfeedbee0 +#define PHY_ID_INVALID 0xffffffff +#define PHY_ID_REV_MASK 0x0000000f +#define PHY_REV_BCM5401_B0 0x1 +#define PHY_REV_BCM5401_B2 0x3 +#define PHY_REV_BCM5401_C0 0x6 + + enum phy_led_mode led_mode; + + char board_part_number[24]; + + /* This macro assumes the passed PHY ID is already masked + * with PHY_ID_MASK. + */ +#define KNOWN_PHY_ID(X) \ + ((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \ + (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ + (X) == PHY_ID_BCM5703 || \ + (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) + + unsigned long regs; + struct pci_dev *pdev; + struct net_device *dev; +#if TG3_VLAN_TAG_USED + struct vlan_group *vlgrp; +#endif + + struct tg3_rx_buffer_desc *rx_std; + struct ring_info *rx_std_buffers; + dma_addr_t rx_std_mapping; +#if TG3_MINI_RING_WORKS + struct tg3_rx_buffer_desc *rx_mini; + struct ring_info *rx_mini_buffers; + dma_addr_t rx_mini_mapping; +#endif + struct tg3_rx_buffer_desc *rx_jumbo; + struct ring_info *rx_jumbo_buffers; + dma_addr_t rx_jumbo_mapping; + + struct tg3_rx_buffer_desc *rx_rcb; + dma_addr_t rx_rcb_mapping; + + /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ + struct tg3_tx_buffer_desc *tx_ring; + struct ring_info *tx_buffers; + dma_addr_t tx_desc_mapping; + + struct tg3_hw_status *hw_status; + dma_addr_t status_mapping; + + struct tg3_hw_stats *hw_stats; + dma_addr_t stats_mapping; +}; + +#endif /* !(_T3_H) */ diff -urN linux-2.4.18/drivers/net/tokenring/3c359.c linux-2.4.19-pre5/drivers/net/tokenring/3c359.c --- linux-2.4.18/drivers/net/tokenring/3c359.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tokenring/3c359.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,1816 @@ +/* + * 3c359.c (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3c359 Tokenlink Velocity XL PCI NIC + * + * Base Driver Olympic: + * Written 1999 Peter De Schrijver & Mike Phillips + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * 7/17/00 - Clean up, version number 0.9.0. Ready to release to the world. + * + * 2/16/01 - Port up to kernel 2.4.2 ready for submission into the kernel. + * 3/05/01 - Last clean up stuff before submission. + * 2/15/01 - Finally, update to new pci api. + * + * To Do: + */ + +/* + * Technical Card Details + * + * All access to data is done with 16/8 bit transfers. The transfer + * method really sucks. You can only read or write one location at a time. + * + * Also, the microcode for the card must be uploaded if the card does not have + * the flashrom on board. This is a 28K bloat in the driver when compiled + * as a module. + * + * Rx is very simple, status into a ring of descriptors, dma data transfer, + * interrupts to tell us when a packet is received. + * + * Tx is a little more interesting. Similar scenario, descriptor and dma data + * transfers, but we don't have to interrupt the card to tell it another packet + * is ready for transmission, we are just doing simple memory writes, not io or mmio + * writes. The card can be set up to simply poll on the next + * descriptor pointer and when this value is non-zero will automatically download + * the next packet. The card then interrupts us when the packet is done. + * + */ + +#define XL_DEBUG 0 + +#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 "3c359.h" + +static char version[] __devinitdata = +"3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; + +MODULE_AUTHOR("Mike Phillips ") ; +MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; + +/* Module paramters */ + +/* Ring Speed 0,4,16 + * 0 = Autosense + * 4,16 = Selected speed only, no autosense + * This allows the card to be the first on the ring + * and become the active monitor. + * + * WARNING: Some hubs will allow you to insert + * at the wrong speed. + * + * The adapter will _not_ fail to open if there are no + * active monitors on the ring, it will simply open up in + * its last known ringspeed if no ringspeed is specified. + */ + +static int ringspeed[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(ringspeed, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i"); +MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; + +/* Packet buffer size */ + +static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; +/* Message Level */ + +static int message_level[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(message_level, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(message_level, "3c359: Level of reported messages \n") ; +/* + * This is a real nasty way of doing this, but otherwise you + * will be stuck with 1555 lines of hex #'s in the code. + */ + +#include "3c359_microcode.h" + +static struct pci_device_id xl_pci_tbl[] __devinitdata = +{ + {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci,xl_pci_tbl) ; + +static int xl_init(struct net_device *dev); +static int xl_open(struct net_device *dev); +static int xl_open_hw(struct net_device *dev) ; +static int xl_hw_reset(struct net_device *dev); +static int xl_xmit(struct sk_buff *skb, struct net_device *dev); +static void xl_dn_comp(struct net_device *dev); +static int xl_close(struct net_device *dev); +static void xl_set_rx_mode(struct net_device *dev); +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * xl_get_stats(struct net_device *dev); +static int xl_set_mac_address(struct net_device *dev, void *addr) ; +static void xl_arb_cmd(struct net_device *dev); +static void xl_asb_cmd(struct net_device *dev) ; +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) ; +static void xl_wait_misr_flags(struct net_device *dev) ; +static int xl_change_mtu(struct net_device *dev, int mtu); +static void xl_srb_bh(struct net_device *dev) ; +static void xl_asb_bh(struct net_device *dev) ; +static void xl_reset(struct net_device *dev) ; +static void xl_freemem(struct net_device *dev) ; + + +/* EEProm Access Functions */ +static u16 xl_ee_read(struct net_device *dev, int ee_addr) ; +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) ; + +/* Debugging functions */ +#if XL_DEBUG +static void print_tx_state(struct net_device *dev) ; +static void print_rx_state(struct net_device *dev) ; + +static void print_tx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_tx_desc *txd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d \n",xl_priv->tx_ring_head, + xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; + printk("Ring , Address , FSH , DnNextPtr, Buffer, Buffer_Len \n"); + for (i = 0; i < 16; i++) { + txd = &(xl_priv->xl_tx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(txd), + txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; + } + + printk("DNLISTPTR = %04x \n", readl(xl_mmio + MMIO_DNLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} + +static void print_rx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_rx_desc *rxd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("rx_ring_tail: %d \n", xl_priv->rx_ring_tail) ; + printk("Ring , Address , FrameState , UPNextPtr, FragAddr, Frag_Len \n"); + for (i = 0; i < 16; i++) { + /* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */ + rxd = &(xl_priv->xl_rx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(rxd), + rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; + } + + printk("UPLISTPTR = %04x \n", readl(xl_mmio + MMIO_UPLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} +#endif + +/* + * Read values from the on-board EEProm. This looks very strange + * but you have to wait for the EEProm to get/set the value before + * passing/getting the next value from the nic. As with all requests + * on this nic it has to be done in two stages, a) tell the nic which + * memory address you want to access and b) pass/get the value from the nic. + * With the EEProm, you have to wait before and inbetween access a) and b). + * As this is only read at initialization time and the wait period is very + * small we shouldn't have to worry about scheduling issues. + */ + +static u16 xl_ee_read(struct net_device *dev, int ee_addr) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Finally read the value from the EEProm */ + writel(IO_WORD_READ | EEDATA , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + return readw(xl_mmio + MMIO_MACDATA) ; +} + +/* + * Write values to the onboard eeprom. As with eeprom read you need to + * set which location to write, wait, value to write, wait, with the + * added twist of having to enable eeprom writes as well. + */ + +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Enable write/erase */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EE_ENABLE_WRITE, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Put the value we want to write into EEDATA */ + writel(IO_WORD_WRITE | EEDATA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ee_value, xl_mmio + MMIO_MACDATA) ; + + /* Tell EEProm to write eevalue into ee_addr */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEWRITE + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy, to ensure write gets done */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + return ; +} + +int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev ; + struct xl_private *xl_priv ; + static int card_no = -1 ; + int i ; + + card_no++ ; + + if (pci_enable_device(pdev)) { + return -ENODEV ; + } + + pci_set_master(pdev); + + if ((i = pci_request_regions(pdev,"3c359"))) { + return i ; + } ; + + /* + * Allowing init_trdev to allocate the dev->priv structure will align xl_private + * on a 32 bytes boundary which we need for the rx/tx descriptors + */ + + dev = alloc_trdev(sizeof(struct xl_private)) ; + if (!dev) { + pci_release_regions(pdev) ; + return -ENOMEM ; + } + xl_priv = dev->priv ; + +#if XL_DEBUG + printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", + pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ; +#endif + + dev->irq=pdev->irq; + dev->base_addr=pci_resource_start(pdev,0) ; + dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ + xl_priv->xl_card_name = (char *)pdev->name ; + xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); + xl_priv->pdev = pdev ; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) + xl_priv->pkt_buf_sz = PKT_BUF_SZ ; + else + xl_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; + + dev->mtu = xl_priv->pkt_buf_sz - TR_HLEN ; + xl_priv->xl_ring_speed = ringspeed[card_no] ; + xl_priv->xl_message_level = message_level[card_no] ; + xl_priv->xl_functional_addr[0] = xl_priv->xl_functional_addr[1] = xl_priv->xl_functional_addr[2] = xl_priv->xl_functional_addr[3] = 0 ; + xl_priv->xl_copy_all_options = 0 ; + + if((i = xl_init(dev))) { + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + dev->open=&xl_open; + dev->hard_start_xmit=&xl_xmit; + dev->change_mtu=&xl_change_mtu; + dev->stop=&xl_close; + dev->do_ioctl=NULL; + dev->set_multicast_list=&xl_set_rx_mode; + dev->get_stats=&xl_get_stats ; + dev->set_mac_address=&xl_set_mac_address ; + SET_MODULE_OWNER(dev); + + pci_set_drvdata(pdev,dev) ; + if ((i = register_netdev(dev))) { + printk(KERN_ERR "3C359, register netdev failed\n") ; + pci_set_drvdata(pdev,NULL) ; + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + printk(KERN_INFO "3C359: %s registered as: %s\n",xl_priv->xl_card_name,dev->name) ; + + return 0; +} + + +static int __init xl_init(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + printk(KERN_INFO "%s \n", version); + printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", + xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq); + + spin_lock_init(&xl_priv->xl_lock) ; + + return xl_hw_reset(dev) ; + +} + + +/* + * Hardware reset. This needs to be a separate entity as we need to reset the card + * when we change the EEProm settings. + */ + +static int xl_hw_reset(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + u16 i ; + u16 result_16 ; + u8 result_8 ; + u16 start ; + int j ; + + /* + * Reset the card. If the card has got the microcode on board, we have + * missed the initialization interrupt, so we must always do this. + */ + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL card not responding to global reset.\n", dev->name); + return -ENODEV; + } + } + + /* + * Enable pmbar by setting bit in CPAttention + */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_PMBARVIS ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Read cpHold bit in pmbar, if cleared we have got Flashrom on board. + * If not, we need to upload the microcode to the card + */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + +#if XL_DEBUG + printk(KERN_INFO "Read from PMBAR = %04x \n", readw(xl_mmio + MMIO_MACDATA)) ; +#endif + + if ( readw( (xl_mmio + MMIO_MACDATA)) & PMB_CPHOLD ) { + + /* Set PmBar, privateMemoryBase bits (8:2) to 0 */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~((0x7F) << 2) ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + /* Set CPAttention, memWrEn bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Now to write the microcode into the shared ram + * The microcode must finish at position 0xFFFF, so we must subtract + * to get the start position for the code + */ + + start = (0xFFFF - (mc_size) + 1 ) ; /* Looks strange but ensures compiler only uses 16 bit unsigned int for this */ + + printk(KERN_INFO "3C359: Uploading Microcode: "); + + for (i = start,j=0; (j < mc_size && i <= 0xffff) ; i++,j++) { + writel(MEM_BYTE_WRITE | 0XD0000 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[j],xl_mmio + MMIO_MACDATA) ; + if (j % 1024 == 0) + printk("."); + } + printk("\n") ; + + for (i=0;i < 16; i++) { + writel( (MEM_BYTE_WRITE | 0xDFFF0) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[mc_size - 16 + i], xl_mmio + MMIO_MACDATA) ; + } + + /* + * Have to write the start address of the upload to FFF4, but + * the address must be >> 4. You do not want to know how long + * it took me to discover this. + */ + + writel(MEM_WORD_WRITE | 0xDFFF4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(start >> 4, xl_mmio + MMIO_MACDATA); + + /* Clear the CPAttention, memWrEn Bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 & ~CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* Clear the cpHold bit in pmbar */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~PMB_CPHOLD ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + + } /* If microcode upload required */ + + /* + * The card should now go though a self test procedure and get itself ready + * to be opened, we must wait for an srb response with the initialization + * information. + */ + +#if XL_DEBUG + printk(KERN_INFO "%s: Microcode uploaded, must wait for the self test to complete\n", dev->name); +#endif + + writew(SETINDENABLE | 0xFFF, xl_mmio + MMIO_COMMAND) ; + + t=jiffies; + while ( !(readw(xl_mmio + MMIO_INTSTATUS_AUTO) & INTSTAT_SRB) ) { + schedule(); + if(jiffies-t > 15*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + return -ENODEV; + } + } + + /* + * Write the RxBufArea with D000, RxEarlyThresh, TxStartThresh, + * DnPriReqThresh, read the tech docs if you want to know what + * values they need to be. + */ + + writel(MMIO_WORD_WRITE | RXBUFAREA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0xD000, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_WORD_WRITE | RXEARLYTHRESH, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0X0020, xl_mmio + MMIO_MACDATA) ; + + writew( SETTXSTARTTHRESH | 0x40 , xl_mmio + MMIO_COMMAND) ; + + writeb(0x04, xl_mmio + MMIO_DNBURSTTHRESH) ; + writeb(0x04, xl_mmio + DNPRIREQTHRESH) ; + + /* + * Read WRBR to provide the location of the srb block, have to use byte reads not word reads. + * Tech docs have this wrong !!!! + */ + + writel(MMIO_BYTE_READ | WRBR, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MMIO_BYTE_READ | WRBR) + 1, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = xl_priv->srb | readb(xl_mmio + MMIO_MACDATA) ; + +#if XL_DEBUG + writel(IO_WORD_READ | SWITCHSETTINGS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if ( readw(xl_mmio + MMIO_MACDATA) & 2) { + printk(KERN_INFO "Default ring speed 4 mbps \n") ; + } else { + printk(KERN_INFO "Default ring speed 16 mbps \n") ; + } + printk(KERN_INFO "%s: xl_priv->srb = %04x\n",xl_priv->xl_card_name, xl_priv->srb); +#endif + + return 0; +} + +static int xl_open(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 i ; + u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ + int open_err ; + + u16 switchsettings, switchsettings_eeprom ; + + if(request_irq(dev->irq, &xl_interrupt, SA_SHIRQ , "3c359", dev)) { + return -EAGAIN; + } + + /* + * Read the information from the EEPROM that we need. I know we + * should use ntohs, but the word gets stored reversed in the 16 + * bit field anyway and it all works its self out when we memcpy + * it into dev->dev_addr. + */ + + hwaddr[0] = xl_ee_read(dev,0x10) ; + hwaddr[1] = xl_ee_read(dev,0x11) ; + hwaddr[2] = xl_ee_read(dev,0x12) ; + + /* Ring speed */ + + switchsettings_eeprom = xl_ee_read(dev,0x08) ; + switchsettings = switchsettings_eeprom ; + + if (xl_priv->xl_ring_speed != 0) { + if (xl_priv->xl_ring_speed == 4) + switchsettings = switchsettings | 0x02 ; + else + switchsettings = switchsettings & ~0x02 ; + } + + /* Only write EEProm if there has been a change */ + if (switchsettings != switchsettings_eeprom) { + xl_ee_write(dev,0x08,switchsettings) ; + /* Hardware reset after changing EEProm */ + xl_hw_reset(dev) ; + } + + memcpy(dev->dev_addr,hwaddr,dev->addr_len) ; + + open_err = xl_open_hw(dev) ; + + /* + * This really needs to be cleaned up with better error reporting. + */ + + if (open_err != 0) { /* Something went wrong with the open command */ + if (open_err & 0x07) { /* Wrong speed, retry at different speed */ + printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed \n", dev->name) ; + switchsettings = switchsettings ^ 2 ; + xl_ee_write(dev,0x08,switchsettings) ; + xl_hw_reset(dev) ; + open_err = xl_open_hw(dev) ; + if (open_err != 0) { + printk(KERN_WARNING "%s: Open error returned a second time, we're bombing out now\n", dev->name); + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } else { + printk(KERN_WARNING "%s: Open Error = %04x\n", dev->name, open_err) ; + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } + + /* + * Now to set up the Rx and Tx buffer structures + */ + /* These MUST be on 8 byte boundaries */ + xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; + memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; + memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; + + /* Setup Rx Ring */ + for (i=0 ; i < XL_RX_RING_SIZE ; i++) { + struct sk_buff *skb ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + if (skb==NULL) + break ; + + skb->dev = dev ; + xl_priv->xl_rx_ring[i].upfragaddr = pci_map_single(xl_priv->pdev, skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[i].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG; + xl_priv->rx_ring_skb[i] = skb ; + } + + if (i==0) { + printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; + free_irq(dev->irq,dev) ; + return -EIO ; + } + + xl_priv->rx_ring_no = i ; + xl_priv->rx_ring_tail = 0 ; + xl_priv->rx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_rx_ring, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_TODEVICE) ; + for (i=0;i<(xl_priv->rx_ring_no-1);i++) { + xl_priv->xl_rx_ring[i].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * (i+1)) ; + } + xl_priv->xl_rx_ring[i].upnextptr = 0 ; + + writel(xl_priv->rx_ring_dma_addr, xl_mmio + MMIO_UPLISTPTR) ; + + /* Setup Tx Ring */ + + xl_priv->tx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_tx_ring, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE,PCI_DMA_TODEVICE) ; + + xl_priv->tx_ring_head = 1 ; + xl_priv->tx_ring_tail = 255 ; /* Special marker for first packet */ + xl_priv->free_ring_entries = XL_TX_RING_SIZE ; + + /* + * Setup the first dummy DPD entry for polling to start working. + */ + + xl_priv->xl_tx_ring[0].framestartheader = TXDPDEMPTY ; + xl_priv->xl_tx_ring[0].buffer = 0 ; + xl_priv->xl_tx_ring[0].buffer_length = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + + writel(xl_priv->tx_ring_dma_addr, xl_mmio + MMIO_DNLISTPTR) ; + writel(DNUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(UPUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(DNENABLE, xl_mmio + MMIO_COMMAND) ; + writeb(0x40, xl_mmio + MMIO_DNPOLL) ; + + /* + * Enable interrupts on the card + */ + + writel(SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel(SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + netif_start_queue(dev) ; + return 0; + +} + +static int xl_open_hw(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 vsoff ; + char ver_str[33]; + int open_err ; + int i ; + unsigned long t ; + + /* + * Okay, let's build up the Open.NIC srb command + * + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(OPEN_NIC, xl_mmio + MMIO_MACDATA) ; + + /* + * Use this as a test byte, if it comes back with the same value, the command didn't work + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb)+ 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xff,xl_mmio + MMIO_MACDATA) ; + + /* Open options */ + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 9, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + + /* + * Node address, be careful here, the docs say you can just put zeros here and it will use + * the hardware address, it doesn't, you must include the node address in the open command. + */ + + if (xl_priv->xl_laa[0]) { /* If using a LAA address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_laa[i],xl_mmio + MMIO_MACDATA) ; + } + memcpy(dev->dev_addr,xl_priv->xl_laa,dev->addr_len) ; + } else { /* Regular hardware address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(dev->dev_addr[i-10], xl_mmio + MMIO_MACDATA) ; + } + } + + /* Default everything else to 0 */ + for (i = 16; i < 34; i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00,xl_mmio + MMIO_MACDATA) ; + } + + /* + * Set the csrb bit in the MISR register + */ + + xl_wait_misr_flags(dev) ; + writel(MEM_BYTE_WRITE | MF_CSRB, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB , xl_mmio + MMIO_MACDATA) ; + + /* + * Now wait for the command to run + */ + + t=jiffies; + while (! (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + + /* + * Let's interpret the open response + */ + + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb)+2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)!=0) { + open_err = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb) + 7, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + open_err |= readb(xl_mmio + MMIO_MACDATA) ; + return open_err ; + } else { + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->asb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(KERN_INFO "%s: Adapter Opened Details: ",dev->name) ; + printk("ASB: %04x",xl_priv->asb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 10, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + printk(", SRB: %04x",ntohs(readw(xl_mmio + MMIO_MACDATA)) ) ; + + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 12, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->arb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(", ARB: %04x \n",xl_priv->arb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 14, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + vsoff = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* + * Interesting, sending the individual characters directly to printk was causing klogd to use + * use 100% of processor time, so we build up the string and print that instead. + */ + + for (i=0;i<0x20;i++) { + writel( (MEM_BYTE_READ | 0xD0000 | vsoff) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ver_str[i] = readb(xl_mmio + MMIO_MACDATA) ; + } + ver_str[i] = '\0' ; + printk(KERN_INFO "%s: Microcode version String: %s \n",dev->name,ver_str); + } + + /* + * Issue the AckInterrupt + */ + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + return 0 ; +} + +/* + * There are two ways of implementing rx on the 359 NIC, either + * interrupt driven or polling. We are going to uses interrupts, + * it is the easier way of doing things. + * + * The Rx works with a ring of Rx descriptors. At initialise time the ring + * entries point to the next entry except for the last entry in the ring + * which points to 0. The card is programmed with the location of the first + * available descriptor and keeps reading the next_ptr until next_ptr is set + * to 0. Hopefully with a ring size of 16 the card will never get to read a next_ptr + * of 0. As the Rx interrupt is received we copy the frame up to the protocol layers + * and then point the end of the ring to our current position and point our current + * position to 0, therefore making the current position the last position on the ring. + * The last position on the ring therefore loops continually loops around the rx ring. + * + * rx_ring_tail is the position on the ring to process next. (Think of a snake, the head + * expands as the card adds new packets and we go around eating the tail processing the + * packets.) + * + * Undoubtably it could be streamlined and improved upon, but at the moment it works + * and the fast path through the routine is fine. + * + * adv_rx_ring could be inlined to increase performance, but its called a *lot* of times + * in xl_rx so would increase the size of the function significantly. + */ + +static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + int prev_ring_loc ; + + prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); + xl_priv->xl_rx_ring[prev_ring_loc].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * xl_priv->rx_ring_tail) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus = 0 ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upnextptr = 0 ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= (XL_RX_RING_SIZE-1) ; + + return ; +} + +static void xl_rx(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct sk_buff *skb, *skb2 ; + int frame_length = 0, copy_len = 0 ; + int temp_ring_loc ; + + /* + * Receive the next frame, loop around the ring until all frames + * have been received. + */ + + while (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & (RXUPDCOMPLETE | RXUPDFULL) ) { /* Descriptor to process */ + + if (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & RXUPDFULL ) { /* UpdFull, Multiple Descriptors used for the frame */ + + /* + * This is a pain, you need to go through all the descriptors until the last one + * for this frame to find the framelength + */ + + temp_ring_loc = xl_priv->rx_ring_tail ; + + while (xl_priv->xl_rx_ring[temp_ring_loc].framestatus & RXUPDFULL ) { + temp_ring_loc++ ; + temp_ring_loc &= (XL_RX_RING_SIZE-1) ; + } + + frame_length = xl_priv->xl_rx_ring[temp_ring_loc].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(frame_length) ; + + if (skb==NULL) { /* No memory for frame, still need to roll forward the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed - multi buffer !\n", dev->name) ; + while (xl_priv->rx_ring_tail != temp_ring_loc) + adv_rx_ring(dev) ; + + adv_rx_ring(dev) ; /* One more time just for luck :) */ + xl_priv->xl_stats.rx_dropped++ ; + + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + while (xl_priv->rx_ring_tail != temp_ring_loc) { + copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; + frame_length -= copy_len ; + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; + adv_rx_ring(dev) ; + } + + /* Now we have found the last fragment */ + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; +/* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ + adv_rx_ring(dev) ; + skb->protocol = tr_type_trans(skb,dev) ; + netif_rx(skb) ; + + } else { /* Single Descriptor Used, simply swap buffers over, fast path */ + + frame_length = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + + if (skb==NULL) { /* Still need to fix the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_dropped++ ; + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; + pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + skb_put(skb2, frame_length) ; + skb2->protocol = tr_type_trans(skb2,dev) ; + + xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] = skb ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_packets++ ; + xl_priv->xl_stats.rx_bytes += frame_length ; + + netif_rx(skb2) ; + } /* if multiple buffers */ + dev->last_rx = jiffies ; + } /* while packet to do */ + + /* Clear the updComplete interrupt */ + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * This is ruthless, it doesn't care what state the card is in it will + * completely reset the adapter. + */ + +static void xl_reset(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t; + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + +} + +static void xl_freemem(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv ; + int i ; + + for (i=0;irx_ring_skb[xl_priv->rx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= XL_RX_RING_SIZE-1; + } + + /* unmap ring */ + pci_unmap_single(xl_priv->pdev,xl_priv->rx_ring_dma_addr, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_FROMDEVICE) ; + + pci_unmap_single(xl_priv->pdev,xl_priv->tx_ring_dma_addr, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE, PCI_DMA_TODEVICE) ; + + kfree(xl_priv->xl_rx_ring) ; + kfree(xl_priv->xl_tx_ring) ; + + return ; +} + +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct xl_private *xl_priv =(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 intstatus, macstatus ; + + if (!dev) { + printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; + return ; + } + + intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; + + if (!(intstatus & 1)) /* We didn't generate the interrupt */ + return ; + + spin_lock(&xl_priv->xl_lock) ; + + /* + * Process the interrupt + */ + /* + * Something fishy going on here, we shouldn't get 0001 ints, not fatal though. + */ + if (intstatus == 0x0001) { + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + printk(KERN_INFO "%s: 00001 int received \n",dev->name) ; + } else { + if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { + + /* + * Host Error. + * It may be possible to recover from this, but usually it means something + * is seriously fubar, so we just close the adapter. + */ + + if (intstatus & HOSTERRINT) { + printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x \n",dev->name,intstatus) ; + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } /* Host Error */ + + if (intstatus & SRBRINT ) { /* Srbc interrupt */ + writel(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + if (xl_priv->srb_queued) + xl_srb_bh(dev) ; + } /* SRBR Interrupt */ + + if (intstatus & TXUNDERRUN) { /* Issue DnReset command */ + writel(DNRESET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { /* Wait for command to run */ + /* !!! FIX-ME !!!! + Must put a timeout check here ! */ + /* Empty Loop */ + } + printk(KERN_WARNING "%s: TX Underrun received \n",dev->name) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } /* TxUnderRun */ + + if (intstatus & ARBCINT ) { /* Arbc interrupt */ + xl_arb_cmd(dev) ; + } /* Arbc */ + + if (intstatus & ASBFINT) { + if (xl_priv->asb_queued == 1) { + xl_asb_cmd(dev) ; + } else if (xl_priv->asb_queued == 2) { + xl_asb_bh(dev) ; + } else { + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + } + } /* Asbf */ + + if (intstatus & UPCOMPINT ) /* UpComplete */ + xl_rx(dev) ; + + if (intstatus & DNCOMPINT ) /* DnComplete */ + xl_dn_comp(dev) ; + + if (intstatus & HARDERRINT ) { /* Hardware error */ + writel(MMIO_WORD_READ | MACSTATUS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + macstatus = readw(xl_mmio + MMIO_MACDATA) ; + printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name); + if (macstatus & (1<<14)) + printk(KERN_WARNING "tchk error: Unrecoverable error \n") ; + if (macstatus & (1<<3)) + printk(KERN_WARNING "eint error: Internal watchdog timer expired \n") ; + if (macstatus & (1<<2)) + printk(KERN_WARNING "aint error: Host tried to perform illegal operation \n") ; + printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + unregister_trdev(dev) ; + kfree(dev) ; + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } + } else { + printk(KERN_WARNING "%s: Received Unknown interrupt : %04x \n", dev->name, intstatus) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } + } + + /* Turn interrupts back on */ + + writel( SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel( SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + spin_unlock(&xl_priv->xl_lock) ; +} + +/* + * Tx - Polling configuration + */ + +static int xl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_tx_desc *txd ; + int tx_head, tx_tail, tx_prev ; + unsigned long flags ; + + spin_lock_irqsave(&xl_priv->xl_lock,flags) ; + + netif_stop_queue(dev) ; + + if (xl_priv->free_ring_entries > 1 ) { + /* + * Set up the descriptor for the packet + */ + tx_head = xl_priv->tx_ring_head ; + tx_tail = xl_priv->tx_ring_tail ; + + txd = &(xl_priv->xl_tx_ring[tx_head]) ; + txd->dnnextptr = 0 ; + txd->framestartheader = skb->len | TXDNINDICATE ; + txd->buffer = pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE) ; + txd->buffer_length = skb->len | TXDNFRAGLAST ; + xl_priv->tx_ring_skb[tx_head] = skb ; + xl_priv->xl_stats.tx_packets++ ; + xl_priv->xl_stats.tx_bytes += skb->len ; + + /* + * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 + * to ensure no negative numbers in unsigned locations. + */ + + tx_prev = (xl_priv->tx_ring_head + XL_TX_RING_SIZE - 1) & (XL_TX_RING_SIZE - 1) ; + + xl_priv->tx_ring_head++ ; + xl_priv->tx_ring_head &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries-- ; + + xl_priv->xl_tx_ring[tx_prev].dnnextptr = xl_priv->tx_ring_dma_addr + (sizeof (struct xl_tx_desc) * tx_head) ; + + /* Sneaky, by doing a read on DnListPtr we can force the card to poll on the DnNextPtr */ + /* readl(xl_mmio + MMIO_DNLISTPTR) ; */ + + netif_wake_queue(dev) ; + + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + + return 0; + } else { + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + return 1; + } + +} + +/* + * The NIC has told us that a packet has been downloaded onto the card, we must + * find out which packet it has done, clear the skb and information for the packet + * then advance around the ring for all tranmitted packets + */ + +static void xl_dn_comp(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct xl_tx_desc *txd ; + + + if (xl_priv->tx_ring_tail == 255) {/* First time */ + xl_priv->xl_tx_ring[0].framestartheader = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + xl_priv->tx_ring_tail = 1 ; + } + + while (xl_priv->xl_tx_ring[xl_priv->tx_ring_tail].framestartheader & TXDNCOMPLETE ) { + txd = &(xl_priv->xl_tx_ring[xl_priv->tx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,txd->buffer, xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]->len, PCI_DMA_TODEVICE) ; + txd->framestartheader = 0 ; + txd->buffer = 0xdeadbeef ; + txd->buffer_length = 0 ; + dev_kfree_skb_irq(xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]) ; + xl_priv->tx_ring_tail++ ; + xl_priv->tx_ring_tail &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries++ ; + } + + netif_wake_queue(dev) ; + + writel(ACK_INTERRUPT | DNCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; +} + +/* + * Close the adapter properly. + * This srb reply cannot be handled from interrupt context as we have + * to free the interrupt from the driver. + */ + +static int xl_close(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + + netif_stop_queue(dev) ; + + /* + * Close the adapter, need to stall the rx and tx queues. + */ + + writew(DNSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNSTALL not responding.\n", dev->name); + break ; + } + } + writew(DNDISABLE, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNDISABLE not responding.\n", dev->name); + break ; + } + } + writew(UPSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPSTALL not responding.\n", dev->name); + break ; + } + } + + /* Turn off interrupts, we will still get the indication though + * so we can trap it + */ + + writel(SETINTENABLE, xl_mmio + MMIO_COMMAND) ; + + xl_srb_cmd(dev,CLOSE_NIC) ; + + t=jiffies; + while (!(readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-CLOSENIC not responding.\n", dev->name); + break ; + } + } + /* Read the srb response from the adapter */ + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD); + if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { + printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response \n",dev->name) ; + } else { + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)==0) { + printk(KERN_INFO "%s: Adapter has been closed \n",dev->name) ; + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + xl_freemem(dev) ; + free_irq(dev->irq,dev) ; + } else { + printk(KERN_INFO "%s: Close nic command returned error code %02x\n",dev->name, readb(xl_mmio + MMIO_MACDATA)) ; + } + } + + /* Reset the upload and download logic */ + + writew(UPRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPRESET not responding.\n", dev->name); + break ; + } + } + writew(DNRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNRESET not responding.\n", dev->name); + break ; + } + } + xl_hw_reset(dev) ; + return 0 ; +} + +static void xl_set_rx_mode(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct dev_mc_list *dmi ; + unsigned char dev_mc_address[4] ; + u16 options ; + int i ; + + if (dev->flags & IFF_PROMISC) + options = 0x0004 ; + else + options = 0x0000 ; + + if (options ^ xl_priv->xl_copy_all_options) { /* Changed, must send command */ + xl_priv->xl_copy_all_options = options ; + xl_srb_cmd(dev, SET_RECEIVE_MODE) ; + return ; + } + + dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; + + for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + dev_mc_address[0] |= dmi->dmi_addr[2] ; + dev_mc_address[1] |= dmi->dmi_addr[3] ; + dev_mc_address[2] |= dmi->dmi_addr[4] ; + dev_mc_address[3] |= dmi->dmi_addr[5] ; + } + + if (memcmp(xl_priv->xl_functional_addr,dev_mc_address,4) != 0) { /* Options have changed, run the command */ + memcpy(xl_priv->xl_functional_addr, dev_mc_address,4) ; + xl_srb_cmd(dev, SET_FUNC_ADDRESS) ; + } + return ; +} + + +/* + * We issued an srb command and now we must read + * the response from the completed command. + */ + +static void xl_srb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 srb_cmd, ret_code ; + int i ; + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + srb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + + /* Ret_code is standard across all commands */ + + switch (ret_code) { + case 1: + printk(KERN_INFO "%s: Command: %d - Invalid Command code\n",dev->name,srb_cmd) ; + break ; + case 4: + printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command \n",dev->name,srb_cmd) ; + break ; + + case 6: + printk(KERN_INFO "%s: Command: %d - Options Invalid for command \n",dev->name,srb_cmd) ; + break ; + + case 0: /* Successful command execution */ + switch (srb_cmd) { + case READ_LOG: /* Returns 14 bytes of data from the NIC */ + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: READ.LOG 14 bytes of data ",dev->name) ; + /* + * We still have to read the log even if message_level = 0 and we don't want + * to see it + */ + for (i=0;i<14;i++) { + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if(xl_priv->xl_message_level) + printk("%02x:",readb(xl_mmio + MMIO_MACDATA)) ; + } + printk("\n") ; + break ; + case SET_FUNC_ADDRESS: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Functional Address Set \n",dev->name) ; + break ; + case CLOSE_NIC: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler \n",dev->name) ; + break ; + case SET_MULTICAST_MODE: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Multicast options successfully changed\n",dev->name) ; + break ; + case SET_RECEIVE_MODE: + if(xl_priv->xl_message_level) { + if (xl_priv->xl_copy_all_options == 0x0004) + printk(KERN_INFO "%s: Entering promiscuous mode \n", dev->name) ; + else + printk(KERN_INFO "%s: Entering normal receive mode \n",dev->name) ; + } + break ; + + } /* switch */ + break ; + } /* switch */ + return ; +} + +static struct net_device_stats * xl_get_stats(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + return (struct net_device_stats *) &xl_priv->xl_stats; +} + +static int xl_set_mac_address (struct net_device *dev, void *addr) +{ + struct sockaddr *saddr = addr ; + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + if (netif_running(dev)) { + printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; + return -EIO ; + } + + memcpy(xl_priv->xl_laa, saddr->sa_data,dev->addr_len) ; + + if (xl_priv->xl_message_level) { + printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, xl_priv->xl_laa[0], + xl_priv->xl_laa[1], xl_priv->xl_laa[2], + xl_priv->xl_laa[3], xl_priv->xl_laa[4], + xl_priv->xl_laa[5]); + } + + return 0 ; +} + +static void xl_arb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 arb_cmd ; + u16 lan_status, lan_status_diff ; + + writel( ( MEM_BYTE_READ | 0xD0000 | xl_priv->arb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + arb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + + if (arb_cmd == RING_STATUS_CHANGE) { /* Ring.Status.Change */ + writel( ( (MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + + printk(KERN_INFO "%s: Ring Status Change: New Status = %04x\n", dev->name, ntohs(readw(xl_mmio + MMIO_MACDATA) )) ; + + lan_status = ntohs(readw(xl_mmio + MMIO_MACDATA)); + + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + lan_status_diff = xl_priv->xl_lan_status ^ lan_status ; + + if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { + if (lan_status_diff & LSC_LWF) + printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); + if (lan_status_diff & LSC_ARW) + printk(KERN_WARNING "%s: Auto removal error\n",dev->name); + if (lan_status_diff & LSC_FPE) + printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); + if (lan_status_diff & LSC_RR) + printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); + + /* Adapter has been closed by the hardware */ + + netif_stop_queue(dev); + xl_freemem(dev) ; + free_irq(dev->irq,dev); + + printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; + } /* If serious error */ + + if (xl_priv->xl_message_level) { + if (lan_status_diff & LSC_SIG_LOSS) + printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; + if (lan_status_diff & LSC_HARD_ERR) + printk(KERN_INFO "%s: Beaconing \n",dev->name); + if (lan_status_diff & LSC_SOFT_ERR) + printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name); + if (lan_status_diff & LSC_TRAN_BCN) + printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + if (lan_status_diff & LSC_SS) + printk(KERN_INFO "%s: Single Station on the ring \n", dev->name); + if (lan_status_diff & LSC_RING_REC) + printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); + if (lan_status_diff & LSC_FDX_MODE) + printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); + } + + if (lan_status_diff & LSC_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Counter Overflow \n", dev->name); + /* Issue READ.LOG command */ + xl_srb_cmd(dev, READ_LOG) ; + } + + /* There is no command in the tech docs to issue the read_sr_counters */ + if (lan_status_diff & LSC_SR_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); + } + + xl_priv->xl_lan_status = lan_status ; + + } /* Lan.change.status */ + else if ( arb_cmd == RECEIVE_DATA) { /* Received.Data */ +#if XL_DEBUG + printk(KERN_INFO "Received.Data \n") ; +#endif + writel( ((MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->mac_buffer = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* Now we are going to be really basic here and not do anything + * with the data at all. The tech docs do not give me enough + * information to calculate the buffers properly so we're + * just going to tell the nic that we've dealt with the frame + * anyway. + */ + + dev->last_rx = jiffies ; + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + /* Is the ASB free ? */ + + xl_priv->asb_queued = 0 ; + writel( ((MEM_BYTE_READ | 0xD0000 | xl_priv->asb) + 2), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0xff) { + xl_priv->asb_queued = 1 ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_ASBFR, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_ASBFR, xl_mmio + MMIO_MACDATA) ; + return ; + /* Drop out and wait for the bottom half to be run */ + } + + xl_asb_cmd(dev) ; + + } else { + printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x \n",dev->name,arb_cmd) ; + } + + /* Acknowledge the arb interrupt */ + + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + + return ; +} + + +/* + * There is only one asb command, but we can get called from different + * places. + */ + +static void xl_asb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + if (xl_priv->asb_queued == 1) + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + + writel(MEM_BYTE_WRITE | 0xd0000 | xl_priv->asb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x81, xl_mmio + MMIO_MACDATA) ; + + writel(MEM_WORD_WRITE | 0xd0000 | xl_priv->asb | 6, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ntohs(xl_priv->mac_buffer), xl_mmio + MMIO_MACDATA) ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_RASB, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_RASB, xl_mmio + MMIO_MACDATA) ; + + xl_priv->asb_queued = 2 ; + + return ; +} + +/* + * This will only get called if there was an error + * from the asb cmd. + */ +static void xl_asb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 ret_code ; + + writel(MMIO_BYTE_READ | 0xd0000 | xl_priv->asb | 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + switch (ret_code) { + case 0x01: + printk(KERN_INFO "%s: ASB Command, unrecognized command code \n",dev->name) ; + break ; + case 0x26: + printk(KERN_INFO "%s: ASB Command, unexpected receive buffer \n", dev->name) ; + break ; + case 0x40: + printk(KERN_INFO "%s: ASB Command, Invalid Station ID \n", dev->name) ; + break ; + } + xl_priv->asb_queued = 0 ; + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * Issue srb commands to the nic + */ + +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + switch (srb_cmd) { + case READ_LOG: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(READ_LOG, xl_mmio + MMIO_MACDATA) ; + break; + + case CLOSE_NIC: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(CLOSE_NIC, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_RECEIVE_MODE: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_RECEIVE_MODE, xl_mmio + MMIO_MACDATA) ; + writel(MEM_WORD_WRITE | 0xD0000 | xl_priv->srb | 4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(xl_priv->xl_copy_all_options, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_FUNC_ADDRESS: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_FUNC_ADDRESS, xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 6 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[0], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 7 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[1], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 8 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[2], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 9 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[3], xl_mmio + MMIO_MACDATA) ; + break ; + } /* switch */ + + + xl_wait_misr_flags(dev) ; + + /* Write 0xff to the CSRB flag */ + writel(MEM_BYTE_WRITE | MF_CSRB , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + /* Set csrb bit in MISR register to process command */ + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB, xl_mmio + MMIO_MACDATA) ; + xl_priv->srb_queued = 1 ; + + return ; +} + +/* + * This is nasty, to use the MISR command you have to wait for 6 memory locations + * to be zero. This is the way the driver does on other OS'es so we should be ok with + * the empty loop. + */ + +static void xl_wait_misr_flags(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + int i ; + + writel(MMIO_BYTE_READ | MISR_RW, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0) { /* Misr not clear */ + for (i=0; i<6; i++) { + writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readb(xl_mmio + MMIO_MACDATA) != 0 ) {} ; /* Empty Loop */ + } + } + + writel(MMIO_BYTE_WRITE | MISR_AND, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x80, xl_mmio + MMIO_MACDATA) ; + + return ; +} + +/* + * Change mtu size, this should work the same as olympic + */ + +static int xl_change_mtu(struct net_device *dev, int mtu) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u16 max_mtu ; + + if (xl_priv->xl_ring_speed == 4) + max_mtu = 4500 ; + else + max_mtu = 18000 ; + + if (mtu > max_mtu) + return -EINVAL ; + if (mtu < 100) + return -EINVAL ; + + dev->mtu = mtu ; + xl_priv->pkt_buf_sz = mtu + TR_HLEN ; + + return 0 ; +} + +static void __devexit xl_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + + unregister_trdev(dev); + iounmap(xl_priv->xl_mmio) ; + pci_release_regions(pdev) ; + pci_set_drvdata(pdev,NULL) ; + kfree(dev); + return ; +} + +static struct pci_driver xl_3c359_driver = { + name: "3c359", + id_table: xl_pci_tbl, + probe: xl_probe, + remove: __devexit_p(xl_remove_one), +}; + +static int __init xl_pci_init (void) +{ + return pci_module_init (&xl_3c359_driver); +} + + +static void __exit xl_pci_cleanup (void) +{ + pci_unregister_driver (&xl_3c359_driver); +} + +module_init(xl_pci_init); +module_exit(xl_pci_cleanup); + +MODULE_LICENSE("GPL") ; diff -urN linux-2.4.18/drivers/net/tokenring/3c359.h linux-2.4.19-pre5/drivers/net/tokenring/3c359.h --- linux-2.4.18/drivers/net/tokenring/3c359.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tokenring/3c359.h Sat Mar 30 22:55:28 2002 @@ -0,0 +1,294 @@ +/* + * 3c359.h (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3C359 Token Link PCI XL cards. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License Version 2 or (at your option) + * any later verion, incorporated herein by reference. + */ + +#ifndef PCI_DEVICE_ID_3COM_3C359 +#define PCI_DEVICE_ID_3COM_3C359 0x3590 +#endif + +/* Memory Access Commands */ +#define IO_BYTE_READ 0x28 << 24 +#define IO_BYTE_WRITE 0x18 << 24 +#define IO_WORD_READ 0x20 << 24 +#define IO_WORD_WRITE 0x10 << 24 +#define MMIO_BYTE_READ 0x88 << 24 +#define MMIO_BYTE_WRITE 0x48 << 24 +#define MMIO_WORD_READ 0x80 << 24 +#define MMIO_WORD_WRITE 0x40 << 24 +#define MEM_BYTE_READ 0x8C << 24 +#define MEM_BYTE_WRITE 0x4C << 24 +#define MEM_WORD_READ 0x84 << 24 +#define MEM_WORD_WRITE 0x44 << 24 + +#define PMBAR 0x1C80 +#define PMB_CPHOLD (1<<10) + +#define CPATTENTION 0x180D +#define CPA_PMBARVIS (1<<7) +#define CPA_MEMWREN (1<<6) + +#define SWITCHSETTINGS 0x1C88 +#define EECONTROL 0x1C8A +#define EEDATA 0x1C8C +#define EEREAD 0x0080 +#define EEWRITE 0x0040 +#define EEERASE 0x0060 +#define EE_ENABLE_WRITE 0x0030 +#define EEBUSY (1<<15) + +#define WRBR 0xCDE02 +#define WWOR 0xCDE04 +#define WWCR 0xCDE06 +#define MACSTATUS 0xCDE08 +#define MISR_RW 0xCDE0B +#define MISR_AND 0xCDE2B +#define MISR_SET 0xCDE4B +#define RXBUFAREA 0xCDE10 +#define RXEARLYTHRESH 0xCDE12 +#define TXSTARTTHRESH 0x58 +#define DNPRIREQTHRESH 0x2C + +#define MISR_CSRB (1<<5) +#define MISR_RASB (1<<4) +#define MISR_SRBFR (1<<3) +#define MISR_ASBFR (1<<2) +#define MISR_ARBF (1<<1) + +/* MISR Flags memory locations */ +#define MF_SSBF 0xDFFE0 +#define MF_ARBF 0xDFFE1 +#define MF_ASBFR 0xDFFE2 +#define MF_SRBFR 0xDFFE3 +#define MF_RASB 0xDFFE4 +#define MF_CSRB 0xDFFE5 + +#define MMIO_MACDATA 0x10 +#define MMIO_MAC_ACCESS_CMD 0x14 +#define MMIO_TIMER 0x1A +#define MMIO_DMA_CTRL 0x20 +#define MMIO_DNLISTPTR 0x24 +#define MMIO_HASHFILTER 0x28 +#define MMIO_CONFIG 0x29 +#define MMIO_DNPRIREQTHRESH 0x2C +#define MMIO_DNPOLL 0x2D +#define MMIO_UPPKTSTATUS 0x30 +#define MMIO_FREETIMER 0x34 +#define MMIO_COUNTDOWN 0x36 +#define MMIO_UPLISTPTR 0x38 +#define MMIO_UPPOLL 0x3C +#define MMIO_UPBURSTTHRESH 0x40 +#define MMIO_DNBURSTTHRESH 0x41 +#define MMIO_INTSTATUS_AUTO 0x56 +#define MMIO_TXSTARTTHRESH 0x58 +#define MMIO_INTERRUPTENABLE 0x5A +#define MMIO_INDICATIONENABLE 0x5C +#define MMIO_COMMAND 0x5E /* These two are meant to be the same */ +#define MMIO_INTSTATUS 0x5E /* Makes the code more readable this way */ +#define INTSTAT_CMD_IN_PROGRESS (1<<12) +#define INTSTAT_SRB (1<<14) +#define INTSTAT_INTLATCH (1<<0) + +/* Indication / Interrupt Mask + * Annoyingly the bits to be set in the indication and interrupt enable + * do not match with the actual bits received in the interrupt, although + * they are in the same order. + * The mapping for the indication / interrupt are: + * Bit Indication / Interrupt + * 0 HostError + * 1 txcomplete + * 2 updneeded + * 3 rxcomplete + * 4 intrequested + * 5 macerror + * 6 dncomplete + * 7 upcomplete + * 8 txunderrun + * 9 asbf + * 10 srbr + * 11 arbc + * + * The only ones we don't want to receive are txcomplete and rxcomplete + * we use dncomplete and upcomplete instead. + */ + +#define INT_MASK 0xFF5 + +/* Note the subtle difference here, IND and INT */ + +#define SETINDENABLE (8<<12) +#define SETINTENABLE (7<<12) +#define SRBBIT (1<<10) +#define ASBBIT (1<<9) +#define ARBBIT (1<<11) + +#define SRB 0xDFE90 +#define ASB 0xDFED0 +#define ARB 0xD0000 +#define SCRATCH 0xDFEF0 + +#define INT_REQUEST 0x6000 /* (6 << 12) */ +#define ACK_INTERRUPT 0x6800 /* (13 <<11) */ +#define GLOBAL_RESET 0x00 +#define DNDISABLE 0x5000 +#define DNENABLE 0x4800 +#define DNSTALL 0x3002 +#define DNRESET 0x5800 +#define DNUNSTALL 0x3003 +#define UPRESET 0x2800 +#define UPSTALL 0x3000 +#define UPUNSTALL 0x3001 +#define SETCONFIG 0x4000 +#define SETTXSTARTTHRESH 0x9800 + +/* Received Interrupts */ +#define ASBFINT (1<<13) +#define SRBRINT (1<<14) +#define ARBCINT (1<<15) +#define TXUNDERRUN (1<<11) + +#define UPCOMPINT (1<<10) +#define DNCOMPINT (1<<9) +#define HARDERRINT (1<<7) +#define RXCOMPLETE (1<<4) +#define TXCOMPINT (1<<2) +#define HOSTERRINT (1<<1) + +/* Receive descriptor bits */ +#define RXOVERRUN (1<<19) +#define RXFC (1<<21) +#define RXAR (1<<22) +#define RXUPDCOMPLETE (1<<23) +#define RXUPDFULL (1<<24) +#define RXUPLASTFRAG (1<<31) + +/* Transmit descriptor bits */ +#define TXDNCOMPLETE (1<<16) +#define TXTXINDICATE (1<<27) +#define TXDPDEMPTY (1<<29) +#define TXDNINDICATE (1<<31) +#define TXDNFRAGLAST (1<<31) + +/* Interrupts to Acknowledge */ +#define LATCH_ACK 1 +#define TXCOMPACK (1<<1) +#define INTREQACK (1<<2) +#define DNCOMPACK (1<<3) +#define UPCOMPACK (1<<4) +#define ASBFACK (1<<5) +#define SRBRACK (1<<6) +#define ARBCACK (1<<7) + +#define XL_IO_SPACE 128 +#define SRB_COMMAND_SIZE 50 + +/* Adapter Commands */ +#define REQUEST_INT 0x00 +#define MODIFY_OPEN_PARMS 0x01 +#define RESTORE_OPEN_PARMS 0x02 +#define OPEN_NIC 0x03 +#define CLOSE_NIC 0x04 +#define SET_SLEEP_MODE 0x05 +#define SET_GROUP_ADDRESS 0x06 +#define SET_FUNC_ADDRESS 0x07 +#define READ_LOG 0x08 +#define SET_MULTICAST_MODE 0x0C +#define CHANGE_WAKEUP_PATTERN 0x0D +#define GET_STATISTICS 0x13 +#define SET_RECEIVE_MODE 0x1F + +/* ARB Commands */ +#define RECEIVE_DATA 0x81 +#define RING_STATUS_CHANGE 0x84 + +/* ASB Commands */ +#define ASB_RECEIVE_DATE 0x81 + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +#define XL_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* 3c359 defaults for buffers */ + +#define XL_RX_RING_SIZE 16 /* must be a power of 2 */ +#define XL_TX_RING_SIZE 16 /* must be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* 3c359 data structures */ + +struct xl_tx_desc { + u32 dnnextptr ; + u32 framestartheader ; + u32 buffer ; + u32 buffer_length ; +}; + +struct xl_rx_desc { + u32 upnextptr ; + u32 framestatus ; + u32 upfragaddr ; + u32 upfraglen ; +}; + +struct xl_private { + + + /* These two structures must be aligned on 8 byte boundaries */ + + /* struct xl_rx_desc xl_rx_ring[XL_RX_RING_SIZE]; */ + /* struct xl_tx_desc xl_tx_ring[XL_TX_RING_SIZE]; */ + struct xl_rx_desc *xl_rx_ring ; + struct xl_tx_desc *xl_tx_ring ; + struct sk_buff *tx_ring_skb[XL_TX_RING_SIZE], *rx_ring_skb[XL_RX_RING_SIZE]; + int tx_ring_head, tx_ring_tail ; + int rx_ring_tail, rx_ring_no ; + int free_ring_entries ; + + u16 srb; + u16 arb; + u16 asb; + + u8 *xl_mmio; + char *xl_card_name; + struct pci_dev *pdev ; + + spinlock_t xl_lock ; + + volatile int srb_queued; + struct wait_queue *srb_wait; + volatile int asb_queued; + + struct net_device_stats xl_stats ; + + u16 mac_buffer ; + u16 xl_lan_status ; + u8 xl_ring_speed ; + u16 pkt_buf_sz ; + u8 xl_message_level; + u16 xl_copy_all_options ; + unsigned char xl_functional_addr[4] ; + u16 xl_addr_table_addr, xl_parms_addr ; + u8 xl_laa[6] ; + u32 rx_ring_dma_addr ; + u32 tx_ring_dma_addr ; +}; + diff -urN linux-2.4.18/drivers/net/tokenring/3c359_microcode.h linux-2.4.19-pre5/drivers/net/tokenring/3c359_microcode.h --- linux-2.4.18/drivers/net/tokenring/3c359_microcode.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/tokenring/3c359_microcode.h Sat Mar 30 22:55:28 2002 @@ -0,0 +1,1585 @@ + +/* + * The firmware this driver downloads into the tokenring card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * This firmware is licensed to you strictly for use in conjunction + * with the use of 3Com 3C359 TokenRing adapters. There is no + * waranty expressed or implied about its fitness for any purpose. + */ + +/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode. + * + * Notes: + * - Loaded from xl_init upon adapter initialization. + * + * Available from 3Com as part of their standard 3C359 driver. + * + * mc_size *must* must match the microcode being used, each version is a + * different length. + */ + + +#if defined(CONFIG_3C359) || defined(CONFIG_3C359_MODULE) + +static int mc_size = 24880 ; + +u8 microcode[] = { + 0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x33,0x2f,0x30,0x32,0x2f,0x39,0x39,0x20,0x31 +,0x37,0x3a,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 +,0x00,0x00,0x07,0xff,0x02,0x00,0xfe,0x9f,0x06,0x00,0x00,0x7c,0x48,0x00,0x00,0x70 +,0x82,0x00,0xff,0xff,0x86,0x00,0xff,0xff,0x88,0x00,0xff,0xff,0x9a,0x00,0xff,0xff +,0xff,0xff,0x11,0x00,0xc0,0x00,0xff,0xff,0xff,0xff,0x11,0x22,0x33,0x44,0x55,0x66 +,0x33,0x43,0x4f,0x4d,0x20,0x42,0x41,0x42,0x45,0x11,0x40,0xc0,0x00,0xff,0xff,0xff +,0xff,0x11,0x22,0x33,0x44,0x55,0x66,0x53,0x74,0x61,0x72,0x74,0x20,0x6f,0x66,0x20 +,0x4c,0x4c,0x43,0x20,0x66,0x72,0x61,0x6d,0x65,0x2e,0x20,0x20,0x54,0x6f,0x74,0x61 +,0x6c,0x20,0x64,0x61,0x74,0x61,0x20,0x73,0x69,0x7a,0x65,0x20,0x69,0x73,0x20,0x78 +,0x78,0x78,0x20,0x20,0x20,0x42,0x41,0x42,0x45,0xe8,0xd2,0x01,0x83,0x3e,0xf7,0x34 +,0x00,0x75,0x21,0xe8,0x41,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75,0x17,0xe8,0x82,0x00 +,0x83,0x3e,0xf7,0x34,0x00,0x75,0x0d,0xe8,0xbf,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75 +,0x03,0xe8,0x41,0x02,0xc3,0x1e,0xb8,0x00,0xf0,0x8e,0xd8,0x33,0xf6,0xb9,0x00,0x80 +,0x33,0xdb,0xad,0x03,0xd8,0xe2,0xfb,0x1f,0xb8,0x00,0x00,0x83,0xfb,0x00,0x74,0x03 +,0xb8,0x22,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x56,0x00,0xb0,0xff,0xee,0x33,0xc0 +,0x8e,0xc0,0x33,0xf6,0xb9,0xff,0x7f,0x83,0x3e,0xff,0x34,0x00,0x74,0x08,0x8d,0x3e +,0x30,0x61,0xd1,0xef,0x2b,0xcf,0x26,0x8b,0x1c,0x26,0xc7,0x04,0xff,0xff,0x26,0x83 +,0x3c,0xff,0x75,0x17,0x26,0xc7,0x04,0x00,0x00,0x26,0x83,0x3c,0x00,0x75,0x0c,0x26 +,0x89,0x1c,0x46,0x46,0xe2,0xe0,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x24,0x00,0xa3,0xf7 +,0x34,0xc3,0xfa,0xb4,0xd7,0x9e,0x73,0x3a,0x75,0x38,0x79,0x36,0x7b,0x34,0x9f,0xb1 +,0x05,0xd2,0xec,0x73,0x2d,0xb0,0x40,0xd0,0xe0,0x71,0x27,0x79,0x25,0xd0,0xe0,0x73 +,0x21,0x7b,0x1f,0x32,0xc0,0x75,0x1b,0x32,0xe4,0x9e,0x72,0x16,0x74,0x14,0x78,0x12 +,0x7a,0x10,0x9f,0xd2,0xec,0x72,0x0b,0xd0,0xe4,0x70,0x07,0x75,0x05,0xb8,0x00,0x00 +,0xeb,0x03,0xb8,0x26,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x5a,0x00,0x33,0xc0,0xef +,0xef,0xef,0xef,0xb0,0x00,0xe6,0x56,0xb0,0x00,0xe6,0x54,0xba,0x52,0x00,0xb8,0x01 +,0x01,0xef,0xe8,0xca,0x00,0x3c,0x01,0x75,0x7f,0xe8,0x83,0x00,0xba,0x52,0x00,0xb8 +,0x02,0x02,0xef,0xe8,0xb9,0x00,0x3c,0x02,0x75,0x6e,0xe8,0x7a,0x00,0xba,0x52,0x00 +,0xb8,0x04,0x04,0xef,0xe8,0xa8,0x00,0x3c,0x04,0x75,0x5d,0xe8,0x71,0x00,0xba,0x52 +,0x00,0xb8,0x08,0x08,0xef,0xe8,0x97,0x00,0x3c,0x08,0x75,0x4c,0xe8,0x68,0x00,0xba +,0x52,0x00,0xb8,0x10,0x10,0xef,0xe8,0x86,0x00,0x3c,0x10,0x75,0x3b,0xe8,0x5f,0x00 +,0xba,0x52,0x00,0xb8,0x20,0x20,0xef,0xe8,0x75,0x00,0x3c,0x20,0x75,0x2a,0xe8,0x56 +,0x00,0xba,0x52,0x00,0xb8,0x40,0x40,0xef,0xe8,0x64,0x00,0x3c,0x40,0x75,0x19,0xe8 +,0x4d,0x00,0xba,0x52,0x00,0xb8,0x80,0x80,0xef,0xe8,0x53,0x00,0x3c,0x80,0x75,0x08 +,0xe8,0x44,0x00,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x28,0x00,0xa3,0xf7,0x34,0xc3,0xba +,0x5a,0x00,0xb8,0x00,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x01,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x02,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x03,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x04,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x05,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x06,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x07,0x80,0xef,0xc3,0xb9 +,0xff,0xff,0xe4,0x58,0xe4,0x54,0x3c,0x00,0x75,0x03,0x49,0x75,0xf7,0xc3,0xfa,0x32 +,0xc0,0xe6,0x56,0xe4,0x56,0x3c,0x00,0x74,0x03,0xe9,0x82,0x00,0xb0,0xff,0xe6,0x56 +,0xe4,0x56,0x3c,0xff,0x75,0x78,0xba,0x52,0x00,0xb8,0xff,0xff,0xef,0xed,0x3c,0xff +,0x75,0x6c,0xb8,0x00,0xff,0xef,0xed,0x3c,0x00,0x75,0x63,0xb0,0xff,0xe6,0x54,0xe4 +,0x54,0x3c,0xff,0x75,0x59,0x32,0xc0,0xe6,0x54,0xe4,0x54,0x3c,0x00,0x75,0x4f,0xb0 +,0x0f,0xe6,0x50,0xe4,0x50,0x24,0x0f,0x3c,0x0f,0x75,0x43,0xb0,0x00,0xe6,0x50,0xe4 +,0x50,0x24,0x0f,0x3c,0x00,0x75,0x37,0x8c,0xc8,0x8e,0xc0,0xbe,0x70,0x00,0x26,0x8b +,0x14,0x26,0x8b,0x5c,0x02,0xb8,0x00,0x00,0xef,0xed,0x23,0xc3,0x3d,0x00,0x00,0x75 +,0x1d,0xb8,0xff,0xff,0x23,0xc3,0xef,0x8b,0xc8,0xed,0x23,0xc3,0x3b,0xc1,0x75,0x0e +,0x83,0xc6,0x04,0x26,0x83,0x3c,0xff,0x75,0xd5,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x2a +,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0x33,0xc0,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xab +,0xbf,0x00,0x30,0xb9,0x17,0x00,0xf3,0xab,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xab +,0xbf,0x00,0x32,0xb9,0x40,0x00,0xf3,0xab,0xfc,0x1e,0x8c,0xc8,0x8e,0xd8,0x33,0xc0 +,0x8e,0xc0,0xbe,0x92,0x00,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xa4,0xbe,0xa9,0x00 +,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0xfb,0x34,0x64,0x00,0xba +,0x08,0x00,0xb8,0x0f,0x00,0xef,0xe8,0x82,0x01,0xe8,0x9b,0x01,0x72,0x0d,0xc7,0x06 +,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34,0x04,0x00,0xc3,0xba,0x0a,0x00,0x33,0xc0 +,0xef,0xe8,0x98,0x01,0xe8,0xb5,0x01,0xb8,0x17,0x00,0xba,0x9c,0x00,0xef,0xb8,0x00 +,0x10,0xba,0x9a,0x00,0xef,0xb8,0x17,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x8c +,0x00,0xef,0xb8,0x00,0x18,0xba,0x86,0x00,0xef,0xb8,0x0c,0x00,0xba,0x82,0x00,0xef +,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x02,0x00,0xef,0xba,0x06,0x00,0x33,0xc0 +,0xef,0xba,0x04,0x00,0xb8,0x60,0x00,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba +,0x80,0x00,0xb9,0xff,0xff,0xed,0xa9,0x01,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x3e,0xba +,0x0a,0x00,0xed,0xa9,0x00,0x40,0x74,0x35,0xa9,0x00,0x20,0x74,0x30,0x33,0xc0,0xef +,0x51,0xb9,0xc8,0x00,0xe2,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x30,0x83 +,0xf9,0x17,0x75,0x18,0x49,0x49,0xbe,0x02,0x20,0xbf,0x06,0x30,0xf3,0xa6,0x1f,0x23 +,0xc9,0x75,0x0a,0xff,0x0e,0xfb,0x34,0x74,0x12,0xe9,0x4d,0xff,0x1f,0xb8,0x2c,0x00 +,0xbb,0x00,0x00,0xa3,0xf7,0x34,0x89,0x1e,0xf9,0x34,0xc3,0xc7,0x06,0xfb,0x34,0x64 +,0x00,0xe8,0xd3,0x00,0x72,0x0d,0xc7,0x06,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34 +,0x04,0x00,0xc3,0xe8,0xd6,0x00,0xe8,0xf3,0x00,0xb8,0x03,0x00,0xba,0x82,0x00,0xef +,0xb8,0x40,0x80,0xba,0x98,0x00,0xef,0xb8,0x00,0x11,0xba,0x96,0x00,0xef,0xb8,0x40 +,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x92,0x00,0xef,0xb8,0x00,0x19,0xba,0x8e +,0x00,0xef,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x06,0x00,0xef,0xba,0x06,0x00 +,0x33,0xc0,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba,0x80,0x00,0xb9,0xff,0xff +,0xed,0xa9,0x20,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x43,0xba,0x0a,0x00,0xed,0xa9,0x00 +,0x40,0x74,0x3a,0xa9,0x00,0x20,0x74,0x35,0x33,0xc0,0xef,0x51,0xb9,0xc8,0x00,0xe2 +,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x32,0x83,0xf9,0x40,0x75,0x1d,0x49 +,0x49,0xbe,0x02,0x22,0xbf,0x06,0x32,0xf3,0xa6,0x1f,0x23,0xc9,0x75,0x0f,0xff,0x0e +,0xfb,0x34,0x74,0x03,0xe9,0x5a,0xff,0xb8,0x00,0x00,0xeb,0x0b,0x1f,0xb8,0x2c,0x00 +,0xbb,0x02,0x00,0x89,0x1e,0xf9,0x34,0xa3,0xf7,0x34,0xc3,0xba,0x02,0x00,0xb8,0x00 +,0x9c,0xef,0xba,0x00,0x00,0xb8,0x00,0x84,0xef,0x33,0xc0,0xef,0xba,0x0a,0x00,0xef +,0xba,0x0e,0x00,0x33,0xc0,0xef,0xc3,0xba,0x0a,0x00,0xb9,0xff,0xff,0xed,0x25,0x00 +,0x60,0x3d,0x00,0x60,0x74,0x04,0xe2,0xf5,0xf8,0xc3,0xf9,0xc3,0xb0,0x00,0xe6,0x56 +,0xb8,0x00,0xff,0xba,0x52,0x00,0xef,0xb9,0xff,0xff,0xba,0x58,0x00,0xed,0x25,0xef +,0x00,0x74,0x08,0xba,0x5a,0x00,0x33,0xc0,0xef,0xe2,0xef,0xc3,0xba,0x80,0x00,0xed +,0xba,0x84,0x00,0xef,0xba,0x80,0x00,0xed,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x06,0xec,0x34,0x15,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0x1e,0x8c,0xc8,0xbe,0x40 +,0x54,0xbf,0x60,0xfe,0x8e,0xd8,0xb9,0x10,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0x80,0x36 +,0x10,0x35,0xc7,0x06,0x8c,0x36,0x30,0x35,0x8d,0x06,0x38,0x35,0xa3,0x30,0x35,0xa3 +,0x32,0x35,0x05,0x33,0x01,0xa3,0x34,0x35,0xc7,0x06,0x36,0x35,0x50,0x01,0xc7,0x06 +,0x84,0x36,0x80,0xfe,0xc7,0x06,0x88,0x36,0xc0,0xfe,0xc6,0x06,0xc2,0xfe,0xff,0xc6 +,0x06,0x93,0x36,0x80,0xc6,0x06,0x92,0x36,0x00,0xc6,0x06,0x80,0xfe,0x80,0xc7,0x06 +,0x82,0xfe,0x54,0x50,0xc7,0x06,0x84,0xfe,0x2b,0x4d,0xe5,0xce,0xa9,0x02,0x00,0x75 +,0x08,0xc6,0x06,0x81,0xfe,0x23,0xe9,0x05,0x00,0xc6,0x06,0x81,0xfe,0x22,0xa1,0xf7 +,0x34,0xa3,0x86,0xfe,0xb8,0x48,0x34,0x86,0xe0,0xa3,0x88,0xfe,0x8d,0x06,0x4e,0x34 +,0x86,0xe0,0xa3,0x8a,0xfe,0xb8,0x58,0x34,0x86,0xe0,0xa3,0x8c,0xfe,0xb8,0x9c,0x34 +,0x86,0xe0,0xa3,0x8e,0xfe,0x8d,0x06,0x20,0x03,0x86,0xe0,0xa3,0x90,0xfe,0x33,0xc0 +,0xba,0x72,0x00,0xef,0x33,0xc0,0xba,0x74,0x00,0xef,0xba,0x76,0x00,0xef,0xb8,0x80 +,0xfe,0x86,0xe0,0xba,0x72,0x00,0xef,0xe8,0xbf,0x07,0xba,0x0c,0x01,0xb8,0x40,0x40 +,0xef,0xed,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0xb9 +,0x0a,0x00,0xe8,0x94,0x00,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0xef,0xa1 +,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc7,0x06,0x90,0x36,0xff,0xff,0xe9,0xe3,0x00,0x63,0x0d,0x66 +,0x0d,0x66,0x0d,0x8a,0x0d,0xe6,0x0e,0x75,0x12,0x2e,0x0f,0x03,0x0f,0x50,0x0f,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0xed,0x0f,0xe9,0x12,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x22,0x10,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xfe,0x10,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xaf,0x0f,0x32,0x10,0x37 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x64,0x0e,0x00,0x0f,0x95,0x09,0x60,0x0a,0x49,0xbb,0xff,0xff,0xba,0x6a,0x00 +,0xed,0xa9,0x00,0x20,0x74,0x38,0x80,0x3e,0x80,0xfe,0x12,0x75,0x31,0xe8,0x4a,0x00 +,0xa1,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33 +,0xc1,0xe8,0x04,0xcd,0x39,0xe8,0x22,0x00,0xc7,0x06,0xf3,0x34,0x46,0x00,0xc7,0x06 +,0xf5,0x34,0xff,0xff,0xc7,0x06,0x90,0x36,0xff,0xff,0x58,0xe9,0x32,0x00,0x4b,0x83 +,0xfb,0x00,0x75,0xb9,0x83,0xf9,0x00,0x75,0xb0,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0x5a,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0xef,0x5a,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x68,0x80,0x07,0xa1,0x90,0x36,0xcd,0x35,0x8b,0x36,0x24,0x02,0x2e,0xff,0xa4,0x35 +,0x0a,0xfa,0x8a,0x26,0x94,0x36,0x88,0x26,0xe8,0x34,0xc6,0x06,0x94,0x36,0x00,0xfb +,0x22,0xe4,0x75,0x01,0xc3,0xf6,0xc4,0x20,0x74,0x7d,0xf6,0xc4,0x08,0x74,0x05,0x80 +,0x0e,0x92,0x36,0x04,0x80,0x26,0xe8,0x34,0xd7,0xc4,0x1e,0x84,0x36,0x26,0x8b,0x37 +,0x81,0xe6,0xff,0x00,0x83,0xfe,0x20,0x76,0x05,0xb0,0x01,0xe9,0x28,0x00,0x53,0x06 +,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0x07,0x5b,0x26,0x88,0x47,0x02,0x3c,0xff,0x74 +,0x07,0x3c,0xfe,0x75,0x11,0xe9,0x3b,0x00,0xf6,0x06,0x92,0x36,0x08,0x75,0x34,0xf6 +,0x06,0x92,0x36,0x04,0x74,0x2d,0x80,0x26,0x92,0x36,0xf3,0x80,0x3e,0x95,0x36,0x00 +,0x75,0x21,0x26,0x80,0x3f,0x05,0x75,0x13,0xc6,0x06,0x95,0x36,0x00,0x26,0x80,0x7f +,0x06,0x00,0x74,0x07,0x26,0x8b,0x47,0x04,0xa2,0x95,0x36,0xba,0x0c,0x01,0xb8,0x40 +,0x40,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x10,0x75,0x03,0xe9,0x5b,0x00,0xf6 +,0xc4,0x04,0x74,0x05,0x80,0x0e,0x92,0x36,0x01,0x80,0x26,0xe8,0x34,0xeb,0xc4,0x3e +,0x88,0x36,0x26,0x8b,0x35,0x83,0xe6,0x7f,0x83,0xfe,0x12,0x72,0x08,0x26,0xc6,0x45 +,0x02,0x01,0xe9,0x24,0x00,0x83,0xc6,0x20,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0xc4 +,0x3e,0x88,0x36,0x26,0x88,0x45,0x02,0x3c,0xff,0x75,0x0e,0xf6,0x06,0x92,0x36,0x01 +,0x74,0x14,0xf6,0x06,0x92,0x36,0x02,0x75,0x0d,0x80,0x26,0x92,0x36,0xfc,0xba,0x0c +,0x01,0xb8,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x08,0x74,0x22,0x80 +,0x26,0xe8,0x34,0xf7,0x80,0x0e,0x92,0x36,0x04,0xf6,0x06,0x92,0x36,0x08,0x74,0x11 +,0x80,0x26,0x92,0x36,0xf3,0xba,0x0c,0x01,0xb8,0x40,0x40,0xef,0xed,0x8a,0x26,0xe8 +,0x34,0xf6,0xc4,0x04,0x74,0x22,0x80,0x26,0xe8,0x34,0xfb,0x80,0x0e,0x92,0x36,0x01 +,0xf6,0x06,0x92,0x36,0x02,0x75,0x11,0x80,0x26,0x92,0x36,0xfe,0xba,0x0c,0x01,0xb8 +,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x01,0x74,0x67,0x80,0x26,0xe8 +,0x34,0xfe,0x80,0x3e,0xe8,0xff,0x00,0x74,0x39,0x80,0x3e,0xe8,0xff,0x04,0x74,0x32 +,0x80,0x3e,0xe8,0xff,0x01,0x75,0x21,0xe5,0x80,0xa9,0x00,0x07,0x74,0x0a,0xba,0x9e +,0x00,0xb8,0x00,0x02,0xef,0xe9,0xef,0xff,0xc6,0x06,0xe8,0xff,0x03,0xba,0x0c,0x01 +,0xb8,0x08,0x08,0xef,0xed,0xe9,0x28,0x00,0x80,0x3e,0xe8,0xff,0x03,0x74,0x06,0xe9 +,0x1e,0x00,0xe9,0x00,0x00,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0xe5,0x00,0x0d +,0x18,0x00,0xe7,0x00,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xc6,0x06,0xe8,0xff,0x04 +,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x02,0x74,0x0d,0x80,0x26,0xe8,0x34,0xfd,0x80,0x26 +,0x92,0x36,0xbf,0xe8,0x4f,0x0b,0xfa,0xa0,0xe8,0x34,0x08,0x06,0x94,0x36,0xc6,0x06 +,0xe8,0x34,0x00,0xfb,0xc3,0xe8,0xe7,0x0f,0xc4,0x1e,0x84,0x36,0x2e,0xff,0x16,0x01 +,0x07,0x26,0x88,0x47,0x02,0xe9,0x7e,0xfe,0xe8,0x2d,0x10,0xc4,0x1e,0x84,0x36,0x2e +,0xff,0x16,0x03,0x07,0x26,0x88,0x47,0x02,0xe9,0x6b,0xfe,0x8e,0x06,0x26,0x02,0x2e +,0xff,0x16,0x07,0x07,0xc3,0xc3,0x83,0x3e,0xf5,0x34,0x00,0x74,0x0f,0xff,0x0e,0xf3 +,0x34,0x75,0x09,0xe8,0xc4,0xfd,0xc7,0x06,0xf5,0x34,0x00,0x00,0xf6,0x06,0x93,0x36 +,0x20,0x74,0x30,0xa1,0xc2,0x34,0x3b,0x06,0xe9,0x34,0xa3,0xe9,0x34,0x74,0x24,0x80 +,0x3e,0x95,0x36,0x00,0x75,0x1d,0xf7,0x06,0xe6,0x34,0x20,0x00,0x74,0x12,0xa9,0x20 +,0x00,0x74,0x0d,0x83,0x26,0xc2,0x34,0xdf,0x83,0x26,0xe9,0x34,0xdf,0xe9,0x03,0x00 +,0xe8,0xdd,0x09,0xba,0x06,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e +,0x03,0x16,0x74,0x34,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06,0x74 +,0x34,0xba,0x02,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e,0x03,0x16 +,0x70,0x34,0xc1,0xe0,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0xc7 +,0x06,0xa6,0x33,0x04,0x00,0xc7,0x06,0xaa,0x33,0x00,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc3,0x95,0x09,0x95,0x09,0x65,0x09,0x78,0x09,0x95,0x09,0x95 +,0x09,0x91,0x07,0x95,0x09,0x96,0x09,0x8b,0x09,0x95,0x09,0x95,0x09,0x95,0x09,0x95 +,0x09,0x95,0x09,0x95,0x09,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x90 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9,0xcc,0x00,0x8c,0xc0,0x40,0x8e,0xc0,0x26 +,0x8b,0x0e,0x06,0x00,0x86,0xe9,0x26,0x89,0x0e,0x06,0x00,0x8c,0xc2,0xc1,0xe2,0x04 +,0xbe,0x0e,0x00,0x26,0xa1,0x04,0x00,0xd0,0xe0,0x24,0xc0,0x8a,0xe0,0xc0,0xec,0x04 +,0x0a,0xc4,0x26,0xa2,0x05,0x00,0x26,0xa1,0x08,0x00,0xa9,0x00,0xc0,0x74,0x03,0xe9 +,0x9e,0x00,0x26,0xf6,0x06,0x10,0x00,0x80,0x75,0x03,0xe9,0x0a,0x00,0x26,0xa0,0x16 +,0x00,0x24,0x1f,0x32,0xe4,0x03,0xf0,0x80,0x3e,0xec,0x34,0x06,0x72,0x5c,0x80,0x3e +,0x95,0x36,0x00,0x75,0x66,0x8b,0xfa,0x33,0xdb,0x8e,0xc3,0x26,0x89,0x1d,0x26,0x88 +,0x5d,0x04,0x51,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x21,0x09 +,0x58,0x59,0x0b,0xdb,0x74,0x34,0xfe,0x0e,0xe6,0x3a,0x26,0xc6,0x07,0x81,0x26,0xc6 +,0x47,0x01,0x00,0x26,0xc6,0x47,0x02,0xff,0x26,0xc7,0x47,0x04,0x00,0x00,0x26,0x89 +,0x4f,0x0a,0x86,0xf2,0x26,0x89,0x57,0x06,0x26,0x89,0x77,0x08,0x26,0xc6,0x47,0x09 +,0x00,0x26,0xc6,0x47,0x0c,0x02,0xe8,0x8c,0x09,0xc3,0xff,0x06,0xec,0x33,0x8c,0xc0 +,0x48,0x8e,0xc0,0xfa,0xe8,0x97,0x10,0xfb,0xe9,0xeb,0xff,0x8c,0xc0,0x48,0x8e,0xc0 +,0xfa,0xe8,0x8a,0x10,0xfb,0xc3,0x8c,0xc0,0x8e,0xc0,0xfa,0xe8,0x80,0x10,0xfb,0xc3 +,0x80,0x3e,0x95,0x36,0x00,0x75,0x03,0xe9,0xc2,0x00,0xbf,0x08,0x00,0x26,0xf6,0x06 +,0x10,0x00,0x80,0x75,0x05,0x03,0xfe,0xe9,0x0c,0x00,0x26,0xa0,0x16,0x00,0x24,0x1f +,0x32,0xe4,0x03,0xf0,0x03,0xfe,0xa0,0x95,0x36,0x3c,0x00,0x75,0x03,0xe9,0x9c,0x00 +,0x3c,0x01,0x74,0x0b,0x3c,0x02,0x74,0x14,0x3c,0x03,0x74,0x1d,0xe9,0x8d,0x00,0xc6 +,0x06,0x96,0x36,0x01,0xe8,0x3c,0x01,0x72,0x27,0xe9,0x80,0x00,0xc6,0x06,0x96,0x36 +,0x02,0xe8,0x83,0x00,0x72,0x1a,0xe9,0x73,0x00,0xc6,0x06,0x96,0x36,0x01,0xe8,0x22 +,0x01,0x72,0x0d,0xc6,0x06,0x96,0x36,0x02,0xe8,0x6c,0x00,0x72,0x03,0xe9,0x5c,0x00 +,0x53,0x06,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0b,0x00,0x33,0xc0,0xe8,0x42,0x08,0x58 +,0x26,0xc6,0x07,0x82,0x26,0xc6,0x47,0x02,0xff,0x8d,0x06,0xe0,0xfe,0x86,0xc4,0x26 +,0x89,0x47,0x06,0xa0,0x96,0x36,0x26,0x88,0x47,0x08,0xe8,0xc8,0x08,0x07,0x5b,0x83 +,0x26,0xad,0x36,0xfe,0xa1,0xad,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef +,0xed,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0x52,0xba,0xe0,0x00,0xb8,0x41,0x10 +,0xef,0x5a,0xb8,0x9c,0x03,0xcd,0x39,0xc6,0x06,0x95,0x36,0x00,0x8c,0xc0,0x48,0x8e +,0xc0,0xfa,0xe8,0xa9,0x0f,0xfb,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x8b +,0xf0,0x8d,0x3e,0x20,0xf3,0x51,0xb1,0x0a,0x26,0x83,0x7d,0x0c,0x01,0x75,0x2a,0x57 +,0x26,0x83,0x7d,0x0e,0x00,0x74,0x06,0xe8,0x2f,0x00,0xe9,0x03,0x00,0xe8,0x66,0x07 +,0x5f,0x73,0x16,0x33,0xc0,0x8e,0xd8,0x26,0x8b,0x4d,0x12,0x8d,0x75,0x20,0x8d,0x3e +,0xe0,0xfe,0xf3,0xa4,0x59,0x07,0x1f,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20 +,0x01,0xe9,0xc4,0xff,0x59,0x07,0x1f,0xf8,0xc3,0x51,0x50,0x53,0x56,0x52,0x57,0x33 +,0xdb,0x26,0x8a,0x5d,0x0e,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0x5a,0x87,0xd7,0x26 +,0x8a,0x45,0x14,0x87,0xd7,0x42,0x32,0xff,0x80,0xff,0x08,0x75,0x08,0xfe,0xcb,0x22 +,0xdb,0x75,0xea,0x33,0xdb,0x23,0xdb,0x74,0x06,0xfe,0xc7,0xd0,0xc8,0x73,0x0c,0x50 +,0x26,0x8a,0x05,0x38,0x04,0x58,0x74,0x03,0xe9,0x0a,0x00,0x49,0x46,0x47,0x23,0xc9 +,0x74,0x0a,0xe9,0xd3,0xff,0x5a,0x5e,0x5b,0x58,0x59,0xf8,0xc3,0x5a,0x5e,0x5b,0x58 +,0x59,0xf9,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x86,0xcd,0x2b,0xce,0x8b +,0xf7,0x8b,0xc1,0x33,0xc9,0x80,0x3c,0xff,0x74,0x16,0x80,0xf9,0x06,0x73,0x09,0x32 +,0xc9,0x46,0x48,0x74,0x2e,0xe9,0xed,0xff,0x3d,0x60,0x00,0x73,0x0c,0xe9,0x23,0x00 +,0xfe,0xc1,0x46,0x48,0x74,0x1d,0xe9,0xdc,0xff,0xb8,0x10,0x00,0x8d,0x3e,0x18,0x34 +,0x32,0xed,0xb1,0x06,0xf3,0xa6,0x74,0x03,0xe9,0x08,0x00,0x48,0x23,0xc0,0x74,0x07 +,0xe9,0xe9,0xff,0x07,0x1f,0xf8,0xc3,0x8d,0x36,0x18,0x34,0x33,0xc0,0x8e,0xd8,0x8d +,0x3e,0xe0,0xfe,0xb8,0x10,0x00,0xb9,0x06,0x00,0x56,0xf3,0xa4,0x5e,0x48,0x3d,0x00 +,0x00,0x75,0xf3,0x07,0x1f,0xf9,0xc3,0xff,0x06,0xe4,0x33,0xc6,0x06,0xeb,0x34,0x00 +,0x26,0x8b,0x45,0x06,0x86,0xe0,0xc1,0xe8,0x04,0x48,0x06,0x8e,0xc0,0xfe,0x06,0xe6 +,0x3a,0xfa,0xe8,0x69,0x0e,0xfb,0x07,0xb0,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb0,0x01,0xc3,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3 +,0x8b,0x0e,0x97,0x36,0x81,0xe1,0x80,0x30,0x26,0x8b,0x47,0x04,0x25,0x7f,0xcf,0x0b +,0xc1,0xa3,0x97,0x36,0xa3,0xe6,0x34,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x74 +,0x03,0xb0,0x03,0xc3,0x26,0x8b,0x47,0x08,0xa3,0x97,0x36,0xa3,0xe6,0x34,0x26,0x8a +,0x47,0x20,0xa2,0xfd,0x34,0x3c,0x01,0x75,0x06,0xc7,0x06,0xa1,0x36,0x00,0x00,0x26 +,0x8a,0x47,0x21,0xa2,0xfe,0x34,0x26,0x8b,0x47,0x0a,0xa3,0x18,0x34,0xa3,0x58,0x34 +,0x26,0x8b,0x47,0x0c,0xa3,0x1a,0x34,0xa3,0x5a,0x34,0x26,0x8b,0x47,0x0e,0xa3,0x1c +,0x34,0xa3,0x5c,0x34,0xc6,0x06,0x2a,0x34,0xc0,0x26,0x8b,0x47,0x14,0x25,0x7f,0xff +,0x09,0x06,0x2c,0x34,0x26,0x8b,0x47,0x16,0x25,0xff,0xfe,0x25,0xff,0xfc,0x09,0x06 +,0x2e,0x34,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47,0x10,0xa3,0x02,0x34,0x26,0x8b +,0x47,0x12,0xa3,0x04,0x34,0x06,0x53,0xe8,0x84,0x0a,0x5b,0x07,0x3d,0x00,0x00,0x75 +,0x07,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3,0xb9,0x00,0x01,0xa1,0xac,0x33,0x33 +,0xd2,0xf7,0xf9,0xa3,0xae,0x33,0x91,0x49,0x33,0xd2,0xf7,0xe9,0x05,0x00,0x3b,0xa3 +,0x46,0x34,0xbf,0x00,0x3b,0x89,0x3e,0x44,0x34,0xba,0x68,0x00,0xb8,0xe0,0xe0,0xef +,0xa1,0xae,0x33,0xe7,0x62,0xa1,0xae,0x33,0xba,0x08,0x01,0xef,0xa1,0x44,0x34,0xe7 +,0x64,0xa1,0x44,0x34,0xba,0x0a,0x01,0xef,0xb8,0x00,0x01,0x2d,0x04,0x00,0x0d,0x00 +,0x10,0xe7,0x92,0xc3,0x3d,0x00,0x00,0x74,0x0a,0x26,0x89,0x47,0x07,0xe8,0x83,0x3a +,0xb0,0x07,0xc3,0xa1,0xae,0x33,0x26,0x89,0x47,0x2b,0xa1,0x44,0x34,0x26,0x89,0x47 +,0x2d,0xa1,0x46,0x34,0x26,0x89,0x47,0x2f,0x80,0x0e,0x93,0x36,0x20,0xa1,0x88,0x36 +,0x86,0xe0,0x26,0x89,0x47,0x08,0xa1,0x84,0x36,0x86,0xe0,0x26,0x89,0x47,0x0a,0xa1 +,0x80,0x36,0x86,0xe0,0x26,0x89,0x47,0x0c,0xb8,0x60,0xfe,0x86,0xe0,0x26,0x89,0x47 +,0x0e,0xa0,0xa1,0x36,0x26,0x88,0x47,0x10,0x8b,0x36,0x88,0x36,0x26,0xc6,0x44,0x02 +,0xff,0xe5,0x9e,0xa9,0x00,0x08,0x74,0x0c,0xba,0x84,0x00,0xed,0x0d,0x08,0x00,0xef +,0xba,0x8e,0x00,0xef,0xe5,0x02,0x25,0xf9,0xff,0xe7,0x02,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3 +,0x80,0x26,0x93,0x36,0x9f,0xe8,0x8d,0x0a,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3 +,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x2a +,0x34,0xc0,0x26,0x8b,0x47,0x06,0x25,0x7f,0xff,0xa3,0x2c,0x34,0x26,0x8b,0x47,0x08 +,0x25,0xff,0xfe,0x25,0xff,0xfc,0xa3,0x2e,0x34,0xcd,0x52,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47 +,0x06,0xa3,0x02,0x34,0x26,0x8b,0x47,0x08,0xa3,0x04,0x34,0xcd,0x52,0xb0,0x00,0xc3 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x57,0x8d,0x7f,0x06,0x51,0xb9 +,0x07,0x00,0x33,0xc0,0xf3,0xab,0x59,0x8d,0x7f,0x06,0xa1,0x7a,0x34,0x03,0x06,0x39 +,0x37,0x26,0x88,0x05,0xa1,0x95,0x37,0x26,0x88,0x45,0x02,0xa1,0x80,0x34,0x03,0x06 +,0x76,0x34,0x26,0x88,0x45,0x07,0xa1,0xc6,0x34,0x26,0x88,0x45,0x09,0xa1,0xd8,0x33 +,0x26,0x88,0x45,0x0a,0x33,0xc0,0xa3,0x7a,0x34,0xa3,0x39,0x37,0xa3,0x95,0x37,0xa3 +,0x80,0x34,0xa3,0x76,0x34,0xa3,0xc6,0x34,0xa3,0xd8,0x33,0x5f,0xb0,0x00,0xc3,0xf6 +,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x83,0xf9,0x06 +,0x74,0x12,0x83,0xf9,0x04,0x74,0x0d,0x83,0xf9,0x00,0x74,0x08,0x83,0xf9,0x02,0x74 +,0x03,0xb0,0x01,0xc3,0x89,0x0e,0xe8,0x3a,0x83,0x26,0xab,0x36,0xf9,0x09,0x0e,0xab +,0x36,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc1,0xe7,0x02,0xb0,0x00,0xc3,0xf6,0x06,0x93 +,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x80,0xf9,0xff,0x74,0x08 +,0x80,0xf9,0x00,0x74,0x10,0xb0,0x01,0xc3,0x83,0x0e,0xad,0x36,0x02,0xa1,0xad,0x36 +,0xe7,0x04,0xe9,0x0a,0x00,0x83,0x26,0xad,0x36,0xfd,0xa1,0xad,0x36,0xe7,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xe8,0xd5,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x06 +,0x05,0x75,0x03,0xe9,0x9d,0x00,0x26,0x8b,0x57,0x04,0x26,0x8b,0x47,0x08,0x26,0x81 +,0x7f,0x06,0x00,0x80,0x75,0x08,0xed,0x26,0x89,0x47,0x0a,0xe9,0x9d,0x00,0x26,0x83 +,0x7f,0x06,0x01,0x75,0x04,0xef,0xe9,0x92,0x00,0x26,0x81,0x7f,0x06,0x01,0x80,0x75 +,0x09,0xef,0xed,0x26,0x89,0x47,0x0a,0xe9,0x81,0x00,0x26,0x83,0x7f,0x06,0x02,0x75 +,0x07,0x26,0x21,0x47,0x04,0xe9,0x73,0x00,0x26,0x81,0x7f,0x06,0x02,0x80,0x75,0x0c +,0x26,0x21,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x5f,0x00,0x26,0x83,0x7f,0x06 +,0x03,0x75,0x07,0x26,0x09,0x47,0x04,0xe9,0x51,0x00,0x26,0x81,0x7f,0x06,0x03,0x80 +,0x75,0x0c,0x26,0x09,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x3d,0x00,0x26,0x83 +,0x7f,0x06,0x04,0x75,0x07,0x26,0x31,0x47,0x04,0xe9,0x2f,0x00,0x26,0x81,0x7f,0x06 +,0x04,0x80,0x75,0x0c,0x26,0x31,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x1b,0x00 +,0xb0,0x01,0xc3,0xfa,0x53,0x26,0x8b,0x4f,0x08,0x0b,0xc9,0x74,0x0c,0x8d,0x1e,0xe0 +,0xfe,0xe8,0x52,0xff,0x83,0xc3,0x08,0xe2,0xf8,0x5b,0xfb,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x80,0x75,0x0a,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3,0x8d +,0x3e,0xe0,0xfe,0xe5,0x00,0x26,0x89,0x05,0xe5,0x02,0x26,0x89,0x45,0x02,0xa1,0xad +,0x36,0x26,0x89,0x45,0x04,0xe5,0x06,0x26,0x89,0x45,0x06,0xe5,0x08,0x26,0x89,0x45 +,0x08,0xe5,0x0a,0x26,0x89,0x45,0x0a,0xe5,0x0e,0x26,0x89,0x45,0x0c,0xe5,0x48,0x26 +,0x89,0x45,0x0e,0xe5,0x4a,0x26,0x89,0x45,0x10,0xe5,0x4c,0x26,0x89,0x45,0x12,0xa1 +,0xb7,0x36,0x26,0x89,0x45,0x14,0xe5,0x50,0x26,0x89,0x45,0x16,0xe5,0x52,0x26,0x89 +,0x45,0x18,0xe5,0x54,0x26,0x89,0x45,0x1a,0xe5,0x56,0x26,0x89,0x45,0x1c,0xe5,0x58 +,0x26,0x89,0x45,0x1e,0xe5,0x62,0x26,0x89,0x45,0x20,0xe5,0x64,0x26,0x89,0x45,0x22 +,0xe5,0x66,0x26,0x89,0x45,0x24,0xe5,0x68,0x26,0x89,0x45,0x26,0xe5,0x6a,0x26,0x89 +,0x45,0x28,0xe5,0x6c,0x26,0x89,0x45,0x2a,0xe5,0x70,0x26,0x89,0x45,0x2c,0xe5,0x72 +,0x26,0x89,0x45,0x2e,0xe5,0x74,0x26,0x89,0x45,0x30,0xe5,0x76,0x26,0x89,0x45,0x32 +,0xe5,0x7c,0x26,0x89,0x45,0x34,0xe5,0x7e,0x26,0x89,0x45,0x36,0xe5,0x80,0x26,0x89 +,0x45,0x38,0xe5,0x82,0x26,0x89,0x45,0x3a,0xe5,0x86,0x26,0x89,0x45,0x3c,0xe5,0x88 +,0x26,0x89,0x45,0x3e,0xe5,0x9a,0x26,0x89,0x45,0x40,0xe5,0x9e,0x26,0x89,0x45,0x42 +,0xe5,0xcc,0x26,0x89,0x45,0x44,0xe5,0xce,0x26,0x89,0x45,0x46,0xe5,0xd0,0x26,0x89 +,0x45,0x48,0xe5,0xd2,0x26,0x89,0x45,0x4a,0xba,0x00,0x01,0xed,0x11,0x06,0x66,0x34 +,0x73,0x04,0xff,0x06,0x68,0x34,0x26,0x89,0x45,0x4c,0xba,0x02,0x01,0xed,0xc1,0xe0 +,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0x26,0x89,0x45,0x4e,0xba +,0x04,0x01,0xed,0x11,0x06,0x6a,0x34,0x73,0x04,0xff,0x06,0x6c,0x34,0x26,0x89,0x45 +,0x50,0xba,0x06,0x01,0xed,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06 +,0x74,0x34,0x26,0x89,0x45,0x52,0xba,0x08,0x01,0xed,0x26,0x89,0x45,0x54,0xba,0x0a +,0x01,0xed,0x26,0x89,0x45,0x56,0xba,0x0c,0x01,0xed,0x26,0x89,0x45,0x58,0xba,0x0e +,0x01,0xed,0x01,0x06,0x7a,0x34,0x26,0x89,0x45,0x5e,0xba,0x10,0x01,0xed,0x26,0x89 +,0x45,0x5c,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x74,0x07,0xf6,0x06,0x93,0x36 +,0x20,0x75,0x03,0xb0,0x01,0xc3,0x26,0x80,0x7f,0x06,0x00,0x75,0x30,0x80,0x3e,0x95 +,0x36,0x00,0x74,0x52,0xc6,0x06,0x95,0x36,0x00,0x83,0x26,0xad,0x36,0xfe,0xa1,0xad +,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef,0xed,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0xb0,0x00,0xc3,0x26,0x8b,0x47 +,0x04,0x3d,0x00,0x00,0x74,0x20,0x3d,0x03,0x00,0x77,0x1b,0xba,0x10,0x01,0xb8,0x02 +,0x00,0xef,0xba,0xe0,0x00,0xb8,0x01,0x10,0xef,0x83,0x0e,0xad,0x36,0x01,0xa1,0xad +,0x36,0xe7,0x04,0xb0,0x00,0xc3,0xb0,0x06,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03 +,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x04,0x01,0x74,0x0a,0x26,0x83,0x7f,0x04,0x02,0x74 +,0x19,0xb0,0x06,0xc3,0x26,0x83,0x7f,0x06,0x0c,0x77,0xf6,0x26,0x83,0x7f,0x0a,0x60 +,0x77,0xef,0xe8,0x10,0x00,0x72,0x0b,0xb0,0x46,0xc3,0xe8,0x4e,0x00,0x72,0x03,0xb0 +,0x46,0xc3,0xb0,0x00,0xc3,0x51,0xb1,0x0a,0x8b,0x3e,0x20,0xf3,0x26,0x83,0x7d,0x0c +,0x02,0x75,0x03,0xe9,0x0e,0x00,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01,0xe9,0xeb +,0xff,0x59,0xf8,0xc3,0x57,0x8d,0x7d,0x0e,0x8d,0x77,0x06,0xb9,0x12,0x00,0xf3,0xa4 +,0x8d,0x7d,0x20,0x8d,0x36,0xe0,0xfe,0x26,0x8b,0x4d,0x12,0xf3,0xa4,0xff,0x06,0x01 +,0x35,0x5f,0x26,0xc7,0x45,0x0c,0x01,0x00,0x59,0xf9,0xc3,0x51,0xb1,0x0a,0x8d,0x3e +,0x20,0xf3,0x8d,0x36,0xe0,0xfe,0x26,0x83,0x7d,0x0c,0x01,0x75,0x1b,0x57,0xe8,0x25 +,0x00,0x5f,0x73,0x14,0x33,0xc0,0xb9,0x20,0x01,0xf3,0xaa,0x26,0xc7,0x45,0x0c,0x02 +,0x00,0xff,0x0e,0x01,0x35,0x59,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01 +,0xe9,0xd3,0xff,0x59,0xf8,0xc3,0x51,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0xf3,0xa6 +,0x74,0x03,0x59,0xf8,0xc3,0x59,0xf9,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xec,0x34,0x06,0x72,0x33,0xff,0x06,0xf0,0x33,0x50,0xc4,0x1e,0x8c,0x36 +,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x29,0x00,0x58,0x81,0x26,0xc2,0x34,0xdf,0x7f,0x81 +,0x26,0xe9,0x34,0xdf,0x7f,0x0b,0xdb,0x74,0x11,0x26,0xc6,0x07,0x84,0x26,0xc6,0x47 +,0x02,0xff,0x26,0x89,0x47,0x06,0xe8,0xac,0x00,0xc3,0xff,0x06,0xea,0x33,0xe9,0xf5 +,0xff,0x57,0x26,0x8b,0x3f,0x03,0xf9,0x26,0x3b,0x7f,0x02,0x74,0x16,0x26,0x3b,0x7f +,0x04,0x7c,0x2a,0x3d,0x00,0x00,0x75,0x13,0x8d,0x7f,0x08,0x03,0xf9,0x26,0x3b,0x7f +,0x02,0x7c,0x14,0xff,0x06,0xde,0x33,0x33,0xdb,0x5f,0xc3,0x26,0x8b,0x7f,0x02,0x26 +,0x89,0x3f,0x03,0xf9,0xe9,0x06,0x00,0x26,0x89,0x3f,0x26,0x29,0x0f,0x26,0xc7,0x05 +,0xff,0xff,0x26,0x87,0x3f,0x26,0x89,0x0d,0x8d,0x5d,0x02,0x50,0x8b,0xfb,0x83,0xe9 +,0x02,0x33,0xc0,0xf3,0xaa,0x58,0xfe,0x0e,0xec,0x34,0x5f,0xc3,0x8b,0x7c,0x02,0x3b +,0x3c,0x74,0x2f,0x83,0x3d,0xff,0x75,0x0b,0x8d,0x7c,0x08,0x89,0x7c,0x02,0x83,0x3d +,0xff,0x74,0x1e,0x8a,0x45,0x02,0x3c,0x81,0x75,0x0c,0x80,0x3e,0xeb,0x34,0x00,0x74 +,0x05,0x33,0xc0,0xe9,0x0b,0x00,0x8b,0x0d,0x01,0x4c,0x02,0x8d,0x75,0x02,0x83,0xe9 +,0x02,0xc3,0x80,0x3e,0xec,0x34,0x06,0x72,0x05,0x33,0xc0,0xe9,0xf3,0xff,0xff,0x06 +,0xee,0x33,0xe9,0xbe,0xff,0xf6,0x06,0x92,0x36,0x40,0x74,0x01,0xc3,0x57,0x56,0x51 +,0x52,0x8b,0x36,0x8c,0x36,0xe8,0xa4,0xff,0x75,0x03,0xe9,0x1a,0x00,0xe9,0x1c,0x00 +,0xfe,0x06,0xec,0x34,0xc4,0x3e,0x80,0x36,0xf3,0xa4,0x80,0x0e,0x92,0x36,0x40,0xba +,0x0c,0x01,0xb8,0x80,0x80,0xef,0xed,0x5a,0x59,0x5e,0x5f,0xc3,0xff,0x06,0xe0,0x33 +,0x80,0x3c,0x81,0x75,0x0c,0xff,0x06,0xe2,0x33,0xc6,0x06,0xeb,0x34,0x01,0xe9,0xcf +,0xff,0x80,0x3c,0x84,0x75,0x07,0xff,0x06,0xe6,0x33,0xe9,0xc3,0xff,0xff,0x06,0xe8 +,0x33,0xe9,0xbc,0xff,0x8d,0x3e,0xe0,0xfe,0xa1,0x72,0x34,0xc7,0x06,0x72,0x34,0x00 +,0x00,0x89,0x05,0xa1,0x74,0x34,0xc7,0x06,0x74,0x34,0x00,0x00,0x89,0x45,0x02,0xba +,0x04,0x01,0xed,0x89,0x45,0x04,0xc7,0x45,0x06,0x00,0x00,0xa1,0x6e,0x34,0xc7,0x06 +,0x6e,0x34,0x00,0x00,0x89,0x45,0x08,0xa1,0x70,0x34,0xc7,0x06,0x70,0x34,0x00,0x00 +,0x89,0x45,0x0a,0xba,0x00,0x01,0xed,0x89,0x45,0x0c,0xc7,0x45,0x0e,0x00,0x00,0x32 +,0xe4,0xba,0x0e,0x01,0xec,0x89,0x45,0x10,0xa1,0x7e,0x34,0xc7,0x06,0x7e,0x34,0x00 +,0x00,0x89,0x45,0x12,0xa1,0x8c,0x34,0xc7,0x06,0x8c,0x34,0x00,0x00,0x89,0x45,0x14 +,0xa1,0x8a,0x34,0xc7,0x06,0x8a,0x34,0x00,0x00,0x89,0x45,0x16,0xa1,0x7c,0x34,0xc7 +,0x06,0x7c,0x34,0x00,0x00,0x89,0x45,0x18,0xa1,0x88,0x34,0xc7,0x06,0x88,0x34,0x00 +,0x00,0x89,0x45,0x1a,0xa1,0xca,0x33,0xc7,0x06,0xca,0x33,0x00,0x00,0x89,0x45,0x1c +,0xa1,0x78,0x34,0xc7,0x06,0x78,0x34,0x00,0x00,0x89,0x45,0x1e,0xa1,0xc6,0x34,0xc7 +,0x06,0xc6,0x34,0x00,0x00,0x89,0x45,0x20,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xfa,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0xb8,0xa0,0x01,0xc1,0xe8,0x04,0x8e,0xd0,0x8d +,0x26,0x80,0x00,0xe8,0x00,0x01,0xe8,0x10,0xeb,0x8b,0x1e,0xf7,0x34,0x8b,0x16,0xf9 +,0x34,0x8b,0x36,0xff,0x34,0x33,0xc0,0xb9,0xef,0xff,0x8d,0x3e,0x14,0x00,0x2b,0xcf +,0x2b,0xce,0xd1,0xe9,0xf3,0xab,0x89,0x1e,0xf7,0x34,0x89,0x16,0xf9,0x34,0x83,0xfe +,0x00,0x74,0x0c,0xb9,0xef,0xff,0xbf,0x80,0xfe,0x2b,0xcf,0xd1,0xe9,0xf3,0xab,0xb9 +,0xff,0xff,0x81,0xe9,0x00,0x3b,0x83,0xfe,0x00,0x74,0x03,0xe9,0x1b,0x00,0x51,0x1e +,0xb8,0x00,0xe0,0x8e,0xd8,0x33,0xf6,0x8d,0x3e,0x00,0xd8,0xb9,0x00,0x0c,0xf3,0xa5 +,0x1f,0x59,0xbe,0xff,0xff,0x81,0xee,0x00,0xd8,0x2b,0xce,0x81,0xe1,0x00,0xff,0x89 +,0x0e,0xac,0x33,0x8d,0x06,0x20,0x02,0xc1,0xe8,0x04,0xa3,0x32,0x34,0x8e,0xd0,0x36 +,0xc7,0x06,0x1e,0x00,0x80,0x18,0x36,0xc7,0x06,0x22,0x00,0xff,0x7f,0x36,0xc7,0x06 +,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0x8d,0x06,0xa0,0x02,0xc1 +,0xe8,0x04,0xa3,0x30,0x34,0x8e,0xd0,0x36,0xc7,0x06,0x1e,0x00,0x50,0x28,0x36,0xc7 +,0x06,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0xb8,0xa0,0x01,0xc1 +,0xe8,0x04,0xa3,0x34,0x34,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00,0xb8,0x00 +,0x90,0xe7,0x02,0x8d,0x3e,0x70,0x01,0x8b,0xc7,0xc1,0xe8,0x04,0xb9,0x03,0x00,0x89 +,0x45,0x0e,0x89,0x45,0x02,0xc7,0x05,0xff,0xff,0x83,0xc7,0x10,0x05,0x01,0x00,0xe2 +,0xee,0xe8,0x5b,0x01,0xe5,0xce,0xa3,0xb5,0x36,0xe8,0x21,0x00,0xe8,0x45,0x01,0xa1 +,0x32,0x34,0x8c,0xcb,0xcd,0x37,0x0e,0x58,0xa9,0x00,0xf0,0x74,0x07,0x33,0xf6,0x89 +,0x36,0xff,0x34,0xc3,0x8d,0x36,0x30,0x61,0x89,0x36,0xff,0x34,0xc3,0x33,0xc0,0x8b +,0xd0,0x8b,0xf2,0xb9,0x68,0x00,0x2e,0x80,0xbc,0xac,0x17,0x80,0x75,0x01,0xef,0x83 +,0xc2,0x02,0x46,0xe2,0xf1,0xb8,0x02,0x00,0xe7,0x50,0xb9,0x5a,0x00,0x33,0xff,0xc7 +,0x05,0x65,0x18,0x8c,0x4d,0x02,0x83,0xc7,0x04,0xe2,0xf4,0x33,0xc0,0x8e,0xc0,0x8c +,0xc8,0x8e,0xd8,0x8d,0x3e,0x80,0x00,0x8d,0x36,0x9c,0x17,0xb9,0x08,0x00,0xe8,0x37 +,0x00,0x8d,0x36,0x20,0x21,0x8d,0x3e,0xc0,0x00,0xb9,0x0d,0x00,0xe8,0x29,0x00,0x8d +,0x3e,0x40,0x01,0xb9,0x0a,0x00,0xe8,0x1f,0x00,0xe8,0x4b,0x0e,0x33,0xc0,0x8e,0xd8 +,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xe7,0x48,0xe7,0x4c,0xb8,0x40,0x9c,0xe7,0x4a,0xe5 +,0x48,0x90,0xb8,0x00,0x70,0xe7,0x48,0xc3,0xa5,0x83,0xc7,0x02,0xe2,0xfa,0xc3,0xe5 +,0x4c,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe5,0x58,0xd1 +,0xe0,0x73,0x11,0x8b,0xf0,0xd1,0xe6,0x33,0xc0,0x8e,0xd8,0x8b,0xb4,0x80,0x00,0x83 +,0xc6,0x0b,0xff,0xe6,0x1f,0x07,0x5a,0x5f,0x5e,0x59,0x58,0xcf,0x58,0x1c,0xe4,0x1c +,0x6c,0x1c,0x8e,0x1a,0xc0,0x1f,0x40,0x1a,0x44,0x1c,0x65,0x18,0x80,0x80,0x80,0xff +,0x80,0x03,0x02,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0x80,0x03,0x03,0x43,0x80,0x80,0x02,0x80,0x42,0x03,0x02,0xff,0x03,0x01,0x03,0x01 +,0x01,0x03,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x03,0x01,0x03 +,0x03,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0x01,0x03,0x03,0x03,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0x02,0xb8,0x0f,0x00,0xe7,0x84,0xb8,0x0f,0xf8,0xe7,0x82,0xc3,0xb9 +,0x08,0x00,0x89,0x0e,0xe6,0x3a,0x8d,0x06,0x20,0x03,0x8b,0xd0,0xc1,0xe8,0x04,0xa3 +,0x90,0x01,0x8b,0xc2,0x8b,0xd8,0xc1,0xe8,0x04,0x8e,0xc0,0x05,0x61,0x00,0x26,0xa3 +,0x00,0x00,0xa1,0x30,0x34,0x26,0xa3,0x02,0x00,0x83,0xc3,0x14,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0x81,0xc2,0x10,0x06,0xe2,0xd9,0x26,0xc7,0x06,0x00,0x00,0xff,0xff +,0x8c,0x06,0x92,0x01,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8 +,0xe7,0x5a,0xff,0x06,0xbe,0x33,0xba,0xd2,0x00,0xed,0xcf,0x00,0x00,0x00,0x00,0x00 +,0x8c,0xcb,0xa1,0x30,0x34,0xcd,0x37,0xe9,0x06,0xed,0xb8,0x32,0x00,0xc3,0xe8,0x8c +,0x01,0xfe,0x06,0xe2,0x34,0xe8,0x21,0x01,0x75,0xf0,0xe8,0x53,0x0e,0x81,0x0e,0xaf +,0x36,0x00,0xc0,0xc7,0x06,0xad,0x36,0x60,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75 +,0x1a,0xf7,0x06,0xe6,0x34,0x00,0x08,0x74,0x09,0xc7,0x06,0xab,0x36,0x0b,0x00,0xe9 +,0x0f,0x00,0xc7,0x06,0xab,0x36,0x03,0x00,0xe9,0x06,0x00,0xc7,0x06,0xab,0x36,0x11 +,0x9c,0xc7,0x06,0xa9,0x36,0x18,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75,0x0d,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x05,0x83,0x0e,0xa9,0x36,0x20,0xa1,0xa9,0x36,0xe7 +,0x00,0xa1,0xab,0x36,0xe7,0x02,0xf7,0x06,0xe6,0x34,0x80,0x00,0x74,0x2e,0xe8,0xf2 +,0x2f,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08 +,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xb8,0x40,0x00,0xe7,0x4e,0x33 +,0xc0,0xe7,0x0e,0xc7,0x06,0x26,0x02,0x00,0x00,0xe9,0x23,0x00,0xc7,0x06,0x4e,0x37 +,0x3f,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x80,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x80,0xc6,0x06,0xe0,0x34,0x01,0xb8,0x00,0x00,0xc3,0xfe +,0x06,0xe1,0x34,0xc6,0x06,0xe0,0x34,0x00,0xa1,0x26,0x02,0x0b,0xc0,0x74,0x01,0xc3 +,0xe8,0x04,0x00,0xb8,0x00,0x00,0xc3,0xa1,0xa9,0x36,0xe7,0x00,0x8b,0x1e,0xab,0x36 +,0x83,0xe3,0x06,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc3,0x0d,0x10,0x00,0xe7,0x02,0xa1 +,0xad,0x36,0xe7,0x04,0xc3,0xb8,0x0a,0x00,0xe7,0x84,0xfe,0x06,0xe5,0x34,0xc6,0x06 +,0xe3,0x34,0x01,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x40,0x74,0x07 +,0x26,0x81,0x0e,0x08,0x00,0x00,0x40,0xc3,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xfe,0x06 +,0xe4,0x34,0xc6,0x06,0xe3,0x34,0x00,0xc3,0xc3,0xf6,0x06,0x18,0x34,0x80,0x75,0x0d +,0xa1,0x18,0x34,0x0b,0x06,0x1a,0x34,0x0b,0x06,0x1c,0x34,0x75,0x01,0xc3,0xa1,0x2e +,0x34,0x25,0xff,0xfe,0x8b,0x16,0xe7,0x36,0x81,0xe2,0x00,0x01,0x0b,0xc2,0xa3,0x2e +,0x34,0x8d,0x16,0x10,0x00,0xbf,0x00,0x00,0xb9,0x08,0x00,0x8b,0x85,0x00,0x34,0xef +,0x83,0xc2,0x10,0x8b,0x85,0x02,0x34,0xef,0x83,0xc2,0x10,0x8b,0x85,0x04,0x34,0xef +,0x83,0xc2,0xe2,0x83,0xc7,0x06,0x49,0x75,0xe2,0xb8,0x00,0x00,0x8e,0xc0,0xbe,0x00 +,0x34,0xbf,0xb9,0x36,0xb9,0x18,0x00,0xf3,0xa5,0xb8,0x00,0x00,0xc3,0x33,0xc0,0x8e +,0xc0,0x8d,0x3e,0xb0,0x33,0xb9,0x08,0x00,0xf3,0xab,0x8d,0x3e,0x3e,0x34,0xb9,0x03 +,0x00,0xf3,0xab,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xba +,0x33,0xe5,0x56,0x0d,0x20,0x00,0xe7,0x56,0xba,0x7a,0x00,0xed,0x08,0x26,0x94,0x36 +,0x33,0xc0,0xb1,0x08,0x32,0xed,0x06,0x8e,0xc0,0x8d,0x3e,0xe0,0xff,0xf3,0xaa,0x8e +,0x06,0x32,0x34,0x26,0x81,0x0e,0x08,0x00,0x00,0x02,0x07,0xe5,0x56,0x25,0xdf,0xff +,0xe7,0x56,0xe9,0xf8,0xfc,0x00,0xbd,0x1b,0x10,0x1b,0xd9,0x1a,0xf3,0x1a,0x50,0x51 +,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb6,0x33,0x53 +,0x06,0x51,0xe5,0x80,0xa3,0xb4,0x33,0x8b,0xd8,0x8b,0xc8,0x25,0x10,0x00,0xa3,0xed +,0x34,0x0b,0xc0,0x74,0x14,0xff,0x06,0x80,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x03 +,0xe9,0x06,0x00,0xb8,0x80,0x00,0xe8,0x9d,0x04,0x83,0xe3,0x03,0xd1,0xe3,0x2e,0xff +,0x97,0x86,0x1a,0x59,0x07,0x5b,0xe9,0xa4,0xfc,0xba,0x20,0x00,0x8e,0x06,0x3c,0x34 +,0x83,0x3e,0x3c,0x34,0x00,0x75,0x03,0xe9,0xf0,0x00,0xc7,0x06,0x3c,0x34,0x00,0x00 +,0xe9,0x2a,0x00,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0x83,0x3e,0x3a,0x34,0x00,0x75 +,0x03,0xe9,0xd5,0xff,0xc7,0x06,0x3a,0x34,0x00,0x00,0xe8,0x10,0x00,0xe9,0xc9,0xff +,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0xc7,0x06,0x3a,0x34,0x00,0x00,0x26,0xa1,0x14 +,0x00,0x26,0xa3,0x0c,0x00,0x26,0xa1,0x16,0x00,0x26,0xa3,0x0e,0x00,0x26,0xc6,0x06 +,0x0a,0x00,0x00,0xc1,0xea,0x02,0x23,0xd1,0x74,0x1c,0xba,0x20,0x00,0x26,0xc7,0x06 +,0x0e,0x00,0xea,0x05,0x26,0x0b,0x16,0x0c,0x00,0x26,0x89,0x16,0x0c,0x00,0xff,0x06 +,0x86,0x34,0xff,0x06,0xdc,0x33,0x26,0xa1,0x0c,0x00,0xa9,0x00,0x37,0x74,0x16,0x26 +,0xc6,0x06,0x0a,0x00,0x02,0xa9,0x00,0x30,0x74,0x04,0xff,0x06,0x7a,0x34,0xff,0x06 +,0xda,0x33,0xe9,0x49,0x00,0xc0,0xec,0x07,0x83,0x16,0x8a,0x34,0x00,0x24,0x07,0x3c +,0x07,0x75,0x04,0xff,0x06,0x8c,0x34,0xff,0x06,0x7e,0x34,0xa1,0x30,0x34,0x8c,0xc3 +,0x8e,0xc0,0x8e,0xdb,0x26,0x83,0x0e,0x08,0x00,0x40,0x8c,0xd8,0x26,0x87,0x06,0x16 +,0x00,0x26,0x83,0x3e,0x14,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x8c,0x1e,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x8c,0x1e,0x14,0x00,0x33,0xc0,0x8e,0xd8,0xc3,0xc3,0x8c,0xc0 +,0x87,0x06,0x92,0x01,0x3d,0xff,0xff,0x74,0x0d,0x8e,0xd8,0x8c,0x06,0x00,0x00,0x33 +,0xc0,0x8e,0xd8,0xe9,0x04,0x00,0x8c,0x06,0x90,0x01,0xe8,0x01,0x00,0xc3,0x06,0x83 +,0x3e,0x90,0x01,0xff,0x74,0x29,0x83,0x3e,0x3a,0x34,0x00,0x75,0x11,0xba,0x86,0x00 +,0xe8,0x1e,0x00,0x8c,0x06,0x3a,0x34,0x83,0x3e,0x90,0x01,0xff,0x74,0x11,0x83,0x3e +,0x3c,0x34,0x00,0x75,0x0a,0xba,0x88,0x00,0xe8,0x06,0x00,0x8c,0x06,0x3c,0x34,0x07 +,0xc3,0xa1,0x90,0x01,0x8e,0xc0,0x26,0xa1,0x08,0x00,0xef,0x26,0xa1,0x00,0x00,0x26 +,0xc7,0x06,0x00,0x00,0xff,0xff,0xa3,0x90,0x01,0x3d,0xff,0xff,0x75,0x03,0xa3,0x92 +,0x01,0x83,0x3e,0xed,0x34,0x00,0x74,0x0b,0xb8,0x10,0x00,0xe7,0x84,0xc7,0x06,0xed +,0x34,0x00,0x00,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xbc,0x33,0xe9,0x25,0xfb,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33 +,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb0,0x33,0xe9,0x11,0xfb,0x50,0x51,0x56,0x57 +,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb4,0x33,0x06,0xff,0x06 +,0x76,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x04,0x07,0xe9,0xf0,0xfa,0xb8,0x80,0x00 +,0xe8,0xd3,0x02,0x07,0xe9,0xe6,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x1d,0x08,0x1d,0x91,0x1e,0x5d,0x1e,0x73,0x1e,0x89,0x1e,0x91,0x1e,0xa8,0x1d +,0x91,0x1e,0x91,0x1e,0xaf,0x1e,0xaf,0x1e,0x15,0x1d,0x15,0x1d,0x91,0x1e,0x99,0x1f +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00 +,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00 +,0x07,0xe9,0x99,0xfa,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xb2,0x33,0x06,0x68,0xf6,0x1c,0xe5,0x06,0xa3,0xb2,0x33,0x8b,0xf0 +,0x83,0xe6,0x1e,0x2e,0xff,0xa4,0xa0,0x1c,0xe5,0x0c,0xa9,0x80,0x00,0x74,0x06,0xe8 +,0xa4,0x01,0xe5,0x06,0xc3,0x53,0xe5,0x0c,0x8b,0xd8,0xa9,0x01,0x00,0x74,0x14,0x83 +,0x3e,0xe0,0x3a,0x00,0x74,0x0d,0x8e,0x06,0x38,0x34,0xe8,0xbf,0x06,0xc7,0x06,0xe0 +,0x3a,0x00,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7 +,0x02,0x8b,0xc3,0x5b,0xa9,0x01,0x00,0x74,0x01,0xc3,0x8b,0xd0,0xb8,0x00,0x08,0xe7 +,0x84,0x8b,0xc2,0x8e,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0x8b,0xd0,0xc1,0xe0,0x03 +,0x83,0x16,0x88,0x34,0x00,0xff,0x06,0x7c,0x34,0x26,0x83,0x3e,0x06,0x00,0x0a,0x75 +,0x21,0x8b,0xc2,0x25,0x40,0x18,0x3d,0x40,0x00,0x74,0x0c,0x3d,0x00,0x10,0x75,0x12 +,0x26,0xfe,0x0e,0x0a,0x00,0x74,0x0b,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x03,0xe9 +,0x5a,0x06,0x8c,0xc0,0x26,0x8e,0x06,0x02,0x00,0x26,0x83,0x0e,0x08,0x00,0x20,0x26 +,0xa3,0x12,0x00,0x26,0xa3,0x10,0x00,0xc3,0xff,0x06,0xc4,0x33,0xe5,0x0c,0xa9,0x01 +,0x00,0x75,0x01,0xc3,0xa9,0xf0,0x07,0x74,0x01,0xc3,0xff,0x06,0xd4,0x33,0xe5,0x00 +,0x0d,0x18,0x00,0xe7,0x00,0xc3,0xff,0x06,0xca,0x33,0x80,0x3e,0xa0,0x36,0x08,0x75 +,0x14,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26,0x81 +,0x0e,0x08,0x00,0x00,0x08,0xe5,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe5,0x0c,0x50,0xe5 +,0x80,0x25,0x00,0x07,0xa3,0xe4,0x3a,0xe5,0x8c,0x25,0x00,0x80,0xa3,0xe2,0x3a,0x58 +,0xa9,0x02,0x00,0x75,0x25,0x83,0x3e,0xe2,0x3a,0x00,0x75,0x1e,0x83,0x3e,0xe4,0x3a +,0x00,0x75,0x17,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe8,0x6a,0x01 +,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xe9,0x21,0x00,0xe8,0x1a,0x06,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0x80,0x3e,0x9f,0x36,0x06 +,0x75,0x05,0x83,0x0e,0x99,0x36,0x40,0xb8,0x00,0x01,0xe9,0x09,0x01,0xff,0x06,0xcc +,0x33,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xff,0x06,0xc6,0x34 +,0xe9,0x1e,0x00,0xff,0x06,0xce,0x33,0xff,0x06,0x95,0x37,0x81,0x26,0xaf,0x36,0xff +,0xef,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x08,0x00,0xff,0x06,0xd0,0x33,0xff,0x06,0x7a +,0x34,0xff,0x06,0xd2,0x33,0xd1,0xe6,0x8e,0x06,0x30,0x34,0x2e,0x8b,0x84,0xc0,0x1c +,0x26,0x09,0x06,0x08,0x00,0x2e,0x8b,0x84,0xc2,0x1c,0x09,0x06,0x66,0x37,0xc3,0xe5 +,0x0c,0xa9,0x80,0x00,0x74,0x56,0x50,0xe8,0xf0,0x00,0x58,0xa9,0x00,0x01,0x75,0x07 +,0xff,0x06,0xc6,0x33,0xe9,0x08,0x00,0xff,0x06,0x78,0x34,0xff,0x06,0xc8,0x33,0xe5 +,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe8,0x6e,0x05,0xba,0x10,0x01,0xed,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x1d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x03,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xc3,0xa9,0x01,0x00,0x74 +,0x1c,0xe8,0x2c,0x00,0x83,0x3e,0xe0,0x3a,0x00,0x74,0x0f,0x06,0x8e,0x06,0x38,0x34 +,0xe8,0xc9,0x04,0xc7,0x06,0xe0,0x3a,0x00,0x00,0x07,0xe9,0x5d,0x00,0x8b,0xd0,0x8e +,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0xe8,0x06,0x00,0x68,0x69,0x1d,0xe9,0x4a,0x00 +,0xa9,0x00,0x04,0x74,0x0a,0xb8,0x00,0x04,0xff,0x06,0xd8,0x33,0xe9,0x17,0x00,0xa9 +,0x00,0x01,0x74,0x0a,0xff,0x06,0x39,0x37,0xb8,0x00,0x01,0xe9,0x08,0x00,0xa9,0x10 +,0x00,0xb8,0x10,0x00,0x74,0x1d,0x09,0x06,0x66,0x37,0x8c,0xc0,0x8e,0x06,0x30,0x34 +,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01 +,0x8e,0xc0,0xc3,0xff,0x06,0xc2,0x33,0xe9,0xf8,0xff,0xe5,0x00,0x0d,0x18,0x00,0xe7 +,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0xc3,0x58,0xe9,0x43,0xfd,0xe5,0x08,0x0d +,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe9,0xe0,0xff,0xe5,0x0e,0xa9,0x00,0x08,0x75 +,0x01,0xc3,0xe9,0xf5,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb8 +,0x33,0xe5,0x48,0x06,0x53,0x57,0xff,0x16,0x4e,0x37,0x5f,0x5b,0x83,0x3e,0x80,0x01 +,0xff,0x74,0x58,0x8e,0x06,0x80,0x01,0x26,0xff,0x0e,0x08,0x00,0x75,0x4d,0x26,0xa1 +,0x00,0x00,0xa3,0x80,0x01,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8c,0xc0,0x26,0x8e +,0x06,0x02,0x00,0x26,0x81,0x0e,0x08,0x00,0x80,0x00,0x8b,0xd0,0x26,0x87,0x06,0x1a +,0x00,0x26,0x83,0x3e,0x18,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x89,0x16,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x89,0x16,0x18,0x00,0x83,0x3e,0x80,0x01,0xff,0x74,0x0c,0x8e +,0x06,0x80,0x01,0x26,0x83,0x3e,0x08,0x00,0x00,0x74,0xb3,0x07,0xe9,0x3e,0xf7,0xe5 +,0x4c,0x90,0xe5,0x02,0xa9,0x00,0x20,0x74,0x0d,0x25,0xff,0xdf,0x0d,0x01,0x00,0xe7 +,0x02,0x0d,0x00,0x20,0xe7,0x02,0xe5,0x0a,0x8b,0xd8,0xa3,0xf4,0x33,0x25,0xc3,0x57 +,0x0d,0x00,0x10,0xe7,0x0a,0xf7,0x06,0x9b,0x36,0x00,0x80,0x74,0x37,0xf7,0xc3,0x00 +,0x80,0x74,0x06,0xf7,0xc3,0x00,0x08,0x74,0x5d,0x81,0x26,0xc2,0x34,0x7f,0xff,0xc7 +,0x06,0x35,0x37,0x05,0x00,0xb8,0x80,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0xff,0x7f +,0xc7,0x06,0x0f,0x37,0x04,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x03,0x00,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x2a,0xf7,0xc3,0x00,0x08 +,0x74,0x24,0x80,0x3e,0x9d,0x36,0x06,0x7c,0x1d,0xff,0x06,0x94,0x34,0x83,0x0e,0x66 +,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x01,0xf7,0xc3,0x00,0x20,0x75,0x3b,0xf7,0x06,0x9a,0x37 +,0x80,0x00,0x74,0x0b,0xff,0x06,0x89,0x37,0x33,0xc0,0xe7,0x0e,0xe9,0x04,0x00,0xff +,0x06,0x3b,0x37,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x1c,0x80,0x26,0x9e,0x36,0xff +,0x75,0x15,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x08,0xc3,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x02,0x23,0x02,0x23,0x02,0x23,0x02,0x23,0x03,0x23,0xdd,0x22,0x02,0x23,0xfd,0x21 +,0x02,0x23,0xa4,0x24,0xf3,0x24,0x02,0x23,0x8d,0x22,0x7a,0x23,0x02,0x23,0x97,0x24 +,0x1b,0x24,0x75,0x24,0x02,0x23,0x02,0x23,0x8e,0x25,0xfb,0x8e,0x06,0x7e,0x01,0xfb +,0x26,0x83,0x3e,0x00,0x00,0xff,0x74,0xf2,0x26,0x8e,0x06,0x00,0x00,0xfa,0x26,0x8b +,0x1e,0x08,0x00,0x26,0x23,0x1e,0x0a,0x00,0x74,0xe5,0x8c,0xc0,0x8e,0xd0,0x26,0x8b +,0x26,0x02,0x00,0x8c,0x16,0xf2,0x33,0x22,0xff,0x75,0x6a,0x26,0xa1,0x1c,0x00,0x8a +,0xe3,0x8a,0xdc,0x22,0xd8,0x75,0x0d,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0xf2,0xb0 +,0x80,0xe9,0xed,0xff,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0x02,0xb0,0x80,0x32,0xe4 +,0x26,0xa3,0x1c,0x00,0xf7,0xc3,0x08,0x00,0x75,0x47,0x2e,0x8a,0x9f,0xc5,0x25,0x2e +,0x8b,0xbf,0xc5,0x26,0x80,0xc3,0x10,0x26,0x8e,0x1d,0x26,0x8c,0x1e,0x06,0x00,0x8b +,0x16,0x00,0x00,0xc7,0x06,0x00,0x00,0xff,0xff,0x26,0x89,0x15,0x83,0xfa,0xff,0x75 +,0x0a,0x2e,0x8b,0x97,0xcd,0x26,0x26,0x21,0x16,0x08,0x00,0x33,0xc0,0x8e,0xd8,0x26 +,0x89,0x1e,0x04,0x00,0xc3,0x8a,0xdf,0xb7,0x00,0x2e,0x8a,0x9f,0xc5,0x25,0xe9,0xe0 +,0xff,0x26,0x83,0x26,0x08,0x00,0xf7,0x83,0xc3,0x10,0xe9,0xde,0xff,0x60,0x06,0x1e +,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x8b,0x0e,0x34,0x34,0x39,0x0e +,0xf2,0x33,0x74,0x0e,0x26,0x81,0x0e,0x0a,0x00,0x00,0x02,0x26,0x81,0x0e,0x08,0x00 +,0x00,0x02,0x26,0x89,0x26,0x02,0x00,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00 +,0x36,0x89,0x26,0x02,0x00,0x36,0x89,0x1e,0x20,0x00,0x36,0xc7,0x06,0x08,0x00,0x00 +,0x00,0xb9,0x04,0x00,0xbe,0x00,0x00,0x2e,0x8b,0xbc,0xc5,0x26,0x36,0xc7,0x05,0xff +,0xff,0x36,0xc7,0x45,0x02,0xff,0xff,0x83,0xc6,0x02,0xe2,0xeb,0x8e,0x06,0x7e,0x01 +,0x36,0x8b,0x0e,0x22,0x00,0x8c,0xc0,0x26,0x83,0x3e,0x00,0x00,0xff,0x26,0x8e,0x06 +,0x00,0x00,0x74,0x07,0x26,0x3b,0x0e,0x22,0x00,0x7d,0xea,0x36,0x8c,0x06,0x00,0x00 +,0x8e,0xc0,0x26,0x8c,0x16,0x00,0x00,0xfb,0x36,0xff,0x2e,0x1e,0x00,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x26,0x09,0x36,0x08,0x00,0xf7,0xc6,0x00,0xff,0x74,0x01 +,0xc3,0x56,0x52,0x2e,0x8b,0xb4,0xc5,0x25,0x81,0xe6,0xff,0x00,0x2e,0x8b,0xb4,0xc5 +,0x26,0x8c,0xc2,0x8e,0xc0,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8e,0xc2,0x26,0x83 +,0x3c,0xff,0x74,0x0f,0x8b,0xd0,0x26,0x87,0x54,0x02,0x8e,0xc2,0x26,0xa3,0x00,0x00 +,0xe9,0x07,0x00,0x26,0x89,0x44,0x02,0x26,0x89,0x04,0x5a,0x5e,0xc3,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x26,0xa3,0x0a,0x00,0x26,0x89,0x26 +,0x02,0x00,0xa1,0x34,0x34,0x8e,0xd0,0x8d,0x26,0x80,0x00,0x8c,0x16,0xf2,0x33,0xe9 +,0x4d,0xfe,0xcf,0x50,0x1e,0x52,0x53,0x33,0xc0,0x8e,0xd8,0x26,0x83,0x3e,0x04,0x00 +,0xff,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,0x74,0x03,0xe9,0x1a,0x00,0x83,0x3e,0xe6 +,0x3a,0x02,0x76,0x13,0xff,0x06,0xd6,0x33,0x8c,0xc0,0x8e,0x06,0x32,0x34,0xbe,0x40 +,0x00,0x68,0x3a,0x23,0xe9,0x5e,0xff,0xe8,0x84,0xf8,0x5b,0x5a,0x1f,0x58,0xcf,0xe8 +,0xe1,0x00,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0x8a,0x1e,0x29,0x00,0x88,0x1e,0x1b +,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c,0x26,0xa1 +,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x80,0xfb,0x08,0x74,0x09,0x0d,0x18,0xac,0xe7,0x00 +,0x07,0x1f,0x58,0xcf,0x0d,0x18,0x00,0xe9,0xf4,0xff,0x50,0x1e,0x06,0x33,0xc0,0x8e +,0xd8,0x83,0x3e,0xa1,0x36,0x00,0x75,0xb7,0x26,0x8b,0x36,0x06,0x00,0x2e,0xff,0x94 +,0xdc,0x23,0x07,0x1f,0x58,0xcf,0xe8,0x8a,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00 +,0xe8,0x49,0x00,0xc3,0x53,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x2d,0xe5,0x8c,0x25 +,0x00,0x70,0x8b,0xd8,0xe5,0x8c,0x25,0x00,0x70,0x3b,0xc3,0x74,0x05,0x8b,0xd8,0xe9 +,0xf2,0xff,0x3d,0x00,0x30,0x75,0x10,0xe5,0x02,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06 +,0xe0,0x3a,0xff,0xff,0xe9,0x03,0x00,0xe8,0x12,0x00,0x5b,0xc3,0xa3,0x23,0x96,0x23 +,0xa4,0x23,0xa4,0x23,0x96,0x23,0xa4,0x23,0x96,0x23,0x96,0x23,0x26,0xa0,0x29,0x00 +,0xa2,0x1b,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c +,0x26,0xa1,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x25,0xff,0x53,0x26,0x8b,0x36,0x06,0x00 +,0x83,0xe6,0x0e,0x2e,0x0b,0x84,0xad,0x25,0xe7,0x00,0xc3,0x06,0x1e,0x68,0x8b,0x25 +,0x6a,0x00,0x1f,0x83,0x0e,0xef,0x34,0x20,0x83,0x0e,0x9b,0x36,0x08,0xe5,0x00,0x25 +,0xef,0xff,0x0d,0x08,0x00,0xe7,0x00,0xe5,0x00,0xa9,0x10,0x00,0x75,0x01,0xc3,0xe5 +,0x00,0xa9,0x10,0x00,0x75,0xf9,0xc3,0x50,0x53,0x51,0x56,0x06,0x1e,0x33,0xc0,0x8e +,0xd8,0xb8,0x05,0x00,0xe7,0x84,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08 +,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0x1f,0x07 +,0x5e,0x59,0x5b,0x58,0xc3,0x50,0x1e,0x33,0xc0,0x8e,0xd8,0xc7,0x06,0xef,0x34,0x00 +,0x00,0x83,0x26,0x9b,0x36,0xf7,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d +,0x11,0x00,0xe7,0x02,0x1f,0x58,0xcf,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f +,0xe8,0x16,0xf5,0xc3,0x06,0x1e,0x68,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x26,0x83 +,0x3e,0x0a,0x00,0x00,0x74,0x03,0xe8,0x43,0x00,0x26,0xc7,0x06,0x0a,0x00,0xff,0xff +,0x26,0x8b,0x16,0x06,0x00,0x8e,0x1e,0x8e,0x01,0x8c,0xd8,0x8b,0xca,0x83,0x3e,0x00 +,0x00,0xff,0x8e,0x1e,0x00,0x00,0x74,0x0a,0x2b,0x16,0x08,0x00,0x73,0xeb,0x29,0x0e +,0x08,0x00,0x26,0x89,0x0e,0x08,0x00,0x26,0x8c,0x1e,0x00,0x00,0x8e,0xd8,0x8c,0x06 +,0x00,0x00,0xc3,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x8b,0xc8 +,0x8e,0x1e,0x8e,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x8c,0xd8,0x83,0x3e,0x00 +,0x00,0xff,0x74,0x25,0x3b,0x0e,0x00,0x00,0x8e,0x1e,0x00,0x00,0x75,0xed,0x8e,0xd8 +,0x26,0xa1,0x00,0x00,0xa3,0x00,0x00,0x3d,0xff,0xff,0x74,0x56,0x8e,0xd8,0x26,0xa1 +,0x08,0x00,0x01,0x06,0x08,0x00,0xe9,0x49,0x00,0x26,0x8e,0x1e,0x02,0x00,0xbe,0x18 +,0x00,0x83,0x3c,0xff,0x74,0x3c,0x39,0x0c,0x74,0x19,0x8e,0x1c,0xbe,0x00,0x00,0x83 +,0x3e,0x00,0x00,0xff,0x74,0x2c,0x39,0x0e,0x00,0x00,0x74,0x07,0x8e,0x1e,0x00,0x00 +,0xe9,0xec,0xff,0x26,0xa1,0x00,0x00,0x89,0x04,0x33,0xc9,0x8e,0xd9,0x3d,0xff,0xff +,0x75,0x10,0x83,0xfe,0x18,0x75,0x0b,0x26,0x8e,0x1e,0x02,0x00,0x81,0x26,0x08,0x00 +,0x7f,0xff,0x33,0xc0,0x8e,0xd8,0xc3,0x1f,0x07,0x61,0xcf,0x1f,0x07,0xcf,0x60,0x06 +,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75 +,0xf6,0xb9,0x08,0x00,0xe5,0x58,0xe7,0x5a,0x23,0xc0,0xe0,0xf8,0xc3,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x00,0x00,0x00,0xa8,0x00,0x8c,0x02,0x04,0x00 +,0x00,0x08,0x10,0x20,0x00,0xff,0x0e,0x0c,0x0c,0x0a,0x0a,0x0a,0x0a,0x08,0x08,0x08 +,0x08,0x08,0x08,0x08,0x08,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06 +,0x06,0x06,0x06,0x06,0x06,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x10,0x00,0x0c,0x00,0xff,0x7f,0xff +,0xbf,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0x7f,0xff,0xbf +,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,0x00,0x00,0x00 +,0x80,0x3e,0xe2,0x34,0x01,0x76,0x03,0xe9,0xa5,0x00,0xb8,0x00,0x00,0xe7,0x4e,0xb9 +,0x28,0x00,0xe2,0xfe,0xc6,0x06,0x45,0x37,0x02,0xbf,0x3f,0x28,0x2e,0x8b,0x45,0x08 +,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x1d,0xc7,0x06,0xb3,0x36,0x40,0x11 +,0xc7,0x06,0xb1,0x36,0x27,0x00,0xc7,0x06,0x46,0x37,0x02,0x00,0xc7,0x06,0x48,0x37 +,0x64,0x00,0xf7,0x06,0xb5,0x36,0x02,0x00,0x75,0x1c,0x2e,0x0b,0x5d,0x02,0x81,0x26 +,0xb3,0x36,0xff,0xfe,0xc7,0x06,0xb1,0x36,0x9c,0x00,0xc7,0x06,0x46,0x37,0x08,0x00 +,0xc7,0x06,0x48,0x37,0x90,0x01,0x89,0x1e,0xb7,0x36,0x89,0x1e,0xfe,0x33,0xbe,0x20 +,0x00,0x8b,0xc3,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x45,0x04,0xe7,0x4e +,0xb9,0x28,0x00,0xe2,0xfe,0xe5,0x4e,0x8b,0xcb,0x2e,0x23,0x45,0x06,0x2e,0x23,0x4d +,0x06,0x3a,0xc1,0x74,0x36,0x4e,0x75,0xd9,0x80,0x3e,0x45,0x37,0x00,0x74,0x0b,0xc6 +,0x06,0x45,0x37,0x00,0xbf,0x2f,0x28,0xe9,0x72,0xff,0xc6,0x06,0x45,0x37,0x01,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x14,0xe5,0xce,0x25,0xfd,0xff,0xe7,0xce,0xe8,0x43 +,0x00,0xe5,0xce,0x0d,0x02,0x00,0xe7,0xce,0xe8,0x39,0x00,0x80,0x3e,0xe2,0x34,0x01 +,0x76,0x01,0xc3,0xb8,0xea,0x05,0xe7,0x8c,0xfa,0xe8,0x12,0xf4,0xfb,0x8d,0x06,0xd0 +,0x39,0x8b,0xd8,0xc1,0xe8,0x04,0xa3,0x38,0x34,0x8e,0xc0,0xa1,0x30,0x34,0x26,0xa3 +,0x02,0x00,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x83,0xc3,0x18,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0xc3,0xe5,0x02,0x0d,0x00,0x40,0xe7,0x02,0xe5,0x00,0x0d,0x04,0x00 +,0xe7,0x00,0xb8,0x00,0x00,0xe7,0x0a,0xe5,0x0a,0xa9,0x00,0x80,0x75,0x14,0xe5,0x08 +,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x0a,0x0d,0x00,0x08,0xb9,0x05,0x00,0xe7,0x0a,0xe2 +,0xfc,0xc3,0xe5,0x08,0x0d,0x00,0x10,0xb9,0x05,0x00,0xe7,0x08,0xe2,0xfc,0xc3,0x04 +,0x0c,0x20,0x00,0x01,0x0c,0x7e,0xff,0x00,0x0c,0x02,0x00,0x10,0x00,0x40,0x00,0x0c +,0xc6,0x01,0x00,0x00,0xc0,0xf7,0xff,0x00,0xc0,0x02,0x00,0x10,0x00,0x40,0x00,0x00 +,0x33,0xc0,0x8e,0xd8,0x8d,0x3e,0x72,0x49,0x8d,0x36,0xb0,0x37,0xb9,0x14,0x00,0x8b +,0x1e,0x30,0x34,0x89,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05 +,0x89,0x44,0x04,0x83,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xc6,0x06,0x9e,0x36,0x0e +,0xe8,0xfd,0x26,0x68,0x83,0x28,0xa1,0xaa,0x02,0xcd,0x35,0x83,0x3e,0xa1,0x36,0x00 +,0x74,0x03,0xe9,0x3b,0x27,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e +,0xff,0xa4,0x2e,0x30,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x01,0x00,0xc6 +,0x06,0xca,0x34,0x01,0xe9,0x7d,0x19,0x80,0x3e,0xa0,0x36,0x08,0x74,0xe6,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x1a,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x12,0xf7,0x06,0x9b +,0x36,0x03,0x00,0x75,0x0a,0x83,0x0e,0x66,0x37,0x10,0xc6,0x06,0xa0,0x36,0x08,0xe9 +,0xfb,0x01,0x80,0x3e,0x9e,0x36,0x02,0x75,0xce,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xec +,0x01,0xc3,0xe9,0xe8,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x26,0xff,0x26,0x04 +,0x00,0xa1,0xd1,0x36,0x26,0x39,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39 +,0x06,0x1c,0x00,0x75,0x18,0xa1,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26 +,0xf7,0x06,0x0c,0x00,0x40,0x00,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf +,0x36,0x00,0x10,0xa1,0xaf,0x36,0xe7,0x06,0x80,0x3e,0x9d,0x36,0x02,0x75,0x06,0xcd +,0x34,0xe9,0xa2,0x1a,0xc3,0xf7,0x06,0x9b,0x36,0x10,0x00,0x75,0x54,0x26,0xf6,0x06 +,0x0a,0x00,0xff,0x75,0x4c,0x26,0xa0,0x19,0x00,0x24,0xc0,0x3c,0x40,0x75,0x11,0x80 +,0x3e,0x95,0x36,0x00,0x74,0x3b,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0xe9,0x31,0x00 +,0xe8,0xf1,0x04,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0x2f,0x8b,0xd8,0xb8,0x7d,0x03 +,0xcd,0x3a,0x8b,0xc3,0xc6,0x06,0xa0,0x36,0x06,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75 +,0x05,0xc6,0x06,0xa0,0x36,0x04,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83,0x26,0x9b,0x36 +,0xfc,0xe9,0x23,0x01,0xe8,0x87,0x1d,0xe9,0x33,0x01,0x50,0x26,0xa1,0x0c,0x00,0x25 +,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x84,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9 +,0x7c,0x00,0x83,0x3e,0xe8,0x3a,0x04,0x74,0x75,0x83,0x3e,0xe8,0x3a,0x02,0x74,0x6e +,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00 +,0x80,0x74,0x35,0x26,0x80,0x3e,0x29,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36 +,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x74,0x45 +,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1 +,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b +,0x26,0x80,0x3e,0x19,0x00,0x00,0x74,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10 +,0x00,0x74,0x12,0x26,0xa0,0x28,0x00,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7 +,0x06,0x04,0x00,0xff,0xff,0x58,0x23,0xc0,0x74,0x03,0xe9,0x57,0xff,0x81,0x26,0x9b +,0x36,0xff,0xfe,0x83,0xfe,0x06,0x7f,0x24,0x26,0xa1,0x20,0x00,0x3b,0x06,0xd1,0x36 +,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10,0x26,0xa1,0x24,0x00 +,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01,0x26,0xa1,0x20,0x00 +,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba,0x34,0x26,0xa1,0x24 +,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1,0xe6,0x80,0xfc,0x09 +,0x74,0x03,0xe8,0xaa,0x1c,0x8b,0xc6,0x2e,0xff,0xa4,0x30,0x49,0x26,0xa1,0x0c,0x00 +,0x3d,0xff,0x7f,0x74,0x0f,0x26,0xff,0x26,0x04,0x00,0x8e,0x06,0x38,0x34,0xe8,0x36 +,0x06,0xcd,0x50,0xc3,0xe9,0x16,0x00,0xcd,0x34,0xe9,0x11,0x00,0xcd,0x34,0x89,0x36 +,0x3d,0x37,0xa1,0x9d,0x36,0xa3,0x3f,0x37,0xc6,0x06,0xa0,0x36,0x0c,0xe8,0x8e,0x00 +,0xa1,0x9f,0x36,0x22,0xe4,0x75,0x32,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x2a,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x07,0x88,0x26,0x9e,0x36,0xe9,0x31,0x00,0x3a,0x06,0x9d +,0x36,0xa3,0x9d,0x36,0x74,0x28,0x8b,0xf0,0x2e,0xff,0xa4,0x0d,0x2b,0x44,0x29,0xee +,0x42,0x19,0x44,0xcd,0x44,0x2f,0x45,0x5a,0x45,0x3a,0x26,0x9e,0x36,0x75,0x01,0xc3 +,0x32,0xc0,0x86,0xc4,0x8b,0xf0,0xa2,0x9e,0x36,0x2e,0xff,0xa4,0x20,0x49,0x8b,0x2e +,0x99,0x36,0x23,0xed,0x75,0x01,0xc3,0xbf,0x01,0x00,0xbe,0x00,0x00,0x85,0xfd,0x75 +,0x1a,0x46,0xd1,0xe7,0xe9,0xf6,0xff,0x2a,0x00,0x29,0x00,0x28,0x00,0x27,0x00,0x25 +,0x00,0x05,0x00,0x07,0x00,0x26,0x00,0x06,0x00,0x20,0x00,0xf7,0xd7,0x21,0x3e,0x99 +,0x36,0xd1,0xe6,0x2e,0x8b,0xb4,0x47,0x2b,0xe9,0x4f,0xff,0xe9,0x56,0xff,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x17,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x0f,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x08,0xf7,0x06,0x66,0x37,0xff,0xff,0x75,0x07,0xc7,0x06,0x66,0x37 +,0x00,0x00,0xc3,0xf7,0x06,0x41,0x37,0x01,0x00,0x75,0x0b,0xb8,0x7f,0x03,0xcd,0x39 +,0xc7,0x06,0x41,0x37,0x01,0x00,0x33,0xf6,0xb8,0x00,0x40,0x85,0x06,0x66,0x37,0x74 +,0x21,0x80,0xbc,0x54,0x37,0xff,0x74,0x04,0xfe,0x84,0x54,0x37,0x80,0xbc,0x96,0x34 +,0xff,0x74,0x04,0xfe,0x84,0x96,0x34,0x31,0x06,0x66,0x37,0x83,0x3e,0x66,0x37,0x00 +,0x74,0x05,0x46,0xd1,0xe8,0x73,0xd4,0xc3,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b +,0xa9,0x00,0x10,0x75,0x09,0x8b,0x1e,0x43,0x37,0xff,0xe3,0xe9,0xd7,0x00,0xc7,0x06 +,0x35,0x37,0x05,0x00,0xc7,0x06,0x43,0x37,0x1e,0x2c,0xf7,0x06,0xf4,0x33,0x00,0x08 +,0x74,0x06,0xc7,0x06,0x43,0x37,0x10,0x2c,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xcd,0xfe +,0xa9,0x00,0x08,0x74,0xd9,0xff,0x0e,0x35,0x37,0x75,0xed,0xe9,0x66,0x00,0xa9,0x00 +,0x08,0x75,0xcb,0xff,0x0e,0x35,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x48,0x81,0x0e,0x9b,0x36,0x00,0x80,0xf7,0x06,0x9b,0x36 +,0x01,0x00,0x74,0x1e,0xb8,0x7d,0x03,0xcd,0x3a,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83 +,0x26,0x9b,0x36,0xfe,0xc7,0x06,0x0f,0x37,0x02,0x00,0xc6,0x06,0xa0,0x36,0x04,0xe9 +,0x7b,0xfe,0x80,0x3e,0xa0,0x36,0x04,0x75,0x07,0x83,0x3e,0x0f,0x37,0x01,0x75,0x05 +,0xc6,0x06,0xa0,0x36,0x06,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x5f,0xfe,0xbe,0x02 +,0x00,0xe9,0x4a,0xfe,0x80,0x26,0x9e,0x36,0xff,0x75,0x3a,0xf6,0x06,0x9d,0x36,0x80 +,0x74,0x2d,0xf7,0x06,0x9b,0x36,0x00,0x20,0x75,0x2b,0xc6,0x06,0xa0,0x36,0x06,0xff +,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a +,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01,0xe9,0x06,0x00,0xbe +,0x04,0x00,0xe9,0x09,0xfe,0x81,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06 +,0xe5,0x0a,0xa9,0x00,0x80,0x74,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36 +,0xe7,0x06,0xe9,0x09,0xff,0xe9,0xf5,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0x83,0x0e +,0x99,0x36,0x02,0xe9,0xe7,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0x1d,0xf7,0x06,0x9b +,0x36,0x00,0x40,0x75,0x05,0x83,0x0e,0x99,0x36,0x08,0x83,0x0e,0x99,0x36,0x20,0x81 +,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x85,0x03,0xcd,0x39,0xe9,0xc0,0xfd,0x80,0x3e,0x9e +,0x36,0x06,0x74,0x07,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x34,0xf6,0x06,0x9d,0x36,0x80 +,0x75,0x06,0xbe,0x07,0x00,0xe9,0x96,0xfd,0xc6,0x06,0xa0,0x36,0x04,0x83,0x3e,0x0f +,0x37,0x02,0x74,0x1b,0xc7,0x06,0x0f,0x37,0x04,0x00,0x80,0x3e,0x9e,0x36,0x06,0x75 +,0x0e,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xe9 +,0x7b,0xfd,0x80,0x3e,0x9d,0x36,0x04,0x75,0x12,0x81,0x0e,0xc2,0x34,0x00,0x40,0xff +,0x06,0x92,0x34,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x62,0xfd,0xbe,0x05,0x00,0xe9,0x4d +,0xfd,0xf6,0x06,0x9d,0x36,0x80,0x75,0x19,0x83,0x0e,0xc2,0x34,0x04,0xbe,0x06,0x00 +,0xe9,0x3b,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0xc5,0xff,0x06,0x31,0x37,0xe9,0x00 +,0x00,0x83,0x26,0xc2,0x34,0xbf,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x2f,0xfd,0xe5,0x0a +,0x50,0x25,0xc3,0xbf,0xe7,0x0a,0x58,0x80,0x26,0x9e,0x36,0xff,0x75,0x0d,0xa9,0x00 +,0x40,0x75,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x12,0xfd,0xb8,0x83,0x03,0xcd,0x39 +,0xc3,0xb8,0x7c,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09,0xc7,0x06 +,0x33,0x37,0x02,0x00,0xe9,0xf6,0xfc,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9,0xed,0xfc +,0xff,0x06,0x8e,0x34,0xe8,0xf7,0x19,0x83,0x0e,0xc2,0x34,0x08,0xbe,0x03,0x00,0xe9 +,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x04,0x05 +,0x04,0x04,0x04,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x04,0x00,0x08,0x08,0x05,0x08,0x08,0x08,0x00,0x03,0x00,0x03,0x03,0x00,0x00 +,0x02,0x04,0x04,0x04,0x04,0x00,0x00,0x08,0x00,0x00,0x0a,0x14,0x00,0x00,0x1a,0x00 +,0x1c,0x00,0x1e,0x20,0x00,0x00,0x04,0x41,0x06,0x0b,0x08,0xc2,0xff,0xe7,0x04,0x03 +,0x06,0x04,0x04,0x05,0x04,0x06,0x04,0x87,0x04,0x03,0x06,0x04,0x04,0x85,0x4e,0xa2 +,0x04,0xcf,0x04,0xcd,0xc7,0x06,0xa2,0x37,0x00,0x00,0xc7,0x06,0xa6,0x37,0x00,0x00 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xf5,0x36,0x26,0xa1,0x22,0x00,0xa3,0xf7 +,0x36,0x26,0xa1,0x24,0x00,0xa3,0xf9,0x36,0xe8,0x3b,0x19,0x8b,0xf0,0x26,0x8b,0x0e +,0x0e,0x00,0x2b,0xc8,0x83,0xe9,0x0e,0xb8,0x01,0x80,0x83,0xf9,0x04,0x7c,0x51,0x26 +,0x8a,0x54,0x28,0x88,0x16,0x1c,0x37,0x40,0x26,0x8b,0x6c,0x26,0x86,0xcd,0x3b,0xcd +,0x86,0xcd,0x89,0x0e,0xa4,0x37,0x75,0x38,0x40,0x32,0xff,0x26,0x8a,0x5c,0x29,0x80 +,0xfb,0x15,0x77,0x25,0x80,0xfb,0x0a,0x74,0x20,0x80,0xfb,0x01,0x74,0x1b,0xb8,0x04 +,0x80,0x2e,0x3a,0x97,0x02,0x2e,0x74,0x07,0x2e,0x3a,0x97,0x18,0x2e,0x75,0x11,0x33 +,0xc0,0x80,0xfb,0x09,0x75,0x4f,0x8b,0xf3,0xc3,0x26,0xc7,0x06,0x04,0x00,0xff,0xff +,0x50,0x52,0xa1,0xa4,0x37,0x86,0xc4,0x26,0x3b,0x06,0x26,0x00,0x7c,0x32,0x26,0x81 +,0x3e,0x26,0x00,0x00,0x04,0x7e,0x29,0x8d,0x74,0x2a,0x26,0x8b,0x14,0x22,0xd2,0x74 +,0x1f,0x80,0xe6,0xbf,0x80,0xfe,0x09,0x75,0x17,0xc7,0x06,0xa2,0x37,0x01,0x00,0x80 +,0xfa,0x04,0x75,0x0c,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34 +,0x5a,0x58,0xe9,0xb1,0xff,0xbd,0x72,0x37,0x2e,0x8a,0x87,0x2e,0x2e,0x22,0xc0,0x74 +,0x16,0x05,0x44,0x2e,0x8b,0xf8,0x2e,0x8b,0x05,0x3e,0x89,0x46,0x00,0x83,0xc5,0x02 +,0x83,0xc7,0x02,0x22,0xe4,0x7d,0xef,0x8d,0x74,0x2a,0x83,0xe9,0x04,0x75,0x03,0xe9 +,0xa1,0x00,0x26,0x8b,0x14,0x22,0xd2,0x75,0x03,0xe9,0x7c,0x00,0xc7,0x06,0xa6,0x37 +,0x01,0x00,0xbf,0x72,0x37,0x8b,0x05,0x83,0xc7,0x02,0x80,0xe6,0xbf,0x80,0xe4,0x3f +,0x80,0xfe,0x09,0x75,0x22,0x80,0xfa,0x04,0x75,0x5e,0xc7,0x06,0xa2,0x37,0x01,0x00 +,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34,0x86,0xc4,0xc7,0x06 +,0xa6,0x37,0x00,0x00,0xe9,0x47,0x00,0x3b,0xfd,0x7e,0x15,0x26,0x8b,0x04,0xa8,0x40 +,0x74,0x06,0xb8,0x07,0x80,0xe9,0x38,0xff,0x32,0xc0,0x26,0x8b,0x04,0xe9,0x2e,0x00 +,0x3a,0xf4,0x75,0xb1,0xc7,0x45,0xfe,0x00,0x00,0x80,0xfe,0x22,0x75,0x0d,0x3a,0xd0 +,0x77,0x16,0xc7,0x06,0xa6,0x37,0x00,0x00,0xe9,0x13,0x00,0x3a,0xd0,0x75,0x09,0xc7 +,0x06,0xa6,0x37,0x00,0x00,0xe9,0x06,0x00,0xb8,0x05,0x80,0xe9,0x02,0xff,0x32,0xf6 +,0x03,0xf2,0x2b,0xca,0xb8,0x05,0x80,0x23,0xc9,0x76,0x03,0xe9,0x64,0xff,0x74,0x03 +,0xe9,0xed,0xfe,0x33,0xc0,0xbf,0x72,0x37,0x8b,0x15,0x47,0x47,0x3b,0xfd,0x7f,0x1b +,0xf6,0xc6,0x80,0x74,0x16,0xf7,0x06,0xa6,0x37,0x01,0x00,0x74,0x06,0xb8,0x08,0x80 +,0xe9,0xc3,0xfe,0xf6,0xc6,0x40,0x74,0xe0,0xb8,0x07,0x80,0xe9,0xb8,0xfe,0x7d,0x42 +,0xa3,0x45,0x44,0x29,0x44,0x29,0xb7,0x28,0xe2,0x28,0xee,0x2b,0xf2,0x28,0xf5,0x28 +,0x01,0x29,0xac,0x2a,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x00,0x00 +,0x73,0x36,0x00,0x00,0x03,0x36,0xc5,0x35,0x83,0x35,0x45,0x35,0x07,0x35,0xd2,0x34 +,0x45,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0xa6,0x38,0x00,0x00,0xe0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xf2,0x33,0x00,0x00,0xa6,0x33,0x60,0x33,0xfd,0x32,0xbc,0x32,0x77,0x32,0x3c,0x32 +,0xfb,0x31,0x6a,0x31,0x0a,0x31,0xe0,0xe0,0x10,0x10,0x10,0xe0,0xe0,0xe0,0xe0,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0 +,0xe0,0x33,0xff,0x26,0xf6,0x06,0x1a,0x00,0x80,0x74,0x1b,0x26,0x80,0x26,0x1a,0x00 +,0x7f,0x26,0x8b,0x3e,0x26,0x00,0x83,0xe7,0x1f,0x74,0x0b,0x26,0x80,0x0e,0x20,0x00 +,0x80,0x26,0x01,0x3e,0x0e,0x00,0xc3,0x60,0x2e,0x8b,0x84,0xa6,0x30,0x26,0xa3,0x18 +,0x00,0xd1,0xe6,0x2e,0xff,0x94,0x50,0x30,0x61,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4 +,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x16,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26 +,0xc6,0x06,0x19,0x00,0x00,0xe8,0xbf,0x05,0xe8,0x98,0x05,0x26,0xc7,0x06,0x26,0x00 +,0x00,0x08,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x2a,0xbf,0x2a +,0x00,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x2a,0xa1,0x93,0x37,0x33,0xdb,0xa9 +,0x40,0x00,0x75,0x02,0xb3,0x01,0xa9,0x00,0x10,0x74,0x02,0xb7,0x88,0xa9,0x00,0x08 +,0x74,0x03,0x80,0xcf,0x44,0x26,0x89,0x5d,0x02,0xc3,0x83,0x0e,0xc2,0x34,0x20,0x26 +,0xc7,0x06,0x04,0x00,0x6b,0x2b,0x26,0xc7,0x06,0x0e,0x00,0x30,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0x69,0x05,0xe8,0x2c,0x05,0x26,0xc7,0x06,0x26,0x00,0x00,0x22,0x26,0xc6 +,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x29,0xbf,0x2a,0x00,0x26,0xc6,0x05 +,0x08,0x26,0xc6,0x45,0x01,0x2d,0x8d,0x7d,0x02,0xbe,0x54,0x37,0xb9,0x03,0x00,0xf3 +,0xa5,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x2e,0x8d,0x7d,0x02,0xbe,0x5a,0x37 +,0xb9,0x03,0x00,0xf3,0xa5,0xe8,0xd4,0x05,0xe8,0x64,0x05,0xb9,0x06,0x00,0xbe,0x54 +,0x37,0x8d,0x2e,0x2c,0x00,0x26,0x8b,0x46,0x00,0x29,0x04,0x83,0xc6,0x02,0x83,0xc5 +,0x02,0x83,0xf9,0x04,0x75,0x02,0x45,0x45,0xe2,0xeb,0xc3,0x26,0xc7,0x06,0x04,0x00 +,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00 +,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xe4,0x04,0xe8,0xa7,0x04,0x26,0xc7,0x06,0x26 +,0x00,0x00,0x16,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x28,0xbf +,0x2a,0x00,0xe8,0x5b,0x06,0xe8,0x74,0x05,0xe8,0x04,0x05,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1a,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xa3,0x04,0xe8,0x66,0x04,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x0c,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x27 +,0xbf,0x2a,0x00,0xe8,0x21,0x05,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a +,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x4b,0x04,0xe8,0x24,0x04,0x26 +,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29 +,0x00,0x26,0xbf,0x2a,0x00,0xe8,0xf4,0x04,0xe8,0x84,0x04,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x0d,0x04,0xe8,0xe6,0x03,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x26,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x25 +,0xbf,0x2a,0x00,0xe8,0xb6,0x04,0xe8,0x46,0x04,0xe8,0xfa,0x04,0xc3,0x26,0xc7,0x06 +,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x38,0x00,0xa1,0xa2,0x37,0x50,0x0b +,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x99,0x03,0xe8,0xa4,0xfd,0x26,0xc7,0x45 +,0x26,0x00,0x2a,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c +,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x24,0x83,0xc7,0x2a +,0xe8,0x29,0x04,0xe8,0xa0,0x04,0xe8,0x22,0x05,0xe8,0xf8,0x03,0xe8,0x09,0x04,0xc3 +,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x32,0x00,0x26,0xc7 +,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x45,0x03,0xe8,0x50 +,0xfd,0x26,0xc7,0x45,0x26,0x00,0x24,0xa1,0x1c,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45 +,0x28,0x26,0xc6,0x45,0x29,0x23,0x83,0xc7,0x2a,0xe8,0xe0,0x03,0xe8,0x6c,0x04,0xe8 +,0x8a,0x04,0xe8,0x9c,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06 +,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0xff,0x02,0xe8,0x0a,0xfd,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c,0x37 +,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x22,0x83,0xc7,0x2a,0xe8 +,0x9a,0x03,0xe8,0xc7,0x03,0xe8,0x57,0x03,0xe8,0xf8,0x03,0xe8,0x78,0x04,0xe8,0x8a +,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0x74,0x45,0x26,0xc7,0x06,0x0e,0x00,0x3e,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0xfc,0x02,0xe8,0xa9,0x02,0x83,0x3e,0x8d,0x37,0x03,0x75 +,0x01,0x90,0x26,0xc7,0x06,0x26,0x00,0x00,0x30,0x26,0xc6,0x06,0x28,0x00,0x50,0x26 +,0xc6,0x06,0x29,0x00,0x20,0xbf,0x2a,0x00,0xe8,0xd0,0x03,0xe8,0x01,0x03,0xe8,0xb5 +,0x03,0xe8,0x9f,0x03,0xc3,0x26,0xc7,0x06,0x04,0x00,0x61,0x43,0xb9,0xf0,0x00,0x83 +,0xe9,0x02,0x26,0x89,0x0e,0x0e,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0x26,0xc7,0x06,0x1a,0x00,0x00,0x00,0x26,0xc7,0x06,0x1c,0x00 +,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x00,0xe8,0x47,0x02,0x83,0xe9,0x0e,0x86 +,0xcd,0x26,0x89,0x0e,0x26,0x00,0x86,0xcd,0x26,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6 +,0x06,0x29,0x00,0x08,0xbf,0x2a,0x00,0x83,0xe9,0x04,0x26,0x89,0x0d,0x26,0xc6,0x45 +,0x01,0x26,0x8d,0x7d,0x02,0x83,0xe9,0x02,0xbb,0x01,0x00,0xb8,0x30,0x30,0x4b,0x75 +,0x17,0xbb,0x0a,0x00,0x8a,0xc4,0x26,0x88,0x05,0xb0,0x31,0x80,0xc4,0x01,0x80,0xfc +,0x3a,0x75,0x0a,0xb4,0x61,0xe9,0x05,0x00,0x26,0x88,0x05,0x04,0x01,0x47,0x49,0x75 +,0xdd,0xc3,0x26,0xc7,0x06,0x04,0x00,0x04,0x45,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x01,0xe8,0xe5,0x01 +,0xe8,0xd0,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x04,0x26,0xc6,0x06,0x28,0x00,0x00 +,0x26,0xc6,0x06,0x29,0x00,0x07,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x06,0xe8,0x04,0x02,0xe8,0x9b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x06,0xbf,0x2a,0x00,0xe8,0x6b +,0x02,0xe8,0xfb,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x05 +,0xe8,0xc6,0x01,0xe8,0x5d,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x05,0xbf,0x2a,0x00,0xe8,0x2d,0x02,0xe8 +,0xbd,0x01,0xc3,0xff,0x06,0x82,0x34,0x26,0xc7,0x06,0x04,0x00,0x3d,0x41,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0e,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x04,0xe8,0x84,0x01,0xe8,0x1b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x04,0xbf,0x2a,0x00,0xe8,0xeb +,0x01,0xe8,0x7b,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19,0x00,0x03 +,0xe8,0x46,0x01,0xe8,0xdd,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x03,0xbf,0x2a,0x00,0xe8,0xad,0x01,0xe8 +,0x3d,0x01,0xc3,0xff,0x06,0x84,0x34,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7 +,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x02,0xe8,0x04,0x01,0xe8,0x9b,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x16,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x02,0xbf,0x2a,0x00,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x01,0xa1,0x0f,0x37,0x86,0xe0,0xf6,0x06,0x6f,0x37 +,0x01,0x75,0x0f,0x39,0x06,0xcc,0x34,0x74,0x09,0x8b,0xd8,0xb8,0x89,0x03,0xcd,0x39 +,0x8b,0xc3,0xa3,0xcc,0x34,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xe8,0x3d,0x01,0xe8 +,0xcd,0x00,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1c +,0x00,0xa1,0xa2,0x37,0x50,0x0b,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x18,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x23,0x00 +,0xe8,0x2e,0xfa,0x26,0xc7,0x45,0x26,0x00,0x0e,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7 +,0x45,0x26,0x00,0x0a,0x26,0xc6,0x45,0x29,0x00,0x83,0xc7,0x2a,0xe8,0xbd,0x00,0xe8 +,0xff,0x00,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x20,0x00,0xf3 +,0xa5,0x59,0x5f,0x5e,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x1a +,0x00,0xf3,0xa5,0x59,0x5f,0x5e,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7 +,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x10,0xc3,0x26,0xc7,0x06 +,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00 +,0x00,0x08,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00 +,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x02,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00 +,0x26,0xc7,0x06,0x1c,0x00,0xff,0xff,0x26,0xc7,0x06,0x1e,0x00,0xff,0xff,0xc3,0x26 +,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03 +,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x06,0xa1,0x0d,0x37 +,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01 +,0x07,0xa1,0x0b,0x37,0x26,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0xa1,0xa2,0x37,0x0b +,0xc0,0x74,0x13,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x09,0xa1,0x03,0x37,0x26 +,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02 +,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06 +,0x26,0xc6,0x45,0x01,0x0b,0x8d,0x7d,0x02,0xbe,0xef,0x36,0xb9,0x02,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x20,0xa1,0x68,0x37,0x26,0x89,0x45 +,0x02,0xa1,0x6a,0x37,0x26,0x88,0x65,0x05,0xc1,0xe0,0x04,0x26,0x88,0x45,0x04,0x83 +,0xc7,0x06,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45,0x02 +,0x00,0x00,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x14,0x26,0xc6,0x45,0x01,0x22,0x8d +,0x7d,0x02,0xbe,0x1f,0x37,0xb9,0x09,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x0c,0x26 +,0xc6,0x45,0x01,0x23,0x8d,0x7d,0x02,0x1e,0x0e,0x1f,0x8d,0x36,0x40,0x54,0xb9,0x03 +,0x00,0xf3,0xa5,0x33,0xc0,0xb9,0x02,0x00,0xf3,0xab,0x1f,0xc3,0x26,0xc6,0x05,0x08 +,0x26,0xc6,0x45,0x01,0x28,0x8d,0x7d,0x02,0xbe,0xd1,0x36,0xb9,0x03,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x29,0xa1,0xc2,0x34,0x86,0xe0,0x26 +,0x89,0x45,0x02,0xa1,0x9b,0x36,0x26,0x89,0x45,0x04,0x26,0x88,0x45,0x06,0x26,0x88 +,0x45,0x07,0x8d,0x7d,0x08,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x2b,0x8d +,0x7d,0x02,0xbe,0xbb,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06,0x26 +,0xc6,0x45,0x01,0x2c,0x8d,0x7d,0x02,0xbe,0xe5,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3 +,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x30,0xa1,0x37,0x37,0x86,0xe0,0x26,0x89 +,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc7,0x06,0x0e,0x00,0x1e,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x02,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x6c,0xfe,0xe8,0x03,0xfe +,0x26,0xc7,0x06,0x26,0x00,0x00,0x10,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06 +,0x29,0x00,0x11,0xbf,0x2a,0x00,0xe8,0x35,0x00,0xe8,0x45,0x00,0xe8,0x55,0x00,0xc3 +,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0x32,0xfe,0xe8,0xc9,0xfd,0x26,0xc7,0x06,0x26,0x00,0x00 +,0x04,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06,0x29,0x00,0x13,0xc3,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x0c,0x26,0xc7,0x45,0x02,0x00,0x01,0x83,0xc7,0x04 +,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x0e,0x26,0xc7,0x45,0x02,0x00,0x02 +,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45 +,0x02,0x00,0x00,0x83,0xc7,0x04,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb3,0x39,0xc9,0x39,0x83,0x3a,0xb3,0x39,0xb3,0x39,0xb3,0x39,0x1c,0x3a,0x1c,0x3a +,0xa3,0xb6,0x34,0xa1,0xe9,0x36,0xa3,0x11,0x37,0xa3,0xd2,0x34,0xa1,0xeb,0x36,0xa3 +,0x13,0x37,0xa3,0xd4,0x34,0xa1,0xed,0x36,0xa3,0x15,0x37,0xa3,0xd6,0x34,0xa1,0x01 +,0x37,0xa3,0xce,0x34,0xa1,0xf7,0x36,0xa3,0x17,0x37,0xa3,0xdc,0x34,0xa1,0xf9,0x36 +,0xa3,0x19,0x37,0xa3,0xde,0x34,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75,0x0c,0x33,0xc0 +,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x50,0x39,0xe9,0x0f,0x01,0xbe,0x07,0x00 +,0xe9,0x19,0xf1,0xf6,0x06,0x9d,0x36,0x80,0x74,0xf3,0xc6,0x06,0xa0,0x36,0x02,0xc6 +,0x06,0x6e,0x37,0x08,0xc6,0x06,0x70,0x37,0x02,0xb8,0x88,0x03,0xcd,0x39,0xf6,0x06 +,0x6f,0x37,0x01,0x75,0x4a,0xa1,0xd1,0x36,0x3a,0x06,0xe9,0x36,0x75,0x41,0x3a,0x26 +,0xea,0x36,0x75,0x3b,0xa1,0xd3,0x36,0x3a,0x06,0xeb,0x36,0x75,0x32,0x3a,0x26,0xec +,0x36,0x75,0x2c,0xa1,0xd5,0x36,0x3a,0x06,0xed,0x36,0x75,0x23,0x3a,0x26,0xee,0x36 +,0x75,0x1d,0xc6,0x06,0x70,0x37,0x02,0xfe,0x0e,0x6e,0x37,0x75,0x0f,0xb8,0x88,0x03 +,0xcd,0x3a,0x83,0x0e,0x9b,0x36,0x12,0xc6,0x06,0xa0,0x36,0x0c,0xe9,0xa8,0xf0,0xa1 +,0x05,0x37,0x26,0x3b,0x06,0x20,0x00,0x75,0x40,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22 +,0x00,0x75,0x36,0xa1,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x2c,0xa0,0x9e,0x36 +,0x3c,0x02,0x75,0x08,0x26,0xf6,0x06,0x18,0x00,0x08,0x75,0x47,0xc6,0x06,0x6e,0x37 +,0x08,0xfe,0x0e,0x70,0x37,0x75,0x1c,0xc6,0x06,0x70,0x37,0x02,0xe5,0x02,0x0d,0x01 +,0x04,0x25,0xef,0xff,0xe7,0x02,0xe9,0x5e,0xf0,0xc6,0x06,0x70,0x37,0x02,0xc6,0x06 +,0x6e,0x37,0x08,0xe5,0x02,0x25,0xff,0xfb,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe9,0x44,0xf0,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x25,0x26,0xf6,0x06,0x18,0x00 +,0x08,0x75,0xed,0x81,0x26,0x9b,0x36,0x7f,0xff,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x84 +,0x03,0xcd,0x3a,0xc6,0x06,0xa0,0x36,0x06,0x83,0x26,0xc2,0x34,0xaf,0xe9,0x17,0xf0 +,0xa1,0x01,0x37,0x3a,0x26,0x0f,0x37,0x7f,0xc7,0xe9,0xf7,0xfe,0x83,0x26,0x9b,0x36 +,0xec,0xe8,0x2a,0x0d,0x81,0x0e,0x9b,0x36,0x80,0x00,0xbb,0xff,0x7f,0xcd,0x53,0xc6 +,0x06,0xa0,0x36,0x02,0xe9,0xf0,0xef,0x83,0x0e,0x9b,0x36,0x11,0xc6,0x06,0xa0,0x36 +,0x0c,0xe9,0xf9,0xef,0x44,0x3b,0x2c,0x3b,0xc7,0x2a,0x6b,0x3b,0x44,0x3b,0xc7,0x2a +,0xc7,0x2a,0xc7,0x2a,0xa3,0xb6,0x34,0x81,0x0e,0xc2,0x34,0x00,0x20,0xf7,0x06,0x41 +,0x37,0x01,0x00,0x74,0x1b,0x8c,0xc3,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f,0x03 +,0xcd,0x3a,0x33,0xc0,0x8e,0xc0,0xbf,0x54,0x37,0xb9,0x06,0x00,0xf3,0xab,0x8e,0xc3 +,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0xe4,0x3a,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x75,0x21,0x83,0x26,0xc2,0x34,0xbf,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0x9b +,0x36,0xe9,0x09,0x00,0xa1,0x9b,0x36,0x81,0x26,0x9b,0x36,0xff,0xdf,0xa9,0x00,0x20 +,0x75,0x06,0xe9,0x6e,0x00,0xe9,0x6f,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37 +,0x37,0x01,0x00,0xc6,0x06,0xca,0x34,0x01,0xe9,0x58,0x00,0x83,0x0e,0x9b,0x36,0x40 +,0xe8,0x58,0x00,0xa1,0x05,0x37,0x3b,0x06,0xe9,0x36,0x75,0x37,0xa1,0x07,0x37,0x3b +,0x06,0xeb,0x36,0x75,0x2e,0xa1,0x09,0x37,0x3b,0x06,0xed,0x36,0x75,0x25,0xfe,0x0e +,0x71,0x37,0x75,0x1c,0xb8,0x87,0x03,0xcd,0x3a,0x83,0x0e,0x99,0x36,0x10,0xa1,0x50 +,0x37,0xc7,0x06,0x50,0x37,0x00,0x00,0x09,0x06,0x99,0x36,0xc6,0x06,0xa0,0x36,0x08 +,0xe9,0x14,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x03,0x00,0xc6,0x06 +,0xca,0x34,0x03,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0xfc,0xee,0xa1,0xd1,0x36,0x26,0x3b +,0x06,0x20,0x00,0x75,0x15,0xa1,0xd3,0x36,0x26,0x3b,0x06,0x22,0x00,0x75,0x12,0xa1 +,0xd5,0x36,0x26,0x3b,0x06,0x24,0x00,0x75,0x0f,0xc3,0x8d,0x36,0x20,0x00,0xe9,0x0b +,0x00,0x8d,0x36,0x22,0x00,0xe9,0x04,0x00,0x8d,0x36,0x24,0x00,0x83,0xc4,0x02,0xf7 +,0x06,0xe6,0x34,0x01,0x00,0x74,0x15,0x26,0x3a,0x04,0x77,0x08,0x72,0x0e,0x26,0x3a +,0x64,0x01,0x72,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xab,0xee,0xe8,0x7c,0x0a,0x8c +,0xc0,0x3d,0xff,0xff,0x74,0x1b,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0xc7,0x06,0x04 +,0x00,0x49,0x3c,0x26,0xc7,0x06,0x06,0x00,0x0c,0x00,0xcd,0x50,0xb9,0x4e,0x00,0xe2 +,0xfe,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0x94,0xee,0xe9,0x7b,0xee,0x8f,0x3c,0x06,0x3d +,0x06,0x3d,0x06,0x3d,0xd2,0x3c,0xea,0x3c,0x06,0x3d,0x06,0x3d,0xa3,0xb6,0x34,0x81 +,0x26,0xc2,0x34,0xaf,0xdf,0xc7,0x06,0x4c,0x37,0x00,0x00,0xb8,0x8a,0x03,0xcd,0x3a +,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74,0x05,0xc6,0x06 +,0x9f,0x36,0x06,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x4c,0x3c,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x0e,0x81,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x8b,0x03 +,0xcd,0x3a,0xe9,0x54,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x03,0xe9,0x17,0xee +,0xc7,0x06,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04 +,0x83,0x0e,0x50,0x37,0x04,0xf6,0x06,0x9d,0x36,0x80,0x75,0x2a,0xe8,0x1f,0x0b,0xe9 +,0x27,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x75,0xd3,0xc7,0x06,0x37,0x37,0x02,0x00 +,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0xc6,0x06,0xa0,0x36,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x03,0xe8,0xde,0x0a,0x81,0x26,0x9b,0x36,0x7c,0xff,0xbb +,0xff,0xff,0xcd,0x53,0xcd,0x54,0xe9,0xbe,0xed,0xa3,0xb6,0x34,0xe8,0xad,0x01,0xb8 +,0x86,0x03,0xcd,0x39,0xc7,0x06,0x4c,0x37,0x00,0x00,0x81,0x26,0xc2,0x34,0xaf,0xdf +,0xf6,0x06,0x9d,0x36,0x80,0x74,0x34,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x56,0xf7 +,0x06,0x9b,0x36,0x00,0x01,0x74,0x27,0xe8,0x35,0x01,0x72,0x1c,0xbe,0x00,0x40,0x85 +,0x36,0xc2,0x34,0x75,0x08,0x09,0x36,0xc2,0x34,0xff,0x06,0x92,0x34,0xe8,0x8b,0x01 +,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x6c,0xed,0xe9,0xb5,0x00,0xc7,0x06 +,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0x83,0x0e +,0x50,0x37,0x04,0x80,0x3e,0x9e,0x36,0x08,0x74,0x03,0xe8,0x5a,0x0a,0xe8,0xef,0x00 +,0x72,0xd6,0xe9,0xc8,0xff,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x12,0xc6,0x06,0xa0,0x36 +,0x00,0xf7,0x06,0x9b,0x36,0x08,0x00,0x74,0x02,0xcd,0x54,0xe8,0x39,0x0a,0x81,0x26 +,0x9b,0x36,0xff,0xbf,0xe8,0xc8,0x00,0x72,0xaf,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x9c +,0xff,0xf6,0x06,0x9e,0x36,0xff,0x75,0x58,0xa3,0xb6,0x34,0xe8,0xfe,0x00,0x81,0x26 +,0xc2,0x34,0xff,0xbf,0xf6,0x06,0x9d,0x36,0x80,0x74,0x48,0xf7,0x06,0x9b,0x36,0x00 +,0x20,0x74,0x22,0xf7,0x06,0x9b,0x36,0x00,0x40,0x75,0x08,0xe8,0x91,0x00,0x72,0x30 +,0xe9,0x22,0x00,0x26,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x75,0x24,0x81,0x0e,0x66,0x37 +,0x00,0x08,0xe9,0xd2,0xec,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe8,0x71,0x00,0x72,0x10 +,0xb8,0x8b,0x03,0xcd,0x39,0xe8,0xd3,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00 +,0xe9,0xb4,0xec,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74 +,0x46,0xc6,0x06,0x9f,0x36,0x06,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x0c,0x80,0x3e +,0x9d,0x36,0x08,0x75,0x05,0xc6,0x06,0x9f,0x36,0x0a,0xe8,0x32,0x00,0x72,0xd1,0xe8 +,0x99,0x00,0x80,0x3e,0x9d,0x36,0x08,0x75,0x13,0x81,0x0e,0x99,0x36,0x80,0x00,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x08,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x68,0xec,0xc6 +,0x06,0x9f,0x36,0x0a,0xe9,0x60,0xec,0xb8,0x86,0x03,0xcd,0x3a,0xe9,0x58,0xec,0x26 +,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x74,0x08,0x81,0x26,0xc2,0x34,0xff,0xbf,0xf9,0xc3 +,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x13,0x81,0x0e,0x66,0x37,0x00,0x08,0xe8,0x4a +,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xf9,0xc3,0x81,0x0e,0x9b,0x36,0x00 +,0x40,0x80,0x26,0x6f,0x37,0xfe,0x81,0x26,0x9b,0x36,0x7f,0xff,0xc6,0x06,0xa0,0x36 +,0x00,0xf8,0xc3,0x81,0x0e,0x99,0x36,0x00,0x01,0xe9,0x21,0xec,0x26,0xa1,0x20,0x00 +,0xa3,0xfb,0x36,0xa3,0xaa,0x34,0x26,0xa1,0x22,0x00,0xa3,0xfd,0x36,0xa3,0xac,0x34 +,0x26,0xa1,0x24,0x00,0xa3,0xff,0x36,0xa3,0xae,0x34,0xc3,0xa1,0x05,0x37,0x26,0x3b +,0x06,0x20,0x00,0x75,0x19,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22,0x00,0x75,0x0f,0xa1 +,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x05,0xe8,0x02,0x00,0xf8,0xc3,0x51,0x1e +,0x06,0x8b,0xc7,0x8d,0x36,0x20,0x00,0xbf,0x05,0x37,0xb9,0x03,0x00,0x1e,0x06,0x1f +,0x07,0xf3,0xa5,0x8b,0xf8,0x8d,0x36,0x20,0x00,0xbf,0xa0,0x34,0xb9,0x03,0x00,0xf3 +,0xa5,0x07,0x1f,0x59,0x8b,0xf8,0xa1,0x07,0x37,0xa3,0xa6,0x34,0xa1,0x09,0x37,0xa3 +,0xa8,0x34,0xf9,0xc3,0xc6,0x06,0xb6,0x34,0x01,0xe9,0x8b,0xeb,0xe8,0x87,0x08,0x8b +,0xf0,0x05,0x12,0x00,0x26,0x29,0x06,0x0e,0x00,0x26,0x8b,0x44,0x2a,0x26,0x3a,0x06 +,0x0e,0x00,0x75,0x5b,0x26,0x83,0x2e,0x0e,0x00,0x02,0x80,0xfc,0x27,0x75,0x50,0x26 +,0x8b,0x44,0x2c,0xa9,0xff,0xff,0x75,0x47,0x8b,0xfe,0x33,0xc0,0x26,0xf6,0x45,0x3c +,0x80,0x74,0x06,0x26,0x8a,0x45,0x3a,0x24,0x1f,0x03,0xf8,0x26,0x80,0x7d,0x45,0x09 +,0x75,0x2d,0x8c,0xc2,0x8e,0x06,0x38,0x34,0x8e,0xda,0x8b,0x0e,0x0e,0x00,0x26,0x89 +,0x0e,0x0e,0x00,0x8d,0x74,0x2c,0xbf,0x18,0x00,0xf3,0xa4,0x33,0xc0,0x8e,0xd8,0x26 +,0xc7,0x06,0x04,0x00,0xb5,0x3f,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0xcd,0x50,0xb8 +,0x06,0x80,0xe9,0xef,0xe9,0x26,0xa1,0x0c,0x00,0xa3,0x93,0x37,0x83,0x0e,0x99,0x36 +,0x01,0xe9,0x00,0xeb,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e +,0x00,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36 +,0x26,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3 +,0x1e,0x00,0xb8,0x0a,0x80,0xe8,0x36,0x07,0xe9,0xe2,0xea,0xff,0x06,0x90,0x34,0xbe +,0x0a,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e +,0xc2,0x34,0x01,0xe9,0xb6,0xea,0x80,0x3e,0x9d,0x36,0x0a,0x75,0x0f,0x26,0xa1,0x0c +,0x00,0x25,0x07,0x00,0x3d,0x04,0x00,0x75,0x03,0xe8,0x79,0x00,0xa1,0xf3,0x36,0x86 +,0xe0,0xe7,0x1e,0xa3,0xe3,0x36,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37 +,0x7b,0x7f,0x83,0x0e,0x0d,0x37,0x48,0xe8,0x1e,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07 +,0x00,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20,0x00,0x75,0x06,0xb8 +,0x01,0x00,0xe9,0x3f,0xe9,0xe9,0x5f,0xea,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f +,0x03,0xcd,0x3a,0xa1,0x1d,0x37,0xa3,0xc4,0x34,0x86,0xe0,0x68,0x7f,0x03,0x1f,0xa3 +,0x06,0x00,0x33,0xc0,0x8e,0xd8,0xa1,0x0b,0x37,0xa3,0xb2,0x34,0xa1,0x0d,0x37,0xa3 +,0xb4,0x34,0xa1,0xf3,0x36,0xa3,0xc8,0x34,0xa1,0xef,0x36,0xa3,0x9c,0x34,0xa1,0xf1 +,0x36,0xa3,0x9e,0x34,0xc3,0x80,0x0e,0x9d,0x36,0x80,0xbe,0x00,0x00,0xe8,0xb4,0x07 +,0xb8,0x7b,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00 +,0xa1,0xe5,0x36,0xe7,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xb8,0x82,0x03,0xcd,0x3a,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x03,0xe8,0xfd,0x06,0xa1,0xd3,0x36,0xa3,0xef,0x36 +,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3,0xf1,0x36,0xa3,0x9e,0x34,0xc3,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x31,0xbe,0x22,0x00,0xe9,0x17,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74 +,0x24,0xbe,0x23,0x00,0xe9,0x0a,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x17,0xbe,0x24 +,0x00,0x56,0xe8,0xa8,0x05,0x8c,0xc0,0x3d,0xff,0xff,0x5e,0x74,0x05,0xe8,0xd7,0xef +,0xcd,0x50,0xe9,0x1f,0xe8,0xe9,0x9f,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x8a,0x03,0xcd,0x39,0xe9,0xf7,0x00,0x80,0x3e,0xa0 +,0x36,0x08,0x75,0x2e,0xa9,0xd0,0x07,0x75,0x2c,0xa1,0xb1,0x36,0x0d,0x00,0x04,0xe7 +,0x08,0xe5,0x00,0x25,0xff,0x73,0xe7,0x00,0xb8,0x8a,0x03,0xcd,0x3a,0xe8,0xc3,0x06 +,0x33,0xc0,0xe7,0x0e,0xe5,0x0a,0x25,0xc3,0x17,0xe7,0x0a,0xcd,0x54,0xc6,0x06,0xa0 +,0x36,0x00,0xe9,0x68,0xe9,0xbe,0x04,0x00,0xe9,0x3f,0xe9,0x83,0x26,0x9b,0x36,0xbf +,0xc6,0x06,0x71,0x37,0x03,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8 +,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x39,0x81,0x0e,0xc2,0x34,0x00,0x20,0xe9 +,0x92,0x00,0xe8,0x49,0x06,0xb8,0x87,0x03,0xcd,0x39,0xbb,0xff,0x7f,0xcd,0x53,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x83 +,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xc3,0xe5,0x00 +,0x25,0xff,0x53,0xe7,0x00,0x83,0x0e,0xc2,0x34,0x40,0x83,0x26,0xc2,0x34,0xef,0xe8 +,0x0c,0x06,0xbb,0xff,0x7f,0xcd,0x53,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd +,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a +,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xc3 +,0x83,0x0e,0xc2,0x34,0x50,0xe8,0x18,0x04,0xe8,0xd3,0x05,0xf6,0x06,0x6f,0x37,0x01 +,0x75,0x12,0xb8,0x89,0x03,0xcd,0x39,0x83,0x3e,0x0f,0x37,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x04,0x00,0xa1,0x9d,0x36,0x80,0xfc,0x08,0x74,0x05,0xb8,0x84,0x03,0xcd +,0x39,0xe5,0x02,0x0d,0x01,0x08,0x25,0xef,0xff,0xe7,0x02,0xa1,0x9d,0x36,0x86,0xe0 +,0x32,0xe4,0x8b,0xf0,0xd1,0xee,0x33,0xc0,0x0d,0x20,0x00,0x09,0x06,0xad,0x36,0xa1 +,0xad,0x36,0xe7,0x04,0xe9,0x53,0xe8,0xe9,0x5a,0xe8,0x33,0xc0,0xa0,0x1b,0x37,0xd1 +,0xe0,0x3a,0x06,0xa0,0x36,0x75,0x03,0xe9,0xba,0xff,0xe9,0x60,0xe8,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xc1,0xe1,0xe8,0x6a,0x06,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56 +,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x02,0x25,0xf9,0xff,0x0d,0x03,0x00 +,0xe7,0x02,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1,0xad,0x36,0xe7 +,0x04,0xe8,0x7c,0x03,0xe8,0x9f,0x03,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x99,0x36,0xa3,0x9b +,0x36,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xa3,0x4c,0x37,0xa3,0xf3,0x36,0xa3,0xef,0x36 +,0xa3,0xf1,0x36,0xe8,0x82,0xfd,0xc6,0x06,0x9f,0x36,0x02,0xe9,0xef,0xe7,0xe5,0x02 +,0x0d,0x01,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xe8,0xf2 +,0x05,0xe5,0x0a,0x0d,0x40,0x00,0xe7,0x0a,0x33,0xc0,0xa3,0x81,0x37,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xe5,0x00,0x0d,0x00,0x84,0xe7,0x00 +,0xb8,0x8c,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xe5,0x00,0x25,0xff,0x7b,0xe7,0x00,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x7e,0x03 +,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0xa7,0xed +,0x83,0x26,0xef,0x34,0xdf,0xff,0x06,0x81,0x37,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20 +,0xc3,0xf7,0x06,0x9a,0x37,0x80,0x00,0x74,0x3d,0xa9,0xd0,0x07,0x74,0x10,0xa9,0x00 +,0x04,0x74,0x12,0x33,0xc0,0xe7,0x0e,0xff,0x06,0x87,0x37,0xe9,0xd2,0xff,0xff,0x06 +,0x85,0x37,0xe9,0xcb,0xff,0xff,0x06,0x83,0x37,0xe9,0xc4,0xff,0x83,0x26,0x9a,0x37 +,0x7f,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f,0x01,0xc3,0xbb,0xff +,0x7f,0xcd,0x53,0xe9,0x00,0x00,0xe5,0x02,0x25,0xff,0xfb,0x25,0xef,0xff,0x0d,0x01 +,0x00,0xe7,0x02,0xa1,0x83,0x37,0x3b,0x06,0x46,0x37,0x7f,0x2a,0xa1,0x85,0x37,0x3b +,0x06,0x48,0x37,0x7c,0x21,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f +,0x15,0xc6,0x06,0x9f,0x36,0x04,0xe5,0x02,0x25,0xff,0xf7,0x0d,0x01,0x00,0x25,0xef +,0xff,0xe7,0x02,0xe9,0xf7,0xe6,0xbe,0x01,0x00,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0a,0x83,0x26,0x9b,0x36,0xfc,0x83,0x0e,0xc2,0x34,0x04,0xe9,0xd0,0xe6,0xb8,0x7b +,0x03,0xcd,0x39,0xe5,0x02,0x0d,0x01,0x60,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06,0xf1 +,0x34,0x20,0x03,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0x81,0x26,0xc2,0x34,0x7f,0xff,0x80 +,0x0e,0x6f,0x37,0x01,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0xd2,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x7d,0x03,0xcd,0x39,0x83,0x26,0x9b,0x36,0xef,0x33,0xc0,0xb0,0x8a,0xa2 +,0x9f,0x36,0xa2,0x9d,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc7,0x06,0x0f,0x37,0x04 +,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xb8 +,0x8d,0x03,0xcd,0x39,0xe8,0x00,0xd5,0xe5,0x02,0x0d,0x01,0x40,0x25,0xef,0xff,0x8b +,0xd8,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00,0x8b,0xc3,0x0d,0x00 +,0x20,0x25,0xf9,0xff,0x0b,0x06,0xe8,0x3a,0xe7,0x02,0xc3,0xff,0x0e,0xf1,0x34,0x75 +,0x01,0xc3,0xe5,0x4e,0xa9,0x01,0x00,0x75,0x12,0xe5,0x00,0xa9,0x00,0x04,0x75,0x05 +,0x0d,0x00,0x04,0xe7,0x00,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0xe5,0x00,0xa9,0x00,0x04 +,0x74,0xf3,0x25,0xff,0xfb,0xe7,0x00,0xe9,0xeb,0xff,0xc6,0x06,0xa0,0x36,0x04,0x83 +,0x26,0x9b,0x36,0xfc,0x81,0x0e,0x9b,0x36,0x80,0x00,0xe9,0x10,0xe6,0xb8,0x8e,0x03 +,0xcd,0x3a,0xcd,0x54,0x81,0x0e,0xaf,0x36,0x00,0x18,0xa1,0xaf,0x36,0xe7,0x06,0xb8 +,0x7b,0x03,0xcd,0x39,0xa1,0xd3,0x36,0xa3,0x8f,0x37,0xa1,0xd5,0x36,0xa3,0x91,0x37 +,0xc7,0x06,0x8b,0x37,0x02,0x00,0xc7,0x06,0x8d,0x37,0x02,0x00,0x83,0x0e,0x99,0x36 +,0x40,0xe9,0xd9,0xe5,0x80,0x3e,0x9f,0x36,0x06,0x75,0x15,0xa9,0xd0,0x07,0x75,0xec +,0x25,0x00,0x18,0x75,0x0e,0xff,0x0e,0x8b,0x37,0x75,0xe1,0xc6,0x06,0x9f,0x36,0x08 +,0xe9,0xba,0xe5,0xff,0x0e,0x8d,0x37,0x75,0xd3,0xbe,0x08,0x00,0xe9,0x9f,0xe5,0xb8 +,0x7b,0x03,0xcd,0x39,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x08,0xc6,0x06,0x9f,0x36 +,0x0a,0xe9,0x0d,0x00,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x0b,0xb8,0x8b,0x03,0xcd +,0x39,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x83,0xe5,0xb8,0x7b,0x03,0xcd,0x39,0xc7 +,0x06,0x8b,0x37,0x04,0x00,0xc7,0x06,0x8d,0x37,0x04,0x00,0x81,0x0e,0x99,0x36,0x00 +,0x02,0xe9,0x69,0xe5,0xf6,0x06,0x9d,0x36,0x80,0x75,0x1b,0xa9,0xd0,0x07,0x75,0xeb +,0xa9,0x00,0x18,0x75,0x0c,0xff,0x0e,0x8d,0x37,0x75,0xe0,0xe8,0x17,0xfb,0xe9,0x4c +,0xe5,0xb8,0x82,0x03,0xcd,0x39,0xc3,0xff,0x0e,0x8b,0x37,0x75,0xce,0xbe,0x09,0x00 +,0xe9,0x2b,0xe5,0xc7,0x06,0x3d,0x37,0x00,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x3c,0x02,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x50,0x00 +,0xe8,0x73,0x00,0xb8,0x81,0x03,0xcd,0x39,0xc3,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0d,0xc6,0x06,0x9f,0x36,0x02,0xc6,0x06,0xa0,0x36,0x00,0xe9,0xdf,0xe4,0x83,0x0e +,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xe7,0x02,0xe5,0x56,0x0d,0x02 +,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0x8b,0x36,0x3d,0x37,0xe8,0x44,0x02 +,0xc6,0x06,0xa0,0x36,0x0e,0xe9,0xb5,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x06,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a +,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8 +,0x88,0x03,0xcd,0x3a,0x07,0xc3,0x06,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x82,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x3a +,0xb8,0x7e,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0xb8,0x81,0x03,0xcd,0x3a,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x7d,0x03,0xcd,0x3a,0xb8,0x8d +,0x03,0xcd,0x3a,0xc7,0x06,0x41,0x37,0x00,0x00,0x07,0xc3,0x06,0x8e,0x06,0x38,0x34 +,0x1f,0x8b,0x0e,0x0e,0x00,0x26,0x89,0x0e,0x0e,0x00,0xbe,0x18,0x00,0xbf,0x18,0x00 +,0xf3,0xa4,0x06,0x1e,0x07,0xcd,0x34,0x07,0x33,0xc0,0x8e,0xd8,0xc3,0x26,0xf6,0x06 +,0x20,0x00,0x80,0x74,0x44,0x33,0xc0,0x26,0xa0,0x26,0x00,0x24,0x1f,0x8b,0xf0,0x26 +,0x8b,0x5c,0x28,0x89,0x1e,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04 +,0x26,0x88,0x5c,0x28,0x8b,0xc6,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3 +,0xa4,0x8b,0xc8,0x83,0xc7,0x06,0xf3,0xa4,0x26,0x81,0x26,0x26,0x00,0x1f,0x80,0x26 +,0x81,0x36,0x26,0x00,0x00,0x80,0xe9,0xa9,0xff,0x26,0x8b,0x1e,0x28,0x00,0x89,0x1e +,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04,0x26,0x88,0x1e,0x28,0x00 +,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3,0xa4,0xe9,0x84,0xff,0x86,0xc4 +,0xa3,0x68,0x37,0xe8,0x87,0xff,0xf7,0x06,0x6a,0x37,0x0f,0x00,0x74,0x10,0x80,0x3e +,0x9e,0x36,0x00,0x75,0x09,0xbe,0x00,0x00,0xe8,0xac,0xe9,0xcd,0x50,0xc3,0xc3,0x50 +,0x56,0x06,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06,0x26,0xa0,0x26,0x00 +,0x24,0x1f,0x8b,0xf0,0x26,0x8b,0x5c,0x26,0x86,0xfb,0x83,0xeb,0x04,0x74,0x4f,0x83 +,0xc6,0x2a,0x8c,0xc0,0x8e,0xd8,0xb9,0x07,0x00,0x33,0xc0,0x8e,0xc0,0xbf,0x72,0x37 +,0xf3,0xab,0x33,0xc9,0x8a,0x0c,0x80,0xf9,0x00,0x75,0x03,0xe9,0x30,0x00,0x3b,0xd9 +,0x73,0x03,0xe9,0x29,0x00,0x2b,0xd9,0x8a,0x44,0x01,0x25,0x3f,0x00,0x74,0x19,0x3d +,0x0b,0x00,0x7d,0x14,0xd1,0xe0,0x8b,0xf8,0x2e,0x8b,0xbd,0x5c,0x49,0x8d,0x74,0x02 +,0x83,0xe9,0x02,0xf3,0xa4,0xe9,0x02,0x00,0x03,0xf1,0x23,0xdb,0x75,0xc4,0x33,0xc0 +,0x8e,0xd8,0x07,0x5e,0x58,0xc3,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06 +,0x26,0xa0,0x26,0x00,0x24,0x1f,0xc3,0xe5,0x0a,0x25,0xc3,0xbf,0xe7,0x0a,0xb8,0x86 +,0x03,0xcd,0x39,0xb8,0x83,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0x7c,0xdf,0xb8,0x85 +,0x03,0xcd,0x3a,0xe5,0x02,0x25,0xff,0xf3,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00,0xa1,0xe7,0x36,0x25,0xff,0xfe,0xa3,0xe7,0x36 +,0xe7,0x3e,0x83,0x26,0x99,0x36,0xcf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0xc3,0xe5,0x02,0x0d,0x01,0x0c,0x25,0xef,0xff,0xe7,0x02,0xa1,0xe7,0x36 +,0x0d,0x00,0x01,0xe7,0x3e,0xa3,0xe7,0x36,0x81,0x0e,0x9b,0x36,0x00,0x20,0x83,0x0e +,0x99,0x36,0x20,0x81,0x26,0x9b,0x36,0x7c,0xbf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1 +,0xaf,0x36,0xe7,0x06,0xb8,0x86,0x03,0xcd,0x39,0xb8,0x85,0x03,0xcd,0x39,0xb8,0x83 +,0x03,0xcd,0x3a,0xc3,0x0b,0xf6,0x75,0x49,0x06,0x8e,0x06,0x32,0x34,0x80,0x3e,0xe0 +,0x34,0x01,0x75,0x1b,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26,0xf7,0x06 +,0x0a,0x00,0x00,0x20,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x20,0x07,0xc3,0x80 +,0x3e,0xe3,0x34,0x01,0x75,0x19,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26 +,0xf7,0x06,0x0a,0x00,0x00,0x10,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x10,0x07 +,0xc3,0xe9,0xb4,0xff,0x50,0x51,0x57,0x33,0xc0,0xb9,0x06,0x00,0x8e,0xc0,0xbf,0xd1 +,0x36,0xf3,0xae,0x5f,0x74,0x0c,0x26,0xf6,0x06,0x00,0x00,0xc0,0x75,0x04,0xf8,0x59 +,0x58,0xc3,0xf9,0xe9,0xf9,0xff,0x8b,0x05,0x0b,0x45,0x02,0x0b,0x45,0x04,0xc3,0x52 +,0x50,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75,0xf6,0xb8,0x01,0x80,0xe7,0x5a +,0x58,0x5a,0xc3,0xe8,0xe9,0xff,0x50,0xe5,0x02,0x25,0xff,0x7f,0x0d,0x01,0x00,0x25 +,0xef,0xff,0xe7,0x02,0x0d,0x00,0x80,0xe7,0x02,0xa1,0xad,0x36,0xe7,0x04,0xa1,0xaf +,0x36,0xe7,0x06,0x58,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x2e,0x2b,0xce,0x41,0x10,0x42,0x7b,0x41,0x30,0x41,0xa2,0x41,0xaf,0x45,0x44,0x29 +,0xc7,0x2a,0xc7,0x2a,0x60,0x39,0xf4,0x3a,0x5c,0x3c,0x09,0x3d,0xb1,0x3d,0x34,0x3f +,0xc7,0x2a,0x3c,0x3f,0xc7,0x2a,0xc4,0x3f,0x16,0x40,0x16,0x40,0xed,0x40,0xfa,0x40 +,0x07,0x41,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xd6,0x52,0x00,0x00,0x01,0x37 +,0xe9,0x36,0xf3,0x36,0xef,0x36,0x1d,0x37,0x0d,0x37,0x0b,0x37,0x9c,0x37,0x03,0x37 +,0xfb,0x36,0x62,0x2d,0x40,0x06,0xd1,0x2d,0xf4,0x01,0xba,0x44,0x40,0x06,0x8c,0x43 +,0x64,0x00,0xe8,0x2c,0xc8,0x00,0xd8,0x2b,0x05,0x00,0xe9,0x45,0x50,0x00,0x97,0x45 +,0xfa,0x00,0xae,0x2d,0x04,0x01,0x6a,0x42,0x02,0x00,0xf6,0x2c,0xbc,0x02,0x93,0x2d +,0xdc,0x05,0x1d,0x2d,0x64,0x00,0xa1,0x2d,0x14,0x00,0xd7,0x3a,0x08,0x07,0x81,0x2d +,0x64,0x00,0xb3,0x3e,0x02,0x00,0x30,0x43,0x64,0x00,0xc5,0x2c,0xf4,0x01,0x8b,0x44 +,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xfd,0x34,0x02,0x74,0x0c,0xe8,0x20,0x05,0xc7,0x06,0xa1,0x36,0x00,0x00 +,0xe9,0x9a,0xf8,0xff,0x06,0xc0,0x33,0xe8,0x10,0x05,0x8b,0x36,0x3d,0x37,0xe8,0x73 +,0xfe,0xc3,0xcd,0x34,0xe9,0xe8,0x05,0xc7,0x06,0xa3,0x36,0x00,0x00,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xed,0xfe,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36 +,0x0d,0x00,0x10,0xe7,0x08,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1 +,0xad,0x36,0xe7,0x04,0xe8,0x2b,0x09,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x9b,0x36,0xa3,0x9d +,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x05,0x37 +,0x00,0x00,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xa3,0xf3 +,0x36,0xa3,0xef,0x36,0xa3,0xf1,0x36,0xe8,0xfe,0xf5,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xb8,0x8f,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xa1,0xa9,0x36,0xa3,0xa7,0x36,0x0d,0x00,0xa4,0x0d,0x00,0x08,0xe7,0x00,0xa3,0xa9 +,0x36,0xc7,0x06,0xa3,0x36,0x01,0x00,0xc7,0x06,0xa5,0x36,0x0c,0x00,0x83,0x3e,0xa5 +,0x36,0x00,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9,0x13,0xff,0xff,0x0e,0xa5 +,0x36,0xbe,0x11,0x00,0xe8,0x22,0x05,0xb8,0x90,0x03,0xcd,0x39,0xc3,0x83,0x3e,0xa3 +,0x36,0x01,0x74,0xd9,0xc3,0xb8,0x90,0x03,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b +,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x01,0x74,0x03,0xe9,0xf0,0x04,0x3c +,0x0f,0x75,0x1e,0x81,0xfb,0x00,0x02,0x75,0x18,0x26,0xa1,0x20,0x00,0xa3,0x05,0x37 +,0x26,0xa1,0x22,0x00,0xa3,0x07,0x37,0x26,0xa1,0x24,0x00,0xa3,0x09,0x37,0xe9,0x09 +,0x00,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xb6,0xfe,0xc7,0x06,0xa3,0x36,0x02,0x00 +,0xc6,0x06,0x9e,0x36,0xff,0xe8,0xcb,0xfd,0xe8,0x1c,0xd9,0x33,0xc0,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xb8,0x91,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00 +,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x92,0x03,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe +,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0x8e,0xe5,0x26,0xc7,0x06,0x04,0x00,0x7d,0x4b +,0x83,0x26,0xef,0x34,0xdf,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20,0xc3,0xf7,0x06,0x9a +,0x37,0x80,0x00,0x74,0x32,0xa9,0xd0,0x07,0x74,0x0c,0xa9,0x00,0x04,0x74,0x0e,0x33 +,0xc0,0xe7,0x0e,0xe9,0xda,0xff,0xff,0x06,0x85,0x37,0xe9,0xd3,0xff,0xff,0x06,0x83 +,0x37,0xe9,0xcc,0xff,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0x36,0xfe,0x83,0x26,0x9a +,0x37,0x7f,0xbb,0xff,0x7f,0xcd,0x53,0xe5,0x00,0x0d,0x00,0xac,0xe7,0x00,0xe5,0x02 +,0x25,0xff,0xfb,0x25,0xef,0xff,0x25,0xff,0xf7,0x0d,0x01,0x00,0xe7,0x02,0xa1,0x83 +,0x37,0x3b,0x06,0x46,0x37,0x7f,0xcd,0xa1,0x85,0x37,0x3b,0x06,0x48,0x37,0x7c,0xc4 +,0xc7,0x06,0xa3,0x36,0x03,0x00,0xbe,0x13,0x00,0xe8,0xfd,0x03,0xb8,0x93,0x03,0xcd +,0x39,0xb8,0x94,0x03,0xcd,0x39,0xb8,0x96,0x03,0xcd,0x39,0xb8,0x95,0x03,0xcd,0x39 +,0xbe,0x06,0x00,0xe8,0xe3,0x03,0xe9,0xd6,0x03,0x83,0x3e,0xa3,0x36,0x03,0x74,0x01 +,0xc3,0xbe,0x13,0x00,0xe8,0xd2,0x03,0xb8,0x94,0x03,0xcd,0x39,0xc3,0xb8,0x94,0x03 +,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3 +,0x36,0x03,0x74,0x03,0xe9,0xa8,0x03,0x3c,0x0d,0x75,0x3e,0x83,0xfb,0x00,0x75,0x39 +,0xe5,0x02,0x0d,0x00,0x20,0xe7,0x02,0xb8,0x93,0x03,0xcd,0x3a,0xc7,0x06,0xa3,0x36 +,0x04,0x00,0xbe,0x00,0x00,0xe8,0x0c,0xfc,0xc6,0x06,0x9d,0x36,0x80,0xc6,0x06,0x9e +,0x36,0x00,0xc7,0x06,0x33,0x37,0x02,0x00,0xb8,0x9a,0x03,0xcd,0x39,0xe8,0xfc,0x00 +,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe9,0x66,0x03,0xc7,0x06,0x3d,0x37,0x08,0x00,0xe9 +,0x61,0xfd,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9 +,0x51,0xfd,0xe9,0x4a,0x03,0x83,0x3e,0xa3,0x36,0x04,0x74,0x12,0x83,0x3e,0xa3,0x36 +,0x05,0x74,0x0b,0xcd,0x34,0xc7,0x06,0x3d,0x37,0x07,0x00,0xe9,0x35,0xfd,0xc7,0x06 +,0xa3,0x36,0x06,0x00,0xc6,0x06,0x9e,0x36,0xff,0xb8,0x9a,0x03,0xcd,0x3a,0xb8,0x99 +,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03 +,0xcd,0x39,0xb8,0x9b,0x03,0xcd,0x39,0xe9,0x18,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36 +,0x04,0x77,0x18,0x83,0x3e,0xa3,0x36,0x03,0x75,0x08,0xf7,0x06,0x9b,0x36,0x00,0x01 +,0x75,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xe8,0xfc,0xe9,0xe1,0x02,0xcd,0x34 +,0x83,0x3e,0xa3,0x36,0x02,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xd3,0xfc +,0x83,0x3e,0xa3,0x36,0x04,0x77,0x05,0xb8,0x96,0x03,0xcd,0x39,0xe9,0xc0,0x02,0x83 +,0x3e,0xa3,0x36,0x03,0x75,0x10,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x50,0x3d,0x04 +,0x00,0x75,0x03,0xe8,0x36,0x00,0xa1,0xf3,0x36,0x86,0xe0,0xe7,0x1e,0xa3,0xe3,0x36 +,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37,0x7b,0x7f,0x83,0x0e,0x0d,0x37 +,0x48,0xe8,0x14,0xf3,0x58,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20 +,0x00,0x75,0x06,0xb8,0x01,0x00,0xe9,0x7a,0x02,0xe9,0x86,0xfc,0xa1,0xe5,0x36,0xe7 +,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xa1,0xd3,0x36,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3 +,0x9e,0x34,0xc3,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e,0x00 +,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36,0x26 +,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3,0x1e +,0x00,0xb8,0x0a,0x80,0xe9,0x2c,0x02,0xe9,0x38,0xfc,0xff,0x06,0x90,0x34,0xbe,0x0a +,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e,0xc2 +,0x34,0x01,0xcd,0x34,0xe9,0x0c,0xfc,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06 +,0x3d,0x37,0x05,0x00,0xe9,0xfc,0xfb,0xe5,0x02,0x0d,0x03,0x00,0x0d,0x00,0x88,0x0d +,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x05,0x00,0xc6,0x06,0x9e +,0x36,0xff,0xbe,0x02,0x00,0xe8,0xe1,0x01,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x9a,0x03 +,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x39,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03,0xcd +,0x39,0xe9,0xbb,0x01,0x83,0x3e,0xa3,0x36,0x03,0x74,0x0a,0x83,0x3e,0xa3,0x36,0x04 +,0x74,0x03,0xe9,0xaa,0x01,0xbe,0x06,0x00,0xe8,0xae,0x01,0xb8,0x95,0x03,0xcd,0x39 +,0xe9,0x9c,0x01,0x83,0x3e,0xa3,0x36,0x05,0x74,0x03,0xe9,0x92,0x01,0xbe,0x02,0x00 +,0xe8,0x96,0x01,0xb8,0x99,0x03,0xcd,0x39,0xe9,0x84,0x01,0xc7,0x06,0x0f,0x37,0x05 +,0x00,0xe9,0x7b,0x01,0xe5,0x02,0x25,0xff,0xdf,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x07 +,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xe9,0x65,0x01,0xe8,0xd5,0x04,0xc6,0x06,0x9d +,0x36,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc7,0x06 +,0xa8,0x02,0x00,0x00,0xc7,0x06,0x4c,0x37,0x01,0x00,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xe9,0x67,0xfc,0xb8,0x9a,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09 +,0xc7,0x06,0x33,0x37,0x02,0x00,0xe9,0x16,0x01,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9 +,0x0d,0x01,0xff,0x06,0x8e,0x34,0x83,0x0e,0xc2,0x34,0x08,0xc7,0x06,0x3d,0x37,0x03 +,0x00,0xe9,0xff,0xfa,0xc3,0x52,0x50,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0x58,0x5a +,0xc3,0xc7,0x06,0x3d,0x37,0x00,0x00,0xe9,0xe9,0xfa,0xfa,0xe8,0x54,0x04,0xb8,0x80 +,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xd8,0x2b,0xb8,0x7f,0x03,0x8e,0xc0,0x26 +,0xc7,0x06,0x04,0x00,0xe8,0x2c,0x33,0xc0,0x8e,0xc0,0xa1,0xa7,0x36,0xa3,0xa9,0x36 +,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0xab,0x36,0xe7,0x02,0xc7,0x06,0x05,0x37,0x00,0x00 +,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xc6,0x06,0x9d,0x36 +,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0xa3,0x36 +,0x00,0x00,0xc7,0x06,0x0f,0x37,0x00,0x00,0xc7,0x06,0xa8,0x02,0x00,0x00,0xc7,0x06 +,0x4c,0x37,0x01,0x00,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0xbb +,0xff,0x7f,0xcd,0x53,0xe8,0x7c,0xf9,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xfb,0xc3 +,0x8d,0x3e,0xc0,0x53,0x8d,0x36,0xf0,0x38,0xb9,0x0e,0x00,0x8b,0x1e,0x30,0x34,0x89 +,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05,0x89,0x44,0x04,0x83 +,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xb8,0x80,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04 +,0x00,0xe2,0x51,0xb8,0x7f,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xb2,0x52,0x33 +,0xc0,0x8e,0xc0,0xc7,0x06,0xa1,0x36,0x01,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc3 +,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e,0xff,0xa4,0xa0,0x53,0xe8 +,0x8c,0xdb,0xc3,0xe8,0x48,0xf7,0xe9,0xf6,0xff,0x8e,0x06,0x38,0x34,0xe8,0x07,0xe1 +,0x26,0xc7,0x06,0x04,0x00,0xdf,0x4f,0xcd,0x50,0xc3,0x26,0xc7,0x06,0x0a,0x00,0x00 +,0x00,0x26,0xff,0x26,0x04,0x00,0xcd,0x34,0xe9,0xd4,0xff,0xa1,0xd1,0x36,0x26,0x39 +,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39,0x06,0x1c,0x00,0x75,0x18,0xa1 +,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00 +,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0x83,0x3e,0xa3,0x36,0x02,0x75,0x05,0xcd,0x34,0xe9,0x56,0xfb,0x83,0x3e +,0xa3,0x36,0x00,0x74,0xb1,0x83,0x3e,0xa3,0x36,0x05,0x77,0xaa,0x26,0xf6,0x06,0x0a +,0x00,0xff,0x75,0xa2,0xe8,0xfd,0xdd,0x50,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9 +,0x8c,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x76 +,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9,0x6e,0x00,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75 +,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00,0x80,0x74,0x35,0x26,0x80,0x3e,0x29 +,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9 +,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x75,0x45,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34 +,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26 +,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b,0x26,0x80,0x3e,0x19,0x00,0x00,0x74 +,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10,0x00,0x74,0x12,0x26,0xa0,0x28,0x00 +,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0x58,0x23 +,0xc0,0x74,0x03,0xe9,0xdd,0xfe,0x81,0x26,0x9b,0x36,0xff,0xfe,0x26,0xa1,0x20,0x00 +,0x3b,0x06,0xd1,0x36,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10 +,0x26,0xa1,0x24,0x00,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba +,0x34,0x26,0xa1,0x24,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1 +,0xe6,0x80,0xfc,0x09,0x74,0x03,0xe8,0xf6,0xf5,0xa1,0x05,0x37,0x0b,0x06,0x07,0x37 +,0x0b,0x06,0x09,0x37,0x74,0x3e,0x26,0xa1,0x20,0x00,0x3b,0x06,0x05,0x37,0x75,0x17 +,0x26,0xa1,0x22,0x00,0x3b,0x06,0x07,0x37,0x75,0x0d,0x26,0xa1,0x24,0x00,0x3b,0x06 +,0x09,0x37,0x75,0x03,0xe9,0x1d,0x00,0x26,0xa0,0x28,0x00,0x24,0x0f,0x3c,0x03,0x74 +,0x1b,0x3c,0x00,0x75,0x0f,0x83,0x3e,0xa3,0x36,0x04,0x74,0x10,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x74,0x08,0x2e,0xff,0x94,0xf8,0x53,0xe9,0x33,0xfe,0xcd,0x34,0xc7,0x06 +,0x3d,0x37,0x01,0x00,0xe9,0x2c,0xf8,0x83,0x3e,0xa3,0x36,0x05,0x74,0x10,0x83,0x3e +,0xa3,0x36,0x01,0x7e,0x09,0x83,0xee,0x16,0x2e,0xff,0x94,0x24,0x54,0xc3,0xcd,0x34 +,0xc3,0x26,0xa1,0x0c,0x00,0x3d,0xff,0x7f,0x74,0x05,0x26,0xff,0x26,0x04,0x00,0xe9 +,0xfd,0xfd,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b,0xa9,0x00,0x10,0x75,0x09,0x8b +,0x1e,0x43,0x37,0xff,0xe3,0xe9,0x97,0x00,0xc7,0x06,0x35,0x37,0x05,0x00,0xc7,0x06 +,0x43,0x37,0x28,0x52,0xf7,0x06,0xf4,0x33,0x00,0x08,0x74,0x06,0xc7,0x06,0x43,0x37 +,0x1a,0x52,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xc5,0xfd,0xa9,0x00,0x08,0x74,0xd9,0xff +,0x0e,0x35,0x37,0x75,0xed,0xe9,0x30,0x00,0xa9,0x00,0x08,0x75,0xcb,0xff,0x0e,0x35 +,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x0f +,0x81,0x0e,0x9b,0x36,0x00,0x80,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x90,0xfd,0xc7 +,0x06,0x3d,0x37,0x02,0x00,0xe9,0x8b,0xf7,0x80,0x26,0x9e,0x36,0xff,0x75,0x30,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x20,0xff,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e +,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08 +,0x00,0x00,0x01,0xe9,0x09,0x00,0xc7,0x06,0x3d,0x37,0x04,0x00,0xe9,0x54,0xf7,0x81 +,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06,0xe5,0x0a,0xa9,0x00,0x80,0x74 +,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x49,0xff,0xe9 +,0x2d,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0xbe,0x29,0x00,0xe8,0x2b,0xfd,0xe9,0x1e +,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x04,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00 +,0xe9,0x10,0xf7,0xe9,0x09,0xfd,0xcd,0x34,0xc3,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x0c,0xf5,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x20,0xf3 +,0xe8,0x43,0xf3,0x83,0x0e,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xd2 +,0xf5,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0xbe,0x00 +,0x00,0xe8,0x30,0xf5,0xc6,0x06,0xa0,0x36,0x0e,0xb8,0x9c,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xc7,0x06,0xa1,0x36,0x01,0x00,0xe9 +,0xa5,0xf6,0x06,0xb8,0x8f,0x03,0xcd,0x3a,0xb8,0x90,0x03,0xcd,0x3a,0xb8,0x91,0x03 +,0xcd,0x3a,0xb8,0x92,0x03,0xcd,0x3a,0xb8,0x93,0x03,0xcd,0x3a,0xb8,0x94,0x03,0xcd +,0x3a,0xb8,0x95,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x3a +,0xb8,0x98,0x03,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x3a,0xb8,0x9a,0x03,0xcd,0x3a,0xb8 +,0x9b,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0x07,0xc3 +,0xf7,0x49,0xf1,0x4e,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xf8,0x51,0xdf,0x4f +,0xfa,0x4f,0x0b,0x50,0xd1,0x51,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f +,0xe4,0x4e,0x06,0x00,0xcd,0x4a,0x04,0x00,0xe4,0x4e,0x19,0x00,0xad,0x4b,0xfa,0x00 +,0x82,0x4c,0x08,0x07,0x09,0x4c,0x14,0x00,0x24,0x4e,0x64,0x00,0xd7,0x4d,0xf4,0x01 +,0x64,0x4e,0xbc,0x02,0x7a,0x4e,0xe8,0x03,0x43,0x4e,0x02,0x00,0xb3,0x4e,0xf4,0x01 +,0x5b,0x4e,0xf4,0x01,0xe5,0x4e,0x14,0x00,0x06,0x50,0x06,0x50,0x95,0x4c,0xc1,0x52 +,0xc1,0x52,0xfe,0x4c,0xda,0x4c,0x06,0x50,0x06,0x50,0x06,0x50,0x06,0x50,0xb7,0x51 +,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0x06,0x50,0xd5,0x4a,0x06,0x50 +,0x1d,0x4c,0x06,0x50,0x83,0x4d,0x1f,0x4d,0x1f,0x4d,0xed,0x40,0xfa,0x40,0x07,0x41 +,0x37,0x37,0x2e,0x37,0x37,0x20,0x20,0x79,0x79,0x2f,0x79,0x79,0x2f,0x79,0x79,0x20 +,0x30,0x31,0x2e,0x39,0x30,0x20,0x20,0x30,0x32,0x2f,0x31,0x37,0x2f,0x39,0x39,0x20 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x90,0xea,0xc0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x06 +} ; +#endif diff -urN linux-2.4.18/drivers/net/tokenring/Config.in linux-2.4.19-pre5/drivers/net/tokenring/Config.in --- linux-2.4.18/drivers/net/tokenring/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/Config.in Sat Mar 30 22:55:28 2002 @@ -18,6 +18,7 @@ fi dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI + dep_tristate ' 3Com 3C359 Token Link Velocity XL adapter support' CONFIG_3C359 $CONFIG_TR $CONFIG_PCI tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR if [ "$CONFIG_TMS380TR" != "n" ]; then dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI diff -urN linux-2.4.18/drivers/net/tokenring/Makefile linux-2.4.19-pre5/drivers/net/tokenring/Makefile --- linux-2.4.18/drivers/net/tokenring/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/Makefile Sat Mar 30 22:55:28 2002 @@ -21,6 +21,7 @@ obj-$(CONFIG_TMSPCI) += tmspci.o obj-$(CONFIG_TMSISA) += tmsisa.o obj-$(CONFIG_SMCTR) += smctr.o +obj-$(CONFIG_3C359) += 3c359.o O_TARGET := tr.o diff -urN linux-2.4.18/drivers/net/tokenring/lanstreamer.c linux-2.4.19-pre5/drivers/net/tokenring/lanstreamer.c --- linux-2.4.18/drivers/net/tokenring/lanstreamer.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/lanstreamer.c Sat Mar 30 22:55:35 2002 @@ -60,6 +60,11 @@ * malloc free checks, reviewed code. * 03/13/00 - Added spinlocks for smp * 03/08/01 - Added support for module_init() and module_exit() + * 08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue + * calls and other incorrectness - Kent Yoder + * 11/05/01 - Restructured the interrupt function, added delays, reduced the + * the number of TX descriptors to 1, which together can prevent + * the card from locking up the box - * * To Do: * @@ -84,6 +89,14 @@ #define STREAMER_NETWORK_MONITOR 0 +/* #define CONFIG_PROC_FS */ + +/* + * Allow or disallow ioctl's for debugging + */ + +#define STREAMER_IOCTL 0 + #include #include @@ -105,6 +118,7 @@ #include #include #include +#include #include #include @@ -121,7 +135,8 @@ * Official releases will only have an a.b.c version number format. */ -static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan"; +static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n" + " v0.5.1 03/04/02 - Kent Yoder"; static struct pci_device_id streamer_pci_tbl[] __initdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, @@ -175,6 +190,10 @@ MODULE_PARM(message_level, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i"); +#if STREAMER_IOCTL +static int streamer_ioctl(struct net_device *, struct ifreq *, int); +#endif + static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); @@ -206,6 +225,8 @@ __u32 mmio_start, mmio_end, mmio_flags, mmio_len; int rc=0; static int card_no=-1; + u16 pcr; + u8 cls = 0; #if STREAMER_DEBUG printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); @@ -281,7 +302,11 @@ dev->hard_start_xmit = &streamer_xmit; dev->change_mtu = &streamer_change_mtu; dev->stop = &streamer_close; +#if STREAMER_IOCTL + dev->do_ioctl = &streamer_ioctl; +#else dev->do_ioctl = NULL; +#endif dev->set_multicast_list = &streamer_set_rx_mode; dev->get_stats = &streamer_get_stats; dev->set_mac_address = &streamer_set_mac_address; @@ -303,6 +328,27 @@ spin_lock_init(&streamer_priv->streamer_lock); + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls); + cls <<= 2; + if (cls != SMP_CACHE_BYTES) { + printk(KERN_INFO " PCI cache line size set incorrectly " + "(%i bytes) by BIOS/FW, ", cls); + if (cls > SMP_CACHE_BYTES) + printk("expecting %i\n", SMP_CACHE_BYTES); + else { + printk("correcting to %i\n", SMP_CACHE_BYTES); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, + SMP_CACHE_BYTES >> 2); + } + } + + pci_read_config_word (pdev, PCI_COMMAND, &pcr); + + pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR); + + pci_write_config_word (pdev, PCI_COMMAND, pcr); + pci_read_config_word (pdev, PCI_COMMAND, &pcr); + printk("%s \n", version); printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, streamer_priv->streamer_card_name, @@ -403,6 +449,7 @@ printk("GPR: %x\n", readw(streamer_mmio + GPR)); printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK)); #endif + writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL ); if (streamer_priv->streamer_ring_speed == 0) { /* Autosense */ writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE, @@ -558,8 +605,6 @@ do { int i; - save_flags(flags); - cli(); for (i = 0; i < SRB_COMMAND_SIZE; i += 2) { writew(0, streamer_mmio + LAPDINC); } @@ -599,11 +644,12 @@ } printk("\n"); #endif - + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); streamer_priv->srb_queued = 1; /* signal solo that SRB command has been issued */ writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); + spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); while (streamer_priv->srb_queued) { interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ); @@ -617,7 +663,6 @@ break; } } - restore_flags(flags); #if STREAMER_DEBUG printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK)); @@ -767,9 +812,12 @@ streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0; streamer_priv->streamer_tx_ring[i].buffer = 0; streamer_priv->streamer_tx_ring[i].buflen = 0; + streamer_priv->streamer_tx_ring[i].rsvd1 = 0; + streamer_priv->streamer_tx_ring[i].rsvd2 = 0; + streamer_priv->streamer_tx_ring[i].rsvd3 = 0; } streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward = - virt_to_bus(&streamer_priv->streamer_tx_ring[0]);; + virt_to_bus(&streamer_priv->streamer_tx_ring[0]); streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE; streamer_priv->tx_ring_free = 0; /* next entry in tx ring to use */ @@ -941,37 +989,30 @@ __u8 *streamer_mmio = streamer_priv->streamer_mmio; __u16 sisr; __u16 misr; - __u16 sisrmask; + u8 max_intr = MAX_INTR; - sisrmask = SISR_MI; - writew(~sisrmask, streamer_mmio + SISR_MASK_RUM); + spin_lock(&streamer_priv->streamer_lock); sisr = readw(streamer_mmio + SISR); - writew(~sisr, streamer_mmio + SISR_RUM); - misr = readw(streamer_mmio + MISR_RUM); - writew(~misr, streamer_mmio + MISR_RUM); - if (!sisr) - { /* Interrupt isn't for us */ - writew(~misr,streamer_mmio+MISR_RUM); - return; - } + while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | + SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR)) + && (max_intr > 0)) { - spin_lock(&streamer_priv->streamer_lock); + if(sisr & SISR_PAR_ERR) { + writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); + } - if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY)) - || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) { - if (sisr & SISR_SRB_REPLY) { - if (streamer_priv->srb_queued == 1) { - wake_up_interruptible(&streamer_priv->srb_wait); - } else if (streamer_priv->srb_queued == 2) { - streamer_srb_bh(dev); - } - streamer_priv->srb_queued = 0; + else if(sisr & SISR_SERR_ERR) { + writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } - /* SISR_SRB_REPLY */ + + else if(sisr & SISR_MI) { + misr = readw(streamer_mmio + MISR_RUM); + if (misr & MISR_TX2_EOF) { - while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) - { + while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) { streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1); streamer_priv->free_tx_ring_entries++; streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len; @@ -981,6 +1022,9 @@ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0; } netif_wake_queue(dev); } @@ -989,7 +1033,30 @@ streamer_rx(dev); } /* MISR_RX_EOF */ - if (sisr & SISR_ADAPTER_CHECK) { + + if (misr & MISR_RX_NOBUF) { + /* According to the documentation, we don't have to do anything, + * but trapping it keeps it out of /var/log/messages. + */ + } /* SISR_RX_NOBUF */ + + writew(~misr, streamer_mmio + MISR_RUM); + (void)readw(streamer_mmio + MISR_RUM); + } + + else if (sisr & SISR_SRB_REPLY) { + if (streamer_priv->srb_queued == 1) { + wake_up_interruptible(&streamer_priv->srb_wait); + } else if (streamer_priv->srb_queued == 2) { + streamer_srb_bh(dev); + } + streamer_priv->srb_queued = 0; + + writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); + } + + else if (sisr & SISR_ADAPTER_CHECK) { printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA); printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n", @@ -1001,38 +1068,37 @@ } /* SISR_ADAPTER_CHECK */ - if (sisr & SISR_ASB_FREE) { + else if (sisr & SISR_ASB_FREE) { /* Wake up anything that is waiting for the asb response */ if (streamer_priv->asb_queued) { streamer_asb_bh(dev); } + writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_ASB_FREE */ - if (sisr & SISR_ARB_CMD) { + else if (sisr & SISR_ARB_CMD) { streamer_arb_cmd(dev); + writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_ARB_CMD */ - if (sisr & SISR_TRB_REPLY) { + else if (sisr & SISR_TRB_REPLY) { /* Wake up anything that is waiting for the trb response */ if (streamer_priv->trb_queued) { wake_up_interruptible(&streamer_priv-> trb_wait); } streamer_priv->trb_queued = 0; + writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_TRB_REPLY */ - if (misr & MISR_RX_NOBUF) { - /* According to the documentation, we don't have to do anything, but trapping it keeps it out of - /var/log/messages. */ - } /* SISR_RX_NOBUF */ - } else { - printk(KERN_WARNING "%s: Unexpected interrupt: %x\n", - dev->name, sisr); - printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name, - readw(streamer_mmio + SISR_MASK)); - } /* One if the interrupts we want */ - writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + sisr = readw(streamer_mmio + SISR); + max_intr--; + } /* while() */ + spin_unlock(&streamer_priv->streamer_lock) ; } @@ -1044,13 +1110,16 @@ unsigned long flags ; spin_lock_irqsave(&streamer_priv->streamer_lock, flags); - netif_stop_queue(dev); if (streamer_priv->free_tx_ring_entries) { streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data); + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len; + streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb; streamer_priv->free_tx_ring_entries--; #if STREAMER_DEBUG_PACKETS @@ -1067,12 +1136,13 @@ #endif writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA); + (void)readl(streamer_mmio + TX2LFDA); streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); - netif_wake_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 0; } else { + netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 1; } @@ -1092,12 +1162,13 @@ writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC); writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - save_flags(flags); - cli(); + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); streamer_priv->srb_queued = 1; writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); + spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); + while (streamer_priv->srb_queued) { interruptible_sleep_on_timeout(&streamer_priv->srb_wait, @@ -1114,7 +1185,6 @@ } } - restore_flags(flags); streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { @@ -1806,6 +1876,64 @@ return size; } #endif +#endif + +#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int i; + struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + u8 *streamer_mmio = streamer_priv->streamer_mmio; + + switch(cmd) { + case IOCTL_SISR_MASK: + writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + break; + case IOCTL_SPIN_LOCK_TEST: + printk(KERN_INFO "spin_lock() called.\n"); + spin_lock(&streamer_priv->streamer_lock); + spin_unlock(&streamer_priv->streamer_lock); + printk(KERN_INFO "spin_unlock() finished.\n"); + break; + case IOCTL_PRINT_BDAS: + printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n", + readw(streamer_mmio + RXBDA), + readw(streamer_mmio + RXLBDA), + readw(streamer_mmio + TX2FDA), + readw(streamer_mmio + TX2LFDA)); + break; + case IOCTL_PRINT_REGISTERS: + printk(KERN_INFO "registers:\n"); + printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n", + readw(streamer_mmio + SISR), + readw(streamer_mmio + MISR_RUM), + readw(streamer_mmio + LISR), + readw(streamer_mmio + BCTL), + readw(streamer_mmio + BMCTL_SUM), + readw(streamer_mmio + SISR_MASK), + readw(streamer_mmio + MISR_MASK)); + break; + case IOCTL_PRINT_RX_BUFS: + printk(KERN_INFO "Print rx bufs:\n"); + for(i=0; istreamer_rx_ring[i].status); + break; + case IOCTL_PRINT_TX_BUFS: + printk(KERN_INFO "Print tx bufs:\n"); + for(i=0; istreamer_tx_ring[i].status); + break; + case IOCTL_RX_CMD: + streamer_rx(dev); + printk(KERN_INFO "Sent rx command.\n"); + break; + default: + printk(KERN_INFO "Bad ioctl!\n"); + } + return 0; +} #endif static struct pci_driver streamer_pci_driver = { diff -urN linux-2.4.18/drivers/net/tokenring/lanstreamer.h linux-2.4.19-pre5/drivers/net/tokenring/lanstreamer.h --- linux-2.4.18/drivers/net/tokenring/lanstreamer.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/lanstreamer.h Sat Mar 30 22:55:35 2002 @@ -56,11 +56,36 @@ * * 12/10/99 - Alpha Release 0.1.0 * First release to the public + * 08/15/01 - Added ioctl() definitions and others - Kent Yoder * */ +#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include +#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE +#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1 +#define IOCTL_RX_CMD SIOCDEVPRIVATE+2 +#define IOCTL_TX_CMD SIOCDEVPRIVATE+3 +#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4 +#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5 +#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6 +#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7 +#endif + +/* MAX_INTR - the maximum number of times we can loop + * inside the interrupt function before returning + * control to the OS (maximum value is 256) + */ +#define MAX_INTR 5 + +#define CLS 0x0C +#define MLR 0x86 +#define LTR 0x0D + #define BCTL 0x60 #define BCTL_SOFTRESET (1<<15) +#define BCTL_RX_FIFO_8 (1<<1) +#define BCTL_TX_FIFO_8 (1<<3) #define GPR 0x4a #define GPR_AUTOSENSE (1<<2) @@ -89,6 +114,7 @@ #define SISR_MASK_RUM 0x58 #define SISR_MI (1<<15) +#define SISR_SERR_ERR (1<<14) #define SISR_TIMER (1<<11) #define SISR_LAP_PAR_ERR (1<<10) #define SISR_LAP_ACC_ERR (1<<9) @@ -218,7 +244,13 @@ /* Streamer defaults for buffers */ #define STREAMER_RX_RING_SIZE 16 /* should be a power of 2 */ -#define STREAMER_TX_RING_SIZE 8 /* should be a power of 2 */ +/* Setting the number of TX descriptors to 1 is a workaround for an + * undocumented hardware problem with the lanstreamer board. Setting + * this to something higher may slightly increase the throughput you + * can get from the card, but at the risk of locking up the box. - + * + */ +#define STREAMER_TX_RING_SIZE 1 /* should be a power of 2 */ #define PKT_BUF_SZ 4096 /* Default packet size */ diff -urN linux-2.4.18/drivers/net/tokenring/olympic.c linux-2.4.19-pre5/drivers/net/tokenring/olympic.c --- linux-2.4.18/drivers/net/tokenring/olympic.c Sun Dec 23 16:23:45 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/olympic.c Sat Mar 30 22:55:28 2002 @@ -50,10 +50,16 @@ * adapter when live does not take the system down with it. * * 06/02/01 - Clean up, copy skb for small packets + * + * 06/22/01 - Add EISR error handling routines + * + * 07/19/01 - Improve bad LAA reporting, strip out freemem + * into a separate function, its called from 3 + * different places now. + * 02/09/01 - Replaced sleep_on. * * To Do: * - * Complete full Cardbus / hot-swap support. * Wake on lan * * If Problems do Occur @@ -105,7 +111,7 @@ */ static char version[] __devinitdata = -"Olympic.c v0.9.7 6/02/01 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v1.0.0 2/9/02 - Peter De Schrijver & Mike Phillips" ; static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", @@ -172,6 +178,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev); static int olympic_close(struct net_device *dev); static void olympic_set_rx_mode(struct net_device *dev); +static void olympic_freemem(struct net_device *dev) ; static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats * olympic_get_stats(struct net_device *dev); static int olympic_set_mac_address(struct net_device *dev, void *addr) ; @@ -396,6 +403,8 @@ char open_error[255] ; int i, open_finished = 1 ; + DECLARE_WAITQUEUE(wait,current) ; + if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { return -EAGAIN; } @@ -424,8 +433,6 @@ do { int i; - save_flags(flags); - cli(); for(i=0;iolympic_laa[0]) { + if (olympic_priv->olympic_laa[0] | olympic_priv->olympic_laa[1] | olympic_priv->olympic_laa[2]) { writeb(olympic_priv->olympic_laa[0],init_srb+12); writeb(olympic_priv->olympic_laa[1],init_srb+13); writeb(olympic_priv->olympic_laa[2],init_srb+14); @@ -452,14 +463,20 @@ memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; } writeb(1,init_srb+30); - + + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; + + add_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_INTERRUPTIBLE) ; + while(olympic_priv->srb_queued) { - interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ); + schedule() ; if(signal_pending(current)) { printk(KERN_WARNING "%s: Signal received in open.\n", dev->name); @@ -474,8 +491,11 @@ olympic_priv->srb_queued=0; break ; } + set_current_state(TASK_INTERRUPTIBLE) ; } - restore_flags(flags); + remove_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_RUNNING) ; + #if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) @@ -515,6 +535,17 @@ return -EIO ; } /* if autosense && open_finished */ + } else if (init_srb[2] == 0x32) { + printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + olympic_priv->olympic_laa[0], + olympic_priv->olympic_laa[1], + olympic_priv->olympic_laa[2], + olympic_priv->olympic_laa[3], + olympic_priv->olympic_laa[4], + olympic_priv->olympic_laa[5]) ; + free_irq(dev->irq,dev) ; + return -EIO ; } else { printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]); free_irq(dev->irq, dev); @@ -634,7 +665,10 @@ olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ - writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM); + writel(0xffffffff, olympic_mmio+EISR_RWM) ; /* clean the eisr */ + writel(0,olympic_mmio+EISR) ; + writel(EISR_MASK_OPTIONS,olympic_mmio+EISR_MASK) ; /* enables most of the TX error interrupts */ + writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE | SISR_ERR,olympic_mmio+SISR_MASK_SUM); #if OLYMPIC_DEBUG printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); @@ -822,6 +856,35 @@ } +static void olympic_freemem(struct net_device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + int i; + + for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); + if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { + pci_unmap_single(olympic_priv->pdev, + le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), + olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); + } + olympic_priv->rx_status_last_received++; + olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; + } + /* unmap rings */ + pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, + sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, + sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); + + pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, + sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, + sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); + + return ; +} + static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev= (struct net_device *)dev_id; @@ -842,9 +905,33 @@ spin_lock(&olympic_priv->olympic_lock); + /* Hotswap gives us this on removal */ + if (sisr == 0xffffffff) { + printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ; + olympic_freemem(dev) ; + free_irq(dev->irq, dev) ; + dev->stop = NULL ; + spin_unlock(&olympic_priv->olympic_lock) ; + return ; + } + if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | - SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) { + SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF | SISR_ERR)) { + /* If we ever get this the adapter is seriously dead. Only a reset is going to + * bring it back to life. We're talking pci bus errors and such like :( */ + if((sisr & SISR_ERR) && (readl(olympic_mmio+EISR) & EISR_MASK_OPTIONS)) { + printk(KERN_ERR "Olympic: EISR Error, EISR=%08x\n",readl(olympic_mmio+EISR)) ; + printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ; + printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ; + printk(KERN_ERR "or the linux-tr mailing list.\n") ; + olympic_freemem(dev) ; + free_irq(dev->irq, dev) ; + dev->stop = NULL ; + spin_unlock(&olympic_priv->olympic_lock) ; + return ; + } /* SISR_ERR */ + if(sisr & SISR_SRB_REPLY) { if(olympic_priv->srb_queued==1) { wake_up_interruptible(&olympic_priv->srb_wait); @@ -878,34 +965,12 @@ } /* SISR_RX_STATUS */ if (sisr & SISR_ADAPTER_CHECK) { - int i ; netif_stop_queue(dev); printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); - writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); - adapter_check_area = (u8 *)(olympic_mmio+LAPWWO) ; + writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA); + adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ; printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; - /* The adapter is effectively dead, clean up and exit */ - for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - } - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - } - /* unmap rings */ - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); - + olympic_freemem(dev) ; free_irq(dev->irq, dev) ; dev->stop = NULL ; spin_unlock(&olympic_priv->olympic_lock) ; @@ -980,7 +1045,8 @@ struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; unsigned long t,flags; - int i; + + DECLARE_WAITQUEUE(wait,current) ; netif_stop_queue(dev); @@ -991,16 +1057,19 @@ writeb(0,srb+1); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - save_flags(flags); - cli(); - + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; + + add_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_INTERRUPTIBLE) ; + while(olympic_priv->srb_queued) { - interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ); + schedule() ; if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR)); @@ -1012,32 +1081,15 @@ olympic_priv->srb_queued=0; break ; } + set_current_state(TASK_INTERRUPTIBLE) ; } + remove_wait_queue(&olympic_priv->srb_wait,&wait) ; + set_current_state(TASK_RUNNING) ; - restore_flags(flags) ; olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - - for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - } - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - } - /* unmap rings */ - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); + olympic_freemem(dev) ; /* reset tx/rx fifo's and busmaster logic */ diff -urN linux-2.4.18/drivers/net/tokenring/olympic.h linux-2.4.19-pre5/drivers/net/tokenring/olympic.h --- linux-2.4.18/drivers/net/tokenring/olympic.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/tokenring/olympic.h Sat Mar 30 22:55:28 2002 @@ -79,6 +79,7 @@ #define EISR 0x34 #define EISR_RWM 0x38 #define EISR_MASK 0x3c +#define EISR_MASK_OPTIONS 0x001FFF7F #define LAPA 0x60 #define LAPWWO 0x64 diff -urN linux-2.4.18/drivers/net/tulip/ChangeLog linux-2.4.19-pre5/drivers/net/tulip/ChangeLog --- linux-2.4.18/drivers/net/tulip/ChangeLog Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/tulip/ChangeLog Sat Mar 30 22:55:35 2002 @@ -1,3 +1,10 @@ +2002-03-07 Jeff Garzik + + * tulip_core (tulip_mwi_config): Use new PCI API functions + for enabling and disabled Memory-Write-Invalidate + PCI transaction. + Fix bugs in tulip MWI config also. + 2002-02-07 Uwe Bonnes * tulip_core (tulip_pci_tbl[]): diff -urN linux-2.4.18/drivers/net/tulip/tulip_core.c linux-2.4.19-pre5/drivers/net/tulip/tulip_core.c --- linux-2.4.18/drivers/net/tulip/tulip_core.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/tulip/tulip_core.c Sat Mar 30 22:55:35 2002 @@ -2,7 +2,7 @@ /* Maintained by Jeff Garzik - Copyright 2000,2001 The Linux Kernel Team + Copyright 2000-2002 The Linux Kernel Team Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms @@ -15,8 +15,8 @@ */ #define DRV_NAME "tulip" -#define DRV_VERSION "0.9.15-pre9" -#define DRV_RELDATE "Nov 6, 2001" +#define DRV_VERSION "0.9.15-pre10" +#define DRV_RELDATE "Mar 8, 2002" #include #include @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,8 @@ static int csr0 = 0x01A00000 | 0x9000; #elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; +#elif defined(__mips__) +static int csr0 = 0x00200000 | 0x4000; #else #warning Processor architecture undefined! static int csr0 = 0x00A00000 | 0x4800; @@ -1036,41 +1039,6 @@ new frame, not around filling tp->setup_frame. This is non-deterministic when re-entered but still correct. */ -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline u32 ether_crc_le(int length, unsigned char *data) -{ - u32 crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - #undef set_bit_le #define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0) @@ -1263,7 +1231,7 @@ { struct tulip_private *tp = dev->priv; u8 cache; - u16 pci_command, new_command; + u16 pci_command; u32 csr0; if (tulip_debug > 3) @@ -1271,24 +1239,6 @@ tp->csr0 = csr0 = 0; - /* check for sane cache line size. from acenic.c. */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache); - if ((cache << 2) != SMP_CACHE_BYTES) { - printk(KERN_WARNING "%s: PCI cache line size set incorrectly " - "(%i bytes) by BIOS/FW, correcting to %i\n", - pdev->slot_name, (cache << 2), SMP_CACHE_BYTES); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, - SMP_CACHE_BYTES >> 2); - udelay(5); - } - - /* read cache line size again, hardware may not have accepted - * our cache line size change - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache); - if (!cache) - goto out; - /* if we have any cache line size at all, we can do MRM */ csr0 |= MRM; @@ -1299,15 +1249,19 @@ /* set or disable MWI in the standard PCI command bit. * Check for the case where mwi is desired but not available */ + if (csr0 & MWI) pci_set_mwi(pdev); + else pci_clear_mwi(pdev); + + /* read result from hardware (in case bit refused to enable) */ pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (csr0 & MWI) new_command = pci_command | PCI_COMMAND_INVALIDATE; - else new_command = pci_command & ~PCI_COMMAND_INVALIDATE; - if (new_command != pci_command) { - pci_write_config_word(pdev, PCI_COMMAND, new_command); - udelay(5); - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if ((csr0 & MWI) && (!(pci_command & PCI_COMMAND_INVALIDATE))) - csr0 &= ~MWI; + if ((csr0 & MWI) && (!(pci_command & PCI_COMMAND_INVALIDATE))) + csr0 &= ~MWI; + + /* if cache line size hardwired to zero, no MWI */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache); + if ((csr0 & MWI) && (cache == 0)) { + csr0 &= ~MWI; + pci_clear_mwi(pdev); } /* assign per-cacheline-size cache alignment and @@ -1324,20 +1278,29 @@ csr0 |= MRL | (3 << CALShift) | (32 << BurstLenShift); break; default: - goto out; + cache = 0; + break; } - tp->csr0 = csr0; - goto out; + /* if we have a good cache line size, we by now have a good + * csr0, so save it and exit + */ + if (cache) + goto out; + /* we don't have a good csr0 or cache line size, disable MWI */ if (csr0 & MWI) { - pci_command &= ~PCI_COMMAND_INVALIDATE; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); + pci_clear_mwi(pdev); csr0 &= ~MWI; } - tp->csr0 = csr0 | (8 << BurstLenShift) | (1 << CALShift); + + /* sane defaults for burst length and cache alignment + * originally from de4x5 driver + */ + csr0 |= (8 << BurstLenShift) | (1 << CALShift); out: + tp->csr0 = csr0; if (tulip_debug > 2) printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n", pdev->slot_name, cache, csr0); @@ -1599,6 +1562,16 @@ #ifdef CONFIG_DDB5477 if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) { /* DDB5477 MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif +#ifdef CONFIG_MIPS_COBALT + if ((pdev->bus->number == 0) && + ((PCI_SLOT(pdev->devfn) == 7) || + (PCI_SLOT(pdev->devfn) == 12))) { + /* Cobalt MAC address in first EEPROM locations. */ sa_offset = 0; /* No media table either */ tp->flags &= ~HAS_MEDIA_TABLE; diff -urN linux-2.4.18/drivers/net/via-rhine.c linux-2.4.19-pre5/drivers/net/via-rhine.c --- linux-2.4.18/drivers/net/via-rhine.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/via-rhine.c Sat Mar 30 22:55:35 2002 @@ -161,6 +161,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -1533,26 +1534,6 @@ writel(0, ioaddr + RxMissed); readw(ioaddr + RxCRCErrs); readw(ioaddr + RxMissed); -} - - -/* The big-endian AUTODIN II ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; } static void via_rhine_set_rx_mode(struct net_device *dev) diff -urN linux-2.4.18/drivers/net/wan/Config.in linux-2.4.19-pre5/drivers/net/wan/Config.in --- linux-2.4.18/drivers/net/wan/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wan/Config.in Sat Mar 30 22:55:35 2002 @@ -24,6 +24,7 @@ dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX + dep_tristate ' Support for MUNICH based boards: SliceCOM, PCICOM (WelCOM)' CONFIG_COMX_HW_MUNICH $CONFIG_COMX dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX if [ "$CONFIG_LAPB" = "y" ]; then dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX diff -urN linux-2.4.18/drivers/net/wan/Makefile linux-2.4.19-pre5/drivers/net/wan/Makefile --- linux-2.4.18/drivers/net/wan/Makefile Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/wan/Makefile Sat Mar 30 22:55:35 2002 @@ -29,6 +29,7 @@ obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o +obj-$(CONFIG_COMX_HW_MUNICH) += comx-hw-munich.o obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o diff -urN linux-2.4.18/drivers/net/wan/comx-hw-locomx.c linux-2.4.19-pre5/drivers/net/wan/comx-hw-locomx.c --- linux-2.4.18/drivers/net/wan/comx-hw-locomx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wan/comx-hw-locomx.c Sat Mar 30 22:55:28 2002 @@ -154,11 +154,9 @@ return -ENODEV; } - if (check_region(dev->base_addr, hw->io_extent)) { + if (!request_region(dev->base_addr, hw->io_extent, dev->name)) { return -EAGAIN; } - - request_region(dev->base_addr, hw->io_extent, dev->name); hw->board.chanA.ctrlio=dev->base_addr + 5; hw->board.chanA.dataio=dev->base_addr + 7; diff -urN linux-2.4.18/drivers/net/wan/comx-hw-munich.c linux-2.4.19-pre5/drivers/net/wan/comx-hw-munich.c --- linux-2.4.18/drivers/net/wan/comx-hw-munich.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/wan/comx-hw-munich.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,2860 @@ +/* + * Hardware-level driver for the SliceCOM board for Linux kernels 2.4.X + * + * Current maintainer / latest changes: Pasztor Szilard + * + * Original author: Bartok Istvan + * Based on skeleton by Tivadar Szemethy + * + * 0.51: + * - port for 2.4.x + * - clean up some code, make it more portable + * - busted direct hardware access through mapped memory + * - fix a possible race + * - prevent procfs buffer overflow + * + * 0.50: + * - support for the pcicom board, lots of rearrangements + * - handle modem status lines + * + * 0.50a: + * - fix for falc version 1.0 + * + * 0.50b: T&t + * - fix for bad localbus + */ + +#define VERSION "0.51" +#define VERSIONSTR "SliceCOM v" VERSION ", 2002/01/07\n" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COMX_NEW + +#ifndef COMX_NEW +#include "../include/comx.h" +#include "../include/munich32x.h" +#include "../include/falc-lh.h" +#else +#include "comx.h" +#include "munich32x.h" +#include "falc-lh.h" +#endif + +MODULE_AUTHOR + ("Bartok Istvan , Gergely Madarasz , Szilard Pasztor "); +MODULE_DESCRIPTION + ("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters"); + +/* + * TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda: + */ + +#define FILENAME_BOARDNUM "boardnum" /* /proc/comx/comx0.1/boardnum */ +#define FILENAME_TIMESLOTS "timeslots" /* /proc/comx/comx0.1/timeslots */ +#define FILENAME_FRAMING "framing" /* /proc/comx/comx0.1/framing */ +#define FILENAME_LINECODE "linecode" /* /proc/comx/comx0.1/linecode */ +#define FILENAME_CLOCK_SOURCE "clock_source" /* /proc/comx/comx0.1/clock_source */ +#define FILENAME_LOOPBACK "loopback" /* /proc/comx/comx0.1/loopback */ +#define FILENAME_REG "reg" /* /proc/comx/comx0.1/reg */ +#define FILENAME_LBIREG "lbireg" /* /proc/comx/comx0.1/lbireg */ + +#define SLICECOM_BOARDNUM_DEFAULT 0 + +#define SLICECOM_FRAMING_CRC4 1 +#define SLICECOM_FRAMING_NO_CRC4 2 +#define SLICECOM_FRAMING_DEFAULT SLICECOM_FRAMING_CRC4 + +#define SLICECOM_LINECODE_HDB3 1 +#define SLICECOM_LINECODE_AMI 2 +#define SLICECOM_LINECODE_DEFAULT SLICECOM_LINECODE_HDB3 + +#define SLICECOM_CLOCK_SOURCE_LINE 1 +#define SLICECOM_CLOCK_SOURCE_INTERNAL 2 +#define SLICECOM_CLOCK_SOURCE_DEFAULT SLICECOM_CLOCK_SOURCE_LINE + +#define SLICECOM_LOOPBACK_NONE 1 +#define SLICECOM_LOOPBACK_LOCAL 2 +#define SLICECOM_LOOPBACK_REMOTE 3 +#define SLICECOM_LOOPBACK_DEFAULT SLICECOM_LOOPBACK_NONE + +#define MUNICH_VIRT(addr) (void *)(&bar1[addr]) + +struct slicecom_stringtable +{ + char *name; + int value; +}; + +/* A convention: keep "default" the last not NULL when reading from /proc, + "error" is an indication that something went wrong, we have an undefined value */ + +struct slicecom_stringtable slicecom_framings[] = +{ + {"crc4", SLICECOM_FRAMING_CRC4}, + {"no-crc4", SLICECOM_FRAMING_NO_CRC4}, + {"default", SLICECOM_FRAMING_DEFAULT}, + {"error", 0} +}; + +struct slicecom_stringtable slicecom_linecodes[] = +{ + {"hdb3", SLICECOM_LINECODE_HDB3}, + {"ami", SLICECOM_LINECODE_AMI}, + {"default", SLICECOM_LINECODE_DEFAULT}, + {"error", 0} +}; + +struct slicecom_stringtable slicecom_clock_sources[] = +{ + {"line", SLICECOM_CLOCK_SOURCE_LINE}, + {"internal", SLICECOM_CLOCK_SOURCE_INTERNAL}, + {"default", SLICECOM_CLOCK_SOURCE_DEFAULT}, + {"error", 0} +}; + +struct slicecom_stringtable slicecom_loopbacks[] = +{ + {"none", SLICECOM_LOOPBACK_NONE}, + {"local", SLICECOM_LOOPBACK_LOCAL}, + {"remote", SLICECOM_LOOPBACK_REMOTE}, + {"default", SLICECOM_LOOPBACK_DEFAULT}, + {"error", 0} +}; + +/* + * Some tunable values... + * + * Note: when tuning values which change the length of text in + * /proc/comx/comx[n]/status, keep in mind that it must be shorter then + * PAGESIZE ! + */ + +#define MAX_BOARDS 4 /* ezzel 4 kartya lehet a gepben: 0..3 */ +#define RX_DESC_MAX 8 /* Rx ring size, must be >= 4 */ +#define TX_DESC_MAX 4 /* Tx ring size, must be >= 2 */ + /* a sokkal hosszabb Tx ring mar ronthatja a nem-FIFO packet */ + /* schedulerek (fair queueing, stb.) hatekonysagat. */ +#define MAX_WORK 10 /* TOD: update the info max. ennyi-1 esemenyt dolgoz fel egy interrupt hivasnal */ + +/* + * These are tunable too, but don't touch them without fully understanding what is happening + */ + +#define UDELAY 20 /* We wait UDELAY usecs with disabled interrupts before and */ + /* after each command to avoid writing into each other's */ + /* ccb->action_spec. A _send_packet nem var, mert azt az */ + /* _interrupt()-bol is meghivhatja a LINE_tx() */ + +/* + * Just to avoid warnings about implicit declarations: + */ + +static int MUNICH_close(struct net_device *dev); +static struct comx_hardware slicecomhw; +static struct comx_hardware pcicomhw; + +static unsigned long flags; +static spinlock_t mister_lock = SPIN_LOCK_UNLOCKED; + +typedef volatile struct /* Time Slot Assignment */ +{ + u32 rxfillmask:8, // ----------------------------+------+ + // | | + rxchannel:5, // ----------------------+---+ | | + rti:1, // ---------------------+| | | | + res2:2, // -------------------++|| | | | + // |||| | | | + txfillmask:8, // ----------+------+ |||| | | | + // | | |||| | | | + txchannel:5, // ----+---+ | | |||| | | | + tti:1, // ---+| | | | |||| | | | + res1:2; // -++|| | | | |||| | | | + // 3 2 1 + // 10987654 32109876 54321098 76543210 +} timeslot_spec_t; + +typedef volatile struct /* Receive Descriptor */ +{ + u32 zero1:16, no:13, hi:1, hold:1, zero2:1; + + u32 next; + u32 data; + + u32 zero3:8, status:8, bno:13, zero4:1, c:1, fe:1; +} rx_desc_t; + +typedef volatile struct /* Transmit Descriptor */ +{ + u32 fnum:11, csm:1, no13:1, zero1:2, v110:1, no:13, hi:1, hold:1, fe:1; + + u32 next; + u32 data; + +} tx_desc_t; + +typedef volatile struct /* Channel Specification */ +{ + u32 iftf:1, mode:2, fa:1, trv:2, crc:1, inv:1, cs:1, tflag:7, ra:1, ro:1, + th:1, ta:1, to:1, ti:1, ri:1, nitbs:1, fit:1, fir:1, re:1, te:1, ch:1, + ifc:1, sfe:1, fe2:1; + + u32 frda; + u32 ftda; + + u32 itbs:6, zero1:26; + +} channel_spec_t; + +typedef volatile struct /* Configuration Control Block */ +{ + u32 action_spec; + u32 reserved1; + u32 reserved2; + timeslot_spec_t timeslot_spec[32]; + channel_spec_t channel_spec[32]; + u32 current_rx_desc[32]; + u32 current_tx_desc[32]; + u32 csa; /* Control Start Address. CSA = *CCBA; CCB = *CSA */ + /* MUNICH does it like: CCB = *( *CCBA ) */ +} munich_ccb_t; + +typedef volatile struct /* Entry in the interrupt queue */ +{ + u32 all; +} munich_intq_t; + +#define MUNICH_INTQLEN 63 /* Rx/Tx Interrupt Queue Length + (not the real len, but the TIQL/RIQL value) */ +#define MUNICH_INTQMAX ( 16*(MUNICH_INTQLEN+1) ) /* Rx/Tx/Periph Interrupt Queue size in munich_intq_t's */ +#define MUNICH_INTQSIZE ( 4*MUNICH_INTQMAX ) /* Rx/Tx/Periph Interrupt Queue size in bytes */ + +#define MUNICH_PIQLEN 4 /* Peripheral Interrupt Queue Length. Unlike the RIQL/TIQL, */ +#define MUNICH_PIQMAX ( 4*MUNICH_PIQLEN ) /* PIQL register needs it like this */ +#define MUNICH_PIQSIZE ( 4*MUNICH_PIQMAX ) + +typedef volatile u32 vol_u32; /* TOD: ezek megszunnek ha atirom readw()/writew()-re - kész */ +typedef volatile u8 vol_u8; + +typedef volatile struct /* counters of E1-errors and errored seconds, see rfc2495 */ +{ + /* use here only unsigned ints, we depend on it when calculating the sum for the last N intervals */ + + unsigned line_code_violations, /* AMI: bipolar violations, HDB3: hdb3 violations */ + path_code_violations, /* FAS errors and CRC4 errors */ + e_bit_errors, /* E-Bit Errors (the remote side received from us with CRC4-error) */ + slip_secs, /* number of seconds with (receive) Controlled Slip(s) */ + fr_loss_secs, /* number of seconds an Out Of Frame defect was detected */ + line_err_secs, /* number of seconds with one or more Line Code Violations */ + degraded_mins, /* Degraded Minute - the estimated error rate is >1E-6, but <1E-3 */ + errored_secs, /* Errored Second - at least one of these happened: + - Path Code Violation + - Out Of Frame defect + - Slip + - receiving AIS + - not incremented during an Unavailable Second */ + bursty_err_secs, /* Bursty Errored Second: (rfc2495 says it does not apply to E1) + - Path Code Violations >1, but <320 + - not a Severely Errored Second + - no AIS + - not incremented during an Unavailabla Second */ + severely_err_secs, /* Severely Errored Second: + - CRC4: >=832 Path COde Violations || >0 Out Of Frame defects + - noCRC4: >=2048 Line Code Violations + - not incremented during an Unavailable Second */ + unavail_secs; /* number of Unavailable Seconds. Unavailable state is said after: + - 10 contiguous Severely Errored Seconds + - or RAI || AIS || LOF || LOS + - (any) loopback has been set */ + + /* + * we do not strictly comply to the rfc: we do not retroactively reduce errored_secs, + * bursty_err_secs, severely_err_secs when 'unavailable state' is reached + */ + +} e1_stats_t; + +typedef volatile struct /* ezek board-adatok, nem lehetnek a slicecom_privdata -ban */ +{ + int use_count; /* num. of interfaces using the board */ + int irq; /* a kartya irq-ja. belemasoljuk a dev->irq -kba is, de csak hogy */ + /* szebb legyen az ifconfig outputja */ + /* ha != 0, az azt jelenti hogy az az irq most nekunk sikeresen */ + /* le van foglalva */ + struct pci_dev *pci; /* a kartya PCI strukturaja. NULL, ha nincs kartya */ + u32 *bar1; /* pci->base_address[0] ioremap()-ed by munich_probe(), */ + /* on x86 can be used both as a bus or virtual address. */ + /* These are the Munich's registers */ + u8 *lbi; /* pci->base_address[1] ioremap()-ed by munich_probe(), */ + /* this is a 256-byte range, the start of the LBI on the board */ + munich_ccb_t *ccb; /* virtual address of CCB */ + munich_intq_t *tiq; /* Tx Interrupt Queue */ + munich_intq_t *riq; /* Rx Interrupt Queue */ + munich_intq_t *piq; /* Peripheral Interrupt Queue (FALC interrupts arrive here) */ + int tiq_ptr, /* A 'current' helyek a tiq/riq/piq -ban. */ + riq_ptr, /* amikor feldolgoztam az interruptokat, a legelso ures */ + piq_ptr; /* interrupt_information szora mutatnak. */ + struct net_device *twins[32]; /* MUNICH channel -> network interface assignment */ + + unsigned long lastcheck; /* When were the Rx rings last checked. Time in jiffies */ + + struct timer_list modemline_timer; + char isx21; + char lineup; + char framing; /* a beallitasok tarolasa */ + char linecode; + char clock_source; + char loopback; + + char devname[30]; /* what to show in /proc/interrupts */ + unsigned histogram[MAX_WORK]; /* number of processed events in the interrupt loop */ + unsigned stat_pri_races; /* number of special events, we try to handle them */ + unsigned stat_pti_races; + unsigned stat_pri_races_missed; /* when it can not be handled, because of MAX_WORK */ + unsigned stat_pti_races_missed; + +#define SLICECOM_BOARD_INTERVALS_SIZE 97 + e1_stats_t intervals[SLICECOM_BOARD_INTERVALS_SIZE]; /* E1 line statistics */ + unsigned current_interval; /* pointer to the current interval */ + unsigned elapsed_seconds; /* elapsed seconds from the start of the current interval */ + unsigned ses_seconds; /* counter of contiguous Severely Errored Seconds */ + unsigned is_unavailable; /* set to 1 after 10 contiguous Severely Errored Seconds */ + unsigned no_ses_seconds; /* contiguous Severely Error -free seconds in unavail state */ + + unsigned deg_elapsed_seconds; /* for counting the 'Degraded Mins' */ + unsigned deg_cumulated_errors; + + struct module *owner; /* pointer to our module to avoid module load races */ +} munich_board_t; + +struct slicecom_privdata +{ + int busy; /* transmitter busy - number of packets in the Tx ring */ + int channel; /* Munich logical channel ('channel-group' in Cisco) */ + unsigned boardnum; + u32 timeslots; /* i-th bit means i-th timeslot is our */ + + int tx_ring_hist[TX_DESC_MAX]; /* histogram: number of packets in Tx ring when _send_packet is called */ + + tx_desc_t tx_desc[TX_DESC_MAX]; /* the ring of Tx descriptors */ + u8 tx_data[TX_DESC_MAX][TXBUFFER_SIZE]; /* buffers for data to transmit */ + int tx_desc_ptr; /* hanyadik descriptornal tartunk a beirassal */ + /* ahol ez all, oda irtunk utoljara */ + + rx_desc_t rx_desc[RX_DESC_MAX]; /* the ring of Rx descriptors */ + u8 rx_data[RX_DESC_MAX][RXBUFFER_SIZE]; /* buffers for received data */ + int rx_desc_ptr; /* hanyadik descriptornal tartunk az olvasassal */ + + int rafutott; +}; + +static u32 reg, reg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */ +static u32 lbireg; +static u8 lbireg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */ + +static munich_board_t slicecom_boards[MAX_BOARDS]; +static munich_board_t pcicom_boards[MAX_BOARDS]; + +/* + * Reprogram Idle Channel Registers in the FALC - send special code in not used channels + * Should be called from the open and close, when the timeslot assignment changes + */ + +void rework_idle_channels(struct net_device *dev) +{ + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + munich_board_t *board = slicecom_boards + hw->boardnum; + munich_ccb_t *ccb = board->ccb; + + u8 *lbi = board->lbi; + int i, j, tmp; + + + spin_lock_irqsave(&mister_lock, flags); + + for (i = 0; i < 4; i++) + { + tmp = 0xFF; + for (j = 0; j < 8; j++) + if (ccb->timeslot_spec[8 * i + j].tti == 0) tmp ^= (0x80 >> j); + writeb(tmp, lbi + 0x30 + i); + } + + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * Set PCM framing - /proc/comx/comx0/framing + */ + +void slicecom_set_framing(int boardnum, int value) +{ + u8 *lbi = slicecom_boards[boardnum].lbi; + + spin_lock_irqsave(&mister_lock, flags); + + slicecom_boards[boardnum].framing = value; + switch (value) + { + case SLICECOM_FRAMING_CRC4: + writeb(readb(lbi + FMR1) | 8, lbi + FMR1); + writeb((readb(lbi + FMR2) & 0x3f) | 0x80, lbi + FMR2); + break; + case SLICECOM_FRAMING_NO_CRC4: + writeb(readb(lbi + FMR1) & 0xf7, lbi + FMR1); + writeb(readb(lbi + FMR2) & 0x3f, lbi + FMR2); + break; + default: + printk("slicecom: board %d: unhandled " FILENAME_FRAMING + " value %d\n", boardnum, value); + } + + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * Set PCM linecode - /proc/comx/comx0/linecode + */ + +void slicecom_set_linecode(int boardnum, int value) +{ + u8 *lbi = slicecom_boards[boardnum].lbi; + + spin_lock_irqsave(&mister_lock, flags); + + slicecom_boards[boardnum].linecode = value; + switch (value) + { + case SLICECOM_LINECODE_HDB3: + writeb(readb(lbi + FMR0) | 0xf0, lbi + FMR0); + break; + case SLICECOM_LINECODE_AMI: + writeb((readb(lbi + FMR0) & 0x0f) | 0xa0, lbi + FMR0); + break; + default: + printk("slicecom: board %d: unhandled " FILENAME_LINECODE + " value %d\n", boardnum, value); + } + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * Set PCM clock source - /proc/comx/comx0/clock_source + */ + +void slicecom_set_clock_source(int boardnum, int value) +{ + u8 *lbi = slicecom_boards[boardnum].lbi; + + spin_lock_irqsave(&mister_lock, flags); + + slicecom_boards[boardnum].clock_source = value; + switch (value) + { + case SLICECOM_CLOCK_SOURCE_LINE: + writeb(readb(lbi + LIM0) & ~1, lbi + LIM0); + break; + case SLICECOM_CLOCK_SOURCE_INTERNAL: + writeb(readb(lbi + LIM0) | 1, lbi + LIM0); + break; + default: + printk("slicecom: board %d: unhandled " FILENAME_CLOCK_SOURCE + " value %d\n", boardnum, value); + } + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * Set loopbacks - /proc/comx/comx0/loopback + */ + +void slicecom_set_loopback(int boardnum, int value) +{ + u8 *lbi = slicecom_boards[boardnum].lbi; + + spin_lock_irqsave(&mister_lock, flags); + + slicecom_boards[boardnum].loopback = value; + switch (value) + { + case SLICECOM_LOOPBACK_NONE: + writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */ + writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */ + break; + case SLICECOM_LOOPBACK_LOCAL: + writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */ + writeb(readb(lbi + LIM0) | 2, lbi + LIM0); /* Local Loop ON */ + break; + case SLICECOM_LOOPBACK_REMOTE: + writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */ + writeb(readb(lbi + LIM1) | 2, lbi + LIM1); /* Remote Loop ON */ + break; + default: + printk("slicecom: board %d: unhandled " FILENAME_LOOPBACK + " value %d\n", boardnum, value); + } + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * Update E1 line status LEDs on the adapter + */ + +void slicecom_update_leds(munich_board_t * board) +{ + u32 *bar1 = board->bar1; + u8 *lbi = board->lbi; + u8 frs0; + u32 leds; + int i; + + spin_lock_irqsave(&mister_lock, flags); + + leds = 0; + frs0 = readb(lbi + FRS0); /* FRS0 bits described on page 137 */ + + if (!(frs0 & 0xa0)) + { + leds |= 0x2000; /* Green LED: Input signal seems to be OK, no LOS, no LFA */ + if (frs0 & 0x10) + leds |= 0x8000; /* Red LED: Receiving Remote Alarm */ + } + writel(leds, MUNICH_VIRT(GPDATA)); + + if (leds == 0x2000 && !board->lineup) + { /* line up */ + board->lineup = 1; + for (i = 0; i < 32; i++) + { + if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING)) + { + struct comx_channel *ch = board->twins[i]->priv; + + if (!test_and_set_bit(0, &ch->lineup_pending)) + { + ch->lineup_timer.function = comx_lineup_func; + ch->lineup_timer.data = (unsigned long)board->twins[i]; + ch->lineup_timer.expires = jiffies + HZ * ch->lineup_delay; + add_timer(&ch->lineup_timer); + } + } + } + } + else if (leds != 0x2000 && board->lineup) + { /* line down */ + board->lineup = 0; + for (i = 0; i < 32; i++) + if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING)) + { + struct comx_channel *ch = board->twins[i]->priv; + + if (test_and_clear_bit(0, &ch->lineup_pending)) + del_timer(&ch->lineup_timer); + else if (ch->line_status & LINE_UP) + { + ch->line_status &= ~LINE_UP; + if (ch->LINE_status) + ch->LINE_status(board->twins[i], ch->line_status); + } + } + } + spin_unlock_irqrestore(&mister_lock, flags); +} + +/* + * This function gets called every second when the FALC issues the interrupt. + * Hardware counters contain error counts for last 1-second time interval. + * We add them to the global counters here. + * Read rfc2495 to understand this. + */ + +void slicecom_update_line_counters(munich_board_t * board) +{ + e1_stats_t *curr_int = &board->intervals[board->current_interval]; + + u8 *lbi = board->lbi; + + unsigned framing_errors, code_violations, path_code_violations, crc4_errors, + e_bit_errors; + unsigned slip_detected, /* this one has logical value, not the number of slips! */ + out_of_frame_defect, /* logical value */ + ais_defect, /* logical value */ + errored_sec, bursty_err_sec, severely_err_sec = 0, failure_sec; + u8 isr2, isr3, isr5, frs0; + + spin_lock_irqsave(&mister_lock, flags); + + isr2 = readb(lbi + ISR2); /* ISR0-5 described on page 156 */ + isr3 = readb(lbi + ISR3); + isr5 = readb(lbi + ISR5); + frs0 = readb(lbi + FRS0); /* FRS0 described on page 137 */ + + /* Error Events: */ + + code_violations = readb(lbi + CVCL) + (readb(lbi + CVCH) << 8); + framing_errors = readb(lbi + FECL) + (readb(lbi + FECH) << 8); + crc4_errors = readb(lbi + CEC1L) + (readb(lbi + CEC1H) << 8); + e_bit_errors = readb(lbi + EBCL) + (readb(lbi + EBCH) << 8); + slip_detected = isr3 & (ISR3_RSN | ISR3_RSP); + + path_code_violations = framing_errors + crc4_errors; + + curr_int->line_code_violations += code_violations; + curr_int->path_code_violations += path_code_violations; + curr_int->e_bit_errors += e_bit_errors; + + /* Performance Defects: */ + + /* there was an LFA in the last second, but maybe disappeared: */ + out_of_frame_defect = (isr2 & ISR2_LFA) || (frs0 & FRS0_LFA); + + /* there was an AIS in the last second, but maybe disappeared: */ + ais_defect = (isr2 & ISR2_AIS) || (frs0 & FRS0_AIS); + + /* Performance Parameters: */ + + if (out_of_frame_defect) + curr_int->fr_loss_secs++; + if (code_violations) + curr_int->line_err_secs++; + + errored_sec = ((board->framing == SLICECOM_FRAMING_NO_CRC4) && + (code_violations)) || path_code_violations || + out_of_frame_defect || slip_detected || ais_defect; + + bursty_err_sec = !out_of_frame_defect && !ais_defect && + (path_code_violations > 1) && (path_code_violations < 320); + + switch (board->framing) + { + case SLICECOM_FRAMING_CRC4: + severely_err_sec = out_of_frame_defect || + (path_code_violations >= 832); + break; + case SLICECOM_FRAMING_NO_CRC4: + severely_err_sec = (code_violations >= 2048); + break; + } + + /* + * failure_sec: true if there was a condition leading to a failure + * (and leading to unavailable state) in this second: + */ + + failure_sec = (isr2 & ISR2_RA) || (frs0 & FRS0_RRA) /* Remote/Far End/Distant Alarm Failure */ + || ais_defect || out_of_frame_defect /* AIS or LOF Failure */ + || (isr2 & ISR2_LOS) || (frs0 & FRS0_LOS) /* Loss Of Signal Failure */ + || (board->loopback != SLICECOM_LOOPBACK_NONE); /* Loopback has been set */ + + if (board->is_unavailable) + { + if (severely_err_sec) + board->no_ses_seconds = 0; + else + board->no_ses_seconds++; + + if ((board->no_ses_seconds >= 10) && !failure_sec) + { + board->is_unavailable = 0; + board->ses_seconds = 0; + board->no_ses_seconds = 0; + } + } + else + { + if (severely_err_sec) + board->ses_seconds++; + else + board->ses_seconds = 0; + + if ((board->ses_seconds >= 10) || failure_sec) + { + board->is_unavailable = 1; + board->ses_seconds = 0; + board->no_ses_seconds = 0; + } + } + + if (board->is_unavailable) + curr_int->unavail_secs++; + else + { + if (slip_detected) + curr_int->slip_secs++; + curr_int->errored_secs += errored_sec; + curr_int->bursty_err_secs += bursty_err_sec; + curr_int->severely_err_secs += severely_err_sec; + } + + /* the RFC does not say clearly which errors to count here, we try to count bit errors */ + + if (!board->is_unavailable && !severely_err_sec) + { + board->deg_cumulated_errors += code_violations; + board->deg_elapsed_seconds++; + if (board->deg_elapsed_seconds >= 60) + { + if (board->deg_cumulated_errors >= 123) + curr_int->degraded_mins++; + board->deg_cumulated_errors = 0; + board->deg_elapsed_seconds = 0; + } + + } + + board->elapsed_seconds++; + if (board->elapsed_seconds >= 900) + { + board->current_interval = + (board->current_interval + 1) % SLICECOM_BOARD_INTERVALS_SIZE; + memset((void *)&board->intervals[board->current_interval], 0, + sizeof(e1_stats_t)); + board->elapsed_seconds = 0; + } + + spin_unlock_irqrestore(&mister_lock, flags); +} + +static void pcicom_modemline(unsigned long b) +{ + munich_board_t *board = (munich_board_t *) b; + struct net_device *dev = board->twins[0]; + struct comx_channel *ch = dev->priv; + unsigned long regs; + + regs = readl((void *)(&board->bar1[GPDATA])); + if ((ch->line_status & LINE_UP) && (regs & 0x0800)) + { + ch->line_status &= ~LINE_UP; + board->lineup = 0; + if (ch->LINE_status) + { + ch->LINE_status(dev, ch->line_status); + } + } + + if (!(ch->line_status & LINE_UP) && !(regs & 0x0800)) + { + ch->line_status |= LINE_UP; + board->lineup = 1; + if (ch->LINE_status) + { + ch->LINE_status(dev, ch->line_status); + } + } + + mod_timer((struct timer_list *)&board->modemline_timer, jiffies + HZ); +} + +/* + * Is it possible to transmit ? + * Called (may be called) by the protocol layer + */ + +static int MUNICH_txe(struct net_device *dev) +{ + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + + return (hw->busy < TX_DESC_MAX - 1); +} + +/* + * Hw probe function. Detects all the boards in the system, + * and fills up slicecom_boards[] and pcicom_boards[] + * Returns 0 on success. + * We do not disable interrupts! + */ +static int munich_probe(void) +{ + struct pci_dev *pci; + int boardnum; + int slicecom_boardnum; + int pcicom_boardnum; + u32 *bar1; + u8 *lbi; + munich_board_t *board; + + for (boardnum = 0; boardnum < MAX_BOARDS; boardnum++) + { + pcicom_boards[boardnum].pci = 0; + pcicom_boards[boardnum].bar1 = 0; + pcicom_boards[boardnum].lbi = 0; + slicecom_boards[boardnum].pci = 0; + slicecom_boards[boardnum].bar1 = 0; + slicecom_boards[boardnum].lbi = 0; + } + + pci = NULL; + board = NULL; + slicecom_boardnum = 0; + pcicom_boardnum = 0; + + for (boardnum = 0; + boardnum < MAX_BOARDS && (pci = pci_find_device(PCI_VENDOR_ID_SIEMENS, + PCI_DEVICE_ID_SIEMENS_MUNICH32X, pci)); boardnum++) + { + if (pci_enable_device(pci)) + continue; + + printk("munich_probe: munich chip found, IRQ %d\n", pci->irq); + +#if (LINUX_VERSION_CODE < 0x02030d) + bar1 = ioremap_nocache(pci->base_address[0], 0x100); + lbi = ioremap_nocache(pci->base_address[1], 0x100); +#else + bar1 = ioremap_nocache(pci->resource[0].start, 0x100); + lbi = ioremap_nocache(pci->resource[1].start, 0x100); +#endif + + if (bar1 && lbi) + { + pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0xe0000); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + /* check the type of the card */ + writel(LREG0_MAGIC, MUNICH_VIRT(LREG0)); + writel(LREG1_MAGIC, MUNICH_VIRT(LREG1)); + writel(LREG2_MAGIC, MUNICH_VIRT(LREG2)); + writel(LREG3_MAGIC, MUNICH_VIRT(LREG3)); + writel(LREG4_MAGIC, MUNICH_VIRT(LREG4)); + writel(LREG5_MAGIC, MUNICH_VIRT(LREG5)); + writel(LCONF_MAGIC2,MUNICH_VIRT(LCONF)); /* enable the DMSM */ + + if ((readb(lbi + VSTR) == 0x13) || (readb(lbi + VSTR) == 0x10)) + { + board = slicecom_boards + slicecom_boardnum; + sprintf((char *)board->devname, "slicecom%d", + slicecom_boardnum); + board->isx21 = 0; + slicecom_boardnum++; + } + else if ((readb(lbi + VSTR) == 0x6) || (readb(lbi + GIS) == 0x6)) + { + board = pcicom_boards + pcicom_boardnum; + sprintf((char *)board->devname, "pcicom%d", pcicom_boardnum); + board->isx21 = 1; + pcicom_boardnum++; + } + if (board) + { + printk("munich_probe: %s board found\n", board->devname); + writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */ + board->pci = pci; + board->bar1 = bar1; + board->lbi = lbi; + board->framing = SLICECOM_FRAMING_DEFAULT; + board->linecode = SLICECOM_LINECODE_DEFAULT; + board->clock_source = SLICECOM_CLOCK_SOURCE_DEFAULT; + board->loopback = SLICECOM_LOOPBACK_DEFAULT; + SET_MODULE_OWNER(board); + } + else + { + printk("munich_probe: Board error, VSTR: %02X\n", + readb(lbi + VSTR)); + iounmap((void *)bar1); + iounmap((void *)lbi); + } + } + else + { + printk("munich_probe: ioremap() failed, not enabling this board!\n"); + /* .pci = NULL, so the MUNICH_open will not try to open it */ + if (bar1) iounmap((void *)bar1); + if (lbi) iounmap((void *)lbi); + } + } + + if (!pci && !boardnum) + { + printk("munich_probe: no PCI present!\n"); + return -ENODEV; + } + + if (pcicom_boardnum + slicecom_boardnum == 0) + { + printk + ("munich_probe: Couldn't find any munich board: vendor:device %x:%x not found\n", + PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_MUNICH32X); + return -ENODEV; + } + + /* Found some */ + if (pcicom_boardnum) + printk("%d pcicom board(s) found.\n", pcicom_boardnum); + if (slicecom_boardnum) + printk("%d slicecom board(s) found.\n", slicecom_boardnum); + + return 0; +} + +/* + * Reset the hardware. Get called only from within this module if needed. + */ +#if 0 +static int slicecom_reset(struct net_device *dev) +{ + struct comx_channel *ch = dev->priv; + + printk("slicecom_reset: resetting the hardware\n"); + + /* Begin to reset the hardware */ + + if (ch->HW_set_clock) + ch->HW_set_clock(dev); + + /* And finish it */ + + return 0; +} +#endif + +/* + * Transmit a packet. + * Called by the protocol layer + * Return values: + * FRAME_ACCEPTED: frame is being transmited, transmitter is busy + * FRAME_QUEUED: frame is being transmitted, there's more room in + * the transmitter for additional packet(s) + * FRAME_ERROR: + * FRAME_DROPPED: there was some error + */ + +static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb) +{ + struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + + /* Send it to the debug facility too if needed: */ + + if (ch->debug_flags & DEBUG_HW_TX) + comx_debug_bytes(dev, skb->data, skb->len, "MUNICH_send_packet"); + + /* If the line is inactive, don't accept: */ + + /* TODO: atgondolni hogy mi is legyen itt */ + /* if (!(ch->line_status & LINE_UP)) return FRAME_DROPPED; */ + + /* More check, to be sure: */ + + if (skb->len > TXBUFFER_SIZE) + { + ch->stats.tx_errors++; + kfree_skb(skb); + return FRAME_ERROR; + } + + /* Maybe you have to disable irq's while programming the hw: */ + + spin_lock_irqsave(&mister_lock, flags); + + /* And more check: */ + + if (hw->busy >= TX_DESC_MAX - 1) + { + printk(KERN_ERR + "%s: Transmitter called while busy... dropping frame, busy = %d\n", + dev->name, hw->busy); + spin_unlock_irqrestore(&mister_lock, flags); + kfree_skb(skb); + return FRAME_DROPPED; + } + + if (hw->busy >= 0) + hw->tx_ring_hist[hw->busy]++; + /* DELL: */ + else + printk("slicecom: %s: FATAL: busy = %d\n", dev->name, hw->busy); + +// /* DEL: */ +// printk("slicecom: %s: _send_packet called, busy = %d\n", dev->name, hw->busy ); + + /* Packet can go, update stats: */ + + ch->stats.tx_packets++; + ch->stats.tx_bytes += skb->len; + + /* Pass the packet to the HW: */ + /* Step forward with the transmit descriptors: */ + + hw->tx_desc_ptr = (hw->tx_desc_ptr + 1) % TX_DESC_MAX; + + memcpy(&(hw->tx_data[hw->tx_desc_ptr][0]), skb->data, skb->len); + hw->tx_desc[hw->tx_desc_ptr].no = skb->len; + + /* We don't issue any command, just step with the HOLD bit */ + + hw->tx_desc[hw->tx_desc_ptr].hold = 1; + hw->tx_desc[(hw->tx_desc_ptr + TX_DESC_MAX - 1) % TX_DESC_MAX].hold = 0; + +#ifdef COMX_NEW + dev_kfree_skb(skb); +#endif + /* csomag kerult a Tx ringbe: */ + + hw->busy++; + + /* Report it: */ + + if (ch->debug_flags & DEBUG_HW_TX) + comx_debug(dev, "%s: MUNICH_send_packet was successful\n\n", dev->name); + + if (hw->busy >= TX_DESC_MAX - 1) + { + spin_unlock_irqrestore(&mister_lock, flags); + return FRAME_ACCEPTED; + } + + spin_unlock_irqrestore(&mister_lock, flags); + + /* All done */ + + return FRAME_QUEUED; +} + +/* + * Interrupt handler routine. + * Called by the Linux kernel. + * BEWARE! The interrupts are enabled on the call! + */ +static void MUNICH_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sk_buff *skb; + int length; + int rx_status; + int work; /* hany esemenyt kezeltem mar le */ + u32 *bar1; + u8 *lbi; + u32 stat, /* az esemenyek, amiket a ebben a loop korben le kell meg kezelni */ + race_stat = 0, /* race eseten ebben uzenek magamnak hogy mit kell meg lekezelni */ + ack; /* ezt fogom a vegen a STAT-ba irni, kiveszek belole 1-1 bitet ha */ + + /* az adott dolgot nem kell ack-olni mert volt vele munkam, es */ + /* legjobb ha visszaterek ide megegyszer */ + munich_intq_t int_info; + + struct net_device *dev; + struct comx_channel *ch; + struct slicecom_privdata *hw; + munich_board_t *board = (munich_board_t *) dev_id; + int channel; + + // , boardnum = (int)dev_id; + + // board = munich_boards + boardnum; + bar1 = board->bar1; + lbi = board->lbi; + + // Do not uncomment this under heavy load! :-> + // printk("MUNICH_interrupt: masked STAT=0x%08x, tiq=0x%08x, riq=0x%08x, piq=0x%08x\n", stat, board->tiq[0].all, board->riq[0].all, board->piq[0].all ); + + for (work = 0; (stat = (race_stat | (readl(MUNICH_VIRT(STAT)) & ~STAT_NOT_HANDLED_BY_INTERRUPT))) && (work < MAX_WORK - 1); work++) + { + ack = stat & (STAT_PRI | STAT_PTI | STAT_LBII); + + /* Handle the interrupt information in the Rx queue. We don't really trust */ + /* info from this queue, because it can be overflowed, so later check */ + /* every Rx ring for received packets. But there are some errors which can't */ + /* be counted from the Rx rings, so we parse it. */ + + int_info = board->riq[board->riq_ptr]; + if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ + { + ack &= ~STAT_PRI; /* don't ack the interrupt, we had some work to do */ + + channel = PCM_INT_CHANNEL(int_info.all); + dev = board->twins[channel]; + + if (dev == NULL) + { + printk + ("MUNICH_interrupt: got an Rx interrupt info for NULL device " + "%s.twins[%d], int_info = 0x%08x\n", board->devname, + channel, int_info.all); + goto go_for_next_interrupt; + } + + ch = (struct comx_channel *)dev->priv; + hw = (struct slicecom_privdata *)ch->HW_privdata; + + // printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n", + // stat, int_info.all, hw->rx_desc_ptr, hw->rx_desc[ hw->rx_desc_ptr ].status ); + + if (int_info.all & PCM_INT_HI) + printk("SliceCOM: %s: Host Initiated interrupt\n", dev->name); + if (int_info.all & PCM_INT_IFC) + printk("SliceCOM: %s: Idle/Flag Change\n", dev->name); + /* TOD: jo ez az Idle/Flag Change valamire? - azonnal latszik belole hogy mikor ad a masik oldal */ + /* TOD: ilyen IT most nem is jon, mert ki van maszkolva az interrupt, biztosan kell ez? */ + + if (int_info.all & PCM_INT_FO) + /* Internal buffer (RB) overrun */ + ch->stats.rx_over_errors++; /* TOD: Ez azt jelenti hogy a belso RB nem volt hozzaferheto, es ezert kihagyott valamit. De nem csak csomag lehetett, hanem esemeny, stb. is. lasd page 247. Ezzel a 'cat status'-hoz igazodok, de a netdevice.h szerint nem egyertelmu hogy ide ez kellene. Nem lehet hogy rx_missed ? */ + /* DE: nem gotozok sehova, elvileg jo igy */ + /* kesobb meg visszaterek az FO-ra, ha packet-FO volt. Keresd a "packet-FO"-t. */ + if (int_info.all & PCM_INT_FI) /* frame received, but we do not trust the int_info queue */ + if (int_info.all & PCM_INT_SF) + { /* Short Frame: rovidebb mint a CRC */ + /* "rovidebb mint CRC+2byte" vizsgalat a "CRC+2"-nel */ + ch->stats.rx_length_errors++; /* TOD: noveljem? ne noveljem? */ + goto go_for_next_interrupt; + } + + go_for_next_interrupt: /* One step in the interrupt queue */ + board->riq[board->riq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */ + board->riq_ptr = (board->riq_ptr + 1) % MUNICH_INTQMAX; + + } + + /* Check every Rx ring for incomed packets: */ + + for (channel = 0; channel < 32; channel++) + { + dev = board->twins[channel]; + + if (dev != NULL) + { + ch = (struct comx_channel *)dev->priv; + hw = (struct slicecom_privdata *)ch->HW_privdata; + + rx_status = hw->rx_desc[hw->rx_desc_ptr].status; + + if (!(rx_status & 0x80)) /* mar jart itt a hardver */ + { + ack &= ~STAT_PRI; /* Don't ack, we had some work */ + + /* Ez most egy kicsit zuros, mert itt mar nem latom az int_infot */ + if (rx_status & RX_STATUS_ROF) + ch->stats.rx_over_errors++; /* TOD: 'cat status'-hoz igazodok */ + + if (rx_status & RX_STATUS_RA) + /* Abort received or issued on channel */ + ch->stats.rx_frame_errors++; /* or HOLD bit in the descriptor */ + /* TOD: 'cat status'-hoz igazodok */ + + if (rx_status & RX_STATUS_LFD) + { /* Long Frame (longer then MFL in the MODE1) */ + ch->stats.rx_length_errors++; + goto go_for_next_frame; + } + + if (rx_status & RX_STATUS_NOB) + { /* Not n*8 bits long frame - frame alignment */ + ch->stats.rx_frame_errors++; /* ez viszont nem igazodik a 'cat status'-hoz */ + goto go_for_next_frame; + } + + if (rx_status & RX_STATUS_CRCO) + { /* CRC error */ + ch->stats.rx_crc_errors++; + goto go_for_next_frame; + } + + if (rx_status & RX_STATUS_SF) + { /* Short Frame: rovidebb mint CRC+2byte */ + ch->stats.rx_errors++; /* The HW does not set PCI_INT_ERR bit for this one, see page 246 */ + ch->stats.rx_length_errors++; + goto go_for_next_frame; + } + + if (rx_status != 0) + { + printk("SliceCOM: %s: unhandled rx_status: 0x%02x\n", + dev->name, rx_status); + goto go_for_next_frame; + } + + /* frame received without errors: */ + + length = hw->rx_desc[hw->rx_desc_ptr].bno; + ch->stats.rx_packets++; /* Count only 'good' packets */ + ch->stats.rx_bytes += length; + + /* Allocate a larger skb and reserve the heading for efficiency: */ + + if ((skb = dev_alloc_skb(length + 16)) == NULL) + { + ch->stats.rx_dropped++; + goto go_for_next_frame; + } + + /* Do bookkeeping: */ + + skb_reserve(skb, 16); + skb_put(skb, length); + skb->dev = dev; + + /* Now copy the data into the buffer: */ + + memcpy(skb->data, &(hw->rx_data[hw->rx_desc_ptr][0]), length); + + /* DEL: UGLY HACK!!!! */ + if (*((int *)skb->data) == 0x02000000 && + *(((int *)skb->data) + 1) == 0x3580008f) + { + printk("%s: swapping hack\n", dev->name); + *((int *)skb->data) = 0x3580008f; + *(((int *)skb->data) + 1) = 0x02000000; + } + + if (ch->debug_flags & DEBUG_HW_RX) + comx_debug_skb(dev, skb, "MUNICH_interrupt receiving"); + + /* Pass it to the protocol entity: */ + + ch->LINE_rx(dev, skb); + + go_for_next_frame: + /* DEL: rafutott-e a HOLD bitre -detektalas */ + { + if( ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->hold + && ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->status != 0xff) + hw->rafutott++; /* rafutott: hanyszor volt olyan hogy a current descriptoron HOLD bit volt, es a hw mar befejezte az irast (azaz a hw rafutott a HOLD bitre) */ + } + + // if( jiffies % 2 ) /* DELL: okozzunk egy kis Rx ring slipet :) */ + // { + /* Step forward with the receive descriptors: */ + /* if you change this, change the copy of it below too! Search for: "RxSlip" */ + hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 1) % RX_DESC_MAX].hold = 1; + hw->rx_desc[hw->rx_desc_ptr].status = 0xFF; /* megjelolom hogy itt meg nem jart a hw */ + hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 0; + hw->rx_desc_ptr = (hw->rx_desc_ptr + 1) % RX_DESC_MAX; + // } + } + } + } + + stat &= ~STAT_PRI; + +// } + +// if( stat & STAT_PTI ) /* TOD: primko megvalositas: mindig csak egy esemenyt dolgozok fel, */ + /* es nem torlom a STAT-ot, ezert ujra visszajon ide a rendszer. Amikor */ + /* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot. */ + /* 'needs a rewrite', de elso megoldasnak jo lesz */ +// { + +udelay(10000); + int_info = board->tiq[board->tiq_ptr]; + if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ + { + ack &= ~STAT_PTI; /* don't ack the interrupt, we had some work to do */ + + channel = PCM_INT_CHANNEL(int_info.all); + dev = board->twins[channel]; + + if (dev == NULL) + { + printk("MUNICH_interrupt: got a Tx interrupt for NULL device " + "%s.twins[%d], int_info = 0x%08x\n", + board->isx21 ? "pcicom" : "slicecom", channel, int_info.all); + goto go_for_next_tx_interrupt; + } + + ch = (struct comx_channel *)dev->priv; + hw = (struct slicecom_privdata *)ch->HW_privdata; + + // printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr ); + + if (int_info.all & PCM_INT_FE2) + { /* "Tx available" */ + /* do nothing */ + } + else if (int_info.all & PCM_INT_FO) + { /* Internal buffer (RB) overrun */ + ch->stats.rx_over_errors++; + } + else + { + printk("slicecom: %s: unhandled Tx int_info: 0x%08x\n", + dev->name, int_info.all); + } + + go_for_next_tx_interrupt: + board->tiq[board->tiq_ptr].all = 0; + board->tiq_ptr = (board->tiq_ptr + 1) % MUNICH_INTQMAX; + } + + /* Check every Tx ring for incoming packets: */ + + for (channel = 0; channel < 32; channel++) + { + dev = board->twins[channel]; + + if (dev != NULL) + { + int newbusy; + + ch = (struct comx_channel *)dev->priv; + hw = (struct slicecom_privdata *)ch->HW_privdata; + + /* We dont trust the "Tx available" info from the TIQ, but check */ + /* every ring if there is some free room */ + + if (ch->init_status && netif_running(dev)) + { + newbusy = ( TX_DESC_MAX + (& hw->tx_desc[ hw->tx_desc_ptr ]) - + (tx_desc_t*)phys_to_virt(board->ccb->current_tx_desc[ hw->channel ]) ) % TX_DESC_MAX; + + if(newbusy < 0) + { + printk("slicecom: %s: FATAL: fresly computed busy = %d, HW: 0x%p, SW: 0x%p\n", + dev->name, newbusy, + phys_to_virt(board->ccb->current_tx_desc[hw->channel]), + & hw->tx_desc[hw->tx_desc_ptr]); + } + + /* Fogyott valami a Tx ringbol? */ + + if (newbusy < hw->busy) + { + // ack &= ~STAT_PTI; /* Don't ack, we had some work */ + hw->busy = newbusy; + if (ch->LINE_tx) + ch->LINE_tx(dev); /* Report it to protocol driver */ + } + else if (newbusy > hw->busy) + printk("slicecom: %s: newbusy > hw->busy, this should not happen!\n", dev->name); + } + } + } + stat &= ~STAT_PTI; + + int_info = board->piq[board->piq_ptr]; + if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ + { + ack &= ~STAT_LBII; /* don't ack the interrupt, we had some work to do */ + + /* We do not really use (yet) the interrupt info from this queue, */ + + // printk("slicecom: %s: LBI Interrupt event: %08x\n", board->devname, int_info.all); + + if (!board->isx21) + { + slicecom_update_leds(board); + slicecom_update_line_counters(board); + } + + goto go_for_next_lbi_interrupt; /* To avoid warning about unused label */ + + go_for_next_lbi_interrupt: /* One step in the interrupt queue */ + board->piq[board->piq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */ + board->piq_ptr = (board->piq_ptr + 1) % MUNICH_PIQMAX; + } + stat &= ~STAT_LBII; + + writel(ack, MUNICH_VIRT(STAT)); + + if (stat & STAT_TSPA) + { + // printk("slicecom: %s: PCM TSP Asynchronous\n", board->devname); + writel(STAT_TSPA, MUNICH_VIRT(STAT)); + stat &= ~STAT_TSPA; + } + + if (stat & STAT_RSPA) + { + // printk("slicecom: %s: PCM RSP Asynchronous\n", board->devname); + writel(STAT_RSPA, MUNICH_VIRT(STAT)); + stat &= ~STAT_RSPA; + } + if (stat) + { + printk("MUNICH_interrupt: unhandled interrupt, STAT=0x%08x\n", + stat); + writel(stat, MUNICH_VIRT(STAT)); /* ha valamit megsem kezeltunk le, azert ack-ot kuldunk neki */ + } + + } + board->histogram[work]++; + + /* We can miss these if we reach the MAX_WORK */ + /* Count it to see how often it happens */ + + if (race_stat & STAT_PRI) + board->stat_pri_races_missed++; + if (race_stat & STAT_PTI) + board->stat_pti_races_missed++; + return; +} + +/* + * Hardware open routine. + * Called by comx (upper) layer when the user wants to bring up the interface + * with ifconfig. + * Initializes hardware, allocates resources etc. + * Returns 0 on OK, or standard error value on error. + */ + +static int MUNICH_open(struct net_device *dev) +{ + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + struct proc_dir_entry *procfile = ch->procdir->subdir; + munich_board_t *board; + munich_ccb_t *ccb; + + u32 *bar1; + u8 *lbi; + u32 stat; + unsigned long flags, jiffs; + + int i, channel; + u32 timeslots = hw->timeslots; + + board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + bar1 = board->bar1; + lbi = board->lbi; + + /* TODO: a timeslotok ellenorzese kell majd ide .. hat, biztos? mar a write_proc-ban is + ellenorzom valamennyire. + if (!dev->io || !dev->irq) return -ENODEV; + */ + + if (!board->pci) + { + printk("MUNICH_open: no %s board with boardnum = %d\n", + ch->hardware->name, hw->boardnum); + return -ENODEV; + } + + spin_lock_irqsave(&mister_lock, flags); + /* lock the section to avoid race with multiple opens and make sure + that no interrupts get called while this lock is active */ + + if (board->use_count == 0) /* bring up the board if it was unused */ + /* if fails, frees allocated resources and returns. */ + /* TOD: is it safe? nem kellene resetelni a kartyat? */ + { + printk("MUNICH_open: %s: bringing up board\n", board->devname); + + /* Clean up the board's static struct if messed: */ + + for (i = 0; i < 32; i++) + board->twins[i] = NULL; + for (i = 0; i < MAX_WORK; i++) + board->histogram[i] = 0; + + board->lineup = 0; + + /* Allocate CCB: */ + board->ccb = kmalloc(sizeof(munich_ccb_t), GFP_KERNEL); + if (board->ccb == NULL) + { + spin_unlock_irqrestore(&mister_lock, flags); + return -ENOMEM; + } + memset((void *)board->ccb, 0, sizeof(munich_ccb_t)); + board->ccb->csa = virt_to_phys(board->ccb); + ccb = board->ccb; + for (i = 0; i < 32; i++) + { + ccb->timeslot_spec[i].tti = 1; + ccb->timeslot_spec[i].rti = 1; + } + + /* Interrupt queues: */ + + board->tiq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL); + if (board->tiq == NULL) + { + spin_unlock_irqrestore(&mister_lock, flags); + return -ENOMEM; + } + memset((void *)board->tiq, 0, MUNICH_INTQSIZE); + + board->riq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL); + if (board->riq == NULL) + { + spin_unlock_irqrestore(&mister_lock, flags); + return -ENOMEM; + } + memset((void *)board->riq, 0, MUNICH_INTQSIZE); + + board->piq = kmalloc(MUNICH_PIQSIZE, GFP_KERNEL); + if (board->piq == NULL) + { + spin_unlock_irqrestore(&mister_lock, flags); + return -ENOMEM; + } + memset((void *)board->piq, 0, MUNICH_PIQSIZE); + + board->tiq_ptr = 0; + board->riq_ptr = 0; + board->piq_ptr = 0; + + /* Request irq: */ + + board->irq = 0; + + /* (char*) cast to avoid warning about discarding volatile: */ + if (request_irq(board->pci->irq, MUNICH_interrupt, 0, + (char *)board->devname, (void *)board)) + { + printk("MUNICH_open: %s: unable to obtain irq %d\n", board->devname, + board->pci->irq); + /* TOD: free other resources (a sok malloc feljebb) */ + spin_unlock_irqrestore(&mister_lock, flags); + return -EAGAIN; + } + board->irq = board->pci->irq; /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */ + + /* Programming device: */ + + /* Reset the board like a power-on: */ + /* TOD: + - It is not a real power-on: if a DMA transaction fails with master abort, the board + stays in half-dead state. + - It doesn't reset the FALC line driver */ + + pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + writel(virt_to_phys(&ccb->csa), MUNICH_VIRT(CCBA)); + writel(virt_to_phys( board->tiq ), MUNICH_VIRT(TIQBA)); + writel(MUNICH_INTQLEN, MUNICH_VIRT(TIQL)); + writel(virt_to_phys( board->riq ), MUNICH_VIRT(RIQBA)); + writel(MUNICH_INTQLEN, MUNICH_VIRT(RIQL)); + writel(virt_to_phys( board->piq ), MUNICH_VIRT(PIQBA)); + writel(MUNICH_PIQLEN, MUNICH_VIRT(PIQL)); + + /* Put the magic values into the registers: */ + + writel(MODE1_MAGIC, MUNICH_VIRT(MODE1)); + writel(MODE2_MAGIC, MUNICH_VIRT(MODE2)); + + writel(LREG0_MAGIC, MUNICH_VIRT(LREG0)); + writel(LREG1_MAGIC, MUNICH_VIRT(LREG1)); + writel(LREG2_MAGIC, MUNICH_VIRT(LREG2)); + writel(LREG3_MAGIC, MUNICH_VIRT(LREG3)); + writel(LREG4_MAGIC, MUNICH_VIRT(LREG4)); + writel(LREG5_MAGIC, MUNICH_VIRT(LREG5)); + + writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */ + writel(LCONF_MAGIC2, MUNICH_VIRT(LCONF)); /* enable the DMSM */ + + writel(~0, MUNICH_VIRT(TXPOLL)); + writel(board->isx21 ? 0x1400 : 0xa000, MUNICH_VIRT(GPDIR)); + + if (readl(MUNICH_VIRT(STAT))) writel(readl(MUNICH_VIRT(STAT)), MUNICH_VIRT(STAT)); + + ccb->action_spec = CCB_ACTIONSPEC_RES | CCB_ACTIONSPEC_IA; + writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the PCM core reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + stat = 0; /* Wait for the action to complete max. 1 second */ + jiffs = jiffies; + while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (stat & STAT_PCMF) + { + printk(KERN_ERR + "MUNICH_open: %s: Initial ARPCM failed. STAT=0x%08x\n", + board->devname, stat); + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); + free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut down hw? */ + board->irq = 0; + spin_unlock_irqrestore(&mister_lock, flags); + return -EAGAIN; + } + else if (!(stat & STAT_PCMA)) + { + printk(KERN_ERR + "MUNICH_open: %s: Initial ARPCM timeout. STAT=0x%08x\n", + board->devname, stat); + free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut off the hw? */ + board->irq = 0; + spin_unlock_irqrestore(&mister_lock, flags); + return -EIO; + } + + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); /* Acknowledge */ + + if (board->isx21) writel(0, MUNICH_VIRT(GPDATA)); + + printk("MUNICH_open: %s: succesful HW-open took %ld jiffies\n", + board->devname, jiffies - jiffs); + + /* Set up the FALC hanging on the Local Bus: */ + + if (!board->isx21) + { + writeb(0x0e, lbi + FMR1); + writeb(0, lbi + LIM0); + writeb(0xb0, lbi + LIM1); /* TODO: input threshold */ + writeb(0xf7, lbi + XPM0); + writeb(0x02, lbi + XPM1); + writeb(0x00, lbi + XPM2); + writeb(0xf0, lbi + FMR0); + writeb(0x80, lbi + PCD); + writeb(0x80, lbi + PCR); + writeb(0x00, lbi + LIM2); + writeb(0x07, lbi + XC0); + writeb(0x3d, lbi + XC1); + writeb(0x05, lbi + RC0); + writeb(0x00, lbi + RC1); + writeb(0x83, lbi + FMR2); + writeb(0x9f, lbi + XSW); + writeb(0x0f, lbi + XSP); + writeb(0x00, lbi + TSWM); + writeb(0xe0, lbi + MODE); + writeb(0xff, lbi + IDLE); /* Idle Code to send in unused timeslots */ + writeb(0x83, lbi + IPC); /* interrupt query line mode: Push/pull output, active high */ + writeb(0xbf, lbi + IMR3); /* send an interrupt every second */ + + slicecom_set_framing(hw->boardnum, board->framing); + slicecom_set_linecode(hw->boardnum, board->linecode); + slicecom_set_clock_source(hw->boardnum, board->clock_source); + slicecom_set_loopback(hw->boardnum, board->loopback); + + memset((void *)board->intervals, 0, sizeof(board->intervals)); + board->current_interval = 0; + board->elapsed_seconds = 0; + board->ses_seconds = 0; + board->is_unavailable = 0; + board->no_ses_seconds = 0; + board->deg_elapsed_seconds = 0; + board->deg_cumulated_errors = 0; + } + + /* Enable the interrupts last */ + /* These interrupts will be enabled. We do not need the others. */ + + writel(readl(MUNICH_VIRT(IMASK)) & ~(STAT_PTI | STAT_PRI | STAT_LBII | STAT_TSPA | STAT_RSPA), MUNICH_VIRT(IMASK)); + } + + spin_unlock_irqrestore(&mister_lock, flags); + + dev->irq = board->irq; /* hogy szep legyen az ifconfig outputja */ + ccb = board->ccb; /* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */ + + spin_lock_irqsave(&mister_lock, flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + /* Check if the selected timeslots aren't used already */ + + for (i = 0; i < 32; i++) + if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti) + { + printk("MUNICH_open: %s: timeslot %d already used by %s\n", + dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name); + spin_unlock_irqrestore(&mister_lock, flags); + return -EBUSY; /* TODO: lehet hogy valami mas errno kellene? */ + } + + /* find a free channel: */ + /* TODO: ugly, rewrite it */ + + for (channel = 0; channel <= 32; channel++) + { + if (channel == 32) + { /* not found a free one */ + printk + ("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n", + dev->name); + spin_unlock_irqrestore(&mister_lock, flags); + return -ENODEV; + } + if (board->twins[channel] == NULL) + break; /* found the first free one */ + } + + board->lastcheck = jiffies; /* avoid checking uninitialized hardware channel */ + + /* Open the channel. If fails, calls MUNICH_close() to properly free resources and stop the HW */ + + hw->channel = channel; + board->twins[channel] = dev; + + board->use_count++; /* meg nem nyitottuk meg a csatornat, de a twins-ben + mar elfoglaltunk egyet, es ha a _close-t akarjuk hivni, akkor ez kell. */ + for (i = 0; i < 32; i++) + if ((1 << i) & timeslots) + { + ccb->timeslot_spec[i].tti = 0; + ccb->timeslot_spec[i].txchannel = channel; + ccb->timeslot_spec[i].txfillmask = ~0; + + ccb->timeslot_spec[i].rti = 0; + ccb->timeslot_spec[i].rxchannel = channel; + ccb->timeslot_spec[i].rxfillmask = ~0; + } + + if (!board->isx21) rework_idle_channels(dev); + + memset((void *)&(hw->tx_desc), 0, TX_DESC_MAX * sizeof(tx_desc_t)); + memset((void *)&(hw->rx_desc), 0, RX_DESC_MAX * sizeof(rx_desc_t)); + + for (i = 0; i < TX_DESC_MAX; i++) + { + hw->tx_desc[i].fe = 1; + hw->tx_desc[i].fnum = 2; + hw->tx_desc[i].data = virt_to_phys( & (hw->tx_data[i][0]) ); + hw->tx_desc[i].next = virt_to_phys( & (hw->tx_desc[ (i+1) % TX_DESC_MAX ]) ); + + } + hw->tx_desc_ptr = 0; /* we will send an initial packet so it is correct: "oda irtunk utoljara" */ + hw->busy = 0; + hw->tx_desc[hw->tx_desc_ptr].hold = 1; + hw->tx_desc[hw->tx_desc_ptr].no = 1; /* TOD: inkabb csak 0 hosszut kuldjunk ki az initkor? */ + + for (i = 0; i < RX_DESC_MAX; i++) + { + hw->rx_desc[i].no = RXBUFFER_SIZE; + hw->rx_desc[i].data = virt_to_phys(&(hw->rx_data[i][0])); + hw->rx_desc[i].next = virt_to_phys(&(hw->rx_desc[(i+1) % RX_DESC_MAX])); + hw->rx_desc[i].status = 0xFF; + } + hw->rx_desc_ptr = 0; + + hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 1; + + memset((void *)&ccb->channel_spec[channel], 0, sizeof(channel_spec_t)); + + ccb->channel_spec[channel].ti = 0; /* Transmit off */ + ccb->channel_spec[channel].to = 1; + ccb->channel_spec[channel].ta = 0; + + ccb->channel_spec[channel].th = 1; /* Transmit hold */ + + ccb->channel_spec[channel].ri = 0; /* Receive off */ + ccb->channel_spec[channel].ro = 1; + ccb->channel_spec[channel].ra = 0; + + ccb->channel_spec[channel].mode = 3; /* HDLC */ + + ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8); + writel(CMD_ARPCM, MUNICH_VIRT(CMD)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + spin_unlock_irqrestore(&mister_lock, flags); + + stat = 0; + jiffs = jiffies; + while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (stat & STAT_PCMF) + { + printk(KERN_ERR "MUNICH_open: %s: %s channel %d off failed\n", + dev->name, board->devname, channel); + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); + MUNICH_close(dev); + return -EAGAIN; + } + else if (!(stat & STAT_PCMA)) + { + printk(KERN_ERR "MUNICH_open: %s: %s channel %d off timeout\n", + dev->name, board->devname, channel); + MUNICH_close(dev); + return -EIO; + } + + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); + // printk("MUNICH_open: %s: succesful channel off took %ld jiffies\n", board->devname, jiffies-jiffs); + + spin_lock_irqsave(&mister_lock, flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + ccb->channel_spec[channel].ifc = 1; /* 1 .. 'Idle/Flag change' interrupt letiltva */ + ccb->channel_spec[channel].fit = 1; + ccb->channel_spec[channel].nitbs = 1; + ccb->channel_spec[channel].itbs = 2; + + /* TODOO: lehet hogy jo lenne igy, de utana kellene nezni hogy nem okoz-e fragmentaciot */ + // ccb->channel_spec[channel].itbs = 2 * number_of_timeslots; + // printk("open: %s: number_of_timeslots: %d\n", dev->name, number_of_timeslots); + + ccb->channel_spec[channel].mode = 3; /* HDLC */ + ccb->channel_spec[channel].ftda = virt_to_phys(&(hw->tx_desc)); + ccb->channel_spec[channel].frda = virt_to_phys(&(hw->rx_desc[0])); + + ccb->channel_spec[channel].ti = 1; /* Transmit init */ + ccb->channel_spec[channel].to = 0; + ccb->channel_spec[channel].ta = 1; + + ccb->channel_spec[channel].th = 0; + + ccb->channel_spec[channel].ri = 1; /* Receive init */ + ccb->channel_spec[channel].ro = 0; + ccb->channel_spec[channel].ra = 1; + + ccb->action_spec = CCB_ACTIONSPEC_ICO | (channel << 8); + writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the channel init */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + spin_unlock_irqrestore(&mister_lock, flags); + + stat = 0; /* Wait for the action to complete max. 1 second */ + jiffs = jiffies; + while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (stat & STAT_PCMF) + { + printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM failed\n", + board->devname); + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); + MUNICH_close(dev); + return -EAGAIN; + } + else if (!(stat & STAT_PCMA)) + { + printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM timeout\n", + board->devname); + MUNICH_close(dev); + return -EIO; + } + + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); + // printk("MUNICH_open: %s: succesful channel open took %ld jiffies\n", board->devname, jiffies-jiffs); + + spin_lock_irqsave(&mister_lock, flags); + + ccb->channel_spec[channel].nitbs = 0; /* once ITBS defined, these must be 0 */ + ccb->channel_spec[channel].itbs = 0; + + if (board->isx21) + { + board->modemline_timer.data = (unsigned int)board; + board->modemline_timer.function = pcicom_modemline; + board->modemline_timer.expires = jiffies + HZ; + add_timer((struct timer_list *)&board->modemline_timer); + } + + /* It is done. Declare that we're open: */ + hw->busy = 0; /* It may be 1 if the frame at Tx init already ended, but it is not */ + /* a real problem: we compute hw->busy on every interrupt */ + hw->rafutott = 0; + ch->init_status |= HW_OPEN; + + /* Initialize line state: */ + if (board->lineup) + ch->line_status |= LINE_UP; + else + ch->line_status &= ~LINE_UP; + + /* Remove w attribute from /proc files associated to hw parameters: + no write when the device is open */ + + for (; procfile; procfile = procfile->next) + if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 || + strcmp(procfile->name, FILENAME_TIMESLOTS) == 0) + procfile->mode = S_IFREG | 0444; + + spin_unlock_irqrestore(&mister_lock, flags); + + return 0; +} + +/* + * Hardware close routine. + * Called by comx (upper) layer when the user wants to bring down the interface + * with ifconfig. + * We also call it from MUNICH_open, if the open fails. + * Brings down hardware, frees resources, stops receiver + * Returns 0 on OK, or standard error value on error. + */ + +static int MUNICH_close(struct net_device *dev) +{ + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + struct proc_dir_entry *procfile = ch->procdir->subdir; + munich_board_t *board; + munich_ccb_t *ccb; + + u32 *bar1; + u32 timeslots = hw->timeslots; + int stat, i, channel = hw->channel; + unsigned long jiffs; + + board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + ccb = board->ccb; + bar1 = board->bar1; + + if (board->isx21) + del_timer((struct timer_list *)&board->modemline_timer); + + spin_lock_irqsave(&mister_lock, flags); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + /* Disable receiver for the channel: */ + + for (i = 0; i < 32; i++) + if ((1 << i) & timeslots) + { + ccb->timeslot_spec[i].tti = 1; + ccb->timeslot_spec[i].txfillmask = 0; /* just to be double-sure :) */ + + ccb->timeslot_spec[i].rti = 1; + ccb->timeslot_spec[i].rxfillmask = 0; + } + + if (!board->isx21) rework_idle_channels(dev); + + ccb->channel_spec[channel].ti = 0; /* Receive off, Transmit off */ + ccb->channel_spec[channel].to = 1; + ccb->channel_spec[channel].ta = 0; + ccb->channel_spec[channel].th = 1; + + ccb->channel_spec[channel].ri = 0; + ccb->channel_spec[channel].ro = 1; + ccb->channel_spec[channel].ra = 0; + + board->twins[channel] = NULL; + + ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8); + writel(CMD_ARPCM, MUNICH_VIRT(CMD)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + + spin_unlock_irqrestore(&mister_lock, flags); + + stat = 0; + jiffs = jiffies; + while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (stat & STAT_PCMF) + { + printk(KERN_ERR + "MUNICH_close: %s: FATAL: channel off ARPCM failed, not closing!\n", + dev->name); + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); + /* If we return success, the privdata (and the descriptor list) will be freed */ + return -EIO; + } + else if (!(stat & STAT_PCMA)) + printk(KERN_ERR "MUNICH_close: %s: channel off ARPCM timeout\n", + board->devname); + + writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); + // printk("MUNICH_close: %s: channel off took %ld jiffies\n", board->devname, jiffies-jiffs); + + spin_lock_irqsave(&mister_lock, flags); + + if (board->use_count) board->use_count--; + + if (!board->use_count) /* we were the last user of the board */ + { + printk("MUNICH_close: bringing down board %s\n", board->devname); + + /* program down the board: */ + + writel(0x0000FF7F, MUNICH_VIRT(IMASK)); /* do not send any interrupts */ + writel(0, MUNICH_VIRT(CMD)); /* stop the timer if someone started it */ + writel(~0U, MUNICH_VIRT(STAT)); /* if an interrupt came between the cli()-sti(), quiet it */ + if (ch->hardware == &pcicomhw) + writel(0x1400, MUNICH_VIRT(GPDATA)); + + /* Put the board into 'reset' state: */ + pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000); + + /* Free irq and other resources: */ + if (board->irq) + free_irq(board->irq, (void *)board); /* Ha nem inicializalta magat, akkor meg nincs irq */ + board->irq = 0; + + /* Free CCB and the interrupt queues */ + if (board->ccb) kfree((void *)board->ccb); + if (board->tiq) kfree((void *)board->tiq); + if (board->riq) kfree((void *)board->riq); + if (board->piq) kfree((void *)board->piq); + board->ccb = board->tiq = board->riq = board->piq = NULL; + } + + /* Enable setting of hw parameters */ + for (; procfile; procfile = procfile->next) + if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 || + strcmp(procfile->name, FILENAME_TIMESLOTS) == 0) + procfile->mode = S_IFREG | 0644; + + /* We're not open anymore */ + ch->init_status &= ~HW_OPEN; + + spin_unlock_irqrestore(&mister_lock, flags); + + return 0; +} + +/* + * Give (textual) status information. + * The text it returns will be a part of what appears when the user does a + * cat /proc/comx/comx[n]/status + * Don't write more than PAGESIZE. + * Return value: number of bytes written (length of the string, incl. 0) + */ + +static int MUNICH_minden(struct net_device *dev, char *page) +{ + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + munich_board_t *board; + struct net_device *devp; + + u8 *lbi; + e1_stats_t *curr_int, *prev_int; + e1_stats_t last4, last96; /* sum of last 4, resp. last 96 intervals */ + unsigned *sump, /* running pointer for the sum data */ + *p; /* running pointer for the interval data */ + + int len = 0; + u8 frs0, frs1; + u8 fmr2; + int i, j; + u32 timeslots; + + board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + lbi = board->lbi; + curr_int = &board->intervals[board->current_interval]; + prev_int = + &board-> + intervals[(board->current_interval + SLICECOM_BOARD_INTERVALS_SIZE - + 1) % SLICECOM_BOARD_INTERVALS_SIZE]; + + if (!board->isx21) + { + frs0 = readb(lbi + FRS0); + fmr2 = readb(lbi + FMR2); + len += snprintf(page + len, PAGE_SIZE - len, "Controller status:\n"); + if (frs0 == 0) + len += snprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n"); + else + { + if (frs0 & FRS0_LOS) + len += snprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n"); + else + { + if (frs0 & FRS0_AIS) + len += snprintf(page + len, PAGE_SIZE - len, + "\tAlarm Indication Signal\n"); + else + { + if (frs0 & FRS0_AUXP) + len += snprintf(page + len, PAGE_SIZE - len, + "\tAuxiliary Pattern Indication\n"); + if (frs0 & FRS0_LFA) + len += snprintf(page + len, PAGE_SIZE - len, + "\tLoss of Frame Alignment\n"); + else + { + if (frs0 & FRS0_RRA) + len += snprintf(page + len, PAGE_SIZE - len, + "\tReceive Remote Alarm\n"); + + /* You can't set this framing with the /proc interface, but it */ + /* may be good to have here this alarm if you set it by hand: */ + + if ((board->framing == SLICECOM_FRAMING_CRC4) && + (frs0 & FRS0_LMFA)) + len += snprintf(page + len, PAGE_SIZE - len, + "\tLoss of CRC4 Multiframe Alignment\n"); + + if (((fmr2 & 0xc0) == 0xc0) && (frs0 & FRS0_NMF)) + len += snprintf(page + len, PAGE_SIZE - len, + "\tNo CRC4 Multiframe alignment Found after 400 msec\n"); + } + } + } + } + + frs1 = readb(lbi + FRS1); + if (FRS1_XLS & frs1) + len += snprintf(page + len, PAGE_SIZE - len, + "\tTransmit Line Short\n"); + + /* debug Rx ring: DEL: - vagy meghagyni, de akkor legyen kicsit altalanosabb */ + } + + len += snprintf(page + len, PAGE_SIZE - len, "Rx ring:\n"); + len += snprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott); + len += snprintf(page + len, PAGE_SIZE - len, + "\tlastcheck: %ld, jiffies: %ld\n", board->lastcheck, jiffies); + len += snprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n", + (u32) virt_to_phys(&hw->rx_desc[0])); + len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n", + hw->rx_desc_ptr); + len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n", + (u32) virt_to_phys(&hw->rx_desc[hw->rx_desc_ptr])); + len += snprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n", + board->ccb->current_rx_desc[hw->channel]); + + for (i = 0; i < RX_DESC_MAX; i++) + len += snprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n", + *((u32 *) & hw->rx_desc[i] + 0), + *((u32 *) & hw->rx_desc[i] + 1), + *((u32 *) & hw->rx_desc[i] + 2), + *((u32 *) & hw->rx_desc[i] + 3)); + + if (!board->isx21) + { + len += snprintf(page + len, PAGE_SIZE - len, + "Interfaces using this board: (channel-group, interface, timeslots)\n"); + for (i = 0; i < 32; i++) + { + devp = board->twins[i]; + if (devp != NULL) + { + timeslots = + ((struct slicecom_privdata *)((struct comx_channel *)devp-> + priv)->HW_privdata)-> + timeslots; + len += snprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i, + devp->name); + for (j = 0; j < 32; j++) + if ((1 << j) & timeslots) + len += snprintf(page + len, PAGE_SIZE - len, "%d ", j); + len += snprintf(page + len, PAGE_SIZE - len, "\n"); + } + } + } + + len += snprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n"); + for (i = 0; i < MAX_WORK; i++) + len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i, + board->histogram[i], (i && + ((i + 1) % 4 == 0 || + i == MAX_WORK - 1)) ? '\n' : ' '); + + len += snprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n"); + for (i = 0; i < TX_DESC_MAX; i++) + len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i, + hw->tx_ring_hist[i], (i && + ((i + 1) % 4 == 0 || + i == + TX_DESC_MAX - 1)) ? '\n' : ' '); + + if (!board->isx21) + { + + memset((void *)&last4, 0, sizeof(last4)); + memset((void *)&last96, 0, sizeof(last96)); + + /* Calculate the sum of last 4 intervals: */ + + for (i = 1; i <= 4; i++) + { + p = (unsigned *)&board->intervals[(board->current_interval + + SLICECOM_BOARD_INTERVALS_SIZE - + i) % SLICECOM_BOARD_INTERVALS_SIZE]; + sump = (unsigned *)&last4; + for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++) + sump[j] += p[j]; + } + + /* Calculate the sum of last 96 intervals: */ + + for (i = 1; i <= 96; i++) + { + p = (unsigned *)&board->intervals[(board->current_interval + + SLICECOM_BOARD_INTERVALS_SIZE - + i) % SLICECOM_BOARD_INTERVALS_SIZE]; + sump = (unsigned *)&last96; + for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++) + sump[j] += p[j]; + } + + len += snprintf(page + len, PAGE_SIZE - len, + "Data in current interval (%d seconds elapsed):\n", + board->elapsed_seconds); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", + curr_int->line_code_violations, + curr_int->path_code_violations, curr_int->e_bit_errors); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", + curr_int->slip_secs, curr_int->fr_loss_secs, + curr_int->line_err_secs, curr_int->degraded_mins); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", + curr_int->errored_secs, curr_int->bursty_err_secs, + curr_int->severely_err_secs, curr_int->unavail_secs); + + len += snprintf(page + len, PAGE_SIZE - len, + "Data in Interval 1 (15 minutes):\n"); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", + prev_int->line_code_violations, + prev_int->path_code_violations, prev_int->e_bit_errors); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", + prev_int->slip_secs, prev_int->fr_loss_secs, + prev_int->line_err_secs, prev_int->degraded_mins); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", + prev_int->errored_secs, prev_int->bursty_err_secs, + prev_int->severely_err_secs, prev_int->unavail_secs); + + len += snprintf(page + len, PAGE_SIZE - len, + "Data in last 4 intervals (1 hour):\n"); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", + last4.line_code_violations, last4.path_code_violations, + last4.e_bit_errors); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", + last4.slip_secs, last4.fr_loss_secs, last4.line_err_secs, + last4.degraded_mins); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", + last4.errored_secs, last4.bursty_err_secs, + last4.severely_err_secs, last4.unavail_secs); + + len += snprintf(page + len, PAGE_SIZE - len, + "Data in last 96 intervals (24 hours):\n"); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", + last96.line_code_violations, last96.path_code_violations, + last96.e_bit_errors); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", + last96.slip_secs, last96.fr_loss_secs, + last96.line_err_secs, last96.degraded_mins); + len += snprintf(page + len, PAGE_SIZE - len, + " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", + last96.errored_secs, last96.bursty_err_secs, + last96.severely_err_secs, last96.unavail_secs); + + } + +// len +=snprintf( page + len, PAGE_SIZE - len, "Special events:\n" ); +// len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed ); +// len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed ); + return len; +} + +/* + * Memory dump function. Not used currently. + */ +static int BOARD_dump(struct net_device *dev) +{ + printk + ("BOARD_dump() requested. It is unimplemented, it should not be called\n"); + return (-1); +} + +/* + * /proc file read function for the files registered by this module. + * This function is called by the procfs implementation when a user + * wants to read from a file registered by this module. + * page is the workspace, start should point to the real start of data, + * off is the file offset, data points to the file's proc_dir_entry + * structure. + * Returns the number of bytes copied to the request buffer. + */ + +static int munich_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct proc_dir_entry *file = (struct proc_dir_entry *)data; + struct net_device *dev = file->parent->data; + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + munich_board_t *board; + + int len = 0, i; + u32 timeslots = hw->timeslots; + + board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + if (!strcmp(file->name, FILENAME_BOARDNUM)) + len = sprintf(page, "%d\n", hw->boardnum); + else if (!strcmp(file->name, FILENAME_TIMESLOTS)) + { + for (i = 0; i < 32; i++) + if ((1 << i) & timeslots) + len += snprintf(page + len, PAGE_SIZE - len, "%d ", i); + len += snprintf(page + len, PAGE_SIZE - len, "\n"); + } + else if (!strcmp(file->name, FILENAME_FRAMING)) + { + i = 0; + while (slicecom_framings[i].value && + slicecom_framings[i].value != board->framing) + i++; + len += snprintf(page + len, PAGE_SIZE - len, "%s\n", + slicecom_framings[i].name); + } + else if (!strcmp(file->name, FILENAME_LINECODE)) + { + i = 0; + while (slicecom_linecodes[i].value && + slicecom_linecodes[i].value != board->linecode) + i++; + len += snprintf(page + len, PAGE_SIZE - len, "%s\n", + slicecom_linecodes[i].name); + } + else if (!strcmp(file->name, FILENAME_CLOCK_SOURCE)) + { + i = 0; + while (slicecom_clock_sources[i].value && + slicecom_clock_sources[i].value != board->clock_source) + i++; + len += + snprintf(page + len, PAGE_SIZE - len, "%s\n", + slicecom_clock_sources[i].name); + } + else if (!strcmp(file->name, FILENAME_LOOPBACK)) + { + i = 0; + while (slicecom_loopbacks[i].value && + slicecom_loopbacks[i].value != board->loopback) + i++; + len += snprintf(page + len, PAGE_SIZE - len, "%s\n", + slicecom_loopbacks[i].name); + } + /* We set permissions to write-only for REG and LBIREG, but root can read them anyway: */ + else if (!strcmp(file->name, FILENAME_REG)) + { + len += snprintf(page + len, PAGE_SIZE - len, + "%s: " FILENAME_REG ": write-only file\n", dev->name); + } + else if (!strcmp(file->name, FILENAME_LBIREG)) + { + len += snprintf(page + len, PAGE_SIZE - len, + "%s: " FILENAME_LBIREG ": write-only file\n", dev->name); + } + else + { + printk("slicecom_read_proc: internal error, filename %s\n", file->name); + return -EBADF; + } + /* file handling administration: count eof status, offset, start address + and count: */ + + if (off >= len) + { + *eof = 1; + return 0; + } + + *start = page + off; + if (count >= len - off) + *eof = 1; + return min((off_t) count, (off_t) len - off); +} + +/* + * Write function for /proc files registered by us. + * See the comment on read function above. + * Beware! buffer is in userspace!!! + * Returns the number of bytes written + */ + +static int munich_write_proc(struct file *file, const char *buffer, + u_long count, void *data) +{ + struct proc_dir_entry *entry = (struct proc_dir_entry *)data; + struct net_device *dev = (struct net_device *)entry->parent->data; + struct comx_channel *ch = dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; + munich_board_t *board; + + unsigned long ts, tmp_boardnum; + + u32 tmp_timeslots = 0; + char *page, *p; + int i; + + board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + /* Paranoia checking: */ + + if (file->f_dentry->d_inode->i_ino != entry->low_ino) + { + printk(KERN_ERR "munich_write_proc: file <-> data internal error\n"); + return -EIO; + } + + /* Request tmp buffer */ + if (!(page = (char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + + /* Copy user data and cut trailing \n */ + copy_from_user(page, buffer, count = min(count, PAGE_SIZE)); + if (*(page + count - 1) == '\n') + *(page + count - 1) = 0; + *(page + PAGE_SIZE - 1) = 0; + + if (!strcmp(entry->name, FILENAME_BOARDNUM)) + { + tmp_boardnum = simple_strtoul(page, NULL, 0); + if (0 <= tmp_boardnum && tmp_boardnum < MAX_BOARDS) + hw->boardnum = tmp_boardnum; + else + { + printk("%s: " FILENAME_BOARDNUM " range is 0...%d\n", dev->name, + MAX_BOARDS - 1); + free_page((unsigned long)page); + return -EINVAL; + } + } + else if (!strcmp(entry->name, FILENAME_TIMESLOTS)) + { + p = page; + while (*p) + { + if (isspace(*p)) + p++; + else + { + ts = simple_strtoul(p, &p, 10); /* base = 10: Don't read 09 as an octal number */ + /* ts = 0 ha nem tudta beolvasni a stringet, erre egy kicsit epitek itt: */ + if (0 <= ts && ts < 32) + { + tmp_timeslots |= (1 << ts); + } + else + { + printk("%s: " FILENAME_TIMESLOTS " range is 1...31\n", + dev->name); + free_page((unsigned long)page); + return -EINVAL; + } + } + } + hw->timeslots = tmp_timeslots; + } + else if (!strcmp(entry->name, FILENAME_FRAMING)) + { + i = 0; + while (slicecom_framings[i].value && + strncmp(slicecom_framings[i].name, page, + strlen(slicecom_framings[i].name))) + i++; + if (!slicecom_framings[i].value) + { + printk("slicecom: %s: Invalid " FILENAME_FRAMING " '%s'\n", + dev->name, page); + free_page((unsigned long)page); + return -EINVAL; + } + else + { /* + * If somebody says: + * echo >boardnum 0 + * echo >framing no-crc4 + * echo >boardnum 1 + * - when the framing was set, hw->boardnum was 0, so it would set the framing for board 0 + * Workaround: allow to set it only if interface is administrative UP + */ + if (netif_running(dev)) + slicecom_set_framing(hw->boardnum, slicecom_framings[i].value); + else + { + printk("%s: " FILENAME_FRAMING + " can not be set while the interface is DOWN\n", + dev->name); + free_page((unsigned long)page); + return -EINVAL; + } + } + } + else if (!strcmp(entry->name, FILENAME_LINECODE)) + { + i = 0; + while (slicecom_linecodes[i].value && + strncmp(slicecom_linecodes[i].name, page, + strlen(slicecom_linecodes[i].name))) + i++; + if (!slicecom_linecodes[i].value) + { + printk("slicecom: %s: Invalid " FILENAME_LINECODE " '%s'\n", + dev->name, page); + free_page((unsigned long)page); + return -EINVAL; + } + else + { /* + * Allow to set it only if interface is administrative UP, + * for the same reason as FILENAME_FRAMING + */ + if (netif_running(dev)) + slicecom_set_linecode(hw->boardnum, + slicecom_linecodes[i].value); + else + { + printk("%s: " FILENAME_LINECODE + " can not be set while the interface is DOWN\n", + dev->name); + free_page((unsigned long)page); + return -EINVAL; + } + } + } + else if (!strcmp(entry->name, FILENAME_CLOCK_SOURCE)) + { + i = 0; + while (slicecom_clock_sources[i].value && + strncmp(slicecom_clock_sources[i].name, page, + strlen(slicecom_clock_sources[i].name))) + i++; + if (!slicecom_clock_sources[i].value) + { + printk("%s: Invalid " FILENAME_CLOCK_SOURCE " '%s'\n", dev->name, + page); + free_page((unsigned long)page); + return -EINVAL; + } + else + { /* + * Allow to set it only if interface is administrative UP, + * for the same reason as FILENAME_FRAMING + */ + if (netif_running(dev)) + slicecom_set_clock_source(hw->boardnum, + slicecom_clock_sources[i].value); + else + { + printk("%s: " FILENAME_CLOCK_SOURCE + " can not be set while the interface is DOWN\n", + dev->name); + free_page((unsigned long)page); + return -EINVAL; + } + } + } + else if (!strcmp(entry->name, FILENAME_LOOPBACK)) + { + i = 0; + while (slicecom_loopbacks[i].value && + strncmp(slicecom_loopbacks[i].name, page, + strlen(slicecom_loopbacks[i].name))) + i++; + if (!slicecom_loopbacks[i].value) + { + printk("%s: Invalid " FILENAME_LOOPBACK " '%s'\n", dev->name, page); + free_page((unsigned long)page); + return -EINVAL; + } + else + { /* + * Allow to set it only if interface is administrative UP, + * for the same reason as FILENAME_FRAMING + */ + if (netif_running(dev)) + slicecom_set_loopback(hw->boardnum, + slicecom_loopbacks[i].value); + else + { + printk("%s: " FILENAME_LOOPBACK + " can not be set while the interface is DOWN\n", + dev->name); + free_page((unsigned long)page); + return -EINVAL; + } + } + } + else if (!strcmp(entry->name, FILENAME_REG)) + { /* DEL: 'reg' csak tmp */ + char *p; + u32 *bar1 = board->bar1; + + reg = simple_strtoul(page, &p, 0); + reg_ertek = simple_strtoul(p + 1, NULL, 0); + + if (reg < 0x100) + { + printk("reg(0x%02x) := 0x%08x jiff: %lu\n", reg, reg_ertek, jiffies); + writel(reg_ertek, MUNICH_VIRT(reg >> 2)); + } + else + { + printk("reg(0x%02x) is 0x%08x jiff: %lu\n", reg - 0x100, + readl(MUNICH_VIRT((reg - 0x100) >> 2)), jiffies); + } + } + else if (!strcmp(entry->name, FILENAME_LBIREG)) + { /* DEL: 'lbireg' csak tmp */ + char *p; + u8 *lbi = board->lbi; + + lbireg = simple_strtoul(page, &p, 0); + lbireg_ertek = simple_strtoul(p + 1, NULL, 0); + + if (lbireg < 0x100) + { + printk("lbireg(0x%02x) := 0x%02x jiff: %lu\n", lbireg, + lbireg_ertek, jiffies); + writeb(lbireg_ertek, lbi + lbireg); + } + else + printk("lbireg(0x%02x) is 0x%02x jiff: %lu\n", lbireg - 0x100, + readb(lbi + lbireg - 0x100), jiffies); + } + else + { + printk(KERN_ERR "munich_write_proc: internal error, filename %s\n", + entry->name); + free_page((unsigned long)page); + return -EBADF; + } + + /* Don't forget to free the workspace */ + free_page((unsigned long)page); + return count; +} + +/* + * Boardtype init function. + * Called by the comx (upper) layer, when you set boardtype. + * Allocates resources associated to using munich board for this device, + * initializes ch_struct pointers etc. + * Returns 0 on success and standard error codes on error. + */ + +static int init_escape(struct comx_channel *ch) +{ + kfree(ch->HW_privdata); + return -EIO; +} + +static int BOARD_init(struct net_device *dev) +{ + struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct slicecom_privdata *hw; + struct proc_dir_entry *new_file; + + /* Alloc data for private structure */ + if ((ch->HW_privdata = + kmalloc(sizeof(struct slicecom_privdata), GFP_KERNEL)) == NULL) + return -ENOMEM; + + memset(hw = ch->HW_privdata, 0, sizeof(struct slicecom_privdata)); + + /* Register /proc files */ + if ((new_file = create_proc_entry(FILENAME_BOARDNUM, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + if (ch->hardware == &slicecomhw) + { + if ((new_file = create_proc_entry(FILENAME_TIMESLOTS, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + if ((new_file = create_proc_entry(FILENAME_FRAMING, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + if ((new_file = create_proc_entry(FILENAME_LINECODE, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + if ((new_file = create_proc_entry(FILENAME_CLOCK_SOURCE, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + if ((new_file = create_proc_entry(FILENAME_LOOPBACK, S_IFREG | 0644, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + } + + /* DEL: ez itt csak fejlesztesi celokra!! */ + if ((new_file = create_proc_entry(FILENAME_REG, S_IFREG | 0200, ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + /* DEL: ez itt csak fejlesztesi celokra!! */ + if ((new_file = create_proc_entry(FILENAME_LBIREG, S_IFREG | 0200, + ch->procdir)) == NULL) + return init_escape(ch); + new_file->data = (void *)new_file; + new_file->read_proc = &munich_read_proc; + new_file->write_proc = &munich_write_proc; +// new_file->proc_iops = &comx_normal_inode_ops; + new_file->nlink = 1; + + /* Fill in ch_struct hw specific pointers: */ + + ch->HW_txe = MUNICH_txe; + ch->HW_open = MUNICH_open; + ch->HW_close = MUNICH_close; + ch->HW_send_packet = MUNICH_send_packet; +#ifndef COMX_NEW + ch->HW_minden = MUNICH_minden; +#else + ch->HW_statistics = MUNICH_minden; +#endif + + hw->boardnum = SLICECOM_BOARDNUM_DEFAULT; + hw->timeslots = ch->hardware == &pcicomhw ? 0xffffffff : 2; + + /* O.K. Count one more user on this module */ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Boardtype exit function. + * Called by the comx (upper) layer, when you clear boardtype from munich. + * Frees resources associated to using munich board for this device, + * resets ch_struct pointers etc. + */ +static int BOARD_exit(struct net_device *dev) +{ + struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct slicecom_privdata *hw = ch->HW_privdata; +// munich_board_t *board; + + /* Free private data area */ +// board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); + + kfree(ch->HW_privdata); + /* Remove /proc files */ + remove_proc_entry(FILENAME_BOARDNUM, ch->procdir); + if (ch->hardware == &slicecomhw) + { + remove_proc_entry(FILENAME_TIMESLOTS, ch->procdir); + remove_proc_entry(FILENAME_FRAMING, ch->procdir); + remove_proc_entry(FILENAME_LINECODE, ch->procdir); + remove_proc_entry(FILENAME_CLOCK_SOURCE, ch->procdir); + remove_proc_entry(FILENAME_LOOPBACK, ch->procdir); + } + remove_proc_entry(FILENAME_REG, ch->procdir); + remove_proc_entry(FILENAME_LBIREG, ch->procdir); + + /* Minus one user for the module accounting */ + MOD_DEC_USE_COUNT; + return 0; +} + +static struct comx_hardware slicecomhw = +{ + "slicecom", +#ifdef COMX_NEW + VERSION, +#endif + BOARD_init, + BOARD_exit, + BOARD_dump, + NULL +}; + +static struct comx_hardware pcicomhw = +{ + "pcicom", +#ifdef COMX_NEW + VERSION, +#endif + BOARD_init, + BOARD_exit, + BOARD_dump, + NULL +}; + +/* Module management */ + +int __init init_mister(void) +{ + printk(VERSIONSTR); + comx_register_hardware(&slicecomhw); + comx_register_hardware(&pcicomhw); + return munich_probe(); +} + +static void __exit cleanup_mister(void) +{ + int i; + + comx_unregister_hardware("slicecom"); + comx_unregister_hardware("pcicom"); + + for (i = 0; i < MAX_BOARDS; i++) + { + if (slicecom_boards[i].bar1) + iounmap((void *)slicecom_boards[i].bar1); + if (slicecom_boards[i].lbi) + iounmap((void *)slicecom_boards[i].lbi); + if (pcicom_boards[i].bar1) + iounmap((void *)pcicom_boards[i].bar1); + if (pcicom_boards[i].lbi) + iounmap((void *)pcicom_boards[i].lbi); + } +} + +module_init(init_mister); +module_exit(cleanup_mister); diff -urN linux-2.4.18/drivers/net/wan/comx.c linux-2.4.19-pre5/drivers/net/wan/comx.c --- linux-2.4.18/drivers/net/wan/comx.c Sun Feb 17 02:59:48 2002 +++ linux-2.4.19-pre5/drivers/net/wan/comx.c Sat Mar 30 22:55:35 2002 @@ -1,7 +1,7 @@ /* * Device driver framework for the COMX line of synchronous serial boards * - * for Linux kernel 2.2.X + * for Linux kernel 2.2.X / 2.4.X * * Original authors: Arpad Bakay , * Peter Bajan , diff -urN linux-2.4.18/drivers/net/wan/falc-lh.h linux-2.4.19-pre5/drivers/net/wan/falc-lh.h --- linux-2.4.18/drivers/net/wan/falc-lh.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/wan/falc-lh.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,102 @@ +/* + * Defines for comx-hw-slicecom.c - FALC-LH specific + * + * Author: Bartok Istvan + * Last modified: Mon Feb 7 20:00:38 CET 2000 + * + * :set tabstop=6 + */ + +/* + * Control register offsets on the LBI (page 90) + * use it like: + * lbi[ MODE ] = 0x34; + */ + +#define MODE 0x03 +#define IPC 0x08 +#define IMR0 0x14 /* Interrupt Mask Register 0 */ +#define IMR1 0x15 +#define IMR2 0x16 +#define IMR3 0x17 +#define IMR4 0x18 +#define IMR5 0x19 +#define FMR0 0x1a /* Framer Mode Register 0 */ +#define FMR1 0x1b +#define FMR2 0x1c +#define XSW 0x1e +#define XSP 0x1f +#define XC0 0x20 +#define XC1 0x21 +#define RC0 0x22 +#define RC1 0x23 +#define XPM0 0x24 +#define XPM1 0x25 +#define XPM2 0x26 +#define TSWM 0x27 +#define IDLE 0x29 /* Idle Code */ +#define LIM0 0x34 +#define LIM1 0x35 +#define PCD 0x36 +#define PCR 0x37 +#define LIM2 0x38 + +/* + * Status registers on the LBI (page 134) + * these are read-only, use it like: + * if( lbi[ FRS0 ] ) ... + */ + +#define FRS0 0x4c /* Framer Receive Status register 0 */ +#define FRS1 0x4d /* Framer Receive Status register 1 */ +#define FECL 0x50 /* Framing Error Counter low byte */ /* Counts FAS word receive errors */ +#define FECH 0x51 /* high byte */ +#define CVCL 0x52 /* Code Violation Counter low byte */ /* Counts bipolar and HDB3 code violations */ +#define CVCH 0x53 /* high byte */ +#define CEC1L 0x54 /* CRC4 Error Counter 1 low byte */ /* Counts CRC4 errors in the incoming stream */ +#define CEC1H 0x55 /* high byte */ +#define EBCL 0x56 /* E Bit error Counter low byte */ /* E-bits: the remote end sends them, when */ +#define EBCH 0x57 /* high byte */ /* it detected a CRC4-error */ +#define ISR0 0x68 /* Interrupt Status Register 0 */ +#define ISR1 0x69 /* Interrupt Status Register 1 */ +#define ISR2 0x6a /* Interrupt Status Register 2 */ +#define ISR3 0x6b /* Interrupt Status Register 3 */ +#define ISR5 0x6c /* Interrupt Status Register 5 */ +#define GIS 0x6e /* Global Interrupt Status Register */ +#define VSTR 0x6f /* version information */ + +/* + * Bit fields + */ + +#define FRS0_LOS (1 << 7) +#define FRS0_AIS (1 << 6) +#define FRS0_LFA (1 << 5) +#define FRS0_RRA (1 << 4) +#define FRS0_AUXP (1 << 3) +#define FRS0_NMF (1 << 2) +#define FRS0_LMFA (1 << 1) + +#define FRS1_XLS (1 << 1) +#define FRS1_XLO (1) + +#define ISR2_FAR (1 << 7) +#define ISR2_LFA (1 << 6) +#define ISR2_MFAR (1 << 5) +#define ISR2_T400MS (1 << 4) +#define ISR2_AIS (1 << 3) +#define ISR2_LOS (1 << 2) +#define ISR2_RAR (1 << 1) +#define ISR2_RA (1) + +#define ISR3_ES (1 << 7) +#define ISR3_SEC (1 << 6) +#define ISR3_LMFA16 (1 << 5) +#define ISR3_AIS16 (1 << 4) +#define ISR3_RA16 (1 << 3) +#define ISR3_API (1 << 2) +#define ISR3_RSN (1 << 1) +#define ISR3_RSP (1) + +#define ISR5_XSP (1 << 7) +#define ISR5_XSN (1 << 6) diff -urN linux-2.4.18/drivers/net/wan/lmc/lmc_debug.c linux-2.4.19-pre5/drivers/net/wan/lmc/lmc_debug.c --- linux-2.4.18/drivers/net/wan/lmc/lmc_debug.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wan/lmc/lmc_debug.c Sat Mar 30 22:55:35 2002 @@ -72,12 +72,12 @@ if(in_interrupt()){ printk("%s: * %s\n", dev->name, msg); -// while(jiffies < j+10) +// while(time_before(jiffies, j+10)) // ; } else { printk("%s: %s\n", dev->name, msg); - while(jiffies < j) + while(time_before(jiffies, j)) schedule(); } #endif diff -urN linux-2.4.18/drivers/net/wan/lmc/lmc_var.h linux-2.4.19-pre5/drivers/net/wan/lmc/lmc_var.h --- linux-2.4.18/drivers/net/wan/lmc/lmc_var.h Mon Feb 18 06:30:51 2002 +++ linux-2.4.19-pre5/drivers/net/wan/lmc/lmc_var.h Sat Mar 30 22:55:28 2002 @@ -87,7 +87,7 @@ lmc_delay(); \ LMC_CSR_WRITE((sc), csr_9, 0x30000); \ lmc_delay(); \ - n--; }} while(0); + n--; }} while(0) struct lmc_regfile_t { lmc_csrptr_t csr_busmode; /* CSR0 */ diff -urN linux-2.4.18/drivers/net/wan/munich32x.h linux-2.4.19-pre5/drivers/net/wan/munich32x.h --- linux-2.4.18/drivers/net/wan/munich32x.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/net/wan/munich32x.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,191 @@ +/* + * Defines for comx-hw-slicecom.c - MUNICH32X specific + * + * Author: Bartok Istvan + * Last modified: Tue Jan 11 14:27:36 CET 2000 + * + * :set tabstop=6 + */ + +#define TXBUFFER_SIZE 1536 /* Max mennyit tud a kartya hardver atvenni */ +#define RXBUFFER_SIZE (TXBUFFER_SIZE+4) /* For Rx reasons it must be a multiple of 4, and =>4 (page 265) */ + /* +4 .. see page 265, bit FE */ + /* TOD: a MODE1-be nem is ezt teszem, hanem a TXBUFFER-t, lehet hogy nem is kell? */ + +//#define PCI_VENDOR_ID_SIEMENS 0x110a +#define PCI_DEVICE_ID_SIEMENS_MUNICH32X 0x2101 + +/* + * PCI config space registers (page 120) + */ + +#define MUNICH_PCI_PCIRES 0x4c /* 0xe0000 resets the chip */ + + +/* + * MUNICH slave register offsets relative to base_address[0] (PCI BAR1) (page 181): + * offsets are in bytes, registers are u32's, so we need a >>2 for indexing + * the int[] by byte offsets. Use it like: + * + * bar1[ STAT ] = ~0L; or + * x = bar1[ STAT ]; + */ + +#define CONF (0x00 >> 2) +#define CMD (0x04 >> 2) +#define STAT (0x08 >> 2) +#define STACK (0x08 >> 2) +#define IMASK (0x0c >> 2) +#define PIQBA (0x14 >> 2) +#define PIQL (0x18 >> 2) +#define MODE1 (0x20 >> 2) +#define MODE2 (0x24 >> 2) +#define CCBA (0x28 >> 2) +#define TXPOLL (0x2c >> 2) +#define TIQBA (0x30 >> 2) +#define TIQL (0x34 >> 2) +#define RIQBA (0x38 >> 2) +#define RIQL (0x3c >> 2) +#define LCONF (0x40 >> 2) /* LBI Configuration Register */ +#define LCCBA (0x44 >> 2) /* LBI Configuration Control Block */ /* DE: lehet hogy nem is kell? */ +#define LTIQBA (0x50 >> 2) /* DE: lehet hogy nem is kell? page 210: LBI DMA Controller intq - nem hasznalunk DMA-t.. */ +#define LTIQL (0x54 >> 2) /* DE: lehet hogy nem is kell? */ +#define LRIQBA (0x58 >> 2) /* DE: lehet hogy nem is kell? */ +#define LRIQL (0x5c >> 2) /* DE: lehet hogy nem is kell? */ +#define LREG0 (0x60 >> 2) /* LBI Indirect External Configuration register 0 */ +#define LREG1 (0x64 >> 2) +#define LREG2 (0x68 >> 2) +#define LREG3 (0x6c >> 2) +#define LREG4 (0x70 >> 2) +#define LREG5 (0x74 >> 2) +#define LREG6 (0x78 >> 2) /* LBI Indirect External Configuration register 6 */ +#define LSTAT (0x7c >> 2) /* LBI Status Register */ +#define GPDIR (0x80 >> 2) /* General Purpose Bus DIRection - 0..input, 1..output */ +#define GPDATA (0x84 >> 2) /* General Purpose Bus DATA */ + + +/* + * MUNICH commands: (they go into register CMD) + */ + +#define CMD_ARPCM 0x01 /* Action Request Serial PCM Core */ +#define CMD_ARLBI 0x02 /* Action Request LBI */ + + +/* + * MUNICH event bits in the STAT, STACK, IMASK registers (page 188,189) + */ + +#define STAT_PTI (1 << 15) +#define STAT_PRI (1 << 14) +#define STAT_LTI (1 << 13) +#define STAT_LRI (1 << 12) +#define STAT_IOMI (1 << 11) +#define STAT_SSCI (1 << 10) +#define STAT_LBII (1 << 9) +#define STAT_MBI (1 << 8) + +#define STAT_TI (1 << 6) +#define STAT_TSPA (1 << 5) +#define STAT_RSPA (1 << 4) +#define STAT_LBIF (1 << 3) +#define STAT_LBIA (1 << 2) +#define STAT_PCMF (1 << 1) +#define STAT_PCMA (1) + +/* + * We do not handle these (and do not touch their STAT bits) in the interrupt loop + */ + +#define STAT_NOT_HANDLED_BY_INTERRUPT (STAT_PCMF | STAT_PCMA) + + +/* + * MUNICH MODE1/MODE2 slave register fields (page 193,196) + * these are not all masks, MODE1_XX_YY are my magic values! + */ + +#define MODE1_PCM_E1 (1 << 31) /* E1, 2.048 Mbit/sec */ +#define MODE1_TBS_4 (1 << 24) /* TBS = 4 .. no Tx bit shift */ +#define MODE1_RBS_4 (1 << 18) /* RBS = 4 .. no Rx bit shift */ +#define MODE1_REN (1 << 15) /* Rx Enable */ +#define MODE1_MFL_MY TXBUFFER_SIZE /* Maximum Frame Length */ +#define MODE1_MAGIC (MODE1_PCM_E1 | MODE1_TBS_4 | MODE1_RBS_4 | MODE1_REN | MODE1_MFL_MY) + +#define MODE2_HPOLL (1 << 8) /* Hold Poll */ +#define MODE2_SPOLL (1 << 7) /* Slow Poll */ +#define MODE2_TSF (1) /* real magic - discovered by probing :) */ +// #define MODE2_MAGIC (MODE2_TSF) +#define MODE2_MAGIC (MODE2_SPOLL | MODE2_TSF) + + +/* + * LCONF bits (page 205) + * these are not all masks, LCONF_XX_YY are my magic values! + */ + +#define LCONF_IPA (1 << 31) /* Interrupt Pass. Use 1 for FALC54 */ +#define LCONF_DCA (1 << 30) /* Disregard the int's for Channel A - DMSM does not try to handle them */ +#define LCONF_DCB (1 << 29) /* Disregard the int's for Channel B */ +#define LCONF_EBCRES (1 << 22) /* Reset LBI External Bus Controller, 0..reset, 1..normal operation */ +#define LCONF_LBIRES (1 << 21) /* Reset LBI DMSM, 0..reset, 1..normal operation */ +#define LCONF_BTYP_16DEMUX (1 << 7) /* 16-bit demultiplexed bus */ +#define LCONF_ABM (1 << 4) /* Arbitration Master */ + +/* writing LCONF_MAGIC1 followed by a LCONF_MAGIC2 into LCONF resets the EBC and DMSM: */ + +#define LCONF_MAGIC1 (LCONF_BTYP_16DEMUX | LCONF_ABM | LCONF_IPA | LCONF_DCA | LCONF_DCB) +#define LCONF_MAGIC2 (LCONF_MAGIC1 | LCONF_EBCRES | LCONF_LBIRES) + + +/* + * LREGx magic values if a FALC54 is on the LBI (page 217) + */ + +#define LREG0_MAGIC 0x00000264 +#define LREG1_MAGIC 0x6e6a6b66 +#define LREG2_MAGIC 0x00000264 +#define LREG3_MAGIC 0x6e686966 +#define LREG4_MAGIC 0x00000000 +#define LREG5_MAGIC ( (7<<27) | (3<<24) | (1<<21) | (7<<3) | (2<<9) ) + + +/* + * PCM Action Specification fields (munich_ccb_t.action_spec) + */ + +#define CCB_ACTIONSPEC_IN (1 << 15) /* init */ +#define CCB_ACTIONSPEC_ICO (1 << 14) /* init only this channel */ +#define CCB_ACTIONSPEC_RES (1 << 6) /* reset all channels */ +#define CCB_ACTIONSPEC_LOC (1 << 5) +#define CCB_ACTIONSPEC_LOOP (1 << 4) +#define CCB_ACTIONSPEC_LOOPI (1 << 3) +#define CCB_ACTIONSPEC_IA (1 << 2) + + +/* + * Interrupt Information bits in the TIQ, RIQ + */ + +#define PCM_INT_HI (1 << 12) +#define PCM_INT_FI (1 << 11) +#define PCM_INT_IFC (1 << 10) +#define PCM_INT_SF (1 << 9) +#define PCM_INT_ERR (1 << 8) +#define PCM_INT_FO (1 << 7) +#define PCM_INT_FE2 (1 << 6) + +#define PCM_INT_CHANNEL( info ) (info & 0x1F) + + +/* + * Rx status info in the rx_desc_t.status + */ + +#define RX_STATUS_SF (1 << 6) +#define RX_STATUS_LOSS (1 << 5) +#define RX_STATUS_CRCO (1 << 4) +#define RX_STATUS_NOB (1 << 3) +#define RX_STATUS_LFD (1 << 2) +#define RX_STATUS_RA (1 << 1) +#define RX_STATUS_ROF 1 diff -urN linux-2.4.18/drivers/net/wan/sdla_x25.c linux-2.4.19-pre5/drivers/net/wan/sdla_x25.c --- linux-2.4.18/drivers/net/wan/sdla_x25.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wan/sdla_x25.c Sat Mar 30 22:55:28 2002 @@ -1272,7 +1272,7 @@ add_timer(&card->u.x.x25_timer); } } - /* Device is not up untill the we are in connected state */ + /* Device is not up until the we are in connected state */ do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; @@ -4756,7 +4756,7 @@ * send_delayed_cmd_result * * Wait commands like PLEACE CALL or CLEAR CALL must wait - * untill the result arrivers. This function passes + * until the result arrives. This function passes * the result to a waiting sock. * *===============================================================*/ diff -urN linux-2.4.18/drivers/net/wan/sealevel.c linux-2.4.19-pre5/drivers/net/wan/sealevel.c --- linux-2.4.18/drivers/net/wan/sealevel.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wan/sealevel.c Sat Mar 30 22:55:28 2002 @@ -219,12 +219,11 @@ * Get the needed I/O space */ - if(check_region(iobase, 8)) + if(!request_region(iobase, 8, "Sealevel 4021")) { printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); return NULL; } - request_region(iobase, 8, "Sealevel 4021"); b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); if(!b) diff -urN linux-2.4.18/drivers/net/wd.c linux-2.4.19-pre5/drivers/net/wd.c --- linux-2.4.18/drivers/net/wd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/wd.c Sat Mar 30 22:55:40 2002 @@ -97,7 +97,7 @@ return -EBUSY; i = wd_probe1(dev, base_addr); if (i != 0) - release_resource(r); + release_region(base_addr, WD_IO_EXTENT); else r->name = dev->name; return i; @@ -114,7 +114,7 @@ r->name = dev->name; return 0; } - release_resource(r); + release_region(ioaddr, WD_IO_EXTENT); } return -ENODEV; @@ -450,10 +450,11 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_WD_CARDS) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_WD_CARDS) "i"); MODULE_PARM(mem_end, "1-" __MODULE_STRING(MAX_WD_CARDS) "i"); -MODULE_PARM_DESC(io, "WD80x3 I/O base address(es)"); -MODULE_PARM_DESC(irq, "WD80x3 IRQ number(s) (ignored for PureData boards)"); -MODULE_PARM_DESC(mem, "WD80x3 memory base address(es)(ignored for PureData boards)"); -MODULE_PARM_DESC(mem_end, "WD80x3 memory end address(es)"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)"); +MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)"); +MODULE_PARM_DESC(mem_end, "memory end address(es)"); +MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver"); MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. diff -urN linux-2.4.18/drivers/net/winbond-840.c linux-2.4.19-pre5/drivers/net/winbond-840.c --- linux-2.4.18/drivers/net/winbond-840.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/winbond-840.c Sat Mar 30 22:55:35 2002 @@ -138,6 +138,7 @@ #include #include #include +#include #include #include /* Processor type for cache alignment. */ #include @@ -388,7 +389,6 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); -static inline unsigned ether_crc(int length, unsigned char *data); static u32 __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); @@ -1410,21 +1410,6 @@ return &np->stats; } -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; -} static u32 __set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/wireless/orinoco_plx.c linux-2.4.19-pre5/drivers/net/wireless/orinoco_plx.c --- linux-2.4.18/drivers/net/wireless/orinoco_plx.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/net/wireless/orinoco_plx.c Sat Mar 30 22:55:40 2002 @@ -385,18 +385,17 @@ {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ + {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 */ {0,}, }; MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table); static struct pci_driver orinoco_plx_driver = { - name:"orinoco_plx", - id_table:orinoco_plx_pci_id_table, - probe:orinoco_plx_init_one, - remove:__devexit_p(orinoco_plx_remove_one), - suspend:0, - resume:0 + name: "orinoco_plx", + id_table: orinoco_plx_pci_id_table, + probe: orinoco_plx_init_one, + remove: __devexit_p(orinoco_plx_remove_one), }; static int __init orinoco_plx_init(void) diff -urN linux-2.4.18/drivers/net/yellowfin.c linux-2.4.19-pre5/drivers/net/yellowfin.c --- linux-2.4.18/drivers/net/yellowfin.c Sun Dec 23 16:23:46 2001 +++ linux-2.4.19-pre5/drivers/net/yellowfin.c Sat Mar 30 22:55:35 2002 @@ -125,6 +125,7 @@ #include #include #include +#include #include #include /* Processor type for cache alignment. */ #include @@ -1338,29 +1339,6 @@ } /* Set or clear the multicast filter for this adaptor. */ - -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; - -static inline unsigned ether_crc_le(int length, unsigned char *data) -{ - unsigned int crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { diff -urN linux-2.4.18/drivers/net/zlib.c linux-2.4.19-pre5/drivers/net/zlib.c --- linux-2.4.18/drivers/net/zlib.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/net/zlib.c Sat Mar 30 22:55:35 2002 @@ -14,7 +14,7 @@ */ /* - * ==FILEVERSION 971210== + * ==FILEVERSION 20020318== * * This marker is used by the Linux installation script to determine * whether an up-to-date version of this file is already installed. @@ -772,7 +772,7 @@ windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { return Z_STREAM_ERROR; } @@ -3860,10 +3860,12 @@ &s->sub.trees.tb, z); if (t != Z_OK) { - ZFREE(z, s->sub.trees.blens); r = t; if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BADB; + } LEAVE } s->sub.trees.index = 0; @@ -3928,11 +3930,13 @@ #endif t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, z); - ZFREE(z, s->sub.trees.blens); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BADB; + } r = t; LEAVE } @@ -3945,6 +3949,7 @@ r = Z_MEM_ERROR; LEAVE } + ZFREE(z, s->sub.trees.blens); s->sub.decode.codes = c; s->sub.decode.tl = tl; s->sub.decode.td = td; diff -urN linux-2.4.18/drivers/parport/ChangeLog linux-2.4.19-pre5/drivers/parport/ChangeLog --- linux-2.4.18/drivers/parport/ChangeLog Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/parport/ChangeLog Sat Mar 30 22:55:28 2002 @@ -1,3 +1,26 @@ +2001-12-07 Tim Waugh + + * parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before + and after probing for ports. + * parport_serial.c (parport_register): Likewise. + +2002-01-20 Tim Waugh + + * parport_pc.c (parport_pc_compat_write_block_pio, + parport_pc_ecp_write_block_pio, parport_pc_ecp_read_block_pio): + Use the default implementations if the caller wants to use + O_NONBLOCK. + +2002-01-21 Tim Waugh + + * daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select + work for ECP/EPP modes. + +2002-02-25 Tim Waugh + + * parport_pc.c: Make sure that priv->ctr_writable includes IntEn + even if IRQ is given as a parameter. + 2002-01-13 Niels Kristian Bech Jensen * parport_pc.c: Change some occurrences of frob_set_mode to diff -urN linux-2.4.18/drivers/parport/daisy.c linux-2.4.19-pre5/drivers/parport/daisy.c --- linux-2.4.18/drivers/parport/daisy.c Sun Dec 23 16:23:46 2001 +++ linux-2.4.19-pre5/drivers/parport/daisy.c Sat Mar 30 22:55:28 2002 @@ -406,8 +406,33 @@ int parport_daisy_select (struct parport *port, int daisy, int mode) { - /* mode is currently ignored. FIXME? */ - return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR; + switch (mode) + { + // For these modes we should switch to EPP mode: + case IEEE1284_MODE_EPP: + case IEEE1284_MODE_EPPSL: + case IEEE1284_MODE_EPPSWE: + return (cpp_daisy (port, 0x20 + daisy) & + PARPORT_STATUS_ERROR); + + // For these modes we should switch to ECP mode: + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + case IEEE1284_MODE_ECPSWE: + return (cpp_daisy (port, 0xd0 + daisy) & + PARPORT_STATUS_ERROR); + + // Nothing was told for BECP in Daisy chain specification. + // May be it's wise to use ECP? + case IEEE1284_MODE_BECP: + // Others use compat mode + case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: + case IEEE1284_MODE_COMPAT: + default: + return (cpp_daisy (port, 0xe0 + daisy) & + PARPORT_STATUS_ERROR); + } } static int mux_present (struct parport *port) diff -urN linux-2.4.18/drivers/parport/parport_mfc3.c linux-2.4.19-pre5/drivers/parport/parport_mfc3.c --- linux-2.4.18/drivers/parport/parport_mfc3.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/parport/parport_mfc3.c Sat Mar 30 22:55:35 2002 @@ -408,6 +408,7 @@ MODULE_AUTHOR("Joerg Dorchain "); MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port"); MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port"); +MODULE_LICENSE("GPL"); module_init(parport_mfc3_init) module_exit(parport_mfc3_exit) diff -urN linux-2.4.18/drivers/parport/parport_pc.c linux-2.4.19-pre5/drivers/parport/parport_pc.c --- linux-2.4.18/drivers/parport/parport_pc.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/parport/parport_pc.c Sat Mar 30 22:55:28 2002 @@ -821,8 +821,9 @@ long int expire; const struct parport_pc_private *priv = port->physport->private_data; - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->physport->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_write_compat (port, buf, length, flags); @@ -897,8 +898,9 @@ long int expire; const struct parport_pc_private *priv = port->physport->private_data; - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->physport->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_ecp_write_data (port, buf, length, flags); @@ -1017,8 +1019,9 @@ DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); dump_parport_state ("enter fcn", port); - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_ecp_read_data (port, buf, length, flags); @@ -2139,8 +2142,6 @@ { struct parport_pc_private *priv = pb->private_data; - priv->ctr_writable |= 0x10; - if (priv->ecr) { pb->irq = programmable_irq_support(pb); @@ -2165,9 +2166,6 @@ if (pb->irq == PARPORT_IRQ_NONE) pb->irq = get_superio_irq(pb); - if (pb->irq == PARPORT_IRQ_NONE) - priv->ctr_writable &= ~0x10; - return pb->irq; } @@ -2296,6 +2294,7 @@ } if (p->irq != PARPORT_IRQ_NONE) { printk(", irq %d", p->irq); + priv->ctr_writable |= 0x10; if (p->dma == PARPORT_DMA_AUTO) { p->dma = PARPORT_DMA_NONE; @@ -2723,6 +2722,15 @@ int hi; /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4]; + + /* If set, this is called immediately after pci_enable_device. + * If it returns non-zero, no probing will take place and the + * ports will not be used. */ + int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); + + /* If set, this is called after probing for ports. If 'failed' + * is non-zero we couldn't use any of the ports. */ + void (*postinit_hook) (struct pci_dev *pdev, int failed); } cards[] __devinitdata = { /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } }, /* siig_1s1p_10x_650 */ { 1, { { 3, 4 }, } }, @@ -2899,6 +2907,10 @@ if ((err = pci_enable_device (dev)) != 0) return err; + if (cards[i].preinit_hook && + cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) + return -ENODEV; + for (n = 0; n < cards[i].numports; n++) { int lo = cards[i].addr[n].lo; int hi = cards[i].addr[n].hi; @@ -2920,6 +2932,9 @@ PARPORT_DMA_NONE, dev)) count++; } + + if (cards[i].postinit_hook) + cards[i].postinit_hook (dev, count == 0); return count == 0 ? -ENODEV : 0; } diff -urN linux-2.4.18/drivers/parport/parport_serial.c linux-2.4.19-pre5/drivers/parport/parport_serial.c --- linux-2.4.18/drivers/parport/parport_serial.c Sun Dec 23 16:23:46 2001 +++ linux-2.4.19-pre5/drivers/parport/parport_serial.c Sat Mar 30 22:55:28 2002 @@ -53,6 +53,15 @@ int hi; /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4]; + + /* If set, this is called immediately after pci_enable_device. + * If it returns non-zero, no probing will take place and the + * ports will not be used. */ + int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); + + /* If set, this is called after probing for ports. If 'failed' + * is non-zero we couldn't use any of the ports. */ + void (*postinit_hook) (struct pci_dev *pdev, int failed); } cards[] __devinitdata = { /* titan_110l */ { 1, { { 3, -1 }, } }, /* titan_210l */ { 1, { { 3, -1 }, } }, @@ -239,6 +248,10 @@ int i = id->driver_data, n; int success = 0; + if (cards[i].preinit_hook && + cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) + return -ENODEV; + for (n = 0; n < cards[i].numports; n++) { struct parport *port; int lo = cards[i].addr[n].lo; @@ -264,6 +277,9 @@ success = 1; } } + + if (cards[i].postinit_hook) + cards[i].postinit_hook (dev, !success); return success ? 0 : 1; } diff -urN linux-2.4.18/drivers/pci/Makefile linux-2.4.19-pre5/drivers/pci/Makefile --- linux-2.4.18/drivers/pci/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pci/Makefile Sat Mar 30 22:55:28 2002 @@ -28,8 +28,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_ALL_PPC) += setup-bus.o -obj-$(CONFIG_DDB5476) += setup-bus.o obj-$(CONFIG_SGI_IP27) += setup-irq.o +obj-$(CONFIG_SGI_IP32) += setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -urN linux-2.4.18/drivers/pci/gen-devlist.c linux-2.4.19-pre5/drivers/pci/gen-devlist.c --- linux-2.4.18/drivers/pci/gen-devlist.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pci/gen-devlist.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* * Generate devlist.h and classlist.h from the PCI ID file. * - * (c) 1999--2000 Martin Mares + * (c) 1999--2002 Martin Mares */ #include @@ -15,8 +15,13 @@ while (*c) { if (*c == '"') fprintf(f, "\\\""); - else + else { fputc(*c, f); + if (*c == '?' && c[1] == '?') { + /* Avoid trigraphs */ + fprintf(f, "\" \""); + } + } c++; } } diff -urN linux-2.4.18/drivers/pci/pci.c linux-2.4.19-pre5/drivers/pci/pci.c --- linux-2.4.18/drivers/pci/pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pci/pci.c Sat Mar 30 22:55:35 2002 @@ -23,6 +23,7 @@ #include /* for hotplug_path */ #include #include +#include #include #include /* isa_dma_bridge_buggy */ @@ -846,6 +847,100 @@ pcibios_set_master(dev); } +/** + * pdev_set_mwi - arch helper function for pcibios_set_mwi + * @dev: the PCI device for which MWI is enabled + * + * Helper function for implementation the arch-specific pcibios_set_mwi + * function. Originally copied from drivers/net/acenic.c. + * Copyright 1998-2001 by Jes Sorensen, . + * + * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success. + */ +int +pdev_set_mwi(struct pci_dev *dev) +{ + int rc = 0; + u8 cache_size; + + /* + * Looks like this is necessary to deal with on all architectures, + * even this %$#%$# N440BX Intel based thing doesn't get it right. + * Ie. having two NICs in the machine, one will have the cache + * line set at boot time, the other will not. + */ + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size); + cache_size <<= 2; + if (cache_size != SMP_CACHE_BYTES) { + printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly " + "(%i bytes) by BIOS/FW, ", + dev->slot_name, cache_size); + if (cache_size > SMP_CACHE_BYTES) { + printk("expecting %i\n", SMP_CACHE_BYTES); + rc = -EINVAL; + } else { + printk("correcting to %i\n", SMP_CACHE_BYTES); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + SMP_CACHE_BYTES >> 2); + } + } + + return rc; +} + +/** + * pci_set_mwi - enables memory-write-validate PCI transaction + * @dev: the PCI device for which MWI is enabled + * + * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND, + * and then calls @pcibios_set_mwi to do the needed arch specific + * operations or a generic mwi-prep function. + * + * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success. + */ +int +pci_set_mwi(struct pci_dev *dev) +{ + int rc; + u16 cmd; + +#ifdef HAVE_ARCH_PCI_MWI + rc = pcibios_set_mwi(dev); +#else + rc = pdev_set_mwi(dev); +#endif + + if (rc) + return rc; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (! (cmd & PCI_COMMAND_INVALIDATE)) { + DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name); + cmd |= PCI_COMMAND_INVALIDATE; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + return 0; +} + +/** + * pci_clear_mwi - disables Memory-Write-Invalidate for device dev + * @dev: the PCI device to disable + * + * Disables PCI Memory-Write-Invalidate transaction on the device + */ +void +pci_clear_mwi(struct pci_dev *dev) +{ + u16 cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_INVALIDATE) { + cmd &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } +} + int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { @@ -914,13 +1009,15 @@ l = 0; if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { res->start = l & PCI_BASE_ADDRESS_MEM_MASK; + res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK); } else { res->start = l & PCI_BASE_ADDRESS_IO_MASK; + res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); } res->end = res->start + (unsigned long) sz; - res->flags |= (l & 0xf) | pci_calc_resource_flags(l); + res->flags |= 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); @@ -964,7 +1061,7 @@ } } -void __devinit pci_read_bridge_bases(struct pci_bus *child) +void __devinit pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; @@ -1055,7 +1152,7 @@ } } -static struct pci_bus * __devinit pci_alloc_bus(void) +static struct pci_bus * __devinit pci_alloc_bus(void) { struct pci_bus *b; @@ -1380,7 +1477,7 @@ return max; } -int __devinit pci_bus_exists(const struct list_head *list, int nr) +int __devinit pci_bus_exists(const struct list_head *list, int nr) { const struct list_head *l; @@ -1392,7 +1489,7 @@ return 0; } -struct pci_bus * __devinit pci_alloc_primary_bus(int bus) +struct pci_bus * __devinit pci_alloc_primary_bus(int bus) { struct pci_bus *b; @@ -1411,7 +1508,7 @@ return b; } -struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) +struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b = pci_alloc_primary_bus(bus); if (b) { @@ -1944,7 +2041,7 @@ #endif } -static int __devinit pci_setup(char *str) +static int __devinit pci_setup(char *str) { while (str) { char *k = strchr(str, ','); @@ -1979,6 +2076,9 @@ EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); EXPORT_SYMBOL(pci_set_master); +EXPORT_SYMBOL(pci_set_mwi); +EXPORT_SYMBOL(pci_clear_mwi); +EXPORT_SYMBOL(pdev_set_mwi); EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_dac_set_dma_mask); EXPORT_SYMBOL(pci_assign_resource); @@ -1996,10 +2096,12 @@ EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); +#ifdef CONFIG_PROC_FS EXPORT_SYMBOL(pci_proc_attach_device); EXPORT_SYMBOL(pci_proc_detach_device); EXPORT_SYMBOL(pci_proc_attach_bus); EXPORT_SYMBOL(pci_proc_detach_bus); +#endif #endif EXPORT_SYMBOL(pci_set_power_state); diff -urN linux-2.4.18/drivers/pci/pci.ids linux-2.4.19-pre5/drivers/pci/pci.ids --- linux-2.4.18/drivers/pci/pci.ids Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/pci/pci.ids Sat Mar 30 22:55:40 2002 @@ -7,7 +7,7 @@ # so if you have anything to contribute, please visit the home page or # send a diff -u against the most recent pci.ids to pci-ids@ucw.cz. # -# $Id: pci.ids,v 1.24 2001/10/28 21:55:26 mares Exp $ +# $Id: pci.ids,v 1.39 2002/03/23 14:58:55 mares Exp $ # # Vendors, devices and subsystems. Please keep sorted. @@ -26,6 +26,10 @@ 0675 Dynalink 1700 IS64PH ISDN Adapter 1702 IS64PH ISDN Adapter +# Wrong ID used in subsystem ID of VIA USB controllers. +0925 VIA Technologies, Inc. (Wrong ID) +09c1 Arris + 0704 CM 200E Cable Modem 0a89 BREA Technologies Inc 0e11 Compaq Computer Corporation 0001 PCI to EISA Bridge @@ -47,7 +51,7 @@ a0f7 PCI Hotplug Controller 8086 002a PCI Hotplug Controller A 8086 002b PCI Hotplug Controller B - a0f8 USB Open Host Controller + a0f8 ZFMicro Chipset USB a0fc Fibre Channel Host Controller ae10 Smart-2/P RAID Controller 0e11 4030 Smart-2/P Array Controller @@ -69,28 +73,10 @@ ae6d NorthStar CPU to PCI Bridge b011 Integrated Netelligent 10/100 b012 Netelligent 10 T/2 - b01e NC3120 Fast Ethernet NIC - b01f NC3122 Fast Ethernet NIC b02f NC1120 Ethernet NIC b030 Netelligent WS 5100 - b04a 10/100 TX PCI Intel WOL UTP Controller b060 Smart Array 5300 Controller - b0c6 NC3161 Fast Ethernet NIC - b0c7 NC3160 Fast Ethernet NIC - b0d7 NC3121 Fast Ethernet NIC - b0dd NC3131 Fast Ethernet NIC - b0de NC3132 Fast Ethernet Module - b0df NC6132 Gigabit Module - b0e0 NC6133 Gigabit Module - b0e1 NC3133 Fast Ethernet Module - b123 NC6134 Gigabit NIC - b134 NC3163 Fast Ethernet NIC - b13c NC3162 Fast Ethernet NIC - b144 NC3123 Fast Ethernet NIC - b163 NC3134 Fast Ethernet NIC - b164 NC3135 Fast Ethernet Upgrade Module b178 Smart Array 5i/532 - b1a4 NC7131 Gigabit Server Adapter f130 NetFlex-3/P ThunderLAN 1.0 f150 NetFlex-3/P ThunderLAN 2.3 1000 LSI Logic / Symbios Logic (formerly NCR) @@ -109,6 +95,9 @@ 0e11 7004 Embedded Ultra Wide SCSI Controller 1092 8760 FirePort 40 Dual SCSI Controller 1de1 3904 DC390F Ultra Wide SCSI Controller + 0010 53c895 + 0e11 4040 Integrated Array Controller + 0e11 4048 Integrated Array Controller 0012 53c895a 0020 53c1010 Ultra3 SCSI Adapter 0021 53c1010 66MHz Ultra3 SCSI Adapter @@ -122,7 +111,11 @@ 0623 FC929 LAN 0624 FC919 0625 FC919 LAN - 0701 83C885 + 0626 FC929X + 0627 FC929X LAN + 0628 FC919X + 0629 FC919X LAN + 0701 83C885 NT50 DigitalScape Fast Ethernet 0702 Yellowfin G-NIC gigabit ethernet 1318 0000 PEI100X 0901 61C102 @@ -139,28 +132,65 @@ 9100 INI-9100/9100W SCSI Host 1002 ATI Technologies Inc 4158 68800AX [Mach32] + 4242 Radeon 8500 DV + 1002 02aa Radeon 8500 AIW DV Edition 4354 215CT [Mach64 CT] 4358 210888CX [Mach64 CX] 4554 210888ET [Mach64 ET] 4654 Mach64 VT 4742 3D Rage Pro AGP 1X/2X + 1002 0040 Rage Pro Turbo AGP 2X + 1002 0044 Rage Pro Turbo AGP 2X + 1002 0061 Rage Pro AIW AGP 2X + 1002 0062 Rage Pro AIW AGP 2X + 1002 0063 Rage Pro AIW AGP 2X + 1002 0080 Rage Pro Turbo AGP 2X + 1002 0084 Rage Pro Turbo AGP 2X + 1002 4742 Rage Pro Turbo AGP 2X + 1002 8001 Rage Pro Turbo AGP 2X + 1028 0082 Rage Pro Turbo AGP 2X 1028 4082 Optiplex GX1 Onboard Display Adapter - 8086 4152 Rage 3D Pro AGP + 1028 8082 Rage Pro Turbo AGP 2X + 1028 c082 Rage Pro Turbo AGP 2X + 8086 4152 Xpert 98D AGP 2X + 8086 464a Rage Pro Turbo AGP 2X 4744 3D Rage Pro AGP 1X + 1002 4744 Rage Pro Turbo AGP 4747 3D Rage Pro 4749 3D Rage Pro + 1002 0061 Rage Pro AIW + 1002 0062 Rage Pro AIW 474c Rage XC - 474d Rage XL AGP + 474d Rage XL AGP 2X + 1002 0004 Xpert 98 RXL AGP 2X + 1002 0008 Xpert 98 RXL AGP 2X + 1002 0080 Rage XL AGP 2X + 1002 0084 Xpert 98 AGP 2X + 1002 474d Rage XL AGP + 1033 806a Rage XL AGP 474e Rage XC AGP + 1002 474e Rage XC AGP 474f Rage XL + 1002 0008 Rage XL + 1002 474f Rage XL 4750 3D Rage Pro 215GP + 1002 0040 Rage Pro Turbo + 1002 0044 Rage Pro Turbo + 1002 0080 Rage Pro Turbo + 1002 0084 Rage Pro Turbo + 1002 4750 Rage Pro Turbo 4751 3D Rage Pro 215GQ 4752 Rage XL + 1002 0008 Rage XL + 1002 4752 Rage XL 4753 Rage XC + 1002 4753 Rage XC 4754 3D Rage I/II 215GT [Mach64 GT] 4755 3D Rage II+ 215GTB [Mach64 GTB] 4756 3D Rage IIC 215IIC [Mach64 GT IIC] + 1002 4756 Rage IIC 4757 3D Rage IIC AGP + 1002 4757 Rage IIC AGP 1028 0089 Rage 3D IIC 1028 4082 Rage 3D IIC 1028 8082 Rage 3D IIC @@ -169,77 +199,159 @@ 4759 3D Rage IIC 475a 3D Rage IIC AGP 1002 0087 Rage 3D IIC + 1002 475a Rage IIC AGP 4c42 3D Rage LT Pro AGP-133 0e11 b0e8 Rage 3D LT Pro 0e11 b10e 3D Rage LT Pro (Compaq Armada 1750) + 1002 0040 Rage LT Pro AGP 2X + 1002 0044 Rage LT Pro AGP 2X + 1002 4c42 Rage LT Pro AGP 2X + 1002 8001 Rage LT Pro AGP 2X 1028 0085 Rage 3D LT Pro 4c44 3D Rage LT Pro AGP-66 4c45 Rage Mobility M3 AGP 4c46 Rage Mobility M3 AGP 2x 4c47 3D Rage LT-G 215LG 4c49 3D Rage LT Pro + 1002 0004 Rage LT Pro + 1002 0040 Rage LT Pro + 1002 0044 Rage LT Pro + 1002 4c49 Rage LT Pro 4c4d Rage Mobility P/M AGP 2x + 1002 0084 Xpert 98 AGP 2X (Mobility) 4c4e Rage Mobility L AGP 2x 4c50 3D Rage LT Pro + 1002 4c50 Rage LT Pro 4c51 3D Rage LT Pro 4c52 Rage Mobility P/M 4c53 Rage Mobility L 4c54 264LT [Mach64 LT] - 4c57 Radeon Mobility M6 LW + 4c57 Radeon Mobility M7 LW + 1028 00e6 Radeon Mobility M7 LW (Dell Inspiron 8100) + 4c58 Radeon Mobility M6 LX 4c59 Radeon Mobility M6 LY + 104d 80e7 Vaio PCG Series video card 4c5a Radeon Mobility M6 LZ 4d46 Rage Mobility M4 AGP 4d4c Rage Mobility M4 AGP - 5041 Rage 128 PA - 5042 Rage 128 PB - 5043 Rage 128 PC - 5044 Rage 128 PD - 5045 Rage 128 PE - 5046 Rage 128 PF + 5041 Rage 128 PA/PRO + 5042 Rage 128 PB/PRO AGP 2x + 5043 Rage 128 PC/PRO AGP 4x + 5044 Rage 128 PD/PRO TMDS + 1002 0028 Rage 128 AIW + 1002 0029 Rage 128 AIW + 5045 Rage 128 PE/PRO AGP 2x TMDS + 5046 Rage 128 PF/PRO AGP 4x TMDS + 1002 0004 Rage Fury Pro + 1002 0008 Rage Fury Pro/Xpert 2000 Pro + 1002 0014 Rage Fury Pro + 1002 0018 Rage Fury Pro/Xpert 2000 Pro + 1002 0028 Rage 128 Pro AIW AGP + 1002 002a Rage 128 Pro AIW AGP + 1002 0048 Rage Fury Pro 1002 2000 Rage Fury MAXX AGP 4x (TMDS) (VGA device) 1002 2001 Rage Fury MAXX AGP 4x (TMDS) (Extra device?!) - 5047 Rage 128 PG - 5048 Rage 128 PH - 5049 Rage 128 PI - 504a Rage 128 PJ - 504b Rage 128 PK - 504c Rage 128 PL - 504d Rage 128 PM - 504e Rage 128 PN - 504f Rage 128 PO - 5050 Rage 128 PP - 5051 Rage 128 PQ - 5052 Rage 128 PR - 5053 Rage 128 PS - 5054 Rage 128 PT - 5055 Rage 128 PU - 5056 Rage 128 PV - 5057 Rage 128 PW - 5058 Rage 128 PX + 5047 Rage 128 PG/PRO + 5048 Rage 128 PH/PRO AGP 2x + 5049 Rage 128 PI/PRO AGP 4x + 504a Rage 128 PJ/PRO TMDS + 504b Rage 128 PK/PRO AGP 2x TMDS + 504c Rage 128 PL/PRO AGP 4x TMDS + 504d Rage 128 PM/PRO + 504e Rage 128 PN/PRO AGP 2x + 504f Rage 128 PO/PRO AGP 4x + 5050 Rage 128 PP/PRO TMDS + 1002 0008 Xpert 128 + 5051 Rage 128 PQ/PRO AGP 2x TMDS + 5052 Rage 128 PR/PRO AGP 4x TMDS + 5053 Rage 128 PS/PRO + 5054 Rage 128 PT/PRO AGP 2x + 5055 Rage 128 PU/PRO AGP 4x + 5056 Rage 128 PV/PRO TMDS + 5057 Rage 128 PW/PRO AGP 2x TMDS + 5058 Rage 128 PX/PRO AGP 4x TMDS 5144 Radeon QD + 1002 0008 Radeon 7000/Radeon VE + 1002 0009 Radeon 7000/Radeon + 1002 000a Radeon 7000/Radeon + 1002 001a Radeon 7000/Radeon + 1002 0029 Radeon AIW + 1002 0038 Radeon 7000/Radeon + 1002 0039 Radeon 7000/Radeon + 1002 008a Radeon 7000/Radeon + 1002 00ba Radeon 7000/Radeon + 1002 0139 Radeon 7000/Radeon + 1002 028a Radeon 7000/Radeon + 1002 02aa Radeon AIW + 1002 053a Radeon 7000/Radeon 5145 Radeon QE 5146 Radeon QF 5147 Radeon QG + 5148 Radeon R200 QH + 5149 Radeon R200 QI + 514a Radeon R200 QJ + 514b Radeon R200 QK + 514c Radeon QL + 1002 013a Radeon 8500 + 5157 Radeon 7500 QW + 1002 013a Radeon 7500 + 5158 Radeon 7500 QX 5159 Radeon VE QY + 1002 000a Radeon 7000/Radeon VE + 1002 0038 Radeon 7000/Radeon VE + 1002 003a Radeon 7000/Radeon VE + 1002 00ba Radeon 7000/Radeon VE + 1002 013a Radeon 7000/Radeon VE 515a Radeon VE QZ - 5245 Rage 128 RE - 5246 Rage 128 RF + 5168 Radeon R200 Qh + 5169 Radeon R200 Qi + 516a Radeon R200 Qj + 516b Radeon R200 Qk + 5245 Rage 128 RE/SG + 1002 0008 Xpert 128 + 1002 0028 Rage 128 AIW + 1002 0029 Rage 128 AIW + 1002 0068 Rage 128 AIW + 5246 Rage 128 RF/SG AGP + 1002 0004 Magnum/Xpert 128/Xpert 99 + 1002 0008 Magnum/Xpert128/X99/Xpert2000 + 1002 0028 Rage 128 AIW AGP + 1002 0044 Rage Fury/Xpert 128/Xpert 2000 + 1002 0068 Rage 128 AIW AGP + 1002 0448 Rage Fury 5247 Rage 128 RG - 524b Rage 128 RK - 524c Rage 128 RL - 5345 Rage 128 SE - 5346 Rage 128 SF - 5347 Rage 128 SG - 5348 Rage 128 4x - 534b Rage 128 SK - 534c Rage 128 SL - 534d Rage 128 SM - 534e Rage 128 SN + 524b Rage 128 RK/VR + 524c Rage 128 RL/VR AGP + 1002 0008 Xpert 99/Xpert 2000 + 1002 0088 Xpert 99 + 5345 Rage 128 SE/4x + 5346 Rage 128 SF/4x AGP 2x + 5347 Rage 128 SG/4x AGP 4x + 5348 Rage 128 SH + 534b Rage 128 SK/4x + 534c Rage 128 SL/4x AGP 2x + 534d Rage 128 SM/4x AGP 4x + 1002 0008 Xpert 99/Xpert 2000 + 1002 0018 Xpert 2000 + 534e Rage 128 4x 5354 Mach 64 VT 1002 5654 Mach 64 reference - 5446 Rage 128 Pro TF - 544c Rage 128 Pro TL - 5452 Rage 128 Pro TR + 5446 Rage 128 Pro Ultra TF + 1002 0004 Rage Fury Pro + 1002 0008 Rage Fury Pro/Xpert 2000 Pro + 1002 0018 Rage Fury Pro/Xpert 2000 Pro + 1002 0028 Rage 128 AIW Pro AGP + 1002 0029 Rage 128 AIW + 1002 002a Rage 128 AIW Pro AGP + 1002 002b Rage 128 AIW + 1002 0048 Xpert 2000 Pro + 544c Rage 128 Pro Ultra TL + 5452 Rage 128 Pro Ultra TR + 1002 001c Rage 128 Pro 4XL + 103c 1279 Rage 128 Pro 4XL + 5453 Rage 128 Pro Ultra TS + 5454 Rage 128 Pro Ultra TT + 5455 Rage 128 Pro Ultra TU 5654 264VT [Mach64 VT] 1002 5654 Mach64VT Reference 5655 264VT3 [Mach64 VT3] @@ -255,7 +367,7 @@ 000c 82C541 [Lynx] 000d 82C543 [Lynx] 0101 82C532 - 0102 82C534 + 0102 82C534 [Eagle] 0103 82C538 0104 82C535 0105 82C147 @@ -290,11 +402,17 @@ 0001 DP83810 0002 87415/87560 IDE 000e 87560 Legacy I/O - 000f OHCI Compliant FireWire Controller - 0011 National PCI System I/O + 000f FireWire Controller + 0011 NS87560 National PCI System I/O 0012 USB Controller 0020 DP83815 (MacPhyter) Ethernet Controller 0022 DP83820 10/100/1000 Ethernet Controller + 0500 SCx200 Bridge + 0501 SCx200 SMI + 0502 SCx200 IDE + 0503 SCx200 Audio + 0504 SCx200 Video + 0505 SCx200 XBus d001 87410 IDE 100c Tseng Labs Inc 3202 ET4000/W32p rev A @@ -305,9 +423,10 @@ 4702 ET6300 100d AST Research Inc 100e Weitek - 9000 P9000 - 9001 P9000 - 9100 P9100 + 9000 P9000 Viper + 9001 P9000 Viper + 9002 P9000 Viper + 9100 P9100 Viper Pro/SE 1010 Video Logic, Ltd. 1011 Digital Equipment Corporation 0001 DECchip 21050 @@ -360,6 +479,7 @@ 1374 0001 Cardbus Ethernet Card 10/100 1395 0001 10/100 Ethernet CardBus PC Card 8086 0001 EtherExpress PRO/100 Mobile CardBus 32 + 001a Farallon PN9000SX 0021 DECchip 21052 0022 DECchip 21150 0023 DECchip 21150 @@ -368,7 +488,11 @@ 0026 DECchip 21154 0045 DECchip 21553 0046 DECchip 21554 + 0e11 4050 Integrated Smart Array + 0e11 4051 Integrated Smart Array + 0e11 4058 Integrated Smart Array 103c 10c2 Hewlett-Packard NetRAID-4M + 12d9 000a VoIP PCI Gateway 9005 0365 Adaptec 5400S 9005 1364 Dell PowerEdge RAID Controller 2 9005 1365 Dell PowerEdge RAID Controller 2 @@ -394,7 +518,7 @@ 00d6 GD 5465 [Laguna] 00e8 GD 5436U 1100 CL 6729 - 1110 PD 6832 + 1110 PD 6832 PCMCIA/CardBus Ctrlr 1112 PD 6834 PCMCIA/CardBus Ctrlr 1113 PD 6833 PCMCIA/CardBus Ctrlr 1200 GD 7542 [Nordic] @@ -405,6 +529,8 @@ 1014 1010 CS4610 SoundFusion Audio Accelerator 6003 CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator] 1013 4280 Crystal SoundFusion PCI Audio Accelerator + 1681 0050 Hercules Game Theater XP + 6004 CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator] 6005 Crystal CS4281 PCI Audio 1013 4281 Crystal CS4281 PCI Audio 10cf 10a8 Crystal CS4281 PCI Audio @@ -424,6 +550,7 @@ 0017 CPU to PCI Bridge 0018 TR Auto LANstreamer 001b GXT-150P + 001c Carrera 001d 82G2675 0020 MCA 0022 IBM27-82351 @@ -469,6 +596,7 @@ 0144 Yotta Video Compositor Output 1014 0145 Yotta Output Controller (ytout) 0156 405GP PLB to PCI Bridge + 01a7 PCI-X to PCI-X Bridge 01bd Netfinity ServeRAID controller 01be ServeRAID-4M 01bf ServeRAID-4L @@ -497,20 +625,25 @@ c24a 90C 101e American Megatrends Inc. 1960 MegaRAID + 101e 0471 MegaRAID 471 Enterprise 1600 RAID Controller + 101e 0475 MegaRAID 475 Express 500 RAID Controller + 101e 0493 MegaRAID 493 Elite 1600 RAID Controller 1028 0471 PowerEdge RAID Controller 3/QC 1028 0493 PowerEdge RAID Controller 3/DC - 9010 MegaRAID + 9010 MegaRAID 428 Ultra RAID Controller 9030 EIDE Controller 9031 EIDE Controller 9032 EIDE & SCSI Controller 9033 SCSI Controller 9040 Multimedia card - 9060 MegaRAID + 9060 MegaRAID 434 Ultra GT RAID Controller + 9063 MegaRAC 101f PictureTel 1020 Hitachi Computer Products 1021 OKI Electric Industry Co. Ltd. 1022 Advanced Micro Devices [AMD] 2000 79c970 [PCnet LANCE] + 1014 2000 NetFinity 10/100 Fast Ethernet 103c 104c Ethernet with LAN remote power Adapter 103c 1064 Ethernet with LAN remote power Adapter 103c 1065 Ethernet with LAN remote power Adapter @@ -519,15 +652,20 @@ 103c 10ea Ethernet with LAN remote power Adapter 1113 1220 EN1220 10/100 Fast Ethernet 1259 2450 AT-2450 10/100 Fast Ethernet + 1259 2454 AT-2450v4 10Mb Ethernet Adapter 1259 2700 AT-2700TX 10/100 Fast Ethernet 1259 2701 AT-2700FX 100Mb Ethernet 2001 79c978 [HomePNA] + 1092 0a78 Multimedia Home Network Adapter + 1668 0299 ActionLink Home Network Adapter 2020 53c974 [PCscsi] 2040 79c974 7006 AMD-751 [Irongate] System Controller 7007 AMD-751 [Irongate] AGP Bridge - 700e AMD-760 [Irongate] System Controller - 700f AMD-760 [Irongate] AGP Bridge + 700c AMD-760 MP [IGD4-2P] System Controller + 700d AMD-760 MP [IGD4-2P] AGP Bridge + 700e AMD-760 [IGD4-1P] System Controller + 700f AMD-760 [IGD4-1P] AGP Bridge 7400 AMD-755 [Cobra] ISA 7401 AMD-755 [Cobra] IDE 7403 AMD-755 [Cobra] ACPI @@ -536,15 +674,28 @@ 7409 AMD-756 [Viper] IDE 740b AMD-756 [Viper] ACPI 740c AMD-756 [Viper] USB - 7410 AMD-765 [Viper] ISA - 7411 AMD-765 [Viper] IDE - 7413 AMD-765 [Viper] ACPI - 7414 AMD-765 [Viper] USB - 7440 AMD-768 [??] ISA - 7441 AMD-768 [??] IDE - 7443 AMD-768 [??] ACPI - 7448 AMD-768 [??] PCI - 7449 AMD-768 [??] USB + 7410 AMD-766 [ViperPlus] ISA + 7411 AMD-766 [ViperPlus] IDE + 7413 AMD-766 [ViperPlus] ACPI + 7414 AMD-766 [ViperPlus] USB + 7440 AMD-768 [Opus] ISA + 1043 8044 Asus A7M-D motherboard ISA bridge + 7441 AMD-768 [Opus] IDE + 7443 AMD-768 [Opus] ACPI + 1043 8044 Asus A7M-D motherboard + 7448 AMD-768 [Opus] PCI + 7449 AMD-768 [Opus] USB + 7454 AMD-8151 System Controller + 7455 AMD-8151 AGP Bridge + 7460 AMD-8111 PCI + 7461 AMD-8111 USB + 7462 AMD-8111 Ethernet + 7468 AMD-8111 LPC + 7469 AMD-8111 IDE + 746a AMD-8111 SMBus 2.0 + 746b AMD-8111 ACPI + 746d AMD-8111 AC97 Audio + 756b AMD-8111 ACPI 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -557,6 +708,7 @@ 8520 CyberBlade i1 0e11 b16e CyberBlade i1 AGP 1023 8520 CyberBlade i1 AGP + 8820 CyberBlade XPAi1 9320 TGUI 9320 9350 GUI Accelerator 9360 Flat panel GUI Accelerator @@ -580,7 +732,7 @@ 9682 TGUI 9682 9683 TGUI 9683 9685 ProVIDIA 9685 - 9750 3DIm`age 975 + 9750 3DImage 9750 1014 9750 3DImage 9750 1023 9750 3DImage 9750 9753 TGUI 9753 @@ -620,6 +772,7 @@ 1621 M1621 Northbridge [Aladdin-Pro II] 1631 M1631 Northbridge+3D Graphics [Aladdin TNT2] 1641 M1641 Northbridge [Aladdin-Pro IV] + 1647 M1647 [MaGiK1] PCI North Bridge 3141 M3141 3143 M3143 3145 M3145 @@ -629,26 +782,26 @@ 3307 M3307 MPEG-I Video Controller 3309 M3309 MPEG-II Video w/ Software Audio Decoder 3321 M3321 MPEG-II Audio/Video Decoder - 5212 ALI M4803 + 5212 M4803 5215 ALI PCI EIDE Controller 5217 M5217H 5219 M5219 5225 M5225 5229 M5229 5235 M5235 - 5237 ALI M5237 PCI USB Host Controller + 5237 M5237 PCI USB Host Controller 5240 EIDE Controller 5241 PCMCIA Bridge 5242 General Purpose Controller 5243 PCI to PCI Bridge Controller 5244 Floppy Disk Controller - 5247 ALI M1541 PCI to PCI Bridge - 5251 M5251 P1394 OHCI Controller - 5427 ALI PCI to AGP Bridge - 5451 ALI M5451 PCI AC-Link Controller Audio Device - 5453 ALI M5453 PCI AC-Link Controller Modem Device - 7101 ALI M7101 PCI PMU Power Management Controller - 10b9 7101 ALI M7101 PCI PMU Power Management Controller + 5247 M1541 PCI to PCI Bridge + 5251 M5251 P1394 Controller + 5427 PCI to AGP Bridge + 5451 M5451 PCI AC-Link Controller Audio Device + 5453 M5453 PCI AC-Link Controller Modem Device + 7101 M7101 PCI PMU Power Management Controller + 10b9 7101 M7101 PCI PMU Power Management Controller 1028 Dell Computer Corporation 0001 PowerEdge Expandable RAID Controller 2/Si 0002 PowerEdge Expandable RAID Controller 3/Di @@ -656,8 +809,10 @@ 0004 PowerEdge Expandable RAID Controller 3/Si 0005 PowerEdge Expandable RAID Controller 3/Di 0006 PowerEdge Expandable RAID Controller 3/Di + 0007 Remote Assitant Card 3 0008 PowerEdge Expandable RAID Controller 3/Di 000a PowerEdge Expandable RAID Controller 3/Di + 000c Embedded Systems Management Device 4 1029 Siemens Nixdorf IS 102a LSI Logic 0000 HYDRA @@ -698,9 +853,23 @@ 102b ca6c Millennium G250 AGP 102b dbbc Millennium G200 AGP 102b dbc2 Millennium G200 MMS (Dual G200) + 102b dbc3 G200 Multi-Monitor 102b dbc8 Millennium G200 MMS (Dual G200) + 102b dbd2 G200 Multi-Monitor + 102b dbd3 G200 Multi-Monitor + 102b dbd4 G200 Multi-Monitor + 102b dbd5 G200 Multi-Monitor + 102b dbd8 G200 Multi-Monitor + 102b dbd9 G200 Multi-Monitor 102b dbe2 Millennium G200 MMS (Quad G200) + 102b dbe3 G200 Multi-Monitor 102b dbe8 Millennium G200 MMS (Quad G200) + 102b dbf2 G200 Multi-Monitor + 102b dbf3 G200 Multi-Monitor + 102b dbf4 G200 Multi-Monitor + 102b dbf5 G200 Multi-Monitor + 102b dbf8 G200 Multi-Monitor + 102b dbf9 G200 Multi-Monitor 102b f806 Mystique G200 Video AGP 102b ff00 MGA-G200 AGP 102b ff02 Mystique G200 AGP @@ -708,16 +877,18 @@ 102b ff04 Marvel G200 AGP 110a 0032 MGA-G200 AGP 0525 MGA G400 AGP - 0e11 b16f Matrox MGA-G400 AGP + 0e11 b16f MGA-G400 AGP 102b 0328 Millennium G400 16Mb SDRAM 102b 0338 Millennium G400 16Mb SDRAM 102b 0378 Millennium G400 32Mb SDRAM 102b 0541 Millennium G450 Dual Head 102b 0542 Millennium G450 Dual Head LX - 102b 0641 Millennium G450 32Mb SDRAM + 102b 0543 Millennium G450 Single Head LX + 102b 0641 Millennium G450 32Mb SDRAM Dual Head 102b 0642 Millennium G450 32Mb SDRAM Dual Head LX + 102b 0643 Millennium G450 32Mb SDRAM Single Head LX 102b 07c0 Millennium G450 Dual Head LE - 102b 07c1 Millennium G450 SDR Dual Head + 102b 07c1 Millennium G450 SDR Dual Head LE 102b 0d41 Millennium G450 Dual Head PCI 102b 0d42 Millennium G450 Dual Head LX PCI 102b 0e00 Marvel G450 eTV @@ -733,11 +904,24 @@ 102b 2159 Millennium G400 Dual Head 16Mb 102b 2179 Millennium G400 MAX/Dual Head 32Mb 102b 217d Millennium G400 Dual Head Max + 102b 23c0 Millennium G450 + 102b 23c1 Millennium G450 + 102b 23c2 Millennium G450 DVI + 102b 23c3 Millennium G450 DVI 102b 2f58 Millennium G400 102b 2f78 Millennium G400 102b 3693 Marvel G400 AGP - 1705 0001 Millennium G450 32MB SGRAM - b16f 0e11 Matrox MGA-G400 AGP + 102b 5dd0 4Sight II + 102b 5f50 4Sight II + 102b 5f51 4Sight II + 102b 5f52 4Sight II + 102b 9010 Millennium G400 Dual Head + 1458 0400 GA-G400 + 1705 0001 Digital First Millennium G450 32MB SGRAM + 1705 0002 Digital First Millennium G450 16MB SGRAM + 1705 0003 Digital First Millennium G450 32MB + 1705 0004 Digital First Millennium G450 16MB + b16f 0e11 MGA-G400 AGP 0d10 MGA Ultima/Impression 1000 MGA G100 [Productiva] 102b ff01 Productiva G100 @@ -752,12 +936,15 @@ 110a 001e MGA-G100 AGP 2007 MGA Mistral 2527 MGA G550 AGP + 102b 0f83 Millennium G550 102b 0f84 Millennium G550 Dual Head DDR 32Mb + 102b 1e41 Millennium G550 4536 VIA Framegrabber 6573 Shark 10/100 Multiport SwitchNIC 102c Chips and Technologies 00b8 F64310 00c0 F69000 HiQVideo + 102c 00c0 F69000 HiQVideo 00d0 F65545 00d8 F65545 00dc F65548 @@ -796,6 +983,7 @@ 0029 PowerVR PCX1 002a PowerVR 3D 0035 USB + 12ee 7000 Root Hub 003e NAPCCARD Cardbus Controller 0046 PowerVR PCX2 [midas] 005a Vrc5074 [Nile 4] @@ -812,6 +1000,11 @@ 0074 56k Voice Modem 1033 8014 RCV56ACF 56k Voice Modem 009b Vrc5476 + 00a6 VRC5477 AC97 + 00cd IEEE 1394 [OrangeLink] Host Controller + 12ee 8011 Root hub + 00e0 USB 2.0 + 12ee 7001 Root hub 1034 Framatome Connectors USA Inc. 1035 Comp. & Comm. Research Lab 1036 Future Domain Corp. @@ -870,8 +1063,9 @@ 1092 4920 SpeedStar A70 1569 6326 SiS6326 GUI Accelerator 7001 7001 - 7007 OHCI Compliant FireWire Controller + 7007 FireWire Controller 7012 SiS7012 PCI Audio Accelerator + 7013 56k Winmodem (Smart Link HAMR5600 compatible) 7016 SiS7016 10/100 Ethernet Adapter 1039 7016 SiS7016 10/100 Ethernet Adapter 7018 SiS PCI Audio Accelerator @@ -901,8 +1095,17 @@ 103b Tatung Co. of America 103c Hewlett-Packard Company 1005 A4977A Visualize EG - 1030 J2585A - 1031 J2585B + 1028 Tach TL Fibre Channel Host Adapter + 1029 Tach XL2 Fibre Channel Host Adapter + 107e 000f Interphase 5560 Fibre Channel Adapter + 9004 9210 1Gb/2Gb Family Fibre Channel Controller + 9004 9211 1Gb/2Gb Family Fibre Channel Controller + 102a Tach TS Fibre Channel Host Adapter + 107e 000e Interphase 5540/5541 Fibre Channel Adapter + 9004 9110 1Gb/2Gb Family Fibre Channel Controller + 9004 9111 1Gb/2Gb Family Fibre Channel Controller + 1030 J2585A DeskDirect 10/100VG NIC + 1031 J2585B HP 10/100VG PCI LAN Adapter 103c 1040 J2973A DeskDirect 10BaseT NIC 103c 1041 J2585B DeskDirect 10/100VG NIC 103c 1042 J2970A DeskDirect 10BaseT/2 NIC @@ -917,8 +1120,8 @@ 121a NetServer SMIC Controller 121b NetServer Legacy COM Port Decoder 121c NetServer PCI COM Port Decoder - 2910 E2910A - 2925 E2925A + 2910 E2910A PCIBus Exerciser + 2925 E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer 103e Solliday Engineering 103f Synopsys/Logic Modeling Group 1040 Accelgraphics Inc. @@ -930,11 +1133,49 @@ 3010 Samurai_1 3020 Samurai_IDE 1043 Asustek Computer, Inc. + 0675 ISDNLink P-IN100-ST-D + 4057 V8200 GeForce 3 1044 Distributed Processing Technology 1012 Domino RAID Engine a400 SmartCache/Raid I-IV Controller a500 PCI Bridge a501 SmartRAID V Controller + 1044 c001 PM1554U2 Ultra2 Single Channel + 1044 c002 PM1654U2 Ultra2 Single Channel + 1044 c003 PM1564U3 Ultra3 Single Channel + 1044 c004 PM1564U3 Ultra3 Dual Channel + 1044 c005 PM1554U2 Ultra2 Single Channel (NON ACPI) + 1044 c00a PM2554U2 Ultra2 Single Channel + 1044 c00b PM2654U2 Ultra2 Single Channel + 1044 c00c PM2664U3 Ultra3 Single Channel + 1044 c00d PM2664U3 Ultra3 Dual Channel + 1044 c00e PM2554U2 Ultra2 Single Channel (NON ACPI) + 1044 c00f PM2654U2 Ultra2 Single Channel (NON ACPI) + 1044 c014 PM3754U2 Ultra2 Single Channel (NON ACPI) + 1044 c015 PM3755U2B Ultra2 Single Channel (NON ACPI) + 1044 c016 PM3755F Fibre Channel (NON ACPI) + 1044 c01e PM3757U2 Ultra2 Single Channel + 1044 c01f PM3757U2 Ultra2 Dual Channel + 1044 c020 PM3767U3 Ultra3 Dual Channel + 1044 c021 PM3767U3 Ultra3 Quad Channel + 1044 c028 PM2865U3 Ultra3 Single Channel + 1044 c029 PM2865U3 Ultra3 Dual Channel + 1044 c02a PM2865F Fibre Channel + 1044 c03c 2000S Ultra3 Single Channel + 1044 c03d 2000S Ultra3 Dual Channel + 1044 c03e 2000F Fibre Channel + 1044 c046 3000S Ultra3 Single Channel + 1044 c047 3000S Ultra3 Dual Channel + 1044 c048 3000F Fibre Channel + 1044 c050 5000S Ultra3 Single Channel + 1044 c051 5000S Ultra3 Dual Channel + 1044 c052 5000F Fibre Channel + 1044 c05a 2400A UDMA Four Channel + 1044 c05b 2400A UDMA Four Channel DAC + 1044 c064 3010S Ultra3 Dual Channel + 1044 c065 3010S Ultra3 Four Channel + 1044 c066 3010S Fibre Channel + a511 SmartRAID V Controller 1045 OPTi Inc. a0f8 82C750 [Vendetta] USB Controller c101 92C264 @@ -966,7 +1207,9 @@ 104a SGS Thomson Microelectronics 0008 STG 2000X 0009 STG 1764X + 0981 DEC-Tulip compatible 10/100 Ethernet 1746 STG 1764X + 2774 DEC-Tulip compatible 10/100 Ethernet 3520 MPEG-II decoder card 104b BusLogic 0140 BT-946C (old) [multimaster 01] @@ -978,6 +1221,13 @@ 1000 Eagle i/f AS 3d04 TVP4010 [Permedia] 3d07 TVP4020 [Permedia 2] + 1011 4d10 Comet + 1040 000f AccelStar II + 1040 0011 AccelStar II + 1048 0a31 WINNER 2000 + 1048 0a32 GLoria Synergy + 1048 0a35 GLoria Synergy + 107d 2633 WinFast 3D L2300 1092 0127 FIRE GL 1000 PRO 1092 0136 FIRE GL 1000 PRO 1092 0141 FIRE GL 1000 PRO @@ -990,15 +1240,26 @@ 1092 0156 FIRE GL 1000 PRO 1092 0157 FIRE GL 1000 PRO 1097 3d01 Jeronimo Pro + 1102 100f Graphics Blaster Extreme 3d3d 0100 Reference Permedia 2 3D 8000 PCILynx/PCILynx2 IEEE 1394 Link Layer Controller e4bf 1010 CF1-1-SNARE e4bf 1020 CF1-2-SNARE - 8009 OHCI Compliant FireWire Controller - 8019 TSB12LV23 OHCI Compliant IEEE-1394 Controller + 8009 FireWire Controller + 104d 8032 8032 OHCI i.LINK (IEEE 1394) Controller + 8017 PCI4410 FireWire Controller + 8019 TSB12LV23 IEEE-1394 Controller 11bd 000a Studio DV500-1394 11bd 000e Studio DV e4bf 1010 CF2-1-CYMBAL + 8020 TSB12LV26 IEEE-1394 Controller (Link) + 8021 TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated) + 104d 80e7 Notebook Computer Vaio PCG Series + 8022 TSB43AB22 IEEE-1394 Controller (PHY/Link) 1394a-2000 + 8024 TSB43AB23 IEEE-1394 Controller (PHY/Link) 1394a-2000 + 8026 TSB43AB21 IEEE-1394 Controller (PHY/Link) 1394a-2000 + 8027 PCI4451 IEEE-1394 Controller + 1028 00e6 PCI4451 IEEE-1394 Controller (Dell Inspiron 8100) a001 TDC1570 a100 TDC1561 ac10 PCI1050 @@ -1017,10 +1278,12 @@ ac1e PCI1211 ac1f PCI1251B ac20 TI 2030 + ac21 PCI2031 ac30 PCI1260 PC card Cardbus Controller ac40 PCI4450 PC card Cardbus Controller ac41 PCI4410 PC card Cardbus Controller ac42 PCI4451 PC card Cardbus Controller + 1028 00e6 PCI4451 PC card CardBus Controller (Dell Inspiron 8100) ac50 PCI1410 PC card Cardbus Controller ac51 PCI1420 ac52 PCI1451 PC card Cardbus Controller @@ -1032,6 +1295,7 @@ 8039 CXD3222 i.LINK Controller 8056 Rockwell HCF 56K modem 808a Memory Stick Controller + 80e7 Vaio PCG-GR114MK 104e Oak Technology, Inc 0017 OTI-64017 0107 OTI-107 [Spitfire] @@ -1057,7 +1321,7 @@ 1055 EFAR Microsystems 9130 EIDE Controller 9460 PCI to ISA Bridge - 9462 USB Universal Host Controller [OHCI] + 9462 USB Universal Host Controller 9463 Power Management Controller [Bridge] 1056 ICL # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this. @@ -1095,13 +1359,24 @@ 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. 0d30 20265 + 105a 4d33 Ultra100 + 0d38 20263 + 105a 4d39 Fasttrak66 4d30 20267 + 105a 4d33 Ultra100 + 105a 4d39 Fasttrak100 4d33 20246 4d38 20262 + 105a 4d30 Ultra Device on SuperTrak + 105a 4d33 Ultra66 + 105a 4d39 Fasttrak66 4d68 20268 - 6268 20268R + 105a 4d68 Ultra100TX2 4d69 20269 + 5275 PDC20276 IDE + 105a 0275 SuperTrak SX6000 IDE 5300 DC5300 + 6268 20268R 105b Foxconn International, Inc. 105c Wipro Infotech Limited 105d Number 9 Computer Company @@ -1166,7 +1441,9 @@ 0001 DAC960P 0002 DAC960PD 0010 DAC960PX - ba55 eXtremeRAID support Device + 0050 AcceleRAID 352/170/160 support Device + ba55 eXtremeRAID 1100 support Device + ba56 eXtremeRAID 2000/3000 support Device 106a Aten Research Inc 106b Apple Computer Inc. 0001 Bandit PowerPC host bridge @@ -1237,19 +1514,21 @@ 1075 Advanced Integrations Research 1076 Chaintech Computer Co. Ltd 1077 QLogic Corp. - 1016 QLA10160 - 1020 ISP1020 - 1022 ISP1022 - 1080 QLA1080 - 1216 QLA12160 + 1016 ISP10160 Single Channel Ultra3 SCSI Processor + 1020 ISP1020 Fast-wide SCSI + 1022 ISP1022 Fast-wide SCSI + 1080 ISP1080 SCSI Host Adapter + 1216 ISP12160 Dual Channel Ultra3 SCSI Processor 101e 8471 QLA12160 on AMI MegaRAID 101e 8493 QLA12160 on AMI MegaRAID - 1240 QLA1240 - 1280 QLA1280 - 2020 ISP2020A - 2100 QLA2100 + 1240 ISP1240 SCSI Host Adapter + 1280 ISP1280 + 2020 ISP2020A Fast!SCSI Basic Adapter + 2100 QLA2100 64-bit Fibre Channel Adapter + 1077 0001 QLA2100 64-bit Fibre Channel Adapter 2200 QLA2200 - 2300 QLA2300 + 2300 QLA2300 64-bit FC-AL Adapter + 2312 QLA2312 Fibre Channel Adapter 1078 Cyrix Corporation 0000 5510 [Grappa] 0001 PCI Master @@ -1259,6 +1538,10 @@ 0102 5530 IDE [Kahlua] 0103 5530 Audio [Kahlua] 0104 5530 Video [Kahlua] + 0400 ZFMicro PCI Bridge + 0401 ZFMicro Chipset SMI + 0402 ZFMicro Chipset IDE + 0403 ZFMicro Expansion Bus 1079 I-Bus 107a NetWorth 107b Gateway 2000 @@ -1266,9 +1549,22 @@ 107d LeadTek Research Inc. 0000 P86C850 107e Interphase Corporation - 0001 ATM Interface Card + 0001 5515 ATM Adapter [Flipper] 0002 100 VG AnyLan Controller - 0008 155 Mbit ATM Controller + 0004 5526 Fibre Channel Host Adapter + 0005 x526 Fibre Channel Host Adapter + 0008 5525/5575 ATM Adapter (155 Mbit) [Atlantic] + 9003 5535-4P-BRI-ST + 9007 5535-4P-BRI-U + 9008 5535-1P-SR + 900c 5535-1P-SR-ST + 900e 5535-1P-SR-U + 9011 5535-1P-PRI + 9013 5535-2P-PRI + 9023 5536-4P-BRI-ST + 9027 5536-4P-BRI-U + 9031 5536-1P-PRI + 9033 5536-2P-PRI 107f Data Technology Corporation 0802 SL82C105 1080 Contaq Microsystems @@ -1341,6 +1637,7 @@ 00a8 Speedstar 64 0550 Viper V550 08d4 Supra 2260 Modem + 094c SupraExpress 56i Pro 1092 Viper V330 6120 Maximum DVD 8810 Stealth SE @@ -1384,6 +1681,9 @@ 0647 PCI0647 0648 PCI0648 0649 PCI0649 + 0e11 005d Integrated Ultra ATA-100 Dual Channel Controller + 0e11 007e Integrated Ultra ATA-100 IDE RAID Controller + 101e 0649 AMI MegaRAID IDE 100 Controller 0650 PBC0650A 0670 USB0670 0673 USB0673 @@ -1405,6 +1705,7 @@ 13e9 0070 Win/TV (Video Section) 036e Bt878 0070 13eb WinTV/GO + 0070 ff01 Viewcast Osprey 200 127a 0001 Bt878 Mediastream Controller NTSC 127a 0002 Bt878 Mediastream Controller PAL BG 127a 0003 Bt878a Mediastream Controller PAL BG @@ -1453,6 +1754,7 @@ 1852 1852 FlyVideo'98 (with FM Tuner) 0878 Bt878 0070 13eb WinTV/GO + 0070 ff01 Viewcast Osprey 200 127a 0001 Bt878 Video Capture (Audio Section) 127a 0002 Bt878 Video Capture (Audio Section) 127a 0003 Bt878 Video Capture (Audio Section) @@ -1560,9 +1862,25 @@ 0001 i960 PCI bus interface 1076 VScom 800 8 port serial adaptor 1077 VScom 400 4 port serial adaptor + 1078 VScom 210 2 port serial and 1 port parallel adaptor + 1103 VScom 200 2 port serial adaptor + 1146 VScom 010 1 port parallel adaptor + 1147 VScom 020 2 port parallel adaptor + 9030 PCI <-> IOBus Bridge Hot Swap + 15ed 1002 MCCS 8-port Serial Hot Swap + 15ed 1003 MCCS 16-port Serial Hot Swap 9036 9036 9050 PCI <-> IOBus Bridge 10b5 2273 SH-ARC SoHard ARCnet card + 1522 0001 RockForce 4 Port V.90 Data/Fax/Voice Modem + 1522 0002 RockForce 2 Port V.90 Data/Fax/Voice Modem + 1522 0010 RockForce2000 4 Port V.90 Data/Fax/Voice Modem + 1522 0020 RockForce2000 2 Port V.90 Data/Fax/Voice Modem + 15ed 1000 Macrolink MCCS 8-port Serial + 15ed 1001 Macrolink MCCS 16-port Serial + 15ed 1002 Macrolink MCCS 8-port Serial Hot Swap + 15ed 1003 Macrolink MCCS 16-port Serial Hot Swap + d531 c002 PCIntelliCAN 2xSJA1000 CAN bus d84d 4006 EX-4006 1P d84d 4008 EX-4008 1P EPP/ECP d84d 4014 EX-4014 2P @@ -1586,6 +1904,7 @@ 906e 9060ES 9080 9080 10b5 9080 9080 [real subsystem ID not set] + 129d 0002 Aculab PCI Prosidy card a001 GTEK Jetport II 2 port serial adaptor c001 GTEK Cyclone 16/32 port serial adaptor 10b6 Madge Networks @@ -1607,14 +1926,19 @@ 000a Smart 100/16/4 PCI Ringnode 10b6 000a Smart 100/16/4 PCI Ringnode 000b 16/4 CardBus Adapter Mk2 + 10b6 0008 16/4 CardBus Adapter Mk2 10b6 000b 16/4 Cardbus Adapter Mk2 - 1000 Collage 25 ATM Adapter + 000c RapidFire 3140V2 16/4 TR Adapter + 10b6 000c RapidFire 3140V2 16/4 TR Adapter + 1000 Collage 25/155 ATM Client Adapter 1001 Collage 155 ATM Server Adapter 10b7 3Com Corporation - 0001 3c985 1000BaseSX - 3390 Token Link Velocity + 0001 3c985 1000BaseSX (SX/TX) + 1007 Mini PCI 56k Winmodem + 10b7 615c Mini PCI 56K Modem + 3390 3c339 TokenLink Velocity 3590 3c359 TokenLink Velocity XL - 10b7 3590 TokenLink Velocity XL Adapter + 10b7 3590 TokenLink Velocity XL Adapter (3C359/359B) 4500 3c450 Cyclone/unknown 5055 3c555 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus @@ -1622,6 +1946,7 @@ 5157 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5257 3CCFE575CT Cyclone CardBus + 10b7 5c57 FE575C-3Com 10/100 LAN CardBus-Fast Ethernet 5900 3c590 10BaseT [Vortex] 5920 3c592 EISA 10mbps Demon/Vortex 5950 3c595 100BaseTX [Vortex] @@ -1632,10 +1957,20 @@ 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 6055 3c556 Hurricane CardBus 6056 3c556B Hurricane CardBus + 10b7 6556 10/100 Mini PCI Ethernet Adapter 6560 3CCFE656 Cyclone CardBus + 10b7 656a 3CCFEM656 10/100 LAN 56K Modem CardBus + 6561 3CCFEM656 10/100 LAN 56K Modem CardBus + 10b7 656b 3CCFEM656 10/100 LAN 56K Modem CardBus 6562 3CCFEM656 [id 6562] Cyclone CardBus + 10b7 656b 3CCFEM656B 10/100 LAN 56K Modem CardBus + 6563 3CCFEM656B 10/100 LAN 56K Modem CardBus + 10b7 656b 3CCFEM656 10/100 LAN 56K Modem CardBus 6564 3CCFEM656 [id 6564] Cyclone CardBus 7646 3cSOHO100-TX Hurricane + 7940 3c803 FDDILink UTP Controller + 7980 3c804 FDDILink SAS Controller + 7990 3c805 FDDILink DAS Controller 8811 Token ring 9000 3c900 10BaseT [Boomerang] 9001 3c900 Combo [Boomerang] @@ -1646,7 +1981,7 @@ 9006 3c900B-TPC [Etherlink XL TPC] 900a 3c900B-FL [Etherlink XL FL] 9050 3c905 100BaseTX [Boomerang] - 9051 3c905 100BaseT4 + 9051 3c905 100BaseT4 [Boomerang] 9055 3c905B 100BaseTX [Cyclone] 1028 0080 3C905B Fast Etherlink XL 10/100 1028 0081 3C905B Fast Etherlink XL 10/100 @@ -1669,19 +2004,26 @@ 1028 0098 3C905B Fast Etherlink XL 10/100 1028 0099 3C905B Fast Etherlink XL 10/100 10b7 9055 3C905B Fast Etherlink XL 10/100 - 9056 3c905B-T4 + 9056 3c905B-T4 [Fast EtherLink XL 10/100] 9058 3c905B-Combo [Deluxe Etherlink XL 10/100] 905a 3c905B-FX [Fast Etherlink XL FX 10/100] - 9200 3c905C-TX [Fast Etherlink] + 9200 3c905C-TX/TX-M [Tornado] 10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC + 10b7 7000 10/100 Mini PCI Ethernet Adapter 9800 3c980-TX [Fast Etherlink XL Server Adapter] 10b7 9800 3c980-TX Fast Etherlink XL Server Adapter 9805 3c980-TX 10/100baseTX NIC [Python-T] + 10b7 1201 3c982-TXM 10/100baseTX Dual Port A [Hydra] + 10b7 1202 3c982-TXM 10/100baseTX Dual Port B [Hydra] 10b7 9805 3c980 10/100baseTX NIC [Python-T] + 9902 3CR990-TX-95 56-bit Typhoon Client + 9903 3CR990-TX-97 168-bit Typhoon Client + 9908 3CR990SVR95 56-bit Typhoon Server + 9909 3CR990SVR97 Typhoon Server 10b8 Standard Microsystems Corp [SMC] 0005 83C170QF - 1055 e000 LANEPIC - 1055 e002 LANEPIC + 1055 e000 LANEPIC 10/100 [EVB171Q-PCI] + 1055 e002 LANEPIC 10/100 [EVB171G-PCI] 10b8 a011 EtherPower II 10/100 10b8 a014 EtherPower II 10/100 10b8 a015 EtherPower II 10/100 @@ -1723,7 +2065,13 @@ 1543 M1543 1621 M1621 1631 ALI M1631 PCI North Bridge Aladdin Pro III + 1632 M1632M Northbridge+Trident 1641 ALI M1641 PCI North Bridge Aladdin Pro IV + 1644 M1644/M1644T Northbridge+Trident + 1646 M1646 Northbridge+Trident + 1647 M1647 Northbridge [MAGiK 1 / MobileMAGiK 1] + 1651 M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM] + 1671 M1671 Northbridge [Aladdin-P4] 3141 M3141 3143 M3143 3145 M3145 @@ -1738,11 +2086,21 @@ 5219 M5219 5225 M5225 5229 M5229 IDE + 1043 8053 A7A66 Motherboard IDE 5235 M5225 - 5237 M5237 USB - 5243 M5243 - 5247 M5247 - 5451 M5451 PCI South Bridge Audio + 5237 USB 1.1 Controller + 5239 USB 2.0 Controller + 5243 M1541 PCI to AGP Controller + 5247 PCI to AGP Controller + 5251 M5251 P1394 OHCI 1.0 Controller + 5253 M5253 P1394 OHCI 1.1 Controller + 5261 M5261 Ethernet Controller + 5451 M5451 PCI AC-Link Controller Audio Device + 5453 M5453 PCI AC-Link Controller Modem Device + 5455 M5455 PCI AC-Link Controller Audio Device + 5457 M5457 AC-Link Modem Interface Controller + 5471 M5471 Memory Stick Controller + 5473 M5473 SD-MMC Controller 7101 M7101 PMU 10b9 7101 ALI M7101 Power Management Controller 10ba Mitsubishi Electric Corp. @@ -1804,6 +2162,7 @@ 110a 8005 MagicMedia 256AV Audio Device 14c0 0004 MagicMedia 256AV Audio Device 8006 NM2360 [MagicMedia 256ZX Audio] + 8016 NM2360 [MagicMedia 256ZX Audio] 10c9 Dataexpert Corporation 10ca Fujitsu Microelectr., Inc. 10cb Omron Corporation @@ -1830,6 +2189,7 @@ 10d9 Macronix, Inc. [MXIC] 0512 MX98713 0531 MX987x5 + 1186 1200 DFE-540TX ProFAST 10/100 Adapter 8625 MX86250 8888 MX86200 10da Compaq IPG-Austin @@ -1907,12 +2267,13 @@ 002f Vanta [NV6] 00a0 Riva TNT2 14af 5810 Maxi Gamer Xentor - 0100 GeForce 256 + 0100 NV10 (GeForce 256) 1043 0200 AGP-V6600 SGRAM 1043 0201 AGP-V6600 SDRAM 1043 4008 AGP-V6600 SGRAM 1043 4009 AGP-V6600 SDRAM 1102 102d CT6941 GeForce 256 + 14af 5022 3D Prophet SE 0101 GeForce 256 DDR 1043 0202 AGP-V6800 DDR 1043 400a AGP-V6800 DDR SGRAM @@ -1921,16 +2282,43 @@ 14af 5021 3D Prophet DDR-DVI 0103 Quadro (GeForce 256 GL) 0110 NV11 (GeForce2 MX) + 1043 4015 AGP-7100 Pro with TV output + 1043 4031 V7100 Pro with TV output 0111 NV11 (GeForce2 MX DDR) 0112 GeForce2 Go 0113 NV11 (GeForce2 MXR) 0150 NV15 (GeForce2 Pro) + 1043 4016 V7700 AGP Video Card 107d 2840 WinFast GeForce2 GTS with TV output + 1462 8831 Creative GeForce2 Pro 0151 NV15 DDR (GeForce2 GTS) 0152 NV15 Bladerunner (GeForce2 Ultra) 0153 NV15 GL (Quadro2 Pro) + 0170 NV1x + 0171 NV1x + 0172 NV1x + 0173 NV1x + 0174 NV1x + 0175 NV1x + 0176 GeForce4 420 Go 32M + 0178 NV1x + 0179 GeForce4 440 Go 64M + 017a NV1x + 017b NV1x + 017c NV1x + 01a0 GeForce2 Integrated GPU + 01bc nForce IDE 0200 NV20 (GeForce3) + 1043 402f AGP-V8200 DDR + 0201 GeForce3 Ti200 + 0202 GeForce3 Ti500 + 1043 405b V8200 T5 0203 Quadro DCC + 0250 NV25 (GeForce 4) + 0251 GeForce4 Ti 4400 + 0253 GeForce4 Ti 4200 + 0258 NV25 (GeForce 4) + 025b NV25 (GeForce 4) 10df Emulex Corporation 10df Light Pulse Fibre Channel Adapter 1ae5 LP6000 Fibre Channel Host Adapter @@ -1962,14 +2350,15 @@ 8043 LANai4.x [Myrinet LANai interface chip] 8062 S5933_PARASTATION 807d S5933 [Matchmaker] - 8088 Kingsberg Spacetec Format Synchronizer - 8089 Kingsberg Spacetec Serial Output Board + 8088 Kongsberg Spacetec Format Synchronizer + 8089 Kongsberg Spacetec Serial Output Board 809c S5933_HEPC3 80d7 PCI-9112 80d9 PCI-9118 80da PCI-9812 811a PCI-IEEE1355-DS-DE Interface 8170 S5933 [Matchmaker] (Chipset Development Tool) + 82db AJA HDNTV HD SDI Framestore 10e9 Alps Electric Co., Ltd. 10ea Intergraphics Systems 1680 IGA-1680 @@ -1993,7 +2382,7 @@ 10ec 8129 RT8129 Fast Ethernet Adapter 8138 RT8139 (B/C) Cardbus Fast Ethernet Adapter 10ec 8138 RT8139 (B/C) Fast Ethernet Adapter - 8139 RTL-8139 + 8139 RTL-8139/8139C 1025 8920 ALN-325 1025 8921 ALN-325 10bd 0320 EP-320X-R @@ -2037,6 +2426,8 @@ 000c TARGA 1000 10fb Thesys Gesellschaft für Mikroelektronik mbH 10fc I-O Data Device, Inc. +# What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives + 0003 Cardbus IDE Controller 10fd Soyo Computer, Inc 10fe Fast Multimedia AG 10ff NCube @@ -2062,18 +2453,26 @@ 1102 8031 CT4831 SBLive! Value 1102 8040 CT4760 SBLive! 1102 8051 CT4850 SBLive! Value - 7002 SB Live! + 0004 SB Audigy + 4001 SB Audigy FireWire Port + 7002 SB Live! MIDI/Game Port 1102 0020 Gameport Joystick + 7003 SB Audigy MIDI/Game port 8938 ES1371 1103 Triones Technologies, Inc. 0003 HPT343 0004 HPT366 / HPT370 1103 0005 HPT370 UDMA100 +# Not HPT370A, It's HPT370. I don't know what ID HPT370A has. + 0005 HPT370 1104 RasterOps Corp. 1105 Sigma Designs, Inc. 8300 REALmagic Hollywood Plus DVD Decoder + 8400 EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder 1106 VIA Technologies, Inc. 0305 VT8363/8365 [KT133/KM133] + 1043 8042 A7V133/A7V133-C + 147b a401 KT7/KT7-RAID/KT7A/KT7A-RAID 0391 VT8371 [KX133] 0501 VT8501 [Apollo MVP4] 0505 VT82C505 @@ -2093,6 +2492,7 @@ 0605 VT8605 [ProSavage PM133] 0680 VT82C680 [Apollo P6] 0686 VT82C686 [Apollo Super South] + 1043 8042 ATV133/A7V133-C 1106 0000 VT82C686/A PCI to ISA Bridge 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C693A/694x [Apollo PRO133x] @@ -2105,25 +2505,30 @@ 1571 VT82C416MV 1595 VT82C595/97 [Apollo VP2/97] 3038 UHCI USB - 1234 0925 MVP3 USB Controller 3040 VT82C586B ACPI - 3043 VT86C100A [Rhine 10/100] + 3043 VT3043 [Rhine] 10bd 0000 VT86C100A Fast Ethernet Adapter 1106 0100 VT86C100A Fast Ethernet Adapter - 1186 1400 DFE-530TX - 3044 OHCI Compliant IEEE 1394 Host Controller + 1186 1400 DFE-530TX rev A + 3044 IEEE 1394 Host Controller 3050 VT82C596 Power Management 3051 VT82C596 Power Management 3057 VT82C686 [Apollo Super ACPI] - 3058 AC97 Audio Controller + 1043 8042 ATV133/A7V133-C + 3058 VT82C686 AC97 Audio Controller + 1458 7600 Onboard Audio 1462 3091 MS-6309 Onboard Audio - 3059 AC97 Audio Controller - 3065 Ethernet Controller + 3059 VT8233 AC97 Audio Controller + 3065 VT6102 [Rhine-II] + 1186 1400 DFE-530TX rev A + 1186 1401 DFE-530TX rev B 3068 AC97 Modem Controller 3074 VT8233 PCI to ISA Bridge 3091 VT8633 [Apollo Pro266] 3099 VT8367 [KT266] + 3104 USB 2.0 3109 VT8233C PCI to ISA Bridge + 3128 VT8753 [P4X266 AGP] 5030 VT82C596 ACPI [Apollo PRO] 6100 VT85C100A [Rhine II] 8231 VT8231 [PCI-to-ISA Bridge] @@ -2160,6 +2565,7 @@ 6120 SZB6120 110b Chromatic Research Inc. 0001 Mpact Media Processor + 0004 Mpact 2 110c Mini-Max Technology, Inc. 110d Znyx Advanced Systems 110e CPU Technology @@ -2183,6 +2589,7 @@ 5105 10Mbps Network card 9211 EN-1207D Fast Ethernet Adapter 1113 9211 EN-1207D Fast Ethernet Adapter + 9511 Fast Ethernet Adapter 1114 Atmel Corporation 1115 3D Labs 1116 Data Translation @@ -2287,6 +2694,7 @@ 0001 Powerbis Bridge 111d Integrated Device Tech 0001 IDT77211 ATM Adapter + 0003 IDT77252 ATM network controller 111e Eldec 111f Precision Digital Images 4a47 Precision MX Video engine interface @@ -2329,8 +2737,11 @@ 7912 EiconCard S91 7941 EiconCard S94 7942 EiconCard S94 + 7943 EiconCard S94 + 7944 EiconCard S94 b921 EiconCard P92 b922 EiconCard P92 + b923 EiconCard P92 e001 DIVA 20PRO 1133 e001 DIVA Pro 2.0 S/T e002 DIVA 20 @@ -2339,8 +2750,12 @@ 1133 e003 DIVA Pro 2.0 U e004 DIVA 20_U 1133 e004 DIVA 2.0 U + e005 DIVA LOW + 1133 e005 DIVA 2.01 S/T e010 DIVA Server BRI-2M 1133 e010 DIVA Server BRI-2M + e012 DIVA Server BRI-8M + 1133 e012 DIVA Server BRI-8M e014 DIVA Server PRI-30M 1133 e014 DIVA Server PRI-30M 1134 Mercury Computer Systems @@ -2367,8 +2782,8 @@ 113f Equinox Systems, Inc. 0808 SST-64P Adapter 1010 SST-128P Adapter - 80c0 SST-16P Adapter - 80c4 SST-16P Adapter + 80c0 SST-16P DB Adapter + 80c4 SST-16P RJ Adapter 80c8 SST-16P Adapter 8888 SST-4P Adapter 9090 SST-8P Adapter @@ -2415,6 +2830,7 @@ 1148 9862 SK-9862 (1000Base-SX VF45 dual link) 1149 Win System Corporation 114a VMIC + 5579 VMIPCI-5579 (Reflective Memory Card) 7587 VMIVME-7587 114b Canopus Co., Ltd 114c Annabooks @@ -2440,12 +2856,24 @@ 001a DataFirePRIme E1 (1-port) 001b AccelePort C/X (IBM) 001d DataFire RAS T1/E1/PRI + 114f 0050 DataFire RAS E1 Adapter + 114f 0051 DataFire RAS Dual E1 Adapter + 114f 0052 DataFire RAS T1 Adapter + 114f 0053 DataFire RAS Dual T1 Adapter 0023 AccelePort RAS 0024 DataFire RAS B4 ST/U + 114f 0030 DataFire RAS BRI U Adapter + 114f 0031 DataFire RAS BRI S/T Adapter 0026 AccelePort 4r 920 0027 AccelePort Xr 920 0034 AccelePort 2r 920 0035 DataFire DSP T1/E1/PRI cPCI + 0040 AccelePort Xp + 0042 AccelePort 2p PCI + 0070 Datafire Micro V IOM2 (Europe) + 0071 Datafire Micro V (Europe) + 0072 Datafire Micro V IOM2 (North America) + 0073 Datafire Micro V (North America) 6001 Avanstar 1150 Thinking Machines Corp 1151 JAE Electronics Inc. @@ -2468,6 +2896,8 @@ 0003 Cardbus Ethernet 10/100 1014 0181 10/100 EtherJet Cardbus Adapter 1014 1181 10/100 EtherJet Cardbus Adapter + 1014 8181 10/100 EtherJet Cardbus Adapter + 1014 9181 10/100 EtherJet Cardbus Adapter 115d 0181 Cardbus Ethernet 10/100 115d 1181 Cardbus Ethernet 10/100 8086 8181 EtherExpress PRO/100 Mobile CardBus 32 Adapter @@ -2485,6 +2915,7 @@ 000b Cardbus Ethernet 10/100 1014 0183 10/100 EtherJet Cardbus Adapter 115d 0183 Cardbus Ethernet 10/100 + 000c Mini-PCI V.90 56k Modem 000f Cardbus Ethernet 10/100 1014 0183 10/100 EtherJet Cardbus Adapter 115d 0183 Cardbus Ethernet 10/100 @@ -2515,7 +2946,7 @@ 0201 CSB5 South Bridge 0211 OSB4 IDE Controller 0212 CSB5 IDE Controller - 0220 OSB4/CSB5 OHCI USB Controller + 0220 OSB4/CSB5 USB Controller 1167 Mutoh Industries Inc 1168 Thine Electronics Inc 1169 Centre for Development of Advanced Computing @@ -2566,6 +2997,7 @@ 0476 RL5c476 II 0477 RL5c477 0478 RL5c478 + 0552 R5C552 IEEE 1394 Controller 1181 Telmatics International 1183 Fujikura Ltd 1184 Forks Inc @@ -2574,6 +3006,8 @@ 0100 DC21041 1002 Sundance Ethernet 1300 RTL8139 Ethernet + 1340 DFE-690TXD CardBus PC Card + 1561 DRP-32TXD Cardbus PC Card 4000 DL2K Ethernet 1187 Advanced Technology Laboratories, Inc. 1188 Shima Seiki Manufacturing Ltd. @@ -2693,6 +3127,7 @@ 0440 56k WinModem 0001 0440 LT WinModem 56k Data+Fax+Voice+Dsvd 1033 8015 LT WinModem 56k Data+Fax+Voice+Dsvd + 1033 8047 LT WinModem 56k Data+Fax+Voice+Dsvd 1033 804f LT WinModem 56k Data+Fax+Voice+Dsvd 10cf 102c LB LT Modem V.90 56k 10cf 104a BIBLO LT Modem 56k @@ -2700,15 +3135,18 @@ 1179 0001 Internal V.90 Modem 11c1 0440 LT WinModem 56k Data+Fax+Voice+Dsvd 122d 4101 MDP7800-U Modem + 122d 4102 MDP7800SP-U Modem 13e0 0040 LT WinModem 56k Data+Fax+Voice+Dsvd 13e0 0440 LT WinModem 56k Data+Fax+Voice+Dsvd 13e0 0441 LT WinModem 56k Data+Fax+Voice+Dsvd + 13e0 0450 LT WinModem 56k Data+Fax+Voice+Dsvd 13e0 f100 LT WinModem 56k Data+Fax+Voice+Dsvd 13e0 f101 LT WinModem 56k Data+Fax+Voice+Dsvd 144d 2101 LT56PV Modem 149f 0440 LT WinModem 56k Data+Fax+Voice+Dsvd 0441 56k WinModem 1033 804d LT WinModem 56k Data+Fax + 1033 8065 LT WinModem 56k Data+Fax 1092 0440 Supra 56i 1179 0001 Internal V.90 Modem 11c1 0440 LT WinModem 56k Data+Fax @@ -2718,11 +3156,16 @@ 13e0 0100 LT WinModem 56k Data+Fax 13e0 0410 LT WinModem 56k Data+Fax 13e0 0420 TelePath Internet 56k WinModem + 13e0 0440 LT WinModem 56k Data+Fax 13e0 0443 LT WinModem 56k Data+Fax + 13e0 f102 LT WinModem 56k Data+Fax 1416 9804 CommWave 56k Modem 141d 0440 LT WinModem 56k Data+Fax 144f 0441 Lucent 56k V.90 DF Modem + 144f 0449 Lucent 56k V.90 DF Modem + 144f 110d Lucent Win Modem 1468 0441 Presario 56k V.90 DF Modem + 1668 0440 Lucent Win Modem 0442 56k WinModem 0001 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 11c1 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd @@ -2731,6 +3174,7 @@ 13e0 0442 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 13fc 2471 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 144d 2104 LT56PT Modem + 144f 1104 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 149f 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 1668 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 0443 LT WinModem @@ -2739,14 +3183,22 @@ 0446 LT WinModem 0447 LT WinModem 0448 WinModem 56k + 1014 0131 Lucent Win Modem + 1033 8066 LT WinModem 56k Data+Fax+Voice+Dsvd + 13e0 0030 56k Voice Modem 13e0 0040 LT WinModem 56k Data+Fax+Voice+Dsvd +# Actiontech eth+modem card as used by Dell &c. + 1668 2400 LT WinModem 56k (MiniPCI Ethernet+Modem) 0449 WinModem 56k 0e11 b14d 56k V.90 Modem 13e0 0020 LT WinModem 56k Data+Fax 13e0 0041 TelePath Internet 56k WinModem + 1436 0440 Lucent Win Modem 144f 0449 Lucent 56k V.90 DFi Modem + 1468 0440 Lucent Win Modem 1468 0449 Presario 56k V.90 DFi Modem 044a F-1156IV WinModem (V90, 56KFlex) + 10cf 1072 LB Global LT Modem 13e0 0012 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 13e0 0042 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 144f 1005 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd @@ -2754,6 +3206,7 @@ 044c LT WinModem 044d LT WinModem 044e LT WinModem + 044f V90 WildWire Modem 0450 LT WinModem 0451 LT WinModem 0452 LT WinModem @@ -2765,7 +3218,11 @@ 0458 LT WinModem 0459 LT WinModem 045a LT WinModem + 0461 V90 WildWire Modem + 0462 V90 WildWire Modem 0480 Venus Modem (V90, 56KFlex) + 5811 FW323 + dead 0800 FireWire Host Bus Adapter 11c2 Sand Microelectronics 11c3 NEC Corp 11c4 Document Technologies, Inc @@ -2796,6 +3253,7 @@ 11d2 Intercom Inc. 11d3 Trancell Systems Inc 11d4 Analog Devices + 1805 SM56 PCI modem 1889 AD1889 sound chip 11d5 Ikon Corporation 0115 10115 @@ -2932,7 +3390,7 @@ 1092 8030 Monster Fusion 1092 8035 Monster Fusion AGP 10b0 0001 Dragon 4000 - 1102 1017 CT6760 3D Blaster Banshee + 1102 1018 3D Blaster Banshee VE 121a 0001 Voodoo Banshee AGP 121a 0003 Voodoo Banshee AGP SGRAM 121a 0004 Voodoo Banshee @@ -2962,6 +3420,7 @@ 121a 0062 Voodoo3 3500 TV (SECAM) 0009 Voodoo 4 / Voodoo 5 121a 0009 Voodoo5 AGP 5500/6000 + 0057 Voodoo 3/3000 [Avenger] 121b Advanced Telecommunications Modules 121c Nippon Texaco., Ltd 121d Lippert Automationstechnik GmbH @@ -3034,8 +3493,12 @@ 1243 Delphax 1244 AVM Audiovisuelles MKTG & Computer System GmbH 0700 B1 ISDN + 0800 C4 ISDN 0a00 A1 ISDN [Fritz] 1244 0a00 FRITZ!Card ISDN Controller + 0e00 Fritz!PCI v2.0 ISDN + 1100 C2 ISDN + 1200 T1 ISDN 1245 A.P.D., S.A. 1246 Dipix Technologies, Inc. 1247 Xylon Research, Inc. @@ -3043,11 +3506,14 @@ 1249 Samsung Electronics Co., Ltd. 124a AEG Electrocom GmbH 124b SBS/Greenspring Modular I/O + 0040 cPCI-200 Four Slot IndustryPack carrier + 124b 9080 PCI9080 Bridge 124c Solitron Technologies, Inc. 124d Stallion Technologies, Inc. 0000 EasyConnection 8/32 0002 EasyConnection 8/64 0003 EasyIO + 0004 EasyConnection/RA 124e Cylink 124f Infotrend Technology, Inc. 0041 IFT-2000 Series RAID Controller @@ -3094,10 +3560,22 @@ 1989 ESS Modem 125d 1989 ESS Modem 1998 ES1983S Maestro-3i PCI Audio Accelerator + 1028 00e6 ES1983S Maestro-3i (Dell Inspiron 8100) 1999 ES1983S Maestro-3i PCI Modem Accelerator + 199a ES1983S Maestro-3i PCI Audio Accelerator + 199b ES1983S Maestro-3i PCI Modem Accelerator 2808 ES336H Fax Modem (Later Model) 2838 ES2838/2839 SuperLink Modem 2898 ES2898 Modem + 125d 0424 ES56-PI Data Fax Modem + 125d 0425 ES56T-PI Data Fax Modem + 125d 0426 ES56V-PI Data Fax Modem + 125d 0427 VW-PI Data Fax Modem + 125d 0428 ES56ST-PI Data Fax Modem + 125d 0429 ES56SV-PI Data Fax Modem + 147a c001 ES56-PI Data Fax Modem + 14fe 0428 ES56-PI Data Fax Modem + 14fe 0429 ES56-PI Data Fax Modem 125e Specialvideo Engineering SRL 125f Concurrent Technologies, Inc. 1260 Harris Semiconductor @@ -3193,7 +3671,9 @@ 4942 4c4c Creative Sound Blaster AudioPCI128 5880 5880 AudioPCI 1274 2000 Creative Sound Blaster AudioPCI128 + 1274 2003 Creative SoundBlaster AudioPCI 128 1274 5880 Creative Sound Blaster AudioPCI128 + 1458 a000 5880 AudioPCI On Motherboard 6OXET 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 270f 2001 5880 AudioPCI On Motherboard 6CTR 270f 2200 5880 AudioPCI On Motherboard 6WTX @@ -3202,6 +3682,7 @@ 1276 Switched Network Technologies, Inc. 1277 Comstream 1278 Transtech Parallel Systems Ltd. + 0701 TPE3/TM3 PowerPC Node 1279 Transmeta Corporation 0295 Northbridge 0395 LongRun Northbridge @@ -3209,26 +3690,29 @@ 0397 BIOS scratchpad 127a Rockwell International 1002 HCF 56k Data/Fax Modem + 1092 094c SupraExpress 56i PRO [Diamond SUP2380] 122d 4002 HPG / MDP3858-U # Aztech 122d 4005 MDP3858-E # Aztech 122d 4007 MDP3858-A/-NZ # Aztech 122d 4012 MDP3858-SA # Aztech 122d 4017 MDP3858-W # Aztech 122d 4018 MDP3858-W # Aztech + 127a 1002 Rockwell 56K D/F HCF Modem 1003 HCF 56k Data/Fax Modem 0e11 b0bc 229-DF Zephyr # Compaq 0e11 b114 229-DF Cheetah # Compaq 1033 802b 229-DF # NEC 13df 1003 PCI56RX Modem # E-Tech Inc 13e0 0117 IBM # GVC - 13e0 0147 IBM # GVC + 13e0 0147 IBM # GVC F-1156IV /R3 Spain V.90 Modem 13e0 0197 IBM # GVC - 13e0 01c7 IBM # GVC + 13e0 01c7 IBM # GVC F-1156IV /R3 WW V.90 Modem 13e0 01f7 IBM # GVC 1436 1003 IBM # CIS - 1436 1103 IBM # CIS + 1436 1103 IBM # CIS 5614PM3G V.90 Modem 1436 1602 Compaq 229-DF Ducati 1004 HCF 56k Data/Fax/Voice Modem + 1048 1500 MicroLink 56k Modem 10cf 1059 Fujitsu 229-DFRT 1005 HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem 1033 8029 229-DFSV # NEC @@ -3249,16 +3733,19 @@ 13df 1005 PCI56RVP Modem # E-Tech Inc 13e0 0187 IBM # GVC 13e0 01a7 IBM # GVC - 13e0 01b7 IBM # GVC - 13e0 01d7 IBM # GVC + 13e0 01b7 IBM # GVC DF-1156IV /R3 Spain V.90 Modem + 13e0 01d7 IBM # GVC DF-1156IV /R3 WW V.90 Modem 1436 1005 IBM # CIS 1436 1105 IBM # CIS + 1437 1105 IBM # CIS 5614PS3G V.90 Modem + 1022 HCF 56k Modem + 1436 1303 M3-5614PM3G V.90 Modem 1023 HCF 56k Data/Fax Modem 122d 4020 Packard Bell MDP3858-WE # Aztech 122d 4023 MDP3858-UE # Aztech - 13e0 0247 IBM # GVC + 13e0 0247 IBM # GVC F-1156IV /R6 Spain V.90 Modem 13e0 0297 IBM # GVC - 13e0 02c7 IBM # GVC + 13e0 02c7 IBM # GVC F-1156IV /R6 WW V.90 Modem 1436 1203 IBM # CIS 1436 1303 IBM # CIS 1024 HCF 56k Data/Fax/Voice Modem @@ -3269,7 +3756,11 @@ 122d 4024 MDP3858V-UE # Aztech 122d 4025 MDP3858SP-UE # Aztech 1026 HCF 56k PCI Speakerphone Modem + 1032 HCF 56k Modem + 1033 HCF 56k Modem + 1034 HCF 56k Modem 1035 HCF 56k PCI Speakerphone Modem + 1036 HCF 56k Modem 1085 HCF 56k Volcano PCI Modem 2005 HCF 56k Data/Fax Modem 104d 8044 229-DFSV # Sony @@ -3309,6 +3800,7 @@ 4322 Riptide PCI Game Controller 1235 4322 Riptide PCI Game Controller 8234 RapidFire 616X ATM155 Adapter + 108d 0022 RapidFire 616X ATM155 Adapter 108d 0027 RapidFire 616X ATM155 Adapter 127b Pixera Corporation 127c Crosspoint Solutions, Inc. @@ -3360,6 +3852,7 @@ 1298 Spellcaster Telecommunications Inc. 1299 Knowledge Technology Lab. 129a VMetro, inc. + 0615 PBT-615 PCI-X Bus Analyzer 129b Image Access 129c Jaycor 129d Compcore Multimedia, Inc. @@ -3382,8 +3875,10 @@ 12ad Multidata GmbH 12ae Alteon Networks Inc. 0001 AceNIC Gigabit Ethernet (Fibre) - 1410 0104 Gigabit Ethernet-SX PCI Adapter (14100401) + 12ae 0001 Gigabit Ethernet-SX (Universal) + 1410 0104 Gigabit Ethernet-SX PCI Adapter 0002 AceNIC Gigabit Ethernet (Copper) + 12ae 0002 Gigabit Ethernet-T (3C986-T) 12af TDK USA Corp 12b0 Jorge Scientific Corp 12b1 GammaLink @@ -3449,19 +3944,24 @@ 0008 NV1 0009 DAC64 0018 Riva128 + 1048 0c10 VICTORY Erazor 107b 8030 STB Velocity 128 1092 0350 Viper V330 1092 1092 Viper V330 10b4 1b1b STB Velocity 128 - 10b4 1b20 STB Velocity 128 + 10b4 1b1d STB Velocity 128 + 10b4 1b1e STB Velocity 128, PAL TV-Out + 10b4 1b20 STB Velocity 128 Sapphire 10b4 1b21 STB Velocity 128 10b4 1b22 STB Velocity 128 AGP, NTSC TV-Out 10b4 1b23 STB Velocity 128 AGP, PAL TV-Out 10b4 1b27 STB Velocity 128 DVD + 10b4 1b88 MVP Pro 128 10b4 222a STB Velocity 128 AGP 10b4 2230 STB Velocity 128 + 10b4 2232 STB Velocity 128 10b4 2235 STB Velocity 128 AGP - 2a15 54a3 3DVision-SAGP + 2a15 54a3 3DVision-SAGP / 3DexPlorer 3000 0019 Riva128ZX 0020 TNT 0028 TNT2 @@ -3469,7 +3969,7 @@ 002c VTNT2 00a0 ITNT2 12d3 Vingmed Sound A/S -12d4 DGM&S +12d4 Ulticom (Formerly DGM&S) 12d5 Equator Technologies 12d6 Analogic Corp 12d7 Biotronic SRL @@ -3768,6 +4268,7 @@ 1383 Controlnet Inc 1384 Reality Simulation Systems Inc 1385 Netgear + 4100 802.11b Wireless Adapter (MA301) 620a GA620 622a GA622 630a GA630 @@ -3793,6 +4294,7 @@ 2180 Intellio C218 Turbo PCI 3200 Intellio C320 Turbo PCI 1394 Level One Communications + 0001 LXT1001 Gigabit Ethernet 1395 Ambicom Inc 1396 Cipher Systems Inc 1397 Cologne Chip Designs GmbH @@ -3810,12 +4312,17 @@ 13a0 Crystal Group Inc 13a1 Kawasaki Heavy Industries Ltd 13a2 Ositech Communications Inc -13a3 Hi-Fn +13a3 Hifn Inc. + 0005 7751 Security Processor + 0006 6500 Public Key Processor + 0007 7811 Security Processor + 0012 7951 Security Processor 13a4 Rascom Inc 13a5 Audio Digital Imaging Inc 13a6 Videonics Inc 13a7 Teles AG 13a8 Exar Corp. + 0158 XR17C158 Octal UART 13a9 Siemens Medical Systems, Ultrasound Group 13aa Broadband Networks Inc 13ab Arcom Control Systems Ltd @@ -3860,6 +4367,7 @@ 13cf Studio Audio & Video Ltd 13d0 Techsan Electronics Co Ltd 13d1 Abocom Systems Inc + ab06 RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter 13d2 Shark Multimedia Inc 13d3 IMC Networks 13d4 Graphics Microsystems Inc @@ -3897,7 +4405,8 @@ 13f1 Oce' - Technologies B.V. 13f2 Ford Microelectronics Inc 13f3 Mcdata Corporation -13f4 Troika Design Inc +13f4 Troika Networks, Inc. + 1401 Zentai Fibre Channel Adapter 13f5 Kansai Electric Co. Ltd 13f6 C-Media Electronics Inc 0100 CM8338A @@ -3905,6 +4414,7 @@ 0101 CM8338B 13f6 0101 CMI8338-031 PCI Audio Device 0111 CM8738 + 1043 8077 CMI8738 6-channel audio controller 13f6 0111 CMI8738/C3DX PCI Audio Device 0211 CM8738 13f7 Wildfire Communications @@ -3939,6 +4449,7 @@ 8800 BOCA Research IOPPAR 1408 Aloka Co. Ltd 1409 Timedia Technology Co Ltd + 7168 PCI2S550 (Dual 16550 UART) 140a DSP Research Inc 140b Ramix Inc 140c Elmic Systems Inc @@ -3952,6 +4463,14 @@ 1413 Addonics 1414 Microsoft Corporation 1415 Oxford Semiconductor Ltd + 8403 VScom 011H-EP1 1 port parallel adaptor + 9501 Quad 16950 UART + 15ed 2000 MCCR Serial p0-3 of 8 + 15ed 2001 MCCR Serial p0-3 of 16 + 9511 OX16PCI954 (Quad 16950 UART) function 1 + 15ed 2000 MCCR Serial p4-7 of 8 + 15ed 2001 MCCR Serial p4-15 of 16 + 9521 OX16PCI952 (Dual 16950 UART) 1416 Multiwave Innovation pte Ltd 1417 Convergenet Technologies Inc 1418 Kyushu electronics systems Inc @@ -4128,6 +4647,10 @@ 14b8 Techsoft Technology Co Ltd 14b9 AIRONET Wireless Communications 0001 PC4800 + 0340 PC4800 + 0350 PC4800 + 4500 PC4500 + 4800 PC4800 14ba INTERNIX Inc. 14bb SEMTECH Corporation 14bc Globespan Semiconductor Inc. @@ -4153,6 +4676,22 @@ 14d0 Ericsson Axe R & D 14d1 Computer Hi-Tech Co Ltd 14d2 Titan Electronics Inc + 8001 VScom 010L 1 port parallel adaptor + 8002 VScom 020L 2 port parallel adaptor + 8010 VScom 100L 1 port serial adaptor + 8011 VScom 110L 1 port serial and 1 port parallel adaptor + 8020 VScom 200L 1 port serial adaptor + 8021 VScom 210L 2 port serial and 1 port parallel adaptor + 8040 VScom 400L 4 port serial adaptor + 8080 VScom 800L 8 port serial adaptor + a000 VScom 010H 1 port parallel adaptor + a001 VScom 100H 1 port serial adaptor + a003 VScom 400H 4 port serial adaptor + a004 VScom 400HF1 4 port serial adaptor + a005 VScom 200H 2 port serial adaptor + e001 VScom 010HV2 1 port parallel adaptor + e010 VScom 100HV2 1 port serial adaptor + e020 VScom 200HV2 2 port serial adaptor 14d3 CIRTECH (UK) Ltd 14d4 Panacom Technology Corp 14d5 Nitsuko Corporation @@ -4182,20 +4721,29 @@ 14e3 AMTELCO 14e4 BROADCOM Corporation 1644 NetXtreme BCM5700 Gigabit Ethernet + 1014 0277 Vigil B5700 1000BaseTX + 1028 00d1 NetXtreme 1000BaseTX + 1028 0106 NetXtreme 1000BaseTX + 1028 0109 NetXtreme 1000BaseTX 10b7 1000 3C996-T 1000BaseTX 10b7 1001 3C996B-T 1000BaseTX 10b7 1002 3C996C-T 1000BaseTX - 10b7 1003 3C997-T 1000BaseTX + 10b7 1003 3C997-T 1000BaseTX Dual Port 10b7 1004 3C996-SX 1000BaseSX - 10b7 1005 3C997-SX 1000BaseSX + 10b7 1005 3C997-SX 1000BaseSX Dual Port + 10b7 1008 3C942 Gigabit LOM (31X31) 14e4 0002 NetXtreme 1000BaseSX 14e4 0003 NetXtreme 1000BaseSX 14e4 0004 NetXtreme 1000BaseTX + 14e4 1028 NetXtreme 1000BaseTX 14e4 1644 NetXtreme BCM5700 1000BaseTX 1645 NetXtreme BCM5701 Gigabit Ethernet - 0e11 007c NC7770 1000BaseTX - 0e11 007d NC6770 1000BaseSX - 0e11 0085 NC7780 1000BaseTX + 0e11 007c NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T) + 0e11 007d NC6770 Gigabit Server Adapter (PCI-X, 1000-SX) + 0e11 0085 NC7780 Gigabit Server Adapter (embedded, WOL) + 0e11 0099 NC7780 Gigabit Server Adapter (embedded, WOL) + 0e11 009a NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T) + 1028 0121 NetXtreme BCM5701 1000BaseTX 10b7 1004 3C996-SX 1000BaseSX 10b7 1006 3C996B-T 1000BaseTX 10b7 1007 3C1000-T 1000BaseTX @@ -4206,7 +4754,22 @@ 14e4 0007 NetXtreme BCM5701 1000BaseSX 14e4 0008 NetXtreme BCM5701 1000BaseTX 14e4 8008 NetXtreme BCM5701 1000BaseTX + 1646 NetXtreme BCM5702 Gigabit Ethernet + 0e11 00bb NC7760 1000BaseTX + 1028 0126 NetXtreme BCM5702 1000BaseTX + 14e4 8009 NetXtreme BCM5702 1000BaseTX 1647 NetXtreme BCM5703 Gigabit Ethernet + 0e11 0099 NC7780 1000BaseTX + 0e11 009a NC7770 1000BaseTX + 14e4 0009 NetXtreme BCM5703 1000BaseTX + 14e4 000a NetXtreme BCM5703 1000BaseSX + 14e4 000b NetXtreme BCM5703 1000BaseTX + 14e4 8009 NetXtreme BCM5703 1000BaseTX + 14e4 800a NetXtreme BCM5703 1000BaseTX + 164d NetXtreme BCM5702FE Gigabit Ethernet + 16a6 NetXtreme BCM5702X Gigabit Ethernet + 16a7 NetXtreme BCM5703X Gigabit Ethernet + 4212 BCM v.90 56k modem 5820 BCM5820 Crypto Accelerator 14e5 Pixelfusion Ltd 14e6 SHINING Technology Inc @@ -4221,14 +4784,30 @@ 14ef CARRY Computer ENG. CO Ltd 14f0 CANON RESEACH CENTRE FRANCE 14f1 Conexant + 1002 HCF 56k Modem + 1003 HCF 56k Modem + 1004 HCF 56k Modem + 1005 HCF 56k Modem + 1006 HCF 56k Modem + 1022 HCF 56k Modem + 1023 HCF 56k Modem + 1024 HCF 56k Modem + 1025 HCF 56k Modem + 1026 HCF 56k Modem + 1032 HCF 56k Modem 1033 HCF 56k Data/Fax Modem + 1033 8077 NEC 122d 4027 Dell Zeus - MDP3880-W(B) Data Fax Modem 122d 4030 Dell Mercury - MDP3880-U(B) Data Fax Modem 122d 4034 Dell Thor - MDP3880-W(U) Data Fax Modem 13e0 020d Dell Copper 13e0 020e Dell Silver + 13e0 0261 IBM # GVC 13e0 0290 Compaq Goldwing + 13e0 02a0 IBM # GVC + 13e0 02b0 IBM # GVC 13e0 02c0 Compaq Scooter + 13e0 02d0 IBM # GVC 144f 1500 IBM P85-DF (1) 144f 1501 IBM P85-DF (2) 144f 150a IBM P85-DF (3) @@ -4238,6 +4817,7 @@ 1035 HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem 10cf 1098 Fujitsu P85-DFSV 1036 HCF 56k Data/Fax/Voice/Spkp Modem + 104d 8067 HCF 56k Modem 122d 4029 MDP3880SP-W 122d 4031 MDP3880SP-U 13e0 0209 Dell Titanium @@ -4261,6 +4841,8 @@ 1435 HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem 1436 HCF 56k Data/Fax Modem 1453 HCF 56k Data/Fax Modem + 13e0 0240 IBM # GVC + 13e0 0250 IBM # GVC 144f 1502 IBM P95-DF (1) 144f 1503 IBM P95-DF (2) 1454 HCF 56k Data/Fax/Voice Modem @@ -4282,6 +4864,9 @@ 0e11 b195 Bear 0e11 b196 Seminole 1 0e11 b1be Seminole 2 + 1025 8013 Acer + 1033 809d NEC + 1033 80bc NEC 155d 6793 HP 155d 8850 E Machines 2014 HSF 56k Data/Fax/Voice Modem @@ -4314,6 +4899,9 @@ 2365 HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA) 2366 HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA) 2443 HSF 56k Data/Fax Modem (Mob WorldW SmartDAA) + 104d 8075 Modem # Sony + 104d 8083 Modem # Sony + 104d 8097 Modem # Sony 2444 HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA) 2445 HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA) 2446 HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA) @@ -4383,9 +4971,16 @@ 151d Fujitsu Computer Products Of America 151e MATRIX Corp 151f TOPIC SEMICONDUCTOR Corp + 0000 TP560 Data/Fax/Voice 56k modem 1520 CHAPLET System Inc 1521 BELL Corp 1522 MainPine Ltd + 0100 PCI <-> IOBus Bridge + 1522 0200 RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem + 1522 0300 RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem + 1522 0400 RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem + 1522 0500 RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem + 1522 0600 RockForce+ 2 Port V.90 Data/Fax/Voice Modem 1523 MUSIC Semiconductors 1524 ENE Technology Inc 1525 IMPACT Technologies @@ -4540,6 +5135,7 @@ 15a0 Compumaster SRL 15a1 Geocast Network Systems 15a2 Catalyst Enterprises Inc + 0001 TA700 PCI Bus Analyzer/Exerciser 15a3 Italtel 15a4 X-Net OY 15a5 Toyota Macs Inc @@ -4556,6 +5152,7 @@ 15b1 Source Technology Inc 15b2 Mosaid Technologies Inc 15b3 Mellanox Technology + 5274 MT21108 InfiniBridge 15b4 CCI/TRIAD 15b5 Cimetrics Inc 15b6 Texas Memory Systems Inc @@ -4565,6 +5162,7 @@ 15ba Impacct Technology Corp 15bb Portwell Inc 15bc Agilent Technologies + 2929 E2929A PCI/PCI-X Bus Analyzer 15bd DFI Inc 15be Sola Electronics 15bf High Tech Computer Corp (HTC) @@ -4645,7 +5243,18 @@ 1619 FarSite Communications Ltd 0400 FarSync T2P (2 port X.21/V.35/V.24) 0440 FarSync T4P (4 port X.21/V.35/V.24) +1629 Kongsberg Spacetec AS + 1003 Format synchronizer v3.0 + 2002 Fast Universal Data Output +1657 Brocade Communications Systems, Inc. 1668 Action Tec Electronics Inc +16f6 VideoTele.com, Inc. +170b NetOctave Inc +170c YottaYotta Inc. +173b Altima (nee BroadCom) + 03e8 AC1000 Gigabit Ethernet +1743 Peppercon AG + 8139 ROL/F-100 Fast Ethernet Adapter with ROL 1813 Ambient Technologies Inc 1a08 Sierra semiconductor 0000 SC15064 @@ -4671,6 +5280,7 @@ 3000 Hansol Electronics Inc. 3142 Post Impression Systems. 3388 Hint Corp + 0021 HB1-SE33 PCI-PCI Bridge 8011 VXPro II Chipset 3388 8011 VXPro II Chipset CPU to PCI Bridge 8012 VXPro II Chipset @@ -4690,6 +5300,7 @@ 0007 3D Extreme 0008 GLINT Gamma G1 0009 Permedia II 2D+3D + 1040 0011 AccelStar II 3d3d 0100 AccelStar II 3D Accelerator 3d3d 0111 Permedia 3:16 3d3d 0114 Santa Ana @@ -4719,6 +5330,7 @@ 2501 ALG-2564A/25128A 4000 ALS4000 Audio Chipset 4005 4000 ALS4000 Audio Chipset + 4710 ALC200/200P 4033 Addtron Technology Co, Inc. 1360 RTL8139 Ethernet 4143 Digital Equipment Corp @@ -4745,6 +5357,8 @@ 0200 MQ-200 4d54 Microtechnica Co Ltd 4ddc ILC Data Device Corp +5046 GemTek Technology Corporation + 1001 PCI Radio 5053 Voyetra Technologies 2010 Daytona Audio Adapter 5136 S S Technologies @@ -4788,7 +5402,7 @@ 88f3 86c968 [Vision 968 VRAM] rev 3 8900 86c755 [Trio 64V2/DX] 5333 8900 86C775 Trio64V2/DX - 8901 Trio 64V2/DX or /GX + 8901 86c775/86c785 [Trio 64V2/DX or /GX] 5333 8901 86C775 Trio64V2/DX, 86C785 Trio64V2/GX 8902 Plato/PX 8903 Trio 3D business multimedia @@ -4817,9 +5431,11 @@ 5333 8a13 Trio3D/2X 8a20 86c794 [Savage 3D] 5333 8a20 86C391 Savage3D - 8a21 86c795 [Savage 3D/MV] + 8a21 86c390 [Savage 3D/MV] 5333 8a21 86C390 Savage3D/MV 8a22 Savage 4 + 1033 8068 Savage 4 + 1033 8069 Savage 4 105d 0018 SR9 8Mb SDRAM 105d 002a SR9 Pro 16Mb SDRAM 105d 003a SR9 Pro 32Mb SDRAM @@ -4901,21 +5517,51 @@ 04d0 82437FX [Triton FX] 0600 RAID Controller 0960 80960RP [i960 RP Microprocessor/Bridge] + 0962 80960RM [i960RM Bridge] 0964 80960RP [i960 RP Microprocessor/Bridge] 1000 82542 Gigabit Ethernet Controller - 0e11 b0df NC1632 Gigabit Ethernet Adapter - 0e11 b0e0 NC1633 Gigabit Ethernet Adapter - 0e11 b123 NC1634 Gigabit Ethernet Adapter + 0e11 b0df NC1632 Gigabit Ethernet Adapter (1000-SX) + 0e11 b0e0 NC1633 Gigabit Ethernet Adapter (1000-LX) + 0e11 b123 NC1634 Gigabit Ethernet Adapter (1000-SX) 1014 0119 Netfinity Gigabit Ethernet SX Adapter + 8086 1000 PRO/1000 Gigabit Server Adapter 1001 82543GC Gigabit Ethernet Controller + 0e11 004a NC6136 Gigabit Server Adapter + 1014 01ea Netfinity Gigabit Ethernet SX Adapter + 8086 1003 PRO/1000 F Server Adapter + 1002 Pro 100 LAN Modem 56 Cardbus II + 8086 200e Pro 100 LAN Modem 56 Cardbus II + 8086 2013 Pro 100 SR Mobile Combo Adapter + 8086 2017 Pro 100 S Combo Mobile Adapter 1004 82543GC Gigabit Ethernet Controller + 0e11 0049 NC7132 Gigabit Upgrade Module + 0e11 b1a4 NC7131 Gigabit Server Adapter + 1014 10f2 Gigabit Ethernet Server Adapter + 8086 1004 PRO/1000 T Server Adapter + 8086 2004 PRO/1000 T Server Adapter 1008 82544EI Gigabit Ethernet Controller + 8086 1107 PRO/1000 XT Server Adapter + 8086 2107 PRO/1000 XT Server Adapter + 8086 2110 PRO/1000 XT Server Adapter 1009 82544EI Gigabit Ethernet Controller + 8086 1109 PRO/1000 XF Server Adapter + 8086 2109 PRO/1000 XF Server Adapter 100c 82544GC Gigabit Ethernet Controller + 8086 1109 PRO/1000 T Desktop Adapter + 8086 1112 PRO/1000 T Desktop Adapter + 8086 2109 PRO/1000 T Desktop Adapter + 8086 2112 PRO/1000 T Desktop Adapter 100d 82544GC Gigabit Ethernet Controller 1029 82559 Ethernet Controller 1030 82559 InBusiness 10/100 1031 82801CAM (ICH3) Chipset Ethernet Controller + 1014 0209 EtherExpress PRO/100 VE + 104d 80e7 Vaio PCG Series + 107b 5350 EtherExpress PRO/100 VE + 1179 0001 EtherExpress PRO/100 VE + 144d c000 EtherExpress PRO/100 VE + 144d c001 EtherExpress PRO/100 VE + 144d c003 EtherExpress PRO/100 VE 1032 82801CAM (ICH3) Chipset Ethernet Controller 1033 82801CAM (ICH3) Chipset Ethernet Controller 1034 82801CAM (ICH3) Chipset Ethernet Controller @@ -4924,8 +5570,12 @@ 1037 82801CAM (ICH3) Chipset Ethernet Controller 1038 82801CAM (ICH3) Chipset Ethernet Controller 1130 82815 815 Chipset Host Bridge and Memory Controller Hub + 1131 82815 815 Chipset AGP Bridge 1132 82815 CGC [Chipset Graphics Controller] 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller + 8086 1161 82806AA PCI64 Hub APIC + 1200 Unknown device + 172a 0000 AEP SSL Accelerator 1209 82559ER 1221 82092AA_0 1222 82092AA_1 @@ -4934,31 +5584,61 @@ 1226 82596 PRO/10 PCI 1227 82865 EtherExpress PRO/100A 1228 82556 EtherExpress PRO/100 Smart - 1229 82557 [Ethernet Pro 100] - 0e11 b01e NC3120 - 0e11 b01f NC3122 - 0e11 b02f NC1120 +# the revision field differentiates between them (1-3 is 82557, 4-5 is 82558, 6-8 is 82559, 9 is 82559ER) + 1229 82557/8/9 [Ethernet Pro 100] + 0e11 3001 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3002 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3003 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3004 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3005 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3006 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 3007 82559 Fast Ethernet LOM with Alert on LAN* + 0e11 b01e NC3120 Fast Ethernet NIC + 0e11 b01f NC3122 Fast Ethernet NIC (dual port) + 0e11 b02f NC1120 Ethernet NIC 0e11 b04a Netelligent 10/100TX NIC with Wake on LAN - 0e11 b0c6 Embedded NC3120 with Wake on LAN - 0e11 b0c7 Embedded NC3121 - 0e11 b0d7 NC3121 with Wake on LAN - 0e11 b0dd NC3131 (82558B) - 0e11 b0de NC3132 - 0e11 b0e1 NC3133 - 0e11 b144 NC3123 (82559) + 0e11 b0c6 NC3161 Fast Ethernet NIC (embedded, WOL) + 0e11 b0c7 NC3160 Fast Ethernet NIC (embedded) + 0e11 b0d7 NC3121 Fast Ethernet NIC (WOL) + 0e11 b0dd NC3131 Fast Ethernet NIC (dual port) + 0e11 b0de NC3132 Fast Ethernet Module (dual port) + 0e11 b0e1 NC3133 Fast Ethernet Module (100-FX) + 0e11 b134 NC3163 Fast Ethernet NIC (embedded, WOL) + 0e11 b13c NC3162 Fast Ethernet NIC (embedded) + 0e11 b144 NC3123 Fast Ethernet NIC (WOL) + 0e11 b163 NC3134 Fast Ethernet NIC (dual port) + 0e11 b164 NC3135 Fast Ethernet Upgrade Module (dual port) + 0e11 b1a4 NC7131 Gigabit Server Adapter 1014 005c 82558B Ethernet Pro 10/100 + 1014 01f1 10/100 Ethernet Server Adapter + 1014 01f2 10/100 Ethernet Server Adapter + 1014 0207 Ethernet Pro/100 S + 1014 0232 10/100 Dual Port Server Adapter 1014 105c Netfinity 10/100 + 1014 305c 10/100 EtherJet Management Adapter + 1014 405c 10/100 EtherJet Adapter with Alert on LAN + 1014 505c 10/100 EtherJet Secure Management Adapter + 1014 605c 10/100 EtherJet Secure Management Adapter + 1014 705c 10/100 Netfinity 10/100 Ethernet Security Adapter + 1014 805c 10/100 Netfinity 10/100 Ethernet Security Adapter 1033 8000 PC-9821X-B06 1033 8016 PK-UG-X006 1033 801f PK-UG-X006 - 103c 10c0 Ethernet Pro 10/100TX - 103c 10c3 Ethernet Pro 10/100TX - 103c 1200 Ethernet Pro 10/100TX + 103c 10c0 NetServer 10/100TX + 103c 10c3 NetServer 10/100TX + 103c 10ca NetServer 10/100TX + 103c 10cb NetServer 10/100TX + 103c 10e3 NetServer 10/100TX + 103c 10e4 NetServer 10/100TX + 103c 1200 NetServer 10/100TX 10c3 1100 SmartEther100 SC1100 1179 0002 PCI FastEther LAN on Docker 1259 2560 AT-2560 100 1259 2561 AT-2560 100 FX Ethernet Adapter 1266 0001 NE10/100 Adapter + 144d 2501 SEM-2000 MiniPCI LAN Adapter + 144d 2502 SEM-2100IL MiniPCI LAN Adapter + 1668 1100 EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem) 8086 0001 EtherExpress PRO/100B (TX) 8086 0002 EtherExpress PRO/100B (T4) 8086 0003 EtherExpress PRO/10+ @@ -4973,14 +5653,76 @@ 8086 000c EtherExpress PRO/100+ Management Adapter 8086 000d EtherExpress PRO/100+ Alert On LAN II* Adapter 8086 000e EtherExpress PRO/100+ Management Adapter with Alert On LAN* + 8086 000f EtherExpress PRO/100 Desktop Adapter + 8086 0010 EtherExpress PRO/100 S Management Adapter + 8086 0011 EtherExpress PRO/100 S Management Adapter + 8086 0012 EtherExpress PRO/100 S Advanced Management Adapter (D) + 8086 0013 EtherExpress PRO/100 S Advanced Management Adapter (E) + 8086 0030 EtherExpress PRO/100 Management Adapter with Alert On LAN* GC + 8086 0031 EtherExpress PRO/100 Desktop Adapter + 8086 0040 EtherExpress PRO/100 S Desktop Adapter + 8086 0041 EtherExpress PRO/100 S Desktop Adapter + 8086 0042 EtherExpress PRO/100 Desktop Adapter + 8086 0050 EtherExpress PRO/100 S Desktop Adapter 8086 1009 EtherExpress PRO/100+ Server Adapter 8086 100c EtherExpress PRO/100+ Server Adapter (PILA8470B) + 8086 1012 EtherExpress PRO/100 S Server Adapter (D) + 8086 1013 EtherExpress PRO/100 S Server Adapter (E) + 8086 1015 EtherExpress PRO/100 S Dual Port Server Adapter + 8086 1017 EtherExpress PRO/100+ Dual Port Server Adapter + 8086 1030 EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server + 8086 1040 EtherExpress PRO/100 S Server Adapter + 8086 1041 EtherExpress PRO/100 S Server Adapter + 8086 1042 EtherExpress PRO/100 Server Adapter + 8086 1050 EtherExpress PRO/100 S Server Adapter + 8086 1051 EtherExpress PRO/100 Server Adapter + 8086 1052 EtherExpress PRO/100 Server Adapter 8086 10f0 EtherExpress PRO/100+ Dual Port Adapter + 8086 2009 EtherExpress PRO/100 S Mobile Adapter 8086 200d EtherExpress PRO/100 Cardbus 8086 200e EtherExpress PRO/100 LAN+V90 Cardbus Modem + 8086 200f EtherExpress PRO/100 SR Mobile Adapter + 8086 2010 EtherExpress PRO/100 S Mobile Combo Adapter + 8086 2013 EtherExpress PRO/100 SR Mobile Combo Adapter + 8086 2016 EtherExpress PRO/100 S Mobile Adapter + 8086 2017 EtherExpress PRO/100 S Combo Mobile Adapter + 8086 2018 EtherExpress PRO/100 SR Mobile Adapter + 8086 2019 EtherExpress PRO/100 SR Combo Mobile Adapter + 8086 2101 EtherExpress PRO/100 P Mobile Adapter + 8086 2102 EtherExpress PRO/100 SP Mobile Adapter + 8086 2103 EtherExpress PRO/100 SP Mobile Adapter + 8086 2104 EtherExpress PRO/100 SP Mobile Adapter + 8086 2105 EtherExpress PRO/100 SP Mobile Adapter + 8086 2106 EtherExpress PRO/100 P Mobile Adapter + 8086 2107 EtherExpress PRO/100 Network Connection + 8086 2108 EtherExpress PRO/100 Network Connection + 8086 2200 EtherExpress PRO/100 P Mobile Combo Adapter + 8086 2201 EtherExpress PRO/100 P Mobile Combo Adapter + 8086 2202 EtherExpress PRO/100 SP Mobile Combo Adapter + 8086 2203 EtherExpress PRO/100+ MiniPCI + 8086 2204 EtherExpress PRO/100+ MiniPCI + 8086 2205 EtherExpress PRO/100 SP Mobile Combo Adapter + 8086 2206 EtherExpress PRO/100 SP Mobile Combo Adapter + 8086 2207 EtherExpress PRO/100 SP Mobile Combo Adapter + 8086 2208 EtherExpress PRO/100 P Mobile Combo Adapter + 8086 2402 EtherExpress PRO/100+ MiniPCI + 8086 2407 EtherExpress PRO/100+ MiniPCI + 8086 2408 EtherExpress PRO/100+ MiniPCI + 8086 2409 EtherExpress PRO/100+ MiniPCI + 8086 240f EtherExpress PRO/100+ MiniPCI + 8086 2410 EtherExpress PRO/100+ MiniPCI + 8086 2411 EtherExpress PRO/100+ MiniPCI + 8086 2412 EtherExpress PRO/100+ MiniPCI + 8086 2413 EtherExpress PRO/100+ MiniPCI 8086 3000 82559 Fast Ethernet LAN on Motherboard 8086 3001 82559 Fast Ethernet LOM with Basic Alert on LAN* 8086 3002 82559 Fast Ethernet LOM with Alert on LAN II* + 8086 3006 EtherExpress PRO/100 S Network Connection + 8086 3007 EtherExpress PRO/100 S Network Connection + 8086 3008 EtherExpress PRO/100 Network Connection + 8086 3010 EtherExpress PRO/100 S Network Connection + 8086 3011 EtherExpress PRO/100 S Network Connection + 8086 3012 EtherExpress PRO/100 Network Connection 122d 430FX - 82437FX TSC [Triton I] 122e 82371FB PIIX ISA [Triton I] 1230 82371FB PIIX IDE [Triton I] @@ -4992,24 +5734,38 @@ 123b 82380PB 123c 82380AB 123d 683053 Programmable Interrupt Device + 123f 82466GX Integrated Hot-Plug Controller (IHPC) 1240 752 AGP 124b 82380FB 1250 430HX - 82439HX TXC [Triton II] 1360 82806AA PCI64 Hub PCI Bridge 1361 82806AA PCI64 Hub Controller (HRes) + 1460 82870P2 P64H2 Hub PCI Bridge + 1461 82870P2 P64H2 I/OxAPIC + 1462 82870P2 P64H2 Hot Plug Controller 1960 80960RP [i960RP Microprocessor] - 101e 0438 MegaRaid 438 - 101e 0466 MegaRaid 466 - 101e 0467 MegaRaid 467 + 101e 0431 MegaRAID 431 RAID Controller + 101e 0438 MegaRAID 438 Ultra2 LVD RAID Controller + 101e 0466 MegaRAID 466 Express Plus RAID Controller + 101e 0467 MegaRAID 467 Enterprise 1500 RAID Controller + 101e 0490 MegaRAID 490 Express 300 RAID Controller + 101e 0762 MegaRAID 762 Express RAID Controller 101e 09a0 PowerEdge Expandable RAID Controller 2/SC 1028 0467 PowerEdge Expandable RAID Controller 2/DC 1028 1111 PowerEdge Expandable RAID Controller 2/SC - 103c 03a2 MegaRaid - 103c 10c6 MegaRaid 438 - 103c 10c7 MegaRaid T5 - 103c 10cc MegaRaid - 1111 1111 MegaRaid 466 - 113c 03a2 MegaRaid + 103c 03a2 MegaRAID + 103c 10c6 MegaRAID 438, HP NetRAID-3Si + 103c 10c7 MegaRAID T5, Integrated HP NetRAID + 103c 10cc MegaRAID, Integrated HP NetRAID + 103c 10cd HP NetRAID-1Si + 105a 0000 SuperTrak + 105a 2168 SuperTrak Pro + 105a 5168 SuperTrak66/100 + 1111 1111 MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC + 1111 1112 PowerEdge Expandable RAID Controller 2/SC + 113c 03a2 MegaRAID + 1962 80960RM [i960RM Microprocessor] + 105a 0000 SuperTrak SX6000 I2O CPU 1a21 82840 840 (Carmel) Chipset Host Bridge (Hub A) 1a23 82840 840 (Carmel) Chipset AGP Bridge 1a24 82840 840 (Carmel) Chipset PCI Bridge (Hub B) @@ -5034,32 +5790,54 @@ 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB AC'97 Modem 2428 82801AB PCI Bridge - 2440 82820 820 (Camino 2) Chipset ISA Bridge (ICH2) - 2442 82820 820 (Camino 2) Chipset USB (Hub A) - 2443 82820 820 (Camino 2) Chipset SMBus - 2444 82820 820 (Camino 2) Chipset USB (Hub B) - 2445 82820 820 (Camino 2) Chipset AC'97 Audio Controller - 2446 82820 820 (Camino 2) Chipset AC'97 Modem Controller - 2448 82820 820 (Camino 2) Chipset PCI (-M) - 2449 82820 (ICH2) Chipset Ethernet Controller - 244a 82820 820 (Camino 2) Chipset IDE U100 (-M) - 244b 82820 820 (Camino 2) Chipset IDE U100 - 244c 82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M) - 244e 82820 820 (Camino 2) Chipset PCI - 2485 AC'97 Audio Controller + 2440 82801BA ISA Bridge (LPC) + 2442 82801BA/BAM USB (Hub #1) + 2443 82801BA/BAM SMBus + 2444 82801BA/BAM USB (Hub #2) + 2445 82801BA/BAM AC'97 Audio + 2446 82801BA/BAM AC'97 Modem + 2448 82801BAM/CAM PCI Bridge + 2449 82801BA/BAM/CA/CAM Ethernet Controller + 244a 82801BAM IDE U100 + 244b 82801BA IDE U100 + 244c 82801BAM ISA Bridge (LPC) + 244e 82801BA/CA PCI Bridge + 2480 82801CA ISA Bridge (LPC) + 2482 82801CA/CAM USB (Hub #1) + 2483 82801CA/CAM SMBus + 2484 82801CA/CAM USB (Hub #2) + 2485 82801CA/CAM AC'97 Audio + 2486 82801CA/CAM AC'97 Modem + 2487 82801CA/CAM USB (Hub #3) + 248a 82801CAM IDE U100 + 248b 82801CA IDE U100 + 248c 82801CAM ISA Bridge (LPC) 2500 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset 2501 82820 820 (Camino) Chipset Host Bridge (MCH) 1043 801c P3C-2000 system chipset 250b 82820 820 (Camino) Chipset Host Bridge - 250f 82820 820 (Camino) Chipset PCI to AGP Bridge + 250f 82820 820 (Camino) Chipset AGP Bridge 2520 82805AA MTH Memory Translator Hub 2521 82804AA MRH-S Memory Repeater Hub for SDRAM 2530 82850 850 (Tehama) Chipset Host Bridge (MCH) 2531 82850 860 (Wombat) Chipset Host Bridge (MCH) 2532 82850 850 (Tehama) Chipset AGP Bridge 2533 82860 860 (Wombat) Chipset AGP Bridge + 2534 82860 860 (Wombat) Chipset PCI Bridge + 2540 e7500 DRAM Controller + 2541 e7500 DRAM Controller Error Reporting + 2543 e7500 HI_B Virtual PCI-to-PCI Bridge (F0) + 2544 e7500 HI_B Virtual PCI-to-PCI Bridge (F1) + 2545 e7500 HI_C Virtual PCI-to-PCI Bridge (F0) + 2546 e7500 HI_C Virtual PCI-to-PCI Bridge (F1) + 2547 e7500 HI_D Virtual PCI-to-PCI Bridge (F0) + 2548 e7500 HI_D Virtual PCI-to-PCI Bridge (F1) 3092 Integrated RAID + 3575 82830 830 Chipset Host Bridge + 3576 82830 830 Chipset AGP Bridge + 3577 82830 CGC [Chipset Graphics Controller] + 3578 82830 830 Chipset Host Bridge 5200 EtherExpress PRO/100 Intelligent Server 5201 EtherExpress PRO/100 Intelligent Server 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter @@ -5069,30 +5847,34 @@ 7020 82371SB PIIX3 USB [Natoma/Triton II] 7030 430VX - 82437VX TVX [Triton VX] 7100 430TX - 82439TX MTXC - 7110 82371AB PIIX4 ISA - 7111 82371AB PIIX4 IDE - 7112 82371AB PIIX4 USB - 7113 82371AB PIIX4 ACPI + 7110 82371AB/EB/MB PIIX4 ISA + 7111 82371AB/EB/MB PIIX4 IDE + 7112 82371AB/EB/MB PIIX4 USB + 7113 82371AB/EB/MB PIIX4 ACPI 7120 82810 GMCH [Graphics Memory Controller Hub] 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] - 7126 82810 810 Chipset Host Bridge and Memory Controller Hub + 7122 82810 DC-100 GMCH [Graphics Memory Controller Hub] + 7123 82810 DC-100 CGC [Chipset Graphics Controller] + 7124 82810E DC-133 GMCH [Graphics Memory Controller Hub] + 7125 82810E DC-133 CGC [Chipset Graphics Controller] + 7126 82810 DC-133 System and Graphics Controller + 7128 82810-M DC-100 System and Graphics Controller + 712a 82810-M DC-133 System and Graphics Controller 7180 440LX/EX - 82443LX/EX Host bridge 7181 440LX/EX - 82443LX/EX AGP bridge - 7190 440BX/ZX - 82443BX/ZX Host bridge + 7190 440BX/ZX/DX - 82443BX/ZX/DX Host bridge 0e11 0500 Armada 1750 Laptop System Chipset - 7191 440BX/ZX - 82443BX/ZX AGP bridge - 7192 440BX/ZX - 82443BX/ZX Host bridge (AGP disabled) + 1179 0001 Toshiba Tecra 8100 Laptop System Chipset + 7191 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge + 7192 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled) 0e11 0460 Armada 1700 Laptop System Chipset - 7194 82440MX I/O Controller + 7194 82440MX Host Bridge 7195 82440MX AC'97 Audio Controller 10cf 1099 QSound_SigmaTel Stac97 PCI Audio 11d4 0040 SoundMAX Integrated Digital Audio 11d4 0048 SoundMAX Integrated Digital Audio - 7198 82440MX PCI to ISA Bridge + 7196 82440MX AC'97 Modem Controller + 7198 82440MX ISA Bridge 7199 82440MX EIDE Controller 719a 82440MX USB Universal Host Controller 719b 82440MX Power Management Controller @@ -5104,7 +5886,12 @@ 7602 82372FB [PCI-to-USB UHCI] 7603 82372FB System Management Bus Controller 7800 i740 + 003d 0008 Starfighter AGP + 003d 000b Starfighter AGP 1092 0100 Stealth II G460 + 10b4 201a Lightspeed 740 + 10b4 202f Lightspeed 740 + 8086 0000 Terminator 2x/i 8086 0100 Intel740 Graphics Accelerator 84c4 450KX/GX [Orion] - 82454KX/GX PCI bridge 84c5 450KX/GX [Orion] - 82453KX/GX Memory controller @@ -5115,6 +5902,7 @@ 84e2 460GX - 84460GX AGP Bridge (GXB) 84e3 460GX - 84460GX Memory Address Controller (MAC) 84e4 460GX - 84460GX Memory Data Controller (MDC) + 84e6 460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB) 9621 Integrated RAID 9622 Integrated RAID 9641 Integrated RAID @@ -5142,12 +5930,12 @@ 5278 AIC-7852 5375 AIC-755x 5378 AIC-7850 - 5475 AIC-2930 + 5475 AIC-755x 5478 AIC-7850 5575 AVA-2930 5578 AIC-7855 5675 AIC-755x - 5678 AIC-7850 + 5678 AIC-7856 5775 AIC-755x 5778 AIC-7850 5800 AIC-5800 @@ -5155,37 +5943,38 @@ 5905 ANA-5910A/5930A/5940A ATM Adapter 6038 AIC-3860 6075 AIC-1480 / APA-1480 + 9004 7560 AIC-1480 / APA-1480 Cardbus 6078 AIC-7860 6178 AIC-7861 9004 7861 AHA-2940AU Single 6278 AIC-7860 6378 AIC-7860 - 6478 AIC-786 + 6478 AIC-786x 6578 AIC-786x - 6678 AIC-786 + 6678 AIC-786x 6778 AIC-786x 6915 ANA620xx/ANA69011A 9004 0008 ANA69011A/TX 10/100 9004 0009 ANA69011A/TX 10/100 9004 0010 ANA62022 2-port 10/100 9004 0018 ANA62044 4-port 10/100 + 9004 0019 ANA62044 4-port 10/100 9004 0020 ANA62022 2-port 10/100 9004 0028 ANA69011A/TX 10/100 9004 8008 ANA69011A/TX 64 bit 10/100 9004 8009 ANA69011A/TX 64 bit 10/100 9004 8010 ANA62022 2-port 64 bit 10/100 9004 8018 ANA62044 4-port 64 bit 10/100 + 9004 8019 ANA62044 4-port 64 bit 10/100 9004 8020 ANA62022 2-port 64 bit 10/100 9004 8028 ANA69011A/TX 64 bit 10/100 7078 AHA-294x / AIC-7870 - 7178 AHA-294x / AIC-7871 - 7278 AHA-3940 / AIC-7872 + 7178 AHA-2940/2940W / AIC-7871 + 7278 AHA-3940/3940W / AIC-7872 7378 AHA-3985 / AIC-7873 - 7478 AHA-2944 / AIC-7874 -# DJ: Where did the 3rd number come from? - 7578 AHA-3944 / AHA-3944W / 7875 -# DJ: Where did the 3rd number come from? - 7678 AHA-4944W/UW / 7876 + 7478 AHA-2944/2944W / AIC-7874 + 7578 AHA-3944/3944W / AIC-7875 + 7678 AHA-4944W/UW / AIC-7876 7778 AIC-787x 7810 AIC-7810 7815 AIC-7815 RAID+Memory Controller IC @@ -5206,49 +5995,69 @@ 7893 AIC-789x 7894 AIC-789x 7895 AHA-2940U/UW / AHA-39xx / AIC-7895 + 9004 7890 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + 9004 7891 AHA-2940U/2940UW Dual + 9004 7892 AHA-3940AU/AUW/AUWD/UWD + 9004 7894 AHA-3944AUWD 9004 7895 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + 9004 7896 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + 9004 7897 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B 7896 AIC-789x 7897 AIC-789x 8078 AIC-7880U 9004 7880 AIC-7880P Ultra/Ultra Wide SCSI Chipset - 8178 AIC-7881U + 8178 AHA-2940U/UW/D / AIC-7881U 9004 7881 AHA-2940UW SCSI Host Adapter - 8278 AHA-3940U/UW / AIC-7882U + 8278 AHA-3940U/UW/UWD / AIC-7882U 8378 AHA-3940U/UW / AIC-7883U - 8478 AHA-294x / AIC-7884U - 8578 AHA-3944U / AHA-3944UWD / 7885 - 8678 AHA-4944UW / 7886 - 8778 AIC-788x + 8478 AHA-2944UW / AIC-7884U + 8578 AHA-3944U/UWD / AIC-7885 + 8678 AHA-4944UW / AIC-7886 + 8778 AHA-2940UW Pro / AIC-788x 9004 7887 2940UW Pro Ultra-Wide SCSI Controller - 8878 7888 + 8878 AHA-2930UW / AIC-7888 + 9004 7888 AHA-2930UW SCSI Controller 8b78 ABA-1030 ec78 AHA-4944W/UW 9005 Adaptec - 0010 AHA-2940U2/W - 0011 2930U2 + 0010 AHA-2940U2/U2W + 9005 2180 AHA-2940U2 SCSI Controller + 9005 8100 AHA-2940U2B SCSI Controller + 9005 a180 AHA-2940U2W SCSI Controller + 9005 e100 AHA-2950U2B SCSI Controller + 0011 AHA-2930U2 0013 78902 9005 0003 AAA-131U2 Array1000 1 Channel RAID Controller - 001f AHA-2940U2/W / 7890 + 001f AHA-2940U2/U2W / 7890/7891 9005 000f 2940U2W SCSI Controller 9005 a180 2940U2W SCSI Controller 0020 AIC-7890 002f AIC-7890 0030 AIC-7890 003f AIC-7890 - 0050 3940U2 - 0051 3950U2D + 0050 AHA-3940U2x/395U2x + 9005 f500 AHA-3950U2B + 0051 AHA-3950U2D + 9005 b500 AHA-3950U2D 0053 AIC-7896 SCSI Controller 9005 ffff AIC-7896 SCSI Controller mainboard implementation - 005f 7896 - 0080 7892A - 0081 7892B - 0083 7892D - 008f 7892P - 00c0 7899A - 00c1 7899B - 00c3 7899D + 005f AIC-7896U2/7897U2 + 0080 AIC-7892A U160/m + 0e11 e2a0 Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter + 9005 62a0 29160N Ultra160 SCSI Controller + 9005 e220 29160LP Low Profile Ultra160 SCSI Controller + 9005 e2a0 29160 Ultra160 SCSI Controller + 0081 AIC-7892B U160/m + 9005 62a1 19160 Ultra160 SCSI Controller + 0083 AIC-7892D U160/m + 008f AIC-7892P U160/m + 00c0 AHA-3960D / AIC-7899A U160/m + 0e11 f620 Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter + 9005 f620 AHA-3960D U160/m + 00c1 AIC-7899B U160/m + 00c3 AIC-7899D U160/m 00c5 RAID subsystem HBA - 00cf 7899P + 00cf AIC-7899P U160/m 907f Atronics 2015 IDE-2015PL 919a Gigapixel Corp @@ -5256,6 +6065,9 @@ 6565 6565 9699 Omni Media Technology Inc 6565 6565 +9710 NetMos Technology + 9815 VScom 021H-EP2 2 port parallel adaptor + 9835 2xserial 1xparallel port adapter a0a0 AOPEN Inc. a0f1 UNISYS Corporation a200 NEC Corporation @@ -5275,7 +6087,9 @@ cccc Catapult Communications d4d4 Dy4 Systems Inc 0601 PCI Mezzanine Card +d531 I+ME ACTIA GmbH d84d Exsys +dead Indigita Corporation e000 Winbond e000 W89C940 e159 Tiger Jet Network Inc. @@ -5285,6 +6099,7 @@ e4bf EKF Elektronik GmbH ea01 Eagle Technology eabb Aashima Technology B.V. +eace Endace Measurement Systems, Ltd ecc0 Echo Corporation edd8 ARK Logic Inc a091 1000PV [Stingray] @@ -5292,6 +6107,7 @@ a0a1 2000MT a0a9 2000MI fa57 Fast Search & Transfer ASA +febd Ultraview Corp. feda Epigram Inc fffe VMWare Inc 0710 Virtual SVGA diff -urN linux-2.4.18/drivers/pcmcia/Config.in linux-2.4.19-pre5/drivers/pcmcia/Config.in --- linux-2.4.18/drivers/pcmcia/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/Config.in Sat Mar 30 22:55:40 2002 @@ -24,5 +24,6 @@ dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA fi fi +dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA endmenu diff -urN linux-2.4.18/drivers/pcmcia/Makefile linux-2.4.19-pre5/drivers/pcmcia/Makefile --- linux-2.4.18/drivers/pcmcia/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/Makefile Sat Mar 30 22:55:40 2002 @@ -62,22 +62,24 @@ obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o sa1100_cs-objs-y := sa1100_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o -sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o -sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o +sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o +sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o +sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o -sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o +sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o -sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o -sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o -sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o -sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o -sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o +sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o -sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o -sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o +sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o +sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/pcmcia/au1000_generic.c linux-2.4.19-pre5/drivers/pcmcia/au1000_generic.c --- linux-2.4.18/drivers/pcmcia/au1000_generic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/au1000_generic.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,696 @@ +/* + * + * Alchemy Semi Au1000 pcmcia driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug; +#endif + +MODULE_AUTHOR("Pete Popov, MontaVista Software "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); + +#define MAP_SIZE 0x1000000 + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +static struct au1000_pcmcia_socket *pcmcia_socket; +static int socket_count; + + +/* Returned by the low-level PCMCIA interface: */ +static struct pcmcia_low_level *pcmcia_low_level; + +/* Event poll timer structure */ +static struct timer_list poll_timer; + + +/* Prototypes for routines which are used internally: */ + +static int au1000_pcmcia_driver_init(void); +static void au1000_pcmcia_driver_shutdown(void); +static void au1000_pcmcia_task_handler(void *data); +static void au1000_pcmcia_poll_event(u32 data); +static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs); +static struct tq_struct au1000_pcmcia_task; + +#ifdef CONFIG_PROC_FS +static int au1000_pcmcia_proc_status(char *buf, char **start, + off_t pos, int count, int *eof, void *data); +#endif + + +/* Prototypes for operations which are exported to the + * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: + */ + +static int au1000_pcmcia_init(u32 sock); +static int au1000_pcmcia_suspend(u32 sock); +static int au1000_pcmcia_register_callback(u32 sock, + void (*handler)(void *, u32), void *info); +static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap); +static int au1000_pcmcia_get_status(u32 sock, u_int *value); +static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem); +static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem); +#ifdef CONFIG_PROC_FS +static void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base); +#endif + +static struct pccard_operations au1000_pcmcia_operations = { + au1000_pcmcia_init, + au1000_pcmcia_suspend, + au1000_pcmcia_register_callback, + au1000_pcmcia_inquire_socket, + au1000_pcmcia_get_status, + au1000_pcmcia_get_socket, + au1000_pcmcia_set_socket, + au1000_pcmcia_get_io_map, + au1000_pcmcia_set_io_map, + au1000_pcmcia_get_mem_map, + au1000_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + au1000_pcmcia_proc_setup +#endif +}; + +static int __init au1000_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state; + unsigned int i; + unsigned long timing3; + + printk("\nAu1x00 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + + if(info.Revision!=CS_RELEASE_CODE){ + printk(KERN_ERR "Card Services release codes do not match\n"); + return -1; + } + +#ifdef CONFIG_MIPS_PB1000 + pcmcia_low_level=&pb1000_pcmcia_ops; +#elif defined(CONFIG_MIPS_PB1500) + pcmcia_low_level=&pb1500_pcmcia_ops; +#else +#error Unsupported AU1000 board. +#endif + + pcmcia_init.handler=au1000_pcmcia_interrupt; + if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) { + printk(KERN_ERR "Unable to initialize PCMCIA service.\n"); + return -EIO; + } + + /* setup the static bus controller */ + timing3 = 0x100e3a07; + writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + writel(timing3, MEM_STTIME3); + writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + au_sync_delay(1); + + pcmcia_socket = + kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, + GFP_KERNEL); + if (!pcmcia_socket) { + printk(KERN_ERR "Card Services can't get memory \n"); + return -1; + } + memset(pcmcia_socket, 0, + sizeof(struct au1000_pcmcia_socket) * socket_count); + + for(i=0; i < socket_count; i++) { + + if(pcmcia_low_level->socket_state(i, &state)<0){ + printk(KERN_ERR "Unable to get PCMCIA status\n"); + return -EIO; + } + pcmcia_socket[i].k_state=state; + pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; + + if (i == 0) { + pcmcia_socket[i].virt_io = + (u32)ioremap(0xC0000000, 0x1000); + pcmcia_socket[i].phys_attr = 0xC4000000; + pcmcia_socket[i].phys_mem = 0xC8000000; + } + else { + printk(KERN_ERR "au1000: socket 1 not supported\n"); + return 1; + } + } + + /* Only advertise as many sockets as we can detect: */ + if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){ + printk(KERN_ERR "Unable to register socket service routine\n"); + return -ENXIO; + } + + /* Start the event poll timer. + * It will reschedule by itself afterwards. + */ + au1000_pcmcia_poll_event(0); + + DEBUG(1, "au1000: initialization complete\n"); + return 0; + +} /* au1000_pcmcia_driver_init() */ + +module_init(au1000_pcmcia_driver_init); + +static void __exit au1000_pcmcia_driver_shutdown(void) +{ + int i; + + del_timer_sync(&poll_timer); + unregister_ss_entry(&au1000_pcmcia_operations); + pcmcia_low_level->shutdown(); + flush_scheduled_tasks(); + for(i=0; i < socket_count; i++) { + if (pcmcia_socket[i].virt_io) + iounmap((void *)pcmcia_socket[i].virt_io); + } + DEBUG(1, "au1000: shutdown complete\n"); +} + +module_exit(au1000_pcmcia_driver_shutdown); + +static int au1000_pcmcia_init(unsigned int sock) { return 0; } + +static int au1000_pcmcia_suspend(unsigned int sock) +{ + return 0; +} + + +static inline unsigned +au1000_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events=0; + + if(state->detect!=prev_state->detect){ + DEBUG(2, "%s(): card detect value %u\n", + __FUNCTION__, state->detect); + events |= mask&SS_DETECT; + } + + + if(state->ready!=prev_state->ready){ + DEBUG(2, "%s(): card ready value %u\n", + __FUNCTION__, state->ready); + events |= mask&((flags&SS_IOCARD)?0:SS_READY); + } + + *prev_state=*state; + return events; + +} /* au1000_pcmcia_events() */ + + +/* + * Au1000_pcmcia_task_handler() + * Processes socket events. + */ +static void au1000_pcmcia_task_handler(void *data) +{ + struct pcmcia_state state; + int i, events, irq_status; + + for(i=0; isocket_state(i, &state))<0) + printk(KERN_ERR "low-level PCMCIA error\n"); + + events = au1000_pcmcia_events(&state, + &pcmcia_socket[i].k_state, + pcmcia_socket[i].cs_state.csc_mask, + pcmcia_socket[i].cs_state.flags); + if(pcmcia_socket[i].handler!=NULL) { + pcmcia_socket[i].handler(pcmcia_socket[i].handler_info, + events); + } + } + +} /* au1000_pcmcia_task_handler() */ + +static struct tq_struct au1000_pcmcia_task = { + routine: au1000_pcmcia_task_handler +}; + + +static void au1000_pcmcia_poll_event(u32 dummy) +{ + poll_timer.function = au1000_pcmcia_poll_event; + poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; + add_timer(&poll_timer); + schedule_task(&au1000_pcmcia_task); +} + + +/* + * au1000_pcmcia_interrupt() + * The actual interrupt work is performed by au1000_pcmcia_task(), + * because the Card Services event handling code performs scheduling + * operations which cannot be executed from within an interrupt context. + */ +static void +au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + schedule_task(&au1000_pcmcia_task); +} + + +static int +au1000_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), void *info) +{ + if(handler==NULL){ + pcmcia_socket[sock].handler=NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + pcmcia_socket[sock].handler=handler; + pcmcia_socket[sock].handler_info=info; + } + return 0; +} + + +/* au1000_pcmcia_inquire_socket() + * + * From the sa1100 socket driver : + * + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). We set + * SS_CAP_STATIC_MAP, which disables the memory resource database check. + * (Mapped memory is set up within the socket driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * Returns: 0 on success, -1 if no pin has been configured for `sock' + */ +static int au1000_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct pcmcia_irq_info irq_info; + + if(sock > socket_count){ + printk(KERN_ERR "au1000: socket %u not configured\n", sock); + return -1; + } + + /* from the sa1100_generic driver: */ + + /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + */ + cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + + irq_info.sock=sock; + irq_info.irq=-1; + + if(pcmcia_low_level->get_irq_info(&irq_info)<0){ + printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock); + return -1; + } + + cap->irq_mask=0; + cap->map_size=MAP_SIZE; + cap->pci_irq=irq_info.irq; + cap->io_offset=pcmcia_socket[sock].virt_io; + + return 0; + +} /* au1000_pcmcia_inquire_socket() */ + + +static int +au1000_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct pcmcia_state state; + + + if((pcmcia_low_level->socket_state(sock, &state))<0){ + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -1; + } + + pcmcia_socket[sock].k_state = state; + + *status = state.detect?SS_DETECT:0; + + *status |= state.ready?SS_READY:0; + + *status |= pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; + + if(pcmcia_socket[sock].cs_state.flags&SS_IOCARD) + *status |= state.bvd1?SS_STSCHG:0; + else { + if(state.bvd1==0) + *status |= SS_BATDEAD; + else if(state.bvd2 == 0) + *status |= SS_BATWARN; + } + + *status|=state.vs_3v?SS_3VCARD:0; + + *status|=state.vs_Xv?SS_XVCARD:0; + + DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n", + (*status&SS_DETECT)?"DETECT ":"", + (*status&SS_READY)?"READY ":"", + (*status&SS_BATDEAD)?"BATDEAD ":"", + (*status&SS_BATWARN)?"BATWARN ":"", + (*status&SS_POWERON)?"POWERON ":"", + (*status&SS_STSCHG)?"STSCHG ":"", + (*status&SS_3VCARD)?"3VCARD ":"", + (*status&SS_XVCARD)?"XVCARD ":""); + + return 0; + +} /* au1000_pcmcia_get_status() */ + + +static int +au1000_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + *state = pcmcia_socket[sock].cs_state; + return 0; +} + + +static int +au1000_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct pcmcia_configure configure; + + DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" + "\tVcc %d Vpp %d irq %d\n", + (state->csc_mask==0)?"":"", + (state->csc_mask&SS_DETECT)?"DETECT ":"", + (state->csc_mask&SS_READY)?"READY ":"", + (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", + (state->csc_mask&SS_BATWARN)?"BATWARN ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + state->Vcc, state->Vpp, state->io_irq); + + configure.sock=sock; + configure.vcc=state->Vcc; + configure.vpp=state->Vpp; + configure.output=(state->flags&SS_OUTPUT_ENA)?1:0; + configure.speaker=(state->flags&SS_SPKR_ENA)?1:0; + configure.reset=(state->flags&SS_RESET)?1:0; + + if(pcmcia_low_level->configure_socket(&configure)<0){ + printk(KERN_ERR "Unable to configure socket %u\n", sock); + return -1; + } + + pcmcia_socket[sock].cs_state = *state; + return 0; + +} /* au1000_pcmcia_set_socket() */ + + +static int +au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock); + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].io_map[map->map]; + return 0; +} + + +int +au1000_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + unsigned int speed; + unsigned long start; + + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; + pcmcia_socket[sock].speed_io=speed; + } + + start=map->start; + + if(map->stop==1) { + map->stop=PAGE_SIZE-1; + } + + map->start=pcmcia_socket[sock].virt_io; + map->stop=map->start+(map->stop-start); + pcmcia_socket[sock].io_map[map->map]=*map; + DEBUG(3, "set_io_map %d start %x stop %x\n", + map->map, map->start, map->stop); + return 0; + +} /* au1000_pcmcia_set_io_map() */ + + +static int +au1000_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + + if(map->map>=MAX_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].mem_map[map->map]; + return 0; +} + + +static int +au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + unsigned int speed; + unsigned long start; + u_long flags; + + if(map->map>=MAX_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_MEM_SPEED; + + /* TBD */ + if(map->flags&MAP_ATTRIB){ + pcmcia_socket[sock].speed_attr=speed; + } + else { + pcmcia_socket[sock].speed_mem=speed; + } + } + + save_flags(flags); + cli(); + start=map->sys_start; + + if(map->sys_stop==0) + map->sys_stop=MAP_SIZE-1; + + if (map->flags & MAP_ATTRIB) { + map->sys_start = pcmcia_socket[sock].phys_attr + + map->card_start; + } + else { + map->sys_start = pcmcia_socket[sock].phys_mem + + map->card_start; + } + + map->sys_stop=map->sys_start+(map->sys_stop-start); + pcmcia_socket[sock].mem_map[map->map]=*map; + restore_flags(flags); + DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n", + map->map, map->sys_start, map->sys_stop, + map->card_start); + return 0; + +} /* au1000_pcmcia_set_mem_map() */ + + +#if defined(CONFIG_PROC_FS) + +static void +au1000_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + if((entry=create_proc_entry("status", 0, base))==NULL){ + printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc=au1000_pcmcia_proc_status; + entry->data=(void *)sock; +} + + +/* au1000_pcmcia_proc_status() + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int +au1000_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + char *p=buf; + unsigned int sock=(unsigned int)data; + + p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"detect ":"", + pcmcia_socket[sock].k_state.ready?"ready ":"", + pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", + pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", + pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", + pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", + pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); + + p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", + pcmcia_socket[sock].k_state.ready?"SS_READY ":"", + pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + (pcmcia_socket[sock].cs_state.flags&SS_IOCARD && + pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", + pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", + pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); + + p+=sprintf(p, "mask : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ + "SS_DETECT ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ + "SS_READY ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ + "SS_BATDEAD ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ + "SS_BATWARN ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ + "SS_STSCHG ":""); + + p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ + "SS_PWR_AUTO ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + pcmcia_socket[sock].cs_state.flags&SS_RESET?\ + "SS_RESET ":"", + pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ + "SS_SPKR_ENA ":"", + pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ + "SS_OUTPUT_ENA ":""); + + p+=sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp); + p+=sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq); + p+=sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io); + p+=sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr); + p+=sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem); + return p-buf; +} + + +#endif /* defined(CONFIG_PROC_FS) */ diff -urN linux-2.4.18/drivers/pcmcia/au1000_pb1000.c linux-2.4.19-pre5/drivers/pcmcia/au1000_pb1000.c --- linux-2.4.18/drivers/pcmcia/au1000_pb1000.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/au1000_pb1000.c Sat Mar 30 22:55:28 2002 @@ -0,0 +1,307 @@ +/* + * + * Alchemy Semi PB1000 board specific pcmcia routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include +#include + + +extern struct pcmcia_x_table x_table; + +static int pb1000_pcmcia_init(struct pcmcia_init *init) +{ + u32 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + + writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ + au_sync_delay(100); + writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ + au_sync(); + + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + + /* There's two sockets, but only the first one, 0, is used and tested */ + return 1; +} + +static int pb1000_pcmcia_shutdown(void) +{ + u16 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + return 0; +} + +static int +pb1000_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) +{ + u16 levels, pcr; + unsigned char vs; + + levels = readw(PB1000_ACR1); + pcr = readw(PB1000_PCR); + + state->ready = 0; + state->vs_Xv = 0; + state->vs_3v = 0; + state->detect = 0; + + /* + * This is tricky. The READY pin is also the #IRQ pin. We'll treat + * READY as #IRQ and set state->ready to 1 whenever state->detect + * is true. + */ + + /* + * CD1/2 are active low; so are the VSS pins; Ready is active high + */ + if (sock == 0) { + if (!(levels & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2))) { + state->detect = 1; + vs = (levels >> 4) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else if (sock == 1) { + if (!(levels & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2))) { + state->detect = 1; + vs = (levels >> 12) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else { + printk(KERN_ERR "pb1000 socket_state bad sock %d\n", sock); + } + + if (state->detect) + state->ready = 1; + + state->bvd1=1; + state->bvd2=1; + state->wrprot=0; + return 1; +} + + +static int pb1000_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + + if(info->sock > PCMCIA_MAX_SOCK) return -1; + + if(info->sock == 0) + info->irq = AU1000_GPIO_15; + else + info->irq = -1; + + return 0; +} + + +static int +pb1000_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + u16 pcr; + + if(configure->sock > PCMCIA_MAX_SOCK) return -1; + + pcr = readw(PB1000_PCR); + + if (configure->sock == 0) { + pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | + PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); + } + else { + pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | + PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); + } + + pcr &= ~PCR_SLOT_0_RST; + /* + writew(pcr, PB1000_PCR); + au_sync_delay(200); + */ + DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", + configure->vcc, configure->vpp, pcr); + switch(configure->vcc){ + case 0: /* Vcc 0 */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 50: /* Vcc 5V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 33: /* Vcc 3.3V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + default: /* what's this ? */ + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); + printk(KERN_ERR "%s: bad Vcc %d\n", + __FUNCTION__, configure->vcc); + break; + } + + pcr &= ~(PCR_SLOT_0_RST); + if (configure->reset) { + pcr |= PCR_SLOT_0_RST; + } + writew(pcr, PB1000_PCR); + au_sync_delay(300); + return 0; +} + +struct pcmcia_low_level pb1000_pcmcia_ops = { + pb1000_pcmcia_init, + pb1000_pcmcia_shutdown, + pb1000_pcmcia_socket_state, + pb1000_pcmcia_get_irq_info, + pb1000_pcmcia_configure_socket +}; + diff -urN linux-2.4.18/drivers/pcmcia/cs.c linux-2.4.19-pre5/drivers/pcmcia/cs.c --- linux-2.4.18/drivers/pcmcia/cs.c Sun Dec 23 16:23:46 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/cs.c Sat Mar 30 22:55:28 2002 @@ -1268,7 +1268,7 @@ } else c = CONFIG(handle); if ((c != NULL) && (c->state & CONFIG_LOCKED) && - (c->IntType & INT_MEMORY_AND_IO)) { + (c->IntType & (INT_MEMORY_AND_IO|INT_ZOOMED_VIDEO))) { u_char reg; if (c->Present & PRESENT_PIN_REPLACE) { read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); @@ -1696,6 +1696,8 @@ c->Attributes = req->Attributes; if (req->IntType & INT_MEMORY_AND_IO) s->socket.flags |= SS_IOCARD; + if (req->IntType & INT_ZOOMED_VIDEO) + s->socket.flags |= SS_ZVCARD|SS_IOCARD; if (req->Attributes & CONF_ENABLE_DMA) s->socket.flags |= SS_DMA_MODE; if (req->Attributes & CONF_ENABLE_SPKR) diff -urN linux-2.4.18/drivers/pcmcia/pci_socket.h linux-2.4.19-pre5/drivers/pcmcia/pci_socket.h --- linux-2.4.18/drivers/pcmcia/pci_socket.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/pci_socket.h Sat Mar 30 22:55:28 2002 @@ -23,7 +23,9 @@ struct socket_info_t *pcmcia_socket; struct tq_struct tq_task; struct timer_list poll_timer; - + /* Zoom video behaviour is so chip specific its not worth adding + this to _ops */ + void (*zoom_video)(struct pci_socket *, int); /* A few words of private data for the low-level driver.. */ unsigned int private[8]; } pci_socket_t; diff -urN linux-2.4.18/drivers/pcmcia/ricoh.h linux-2.4.19-pre5/drivers/pcmcia/ricoh.h --- linux-2.4.18/drivers/pcmcia/ricoh.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/ricoh.h Sat Mar 30 22:55:40 2002 @@ -110,6 +110,8 @@ #define RL5C4XX_CMD_SHIFT 4 #define RL5C4XX_HOLD_MASK 0x1c00 #define RL5C4XX_HOLD_SHIFT 10 +#define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */ +#define RL5C4XX_ZV_ENABLE 0x08 #ifdef __YENTA_H @@ -134,14 +136,45 @@ return 0; } +static void ricoh_zoom_video(pci_socket_t *socket, int onoff) +{ + u8 reg; + + reg = exca_readb(socket, RL5C4XX_MISC_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= RL5C4XX_ZV_ENABLE; + else + reg &= ~RL5C4XX_ZV_ENABLE; + + exca_writeb(socket, RL5C4XX_MISC_CONTROL, reg); +} + +static void ricoh_set_zv(pci_socket_t *socket) +{ + if(socket->dev->vendor == PCI_VENDOR_ID_RICOH) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_RICOH_RL5C478: + socket->zoom_video = ricoh_zoom_video; + break; + } + } +} + + static int ricoh_init(pci_socket_t *socket) { yenta_init(socket); + ricoh_set_zv(socket); config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); + return 0; } diff -urN linux-2.4.18/drivers/pcmcia/sa1100.h linux-2.4.19-pre5/drivers/pcmcia/sa1100.h --- linux-2.4.18/drivers/pcmcia/sa1100.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100.h Sat Mar 30 22:55:40 2002 @@ -38,9 +38,7 @@ #include #include #include "cs_internal.h" - -#include - +#include "sa1100_generic.h" /* MECR: Expansion Memory Configuration Register * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) @@ -157,15 +155,24 @@ * use when responding to a Card Services query of some kind. */ struct sa1100_pcmcia_socket { + /* + * Core PCMCIA state + */ socket_state_t cs_state; - struct pcmcia_state k_state; - unsigned int irq; - void (*handler)(void *, unsigned int); - void *handler_info; pccard_io_map io_map[MAX_IO_WIN]; pccard_mem_map mem_map[MAX_WIN]; - ioaddr_t virt_io, phys_attr, phys_mem; + void (*handler)(void *, unsigned int); + void *handler_info; + + struct pcmcia_state k_state; + ioaddr_t phys_attr, phys_mem; + void *virt_io; unsigned short speed_io, speed_attr, speed_mem; + + /* + * Info from low level handler + */ + unsigned int irq; }; @@ -189,6 +196,7 @@ extern struct pcmcia_low_level gcplus_pcmcia_ops; extern struct pcmcia_low_level xp860_pcmcia_ops; extern struct pcmcia_low_level yopy_pcmcia_ops; +extern struct pcmcia_low_level shannon_pcmcia_ops; extern struct pcmcia_low_level pangolin_pcmcia_ops; extern struct pcmcia_low_level freebird_pcmcia_ops; extern struct pcmcia_low_level pfs168_pcmcia_ops; @@ -198,5 +206,6 @@ extern struct pcmcia_low_level graphicsmaster_pcmcia_ops; extern struct pcmcia_low_level adsbitsy_pcmcia_ops; extern struct pcmcia_low_level stork_pcmcia_ops; +extern struct pcmcia_low_level badge4_pcmcia_ops; #endif /* !defined(_PCMCIA_SA1100_H) */ diff -urN linux-2.4.18/drivers/pcmcia/sa1100_adsbitsy.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_adsbitsy.c --- linux-2.4.18/drivers/pcmcia/sa1100_adsbitsy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_adsbitsy.c Sat Mar 30 22:55:40 2002 @@ -12,205 +12,83 @@ #include #include -#include #include -#include -#include + +#include "sa1100_generic.h" +#include "sa1111_generic.h" static int adsbitsy_pcmcia_init(struct pcmcia_init *init) { - int return_val=0; - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* Disable Power 3.3V/5V for PCMCIA/CF */ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master CF (1) BVD1", NULL); - + /* Why? */ MECR = 0x09430943; - return (return_val<0) ? -1 : 2; -} - -static int adsbitsy_pcmcia_shutdown(void) -{ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array) -{ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; + return sa1111_pcmcia_init(init); } -static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure) +static int +adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long pccr=PCCR, gpio=PA_DWR; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - switch(configure->sock){ + switch (conf->sock) { case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio |= GPIO_GPIO0 | GPIO_GPIO1; - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio &= ~GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio |= GPIO_GPIO0; - break; - + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO2; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO3; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - default: return -1; } - PCCR = pccr; - PA_DWR = gpio; + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } - return 0; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } + + return ret; } struct pcmcia_low_level adsbitsy_pcmcia_ops = { - adsbitsy_pcmcia_init, - adsbitsy_pcmcia_shutdown, - adsbitsy_pcmcia_socket_state, - adsbitsy_pcmcia_get_irq_info, - adsbitsy_pcmcia_configure_socket + init: adsbitsy_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: adsbitsy_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_assabet.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_assabet.c --- linux-2.4.18/drivers/pcmcia/sa1100_assabet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_assabet.c Sat Mar 30 22:55:40 2002 @@ -9,141 +9,194 @@ #include #include -#include #include -static int assabet_pcmcia_init(struct pcmcia_init *init){ - int irq, res; +#include "sa1100_generic.h" - /* Enable CF bus: */ - ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); +static struct irqs { + int irq; + unsigned int gpio; + const char *str; +} irqs[] = { + { ASSABET_IRQ_GPIO_CF_CD, ASSABET_GPIO_CF_CD, "CF_CD" }, + { ASSABET_IRQ_GPIO_CF_BVD2, ASSABET_GPIO_CF_BVD2, "CF_BVD2" }, + { ASSABET_IRQ_GPIO_CF_BVD1, ASSABET_GPIO_CF_BVD1, "CF_BVD1" }, +}; - /* All those are inputs */ - GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ); - - /* Set transition detect */ - set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE ); - - /* Register interrupts */ - irq = ASSABET_IRQ_GPIO_CF_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); - if( res < 0 ) goto irq_err; - irq = ASSABET_IRQ_GPIO_CF_BVD2; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); - if( res < 0 ) goto irq_err; - irq = ASSABET_IRQ_GPIO_CF_BVD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); - if( res < 0 ) goto irq_err; - - /* There's only one slot, but it's "Slot 1": */ - return 2; - -irq_err: - printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq ); - return -1; -} - -static int assabet_pcmcia_shutdown(void) +static int assabet_pcmcia_init(struct pcmcia_init *init) { - /* disable IRQs */ - free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL ); - free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL ); - free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL ); - - /* Disable CF bus: */ - ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF); - - return 0; -} - -static int assabet_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long levels; + int i, res; - if(state_array->size<2) return -1; + /* Set transition detect */ + set_GPIO_IRQ_edge(ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE); - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); + /* Register interrupts */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } + + /* There's only one slot, but it's "Slot 1": */ + return 2; + + irq_err: + printk(KERN_ERR "%s: request for IRQ%d failed\n", + __FUNCTION__, irqs[i].irq); - levels=GPLR; + while (i--) + free_irq(irqs[i].irq, NULL); - state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0; + return -1; +} - state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0; +/* + * Release all resources. + */ +static int assabet_pcmcia_shutdown(void) +{ + int i; - state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0; + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + + return 0; +} - state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0; +static int +assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + unsigned long levels; - state_array->state[1].wrprot=0; /* Not available on Assabet. */ + if (state_array->size < 2) + return -1; - state_array->state[1].vs_3v=1; /* Can only apply 3.3V on Assabet. */ + levels = GPLR; - state_array->state[1].vs_Xv=0; + state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; + state_array->state[1].ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; + state_array->state[1].bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; + state_array->state[1].bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; + state_array->state[1].wrprot = 0; /* Not available on Assabet. */ + state_array->state[1].vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state_array->state[1].vs_Xv = 0; - return 1; + return 1; } -static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - if(info->sock>1) return -1; +static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (info->sock > 1) + return -1; - if(info->sock==1) - info->irq=ASSABET_IRQ_GPIO_CF_IRQ; + if (info->sock == 1) + info->irq = ASSABET_IRQ_GPIO_CF_IRQ; - return 0; + return 0; } -static int assabet_pcmcia_configure_socket(const struct pcmcia_configure - *configure) +static int +assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure) { - unsigned long value, flags; - - if(configure->sock>1) return -1; - - if(configure->sock==0) return 0; + unsigned int mask; - save_flags_cli(flags); + if (configure->sock > 1) + return -1; - value = BCR_value; + if (configure->sock == 0) + return 0; - switch(configure->vcc){ - case 0: - value &= ~ASSABET_BCR_CF_PWR; - break; + switch (configure->vcc) { + case 0: + mask = 0; + break; + + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); + + case 33: /* Can only apply 3.3V to the CF slot. */ + mask = ASSABET_BCR_CF_PWR; + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + configure->vcc); + return -1; + } + + /* Silently ignore Vpp, output enable, speaker enable. */ + + if (configure->reset) + mask |= ASSABET_BCR_CF_RST; + + ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask); + + /* + * Handle suspend mode properly. This prevents a + * flood of IRQs from the CF device. + */ + if (configure->irq) + enable_irq(ASSABET_IRQ_GPIO_CF_IRQ); + else + disable_irq(ASSABET_IRQ_GPIO_CF_IRQ); - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); - - case 33: /* Can only apply 3.3V to the CF slot. */ - value |= ASSABET_BCR_CF_PWR; - break; + return 0; +} - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - restore_flags(flags); - return -1; - } +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static int assabet_pcmcia_socket_init(int sock) +{ + int i; - value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST); + if (sock == 1) { + /* + * Enable CF bus + */ + ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); + } - /* Silently ignore Vpp, output enable, speaker enable. */ + return 0; +} - ASSABET_BCR = BCR_value = value; +/* + * Disable card status IRQs on suspend. + */ +static int assabet_pcmcia_socket_suspend(int sock) +{ + int i; - restore_flags(flags); + if (sock == 1) { + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + + /* + * Tristate the CF bus signals. Also assert CF + * reset as per user guide page 4-11. + */ + ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST); + } - return 0; + return 0; } struct pcmcia_low_level assabet_pcmcia_ops = { - assabet_pcmcia_init, - assabet_pcmcia_shutdown, - assabet_pcmcia_socket_state, - assabet_pcmcia_get_irq_info, - assabet_pcmcia_configure_socket + init: assabet_pcmcia_init, + shutdown: assabet_pcmcia_shutdown, + socket_state: assabet_pcmcia_socket_state, + get_irq_info: assabet_pcmcia_get_irq_info, + configure_socket: assabet_pcmcia_configure_socket, + + socket_init: assabet_pcmcia_socket_init, + socket_suspend: assabet_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_badge4.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_badge4.c --- linux-2.4.18/drivers/pcmcia/sa1100_badge4.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_badge4.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,172 @@ +/* + * linux/drivers/pcmcia/sa1100_badge4.c + * + * BadgePAD 4 PCMCIA specific routines + * + * Christopher Hoover + * + * Copyright (C) 2002 Hewlett-Packard Company + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include + +#include +#include +#include + +#include "sa1100_generic.h" +#include "sa1111_generic.h" + +/* + * BadgePAD 4 Details + * + * PCM Vcc: + * + * PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3 + * on JP6) or 5V (short pins 3 and 5 on JP6). N.B., 5V supply rail + * is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24). + * + * PCM Vpp: + * + * PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4 + * on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6). N.B., 12V + * operation requires that the power supply actually supply 12V. + * + * CF Vcc: + * + * CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1 + * and 2 on JP10) or 5V (short pins 2 and 3 on JP10). The note above + * about the 5V supply rail applies. + * + * There's no way programmatically to determine how a given board is + * jumpered. This code assumes a default jumpering: 5V PCM Vcc (pins + * 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and + * no jumpering for CF Vcc. If this isn't correct, Override these + * defaults with a pcmv setup argument: pcmv=,,. E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp, + * and 5.0V CF Vcc. + * + */ + +static int badge4_pcmvcc = 50; +static int badge4_pcmvpp = 50; +static int badge4_cfvcc = 0; + +static int badge4_pcmcia_init(struct pcmcia_init *init) +{ + printk(KERN_INFO __FUNCTION__ + ": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", + badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); + + return sa1111_pcmcia_init(init); +} + +static int badge4_pcmcia_shutdown(void) +{ + int rc = sa1111_pcmcia_shutdown(); + + /* be sure to disable 5V use */ + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0); + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0); + + return rc; +} + +static void complain_about_jumpering(const char *whom, + const char *supply, + int given, int wanted) +{ + printk(KERN_ERR + "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation" + "; re-jumper the board and/or use pcmv=xx,xx,xx\n", + whom, supply, + wanted / 10, wanted % 10, + supply, + given / 10, given % 10); +} + +static unsigned badge4_need_5V_bitmap = 0; + +static int +badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + int ret; + + switch (conf->sock) { + case 0: + if ((conf->vcc != 0) && + (conf->vcc != badge4_pcmvcc)) { + complain_about_jumpering(__FUNCTION__, "pcmvcc", + badge4_pcmvcc, conf->vcc); + return -1; + } + if ((conf->vpp != 0) && + (conf->vpp != badge4_pcmvpp)) { + complain_about_jumpering(__FUNCTION__, "pcmvpp", + badge4_pcmvpp, conf->vpp); + return -1; + } + break; + + case 1: + if ((conf->vcc != 0) && + (conf->vcc != badge4_cfvcc)) { + complain_about_jumpering(__FUNCTION__, "cfvcc", + badge4_cfvcc, conf->vcc); + return -1; + } + break; + + default: + return -1; + } + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + int need5V; + + local_irq_save(flags); + + need5V = ((conf->vcc == 50) || (conf->vpp == 50)); + + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V); + + local_irq_restore(flags); + } + + return 0; +} + +struct pcmcia_low_level badge4_pcmcia_ops = { + init: badge4_pcmcia_init, + shutdown: badge4_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: badge4_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, +}; + + +static int __init pcmv_setup(char *s) +{ + int v[4]; + + s = get_options(s, ARRAY_SIZE(v), v); + + if (v[0] >= 1) badge4_pcmvcc = v[1]; + if (v[0] >= 2) badge4_pcmvpp = v[2]; + if (v[0] >= 3) badge4_cfvcc = v[3]; + + return 1; +} + +__setup("pcmv=", pcmv_setup); diff -urN linux-2.4.18/drivers/pcmcia/sa1100_cerf.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_cerf.c --- linux-2.4.18/drivers/pcmcia/sa1100_cerf.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_cerf.c Sat Mar 30 22:55:40 2002 @@ -10,40 +10,55 @@ #include #include -#include +#include "sa1100_generic.h" +#ifdef CONFIG_SA1100_CERF_CPLD +#define CERF_SOCKET 0 +#else +#define CERF_SOCKET 1 +#endif -static int cerf_pcmcia_init(struct pcmcia_init *init){ - int irq, res; +static struct irqs { + int irq; + unsigned int gpio; + const char *str; +} irqs[] = { + { IRQ_GPIO_CF_CD, GPIO_CF_CD, "CF_CD" }, + { IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" }, + { IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" } +}; - GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); - GPDR |= (GPIO_CF_RESET); +static int cerf_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; - set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); - irq = IRQ_GPIO_CF_CD; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_CF_BVD2; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_CF_BVD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); - if( res < 0 ) goto irq_err; + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + goto irq_err; + } return 2; -irq_err: - printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); + irq_err: + printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq); + + while (i--) + free_irq(irqs[i].irq, NULL); + return -1; } static int cerf_pcmcia_shutdown(void) { - free_irq( IRQ_GPIO_CF_CD, NULL ); - free_irq( IRQ_GPIO_CF_BVD2, NULL ); - free_irq( IRQ_GPIO_CF_BVD1, NULL ); + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); return 0; } @@ -51,31 +66,18 @@ static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array){ unsigned long levels; -#ifdef CONFIG_SA1100_CERF_CPLD - int i = 0; -#else - int i = 1; -#endif + int i = CERF_SOCKET; if(state_array->size<2) return -1; - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - levels=GPLR; state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; - state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; - state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; - state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; - state_array->state[i].wrprot=0; - state_array->state[i].vs_3v=1; - state_array->state[i].vs_Xv=0; return 1; @@ -85,11 +87,7 @@ if(info->sock>1) return -1; -#ifdef CONFIG_SA1100_CERF_CPLD - if(info->sock==0) -#else - if(info->sock==1) -#endif + if (info->sock == CERF_SOCKET) info->irq=IRQ_GPIO_CF_IRQ; return 0; @@ -98,20 +96,12 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure *configure) { - unsigned long flags; - if(configure->sock>1) return -1; -#ifdef CONFIG_SA1100_CERF_CPLD - if(configure->sock==1) -#else - if(configure->sock==0) -#endif + if (configure->sock != CERF_SOCKET) return 0; - save_flags_cli(flags); - switch(configure->vcc){ case 0: break; @@ -119,43 +109,62 @@ case 50: case 33: #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_PWR_SHUTDOWN; - GPCR |= GPIO_PWR_SHUTDOWN; + GPCR = GPIO_PWR_SHUTDOWN; #endif break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, configure->vcc); - restore_flags(flags); return -1; } if(configure->reset) { #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_CF_RESET; - GPSR |= GPIO_CF_RESET; + GPSR = GPIO_CF_RESET; #endif } else { #ifdef CONFIG_SA1100_CERF_CPLD - GPDR |= GPIO_CF_RESET; - GPCR |= GPIO_CF_RESET; + GPCR = GPIO_CF_RESET; #endif } - restore_flags(flags); + return 0; +} + +static int cerf_pcmcia_socket_init(int sock) +{ + int i; + + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); + + return 0; +} + +static int cerf_pcmcia_socket_suspend(int sock) +{ + int i; + + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); return 0; } struct pcmcia_low_level cerf_pcmcia_ops = { - cerf_pcmcia_init, - cerf_pcmcia_shutdown, - cerf_pcmcia_socket_state, - cerf_pcmcia_get_irq_info, - cerf_pcmcia_configure_socket + init: cerf_pcmcia_init, + shutdown: cerf_pcmcia_shutdown, + socket_state: cerf_pcmcia_socket_state, + get_irq_info: cerf_pcmcia_get_irq_info, + configure_socket: cerf_pcmcia_configure_socket, + + socket_init: cerf_pcmcia_socket_init, + socket_suspend: cerf_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_flexanet.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_flexanet.c --- linux-2.4.18/drivers/pcmcia/sa1100_flexanet.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_flexanet.c Sat Mar 30 22:55:40 2002 @@ -4,7 +4,6 @@ * PCMCIA implementation routines for Flexanet. * by Jordi Colomer, 09/05/2001 * - * Yet to be defined. */ #include @@ -12,8 +11,18 @@ #include #include -#include +#include "sa1100_generic.h" +static struct { + int irq; + unsigned int gpio; + const char *name; +} irqs[] = { + { IRQ_GPIO_CF1_CD, GPIO_CF1_NCD, "CF1_CD" }, + { IRQ_GPIO_CF1_BVD1, GPIO_CF1_BVD1, "CF1_BVD1" }, + { IRQ_GPIO_CF2_CD, GPIO_CF2_NCD, "CF2_CD" }, + { IRQ_GPIO_CF2_BVD1, GPIO_CF2_BVD1, "CF2_BVD1" } +}; /* * Socket initialization. @@ -22,9 +31,36 @@ * Must return the number of slots. * */ -static int flexanet_pcmcia_init(struct pcmcia_init *init){ +static int flexanet_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; - return 0; + /* Configure the GPIOs as inputs (BVD2 is not implemented) */ + GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ | + GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ ); + + /* Set IRQ edge */ + set_GPIO_IRQ_edge( GPIO_CF1_IRQ | GPIO_CF2_IRQ, GPIO_FALLING_EDGE ); + + /* Register the socket interrupts (not the card interrupts) */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].name, NULL); + if (res < 0) + break; + } + + /* If we failed, then free all interrupts requested thus far. */ + if (res < 0) { + printk(KERN_ERR "%s: Request for IRQ%u failed: %d\n", __FUNCTION__, + irqs[i].irq, res); + while (i--) + free_irq(irqs[i].irq, NULL); + return -1; + } + + return 2; } @@ -34,6 +70,12 @@ */ static int flexanet_pcmcia_shutdown(void) { + int i; + + /* disable IRQs */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + return 0; } @@ -46,7 +88,33 @@ */ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array *state_array){ - return -1; + unsigned long levels; + + if (state_array->size < 2) + return -1; + + /* Sense the GPIOs, asynchronously */ + levels = GPLR; + + /* Socket 0 */ + state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0; + state_array->state[0].ready = (levels & GPIO_CF1_IRQ)?1:0; + state_array->state[0].bvd1 = (levels & GPIO_CF1_BVD1)?1:0; + state_array->state[0].bvd2 = 1; + state_array->state[0].wrprot = 0; + state_array->state[0].vs_3v = 1; + state_array->state[0].vs_Xv = 0; + + /* Socket 1 */ + state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0; + state_array->state[1].ready = (levels & GPIO_CF2_IRQ)?1:0; + state_array->state[1].bvd1 = (levels & GPIO_CF2_BVD1)?1:0; + state_array->state[1].bvd2 = 1; + state_array->state[1].wrprot = 0; + state_array->state[1].vs_3v = 1; + state_array->state[1].vs_Xv = 0; + + return 1; } @@ -56,7 +124,16 @@ */ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - return -1; + /* check the socket index */ + if (info->sock > 1) + return -1; + + if (info->sock == 0) + info->irq = IRQ_GPIO_CF1_IRQ; + else if (info->sock == 1) + info->irq = IRQ_GPIO_CF2_IRQ; + + return 0; } @@ -66,19 +143,84 @@ static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure *configure) { - return -1; + unsigned long value, flags, mask; + + + if (configure->sock > 1) + return -1; + + /* Ignore the VCC level since it is 3.3V and always on */ + switch (configure->vcc) + { + case 0: + printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__); + break; + + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); + + case 33: + break; + + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + configure->vcc); + return -1; + } + + /* Reset the slot(s) using the controls in the BCR */ + mask = 0; + + switch (configure->sock) + { + case 0 : mask = FHH_BCR_CF1_RST; break; + case 1 : mask = FHH_BCR_CF2_RST; break; + } + + save_flags_cli(flags); + + value = flexanet_BCR; + value = (configure->reset) ? (value | mask) : (value & ~mask); + FHH_BCR = flexanet_BCR = value; + + restore_flags(flags); + + return 0; +} + +static int flexanet_pcmcia_socket_init(int sock) +{ + if (sock == 0) + set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_BOTH_EDGES); + else if (sock == 1) + set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_BOTH_EDGES); + + return 0; } +static int flexanet_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) + set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_NO_EDGES); + else if (sock == 1) + set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_NO_EDGES); + + return 0; +} /* * The set of socket operations * */ struct pcmcia_low_level flexanet_pcmcia_ops = { - flexanet_pcmcia_init, - flexanet_pcmcia_shutdown, - flexanet_pcmcia_socket_state, - flexanet_pcmcia_get_irq_info, - flexanet_pcmcia_configure_socket + init: flexanet_pcmcia_init, + shutdown: flexanet_pcmcia_shutdown, + socket_state: flexanet_pcmcia_socket_state, + get_irq_info: flexanet_pcmcia_get_irq_info, + configure_socket: flexanet_pcmcia_configure_socket, + + socket_init: flexanet_pcmcia_socket_init, + socket_suspend: flexanet_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_freebird.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_freebird.c --- linux-2.4.18/drivers/pcmcia/sa1100_freebird.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_freebird.c Sat Mar 30 22:55:40 2002 @@ -9,7 +9,7 @@ #include #include -#include +#include "sa1100_generic.h" static int freebird_pcmcia_init(struct pcmcia_init *init){ @@ -26,14 +26,10 @@ mdelay(100); LINKUP_PRC = 0xc0; - /* All those are inputs */ - ////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); - GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD); - /* Set transition detect */ //set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); //set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); - set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES); + set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_NO_EDGES); set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE); /* Register interrupts */ @@ -150,11 +146,26 @@ return 0; } +static int freebird_pcmcia_socket_init(int sock) +{ + set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD, GPIO_BOTH_EDGES); + return 0; +} + +static int freebird_pcmcia_socket_suspend(int sock) +{ + set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD, GPIO_NO_EDGES); + return 0; +} + struct pcmcia_low_level freebird_pcmcia_ops = { - freebird_pcmcia_init, - freebird_pcmcia_shutdown, - freebird_pcmcia_socket_state, - freebird_pcmcia_get_irq_info, - freebird_pcmcia_configure_socket + init: freebird_pcmcia_init, + shutdown: freebird_pcmcia_shutdown, + socket_state: freebird_pcmcia_socket_state, + get_irq_info: freebird_pcmcia_get_irq_info, + configure_socket: freebird_pcmcia_configure_socket, + + socket_init: freebird_pcmcia_socket_init, + socket_suspend: freebird_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_generic.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.c --- linux-2.4.18/drivers/pcmcia/sa1100_generic.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.c Sat Mar 30 22:55:40 2002 @@ -29,6 +29,10 @@ file under either the MPL or the GPL. ======================================================================*/ +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ #include #include @@ -43,6 +47,7 @@ #include #include #include +#include #include #include @@ -62,338 +67,94 @@ static int pc_debug; #endif -MODULE_AUTHOR("John Dorsey "); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); - /* This structure maintains housekeeping state for each socket, such * as the last known values of the card detect pins, or the Card Services * callback value associated with the socket: */ -static struct sa1100_pcmcia_socket -sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; - static int sa1100_pcmcia_socket_count; +static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; +#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x)) /* Returned by the low-level PCMCIA interface: */ static struct pcmcia_low_level *pcmcia_low_level; -/* Event poll timer structure */ static struct timer_list poll_timer; - - -/* Prototypes for routines which are used internally: */ - -static int sa1100_pcmcia_driver_init(void); -static void sa1100_pcmcia_driver_shutdown(void); -static void sa1100_pcmcia_task_handler(void *data); -static void sa1100_pcmcia_poll_event(unsigned long data); -static void sa1100_pcmcia_interrupt(int irq, void *dev, - struct pt_regs *regs); static struct tq_struct sa1100_pcmcia_task; -#ifdef CONFIG_PROC_FS -static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, - int count, int *eof, void *data); -#endif - - -/* Prototypes for operations which are exported to the - * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: - */ - -static int sa1100_pcmcia_init(unsigned int sock); -static int sa1100_pcmcia_suspend(unsigned int sock); -static int sa1100_pcmcia_register_callback(unsigned int sock, - void (*handler)(void *, - unsigned int), - void *info); -static int sa1100_pcmcia_inquire_socket(unsigned int sock, - socket_cap_t *cap); -static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value); -static int sa1100_pcmcia_get_socket(unsigned int sock, - socket_state_t *state); -static int sa1100_pcmcia_set_socket(unsigned int sock, - socket_state_t *state); -static int sa1100_pcmcia_get_io_map(unsigned int sock, - struct pccard_io_map *io); -static int sa1100_pcmcia_set_io_map(unsigned int sock, - struct pccard_io_map *io); -static int sa1100_pcmcia_get_mem_map(unsigned int sock, - struct pccard_mem_map *mem); -static int sa1100_pcmcia_set_mem_map(unsigned int sock, - struct pccard_mem_map *mem); -#ifdef CONFIG_PROC_FS -static void sa1100_pcmcia_proc_setup(unsigned int sock, - struct proc_dir_entry *base); -#endif - -static struct pccard_operations sa1100_pcmcia_operations = { - sa1100_pcmcia_init, - sa1100_pcmcia_suspend, - sa1100_pcmcia_register_callback, - sa1100_pcmcia_inquire_socket, - sa1100_pcmcia_get_status, - sa1100_pcmcia_get_socket, - sa1100_pcmcia_set_socket, - sa1100_pcmcia_get_io_map, - sa1100_pcmcia_set_io_map, - sa1100_pcmcia_get_mem_map, - sa1100_pcmcia_set_mem_map, -#ifdef CONFIG_PROC_FS - sa1100_pcmcia_proc_setup -#endif -}; - -#ifdef CONFIG_CPU_FREQ -/* forward declaration */ -static struct notifier_block sa1100_pcmcia_notifier_block; -#endif - - -/* sa1100_pcmcia_driver_init() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * This routine performs a basic sanity check to ensure that this - * kernel has been built with the appropriate board-specific low-level - * PCMCIA support, performs low-level PCMCIA initialization, registers - * this socket driver with Card Services, and then spawns the daemon - * thread which is the real workhorse of the socket driver. - * - * Please see linux/Documentation/arm/SA1100/PCMCIA for more information - * on the low-level kernel interface. +/* + * sa1100_pcmcia_state_to_config + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * Returns: 0 on success, -1 on error - */ -static int __init sa1100_pcmcia_driver_init(void){ - servinfo_t info; - struct pcmcia_init pcmcia_init; - struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; - struct pcmcia_state_array state_array; - unsigned int i, clock; - unsigned long mecr; - - printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); - - CardServices(GetCardServicesInfo, &info); - - if(info.Revision!=CS_RELEASE_CODE){ - printk(KERN_ERR "Card Services release codes do not match\n"); - return -1; - } - - if(machine_is_assabet()){ -#ifdef CONFIG_SA1100_ASSABET - if(machine_has_neponset()){ -#ifdef CONFIG_ASSABET_NEPONSET - pcmcia_low_level=&neponset_pcmcia_ops; -#else - printk(KERN_ERR "Card Services disabled: missing Neponset support\n"); - return -1; -#endif - }else{ - pcmcia_low_level=&assabet_pcmcia_ops; - } -#endif - } else if (machine_is_freebird()) { -#ifdef CONFIG_SA1100_FREEBIRD - pcmcia_low_level = &freebird_pcmcia_ops; -#endif - } else if (machine_is_h3600()) { -#ifdef CONFIG_SA1100_H3600 - pcmcia_low_level = &h3600_pcmcia_ops; -#endif - } else if (machine_is_cerf()) { -#ifdef CONFIG_SA1100_CERF - pcmcia_low_level = &cerf_pcmcia_ops; -#endif - } else if (machine_is_graphicsclient()) { -#ifdef CONFIG_SA1100_GRAPHICSCLIENT - pcmcia_low_level = &gcplus_pcmcia_ops; -#endif - } else if (machine_is_xp860()) { -#ifdef CONFIG_SA1100_XP860 - pcmcia_low_level = &xp860_pcmcia_ops; -#endif - } else if (machine_is_yopy()) { -#ifdef CONFIG_SA1100_YOPY - pcmcia_low_level = &yopy_pcmcia_ops; -#endif - } else if (machine_is_pangolin()) { -#ifdef CONFIG_SA1100_PANGOLIN - pcmcia_low_level = &pangolin_pcmcia_ops; -#endif - } else if (machine_is_jornada720()) { -#ifdef CONFIG_SA1100_JORNADA720 - pcmcia_low_level = &jornada720_pcmcia_ops; -#endif - } else if(machine_is_pfs168()){ -#ifdef CONFIG_SA1100_PFS168 - pcmcia_low_level=&pfs168_pcmcia_ops; -#endif - } else if(machine_is_flexanet()){ -#ifdef CONFIG_SA1100_FLEXANET - pcmcia_low_level=&flexanet_pcmcia_ops; -#endif - } else if(machine_is_simpad()){ -#ifdef CONFIG_SA1100_SIMPAD - pcmcia_low_level=&simpad_pcmcia_ops; -#endif - } else if(machine_is_graphicsmaster()) { -#ifdef CONFIG_SA1100_GRAPHICSMASTER - pcmcia_low_level=&graphicsmaster_pcmcia_ops; -#endif - } else if(machine_is_adsbitsy()) { -#ifdef CONFIG_SA1100_ADSBITSY - pcmcia_low_level=&adsbitsy_pcmcia_ops; -#endif - } else if(machine_is_stork()) { -#ifdef CONFIG_SA1100_STORK - pcmcia_low_level=&stork_pcmcia_ops; -#endif - } - - if (!pcmcia_low_level) { - printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n"); - return -ENODEV; - } - - pcmcia_init.handler=sa1100_pcmcia_interrupt; - - if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){ - printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n"); - return -EIO; - } - - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; - - if(pcmcia_low_level->socket_state(&state_array)<0){ - printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); - return -EIO; - } - - /* We initialize the MECR to default values here, because we are - * not guaranteed to see a SetIOMap operation at runtime. - */ - mecr=0; - - clock = get_cclk_frequency() * 100; - - for(i=0; ishutdown(); - flush_scheduled_tasks(); + conf.sock = sock; + conf.vcc = state->Vcc; + conf.vpp = state->Vpp; + conf.output = state->flags & SS_OUTPUT_ENA ? 1 : 0; + conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0; + conf.reset = state->flags & SS_RESET ? 1 : 0; + conf.irq = state->io_irq != 0; - DEBUG(1, "sa1100: shutdown complete\n"); + return conf; } -module_exit(sa1100_pcmcia_driver_shutdown); - - /* sa1100_pcmcia_init() * ^^^^^^^^^^^^^^^^^^^^ - * We perform all of the interesting initialization tasks in - * sa1100_pcmcia_driver_init(). + * + * (Re-)Initialise the socket, turning on status interrupts + * and PCMCIA bus. This must wait for power to stabilise + * so that the card status signals report correctly. * * Returns: 0 */ -static int sa1100_pcmcia_init(unsigned int sock){ - +static int sa1100_pcmcia_init(unsigned int sock) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); - return 0; + skt->cs_state = dead_socket; + + conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); + + pcmcia_low_level->configure_socket(&conf); + + return pcmcia_low_level->socket_init(sock); } -/* sa1100_pcmcia_suspend() +/* + * sa1100_pcmcia_suspend() * ^^^^^^^^^^^^^^^^^^^^^^^ - * We don't currently perform any actions on a suspend. + * + * Remove power on the socket, disable IRQs from the card. + * Turn off status interrupts, and disable the PCMCIA bus. * * Returns: 0 */ static int sa1100_pcmcia_suspend(unsigned int sock) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_configure conf; int ret; DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); - conf.sock = sock; - conf.vcc = 0; - conf.vpp = 0; - conf.output = 0; - conf.speaker = 0; - conf.reset = 1; + conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); ret = pcmcia_low_level->configure_socket(&conf); - if (ret == 0) - sa1100_pcmcia_socket[sock].cs_state = dead_socket; + if (ret == 0) { + skt->cs_state = dead_socket; + ret = pcmcia_low_level->socket_suspend(sock); + } return ret; } @@ -407,52 +168,50 @@ * * Returns: an event mask for the given socket state. */ -static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state, - struct pcmcia_state *prev_state, - unsigned int mask, - unsigned int flags){ - unsigned int events=0; - - if(state->detect!=prev_state->detect){ +static inline unsigned int +sa1100_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events = 0; - DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect); + if (state->detect != prev_state->detect) { + DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); - events|=mask&SS_DETECT; + events |= SS_DETECT; } - if(state->ready!=prev_state->ready){ + if (state->ready != prev_state->ready) { + DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); - DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready); - - events|=mask&((flags&SS_IOCARD)?0:SS_READY); + events |= flags & SS_IOCARD ? 0 : SS_READY; } - if(state->bvd1!=prev_state->bvd1){ - - DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); + if (state->bvd1 != prev_state->bvd1) { + DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); - events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD; + events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD; } - if(state->bvd2!=prev_state->bvd2){ + if (state->bvd2 != prev_state->bvd2) { + DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - - events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN; + events |= flags & SS_IOCARD ? 0 : SS_BATWARN; } - DEBUG(2, "events: %s%s%s%s%s%s\n", - (events==0)?"":"", - (events&SS_DETECT)?"DETECT ":"", - (events&SS_READY)?"READY ":"", - (events&SS_BATDEAD)?"BATDEAD ":"", - (events&SS_BATWARN)?"BATWARN ":"", - (events&SS_STSCHG)?"STSCHG ":""); + *prev_state = *state; - *prev_state=*state; + events &= mask; - return events; + DEBUG(2, "events: %s%s%s%s%s%s\n", + events == 0 ? "" : "", + events & SS_DETECT ? "DETECT " : "", + events & SS_READY ? "READY " : "", + events & SS_BATDEAD ? "BATDEAD " : "", + events & SS_BATWARN ? "BATWARN " : "", + events & SS_STSCHG ? "STSCHG " : ""); + return events; } /* sa1100_pcmcia_events() */ @@ -464,38 +223,43 @@ * callback) occurs in this thread rather than in the actual interrupt * handler due to the use of scheduling operations in the PCMCIA core. */ -static void sa1100_pcmcia_task_handler(void *data) { +static void sa1100_pcmcia_task_handler(void *data) +{ struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; - int i, events, all_events, irq_status; + unsigned int all_events; - DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; + state_array.size = sa1100_pcmcia_socket_count; + state_array.state = state; do { + unsigned int events; + int ret, i; - DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); + memset(state, 0, sizeof(state)); - if((irq_status=pcmcia_low_level->socket_state(&state_array))<0) - printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n"); + DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); - all_events=0; + ret = pcmcia_low_level->socket_state(&state_array); + if (ret < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n"); + break; + } - if(irq_status>0){ + all_events = 0; - for(i=0; ik_state, + skt->cs_state.csc_mask, + skt->cs_state.flags); + + if (events && sa1100_pcmcia_socket[i].handler != NULL) + skt->handler(skt->handler_info, events); + } } while(all_events); } /* sa1100_pcmcia_task_handler() */ @@ -510,7 +274,7 @@ */ static void sa1100_pcmcia_poll_event(unsigned long dummy) { - DEBUG(3, "%s(): polling for events\n", __FUNCTION__); + DEBUG(4, "%s(): polling for events\n", __FUNCTION__); poll_timer.function = sa1100_pcmcia_poll_event; poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; add_timer(&poll_timer); @@ -527,7 +291,8 @@ * handling code performs scheduling operations which cannot be * executed from within an interrupt context. */ -static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){ +static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); schedule_task(&sa1100_pcmcia_task); } @@ -546,17 +311,20 @@ * * Returns: 0 */ -static int sa1100_pcmcia_register_callback(unsigned int sock, - void (*handler)(void *, - unsigned int), - void *info){ - if(handler==NULL){ - sa1100_pcmcia_socket[sock].handler=NULL; +static int +sa1100_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + if (handler == NULL) { + skt->handler = NULL; MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; - sa1100_pcmcia_socket[sock].handler=handler; - sa1100_pcmcia_socket[sock].handler_info=info; + skt->handler_info = info; + skt->handler = handler; } return 0; @@ -580,51 +348,41 @@ * an offset which is applied to client-requested base I/O addresses * in alloc_io_space(). * - * Returns: 0 on success, -1 if no pin has been configured for `sock' + * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + * + * Return value is irrelevant; the pcmcia subsystem ignores it. */ -static int sa1100_pcmcia_inquire_socket(unsigned int sock, - socket_cap_t *cap){ - struct pcmcia_irq_info irq_info; - - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); - - if(sock>=sa1100_pcmcia_socket_count){ - printk(KERN_ERR "sa1100: socket %u not configured\n", sock); - return -1; - } +static int +sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the - * force_low argument to validate_mem() in rsrc_mgr.c -- since in - * general, the mapped * addresses of the PCMCIA memory regions - * will not be within 0xffff, setting force_low would be - * undesirable. - * - * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory - * resource database; we instead pass up physical address ranges - * and allow other parts of Card Services to deal with remapping. - * - * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but - * not 32-bit CardBus devices. - */ - cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - irq_info.sock=sock; - irq_info.irq=-1; + if (sock < sa1100_pcmcia_socket_count) { + cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD; + cap->irq_mask = 0; + cap->map_size = PAGE_SIZE; + cap->pci_irq = skt->irq; + cap->io_offset = (unsigned long)skt->virt_io; - if(pcmcia_low_level->get_irq_info(&irq_info)<0){ - printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n", - sock); - return -1; + ret = 0; } - cap->irq_mask=0; - cap->map_size=PAGE_SIZE; - cap->pci_irq=irq_info.irq; - cap->io_offset=sa1100_pcmcia_socket[sock].virt_io; - - return 0; - -} /* sa1100_pcmcia_inquire_socket() */ + return ret; +} /* sa1100_pcmcia_get_status() @@ -643,58 +401,61 @@ * * Returns: 0 */ -static int sa1100_pcmcia_get_status(unsigned int sock, - unsigned int *status){ +static int +sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; + unsigned int stat; - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - state_array.size=sa1100_pcmcia_socket_count; - state_array.state=state; + state_array.size = sa1100_pcmcia_socket_count; + state_array.state = state; - if((pcmcia_low_level->socket_state(&state_array))<0){ - printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + memset(state, 0, sizeof(state)); + + if ((pcmcia_low_level->socket_state(&state_array)) < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n"); return -1; } - sa1100_pcmcia_socket[sock].k_state=state[sock]; - - *status=state[sock].detect?SS_DETECT:0; + skt->k_state = state[sock]; - *status|=state[sock].ready?SS_READY:0; + stat = state[sock].detect ? SS_DETECT : 0; + stat |= state[sock].ready ? SS_READY : 0; + stat |= state[sock].vs_3v ? SS_3VCARD : 0; + stat |= state[sock].vs_Xv ? SS_XVCARD : 0; /* The power status of individual sockets is not available * explicitly from the hardware, so we just remember the state * and regurgitate it upon request: */ - *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; + stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD) - *status|=state[sock].bvd1?SS_STSCHG:0; + if (skt->cs_state.flags & SS_IOCARD) + stat |= state[sock].bvd1 ? SS_STSCHG : 0; else { - if(state[sock].bvd1==0) - *status|=SS_BATDEAD; - else if(state[sock].bvd2==0) - *status|=SS_BATWARN; + if (state[sock].bvd1 == 0) + stat |= SS_BATDEAD; + else if (state[sock].bvd2 == 0) + stat |= SS_BATWARN; } - *status|=state[sock].vs_3v?SS_3VCARD:0; - - *status|=state[sock].vs_Xv?SS_XVCARD:0; - DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", - (*status&SS_DETECT)?"DETECT ":"", - (*status&SS_READY)?"READY ":"", - (*status&SS_BATDEAD)?"BATDEAD ":"", - (*status&SS_BATWARN)?"BATWARN ":"", - (*status&SS_POWERON)?"POWERON ":"", - (*status&SS_STSCHG)?"STSCHG ":"", - (*status&SS_3VCARD)?"3VCARD ":"", - (*status&SS_XVCARD)?"XVCARD ":""); + stat & SS_DETECT ? "DETECT " : "", + stat & SS_READY ? "READY " : "", + stat & SS_BATDEAD ? "BATDEAD " : "", + stat & SS_BATWARN ? "BATWARN " : "", + stat & SS_POWERON ? "POWERON " : "", + stat & SS_STSCHG ? "STSCHG " : "", + stat & SS_3VCARD ? "3VCARD " : "", + stat & SS_XVCARD ? "XVCARD " : ""); - return 0; + *status = stat; + return 0; } /* sa1100_pcmcia_get_status() */ @@ -706,20 +467,18 @@ * * Returns: 0 */ -static int sa1100_pcmcia_get_socket(unsigned int sock, - socket_state_t *state){ +static int +sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - /* This information was given to us in an earlier call to set_socket(), - * so we're just regurgitating it here: - */ - *state=sa1100_pcmcia_socket[sock].cs_state; + *state = skt->cs_state; return 0; } - /* sa1100_pcmcia_set_socket() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_socket() operation for the in-kernel PCMCIA @@ -730,14 +489,15 @@ * * Returns: 0 */ -static int sa1100_pcmcia_set_socket(unsigned int sock, - socket_state_t *state){ - struct pcmcia_configure configure; +static int +sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; - DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" - "\tVcc %d Vpp %d irq %d\n", + DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", (state->csc_mask==0)?"":"", (state->csc_mask&SS_DETECT)?"DETECT ":"", (state->csc_mask&SS_READY)?"READY ":"", @@ -749,25 +509,20 @@ (state->flags&SS_IOCARD)?"IOCARD ":"", (state->flags&SS_RESET)?"RESET ":"", (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); + DEBUG(3, "\tVcc %d Vpp %d irq %d\n", state->Vcc, state->Vpp, state->io_irq); - configure.sock=sock; - configure.vcc=state->Vcc; - configure.vpp=state->Vpp; - configure.output=(state->flags&SS_OUTPUT_ENA)?1:0; - configure.speaker=(state->flags&SS_SPKR_ENA)?1:0; - configure.reset=(state->flags&SS_RESET)?1:0; + conf = sa1100_pcmcia_state_to_config(sock, state); - if(pcmcia_low_level->configure_socket(&configure)<0){ - printk(KERN_ERR "Unable to configure socket %u\n", sock); + if (pcmcia_low_level->configure_socket(&conf) < 0) { + printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock); return -1; } - sa1100_pcmcia_socket[sock].cs_state=*state; + skt->cs_state = *state; return 0; - } /* sa1100_pcmcia_set_socket() */ @@ -779,20 +534,20 @@ * * Returns: 0 on success, -1 if the map index was out of range */ -static int sa1100_pcmcia_get_io_map(unsigned int sock, - struct pccard_io_map *map){ +static int +sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - if(map->map>=MAX_IO_WIN){ - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; + if (map->map < MAX_IO_WIN) { + *map = skt->io_map[map->map]; + ret = 0; } - *map=sa1100_pcmcia_socket[sock].io_map[map->map]; - - return 0; + return ret; } @@ -805,16 +560,16 @@ * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_set_io_map(unsigned int sock, - struct pccard_io_map *map){ - unsigned int clock, speed; - unsigned long mecr, start; +static int +sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n" - "\tflags: %s%s%s%s%s%s%s%s\n", - map->map, map->speed, map->start, map->stop, + DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", + map->map, map->speed, map->start, map->stop); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", @@ -824,45 +579,45 @@ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", (map->flags&MAP_PREFETCH)?"PREFETCH ":""); - if(map->map>=MAX_IO_WIN){ + if (map->map >= MAX_IO_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } - if(map->flags&MAP_ACTIVE){ + if (map->flags & MAP_ACTIVE) { + unsigned int clock, speed = map->speed; + unsigned long mecr; - speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS; + if (speed == 0) + speed = SA1100_PCMCIA_IO_ACCESS; - clock = get_cclk_frequency() * 100; + clock = cpufreq_get(0); - mecr=MECR; + mecr = MECR; MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_io=speed; + skt->speed_io = speed; DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); - MECR=mecr; - + MECR = mecr; } - start=map->start; - - if(map->stop==1) - map->stop=PAGE_SIZE-1; + if (map->stop == 1) + map->stop = PAGE_SIZE-1; - map->start=sa1100_pcmcia_socket[sock].virt_io; - map->stop=map->start+(map->stop-start); + map->stop -= map->start; + map->stop += (unsigned long)skt->virt_io; + map->start = (unsigned long)skt->virt_io; - sa1100_pcmcia_socket[sock].io_map[map->map]=*map; + skt->io_map[map->map] = *map; return 0; - } /* sa1100_pcmcia_set_io_map() */ @@ -875,20 +630,20 @@ * * Returns: 0 on success, -1 if the map index was out of range */ -static int sa1100_pcmcia_get_mem_map(unsigned int sock, - struct pccard_mem_map *map){ +static int +sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - if(map->map>=MAX_WIN){ - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; + if (map->map < MAX_WIN) { + *map = skt->mem_map[map->map]; + ret = 0; } - *map=sa1100_pcmcia_socket[sock].mem_map[map->map]; - - return 0; + return ret; } @@ -901,18 +656,18 @@ * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_set_mem_map(unsigned int sock, - struct pccard_mem_map *map){ - unsigned int clock, speed; - unsigned long mecr, start; +static int +sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + unsigned long start; - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n" - "\tsys_stop %#lx\n\tcard_start %#x\n" - "\tflags: %s%s%s%s%s%s%s%s\n", - map->map, map->speed, map->sys_start, map->sys_stop, - map->card_start, (map->flags==0)?"":"", + DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", + map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + (map->flags==0)?"":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", @@ -921,177 +676,175 @@ (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - if(map->map>=MAX_WIN){ + if (map->map >= MAX_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } - if(map->flags&MAP_ACTIVE){ - - /* When clients issue RequestMap, the access speed is not always - * properly configured: + if (map->flags & MAP_ACTIVE) { + unsigned int clock, speed = map->speed; + unsigned long mecr; + + /* + * When clients issue RequestMap, the access speed is not always + * properly configured. Choose some sensible defaults. */ - if(map->speed > 0) - speed = map->speed; - else - switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){ - case 33: + if (speed == 0) { + if (skt->cs_state.Vcc == 33) speed = SA1100_PCMCIA_3V_MEM_ACCESS; - break; - default: + else speed = SA1100_PCMCIA_5V_MEM_ACCESS; - } + } - clock = get_cclk_frequency() * 100; - - mecr=MECR; - - if(map->flags&MAP_ATTRIB){ + clock = cpufreq_get(0); - MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_attr=speed; + /* Fixme: MECR is not pre-empt safe. */ + mecr = MECR; + if (map->flags & MAP_ATTRIB) { + MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); + skt->speed_attr = speed; } else { - MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); - sa1100_pcmcia_socket[sock].speed_mem=speed; - + skt->speed_mem = speed; } - + DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); - - MECR=mecr; + MECR = mecr; } - start=map->sys_start; + start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; - if(map->sys_stop==0) - map->sys_stop=PAGE_SIZE-1; + if (map->sys_stop == 0) + map->sys_stop = PAGE_SIZE-1; - map->sys_start=(map->flags & MAP_ATTRIB)?\ - sa1100_pcmcia_socket[sock].phys_attr:\ - sa1100_pcmcia_socket[sock].phys_mem; + map->sys_stop -= map->sys_start; + map->sys_stop += start; + map->sys_start = start; - map->sys_stop=map->sys_start+(map->sys_stop-start); - - sa1100_pcmcia_socket[sock].mem_map[map->map]=*map; + skt->mem_map[map->map] = *map; return 0; - } /* sa1100_pcmcia_set_mem_map() */ #if defined(CONFIG_PROC_FS) -/* sa1100_pcmcia_proc_setup() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the proc_setup() operation for the in-kernel PCMCIA - * service (formerly SS_ProcSetup in Card Services). - * - * Returns: 0 on success, -1 on error - */ -static void sa1100_pcmcia_proc_setup(unsigned int sock, - struct proc_dir_entry *base){ - struct proc_dir_entry *entry; - - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); - - if((entry=create_proc_entry("status", 0, base))==NULL){ - printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); - return; - } - - entry->read_proc=sa1100_pcmcia_proc_status; - entry->data=(void *)sock; -} - - /* sa1100_pcmcia_proc_status() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the /proc/bus/pccard/??/status file. * * Returns: the number of characters added to the buffer */ -static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, - int count, int *eof, void *data){ - char *p=buf; - unsigned int sock=(unsigned int)data; - unsigned int clock = get_cclk_frequency() * 100; +static int +sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + unsigned int sock = (unsigned int)data; + unsigned int clock = cpufreq_get(0); + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); unsigned long mecr = MECR; + char *p = buf; - p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"", - sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"", - sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", - sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", - sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", - sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", - sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); + p+=sprintf(p, "k_state : %s%s%s%s%s%s%s\n", + skt->k_state.detect ? "detect " : "", + skt->k_state.ready ? "ready " : "", + skt->k_state.bvd1 ? "bvd1 " : "", + skt->k_state.bvd2 ? "bvd2 " : "", + skt->k_state.wrprot ? "wrprot " : "", + skt->k_state.vs_3v ? "vs_3v " : "", + skt->k_state.vs_Xv ? "vs_Xv " : ""); p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", - sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"", - sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ - "SS_IOCARD ":"", - (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD && - sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", - ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && - (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", - ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && - (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", - sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", - sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); + skt->k_state.detect ? "SS_DETECT " : "", + skt->k_state.ready ? "SS_READY " : "", + skt->cs_state.Vcc ? "SS_POWERON " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + (skt->cs_state.flags & SS_IOCARD && + skt->k_state.bvd1) ? "SS_STSCHG " : "", + ((skt->cs_state.flags & SS_IOCARD)==0 && + (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "", + ((skt->cs_state.flags & SS_IOCARD)==0 && + (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "", + skt->k_state.vs_3v ? "SS_3VCARD " : "", + skt->k_state.vs_Xv ? "SS_XVCARD " : ""); p+=sprintf(p, "mask : %s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ - "SS_DETECT ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ - "SS_READY ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ - "SS_BATDEAD ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ - "SS_BATWARN ":"", - sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ - "SS_STSCHG ":""); + skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", + skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "", + skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "", + skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "", + skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ - "SS_PWR_AUTO ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ - "SS_IOCARD ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\ - "SS_RESET ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ - "SS_SPKR_ENA ":"", - sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ - "SS_OUTPUT_ENA ":""); - - p+=sprintf(p, "Vcc : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc); + skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + skt->cs_state.flags & SS_RESET ? "SS_RESET " : "", + skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "", + skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : ""); + + p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p+=sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq); - p+=sprintf(p, "Vpp : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp); - - p+=sprintf(p, "irq : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq); - - p+=sprintf(p, "I/O : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io, + p+=sprintf(p, "I/O : %u (%u)\n", skt->speed_io, sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock))); - p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr, + p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr, sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock))); - p+=sprintf(p, "common : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem, + p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem, sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock))); return p-buf; } +/* sa1100_pcmcia_proc_setup() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the proc_setup() operation for the in-kernel PCMCIA + * service (formerly SS_ProcSetup in Card Services). + * + * Returns: 0 on success, -1 on error + */ +static void +sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if ((entry = create_proc_entry("status", 0, base)) == NULL){ + printk(KERN_ERR "unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc = sa1100_pcmcia_proc_status; + entry->data = (void *)sock; +} + #endif /* defined(CONFIG_PROC_FS) */ +static struct pccard_operations sa1100_pcmcia_operations = { + init: sa1100_pcmcia_init, + suspend: sa1100_pcmcia_suspend, + register_callback: sa1100_pcmcia_register_callback, + inquire_socket: sa1100_pcmcia_inquire_socket, + get_status: sa1100_pcmcia_get_status, + get_socket: sa1100_pcmcia_get_socket, + set_socket: sa1100_pcmcia_set_socket, + get_io_map: sa1100_pcmcia_get_io_map, + set_io_map: sa1100_pcmcia_set_io_map, + get_mem_map: sa1100_pcmcia_get_mem_map, + set_mem_map: sa1100_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + proc_setup: sa1100_pcmcia_proc_setup +#endif +}; #ifdef CONFIG_CPU_FREQ @@ -1101,7 +854,8 @@ * to a core clock frequency change) is needed, this routine establishes * new BS_xx values consistent with the clock speed `clock'. */ -static void sa1100_pcmcia_update_mecr(unsigned int clock){ +static void sa1100_pcmcia_update_mecr(unsigned int clock) +{ unsigned int sock; unsigned long mecr = MECR; @@ -1132,53 +886,293 @@ * * Returns: 0 on success, -1 on error */ -static int sa1100_pcmcia_notifier(struct notifier_block *nb, - unsigned long val, void *data){ +static int +sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ struct cpufreq_info *ci = data; - switch(val){ - case CPUFREQ_MINMAX: - - break; - + switch (val) { case CPUFREQ_PRECHANGE: - - if(ci->new_freq > ci->old_freq){ + if (ci->new_freq > ci->old_freq) { DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", __FUNCTION__, ci->new_freq / 1000, (ci->new_freq / 100) % 10, ci->old_freq / 1000, (ci->old_freq / 100) % 10); sa1100_pcmcia_update_mecr(ci->new_freq); } - break; case CPUFREQ_POSTCHANGE: - - if(ci->new_freq < ci->old_freq){ + if (ci->new_freq < ci->old_freq) { DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", __FUNCTION__, ci->new_freq / 1000, (ci->new_freq / 100) % 10, ci->old_freq / 1000, (ci->old_freq / 100) % 10); sa1100_pcmcia_update_mecr(ci->new_freq); } - break; - - default: - printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__, - val); - return -1; - } return 0; - } static struct notifier_block sa1100_pcmcia_notifier_block = { notifier_call: sa1100_pcmcia_notifier }; +#endif +static int __init sa1100_pcmcia_machine_init(void) +{ +#ifdef CONFIG_SA1100_ASSABET + if(machine_is_assabet()) { + if(machine_has_neponset()) { +#ifdef CONFIG_ASSABET_NEPONSET + pcmcia_low_level = &neponset_pcmcia_ops; +#else + printk(KERN_ERR "Card Services disabled: missing Neponset support\n"); + return -1; +#endif + } else + pcmcia_low_level = &assabet_pcmcia_ops; + } +#endif +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) + pcmcia_low_level = &badge4_pcmcia_ops; #endif +#ifdef CONFIG_SA1100_FREEBIRD + if (machine_is_freebird()) + pcmcia_low_level = &freebird_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_H3600 + if (machine_is_h3600()) + pcmcia_low_level = &h3600_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) + pcmcia_low_level = &cerf_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_GRAPHICSCLIENT + if (machine_is_graphicsclient()) + pcmcia_low_level = &gcplus_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_XP860 + if (machine_is_xp860()) + pcmcia_low_level = &xp860_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_YOPY + if (machine_is_yopy()) + pcmcia_low_level = &yopy_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_SHANNON + if (machine_is_shannon()) + pcmcia_low_level = &shannon_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_PANGOLIN + if (machine_is_pangolin()) + pcmcia_low_level = &pangolin_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_JORNADA720 + if (machine_is_jornada720()) + pcmcia_low_level = &jornada720_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_PFS168 + if(machine_is_pfs168()) + pcmcia_low_level = &pfs168_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_FLEXANET + if(machine_is_flexanet()) + pcmcia_low_level = &flexanet_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_SIMPAD + if(machine_is_simpad()) + pcmcia_low_level = &simpad_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_GRAPHICSMASTER + if(machine_is_graphicsmaster()) + pcmcia_low_level = &graphicsmaster_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_ADSBITSY + if(machine_is_adsbitsy()) + pcmcia_low_level = &adsbitsy_pcmcia_ops; +#endif +#ifdef CONFIG_SA1100_STORK + if(machine_is_stork()) + pcmcia_low_level = &stork_pcmcia_ops; +#endif + + if (!pcmcia_low_level) { + printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n"); + return -ENODEV; + } + + return 0; +} + +/* sa1100_pcmcia_driver_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * This routine performs a basic sanity check to ensure that this + * kernel has been built with the appropriate board-specific low-level + * PCMCIA support, performs low-level PCMCIA initialization, registers + * this socket driver with Card Services, and then spawns the daemon + * thread which is the real workhorse of the socket driver. + * + * Returns: 0 on success, -1 on error + */ +static int __init sa1100_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int i, clock; + unsigned long mecr; + int ret; + + printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + + if (info.Revision != CS_RELEASE_CODE) { + printk(KERN_ERR "Card Services release codes do not match\n"); + return -EINVAL; + } + + ret = sa1100_pcmcia_machine_init(); + if (ret) + return ret; + + pcmcia_init.handler = sa1100_pcmcia_interrupt; + + ret = pcmcia_low_level->init(&pcmcia_init); + if (ret < 0) { + printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); + return ret == -1 ? -EIO : ret; + } + + sa1100_pcmcia_socket_count = ret; + state_array.size = sa1100_pcmcia_socket_count; + state_array.state = state; + + memset(state, 0, sizeof(state)); + + if (pcmcia_low_level->socket_state(&state_array) < 0) { + pcmcia_low_level->shutdown(); + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -EIO; + } + + /* + * We initialize the MECR to default values here, because we are + * not guaranteed to see a SetIOMap operation at runtime. + */ + mecr = 0; + clock = cpufreq_get(0); + + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + struct pcmcia_irq_info irq_info; + + if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) { + ret = -EBUSY; + goto out_err; + } + + irq_info.sock = i; + irq_info.irq = -1; + ret = pcmcia_low_level->get_irq_info(&irq_info); + if (ret < 0) + printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret); + + skt->irq = irq_info.irq; + skt->k_state = state[i]; + skt->speed_io = SA1100_PCMCIA_IO_ACCESS; + skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; + skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; + skt->phys_attr = _PCMCIAAttr(i); + skt->phys_mem = _PCMCIAMem(i); + skt->virt_io = ioremap(_PCMCIAIO(i), 0x10000); + + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err; + } + + MECR_FAST_SET(mecr, i, 0); + MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock)); + MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock)); + MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock)); + } + + MECR = mecr; + +#ifdef CONFIG_CPU_FREQ + ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block); + if (ret < 0) { + printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret); + goto out_err; + } +#endif + + /* Only advertise as many sockets as we can detect */ + ret = register_ss_entry(sa1100_pcmcia_socket_count, + &sa1100_pcmcia_operations); + if (ret < 0) { + printk(KERN_ERR "Unable to register sockets\n"); + goto out_err; + } + + /* + * Start the event poll timer. It will reschedule by itself afterwards. + */ + sa1100_pcmcia_poll_event(0); + + return 0; + + out_err: + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + iounmap(sa1100_pcmcia_socket[i].virt_io); + release_mem_region(_PCMCIA(i), PCMCIASp); + } + + pcmcia_low_level->shutdown(); + + return ret; +} /* sa1100_pcmcia_driver_init() */ + +/* sa1100_pcmcia_driver_shutdown() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit sa1100_pcmcia_driver_shutdown(void) +{ + int i; + + del_timer_sync(&poll_timer); + + unregister_ss_entry(&sa1100_pcmcia_operations); + +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block); +#endif + + for (i = 0; i < sa1100_pcmcia_socket_count; i++) { + iounmap(sa1100_pcmcia_socket[i].virt_io); + release_mem_region(_PCMCIA(i), PCMCIASp); + } + + pcmcia_low_level->shutdown(); + + flush_scheduled_tasks(); +} + +MODULE_AUTHOR("John Dorsey "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); +MODULE_LICENSE("Dual MPL/GPL"); + +module_init(sa1100_pcmcia_driver_init); +module_exit(sa1100_pcmcia_driver_shutdown); diff -urN linux-2.4.18/drivers/pcmcia/sa1100_generic.h linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.h --- linux-2.4.18/drivers/pcmcia/sa1100_generic.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.h Sat Mar 30 22:55:40 2002 @@ -0,0 +1,76 @@ +/* + * linux/include/asm/arch/pcmcia.h + * + * Copyright (C) 2000 John G Dorsey + * + * This file contains definitions for the low-level SA-1100 kernel PCMCIA + * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. + */ +#ifndef _ASM_ARCH_PCMCIA +#define _ASM_ARCH_PCMCIA + +/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only + * has support for two. This shows up in lots of hardwired ways, such + * as the fact that MECR only has enough bits to configure two sockets. + * Since it's so entrenched in the hardware, limiting the software + * in this way doesn't seem too terrible. + */ +#define SA1100_PCMCIA_MAX_SOCK (2) + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + output: 1, + speaker: 1, + reset: 1, + irq: 1; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); + + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + int (*socket_init)(int sock); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + int (*socket_suspend)(int sock); +}; + +extern struct pcmcia_low_level *pcmcia_low_level; + +#endif diff -urN linux-2.4.18/drivers/pcmcia/sa1100_graphicsclient.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsclient.c --- linux-2.4.18/drivers/pcmcia/sa1100_graphicsclient.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsclient.c Sat Mar 30 22:55:40 2002 @@ -17,7 +17,9 @@ #include #include -#include +#include "sa1100_generic.h" + +#error This is broken! #define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ #define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ @@ -144,11 +146,24 @@ return 0; } +static int gcplus_pcmcia_socket_init(int sock) +{ + return 0; +} + +static int gcplus_pcmcia_socket_suspend(int sock) +{ + return 0; +} + struct pcmcia_low_level gcplus_pcmcia_ops = { - gcplus_pcmcia_init, - gcplus_pcmcia_shutdown, - gcplus_pcmcia_socket_state, - gcplus_pcmcia_get_irq_info, - gcplus_pcmcia_configure_socket + init: gcplus_pcmcia_init, + shutdown: gcplus_pcmcia_shutdown, + socket_state: gcplus_pcmcia_socket_state, + get_irq_info: gcplus_pcmcia_get_irq_info, + configure_socket: gcplus_pcmcia_configure_socket, + + socket_init: gcplus_pcmcia_socket_init, + socket_suspend: gcplus_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_graphicsmaster.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsmaster.c --- linux-2.4.18/drivers/pcmcia/sa1100_graphicsmaster.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsmaster.c Sat Mar 30 22:55:40 2002 @@ -11,10 +11,10 @@ #include #include -#include #include -#include -#include + +#include "sa1100_generic.h" +#include "sa1111_generic.h" static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) { @@ -26,190 +26,67 @@ /* Disable Power 3.3V/5V for PCMCIA/CF */ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "GC Master CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "GC Master CF (1) BVD1", NULL); - + /* why? */ MECR = 0x09430943; - return (return_val<0) ? -1 : 2; -} - -static int graphicsmaster_pcmcia_shutdown(void) -{ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array) -{ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; + return sa1111_pcmcia_init(init); } -static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure) +static int +graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long pccr=PCCR, gpio=PA_DWR; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - switch(configure->sock){ + switch (conf->sock) { case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio |= GPIO_GPIO0 | GPIO_GPIO1; - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio &= ~GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - gpio |= GPIO_GPIO0; - break; - + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio |= GPIO_GPIO2 | GPIO_GPIO3; - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio &= ~GPIO_GPIO2; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); - gpio |= GPIO_GPIO2; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; + case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; + case 33: pa_dwr_set = GPIO_GPIO3; break; + case 50: pa_dwr_set = GPIO_GPIO2; break; } + } - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - - default: + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, + conf->vpp); return -1; } - PCCR = pccr; - PA_DWR = gpio; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } - return 0; + return ret; } struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - graphicsmaster_pcmcia_init, - graphicsmaster_pcmcia_shutdown, - graphicsmaster_pcmcia_socket_state, - graphicsmaster_pcmcia_get_irq_info, - graphicsmaster_pcmcia_configure_socket + init: graphicsmaster_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: graphicsmaster_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_h3600.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_h3600.c --- linux-2.4.18/drivers/pcmcia/sa1100_h3600.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_h3600.c Sat Mar 30 22:55:40 2002 @@ -9,139 +9,188 @@ #include #include -#include +#include "sa1100_generic.h" +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, + { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } +}; -static int h3600_pcmcia_init(struct pcmcia_init *init){ - int irq, res; - - /* Enable CF bus: */ - set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON); - clr_h3600_egpio(EGPIO_H3600_OPT_RESET); - - /* All those are inputs */ - GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1); - - /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE ); - - /* Register interrupts */ - irq = IRQ_GPIO_H3600_PCMCIA_CD0; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL ); - if( res < 0 ) goto irq_err; - irq = IRQ_GPIO_H3600_PCMCIA_CD1; - res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL ); - if( res < 0 ) goto irq_err; +static int h3600_pcmcia_init(struct pcmcia_init *init) +{ + int i, res; - return 2; + /* + * Set transition detect + */ + set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1, + GPIO_FALLING_EDGE); + + /* + * Register interrupts + */ + for (i = res = 0; i < ARRAY_SIZE(irqs); i++) { + res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (res) + break; + } + + if (res) { + printk(KERN_ERR "h3600_pcmcia: request for IRQ%d failed: %d\n", + irqs[i].irq, res); + + while (i--) + free_irq(irqs[i].irq, NULL); + } -irq_err: - printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); - return -1; + return res ? -1 : 2; } static int h3600_pcmcia_shutdown(void) { - /* disable IRQs */ - free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL ); - free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); + int i; + + /* + * disable IRQs + */ + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); - /* Disable CF bus: */ - clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON); - set_h3600_egpio(EGPIO_H3600_OPT_RESET); + /* Disable CF bus: */ + clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); + set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); - return 0; + return 0; } -static int h3600_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long levels; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); +static int +h3600_pcmcia_socket_state(struct pcmcia_state_array *state) +{ + unsigned long levels; - levels=GPLR; + if (state->size < 2) + return -1; - state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0; - state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0; - state_array->state[0].bvd1= 0; - state_array->state[0].bvd2= 0; - state_array->state[0].wrprot=0; /* Not available on H3600. */ - state_array->state[0].vs_3v=0; - state_array->state[0].vs_Xv=0; + levels = GPLR; - state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; - state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; - state_array->state[1].bvd1=0; - state_array->state[1].bvd2=0; - state_array->state[1].wrprot=0; /* Not available on H3600. */ - state_array->state[1].vs_3v=0; - state_array->state[1].vs_Xv=0; + state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1; + state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0; + state->state[0].bvd1 = 0; + state->state[0].bvd2 = 0; + state->state[0].wrprot = 0; /* Not available on H3600. */ + state->state[0].vs_3v = 0; + state->state[0].vs_Xv = 0; + + state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1; + state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0; + state->state[1].bvd1 = 0; + state->state[1].bvd2 = 0; + state->state[1].wrprot = 0; /* Not available on H3600. */ + state->state[1].vs_3v = 0; + state->state[1].vs_Xv = 0; - return 1; + return 1; } -static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch (info->sock) { - case 0: - info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0; - break; - case 1: - info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1; - break; - default: - return -1; - } - return 0; +static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + switch (info->sock) { + case 0: + info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0; + break; + case 1: + info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1; + break; + default: + return -1; + } + return 0; } -static int h3600_pcmcia_configure_socket(const struct pcmcia_configure - *configure) +static int +h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - unsigned long flags; - - if(configure->sock>1) return -1; + if (conf->sock > 1) + return -1; - save_flags_cli(flags); + if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) { + printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", + conf->vcc / 10, conf->vcc % 10); + return -1; + } + + if (conf->reset) + set_h3600_egpio(IPAQ_EGPIO_CARD_RESET); + else + clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); - switch (configure->vcc) { - case 0: - clr_h3600_egpio(EGPIO_H3600_OPT_ON); - break; + /* Silently ignore Vpp, output enable, speaker enable. */ - case 33: - case 50: - set_h3600_egpio(EGPIO_H3600_OPT_ON); - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - restore_flags(flags); - return -1; - } + return 0; +} - if (configure->reset) - set_h3600_egpio(EGPIO_H3600_CARD_RESET); - else - clr_h3600_egpio(EGPIO_H3600_CARD_RESET); +static int h3600_pcmcia_socket_init(int sock) +{ + /* Enable CF bus: */ + set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + set_h3600_egpio(IPAQ_EGPIO_OPT_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(10*HZ / 1000); + + switch (sock) { + case 0: + set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_BOTH_EDGES); + break; + case 1: + set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES); + break; + } - /* Silently ignore Vpp, output enable, speaker enable. */ + return 0; +} - restore_flags(flags); +static int h3600_pcmcia_socket_suspend(int sock) +{ + switch (sock) { + case 0: + set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_NO_EDGES); + break; + case 1: + set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_NO_EDGES); + break; + } + + /* + * FIXME: This doesn't fit well. We don't have the mechanism in + * the generic PCMCIA layer to deal with the idea of two sockets + * on one bus. We rely on the cs.c behaviour shutting down + * socket 0 then socket 1. + */ + if (sock == 1) { + clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); + clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); + /* hmm, does this suck power? */ + set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); + } - return 0; + return 0; } struct pcmcia_low_level h3600_pcmcia_ops = { - h3600_pcmcia_init, - h3600_pcmcia_shutdown, - h3600_pcmcia_socket_state, - h3600_pcmcia_get_irq_info, - h3600_pcmcia_configure_socket + init: h3600_pcmcia_init, + shutdown: h3600_pcmcia_shutdown, + socket_state: h3600_pcmcia_socket_state, + get_irq_info: h3600_pcmcia_get_irq_info, + configure_socket: h3600_pcmcia_configure_socket, + + socket_init: h3600_pcmcia_socket_init, + socket_suspend: h3600_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_jornada720.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_jornada720.c --- linux-2.4.18/drivers/pcmcia/sa1100_jornada720.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_jornada720.c Sat Mar 30 22:55:40 2002 @@ -7,20 +7,22 @@ #include #include -#include #include -#include -#include + +#include "sa1100_generic.h" +#include "sa1111_generic.h" #define SOCKET0_POWER GPIO_GPIO0 #define SOCKET0_3V GPIO_GPIO2 #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) -#define SOCKET1_3V GPIO_GPIO3 +#warning *** Does SOCKET1_3V actually do anything? +#define SOCKET1_3V GPIO_GPIO3 static int jornada720_pcmcia_init(struct pcmcia_init *init) { - int return_val=0; - + /* + * What is all this crap for? + */ GRER |= 0x00000002; /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ PA_DDR = 0; @@ -38,178 +40,68 @@ PC_SDR = 0; PC_SSR = 0; - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "Jornada720 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "Jornada720 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Jornada720 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Jornada720 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; + return sa1111_pcmcia_init(init); } -static int jornada720_pcmcia_shutdown(void) +static int +jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf) { - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int jornada720_pcmcia_socket_state(struct pcmcia_state_array - *state_array) -{ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - status=PCSR; - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - return return_val; -} - -static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - return 0; -} - -static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure - *configure) -{ - unsigned long pccr=PCCR, gpio=PA_DWR; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, - configure->sock, configure->vcc, configure->vpp); - switch(configure->sock){ + conf->sock, conf->vcc, conf->vpp); + + switch (conf->sock) { case 0: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio&=~(SOCKET0_POWER | SOCKET0_3V); - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio |= SOCKET0_POWER | SOCKET0_3V; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER; - break; + pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - switch(configure->vpp){ - case 0: - break; - case 50: - printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__, - configure->vpp); - break; - case 120: - printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__, - configure->vpp); - break; - default: - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break; + case 50: pa_dwr_set = SOCKET0_POWER; break; } - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - gpio &= ~(SOCKET1_POWER); - break; - - case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio |= SOCKET1_POWER; - break; - - case 50: - pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER; - break; + pa_dwr_mask = SOCKET1_POWER; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = SOCKET1_POWER; break; + case 50: pa_dwr_set = SOCKET1_POWER; break; } - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); break; - default: + } + + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); return -1; } - PCCR = pccr; - PA_DWR = gpio; - return 0; + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + locla_irq_restore(flags); + } + + return ret; } struct pcmcia_low_level jornada720_pcmcia_ops = { - jornada720_pcmcia_init, - jornada720_pcmcia_shutdown, - jornada720_pcmcia_socket_state, - jornada720_pcmcia_get_irq_info, - jornada720_pcmcia_configure_socket + init: jornada720_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: jornada720_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_neponset.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_neponset.c --- linux-2.4.18/drivers/pcmcia/sa1100_neponset.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_neponset.c Sat Mar 30 22:55:40 2002 @@ -1,249 +1,129 @@ /* - * drivers/pcmcia/sa1100_neponset.c + * linux/drivers/pcmcia/sa1100_neponset.c * * Neponset PCMCIA specific routines - * */ #include #include -#include #include -#include -#include #include +#include -static int neponset_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; - - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ - PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - - /* MAX1600 to standby mode: */ - PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "Neponset PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "Neponset CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Neponset PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "Neponset CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; -} - -static int neponset_pcmcia_shutdown(void){ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int neponset_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; +#include "sa1100_generic.h" +#include "sa1111_generic.h" - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; +static int neponset_pcmcia_init(struct pcmcia_init *init) +{ + /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ + PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; + /* MAX1600 to standby mode: */ + PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; + return sa1111_pcmcia_init(init); } -static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } +static int +neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int ncr_mask, pa_dwr_mask; + unsigned int ncr_set, pa_dwr_set; + int ret; + + /* Neponset uses the Maxim MAX1600, with the following connections: + + * MAX1600 Neponset + * + * A0VCC SA-1111 GPIO A<1> + * A1VCC SA-1111 GPIO A<0> + * A0VPP CPLD NCR A0VPP + * A1VPP CPLD NCR A1VPP + * B0VCC SA-1111 GPIO A<2> + * B1VCC SA-1111 GPIO A<3> + * B0VPP ground (slot B is CF) + * B1VPP ground (slot B is CF) + * + * VX VCC (5V) + * VY VCC3_3 (3.3V) + * 12INA 12V + * 12INB ground (slot B is CF) + * + * The MAX1600 CODE pin is tied to ground, placing the device in + * "Standard Intel code" mode. Refer to the Maxim data sheet for + * the corresponding truth table. + */ + + switch (conf->sock) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + ncr_mask = NCR_A0VPP | NCR_A1VPP; + + switch (conf->vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; + } + + switch (conf->vpp) { + case 0: ncr_set = 0; break; + case 120: ncr_set = NCR_A1VPP; break; + default: + if (conf->vpp == conf->vcc) + ncr_set = NCR_A0VPP; + else { + printk(KERN_ERR "%s(): unrecognized VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + ncr_mask = 0; + ncr_set = 0; + + switch (conf->vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; + } + + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, conf->vpp); + return -1; + } + break; + + default: + return -1; + } + + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } - return 0; + return 0; } -static int neponset_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR; - - /* Neponset uses the Maxim MAX1600, with the following connections: - * - * MAX1600 Neponset - * - * A0VCC SA-1111 GPIO A<1> - * A1VCC SA-1111 GPIO A<0> - * A0VPP CPLD NCR A0VPP - * A1VPP CPLD NCR A1VPP - * B0VCC SA-1111 GPIO A<2> - * B1VCC SA-1111 GPIO A<3> - * B0VPP ground (slot B is CF) - * B1VPP ground (slot B is CF) - * - * VX VCC (5V) - * VY VCC3_3 (3.3V) - * 12INA 12V - * 12INB ground (slot B is CF) - * - * The MAX1600 CODE pin is tied to ground, placing the device in - * "Standard Intel code" mode. Refer to the Maxim data sheet for - * the corresponding truth table. - */ - - switch(configure->sock){ - case 0: - - switch(configure->vcc){ - case 0: - pccr=(pccr & ~PCCR_S0_FLT); - gpio&=~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - - case 50: - pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - switch(configure->vpp){ - case 0: - ncr&=~(NCR_A0VPP | NCR_A1VPP); - break; - - case 120: - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP; - break; - - default: - if(configure->vpp == configure->vcc) - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP; - else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - - break; - - case 1: - switch(configure->vcc){ - case 0: - pccr=(pccr & ~PCCR_S1_FLT); - gpio&=~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2; - break; - - case 50: - pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } - - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); - return -1; - } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - - break; - - default: - return -1; - } - - PCCR = pccr; - NCR_0 = ncr; - PA_DWR = gpio; +struct pcmcia_low_level neponset_pcmcia_ops = { + init: neponset_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: neponset_pcmcia_configure_socket, - return 0; -} - -struct pcmcia_low_level neponset_pcmcia_ops = { - neponset_pcmcia_init, - neponset_pcmcia_shutdown, - neponset_pcmcia_socket_state, - neponset_pcmcia_get_irq_info, - neponset_pcmcia_configure_socket + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; - diff -urN linux-2.4.18/drivers/pcmcia/sa1100_pangolin.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_pangolin.c --- linux-2.4.18/drivers/pcmcia/sa1100_pangolin.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_pangolin.c Sat Mar 30 22:55:40 2002 @@ -9,22 +9,16 @@ #include #include -#include +#include "sa1100_generic.h" static int pangolin_pcmcia_init(struct pcmcia_init *init){ int irq, res; - /* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */ - GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ); #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */ - GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET); /* Enable PCMCIA bus: */ GPCR = GPIO_PCMCIA_BUS_ON; -#else - /* set GPIO pin GPIO_PCMCIA_RESET as output */ - GPDR |= GPIO_PCMCIA_RESET; #endif + /* Set transition detect */ set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES ); set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE ); @@ -147,11 +141,26 @@ return 0; } +static int pangolin_pcmcia_socket_init(int sock) +{ + /* enable card status IRQs - see sa1100_assabet.c for details */ + return -1; +} + +static int pangolin_pcmcia_socket_suspend(int sock) +{ + /* disable card status IRQs - see sa1100_assabet.c for details */ + return -1; +} + struct pcmcia_low_level pangolin_pcmcia_ops = { - pangolin_pcmcia_init, - pangolin_pcmcia_shutdown, - pangolin_pcmcia_socket_state, - pangolin_pcmcia_get_irq_info, - pangolin_pcmcia_configure_socket + init: pangolin_pcmcia_init, + shutdown: pangolin_pcmcia_shutdown, + socket_state: pangolin_pcmcia_socket_state, + get_irq_info: pangolin_pcmcia_get_irq_info, + configure_socket: pangolin_pcmcia_configure_socket, + + socket_init: pangolin_pcmcia_socket_init, + socket_suspend, pangolin_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_pfs168.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_pfs168.c --- linux-2.4.18/drivers/pcmcia/sa1100_pfs168.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_pfs168.c Sat Mar 30 22:55:40 2002 @@ -11,117 +11,26 @@ #include #include #include -#include -static int pfs168_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; +#include "sa1100_generic.h" +#include "sa1111_generic.h" +static int pfs168_pcmcia_init(struct pcmcia_init *init) +{ /* TPS2211 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "PFS168 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "PFS168 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "PFS168 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "PFS168 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; -} - -static int pfs168_pcmcia_shutdown(void){ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int pfs168_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int pfs168_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; + return sa1111_pcmcia_init(init); } -static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, gpio=PA_DWR; +static int +pfs168_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int pa_dwr_mask = 0, pa_dwr_set = 0; + int ret; /* PFS168 uses the Texas Instruments TPS2211 for PCMCIA (socket 0) voltage control only, * with the following connections: @@ -135,103 +44,85 @@ * */ - switch(configure->sock){ + switch (conf->sock) { case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S0_FLT); - gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; - gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; - - case 50: - pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); - gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO0; break; + case 50: pa_dwr_set = GPIO_GPIO1; break; } - switch(configure->vpp){ + switch (conf->vpp) { case 0: - gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3); break; case 120: - printk(KERN_ERR "%s(): PFS-168 does not support Vpp %uV\n", __FUNCTION__, - configure->vpp/10); + printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n", + __FUNCTION__, conf->vpp / 10); return -1; break; default: - if(configure->vpp == configure->vcc) - gpio = (gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; + if (conf->vpp == conf->vcc) + pa_dwr_set |= GPIO_GPIO3; else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); + printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__, + conf->vpp); return -1; } } - - pccr = (configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - - PA_DWR = gpio; - break; case 1: - switch(configure->vcc){ - case 0: - pccr = (pccr & ~PCCR_S1_FLT); - break; + pa_dwr_mask = 0; + pa_dwr_set = 0; + switch (conf->vcc) { + case 0: case 33: - pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; break; case 50: - printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support Vcc %uV\n", __FUNCTION__, - configure->vcc/10); + printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n", + __FUNCTION__, conf->vcc / 10); return -1; - break; default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__, + conf->vcc); return -1; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CompactFlash socket does not support Vpp %uV\n", __FUNCTION__, - configure->vpp/10); + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n" + __FUNCTION__, conf->vpp/10); return -1; } - - pccr = (configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - break; - - default: - return -1; } - PCCR = pccr; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } return 0; } struct pcmcia_low_level pfs168_pcmcia_ops = { - pfs168_pcmcia_init, - pfs168_pcmcia_shutdown, - pfs168_pcmcia_socket_state, - pfs168_pcmcia_get_irq_info, - pfs168_pcmcia_configure_socket + init: pfs168_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: pfs168_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_shannon.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_shannon.c --- linux-2.4.18/drivers/pcmcia/sa1100_shannon.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_shannon.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,144 @@ +/* + * drivers/pcmcia/sa1100_shannon.c + * + * PCMCIA implementation routines for Shannon + * + */ +#include +#include + +#include +#include +#include +#include "sa1100_generic.h" + +static int shannon_pcmcia_init(struct pcmcia_init *init) +{ + int irq, res; + + /* All those are inputs */ + GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | + SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); + GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | + SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); + + /* Set transition detect */ + set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1, GPIO_NO_EDGES); + set_GPIO_IRQ_edge(SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1, GPIO_FALLING_EDGE); + + /* Register interrupts */ + irq = SHANNON_IRQ_GPIO_EJECT_0; + res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA_CD_0", NULL); + if (res < 0) goto irq_err; + irq = SHANNON_IRQ_GPIO_EJECT_1; + res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA_CD_1", NULL); + if (res < 0) goto irq_err; + + return 2; +irq_err: + printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq); + return -1; +} + +static int shannon_pcmcia_shutdown(void) +{ + /* disable IRQs */ + free_irq(SHANNON_IRQ_GPIO_EJECT_0, NULL); + free_irq(SHANNON_IRQ_GPIO_EJECT_1, NULL); + + return 0; +} + +static int shannon_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + unsigned long levels; + + memset(state_array->state, 0, + state_array->size * sizeof(struct pcmcia_state)); + + levels = GPLR; + + state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; + state_array->state[0].ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0; + state_array->state[0].wrprot = 0; /* Not available on Shannon. */ + state_array->state[0].bvd1 = 1; + state_array->state[0].bvd2 = 1; + state_array->state[0].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ + state_array->state[0].vs_Xv = 0; + + state_array->state[1].detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1; + state_array->state[1].ready = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0; + state_array->state[1].wrprot = 0; /* Not available on Shannon. */ + state_array->state[1].bvd1 = 1; + state_array->state[1].bvd2 = 1; + state_array->state[1].vs_3v = 1; /* FIXME Can only apply 3.3V on Shannon. */ + state_array->state[1].vs_Xv = 0; + + return 1; +} + +static int shannon_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (info->sock == 0) + info->irq = SHANNON_IRQ_GPIO_RDY_0; + else if (info->sock == 1) + info->irq = SHANNON_IRQ_GPIO_RDY_1; + else return -1; + + return 0; +} + +static int shannon_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + + switch (configure->vcc) { + case 0: /* power off */; + printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n"); + break; + case 50: + printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n"); + case 33: + break; + default: + printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", + configure->vcc); + return -1; + } + + printk(KERN_WARNING __FUNCTION__"(): Warning, Can't perform reset\n"); + + /* Silently ignore Vpp, output enable, speaker enable. */ + + return 0; +} + +static int shannon_pcmcia_socket_init(int sock) +{ + if (sock == 0) + set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0, GPIO_BOTH_EDGES); + else if (sock == 1) + set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_1, GPIO_BOTH_EDGES); + + return 0; +} + +static int shannon_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) + set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0, GPIO_NO_EDGES); + else if (sock == 1) + set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_1, GPIO_NO_EDGES); + + return 0; +} + +struct pcmcia_low_level shannon_pcmcia_ops = { + init: shannon_pcmcia_init, + shutdown: shannon_pcmcia_shutdown, + socket_state: shannon_pcmcia_socket_state, + get_irq_info: shannon_pcmcia_get_irq_info, + configure_socket: shannon_pcmcia_configure_socket, + + socket_init: shannon_pcmcia_socket_init, + socket_suspend: shannon_pcmcia_socket_suspend, +}; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_simpad.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_simpad.c --- linux-2.4.18/drivers/pcmcia/sa1100_simpad.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_simpad.c Sat Mar 30 22:55:40 2002 @@ -9,7 +9,7 @@ #include #include -#include +#include "sa1100_generic.h" extern long get_cs3_shadow(void); extern void set_cs3_bit(int value); @@ -19,9 +19,6 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){ int irq, res; - /* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */ - GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ); - set_cs3_bit(PCMCIA_RESET); clear_cs3_bit(PCMCIA_BUFF_DIS); clear_cs3_bit(PCMCIA_RESET); @@ -29,7 +26,7 @@ clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES ); + set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_NO_EDGES ); set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); /* Register interrupts */ @@ -146,11 +143,26 @@ return 0; } +static int simpad_pcmcia_socket_init(int sock) +{ + set_GPIO_IRQ_edge(GPIO_CF_CD, GPIO_BOTH_EDGES); + return 0; +} + +static int simpad_pcmcia_socket_suspend(int sock) +{ + set_GPIO_IRQ_edge(GPIO_CF_CD, GPIO_NO_EDGES); + return 0; +} + struct pcmcia_low_level simpad_pcmcia_ops = { - simpad_pcmcia_init, - simpad_pcmcia_shutdown, - simpad_pcmcia_socket_state, - simpad_pcmcia_get_irq_info, - simpad_pcmcia_configure_socket + init: simpad_pcmcia_init, + shutdown: simpad_pcmcia_shutdown, + socket_state: simpad_pcmcia_socket_state, + get_irq_info: simpad_pcmcia_get_irq_info, + configure_socket: simpad_pcmcia_configure_socket, + + socket_init: simpad_pcmcia_socket_init, + socket_suspend: simpad_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_stork.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_stork.c --- linux-2.4.18/drivers/pcmcia/sa1100_stork.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_stork.c Sat Mar 30 22:55:40 2002 @@ -28,7 +28,7 @@ #include #include -#include +#include "sa1100_generic.h" static int debug = 0; @@ -41,14 +41,8 @@ sa1100_stork_pcmcia_init = *init; - /* Enable CF bus: */ - storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); - - /* All those are inputs */ - GPDR &= ~(GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT | GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY); - /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES ); + set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_NO_EDGES ); set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY, GPIO_FALLING_EDGE ); /* Register interrupts */ @@ -192,11 +186,41 @@ return 0; } +static int stork_pcmcia_socket_init(int sock) +{ + storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); + + if (sock == 0) + set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_A_CARD_DETECT, GPIO_BOTH_EDGES); + else if (sock == 1) + set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES); + + return 0; +} + +static int stork_pcmcia_socket_suspend(int sock) +{ + if (sock == 0) + set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_A_CARD_DETECT, GPIO_NO_EDGES); + else if (sock == 1) { + set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_NO_EDGES); + + /* + * Hack! + */ + storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); + } + + return 0; +} + struct pcmcia_low_level stork_pcmcia_ops = { - stork_pcmcia_init, - stork_pcmcia_shutdown, - stork_pcmcia_socket_state, - stork_pcmcia_get_irq_info, - stork_pcmcia_configure_socket -}; + init: stork_pcmcia_init, + shutdown: stork_pcmcia_shutdown, + socket_state: stork_pcmcia_socket_state, + get_irq_info: stork_pcmcia_get_irq_info, + configure_socket: stork_pcmcia_configure_socket, + socket_init: stork_pcmcia_socket_init, + socket_suspend: stork_pcmcia_socket_suspend, +}; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_xp860.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_xp860.c --- linux-2.4.18/drivers/pcmcia/sa1100_xp860.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_xp860.c Sat Mar 30 22:55:40 2002 @@ -10,125 +10,42 @@ #include #include -#include +#include "sa1100_generic.h" #define NCR_A0VPP (1<<16) #define NCR_A1VPP (1<<17) -static int xp860_pcmcia_init(struct pcmcia_init *init){ - int return_val=0; - +static int xp860_pcmcia_init(struct pcmcia_init *init) +{ /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); /* MAX1600 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + +#error Consider the following comment + /* + * 1- Please move GPDR initialisation where it is interrupt or preemption + * safe (like from xp860_map_io). + * 2- The GPCR line is bogus i.e. it will simply have absolutely no effect. + * Please see its definition in the SA1110 manual. + * 3- Please do not use NCR_* values! + */ GPDR |= (NCR_A0VPP | NCR_A1VPP); GPCR &= ~(NCR_A0VPP | NCR_A1VPP); - INTPOL1 |= - (1 << (S0_READY_NINT - SA1111_IRQ(32))) | - (1 << (S1_READY_NINT - SA1111_IRQ(32))) | - (1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))); - - return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, - "XP860 PCMCIA (0) CD", NULL); - return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, - "XP860 CF (1) CD", NULL); - return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "XP860 PCMCIA (0) BVD1", NULL); - return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, - "XP860 CF (1) BVD1", NULL); - - return (return_val<0) ? -1 : 2; + return sa1111_pcmcia_init(init); } -static int xp860_pcmcia_shutdown(void){ - - free_irq(S0_CD_VALID, NULL); - free_irq(S1_CD_VALID, NULL); - free_irq(S0_BVD1_STSCHG, NULL); - free_irq(S1_BVD1_STSCHG, NULL); - - INTPOL1 &= - ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | - (1 << (S1_CD_VALID - SA1111_IRQ(32))) | - (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) | - (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)))); - - return 0; -} - -static int xp860_pcmcia_socket_state(struct pcmcia_state_array - *state_array){ - unsigned long status; - int return_val=1; - - if(state_array->size<2) return -1; - - memset(state_array->state, 0, - (state_array->size)*sizeof(struct pcmcia_state)); - - status=PCSR; - - state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; - - state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; - - state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; - - state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; - - state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; - - state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; - - state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; - - state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; - - state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; - - state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; - - state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; - - state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; - - state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; - - state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; - - return return_val; -} - -static int xp860_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ - - switch(info->sock){ - case 0: - info->irq=S0_READY_NINT; - break; - - case 1: - info->irq=S1_READY_NINT; - break; - - default: - return -1; - } - - return 0; -} - -static int xp860_pcmcia_configure_socket(const struct pcmcia_configure - *configure){ - unsigned long pccr=PCCR, ncr=GPLR, gpio=PA_DWR; - +static int +xp860_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int gpio_mask, pa_dwr_mask; + unsigned int gpio_set, pa_dwr_set; + int ret; /* Neponset uses the Maxim MAX1600, with the following connections: +#warning ^^^ This isn't a neponset! * * MAX1600 Neponset * @@ -151,105 +68,75 @@ * the corresponding truth table. */ - switch(configure->sock){ + switch (conf->sock) { case 0: - - switch(configure->vcc){ - case 0: - gpio&=~(GPIO_GPIO0 | GPIO_GPIO1); - break; - - case 33: - pccr=(pccr & ~PCCR_S0_PSE); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1; - break; - - case 50: - pccr=(pccr | PCCR_S0_PSE); - gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0; - break; + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + gpio_mask = NCR_A0VPP | NCR_A1VPP; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; } - switch(configure->vpp){ - case 0: - ncr&=~(NCR_A0VPP | NCR_A1VPP); - break; - - case 120: - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP; - break; + switch (conf->vpp) { + case 0: gpio_set = 0; break; + case 120: gpio_set = NCR_A1VPP; break; default: - if(configure->vpp == configure->vcc) - ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP; + if (conf->vpp == conf->vcc) + gpio_set = NCR_A0VPP; else { - printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, - configure->vpp); + printk(KERN_ERR "%s(): unrecognized Vpp %u\n", + __FUNCTION__, conf->vpp); return -1; } } - - pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST); - pccr=(configure->output)?(pccr | PCCR_S0_FLT):(pccr & ~PCCR_S0_FLT); - break; case 1: - switch(configure->vcc){ - case 0: - gpio&=~(GPIO_GPIO2 | GPIO_GPIO3); - break; - - case 33: - pccr=(pccr & ~PCCR_S1_PSE); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2; - break; - - case 50: - pccr=(pccr | PCCR_S1_PSE); - gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3; - break; + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + gpio_mask = 0; + gpio_set = 0; + switch (conf->vcc) { default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; } - if(configure->vpp!=configure->vcc && configure->vpp!=0){ - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - configure->vpp); + if (conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, conf->vpp); return -1; } - - pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); - pccr=(configure->output)?(pccr | PCCR_S1_FLT):(pccr & ~PCCR_S1_FLT); - break; - - default: - return -1; } - PCCR = pccr; - ncr &= NCR_A0VPP|NCR_A1VPP; - GPSR = ncr; - GPCR = (~ncr)&(NCR_A0VPP|NCR_A1VPP); - PA_DWR = gpio; + ret = sa1111_pcmcia_configure_socket(conf); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + GPSR = gpio_set; + GPCR = gpio_set ^ gpio_mask; + local_irq_restore(flags); + } - return 0; + return ret; } struct pcmcia_low_level xp860_pcmcia_ops = { - xp860_pcmcia_init, - xp860_pcmcia_shutdown, - xp860_pcmcia_socket_state, - xp860_pcmcia_get_irq_info, - xp860_pcmcia_configure_socket + init: xp860_pcmcia_init, + shutdown: sa1111_pcmcia_shutdown, + socket_state: sa1111_pcmcia_socket_state, + get_irq_info: sa1111_pcmcia_get_irq_info, + configure_socket: xp860_pcmcia_configure_socket, + + socket_init: sa1111_pcmcia_socket_init, + socket_suspend: sa1111_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1100_yopy.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_yopy.c --- linux-2.4.18/drivers/pcmcia/sa1100_yopy.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_yopy.c Sat Mar 30 22:55:40 2002 @@ -9,7 +9,7 @@ #include #include -#include +#include "sa1100_generic.h" static inline void pcmcia_power(int on) { @@ -30,13 +30,9 @@ pcmcia_power(0); pcmcia_reset(1); - /* All those are inputs */ - GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ); - GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ); - /* Set transition detect */ - set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, - GPIO_BOTH_EDGES ); + set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, + GPIO_NO_EDGES); set_GPIO_IRQ_edge( GPIO_CF_IREQ, GPIO_FALLING_EDGE ); /* Register interrupts */ @@ -130,10 +126,27 @@ return 0; } +static int yopy_pcmcia_socket_init(int sock) +{ + set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, + GPIO_BOTH_EDGES); + return 0; +} + +static int yopy_pcmcia_socket_suspend(int sock) +{ + set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, + GPIO_NO_EDGES); + return 0; +} + struct pcmcia_low_level yopy_pcmcia_ops = { - yopy_pcmcia_init, - yopy_pcmcia_shutdown, - yopy_pcmcia_socket_state, - yopy_pcmcia_get_irq_info, - yopy_pcmcia_configure_socket + init: yopy_pcmcia_init, + shutdown: yopy_pcmcia_shutdown, + socket_state: yopy_pcmcia_socket_state, + get_irq_info: yopy_pcmcia_get_irq_info, + configure_socket: yopy_pcmcia_configure_socket, + + socket_init: yopy_pcmcia_socket_init, + socket_suspend: yopy_pcmcia_socket_suspend, }; diff -urN linux-2.4.18/drivers/pcmcia/sa1111_generic.c linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.c --- linux-2.4.18/drivers/pcmcia/sa1111_generic.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.c Sat Mar 30 22:55:40 2002 @@ -0,0 +1,189 @@ +/* + * linux/drivers/pcmcia/sa1100_sa1111.c + * + * We implement the generic parts of a SA1111 PCMCIA driver. This + * basically means we handle everything except controlling the + * power. Power is machine specific... + */ +#include +#include +#include + +#include +#include +#include + +#include "sa1100_generic.h" +#include "sa1111_generic.h" + +static struct irqs { + int irq; + const char *str; +} irqs[] = { + { S0_CD_VALID, "SA1111 PCMCIA card detect" }, + { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, + { S1_CD_VALID, "SA1111 CF card detect" }, + { S1_BVD1_STSCHG, "SA1111 CF BVD1" }, +}; + +int sa1111_pcmcia_init(struct pcmcia_init *init) +{ + int i, ret; + + if (!request_mem_region(_PCCR, 512, "PCMCIA")) + return -1; + + INTPOL1 |= SA1111_IRQMASK_HI(S0_CD_VALID) | + SA1111_IRQMASK_HI(S1_CD_VALID) | + SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | + SA1111_IRQMASK_HI(S1_BVD1_STSCHG); + + for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) { + ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, + irqs[i].str, NULL); + if (ret) + break; + } + + if (i < ARRAY_SIZE(irqs)) { + printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n", + irqs[i].irq, ret); + while (i--) + free_irq(irqs[i].irq, NULL); + + release_mem_region(_PCCR, 16); + } + + return ret ? -1 : 2; +} + +int sa1111_pcmcia_shutdown(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) + free_irq(irqs[i].irq, NULL); + + INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | + SA1111_IRQMASK_HI(S1_CD_VALID) | + SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | + SA1111_IRQMASK_HI(S1_BVD1_STSCHG)); + + release_mem_region(_PCCR, 512); + + return 0; +} + +int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state) +{ + unsigned long status; + + if (state->size < 2) + return -1; + + status = PCSR; + + state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; + state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; + state->state[0].bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; + state->state[0].bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; + state->state[0].wrprot = status & PCSR_S0_WP ? 1 : 0; + state->state[0].vs_3v = status & PCSR_S0_VS1 ? 0 : 1; + state->state[0].vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; + + state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1; + state->state[1].ready = status & PCSR_S1_READY ? 1 : 0; + state->state[1].bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; + state->state[1].bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; + state->state[1].wrprot = status & PCSR_S1_WP ? 1 : 0; + state->state[1].vs_3v = status & PCSR_S1_VS1 ? 0 : 1; + state->state[1].vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; + + return 1; +} + +int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + int ret = 0; + + switch (info->sock) { + case 0: info->irq = S0_READY_NINT; break; + case 1: info->irq = S1_READY_NINT; break; + default: ret = 1; + } + + return ret; +} + +int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + unsigned int rst, flt, wait, pse, irq, pccr_mask; + unsigned long flags; + + switch (conf->sock) { + case 0: + rst = PCCR_S0_RST; + flt = PCCR_S0_FLT; + wait = PCCR_S0_PWAITEN; + pse = PCCR_S0_PSE; + irq = S0_READY_NINT; + break; + + case 1: + rst = PCCR_S1_RST; + flt = PCCR_S1_FLT; + wait = PCCR_S1_PWAITEN; + pse = PCCR_S1_PSE; + irq = S1_READY_NINT; + break; + + default: + return -1; + } + + switch (conf->vcc) { + case 0: + pccr_mask = 0; + break; + + case 33: + pccr_mask = wait; + break; + + case 50: + pccr_mask = pse | wait; + break; + + default: + printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n", + conf->vcc); + return -1; + } + + if (conf->reset) + pccr_mask |= rst; + + if (conf->output) + pccr_mask |= flt; + + local_irq_save(flags); + PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask; + local_irq_restore(flags); + + if (conf->irq) + enable_irq(irq); + else + disable_irq(irq); + + return 0; +} + +int sa1111_pcmcia_socket_init(int sock) +{ + return 0; +} + +int sa1111_pcmcia_socket_suspend(int sock) +{ + return 0; +} diff -urN linux-2.4.18/drivers/pcmcia/sa1111_generic.h linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.h --- linux-2.4.18/drivers/pcmcia/sa1111_generic.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.h Sat Mar 30 22:55:40 2002 @@ -0,0 +1,15 @@ +extern int sa1111_pcmcia_init(struct pcmcia_init *); +extern int sa1111_pcmcia_shutdown(void); +extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *); +extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *); +extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *); +extern int sa1111_pcmcia_socket_init(int); +extern int sa1111_pcmcia_socket_suspend(int); + +/* + * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c + */ +#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) +#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) + + diff -urN linux-2.4.18/drivers/pcmcia/ti113x.h linux-2.4.19-pre5/drivers/pcmcia/ti113x.h --- linux-2.4.18/drivers/pcmcia/ti113x.h Mon Feb 18 06:26:35 2002 +++ linux-2.4.19-pre5/drivers/pcmcia/ti113x.h Sat Mar 30 22:55:28 2002 @@ -170,9 +170,88 @@ return 0; } +/* + * Zoom video control for TI122x/113x chips + */ + +static void ti_zoom_video(pci_socket_t *socket, int onoff) +{ + u8 reg; + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} + +/* + * The 145x series can also use this. They have an additional + * ZV autodetect mode we don't use but don't actually need. + * FIXME: manual says its in func0 and func1 but disagrees with + * itself about this - do we need to force func0, if so we need + * to know a lot more about socket pairings in pci_socket than we + * do now.. uggh. + */ + +static void ti1250_zoom_video(pci_socket_t *socket, int onoff) +{ + int shift = 0; + u8 reg; + + ti_zoom_video(socket, onoff); + + reg = config_readb(socket, 0x84); + reg |= (1<<7); /* ZV bus enable */ + + if(PCI_FUNC(socket->dev->devfn)==1) + shift = 1; + + if(onoff) + { + reg &= ~(1<<6); /* Clear select bit */ + reg |= shift<<6; /* Favour our socket */ + reg |= 1<dev->vendor == PCI_VENDOR_ID_TI) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_TI_1220: + case PCI_DEVICE_ID_TI_1221: + case PCI_DEVICE_ID_TI_1225: + socket->zoom_video = ti_zoom_video; + break; + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + socket->zoom_video = ti1250_zoom_video; + } + } +} + static int ti_init(pci_socket_t *socket) { yenta_init(socket); + ti_set_zv(socket); ti_intctl(socket); return 0; } @@ -251,7 +330,7 @@ static int ti1250_init(pci_socket_t *socket) { yenta_init(socket); - + ti_set_zv(socket); config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); ti_intctl(socket); return 0; diff -urN linux-2.4.18/drivers/pcmcia/yenta.c linux-2.4.19-pre5/drivers/pcmcia/yenta.c --- linux-2.4.18/drivers/pcmcia/yenta.c Sun Dec 23 16:23:46 2001 +++ linux-2.4.19-pre5/drivers/pcmcia/yenta.c Sat Mar 30 22:55:28 2002 @@ -286,6 +286,9 @@ } exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); + + if(socket->zoom_video) + socket->zoom_video(socket, state->flags & SS_ZVCARD); } config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ diff -urN linux-2.4.18/drivers/pnp/quirks.c linux-2.4.19-pre5/drivers/pnp/quirks.c --- linux-2.4.18/drivers/pnp/quirks.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/pnp/quirks.c Sat Mar 30 22:55:28 2002 @@ -18,6 +18,10 @@ #include #include +#if 0 +#define ISAPNP_DEBUG +#endif + static void __init quirk_awe32_resources(struct pci_dev *dev) { struct isapnp_port *port, *port2, *port3; @@ -139,8 +143,10 @@ while (isapnp_fixups[i].vendor != 0) { if ((isapnp_fixups[i].vendor == dev->vendor) && (isapnp_fixups[i].device == dev->device)) { +#ifdef ISAPNP_DEBUG printk(KERN_DEBUG "isapnp: Calling quirk for %02x:%02x\n", dev->bus->number, dev->devfn); +#endif isapnp_fixups[i].quirk_function(dev); } i++; diff -urN linux-2.4.18/drivers/s390/block/dasd_int.h linux-2.4.19-pre5/drivers/s390/block/dasd_int.h --- linux-2.4.18/drivers/s390/block/dasd_int.h Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/s390/block/dasd_int.h Sat Mar 30 22:55:29 2002 @@ -203,14 +203,14 @@ debug_sprintf_event(d_device->debug_area,d_level,\ DASD_DEVICE_FORMAT_STRING d_str "\n",\ d_device, d_data);\ -} while(0); +} while(0) #define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ do {\ if ( d_device->debug_area != NULL )\ debug_sprintf_exception(d_device->debug_area,d_level,\ DASD_DEVICE_FORMAT_STRING d_str "\n",\ d_device, d_data);\ -} while(0); +} while(0) #define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" #define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ @@ -219,14 +219,14 @@ debug_sprintf_event(dasd_debug_area, d_level,\ DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ d_fn, d_data);\ -} while(0); +} while(0) #define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ do {\ if ( dasd_debug_area != NULL )\ debug_sprintf_exception(dasd_debug_area, d_level,\ DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ d_fn, d_data);\ -} while(0); +} while(0) struct dasd_device_t; struct request; diff -urN linux-2.4.18/drivers/s390/char/hwc_con.c linux-2.4.19-pre5/drivers/s390/char/hwc_con.c --- linux-2.4.18/drivers/s390/char/hwc_con.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/s390/char/hwc_con.c Sat Mar 30 22:55:40 2002 @@ -31,20 +31,12 @@ #define HWC_CON_PRINT_HEADER "hwc console driver: " -struct console hwc_console = -{ - - hwc_console_name, - hwc_console_write, - NULL, - hwc_console_device, - NULL, - hwc_console_unblank, - NULL, - CON_PRINTBUFFER, - 0, - 0, - NULL +struct console hwc_console = { + name: hwc_console_name, + write: hwc_console_write, + device: hwc_console_device, + unblank:hwc_console_unblank, + flags: CON_PRINTBUFFER, }; void diff -urN linux-2.4.18/drivers/s390/char/tape34xx.c linux-2.4.19-pre5/drivers/s390/char/tape34xx.c --- linux-2.4.18/drivers/s390/char/tape34xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/s390/char/tape34xx.c Sat Mar 30 22:55:29 2002 @@ -2152,7 +2152,7 @@ tape34xx_error_recovery_HWBUG(ti,21); return; case 0x3490: - // Resetting event recieved. Since the driver does not support resetting event recovery + // Resetting event received. Since the driver does not support resetting event recovery // (which has to be handled by the I/O Layer), we'll report and retry our command. tape34xx_error_recovery_do_retry(ti); return; @@ -2219,7 +2219,7 @@ return; case 0x3490: // Global status intercept. We have to reissue the command. - PRINT_WARN("An global status intercept was recieved, which will be recovered.\n"); + PRINT_WARN("An global status intercept was received, which will be recovered.\n"); tape34xx_error_recovery_do_retry(ti); return; } diff -urN linux-2.4.18/drivers/s390/misc/chandev.c linux-2.4.19-pre5/drivers/s390/misc/chandev.c --- linux-2.4.18/drivers/s390/misc/chandev.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/s390/misc/chandev.c Sat Mar 30 22:55:35 2002 @@ -902,25 +902,6 @@ (int)lo_devno,(int)hi_devno); return; } - chandev_lock(); - for_each(parms,chandev_parms_head) - { - if(chan_type&(parms->chan_type)) - { - u16 lomax=MAX(parms->lo_devno,lo_devno), - himin=MIN(parms->hi_devno,lo_devno); - if(lomax<=himin) - { - chandev_unlock(); - printk("chandev_add_parms detected overlapping " - "parameter definitions for chan_type=0x%02x" - " lo_devno=0x%04x hi_devno=0x%04x\n," - " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno); - return; - } - } - } - chandev_unlock(); if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr)))) { parms->chan_type=chan_type; @@ -1727,8 +1708,16 @@ read->sch.devno>=curr_parms->lo_devno&& read->sch.devno<=curr_parms->hi_devno) { - probeinfo.parmstr=curr_parms->parmstr; - break; + if (!probeinfo.parmstr) { + probeinfo.parmstr = vmalloc(sizeof(curr_parms->parmstr)+1); + strcpy(probeinfo.parmstr, curr_parms->parmstr); + } else { + char *buf; + + buf = vmalloc(strlen(probeinfo.parmstr)+strlen(curr_parms->parmstr)+2); + sprintf(buf, "%s,%s",probeinfo.parmstr, curr_parms->parmstr); + probeinfo.parmstr=buf; + } } } if(force) @@ -2024,7 +2013,7 @@ /* This is required because the device can go & come back */ /* even before we realize it is gone owing to the waits in our kernel threads */ /* & the device will be marked as not owned but its status will be good */ - /* & an attempt to accidently reprobe it may be done. */ + /* & an attempt to accidentally reprobe it may be done. */ remove: chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq)); diff -urN linux-2.4.18/drivers/s390/net/Makefile linux-2.4.19-pre5/drivers/s390/net/Makefile --- linux-2.4.18/drivers/s390/net/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/s390/net/Makefile Sat Mar 30 22:55:35 2002 @@ -9,8 +9,8 @@ ctc-objs := ctcmain.o ctctty.o -obj-y += iucv.o fsm.o -obj-$(CONFIG_CTC) += ctc.o +obj-$(CONFIG_IUCV) += iucv.o fsm.o +obj-$(CONFIG_CTC) += ctc.o fsm.o obj-$(CONFIG_IUCV) += netiucv.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/s390/net/ctctty.c linux-2.4.19-pre5/drivers/s390/net/ctctty.c --- linux-2.4.18/drivers/s390/net/ctctty.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/s390/net/ctctty.c Sat Mar 30 22:55:40 2002 @@ -286,7 +286,7 @@ if (!info->netdev) { if (skb) - kfree(skb); + kfree_skb(skb); return 0; } if (info->flags & CTC_ASYNC_TX_LINESTAT) { diff -urN linux-2.4.18/drivers/s390/net/iucv.c linux-2.4.19-pre5/drivers/s390/net/iucv.c --- linux-2.4.18/drivers/s390/net/iucv.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/s390/net/iucv.c Sat Mar 30 22:55:35 2002 @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: iucv.c,v 1.32 2002/02/12 21:52:20 felfert Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision$ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.32 $ * */ @@ -51,7 +51,7 @@ #include #include -#undef DEBUG +#define DEBUG /* FLAGS: * All flags are defined in the field IPFLAGS1 of each function @@ -165,6 +165,10 @@ * declare_flag: is 0 when iucv_declare_buffer has not been called */ static int declare_flag; +/** + * register_flag: is 0 when external interrupt has not been registered + */ +static int register_flag; /****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ /* Data struct 1: iparml_control @@ -271,37 +275,56 @@ static iucv_param * iucv_param_pool; +MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); +MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12)) +MODULE_LICENSE("GPL"); +#endif + /* * Debugging stuff *******************************************************************************/ + #ifdef DEBUG +static int debuglevel = 0; + +MODULE_PARM(debuglevel, "i"); +MODULE_PARM_DESC(debuglevel, + "Specifies the debug level (0=off ... 3=all)"); static void -iucv_dumpit(void *buf, int len) +iucv_dumpit(char *title, void *buf, int len) { int i; __u8 *p = (__u8 *)buf; - printk(KERN_DEBUG " "); + if (debuglevel < 3) + return; + + printk(KERN_DEBUG __FUNCTION__ ": %s\n", title); + printk(" "); for (i = 0; i < len; i++) { if (!(i % 16) && i != 0) printk ("\n "); else if (!(i % 4) && i != 0) - printk (" "); - printk ("%02X", *p++); + printk(" "); + printk("%02X", *p++); } if (len % 16) printk ("\n"); return; } -#define iucv_debug(fmt, args...) \ -printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args); +#define iucv_debug(lvl, fmt, args...) \ +do { \ + if (debuglevel >= lvl) \ + printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args); \ +} while (0) #else -#define iucv_debug(fmt, args...) -#define iucv_dumpit(buf, len) +#define iucv_debug(lvl, fmt, args...) +#define iucv_dumpit(title, buf, len) #endif @@ -310,6 +333,25 @@ *******************************************************************************/ /** + * print start banner + */ +static void +iucv_banner(void) +{ + char vbuf[] = "$Revision: 1.32 $"; + char *version = vbuf; + + if ((version = strchr(version, ':'))) { + char *p = strchr(version + 1, '$'); + if (p) + *p = '\0'; + } else + version = " ??? "; + printk(KERN_INFO + "IUCV lowlevel driver Version%s initialized\n", version); +} + +/** * iucv_init - Initialization * * Allocates and initializes various data structures. @@ -354,10 +396,26 @@ /* Initialize handler table */ INIT_LIST_HEAD(&iucv_handler_table); + iucv_banner(); return 0; } /** + * iucv_exit - De-Initialization + * + * Frees everything allocated from iucv_init. + */ +static void +iucv_exit(void) +{ + if (iucv_external_int_buffer) + kfree(iucv_external_int_buffer); + if (iucv_param_pool) + kfree(iucv_param_pool); + printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); +} + +/** * grab_param: - Get a parameter buffer from the pre-allocated pool. * * This function searches for an unused element in the the pre-allocated pool @@ -410,8 +468,8 @@ { ulong flags; - iucv_debug("entering"); - iucv_dumpit(new, sizeof(handler)); + iucv_debug(1, "entering"); + iucv_dumpit("handler:", new, sizeof(handler)); spin_lock_irqsave (&iucv_lock, flags); if (!list_empty(&iucv_handler_table)) { @@ -424,7 +482,7 @@ list_for_each(lh, &iucv_handler_table) { handler *h = list_entry(lh, handler, list); if (memcmp(&new->id, &h->id, sizeof(h->id)) == 0) { - iucv_debug("ret 1"); + iucv_debug(1, "ret 1"); spin_unlock_irqrestore (&iucv_lock, flags); return 1; } @@ -437,35 +495,11 @@ list_add(&new->list, &iucv_handler_table); spin_unlock_irqrestore (&iucv_lock, flags); - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return 0; } /** - * iucv_remove_handler: - * @users_handler: handler to be removed - * - * Remove handler when application unregisters. - */ -static void -iucv_remove_handler(handler *handler) -{ - unsigned long flags; - - if ((!iucv_pathid_table) || (!handler)) - return; - - iucv_debug("entering"); - - spin_lock_irqsave (&iucv_lock, flags); - list_del(&handler->list); - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug("exiting"); - return; -} - -/** * b2f0: * @code: identifier of IUCV call to CP. * @parm: pointer to 40 byte iparml area passed to CP @@ -477,8 +511,7 @@ static __inline__ ulong b2f0(__u32 code, void *parm) { - iucv_debug("iparml before b2f0 call:"); - iucv_dumpit(parm, sizeof(iucv_param)); + iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); asm volatile ( "LRA 1,0(%1)\n\t" @@ -489,8 +522,7 @@ : "0", "1" ); - iucv_debug("iparml after b2f0 call:"); - iucv_dumpit(parm, sizeof(iucv_param)); + iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); return (unsigned long)*((__u8 *)(parm + 3)); } @@ -511,9 +543,9 @@ { ulong flags; - iucv_debug("entering"); + iucv_debug(1, "entering"); - iucv_debug("handler is pointing to %p", handler); + iucv_debug(1, "handler is pointing to %p", handler); if (pathid > (max_connections - 1)) return -EINVAL; @@ -521,7 +553,7 @@ spin_lock_irqsave (&iucv_lock, flags); if (iucv_pathid_table[pathid]) { spin_unlock_irqrestore (&iucv_lock, flags); - iucv_debug("pathid entry is %p", iucv_pathid_table[pathid]); + iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); printk(KERN_WARNING "%s: Pathid being used, error.\n", __FUNCTION__); return -EINVAL; @@ -529,7 +561,7 @@ iucv_pathid_table[pathid] = handler; spin_unlock_irqrestore (&iucv_lock, flags); - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return 0; } /* end of add_pathid function */ @@ -546,24 +578,63 @@ spin_unlock_irqrestore (&iucv_lock, flags); } -/* +/** + * iucv_declare_buffer_cpu0 + * Register at VM for subsequent IUCV operations. This is always + * executed on CPU 0. Called from iucv_declare_buffer(). + */ +static void +iucv_declare_buffer_cpu0 (void *result) +{ + iparml_db *parm; + + if (!(result && (smp_processor_id() == 0))) + return; + parm = (iparml_db *)grab_param(); + parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); + if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) + *((ulong *)result) = parm->iprcode; + release_param(parm); +} + +/** + * iucv_retrieve_buffer_cpu0: + * Unregister IUCV usage at VM. This is always executed on CPU 0. + * Called from iucv_retrieve_buffer(). + */ +void +iucv_retrieve_buffer_cpu0 (void *result) +{ + iparml_control *parm; + + if (smp_processor_id() != 0) + return; + parm = (iparml_control *)grab_param(); + b2f0(RETRIEVE_BUFFER, parm); + release_param(parm); +} + +/** * Name: iucv_declare_buffer * Purpose: Specifies the guests real address of an external * interrupt. * Input: void * Output: iprcode - return code from b2f0 call -*/ + */ int iucv_declare_buffer (void) { - ulong b2f0_result; - iparml_db *parm = (iparml_db *)grab_param(); + ulong b2f0_result = 0x0deadbeef; - parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); - b2f0_result = b2f0(DECLARE_BUFFER, parm); - release_param(parm); - iucv_debug("Address of EIB = %p", iucv_external_int_buffer); - iucv_debug("exiting"); + iucv_debug(1, "entering"); + if (smp_processor_id() == 0) + iucv_declare_buffer_cpu0(&b2f0_result); + else + smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1); + iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); + if (b2f0_result == 0x0deadbeef) + b2f0_result = 0xaa; + iucv_debug(1, "exiting"); return b2f0_result; } @@ -576,20 +647,47 @@ int iucv_retrieve_buffer (void) { - ulong b2f0_result = 0; - iparml_control *parm = (iparml_control *)grab_param(); + iucv_debug(1, "entering"); + if (declare_flag) { + if (smp_processor_id() == 0) + iucv_retrieve_buffer_cpu0(0); + else + smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1); + declare_flag = 0; + } + iucv_debug(1, "exiting"); + return 0; +} - iucv_debug("entering"); +/** + * iucv_remove_handler: + * @users_handler: handler to be removed + * + * Remove handler when application unregisters. + */ +static void +iucv_remove_handler(handler *handler) +{ + unsigned long flags; - b2f0_result = b2f0(RETRIEVE_BUFFER, parm); - release_param(parm); - if (b2f0_result == 0) { - kfree(iucv_pathid_table); - iucv_pathid_table = NULL; - declare_flag = 0; + if ((!iucv_pathid_table) || (!handler)) + return; + + iucv_debug(1, "entering"); + + spin_lock_irqsave (&iucv_lock, flags); + list_del(&handler->list); + if (list_empty(&iucv_handler_table)) { + iucv_retrieve_buffer(); + if (register_flag) { + unregister_external_interrupt(0x4000, iucv_irq_handler); + register_flag = 0; + } } - iucv_debug("exiting"); - return b2f0_result; + spin_unlock_irqrestore (&iucv_lock, flags); + + iucv_debug(1, "exiting"); + return; } /** @@ -623,7 +721,7 @@ ulong rc = 0; /* return code from function calls */ handler *new_handler; - iucv_debug("entering"); + iucv_debug(1, "entering"); if (ops == NULL) { /* interrupt table is not defined */ @@ -711,17 +809,41 @@ if (declare_flag == 0) { rc = iucv_declare_buffer(); if (rc) { + char *err = "Unknown"; iucv_remove_handler(new_handler); kfree(new_handler); + switch(rc) { + case 0x03: + err = "Directory error"; + break; + case 0x0a: + err = "Invalid length"; + break; + case 0x13: + err = "Buffer already exists"; + break; + case 0x3e: + err = "Buffer overlap"; + break; + case 0x5c: + err = "Paging or storage error"; + break; + case 0xaa: + err = "Function not called"; + break; + } printk(KERN_WARNING "%s: iucv_declare_buffer " - "returned %ld\n", __FUNCTION__, rc); + "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, + err); return NULL; } + declare_flag = 1; + } + if (register_flag == 0) { /* request the 0x4000 external interrupt */ rc = register_external_interrupt (0x4000, iucv_irq_handler); if (rc) { iucv_remove_handler(new_handler); - iucv_retrieve_buffer(); kfree (new_handler); printk(KERN_WARNING "%s: " "register_external_interrupt returned %ld\n", @@ -729,9 +851,10 @@ return NULL; } - declare_flag = 1; + register_flag = 1; } - iucv_debug("exiting"); + MOD_INC_USE_COUNT; + iucv_debug(1, "exiting"); return new_handler; } /* end of register function */ @@ -741,24 +864,45 @@ * * Unregister application with IUCV. * Returns: - * Always 0 + * 0 on success, -EINVAL, if specified handle is invalid. */ int iucv_unregister_program (iucv_handle_t handle) { - handler *h = (handler *)handle; + handler *h = NULL; + struct list_head *lh; int i; ulong flags; - iucv_debug("entering"); - iucv_debug("address of handler is %p", h); + iucv_debug(1, "entering"); + iucv_debug(1, "address of handler is %p", h); + + /* Checking if handle is valid */ + spin_lock_irqsave (&iucv_lock, flags); + list_for_each(lh, &iucv_handler_table) { + if ((handler *)handle == list_entry(lh, handler, list)) { + h = (handler *)handle; + break; + } + } + if (!h) { + spin_unlock_irqrestore (&iucv_lock, flags); + if (handle) + printk(KERN_WARNING + "%s: Handler not found in iucv_handler_table.\n", + __FUNCTION__); + else + printk(KERN_WARNING + "%s: NULL handle passed by application.\n", + __FUNCTION__); + return -EINVAL; + } /** * First, walk thru iucv_pathid_table and sever any pathid which is * still pointing to the handler to be removed. */ - spin_lock_irqsave (&iucv_lock, flags); for (i = 0; i < max_connections; i++) if (iucv_pathid_table[i] == h) { spin_unlock_irqrestore (&iucv_lock, flags); @@ -770,7 +914,8 @@ iucv_remove_handler(h); kfree(h); - iucv_debug("exiting"); + MOD_DEC_USE_COUNT; + iucv_debug(1, "exiting"); return 0; } @@ -811,8 +956,8 @@ handler *h = NULL; iparml_control *parm; - iucv_debug("entering"); - iucv_debug("pathid = %d", pathid); + iucv_debug(1, "entering"); + iucv_debug(1, "pathid = %d", pathid); /* Checking if handle is valid */ spin_lock_irqsave (&iucv_lock, flags); @@ -825,9 +970,14 @@ spin_unlock_irqrestore (&iucv_lock, flags); if (!h) { - printk(KERN_WARNING "%s: NULL handle passed by application " - "or handler not found in iucv_handler_table\n", - __FUNCTION__); + if (handle) + printk(KERN_WARNING + "%s: Handler not found in iucv_handler_table.\n", + __FUNCTION__); + else + printk(KERN_WARNING + "%s: NULL handle passed by application.\n", + __FUNCTION__); return -EINVAL; } @@ -849,7 +999,7 @@ } release_param(parm); - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -904,7 +1054,7 @@ handler *h = NULL; __u8 no_memory[16] = "NO MEMORY"; - iucv_debug("entering"); + iucv_debug(1, "entering"); /* Checking if handle is valid */ spin_lock_irqsave (&iucv_lock, flags); @@ -917,9 +1067,14 @@ spin_unlock_irqrestore (&iucv_lock, flags); if (!h) { - printk(KERN_WARNING "%s: NULL handle passed by application " - "or handler not found in iucv_handler_table\n", - __FUNCTION__); + if (handle) + printk(KERN_WARNING + "%s: Handler not found in iucv_handler_table.\n", + __FUNCTION__); + else + printk(KERN_WARNING + "%s: NULL handle passed by application.\n", + __FUNCTION__); return -EINVAL; } @@ -971,7 +1126,7 @@ return(add_pathid_result); } - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -993,8 +1148,8 @@ iparml_purge *parm; ulong b2f0_result = 0; - iucv_debug("entering"); - iucv_debug("pathid = %d", pathid); + iucv_debug(1, "entering"); + iucv_debug(1, "pathid = %d", pathid); parm = (iparml_purge *)grab_param(); @@ -1012,8 +1167,8 @@ release_param(parm); - iucv_debug("b2f0_result = %ld", b2f0_result); - iucv_debug("exiting"); + iucv_debug(1, "b2f0_result = %ld", b2f0_result); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -1099,8 +1254,8 @@ iparml_control *parm; ulong b2f0_result = 0; - iucv_debug("entering"); - iucv_debug("pathid = %d", pathid); + iucv_debug(1, "entering"); + iucv_debug(1, "pathid = %d", pathid); parm = (iparml_control *)grab_param(); @@ -1110,8 +1265,8 @@ b2f0_result = b2f0(QUIESCE, parm); release_param(parm); - iucv_debug("b2f0_result = %ld", b2f0_result); - iucv_debug("exiting"); + iucv_debug(1, "b2f0_result = %ld", b2f0_result); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -1152,7 +1307,7 @@ ulong b2f0_result; int moved = 0; /* number of bytes moved from parmlist to buffer */ - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1170,9 +1325,9 @@ if (b2f0_result == 0 || b2f0_result == 5) { if (flags1_out) { - iucv_debug("*flags1_out = %d", *flags1_out); + iucv_debug(2, "*flags1_out = %d", *flags1_out); *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug("*flags1_out = %d", *flags1_out); + iucv_debug(2, "*flags1_out = %d", *flags1_out); } if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ @@ -1199,7 +1354,7 @@ } release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1242,7 +1397,7 @@ ulong b2f0_result; int i = 0, moved = 0, need_to_move = 8, dyn_len; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1261,9 +1416,9 @@ if (b2f0_result == 0 || b2f0_result == 5) { if (flags1_out) { - iucv_debug("*flags1_out = %d", *flags1_out); + iucv_debug(2, "*flags1_out = %d", *flags1_out); *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug("*flags1_out = %d", *flags1_out); + iucv_debug(2, "*flags1_out = %d", *flags1_out); } if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ @@ -1316,7 +1471,7 @@ } release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1337,8 +1492,8 @@ iparml_db *parm; ulong b2f0_result = 0; - iucv_debug("entering"); - iucv_debug("pathid = %d", pathid); + iucv_debug(1, "entering"); + iucv_debug(1, "pathid = %d", pathid); parm = (iparml_db *)grab_param(); @@ -1350,8 +1505,8 @@ b2f0_result = b2f0(REJECT, parm); release_param(parm); - iucv_debug("b2f0_result = %ld", b2f0_result); - iucv_debug("exiting"); + iucv_debug(1, "b2f0_result = %ld", b2f0_result); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -1391,7 +1546,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1415,7 +1570,7 @@ } release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1457,7 +1612,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1482,7 +1637,7 @@ } release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1511,7 +1666,7 @@ iparml_dpl *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); parm = (iparml_dpl *)grab_param(); @@ -1524,7 +1679,7 @@ b2f0_result = b2f0(REPLY, parm); release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1543,8 +1698,8 @@ iparml_control *parm; ulong b2f0_result = 0; - iucv_debug("entering"); - iucv_debug("pathid = %d", pathid); + iucv_debug(1, "entering"); + iucv_debug(1, "pathid = %d", pathid); parm = (iparml_control *)grab_param(); @@ -1554,7 +1709,7 @@ b2f0_result = b2f0(RESUME, parm); release_param(parm); - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -1582,7 +1737,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1603,7 +1758,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1637,7 +1792,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer) return -EINVAL; @@ -1657,7 +1812,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1686,7 +1841,7 @@ iparml_dpl *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); parm = (iparml_dpl *)grab_param(); @@ -1703,7 +1858,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1741,7 +1896,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer || !ansbuf) return -EINVAL; @@ -1764,7 +1919,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1804,7 +1959,7 @@ iparml_db *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!buffer || !ansbuf) return -EINVAL; @@ -1825,7 +1980,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1861,7 +2016,7 @@ iparml_dpl *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!ansbuf) return -EINVAL; @@ -1883,7 +2038,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1924,7 +2079,7 @@ iparml_dpl *parm; ulong b2f0_result; - iucv_debug("entering"); + iucv_debug(2, "entering"); if (!ansbuf) return -EINVAL; @@ -1944,7 +2099,7 @@ *msgid = parm->ipmsgid; release_param(parm); - iucv_debug("exiting"); + iucv_debug(2, "exiting"); return b2f0_result; } @@ -1967,7 +2122,7 @@ iparml_set_mask *parm; ulong b2f0_result = 0; - iucv_debug("entering"); + iucv_debug(1, "entering"); parm = (iparml_set_mask *)grab_param(); @@ -1976,8 +2131,8 @@ b2f0_result = b2f0(SETMASK, parm); release_param(parm); - iucv_debug("b2f0_result = %ld", b2f0_result); - iucv_debug("exiting"); + iucv_debug(1, "b2f0_result = %ld", b2f0_result); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -1996,7 +2151,7 @@ iparml_control *parm; ulong b2f0_result = 0; - iucv_debug("entering"); + iucv_debug(1, "entering"); parm = (iparml_control *)grab_param(); memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); @@ -2008,7 +2163,7 @@ iucv_remove_pathid(pathid); release_param(parm); - iucv_debug("exiting"); + iucv_debug(1, "exiting"); return b2f0_result; } @@ -2073,10 +2228,10 @@ int rc = 0, j = 0; __u8 no_listener[16] = "NO LISTENER"; - iucv_debug("entering, pathid %d, type %02X", + iucv_debug(2, "entering, pathid %d, type %02X", int_buf->ippathid, int_buf->iptype); - iucv_debug("External Interrupt Buffer:"); - iucv_dumpit(int_buf, sizeof(iucv_GeneralInterrupt)); + iucv_dumpit("External Interrupt Buffer:", + int_buf, sizeof(iucv_GeneralInterrupt)); ASCEBC (no_listener, 16); @@ -2088,9 +2243,7 @@ } else { h = iucv_pathid_table[int_buf->ippathid]; interrupt = h->interrupt_table; - - iucv_debug("Handler:"); - iucv_dumpit(h, sizeof(handler)); + iucv_dumpit("Handler:", h, sizeof(handler)); } } @@ -2107,14 +2260,15 @@ temp_buff2[j] &= (h->id.mask)[j]; } - iucv_debug("temp_buff1:"); - iucv_dumpit(temp_buff1, sizeof(temp_buff1)); - iucv_debug("temp_buff2"); - iucv_dumpit(temp_buff2, sizeof(temp_buff2)); + iucv_dumpit("temp_buff1:", + temp_buff1, sizeof(temp_buff1)); + iucv_dumpit("temp_buff2", + temp_buff2, sizeof(temp_buff2)); if (memcmp (temp_buff1, temp_buff2, 24) == 0) { - iucv_debug("found a matching handler"); + iucv_debug(2, + "found a matching handler"); break; } } @@ -2125,7 +2279,8 @@ if (rc) { iucv_sever (int_buf->ippathid, no_listener); - iucv_debug("add_pathid failed, rc = %d", + iucv_debug(1, + "add_pathid failed, rc = %d", rc); } else { interrupt = h->interrupt_table; @@ -2149,7 +2304,8 @@ (iucv_ConnectionComplete *)int_buf, h->pgm_data); else - iucv_debug("ConnectionComplete not called"); + iucv_debug(1, + "ConnectionComplete not called"); } else iucv_sever(int_buf->ippathid, no_listener); break; @@ -2174,7 +2330,8 @@ (iucv_ConnectionQuiesced *)int_buf, h->pgm_data); else - iucv_debug("ConnectionQuiesced not called"); + iucv_debug(1, + "ConnectionQuiesced not called"); } break; @@ -2185,7 +2342,8 @@ (iucv_ConnectionResumed *)int_buf, h->pgm_data); else - iucv_debug("ConnectionResumed not called"); + iucv_debug(1, + "ConnectionResumed not called"); } break; @@ -2197,7 +2355,8 @@ (iucv_MessageComplete *)int_buf, h->pgm_data); else - iucv_debug("MessageComplete not called"); + iucv_debug(2, + "MessageComplete not called"); } break; @@ -2209,7 +2368,8 @@ (iucv_MessagePending *) int_buf, h->pgm_data); else - iucv_debug("MessagePending not called"); + iucv_debug(2, + "MessagePending not called"); } break; default: /* unknown iucv type */ @@ -2218,7 +2378,7 @@ break; } /* end switch */ - iucv_debug("exiting pathid %d, type %02X", + iucv_debug(2, "exiting pathid %d, type %02X", int_buf->ippathid, int_buf->iptype); return; @@ -2255,6 +2415,9 @@ return; } + +module_init(iucv_init); +module_exit(iucv_exit); /** * Export all public stuff diff -urN linux-2.4.18/drivers/s390/net/netiucv.c linux-2.4.19-pre5/drivers/s390/net/netiucv.c --- linux-2.4.18/drivers/s390/net/netiucv.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/s390/net/netiucv.c Sat Mar 30 22:55:35 2002 @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.16 2001/12/03 14:28:45 felfert Exp $ + * $Id: netiucv.c,v 1.17 2002/02/12 21:52:20 felfert Exp $ * * IUCV network driver * @@ -28,7 +28,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.16 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.17 $ * */ @@ -70,7 +70,7 @@ MODULE_PARM (iucv, "1s"); MODULE_PARM_DESC (iucv, "Specify the initial remote userids for iucv0 .. iucvn:\n" - "iucv=userid0:userid1:...:useridN\n"); + "iucv=userid0:userid1:...:useridN"); #endif static char *iucv = ""; @@ -2005,7 +2005,7 @@ static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.16 $"; + char vbuf[] = "$Revision: 1.17 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff -urN linux-2.4.18/drivers/s390/s390io.c linux-2.4.19-pre5/drivers/s390/s390io.c --- linux-2.4.18/drivers/s390/s390io.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/s390/s390io.c Sat Mar 30 22:55:35 2002 @@ -93,7 +93,6 @@ static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED; // adapter interrupt lock -static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc static int cons_dev = -1; // identify console device static int init_IRQ_complete = 0; static int cio_show_msg = 0; @@ -1413,7 +1412,7 @@ */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) { - psw_t io_new_psw; + unsigned long psw_mask; int ccode; uint64_t time_start; uint64_t time_curr; @@ -1431,30 +1430,25 @@ * sync. interrupt arrived we reset the I/O old PSW to * its original value. */ - memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); ccode = iac(); switch (ccode) { case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT; break; case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT; break; case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_ACC_REG_MODE | _PSW_IO_WAIT; break; case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT; break; default: panic( "start_IO() : unexpected " @@ -1463,8 +1457,6 @@ break; } /* endswitch */ - io_sync_wait.addr = FIX_PSW(&&io_wakeup); - /* * Martin didn't like modifying the new PSW, now we take * a fast exit in do_IRQ() instead @@ -1502,9 +1494,8 @@ } else { - __load_psw( io_sync_wait ); + __load_psw_mask( psw_mask ); -io_wakeup: io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; } /* endif */ @@ -1984,7 +1975,7 @@ { int io_sub; __u32 io_parm; - psw_t io_new_psw; + unsigned long psw_mask; int ccode; int ready = 0; @@ -1999,32 +1990,29 @@ * arrived we reset the I/O old PSW to its * original value. */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); ccode = iac(); switch (ccode) { case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_PRIM_SPACE_MODE + | _PSW_IO_WAIT; break; case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_SEC_SPACE_MODE + | _PSW_IO_WAIT; break; case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_ACC_REG_MODE + | _PSW_IO_WAIT; break; case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_HOME_SPACE_MODE + | _PSW_IO_WAIT; break; default: panic( "halt_IO() : unexpected " @@ -2033,8 +2021,6 @@ break; } /* endswitch */ - io_sync_wait.addr = FIX_PSW(&&hio_wakeup); - /* * Martin didn't like modifying the new PSW, now we take * a fast exit in do_IRQ() instead @@ -2044,8 +2030,8 @@ do { - __load_psw( io_sync_wait ); -hio_wakeup: + __load_psw_mask( psw_mask ); + io_parm = *(__u32 *)__LC_IO_INT_PARM; io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; @@ -2243,7 +2229,7 @@ { int io_sub; __u32 io_parm; - psw_t io_new_psw; + unsigned long psw_mask; int ccode; int ready = 0; @@ -2258,32 +2244,29 @@ * arrived we reset the I/O old PSW to its * original value. */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); ccode = iac(); switch (ccode) { case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_PRIM_SPACE_MODE + | _PSW_IO_WAIT; break; case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_SEC_SPACE_MODE + | _PSW_IO_WAIT; break; case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_ACC_REG_MODE + | _PSW_IO_WAIT; break; case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; + psw_mask = _IO_PSW_MASK + | _PSW_HOME_SPACE_MODE + | _PSW_IO_WAIT; break; default: panic( "clear_IO() : unexpected " @@ -2292,8 +2275,6 @@ break; } /* endswitch */ - io_sync_wait.addr = FIX_PSW(&&cio_wakeup); - /* * Martin didn't like modifying the new PSW, now we take * a fast exit in do_IRQ() instead @@ -2302,9 +2283,8 @@ do { + __load_psw_mask( psw_mask ); - __load_psw( io_sync_wait ); -cio_wakeup: io_parm = *(__u32 *)__LC_IO_INT_PARM; io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; diff -urN linux-2.4.18/drivers/sbus/audio/amd7930.c linux-2.4.19-pre5/drivers/sbus/audio/amd7930.c --- linux-2.4.18/drivers/sbus/audio/amd7930.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sbus/audio/amd7930.c Sat Mar 30 22:55:40 2002 @@ -1619,7 +1619,6 @@ info->irq = irq.pri; request_irq(info->irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", drv); - enable_irq(info->irq); amd7930_enable_ints(info); /* Initalize the local copy of the MAP registers. */ @@ -1644,7 +1643,6 @@ err = register_sparcaudio_driver(drv, 1); if (err < 0) { printk(KERN_ERR "amd7930: unable to register\n"); - disable_irq(info->irq); free_irq(info->irq, drv); sbus_iounmap(info->regs, info->regs_size); kfree(drv->private); @@ -1666,7 +1664,6 @@ unregister_sparcaudio_driver(drv, 1); amd7930_idle(info); - disable_irq(info->irq); free_irq(info->irq, drv); sbus_iounmap(info->regs, info->regs_size); kfree(drv->private); diff -urN linux-2.4.18/drivers/sbus/audio/cs4231.c linux-2.4.19-pre5/drivers/sbus/audio/cs4231.c --- linux-2.4.18/drivers/sbus/audio/cs4231.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sbus/audio/cs4231.c Sat Mar 30 22:55:40 2002 @@ -2210,7 +2210,6 @@ /* Attach the interrupt handler to the audio interrupt. */ cs4231_chip->irq = sdev->irqs[0]; request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv); - enable_irq(cs4231_chip->irq); cs4231_chip->nirqs = 1; cs4231_enable_interrupts(drv); @@ -2224,7 +2223,6 @@ if (err < 0) { printk(KERN_ERR "cs4231: unable to register\n"); cs4231_disable_interrupts(drv); - disable_irq(cs4231_chip->irq); free_irq(cs4231_chip->irq, drv); sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size); kfree(drv->private); @@ -2312,9 +2310,7 @@ bail: printk(KERN_ERR "cs4231: unable to register\n"); cs4231_disable_interrupts(drv); - disable_irq(cs4231_chip->irq); free_irq(cs4231_chip->irq, drv); - disable_irq(cs4231_chip->irq2); free_irq(cs4231_chip->irq2, drv); kfree(drv->private); return -EIO; @@ -2371,7 +2367,6 @@ cs4231_disable_interrupts(drv); unregister_sparcaudio_driver(drv, 1); - disable_irq(cs4231_chip->irq); free_irq(cs4231_chip->irq, drv); if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) { sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size); @@ -2380,7 +2375,6 @@ iounmap(cs4231_chip->regs); iounmap(cs4231_chip->eb2p); iounmap(cs4231_chip->eb2c); - disable_irq(cs4231_chip->irq2); free_irq(cs4231_chip->irq2, drv); #endif } diff -urN linux-2.4.18/drivers/sbus/char/uctrl.c linux-2.4.19-pre5/drivers/sbus/char/uctrl.c --- linux-2.4.18/drivers/sbus/char/uctrl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sbus/char/uctrl.c Sat Mar 30 22:55:40 2002 @@ -389,15 +389,11 @@ if(!driver->irq) driver->irq = tmp_irq[0].pri; - request_irq(driver->irq, uctrl_interrupt, 0, - "uctrl", driver); - - enable_irq(driver->irq); + request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", __FUNCTION__, uctrl_dev.minor); - disable_irq(driver->irq); free_irq(driver->irq, driver); return -ENODEV; } @@ -414,10 +410,8 @@ struct uctrl_driver *driver = &drv; misc_deregister(&uctrl_dev); - if (driver->irq) { - disable_irq(driver->irq); + if (driver->irq) free_irq(driver->irq, driver); - } if (driver->regs) driver->regs = 0; } diff -urN linux-2.4.18/drivers/scsi/3w-xxxx.c linux-2.4.19-pre5/drivers/scsi/3w-xxxx.c --- linux-2.4.18/drivers/scsi/3w-xxxx.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/3w-xxxx.c Sat Mar 30 22:55:40 2002 @@ -121,13 +121,28 @@ 1.02.00.015 - Re-write raw command post with data ioctl method. 1.02.00.016 - Set max_cmd_len for 3dm. Set max sectors to 256 for non raid5 & 6XXX. + 1.02.00.017 - Modified pci parity error handling/clearing from config space + during initialization. + 1.02.00.018 - Better handling of request sense opcode and sense information + for failed commands. Add tw_decode_sense(). + Replace all mdelay()'s with scsi_sleep(). + 1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on + some SMP systems. + 1.02.00.020 - Bump cmd_per_lun in SHT to 255 for better jbod performance. + Make module license ifdef'd for backward compatibility. + Improve handling of errors in tw_interrupt(). + Add handling/clearing of controller queue error. + Better alignment checking in tw_allocate_memory(). + Cleanup tw_initialize_device_extension(). + Empty stale responses before draining aen queue. + Fix tw_scsi_eh_abort() to not reset on every io abort. + Set can_queue in SHT to 255 to prevent hang from AEN. */ #include MODULE_AUTHOR ("3ware Inc."); MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver"); -MODULE_LICENSE("GPL"); #include #include @@ -156,6 +171,10 @@ #include "3w-xxxx.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE("GPL"); +#endif + static int tw_copy_info(TW_Info *info, char *fmt, ...); static void tw_copy_mem_info(TW_Info *info, char *data, int len); static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs); @@ -167,7 +186,7 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.016"; +char *tw_driver_version="1.02.00.020"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -269,6 +288,9 @@ } tw_clear_attention_interrupt(tw_dev); + /* Empty response queue */ + tw_empty_response_que(tw_dev); + /* Initialize command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n"); @@ -322,7 +344,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -338,8 +360,7 @@ if (command_packet->status != 0) { if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { /* Bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } else { /* We know this is a 3w-1x00, and doesn't support aen's */ @@ -437,7 +458,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); return 1; } if (tw_dev->command_packet_virtual_address[request_id] == NULL) { @@ -504,9 +525,9 @@ return 1; } - if ((u32)virt_addr % TW_ALIGNMENT) { + if ((u32)virt_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { kfree(virt_addr); - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); + printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n"); return 1; } @@ -552,12 +573,24 @@ status_reg_addr = tw_dev->registers.status_reg_addr; status_reg_value = inl(status_reg_addr); - if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) + if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) { + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; + } return 0; } /* End tw_check_errors() */ +/* This function will clear all interrupts on the controller */ +void tw_clear_all_interrupts(TW_Device_Extension *tw_dev) +{ + u32 control_reg_addr, control_reg_value; + + control_reg_addr = tw_dev->registers.control_reg_addr; + control_reg_value = TW_STATUS_VALID_INTERRUPT; + outl(control_reg_value, control_reg_addr); +} /* End tw_clear_all_interrupts() */ + /* This function will clear the attention interrupt */ void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev) { @@ -613,47 +646,90 @@ } /* End tw_copy_mem_info() */ /* This function will print readable messages from status register errors */ -void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) +int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host) { + char host[16]; + dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n"); + + if (print_host) + sprintf(host, " scsi%d:", tw_dev->host->host_no); + else + host[0] = '\0'; + switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) { case TW_STATUS_PCI_PARITY_ERROR: - printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n"); + printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host); outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr); - pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS); break; case TW_STATUS_MICROCONTROLLER_ERROR: - printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n"); - break; + if (tw_dev->reset_print == 0) { + printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host); + tw_dev->reset_print = 1; + } + return 1; case TW_STATUS_PCI_ABORT: - printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n"); + printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host); outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr); pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); break; - } + case TW_STATUS_QUEUE_ERROR: + printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host); + outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr); + break; + case TW_STATUS_SBUF_WRITE_ERROR: + printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host); + outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr); + break; + } + + return 0; } /* End tw_decode_bits() */ -/* This function will print readable messages from flags and status values */ -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit) +/* This function will return valid sense buffer information for failed cmds */ +int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense) { - dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n"); - switch (status) { - case 0xc7: - switch (flags) { - case 0x1b: - printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit); - break; - case 0x51: - printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit); - break; - default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); + int i; + TW_Command *command; + + dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n"); + command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + + printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit); + + /* Attempt to return intelligent sense information */ + if (fill_sense) { + if ((command->status == 0xc7) || (command->status == 0xcb)) { + for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) { + if (command->flags == tw_sense_table[i][0]) { + + /* Valid bit and 'current errors' */ + tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70); + + /* Sense key */ + tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1]; + + /* Additional sense length */ + tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */ + + /* Additional sense code */ + tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2]; + + /* Additional sense code qualifier */ + tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3]; + + tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */ + } + } } - break; - default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); + + /* If no table match, error so we get a reset */ + return 1; } -} /* End tw_decode_error() */ + + return 0; +} /* End tw_decode_sense() */ /* This function will disable interrupts on the controller */ void tw_disable_interrupts(TW_Device_Extension *tw_dev) @@ -666,7 +742,7 @@ } /* End tw_disable_interrupts() */ /* This function will empty the response que */ -int tw_empty_response_que(TW_Device_Extension *tw_dev) +void tw_empty_response_que(TW_Device_Extension *tw_dev) { u32 status_reg_addr, status_reg_value; u32 response_que_addr, response_que_value; @@ -676,22 +752,10 @@ status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); - tw_decode_bits(tw_dev, status_reg_value); - return 1; - } - while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_que_value = inl(response_que_addr); status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); - tw_decode_bits(tw_dev, status_reg_value); - return 1; - } } - return 0; } /* End tw_empty_response_que() */ /* This function will enable interrupts on the controller */ @@ -744,6 +808,9 @@ } memset(tw_dev, 0, sizeof(TW_Device_Extension)); + /* Save pci_dev struct to device extension */ + tw_dev->tw_pci_dev = tw_pci_dev; + error = tw_initialize_device_extension(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards); @@ -758,13 +825,11 @@ tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4; tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8; tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC; - /* Save pci_dev struct to device extension */ - tw_dev->tw_pci_dev = tw_pci_dev; /* Check for errors and clear them */ status_reg_value = inl(tw_dev->registers.status_reg_addr); - if (TW_STATUS_ERRORS(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value); + if (TW_STATUS_ERRORS(status_reg_value)) + tw_decode_bits(tw_dev, status_reg_value, 0); /* Poll status register for 60 secs for 'Controller Ready' flag */ if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { @@ -780,7 +845,7 @@ while (tries < TW_MAX_RESET_TRIES) { /* Do soft reset */ tw_soft_reset(tw_dev); - + error = tw_aen_drain_queue(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards); @@ -795,14 +860,6 @@ continue; } - /* Empty the response queue */ - error = tw_empty_response_que(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards); - tries++; - continue; - } - /* Now the controller is in a good state */ break; } @@ -829,7 +886,7 @@ request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); error = tw_initialize_units(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -853,7 +910,7 @@ tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1; tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1; } else { - tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units; + /* Use SHT cmd_per_lun here */ tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_LENGTH - 1; tw_dev->free_wrap = TW_Q_LENGTH - 1; @@ -1033,7 +1090,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1046,8 +1103,7 @@ } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } break; /* Response was okay, so we exit */ @@ -1059,12 +1115,11 @@ /* This function will initialize the fields of a device extension */ int tw_initialize_device_extension(TW_Device_Extension *tw_dev) { - int i, imax; + int i; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); - imax = TW_Q_LENGTH; - for (i=0; icommand_packet_virtual_address[i] == NULL) { @@ -1083,34 +1138,12 @@ tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; - tw_dev->ioctl_size[i] = 0; - tw_dev->aen_queue[i] = 0; - tw_dev->ioctl_data[i] = NULL; - } - - for (i=0;iis_unit_present[i] = 0; - tw_dev->is_raid_five[i] = 0; } - tw_dev->num_units = 0; - tw_dev->num_aborts = 0; - tw_dev->num_resets = 0; - tw_dev->posted_request_count = 0; - tw_dev->max_posted_request_count = 0; - tw_dev->max_sgl_entries = 0; - tw_dev->sgl_entries = 0; - tw_dev->host = NULL; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; - tw_dev->aen_head = 0; - tw_dev->aen_tail = 0; - tw_dev->sector_count = 0; - tw_dev->max_sector_count = 0; - tw_dev->aen_count = 0; - tw_dev->num_raid_five = 0; spin_lock_init(&tw_dev->tw_lock); - tw_dev->flags = 0; + return 0; } /* End tw_initialize_device_extension() */ @@ -1187,7 +1220,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1200,8 +1233,7 @@ } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } found = 1; @@ -1291,7 +1323,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1304,8 +1336,7 @@ } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } found = 1; @@ -1351,46 +1382,52 @@ u32 response_que_addr; TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; TW_Response_Queue response_que; - int error = 0; - int do_response_interrupt=0; - int do_attention_interrupt=0; - int do_host_interrupt=0; - int do_command_interrupt=0; + int error = 0, retval = 0; unsigned long flags = 0; TW_Command *command_packet; + + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); + + /* See if we are already running on another processor */ if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags)) return; - spin_lock_irqsave(&io_request_lock, flags); + /* Get the block layer lock for io completions */ + spin_lock_irqsave(&io_request_lock, flags); + + /* See if the interrupt matches this instance */ if (tw_dev->tw_pci_dev->irq == irq) { + + /* Make sure io isn't queueing */ spin_lock(&tw_dev->tw_lock); - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; status_reg_value = inl(status_reg_addr); - /* Check which interrupt */ - if (status_reg_value & TW_STATUS_HOST_INTERRUPT) - do_host_interrupt=1; - if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) - do_attention_interrupt=1; - if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) - do_command_interrupt=1; - if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) - do_response_interrupt=1; + /* Check if this is our interrupt, otherwise bail */ + if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) + goto tw_interrupt_bail; + + /* Check controller for errors */ + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + if (tw_decode_bits(tw_dev, status_reg_value, 1)) { + tw_clear_all_interrupts(tw_dev); + goto tw_interrupt_bail; + } + } /* Handle host interrupt */ - if (do_host_interrupt) { + if (status_reg_value & TW_STATUS_HOST_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n"); tw_clear_host_interrupt(tw_dev); } /* Handle attention interrupt */ - if (do_attention_interrupt) { + if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); @@ -1402,7 +1439,7 @@ } /* Handle command interrupt */ - if (do_command_interrupt) { + if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { /* Drain as many pending commands as we can */ while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; @@ -1418,6 +1455,7 @@ } tw_dev->pending_request_count--; } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no); break; } } @@ -1427,40 +1465,41 @@ } /* Handle response interrupt */ - if (do_response_interrupt) { + if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { /* Drain the response queue from the board */ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { + /* Read response queue register */ response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; error = 0; + + /* Check for bad response */ if (command_packet->status != 0) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); - error = 1; + /* If internal command, don't error, don't fill sense */ + if (tw_dev->srb[request_id] == 0) { + tw_decode_sense(tw_dev, request_id, 0); + } else { + error = tw_decode_sense(tw_dev, request_id, 1); + } } + + /* Check for correct state */ if (tw_dev->state[request_id] != TW_S_POSTED) { printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode); error = 1; } - if (TW_STATUS_ERRORS(status_reg_value)) { - tw_decode_bits(tw_dev, status_reg_value); - error = 1; - } + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); - /* Check for internal command */ + + /* Check for internal command completion */ if (tw_dev->srb[request_id] == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); - error = tw_aen_complete(tw_dev, request_id); - if (error) { + retval = tw_aen_complete(tw_dev, request_id); + if (retval) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); } - status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); - } - } else { + } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: case READ_6: @@ -1483,35 +1522,45 @@ error = tw_ioctl_complete(tw_dev, request_id); break; default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]); - tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - } - if (error == 1) { - /* Tell scsi layer there was an error */ - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); - tw_dev->srb[request_id]->result = (DID_RESET << 16); + printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n"); + error = 1; } + + /* If no error command was a success */ if (error == 0) { - /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); } - if (error != 2) { + + /* If error, command failed */ + if (error == 1) { + tw_dev->srb[request_id]->result = (DID_RESET << 16); + } + + /* Now complete the io */ + if ((error != TW_ISR_DONT_COMPLETE)) { tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } - status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + } + + /* Check for valid status after each drain */ + status_reg_value = inl(status_reg_addr); + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + if (tw_decode_bits(tw_dev, status_reg_value, 1)) { + tw_clear_all_interrupts(tw_dev); + goto tw_interrupt_bail; } } } } +tw_interrupt_bail: spin_unlock(&tw_dev->tw_lock); - } + } else + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n"); + spin_unlock_irqrestore(&io_request_lock, flags); clear_bit(TW_IN_INTR, &tw_dev->flags); } /* End tw_interrupt() */ @@ -1871,7 +1920,7 @@ break; case TW_CMD_PACKET_WITH_DATA: dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n"); - return 2; /* Special case for isr to not complete io */ + return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */ default: memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; @@ -1905,14 +1954,25 @@ do_gettimeofday(&before); status_reg_value = inl(status_reg_addr); + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + while ((status_reg_value & flag) != flag) { status_reg_value = inl(status_reg_addr); + + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + do_gettimeofday(&timeout); if (before.tv_sec + seconds < timeout.tv_sec) { dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); return 1; } - mdelay(1); + mdelay(5); } return 0; } /* End tw_poll_status() */ @@ -1931,7 +1991,7 @@ if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); } if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { @@ -1985,7 +2045,6 @@ (tw_dev->state[i] != TW_S_COMPLETED)) { srb = tw_dev->srb[i]; if (srb != NULL) { - srb = tw_dev->srb[i]; srb->result = (DID_RESET << 16); tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); } @@ -2003,6 +2062,7 @@ tw_dev->pending_request_count = 0; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; + tw_dev->reset_print = 0; return 0; } /* End tw_reset_device_extension() */ @@ -2034,14 +2094,6 @@ continue; } - /* Empty the response queue again */ - error = tw_empty_response_que(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no); - tries++; - continue; - } - /* Now the controller is in a good state */ break; } @@ -2131,11 +2183,6 @@ return (FAILED); } - /* We have to let AEN requests through before the reset */ - spin_unlock_irq(&io_request_lock); - mdelay(TW_AEN_WAIT_TIME); - spin_lock_irq(&io_request_lock); - spin_lock(&tw_dev->tw_lock); tw_dev->num_aborts++; @@ -2162,18 +2209,26 @@ spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } + if (tw_dev->state[i] == TW_S_POSTED) { + /* If the command has already been posted, we have to reset the card */ + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); + /* We have to let AEN requests through before the reset */ + spin_unlock(&tw_dev->tw_lock); + spin_unlock_irq(&io_request_lock); + mdelay(TW_AEN_WAIT_TIME); + spin_lock_irq(&io_request_lock); + spin_lock(&tw_dev->tw_lock); + + if (tw_reset_device_extension(tw_dev)) { + dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); + spin_unlock(&tw_dev->tw_lock); + return (FAILED); + } + } } } - /* If the command has already been posted, we have to reset the card */ - printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); - if (tw_reset_device_extension(tw_dev)) { - dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); - spin_unlock(&tw_dev->tw_lock); - return (FAILED); - } spin_unlock(&tw_dev->tw_lock); - return (SUCCESS); } /* End tw_scsi_eh_abort() */ @@ -2638,7 +2693,7 @@ } command_packet->byte0.sgl_offset = 3; - command_packet->size = 5; + command_packet->size = 3; command_packet->request_id = request_id; command_packet->byte3.unit = srb->target; command_packet->byte3.host_id = 0; @@ -2673,6 +2728,7 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n"); command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer); command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen; + command_packet->size+=2; } /* Do this if we have multiple sg list entries */ @@ -2682,8 +2738,6 @@ command_packet->byte8.io.sgl[i].length = sglist[i].length; command_packet->size+=2; } - if (tw_dev->srb[request_id]->use_sg >= 1) - command_packet->size-=2; } } else { /* Do this if there are no sg list entries for raid 5 */ @@ -2692,6 +2746,7 @@ memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]); command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen; + command_packet->size+=2; } /* Do this if we have multiple sg list entries for raid 5 */ @@ -2727,18 +2782,19 @@ /* This function will handle the request sense scsi command */ int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); - /* For now we just zero the sense buffer */ - memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); + /* For now we just zero the request buffer */ + memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); - /* If we got a request_sense, we probably want a reset, return error */ - tw_dev->srb[request_id]->result = (DID_ERROR << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + /* If we got a request_sense, we probably want a reset, return error */ + tw_dev->srb[request_id]->result = (DID_ERROR << 16); + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - return 0; + return 0; } /* End tw_scsiop_request_sense() */ /* This function will handle test unit ready scsi command */ @@ -2819,7 +2875,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -2832,8 +2888,7 @@ } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } break; /* Response was okay, so we exit */ diff -urN linux-2.4.18/drivers/scsi/3w-xxxx.h linux-2.4.19-pre5/drivers/scsi/3w-xxxx.h --- linux-2.4.18/drivers/scsi/3w-xxxx.h Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/3w-xxxx.h Sat Mar 30 22:55:40 2002 @@ -92,10 +92,35 @@ "Verify failed: Port #", // 0x02A "Verify complete: Unit #", // 0x02B "Overwrote bad sector during rebuild: Port #", //0x2C - "Encountered bad sector during rebuild: Port #" //0x2D + "Encountered bad sector during rebuild: Port #", //0x2D + "Replacement drive is too small: Port #" //0x2E }; -#define TW_AEN_STRING_MAX 0x02E +#define TW_AEN_STRING_MAX 0x02F + +/* + Sense key lookup table + Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier +*/ +static unsigned char tw_sense_table[][4] = +{ + /* Codes for newer firmware */ + // ATA Error SCSI Error + {0x01, 0x03, 0x13, 0x00}, // Address mark not found Address mark not found for data field + {0x04, 0x0b, 0x00, 0x00}, // Aborted command Aborted command + {0x10, 0x0b, 0x14, 0x00}, // ID not found Recorded entity not found + {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error Unrecovered read error + {0x61, 0x04, 0x00, 0x00}, // Device fault Hardware error + {0x84, 0x0b, 0x47, 0x00}, // Data CRC error SCSI parity error + {0xd0, 0x0b, 0x00, 0x00}, // Device busy Aborted command + {0xd1, 0x0b, 0x00, 0x00}, // Device busy Aborted command + + /* Codes for older firmware */ + // 3ware Error SCSI Error + {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error Aborted command + {0x37, 0x0b, 0x04, 0x00}, // Unit offline Logical unit not ready + {0x51, 0x0b, 0x00, 0x00} // Unspecified Aborted command +}; /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 @@ -110,7 +135,9 @@ #define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 #define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 #define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 +#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000 #define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 +#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008 /* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 @@ -130,7 +157,9 @@ #define TW_STATUS_ALL_INTERRUPTS 0x000F0000 #define TW_STATUS_CLEARABLE_BITS 0x00D00000 #define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F80000 +#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 +#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 +#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 /* RESPONSE QUEUE BIT DEFINITIONS */ #define TW_RESPONSE_ID_MASK 0x00000FF0 @@ -174,7 +203,8 @@ #define TW_AEN_SBUF_FAIL 0x0024 /* Misc defines */ -#define TW_ALIGNMENT 0x200 /* 16 D-WORDS */ +#define TW_ALIGNMENT_6000 64 /* 64 bytes */ +#define TW_ALIGNMENT_7000 4 /* 4 bytes */ #define TW_MAX_UNITS 16 #define TW_COMMAND_ALIGNMENT_MASK 0x1ff #define TW_INIT_MESSAGE_CREDITS 0x100 @@ -190,7 +220,7 @@ #define TW_MAX_PCI_BUSES 255 #define TW_MAX_RESET_TRIES 3 #define TW_UNIT_INFORMATION_TABLE_BASE 0x300 -#define TW_MAX_CMDS_PER_LUN (TW_Q_LENGTH-2)/TW_MAX_UNITS +#define TW_MAX_CMDS_PER_LUN 255 #define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */ #define TW_IOCTL 0x80 #define TW_MAX_AEN_TRIES 100 @@ -201,6 +231,8 @@ #define TW_AEN_WAIT_TIME 1000 #define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ #define TW_MAX_CDB_LEN 16 +#define TW_ISR_DONT_COMPLETE 2 +#define TW_ISR_DONT_RESULT 3 /* Macros */ #define TW_STATUS_ERRORS(x) \ @@ -213,7 +245,7 @@ #ifdef TW_DEBUG #define dprintk(msg...) printk(msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif /* Scatter Gather List Entry */ @@ -386,8 +418,9 @@ unsigned short aen_queue[TW_Q_LENGTH]; unsigned char aen_head; unsigned char aen_tail; - long flags; /* long req'd for set_bit --RR */ + volatile long flags; /* long req'd for set_bit --RR */ char *ioctl_data[TW_Q_LENGTH]; + int reset_print; } TW_Device_Extension; /* Function prototypes */ @@ -397,12 +430,13 @@ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which); int tw_check_bits(u32 status_reg_value); int tw_check_errors(TW_Device_Extension *tw_dev); +void tw_clear_all_interrupts(TW_Device_Extension *tw_dev); void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev); void tw_clear_host_interrupt(TW_Device_Extension *tw_dev); -void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value); -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit); +int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host); +int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense); void tw_disable_interrupts(TW_Device_Extension *tw_dev); -int tw_empty_response_que(TW_Device_Extension *tw_dev); +void tw_empty_response_que(TW_Device_Extension *tw_dev); void tw_enable_interrupts(TW_Device_Extension *tw_dev); void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev); int tw_findcards(Scsi_Host_Template *tw_host); @@ -462,7 +496,7 @@ reset : NULL, \ slave_attach : NULL, \ bios_param : tw_scsi_biosparam, \ - can_queue : TW_Q_LENGTH, \ + can_queue : TW_Q_LENGTH-1, \ this_id: -1, \ sg_tablesize : TW_MAX_SGL_LENGTH, \ cmd_per_lun: TW_MAX_CMDS_PER_LUN, \ diff -urN linux-2.4.18/drivers/scsi/NCR53C9x.c linux-2.4.19-pre5/drivers/scsi/NCR53C9x.c --- linux-2.4.18/drivers/scsi/NCR53C9x.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/NCR53C9x.c Sat Mar 30 22:55:35 2002 @@ -3613,3 +3613,5 @@ esps_running = esps_in_use; } #endif + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/a2091.c linux-2.4.19-pre5/drivers/scsi/a2091.c --- linux-2.4.18/drivers/scsi/a2091.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/a2091.c Sat Mar 30 22:55:35 2002 @@ -248,3 +248,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/a3000.c linux-2.4.19-pre5/drivers/scsi/a3000.c --- linux-2.4.18/drivers/scsi/a3000.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/a3000.c Sat Mar 30 22:55:35 2002 @@ -199,9 +199,7 @@ return 1; fail_irq: -#ifdef MODULE wd33c93_release(); -#endif /* MODULE */ scsi_unregister(a3000_host); fail_register: release_mem_region(0xDD0000, 256); @@ -216,11 +214,11 @@ int __exit a3000_release(struct Scsi_Host *instance) { -#ifdef MODULE wd33c93_release(); -#endif /* MODULE*/ DMA(instance)->CNTR = 0; release_mem_region(0xDD0000, 256); free_irq(IRQ_AMIGA_PORTS, a3000_intr); return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/aacraid/aachba.c linux-2.4.19-pre5/drivers/scsi/aacraid/aachba.c --- linux-2.4.18/drivers/scsi/aacraid/aachba.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/aachba.c Sat Mar 30 22:55:29 2002 @@ -494,8 +494,9 @@ scsicmd->use_sg, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (u32)scsicmd->SCp.ptr, scsicmd->request_bufflen, - scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); readreply = (struct aac_read_reply *)fib_data(fibptr); if (le32_to_cpu(readreply->status) == ST_OK) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; @@ -537,8 +538,9 @@ scsicmd->use_sg, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, (u32)scsicmd->SCp.ptr, scsicmd->request_bufflen, - scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); writereply = (struct aac_write_reply *) fib_data(fibptr); if (le32_to_cpu(writereply->status) == ST_OK) @@ -641,10 +643,10 @@ } else if(scsicmd->request_bufflen) { - u32 addr; + dma_addr_t addr; addr = pci_map_single(dev->pdev, scsicmd->request_buffer, scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); - scsicmd->SCp.ptr = (void *)addr; + scsicmd->SCp.ptr = (void *)(long)addr; readcmd->sg.sg[0].addr = cpu_to_le32(addr); readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); @@ -763,14 +765,14 @@ } else if(scsicmd->request_bufflen) { - u32 addr; + dma_addr_t addr; addr = pci_map_single(dev->pdev, scsicmd->request_buffer, scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); writecmd->sg.sg[0].addr = cpu_to_le32(addr); writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (void *)addr; + scsicmd->SCp.ptr = (void *)(long)addr; byte_count = scsicmd->request_bufflen; if (byte_count > (64 * 1024)) diff -urN linux-2.4.18/drivers/scsi/aacraid/aacraid.h linux-2.4.19-pre5/drivers/scsi/aacraid/aacraid.h --- linux-2.4.18/drivers/scsi/aacraid/aacraid.h Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/aacraid.h Sat Mar 30 22:55:29 2002 @@ -682,7 +682,7 @@ unsigned long fsrev; /* Main driver's revision number */ struct aac_init *init; /* Holds initialization info to communicate with adapter */ - void * init_pa; /* Holds physical address of the init struct */ + dma_addr_t init_pa; /* Holds physical address of the init struct */ struct pci_dev *pdev; /* Our PCI interface */ void * printfbuf; /* pointer to buffer used for printf's from the adapter */ @@ -1168,7 +1168,17 @@ u32 options; u32 OEM; }; - + +static inline u32 fib2addr(struct hw_fib *hw) +{ + return (u32)hw; +} + +static inline struct hw_fib *addr2fib(u32 addr) +{ + return (struct hw_fib *)addr; +} + const char *aac_driverinfo(struct Scsi_Host *); struct fib *fib_alloc(struct aac_dev *dev); int fib_setup(struct aac_dev *dev); diff -urN linux-2.4.18/drivers/scsi/aacraid/comminit.c linux-2.4.19-pre5/drivers/scsi/aacraid/comminit.c --- linux-2.4.18/drivers/scsi/aacraid/comminit.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/comminit.c Sat Mar 30 22:55:29 2002 @@ -65,12 +65,12 @@ printk(KERN_ERR "aacraid: unable to create mapping.\n"); return 0; } - dev->comm_addr = (void *)base; + dev->comm_addr = (void *)base; dev->comm_phys = phys; - dev->comm_size = size; + dev->comm_size = size; dev->init = (struct aac_init *)(base + fibsize); - dev->init_pa = (struct aac_init *)(phys + fibsize); + dev->init_pa = phys + fibsize; init = dev->init; @@ -82,7 +82,7 @@ * Adapter Fibs are the first thing allocated so that they * start page aligned */ - init->AdapterFibsVirtualAddress = cpu_to_le32(base); + init->AdapterFibsVirtualAddress = cpu_to_le32((long)base); init->AdapterFibsPhysicalAddress = cpu_to_le32(phys); init->AdapterFibsSize = cpu_to_le32(fibsize); init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); diff -urN linux-2.4.18/drivers/scsi/aacraid/commsup.c linux-2.4.19-pre5/drivers/scsi/aacraid/commsup.c --- linux-2.4.18/drivers/scsi/aacraid/commsup.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/commsup.c Sat Mar 30 22:55:29 2002 @@ -445,13 +445,18 @@ fib->header.XferState |= cpu_to_le32(ResponseExpected); FIB_COUNTER_INCREMENT(aac_config.NormalSent); } - fib->header.SenderData = (unsigned long)fibptr; /* for callback */ + /* + * Map the fib into 32bits by using the fib number + */ + fib->header.SenderData = fibptr-&dev->fibs[0]; /* for callback */ /* * Set FIB state to indicate where it came from and if we want a * response from the adapter. Also load the command from the * caller. + * + * Map the hw fib pointer as a 32bit value */ - fib->header.SenderFibAddress = cpu_to_le32((u32)fib); + fib->header.SenderFibAddress = fib2addr(fib); fib->header.Command = cpu_to_le16(command); fib->header.XferState |= cpu_to_le32(SentFromHost); fibptr->fib->header.Flags = 0; /* Zero the flags field - its internal only... */ @@ -756,9 +761,9 @@ if (cp[length] != 0) cp[length] = 0; if (level == LOG_HIGH_ERROR) - printk(KERN_WARNING "aacraid:%s.\n", cp); + printk(KERN_WARNING "aacraid:%s", cp); else - printk(KERN_INFO "aacraid:%s.\n", cp); + printk(KERN_INFO "aacraid:%s", cp); memset(cp, 0, 256); } diff -urN linux-2.4.18/drivers/scsi/aacraid/dpcsup.c linux-2.4.19-pre5/drivers/scsi/aacraid/dpcsup.c --- linux-2.4.18/drivers/scsi/aacraid/dpcsup.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/dpcsup.c Sat Mar 30 22:55:29 2002 @@ -77,9 +77,9 @@ int fast; fast = (int) (entry->addr & 0x01); - fib = (struct hw_fib *) (entry->addr & ~0x01); + fib = addr2fib(entry->addr & ~0x01); aac_consumer_free(dev, q, HostNormRespQueue); - fibctx = (struct fib *)fib->header.SenderData; + fibctx = &dev->fibs[fib->header.SenderData]; /* * Remove this fibctx from the Outstanding I/O queue. * But only if it has not already been timed out. @@ -172,7 +172,7 @@ while(aac_consumer_get(dev, q, &entry)) { struct hw_fib * fib; - fib = (struct hw_fib *)entry->addr; + fib = addr2fib(entry->addr); if (dev->aif_thread) { list_add_tail(&fib->header.FibLinks, &q->cmdq); diff -urN linux-2.4.18/drivers/scsi/aacraid/linit.c linux-2.4.19-pre5/drivers/scsi/aacraid/linit.c --- linux-2.4.18/drivers/scsi/aacraid/linit.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/aacraid/linit.c Sat Mar 30 22:55:29 2002 @@ -35,7 +35,7 @@ * */ -#define AAC_DRIVER_VERSION "0.9.9ac2-rel" +#define AAC_DRIVER_VERSION "0.9.9ac4-rel" #define AAC_DRIVER_BUILD_DATE __DATE__ #include diff -urN linux-2.4.18/drivers/scsi/aic7xxx/Config.in linux-2.4.19-pre5/drivers/scsi/aic7xxx/Config.in --- linux-2.4.18/drivers/scsi/aic7xxx/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/Config.in Sat Mar 30 22:55:35 2002 @@ -1,8 +1,13 @@ if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "y" ]; then dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 - int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000 - bool ' Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE + int ' Maximum number of TCQ commands per device' \ + CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 + int ' Initial bus reset delay in milli-seconds' \ + CONFIG_AIC7XXX_RESET_DELAY_MS 15000 + bool ' Probe for EISA and VL AIC7XXX Adapters' \ + CONFIG_AIC7XXX_PROBE_EISA_VL + bool ' Build Adapter Firmware with Kernel Build' \ + CONFIG_AIC7XXX_BUILD_FIRMWARE fi fi diff -urN linux-2.4.18/drivers/scsi/aic7xxx/Makefile linux-2.4.19-pre5/drivers/scsi/aic7xxx/Makefile --- linux-2.4.18/drivers/scsi/aic7xxx/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/Makefile Sat Mar 30 22:55:35 2002 @@ -6,32 +6,36 @@ O_TARGET := aic7xxx_drv.o -list-multi := aic7xxx_mod.o +list-multi := aic7xxx_mod.o aic79xx_mod.o -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx_mod.o +ifeq (aic7xxx_core.c, $(wildcard aic7xxx_core.c)) +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o +endif #EXTRA_CFLAGS += -g # Platform Specific Files -AIC7XXX_OBJS = aic7xxx_linux.o -AIC7XXX_OBJS += aic7xxx_proc.o aic7770_linux.o +AIC7XXX_OBJS = aic7xxx_osm.o +AIC7XXX_OBJS += aic7xxx_proc.o aic7770_osm.o #PCI Specific Platform Files ifeq ($(CONFIG_PCI),y) -AIC7XXX_OBJS += aic7xxx_linux_pci.o +AIC7XXX_OBJS += aic7xxx_osm_pci.o endif # Core Files -AIC7XXX_OBJS += aic7xxx.o aic7xxx_93cx6.o aic7770.o +AIC7XXX_OBJS += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o #PCI Specific Core Files ifeq ($(CONFIG_PCI),y) AIC7XXX_OBJS += aic7xxx_pci.o endif # Override our module desitnation -MOD_TARGET = aic7xxx.o +MOD_DESTDIR = $(shell cd .. && $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) include $(TOPDIR)/Rules.make -aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) +.NOPARALLEL: + +aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7770.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7770.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770.c Sat Mar 30 22:55:35 2002 @@ -37,14 +37,20 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#14 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ */ +#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" +#else +#include +#include +#include +#endif #define ID_AIC7770 0x04907770 #define ID_AHA_274x 0x04907771 @@ -96,7 +102,7 @@ } int -aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) +aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) { int error; u_int hostconf; @@ -107,10 +113,18 @@ if (error != 0) return (error); - error = aic7770_map_registers(ahc); + error = aic7770_map_registers(ahc, io); if (error != 0) return (error); + /* + * Before we continue probing the card, ensure that + * its interrupts are *disabled*. We don't want + * a misstep to hang the machine in an interrupt + * storm. + */ + ahc_intr_enable(ahc, FALSE); + ahc->description = entry->name; error = ahc_softc_init(ahc); @@ -231,7 +245,6 @@ { struct seeprom_descriptor sd; struct seeprom_config sc; - uint16_t checksum = 0; uint8_t scsi_conf; int have_seeprom; @@ -249,20 +262,12 @@ if (bootverbose) printf("%s: Reading SEEPROM...", ahc_name(ahc)); - have_seeprom = read_seeprom(&sd, - (uint16_t *)&sc, - /*start_addr*/0, - sizeof(sc)/2); + have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc, + /*start_addr*/0, sizeof(sc)/2); if (have_seeprom) { - /* Check checksum */ - int i; - int maxaddr = (sizeof(sc)/2) - 1; - uint16_t *scarray = (uint16_t *)≻ - - for (i = 0; i < maxaddr; i++) - checksum = checksum + scarray[i]; - if (checksum != sc.checksum) { + + if (ahc_verify_cksum(&sc) == 0) { if(bootverbose) printf ("checksum error\n"); have_seeprom = 0; diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7770_linux.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770_linux.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7770_linux.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770_linux.c Thu Jan 1 01:00:00 1970 @@ -1,153 +0,0 @@ -/* - * Linux driver attachment glue for aic7770 based controllers. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_linux.c#9 $ - */ - -#include "aic7xxx_osm.h" - -#define MINSLOT 1 -#define NUMSLOTS 16 -#define IDOFFSET 0x80 - -int -aic7770_linux_probe(Scsi_Host_Template *template) -{ -#if defined(__i386__) || defined(__alpha__) - struct aic7770_identity *entry; - struct ahc_softc *ahc; - int i, slot; - int eisaBase; - int found; - - if (aic7xxx_no_probe) - return (0); - - eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; - found = 0; - for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { - uint32_t eisa_id; - size_t id_size; - - if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0) - continue; - - eisa_id = 0; - id_size = sizeof(eisa_id); - for (i = 0; i < 4; i++) { - /* VLcards require priming*/ - outb(0x80 + i, eisaBase + IDOFFSET); - eisa_id |= inb(eisaBase + IDOFFSET + i) - << ((id_size-i-1) * 8); - } - if (eisa_id & 0x80000000) - continue; /* no EISA card in slot */ - - entry = aic7770_find_device(eisa_id); - if (entry != NULL) { - char buf[80]; - char *name; - int error; - - /* - * Allocate a softc for this card and - * set it up for attachment by our - * common detect routine. - */ - sprintf(buf, "ahc_eisa:%d", slot); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); - if (name == NULL) - break; - strcpy(name, buf); - ahc = ahc_alloc(template, name); - if (ahc == NULL) { - /* - * If we can't allocate this one, - * chances are we won't be able to - * allocate future card structures. - */ - break; - } - ahc->tag = BUS_SPACE_PIO; - ahc->bsh.ioport = eisaBase; - error = aic7770_config(ahc, entry); - if (error != 0) { - ahc_free(ahc); - continue; - } - found++; - } - } - return (found); -#else - return (0); -#endif -} - -int -aic7770_map_registers(struct ahc_softc *ahc) -{ - /* - * Lock out other contenders for our i/o space. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx"); -#else - if (request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx") == 0) - return (ENOMEM); -#endif - - return (0); -} - -int -aic7770_map_int(struct ahc_softc *ahc, u_int irq) -{ - int error; - int shared; - - shared = 0; - if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) - shared = SA_SHIRQ; - - ahc->platform_data->irq = irq; - error = request_irq(ahc->platform_data->irq, ahc_linux_isr, - shared, "aic7xxx", ahc); - - return (-error); -} diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7770_osm.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770_osm.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7770_osm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7770_osm.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,150 @@ +/* + * Linux driver attachment glue for aic7770 based controllers. + * + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7770_osm.c#1 $ + */ + +#include "aic7xxx_osm.h" + +#define MINSLOT 1 +#define NUMSLOTS 16 +#define IDOFFSET 0x80 + +int +aic7770_linux_probe(Scsi_Host_Template *template) +{ +#if defined(__i386__) || defined(__alpha__) + struct aic7770_identity *entry; + struct ahc_softc *ahc; + int i, slot; + int eisaBase; + int found; + + eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; + found = 0; + for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { + uint32_t eisa_id; + size_t id_size; + + if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0) + continue; + + eisa_id = 0; + id_size = sizeof(eisa_id); + for (i = 0; i < 4; i++) { + /* VLcards require priming*/ + outb(0x80 + i, eisaBase + IDOFFSET); + eisa_id |= inb(eisaBase + IDOFFSET + i) + << ((id_size-i-1) * 8); + } + if (eisa_id & 0x80000000) + continue; /* no EISA card in slot */ + + entry = aic7770_find_device(eisa_id); + if (entry != NULL) { + char buf[80]; + char *name; + int error; + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_eisa:%d", slot); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + break; + strcpy(name, buf); + ahc = ahc_alloc(template, name); + if (ahc == NULL) { + /* + * If we can't allocate this one, + * chances are we won't be able to + * allocate future card structures. + */ + break; + } + error = aic7770_config(ahc, entry, eisaBase); + if (error != 0) { + ahc->bsh.ioport = 0; + ahc_free(ahc); + continue; + } + found++; + } + } + return (found); +#else + return (0); +#endif +} + +int +aic7770_map_registers(struct ahc_softc *ahc, u_int port) +{ + /* + * Lock out other contenders for our i/o space. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(port, AHC_EISA_IOSIZE, "aic7xxx"); +#else + if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) + return (ENOMEM); +#endif + ahc->tag = BUS_SPACE_PIO; + ahc->bsh.ioport = port; + return (0); +} + +int +aic7770_map_int(struct ahc_softc *ahc, u_int irq) +{ + int error; + int shared; + + shared = 0; + if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) + shared = SA_SHIRQ; + + error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc); + if (error == 0) + ahc->platform_data->irq = irq; + + return (-error); +} diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.c Thu Jan 1 01:00:00 1970 @@ -1,6988 +0,0 @@ -/* - * Core routines and tables shareable across OS platforms. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#50 $ - * - * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ - */ - -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aicasm/aicasm_insformat.h" - -/****************************** Softc Data ************************************/ -struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq); - -/***************************** Lookup Tables **********************************/ -char *ahc_chip_names[] = -{ - "NONE", - "aic7770", - "aic7850", - "aic7855", - "aic7859", - "aic7860", - "aic7870", - "aic7880", - "aic7895", - "aic7895C", - "aic7890/91", - "aic7896/97", - "aic7892", - "aic7899" -}; -static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); - -/* - * Hardware error codes. - */ -struct ahc_hard_error_entry { - uint8_t errno; - char *errmesg; -}; - -static struct ahc_hard_error_entry ahc_hard_errors[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referrenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Parity Error" }, - { DPARERR, "Data-path Parity Error" }, - { MPARERR, "Scratch or SCB Memory Parity Error" }, - { PCIERRSTAT, "PCI Error detected" }, - { CIOPARERR, "CIOBUS Parity Error" }, -}; -static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); - -static struct ahc_phase_table_entry ahc_phase_table[] = -{ - { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, - { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, - { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, - { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, - { P_COMMAND, MSG_NOOP, "in Command phase" }, - { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, - { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, - { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, - { P_BUSFREE, MSG_NOOP, "while idle" }, - { 0, MSG_NOOP, "in unknown phase" } -}; - -/* - * In most cases we only wish to itterate over real phases, so - * exclude the last element from the count. - */ -static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of tranfer periods in ns to the proper value to - * stick in the scsixfer reg. - */ -static struct ahc_syncrate ahc_syncrates[] = -{ - /* ultra2 fast/ultra period rate */ - { 0x42, 0x000, 9, "80.0" }, - { 0x03, 0x000, 10, "40.0" }, - { 0x04, 0x000, 11, "33.0" }, - { 0x05, 0x100, 12, "20.0" }, - { 0x06, 0x110, 15, "16.0" }, - { 0x07, 0x120, 18, "13.4" }, - { 0x08, 0x000, 25, "10.0" }, - { 0x19, 0x010, 31, "8.0" }, - { 0x1a, 0x020, 37, "6.67" }, - { 0x1b, 0x030, 43, "5.7" }, - { 0x1c, 0x040, 50, "5.0" }, - { 0x00, 0x050, 56, "4.4" }, - { 0x00, 0x060, 62, "4.0" }, - { 0x00, 0x070, 68, "3.6" }, - { 0x00, 0x000, 0, NULL } -}; - -/* Our Sequencer Program */ -#include "aic7xxx_seq.h" - -/**************************** Function Declarations ***************************/ -static void ahc_force_renegotiation(struct ahc_softc *ahc); -static struct ahc_tmode_tstate* - ahc_alloc_tstate(struct ahc_softc *ahc, - u_int scsi_id, char channel); -#ifdef AHC_TARGET_MODE -static void ahc_free_tstate(struct ahc_softc *ahc, - u_int scsi_id, char channel, int force); -#endif -static struct ahc_syncrate* - ahc_devlimited_syncrate(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *, - u_int *period, - u_int *ppr_options, - role_t role); -static void ahc_update_pending_scbs(struct ahc_softc *ahc); -static void ahc_fetch_devinfo(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_scb_devinfo(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -static void ahc_assert_atn(struct ahc_softc *ahc); -static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -static void ahc_build_transfer_msg(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_construct_sdtr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int period, u_int offset); -static void ahc_construct_wdtr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int bus_width); -static void ahc_construct_ppr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int period, u_int offset, - u_int bus_width, u_int ppr_options); -static void ahc_clear_msg_state(struct ahc_softc *ahc); -static void ahc_handle_message_phase(struct ahc_softc *ahc); -typedef enum { - AHCMSG_1B, - AHCMSG_2B, - AHCMSG_EXT -} ahc_msgtype; -static int ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, - u_int msgval, int full); -static int ahc_parse_msg(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static int ahc_handle_msg_reject(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_reinitialize_dataptrs(struct ahc_softc *ahc); -static void ahc_handle_devreset(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - cam_status status, char *message, - int verbose_level); -#if AHC_TARGET_MODE -static void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -#endif - -static bus_dmamap_callback_t ahc_dmamap_cb; -static void ahc_build_free_scb_list(struct ahc_softc *ahc); -static int ahc_init_scbdata(struct ahc_softc *ahc); -static void ahc_fini_scbdata(struct ahc_softc *ahc); -static void ahc_qinfifo_requeue(struct ahc_softc *ahc, - struct scb *prev_scb, - struct scb *scb); -static int ahc_qinfifo_count(struct ahc_softc *ahc); -static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, - u_int prev, u_int scbptr); -static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); -static u_int ahc_rem_wscb(struct ahc_softc *ahc, - u_int scbpos, u_int prev); -static void ahc_reset_current_bus(struct ahc_softc *ahc); -#ifdef AHC_DUMP_SEQ -static void ahc_dumpseq(struct ahc_softc *ahc); -#endif -static void ahc_loadseq(struct ahc_softc *ahc); -static int ahc_check_patch(struct ahc_softc *ahc, - struct patch **start_patch, - u_int start_instr, u_int *skip_addr); -static void ahc_download_instr(struct ahc_softc *ahc, - u_int instrptr, uint8_t *dconsts); -#ifdef AHC_TARGET_MODE -static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct ahc_tmode_lstate *lstate, - u_int initiator_id, - u_int event_type, - u_int event_arg); -static void ahc_update_scsiid(struct ahc_softc *ahc, - u_int targid_mask); -static int ahc_handle_target_cmd(struct ahc_softc *ahc, - struct target_cmd *cmd); -#endif -/************************* Sequencer Execution Control ************************/ -/* - * Restart the sequencer program from address zero - */ -void -ahc_restart(struct ahc_softc *ahc) -{ - - ahc_pause(ahc); - - ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ - ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ - ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); - ahc_outb(ahc, LASTPHASE, P_BUSFREE); - - /* - * Ensure that the sequencer's idea of TQINPOS - * matches our own. The sequencer increments TQINPOS - * only after it sees a DMA complete and a reset could - * occur before the increment leaving the kernel to believe - * the command arrived but the sequencer to not. - */ - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - - /* Always allow reselection */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Ensure that no DMA operations are in progress */ - ahc_outb(ahc, CCSCBCNT, 0); - ahc_outb(ahc, CCSGCTL, 0); - ahc_outb(ahc, CCSCBCTL, 0); - } - /* - * If we were in the process of DMA'ing SCB data into - * an SCB, replace that SCB on the free list. This prevents - * an SCB leak. - */ - if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) { - ahc_add_curscb_to_free_list(ahc); - ahc_outb(ahc, SEQ_FLAGS2, - ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); - } - ahc_outb(ahc, MWI_RESIDUAL, 0); - ahc_outb(ahc, SEQCTL, FASTMODE); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - ahc_unpause(ahc); -} - -/************************* Input/Output Queues ********************************/ -void -ahc_run_qoutfifo(struct ahc_softc *ahc) -{ - struct scb *scb; - u_int scb_index; - - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); - while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) { - - scb_index = ahc->qoutfifo[ahc->qoutfifonext]; - if ((ahc->qoutfifonext & 0x03) == 0x03) { - u_int modnext; - - /* - * Clear 32bits of QOUTFIFO at a time - * so that we don't clobber an incoming - * byte DMA to the array on architectures - * that only support 32bit load and store - * operations. - */ - modnext = ahc->qoutfifonext & ~0x3; - *((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - /*offset*/modnext, /*len*/4, - BUS_DMASYNC_PREREAD); - } - ahc->qoutfifonext++; - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: WARNING no command for scb %d " - "(cmdcmplt)\nQOUTPOS = %d\n", - ahc_name(ahc), scb_index, - ahc->qoutfifonext - 1); - continue; - } - - /* - * Save off the residual - * if there is one. - */ - ahc_update_residual(scb); - ahc_done(ahc, scb); - } -} - -void -ahc_run_untagged_queues(struct ahc_softc *ahc) -{ - int i; - - for (i = 0; i < 16; i++) - ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]); -} - -void -ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue) -{ - struct scb *scb; - - if (ahc->untagged_queue_lock != 0) - return; - - if ((scb = TAILQ_FIRST(queue)) != NULL - && (scb->flags & SCB_ACTIVE) == 0) { - scb->flags |= SCB_ACTIVE; - ahc_queue_scb(ahc, scb); - } -} - -/************************* Interrupt Handling *********************************/ -void -ahc_handle_brkadrint(struct ahc_softc *ahc) -{ - /* - * We upset the sequencer :-( - * Lookup the error message - */ - int i; - int error; - - error = ahc_inb(ahc, ERROR); - for (i = 0; error != 1 && i < num_errors; i++) - error >>= 1; - printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), ahc_hard_errors[i].errmesg, - ahc_inb(ahc, SEQADDR0) | - (ahc_inb(ahc, SEQADDR1) << 8)); - - ahc_dump_card_state(ahc); - - /* Tell everyone that this HBA is no longer availible */ - ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_NO_HBA); - - /* Disable all interrupt sources by resetting the controller */ - ahc_shutdown(ahc); -} - -void -ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) -{ - struct scb *scb; - struct ahc_devinfo devinfo; - - ahc_fetch_devinfo(ahc, &devinfo); - - /* - * Clear the upper byte that holds SEQINT status - * codes and clear the SEQINT bit. We will unpause - * the sequencer, if appropriate, after servicing - * the request. - */ - ahc_outb(ahc, CLRINT, CLRSEQINT); - switch (intstat & SEQINT_MASK) { - case BAD_STATUS: - { - u_int scb_index; - struct hardware_scb *hscb; - - /* - * Set the default return value to 0 (don't - * send sense). The sense code will change - * this if needed. - */ - ahc_outb(ahc, RETURN_1, 0); - - /* - * The sequencer will notify us when a command - * has an error that would be of interest to - * the kernel. This allows us to leave the sequencer - * running in the common case of command completes - * without error. The sequencer will already have - * dma'd the SCB back up to us, so we can reference - * the in kernel copy directly. - */ - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s:%c:%d: ahc_intr - referenced scb " - "not valid during seqint 0x%x scb(%d)\n", - ahc_name(ahc), devinfo.channel, - devinfo.target, intstat, scb_index); - ahc_dump_card_state(ahc); - panic("for safety"); - goto unpause; - } - - hscb = scb->hscb; - - /* Don't want to clobber the original sense code */ - if ((scb->flags & SCB_SENSE) != 0) { - /* - * Clear the SCB_SENSE Flag and have - * the sequencer do a normal command - * complete. - */ - scb->flags &= ~SCB_SENSE; - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - break; - } - ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); - /* Freeze the queue until the client sees the error. */ - ahc_freeze_devq(ahc, scb); - ahc_freeze_scb(scb); - ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); - switch (hscb->shared_data.status.scsi_status) { - case SCSI_STATUS_OK: - printf("%s: Interrupted for staus of 0???\n", - ahc_name(ahc)); - break; - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - struct ahc_transinfo *tinfo; -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("SCB %d: requests Check Status\n", - scb->hscb->tag); - } -#endif - - if (ahc_perform_autosense(scb) == 0) - break; - - targ_info = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo = &targ_info->curr; - sg = scb->sg_list; - sc = (struct scsi_sense *)(&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - ahc_update_residual(scb); -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("Sending Sense\n"); - } -#endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; - - /* - * We can't allow the target to disconnect. - * This will be an untagged transaction and - * having the target disconnect will make this - * transaction indestinguishable from outstanding - * tagged transactions. - */ - hscb->control = 0; - - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_neg_request(ahc, &devinfo, - tstate, targ_info, - /*force*/TRUE); - } - if (tstate->auto_negotiate & devinfo.target_mask) { - hscb->control |= MK_MESSAGE; - scb->flags &= ~SCB_NEGOTIATE; - scb->flags |= SCB_AUTO_NEGOTIATE; - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); -#ifdef __FreeBSD__ - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, 5 * hz); -#endif - break; - } - default: - break; - } - break; - } - case NO_MATCH: - { - /* Ensure we don't leave the selection hardware on */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - - printf("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahc_name(ahc), devinfo.channel, devinfo.target); - printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "ARG_1 == 0x%x ACCUM = 0x%x\n", - ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), - ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " - "SINDEX == 0x%x\n", - ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), - ahc_index_busy_tcl(ahc, - BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), - ahc_inb(ahc, SAVED_LUN))), - ahc_inb(ahc, SINDEX)); - printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", - ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), - ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), - ahc_inb(ahc, SCB_CONTROL)); - printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", - ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); - printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); - printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); - ahc_dump_card_state(ahc); - ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; - ahc->msgout_len = 1; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_assert_atn(ahc); - break; - } - case SEND_REJECT: - { - u_int rejbyte = ahc_inb(ahc, ACCUM); - printf("%s:%c:%d: Warning - unknown message received from " - "target (0x%x). Rejecting\n", - ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); - break; - } - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find an SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - int found; - - printf("%s:%c:%d: Target did not send an IDENTIFY message. " - "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID)); - found = ahc_reset_channel(ahc, devinfo.channel, - /*initiate reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel, - found); - return; - } - case IGN_WIDE_RES: - ahc_handle_ign_wide_residue(ahc, &devinfo); - break; - case PDATA_REINIT: - ahc_reinitialize_dataptrs(ahc); - break; - case BAD_PHASE: - { - u_int lastphase; - - lastphase = ahc_inb(ahc, LASTPHASE); - printf("%s:%c:%d: unknown scsi bus phase %x, " - "lastphase = 0x%x. Attempting to continue\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - lastphase, ahc_inb(ahc, SCSISIGI)); - break; - } - case MISSED_BUSFREE: - { - u_int lastphase; - - lastphase = ahc_inb(ahc, LASTPHASE); - printf("%s:%c:%d: Missed busfree. " - "Lastphase = 0x%x, Curphase = 0x%x\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - lastphase, ahc_inb(ahc, SCSISIGI)); - ahc_restart(ahc); - return; - } - case HOST_MSG_LOOP: - { - /* - * The sequencer has encountered a message phase - * that requires host assistance for completion. - * While handling the message phase(s), we will be - * notified by the sequencer after each byte is - * transfered so we can track bus phase changes. - * - * If this is the first time we've seen a HOST_MSG_LOOP - * interrupt, initialize the state of the host message - * loop. - */ - if (ahc->msg_type == MSG_TYPE_NONE) { - struct scb *scb; - u_int scb_index; - u_int bus_phase; - - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - if (bus_phase != P_MESGIN - && bus_phase != P_MESGOUT) { - printf("ahc_intr: HOST_MSG_LOOP bad " - "phase 0x%x\n", - bus_phase); - /* - * Probably transitioned to bus free before - * we got here. Just punt the message. - */ - ahc_clear_intstat(ahc); - ahc_restart(ahc); - return; - } - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (devinfo.role == ROLE_INITIATOR) { - if (scb == NULL) - panic("HOST_MSG_LOOP with " - "invalid SCB %x\n", scb_index); - - if (bus_phase == P_MESGOUT) - ahc_setup_initiator_msgout(ahc, - &devinfo, - scb); - else { - ahc->msg_type = - MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; - } - } -#if AHC_TARGET_MODE - else { - if (bus_phase == P_MESGOUT) { - ahc->msg_type = - MSG_TYPE_TARGET_MSGOUT; - ahc->msgin_index = 0; - } - else - ahc_setup_target_msgin(ahc, - &devinfo, - scb); - } -#endif - } - - ahc_handle_message_phase(ahc); - break; - } - case PERR_DETECTED: - { - /* - * If we've cleared the parity error interrupt - * but the sequencer still believes that SCSIPERR - * is true, it must be that the parity error is - * for the currently presented byte on the bus, - * and we are not in a phase (data-in) where we will - * eventually ack this byte. Ack the byte and - * throw it away in the hope that the target will - * take us to message out to deliver the appropriate - * error message. - */ - if ((intstat & SCSIINT) == 0 - && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - - if ((ahc->features & AHC_DT) == 0) { - u_int curphase; - - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); - } - ahc_inb(ahc, SCSIDATL); - } - break; - } - case DATA_OVERRUN: - { - /* - * When the sequencer detects an overrun, it - * places the controller in "BITBUCKET" mode - * and allows the target to complete its transfer. - * Unfortunately, none of the counters get updated - * when the controller is in this mode, so we have - * no way of knowing how large the overrun was. - */ - u_int scbindex = ahc_inb(ahc, SCB_TAG); - u_int lastphase = ahc_inb(ahc, LASTPHASE); - u_int i; - - scb = ahc_lookup_scb(ahc, scbindex); - for (i = 0; i < num_phases; i++) { - if (lastphase == ahc_phase_table[i].phase) - break; - } - ahc_print_path(ahc, scb); - printf("data overrun detected %s." - " Tag == 0x%x.\n", - ahc_phase_table[i].phasemsg, - scb->hscb->tag); - ahc_print_path(ahc, scb); - printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", - ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - ahc_get_transfer_length(scb), scb->sg_count); - if (scb->sg_count > 0) { - for (i = 0; i < scb->sg_count; i++) { - - printf("sg[%d] - Addr 0x%x%x : Length %d\n", - i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 - & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len) - & AHC_SG_LEN_MASK); - } - } - /* - * Set this and it will take effect when the - * target does a command complete. - */ - ahc_freeze_devq(ahc, scb); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); - ahc_freeze_scb(scb); - - if ((ahc->features & AHC_ULTRA2) != 0) { - /* - * Clear the channel in case we return - * to data phase later. - */ - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); - } - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - u_int dscommand1; - - /* Ensure HHADDR is 0 for future DMA operations. */ - dscommand1 = ahc_inb(ahc, DSCOMMAND1); - ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); - ahc_outb(ahc, HADDR, 0); - ahc_outb(ahc, DSCOMMAND1, dscommand1); - } - break; - } - case MKMSG_FAILED: - { - u_int scbindex; - - printf("%s:%c:%d:%d: Attempt to issue message failed\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - devinfo.lun); - scbindex = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scbindex); - if (scb != NULL - && (scb->flags & SCB_RECOVERY_SCB) != 0) - /* - * Ensure that we didn't put a second instance of this - * SCB into the QINFIFO. - */ - ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), scb->hscb->tag, - ROLE_INITIATOR, /*status*/0, - SEARCH_REMOVE); - break; - } - case NO_FREE_SCB: - { - printf("%s: No free or disconnected SCBs\n", ahc_name(ahc)); - ahc_dump_card_state(ahc); - panic("for safety"); - break; - } - case SCB_MISMATCH: - { - u_int scbptr; - - scbptr = ahc_inb(ahc, SCBPTR); - printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", - scbptr, ahc_inb(ahc, ARG_1), - ahc->scb_data->hscbs[scbptr].tag); - ahc_dump_card_state(ahc); - panic("for saftey"); - break; - } - case OUT_OF_RANGE: - { - printf("%s: BTT calculation out of range\n", ahc_name(ahc)); - printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "ARG_1 == 0x%x ACCUM = 0x%x\n", - ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), - ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " - "SINDEX == 0x%x\n, A == 0x%x\n", - ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), - ahc_index_busy_tcl(ahc, - BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), - ahc_inb(ahc, SAVED_LUN))), - ahc_inb(ahc, SINDEX), - ahc_inb(ahc, ACCUM)); - printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", - ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), - ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), - ahc_inb(ahc, SCB_CONTROL)); - printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", - ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); - ahc_dump_card_state(ahc); - panic("for safety"); - break; - } - default: - printf("ahc_intr: seqint, " - "intstat == 0x%x, scsisigi = 0x%x\n", - intstat, ahc_inb(ahc, SCSISIGI)); - break; - } -unpause: - /* - * The sequencer is paused immediately on - * a SEQINT, so we should restart it when - * we're done. - */ - ahc_unpause(ahc); -} - -void -ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) -{ - u_int scb_index; - u_int status0; - u_int status; - struct scb *scb; - char cur_channel; - char intr_channel; - - /* Make sure the sequencer is in a safe location. */ - ahc_clear_critical_section(ahc); - - if ((ahc->features & AHC_TWIN) != 0 - && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0)) - cur_channel = 'B'; - else - cur_channel = 'A'; - intr_channel = cur_channel; - - if ((ahc->features & AHC_ULTRA2) != 0) - status0 = ahc_inb(ahc, SSTAT0) & IOERR; - else - status0 = 0; - status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); - if (status == 0 && status0 == 0) { - if ((ahc->features & AHC_TWIN) != 0) { - /* Try the other channel */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); - status = ahc_inb(ahc, SSTAT1) - & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); - intr_channel = (cur_channel == 'A') ? 'B' : 'A'; - } - if (status == 0) { - printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_unpause(ahc); - return; - } - } - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb != NULL - && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0) - scb = NULL; - - if ((ahc->features & AHC_ULTRA2) != 0 - && (status0 & IOERR) != 0) { - int now_lvd; - - now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40; - printf("%s: Transceiver State Has Changed to %s mode\n", - ahc_name(ahc), now_lvd ? "LVD" : "SE"); - ahc_outb(ahc, CLRSINT0, CLRIOERR); - /* - * When transitioning to SE mode, the reset line - * glitches, triggering an arbitration bug in some - * Ultra2 controllers. This bug is cleared when we - * assert the reset line. Since a reset glitch has - * already occurred with this transition and a - * transceiver state change is handled just like - * a bus reset anyway, asserting the reset line - * ourselves is safe. - */ - ahc_reset_channel(ahc, intr_channel, - /*Initiate Reset*/now_lvd == 0); - } else if ((status & SCSIRSTI) != 0) { - printf("%s: Someone reset channel %c\n", - ahc_name(ahc), intr_channel); - if (intr_channel != cur_channel) - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); - ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE); - } else if ((status & SCSIPERR) != 0) { - /* - * Determine the bus phase and queue an appropriate message. - * SCSIPERR is latched true as soon as a parity error - * occurs. If the sequencer acked the transfer that - * caused the parity error and the currently presented - * transfer on the bus has correct parity, SCSIPERR will - * be cleared by CLRSCSIPERR. Use this to determine if - * we should look at the last phase the sequencer recorded, - * or the current phase presented on the bus. - */ - u_int mesg_out; - u_int curphase; - u_int errorphase; - u_int lastphase; - u_int scsirate; - u_int i; - u_int sstat2; - - lastphase = ahc_inb(ahc, LASTPHASE); - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - sstat2 = ahc_inb(ahc, SSTAT2); - ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); - /* - * For all phases save DATA, the sequencer won't - * automatically ack a byte that has a parity error - * in it. So the only way that the current phase - * could be 'data-in' is if the parity error is for - * an already acked byte in the data phase. During - * synchronous data-in transfers, we may actually - * ack bytes before latching the current phase in - * LASTPHASE, leading to the discrepancy between - * curphase and lastphase. - */ - if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0 - || curphase == P_DATAIN || curphase == P_DATAIN_DT) - errorphase = curphase; - else - errorphase = lastphase; - - for (i = 0; i < num_phases; i++) { - if (errorphase == ahc_phase_table[i].phase) - break; - } - mesg_out = ahc_phase_table[i].mesg_out; - if (scb != NULL) - ahc_print_path(ahc, scb); - else - printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, - SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); - scsirate = ahc_inb(ahc, SCSIRATE); - printf("parity error detected %s. " - "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - ahc_phase_table[i].phasemsg, - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), - scsirate); - - if ((ahc->features & AHC_DT) != 0) { - - if ((sstat2 & CRCVALERR) != 0) - printf("\tCRC Value Mismatch\n"); - if ((sstat2 & CRCENDERR) != 0) - printf("\tNo terminal CRC packet recevied\n"); - if ((sstat2 & CRCREQERR) != 0) - printf("\tIllegal CRC packet request\n"); - if ((sstat2 & DUAL_EDGE_ERR) != 0) - printf("\tUnexpected %sDT Data Phase\n", - (scsirate & SINGLE_EDGE) ? "" : "non-"); - } - - /* - * We've set the hardware to assert ATN if we - * get a parity error on "in" phases, so all we - * need to do is stuff the message buffer with - * the appropriate message. "In" phases have set - * mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) { - if (ahc->msg_type != MSG_TYPE_NONE) - ahc->send_msg_perror = TRUE; - else - ahc_outb(ahc, MSG_OUT, mesg_out); - } - /* - * Force a renegotiation with this target just in - * case we are out of sync for some external reason - * unknown (or unreported) by the target. - */ - ahc_force_renegotiation(ahc); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_unpause(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessfull - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - } else { - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - /* - * Force a renegotiation with this target just in - * case the cable was pulled and will later be - * re-attached. The target may forget its negotiation - * settings with us should it attempt to reselect - * during the interruption. The target will not issue - * a unit attention in this case, so we must always - * renegotiate. - */ - ahc_force_renegotiation(ahc); - ahc_restart(ahc); - } else if ((status & BUSFREE) != 0 - && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { - u_int lastphase; - u_int saved_scsiid; - u_int saved_lun; - u_int target; - u_int initiator_role_id; - char channel; - int printerror; - - /* - * Clear our selection hardware as soon as possible. - * We may have an entry in the waiting Q for this target, - * that is affected by this busfree and we don't want to - * go about selecting the target while we handle the event. - */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - - /* - * Disable busfree interrupts and clear the busfree - * interrupt status. We do this here so that several - * bus transactions occur prior to clearing the SCSIINT - * latch. It can take a bit for the clearing to take effect. - */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); - - /* - * Look at what phase we were last in. - * If its message out, chances are pretty good - * that the busfree was in response to one of - * our abort requests. - */ - lastphase = ahc_inb(ahc, LASTPHASE); - saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); - saved_lun = ahc_inb(ahc, SAVED_LUN); - target = SCSIID_TARGET(ahc, saved_scsiid); - initiator_role_id = SCSIID_OUR_ID(saved_scsiid); - channel = SCSIID_CHANNEL(ahc, saved_scsiid); - printerror = 1; - - if (lastphase == P_MESGOUT) { - struct ahc_devinfo devinfo; - u_int tag; - - ahc_fetch_devinfo(ahc, &devinfo); - tag = SCB_LIST_NULL; - if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE) - || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) { - if (ahc->msgout_buf[ahc->msgout_index - 1] - == MSG_ABORT_TAG) - tag = scb->hscb->tag; - ahc_print_path(ahc, scb); - printf("SCB %d - Abort%s Completed.\n", - scb->hscb->tag, tag == SCB_LIST_NULL ? - "" : " Tag"); - ahc_abort_scbs(ahc, target, channel, - saved_lun, tag, - ROLE_INITIATOR, - CAM_REQ_ABORTED); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_1B, - MSG_BUS_DEV_RESET, TRUE)) { -#ifdef __FreeBSD__ - /* - * Don't mark the user's request for this BDR - * as completing with CAM_BDR_SENT. CAM3 - * specifies CAM_REQ_CMP. - */ - if (scb != NULL - && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV - && ahc_match_scb(ahc, scb, target, channel, - CAM_LUN_WILDCARD, - SCB_LIST_NULL, - ROLE_INITIATOR)) { - ahc_set_transaction_status(scb, CAM_REQ_CMP); - } -#endif - ahc_compile_devinfo(&devinfo, - initiator_role_id, - target, - CAM_LUN_WILDCARD, - channel, - ROLE_INITIATOR); - ahc_handle_devreset(ahc, &devinfo, - CAM_BDR_SENT, - "Bus Device Reset", - /*verbose_level*/0); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_PPR, FALSE)) { - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - - /* - * PPR Rejected. Try non-ppr negotiation - * and retry command. - */ - tinfo = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - tinfo->goal.ppr_options = 0; - ahc_qinfifo_requeue_tail(ahc, scb); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_WDTR, FALSE) - || ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_SDTR, FALSE)) { - /* - * Negotiation Rejected. Go-async and - * retry command. - */ - ahc_set_width(ahc, &devinfo, - MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_set_syncrate(ahc, &devinfo, - /*syncrate*/NULL, - /*period*/0, /*offset*/0, - /*ppr_options*/0, - AHC_TRANS_CUR|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_qinfifo_requeue_tail(ahc, scb); - printerror = 0; - } - } - if (printerror != 0) { - u_int i; - - if (scb != NULL) { - u_int tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - tag = scb->hscb->tag; - else - tag = SCB_LIST_NULL; - ahc_print_path(ahc, scb); - ahc_abort_scbs(ahc, target, channel, - SCB_GET_LUN(scb), tag, - ROLE_INITIATOR, - CAM_UNEXP_BUSFREE); - } else { - /* - * We had not fully identified this connection, - * so we cannot abort anything. - */ - printf("%s: ", ahc_name(ahc)); - } - for (i = 0; i < num_phases; i++) { - if (lastphase == ahc_phase_table[i].phase) - break; - } - printf("Unexpected busfree %s\n" - "SEQADDR == 0x%x\n", - ahc_phase_table[i].phasemsg, - ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8)); - } - ahc_clear_msg_state(ahc); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_restart(ahc); - } else { - printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", - ahc_name(ahc), status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - } -} - -/* - * Force renegotiation to occur the next time we initiate - * a command to the current device. - */ -static void -ahc_force_renegotiation(struct ahc_softc *ahc) -{ - struct ahc_devinfo devinfo; - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - - ahc_fetch_devinfo(ahc, &devinfo); - targ_info = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - ahc_update_neg_request(ahc, &devinfo, tstate, - targ_info, /*force*/TRUE); -} - -#define AHC_MAX_STEPS 2000 -void -ahc_clear_critical_section(struct ahc_softc *ahc) -{ - int stepping; - int steps; - u_int simode0; - u_int simode1; - - if (ahc->num_critical_sections == 0) - return; - - stepping = FALSE; - steps = 0; - simode0 = 0; - simode1 = 0; - for (;;) { - struct cs *cs; - u_int seqaddr; - u_int i; - - seqaddr = ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8); - - /* - * Seqaddr represents the next instruction to execute, - * so we are really executing the instruction just - * before it. - */ - if (seqaddr != 0) - seqaddr -= 1; - cs = ahc->critical_sections; - for (i = 0; i < ahc->num_critical_sections; i++, cs++) { - - if (cs->begin < seqaddr && cs->end >= seqaddr) - break; - } - - if (i == ahc->num_critical_sections) - break; - - if (steps > AHC_MAX_STEPS) { - printf("%s: Infinite loop in critical section\n", - ahc_name(ahc)); - ahc_dump_card_state(ahc); - panic("critical section loop"); - } - - steps++; - if (stepping == FALSE) { - - /* - * Disable all interrupt sources so that the - * sequencer will not be stuck by a pausing - * interrupt condition while we attempt to - * leave a critical section. - */ - simode0 = ahc_inb(ahc, SIMODE0); - ahc_outb(ahc, SIMODE0, 0); - simode1 = ahc_inb(ahc, SIMODE1); - ahc_outb(ahc, SIMODE1, 0); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); - stepping = TRUE; - } - ahc_outb(ahc, HCNTRL, ahc->unpause); - do { - ahc_delay(200); - } while (!ahc_is_paused(ahc)); - } - if (stepping) { - ahc_outb(ahc, SIMODE0, simode0); - ahc_outb(ahc, SIMODE1, simode1); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); - } -} - -/* - * Clear any pending interrupt status. - */ -void -ahc_clear_intstat(struct ahc_softc *ahc) -{ - /* Clear any interrupt conditions this may have caused */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI - |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| - CLRREQINIT); - ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); - ahc_outb(ahc, CLRINT, CLRSCSIINT); -} - -/**************************** Debugging Routines ******************************/ -void -ahc_print_scb(struct scb *scb) -{ - int i; - - struct hardware_scb *hscb = scb->hscb; - - printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", - (void *)scb, - hscb->control, - hscb->scsiid, - hscb->lun, - hscb->cdb_len); - printf("Shared Data: "); - for (i = 0; i < sizeof(hscb->shared_data.cdb); i++) - printf("%#02x", hscb->shared_data.cdb[i]); - printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", - ahc_le32toh(hscb->dataptr), - ahc_le32toh(hscb->datacnt), - ahc_le32toh(hscb->sgptr), - hscb->tag); - if (scb->sg_count > 0) { - for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x%x : Length %d\n", - i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 - & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len)); - } - } -} - -/************************* Transfer Negotiation *******************************/ -/* - * Allocate per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static struct ahc_tmode_tstate * -ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) -{ - struct ahc_tmode_tstate *master_tstate; - struct ahc_tmode_tstate *tstate; - int i; - - master_tstate = ahc->enabled_targets[ahc->our_id]; - if (channel == 'B') { - scsi_id += 8; - master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; - } - if (ahc->enabled_targets[scsi_id] != NULL - && ahc->enabled_targets[scsi_id] != master_tstate) - panic("%s: ahc_alloc_tstate - Target already allocated", - ahc_name(ahc)); - tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); - if (tstate == NULL) - return (NULL); - - /* - * If we have allocated a master tstate, copy user settings from - * the master tstate (taken from SRAM or the EEPROM) for this - * channel, but reset our current and goal settings to async/narrow - * until an initiator talks to us. - */ - if (master_tstate != NULL) { - memcpy(tstate, master_tstate, sizeof(*tstate)); - memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); - tstate->ultraenb = 0; - for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].curr, 0, - sizeof(tstate->transinfo[i].curr)); - memset(&tstate->transinfo[i].goal, 0, - sizeof(tstate->transinfo[i].goal)); - } - } else - memset(tstate, 0, sizeof(*tstate)); - ahc->enabled_targets[scsi_id] = tstate; - return (tstate); -} - -#ifdef AHC_TARGET_MODE -/* - * Free per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static void -ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) -{ - struct ahc_tmode_tstate *tstate; - - /* - * Don't clean up our "master" tstate. - * It has our default user settings. - */ - if (((channel == 'B' && scsi_id == ahc->our_id_b) - || (channel == 'A' && scsi_id == ahc->our_id)) - && force == FALSE) - return; - - if (channel == 'B') - scsi_id += 8; - tstate = ahc->enabled_targets[scsi_id]; - if (tstate != NULL) - free(tstate, M_DEVBUF); - ahc->enabled_targets[scsi_id] = NULL; -} -#endif - -/* - * Called when we have an active connection to a target on the bus, - * this function finds the nearest syncrate to the input period limited - * by the capabilities of the bus connectivity of and sync settings for - * the target. - */ -struct ahc_syncrate * -ahc_devlimited_syncrate(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *tinfo, - u_int *period, u_int *ppr_options, role_t role) { - struct ahc_transinfo *transinfo; - u_int maxsync; - - if ((ahc->features & AHC_ULTRA2) != 0) { - if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 - && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { - maxsync = AHC_SYNCRATE_DT; - } else { - maxsync = AHC_SYNCRATE_ULTRA; - /* Can't do DT on an SE bus */ - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - } else if ((ahc->features & AHC_ULTRA) != 0) { - maxsync = AHC_SYNCRATE_ULTRA; - } else { - maxsync = AHC_SYNCRATE_FAST; - } - /* - * Never allow a value higher than our current goal - * period otherwise we may allow a target initiated - * negotiation to go above the limit as set by the - * user. In the case of an initiator initiated - * sync negotiation, we limit based on the user - * setting. This allows the system to still accept - * incoming negotiations even if target initiated - * negotiation is not performed. - */ - if (role == ROLE_TARGET) - transinfo = &tinfo->user; - else - transinfo = &tinfo->goal; - *ppr_options &= transinfo->ppr_options; - if (transinfo->period == 0) { - *period = 0; - *ppr_options = 0; - return (NULL); - } - *period = MAX(*period, transinfo->period); - return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); -} - -/* - * Look up the valid period to SCSIRATE conversion in our table. - * Return the period and offset that should be sent to the target - * if this was the beginning of an SDTR. - */ -struct ahc_syncrate * -ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, - u_int *ppr_options, u_int maxsync) -{ - struct ahc_syncrate *syncrate; - - if ((ahc->features & AHC_DT) == 0) - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - - /* Skip all DT only entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && maxsync < AHC_SYNCRATE_ULTRA2) - maxsync = AHC_SYNCRATE_ULTRA2; - - for (syncrate = &ahc_syncrates[maxsync]; - syncrate->rate != NULL; - syncrate++) { - - /* - * The Ultra2 table doesn't go as low - * as for the Fast/Ultra cards. - */ - if ((ahc->features & AHC_ULTRA2) != 0 - && (syncrate->sxfr_u2 == 0)) - break; - - if (*period <= syncrate->period) { - /* - * When responding to a target that requests - * sync, the requested rate may fall between - * two rates that we can output, but still be - * a rate that we can receive. Because of this, - * we want to respond to the target with - * the same rate that it sent to us even - * if the period we use to send data to it - * is lower. Only lower the response period - * if we must. - */ - if (syncrate == &ahc_syncrates[maxsync]) - *period = syncrate->period; - - /* - * At some speeds, we only support - * ST transfers. - */ - if ((syncrate->sxfr_u2 & ST_SXFR) != 0) - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - break; - } - } - - if ((*period == 0) - || (syncrate->rate == NULL) - || ((ahc->features & AHC_ULTRA2) != 0 - && (syncrate->sxfr_u2 == 0))) { - /* Use asynchronous transfers. */ - *period = 0; - syncrate = NULL; - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - return (syncrate); -} - -/* - * Convert from an entry in our syncrate table to the SCSI equivalent - * sync "period" factor. - */ -u_int -ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync) -{ - struct ahc_syncrate *syncrate; - - if ((ahc->features & AHC_ULTRA2) != 0) - scsirate &= SXFR_ULTRA2; - else - scsirate &= SXFR; - - syncrate = &ahc_syncrates[maxsync]; - while (syncrate->rate != NULL) { - - if ((ahc->features & AHC_ULTRA2) != 0) { - if (syncrate->sxfr_u2 == 0) - break; - else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2)) - return (syncrate->period); - } else if (scsirate == (syncrate->sxfr & SXFR)) { - return (syncrate->period); - } - syncrate++; - } - return (0); /* async */ -} - -/* - * Truncate the given synchronous offset to a value the - * current adapter type and syncrate are capable of. - */ -void -ahc_validate_offset(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *tinfo, - struct ahc_syncrate *syncrate, - u_int *offset, int wide, role_t role) -{ - u_int maxoffset; - - /* Limit offset to what we can do */ - if (syncrate == NULL) { - maxoffset = 0; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - maxoffset = MAX_OFFSET_ULTRA2; - } else { - if (wide) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - } - *offset = MIN(*offset, maxoffset); - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *offset = MIN(*offset, tinfo->user.offset); - else - *offset = MIN(*offset, tinfo->goal.offset); - } -} - -/* - * Truncate the given transfer width parameter to a value the - * current adapter type is capable of. - */ -void -ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, - u_int *bus_width, role_t role) -{ - switch (*bus_width) { - default: - if (ahc->features & AHC_WIDE) { - /* Respond Wide */ - *bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - /* FALLTHROUGH */ - case MSG_EXT_WDTR_BUS_8_BIT: - *bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *bus_width = MIN(tinfo->user.width, *bus_width); - else - *bus_width = MIN(tinfo->goal.width, *bus_width); - } -} - -/* - * Update the bitmask of targets for which the controller should - * negotiate with at the next convenient oportunity. This currently - * means the next time we send the initial identify messages for - * a new transaction. - */ -int -ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct ahc_tmode_tstate *tstate, - struct ahc_initiator_tinfo *tinfo, int force) -{ - u_int auto_negotiate_orig; - - auto_negotiate_orig = tstate->auto_negotiate; - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options - || (force - && (tinfo->goal.period != 0 - || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT - || tinfo->goal.ppr_options != 0))) - tstate->auto_negotiate |= devinfo->target_mask; - else - tstate->auto_negotiate &= ~devinfo->target_mask; - - return (auto_negotiate_orig != tstate->auto_negotiate); -} - -/* - * Update the user/goal/curr tables of synchronous negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct ahc_syncrate *syncrate, u_int period, - u_int offset, u_int ppr_options, u_int type, int paused) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int old_period; - u_int old_offset; - u_int old_ppr; - int active; - int update_needed; - - active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; - update_needed = 0; - - if (syncrate == NULL) { - period = 0; - offset = 0; - } - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHC_TRANS_USER) != 0) { - tinfo->user.period = period; - tinfo->user.offset = offset; - tinfo->user.ppr_options = ppr_options; - } - - if ((type & AHC_TRANS_GOAL) != 0) { - tinfo->goal.period = period; - tinfo->goal.offset = offset; - tinfo->goal.ppr_options = ppr_options; - } - - old_period = tinfo->curr.period; - old_offset = tinfo->curr.offset; - old_ppr = tinfo->curr.ppr_options; - - if ((type & AHC_TRANS_CUR) != 0 - && (old_period != period - || old_offset != offset - || old_ppr != ppr_options)) { - u_int scsirate; - - update_needed++; - scsirate = tinfo->scsirate; - if ((ahc->features & AHC_ULTRA2) != 0) { - - scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); - if (syncrate != NULL) { - scsirate |= syncrate->sxfr_u2; - if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) - scsirate |= ENABLE_CRC; - else - scsirate |= SINGLE_EDGE; - } - } else { - - scsirate &= ~(SXFR|SOFS); - /* - * Ensure Ultra mode is set properly for - * this target. - */ - tstate->ultraenb &= ~devinfo->target_mask; - if (syncrate != NULL) { - if (syncrate->sxfr & ULTRA_SXFR) { - tstate->ultraenb |= - devinfo->target_mask; - } - scsirate |= syncrate->sxfr & SXFR; - scsirate |= offset & SOFS; - } - if (active) { - u_int sxfrctl0; - - sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - sxfrctl0 &= ~FAST20; - if (tstate->ultraenb & devinfo->target_mask) - sxfrctl0 |= FAST20; - ahc_outb(ahc, SXFRCTL0, sxfrctl0); - } - } - if (active) { - ahc_outb(ahc, SCSIRATE, scsirate); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIOFFSET, offset); - } - - tinfo->scsirate = scsirate; - tinfo->curr.period = period; - tinfo->curr.offset = offset; - tinfo->curr.ppr_options = ppr_options; - - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); - if (bootverbose) { - if (offset != 0) { - printf("%s: target %d synchronous at %sMHz%s, " - "offset = 0x%x\n", ahc_name(ahc), - devinfo->target, syncrate->rate, - (ppr_options & MSG_EXT_PPR_DT_REQ) - ? " DT" : "", offset); - } else { - printf("%s: target %d using " - "asynchronous transfers\n", - ahc_name(ahc), devinfo->target); - } - } - } - - update_needed += ahc_update_neg_request(ahc, devinfo, tstate, - tinfo, /*force*/FALSE); - - if (update_needed) - ahc_update_pending_scbs(ahc); -} - -/* - * Update the user/goal/curr tables of wide negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int width, u_int type, int paused) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int oldwidth; - int active; - int update_needed; - - active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; - update_needed = 0; - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHC_TRANS_USER) != 0) - tinfo->user.width = width; - - if ((type & AHC_TRANS_GOAL) != 0) - tinfo->goal.width = width; - - oldwidth = tinfo->curr.width; - if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { - u_int scsirate; - - update_needed++; - scsirate = tinfo->scsirate; - scsirate &= ~WIDEXFER; - if (width == MSG_EXT_WDTR_BUS_16_BIT) - scsirate |= WIDEXFER; - - tinfo->scsirate = scsirate; - - if (active) - ahc_outb(ahc, SCSIRATE, scsirate); - - tinfo->curr.width = width; - - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); - if (bootverbose) { - printf("%s: target %d using %dbit transfers\n", - ahc_name(ahc), devinfo->target, - 8 * (0x01 << width)); - } - } - - update_needed += ahc_update_neg_request(ahc, devinfo, tstate, - tinfo, /*force*/FALSE); - if (update_needed) - ahc_update_pending_scbs(ahc); -} - -/* - * Update the current state of tagged queuing for a given target. - */ -void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - ahc_queue_alg alg) -{ - ahc_platform_set_tags(ahc, devinfo, alg); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG, &alg); -} - -/* - * When the transfer settings for a connection change, update any - * in-transit SCBs to contain the new data so the hardware will - * be set correctly during future (re)selections. - */ -static void -ahc_update_pending_scbs(struct ahc_softc *ahc) -{ - struct scb *pending_scb; - int pending_scb_count; - int i; - int paused; - u_int saved_scbptr; - - /* - * Traverse the pending SCB list and ensure that all of the - * SCBs there have the proper settings. - */ - pending_scb_count = 0; - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - struct ahc_devinfo devinfo; - struct hardware_scb *pending_hscb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - - ahc_scb_devinfo(ahc, &devinfo, pending_scb); - tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - pending_hscb = pending_scb->hscb; - pending_hscb->control &= ~ULTRAENB; - if ((tstate->ultraenb & devinfo.target_mask) != 0) - pending_hscb->control |= ULTRAENB; - pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->curr.offset; - if ((tstate->auto_negotiate & devinfo.target_mask) == 0 - && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { - pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; - pending_hscb->control &= ~MK_MESSAGE; - } - ahc_sync_scb(ahc, pending_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - pending_scb_count++; - } - - if (pending_scb_count == 0) - return; - - if (ahc_is_paused(ahc)) { - paused = 1; - } else { - paused = 0; - ahc_pause(ahc); - } - - saved_scbptr = ahc_inb(ahc, SCBPTR); - /* Ensure that the hscbs down on the card match the new information */ - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - struct hardware_scb *pending_hscb; - u_int control; - u_int scb_tag; - - ahc_outb(ahc, SCBPTR, i); - scb_tag = ahc_inb(ahc, SCB_TAG); - pending_scb = ahc_lookup_scb(ahc, scb_tag); - if (pending_scb == NULL) - continue; - - pending_hscb = pending_scb->hscb; - control = ahc_inb(ahc, SCB_CONTROL); - control &= ~(ULTRAENB|MK_MESSAGE); - control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); - ahc_outb(ahc, SCB_CONTROL, control); - ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); - ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); - } - ahc_outb(ahc, SCBPTR, saved_scbptr); - - if (paused == 0) - ahc_unpause(ahc); -} - -/**************************** Pathing Information *****************************/ -static void -ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - u_int saved_scsiid; - role_t role; - int our_id; - - if (ahc_inb(ahc, SSTAT0) & TARGET) - role = ROLE_TARGET; - else - role = ROLE_INITIATOR; - - if (role == ROLE_TARGET - && (ahc->features & AHC_MULTI_TID) != 0 - && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { - /* We were selected, so pull our id from TARGIDIN */ - our_id = ahc_inb(ahc, TARGIDIN) & OID; - } else if ((ahc->features & AHC_ULTRA2) != 0) - our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; - else - our_id = ahc_inb(ahc, SCSIID) & OID; - - saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); - ahc_compile_devinfo(devinfo, - our_id, - SCSIID_TARGET(ahc, saved_scsiid), - ahc_inb(ahc, SAVED_LUN), - SCSIID_CHANNEL(ahc, saved_scsiid), - role); -} - -struct ahc_phase_table_entry* -ahc_lookup_phase_entry(int phase) -{ - struct ahc_phase_table_entry *entry; - struct ahc_phase_table_entry *last_entry; - - /* - * num_phases doesn't include the default entry which - * will be returned if the phase doesn't match. - */ - last_entry = &ahc_phase_table[num_phases]; - for (entry = ahc_phase_table; entry < last_entry; entry++) { - if (phase == entry->phase) - break; - } - return (entry); -} - -void -ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, - u_int lun, char channel, role_t role) -{ - devinfo->our_scsiid = our_id; - devinfo->target = target; - devinfo->lun = lun; - devinfo->target_offset = target; - devinfo->channel = channel; - devinfo->role = role; - if (channel == 'B') - devinfo->target_offset += 8; - devinfo->target_mask = (0x01 << devinfo->target_offset); -} - -static void -ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - role_t role; - int our_id; - - our_id = SCSIID_OUR_ID(scb->hscb->scsiid); - role = ROLE_INITIATOR; - if ((scb->hscb->control & TARGET_SCB) != 0) - role = ROLE_TARGET; - ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb), - SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role); -} - - -/************************ Message Phase Processing ****************************/ -static void -ahc_assert_atn(struct ahc_softc *ahc) -{ - u_int scsisigo; - - scsisigo = ATNO; - if ((ahc->features & AHC_DT) == 0) - scsisigo |= ahc_inb(ahc, SCSISIGI); - ahc_outb(ahc, SCSISIGO, scsisigo); -} - -/* - * When an initiator transaction with the MK_MESSAGE flag either reconnects - * or enters the initial message out phase, we are interrupted. Fill our - * outgoing message buffer with the appropriate message and beging handing - * the message phase(s) manually. - */ -static void -ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if ((scb->flags & SCB_DEVICE_RESET) == 0 - && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { - u_int identify_msg; - - identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); - if ((scb->hscb->control & DISCENB) != 0) - identify_msg |= MSG_IDENTIFY_DISCFLAG; - ahc->msgout_buf[ahc->msgout_index++] = identify_msg; - ahc->msgout_len++; - - if ((scb->hscb->control & TAG_ENB) != 0) { - ahc->msgout_buf[ahc->msgout_index++] = - scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); - ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; - ahc->msgout_len += 2; - } - } - - if (scb->flags & SCB_DEVICE_RESET) { - ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; - ahc->msgout_len++; - ahc_print_path(ahc, scb); - printf("Bus Device Reset Message Sent\n"); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((scb->flags & SCB_ABORT) != 0) { - if ((scb->hscb->control & TAG_ENB) != 0) - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; - else - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; - ahc->msgout_len++; - ahc_print_path(ahc, scb); - printf("Abort%s Message Sent\n", - (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { - ahc_build_transfer_msg(ahc, devinfo); - } else { - printf("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message\n"); - printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, - devinfo->target_mask); - panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " - "SCB flags = %x", scb->hscb->tag, scb->hscb->control, - ahc_inb(ahc, MSG_OUT), scb->flags); - } - - /* - * Clear the MK_MESSAGE flag from the SCB so we aren't - * asked to send this message again. - */ - ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); - scb->hscb->control &= ~MK_MESSAGE; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; -} - -/* - * Build an appropriate transfer negotiation message for the - * currently active target. - */ -static void -ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * We need to initiate transfer negotiations. - * If our current and goal settings are identical, - * we want to renegotiate due to a check condition. - */ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - struct ahc_syncrate *rate; - int dowide; - int dosync; - int doppr; - int use_ppr; - u_int period; - u_int ppr_options; - u_int offset; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - /* - * Filter our period based on the current connection. - * If we can't perform DT transfers on this segment (not in LVD - * mode for instance), then our decision to issue a PPR message - * may change. - */ - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); - dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.period != period; - doppr = tinfo->curr.ppr_options != ppr_options; - - if (!dowide && !dosync && !doppr) { - dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.period != 0; - doppr = tinfo->goal.ppr_options != 0; - } - - if (!dowide && !dosync && !doppr) { - panic("ahc_intr: AWAITING_MSG for negotiation, " - "but no negotiation needed\n"); - } - - use_ppr = (tinfo->curr.transport_version >= 3) || doppr; - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - use_ppr = 0; - - /* - * Both the PPR message and SDTR message require the - * goal syncrate to be limited to what the target device - * is capable of handling (based on whether an LVD->SE - * expander is on the bus), so combine these two cases. - * Regardless, guarantee that if we are using WDTR and SDTR - * messages that WDTR comes first. - */ - if (use_ppr || (dosync && !dowide)) { - - offset = tinfo->goal.offset; - ahc_validate_offset(ahc, tinfo, rate, &offset, - use_ppr ? tinfo->goal.width - : tinfo->curr.width, - devinfo->role); - if (use_ppr) { - ahc_construct_ppr(ahc, devinfo, period, offset, - tinfo->goal.width, ppr_options); - } else { - ahc_construct_sdtr(ahc, devinfo, period, offset); - } - } else { - ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width); - } -} - -/* - * Build a synchronous negotiation message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int period, u_int offset) -{ - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR; - ahc->msgout_buf[ahc->msgout_index++] = period; - ahc->msgout_buf[ahc->msgout_index++] = offset; - ahc->msgout_len += 5; - if (bootverbose) { - printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, period, offset); - } -} - -/* - * Build a wide negotiation message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int bus_width) -{ - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR; - ahc->msgout_buf[ahc->msgout_index++] = bus_width; - ahc->msgout_len += 4; - if (bootverbose) { - printf("(%s:%c:%d:%d): Sending WDTR %x\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, bus_width); - } -} - -/* - * Build a parallel protocol request message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int period, u_int offset, u_int bus_width, - u_int ppr_options) -{ - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR; - ahc->msgout_buf[ahc->msgout_index++] = period; - ahc->msgout_buf[ahc->msgout_index++] = 0; - ahc->msgout_buf[ahc->msgout_index++] = offset; - ahc->msgout_buf[ahc->msgout_index++] = bus_width; - ahc->msgout_buf[ahc->msgout_index++] = ppr_options; - ahc->msgout_len += 8; - if (bootverbose) { - printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " - "offset %x, ppr_options %x\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun, - bus_width, period, offset, ppr_options); - } -} - -/* - * Clear any active message state. - */ -static void -ahc_clear_msg_state(struct ahc_softc *ahc) -{ - ahc->msgout_len = 0; - ahc->msgin_index = 0; - ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { - /* - * The target didn't care to respond to our - * message request, so clear ATN. - */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - } - ahc_outb(ahc, MSG_OUT, MSG_NOOP); - ahc_outb(ahc, SEQ_FLAGS2, - ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); -} - -/* - * Manual message loop handler. - */ -static void -ahc_handle_message_phase(struct ahc_softc *ahc) -{ - struct ahc_devinfo devinfo; - u_int bus_phase; - int end_session; - - ahc_fetch_devinfo(ahc, &devinfo); - end_session = FALSE; - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - -reswitch: - switch (ahc->msg_type) { - case MSG_TYPE_INITIATOR_MSGOUT: - { - int lastbyte; - int phasemis; - int msgdone; - - if (ahc->msgout_len == 0) - panic("HOST_MSG_LOOP interrupt with no active message"); - - phasemis = bus_phase != P_MESGOUT; - if (phasemis) { - if (bus_phase == P_MESGIN) { - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc->send_msg_perror = FALSE; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; - goto reswitch; - } - end_session = TRUE; - break; - } - - if (ahc->send_msg_perror) { - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); - break; - } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - /* - * The target has requested a retry. - * Re-assert ATN, reset our message index to - * 0, and try again. - */ - ahc->msgout_index = 0; - ahc_assert_atn(ahc); - } - - lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); - if (lastbyte) { - /* Last byte is signified by dropping ATN */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - } - - /* - * Clear our interrupt status and present - * the next byte on the bus. - */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - int phasemis; - int message_done; - - phasemis = bus_phase != P_MESGIN; - - if (phasemis) { - ahc->msgin_index = 0; - if (bus_phase == P_MESGOUT - && (ahc->send_msg_perror == TRUE - || (ahc->msgout_len != 0 - && ahc->msgout_index == 0))) { - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - goto reswitch; - } - end_session = TRUE; - break; - } - - /* Pull the byte in without acking it */ - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); - - message_done = ahc_parse_msg(ahc, &devinfo); - - if (message_done) { - /* - * Clear our incoming message buffer in case there - * is another message following this one. - */ - ahc->msgin_index = 0; - - /* - * If this message illicited a response, - * assert ATN so the target takes us to the - * message out phase. - */ - if (ahc->msgout_len != 0) - ahc_assert_atn(ahc); - } else - ahc->msgin_index++; - - /* Ack the byte */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_inb(ahc, SCSIDATL); - break; - } - case MSG_TYPE_TARGET_MSGIN: - { - int msgdone; - int msgout_request; - - if (ahc->msgout_len == 0) - panic("Target MSGIN with no active message"); - - /* - * If we interrupted a mesgout session, the initiator - * will not know this until our first REQ. So, we - * only honor mesgout requests after we've sent our - * first byte. - */ - if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 - && ahc->msgout_index > 0) - msgout_request = TRUE; - else - msgout_request = FALSE; - - if (msgout_request) { - - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; - ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); - ahc->msgin_index = 0; - /* Dummy read to REQ for first byte */ - ahc_inb(ahc, SCSIDATL); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - break; - } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - end_session = TRUE; - break; - } - - /* - * Present the next byte on the bus. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_TARGET_MSGOUT: - { - int lastbyte; - int msgdone; - - /* - * The initiator signals that this is - * the last byte by dropping ATN. - */ - lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0; - - /* - * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertantly cause a REQ for the - * next byte. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); - msgdone = ahc_parse_msg(ahc, &devinfo); - if (msgdone == MSGLOOP_TERMINATED) { - /* - * The message is *really* done in that it caused - * us to go to bus free. The sequencer has already - * been reset at this point, so pull the ejection - * handle. - */ - return; - } - - ahc->msgin_index++; - - /* - * XXX Read spec about initiator dropping ATN too soon - * and use msgdone to detect it. - */ - if (msgdone == MSGLOOP_MSGCOMPLETE) { - ahc->msgin_index = 0; - - /* - * If this message illicited a response, transition - * to the Message in phase and send it. - */ - if (ahc->msgout_len != 0) { - ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; - ahc->msgin_index = 0; - break; - } - } - - if (lastbyte) - end_session = TRUE; - else { - /* Ask for the next byte. */ - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - } - - break; - } - default: - panic("Unknown REQINIT message type"); - } - - if (end_session) { - ahc_clear_msg_state(ahc); - ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); - } else - ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); -} - -/* - * See if we sent a particular extended message to the target. - * If "full" is true, return true only if the target saw the full - * message. If "full" is false, return true if the target saw at - * least the first byte of the message. - */ -static int -ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) -{ - int found; - u_int index; - - found = FALSE; - index = 0; - - while (index < ahc->msgout_len) { - if (ahc->msgout_buf[index] == MSG_EXTENDED) { - u_int end_index; - - end_index = index + 1 + ahc->msgout_buf[index + 1]; - if (ahc->msgout_buf[index+2] == msgval - && type == AHCMSG_EXT) { - - if (full) { - if (ahc->msgout_index > end_index) - found = TRUE; - } else if (ahc->msgout_index > index) - found = TRUE; - } - index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK - && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { - - /* Skip tag type and tag id or residue param*/ - index += 2; - } else { - /* Single byte message */ - if (type == AHCMSG_1B - && ahc->msgout_buf[index] == msgval - && ahc->msgout_index > index) - found = TRUE; - index++; - } - - if (found) - break; - } - return (found); -} - -/* - * Wait for a complete incoming message, parse it, and respond accordingly. - */ -static int -ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - int reject; - int done; - int response; - u_int targ_scsirate; - - done = MSGLOOP_IN_PROG; - response = FALSE; - reject = FALSE; - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - targ_scsirate = tinfo->scsirate; - - /* - * Parse as much of the message as is availible, - * rejecting it if we don't support it. When - * the entire message is availible and has been - * handled, return MSGLOOP_MSGCOMPLETE, indicating - * that we have parsed an entire message. - * - * In the case of extended messages, we accept the length - * byte outright and perform more checking once we know the - * extended message type. - */ - switch (ahc->msgin_buf[0]) { - case MSG_MESSAGE_REJECT: - response = ahc_handle_msg_reject(ahc, devinfo); - /* FALLTHROUGH */ - case MSG_NOOP: - done = MSGLOOP_MSGCOMPLETE; - break; - case MSG_EXTENDED: - { - /* Wait for enough of the message to begin validation */ - if (ahc->msgin_index < 2) - break; - switch (ahc->msgin_buf[2]) { - case MSG_EXT_SDTR: - { - struct ahc_syncrate *syncrate; - u_int period; - u_int ppr_options; - u_int offset; - u_int saved_offset; - - if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have both args before validating - * and acting on this message. - * - * Add one to MSG_EXT_SDTR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) - break; - - period = ahc->msgin_buf[3]; - ppr_options = 0; - saved_offset = offset = ahc->msgin_buf[4]; - syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, - devinfo->role); - ahc_validate_offset(ahc, tinfo, syncrate, &offset, - targ_scsirate & WIDEXFER, - devinfo->role); - if (bootverbose) { - printf("(%s:%c:%d:%d): Received " - "SDTR period %x, offset %x\n\t" - "Filtered to period %x, offset %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_offset, - period, offset); - } - ahc_set_syncrate(ahc, devinfo, - syncrate, period, - offset, ppr_options, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - - /* - * See if we initiated Sync Negotiation - * and didn't have to fall down to async - * transfers. - */ - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) { - /* We started it */ - if (saved_offset != offset) { - /* Went too low - force async */ - reject = TRUE; - } - } else { - /* - * Send our own SDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " - "Initiated SDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_sdtr(ahc, devinfo, - period, offset); - ahc->msgout_index = 0; - response = TRUE; - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_WDTR: - { - u_int bus_width; - u_int saved_width; - u_int sending_reply; - - sending_reply = FALSE; - if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have our arg before validating - * and acting on this message. - * - * Add one to MSG_EXT_WDTR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) - break; - - bus_width = ahc->msgin_buf[3]; - saved_width = bus_width; - ahc_validate_width(ahc, tinfo, &bus_width, - devinfo->role); - if (bootverbose) { - printf("(%s:%c:%d:%d): Received WDTR " - "%x filtered to %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, bus_width); - } - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) { - /* - * Don't send a WDTR back to the - * target, since we asked first. - * If the width went higher than our - * request, reject it. - */ - if (saved_width > bus_width) { - reject = TRUE; - printf("(%s:%c:%d:%d): requested %dBit " - "transfers. Rejecting...\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - 8 * (0x01 << bus_width)); - bus_width = 0; - } - } else { - /* - * Send our own WDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " - "Initiated WDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_wdtr(ahc, devinfo, bus_width); - ahc->msgout_index = 0; - response = TRUE; - sending_reply = TRUE; - } - ahc_set_width(ahc, devinfo, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - /* After a wide message, we are async */ - ahc_set_syncrate(ahc, devinfo, - /*syncrate*/NULL, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHC_TRANS_ACTIVE, /*paused*/TRUE); - if (sending_reply == FALSE && reject == FALSE) { - - if (tinfo->goal.period) { - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = TRUE; - } - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_PPR: - { - struct ahc_syncrate *syncrate; - u_int period; - u_int offset; - u_int bus_width; - u_int ppr_options; - u_int saved_width; - u_int saved_offset; - u_int saved_ppr_options; - - if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have all args before validating - * and acting on this message. - * - * Add one to MSG_EXT_PPR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1)) - break; - - period = ahc->msgin_buf[3]; - offset = ahc->msgin_buf[5]; - bus_width = ahc->msgin_buf[6]; - saved_width = bus_width; - ppr_options = ahc->msgin_buf[7]; - /* - * According to the spec, a DT only - * period factor with no DT option - * set implies async. - */ - if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && period == 9) - offset = 0; - saved_ppr_options = ppr_options; - saved_offset = offset; - - /* - * Mask out any options we don't support - * on any controller. Transfer options are - * only available if we are negotiating wide. - */ - ppr_options &= MSG_EXT_PPR_DT_REQ; - if (bus_width == 0) - ppr_options = 0; - - ahc_validate_width(ahc, tinfo, &bus_width, - devinfo->role); - syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, - devinfo->role); - ahc_validate_offset(ahc, tinfo, syncrate, - &offset, bus_width, - devinfo->role); - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) { - /* - * If we are unable to do any of the - * requested options (we went too low), - * then we'll have to reject the message. - */ - if (saved_width > bus_width - || saved_offset != offset - || saved_ppr_options != ppr_options) { - reject = TRUE; - period = 0; - offset = 0; - bus_width = 0; - ppr_options = 0; - syncrate = NULL; - } - } else { - if (devinfo->role != ROLE_TARGET) - printf("(%s:%c:%d:%d): Target " - "Initiated PPR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - else - printf("(%s:%c:%d:%d): Initiator " - "Initiated PPR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_ppr(ahc, devinfo, period, offset, - bus_width, ppr_options); - ahc->msgout_index = 0; - response = TRUE; - } - if (bootverbose) { - printf("(%s:%c:%d:%d): Received PPR width %x, " - "period %x, offset %x,options %x\n" - "\tFiltered to width %x, period %x, " - "offset %x, options %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, ahc->msgin_buf[3], - saved_offset, saved_ppr_options, - bus_width, period, offset, ppr_options); - } - ahc_set_width(ahc, devinfo, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_set_syncrate(ahc, devinfo, - syncrate, period, - offset, ppr_options, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - done = MSGLOOP_MSGCOMPLETE; - break; - } - default: - /* Unknown extended message. Reject it. */ - reject = TRUE; - break; - } - break; - } -#ifdef AHC_TARGET_MODE - case MSG_BUS_DEV_RESET: - ahc_handle_devreset(ahc, devinfo, - CAM_BDR_SENT, - "Bus Device Reset Received", - /*verbose_level*/0); - ahc_restart(ahc); - done = MSGLOOP_TERMINATED; - break; - case MSG_ABORT_TAG: - case MSG_ABORT: - case MSG_CLEAR_QUEUE: - { - int tag; - - /* Target mode messages */ - if (devinfo->role != ROLE_TARGET) { - reject = TRUE; - break; - } - tag = SCB_LIST_NULL; - if (ahc->msgin_buf[0] == MSG_ABORT_TAG) - tag = ahc_inb(ahc, INITIATOR_TAG); - ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, - devinfo->lun, tag, ROLE_TARGET, - CAM_REQ_ABORTED); - - tstate = ahc->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[devinfo->lun]; - if (lstate != NULL) { - ahc_queue_lstate_event(ahc, lstate, - devinfo->our_scsiid, - ahc->msgin_buf[0], - /*arg*/tag); - ahc_send_lstate_events(ahc, lstate); - } - } - ahc_restart(ahc); - done = MSGLOOP_TERMINATED; - break; - } -#endif - case MSG_TERM_IO_PROC: - default: - reject = TRUE; - break; - } - - if (reject) { - /* - * Setup to reject the message. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 1; - ahc->msgout_buf[0] = MSG_MESSAGE_REJECT; - done = MSGLOOP_MSGCOMPLETE; - response = TRUE; - } - - if (done != MSGLOOP_IN_PROG && !response) - /* Clear the outgoing message buffer */ - ahc->msgout_len = 0; - - return (done); -} - -/* - * Process a message reject message. - */ -static int -ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - struct scb *scb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int scb_index; - u_int last_msg; - int response = 0; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - /* Might be necessary */ - last_msg = ahc_inb(ahc, LAST_MSG); - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { - /* - * Target does not support the PPR message. - * Attempt to negotiate SPI-2 style. - */ - if (bootverbose) { - printf("(%s:%c:%d:%d): PPR Rejected. " - "Trying WDTR/SDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - tinfo->goal.ppr_options = 0; - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = 1; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { - - /* note 8bit xfers */ - printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " - "8bit transfers\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - /* - * No need to clear the sync rate. If the target - * did not accept the command, our syncrate is - * unaffected. If the target started the negotiation, - * but rejected our response, we already cleared the - * sync rate before sending our WDTR. - */ - if (tinfo->goal.period) { - - /* Start the sync negotiation */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = 1; - } - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { - /* note asynch xfers and clear flag */ - ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - printf("(%s:%c:%d:%d): refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { - int tag_type; - int mask; - - tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); - - if (tag_type == MSG_SIMPLE_TASK) { - printf("(%s:%c:%d:%d): refuses tagged commands. " - "Performing non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); - mask = ~0x23; - } else { - printf("(%s:%c:%d:%d): refuses %s tagged commands. " - "Performing simple queue tagged I/O only\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, tag_type == MSG_ORDERED_TASK - ? "ordered" : "head of queue"); - ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); - mask = ~0x03; - } - - /* - * Resend the identify for this CCB as the target - * may believe that the selection is invalid otherwise. - */ - ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & mask); - scb->hscb->control &= mask; - ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_TASK); - ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_assert_atn(ahc); - - /* - * This transaction is now at the head of - * the untagged queue for this target. - */ - if ((ahc->flags & AHC_SCB_BTT) == 0) { - struct scb_tailq *untagged_q; - - untagged_q = - &(ahc->untagged_queues[devinfo->target_offset]); - TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe); - scb->flags |= SCB_UNTAGGEDQ; - } - ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), - scb->hscb->tag); - - /* - * Requeue all tagged commands for this target - * currently in our posession so they can be - * converted to untagged commands. - */ - ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ, - SEARCH_COMPLETE); - } else { - /* - * Otherwise, we ignore it. - */ - printf("%s:%c:%d: Message reject for %x -- ignored\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - last_msg); - } - return (response); -} - -/* - * Process an ingnore wide residue message. - */ -static void -ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - u_int scb_index; - struct scb *scb; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - /* - * XXX Actually check data direction in the sequencer? - * Perhaps add datadir to some spare bits in the hscb? - */ - if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 - || ahc_get_transfer_dir(scb) != CAM_DIR_IN) { - /* - * Ignore the message if we haven't - * seen an appropriate data phase yet. - */ - } else { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. Otherwise, subtract a byte - * and update the residual count accordingly. - */ - uint32_t sgptr; - - sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); - if ((sgptr & SG_LIST_NULL) != 0 - && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. - */ - } else { - struct ahc_dma_seg *sg; - uint32_t data_cnt; - uint32_t data_addr; - uint32_t sglen; - - /* Pull in the rest of the sgptr */ - sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); - sgptr &= SG_PTR_MASK; - data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); - - data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) - | (ahc_inb(ahc, SHADDR + 2) << 16) - | (ahc_inb(ahc, SHADDR + 1) << 8) - | (ahc_inb(ahc, SHADDR)); - - data_cnt += 1; - data_addr -= 1; - - sg = ahc_sg_bus_to_virt(scb, sgptr); - /* - * The residual sg ptr points to the next S/G - * to load so we must go back one. - */ - sg--; - sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; - if (sg != scb->sg_list - && sglen < (data_cnt & AHC_SG_LEN_MASK)) { - - sg--; - sglen = ahc_le32toh(sg->len); - /* - * Preserve High Address and SG_LIST bits - * while setting the count to 1. - */ - data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK)); - data_addr = ahc_le32toh(sg->addr) - + (sglen & AHC_SG_LEN_MASK) - 1; - - /* - * Increment sg so it points to the - * "next" sg. - */ - sg++; - sgptr = ahc_sg_virt_to_bus(scb, sg); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, - sgptr >> 24); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, - sgptr >> 16); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, - sgptr >> 8); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); - } - - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); - } - } -} - - -/* - * Reinitialize the data pointers for the active transfer - * based on its current residual. - */ -static void -ahc_reinitialize_dataptrs(struct ahc_softc *ahc) -{ - struct scb *scb; - struct ahc_dma_seg *sg; - u_int scb_index; - uint32_t sgptr; - uint32_t resid; - uint32_t dataptr; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - sgptr = (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8) - | ahc_inb(ahc, SCB_RESIDUAL_SGPTR); - - sgptr &= SG_PTR_MASK; - sg = ahc_sg_bus_to_virt(scb, sgptr); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - resid = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8) - | ahc_inb(ahc, SCB_RESIDUAL_DATACNT); - - dataptr = ahc_le32toh(sg->addr) - + (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK) - - resid; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - u_int dscommand1; - - dscommand1 = ahc_inb(ahc, DSCOMMAND1); - ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); - ahc_outb(ahc, HADDR, - (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS); - ahc_outb(ahc, DSCOMMAND1, dscommand1); - } - ahc_outb(ahc, HADDR + 3, dataptr >> 24); - ahc_outb(ahc, HADDR + 2, dataptr >> 16); - ahc_outb(ahc, HADDR + 1, dataptr >> 8); - ahc_outb(ahc, HADDR, dataptr); - ahc_outb(ahc, HCNT + 2, resid >> 16); - ahc_outb(ahc, HCNT + 1, resid >> 8); - ahc_outb(ahc, HCNT, resid); - if ((ahc->features & AHC_ULTRA2) == 0) { - ahc_outb(ahc, STCNT + 2, resid >> 16); - ahc_outb(ahc, STCNT + 1, resid >> 8); - ahc_outb(ahc, STCNT, resid); - } -} - -/* - * Handle the effects of issuing a bus device reset message. - */ -static void -ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - cam_status status, char *message, int verbose_level) -{ -#ifdef AHC_TARGET_MODE - struct ahc_tmode_tstate* tstate; - u_int lun; -#endif - int found; - - found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role, - status); - -#ifdef AHC_TARGET_MODE - /* - * Send an immediate notify ccb to all target mord peripheral - * drivers affected by this action. - */ - tstate = ahc->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[lun]; - if (lstate == NULL) - continue; - - ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid, - MSG_BUS_DEV_RESET, /*arg*/0); - ahc_send_lstate_events(ahc, lstate); - } - } -#endif - - /* - * Go back to async/narrow transfers and renegotiate. - */ - ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR, /*paused*/TRUE); - ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, - /*period*/0, /*offset*/0, /*ppr_options*/0, - AHC_TRANS_CUR, /*paused*/TRUE); - - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); - - if (message != NULL - && (verbose_level <= bootverbose)) - printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), - message, devinfo->channel, devinfo->target, found); -} - -#ifdef AHC_TARGET_MODE -static void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) - ahc_build_transfer_msg(ahc, devinfo); - else - panic("ahc_intr: AWAITING target message with no message"); - - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; -} -#endif -/**************************** Initialization **********************************/ -/* - * Allocate a controller structure for a new device - * and perform initial initializion. - */ -struct ahc_softc * -ahc_alloc(void *platform_arg, char *name) -{ - struct ahc_softc *ahc; - int i; - -#ifndef __FreeBSD__ - ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT); - if (!ahc) { - printf("aic7xxx: cannot malloc softc!\n"); - free(name, M_DEVBUF); - return NULL; - } -#else - ahc = device_get_softc((device_t)platform_arg); -#endif - memset(ahc, 0, sizeof(*ahc)); - LIST_INIT(&ahc->pending_scbs); - /* We don't know our unit number until the OSM sets it */ - ahc->name = name; - ahc->unit = -1; - ahc->description = NULL; - ahc->channel = 'A'; - ahc->channel_b = 'B'; - ahc->chip = AHC_NONE; - ahc->features = AHC_FENONE; - ahc->bugs = AHC_BUGNONE; - ahc->flags = AHC_FNONE; - - for (i = 0; i < 16; i++) - TAILQ_INIT(&ahc->untagged_queues[i]); - if (ahc_platform_alloc(ahc, platform_arg) != 0) { - ahc_free(ahc); - ahc = NULL; - } - return (ahc); -} - -int -ahc_softc_init(struct ahc_softc *ahc) -{ - - /* The IRQMS bit is only valid on VL and EISA chips */ - if ((ahc->chip & AHC_PCI) == 0) - ahc->unpause = ahc_inb(ahc, HCNTRL) & IRQMS; - else - ahc->unpause = 0; - ahc->pause = ahc->unpause | PAUSE; - /* XXX The shared scb data stuff should be deprecated */ - if (ahc->scb_data == NULL) { - ahc->scb_data = malloc(sizeof(*ahc->scb_data), - M_DEVBUF, M_NOWAIT); - if (ahc->scb_data == NULL) - return (ENOMEM); - memset(ahc->scb_data, 0, sizeof(*ahc->scb_data)); - } - - return (0); -} - -void -ahc_softc_insert(struct ahc_softc *ahc) -{ - struct ahc_softc *list_ahc; - -#if AHC_PCI_CONFIG > 0 - /* - * Second Function PCI devices need to inherit some - * settings from function 0. - */ - if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI - && (ahc->features & AHC_MULTI_FUNC) != 0) { - TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { - ahc_dev_softc_t list_pci; - ahc_dev_softc_t pci; - - list_pci = list_ahc->dev_softc; - pci = ahc->dev_softc; - if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { - struct ahc_softc *master; - struct ahc_softc *slave; - - if (ahc_get_pci_function(list_pci) == 0) { - master = list_ahc; - slave = ahc; - } else { - master = ahc; - slave = list_ahc; - } - slave->flags &= ~AHC_BIOS_ENABLED; - slave->flags |= - master->flags & AHC_BIOS_ENABLED; - slave->flags &= ~AHC_PRIMARY_CHANNEL; - slave->flags |= - master->flags & AHC_PRIMARY_CHANNEL; - break; - } - } - } -#endif - - /* - * Insertion sort into our list of softcs. - */ - list_ahc = TAILQ_FIRST(&ahc_tailq); - while (list_ahc != NULL - && ahc_softc_comp(list_ahc, ahc) <= 0) - list_ahc = TAILQ_NEXT(list_ahc, links); - if (list_ahc != NULL) - TAILQ_INSERT_BEFORE(list_ahc, ahc, links); - else - TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links); - ahc->init_level++; -} - -void -ahc_set_unit(struct ahc_softc *ahc, int unit) -{ - ahc->unit = unit; -} - -void -ahc_set_name(struct ahc_softc *ahc, char *name) -{ - if (ahc->name != NULL) - free(ahc->name, M_DEVBUF); - ahc->name = name; -} - -void -ahc_free(struct ahc_softc *ahc) -{ - int i; - - ahc_fini_scbdata(ahc); - switch (ahc->init_level) { - default: - case 5: - ahc_shutdown(ahc); - TAILQ_REMOVE(&ahc_tailq, ahc, links); - /* FALLTHROUGH */ - case 4: - ahc_dmamap_unload(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap); - /* FALLTHROUGH */ - case 3: - ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, - ahc->shared_data_dmamap); - ahc_dmamap_destroy(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap); - /* FALLTHROUGH */ - case 2: - ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); - case 1: -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); -#endif - break; - case 0: - break; - } - -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->parent_dmat); -#endif - ahc_platform_free(ahc); - for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct ahc_tmode_tstate *tstate; - - tstate = ahc->enabled_targets[i]; - if (tstate != NULL) { -#if AHC_TARGET_MODE - int j; - - for (j = 0; j < AHC_NUM_LUNS; j++) { - struct ahc_tmode_lstate *lstate; - - lstate = tstate->enabled_luns[j]; - if (lstate != NULL) { - xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); - } - } -#endif - free(tstate, M_DEVBUF); - } - } -#if AHC_TARGET_MODE - if (ahc->black_hole != NULL) { - xpt_free_path(ahc->black_hole->path); - free(ahc->black_hole, M_DEVBUF); - } -#endif - if (ahc->name != NULL) - free(ahc->name, M_DEVBUF); -#ifndef __FreeBSD__ - free(ahc, M_DEVBUF); -#endif - return; -} - -void -ahc_shutdown(void *arg) -{ - struct ahc_softc *ahc; - int i; - - ahc = (struct ahc_softc *)arg; - - /* This will reset most registers to 0, but not all */ - ahc_reset(ahc); - ahc_outb(ahc, SCSISEQ, 0); - ahc_outb(ahc, SXFRCTL0, 0); - ahc_outb(ahc, DSPCISTATUS, 0); - - for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++) - ahc_outb(ahc, i, 0); -} - -/* - * Reset the controller and record some information about it - * that is only availabel just after a reset. - */ -int -ahc_reset(struct ahc_softc *ahc) -{ - u_int sblkctl; - u_int sxfrctl1_a, sxfrctl1_b; - int wait; - - /* - * Preserve the value of the SXFRCTL1 register for all channels. - * It contains settings that affect termination and we don't want - * to disturb the integrity of the bus. - */ - ahc_pause(ahc); - sxfrctl1_b = 0; - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { - u_int sblkctl; - - /* - * Save channel B's settings in case this chip - * is setup for TWIN channel operation. - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); - sxfrctl1_b = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); - } - sxfrctl1_a = ahc_inb(ahc, SXFRCTL1); - - ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); - - /* - * Ensure that the reset has finished - */ - wait = 1000; - do { - ahc_delay(1000); - } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)); - - if (wait == 0) { - printf("%s: WARNING - Failed chip reset! " - "Trying to initialize anyway.\n", ahc_name(ahc)); - } - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* Determine channel configuration */ - sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE); - /* No Twin Channel PCI cards */ - if ((ahc->chip & AHC_PCI) != 0) - sblkctl &= ~SELBUSB; - switch (sblkctl) { - case 0: - /* Single Narrow Channel */ - break; - case 2: - /* Wide Channel */ - ahc->features |= AHC_WIDE; - break; - case 8: - /* Twin Channel */ - ahc->features |= AHC_TWIN; - break; - default: - printf(" Unsupported adapter type. Ignoring\n"); - return(-1); - } - - /* - * Reload sxfrctl1. - * - * We must always initialize STPWEN to 1 before we - * restore the saved values. STPWEN is initialized - * to a tri-state condition which can only be cleared - * by turning it on. - */ - if ((ahc->features & AHC_TWIN) != 0) { - u_int sblkctl; - - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); - ahc_outb(ahc, SXFRCTL1, sxfrctl1_b); - ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); - } - ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); - -#ifdef AHC_DUMP_SEQ - if (ahc->init_level == 0) - ahc_dumpseq(ahc); -#endif - - return (0); -} - -/* - * Determine the number of SCBs available on the controller - */ -int -ahc_probe_scbs(struct ahc_softc *ahc) { - int i; - - for (i = 0; i < AHC_SCB_MAX; i++) { - - ahc_outb(ahc, SCBPTR, i); - ahc_outb(ahc, SCB_BASE, i); - if (ahc_inb(ahc, SCB_BASE) != i) - break; - ahc_outb(ahc, SCBPTR, 0); - if (ahc_inb(ahc, SCB_BASE) != 0) - break; - } - return (i); -} - -static void -ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - bus_addr_t *baddr; - - baddr = (bus_addr_t *)arg; - *baddr = segs->ds_addr; -} - -static void -ahc_build_free_scb_list(struct ahc_softc *ahc) -{ - int i; - - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - ahc_outb(ahc, SCBPTR, i); - - /* Clear the control byte. */ - ahc_outb(ahc, SCB_CONTROL, 0); - - /* Set the next pointer */ - if ((ahc->flags & AHC_PAGESCBS) != 0) - ahc_outb(ahc, SCB_NEXT, i+1); - else - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Make the tag number invalid */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - } - - /* Make sure that the last SCB terminates the free list */ - ahc_outb(ahc, SCBPTR, i-1); - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Ensure we clear the 0 SCB's control byte. */ - ahc_outb(ahc, SCBPTR, 0); - ahc_outb(ahc, SCB_CONTROL, 0); -} - -static int -ahc_init_scbdata(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - - scb_data = ahc->scb_data; - SLIST_INIT(&scb_data->free_scbs); - SLIST_INIT(&scb_data->sg_maps); - - /* Allocate SCB resources */ - scb_data->scbarray = - (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, - M_DEVBUF, M_NOWAIT); - if (scb_data->scbarray == NULL) - return (ENOMEM); - memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC); - - /* Determine the number of hardware SCBs and initialize them */ - - scb_data->maxhscbs = ahc_probe_scbs(ahc); - if ((ahc->flags & AHC_PAGESCBS) != 0) { - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); - } else { - ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); - } - - if (ahc->scb_data->maxhscbs == 0) { - printf("%s: No SCB space found\n", ahc_name(ahc)); - return (ENXIO); - } - - ahc_build_free_scb_list(ahc); - - /* - * Create our DMA tags. These tags define the kinds of device - * accessible memory allocations and memory mappings we will - * need to perform during normal operation. - * - * Unless we need to further restrict the allocation, we rely - * on the restrictions of the parent dmat, hence the common - * use of MAXADDR and MAXSIZE. - */ - - /* DMA tag for our hardware scb structures */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->hscb_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Allocation for our hscbs */ - if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat, - (void **)&scb_data->hscbs, - BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, - scb_data->hscbs, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), - ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); - - scb_data->init_level++; - - /* DMA tag for our sense buffers */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sense_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Allocate them */ - if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat, - (void **)&scb_data->sense, - BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, - scb_data->sense, - AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), - ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); - - scb_data->init_level++; - - /* DMA tag for our S/G structures. We allocate in page sized chunks */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - PAGE_SIZE, /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sg_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Perform initial CCB allocation */ - memset(scb_data->hscbs, 0, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb)); - ahc_alloc_scbs(ahc); - - if (scb_data->numscbs == 0) { - printf("%s: ahc_init_scbdata - " - "Unable to allocate initial scbs\n", - ahc_name(ahc)); - goto error_exit; - } - - /* - * Tell the sequencer which SCB will be the next one it receives. - */ - ahc->next_queued_scb = ahc_get_scb(ahc); - ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); - - /* - * Note that we were successfull - */ - return (0); - -error_exit: - - return (ENOMEM); -} - -static void -ahc_fini_scbdata(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - - scb_data = ahc->scb_data; - if (scb_data == NULL) - return; - - switch (scb_data->init_level) { - default: - case 7: - { - struct sg_map_node *sg_map; - - while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { - SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); - ahc_dmamap_unload(ahc, scb_data->sg_dmat, - sg_map->sg_dmamap); - ahc_dmamem_free(ahc, scb_data->sg_dmat, - sg_map->sg_vaddr, - sg_map->sg_dmamap); - free(sg_map, M_DEVBUF); - } - ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); - } - case 6: - ahc_dmamap_unload(ahc, scb_data->sense_dmat, - scb_data->sense_dmamap); - case 5: - ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, - scb_data->sense_dmamap); - ahc_dmamap_destroy(ahc, scb_data->sense_dmat, - scb_data->sense_dmamap); - case 4: - ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); - case 3: - ahc_dmamap_unload(ahc, scb_data->hscb_dmat, - scb_data->hscb_dmamap); - case 2: - ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, - scb_data->hscb_dmamap); - ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, - scb_data->hscb_dmamap); - case 1: - ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); - break; - case 0: - break; - } - if (scb_data->scbarray != NULL) - free(scb_data->scbarray, M_DEVBUF); -} - -void -ahc_alloc_scbs(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - struct scb *next_scb; - struct sg_map_node *sg_map; - bus_addr_t physaddr; - struct ahc_dma_seg *segs; - int newcount; - int i; - - scb_data = ahc->scb_data; - if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC) - /* Can't allocate any more */ - return; - - next_scb = &scb_data->scbarray[scb_data->numscbs]; - - sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); - - if (sg_map == NULL) - return; - - /* Allocate S/G space for the next batch of SCBS */ - if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, - (void **)&sg_map->sg_vaddr, - BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { - free(sg_map, M_DEVBUF); - return; - } - - SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - - ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, - sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb, - &sg_map->sg_physaddr, /*flags*/0); - - segs = sg_map->sg_vaddr; - physaddr = sg_map->sg_physaddr; - - newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); - newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); - for (i = 0; i < newcount; i++) { - struct scb_platform_data *pdata; -#ifndef __linux__ - int error; -#endif - pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), - M_DEVBUF, M_NOWAIT); - if (pdata == NULL) - break; - next_scb->platform_data = pdata; - next_scb->sg_map = sg_map; - next_scb->sg_list = segs; - /* - * The sequencer always starts with the second entry. - * The first entry is embedded in the scb. - */ - next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); - next_scb->ahc_softc = ahc; - next_scb->flags = SCB_FREE; -#ifndef __linux__ - error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, - &next_scb->dmamap); - if (error != 0) - break; -#endif - next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; - next_scb->hscb->tag = ahc->scb_data->numscbs; - SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, - next_scb, links.sle); - segs += AHC_NSEG; - physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); - next_scb++; - ahc->scb_data->numscbs++; - } -} - -void -ahc_controller_info(struct ahc_softc *ahc, char *buf) -{ - int len; - - len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]); - buf += len; - if ((ahc->features & AHC_TWIN) != 0) - len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " - "B SCSI Id=%d, primary %c, ", - ahc->our_id, ahc->our_id_b, - (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); - else { - const char *speed; - const char *type; - - speed = ""; - if ((ahc->features & AHC_ULTRA) != 0) { - speed = "Ultra "; - } else if ((ahc->features & AHC_DT) != 0) { - speed = "Ultra160 "; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - speed = "Ultra2 "; - } - if ((ahc->features & AHC_WIDE) != 0) { - type = "Wide"; - } else { - type = "Single"; - } - len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", - speed, type, ahc->channel, ahc->our_id); - } - buf += len; - - if ((ahc->flags & AHC_PAGESCBS) != 0) - sprintf(buf, "%d/%d SCBs", - ahc->scb_data->maxhscbs, AHC_MAX_QUEUE); - else - sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); -} - -/* - * Start the board, ready for normal operation - */ -int -ahc_init(struct ahc_softc *ahc) -{ - int max_targ; - int i; - int term; - u_int scsi_conf; - u_int scsiseq_template; - u_int ultraenb; - u_int discenable; - u_int tagenable; - size_t driver_data_size; - uint32_t physaddr; - -#ifdef AHC_DEBUG_SEQUENCER - ahc->flags |= AHC_SEQUENCER_DEBUG; -#endif - -#ifdef AHC_PRINT_SRAM - printf("Scratch Ram:"); - for (i = 0x20; i < 0x5f; i++) { - if (((i % 8) == 0) && (i != 0)) { - printf ("\n "); - } - printf (" 0x%x", ahc_inb(ahc, i)); - } - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0x70; i < 0x7f; i++) { - if (((i % 8) == 0) && (i != 0)) { - printf ("\n "); - } - printf (" 0x%x", ahc_inb(ahc, i)); - } - } - printf ("\n"); -#endif - max_targ = 15; - - /* - * Assume we have a board at this stage and it has been reset. - */ - if ((ahc->flags & AHC_USEDEFAULTS) != 0) - ahc->our_id = ahc->our_id_b = 7; - - /* - * Default to allowing initiator operations. - */ - ahc->flags |= AHC_INITIATORROLE; - - /* - * Only allow target mode features if this unit has them enabled. - */ - if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) - ahc->features &= ~AHC_TARGETMODE; - -#ifndef __linux__ - /* DMA tag for mapping buffers into device visible space. */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, - /*maxsegsz*/AHC_MAXTRANSFER_SIZE, - /*flags*/BUS_DMA_ALLOCNOW, - &ahc->buffer_dmat) != 0) { - return (ENOMEM); - } -#endif - - ahc->init_level++; - - /* - * DMA tag for our command fifos and other data in system memory - * the card's sequencer must be able to access. For initiator - * roles, we need to allocate space for the the qinfifo and qoutfifo. - * The qinfifo and qoutfifo are composed of 256 1 byte elements. - * When providing for the target mode role, we must additionally - * provide space for the incoming target command fifo and an extra - * byte to deal with a dma bug in some chip versions. - */ - driver_data_size = 2 * 256 * sizeof(uint8_t); - if ((ahc->features & AHC_TARGETMODE) != 0) - driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) - + /*DMA WideOdd Bug Buffer*/1; - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - driver_data_size, - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &ahc->shared_data_dmat) != 0) { - return (ENOMEM); - } - - ahc->init_level++; - - /* Allocation of driver data */ - if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat, - (void **)&ahc->qoutfifo, - BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { - return (ENOMEM); - } - - ahc->init_level++; - - /* And permanently map it in */ - ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, - ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, - &ahc->shared_data_busaddr, /*flags*/0); - - if ((ahc->features & AHC_TARGETMODE) != 0) { - ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; - ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS]; - ahc->dma_bug_buf = ahc->shared_data_busaddr - + driver_data_size - 1; - /* All target command blocks start out invalid. */ - for (i = 0; i < AHC_TMODE_CMDS; i++) - ahc->targetcmds[i].cmd_valid = 0; - ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD); - ahc->tqinfifonext = 1; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; - } - ahc->qinfifo = &ahc->qoutfifo[256]; - - ahc->init_level++; - - /* Allocate SCB data now that buffer_dmat is initialized */ - if (ahc->scb_data->maxhscbs == 0) - if (ahc_init_scbdata(ahc) != 0) - return (ENOMEM); - - /* - * Allocate a tstate to house information for our - * initiator presence on the bus as well as the user - * data for any target mode initiator. - */ - if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate ahc_tmode_tstate. " - "Failing attach\n", ahc_name(ahc)); - return (ENOMEM); - } - - if ((ahc->features & AHC_TWIN) != 0) { - if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate ahc_tmode_tstate. " - "Failing attach\n", ahc_name(ahc)); - return (ENOMEM); - } - } - - ahc_outb(ahc, SEQ_FLAGS, 0); - ahc_outb(ahc, SEQ_FLAGS2, 0); - - if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { - ahc->flags |= AHC_PAGESCBS; - } else { - ahc->flags &= ~AHC_PAGESCBS; - } - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - printf("%s: hardware scb %d bytes; kernel scb %d bytes; " - "ahc_dma %d bytes\n", - ahc_name(ahc), - sizeof(struct hardware_scb), - sizeof(struct scb), - sizeof(struct ahc_dma_seg)); - } -#endif /* AHC_DEBUG */ - - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ - if (ahc->features & AHC_TWIN) { - - /* - * The device is gated to channel B after a chip reset, - * so set those values first - */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; - ahc_outb(ahc, SCSIID, ahc->our_id_b); - scsi_conf = ahc_inb(ahc, SCSICONF + 1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) - ahc->flags |= AHC_RESET_BUS_B; - - /* Select Channel A */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); - else - ahc_outb(ahc, SCSIID, ahc->our_id); - scsi_conf = ahc_inb(ahc, SCSICONF); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime - |ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) - ahc->flags |= AHC_RESET_BUS_A; - - /* - * Look at the information that board initialization or - * the board bios has left us. - */ - ultraenb = 0; - tagenable = ALL_TARGETS_MASK; - - /* Grab the disconnection disable table and invert it for our needs */ - if (ahc->flags & AHC_USEDEFAULTS) { - printf("%s: Host Adapter Bios disabled. Using default SCSI " - "device parameters\n", ahc_name(ahc)); - ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| - AHC_TERM_ENB_A|AHC_TERM_ENB_B; - discenable = ALL_TARGETS_MASK; - if ((ahc->features & AHC_ULTRA) != 0) - ultraenb = ALL_TARGETS_MASK; - } else { - discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) - | ahc_inb(ahc, DISC_DSB)); - if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) - ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) - | ahc_inb(ahc, ULTRA_ENB); - } - - if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) - max_targ = 7; - - for (i = 0; i <= max_targ; i++) { - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int our_id; - u_int target_id; - char channel; - - channel = 'A'; - our_id = ahc->our_id; - target_id = i; - if (i > 7 && (ahc->features & AHC_TWIN) != 0) { - channel = 'B'; - our_id = ahc->our_id_b; - target_id = i % 8; - } - tinfo = ahc_fetch_transinfo(ahc, channel, our_id, - target_id, &tstate); - /* Default to async narrow across the board */ - memset(tinfo, 0, sizeof(*tinfo)); - if (ahc->flags & AHC_USEDEFAULTS) { - if ((ahc->features & AHC_WIDE) != 0) - tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - - /* - * These will be truncated when we determine the - * connection type we have with the target. - */ - tinfo->user.period = ahc_syncrates->period; - tinfo->user.offset = ~0; - } else { - u_int scsirate; - uint16_t mask; - - /* Take the settings leftover in scratch RAM. */ - scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); - mask = (0x01 << i); - if ((ahc->features & AHC_ULTRA2) != 0) { - u_int offset; - u_int maxsync; - - if ((scsirate & SOFS) == 0x0F) { - /* - * Haven't negotiated yet, - * so the format is different. - */ - scsirate = (scsirate & SXFR) >> 4 - | (ultraenb & mask) - ? 0x08 : 0x0 - | (scsirate & WIDEXFER); - offset = MAX_OFFSET_ULTRA2; - } else - offset = ahc_inb(ahc, TARG_OFFSET + i); - if ((scsirate & ~WIDEXFER) == 0 && offset != 0) - /* Set to the lowest sync rate, 5MHz */ - scsirate |= 0x1c; - maxsync = AHC_SYNCRATE_ULTRA2; - if ((ahc->features & AHC_DT) != 0) - maxsync = AHC_SYNCRATE_DT; - tinfo->user.period = - ahc_find_period(ahc, scsirate, maxsync); - if (offset == 0) - tinfo->user.period = 0; - else - tinfo->user.offset = ~0; - if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ - && (ahc->features & AHC_DT) != 0) - tinfo->user.ppr_options = - MSG_EXT_PPR_DT_REQ; - } else if ((scsirate & SOFS) != 0) { - if ((scsirate & SXFR) == 0x40 - && (ultraenb & mask) != 0) { - /* Treat 10MHz as a non-ultra speed */ - scsirate &= ~SXFR; - ultraenb &= ~mask; - } - tinfo->user.period = - ahc_find_period(ahc, scsirate, - (ultraenb & mask) - ? AHC_SYNCRATE_ULTRA - : AHC_SYNCRATE_FAST); - if (tinfo->user.period != 0) - tinfo->user.offset = ~0; - } - if (tinfo->user.period == 0) - tinfo->user.offset = 0; - if ((scsirate & WIDEXFER) != 0 - && (ahc->features & AHC_WIDE) != 0) - tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - tinfo->user.protocol_version = 4; - if ((ahc->features & AHC_DT) != 0) - tinfo->user.transport_version = 3; - else - tinfo->user.transport_version = 2; - tinfo->goal.protocol_version = 2; - tinfo->goal.transport_version = 2; - tinfo->curr.protocol_version = 2; - tinfo->curr.transport_version = 2; - } - tstate->ultraenb = ultraenb; - } - ahc->user_discenable = discenable; - ahc->user_tagenable = tagenable; - - /* There are no untagged SCBs active yet. */ - for (i = 0; i < 16; i++) { - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); - if ((ahc->flags & AHC_SCB_BTT) != 0) { - int lun; - - /* - * The SCB based BTT allows an entry per - * target and lun pair. - */ - for (lun = 1; lun < AHC_NUM_LUNS; lun++) - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); - } - } - - /* All of our queues are empty */ - for (i = 0; i < 256; i++) - ahc->qoutfifo[i] = SCB_LIST_NULL; - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD); - - for (i = 0; i < 256; i++) - ahc->qinfifo[i] = SCB_LIST_NULL; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - ahc_outb(ahc, TARGID, 0); - ahc_outb(ahc, TARGID + 1, 0); - } - - /* - * Tell the sequencer where it can find our arrays in memory. - */ - physaddr = ahc->scb_data->hscb_busaddr; - ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); - - physaddr = ahc->shared_data_busaddr; - ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); - - /* - * Initialize the group code to command length table. - * This overrides the values in TARG_SCSIRATE, so only - * setup the table after we have processed that information. - */ - ahc_outb(ahc, CMDSIZE_TABLE, 5); - ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); - ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); - ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); - - /* Tell the sequencer of our initial queue positions */ - ahc_outb(ahc, KERNEL_QINPOS, 0); - ahc_outb(ahc, QINPOS, 0); - ahc_outb(ahc, QOUTPOS, 0); - - /* - * Use the built in queue management registers - * if they are available. - */ - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); - ahc_outb(ahc, SDSCB_QOFF, 0); - ahc_outb(ahc, SNSCB_QOFF, 0); - ahc_outb(ahc, HNSCB_QOFF, 0); - } - - - /* We don't have any waiting selections */ - ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); - - /* Our disconnection list is empty too */ - ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); - - /* Message out buffer starts empty */ - ahc_outb(ahc, MSG_OUT, MSG_NOOP); - - /* - * Setup the allowed SCSI Sequences based on operational mode. - * If we are a target, we'll enalbe select in operations once - * we've had a lun enabled. - */ - scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; - if ((ahc->flags & AHC_INITIATORROLE) != 0) - scsiseq_template |= ENRSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); - - /* - * Load the Sequencer program and Enable the adapter - * in "fast" mode. - */ - if (bootverbose) - printf("%s: Downloading Sequencer Program...", - ahc_name(ahc)); - - ahc_loadseq(ahc); - - if ((ahc->features & AHC_ULTRA2) != 0) { - int wait; - - /* - * Wait for up to 500ms for our transceivers - * to settle. If the adapter does not have - * a cable attached, the tranceivers may - * never settle, so don't complain if we - * fail here. - */ - ahc_pause(ahc); - for (wait = 5000; - (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; - wait--) - ahc_delay(100); - ahc_unpause(ahc); - } - return (0); -} - -void -ahc_intr_enable(struct ahc_softc *ahc, int enable) -{ - u_int hcntrl; - - hcntrl = ahc_inb(ahc, HCNTRL); - hcntrl &= ~INTEN; - ahc->pause &= ~INTEN; - ahc->unpause &= ~INTEN; - if (enable) { - hcntrl |= INTEN; - ahc->pause |= INTEN; - ahc->unpause |= INTEN; - } - ahc_outb(ahc, HCNTRL, hcntrl); -} - -/* - * Ensure that the card is paused in a location - * outside of all critical sections and that all - * pending work is completed prior to returning. - * This routine should only be called from outside - * an interrupt context. - */ -void -ahc_pause_and_flushwork(struct ahc_softc *ahc) -{ - int intstat; - int maxloops; - - maxloops = 1000; - ahc->flags |= AHC_ALL_INTERRUPTS; - intstat = 0; - do { - ahc_intr(ahc); - ahc_pause(ahc); - ahc_clear_critical_section(ahc); - if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) - break; - maxloops--; - } while (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) && --maxloops); - if (maxloops == 0) { - printf("Infinite interrupt loop, INTSTAT = %x", - ahc_inb(ahc, INTSTAT)); - } - ahc_platform_flushwork(ahc); - ahc->flags &= ~AHC_ALL_INTERRUPTS; -} - -int -ahc_suspend(struct ahc_softc *ahc) -{ - uint8_t *ptr; - int i; - - ahc_pause_and_flushwork(ahc); - - if (LIST_FIRST(&ahc->pending_scbs) != NULL) - return (EBUSY); - -#if AHC_TARGET_MODE - /* - * XXX What about ATIOs that have not yet been serviced? - * Perhaps we should just refuse to be suspended if we - * are acting in a target role. - */ - if (ahc->pending_device != NULL) - return (EBUSY); -#endif - - /* Save volatile registers */ - if ((ahc->features & AHC_TWIN) != 0) { - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ); - ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0); - ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1); - ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER); - ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL); - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ); - ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0); - ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1); - ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER); - ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL); - - if ((ahc->chip & AHC_PCI) != 0) { - ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0); - ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS); - } - - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE); - ahc_outb(ahc, SFUNCT, sfunct); - ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1); - } - - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH); - - ptr = ahc->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - *ptr++ = ahc_inb(ahc, SRAM_BASE + i); - - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - *ptr++ = ahc_inb(ahc, TARG_OFFSET + i); - } - - ptr = ahc->suspend_state.btt; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - for (i = 0;i < AHC_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHC_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - *ptr = ahc_index_busy_tcl(ahc, tcl); - } - } - } - ahc_shutdown(ahc); - return (0); -} - -int -ahc_resume(struct ahc_softc *ahc) -{ - uint8_t *ptr; - int i; - - ahc_reset(ahc); - - ahc_build_free_scb_list(ahc); - - /* Restore volatile registers */ - if ((ahc->features & AHC_TWIN) != 0) { - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - ahc_outb(ahc, SCSIID, ahc->our_id); - ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq); - ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0); - ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1); - ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0); - ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1); - ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer); - ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl); - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq); - ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0); - ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1); - ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0); - ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1); - ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer); - ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); - else - ahc_outb(ahc, SCSIID, ahc->our_id); - - if ((ahc->chip & AHC_PCI) != 0) { - ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0); - ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus); - } - - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode); - ahc_outb(ahc, SFUNCT, sfunct); - ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1); - } - - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh); - - ptr = ahc->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - ahc_outb(ahc, SRAM_BASE + i, *ptr++); - - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - ahc_outb(ahc, TARG_OFFSET + i, *ptr++); - } - - ptr = ahc->suspend_state.btt; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - for (i = 0;i < AHC_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHC_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - ahc_busy_tcl(ahc, tcl, *ptr); - } - } - } - return (0); -} - -/************************** Busy Target Table *********************************/ -/* - * Return the untagged transaction id for a given target/channel lun. - * Optionally, clear the entry. - */ -u_int -ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl) -{ - u_int scbid; - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl)); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset); - } - - return (scbid); -} - -void -ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl) -{ - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL); - } -} - -void -ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid) -{ - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid); - } -} - -/************************** SCB and SCB queue management **********************/ -int -ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target, - char channel, int lun, u_int tag, role_t role) -{ - int targ = SCB_GET_TARGET(ahc, scb); - char chan = SCB_GET_CHANNEL(ahc, scb); - int slun = SCB_GET_LUN(scb); - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); - if (match != 0) - match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); - if (match != 0) { -#if AHC_TARGET_MODE - int group; - - group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); - if (role == ROLE_INITIATOR) { - match = (group != XPT_FC_GROUP_TMODE) - && ((tag == scb->hscb->tag) - || (tag == SCB_LIST_NULL)); - } else if (role == ROLE_TARGET) { - match = (group == XPT_FC_GROUP_TMODE) - && ((tag == scb->io_ctx->csio.tag_id) - || (tag == SCB_LIST_NULL)); - } -#else /* !AHC_TARGET_MODE */ - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); -#endif /* AHC_TARGET_MODE */ - } - - return match; -} - -void -ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb) -{ - int target; - char channel; - int lun; - - target = SCB_GET_TARGET(ahc, scb); - lun = SCB_GET_LUN(scb); - channel = SCB_GET_CHANNEL(ahc, scb); - - ahc_search_qinfifo(ahc, target, channel, lun, - /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - ahc_platform_freeze_devq(ahc, scb); -} - -void -ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb) -{ - struct scb *prev_scb; - - prev_scb = NULL; - if (ahc_qinfifo_count(ahc) != 0) { - u_int prev_tag; - uint8_t prev_pos; - - prev_pos = ahc->qinfifonext - 1; - prev_tag = ahc->qinfifo[prev_pos]; - prev_scb = ahc_lookup_scb(ahc, prev_tag); - } - ahc_qinfifo_requeue(ahc, prev_scb, scb); - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - } -} - -static void -ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, - struct scb *scb) -{ - if (prev_scb == NULL) { - ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); - } else { - prev_scb->hscb->next = scb->hscb->tag; - ahc_sync_scb(ahc, prev_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - } - ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; - scb->hscb->next = ahc->next_queued_scb->hscb->tag; - ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); -} - -static int -ahc_qinfifo_count(struct ahc_softc *ahc) -{ - u_int8_t qinpos; - u_int8_t diff; - - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - qinpos = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinpos); - } else - qinpos = ahc_inb(ahc, QINPOS); - diff = ahc->qinfifonext - qinpos; - return (diff); -} - -int -ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status, - ahc_search_action action) -{ - struct scb *scb; - struct scb *prev_scb; - uint8_t qinstart; - uint8_t qinpos; - uint8_t qintail; - uint8_t next, prev; - uint8_t curscbptr; - int found; - int maxtarget; - int i; - int have_qregs; - - qintail = ahc->qinfifonext; - have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0; - if (have_qregs) { - qinstart = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinstart); - } else - qinstart = ahc_inb(ahc, QINPOS); - qinpos = qinstart; - next = ahc_inb(ahc, NEXT_QUEUED_SCB); - found = 0; - prev_scb = NULL; - - if (action == SEARCH_COMPLETE) { - /* - * Don't attempt to run any queued untagged transactions - * until we are done with the abort process. - */ - ahc_freeze_untagged_queues(ahc); - } - - /* - * Start with an empty queue. Entries that are not chosen - * for removal will be re-added to the queue as we go. - */ - ahc->qinfifonext = qinpos; - ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); - - while (qinpos != qintail) { - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]); - if (scb == NULL) { - printf("qinpos = %d, SCB index = %d\n", - qinpos, ahc->qinfifo[qinpos]); - panic("Loop 1\n"); - } - - if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, - status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in qinfifo\n"); - ahc_done(ahc, scb); - - /* FALLTHROUGH */ - case SEARCH_REMOVE: - break; - } - case SEARCH_COUNT: - ahc_qinfifo_requeue(ahc, prev_scb, scb); - prev_scb = scb; - break; - } - } else { - ahc_qinfifo_requeue(ahc, prev_scb, scb); - prev_scb = scb; - } - qinpos++; - } - - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - } - - if (action != SEARCH_COUNT - && (found != 0) - && (qinstart != ahc->qinfifonext)) { - /* - * The sequencer may be in the process of dmaing - * down the SCB at the beginning of the queue. - * This could be problematic if either the first, - * or the second SCB is removed from the queue - * (the first SCB includes a pointer to the "next" - * SCB to dma). If we have removed any entries, swap - * the first element in the queue with the next HSCB - * so the sequencer will notice that NEXT_QUEUED_SCB - * has changed during its dma attempt and will retry - * the DMA. - */ - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]); - - if (scb == NULL) { - printf("found = %d, qinstart = %d, qinfifionext = %d\n", - found, qinstart, ahc->qinfifonext); - panic("First/Second Qinfifo fixup\n"); - } - /* - * ahc_swap_with_next_hscb forces our next pointer to - * point to the reserved SCB for future commands. Save - * and restore our original next pointer to maintain - * queue integrity. - */ - next = scb->hscb->next; - ahc->scb_data->scbindex[scb->hscb->tag] = NULL; - ahc_swap_with_next_hscb(ahc, scb); - scb->hscb->next = next; - ahc->qinfifo[qinstart] = scb->hscb->tag; - - /* Tell the card about the new head of the qinfifo. */ - ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); - - /* Fixup the tail "next" pointer. */ - qintail = ahc->qinfifonext - 1; - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]); - scb->hscb->next = ahc->next_queued_scb->hscb->tag; - } - - /* - * Search waiting for selection list. - */ - curscbptr = ahc_inb(ahc, SCBPTR); - next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - uint8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - printf("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - ahc_dump_card_state(ahc); - panic("for safety"); - } - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("scb_index = %d, next = %d\n", - scb_index, next); - panic("Waiting List traversal\n"); - } - if (ahc_match_scb(ahc, scb, target, channel, - lun, SCB_LIST_NULL, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, - status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in Waiting List\n"); - ahc_done(ahc, scb); - /* FALLTHROUGH */ - } - case SEARCH_REMOVE: - next = ahc_rem_wscb(ahc, next, prev); - break; - case SEARCH_COUNT: - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - break; - } - } else { - - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - ahc_outb(ahc, SCBPTR, curscbptr); - - /* - * And lastly, the untagged holding queues. - */ - i = 0; - if ((ahc->flags & AHC_SCB_BTT) == 0) { - - maxtarget = 16; - if (target != CAM_TARGET_WILDCARD) { - - i = target; - if (channel == 'B') - i += 8; - maxtarget = i + 1; - } - } else { - maxtarget = 0; - } - - for (; i < maxtarget; i++) { - struct scb_tailq *untagged_q; - struct scb *next_scb; - - untagged_q = &(ahc->untagged_queues[i]); - next_scb = TAILQ_FIRST(untagged_q); - while (next_scb != NULL) { - - scb = next_scb; - next_scb = TAILQ_NEXT(scb, links.tqe); - - /* - * The head of the list may be the currently - * active untagged command for a device. - * We're only searching for commands that - * have not been started. A transaction - * marked active but still in the qinfifo - * is removed by the qinfifo scanning code - * above. - */ - if ((scb->flags & SCB_ACTIVE) != 0) - continue; - - if (ahc_match_scb(ahc, scb, target, channel, - lun, SCB_LIST_NULL, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, - status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in untaggedQ\n"); - ahc_done(ahc, scb); - break; - } - case SEARCH_REMOVE: - TAILQ_REMOVE(untagged_q, scb, - links.tqe); - break; - case SEARCH_COUNT: - break; - } - } - } - } - - if (action == SEARCH_COMPLETE) - ahc_release_untagged_queues(ahc); - return (found); -} - -int -ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, int stop_on_first, int remove, - int save_state) -{ - struct scb *scbp; - u_int next; - u_int prev; - u_int count; - u_int active_scb; - - count = 0; - next = ahc_inb(ahc, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - - if (save_state) { - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - } else - /* Silence compiler */ - active_scb = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - printf("Disconnected List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - ahc_dump_card_state(ahc); - panic("for safety"); - } - - if (next == prev) { - panic("Disconnected List Loop. " - "cur SCBPTR == %x, prev SCBPTR == %x.", - next, prev); - } - scbp = ahc_lookup_scb(ahc, scb_index); - if (ahc_match_scb(ahc, scbp, target, channel, lun, - tag, ROLE_INITIATOR)) { - count++; - if (remove) { - next = - ahc_rem_scb_from_disc_list(ahc, prev, next); - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - if (stop_on_first) - break; - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - if (save_state) - ahc_outb(ahc, SCBPTR, active_scb); - return (count); -} - -/* - * Remove an SCB from the on chip list of disconnected transactions. - * This is empty/unused if we are not performing SCB paging. - */ -static u_int -ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr) -{ - u_int next; - - ahc_outb(ahc, SCBPTR, scbptr); - next = ahc_inb(ahc, SCB_NEXT); - - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - if (prev != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } else - ahc_outb(ahc, DISCONNECTED_SCBH, next); - - return (next); -} - -/* - * Add the SCB as selected by SCBPTR onto the on chip list of - * free hardware SCBs. This list is empty/unused if we are not - * performing SCB paging. - */ -static void -ahc_add_curscb_to_free_list(struct ahc_softc *ahc) -{ - /* - * Invalidate the tag so that our abort - * routines don't think it's active. - */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - if ((ahc->flags & AHC_PAGESCBS) != 0) { - ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); - ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); - } -} - -/* - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - */ -static u_int -ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) -{ - u_int curscb, next; - - /* - * Select the SCB we want to abort and - * pull the next pointer out of it. - */ - curscb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, scbpos); - next = ahc_inb(ahc, SCB_NEXT); - - /* Clear the necessary fields */ - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - /* update the waiting list */ - if (prev == SCB_LIST_NULL) { - /* First in the list */ - ahc_outb(ahc, WAITING_SCBH, next); - - /* - * Ensure we aren't attempting to perform - * selection for this entry. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else { - /* - * Select the scb that pointed to us - * and update its next pointer. - */ - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } - - /* - * Point us back at the original scb position. - */ - ahc_outb(ahc, SCBPTR, curscb); - return next; -} - -/******************************** Error Handling ******************************/ -/* - * Abort all SCBs that match the given description (target/channel/lun/tag), - * setting their status to the passed in status if the status has not already - * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer - * is paused before it is called. - */ -int -ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - struct scb *scbp; - struct scb *scbp_next; - u_int active_scb; - int i, j; - int maxtarget; - int minlun; - int maxlun; - - int found; - - /* - * Don't attempt to run any queued untagged transactions - * until we are done with the abort process. - */ - ahc_freeze_untagged_queues(ahc); - - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - - found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, - role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - /* - * Clean out the busy target table for any untagged commands. - */ - i = 0; - maxtarget = 16; - if (target != CAM_TARGET_WILDCARD) { - i = target; - if (channel == 'B') - i += 8; - maxtarget = i + 1; - } - - if (lun == CAM_LUN_WILDCARD) { - - /* - * Unless we are using an SCB based - * busy targets table, there is only - * one table entry for all luns of - * a target. - */ - minlun = 0; - maxlun = 1; - if ((ahc->flags & AHC_SCB_BTT) != 0) - maxlun = AHC_NUM_LUNS; - } else { - minlun = lun; - maxlun = lun + 1; - } - - if (role != ROLE_TARGET) { - for (;i < maxtarget; i++) { - for (j = minlun;j < maxlun; j++) { - u_int scbid; - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - scbid = ahc_index_busy_tcl(ahc, tcl); - scbp = ahc_lookup_scb(ahc, scbid); - if (scbp == NULL - || ahc_match_scb(ahc, scbp, target, channel, - lun, tag, role) == 0) - continue; - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); - } - } - - /* - * Go through the disconnected list and remove any entries we - * have queued for completion, 0'ing their control byte too. - * We save the active SCB and restore it ourselves, so there - * is no reason for this search to restore it too. - */ - ahc_search_disc_list(ahc, target, channel, lun, tag, - /*stop_on_first*/FALSE, /*remove*/TRUE, - /*save_state*/FALSE); - } - - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. In some cases, these remnants - * might not still have mappings in the scbindex array (e.g. unexpected - * bus free with the same scb queued for an abort). Don't hold this - * against them. - */ - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - u_int scbid; - - ahc_outb(ahc, SCBPTR, i); - scbid = ahc_inb(ahc, SCB_TAG); - scbp = ahc_lookup_scb(ahc, scbid); - if ((scbp == NULL && scbid != SCB_LIST_NULL) - || (scbp != NULL - && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))) - ahc_add_curscb_to_free_list(ahc); - } - - /* - * Go through the pending CCB list and look for - * commands for this target that are still active. - * These are other tagged commands that were - * disconnected when the reset occurred. - */ - scbp_next = LIST_FIRST(&ahc->pending_scbs); - while (scbp_next != NULL) { - scbp = scbp_next; - scbp_next = LIST_NEXT(scbp, pending_links); - if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { - cam_status ostat; - - ostat = ahc_get_transaction_status(scbp); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scbp, status); - if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) - ahc_freeze_scb(scbp); - if ((scbp->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB on pending list\n"); - ahc_done(ahc, scbp); - found++; - } - } - ahc_outb(ahc, SCBPTR, active_scb); - ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status); - ahc_release_untagged_queues(ahc); - return found; -} - -static void -ahc_reset_current_bus(struct ahc_softc *ahc) -{ - uint8_t scsiseq; - - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); - scsiseq = ahc_inb(ahc, SCSISEQ); - ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); - ahc_delay(AHC_BUSRESET_DELAY); - /* Turn off the bus reset */ - ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); - - ahc_clear_intstat(ahc); - - /* Re-enable reset interrupts */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); -} - -int -ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) -{ - struct ahc_devinfo devinfo; - u_int initiator, target, max_scsiid; - u_int sblkctl; - u_int scsiseq; - u_int simode1; - int found; - int restart_needed; - char cur_channel; - - ahc->pending_device = NULL; - - ahc_compile_devinfo(&devinfo, - CAM_TARGET_WILDCARD, - CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - ahc_pause(ahc); - - /* Make sure the sequencer is in a safe location. */ - ahc_clear_critical_section(ahc); - - /* - * Run our command complete fifos to ensure that we perform - * completion processing on any commands that 'completed' - * before the reset occurred. - */ - ahc_run_qoutfifo(ahc); -#if AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETROLE) != 0) { - ahc_run_tqinfifo(ahc, /*paused*/TRUE); - } -#endif - - /* - * Reset the bus if we are initiating this reset - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = 'A'; - if ((ahc->features & AHC_TWIN) != 0 - && ((sblkctl & SELBUSB) != 0)) - cur_channel = 'B'; - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - if (cur_channel != channel) { - /* Case 1: Command for another bus is active - * Stealthily reset the other bus without - * upsetting the current bus. - */ - ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); - simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); -#if AHC_TARGET_MODE - /* - * Bus resets clear ENSELI, so we cannot - * defer re-enabling bus reset interrupts - * if we are in target mode. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) - ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); -#endif - ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); - ahc_outb(ahc, SBLKCTL, sblkctl); - restart_needed = FALSE; - } else { - /* Case 2: A command from this bus is active or we're idle */ - ahc_clear_msg_state(ahc); - simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); -#if AHC_TARGET_MODE - /* - * Bus resets clear ENSELI, so we cannot - * defer re-enabling bus reset interrupts - * if we are in target mode. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) - ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); -#endif - ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); - restart_needed = TRUE; - } - - /* - * Clean up all the state information for the - * pending transactions on this bus. - */ - found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); - - max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7; - -#ifdef AHC_TARGET_MODE - /* - * Send an immediate notify ccb to all target more peripheral - * drivers affected by this action. - */ - for (target = 0; target <= max_scsiid; target++) { - struct ahc_tmode_tstate* tstate; - u_int lun; - - tstate = ahc->enabled_targets[target]; - if (tstate == NULL) - continue; - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[lun]; - if (lstate == NULL) - continue; - - ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD, - EVENT_TYPE_BUS_RESET, /*arg*/0); - ahc_send_lstate_events(ahc, lstate); - } - } -#endif - /* Notify the XPT that a bus reset occurred */ - ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); - - /* - * Revert to async/narrow transfers until we renegotiate. - */ - for (target = 0; target <= max_scsiid; target++) { - - if (ahc->enabled_targets[target] == NULL) - continue; - for (initiator = 0; initiator <= max_scsiid; initiator++) { - struct ahc_devinfo devinfo; - - ahc_compile_devinfo(&devinfo, target, initiator, - CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR, /*paused*/TRUE); - ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, - /*period*/0, /*offset*/0, - /*ppr_options*/0, AHC_TRANS_CUR, - /*paused*/TRUE); - } - } - - if (restart_needed) - ahc_restart(ahc); - else - ahc_unpause(ahc); - return found; -} - - -/***************************** Residual Processing ****************************/ -/* - * Calculate the residual for a just completed SCB. - */ -void -ahc_calc_residual(struct scb *scb) -{ - struct hardware_scb *hscb; - struct status_pkt *spkt; - uint32_t sgptr; - uint32_t resid_sgptr; - uint32_t resid; - - /* - * 5 cases. - * 1) No residual. - * SG_RESID_VALID clear in sgptr. - * 2) Transferless command - * 3) Never performed any transfers. - * sgptr has SG_FULL_RESID set. - * 4) No residual but target did not - * save data pointers after the - * last transfer, so sgptr was - * never updated. - * 5) We have a partial residual. - * Use residual_sgptr to determine - * where we are. - */ - - hscb = scb->hscb; - sgptr = ahc_le32toh(hscb->sgptr); - if ((sgptr & SG_RESID_VALID) == 0) - /* Case 1 */ - return; - sgptr &= ~SG_RESID_VALID; - - if ((sgptr & SG_LIST_NULL) != 0) - /* Case 2 */ - return; - - spkt = &hscb->shared_data.status; - resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); - if ((sgptr & SG_FULL_RESID) != 0) { - /* Case 3 */ - resid = ahc_get_transfer_length(scb); - } else if ((resid_sgptr & SG_LIST_NULL) != 0) { - /* Case 4 */ - return; - } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { - panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); - } else { - struct ahc_dma_seg *sg; - - /* - * Remainder of the SG where the transfer - * stopped. - */ - resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; - sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - /* - * Add up the contents of all residual - * SG segments that are after the SG where - * the transfer stopped. - */ - while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { - sg++; - resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; - } - } - if ((scb->flags & SCB_SENSE) == 0) - ahc_set_residual(scb, resid); - else - ahc_set_sense_residual(scb, resid); - -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOWMISC) != 0) { - ahc_print_path(ahc, scb); - printf("Handled Residual of %d bytes\n", resid); - } -#endif -} - -/******************************* Target Mode **********************************/ -#ifdef AHC_TARGET_MODE -/* - * Add a target mode event to this lun's queue - */ -static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, - u_int initiator_id, u_int event_type, u_int event_arg) -{ - struct ahc_tmode_event *event; - int pending; - - xpt_freeze_devq(lstate->path, /*count*/1); - if (lstate->event_w_idx >= lstate->event_r_idx) - pending = lstate->event_w_idx - lstate->event_r_idx; - else - pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1 - - (lstate->event_r_idx - lstate->event_w_idx); - - if (event_type == EVENT_TYPE_BUS_RESET - || event_type == MSG_BUS_DEV_RESET) { - /* - * Any earlier events are irrelevant, so reset our buffer. - * This has the effect of allowing us to deal with reset - * floods (an external device holding down the reset line) - * without losing the event that is really interesting. - */ - lstate->event_r_idx = 0; - lstate->event_w_idx = 0; - xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); - } - - if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) { - xpt_print_path(lstate->path); - printf("immediate event %x:%x lost\n", - lstate->event_buffer[lstate->event_r_idx].event_type, - lstate->event_buffer[lstate->event_r_idx].event_arg); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); - } - - event = &lstate->event_buffer[lstate->event_w_idx]; - event->initiator_id = initiator_id; - event->event_type = event_type; - event->event_arg = event_arg; - lstate->event_w_idx++; - if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_w_idx = 0; -} - -/* - * Send any target mode events queued up waiting - * for immediate notify resources. - */ -void -ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) -{ - struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; - - while (lstate->event_r_idx != lstate->event_w_idx - && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { - struct ahc_tmode_event *event; - - event = &lstate->event_buffer[lstate->event_r_idx]; - SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); - inot = (struct ccb_immed_notify *)ccbh; - switch (event->event_type) { - case EVENT_TYPE_BUS_RESET: - ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; - break; - default: - ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; - inot->message_args[0] = event->event_type; - inot->message_args[1] = event->event_arg; - break; - } - inot->initiator_id = event->initiator_id; - inot->sense_len = 0; - xpt_done((union ccb *)inot); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - } -} -#endif - -/******************** Sequencer Program Patching/Download *********************/ - -#ifdef AHC_DUMP_SEQ -void -ahc_dumpseq(struct ahc_softc* ahc) -{ - int i; - int max_prog; - - if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI) - max_prog = 448; - else if ((ahc->features & AHC_ULTRA2) != 0) - max_prog = 768; - else - max_prog = 512; - - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - for (i = 0; i < max_prog; i++) { - uint8_t ins_bytes[4]; - - ahc_insb(ahc, SEQRAM, ins_bytes, 4); - printf("0x%08x\n", ins_bytes[0] << 24 - | ins_bytes[1] << 16 - | ins_bytes[2] << 8 - | ins_bytes[3]); - } -} -#endif - -static void -ahc_loadseq(struct ahc_softc *ahc) -{ - struct cs cs_table[num_critical_sections]; - u_int begin_set[num_critical_sections]; - u_int end_set[num_critical_sections]; - struct patch *cur_patch; - u_int cs_count; - u_int cur_cs; - u_int i; - int downloaded; - u_int skip_addr; - u_int sg_prefetch_cnt; - uint8_t download_consts[7]; - - /* - * Start out with 0 critical sections - * that apply to this firmware load. - */ - cs_count = 0; - cur_cs = 0; - memset(begin_set, 0, sizeof(begin_set)); - memset(end_set, 0, sizeof(end_set)); - - /* Setup downloadable constant table */ - download_consts[QOUTFIFO_OFFSET] = 0; - if (ahc->targetcmds != NULL) - download_consts[QOUTFIFO_OFFSET] += 32; - download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1; - download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1; - download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1); - sg_prefetch_cnt = ahc->pci_cachesize; - if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg))) - sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg); - download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; - download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1); - download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1); - - cur_patch = patches; - downloaded = 0; - skip_addr = 0; - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - - for (i = 0; i < sizeof(seqprog)/4; i++) { - if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) { - /* - * Don't download this instruction as it - * is in a patch that was removed. - */ - continue; - } - /* - * Move through the CS table until we find a CS - * that might apply to this instruction. - */ - for (; cur_cs < num_critical_sections; cur_cs++) { - if (critical_sections[cur_cs].end <= i) { - if (begin_set[cs_count] == TRUE - && end_set[cs_count] == FALSE) { - cs_table[cs_count].end = downloaded; - end_set[cs_count] = TRUE; - cs_count++; - } - continue; - } - if (critical_sections[cur_cs].begin <= i - && begin_set[cs_count] == FALSE) { - cs_table[cs_count].begin = downloaded; - begin_set[cs_count] = TRUE; - } - break; - } - ahc_download_instr(ahc, i, download_consts); - downloaded++; - } - - ahc->num_critical_sections = cs_count; - if (cs_count != 0) { - - cs_count *= sizeof(struct cs); - ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); - if (ahc->critical_sections == NULL) - panic("ahc_loadseq: Could not malloc"); - memcpy(ahc->critical_sections, cs_table, cs_count); - } - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - ahc_restart(ahc); - - if (bootverbose) - printf(" %d instructions downloaded\n", downloaded); -} - -static int -ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, - u_int start_instr, u_int *skip_addr) -{ - struct patch *cur_patch; - struct patch *last_patch; - u_int num_patches; - - num_patches = sizeof(patches)/sizeof(struct patch); - last_patch = &patches[num_patches]; - cur_patch = *start_patch; - - while (cur_patch < last_patch && start_instr == cur_patch->begin) { - - if (cur_patch->patch_func(ahc) == 0) { - - /* Start rejecting code */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } else { - /* Accepted this patch. Advance to the next - * one and wait for our intruction pointer to - * hit this point. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* Still skipping */ - return (0); - - return (1); -} - -static void -ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - u_int opcode; - - /* - * The firmware is always compiled into a little endian format. - */ - instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - struct patch *cur_patch; - int address_offset; - u_int address; - u_int skip_addr; - u_int i; - - fmt3_ins = &instr.format3; - address_offset = 0; - address = fmt3_ins->address; - cur_patch = patches; - skip_addr = 0; - - for (i = 0; i < address;) { - - ahc_check_patch(ahc, &cur_patch, i, &skip_addr); - - if (skip_addr > i) { - int end_addr; - - end_addr = MIN(address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } else { - i++; - } - } - address -= address_offset; - fmt3_ins->address = address; - /* FALLTHROUGH */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - if ((ahc->features & AHC_CMD_CHAN) == 0 - && opcode == AIC_OP_BMOV) { - /* - * Block move was added at the same time - * as the command channel. Verify that - * this is only a move of a single element - * and convert the BMOV to a MOV - * (AND with an immediate of FF). - */ - if (fmt1_ins->immediate != 1) - panic("%s: BMOV not supported\n", - ahc_name(ahc)); - fmt1_ins->opcode = AIC_OP_AND; - fmt1_ins->immediate = 0xff; - } - /* FALLTHROUGH */ - case AIC_OP_ROL: - if ((ahc->features & AHC_ULTRA2) != 0) { - int i, count; - - /* Calculate odd parity for the instruction */ - for (i = 0, count = 0; i < 31; i++) { - uint32_t mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if ((count & 0x01) == 0) - instr.format1.parity = 1; - } else { - /* Compress the instruction for older sequencers */ - if (fmt3_ins != NULL) { - instr.integer = - fmt3_ins->immediate - | (fmt3_ins->source << 8) - | (fmt3_ins->address << 16) - | (fmt3_ins->opcode << 25); - } else { - instr.integer = - fmt1_ins->immediate - | (fmt1_ins->source << 8) - | (fmt1_ins->destination << 16) - | (fmt1_ins->ret << 24) - | (fmt1_ins->opcode << 25); - } - } - /* The sequencer is a little endian cpu */ - instr.integer = ahc_htole32(instr.integer); - ahc_outsb(ahc, SEQRAM, instr.bytes, 4); - break; - default: - panic("Unknown opcode encountered in seq program"); - break; - } -} - -void -ahc_dump_card_state(struct ahc_softc *ahc) -{ - struct scb *scb; - struct scb_tailq *untagged_q; - int target; - int maxtarget; - int i; - uint8_t last_phase; - uint8_t qinpos; - uint8_t qintail; - uint8_t qoutpos; - uint8_t scb_index; - uint8_t saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - - last_phase = ahc_inb(ahc, LASTPHASE); - printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", - ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", - ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX), - ahc_inb(ahc, ARG_2)); - printf("HCNT = 0x%x\n", ahc_inb(ahc, HCNT)); - printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); - printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", - ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); - printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", - last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); - printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", - ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); - if ((ahc->features & AHC_DT) != 0) - printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); - printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", - ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), - ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), - ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), - ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); - printf("SCB count = %d\n", ahc->scb_data->numscbs); - printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); - printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); - /* QINFIFO */ - printf("QINFIFO entries: "); - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - qinpos = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinpos); - } else - qinpos = ahc_inb(ahc, QINPOS); - qintail = ahc->qinfifonext; - while (qinpos != qintail) { - printf("%d ", ahc->qinfifo[qinpos]); - qinpos++; - } - printf("\n"); - - printf("Waiting Queue entries: "); - scb_index = ahc_inb(ahc, WAITING_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printf("\n"); - - printf("Disconnected Queue entries: "); - scb_index = ahc_inb(ahc, DISCONNECTED_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printf("\n"); - - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); - printf("QOUTFIFO entries: "); - qoutpos = ahc->qoutfifonext; - i = 0; - while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) { - printf("%d ", ahc->qoutfifo[qoutpos]); - qoutpos++; - } - printf("\n"); - - printf("Sequencer Free SCB List: "); - scb_index = ahc_inb(ahc, FREE_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printf("%d ", scb_index); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printf("\n"); - - printf("Pending list: "); - i = 0; - LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { - if (i++ > 256) - break; - if (scb != LIST_FIRST(&ahc->pending_scbs)) - printf(", "); - printf("%d", scb->hscb->tag); - if ((ahc->flags & AHC_PAGESCBS) == 0) { - ahc_outb(ahc, SCBPTR, scb->hscb->tag); - printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL), - ahc_inb(ahc, SCB_TAG)); - } - } - printf("\n"); - - printf("Kernel Free SCB list: "); - i = 0; - SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) { - if (i++ > 256) - break; - printf("%d ", scb->hscb->tag); - } - printf("\n"); - - maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; - for (target = 0; target <= maxtarget; target++) { - untagged_q = &ahc->untagged_queues[target]; - if (TAILQ_FIRST(untagged_q) == NULL) - continue; - printf("Untagged Q(%d): ", target); - i = 0; - TAILQ_FOREACH(scb, untagged_q, links.tqe) { - if (i++ > 256) - break; - printf("%d ", scb->hscb->tag); - } - printf("\n"); - } - - ahc_platform_dump_card_state(ahc); - ahc_outb(ahc, SCBPTR, saved_scbptr); -} - -/************************* Target Mode ****************************************/ -#ifdef AHC_TARGET_MODE -cam_status -ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct ahc_tmode_tstate **tstate, - struct ahc_tmode_lstate **lstate, - int notfound_failure) -{ - - if ((ahc->features & AHC_TARGETMODE) == 0) - return (CAM_REQ_INVALID); - - /* - * Handle the 'black hole' device that sucks up - * requests to unattached luns on enabled targets. - */ - if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD - && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { - *tstate = NULL; - *lstate = ahc->black_hole; - } else { - u_int max_id; - - max_id = (ahc->features & AHC_WIDE) ? 15 : 7; - if (ccb->ccb_h.target_id > max_id) - return (CAM_TID_INVALID); - - if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS) - return (CAM_LUN_INVALID); - - *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; - *lstate = NULL; - if (*tstate != NULL) - *lstate = - (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; - } - - if (notfound_failure != 0 && *lstate == NULL) - return (CAM_PATH_INVALID); - - return (CAM_REQ_CMP); -} - -void -ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) -{ - struct ahc_tmode_tstate *tstate; - struct ahc_tmode_lstate *lstate; - struct ccb_en_lun *cel; - cam_status status; - u_int target; - u_int lun; - u_int target_mask; - u_long s; - char channel; - - status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, - /*notfound_failure*/FALSE); - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - if ((ahc->features & AHC_MULTIROLE) != 0) { - u_int our_id; - - if (cam_sim_bus(sim) == 0) - our_id = ahc->our_id; - else - our_id = ahc->our_id_b; - - if (ccb->ccb_h.target_id != our_id) { - if ((ahc->features & AHC_MULTI_TID) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) { - /* - * Only allow additional targets if - * the initiator role is disabled. - * The hardware cannot handle a re-select-in - * on the initiator id during a re-select-out - * on a different target id. - */ - status = CAM_TID_INVALID; - } else if ((ahc->flags & AHC_INITIATORROLE) != 0 - || ahc->enabled_luns > 0) { - /* - * Only allow our target id to change - * if the initiator role is not configured - * and there are no enabled luns which - * are attached to the currently registered - * scsi id. - */ - status = CAM_TID_INVALID; - } - } - } - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - /* - * We now have an id that is valid. - * If we aren't in target mode, switch modes. - */ - if ((ahc->flags & AHC_TARGETROLE) == 0 - && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - u_long s; - - printf("Configuring Target Mode\n"); - ahc_lock(ahc, &s); - if (LIST_FIRST(&ahc->pending_scbs) != NULL) { - ccb->ccb_h.status = CAM_BUSY; - ahc_unlock(ahc, &s); - return; - } - ahc->flags |= AHC_TARGETROLE; - if ((ahc->features & AHC_MULTIROLE) == 0) - ahc->flags &= ~AHC_INITIATORROLE; - ahc_pause(ahc); - ahc_loadseq(ahc); - ahc_unlock(ahc, &s); - } - cel = &ccb->cel; - target = ccb->ccb_h.target_id; - lun = ccb->ccb_h.target_lun; - channel = SIM_CHANNEL(ahc, sim); - target_mask = 0x01 << target; - if (channel == 'B') - target_mask <<= 8; - - if (cel->enable != 0) { - u_int scsiseq; - - /* Are we already enabled?? */ - if (lstate != NULL) { - xpt_print_path(ccb->ccb_h.path); - printf("Lun already enabled\n"); - ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return; - } - - if (cel->grp6_len != 0 - || cel->grp7_len != 0) { - /* - * Don't (yet?) support vendor - * specific commands. - */ - ccb->ccb_h.status = CAM_REQ_INVALID; - printf("Non-zero Group Codes\n"); - return; - } - - /* - * Seems to be okay. - * Setup our data structures. - */ - if (target != CAM_TARGET_WILDCARD && tstate == NULL) { - tstate = ahc_alloc_tstate(ahc, target, channel); - if (tstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate tstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - } - lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); - if (lstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate lstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - memset(lstate, 0, sizeof(*lstate)); - status = xpt_create_path(&lstate->path, /*periph*/NULL, - xpt_path_path_id(ccb->ccb_h.path), - xpt_path_target_id(ccb->ccb_h.path), - xpt_path_lun_id(ccb->ccb_h.path)); - if (status != CAM_REQ_CMP) { - free(lstate, M_DEVBUF); - xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate path\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - SLIST_INIT(&lstate->accept_tios); - SLIST_INIT(&lstate->immed_notifies); - ahc_lock(ahc, &s); - ahc_pause(ahc); - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = lstate; - ahc->enabled_luns++; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - u_int targid_mask; - - targid_mask = ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) << 8); - - targid_mask |= target_mask; - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); - - ahc_update_scsiid(ahc, targid_mask); - } else { - u_int our_id; - char channel; - - channel = SIM_CHANNEL(ahc, sim); - our_id = SIM_SCSI_ID(ahc, sim); - - /* - * This can only happen if selections - * are not enabled - */ - if (target != our_id) { - u_int sblkctl; - char cur_channel; - int swap; - - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = (sblkctl & SELBUSB) - ? 'B' : 'A'; - if ((ahc->features & AHC_TWIN) == 0) - cur_channel = 'A'; - swap = cur_channel != channel; - if (channel == 'A') - ahc->our_id = target; - else - ahc->our_id_b = target; - - if (swap) - ahc_outb(ahc, SBLKCTL, - sblkctl ^ SELBUSB); - - ahc_outb(ahc, SCSIID, target); - - if (swap) - ahc_outb(ahc, SBLKCTL, sblkctl); - } - } - } else - ahc->black_hole = lstate; - /* Allow select-in operations */ - if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - } - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print_path(ccb->ccb_h.path); - printf("Lun now enabled for target mode\n"); - } else { - struct scb *scb; - int i, empty; - - if (lstate == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - return; - } - - ahc_lock(ahc, &s); - - ccb->ccb_h.status = CAM_REQ_CMP; - LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { - struct ccb_hdr *ccbh; - - ccbh = &scb->io_ctx->ccb_h; - if (ccbh->func_code == XPT_CONT_TARGET_IO - && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ - printf("CTIO pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - ahc_unlock(ahc, &s); - return; - } - } - - if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printf("ATIOs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printf("INOTs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (ccb->ccb_h.status != CAM_REQ_CMP) { - ahc_unlock(ahc, &s); - return; - } - - xpt_print_path(ccb->ccb_h.path); - printf("Target mode disabled\n"); - xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); - - ahc_pause(ahc); - /* Can we clean up the target too? */ - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = NULL; - ahc->enabled_luns--; - for (empty = 1, i = 0; i < 8; i++) - if (tstate->enabled_luns[i] != NULL) { - empty = 0; - break; - } - - if (empty) { - ahc_free_tstate(ahc, target, channel, - /*force*/FALSE); - if (ahc->features & AHC_MULTI_TID) { - u_int targid_mask; - - targid_mask = ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) - << 8); - - targid_mask &= ~target_mask; - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, - (targid_mask >> 8)); - ahc_update_scsiid(ahc, targid_mask); - } - } - } else { - - ahc->black_hole = NULL; - - /* - * We can't allow selections without - * our black hole device. - */ - empty = TRUE; - } - if (ahc->enabled_luns == 0) { - /* Disallow select-in */ - u_int scsiseq; - - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - - if ((ahc->features & AHC_MULTIROLE) == 0) { - printf("Configuring Initiator Mode\n"); - ahc->flags &= ~AHC_TARGETROLE; - ahc->flags |= AHC_INITIATORROLE; - ahc_pause(ahc); - ahc_loadseq(ahc); - } - } - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - } -} - -static void -ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask) -{ - u_int scsiid_mask; - u_int scsiid; - - if ((ahc->features & AHC_MULTI_TID) == 0) - panic("ahc_update_scsiid called on non-multitid unit\n"); - - /* - * Since we will rely on the the TARGID mask - * for selection enables, ensure that OID - * in SCSIID is not set to some other ID - * that we don't want to allow selections on. - */ - if ((ahc->features & AHC_ULTRA2) != 0) - scsiid = ahc_inb(ahc, SCSIID_ULTRA2); - else - scsiid = ahc_inb(ahc, SCSIID); - scsiid_mask = 0x1 << (scsiid & OID); - if ((targid_mask & scsiid_mask) == 0) { - u_int our_id; - - /* ffs counts from 1 */ - our_id = ffs(targid_mask); - if (our_id == 0) - our_id = ahc->our_id; - else - our_id--; - scsiid &= TID; - scsiid |= our_id; - } - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, scsiid); - else - ahc_outb(ahc, SCSIID, scsiid); -} - -void -ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) -{ - struct target_cmd *cmd; - - /* - * If the card supports auto-access pause, - * we can access the card directly regardless - * of whether it is paused or not. - */ - if ((ahc->features & AHC_AUTOPAUSE) != 0) - paused = TRUE; - - ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD); - while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) { - - /* - * Only advance through the queue if we - * have the resources to process the command. - */ - if (ahc_handle_target_cmd(ahc, cmd) != 0) - break; - - cmd->cmd_valid = 0; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - ahc_targetcmd_offset(ahc, ahc->tqinfifonext), - sizeof(struct target_cmd), - BUS_DMASYNC_PREREAD); - ahc->tqinfifonext++; - - /* - * Lazily update our position in the target mode incoming - * command queue as seen by the sequencer. - */ - if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - u_int hs_mailbox; - - hs_mailbox = ahc_inb(ahc, HS_MAILBOX); - hs_mailbox &= ~HOST_TQINPOS; - hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS; - ahc_outb(ahc, HS_MAILBOX, hs_mailbox); - } else { - if (!paused) - ahc_pause(ahc); - ahc_outb(ahc, KERNEL_TQINPOS, - ahc->tqinfifonext & HOST_TQINPOS); - if (!paused) - ahc_unpause(ahc); - } - } - } -} - -static int -ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) -{ - struct ahc_tmode_tstate *tstate; - struct ahc_tmode_lstate *lstate; - struct ccb_accept_tio *atio; - uint8_t *byte; - int initiator; - int target; - int lun; - - initiator = SCSIID_TARGET(ahc, cmd->scsiid); - target = SCSIID_OUR_ID(cmd->scsiid); - lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); - - byte = cmd->bytes; - tstate = ahc->enabled_targets[target]; - lstate = NULL; - if (tstate != NULL) - lstate = tstate->enabled_luns[lun]; - - /* - * Commands for disabled luns go to the black hole driver. - */ - if (lstate == NULL) - lstate = ahc->black_hole; - - atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); - if (atio == NULL) { - ahc->flags |= AHC_TQINFIFO_BLOCKED; - /* - * Wait for more ATIOs from the peripheral driver for this lun. - */ - return (1); - } else - ahc->flags &= ~AHC_TQINFIFO_BLOCKED; -#if 0 - printf("Incoming command from %d for %d:%d%s\n", - initiator, target, lun, - lstate == ahc->black_hole ? "(Black Holed)" : ""); -#endif - SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); - - if (lstate == ahc->black_hole) { - /* Fill in the wildcards */ - atio->ccb_h.target_id = target; - atio->ccb_h.target_lun = lun; - } - - /* - * Package it up and send it off to - * whomever has this lun enabled. - */ - atio->sense_len = 0; - atio->init_id = initiator; - if (byte[0] != 0xFF) { - /* Tag was included */ - atio->tag_action = *byte++; - atio->tag_id = *byte++; - atio->ccb_h.flags = CAM_TAG_ACTION_VALID; - } else { - atio->ccb_h.flags = 0; - } - byte++; - - /* Okay. Now determine the cdb size based on the command code */ - switch (*byte >> CMD_GROUP_CODE_SHIFT) { - case 0: - atio->cdb_len = 6; - break; - case 1: - case 2: - atio->cdb_len = 10; - break; - case 4: - atio->cdb_len = 16; - break; - case 5: - atio->cdb_len = 12; - break; - case 3: - default: - /* Only copy the opcode. */ - atio->cdb_len = 1; - printf("Reserved or VU command code type encountered\n"); - break; - } - - memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); - - atio->ccb_h.status |= CAM_CDB_RECVD; - - if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { - /* - * We weren't allowed to disconnect. - * We're hanging on the bus until a - * continue target I/O comes in response - * to this accept tio. - */ -#if 0 - printf("Received Immediate Command %d:%d:%d - %p\n", - initiator, target, lun, ahc->pending_device); -#endif - ahc->pending_device = lstate; - ahc_freeze_ccb((union ccb *)atio); - atio->ccb_h.flags |= CAM_DIS_DISCONNECT; - } - xpt_done((union ccb*)atio); - return (0); -} - -#endif diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.h Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#34 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ */ @@ -1093,7 +1093,8 @@ /*************************** EISA/VL Front End ********************************/ struct aic7770_identity *aic7770_find_device(uint32_t); int aic7770_config(struct ahc_softc *ahc, - struct aic7770_identity *); + struct aic7770_identity *, + u_int port); /************************** SCB and SCB queue management **********************/ int ahc_probe_scbs(struct ahc_softc *); @@ -1157,7 +1158,8 @@ char channel, int lun, u_int tag, role_t role, uint32_t status); void ahc_restart(struct ahc_softc *ahc); -void ahc_calc_residual(struct scb *scb); +void ahc_calc_residual(struct ahc_softc *ahc, + struct scb *scb); /*************************** Utility Functions ********************************/ struct ahc_phase_table_entry* ahc_lookup_phase_entry(int phase); @@ -1219,6 +1221,11 @@ #endif #endif /******************************* Debug ***************************************/ +#ifdef AHC_DEBUG +extern int ahc_debug; +#define AHC_SHOWMISC 0x1 +#define AHC_SHOWSENSE 0x2 +#endif void ahc_print_scb(struct scb *scb); void ahc_dump_card_state(struct ahc_softc *ahc); #endif /* _AIC7XXX_H_ */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.reg --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.reg Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.reg Sat Mar 30 22:55:35 2002 @@ -37,9 +37,9 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.20.2.10 2001/07/28 18:46:40 gibbs Exp $ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#24 $" +VERSION = "$Id$" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1009,7 +1009,9 @@ * SCB Definition (p. 5-4) */ scb { - address 0x0a0 + address 0x0a0 + size 64 + SCB_CDB_PTR { size 4 alias SCB_RESIDUAL_DATACNT @@ -1254,7 +1256,8 @@ */ scratch_ram { - address 0x020 + address 0x020 + size 58 /* * 1 byte per target starting at this address for configuration values @@ -1482,13 +1485,17 @@ bit SCB_DMA 0x01 bit TARGET_MSG_PENDING 0x02 } +} + +scratch_ram { + address 0x05a + size 6 /* * These are reserved registers in the card's scratch ram. Some of * the values are specified in the AHA2742 technical reference manual * and are initialized by the BIOS at boot time. */ SCSICONF { - address 0x05a size 1 bit TERM_ENB 0x80 bit RESET_SCSI 0x40 @@ -1513,11 +1520,16 @@ mask BIOSDISABLED 0x30 bit CHANNEL_B_PRIMARY 0x08 } +} + +scratch_ram { + address 0x070 + size 16 + /* * Per target SCSI offset values for Ultra2 controllers. */ TARG_OFFSET { - address 0x070 size 16 } } diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.seq linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.seq --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx.seq Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx.seq Sat Mar 30 22:55:35 2002 @@ -40,7 +40,8 @@ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#37 $" +VERSION = "$Id$" +PATCH_ARG_LIST = "struct ahc_softc *ahc" #include "aic7xxx.reg" #include "scsi_message.h" @@ -89,7 +90,7 @@ test SSTAT0, SELDO|SELDI jnz selection; test_queue: /* Has the driver posted any work for us? */ -BEGIN_CRITICAL +BEGIN_CRITICAL; if ((ahc->features & AHC_QUEUE_REGS) != 0) { test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; } else { @@ -110,7 +111,7 @@ mov SCBPTR, ARG_1; } or SEQ_FLAGS2, SCB_DMA; -END_CRITICAL +END_CRITICAL; dma_queued_scb: /* * DMA the SCB from host ram into the current SCB location. @@ -124,7 +125,7 @@ * value. */ mov A, ARG_1; -BEGIN_CRITICAL +BEGIN_CRITICAL; cmp NEXT_QUEUED_SCB, A jne abort_qinscb; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { cmp SCB_TAG, A je . + 2; @@ -139,7 +140,7 @@ inc QINPOS; } and SEQ_FLAGS2, ~SCB_DMA; -END_CRITICAL +END_CRITICAL; start_waiting: /* * Start the first entry on the waiting SCB list. @@ -968,12 +969,12 @@ ultra2_ensure_sg: test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; /* Record if we've consumed all S/G entries */ - test SSTAT2, SHVALID jnz residuals_correct; + test SSTAT2, SHVALID jnz residuals_correct; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; jmp residuals_correct; ultra2_shvalid: - test SSTAT2, SHVALID jnz sgptr_fixup; + test SSTAT2, SHVALID jnz sgptr_fixup; call idle_loop; jmp ultra2_ensure_sg; @@ -1397,7 +1398,7 @@ * The data fifo seems to require 4 byte aligned * transfers from the sequencer. Force this to * be the case by clearing HADDR[0] even though - * we aren't going to touch host memeory. + * we aren't going to touch host memory. */ clr HADDR[0]; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -2003,7 +2004,7 @@ * removal of the found SCB from the disconnected list. */ if ((ahc->flags & AHC_PAGESCBS) != 0) { -BEGIN_CRITICAL +BEGIN_CRITICAL; findSCB: mov A, SINDEX; /* Tag passed in SINDEX */ cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; @@ -2025,7 +2026,7 @@ mov SCBPTR, SINDEX ret; rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret; -END_CRITICAL +END_CRITICAL; findSCB_notFound: /* * We didn't find it. Page in the SCB. @@ -2150,7 +2151,7 @@ adc DINDIR, A, SINDIR ret; /* - * Either post or fetch and SCB from host memory based on the + * Either post or fetch an SCB from host memory based on the * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. */ dma_scb: @@ -2308,11 +2309,11 @@ } add_scb_to_free_list: if ((ahc->flags & AHC_PAGESCBS) != 0) { -BEGIN_CRITICAL +BEGIN_CRITICAL; mov SCB_NEXT, FREE_SCBH; mvi SCB_TAG, SCB_LIST_NULL; mov FREE_SCBH, SCBPTR ret; -END_CRITICAL +END_CRITICAL; } else { mvi SCB_TAG, SCB_LIST_NULL ret; } @@ -2326,7 +2327,7 @@ if ((ahc->flags & AHC_PAGESCBS) != 0) { get_free_or_disc_scb: -BEGIN_CRITICAL +BEGIN_CRITICAL; cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; return_error: @@ -2335,14 +2336,14 @@ dequeue_disc_scb: mov SCBPTR, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCB_NEXT; -END_CRITICAL +END_CRITICAL; mvi DMAPARAMS, FIFORESET; mov SCB_TAG jmp dma_scb; -BEGIN_CRITICAL +BEGIN_CRITICAL; dequeue_free_scb: mov SCBPTR, FREE_SCBH; mov FREE_SCBH, SCB_NEXT ret; -END_CRITICAL +END_CRITICAL; add_scb_to_disc_list: /* @@ -2350,10 +2351,10 @@ * candidates for paging out an SCB if one is needed for a new command. * Modifying the disconnected list is a critical(pause dissabled) section. */ -BEGIN_CRITICAL +BEGIN_CRITICAL; mov SCB_NEXT, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCBPTR ret; -END_CRITICAL +END_CRITICAL; } set_seqint: mov INTSTAT, SINDEX; diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Sat Mar 30 22:55:35 2002 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#10 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.9 2000/11/10 20:13:41 gibbs Exp $ */ @@ -67,9 +67,15 @@ * */ +#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" +#else +#include +#include +#include +#endif /* * Right now, we only have to read the SEEPROM. But we make it easier to @@ -94,11 +100,8 @@ * not successful. */ int -read_seeprom(sd, buf, start_addr, count) - struct seeprom_descriptor *sd; - uint16_t *buf; - u_int start_addr; - u_int count; +ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count) { int i = 0; u_int k = 0; @@ -183,7 +186,7 @@ } int -verify_cksum(struct seeprom_config *sc) +ahc_verify_cksum(struct seeprom_config *sc) { int i; int maxaddr; diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Sat Mar 30 22:55:35 2002 @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#7 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.8 2000/11/10 20:13:41 gibbs Exp $ */ @@ -93,8 +93,8 @@ #define SEEPROM_DATA_INB(sd) \ ahc_inb(sd->sd_ahc, sd->sd_dataout_offset) -int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, - u_int start_addr, u_int count); -int verify_cksum(struct seeprom_config *sc); +int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count); +int ahc_verify_cksum(struct seeprom_config *sc); #endif /* _AIC7XXX_93CX6_H_ */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_core.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_core.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_core.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,7016 @@ +/* + * Core routines and tables shareable across OS platforms. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#1 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ + */ + +#ifdef __linux__ +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aicasm/aicasm_insformat.h" +#else +#include +#include +#include +#endif + +/****************************** Softc Data ************************************/ +struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq); + +/***************************** Lookup Tables **********************************/ +char *ahc_chip_names[] = +{ + "NONE", + "aic7770", + "aic7850", + "aic7855", + "aic7859", + "aic7860", + "aic7870", + "aic7880", + "aic7895", + "aic7895C", + "aic7890/91", + "aic7896/97", + "aic7892", + "aic7899" +}; +static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); + +/* + * Hardware error codes. + */ +struct ahc_hard_error_entry { + uint8_t errno; + char *errmesg; +}; + +static struct ahc_hard_error_entry ahc_hard_errors[] = { + { ILLHADDR, "Illegal Host Access" }, + { ILLSADDR, "Illegal Sequencer Address referrenced" }, + { ILLOPCODE, "Illegal Opcode in sequencer program" }, + { SQPARERR, "Sequencer Parity Error" }, + { DPARERR, "Data-path Parity Error" }, + { MPARERR, "Scratch or SCB Memory Parity Error" }, + { PCIERRSTAT, "PCI Error detected" }, + { CIOPARERR, "CIOBUS Parity Error" }, +}; +static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); + +static struct ahc_phase_table_entry ahc_phase_table[] = +{ + { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, + { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, + { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, + { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, + { P_COMMAND, MSG_NOOP, "in Command phase" }, + { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, + { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, + { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, + { P_BUSFREE, MSG_NOOP, "while idle" }, + { 0, MSG_NOOP, "in unknown phase" } +}; + +/* + * In most cases we only wish to itterate over real phases, so + * exclude the last element from the count. + */ +static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; + +/* + * Valid SCSIRATE values. (p. 3-17) + * Provides a mapping of tranfer periods in ns to the proper value to + * stick in the scsixfer reg. + */ +static struct ahc_syncrate ahc_syncrates[] = +{ + /* ultra2 fast/ultra period rate */ + { 0x42, 0x000, 9, "80.0" }, + { 0x03, 0x000, 10, "40.0" }, + { 0x04, 0x000, 11, "33.0" }, + { 0x05, 0x100, 12, "20.0" }, + { 0x06, 0x110, 15, "16.0" }, + { 0x07, 0x120, 18, "13.4" }, + { 0x08, 0x000, 25, "10.0" }, + { 0x19, 0x010, 31, "8.0" }, + { 0x1a, 0x020, 37, "6.67" }, + { 0x1b, 0x030, 43, "5.7" }, + { 0x1c, 0x040, 50, "5.0" }, + { 0x00, 0x050, 56, "4.4" }, + { 0x00, 0x060, 62, "4.0" }, + { 0x00, 0x070, 68, "3.6" }, + { 0x00, 0x000, 0, NULL } +}; + +/* Our Sequencer Program */ +#include "aic7xxx_seq.h" + +/**************************** Function Declarations ***************************/ +static void ahc_force_renegotiation(struct ahc_softc *ahc); +static struct ahc_tmode_tstate* + ahc_alloc_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel); +#ifdef AHC_TARGET_MODE +static void ahc_free_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel, int force); +#endif +static struct ahc_syncrate* + ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *, + u_int *period, + u_int *ppr_options, + role_t role); +static void ahc_update_pending_scbs(struct ahc_softc *ahc); +static void ahc_fetch_devinfo(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_scb_devinfo(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +static void ahc_assert_atn(struct ahc_softc *ahc); +static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +static void ahc_build_transfer_msg(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_construct_sdtr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int period, u_int offset); +static void ahc_construct_wdtr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int bus_width); +static void ahc_construct_ppr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int period, u_int offset, + u_int bus_width, u_int ppr_options); +static void ahc_clear_msg_state(struct ahc_softc *ahc); +static void ahc_handle_message_phase(struct ahc_softc *ahc); +typedef enum { + AHCMSG_1B, + AHCMSG_2B, + AHCMSG_EXT +} ahc_msgtype; +static int ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, + u_int msgval, int full); +static int ahc_parse_msg(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static int ahc_handle_msg_reject(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_reinitialize_dataptrs(struct ahc_softc *ahc); +static void ahc_handle_devreset(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + cam_status status, char *message, + int verbose_level); +#if AHC_TARGET_MODE +static void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +#endif + +static bus_dmamap_callback_t ahc_dmamap_cb; +static void ahc_build_free_scb_list(struct ahc_softc *ahc); +static int ahc_init_scbdata(struct ahc_softc *ahc); +static void ahc_fini_scbdata(struct ahc_softc *ahc); +static void ahc_qinfifo_requeue(struct ahc_softc *ahc, + struct scb *prev_scb, + struct scb *scb); +static int ahc_qinfifo_count(struct ahc_softc *ahc); +static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, + u_int prev, u_int scbptr); +static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); +static u_int ahc_rem_wscb(struct ahc_softc *ahc, + u_int scbpos, u_int prev); +static void ahc_reset_current_bus(struct ahc_softc *ahc); +#ifdef AHC_DUMP_SEQ +static void ahc_dumpseq(struct ahc_softc *ahc); +#endif +static void ahc_loadseq(struct ahc_softc *ahc); +static int ahc_check_patch(struct ahc_softc *ahc, + struct patch **start_patch, + u_int start_instr, u_int *skip_addr); +static void ahc_download_instr(struct ahc_softc *ahc, + u_int instrptr, uint8_t *dconsts); +#ifdef AHC_TARGET_MODE +static void ahc_queue_lstate_event(struct ahc_softc *ahc, + struct ahc_tmode_lstate *lstate, + u_int initiator_id, + u_int event_type, + u_int event_arg); +static void ahc_update_scsiid(struct ahc_softc *ahc, + u_int targid_mask); +static int ahc_handle_target_cmd(struct ahc_softc *ahc, + struct target_cmd *cmd); +#endif +/************************* Sequencer Execution Control ************************/ +/* + * Restart the sequencer program from address zero + */ +void +ahc_restart(struct ahc_softc *ahc) +{ + + ahc_pause(ahc); + + /* No more pending messages. */ + ahc_clear_msg_state(ahc); + + ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ + ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); + ahc_outb(ahc, LASTPHASE, P_BUSFREE); + ahc_outb(ahc, SAVED_SCSIID, 0xFF); + ahc_outb(ahc, SAVED_LUN, 0xFF); + + /* + * Ensure that the sequencer's idea of TQINPOS + * matches our own. The sequencer increments TQINPOS + * only after it sees a DMA complete and a reset could + * occur before the increment leaving the kernel to believe + * the command arrived but the sequencer to not. + */ + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + + /* Always allow reselection */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Ensure that no DMA operations are in progress */ + ahc_outb(ahc, CCSCBCNT, 0); + ahc_outb(ahc, CCSGCTL, 0); + ahc_outb(ahc, CCSCBCTL, 0); + } + /* + * If we were in the process of DMA'ing SCB data into + * an SCB, replace that SCB on the free list. This prevents + * an SCB leak. + */ + if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) { + ahc_add_curscb_to_free_list(ahc); + ahc_outb(ahc, SEQ_FLAGS2, + ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); + } + ahc_outb(ahc, MWI_RESIDUAL, 0); + ahc_outb(ahc, SEQCTL, FASTMODE); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + ahc_unpause(ahc); +} + +/************************* Input/Output Queues ********************************/ +void +ahc_run_qoutfifo(struct ahc_softc *ahc) +{ + struct scb *scb; + u_int scb_index; + + ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); + while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) { + + scb_index = ahc->qoutfifo[ahc->qoutfifonext]; + if ((ahc->qoutfifonext & 0x03) == 0x03) { + u_int modnext; + + /* + * Clear 32bits of QOUTFIFO at a time + * so that we don't clobber an incoming + * byte DMA to the array on architectures + * that only support 32bit load and store + * operations. + */ + modnext = ahc->qoutfifonext & ~0x3; + *((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL; + ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap, + /*offset*/modnext, /*len*/4, + BUS_DMASYNC_PREREAD); + } + ahc->qoutfifonext++; + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: WARNING no command for scb %d " + "(cmdcmplt)\nQOUTPOS = %d\n", + ahc_name(ahc), scb_index, + ahc->qoutfifonext - 1); + continue; + } + + /* + * Save off the residual + * if there is one. + */ + ahc_update_residual(ahc, scb); + ahc_done(ahc, scb); + } +} + +void +ahc_run_untagged_queues(struct ahc_softc *ahc) +{ + int i; + + for (i = 0; i < 16; i++) + ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]); +} + +void +ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue) +{ + struct scb *scb; + + if (ahc->untagged_queue_lock != 0) + return; + + if ((scb = TAILQ_FIRST(queue)) != NULL + && (scb->flags & SCB_ACTIVE) == 0) { + scb->flags |= SCB_ACTIVE; + ahc_queue_scb(ahc, scb); + } +} + +/************************* Interrupt Handling *********************************/ +void +ahc_handle_brkadrint(struct ahc_softc *ahc) +{ + /* + * We upset the sequencer :-( + * Lookup the error message + */ + int i; + int error; + + error = ahc_inb(ahc, ERROR); + for (i = 0; error != 1 && i < num_errors; i++) + error >>= 1; + printf("%s: brkadrint, %s at seqaddr = 0x%x\n", + ahc_name(ahc), ahc_hard_errors[i].errmesg, + ahc_inb(ahc, SEQADDR0) | + (ahc_inb(ahc, SEQADDR1) << 8)); + + ahc_dump_card_state(ahc); + + /* Tell everyone that this HBA is no longer availible */ + ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, + CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, + CAM_NO_HBA); + + /* Disable all interrupt sources by resetting the controller */ + ahc_shutdown(ahc); +} + +void +ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) +{ + struct scb *scb; + struct ahc_devinfo devinfo; + + ahc_fetch_devinfo(ahc, &devinfo); + + /* + * Clear the upper byte that holds SEQINT status + * codes and clear the SEQINT bit. We will unpause + * the sequencer, if appropriate, after servicing + * the request. + */ + ahc_outb(ahc, CLRINT, CLRSEQINT); + switch (intstat & SEQINT_MASK) { + case BAD_STATUS: + { + u_int scb_index; + struct hardware_scb *hscb; + + /* + * Set the default return value to 0 (don't + * send sense). The sense code will change + * this if needed. + */ + ahc_outb(ahc, RETURN_1, 0); + + /* + * The sequencer will notify us when a command + * has an error that would be of interest to + * the kernel. This allows us to leave the sequencer + * running in the common case of command completes + * without error. The sequencer will already have + * dma'd the SCB back up to us, so we can reference + * the in kernel copy directly. + */ + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s:%c:%d: ahc_intr - referenced scb " + "not valid during seqint 0x%x scb(%d)\n", + ahc_name(ahc), devinfo.channel, + devinfo.target, intstat, scb_index); + ahc_dump_card_state(ahc); + panic("for safety"); + goto unpause; + } + + hscb = scb->hscb; + + /* Don't want to clobber the original sense code */ + if ((scb->flags & SCB_SENSE) != 0) { + /* + * Clear the SCB_SENSE Flag and have + * the sequencer do a normal command + * complete. + */ + scb->flags &= ~SCB_SENSE; + ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + break; + } + ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); + /* Freeze the queue until the client sees the error. */ + ahc_freeze_devq(ahc, scb); + ahc_freeze_scb(scb); + ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); + switch (hscb->shared_data.status.scsi_status) { + case SCSI_STATUS_OK: + printf("%s: Interrupted for staus of 0???\n", + ahc_name(ahc)); + break; + case SCSI_STATUS_CMD_TERMINATED: + case SCSI_STATUS_CHECK_COND: + { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + struct ahc_transinfo *tinfo; +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("SCB %d: requests Check Status\n", + scb->hscb->tag); + } +#endif + + if (ahc_perform_autosense(scb) == 0) + break; + + targ_info = ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + tinfo = &targ_info->curr; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + ahc_update_residual(ahc, scb); +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } +#endif + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; + + /* + * We can't allow the target to disconnect. + * This will be an untagged transaction and + * having the target disconnect will make this + * transaction indestinguishable from outstanding + * tagged transactions. + */ + hscb->control = 0; + + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_neg_request(ahc, &devinfo, + tstate, targ_info, + /*force*/TRUE); + } + if (tstate->auto_negotiate & devinfo.target_mask) { + hscb->control |= MK_MESSAGE; + scb->flags &= ~SCB_NEGOTIATE; + scb->flags |= SCB_AUTO_NEGOTIATE; + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); +#ifdef __FreeBSD__ + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); +#endif + break; + } + default: + break; + } + break; + } + case NO_MATCH: + { + /* Ensure we don't leave the selection hardware on */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + + printf("%s:%c:%d: no active SCB for reconnecting " + "target - issuing BUS DEVICE RESET\n", + ahc_name(ahc), devinfo.channel, devinfo.target); + printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ACCUM = 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN))), + ahc_inb(ahc, SINDEX)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); + printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); + printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); + ahc_dump_card_state(ahc); + ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; + ahc->msgout_len = 1; + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_assert_atn(ahc); + break; + } + case SEND_REJECT: + { + u_int rejbyte = ahc_inb(ahc, ACCUM); + printf("%s:%c:%d: Warning - unknown message received from " + "target (0x%x). Rejecting\n", + ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); + break; + } + case NO_IDENT: + { + /* + * The reconnecting target either did not send an identify + * message, or did, but we didn't find an SCB to match and + * before it could respond to our ATN/abort, it hit a dataphase. + * The only safe thing to do is to blow it away with a bus + * reset. + */ + int found; + + printf("%s:%c:%d: Target did not send an IDENTIFY message. " + "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID)); + found = ahc_reset_channel(ahc, devinfo.channel, + /*initiate reset*/TRUE); + printf("%s: Issued Channel %c Bus Reset. " + "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel, + found); + return; + } + case IGN_WIDE_RES: + ahc_handle_ign_wide_residue(ahc, &devinfo); + break; + case PDATA_REINIT: + ahc_reinitialize_dataptrs(ahc); + break; + case BAD_PHASE: + { + u_int lastphase; + + lastphase = ahc_inb(ahc, LASTPHASE); + printf("%s:%c:%d: unknown scsi bus phase %x, " + "lastphase = 0x%x. Attempting to continue\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + lastphase, ahc_inb(ahc, SCSISIGI)); + break; + } + case MISSED_BUSFREE: + { + u_int lastphase; + + lastphase = ahc_inb(ahc, LASTPHASE); + printf("%s:%c:%d: Missed busfree. " + "Lastphase = 0x%x, Curphase = 0x%x\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + lastphase, ahc_inb(ahc, SCSISIGI)); + ahc_restart(ahc); + return; + } + case HOST_MSG_LOOP: + { + /* + * The sequencer has encountered a message phase + * that requires host assistance for completion. + * While handling the message phase(s), we will be + * notified by the sequencer after each byte is + * transfered so we can track bus phase changes. + * + * If this is the first time we've seen a HOST_MSG_LOOP + * interrupt, initialize the state of the host message + * loop. + */ + if (ahc->msg_type == MSG_TYPE_NONE) { + struct scb *scb; + u_int scb_index; + u_int bus_phase; + + bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + if (bus_phase != P_MESGIN + && bus_phase != P_MESGOUT) { + printf("ahc_intr: HOST_MSG_LOOP bad " + "phase 0x%x\n", + bus_phase); + /* + * Probably transitioned to bus free before + * we got here. Just punt the message. + */ + ahc_clear_intstat(ahc); + ahc_restart(ahc); + return; + } + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + if (devinfo.role == ROLE_INITIATOR) { + if (scb == NULL) + panic("HOST_MSG_LOOP with " + "invalid SCB %x\n", scb_index); + + if (bus_phase == P_MESGOUT) + ahc_setup_initiator_msgout(ahc, + &devinfo, + scb); + else { + ahc->msg_type = + MSG_TYPE_INITIATOR_MSGIN; + ahc->msgin_index = 0; + } + } +#if AHC_TARGET_MODE + else { + if (bus_phase == P_MESGOUT) { + ahc->msg_type = + MSG_TYPE_TARGET_MSGOUT; + ahc->msgin_index = 0; + } + else + ahc_setup_target_msgin(ahc, + &devinfo, + scb); + } +#endif + } + + ahc_handle_message_phase(ahc); + break; + } + case PERR_DETECTED: + { + /* + * If we've cleared the parity error interrupt + * but the sequencer still believes that SCSIPERR + * is true, it must be that the parity error is + * for the currently presented byte on the bus, + * and we are not in a phase (data-in) where we will + * eventually ack this byte. Ack the byte and + * throw it away in the hope that the target will + * take us to message out to deliver the appropriate + * error message. + */ + if ((intstat & SCSIINT) == 0 + && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { + + if ((ahc->features & AHC_DT) == 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + } + ahc_inb(ahc, SCSIDATL); + } + break; + } + case DATA_OVERRUN: + { + /* + * When the sequencer detects an overrun, it + * places the controller in "BITBUCKET" mode + * and allows the target to complete its transfer. + * Unfortunately, none of the counters get updated + * when the controller is in this mode, so we have + * no way of knowing how large the overrun was. + */ + u_int scbindex = ahc_inb(ahc, SCB_TAG); + u_int lastphase = ahc_inb(ahc, LASTPHASE); + u_int i; + + scb = ahc_lookup_scb(ahc, scbindex); + for (i = 0; i < num_phases; i++) { + if (lastphase == ahc_phase_table[i].phase) + break; + } + ahc_print_path(ahc, scb); + printf("data overrun detected %s." + " Tag == 0x%x.\n", + ahc_phase_table[i].phasemsg, + scb->hscb->tag); + ahc_print_path(ahc, scb); + printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", + ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", + ahc_get_transfer_length(scb), scb->sg_count); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + + printf("sg[%d] - Addr 0x%x%x : Length %d\n", + i, + (ahc_le32toh(scb->sg_list[i].len) >> 24 + & SG_HIGH_ADDR_BITS), + ahc_le32toh(scb->sg_list[i].addr), + ahc_le32toh(scb->sg_list[i].len) + & AHC_SG_LEN_MASK); + } + } + /* + * Set this and it will take effect when the + * target does a command complete. + */ + ahc_freeze_devq(ahc, scb); + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + ahc_freeze_scb(scb); + + if ((ahc->features & AHC_ULTRA2) != 0) { + /* + * Clear the channel in case we return + * to data phase later. + */ + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); + } + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + u_int dscommand1; + + /* Ensure HHADDR is 0 for future DMA operations. */ + dscommand1 = ahc_inb(ahc, DSCOMMAND1); + ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); + ahc_outb(ahc, HADDR, 0); + ahc_outb(ahc, DSCOMMAND1, dscommand1); + } + break; + } + case MKMSG_FAILED: + { + u_int scbindex; + + printf("%s:%c:%d:%d: Attempt to issue message failed\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + devinfo.lun); + scbindex = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scbindex); + if (scb != NULL + && (scb->flags & SCB_RECOVERY_SCB) != 0) + /* + * Ensure that we didn't put a second instance of this + * SCB into the QINFIFO. + */ + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_REMOVE); + break; + } + case NO_FREE_SCB: + { + printf("%s: No free or disconnected SCBs\n", ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + case SCB_MISMATCH: + { + u_int scbptr; + + scbptr = ahc_inb(ahc, SCBPTR); + printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", + scbptr, ahc_inb(ahc, ARG_1), + ahc->scb_data->hscbs[scbptr].tag); + ahc_dump_card_state(ahc); + panic("for saftey"); + break; + } + case OUT_OF_RANGE: + { + printf("%s: BTT calculation out of range\n", ahc_name(ahc)); + printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ACCUM = 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n, A == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN))), + ahc_inb(ahc, SINDEX), + ahc_inb(ahc, ACCUM)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + default: + printf("ahc_intr: seqint, " + "intstat == 0x%x, scsisigi = 0x%x\n", + intstat, ahc_inb(ahc, SCSISIGI)); + break; + } +unpause: + /* + * The sequencer is paused immediately on + * a SEQINT, so we should restart it when + * we're done. + */ + ahc_unpause(ahc); +} + +void +ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) +{ + u_int scb_index; + u_int status0; + u_int status; + struct scb *scb; + char cur_channel; + char intr_channel; + + /* Make sure the sequencer is in a safe location. */ + ahc_clear_critical_section(ahc); + + if ((ahc->features & AHC_TWIN) != 0 + && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0)) + cur_channel = 'B'; + else + cur_channel = 'A'; + intr_channel = cur_channel; + + if ((ahc->features & AHC_ULTRA2) != 0) + status0 = ahc_inb(ahc, SSTAT0) & IOERR; + else + status0 = 0; + status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); + if (status == 0 && status0 == 0) { + if ((ahc->features & AHC_TWIN) != 0) { + /* Try the other channel */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); + status = ahc_inb(ahc, SSTAT1) + & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); + intr_channel = (cur_channel == 'A') ? 'B' : 'A'; + } + if (status == 0) { + printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_unpause(ahc); + return; + } + } + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + if (scb != NULL + && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0) + scb = NULL; + + if ((ahc->features & AHC_ULTRA2) != 0 + && (status0 & IOERR) != 0) { + int now_lvd; + + now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40; + printf("%s: Transceiver State Has Changed to %s mode\n", + ahc_name(ahc), now_lvd ? "LVD" : "SE"); + ahc_outb(ahc, CLRSINT0, CLRIOERR); + /* + * When transitioning to SE mode, the reset line + * glitches, triggering an arbitration bug in some + * Ultra2 controllers. This bug is cleared when we + * assert the reset line. Since a reset glitch has + * already occurred with this transition and a + * transceiver state change is handled just like + * a bus reset anyway, asserting the reset line + * ourselves is safe. + */ + ahc_reset_channel(ahc, intr_channel, + /*Initiate Reset*/now_lvd == 0); + } else if ((status & SCSIRSTI) != 0) { + printf("%s: Someone reset channel %c\n", + ahc_name(ahc), intr_channel); + if (intr_channel != cur_channel) + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); + ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE); + } else if ((status & SCSIPERR) != 0) { + /* + * Determine the bus phase and queue an appropriate message. + * SCSIPERR is latched true as soon as a parity error + * occurs. If the sequencer acked the transfer that + * caused the parity error and the currently presented + * transfer on the bus has correct parity, SCSIPERR will + * be cleared by CLRSCSIPERR. Use this to determine if + * we should look at the last phase the sequencer recorded, + * or the current phase presented on the bus. + */ + u_int mesg_out; + u_int curphase; + u_int errorphase; + u_int lastphase; + u_int scsirate; + u_int i; + u_int sstat2; + + lastphase = ahc_inb(ahc, LASTPHASE); + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + sstat2 = ahc_inb(ahc, SSTAT2); + ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); + /* + * For all phases save DATA, the sequencer won't + * automatically ack a byte that has a parity error + * in it. So the only way that the current phase + * could be 'data-in' is if the parity error is for + * an already acked byte in the data phase. During + * synchronous data-in transfers, we may actually + * ack bytes before latching the current phase in + * LASTPHASE, leading to the discrepancy between + * curphase and lastphase. + */ + if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0 + || curphase == P_DATAIN || curphase == P_DATAIN_DT) + errorphase = curphase; + else + errorphase = lastphase; + + for (i = 0; i < num_phases; i++) { + if (errorphase == ahc_phase_table[i].phase) + break; + } + mesg_out = ahc_phase_table[i].mesg_out; + if (scb != NULL) + ahc_print_path(ahc, scb); + else + printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, + SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); + scsirate = ahc_inb(ahc, SCSIRATE); + printf("parity error detected %s. " + "SEQADDR(0x%x) SCSIRATE(0x%x)\n", + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), + scsirate); + + if ((ahc->features & AHC_DT) != 0) { + + if ((sstat2 & CRCVALERR) != 0) + printf("\tCRC Value Mismatch\n"); + if ((sstat2 & CRCENDERR) != 0) + printf("\tNo terminal CRC packet recevied\n"); + if ((sstat2 & CRCREQERR) != 0) + printf("\tIllegal CRC packet request\n"); + if ((sstat2 & DUAL_EDGE_ERR) != 0) + printf("\tUnexpected %sDT Data Phase\n", + (scsirate & SINGLE_EDGE) ? "" : "non-"); + } + + /* + * We've set the hardware to assert ATN if we + * get a parity error on "in" phases, so all we + * need to do is stuff the message buffer with + * the appropriate message. "In" phases have set + * mesg_out to something other than MSG_NOP. + */ + if (mesg_out != MSG_NOOP) { + if (ahc->msg_type != MSG_TYPE_NONE) + ahc->send_msg_perror = TRUE; + else + ahc_outb(ahc, MSG_OUT, mesg_out); + } + /* + * Force a renegotiation with this target just in + * case we are out of sync for some external reason + * unknown (or unreported) by the target. + */ + ahc_force_renegotiation(ahc); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_unpause(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessfull + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + /* + * Force a renegotiation with this target just in + * case the cable was pulled and will later be + * re-attached. The target may forget its negotiation + * settings with us should it attempt to reselect + * during the interruption. The target will not issue + * a unit attention in this case, so we must always + * renegotiate. + */ + ahc_force_renegotiation(ahc); + ahc_restart(ahc); + } else if ((status & BUSFREE) != 0 + && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { + u_int lastphase; + u_int saved_scsiid; + u_int saved_lun; + u_int target; + u_int initiator_role_id; + char channel; + int printerror; + + /* + * Clear our selection hardware as soon as possible. + * We may have an entry in the waiting Q for this target, + * that is affected by this busfree and we don't want to + * go about selecting the target while we handle the event. + */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + + /* + * Disable busfree interrupts and clear the busfree + * interrupt status. We do this here so that several + * bus transactions occur prior to clearing the SCSIINT + * latch. It can take a bit for the clearing to take effect. + */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); + + /* + * Look at what phase we were last in. + * If its message out, chances are pretty good + * that the busfree was in response to one of + * our abort requests. + */ + lastphase = ahc_inb(ahc, LASTPHASE); + saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + saved_lun = ahc_inb(ahc, SAVED_LUN); + target = SCSIID_TARGET(ahc, saved_scsiid); + initiator_role_id = SCSIID_OUR_ID(saved_scsiid); + channel = SCSIID_CHANNEL(ahc, saved_scsiid); + printerror = 1; + + if (lastphase == P_MESGOUT) { + struct ahc_devinfo devinfo; + u_int tag; + + ahc_fetch_devinfo(ahc, &devinfo); + tag = SCB_LIST_NULL; + if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE) + || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) { + if (ahc->msgout_buf[ahc->msgout_index - 1] + == MSG_ABORT_TAG) + tag = scb->hscb->tag; + ahc_print_path(ahc, scb); + printf("SCB %d - Abort%s Completed.\n", + scb->hscb->tag, tag == SCB_LIST_NULL ? + "" : " Tag"); + ahc_abort_scbs(ahc, target, channel, + saved_lun, tag, + ROLE_INITIATOR, + CAM_REQ_ABORTED); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_1B, + MSG_BUS_DEV_RESET, TRUE)) { +#ifdef __FreeBSD__ + /* + * Don't mark the user's request for this BDR + * as completing with CAM_BDR_SENT. CAM3 + * specifies CAM_REQ_CMP. + */ + if (scb != NULL + && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV + && ahc_match_scb(ahc, scb, target, channel, + CAM_LUN_WILDCARD, + SCB_LIST_NULL, + ROLE_INITIATOR)) { + ahc_set_transaction_status(scb, CAM_REQ_CMP); + } +#endif + ahc_compile_devinfo(&devinfo, + initiator_role_id, + target, + CAM_LUN_WILDCARD, + channel, + ROLE_INITIATOR); + ahc_handle_devreset(ahc, &devinfo, + CAM_BDR_SENT, + "Bus Device Reset", + /*verbose_level*/0); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_PPR, FALSE)) { + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + + /* + * PPR Rejected. Try non-ppr negotiation + * and retry command. + */ + tinfo = ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + tinfo->curr.transport_version = 2; + tinfo->goal.transport_version = 2; + tinfo->goal.ppr_options = 0; + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_WDTR, FALSE) + || ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_SDTR, FALSE)) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ + ahc_set_width(ahc, &devinfo, + MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_set_syncrate(ahc, &devinfo, + /*syncrate*/NULL, + /*period*/0, /*offset*/0, + /*ppr_options*/0, + AHC_TRANS_CUR|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } + } + if (printerror != 0) { + u_int i; + + if (scb != NULL) { + u_int tag; + + if ((scb->hscb->control & TAG_ENB) != 0) + tag = scb->hscb->tag; + else + tag = SCB_LIST_NULL; + ahc_print_path(ahc, scb); + ahc_abort_scbs(ahc, target, channel, + SCB_GET_LUN(scb), tag, + ROLE_INITIATOR, + CAM_UNEXP_BUSFREE); + } else { + /* + * We had not fully identified this connection, + * so we cannot abort anything. + */ + printf("%s: ", ahc_name(ahc)); + } + for (i = 0; i < num_phases; i++) { + if (lastphase == ahc_phase_table[i].phase) + break; + } + printf("Unexpected busfree %s\n" + "SEQADDR == 0x%x\n", + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) + | (ahc_inb(ahc, SEQADDR1) << 8)); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_restart(ahc); + } else { + printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", + ahc_name(ahc), status); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + } +} + +/* + * Force renegotiation to occur the next time we initiate + * a command to the current device. + */ +static void +ahc_force_renegotiation(struct ahc_softc *ahc) +{ + struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + + ahc_fetch_devinfo(ahc, &devinfo); + targ_info = ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + ahc_update_neg_request(ahc, &devinfo, tstate, + targ_info, /*force*/TRUE); +} + +#define AHC_MAX_STEPS 2000 +void +ahc_clear_critical_section(struct ahc_softc *ahc) +{ + int stepping; + int steps; + u_int simode0; + u_int simode1; + + if (ahc->num_critical_sections == 0) + return; + + stepping = FALSE; + steps = 0; + simode0 = 0; + simode1 = 0; + for (;;) { + struct cs *cs; + u_int seqaddr; + u_int i; + + seqaddr = ahc_inb(ahc, SEQADDR0) + | (ahc_inb(ahc, SEQADDR1) << 8); + + /* + * Seqaddr represents the next instruction to execute, + * so we are really executing the instruction just + * before it. + */ + if (seqaddr != 0) + seqaddr -= 1; + cs = ahc->critical_sections; + for (i = 0; i < ahc->num_critical_sections; i++, cs++) { + + if (cs->begin < seqaddr && cs->end >= seqaddr) + break; + } + + if (i == ahc->num_critical_sections) + break; + + if (steps > AHC_MAX_STEPS) { + printf("%s: Infinite loop in critical section\n", + ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("critical section loop"); + } + + steps++; + if (stepping == FALSE) { + + /* + * Disable all interrupt sources so that the + * sequencer will not be stuck by a pausing + * interrupt condition while we attempt to + * leave a critical section. + */ + simode0 = ahc_inb(ahc, SIMODE0); + ahc_outb(ahc, SIMODE0, 0); + simode1 = ahc_inb(ahc, SIMODE1); + ahc_outb(ahc, SIMODE1, 0); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); + stepping = TRUE; + } + ahc_outb(ahc, HCNTRL, ahc->unpause); + while (!ahc_is_paused(ahc)) + ahc_delay(200); + } + if (stepping) { + ahc_outb(ahc, SIMODE0, simode0); + ahc_outb(ahc, SIMODE1, simode1); + ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); + } +} + +/* + * Clear any pending interrupt status. + */ +void +ahc_clear_intstat(struct ahc_softc *ahc) +{ + /* Clear any interrupt conditions this may have caused */ + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI + |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| + CLRREQINIT); + ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); + ahc_outb(ahc, CLRINT, CLRSCSIINT); +} + +/**************************** Debugging Routines ******************************/ +#ifdef AHC_DEBUG +int ahc_debug = AHC_DEBUG; +#endif + +void +ahc_print_scb(struct scb *scb) +{ + int i; + + struct hardware_scb *hscb = scb->hscb; + + printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", + (void *)scb, + hscb->control, + hscb->scsiid, + hscb->lun, + hscb->cdb_len); + printf("Shared Data: "); + for (i = 0; i < sizeof(hscb->shared_data.cdb); i++) + printf("%#02x", hscb->shared_data.cdb[i]); + printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", + ahc_le32toh(hscb->dataptr), + ahc_le32toh(hscb->datacnt), + ahc_le32toh(hscb->sgptr), + hscb->tag); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x%x : Length %d\n", + i, + (ahc_le32toh(scb->sg_list[i].len) >> 24 + & SG_HIGH_ADDR_BITS), + ahc_le32toh(scb->sg_list[i].addr), + ahc_le32toh(scb->sg_list[i].len)); + } + } +} + +/************************* Transfer Negotiation *******************************/ +/* + * Allocate per target mode instance (ID we respond to as a target) + * transfer negotiation data structures. + */ +static struct ahc_tmode_tstate * +ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) +{ + struct ahc_tmode_tstate *master_tstate; + struct ahc_tmode_tstate *tstate; + int i; + + master_tstate = ahc->enabled_targets[ahc->our_id]; + if (channel == 'B') { + scsi_id += 8; + master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; + } + if (ahc->enabled_targets[scsi_id] != NULL + && ahc->enabled_targets[scsi_id] != master_tstate) + panic("%s: ahc_alloc_tstate - Target already allocated", + ahc_name(ahc)); + tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); + if (tstate == NULL) + return (NULL); + + /* + * If we have allocated a master tstate, copy user settings from + * the master tstate (taken from SRAM or the EEPROM) for this + * channel, but reset our current and goal settings to async/narrow + * until an initiator talks to us. + */ + if (master_tstate != NULL) { + memcpy(tstate, master_tstate, sizeof(*tstate)); + memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); + tstate->ultraenb = 0; + for (i = 0; i < 16; i++) { + memset(&tstate->transinfo[i].curr, 0, + sizeof(tstate->transinfo[i].curr)); + memset(&tstate->transinfo[i].goal, 0, + sizeof(tstate->transinfo[i].goal)); + } + } else + memset(tstate, 0, sizeof(*tstate)); + ahc->enabled_targets[scsi_id] = tstate; + return (tstate); +} + +#ifdef AHC_TARGET_MODE +/* + * Free per target mode instance (ID we respond to as a target) + * transfer negotiation data structures. + */ +static void +ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) +{ + struct ahc_tmode_tstate *tstate; + + /* + * Don't clean up our "master" tstate. + * It has our default user settings. + */ + if (((channel == 'B' && scsi_id == ahc->our_id_b) + || (channel == 'A' && scsi_id == ahc->our_id)) + && force == FALSE) + return; + + if (channel == 'B') + scsi_id += 8; + tstate = ahc->enabled_targets[scsi_id]; + if (tstate != NULL) + free(tstate, M_DEVBUF); + ahc->enabled_targets[scsi_id] = NULL; +} +#endif + +/* + * Called when we have an active connection to a target on the bus, + * this function finds the nearest syncrate to the input period limited + * by the capabilities of the bus connectivity of and sync settings for + * the target. + */ +struct ahc_syncrate * +ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + u_int *period, u_int *ppr_options, role_t role) +{ + struct ahc_transinfo *transinfo; + u_int maxsync; + + if ((ahc->features & AHC_ULTRA2) != 0) { + if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 + && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { + maxsync = AHC_SYNCRATE_DT; + } else { + maxsync = AHC_SYNCRATE_ULTRA; + /* Can't do DT on an SE bus */ + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + } + } else if ((ahc->features & AHC_ULTRA) != 0) { + maxsync = AHC_SYNCRATE_ULTRA; + } else { + maxsync = AHC_SYNCRATE_FAST; + } + /* + * Never allow a value higher than our current goal + * period otherwise we may allow a target initiated + * negotiation to go above the limit as set by the + * user. In the case of an initiator initiated + * sync negotiation, we limit based on the user + * setting. This allows the system to still accept + * incoming negotiations even if target initiated + * negotiation is not performed. + */ + if (role == ROLE_TARGET) + transinfo = &tinfo->user; + else + transinfo = &tinfo->goal; + *ppr_options &= transinfo->ppr_options; + if (transinfo->period == 0) { + *period = 0; + *ppr_options = 0; + return (NULL); + } + *period = MAX(*period, transinfo->period); + return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); +} + +/* + * Look up the valid period to SCSIRATE conversion in our table. + * Return the period and offset that should be sent to the target + * if this was the beginning of an SDTR. + */ +struct ahc_syncrate * +ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options, u_int maxsync) +{ + struct ahc_syncrate *syncrate; + + if ((ahc->features & AHC_DT) == 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + /* Skip all DT only entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && maxsync < AHC_SYNCRATE_ULTRA2) + maxsync = AHC_SYNCRATE_ULTRA2; + + for (syncrate = &ahc_syncrates[maxsync]; + syncrate->rate != NULL; + syncrate++) { + + /* + * The Ultra2 table doesn't go as low + * as for the Fast/Ultra cards. + */ + if ((ahc->features & AHC_ULTRA2) != 0 + && (syncrate->sxfr_u2 == 0)) + break; + + if (*period <= syncrate->period) { + /* + * When responding to a target that requests + * sync, the requested rate may fall between + * two rates that we can output, but still be + * a rate that we can receive. Because of this, + * we want to respond to the target with + * the same rate that it sent to us even + * if the period we use to send data to it + * is lower. Only lower the response period + * if we must. + */ + if (syncrate == &ahc_syncrates[maxsync]) + *period = syncrate->period; + + /* + * At some speeds, we only support + * ST transfers. + */ + if ((syncrate->sxfr_u2 & ST_SXFR) != 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + break; + } + } + + if ((*period == 0) + || (syncrate->rate == NULL) + || ((ahc->features & AHC_ULTRA2) != 0 + && (syncrate->sxfr_u2 == 0))) { + /* Use asynchronous transfers. */ + *period = 0; + syncrate = NULL; + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + } + return (syncrate); +} + +/* + * Convert from an entry in our syncrate table to the SCSI equivalent + * sync "period" factor. + */ +u_int +ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync) +{ + struct ahc_syncrate *syncrate; + + if ((ahc->features & AHC_ULTRA2) != 0) + scsirate &= SXFR_ULTRA2; + else + scsirate &= SXFR; + + syncrate = &ahc_syncrates[maxsync]; + while (syncrate->rate != NULL) { + + if ((ahc->features & AHC_ULTRA2) != 0) { + if (syncrate->sxfr_u2 == 0) + break; + else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2)) + return (syncrate->period); + } else if (scsirate == (syncrate->sxfr & SXFR)) { + return (syncrate->period); + } + syncrate++; + } + return (0); /* async */ +} + +/* + * Truncate the given synchronous offset to a value the + * current adapter type and syncrate are capable of. + */ +void +ahc_validate_offset(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + struct ahc_syncrate *syncrate, + u_int *offset, int wide, role_t role) +{ + u_int maxoffset; + + /* Limit offset to what we can do */ + if (syncrate == NULL) { + maxoffset = 0; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + maxoffset = MAX_OFFSET_ULTRA2; + } else { + if (wide) + maxoffset = MAX_OFFSET_16BIT; + else + maxoffset = MAX_OFFSET_8BIT; + } + *offset = MIN(*offset, maxoffset); + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *offset = MIN(*offset, tinfo->user.offset); + else + *offset = MIN(*offset, tinfo->goal.offset); + } +} + +/* + * Truncate the given transfer width parameter to a value the + * current adapter type is capable of. + */ +void +ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, + u_int *bus_width, role_t role) +{ + switch (*bus_width) { + default: + if (ahc->features & AHC_WIDE) { + /* Respond Wide */ + *bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + /* FALLTHROUGH */ + case MSG_EXT_WDTR_BUS_8_BIT: + *bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; + } + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *bus_width = MIN(tinfo->user.width, *bus_width); + else + *bus_width = MIN(tinfo->goal.width, *bus_width); + } +} + +/* + * Update the bitmask of targets for which the controller should + * negotiate with at the next convenient oportunity. This currently + * means the next time we send the initial identify messages for + * a new transaction. + */ +int +ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_tmode_tstate *tstate, + struct ahc_initiator_tinfo *tinfo, int force) +{ + u_int auto_negotiate_orig; + + auto_negotiate_orig = tstate->auto_negotiate; + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options + || (force + && (tinfo->goal.period != 0 + || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT + || tinfo->goal.ppr_options != 0))) + tstate->auto_negotiate |= devinfo->target_mask; + else + tstate->auto_negotiate &= ~devinfo->target_mask; + + return (auto_negotiate_orig != tstate->auto_negotiate); +} + +/* + * Update the user/goal/curr tables of synchronous negotiation + * parameters as well as, in the case of a current or active update, + * any data structures on the host controller. In the case of an + * active update, the specified target is currently talking to us on + * the bus, so the transfer parameter update must take effect + * immediately. + */ +void +ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_syncrate *syncrate, u_int period, + u_int offset, u_int ppr_options, u_int type, int paused) +{ + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int old_period; + u_int old_offset; + u_int old_ppr; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; + + if (syncrate == NULL) { + period = 0; + offset = 0; + } + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + if ((type & AHC_TRANS_USER) != 0) { + tinfo->user.period = period; + tinfo->user.offset = offset; + tinfo->user.ppr_options = ppr_options; + } + + if ((type & AHC_TRANS_GOAL) != 0) { + tinfo->goal.period = period; + tinfo->goal.offset = offset; + tinfo->goal.ppr_options = ppr_options; + } + + old_period = tinfo->curr.period; + old_offset = tinfo->curr.offset; + old_ppr = tinfo->curr.ppr_options; + + if ((type & AHC_TRANS_CUR) != 0 + && (old_period != period + || old_offset != offset + || old_ppr != ppr_options)) { + u_int scsirate; + + update_needed++; + scsirate = tinfo->scsirate; + if ((ahc->features & AHC_ULTRA2) != 0) { + + scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); + if (syncrate != NULL) { + scsirate |= syncrate->sxfr_u2; + if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) + scsirate |= ENABLE_CRC; + else + scsirate |= SINGLE_EDGE; + } + } else { + + scsirate &= ~(SXFR|SOFS); + /* + * Ensure Ultra mode is set properly for + * this target. + */ + tstate->ultraenb &= ~devinfo->target_mask; + if (syncrate != NULL) { + if (syncrate->sxfr & ULTRA_SXFR) { + tstate->ultraenb |= + devinfo->target_mask; + } + scsirate |= syncrate->sxfr & SXFR; + scsirate |= offset & SOFS; + } + if (active) { + u_int sxfrctl0; + + sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + sxfrctl0 &= ~FAST20; + if (tstate->ultraenb & devinfo->target_mask) + sxfrctl0 |= FAST20; + ahc_outb(ahc, SXFRCTL0, sxfrctl0); + } + } + if (active) { + ahc_outb(ahc, SCSIRATE, scsirate); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIOFFSET, offset); + } + + tinfo->scsirate = scsirate; + tinfo->curr.period = period; + tinfo->curr.offset = offset; + tinfo->curr.ppr_options = ppr_options; + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + if (bootverbose) { + if (offset != 0) { + printf("%s: target %d synchronous at %sMHz%s, " + "offset = 0x%x\n", ahc_name(ahc), + devinfo->target, syncrate->rate, + (ppr_options & MSG_EXT_PPR_DT_REQ) + ? " DT" : "", offset); + } else { + printf("%s: target %d using " + "asynchronous transfers\n", + ahc_name(ahc), devinfo->target); + } + } + } + + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + + if (update_needed) + ahc_update_pending_scbs(ahc); +} + +/* + * Update the user/goal/curr tables of wide negotiation + * parameters as well as, in the case of a current or active update, + * any data structures on the host controller. In the case of an + * active update, the specified target is currently talking to us on + * the bus, so the transfer parameter update must take effect + * immediately. + */ +void +ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int width, u_int type, int paused) +{ + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int oldwidth; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + if ((type & AHC_TRANS_USER) != 0) + tinfo->user.width = width; + + if ((type & AHC_TRANS_GOAL) != 0) + tinfo->goal.width = width; + + oldwidth = tinfo->curr.width; + if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { + u_int scsirate; + + update_needed++; + scsirate = tinfo->scsirate; + scsirate &= ~WIDEXFER; + if (width == MSG_EXT_WDTR_BUS_16_BIT) + scsirate |= WIDEXFER; + + tinfo->scsirate = scsirate; + + if (active) + ahc_outb(ahc, SCSIRATE, scsirate); + + tinfo->curr.width = width; + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + if (bootverbose) { + printf("%s: target %d using %dbit transfers\n", + ahc_name(ahc), devinfo->target, + 8 * (0x01 << width)); + } + } + + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + if (update_needed) + ahc_update_pending_scbs(ahc); +} + +/* + * Update the current state of tagged queuing for a given target. + */ +void +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) +{ + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); +} + +/* + * When the transfer settings for a connection change, update any + * in-transit SCBs to contain the new data so the hardware will + * be set correctly during future (re)selections. + */ +static void +ahc_update_pending_scbs(struct ahc_softc *ahc) +{ + struct scb *pending_scb; + int pending_scb_count; + int i; + int paused; + u_int saved_scbptr; + + /* + * Traverse the pending SCB list and ensure that all of the + * SCBs there have the proper settings. + */ + pending_scb_count = 0; + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + struct ahc_devinfo devinfo; + struct hardware_scb *pending_hscb; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + + ahc_scb_devinfo(ahc, &devinfo, pending_scb); + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); + pending_hscb = pending_scb->hscb; + pending_hscb->control &= ~ULTRAENB; + if ((tstate->ultraenb & devinfo.target_mask) != 0) + pending_hscb->control |= ULTRAENB; + pending_hscb->scsirate = tinfo->scsirate; + pending_hscb->scsioffset = tinfo->curr.offset; + if ((tstate->auto_negotiate & devinfo.target_mask) == 0 + && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { + pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; + pending_hscb->control &= ~MK_MESSAGE; + } + ahc_sync_scb(ahc, pending_scb, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + pending_scb_count++; + } + + if (pending_scb_count == 0) + return; + + if (ahc_is_paused(ahc)) { + paused = 1; + } else { + paused = 0; + ahc_pause(ahc); + } + + saved_scbptr = ahc_inb(ahc, SCBPTR); + /* Ensure that the hscbs down on the card match the new information */ + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + struct hardware_scb *pending_hscb; + u_int control; + u_int scb_tag; + + ahc_outb(ahc, SCBPTR, i); + scb_tag = ahc_inb(ahc, SCB_TAG); + pending_scb = ahc_lookup_scb(ahc, scb_tag); + if (pending_scb == NULL) + continue; + + pending_hscb = pending_scb->hscb; + control = ahc_inb(ahc, SCB_CONTROL); + control &= ~(ULTRAENB|MK_MESSAGE); + control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); + ahc_outb(ahc, SCB_CONTROL, control); + ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); + ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); + } + ahc_outb(ahc, SCBPTR, saved_scbptr); + + if (paused == 0) + ahc_unpause(ahc); +} + +/**************************** Pathing Information *****************************/ +static void +ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + u_int saved_scsiid; + role_t role; + int our_id; + + if (ahc_inb(ahc, SSTAT0) & TARGET) + role = ROLE_TARGET; + else + role = ROLE_INITIATOR; + + if (role == ROLE_TARGET + && (ahc->features & AHC_MULTI_TID) != 0 + && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { + /* We were selected, so pull our id from TARGIDIN */ + our_id = ahc_inb(ahc, TARGIDIN) & OID; + } else if ((ahc->features & AHC_ULTRA2) != 0) + our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; + else + our_id = ahc_inb(ahc, SCSIID) & OID; + + saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + ahc_compile_devinfo(devinfo, + our_id, + SCSIID_TARGET(ahc, saved_scsiid), + ahc_inb(ahc, SAVED_LUN), + SCSIID_CHANNEL(ahc, saved_scsiid), + role); +} + +struct ahc_phase_table_entry* +ahc_lookup_phase_entry(int phase) +{ + struct ahc_phase_table_entry *entry; + struct ahc_phase_table_entry *last_entry; + + /* + * num_phases doesn't include the default entry which + * will be returned if the phase doesn't match. + */ + last_entry = &ahc_phase_table[num_phases]; + for (entry = ahc_phase_table; entry < last_entry; entry++) { + if (phase == entry->phase) + break; + } + return (entry); +} + +void +ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, + u_int lun, char channel, role_t role) +{ + devinfo->our_scsiid = our_id; + devinfo->target = target; + devinfo->lun = lun; + devinfo->target_offset = target; + devinfo->channel = channel; + devinfo->role = role; + if (channel == 'B') + devinfo->target_offset += 8; + devinfo->target_mask = (0x01 << devinfo->target_offset); +} + +static void +ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + role_t role; + int our_id; + + our_id = SCSIID_OUR_ID(scb->hscb->scsiid); + role = ROLE_INITIATOR; + if ((scb->hscb->control & TARGET_SCB) != 0) + role = ROLE_TARGET; + ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb), + SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role); +} + + +/************************ Message Phase Processing ****************************/ +static void +ahc_assert_atn(struct ahc_softc *ahc) +{ + u_int scsisigo; + + scsisigo = ATNO; + if ((ahc->features & AHC_DT) == 0) + scsisigo |= ahc_inb(ahc, SCSISIGI); + ahc_outb(ahc, SCSISIGO, scsisigo); +} + +/* + * When an initiator transaction with the MK_MESSAGE flag either reconnects + * or enters the initial message out phase, we are interrupted. Fill our + * outgoing message buffer with the appropriate message and beging handing + * the message phase(s) manually. + */ +static void +ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + /* + * To facilitate adding multiple messages together, + * each routine should increment the index and len + * variables instead of setting them explicitly. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + + if ((scb->flags & SCB_DEVICE_RESET) == 0 + && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { + u_int identify_msg; + + identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); + if ((scb->hscb->control & DISCENB) != 0) + identify_msg |= MSG_IDENTIFY_DISCFLAG; + ahc->msgout_buf[ahc->msgout_index++] = identify_msg; + ahc->msgout_len++; + + if ((scb->hscb->control & TAG_ENB) != 0) { + ahc->msgout_buf[ahc->msgout_index++] = + scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); + ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; + ahc->msgout_len += 2; + } + } + + if (scb->flags & SCB_DEVICE_RESET) { + ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; + ahc->msgout_len++; + ahc_print_path(ahc, scb); + printf("Bus Device Reset Message Sent\n"); + /* + * Clear our selection hardware in advance of + * the busfree. We may have an entry in the waiting + * Q for this target, and we don't want to go about + * selecting while we handle the busfree and blow it + * away. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else if ((scb->flags & SCB_ABORT) != 0) { + if ((scb->hscb->control & TAG_ENB) != 0) + ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; + else + ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; + ahc->msgout_len++; + ahc_print_path(ahc, scb); + printf("Abort%s Message Sent\n", + (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); + /* + * Clear our selection hardware in advance of + * the busfree. We may have an entry in the waiting + * Q for this target, and we don't want to go about + * selecting while we handle the busfree and blow it + * away. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { + ahc_build_transfer_msg(ahc, devinfo); + } else { + printf("ahc_intr: AWAITING_MSG for an SCB that " + "does not have a waiting message\n"); + printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, + devinfo->target_mask); + panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " + "SCB flags = %x", scb->hscb->tag, scb->hscb->control, + ahc_inb(ahc, MSG_OUT), scb->flags); + } + + /* + * Clear the MK_MESSAGE flag from the SCB so we aren't + * asked to send this message again. + */ + ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + scb->hscb->control &= ~MK_MESSAGE; + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; +} + +/* + * Build an appropriate transfer negotiation message for the + * currently active target. + */ +static void +ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + /* + * We need to initiate transfer negotiations. + * If our current and goal settings are identical, + * we want to renegotiate due to a check condition. + */ + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + struct ahc_syncrate *rate; + int dowide; + int dosync; + int doppr; + int use_ppr; + u_int period; + u_int ppr_options; + u_int offset; + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + /* Target initiated PPR is not allowed in the SCSI spec */ + if (devinfo->role == ROLE_TARGET) + ppr_options = 0; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + dowide = tinfo->curr.width != tinfo->goal.width; + dosync = tinfo->curr.period != period; + doppr = tinfo->curr.ppr_options != ppr_options; + + if (!dowide && !dosync && !doppr) { + dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; + dosync = tinfo->goal.period != 0; + doppr = tinfo->goal.ppr_options != 0; + } + + if (!dowide && !dosync && !doppr) { + panic("ahc_intr: AWAITING_MSG for negotiation, " + "but no negotiation needed\n"); + } + + use_ppr = (tinfo->curr.transport_version >= 3) || doppr; + /* Target initiated PPR is not allowed in the SCSI spec */ + if (devinfo->role == ROLE_TARGET) + use_ppr = 0; + + /* + * Both the PPR message and SDTR message require the + * goal syncrate to be limited to what the target device + * is capable of handling (based on whether an LVD->SE + * expander is on the bus), so combine these two cases. + * Regardless, guarantee that if we are using WDTR and SDTR + * messages that WDTR comes first. + */ + if (use_ppr || (dosync && !dowide)) { + + offset = tinfo->goal.offset; + ahc_validate_offset(ahc, tinfo, rate, &offset, + use_ppr ? tinfo->goal.width + : tinfo->curr.width, + devinfo->role); + if (use_ppr) { + ahc_construct_ppr(ahc, devinfo, period, offset, + tinfo->goal.width, ppr_options); + } else { + ahc_construct_sdtr(ahc, devinfo, period, offset); + } + } else { + ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width); + } +} + +/* + * Build a synchronous negotiation message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int period, u_int offset) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR; + ahc->msgout_buf[ahc->msgout_index++] = period; + ahc->msgout_buf[ahc->msgout_index++] = offset; + ahc->msgout_len += 5; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, period, offset); + } +} + +/* + * Build a wide negotiation message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int bus_width) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR; + ahc->msgout_buf[ahc->msgout_index++] = bus_width; + ahc->msgout_len += 4; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending WDTR %x\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, bus_width); + } +} + +/* + * Build a parallel protocol request message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int period, u_int offset, u_int bus_width, + u_int ppr_options) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR; + ahc->msgout_buf[ahc->msgout_index++] = period; + ahc->msgout_buf[ahc->msgout_index++] = 0; + ahc->msgout_buf[ahc->msgout_index++] = offset; + ahc->msgout_buf[ahc->msgout_index++] = bus_width; + ahc->msgout_buf[ahc->msgout_index++] = ppr_options; + ahc->msgout_len += 8; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " + "offset %x, ppr_options %x\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun, + bus_width, period, offset, ppr_options); + } +} + +/* + * Clear any active message state. + */ +static void +ahc_clear_msg_state(struct ahc_softc *ahc) +{ + ahc->msgout_len = 0; + ahc->msgin_index = 0; + ahc->msg_type = MSG_TYPE_NONE; + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { + /* + * The target didn't care to respond to our + * message request, so clear ATN. + */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + } + ahc_outb(ahc, MSG_OUT, MSG_NOOP); + ahc_outb(ahc, SEQ_FLAGS2, + ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); +} + +/* + * Manual message loop handler. + */ +static void +ahc_handle_message_phase(struct ahc_softc *ahc) +{ + struct ahc_devinfo devinfo; + u_int bus_phase; + int end_session; + + ahc_fetch_devinfo(ahc, &devinfo); + end_session = FALSE; + bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + +reswitch: + switch (ahc->msg_type) { + case MSG_TYPE_INITIATOR_MSGOUT: + { + int lastbyte; + int phasemis; + int msgdone; + + if (ahc->msgout_len == 0) + panic("HOST_MSG_LOOP interrupt with no active message"); + + phasemis = bus_phase != P_MESGOUT; + if (phasemis) { + if (bus_phase == P_MESGIN) { + /* + * Change gears and see if + * this messages is of interest to + * us or should be passed back to + * the sequencer. + */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + ahc->send_msg_perror = FALSE; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; + ahc->msgin_index = 0; + goto reswitch; + } + end_session = TRUE; + break; + } + + if (ahc->send_msg_perror) { + ahc_outb(ahc, CLRSINT1, CLRATNO); + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); + break; + } + + msgdone = ahc->msgout_index == ahc->msgout_len; + if (msgdone) { + /* + * The target has requested a retry. + * Re-assert ATN, reset our message index to + * 0, and try again. + */ + ahc->msgout_index = 0; + ahc_assert_atn(ahc); + } + + lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); + if (lastbyte) { + /* Last byte is signified by dropping ATN */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + } + + /* + * Clear our interrupt status and present + * the next byte on the bus. + */ + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); + break; + } + case MSG_TYPE_INITIATOR_MSGIN: + { + int phasemis; + int message_done; + + phasemis = bus_phase != P_MESGIN; + + if (phasemis) { + ahc->msgin_index = 0; + if (bus_phase == P_MESGOUT + && (ahc->send_msg_perror == TRUE + || (ahc->msgout_len != 0 + && ahc->msgout_index == 0))) { + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + goto reswitch; + } + end_session = TRUE; + break; + } + + /* Pull the byte in without acking it */ + ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); + + message_done = ahc_parse_msg(ahc, &devinfo); + + if (message_done) { + /* + * Clear our incoming message buffer in case there + * is another message following this one. + */ + ahc->msgin_index = 0; + + /* + * If this message illicited a response, + * assert ATN so the target takes us to the + * message out phase. + */ + if (ahc->msgout_len != 0) + ahc_assert_atn(ahc); + } else + ahc->msgin_index++; + + /* Ack the byte */ + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_inb(ahc, SCSIDATL); + break; + } + case MSG_TYPE_TARGET_MSGIN: + { + int msgdone; + int msgout_request; + + if (ahc->msgout_len == 0) + panic("Target MSGIN with no active message"); + + /* + * If we interrupted a mesgout session, the initiator + * will not know this until our first REQ. So, we + * only honor mesgout requests after we've sent our + * first byte. + */ + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 + && ahc->msgout_index > 0) + msgout_request = TRUE; + else + msgout_request = FALSE; + + if (msgout_request) { + + /* + * Change gears and see if + * this messages is of interest to + * us or should be passed back to + * the sequencer. + */ + ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; + ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); + ahc->msgin_index = 0; + /* Dummy read to REQ for first byte */ + ahc_inb(ahc, SCSIDATL); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + break; + } + + msgdone = ahc->msgout_index == ahc->msgout_len; + if (msgdone) { + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); + end_session = TRUE; + break; + } + + /* + * Present the next byte on the bus. + */ + ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); + ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); + break; + } + case MSG_TYPE_TARGET_MSGOUT: + { + int lastbyte; + int msgdone; + + /* + * The initiator signals that this is + * the last byte by dropping ATN. + */ + lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0; + + /* + * Read the latched byte, but turn off SPIOEN first + * so that we don't inadvertantly cause a REQ for the + * next byte. + */ + ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); + ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); + msgdone = ahc_parse_msg(ahc, &devinfo); + if (msgdone == MSGLOOP_TERMINATED) { + /* + * The message is *really* done in that it caused + * us to go to bus free. The sequencer has already + * been reset at this point, so pull the ejection + * handle. + */ + return; + } + + ahc->msgin_index++; + + /* + * XXX Read spec about initiator dropping ATN too soon + * and use msgdone to detect it. + */ + if (msgdone == MSGLOOP_MSGCOMPLETE) { + ahc->msgin_index = 0; + + /* + * If this message illicited a response, transition + * to the Message in phase and send it. + */ + if (ahc->msgout_len != 0) { + ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + ahc->msg_type = MSG_TYPE_TARGET_MSGIN; + ahc->msgin_index = 0; + break; + } + } + + if (lastbyte) + end_session = TRUE; + else { + /* Ask for the next byte. */ + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + } + + break; + } + default: + panic("Unknown REQINIT message type"); + } + + if (end_session) { + ahc_clear_msg_state(ahc); + ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); + } else + ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); +} + +/* + * See if we sent a particular extended message to the target. + * If "full" is true, return true only if the target saw the full + * message. If "full" is false, return true if the target saw at + * least the first byte of the message. + */ +static int +ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) +{ + int found; + u_int index; + + found = FALSE; + index = 0; + + while (index < ahc->msgout_len) { + if (ahc->msgout_buf[index] == MSG_EXTENDED) { + u_int end_index; + + end_index = index + 1 + ahc->msgout_buf[index + 1]; + if (ahc->msgout_buf[index+2] == msgval + && type == AHCMSG_EXT) { + + if (full) { + if (ahc->msgout_index > end_index) + found = TRUE; + } else if (ahc->msgout_index > index) + found = TRUE; + } + index = end_index; + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK + && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { + + /* Skip tag type and tag id or residue param*/ + index += 2; + } else { + /* Single byte message */ + if (type == AHCMSG_1B + && ahc->msgout_buf[index] == msgval + && ahc->msgout_index > index) + found = TRUE; + index++; + } + + if (found) + break; + } + return (found); +} + +/* + * Wait for a complete incoming message, parse it, and respond accordingly. + */ +static int +ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + int reject; + int done; + int response; + u_int targ_scsirate; + + done = MSGLOOP_IN_PROG; + response = FALSE; + reject = FALSE; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + targ_scsirate = tinfo->scsirate; + + /* + * Parse as much of the message as is availible, + * rejecting it if we don't support it. When + * the entire message is availible and has been + * handled, return MSGLOOP_MSGCOMPLETE, indicating + * that we have parsed an entire message. + * + * In the case of extended messages, we accept the length + * byte outright and perform more checking once we know the + * extended message type. + */ + switch (ahc->msgin_buf[0]) { + case MSG_MESSAGE_REJECT: + response = ahc_handle_msg_reject(ahc, devinfo); + /* FALLTHROUGH */ + case MSG_NOOP: + done = MSGLOOP_MSGCOMPLETE; + break; + case MSG_EXTENDED: + { + /* Wait for enough of the message to begin validation */ + if (ahc->msgin_index < 2) + break; + switch (ahc->msgin_buf[2]) { + case MSG_EXT_SDTR: + { + struct ahc_syncrate *syncrate; + u_int period; + u_int ppr_options; + u_int offset; + u_int saved_offset; + + if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have both args before validating + * and acting on this message. + * + * Add one to MSG_EXT_SDTR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) + break; + + period = ahc->msgin_buf[3]; + ppr_options = 0; + saved_offset = offset = ahc->msgin_buf[4]; + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, &offset, + targ_scsirate & WIDEXFER, + devinfo->role); + if (bootverbose) { + printf("(%s:%c:%d:%d): Received " + "SDTR period %x, offset %x\n\t" + "Filtered to period %x, offset %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + ahc->msgin_buf[3], saved_offset, + period, offset); + } + ahc_set_syncrate(ahc, devinfo, + syncrate, period, + offset, ppr_options, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + + /* + * See if we initiated Sync Negotiation + * and didn't have to fall down to async + * transfers. + */ + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) { + /* We started it */ + if (saved_offset != offset) { + /* Went too low - force async */ + reject = TRUE; + } + } else { + /* + * Send our own SDTR in reply + */ + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { + printf("(%s:%c:%d:%d): Target " + "Initiated SDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_sdtr(ahc, devinfo, + period, offset); + ahc->msgout_index = 0; + response = TRUE; + } + done = MSGLOOP_MSGCOMPLETE; + break; + } + case MSG_EXT_WDTR: + { + u_int bus_width; + u_int saved_width; + u_int sending_reply; + + sending_reply = FALSE; + if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have our arg before validating + * and acting on this message. + * + * Add one to MSG_EXT_WDTR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) + break; + + bus_width = ahc->msgin_buf[3]; + saved_width = bus_width; + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); + if (bootverbose) { + printf("(%s:%c:%d:%d): Received WDTR " + "%x filtered to %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + saved_width, bus_width); + } + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) { + /* + * Don't send a WDTR back to the + * target, since we asked first. + * If the width went higher than our + * request, reject it. + */ + if (saved_width > bus_width) { + reject = TRUE; + printf("(%s:%c:%d:%d): requested %dBit " + "transfers. Rejecting...\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + 8 * (0x01 << bus_width)); + bus_width = 0; + } + } else { + /* + * Send our own WDTR in reply + */ + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { + printf("(%s:%c:%d:%d): Target " + "Initiated WDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_wdtr(ahc, devinfo, bus_width); + ahc->msgout_index = 0; + response = TRUE; + sending_reply = TRUE; + } + ahc_set_width(ahc, devinfo, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + /* After a wide message, we are async */ + ahc_set_syncrate(ahc, devinfo, + /*syncrate*/NULL, /*period*/0, + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_ACTIVE, /*paused*/TRUE); + if (sending_reply == FALSE && reject == FALSE) { + + if (tinfo->goal.period) { + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = TRUE; + } + } + done = MSGLOOP_MSGCOMPLETE; + break; + } + case MSG_EXT_PPR: + { + struct ahc_syncrate *syncrate; + u_int period; + u_int offset; + u_int bus_width; + u_int ppr_options; + u_int saved_width; + u_int saved_offset; + u_int saved_ppr_options; + + if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have all args before validating + * and acting on this message. + * + * Add one to MSG_EXT_PPR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1)) + break; + + period = ahc->msgin_buf[3]; + offset = ahc->msgin_buf[5]; + bus_width = ahc->msgin_buf[6]; + saved_width = bus_width; + ppr_options = ahc->msgin_buf[7]; + /* + * According to the spec, a DT only + * period factor with no DT option + * set implies async. + */ + if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && period == 9) + offset = 0; + saved_ppr_options = ppr_options; + saved_offset = offset; + + /* + * Mask out any options we don't support + * on any controller. Transfer options are + * only available if we are negotiating wide. + */ + ppr_options &= MSG_EXT_PPR_DT_REQ; + if (bus_width == 0) + ppr_options = 0; + + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, + &offset, bus_width, + devinfo->role); + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) { + /* + * If we are unable to do any of the + * requested options (we went too low), + * then we'll have to reject the message. + */ + if (saved_width > bus_width + || saved_offset != offset + || saved_ppr_options != ppr_options) { + reject = TRUE; + period = 0; + offset = 0; + bus_width = 0; + ppr_options = 0; + syncrate = NULL; + } + } else { + if (devinfo->role != ROLE_TARGET) + printf("(%s:%c:%d:%d): Target " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + else + printf("(%s:%c:%d:%d): Initiator " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_ppr(ahc, devinfo, period, offset, + bus_width, ppr_options); + ahc->msgout_index = 0; + response = TRUE; + } + if (bootverbose) { + printf("(%s:%c:%d:%d): Received PPR width %x, " + "period %x, offset %x,options %x\n" + "\tFiltered to width %x, period %x, " + "offset %x, options %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + saved_width, ahc->msgin_buf[3], + saved_offset, saved_ppr_options, + bus_width, period, offset, ppr_options); + } + ahc_set_width(ahc, devinfo, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_set_syncrate(ahc, devinfo, + syncrate, period, + offset, ppr_options, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + done = MSGLOOP_MSGCOMPLETE; + break; + } + default: + /* Unknown extended message. Reject it. */ + reject = TRUE; + break; + } + break; + } +#ifdef AHC_TARGET_MODE + case MSG_BUS_DEV_RESET: + ahc_handle_devreset(ahc, devinfo, + CAM_BDR_SENT, + "Bus Device Reset Received", + /*verbose_level*/0); + ahc_restart(ahc); + done = MSGLOOP_TERMINATED; + break; + case MSG_ABORT_TAG: + case MSG_ABORT: + case MSG_CLEAR_QUEUE: + { + int tag; + + /* Target mode messages */ + if (devinfo->role != ROLE_TARGET) { + reject = TRUE; + break; + } + tag = SCB_LIST_NULL; + if (ahc->msgin_buf[0] == MSG_ABORT_TAG) + tag = ahc_inb(ahc, INITIATOR_TAG); + ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, + devinfo->lun, tag, ROLE_TARGET, + CAM_REQ_ABORTED); + + tstate = ahc->enabled_targets[devinfo->our_scsiid]; + if (tstate != NULL) { + struct ahc_tmode_lstate* lstate; + + lstate = tstate->enabled_luns[devinfo->lun]; + if (lstate != NULL) { + ahc_queue_lstate_event(ahc, lstate, + devinfo->our_scsiid, + ahc->msgin_buf[0], + /*arg*/tag); + ahc_send_lstate_events(ahc, lstate); + } + } + ahc_restart(ahc); + done = MSGLOOP_TERMINATED; + break; + } +#endif + case MSG_TERM_IO_PROC: + default: + reject = TRUE; + break; + } + + if (reject) { + /* + * Setup to reject the message. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 1; + ahc->msgout_buf[0] = MSG_MESSAGE_REJECT; + done = MSGLOOP_MSGCOMPLETE; + response = TRUE; + } + + if (done != MSGLOOP_IN_PROG && !response) + /* Clear the outgoing message buffer */ + ahc->msgout_len = 0; + + return (done); +} + +/* + * Process a message reject message. + */ +static int +ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + /* + * What we care about here is if we had an + * outstanding SDTR or WDTR message for this + * target. If we did, this is a signal that + * the target is refusing negotiation. + */ + struct scb *scb; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int scb_index; + u_int last_msg; + int response = 0; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, + devinfo->our_scsiid, + devinfo->target, &tstate); + /* Might be necessary */ + last_msg = ahc_inb(ahc, LAST_MSG); + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { + /* + * Target does not support the PPR message. + * Attempt to negotiate SPI-2 style. + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): PPR Rejected. " + "Trying WDTR/SDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + tinfo->goal.ppr_options = 0; + tinfo->curr.transport_version = 2; + tinfo->goal.transport_version = 2; + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = 1; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { + + /* note 8bit xfers */ + printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " + "8bit transfers\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + /* + * No need to clear the sync rate. If the target + * did not accept the command, our syncrate is + * unaffected. If the target started the negotiation, + * but rejected our response, we already cleared the + * sync rate before sending our WDTR. + */ + if (tinfo->goal.period) { + + /* Start the sync negotiation */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = 1; + } + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { + /* note asynch xfers and clear flag */ + ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0, + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + printf("(%s:%c:%d:%d): refuses synchronous negotiation. " + "Using asynchronous transfers\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; + + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } + + /* + * Resend the identify for this CCB as the target + * may believe that the selection is invalid otherwise. + */ + ahc_outb(ahc, SCB_CONTROL, + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; + ahc_set_transaction_tag(scb, /*enabled*/FALSE, + /*type*/MSG_SIMPLE_TASK); + ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); + ahc_assert_atn(ahc); + + /* + * This transaction is now at the head of + * the untagged queue for this target. + */ + if ((ahc->flags & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + + untagged_q = + &(ahc->untagged_queues[devinfo->target_offset]); + TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; + } + ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), + scb->hscb->tag); + + /* + * Requeue all tagged commands for this target + * currently in our posession so they can be + * converted to untagged commands. + */ + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, + ROLE_INITIATOR, CAM_REQUEUE_REQ, + SEARCH_COMPLETE); + } else { + /* + * Otherwise, we ignore it. + */ + printf("%s:%c:%d: Message reject for %x -- ignored\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + last_msg); + } + return (response); +} + +/* + * Process an ingnore wide residue message. + */ +static void +ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + u_int scb_index; + struct scb *scb; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + /* + * XXX Actually check data direction in the sequencer? + * Perhaps add datadir to some spare bits in the hscb? + */ + if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 + || ahc_get_transfer_dir(scb) != CAM_DIR_IN) { + /* + * Ignore the message if we haven't + * seen an appropriate data phase yet. + */ + } else { + /* + * If the residual occurred on the last + * transfer and the transfer request was + * expected to end on an odd count, do + * nothing. Otherwise, subtract a byte + * and update the residual count accordingly. + */ + uint32_t sgptr; + + sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); + if ((sgptr & SG_LIST_NULL) != 0 + && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { + /* + * If the residual occurred on the last + * transfer and the transfer request was + * expected to end on an odd count, do + * nothing. + */ + } else { + struct ahc_dma_seg *sg; + uint32_t data_cnt; + uint32_t data_addr; + uint32_t sglen; + + /* Pull in the rest of the sgptr */ + sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); + sgptr &= SG_PTR_MASK; + data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); + + data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) + | (ahc_inb(ahc, SHADDR + 2) << 16) + | (ahc_inb(ahc, SHADDR + 1) << 8) + | (ahc_inb(ahc, SHADDR)); + + data_cnt += 1; + data_addr -= 1; + + sg = ahc_sg_bus_to_virt(scb, sgptr); + /* + * The residual sg ptr points to the next S/G + * to load so we must go back one. + */ + sg--; + sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; + if (sg != scb->sg_list + && sglen < (data_cnt & AHC_SG_LEN_MASK)) { + + sg--; + sglen = ahc_le32toh(sg->len); + /* + * Preserve High Address and SG_LIST bits + * while setting the count to 1. + */ + data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK)); + data_addr = ahc_le32toh(sg->addr) + + (sglen & AHC_SG_LEN_MASK) - 1; + + /* + * Increment sg so it points to the + * "next" sg. + */ + sg++; + sgptr = ahc_sg_virt_to_bus(scb, sg); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, + sgptr >> 24); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, + sgptr >> 16); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, + sgptr >> 8); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); + } + + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + } + } +} + + +/* + * Reinitialize the data pointers for the active transfer + * based on its current residual. + */ +static void +ahc_reinitialize_dataptrs(struct ahc_softc *ahc) +{ + struct scb *scb; + struct ahc_dma_seg *sg; + u_int scb_index; + uint32_t sgptr; + uint32_t resid; + uint32_t dataptr; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + sgptr = (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8) + | ahc_inb(ahc, SCB_RESIDUAL_SGPTR); + + sgptr &= SG_PTR_MASK; + sg = ahc_sg_bus_to_virt(scb, sgptr); + + /* The residual sg_ptr always points to the next sg */ + sg--; + + resid = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8) + | ahc_inb(ahc, SCB_RESIDUAL_DATACNT); + + dataptr = ahc_le32toh(sg->addr) + + (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK) + - resid; + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + u_int dscommand1; + + dscommand1 = ahc_inb(ahc, DSCOMMAND1); + ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); + ahc_outb(ahc, HADDR, + (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS); + ahc_outb(ahc, DSCOMMAND1, dscommand1); + } + ahc_outb(ahc, HADDR + 3, dataptr >> 24); + ahc_outb(ahc, HADDR + 2, dataptr >> 16); + ahc_outb(ahc, HADDR + 1, dataptr >> 8); + ahc_outb(ahc, HADDR, dataptr); + ahc_outb(ahc, HCNT + 2, resid >> 16); + ahc_outb(ahc, HCNT + 1, resid >> 8); + ahc_outb(ahc, HCNT, resid); + if ((ahc->features & AHC_ULTRA2) == 0) { + ahc_outb(ahc, STCNT + 2, resid >> 16); + ahc_outb(ahc, STCNT + 1, resid >> 8); + ahc_outb(ahc, STCNT, resid); + } +} + +/* + * Handle the effects of issuing a bus device reset message. + */ +static void +ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + cam_status status, char *message, int verbose_level) +{ +#ifdef AHC_TARGET_MODE + struct ahc_tmode_tstate* tstate; + u_int lun; +#endif + int found; + + found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, + CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role, + status); + +#ifdef AHC_TARGET_MODE + /* + * Send an immediate notify ccb to all target mord peripheral + * drivers affected by this action. + */ + tstate = ahc->enabled_targets[devinfo->our_scsiid]; + if (tstate != NULL) { + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct ahc_tmode_lstate* lstate; + + lstate = tstate->enabled_luns[lun]; + if (lstate == NULL) + continue; + + ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid, + MSG_BUS_DEV_RESET, /*arg*/0); + ahc_send_lstate_events(ahc, lstate); + } + } +#endif + + /* + * Go back to async/narrow transfers and renegotiate. + */ + ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR, /*paused*/TRUE); + ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, + /*period*/0, /*offset*/0, /*ppr_options*/0, + AHC_TRANS_CUR, /*paused*/TRUE); + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + + if (message != NULL + && (verbose_level <= bootverbose)) + printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), + message, devinfo->channel, devinfo->target, found); +} + +#ifdef AHC_TARGET_MODE +static void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + + /* + * To facilitate adding multiple messages together, + * each routine should increment the index and len + * variables instead of setting them explicitly. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + + if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) + ahc_build_transfer_msg(ahc, devinfo); + else + panic("ahc_intr: AWAITING target message with no message"); + + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_TARGET_MSGIN; +} +#endif +/**************************** Initialization **********************************/ +/* + * Allocate a controller structure for a new device + * and perform initial initializion. + */ +struct ahc_softc * +ahc_alloc(void *platform_arg, char *name) +{ + struct ahc_softc *ahc; + int i; + +#ifndef __FreeBSD__ + ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT); + if (!ahc) { + printf("aic7xxx: cannot malloc softc!\n"); + free(name, M_DEVBUF); + return NULL; + } +#else + ahc = device_get_softc((device_t)platform_arg); +#endif + memset(ahc, 0, sizeof(*ahc)); + LIST_INIT(&ahc->pending_scbs); + /* We don't know our unit number until the OSM sets it */ + ahc->name = name; + ahc->unit = -1; + ahc->description = NULL; + ahc->channel = 'A'; + ahc->channel_b = 'B'; + ahc->chip = AHC_NONE; + ahc->features = AHC_FENONE; + ahc->bugs = AHC_BUGNONE; + ahc->flags = AHC_FNONE; + + for (i = 0; i < 16; i++) + TAILQ_INIT(&ahc->untagged_queues[i]); + if (ahc_platform_alloc(ahc, platform_arg) != 0) { + ahc_free(ahc); + ahc = NULL; + } + return (ahc); +} + +int +ahc_softc_init(struct ahc_softc *ahc) +{ + + /* The IRQMS bit is only valid on VL and EISA chips */ + if ((ahc->chip & AHC_PCI) == 0) + ahc->unpause = ahc_inb(ahc, HCNTRL) & IRQMS; + else + ahc->unpause = 0; + ahc->pause = ahc->unpause | PAUSE; + /* XXX The shared scb data stuff should be deprecated */ + if (ahc->scb_data == NULL) { + ahc->scb_data = malloc(sizeof(*ahc->scb_data), + M_DEVBUF, M_NOWAIT); + if (ahc->scb_data == NULL) + return (ENOMEM); + memset(ahc->scb_data, 0, sizeof(*ahc->scb_data)); + } + + return (0); +} + +void +ahc_softc_insert(struct ahc_softc *ahc) +{ + struct ahc_softc *list_ahc; + +#if AHC_PCI_CONFIG > 0 + /* + * Second Function PCI devices need to inherit some + * settings from function 0. + */ + if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI + && (ahc->features & AHC_MULTI_FUNC) != 0) { + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + ahc_dev_softc_t list_pci; + ahc_dev_softc_t pci; + + list_pci = list_ahc->dev_softc; + pci = ahc->dev_softc; + if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + struct ahc_softc *master; + struct ahc_softc *slave; + + if (ahc_get_pci_function(list_pci) == 0) { + master = list_ahc; + slave = ahc; + } else { + master = ahc; + slave = list_ahc; + } + slave->flags &= ~AHC_BIOS_ENABLED; + slave->flags |= + master->flags & AHC_BIOS_ENABLED; + slave->flags &= ~AHC_PRIMARY_CHANNEL; + slave->flags |= + master->flags & AHC_PRIMARY_CHANNEL; + break; + } + } + } +#endif + + /* + * Insertion sort into our list of softcs. + */ + list_ahc = TAILQ_FIRST(&ahc_tailq); + while (list_ahc != NULL + && ahc_softc_comp(list_ahc, ahc) <= 0) + list_ahc = TAILQ_NEXT(list_ahc, links); + if (list_ahc != NULL) + TAILQ_INSERT_BEFORE(list_ahc, ahc, links); + else + TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links); + ahc->init_level++; +} + +void +ahc_set_unit(struct ahc_softc *ahc, int unit) +{ + ahc->unit = unit; +} + +void +ahc_set_name(struct ahc_softc *ahc, char *name) +{ + if (ahc->name != NULL) + free(ahc->name, M_DEVBUF); + ahc->name = name; +} + +void +ahc_free(struct ahc_softc *ahc) +{ + int i; + + ahc_fini_scbdata(ahc); + switch (ahc->init_level) { + default: + case 5: + ahc_shutdown(ahc); + TAILQ_REMOVE(&ahc_tailq, ahc, links); + /* FALLTHROUGH */ + case 4: + ahc_dmamap_unload(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap); + /* FALLTHROUGH */ + case 3: + ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, + ahc->shared_data_dmamap); + ahc_dmamap_destroy(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap); + /* FALLTHROUGH */ + case 2: + ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); + case 1: +#ifndef __linux__ + ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); +#endif + break; + case 0: + break; + } + +#ifndef __linux__ + ahc_dma_tag_destroy(ahc, ahc->parent_dmat); +#endif + ahc_platform_free(ahc); + for (i = 0; i < AHC_NUM_TARGETS; i++) { + struct ahc_tmode_tstate *tstate; + + tstate = ahc->enabled_targets[i]; + if (tstate != NULL) { +#if AHC_TARGET_MODE + int j; + + for (j = 0; j < AHC_NUM_LUNS; j++) { + struct ahc_tmode_lstate *lstate; + + lstate = tstate->enabled_luns[j]; + if (lstate != NULL) { + xpt_free_path(lstate->path); + free(lstate, M_DEVBUF); + } + } +#endif + free(tstate, M_DEVBUF); + } + } +#if AHC_TARGET_MODE + if (ahc->black_hole != NULL) { + xpt_free_path(ahc->black_hole->path); + free(ahc->black_hole, M_DEVBUF); + } +#endif + if (ahc->name != NULL) + free(ahc->name, M_DEVBUF); +#ifndef __FreeBSD__ + free(ahc, M_DEVBUF); +#endif + return; +} + +void +ahc_shutdown(void *arg) +{ + struct ahc_softc *ahc; + int i; + + ahc = (struct ahc_softc *)arg; + + /* This will reset most registers to 0, but not all */ + ahc_reset(ahc); + ahc_outb(ahc, SCSISEQ, 0); + ahc_outb(ahc, SXFRCTL0, 0); + ahc_outb(ahc, DSPCISTATUS, 0); + + for (i = TARG_SCSIRATE; i < SCSICONF; i++) + ahc_outb(ahc, i, 0); +} + +/* + * Reset the controller and record some information about it + * that is only availabel just after a reset. + */ +int +ahc_reset(struct ahc_softc *ahc) +{ + u_int sblkctl; + u_int sxfrctl1_a, sxfrctl1_b; + int wait; + + /* + * Preserve the value of the SXFRCTL1 register for all channels. + * It contains settings that affect termination and we don't want + * to disturb the integrity of the bus. + */ + ahc_pause(ahc); + sxfrctl1_b = 0; + if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { + u_int sblkctl; + + /* + * Save channel B's settings in case this chip + * is setup for TWIN channel operation. + */ + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); + sxfrctl1_b = ahc_inb(ahc, SXFRCTL1); + ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); + } + sxfrctl1_a = ahc_inb(ahc, SXFRCTL1); + + ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); + + /* + * Ensure that the reset has finished + */ + wait = 1000; + while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)) + ahc_delay(1000); + + if (wait == 0) { + printf("%s: WARNING - Failed chip reset! " + "Trying to initialize anyway.\n", ahc_name(ahc)); + } + ahc_outb(ahc, HCNTRL, ahc->pause); + + /* Determine channel configuration */ + sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE); + /* No Twin Channel PCI cards */ + if ((ahc->chip & AHC_PCI) != 0) + sblkctl &= ~SELBUSB; + switch (sblkctl) { + case 0: + /* Single Narrow Channel */ + break; + case 2: + /* Wide Channel */ + ahc->features |= AHC_WIDE; + break; + case 8: + /* Twin Channel */ + ahc->features |= AHC_TWIN; + break; + default: + printf(" Unsupported adapter type. Ignoring\n"); + return(-1); + } + + /* + * Reload sxfrctl1. + * + * We must always initialize STPWEN to 1 before we + * restore the saved values. STPWEN is initialized + * to a tri-state condition which can only be cleared + * by turning it on. + */ + if ((ahc->features & AHC_TWIN) != 0) { + u_int sblkctl; + + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); + ahc_outb(ahc, SXFRCTL1, sxfrctl1_b); + ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); + } + ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); + +#ifdef AHC_DUMP_SEQ + if (ahc->init_level == 0) + ahc_dumpseq(ahc); +#endif + + return (0); +} + +/* + * Determine the number of SCBs available on the controller + */ +int +ahc_probe_scbs(struct ahc_softc *ahc) { + int i; + + for (i = 0; i < AHC_SCB_MAX; i++) { + + ahc_outb(ahc, SCBPTR, i); + ahc_outb(ahc, SCB_BASE, i); + if (ahc_inb(ahc, SCB_BASE) != i) + break; + ahc_outb(ahc, SCBPTR, 0); + if (ahc_inb(ahc, SCB_BASE) != 0) + break; + } + return (i); +} + +static void +ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *baddr; + + baddr = (bus_addr_t *)arg; + *baddr = segs->ds_addr; +} + +static void +ahc_build_free_scb_list(struct ahc_softc *ahc) +{ + int i; + + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + ahc_outb(ahc, SCBPTR, i); + + /* Clear the control byte. */ + ahc_outb(ahc, SCB_CONTROL, 0); + + /* Set the next pointer */ + if ((ahc->flags & AHC_PAGESCBS) != 0) + ahc_outb(ahc, SCB_NEXT, i+1); + else + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); + + /* Make the tag number invalid */ + ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); + } + + /* Make sure that the last SCB terminates the free list */ + ahc_outb(ahc, SCBPTR, i-1); + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); +} + +static int +ahc_init_scbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + + scb_data = ahc->scb_data; + SLIST_INIT(&scb_data->free_scbs); + SLIST_INIT(&scb_data->sg_maps); + + /* Allocate SCB resources */ + scb_data->scbarray = + (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, + M_DEVBUF, M_NOWAIT); + if (scb_data->scbarray == NULL) + return (ENOMEM); + memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC); + + /* Determine the number of hardware SCBs and initialize them */ + + scb_data->maxhscbs = ahc_probe_scbs(ahc); + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* SCB 0 heads the free list */ + ahc_outb(ahc, FREE_SCBH, 0); + } else { + ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); + } + + if (ahc->scb_data->maxhscbs == 0) { + printf("%s: No SCB space found\n", ahc_name(ahc)); + return (ENXIO); + } + + ahc_build_free_scb_list(ahc); + + /* + * Create our DMA tags. These tags define the kinds of device + * accessible memory allocations and memory mappings we will + * need to perform during normal operation. + * + * Unless we need to further restrict the allocation, we rely + * on the restrictions of the parent dmat, hence the common + * use of MAXADDR and MAXSIZE. + */ + + /* DMA tag for our hardware scb structures */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->hscb_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocation for our hscbs */ + if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat, + (void **)&scb_data->hscbs, + BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, + scb_data->hscbs, + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), + ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our sense buffers */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sense_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocate them */ + if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat, + (void **)&scb_data->sense, + BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, + scb_data->sense, + AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), + ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our S/G structures. We allocate in page sized chunks */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + PAGE_SIZE, /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sg_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Perform initial CCB allocation */ + memset(scb_data->hscbs, 0, + AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb)); + ahc_alloc_scbs(ahc); + + if (scb_data->numscbs == 0) { + printf("%s: ahc_init_scbdata - " + "Unable to allocate initial scbs\n", + ahc_name(ahc)); + goto error_exit; + } + + /* + * Tell the sequencer which SCB will be the next one it receives. + */ + ahc->next_queued_scb = ahc_get_scb(ahc); + ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); + + /* + * Note that we were successfull + */ + return (0); + +error_exit: + + return (ENOMEM); +} + +static void +ahc_fini_scbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + + scb_data = ahc->scb_data; + if (scb_data == NULL) + return; + + switch (scb_data->init_level) { + default: + case 7: + { + struct sg_map_node *sg_map; + + while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { + SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); + ahc_dmamap_unload(ahc, scb_data->sg_dmat, + sg_map->sg_dmamap); + ahc_dmamem_free(ahc, scb_data->sg_dmat, + sg_map->sg_vaddr, + sg_map->sg_dmamap); + free(sg_map, M_DEVBUF); + } + ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); + } + case 6: + ahc_dmamap_unload(ahc, scb_data->sense_dmat, + scb_data->sense_dmamap); + case 5: + ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, + scb_data->sense_dmamap); + ahc_dmamap_destroy(ahc, scb_data->sense_dmat, + scb_data->sense_dmamap); + case 4: + ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); + case 3: + ahc_dmamap_unload(ahc, scb_data->hscb_dmat, + scb_data->hscb_dmamap); + case 2: + ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, + scb_data->hscb_dmamap); + ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, + scb_data->hscb_dmamap); + case 1: + ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); + break; + case 0: + break; + } + if (scb_data->scbarray != NULL) + free(scb_data->scbarray, M_DEVBUF); +} + +void +ahc_alloc_scbs(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + struct scb *next_scb; + struct sg_map_node *sg_map; + bus_addr_t physaddr; + struct ahc_dma_seg *segs; + int newcount; + int i; + + scb_data = ahc->scb_data; + if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC) + /* Can't allocate any more */ + return; + + next_scb = &scb_data->scbarray[scb_data->numscbs]; + + sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); + + if (sg_map == NULL) + return; + + /* Allocate S/G space for the next batch of SCBS */ + if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, + (void **)&sg_map->sg_vaddr, + BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { + free(sg_map, M_DEVBUF); + return; + } + + SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); + + ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, + sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb, + &sg_map->sg_physaddr, /*flags*/0); + + segs = sg_map->sg_vaddr; + physaddr = sg_map->sg_physaddr; + + newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); + newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); + for (i = 0; i < newcount; i++) { + struct scb_platform_data *pdata; +#ifndef __linux__ + int error; +#endif + pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), + M_DEVBUF, M_NOWAIT); + if (pdata == NULL) + break; + next_scb->platform_data = pdata; + next_scb->sg_map = sg_map; + next_scb->sg_list = segs; + /* + * The sequencer always starts with the second entry. + * The first entry is embedded in the scb. + */ + next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); + next_scb->ahc_softc = ahc; + next_scb->flags = SCB_FREE; +#ifndef __linux__ + error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, + &next_scb->dmamap); + if (error != 0) + break; +#endif + next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; + next_scb->hscb->tag = ahc->scb_data->numscbs; + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, + next_scb, links.sle); + segs += AHC_NSEG; + physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); + next_scb++; + ahc->scb_data->numscbs++; + } +} + +void +ahc_controller_info(struct ahc_softc *ahc, char *buf) +{ + int len; + + len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]); + buf += len; + if ((ahc->features & AHC_TWIN) != 0) + len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " + "B SCSI Id=%d, primary %c, ", + ahc->our_id, ahc->our_id_b, + (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); + else { + const char *speed; + const char *type; + + speed = ""; + if ((ahc->features & AHC_ULTRA) != 0) { + speed = "Ultra "; + } else if ((ahc->features & AHC_DT) != 0) { + speed = "Ultra160 "; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + speed = "Ultra2 "; + } + if ((ahc->features & AHC_WIDE) != 0) { + type = "Wide"; + } else { + type = "Single"; + } + len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", + speed, type, ahc->channel, ahc->our_id); + } + buf += len; + + if ((ahc->flags & AHC_PAGESCBS) != 0) + sprintf(buf, "%d/%d SCBs", + ahc->scb_data->maxhscbs, AHC_MAX_QUEUE); + else + sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); +} + +/* + * Start the board, ready for normal operation + */ +int +ahc_init(struct ahc_softc *ahc) +{ + int max_targ; + int i; + int term; + u_int scsi_conf; + u_int scsiseq_template; + u_int ultraenb; + u_int discenable; + u_int tagenable; + size_t driver_data_size; + uint32_t physaddr; + +#ifdef AHC_DEBUG_SEQUENCER + ahc->flags |= AHC_SEQUENCER_DEBUG; +#endif + +#ifdef AHC_PRINT_SRAM + printf("Scratch Ram:"); + for (i = 0x20; i < 0x5f; i++) { + if (((i % 8) == 0) && (i != 0)) { + printf ("\n "); + } + printf (" 0x%x", ahc_inb(ahc, i)); + } + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0x70; i < 0x7f; i++) { + if (((i % 8) == 0) && (i != 0)) { + printf ("\n "); + } + printf (" 0x%x", ahc_inb(ahc, i)); + } + } + printf ("\n"); + /* + * Reading uninitialized scratch ram may + * generate parity errors. + */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); +#endif + max_targ = 15; + + /* + * Assume we have a board at this stage and it has been reset. + */ + if ((ahc->flags & AHC_USEDEFAULTS) != 0) + ahc->our_id = ahc->our_id_b = 7; + + /* + * Default to allowing initiator operations. + */ + ahc->flags |= AHC_INITIATORROLE; + + /* + * Only allow target mode features if this unit has them enabled. + */ + if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) + ahc->features &= ~AHC_TARGETMODE; + +#ifndef __linux__ + /* DMA tag for mapping buffers into device visible space. */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, + /*maxsegsz*/AHC_MAXTRANSFER_SIZE, + /*flags*/BUS_DMA_ALLOCNOW, + &ahc->buffer_dmat) != 0) { + return (ENOMEM); + } +#endif + + ahc->init_level++; + + /* + * DMA tag for our command fifos and other data in system memory + * the card's sequencer must be able to access. For initiator + * roles, we need to allocate space for the the qinfifo and qoutfifo. + * The qinfifo and qoutfifo are composed of 256 1 byte elements. + * When providing for the target mode role, we must additionally + * provide space for the incoming target command fifo and an extra + * byte to deal with a dma bug in some chip versions. + */ + driver_data_size = 2 * 256 * sizeof(uint8_t); + if ((ahc->features & AHC_TARGETMODE) != 0) + driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) + + /*DMA WideOdd Bug Buffer*/1; + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + driver_data_size, + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &ahc->shared_data_dmat) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* Allocation of driver data */ + if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat, + (void **)&ahc->qoutfifo, + BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* And permanently map it in */ + ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, + ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, + &ahc->shared_data_busaddr, /*flags*/0); + + if ((ahc->features & AHC_TARGETMODE) != 0) { + ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS]; + ahc->dma_bug_buf = ahc->shared_data_busaddr + + driver_data_size - 1; + /* All target command blocks start out invalid. */ + for (i = 0; i < AHC_TMODE_CMDS; i++) + ahc->targetcmds[i].cmd_valid = 0; + ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD); + ahc->tqinfifonext = 1; + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; + } + ahc->qinfifo = &ahc->qoutfifo[256]; + + ahc->init_level++; + + /* Allocate SCB data now that buffer_dmat is initialized */ + if (ahc->scb_data->maxhscbs == 0) + if (ahc_init_scbdata(ahc) != 0) + return (ENOMEM); + + /* + * Allocate a tstate to house information for our + * initiator presence on the bus as well as the user + * data for any target mode initiator. + */ + if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { + printf("%s: unable to allocate ahc_tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (ENOMEM); + } + + if ((ahc->features & AHC_TWIN) != 0) { + if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { + printf("%s: unable to allocate ahc_tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (ENOMEM); + } + } + + ahc_outb(ahc, SEQ_FLAGS, 0); + ahc_outb(ahc, SEQ_FLAGS2, 0); + + if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { + ahc->flags |= AHC_PAGESCBS; + } else { + ahc->flags &= ~AHC_PAGESCBS; + } + +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) { + printf("%s: hardware scb %d bytes; kernel scb %d bytes; " + "ahc_dma %d bytes\n", + ahc_name(ahc), + sizeof(struct hardware_scb), + sizeof(struct scb), + sizeof(struct ahc_dma_seg)); + } +#endif /* AHC_DEBUG */ + + /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ + if (ahc->features & AHC_TWIN) { + + /* + * The device is gated to channel B after a chip reset, + * so set those values first + */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; + ahc_outb(ahc, SCSIID, ahc->our_id_b); + scsi_conf = ahc_inb(ahc, SCSICONF + 1); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + if ((scsi_conf & RESET_SCSI) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) + ahc->flags |= AHC_RESET_BUS_B; + + /* Select Channel A */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); + else + ahc_outb(ahc, SCSIID, ahc->our_id); + scsi_conf = ahc_inb(ahc, SCSICONF); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime + |ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + if ((scsi_conf & RESET_SCSI) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) + ahc->flags |= AHC_RESET_BUS_A; + + /* + * Look at the information that board initialization or + * the board bios has left us. + */ + ultraenb = 0; + tagenable = ALL_TARGETS_MASK; + + /* Grab the disconnection disable table and invert it for our needs */ + if ((ahc->flags & AHC_USEDEFAULTS) != 0) { + printf("%s: Host Adapter Bios disabled. Using default SCSI " + "device parameters\n", ahc_name(ahc)); + ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| + AHC_TERM_ENB_A|AHC_TERM_ENB_B; + discenable = ALL_TARGETS_MASK; + if ((ahc->features & AHC_ULTRA) != 0) + ultraenb = ALL_TARGETS_MASK; + } else { + discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) + | ahc_inb(ahc, DISC_DSB)); + if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) + ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) + | ahc_inb(ahc, ULTRA_ENB); + } + + if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) + max_targ = 7; + + for (i = 0; i <= max_targ; i++) { + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int our_id; + u_int target_id; + char channel; + + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); + /* Default to async narrow across the board */ + memset(tinfo, 0, sizeof(*tinfo)); + if (ahc->flags & AHC_USEDEFAULTS) { + if ((ahc->features & AHC_WIDE) != 0) + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + + /* + * These will be truncated when we determine the + * connection type we have with the target. + */ + tinfo->user.period = ahc_syncrates->period; + tinfo->user.offset = ~0; + } else { + u_int scsirate; + uint16_t mask; + + /* Take the settings leftover in scratch RAM. */ + scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); + mask = (0x01 << i); + if ((ahc->features & AHC_ULTRA2) != 0) { + u_int offset; + u_int maxsync; + + if ((scsirate & SOFS) == 0x0F) { + /* + * Haven't negotiated yet, + * so the format is different. + */ + scsirate = (scsirate & SXFR) >> 4 + | (ultraenb & mask) + ? 0x08 : 0x0 + | (scsirate & WIDEXFER); + offset = MAX_OFFSET_ULTRA2; + } else + offset = ahc_inb(ahc, TARG_OFFSET + i); + if ((scsirate & ~WIDEXFER) == 0 && offset != 0) + /* Set to the lowest sync rate, 5MHz */ + scsirate |= 0x1c; + maxsync = AHC_SYNCRATE_ULTRA2; + if ((ahc->features & AHC_DT) != 0) + maxsync = AHC_SYNCRATE_DT; + tinfo->user.period = + ahc_find_period(ahc, scsirate, maxsync); + if (offset == 0) + tinfo->user.period = 0; + else + tinfo->user.offset = ~0; + if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ + && (ahc->features & AHC_DT) != 0) + tinfo->user.ppr_options = + MSG_EXT_PPR_DT_REQ; + } else if ((scsirate & SOFS) != 0) { + if ((scsirate & SXFR) == 0x40 + && (ultraenb & mask) != 0) { + /* Treat 10MHz as a non-ultra speed */ + scsirate &= ~SXFR; + ultraenb &= ~mask; + } + tinfo->user.period = + ahc_find_period(ahc, scsirate, + (ultraenb & mask) + ? AHC_SYNCRATE_ULTRA + : AHC_SYNCRATE_FAST); + if (tinfo->user.period != 0) + tinfo->user.offset = ~0; + } + if (tinfo->user.period == 0) + tinfo->user.offset = 0; + if ((scsirate & WIDEXFER) != 0 + && (ahc->features & AHC_WIDE) != 0) + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + tinfo->user.protocol_version = 4; + if ((ahc->features & AHC_DT) != 0) + tinfo->user.transport_version = 3; + else + tinfo->user.transport_version = 2; + tinfo->goal.protocol_version = 2; + tinfo->goal.transport_version = 2; + tinfo->curr.protocol_version = 2; + tinfo->curr.transport_version = 2; + } + tstate->ultraenb = ultraenb; + } + ahc->user_discenable = discenable; + ahc->user_tagenable = tagenable; + + /* There are no untagged SCBs active yet. */ + for (i = 0; i < 16; i++) { + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); + if ((ahc->flags & AHC_SCB_BTT) != 0) { + int lun; + + /* + * The SCB based BTT allows an entry per + * target and lun pair. + */ + for (lun = 1; lun < AHC_NUM_LUNS; lun++) + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); + } + } + + /* All of our queues are empty */ + for (i = 0; i < 256; i++) + ahc->qoutfifo[i] = SCB_LIST_NULL; + ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD); + + for (i = 0; i < 256; i++) + ahc->qinfifo[i] = SCB_LIST_NULL; + + if ((ahc->features & AHC_MULTI_TID) != 0) { + ahc_outb(ahc, TARGID, 0); + ahc_outb(ahc, TARGID + 1, 0); + } + + /* + * Tell the sequencer where it can find our arrays in memory. + */ + physaddr = ahc->scb_data->hscb_busaddr; + ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); + + physaddr = ahc->shared_data_busaddr; + ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); + + /* + * Initialize the group code to command length table. + * This overrides the values in TARG_SCSIRATE, so only + * setup the table after we have processed that information. + */ + ahc_outb(ahc, CMDSIZE_TABLE, 5); + ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); + ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); + ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); + + /* Tell the sequencer of our initial queue positions */ + ahc_outb(ahc, KERNEL_QINPOS, 0); + ahc_outb(ahc, QINPOS, 0); + ahc_outb(ahc, QOUTPOS, 0); + + /* + * Use the built in queue management registers + * if they are available. + */ + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); + ahc_outb(ahc, SDSCB_QOFF, 0); + ahc_outb(ahc, SNSCB_QOFF, 0); + ahc_outb(ahc, HNSCB_QOFF, 0); + } + + + /* We don't have any waiting selections */ + ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); + + /* Our disconnection list is empty too */ + ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); + + /* Message out buffer starts empty */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); + + /* + * Setup the allowed SCSI Sequences based on operational mode. + * If we are a target, we'll enalbe select in operations once + * we've had a lun enabled. + */ + scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; + if ((ahc->flags & AHC_INITIATORROLE) != 0) + scsiseq_template |= ENRSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); + + /* + * Load the Sequencer program and Enable the adapter + * in "fast" mode. + */ + if (bootverbose) + printf("%s: Downloading Sequencer Program...", + ahc_name(ahc)); + + ahc_loadseq(ahc); + + if ((ahc->features & AHC_ULTRA2) != 0) { + int wait; + + /* + * Wait for up to 500ms for our transceivers + * to settle. If the adapter does not have + * a cable attached, the tranceivers may + * never settle, so don't complain if we + * fail here. + */ + ahc_pause(ahc); + for (wait = 5000; + (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; + wait--) + ahc_delay(100); + ahc_unpause(ahc); + } + return (0); +} + +void +ahc_intr_enable(struct ahc_softc *ahc, int enable) +{ + u_int hcntrl; + + hcntrl = ahc_inb(ahc, HCNTRL); + hcntrl &= ~INTEN; + ahc->pause &= ~INTEN; + ahc->unpause &= ~INTEN; + if (enable) { + hcntrl |= INTEN; + ahc->pause |= INTEN; + ahc->unpause |= INTEN; + } + ahc_outb(ahc, HCNTRL, hcntrl); +} + +/* + * Ensure that the card is paused in a location + * outside of all critical sections and that all + * pending work is completed prior to returning. + * This routine should only be called from outside + * an interrupt context. + */ +void +ahc_pause_and_flushwork(struct ahc_softc *ahc) +{ + int intstat; + int maxloops; + + maxloops = 1000; + ahc->flags |= AHC_ALL_INTERRUPTS; + intstat = 0; + do { + ahc_intr(ahc); + ahc_pause(ahc); + ahc_clear_critical_section(ahc); + if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) + break; + maxloops--; + } while (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) && --maxloops); + if (maxloops == 0) { + printf("Infinite interrupt loop, INTSTAT = %x", + ahc_inb(ahc, INTSTAT)); + } + ahc_platform_flushwork(ahc); + ahc->flags &= ~AHC_ALL_INTERRUPTS; +} + +int +ahc_suspend(struct ahc_softc *ahc) +{ + uint8_t *ptr; + int i; + + ahc_pause_and_flushwork(ahc); + + if (LIST_FIRST(&ahc->pending_scbs) != NULL) + return (EBUSY); + +#if AHC_TARGET_MODE + /* + * XXX What about ATIOs that have not yet been serviced? + * Perhaps we should just refuse to be suspended if we + * are acting in a target role. + */ + if (ahc->pending_device != NULL) + return (EBUSY); +#endif + + /* Save volatile registers */ + if ((ahc->features & AHC_TWIN) != 0) { + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ); + ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); + ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0); + ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1); + ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER); + ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL); + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ); + ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); + ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0); + ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1); + ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER); + ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL); + + if ((ahc->chip & AHC_PCI) != 0) { + ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0); + ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS); + } + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE); + ahc_outb(ahc, SFUNCT, sfunct); + ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1); + } + + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH); + + ptr = ahc->suspend_state.scratch_ram; + for (i = 0; i < 64; i++) + *ptr++ = ahc_inb(ahc, SRAM_BASE + i); + + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0; i < 16; i++) + *ptr++ = ahc_inb(ahc, TARG_OFFSET + i); + } + + ptr = ahc->suspend_state.btt; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + for (i = 0;i < AHC_NUM_TARGETS; i++) { + int j; + + for (j = 0;j < AHC_NUM_LUNS; j++) { + u_int tcl; + + tcl = BUILD_TCL(i << 4, j); + *ptr = ahc_index_busy_tcl(ahc, tcl); + } + } + } + ahc_shutdown(ahc); + return (0); +} + +int +ahc_resume(struct ahc_softc *ahc) +{ + uint8_t *ptr; + int i; + + ahc_reset(ahc); + + ahc_build_free_scb_list(ahc); + + /* Restore volatile registers */ + if ((ahc->features & AHC_TWIN) != 0) { + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + ahc_outb(ahc, SCSIID, ahc->our_id); + ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq); + ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0); + ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1); + ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0); + ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1); + ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer); + ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl); + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq); + ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0); + ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1); + ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0); + ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1); + ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer); + ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); + else + ahc_outb(ahc, SCSIID, ahc->our_id); + + if ((ahc->chip & AHC_PCI) != 0) { + ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0); + ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus); + } + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode); + ahc_outb(ahc, SFUNCT, sfunct); + ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1); + } + + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh); + + ptr = ahc->suspend_state.scratch_ram; + for (i = 0; i < 64; i++) + ahc_outb(ahc, SRAM_BASE + i, *ptr++); + + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0; i < 16; i++) + ahc_outb(ahc, TARG_OFFSET + i, *ptr++); + } + + ptr = ahc->suspend_state.btt; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + for (i = 0;i < AHC_NUM_TARGETS; i++) { + int j; + + for (j = 0;j < AHC_NUM_LUNS; j++) { + u_int tcl; + + tcl = BUILD_TCL(i << 4, j); + ahc_busy_tcl(ahc, tcl, *ptr); + } + } + } + return (0); +} + +/************************** Busy Target Table *********************************/ +/* + * Return the untagged transaction id for a given target/channel lun. + * Optionally, clear the entry. + */ +u_int +ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl) +{ + u_int scbid; + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl)); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset); + } + + return (scbid); +} + +void +ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl) +{ + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL); + } +} + +void +ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid) +{ + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid); + } +} + +/************************** SCB and SCB queue management **********************/ +int +ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target, + char channel, int lun, u_int tag, role_t role) +{ + int targ = SCB_GET_TARGET(ahc, scb); + char chan = SCB_GET_CHANNEL(ahc, scb); + int slun = SCB_GET_LUN(scb); + int match; + + match = ((chan == channel) || (channel == ALL_CHANNELS)); + if (match != 0) + match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); + if (match != 0) + match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); + if (match != 0) { +#if AHC_TARGET_MODE + int group; + + group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); + if (role == ROLE_INITIATOR) { + match = (group != XPT_FC_GROUP_TMODE) + && ((tag == scb->hscb->tag) + || (tag == SCB_LIST_NULL)); + } else if (role == ROLE_TARGET) { + match = (group == XPT_FC_GROUP_TMODE) + && ((tag == scb->io_ctx->csio.tag_id) + || (tag == SCB_LIST_NULL)); + } +#else /* !AHC_TARGET_MODE */ + match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); +#endif /* AHC_TARGET_MODE */ + } + + return match; +} + +void +ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb) +{ + int target; + char channel; + int lun; + + target = SCB_GET_TARGET(ahc, scb); + lun = SCB_GET_LUN(scb); + channel = SCB_GET_CHANNEL(ahc, scb); + + ahc_search_qinfifo(ahc, target, channel, lun, + /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + + ahc_platform_freeze_devq(ahc, scb); +} + +void +ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb) +{ + struct scb *prev_scb; + + prev_scb = NULL; + if (ahc_qinfifo_count(ahc) != 0) { + u_int prev_tag; + uint8_t prev_pos; + + prev_pos = ahc->qinfifonext - 1; + prev_tag = ahc->qinfifo[prev_pos]; + prev_scb = ahc_lookup_scb(ahc, prev_tag); + } + ahc_qinfifo_requeue(ahc, prev_scb, scb); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + } +} + +static void +ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, + struct scb *scb) +{ + if (prev_scb == NULL) { + ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); + } else { + prev_scb->hscb->next = scb->hscb->tag; + ahc_sync_scb(ahc, prev_scb, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + } + ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; + scb->hscb->next = ahc->next_queued_scb->hscb->tag; + ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); +} + +static int +ahc_qinfifo_count(struct ahc_softc *ahc) +{ + u_int8_t qinpos; + u_int8_t diff; + + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + qinpos = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinpos); + } else + qinpos = ahc_inb(ahc, QINPOS); + diff = ahc->qinfifonext - qinpos; + return (diff); +} + +int +ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status, + ahc_search_action action) +{ + struct scb *scb; + struct scb *prev_scb; + uint8_t qinstart; + uint8_t qinpos; + uint8_t qintail; + uint8_t next; + uint8_t prev; + uint8_t curscbptr; + int found; + int maxtarget; + int i; + int have_qregs; + + qintail = ahc->qinfifonext; + have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0; + if (have_qregs) { + qinstart = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinstart); + } else + qinstart = ahc_inb(ahc, QINPOS); + qinpos = qinstart; + found = 0; + prev_scb = NULL; + + if (action == SEARCH_COMPLETE) { + /* + * Don't attempt to run any queued untagged transactions + * until we are done with the abort process. + */ + ahc_freeze_untagged_queues(ahc); + } + + /* + * Start with an empty queue. Entries that are not chosen + * for removal will be re-added to the queue as we go. + */ + ahc->qinfifonext = qinpos; + ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); + + while (qinpos != qintail) { + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]); + if (scb == NULL) { + printf("qinpos = %d, SCB index = %d\n", + qinpos, ahc->qinfifo[qinpos]); + panic("Loop 1\n"); + } + + if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in qinfifo\n"); + ahc_done(ahc, scb); + + /* FALLTHROUGH */ + } + case SEARCH_REMOVE: + break; + case SEARCH_COUNT: + ahc_qinfifo_requeue(ahc, prev_scb, scb); + prev_scb = scb; + break; + } + } else { + ahc_qinfifo_requeue(ahc, prev_scb, scb); + prev_scb = scb; + } + qinpos++; + } + + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + } + + if (action != SEARCH_COUNT + && (found != 0) + && (qinstart != ahc->qinfifonext)) { + /* + * The sequencer may be in the process of dmaing + * down the SCB at the beginning of the queue. + * This could be problematic if either the first, + * or the second SCB is removed from the queue + * (the first SCB includes a pointer to the "next" + * SCB to dma). If we have removed any entries, swap + * the first element in the queue with the next HSCB + * so the sequencer will notice that NEXT_QUEUED_SCB + * has changed during its dma attempt and will retry + * the DMA. + */ + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]); + + if (scb == NULL) { + printf("found = %d, qinstart = %d, qinfifionext = %d\n", + found, qinstart, ahc->qinfifonext); + panic("First/Second Qinfifo fixup\n"); + } + /* + * ahc_swap_with_next_hscb forces our next pointer to + * point to the reserved SCB for future commands. Save + * and restore our original next pointer to maintain + * queue integrity. + */ + next = scb->hscb->next; + ahc->scb_data->scbindex[scb->hscb->tag] = NULL; + ahc_swap_with_next_hscb(ahc, scb); + scb->hscb->next = next; + ahc->qinfifo[qinstart] = scb->hscb->tag; + + /* Tell the card about the new head of the qinfifo. */ + ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); + + /* Fixup the tail "next" pointer. */ + qintail = ahc->qinfifonext - 1; + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]); + scb->hscb->next = ahc->next_queued_scb->hscb->tag; + } + + /* + * Search waiting for selection list. + */ + curscbptr = ahc_inb(ahc, SCBPTR); + next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ + prev = SCB_LIST_NULL; + + while (next != SCB_LIST_NULL) { + uint8_t scb_index; + + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + printf("Waiting List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); + } + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("scb_index = %d, next = %d\n", + scb_index, next); + panic("Waiting List traversal\n"); + } + if (ahc_match_scb(ahc, scb, target, channel, + lun, SCB_LIST_NULL, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in Waiting List\n"); + ahc_done(ahc, scb); + /* FALLTHROUGH */ + } + case SEARCH_REMOVE: + next = ahc_rem_wscb(ahc, next, prev); + break; + case SEARCH_COUNT: + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + break; + } + } else { + + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + } + ahc_outb(ahc, SCBPTR, curscbptr); + + /* + * And lastly, the untagged holding queues. + */ + i = 0; + if ((ahc->flags & AHC_SCB_BTT) == 0) { + + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + + i = target; + if (channel == 'B') + i += 8; + maxtarget = i + 1; + } + } else { + maxtarget = 0; + } + + for (; i < maxtarget; i++) { + struct scb_tailq *untagged_q; + struct scb *next_scb; + + untagged_q = &(ahc->untagged_queues[i]); + next_scb = TAILQ_FIRST(untagged_q); + while (next_scb != NULL) { + + scb = next_scb; + next_scb = TAILQ_NEXT(scb, links.tqe); + + /* + * The head of the list may be the currently + * active untagged command for a device. + * We're only searching for commands that + * have not been started. A transaction + * marked active but still in the qinfifo + * is removed by the qinfifo scanning code + * above. + */ + if ((scb->flags & SCB_ACTIVE) != 0) + continue; + + if (ahc_match_scb(ahc, scb, target, channel, + lun, SCB_LIST_NULL, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in untaggedQ\n"); + ahc_done(ahc, scb); + break; + } + case SEARCH_REMOVE: + TAILQ_REMOVE(untagged_q, scb, + links.tqe); + break; + case SEARCH_COUNT: + break; + } + } + } + } + + if (action == SEARCH_COMPLETE) + ahc_release_untagged_queues(ahc); + return (found); +} + +int +ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, int stop_on_first, int remove, + int save_state) +{ + struct scb *scbp; + u_int next; + u_int prev; + u_int count; + u_int active_scb; + + count = 0; + next = ahc_inb(ahc, DISCONNECTED_SCBH); + prev = SCB_LIST_NULL; + + if (save_state) { + /* restore this when we're done */ + active_scb = ahc_inb(ahc, SCBPTR); + } else + /* Silence compiler */ + active_scb = SCB_LIST_NULL; + + while (next != SCB_LIST_NULL) { + u_int scb_index; + + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + printf("Disconnected List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); + } + + if (next == prev) { + panic("Disconnected List Loop. " + "cur SCBPTR == %x, prev SCBPTR == %x.", + next, prev); + } + scbp = ahc_lookup_scb(ahc, scb_index); + if (ahc_match_scb(ahc, scbp, target, channel, lun, + tag, ROLE_INITIATOR)) { + count++; + if (remove) { + next = + ahc_rem_scb_from_disc_list(ahc, prev, next); + } else { + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + if (stop_on_first) + break; + } else { + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + } + if (save_state) + ahc_outb(ahc, SCBPTR, active_scb); + return (count); +} + +/* + * Remove an SCB from the on chip list of disconnected transactions. + * This is empty/unused if we are not performing SCB paging. + */ +static u_int +ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr) +{ + u_int next; + + ahc_outb(ahc, SCBPTR, scbptr); + next = ahc_inb(ahc, SCB_NEXT); + + ahc_outb(ahc, SCB_CONTROL, 0); + + ahc_add_curscb_to_free_list(ahc); + + if (prev != SCB_LIST_NULL) { + ahc_outb(ahc, SCBPTR, prev); + ahc_outb(ahc, SCB_NEXT, next); + } else + ahc_outb(ahc, DISCONNECTED_SCBH, next); + + return (next); +} + +/* + * Add the SCB as selected by SCBPTR onto the on chip list of + * free hardware SCBs. This list is empty/unused if we are not + * performing SCB paging. + */ +static void +ahc_add_curscb_to_free_list(struct ahc_softc *ahc) +{ + /* + * Invalidate the tag so that our abort + * routines don't think it's active. + */ + ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); + + if ((ahc->flags & AHC_PAGESCBS) != 0) { + ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); + ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); + } +} + +/* + * Manipulate the waiting for selection list and return the + * scb that follows the one that we remove. + */ +static u_int +ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) +{ + u_int curscb, next; + + /* + * Select the SCB we want to abort and + * pull the next pointer out of it. + */ + curscb = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, scbpos); + next = ahc_inb(ahc, SCB_NEXT); + + /* Clear the necessary fields */ + ahc_outb(ahc, SCB_CONTROL, 0); + + ahc_add_curscb_to_free_list(ahc); + + /* update the waiting list */ + if (prev == SCB_LIST_NULL) { + /* First in the list */ + ahc_outb(ahc, WAITING_SCBH, next); + + /* + * Ensure we aren't attempting to perform + * selection for this entry. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else { + /* + * Select the scb that pointed to us + * and update its next pointer. + */ + ahc_outb(ahc, SCBPTR, prev); + ahc_outb(ahc, SCB_NEXT, next); + } + + /* + * Point us back at the original scb position. + */ + ahc_outb(ahc, SCBPTR, curscb); + return next; +} + +/******************************** Error Handling ******************************/ +/* + * Abort all SCBs that match the given description (target/channel/lun/tag), + * setting their status to the passed in status if the status has not already + * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer + * is paused before it is called. + */ +int +ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status) +{ + struct scb *scbp; + struct scb *scbp_next; + u_int active_scb; + int i, j; + int maxtarget; + int minlun; + int maxlun; + + int found; + + /* + * Don't attempt to run any queued untagged transactions + * until we are done with the abort process. + */ + ahc_freeze_untagged_queues(ahc); + + /* restore this when we're done */ + active_scb = ahc_inb(ahc, SCBPTR); + + found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, + role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); + + /* + * Clean out the busy target table for any untagged commands. + */ + i = 0; + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + i = target; + if (channel == 'B') + i += 8; + maxtarget = i + 1; + } + + if (lun == CAM_LUN_WILDCARD) { + + /* + * Unless we are using an SCB based + * busy targets table, there is only + * one table entry for all luns of + * a target. + */ + minlun = 0; + maxlun = 1; + if ((ahc->flags & AHC_SCB_BTT) != 0) + maxlun = AHC_NUM_LUNS; + } else { + minlun = lun; + maxlun = lun + 1; + } + + if (role != ROLE_TARGET) { + for (;i < maxtarget; i++) { + for (j = minlun;j < maxlun; j++) { + u_int scbid; + u_int tcl; + + tcl = BUILD_TCL(i << 4, j); + scbid = ahc_index_busy_tcl(ahc, tcl); + scbp = ahc_lookup_scb(ahc, scbid); + if (scbp == NULL + || ahc_match_scb(ahc, scbp, target, channel, + lun, tag, role) == 0) + continue; + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); + } + } + + /* + * Go through the disconnected list and remove any entries we + * have queued for completion, 0'ing their control byte too. + * We save the active SCB and restore it ourselves, so there + * is no reason for this search to restore it too. + */ + ahc_search_disc_list(ahc, target, channel, lun, tag, + /*stop_on_first*/FALSE, /*remove*/TRUE, + /*save_state*/FALSE); + } + + /* + * Go through the hardware SCB array looking for commands that + * were active but not on any list. In some cases, these remnants + * might not still have mappings in the scbindex array (e.g. unexpected + * bus free with the same scb queued for an abort). Don't hold this + * against them. + */ + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + u_int scbid; + + ahc_outb(ahc, SCBPTR, i); + scbid = ahc_inb(ahc, SCB_TAG); + scbp = ahc_lookup_scb(ahc, scbid); + if ((scbp == NULL && scbid != SCB_LIST_NULL) + || (scbp != NULL + && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))) + ahc_add_curscb_to_free_list(ahc); + } + + /* + * Go through the pending CCB list and look for + * commands for this target that are still active. + * These are other tagged commands that were + * disconnected when the reset occurred. + */ + scbp_next = LIST_FIRST(&ahc->pending_scbs); + while (scbp_next != NULL) { + scbp = scbp_next; + scbp_next = LIST_NEXT(scbp, pending_links); + if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { + cam_status ostat; + + ostat = ahc_get_transaction_status(scbp); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scbp, status); + if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) + ahc_freeze_scb(scbp); + if ((scbp->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB on pending list\n"); + ahc_done(ahc, scbp); + found++; + } + } + ahc_outb(ahc, SCBPTR, active_scb); + ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status); + ahc_release_untagged_queues(ahc); + return found; +} + +static void +ahc_reset_current_bus(struct ahc_softc *ahc) +{ + uint8_t scsiseq; + + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); + scsiseq = ahc_inb(ahc, SCSISEQ); + ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); + ahc_flush_device_writes(ahc); + ahc_delay(AHC_BUSRESET_DELAY); + /* Turn off the bus reset */ + ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); + + ahc_clear_intstat(ahc); + + /* Re-enable reset interrupts */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); +} + +int +ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) +{ + struct ahc_devinfo devinfo; + u_int initiator, target, max_scsiid; + u_int sblkctl; + u_int scsiseq; + u_int simode1; + int found; + int restart_needed; + char cur_channel; + + ahc->pending_device = NULL; + + ahc_compile_devinfo(&devinfo, + CAM_TARGET_WILDCARD, + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD, + channel, ROLE_UNKNOWN); + ahc_pause(ahc); + + /* Make sure the sequencer is in a safe location. */ + ahc_clear_critical_section(ahc); + + /* + * Run our command complete fifos to ensure that we perform + * completion processing on any commands that 'completed' + * before the reset occurred. + */ + ahc_run_qoutfifo(ahc); +#if AHC_TARGET_MODE + if ((ahc->flags & AHC_TARGETROLE) != 0) { + ahc_run_tqinfifo(ahc, /*paused*/TRUE); + } +#endif + + /* + * Reset the bus if we are initiating this reset + */ + sblkctl = ahc_inb(ahc, SBLKCTL); + cur_channel = 'A'; + if ((ahc->features & AHC_TWIN) != 0 + && ((sblkctl & SELBUSB) != 0)) + cur_channel = 'B'; + scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); + if (cur_channel != channel) { + /* Case 1: Command for another bus is active + * Stealthily reset the other bus without + * upsetting the current bus. + */ + ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); + simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); + ahc_outb(ahc, SIMODE1, simode1); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); +#if AHC_TARGET_MODE + /* + * Bus resets clear ENSELI, so we cannot + * defer re-enabling bus reset interrupts + * if we are in target mode. + */ + if ((ahc->flags & AHC_TARGETROLE) != 0) + ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); +#endif + ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); + ahc_outb(ahc, SBLKCTL, sblkctl); + restart_needed = FALSE; + } else { + /* Case 2: A command from this bus is active or we're idle */ + simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); + ahc_outb(ahc, SIMODE1, simode1); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); +#if AHC_TARGET_MODE + /* + * Bus resets clear ENSELI, so we cannot + * defer re-enabling bus reset interrupts + * if we are in target mode. + */ + if ((ahc->flags & AHC_TARGETROLE) != 0) + ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST); +#endif + ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); + restart_needed = TRUE; + } + + /* + * Clean up all the state information for the + * pending transactions on this bus. + */ + found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, + CAM_LUN_WILDCARD, SCB_LIST_NULL, + ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); + + max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7; + +#ifdef AHC_TARGET_MODE + /* + * Send an immediate notify ccb to all target more peripheral + * drivers affected by this action. + */ + for (target = 0; target <= max_scsiid; target++) { + struct ahc_tmode_tstate* tstate; + u_int lun; + + tstate = ahc->enabled_targets[target]; + if (tstate == NULL) + continue; + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct ahc_tmode_lstate* lstate; + + lstate = tstate->enabled_luns[lun]; + if (lstate == NULL) + continue; + + ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD, + EVENT_TYPE_BUS_RESET, /*arg*/0); + ahc_send_lstate_events(ahc, lstate); + } + } +#endif + /* Notify the XPT that a bus reset occurred */ + ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); + + /* + * Revert to async/narrow transfers until we renegotiate. + */ + for (target = 0; target <= max_scsiid; target++) { + + if (ahc->enabled_targets[target] == NULL) + continue; + for (initiator = 0; initiator <= max_scsiid; initiator++) { + struct ahc_devinfo devinfo; + + ahc_compile_devinfo(&devinfo, target, initiator, + CAM_LUN_WILDCARD, + channel, ROLE_UNKNOWN); + ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR, /*paused*/TRUE); + ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, + /*period*/0, /*offset*/0, + /*ppr_options*/0, AHC_TRANS_CUR, + /*paused*/TRUE); + } + } + + if (restart_needed) + ahc_restart(ahc); + else + ahc_unpause(ahc); + return found; +} + + +/***************************** Residual Processing ****************************/ +/* + * Calculate the residual for a just completed SCB. + */ +void +ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb) +{ + struct hardware_scb *hscb; + struct status_pkt *spkt; + uint32_t sgptr; + uint32_t resid_sgptr; + uint32_t resid; + + /* + * 5 cases. + * 1) No residual. + * SG_RESID_VALID clear in sgptr. + * 2) Transferless command + * 3) Never performed any transfers. + * sgptr has SG_FULL_RESID set. + * 4) No residual but target did not + * save data pointers after the + * last transfer, so sgptr was + * never updated. + * 5) We have a partial residual. + * Use residual_sgptr to determine + * where we are. + */ + + hscb = scb->hscb; + sgptr = ahc_le32toh(hscb->sgptr); + if ((sgptr & SG_RESID_VALID) == 0) + /* Case 1 */ + return; + sgptr &= ~SG_RESID_VALID; + + if ((sgptr & SG_LIST_NULL) != 0) + /* Case 2 */ + return; + + spkt = &hscb->shared_data.status; + resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); + if ((sgptr & SG_FULL_RESID) != 0) { + /* Case 3 */ + resid = ahc_get_transfer_length(scb); + } else if ((resid_sgptr & SG_LIST_NULL) != 0) { + /* Case 4 */ + return; + } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { + panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); + } else { + struct ahc_dma_seg *sg; + + /* + * Remainder of the SG where the transfer + * stopped. + */ + resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; + sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK); + + /* The residual sg_ptr always points to the next sg */ + sg--; + + /* + * Add up the contents of all residual + * SG segments that are after the SG where + * the transfer stopped. + */ + while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { + sg++; + resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; + } + } + if ((scb->flags & SCB_SENSE) == 0) + ahc_set_residual(scb, resid); + else + ahc_set_sense_residual(scb, resid); + +#ifdef AHC_DEBUG + if ((ahc_debug & AHC_SHOWMISC) != 0) { + ahc_print_path(ahc, scb); + printf("Handled Residual of %d bytes\n", resid); + } +#endif +} + +/******************************* Target Mode **********************************/ +#ifdef AHC_TARGET_MODE +/* + * Add a target mode event to this lun's queue + */ +static void +ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, + u_int initiator_id, u_int event_type, u_int event_arg) +{ + struct ahc_tmode_event *event; + int pending; + + xpt_freeze_devq(lstate->path, /*count*/1); + if (lstate->event_w_idx >= lstate->event_r_idx) + pending = lstate->event_w_idx - lstate->event_r_idx; + else + pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1 + - (lstate->event_r_idx - lstate->event_w_idx); + + if (event_type == EVENT_TYPE_BUS_RESET + || event_type == MSG_BUS_DEV_RESET) { + /* + * Any earlier events are irrelevant, so reset our buffer. + * This has the effect of allowing us to deal with reset + * floods (an external device holding down the reset line) + * without losing the event that is really interesting. + */ + lstate->event_r_idx = 0; + lstate->event_w_idx = 0; + xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); + } + + if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) { + xpt_print_path(lstate->path); + printf("immediate event %x:%x lost\n", + lstate->event_buffer[lstate->event_r_idx].event_type, + lstate->event_buffer[lstate->event_r_idx].event_arg); + lstate->event_r_idx++; + if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_r_idx = 0; + xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); + } + + event = &lstate->event_buffer[lstate->event_w_idx]; + event->initiator_id = initiator_id; + event->event_type = event_type; + event->event_arg = event_arg; + lstate->event_w_idx++; + if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_w_idx = 0; +} + +/* + * Send any target mode events queued up waiting + * for immediate notify resources. + */ +void +ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) +{ + struct ccb_hdr *ccbh; + struct ccb_immed_notify *inot; + + while (lstate->event_r_idx != lstate->event_w_idx + && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { + struct ahc_tmode_event *event; + + event = &lstate->event_buffer[lstate->event_r_idx]; + SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); + inot = (struct ccb_immed_notify *)ccbh; + switch (event->event_type) { + case EVENT_TYPE_BUS_RESET: + ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; + break; + default: + ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; + inot->message_args[0] = event->event_type; + inot->message_args[1] = event->event_arg; + break; + } + inot->initiator_id = event->initiator_id; + inot->sense_len = 0; + xpt_done((union ccb *)inot); + lstate->event_r_idx++; + if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_r_idx = 0; + } +} +#endif + +/******************** Sequencer Program Patching/Download *********************/ + +#ifdef AHC_DUMP_SEQ +void +ahc_dumpseq(struct ahc_softc* ahc) +{ + int i; + int max_prog; + + if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI) + max_prog = 448; + else if ((ahc->features & AHC_ULTRA2) != 0) + max_prog = 768; + else + max_prog = 512; + + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + for (i = 0; i < max_prog; i++) { + uint8_t ins_bytes[4]; + + ahc_insb(ahc, SEQRAM, ins_bytes, 4); + printf("0x%08x\n", ins_bytes[0] << 24 + | ins_bytes[1] << 16 + | ins_bytes[2] << 8 + | ins_bytes[3]); + } +} +#endif + +static void +ahc_loadseq(struct ahc_softc *ahc) +{ + struct cs cs_table[num_critical_sections]; + u_int begin_set[num_critical_sections]; + u_int end_set[num_critical_sections]; + struct patch *cur_patch; + u_int cs_count; + u_int cur_cs; + u_int i; + int downloaded; + u_int skip_addr; + u_int sg_prefetch_cnt; + uint8_t download_consts[7]; + + /* + * Start out with 0 critical sections + * that apply to this firmware load. + */ + cs_count = 0; + cur_cs = 0; + memset(begin_set, 0, sizeof(begin_set)); + memset(end_set, 0, sizeof(end_set)); + + /* Setup downloadable constant table */ + download_consts[QOUTFIFO_OFFSET] = 0; + if (ahc->targetcmds != NULL) + download_consts[QOUTFIFO_OFFSET] += 32; + download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1; + download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1; + download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1); + sg_prefetch_cnt = ahc->pci_cachesize; + if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg))) + sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg); + download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; + download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1); + download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1); + + cur_patch = patches; + downloaded = 0; + skip_addr = 0; + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + + for (i = 0; i < sizeof(seqprog)/4; i++) { + if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) { + /* + * Don't download this instruction as it + * is in a patch that was removed. + */ + continue; + } + /* + * Move through the CS table until we find a CS + * that might apply to this instruction. + */ + for (; cur_cs < num_critical_sections; cur_cs++) { + if (critical_sections[cur_cs].end <= i) { + if (begin_set[cs_count] == TRUE + && end_set[cs_count] == FALSE) { + cs_table[cs_count].end = downloaded; + end_set[cs_count] = TRUE; + cs_count++; + } + continue; + } + if (critical_sections[cur_cs].begin <= i + && begin_set[cs_count] == FALSE) { + cs_table[cs_count].begin = downloaded; + begin_set[cs_count] = TRUE; + } + break; + } + ahc_download_instr(ahc, i, download_consts); + downloaded++; + } + + ahc->num_critical_sections = cs_count; + if (cs_count != 0) { + + cs_count *= sizeof(struct cs); + ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); + if (ahc->critical_sections == NULL) + panic("ahc_loadseq: Could not malloc"); + memcpy(ahc->critical_sections, cs_table, cs_count); + } + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); + ahc_restart(ahc); + + if (bootverbose) + printf(" %d instructions downloaded\n", downloaded); +} + +static int +ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, + u_int start_instr, u_int *skip_addr) +{ + struct patch *cur_patch; + struct patch *last_patch; + u_int num_patches; + + num_patches = sizeof(patches)/sizeof(struct patch); + last_patch = &patches[num_patches]; + cur_patch = *start_patch; + + while (cur_patch < last_patch && start_instr == cur_patch->begin) { + + if (cur_patch->patch_func(ahc) == 0) { + + /* Start rejecting code */ + *skip_addr = start_instr + cur_patch->skip_instr; + cur_patch += cur_patch->skip_patch; + } else { + /* Accepted this patch. Advance to the next + * one and wait for our intruction pointer to + * hit this point. + */ + cur_patch++; + } + } + + *start_patch = cur_patch; + if (start_instr < *skip_addr) + /* Still skipping */ + return (0); + + return (1); +} + +static void +ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) +{ + union ins_formats instr; + struct ins_format1 *fmt1_ins; + struct ins_format3 *fmt3_ins; + u_int opcode; + + /* + * The firmware is always compiled into a little endian format. + */ + instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); + + fmt1_ins = &instr.format1; + fmt3_ins = NULL; + + /* Pull the opcode */ + opcode = instr.format1.opcode; + switch (opcode) { + case AIC_OP_JMP: + case AIC_OP_JC: + case AIC_OP_JNC: + case AIC_OP_CALL: + case AIC_OP_JNE: + case AIC_OP_JNZ: + case AIC_OP_JE: + case AIC_OP_JZ: + { + struct patch *cur_patch; + int address_offset; + u_int address; + u_int skip_addr; + u_int i; + + fmt3_ins = &instr.format3; + address_offset = 0; + address = fmt3_ins->address; + cur_patch = patches; + skip_addr = 0; + + for (i = 0; i < address;) { + + ahc_check_patch(ahc, &cur_patch, i, &skip_addr); + + if (skip_addr > i) { + int end_addr; + + end_addr = MIN(address, skip_addr); + address_offset += end_addr - i; + i = skip_addr; + } else { + i++; + } + } + address -= address_offset; + fmt3_ins->address = address; + /* FALLTHROUGH */ + } + case AIC_OP_OR: + case AIC_OP_AND: + case AIC_OP_XOR: + case AIC_OP_ADD: + case AIC_OP_ADC: + case AIC_OP_BMOV: + if (fmt1_ins->parity != 0) { + fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; + } + fmt1_ins->parity = 0; + if ((ahc->features & AHC_CMD_CHAN) == 0 + && opcode == AIC_OP_BMOV) { + /* + * Block move was added at the same time + * as the command channel. Verify that + * this is only a move of a single element + * and convert the BMOV to a MOV + * (AND with an immediate of FF). + */ + if (fmt1_ins->immediate != 1) + panic("%s: BMOV not supported\n", + ahc_name(ahc)); + fmt1_ins->opcode = AIC_OP_AND; + fmt1_ins->immediate = 0xff; + } + /* FALLTHROUGH */ + case AIC_OP_ROL: + if ((ahc->features & AHC_ULTRA2) != 0) { + int i, count; + + /* Calculate odd parity for the instruction */ + for (i = 0, count = 0; i < 31; i++) { + uint32_t mask; + + mask = 0x01 << i; + if ((instr.integer & mask) != 0) + count++; + } + if ((count & 0x01) == 0) + instr.format1.parity = 1; + } else { + /* Compress the instruction for older sequencers */ + if (fmt3_ins != NULL) { + instr.integer = + fmt3_ins->immediate + | (fmt3_ins->source << 8) + | (fmt3_ins->address << 16) + | (fmt3_ins->opcode << 25); + } else { + instr.integer = + fmt1_ins->immediate + | (fmt1_ins->source << 8) + | (fmt1_ins->destination << 16) + | (fmt1_ins->ret << 24) + | (fmt1_ins->opcode << 25); + } + } + /* The sequencer is a little endian cpu */ + instr.integer = ahc_htole32(instr.integer); + ahc_outsb(ahc, SEQRAM, instr.bytes, 4); + break; + default: + panic("Unknown opcode encountered in seq program"); + break; + } +} + +void +ahc_dump_card_state(struct ahc_softc *ahc) +{ + struct scb *scb; + struct scb_tailq *untagged_q; + int target; + int maxtarget; + int i; + uint8_t last_phase; + uint8_t qinpos; + uint8_t qintail; + uint8_t qoutpos; + uint8_t scb_index; + uint8_t saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + + last_phase = ahc_inb(ahc, LASTPHASE); + printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", + ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); + printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", + ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX), + ahc_inb(ahc, ARG_2)); + printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT), + ahc_inb(ahc, SCBPTR)); + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); + printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", + ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); + printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", + last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); + printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", + ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); + if ((ahc->features & AHC_DT) != 0) + printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); + printf("SCB count = %d\n", ahc->scb_data->numscbs); + printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); + printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); + /* QINFIFO */ + printf("QINFIFO entries: "); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + qinpos = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinpos); + } else + qinpos = ahc_inb(ahc, QINPOS); + qintail = ahc->qinfifonext; + while (qinpos != qintail) { + printf("%d ", ahc->qinfifo[qinpos]); + qinpos++; + } + printf("\n"); + + printf("Waiting Queue entries: "); + scb_index = ahc_inb(ahc, WAITING_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + printf("Disconnected Queue entries: "); + scb_index = ahc_inb(ahc, DISCONNECTED_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); + printf("QOUTFIFO entries: "); + qoutpos = ahc->qoutfifonext; + i = 0; + while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) { + printf("%d ", ahc->qoutfifo[qoutpos]); + qoutpos++; + } + printf("\n"); + + printf("Sequencer Free SCB List: "); + scb_index = ahc_inb(ahc, FREE_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d ", scb_index); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + printf("Sequencer SCB Info: "); + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + ahc_outb(ahc, SCBPTR, i); + printf("%d(c 0x%x, s 0x%x, l %d, t 0x%x) ", + i, ahc_inb(ahc, SCB_CONTROL), + ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), + ahc_inb(ahc, SCB_TAG)); + } + printf("\n"); + + printf("Pending list: "); + i = 0; + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + if (i++ > 256) + break; + if (scb != LIST_FIRST(&ahc->pending_scbs)) + printf(", "); + printf("%d(c 0x%x, s 0x%x, l %d)", scb->hscb->tag, + scb->hscb->control, scb->hscb->scsiid, scb->hscb->lun); + if ((ahc->flags & AHC_PAGESCBS) == 0) { + ahc_outb(ahc, SCBPTR, scb->hscb->tag); + printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL), + ahc_inb(ahc, SCB_TAG)); + } + } + printf("\n"); + + printf("Kernel Free SCB list: "); + i = 0; + SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) { + if (i++ > 256) + break; + printf("%d ", scb->hscb->tag); + } + printf("\n"); + + maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; + for (target = 0; target <= maxtarget; target++) { + untagged_q = &ahc->untagged_queues[target]; + if (TAILQ_FIRST(untagged_q) == NULL) + continue; + printf("Untagged Q(%d): ", target); + i = 0; + TAILQ_FOREACH(scb, untagged_q, links.tqe) { + if (i++ > 256) + break; + printf("%d ", scb->hscb->tag); + } + printf("\n"); + } + + ahc_platform_dump_card_state(ahc); + ahc_outb(ahc, SCBPTR, saved_scbptr); +} + +/************************* Target Mode ****************************************/ +#ifdef AHC_TARGET_MODE +cam_status +ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, + int notfound_failure) +{ + + if ((ahc->features & AHC_TARGETMODE) == 0) + return (CAM_REQ_INVALID); + + /* + * Handle the 'black hole' device that sucks up + * requests to unattached luns on enabled targets. + */ + if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD + && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { + *tstate = NULL; + *lstate = ahc->black_hole; + } else { + u_int max_id; + + max_id = (ahc->features & AHC_WIDE) ? 15 : 7; + if (ccb->ccb_h.target_id > max_id) + return (CAM_TID_INVALID); + + if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS) + return (CAM_LUN_INVALID); + + *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; + *lstate = NULL; + if (*tstate != NULL) + *lstate = + (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; + } + + if (notfound_failure != 0 && *lstate == NULL) + return (CAM_PATH_INVALID); + + return (CAM_REQ_CMP); +} + +void +ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) +{ + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; + struct ccb_en_lun *cel; + cam_status status; + u_int target; + u_int lun; + u_int target_mask; + u_long s; + char channel; + + status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, + /*notfound_failure*/FALSE); + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + return; + } + + if ((ahc->features & AHC_MULTIROLE) != 0) { + u_int our_id; + + if (cam_sim_bus(sim) == 0) + our_id = ahc->our_id; + else + our_id = ahc->our_id_b; + + if (ccb->ccb_h.target_id != our_id) { + if ((ahc->features & AHC_MULTI_TID) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) { + /* + * Only allow additional targets if + * the initiator role is disabled. + * The hardware cannot handle a re-select-in + * on the initiator id during a re-select-out + * on a different target id. + */ + status = CAM_TID_INVALID; + } else if ((ahc->flags & AHC_INITIATORROLE) != 0 + || ahc->enabled_luns > 0) { + /* + * Only allow our target id to change + * if the initiator role is not configured + * and there are no enabled luns which + * are attached to the currently registered + * scsi id. + */ + status = CAM_TID_INVALID; + } + } + } + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + return; + } + + /* + * We now have an id that is valid. + * If we aren't in target mode, switch modes. + */ + if ((ahc->flags & AHC_TARGETROLE) == 0 + && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { + u_long s; + + printf("Configuring Target Mode\n"); + ahc_lock(ahc, &s); + if (LIST_FIRST(&ahc->pending_scbs) != NULL) { + ccb->ccb_h.status = CAM_BUSY; + ahc_unlock(ahc, &s); + return; + } + ahc->flags |= AHC_TARGETROLE; + if ((ahc->features & AHC_MULTIROLE) == 0) + ahc->flags &= ~AHC_INITIATORROLE; + ahc_pause(ahc); + ahc_loadseq(ahc); + ahc_unlock(ahc, &s); + } + cel = &ccb->cel; + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + channel = SIM_CHANNEL(ahc, sim); + target_mask = 0x01 << target; + if (channel == 'B') + target_mask <<= 8; + + if (cel->enable != 0) { + u_int scsiseq; + + /* Are we already enabled?? */ + if (lstate != NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Lun already enabled\n"); + ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; + return; + } + + if (cel->grp6_len != 0 + || cel->grp7_len != 0) { + /* + * Don't (yet?) support vendor + * specific commands. + */ + ccb->ccb_h.status = CAM_REQ_INVALID; + printf("Non-zero Group Codes\n"); + return; + } + + /* + * Seems to be okay. + * Setup our data structures. + */ + if (target != CAM_TARGET_WILDCARD && tstate == NULL) { + tstate = ahc_alloc_tstate(ahc, target, channel); + if (tstate == NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate tstate\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + } + lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); + if (lstate == NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate lstate\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + memset(lstate, 0, sizeof(*lstate)); + status = xpt_create_path(&lstate->path, /*periph*/NULL, + xpt_path_path_id(ccb->ccb_h.path), + xpt_path_target_id(ccb->ccb_h.path), + xpt_path_lun_id(ccb->ccb_h.path)); + if (status != CAM_REQ_CMP) { + free(lstate, M_DEVBUF); + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate path\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + SLIST_INIT(&lstate->accept_tios); + SLIST_INIT(&lstate->immed_notifies); + ahc_lock(ahc, &s); + ahc_pause(ahc); + if (target != CAM_TARGET_WILDCARD) { + tstate->enabled_luns[lun] = lstate; + ahc->enabled_luns++; + + if ((ahc->features & AHC_MULTI_TID) != 0) { + u_int targid_mask; + + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) << 8); + + targid_mask |= target_mask; + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); + + ahc_update_scsiid(ahc, targid_mask); + } else { + u_int our_id; + char channel; + + channel = SIM_CHANNEL(ahc, sim); + our_id = SIM_SCSI_ID(ahc, sim); + + /* + * This can only happen if selections + * are not enabled + */ + if (target != our_id) { + u_int sblkctl; + char cur_channel; + int swap; + + sblkctl = ahc_inb(ahc, SBLKCTL); + cur_channel = (sblkctl & SELBUSB) + ? 'B' : 'A'; + if ((ahc->features & AHC_TWIN) == 0) + cur_channel = 'A'; + swap = cur_channel != channel; + if (channel == 'A') + ahc->our_id = target; + else + ahc->our_id_b = target; + + if (swap) + ahc_outb(ahc, SBLKCTL, + sblkctl ^ SELBUSB); + + ahc_outb(ahc, SCSIID, target); + + if (swap) + ahc_outb(ahc, SBLKCTL, sblkctl); + } + } + } else + ahc->black_hole = lstate; + /* Allow select-in operations */ + if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { + scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); + scsiseq |= ENSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); + scsiseq = ahc_inb(ahc, SCSISEQ); + scsiseq |= ENSELI; + ahc_outb(ahc, SCSISEQ, scsiseq); + } + ahc_unpause(ahc); + ahc_unlock(ahc, &s); + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_print_path(ccb->ccb_h.path); + printf("Lun now enabled for target mode\n"); + } else { + struct scb *scb; + int i, empty; + + if (lstate == NULL) { + ccb->ccb_h.status = CAM_LUN_INVALID; + return; + } + + ahc_lock(ahc, &s); + + ccb->ccb_h.status = CAM_REQ_CMP; + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + struct ccb_hdr *ccbh; + + ccbh = &scb->io_ctx->ccb_h; + if (ccbh->func_code == XPT_CONT_TARGET_IO + && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ + printf("CTIO pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + ahc_unlock(ahc, &s); + return; + } + } + + if (SLIST_FIRST(&lstate->accept_tios) != NULL) { + printf("ATIOs pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + } + + if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { + printf("INOTs pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + } + + if (ccb->ccb_h.status != CAM_REQ_CMP) { + ahc_unlock(ahc, &s); + return; + } + + xpt_print_path(ccb->ccb_h.path); + printf("Target mode disabled\n"); + xpt_free_path(lstate->path); + free(lstate, M_DEVBUF); + + ahc_pause(ahc); + /* Can we clean up the target too? */ + if (target != CAM_TARGET_WILDCARD) { + tstate->enabled_luns[lun] = NULL; + ahc->enabled_luns--; + for (empty = 1, i = 0; i < 8; i++) + if (tstate->enabled_luns[i] != NULL) { + empty = 0; + break; + } + + if (empty) { + ahc_free_tstate(ahc, target, channel, + /*force*/FALSE); + if (ahc->features & AHC_MULTI_TID) { + u_int targid_mask; + + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) + << 8); + + targid_mask &= ~target_mask; + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, + (targid_mask >> 8)); + ahc_update_scsiid(ahc, targid_mask); + } + } + } else { + + ahc->black_hole = NULL; + + /* + * We can't allow selections without + * our black hole device. + */ + empty = TRUE; + } + if (ahc->enabled_luns == 0) { + /* Disallow select-in */ + u_int scsiseq; + + scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); + scsiseq &= ~ENSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); + scsiseq = ahc_inb(ahc, SCSISEQ); + scsiseq &= ~ENSELI; + ahc_outb(ahc, SCSISEQ, scsiseq); + + if ((ahc->features & AHC_MULTIROLE) == 0) { + printf("Configuring Initiator Mode\n"); + ahc->flags &= ~AHC_TARGETROLE; + ahc->flags |= AHC_INITIATORROLE; + ahc_pause(ahc); + ahc_loadseq(ahc); + } + } + ahc_unpause(ahc); + ahc_unlock(ahc, &s); + } +} + +static void +ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask) +{ + u_int scsiid_mask; + u_int scsiid; + + if ((ahc->features & AHC_MULTI_TID) == 0) + panic("ahc_update_scsiid called on non-multitid unit\n"); + + /* + * Since we will rely on the the TARGID mask + * for selection enables, ensure that OID + * in SCSIID is not set to some other ID + * that we don't want to allow selections on. + */ + if ((ahc->features & AHC_ULTRA2) != 0) + scsiid = ahc_inb(ahc, SCSIID_ULTRA2); + else + scsiid = ahc_inb(ahc, SCSIID); + scsiid_mask = 0x1 << (scsiid & OID); + if ((targid_mask & scsiid_mask) == 0) { + u_int our_id; + + /* ffs counts from 1 */ + our_id = ffs(targid_mask); + if (our_id == 0) + our_id = ahc->our_id; + else + our_id--; + scsiid &= TID; + scsiid |= our_id; + } + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, scsiid); + else + ahc_outb(ahc, SCSIID, scsiid); +} + +void +ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) +{ + struct target_cmd *cmd; + + /* + * If the card supports auto-access pause, + * we can access the card directly regardless + * of whether it is paused or not. + */ + if ((ahc->features & AHC_AUTOPAUSE) != 0) + paused = TRUE; + + ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD); + while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) { + + /* + * Only advance through the queue if we + * have the resources to process the command. + */ + if (ahc_handle_target_cmd(ahc, cmd) != 0) + break; + + cmd->cmd_valid = 0; + ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap, + ahc_targetcmd_offset(ahc, ahc->tqinfifonext), + sizeof(struct target_cmd), + BUS_DMASYNC_PREREAD); + ahc->tqinfifonext++; + + /* + * Lazily update our position in the target mode incoming + * command queue as seen by the sequencer. + */ + if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { + if ((ahc->features & AHC_HS_MAILBOX) != 0) { + u_int hs_mailbox; + + hs_mailbox = ahc_inb(ahc, HS_MAILBOX); + hs_mailbox &= ~HOST_TQINPOS; + hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS; + ahc_outb(ahc, HS_MAILBOX, hs_mailbox); + } else { + if (!paused) + ahc_pause(ahc); + ahc_outb(ahc, KERNEL_TQINPOS, + ahc->tqinfifonext & HOST_TQINPOS); + if (!paused) + ahc_unpause(ahc); + } + } + } +} + +static int +ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) +{ + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; + struct ccb_accept_tio *atio; + uint8_t *byte; + int initiator; + int target; + int lun; + + initiator = SCSIID_TARGET(ahc, cmd->scsiid); + target = SCSIID_OUR_ID(cmd->scsiid); + lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); + + byte = cmd->bytes; + tstate = ahc->enabled_targets[target]; + lstate = NULL; + if (tstate != NULL) + lstate = tstate->enabled_luns[lun]; + + /* + * Commands for disabled luns go to the black hole driver. + */ + if (lstate == NULL) + lstate = ahc->black_hole; + + atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); + if (atio == NULL) { + ahc->flags |= AHC_TQINFIFO_BLOCKED; + /* + * Wait for more ATIOs from the peripheral driver for this lun. + */ + return (1); + } else + ahc->flags &= ~AHC_TQINFIFO_BLOCKED; +#if 0 + printf("Incoming command from %d for %d:%d%s\n", + initiator, target, lun, + lstate == ahc->black_hole ? "(Black Holed)" : ""); +#endif + SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); + + if (lstate == ahc->black_hole) { + /* Fill in the wildcards */ + atio->ccb_h.target_id = target; + atio->ccb_h.target_lun = lun; + } + + /* + * Package it up and send it off to + * whomever has this lun enabled. + */ + atio->sense_len = 0; + atio->init_id = initiator; + if (byte[0] != 0xFF) { + /* Tag was included */ + atio->tag_action = *byte++; + atio->tag_id = *byte++; + atio->ccb_h.flags = CAM_TAG_ACTION_VALID; + } else { + atio->ccb_h.flags = 0; + } + byte++; + + /* Okay. Now determine the cdb size based on the command code */ + switch (*byte >> CMD_GROUP_CODE_SHIFT) { + case 0: + atio->cdb_len = 6; + break; + case 1: + case 2: + atio->cdb_len = 10; + break; + case 4: + atio->cdb_len = 16; + break; + case 5: + atio->cdb_len = 12; + break; + case 3: + default: + /* Only copy the opcode. */ + atio->cdb_len = 1; + printf("Reserved or VU command code type encountered\n"); + break; + } + + memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); + + atio->ccb_h.status |= CAM_CDB_RECVD; + + if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { + /* + * We weren't allowed to disconnect. + * We're hanging on the bus until a + * continue target I/O comes in response + * to this accept tio. + */ +#if 0 + printf("Received Immediate Command %d:%d:%d - %p\n", + initiator, target, lun, ahc->pending_device); +#endif + ahc->pending_device = lstate; + ahc_freeze_ccb((union ccb *)atio); + atio->ccb_h.flags |= CAM_DIS_DISCONNECT; + } + xpt_done((union ccb*)atio); + return (0); +} + +#endif diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_host.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_host.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_host.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,95 @@ +/* + * Adaptec AIC7xxx device driver host template for Linux. + * + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#1 $ + */ + +#ifndef _AIC7XXX_HOST_H_ +#define _AIC7XXX_HOST_H_ + +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int ahc_linux_detect(Scsi_Host_Template *); +int ahc_linux_release(struct Scsi_Host *); +const char *ahc_linux_info(struct Scsi_Host *); +int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_bus_reset(Scsi_Cmnd *); +int ahc_linux_dev_reset(Scsi_Cmnd *); +int ahc_linux_abort(Scsi_Cmnd *); + +#if defined(__i386__) +# define AIC7XXX_BIOSPARAM ahc_linux_biosparam +#else +# define AIC7XXX_BIOSPARAM NULL +#endif + +/* + * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields + * to do with card config are filled in after the card is detected. + */ +#define AIC7XXX { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: ahc_linux_proc_info, \ + name: NULL, \ + detect: ahc_linux_detect, \ + release: ahc_linux_release, \ + info: ahc_linux_info, \ + command: NULL, \ + queuecommand: ahc_linux_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: ahc_linux_abort, \ + eh_device_reset_handler: ahc_linux_dev_reset, \ + eh_bus_reset_handler: ahc_linux_bus_reset, \ + eh_host_reset_handler: NULL, \ + abort: NULL, \ + reset: NULL, \ + slave_attach: NULL, \ + bios_param: AIC7XXX_BIOSPARAM, \ + can_queue: 253, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: 0, /* max scatter-gather cmds */\ + cmd_per_lun: 2, /* cmds per lun */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ +} + +#endif /* _AIC7XXX_HOST_H_ */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_inline.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_inline.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_inline.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_inline.h Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#31 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ */ @@ -231,7 +231,8 @@ /*********************** Miscelaneous Support Functions ***********************/ -static __inline void ahc_update_residual(struct scb *scb); +static __inline void ahc_update_residual(struct ahc_softc *ahc, + struct scb *scb); static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, @@ -255,13 +256,13 @@ * for this SCB/transaction. */ static __inline void -ahc_update_residual(struct scb *scb) +ahc_update_residual(struct ahc_softc *ahc, struct scb *scb) { uint32_t sgptr; sgptr = ahc_le32toh(scb->hscb->sgptr); if ((sgptr & SG_RESID_VALID) != 0) - ahc_calc_residual(scb); + ahc_calc_residual(ahc, scb); } /* @@ -517,10 +518,7 @@ * and asserted the interrupt again. */ ahc_flush_device_writes(ahc); -#ifdef AHC_TARGET_MODE - if ((ahc->flags & AHC_INITIATORROLE) != 0) -#endif - ahc_run_qoutfifo(ahc); + ahc_run_qoutfifo(ahc); #ifdef AHC_TARGET_MODE if ((ahc->flags & AHC_TARGETROLE) != 0) ahc_run_tqinfifo(ahc, /*paused*/FALSE); diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_linux.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_linux.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_linux.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_linux.c Thu Jan 1 01:00:00 1970 @@ -1,2843 +0,0 @@ -/* - * Adaptec AIC7xxx device driver for Linux. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#79 $ - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * 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) - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F - * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA - * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, - * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, - * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file - * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, - * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the - * ANSI SCSI-2 specification (draft 10c), ... - * - * -------------------------------------------------------------------------- - * - * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): - * - * Substantially modified to include support for wide and twin bus - * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * SCB paging, and other rework of the code. - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-2000 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - * - *--------------------------------------------------------------------------- - * - * Thanks also go to (in alphabetical order) the following: - * - * Rory Bolt - Sequencer bug fixes - * Jay Estabrook - Initial DEC Alpha support - * Doug Ledford - Much needed abort/reset bug fixes - * Kai Makisara - DMAing of SCBs - * - * A Boot time option was also added for not resetting the scsi bus. - * - * Form: aic7xxx=extended - * aic7xxx=no_reset - * aic7xxx=verbose - * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 - * - * Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp - */ - -/* - * Further driver modifications made by Doug Ledford - * - * Copyright (c) 1997-1999 Doug Ledford - * - * These changes are released under the same licensing terms as the FreeBSD - * driver written by Justin Gibbs. Please see his Copyright notice above - * for the exact terms and conditions covering my changes as well as the - * warranty statement. - * - * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include - * but are not limited to: - * - * 1: Import of the latest FreeBSD sequencer code for this driver - * 2: Modification of kernel code to accomodate different sequencer semantics - * 3: Extensive changes throughout kernel portion of driver to improve - * abort/reset processing and error hanndling - * 4: Other work contributed by various people on the Internet - * 5: Changes to printk information and verbosity selection code - * 6: General reliability related changes, especially in IRQ management - * 7: Modifications to the default probe/attach order for supported cards - * 8: SMP friendliness has been improved - * - */ - -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) -#include /* __setup */ -#endif - -#include "../sd.h" /* For geometry detection */ - -#include /* For fetching system memory size */ -#include - -/* - * To generate the correct addresses for the controller to issue - * on the bus. Originally added for DEC Alpha support. - */ -#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a)) - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -struct proc_dir_entry proc_scsi_aic7xxx = { - PROC_SCSI_AIC7XXX, 7, "aic7xxx", - S_IFDIR | S_IRUGO | S_IXUGO, 2, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; -#endif - -/* - * Set this to the delay in seconds after SCSI bus reset. - * Note, we honor this only for the initial bus reset. - * The scsi error recovery code performs its own bus settle - * delay handling for error recovery actions. - */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS -#else -#define AIC7XXX_RESET_DELAY 5000 -#endif - -/* - * Control collection of SCSI transfer statistics for the /proc filesystem. - * - * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. - * NOTE: This does affect performance since it has to maintain statistics. - */ -#ifdef CONFIG_AIC7XXX_PROC_STATS -#define AIC7XXX_PROC_STATS -#endif - -/* - * To change the default number of tagged transactions allowed per-device, - * add a line to the lilo.conf file like: - * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - * - * The tag_commands is an array of 16 to allow for wide and twin adapters. - * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15 - * for channel 1. - */ -typedef struct { - uint8_t tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Modify this as you see fit for your system. - * - * 0 tagged queuing disabled - * 1 <= n <= 253 n == max tags ever dispatched. - * - * The driver will throttle the number of commands dispatched to a - * device if it returns queue full. For devices with a fixed maximum - * queue depth, the driver will eventually determine this depth and - * lock it in (a console message is printed to indicate that a lock - * has occurred). On some devices, queue full is returned for a temporary - * resource shortage. These devices will return queue full at varying - * depths. The driver will throttle back when the queue fulls occur and - * attempt to slowly increase the depth over time as the device recovers - * from the resource shortage. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic7xxx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to attempt to use up to 64 tags for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is just below this comment block. -adapter_tag_info_t aic7xxx_tag_info[] = -{ - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE -#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE -#else -#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE -#endif - -#define AIC7XXX_CONFIGED_TAG_COMMANDS { \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE \ -} - -/* - * By default, use the number of commands specified by - * the users kernel configuration. - */ -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS} -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -void -ahc_print_path(struct ahc_softc *ahc, struct scb *scb) -{ - printk("(scsi%d:%c:%d:%d): ", - ahc->platform_data->host->host_no, - scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X', - scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1, - scb != NULL ? SCB_GET_LUN(scb) : -1); -} - -/* - * XXX - these options apply unilaterally to _all_ 274x/284x/294x - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static uint32_t aic7xxx_no_reset; - -/* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static int aic7xxx_reverse_scan = 0; - -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static uint32_t aic7xxx_extended = 0; - -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations, it can generate tons of false error messages. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * -1 = Normal polarity pci parity checking - * 1 = reverse polarity pci parity checking - * - * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this - * variable to -1 you would actually want to simply pass the variable - * name without a number. That will invert the 0 which will result in - * -1. - */ -static int aic7xxx_pci_parity = 0; - -/* - * Certain newer motherboards have put new PCI based devices into the - * IO spaces that used to typically be occupied by VLB or EISA cards. - * This overlap can cause these newer motherboards to lock up when scanned - * for older EISA and VLB devices. Setting this option to non-0 will - * cause the driver to skip scanning for any VLB or EISA controllers and - * only support the PCI controllers. NOTE: this means that if the kernel - * os compiled with PCI support disabled, then setting this to non-0 - * would result in never finding any devices :) - */ -int aic7xxx_no_probe; - -/* - * aic7xxx_detect() has been run, so register all device arrivals - * immediately with the system rather than deferring to the sorted - * attachment performed by aic7xxx_detect(). - */ -int aic7xxx_detect_complete; - -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 256ms because some older devices need a longer time - * to respond to initial selection. - */ -static int aic7xxx_seltime = 0x00; - -/* - * Certain devices do not perform any aging on commands. Should the - * device be saturated by commands in one portion of the disk, it is - * possible for transactions on far away sectors to never be serviced. - * To handle these devices, we can periodically send an ordered tag to - * force all outstanding transactions to be serviced prior to a new - * transaction. - */ -int aic7xxx_periodic_otag; - -/* - * Module information and settable options. - */ -#ifdef MODULE -static char *aic7xxx = NULL; -/* - * 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 trounce on me insmod!!\n"; - -MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); -MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) -MODULE_LICENSE("Dual BSD/GPL"); -#endif -MODULE_PARM(aic7xxx, "s"); -MODULE_PARM_DESC(aic7xxx, "period delimited, options string. - verbose Enable verbose/diagnostic logging - no_probe Disable EISA/VLB controller probing - no_reset Supress initial bus resets - extended Enable extended geometry on all controllers - periodic_otag Send an ordered tagged transaction periodically - to prevent tag starvation. This may be - required by some older disk drives/RAID arrays. - reverse_scan Sort PCI devices highest Bus/Slot to lowest - tag_info: Set per-target tag depth - seltime: Selection Timeout(0/256ms,1/128ms,2/64ms,3/32ms) - - Sample /etc/modules.conf line: - Enable verbose logging - Disable EISA/VLB probing - Set tag depth on Controller 2/Target 2 to 10 tags - Shorten the selection timeout to 128ms from its default of 256 - - options aic7xxx='\"verbose.no_probe.tag_info:{{}.{}.{..10}}.seltime:1\"' -"); -#endif - -static void ahc_linux_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, - struct scb *); -static void ahc_linux_filter_command(struct ahc_softc*, Scsi_Cmnd*, - struct scb*); -static void ahc_linux_sem_timeout(u_long arg); -static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc); -static void ahc_linux_release_sim_queue(u_long arg); -static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); -static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); -static void ahc_linux_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, - Scsi_Device *device); -static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, - u_int, u_int); -static void ahc_linux_free_target(struct ahc_softc*, - struct ahc_linux_target*); -static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, - struct ahc_linux_target*, - u_int); -static void ahc_linux_free_device(struct ahc_softc*, - struct ahc_linux_device*); -static void ahc_linux_run_device_queue(struct ahc_softc*, - struct ahc_linux_device*); -static void ahc_linux_setup_tag_info(char *p, char *end); -static int ahc_linux_next_unit(void); -static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); - -static __inline struct ahc_linux_device* - ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int alloc); -static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); -static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, - struct ahc_cmd *acmd); -static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*, - struct scb*); -static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); - -static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, - struct ahc_dma_seg *sg, - bus_addr_t addr, bus_size_t len); - -static __inline struct ahc_linux_device* -ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, - u_int lun, int alloc) -{ - struct ahc_linux_target *targ; - struct ahc_linux_device *dev; - u_int target_offset; - - target_offset = target; - if (channel != 0) - target_offset += 8; - targ = ahc->platform_data->targets[target_offset]; - if (targ == NULL) { - if (alloc != 0) { - targ = ahc_linux_alloc_target(ahc, channel, target); - if (targ == NULL) - return (NULL); - } else - return (NULL); - } - dev = targ->devices[lun]; - if (dev == NULL && alloc != 0) - dev = ahc_linux_alloc_device(ahc, targ, lun); - return (dev); -} - -static __inline void -ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) -{ - /* - * Typically, the complete queue has very few entries - * queued to it before the queue is emptied by - * ahc_linux_run_complete_queue, so sorting the entries - * by generation number should be inexpensive. - * We perform the sort so that commands that complete - * with an error are retuned in the order origionally - * queued to the controller so that any subsequent retries - * are performed in order. The underlying ahc routines do - * not guarantee the order that aborted commands will be - * returned to us. - */ - struct ahc_completeq *completeq; - struct ahc_cmd *list_cmd; - struct ahc_cmd *acmd; - - /* - * If we want the request requeued, make sure there - * are sufficent retries. In the old scsi error code, - * we used to be able to specify a result code that - * bypassed the retry count. Now we must use this - * hack. - */ - if (cmd->result == (CAM_REQUEUE_REQ << 16)) - cmd->retries--; - completeq = &ahc->platform_data->completeq; - list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahc_cmd *)cmd; - while (list_cmd != NULL - && acmd_scsi_cmd(list_cmd).serial_number - < acmd_scsi_cmd(acmd).serial_number) - list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); - if (list_cmd != NULL) - TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); - else - TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); -} - -static __inline void -ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) -{ - u_long done_flags; - - ahc_done_lock(ahc, &done_flags); - while (acmd != NULL) { - Scsi_Cmnd *cmd; - - cmd = &acmd_scsi_cmd(acmd); - acmd = TAILQ_NEXT(acmd, acmd_links.tqe); - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } - ahc_done_unlock(ahc, &done_flags); -} - -static __inline void -ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev) -{ - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahc_linux_run_device_queue(ahc, dev); -} - -static __inline void -ahc_linux_run_device_queues(struct ahc_softc *ahc) -{ - struct ahc_linux_device *dev; - - while ((ahc->flags & AHC_RESOURCE_SHORTAGE) == 0 - && ahc->platform_data->qfrozen == 0 - && (dev = TAILQ_FIRST(&ahc->platform_data->device_runq)) != NULL) { - TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); - dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_linux_check_device_queue(ahc, dev); - } -} - -static __inline void -ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd, struct scb *scb) -{ - /* - * Determine whether we care to filter - * information out of this command. If so, - * pass it on to ahc_linux_filter_command() for more - * heavy weight processing. - */ - if (cmd->cmnd[0] == INQUIRY) - ahc_linux_filter_command(ahc, cmd, scb); -} - -static __inline void -ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) -{ - Scsi_Cmnd *cmd; - - cmd = scb->io_ctx; - ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE); - if (cmd->use_sg != 0) { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); - } else if (cmd->request_bufflen != 0) { - u_int32_t high_addr; - - high_addr = ahc_le32toh(scb->sg_list[0].len) - & AHC_SG_HIGH_ADDR_MASK; - pci_unmap_single(ahc->dev_softc, - ahc_le32toh(scb->sg_list[0].addr) - | (((dma_addr_t)high_addr) << 8), - cmd->request_bufflen, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); - } -} - -static __inline int -ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, - struct ahc_dma_seg *sg, bus_addr_t addr, bus_size_t len) -{ - int consumed; - - if ((scb->sg_count + 1) > AHC_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHC_NSEG\n"); - - consumed = 1; - sg->addr = ahc_htole32(addr & 0xFFFFFFFF); - scb->platform_data->xfer_len += len; - if (sizeof(bus_addr_t) > 4 - && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* - * Due to DAC restrictions, we can't - * cross a 4GB boundary. - */ - if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) { - struct ahc_dma_seg *next_sg; - uint32_t next_len; - - printf("Crossed Seg\n"); - if ((scb->sg_count + 2) > AHC_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHC_NSEG\n"); - - consumed++; - next_sg = sg + 1; - next_sg->addr = 0; - next_len = 0x100000000 - (addr & 0xFFFFFFFF); - len -= next_len; - next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000; - next_sg->len = ahc_htole32(next_len); - } - len |= (addr >> 8) & 0x7F000000; - } - sg->len = ahc_htole32(len); - return (consumed); -} - -/************************ Shutdown/halt/reboot hook ***************************/ -#include -#include - -static struct notifier_block ahc_linux_notifier = { - ahc_linux_halt, NULL, 0 -}; - -static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) -{ - struct ahc_softc *ahc; - - if (event == SYS_DOWN || event == SYS_HALT) { - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - ahc_shutdown(ahc); - } - } - return (NOTIFY_OK); -} - -/******************************** Macros **************************************/ -#define BUILD_SCSIID(ahc, cmd) \ - ((((cmd)->target << TID_SHIFT) & TID) \ - | (((cmd)->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ - | (((cmd)->channel == 0) ? 0 : TWIN_CHNLB)) - -/******************************** Bus DMA *************************************/ -int -ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - bus_addr_t lowaddr, bus_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) -{ - bus_dma_tag_t dmat; - - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); - if (dmat == NULL) - return (ENOMEM); - - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; - return (0); -} - -void -ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) -{ - free(dmat, M_DEVBUF); -} - -int -ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) -{ - bus_dmamap_t map; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if(ahc->dev_softc) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) - pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF); -#else - ahc->dev_softc->dma_mask = 0xFFFFFFFF; -#endif - *vaddr = pci_alloc_consistent(ahc->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahc->dev_softc) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) - pci_set_dma_mask(ahc->dev_softc, ahc->platform_data->hw_dma_mask); -#else - ahc->dev_softc->dma_mask = ahc->platform_data->hw_dma_mask; -#endif -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ - /* - * At least in 2.2.14, malloc is a slab allocator so all - * allocations are aligned. We assume for these kernel versions - * that all allocations will be bellow 4Gig, physically contiguous, - * and accessable via DMA by the controller. - */ - map = NULL; /* No additional information to store */ - *vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT); -#endif - if (*vaddr == NULL) - return (ENOMEM); - *mapp = map; - return(0); -} - -void -ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - pci_free_consistent(ahc->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); -#else - free(vaddr, M_DEVBUF); -#endif -} - -int -ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) -{ - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - stack_sg.ds_addr = map->bus_addr; -#else - stack_sg.ds_addr = VIRT_TO_BUS(buf); -#endif - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} - -void -ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* - * The map may is NULL in our < 2.3.X implementation. - */ - if (map != NULL) - free(map, M_DEVBUF); -} - -int -ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* Nothing to do */ - return (0); -} - -/********************* Platform Dependent Functions ***************************/ -int -ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) -{ - int value; - int rvalue; - int lvalue; - - /* - * Under Linux, cards are ordered as follows: - * 1) VLB/EISA BIOS enabled devices sorted by BIOS address. - * 2) PCI devices with BIOS enabled sorted by bus/slot/func. - * 3) All remaining VLB/EISA devices sorted by ioport. - * 4) All remaining PCI devices sorted by bus/slot/func. - */ - value = (lahc->flags & AHC_BIOS_ENABLED) - - (rahc->flags & AHC_BIOS_ENABLED); - if (value != 0) - /* Controllers with BIOS enabled have a *higher* priority */ - return (-value); - - /* - * Same BIOS setting, now sort based on bus type. - * EISA and VL controllers sort together. EISA/VL - * have higher priority than PCI. - */ - rvalue = (rahc->chip & AHC_BUS_MASK); - if (rvalue == AHC_VL) - rvalue = AHC_EISA; - lvalue = (lahc->chip & AHC_BUS_MASK); - if (lvalue == AHC_VL) - lvalue = AHC_EISA; - value = lvalue - rvalue; - if (value != 0) - return (value); - - /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ - switch (rvalue) { - case AHC_PCI: - { - char primary_channel; - - if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_bus(rahc->dev_softc) - - ahc_get_pci_bus(lahc->dev_softc); - else - value = ahc_get_pci_bus(lahc->dev_softc) - - ahc_get_pci_bus(rahc->dev_softc); - if (value != 0) - break; - if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_slot(rahc->dev_softc) - - ahc_get_pci_slot(lahc->dev_softc); - else - value = ahc_get_pci_slot(lahc->dev_softc) - - ahc_get_pci_slot(rahc->dev_softc); - if (value != 0) - break; - /* - * On multi-function devices, the user can choose - * to have function 1 probed before function 0. - * Give whichever channel is the primary channel - * the lowest priority. - */ - primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; - value = 1; - if (lahc->channel == primary_channel) - value = -1; - break; - } - case AHC_EISA: - if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { - value = lahc->platform_data->bios_address - - rahc->platform_data->bios_address; - } else { - value = lahc->bsh.ioport - - rahc->bsh.ioport; - } - break; - default: - panic("ahc_softc_sort: invalid bus type"); - } - return (value); -} - -static void -ahc_linux_setup_tag_info(char *p, char *end) -{ - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - - instance = -1; - targ = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - else if (targ == -1) - targ = 0; - tok++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - if ((targ >= AHC_NUM_TARGETS) || - (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) && (targ >= 0) - && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) - && (targ < AHC_NUM_TARGETS)) { - aic7xxx_tag_info[instance].tag_commands[targ] = - simple_strtoul(tok, NULL, 0) & 0xff; - } - tok = tok_end; - break; - } - } - while ((p != base) && (p != NULL)) - p = strtok(NULL, ",."); -} - -/* - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic7xxx=stpwlev:1,extended - */ -int -aic7xxx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static struct { - const char *name; - uint32_t *flag; - } options[] = { - { "extended", &aic7xxx_extended }, - { "no_reset", &aic7xxx_no_reset }, - { "verbose", &aic7xxx_verbose }, - { "reverse_scan", &aic7xxx_reverse_scan }, - { "no_probe", &aic7xxx_no_probe }, - { "periodic_otag", &aic7xxx_periodic_otag }, - { "pci_parity", &aic7xxx_pci_parity }, - { "seltime", &aic7xxx_seltime }, - { "tag_info", NULL } - }; - - end = strchr(s, '\0'); - - for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) { - for (i = 0; i < NUM_ELEMENTS(options); i++) { - n = strlen(options[i].name); - - if (strncmp(options[i].name, p, n) != 0) - continue; - - if (strncmp(p, "tag_info", n) == 0) { - ahc_linux_setup_tag_info(p + n, end); - } else if (p[n] == ':') { - *(options[i].flag) = - simple_strtoul(p + n + 1, NULL, 0); - } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) = ~(*(options[i].flag)); - } - break; - } - } - register_reboot_notifier(&ahc_linux_notifier); - return 1; -} - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) -__setup("aic7xxx=", aic7xxx_setup); -#endif - -int aic7xxx_verbose; - -/* - * Try to detect an Adaptec 7XXX controller. - */ -int -ahc_linux_detect(Scsi_Host_Template *template) -{ - struct ahc_softc *ahc; - int found; - - /* - * Sanity checking of Linux SCSI data structures so - * that some of our hacks^H^H^H^H^Hassumptions aren't - * violated. - */ - if (offsetof(struct ahc_cmd_internal, end) - > offsetof(struct scsi_cmnd, host_scribble)) { - printf("ahc_linux_detect: SCSI data structures changed.\n"); - printf("ahc_linux_detect: Unable to attach\n"); - return (0); - } -#ifdef MODULE - /* - * If we've been passed any parameters, process them now. - */ - if (aic7xxx) - aic7xxx_setup(aic7xxx); - if (dummy_buffer[0] != 'P') - printk(KERN_WARNING -"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n" -"aic7xxx: to see the proper way to specify options to the aic7xxx module\n" -"aic7xxx: Specifically, don't use any commas when passing arguments to\n" -"aic7xxx: insmod or else it might trash certain memory areas.\n"); -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) - template->proc_name = "aic7xxx"; -#else - template->proc_dir = &proc_scsi_aic7xxx; -#endif - template->sg_tablesize = AHC_NSEG; - -#ifdef CONFIG_PCI - ahc_linux_pci_probe(template); -#endif - - if (aic7xxx_no_probe == 0) - aic7770_linux_probe(template); - - /* - * Register with the SCSI layer all - * controllers we've found. - */ - found = 0; - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - - if (ahc_linux_register_host(ahc, template) == 0) - found++; - } - aic7xxx_detect_complete++; - return (found); -} - -int -ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) -{ - char buf[80]; - struct Scsi_Host *host; - char *new_name; - u_long s; - - - template->name = ahc->description; - host = scsi_register(template, sizeof(struct ahc_softc *)); - if (host == NULL) - return (ENOMEM); - - ahc_lock(ahc, &s); - *((struct ahc_softc **)host->hostdata) = ahc; - ahc->platform_data->host = host; - host->can_queue = AHC_MAX_QUEUE; - host->cmd_per_lun = 2; - host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = ahc_linux_select_queue_depth; - /* XXX No way to communicate the ID for multiple channels */ - host->this_id = ahc->our_id; - host->irq = ahc->platform_data->irq; - host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; - host->max_lun = AHC_NUM_LUNS; - host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - ahc_set_unit(ahc, ahc_linux_next_unit()); - sprintf(buf, "scsi%d", host->host_no); - new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); - if (new_name != NULL) { - strcpy(new_name, buf); - ahc_set_name(ahc, new_name); - } - host->unique_id = ahc->unit; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) - scsi_set_pci_device(host, ahc->dev_softc); -#endif - ahc_linux_initialize_scsi_bus(ahc); - ahc_unlock(ahc, &s); - return (0); -} - -uint64_t -ahc_linux_get_memsize() -{ - struct sysinfo si; - - si_meminfo(&si); - return (si.totalram << PAGE_SHIFT); -} - -/* - * Find the smallest available unit number to use - * for a new device. We don't just use a static - * count to handle the "repeated hot-(un)plug" - * scenario. - */ -static int -ahc_linux_next_unit() -{ - struct ahc_softc *ahc; - int unit; - - unit = 0; -retry: - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (ahc->unit == unit) { - unit++; - goto retry; - } - } - return (unit); -} - -/* - * Place the SCSI bus into a known state by either resetting it, - * or forcing transfer negotiations on the next command to any - * target. - */ -void -ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) -{ - int i; - int numtarg; - - i = 0; - numtarg = 0; - - if (aic7xxx_no_reset != 0) - ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B); - - if ((ahc->flags & AHC_RESET_BUS_A) != 0) - ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE); - else - numtarg = (ahc->features & AHC_WIDE) ? 16 : 8; - - if ((ahc->features & AHC_TWIN) != 0) { - - if ((ahc->flags & AHC_RESET_BUS_B) != 0) { - ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE); - } else { - if (numtarg == 0) - i = 8; - numtarg += 8; - } - } - - for (; i < numtarg; i++) { - struct ahc_devinfo devinfo; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int our_id; - u_int target_id; - char channel; - - channel = 'A'; - our_id = ahc->our_id; - target_id = i; - if (i > 7 && (ahc->features & AHC_TWIN) != 0) { - channel = 'B'; - our_id = ahc->our_id_b; - target_id = i % 8; - } - tinfo = ahc_fetch_transinfo(ahc, channel, our_id, - target_id, &tstate); - tinfo->goal = tinfo->user; - /* - * Don't try negotiations that require PPR messages - * until we successfully retrieve Inquiry data. - */ - tinfo->goal.ppr_options = 0; - if (tinfo->goal.transport_version > SCSI_REV_2) - tinfo->goal.transport_version = SCSI_REV_2; - ahc_compile_devinfo(&devinfo, our_id, target_id, - CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_neg_request(ahc, &devinfo, tstate, - tinfo, /*force*/FALSE); - } - /* Give the bus some time to recover */ - if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc_linux_freeze_sim_queue(ahc); - init_timer(&ahc->platform_data->reset_timer); - ahc->platform_data->reset_timer.data = (u_long)ahc; - ahc->platform_data->reset_timer.expires = - jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; - ahc->platform_data->reset_timer.function = - ahc_linux_release_sim_queue; - add_timer(&ahc->platform_data->reset_timer); - } -} - -int -ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) -{ - ahc->platform_data = - malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT); - if (ahc->platform_data == NULL) - return (ENOMEM); - memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); - TAILQ_INIT(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->device_runq); - ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; - ahc_lockinit(ahc); - ahc_done_lockinit(ahc); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); -#else - ahc->platform_data->eh_sem = MUTEX_LOCKED; -#endif - ahc->seltime = (aic7xxx_seltime & 0x3) << 4; - ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; - return (0); -} - -void -ahc_platform_free(struct ahc_softc *ahc) -{ - if (ahc->platform_data != NULL) { - if (ahc->platform_data->host != NULL) - scsi_unregister(ahc->platform_data->host); - if (ahc->platform_data->irq) - free_irq(ahc->platform_data->irq, ahc); - if (ahc->tag == BUS_SPACE_PIO - && ahc->bsh.ioport != 0) - release_region(ahc->bsh.ioport, 256); - if (ahc->tag == BUS_SPACE_MEMIO - && ahc->bsh.maddr != NULL) { - u_long base_addr; - - base_addr = (u_long)ahc->bsh.maddr; - base_addr &= PAGE_MASK; - iounmap((void *)base_addr); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - release_mem_region(ahc->platform_data->mem_busaddr, - 0x1000); -#endif - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - /* XXX Need an instance detach in the PCI code */ - if (ahc->dev_softc != NULL) - ahc->dev_softc->driver = NULL; -#endif - free(ahc->platform_data, M_DEVBUF); - } -} - -void -ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb) -{ - ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_REQUEUE_REQ); -} - -void -ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - ahc_queue_alg alg) -{ - struct ahc_linux_device *dev; - int was_queuing; - int now_queuing; - - dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); - if (dev == NULL) - return; - was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); - now_queuing = alg != AHC_QUEUE_NONE; - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 - && (was_queuing != now_queuing) - && (dev->active != 0)) { - dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen++; - } - - dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG); - if (now_queuing) { - - if (!was_queuing) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm to take - * care of the rest. - */ - dev->maxtags = AHC_MAX_QUEUE; - dev->openings = dev->maxtags - dev->active; - } - if (alg == AHC_QUEUE_TAGGED) { - dev->flags |= AHC_DEV_Q_TAGGED; - if (aic7xxx_periodic_otag != 0) - dev->flags |= AHC_DEV_PERIODIC_OTAG; - } else - dev->flags |= AHC_DEV_Q_BASIC; - } else { - /* We can only have one opening */ - dev->maxtags = 0; - dev->openings = 1 - dev->active; - } -} - -int -ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - int chan; - int maxchan; - int targ; - int maxtarg; - int clun; - int maxlun; - int count; - - if (tag != SCB_LIST_NULL) - return (0); - - chan = 0; - if (channel != ALL_CHANNELS) { - chan = channel - 'A'; - maxchan = chan + 1; - } else { - maxchan = (ahc->features & AHC_TWIN) ? 2 : 1; - } - targ = 0; - if (target != CAM_TARGET_WILDCARD) { - targ = target; - maxtarg = targ + 1; - } else { - maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8; - } - clun = 0; - if (lun != CAM_LUN_WILDCARD) { - clun = lun; - maxlun = clun + 1; - } else { - maxlun = 16; - } - - count = 0; - for (; chan < maxchan; chan++) { - for (; targ < maxtarg; targ++) { - for (; clun < maxlun; clun++) { - struct ahc_linux_device *dev; - struct ahc_busyq *busyq; - struct ahc_cmd *acmd; - - dev = ahc_linux_get_device(ahc, chan, - targ, clun, - /*alloc*/FALSE); - if (dev == NULL) - continue; - - busyq = &dev->busyq; - while ((acmd = TAILQ_FIRST(busyq)) != NULL) { - Scsi_Cmnd *cmd; - - cmd = &acmd_scsi_cmd(acmd); - TAILQ_REMOVE(busyq, acmd, - acmd_links.tqe); - count++; - cmd->result = status << 16; - ahc_linux_queue_cmd_complete(ahc, cmd); - } - } - } - } - - return (count); -} - -/* - * Sets the queue depth for each SCSI device hanging - * off the input host adapter. - */ -static void -ahc_linux_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) -{ - Scsi_Device *device; - struct ahc_softc *ahc; - u_long flags; - int scbnum; - - ahc = *((struct ahc_softc **)host->hostdata); - ahc_lock(ahc, &flags); - scbnum = 0; - for (device = scsi_devs; device != NULL; device = device->next) { - if (device->host == host) { - ahc_linux_device_queue_depth(ahc, device); - scbnum += device->queue_depth; - } - } - ahc_unlock(ahc, &flags); -} - -/* - * Determines the queue depth for a given device. - */ -static void -ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) -{ - struct ahc_devinfo devinfo; - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - uint8_t tags; - - ahc_compile_devinfo(&devinfo, - device->channel == 0 ? ahc->our_id : ahc->our_id_b, - device->id, device->lun, - device->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - - tags = 0; - if (device->tagged_supported != 0 - && (ahc->user_discenable & devinfo.target_mask) != 0) { - if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { - - printf("aic7xxx: WARNING, insufficient " - "tag_info instances for installed " - "controllers. Using defaults\n"); - printf("aic7xxx: Please update the " - "aic7xxx_tag_info array in the " - "aic7xxx.c source file.\n"); - tags = AHC_MAX_QUEUE; - } else { - adapter_tag_info_t *tag_info; - - tag_info = &aic7xxx_tag_info[ahc->unit]; - tags = tag_info->tag_commands[devinfo.target_offset]; - if (tags > AHC_MAX_QUEUE) - tags = AHC_MAX_QUEUE; - } - } - if (tags != 0) { - device->queue_depth = tags; - ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); - printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n", - ahc->platform_data->host->host_no, device->channel + 'A', - device->id, device->lun, tags); - } else { - /* - * We allow the OS to queue 2 untagged transactions to - * us at any time even though we can only execute them - * serially on the controller/device. This should remove - * some latency. - */ - device->queue_depth = 2; - } -} - -/* - * Queue an SCB to the controller. - */ -int -ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) -{ - struct ahc_softc *ahc; - struct ahc_linux_device *dev; - u_long flags; - - ahc = *(struct ahc_softc **)cmd->host->hostdata; - - /* - * Save the callback on completion function. - */ - cmd->scsi_done = scsi_done; - - ahc_lock(ahc, &flags); - dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/TRUE); - if (dev == NULL) { - ahc_unlock(ahc, &flags); - printf("aic7xxx_linux_queue: Unable to allocate device!\n"); - return (-ENOMEM); - } - cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - ahc_linux_run_device_queues(ahc); - } - ahc_unlock(ahc, &flags); - return (0); -} - -static void -ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) -{ - struct ahc_cmd *acmd; - struct scsi_cmnd *cmd; - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - uint16_t mask; - - if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) - panic("running device on run list"); - - while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL - && dev->openings > 0 && dev->qfrozen == 0) { - - /* - * Schedule us to run later. The only reason we are not - * running is because the whole controller Q is frozen. - */ - if (ahc->platform_data->qfrozen != 0) { - - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, - dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - return; - } - /* - * Get an scb to use. - */ - if ((scb = ahc_get_scb(ahc)) == NULL) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, - dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - ahc->flags |= AHC_RESOURCE_SHORTAGE; - return; - } - TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); - cmd = &acmd_scsi_cmd(acmd); - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; - - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahc, cmd); - hscb->lun = cmd->lun; - mask = SCB_GET_TARGET_MASK(ahc, scb); - tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), - SCB_GET_OUR_ID(scb), - SCB_GET_TARGET(ahc, scb), &tstate); - hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->curr.offset; - if ((tstate->ultraenb & mask) != 0) - hscb->control |= ULTRAENB; - - if ((ahc->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } - - if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { - if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH - && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; - dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - if (hscb->cdb_len <= 12) { - memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); - } else { - memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); - scb->flags |= SCB_CDB32_PTR; - } - - scb->platform_data->xfer_len = 0; - ahc_set_residual(scb, 0); - ahc_set_sense_residual(scb, 0); - if (cmd->use_sg != 0) { - struct ahc_dma_seg *sg; - struct scatterlist *cur_seg; - struct scatterlist *end_seg; - int nseg; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, - scsi_to_pci_dma_dir(cmd ->sc_data_direction)); - end_seg = cur_seg + nseg; - /* Copy the segments into the SG list. */ - sg = scb->sg_list; - /* - * The sg_count may be larger than nseg if - * a transfer crosses a 32bit page. - */ - scb->sg_count = 0; - while(cur_seg < end_seg) { - bus_addr_t addr; - bus_size_t len; - int consumed; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - consumed = ahc_linux_map_seg(ahc, scb, - sg, addr, len); - sg += consumed; - scb->sg_count += consumed; - cur_seg++; - } - sg--; - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - - /* - * Reset the sg list pointer. - */ - scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); - - /* - * Copy the first SG into the "current" - * data pointer area. - */ - scb->hscb->dataptr = scb->sg_list->addr; - scb->hscb->datacnt = scb->sg_list->len; - } else if (cmd->request_bufflen != 0) { - struct ahc_dma_seg *sg; - bus_addr_t addr; - - sg = scb->sg_list; - addr = pci_map_single(ahc->dev_softc, - cmd->request_buffer, - cmd->request_bufflen, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); - scb->sg_count = 0; - scb->sg_count = ahc_linux_map_seg(ahc, scb, - sg, addr, - cmd->request_bufflen); - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - - /* - * Reset the sg list pointer. - */ - scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); - - /* - * Copy the first SG into the "current" - * data pointer area. - */ - scb->hscb->dataptr = sg->addr; - scb->hscb->datacnt = sg->len; - } else { - scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); - scb->hscb->dataptr = 0; - scb->hscb->datacnt = 0; - scb->sg_count = 0; - } - - ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE); - LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - - /* - * We only allow one untagged transaction - * per target in the initiator role unless - * we are storing a full busy target *lun* - * table in SCB space. - */ - if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 - && (ahc->features & AHC_SCB_BTT) == 0) { - struct scb_tailq *untagged_q; - int target_offset; - - target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); - untagged_q = &(ahc->untagged_queues[target_offset]); - TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); - scb->flags |= SCB_UNTAGGEDQ; - if (TAILQ_FIRST(untagged_q) != scb) - continue; - } - scb->flags |= SCB_ACTIVE; - ahc_queue_scb(ahc, scb); - } -} - -/* - * SCSI controller interrupt handler. - */ -void -ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) -{ - struct ahc_softc *ahc; - struct ahc_cmd *acmd; - u_long flags; - - ahc = (struct ahc_softc *) dev_id; - ahc_lock(ahc, &flags); - ahc_intr(ahc); - /* - * It would be nice to run the device queues from a - * bottom half handler, but as there is no way to - * dynamically register one, we'll have to postpone - * that until we get integrated into the kernel. - */ - ahc_linux_run_device_queues(ahc); - acmd = TAILQ_FIRST(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->completeq); - ahc_unlock(ahc, &flags); - if (acmd != NULL) - ahc_linux_run_complete_queue(ahc, acmd); -} - -void -ahc_platform_flushwork(struct ahc_softc *ahc) -{ - struct ahc_cmd *acmd; - - acmd = TAILQ_FIRST(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->completeq); - if (acmd != NULL) - ahc_linux_run_complete_queue(ahc, acmd); -} - -static struct ahc_linux_target* -ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) -{ - struct ahc_linux_target *targ; - u_int target_offset; - - targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT); - if (targ == NULL) - return (NULL); - memset(targ, 0, sizeof(*targ)); - targ->channel = channel; - targ->target = target; - target_offset = target; - if (channel != 0) - target_offset += 8; - ahc->platform_data->targets[target_offset] = targ; - return (targ); -} - -static void -ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) -{ - u_int target_offset; - - target_offset = targ->target; - if (targ->channel != 0) - target_offset += 8; - ahc->platform_data->targets[target_offset] = NULL; - free(targ, M_DEVBUF); -} - -static struct ahc_linux_device* -ahc_linux_alloc_device(struct ahc_softc *ahc, - struct ahc_linux_target *targ, u_int lun) -{ - struct ahc_linux_device *dev; - - dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); - if (dev == NULL) - return (NULL); - memset(dev, 0, sizeof(*dev)); - TAILQ_INIT(&dev->busyq); - dev->flags = AHC_DEV_UNCONFIGURED; - dev->lun = lun; - dev->target = targ; - - /* - * We start out life using untagged - * transactions of which we allow one. - */ - dev->openings = 1; - - /* - * Set maxtags to 0. This will be changed if we - * later determine that we are dealing with - * a tagged queuing capable device. - */ - dev->maxtags = 0; - - targ->refcount++; - targ->devices[lun] = dev; - return (dev); -} - -static void -ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) -{ - struct ahc_linux_target *targ; - - targ = dev->target; - targ->devices[dev->lun] = NULL; - free(dev, M_DEVBUF); - targ->refcount--; - if (targ->refcount == 0) - ahc_linux_free_target(ahc, targ); -} - -/* - * Return a string describing the driver. - */ -const char * -ahc_linux_info(struct Scsi_Host *host) -{ - static char buffer[512]; - char ahc_info[256]; - char *bp; - struct ahc_softc *ahc; - - bp = &buffer[0]; - ahc = *(struct ahc_softc **)host->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev "); - strcat(bp, AIC7XXX_DRIVER_VERSION); - strcat(bp, "\n"); - strcat(bp, " <"); - strcat(bp, ahc->description); - strcat(bp, ">\n"); - strcat(bp, " "); - ahc_controller_info(ahc, ahc_info); - strcat(bp, ahc_info); - strcat(bp, "\n"); - - return (bp); -} - -void -ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code, void *arg) -{ - switch (code) { - case AC_TRANSFER_NEG: - { - char buf[80]; - struct ahc_linux_target *targ; - struct info_str info; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - int target_offset; - - info.buffer = buf; - info.length = sizeof(buf); - info.offset = 0; - info.pos = 0; - tinfo = ahc_fetch_transinfo(ahc, channel, - channel == 'A' ? ahc->our_id - : ahc->our_id_b, - target, &tstate); - - /* - * Don't bother reporting results while - * negotiations are still pending. - */ - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options) - if (bootverbose == 0) - break; - - /* - * Don't bother reporting results that - * are identical to those last reported. - */ - target_offset = target; - if (channel == 'B') - target_offset += 8; - targ = ahc->platform_data->targets[target_offset]; - if (targ != NULL - && tinfo->curr.period == targ->last_tinfo.period - && tinfo->curr.width == targ->last_tinfo.width - && tinfo->curr.offset == targ->last_tinfo.offset - && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) - if (bootverbose == 0) - break; - - targ->last_tinfo.period = tinfo->curr.period; - targ->last_tinfo.width = tinfo->curr.width; - targ->last_tinfo.offset = tinfo->curr.offset; - targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; - - printf("(%s:%c:", ahc_name(ahc), channel); - if (target == CAM_TARGET_WILDCARD) - printf("*): "); - else - printf("%d): ", target); - ahc_format_transinfo(&info, &tinfo->curr); - if (info.pos < info.length) - *info.buffer = '\0'; - else - buf[info.length - 1] = '\0'; - printf("%s", buf); - break; - } - case AC_SENT_BDR: - break; - case AC_BUS_RESET: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - if (ahc->platform_data->host != NULL) { - scsi_report_bus_reset(ahc->platform_data->host, - channel - 'A'); - } -#endif - break; - default: - panic("ahc_send_async: Unexpected async event"); - } -} - -/* - * Calls the higher level scsi done function and frees the scb. - */ -void -ahc_done(struct ahc_softc *ahc, struct scb * scb) -{ - Scsi_Cmnd *cmd; - struct ahc_linux_device *dev; - - LIST_REMOVE(scb, pending_links); - if ((scb->flags & SCB_UNTAGGEDQ) != 0) { - struct scb_tailq *untagged_q; - int target_offset; - - target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); - untagged_q = &(ahc->untagged_queues[target_offset]); - TAILQ_REMOVE(untagged_q, scb, links.tqe); - ahc_run_untagged_queue(ahc, untagged_q); - } - - if ((scb->flags & SCB_ACTIVE) == 0) { - printf("SCB %d done'd twice\n", scb->hscb->tag); - ahc_dump_card_state(ahc); - panic("Stopping for safety"); - } - cmd = scb->io_ctx; - dev = scb->platform_data->dev; - dev->active--; - dev->openings++; - ahc_linux_unmap_scb(ahc, scb); - if (scb->flags & SCB_SENSE) { - memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), - MIN(sizeof(struct scsi_sense_data), - sizeof(cmd->sense_buffer))); - cmd->result |= (DRIVER_SENSE << 24); - } else { - /* - * Guard against stale sense data. - * The Linux mid-layer assumes that sense - * was retrieved anytime the first byte of - * the sense buffer looks "sane". - */ - cmd->sense_buffer[0] = 0; - } - if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) { - uint32_t amount_xferred; - - amount_xferred = - ahc_get_transfer_length(scb) - ahc_get_residual(scb); - if (amount_xferred < scb->io_ctx->underflow) { - printf("Saw underflow (%ld of %ld bytes). " - "Treated as error\n", - ahc_get_residual(scb), - ahc_get_transfer_length(scb)); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); - } else { - ahc_set_transaction_status(scb, CAM_REQ_CMP); - ahc_linux_sniff_command(ahc, cmd, scb); - } - } else if (ahc_get_transaction_status(scb) == DID_OK) { - ahc_linux_handle_scsi_status(ahc, dev, scb); - } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { - /* - * Should a selection timeout kill the device? - * That depends on whether the selection timeout - * is persistent. Since we have no guarantee that - * the mid-layer will issue an inquiry for this device - * again, we can't just kill it off. - dev->flags |= AHC_DEV_UNCONFIGURED; - */ - } - - if (dev->openings == 1 - && ahc_get_transaction_status(scb) == CAM_REQ_CMP - && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) - dev->tag_success_count++; - /* - * Some devices deal with temporary internal resource - * shortages by returning queue full. When the queue - * full occurrs, we throttle back. Slowly try to get - * back to our previous queue depth. - */ - if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) { - dev->tag_success_count = 0; - dev->openings++; - } - - if (dev->active == 0) - dev->commands_since_idle_or_otag = 0; - - if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 - && dev->active == 0) - ahc_linux_free_device(ahc, dev); - } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - } - - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printf("Recovery SCB completes\n"); - up(&ahc->platform_data->eh_sem); - } - - ahc_free_scb(ahc, scb); - ahc_linux_queue_cmd_complete(ahc, cmd); -} - -static void -ahc_linux_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) -{ - /* - * We don't currently trust the mid-layer to - * properly deal with queue full or busy. So, - * when one occurs, we tell the mid-layer to - * unconditionally requeue the command to us - * so that we can retry it ourselves. We also - * implement our own throttling mechanism so - * we don't clobber the device with too many - * commands. - */ - switch (ahc_get_scsi_status(scb)) { - default: - break; - case SCSI_STATUS_QUEUE_FULL: - { - /* - * By the time the core driver has returned this - * command, all other commands that were queued - * to us but not the device have been returned. - * This ensures that dev->active is equal to - * the number of commands actually queued to - * the device. - */ - dev->tag_success_count = 0; - if (dev->active != 0) { - /* - * Drop our opening count to the number - * of commands currently outstanding. - */ - dev->openings = 0; -/* - ahc_print_path(ahc, scb); - printf("Dropping tag count to %d\n", dev->active); - */ - if (dev->active == dev->tags_on_last_queuefull) { - - dev->last_queuefull_same_count++; - /* - * If we repeatedly see a queue full - * at the same queue depth, this - * device has a fixed number of tag - * slots. Lock in this tag depth - * so we stop seeing queue fulls from - * this device. - */ - if (dev->last_queuefull_same_count - == AHC_LOCK_TAGS_COUNT) { - dev->maxtags = dev->active; - ahc_print_path(ahc, scb); - printf("Locking max tag count at %d\n", - dev->active); - } - } else { - dev->tags_on_last_queuefull = dev->active; - dev->last_queuefull_same_count = 0; - } - ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahc_set_scsi_status(scb, SCSI_STATUS_OK); - break; - } - /* - * Drop down to a single opening, and treat this - * as if the target return BUSY SCSI status. - */ - dev->openings = 1; - /* FALLTHROUGH */ - } - case SCSI_STATUS_BUSY: - /* - * XXX Set a timer and handle ourselves???? - * For now we pray that the mid-layer does something - * sane for devices that are busy. - */ - ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); - break; - } -} - -static void -ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd, struct scb *scb) -{ - switch (cmd->cmnd[0]) { - case INQUIRY: - { - struct ahc_devinfo devinfo; - struct scsi_inquiry *inq; - struct scsi_inquiry_data *sid; - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - struct ahc_syncrate *syncrate; - struct ahc_linux_device *dev; - u_int scsiid; - u_int maxsync; - int transferred_len; - int minlen; - u_int width; - u_int period; - u_int offset; - u_int ppr_options; - - /* - * Validate the command. We only want to filter - * standard inquiry commands, not those querying - * Vital Product Data. - */ - inq = (struct scsi_inquiry *)cmd->cmnd; - if ((inq->byte2 & SI_EVPD) != 0 - || inq->page_code != 0) - break; - - if (cmd->use_sg != 0) { - printf("%s: SG Inquiry response ignored\n", - ahc_name(ahc)); - break; - } - transferred_len = ahc_get_transfer_length(scb) - - ahc_get_residual(scb); - sid = (struct scsi_inquiry_data *)cmd->request_buffer; - - /* - * Determine if this lun actually exists. If so, - * hold on to its corresponding device structure. - * If not, make sure we release the device and - * don't bother processing the rest of this inquiry - * command. - */ - dev = ahc_linux_get_device(ahc, cmd->channel, - cmd->target, cmd->lun, - /*alloc*/FALSE); - if (transferred_len >= 1 - && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - - dev->flags &= ~AHC_DEV_UNCONFIGURED; - } else { - dev->flags |= AHC_DEV_UNCONFIGURED; - break; - } - - /* - * Update our notion of this device's transfer - * negotiation capabilities. - */ - scsiid = BUILD_SCSIID(ahc, cmd); - ahc_compile_devinfo(&devinfo, SCSIID_OUR_ID(scsiid), - cmd->target, cmd->lun, - SCSIID_CHANNEL(ahc, scsiid), - ROLE_INITIATOR); - targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - width = targ_info->user.width; - period = targ_info->user.period; - offset = targ_info->user.offset; - ppr_options = targ_info->user.ppr_options; - minlen = offsetof(struct scsi_inquiry_data, version) + 1; - if (transferred_len >= minlen) { - targ_info->curr.protocol_version = SID_ANSI_REV(sid); - - /* - * Only attempt SPI3 once we've verified that - * the device claims to support SPI3 features. - */ - if (targ_info->curr.protocol_version < SCSI_REV_2) - targ_info->curr.transport_version = - SID_ANSI_REV(sid); - else - targ_info->curr.transport_version = - SCSI_REV_2; - } - - minlen = offsetof(struct scsi_inquiry_data, flags) + 1; - if (transferred_len >= minlen - && (sid->additional_length + 4) >= minlen) { - if ((sid->flags & SID_WBus16) == 0) - width = MSG_EXT_WDTR_BUS_8_BIT; - if ((sid->flags & SID_Sync) == 0) { - period = 0; - offset = 0; - ppr_options = 0; - } - } else { - /* Keep current settings */ - break; - } - minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; - /* - * This is a kludge to deal with inquiry requests that - * are not large enough for us to pull the spi3 bits. - * In this case, we assume that a device that tells us - * they can provide inquiry data that spans the SPI3 - * bits and says its SCSI3 can handle a PPR request. - * If the inquiry request has sufficient buffer space to - * cover these bits, we check them to see if any ppr options - * are available. - */ - if ((sid->additional_length + 4) >= minlen) { - if (transferred_len >= minlen - && (sid->spi3data & SID_SPI_CLOCK_DT) == 0) - ppr_options = 0; - - if (targ_info->curr.protocol_version > SCSI_REV_2) - targ_info->curr.transport_version = 3; - else - ppr_options = 0; - } else { - ppr_options = 0; - } - ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, - ROLE_UNKNOWN); - if ((ahc->features & AHC_ULTRA2) != 0) - maxsync = AHC_SYNCRATE_DT; - else if ((ahc->features & AHC_ULTRA) != 0) - maxsync = AHC_SYNCRATE_ULTRA; - else - maxsync = AHC_SYNCRATE_FAST; - - syncrate = ahc_find_syncrate(ahc, &period, - &ppr_options, maxsync); - ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, - &offset, width, ROLE_UNKNOWN); - if (offset == 0 || period == 0) { - period = 0; - offset = 0; - ppr_options = 0; - } - /* Apply our filtered user settings. */ - ahc_set_width(ahc, &devinfo, width, - AHC_TRANS_GOAL, /*paused*/FALSE); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, - offset, ppr_options, AHC_TRANS_GOAL, - /*paused*/FALSE); - break; - } - default: - panic("ahc_linux_filter_command: Unexpected Command type %x\n", - cmd->cmnd[0]); - break; - } -} - -static void -ahc_linux_sem_timeout(u_long arg) -{ - struct semaphore *sem; - - sem = (struct semaphore *)arg; - up(sem); -} - -static void -ahc_linux_freeze_sim_queue(struct ahc_softc *ahc) -{ - ahc->platform_data->qfrozen++; - if (ahc->platform_data->qfrozen == 1) - scsi_block_requests(ahc->platform_data->host); -} - -static void -ahc_linux_release_sim_queue(u_long arg) -{ - struct ahc_softc *ahc; - u_long s; - int unblock_reqs; - - ahc = (struct ahc_softc *)arg; - unblock_reqs = 0; - ahc_lock(ahc, &s); - if (ahc->platform_data->qfrozen > 0) - ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) { - unblock_reqs = 1; - ahc_linux_run_device_queues(ahc); - } - ahc_unlock(ahc, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) - scsi_unblock_requests(ahc->platform_data->host); -} - -static int -ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) -{ - struct ahc_softc *ahc; - struct ahc_cmd *acmd; - struct ahc_cmd *list_acmd; - struct ahc_linux_device *dev; - struct scb *pending_scb; - u_long s; - u_int saved_scbptr; - u_int active_scb_index; - u_int last_phase; - int retval; - int paused; - int wait; - int disconnected; - - paused = FALSE; - wait = FALSE; - ahc = *(struct ahc_softc **)cmd->host->hostdata; - acmd = (struct ahc_cmd *)cmd; - - printf("%s:%d:%d:%d: Attempting to queue a%s message\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun, - flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); - - /* - * It is a bug that the upper layer takes - * this lock just prior to calling us. - */ - spin_unlock_irq(&io_request_lock); - - ahc_lock(ahc, &s); - - /* - * First determine if we currently own this command. - * Start by searching the device queue. If not found - * there, check the pending_scb list. If not found - * at all, and the system wanted us to just abort the - * command return success. - */ - dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/FALSE); - - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - printf("%s:%d:%d:%d: Is not an active device\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - retval = SUCCESS; - goto no_cmd; - } - - TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { - if (list_acmd == acmd) - break; - } - - if (list_acmd != NULL) { - printf("%s:%d:%d:%d: Command found on device queue\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - if (flag == SCB_ABORT) { - TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); - cmd->result = DID_ABORT << 16; - ahc_linux_queue_cmd_complete(ahc, cmd); - retval = SUCCESS; - goto done; - } - } - - /* - * See if we can find a matching cmd in the pending list. - */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } - - if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { - - /* Any SCB for this device will do for a target reset */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (ahc_match_scb(ahc, pending_scb, cmd->target, - cmd->channel, CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR) == 0) - break; - } - } - - if (pending_scb == NULL) { - printf("%s:%d:%d:%d: Command not found\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - goto no_cmd; - } - - if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { - /* - * We can't queue two recovery actions using the same SCB - */ - retval = FAILED; - goto done; - } - - /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this cmd. - */ - ahc->flags |= AHC_ALL_INTERRUPTS; - do { - ahc_intr(ahc); - ahc_pause(ahc); - ahc_clear_critical_section(ahc); - } while (ahc_inb(ahc, INTSTAT) & INT_PEND); - ahc->flags &= ~AHC_ALL_INTERRUPTS; - paused = TRUE; - - ahc_dump_card_state(ahc); - - if ((pending_scb->flags & SCB_ACTIVE) == 0) { - printf("%s:%d:%d:%d: Command already completed\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - goto no_cmd; - } - - disconnected = TRUE; - if (flag == SCB_ABORT) { - if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', - cmd->lun, pending_scb->hscb->tag, - ROLE_INITIATOR, CAM_REQ_ABORTED, - SEARCH_COMPLETE) > 0) { - printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahc_name(ahc), cmd->channel, cmd->target, - cmd->lun); - retval = SUCCESS; - goto done; - } - } else if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', - cmd->lun, pending_scb->hscb->tag, - ROLE_INITIATOR, /*status*/0, - SEARCH_COUNT) > 0) { - disconnected = FALSE; - } - - /* - * At this point, pending_scb is the scb associated with the - * passed in command. That command is currently active on the - * bus, is in the disconnected state, or we're hoping to find - * a command for the same target active on the bus to abuse to - * send a BDR. Queue the appropriate message based on which of - * these states we are in. - */ - last_phase = ahc_inb(ahc, LASTPHASE); - saved_scbptr = ahc_inb(ahc, SCBPTR); - active_scb_index = ahc_inb(ahc, SCB_TAG); - if (last_phase != P_BUSFREE - && (pending_scb->hscb->tag == active_scb_index - || (flag == SCB_DEVICE_RESET - && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->target))) { - - /* - * We're active on the bus, so assert ATN - * and hope that the target responds. - */ - pending_scb = ahc_lookup_scb(ahc, active_scb_index); - pending_scb->flags |= SCB_RECOVERY_SCB|flag; - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, last_phase|ATNO); - printf("%s:%d:%d:%d: Device is active, asserting ATN\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - wait = TRUE; - } else if (disconnected) { - - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - * In either case (selection or reselection), - * we will now issue the approprate message - * to the timed-out device. - * - * Set the MK_MESSAGE control bit indicating - * that we desire to send a message. We - * also set the disconnected flag since - * in the paging case there is no guarantee - * that our SCB control byte matches the - * version on the card. We don't want the - * sequencer to abort the command thinking - * an unsolicited reselection occurred. - */ - pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - pending_scb->flags |= SCB_RECOVERY_SCB|flag; - - /* - * Remove any cached copy of this SCB in the - * disconnected list in preparation for the - * queuing of our abort SCB. We use the - * same element in the SCB, SCB_NEXT, for - * both the qinfifo and the disconnected list. - */ - ahc_search_disc_list(ahc, cmd->target, cmd->channel + 'A', - cmd->lun, pending_scb->hscb->tag, - /*stop_on_first*/TRUE, - /*remove*/TRUE, - /*save_state*/FALSE); - - /* - * In the non-paging case, the sequencer will - * never re-reference the in-core SCB. - * To make sure we are notified during - * reslection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - if ((ahc->flags & AHC_PAGESCBS) == 0) { - ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag); - ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE); - } - - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', - cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - ahc_print_path(ahc, pending_scb); - printf("Queuing a recovery SCB\n"); - ahc_qinfifo_requeue_tail(ahc, pending_scb); - ahc_outb(ahc, SCBPTR, saved_scbptr); - printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - wait = TRUE; - } else { - printf("%s:%d:%d:%d: Unable to deliver message\n", - ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); - retval = FAILED; - goto done; - } - -no_cmd: - /* - * Our assumption is that if we don't have the command, no - * recovery action was required, so we return success. Again, - * the semantics of the mid-layer recovery engine are not - * well defined, so this may change in time. - */ - retval = SUCCESS; -done: - if (paused) - ahc_unpause(ahc); - if (wait) { - struct timer_list timer; - int ret; - - ahc_unlock(ahc, &s); - init_timer(&timer); - timer.data = (u_long)&ahc->platform_data->eh_sem; - timer.expires = jiffies + (5 * HZ); - timer.function = ahc_linux_sem_timeout; - add_timer(&timer); - printf("Recovery code sleeping\n"); - down(&ahc->platform_data->eh_sem); - printf("Recovery code awake\n"); - ret = del_timer(&timer); - if (ret == 0) { - printf("Timer Expired\n"); - retval = FAILED; - } - ahc_lock(ahc, &s); - } - ahc_linux_run_device_queues(ahc); - acmd = TAILQ_FIRST(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->completeq); - ahc_unlock(ahc, &s); - if (acmd != NULL) - ahc_linux_run_complete_queue(ahc, acmd); - spin_lock_irq(&io_request_lock); - return (retval); -} - -/* - * Abort the current SCSI command(s). - */ -int -ahc_linux_abort(Scsi_Cmnd *cmd) -{ - int error; - - error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); - if (error != 0) - printf("aic7xxx_abort returns 0x%x\n", error); - return (error); -} - -/* - * Attempt to send a target reset message to the device that timed out. - */ -int -ahc_linux_dev_reset(Scsi_Cmnd *cmd) -{ - int error; - - error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); - if (error != 0) - printf("aic7xxx_dev_reset returns 0x%x\n", error); - return (error); -} - -/* - * Reset the SCSI bus. - */ -int -ahc_linux_bus_reset(Scsi_Cmnd *cmd) -{ - struct ahc_softc *ahc; - struct ahc_cmd *acmd; - u_long s; - int found; - - /* - * It is a bug that the upper layer takes - * this lock just prior to calling us. - */ - spin_unlock_irq(&io_request_lock); - - ahc = *(struct ahc_softc **)cmd->host->hostdata; - ahc_lock(ahc, &s); - found = ahc_reset_channel(ahc, cmd->channel + 'A', - /*initiate reset*/TRUE); - acmd = TAILQ_FIRST(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->completeq); - ahc_unlock(ahc, &s); - if (bootverbose) - printf("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahc_name(ahc), found); - - if (acmd != NULL) - ahc_linux_run_complete_queue(ahc, acmd); - - spin_lock_irq(&io_request_lock); - return SUCCESS; -} - -/* - * Return the disk geometry for the given SCSI device. - */ -int -ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) -{ - int heads; - int sectors; - int cylinders; - int ret; - int extended; - struct ahc_softc *ahc; - struct buffer_head *bh; - - ahc = *((struct ahc_softc **)disk->device->host->hostdata); - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); - - if (bh) { - ret = scsi_partsize(bh, disk->capacity, - &geom[2], &geom[0], &geom[1]); - brelse(bh); - if (ret != -1) - return (ret); - } - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - if (aic7xxx_extended != 0) - extended = 1; - else if (disk->device->channel == 0) - extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; - else - extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; - if (extended && cylinders >= 1024) { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return (0); -} - -/* - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - */ -int -ahc_linux_release(struct Scsi_Host * host) -{ - struct ahc_softc *ahc; - - if (host != NULL) { - - ahc = *(struct ahc_softc **)host->hostdata; - ahc_free(ahc); - } - if (TAILQ_EMPTY(&ahc_tailq)) { - unregister_reboot_notifier(&ahc_linux_notifier); -#ifdef CONFIG_PCI -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pci_unregister_driver(&aic7xxx_pci_driver); -#endif -#endif - } - return (0); -} - -void -ahc_platform_dump_card_state(struct ahc_softc *ahc) -{ - struct ahc_linux_device *dev; - int channel; - int maxchannel; - int target; - int maxtarget; - int lun; - int i; - - maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0; - maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7; - for (channel = 0; channel <= maxchannel; channel++) { - for (target = 0; target <=maxtarget; target++) { - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_cmd *acmd; - - dev = ahc_linux_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - printf("DevQ(%d:%d:%d): ", - channel, target, lun); - i = 0; - TAILQ_FOREACH(acmd, &dev->busyq, - acmd_links.tqe) { - if (i++ > 256) - break; - } - printf("%d waiting\n", i); - } - } - } -} - -#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static Scsi_Host_Template driver_template = AIC7XXX; -Scsi_Host_Template *aic7xxx_driver_template = &driver_template; -#include "../scsi_module.c" -#endif diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Thu Jan 1 01:00:00 1970 @@ -1,95 +0,0 @@ -/* - * Adaptec AIC7xxx device driver host template for Linux. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#5 $ - */ - -#ifndef _AIC7XXX_LINUX_HOST_H_ -#define _AIC7XXX_LINUX_HOST_H_ - -int ahc_linux_proc_info(char *, char **, off_t, int, int, int); -int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -int ahc_linux_detect(Scsi_Host_Template *); -int ahc_linux_release(struct Scsi_Host *); -const char *ahc_linux_info(struct Scsi_Host *); -int ahc_linux_biosparam(Disk *, kdev_t, int[]); -int ahc_linux_bus_reset(Scsi_Cmnd *); -int ahc_linux_dev_reset(Scsi_Cmnd *); -int ahc_linux_abort(Scsi_Cmnd *); - -#if defined(__i386__) -# define AIC7XXX_BIOSPARAM ahc_linux_biosparam -#else -# define AIC7XXX_BIOSPARAM NULL -#endif - -/* - * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields - * to do with card config are filled in after the card is detected. - */ -#define AIC7XXX { \ - next: NULL, \ - module: NULL, \ - proc_dir: NULL, \ - proc_info: ahc_linux_proc_info, \ - name: NULL, \ - detect: ahc_linux_detect, \ - release: ahc_linux_release, \ - info: ahc_linux_info, \ - command: NULL, \ - queuecommand: ahc_linux_queue, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: ahc_linux_abort, \ - eh_device_reset_handler: ahc_linux_dev_reset, \ - eh_bus_reset_handler: ahc_linux_bus_reset, \ - eh_host_reset_handler: NULL, \ - abort: NULL, \ - reset: NULL, \ - slave_attach: NULL, \ - bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 253, /* max simultaneous cmds */\ - this_id: -1, /* scsi id of host adapter */\ - sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 2, /* cmds per lun */\ - present: 0, /* number of 7xxx's present */\ - unchecked_isa_dma: 0, /* no memory DMA restrictions */\ - use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 1 \ -} - -#endif /* _AIC7XXX_LINUX_HOST_H_ */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,2931 @@ +/* + * Adaptec AIC7xxx device driver for Linux. + * + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#1 $ + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * 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) + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F + * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA + * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, + * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, + * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file + * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, + * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the + * ANSI SCSI-2 specification (draft 10c), ... + * + * -------------------------------------------------------------------------- + * + * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): + * + * Substantially modified to include support for wide and twin bus + * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, + * SCB paging, and other rework of the code. + * + * -------------------------------------------------------------------------- + * Copyright (c) 1994-2000 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + *--------------------------------------------------------------------------- + * + * Thanks also go to (in alphabetical order) the following: + * + * Rory Bolt - Sequencer bug fixes + * Jay Estabrook - Initial DEC Alpha support + * Doug Ledford - Much needed abort/reset bug fixes + * Kai Makisara - DMAing of SCBs + * + * A Boot time option was also added for not resetting the scsi bus. + * + * Form: aic7xxx=extended + * aic7xxx=no_reset + * aic7xxx=verbose + * + * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 + * + * Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp + */ + +/* + * Further driver modifications made by Doug Ledford + * + * Copyright (c) 1997-1999 Doug Ledford + * + * These changes are released under the same licensing terms as the FreeBSD + * driver written by Justin Gibbs. Please see his Copyright notice above + * for the exact terms and conditions covering my changes as well as the + * warranty statement. + * + * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include + * but are not limited to: + * + * 1: Import of the latest FreeBSD sequencer code for this driver + * 2: Modification of kernel code to accomodate different sequencer semantics + * 3: Extensive changes throughout kernel portion of driver to improve + * abort/reset processing and error hanndling + * 4: Other work contributed by various people on the Internet + * 5: Changes to printk information and verbosity selection code + * 6: General reliability related changes, especially in IRQ management + * 7: Modifications to the default probe/attach order for supported cards + * 8: SMP friendliness has been improved + * + */ + +/* + * This is the only file where module.h should + * embed module global version info. + */ +#define AHC_MODVERSION_FILE + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#include /* __setup */ +#endif + +#include "../sd.h" /* For geometry detection */ + +#include /* For fetching system memory size */ +#include /* For block_size() */ + +/* + * To generate the correct addresses for the controller to issue + * on the bus. Originally added for DEC Alpha support. + */ +#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a)) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +struct proc_dir_entry proc_scsi_aic7xxx = { + PROC_SCSI_AIC7XXX, 7, "aic7xxx", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif + +/* + * Set this to the delay in seconds after SCSI bus reset. + * Note, we honor this only for the initial bus reset. + * The scsi error recovery code performs its own bus settle + * delay handling for error recovery actions. + */ +#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS +#else +#define AIC7XXX_RESET_DELAY 5000 +#endif + +/* + * Control collection of SCSI transfer statistics for the /proc filesystem. + * + * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. + * NOTE: This does affect performance since it has to maintain statistics. + */ +#ifdef CONFIG_AIC7XXX_PROC_STATS +#define AIC7XXX_PROC_STATS +#endif + +/* + * To change the default number of tagged transactions allowed per-device, + * add a line to the lilo.conf file like: + * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + * + * The tag_commands is an array of 16 to allow for wide and twin adapters. + * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15 + * for channel 1. + */ +typedef struct { + uint8_t tag_commands[16]; /* Allow for wide/twin adapters. */ +} adapter_tag_info_t; + +/* + * Modify this as you see fit for your system. + * + * 0 tagged queuing disabled + * 1 <= n <= 253 n == max tags ever dispatched. + * + * The driver will throttle the number of commands dispatched to a + * device if it returns queue full. For devices with a fixed maximum + * queue depth, the driver will eventually determine this depth and + * lock it in (a console message is printed to indicate that a lock + * has occurred). On some devices, queue full is returned for a temporary + * resource shortage. These devices will return queue full at varying + * depths. The driver will throttle back when the queue fulls occur and + * attempt to slowly increase the depth over time as the device recovers + * from the resource shortage. + * + * In this example, the first line will disable tagged queueing for all + * the devices on the first probed aic7xxx adapter. + * + * The second line enables tagged queueing with 4 commands/LUN for IDs + * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the + * driver to attempt to use up to 64 tags for ID 1. + * + * The third line is the same as the first line. + * + * The fourth line disables tagged queueing for devices 0 and 3. It + * enables tagged queueing for the other IDs, with 16 commands/LUN + * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for + * IDs 2, 5-7, and 9-15. + */ + +/* + * NOTE: The below structure is for reference only, the actual structure + * to modify in order to change things is just below this comment block. +adapter_tag_info_t aic7xxx_tag_info[] = +{ + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} +}; +*/ + +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE +#else +#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE +#endif + +#define AIC7XXX_CONFIGED_TAG_COMMANDS { \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE \ +} + +/* + * By default, use the number of commands specified by + * the users kernel configuration. + */ +static adapter_tag_info_t aic7xxx_tag_info[] = +{ + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS} +}; + +/* + * There should be a specific return value for this in scsi.h, but + * it seems that most drivers ignore it. + */ +#define DID_UNDERFLOW DID_ERROR + +void +ahc_print_path(struct ahc_softc *ahc, struct scb *scb) +{ + printk("(scsi%d:%c:%d:%d): ", + ahc->platform_data->host->host_no, + scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X', + scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1, + scb != NULL ? SCB_GET_LUN(scb) : -1); +} + +/* + * XXX - these options apply unilaterally to _all_ 274x/284x/294x + * cards in the system. This should be fixed. Exceptions to this + * rule are noted in the comments. + */ + +/* + * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This + * has no effect on any later resets that might occur due to things like + * SCSI bus timeouts. + */ +static uint32_t aic7xxx_no_reset; + +/* + * Certain PCI motherboards will scan PCI devices from highest to lowest, + * others scan from lowest to highest, and they tend to do all kinds of + * strange things when they come into contact with PCI bridge chips. The + * net result of all this is that the PCI card that is actually used to boot + * the machine is very hard to detect. Most motherboards go from lowest + * PCI slot number to highest, and the first SCSI controller found is the + * one you boot from. The only exceptions to this are when a controller + * has its BIOS disabled. So, we by default sort all of our SCSI controllers + * from lowest PCI slot number to highest PCI slot number. We also force + * all controllers with their BIOS disabled to the end of the list. This + * works on *almost* all computers. Where it doesn't work, we have this + * option. Setting this option to non-0 will reverse the order of the sort + * to highest first, then lowest, but will still leave cards with their BIOS + * disabled at the very end. That should fix everyone up unless there are + * really strange cirumstances. + */ +static int aic7xxx_reverse_scan = 0; + +/* + * Should we force EXTENDED translation on a controller. + * 0 == Use whatever is in the SEEPROM or default to off + * 1 == Use whatever is in the SEEPROM or default to on + */ +static uint32_t aic7xxx_extended = 0; + +/* + * PCI bus parity checking of the Adaptec controllers. This is somewhat + * dubious at best. To my knowledge, this option has never actually + * solved a PCI parity problem, but on certain machines with broken PCI + * chipset configurations, it can generate tons of false error messages. + * It's included in the driver for completeness. + * 0 = Shut off PCI parity check + * -1 = Normal polarity pci parity checking + * 1 = reverse polarity pci parity checking + * + * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this + * variable to -1 you would actually want to simply pass the variable + * name without a number. That will invert the 0 which will result in + * -1. + */ +static int aic7xxx_pci_parity = 0; + +/* + * Certain newer motherboards have put new PCI based devices into the + * IO spaces that used to typically be occupied by VLB or EISA cards. + * This overlap can cause these newer motherboards to lock up when scanned + * for older EISA and VLB devices. Setting this option to non-0 will + * cause the driver to skip scanning for any VLB or EISA controllers and + * only support the PCI controllers. NOTE: this means that if the kernel + * os compiled with PCI support disabled, then setting this to non-0 + * would result in never finding any devices :) + */ +#ifndef CONFIG_AIC7XXX_PROBE_EISA_VL +#define CONFIG_AIC7XXX_PROBE_EISA_VL n +#endif +#if CONFIG_AIC7XXX_PROBE_EISA_VL == n +static int aic7xxx_no_probe = 1; +#else +static int aic7xxx_no_probe; +#endif + +/* + * aic7xxx_detect() has been run, so register all device arrivals + * immediately with the system rather than deferring to the sorted + * attachment performed by aic7xxx_detect(). + */ +int aic7xxx_detect_complete; + +/* + * So that we can set how long each device is given as a selection timeout. + * The table of values goes like this: + * 0 - 256ms + * 1 - 128ms + * 2 - 64ms + * 3 - 32ms + * We default to 256ms because some older devices need a longer time + * to respond to initial selection. + */ +static int aic7xxx_seltime = 0x00; + +/* + * Certain devices do not perform any aging on commands. Should the + * device be saturated by commands in one portion of the disk, it is + * possible for transactions on far away sectors to never be serviced. + * To handle these devices, we can periodically send an ordered tag to + * force all outstanding transactions to be serviced prior to a new + * transaction. + */ +int aic7xxx_periodic_otag; + +/* + * Module information and settable options. + */ +#ifdef MODULE +static char *aic7xxx = NULL; +/* + * 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 trounce on me insmod!!\n"; + +MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); +MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE("Dual BSD/GPL"); +#endif +MODULE_PARM(aic7xxx, "s"); +MODULE_PARM_DESC(aic7xxx, "period delimited, options string. + verbose Enable verbose/diagnostic logging + no_probe Disable EISA/VLB controller probing + no_reset Supress initial bus resets + extended Enable extended geometry on all controllers + periodic_otag Send an ordered tagged transaction periodically + to prevent tag starvation. This may be + required by some older disk drives/RAID arrays. + reverse_scan Sort PCI devices highest Bus/Slot to lowest + tag_info: Set per-target tag depth + seltime: Selection Timeout(0/256ms,1/128ms,2/64ms,3/32ms) + + Sample /etc/modules.conf line: + Enable verbose logging + Disable EISA/VLB probing + Set tag depth on Controller 2/Target 2 to 10 tags + Shorten the selection timeout to 128ms from its default of 256 + + options aic7xxx='\"verbose.no_probe.tag_info:{{}.{}.{..10}}.seltime:1\"' +"); +#endif + +static void ahc_linux_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, + struct scb *); +static void ahc_linux_filter_command(struct ahc_softc*, Scsi_Cmnd*, + struct scb*); +static void ahc_linux_sem_timeout(u_long arg); +static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc); +static void ahc_linux_release_sim_queue(u_long arg); +static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); +static void ahc_linux_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, + u_int, u_int); +static void ahc_linux_free_target(struct ahc_softc*, + struct ahc_linux_target*); +static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct ahc_linux_target*, + u_int); +static void ahc_linux_free_device(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_run_device_queue(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_setup_tag_info(char *p, char *end); +static int ahc_linux_next_unit(void); +static void ahc_runq_tasklet(unsigned long data); +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); + +static __inline struct ahc_linux_device* + ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int alloc); +static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline struct ahc_linux_device * + ahc_linux_next_device_to_run(struct ahc_softc *ahc); +static __inline void ahc_linux_run_device_queues(struct ahc_softc *ahc); +static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*, + struct scb*); +static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); + +static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, + struct ahc_dma_seg *sg, + bus_addr_t addr, bus_size_t len); + +static __inline struct ahc_linux_device* +ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, + u_int lun, int alloc) +{ + struct ahc_linux_target *targ; + struct ahc_linux_device *dev; + u_int target_offset; + + target_offset = target; + if (channel != 0) + target_offset += 8; + targ = ahc->platform_data->targets[target_offset]; + if (targ == NULL) { + if (alloc != 0) { + targ = ahc_linux_alloc_target(ahc, channel, target); + if (targ == NULL) + return (NULL); + } else + return (NULL); + } + dev = targ->devices[lun]; + if (dev == NULL && alloc != 0) + dev = ahc_linux_alloc_device(ahc, targ, lun); + return (dev); +} + +static __inline void +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +{ + /* + * Typically, the complete queue has very few entries + * queued to it before the queue is emptied by + * ahc_linux_run_complete_queue, so sorting the entries + * by generation number should be inexpensive. + * We perform the sort so that commands that complete + * with an error are retuned in the order origionally + * queued to the controller so that any subsequent retries + * are performed in order. The underlying ahc routines do + * not guarantee the order that aborted commands will be + * returned to us. + */ + struct ahc_completeq *completeq; + struct ahc_cmd *list_cmd; + struct ahc_cmd *acmd; + + /* + * If we want the request requeued, make sure there + * are sufficent retries. In the old scsi error code, + * we used to be able to specify a result code that + * bypassed the retry count. Now we must use this + * hack. + */ + if (cmd->result == (CAM_REQUEUE_REQ << 16)) + cmd->retries--; + completeq = &ahc->platform_data->completeq; + list_cmd = TAILQ_FIRST(completeq); + acmd = (struct ahc_cmd *)cmd; + while (list_cmd != NULL + && acmd_scsi_cmd(list_cmd).serial_number + < acmd_scsi_cmd(acmd).serial_number) + list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); + if (list_cmd != NULL) + TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); + else + TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); +} + +static __inline void +ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +{ + u_long done_flags; + + ahc_done_lock(ahc, &done_flags); + while (acmd != NULL) { + Scsi_Cmnd *cmd; + + cmd = &acmd_scsi_cmd(acmd); + acmd = TAILQ_NEXT(acmd, acmd_links.tqe); + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } + ahc_done_unlock(ahc, &done_flags); +} + +static __inline void +ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev) +{ + if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 + && dev->active == 0) { + dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen--; + } + + if (TAILQ_FIRST(&dev->busyq) == NULL + || dev->openings == 0 || dev->qfrozen != 0) + return; + + ahc_linux_run_device_queue(ahc, dev); +} + +static __inline struct ahc_linux_device * +ahc_linux_next_device_to_run(struct ahc_softc *ahc) +{ + + if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 + || ahc->platform_data->qfrozen != 0) + return (NULL); + return (TAILQ_FIRST(&ahc->platform_data->device_runq)); +} + +static __inline void +ahc_linux_run_device_queues(struct ahc_softc *ahc) +{ + struct ahc_linux_device *dev; + + while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { + TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); + dev->flags &= ~AHC_DEV_ON_RUN_LIST; + ahc_linux_check_device_queue(ahc, dev); + } +} + +static __inline void +ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd, struct scb *scb) +{ + /* + * Determine whether we care to filter + * information out of this command. If so, + * pass it on to ahc_linux_filter_command() for more + * heavy weight processing. + */ + if (cmd->cmnd[0] == INQUIRY) + ahc_linux_filter_command(ahc, cmd, scb); +} + +static __inline void +ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +{ + Scsi_Cmnd *cmd; + + cmd = scb->io_ctx; + ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE); + if (cmd->use_sg != 0) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } else if (cmd->request_bufflen != 0) { + pci_unmap_single(ahc->dev_softc, + scb->platform_data->buf_busaddr, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } +} + +static __inline int +ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, + struct ahc_dma_seg *sg, bus_addr_t addr, bus_size_t len) +{ + int consumed; + + if ((scb->sg_count + 1) > AHC_NSEG) + panic("Too few segs for dma mapping. " + "Increase AHC_NSEG\n"); + + consumed = 1; + sg->addr = ahc_htole32(addr & 0xFFFFFFFF); + scb->platform_data->xfer_len += len; + if (sizeof(bus_addr_t) > 4 + && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + /* + * Due to DAC restrictions, we can't + * cross a 4GB boundary. + */ + if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) { + struct ahc_dma_seg *next_sg; + uint32_t next_len; + + printf("Crossed Seg\n"); + if ((scb->sg_count + 2) > AHC_NSEG) + panic("Too few segs for dma mapping. " + "Increase AHC_NSEG\n"); + + consumed++; + next_sg = sg + 1; + next_sg->addr = 0; + next_len = 0x100000000 - (addr & 0xFFFFFFFF); + len -= next_len; + next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000; + next_sg->len = ahc_htole32(next_len); + } + len |= (addr >> 8) & 0x7F000000; + } + sg->len = ahc_htole32(len); + return (consumed); +} + +/**************************** Tasklet Handler *********************************/ + +static void +ahc_runq_tasklet(unsigned long data) +{ + struct ahc_softc* ahc; + struct ahc_linux_device *dev; + u_long flags; + + ahc = (struct ahc_softc *)data; + ahc_lock(ahc, &flags); + while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { + + TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); + dev->flags &= ~AHC_DEV_ON_RUN_LIST; + ahc_linux_check_device_queue(ahc, dev); + /* Yeild to our interrupt handler */ + ahc_unlock(ahc, &flags); + ahc_lock(ahc, &flags); + } + ahc_unlock(ahc, &flags); +} + +/************************ Shutdown/halt/reboot hook ***************************/ +#include +#include + +static struct notifier_block ahc_linux_notifier = { + ahc_linux_halt, NULL, 0 +}; + +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) +{ + struct ahc_softc *ahc; + + if (event == SYS_DOWN || event == SYS_HALT) { + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + ahc_shutdown(ahc); + } + } + return (NOTIFY_OK); +} + +/******************************** Macros **************************************/ +#define BUILD_SCSIID(ahc, cmd) \ + ((((cmd)->target << TID_SHIFT) & TID) \ + | (((cmd)->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ + | (((cmd)->channel == 0) ? 0 : TWIN_CHNLB)) + +/******************************** Bus DMA *************************************/ +int +ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, + bus_size_t alignment, bus_size_t boundary, + bus_addr_t lowaddr, bus_addr_t highaddr, + bus_dma_filter_t *filter, void *filterarg, + bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) +{ + bus_dma_tag_t dmat; + + dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + if (dmat == NULL) + return (ENOMEM); + + /* + * Linux is very simplistic about DMA memory. For now don't + * maintain all specification information. Once Linux supplies + * better facilities for doing these operations, or the + * needs of this particular driver change, we might need to do + * more here. + */ + dmat->alignment = alignment; + dmat->boundary = boundary; + dmat->maxsize = maxsize; + *ret_tag = dmat; + return (0); +} + +void +ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) +{ + free(dmat, M_DEVBUF); +} + +int +ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, + int flags, bus_dmamap_t *mapp) +{ + bus_dmamap_t map; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); + if (map == NULL) + return (ENOMEM); + /* + * Although we can dma data above 4GB, our + * "consistent" memory is below 4GB for + * space efficiency reasons (only need a 4byte + * address). For this reason, we have to reset + * our dma mask when doing allocations. + */ + if (ahc->dev_softc != NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF); +#else + ahc->dev_softc->dma_mask = 0xFFFFFFFF; +#endif + } + *vaddr = pci_alloc_consistent(ahc->dev_softc, + dmat->maxsize, &map->bus_addr); + if (ahc->dev_softc != NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + pci_set_dma_mask(ahc->dev_softc, + ahc->platform_data->hw_dma_mask); +#else + ahc->dev_softc->dma_mask = ahc->platform_data->hw_dma_mask; +#endif + } +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ + /* + * At least in 2.2.14, malloc is a slab allocator so all + * allocations are aligned. We assume for these kernel versions + * that all allocations will be bellow 4Gig, physically contiguous, + * and accessable via DMA by the controller. + */ + map = NULL; /* No additional information to store */ + *vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT); +#endif + if (*vaddr == NULL) + return (ENOMEM); + *mapp = map; + return(0); +} + +void +ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, + void* vaddr, bus_dmamap_t map) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + pci_free_consistent(ahc->dev_softc, dmat->maxsize, + vaddr, map->bus_addr); +#else + free(vaddr, M_DEVBUF); +#endif +} + +int +ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, + void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, + void *cb_arg, int flags) +{ + /* + * Assume for now that this will only be used during + * initialization and not for per-transaction buffer mapping. + */ + bus_dma_segment_t stack_sg; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + stack_sg.ds_addr = map->bus_addr; +#else + stack_sg.ds_addr = VIRT_TO_BUS(buf); +#endif + stack_sg.ds_len = dmat->maxsize; + cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); + return (0); +} + +void +ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* + * The map may is NULL in our < 2.3.X implementation. + */ + if (map != NULL) + free(map, M_DEVBUF); +} + +int +ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* Nothing to do */ + return (0); +} + +/********************* Platform Dependent Functions ***************************/ +int +ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) +{ + int value; + int rvalue; + int lvalue; + + /* + * Under Linux, cards are ordered as follows: + * 1) VLB/EISA BIOS enabled devices sorted by BIOS address. + * 2) PCI devices with BIOS enabled sorted by bus/slot/func. + * 3) All remaining VLB/EISA devices sorted by ioport. + * 4) All remaining PCI devices sorted by bus/slot/func. + */ + value = (lahc->flags & AHC_BIOS_ENABLED) + - (rahc->flags & AHC_BIOS_ENABLED); + if (value != 0) + /* Controllers with BIOS enabled have a *higher* priority */ + return (-value); + + /* + * Same BIOS setting, now sort based on bus type. + * EISA and VL controllers sort together. EISA/VL + * have higher priority than PCI. + */ + rvalue = (rahc->chip & AHC_BUS_MASK); + if (rvalue == AHC_VL) + rvalue = AHC_EISA; + lvalue = (lahc->chip & AHC_BUS_MASK); + if (lvalue == AHC_VL) + lvalue = AHC_EISA; + value = lvalue - rvalue; + if (value != 0) + return (value); + + /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ + switch (rvalue) { + case AHC_PCI: + { + char primary_channel; + + if (aic7xxx_reverse_scan != 0) + value = ahc_get_pci_bus(rahc->dev_softc) + - ahc_get_pci_bus(lahc->dev_softc); + else + value = ahc_get_pci_bus(lahc->dev_softc) + - ahc_get_pci_bus(rahc->dev_softc); + if (value != 0) + break; + if (aic7xxx_reverse_scan != 0) + value = ahc_get_pci_slot(rahc->dev_softc) + - ahc_get_pci_slot(lahc->dev_softc); + else + value = ahc_get_pci_slot(lahc->dev_softc) + - ahc_get_pci_slot(rahc->dev_softc); + if (value != 0) + break; + /* + * On multi-function devices, the user can choose + * to have function 1 probed before function 0. + * Give whichever channel is the primary channel + * the lowest priority. + */ + primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; + value = 1; + if (lahc->channel == primary_channel) + value = -1; + break; + } + case AHC_EISA: + if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { + value = lahc->platform_data->bios_address + - rahc->platform_data->bios_address; + } else { + value = lahc->bsh.ioport + - rahc->bsh.ioport; + } + break; + default: + panic("ahc_softc_sort: invalid bus type"); + } + return (value); +} + +static void +ahc_linux_setup_tag_info(char *p, char *end) +{ + char *base; + char *tok; + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + if (*p != ':') + return; + + instance = -1; + targ = -1; + done = FALSE; + base = p; + /* Forward us just past the ':' */ + tok = base + 1; + tok_end = strchr(tok, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*tok) { + case '{': + if (instance == -1) + instance = 0; + else if (targ == -1) + targ = 0; + tok++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + tok++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + if ((targ >= AHC_NUM_TARGETS) || + (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) + done = TRUE; + tok++; + if (!done) { + base = tok; + } + break; + case '\0': + done = TRUE; + break; + default: + done = TRUE; + tok_end = strchr(tok, '\0'); + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(tok, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) { + tok_end = tok_end2; + done = FALSE; + } + } + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = + simple_strtoul(tok, NULL, 0) & 0xff; + } + tok = tok_end; + break; + } + } + while ((p != base) && (p != NULL)) + p = strtok(NULL, ",."); +} + +/* + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. aic7xxx=stpwlev:1,extended + */ +int +aic7xxx_setup(char *s) +{ + int i, n; + char *p; + char *end; + + static struct { + const char *name; + uint32_t *flag; + } options[] = { + { "extended", &aic7xxx_extended }, + { "no_reset", &aic7xxx_no_reset }, + { "verbose", &aic7xxx_verbose }, + { "reverse_scan", &aic7xxx_reverse_scan }, + { "no_probe", &aic7xxx_no_probe }, + { "periodic_otag", &aic7xxx_periodic_otag }, + { "pci_parity", &aic7xxx_pci_parity }, + { "seltime", &aic7xxx_seltime }, + { "tag_info", NULL } + }; + + end = strchr(s, '\0'); + + for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) { + for (i = 0; i < NUM_ELEMENTS(options); i++) { + n = strlen(options[i].name); + + if (strncmp(options[i].name, p, n) != 0) + continue; + + if (strncmp(p, "tag_info", n) == 0) { + ahc_linux_setup_tag_info(p + n, end); + } else if (p[n] == ':') { + *(options[i].flag) = + simple_strtoul(p + n + 1, NULL, 0); + } else if (!strncmp(p, "verbose", n)) { + *(options[i].flag) = 1; + } else { + *(options[i].flag) = ~(*(options[i].flag)); + } + break; + } + } + register_reboot_notifier(&ahc_linux_notifier); + return 1; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) +__setup("aic7xxx=", aic7xxx_setup); +#endif + +int aic7xxx_verbose; + +/* + * Try to detect an Adaptec 7XXX controller. + */ +int +ahc_linux_detect(Scsi_Host_Template *template) +{ + struct ahc_softc *ahc; + int found; + + /* + * Sanity checking of Linux SCSI data structures so + * that some of our hacks^H^H^H^H^Hassumptions aren't + * violated. + */ + if (offsetof(struct ahc_cmd_internal, end) + > offsetof(struct scsi_cmnd, host_scribble)) { + printf("ahc_linux_detect: SCSI data structures changed.\n"); + printf("ahc_linux_detect: Unable to attach\n"); + return (0); + } +#ifdef MODULE + /* + * If we've been passed any parameters, process them now. + */ + if (aic7xxx) + aic7xxx_setup(aic7xxx); + if (dummy_buffer[0] != 'P') + printk(KERN_WARNING +"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n" +"aic7xxx: to see the proper way to specify options to the aic7xxx module\n" +"aic7xxx: Specifically, don't use any commas when passing arguments to\n" +"aic7xxx: insmod or else it might trash certain memory areas.\n"); +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) + template->proc_name = "aic7xxx"; +#else + template->proc_dir = &proc_scsi_aic7xxx; +#endif + template->sg_tablesize = AHC_NSEG; + +#ifdef CONFIG_PCI + ahc_linux_pci_probe(template); +#endif + + if (aic7xxx_no_probe == 0) + aic7770_linux_probe(template); + + /* + * Register with the SCSI layer all + * controllers we've found. + */ + found = 0; + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + + if (ahc_linux_register_host(ahc, template) == 0) + found++; + } + aic7xxx_detect_complete++; + return (found); +} + +int +ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +{ + char buf[80]; + struct Scsi_Host *host; + char *new_name; + u_long s; + + + template->name = ahc->description; + host = scsi_register(template, sizeof(struct ahc_softc *)); + if (host == NULL) + return (ENOMEM); + + ahc_lock(ahc, &s); + *((struct ahc_softc **)host->hostdata) = ahc; + ahc->platform_data->host = host; + host->can_queue = AHC_MAX_QUEUE; + host->cmd_per_lun = 2; + host->sg_tablesize = AHC_NSEG; + host->select_queue_depths = ahc_linux_select_queue_depth; + /* XXX No way to communicate the ID for multiple channels */ + host->this_id = ahc->our_id; + host->irq = ahc->platform_data->irq; + host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; + host->max_lun = AHC_NUM_LUNS; + host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; + ahc_set_unit(ahc, ahc_linux_next_unit()); + sprintf(buf, "scsi%d", host->host_no); + new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (new_name != NULL) { + strcpy(new_name, buf); + ahc_set_name(ahc, new_name); + } + host->unique_id = ahc->unit; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) + scsi_set_pci_device(host, ahc->dev_softc); +#endif + ahc_linux_initialize_scsi_bus(ahc); + ahc_unlock(ahc, &s); + return (0); +} + +uint64_t +ahc_linux_get_memsize() +{ + struct sysinfo si; + + si_meminfo(&si); + return (si.totalram << PAGE_SHIFT); +} + +/* + * Find the smallest available unit number to use + * for a new device. We don't just use a static + * count to handle the "repeated hot-(un)plug" + * scenario. + */ +static int +ahc_linux_next_unit() +{ + struct ahc_softc *ahc; + int unit; + + unit = 0; +retry: + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + if (ahc->unit == unit) { + unit++; + goto retry; + } + } + return (unit); +} + +/* + * Place the SCSI bus into a known state by either resetting it, + * or forcing transfer negotiations on the next command to any + * target. + */ +void +ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) +{ + int i; + int numtarg; + + i = 0; + numtarg = 0; + + if (aic7xxx_no_reset != 0) + ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B); + + if ((ahc->flags & AHC_RESET_BUS_A) != 0) + ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE); + else + numtarg = (ahc->features & AHC_WIDE) ? 16 : 8; + + if ((ahc->features & AHC_TWIN) != 0) { + + if ((ahc->flags & AHC_RESET_BUS_B) != 0) { + ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE); + } else { + if (numtarg == 0) + i = 8; + numtarg += 8; + } + } + + for (; i < numtarg; i++) { + struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int our_id; + u_int target_id; + char channel; + + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); + tinfo->goal = tinfo->user; + /* + * Don't try negotiations that require PPR messages + * until we successfully retrieve Inquiry data. + */ + tinfo->goal.ppr_options = 0; + if (tinfo->goal.transport_version > SCSI_REV_2) + tinfo->goal.transport_version = SCSI_REV_2; + ahc_compile_devinfo(&devinfo, our_id, target_id, + CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); + ahc_update_neg_request(ahc, &devinfo, tstate, + tinfo, /*force*/FALSE); + } + /* Give the bus some time to recover */ + if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { + ahc_linux_freeze_sim_queue(ahc); + init_timer(&ahc->platform_data->reset_timer); + ahc->platform_data->reset_timer.data = (u_long)ahc; + ahc->platform_data->reset_timer.expires = + jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; + ahc->platform_data->reset_timer.function = + ahc_linux_release_sim_queue; + add_timer(&ahc->platform_data->reset_timer); + } +} + +int +ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) +{ + ahc->platform_data = + malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT); + if (ahc->platform_data == NULL) + return (ENOMEM); + memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); + TAILQ_INIT(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->device_runq); + ahc->platform_data->irq = AHC_LINUX_NOIRQ; + ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; + ahc_lockinit(ahc); + ahc_done_lockinit(ahc); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); +#else + ahc->platform_data->eh_sem = MUTEX_LOCKED; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet, + (unsigned long)ahc); +#endif + ahc->seltime = (aic7xxx_seltime & 0x3) << 4; + ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; + return (0); +} + +void +ahc_platform_free(struct ahc_softc *ahc) +{ + if (ahc->platform_data != NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_kill(&ahc->platform_data->runq_tasklet); +#endif + if (ahc->platform_data->host != NULL) + scsi_unregister(ahc->platform_data->host); + if (ahc->platform_data->irq != AHC_LINUX_NOIRQ) + free_irq(ahc->platform_data->irq, ahc); + if (ahc->tag == BUS_SPACE_PIO + && ahc->bsh.ioport != 0) + release_region(ahc->bsh.ioport, 256); + if (ahc->tag == BUS_SPACE_MEMIO + && ahc->bsh.maddr != NULL) { + u_long base_addr; + + base_addr = (u_long)ahc->bsh.maddr; + base_addr &= PAGE_MASK; + iounmap((void *)base_addr); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + release_mem_region(ahc->platform_data->mem_busaddr, + 0x1000); +#endif + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* XXX Need an instance detach in the PCI code */ + if (ahc->dev_softc != NULL) + ahc->dev_softc->driver = NULL; +#endif + free(ahc->platform_data, M_DEVBUF); + } +} + +void +ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb) +{ + ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), SCB_LIST_NULL, + ROLE_UNKNOWN, CAM_REQUEUE_REQ); +} + +void +ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) +{ + struct ahc_linux_device *dev; + int was_queuing; + int now_queuing; + + dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + if (dev == NULL) + return; + was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + now_queuing = alg != AHC_QUEUE_NONE; + if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) + && (dev->active != 0)) { + dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen++; + } + + dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG); + if (now_queuing) { + u_int usertags; + + usertags = ahc_linux_user_tagdepth(ahc, devinfo); + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = usertags; + dev->openings = dev->maxtags - dev->active; + } + if (alg == AHC_QUEUE_TAGGED) { + dev->flags |= AHC_DEV_Q_TAGGED; + if (aic7xxx_periodic_otag != 0) + dev->flags |= AHC_DEV_PERIODIC_OTAG; + } else + dev->flags |= AHC_DEV_Q_BASIC; + } else { + /* We can only have one opening. */ + dev->maxtags = 0; + dev->openings = 1 - dev->active; + } +} + +int +ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status) +{ + int chan; + int maxchan; + int targ; + int maxtarg; + int clun; + int maxlun; + int count; + + if (tag != SCB_LIST_NULL) + return (0); + + chan = 0; + if (channel != ALL_CHANNELS) { + chan = channel - 'A'; + maxchan = chan + 1; + } else { + maxchan = (ahc->features & AHC_TWIN) ? 2 : 1; + } + targ = 0; + if (target != CAM_TARGET_WILDCARD) { + targ = target; + maxtarg = targ + 1; + } else { + maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8; + } + clun = 0; + if (lun != CAM_LUN_WILDCARD) { + clun = lun; + maxlun = clun + 1; + } else { + maxlun = AHC_NUM_LUNS; + } + + count = 0; + for (; chan < maxchan; chan++) { + + for (; targ < maxtarg; targ++) { + + for (; clun < maxlun; clun++) { + struct ahc_linux_device *dev; + struct ahc_busyq *busyq; + struct ahc_cmd *acmd; + + dev = ahc_linux_get_device(ahc, chan, + targ, clun, + /*alloc*/FALSE); + if (dev == NULL) + continue; + + busyq = &dev->busyq; + while ((acmd = TAILQ_FIRST(busyq)) != NULL) { + Scsi_Cmnd *cmd; + + cmd = &acmd_scsi_cmd(acmd); + TAILQ_REMOVE(busyq, acmd, + acmd_links.tqe); + count++; + cmd->result = status << 16; + ahc_linux_queue_cmd_complete(ahc, cmd); + } + } + } + } + + return (count); +} + +/* + * Sets the queue depth for each SCSI device hanging + * off the input host adapter. + */ +static void +ahc_linux_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) +{ + Scsi_Device *device; + struct ahc_softc *ahc; + u_long flags; + int scbnum; + + ahc = *((struct ahc_softc **)host->hostdata); + ahc_lock(ahc, &flags); + scbnum = 0; + for (device = scsi_devs; device != NULL; device = device->next) { + if (device->host == host) { + ahc_linux_device_queue_depth(ahc, device); + scbnum += device->queue_depth; + } + } + ahc_unlock(ahc, &flags); +} + +static u_int +ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + static int warned_user; + u_int tags; + + tags = 0; + if ((ahc->user_discenable & devinfo->target_mask) != 0) { + if (warned_user == 0 + && ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { + + printf("aic7xxx: WARNING, insufficient " + "tag_info instances for installed " + "controllers. Using defaults\n"); + printf("aic7xxx: Please update the " + "aic7xxx_tag_info array in the " + "aic7xxx.c source file.\n"); + tags = AHC_MAX_QUEUE; + warned_user++; + } else { + adapter_tag_info_t *tag_info; + + tag_info = &aic7xxx_tag_info[ahc->unit]; + tags = tag_info->tag_commands[devinfo->target_offset]; + if (tags > AHC_MAX_QUEUE) + tags = AHC_MAX_QUEUE; + } + } + return (tags); +} + +/* + * Determines the queue depth for a given device. + */ +static void +ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +{ + struct ahc_devinfo devinfo; + u_int tags; + + ahc_compile_devinfo(&devinfo, + device->channel == 0 ? ahc->our_id : ahc->our_id_b, + device->id, device->lun, + device->channel == 0 ? 'A' : 'B', + ROLE_INITIATOR); + tags = ahc_linux_user_tagdepth(ahc, &devinfo); + if (tags != 0 + && device->tagged_supported != 0) { + + device->queue_depth = tags; + ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); + printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n", + ahc->platform_data->host->host_no, devinfo.channel, + devinfo.target, devinfo.lun, tags); + } else { + /* + * We allow the OS to queue 2 untagged transactions to + * us at any time even though we can only execute them + * serially on the controller/device. This should remove + * some latency. + */ + device->queue_depth = 2; + } +} + +/* + * Queue an SCB to the controller. + */ +int +ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +{ + struct ahc_softc *ahc; + struct ahc_linux_device *dev; + u_long flags; + + ahc = *(struct ahc_softc **)cmd->host->hostdata; + + /* + * Save the callback on completion function. + */ + cmd->scsi_done = scsi_done; + + ahc_lock(ahc, &flags); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); + if (dev == NULL) { + ahc_unlock(ahc, &flags); + printf("aic7xxx_linux_queue: Unable to allocate device!\n"); + return (-ENOMEM); + } + cmd->result = CAM_REQ_INPROG << 16; + TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); + if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + ahc_linux_run_device_queues(ahc); + } + ahc_unlock(ahc, &flags); + return (0); +} + +static void +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + struct ahc_cmd *acmd; + struct scsi_cmnd *cmd; + struct scb *scb; + struct hardware_scb *hscb; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + uint16_t mask; + + if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) + panic("running device on run list"); + + while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL + && dev->openings > 0 && dev->qfrozen == 0) { + + /* + * Schedule us to run later. The only reason we are not + * running is because the whole controller Q is frozen. + */ + if (ahc->platform_data->qfrozen != 0) { + + TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, + dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + return; + } + /* + * Get an scb to use. + */ + if ((scb = ahc_get_scb(ahc)) == NULL) { + TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, + dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + ahc->flags |= AHC_RESOURCE_SHORTAGE; + return; + } + TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); + cmd = &acmd_scsi_cmd(acmd); + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; + + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahc, cmd); + hscb->lun = cmd->lun; + mask = SCB_GET_TARGET_MASK(ahc, scb); + tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), + SCB_GET_OUR_ID(scb), + SCB_GET_TARGET(ahc, scb), &tstate); + hscb->scsirate = tinfo->scsirate; + hscb->scsioffset = tinfo->curr.offset; + if ((tstate->ultraenb & mask) != 0) + hscb->control |= ULTRAENB; + + if ((ahc->user_discenable & mask) != 0) + hscb->control |= DISCENB; + + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } + } + + hscb->cdb_len = cmd->cmd_len; + if (hscb->cdb_len <= 12) { + memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); + } else { + memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); + scb->flags |= SCB_CDB32_PTR; + } + + scb->platform_data->xfer_len = 0; + ahc_set_residual(scb, 0); + ahc_set_sense_residual(scb, 0); + scb->sg_count = 0; + if (cmd->use_sg != 0) { + struct ahc_dma_seg *sg; + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + int nseg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, + scsi_to_pci_dma_dir(cmd ->sc_data_direction)); + end_seg = cur_seg + nseg; + /* Copy the segments into the SG list. */ + sg = scb->sg_list; + /* + * The sg_count may be larger than nseg if + * a transfer crosses a 32bit page. + */ + while (cur_seg < end_seg) { + bus_addr_t addr; + bus_size_t len; + int consumed; + + addr = sg_dma_address(cur_seg); + len = sg_dma_len(cur_seg); + consumed = ahc_linux_map_seg(ahc, scb, + sg, addr, len); + sg += consumed; + scb->sg_count += consumed; + cur_seg++; + } + sg--; + sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); + + /* + * Reset the sg list pointer. + */ + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = scb->sg_list->addr; + scb->hscb->datacnt = scb->sg_list->len; + } else if (cmd->request_bufflen != 0) { + struct ahc_dma_seg *sg; + bus_addr_t addr; + + sg = scb->sg_list; + addr = pci_map_single(ahc->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + scb->platform_data->buf_busaddr = addr; + scb->sg_count = ahc_linux_map_seg(ahc, scb, + sg, addr, + cmd->request_bufflen); + sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); + + /* + * Reset the sg list pointer. + */ + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = sg->addr; + scb->hscb->datacnt = sg->len; + } else { + scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); + scb->hscb->dataptr = 0; + scb->hscb->datacnt = 0; + scb->sg_count = 0; + } + + ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE); + LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->commands_issued++; + if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) + dev->commands_since_idle_or_otag++; + + /* + * We only allow one untagged transaction + * per target in the initiator role unless + * we are storing a full busy target *lun* + * table in SCB space. + */ + if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 + && (ahc->features & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + int target_offset; + + target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); + untagged_q = &(ahc->untagged_queues[target_offset]); + TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; + if (TAILQ_FIRST(untagged_q) != scb) + continue; + } + scb->flags |= SCB_ACTIVE; + ahc_queue_scb(ahc, scb); + } +} + +/* + * SCSI controller interrupt handler. + */ +void +ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + u_long flags; + struct ahc_linux_device *next_dev; + + ahc = (struct ahc_softc *) dev_id; + ahc_lock(ahc, &flags); + ahc_intr(ahc); + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + next_dev = ahc_linux_next_device_to_run(ahc); + ahc_unlock(ahc, &flags); + if (next_dev) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_schedule(&ahc->platform_data->runq_tasklet); +#else + ahc_runq_tasklet((unsigned long)ahc); +#endif + } + if (acmd != NULL) + ahc_linux_run_complete_queue(ahc, acmd); +} + +void +ahc_platform_flushwork(struct ahc_softc *ahc) +{ + struct ahc_cmd *acmd; + + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + if (acmd != NULL) + ahc_linux_run_complete_queue(ahc, acmd); +} + +static struct ahc_linux_target* +ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +{ + struct ahc_linux_target *targ; + u_int target_offset; + + targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT); + if (targ == NULL) + return (NULL); + memset(targ, 0, sizeof(*targ)); + targ->channel = channel; + targ->target = target; + target_offset = target; + if (channel != 0) + target_offset += 8; + ahc->platform_data->targets[target_offset] = targ; + return (targ); +} + +static void +ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +{ + u_int target_offset; + + target_offset = targ->target; + if (targ->channel != 0) + target_offset += 8; + ahc->platform_data->targets[target_offset] = NULL; + free(targ, M_DEVBUF); +} + +static struct ahc_linux_device* +ahc_linux_alloc_device(struct ahc_softc *ahc, + struct ahc_linux_target *targ, u_int lun) +{ + struct ahc_linux_device *dev; + + dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); + if (dev == NULL) + return (NULL); + memset(dev, 0, sizeof(*dev)); + TAILQ_INIT(&dev->busyq); + dev->flags = AHC_DEV_UNCONFIGURED; + dev->lun = lun; + dev->target = targ; + + /* + * We start out life using untagged + * transactions of which we allow one. + */ + dev->openings = 1; + + /* + * Set maxtags to 0. This will be changed if we + * later determine that we are dealing with + * a tagged queuing capable device. + */ + dev->maxtags = 0; + + targ->refcount++; + targ->devices[lun] = dev; + return (dev); +} + +static void +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + struct ahc_linux_target *targ; + + targ = dev->target; + targ->devices[dev->lun] = NULL; + free(dev, M_DEVBUF); + targ->refcount--; + if (targ->refcount == 0) + ahc_linux_free_target(ahc, targ); +} + +/* + * Return a string describing the driver. + */ +const char * +ahc_linux_info(struct Scsi_Host *host) +{ + static char buffer[512]; + char ahc_info[256]; + char *bp; + struct ahc_softc *ahc; + + bp = &buffer[0]; + ahc = *(struct ahc_softc **)host->hostdata; + memset(bp, 0, sizeof(buffer)); + strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev "); + strcat(bp, AIC7XXX_DRIVER_VERSION); + strcat(bp, "\n"); + strcat(bp, " <"); + strcat(bp, ahc->description); + strcat(bp, ">\n"); + strcat(bp, " "); + ahc_controller_info(ahc, ahc_info); + strcat(bp, ahc_info); + strcat(bp, "\n"); + + return (bp); +} + +void +ahc_send_async(struct ahc_softc *ahc, char channel, + u_int target, u_int lun, ac_code code, void *arg) +{ + switch (code) { + case AC_TRANSFER_NEG: + { + char buf[80]; + struct ahc_linux_target *targ; + struct info_str info; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + int target_offset; + + info.buffer = buf; + info.length = sizeof(buf); + info.offset = 0; + info.pos = 0; + tinfo = ahc_fetch_transinfo(ahc, channel, + channel == 'A' ? ahc->our_id + : ahc->our_id_b, + target, &tstate); + + /* + * Don't bother reporting results while + * negotiations are still pending. + */ + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options) + if (bootverbose == 0) + break; + + /* + * Don't bother reporting results that + * are identical to those last reported. + */ + target_offset = target; + if (channel == 'B') + target_offset += 8; + targ = ahc->platform_data->targets[target_offset]; + if (targ == NULL) + break; + if (tinfo->curr.period == targ->last_tinfo.period + && tinfo->curr.width == targ->last_tinfo.width + && tinfo->curr.offset == targ->last_tinfo.offset + && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) + if (bootverbose == 0) + break; + + targ->last_tinfo.period = tinfo->curr.period; + targ->last_tinfo.width = tinfo->curr.width; + targ->last_tinfo.offset = tinfo->curr.offset; + targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; + + printf("(%s:%c:", ahc_name(ahc), channel); + if (target == CAM_TARGET_WILDCARD) + printf("*): "); + else + printf("%d): ", target); + ahc_format_transinfo(&info, &tinfo->curr); + if (info.pos < info.length) + *info.buffer = '\0'; + else + buf[info.length - 1] = '\0'; + printf("%s", buf); + break; + } + case AC_SENT_BDR: + break; + case AC_BUS_RESET: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + if (ahc->platform_data->host != NULL) { + scsi_report_bus_reset(ahc->platform_data->host, + channel - 'A'); + } +#endif + break; + default: + panic("ahc_send_async: Unexpected async event"); + } +} + +/* + * Calls the higher level scsi done function and frees the scb. + */ +void +ahc_done(struct ahc_softc *ahc, struct scb * scb) +{ + Scsi_Cmnd *cmd; + struct ahc_linux_device *dev; + + LIST_REMOVE(scb, pending_links); + if ((scb->flags & SCB_UNTAGGEDQ) != 0) { + struct scb_tailq *untagged_q; + int target_offset; + + target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); + untagged_q = &(ahc->untagged_queues[target_offset]); + TAILQ_REMOVE(untagged_q, scb, links.tqe); + ahc_run_untagged_queue(ahc, untagged_q); + } + + if ((scb->flags & SCB_ACTIVE) == 0) { + printf("SCB %d done'd twice\n", scb->hscb->tag); + ahc_dump_card_state(ahc); + panic("Stopping for safety"); + } + cmd = scb->io_ctx; + dev = scb->platform_data->dev; + dev->active--; + dev->openings++; + ahc_linux_unmap_scb(ahc, scb); + if (scb->flags & SCB_SENSE) { + memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), + MIN(sizeof(struct scsi_sense_data), + sizeof(cmd->sense_buffer))); + cmd->result |= (DRIVER_SENSE << 24); + } else { + /* + * Guard against stale sense data. + * The Linux mid-layer assumes that sense + * was retrieved anytime the first byte of + * the sense buffer looks "sane". + */ + cmd->sense_buffer[0] = 0; + } + if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) { + uint32_t amount_xferred; + + amount_xferred = + ahc_get_transfer_length(scb) - ahc_get_residual(scb); + if (amount_xferred < scb->io_ctx->underflow) { + printf("Saw underflow (%ld of %ld bytes). " + "Treated as error\n", + ahc_get_residual(scb), + ahc_get_transfer_length(scb)); + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + } else { + ahc_set_transaction_status(scb, CAM_REQ_CMP); + ahc_linux_sniff_command(ahc, cmd, scb); + } + } else if (ahc_get_transaction_status(scb) == DID_OK) { + ahc_linux_handle_scsi_status(ahc, dev, scb); + } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { + /* + * Should a selection timeout kill the device? + * That depends on whether the selection timeout + * is persistent. Since we have no guarantee that + * the mid-layer will issue an inquiry for this device + * again, we can't just kill it off. + dev->flags |= AHC_DEV_UNCONFIGURED; + */ + } + + if (dev->openings == 1 + && ahc_get_transaction_status(scb) == CAM_REQ_CMP + && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) + dev->tag_success_count++; + /* + * Some devices deal with temporary internal resource + * shortages by returning queue full. When the queue + * full occurrs, we throttle back. Slowly try to get + * back to our previous queue depth. + */ + if ((dev->openings + dev->active) < dev->maxtags + && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) { + dev->tag_success_count = 0; + dev->openings++; + } + + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; + + if (TAILQ_EMPTY(&dev->busyq)) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) + ahc_linux_free_device(ahc, dev); + } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + } + + if ((scb->flags & SCB_RECOVERY_SCB) != 0) { + printf("Recovery SCB completes\n"); + up(&ahc->platform_data->eh_sem); + } + + ahc_free_scb(ahc, scb); + ahc_linux_queue_cmd_complete(ahc, cmd); +} + +static void +ahc_linux_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) +{ + /* + * We don't currently trust the mid-layer to + * properly deal with queue full or busy. So, + * when one occurs, we tell the mid-layer to + * unconditionally requeue the command to us + * so that we can retry it ourselves. We also + * implement our own throttling mechanism so + * we don't clobber the device with too many + * commands. + */ + switch (ahc_get_scsi_status(scb)) { + default: + break; + case SCSI_STATUS_QUEUE_FULL: + { + /* + * By the time the core driver has returned this + * command, all other commands that were queued + * to us but not the device have been returned. + * This ensures that dev->active is equal to + * the number of commands actually queued to + * the device. + */ + dev->tag_success_count = 0; + if (dev->active != 0) { + /* + * Drop our opening count to the number + * of commands currently outstanding. + */ + dev->openings = 0; +/* + ahc_print_path(ahc, scb); + printf("Dropping tag count to %d\n", dev->active); + */ + if (dev->active == dev->tags_on_last_queuefull) { + + dev->last_queuefull_same_count++; + /* + * If we repeatedly see a queue full + * at the same queue depth, this + * device has a fixed number of tag + * slots. Lock in this tag depth + * so we stop seeing queue fulls from + * this device. + */ + if (dev->last_queuefull_same_count + == AHC_LOCK_TAGS_COUNT) { + dev->maxtags = dev->active; + ahc_print_path(ahc, scb); + printf("Locking max tag count at %d\n", + dev->active); + } + } else { + dev->tags_on_last_queuefull = dev->active; + dev->last_queuefull_same_count = 0; + } + ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); + ahc_set_scsi_status(scb, SCSI_STATUS_OK); + break; + } + /* + * Drop down to a single opening, and treat this + * as if the target return BUSY SCSI status. + */ + dev->openings = 1; + /* FALLTHROUGH */ + } + case SCSI_STATUS_BUSY: + /* + * XXX Set a timer and handle ourselves???? + * For now we pray that the mid-layer does something + * sane for devices that are busy. + */ + ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); + break; + } +} + +static void +ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd, struct scb *scb) +{ + switch (cmd->cmnd[0]) { + case INQUIRY: + { + struct ahc_devinfo devinfo; + struct scsi_inquiry *inq; + struct scsi_inquiry_data *sid; + struct ahc_initiator_tinfo *tinfo; + struct ahc_transinfo *user; + struct ahc_transinfo *goal; + struct ahc_transinfo *curr; + struct ahc_tmode_tstate *tstate; + struct ahc_syncrate *syncrate; + struct ahc_linux_device *dev; + u_int scsiid; + u_int maxsync; + int transferred_len; + int minlen; + u_int width; + u_int period; + u_int offset; + u_int ppr_options; + + /* + * Validate the command. We only want to filter + * standard inquiry commands, not those querying + * Vital Product Data. + */ + inq = (struct scsi_inquiry *)cmd->cmnd; + if ((inq->byte2 & SI_EVPD) != 0 + || inq->page_code != 0) + break; + + if (cmd->use_sg != 0) { + printf("%s: SG Inquiry response ignored\n", + ahc_name(ahc)); + break; + } + transferred_len = ahc_get_transfer_length(scb) + - ahc_get_residual(scb); + sid = (struct scsi_inquiry_data *)cmd->request_buffer; + + /* + * Determine if this lun actually exists. If so, + * hold on to its corresponding device structure. + * If not, make sure we release the device and + * don't bother processing the rest of this inquiry + * command. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); + if (transferred_len >= 1 + && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { + + dev->flags &= ~AHC_DEV_UNCONFIGURED; + } else { + dev->flags |= AHC_DEV_UNCONFIGURED; + break; + } + + /* + * Update our notion of this device's transfer + * negotiation capabilities. + */ + scsiid = BUILD_SCSIID(ahc, cmd); + ahc_compile_devinfo(&devinfo, SCSIID_OUR_ID(scsiid), + cmd->target, cmd->lun, + SCSIID_CHANNEL(ahc, scsiid), + ROLE_INITIATOR); + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); + user = &tinfo->user; + goal = &tinfo->goal; + curr = &tinfo->curr; + width = user->width; + period = user->period; + offset = user->offset; + ppr_options = user->ppr_options; + minlen = offsetof(struct scsi_inquiry_data, version) + 1; + if (transferred_len >= minlen) { + curr->protocol_version = SID_ANSI_REV(sid); + + /* + * Only attempt SPI3 once we've verified that + * the device claims to support SPI3 features. + */ + if (curr->protocol_version < SCSI_REV_2) + curr->transport_version = SID_ANSI_REV(sid); + else + curr->transport_version = SCSI_REV_2; + } + + minlen = offsetof(struct scsi_inquiry_data, flags) + 1; + if (transferred_len >= minlen + && (sid->additional_length + 4) >= minlen) { + if ((sid->flags & SID_WBus16) == 0) + width = MSG_EXT_WDTR_BUS_8_BIT; + if ((sid->flags & SID_Sync) == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } + } else { + /* Keep current settings */ + break; + } + minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; + /* + * This is a kludge to deal with inquiry requests that + * are not large enough for us to pull the spi3/4 bits. + * In this case, we assume that a device that tells us + * they can provide inquiry data that spans the SPI3 + * bits and says its SCSI3 can handle a PPR request. + * If the inquiry request has sufficient buffer space to + * cover SPI3 bits, we honor them regardless of reported + * SCSI REV. We also allow any device that has had its + * goal ppr_options set to allow DT speeds to keep that + * option if a short inquiry occurs that would fail the + * normal tests outlined above. + */ + if ((sid->additional_length + 4) >= minlen) { + if (transferred_len >= minlen) { + if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) + ppr_options = 0; + } else if ((goal->ppr_options & MSG_EXT_PPR_DT_REQ)== 0) + ppr_options = 0; + + if (curr->protocol_version > SCSI_REV_2) + curr->transport_version = 3; + } else { + ppr_options = 0; + } + ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, + ROLE_UNKNOWN); + if ((ahc->features & AHC_ULTRA2) != 0) + maxsync = AHC_SYNCRATE_DT; + else if ((ahc->features & AHC_ULTRA) != 0) + maxsync = AHC_SYNCRATE_ULTRA; + else + maxsync = AHC_SYNCRATE_FAST; + + syncrate = ahc_find_syncrate(ahc, &period, + &ppr_options, maxsync); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, + &offset, width, ROLE_UNKNOWN); + if (offset == 0 || period == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } + /* Apply our filtered user settings. */ + ahc_set_width(ahc, &devinfo, width, + AHC_TRANS_GOAL, /*paused*/FALSE); + ahc_set_syncrate(ahc, &devinfo, syncrate, period, + offset, ppr_options, AHC_TRANS_GOAL, + /*paused*/FALSE); + break; + } + default: + panic("ahc_linux_filter_command: Unexpected Command type %x\n", + cmd->cmnd[0]); + break; + } +} + +static void +ahc_linux_sem_timeout(u_long arg) +{ + struct semaphore *sem; + + sem = (struct semaphore *)arg; + up(sem); +} + +static void +ahc_linux_freeze_sim_queue(struct ahc_softc *ahc) +{ + ahc->platform_data->qfrozen++; + if (ahc->platform_data->qfrozen == 1) + scsi_block_requests(ahc->platform_data->host); +} + +static void +ahc_linux_release_sim_queue(u_long arg) +{ + struct ahc_softc *ahc; + u_long s; + int unblock_reqs; + + ahc = (struct ahc_softc *)arg; + unblock_reqs = 0; + ahc_lock(ahc, &s); + if (ahc->platform_data->qfrozen > 0) + ahc->platform_data->qfrozen--; + if (ahc->platform_data->qfrozen == 0) { + unblock_reqs = 1; + } + ahc_unlock(ahc, &s); + /* + * There is still a race here. The mid-layer + * should keep its own freeze count and use + * a bottom half handler to run the queues + * so we can unblock with our own lock held. + */ + if (unblock_reqs) { + scsi_unblock_requests(ahc->platform_data->host); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_schedule(&ahc->platform_data->runq_tasklet); +#else + ahc_runq_tasklet((unsigned long)ahc); +#endif + } +} + +static int +ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + struct ahc_cmd *list_acmd; + struct ahc_linux_device *dev; + struct scb *pending_scb; + u_long s; + u_int saved_scbptr; + u_int active_scb_index; + u_int last_phase; + int retval; + int paused; + int wait; + int disconnected; + + paused = FALSE; + wait = FALSE; + ahc = *(struct ahc_softc **)cmd->host->hostdata; + acmd = (struct ahc_cmd *)cmd; + + printf("%s:%d:%d:%d: Attempting to queue a%s message\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun, + flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + + /* + * It is a bug that the upper layer takes + * this lock just prior to calling us. + */ + spin_unlock_irq(&io_request_lock); + + ahc_lock(ahc, &s); + + /* + * First determine if we currently own this command. + * Start by searching the device queue. If not found + * there, check the pending_scb list. If not found + * at all, and the system wanted us to just abort the + * command return success. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); + + if (dev == NULL) { + /* + * No target device for this command exists, + * so we must not still own the command. + */ + printf("%s:%d:%d:%d: Is not an active device\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + retval = SUCCESS; + goto no_cmd; + } + + TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { + if (list_acmd == acmd) + break; + } + + if (list_acmd != NULL) { + printf("%s:%d:%d:%d: Command found on device queue\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + if (flag == SCB_ABORT) { + TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); + cmd->result = DID_ABORT << 16; + ahc_linux_queue_cmd_complete(ahc, cmd); + retval = SUCCESS; + goto done; + } + } + + /* + * See if we can find a matching cmd in the pending list. + */ + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + if (pending_scb->io_ctx == cmd) + break; + } + + if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { + + /* Any SCB for this device will do for a target reset */ + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + if (ahc_match_scb(ahc, pending_scb, cmd->target, + cmd->channel, CAM_LUN_WILDCARD, + SCB_LIST_NULL, ROLE_INITIATOR) == 0) + break; + } + } + + if (pending_scb == NULL) { + printf("%s:%d:%d:%d: Command not found\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + goto no_cmd; + } + + if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { + /* + * We can't queue two recovery actions using the same SCB + */ + retval = FAILED; + goto done; + } + + /* + * Ensure that the card doesn't do anything + * behind our back. Also make sure that we + * didn't "just" miss an interrupt that would + * affect this cmd. + */ + ahc->flags |= AHC_ALL_INTERRUPTS; + do { + ahc_intr(ahc); + ahc_pause(ahc); + ahc_clear_critical_section(ahc); + } while (ahc_inb(ahc, INTSTAT) & INT_PEND); + ahc->flags &= ~AHC_ALL_INTERRUPTS; + paused = TRUE; + + ahc_dump_card_state(ahc); + + if ((pending_scb->flags & SCB_ACTIVE) == 0) { + printf("%s:%d:%d:%d: Command already completed\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + goto no_cmd; + } + + disconnected = TRUE; + if (flag == SCB_ABORT) { + if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, CAM_REQ_ABORTED, + SEARCH_COMPLETE) > 0) { + printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + ahc_name(ahc), cmd->channel, cmd->target, + cmd->lun); + retval = SUCCESS; + goto done; + } + } else if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_COUNT) > 0) { + disconnected = FALSE; + } + + /* + * At this point, pending_scb is the scb associated with the + * passed in command. That command is currently active on the + * bus, is in the disconnected state, or we're hoping to find + * a command for the same target active on the bus to abuse to + * send a BDR. Queue the appropriate message based on which of + * these states we are in. + */ + last_phase = ahc_inb(ahc, LASTPHASE); + saved_scbptr = ahc_inb(ahc, SCBPTR); + active_scb_index = ahc_inb(ahc, SCB_TAG); + if (last_phase != P_BUSFREE + && (pending_scb->hscb->tag == active_scb_index + || (flag == SCB_DEVICE_RESET + && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->target))) { + + /* + * We're active on the bus, so assert ATN + * and hope that the target responds. + */ + pending_scb = ahc_lookup_scb(ahc, active_scb_index); + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, last_phase|ATNO); + printf("%s:%d:%d:%d: Device is active, asserting ATN\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + wait = TRUE; + } else if (disconnected) { + + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + * In either case (selection or reselection), + * we will now issue the approprate message + * to the timed-out device. + * + * Set the MK_MESSAGE control bit indicating + * that we desire to send a message. We + * also set the disconnected flag since + * in the paging case there is no guarantee + * that our SCB control byte matches the + * version on the card. We don't want the + * sequencer to abort the command thinking + * an unsolicited reselection occurred. + */ + pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + + /* + * Remove any cached copy of this SCB in the + * disconnected list in preparation for the + * queuing of our abort SCB. We use the + * same element in the SCB, SCB_NEXT, for + * both the qinfifo and the disconnected list. + */ + ahc_search_disc_list(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + /*stop_on_first*/TRUE, + /*remove*/TRUE, + /*save_state*/FALSE); + + /* + * In the non-paging case, the sequencer will + * never re-reference the in-core SCB. + * To make sure we are notified during + * reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + if ((ahc->flags & AHC_PAGESCBS) == 0) { + ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag); + ahc_outb(ahc, SCB_CONTROL, + ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE); + } + + /* + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. + */ + ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + ahc_print_path(ahc, pending_scb); + printf("Queuing a recovery SCB\n"); + ahc_qinfifo_requeue_tail(ahc, pending_scb); + ahc_outb(ahc, SCBPTR, saved_scbptr); + printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + wait = TRUE; + } else { + printf("%s:%d:%d:%d: Unable to deliver message\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + retval = FAILED; + goto done; + } + +no_cmd: + /* + * Our assumption is that if we don't have the command, no + * recovery action was required, so we return success. Again, + * the semantics of the mid-layer recovery engine are not + * well defined, so this may change in time. + */ + retval = SUCCESS; +done: + if (paused) + ahc_unpause(ahc); + if (wait) { + struct timer_list timer; + int ret; + + ahc_unlock(ahc, &s); + init_timer(&timer); + timer.data = (u_long)&ahc->platform_data->eh_sem; + timer.expires = jiffies + (5 * HZ); + timer.function = ahc_linux_sem_timeout; + add_timer(&timer); + printf("Recovery code sleeping\n"); + down(&ahc->platform_data->eh_sem); + printf("Recovery code awake\n"); + ret = del_timer(&timer); + if (ret == 0) { + printf("Timer Expired\n"); + retval = FAILED; + } + ahc_lock(ahc, &s); + } + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + ahc_unlock(ahc, &s); + if (acmd != NULL) + ahc_linux_run_complete_queue(ahc, acmd); + ahc_runq_tasklet((unsigned long)ahc); + spin_lock_irq(&io_request_lock); + return (retval); +} + +/* + * Abort the current SCSI command(s). + */ +int +ahc_linux_abort(Scsi_Cmnd *cmd) +{ + int error; + + error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); + if (error != 0) + printf("aic7xxx_abort returns 0x%x\n", error); + return (error); +} + +/* + * Attempt to send a target reset message to the device that timed out. + */ +int +ahc_linux_dev_reset(Scsi_Cmnd *cmd) +{ + int error; + + error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + if (error != 0) + printf("aic7xxx_dev_reset returns 0x%x\n", error); + return (error); +} + +/* + * Reset the SCSI bus. + */ +int +ahc_linux_bus_reset(Scsi_Cmnd *cmd) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + u_long s; + int found; + + /* + * It is a bug that the upper layer takes + * this lock just prior to calling us. + */ + spin_unlock_irq(&io_request_lock); + + ahc = *(struct ahc_softc **)cmd->host->hostdata; + ahc_lock(ahc, &s); + found = ahc_reset_channel(ahc, cmd->channel + 'A', + /*initiate reset*/TRUE); + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + ahc_unlock(ahc, &s); + if (bootverbose) + printf("%s: SCSI bus reset delivered. " + "%d SCBs aborted.\n", ahc_name(ahc), found); + + if (acmd != NULL) + ahc_linux_run_complete_queue(ahc, acmd); + + spin_lock_irq(&io_request_lock); + return SUCCESS; +} + +/* + * Return the disk geometry for the given SCSI device. + */ +int +ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) +{ + int heads; + int sectors; + int cylinders; + int ret; + int extended; + struct ahc_softc *ahc; + struct buffer_head *bh; + + ahc = *((struct ahc_softc **)disk->device->host->hostdata); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17) + bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); +#else + bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024); +#endif + + if (bh) { + ret = scsi_partsize(bh, disk->capacity, + &geom[2], &geom[0], &geom[1]); + brelse(bh); + if (ret != -1) + return (ret); + } + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if (aic7xxx_extended != 0) + extended = 1; + else if (disk->device->channel == 0) + extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; + else + extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; + if (extended && cylinders >= 1024) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + return (0); +} + +/* + * Free the passed in Scsi_Host memory structures prior to unloading the + * module. + */ +int +ahc_linux_release(struct Scsi_Host * host) +{ + struct ahc_softc *ahc; + + if (host != NULL) { + + ahc = *(struct ahc_softc **)host->hostdata; + ahc_free(ahc); + } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } + return (0); +} + +void +ahc_platform_dump_card_state(struct ahc_softc *ahc) +{ + struct ahc_linux_device *dev; + int channel; + int maxchannel; + int target; + int maxtarget; + int lun; + int i; + + maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0; + maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7; + for (channel = 0; channel <= maxchannel; channel++) { + + for (target = 0; target <=maxtarget; target++) { + + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct ahc_cmd *acmd; + + dev = ahc_linux_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); + if (dev == NULL) + continue; + + printf("DevQ(%d:%d:%d): ", + channel, target, lun); + i = 0; + TAILQ_FOREACH(acmd, &dev->busyq, + acmd_links.tqe) { + if (i++ > AHC_SCB_MAX) + break; + } + printf("%d waiting\n", i); + } + } + } +} + +#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static Scsi_Host_Template driver_template = AIC7XXX; +Scsi_Host_Template *aic7xxx_driver_template = &driver_template; +#include "../scsi_module.c" +#endif diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Feb 18 06:26:49 2002 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm.h Sat Mar 30 22:55:35 2002 @@ -18,7 +18,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#72 $ + * $Id$ * * Copyright (c) 2000-2001 Adaptec Inc. * All rights reserved. @@ -55,7 +55,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#72 $ + * $Id$ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -66,9 +66,11 @@ #include #include #include -#include #include #include +#ifndef AHC_MODVERSION_FILE +#define __NO_VERSION__ +#endif #include #include @@ -77,7 +79,11 @@ #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include /* For tasklet support. */ #include +#include +#else +#include #endif /* Core SCSI definitions */ @@ -391,7 +397,7 @@ /********************************** Includes **********************************/ /* Host template and function declarations referenced by the template. */ -#include "aic7xxx_linux_host.h" +#include "aic7xxx_host.h" /* Core driver definitions */ #include "aic7xxx.h" @@ -403,7 +409,7 @@ #include #endif -#define AIC7XXX_DRIVER_VERSION "6.2.4" +#define AIC7XXX_DRIVER_VERSION "6.2.5" /**************************** Front End Queues ********************************/ /* @@ -554,6 +560,7 @@ */ struct scb_platform_data { struct ahc_linux_device *dev; + bus_addr_t buf_busaddr; uint32_t xfer_len; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) uint32_t resid; /* Transfer residual */ @@ -575,13 +582,17 @@ TAILQ_HEAD(, ahc_linux_device) device_runq; struct ahc_completeq completeq; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) spinlock_t spin_lock; #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + struct tasklet_struct runq_tasklet; +#endif u_int qfrozen; struct timer_list reset_timer; struct semaphore eh_sem; struct Scsi_Host *host; /* pointer to scsi host */ +#define AHC_LINUX_NOIRQ ((uint32_t)~0) uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ @@ -843,7 +854,8 @@ ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ int aic7770_linux_probe(Scsi_Host_Template *); -int aic7770_map_registers(struct ahc_softc *ahc); +int aic7770_map_registers(struct ahc_softc *ahc, + u_int port); int aic7770_map_int(struct ahc_softc *ahc, u_int irq); /******************************* PCI Routines *********************************/ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,412 @@ +/* + * Linux driver attachment glue for PCI based controllers. + * + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#1 $ + */ + +#include "aic7xxx_osm.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +struct pci_device_id +{ +}; +#endif + +static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, + u_long *base); +#ifdef MMAPIO +static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, + u_long *bus_addr, + uint8_t **maddr); +#endif /* MMAPIO */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); + +/* We do our own ID filtering. So, grab all SCSI storage class devices. */ +static struct pci_device_id ahc_linux_pci_id_table[] = { + { + 0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0 + }, + { + 0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0 + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); + +struct pci_driver aic7xxx_pci_driver = { + name: "aic7xxx", + probe: ahc_linux_pci_dev_probe, + remove: ahc_linux_pci_dev_remove, + id_table: ahc_linux_pci_id_table +}; + +static void +ahc_linux_pci_dev_remove(struct pci_dev *pdev) +{ + struct ahc_softc *ahc; + struct ahc_softc *list_ahc; + + /* + * We should be able to just perform + * the free directly, but check our + * list for extra sanity. + */ + ahc = (struct ahc_softc *)pdev->driver_data; + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + if (list_ahc == ahc) { + ahc_free(ahc); + break; + } + } +} +#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ + +static int +ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + char buf[80]; + struct ahc_softc *ahc; + ahc_dev_softc_t pci; + struct ahc_pci_identity *entry; + char *name; + int error; + + /* + * Some BIOSen report the same device multiple times. + */ + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + struct pci_dev *probed_pdev; + + probed_pdev = ahc->dev_softc; + if (probed_pdev->bus->number == pdev->bus->number + && probed_pdev->devfn == pdev->devfn) + break; + } + if (ahc != NULL) { + /* Skip duplicate. */ + return (-ENODEV); + } + + pci = pdev; + entry = ahc_find_pci_device(pci); + if (entry == NULL) + return (-ENODEV); + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_pci:%d:%d:%d", + ahc_get_pci_bus(pci), + ahc_get_pci_slot(pci), + ahc_get_pci_function(pci)); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + return (-ENOMEM); + strcpy(name, buf); + ahc = ahc_alloc(NULL, name); + if (ahc == NULL) + return (-ENOMEM); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (pci_enable_device(pdev)) { + ahc_free(ahc); + return (-ENODEV); + } + pci_set_master(pdev); + + if (sizeof(bus_addr_t) > 4 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + && ahc_linux_get_memsize() > 0x80000000 + && pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) { +#else + && ahc_linux_get_memsize() > 0x80000000) { + + ahc->dev_softc->dma_mask = + (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); +#endif + ahc->flags |= AHC_39BIT_ADDRESSING; + ahc->platform_data->hw_dma_mask = + (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + } +#endif + ahc->dev_softc = pci; + error = ahc_pci_config(ahc, entry); + if (error != 0) { + ahc_free(ahc); + return (-error); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_drvdata(pdev, ahc); + if (aic7xxx_detect_complete) + ahc_linux_register_host(ahc, aic7xxx_driver_template); +#endif + return (0); +} + +int +ahc_linux_pci_probe(Scsi_Host_Template *template) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + return (pci_module_init(&aic7xxx_pci_driver)); +#else + struct pci_dev *pdev; + u_int class; + int found; + + /* If we don't have a PCI bus, we can't find any adapters. */ + if (pci_present() == 0) + return (0); + + found = 0; + pdev = NULL; + class = PCI_CLASS_STORAGE_SCSI << 8; + while ((pdev = pci_find_class(class, pdev)) != NULL) { + ahc_dev_softc_t pci; + int error; + + pci = pdev; + error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL); + if (error == 0) + found++; + } + return (found); +#endif +} + +static int +ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + *base = pci_resource_start(ahc->dev_softc, 0); +#else + *base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4); + *base &= PCI_BASE_ADDRESS_IO_MASK; +#endif + if (*base == 0) + return (ENOMEM); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + if (check_region(*base, 256) != 0) + return (ENOMEM); + else + request_region(*base, 256, "aic7xxx"); +#else + if (request_region(*base, 256, "aic7xxx") == 0) + return (ENOMEM); +#endif + return (0); +} + +#ifdef MMAPIO +static int +ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, + u_long *bus_addr, + uint8_t **maddr) +{ + u_long start; + u_long base_page; + u_long base_offset; + int error; + + error = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + start = pci_resource_start(ahc->dev_softc, 1); + base_page = start & PAGE_MASK; + base_offset = start - base_page; +#else + start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4); + base_offset = start & PCI_BASE_ADDRESS_MEM_MASK; + base_page = base_offset & PAGE_MASK; + base_offset -= base_page; +#endif + if (start != 0) { + *bus_addr = start; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (request_mem_region(start, 0x1000, "aic7xxx") == 0) + error = ENOMEM; +#endif + if (error == 0) { + *maddr = ioremap_nocache(base_page, base_offset + 256); + if (*maddr == NULL) { + error = ENOMEM; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + release_mem_region(start, 0x1000); +#endif + } else + *maddr += base_offset; + } + } else + error = ENOMEM; + return (error); +} +#endif /* MMAPIO */ + +int +ahc_pci_map_registers(struct ahc_softc *ahc) +{ + uint32_t command; + u_long base; + uint8_t *maddr; + int error; + + /* + * If its allowed, we prefer memory mapped access. + */ + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); + command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); + base = 0; + maddr = NULL; +#ifdef MMAPIO + error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr); + if (error == 0) { + ahc->platform_data->mem_busaddr = base; + ahc->tag = BUS_SPACE_MEMIO; + ahc->bsh.maddr = maddr; + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + command | PCIM_CMD_MEMEN, 4); + + /* + * Do a quick test to see if memory mapped + * I/O is functioning correctly. + */ + if (ahc_inb(ahc, HCNTRL) == 0xFF) { + + printf("aic7xxx: PCI Device %d:%d:%d " + "failed memory mapped test\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc)); + iounmap((void *)((u_long)maddr & PAGE_MASK)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + release_mem_region(ahc->platform_data->mem_busaddr, + 0x1000); +#endif + ahc->bsh.maddr = NULL; + maddr = NULL; + } else + command |= PCIM_CMD_MEMEN; + } else { + printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx " + "unavailable. Cannot memory map device.\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc), + base); + } +#endif /* MMAPIO */ + + /* + * We always prefer memory mapped access. + */ + if (maddr == NULL) { + + error = ahc_linux_pci_reserve_io_region(ahc, &base); + if (error == 0) { + ahc->tag = BUS_SPACE_PIO; + ahc->bsh.ioport = base; + command |= PCIM_CMD_PORTEN; + } else { + printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] " + "unavailable. Cannot map device.\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc), + base); + } + } + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); + return (error); +} + +int +ahc_pci_map_int(struct ahc_softc *ahc) +{ + int error; + + error = request_irq(ahc->dev_softc->irq, ahc_linux_isr, + SA_SHIRQ, "aic7xxx", ahc); + if (error == 0) + ahc->platform_data->irq = ahc->dev_softc->irq; + + return (-error); +} + +void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(ahc->dev_softc, new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif +} diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_pci.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_pci.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_pci.c Sat Mar 30 22:55:35 2002 @@ -39,14 +39,20 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#32 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ */ +#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" +#else +#include +#include +#include +#endif #define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ #define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ @@ -207,7 +213,7 @@ : ((id) & 0x1000) >> 12) /* * Informational only. Should use chip register to be - * ceratian, but may be use in identification strings. + * certain, but may be use in identification strings. */ #define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000 #define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000 @@ -782,11 +788,19 @@ ahc->chip |= AHC_PCI; ahc->description = entry->name; + ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + error = ahc_pci_map_registers(ahc); if (error != 0) return (error); - ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + /* + * Before we continue probing the card, ensure that + * its interrupts are *disabled*. We don't want + * a misstep to hang the machine in an interrupt + * storm. + */ + ahc_intr_enable(ahc, FALSE); /* * If we need to support high memory, enable dual @@ -1212,11 +1226,12 @@ start_addr = 32 * (ahc->channel - 'A'); - have_seeprom = read_seeprom(&sd, (uint16_t *)&sc, - start_addr, sizeof(sc)/2); + have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc, + start_addr, + sizeof(sc)/2); if (have_seeprom) - have_seeprom = verify_cksum(&sc); + have_seeprom = ahc_verify_cksum(&sc); if (have_seeprom != 0 || sd.sd_chip == C56_66) { if (bootverbose) { @@ -1257,8 +1272,14 @@ val = ahc_inb(ahc, SRAM_BASE + j) | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; } - have_seeprom = verify_cksum(&sc); + have_seeprom = ahc_verify_cksum(&sc); } + /* + * Clear any SCB parity errors in case this data and + * its associated parity was not initialized by the BIOS + */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); } if (!have_seeprom) { @@ -1534,6 +1555,15 @@ "Only two connectors on the " "adapter may be used at a " "time!\n", ahc_name(ahc)); + + /* + * Pretend there are no cables in the hope + * that having all of the termination on + * gives us a more stable bus. + */ + internal50_present = 0; + internal68_present = 0; + externalcable_present = 0; } if ((ahc->features & AHC_WIDE) != 0 diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_proc.c --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_proc.c Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#13 $ + * $Id$ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_reg.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_reg.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_reg.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_reg.h Sat Mar 30 22:55:35 2002 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#37 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#24 $ + * $Id$ + * $Id$ */ #define SCSISEQ 0x00 @@ -228,8 +228,6 @@ #define BUSY_TARGETS 0x20 #define TARG_SCSIRATE 0x20 -#define SRAM_BASE 0x20 - #define ULTRA_ENB 0x30 #define CMDSIZE_TABLE 0x30 @@ -396,6 +394,8 @@ #define TARG_OFFSET 0x70 +#define SRAM_BASE 0x70 + #define BCTL 0x84 #define ACE 0x08 #define ENABLE 0x01 @@ -714,3 +714,7 @@ #define SG_PREFETCH_CNT 0x04 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 +#define DOWNLOAD_CONST_COUNT 0x07 + + +/* Exported Labels */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_seq.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_seq.h --- linux-2.4.18/drivers/scsi/aic7xxx/aic7xxx_seq.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aic7xxx_seq.h Sat Mar 30 22:55:35 2002 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#37 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#24 $ + * $Id$ + * $Id$ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, @@ -880,410 +880,410 @@ 0xff, 0x6a, 0xd4, 0x0c }; -static int ahc_patch23_func(struct ahc_softc *ahc); +static int aic_patch23_func(struct ahc_softc *ahc); static int -ahc_patch23_func(struct ahc_softc *ahc) +aic_patch23_func(struct ahc_softc *ahc) { return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0); } -static int ahc_patch22_func(struct ahc_softc *ahc); +static int aic_patch22_func(struct ahc_softc *ahc); static int -ahc_patch22_func(struct ahc_softc *ahc) +aic_patch22_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_CMD_CHAN) == 0); } -static int ahc_patch21_func(struct ahc_softc *ahc); +static int aic_patch21_func(struct ahc_softc *ahc); static int -ahc_patch21_func(struct ahc_softc *ahc) +aic_patch21_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_QUEUE_REGS) == 0); } -static int ahc_patch20_func(struct ahc_softc *ahc); +static int aic_patch20_func(struct ahc_softc *ahc); static int -ahc_patch20_func(struct ahc_softc *ahc) +aic_patch20_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_WIDE) != 0); } -static int ahc_patch19_func(struct ahc_softc *ahc); +static int aic_patch19_func(struct ahc_softc *ahc); static int -ahc_patch19_func(struct ahc_softc *ahc) +aic_patch19_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_SCB_BTT) != 0); } -static int ahc_patch18_func(struct ahc_softc *ahc); +static int aic_patch18_func(struct ahc_softc *ahc); static int -ahc_patch18_func(struct ahc_softc *ahc) +aic_patch18_func(struct ahc_softc *ahc) { return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0); } -static int ahc_patch17_func(struct ahc_softc *ahc); +static int aic_patch17_func(struct ahc_softc *ahc); static int -ahc_patch17_func(struct ahc_softc *ahc) +aic_patch17_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); } -static int ahc_patch16_func(struct ahc_softc *ahc); +static int aic_patch16_func(struct ahc_softc *ahc); static int -ahc_patch16_func(struct ahc_softc *ahc) +aic_patch16_func(struct ahc_softc *ahc) { return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0); } -static int ahc_patch15_func(struct ahc_softc *ahc); +static int aic_patch15_func(struct ahc_softc *ahc); static int -ahc_patch15_func(struct ahc_softc *ahc) +aic_patch15_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_ULTRA2) == 0); } -static int ahc_patch14_func(struct ahc_softc *ahc); +static int aic_patch14_func(struct ahc_softc *ahc); static int -ahc_patch14_func(struct ahc_softc *ahc) +aic_patch14_func(struct ahc_softc *ahc) { return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); } -static int ahc_patch13_func(struct ahc_softc *ahc); +static int aic_patch13_func(struct ahc_softc *ahc); static int -ahc_patch13_func(struct ahc_softc *ahc) +aic_patch13_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_39BIT_ADDRESSING) != 0); } -static int ahc_patch12_func(struct ahc_softc *ahc); +static int aic_patch12_func(struct ahc_softc *ahc); static int -ahc_patch12_func(struct ahc_softc *ahc) +aic_patch12_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_HS_MAILBOX) != 0); } -static int ahc_patch11_func(struct ahc_softc *ahc); +static int aic_patch11_func(struct ahc_softc *ahc); static int -ahc_patch11_func(struct ahc_softc *ahc) +aic_patch11_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_ULTRA) != 0); } -static int ahc_patch10_func(struct ahc_softc *ahc); +static int aic_patch10_func(struct ahc_softc *ahc); static int -ahc_patch10_func(struct ahc_softc *ahc) +aic_patch10_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_MULTI_TID) != 0); } -static int ahc_patch9_func(struct ahc_softc *ahc); +static int aic_patch9_func(struct ahc_softc *ahc); static int -ahc_patch9_func(struct ahc_softc *ahc) +aic_patch9_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_CMD_CHAN) != 0); } -static int ahc_patch8_func(struct ahc_softc *ahc); +static int aic_patch8_func(struct ahc_softc *ahc); static int -ahc_patch8_func(struct ahc_softc *ahc) +aic_patch8_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_INITIATORROLE) != 0); } -static int ahc_patch7_func(struct ahc_softc *ahc); +static int aic_patch7_func(struct ahc_softc *ahc); static int -ahc_patch7_func(struct ahc_softc *ahc) +aic_patch7_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_TARGETROLE) != 0); } -static int ahc_patch6_func(struct ahc_softc *ahc); +static int aic_patch6_func(struct ahc_softc *ahc); static int -ahc_patch6_func(struct ahc_softc *ahc) +aic_patch6_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_DT) == 0); } -static int ahc_patch5_func(struct ahc_softc *ahc); +static int aic_patch5_func(struct ahc_softc *ahc); static int -ahc_patch5_func(struct ahc_softc *ahc) +aic_patch5_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0); } -static int ahc_patch4_func(struct ahc_softc *ahc); +static int aic_patch4_func(struct ahc_softc *ahc); static int -ahc_patch4_func(struct ahc_softc *ahc) +aic_patch4_func(struct ahc_softc *ahc) { return ((ahc->flags & AHC_PAGESCBS) != 0); } -static int ahc_patch3_func(struct ahc_softc *ahc); +static int aic_patch3_func(struct ahc_softc *ahc); static int -ahc_patch3_func(struct ahc_softc *ahc) +aic_patch3_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_QUEUE_REGS) != 0); } -static int ahc_patch2_func(struct ahc_softc *ahc); +static int aic_patch2_func(struct ahc_softc *ahc); static int -ahc_patch2_func(struct ahc_softc *ahc) +aic_patch2_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_TWIN) != 0); } -static int ahc_patch1_func(struct ahc_softc *ahc); +static int aic_patch1_func(struct ahc_softc *ahc); static int -ahc_patch1_func(struct ahc_softc *ahc) +aic_patch1_func(struct ahc_softc *ahc) { return ((ahc->features & AHC_ULTRA2) != 0); } -static int ahc_patch0_func(struct ahc_softc *ahc); +static int aic_patch0_func(struct ahc_softc *ahc); static int -ahc_patch0_func(struct ahc_softc *ahc) +aic_patch0_func(struct ahc_softc *ahc) { return (0); } -typedef int patch_func_t (struct ahc_softc *); -struct patch { +typedef int patch_func_t (struct ahc_softc *ahc); +static struct patch { patch_func_t *patch_func; uint32_t begin :10, skip_instr :10, skip_patch :12; } patches[] = { - { ahc_patch1_func, 4, 1, 1 }, - { ahc_patch2_func, 6, 2, 1 }, - { ahc_patch2_func, 9, 1, 1 }, - { ahc_patch3_func, 11, 1, 2 }, - { ahc_patch0_func, 12, 2, 1 }, - { ahc_patch4_func, 15, 1, 2 }, - { ahc_patch0_func, 16, 1, 1 }, - { ahc_patch5_func, 22, 2, 1 }, - { ahc_patch3_func, 27, 1, 2 }, - { ahc_patch0_func, 28, 1, 1 }, - { ahc_patch6_func, 34, 1, 1 }, - { ahc_patch7_func, 37, 54, 19 }, - { ahc_patch8_func, 37, 1, 1 }, - { ahc_patch9_func, 42, 3, 2 }, - { ahc_patch0_func, 45, 3, 1 }, - { ahc_patch10_func, 49, 1, 2 }, - { ahc_patch0_func, 50, 2, 3 }, - { ahc_patch1_func, 50, 1, 2 }, - { ahc_patch0_func, 51, 1, 1 }, - { ahc_patch2_func, 53, 2, 1 }, - { ahc_patch9_func, 55, 1, 2 }, - { ahc_patch0_func, 56, 1, 1 }, - { ahc_patch9_func, 60, 1, 2 }, - { ahc_patch0_func, 61, 1, 1 }, - { ahc_patch9_func, 71, 1, 2 }, - { ahc_patch0_func, 72, 1, 1 }, - { ahc_patch9_func, 75, 1, 2 }, - { ahc_patch0_func, 76, 1, 1 }, - { ahc_patch9_func, 79, 1, 2 }, - { ahc_patch0_func, 80, 1, 1 }, - { ahc_patch8_func, 91, 9, 4 }, - { ahc_patch1_func, 93, 1, 2 }, - { ahc_patch0_func, 94, 1, 1 }, - { ahc_patch2_func, 96, 2, 1 }, - { ahc_patch2_func, 105, 4, 1 }, - { ahc_patch1_func, 109, 1, 2 }, - { ahc_patch0_func, 110, 2, 3 }, - { ahc_patch2_func, 110, 1, 2 }, - { ahc_patch0_func, 111, 1, 1 }, - { ahc_patch7_func, 112, 4, 2 }, - { ahc_patch0_func, 116, 1, 1 }, - { ahc_patch11_func, 118, 2, 1 }, - { ahc_patch1_func, 120, 1, 2 }, - { ahc_patch0_func, 121, 1, 1 }, - { ahc_patch7_func, 122, 4, 1 }, - { ahc_patch7_func, 133, 89, 11 }, - { ahc_patch4_func, 151, 1, 1 }, - { ahc_patch1_func, 164, 1, 1 }, - { ahc_patch12_func, 169, 1, 2 }, - { ahc_patch0_func, 170, 1, 1 }, - { ahc_patch9_func, 181, 1, 2 }, - { ahc_patch0_func, 182, 1, 1 }, - { ahc_patch9_func, 191, 1, 2 }, - { ahc_patch0_func, 192, 1, 1 }, - { ahc_patch9_func, 208, 6, 2 }, - { ahc_patch0_func, 214, 6, 1 }, - { ahc_patch8_func, 222, 18, 2 }, - { ahc_patch1_func, 235, 1, 1 }, - { ahc_patch1_func, 242, 1, 2 }, - { ahc_patch0_func, 243, 2, 2 }, - { ahc_patch11_func, 244, 1, 1 }, - { ahc_patch9_func, 252, 31, 3 }, - { ahc_patch1_func, 268, 14, 2 }, - { ahc_patch13_func, 273, 1, 1 }, - { ahc_patch14_func, 283, 14, 1 }, - { ahc_patch1_func, 299, 1, 2 }, - { ahc_patch0_func, 300, 1, 1 }, - { ahc_patch9_func, 303, 1, 1 }, - { ahc_patch13_func, 308, 1, 1 }, - { ahc_patch9_func, 309, 2, 2 }, - { ahc_patch0_func, 311, 4, 1 }, - { ahc_patch14_func, 315, 1, 1 }, - { ahc_patch15_func, 318, 2, 3 }, - { ahc_patch9_func, 318, 1, 2 }, - { ahc_patch0_func, 319, 1, 1 }, - { ahc_patch6_func, 324, 1, 2 }, - { ahc_patch0_func, 325, 1, 1 }, - { ahc_patch1_func, 329, 50, 11 }, - { ahc_patch6_func, 338, 2, 4 }, - { ahc_patch7_func, 338, 1, 1 }, - { ahc_patch8_func, 339, 1, 1 }, - { ahc_patch0_func, 340, 1, 1 }, - { ahc_patch16_func, 341, 1, 1 }, - { ahc_patch6_func, 360, 6, 3 }, - { ahc_patch16_func, 360, 5, 1 }, - { ahc_patch0_func, 366, 5, 1 }, - { ahc_patch13_func, 374, 5, 1 }, - { ahc_patch0_func, 379, 54, 17 }, - { ahc_patch14_func, 379, 1, 1 }, - { ahc_patch7_func, 381, 2, 2 }, - { ahc_patch17_func, 382, 1, 1 }, - { ahc_patch9_func, 385, 1, 1 }, - { ahc_patch18_func, 392, 1, 1 }, - { ahc_patch14_func, 397, 9, 3 }, - { ahc_patch9_func, 398, 3, 2 }, - { ahc_patch0_func, 401, 3, 1 }, - { ahc_patch9_func, 409, 6, 2 }, - { ahc_patch0_func, 415, 9, 2 }, - { ahc_patch13_func, 415, 1, 1 }, - { ahc_patch13_func, 424, 2, 1 }, - { ahc_patch14_func, 426, 1, 1 }, - { ahc_patch9_func, 428, 1, 2 }, - { ahc_patch0_func, 429, 1, 1 }, - { ahc_patch7_func, 432, 1, 1 }, - { ahc_patch7_func, 433, 1, 1 }, - { ahc_patch8_func, 434, 3, 3 }, - { ahc_patch6_func, 435, 1, 2 }, - { ahc_patch0_func, 436, 1, 1 }, - { ahc_patch9_func, 437, 1, 1 }, - { ahc_patch15_func, 438, 1, 2 }, - { ahc_patch13_func, 438, 1, 1 }, - { ahc_patch14_func, 440, 9, 4 }, - { ahc_patch9_func, 440, 1, 1 }, - { ahc_patch9_func, 447, 2, 1 }, - { ahc_patch0_func, 449, 4, 3 }, - { ahc_patch9_func, 449, 1, 2 }, - { ahc_patch0_func, 450, 3, 1 }, - { ahc_patch1_func, 454, 2, 1 }, - { ahc_patch7_func, 456, 10, 2 }, - { ahc_patch0_func, 466, 1, 1 }, - { ahc_patch8_func, 467, 109, 23 }, - { ahc_patch1_func, 469, 3, 2 }, - { ahc_patch0_func, 472, 5, 3 }, - { ahc_patch9_func, 472, 2, 2 }, - { ahc_patch0_func, 474, 3, 1 }, - { ahc_patch1_func, 479, 2, 2 }, - { ahc_patch0_func, 481, 6, 3 }, - { ahc_patch9_func, 481, 2, 2 }, - { ahc_patch0_func, 483, 3, 1 }, - { ahc_patch1_func, 489, 2, 2 }, - { ahc_patch0_func, 491, 9, 7 }, - { ahc_patch9_func, 491, 5, 6 }, - { ahc_patch19_func, 491, 1, 2 }, - { ahc_patch0_func, 492, 1, 1 }, - { ahc_patch19_func, 494, 1, 2 }, - { ahc_patch0_func, 495, 1, 1 }, - { ahc_patch0_func, 496, 4, 1 }, - { ahc_patch6_func, 500, 3, 2 }, - { ahc_patch0_func, 503, 1, 1 }, - { ahc_patch1_func, 506, 1, 1 }, - { ahc_patch6_func, 512, 1, 2 }, - { ahc_patch0_func, 513, 1, 1 }, - { ahc_patch20_func, 550, 7, 1 }, - { ahc_patch3_func, 578, 1, 2 }, - { ahc_patch0_func, 579, 1, 1 }, - { ahc_patch21_func, 582, 1, 1 }, - { ahc_patch8_func, 584, 104, 33 }, - { ahc_patch4_func, 585, 1, 1 }, - { ahc_patch1_func, 591, 2, 2 }, - { ahc_patch0_func, 593, 1, 1 }, - { ahc_patch1_func, 596, 1, 2 }, - { ahc_patch0_func, 597, 1, 1 }, - { ahc_patch9_func, 598, 3, 3 }, - { ahc_patch15_func, 599, 1, 1 }, - { ahc_patch0_func, 601, 4, 1 }, - { ahc_patch19_func, 609, 2, 2 }, - { ahc_patch0_func, 611, 1, 1 }, - { ahc_patch19_func, 615, 10, 3 }, - { ahc_patch5_func, 617, 8, 1 }, - { ahc_patch0_func, 625, 9, 2 }, - { ahc_patch5_func, 626, 8, 1 }, - { ahc_patch4_func, 636, 1, 2 }, - { ahc_patch0_func, 637, 1, 1 }, - { ahc_patch19_func, 638, 1, 2 }, - { ahc_patch0_func, 639, 3, 2 }, - { ahc_patch4_func, 641, 1, 1 }, - { ahc_patch5_func, 642, 1, 1 }, - { ahc_patch5_func, 645, 1, 1 }, - { ahc_patch5_func, 647, 1, 1 }, - { ahc_patch4_func, 649, 2, 2 }, - { ahc_patch0_func, 651, 2, 1 }, - { ahc_patch5_func, 653, 1, 1 }, - { ahc_patch5_func, 656, 1, 1 }, - { ahc_patch5_func, 659, 1, 1 }, - { ahc_patch19_func, 663, 1, 1 }, - { ahc_patch19_func, 666, 1, 1 }, - { ahc_patch4_func, 672, 1, 1 }, - { ahc_patch6_func, 675, 1, 2 }, - { ahc_patch0_func, 676, 1, 1 }, - { ahc_patch7_func, 688, 16, 1 }, - { ahc_patch4_func, 704, 20, 1 }, - { ahc_patch9_func, 725, 4, 2 }, - { ahc_patch0_func, 729, 4, 1 }, - { ahc_patch9_func, 733, 4, 2 }, - { ahc_patch0_func, 737, 3, 1 }, - { ahc_patch6_func, 743, 1, 1 }, - { ahc_patch22_func, 745, 14, 1 }, - { ahc_patch7_func, 759, 3, 1 }, - { ahc_patch9_func, 771, 24, 8 }, - { ahc_patch19_func, 775, 1, 2 }, - { ahc_patch0_func, 776, 1, 1 }, - { ahc_patch15_func, 781, 4, 2 }, - { ahc_patch0_func, 785, 7, 3 }, - { ahc_patch23_func, 785, 5, 2 }, - { ahc_patch0_func, 790, 2, 1 }, - { ahc_patch0_func, 795, 42, 3 }, - { ahc_patch18_func, 807, 18, 2 }, - { ahc_patch0_func, 825, 1, 1 }, - { ahc_patch4_func, 849, 1, 1 }, - { ahc_patch4_func, 850, 3, 2 }, - { ahc_patch0_func, 853, 1, 1 }, - { ahc_patch13_func, 854, 3, 1 }, - { ahc_patch4_func, 857, 12, 1 } + { aic_patch1_func, 4, 1, 1 }, + { aic_patch2_func, 6, 2, 1 }, + { aic_patch2_func, 9, 1, 1 }, + { aic_patch3_func, 11, 1, 2 }, + { aic_patch0_func, 12, 2, 1 }, + { aic_patch4_func, 15, 1, 2 }, + { aic_patch0_func, 16, 1, 1 }, + { aic_patch5_func, 22, 2, 1 }, + { aic_patch3_func, 27, 1, 2 }, + { aic_patch0_func, 28, 1, 1 }, + { aic_patch6_func, 34, 1, 1 }, + { aic_patch7_func, 37, 54, 19 }, + { aic_patch8_func, 37, 1, 1 }, + { aic_patch9_func, 42, 3, 2 }, + { aic_patch0_func, 45, 3, 1 }, + { aic_patch10_func, 49, 1, 2 }, + { aic_patch0_func, 50, 2, 3 }, + { aic_patch1_func, 50, 1, 2 }, + { aic_patch0_func, 51, 1, 1 }, + { aic_patch2_func, 53, 2, 1 }, + { aic_patch9_func, 55, 1, 2 }, + { aic_patch0_func, 56, 1, 1 }, + { aic_patch9_func, 60, 1, 2 }, + { aic_patch0_func, 61, 1, 1 }, + { aic_patch9_func, 71, 1, 2 }, + { aic_patch0_func, 72, 1, 1 }, + { aic_patch9_func, 75, 1, 2 }, + { aic_patch0_func, 76, 1, 1 }, + { aic_patch9_func, 79, 1, 2 }, + { aic_patch0_func, 80, 1, 1 }, + { aic_patch8_func, 91, 9, 4 }, + { aic_patch1_func, 93, 1, 2 }, + { aic_patch0_func, 94, 1, 1 }, + { aic_patch2_func, 96, 2, 1 }, + { aic_patch2_func, 105, 4, 1 }, + { aic_patch1_func, 109, 1, 2 }, + { aic_patch0_func, 110, 2, 3 }, + { aic_patch2_func, 110, 1, 2 }, + { aic_patch0_func, 111, 1, 1 }, + { aic_patch7_func, 112, 4, 2 }, + { aic_patch0_func, 116, 1, 1 }, + { aic_patch11_func, 118, 2, 1 }, + { aic_patch1_func, 120, 1, 2 }, + { aic_patch0_func, 121, 1, 1 }, + { aic_patch7_func, 122, 4, 1 }, + { aic_patch7_func, 133, 89, 11 }, + { aic_patch4_func, 151, 1, 1 }, + { aic_patch1_func, 164, 1, 1 }, + { aic_patch12_func, 169, 1, 2 }, + { aic_patch0_func, 170, 1, 1 }, + { aic_patch9_func, 181, 1, 2 }, + { aic_patch0_func, 182, 1, 1 }, + { aic_patch9_func, 191, 1, 2 }, + { aic_patch0_func, 192, 1, 1 }, + { aic_patch9_func, 208, 6, 2 }, + { aic_patch0_func, 214, 6, 1 }, + { aic_patch8_func, 222, 18, 2 }, + { aic_patch1_func, 235, 1, 1 }, + { aic_patch1_func, 242, 1, 2 }, + { aic_patch0_func, 243, 2, 2 }, + { aic_patch11_func, 244, 1, 1 }, + { aic_patch9_func, 252, 31, 3 }, + { aic_patch1_func, 268, 14, 2 }, + { aic_patch13_func, 273, 1, 1 }, + { aic_patch14_func, 283, 14, 1 }, + { aic_patch1_func, 299, 1, 2 }, + { aic_patch0_func, 300, 1, 1 }, + { aic_patch9_func, 303, 1, 1 }, + { aic_patch13_func, 308, 1, 1 }, + { aic_patch9_func, 309, 2, 2 }, + { aic_patch0_func, 311, 4, 1 }, + { aic_patch14_func, 315, 1, 1 }, + { aic_patch15_func, 318, 2, 3 }, + { aic_patch9_func, 318, 1, 2 }, + { aic_patch0_func, 319, 1, 1 }, + { aic_patch6_func, 324, 1, 2 }, + { aic_patch0_func, 325, 1, 1 }, + { aic_patch1_func, 329, 50, 11 }, + { aic_patch6_func, 338, 2, 4 }, + { aic_patch7_func, 338, 1, 1 }, + { aic_patch8_func, 339, 1, 1 }, + { aic_patch0_func, 340, 1, 1 }, + { aic_patch16_func, 341, 1, 1 }, + { aic_patch6_func, 360, 6, 3 }, + { aic_patch16_func, 360, 5, 1 }, + { aic_patch0_func, 366, 5, 1 }, + { aic_patch13_func, 374, 5, 1 }, + { aic_patch0_func, 379, 54, 17 }, + { aic_patch14_func, 379, 1, 1 }, + { aic_patch7_func, 381, 2, 2 }, + { aic_patch17_func, 382, 1, 1 }, + { aic_patch9_func, 385, 1, 1 }, + { aic_patch18_func, 392, 1, 1 }, + { aic_patch14_func, 397, 9, 3 }, + { aic_patch9_func, 398, 3, 2 }, + { aic_patch0_func, 401, 3, 1 }, + { aic_patch9_func, 409, 6, 2 }, + { aic_patch0_func, 415, 9, 2 }, + { aic_patch13_func, 415, 1, 1 }, + { aic_patch13_func, 424, 2, 1 }, + { aic_patch14_func, 426, 1, 1 }, + { aic_patch9_func, 428, 1, 2 }, + { aic_patch0_func, 429, 1, 1 }, + { aic_patch7_func, 432, 1, 1 }, + { aic_patch7_func, 433, 1, 1 }, + { aic_patch8_func, 434, 3, 3 }, + { aic_patch6_func, 435, 1, 2 }, + { aic_patch0_func, 436, 1, 1 }, + { aic_patch9_func, 437, 1, 1 }, + { aic_patch15_func, 438, 1, 2 }, + { aic_patch13_func, 438, 1, 1 }, + { aic_patch14_func, 440, 9, 4 }, + { aic_patch9_func, 440, 1, 1 }, + { aic_patch9_func, 447, 2, 1 }, + { aic_patch0_func, 449, 4, 3 }, + { aic_patch9_func, 449, 1, 2 }, + { aic_patch0_func, 450, 3, 1 }, + { aic_patch1_func, 454, 2, 1 }, + { aic_patch7_func, 456, 10, 2 }, + { aic_patch0_func, 466, 1, 1 }, + { aic_patch8_func, 467, 109, 23 }, + { aic_patch1_func, 469, 3, 2 }, + { aic_patch0_func, 472, 5, 3 }, + { aic_patch9_func, 472, 2, 2 }, + { aic_patch0_func, 474, 3, 1 }, + { aic_patch1_func, 479, 2, 2 }, + { aic_patch0_func, 481, 6, 3 }, + { aic_patch9_func, 481, 2, 2 }, + { aic_patch0_func, 483, 3, 1 }, + { aic_patch1_func, 489, 2, 2 }, + { aic_patch0_func, 491, 9, 7 }, + { aic_patch9_func, 491, 5, 6 }, + { aic_patch19_func, 491, 1, 2 }, + { aic_patch0_func, 492, 1, 1 }, + { aic_patch19_func, 494, 1, 2 }, + { aic_patch0_func, 495, 1, 1 }, + { aic_patch0_func, 496, 4, 1 }, + { aic_patch6_func, 500, 3, 2 }, + { aic_patch0_func, 503, 1, 1 }, + { aic_patch1_func, 506, 1, 1 }, + { aic_patch6_func, 512, 1, 2 }, + { aic_patch0_func, 513, 1, 1 }, + { aic_patch20_func, 550, 7, 1 }, + { aic_patch3_func, 578, 1, 2 }, + { aic_patch0_func, 579, 1, 1 }, + { aic_patch21_func, 582, 1, 1 }, + { aic_patch8_func, 584, 104, 33 }, + { aic_patch4_func, 585, 1, 1 }, + { aic_patch1_func, 591, 2, 2 }, + { aic_patch0_func, 593, 1, 1 }, + { aic_patch1_func, 596, 1, 2 }, + { aic_patch0_func, 597, 1, 1 }, + { aic_patch9_func, 598, 3, 3 }, + { aic_patch15_func, 599, 1, 1 }, + { aic_patch0_func, 601, 4, 1 }, + { aic_patch19_func, 609, 2, 2 }, + { aic_patch0_func, 611, 1, 1 }, + { aic_patch19_func, 615, 10, 3 }, + { aic_patch5_func, 617, 8, 1 }, + { aic_patch0_func, 625, 9, 2 }, + { aic_patch5_func, 626, 8, 1 }, + { aic_patch4_func, 636, 1, 2 }, + { aic_patch0_func, 637, 1, 1 }, + { aic_patch19_func, 638, 1, 2 }, + { aic_patch0_func, 639, 3, 2 }, + { aic_patch4_func, 641, 1, 1 }, + { aic_patch5_func, 642, 1, 1 }, + { aic_patch5_func, 645, 1, 1 }, + { aic_patch5_func, 647, 1, 1 }, + { aic_patch4_func, 649, 2, 2 }, + { aic_patch0_func, 651, 2, 1 }, + { aic_patch5_func, 653, 1, 1 }, + { aic_patch5_func, 656, 1, 1 }, + { aic_patch5_func, 659, 1, 1 }, + { aic_patch19_func, 663, 1, 1 }, + { aic_patch19_func, 666, 1, 1 }, + { aic_patch4_func, 672, 1, 1 }, + { aic_patch6_func, 675, 1, 2 }, + { aic_patch0_func, 676, 1, 1 }, + { aic_patch7_func, 688, 16, 1 }, + { aic_patch4_func, 704, 20, 1 }, + { aic_patch9_func, 725, 4, 2 }, + { aic_patch0_func, 729, 4, 1 }, + { aic_patch9_func, 733, 4, 2 }, + { aic_patch0_func, 737, 3, 1 }, + { aic_patch6_func, 743, 1, 1 }, + { aic_patch22_func, 745, 14, 1 }, + { aic_patch7_func, 759, 3, 1 }, + { aic_patch9_func, 771, 24, 8 }, + { aic_patch19_func, 775, 1, 2 }, + { aic_patch0_func, 776, 1, 1 }, + { aic_patch15_func, 781, 4, 2 }, + { aic_patch0_func, 785, 7, 3 }, + { aic_patch23_func, 785, 5, 2 }, + { aic_patch0_func, 790, 2, 1 }, + { aic_patch0_func, 795, 42, 3 }, + { aic_patch18_func, 807, 18, 2 }, + { aic_patch0_func, 825, 1, 1 }, + { aic_patch4_func, 849, 1, 1 }, + { aic_patch4_func, 850, 3, 2 }, + { aic_patch0_func, 853, 1, 1 }, + { aic_patch13_func, 854, 3, 1 }, + { aic_patch4_func, 857, 12, 1 } }; -struct cs { +static struct cs { u_int16_t begin; u_int16_t end; } critical_sections[] = { @@ -1295,5 +1295,5 @@ { 865, 867 }, { 867, 869 } }; -const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections); +static const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections); diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/Makefile linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/Makefile --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/Makefile Sat Mar 30 22:55:35 2002 @@ -1,13 +1,16 @@ PROG= aicasm -.SUFFIXES= .l .y .c +.SUFFIXES= .l .y .c .h CSRCS= aicasm.c aicasm_symbol.c -GENSRCS= aicasm_gram.c aicasm_scan.c -GENHDRS= y.tab.h aicdb.h +YSRCS= aicasm_gram.y aicasm_macro_gram.y +LSRCS= aicasm_scan.l aicasm_macro_scan.l -SRCS= ${GENSRCS} ${CSRCS} -CLEANFILES= ${GENSRCS} ${GENHDRS} y.output +GENHDRS= aicdb.h $(YSRCS:.y=.h) +GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) + +SRCS= ${CSRCS} ${GENSRCS} +CLEANFILES= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d @@ -26,7 +29,9 @@ LFLAGS= -d endif -$(PROG): $(SRCS) $(GENHDRS) +.NOTPARALLEL: + +$(PROG): ${GENHDRS} $(SRCS) $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) aicdb.h: @@ -45,8 +50,18 @@ clean: rm -f $(CLEANFILES) $(PROG) -y.tab.h aicasm_gram.c: aicasm_gram.y - $(YACC) $(YFLAGS) aicasm_gram.y - mv y.tab.c aicasm_gram.c +aicasm_gram.c aicasm_gram.h: aicasm_gram.y + $(YACC) $(YFLAGS) -b $(<:.y=) $< + mv $(<:.y=).tab.c $(<:.y=.c) + mv $(<:.y=).tab.h $(<:.y=.h) + +aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y + $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< + mv $(<:.y=).tab.c $(<:.y=.c) + mv $(<:.y=).tab.h $(<:.y=.h) + +aicasm_scan.c: aicasm_scan.l + $(LEX) $(LFLAGS) -t $< > $@ -aicasm_scan.c: y.tab.h +aicasm_macro_scan.c: aicasm_macro_scan.l + $(LEX) $(LFLAGS) -t -Pmm $< > $@ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm.c --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm.c Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#11 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.29 2000/10/05 04:25:42 gibbs Exp $ */ @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,8 @@ FILE *regfile; char *listfilename; FILE *listfile; +int src_mode; +int dst_mode; static STAILQ_HEAD(,instruction) seq_program; struct cs_tailq cs_tailq; @@ -98,7 +101,9 @@ #if DEBUG extern int yy_flex_debug; +extern int mm_flex_debug; extern int yydebug; +extern int mmdebug; #endif extern FILE *yyin; extern int yyparse(void); @@ -131,7 +136,9 @@ listfile = NULL; #if DEBUG yy_flex_debug = 0; + mm_flex_debug = 0; yydebug = 0; + mmdebug = 0; #endif while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { switch(ch) { @@ -139,8 +146,10 @@ #if DEBUG if (strcmp(optarg, "s") == 0) { yy_flex_debug = 1; + mm_flex_debug = 1; } else if (strcmp(optarg, "p") == 0) { yydebug = 1; + mmdebug = 1; } else { fprintf(stderr, "%s: -d Requires either an " "'s' or 'p' argument\n", appname); @@ -243,8 +252,7 @@ if (retval == 0) { if (SLIST_FIRST(&scope_stack) == NULL || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { - stop("Unterminated conditional expression", - EX_DATAERR); + stop("Unterminated conditional expression", EX_DATAERR); /* NOTREACHED */ } @@ -355,6 +363,10 @@ } fprintf(ofile, "\n};\n\n"); + if (patch_arg_list == NULL) + stop("Patch argument list not defined", + EX_DATAERR); + /* * Output patch information. Patch functions first. */ @@ -362,31 +374,33 @@ cur_node != NULL; cur_node = SLIST_NEXT(cur_node,links)) { fprintf(ofile, -"static int ahc_patch%d_func(struct ahc_softc *ahc); +"static int aic_patch%d_func(%s); static int -ahc_patch%d_func(struct ahc_softc *ahc) +aic_patch%d_func(%s) { return (%s); }\n\n", cur_node->symbol->info.condinfo->func_num, + patch_arg_list, cur_node->symbol->info.condinfo->func_num, + patch_arg_list, cur_node->symbol->name); } fprintf(ofile, -"typedef int patch_func_t (struct ahc_softc *); -struct patch { +"typedef int patch_func_t (%s); +static struct patch { patch_func_t *patch_func; uint32_t begin :10, skip_instr :10, skip_patch :12; -} patches[] = {\n"); +} patches[] = {\n", patch_arg_list); for(cur_patch = STAILQ_FIRST(&patches); cur_patch != NULL; cur_patch = STAILQ_NEXT(cur_patch,links)) { - fprintf(ofile, "%s\t{ ahc_patch%d_func, %d, %d, %d }", + fprintf(ofile, "%s\t{ aic_patch%d_func, %d, %d, %d }", cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", cur_patch->patch_func, cur_patch->begin, cur_patch->skip_instr, cur_patch->skip_patch); @@ -395,7 +409,7 @@ fprintf(ofile, "\n};\n"); fprintf(ofile, -"struct cs { +"static struct cs { u_int16_t begin; u_int16_t end; } critical_sections[] = {\n"); @@ -411,8 +425,8 @@ fprintf(ofile, "\n};\n"); fprintf(ofile, -"const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections);\n"); +"static const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections);\n"); fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); } diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm.h --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm.h Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#7 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -78,10 +78,15 @@ extern char *appname; extern int yylineno; extern char *yyfilename; +extern char *patch_arg_list; extern char *versions; +extern int src_mode; +extern int dst_mode; +struct symbol; void stop(const char *errstring, int err_code); void include_file(char *file_name, include_type type); +void expand_macro(struct symbol *macro_symbol); struct instruction *seq_alloc(void); struct critical_section *cs_alloc(void); struct scope *scope_alloc(void); diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Sat Mar 30 22:55:35 2002 @@ -38,18 +38,20 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#9 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_gram.y,v 1.12 2000/10/31 18:44:32 gibbs Exp $ */ +#include + #include +#include #include #include #include #include -#include #ifdef __linux__ #include "../queue.h" #else @@ -62,21 +64,29 @@ int yylineno; char *yyfilename; +char *patch_arg_list; char *versions; +static char errbuf[255]; +static char regex_pattern[255]; static symbol_t *cur_symbol; +static symbol_t *scb_or_sram_symbol; static symtype cur_symtype; -static symbol_t *accumulator; +static symbol_ref_t accumulator; +static symbol_ref_t mode_ptr; static symbol_ref_t allones; static symbol_ref_t allzeros; static symbol_ref_t none; static symbol_ref_t sindex; static int instruction_ptr; +static int num_srams; static int sram_or_scb_offset; static int download_constant_count; static int in_critical_section; static void process_bitmask(int mask_type, symbol_t *sym, int mask); static void initialize_symbol(symbol_t *symbol); +static void add_macro_arg(const char *argtext, int position); +static void add_macro_body(const char *bodytext); static void process_register(symbol_t **p_symbol); static void format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, symbol_ref_t *src, int ret); @@ -92,13 +102,12 @@ static void add_version(const char *verstring); static int is_download_const(expression_t *immed); -#define YYDEBUG 1 #define SRAM_SYMNAME "SRAM_BASE" #define SCB_SYMNAME "SCB_BASE" %} %union { - int value; + u_int value; char *str; symbol_t *sym; symbol_ref_t sym_ref; @@ -109,6 +118,8 @@ %token T_CONST +%token T_EXPORT + %token T_DOWNLOAD %token T_SCB @@ -119,10 +130,22 @@ %token T_SIZE +%token T_EXPR_LSHIFT + +%token T_EXPR_RSHIFT + %token T_ADDRESS %token T_ACCESS_MODE +%token T_MODES + +%token T_DEFINE + +%token T_SET_SRC_MODE + +%token T_SET_DST_MODE + %token T_MODE %token T_BEGIN_CS @@ -135,11 +158,11 @@ %token T_NUMBER -%token T_PATH T_STRING +%token T_PATH T_STRING T_ARG T_MACROBODY %token T_CEXPR -%token T_EOF T_INCLUDE T_VERSION +%token T_EOF T_INCLUDE T_VERSION T_PATCH_ARG_LIST %token T_SHR T_SHL T_ROR T_ROL @@ -163,7 +186,7 @@ %token T_NOP -%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX +%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR %token T_A @@ -177,13 +200,15 @@ %type expression immediate immediate_or_a -%type ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne +%type export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne -%type numerical_value +%type numerical_value mode_value mode_list macro_arglist %left '|' %left '&' +%left T_EXPR_LSHIFT T_EXPR_RSHIFT %left '+' '-' +%left '*' '/' %right '~' %nonassoc UMINUS %% @@ -191,18 +216,26 @@ program: include | program include +| patch_arg_list +| program patch_arg_list | version | program version | register | program register | constant | program constant +| macrodefn +| program macrodefn | scratch_ram | program scratch_ram | scb | program scb | label | program label +| set_src_mode +| program set_src_mode +| set_dst_mode +| program set_dst_mode | critical_section_start | program critical_section_start | critical_section_end @@ -224,6 +257,18 @@ } ; +patch_arg_list: + T_PATCH_ARG_LIST '=' T_STRING + { + if (patch_arg_list != NULL) + stop("Patch argument list multiply defined", + EX_DATAERR); + patch_arg_list = strdup($3); + if (patch_arg_list == NULL) + stop("Unable to record patch arg list", EX_SOFTWARE); + } +; + version: T_VERSION '=' T_STRING { add_version($3); } @@ -280,10 +325,12 @@ reg_address | size | access_mode +| modes | bit_defn | mask_defn | alias | accumulator +| mode_pointer | allones | allzeros | none @@ -301,6 +348,18 @@ T_SIZE T_NUMBER { cur_symbol->info.rinfo->size = $2; + if (scb_or_sram_symbol != NULL) { + u_int max_addr; + u_int sym_max_addr; + + max_addr = scb_or_sram_symbol->info.rinfo->address + + scb_or_sram_symbol->info.rinfo->size; + sym_max_addr = cur_symbol->info.rinfo->address + + cur_symbol->info.rinfo->size; + + if (sym_max_addr > max_addr) + stop("SCB or SRAM space exhausted", EX_DATAERR); + } } ; @@ -311,6 +370,54 @@ } ; +modes: + T_MODES mode_list + { + cur_symbol->info.rinfo->modes = $2; + } +; + +mode_list: + mode_value + { + $$ = $1; + } +| mode_list ',' mode_value + { + $$ = $1 | $3; + } +; + +mode_value: + T_NUMBER + { + if ($1 > 4) { + stop("Valid register modes range between 0 and 4.", + EX_DATAERR); + /* NOTREACHED */ + } + + $$ = (0x1 << $1); + } +| T_SYMBOL + { + symbol_t *symbol; + + symbol = $1; + if (symbol->type != CONST) { + stop("Only \"const\" symbols allowed in " + "mode definitions.", EX_DATAERR); + /* NOTREACHED */ + } + if (symbol->info.cinfo->value > 4) { + stop("Valid register modes range between 0 and 4.", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = (0x1 << symbol->info.cinfo->value); + } +; + bit_defn: T_BIT T_SYMBOL T_NUMBER { @@ -342,12 +449,24 @@ accumulator: T_ACCUM { - if (accumulator != NULL) { + if (accumulator.symbol != NULL) { stop("Only one accumulator definition allowed", EX_DATAERR); /* NOTREACHED */ } - accumulator = cur_symbol; + accumulator.symbol = cur_symbol; + } +; + +mode_pointer: + T_MODE_PTR + { + if (mode_ptr.symbol != NULL) { + stop("Only one mode pointer definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + mode_ptr.symbol = cur_symbol; } ; @@ -428,6 +547,34 @@ &($1.referenced_syms), &($3.referenced_syms)); } +| expression '*' expression + { + $$.value = $1.value * $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| expression '/' expression + { + $$.value = $1.value / $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| expression T_EXPR_LSHIFT expression + { + $$.value = $1.value << $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression T_EXPR_RSHIFT expression + { + $$.value = $1.value >> $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } | '(' expression ')' { $$ = $2; @@ -471,12 +618,10 @@ case UNINITIALIZED: default: { - char buf[255]; - - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Undefined symbol %s referenced", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ break; } @@ -497,7 +642,6 @@ $2->type = CONST; initialize_symbol($2); $2->info.cinfo->value = $3; - $2->info.cinfo->define = $1; } | T_CONST T_SYMBOL T_DOWNLOAD { @@ -514,7 +658,54 @@ $2->type = DOWNLOAD_CONST; initialize_symbol($2); $2->info.cinfo->value = download_constant_count++; - $2->info.cinfo->define = FALSE; + } +; + +macrodefn_prologue: + T_DEFINE T_SYMBOL + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a macro", + EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol = $2; + cur_symbol->type = MACRO; + initialize_symbol(cur_symbol); + } +; + +macrodefn: + macrodefn_prologue T_MACROBODY + { + add_macro_body($2); + } +| macrodefn_prologue '(' macro_arglist ')' T_MACROBODY + { + add_macro_body($5); + cur_symbol->info.macroinfo->narg = $3; + } +; + +macro_arglist: + { + /* Macros can take no arguments */ + $$ = 0; + } +| T_ARG + { + $$ = 1; + add_macro_arg($1, 0); + } +| macro_arglist ',' T_ARG + { + if ($1 == 0) { + stop("Comma without preceeding argument in arg list", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = $1 + 1; + add_macro_arg($3, $1); } ; @@ -532,13 +723,10 @@ scratch_ram: T_SRAM '{' { + snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME, + num_srams); cur_symbol = symtable_get(SRAM_SYMNAME); cur_symtype = SRAMLOC; - if (cur_symbol->type != UNINITIALIZED) { - stop("Only one SRAM definition allowed", - EX_DATAERR); - /* NOTREACHED */ - } cur_symbol->type = SRAMLOC; initialize_symbol(cur_symbol); } @@ -546,10 +734,15 @@ { sram_or_scb_offset = cur_symbol->info.rinfo->address; } - scb_or_sram_reg_list + size + { + scb_or_sram_symbol = cur_symbol; + } + scb_or_sram_attributes '}' { cur_symbol = NULL; + scb_or_sram_symbol = NULL; } ; @@ -572,13 +765,25 @@ { sram_or_scb_offset = cur_symbol->info.rinfo->address; } - scb_or_sram_reg_list + size + { + scb_or_sram_symbol = cur_symbol; + } + scb_or_sram_attributes '}' { cur_symbol = NULL; + scb_or_sram_symbol = NULL; } ; +scb_or_sram_attributes: + /* NULL definition is okay */ +| modes +| scb_or_sram_reg_list +| modes scb_or_sram_reg_list +; + scb_or_sram_reg_list: reg_definition | scb_or_sram_reg_list reg_definition @@ -619,11 +824,11 @@ } | T_A { - if (accumulator == NULL) { + if (accumulator.symbol == NULL) { stop("No accumulator has been defined", EX_DATAERR); /* NOTREACHED */ } - $$.symbol = accumulator; + $$.symbol = accumulator.symbol; $$.offset = 0; } ; @@ -644,6 +849,14 @@ immediate_or_a: expression { + if ($1.value == 0 && is_download_const(&$1) == 0) { + snprintf(errbuf, sizeof(errbuf), + "\nExpression evaluates to 0 and thus " + "references the accumulator.\n " + "If this is the desired effect, use 'A' " + "instead.\n"); + stop(errbuf, EX_DATAERR); + } $$ = $1; } | T_A @@ -676,8 +889,22 @@ { $$ = 1; } ; +set_src_mode: + T_SET_SRC_MODE T_NUMBER ';' + { + src_mode = $2; + } +; + +set_dst_mode: + T_SET_DST_MODE T_NUMBER ';' + { + dst_mode = $2; + } +; + critical_section_start: - T_BEGIN_CS + T_BEGIN_CS ';' { critical_section_t *cs; @@ -692,7 +919,7 @@ } critical_section_end: - T_END_CS + T_END_CS ';' { critical_section_t *cs; @@ -705,16 +932,23 @@ in_critical_section = FALSE; } +export: + { $$ = 0; } +| T_EXPORT + { $$ = 1; } +; + label: - T_SYMBOL ':' + export T_SYMBOL ':' { - if ($1->type != UNINITIALIZED) { + if ($2->type != UNINITIALIZED) { stop("Program label multiply defined", EX_DATAERR); /* NOTREACHED */ } - $1->type = LABEL; - initialize_symbol($1); - $1->info.linfo->address = instruction_ptr; + $2->type = LABEL; + initialize_symbol($2); + $2->info.linfo->address = instruction_ptr; + $2->info.linfo->exported = $1; } ; @@ -1128,6 +1362,16 @@ } memset(symbol->info.rinfo, 0, sizeof(struct reg_info)); + /* + * Default to allowing access in all register modes + * or to the mode specified by the SCB or SRAM space + * we are in. + */ + if (scb_or_sram_symbol != NULL) + symbol->info.rinfo->modes = + scb_or_sram_symbol->info.rinfo->modes; + else + symbol->info.rinfo->modes = ~0; break; case ALIAS: symbol->info.ainfo = @@ -1181,6 +1425,17 @@ memset(symbol->info.condinfo, 0, sizeof(struct cond_info)); break; + case MACRO: + symbol->info.macroinfo = + (struct macro_info *)malloc(sizeof(struct macro_info)); + if (symbol->info.macroinfo == NULL) { + stop("Can't create macro info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.macroinfo, 0, + sizeof(struct macro_info)); + STAILQ_INIT(&symbol->info.macroinfo->args); + break; default: stop("Call to initialize_symbol with invalid symbol type", EX_SOFTWARE); @@ -1190,25 +1445,75 @@ } static void +add_macro_arg(const char *argtext, int argnum) +{ + struct macro_arg *marg; + int i; + int retval; + + + if (cur_symbol == NULL || cur_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + + marg = (struct macro_arg *)malloc(sizeof(*marg)); + if (marg == NULL) { + stop("Can't create macro_arg structure", EX_SOFTWARE); + /* NOTREACHED */ + } + marg->replacement_text = NULL; + retval = snprintf(regex_pattern, sizeof(regex_pattern), + "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)", + argtext); + if (retval >= sizeof(regex_pattern)) { + stop("Regex text buffer too small for arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED); + if (retval != 0) { + stop("Regex compilation failed", EX_SOFTWARE); + /* NOTREACHED */ + } + STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links); +} + +static void +add_macro_body(const char *bodytext) +{ + if (cur_symbol == NULL || cur_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + cur_symbol->info.macroinfo->body = strdup(bodytext); + if (cur_symbol->info.macroinfo->body == NULL) { + stop("Can't duplicate macro body text", EX_SOFTWARE); + /* NOTREACHED */ + } +} + +static void process_register(symbol_t **p_symbol) { - char buf[255]; symbol_t *symbol = *p_symbol; if (symbol->type == UNINITIALIZED) { - snprintf(buf, sizeof(buf), "Undefined register %s", + snprintf(errbuf, sizeof(errbuf), "Undefined register %s", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } else if (symbol->type == ALIAS) { *p_symbol = symbol->info.ainfo->parent; } else if ((symbol->type != REGISTER) && (symbol->type != SCBLOC) && (symbol->type != SRAMLOC)) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Specified symbol %s is not a register", symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); } } @@ -1242,6 +1547,47 @@ if (is_download_const(immed)) f1_instr->parity = 1; + else if (dest->symbol == mode_ptr.symbol) { + u_int src_value; + u_int dst_value; + + /* + * Attempt to update mode information if + * we are operating on the mode register. + */ + if (src->symbol == allones.symbol) + src_value = 0xFF; + else if (src->symbol == allzeros.symbol) + src_value = 0; + else if (src->symbol == mode_ptr.symbol) + src_value = (dst_mode << 4) | src_mode; + else + goto cant_update; + + switch (opcode) { + case AIC_OP_AND: + dst_value = src_value & immed->value; + break; + case AIC_OP_XOR: + dst_value = src_value ^ immed->value; + break; + case AIC_OP_ADD: + dst_value = (src_value + immed->value) & 0xFF; + break; + case AIC_OP_OR: + dst_value = src_value | immed->value; + break; + break; + case AIC_OP_BMOV: + dst_value = src_value; + break; + default: + goto cant_update; + } + src_mode = dst_value & 0xF; + dst_mode = (dst_value >> 4) & 0xF; +cant_update: + } symlist_free(&immed->referenced_syms); instruction_ptr++; @@ -1350,6 +1696,14 @@ static void test_readable_symbol(symbol_t *symbol) { + + if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) { + snprintf(errbuf, sizeof(errbuf), + "Register %s unavailable in source reg mode %d", + symbol->name, src_mode); + stop(errbuf, EX_DATAERR); + } + if (symbol->info.rinfo->mode == WO) { stop("Write Only register specified as source", EX_DATAERR); @@ -1360,6 +1714,14 @@ static void test_writable_symbol(symbol_t *symbol) { + + if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) { + snprintf(errbuf, sizeof(errbuf), + "Register %s unavailable in destination reg mode %d", + symbol->name, dst_mode); + stop(errbuf, EX_DATAERR); + } + if (symbol->info.rinfo->mode == RO) { stop("Read Only register specified as destination", EX_DATAERR); @@ -1372,7 +1734,6 @@ { symbol_node_t *node; int and_op; - char buf[255]; and_op = FALSE; if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) @@ -1385,11 +1746,11 @@ */ if (and_op == FALSE && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Invalid bit(s) 0x%x in immediate written to %s", expression->value & ~symbol->info.rinfo->valid_bitmask, symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } @@ -1397,7 +1758,7 @@ * Now make sure that all of the symbols referenced by the * expression are defined for this register. */ - if(symbol->info.rinfo->typecheck_masks != FALSE) { + if (symbol->info.rinfo->typecheck_masks != FALSE) { for(node = expression->referenced_syms.slh_first; node != NULL; node = node->links.sle_next) { @@ -1405,11 +1766,11 @@ || node->symbol->type == BIT) && symlist_search(&node->symbol->info.minfo->symrefs, symbol->name) == NULL) { - snprintf(buf, sizeof(buf), + snprintf(errbuf, sizeof(errbuf), "Invalid bit or mask %s " "for register %s", node->symbol->name, symbol->name); - stop(buf, EX_DATAERR); + stop(errbuf, EX_DATAERR); /* NOTREACHED */ } } diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Sat Mar 30 22:55:35 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#7 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3 2000/09/22 22:19:54 gibbs Exp $ */ diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y Sat Mar 30 22:55:35 2002 @@ -0,0 +1,164 @@ +%{ +/* + * Sub-parser for macro invocation in the Aic7xxx SCSI + * Host adapter sequencer assembler. + * + * Copyright (c) 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id$ + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_insformat.h" + +static symbol_t *macro_symbol; + +static void add_macro_arg(const char *argtext, int position); + +%} + +%union { + int value; + char *str; + symbol_t *sym; +} + + +%token T_ARG + +%token T_SYMBOL + +%type macro_arglist + +%% + +macrocall: + T_SYMBOL '(' + { + macro_symbol = $1; + } + macro_arglist ')' + { + if (macro_symbol->info.macroinfo->narg != $4) { + printf("Narg == %d", macro_symbol->info.macroinfo->narg); + stop("Too few arguments for macro invocation", + EX_DATAERR); + /* NOTREACHED */ + } + macro_symbol = NULL; + YYACCEPT; + } +; + +macro_arglist: + { + /* Macros can take 0 arguments */ + $$ = 0; + } +| T_ARG + { + $$ = 1; + add_macro_arg($1, 1); + } +| macro_arglist ',' T_ARG + { + if ($1 == 0) { + stop("Comma without preceeding argument in arg list", + EX_DATAERR); + /* NOTREACHED */ + } + $$ = $1 + 1; + add_macro_arg($3, $$); + } +; + +%% + +static void +add_macro_arg(const char *argtext, int argnum) +{ + struct macro_arg *marg; + int i; + + if (macro_symbol == NULL || macro_symbol->type != MACRO) { + stop("Invalid current symbol for adding macro arg", + EX_SOFTWARE); + /* NOTREACHED */ + } + /* + * Macro Invocation. Find the appropriate argument and fill + * in the replace ment text for this call. + */ + i = 0; + STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { + i++; + if (i == argnum) + break; + } + if (marg == NULL) { + stop("Too many arguments for macro invocation", EX_DATAERR); + /* NOTREACHED */ + } + marg->replacement_text = strdup(argtext); + if (marg->replacement_text == NULL) { + stop("Unable to replicate replacement text", EX_SOFTWARE); + /* NOTREACHED */ + } +} + +void +mmerror(const char *string) +{ + stop(string, EX_DATAERR); +} diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l Sat Mar 30 22:55:35 2002 @@ -0,0 +1,154 @@ +%{ +/* + * Sub-Lexical Analyzer for macro invokation in + * the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $Id$ + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_macro_gram.h" + +#define MAX_STR_CONST 4096 +static char string_buf[MAX_STR_CONST]; +static char *string_buf_ptr; +static int parren_count; +static char buf[255]; +%} + +WORD [A-Za-z_][-A-Za-z_0-9]* +SPACE [ \t]+ +MCARG [^(), \t]+ + +%x ARGLIST + +%% +\n { + ++yylineno; + } +{SPACE} ; +\( { + parren_count++; + if (parren_count == 1) { + string_buf_ptr = string_buf; + return ('('); + } + *string_buf_ptr++ = '('; + } +\) { + if (parren_count == 1) { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this parren so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + mmlval.str = string_buf; + string_buf_ptr = string_buf; + unput(')'); + return T_ARG; + } + BEGIN INITIAL; + return (')'); + } + parren_count--; + *string_buf_ptr++ = ')'; + } +{MCARG} { + char *yptr; + + yptr = mmtext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +\, { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this comma so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + mmlval.str = string_buf; + string_buf_ptr = string_buf; + unput(','); + return T_ARG; + } + return ','; + } +{WORD}[(] { + /* May be a symbol or a macro invocation. */ + mmlval.sym = symtable_get(mmtext); + if (mmlval.sym->type != MACRO) { + stop("Expecting Macro Name", + EX_DATAERR); + } + unput('('); + parren_count = 0; + BEGIN ARGLIST; + return T_SYMBOL; + } +. { + snprintf(buf, sizeof(buf), "Invalid character " + "'%c'", mmtext[0]); + stop(buf, EX_DATAERR); + } +%% + +int +mmwrap() +{ + stop("EOF encountered in macro call", EX_DATAERR); +} diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Sat Mar 30 22:55:35 2002 @@ -38,14 +38,15 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#7 $ + * $Id$ * - * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13 2000/09/22 22:19:54 gibbs Exp $ + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13.2.3 2001/07/28 18:46:44 gibbs Exp $ */ #include #include +#include #include #include #include @@ -57,23 +58,31 @@ #include "aicasm.h" #include "aicasm_symbol.h" -#include "y.tab.h" +#include "aicasm_gram.h" -#define MAX_STR_CONST 256 -char string_buf[MAX_STR_CONST]; -char *string_buf_ptr; -int parren_count; -int quote_count; +/* This is used for macro body capture too, so err on the large size. */ +#define MAX_STR_CONST 4096 +static char string_buf[MAX_STR_CONST]; +static char *string_buf_ptr; +static int parren_count; +static int quote_count; +static char buf[255]; %} -PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]* +PATH ([/]*[-A-Za-z0-9_.])+ WORD [A-Za-z_][-A-Za-z_0-9]* SPACE [ \t]+ +MCARG [^(), \t]+ +MBODY ((\\[^\n])*[^\n\\]*)+ %x COMMENT %x CEXPR %x INCLUDE %x STRING +%x MACRODEF +%x MACROARGLIST +%x MACROCALLARGS +%x MACROBODY %% \n { ++yylineno; } @@ -122,6 +131,7 @@ } VERSION { return T_VERSION; } +PATCH_ARG_LIST { return T_PATCH_ARG_LIST; } \" { string_buf_ptr = string_buf; BEGIN STRING; @@ -140,14 +150,16 @@ yylval.str = string_buf; return T_STRING; } -{SPACE} ; +{SPACE} ; /* Register/SCB/SRAM definition keywords */ +export { return T_EXPORT; } register { return T_REGISTER; } const { yylval.value = FALSE; return T_CONST; } download { return T_DOWNLOAD; } address { return T_ADDRESS; } access_mode { return T_ACCESS_MODE; } +modes { return T_MODES; } RW|RO|WO { if (strcmp(yytext, "RW") == 0) yylval.value = RW; @@ -159,6 +171,8 @@ } BEGIN_CRITICAL { return T_BEGIN_CS; } END_CRITICAL { return T_END_CS; } +SET_SRC_MODE { return T_SET_SRC_MODE; } +SET_DST_MODE { return T_SET_DST_MODE; } bit { return T_BIT; } mask { return T_MASK; } alias { return T_ALIAS; } @@ -166,6 +180,7 @@ scb { return T_SCB; } scratch_ram { return T_SRAM; } accumulator { return T_ACCUM; } +mode_pointer { return T_MODE_PTR; } allones { return T_ALLONES; } allzeros { return T_ALLZEROS; } none { return T_NONE; } @@ -206,7 +221,9 @@ else { return T_ELSE; } /* Allowed Symbols */ -[-+,:()~|&."{};<>[\]!=] { return yytext[0]; } +\<\< { return T_EXPR_LSHIFT; } +\>\> { return T_EXPR_RSHIFT; } +[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } /* Number processing */ 0[0-7]* { @@ -223,7 +240,6 @@ yylval.value = strtol(yytext, NULL, 10); return T_NUMBER; } - /* Include Files */ #include{SPACE} { BEGIN INCLUDE; @@ -238,13 +254,7 @@ quote_count++; return yytext[0]; } -. { stop("Invalid include line", EX_DATAERR); } - - /* For parsing C include files with #define foo */ -#define { yylval.value = TRUE; return T_CONST; } - /* Throw away macros */ -#define[^\n]*[()]+[^\n]* ; -{PATH} { +{PATH} { char *yptr; yptr = yytext; @@ -255,12 +265,158 @@ *string_buf_ptr = '\0'; return T_PATH; } +. { stop("Invalid include line", EX_DATAERR); } +#define{SPACE} { + BEGIN MACRODEF; + return T_DEFINE; + } +{WORD}{SPACE} { + char *yptr; -{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; } + /* Strip space and return as a normal symbol */ + yptr = yytext; + while (*yptr != ' ' && *yptr != '\t') + yptr++; + *yptr = '\0'; + yylval.sym = symtable_get(yytext); + string_buf_ptr = string_buf; + BEGIN MACROBODY; + return T_SYMBOL; + } +{WORD}\( { + /* + * We store the symbol with its opening + * parren so we can differentiate macros + * that take args from macros with the + * same name that do not take args as + * is allowed in C. + */ + BEGIN MACROARGLIST; + yylval.sym = symtable_get(yytext); + unput('('); + return T_SYMBOL; + } +{WORD} { + yylval.str = yytext; + return T_ARG; + } +{SPACE} ; +[(,] { + return yytext[0]; + } +[)] { + string_buf_ptr = string_buf; + BEGIN MACROBODY; + return ')'; + } +. { + snprintf(buf, sizeof(buf), "Invalid character " + "'%c' in macro argument list", + yytext[0]); + stop(buf, EX_DATAERR); + } +{SPACE} ; +\( { + parren_count++; + if (parren_count == 1) + return ('('); + *string_buf_ptr++ = '('; + } +\) { + parren_count--; + if (parren_count == 0) { + BEGIN INITIAL; + return (')'); + } + *string_buf_ptr++ = ')'; + } +{MCARG} { + char *yptr; -. { - char buf[255]; + yptr = yytext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +\, { + if (string_buf_ptr != string_buf) { + /* + * Return an argument and + * rescan this comma so we + * can return it as well. + */ + *string_buf_ptr = '\0'; + yylval.str = string_buf; + string_buf_ptr = string_buf; + unput(','); + return T_ARG; + } + return ','; + } +\\\n { + /* Eat escaped newlines. */ + ++yylineno; + } +\n { + /* Macros end on the first unescaped newline. */ + BEGIN INITIAL; + *string_buf_ptr = '\0'; + yylval.str = string_buf; + ++yylineno; + return T_MACROBODY; + } +{MBODY} { + char *yptr; + + yptr = yytext; + while (*yptr) + *string_buf_ptr++ = *yptr++; + } +{WORD}\( { + char *yptr; + char *ycopy; + /* May be a symbol or a macro invocation. */ + yylval.sym = symtable_get(yytext); + if (yylval.sym->type == MACRO) { + YY_BUFFER_STATE old_state; + YY_BUFFER_STATE temp_state; + + ycopy = strdup(yytext); + yptr = ycopy + yyleng; + while (yptr > ycopy) + unput(*--yptr); + old_state = YY_CURRENT_BUFFER; + temp_state = + yy_create_buffer(stdin, + YY_BUF_SIZE); + yy_switch_to_buffer(temp_state); + mm_switch_to_buffer(old_state); + mmparse(); + mm_switch_to_buffer(temp_state); + yy_switch_to_buffer(old_state); + mm_delete_buffer(temp_state); + expand_macro(yylval.sym); + } else { + if (yylval.sym->type == UNINITIALIZED) { + /* Try without the '(' */ + symbol_delete(yylval.sym); + yytext[yyleng-1] = '\0'; + yylval.sym = + symtable_get(yytext); + } + unput('('); + return T_SYMBOL; + } + } +{WORD} { + yylval.sym = symtable_get(yytext); + if (yylval.sym->type == MACRO) { + expand_macro(yylval.sym); + } else { + return T_SYMBOL; + } + } +. { snprintf(buf, sizeof(buf), "Invalid character " "'%c'", yytext[0]); stop(buf, EX_DATAERR); @@ -327,6 +483,92 @@ yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); yylineno = 1; yyfilename = strdup(file_name); +} + +static void next_substitution(struct symbol *mac_symbol, const char *body_pos, + const char **next_match, + struct macro_arg **match_marg, regmatch_t *match); + +void +expand_macro(struct symbol *macro_symbol) +{ + struct macro_arg *marg; + struct macro_arg *match_marg; + const char *body_head; + const char *body_pos; + const char *next_match; + + /* + * Due to the nature of unput, we must work + * backwards through the macro body performing + * any expansions. + */ + body_head = macro_symbol->info.macroinfo->body; + body_pos = body_head + strlen(body_head); + while (body_pos > body_head) { + regmatch_t match; + + next_match = body_head; + match_marg = NULL; + next_substitution(macro_symbol, body_pos, &next_match, + &match_marg, &match); + + /* Put back everything up until the replacement. */ + while (body_pos > next_match) + unput(*--body_pos); + + /* Perform the replacement. */ + if (match_marg != NULL) { + const char *strp; + + next_match = match_marg->replacement_text; + strp = next_match + strlen(next_match); + while (strp > next_match) + unput(*--strp); + + /* Skip past the unexpanded macro arg. */ + body_pos -= match.rm_eo - match.rm_so; + } + } + + /* Cleanup replacement text. */ + STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { + free(marg->replacement_text); + } +} + +/* + * Find the next substitution in the macro working backwards from + * body_pos until the beginning of the macro buffer. next_match + * should be initialized to the beginning of the macro buffer prior + * to calling this routine. + */ +static void +next_substitution(struct symbol *mac_symbol, const char *body_pos, + const char **next_match, struct macro_arg **match_marg, + regmatch_t *match) +{ + regmatch_t matches[2]; + struct macro_arg *marg; + const char *search_pos; + int retval; + + do { + search_pos = *next_match; + + STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { + + retval = regexec(&marg->arg_regex, search_pos, 2, + matches, 0); + if (retval == 0 + && (matches[1].rm_eo + search_pos) <= body_pos + && (matches[1].rm_eo + search_pos) > *next_match) { + *match = matches[1]; + *next_match = match->rm_eo + search_pos; + *match_marg = marg; + } + } + } while (search_pos != *next_match); } int diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Sat Mar 30 22:55:35 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#9 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -49,6 +49,7 @@ #include #endif #include +#include #include #include #include @@ -318,12 +319,15 @@ symlist_t constants; symlist_t download_constants; symlist_t aliases; + symlist_t exported_labels; + u_int i; SLIST_INIT(®isters); SLIST_INIT(&masks); SLIST_INIT(&constants); SLIST_INIT(&download_constants); SLIST_INIT(&aliases); + SLIST_INIT(&exported_labels); if (symtable != NULL) { DBT key; @@ -345,10 +349,8 @@ symlist_add(&masks, cursym, SYMLIST_SORT); break; case CONST: - if (cursym->info.cinfo->define == FALSE) { - symlist_add(&constants, cursym, - SYMLIST_INSERT_HEAD); - } + symlist_add(&constants, cursym, + SYMLIST_INSERT_HEAD); break; case DOWNLOAD_CONST: symlist_add(&download_constants, cursym, @@ -358,6 +360,12 @@ symlist_add(&aliases, cursym, SYMLIST_INSERT_HEAD); break; + case LABEL: + if (cursym->info.linfo->exported == 0) + break; + symlist_add(&exported_labels, cursym, + SYMLIST_INSERT_HEAD); + break; default: break; } @@ -403,7 +411,7 @@ %s */\n", versions); while (SLIST_FIRST(®isters) != NULL) { symbol_node_t *curnode; - u_int8_t value; + u_int value; char *tab_str; char *tab_str2; @@ -463,7 +471,7 @@ fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); - while (SLIST_FIRST(&download_constants) != NULL) { + for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { symbol_node_t *curnode; curnode = SLIST_FIRST(&download_constants); @@ -471,6 +479,20 @@ fprintf(ofile, "#define\t%-8s\t0x%02x\n", curnode->symbol->name, curnode->symbol->info.cinfo->value); + free(curnode); + } + fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); + + fprintf(ofile, "\n\n/* Exported Labels */\n"); + + while (SLIST_FIRST(&exported_labels) != NULL) { + symbol_node_t *curnode; + + curnode = SLIST_FIRST(&exported_labels); + SLIST_REMOVE_HEAD(&exported_labels, links); + fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.linfo->address); free(curnode); } } diff -urN linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h --- linux-2.4.18/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Sat Mar 30 22:55:35 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#6 $ + * $Id$ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11 2000/09/22 22:19:55 gibbs Exp $ */ @@ -58,8 +58,9 @@ CONST, DOWNLOAD_CONST, LABEL, - CONDITIONAL -}symtype; + CONDITIONAL, + MACRO +} symtype; typedef enum { RO = 0x01, @@ -68,10 +69,11 @@ }amode_t; struct reg_info { - u_int8_t address; + u_int address; int size; amode_t mode; u_int8_t valid_bitmask; + u_int8_t modes; int typecheck_masks; }; @@ -83,8 +85,8 @@ }; struct const_info { - u_int8_t value; - int define; + u_int value; + int define; }; struct alias_info { @@ -93,12 +95,26 @@ struct label_info { int address; + int exported; }; struct cond_info { int func_num; }; +struct macro_arg { + STAILQ_ENTRY(macro_arg) links; + regex_t arg_regex; + char *replacement_text; +}; +STAILQ_HEAD(macro_arg_list, macro_arg) args; + +struct macro_info { + struct macro_arg_list args; + int narg; + const char* body; +}; + typedef struct expression_info { symlist_t referenced_syms; int value; @@ -108,12 +124,13 @@ char *name; symtype type; union { - struct reg_info *rinfo; - struct mask_info *minfo; + struct reg_info *rinfo; + struct mask_info *minfo; struct const_info *cinfo; struct alias_info *ainfo; struct label_info *linfo; - struct cond_info *condinfo; + struct cond_info *condinfo; + struct macro_info *macroinfo; }info; } symbol_t; diff -urN linux-2.4.18/drivers/scsi/aic7xxx/cam.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/cam.h --- linux-2.4.18/drivers/scsi/aic7xxx/cam.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/cam.h Sat Mar 30 22:55:35 2002 @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/cam.h#11 $ + * $Id$ */ #ifndef _AIC7XXX_CAM_H diff -urN linux-2.4.18/drivers/scsi/aic7xxx/scsi_message.h linux-2.4.19-pre5/drivers/scsi/aic7xxx/scsi_message.h --- linux-2.4.18/drivers/scsi/aic7xxx/scsi_message.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/aic7xxx/scsi_message.h Sat Mar 30 22:55:35 2002 @@ -46,7 +46,7 @@ #define MSG_IDENTIFY_DISCFLAG 0x40 #define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) #define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) -#define MSG_IDENTIFY_LUNMASK 0x03F +#define MSG_IDENTIFY_LUNMASK 0x3F /* Extended messages (opcode and length) */ #define MSG_EXT_SDTR 0x01 @@ -60,6 +60,11 @@ #define MSG_EXT_PPR 0x04 /* SPI3 */ #define MSG_EXT_PPR_LEN 0x06 -#define MSG_EXT_PPR_QAS_REQ 0x04 -#define MSG_EXT_PPR_DT_REQ 0x02 +#define MSG_EXT_PPR_PCOMP_EN 0x80 +#define MSG_EXT_PPR_RTI 0x40 +#define MSG_EXT_PPR_RD_STRM 0x20 +#define MSG_EXT_PPR_WR_FLOW 0x10 +#define MSG_EXT_PPR_HOLD_MCS 0x08 +#define MSG_EXT_PPR_QAS_REQ 0x04 +#define MSG_EXT_PPR_DT_REQ 0x02 #define MSG_EXT_PPR_IU_REQ 0x01 diff -urN linux-2.4.18/drivers/scsi/atari_NCR5380.c linux-2.4.19-pre5/drivers/scsi/atari_NCR5380.c --- linux-2.4.18/drivers/scsi/atari_NCR5380.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/atari_NCR5380.c Sat Mar 30 22:55:35 2002 @@ -644,10 +644,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { - NULL, /* next */ - 0, /* sync */ - (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) diff -urN linux-2.4.18/drivers/scsi/atari_scsi.c linux-2.4.19-pre5/drivers/scsi/atari_scsi.c --- linux-2.4.18/drivers/scsi/atari_scsi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/atari_scsi.c Sat Mar 30 22:55:35 2002 @@ -1144,3 +1144,5 @@ static Scsi_Host_Template driver_template = ATARI_SCSI; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/blz1230.c linux-2.4.19-pre5/drivers/scsi/blz1230.c --- linux-2.4.18/drivers/scsi/blz1230.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/blz1230.c Sat Mar 30 22:55:35 2002 @@ -296,3 +296,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/blz2060.c linux-2.4.19-pre5/drivers/scsi/blz2060.c --- linux-2.4.18/drivers/scsi/blz2060.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/blz2060.c Sat Mar 30 22:55:35 2002 @@ -254,3 +254,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/cpqfcTSstructs.h linux-2.4.19-pre5/drivers/scsi/cpqfcTSstructs.h --- linux-2.4.18/drivers/scsi/cpqfcTSstructs.h Sat Mar 16 21:13:23 2002 +++ linux-2.4.19-pre5/drivers/scsi/cpqfcTSstructs.h Sat Mar 30 22:55:35 2002 @@ -27,7 +27,7 @@ #define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \ for( wait_time=jiffies + (secs*HZ); \ - wait_time > jiffies ;) ; } + time_before(jiffies, wait_time) ;) ; } #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) // don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c diff -urN linux-2.4.18/drivers/scsi/cyberstorm.c linux-2.4.19-pre5/drivers/scsi/cyberstorm.c --- linux-2.4.18/drivers/scsi/cyberstorm.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/cyberstorm.c Sat Mar 30 22:55:35 2002 @@ -320,3 +320,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/cyberstormII.c linux-2.4.19-pre5/drivers/scsi/cyberstormII.c --- linux-2.4.18/drivers/scsi/cyberstormII.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/cyberstormII.c Sat Mar 30 22:55:35 2002 @@ -271,3 +271,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/eata.c linux-2.4.19-pre5/drivers/scsi/eata.c --- linux-2.4.18/drivers/scsi/eata.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/eata.c Sat Mar 30 22:55:29 2002 @@ -1,6 +1,9 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 01 Jan 2002 Rev. 6.50 for linux 2.4.16 + * + Use the dynamic DMA mapping API. + * * 1 May 2001 Rev. 6.05 for linux 2.4.4 * + Clean up all pci related routines. * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) @@ -220,7 +223,7 @@ * This driver is based on the CAM (Common Access Method Committee) * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. * - * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -438,13 +441,6 @@ #include #include -#define SPIN_FLAGS unsigned long spin_flags; -#define SPIN_LOCK spin_lock_irq(&io_request_lock); -#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags); -#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock); -#define SPIN_UNLOCK_RESTORE \ - spin_unlock_irqrestore(&io_request_lock, spin_flags); - /* Subversion values */ #define ISA 0 #define ESA 1 @@ -638,7 +634,7 @@ u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ u_int32_t cpp_index; /* Index of address to be returned in sp */ u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ - u_int32_t sp_addr; /* Address where sp is DMA'ed when cp completes */ + u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; @@ -660,7 +656,11 @@ unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ - struct mssp sp[2]; /* Returned status for this board */ + unsigned char is_pci; /* TRUE is bus type is PCI */ + struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ + struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ + dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ + struct mssp sp; /* Local copy of sp buffer */ }; static struct Scsi_Host *sh[MAX_BOARDS + 1]; @@ -697,10 +697,11 @@ #define HD(board) ((struct hostdata *) &sh[board]->hostdata) #define BN(board) (HD(board)->board_name) -#define H2DEV(x) htonl(x) -#define DEV2H(x) H2DEV(x) +/* Device is Big Endian */ +#define H2DEV(x) cpu_to_be32(x) +#define DEV2H(x) be32_to_cpu(x) + #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) -#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); @@ -859,7 +860,7 @@ static inline int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) { - unsigned char irq, dma_channel, subversion, i; + unsigned char irq, dma_channel, subversion, i, is_pci = FALSE; unsigned char protocol_rev; struct eata_info info; char *bus_type, dma_name[16], tag_type; @@ -911,10 +912,12 @@ if (!setup_done && j > 0 && j <= MAX_PCI) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) { @@ -927,6 +930,7 @@ } else if (port_base > MAX_ISA_ADDR) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else { @@ -967,7 +971,13 @@ printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", name, irq); - pdev = get_pci_dev(port_base); + if (is_pci) { + pdev = get_pci_dev(port_base); + if (!pdev) + printk("%s: warning, failed to get pci_dev structure.\n", name); + } + else + pdev = NULL; if (pdev && (irq != pdev->irq)) { printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq); @@ -997,7 +1007,7 @@ /* Set board configuration */ memset((char *)&config, 0, sizeof(struct eata_config)); - config.len = (ushort) htons((ushort)510); + config.len = (ushort) cpu_to_be16((ushort)510); config.ocena = TRUE; if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) { @@ -1026,14 +1036,16 @@ sh[j]->n_io_port = REGION_SIZE; sh[j]->dma_channel = dma_channel; sh[j]->irq = irq; - sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size); + sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size); sh[j]->this_id = (ushort) info.host_addr[3]; - sh[j]->can_queue = (ushort) ntohs(info.queue_size); + sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; sh[j]->select_queue_depths = select_queue_depths; memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->subversion = subversion; HD(j)->protocol_rev = protocol_rev; + HD(j)->is_pci = is_pci; + HD(j)->pdev = pdev; HD(j)->board_number = j; if (HD(j)->subversion == ESA) @@ -1042,14 +1054,14 @@ unsigned long flags; scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; - + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); release_dma_lock(flags); - + } strcpy(BN(j), name); @@ -1098,6 +1110,13 @@ return FALSE; } + if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, + sizeof(struct mssp), &HD(j)->sp_dma_addr))) { + printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); + eata2x_release(sh[j]); + return FALSE; + } + if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) max_queue_depth = MAX_TAGGED_CMD_PER_LUN; @@ -1112,7 +1131,7 @@ else tag_type = 'n'; if (j == 0) { - printk("EATA/DMA 2.0x: Copyright (C) 1994-2001 Dario Ballabio.\n"); + printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n"); printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n", driver_name, tag_type, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), YESNO(ext_tran)); @@ -1148,7 +1167,11 @@ info.pci, info.eisa, info.raidnum); #endif - if (pdev) pci_set_master(pdev); + if (HD(j)->pdev) { + pci_set_master(HD(j)->pdev); + if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff)) + printk("%s: warning, pci_set_dma_mask failed.\n", BN(j)); + } return TRUE; } @@ -1275,25 +1298,92 @@ return j; } -static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) { - unsigned int k; +static inline void map_dma(unsigned int i, unsigned int j) { + unsigned int k, count, pci_dir; struct scatterlist *sgpnt; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (SCpnt->sense_buffer) + cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, + sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + + cpp->sense_len = sizeof SCpnt->sense_buffer; + + if (!SCpnt->use_sg) { + + if (!SCpnt->request_bufflen) + cpp->data_address = V2DEV(SCpnt->request_buffer); + + else if (SCpnt->request_buffer) + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, + SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); + + cpp->data_len = H2DEV(SCpnt->request_bufflen); + return; + } sgpnt = (struct scatterlist *) SCpnt->request_buffer; + count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir); - for (k = 0; k < SCpnt->use_sg; k++) { - cpp->sglist[k].address = V2DEV(sgpnt[k].address); - cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length); + for (k = 0; k < count; k++) { + cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); + cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); } + cpp->sg = TRUE; cpp->data_address = V2DEV(cpp->sglist); cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - unsigned int i, j, k; +static void unmap_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; struct mscp *cpp; - struct mssp *spp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static void sync_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { + unsigned int k; static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, @@ -1304,9 +1394,53 @@ static const unsigned char data_none_cmds[] = { 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 }; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; + SCpnt = cpp->SCpnt; + + if (SCpnt->sc_data_direction == SCSI_DATA_READ) { + cpp->din = TRUE; + cpp->dout = FALSE; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) { + cpp->din = FALSE; + cpp->dout = TRUE; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) { + cpp->din = FALSE; + cpp->dout = FALSE; + return; + } + + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); + + for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->dout = TRUE; + break; + } + + if ((cpp->din = !cpp->dout)) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->din = FALSE; + break; + } + +} + +static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { + unsigned int i, j, k; + struct mscp *cpp; + /* j is the board number */ j = ((struct hostdata *) SCpnt->host->hostdata)->board_number; @@ -1338,11 +1472,8 @@ memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); - /* Set pointer to status packet structure */ - spp = &HD(j)->sp[0]; - - /* The EATA protocol uses Big Endian format */ - cpp->sp_addr = V2DEV(spp); + /* Set pointer to status packet structure, Big Endian format */ + cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr); SCpnt->scsi_done = done; cpp->cpp_index = i; @@ -1352,19 +1483,6 @@ BN(j), i, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->dout = TRUE; - break; - } - - if ((cpp->din = !cpp->dout)) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->din = FALSE; - break; - } - cpp->reqsen = TRUE; cpp->dispri = TRUE; #if 0 @@ -1375,8 +1493,13 @@ cpp->target = SCpnt->target; cpp->lun = SCpnt->lun; cpp->SCpnt = SCpnt; - cpp->sense_addr = V2DEV(SCpnt->sense_buffer); - cpp->sense_len = sizeof SCpnt->sense_buffer; + memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + /* Use data transfer direction SCpnt->sc_data_direction */ + scsi_to_dev_dir(i, j); + + /* Map DMA buffers and SG list */ + map_dma(i, j); if (SCpnt->device->tagged_queue) { @@ -1396,17 +1519,6 @@ cpp->mess[1] = SCpnt->device->current_tag++; } - if (SCpnt->use_sg) { - cpp->sg = TRUE; - build_sg_list(cpp, SCpnt); - } - else { - cpp->data_address = V2DEV(SCpnt->request_buffer); - cpp->data_len = H2DEV(SCpnt->request_bufflen); - } - - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; @@ -1416,6 +1528,7 @@ /* Send control packet to the board */ if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); @@ -1472,6 +1585,7 @@ printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { + unmap_dma(i, j); SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", @@ -1493,6 +1607,7 @@ } if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { + unmap_dma(i, j); SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; @@ -1589,16 +1704,19 @@ #endif HD(j)->in_reset = TRUE; - SPIN_UNLOCK + + spin_unlock_irq(&io_request_lock); time = jiffies; while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - SPIN_LOCK + spin_lock_irq(&io_request_lock); + printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); for (i = 0; i < sh[j]->can_queue; i++) { if (HD(j)->cp_stat[i] == IN_RESET) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1611,6 +1729,7 @@ else if (HD(j)->cp_stat[i] == ABORTING) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1823,7 +1942,7 @@ static inline void ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg; - struct mssp *dspp, *spp; + struct mssp *spp; struct mscp *cpp; if (sh[j]->irq != irq) @@ -1845,14 +1964,13 @@ return; } - dspp = &HD(j)->sp[0]; - spp = &HD(j)->sp[1]; + spp = &HD(j)->sp; /* Make a local copy just before clearing the interrupt indication */ - memcpy(spp, dspp, sizeof(struct mssp)); + memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp)); /* Clear the completion flag and cp pointer on the dynamic copy of sp */ - memset(dspp, 0, sizeof(struct mssp)); + memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp)); /* Read the status register to clear the interrupt indication */ reg = inb(sh[j]->io_port + REG_STATUS); @@ -1910,6 +2028,8 @@ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); + sync_dma(i, j); + if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); @@ -1987,6 +2107,7 @@ #else status = DID_BUS_BUSY << 16; #endif + HD(j)->retries++; HD(j)->last_retried_pid = SCpnt->pid; } @@ -2023,6 +2144,8 @@ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, reg, HD(j)->iocount); + unmap_dma(i, j); + /* Set the command state to inactive */ SCpnt->host_scribble = NULL; @@ -2036,14 +2159,14 @@ static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) { unsigned int j; - SPIN_FLAGS + unsigned long spin_flags; /* Check if the interrupt must be processed by this handler */ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return; - SPIN_LOCK_SAVE + spin_lock_irqsave(&io_request_lock, spin_flags); ihdlr(irq, j); - SPIN_UNLOCK_RESTORE + spin_unlock_irqrestore(&io_request_lock, spin_flags); } int eata2x_release(struct Scsi_Host *shpnt) { @@ -2054,13 +2177,15 @@ 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]); - } + 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); + if (HD(j)->sp_cpu_addr) + pci_free_consistent(HD(j)->pdev, sizeof(struct mssp), + HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr); + free_irq(sh[j]->irq, &sha[j]); if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); @@ -2077,4 +2202,4 @@ #ifndef MODULE __setup("eata=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/eata.h linux-2.4.19-pre5/drivers/scsi/eata.h --- linux-2.4.18/drivers/scsi/eata.h Sun Feb 17 01:23:27 2002 +++ linux-2.4.19-pre5/drivers/scsi/eata.h Sat Mar 30 22:55:29 2002 @@ -13,7 +13,7 @@ int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "6.05.00" +#define EATA_VERSION "6.50.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ diff -urN linux-2.4.18/drivers/scsi/fastlane.c linux-2.4.19-pre5/drivers/scsi/fastlane.c --- linux-2.4.18/drivers/scsi/fastlane.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/fastlane.c Sat Mar 30 22:55:35 2002 @@ -372,3 +372,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/gdth_proc.c linux-2.4.19-pre5/drivers/scsi/gdth_proc.c --- linux-2.4.18/drivers/scsi/gdth_proc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/gdth_proc.c Sat Mar 30 22:55:40 2002 @@ -1464,7 +1464,7 @@ timer_table[SCSI_TIMER].expires = jiffies + timeout; timer_active |= 1 << SCSI_TIMER; } else { - if (jiffies + timeout < timer_table[SCSI_TIMER].expires) + if (time_before(jiffies + timeout, timer_table[SCSI_TIMER].expires)) timer_table[SCSI_TIMER].expires = jiffies + timeout; } } diff -urN linux-2.4.18/drivers/scsi/gvp11.c linux-2.4.19-pre5/drivers/scsi/gvp11.c --- linux-2.4.18/drivers/scsi/gvp11.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/gvp11.c Sat Mar 30 22:55:35 2002 @@ -372,3 +372,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/ide-scsi.c linux-2.4.19-pre5/drivers/scsi/ide-scsi.c --- linux-2.4.18/drivers/scsi/ide-scsi.c Sun Dec 23 16:23:47 2001 +++ linux-2.4.19-pre5/drivers/scsi/ide-scsi.c Sat Mar 30 22:55:35 2002 @@ -529,28 +529,35 @@ return 0; } +int idescsi_reinit(ide_drive_t *drive); + /* * IDE subdriver functions, registered with ide.c */ static ide_driver_t idescsi_driver = { - "ide-scsi", /* name */ - IDESCSI_VERSION, /* version */ - ide_scsi, /* media */ - 0, /* busy */ - 1, /* supports_dma */ - 0, /* supports_dsc_overlap */ - idescsi_cleanup, /* cleanup */ - idescsi_do_request, /* do_request */ - idescsi_end_request, /* end_request */ - NULL, /* ioctl */ - idescsi_open, /* open */ - idescsi_ide_release, /* release */ - NULL, /* media_change */ - NULL, /* revalidate */ - NULL, /* pre_reset */ - NULL, /* capacity */ - NULL, /* special */ - NULL /* proc */ + name: "ide-scsi", + version: IDESCSI_VERSION, + media: ide_scsi, + busy: 0, + supports_dma: 1, + supports_dsc_overlap: 0, + cleanup: idescsi_cleanup, + standby: NULL, + flushcache: NULL, + do_request: idescsi_do_request, + end_request: idescsi_end_request, + ioctl: NULL, + open: idescsi_open, + release: idescsi_ide_release, + media_change: NULL, + revalidate: NULL, + pre_reset: NULL, + capacity: NULL, + special: NULL, + proc: NULL, + reinit: idescsi_reinit, + ata_prebuilder: NULL, + atapi_prebuilder: NULL, }; int idescsi_init (void); @@ -561,6 +568,43 @@ NULL }; +int idescsi_reinit (ide_drive_t *drive) +{ +#if 0 + idescsi_scsi_t *scsi; + byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; + int i, failed, id; + + if (!idescsi_initialized) + return 0; + for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++) + idescsi_drives[i] = NULL; + + MOD_INC_USE_COUNT; + for (i = 0; media[i] != 255; i++) { + failed = 0; + while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { + + if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { + printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); + continue; + } + if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) { + printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); + kfree (scsi); + continue; + } + for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); + idescsi_setup (drive, scsi, id); + failed--; + } + } + ide_register_module(&idescsi_module); + MOD_DEC_USE_COUNT; +#endif + return 0; +} + /* * idescsi_init will register the driver for each scsi. */ @@ -591,7 +635,7 @@ continue; } for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); - idescsi_setup (drive, scsi, id); + idescsi_setup (drive, scsi, id); failed--; } } diff -urN linux-2.4.18/drivers/scsi/ips.c linux-2.4.19-pre5/drivers/scsi/ips.c --- linux-2.4.18/drivers/scsi/ips.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/ips.c Sat Mar 30 22:55:29 2002 @@ -191,6 +191,7 @@ #ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s"); + MODULE_LICENSE("GPL"); #endif /* diff -urN linux-2.4.18/drivers/scsi/mac_NCR5380.c linux-2.4.19-pre5/drivers/scsi/mac_NCR5380.c --- linux-2.4.18/drivers/scsi/mac_NCR5380.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/mac_NCR5380.c Sat Mar 30 22:55:35 2002 @@ -662,10 +662,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { - NULL, /* next */ - 0, /* sync */ - (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) diff -urN linux-2.4.18/drivers/scsi/mac_esp.c linux-2.4.19-pre5/drivers/scsi/mac_esp.c --- linux-2.4.18/drivers/scsi/mac_esp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/mac_esp.c Sat Mar 30 22:55:35 2002 @@ -713,3 +713,5 @@ static Scsi_Host_Template driver_template = SCSI_MAC_ESP; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/oktagon_esp.c linux-2.4.19-pre5/drivers/scsi/oktagon_esp.c --- linux-2.4.18/drivers/scsi/oktagon_esp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/oktagon_esp.c Sat Mar 30 22:55:35 2002 @@ -77,7 +77,9 @@ long oktag_to_io(long *paddr, long *addr, long len); long oktag_from_io(long *addr, long *paddr, long len); -static struct tq_struct tq_fake_dma = { NULL, 0, dma_commit, NULL }; +static struct tq_struct tq_fake_dma = { + routine: dma_commit, +}; #define DMA_MAXTRANSFER 0x8000 @@ -589,3 +591,5 @@ #endif return 1; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/qlogicfas.c linux-2.4.19-pre5/drivers/scsi/qlogicfas.c --- linux-2.4.18/drivers/scsi/qlogicfas.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/qlogicfas.c Sat Mar 30 22:55:40 2002 @@ -271,11 +271,11 @@ int i,k; k = 0; i = jiffies + WATCHDOG; - while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) { + while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) { barrier(); cpu_relax(); } - if (i <= jiffies) + if (time_after_eq(jiffies, i)) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -405,8 +405,8 @@ } /*** Enter Status (and Message In) Phase ***/ k = jiffies + WATCHDOG; - while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if ( k <= jiffies ) { + while ( time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( time_after_eq(jiffies, k) ) { ql_zap(); return (DID_TIME_OUT << 16); } diff -urN linux-2.4.18/drivers/scsi/qlogicfc.c linux-2.4.19-pre5/drivers/scsi/qlogicfc.c --- linux-2.4.18/drivers/scsi/qlogicfc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/qlogicfc.c Sat Mar 30 22:55:40 2002 @@ -803,7 +803,7 @@ outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); isp2x00_enable_irqs(host); /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) { + for (wait_time = jiffies + 10 * HZ; time_before(jiffies, wait_time) && hostdata->adapter_state == AS_LOOP_DOWN;) { barrier(); cpu_relax(); } @@ -820,7 +820,7 @@ some time before recognizing it is attached to a fabric */ #if ISP2x00_FABRIC - for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) { + for (wait_time = jiffies + 5 * HZ; time_before(jiffies, wait_time);) { barrier(); cpu_relax(); } diff -urN linux-2.4.18/drivers/scsi/scsi.c linux-2.4.19-pre5/drivers/scsi/scsi.c --- linux-2.4.18/drivers/scsi/scsi.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/scsi.c Sat Mar 30 22:55:29 2002 @@ -156,7 +156,12 @@ */ extern void scsi_old_done(Scsi_Cmnd * SCpnt); extern void scsi_old_times_out(Scsi_Cmnd * SCpnt); +extern int scsi_old_reset(Scsi_Cmnd *SCpnt, unsigned int flag); +/* + * Private interface into the new error handling code. + */ +extern int scsi_new_reset(Scsi_Cmnd *SCpnt, unsigned int flag); /* * Function: scsi_initialize_queue() @@ -2723,6 +2728,102 @@ */ scsi_release_commandblocks(SDpnt); kfree(SDpnt); +} + +/* + * Function: scsi_reset_provider_done_command + * + * Purpose: Dummy done routine. + * + * Notes: Some low level drivers will call scsi_done and end up here, + * others won't bother. + * We don't want the bogus command used for the bus/device + * reset to find its way into the mid-layer so we intercept + * it here. + */ +static void +scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt) +{ +} + +/* + * Function: scsi_reset_provider + * + * Purpose: Send requested reset to a bus or device at any phase. + * + * Arguments: device - device to send reset to + * flag - reset type (see scsi.h) + * + * Returns: SUCCESS/FAILURE. + * + * Notes: This is used by the SCSI Generic driver to provide + * Bus/Device reset capability. + */ +int +scsi_reset_provider(Scsi_Device *dev, int flag) +{ + Scsi_Cmnd SC, *SCpnt = &SC; + int rtn; + + memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); + SCpnt->host = dev->host; + SCpnt->device = dev; + SCpnt->target = dev->id; + SCpnt->lun = dev->lun; + SCpnt->channel = dev->channel; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.waiting = NULL; + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->old_cmd_len = 0; + SCpnt->underflow = 0; + SCpnt->transfersize = 0; + SCpnt->resid = 0; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->host_scribble = NULL; + SCpnt->next = NULL; + SCpnt->state = SCSI_STATE_INITIALIZING; + SCpnt->owner = SCSI_OWNER_MIDLEVEL; + + memset(&SCpnt->cmnd, '\0', sizeof(SCpnt->cmnd)); + + SCpnt->scsi_done = scsi_reset_provider_done_command; + SCpnt->done = NULL; + SCpnt->reset_chain = NULL; + + SCpnt->buffer = NULL; + SCpnt->bufflen = 0; + SCpnt->request_buffer = NULL; + SCpnt->request_bufflen = 0; + + SCpnt->internal_timeout = NORMAL_TIMEOUT; + SCpnt->abort_reason = DID_ABORT; + + SCpnt->cmd_len = 0; + + SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; + SCpnt->sc_request = NULL; + SCpnt->sc_magic = SCSI_CMND_MAGIC; + + /* + * Sometimes the command can get back into the timer chain, + * so use the pid as an identifier. + */ + SCpnt->pid = 0; + + if (dev->host->hostt->use_new_eh_code) { + rtn = scsi_new_reset(SCpnt, flag); + } else { + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + rtn = scsi_old_reset(SCpnt, flag); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + scsi_delete_timer(SCpnt); + return rtn; } /* diff -urN linux-2.4.18/drivers/scsi/scsi.h linux-2.4.19-pre5/drivers/scsi/scsi.h --- linux-2.4.18/drivers/scsi/scsi.h Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/scsi.h Sat Mar 30 22:55:29 2002 @@ -849,6 +849,16 @@ current->state = TASK_RUNNING; \ }; } +/* + * old style reset request from external source + * (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c) + */ +#define SCSI_TRY_RESET_DEVICE 1 +#define SCSI_TRY_RESET_BUS 2 +#define SCSI_TRY_RESET_HOST 3 + +extern int scsi_reset_provider(Scsi_Device *, int); + #endif /* diff -urN linux-2.4.18/drivers/scsi/scsi_debug.c linux-2.4.19-pre5/drivers/scsi/scsi_debug.c --- linux-2.4.18/drivers/scsi/scsi_debug.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/scsi_debug.c Sat Mar 30 22:55:35 2002 @@ -14,7 +14,7 @@ * * D. Gilbert (dpg) work for MOD device test [20010421] * dpg, work for devfs large number of disks [20010809] - * dpg, make more generic [20011123] + * dpg, use vmalloc() more inquiry+mode_sense [20020302] */ #include @@ -45,7 +45,7 @@ #include #endif -static char scsi_debug_version_str[] = "Version: 0.57 (20011209)"; +static char scsi_debug_version_str[] = "Version: 0.58 (20020302)"; #ifndef SCSI_CMD_READ_16 #define SCSI_CMD_READ_16 0x88 @@ -59,22 +59,26 @@ #define DEF_DEV_SIZE_MB 8 #define DEF_FAKE_BLK0 0 +#define DEF_OPTS 0 +#define SCSI_DEBUG_OPT_NOISE 1 +#define SCSI_DEBUG_OPT_MEDIUM_ERR 2 + +#define OPT_MEDIUM_ERR_ADDR 0x1234 + static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS; +static int scsi_debug_opts = DEF_OPTS; #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) #define N_HEAD 8 #define N_SECTOR 32 -#define DISK_READONLY(TGT) (0) -#define DISK_REMOVEABLE(TGT) (0) +#define DEV_READONLY(TGT) (0) +#define DEV_REMOVEABLE(TGT) (0) #define DEVICE_TYPE(TGT) (TYPE_DISK); #define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1) static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024) -#define STORE_ELEM_ORDER 1 -#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER)) -#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1) /* default sector size is 512 bytes, 2**9 bytes */ #define POW2_SECT_SIZE 9 @@ -82,8 +86,6 @@ #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD)) -static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0; - /* Do not attempt to use a timer to simulate a real disk with latency */ /* Only use this in the actual kernel, not in the simulator. */ #define IMMEDIATE @@ -94,20 +96,14 @@ #define DISK_SPEED (HZ/10) /* 100ms */ #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER) #define SECT_SIZE_PER(TGT) SECT_SIZE -#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE) static int starts[] = {N_SECTOR, N_HEAD * N_SECTOR, /* Single cylinder */ N_HEAD * N_SECTOR * 4, 0 /* CAPACITY */, 0}; -static int npart = 0; -typedef struct scsi_debug_store_elem { - unsigned char * p; -} Sd_store_elem; - -static Sd_store_elem * store_arr = 0; +static unsigned char * fake_storep; typedef struct sdebug_dev_info { Scsi_Device * sdp; @@ -132,13 +128,18 @@ static volatile done_fct_t * do_done = 0; -struct Scsi_Host * SHpnt = NULL; +static struct Scsi_Host * SHpnt = NULL; +static int scsi_debug_inquiry(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip); +static int scsi_debug_mode_sense(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip); static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip); static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip); -static void scsi_debug_send_self_command(struct Scsi_Host * shpnt); static void scsi_debug_intr_handle(unsigned long); static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp); static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, @@ -157,101 +158,11 @@ #define SENSE_BUFF_LEN 32 static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN]; -#ifdef SCSI_DUMP -static void scsi_dump(Scsi_Cmnd * SCpnt, int flag) -{ - int i; - unsigned int *lpnt; - struct scatterlist *sgpnt = NULL; - printk("use_sg: %d", SCpnt->use_sg); - if (SCpnt->use_sg) { - sgpnt = (struct scatterlist *) SCpnt->buffer; - for (i = 0; i < SCpnt->use_sg; i++) { - lpnt = (int *) sgpnt[i].alt_address; - printk(":%p %p %d\n", sgpnt[i].alt_address, - sgpnt[i].address, sgpnt[i].length); - if (lpnt) - printk(" (Alt %x) ", lpnt[15]); - } - } else { - printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); - lpnt = (int *) SCpnt->request.buffer; - if (lpnt) - printk(" (Alt %x) ", lpnt[15]); - } - lpnt = (unsigned int *) SCpnt; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - } - printk("\n"); - if (flag == 0) - return; - lpnt = (unsigned int *) sgpnt[0].alt_address; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - } -#if 0 - printk("\n"); - lpnt = (unsigned int *) sgpnt[0].address; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - } - printk("\n"); -#endif - printk("DMA free %d sectors.\n", scsi_dma_free_sectors); -} -#endif - -static int made_block0 = 0; - -static void scsi_debug_mkblock0(unsigned char * buff, int bufflen, - Scsi_Cmnd * SCpnt) -{ - int i; - struct partition *p; - - memset(buff, 0, bufflen); - *((unsigned short *) (buff + 510)) = 0xAA55; - p = (struct partition *) (buff + 0x1be); - i = 0; - while (starts[i + 1]) { - int start_cyl, end_cyl; - - start_cyl = starts[i] / N_HEAD / N_SECTOR; - end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; - p->boot_ind = 0; - - p->head = (i == 0 ? 1 : 0); - p->sector = 1 | ((start_cyl >> 8) << 6); - p->cyl = (start_cyl & 0xff); - - p->end_head = N_HEAD - 1; - p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); - p->end_cyl = (end_cyl & 0xff); - - p->start_sect = starts[i]; - p->nr_sects = starts[i + 1] - starts[i]; - p->sys_ind = 0x83; /* Linux ext2 partition */ - p++; - i++; - } - if (!npart) - npart = i; - made_block0 = 1; - i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen; - memcpy(store_arr[0].p, buff, i); -} +static int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { - unchar *cmd = (unchar *) SCpnt->cmnd; + unsigned char *cmd = (unsigned char *) SCpnt->cmnd; int block; int upper_blk; unsigned char *buff; @@ -263,17 +174,12 @@ Sdebug_dev_info * devip = NULL; char * sbuff; -#ifdef CONFIG_SMP - /* - * The io_request_lock *must* be held at this point. - */ - if(! spin_is_locked(&io_request_lock)) - { - printk("Warning - io_request_lock is not held in " - "queuecommand\n"); - } -#endif - + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { + printk(KERN_INFO "scsi_debug: queue_command: cmd "); + for (i = 0, num = SCpnt->cmd_len; i < num; ++i) + printk("%02x ", cmd[i]); + printk(" use_sg=%d\n", SCpnt->use_sg); + } /* * If we are being notified of the mid-level reposessing a command * due to timeout, just return. @@ -282,14 +188,23 @@ return 0; } - buff = (unsigned char *) SCpnt->request_buffer; + if (SCpnt->use_sg) { /* just use first element */ + struct scatterlist *sgpnt = (struct scatterlist *) + SCpnt->request_buffer; + + buff = sgpnt[0].address; + bufflen = sgpnt[0].length; + /* READ and WRITE process scatterlist themselves */ + } + else + buff = (unsigned char *) SCpnt->request_buffer; /* * If a command comes for the ID of the host itself, just print * a silly message and return. */ if(target == 7) { - printk("How do you do!\n"); + printk(KERN_WARNING "How do you do!\n"); SCpnt->result = 0; done(SCpnt); return 0; @@ -303,7 +218,7 @@ #if 0 printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n", (int)SCpnt->device->host->host_no, (int)SCpnt->device->id, - SCpnt->device, (int)(unsigned char)*cmd); + SCpnt->device, (int)*cmd); #endif if (NULL == SCpnt->device->hostdata) { devip = devInfoReg(SCpnt->device); @@ -317,6 +232,13 @@ devip = SCpnt->device->hostdata; switch (*cmd) { + case INQUIRY: /* mandatory */ + scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, + bufflen, devip); + /* assume INQUIRY called first so setup max_cmd_len */ + if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) + SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; + break; case REQUEST_SENSE: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Request sense...\n")); if (devip) { @@ -354,23 +276,6 @@ } scsi_debug_errsts = 0; break; - case INQUIRY: /* mandatory */ - SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); - memset(buff, 0, bufflen); - buff[0] = DEVICE_TYPE(target); - buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; - /* Removable disk */ - buff[2] = 2; /* claim SCSI 2 */ - buff[4] = 36 - 5; - memcpy(&buff[8], "Linux ", 8); - memcpy(&buff[16], "scsi_debug ", 16); - memcpy(&buff[32], "0002", 4); - scsi_debug_errsts = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) - if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) - SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; -#endif - break; case SEND_DIAGNOSTIC: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n")); if (buff) @@ -378,7 +283,8 @@ scsi_debug_errsts = 0; break; case TEST_UNIT_READY: /* mandatory */ - SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); + SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", + buff, bufflen)); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; @@ -484,19 +390,15 @@ (done) (SCpnt); return 0; case MODE_SENSE: - /* - * Used to detect write protected status. - */ - scsi_debug_errsts = 0; - memset(buff, 0, 6); + case MODE_SENSE_10: + scsi_debug_errsts = + scsi_debug_mode_sense(cmd, target, buff, bufflen, devip); break; default: #if 0 - SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; -#else + printk(KERN_INFO "scsi_debug: Unsupported command, " + "opcode=0x%x\n", (int)cmd[0]); +#endif if (check_reset(SCpnt, devip)) { done(SCpnt); return 0; @@ -505,7 +407,6 @@ (CHECK_CONDITION << 1); mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14); break; -#endif } spin_lock_irqsave(&mailbox_lock, iflags); @@ -545,10 +446,11 @@ spin_unlock_irqrestore(&mailbox_lock, iflags); add_timer(&timeout[i]); if (!done) - printk("scsi_debug_queuecommand: done can't be NULL\n"); + printk(KERN_ERR "scsi_debug_queuecommand: " + "done can't be NULL\n"); #if 0 - printk("Sending command (%d %x %d %d)...", i, done, + printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies); #endif #endif @@ -556,6 +458,14 @@ return 0; } +static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg) +{ + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { + printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); + } + return -ENOTTY; +} + static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip) { if (devip->reset) { @@ -568,6 +478,190 @@ return 0; } +#define SDEBUG_MAX_INQ_SZ 58 + +static int scsi_debug_inquiry(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip) +{ + unsigned char pq_pdt; + unsigned char arr[SDEBUG_MAX_INQ_SZ]; + int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? + SDEBUG_MAX_INQ_SZ : bufflen; + + SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); + if (bufflen < cmd[4]) + printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d " + "< alloc_length=%d\n", bufflen, (int)cmd[4]); + memset(buff, 0, bufflen); + memset(arr, 0, SDEBUG_MAX_INQ_SZ); + pq_pdt = DEVICE_TYPE(target); + arr[0] = pq_pdt; + if (0x2 & cmd[1]) { /* CMDDT bit set */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + else if (0x1 & cmd[1]) { /* EVPD bit set */ + if (0 == cmd[2]) { /* supported vital product data pages */ + arr[3] = 1; + arr[4] = 0x80; /* ... only unit serial number */ + } + else if (0x80 == cmd[2]) { /* unit serial number */ + arr[1] = 0x80; + arr[3] = 4; + arr[4] = '1'; arr[5] = '2'; arr[6] = '3'; + arr[7] = '4'; + } + else { + /* Illegal request, invalid field in cdb */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + memcpy(buff, arr, min_len); + return 0; + } + /* drops through here for a standard inquiry */ + arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ + arr[2] = 3; /* claim SCSI 3 */ + arr[4] = SDEBUG_MAX_INQ_SZ - 5; + arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ + memcpy(&arr[8], "Linux ", 8); + memcpy(&arr[16], "scsi_debug ", 16); + memcpy(&arr[32], "0003", 4); + memcpy(buff, arr, min_len); + return 0; +} + +/* <> */ + +static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target) +{ /* Read-Write Error Recovery page for mode_sense */ + unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, + 5, 0, 0xff, 0xff}; + + memcpy(p, err_recov_pg, sizeof(err_recov_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(err_recov_pg) - 2); + return sizeof(err_recov_pg); +} + +static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target) +{ /* Disconnect-Reconnect page for mode_sense */ + unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + + memcpy(p, disconnect_pg, sizeof(disconnect_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(disconnect_pg) - 2); + return sizeof(disconnect_pg); +} + +static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target) +{ /* Caching page for mode_sense */ + unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; + + memcpy(p, caching_pg, sizeof(caching_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(caching_pg) - 2); + return sizeof(caching_pg); +} + +static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target) +{ /* Control mode page for mode_sense */ + unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b}; + + memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); + return sizeof(ctrl_m_pg); +} + + +#define SDEBUG_MAX_MSENSE_SZ 256 + +static int scsi_debug_mode_sense(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip) +{ + unsigned char dbd; + int pcontrol, pcode; + unsigned char dev_spec; + int alloc_len, msense_6, offset, len; + unsigned char * ap; + unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; + int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? + SDEBUG_MAX_MSENSE_SZ : bufflen; + + SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen)); + dbd = cmd[1] & 0x8; + pcontrol = (cmd[2] & 0xc0) >> 6; + pcode = cmd[2] & 0x3f; + msense_6 = (MODE_SENSE == cmd[0]); + alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[6]); + /* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d " + "msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, " + "msense_6, alloc_len); */ + if (bufflen < alloc_len) + printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d " + "< alloc_length=%d\n", bufflen, alloc_len); + memset(buff, 0, bufflen); + memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); + if (0x3 == pcontrol) { /* Saving values not supported */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; + if (msense_6) { + arr[2] = dev_spec; + offset = 4; + } + else { + arr[3] = dev_spec; + offset = 8; + } + ap = arr + offset; + + switch (pcode) { + case 0x1: /* Read-Write error recovery page, direct access */ + len = sdebug_err_recov_pg(ap, pcontrol, target); + offset += len; + break; + case 0x2: /* Disconnect-Reconnect page, all devices */ + len = sdebug_disconnect_pg(ap, pcontrol, target); + offset += len; + break; + case 0x8: /* Caching page, direct access */ + len = sdebug_caching_pg(ap, pcontrol, target); + offset += len; + break; + case 0xa: /* Control Mode page, all devices */ + len = sdebug_ctrl_m_pg(ap, pcontrol, target); + offset += len; + break; + case 0x3f: /* Read all Mode pages */ + len = sdebug_err_recov_pg(ap, pcontrol, target); + len += sdebug_disconnect_pg(ap + len, pcontrol, target); + len += sdebug_caching_pg(ap + len, pcontrol, target); + len += sdebug_ctrl_m_pg(ap + len, pcontrol, target); + offset += len; + break; + default: + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + if (msense_6) + arr[0] = offset - 1; + else { + offset -= 2; + arr[0] = (offset >> 8) & 0xff; + arr[1] = offset & 0xff; + } + memcpy(buff, arr, min_len); + return 0; +} + static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip) { @@ -592,11 +686,19 @@ usleep(delay); } #endif - + if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && + (block >= OPT_MEDIUM_ERR_ADDR) && + (block < (OPT_MEDIUM_ERR_ADDR + num))) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14); + /* claim unrecoverable read error */ + return 1; + } read_lock_irqsave(&sdebug_atomic_rw, iflags); sgcount = 0; nbytes = bufflen; - /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", + /* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", block, bufflen); */ if (SCpnt->use_sg) { sgcount = 0; @@ -606,30 +708,7 @@ } *errstsp = 0; do { - int resid, k, off, len, rem, blk; - unsigned char * bp; - - /* If this is block 0, then we want to read the partition - * table for this device. Let's make one up */ - if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) { - scsi_debug_mkblock0(buff, bufflen, SCpnt); - *errstsp = 0; - break; - } - bp = buff; - blk = block; - for (resid = bufflen; resid > 0; resid -= len) { - k = blk / SECT_PER_ELEM; - off = (blk % SECT_PER_ELEM) * SECT_SIZE; - rem = STORE_ELEM_SIZE - off; - len = (resid > rem) ? rem : resid; -/* printk("sdr: blk=%d k=%d off=%d rem=%d resid" - "=%d len=%d sgcount=%d\n", blk, k, - off, rem, resid, len, sgcount); */ - memcpy(bp, store_arr[k].p + off, len); - bp += len; - blk += len / SECT_SIZE; - } + memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen); #if 0 /* Simulate a disk change */ if (block == 0xfff0) { @@ -655,7 +734,8 @@ } } else if (nbytes > 0) - printk("sdebug_read: unexpected nbytes=%d\n", nbytes); + printk(KERN_WARNING "sdebug_read: unexpected " + "nbytes=%d\n", nbytes); } while (nbytes); read_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0; @@ -679,13 +759,6 @@ write_lock_irqsave(&sdebug_atomic_rw, iflags); sgcount = 0; -#ifdef SCSI_DUMP - if (block != *((unsigned long *) (buff + 60))) { - printk("%x %x :", block, *((unsigned long *) (buff + 60))); - scsi_dump(SCpnt, 1); - printk("Bad block written.\n"); - } -#endif nbytes = bufflen; if (SCpnt->use_sg) { sgcount = 0; @@ -695,20 +768,7 @@ } *errstsp = 0; do { - int resid, k, off, len, rem, blk; - unsigned char * bp; - - bp = buff; - blk = block; - for (resid = bufflen; resid > 0; resid -= len) { - k = blk / SECT_PER_ELEM; - off = (blk % SECT_PER_ELEM) * SECT_SIZE; - rem = STORE_ELEM_SIZE - off; - len = (resid > rem) ? rem : resid; - memcpy(store_arr[k].p + off, bp, len); - bp += len; - blk += len / SECT_SIZE; - } + memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen); nbytes -= bufflen; if (SCpnt->use_sg) { @@ -720,52 +780,13 @@ } } else if (nbytes > 0) - printk("sdebug_write: unexpected nbytes=%d\n", nbytes); + printk(KERN_WARNING "sdebug_write: " + "unexpected nbytes=%d\n", nbytes); } while (nbytes); write_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0; } -static void scsi_debug_send_self_command(struct Scsi_Host * shpnt) -{ - static unsigned char cmd[6] = - {TEST_UNIT_READY, 0, 0, 0, 0, 0}; - - Scsi_Request * scp; - Scsi_Device * sdev; - - printk("Allocating host dev\n"); - sdev = scsi_get_host_dev(shpnt); - if(sdev==NULL) - { - printk("Out of memory.\n"); - return; - } - - printk("Got %p. Allocating command block\n", sdev); - scp = scsi_allocate_request(sdev); - printk("Got %p\n", scp); - - if(scp==NULL) - { - printk("Out of memory.\n"); - goto bail; - } - - scp->sr_cmd_len = 6; - scp->sr_use_sg = 0; - - printk("Sending command\n"); - scsi_wait_req (scp, (void *) cmd, (void *) NULL, - 0, 100, 3); - - printk("Releasing command\n"); - scsi_release_request(scp); -bail: - printk("Freeing device\n"); - scsi_free_host_dev(sdev); -} - /* A "high" level interrupt handler. This should be called once per jiffy * to simulate a regular scsi disk. We use a timer to do this. */ @@ -784,18 +805,19 @@ SCint[indx] = NULL; if (!my_done) { - printk("scsi_debug_intr_handle: Unexpected interrupt\n"); + printk(KERN_ERR "scsi_debug_intr_handle: Unexpected " + "interrupt\n"); return; } #if 0 - printk("In intr_handle..."); - printk("...done %d %x %d %d\n", i, my_done, to, jiffies); - printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done); + printk(KERN_INFO "In intr_handle..."); + printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies); + printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done); #endif my_done(SCtmp); #if 0 - printk("Called done.\n"); + printk(KERN_INFO "Called done.\n"); #endif } @@ -803,39 +825,44 @@ static int do_init(void) { - int sz; + int sz = STORE_SIZE; starts[3] = CAPACITY; - sz = sizeof(Sd_store_elem) * STORE_ELEMENTS; - store_arr = kmalloc(sz, GFP_ATOMIC); - if (NULL == store_arr) + fake_storep = vmalloc(sz); + if (NULL == fake_storep) return 1; - memset(store_arr, 0, sz); + memset(fake_storep, 0, sz); + sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES; do_done = kmalloc(sz, GFP_ATOMIC); - if (NULL == do_done) { - kfree(store_arr); - return 1; - } + if (NULL == do_done) + goto out; memset((void *)do_done, 0, sz); + sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES; timeout = kmalloc(sz, GFP_ATOMIC); - if (NULL == timeout) { - kfree((void *)do_done); - kfree(store_arr); - return 1; - } + if (NULL == timeout) + goto out; memset(timeout, 0, sz); + sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES; SCint = kmalloc(sz, GFP_ATOMIC); - if (NULL == SCint) { - kfree(timeout); - kfree((void *)do_done); - kfree(store_arr); - return 1; - } + if (NULL == SCint) + goto out; memset(SCint, 0, sz); + return 0; + +out: + if (fake_storep) + vfree(fake_storep); + if (do_done) + kfree((void *)do_done); + if (timeout) + kfree(timeout); + if (SCint) + kfree(SCint); + return 1; } static void do_end(void) @@ -843,34 +870,31 @@ kfree(SCint); kfree(timeout); kfree((void *)do_done); - kfree(store_arr); + vfree(fake_storep); } -int scsi_debug_detect(Scsi_Host_Template * tpnt) +static int scsi_debug_detect(Scsi_Host_Template * tpnt) { - int k, num, sz; + int k, sz; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: detect\n"); if (0 == initialized) { ++initialized; sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs; devInfop = kmalloc(sz, GFP_ATOMIC); if (NULL == devInfop) { - printk("scsi_debug_detect: out of memory, 0.5\n"); + printk(KERN_ERR "scsi_debug_detect: out of " + "memory, 0.5\n"); return 0; } memset(devInfop, 0, sz); if (do_init()) { - printk("scsi_debug_detect: out of memory, 0\n"); + printk(KERN_ERR "scsi_debug_detect: out of memory" + ", 0\n"); return 0; } - for (k = 0; k < STORE_ELEMENTS; ++k) { - store_arr[k].p = (unsigned char *) - __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER); - if (0 == store_arr[k].p) - goto detect_err; - memset(store_arr[k].p, 0, STORE_ELEM_SIZE); - } for (k = 0; k < NUM_SENSE_BUFFS; ++k) sense_buffers[k][0] = 0x70; for (k = 0; k < NR_HOSTS_PRESENT; k++) { @@ -880,43 +904,21 @@ return NR_HOSTS_PRESENT; } else { - printk("scsi_debug_detect: called again\n"); + printk(KERN_WARNING "scsi_debug_detect: called again\n"); return 0; } - -detect_err: - num = k; - for (k = 0; k < STORE_ELEMENTS; ++k) { - if (0 != store_arr[k].p) { - free_pages((unsigned long)store_arr[k].p, - STORE_ELEM_ORDER); - store_arr[k].p = NULL; - } - } - printk("scsi_debug_detect: out of memory: %d out of %d bytes\n", - (int)(num * STORE_ELEM_SIZE), - (int)(scsi_debug_dev_size_mb * 1024 * 1024)); - return 0; } static int num_releases = 0; -int scsi_debug_release(struct Scsi_Host * hpnt) +static int scsi_debug_release(struct Scsi_Host * hpnt) { - int k; - + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: release\n"); scsi_unregister(hpnt); if (++num_releases != NR_HOSTS_PRESENT) return 0; - - for (k = 0; k < STORE_ELEMENTS; ++k) { - if (0 != store_arr[k].p) { - free_pages((unsigned long)store_arr[k].p, - STORE_ELEM_ORDER); - store_arr[k].p = NULL; - } - } do_end(); kfree(devInfop); return 0; @@ -966,8 +968,10 @@ sbuff[13] = asq; } -int scsi_debug_abort(Scsi_Cmnd * SCpnt) +static int scsi_debug_abort(Scsi_Cmnd * SCpnt) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: abort\n"); #if 1 ++num_aborts; return SUCCESS; @@ -991,8 +995,10 @@ #endif } -int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) +static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: biosparam\n"); /* int size = disk->capacity; */ info[0] = N_HEAD; info[1] = N_SECTOR; @@ -1002,36 +1008,13 @@ return 0; } -#if 0 -int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why) -{ - int i; - unsigned long iflags; - - void (*my_done) (Scsi_Cmnd *); - printk("Bus unlocked by reset - %d\n", why); - scsi_debug_lockup = 0; - for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { - if (SCint[i] == NULL) - continue; - SCint[i]->result = DID_RESET << 16; - my_done = do_done[i]; - my_done(SCint[i]); - spin_lock_irqsave(&mailbox_lock, iflags); - SCint[i] = NULL; - do_done[i] = NULL; - timeout[i].function = NULL; - spin_unlock_irqrestore(&mailbox_lock, iflags); - } - return SCSI_RESET_SUCCESS; -} -#endif - -int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) { Scsi_Device * sdp; int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: device_reset\n"); ++num_dev_resets; if (SCpnt && ((sdp = SCpnt->device))) { for (k = 0; k < scsi_debug_num_devs; ++k) { @@ -1044,12 +1027,14 @@ return SUCCESS; } -int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) { Scsi_Device * sdp; struct Scsi_Host * hp; int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: bus_reset\n"); ++num_bus_resets; if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { for (k = 0; k < scsi_debug_num_devs; ++k) { @@ -1060,10 +1045,12 @@ return SUCCESS; } -int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) { int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: host_reset\n"); ++num_host_resets; for (k = 0; k < scsi_debug_num_devs; ++k) devInfop[k].reset = 1; @@ -1081,7 +1068,7 @@ scsi_debug_num_devs = tmp; return 1; } else { - printk("scsi_debug_num_devs: usage scsi_debug_num_devs= " + printk(KERN_INFO "scsi_debug_num_devs: usage scsi_debug_num_devs= " "( can be from 1 to around 2000)\n"); return 0; } @@ -1098,13 +1085,32 @@ scsi_debug_dev_size_mb = tmp; return 1; } else { - printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=\n" + printk(KERN_INFO "scsi_debug_dev_size_mb: usage " + "scsi_debug_dev_size_mb=\n" " ( is number of MB ram shared by all devs\n"); return 0; } } __setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup); + +static int __init scsi_debug_opts_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_opts = tmp; + return 1; + } else { + printk(KERN_INFO "scsi_debug_opts: usage " + "scsi_debug_opts=\n" + " (1->noise, 2->medium_error, 4->... (can be or-ed)\n"); + return 0; + } +} + +__setup("scsi_debug_opts=", scsi_debug_opts_setup); #endif MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); @@ -1113,6 +1119,8 @@ MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate"); MODULE_PARM(scsi_debug_dev_size_mb, "i"); MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs"); +MODULE_PARM(scsi_debug_opts, "i"); +MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->..."); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); @@ -1123,8 +1131,9 @@ const char * scsi_debug_info(struct Scsi_Host * shp) { sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " - "dev_size_mb=%d\n", scsi_debug_version_str, - scsi_debug_num_devs, scsi_debug_dev_size_mb); + "dev_size_mb=%d, opts=0x%x", scsi_debug_version_str, + scsi_debug_num_devs, scsi_debug_dev_size_mb, + scsi_debug_opts); return sdebug_info; } @@ -1140,55 +1149,28 @@ orig_length = length; if (inout == 1) { - /* First check for the Signature */ - if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { - buffer += 11; - length -= 11; - - if (buffer[length - 1] == '\n') { - buffer[length - 1] = '\0'; - length--; - } - /* - * OK, we are getting some kind of command. Figure out - * what we are supposed to do here. Simulate bus lockups - * to test our reset capability. - */ - if (length == 4 && strncmp(buffer, "test", length) == 0) { - printk("Testing send self command %p\n", SHpnt); - scsi_debug_send_self_command(SHpnt); - return orig_length; - } - if (length == 6 && strncmp(buffer, "lockup", length) == 0) { - scsi_debug_lockup = 1; - return orig_length; - } - if (length == 6 && strncmp(buffer, "unlock", length) == 0) { - scsi_debug_lockup = 0; - return orig_length; - } - printk("Unknown command:%s (%d)\n", buffer, length); - } else - printk("Wrong Signature:%10s\n", (char *) buffer); - - return -EINVAL; + char arr[16]; + int minLen = length > 15 ? 15 : length; + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + memcpy(arr, buffer, minLen); + arr[minLen] = '\0'; + if (1 != sscanf(arr, "%d", &pos)) + return -EINVAL; + scsi_debug_opts = pos; + return length; } begin = 0; pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" - "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" - "cylinders=%d, heads=%d, sectors=%d\n" + "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n" + "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " "host_resets=%d\n", scsi_debug_version_str, scsi_debug_num_devs, - scsi_debug_dev_size_mb, SECT_SIZE, + scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, num_aborts, num_dev_resets, num_bus_resets, num_host_resets); -#if 0 - "This driver is not a real scsi driver, but it plays one on TV.\n" - "It is very handy for debugging specific problems because you\n" - "can simulate a variety of error conditions\n"); -#endif if (pos < offset) { len = 0; begin = pos; diff -urN linux-2.4.18/drivers/scsi/scsi_debug.h linux-2.4.19-pre5/drivers/scsi/scsi_debug.h --- linux-2.4.18/drivers/scsi/scsi_debug.h Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/scsi_debug.h Sat Mar 30 22:55:35 2002 @@ -3,24 +3,23 @@ #include #include -int scsi_debug_detect(Scsi_Host_Template *); -int scsi_debug_command(Scsi_Cmnd *); -int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int scsi_debug_abort(Scsi_Cmnd *); -int scsi_debug_biosparam(Disk *, kdev_t, int[]); -int scsi_debug_bus_reset(Scsi_Cmnd *); -int scsi_debug_dev_reset(Scsi_Cmnd *); -int scsi_debug_host_reset(Scsi_Cmnd *); -int scsi_debug_proc_info(char *, char **, off_t, int, int, int); -const char * scsi_debug_info(struct Scsi_Host *); +static int scsi_debug_detect(Scsi_Host_Template *); +/* static int scsi_debug_command(Scsi_Cmnd *); */ +static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int scsi_debug_abort(Scsi_Cmnd *); +static int scsi_debug_biosparam(Disk *, kdev_t, int[]); +static int scsi_debug_bus_reset(Scsi_Cmnd *); +static int scsi_debug_device_reset(Scsi_Cmnd *); +static int scsi_debug_host_reset(Scsi_Cmnd *); +static int scsi_debug_proc_info(char *, char **, off_t, int, int, int); +static const char * scsi_debug_info(struct Scsi_Host *); #ifndef NULL #define NULL 0 #endif /* - * Allow the driver to reject commands. Thus we accept only one, but - * and the mid-level will queue the remainder. + * This driver is written for the lk 2.4 series */ #define SCSI_DEBUG_CANQUEUE 255 @@ -32,6 +31,7 @@ info: scsi_debug_info, \ detect: scsi_debug_detect, \ release: scsi_debug_release, \ + ioctl: scsi_debug_ioctl, \ queuecommand: scsi_debug_queuecommand, \ eh_abort_handler: scsi_debug_abort, \ eh_bus_reset_handler: scsi_debug_bus_reset, \ diff -urN linux-2.4.18/drivers/scsi/scsi_error.c linux-2.4.19-pre5/drivers/scsi/scsi_error.c --- linux-2.4.18/drivers/scsi/scsi_error.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/scsi_error.c Sat Mar 30 22:55:35 2002 @@ -984,15 +984,24 @@ case DID_SOFT_ERROR: goto maybe_retry; + case DID_ERROR: + if (msg_byte(SCpnt->result) == COMMAND_COMPLETE && + status_byte(SCpnt->result) == RESERVATION_CONFLICT) + /* + * execute reservation conflict processing code + * lower down + */ + break; + /* FALLTHROUGH */ + case DID_BUS_BUSY: case DID_PARITY: - case DID_ERROR: goto maybe_retry; case DID_TIME_OUT: /* - * When we scan the bus, we get timeout messages for - * these commands if there is no device available. - * Other hosts report DID_NO_CONNECT for the same thing. + * When we scan the bus, we get timeout messages for + * these commands if there is no device available. + * Other hosts report DID_NO_CONNECT for the same thing. */ if ((SCpnt->cmnd[0] == TEST_UNIT_READY || SCpnt->cmnd[0] == INQUIRY)) { @@ -1009,13 +1018,7 @@ SCpnt->flags &= ~IS_RESETTING; goto maybe_retry; } - /* - * Examine the sense data to figure out how to proceed from here. - * If there is no sense data, we will be forced into the error - * handler thread, where we get to examine the thing in a lot more - * detail. - */ - return scsi_check_sense(SCpnt); + return SUCCESS; default: return FAILED; } @@ -1053,8 +1056,13 @@ */ return SUCCESS; case BUSY: - case RESERVATION_CONFLICT: goto maybe_retry; + + case RESERVATION_CONFLICT: + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + return SUCCESS; /* causes immediate I/O error */ default: return FAILED; } @@ -1957,6 +1965,45 @@ */ if (host->eh_notify != NULL) up(host->eh_notify); +} + +/* + * Function: scsi_new_reset + * + * Purpose: Send requested reset to a bus or device at any phase. + * + * Arguments: SCpnt - command ptr to send reset with (usually a dummy) + * flag - reset type (see scsi.h) + * + * Returns: SUCCESS/FAILURE. + * + * Notes: This is used by the SCSI Generic driver to provide + * Bus/Device reset capability. + */ +int +scsi_new_reset(Scsi_Cmnd *SCpnt, int flag) +{ + int rtn; + + switch(flag) { + case SCSI_TRY_RESET_DEVICE: + rtn = scsi_try_bus_device_reset(SCpnt, 0); + if (rtn == SUCCESS) + break; + /* FALLTHROUGH */ + case SCSI_TRY_RESET_BUS: + rtn = scsi_try_bus_reset(SCpnt); + if (rtn == SUCCESS) + break; + /* FALLTHROUGH */ + case SCSI_TRY_RESET_HOST: + rtn = scsi_try_host_reset(SCpnt); + break; + default: + rtn = FAILED; + } + + return rtn; } /* diff -urN linux-2.4.18/drivers/scsi/scsi_obsolete.c linux-2.4.19-pre5/drivers/scsi/scsi_obsolete.c --- linux-2.4.18/drivers/scsi/scsi_obsolete.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/scsi_obsolete.c Sat Mar 30 22:55:29 2002 @@ -503,11 +503,18 @@ break; case RESERVATION_CONFLICT: - printk("scsi%d, channel %d : RESERVATION CONFLICT performing" - " reset.\n", SCpnt->host->host_no, SCpnt->channel); - scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); - status = REDO; + /* + * Most HAs will return an error for + * this, so usually reservation + * conflicts will be processed under + * DID_ERROR code + */ + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + status = CMD_FINISHED; /* returns I/O error */ break; + default: printk("Internal error %s %d \n" "status byte = %d \n", __FILE__, @@ -557,6 +564,14 @@ exit = (DRIVER_HARD | SUGGEST_ABORT); break; case DID_ERROR: + if (msg_byte(result) == COMMAND_COMPLETE && + status_byte(result) == RESERVATION_CONFLICT) { + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + status = CMD_FINISHED; /* returns I/O error */ + break; + } status = MAYREDO; exit = (DRIVER_HARD | SUGGEST_ABORT); break; @@ -1098,6 +1113,34 @@ return rtn; } + +/* + * This function exports SCSI Bus, Device or Host reset capability + * and is for use with the SCSI generic driver. + */ +int +scsi_old_reset(Scsi_Cmnd *SCpnt, unsigned int flag) +{ + unsigned int old_flags = SCSI_RESET_SYNCHRONOUS; + + switch(flag) { + case SCSI_TRY_RESET_DEVICE: + /* no suggestion flags to add, device reset is default */ + break; + case SCSI_TRY_RESET_BUS: + old_flags |= SCSI_RESET_SUGGEST_BUS_RESET; + break; + case SCSI_TRY_RESET_HOST: + old_flags |= SCSI_RESET_SUGGEST_HOST_RESET; + break; + default: + return FAILED; + } + + if (scsi_reset(SCpnt, old_flags)) + return FAILED; + return SUCCESS; +} /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN linux-2.4.18/drivers/scsi/scsi_scan.c linux-2.4.19-pre5/drivers/scsi/scsi_scan.c --- linux-2.4.18/drivers/scsi/scsi_scan.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/scsi_scan.c Sat Mar 30 22:55:40 2002 @@ -23,21 +23,20 @@ #include #endif -/* The following devices are known not to tolerate a lun != 0 scan for - * one reason or another. Some will respond to all luns, others will - * lock up. +/* + * Flags for irregular SCSI devices that need special treatment */ - -#define BLIST_NOLUN 0x001 -#define BLIST_FORCELUN 0x002 -#define BLIST_BORKEN 0x004 -#define BLIST_KEY 0x008 -#define BLIST_SINGLELUN 0x010 -#define BLIST_NOTQ 0x020 -#define BLIST_SPARSELUN 0x040 -#define BLIST_MAX5LUN 0x080 -#define BLIST_ISDISK 0x100 -#define BLIST_ISROM 0x200 +#define BLIST_NOLUN 0x001 /* Don't scan for LUNs */ +#define BLIST_FORCELUN 0x002 /* Known to have LUNs, force sanning */ +#define BLIST_BORKEN 0x004 /* Flag for broken handshaking */ +#define BLIST_KEY 0x008 /* Needs to be unlocked by special command */ +#define BLIST_SINGLELUN 0x010 /* LUNs should better not be used in parallel */ +#define BLIST_NOTQ 0x020 /* Buggy Tagged Command Queuing */ +#define BLIST_SPARSELUN 0x040 /* Non consecutive LUN numbering */ +#define BLIST_MAX5LUN 0x080 /* Avoid LUNS >= 5 */ +#define BLIST_ISDISK 0x100 /* Treat as (removable) disk */ +#define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */ +#define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */ static void print_inquiry(unsigned char *data); static int scan_scsis_single(unsigned int channel, unsigned int dev, @@ -62,6 +61,10 @@ */ static struct dev_info device_list[] = { +/* The following devices are known not to tolerate a lun != 0 scan for + * one reason or another. Some will respond to all luns, others will + * lock up. + */ {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ @@ -75,7 +78,6 @@ {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* guess what? */ {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /*Responds to all lun */ - {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ @@ -126,6 +128,7 @@ {"INSITE", "Floptical F*8I", "*", BLIST_KEY}, {"INSITE", "I325VM", "*", BLIST_KEY}, {"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, @@ -152,7 +155,8 @@ {"DELL", "PV660F PSEUDO", "*", BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", "*", BLIST_SPARSELUN}, // Dell PV 530F {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F - {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN}, + {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // HP VA7400, by Alar Aun {"CMD", "CRA-7280", "*", BLIST_SPARSELUN}, // CMD RAID Controller {"CNSI", "G7324", "*", BLIST_SPARSELUN}, // Chaparral G7324 RAID {"CNSi", "G8324", "*", BLIST_SPARSELUN}, // Chaparral G8324 RAID @@ -164,6 +168,8 @@ {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, {"COMPAQ", "MSA1000", "*", BLIST_FORCELUN}, + {"HP", "C1557A", "*", BLIST_FORCELUN}, + {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN}, /* * Must be at end of list... @@ -434,8 +440,13 @@ scsi_result) && !sparse_lun) break; /* break means don't probe further for luns!=0 */ - if (SDpnt && (0 == lun)) - lun0_sl = SDpnt->scsi_level; + if (SDpnt && (0 == lun)) { + int bflags = get_device_flags (scsi_result); + if (bflags & BLIST_LARGELUN) + lun0_sl = SCSI_3; /* treat as SCSI 3 */ + else + lun0_sl = SDpnt->scsi_level; + } } /* for lun ends */ } /* if this_id != id ends */ } /* for dev ends */ diff -urN linux-2.4.18/drivers/scsi/scsi_syms.c linux-2.4.19-pre5/drivers/scsi/scsi_syms.c --- linux-2.4.18/drivers/scsi/scsi_syms.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/scsi_syms.c Sat Mar 30 22:55:29 2002 @@ -84,6 +84,11 @@ EXPORT_SYMBOL(scsi_deregister_blocked_host); /* + * This symbol is for the highlevel drivers (e.g. sg) only. + */ +EXPORT_SYMBOL(scsi_reset_provider); + +/* * These are here only while I debug the rest of the scsi stuff. */ EXPORT_SYMBOL(scsi_hostlist); diff -urN linux-2.4.18/drivers/scsi/sd.c linux-2.4.19-pre5/drivers/scsi/sd.c --- linux-2.4.18/drivers/scsi/sd.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/sd.c Sat Mar 30 22:55:35 2002 @@ -279,7 +279,7 @@ target = DEVICE_NR(dev); dpnt = &rscsi_disks[target]; - if (!dpnt) + if (!dpnt->device) return NULL; /* No such device */ return &dpnt->device->request_queue; } @@ -302,7 +302,7 @@ dpnt = &rscsi_disks[dev]; if (devm >= (sd_template.dev_max << 4) || - !dpnt || + !dpnt->device || !dpnt->device->online || block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); @@ -595,6 +595,7 @@ int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 1; + long error_sector; SCSI_LOG_HLCOMPLETE(1, sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff)); @@ -611,10 +612,11 @@ */ /* An error occurred */ - if (driver_byte(result) != 0) { - /* Sense data is valid */ - if (SCpnt->sense_buffer[0] == 0xF0 && SCpnt->sense_buffer[2] == MEDIUM_ERROR) { - long error_sector = (SCpnt->sense_buffer[3] << 24) | + if (driver_byte(result) != 0 && /* An error occured */ + SCpnt->sense_buffer[0] != 0xF0) { /* Sense data is valid */ + switch (SCpnt->sense_buffer[2]) { + case MEDIUM_ERROR: + error_sector = (SCpnt->sense_buffer[3] << 24) | (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; @@ -647,13 +649,30 @@ good_sectors = error_sector - SCpnt->request.sector; if (good_sectors < 0 || good_sectors >= this_count) good_sectors = 0; - } - if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { + break; + + case RECOVERED_ERROR: + /* + * An error occured, but it recovered. Inform the + * user, but make sure that it's not treated as a + * hard error. + */ + print_sense("sd", SCpnt); + result = 0; + SCpnt->sense_buffer[0] = 0x0; + good_sectors = this_count; + break; + + case ILLEGAL_REQUEST: if (SCpnt->device->ten == 1) { if (SCpnt->cmnd[0] == READ_10 || SCpnt->cmnd[0] == WRITE_10) SCpnt->device->ten = 0; } + break; + + default: + break; } } /* diff -urN linux-2.4.18/drivers/scsi/sg.c linux-2.4.19-pre5/drivers/scsi/sg.c --- linux-2.4.18/drivers/scsi/sg.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/sg.c Sat Mar 30 22:55:40 2002 @@ -19,9 +19,9 @@ */ #include #ifdef CONFIG_PROC_FS - static char sg_version_str[] = "Version: 3.1.22 (20011208)"; + static char sg_version_str[] = "Version: 3.1.23 (20020318)"; #endif - static int sg_version_num = 30122; /* 2 digits for each component */ + static int sg_version_num = 30123; /* 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 @@ -287,7 +287,7 @@ if (flags & O_EXCL) { if (O_RDONLY == (flags & O_ACCMODE)) { - retval = -EACCES; /* Can't lock it with read only access */ + retval = -EPERM; /* Can't lock it with read only access */ goto error_out; } if (sdp->headfp && (flags & O_NONBLOCK)) @@ -580,7 +580,7 @@ hp->iovec_count = 0; hp->mx_sb_len = 0; if (input_size > 0) - hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ? + hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ? SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; else hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : @@ -649,7 +649,7 @@ if (read_only && (! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { sg_remove_request(sfp, srp); - return -EACCES; + return -EPERM; } k = sg_common_write(sfp, srp, cmnd, timeout, blocking); if (k < 0) return k; @@ -981,7 +981,7 @@ copy_from_user(&opcode, siocp->data, 1); if (! sg_allow_access(opcode, sdp->device->type)) - return -EACCES; + return -EPERM; } return scsi_ioctl_send_command(sdp->device, (void *)arg); case SG_SET_DEBUG: @@ -998,7 +998,7 @@ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: if (read_only) - return -EACCES; /* don't know so take safe approach */ + return -EPERM; /* don't know so take safe approach */ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } } @@ -2632,9 +2632,9 @@ } } -static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, -READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, -MODE_SENSE, MODE_SENSE_10}; +static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE, +INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, +MODE_SENSE, MODE_SENSE_10, LOG_SENSE}; static int sg_allow_access(unsigned char opcode, char dev_type) { @@ -3036,17 +3036,28 @@ int size, int * eof, void * data) { SG_PROC_READ_FN(sg_proc_hoststrs_info); } +#define SG_MAX_HOST_STR_LEN 256 + static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { struct Scsi_Host * shp; int k; + char buff[SG_MAX_HOST_STR_LEN]; + char * cp; for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { for ( ; k < shp->host_no; ++k) PRINT_PROC("\n"); - PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : - (shp->hostt->name ? shp->hostt->name : "")); + strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) : + (shp->hostt->name ? shp->hostt->name : ""), + SG_MAX_HOST_STR_LEN); + buff[SG_MAX_HOST_STR_LEN - 1] = '\0'; + for (cp = buff; *cp; ++cp) { + if ('\n' == *cp) + *cp = ' '; /* suppress imbedded newlines */ + } + PRINT_PROC("%s\n", buff); } return 1; } diff -urN linux-2.4.18/drivers/scsi/sgiwd93.c linux-2.4.19-pre5/drivers/scsi/sgiwd93.c --- linux-2.4.18/drivers/scsi/sgiwd93.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/sgiwd93.c Sat Mar 30 22:55:29 2002 @@ -4,10 +4,13 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * 1999 Andrew R. Baker (andrewb@uab.edu) * - Support for 2nd SCSI controller on Indigo2 + * 2001 Florian Lohoff (flo@rfc822.org) + * - Delete HPC scatter gather (Read corruption on + * multiple disks) + * - Cleanup wback cache handling * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $ */ #include #include @@ -36,29 +39,34 @@ struct hpc_chunk { struct hpc_dma_desc desc; - unsigned long padding; + u32 _padding; /* align to quadword boundary */ }; struct Scsi_Host *sgiwd93_host = NULL; struct Scsi_Host *sgiwd93_host1 = NULL; /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value) +static inline void write_wd33c93_count(const wd33c93_regs regs, + unsigned long value) { - regp->SASR = WD_TRANSFER_COUNT_MSB; - regp->SCMD = ((value >> 16) & 0xff); - regp->SCMD = ((value >> 8) & 0xff); - regp->SCMD = ((value >> 0) & 0xff); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + *regs.SCMD = ((value >> 16) & 0xff); + *regs.SCMD = ((value >> 8) & 0xff); + *regs.SCMD = ((value >> 0) & 0xff); + mb(); } -static inline unsigned long read_wd33c93_count(wd33c93_regs *regp) +static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) { unsigned long value; - regp->SASR = WD_TRANSFER_COUNT_MSB; - value = ((regp->SCMD & 0xff) << 16); - value |= ((regp->SCMD & 0xff) << 8); - value |= ((regp->SCMD & 0xff) << 0); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + value = ((*regs.SCMD & 0xff) << 16); + value |= ((*regs.SCMD & 0xff) << 8); + value |= ((*regs.SCMD & 0xff) << 0); + mb(); return value; } @@ -80,7 +88,6 @@ unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -99,7 +106,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -110,42 +116,17 @@ hdata->dma_dir = datainp; - if(cmd->SCp.buffers_residual) { - struct scatterlist *slp = cmd->SCp.buffer; - int i, totlen = 0; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; -#ifdef DEBUG_DMA - printk("SCLIST<"); -#endif - for(i = 0; i <= cmd->SCp.buffers_residual; i++) { -#ifdef DEBUG_DMA - printk("[%p,%d]", slp[i].address, slp[i].length); -#endif - fill_hpc_entries (&hcp, slp[i].address, slp[i].length); - totlen += slp[i].length; - } -#ifdef DEBUG_DMA - printk(">tlen<%d>", totlen); -#endif - hdata->dma_bounce_len = totlen; /* a trick... */ - write_wd33c93_count(regp, totlen); - } else { - /* Non-scattered dma. */ -#ifdef DEBUG_DMA - printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - /* - * wd33c93 shouldn't pass us bogus dma_setups, but - * it does:-( The other wd33c93 drivers deal with - * it the same way (which isn't that obvious). - * IMHO a better fix would be, not to do these - * dma setups in the first place - */ - if (cmd->SCp.ptr == NULL) - return 1; - fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); - write_wd33c93_count(regp, cmd->SCp.this_residual); - } + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); /* To make sure, if we trip an HPC bug, that we transfer * every single byte, we tag on an extra zero length dma @@ -160,10 +141,14 @@ /* Start up the HPC. */ hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); - if(datainp) + if(datainp) { + dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE); - else + } else { + dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + } + return 0; } @@ -171,7 +156,6 @@ int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -191,44 +175,6 @@ } hregs->ctrl = 0; - /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->SCp.buffers_residual) { - struct scatterlist *slp = SCpnt->SCp.buffer; - int totlen, wd93_residual, transferred, i; - - /* Yep, we were doing the scatterlist thang. */ - totlen = hdata->dma_bounce_len; - wd93_residual = read_wd33c93_count(regp); - transferred = totlen - wd93_residual; - -#ifdef DEBUG_DMA - printk("tlen<%d>resid<%d>transf<%d> ", - totlen, wd93_residual, transferred); -#endif - - /* Avoid long winded partial-transfer search for common case. */ - if(transferred != totlen) { - /* This is the nut case. */ -#ifdef DEBUG_DMA - printk("Jed was here..."); -#endif - for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { - if(slp[i].length >= transferred) - break; - transferred -= slp[i].length; - } - } else { - /* This is the common case. */ -#ifdef DEBUG_DMA - printk("did it all..."); -#endif - i = SCpnt->SCp.buffers_residual; - } - SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; - SCpnt->SCp.ptr = (char *) slp[i].address; - SCpnt->SCp.this_residual = slp[i].length; - } #ifdef DEBUG_DMA printk("\n"); #endif @@ -258,6 +204,9 @@ }; hcp--; hcp->desc.pnext = PHYSADDR(buf); + + /* Force flush to memory */ + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); } int __init sgiwd93_detect(Scsi_Host_Template *SGIblows) @@ -267,6 +216,7 @@ struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; + wd33c93_regs regs; uchar *buf; if(called) @@ -287,10 +237,11 @@ return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003), - dma_setup, dma_stop, WD33C93_FS_16_20); + regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003); + regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007); + wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; hdata->no_sync = 0; @@ -321,15 +272,16 @@ return 1; /* We registered host0 so return success*/ } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ - wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003), - dma_setup, dma_stop, WD33C93_FS_16_20); + regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003); + regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007); + wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop, + WD33C93_FS_16_20); hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata; hdata1->no_sync = 0; hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) { printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ); diff -urN linux-2.4.18/drivers/scsi/sr.c linux-2.4.19-pre5/drivers/scsi/sr.c --- linux-2.4.18/drivers/scsi/sr.c Sun Mar 3 17:17:07 2002 +++ linux-2.4.19-pre5/drivers/scsi/sr.c Sat Mar 30 22:55:35 2002 @@ -198,6 +198,7 @@ int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 0; int device_nr = DEVICE_NR(SCpnt->request.rq_dev); + long error_sector; #ifdef DEBUG printk("sr.c done: %x %p\n", result, SCpnt->request.bh->b_data); @@ -210,33 +211,52 @@ if (driver_byte(result) != 0 && /* An error occurred */ - SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ - (SCpnt->sense_buffer[2] == MEDIUM_ERROR || - SCpnt->sense_buffer[2] == VOLUME_OVERFLOW || - SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) { - long error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - if (SCpnt->request.bh != NULL) - block_sectors = SCpnt->request.bh->b_size >> 9; - if (block_sectors < 4) - block_sectors = 4; - if (scsi_CDs[device_nr].device->sector_size == 2048) - error_sector <<= 2; - error_sector &= ~(block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; - /* - * The SCSI specification allows for the value returned by READ - * CAPACITY to be up to 75 2K sectors past the last readable - * block. Therefore, if we hit a medium error within the last - * 75 2K sectors, we decrease the saved size value. - */ - if ((error_sector >> 1) < sr_sizes[device_nr] && - scsi_CDs[device_nr].capacity - error_sector < 4 * 75) - sr_sizes[device_nr] = error_sector >> 1; + SCpnt->sense_buffer[0] == 0xF0) { /* Sense data is valid */ + switch (SCpnt->sense_buffer[2]) { + case MEDIUM_ERROR: + case VOLUME_OVERFLOW: + case ILLEGAL_REQUEST: + error_sector = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + if (block_sectors < 4) + block_sectors = 4; + if (scsi_CDs[device_nr].device->sector_size == 2048) + error_sector <<= 2; + error_sector &= ~(block_sectors - 1); + good_sectors = error_sector - SCpnt->request.sector; + if (good_sectors < 0 || good_sectors >= this_count) + good_sectors = 0; + /* + * The SCSI specification allows for the value returned + * by READ CAPACITY to be up to 75 2K sectors past the + * last readable block. Therefore, if we hit a medium + * error within the last 75 2K sectors, we decrease the + * saved size value. + */ + if ((error_sector >> 1) < sr_sizes[device_nr] && + scsi_CDs[device_nr].capacity - error_sector < 4 *75) + sr_sizes[device_nr] = error_sector >> 1; + break; + + case RECOVERED_ERROR: + /* + * An error occured, but it recovered. Inform the + * user, but make sure that it's not treated as a + * hard error. + */ + print_sense("sr", SCpnt); + result = 0; + SCpnt->sense_buffer[0] = 0x0; + good_sectors = this_count; + break; + + default: + break; + } } /* diff -urN linux-2.4.18/drivers/scsi/sr_ioctl.c linux-2.4.19-pre5/drivers/scsi/sr_ioctl.c --- linux-2.4.18/drivers/scsi/sr_ioctl.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/sr_ioctl.c Sat Mar 30 22:55:29 2002 @@ -48,7 +48,7 @@ if (ti->cdti_trk1 == ntracks) ti->cdti_trk1 = CDROM_LEADOUT; - else + else if (ti->cdti_trk1 != CDROM_LEADOUT) ti->cdti_trk1 ++; trk0_te.cdte_track = ti->cdti_trk0; diff -urN linux-2.4.18/drivers/scsi/sun3_NCR5380.c linux-2.4.19-pre5/drivers/scsi/sun3_NCR5380.c --- linux-2.4.18/drivers/scsi/sun3_NCR5380.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/sun3_NCR5380.c Sat Mar 30 22:55:35 2002 @@ -647,10 +647,7 @@ static volatile int main_running = 0; static struct tq_struct NCR5380_tqueue = { -// NULL, /* next */ - sync: 0, /* sync */ - routine: (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ - data: NULL /* data */ + routine: (void (*)(void*))NCR5380_main /* must have (void *) arg... */ }; static __inline__ void queue_main(void) @@ -1219,9 +1216,9 @@ if((sun3scsi_dma_finish(hostdata->connected->request.cmd))) { printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); - printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); - machine_halt(); + BUG(); } /* make sure we're not stuck in a data phase */ @@ -1232,9 +1229,9 @@ printk("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", HOSTNO); printk("not prepared for this error!\n"); - printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); - machine_halt(); + BUG(); } @@ -1922,7 +1919,7 @@ /* sanity check */ if(!sun3_dma_setup_done) { printk("scsi%d: transfer_dma without setup!\n", HOSTNO); - machine_halt(); + BUG(); } hostdata->dma_len = c; diff -urN linux-2.4.18/drivers/scsi/sun3_scsi.c linux-2.4.19-pre5/drivers/scsi/sun3_scsi.c --- linux-2.4.18/drivers/scsi/sun3_scsi.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/scsi/sun3_scsi.c Sat Mar 30 22:55:35 2002 @@ -80,8 +80,10 @@ #include "NCR5380.h" #include "constants.h" +/* #define OLDDMA */ + #define USE_WRAPPER -#define RESET_BOOT +/*#define RESET_BOOT */ #define DRIVER_SETUP #define NDEBUG 0 @@ -94,7 +96,7 @@ #undef DRIVER_SETUP #endif -#undef SUPPORT_TAGS +/* #define SUPPORT_TAGS */ #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); @@ -126,7 +128,9 @@ static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; +#ifdef OLDDMA static unsigned char *dmabuf = NULL; /* dma memory buffer */ +#endif static struct sun3_udc_regs *udc_regs = NULL; static unsigned char *sun3_dma_orig_addr = NULL; static unsigned long sun3_dma_orig_count = 0; @@ -260,7 +264,7 @@ #endif #ifdef SUPPORT_TAGS if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; + setup_use_tagged_queuing = USE_TAGGED_QUEUING; #endif instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); @@ -310,6 +314,11 @@ dregs->fifo_count = 0; called = 1; + +#ifdef RESET_BOOT + sun3_scsi_reset_boot(instance); +#endif + return 1; } @@ -341,7 +350,7 @@ printk( "Sun3 SCSI: resetting the SCSI bus..." ); /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ - sun3_disable_irq( IRQ_SUN3_SCSI ); +// sun3_disable_irq( IRQ_SUN3_SCSI ); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, @@ -361,7 +370,7 @@ barrier(); /* switch on SCSI IRQ again */ - sun3_enable_irq( IRQ_SUN3_SCSI ); +// sun3_enable_irq( IRQ_SUN3_SCSI ); printk( " done\n" ); } @@ -427,8 +436,12 @@ #else void *addr; + if(sun3_dma_orig_addr != NULL) + dvma_unmap(sun3_dma_orig_addr); + // addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); addr = (void *)dvma_map((unsigned long) data, count); + sun3_dma_orig_addr = addr; sun3_dma_orig_count = count; #endif @@ -454,7 +467,6 @@ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; - if(dregs->fifo_count != count) { printk("scsi%d: fifo_mismatch %04x not %04x\n", default_instance->host_no, dregs->fifo_count, @@ -533,10 +545,10 @@ int ret = 0; sun3_dma_active = 0; - +#if 1 // check to empty the fifo on a read if(!write_flag) { - int tmo = 200000; /* 2 sec */ + int tmo = 20000; /* .2 sec */ while(1) { if(dregs->csr & CSR_FIFO_EMPTY) @@ -549,6 +561,7 @@ } } +#endif count = sun3scsi_dma_count(default_instance); #ifdef OLDDMA @@ -588,6 +601,7 @@ } dvma_unmap(sun3_dma_orig_addr); + sun3_dma_orig_addr = NULL; #endif sun3_udc_write(UDC_RESET, UDC_CSR); dregs->fifo_count = 0; @@ -609,3 +623,4 @@ #include "scsi_module.c" +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/sun3x_esp.c linux-2.4.19-pre5/drivers/scsi/sun3x_esp.c --- linux-2.4.18/drivers/scsi/sun3x_esp.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/sun3x_esp.c Sat Mar 30 22:55:35 2002 @@ -376,3 +376,5 @@ static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/sym53c8xx.c linux-2.4.19-pre5/drivers/scsi/sym53c8xx.c --- linux-2.4.18/drivers/scsi/sym53c8xx.c Sun Dec 23 16:23:48 2001 +++ linux-2.4.19-pre5/drivers/scsi/sym53c8xx.c Sat Mar 30 22:55:35 2002 @@ -14111,7 +14111,7 @@ if (len) return -EINVAL; else { - long flags; + unsigned long flags; NCR_LOCK_NCB(np, flags); ncr_usercmd (np); diff -urN linux-2.4.18/drivers/scsi/sym53c8xx_defs.h linux-2.4.19-pre5/drivers/scsi/sym53c8xx_defs.h --- linux-2.4.18/drivers/scsi/sym53c8xx_defs.h Mon Feb 18 06:27:02 2002 +++ linux-2.4.19-pre5/drivers/scsi/sym53c8xx_defs.h Sat Mar 30 22:55:29 2002 @@ -51,6 +51,10 @@ ** NVRAM detection and reading. ** Copyright (C) 1997 Richard Waltham ** +** Added support for MIPS big endian systems. +** Carsten Langgaard, carstenl@mips.com +** Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. +** ******************************************************************************* */ @@ -384,7 +388,16 @@ #define readl_l2b(a) le32_to_cpu(readl(a)) #define writew_b2l(v,a) writew(cpu_to_le16(v),a) #define writel_b2l(v,a) writel(cpu_to_le32(v),a) -#else /* Other bid-endian */ +#elif defined(__mips__) +#define readw_l2b readw +#define readl_l2b readl +#define writew_b2l writew +#define writel_b2l writel +#define inw_l2b inw +#define inl_l2b inl +#define outw_b2l outw +#define outl_b2l outl +#else /* Other big-endian */ #define readw_l2b readw #define readl_l2b readl #define writew_b2l writew diff -urN linux-2.4.18/drivers/scsi/u14-34f.c linux-2.4.19-pre5/drivers/scsi/u14-34f.c --- linux-2.4.18/drivers/scsi/u14-34f.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/u14-34f.c Sat Mar 30 22:55:29 2002 @@ -1,6 +1,9 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 01 Jan 2002 Rev. 6.50 for linux 2.4.16 + * + Use the dynamic DMA mapping API. + * * 1 May 2001 Rev. 6.05 for linux 2.4.4 * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) * @@ -183,7 +186,7 @@ * * Multiple U14F and/or U34F host adapters are supported. * - * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -334,7 +337,6 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#include #include #ifndef LinuxVersionCode @@ -343,6 +345,9 @@ #define MAX_INT_PARAM 10 +#if defined(MODULE) +#include + MODULE_PARM(boot_options, "s"); MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); MODULE_PARM(linked_comm, "i"); @@ -352,6 +357,8 @@ MODULE_PARM(ext_tran, "i"); MODULE_AUTHOR("Dario Ballabio"); +#endif + #include #include #include @@ -370,17 +377,11 @@ #include "u14-34f.h" #include #include +#include #include #include #include -#define SPIN_FLAGS unsigned long spin_flags; -#define SPIN_LOCK spin_lock_irq(&io_request_lock); -#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags); -#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock); -#define SPIN_UNLOCK_RESTORE \ - spin_unlock_irqrestore(&io_request_lock, spin_flags); - /* Values for the PRODUCT_ID ports for the 14/34F */ #define PRODUCT_ID1 0x56 #define PRODUCT_ID2 0x40 /* NOTE: Only upper nibble is used */ @@ -483,13 +484,13 @@ unsigned char clink_id; /* identifies command in chain */ unsigned char use_sg; /* (if sg is set) 8 bytes per list */ unsigned char sense_len; - unsigned char scsi_cdbs_len; /* 6, 10, or 12 */ - unsigned char scsi_cdbs[12]; /* SCSI commands */ + unsigned char cdb_len; /* 6, 10, or 12 */ + unsigned char cdb[12]; /* SCSI Command Descriptor Block */ unsigned char adapter_status; /* non-zero indicates HA error */ unsigned char target_status; /* non-zero indicates target error */ unsigned int sense_addr PACKED; Scsi_Cmnd *SCpnt; - unsigned int index; /* cp index */ + unsigned int cpp_index; /* cp index */ struct sg_list *sglist; }; @@ -507,6 +508,7 @@ unsigned int retries; /* Number of internal retries */ unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or ESA */ + struct pci_dev *pdev; /* Always NULL */ unsigned char heads; unsigned char sectors; @@ -537,21 +539,11 @@ #define HD(board) ((struct hostdata *) &sh[board]->hostdata) #define BN(board) (HD(board)->board_name) -#define SWAP_BYTE(x) ((unsigned long)( \ - (((unsigned long)(x) & 0x000000ffU) << 24) | \ - (((unsigned long)(x) & 0x0000ff00U) << 8) | \ - (((unsigned long)(x) & 0x00ff0000U) >> 8) | \ - (((unsigned long)(x) & 0xff000000U) >> 24))) - -#if defined(__BIG_ENDIAN) -#define H2DEV(x) SWAP_BYTE(x) -#else -#define H2DEV(x) (x) -#endif +/* Device is Little Endian */ +#define H2DEV(x) cpu_to_le32(x) +#define DEV2H(x) le32_to_cpu(x) -#define DEV2H(x) H2DEV(x) #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) -#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); @@ -653,8 +645,8 @@ cpp->xdir = DTD_IN; cpp->data_address = V2DEV(HD(j)->board_id); cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); - cpp->scsi_cdbs_len = 6; - cpp->scsi_cdbs[0] = HA_CMD_INQUIRY; + cpp->cdb_len = 6; + cpp->cdb[0] = HA_CMD_INQUIRY; if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { printk("%s: board_inquiry, adapter busy.\n", BN(j)); @@ -672,10 +664,10 @@ /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); - SPIN_UNLOCK + spin_unlock_irq(&io_request_lock); time = jiffies; while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); - SPIN_LOCK + spin_lock_irq(&io_request_lock); if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { HD(j)->cp_stat[0] = FREE; @@ -834,14 +826,14 @@ unsigned long flags; scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; - + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); release_dma_lock(flags); - + sh[j]->dma_channel = dma_channel; sprintf(BN(j), "U14F%d", j); bus_type = "ISA"; @@ -881,7 +873,7 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; if (j == 0) { - printk("UltraStor 14F/34F: Copyright (C) 1994-2001 Dario Ballabio.\n"); + printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n"); printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n", driver_name, YESNO(have_old_firmware), YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); @@ -951,8 +943,7 @@ return 1; } -int u14_34f_detect(Scsi_Host_Template *tpnt) -{ +int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; tpnt->proc_name = "u14-34f"; @@ -980,26 +971,94 @@ return j; } -static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) { - unsigned int k, data_len = 0; +static inline void map_dma(unsigned int i, unsigned int j) { + unsigned int k, count, data_len = 0, pci_dir; struct scatterlist *sgpnt; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (SCpnt->sense_buffer) + cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, + sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + + cpp->sense_len = sizeof SCpnt->sense_buffer; + + if (!SCpnt->use_sg) { + + if (!SCpnt->request_bufflen) + cpp->data_address = V2DEV(SCpnt->request_buffer); + + else if (SCpnt->request_buffer) + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, + SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); + + cpp->data_len = H2DEV(SCpnt->request_bufflen); + return; + } sgpnt = (struct scatterlist *) SCpnt->request_buffer; + count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir); - for (k = 0; k < SCpnt->use_sg; k++) { - cpp->sglist[k].address = V2DEV(sgpnt[k].address); - cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length); + for (k = 0; k < count; k++) { + cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); + cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); data_len += sgpnt[k].length; } + cpp->sg = TRUE; cpp->use_sg = SCpnt->use_sg; cpp->data_address = V2DEV(cpp->sglist); cpp->data_len = H2DEV(data_len); } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - unsigned int i, j, k; +static void unmap_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static void sync_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { + unsigned int k; static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, @@ -1010,9 +1069,51 @@ static const unsigned char data_none_cmds[] = { 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 }; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + + if (SCpnt->sc_data_direction == SCSI_DATA_READ) { + cpp->xdir = DTD_IN; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) { + cpp->xdir = DTD_OUT; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) { + cpp->xdir = DTD_NONE; + return; + } + + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); + + cpp->xdir = DTD_IN; + + for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->xdir = DTD_OUT; + break; + } + + if (cpp->xdir == DTD_IN) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->xdir = DTD_NONE; + break; + } + +} + +static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { + unsigned int i, j, k; + struct mscp *cpp; + /* j is the board number */ j = ((struct hostdata *) SCpnt->host->hostdata)->board_number; @@ -1044,47 +1145,26 @@ memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); SCpnt->scsi_done = done; - cpp->index = i; - SCpnt->host_scribble = (unsigned char *) &cpp->index; + cpp->cpp_index = i; + SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", BN(j), i, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); - cpp->xdir = DTD_IN; - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->xdir = DTD_OUT; - break; - } - - if (cpp->xdir == DTD_IN) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->xdir = DTD_NONE; - break; - } - cpp->opcode = OP_SCSI; cpp->channel = SCpnt->channel; cpp->target = SCpnt->target; cpp->lun = SCpnt->lun; cpp->SCpnt = SCpnt; - cpp->sense_addr = V2DEV(SCpnt->sense_buffer); - cpp->sense_len = sizeof SCpnt->sense_buffer; + cpp->cdb_len = SCpnt->cmd_len; + memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - if (SCpnt->use_sg) { - cpp->sg = TRUE; - build_sg_list(cpp, SCpnt); - } - else { - cpp->data_address = V2DEV(SCpnt->request_buffer); - cpp->data_len = H2DEV(SCpnt->request_bufflen); - } + /* Use data transfer direction SCpnt->sc_data_direction */ + scsi_to_dev_dir(i, j); - cpp->scsi_cdbs_len = SCpnt->cmd_len; - memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len); + /* Map DMA buffers and SG list */ + map_dma(i, j); if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { @@ -1094,6 +1174,7 @@ } if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { + unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); @@ -1156,6 +1237,7 @@ printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { + unmap_dma(i, j); SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", @@ -1177,6 +1259,7 @@ } if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { + unmap_dma(i, j); SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; @@ -1274,16 +1357,19 @@ #endif HD(j)->in_reset = TRUE; - SPIN_UNLOCK + + spin_unlock_irq(&io_request_lock); time = jiffies; while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - SPIN_LOCK + spin_lock_irq(&io_request_lock); + printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); for (i = 0; i < sh[j]->can_queue; i++) { if (HD(j)->cp_stat[i] == IN_RESET) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1296,6 +1382,7 @@ else if (HD(j)->cp_stat[i] == ABORTING) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1536,23 +1623,25 @@ return; } - spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM)); - cpp = spp; + ret = inl(sh[j]->io_port + REG_ICM); /* Clear interrupt pending flag */ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); -#if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; -#endif - /* Find the mailbox to be serviced on this board */ - i = cpp - HD(j)->cp; + for (i = 0; i < sh[j]->can_queue; i++) + if (V2DEV(&(HD(j)->cp[i])) == ret) break; - if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue - || i >= sh[j]->can_queue) + if (i >= sh[j]->can_queue) panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), - (void *)ret, HD(j)->cp); + (void *)ret, (void *)V2DEV(HD(j)->cp)); + + cpp = &(HD(j)->cp[i]); + spp = cpp; + +#if defined(DEBUG_GENERATE_ABORTS) + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; +#endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; @@ -1588,6 +1677,8 @@ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); + sync_dma(i, j); + if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); @@ -1705,6 +1796,8 @@ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, reg, HD(j)->iocount); + unmap_dma(i, j); + /* Set the command state to inactive */ SCpnt->host_scribble = NULL; @@ -1718,14 +1811,14 @@ static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) { unsigned int j; - SPIN_FLAGS + unsigned long spin_flags; /* Check if the interrupt must be processed by this handler */ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return; - SPIN_LOCK_SAVE + spin_lock_irqsave(&io_request_lock, spin_flags); ihdlr(irq, j); - SPIN_UNLOCK_RESTORE + spin_unlock_irqrestore(&io_request_lock, spin_flags); } int u14_34f_release(struct Scsi_Host *shpnt) { @@ -1736,9 +1829,7 @@ 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]); - } + 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); @@ -1752,7 +1843,6 @@ return FALSE; } -MODULE_LICENSE("BSD without advertisement clause"); static Scsi_Host_Template driver_template = ULTRASTOR_14_34F; #include "scsi_module.c" @@ -1760,3 +1850,4 @@ #ifndef MODULE __setup("u14-34f=", option_setup); #endif /* end MODULE */ +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/scsi/u14-34f.h linux-2.4.19-pre5/drivers/scsi/u14-34f.h --- linux-2.4.18/drivers/scsi/u14-34f.h Sun Feb 17 01:23:02 2002 +++ linux-2.4.19-pre5/drivers/scsi/u14-34f.h Sat Mar 30 22:55:29 2002 @@ -13,7 +13,7 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "6.05.00" +#define U14_34F_VERSION "6.50.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -urN linux-2.4.18/drivers/scsi/wd33c93.c linux-2.4.19-pre5/drivers/scsi/wd33c93.c --- linux-2.4.18/drivers/scsi/wd33c93.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/scsi/wd33c93.c Sat Mar 30 22:55:35 2002 @@ -1407,12 +1407,32 @@ -static void reset_wd33c93(struct Scsi_Host *instance) +void reset_wd33c93(struct Scsi_Host *instance) { struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata; const wd33c93_regs regs = hostdata->regs; uchar sr; +#ifdef CONFIG_SGI_IP22 +{ +int busycount = 0; +extern void sgiwd93_reset(unsigned long); + /* wait 'til the chip gets some time for us */ + while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100) + udelay (10); + /* + * there are scsi devices out there, which manage to lock up + * the wd33c93 in a busy condition. In this state it won't + * accept the reset command. The only way to solve this is to + * give the chip a hardware reset (if possible). The code below + * does this for the SGI Indy, where this is possible + */ + /* still busy ? */ + if (READ_AUX_STAT() & ASR_BSY) + sgiwd93_reset(instance->base); /* yeah, give it the hard one */ +} +#endif + write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | instance->this_id | hostdata->clock_freq); write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); @@ -2034,3 +2054,5 @@ { MOD_DEC_USE_COUNT; } + +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/sgi/char/Makefile linux-2.4.19-pre5/drivers/sgi/char/Makefile --- linux-2.4.18/drivers/sgi/char/Makefile Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sgi/char/Makefile Sat Mar 30 22:55:29 2002 @@ -9,7 +9,7 @@ O_TARGET := sgichar.o -export-objs := newport.o shmiq.o sgicons.o usema.o +export-objs := newport.o rrm.o shmiq.o sgicons.o usema.o obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o obj-$(CONFIG_SGI_SERIAL) += sgiserial.o diff -urN linux-2.4.18/drivers/sgi/char/ds1286.c linux-2.4.19-pre5/drivers/sgi/char/ds1286.c --- linux-2.4.18/drivers/sgi/char/ds1286.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sgi/char/ds1286.c Sat Mar 30 22:55:29 2002 @@ -61,8 +61,9 @@ static unsigned int ds1286_poll(struct file *file, poll_table *wait); -void get_rtc_time (struct rtc_time *rtc_tm); -void get_rtc_alm_time (struct rtc_time *alm_tm); +void ds1286_get_alm_time (struct rtc_time *alm_tm); +void ds1286_get_time(struct rtc_time *rtc_tm); +int ds1286_set_time(struct rtc_time *rtc_tm); void set_rtc_irq_bit(unsigned char bit); void clear_rtc_irq_bit(unsigned char bit); @@ -173,7 +174,7 @@ * tm_min, and tm_sec values are filled in. */ - get_rtc_alm_time(&wtime); + ds1286_get_alm_time(&wtime); break; } case RTC_ALM_SET: /* Store a time into the alarm */ @@ -215,15 +216,12 @@ } case RTC_RD_TIME: /* Read the time/date from RTC */ { - get_rtc_time(&wtime); + ds1286_get_time(&wtime); break; } case RTC_SET_TIME: /* Set the RTC */ { struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control; - unsigned int yrs, flags; if (!capable(CAP_SYS_TIME)) return -EACCES; @@ -231,57 +229,8 @@ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= 1940) > 255) /* They are unsigned */ - return -EINVAL; - - if (yrs >= 100) - yrs -= 100; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - - spin_lock_irqsave(&ds1286_lock, flags); - save_control = CMOS_READ(RTC_CMD); - CMOS_WRITE((save_control|RTC_TE), RTC_CMD); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DATE); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); - - CMOS_WRITE(save_control, RTC_CMD); - spin_unlock_irqrestore(&ds1286_lock, flags); - - return 0; + + return ds1286_set_time(&rtc_tm); } default: return -EINVAL; @@ -369,7 +318,7 @@ p = buf; - get_rtc_time(&tm); + ds1286_get_time(&tm); hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND); BCD_TO_BIN(hundredth); @@ -384,7 +333,7 @@ * match any value for that particular field. Values that are * greater than a valid time, but less than 0xc0 shouldn't appear. */ - get_rtc_alm_time(&tm); + ds1286_get_alm_time(&tm); p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); if (tm.tm_hour <= 24) p += sprintf(p, "%02d:", tm.tm_hour); @@ -441,12 +390,13 @@ return CMOS_READ(RTC_CMD) & RTC_TE; } -void get_rtc_time(struct rtc_time *rtc_tm) + +void ds1286_get_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char save_control; unsigned int flags; - + unsigned long uip_watchdog = jiffies; + /* * read RTC once any update in progress is done. The update * can take just over 2ms. We wait 10 to 20ms. There is no need to @@ -500,7 +450,66 @@ rtc_tm->tm_mon--; } -void get_rtc_alm_time(struct rtc_time *alm_tm) +int ds1286_set_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control; + unsigned int yrs, flags; + + + yrs = rtc_tm->tm_year + 1900; + mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm->tm_mday; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= 1940) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irqsave(&ds1286_lock, flags); + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DATE); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); + + CMOS_WRITE(save_control, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; +} + +void ds1286_get_alm_time(struct rtc_time *alm_tm) { unsigned char cmd; unsigned int flags; diff -urN linux-2.4.18/drivers/sgi/char/sgiserial.c linux-2.4.19-pre5/drivers/sgi/char/sgiserial.c --- linux-2.4.18/drivers/sgi/char/sgiserial.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sgi/char/sgiserial.c Sat Mar 30 22:55:29 2002 @@ -1916,9 +1916,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); @@ -2017,7 +2017,7 @@ if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT), "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); + panic("Unable to attach zs intr"); restore_flags(flags); return 0; diff -urN linux-2.4.18/drivers/sound/Config.in linux-2.4.19-pre5/drivers/sound/Config.in --- linux-2.4.18/drivers/sound/Config.in Sun Dec 23 16:23:48 2001 +++ linux-2.4.19-pre5/drivers/sound/Config.in Sat Mar 30 22:55:35 2002 @@ -34,6 +34,9 @@ dep_mbool ' Creative SBLive! MIDI' CONFIG_MIDI_EMU10K1 $CONFIG_SOUND_EMU10K1 $CONFIG_EXPERIMENTAL dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND dep_tristate ' Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND +if [ "$CONFIG_SIBYTE_SB1250" = "y" -a "$CONFIG_REMOTE_DEBUG" != "y" ]; then + dep_tristate ' Crystal Sound CS4297a (for Swarm)' CONFIG_SOUND_BCM_CS4297A $CONFIG_SOUND +fi dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND @@ -46,11 +49,22 @@ dep_tristate ' RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND if [ "$CONFIG_VISWS" = "y" ]; then - dep_tristate ' SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND + dep_tristate ' SGI Visual Workstation sound' CONFIG_SOUND_VWSND $CONFIG_SOUND +fi +if [ "$CONFIG_SGI_IP22" = "y" ] ; then + dep_tristate ' SGI HAL2 sound (EXPERIMENTAL)' CONFIG_SOUND_HAL2 $CONFIG_SOUND $CONFIG_SGI_IP22 $CONFIG_EXPERIMENTAL +fi + +if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then + dep_tristate ' IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND fi if [ "$CONFIG_DDB5477" = "y" ]; then dep_tristate ' NEC Vrc5477 AC97 sound' CONFIG_SOUND_VRC5477 $CONFIG_SOUND fi +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then + dep_tristate ' Au1000 Sound' CONFIG_SOUND_AU1000 $CONFIG_SOUND +fi + dep_tristate ' Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND dep_tristate ' Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND diff -urN linux-2.4.18/drivers/sound/Makefile linux-2.4.19-pre5/drivers/sound/Makefile --- linux-2.4.18/drivers/sound/Makefile Sun Dec 23 16:23:48 2001 +++ linux-2.4.19-pre5/drivers/sound/Makefile Sat Mar 30 22:55:29 2002 @@ -20,6 +20,7 @@ # Please leave it as is, cause the link order is significant ! +obj-$(CONFIG_SOUND_HAL2) += hal2.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o @@ -64,16 +65,18 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o +obj-$(CONFIG_SOUND_AU1000) += au1000.o ac97_codec.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o +obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o -obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o +obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o ifeq ($(CONFIG_MIDI_EMU10K1),y) obj-$(CONFIG_SOUND_EMU10K1) += sound.o diff -urN linux-2.4.18/drivers/sound/ac97_codec.c linux-2.4.19-pre5/drivers/sound/ac97_codec.c --- linux-2.4.18/drivers/sound/ac97_codec.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/ac97_codec.c Sat Mar 30 22:55:40 2002 @@ -105,7 +105,9 @@ {0x41445340, "Analog Devices AD1881", &null_ops}, {0x41445348, "Analog Devices AD1881A", &null_ops}, {0x41445360, "Analog Devices AD1885", &default_ops}, + {0x41445361, "Analog Devices AD1886", &default_ops}, {0x41445460, "Analog Devices AD1885", &default_ops}, + {0x41445461, "Analog Devices AD1886", &default_ops}, {0x414B4D00, "Asahi Kasei AK4540", &null_ops}, {0x414B4D01, "Asahi Kasei AK4542", &null_ops}, {0x414B4D02, "Asahi Kasei AK4543", &null_ops}, diff -urN linux-2.4.18/drivers/sound/au1000.c linux-2.4.19-pre5/drivers/sound/au1000.c --- linux-2.4.18/drivers/sound/au1000.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/sound/au1000.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,2152 @@ +/* + * au1000.c -- Sound driver for Alchemy Au1000 MIPS Internet Edge + * Processor. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Module command line parameters: + * + * Supported devices: + * /dev/dsp standard OSS /dev/dsp device + * /dev/mixer standard OSS /dev/mixer device + * + * Notes: + * + * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are + * taken, slightly modified or not at all, from the ES1371 driver, + * so refer to the credits in es1371.c for those. The rest of the + * code (probe, open, read, write, the ISR, etc.) is new. + * + * Revision history + * 06.27.2001 Initial version + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --------------------------------------------------------------------- */ + +#undef OSS_DOCUMENTED_MIXER_SEMANTICS +#define AU1000_DEBUG +#undef AU1000_VERBOSE_DEBUG + + +#define AU1000_MODULE_NAME "Au1000 audio" +#define PFX AU1000_MODULE_NAME + +#ifdef AU1000_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) + + +/* misc stuff */ +#define POLL_COUNT 0x5000 +#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC) + +/* Boot options */ +static int vra = 0; // 0 = no VRA, 1 = use VRA if codec supports it +MODULE_PARM(vra, "i"); +MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); + + +/* --------------------------------------------------------------------- */ + +struct au1000_state { + /* soundcore stuff */ + int dev_audio; + +#ifdef AU1000_DEBUG + /* debug /proc entry */ + struct proc_dir_entry *ps; + struct proc_dir_entry *ac97_ps; +#endif /* AU1000_DEBUG */ + + struct ac97_codec codec; + unsigned codec_base_caps; // AC'97 reg 00h, "Reset Register" + unsigned codec_ext_caps; // AC'97 reg 28h, "Extended Audio ID" + int no_vra; // do not use VRA + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + struct dmabuf { + unsigned int dmanr; // DMA Channel number + int irq; // DMA Channel Done IRQ number + unsigned sample_rate; // Hz + unsigned src_factor; // SRC interp/decimation (no vra) + unsigned sample_size; // 8 or 16 + int num_channels; // 1 = mono, 2 = stereo, 4, 6 + int dma_bytes_per_sample;// DMA bytes per audio sample frame + int user_bytes_per_sample;// User bytes per audio sample frame + int cnt_factor; // user-to-DMA bytes per audio + // sample frame + void *rawbuf; + dma_addr_t dmaaddr; + unsigned buforder; + unsigned numfrag; // # of DMA fragments in DMA buffer + unsigned fragshift; + void *nextIn; // ptr to next-in to DMA buffer + void *nextOut; // ptr to next-out from DMA buffer + int count; // current byte count in DMA buffer + unsigned total_bytes; // total bytes written or read + unsigned error; // over/underrun + wait_queue_head_t wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; // user perception of fragment size + unsigned dma_fragsize; // DMA (real) fragment size + unsigned dmasize; // Total DMA buffer size + // (mult. of DMA fragsize) + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned stopped:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dma_dac , dma_adc; +} au1000_state; + +/* --------------------------------------------------------------------- */ + + +static inline unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* --------------------------------------------------------------------- */ + +static void au1000_delay(int msec) +{ + unsigned long tmo; + signed long tmo2; + + if (in_interrupt()) + return; + + tmo = jiffies + (msec * HZ) / 1000; + for (;;) { + tmo2 = tmo - jiffies; + if (tmo2 <= 0) + break; + schedule_timeout(tmo2); + } +} + + +/* --------------------------------------------------------------------- */ + +static u16 rdcodec(struct ac97_codec *codec, u8 addr) +{ + struct au1000_state *s = (struct au1000_state *)codec->private_data; + unsigned long flags; + u32 cmd; + u16 data; + int i; + + spin_lock_irqsave(&s->lock, flags); + + for (i = 0; i < POLL_COUNT; i++) + if (!(inl(AC97C_STATUS) & AC97C_CP)) + break; + if (i == POLL_COUNT) + err("rdcodec: codec cmd pending expired!"); + + cmd = (u32) addr & AC97C_INDEX_MASK; + cmd |= AC97C_READ; // read command + outl(cmd, AC97C_CMD); + + /* now wait for the data */ + for (i = 0; i < POLL_COUNT; i++) + if (!(inl(AC97C_STATUS) & AC97C_CP)) + break; + if (i == POLL_COUNT) { + err("rdcodec: read poll expired!"); + return 0; + } + + data = inl(AC97C_CMD) & 0xffff; + + spin_unlock_irqrestore(&s->lock, flags); + + return data; +} + + +static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) +{ + struct au1000_state *s = (struct au1000_state *)codec->private_data; + unsigned long flags; + u32 cmd; + int i; + + spin_lock_irqsave(&s->lock, flags); + + for (i = 0; i < POLL_COUNT; i++) + if (!(inl(AC97C_STATUS) & AC97C_CP)) + break; + if (i == POLL_COUNT) + err("wrcodec: codec cmd pending expired!"); + + cmd = (u32) addr & AC97C_INDEX_MASK; + cmd &= ~AC97C_READ; // write command + cmd |= ((u32) data << AC97C_WD_BIT); // OR in the data word + outl(cmd, AC97C_CMD); + + spin_unlock_irqrestore(&s->lock, flags); +} + +static void waitcodec(struct ac97_codec *codec) +{ + u16 temp; + int i; + + /* codec_wait is used to wait for a ready state after + an AC97C_RESET. */ + au1000_delay(10); + + // first poll the CODEC_READY tag bit + for (i = 0; i < POLL_COUNT; i++) + if (inl(AC97C_STATUS) & AC97C_READY) + break; + if (i == POLL_COUNT) { + err("waitcodec: CODEC_READY poll expired!"); + return; + } + // get AC'97 powerdown control/status register + temp = rdcodec(codec, AC97_POWER_CONTROL); + + // If anything is powered down, power'em up + if (temp & 0x7f00) { + // Power on + wrcodec(codec, AC97_POWER_CONTROL, 0); + au1000_delay(100); + // Reread + temp = rdcodec(codec, AC97_POWER_CONTROL); + } + + // Check if Codec REF,ANL,DAC,ADC ready + if ((temp & 0x7f0f) != 0x000f) + err("codec reg 26 status (0x%x) not ready!!", temp); +} + + +/* --------------------------------------------------------------------- */ + +static void set_adc_rate(struct au1000_state *s, unsigned rate) +{ + struct dmabuf *adc = &s->dma_adc; + struct dmabuf *dac = &s->dma_dac; + unsigned adc_rate, dac_rate; + u16 ac97_extstat; + + if (s->no_vra) { + // calc SRC factor + adc->src_factor = ((96000 / rate) + 1) >> 1; + adc->sample_rate = 48000 / adc->src_factor; + return; + } + + adc->src_factor = 1; + + ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); + + rate = rate > 48000 ? 48000 : rate; + + // enable VRA + wrcodec(&s->codec, AC97_EXTENDED_STATUS, + ac97_extstat | AC97_EXTSTAT_VRA); + // now write the sample rate + wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate); + // read it back for actual supported rate + adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE); + +#ifdef AU1000_VERBOSE_DEBUG + dbg(__FUNCTION__ ": set to %d Hz", adc_rate); +#endif + + // some codec's don't allow unequal DAC and ADC rates, in which case + // writing one rate reg actually changes both. + dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE); + if (dac->num_channels > 2) + wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate); + if (dac->num_channels > 4) + wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate); + + adc->sample_rate = adc_rate; + dac->sample_rate = dac_rate; +} + +static void set_dac_rate(struct au1000_state *s, unsigned rate) +{ + struct dmabuf *dac = &s->dma_dac; + struct dmabuf *adc = &s->dma_adc; + unsigned adc_rate, dac_rate; + u16 ac97_extstat; + + if (s->no_vra) { + // calc SRC factor + dac->src_factor = ((96000 / rate) + 1) >> 1; + dac->sample_rate = 48000 / dac->src_factor; + return; + } + + dac->src_factor = 1; + + ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); + + rate = rate > 48000 ? 48000 : rate; + + // enable VRA + wrcodec(&s->codec, AC97_EXTENDED_STATUS, + ac97_extstat | AC97_EXTSTAT_VRA); + // now write the sample rate + wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate); + // I don't support different sample rates for multichannel, + // so make these channels the same. + if (dac->num_channels > 2) + wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate); + if (dac->num_channels > 4) + wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate); + // read it back for actual supported rate + dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE); + +#ifdef AU1000_VERBOSE_DEBUG + dbg(__FUNCTION__ ": set to %d Hz", dac_rate); +#endif + + // some codec's don't allow unequal DAC and ADC rates, in which case + // writing one rate reg actually changes both. + adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE); + + dac->sample_rate = dac_rate; + adc->sample_rate = adc_rate; +} + +static void stop_dac(struct au1000_state *s) +{ + struct dmabuf *db = &s->dma_dac; + unsigned long flags; + + if (db->stopped) + return; + + spin_lock_irqsave(&s->lock, flags); + + disable_dma(db->dmanr); + + db->stopped = 1; + + spin_unlock_irqrestore(&s->lock, flags); +} + +static void stop_adc(struct au1000_state *s) +{ + struct dmabuf *db = &s->dma_adc; + unsigned long flags; + + if (db->stopped) + return; + + spin_lock_irqsave(&s->lock, flags); + + disable_dma(db->dmanr); + + db->stopped = 1; + + spin_unlock_irqrestore(&s->lock, flags); +} + + +static void set_xmit_slots(int num_channels) +{ + u32 ac97_config = inl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK; + + switch (num_channels) { + case 1: // mono + case 2: // stereo, slots 3,4 + ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT); + break; + case 4: // stereo with surround, slots 3,4,7,8 + ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT); + break; + case 6: // stereo with surround and center/LFE, slots 3,4,6,7,8,9 + ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT); + break; + } + + outl(ac97_config, AC97C_CONFIG); +} + +static void set_recv_slots(int num_channels) +{ + u32 ac97_config = inl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK; + + /* + * Always enable slots 3 and 4 (stereo). Slot 6 is + * optional Mic ADC, which I don't support yet. + */ + ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT); + + outl(ac97_config, AC97C_CONFIG); +} + +static void start_dac(struct au1000_state *s) +{ + struct dmabuf *db = &s->dma_dac; + unsigned long flags; + unsigned long buf1, buf2; + + if (!db->stopped) + return; + + spin_lock_irqsave(&s->lock, flags); + + inl(AC97C_STATUS); // read status to clear sticky bits + + // reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize + buf1 = virt_to_phys(db->nextOut); + buf2 = buf1 + db->dma_fragsize; + if (buf2 >= db->dmaaddr + db->dmasize) + buf2 -= db->dmasize; + + set_xmit_slots(db->num_channels); + + set_dma_count(db->dmanr, db->dma_fragsize>>1); + if (get_dma_active_buffer(db->dmanr) == 0) { + set_dma_addr0(db->dmanr, buf1); + set_dma_addr1(db->dmanr, buf2); + } else { + set_dma_addr1(db->dmanr, buf1); + set_dma_addr0(db->dmanr, buf2); + } + enable_dma_buffers(db->dmanr); + + enable_dma(db->dmanr); + +#ifdef AU1000_VERBOSE_DEBUG + dump_au1000_dma_channel(db->dmanr); +#endif + + db->stopped = 0; + + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_adc(struct au1000_state *s) +{ + struct dmabuf *db = &s->dma_adc; + unsigned long flags; + unsigned long buf1, buf2; + + if (!db->stopped) + return; + + spin_lock_irqsave(&s->lock, flags); + + inl(AC97C_STATUS); // read status to clear sticky bits + + // reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize + buf1 = virt_to_phys(db->nextIn); + buf2 = buf1 + db->dma_fragsize; + if (buf2 >= db->dmaaddr + db->dmasize) + buf2 -= db->dmasize; + + set_recv_slots(db->num_channels); + + set_dma_count(db->dmanr, db->dma_fragsize>>1); + if (get_dma_active_buffer(db->dmanr) == 0) { + set_dma_addr0(db->dmanr, buf1); + set_dma_addr1(db->dmanr, buf2); + } else { + set_dma_addr1(db->dmanr, buf1); + set_dma_addr0(db->dmanr, buf2); + } + enable_dma_buffers(db->dmanr); + + enable_dma(db->dmanr); + +#ifdef AU1000_VERBOSE_DEBUG + dump_au1000_dma_channel(db->dmanr); +#endif + + db->stopped = 0; + + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +extern inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db) +{ + struct page *page, *pend; + + if (db->rawbuf) { + /* undo marking the pages as reserved */ + pend = virt_to_page(db->rawbuf + + (PAGE_SIZE << db->buforder) - 1); + for (page = virt_to_page(db->rawbuf); page <= pend; page++) + mem_map_unreserve(page); + pci_free_consistent(NULL, PAGE_SIZE << db->buforder, + db->rawbuf, db->dmaaddr); + } + db->rawbuf = db->nextIn = db->nextOut = NULL; + db->mapped = db->ready = 0; +} + +static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db) +{ + int order; + unsigned user_bytes_per_sec; + unsigned bufs; + struct page *page, *pend; + unsigned rate = db->sample_rate; + + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; + order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = + pci_alloc_consistent(NULL, + PAGE_SIZE << order, + &db->dmaaddr))) + break; + if (!db->rawbuf) + return -ENOMEM; + db->buforder = order; + /* now mark the pages as reserved; + otherwise remap_page_range doesn't do what we want */ + pend = virt_to_page(db->rawbuf + + (PAGE_SIZE << db->buforder) - 1); + for (page = virt_to_page(db->rawbuf); page <= pend; page++) + mem_map_reserve(page); + } + + db->cnt_factor = 1; + if (db->sample_size == 8) + db->cnt_factor *= 2; + if (db->num_channels == 1) + db->cnt_factor *= 2; + db->cnt_factor *= db->src_factor; + + db->count = 0; + db->nextIn = db->nextOut = db->rawbuf; + + db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels; + db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ? + 2 : db->num_channels); + + user_bytes_per_sec = rate * db->user_bytes_per_sample; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < user_bytes_per_sec) + db->fragshift = ld2(user_bytes_per_sec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(user_bytes_per_sec / 100 / + (db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + + db->fragsize = 1 << db->fragshift; + db->dma_fragsize = db->fragsize * db->cnt_factor; + db->numfrag = bufs / db->dma_fragsize; + + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->fragsize = 1 << db->fragshift; + db->dma_fragsize = db->fragsize * db->cnt_factor; + db->numfrag = bufs / db->dma_fragsize; + } + + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + + db->dmasize = db->dma_fragsize * db->numfrag; + memset(db->rawbuf, 0, bufs); + +#ifdef AU1000_VERBOSE_DEBUG + dbg("rate=%d, samplesize=%d, channels=%d", + rate, db->sample_size, db->num_channels); + dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d", + db->fragsize, db->cnt_factor, db->dma_fragsize); + dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize); +#endif + + db->ready = 1; + return 0; +} + +extern inline int prog_dmabuf_adc(struct au1000_state *s) +{ + stop_adc(s); + return prog_dmabuf(s, &s->dma_adc); + +} + +extern inline int prog_dmabuf_dac(struct au1000_state *s) +{ + stop_dac(s); + return prog_dmabuf(s, &s->dma_dac); +} + + +/* hold spinlock for the following */ +static void dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct au1000_state *s = (struct au1000_state *) dev_id; + struct dmabuf *dac = &s->dma_dac; + unsigned long newptr; + u32 ac97c_stat, buff_done; + + ac97c_stat = inl(AC97C_STATUS); +#ifdef AU1000_VERBOSE_DEBUG + if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) + dbg("AC97C status = 0x%08x", ac97c_stat); +#endif + + if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) { + /* fastpath out, to ease interrupt sharing */ + return; + } + + if (buff_done != (DMA_D0 | DMA_D1)) { + dac->nextOut += dac->dma_fragsize; + if (dac->nextOut >= dac->rawbuf + dac->dmasize) + dac->nextOut -= dac->dmasize; + + /* update playback pointers */ + newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize; + if (newptr >= dac->dmaaddr + dac->dmasize) + newptr -= dac->dmasize; + + dac->count -= dac->dma_fragsize; + dac->total_bytes += dac->dma_fragsize; + + if (dac->count <= 0) + stop_dac(s); + else if (buff_done == DMA_D0) { + clear_dma_done0(dac->dmanr); // clear DMA done bit + set_dma_count0(dac->dmanr, dac->dma_fragsize>>1); + set_dma_addr0(dac->dmanr, newptr); + enable_dma_buffer0(dac->dmanr); // reenable + } else { + clear_dma_done1(dac->dmanr); // clear DMA done bit + set_dma_count1(dac->dmanr, dac->dma_fragsize>>1); + set_dma_addr1(dac->dmanr, newptr); + enable_dma_buffer1(dac->dmanr); // reenable + } + } else { + // both done bits set, we missed an interrupt + stop_dac(s); + + dac->nextOut += 2*dac->dma_fragsize; + if (dac->nextOut >= dac->rawbuf + dac->dmasize) + dac->nextOut -= dac->dmasize; + + dac->count -= 2*dac->dma_fragsize; + dac->total_bytes += 2*dac->dma_fragsize; + + if (dac->count > 0) + start_dac(s); + } + + + /* wake up anybody listening */ + if (waitqueue_active(&dac->wait)) + wake_up_interruptible(&dac->wait); +} + + +static void adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct au1000_state *s = (struct au1000_state *) dev_id; + struct dmabuf *adc = &s->dma_adc; + unsigned long newptr; + u32 ac97c_stat, buff_done; + + ac97c_stat = inl(AC97C_STATUS); +#ifdef AU1000_VERBOSE_DEBUG + if (ac97c_stat & (AC97C_RU | AC97C_RO)) + dbg("AC97C status = 0x%08x", ac97c_stat); +#endif + + if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) { + /* fastpath out, to ease interrupt sharing */ + return; + } + + if (buff_done != (DMA_D0 | DMA_D1)) { + if (adc->count + adc->dma_fragsize > adc->dmasize) { + // Overrun. Stop ADC and log the error + stop_adc(s); + adc->error++; + err("adc overrun"); + return; + } + + adc->nextIn += adc->dma_fragsize; + if (adc->nextIn >= adc->rawbuf + adc->dmasize) + adc->nextIn -= adc->dmasize; + + /* update capture pointers */ + newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize; + if (newptr >= adc->dmaaddr + adc->dmasize) + newptr -= adc->dmasize; + + adc->count += adc->dma_fragsize; + adc->total_bytes += adc->dma_fragsize; + + if (buff_done == DMA_D0) { + clear_dma_done0(adc->dmanr); // clear DMA done bit + set_dma_count0(adc->dmanr, adc->dma_fragsize>>1); + set_dma_addr0(adc->dmanr, newptr); + enable_dma_buffer0(adc->dmanr); // reenable + } else { + clear_dma_done1(adc->dmanr); // clear DMA done bit + set_dma_count1(adc->dmanr, adc->dma_fragsize>>1); + set_dma_addr1(adc->dmanr, newptr); + enable_dma_buffer1(adc->dmanr); // reenable + } + } else { + // both done bits set, we missed an interrupt + stop_adc(s); + + if (adc->count + 2*adc->dma_fragsize > adc->dmasize) { + // Overrun. Log the error + adc->error++; + err("adc overrun"); + return; + } + + adc->nextIn += 2*adc->dma_fragsize; + if (adc->nextIn >= adc->rawbuf + adc->dmasize) + adc->nextIn -= adc->dmasize; + + adc->count += 2*adc->dma_fragsize; + adc->total_bytes += 2*adc->dma_fragsize; + + start_adc(s); + } + + /* wake up anybody listening */ + if (waitqueue_active(&adc->wait)) + wake_up_interruptible(&adc->wait); +} + +/* --------------------------------------------------------------------- */ + +static int au1000_open_mixdev(struct inode *inode, struct file *file) +{ + file->private_data = &au1000_state; + return 0; +} + +static int au1000_release_mixdev(struct inode *inode, struct file *file) +{ + return 0; +} + +static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, + unsigned long arg) +{ + return codec->mixer_ioctl(codec, cmd, arg); +} + +static int au1000_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + struct ac97_codec *codec = &s->codec; + + return mixdev_ioctl(codec, cmd, arg); +} + +static /*const */ struct file_operations au1000_mixer_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + ioctl:au1000_ioctl_mixdev, + open:au1000_open_mixdev, + release:au1000_release_mixdev, +}; + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct au1000_state *s, int nonblock) +{ + unsigned long flags; + int count, tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) + return 0; + + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) + return -EBUSY; + tmo = 1000 * count / (s->no_vra ? + 48000 : s->dma_dac.sample_rate); + tmo /= s->dma_dac.dma_bytes_per_sample; + au1000_delay(tmo); + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static inline u8 S16_TO_U8(s16 ch) +{ + return (u8) (ch >> 8) + 0x80; +} +static inline s16 U8_TO_S16(u8 ch) +{ + return (s16) (ch - 0x80) << 8; +} + +/* + * Translates user samples to dma buffer suitable for AC'97 DAC data: + * If mono, copy left channel to right channel in dma buffer. + * If 8 bit samples, cvt to 16-bit before writing to dma buffer. + * If interpolating (no VRA), duplicate every audio frame src_factor times. + */ +static int translate_from_user(struct dmabuf *db, + char* dmabuf, + char* userbuf, + int dmacount) +{ + int sample, i; + int interp_bytes_per_sample; + int num_samples; + int mono = (db->num_channels == 1); + char usersample[12]; + s16 ch, dmasample[6]; + + if (db->sample_size == 16 && !mono && db->src_factor == 1) { + // no translation necessary, just copy + if (copy_from_user(dmabuf, userbuf, dmacount)) + return -EFAULT; + return dmacount; + } + + interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; + num_samples = dmacount / interp_bytes_per_sample; + + for (sample = 0; sample < num_samples; sample++) { + if (copy_from_user(usersample, userbuf, + db->user_bytes_per_sample)) { + dbg(__FUNCTION__ "fault"); + return -EFAULT; + } + + for (i = 0; i < db->num_channels; i++) { + if (db->sample_size == 8) + ch = U8_TO_S16(usersample[i]); + else + ch = *((s16 *) (&usersample[i * 2])); + dmasample[i] = ch; + if (mono) + dmasample[i + 1] = ch; // right channel + } + + // duplicate every audio frame src_factor times + for (i = 0; i < db->src_factor; i++) + memcpy(dmabuf, dmasample, db->dma_bytes_per_sample); + + userbuf += db->user_bytes_per_sample; + dmabuf += interp_bytes_per_sample; + } + + return num_samples * interp_bytes_per_sample; +} + +/* + * Translates AC'97 ADC samples to user buffer: + * If mono, send only left channel to user buffer. + * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer. + * If decimating (no VRA), skip over src_factor audio frames. + */ +static int translate_to_user(struct dmabuf *db, + char* userbuf, + char* dmabuf, + int dmacount) +{ + int sample, i; + int interp_bytes_per_sample; + int num_samples; + int mono = (db->num_channels == 1); + char usersample[12]; + + if (db->sample_size == 16 && !mono && db->src_factor == 1) { + // no translation necessary, just copy + if (copy_to_user(userbuf, dmabuf, dmacount)) + return -EFAULT; + return dmacount; + } + + interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; + num_samples = dmacount / interp_bytes_per_sample; + + for (sample = 0; sample < num_samples; sample++) { + for (i = 0; i < db->num_channels; i++) { + if (db->sample_size == 8) + usersample[i] = + S16_TO_U8(*((s16 *) (&dmabuf[i * 2]))); + else + *((s16 *) (&usersample[i * 2])) = + *((s16 *) (&dmabuf[i * 2])); + } + + if (copy_to_user(userbuf, usersample, + db->user_bytes_per_sample)) { + dbg(__FUNCTION__ "fault"); + return -EFAULT; + } + + userbuf += db->user_bytes_per_sample; + dmabuf += interp_bytes_per_sample; + } + + return num_samples * interp_bytes_per_sample; +} + +/* + * Copy audio data to/from user buffer from/to dma buffer, taking care + * that we wrap when reading/writing the dma buffer. Returns actual byte + * count written to or read from the dma buffer. + */ +static int copy_dmabuf_user(struct dmabuf *db, char* userbuf, + int count, int to_user) +{ + char *bufptr = to_user ? db->nextOut : db->nextIn; + char *bufend = db->rawbuf + db->dmasize; + int cnt, ret; + + if (bufptr + count > bufend) { + int partial = (int) (bufend - bufptr); + if (to_user) { + if ((cnt = translate_to_user(db, userbuf, + bufptr, partial)) < 0) + return cnt; + ret = cnt; + if ((cnt = translate_to_user(db, userbuf + partial, + db->rawbuf, + count - partial)) < 0) + return cnt; + ret += cnt; + } else { + if ((cnt = translate_from_user(db, bufptr, userbuf, + partial)) < 0) + return cnt; + ret = cnt; + if ((cnt = translate_from_user(db, db->rawbuf, + userbuf + partial, + count - partial)) < 0) + return cnt; + ret += cnt; + } + } else { + if (to_user) + ret = translate_to_user(db, userbuf, bufptr, count); + else + ret = translate_from_user(db, bufptr, userbuf, count); + } + + return ret; +} + + +static ssize_t au1000_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + struct dmabuf *db = &s->dma_adc; + ssize_t ret; + unsigned long flags; + int cnt, remainder, usercnt, avail; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (db->mapped) + return -ENXIO; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + count *= db->cnt_factor; + + while (count > 0) { + // wait for samples in ADC dma buffer + do { + if (db->stopped) + start_adc(s); + spin_lock_irqsave(&s->lock, flags); + avail = db->count; + spin_unlock_irqrestore(&s->lock, flags); + if (avail <= 0) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + return ret; + } + interruptible_sleep_on(&db->wait); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + return ret; + } + } + } while (avail <= 0); + + // copy from nextOut to user + if ((cnt = copy_dmabuf_user(db, buffer, + count > avail ? + avail : count, 1)) < 0) { + if (!ret) + ret = -EFAULT; + return ret; + } + + spin_lock_irqsave(&s->lock, flags); + db->count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + + db->nextOut += cnt; + if (db->nextOut >= db->rawbuf + db->dmasize) + db->nextOut -= db->dmasize; + + count -= cnt; + usercnt = cnt / db->cnt_factor; + buffer += usercnt; + ret += usercnt; + } // while (count > 0) + + /* + * See if the dma buffer count after this read call is + * aligned on a dma_fragsize boundary. If not, read from + * buffer until we reach a boundary, and let's hope this + * is just the last remainder of an audio record. If not + * it means the user is not reading in fragsize chunks, in + * which case it's his/her fault that there are audio gaps + * in their record. + */ + spin_lock_irqsave(&s->lock, flags); + remainder = db->count % db->dma_fragsize; + if (remainder) { + db->nextOut += remainder; + if (db->nextOut >= db->rawbuf + db->dmasize) + db->nextOut -= db->dmasize; + db->count -= remainder; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +} + +static ssize_t au1000_write(struct file *file, const char *buffer, + size_t count, loff_t * ppos) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + struct dmabuf *db = &s->dma_dac; + ssize_t ret = 0; + unsigned long flags; + int cnt, remainder, usercnt, avail; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (db->mapped) + return -ENXIO; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + + count *= db->cnt_factor; + + while (count > 0) { + // wait for space in playback buffer + do { + spin_lock_irqsave(&s->lock, flags); + avail = (int) db->dmasize - db->count; + spin_unlock_irqrestore(&s->lock, flags); + if (avail <= 0) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + return ret; + } + interruptible_sleep_on(&db->wait); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + return ret; + } + } + } while (avail <= 0); + + // copy to nextIn + if ((cnt = copy_dmabuf_user(db, (char *) buffer, + count > avail ? + avail : count, 0)) < 0) { + if (!ret) + ret = -EFAULT; + return ret; + } + + spin_lock_irqsave(&s->lock, flags); + db->count += cnt; + spin_unlock_irqrestore(&s->lock, flags); + if (db->stopped) + start_dac(s); + + db->nextIn += cnt; + if (db->nextIn >= db->rawbuf + db->dmasize) + db->nextIn -= db->dmasize; + + count -= cnt; + usercnt = cnt / db->cnt_factor; + buffer += usercnt; + ret += usercnt; + } // while (count > 0) + + /* + * See if the dma buffer count after this write call is + * aligned on a dma_fragsize boundary. If not, fill buffer + * with silence to the next boundary, and let's hope this + * is just the last remainder of an audio playback. If not + * it means the user is not sending us fragsize chunks, in + * which case it's his/her fault that there are audio gaps + * in their playback. + */ + spin_lock_irqsave(&s->lock, flags); + remainder = db->count % db->dma_fragsize; + if (remainder) { + int fill_cnt = db->dma_fragsize - remainder; + memset(db->nextIn, 0, fill_cnt); + db->nextIn += fill_cnt; + if (db->nextIn >= db->rawbuf + db->dmasize) + db->nextIn -= db->dmasize; + db->count += fill_cnt; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +} + + +/* No kernel lock - we have our own spinlock */ +static unsigned int au1000_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) { + if (!s->dma_dac.ready) + return 0; + poll_wait(file, &s->dma_dac.wait, wait); + } + if (file->f_mode & FMODE_READ) { + if (!s->dma_adc.ready) + return 0; + poll_wait(file, &s->dma_adc.wait, wait); + } + + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= + (signed)s->dma_dac.dma_fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed) s->dma_dac.dmasize >= + s->dma_dac.count + (signed)s->dma_dac.dma_fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int au1000_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + struct dmabuf *db; + unsigned long size; + + dbg(__FUNCTION__); + + lock_kernel(); + if (vma->vm_flags & VM_WRITE) + db = &s->dma_dac; + else if (vma->vm_flags & VM_READ) + db = &s->dma_adc; + else { + unlock_kernel(); + return -EINVAL; + } + if (vma->vm_pgoff != 0) { + unlock_kernel(); + return -EINVAL; + } + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) { + unlock_kernel(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), + size, vma->vm_page_prot)) { + unlock_kernel(); + return -EAGAIN; + } + db->mapped = 1; + unlock_kernel(); + return 0; +} + + +#ifdef AU1000_VERBOSE_DEBUG +static struct ioctl_str_t { + unsigned int cmd; + const char *str; +} ioctl_str[] = { + {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, + {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, + {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, + {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, + {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, + {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, + {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, + {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, + {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, + {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, + {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, + {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, + {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, + {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, + {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, + {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, + {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, + {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, + {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, + {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, + {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, + {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, + {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, + {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, + {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, + {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, + {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, + {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, + {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, + {OSS_GETVERSION, "OSS_GETVERSION"}, + {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, + {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, + {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, + {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} +}; +#endif + +// Need to hold a spin-lock before calling this! +static int dma_count_done(struct dmabuf *db) +{ + if (db->stopped) + return 0; + + return db->dma_fragsize - get_dma_residue(db->dmanr); +} + + +static int au1000_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int count; + int val, mapped, ret, diff; + + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + +#ifdef AU1000_VERBOSE_DEBUG + for (count=0; countf_mode & FMODE_WRITE) + return drain_dac(s, file->f_flags & O_NONBLOCK); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | + DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.count = s->dma_dac.total_bytes = 0; + s->dma_dac.nextIn = s->dma_dac.nextOut = + s->dma_dac.rawbuf; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.count = s->dma_adc.total_bytes = 0; + s->dma_adc.nextIn = s->dma_adc.nextOut = + s->dma_adc.rawbuf; + } + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + set_dac_rate(s, val); + } + if (s->open_mode & FMODE_READ) + if ((ret = prog_dmabuf_adc(s))) + return ret; + if (s->open_mode & FMODE_WRITE) + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return put_user((file->f_mode & FMODE_READ) ? + s->dma_adc.sample_rate : + s->dma_dac.sample_rate, + (int *)arg); + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.num_channels = val ? 2 : 1; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.num_channels = val ? 2 : 1; + if (s->codec_ext_caps & AC97_EXT_DACS) { + // disable surround and center/lfe in AC'97 + u16 ext_stat = rdcodec(&s->codec, + AC97_EXTENDED_STATUS); + wrcodec(&s->codec, AC97_EXTENDED_STATUS, + ext_stat | (AC97_EXTSTAT_PRI | + AC97_EXTSTAT_PRJ | + AC97_EXTSTAT_PRK)); + } + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != 0) { + if (file->f_mode & FMODE_READ) { + if (val < 0 || val > 2) + return -EINVAL; + stop_adc(s); + s->dma_adc.num_channels = val; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + switch (val) { + case 1: + case 2: + break; + case 3: + case 5: + return -EINVAL; + case 4: + if (!(s->codec_ext_caps & + AC97_EXTID_SDAC)) + return -EINVAL; + break; + case 6: + if ((s->codec_ext_caps & + AC97_EXT_DACS) != AC97_EXT_DACS) + return -EINVAL; + break; + default: + return -EINVAL; + } + + stop_dac(s); + if (val <= 2 && + (s->codec_ext_caps & AC97_EXT_DACS)) { + // disable surround and center/lfe + // channels in AC'97 + u16 ext_stat = + rdcodec(&s->codec, + AC97_EXTENDED_STATUS); + wrcodec(&s->codec, + AC97_EXTENDED_STATUS, + ext_stat | (AC97_EXTSTAT_PRI | + AC97_EXTSTAT_PRJ | + AC97_EXTSTAT_PRK)); + } else if (val >= 4) { + // enable surround, center/lfe + // channels in AC'97 + u16 ext_stat = + rdcodec(&s->codec, + AC97_EXTENDED_STATUS); + ext_stat &= ~AC97_EXTSTAT_PRJ; + if (val == 6) + ext_stat &= + ~(AC97_EXTSTAT_PRI | + AC97_EXTSTAT_PRK); + wrcodec(&s->codec, + AC97_EXTENDED_STATUS, + ext_stat); + } + + s->dma_dac.num_channels = val; + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + } + return put_user(val, (int *) arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + if (val == AFMT_S16_LE) + s->dma_adc.sample_size = 16; + else { + val = AFMT_U8; + s->dma_adc.sample_size = 8; + } + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + if (val == AFMT_S16_LE) + s->dma_dac.sample_size = 16; + else { + val = AFMT_U8; + s->dma_dac.sample_size = 8; + } + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + } else { + if (file->f_mode & FMODE_READ) + val = (s->dma_adc.sample_size == 16) ? + AFMT_S16_LE : AFMT_U8; + else + val = (s->dma_dac.sample_size == 16) ? + AFMT_S16_LE : AFMT_U8; + } + return put_user(val, (int *) arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) + val |= PCM_ENABLE_OUTPUT; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) + start_adc(s); + else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) + start_dac(s); + else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + abinfo.fragsize = s->dma_dac.fragsize; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + count -= dma_count_done(&s->dma_dac); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + abinfo.bytes = (s->dma_dac.dmasize - count) / + s->dma_dac.cnt_factor; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + abinfo.fragsize = s->dma_adc.fragsize; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_adc.count; + count += dma_count_done(&s->dma_adc); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + abinfo.bytes = count / s->dma_adc.cnt_factor; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + count -= dma_count_done(&s->dma_dac); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + count /= s->dma_dac.cnt_factor; + return put_user(count, (int *) arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_adc.total_bytes; + count = s->dma_adc.count; + if (!s->dma_adc.stopped) { + diff = dma_count_done(&s->dma_adc); + count += diff; + cinfo.bytes += diff; + cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff - + s->dma_adc.dmaaddr; + } else + cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) - + s->dma_adc.dmaaddr; + if (s->dma_adc.mapped) + s->dma_adc.count &= (s->dma_adc.dma_fragsize-1); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_dac.total_bytes; + count = s->dma_dac.count; + if (!s->dma_dac.stopped) { + diff = dma_count_done(&s->dma_dac); + count -= diff; + cinfo.bytes += diff; + cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff - + s->dma_dac.dmaaddr; + } else + cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) - + s->dma_dac.dmaaddr; + if (s->dma_dac.mapped) + s->dma_dac.count &= (s->dma_dac.dma_fragsize-1); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) + return put_user(s->dma_dac.fragsize, (int *) arg); + else + return put_user(s->dma_adc.fragsize, (int *) arg); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.subdivision = val; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.subdivision = val; + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? + s->dma_adc.sample_rate : + s->dma_dac.sample_rate, + (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + if (file->f_mode & FMODE_READ) + return put_user(s->dma_adc.num_channels, (int *)arg); + else + return put_user(s->dma_dac.num_channels, (int *)arg); + + case SOUND_PCM_READ_BITS: + if (file->f_mode & FMODE_READ) + return put_user(s->dma_adc.sample_size, (int *)arg); + else + return put_user(s->dma_dac.sample_size, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + + return mixdev_ioctl(&s->codec, cmd, arg); +} + + +static int au1000_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + struct au1000_state *s = &au1000_state; + int ret; + +#ifdef AU1000_VERBOSE_DEBUG + if (file->f_flags & O_NONBLOCK) + dbg(__FUNCTION__ ": non-blocking"); + else + dbg(__FUNCTION__ ": blocking"); +#endif + + file->private_data = s; + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EBUSY; + } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + up(&s->open_sem); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + + stop_dac(s); + stop_adc(s); + + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = + s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; + s->dma_adc.num_channels = 1; + s->dma_adc.sample_size = 8; + set_adc_rate(s, 8000); + if ((minor & 0xf) == SND_DEV_DSP16) + s->dma_adc.sample_size = 16; + } + + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = + s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; + s->dma_dac.num_channels = 1; + s->dma_dac.sample_size = 8; + set_dac_rate(s, 8000); + if ((minor & 0xf) == SND_DEV_DSP16) + s->dma_dac.sample_size = 16; + } + + if (file->f_mode & FMODE_READ) { + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&s->open_sem); + return 0; +} + +static int au1000_release(struct inode *inode, struct file *file) +{ + struct au1000_state *s = (struct au1000_state *)file->private_data; + + lock_kernel(); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(s, &s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(s, &s->dma_adc); + } + s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); + up(&s->open_sem); + wake_up(&s->open_wait); + unlock_kernel(); + return 0; +} + +static /*const */ struct file_operations au1000_audio_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: au1000_read, + write: au1000_write, + poll: au1000_poll, + ioctl: au1000_ioctl, + mmap: au1000_mmap, + open: au1000_open, + release: au1000_release, +}; + + +/* --------------------------------------------------------------------- */ + + +/* --------------------------------------------------------------------- */ + +/* + * for debugging purposes, we'll create a proc device that dumps the + * CODEC chipstate + */ + +#ifdef AU1000_DEBUG +static int proc_au1000_dump(char *buf, char **start, off_t fpos, + int length, int *eof, void *data) +{ + struct au1000_state *s = &au1000_state; + int cnt, len = 0; + + /* print out header */ + len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n"); + + // print out digital controller state + len += sprintf(buf + len, "AU1000 Audio Controller registers\n"); + len += sprintf(buf + len, "---------------------------------\n"); + len += sprintf (buf + len, "AC97C_CONFIG = %08x\n", inl(AC97C_CONFIG)); + len += sprintf (buf + len, "AC97C_STATUS = %08x\n", inl(AC97C_STATUS)); + len += sprintf (buf + len, "AC97C_CNTRL = %08x\n", inl(AC97C_CNTRL)); + + /* print out CODEC state */ + len += sprintf(buf + len, "\nAC97 CODEC registers\n"); + len += sprintf(buf + len, "----------------------\n"); + for (cnt = 0; cnt <= 0x7e; cnt += 2) + len += sprintf(buf + len, "reg %02x = %04x\n", + cnt, rdcodec(&s->codec, cnt)); + + if (fpos >= len) { + *start = buf; + *eof = 1; + return 0; + } + *start = buf + fpos; + if ((len -= fpos) > length) + return length; + *eof = 1; + return len; + +} +#endif /* AU1000_DEBUG */ + +/* --------------------------------------------------------------------- */ + +MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com"); +MODULE_DESCRIPTION("Au1000 Audio Driver"); + +/* --------------------------------------------------------------------- */ + +static int __devinit au1000_probe(void) +{ + struct au1000_state *s = &au1000_state; + int val; + char proc_str[80]; + + memset(s, 0, sizeof(struct au1000_state)); + + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->codec.private_data = s; + s->codec.id = 0; + s->codec.codec_read = rdcodec; + s->codec.codec_write = wrcodec; + s->codec.codec_wait = waitcodec; + + if (!request_region(virt_to_phys((void *) AC97C_CONFIG), + 0x14, AU1000_MODULE_NAME)) { + err("AC'97 ports in use"); + return -1; + } + // Allocate the DMA Channels + if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX, + "audio DAC")) < 0) { + err("Can't get DAC DMA"); + goto err_dma1; + } + if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX, + "audio ADC")) < 0) { + err("Can't get ADC DMA"); + goto err_dma2; + } + + s->dma_dac.irq = get_dma_done_irq(s->dma_dac.dmanr); + s->dma_adc.irq = get_dma_done_irq(s->dma_adc.dmanr); + + if (request_irq(s->dma_dac.irq, dac_dma_interrupt, + SA_INTERRUPT, "audio DAC", s)) { + err("Can't get DAC irq #%d", s->dma_dac.irq); + goto err_irq1; + } + if (request_irq(s->dma_adc.irq, adc_dma_interrupt, + SA_INTERRUPT, "audio ADC", s)) { + err("Can't get ADC irq #%d", s->dma_adc.irq); + goto err_irq2; + } + + info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d", + s->dma_dac.dmanr, s->dma_dac.irq, + s->dma_adc.dmanr, s->dma_adc.irq); + + /* register devices */ + + if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->codec.dev_mixer = + register_sound_mixer(&au1000_mixer_fops, -1)) < 0) + goto err_dev2; + +#ifdef AU1000_DEBUG + /* intialize the debug proc device */ + s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL, + proc_au1000_dump, NULL); +#endif /* AU1000_DEBUG */ + + // configure pins for AC'97 + outl(inl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); + + // Assert reset for 10msec to the AC'97 controller, and enable clock + outl(AC97C_RS | AC97C_CE, AC97C_CNTRL); + au1000_delay(10); + outl(AC97C_CE, AC97C_CNTRL); + au1000_delay(10); // wait for clock to stabilize + + /* cold reset the AC'97 */ + outl(AC97C_RESET, AC97C_CONFIG); + au1000_delay(10); + outl(0, AC97C_CONFIG); + /* need to delay around 500msec(bleech) to give + some CODECs enough time to wakeup */ + au1000_delay(500); + + /* warm reset the AC'97 to start the bitclk */ + outl(AC97C_SG | AC97C_SYNC, AC97C_CONFIG); + udelay(100); + outl(0, AC97C_CONFIG); + + /* codec init */ + if (!ac97_probe_codec(&s->codec)) + goto err_dev3; + + s->codec_base_caps = rdcodec(&s->codec, AC97_RESET); + s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID); + info("AC'97 Base/Extended ID = %04x/%04x", + s->codec_base_caps, s->codec_ext_caps); + + /* + * On the Pb1000, audio playback is on the AUX_OUT + * channel (which defaults to LNLVL_OUT in AC'97 + * rev 2.2) so make sure this channel is listed + * as supported (soundcard.h calls this channel + * ALTPCM). ac97_codec.c does not handle detection + * of this channel correctly. + */ + s->codec.supported_mixers |= SOUND_MASK_ALTPCM; + /* + * Now set AUX_OUT's default volume. + */ + val = 0x4343; + mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM, + (unsigned long) &val); + + if (!(s->codec_ext_caps & AC97_EXTID_VRA)) { + // codec does not support VRA + s->no_vra = 1; + } else if (!vra) { + // Boot option says disable VRA + u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS); + wrcodec(&s->codec, AC97_EXTENDED_STATUS, + ac97_extstat & ~AC97_EXTSTAT_VRA); + s->no_vra = 1; + } + if (s->no_vra) + info("no VRA, interpolating and decimating"); + + /* set mic to be the recording source */ + val = SOUND_MASK_MIC; + mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, + (unsigned long) &val); + +#ifdef AU1000_DEBUG + sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME, + s->codec.id); + s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, + ac97_read_proc, &s->codec); +#endif + + return 0; + + err_dev3: + unregister_sound_mixer(s->codec.dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + free_au1000_dma(s->dma_adc.dmanr); + err_dma2: + free_au1000_dma(s->dma_dac.dmanr); + err_dma1: + free_irq(s->dma_adc.irq, s); + err_irq2: + free_irq(s->dma_dac.irq, s); + err_irq1: + release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14); + return -1; +} + +static void __devinit au1000_remove(void) +{ + struct au1000_state *s = &au1000_state; + + if (!s) + return; +#ifdef AU1000_DEBUG + if (s->ps) + remove_proc_entry(AU1000_MODULE_NAME, NULL); +#endif /* AU1000_DEBUG */ + synchronize_irq(); + free_irq(s->dma_adc.irq, s); + free_irq(s->dma_dac.irq, s); + free_au1000_dma(s->dma_adc.dmanr); + free_au1000_dma(s->dma_dac.dmanr); + release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->codec.dev_mixer); +} + +static int __init init_au1000(void) +{ + info("stevel@mvista.com, built " __TIME__ " on " __DATE__); + return au1000_probe(); +} + +static void __exit cleanup_au1000(void) +{ + info("unloading"); + au1000_remove(); +} + +module_init(init_au1000); +module_exit(cleanup_au1000); + +/* --------------------------------------------------------------------- */ + +#ifndef MODULE + +static int __init au1000_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for(this_opt=strtok(options, ","); + this_opt; this_opt=strtok(NULL, ",")) { + if (!strncmp(this_opt, "vra", 3)) { + vra = 1; + } + } + + return 1; +} + +__setup("au1000_audio=", au1000_setup); + +#endif /* MODULE */ diff -urN linux-2.4.18/drivers/sound/btaudio.c linux-2.4.19-pre5/drivers/sound/btaudio.c --- linux-2.4.18/drivers/sound/btaudio.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/btaudio.c Sat Mar 30 22:55:29 2002 @@ -1,7 +1,7 @@ /* btaudio - bt878 audio dma driver for linux 2.4.x - (c) 2000 Gerd Knorr + (c) 2000-2002 Gerd Knorr 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 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -300,7 +301,7 @@ static int btaudio_mixer_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -459,7 +460,7 @@ static int btaudio_dsp_open_digital(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -475,7 +476,7 @@ static int btaudio_dsp_open_analog(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -682,7 +683,7 @@ return put_user((bta->channels)-1, (int *)arg); case SNDCTL_DSP_CHANNELS: - if (!analog) { + if (!bta->analog) { if (get_user(val, (int*)arg)) return -EFAULT; bta->channels = (val > 1) ? 2 : 1; @@ -697,7 +698,7 @@ return put_user(bta->channels, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - if (analog) + if (bta->analog) return put_user(AFMT_S16_LE|AFMT_S8, (int*)arg); else return put_user(AFMT_S16_LE, (int*)arg); @@ -706,7 +707,7 @@ if (get_user(val, (int*)arg)) return -EFAULT; if (val != AFMT_QUERY) { - if (analog) + if (bta->analog) bta->bits = (val == AFMT_S8) ? 8 : 16; else bta->bits = 16; @@ -783,7 +784,7 @@ poll_wait(file, &bta->readq, wait); - if (0 == bta->read_count) + if (0 != bta->read_count) mask |= (POLLIN | POLLRDNORM); return mask; @@ -886,10 +887,8 @@ bta = kmalloc(sizeof(*bta),GFP_ATOMIC); if (!bta) { - printk(KERN_WARNING - "btaudio: not enough memory\n"); rc = -ENOMEM; - goto fail1; + goto fail0; } memset(bta,0,sizeof(*bta)); @@ -942,6 +941,8 @@ "btaudio: can't register digital dsp (rc=%d)\n",rc); goto fail2; } + printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n", + bta->dsp_digital >> 4); } if (analog) { rc = bta->dsp_analog = @@ -951,16 +952,17 @@ "btaudio: can't register analog dsp (rc=%d)\n",rc); goto fail3; } + printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n", + bta->dsp_analog >> 4); rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer); if (rc < 0) { printk(KERN_WARNING "btaudio: can't register mixer (rc=%d)\n",rc); goto fail4; } + printk(KERN_INFO "btaudio: registered device mixer%d\n", + bta->mixer_dev >> 4); } - if (debug) - printk(KERN_DEBUG "btaudio: minors: digital=%d, analog=%d, mixer=%d\n", - bta->dsp_digital, bta->dsp_analog, bta->mixer_dev); /* hook into linked list */ bta->next = btaudios; @@ -977,9 +979,10 @@ fail2: free_irq(bta->irq,bta); fail1: + kfree(bta); + fail0: release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); - kfree(bta); return rc; } @@ -1039,16 +1042,16 @@ remove: __devexit_p(btaudio_remove), }; -int btaudio_init_module(void) +static int btaudio_init_module(void) { printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n", - analog ? "analog" : "", + digital ? "digital" : "", analog && digital ? "+" : "", - digital ? "digital" : ""); + analog ? "analog" : ""); return pci_module_init(&btaudio_pci_driver); } -void btaudio_cleanup_module(void) +static void btaudio_cleanup_module(void) { pci_unregister_driver(&btaudio_pci_driver); return; diff -urN linux-2.4.18/drivers/sound/cs4281/cs4281_wrapper.h linux-2.4.19-pre5/drivers/sound/cs4281/cs4281_wrapper.h --- linux-2.4.18/drivers/sound/cs4281/cs4281_wrapper.h Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/cs4281/cs4281_wrapper.h Sat Mar 30 22:55:35 2002 @@ -28,7 +28,7 @@ #define __CS4281_WRAPPER_H /* 2.4.x wrapper */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,12) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9) static int cs4281_null_suspend(struct pci_dev *pcidev, u32 unused) { return 0; } static int cs4281_null_resume(struct pci_dev *pcidev) { return 0; } #else diff -urN linux-2.4.18/drivers/sound/cs4281/cs4281m.c linux-2.4.19-pre5/drivers/sound/cs4281/cs4281m.c --- linux-2.4.18/drivers/sound/cs4281/cs4281m.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/cs4281/cs4281m.c Sat Mar 30 22:55:35 2002 @@ -2628,17 +2628,6 @@ } } - -// --------------------------------------------------------------------- - -static loff_t cs4281_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - -// --------------------------------------------------------------------- - static int cs4281_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); @@ -2694,7 +2683,7 @@ // Mixer file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_mixer_fops = { - llseek:cs4281_llseek, + llseek:no_llseek, ioctl:cs4281_ioctl_mixdev, open:cs4281_open_mixdev, release:cs4281_release_mixdev, @@ -3835,7 +3824,7 @@ // Wave (audio) file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_audio_fops = { - llseek:cs4281_llseek, + llseek:no_llseek, read:cs4281_read, write:cs4281_write, poll:cs4281_poll, @@ -4184,7 +4173,7 @@ // Midi file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_midi_fops = { - llseek:cs4281_llseek, + llseek:no_llseek, read:cs4281_midi_read, write:cs4281_midi_write, poll:cs4281_midi_poll, diff -urN linux-2.4.18/drivers/sound/dmasound/dmasound.h linux-2.4.19-pre5/drivers/sound/dmasound/dmasound.h --- linux-2.4.18/drivers/sound/dmasound/dmasound.h Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/dmasound/dmasound.h Sat Mar 30 22:55:35 2002 @@ -252,17 +252,14 @@ #define WAKE_UP(queue) (wake_up_interruptible(&queue)) extern struct sound_queue dmasound_write_sq; -#ifdef HAS_RECORD -extern struct sound_queue dmasound_read_sq; -#endif - #define write_sq dmasound_write_sq + #ifdef HAS_RECORD +extern struct sound_queue dmasound_read_sq; #define read_sq dmasound_read_sq #endif extern int dmasound_catchRadius; - #define catchRadius dmasound_catchRadius /* define the value to be put in the byte-swap reg in mac-io diff -urN linux-2.4.18/drivers/sound/dmasound/dmasound_atari.c linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_atari.c --- linux-2.4.18/drivers/sound/dmasound/dmasound_atari.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_atari.c Sat Mar 30 22:55:35 2002 @@ -143,7 +143,7 @@ static int AtaMixerIoctl(u_int cmd, u_long arg); static int TTMixerIoctl(u_int cmd, u_long arg); static int FalconMixerIoctl(u_int cmd, u_long arg); -static void AtaWriteSqSetup(void); +static int AtaWriteSqSetup(void); static int AtaSqOpen(mode_t mode); static int TTStateInfo(char *buffer, size_t space); static int FalconStateInfo(char *buffer, size_t space); diff -urN linux-2.4.18/drivers/sound/dmasound/dmasound_core.c linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_core.c --- linux-2.4.18/drivers/sound/dmasound/dmasound_core.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_core.c Sat Mar 30 22:55:35 2002 @@ -195,20 +195,20 @@ */ int dmasound_catchRadius = 0; -static unsigned int numWriteBufs = DEFAULT_N_BUFFERS; -static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */ -#ifdef HAS_RECORD -static unsigned int numReadBufs = DEFAULT_N_BUFFERS; -static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */ -#endif - MODULE_PARM(dmasound_catchRadius, "i"); + +static unsigned int numWriteBufs = DEFAULT_N_BUFFERS; MODULE_PARM(numWriteBufs, "i"); +static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */ MODULE_PARM(writeBufSize, "i"); + #ifdef HAS_RECORD +static unsigned int numReadBufs = DEFAULT_N_BUFFERS; MODULE_PARM(numReadBufs, "i"); +static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */ MODULE_PARM(readBufSize, "i"); #endif + MODULE_LICENSE("GPL"); #ifdef MODULE @@ -396,12 +396,9 @@ */ struct sound_queue dmasound_write_sq; -#ifdef HAS_RECORD -struct sound_queue dmasound_read_sq; -#endif - static void sq_reset_output(void) ; #ifdef HAS_RECORD +struct sound_queue dmasound_read_sq; static void sq_reset_input(void) ; #endif @@ -444,7 +441,7 @@ static int sq_setup(struct sound_queue *sq) { - int (*setup_func)(void); + int (*setup_func)(void) = 0; int hard_frame ; if (sq->locked) { /* are we already set? - and not changeable */ @@ -548,7 +545,7 @@ { ssize_t uWritten = 0; u_char *dest; - ssize_t uUsed, bUsed, bLeft; + ssize_t uUsed = 0, bUsed, bLeft; unsigned long flags ; /* ++TeSche: Is something like this necessary? @@ -859,6 +856,13 @@ #define read_sq_release_buffers() sq_release_buffers(&read_sq) #define read_sq_open(file) \ sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize ) +#else +#define read_sq_init_waitqueue() do {} while (0) +#if 0 /* blocking open() */ +#define read_sq_wake_up(file) do {} while (0) +#endif +#define read_sq_release_buffers() do {} while (0) +#define sq_reset_input() do {} while (0) #endif static int sq_open(struct inode *inode, struct file *file) @@ -981,9 +985,7 @@ static void sq_reset(void) { sq_reset_output() ; -#ifdef HAS_RECORD sq_reset_input() ; -#endif /* we could consider resetting the shared_resources_owner here... but I think it is probably still rather non-obvious to application writer */ @@ -1058,9 +1060,7 @@ /* Iain: hmm I don't understand this next comment ... */ /* There is probably a DOS atack here. They change the mode flag. */ /* XXX add check here,*/ -#ifdef HAS_RECORD read_sq_wake_up(file); /* checks f_mode */ -#endif write_sq_wake_up(file); /* checks f_mode */ #endif /* blocking open() */ @@ -1200,10 +1200,8 @@ everything - read, however, is killed imediately. */ result = 0 ; -#ifdef HAS_RECORD if ((file->f_mode & FMODE_READ) && dmasound.mach.record) sq_reset_input() ; -#endif if (file->f_mode & FMODE_WRITE) { result = sq_fsync(file, file->f_dentry); sq_reset_output() ; @@ -1356,9 +1354,7 @@ } write_sq_init_waitqueue(); -#ifdef HAS_RECORD read_sq_init_waitqueue(); -#endif /* These parameters will be restored for every clean open() * in the case of multiple open()s (e.g. dsp0 & dsp1) they diff -urN linux-2.4.18/drivers/sound/dmasound/dmasound_paula.c linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_paula.c --- linux-2.4.18/drivers/sound/dmasound/dmasound_paula.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_paula.c Sat Mar 30 22:55:35 2002 @@ -122,7 +122,7 @@ static void AmiMixerInit(void); static int AmiMixerIoctl(u_int cmd, u_long arg); -static void AmiWriteSqSetup(void); +static int AmiWriteSqSetup(void); static int AmiStateInfo(char *buffer, size_t space); @@ -655,10 +655,11 @@ } -static void AmiWriteSqSetup(void) +static int AmiWriteSqSetup(void) { write_sq_block_size_half = write_sq.block_size>>1; write_sq_block_size_quarter = write_sq_block_size_half>>1; + return 0; } diff -urN linux-2.4.18/drivers/sound/dmasound/dmasound_q40.c linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_q40.c --- linux-2.4.18/drivers/sound/dmasound/dmasound_q40.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/dmasound/dmasound_q40.c Sat Mar 30 22:55:35 2002 @@ -20,6 +20,7 @@ #include #include +#include #include #include "dmasound.h" @@ -56,7 +57,7 @@ /*** Mid level stuff *********************************************************/ -#if 1 + /* userCount, frameUsed, frameLeft == byte counts */ static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, @@ -77,42 +78,8 @@ *frameUsed += used ; return used; } -#else -static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8; - ssize_t count, used; - u_char *p = (u_char *) &frame[*frameUsed]; - u_char val; - int stereo = sound.soft.stereo; - - frameLeft >>= 1; - if (stereo) - userCount >>= 1; - used = count = min_t(size_t, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]+128; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]+128; - } - *p++ = val; - count--; - } - *frameUsed += used * 2; - return stereo? used * 2: used; -} -#endif -#if 1 static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) @@ -131,40 +98,7 @@ *frameUsed += used; return used; } -#else -static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - u_char *p = (u_char *) &frame[*frameUsed]; - u_char val; - int stereo = dmasound.soft.stereo; - frameLeft >>= 1; - if (stereo) - userCount >>= 1; - used = count = min_t(size_t, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = data + 128; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = data + 128; - } - *p++ = val; - count--; - } - *frameUsed += used * 2; - return stereo? used * 2: used; -} -#endif - -#if 1 static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) @@ -178,40 +112,8 @@ *frameUsed += used; return used; } -#else -static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - u_char *p = (u_char *) &frame[*frameUsed]; - u_char val; - int stereo = dmasound.soft.stereo; - frameLeft >>= 1; - if (stereo) - userCount >>= 1; - used = count = min_t(size_t, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = data; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = data; - } - *p++ = val; - count--; - } - *frameUsed += used * 2; - return stereo? used * 2: used; -} -#endif - /* a bit too complicated to optimise right now ..*/ static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, @@ -322,6 +224,125 @@ return utotal; } +/* compressing versions */ +static ssize_t q40_ctc_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned char *table = (unsigned char *) + (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8); + unsigned int data = expand_data; + u_char *p = (u_char *) &frame[*frameUsed]; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int utotal, ftotal; + + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + while(bal<0) { + if (userCount == 0) + goto lout; + if (!(bal<(-hSpeed))) { + if (get_user(c, userPtr)) + return -EFAULT; + data = 0x80 + table[c]; + } + userPtr++; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + lout: + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft); + utotal -= userCount; + return utotal; +} + + +static ssize_t q40_ctc_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + u_char *p = (u_char *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int utotal, ftotal; + + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + while (bal < 0) { + if (userCount == 0) + goto lout; + if (!(bal<(-hSpeed))) { + if (get_user(c, userPtr)) + return -EFAULT; + data = c + 0x80; + } + userPtr++; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + lout: + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft); + utotal -= userCount; + return utotal; +} + + +static ssize_t q40_ctc_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + u_char *p = (u_char *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int utotal, ftotal; + + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + while (bal < 0) { + if (userCount == 0) + goto lout; + if (!(bal<(-hSpeed))) { + if (get_user(c, userPtr)) + return -EFAULT; + data = c ; + } + userPtr++; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + lout: + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) ; + utotal -= userCount; + return utotal; +} + static TRANS transQ40Normal = { q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL @@ -331,6 +352,10 @@ q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL }; +static TRANS transQ40Compressing = { + q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL +}; + /*** Low level stuff *********************************************************/ @@ -378,7 +403,7 @@ static void Q40Silence(void) { master_outb(0,SAMPLE_ENABLE_REG); - *DAC_LEFT=*DAC_RIGHT=0; + *DAC_LEFT=*DAC_RIGHT=127; } static char *q40_pp=NULL; @@ -473,7 +498,7 @@ if (q40_sc<2) { /* there was nothing to play, disable irq */ master_outb(0,SAMPLE_ENABLE_REG); - *DAC_LEFT=*DAC_RIGHT=0; + *DAC_LEFT=*DAC_RIGHT=127; } WAKE_UP(write_sq.action_queue); @@ -506,10 +531,10 @@ Q40Silence(); - if (dmasound.hard.speed > 20000) { - /* we would need to squeeze the sound, but we won't do that */ + if (dmasound.hard.speed > 20200) { + /* squeeze the sound, we do that */ dmasound.hard.speed = 20000; - dmasound.trans_write = &transQ40Normal; + dmasound.trans_write = &transQ40Compressing; } else if (dmasound.hard.speed > 10000) { dmasound.hard.speed = 20000; } else { @@ -584,6 +609,7 @@ setFormat: Q40SetFormat, setVolume: Q40SetVolume, play: Q40Play, + min_dsp_speed: 10000, version: ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION), hardware_afmts: AFMT_U8, /* h'ware-supported formats *only* here */ capabilities: DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ @@ -611,4 +637,6 @@ module_init(dmasound_q40_init); module_exit(dmasound_q40_cleanup); + +MODULE_DESCRIPTION("Q40/Q60 sound driver"); MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/sound/es1370.c linux-2.4.19-pre5/drivers/sound/es1370.c --- linux-2.4.18/drivers/sound/es1370.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/es1370.c Sat Mar 30 22:55:29 2002 @@ -397,7 +397,7 @@ * so that it cannot wreak havoc. The attribute makes sure it doesn't * cross a page boundary and ensures dword alignment for the DMA engine */ -static unsigned char bugbuf[16] __attribute__ ((aligned (16))); +static unsigned char *bugbuf; // [16] __attribute__ ((aligned (16))); /* --------------------------------------------------------------------- */ @@ -2564,6 +2564,11 @@ mm_segment_t fs; int i, val, ret; + if (bugbuf == NULL) + bugbuf = kmalloc(16, GFP_KERNEL); + if (bugbuf == NULL) + return -ENOMEM; + if ((ret=pci_enable_device(pcidev))) return ret; @@ -2747,6 +2752,8 @@ { printk(KERN_INFO "es1370: unloading\n"); pci_unregister_driver(&es1370_driver); + if(bugbuf) + kfree(bugbuf); } module_init(init_es1370); diff -urN linux-2.4.18/drivers/sound/hal2.c linux-2.4.19-pre5/drivers/sound/hal2.c --- linux-2.4.18/drivers/sound/hal2.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/sound/hal2.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,1496 @@ +/* + * Driver for HAL2 sound processors + * Copyright (c) 2001, 2002 Ladislav Michl + * + * Based on Ulf Carlsson's code. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Supported devices: + * /dev/dsp standard dsp device, (mostly) OSS compatible + * /dev/mixer standard mixer device, (mostly) OSS compatible + * + * Driver currently supports indigo mode only. Recording doesn't work. Why? + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hal2.h" + +#if 0 +#define DEBUG(args...) printk(args) +#else +#define DEBUG(args...) +#endif + +#if 0 +#define DEBUG_MIX(args...) printk(args) +#else +#define DEBUG_MIX(args...) +#endif + +#define H2_INDIRECT_WAIT(regs) while (regs->isr & H2_ISR_TSTATUS); + +#define H2_READ_ADDR(addr) (addr | (1<<7)) +#define H2_WRITE_ADDR(addr) (addr) + +static char *hal2str = "HAL2 audio"; +static int ibuffers = 32; +static int obuffers = 32; + +/* I doubt anyone has a machine with two HAL2 cards. It's possible to + * have two HPC's, so it is probably possible to have two HAL2 cards. + * Try to deal with it, but note that it is not tested. + */ +#define MAXCARDS 2 +static hal2_card_t* hal2_card[MAXCARDS]; + +static const struct { + unsigned char idx:4, avail:1; +} mixtable[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_PCM] = { H2_MIX_OUTPUT_ATT, 1 }, /* voice */ + [SOUND_MIXER_MIC] = { H2_MIX_INPUT_GAIN, 1 }, /* mic */ +}; + +#define H2_SUPPORTED_FORMATS (AFMT_S16_LE | AFMT_S16_BE) + +static inline void hal2_isr_write(hal2_card_t *hal2, u32 val) +{ + hal2->ctl_regs->isr = val; +} + +static inline u32 hal2_isr_look(hal2_card_t *hal2) +{ + return hal2->ctl_regs->isr; +} + +static inline u32 hal2_rev_look(hal2_card_t *hal2) +{ + return hal2->ctl_regs->rev; +} + +#if 0 +static u16 hal2_i_look16(hal2_card_t *hal2, u32 addr) +{ + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + return (regs->idr0 & 0xffff); +} +#endif + +static u32 hal2_i_look32(hal2_card_t *hal2, u32 addr) +{ + u32 ret; + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + ret = regs->idr0 & 0xffff; + regs->iar = H2_READ_ADDR(addr | 0x1); + H2_INDIRECT_WAIT(regs); + ret |= (regs->idr0 & 0xffff) << 16; + return ret; +} + +static void hal2_i_write16(hal2_card_t *hal2, u32 addr, u16 val) +{ + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->idr0 = val; + regs->idr1 = 0; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} + +static void hal2_i_write32(hal2_card_t *hal2, u32 addr, u32 val) +{ + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->idr0 = val & 0xffff; + regs->idr1 = val >> 16; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} + +static void hal2_i_setbit16(hal2_card_t *hal2, u32 addr, u16 bit) +{ + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + regs->idr0 = regs->idr0 | bit; + regs->idr1 = 0; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} + +static void hal2_i_setbit32(hal2_card_t *hal2, u32 addr, u32 bit) +{ + u32 tmp; + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + tmp = regs->idr0 | (regs->idr1 << 16) | bit; + regs->idr0 = tmp & 0xffff; + regs->idr1 = tmp >> 16; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} + +static void hal2_i_clearbit16(hal2_card_t *hal2, u32 addr, u16 bit) +{ + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + regs->idr0 = regs->idr0 & ~bit; + regs->idr1 = 0; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} + +#if 0 +static void hal2_i_clearbit32(hal2_card_t *hal2, u32 addr, u32 bit) +{ + u32 tmp; + hal2_ctl_regs_t *regs = hal2->ctl_regs; + + regs->iar = H2_READ_ADDR(addr); + H2_INDIRECT_WAIT(regs); + tmp = (regs->idr0 | (regs->idr1 << 16)) & ~bit; + regs->idr0 = tmp & 0xffff; + regs->idr1 = tmp >> 16; + regs->idr2 = 0; + regs->idr3 = 0; + regs->iar = H2_WRITE_ADDR(addr); + H2_INDIRECT_WAIT(regs); +} +#endif + +#ifdef HAL2_DEBUG +static void hal2_dump_regs(hal2_card_t *hal2) +{ + printk("isr: %08hx ", hal2_isr_look(hal2)); + printk("rev: %08hx\n", hal2_rev_look(hal2)); + printk("relay: %04hx\n", hal2_i_look16(hal2, H2I_RELAY_C)); + printk("port en: %04hx ", hal2_i_look16(hal2, H2I_DMA_PORT_EN)); + printk("dma end: %04hx ", hal2_i_look16(hal2, H2I_DMA_END)); + printk("dma drv: %04hx\n", hal2_i_look16(hal2, H2I_DMA_DRV)); + printk("syn ctl: %04hx ", hal2_i_look16(hal2, H2I_SYNTH_C)); + printk("aesrx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESRX_C)); + printk("aestx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESTX_C)); + printk("dac ctl1: %04hx ", hal2_i_look16(hal2, H2I_ADC_C1)); + printk("dac ctl2: %08lx ", hal2_i_look32(hal2, H2I_ADC_C2)); + printk("adc ctl1: %04hx ", hal2_i_look16(hal2, H2I_DAC_C1)); + printk("adc ctl2: %08lx ", hal2_i_look32(hal2, H2I_DAC_C2)); + printk("syn map: %04hx\n", hal2_i_look16(hal2, H2I_SYNTH_MAP_C)); + printk("bres1 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES1_C1)); + printk("bres1 ctl2: %04lx ", hal2_i_look32(hal2, H2I_BRES1_C2)); + printk("bres2 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES2_C1)); + printk("bres2 ctl2: %04lx ", hal2_i_look32(hal2, H2I_BRES2_C2)); + printk("bres3 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES3_C1)); + printk("bres3 ctl2: %04lx\n", hal2_i_look32(hal2, H2I_BRES3_C2)); +} +#endif + +static hal2_card_t* hal2_dsp_find_card(int minor) +{ + int i; + + for (i = 0; i < MAXCARDS; i++) + if (hal2_card[i] != NULL && hal2_card[i]->dev_dsp == minor) + return hal2_card[i]; + return NULL; +} + +static hal2_card_t* hal2_mixer_find_card(int minor) +{ + int i; + + for (i = 0; i < MAXCARDS; i++) + if (hal2_card[i] != NULL && hal2_card[i]->dev_mixer == minor) + return hal2_card[i]; + return NULL; +} + + +static void hal2_dac_interrupt(hal2_codec_t *dac) +{ + int running; + + spin_lock(&dac->lock); + + /* if tail buffer contains zero samples DMA stream was already + * stopped */ + running = dac->tail->info.cnt; + dac->tail->info.cnt = 0; + dac->tail->info.desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX; + dma_cache_wback_inv((unsigned long) dac->tail, + sizeof(struct hpc_dma_desc)); + /* we just proccessed empty buffer, don't update tail pointer */ + if (running) + dac->tail = dac->tail->info.next; + + spin_unlock(&dac->lock); + + wake_up(&dac->dma_wait); +} + +static void hal2_adc_interrupt(hal2_codec_t *adc) +{ + int running; + + spin_lock(&adc->lock); + + /* if head buffer contains nonzero samples DMA stream was already + * stopped */ + running = !adc->head->info.cnt; + adc->head->info.cnt = H2_BUFFER_SIZE; + adc->head->info.desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX; + dma_cache_wback_inv((unsigned long) adc->head, + sizeof(struct hpc_dma_desc)); + /* we just proccessed empty buffer, don't update head pointer */ + if (running) { + dma_cache_inv((unsigned long) adc->head->data, H2_BUFFER_SIZE); + adc->head = adc->head->info.next; + } + + spin_unlock(&adc->lock); + + wake_up(&adc->dma_wait); +} + +static void hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + hal2_card_t *hal2 = (hal2_card_t*)dev_id; + + /* decide what caused this interrupt */ + if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) + hal2_dac_interrupt(&hal2->dac); + if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) + hal2_adc_interrupt(&hal2->adc); +} + +static int hal2_compute_rate(hal2_codec_t *codec, unsigned int rate) +{ + unsigned short inc; + + /* We default to 44.1 kHz and if it isn't possible to fall back to + * 48.0 kHz with the needed adjustments of real_rate. + */ + + DEBUG("rate: %d\n", rate); + + /* Refer to CS4216 data sheet */ + if (rate < 4000) + rate = 4000; + if (rate > 50000) + rate = 50000; + + /* Note: This is NOT the way they set up the bresenham clock generators + * in the specification. I've tried to implement that method but it + * doesn't work. It's probably another silly bug in the spec. + * + * I accidently discovered this method while I was testing and it seems + * to work very well with all frequencies, and thee shall follow rule #1 + * of programming :-) + */ + + if (44100 % rate == 0) { + inc = 44100 / rate; + if (inc < 1) inc = 1; + codec->master = 44100; + } else { + inc = 48000 / rate; + if (inc < 1) inc = 1; + rate = 48000 / inc; + codec->master = 48000; + } + codec->inc = inc; + codec->mod = 1; + + DEBUG("real_rate: %d\n", rate); + + return rate; +} + +static void hal2_set_dac_rate(hal2_card_t *hal2) +{ + unsigned int master = hal2->dac.master; + int inc = hal2->dac.inc; + int mod = hal2->dac.mod; + + DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod); + + hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0); + hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (mod - inc - 1)) << 16) | 1); +} + +static void hal2_set_adc_rate(hal2_card_t *hal2) +{ + unsigned int master = hal2->adc.master; + int inc = hal2->adc.inc; + int mod = hal2->adc.mod; + + DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod); + + hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0); + hal2_i_write32(hal2, H2I_BRES2_C2, ((0xffff & (mod - inc - 1)) << 16) | 1); +} + +static void hal2_setup_dac(hal2_card_t *hal2) +{ + unsigned int fifobeg, fifoend, highwater, sample_size; + hal2_pbus_t *pbus = &hal2->dac.pbus; + + DEBUG("hal2_setup_dac\n"); + + /* Now we set up some PBUS information. The PBUS needs information about + * what portion of the fifo it will use. If it's receiving or + * transmitting, and finally whether the stream is little endian or big + * endian. The information is written later, on the start call. + */ + sample_size = 2 * hal2->dac.voices; + + /* Fifo should be set to hold exactly four samples. Highwater mark + * should be set to two samples. */ + highwater = (sample_size * 2) >> 1; /* halfwords */ + fifobeg = 0; /* playback is first */ + fifoend = (sample_size * 4) >> 3; /* doublewords */ + pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD | + (highwater << 8) | (fifobeg << 16) | (fifoend << 24); + /* We disable everything before we do anything at all */ + pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; + hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); + hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); + /* Setup the HAL2 for playback */ + hal2_set_dac_rate(hal2); + /* We are using 1st Bresenham clock generator for playback */ + hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) + | (1 << H2I_C1_CLKID_SHIFT) + | (hal2->dac.voices << H2I_C1_DATAT_SHIFT)); +} + +static void hal2_setup_adc(hal2_card_t *hal2) +{ + unsigned int fifobeg, fifoend, highwater, sample_size; + hal2_pbus_t *pbus = &hal2->adc.pbus; + + DEBUG("hal2_setup_adc\n"); + + sample_size = 2 * hal2->adc.voices; + + highwater = (sample_size * 2) >> 1; /* halfwords */ + fifobeg = (4 * 4) >> 3; /* record is second */ + fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */ + pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | + (highwater << 8) | (fifobeg << 16) | (fifoend << 24); + pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; + hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); + hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); + /* Setup the HAL2 for record */ + hal2_set_adc_rate(hal2); + /* We are using 2nd Bresenham clock generator for record */ + hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) + | (2 << H2I_C1_CLKID_SHIFT) + | (hal2->adc.voices << H2I_C1_DATAT_SHIFT)); +} + +static void hal2_start_dac(hal2_card_t *hal2) +{ + hal2_pbus_t *pbus = &hal2->dac.pbus; + + DEBUG("hal2_start_dac\n"); + + pbus->pbus->pbdma_dptr = PHYSADDR(hal2->dac.tail); + pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; + + /* set endianess */ + if (hal2->dac.format & AFMT_S16_LE) + hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); + else + hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); + /* set DMA bus */ + hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); + /* enable DAC */ + hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); +} + +static void hal2_start_adc(hal2_card_t *hal2) +{ + hal2_pbus_t *pbus = &hal2->adc.pbus; + + DEBUG("hal2_start_adc\n"); + + pbus->pbus->pbdma_dptr = PHYSADDR(hal2->adc.head); + pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; + + /* set endianess */ + if (hal2->adc.format & AFMT_S16_LE) + hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); + else + hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); + /* set DMA bus */ + hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); + /* enable ADC */ + hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); +} + +static inline void hal2_stop_dac(hal2_card_t *hal2) +{ + DEBUG("hal2_stop_dac\n"); + + hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; + /* The HAL2 itself may remain enabled safely */ +} + +static inline void hal2_stop_adc(hal2_card_t *hal2) +{ + DEBUG("hal2_stop_adc\n"); + + hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; +} + +#define hal2_alloc_dac_dmabuf(hal2) hal2_alloc_dmabuf(hal2, 1) +#define hal2_alloc_adc_dmabuf(hal2) hal2_alloc_dmabuf(hal2, 0) +static int hal2_alloc_dmabuf(hal2_card_t *hal2, int is_dac) +{ + int buffers, cntinfo; + hal2_buf_t *buf, *prev; + hal2_codec_t *codec; + + if (is_dac) { + codec = &hal2->dac; + buffers = obuffers; + cntinfo = HPCDMA_XIE | HPCDMA_EOX; + } else { + codec = &hal2->adc; + buffers = ibuffers; + cntinfo = HPCDMA_XIE | H2_BUFFER_SIZE; + } + + DEBUG("allocating %d DMA buffers.\n", buffers); + + buf = (hal2_buf_t*) get_zeroed_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + codec->head = buf; + codec->tail = buf; + + while (--buffers) { + buf->info.desc.pbuf = PHYSADDR(&buf->data); + buf->info.desc.cntinfo = cntinfo; + buf->info.cnt = 0; + prev = buf; + buf = (hal2_buf_t*) get_zeroed_page(GFP_KERNEL); + if (!buf) { + printk("HAL2: Not enough memory for DMA buffer.\n"); + buf = codec->head; + while (buf) { + prev = buf; + free_page((unsigned long) buf); + buf = prev->info.next; + } + return -ENOMEM; + } + prev->info.next = buf; + prev->info.desc.pnext = PHYSADDR(buf); + /* The PBUS can prolly not read this stuff when it's in + * the cache so we have to flush it back to main memory + */ + dma_cache_wback_inv((unsigned long) prev, PAGE_SIZE); + } + buf->info.desc.pbuf = PHYSADDR(&buf->data); + buf->info.desc.cntinfo = cntinfo; + buf->info.cnt = 0; + buf->info.next = codec->head; + buf->info.desc.pnext = PHYSADDR(codec->head); + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + + return 0; +} + +#define hal2_free_dac_dmabuf(hal2) hal2_free_dmabuf(hal2, 1) +#define hal2_free_adc_dmabuf(hal2) hal2_free_dmabuf(hal2, 0) +static void hal2_free_dmabuf(hal2_card_t *hal2, int is_dac) +{ + hal2_buf_t *buf, *next; + hal2_codec_t *codec = (is_dac) ? &hal2->dac : &hal2->adc; + + if (!codec->head) + return; + + buf = codec->head->info.next; + codec->head->info.next = NULL; + while (buf) { + next = buf->info.next; + free_page((unsigned long) buf); + buf = next; + } + codec->head = codec->tail = NULL; +} + +/* + * Add 'count' bytes to 'buffer' from DMA ring buffers. Return number of + * bytes added or -EFAULT if copy_from_user failed. + */ +static int hal2_get_buffer(hal2_card_t *hal2, char *buffer, int count) +{ + unsigned long flags; + int size, ret = 0; + hal2_codec_t *adc = &hal2->adc; + + spin_lock_irqsave(&adc->lock, flags); + + DEBUG("getting %d bytes ", count); + + /* enable DMA stream if there are no data */ + if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && + adc->tail->info.cnt == 0) + hal2_start_adc(hal2); + + DEBUG("... "); + + while (adc->tail->info.cnt > 0 && count > 0) { + size = min(adc->tail->info.cnt, count); + spin_unlock_irqrestore(&adc->lock, flags); + + if (copy_to_user(buffer, &adc->tail->data[H2_BUFFER_SIZE-size], + size)) { + ret = -EFAULT; + goto out; + } + + spin_lock_irqsave(&adc->lock, flags); + + adc->tail->info.cnt -= size; + /* buffer is empty, update tail pointer */ + if (adc->tail->info.cnt == 0) { + adc->tail->info.desc.cntinfo = HPCDMA_XIE | + H2_BUFFER_SIZE; + dma_cache_wback_inv((unsigned long) adc->tail, + sizeof(struct hpc_dma_desc)); + adc->tail = adc->tail->info.next; + /* enable DMA stream again if needed */ + if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT)) + hal2_start_adc(hal2); + + } + buffer += size; + ret += size; + count -= size; + + DEBUG("(%d) ", size); + } + spin_unlock_irqrestore(&adc->lock, flags); +out: + DEBUG("\n"); + + return ret; +} + +/* + * Add 'count' bytes from 'buffer' to DMA ring buffers. Return number of + * bytes added or -EFAULT if copy_from_user failed. + */ +static int hal2_add_buffer(hal2_card_t *hal2, char *buffer, int count) +{ + unsigned long flags; + int size, ret = 0; + hal2_codec_t *dac = &hal2->dac; + + spin_lock_irqsave(&dac->lock, flags); + + DEBUG("adding %d bytes ", count); + + while (dac->head->info.cnt == 0 && count > 0) { + size = min((int)H2_BUFFER_SIZE, count); + spin_unlock_irqrestore(&dac->lock, flags); + + if (copy_from_user(dac->head->data, buffer, size)) { + ret = -EFAULT; + goto out; + } + spin_lock_irqsave(&dac->lock, flags); + + dac->head->info.desc.cntinfo = size | HPCDMA_XIE; + dac->head->info.cnt = size; + dma_cache_wback_inv((unsigned long) dac->head, + size + PAGE_SIZE - H2_BUFFER_SIZE); + buffer += size; + ret += size; + count -= size; + dac->head = dac->head->info.next; + + DEBUG("(%d) ", size); + } + if (!(dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && ret > 0) + hal2_start_dac(hal2); + + spin_unlock_irqrestore(&dac->lock, flags); +out: + DEBUG("\n"); + + return ret; +} + +#define hal2_reset_dac_pointer(hal2) hal2_reset_pointer(hal2, 1) +#define hal2_reset_adc_pointer(hal2) hal2_reset_pointer(hal2, 0) +static void hal2_reset_pointer(hal2_card_t *hal2, int is_dac) +{ + hal2_codec_t *codec = (is_dac) ? &hal2->dac : &hal2->adc; + + DEBUG("hal2_reset_pointer\n"); + + codec->tail = codec->head; + do { + codec->tail->info.desc.cntinfo = HPCDMA_XIE | (is_dac) ? + HPCDMA_EOX : H2_BUFFER_SIZE; + codec->tail->info.cnt = 0; + dma_cache_wback_inv((unsigned long) codec->tail, + sizeof(struct hpc_dma_desc)); + codec->tail = codec->tail->info.next; + } while (codec->tail != codec->head); +} + +static int hal2_sync_dac(hal2_card_t *hal2) +{ + DECLARE_WAITQUEUE(wait, current); + hal2_codec_t *dac = &hal2->dac; + int ret = 0; + signed long timeout = 1 + 1000 * H2_BUFFER_SIZE * 2 * dac->voices * + HZ / dac->sample_rate / 900; + + down(&dac->sem); + + while (dac->tail->info.cnt > 0 && ret == 0) { + add_wait_queue(&dac->dma_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (!schedule_timeout(timeout)) + /* We may get bogus timeout when system is + * heavily loaded */ + if (dac->tail->info.cnt) { + printk("HAL2: timeout...\n"); + ret = -ETIME; + } + if (signal_pending(current)) + ret = -ERESTARTSYS; + remove_wait_queue(&dac->dma_wait, &wait); + } + + /* Make sure that DMA is stopped */ + if (dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) { + hal2_stop_dac(hal2); + hal2_reset_dac_pointer(hal2); + } + + up(&dac->sem); + + return ret; +} + +static int hal2_write_mixer(hal2_card_t *hal2, int index, int vol) +{ + unsigned int l, r; + + DEBUG_MIX("mixer %d write\n", index); + + if (index >= SOUND_MIXER_NRDEVICES || !mixtable[index].avail) + return -EINVAL; + + r = (vol >> 8) & 0xff; + if (r > 100) + r = 100; + l = vol & 0xff; + if (l > 100) + l = 100; + + hal2->mixer.volume[mixtable[index].idx] = l | (r << 8); + + switch (mixtable[index].idx) { + case H2_MIX_OUTPUT_ATT: { + + DEBUG_MIX("output attenuator %d,%d\n", l, r); + + if (r | l) { + unsigned int tmp = hal2_i_look32(hal2, H2I_DAC_C2); + + tmp &= ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); + + /* Attenuator has five bits */ + l = (31 * (100 - l) / 99); + r = (31 * (100 - r) / 99); + + DEBUG_MIX("left: %d, right %d\n", l, r); + + tmp |= (l << H2I_C2_L_ATT_SHIFT) & H2I_C2_L_ATT_M; + tmp |= (r << H2I_C2_R_ATT_SHIFT) & H2I_C2_R_ATT_M; + hal2_i_write32(hal2, H2I_DAC_C2, tmp); + } else + hal2_i_setbit32(hal2, H2I_DAC_C2, H2I_C2_MUTE); + } + case H2_MIX_INPUT_GAIN: { + /* TODO */ + } + } + return 0; +} + +static void hal2_init_mixer(hal2_card_t *hal2) +{ + int i; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + hal2_write_mixer(hal2, i, 100 | (100 << 8)); + +} + +static int hal2_mixer_ioctl(hal2_card_t *hal2, unsigned int cmd, + unsigned long arg) +{ + int val; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + + strncpy(info.id, hal2str, sizeof(info.id)); + strncpy(info.name, hal2str, sizeof(info.name)); + info.modify_counter = hal2->mixer.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, hal2str, sizeof(info.id)); + strncpy(info.name, hal2str, 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)) { + /* Give the current record source */ + case SOUND_MIXER_RECSRC: + val = 0; /* FIXME */ + break; + /* Give the supported mixers, all of them support stereo */ + case SOUND_MIXER_DEVMASK: + case SOUND_MIXER_STEREODEVS: { + int i; + + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].avail) + val |= 1 << i; + break; + } + /* Arg contains a bit for each supported recording source */ + case SOUND_MIXER_RECMASK: + val = 0; + break; + case SOUND_MIXER_CAPS: + val = 0; + break; + /* Read a specific mixer */ + default: { + int i = _IOC_NR(cmd); + + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) + return -EINVAL; + val = hal2->mixer.volume[mixtable[i].idx]; + break; + } + } + return put_user(val, (int *)arg); + } + + if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ)) + return -EINVAL; + + hal2->mixer.modcnt++; + + if (get_user(val, (int *)arg)) + return -EFAULT; + + switch (_IOC_NR(cmd)) { + /* Arg contains a bit for each recording source */ + case SOUND_MIXER_RECSRC: + return 0; /* FIXME */ + default: + return hal2_write_mixer(hal2, _IOC_NR(cmd), val); + } + + return 0; +} + +static int hal2_open_mixdev(struct inode *inode, struct file *file) +{ + hal2_card_t *hal2 = hal2_mixer_find_card(MINOR(inode->i_rdev)); + + if (hal2) { + file->private_data = hal2; + return 0; + } + return -ENODEV; +} + +static int hal2_release_mixdev(struct inode *inode, struct file *file) +{ + return 0; +} + +static int hal2_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hal2_mixer_ioctl((hal2_card_t *)file->private_data, cmd, arg); +} + + +static int hal2_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int val; + hal2_card_t *hal2 = (hal2_card_t *) file->private_data; + + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return hal2_sync_dac(hal2); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_MULTI, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + hal2_reset_adc_pointer(hal2); + } + if (file->f_mode & FMODE_WRITE) { + hal2_stop_dac(hal2); + hal2_reset_dac_pointer(hal2); + } + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + val = hal2_compute_rate(&hal2->adc, val); + hal2->adc.sample_rate = val; + hal2_set_adc_rate(hal2); + } + if (file->f_mode & FMODE_WRITE) { + hal2_stop_dac(hal2); + val = hal2_compute_rate(&hal2->dac, val); + hal2->dac.sample_rate = val; + hal2_set_dac_rate(hal2); + } + return put_user(val, (int *)arg); + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + hal2->adc.voices = (val) ? 2 : 1; + hal2_setup_adc(hal2); + } + if (file->f_mode & FMODE_WRITE) { + hal2_stop_dac(hal2); + hal2->dac.voices = (val) ? 2 : 1; + hal2_setup_dac(hal2); + } + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != 0) { + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + hal2->adc.voices = (val == 1) ? 1 : 2; + hal2_setup_adc(hal2); + } + if (file->f_mode & FMODE_WRITE) { + hal2_stop_dac(hal2); + hal2->dac.voices = (val == 1) ? 1 : 2; + hal2_setup_dac(hal2); + } + } + val = -EINVAL; + if (file->f_mode & FMODE_READ) + val = hal2->adc.voices; + if (file->f_mode & FMODE_WRITE) + val = hal2->dac.voices; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(H2_SUPPORTED_FORMATS, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != AFMT_QUERY) { + if (!(val & H2_SUPPORTED_FORMATS)) + return -EINVAL; + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + hal2->adc.format = val; + hal2_setup_adc(hal2); + } + if (file->f_mode & FMODE_WRITE) { + hal2_stop_dac(hal2); + hal2->dac.format = val; + hal2_setup_dac(hal2); + } + } else { + val = -EINVAL; + if (file->f_mode & FMODE_READ) + val = hal2->adc.format; + if (file->f_mode & FMODE_WRITE) + val = hal2->dac.format; + } + return put_user(val, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETOSPACE: { + unsigned long flags; + audio_buf_info info; + hal2_buf_t *buf; + hal2_codec_t *dac = &hal2->dac; + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + spin_lock_irqsave(&dac->lock, flags); + info.fragments = 0; + buf = dac->head; + while (buf->info.cnt == 0 && buf != dac->tail) { + info.fragments++; + buf = buf->info.next; + } + spin_unlock_irqrestore(&dac->lock, flags); + + info.fragstotal = obuffers; + info.fragsize = H2_BUFFER_SIZE; + info.bytes = info.fragsize * info.fragments; + + return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; + } + + case SNDCTL_DSP_GETISPACE: { + unsigned long flags; + audio_buf_info info; + hal2_buf_t *buf; + hal2_codec_t *adc = &hal2->adc; + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + + spin_lock_irqsave(&adc->lock, flags); + info.fragments = 0; + info.bytes = 0; + buf = adc->tail; + while (buf->info.cnt > 0 && buf != adc->head) { + info.fragments++; + info.bytes += buf->info.cnt; + buf = buf->info.next; + } + spin_unlock_irqrestore(&adc->lock, flags); + + info.fragstotal = ibuffers; + info.fragsize = H2_BUFFER_SIZE; + + return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; + } + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETBLKSIZE: + return put_user(H2_BUFFER_SIZE, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + return 0; + + case SOUND_PCM_READ_RATE: + val = -EINVAL; + if (file->f_mode & FMODE_READ) + val = hal2->adc.sample_rate; + if (file->f_mode & FMODE_WRITE) + val = hal2->dac.sample_rate; + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + val = -EINVAL; + if (file->f_mode & FMODE_READ) + val = hal2->adc.voices; + if (file->f_mode & FMODE_WRITE) + val = hal2->dac.voices; + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_BITS: + val = 16; + return put_user(val, (int *)arg); + } + + return hal2_mixer_ioctl(hal2, cmd, arg); +} + +static ssize_t hal2_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) +{ + ssize_t err; + hal2_card_t *hal2 = (hal2_card_t *) file->private_data; + hal2_codec_t *adc = &hal2->adc; + + if (count == 0) + return 0; + if (ppos != &file->f_pos) + return -ESPIPE; + + down(&adc->sem); + + if (file->f_flags & O_NONBLOCK) { + err = hal2_get_buffer(hal2, buffer, count); + err = err == 0 ? -EAGAIN : err; + } else { + do { + /* ~10% longer */ + signed long timeout = 1 + 1000 * H2_BUFFER_SIZE * + 2 * adc->voices * HZ / adc->sample_rate / 900; + DECLARE_WAITQUEUE(wait, current); + ssize_t cnt = 0; + + err = hal2_get_buffer(hal2, buffer, count); + if (err > 0) { + count -= err; + cnt += err; + buffer += err; + err = cnt; + } + if (count > 0 && err >= 0) { + add_wait_queue(&adc->dma_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Well, it is possible, that interrupt already + * arrived. Hmm, shit happens, we have one more + * buffer filled ;) */ + if (!schedule_timeout(timeout)) + /* We may get bogus timeout when system + * is heavily loaded */ + if (!adc->tail->info.cnt) { + printk("HAL2: timeout...\n"); + hal2_stop_adc(hal2); + hal2_reset_adc_pointer(hal2); + err = -EAGAIN; + } + if (signal_pending(current)) + err = -ERESTARTSYS; + remove_wait_queue(&adc->dma_wait, &wait); + } + } while (count > 0 && err >= 0); + + } + + up(&adc->sem); + + return err; +} + +static ssize_t hal2_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + ssize_t err; + char *buf = (char*) buffer; + hal2_card_t *hal2 = (hal2_card_t *) file->private_data; + hal2_codec_t *dac = &hal2->dac; + + if (count == 0) + return 0; + if (ppos != &file->f_pos) + return -ESPIPE; + + down(&dac->sem); + + if (file->f_flags & O_NONBLOCK) { + err = hal2_add_buffer(hal2, buf, count); + err = err == 0 ? -EAGAIN : err; + } else { + do { + /* ~10% longer */ + signed long timeout = 1 + 1000 * H2_BUFFER_SIZE * + 2 * dac->voices * HZ / dac->sample_rate / 900; + DECLARE_WAITQUEUE(wait, current); + ssize_t cnt = 0; + + err = hal2_add_buffer(hal2, buf, count); + if (err > 0) { + count -= err; + cnt += err; + buf += err; + err = cnt; + } + if (count > 0 && err >= 0) { + add_wait_queue(&dac->dma_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Well, it is possible, that interrupt already + * arrived. Hmm, shit happens, we have one more + * buffer free ;) */ + if (!schedule_timeout(timeout)) + /* We may get bogus timeout when system + * is heavily loaded */ + if (dac->head->info.cnt) { + printk("HAL2: timeout...\n"); + hal2_stop_dac(hal2); + hal2_reset_dac_pointer(hal2); + err = -EAGAIN; + } + if (signal_pending(current)) + err = -ERESTARTSYS; + remove_wait_queue(&dac->dma_wait, &wait); + } + } while (count > 0 && err >= 0); + } + + up(&dac->sem); + + return err; +} + +static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait) +{ + unsigned long flags; + unsigned int mask = 0; + hal2_card_t *hal2 = (hal2_card_t *) file->private_data; + + if (file->f_mode & FMODE_READ) { + hal2_codec_t *adc = &hal2->adc; + + poll_wait(file, &hal2->adc.dma_wait, wait); + spin_lock_irqsave(&adc->lock, flags); + if (adc->tail->info.cnt > 0) + mask |= POLLIN; + spin_unlock_irqrestore(&adc->lock, flags); + } + + if (file->f_mode & FMODE_WRITE) { + hal2_codec_t *dac = &hal2->dac; + + poll_wait(file, &dac->dma_wait, wait); + spin_lock_irqsave(&dac->lock, flags); + if (dac->head->info.cnt == 0) + mask |= POLLOUT; + spin_unlock_irqrestore(&dac->lock, flags); + } + + return mask; +} + +static int hal2_open(struct inode *inode, struct file *file) +{ + int err; + hal2_card_t *hal2 = hal2_dsp_find_card(MINOR(inode->i_rdev)); + + DEBUG("opening audio device.\n"); + + if (!hal2) { + printk("HAL2: Whee?! Open door and go away!\n"); + return -ENODEV; + } + file->private_data = hal2; + + if (file->f_mode & FMODE_READ) { + if (hal2->adc.usecount) + return -EBUSY; + + /* OSS spec wanted us to use 8 bit, 8 kHz mono by default, + * but HAL2 can't do 8bit audio */ + hal2->adc.format = AFMT_S16_BE; + hal2->adc.voices = 1; + hal2->adc.sample_rate = hal2_compute_rate(&hal2->adc, 8000); + hal2_set_adc_rate(hal2); + + /* alloc DMA buffers */ + err = hal2_alloc_adc_dmabuf(hal2); + if (err) + return err; + hal2_setup_adc(hal2); + + hal2->adc.usecount++; + } + + if (file->f_mode & FMODE_WRITE) { + if (hal2->dac.usecount) + return -EBUSY; + + hal2->dac.format = AFMT_S16_BE; + hal2->dac.voices = 1; + hal2->dac.sample_rate = hal2_compute_rate(&hal2->dac, 8000); + hal2_set_dac_rate(hal2); + + /* alloc DMA buffers */ + err = hal2_alloc_dac_dmabuf(hal2); + if (err) + return err; + hal2_setup_dac(hal2); + + hal2->dac.usecount++; + } + + return 0; +} + +static int hal2_release(struct inode *inode, struct file *file) +{ + hal2_card_t *hal2 = (hal2_card_t *) file->private_data; + + if (file->f_mode & FMODE_READ) { + hal2_stop_adc(hal2); + hal2_free_adc_dmabuf(hal2); + hal2->adc.usecount--; + } + + if (file->f_mode & FMODE_WRITE) { + hal2_sync_dac(hal2); + hal2_free_dac_dmabuf(hal2); + hal2->dac.usecount--; + } + + return 0; +} + +static struct file_operations hal2_audio_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: hal2_read, + write: hal2_write, + poll: hal2_poll, + ioctl: hal2_ioctl, + open: hal2_open, + release: hal2_release, +}; + +static struct file_operations hal2_mixer_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + ioctl: hal2_ioctl_mixdev, + open: hal2_open_mixdev, + release: hal2_release_mixdev, +}; + +static int hal2_request_irq(hal2_card_t *hal2, int irq) +{ + unsigned long flags; + int ret = 0; + + save_and_cli(flags); + if (request_irq(irq, hal2_interrupt, SA_SHIRQ, hal2str, hal2)) { + printk(KERN_ERR "HAL2: Can't get irq %d\n", irq); + ret = -EAGAIN; + } + restore_flags(flags); + return ret; +} + +static int hal2_alloc_resources(hal2_card_t *hal2, struct hpc3_regs *hpc3) +{ + hal2_pbus_t *pbus; + + pbus = &hal2->dac.pbus; + pbus->pbusnr = 0; + pbus->pbus = &hpc3->pbdma[pbus->pbusnr]; + /* The spec says that we should write 0x08248844 but that's WRONG. HAL2 + * does 8 bit DMA, not 16 bit even if it generates 16 bit audio. */ + hpc3->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */ + + pbus = &hal2->adc.pbus; + pbus->pbusnr = 1; + pbus->pbus = &hpc3->pbdma[pbus->pbusnr]; + hpc3->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */ + + return hal2_request_irq(hal2, SGI_HPCDMA_IRQ); +} + +static void hal2_init_codec(hal2_codec_t *codec) +{ + init_waitqueue_head(&codec->dma_wait); + init_MUTEX(&codec->sem); + spin_lock_init(&codec->lock); +} + +static void hal2_free_resources(hal2_card_t *hal2) +{ + free_irq(SGI_HPCDMA_IRQ, hal2); +} + +static int hal2_detect(hal2_card_t *hal2) +{ + unsigned short board, major, minor; + unsigned short rev; + + /* reset HAL2 */ + hal2_isr_write(hal2, 0); + + /* release reset */ + hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N); + + hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); + + if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT) { + DEBUG("HAL2: no device detected, rev: 0x%04hx\n", rev); + return -ENODEV; + } + + board = (rev & H2_REV_BOARD_M) >> 12; + major = (rev & H2_REV_MAJOR_CHIP_M) >> 4; + minor = (rev & H2_REV_MINOR_CHIP_M); + + printk("SGI HAL2 Processor revision %i.%i.%i detected\n", + board, major, minor); + + if (board != 4 || major != 1 || minor != 0) + printk( "Other revision than 4.1.0 detected. " + "Your card is probably unsupported\n"); + + return 0; +} + +static int hal2_init_card(hal2_card_t **phal2, struct hpc3_regs *hpc3, + unsigned long hpc3_base) +{ + int ret = 0; + hal2_card_t *hal2; + + hal2 = (hal2_card_t *) kmalloc(sizeof(hal2_card_t), GFP_KERNEL); + if (!hal2) + return -ENOMEM; + memset(hal2, 0, sizeof(hal2_card_t)); + + hal2->ctl_regs = (hal2_ctl_regs_t *) KSEG1ADDR(hpc3_base + H2_CTL_PIO); + hal2->aes_regs = (hal2_aes_regs_t *) KSEG1ADDR(hpc3_base + H2_AES_PIO); + hal2->vol_regs = (hal2_vol_regs_t *) KSEG1ADDR(hpc3_base + H2_VOL_PIO); + hal2->syn_regs = (hal2_syn_regs_t *) KSEG1ADDR(hpc3_base + H2_SYN_PIO); + + if (hal2_detect(hal2) < 0) { + printk("HAL2 audio processor not found\n"); + ret = -ENODEV; + goto fail1; + } + + hal2_init_codec(&hal2->dac); + hal2_init_codec(&hal2->adc); + + ret = hal2_alloc_resources(hal2, hpc3); + if (ret) + goto fail1; + + hal2_init_mixer(hal2); + + hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1); + if (hal2->dev_dsp < 0) { + ret = hal2->dev_dsp; + goto fail2; + } + + hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1); + if (hal2->dev_mixer < 0) { + ret = hal2->dev_mixer; + goto fail3; + } + + *phal2 = hal2; + return 0; +fail3: + unregister_sound_dsp(hal2->dev_dsp); +fail2: + hal2_free_resources(hal2); +fail1: + kfree(hal2); + + return ret; +} + +/* + * We are assuming only one HAL2 card. If you ever meet machine with more than + * one, tell immediately about it to someone. Preferably to me. --ladis + */ +static int __init init_hal2(void) +{ + int i; + + for (i = 0; i < MAXCARDS; i++) + hal2_card[i] = NULL; + + return hal2_init_card(&hal2_card[0], hpc3c0, HPC3_CHIP0_PBASE); +} + +static void __exit exit_hal2(void) +{ + int i; + + for (i = 0; i < MAXCARDS; i++) + if (hal2_card[i]) { + hal2_free_resources(hal2_card[i]); + unregister_sound_dsp(hal2_card[i]->dev_dsp); + unregister_sound_mixer(hal2_card[i]->dev_mixer); + kfree(hal2_card[i]); + } +} + +module_init(init_hal2); +module_exit(exit_hal2); + +MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio"); +MODULE_AUTHOR("Ladislav Michl"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.18/drivers/sound/hal2.h linux-2.4.19-pre5/drivers/sound/hal2.h --- linux-2.4.18/drivers/sound/hal2.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/sound/hal2.h Sat Mar 30 22:55:29 2002 @@ -0,0 +1,328 @@ +#ifndef __HAL2_H +#define __HAL2_H + +/* + * Driver for HAL2 sound processors + * Copyright (c) 1999 Ulf Carlsson + * Copyright (c) 2001 Ladislav Michl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#define H2_HAL2_BASE 0x58000 +#define H2_CTL_PIO (H2_HAL2_BASE + 0 * 0x400) +#define H2_AES_PIO (H2_HAL2_BASE + 1 * 0x400) +#define H2_VOL_PIO (H2_HAL2_BASE + 2 * 0x400) +#define H2_SYN_PIO (H2_HAL2_BASE + 3 * 0x400) + +/* Indirect status register */ + +#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */ +#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */ +#define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */ +#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */ +#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */ + +/* Revision register */ + +#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */ +#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */ +#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */ +#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */ + +/* Indirect address register */ + +/* + * Address of indirect internal register to be accessed. A write to this + * register initiates read or write access to the indirect registers in the + * HAL2. Note that there af four indirect data registers for write access to + * registers larger than 16 byte. + */ + +#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */ + /* block the register resides in */ + /* 1=DMA Port */ + /* 9=Global DMA Control */ + /* 2=Bresenham */ + /* 3=Unix Timer */ +#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */ + /* blockin which the indirect */ + /* register resides */ + /* If IAR_TYPE_M=DMA Port: */ + /* 1=Synth In */ + /* 2=AES In */ + /* 3=AES Out */ + /* 4=DAC Out */ + /* 5=ADC Out */ + /* 6=Synth Control */ + /* If IAR_TYPE_M=Global DMA Control: */ + /* 1=Control */ + /* If IAR_TYPE_M=Bresenham: */ + /* 1=Bresenham Clock Gen 1 */ + /* 2=Bresenham Clock Gen 2 */ + /* 3=Bresenham Clock Gen 3 */ + /* If IAR_TYPE_M=Unix Timer: */ + /* 1=Unix Timer */ +#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */ +#define H2_IAR_PARAM 0x000C /* Parameter Select */ +#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */ + /* 00:word0 */ + /* 01:word1 */ + /* 10:word2 */ + /* 11:word3 */ +/* + * HAL2 internal addressing + * + * The HAL2 has "indirect registers" (idr) which are accessed by writing to the + * Indirect Data registers. Write the address to the Indirect Address register + * to transfer the data. + * + * We define the H2IR_* to the read address and H2IW_* to the write address and + * H2I_* to be fields in whatever register is referred to. + * + * When we write to indirect registers which are larger than one word (16 bit) + * we have to fill more than one indirect register before writing. When we read + * back however we have to read several times, each time with different Read + * Back Indexes (there are defs for doing this easily). + */ + +/* + * Relay Control + */ +#define H2I_RELAY_C 0x9100 +#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */ + +/* DMA port enable */ + +#define H2I_DMA_PORT_EN 0x9104 +#define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */ +#define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */ +#define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */ +#define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */ +#define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */ + +#define H2I_DMA_END 0x9108 /* global dma endian select */ +#define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */ +#define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */ +#define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */ +#define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */ +#define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */ + /* 0=b_end 1=l_end */ + +#define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */ + +#define H2I_SYNTH_C 0x1104 /* Synth DMA control */ + +#define H2I_AESRX_C 0x1204 /* AES RX dma control */ + +#define H2I_C_TS_EN 0x20 /* Timestamp enable */ +#define H2I_C_TS_FRMT 0x40 /* Timestamp format */ +#define H2I_C_NAUDIO 0x80 /* Sign extend */ + +/* AESRX CTL, 16 bit */ + +#define H2I_AESTX_C 0x1304 /* AES TX DMA control */ +#define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ +#define H2I_AESTX_C_CLKID_M 0x18 +#define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ +#define H2I_AESTX_C_DATAT_M 0x300 + +/* CODEC registers */ + +#define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */ +#define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */ +#define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */ +#define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */ + +/* Bits in CTL1 register */ + +#define H2I_C1_DMA_SHIFT 0 /* DMA channel */ +#define H2I_C1_DMA_M 0x7 +#define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ +#define H2I_C1_CLKID_M 0x18 +#define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ +#define H2I_C1_DATAT_M 0x300 + +/* Bits in CTL2 register */ + +#define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */ +#define H2I_C2_R_GAIN_M 0xf +#define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */ +#define H2I_C2_L_GAIN_M 0xf0 +#define H2I_C2_R_SEL 0x100 /* right input select */ +#define H2I_C2_L_SEL 0x200 /* left input select */ +#define H2I_C2_MUTE 0x400 /* mute */ +#define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */ +#define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */ +#define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */ +#define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */ +#define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */ +#define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */ + +#define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */ + +/* Clock generator CTL 1, 16 bit */ + +#define H2I_BRES1_C1 0x2104 +#define H2I_BRES2_C1 0x2204 +#define H2I_BRES3_C1 0x2304 + +#define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */ +#define H2I_BRES_C1_M 0x03 + +/* Clock generator CTL 2, 32 bit */ + +#define H2I_BRES1_C2 0x2108 +#define H2I_BRES2_C2 0x2208 +#define H2I_BRES3_C2 0x2308 + +#define H2I_BRES_C2_INC_SHIFT 0 /* increment value */ +#define H2I_BRES_C2_INC_M 0xffff +#define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */ +#define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */ + +/* Unix timer, 64 bit */ + +#define H2I_UTIME 0x3104 +#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */ +#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */ +#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */ +#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */ +#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */ + +typedef volatile u32 hal2_reg_t; + +typedef struct stru_hal2_ctl_regs hal2_ctl_regs_t; +struct stru_hal2_ctl_regs { + hal2_reg_t _unused0[4]; + hal2_reg_t isr; /* 0x10 Status Register */ + hal2_reg_t _unused1[3]; + hal2_reg_t rev; /* 0x20 Revision Register */ + hal2_reg_t _unused2[3]; + hal2_reg_t iar; /* 0x30 Indirect Address Register */ + hal2_reg_t _unused3[3]; + hal2_reg_t idr0; /* 0x40 Indirect Data Register 0 */ + hal2_reg_t _unused4[3]; + hal2_reg_t idr1; /* 0x50 Indirect Data Register 1 */ + hal2_reg_t _unused5[3]; + hal2_reg_t idr2; /* 0x60 Indirect Data Register 2 */ + hal2_reg_t _unused6[3]; + hal2_reg_t idr3; /* 0x70 Indirect Data Register 3 */ +}; + +typedef struct stru_hal2_aes_regs hal2_aes_regs_t; +struct stru_hal2_aes_regs { + hal2_reg_t rx_stat[2]; /* Status registers */ + hal2_reg_t rx_cr[2]; /* Control registers */ + hal2_reg_t rx_ud[4]; /* User data window */ + hal2_reg_t rx_st[24]; /* Channel status data */ + + hal2_reg_t tx_stat[1]; /* Status register */ + hal2_reg_t tx_cr[3]; /* Control registers */ + hal2_reg_t tx_ud[4]; /* User data window */ + hal2_reg_t tx_st[24]; /* Channel status data */ +}; + +typedef struct stru_hal2_vol_regs hal2_vol_regs_t; +struct stru_hal2_vol_regs { + hal2_reg_t right; /* 0x00 Right volume */ + hal2_reg_t left; /* 0x04 Left volume */ +}; + +typedef struct stru_hal2_syn_regs hal2_syn_regs_t; +struct stru_hal2_syn_regs { + hal2_reg_t _unused0[2]; + hal2_reg_t page; /* DOC Page register */ + hal2_reg_t regsel; /* DOC Register selection */ + hal2_reg_t dlow; /* DOC Data low */ + hal2_reg_t dhigh; /* DOC Data high */ + hal2_reg_t irq; /* IRQ Status */ + hal2_reg_t dram; /* DRAM Access */ +}; + +/* HAL2 specific structures */ + +typedef struct stru_hal2_pbus hal2_pbus_t; +struct stru_hal2_pbus { + struct hpc3_pbus_dmacregs *pbus; + int pbusnr; + unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */ +}; + +typedef struct stru_hal2_binfo hal2_binfo_t; +typedef struct stru_hal2_buffer hal2_buf_t; +struct stru_hal2_binfo { + volatile struct hpc_dma_desc desc; + hal2_buf_t *next; /* pointer to next buffer */ + int cnt; /* bytes in buffer */ +}; +#define H2_BUFFER_SIZE (PAGE_SIZE - \ + ((sizeof(hal2_binfo_t) - 1) / 8 + 1) * 8) +struct stru_hal2_buffer { + hal2_binfo_t info; + char data[H2_BUFFER_SIZE] __attribute__((aligned(8))); +}; + +typedef struct stru_hal2_codec hal2_codec_t; +struct stru_hal2_codec { + hal2_buf_t *head; + hal2_buf_t *tail; + hal2_pbus_t pbus; + unsigned int format; /* Audio data format */ + int voices; /* mono/stereo */ + unsigned int sample_rate; + unsigned int master; /* Master frequency */ + unsigned short mod; /* MOD value */ + unsigned short inc; /* INC value */ + + wait_queue_head_t dma_wait; + spinlock_t lock; + struct semaphore sem; + + int usecount; /* recording and playback are + * independent */ +}; + +#define H2_MIX_OUTPUT_ATT 0 +#define H2_MIX_INPUT_GAIN 1 +#define H2_MIXERS 2 +typedef struct stru_hal2_mixer hal2_mixer_t; +struct stru_hal2_mixer { + int modcnt; + unsigned int volume[H2_MIXERS]; +}; + +typedef struct stru_hal2_card hal2_card_t; +struct stru_hal2_card { + int dev_dsp; /* audio device */ + int dev_mixer; /* mixer device */ + int dev_midi; /* midi device */ + + hal2_ctl_regs_t *ctl_regs; /* HAL2 ctl registers */ + hal2_aes_regs_t *aes_regs; /* HAL2 vol registers */ + hal2_vol_regs_t *vol_regs; /* HAL2 aes registers */ + hal2_syn_regs_t *syn_regs; /* HAL2 syn registers */ + + hal2_codec_t dac; + hal2_codec_t adc; + hal2_mixer_t mixer; +}; + +#endif /* __HAL2_H */ diff -urN linux-2.4.18/drivers/sound/i810_audio.c linux-2.4.19-pre5/drivers/sound/i810_audio.c --- linux-2.4.18/drivers/sound/i810_audio.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/i810_audio.c Sat Mar 30 22:55:29 2002 @@ -110,6 +110,9 @@ #ifndef PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO #define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 #endif +#ifndef PCI_DEVICE_ID_AMD_768_AUDIO +#define PCI_DEVICE_ID_AMD_768_AUDIO 0x7445 +#endif static int ftsodell=0; static int strict_clocking=0; @@ -231,7 +234,8 @@ INTELICH2, INTELICH3, SI7012, - NVIDIA_NFORCE + NVIDIA_NFORCE, + AMD768 }; static char * card_names[] = { @@ -241,7 +245,8 @@ "Intel ICH2", "Intel ICH3", "SiS 7012", - "NVIDIA nForce Audio" + "NVIDIA nForce Audio", + "AMD 768" }; static struct pci_device_id i810_pci_tbl [] __initdata = { @@ -259,6 +264,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012}, {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_768_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768}, {0,} }; @@ -2679,6 +2686,14 @@ break; } + codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L); + if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID)) + { + printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97); + kfree(codec); + continue; + } + card->ac97_features = eid; /* Now check the codec for useful features to make up for diff -urN linux-2.4.18/drivers/sound/ite8172.c linux-2.4.19-pre5/drivers/sound/ite8172.c --- linux-2.4.18/drivers/sound/ite8172.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/ite8172.c Sat Mar 30 22:55:35 2002 @@ -42,14 +42,15 @@ * * Memory mapping the audio buffers, and the ioctl controls that go * with it. * * S/PDIF output. + * * I2S support. * 3. The following is not supported: - * * I2S input. * * legacy audio mode. * 4. Support for volume button interrupts is implemented but doesn't * work yet. * * Revision history - * 02.08.2001 0.1 Initial release + * 02.08.2001 Initial release + * 06.22.2001 Added I2S support */ #include #include @@ -58,7 +59,7 @@ #include #include #include -#include +#include #include #include #include @@ -82,6 +83,19 @@ #undef IT8172_VERBOSE_DEBUG #define DBG(x) {} +#define IT8172_MODULE_NAME "IT8172 audio" +#define PFX IT8172_MODULE_NAME + +#ifdef IT8172_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) + + static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -228,75 +242,84 @@ #define POLL_COUNT 0x5000 -#define IT8172_MODULE_NAME "IT8172 audio" -#define PFX IT8172_MODULE_NAME ": " +/* --------------------------------------------------------------------- */ +/* + * Define DIGITAL1 as the I2S channel, since it is not listed in + * soundcard.h. + */ +#define SOUND_MIXER_I2S SOUND_MIXER_DIGITAL1 +#define SOUND_MASK_I2S SOUND_MASK_DIGITAL1 +#define SOUND_MIXER_READ_I2S MIXER_READ(SOUND_MIXER_I2S) +#define SOUND_MIXER_WRITE_I2S MIXER_WRITE(SOUND_MIXER_I2S) /* --------------------------------------------------------------------- */ struct it8172_state { - /* list of it8172 devices */ - struct list_head devs; + /* list of it8172 devices */ + struct list_head devs; - /* the corresponding pci_dev structure */ - struct pci_dev *dev; + /* the corresponding pci_dev structure */ + struct pci_dev *dev; - /* soundcore stuff */ - int dev_audio; - - /* hardware resources */ - unsigned long io; - unsigned int irq; - - /* PCI ID's */ - u16 vendor; - u16 device; - u8 rev; /* the chip revision */ - - /* options */ - int spdif_volume; /* S/PDIF output is enabled if != -1 */ + /* soundcore stuff */ + int dev_audio; + /* hardware resources */ + unsigned long io; + unsigned int irq; + + /* PCI ID's */ + u16 vendor; + u16 device; + u8 rev; /* the chip revision */ + + /* options */ + int spdif_volume; /* S/PDIF output is enabled if != -1 */ + int i2s_volume; /* current I2S out volume, in OSS format */ + int i2s_recording;/* 1 = recording from I2S, 0 = not */ + #ifdef IT8172_DEBUG - /* debug /proc entry */ - struct proc_dir_entry *ps; - struct proc_dir_entry *ac97_ps; + /* debug /proc entry */ + struct proc_dir_entry *ps; + struct proc_dir_entry *ac97_ps; #endif /* IT8172_DEBUG */ - struct ac97_codec codec; + struct ac97_codec codec; - unsigned short pcc, capcc; - unsigned dacrate, adcrate; + unsigned short pcc, capcc; + unsigned dacrate, adcrate; - spinlock_t lock; - struct semaphore open_sem; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - void* nextIn; - void* nextOut; - int count; - int curBufPtr; - unsigned total_bytes; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned stopped:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + struct dmabuf { + void *rawbuf; + dma_addr_t dmaaddr; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + void* nextIn; + void* nextOut; + int count; + int curBufPtr; + unsigned total_bytes; + unsigned error; /* over/underrun */ + wait_queue_head_t wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned stopped:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dma_dac, dma_adc; }; /* --------------------------------------------------------------------- */ @@ -307,114 +330,114 @@ extern inline unsigned ld2(unsigned int x) { - unsigned r = 0; + unsigned r = 0; - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; } /* --------------------------------------------------------------------- */ static void it8172_delay(int msec) { - unsigned long tmo; - signed long tmo2; + unsigned long tmo; + signed long tmo2; - if (in_interrupt()) - return; + if (in_interrupt()) + return; - tmo = jiffies + (msec*HZ)/1000; - for (;;) { - tmo2 = tmo - jiffies; - if (tmo2 <= 0) - break; - schedule_timeout(tmo2); - } + tmo = jiffies + (msec*HZ)/1000; + for (;;) { + tmo2 = tmo - jiffies; + if (tmo2 <= 0) + break; + schedule_timeout(tmo2); + } } static unsigned short get_compat_rate(unsigned* rate) { - unsigned rate_out = *rate; - unsigned short sr; + unsigned rate_out = *rate; + unsigned short sr; - if (rate_out >= 46050) { - sr = CC_SR_48000; rate_out = 48000; - } else if (rate_out >= 41250) { - sr = CC_SR_44100; rate_out = 44100; - } else if (rate_out >= 35200) { - sr = CC_SR_38400; rate_out = 38400; - } else if (rate_out >= 27025) { - sr = CC_SR_32000; rate_out = 32000; - } else if (rate_out >= 20625) { - sr = CC_SR_22050; rate_out = 22050; - } else if (rate_out >= 17600) { - sr = CC_SR_19200; rate_out = 19200; - } else if (rate_out >= 13513) { - sr = CC_SR_16000; rate_out = 16000; - } else if (rate_out >= 10313) { - sr = CC_SR_11025; rate_out = 11025; - } else if (rate_out >= 8800) { - sr = CC_SR_9600; rate_out = 9600; - } else if (rate_out >= 6750) { - sr = CC_SR_8000; rate_out = 8000; - } else { - sr = CC_SR_5500; rate_out = 5500; - } + if (rate_out >= 46050) { + sr = CC_SR_48000; rate_out = 48000; + } else if (rate_out >= 41250) { + sr = CC_SR_44100; rate_out = 44100; + } else if (rate_out >= 35200) { + sr = CC_SR_38400; rate_out = 38400; + } else if (rate_out >= 27025) { + sr = CC_SR_32000; rate_out = 32000; + } else if (rate_out >= 20625) { + sr = CC_SR_22050; rate_out = 22050; + } else if (rate_out >= 17600) { + sr = CC_SR_19200; rate_out = 19200; + } else if (rate_out >= 13513) { + sr = CC_SR_16000; rate_out = 16000; + } else if (rate_out >= 10313) { + sr = CC_SR_11025; rate_out = 11025; + } else if (rate_out >= 8800) { + sr = CC_SR_9600; rate_out = 9600; + } else if (rate_out >= 6750) { + sr = CC_SR_8000; rate_out = 8000; + } else { + sr = CC_SR_5500; rate_out = 5500; + } - *rate = rate_out; - return sr; + *rate = rate_out; + return sr; } static void set_adc_rate(struct it8172_state *s, unsigned rate) { - unsigned long flags; - unsigned short sr; + unsigned long flags; + unsigned short sr; - sr = get_compat_rate(&rate); + sr = get_compat_rate(&rate); - spin_lock_irqsave(&s->lock, flags); - s->capcc &= ~CC_SR_MASK; - s->capcc |= sr; - outw(s->capcc, s->io+IT_AC_CAPCC); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); + s->capcc &= ~CC_SR_MASK; + s->capcc |= sr; + outw(s->capcc, s->io+IT_AC_CAPCC); + spin_unlock_irqrestore(&s->lock, flags); - s->adcrate = rate; + s->adcrate = rate; } static void set_dac_rate(struct it8172_state *s, unsigned rate) { - unsigned long flags; - unsigned short sr; + unsigned long flags; + unsigned short sr; - sr = get_compat_rate(&rate); + sr = get_compat_rate(&rate); - spin_lock_irqsave(&s->lock, flags); - s->pcc &= ~CC_SR_MASK; - s->pcc |= sr; - outw(s->pcc, s->io+IT_AC_PCC); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); + s->pcc &= ~CC_SR_MASK; + s->pcc |= sr; + outw(s->pcc, s->io+IT_AC_PCC); + spin_unlock_irqrestore(&s->lock, flags); - s->dacrate = rate; + s->dacrate = rate; } @@ -422,89 +445,88 @@ static u16 rdcodec(struct ac97_codec *codec, u8 addr) { - struct it8172_state *s = (struct it8172_state *)codec->private_data; - unsigned long flags; - unsigned short circp, data; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) - break; - if (i == POLL_COUNT) - printk(KERN_INFO PFX "rdcodec: codec ready poll expired!\n"); - - circp = addr & CIRCP_CIA_MASK; - circp |= (codec->id << CIRCP_CID_BIT); - circp |= CIRCP_RWC; // read command - outw(circp, s->io+IT_AC_CIRCP); - - /* now wait for the data */ - for (i = 0; i < POLL_COUNT; i++) - if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF) - break; - if (i == POLL_COUNT) - printk(KERN_INFO PFX "rdcodec: read poll expired!\n"); + struct it8172_state *s = (struct it8172_state *)codec->private_data; + unsigned long flags; + unsigned short circp, data; + int i; + + spin_lock_irqsave(&s->lock, flags); - data = inw(s->io+IT_AC_CIRDP); - spin_unlock_irqrestore(&s->lock, flags); + for (i = 0; i < POLL_COUNT; i++) + if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) + break; + if (i == POLL_COUNT) + err("rdcodec: codec ready poll expired!"); + + circp = addr & CIRCP_CIA_MASK; + circp |= (codec->id << CIRCP_CID_BIT); + circp |= CIRCP_RWC; // read command + outw(circp, s->io+IT_AC_CIRCP); + + /* now wait for the data */ + for (i = 0; i < POLL_COUNT; i++) + if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF) + break; + if (i == POLL_COUNT) + err("rdcodec: read poll expired!"); - return data; + data = inw(s->io+IT_AC_CIRDP); + spin_unlock_irqrestore(&s->lock, flags); + + return data; } static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) { - struct it8172_state *s = (struct it8172_state *)codec->private_data; - unsigned long flags; - unsigned short circp; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) - if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) - break; - if (i == POLL_COUNT) - printk(KERN_INFO PFX "wrcodec: codec ready poll expired!\n"); - - circp = addr & CIRCP_CIA_MASK; - circp |= (codec->id << CIRCP_CID_BIT); - circp &= ~CIRCP_RWC; // write command + struct it8172_state *s = (struct it8172_state *)codec->private_data; + unsigned long flags; + unsigned short circp; + int i; + + spin_lock_irqsave(&s->lock, flags); + + for (i = 0; i < POLL_COUNT; i++) + if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) + break; + if (i == POLL_COUNT) + err("wrcodec: codec ready poll expired!"); + + circp = addr & CIRCP_CIA_MASK; + circp |= (codec->id << CIRCP_CID_BIT); + circp &= ~CIRCP_RWC; // write command - outw(data, s->io+IT_AC_CIRDP); // send data first - outw(circp, s->io+IT_AC_CIRCP); + outw(data, s->io+IT_AC_CIRDP); // send data first + outw(circp, s->io+IT_AC_CIRCP); - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->lock, flags); } static void waitcodec(struct ac97_codec *codec) { - unsigned short temp; + unsigned short temp; + + /* codec_wait is used to wait for a ready state after + an AC97_RESET. */ + it8172_delay(10); - /* codec_wait is used to wait for a ready state after - an AC97_RESET. */ - it8172_delay(10); - - temp = rdcodec(codec, 0x26); - - // If power down, power up - if (temp & 0x3f00) { - // Power on - wrcodec(codec, 0x26, 0); - it8172_delay(100); - // Reread temp = rdcodec(codec, 0x26); - } + + // If power down, power up + if (temp & 0x3f00) { + // Power on + wrcodec(codec, 0x26, 0); + it8172_delay(100); + // Reread + temp = rdcodec(codec, 0x26); + } - // Check if Codec REF,ANL,DAC,ADC ready***/ - if ((temp & 0x3f0f) != 0x000f) { - printk(KERN_INFO PFX "codec reg 26 status (0x%x) not ready!!\n", - temp); - return; - } + // Check if Codec REF,ANL,DAC,ADC ready***/ + if ((temp & 0x3f0f) != 0x000f) { + err("codec reg 26 status (0x%x) not ready!!", temp); + return; + } } @@ -512,120 +534,120 @@ extern inline void stop_adc(struct it8172_state *s) { - struct dmabuf* db = &s->dma_adc; - unsigned long flags; - unsigned char imc; + struct dmabuf* db = &s->dma_adc; + unsigned long flags; + unsigned char imc; - if (db->stopped) - return; + if (db->stopped) + return; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); - s->capcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); - s->capcc |= CC_CSP; - outw(s->capcc, s->io+IT_AC_CAPCC); + s->capcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); + s->capcc |= CC_CSP; + outw(s->capcc, s->io+IT_AC_CAPCC); - // disable capture interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc | IMC_CCIM, s->io+IT_AC_IMC); + // disable capture interrupt + imc = inb(s->io+IT_AC_IMC); + outb(imc | IMC_CCIM, s->io+IT_AC_IMC); - db->stopped = 1; + db->stopped = 1; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->lock, flags); } extern inline void stop_dac(struct it8172_state *s) { - struct dmabuf* db = &s->dma_dac; - unsigned long flags; - unsigned char imc; + struct dmabuf* db = &s->dma_dac; + unsigned long flags; + unsigned char imc; - if (db->stopped) - return; + if (db->stopped) + return; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); - s->pcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); - s->pcc |= CC_CSP; - outw(s->pcc, s->io+IT_AC_PCC); + s->pcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L); + s->pcc |= CC_CSP; + outw(s->pcc, s->io+IT_AC_PCC); - // disable playback interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc | IMC_PCIM, s->io+IT_AC_IMC); + // disable playback interrupt + imc = inb(s->io+IT_AC_IMC); + outb(imc | IMC_PCIM, s->io+IT_AC_IMC); - db->stopped = 1; + db->stopped = 1; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->lock, flags); } static void start_dac(struct it8172_state *s) { - struct dmabuf* db = &s->dma_dac; - unsigned long flags; - unsigned char imc; - unsigned long buf1, buf2; + struct dmabuf* db = &s->dma_dac; + unsigned long flags; + unsigned char imc; + unsigned long buf1, buf2; - if (!db->stopped) - return; + if (!db->stopped) + return; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); - // reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize - buf1 = virt_to_bus(db->nextOut); - buf2 = buf1 + db->fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - outl(buf1, s->io+IT_AC_PCB1STA); - outl(buf2, s->io+IT_AC_PCB2STA); - db->curBufPtr = IT_AC_PCB1STA; - - // enable playback interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_PCIM, s->io+IT_AC_IMC); + // reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize + buf1 = virt_to_bus(db->nextOut); + buf2 = buf1 + db->fragsize; + if (buf2 >= db->dmaaddr + db->dmasize) + buf2 -= db->dmasize; + + outl(buf1, s->io+IT_AC_PCB1STA); + outl(buf2, s->io+IT_AC_PCB2STA); + db->curBufPtr = IT_AC_PCB1STA; + + // enable playback interrupt + imc = inb(s->io+IT_AC_IMC); + outb(imc & ~IMC_PCIM, s->io+IT_AC_IMC); - s->pcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); - s->pcc |= CC_CA; - outw(s->pcc, s->io+IT_AC_PCC); + s->pcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); + s->pcc |= CC_CA; + outw(s->pcc, s->io+IT_AC_PCC); - db->stopped = 0; + db->stopped = 0; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->lock, flags); } static void start_adc(struct it8172_state *s) { - struct dmabuf* db = &s->dma_adc; - unsigned long flags; - unsigned char imc; - unsigned long buf1, buf2; + struct dmabuf* db = &s->dma_adc; + unsigned long flags; + unsigned char imc; + unsigned long buf1, buf2; - if (!db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); + if (!db->stopped) + return; - // reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize - buf1 = virt_to_bus(db->nextIn); - buf2 = buf1 + db->fragsize; - if (buf2 >= db->dmaaddr + db->dmasize) - buf2 -= db->dmasize; - - outl(buf1, s->io+IT_AC_CAPB1STA); - outl(buf2, s->io+IT_AC_CAPB2STA); - db->curBufPtr = IT_AC_CAPB1STA; + spin_lock_irqsave(&s->lock, flags); - // enable capture interrupt - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_CCIM, s->io+IT_AC_IMC); + // reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize + buf1 = virt_to_bus(db->nextIn); + buf2 = buf1 + db->fragsize; + if (buf2 >= db->dmaaddr + db->dmasize) + buf2 -= db->dmasize; + + outl(buf1, s->io+IT_AC_CAPB1STA); + outl(buf2, s->io+IT_AC_CAPB2STA); + db->curBufPtr = IT_AC_CAPB1STA; + + // enable capture interrupt + imc = inb(s->io+IT_AC_IMC); + outb(imc & ~IMC_CCIM, s->io+IT_AC_IMC); - s->capcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); - s->capcc |= CC_CA; - outw(s->capcc, s->io+IT_AC_CAPCC); + s->capcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L); + s->capcc |= CC_CA; + outw(s->capcc, s->io+IT_AC_CAPCC); - db->stopped = 0; + db->stopped = 0; - spin_unlock_irqrestore(&s->lock, flags); + spin_unlock_irqrestore(&s->lock, flags); } /* --------------------------------------------------------------------- */ @@ -635,94 +657,103 @@ extern inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db) { - struct page *page, *pend; + struct page *page, *pend; - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - mem_map_unreserve(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, - db->rawbuf, db->dmaaddr); - } - db->rawbuf = db->nextIn = db->nextOut = NULL; - db->mapped = db->ready = 0; + if (db->rawbuf) { + /* undo marking the pages as reserved */ + pend = virt_to_page(db->rawbuf + + (PAGE_SIZE << db->buforder) - 1); + for (page = virt_to_page(db->rawbuf); page <= pend; page++) + mem_map_unreserve(page); + pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, + db->rawbuf, db->dmaaddr); + } + db->rawbuf = db->nextIn = db->nextOut = NULL; + db->mapped = db->ready = 0; } static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg) { - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, - PAGE_SIZE << order, - &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; - otherwise remap_page_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - mem_map_reserve(page); - } - - db->count = 0; - db->nextIn = db->nextOut = db->rawbuf; - - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? - db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; + int order; + unsigned bytepersec; + unsigned bufs; + struct page *page, *pend; + + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; + order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = + pci_alloc_consistent(s->dev, + PAGE_SIZE << order, + &db->dmaaddr))) + break; + if (!db->rawbuf) + return -ENOMEM; + db->buforder = order; + /* now mark the pages as reserved; + otherwise remap_page_range doesn't do what we want */ + pend = virt_to_page(db->rawbuf + + (PAGE_SIZE << db->buforder) - 1); + for (page = virt_to_page(db->rawbuf); page <= pend; page++) + mem_map_reserve(page); + } + + db->count = 0; + db->nextIn = db->nextOut = db->rawbuf; + + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? + db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & (CC_DF>>CC_FMT_BIT)) ? 0 : 0x80, db->dmasize); - - // set data length register - outw(db->fragsize, s->io+reg+2); - db->ready = 1; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & (CC_DF>>CC_FMT_BIT)) ? 0 : 0x80, bufs); + +#ifdef IT8172_VERBOSE_DEBUG + dbg("rate=%d, fragsize=%d, numfrag=%d, dmasize=%d", + rate, db->fragsize, db->numfrag, db->dmasize); +#endif + + // set data length register + outw(db->fragsize, s->io+reg+2); + db->ready = 1; - return 0; + return 0; } extern inline int prog_dmabuf_adc(struct it8172_state *s) { - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc, s->adcrate, - (s->capcc & CC_FMT_MASK) >> CC_FMT_BIT, - IT_AC_CAPCC); + stop_adc(s); + return prog_dmabuf(s, &s->dma_adc, s->adcrate, + (s->capcc & CC_FMT_MASK) >> CC_FMT_BIT, + IT_AC_CAPCC); } extern inline int prog_dmabuf_dac(struct it8172_state *s) { - stop_dac(s); - return prog_dmabuf(s, &s->dma_dac, s->dacrate, - (s->pcc & CC_FMT_MASK) >> CC_FMT_BIT, - IT_AC_PCC); + stop_dac(s); + return prog_dmabuf(s, &s->dma_dac, s->dacrate, + (s->pcc & CC_FMT_MASK) >> CC_FMT_BIT, + IT_AC_PCC); } @@ -730,917 +761,1120 @@ static void it8172_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct it8172_state *s = (struct it8172_state *)dev_id; - struct dmabuf* dac = &s->dma_dac; - struct dmabuf* adc = &s->dma_adc; - unsigned char isc, vs; - unsigned short vol, mute; - unsigned long newptr; - - spin_lock(&s->lock); - - isc = inb(s->io+IT_AC_ISC); - - /* fastpath out, to ease interrupt sharing */ - if (!(isc & (ISC_VCI | ISC_CCI | ISC_PCI))) - return; - - /* clear audio interrupts first */ - outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC); - - /* handle volume button events */ - if (isc & ISC_VCI) { - vs = inb(s->io+IT_AC_VS); - outb(0, s->io+IT_AC_VS); - vol = inw(s->io+IT_AC_PCMOV); - mute = vol & PCMOV_PCMOM; - vol &= PCMOV_PCMLCG_MASK; - if ((vs & VS_VUP) && vol > 0) - vol--; - if ((vs & VS_VDP) && vol < 0x1f) - vol++; - vol |= (vol << PCMOV_PCMRCG_BIT); - if (vs & VS_VMP) - vol |= (mute ^ PCMOV_PCMOM); - outw(vol, s->io+IT_AC_PCMOV); - } - - /* update capture pointers */ - if (isc & ISC_CCI) { - if (adc->count > adc->dmasize - adc->fragsize) { - // Overrun. Stop ADC and log the error - stop_adc(s); - adc->error++; - printk(KERN_INFO PFX "adc overrun\n"); - } else { - newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize; - if (newptr >= adc->dmaaddr + adc->dmasize) - newptr -= adc->dmasize; + struct it8172_state *s = (struct it8172_state *)dev_id; + struct dmabuf* dac = &s->dma_dac; + struct dmabuf* adc = &s->dma_adc; + unsigned char isc, vs; + unsigned short vol, mute; + unsigned long newptr; + + spin_lock(&s->lock); + + isc = inb(s->io+IT_AC_ISC); + + /* fastpath out, to ease interrupt sharing */ + if (!(isc & (ISC_VCI | ISC_CCI | ISC_PCI))) { + spin_unlock(&s->lock); + return; + } + + /* clear audio interrupts first */ + outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC); + + /* handle volume button events (ignore if S/PDIF enabled) */ + if ((isc & ISC_VCI) && s->spdif_volume == -1) { + vs = inb(s->io+IT_AC_VS); + outb(0, s->io+IT_AC_VS); + vol = inw(s->io+IT_AC_PCMOV); + mute = vol & PCMOV_PCMOM; + vol &= PCMOV_PCMLCG_MASK; + if ((vs & VS_VUP) && vol > 0) + vol--; + if ((vs & VS_VDP) && vol < 0x1f) + vol++; + vol |= (vol << PCMOV_PCMRCG_BIT); + if (vs & VS_VMP) + vol |= (mute ^ PCMOV_PCMOM); + outw(vol, s->io+IT_AC_PCMOV); + } + + /* update capture pointers */ + if (isc & ISC_CCI) { + if (adc->count > adc->dmasize - adc->fragsize) { + // Overrun. Stop ADC and log the error + stop_adc(s); + adc->error++; + dbg("adc overrun"); + } else { + newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize; + if (newptr >= adc->dmaaddr + adc->dmasize) + newptr -= adc->dmasize; - outl(newptr, s->io+adc->curBufPtr); - adc->curBufPtr = (adc->curBufPtr == IT_AC_CAPB1STA) ? - IT_AC_CAPB2STA : IT_AC_CAPB1STA; + outl(newptr, s->io+adc->curBufPtr); + adc->curBufPtr = (adc->curBufPtr == IT_AC_CAPB1STA) ? + IT_AC_CAPB2STA : IT_AC_CAPB1STA; - adc->nextIn += adc->fragsize; - if (adc->nextIn >= adc->rawbuf + adc->dmasize) - adc->nextIn -= adc->dmasize; + adc->nextIn += adc->fragsize; + if (adc->nextIn >= adc->rawbuf + adc->dmasize) + adc->nextIn -= adc->dmasize; - adc->count += adc->fragsize; - adc->total_bytes += adc->fragsize; + adc->count += adc->fragsize; + adc->total_bytes += adc->fragsize; - /* wake up anybody listening */ - if (waitqueue_active(&adc->wait)) - wake_up_interruptible(&adc->wait); - } - } - - /* update playback pointers */ - if (isc & ISC_PCI) { - newptr = virt_to_bus(dac->nextOut) + 2*dac->fragsize; - if (newptr >= dac->dmaaddr + dac->dmasize) - newptr -= dac->dmasize; + /* wake up anybody listening */ + if (waitqueue_active(&adc->wait)) + wake_up_interruptible(&adc->wait); + } + } + + /* update playback pointers */ + if (isc & ISC_PCI) { + newptr = virt_to_bus(dac->nextOut) + 2*dac->fragsize; + if (newptr >= dac->dmaaddr + dac->dmasize) + newptr -= dac->dmasize; - outl(newptr, s->io+dac->curBufPtr); - dac->curBufPtr = (dac->curBufPtr == IT_AC_PCB1STA) ? - IT_AC_PCB2STA : IT_AC_PCB1STA; + outl(newptr, s->io+dac->curBufPtr); + dac->curBufPtr = (dac->curBufPtr == IT_AC_PCB1STA) ? + IT_AC_PCB2STA : IT_AC_PCB1STA; - dac->nextOut += dac->fragsize; - if (dac->nextOut >= dac->rawbuf + dac->dmasize) - dac->nextOut -= dac->dmasize; + dac->nextOut += dac->fragsize; + if (dac->nextOut >= dac->rawbuf + dac->dmasize) + dac->nextOut -= dac->dmasize; - dac->count -= dac->fragsize; - dac->total_bytes += dac->fragsize; + dac->count -= dac->fragsize; + dac->total_bytes += dac->fragsize; - /* wake up anybody listening */ - if (waitqueue_active(&dac->wait)) - wake_up_interruptible(&dac->wait); + /* wake up anybody listening */ + if (waitqueue_active(&dac->wait)) + wake_up_interruptible(&dac->wait); - if (dac->count <= 0) - stop_dac(s); - } + if (dac->count <= 0) + stop_dac(s); + } - spin_unlock(&s->lock); + spin_unlock(&s->lock); } /* --------------------------------------------------------------------- */ -static loff_t it8172_llseek(struct file *file, loff_t offset, int origin) +static int it8172_open_mixdev(struct inode *inode, struct file *file) { - return -ESPIPE; + int minor = MINOR(inode->i_rdev); + struct list_head *list; + struct it8172_state *s; + + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct it8172_state, devs); + if (s->codec.dev_mixer == minor) + break; + } + file->private_data = s; + return 0; } - -static int it8172_open_mixdev(struct inode *inode, struct file *file) +static int it8172_release_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); - struct list_head *list; - struct it8172_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct it8172_state, devs); - if (s->codec.dev_mixer == minor) - break; - } - file->private_data = s; - return 0; + return 0; } -static int it8172_release_mixdev(struct inode *inode, struct file *file) + +static u16 +cvt_ossvol(unsigned int gain) { - return 0; + u16 ret; + + if (gain == 0) + return 0; + + if (gain > 100) + gain = 100; + + ret = (100 - gain + 32) / 4; + ret = ret > 31 ? 31 : ret; + return ret; } static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) { - return codec->mixer_ioctl(codec, cmd, arg); + struct it8172_state *s = (struct it8172_state *)codec->private_data; + unsigned int left, right; + unsigned long flags; + int val; + u16 vol; + + /* + * When we are in S/PDIF mode, we want to disable any analog output so + * we filter the master/PCM channel volume ioctls. + * + * Also filter I2S channel, which AC'97 knows nothing about. + */ + + switch (cmd) { + case SOUND_MIXER_WRITE_VOLUME: + // if not in S/PDIF mode, pass to AC'97 + if (s->spdif_volume == -1) + break; + return 0; + case SOUND_MIXER_WRITE_PCM: + // if not in S/PDIF mode, pass to AC'97 + if (s->spdif_volume == -1) + break; + if (get_user(val, (int *)arg)) + return -EFAULT; + right = ((val >> 8) & 0xff); + left = (val & 0xff); + if (right > 100) + right = 100; + if (left > 100) + left = 100; + s->spdif_volume = (right << 8) | left; + vol = cvt_ossvol(left); + vol |= (cvt_ossvol(right) << PCMOV_PCMRCG_BIT); + if (vol == 0) + vol = PCMOV_PCMOM; // mute + spin_lock_irqsave(&s->lock, flags); + outw(vol, s->io+IT_AC_PCMOV); + spin_unlock_irqrestore(&s->lock, flags); + return put_user(s->spdif_volume, (int *)arg); + case SOUND_MIXER_READ_PCM: + // if not in S/PDIF mode, pass to AC'97 + if (s->spdif_volume == -1) + break; + return put_user(s->spdif_volume, (int *)arg); + case SOUND_MIXER_WRITE_I2S: + if (get_user(val, (int *)arg)) + return -EFAULT; + right = ((val >> 8) & 0xff); + left = (val & 0xff); + if (right > 100) + right = 100; + if (left > 100) + left = 100; + s->i2s_volume = (right << 8) | left; + vol = cvt_ossvol(left); + vol |= (cvt_ossvol(right) << I2SV_I2SRCG_BIT); + if (vol == 0) + vol = I2SV_I2SOM; // mute + outw(vol, s->io+IT_AC_I2SV); + return put_user(s->i2s_volume, (int *)arg); + case SOUND_MIXER_READ_I2S: + return put_user(s->i2s_volume, (int *)arg); + case SOUND_MIXER_WRITE_RECSRC: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val & SOUND_MASK_I2S) { + s->i2s_recording = 1; + outb(DRSS_I2S, s->io+IT_AC_DRSS); + return 0; + } else { + s->i2s_recording = 0; + outb(DRSS_AC97_PRIM, s->io+IT_AC_DRSS); + // now let AC'97 select record source + break; + } + case SOUND_MIXER_READ_RECSRC: + if (s->i2s_recording) + return put_user(SOUND_MASK_I2S, (int *)arg); + else + // let AC'97 report recording source + break; + } + + return codec->mixer_ioctl(codec, cmd, arg); } static int it8172_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct ac97_codec *codec = &s->codec; + struct it8172_state *s = (struct it8172_state *)file->private_data; + struct ac97_codec *codec = &s->codec; - return mixdev_ioctl(codec, cmd, arg); + return mixdev_ioctl(codec, cmd, arg); } static /*const*/ struct file_operations it8172_mixer_fops = { - owner: THIS_MODULE, - llseek: it8172_llseek, - ioctl: it8172_ioctl_mixdev, - open: it8172_open_mixdev, - release: it8172_release_mixdev, + owner: THIS_MODULE, + llseek: no_llseek, + ioctl: it8172_ioctl_mixdev, + open: it8172_open_mixdev, + release: it8172_release_mixdev, }; /* --------------------------------------------------------------------- */ static int drain_dac(struct it8172_state *s, int nonblock) { - unsigned long flags; - int count, tmo; + unsigned long flags; + int count, tmo; - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; + if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) + return 0; - for (;;) { - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + //if (nonblock) + //return -EBUSY; + tmo = 1000 * count / s->dacrate; + tmo >>= sample_shift[(s->pcc & CC_FMT_MASK) >> CC_FMT_BIT]; + it8172_delay(tmo); + } if (signal_pending(current)) - break; - if (nonblock) - return -EBUSY; - tmo = 1000 * count / s->dacrate; - tmo >>= sample_shift[(s->pcc & CC_FMT_MASK) >> CC_FMT_BIT]; - it8172_delay(tmo); - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; + return -ERESTARTSYS; + return 0; } /* --------------------------------------------------------------------- */ + +/* + * Copy audio data to/from user buffer from/to dma buffer, taking care + * that we wrap when reading/writing the dma buffer. Returns actual byte + * count written to or read from the dma buffer. + */ +static int copy_dmabuf_user(struct dmabuf *db, char* userbuf, + int count, int to_user) +{ + char* bufptr = to_user ? db->nextOut : db->nextIn; + char* bufend = db->rawbuf + db->dmasize; + + if (bufptr + count > bufend) { + int partial = (int)(bufend - bufptr); + if (to_user) { + if (copy_to_user(userbuf, bufptr, partial)) + return -EFAULT; + if (copy_to_user(userbuf + partial, db->rawbuf, + count - partial)) + return -EFAULT; + } else { + if (copy_from_user(bufptr, userbuf, partial)) + return -EFAULT; + if (copy_from_user(db->rawbuf, + userbuf + partial, + count - partial)) + return -EFAULT; + } + } else { + if (to_user) { + if (copy_to_user(userbuf, bufptr, count)) + return -EFAULT; + } else { + if (copy_from_user(bufptr, userbuf, count)) + return -EFAULT; + } + } + + return count; +} + + static ssize_t it8172_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db = &s->dma_adc; - ssize_t ret; - unsigned long flags; - int cnt, bufcnt, avail; - - if (ppos != &file->f_pos) - return -ESPIPE; - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - while (count > 0) { - // wait for samples in capture buffer - do { - spin_lock_irqsave(&s->lock, flags); - if (db->stopped) - start_adc(s); - avail = db->count; - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - return ret; - } - interruptible_sleep_on(&db->wait); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - return ret; - } - } - } while (avail <= 0); - - cnt = count > avail ? avail : count; - bufcnt = cnt; - if (cnt % db->fragsize) { - // round count up to nearest fragment - int newcnt = db->fragsize * ((cnt + db->fragsize) / db->fragsize); - cnt = newcnt; - } - - // copy from nextOut to user - if (copy_to_user(buffer, db->nextOut, bufcnt)) { - if (!ret) - ret = -EFAULT; - return ret; - } + struct it8172_state *s = (struct it8172_state *)file->private_data; + struct dmabuf *db = &s->dma_adc; + ssize_t ret; + unsigned long flags; + int cnt, remainder, avail; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (db->mapped) + return -ENXIO; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + // wait for samples in capture buffer + do { + spin_lock_irqsave(&s->lock, flags); + if (db->stopped) + start_adc(s); + avail = db->count; + spin_unlock_irqrestore(&s->lock, flags); + if (avail <= 0) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + return ret; + } + interruptible_sleep_on(&db->wait); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + return ret; + } + } + } while (avail <= 0); + + // copy from nextOut to user + if ((cnt = copy_dmabuf_user(db, buffer, count > avail ? + avail : count, 1)) < 0) { + if (!ret) + ret = -EFAULT; + return ret; + } + spin_lock_irqsave(&s->lock, flags); + db->count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + + db->nextOut += cnt; + if (db->nextOut >= db->rawbuf + db->dmasize) + db->nextOut -= db->dmasize; + + count -= cnt; + buffer += cnt; + ret += cnt; + } // while (count > 0) + + /* + * See if the dma buffer count after this read call is + * aligned on a fragsize boundary. If not, read from + * buffer until we reach a boundary, and let's hope this + * is just the last remainder of an audio record. If not + * it means the user is not reading in fragsize chunks, in + * which case it's his/her fault that there are audio gaps + * in their record. + */ spin_lock_irqsave(&s->lock, flags); - db->count -= cnt; + remainder = db->count % db->fragsize; + if (remainder) { + db->nextOut += remainder; + if (db->nextOut >= db->rawbuf + db->dmasize) + db->nextOut -= db->dmasize; + db->count -= remainder; + } spin_unlock_irqrestore(&s->lock, flags); - db->nextOut += cnt; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - - count -= bufcnt; - buffer += bufcnt; - ret += bufcnt; - } // while (count > 0) - - return ret; + return ret; } static ssize_t it8172_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db = &s->dma_dac; - ssize_t ret; - unsigned long flags; - int cnt, bufcnt, avail; - - if (ppos != &file->f_pos) - return -ESPIPE; - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - while (count > 0) { - // wait for space in playback buffer - do { - spin_lock_irqsave(&s->lock, flags); - avail = db->dmasize - db->count; - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - return ret; - } - interruptible_sleep_on(&db->wait); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - return ret; - } - } - } while (avail <= 0); + struct it8172_state *s = (struct it8172_state *)file->private_data; + struct dmabuf *db = &s->dma_dac; + ssize_t ret; + unsigned long flags; + int cnt, remainder, avail; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (db->mapped) + return -ENXIO; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + // wait for space in playback buffer + do { + spin_lock_irqsave(&s->lock, flags); + avail = db->dmasize - db->count; + spin_unlock_irqrestore(&s->lock, flags); + if (avail <= 0) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + return ret; + } + interruptible_sleep_on(&db->wait); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + return ret; + } + } + } while (avail <= 0); - cnt = count > avail ? avail : count; - // copy to nextIn - if (copy_from_user(db->nextIn, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - return ret; - } - - bufcnt = cnt; - if (cnt % db->fragsize) { - // round count up to nearest fragment, and fill remainder of - // fragment with silence - int newcnt = db->fragsize * ((cnt + db->fragsize) / db->fragsize); - memset(db->nextIn + cnt, (s->pcc & CC_DF) ? 0 : 0x80, newcnt - cnt); - cnt = newcnt; - } + // copy to nextIn + if ((cnt = copy_dmabuf_user(db, (char*)buffer, + count > avail ? + avail : count, 0)) < 0) { + if (!ret) + ret = -EFAULT; + return ret; + } - spin_lock_irqsave(&s->lock, flags); - db->count += cnt; - if (db->stopped) - start_dac(s); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); + db->count += cnt; + if (db->stopped) + start_dac(s); + spin_unlock_irqrestore(&s->lock, flags); - db->nextIn += cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; + db->nextIn += cnt; + if (db->nextIn >= db->rawbuf + db->dmasize) + db->nextIn -= db->dmasize; - count -= bufcnt; - buffer += bufcnt; - ret += bufcnt; - } // while (count > 0) + count -= cnt; + buffer += cnt; + ret += cnt; + } // while (count > 0) - return ret; + /* + * See if the dma buffer count after this write call is + * aligned on a fragsize boundary. If not, fill buffer + * with silence to the next boundary, and let's hope this + * is just the last remainder of an audio playback. If not + * it means the user is not sending us fragsize chunks, in + * which case it's his/her fault that there are audio gaps + * in their playback. + */ + spin_lock_irqsave(&s->lock, flags); + remainder = db->count % db->fragsize; + if (remainder) { + int fill_cnt = db->fragsize - remainder; + memset(db->nextIn, 0, fill_cnt); + db->nextIn += fill_cnt; + if (db->nextIn >= db->rawbuf + db->dmasize) + db->nextIn -= db->dmasize; + db->count += fill_cnt; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; } /* No kernel lock - we have our own spinlock */ static unsigned int it8172_poll(struct file *file, struct poll_table_struct *wait) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= - s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; + struct it8172_state *s = (struct it8172_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) { + if (!s->dma_dac.ready) + return 0; + poll_wait(file, &s->dma_dac.wait, wait); + } + if (file->f_mode & FMODE_READ) { + if (!s->dma_adc.ready) + return 0; + poll_wait(file, &s->dma_adc.wait, wait); + } + + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= + s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; } static int it8172_mmap(struct file *file, struct vm_area_struct *vma) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - struct dmabuf *db; - unsigned long size; - - lock_kernel(); - if (vma->vm_flags & VM_WRITE) - db = &s->dma_dac; - else if (vma->vm_flags & VM_READ) - db = &s->dma_adc; - else { - unlock_kernel(); - return -EINVAL; - } - if (vma->vm_pgoff != 0) { - unlock_kernel(); - return -EINVAL; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - unlock_kernel(); - return -EINVAL; - } - if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), - size, vma->vm_page_prot)) { + struct it8172_state *s = (struct it8172_state *)file->private_data; + struct dmabuf *db; + unsigned long size; + + lock_kernel(); + if (vma->vm_flags & VM_WRITE) + db = &s->dma_dac; + else if (vma->vm_flags & VM_READ) + db = &s->dma_adc; + else { + unlock_kernel(); + return -EINVAL; + } + if (vma->vm_pgoff != 0) { + unlock_kernel(); + return -EINVAL; + } + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) { + unlock_kernel(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), + size, vma->vm_page_prot)) { + unlock_kernel(); + return -EAGAIN; + } + db->mapped = 1; unlock_kernel(); - return -EAGAIN; - } - db->mapped = 1; - unlock_kernel(); - return 0; + return 0; } #ifdef IT8172_VERBOSE_DEBUG static struct ioctl_str_t { - unsigned int cmd; - const char* str; + unsigned int cmd; + const char* str; } ioctl_str[] = { - {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, - {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, - {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, - {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, - {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, - {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, - {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, - {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, - {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, - {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, - {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, - {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, - {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, - {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, - {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, - {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, - {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, - {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, - {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, - {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, - {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, - {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, - {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, - {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, - {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, - {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, - {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, - {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, - {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, - {OSS_GETVERSION, "OSS_GETVERSION"}, - {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, - {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, - {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, - {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} + {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, + {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, + {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, + {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, + {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, + {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, + {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, + {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, + {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, + {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, + {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, + {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, + {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, + {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, + {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, + {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, + {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, + {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, + {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, + {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, + {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, + {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, + {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, + {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, + {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, + {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, + {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, + {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, + {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, + {OSS_GETVERSION, "OSS_GETVERSION"}, + {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, + {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, + {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, + {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} }; #endif static int it8172_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct it8172_state *s = (struct it8172_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret, diff; + struct it8172_state *s = (struct it8172_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int count; + int val, mapped, ret, diff; - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); #ifdef IT8172_VERBOSE_DEBUG - for (count=0; countf_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, file->f_flags & O_NONBLOCK); + return 0; - case SNDCTL_DSP_SETDUPLEX: - return 0; + case SNDCTL_DSP_SETDUPLEX: + return 0; - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | + DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(); - s->dma_dac.count = s->dma_dac.total_bytes = 0; - s->dma_dac.nextIn = s->dma_dac.nextOut = s->dma_dac.rawbuf; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(); - s->dma_adc.count = s->dma_adc.total_bytes = 0; - s->dma_adc.nextIn = s->dma_adc.nextOut = s->dma_adc.rawbuf; - } - return 0; + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.count = s->dma_dac.total_bytes = 0; + s->dma_dac.nextIn = s->dma_dac.nextOut = + s->dma_dac.rawbuf; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.count = s->dma_adc.total_bytes = 0; + s->dma_adc.nextIn = s->dma_adc.nextOut = + s->dma_adc.rawbuf; + } + return 0; - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - set_adc_rate(s, val); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - set_dac_rate(s, val); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user((file->f_mode & FMODE_READ) ? - s->adcrate : s->dacrate, (int *)arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val) - s->capcc |= CC_SM; - else - s->capcc &= ~CC_SM; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val) - s->pcc |= CC_SM; - else - s->pcc &= ~CC_SM; - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; + case SNDCTL_DSP_SPEED: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + set_adc_rate(s, val); + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + set_dac_rate(s, val); + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + } + return put_user((file->f_mode & FMODE_READ) ? + s->adcrate : s->dacrate, (int *)arg); - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val >= 2) { - val = 2; - s->capcc |= CC_SM; + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + if (val) + s->capcc |= CC_SM; + else + s->capcc &= ~CC_SM; + outw(s->capcc, s->io+IT_AC_CAPCC); + if ((ret = prog_dmabuf_adc(s))) + return ret; } - else - s->capcc &= ~CC_SM; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - switch (val) { - case 1: - s->pcc &= ~CC_SM; - break; - case 2: - s->pcc |= CC_SM; - break; - default: - // FIX! support multichannel??? - val = 2; - s->pcc |= CC_SM; - break; + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + if (val) + s->pcc |= CC_SM; + else + s->pcc &= ~CC_SM; + outw(s->pcc, s->io+IT_AC_PCC); + if ((ret = prog_dmabuf_dac(s))) + return ret; } - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user(val, (int *)arg); + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + if (val >= 2) { + val = 2; + s->capcc |= CC_SM; + } + else + s->capcc &= ~CC_SM; + outw(s->capcc, s->io+IT_AC_CAPCC); + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + switch (val) { + case 1: + s->pcc &= ~CC_SM; + break; + case 2: + s->pcc |= CC_SM; + break; + default: + // FIX! support multichannel??? + val = 2; + s->pcc |= CC_SM; + break; + } + outw(s->pcc, s->io+IT_AC_PCC); + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + } + return put_user(val, (int *)arg); - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val == AFMT_S16_LE) - s->capcc |= CC_DF; - else { - val = AFMT_U8; - s->capcc &= ~CC_DF; + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + if (val == AFMT_S16_LE) + s->capcc |= CC_DF; + else { + val = AFMT_U8; + s->capcc &= ~CC_DF; + } + outw(s->capcc, s->io+IT_AC_CAPCC); + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + if (val == AFMT_S16_LE) + s->pcc |= CC_DF; + else { + val = AFMT_U8; + s->pcc &= ~CC_DF; + } + outw(s->pcc, s->io+IT_AC_PCC); + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + } else { + if (file->f_mode & FMODE_READ) + val = (s->capcc & CC_DF) ? + AFMT_S16_LE : AFMT_U8; + else + val = (s->pcc & CC_DF) ? + AFMT_S16_LE : AFMT_U8; } - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val == AFMT_S16_LE) - s->pcc |= CC_DF; - else { - val = AFMT_U8; - s->pcc &= ~CC_DF; - } - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } else { - if (file->f_mode & FMODE_READ) - val = (s->capcc & CC_DF) ? AFMT_S16_LE : AFMT_U8; - else - val = (s->pcc & CC_DF) ? AFMT_S16_LE : AFMT_U8; - } - return put_user(val, (int *)arg); + return put_user(val, (int *)arg); - case SNDCTL_DSP_POST: - return 0; + case SNDCTL_DSP_POST: + return 0; - case SNDCTL_DSP_GETTRIGGER: - val = 0; - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) - val |= PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + case SNDCTL_DSP_GETTRIGGER: + val = 0; + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) + val |= PCM_ENABLE_OUTPUT; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) - start_adc(s); - else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) - start_dac(s); - else - stop_dac(s); - } - return 0; + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) + start_adc(s); + else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) + start_dac(s); + else + stop_dac(s); + } + return 0; - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - abinfo.fragsize = s->dma_dac.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - if (!s->dma_dac.stopped) - count -= (s->dma_dac.fragsize - inw(s->io+IT_AC_PCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac.dmasize - count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - abinfo.fragsize = s->dma_adc.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - if (!s->dma_adc.stopped) - count += (s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + abinfo.fragsize = s->dma_dac.fragsize; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + if (!s->dma_dac.stopped) + count -= (s->dma_dac.fragsize - + inw(s->io+IT_AC_PCDL)); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac.dmasize - count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? + -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + abinfo.fragsize = s->dma_adc.fragsize; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_adc.count; + if (!s->dma_adc.stopped) + count += (s->dma_adc.fragsize - + inw(s->io+IT_AC_CAPCDL)); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + abinfo.bytes = count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? + -EFAULT : 0; - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - if (!s->dma_dac.stopped) - count -= (s->dma_dac.fragsize - inw(s->io+IT_AC_PCDL)); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, (int *)arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (!s->dma_adc.stopped) { - diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL); - count += diff; - cinfo.bytes += diff; - cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) - s->dma_adc.dmaaddr; - } else - cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) - s->dma_adc.dmaaddr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (!s->dma_dac.stopped) { - diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL); - count -= diff; - cinfo.bytes += diff; - cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) - s->dma_dac.dmaaddr; - } else - cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) - s->dma_dac.dmaaddr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) - return put_user(s->dma_dac.fragsize, (int *)arg); - else - return put_user(s->dma_adc.fragsize, (int *)arg); + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + if (!s->dma_dac.stopped) + count -= (s->dma_dac.fragsize - + inw(s->io+IT_AC_PCDL)); + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_adc.total_bytes; + count = s->dma_adc.count; + if (!s->dma_adc.stopped) { + diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL); + count += diff; + cinfo.bytes += diff; + cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) - + s->dma_adc.dmaaddr; + } else + cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) - + s->dma_adc.dmaaddr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_dac.total_bytes; + count = s->dma_dac.count; + if (!s->dma_dac.stopped) { + diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL); + count -= diff; + cinfo.bytes += diff; + cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) - + s->dma_dac.dmaaddr; + } else + cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) - + s->dma_dac.dmaaddr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) + return put_user(s->dma_dac.fragsize, (int *)arg); + else + return put_user(s->dma_adc.fragsize, (int *)arg); - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return 0; - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.subdivision = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.subdivision = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.subdivision = val; + if ((ret = prog_dmabuf_adc(s))) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.subdivision = val; + if ((ret = prog_dmabuf_dac(s))) + return ret; + } + return 0; - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - s->adcrate : s->dacrate, (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user((s->capcc & CC_SM) ? 2 : 1, (int *)arg); - else - return put_user((s->pcc & CC_SM) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? + s->adcrate : s->dacrate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + if (file->f_mode & FMODE_READ) + return put_user((s->capcc & CC_SM) ? 2 : 1, + (int *)arg); + else + return put_user((s->pcc & CC_SM) ? 2 : 1, + (int *)arg); - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return put_user((s->capcc & CC_DF) ? 16 : 8, (int *)arg); - else - return put_user((s->pcc & CC_DF) ? 16 : 8, (int *)arg); + case SOUND_PCM_READ_BITS: + if (file->f_mode & FMODE_READ) + return put_user((s->capcc & CC_DF) ? 16 : 8, + (int *)arg); + else + return put_user((s->pcc & CC_DF) ? 16 : 8, + (int *)arg); - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } - return mixdev_ioctl(&s->codec, cmd, arg); + return mixdev_ioctl(&s->codec, cmd, arg); } static int it8172_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct it8172_state *s; - int ret; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct it8172_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - file->private_data = s; - /* wait for device to become free */ - down(&s->open_sem); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - up(&s->open_sem); - return -EBUSY; + int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + struct list_head *list; + struct it8172_state *s; + int ret; + +#ifdef IT8172_VERBOSE_DEBUG + if (file->f_flags & O_NONBLOCK) + dbg(__FUNCTION__ ": non-blocking"); + else + dbg(__FUNCTION__ ": blocking"); +#endif + + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct it8172_state, devs); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - up(&s->open_sem); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; + file->private_data = s; + /* wait for device to become free */ down(&s->open_sem); - } + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EBUSY; + } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + up(&s->open_sem); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; - s->capcc &= ~(CC_SM | CC_DF); - set_adc_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->capcc |= CC_DF; - outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; - s->pcc &= ~(CC_SM | CC_DF); - set_dac_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->pcc |= CC_DF; - outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - - spin_unlock_irqrestore(&s->lock, flags); - - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - up(&s->open_sem); - return 0; + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = + s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; + s->capcc &= ~(CC_SM | CC_DF); + set_adc_rate(s, 8000); + if ((minor & 0xf) == SND_DEV_DSP16) + s->capcc |= CC_DF; + outw(s->capcc, s->io+IT_AC_CAPCC); + if ((ret = prog_dmabuf_adc(s))) { + spin_unlock_irqrestore(&s->lock, flags); + return ret; + } + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = + s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; + s->pcc &= ~(CC_SM | CC_DF); + set_dac_rate(s, 8000); + if ((minor & 0xf) == SND_DEV_DSP16) + s->pcc |= CC_DF; + outw(s->pcc, s->io+IT_AC_PCC); + if ((ret = prog_dmabuf_dac(s))) { + spin_unlock_irqrestore(&s->lock, flags); + return ret; + } + } + + spin_unlock_irqrestore(&s->lock, flags); + + s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE)); + up(&s->open_sem); + return 0; } static int it8172_release(struct inode *inode, struct file *file) { - struct it8172_state *s = (struct it8172_state *)file->private_data; + struct it8172_state *s = (struct it8172_state *)file->private_data; - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - down(&s->open_sem); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - up(&s->open_sem); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; +#ifdef IT8172_VERBOSE_DEBUG + dbg(__FUNCTION__); +#endif + lock_kernel(); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(s, &s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(s, &s->dma_adc); + } + s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); + up(&s->open_sem); + wake_up(&s->open_wait); + unlock_kernel(); + return 0; } static /*const*/ struct file_operations it8172_audio_fops = { - owner: THIS_MODULE, - llseek: it8172_llseek, - read: it8172_read, - write: it8172_write, - poll: it8172_poll, - ioctl: it8172_ioctl, - mmap: it8172_mmap, - open: it8172_open, - release: it8172_release, + owner: THIS_MODULE, + llseek: no_llseek, + read: it8172_read, + write: it8172_write, + poll: it8172_poll, + ioctl: it8172_ioctl, + mmap: it8172_mmap, + open: it8172_open, + release: it8172_release, }; @@ -1658,51 +1892,51 @@ static int proc_it8172_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data) { - struct it8172_state *s; - int cnt, len = 0; - - if (list_empty(&devs)) - return 0; - s = list_entry(devs.next, struct it8172_state, devs); + struct it8172_state *s; + int cnt, len = 0; - /* print out header */ - len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n"); - - // print out digital controller state - len += sprintf (buf + len, "IT8172 Audio Controller registers\n"); - len += sprintf (buf + len, "---------------------------------\n"); - cnt=0; - while (cnt < 0x72) { - if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA || - cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA || - cnt == IT_AC_PFDP) { - len+= sprintf (buf + len, "reg %02x = %08x\n", - cnt, inl(s->io+cnt)); - cnt += 4; - } else { - len+= sprintf (buf + len, "reg %02x = %04x\n", - cnt, inw(s->io+cnt)); - cnt += 2; - } - } - - /* print out CODEC state */ - len += sprintf (buf + len, "\nAC97 CODEC registers\n"); - len += sprintf (buf + len, "----------------------\n"); - for (cnt=0; cnt <= 0x7e; cnt = cnt +2) - len+= sprintf (buf + len, "reg %02x = %04x\n", - cnt, rdcodec(&s->codec, cnt)); - - if (fpos >=len){ - *start = buf; + if (list_empty(&devs)) + return 0; + s = list_entry(devs.next, struct it8172_state, devs); + + /* print out header */ + len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n"); + + // print out digital controller state + len += sprintf (buf + len, "IT8172 Audio Controller registers\n"); + len += sprintf (buf + len, "---------------------------------\n"); + cnt=0; + while (cnt < 0x72) { + if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA || + cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA || + cnt == IT_AC_PFDP) { + len+= sprintf (buf + len, "reg %02x = %08x\n", + cnt, inl(s->io+cnt)); + cnt += 4; + } else { + len+= sprintf (buf + len, "reg %02x = %04x\n", + cnt, inw(s->io+cnt)); + cnt += 2; + } + } + + /* print out CODEC state */ + len += sprintf (buf + len, "\nAC97 CODEC registers\n"); + len += sprintf (buf + len, "----------------------\n"); + for (cnt=0; cnt <= 0x7e; cnt = cnt +2) + len+= sprintf (buf + len, "reg %02x = %04x\n", + cnt, rdcodec(&s->codec, cnt)); + + if (fpos >=len){ + *start = buf; + *eof =1; + return 0; + } + *start = buf + fpos; + if ((len -= fpos) > length) + return length; *eof =1; - return 0; - } - *start = buf + fpos; - if ((len -= fpos) > length) - return length; - *eof =1; - return len; + return len; } #endif /* IT8172_DEBUG */ @@ -1713,246 +1947,299 @@ #define NR_DEVICE 5 static int spdif[NR_DEVICE] = { 0, }; +static int i2s_fmt[NR_DEVICE] = { 0, }; static unsigned int devindex = 0; MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled"); +MODULE_PARM(i2s_fmt, "1-" __MODULE_STRING(NR_DEVICE) "i"); +MODULE_PARM_DESC(i2s_fmt, "the format of I2S"); MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com"); -MODULE_DESCRIPTION("IT8172 AudioPCI97 Driver"); -MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IT8172 Audio Driver"); /* --------------------------------------------------------------------- */ static int __devinit it8172_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { - struct it8172_state *s; - int i, val; - unsigned short pcisr, vol; - unsigned char legacy, imc; - char proc_str[80]; - - if (pcidev->irq == 0) - return -1; - - if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) { - printk(KERN_ERR PFX "alloc of device struct failed\n"); - return -1; - } + struct it8172_state *s; + int i, val; + unsigned short pcisr, vol; + unsigned char legacy, imc; + char proc_str[80]; + + if (pcidev->irq == 0) + return -1; + + if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) { + err("alloc of device struct failed"); + return -1; + } - memset(s, 0, sizeof(struct it8172_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_MUTEX(&s->open_sem); - spin_lock_init(&s->lock); - s->dev = pcidev; - s->io = pci_resource_start(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; - s->codec.codec_wait = waitcodec; - - if (!request_region(s->io, pci_resource_len(pcidev,0), - IT8172_MODULE_NAME)) { - printk(KERN_ERR PFX "io ports %#lx->%#lx in use\n", - s->io, s->io + pci_resource_len(pcidev,0)-1); - goto err_region; - } - if (request_irq(s->irq, it8172_interrupt, SA_INTERRUPT, - IT8172_MODULE_NAME, s)) { - printk(KERN_ERR PFX "irq %u in use\n", s->irq); - goto err_irq; - } - - printk(KERN_INFO PFX "IO at %#lx, IRQ %d\n", s->io, s->irq); - - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->codec.dev_mixer = - register_sound_mixer(&it8172_mixer_fops, -1)) < 0) - goto err_dev2; + memset(s, 0, sizeof(struct it8172_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->dev = pcidev; + s->io = pci_resource_start(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; + s->codec.codec_wait = waitcodec; + + if (!request_region(s->io, pci_resource_len(pcidev,0), + IT8172_MODULE_NAME)) { + err("io ports %#lx->%#lx in use", + s->io, s->io + pci_resource_len(pcidev,0)-1); + goto err_region; + } + if (request_irq(s->irq, it8172_interrupt, SA_INTERRUPT, + IT8172_MODULE_NAME, s)) { + err("irq %u in use", s->irq); + goto err_irq; + } + + info("IO at %#lx, IRQ %d", s->io, s->irq); + + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->codec.dev_mixer = + register_sound_mixer(&it8172_mixer_fops, -1)) < 0) + goto err_dev2; #ifdef IT8172_DEBUG - /* intialize the debug proc device */ - s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL, - proc_it8172_dump, NULL); + /* intialize the debug proc device */ + s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL, + proc_it8172_dump, NULL); #endif /* IT8172_DEBUG */ - /* - * Reset the Audio device using the IT8172 PCI Reset register. This - * creates an audible double click on a speaker connected to Line-out. - */ - IT_IO_READ16(IT_PM_PCISR, pcisr); - pcisr |= IT_PM_PCISR_ACSR; - IT_IO_WRITE16(IT_PM_PCISR, pcisr); - /* wait up to 100msec for reset to complete */ - for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) { - it8172_delay(10); - if (i == 10) - break; + /* + * Reset the Audio device using the IT8172 PCI Reset register. This + * creates an audible double click on a speaker connected to Line-out. + */ IT_IO_READ16(IT_PM_PCISR, pcisr); - } - if (i == 10) { - printk(KERN_ERR PFX "chip reset timeout!\n"); - goto err_dev3; - } - - /* enable pci io and bus mastering */ - if (pci_enable_device(pcidev)) - goto err_dev3; - pci_set_master(pcidev); - - /* get out of legacy mode */ - pci_read_config_byte (pcidev, 0x40, &legacy); - pci_write_config_byte (pcidev, 0x40, legacy & ~1); - - s->spdif_volume = -1; - /* check to see if s/pdif mode is being requested */ - if (spdif[devindex]) { - printk(KERN_INFO PFX "enabling S/PDIF output\n"); - s->spdif_volume = 0; - outb(GC_SOE, s->io+IT_AC_GC); - } else { - printk(KERN_INFO PFX "disabling S/PDIF output\n"); - outb(0, s->io+IT_AC_GC); - } - - /* cold reset the AC97 */ - outw(CODECC_CR, s->io+IT_AC_CODECC); - udelay(1000); - outw(0, s->io+IT_AC_CODECC); - /* need to delay around 500msec(bleech) to give - some CODECs enough time to wakeup */ - it8172_delay(500); - - /* AC97 warm reset to start the bitclk */ - outw(CODECC_WR, s->io+IT_AC_CODECC); - udelay(1000); - outw(0, s->io+IT_AC_CODECC); - - /* codec init */ - if (!ac97_probe_codec(&s->codec)) - goto err_dev3; - - /* Enable Volume button interrupts */ - imc = inb(s->io+IT_AC_IMC); - outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC); - - /* Un-mute PCM and FM out on the controller */ - vol = inw(s->io+IT_AC_PCMOV); - outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV); - vol = inw(s->io+IT_AC_FMOV); - outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV); - - /* set channel defaults to 8-bit, mono, 8 Khz */ - s->pcc = 0; - s->capcc = 0; - set_dac_rate(s, 8000); - set_adc_rate(s, 8000); - - /* set mic to be the recording source */ - val = SOUND_MASK_MIC; - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - - /* mute master and PCM when in S/PDIF mode */ - if (s->spdif_volume != -1) { - val = 0x0000; - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME, - (unsigned long)&val); - mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM, + pcisr |= IT_PM_PCISR_ACSR; + IT_IO_WRITE16(IT_PM_PCISR, pcisr); + /* wait up to 100msec for reset to complete */ + for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) { + it8172_delay(10); + if (i == 10) + break; + IT_IO_READ16(IT_PM_PCISR, pcisr); + } + if (i == 10) { + err("chip reset timeout!"); + goto err_dev3; + } + + /* enable pci io and bus mastering */ + if (pci_enable_device(pcidev)) + goto err_dev3; + pci_set_master(pcidev); + + /* get out of legacy mode */ + pci_read_config_byte (pcidev, 0x40, &legacy); + pci_write_config_byte (pcidev, 0x40, legacy & ~1); + + s->spdif_volume = -1; + /* check to see if s/pdif mode is being requested */ + if (spdif[devindex]) { + info("enabling S/PDIF output"); + s->spdif_volume = 0; + outb(GC_SOE, s->io+IT_AC_GC); + } else { + info("disabling S/PDIF output"); + outb(0, s->io+IT_AC_GC); + } + + /* check to see if I2S format requested */ + if (i2s_fmt[devindex]) { + info("setting I2S format to 0x%02x", i2s_fmt[devindex]); + outb(i2s_fmt[devindex], s->io+IT_AC_I2SMC); + } else { + outb(I2SMC_I2SF_I2S, s->io+IT_AC_I2SMC); + } + + /* cold reset the AC97 */ + outw(CODECC_CR, s->io+IT_AC_CODECC); + udelay(1000); + outw(0, s->io+IT_AC_CODECC); + /* need to delay around 500msec(bleech) to give + some CODECs enough time to wakeup */ + it8172_delay(500); + + /* AC97 warm reset to start the bitclk */ + outw(CODECC_WR, s->io+IT_AC_CODECC); + udelay(1000); + outw(0, s->io+IT_AC_CODECC); + + /* codec init */ + if (!ac97_probe_codec(&s->codec)) + goto err_dev3; + + /* add I2S as allowable recording source */ + s->codec.record_sources |= SOUND_MASK_I2S; + + /* Enable Volume button interrupts */ + imc = inb(s->io+IT_AC_IMC); + outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC); + + /* Un-mute PCM and FM out on the controller */ + vol = inw(s->io+IT_AC_PCMOV); + outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV); + vol = inw(s->io+IT_AC_FMOV); + outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV); + + /* set channel defaults to 8-bit, mono, 8 Khz */ + s->pcc = 0; + s->capcc = 0; + set_dac_rate(s, 8000); + set_adc_rate(s, 8000); + + /* set mic to be the recording source */ + val = SOUND_MASK_MIC; + mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - } + + /* mute AC'97 master and PCM when in S/PDIF mode */ + if (s->spdif_volume != -1) { + val = 0x0000; + s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME, + (unsigned long)&val); + s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM, + (unsigned long)&val); + } #ifdef IT8172_DEBUG - sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME, s->codec.id); - s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, - ac97_read_proc, &s->codec); + sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME, + s->codec.id); + s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, + ac97_read_proc, &s->codec); #endif - /* store it in the driver field */ - pci_set_drvdata(pcidev, 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; + /* store it in the driver field */ + pci_set_drvdata(pcidev, 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_dev3: - unregister_sound_mixer(s->codec.dev_mixer); + unregister_sound_mixer(s->codec.dev_mixer); err_dev2: - unregister_sound_dsp(s->dev_audio); + unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR PFX "cannot register misc device\n"); - free_irq(s->irq, s); + err("cannot register misc device"); + free_irq(s->irq, s); err_irq: - release_region(s->io, pci_resource_len(pcidev,0)); + release_region(s->io, pci_resource_len(pcidev,0)); err_region: - kfree(s); - return -1; + kfree(s); + return -1; } static void __devinit it8172_remove(struct pci_dev *dev) { - struct it8172_state *s = pci_get_drvdata(dev); + struct it8172_state *s = pci_get_drvdata(dev); - if (!s) - return; - list_del(&s->devs); + if (!s) + return; + list_del(&s->devs); #ifdef IT8172_DEBUG - if (s->ps) - remove_proc_entry(IT8172_MODULE_NAME, NULL); + if (s->ps) + remove_proc_entry(IT8172_MODULE_NAME, NULL); #endif /* IT8172_DEBUG */ - synchronize_irq(); - free_irq(s->irq, s); - release_region(s->io, pci_resource_len(dev,0)); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec.dev_mixer); - kfree(s); - pci_set_drvdata(dev, NULL); + synchronize_irq(); + free_irq(s->irq, s); + release_region(s->io, pci_resource_len(dev,0)); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->codec.dev_mixer); + kfree(s); + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID, - PCI_ANY_ID, 0, 0 }, - { 0, } + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID, + PCI_ANY_ID, 0, 0 }, + { 0, } }; MODULE_DEVICE_TABLE(pci, id_table); static struct pci_driver it8172_driver = { - name: IT8172_MODULE_NAME, - id_table: id_table, - probe: it8172_probe, - remove: it8172_remove + name: IT8172_MODULE_NAME, + id_table: id_table, + probe: it8172_probe, + remove: it8172_remove }; static int __init init_it8172(void) { - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; - printk("version v0.26 time " __TIME__ " " __DATE__ "\n"); - return pci_module_init(&it8172_driver); + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + info("version v0.5 time " __TIME__ " " __DATE__); + return pci_module_init(&it8172_driver); } static void __exit cleanup_it8172(void) { - printk(KERN_INFO PFX "unloading\n"); - pci_unregister_driver(&it8172_driver); + info("unloading"); + pci_unregister_driver(&it8172_driver); } module_init(init_it8172); module_exit(cleanup_it8172); +/* --------------------------------------------------------------------- */ + +#ifndef MODULE + +/* format is: it8172=[spdif],[i2s:] */ + +static int __init it8172_setup(char *options) +{ + char* this_opt; + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= NR_DEVICE) + return 0; + + if (!options || !*options) + return 0; + + for(this_opt=strtok(options, ","); + this_opt; this_opt=strtok(NULL, ",")) { + if (!strncmp(this_opt, "spdif", 5)) { + spdif[nr_dev] = 1; + } else if (!strncmp(this_opt, "i2s:", 4)) { + if (!strncmp(this_opt+4, "dac", 3)) + i2s_fmt[nr_dev] = I2SMC_I2SF_DAC; + else if (!strncmp(this_opt+4, "adc", 3)) + i2s_fmt[nr_dev] = I2SMC_I2SF_ADC; + else if (!strncmp(this_opt+4, "i2s", 3)) + i2s_fmt[nr_dev] = I2SMC_I2SF_I2S; + } + } + + nr_dev++; + return 1; +} + +__setup("it8172=", it8172_setup); + +#endif /* MODULE */ diff -urN linux-2.4.18/drivers/sound/nec_vrc5477.c linux-2.4.19-pre5/drivers/sound/nec_vrc5477.c --- linux-2.4.18/drivers/sound/nec_vrc5477.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/nec_vrc5477.c Sat Mar 30 22:55:35 2002 @@ -6,6 +6,8 @@ * AC97 sound dirver for NEC Vrc5477 chip (an integrated, * multi-function controller chip for MIPS CPUs) * + * VRA support Copyright 2001 Bradley D. LaRonde + * * 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 @@ -83,17 +85,25 @@ #include #include -#include +/* -------------------debug macros -------------------------------------- */ +/* #undef VRC5477_AC97_DEBUG */ +#define VRC5477_AC97_DEBUG #undef VRC5477_AC97_VERBOSE_DEBUG +/* #define VRC5477_AC97_VERBOSE_DEBUG */ -/* one must turn on CONFIG_LL_DEBUG before VERBOSE_DEBUG is turned */ #if defined(VRC5477_AC97_VERBOSE_DEBUG) -#if !defined(CONFIG_LL_DEBUG) -#error "You must turn CONFIG_LL_DEBUG" -#endif +#define VRC5477_AC97_DEBUG #endif +#if defined(VRC5477_AC97_DEBUG) +#include +#define ASSERT(x) if (!(x)) { \ + panic("assertion failed at %s:%d: %s\n", __FILE__, __LINE__, #x); } +#else +#define ASSERT(x) +#endif /* VRC5477_AC97_DEBUG */ + #if defined(VRC5477_AC97_VERBOSE_DEBUG) static u16 inTicket=0; /* check sync between intr & write */ static u16 outTicket=0; @@ -179,16 +189,17 @@ unsigned long io; unsigned int irq; -#ifdef CONFIG_LL_DEBUG +#ifdef VRC5477_AC97_DEBUG /* debug /proc entry */ struct proc_dir_entry *ps; struct proc_dir_entry *ac97_ps; -#endif /* CONFIG_LL_DEBUG */ +#endif /* VRC5477_AC97_DEBUG */ struct ac97_codec codec; unsigned dacChannels, adcChannels; unsigned short dacRate, adcRate; + unsigned short extended_status; spinlock_t lock; struct semaphore open_sem; @@ -275,7 +286,7 @@ (VRC5477_CODEC_RD_RRDYA | VRC5477_CODEC_RD_RRDYD) ) { /* we get either addr or data, or both */ if (result & VRC5477_CODEC_RD_RRDYA) { - MIPS_ASSERT(addr == ((result >> 16) & 0x7f) ); + ASSERT(addr == ((result >> 16) & 0x7f) ); } if (result & VRC5477_CODEC_RD_RRDYD) { break; @@ -345,8 +356,10 @@ static void set_dac_rate(struct vrc5477_ac97_state *s, unsigned rate) { + if(s->extended_status & AC97_EXTSTAT_VRA) { wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, rate); - s->dacRate = rate; + s->dacRate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE); + } } @@ -408,7 +421,7 @@ } /* we should have some data to do the DMA trasnfer */ - MIPS_ASSERT(db->count >= db->fragSize); + ASSERT(db->count >= db->fragSize); /* clear pending fales interrupts */ outl(VRC5477_INT_MASK_DAC1END | VRC5477_INT_MASK_DAC2END, @@ -442,12 +455,12 @@ outl (temp, s->io + VRC5477_CTRL); /* it is time to setup next dma transfer */ - MIPS_ASSERT(inl(s->io + VRC5477_DAC1_CTRL) & VRC5477_DMA_WIP); - MIPS_ASSERT(inl(s->io + VRC5477_DAC2_CTRL) & VRC5477_DMA_WIP); + ASSERT(inl(s->io + VRC5477_DAC1_CTRL) & VRC5477_DMA_WIP); + ASSERT(inl(s->io + VRC5477_DAC2_CTRL) & VRC5477_DMA_WIP); temp = db->nextOut + db->fragSize; if (temp >= db->fragTotalSize) { - MIPS_ASSERT(temp == db->fragTotalSize); + ASSERT(temp == db->fragTotalSize); temp = 0; } @@ -463,7 +476,7 @@ #if defined(VRC5477_AC97_VERBOSE_DEBUG) outTicket = *(u16*)(db->lbuf+db->nextOut); if (db->count > db->fragSize) { - MIPS_ASSERT((u16)(outTicket+1) == *(u16*)(db->lbuf+temp)); + ASSERT((u16)(outTicket+1) == *(u16*)(db->lbuf+temp)); } #endif @@ -521,7 +534,7 @@ } /* we should at least have some free space in the buffer */ - MIPS_ASSERT(db->count < db->fragTotalSize - db->fragSize * 2); + ASSERT(db->count < db->fragTotalSize - db->fragSize * 2); /* clear pending ones */ outl(VRC5477_INT_MASK_ADC1END | VRC5477_INT_MASK_ADC2END, @@ -553,7 +566,7 @@ /* it is time to setup next dma transfer */ temp = db->nextIn + db->fragSize; if (temp >= db->fragTotalSize) { - MIPS_ASSERT(temp == db->fragTotalSize); + ASSERT(temp == db->fragTotalSize); temp = 0; } outl(db->lbufDma + temp, s->io + VRC5477_ADC1_BADDR); @@ -573,7 +586,7 @@ struct dmabuf *db) { if (db->lbuf) { - MIPS_ASSERT(db->rbuf); + ASSERT(db->rbuf); pci_free_consistent(s->dev, PAGE_SIZE << db->bufOrder, db->lbuf, db->lbufDma); pci_free_consistent(s->dev, PAGE_SIZE << db->bufOrder, @@ -592,7 +605,7 @@ unsigned bufsize; if (!db->lbuf) { - MIPS_ASSERT(!db->rbuf); + ASSERT(!db->rbuf); db->ready = 0; for (order = DMABUF_DEFAULTORDER; @@ -606,7 +619,7 @@ &db->rbufDma); if (db->lbuf && db->rbuf) break; if (db->lbuf) { - MIPS_ASSERT(!db->rbuf); + ASSERT(!db->rbuf); pci_free_consistent(s->dev, PAGE_SIZE << order, db->lbuf, @@ -614,7 +627,7 @@ } } if (!db->lbuf) { - MIPS_ASSERT(!db->rbuf); + ASSERT(!db->rbuf); return -ENOMEM; } @@ -677,7 +690,7 @@ /* set the base addr for next DMA transfer */ temp = adc->nextIn + 2*adc->fragSize; if (temp >= adc->fragTotalSize) { - MIPS_ASSERT( (temp == adc->fragTotalSize) || + ASSERT( (temp == adc->fragTotalSize) || (temp == adc->fragTotalSize + adc->fragSize) ); temp -= adc->fragTotalSize; } @@ -687,7 +700,7 @@ /* adjust nextIn */ adc->nextIn += adc->fragSize; if (adc->nextIn >= adc->fragTotalSize) { - MIPS_ASSERT(adc->nextIn == adc->fragTotalSize); + ASSERT(adc->nextIn == adc->fragTotalSize); adc->nextIn = 0; } @@ -706,13 +719,13 @@ unsigned temp; /* next DMA transfer should already started */ - MIPS_ASSERT(inl(s->io + VRC5477_DAC1_CTRL) & VRC5477_DMA_WIP); - MIPS_ASSERT(inl(s->io + VRC5477_DAC2_CTRL) & VRC5477_DMA_WIP); + ASSERT(inl(s->io + VRC5477_DAC1_CTRL) & VRC5477_DMA_WIP); + ASSERT(inl(s->io + VRC5477_DAC2_CTRL) & VRC5477_DMA_WIP); /* let us set for next next DMA transfer */ temp = dac->nextOut + dac->fragSize*2; if (temp >= dac->fragTotalSize) { - MIPS_ASSERT( (temp == dac->fragTotalSize) || + ASSERT( (temp == dac->fragTotalSize) || (temp == dac->fragTotalSize + dac->fragSize) ); temp -= dac->fragTotalSize; } @@ -728,22 +741,22 @@ printk("assert fail: - %d vs %d\n", *(u16*)(dac->lbuf + dac->nextOut), outTicket); - MIPS_ASSERT(1 == 0); + ASSERT(1 == 0); } #endif /* adjust nextOut pointer */ dac->nextOut += dac->fragSize; if (dac->nextOut >= dac->fragTotalSize) { - MIPS_ASSERT(dac->nextOut == dac->fragTotalSize); + ASSERT(dac->nextOut == dac->fragTotalSize); dac->nextOut = 0; } /* adjust count */ dac->count -= dac->fragSize; if (dac->count <=0 ) { - MIPS_ASSERT(dac->count == 0); - MIPS_ASSERT(dac->nextIn == dac->nextOut); + ASSERT(dac->count == 0); + ASSERT(dac->nextIn == dac->nextOut); /* buffer under run */ stop_dac(s); } @@ -751,12 +764,12 @@ #if defined(VRC5477_AC97_VERBOSE_DEBUG) if (dac->count) { outTicket ++; - MIPS_ASSERT(*(u16*)(dac->lbuf + dac->nextOut) == outTicket); + ASSERT(*(u16*)(dac->lbuf + dac->nextOut) == outTicket); } #endif /* we cannot have both under run and someone is waiting on us */ - MIPS_ASSERT(! (waitqueue_active(&dac->wait) && (dac->count <= 0)) ); + ASSERT(! (waitqueue_active(&dac->wait) && (dac->count <= 0)) ); /* wake up anybody listening */ if (waitqueue_active(&dac->wait)) @@ -805,12 +818,6 @@ /* --------------------------------------------------------------------- */ -static loff_t vrc5477_ac97_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - static int vrc5477_ac97_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); @@ -852,7 +859,7 @@ static /*const*/ struct file_operations vrc5477_ac97_mixer_fops = { owner: THIS_MODULE, - llseek: vrc5477_ac97_llseek, + llseek: no_llseek, ioctl: vrc5477_ac97_ioctl_mixdev, open: vrc5477_ac97_open_mixdev, release: vrc5477_ac97_release_mixdev, @@ -911,7 +918,7 @@ copyCount -= count; bufStart += count; - MIPS_ASSERT(bufStart <= db->fragTotalSize); + ASSERT(bufStart <= db->fragTotalSize); buffer += count *2; } return 0; @@ -943,12 +950,12 @@ } if (copyCount + db->nextOut > db->fragTotalSize) { copyCount = db->fragTotalSize - db->nextOut; - MIPS_ASSERT((copyCount % db->fragSize) == 0); + ASSERT((copyCount % db->fragSize) == 0); } copyFragCount = (copyCount-1) >> db->fragShift; copyFragCount = (copyFragCount+1) << db->fragShift; - MIPS_ASSERT(copyFragCount >= copyCount); + ASSERT(copyFragCount >= copyCount); /* we copy differently based on adc channels */ if (s->adcChannels == 1) { @@ -971,12 +978,12 @@ db->nextOut += copyFragCount; if (db->nextOut >= db->fragTotalSize) { - MIPS_ASSERT(db->nextOut == db->fragTotalSize); + ASSERT(db->nextOut == db->fragTotalSize); db->nextOut = 0; } - MIPS_ASSERT((copyFragCount % db->fragSize) == 0); - MIPS_ASSERT( (count == 0) || (copyCount == copyFragCount)); + ASSERT((copyFragCount % db->fragSize) == 0); + ASSERT( (count == 0) || (copyCount == copyFragCount)); } spin_lock_irqsave(&s->lock, flags); @@ -1005,7 +1012,7 @@ if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - MIPS_ASSERT(db->ready); + ASSERT(db->ready); while (count > 0) { // wait for samples in capture buffer @@ -1030,7 +1037,7 @@ } } while (avail <= 0); - MIPS_ASSERT( (avail % db->fragSize) == 0); + ASSERT( (avail % db->fragSize) == 0); copyCount = copy_adc_to_user(s, buffer, count, avail); if (copyCount <=0 ) { if (!ret) ret = -EFAULT; @@ -1053,7 +1060,7 @@ struct dmabuf *db = &s->dma_dac; int bufStart = db->nextIn; - MIPS_ASSERT(db->ready); + ASSERT(db->ready); for (; copyCount > 0; ) { int i; @@ -1071,7 +1078,7 @@ copyCount -= count; bufStart += count; - MIPS_ASSERT(bufStart <= db->fragTotalSize); + ASSERT(bufStart <= db->fragTotalSize); buffer += count *2; } return 0; @@ -1107,13 +1114,13 @@ } if (copyCount + db->nextIn > db->fragTotalSize) { copyCount = db->fragTotalSize - db->nextIn; - MIPS_ASSERT((copyCount % db->fragSize) == 0); - MIPS_ASSERT(copyCount > 0); + ASSERT((copyCount % db->fragSize) == 0); + ASSERT(copyCount > 0); } copyFragCount = (copyCount-1) >> db->fragShift; copyFragCount = (copyFragCount+1) << db->fragShift; - MIPS_ASSERT(copyFragCount >= copyCount); + ASSERT(copyFragCount >= copyCount); /* we copy differently based on the number channels */ if (s->dacChannels == 1) { @@ -1153,12 +1160,12 @@ db->nextIn += copyFragCount; if (db->nextIn >= db->fragTotalSize) { - MIPS_ASSERT(db->nextIn == db->fragTotalSize); + ASSERT(db->nextIn == db->fragTotalSize); db->nextIn = 0; } - MIPS_ASSERT((copyFragCount % db->fragSize) == 0); - MIPS_ASSERT( (count == 0) || (copyCount == copyFragCount)); + ASSERT((copyFragCount % db->fragSize) == 0); + ASSERT( (count == 0) || (copyCount == copyFragCount)); } spin_lock_irqsave(&s->lock, flags); @@ -1168,7 +1175,7 @@ } /* nextIn should not be equal to nextOut unless we are full */ - MIPS_ASSERT( ( (db->count == db->fragTotalSize) && + ASSERT( ( (db->count == db->fragTotalSize) && (db->nextIn == db->nextOut) ) || ( (db->count < db->fragTotalSize) && (db->nextIn != db->nextOut) ) ); @@ -1216,7 +1223,7 @@ } } while (avail <= 0); - MIPS_ASSERT( (avail % db->fragSize) == 0); + ASSERT( (avail % db->fragSize) == 0); copyCount = copy_dac_from_user(s, buffer, count, avail); if (copyCount < 0) { if (!ret) ret = -EFAULT; @@ -1257,7 +1264,7 @@ return mask; } -#ifdef CONFIG_LL_DEBUG +#ifdef VRC5477_AC97_DEBUG static struct ioctl_str_t { unsigned int cmd; const char* str; @@ -1308,7 +1315,7 @@ int count; int val, ret; -#ifdef CONFIG_LL_DEBUG +#ifdef VRC5477_AC97_DEBUG for (count=0; count> 16) & 0x7f) ); + ASSERT(addr == ((result >> 16) & 0x7f) ); return result & 0xffff; } @@ -1829,7 +1836,7 @@ while (myinl(VRC5477_CODEC_WR) & 0x80000000); for (i=0; i< 0x40; i+=4) { - MIPS_ASSERT(inl(s->io+i) == myinl(i)); + ASSERT(inl(s->io+i) == myinl(i)); } printk("codec registers : "); @@ -1855,9 +1862,9 @@ const struct pci_device_id *pciid) { struct vrc5477_ac97_state *s; +#ifdef VRC5477_AC97_DEBUG char proc_str[80]; - - MIPS_DEBUG(printk("vrc5477_ac97_probe() invoked\n")); +#endif if (pcidev->irq == 0) return -1; @@ -1910,37 +1917,27 @@ register_sound_mixer(&vrc5477_ac97_mixer_fops, -1)) < 0) goto err_dev2; -#ifdef CONFIG_LL_DEBUG +#ifdef VRC5477_AC97_DEBUG /* intialize the debug proc device */ s->ps = create_proc_read_entry(VRC5477_AC97_MODULE_NAME, 0, NULL, proc_vrc5477_ac97_dump, NULL); -#endif /* CONFIG_LL_DEBUG */ +#endif /* VRC5477_AC97_DEBUG */ /* enable pci io and bus mastering */ if (pci_enable_device(pcidev)) goto err_dev3; pci_set_master(pcidev); -/* -jsun_scan_pci_bus(); -vrc5477_show_pci_regs(); -vrc5477_show_pdar_regs(); -*/ - /* cold reset the AC97 */ outl(VRC5477_ACLINK_CTRL_RST_ON | VRC5477_ACLINK_CTRL_RST_TIME, s->io + VRC5477_ACLINK_CTRL); while (inl(s->io + VRC5477_ACLINK_CTRL) & VRC5477_ACLINK_CTRL_RST_ON); -/* -jsun_ac97_test(s); -*/ - /* codec init */ if (!ac97_probe_codec(&s->codec)) goto err_dev3; -#ifdef CONFIG_LL_DEBUG +#ifdef VRC5477_AC97_DEBUG sprintf(proc_str, "driver/%s/%d/ac97", VRC5477_AC97_MODULE_NAME, s->codec.id); s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, @@ -1948,6 +1945,25 @@ /* TODO : why this proc file does not show up? */ #endif + /* Try to enable variable rate audio mode. */ + wrcodec(&s->codec, AC97_EXTENDED_STATUS, + rdcodec(&s->codec, AC97_EXTENDED_STATUS) | AC97_EXTSTAT_VRA); + /* Did we enable it? */ + if(rdcodec(&s->codec, AC97_EXTENDED_STATUS) & AC97_EXTSTAT_VRA) + s->extended_status |= AC97_EXTSTAT_VRA; + else { + s->dacRate = 48000; + printk(KERN_INFO PFX "VRA mode not enabled; rate fixed at %d.", + s->dacRate); + } + +#if 0 + /* What's wrong with the codec chip defaults? + * If at all, shouldn't this be done through ac97_codec.c instead? + * This code just ends up making my system noisey at boot. + * /dev/mixer reaches these anyway. bdl + */ + /* let us get the default volumne louder */ wrcodec(&s->codec, 0x2, 0); wrcodec(&s->codec, 0x18, 0x0707); @@ -1960,6 +1976,7 @@ // wrcodec(&s->codec, 0x1c, 0x0707); wrcodec(&s->codec, 0x1c, 0x0f0f); wrcodec(&s->codec, 0x1e, 0x07); +#endif /* enable the master interrupt but disable all others */ outl(VRC5477_INT_MASK_NMASK, s->io + VRC5477_INT_MASK); @@ -1995,10 +2012,12 @@ if (!s) return; list_del(&s->devs); -#ifdef CONFIG_LL_DEBUG + +#ifdef VRC5477_AC97_DEBUG if (s->ps) remove_proc_entry(VRC5477_AC97_MODULE_NAME, NULL); -#endif /* CONFIG_LL_DEBUG */ +#endif /* VRC5477_AC97_DEBUG */ + synchronize_irq(); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,0)); @@ -2009,8 +2028,6 @@ } -#define PCI_VENDOR_ID_NEC 0x1033 -#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00A6 static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_VRC5477_AC97, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, diff -urN linux-2.4.18/drivers/sound/nm256_audio.c linux-2.4.19-pre5/drivers/sound/nm256_audio.c --- linux-2.4.18/drivers/sound/nm256_audio.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/nm256_audio.c Sat Mar 30 22:55:29 2002 @@ -896,7 +896,7 @@ /* Reset the mixer. 'Tis magic! */ nm256_writePort8 (card, 2, 0x6c0, 1); - nm256_writePort8 (card, 2, 0x6cc, 0x87); +// nm256_writePort8 (card, 2, 0x6cc, 0x87); /* This crashes Dell latitudes */ nm256_writePort8 (card, 2, 0x6cc, 0x80); nm256_writePort8 (card, 2, 0x6cc, 0x0); diff -urN linux-2.4.18/drivers/sound/opl3sa2.c linux-2.4.19-pre5/drivers/sound/opl3sa2.c --- linux-2.4.18/drivers/sound/opl3sa2.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/opl3sa2.c Sat Mar 30 22:55:29 2002 @@ -56,6 +56,7 @@ * Scott Murray Some small cleanups to the init code output. * (Jan 7, 2001) * Zwane Mwaikambo Added PM support. (Dec 4 2001) + * Zwane Mwaikambo Code, data structure cleanups. (Feb 15 2002) * */ @@ -71,6 +72,7 @@ #include "mpu401.h" #define OPL3SA2_MODULE_NAME "opl3sa2" +#define PFX OPL3SA2_MODULE_NAME ": " /* Useful control port indexes: */ #define OPL3SA2_PM 0x01 @@ -92,9 +94,10 @@ #define DEFAULT_TIMBRE 0 /* Power saving modes */ -#define OPL3SA2_PM_MODE1 0x05 -#define OPL3SA2_PM_MODE2 0x04 -#define OPL3SA2_PM_MODE3 0x03 +#define OPL3SA2_PM_MODE0 0x00 +#define OPL3SA2_PM_MODE1 0x04 /* PSV */ +#define OPL3SA2_PM_MODE2 0x05 /* PSV | PDX */ +#define OPL3SA2_PM_MODE3 0x27 /* ADOWN | PSV | PDN | PDX */ /* For checking against what the card returns: */ #define VERSION_UNKNOWN 0 @@ -108,6 +111,7 @@ #define CHIPSET_UNKNOWN -1 #define CHIPSET_OPL3SA2 0 #define CHIPSET_OPL3SA3 1 +static const char *CHIPSET_TABLE[] = {"OPL3-SA2", "OPL3-SA3"}; #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE #define OPL3SA2_CARDS_MAX 4 @@ -118,38 +122,40 @@ /* This should be pretty obvious */ static int opl3sa2_cards_num; /* = 0 */ -/* What's my version(s)? */ -static int chipset[OPL3SA2_CARDS_MAX] = { CHIPSET_UNKNOWN }; - -/* Oh well, let's just cache the name(s) */ -static char chipset_name[OPL3SA2_CARDS_MAX][12]; +typedef struct { + /* device resources */ + unsigned short cfg_port; + struct address_info cfg; + struct address_info cfg_mss; + struct address_info cfg_mpu; -/* Where's my mixer(s)? */ -static int opl3sa2_mixer[OPL3SA2_CARDS_MAX] = { -1 }; +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + /* PnP Stuff */ + struct pci_dev* pdev; + int activated; /* Whether said devices have been activated */ +#endif -/* Bag o' mixer data */ -typedef struct opl3sa2_mixerdata_tag { - unsigned short cfg_port; - unsigned short padding; - unsigned char pm_reg; - unsigned int in_suspend; - struct pm_dev *pmdev; - unsigned int card; - unsigned int volume_l; - unsigned int volume_r; - unsigned int mic; - unsigned int bass_l; - unsigned int bass_r; - unsigned int treble_l; - unsigned int treble_r; - unsigned int wide_l; - unsigned int wide_r; -} opl3sa2_mixerdata; -static opl3sa2_mixerdata opl3sa2_data[OPL3SA2_CARDS_MAX]; - -static struct address_info cfg[OPL3SA2_CARDS_MAX]; -static struct address_info cfg_mss[OPL3SA2_CARDS_MAX]; -static struct address_info cfg_mpu[OPL3SA2_CARDS_MAX]; +#ifdef CONFIG_PM + unsigned int in_suspend; + struct pm_dev *pmdev; +#endif + unsigned int card; + int chipset; /* What's my version(s)? */ + char *chipset_name; + + /* mixer data */ + int mixer; + unsigned int volume_l; + unsigned int volume_r; + unsigned int mic; + unsigned int bass_l; + unsigned int bass_r; + unsigned int treble_l; + unsigned int treble_r; + unsigned int wide_l; + unsigned int wide_r; +} opl3sa2_state_t; +static opl3sa2_state_t opl3sa2_state[OPL3SA2_CARDS_MAX]; /* Our parameters */ static int __initdata io = -1; @@ -166,11 +172,6 @@ static int __initdata isapnp = 1; static int __initdata multiple = 1; -/* PnP devices */ -struct pci_dev* opl3sa2_dev[OPL3SA2_CARDS_MAX]; - -/* Whether said devices have been activated */ -static int opl3sa2_activated[OPL3SA2_CARDS_MAX]; #else static int __initdata isapnp; /* = 0 */ static int __initdata multiple; /* = 0 */ @@ -240,7 +241,7 @@ * All of the mixer functions... */ -static void opl3sa2_set_volume(opl3sa2_mixerdata* devc, int left, int right) +static void opl3sa2_set_volume(opl3sa2_state_t* devc, int left, int right) { static unsigned char scale[101] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, @@ -275,7 +276,7 @@ } -static void opl3sa2_set_mic(opl3sa2_mixerdata* devc, int level) +static void opl3sa2_set_mic(opl3sa2_state_t* devc, int level) { unsigned char vol = 0x1F; @@ -290,7 +291,7 @@ } -static void opl3sa3_set_bass(opl3sa2_mixerdata* devc, int left, int right) +static void opl3sa3_set_bass(opl3sa2_state_t* devc, int left, int right) { unsigned char bass; @@ -301,7 +302,7 @@ } -static void opl3sa3_set_treble(opl3sa2_mixerdata* devc, int left, int right) +static void opl3sa3_set_treble(opl3sa2_state_t* devc, int left, int right) { unsigned char treble; @@ -312,7 +313,7 @@ } -static void opl3sa3_set_wide(opl3sa2_mixerdata* devc, int left, int right) +static void opl3sa3_set_wide(opl3sa2_state_t* devc, int left, int right) { unsigned char wide; @@ -323,7 +324,7 @@ } -static void opl3sa2_mixer_reset(opl3sa2_mixerdata* devc, int card) +static void opl3sa2_mixer_reset(opl3sa2_state_t* devc) { if(devc) { opl3sa2_set_volume(devc, DEFAULT_VOLUME, DEFAULT_VOLUME); @@ -332,7 +333,7 @@ opl3sa2_set_mic(devc, DEFAULT_MIC); devc->mic = DEFAULT_MIC; - if(chipset[card] == CHIPSET_OPL3SA3) { + if(devc->chipset == CHIPSET_OPL3SA3) { opl3sa3_set_bass(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE); devc->bass_l = devc->bass_r = DEFAULT_TIMBRE; opl3sa3_set_treble(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE); @@ -342,13 +343,13 @@ } -static void opl3sa2_mixer_restore(opl3sa2_mixerdata* devc, int card) +static void opl3sa2_mixer_restore(opl3sa2_state_t* devc) { if (devc) { opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r); opl3sa2_set_mic(devc, devc->mic); - if (chipset[card] == CHIPSET_OPL3SA3) { + if (devc->chipset == CHIPSET_OPL3SA3) { opl3sa3_set_bass(devc, devc->bass_l, devc->bass_r); opl3sa3_set_treble(devc, devc->treble_l, devc->treble_r); } @@ -390,7 +391,7 @@ { int cmdf = cmd & 0xff; - opl3sa2_mixerdata* devc = (opl3sa2_mixerdata*) mixer_devs[dev]->devc; + opl3sa2_state_t* devc = (opl3sa2_state_t *) mixer_devs[dev]->devc; switch(cmdf) { case SOUND_MIXER_VOLUME: @@ -473,7 +474,7 @@ { int cmdf = cmd & 0xff; - opl3sa2_mixerdata* devc = (opl3sa2_mixerdata*) mixer_devs[dev]->devc; + opl3sa2_state_t* devc = (opl3sa2_state_t *) mixer_devs[dev]->devc; switch(cmdf) { case SOUND_MIXER_BASS: @@ -616,7 +617,7 @@ AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); } else { - printk(KERN_ERR "opl3sa2: MSS mixer not installed?\n"); + printk(KERN_ERR PFX "MSS mixer not installed?\n"); } } } @@ -633,13 +634,12 @@ unsigned char misc; unsigned char tmp; unsigned char version; - char tag; /* * Try and allocate our I/O port range. */ if(!request_region(hw_config->io_base, 2, OPL3SA2_MODULE_NAME)) { - printk(KERN_ERR "opl3sa2: Control I/O port %#x not free\n", + printk(KERN_ERR PFX "Control I/O port %#x not free\n", hw_config->io_base); return 0; } @@ -652,7 +652,7 @@ opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc ^ 0x07); opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &tmp); if(tmp != misc) { - printk(KERN_ERR "opl3sa2: Control I/O port %#x is not a YMF7xx chipset!\n", + printk(KERN_ERR PFX "Control I/O port %#x is not a YMF7xx chipset!\n", hw_config->io_base); return 0; } @@ -665,7 +665,7 @@ opl3sa2_read(hw_config->io_base, OPL3SA2_MIC, &tmp); if((tmp & 0x9f) != 0x8a) { printk(KERN_ERR - "opl3sa2: Control I/O port %#x is not a YMF7xx chipset!\n", + PFX "Control I/O port %#x is not a YMF7xx chipset!\n", hw_config->io_base); return 0; } @@ -678,47 +678,42 @@ * of the miscellaneous register. */ version = misc & 0x07; - printk(KERN_DEBUG "opl3sa2: chipset version = %#x\n", version); + printk(KERN_DEBUG PFX "chipset version = %#x\n", version); switch(version) { case 0: - chipset[card] = CHIPSET_UNKNOWN; - tag = '?'; /* silence compiler warning */ + opl3sa2_state[card].chipset = CHIPSET_UNKNOWN; printk(KERN_ERR - "opl3sa2: Unknown Yamaha audio controller version\n"); + PFX "Unknown Yamaha audio controller version\n"); break; case VERSION_YMF711: - chipset[card] = CHIPSET_OPL3SA2; - tag = '2'; - printk(KERN_INFO "opl3sa2: Found OPL3-SA2 (YMF711)\n"); + opl3sa2_state[card].chipset = CHIPSET_OPL3SA2; + printk(KERN_INFO PFX "Found OPL3-SA2 (YMF711)\n"); break; case VERSION_YMF715: - chipset[card] = CHIPSET_OPL3SA3; - tag = '3'; + opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; printk(KERN_INFO - "opl3sa2: Found OPL3-SA3 (YMF715 or YMF719)\n"); + PFX "Found OPL3-SA3 (YMF715 or YMF719)\n"); break; case VERSION_YMF715B: - chipset[card] = CHIPSET_OPL3SA3; - tag = '3'; + opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; printk(KERN_INFO - "opl3sa2: Found OPL3-SA3 (YMF715B or YMF719B)\n"); + PFX "Found OPL3-SA3 (YMF715B or YMF719B)\n"); break; case VERSION_YMF715E: default: - chipset[card] = CHIPSET_OPL3SA3; - tag = '3'; + opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; printk(KERN_INFO - "opl3sa2: Found OPL3-SA3 (YMF715E or YMF719E)\n"); + PFX "Found OPL3-SA3 (YMF715E or YMF719E)\n"); break; } - if(chipset[card] != CHIPSET_UNKNOWN) { + if(opl3sa2_state[card].chipset != CHIPSET_UNKNOWN) { /* Generate a pretty name */ - sprintf(chipset_name[card], "OPL3-SA%c", tag); + opl3sa2_state[card].chipset_name = (char *)CHIPSET_TABLE[opl3sa2_state[card].chipset]; return 1; } return 0; @@ -746,30 +741,28 @@ static void __init attach_opl3sa2_mixer(struct address_info *hw_config, int card) { struct mixer_operations* mixer_operations; - opl3sa2_mixerdata* devc; + opl3sa2_state_t* devc = &opl3sa2_state[card]; /* Install master mixer */ - if(chipset[card] == CHIPSET_OPL3SA3) { + if(devc->chipset == CHIPSET_OPL3SA3) { mixer_operations = &opl3sa3_mixer_operations; } else { mixer_operations = &opl3sa2_mixer_operations; } - if((devc = &opl3sa2_data[card])) { - devc->cfg_port = hw_config->io_base; - - opl3sa2_mixer[card] = sound_install_mixer(MIXER_DRIVER_VERSION, - mixer_operations->name, - mixer_operations, - sizeof(struct mixer_operations), - devc); - if(opl3sa2_mixer[card] < 0) { - printk(KERN_ERR "opl3sa2: Could not install %s master mixer\n", - mixer_operations->name); - } - else - opl3sa2_mixer_reset(devc, card); + devc->cfg_port = hw_config->io_base; + devc->mixer = sound_install_mixer(MIXER_DRIVER_VERSION, + mixer_operations->name, + mixer_operations, + sizeof(struct mixer_operations), + devc); + if(devc->mixer < 0) { + printk(KERN_ERR PFX "Could not install %s master mixer\n", + mixer_operations->name); + } + else { + opl3sa2_mixer_reset(devc); } } @@ -803,7 +796,7 @@ opl3sa2_write(hw_config->io_base, OPL3SA2_SYS_CTRL, sys_ctrl); } else { - printk(KERN_ERR "opl3sa2: not setting ymode, it must be one of 0,1,2,3\n"); + printk(KERN_ERR PFX "not setting ymode, it must be one of 0,1,2,3\n"); } } @@ -818,7 +811,7 @@ opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc); } else { - printk(KERN_ERR "opl3sa2: not setting loopback, it must be either 0 or 1\n"); + printk(KERN_ERR PFX "not setting loopback, it must be either 0 or 1\n"); } } @@ -829,8 +822,8 @@ release_region(hw_config->io_base, 2); /* Unload mixer */ - if(opl3sa2_mixer[card] >= 0) - sound_unload_mixerdev(opl3sa2_mixer[card]); + if(opl3sa2_state[card].mixer >= 0) + sound_unload_mixerdev(opl3sa2_state[card].mixer); } @@ -868,21 +861,21 @@ */ ret = dev->prepare(dev); if(ret && ret != -EBUSY) { - printk(KERN_ERR "opl3sa2: ISA PnP found device that could not be autoconfigured.\n"); + printk(KERN_ERR PFX "ISA PnP found device that could not be autoconfigured.\n"); return -ENODEV; } if(ret == -EBUSY) { - opl3sa2_activated[card] = 1; + opl3sa2_state[card].activated = 1; } else { if(dev->activate(dev) < 0) { - printk(KERN_WARNING "opl3sa2: ISA PnP activate failed\n"); - opl3sa2_activated[card] = 0; + printk(KERN_WARNING PFX "ISA PnP activate failed\n"); + opl3sa2_state[card].activated = 0; return -ENODEV; } printk(KERN_DEBUG - "opl3sa2: Activated ISA PnP card %d (active=%d)\n", + PFX "Activated ISA PnP card %d (active=%d)\n", card, dev->active); } @@ -911,7 +904,7 @@ opl3sa2_clear_slots(mss_cfg); opl3sa2_clear_slots(mpu_cfg); - opl3sa2_dev[card] = dev; + opl3sa2_state[card].pdev = dev; return 0; } @@ -919,11 +912,12 @@ /* End of component functions */ +#ifdef CONFIG_PM /* Power Management support functions */ static int opl3sa2_suspend(struct pm_dev *pdev, unsigned char pm_mode) { unsigned long flags; - opl3sa2_mixerdata *p; + opl3sa2_state_t *p; if (!pdev) return -EINVAL; @@ -931,7 +925,7 @@ save_flags(flags); cli(); - p = (opl3sa2_mixerdata *) pdev->data; + p = (opl3sa2_state_t *) pdev->data; switch (pm_mode) { case 1: @@ -951,8 +945,7 @@ p->in_suspend = 1; /* its supposed to automute before suspending, so we wont bother */ - opl3sa2_read(p->cfg_port, OPL3SA2_PM, &p->pm_reg); - opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg | pm_mode); + opl3sa2_write(p->cfg_port, OPL3SA2_PM, pm_mode); /* wait a while for the clock oscillator to stabilise */ mdelay(10); @@ -963,18 +956,17 @@ static int opl3sa2_resume(struct pm_dev *pdev) { unsigned long flags; - opl3sa2_mixerdata *p; + opl3sa2_state_t *p; if (!pdev) return -EINVAL; - p = (opl3sa2_mixerdata *) pdev->data; + p = (opl3sa2_state_t *) pdev->data; save_flags(flags); cli(); - /* I don't think this is necessary */ - opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg); - opl3sa2_mixer_restore(p, p->card); + opl3sa2_write(p->cfg_port, OPL3SA2_PM, OPL3SA2_PM_MODE0); + opl3sa2_mixer_restore(p); p->in_suspend = 0; restore_flags(flags); @@ -994,6 +986,7 @@ } return 0; } +#endif /* CONFIG_PM */ /* * Install OPL3-SA2 based card(s). @@ -1017,16 +1010,16 @@ * should still be able to disable PNP support for this * single driver! */ - if(isapnp && opl3sa2_isapnp_probe(&cfg[card], - &cfg_mss[card], - &cfg_mpu[card], + if(isapnp && opl3sa2_isapnp_probe(&opl3sa2_state[card].cfg, + &opl3sa2_state[card].cfg_mss, + &opl3sa2_state[card].cfg_mpu, card) < 0) { if(!opl3sa2_cards_num) - printk(KERN_INFO "opl3sa2: No PnP cards found\n"); + printk(KERN_INFO PFX "No PnP cards found\n"); if(io == -1) break; isapnp=0; - printk(KERN_INFO "opl3sa2: Search for a card at 0x%d.\n", io); + printk(KERN_INFO PFX "Search for a card at 0x%d.\n", io); /* Fall through */ } #endif @@ -1036,7 +1029,7 @@ if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) { printk(KERN_ERR - "opl3sa2: io, mss_io, irq, dma, and dma2 must be set\n"); + PFX "io, mss_io, irq, dma, and dma2 must be set\n"); return -EINVAL; } @@ -1045,31 +1038,31 @@ * (NOTE: IRQ and DMA aren't used, so they're set to * give pretty output from conf_printf. :) */ - cfg[card].io_base = io; - cfg[card].irq = irq; - cfg[card].dma = dma; - cfg[card].dma2 = dma2; + opl3sa2_state[card].cfg.io_base = io; + opl3sa2_state[card].cfg.irq = irq; + opl3sa2_state[card].cfg.dma = dma; + opl3sa2_state[card].cfg.dma2 = dma2; /* The MSS config: */ - cfg_mss[card].io_base = mss_io; - cfg_mss[card].irq = irq; - cfg_mss[card].dma = dma; - cfg_mss[card].dma2 = dma2; - cfg_mss[card].card_subtype = 1; /* No IRQ or DMA setup */ - - cfg_mpu[card].io_base = mpu_io; - cfg_mpu[card].irq = irq; - cfg_mpu[card].dma = -1; - cfg_mpu[card].always_detect = 1; /* Use shared IRQs */ + opl3sa2_state[card].cfg_mss.io_base = mss_io; + opl3sa2_state[card].cfg_mss.irq = irq; + opl3sa2_state[card].cfg_mss.dma = dma; + opl3sa2_state[card].cfg_mss.dma2 = dma2; + opl3sa2_state[card].cfg_mss.card_subtype = 1; /* No IRQ or DMA setup */ + + opl3sa2_state[card].cfg_mpu.io_base = mpu_io; + opl3sa2_state[card].cfg_mpu.irq = irq; + opl3sa2_state[card].cfg_mpu.dma = -1; + opl3sa2_state[card].cfg_mpu.always_detect = 1; /* Use shared IRQs */ /* Call me paranoid: */ - opl3sa2_clear_slots(&cfg[card]); - opl3sa2_clear_slots(&cfg_mss[card]); - opl3sa2_clear_slots(&cfg_mpu[card]); + opl3sa2_clear_slots(&opl3sa2_state[card].cfg); + opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mss); + opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mpu); } - if(!probe_opl3sa2(&cfg[card], card) || - !probe_opl3sa2_mss(&cfg_mss[card])) { + if(!probe_opl3sa2(&opl3sa2_state[card].cfg, card) || + !probe_opl3sa2_mss(&opl3sa2_state[card].cfg_mss)) { /* * If one or more cards are already registered, don't * return an error but print a warning. Note, this @@ -1078,7 +1071,7 @@ */ if(opl3sa2_cards_num) { printk(KERN_WARNING - "opl3sa2: There was a problem probing one " + PFX "There was a problem probing one " " of the ISA PNP cards, continuing\n"); opl3sa2_cards_num--; continue; @@ -1086,47 +1079,51 @@ return -ENODEV; } - attach_opl3sa2(&cfg[card], card); - conf_printf(chipset_name[card], &cfg[card]); - attach_opl3sa2_mss(&cfg_mss[card]); - attach_opl3sa2_mixer(&cfg[card], card); + attach_opl3sa2(&opl3sa2_state[card].cfg, card); + conf_printf(opl3sa2_state[card].chipset_name, &opl3sa2_state[card].cfg); + attach_opl3sa2_mss(&opl3sa2_state[card].cfg_mss); + attach_opl3sa2_mixer(&opl3sa2_state[card].cfg, card); + + /* ewww =) */ + opl3sa2_state[card].card = card; - opl3sa2_data[card].card = card; +#ifdef CONFIG_PM /* register our power management capabilities */ - opl3sa2_data[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback); - if (opl3sa2_data[card].pmdev) - opl3sa2_data[card].pmdev->data = &opl3sa2_data[card]; + opl3sa2_state[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback); + if (opl3sa2_state[card].pmdev) + opl3sa2_state[card].pmdev->data = &opl3sa2_state[card]; +#endif /* * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and * it's supported. */ if(ymode != -1) { - if(chipset[card] == CHIPSET_OPL3SA2) { + if(opl3sa2_state[card].chipset == CHIPSET_OPL3SA2) { printk(KERN_ERR - "opl3sa2: ymode not supported on OPL3-SA2\n"); + PFX "ymode not supported on OPL3-SA2\n"); } else { - opl3sa2_set_ymode(&cfg[card], ymode); + opl3sa2_set_ymode(&opl3sa2_state[card].cfg, ymode); } } /* Set A/D input to Mono loopback if asked to. */ if(loopback != -1) { - opl3sa2_set_loopback(&cfg[card], loopback); + opl3sa2_set_loopback(&opl3sa2_state[card].cfg, loopback); } /* Attach MPU if we've been asked to do so */ - if(cfg_mpu[card].io_base != -1) { - if(probe_opl3sa2_mpu(&cfg_mpu[card])) { - attach_opl3sa2_mpu(&cfg_mpu[card]); + if(opl3sa2_state[card].cfg_mpu.io_base != -1) { + if(probe_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu)) { + attach_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu); } } } if(isapnp) { - printk(KERN_NOTICE "opl3sa2: %d PnP card(s) found.\n", opl3sa2_cards_num); + printk(KERN_NOTICE PFX "%d PnP card(s) found.\n", opl3sa2_cards_num); } return 0; @@ -1141,22 +1138,23 @@ int card; for(card = 0; card < opl3sa2_cards_num; card++) { - if (opl3sa2_data[card].pmdev) - pm_unregister(opl3sa2_data[card].pmdev); - - if(cfg_mpu[card].slots[1] != -1) { - unload_opl3sa2_mpu(&cfg_mpu[card]); +#ifdef CONFIG_PM + if (opl3sa2_state[card].pmdev) + pm_unregister(opl3sa2_state[card].pmdev); +#endif + if(opl3sa2_state[card].cfg_mpu.slots[1] != -1) { + unload_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu); } - unload_opl3sa2_mss(&cfg_mss[card]); - unload_opl3sa2(&cfg[card], card); + unload_opl3sa2_mss(&opl3sa2_state[card].cfg_mss); + unload_opl3sa2(&opl3sa2_state[card].cfg, card); #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE - if(opl3sa2_activated[card] && opl3sa2_dev[card]) { - opl3sa2_dev[card]->deactivate(opl3sa2_dev[card]); + if(opl3sa2_state[card].activated && opl3sa2_state[card].pdev) { + opl3sa2_state[card].pdev->deactivate(opl3sa2_state[card].pdev); printk(KERN_DEBUG - "opl3sa2: Deactivated ISA PnP card %d (active=%d)\n", - card, opl3sa2_dev[card]->active); + PFX "Deactivated ISA PnP card %d (active=%d)\n", + card, opl3sa2_state[card].pdev->active); } #endif } diff -urN linux-2.4.18/drivers/sound/rme96xx.c linux-2.4.19-pre5/drivers/sound/rme96xx.c --- linux-2.4.18/drivers/sound/rme96xx.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/rme96xx.c Sat Mar 30 22:55:40 2002 @@ -2,14 +2,23 @@ with copy/pastes from the driver of Winfried Ritsch based on es1370.c - - * 10 Jan 2001: 0.1 initial version * 19 Jan 2001: 0.2 fixed bug in select() * 27 Apr 2001: 0.3 more than one card usable * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree * 17 May 2001: 0.5 draining code didn't work on new cards * 18 May 2001: 0.6 remove synchronize_irq() call + * 17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards + * 2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!) + Marcus Meissner + + Modifications - Heiko Purnhagen + HP20020108 fixed handling of "large" read() + HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c + HP20020118 made mixer ioctl and handling of devices>1 more safe + HP20020201 fixed handling of "large" read() properly + added REV 1.5 S/P-DIF receiver support + SNDCTL_DSP_SPEED now returns the actual speed TODO: - test more than one card --- done @@ -19,15 +28,18 @@ - mixer mmap interface - mixer ioctl - get rid of noise upon first open (why ??) - - allow multiple open(at least for read) + - allow multiple open (at least for read) - allow multiple open for non overlapping regions - recheck the multiple devices part (offsets of different devices, etc) - do decent draining in _release --- done - SMP support + - what about using fragstotal>2 for small fragsize? (HP20020118) + - add support for AFMT_S32_LE */ + #ifndef RMEVERSION -#define RMEVERSION "0.6" +#define RMEVERSION "0.8" #endif #include @@ -54,7 +66,7 @@ MODULE_AUTHOR("Guenter Geiger, geiger@debian.org"); MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver"); -MODULE_LICENSE("GPL"); +/*MODULE_LICENSE("GPL");*/ #ifdef DEBUG @@ -125,48 +137,60 @@ #define RME96xx_tc_busy 0x0100000 /* 1=time-code copy in progress (960ms) */ #define RME96xx_tc_out 0x0200000 /* time-code out bit */ -#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */ -#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz, */ +#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */ +#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz */ -#define RME96xx_F_2 0x1000000 /* od external Crystal Chip if ERF=1*/ +#define RME96xx_F_2 0x1000000 /* 001=Rev 1.5+ external Crystal Chip */ #define RME96xx_ERF 0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/ #define RME96xx_buffer_id 0x4000000 /* toggles by each interrupt on rec/play */ #define RME96xx_tc_valid 0x8000000 /* 1 = a signal is detected on time-code input */ +#define RME96xx_SPDIF_READ 0x10000000 /* byte available from Rev 1.5+ SPDIF interface */ /* Status Register Fields */ #define RME96xx_lock (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2) -#define RME96xx_buf_pos 0x000FFC0 #define RME96xx_sync (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2) #define RME96xx_F (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2) +#define rme96xx_decode_spdif_rate(x) ((x)>>22) +/* Bit 6..15 : h/w buffer pointer */ +#define RME96xx_buf_pos 0x000FFC0 +/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later + Rev G EEPROMS and Rev 1.5 cards or later. +*/ +#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos)) /* Control-Register: */ /*--------------------------------------------------------------------------------*/ -#define RME96xx_start_bit 0x0001 /* start record/play */ -#define RME96xx_latency0 0x0002 /* Bit 0 - Buffer size or latency */ -#define RME96xx_latency1 0x0004 /* Bit 1 - Buffer size or latency */ -#define RME96xx_latency2 0x0008 /* Bit 2 - Buffer size or latency */ - -#define RME96xx_Master 0x0010 /* Clock Mode Master=1,Slave/Auto=0 */ -#define RME96xx_IE 0x0020 /* Interupt Enable */ -#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/ - - -#define RME96xx_DS 0x0100 /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ -#define RME96xx_PRO 0x0200 /* spdif 0=consumer, 1=professional Mode*/ -#define RME96xx_EMP 0x0400 /* spdif Emphasis 0=None, 1=ON */ -#define RME96xx_Dolby 0x0800 /* spdif Non-audio bit 1=set, 0=unset */ - -#define RME96xx_opt_out 0x1000 /* Use 1st optical OUT as SPDIF: 1=yes,0=no */ -#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master)*/ -#define RME96xx_inp_0 0x4000 /* SPDIF-IN: 00=optical (ADAT1), */ -#define RME96xx_inp_1 0x8000 /* 01=koaxial (Cinch), 10=Internal CDROM*/ - -#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */ -#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1,01=ADAT2,10=ADAT3,11=SPDIF */ +#define RME96xx_start_bit 0x0001 /* start record/play */ +#define RME96xx_latency0 0x0002 /* Buffer size / latency */ +#define RME96xx_latency1 0x0004 /* buffersize = 512Bytes * 2^n */ +#define RME96xx_latency2 0x0008 /* 0=64samples ... 7=8192samples */ + +#define RME96xx_Master 0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */ +#define RME96xx_IE 0x0020 /* Interupt Enable */ +#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/ +#define RME96xx_freq1 0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */ +#define RME96xx_DS 0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */ +#define RME96xx_PRO 0x0200 /* SPDIF-OUT 0=consumer, 1=professional */ +#define RME96xx_EMP 0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */ +#define RME96xx_Dolby 0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */ + +#define RME96xx_opt_out 0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */ +#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master) */ +#define RME96xx_inp_0 0x4000 /* SPDIF-IN 00=optical (ADAT1), */ +#define RME96xx_inp_1 0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */ + +#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */ +#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */ + +#define RME96xx_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w SPDIF receiver */ +#define RME96xx_SPDIF_SELECT (1<<19) +#define RME96xx_SPDIF_CLOCK (1<<20) +#define RME96xx_SPDIF_WRITE (1<<21) +#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */ #define RME96xx_ctrl_init (RME96xx_latency0 |\ @@ -174,13 +198,14 @@ RME96xx_inp_1) - /* Control register fields and shortcuts */ #define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2) #define RME96xx_inp (RME96xx_inp_0|RME96xx_inp_1) #define RME96xx_SyncRef (RME96xx_SyncRef0|RME96xx_SyncRef1) -/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit0 */ +#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL) + +/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1 (??? HP20020201) */ #define RME96xx_SET_LATENCY(x) (((x)&0x7)<<1) #define RME96xx_GET_LATENCY(x) (((x)>>1)&0x7) @@ -205,8 +230,10 @@ #define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */ +#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */ #define RME_MESS "rme96xx:" + /*------------------------------------------------------------------------ Types, struct and function declarations ------------------------------------------------------------------------*/ @@ -253,8 +280,10 @@ u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */ - int open_count; + int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */ + char *card_name; /* hammerfall or hammerfall light names */ + int open_count; /* unused ??? HP20020201 */ int rate; int latency; @@ -318,6 +347,181 @@ } +inline int rme96xx_get_sample_rate_status(rme96xx_info* s) +{ + int val; + u32 status; + status = readl(s->iobase + RME96xx_status_register); + val = (status & RME96xx_fs48) ? 48000 : 44100; + if (status & RME96xx_DS_rd) + val *= 2; + return val; +} + +inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s) +{ + int val; + val = (s->control_register & RME96xx_freq) ? 48000 : 44100; + if (s->control_register & RME96xx_DS) + val *= 2; + return val; +} + + +/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver HP 20020201 */ + +static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff) +{ + if (onoff) + s->control_register |= mask; + else + s->control_register &= ~mask; + + writel(s->control_register,s->iobase + RME96xx_control_register); +} + +static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val) +{ + long mask; + long i; + + for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { + if (val & mask) + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1); + else + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0); + + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1); + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0); + } +} + +static int rme96xx_spdif_read_byte (rme96xx_info* s) +{ + long mask; + long val; + long i; + + val = 0; + + for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) { + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1); + if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ) + val |= mask; + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0); + } + + return val; +} + +static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data) +{ + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); + rme96xx_spdif_write_byte (s, 0x20); + rme96xx_spdif_write_byte (s, address); + rme96xx_spdif_write_byte (s, data); + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); +} + + +static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address) +{ + int ret; + + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); + rme96xx_spdif_write_byte (s, 0x20); + rme96xx_spdif_write_byte (s, address); + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1); + + rme96xx_spdif_write_byte (s, 0x21); + ret = rme96xx_spdif_read_byte (s); + rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0); + + return ret; +} + +static void rme96xx_initialize_spdif_receiver (rme96xx_info* s) +{ + /* XXX what unsets this ? */ + /* no idea ??? HP 20020201 */ + + s->control_register |= RME96xx_SPDIF_RESET; + + rme96xx_write_spdif_codec (s, 4, 0x40); + rme96xx_write_spdif_codec (s, 17, 0x13); + rme96xx_write_spdif_codec (s, 6, 0x02); +} + +static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate) +{ + unsigned int rate_bits; + + *spdifrate = 0x1; + if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) { + return -1; /* error condition */ + } + + if (s->hw_rev == 15) { + + int x, y, ret; + + x = rme96xx_spdif_read_codec (s, 30); + + if (x != 0) + y = 48000 * 64 / x; + else + y = 0; + + if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;} + else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;} + else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;} + else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;} + else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;} + else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;} + else {ret = 0; *spdifrate = 0x1;} + return ret; + } + + rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F; + + switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) { + case 0x7: + return 32000; + break; + + case 0x6: + return 44100; + break; + + case 0x5: + return 48000; + break; + + case 0x4: + return 88200; + break; + + case 0x3: + return 96000; + break; + + case 0x0: + return 64000; + break; + + default: + /* was an ALSA warning ... + snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n", + s->card_name, rate_bits); + */ + return 0; + break; + } +} + +/* end of code from ALSA card-rme9652.c */ + /* the hwbuf in the status register seems to have some jitter, to get rid of @@ -656,6 +860,9 @@ int rme96xx_init(rme96xx_info* s) { int i; + int status; + unsigned short rev; + DBG(printk(__FUNCTION__"\n")); numcards++; @@ -688,6 +895,56 @@ rme96xx_dmabuf_init(s,dma,2*i,2*i); } + /* code from ALSA card-rme9652.c HP 20020201 */ + /* Determine the h/w rev level of the card. This seems like + a particularly kludgy way to encode it, but its what RME + chose to do, so we follow them ... + */ + + status = readl(s->iobase + RME96xx_status_register); + if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) { + s->hw_rev = 15; + } else { + s->hw_rev = 11; + } + + /* Differentiate between the standard Hammerfall, and the + "Light", which does not have the expansion board. This + method comes from information received from Mathhias + Clausen at RME. Display the EEPROM and h/w revID where + relevant. + */ + + pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev); + switch (rev & 0xff) { + case 8: /* original eprom */ + if (s->hw_rev == 15) { + s->card_name = "RME Digi9636 (Rev 1.5)"; + } else { + s->card_name = "RME Digi9636"; + } + break; + case 9: /* W36_G EPROM */ + s->card_name = "RME Digi9636 (Rev G)"; + break; + case 4: /* W52_G EPROM */ + s->card_name = "RME Digi9652 (Rev G)"; + break; + default: + case 3: /* original eprom */ + if (s->hw_rev == 15) { + s->card_name = "RME Digi9652 (Rev 1.5)"; + } else { + s->card_name = "RME Digi9652"; + } + break; + } + + printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev); + + if (s->hw_rev == 15) + rme96xx_initialize_spdif_receiver (s); + s->started = 0; rme96xx_setlatency(s,7); @@ -728,7 +985,7 @@ if (pci_enable_device(pcidev)) goto err_irq; - if (request_irq(s->irq, rme96xx_interrupt, SA_SHIRQ, "es1370", s)) { + if (request_irq(s->irq, rme96xx_interrupt, SA_SHIRQ, "rme96xx", s)) { printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq); goto err_irq; } @@ -825,6 +1082,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n"); + devices = ((devices-1) & RME96xx_MASK_DEVS) + 1; printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices); numcards = 0; return pci_module_init(&rme96xx_driver); @@ -848,13 +1106,11 @@ ---------------------------------------------------------------------------*/ #define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED) +/* AFTM_U8 is not (yet?) supported ... HP20020201 */ - -static int rme96xx_ioctl(struct inode *in, struct file *file, - unsigned int cmd, unsigned long arg) +static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg) { - struct dmabuf * dma = (struct dmabuf *)file->private_data; rme96xx_info *s = dma->s; unsigned long flags; @@ -907,14 +1163,23 @@ case 96000: rme96xx_set_ctrl(s,RME96xx_freq); break; + /* just report current rate as default + e.g. use 0 to "select" current digital input rate default: rme96xx_unset_ctrl(s,RME96xx_freq); val = 44100; + */ } if (val > 50000) rme96xx_set_ctrl(s,RME96xx_DS); else rme96xx_unset_ctrl(s,RME96xx_DS); + /* set val to actual value HP 20020201 */ + /* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */ + if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel)) + val = rme96xx_get_sample_rate_ctrl(s); + else + val = rme96xx_get_sample_rate_status(s); s->rate = val; spin_unlock_irqrestore(&s->lock, flags); } @@ -1131,6 +1396,8 @@ return 0; case SOUND_PCM_READ_RATE: + /* HP20020201 */ + s->rate = rme96xx_get_sample_rate_status(s); return put_user(s->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: @@ -1164,28 +1431,29 @@ { int minor = MINOR(in->i_rdev); struct list_head *list; - int devnum = ((minor-3)/16) % devices; /* default = 0 */ + int devnum; rme96xx_info *s; struct dmabuf* dma; DECLARE_WAITQUEUE(wait, current); DBG(printk("device num %d open\n",devnum)); -/* ??? */ for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, rme96xx_info, devs); - if (!((s->dspnum[devnum] ^ minor) & ~0xf)) + for (devnum=0; devnumdspnum[devnum] ^ minor) & ~0xf)) + break; + if (devnumdma[devnum]; f->private_data = dma; /* wait for device to become free */ - down(&s->dma[devnum].open_sem); + down(&dma->open_sem); while (dma->open_mode & f->f_mode) { if (f->f_flags & O_NONBLOCK) { up(&dma->open_sem); @@ -1204,11 +1472,11 @@ COMM ("hardware open") - if (!s->dma[devnum].opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset); + if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset); - s->dma[devnum].open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE)); - s->dma[devnum].opened = 1; - up(&s->dma[devnum].open_sem); + dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE)); + dma->opened = 1; + up(&dma->open_sem); DBG(printk("device num %d open finished\n",devnum)); return 0; @@ -1217,7 +1485,7 @@ static int rme96xx_release(struct inode *in, struct file *file) { struct dmabuf * dma = (struct dmabuf*) file->private_data; - int hwp; + /* int hwp; ... was unused HP20020201 */ DBG(printk(__FUNCTION__"\n")); COMM ("draining") @@ -1246,8 +1514,7 @@ } -static ssize_t rme96xx_write(struct file *file, const char *buffer, - size_t count, loff_t *ppos) +static ssize_t rme96xx_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct dmabuf *dma = (struct dmabuf *)file->private_data; ssize_t ret = 0; @@ -1269,7 +1536,7 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - if (! (dma->open_mode & FMODE_WRITE)) + if (! (dma->open_mode & FMODE_WRITE)) return -ENXIO; if (!dma->s->started) rme96xx_startcard(dma->s,exact); @@ -1281,7 +1548,6 @@ dma->readptr = hwp; dma->writeptr = hwp; dma->started = 1; - COMM ("first write done") } while (count > 0) { @@ -1316,11 +1582,11 @@ return ret; } -static ssize_t rme96xx_read(struct file *file, char *buffer,size_t count, loff_t *ppos) +static ssize_t rme96xx_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct dmabuf *dma = (struct dmabuf *)file->private_data; ssize_t ret = 0; - int cnt; + int cnt; /* number of bytes from "buffer" that will/can be used */ int hop = count/dma->inchannels; int hwp; int exact = (file->f_flags & O_NONBLOCK); @@ -1341,9 +1607,6 @@ if (! (dma->open_mode & FMODE_READ)) return -ENXIO; - if (count > ((dma->s->fragsize*dma->inchannels)>>dma->formatshift)) - return -EFAULT; - if (!dma->s->started) rme96xx_startcard(dma->s,exact); hwp = rme96xx_gethwptr(dma->s,0); @@ -1359,15 +1622,12 @@ cnt = rme96xx_getispace(dma,hwp); cnt>>=dma->formatshift; cnt*=dma->inchannels; - if (cnt > count) cnt = count; if (cnt != 0) { - if (rme96xx_copytouser(dma,buffer,cnt,hop)) return ret ? ret : -EFAULT; - count -= cnt; buffer += cnt; ret += cnt; @@ -1382,6 +1642,7 @@ if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; } + hwp = rme96xx_gethwptr(dma->s,exact); }; /* count > 0 */ @@ -1500,7 +1761,7 @@ if (list == &devs) return -ENODEV; s = list_entry(list, rme96xx_info, devs); - if (s->mixer== minor) + if (s->mixer == minor) break; } VALIDATE_STATE(s); @@ -1514,19 +1775,34 @@ { rme96xx_info *s = (rme96xx_info *)file->private_data; u32 status; + int spdifrate; status = readl(s->iobase + RME96xx_status_register); + /* hack to convert rev 1.5 SPDIF rate to "crystalrate" format HP 20020201 */ + rme96xx_spdif_sample_rate(s,&spdifrate); + status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F); VALIDATE_STATE(s); if (cmd == SOUND_MIXER_PRIVATE1) { rme_mixer mixer; copy_from_user(&mixer,(void*)arg,sizeof(mixer)); - if (file->f_mode & FMODE_WRITE) { - s->dma[mixer.devnr].outoffset = mixer.o_offset; - s->dma[mixer.devnr].inoffset = mixer.i_offset; + mixer.devnr &= RME96xx_MASK_DEVS; + if (mixer.devnr >= devices) + mixer.devnr = devices-1; + if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) { + /* modify only if device not open */ + if (mixer.o_offset < 0) + mixer.o_offset = 0; + if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD) + mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1; + if (mixer.i_offset < 0) + mixer.i_offset = 0; + if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD) + mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1; + s->dma[mixer.devnr].outoffset = mixer.o_offset; + s->dma[mixer.devnr].inoffset = mixer.i_offset; } - mixer.o_offset = s->dma[mixer.devnr].outoffset; mixer.i_offset = s->dma[mixer.devnr].inoffset; @@ -1536,14 +1812,15 @@ return put_user(status, (int *)arg); } if (cmd == SOUND_MIXER_PRIVATE3) { - u32 control; - copy_from_user(&control,(void*)arg,sizeof(control)); - if (file->f_mode & FMODE_WRITE) { - s->control_register = control; - writel(control,s->iobase + RME96xx_control_register); - } + u32 control; + copy_from_user(&control,(void*)arg,sizeof(control)); + if (file->f_mode & FMODE_WRITE) { + s->control_register &= ~RME96xx_mixer_allowed; + s->control_register |= control & RME96xx_mixer_allowed; + writel(control,s->iobase + RME96xx_control_register); + } - return put_user(s->control_register, (int *)arg); + return put_user(s->control_register, (int *)arg); } return -1; } diff -urN linux-2.4.18/drivers/sound/rme96xx.h linux-2.4.19-pre5/drivers/sound/rme96xx.h --- linux-2.4.18/drivers/sound/rme96xx.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/rme96xx.h Sat Mar 30 22:55:40 2002 @@ -1,5 +1,12 @@ /* (C) 2000 Guenter Geiger with copy/pastes from the driver of Winfried Ritsch + +Modifications - Heiko Purnhagen + HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c + HP20020201 completed? + +A text/graphic control panel (rmectrl/xrmectrl) is available from + http://gige.xdv.org/pages/soft/pages/rme */ @@ -7,55 +14,65 @@ #define AFMT_S32_BLOCKED 0x0000400 #endif +/* AFMT_S16_BLOCKED not yet supported */ #ifndef AFMT_S16_BLOCKED #define AFMT_S16_BLOCKED 0x0000800 #endif typedef struct rme_status { - unsigned int irq:1; /* high or low */ - unsigned int lockmask:3; /* ADAT1, ADAT2, ADAT3 */ - unsigned int sr48:1; /* current sample rate */ - unsigned int wclock:1; /* wordclock used ? */ - unsigned int bufpoint:10; - - unsigned int syncmask:3; /* ADAT1, ADAT2, ADAT3 */ - unsigned int doublespeed:1; - unsigned int tc_busy:1; - unsigned int tc_out:1; - unsigned int crystalrate:3; - unsigned int spdif_error:1; - unsigned int bufid:1; - unsigned int tc_valid:1; + unsigned int irq:1; + unsigned int lockmask:3; /* ADAT input PLLs locked */ + /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */ + unsigned int sr48:1; /* sample rate: 0=44.1/88.2 1=48/96 kHz */ + unsigned int wclock:1; /* 1=wordclock used */ + unsigned int bufpoint:10; + unsigned int syncmask:3; /* ADAT input in sync with system clock */ + /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */ + unsigned int doublespeed:1; /* sample rate: 0=44.1/48 1=88.2/96 kHz */ + unsigned int tc_busy:1; + unsigned int tc_out:1; + unsigned int crystalrate:3; /* spdif input sample rate: */ + /* 000=64kHz, 100=88.2kHz, 011=96kHz */ + /* 111=32kHz, 110=44.1kHz, 101=48kHz */ + unsigned int spdif_error:1; /* 1=no spdif lock */ + unsigned int bufid:1; + unsigned int tc_valid:1; /* 1=timecode input detected */ + unsigned int spdif_read:1; } rme_status_t; +/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */ typedef struct rme_control { - unsigned int start:1; - unsigned int latency:3; - - unsigned int master:1; - unsigned int ie:1; - unsigned int sr48:1; - unsigned int spare:1; - - unsigned int doublespeed:1; - unsigned int pro:1; - unsigned int emphasis:1; - unsigned int dolby:1; - - unsigned int opt_out:1; - unsigned int wordclock:1; - unsigned int spdif_in:2; - - unsigned int sync_ref:2; + unsigned int start:1; + unsigned int latency:3; /* buffer size / latency [samples]: */ + /* 0=64 ... 7=8192 */ + unsigned int master:1; /* W: clock mode: 1=master 0=slave/auto */ + unsigned int ie:1; + unsigned int sr48:1; /* samplerate 0=44.1/88.2, 1=48/96 kHz */ + unsigned int spare:1; + unsigned int doublespeed:1; /* double speed 0=44.1/48, 1=88.2/96 Khz */ + unsigned int pro:1; /* W: SPDIF-OUT 0=consumer, 1=professional */ + unsigned int emphasis:1; /* W: SPDIF-OUT emphasis 0=off, 1=on */ + unsigned int dolby:1; /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */ + unsigned int opt_out:1; /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */ + unsigned int wordclock:1; /* W: use Wordclock as sync (overwrites master) */ + unsigned int spdif_in:2; /* W: SPDIF-IN: */ + /* 00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */ + unsigned int sync_ref:2; /* W: preferred sync-source in autosync */ + /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */ + unsigned int spdif_reset:1; + unsigned int spdif_select:1; + unsigned int spdif_clock:1; + unsigned int spdif_write:1; + unsigned int adat1_cd:1; /* W: Rev 1.5+: if set, internal CD connector carries ADAT */ } rme_ctrl_t; typedef struct _rme_mixer { - int i_offset; - int o_offset; - int devnr; - int spare[8]; + int i_offset; + int o_offset; + int devnr; + int spare[8]; } rme_mixer; diff -urN linux-2.4.18/drivers/sound/swarm_cs4297a.c linux-2.4.19-pre5/drivers/sound/swarm_cs4297a.c --- linux-2.4.18/drivers/sound/swarm_cs4297a.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/sound/swarm_cs4297a.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,2738 @@ +/******************************************************************************* +* +* "swarm_cs4297a.c" -- Cirrus Logic-Crystal CS4297a linux audio driver. +* +* Copyright (C) 2001 Broadcom Corporation. +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- adapted from drivers by Thomas Sailer, +* -- but don't bug him; Problems should go to: +* -- tom woller (twoller@crystal.cirrus.com) or +* (audio@crystal.cirrus.com). +* -- adapted from cs4281 PCI driver for cs4297a on +* BCM1250 Synchronous Serial interface +* (kwalker@broadcom.com) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Module command line parameters: +* none +* +* Supported devices: +* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible +* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible +* /dev/midi simple MIDI UART interface, no ioctl +* +* Modification History +* 08/20/00 trw - silence and no stopping DAC until release +* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop. +* 09/18/00 trw - added 16bit only record with conversion +* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous +* capture/playback rates) +* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin +* libOSSm.so) +* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal) +* 11/03/00 trw - fixed interrupt loss/stutter, added debug. +* 11/10/00 bkz - added __devinit to cs4297a_hw_init() +* 11/10/00 trw - fixed SMP and capture spinlock hang. +* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm. +* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix. +* 12/08/00 trw - added PM support. +* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 +* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident. +* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup. +* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use +* defaultorder-100 as power of 2 for the buffer size. example: +* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. +* +*******************************************************************************/ + +#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 + +struct cs4297a_state; +EXPORT_NO_SYMBOLS; + +static void stop_dac(struct cs4297a_state *s); +static void stop_adc(struct cs4297a_state *s); +static void start_dac(struct cs4297a_state *s); +static void start_adc(struct cs4297a_state *s); +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +// --------------------------------------------------------------------- + +#define CS4297a_MAGIC 0xf00beef1 + +// buffer order determines the size of the dma buffer for the driver. +// under Linux, a smaller buffer allows more responsiveness from many of the +// applications (e.g. games). A larger buffer allows some of the apps (esound) +// to not underrun the dma buffer as easily. As default, use 32k (order=3) +// rather than 64k as some of the games work more responsively. +// log base 2( buff sz = 32k). + +//static unsigned long defaultorder = 3; +//MODULE_PARM(defaultorder, "i"); + +// +// Turn on/off debugging compilation by commenting out "#define CSDEBUG" +// +#define CSDEBUG 0 +#if CSDEBUG +#define CSDEBUG_INTERFACE 1 +#else +#undef CSDEBUG_INTERFACE +#endif +// +// cs_debugmask areas +// +#define CS_INIT 0x00000001 // initialization and probe functions +#define CS_ERROR 0x00000002 // tmp debugging bit placeholder +#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) +#define CS_FUNCTION 0x00000008 // enter/leave functions +#define CS_WAVE_WRITE 0x00000010 // write information for wave +#define CS_WAVE_READ 0x00000020 // read information for wave +#define CS_AC97 0x00000040 // AC97 register access +#define CS_DESCR 0x00000080 // descriptor management +#define CS_OPEN 0x00000400 // all open functions in the driver +#define CS_RELEASE 0x00000800 // all release functions in the driver +#define CS_PARMS 0x00001000 // functional and operational parameters +#define CS_IOCTL 0x00002000 // ioctl (non-mixer) +#define CS_TMP 0x10000000 // tmp debug mask bit + +// +// CSDEBUG is usual mode is set to 1, then use the +// cs_debuglevel and cs_debugmask to turn on or off debugging. +// Debug level of 1 has been defined to be kernel errors and info +// that should be printed on any released driver. +// +#if CSDEBUG +#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;} +#else +#define CS_DBGOUT(mask,level,x) +#endif + +#if CSDEBUG +static unsigned long cs_debuglevel = 4; // levels range from 1-9 +static unsigned long cs_debugmask = CS_INIT /*| CS_IOCTL*/; +MODULE_PARM(cs_debuglevel, "i"); +MODULE_PARM(cs_debugmask, "i"); +#endif +#define CS_TRUE 1 +#define CS_FALSE 0 + +#define CS_TYPE_ADC 0 +#define CS_TYPE_DAC 1 + +#define SER_BASE (A_SER_BASE_1 + KSEG1) +#define SS_CSR(t) (SER_BASE+t) +#define SS_TXTBL(t) (SER_BASE+R_SER_TX_TABLE_BASE+(t*8)) +#define SS_RXTBL(t) (SER_BASE+R_SER_RX_TABLE_BASE+(t*8)) + +#define FRAME_BYTES 32 +#define FRAME_SAMPLE_BYTES 4 + +/* Should this be variable? */ +#define SAMPLE_BUF_SIZE (16*1024) +#define SAMPLE_FRAME_COUNT (SAMPLE_BUF_SIZE / FRAME_SAMPLE_BYTES) +/* The driver can explode/shrink the frames to/from a smaller sample + buffer */ +#define DMA_BLOAT_FACTOR 1 +#define DMA_DESCR (SAMPLE_FRAME_COUNT / DMA_BLOAT_FACTOR) +#define DMA_BUF_SIZE (DMA_DESCR * FRAME_BYTES) + +/* Use the maxmium count (255 == 5.1 ms between interrupts) */ +#define DMA_INT_CNT ((1 << S_DMA_INT_PKTCNT) - 1) + +/* Figure this out: how many TX DMAs ahead to schedule a reg access */ +#define REG_LATENCY 150 + +#define FRAME_TX_US 20 + +#define SERDMA_NEXTBUF(d,f) (((d)->f+1) % (d)->ringsz) + +static const char invalid_magic[] = + KERN_CRIT "cs4297a: invalid magic value\n"; + +#define VALIDATE_STATE(s) \ +({ \ + if (!(s) || (s)->magic != CS4297a_MAGIC) { \ + printk(invalid_magic); \ + return -ENXIO; \ + } \ +}) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs }; + +typedef struct serdma_descr_s { + u64 descr_a; + u64 descr_b; +} serdma_descr_t; + +typedef unsigned long paddr_t; + +typedef struct serdma_s { + unsigned ringsz; + serdma_descr_t *descrtab; + serdma_descr_t *descrtab_end; + paddr_t descrtab_phys; + + serdma_descr_t *descr_add; + serdma_descr_t *descr_rem; + + u64 *dma_buf; // buffer for DMA contents (frames) + paddr_t dma_buf_phys; + u16 *sample_buf; // tmp buffer for sample conversions + u16 *sb_swptr; + u16 *sb_hwptr; + u16 *sb_end; + + dma_addr_t dmaaddr; +// unsigned buforder; // Log base 2 of 'dma_buf' size in bytes.. + unsigned numfrag; // # of 'fragments' in the buffer. + unsigned fragshift; // Log base 2 of fragment size. + unsigned hwptr, swptr; + unsigned total_bytes; // # bytes process since open. + unsigned blocks; // last returned blocks value GETOPTR + unsigned wakeup; // interrupt occurred on block + int count; + unsigned underrun; // underrun flag + unsigned error; // over/underrun + wait_queue_head_t wait; + wait_queue_head_t reg_wait; + // redundant, but makes calculations easier + unsigned fragsize; // 2**fragshift.. + unsigned sbufsz; // 2**buforder. + unsigned fragsamples; + // OSS stuff + unsigned mapped:1; // Buffer mapped in cs4297a_mmap()? + unsigned ready:1; // prog_dmabuf_dac()/adc() successful? + unsigned endcleared:1; + unsigned type:1; // adc or dac buffer (CS_TYPE_XXX) + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; +} serdma_t; + +struct cs4297a_state { + // magic + unsigned int magic; + + struct list_head list; + + // soundcore stuff + int dev_audio; + int dev_mixer; + + // hardware resources + unsigned int irq; + + struct { + unsigned int rx_ovrrn; /* FIFO */ + unsigned int rx_overflow; /* staging buffer */ + unsigned int tx_underrun; + unsigned int rx_bad; + unsigned int rx_good; + } stats; + + // mixer registers + struct { + unsigned short vol[10]; + unsigned int recsrc; + unsigned int modcnt; + unsigned short micpreamp; + } mix; + + // wave stuff + struct properties { + unsigned fmt; + unsigned fmt_original; // original requested format + unsigned channels; + unsigned rate; + } prop_dac, prop_adc; + unsigned conversion:1; // conversion from 16 to 8 bit in progress + unsigned ena; + spinlock_t lock; + struct semaphore open_sem; + struct semaphore open_sem_adc; + struct semaphore open_sem_dac; + mode_t open_mode; + wait_queue_head_t open_wait; + wait_queue_head_t open_wait_adc; + wait_queue_head_t open_wait_dac; + + dma_addr_t dmaaddr_sample_buf; + unsigned buforder_sample_buf; // Log base 2 of 'dma_buf' size in bytes.. + + serdma_t dma_dac, dma_adc; + + volatile u16 read_value; + volatile u16 read_reg; + volatile u64 reg_request; +}; + +#if 1 +#define prog_codec(a,b) +#define dealloc_dmabuf(a,b); +#endif + +static int prog_dmabuf_adc(struct cs4297a_state *s) +{ + s->dma_adc.ready = 1; + return 0; +} + + +static int prog_dmabuf_dac(struct cs4297a_state *s) +{ + s->dma_dac.ready = 1; + return 0; +} + +static void clear_advance(void *buf, unsigned bsize, unsigned bptr, + unsigned len, unsigned char c) +{ + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(((char *) buf) + bptr, c, x); + bptr = 0; + len -= x; + } + CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO + "cs4297a: clear_advance(): memset %d at 0x%.8x for %d size \n", + (unsigned)c, (unsigned)((char *) buf) + bptr, len)); + memset(((char *) buf) + bptr, c, len); +} + +#if CSDEBUG + +// DEBUG ROUTINES + +#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) +#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) +#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) +#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) + +static void cs_printioctl(unsigned int x) +{ + unsigned int i; + unsigned char vidx; + // Index of mixtable1[] member is Device ID + // and must be <= SOUND_MIXER_NRDEVICES. + // Value of array member is index into s->mix.vol[] + static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_PCM] = 1, // voice + [SOUND_MIXER_LINE1] = 2, // AUX + [SOUND_MIXER_CD] = 3, // CD + [SOUND_MIXER_LINE] = 4, // Line + [SOUND_MIXER_SYNTH] = 5, // FM + [SOUND_MIXER_MIC] = 6, // Mic + [SOUND_MIXER_SPEAKER] = 7, // Speaker + [SOUND_MIXER_RECLEV] = 8, // Recording level + [SOUND_MIXER_VOLUME] = 9 // Master Volume + }; + + switch (x) { + case SOUND_MIXER_CS_GETDBGMASK: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_CS_GETDBGMASK:\n")); + break; + case SOUND_MIXER_CS_GETDBGLEVEL: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_CS_GETDBGLEVEL:\n")); + break; + case SOUND_MIXER_CS_SETDBGMASK: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_CS_SETDBGMASK:\n")); + break; + case SOUND_MIXER_CS_SETDBGLEVEL: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_CS_SETDBGLEVEL:\n")); + break; + case OSS_GETVERSION: + CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n")); + break; + case SNDCTL_DSP_SYNC: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n")); + break; + case SNDCTL_DSP_SETDUPLEX: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n")); + break; + case SNDCTL_DSP_GETCAPS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n")); + break; + case SNDCTL_DSP_RESET: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n")); + break; + case SNDCTL_DSP_SPEED: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n")); + break; + case SNDCTL_DSP_STEREO: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n")); + break; + case SNDCTL_DSP_CHANNELS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n")); + break; + case SNDCTL_DSP_GETFMTS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n")); + break; + case SNDCTL_DSP_SETFMT: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n")); + break; + case SNDCTL_DSP_POST: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n")); + break; + case SNDCTL_DSP_GETTRIGGER: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n")); + break; + case SNDCTL_DSP_SETTRIGGER: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n")); + break; + case SNDCTL_DSP_GETOSPACE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n")); + break; + case SNDCTL_DSP_GETISPACE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n")); + break; + case SNDCTL_DSP_NONBLOCK: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n")); + break; + case SNDCTL_DSP_GETODELAY: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n")); + break; + case SNDCTL_DSP_GETIPTR: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n")); + break; + case SNDCTL_DSP_GETOPTR: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n")); + break; + case SNDCTL_DSP_GETBLKSIZE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n")); + break; + case SNDCTL_DSP_SETFRAGMENT: + CS_DBGOUT(CS_IOCTL, 4, + printk("SNDCTL_DSP_SETFRAGMENT:\n")); + break; + case SNDCTL_DSP_SUBDIVIDE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n")); + break; + case SOUND_PCM_READ_RATE: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n")); + break; + case SOUND_PCM_READ_CHANNELS: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_PCM_READ_CHANNELS:\n")); + break; + case SOUND_PCM_READ_BITS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); + break; + case SOUND_PCM_WRITE_FILTER: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_PCM_WRITE_FILTER:\n")); + break; + case SNDCTL_DSP_SETSYNCRO: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); + break; + case SOUND_PCM_READ_FILTER: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); + break; + case SOUND_MIXER_PRIVATE1: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); + break; + case SOUND_MIXER_PRIVATE2: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); + break; + case SOUND_MIXER_PRIVATE3: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); + break; + case SOUND_MIXER_PRIVATE4: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); + break; + case SOUND_MIXER_PRIVATE5: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); + break; + case SOUND_MIXER_INFO: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); + break; + case SOUND_OLD_MIXER_INFO: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); + break; + + default: + switch (_IOC_NR(x)) { + case SOUND_MIXER_VOLUME: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_VOLUME:\n")); + break; + case SOUND_MIXER_SPEAKER: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_SPEAKER:\n")); + break; + case SOUND_MIXER_RECLEV: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_RECLEV:\n")); + break; + case SOUND_MIXER_MIC: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_MIC:\n")); + break; + case SOUND_MIXER_SYNTH: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_SYNTH:\n")); + break; + case SOUND_MIXER_RECSRC: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_RECSRC:\n")); + break; + case SOUND_MIXER_DEVMASK: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_DEVMASK:\n")); + break; + case SOUND_MIXER_RECMASK: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_RECMASK:\n")); + break; + case SOUND_MIXER_STEREODEVS: + CS_DBGOUT(CS_IOCTL, 4, + printk("SOUND_MIXER_STEREODEVS:\n")); + break; + case SOUND_MIXER_CAPS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n")); + break; + default: + i = _IOC_NR(x); + if (i >= SOUND_MIXER_NRDEVICES + || !(vidx = mixtable1[i])) { + CS_DBGOUT(CS_IOCTL, 4, printk + ("UNKNOWN IOCTL: 0x%.8x NR=%d\n", + x, i)); + } else { + CS_DBGOUT(CS_IOCTL, 4, printk + ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n", + x, i)); + } + break; + } + } +} +#endif + + +static int ser_init(struct cs4297a_state *s) +{ + int i; + + CS_DBGOUT(CS_INIT, 2, + printk(KERN_INFO "cs4297a: Setting up serial parameters\n")); + + out64(M_SYNCSER_CMD_RX_RESET | M_SYNCSER_CMD_TX_RESET, SS_CSR(R_SER_CMD)); + + out64(M_SYNCSER_MSB_FIRST, SS_CSR(R_SER_MODE)); + out64(32, SS_CSR(R_SER_MINFRM_SZ)); + out64(32, SS_CSR(R_SER_MAXFRM_SZ)); + + out64(1, SS_CSR(R_SER_TX_RD_THRSH)); + out64(4, SS_CSR(R_SER_TX_WR_THRSH)); + out64(8, SS_CSR(R_SER_RX_RD_THRSH)); + + /* This looks good from experimentation */ + out64((M_SYNCSER_TXSYNC_INT | V_SYNCSER_TXSYNC_DLY(0) | M_SYNCSER_TXCLK_EXT | + M_SYNCSER_RXSYNC_INT | V_SYNCSER_RXSYNC_DLY(1) | M_SYNCSER_RXCLK_EXT | M_SYNCSER_RXSYNC_EDGE), + SS_CSR(R_SER_LINE_MODE)); + + /* This looks good from experimentation */ + out64(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, + SS_TXTBL(0)); + out64(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, + SS_TXTBL(1)); + out64(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, + SS_TXTBL(2)); + out64(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | + M_SYNCSER_SEQ_STROBE | M_SYNCSER_SEQ_LAST, SS_TXTBL(3)); + + out64(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, + SS_RXTBL(0)); + out64(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, + SS_RXTBL(1)); + out64(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, + SS_RXTBL(2)); + out64(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE | + M_SYNCSER_SEQ_LAST, SS_RXTBL(3)); + + for (i=4; i<16; i++) { + /* Just in case... */ + out64(M_SYNCSER_SEQ_LAST, SS_TXTBL(i)); + out64(M_SYNCSER_SEQ_LAST, SS_RXTBL(i)); + } + + return 0; +} + +static int init_serdma(serdma_t *dma) +{ + CS_DBGOUT(CS_INIT, 2, + printk(KERN_ERR "cs4297a: desc - %d sbufsize - %d dbufsize - %d\n", + DMA_DESCR, SAMPLE_BUF_SIZE, DMA_BUF_SIZE)); + + /* Descriptors */ + dma->ringsz = DMA_DESCR; + dma->descrtab = kmalloc(dma->ringsz * sizeof(serdma_descr_t), GFP_KERNEL); + if (!dma->descrtab) { + printk(KERN_ERR "cs4297a: kmalloc descrtab failed\n"); + return -1; + } + memset(dma->descrtab, 0, dma->ringsz * sizeof(serdma_descr_t)); + dma->descrtab_end = dma->descrtab + dma->ringsz; + /* XXX bloddy mess, use proper DMA API here ... */ + dma->descrtab_phys = PHYSADDR((int)dma->descrtab); + dma->descr_add = dma->descr_rem = dma->descrtab; + + /* Frame buffer area */ + dma->dma_buf = kmalloc(DMA_BUF_SIZE, GFP_KERNEL); + if (!dma->dma_buf) { + printk(KERN_ERR "cs4297a: kmalloc dma_buf failed\n"); + kfree(dma->descrtab); + return -1; + } + memset(dma->dma_buf, 0, DMA_BUF_SIZE); + dma->dma_buf_phys = PHYSADDR((int)dma->dma_buf); + + /* Samples buffer area */ + dma->sbufsz = SAMPLE_BUF_SIZE; + dma->sample_buf = kmalloc(dma->sbufsz, GFP_KERNEL); + if (!dma->sample_buf) { + printk(KERN_ERR "cs4297a: kmalloc sample_buf failed\n"); + kfree(dma->descrtab); + kfree(dma->dma_buf); + return -1; + } + dma->sb_swptr = dma->sb_hwptr = dma->sample_buf; + dma->sb_end = (u16 *)((void *)dma->sample_buf + dma->sbufsz); + dma->fragsize = dma->sbufsz >> 1; + + CS_DBGOUT(CS_INIT, 4, + printk(KERN_ERR "cs4297a: descrtab - %08x dma_buf - %x sample_buf - %x\n", + (int)dma->descrtab, (int)dma->dma_buf, + (int)dma->sample_buf)); + + return 0; +} + +static int dma_init(struct cs4297a_state *s) +{ + int i; + + CS_DBGOUT(CS_INIT, 2, + printk(KERN_INFO "cs4297a: Setting up DMA\n")); + + if (init_serdma(&s->dma_adc) || + init_serdma(&s->dma_dac)) + return -1; + + if (in64(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))|| + in64(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) { + panic("DMA state corrupted?!"); + } + + /* Initialize now - the descr/buffer pairings will never + change... */ + for (i=0; idma_dac.descrtab[i].descr_a = M_DMA_SERRX_SOP | V_DMA_DSCRA_A_SIZE(1) | + (s->dma_dac.dma_buf_phys + i*FRAME_BYTES); + s->dma_dac.descrtab[i].descr_b = V_DMA_DSCRB_PKT_SIZE(FRAME_BYTES); + s->dma_adc.descrtab[i].descr_a = V_DMA_DSCRA_A_SIZE(1) | + (s->dma_adc.dma_buf_phys + i*FRAME_BYTES); + s->dma_adc.descrtab[i].descr_b = 0; + } + + out64((M_DMA_EOP_INT_EN | V_DMA_INT_PKTCNT(DMA_INT_CNT) | + V_DMA_RINGSZ(DMA_DESCR) | M_DMA_TDX_EN), + SS_CSR(R_SER_DMA_CONFIG0_RX)); + out64(M_DMA_L2CA, SS_CSR(R_SER_DMA_CONFIG1_RX)); + out64(s->dma_adc.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_RX)); + + out64(V_DMA_RINGSZ(DMA_DESCR), SS_CSR(R_SER_DMA_CONFIG0_TX)); + out64(M_DMA_L2CA | M_DMA_NO_DSCR_UPDT, SS_CSR(R_SER_DMA_CONFIG1_TX)); + out64(s->dma_dac.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_TX)); + + /* Prep the receive DMA descriptor ring */ + out64(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); + + out64(M_SYNCSER_DMA_RX_EN | M_SYNCSER_DMA_TX_EN, SS_CSR(R_SER_DMA_ENABLE)); + + out64((M_SYNCSER_RX_SYNC_ERR | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_EOP_COUNT), + SS_CSR(R_SER_INT_MASK)); + + /* Enable the rx/tx; let the codec warm up to the sync and + start sending good frames before the receive FIFO is + enabled */ + out64(M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); + udelay(1000); + out64(M_SYNCSER_CMD_RX_EN | M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); + + /* XXXKW is this magic? (the "1" part) */ + while ((in64(SS_CSR(R_SER_STATUS)) & 0xf1) != 1) + ; + + CS_DBGOUT(CS_INIT, 4, + printk(KERN_INFO "cs4297a: status: %08x\n", + (unsigned int)(in64(SS_CSR(R_SER_STATUS)) & 0xffffffff))); + + return 0; +} + +static int serdma_reg_access(struct cs4297a_state *s, u64 data) +{ + serdma_t *d = &s->dma_dac; + u64 *data_p; + unsigned swptr; + int flags; + serdma_descr_t *descr; + + if (s->reg_request) { + printk(KERN_ERR "cs4297a: attempt to issue multiple reg_access\n"); + return -1; + } + + if (s->ena & FMODE_WRITE) { + /* Since a writer has the DSP open, we have to mux the + request in */ + s->reg_request = data; + interruptible_sleep_on(&s->dma_dac.reg_wait); + /* XXXKW how can I deal with the starvation case where + the opener isn't writing? */ + } else { + /* Be safe when changing ring pointers */ + spin_lock_irqsave(&s->lock, flags); + if (d->hwptr != d->swptr) { + printk(KERN_ERR "cs4297a: reg access found bookkeeping error (hw/sw = %d/%d\n", + d->hwptr, d->swptr); + spin_unlock_irqrestore(&s->lock, flags); + return -1; + } + swptr = d->swptr; + d->hwptr = d->swptr = (d->swptr + 1) % d->ringsz; + spin_unlock_irqrestore(&s->lock, flags); + + descr = &d->descrtab[swptr]; + data_p = &d->dma_buf[swptr * 4]; + *data_p = data; + out64(1, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); + CS_DBGOUT(CS_DESCR, 4, + printk(KERN_INFO "cs4297a: add_tx %p (%x -> %x)\n", + data_p, swptr, d->hwptr)); + } + + CS_DBGOUT(CS_FUNCTION, 6, + printk(KERN_INFO "cs4297a: serdma_reg_access()-\n")); + + return 0; +} + +//**************************************************************************** +// "cs4297a_read_ac97" -- Reads an AC97 register +//**************************************************************************** +static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset, + u32 * value) +{ + CS_DBGOUT(CS_AC97, 1, + printk(KERN_INFO "cs4297a: read reg %2x\n", offset)); + if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40))) + return -1; + + interruptible_sleep_on(&s->dma_adc.reg_wait); + *value = s->read_value; + CS_DBGOUT(CS_AC97, 2, + printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value)); + + return 0; +} + + +//**************************************************************************** +// "cs4297a_write_ac97()"-- writes an AC97 register +//**************************************************************************** +static int cs4297a_write_ac97(struct cs4297a_state *s, u32 offset, + u32 value) +{ + CS_DBGOUT(CS_AC97, 1, + printk(KERN_INFO "cs4297a: write reg %2x -> %04x\n", offset, value)); + return (serdma_reg_access(s, (0xELL << 60) | ((u64)(offset & 0x7F) << 40) | ((value & 0xffff) << 12))); +} + +static void stop_dac(struct cs4297a_state *s) +{ + unsigned long flags; + + CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4297a: stop_dac():\n")); + spin_lock_irqsave(&s->lock, flags); + s->ena &= ~FMODE_WRITE; +#if 0 + /* XXXKW what do I really want here? My theory for now is + that I just flip the "ena" bit, and the interrupt handler + will stop processing the xmit channel */ + out64((s->ena & FMODE_READ) ? M_SYNCSER_DMA_RX_EN : 0, + SS_CSR(R_SER_DMA_ENABLE)); +#endif + + spin_unlock_irqrestore(&s->lock, flags); +} + + +static void start_dac(struct cs4297a_state *s) +{ + unsigned long flags; + + CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: start_dac()+\n")); + spin_lock_irqsave(&s->lock, flags); + if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || + (s->dma_dac.count > 0 + && s->dma_dac.ready))) { + s->ena |= FMODE_WRITE; + /* XXXKW what do I really want here? My theory for + now is that I just flip the "ena" bit, and the + interrupt handler will start processing the xmit + channel */ + + CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO + "cs4297a: start_dac(): start dma\n")); + + } + spin_unlock_irqrestore(&s->lock, flags); + CS_DBGOUT(CS_FUNCTION, 3, + printk(KERN_INFO "cs4297a: start_dac()-\n")); +} + + +static void stop_adc(struct cs4297a_state *s) +{ + unsigned long flags; + + CS_DBGOUT(CS_FUNCTION, 3, + printk(KERN_INFO "cs4297a: stop_adc()+\n")); + + spin_lock_irqsave(&s->lock, flags); + s->ena &= ~FMODE_READ; + + if (s->conversion == 1) { + s->conversion = 0; + s->prop_adc.fmt = s->prop_adc.fmt_original; + } + /* Nothing to do really, I need to keep the DMA going + XXXKW when do I get here, and is there more I should do? */ + spin_unlock_irqrestore(&s->lock, flags); + CS_DBGOUT(CS_FUNCTION, 3, + printk(KERN_INFO "cs4297a: stop_adc()-\n")); +} + + +static void start_adc(struct cs4297a_state *s) +{ + unsigned long flags; + + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: start_adc()+\n")); + + if (!(s->ena & FMODE_READ) && + (s->dma_adc.mapped || s->dma_adc.count <= + (signed) (s->dma_adc.sbufsz - 2 * s->dma_adc.fragsize)) + && s->dma_adc.ready) { + if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { + // + // now only use 16 bit capture, due to truncation issue + // in the chip, noticable distortion occurs. + // allocate buffer and then convert from 16 bit to + // 8 bit for the user buffer. + // + s->prop_adc.fmt_original = s->prop_adc.fmt; + if (s->prop_adc.fmt & AFMT_S8) { + s->prop_adc.fmt &= ~AFMT_S8; + s->prop_adc.fmt |= AFMT_S16_LE; + } + if (s->prop_adc.fmt & AFMT_U8) { + s->prop_adc.fmt &= ~AFMT_U8; + s->prop_adc.fmt |= AFMT_U16_LE; + } + // + // prog_dmabuf_adc performs a stop_adc() but that is + // ok since we really haven't started the DMA yet. + // + prog_codec(s, CS_TYPE_ADC); + + prog_dmabuf_adc(s); + s->conversion = 1; + } + spin_lock_irqsave(&s->lock, flags); + s->ena |= FMODE_READ; + /* Nothing to do really, I am probably already + DMAing... XXXKW when do I get here, and is there + more I should do? */ + spin_unlock_irqrestore(&s->lock, flags); + + CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO + "cs4297a: start_adc(): start adc\n")); + } + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: start_adc()-\n")); + +} + + +// call with spinlock held! +static void cs4297a_update_ptr(struct cs4297a_state *s, int intflag) +{ + int good_diff, diff, diff2; + u64 *data_p, data; + u32 *s_ptr; + unsigned hwptr; + u32 status; + serdma_t *d; + serdma_descr_t *descr; + + // update ADC pointer + status = intflag ? in64(SS_CSR(R_SER_STATUS)) : 0; + + if ((s->ena & FMODE_READ) || (status & (M_SYNCSER_RX_EOP_COUNT))) { + d = &s->dma_adc; + hwptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - + d->descrtab_phys) / sizeof(serdma_descr_t)); + + if (s->ena & FMODE_READ) { + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: upd_rcv sw->hw->hw %x/%x/%x (int-%d)n", + d->swptr, d->hwptr, hwptr, intflag)); + /* Number of DMA buffers available for software: */ + diff2 = diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; + d->hwptr = hwptr; + good_diff = 0; + s_ptr = (u32 *)&(d->dma_buf[d->swptr*4]); + descr = &d->descrtab[d->swptr]; + while (diff2--) { + u64 data = *(u64 *)s_ptr; + u64 descr_a; + u16 left, right; + descr_a = descr->descr_a; + descr->descr_a &= ~M_DMA_SERRX_SOP; + if ((descr_a & M_DMA_DSCRA_A_ADDR) != PHYSADDR((int)s_ptr)) { + printk(KERN_ERR "cs4297a: RX Bad address (read)\n"); + } + if (((data & 0x9800000000000000) != 0x9800000000000000) || + (!(descr_a & M_DMA_SERRX_SOP)) || + (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { + s->stats.rx_bad++; + printk(KERN_DEBUG "cs4297a: RX Bad attributes (read)\n"); + continue; + } + s->stats.rx_good++; + if ((data >> 61) == 7) { + s->read_value = (data >> 12) & 0xffff; + s->read_reg = (data >> 40) & 0x7f; + wake_up(&d->reg_wait); + } + if (d->count && (d->sb_hwptr == d->sb_swptr)) { + s->stats.rx_overflow++; + printk(KERN_DEBUG "cs4297a: RX overflow\n"); + continue; + } + good_diff++; + left = ((s_ptr[1] & 0xff) << 8) | ((s_ptr[2] >> 24) & 0xff); + right = (s_ptr[2] >> 4) & 0xffff; + *d->sb_hwptr++ = left; + *d->sb_hwptr++ = right; + if (d->sb_hwptr == d->sb_end) + d->sb_hwptr = d->sample_buf; + descr++; + if (descr == d->descrtab_end) { + descr = d->descrtab; + s_ptr = (u32 *)s->dma_adc.dma_buf; + } else { + s_ptr += 8; + } + } + d->total_bytes += good_diff * FRAME_SAMPLE_BYTES; + d->count += good_diff * FRAME_SAMPLE_BYTES; + if (d->count > d->sbufsz) { + printk(KERN_ERR "cs4297a: bogus receive overflow!!\n"); + } + d->swptr = (d->swptr + diff) % d->ringsz; + out64(diff, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); + if (d->mapped) { + if (d->count >= (signed) d->fragsize) + wake_up(&d->wait); + } else { + if (d->count > 0) { + CS_DBGOUT(CS_WAVE_READ, 4, + printk(KERN_INFO + "cs4297a: update count -> %d\n", d->count)); + wake_up(&d->wait); + } + } + } else { + /* Receive is going even if no one is + listening (for register accesses and to + avoid FIFO overrun) */ + diff2 = diff = (hwptr + d->ringsz - d->hwptr) % d->ringsz; + if (!diff) { + printk(KERN_ERR "cs4297a: RX full or empty?\n"); + } + + descr = &d->descrtab[d->swptr]; + data_p = &d->dma_buf[d->swptr*4]; + + /* Force this to happen at least once; I got + here because of an interrupt, so there must + be a buffer to process. */ + do { + data = *data_p; + if ((descr->descr_a & M_DMA_DSCRA_A_ADDR) != PHYSADDR((int)data_p)) { + printk(KERN_ERR "cs4297a: RX Bad address %d (%x %x)\n", d->swptr, + (int)(descr->descr_a & M_DMA_DSCRA_A_ADDR), + (int)PHYSADDR((int)data_p)); + } + if (!(data & (1LL << 63)) || + !(descr->descr_a & M_DMA_SERRX_SOP) || + (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { + s->stats.rx_bad++; + printk(KERN_DEBUG "cs4297a: RX Bad attributes\n"); + } else { + s->stats.rx_good++; + if ((data >> 61) == 7) { + s->read_value = (data >> 12) & 0xffff; + s->read_reg = (data >> 40) & 0x7f; + wake_up(&d->reg_wait); + } + } + descr->descr_a &= ~M_DMA_SERRX_SOP; + descr++; + d->swptr++; + data_p += 4; + if (descr == d->descrtab_end) { + descr = d->descrtab; + d->swptr = 0; + data_p = d->dma_buf; + } + out64(1, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); + } while (--diff); + d->hwptr = hwptr; + + CS_DBGOUT(CS_DESCR, 6, + printk(KERN_INFO "cs4297a: hw/sw %x/%x\n", d->hwptr, d->swptr)); + } + + CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO + "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", + (unsigned)s, d->hwptr, + d->total_bytes, d->count)); + } + + /* XXXKW worry about s->reg_request -- there is a starvation + case if s->ena has FMODE_WRITE on, but the client isn't + doing writes */ + + // update DAC pointer + // + // check for end of buffer, means that we are going to wait for another interrupt + // to allow silence to fill the fifos on the part, to keep pops down to a minimum. + // + if (s->ena & FMODE_WRITE) { + serdma_t *d = &s->dma_dac; + hwptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - + d->descrtab_phys) / sizeof(serdma_descr_t)); + diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; + CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO + "cs4297a: cs4297a_update_ptr(): hw/hw/sw %x/%x/%x diff %d count %d\n", + d->hwptr, hwptr, d->swptr, diff, d->count)); + d->hwptr = hwptr; + /* XXXKW stereo? conversion? Just assume 2 16-bit samples for now */ + d->total_bytes += diff * FRAME_SAMPLE_BYTES; + if (d->mapped) { + d->count += diff * FRAME_SAMPLE_BYTES; + if (d->count >= d->fragsize) { + d->wakeup = 1; + wake_up(&d->wait); + if (d->count > d->sbufsz) + d->count &= d->sbufsz - 1; + } + } else { + d->count -= diff * FRAME_SAMPLE_BYTES; + if (d->count <= 0) { + // + // fill with silence, and do not shut down the DAC. + // Continue to play silence until the _release. + // + CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO + "cs4297a: cs4297a_update_ptr(): memset %d at 0x%.8x for %d size \n", + (unsigned)(s->prop_dac.fmt & + (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, + (unsigned)d->dma_buf, + d->ringsz)); + memset(d->dma_buf, 0, d->ringsz * FRAME_BYTES); + if (d->count < 0) { + d->underrun = 1; + s->stats.tx_underrun++; + d->count = 0; + CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO + "cs4297a: cs4297a_update_ptr(): underrun\n")); + } + } else if (d->count <= + (signed) d->fragsize + && !d->endcleared) { + /* XXXKW what is this for? */ + clear_advance(d->dma_buf, + d->sbufsz, + d->swptr, + d->fragsize, + 0); + d->endcleared = 1; + } + if ( (d->count <= (signed) d->sbufsz/2) || intflag) + { + CS_DBGOUT(CS_WAVE_WRITE, 4, + printk(KERN_INFO + "cs4297a: update count -> %d\n", d->count)); + wake_up(&d->wait); + } + } + CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO + "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", + (unsigned) s, d->hwptr, + d->total_bytes, d->count)); + } +} + +static int mixer_ioctl(struct cs4297a_state *s, unsigned int cmd, + unsigned long arg) +{ + // Index to mixer_src[] is value of AC97 Input Mux Select Reg. + // Value of array member is recording source Device ID Mask. + static const unsigned int mixer_src[8] = { + SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, + SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 + }; + + // Index of mixtable1[] member is Device ID + // and must be <= SOUND_MIXER_NRDEVICES. + // Value of array member is index into s->mix.vol[] + static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_PCM] = 1, // voice + [SOUND_MIXER_LINE1] = 2, // AUX + [SOUND_MIXER_CD] = 3, // CD + [SOUND_MIXER_LINE] = 4, // Line + [SOUND_MIXER_SYNTH] = 5, // FM + [SOUND_MIXER_MIC] = 6, // Mic + [SOUND_MIXER_SPEAKER] = 7, // Speaker + [SOUND_MIXER_RECLEV] = 8, // Recording level + [SOUND_MIXER_VOLUME] = 9 // Master Volume + }; + + static const unsigned mixreg[] = { + AC97_PCMOUT_VOL, + AC97_AUX_VOL, + AC97_CD_VOL, + AC97_LINEIN_VOL + }; + unsigned char l, r, rl, rr, vidx; + unsigned char attentbl[11] = + { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 }; + unsigned temp1; + int i, val; + + VALIDATE_STATE(s); + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs4297a: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n", + (unsigned) s, cmd)); +#if CSDEBUG + cs_printioctl(cmd); +#endif +#if CSDEBUG_INTERFACE + + if ((cmd == SOUND_MIXER_CS_GETDBGMASK) || + (cmd == SOUND_MIXER_CS_SETDBGMASK) || + (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || + (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) + { + switch (cmd) { + + case SOUND_MIXER_CS_GETDBGMASK: + return put_user(cs_debugmask, + (unsigned long *) arg); + + case SOUND_MIXER_CS_GETDBGLEVEL: + return put_user(cs_debuglevel, + (unsigned long *) arg); + + case SOUND_MIXER_CS_SETDBGMASK: + if (get_user(val, (unsigned long *) arg)) + return -EFAULT; + cs_debugmask = val; + return 0; + + case SOUND_MIXER_CS_SETDBGLEVEL: + if (get_user(val, (unsigned long *) arg)) + return -EFAULT; + cs_debuglevel = val; + return 0; + default: + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs4297a: mixer_ioctl(): ERROR unknown debug cmd\n")); + return 0; + } + } +#endif + + if (cmd == SOUND_MIXER_PRIVATE1) { + return -EINVAL; + } + if (cmd == SOUND_MIXER_PRIVATE2) { + // enable/disable/query spatializer + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != -1) { + temp1 = (val & 0x3f) >> 2; + cs4297a_write_ac97(s, AC97_3D_CONTROL, temp1); + cs4297a_read_ac97(s, AC97_GENERAL_PURPOSE, + &temp1); + cs4297a_write_ac97(s, AC97_GENERAL_PURPOSE, + temp1 | 0x2000); + } + cs4297a_read_ac97(s, AC97_3D_CONTROL, &temp1); + return put_user((temp1 << 2) | 3, (int *) arg); + } + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "CS4297a", sizeof(info.id)); + strncpy(info.name, "Crystal CS4297a", 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, "CS4297a", sizeof(info.id)); + strncpy(info.name, "Crystal CS4297a", 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' || _SIOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + // If ioctl has only the SIOC_READ bit(bit 31) + // on, process the only-read commands. + if (_SIOC_DIR(cmd) == _SIOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source + cs4297a_read_ac97(s, AC97_RECORD_SELECT, + &temp1); + return put_user(mixer_src[temp1 & 7], (int *) arg); + + case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device + return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, + (int *) arg); + + case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source + return put_user(SOUND_MASK_LINE | SOUND_MASK_VOLUME, + (int *) arg); + + case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo + return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | 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 + || !(vidx = mixtable1[i])) + return -EINVAL; + return put_user(s->mix.vol[vidx - 1], (int *) arg); + } + } + // If ioctl doesn't have both the SIOC_READ and + // the SIOC_WRITE bit set, return invalid. + if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE)) + return -EINVAL; + + // Increment the count of volume writes. + s->mix.modcnt++; + + // Isolate the command; it must be a write. + switch (_IOC_NR(cmd)) { + + case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source + if (get_user(val, (int *) arg)) + return -EFAULT; + i = hweight32(val); // i = # bits on in val. + if (i != 1) // One & only 1 bit must be on. + return 0; + for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { + if (val == mixer_src[i]) { + temp1 = (i << 8) | i; + cs4297a_write_ac97(s, + AC97_RECORD_SELECT, + temp1); + return 0; + } + } + return 0; + + case SOUND_MIXER_VOLUME: + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; // Max soundcard.h vol is 100. + if (l < 6) { + rl = 63; + l = 0; + } else + rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten. + + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; // Max right volume is 100, too + if (r < 6) { + rr = 63; + r = 0; + } else + rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation. + + if ((rl > 60) && (rr > 60)) // If both l & r are 'low', + temp1 = 0x8000; // turn on the mute bit. + else + temp1 = 0; + + temp1 |= (rl << 8) | rr; + + cs4297a_write_ac97(s, AC97_MASTER_VOL_STEREO, temp1); + cs4297a_write_ac97(s, AC97_PHONE_VOL, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[8] = ((unsigned int) r << 8) | l; +#else + s->mix.vol[8] = val; +#endif + return put_user(s->mix.vol[8], (int *) arg); + + case SOUND_MIXER_SPEAKER: + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (l < 3) { + rl = 0; + l = 0; + } else { + rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15. + l = (rl * 13 + 5) / 2; + } + + if (rl < 3) { + temp1 = 0x8000; + rl = 0; + } else + temp1 = 0; + rl = 15 - rl; // Convert volume to attenuation. + temp1 |= rl << 1; + cs4297a_write_ac97(s, AC97_PCBEEP_VOL, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[6] = l << 8; +#else + s->mix.vol[6] = val; +#endif + return put_user(s->mix.vol[6], (int *) arg); + + case SOUND_MIXER_RECLEV: + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15. + rr = (r * 2 - 5) / 13; + if (rl < 3 && rr < 3) + temp1 = 0x8000; + else + temp1 = 0; + + temp1 = temp1 | (rl << 8) | rr; + cs4297a_write_ac97(s, AC97_RECORD_GAIN, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[7] = ((unsigned int) r << 8) | l; +#else + s->mix.vol[7] = val; +#endif + return put_user(s->mix.vol[7], (int *) arg); + + case SOUND_MIXER_MIC: + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (l < 1) { + l = 0; + rl = 0; + } else { + rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31. + l = (rl * 16 + 4) / 5; + } + cs4297a_read_ac97(s, AC97_MIC_VOL, &temp1); + temp1 &= 0x40; // Isolate 20db gain bit. + if (rl < 3) { + temp1 |= 0x8000; + rl = 0; + } + rl = 31 - rl; // Convert volume to attenuation. + temp1 |= rl; + cs4297a_write_ac97(s, AC97_MIC_VOL, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[5] = val << 8; +#else + s->mix.vol[5] = val; +#endif + return put_user(s->mix.vol[5], (int *) arg); + + + case SOUND_MIXER_SYNTH: + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (get_user(val, (int *) arg)) + return -EFAULT; + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63. + rr = (r * 2 - 11) / 3; + if (rl < 3) // If l is low, turn on + temp1 = 0x0080; // the mute bit. + else + temp1 = 0; + + rl = 63 - rl; // Convert vol to attenuation. +// writel(temp1 | rl, s->pBA0 + FMLVC); + if (rr < 3) // If rr is low, turn on + temp1 = 0x0080; // the mute bit. + else + temp1 = 0; + rr = 63 - rr; // Convert vol to attenuation. +// writel(temp1 | rr, s->pBA0 + FMRVC); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[4] = (r << 8) | l; +#else + s->mix.vol[4] = val; +#endif + return put_user(s->mix.vol[4], (int *) arg); + + + default: + CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO + "cs4297a: mixer_ioctl(): default\n")); + + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) + return -EINVAL; + if (get_user(val, (int *) arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (l < 1) { + l = 0; + rl = 31; + } else + rl = (attentbl[(l * 10) / 100]) >> 1; + + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + if (r < 1) { + r = 0; + rr = 31; + } else + rr = (attentbl[(r * 10) / 100]) >> 1; + if ((rl > 30) && (rr > 30)) + temp1 = 0x8000; + else + temp1 = 0; + temp1 = temp1 | (rl << 8) | rr; + cs4297a_write_ac97(s, mixreg[vidx - 1], temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l; +#else + s->mix.vol[vidx - 1] = val; +#endif + return put_user(s->mix.vol[vidx - 1], (int *) arg); + } +} + +// --------------------------------------------------------------------- + +static int cs4297a_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs4297a_state *s=NULL; + struct list_head *entry; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); + + list_for_each(entry, &cs4297a_devs) + { + s = list_entry(entry, struct cs4297a_state, list); + if(s->dev_mixer == minor) + break; + } + if (!s) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); + return -ENODEV; + } + VALIDATE_STATE(s); + file->private_data = s; + MOD_INC_USE_COUNT; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); + + return 0; +} + + +static int cs4297a_release_mixdev(struct inode *inode, struct file *file) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + + VALIDATE_STATE(s); + MOD_DEC_USE_COUNT; + return 0; +} + + +static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, + arg); +} + + +// ****************************************************************************************** +// Mixer file operations struct. +// ****************************************************************************************** +static /*const */ struct file_operations cs4297a_mixer_fops = { + llseek:no_llseek, + ioctl:cs4297a_ioctl_mixdev, + open:cs4297a_open_mixdev, + release:cs4297a_release_mixdev, +}; + +// --------------------------------------------------------------------- + + +static int drain_adc(struct cs4297a_state *s, int nonblock) +{ + /* This routine serves no purpose currently - any samples + sitting in the receive queue will just be processed by the + background consumer. This would be different if DMA + actually stopped when there were no clients. */ + return 0; +} + +static int drain_dac(struct cs4297a_state *s, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned hwptr; + unsigned tmo; + int count; + + if (s->dma_dac.mapped) + return 0; + if (nonblock) + return -EBUSY; + add_wait_queue(&s->dma_dac.wait, &wait); + while ((count = in64(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) || + (s->dma_dac.count > 0)) { + if (!signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); + /* XXXKW is this calculation working? */ + tmo = ((count * FRAME_TX_US) * HZ) / 1000000; + schedule_timeout(tmo + 1); + } else { + /* XXXKW do I care if there is a signal pending? */ + } + } + spin_lock_irqsave(&s->lock, flags); + /* Reset the bookkeeping */ + hwptr = (int)(((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - + s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); + s->dma_dac.hwptr = s->dma_dac.swptr = hwptr; + spin_unlock_irqrestore(&s->lock, flags); + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return 0; +} + + +// --------------------------------------------------------------------- + +static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count, + loff_t * ppos) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + ssize_t ret; + unsigned long flags; + int cnt, count_fr, cnt_by; + unsigned copied = 0; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, + printk(KERN_INFO "cs4297a: cs4297a_read()+ %d \n", count)); + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; +// +// "count" is the amount of bytes to read (from app), is decremented each loop +// by the amount of bytes that have been returned to the user buffer. +// "cnt" is the running total of each read from the buffer (changes each loop) +// "buffer" points to the app's buffer +// "ret" keeps a running total of the amount of bytes that have been copied +// to the user buffer. +// "copied" is the total bytes copied into the user buffer for each loop. +// + while (count > 0) { + CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO + "_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n", + count, s->dma_adc.count, + s->dma_adc.swptr, s->dma_adc.hwptr)); + spin_lock_irqsave(&s->lock, flags); + + /* cnt will be the number of available samples (16-bit + stereo); it starts out as the maxmimum consequetive + samples */ + cnt = (s->dma_adc.sb_end - s->dma_adc.sb_swptr) / 2; + count_fr = s->dma_adc.count / FRAME_SAMPLE_BYTES; + + // dma_adc.count is the current total bytes that have not been read. + // if the amount of unread bytes from the current sw pointer to the + // end of the buffer is greater than the current total bytes that + // have not been read, then set the "cnt" (unread bytes) to the + // amount of unread bytes. + + if (count_fr < cnt) + cnt = count_fr; + cnt_by = cnt * FRAME_SAMPLE_BYTES; + spin_unlock_irqrestore(&s->lock, flags); + // + // if we are converting from 8/16 then we need to copy + // twice the number of 16 bit bytes then 8 bit bytes. + // + if (s->conversion) { + if (cnt_by > (count * 2)) { + cnt = (count * 2) / FRAME_SAMPLE_BYTES; + cnt_by = count * 2; + } + } else { + if (cnt_by > count) { + cnt = count / FRAME_SAMPLE_BYTES; + cnt_by = count; + } + } + // + // "cnt" NOW is the smaller of the amount that will be read, + // and the amount that is requested in this read (or partial). + // if there are no bytes in the buffer to read, then start the + // ADC and wait for the interrupt handler to wake us up. + // + if (cnt <= 0) { + + // start up the dma engine and then continue back to the top of + // the loop when wake up occurs. + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->dma_adc.wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + // there are bytes in the buffer to read. + // copy from the hw buffer over to the user buffer. + // user buffer is designated by "buffer" + // virtual address to copy from is dma_buf+swptr + // the "cnt" is the number of bytes to read. + + CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO + "_read() copy_to cnt=%d count=%d ", cnt_by, count)); + CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO + " .sbufsz=%d .count=%d buffer=0x%.8x ret=%d\n", + s->dma_adc.sbufsz, s->dma_adc.count, + (unsigned) buffer, ret)); + + if (copy_to_user (buffer, ((void *)s->dma_adc.sb_swptr), cnt_by)) + return ret ? ret : -EFAULT; + copied = cnt_by; + + /* Return the descriptors */ + spin_lock_irqsave(&s->lock, flags); + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: upd_rcv sw->hw %x/%x\n", s->dma_adc.swptr, s->dma_adc.hwptr)); + s->dma_adc.count -= cnt_by; + s->dma_adc.sb_swptr += cnt * 2; + if (s->dma_adc.sb_swptr == s->dma_adc.sb_end) + s->dma_adc.sb_swptr = s->dma_adc.sample_buf; + spin_unlock_irqrestore(&s->lock, flags); + count -= copied; + buffer += copied; + ret += copied; + start_adc(s); + } + CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, + printk(KERN_INFO "cs4297a: cs4297a_read()- %d\n", ret)); + return ret; +} + + +static ssize_t cs4297a_write(struct file *file, const char *buffer, + size_t count, loff_t * ppos) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr, hwptr; + int cnt; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, + printk(KERN_INFO "cs4297a: cs4297a_write()+ count=%d\n", + count)); + VALIDATE_STATE(s); + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + serdma_t *d = &s->dma_dac; + int copy_cnt; + u32 *s_tmpl; + u32 *t_tmpl; + u32 left, right; + /* XXXKW check system endian here ... */ + int swap = (s->prop_dac.fmt == AFMT_S16_LE) || (s->prop_dac.fmt == AFMT_U16_LE); + + /* XXXXXX this is broken for BLOAT_FACTOR */ + spin_lock_irqsave(&s->lock, flags); + if (d->count < 0) { + d->count = 0; + d->swptr = d->hwptr; + } + if (d->underrun) { + d->underrun = 0; + hwptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - + d->descrtab_phys) / sizeof(serdma_descr_t)); + d->swptr = d->hwptr = hwptr; + } + swptr = d->swptr; + cnt = d->sbufsz - (swptr * FRAME_SAMPLE_BYTES); + /* Will this write fill up the buffer? */ + if (d->count + cnt > d->sbufsz) + cnt = d->sbufsz - d->count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&d->wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(d->sample_buf, buffer, cnt)) + return ret ? ret : -EFAULT; + + copy_cnt = cnt; + s_tmpl = (u32 *)d->sample_buf; + t_tmpl = (u32 *)(d->dma_buf + (swptr * 4)); + + /* XXXKW assuming 16-bit stereo! */ + do { + t_tmpl[0] = 0x98000000; + left = s_tmpl[0] >> 16; + if (left & 0x8000) + left |= 0xf0000; + right = s_tmpl[0] & 0xffff; + if (right & 0x8000) + right |= 0xf0000; + if (swap) { + t_tmpl[1] = left & 0xff; + t_tmpl[2] = ((left & 0xff00) << 16) | ((right & 0xff) << 12) | + ((right & 0xff00) >> 4); + } else { + t_tmpl[1] = left >> 8; + t_tmpl[2] = ((left & 0xff) << 24) | (right << 4); + } + s_tmpl++; + t_tmpl += 8; + copy_cnt -= 4; + } while (copy_cnt); + + /* Mux in any pending read/write accesses */ + if (s->reg_request) { + *(u64 *)(d->dma_buf + (swptr * 4)) |= s->reg_request; + s->reg_request = 0; + wake_up(&s->dma_dac.reg_wait); + } + + CS_DBGOUT(CS_WAVE_WRITE, 4, + printk(KERN_INFO + "cs4297a: copy in %d to swptr %x\n", cnt, swptr)); + + swptr = (swptr + (cnt/FRAME_SAMPLE_BYTES)) % d->ringsz; + out64(cnt/FRAME_SAMPLE_BYTES, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); + spin_lock_irqsave(&s->lock, flags); + d->swptr = swptr; + d->count += cnt; + d->endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, + printk(KERN_INFO "cs4297a: cs4297a_write()- %d\n", ret)); + return ret; +} + + +static unsigned int cs4297a_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + unsigned long flags; + unsigned int mask = 0; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO "cs4297a: cs4297a_poll()+\n")); + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) { + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO + "cs4297a: cs4297a_poll() wait on FMODE_WRITE\n")); + if(!s->dma_dac.ready && prog_dmabuf_dac(s)) + return 0; + poll_wait(file, &s->dma_dac.wait, wait); + } + if (file->f_mode & FMODE_READ) { + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO + "cs4297a: cs4297a_poll() wait on FMODE_READ\n")); + if(!s->dma_dac.ready && prog_dmabuf_adc(s)) + return 0; + poll_wait(file, &s->dma_adc.wait, wait); + } + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= + (signed) s->dma_dac.fragsize) { + if (s->dma_dac.wakeup) + mask |= POLLOUT | POLLWRNORM; + else + mask = 0; + s->dma_dac.wakeup = 0; + } + } else { + if ((signed) (s->dma_dac.sbufsz/2) >= s->dma_dac.count) + mask |= POLLOUT | POLLWRNORM; + } + } else if (file->f_mode & FMODE_READ) { + if (s->dma_adc.mapped) { + if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } else { + if (s->dma_adc.count > 0) + mask |= POLLIN | POLLRDNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO "cs4297a: cs4297a_poll()- 0x%.8x\n", + mask)); + return mask; +} + + +static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* XXXKW currently no mmap support */ + return -EINVAL; + return 0; +} + + +static int cs4297a_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + CS_DBGOUT(CS_FUNCTION|CS_IOCTL, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): file=0x%.8x cmd=0x%.8x\n", + (unsigned) file, cmd)); +#if CSDEBUG + cs_printioctl(cmd); +#endif + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + switch (cmd) { + case OSS_GETVERSION: + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): SOUND_VERSION=0x%.8x\n", + SOUND_VERSION)); + return put_user(SOUND_VERSION, (int *) arg); + + case SNDCTL_DSP_SYNC: + CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_SYNC\n")); + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, + 0 /*file->f_flags & O_NONBLOCK */ + ); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | + DSP_CAP_TRIGGER | DSP_CAP_MMAP, + (int *) arg); + + case SNDCTL_DSP_RESET: + CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_RESET\n")); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.count = s->dma_dac.total_bytes = + s->dma_dac.blocks = s->dma_dac.wakeup = 0; + s->dma_dac.swptr = s->dma_dac.hwptr = + (int)(((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - + s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.count = s->dma_adc.total_bytes = + s->dma_adc.blocks = s->dma_dac.wakeup = 0; + s->dma_adc.swptr = s->dma_adc.hwptr = + (int)(((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - + s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); + } + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, (int *) arg)) + return -EFAULT; + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_SPEED val=%d -> 48000\n", val)); + val = 48000; + return put_user(val, (int *) arg); + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *) arg)) + return -EFAULT; + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_STEREO val=%d\n", val)); + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + s->prop_adc.channels = val ? 2 : 1; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + s->prop_dac.channels = val ? 2 : 1; + } + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *) arg)) + return -EFAULT; + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_CHANNELS val=%d\n", + val)); + if (val != 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + s->prop_adc.channels = 2; + else + s->prop_adc.channels = 1; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + s->prop_dac.channels = 2; + else + s->prop_dac.channels = 1; + } + } + + if (file->f_mode & FMODE_WRITE) + val = s->prop_dac.channels; + else if (file->f_mode & FMODE_READ) + val = s->prop_adc.channels; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_GETFMTS: // Returns a mask + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_GETFMT val=0x%.8x\n", + AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | + AFMT_U8)); + return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | + AFMT_U8, (int *) arg); + + case SNDCTL_DSP_SETFMT: + if (get_user(val, (int *) arg)) + return -EFAULT; + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_SETFMT val=0x%.8x\n", + val)); + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val != AFMT_S16_LE + && val != AFMT_U16_LE && val != AFMT_S8 + && val != AFMT_U8) + val = AFMT_U8; + s->prop_adc.fmt = val; + s->prop_adc.fmt_original = s->prop_adc.fmt; + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val != AFMT_S16_LE + && val != AFMT_U16_LE && val != AFMT_S8 + && val != AFMT_U8) + val = AFMT_U8; + s->prop_dac.fmt = val; + s->prop_dac.fmt_original = s->prop_dac.fmt; + } + } else { + if (file->f_mode & FMODE_WRITE) + val = s->prop_dac.fmt_original; + else if (file->f_mode & FMODE_READ) + val = s->prop_adc.fmt_original; + } + CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_SETFMT return val=0x%.8x\n", + val)); + return put_user(val, (int *) arg); + + case SNDCTL_DSP_POST: + CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): DSP_POST\n")); + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & s->ena & FMODE_READ) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & s->ena & FMODE_WRITE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *) arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready + && (ret = prog_dmabuf_adc(s))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready + && (ret = prog_dmabuf_dac(s))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s))) + return val; + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + abinfo.fragsize = s->dma_dac.fragsize; + if (s->dma_dac.mapped) + abinfo.bytes = s->dma_dac.sbufsz; + else + abinfo.bytes = + s->dma_dac.sbufsz - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO + "cs4297a: cs4297a_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n", + abinfo.fragsize,abinfo.bytes,abinfo.fragstotal, + abinfo.fragments)); + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s))) + return val; + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + if (s->conversion) { + abinfo.fragsize = s->dma_adc.fragsize / 2; + abinfo.bytes = s->dma_adc.count / 2; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = + abinfo.bytes >> (s->dma_adc.fragshift - 1); + } else { + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = + abinfo.bytes >> s->dma_adc.fragshift; + } + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if(!s->dma_dac.ready && prog_dmabuf_dac(s)) + return 0; + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *) arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if(!s->dma_adc.ready && prog_dmabuf_adc(s)) + return 0; + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + cinfo.bytes = s->dma_adc.total_bytes; + if (s->dma_adc.mapped) { + cinfo.blocks = + (cinfo.bytes >> s->dma_adc.fragshift) - + s->dma_adc.blocks; + s->dma_adc.blocks = + cinfo.bytes >> s->dma_adc.fragshift; + } else { + if (s->conversion) { + cinfo.blocks = + s->dma_adc.count / + 2 >> (s->dma_adc.fragshift - 1); + } else + cinfo.blocks = + s->dma_adc.count >> s->dma_adc. + fragshift; + } + if (s->conversion) + cinfo.ptr = s->dma_adc.hwptr / 2; + else + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize - 1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if(!s->dma_dac.ready && prog_dmabuf_dac(s)) + return 0; + spin_lock_irqsave(&s->lock, flags); + cs4297a_update_ptr(s,CS_FALSE); + cinfo.bytes = s->dma_dac.total_bytes; + if (s->dma_dac.mapped) { + cinfo.blocks = + (cinfo.bytes >> s->dma_dac.fragshift) - + s->dma_dac.blocks; + s->dma_dac.blocks = + cinfo.bytes >> s->dma_dac.fragshift; + } else { + cinfo.blocks = + s->dma_dac.count >> s->dma_dac.fragshift; + } + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize - 1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf_dac(s))) + return val; + return put_user(s->dma_dac.fragsize, (int *) arg); + } + if ((val = prog_dmabuf_adc(s))) + return val; + if (s->conversion) + return put_user(s->dma_adc.fragsize / 2, + (int *) arg); + else + return put_user(s->dma_adc.fragsize, (int *) arg); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int *) arg)) + return -EFAULT; + return 0; // Say OK, but do nothing. + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) + || (file->f_mode & FMODE_WRITE + && s->dma_dac.subdivision)) return -EINVAL; + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + else if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + if (file->f_mode & FMODE_READ) + return put_user(s->prop_adc.rate, (int *) arg); + else if (file->f_mode & FMODE_WRITE) + return put_user(s->prop_dac.rate, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: + if (file->f_mode & FMODE_READ) + return put_user(s->prop_adc.channels, (int *) arg); + else if (file->f_mode & FMODE_WRITE) + return put_user(s->prop_dac.channels, (int *) arg); + + case SOUND_PCM_READ_BITS: + if (file->f_mode & FMODE_READ) + return + put_user( + (s->prop_adc. + fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, + (int *) arg); + else if (file->f_mode & FMODE_WRITE) + return + put_user( + (s->prop_dac. + fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, + (int *) arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return mixer_ioctl(s, cmd, arg); +} + + +static int cs4297a_release(struct inode *inode, struct file *file) +{ + struct cs4297a_state *s = + (struct cs4297a_state *) file->private_data; + + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO + "cs4297a: cs4297a_release(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", + (unsigned) inode, (unsigned) file, file->f_mode)); + VALIDATE_STATE(s); + + if (file->f_mode & FMODE_WRITE) { + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem_dac); + stop_dac(s); + dealloc_dmabuf(s, &s->dma_dac); + s->open_mode &= ~FMODE_WRITE; + up(&s->open_sem_dac); + wake_up(&s->open_wait_dac); + MOD_DEC_USE_COUNT; + } + if (file->f_mode & FMODE_READ) { + drain_adc(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem_adc); + stop_adc(s); + dealloc_dmabuf(s, &s->dma_adc); + s->open_mode &= ~FMODE_READ; + up(&s->open_sem_adc); + wake_up(&s->open_wait_adc); + MOD_DEC_USE_COUNT; + } + return 0; +} + +static int cs4297a_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs4297a_state *s=NULL; + struct list_head *entry; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs4297a: cs4297a_open(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", + (unsigned) inode, (unsigned) file, file->f_mode)); + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs4297a: status = %08x\n", (int)in64(SS_CSR(R_SER_STATUS_DEBUG)))); + + list_for_each(entry, &cs4297a_devs) + { + s = list_entry(entry, struct cs4297a_state, list); + + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } + if (entry == &cs4297a_devs) + return -ENODEV; + if (!s) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs4297a: cs4297a_open(): Error - unable to find audio state struct\n")); + return -ENODEV; + } + VALIDATE_STATE(s); + file->private_data = s; + + // wait for device to become free + if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO + "cs4297a: cs4297a_open(): Error - must open READ and/or WRITE\n")); + return -ENODEV; + } + if (file->f_mode & FMODE_WRITE) { + if (in64(SS_CSR(R_SER_DMA_DSCR_COUNT_TX)) != 0) { + printk(KERN_ERR "cs4297a: TX pipe needs to drain\n"); + while (in64(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) + ; + } + + down(&s->open_sem_dac); + while (s->open_mode & FMODE_WRITE) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem_dac); + return -EBUSY; + } + up(&s->open_sem_dac); + interruptible_sleep_on(&s->open_wait_dac); + + if (signal_pending(current)) { + printk("open - sig pending\n"); + return -ERESTARTSYS; + } + down(&s->open_sem_dac); + } + } + if (file->f_mode & FMODE_READ) { + down(&s->open_sem_adc); + while (s->open_mode & FMODE_READ) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem_adc); + return -EBUSY; + } + up(&s->open_sem_adc); + interruptible_sleep_on(&s->open_wait_adc); + + if (signal_pending(current)) { + printk("open - sig pending\n"); + return -ERESTARTSYS; + } + down(&s->open_sem_adc); + } + } + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + if (file->f_mode & FMODE_READ) { + s->prop_adc.fmt = AFMT_S16_BE; + s->prop_adc.fmt_original = s->prop_adc.fmt; + s->prop_adc.channels = 2; + s->prop_adc.rate = 48000; + s->conversion = 0; + s->ena &= ~FMODE_READ; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = + s->dma_adc.subdivision = 0; + up(&s->open_sem_adc); + MOD_INC_USE_COUNT; + + if (prog_dmabuf_adc(s)) { + CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR + "cs4297a: adc Program dmabufs failed.\n")); + cs4297a_release(inode, file); + return -ENOMEM; + } + } + if (file->f_mode & FMODE_WRITE) { + s->prop_dac.fmt = AFMT_S16_BE; + s->prop_dac.fmt_original = s->prop_dac.fmt; + s->prop_dac.channels = 2; + s->prop_dac.rate = 48000; + s->conversion = 0; + s->ena &= ~FMODE_WRITE; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = + s->dma_dac.subdivision = 0; + up(&s->open_sem_dac); + MOD_INC_USE_COUNT; + + if (prog_dmabuf_dac(s)) { + CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR + "cs4297a: dac Program dmabufs failed.\n")); + cs4297a_release(inode, file); + return -ENOMEM; + } + } + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, + printk(KERN_INFO "cs4297a: cs4297a_open()- 0\n")); + return 0; +} + + +// ****************************************************************************************** +// Wave (audio) file operations struct. +// ****************************************************************************************** +static /*const */ struct file_operations cs4297a_audio_fops = { + llseek:no_llseek, + read:cs4297a_read, + write:cs4297a_write, + poll:cs4297a_poll, + ioctl:cs4297a_ioctl, + mmap:cs4297a_mmap, + open:cs4297a_open, + release:cs4297a_release, +}; + +static void cs4297a_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cs4297a_state *s = (struct cs4297a_state *) dev_id; + u32 status; + + status = in64(SS_CSR(R_SER_STATUS_DEBUG)); + + CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO + "cs4297a: cs4297a_interrupt() HISR=0x%.8x\n", status)); + +#if 0 + /* XXXKW what check *should* be done here? */ + if (!(status & (M_SYNCSER_RX_EOP_COUNT | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_SYNC_ERR))) { + status = in64(SS_CSR(R_SER_STATUS)); + printk(KERN_ERR "cs4297a: unexpected interrupt (status %08x)\n", status); + return; + } +#endif + + if (status & M_SYNCSER_RX_SYNC_ERR) { + status = in64(SS_CSR(R_SER_STATUS)); + printk(KERN_ERR "cs4297a: rx sync error (status %08x)\n", status); + return; + } + + if (status & M_SYNCSER_RX_OVERRUN) { + int newptr, i; + s->stats.rx_ovrrn++; + printk(KERN_ERR "cs4297a: receive FIFO overrun\n"); + + /* Fix things up: get the receive descriptor pool + clean and give them back to the hardware */ + while (in64(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))) + ; + newptr = (unsigned) (((in64(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - + s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); + for (i=0; idma_adc.descrtab[i].descr_a &= ~M_DMA_SERRX_SOP; + } + s->dma_adc.swptr = s->dma_adc.hwptr = newptr; + s->dma_adc.count = 0; + s->dma_adc.sb_swptr = s->dma_adc.sb_hwptr = s->dma_adc.sample_buf; + out64(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); + } + + spin_lock(&s->lock); + cs4297a_update_ptr(s,CS_TRUE); + spin_unlock(&s->lock); + + CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO + "cs4297a: cs4297a_interrupt()-\n")); +} + +static struct initvol { + int mixch; + int vol; +} initvol[] __initdata = { + + {SOUND_MIXER_WRITE_VOLUME, 0x4040}, + {SOUND_MIXER_WRITE_PCM, 0x4040}, + {SOUND_MIXER_WRITE_SYNTH, 0x4040}, + {SOUND_MIXER_WRITE_CD, 0x4040}, + {SOUND_MIXER_WRITE_LINE, 0x4040}, + {SOUND_MIXER_WRITE_LINE1, 0x4040}, + {SOUND_MIXER_WRITE_RECLEV, 0x0000}, + {SOUND_MIXER_WRITE_SPEAKER, 0x4040}, + {SOUND_MIXER_WRITE_MIC, 0x0000} +}; + +static int __init cs4297a_init(void) +{ + struct cs4297a_state *s; + u64 cfg; + u32 pwr, id; + mm_segment_t fs; + int rval, mdio_val; + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs4297a: cs4297a_init_module()+ \n")); + + mdio_val = in64(KSEG1 + A_MAC_REGISTER(2, R_MAC_MDIO)) & + (M_MAC_MDIO_DIR|M_MAC_MDIO_OUT); + + /* Check syscfg for synchronous serial on port 1 */ + cfg = in64(KSEG1 + A_SCD_SYSTEM_CFG); + if (!(cfg & M_SYS_SER1_ENABLE)) { + out64(cfg | M_SYS_SER1_ENABLE, KSEG1+A_SCD_SYSTEM_CFG); + cfg = in64(KSEG1 + A_SCD_SYSTEM_CFG); + if (!(cfg & M_SYS_SER1_ENABLE)) { + printk(KERN_INFO "cs4297a: serial port 1 not configured for synchronous operation\n"); + return -1; + } + + printk(KERN_INFO "cs4297a: serial port 1 switching to synchronous operation\n"); + + /* Force the codec (on SWARM) to reset by clearing + GENO, preserving MDIO (no effect on CSWARM) */ + out64(mdio_val, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); + udelay(10); + } + + /* Now set GENO */ + out64(mdio_val | M_MAC_GENC, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); + /* Give the codec some time to finish resetting (start the bit clock) */ + udelay(100); + + if (!(s = kmalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4297a: probe() no memory for state struct.\n")); + return -1; + } + memset(s, 0, sizeof(struct cs4297a_state)); + s->magic = CS4297a_MAGIC; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->dma_adc.reg_wait); + init_waitqueue_head(&s->dma_dac.reg_wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->open_wait_adc); + init_waitqueue_head(&s->open_wait_dac); + init_MUTEX(&s->open_sem_adc); + init_MUTEX(&s->open_sem_dac); + spin_lock_init(&s->lock); + + s->irq = K_INT_SER_1; + + if (request_irq + (s->irq, cs4297a_interrupt, 0, "Crystal CS4297a", s)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4297a: irq %u in use\n", s->irq)); + goto err_irq; + } + if ((s->dev_audio = register_sound_dsp(&cs4297a_audio_fops, -1)) < + 0) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs4297a: probe() register_sound_dsp() failed.\n")); + goto err_dev1; + } + if ((s->dev_mixer = register_sound_mixer(&cs4297a_mixer_fops, -1)) < + 0) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs4297a: probe() register_sound_mixer() failed.\n")); + goto err_dev2; + } + + if (ser_init(s) || dma_init(s)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs4297a: ser_init failed.\n")); + goto err_dev3; + } + + do { + udelay(4000); + rval = cs4297a_read_ac97(s, AC97_POWER_CONTROL, &pwr); + } while (!rval && (pwr != 0xf)); + + if (!rval) { + fs = get_fs(); + set_fs(KERNEL_DS); +#if 0 + val = SOUND_MASK_LINE; + 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); + } +// cs4297a_write_ac97(s, 0x18, 0x0808); +#else + // cs4297a_write_ac97(s, 0x5e, 0x180); + cs4297a_write_ac97(s, 0x02, 0x0808); + cs4297a_write_ac97(s, 0x18, 0x0808); +#endif + set_fs(fs); + + list_add(&s->list, &cs4297a_devs); + + cs4297a_read_ac97(s, AC97_VENDOR_ID1, &id); + + printk(KERN_INFO "cs4297a: initialized (vendor id = %x)\n", id); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: cs4297a_init_module()-\n")); + + return 0; + } + + err_dev3: + unregister_sound_mixer(s->dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + free_irq(s->irq, s); + err_irq: + kfree(s); + + printk(KERN_INFO "cs4297a: initialization failed\n"); + + return -1; +} + +static void __exit cs4297a_cleanup(void) +{ + /* + XXXKW + disable_irq, free_irq + drain DMA queue + disable DMA + disable TX/RX + free memory + */ + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4297a: cleanup_cs4297a() finished\n")); +} + +// --------------------------------------------------------------------- + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Kip Walker, kwalker@broadcom.com"); +MODULE_DESCRIPTION("Cirrus Logic CS4297a Driver for Broadcom SWARM board"); + +// --------------------------------------------------------------------- + +module_init(cs4297a_init); +module_exit(cs4297a_cleanup); diff -urN linux-2.4.18/drivers/sound/trident.c linux-2.4.19-pre5/drivers/sound/trident.c --- linux-2.4.18/drivers/sound/trident.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/trident.c Sat Mar 30 22:55:40 2002 @@ -3813,7 +3813,7 @@ pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff); udelay(5000); - wCount = 200; + wCount = 2000; while(wCount--) { wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL); if((wReg & 0x000f) == 0x000f) diff -urN linux-2.4.18/drivers/sound/via82cxxx_audio.c linux-2.4.19-pre5/drivers/sound/via82cxxx_audio.c --- linux-2.4.18/drivers/sound/via82cxxx_audio.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/via82cxxx_audio.c Sat Mar 30 22:55:35 2002 @@ -354,8 +354,6 @@ static struct pci_device_id via_pci_tbl[] __initdata = { { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, - PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; MODULE_DEVICE_TABLE(pci,via_pci_tbl); @@ -2051,7 +2049,7 @@ while ((count > 0) && (chan->slop_len < chan->frag_size)) { size_t slop_left = chan->frag_size - chan->slop_len; void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr; - unsigned ofs = n % (PAGE_SIZE / chan->frag_size); + unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size; size = (count < slop_left) ? count : slop_left; if (copy_to_user (userbuf, diff -urN linux-2.4.18/drivers/sound/vwsnd.c linux-2.4.19-pre5/drivers/sound/vwsnd.c --- linux-2.4.18/drivers/sound/vwsnd.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/sound/vwsnd.c Sat Mar 30 22:55:40 2002 @@ -535,7 +535,7 @@ { unsigned long later = jiffies + 2; while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY) - if (jiffies >= later) + if (time_after_eq(jiffies, later)) return -EBUSY; return 0; } @@ -1358,7 +1358,7 @@ later = jiffies + HZ / 2; /* roughly half a second */ DBGDO(shut_up++); while (ad1843_read_bits(lith, &ad1843_PDNO)) { - if (jiffies > later) { + if (time_after(jiffies, later)) { printk(KERN_ERR "vwsnd audio: AD1843 won't power up\n"); return -EIO; diff -urN linux-2.4.18/drivers/sound/ymfpci.c linux-2.4.19-pre5/drivers/sound/ymfpci.c --- linux-2.4.18/drivers/sound/ymfpci.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/sound/ymfpci.c Sat Mar 30 22:55:29 2002 @@ -1,6 +1,8 @@ /* * Copyright 1999 Jaroslav Kysela * Copyright 2000 Alan Cox + * Copyright 2001 Kai Germaschewski + * Copyright 2002 Pete Zaitcev * * Yamaha YMF7xx driver. * @@ -37,9 +39,16 @@ * - Remove prog_dmabuf from read/write, leave it in open. * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with * native synthesizer through a playback slot. - * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus. - * - Make the thing big endian compatible. ALSA has it done. * - 2001/11/29 ac97_save_state + * Talk to Kai to remove ac97_save_state before it's too late! + * - Second AC97 + * - Restore S/PDIF - Toshibas have it. + * + * Kai used pci_alloc_consistent for DMA buffer, which sounds a little + * unconventional. However, given how small our fragments can be, + * a little uncached access is perhaps better than endless flushing. + * On i386 and other I/O-coherent architectures pci_alloc_consistent + * is entirely harmless. */ #include @@ -147,7 +156,7 @@ { signed long end_time; u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR; - + end_time = jiffies + 3 * (HZ / 4); do { if ((ymfpci_readw(codec, reg) & 0x8000) == 0) @@ -281,18 +290,22 @@ #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_MINORDER 1 -/* allocate DMA buffer, playback and recording buffer should be allocated seperately */ -static int alloc_dmabuf(struct ymf_dmabuf *dmabuf) +/* + * Allocate DMA buffer + */ +static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf) { void *rawbuf = NULL; + dma_addr_t dma_addr; int order; - struct page * map, * mapend; + struct page *map, *mapend; /* alloc as big a chunk as we can */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { + rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr); + if (rawbuf) break; - + } if (!rawbuf) return -ENOMEM; @@ -303,6 +316,7 @@ dmabuf->ready = dmabuf->mapped = 0; dmabuf->rawbuf = rawbuf; + dmabuf->dma_addr = dma_addr; dmabuf->buforder = order; /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ @@ -313,8 +327,10 @@ return 0; } -/* free DMA buffer */ -static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf) +/* + * Free DMA buffer + */ +static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf) { struct page *map, *mapend; @@ -323,7 +339,9 @@ mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &map->flags); - free_pages((unsigned long)dmabuf->rawbuf,dmabuf->buforder); + + pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_addr); } dmabuf->rawbuf = NULL; dmabuf->mapped = dmabuf->ready = 0; @@ -349,7 +367,7 @@ /* allocate DMA buffer if not allocated yet */ if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(dmabuf))) + if ((ret = alloc_dmabuf(state->unit, dmabuf))) return ret; /* @@ -589,7 +607,8 @@ if (ypcm->running) { YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n", voice->number, codec->active_bank, dmabuf->count, - voice->bank[0].start, voice->bank[1].start); + le32_to_cpu(voice->bank[0].start), + le32_to_cpu(voice->bank[1].start)); silence = (ymf_pcm_format_width(state->format.format) == 16) ? 0 : 0x80; /* We need actual left-hand-side redzone size here. */ @@ -597,7 +616,7 @@ redzone <<= (state->format.shift + 1); swptr = dmabuf->swptr; - pos = voice->bank[codec->active_bank].start; + pos = le32_to_cpu(voice->bank[codec->active_bank].start); pos <<= state->format.shift; if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n", @@ -700,7 +719,7 @@ redzone = ymf_calc_lend(state->format.rate); redzone <<= (state->format.shift + 1); - pos = cap->bank[unit->active_bank].start; + pos = le32_to_cpu(cap->bank[unit->active_bank].start); // pos <<= state->format.shift; if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n", @@ -744,9 +763,11 @@ return -EINVAL; } if (cmd != 0) { - codec->ctrl_playback[ypcm->voices[0]->number + 1] = virt_to_bus(ypcm->voices[0]->bank); + codec->ctrl_playback[ypcm->voices[0]->number + 1] = + cpu_to_le32(ypcm->voices[0]->bank_ba); if (ypcm->voices[1] != NULL) - codec->ctrl_playback[ypcm->voices[1]->number + 1] = virt_to_bus(ypcm->voices[1]->bank); + codec->ctrl_playback[ypcm->voices[1]->number + 1] = + cpu_to_le32(ypcm->voices[1]->bank_ba); ypcm->running = 1; } else { codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0; @@ -813,6 +834,14 @@ ymfpci_playback_bank_t *bank; int nbank; + /* + * The gain is a floating point number. According to the manual, + * bit 31 indicates a sign bit, bit 30 indicates an integer part, + * and bits [29:15] indicate a decimal fraction part. Thus, + * for a gain of 1.0 the constant of 0x40000000 is loaded. + */ + unsigned default_gain = cpu_to_le32(0x40000000); + format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000); if (stereo) end >>= 1; @@ -820,24 +849,24 @@ end >>= 1; for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; - bank->format = format; + bank->format = cpu_to_le32(format); bank->loop_default = 0; /* 0-loops forever, otherwise count */ - bank->base = addr; + bank->base = cpu_to_le32(addr); bank->loop_start = 0; - bank->loop_end = end; + bank->loop_end = cpu_to_le32(end); bank->loop_frac = 0; - bank->eg_gain_end = 0x40000000; - bank->lpfQ = lpfQ; + bank->eg_gain_end = default_gain; + bank->lpfQ = cpu_to_le32(lpfQ); bank->status = 0; bank->num_of_frames = 0; bank->loop_count = 0; bank->start = 0; bank->start_frac = 0; bank->delta = - bank->delta_end = delta; + bank->delta_end = cpu_to_le32(delta); bank->lpfK = - bank->lpfK_end = lpfK; - bank->eg_gain = 0x40000000; + bank->lpfK_end = cpu_to_le32(lpfK); + bank->eg_gain = default_gain; bank->lpfD1 = bank->lpfD2 = 0; @@ -857,31 +886,31 @@ bank->left_gain = bank->right_gain = bank->left_gain_end = - bank->right_gain_end = 0x40000000; + bank->right_gain_end = default_gain; } else { bank->eff2_gain = bank->eff2_gain_end = bank->eff3_gain = - bank->eff3_gain_end = 0x40000000; + bank->eff3_gain_end = default_gain; } } else { if (!spdif) { if ((voice->number & 1) == 0) { bank->left_gain = - bank->left_gain_end = 0x40000000; + bank->left_gain_end = default_gain; } else { - bank->format |= 1; + bank->format |= cpu_to_le32(1); bank->right_gain = - bank->right_gain_end = 0x40000000; + bank->right_gain_end = default_gain; } } else { if ((voice->number & 1) == 0) { bank->eff2_gain = - bank->eff2_gain_end = 0x40000000; + bank->eff2_gain_end = default_gain; } else { - bank->format |= 1; + bank->format |= cpu_to_le32(1); bank->eff3_gain = - bank->eff3_gain_end = 0x40000000; + bank->eff3_gain_end = default_gain; } } } @@ -922,7 +951,7 @@ ymf_pcm_init_voice(ypcm->voices[nvoice], state->format.voices == 2, state->format.rate, ymf_pcm_format_width(state->format.format) == 16, - virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize, + ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize, ypcm->spdif); } return 0; @@ -971,9 +1000,9 @@ } for (nbank = 0; nbank < 2; nbank++) { bank = unit->bank_capture[ypcm->capture_bank_number][nbank]; - bank->base = virt_to_bus(ypcm->dmabuf.rawbuf); + bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr); // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift; - bank->loop_end = ypcm->dmabuf.dmasize; + bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize); bank->start = 0; bank->num_of_loops = 0; } @@ -1810,9 +1839,9 @@ cinfo.ptr, cinfo.bytes); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */ + case SNDCTL_DSP_SETDUPLEX: YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd); - return -EINVAL; + return 0; /* Always duplex */ case SOUND_PCM_READ_RATE: YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd); @@ -1839,6 +1868,7 @@ * Some programs mix up audio devices and ioctls * or perhaps they expect "universal" ioctls, * for instance we get SNDCTL_TMR_CONTINUE here. + * (mpg123 -g 100 ends here too - to be fixed.) */ YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd); break; @@ -1923,8 +1953,8 @@ * a nestable exception, but here it is not nestable due to semaphore. * XXX Doubtful technique of self-describing objects.... */ - dealloc_dmabuf(&state->wpcm.dmabuf); - dealloc_dmabuf(&state->rpcm.dmabuf); + dealloc_dmabuf(unit, &state->wpcm.dmabuf); + dealloc_dmabuf(unit, &state->rpcm.dmabuf); ymf_pcm_free_substream(&state->wpcm); ymf_pcm_free_substream(&state->rpcm); @@ -1952,8 +1982,8 @@ */ ymf_wait_dac(state); ymf_stop_adc(state); /* fortunately, it's immediate */ - dealloc_dmabuf(&state->wpcm.dmabuf); - dealloc_dmabuf(&state->rpcm.dmabuf); + dealloc_dmabuf(unit, &state->wpcm.dmabuf); + dealloc_dmabuf(unit, &state->rpcm.dmabuf); ymf_pcm_free_substream(&state->wpcm); ymf_pcm_free_substream(&state->rpcm); @@ -2043,11 +2073,6 @@ unit->suspended = 1; - /* - * XXX Talk to Kai to remove ac97_save_state before it's too late! - * Other drivers call ac97_reset, which does not have - * a save counterpart. Current ac97_save_state is empty. - */ for (i = 0; i < NR_AC97; i++) { if ((codec = unit->ac97_codec[i]) != NULL) ac97_save_state(codec); @@ -2288,29 +2313,39 @@ static int ymfpci_memalloc(ymfpci_t *codec) { - long size, playback_ctrl_size; + unsigned int playback_ctrl_size; + unsigned int bank_size_playback; + unsigned int bank_size_capture; + unsigned int bank_size_effect; + unsigned int size; + unsigned int off; + char *ptr; + dma_addr_t pba; int voice, bank; - u8 *ptr; playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES; - codec->bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2; - codec->bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2; - codec->bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2; + bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2; + bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2; + bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2; codec->work_size = YDSXG_DEFAULT_WORK_SIZE; size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) + - ((codec->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) + - ((codec->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) + - ((codec->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) + + ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) + + ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) + + ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) + codec->work_size; - ptr = (u8 *)kmalloc(size + 0x00ff, GFP_KERNEL); + ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba); if (ptr == NULL) return -ENOMEM; - - codec->work_ptr = ptr; - ptr += 0x00ff; - (long)ptr &= ~0x00ff; + codec->dma_area_va = ptr; + codec->dma_area_ba = pba; + codec->dma_area_size = size + 0xff; + + if ((off = ((uint) ptr) & 0xff) != 0) { + ptr += 0x100 - off; + pba += 0x100 - off; + } /* * Hardware requires only ptr[playback_ctrl_size] zeroed, @@ -2318,34 +2353,49 @@ */ memset(ptr, 0, size); - codec->bank_base_playback = ptr; codec->ctrl_playback = (u32 *)ptr; - codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES; + codec->ctrl_playback_ba = pba; + codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES); ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff; + pba += (playback_ctrl_size + 0x00ff) & ~0x00ff; + + off = 0; for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) { - for (bank = 0; bank < 2; bank++) { - codec->bank_playback[voice][bank] = (ymfpci_playback_bank_t *)ptr; - ptr += codec->bank_size_playback; - } codec->voices[voice].number = voice; - codec->voices[voice].bank = codec->bank_playback[voice][0]; - } - ptr += (codec->bank_size_playback + 0x00ff) & ~0x00ff; - codec->bank_base_capture = ptr; + codec->voices[voice].bank = + (ymfpci_playback_bank_t *) (ptr + off); + codec->voices[voice].bank_ba = pba + off; + off += 2 * bank_size_playback; /* 2 banks */ + } + off = (off + 0xff) & ~0xff; + ptr += off; + pba += off; + + off = 0; + codec->bank_base_capture = pba; for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++) for (bank = 0; bank < 2; bank++) { - codec->bank_capture[voice][bank] = (ymfpci_capture_bank_t *)ptr; - ptr += codec->bank_size_capture; - } - ptr += (codec->bank_size_capture + 0x00ff) & ~0x00ff; - codec->bank_base_effect = ptr; + codec->bank_capture[voice][bank] = + (ymfpci_capture_bank_t *) (ptr + off); + off += bank_size_capture; + } + off = (off + 0xff) & ~0xff; + ptr += off; + pba += off; + + off = 0; + codec->bank_base_effect = pba; for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++) for (bank = 0; bank < 2; bank++) { - codec->bank_effect[voice][bank] = (ymfpci_effect_bank_t *)ptr; - ptr += codec->bank_size_effect; - } - ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff; - codec->work_base = ptr; + codec->bank_effect[voice][bank] = + (ymfpci_effect_bank_t *) (ptr + off); + off += bank_size_effect; + } + off = (off + 0xff) & ~0xff; + ptr += off; + pba += off; + + codec->work_base = pba; return 0; } @@ -2357,16 +2407,17 @@ ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0); ymfpci_writel(codec, YDSXGR_WORKBASE, 0); ymfpci_writel(codec, YDSXGR_WORKSIZE, 0); - kfree(codec->work_ptr); + pci_free_consistent(codec->pci, + codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba); } static void ymf_memload(ymfpci_t *unit) { - ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback)); - ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture)); - ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect)); - ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base)); + ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba); + ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture); + ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect); + ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base); ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2); /* S/PDIF output initialization */ @@ -2531,7 +2582,7 @@ codec->opl3_data.irq = -1; codec->mpu_data.io_base = codec->iomidi; - codec->mpu_data.irq = -1; /* XXX Make it ours. */ + codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */ if (codec->iomidi) { if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) { diff -urN linux-2.4.18/drivers/sound/ymfpci.h linux-2.4.19-pre5/drivers/sound/ymfpci.h --- linux-2.4.18/drivers/sound/ymfpci.h Mon Feb 18 06:29:57 2002 +++ linux-2.4.19-pre5/drivers/sound/ymfpci.h Sat Mar 30 22:55:29 2002 @@ -227,6 +227,7 @@ char use, pcm, synth, midi; // bool ymfpci_playback_bank_t *bank; struct ymf_pcm *ypcm; + dma_addr_t bank_ba; }; struct ymf_capture { @@ -239,19 +240,17 @@ struct ymf_unit { u8 rev; /* PCI revision */ void *reg_area_virt; - void *work_ptr; - - unsigned int bank_size_playback; - unsigned int bank_size_capture; - unsigned int bank_size_effect; + void *dma_area_va; + dma_addr_t dma_area_ba; + unsigned int dma_area_size; + + dma_addr_t bank_base_capture; + dma_addr_t bank_base_effect; + dma_addr_t work_base; unsigned int work_size; - void *bank_base_playback; - void *bank_base_capture; - void *bank_base_effect; - void *work_base; - u32 *ctrl_playback; + dma_addr_t ctrl_playback_ba; ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2]; ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2]; ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2]; @@ -286,10 +285,11 @@ }; struct ymf_dmabuf { - - /* OSS buffer management stuff */ + dma_addr_t dma_addr; void *rawbuf; unsigned buforder; + + /* OSS buffer management stuff */ unsigned numfrag; unsigned fragshift; diff -urN linux-2.4.18/drivers/tc/lk201.c linux-2.4.19-pre5/drivers/tc/lk201.c --- linux-2.4.18/drivers/tc/lk201.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/tc/lk201.c Sat Mar 30 22:55:29 2002 @@ -4,13 +4,22 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (C) 2001 Maciej W. Rozycki */ + +#include + #include +#include #include #include #include #include #include +#include +#include + +#include #include #include #include @@ -27,6 +36,8 @@ */ unsigned char lk201_sysrq_xlate[128]; unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate; + +unsigned char kbd_sysrq_key = -1; #endif #define KEYB_LINE 3 @@ -71,6 +82,8 @@ LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf) }; +static struct dec_serial* lk201kbd_info; + static int __init lk201_reset(struct dec_serial *info) { int i; @@ -83,9 +96,115 @@ return 0; } +#define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */ +#define DEFAULT_KEYB_REP_RATE 30 /* [cps] */ + +static struct kbd_repeat kbdrate = { + DEFAULT_KEYB_REP_DELAY, + DEFAULT_KEYB_REP_RATE +}; + +static void parse_kbd_rate(struct kbd_repeat *r) +{ + if (r->delay <= 0) + r->delay = kbdrate.delay; + if (r->rate <= 0) + r->rate = kbdrate.rate; + + if (r->delay < 5) + r->delay = 5; + if (r->delay > 630) + r->delay = 630; + if (r->rate < 12) + r->rate = 12; + if (r->rate > 127) + r->rate = 127; + if (r->rate == 125) + r->rate = 124; +} + +static int write_kbd_rate(struct kbd_repeat *rep) +{ + struct dec_serial* info = lk201kbd_info; + int delay, rate; + int i; + + delay = rep->delay / 5; + rate = rep->rate; + for (i = 0; i < 4; i++) { + if (info->hook->poll_tx_char(info, LK_CMD_RPT_RATE(i))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_DELAY(delay))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_RATE(rate))) + return 1; + } + return 0; +} + +static int lk201kbd_rate(struct kbd_repeat *rep) +{ + if (rep == NULL) + return -EINVAL; + + parse_kbd_rate(rep); + + if (write_kbd_rate(rep)) { + memcpy(rep, &kbdrate, sizeof(struct kbd_repeat)); + return -EIO; + } + + memcpy(&kbdrate, rep, sizeof(struct kbd_repeat)); + + return 0; +} + +static void lk201kd_mksound(unsigned int hz, unsigned int ticks) +{ + struct dec_serial* info = lk201kbd_info; + + if (!ticks) + return; + + /* + * Can't set frequency and we "approximate" + * duration by volume. ;-) + */ + ticks /= HZ / 32; + if (ticks > 7) + ticks = 7; + ticks = 7 - ticks; + + if (info->hook->poll_tx_char(info, LK_CMD_ENB_BELL)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_VOLUME(ticks))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_BELL)) + return; +} + void kbd_leds(unsigned char leds) { - return; + struct dec_serial* info = lk201kbd_info; + unsigned char l = 0; + + if (!info) /* FIXME */ + return; + + /* FIXME -- Only Hold and Lock LEDs for now. --macro */ + if (leds & LED_SCR) + l |= LK_LED_HOLD; + if (leds & LED_CAP) + l |= LK_LED_LOCK; + + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_ON)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(l))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_OFF)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(~l))) + return; } int kbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -118,7 +237,12 @@ if (!stat || stat == 4) { switch (ch) { - case LK_KEY_ACK: + case LK_STAT_RESUME_ERR: + case LK_STAT_ERROR: + case LK_STAT_INHIBIT_ACK: + case LK_STAT_TEST_ACK: + case LK_STAT_MODE_KEYDOWN: + case LK_STAT_MODE_ACK: break; case LK_KEY_LOCK: shift_state ^= LK_LOCK; @@ -157,6 +281,7 @@ } } else printk("Error reading LKx01 keyboard: 0x%02x\n", stat); + tasklet_schedule(&keyboard_tasklet); } static void __init lk201_info(struct dec_serial *info) @@ -200,6 +325,10 @@ */ info->hook->rx_char = lk201_kbd_rx_char; + lk201kbd_info = info; + kbd_rate = lk201kbd_rate; + kd_mksound = lk201kd_mksound; + return 0; } @@ -231,7 +360,3 @@ printk("LK201 Support for DS3100 not yet ready ...\n"); } } - - - - diff -urN linux-2.4.18/drivers/tc/lk201.h linux-2.4.19-pre5/drivers/tc/lk201.h --- linux-2.4.18/drivers/tc/lk201.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/tc/lk201.h Sat Mar 30 22:55:29 2002 @@ -2,52 +2,121 @@ * Commands to the keyboard processor */ -#define LK_PARAM 0x80 /* start/end parameter list */ +#define LK_PARAM 0x80 /* start/end parameter list */ -#define LK_CMD_RESUME 0x8b -#define LK_CMD_INHIBIT 0xb9 -#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */ -#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */ -#define LK_CMD_DIS_KEYCLK 0x99 -#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */ -#define LK_CMD_DIS_CTLCLK 0xb9 -#define LK_CMD_ENB_CTLCLK 0xbb -#define LK_CMD_SOUND_CLK 0x9f -#define LK_CMD_DIS_BELL 0xa1 -#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */ -#define LK_CMD_BELL 0xa7 -#define LK_CMD_TMP_NORPT 0xc1 -#define LK_CMD_ENB_RPT 0xe3 -#define LK_CMD_DIS_RPT 0xe1 -#define LK_CMD_RPT_TO_DOWN 0xd9 -#define LK_CMD_REQ_ID 0xab -#define LK_CMD_POWER_UP 0xfd -#define LK_CMD_TEST_MODE 0xcb -#define LK_CMD_SET_DEFAULTS 0xd3 +#define LK_CMD_RESUME 0x8b /* resume transmission to the host */ +#define LK_CMD_INHIBIT 0x89 /* stop transmission to the host */ +#define LK_CMD_LEDS_ON 0x13 /* light LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */ +#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick */ + /* 1st param: volume */ +#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */ +#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */ +#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick */ +#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */ +#define LK_CMD_ENB_BELL 0x23 /* enable the bell */ + /* 1st param: volume */ +#define LK_CMD_BELL 0xa7 /* emit a bell */ +#define LK_CMD_TMP_NORPT 0xc1 /* disable typematic */ + /* for the currently pressed key */ +#define LK_CMD_ENB_RPT 0xe3 /* enable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_DIS_RPT 0xe1 /* disable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_RPT_TO_DOWN 0xd9 /* set RPT_DOWN groups to DOWN */ +#define LK_CMD_REQ_ID 0xab /* request the keyboard ID */ +#define LK_CMD_POWER_UP 0xfd /* init power-up sequence */ +#define LK_CMD_TEST_MODE 0xcb /* enter the factory test mode */ +#define LK_CMD_TEST_EXIT 0x80 /* exit the factory test mode */ +#define LK_CMD_SET_DEFAULTS 0xd3 /* set power-up defaults */ + +#define LK_CMD_MODE(m,div) (LK_PARAM|(((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* for the selected key group */ +#define LK_CMD_MODE_AR(m,div) ((((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* and the repeat register */ + /* for the selected key group */ + /* 1st param: register number */ +#define LK_CMD_RPT_RATE(r) (0x04|((((r)&0x3)<<1))) + /* set the delay and repeat rate */ + /* for the selected repeat register */ + /* 1st param: initial delay */ + /* 2nd param: repeat rate */ /* there are 4 leds, represent them in the low 4 bits of a byte */ -#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|(ledbmap)) +#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|((ledbmap)&0xf)) +#define LK_LED_WAIT 0x1 /* Wait LED */ +#define LK_LED_COMP 0x2 /* Compose LED */ +#define LK_LED_LOCK 0x4 /* Lock LED */ +#define LK_LED_HOLD 0x8 /* Hold Screen LED */ /* max volume is 0, lowest is 0x7 */ -#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) +#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) -/* mode set command(s) details */ -#define LK_MODE_DOWN 0x0 -#define LK_MODE_RPT_DOWN 0x2 -#define LK_MODE_DOWN_UP 0x6 -#define LK_CMD_MODE(m,div) (LK_PARAM|(div<<3)|m) +/* mode set command details, div is a key group number */ +#define LK_MODE_DOWN 0x0 /* make only */ +#define LK_MODE_RPT_DOWN 0x2 /* make and typematic */ +#define LK_MODE_DOWN_UP 0x6 /* make and release */ + +/* there are 4 repeat registers */ +#define LK_PARAM_AR(r) (LK_PARAM|((v)&0x3)) + +/* + * Mappings between key groups and keycodes are as follows: + * + * 1: 0xbf - 0xfb -- alphanumeric, + * 2: 0x92 - 0xa4 -- numeric keypad, + * 3: 0xbc -- Backspace, + * 4: 0xbd - 0xbe -- Tab, Return, + * 5: 0xb0 - 0xb1 -- Lock, Compose Character, + * 6: 0xae - 0xaf -- Ctrl, Shift, + * 7: 0xa7 - 0xa8 -- Left Arrow, Right Arrow, + * 8: 0xa9 - 0xab -- Up Arrow, Down Arrow, Right Shift, + * 9: 0x8a - 0x8f -- editor keypad, + * 10: 0x56 - 0x5a -- F1 - F5, + * 11: 0x64 - 0x68 -- F6 - F10, + * 12: 0x71 - 0x74 -- F11 - F14, + * 13: 0x7c - 0x7d -- Help, Do, + * 14: 0x80 - 0x83 -- F17 - F20. + * + * Others, i.e. 0x55, 0xac, 0xad, 0xb2, are undiscovered. + */ + +/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */ +#define LK_PARAM_DELAY(t) ((t)&0x7f) + +/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */ +#define LK_PARAM_RATE(r) (LK_PARAM|((r)&0x7f)) #define LK_SHIFT 1<<0 #define LK_CTRL 1<<1 #define LK_LOCK 1<<2 #define LK_COMP 1<<3 -#define LK_KEY_SHIFT 174 -#define LK_KEY_CTRL 175 -#define LK_KEY_LOCK 176 -#define LK_KEY_COMP 177 -#define LK_KEY_RELEASE 179 -#define LK_KEY_REPEAT 180 -#define LK_KEY_ACK 186 +#define LK_KEY_SHIFT 0xae +#define LK_KEY_CTRL 0xaf +#define LK_KEY_LOCK 0xb0 +#define LK_KEY_COMP 0xb1 + +#define LK_KEY_RELEASE 0xb3 /* all keys released */ +#define LK_KEY_REPEAT 0xb4 /* repeat the last key */ + +/* status responses */ +#define LK_STAT_RESUME_ERR 0xb5 /* keystrokes lost while inhibited */ +#define LK_STAT_ERROR 0xb6 /* an invalid command received */ +#define LK_STAT_INHIBIT_ACK 0xb7 /* transmission inhibited */ +#define LK_STAT_TEST_ACK 0xb8 /* the factory test mode entered */ +#define LK_STAT_MODE_KEYDOWN 0xb9 /* a key is down on a change */ + /* to the DOWN_UP mode; */ + /* the keycode follows */ +#define LK_STAT_MODE_ACK 0xba /* the mode command succeeded */ + +#define LK_STAT_PWRUP_OK 0x00 /* the power-up self test OK */ +#define LK_STAT_PWRUP_KDOWN 0x3d /* a key was down during the test */ +#define LK_STAT_PWRUP_ERROR 0x3e /* keyboard self test failure */ -extern unsigned char scancodeRemap[256]; \ No newline at end of file +extern unsigned char scancodeRemap[256]; diff -urN linux-2.4.18/drivers/tc/zs.c linux-2.4.19-pre5/drivers/tc/zs.c --- linux-2.4.18/drivers/tc/zs.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/tc/zs.c Sat Mar 30 22:55:29 2002 @@ -1473,7 +1473,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING; @@ -1925,9 +1925,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); diff -urN linux-2.4.18/drivers/telephony/Config.in linux-2.4.19-pre5/drivers/telephony/Config.in --- linux-2.4.18/drivers/telephony/Config.in Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/telephony/Config.in Sat Mar 30 22:55:40 2002 @@ -6,5 +6,5 @@ tristate 'Linux telephony support' CONFIG_PHONE dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE -dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ +dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ $CONFIG_PCMCIA endmenu diff -urN linux-2.4.18/drivers/telephony/ixj.c linux-2.4.19-pre5/drivers/telephony/ixj.c --- linux-2.4.18/drivers/telephony/ixj.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/telephony/ixj.c Sat Mar 30 22:55:29 2002 @@ -387,7 +387,7 @@ #ifdef PERFMON_STATS #define ixj_perfmon(x) ((x)++) #else -#define ixj_perfmon(x) do {} while(0); +#define ixj_perfmon(x) do { } while(0) #endif static int ixj_convert_loaded; @@ -3451,7 +3451,7 @@ j->cidcw_wait = 0; if(!j->flags.cidcw_ack) { if(ixjdebug & 0x0200) { - printk("IXJ cidcw phone%d did not recieve ACK from display %ld\n", j->board, jiffies); + printk("IXJ cidcw phone%d did not receive ACK from display %ld\n", j->board, jiffies); } ixj_post_cid(j); if(j->cid_play_flag) { diff -urN linux-2.4.18/drivers/usb/Config.in linux-2.4.19-pre5/drivers/usb/Config.in --- linux-2.4.18/drivers/usb/Config.in Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/Config.in Sat Mar 30 22:55:35 2002 @@ -8,7 +8,7 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then bool ' USB verbose debug messages' CONFIG_USB_DEBUG -comment 'Miscellaneous USB options' + comment 'Miscellaneous USB options' bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH @@ -16,87 +16,89 @@ define_bool CONFIG_USB_BANDWIDTH n fi bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT -fi -comment 'USB Controllers' -if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then - dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB -fi -if [ "$CONFIG_USB_UHCI" != "y" ]; then - dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB -else - define_bool CONFIG_USB_UHCI_ALT n -fi -dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB - -comment 'USB Device Class drivers' -dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND -dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL -if [ "$CONFIG_SCSI" = "n" ]; then - comment ' SCSI support is needed for USB Storage' -fi -dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI - dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE - dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE - dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE - dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE - dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL - dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL -dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB -dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB - -comment 'USB Human Interface Devices (HID)' -if [ "$CONFIG_INPUT" = "n" ]; then - comment ' Input core support is needed for USB HID' -else - dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT - dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID - if [ "$CONFIG_USB_HID" != "y" ]; then - dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT - dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT + comment 'USB Host Controller Drivers' + source drivers/usb/hcd/Config.in + if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then + dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB fi - dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT -fi - -comment 'USB Imaging devices' -dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB -dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL -dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB -dep_tristate ' Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI -dep_tristate ' HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL - -comment 'USB Multimedia devices' -if [ "$CONFIG_VIDEO_DEV" = "n" ]; then - comment ' Video4Linux support is needed for USB Multimedia device support' -else - dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL - dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL - dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB -fi + if [ "$CONFIG_USB_UHCI" != "y" ]; then + dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB + else + define_bool CONFIG_USB_UHCI_ALT n + fi + dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB -comment 'USB Network adaptors' -if [ "$CONFIG_NET" = "n" ]; then - comment ' Networking support is needed for USB Networking device support' -else - dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL - dep_tristate ' USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL -fi + comment 'USB Device Class drivers' + dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND + dep_tristate ' EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO + dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL + if [ "$CONFIG_SCSI" = "n" ]; then + comment ' SCSI support is needed for USB Storage' + fi + dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI + dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE + dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE + dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE + dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE + dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL + dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB + dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB + + comment 'USB Human Interface Devices (HID)' + if [ "$CONFIG_INPUT" = "n" ]; then + comment ' Input core support is needed for USB HID' + else + dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT + dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT + dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT + fi + dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT + fi -comment 'USB port drivers' -dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT -source drivers/usb/serial/Config.in + comment 'USB Imaging devices' + dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB + dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB + dep_tristate ' Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI + dep_tristate ' HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL + + comment 'USB Multimedia devices' + if [ "$CONFIG_VIDEO_DEV" = "n" ]; then + comment ' Video4Linux support is needed for USB Multimedia device support' + else + dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL + dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL + dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB + fi -comment 'USB Miscellaneous drivers' -dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL + comment 'USB Network adaptors' + if [ "$CONFIG_NET" = "n" ]; then + comment ' Networking support is needed for USB Networking device support' + else + dep_tristate ' USB Pegasus/Pegasus-II based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + fi + comment 'USB port drivers' + dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT + source drivers/usb/serial/Config.in + + comment 'USB Miscellaneous drivers' + dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL +fi endmenu diff -urN linux-2.4.18/drivers/usb/Makefile linux-2.4.19-pre5/drivers/usb/Makefile --- linux-2.4.18/drivers/usb/Makefile Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/Makefile Sat Mar 30 22:55:35 2002 @@ -40,10 +40,22 @@ # Each configuration option enables a list of files. obj-$(CONFIG_USB) += usbcore.o + +# EHCI should initialize/link before the other HCDs +ifeq ($(CONFIG_USB_EHCI_HCD),y) + obj-y += hcd/ehci-hcd.o +endif + obj-$(CONFIG_USB_UHCI) += usb-uhci.o obj-$(CONFIG_USB_UHCI_ALT) += uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o +ifneq ($(CONFIG_EHCI_HCD),n) + usbcore-objs += hcd.o + export-objs += hcd.o +endif +subdir-$(CONFIG_USB_EHCI_HCD) += hcd + obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_HID) += hid.o obj-$(CONFIG_USB_KBD) += usbkbd.o @@ -53,6 +65,7 @@ obj-$(CONFIG_USB_ACM) += acm.o obj-$(CONFIG_USB_PRINTER) += printer.o obj-$(CONFIG_USB_AUDIO) += audio.o +obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_DC2XX) += dc2xx.o @@ -73,9 +86,10 @@ obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o obj-$(CONFIG_USB_USBNET) += usbnet.o +obj-$(CONFIG_USB_AUERSWALD) += auerswald.o # Object files in subdirectories -mod-subdirs := serial +mod-subdirs := serial hcd subdir-$(CONFIG_USB_SERIAL) += serial subdir-$(CONFIG_USB_STORAGE) += storage diff -urN linux-2.4.18/drivers/usb/auerswald.c linux-2.4.19-pre5/drivers/usb/auerswald.c --- linux-2.4.18/drivers/usb/auerswald.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/auerswald.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,2196 @@ +/*****************************************************************************/ +/* + * auerswald.c -- Auerswald PBX/System Telephone usb driver. + * + * Copyright (C) 2001 Wolfgang Mües (wmues@nexgo.de) + * + * Very much code of this driver is borrowed from dabusb.c (Deti Fliegl) + * and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + /*****************************************************************************/ + +/* Standard Linux module include files */ +#include +#include +#include +#include +#include +#undef DEBUG /* include debug macros until it's done */ +#include + +/*-------------------------------------------------------------------*/ +/* Debug support */ +#ifdef DEBUG +#define dump( adr, len) \ +do { \ + unsigned int u; \ + printk (KERN_DEBUG); \ + for (u = 0; u < len; u++) \ + printk (" %02X", adr[u] & 0xFF); \ + printk ("\n"); \ +} while (0) +#else +#define dump( adr, len) +#endif + +/*-------------------------------------------------------------------*/ +/* Version Information */ +#define DRIVER_VERSION "0.9.11" +#define DRIVER_AUTHOR "Wolfgang Mües " +#define DRIVER_DESC "Auerswald PBX/System Telephone usb driver" + +/*-------------------------------------------------------------------*/ +/* Private declarations for Auerswald USB driver */ + +/* Auerswald Vendor ID */ +#define ID_AUERSWALD 0x09BF + +#ifndef AUER_MINOR_BASE /* allow external override */ +#define AUER_MINOR_BASE 112 /* auerswald driver minor number */ +#endif + +/* we can have up to this number of device plugged in at once */ +#define AUER_MAX_DEVICES 16 + +/* prefix for the device descriptors in /dev/usb */ +#define AU_PREFIX "auer" + +/* Number of read buffers for each device */ +#define AU_RBUFFERS 10 + +/* Number of chain elements for each control chain */ +#define AUCH_ELEMENTS 20 + +/* Number of retries in communication */ +#define AU_RETRIES 10 + +/*-------------------------------------------------------------------*/ +/* vendor specific protocol */ +/* Header Byte */ +#define AUH_INDIRMASK 0x80 /* mask for direct/indirect bit */ +#define AUH_DIRECT 0x00 /* data is for USB device */ +#define AUH_INDIRECT 0x80 /* USB device is relay */ + +#define AUH_SPLITMASK 0x40 /* mask for split bit */ +#define AUH_UNSPLIT 0x00 /* data block is full-size */ +#define AUH_SPLIT 0x40 /* data block is part of a larger one, + split-byte follows */ + +#define AUH_TYPEMASK 0x3F /* mask for type of data transfer */ +#define AUH_TYPESIZE 0x40 /* different types */ +#define AUH_DCHANNEL 0x00 /* D channel data */ +#define AUH_B1CHANNEL 0x01 /* B1 channel transparent */ +#define AUH_B2CHANNEL 0x02 /* B2 channel transparent */ +/* 0x03..0x0F reserved for driver internal use */ +#define AUH_COMMAND 0x10 /* Command channel */ +#define AUH_BPROT 0x11 /* Configuration block protocol */ +#define AUH_DPROTANA 0x12 /* D channel protocol analyzer */ +#define AUH_TAPI 0x13 /* telephone api data (ATD) */ +/* 0x14..0x3F reserved for other protocols */ +#define AUH_UNASSIGNED 0xFF /* if char device has no assigned service */ +#define AUH_FIRSTUSERCH 0x11 /* first channel which is available for driver users */ + +#define AUH_SIZE 1 /* Size of Header Byte */ + +/* Split Byte. Only present if split bit in header byte set.*/ +#define AUS_STARTMASK 0x80 /* mask for first block of splitted frame */ +#define AUS_FIRST 0x80 /* first block */ +#define AUS_FOLLOW 0x00 /* following block */ + +#define AUS_ENDMASK 0x40 /* mask for last block of splitted frame */ +#define AUS_END 0x40 /* last block */ +#define AUS_NOEND 0x00 /* not the last block */ + +#define AUS_LENMASK 0x3F /* mask for block length information */ + +/* Request types */ +#define AUT_RREQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER) /* Read Request */ +#define AUT_WREQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER) /* Write Request */ + +/* Vendor Requests */ +#define AUV_GETINFO 0x00 /* GetDeviceInfo */ +#define AUV_WBLOCK 0x01 /* Write Block */ +#define AUV_RBLOCK 0x02 /* Read Block */ +#define AUV_CHANNELCTL 0x03 /* Channel Control */ +#define AUV_DUMMY 0x04 /* Dummy Out for retry */ + +/* Device Info Types */ +#define AUDI_NUMBCH 0x0000 /* Number of supported B channels */ +#define AUDI_OUTFSIZE 0x0001 /* Size of OUT B channel fifos */ +#define AUDI_MBCTRANS 0x0002 /* max. Blocklength of control transfer */ + +/* Interrupt endpoint definitions */ +#define AU_IRQENDP 1 /* Endpoint number */ +#define AU_IRQCMDID 16 /* Command-block ID */ +#define AU_BLOCKRDY 0 /* Command: Block data ready on ctl endpoint */ +#define AU_IRQMINSIZE 5 /* Nr. of bytes decoded in this driver */ + +/* Device String Descriptors */ +#define AUSI_VENDOR 1 /* "Auerswald GmbH & Co. KG" */ +#define AUSI_DEVICE 2 /* Name of the Device */ +#define AUSI_SERIALNR 3 /* Serial Number */ +#define AUSI_MSN 4 /* "MSN ..." (first) Multiple Subscriber Number */ + +#define AUSI_DLEN 100 /* Max. Length of Device Description */ + +#define AUV_RETRY 0x101 /* First Firmware version which can do control retries */ + +/*-------------------------------------------------------------------*/ +/* External data structures / Interface */ +typedef struct +{ + char *buf; /* return buffer for string contents */ + unsigned int bsize; /* size of return buffer */ +} audevinfo_t,*paudevinfo_t; + +/* IO controls */ +#define IOCTL_AU_SLEN _IOR( 'U', 0xF0, int) /* return the max. string descriptor length */ +#define IOCTL_AU_DEVINFO _IOWR('U', 0xF1, audevinfo_t) /* get name of a specific device */ +#define IOCTL_AU_SERVREQ _IOW( 'U', 0xF2, int) /* request a service channel */ +#define IOCTL_AU_BUFLEN _IOR( 'U', 0xF3, int) /* return the max. buffer length for the device */ +#define IOCTL_AU_RXAVAIL _IOR( 'U', 0xF4, int) /* return != 0 if Receive Data available */ +#define IOCTL_AU_CONNECT _IOR( 'U', 0xF5, int) /* return != 0 if connected to a service channel */ +#define IOCTL_AU_TXREADY _IOR( 'U', 0xF6, int) /* return != 0 if Transmitt channel ready to send */ +/* 'U' 0xF7..0xFF reseved */ + +/*-------------------------------------------------------------------*/ +/* Internal data structures */ + +/* ..................................................................*/ +/* urb chain element */ +struct auerchain; /* forward for circular reference */ +typedef struct +{ + struct auerchain *chain; /* pointer to the chain to which this element belongs */ + urb_t * urbp; /* pointer to attached urb */ + void *context; /* saved URB context */ + usb_complete_t complete; /* saved URB completion function */ + struct list_head list; /* to include element into a list */ +} auerchainelement_t,*pauerchainelement_t; + +/* urb chain */ +typedef struct auerchain +{ + pauerchainelement_t active; /* element which is submitted to urb */ + spinlock_t lock; /* protection agains interrupts */ + struct list_head waiting_list; /* list of waiting elements */ + struct list_head free_list; /* list of available elements */ +} auerchain_t,*pauerchain_t; + +/* urb blocking completion helper struct */ +typedef struct +{ + wait_queue_head_t wqh; /* wait for completion */ + unsigned int done; /* completion flag */ +} auerchain_chs_t,*pauerchain_chs_t; + +/* ...................................................................*/ +/* buffer element */ +struct auerbufctl; /* forward */ +typedef struct +{ + char *bufp; /* reference to allocated data buffer */ + unsigned int len; /* number of characters in data buffer */ + unsigned int retries; /* for urb retries */ + devrequest *dr; /* for setup data in control messages */ + urb_t * urbp; /* USB urb */ + struct auerbufctl *list; /* pointer to list */ + struct list_head buff_list; /* reference to next buffer in list */ +} auerbuf_t,*pauerbuf_t; + +/* buffer list control block */ +typedef struct auerbufctl +{ + spinlock_t lock; /* protection in interrupt */ + struct list_head free_buff_list;/* free buffers */ + struct list_head rec_buff_list; /* buffers with receive data */ +} auerbufctl_t,*pauerbufctl_t; + +/* ...................................................................*/ +/* service context */ +struct auerscon; /* forward */ +typedef void (*auer_dispatch_t)(struct auerscon*, pauerbuf_t); +typedef void (*auer_disconn_t) (struct auerscon*); +typedef struct auerscon +{ + unsigned int id; /* protocol service id AUH_xxxx */ + auer_dispatch_t dispatch; /* dispatch read buffer */ + auer_disconn_t disconnect; /* disconnect from device, wake up all char readers */ +} auerscon_t,*pauerscon_t; + +/* ...................................................................*/ +/* USB device context */ +typedef struct +{ + struct semaphore mutex; /* protection in user context */ + char name[16]; /* name of the /dev/usb entry */ + unsigned int dtindex; /* index in the device table */ + devfs_handle_t devfs; /* devfs device node */ + struct usb_device * usbdev; /* USB device handle */ + int open_count; /* count the number of open character channels */ + char dev_desc[AUSI_DLEN];/* for storing a textual description */ + unsigned int maxControlLength; /* max. Length of control paket (without header) */ + urb_t * inturbp; /* interrupt urb */ + char * intbufp; /* data buffer for interrupt urb */ + unsigned int irqsize; /* size of interrupt endpoint 1 */ + struct auerchain controlchain; /* for chaining of control messages */ + auerbufctl_t bufctl; /* Buffer control for control transfers */ + pauerscon_t services[AUH_TYPESIZE];/* context pointers for each service */ + unsigned int version; /* Version of the device */ + wait_queue_head_t bufferwait; /* wait for a control buffer */ +} auerswald_t,*pauerswald_t; + +/* the global usb devfs handle */ +extern devfs_handle_t usb_devfs_handle; + +/* array of pointers to our devices that are currently connected */ +static pauerswald_t dev_table[AUER_MAX_DEVICES]; + +/* lock to protect the dev_table structure */ +static struct semaphore dev_table_mutex; + +/* ................................................................... */ +/* character device context */ +typedef struct +{ + struct semaphore mutex; /* protection in user context */ + pauerswald_t auerdev; /* context pointer of assigned device */ + auerbufctl_t bufctl; /* controls the buffer chain */ + auerscon_t scontext; /* service context */ + wait_queue_head_t readwait; /* for synchronous reading */ + struct semaphore readmutex; /* protection against multiple reads */ + pauerbuf_t readbuf; /* buffer held for partial reading */ + unsigned int readoffset; /* current offset in readbuf */ + unsigned int removed; /* is != 0 if device is removed */ +} auerchar_t,*pauerchar_t; + + +/*-------------------------------------------------------------------*/ +/* Forwards */ +static void auerswald_ctrlread_complete (urb_t * urb); +static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); + + +/*-------------------------------------------------------------------*/ +/* USB chain helper functions */ +/* -------------------------- */ + +/* completion function for chained urbs */ +static void auerchain_complete (urb_t * urb) +{ + unsigned long flags; + int result; + + /* get pointer to element and to chain */ + pauerchainelement_t acep = (pauerchainelement_t) urb->context; + pauerchain_t acp = acep->chain; + + /* restore original entries in urb */ + urb->context = acep->context; + urb->complete = acep->complete; + + dbg ("auerchain_complete called"); + + /* call original completion function + NOTE: this function may lead to more urbs submitted into the chain. + (no chain lock at calling complete()!) + acp->active != NULL is protecting us against recursion.*/ + urb->complete (urb); + + /* detach element from chain data structure */ + spin_lock_irqsave (&acp->lock, flags); + if (acp->active != acep) /* paranoia debug check */ + dbg ("auerchain_complete: completion on non-active element called!"); + else + acp->active = NULL; + + /* add the used chain element to the list of free elements */ + list_add_tail (&acep->list, &acp->free_list); + acep = NULL; + + /* is there a new element waiting in the chain? */ + if (!acp->active && !list_empty (&acp->waiting_list)) { + /* yes: get the entry */ + struct list_head *tmp = acp->waiting_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + acp->active = acep; + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* submit the new urb */ + if (acep) { + urb = acep->urbp; + dbg ("auerchain_complete: submitting next urb from chain"); + urb->status = 0; /* needed! */ + result = usb_submit_urb( urb); + + /* check for submit errors */ + if (result) { + urb->status = result; + dbg("auerchain_complete: usb_submit_urb with error code %d", result); + /* and do error handling via *this* completion function (recursive) */ + auerchain_complete( urb); + } + } else { + /* simple return without submitting a new urb. + The empty chain is detected with acp->active == NULL. */ + }; +} + + +/* submit function for chained urbs + this function may be called from completion context or from user space! + early = 1 -> submit in front of chain +*/ +static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early) +{ + int result; + unsigned long flags; + pauerchainelement_t acep = NULL; + + dbg ("auerchain_submit_urb called"); + + /* try to get a chain element */ + spin_lock_irqsave (&acp->lock, flags); + if (!list_empty (&acp->free_list)) { + /* yes: get the entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* if no chain element available: return with error */ + if (!acep) { + return -ENOMEM; + } + + /* fill in the new chain element values */ + acep->chain = acp; + acep->context = urb->context; + acep->complete = urb->complete; + acep->urbp = urb; + INIT_LIST_HEAD (&acep->list); + + /* modify urb */ + urb->context = acep; + urb->complete = auerchain_complete; + urb->status = -EINPROGRESS; /* usb_submit_urb does this, too */ + + /* add element to chain - or start it immediately */ + spin_lock_irqsave (&acp->lock, flags); + if (acp->active) { + /* there is traffic in the chain, simple add element to chain */ + if (early) { + dbg ("adding new urb to head of chain"); + list_add (&acep->list, &acp->waiting_list); + } else { + dbg ("adding new urb to end of chain"); + list_add_tail (&acep->list, &acp->waiting_list); + } + acep = NULL; + } else { + /* the chain is empty. Prepare restart */ + acp->active = acep; + } + /* Spin has to be removed before usb_submit_urb! */ + spin_unlock_irqrestore (&acp->lock, flags); + + /* Submit urb if immediate restart */ + if (acep) { + dbg("submitting urb immediate"); + urb->status = 0; /* needed! */ + result = usb_submit_urb( urb); + /* check for submit errors */ + if (result) { + urb->status = result; + dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result); + /* and do error handling via completion function */ + auerchain_complete( urb); + } + } + + return 0; +} + +/* submit function for chained urbs + this function may be called from completion context or from user space! +*/ +static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb) +{ + return auerchain_submit_urb_list (acp, urb, 0); +} + +/* cancel an urb which is submitted to the chain + the result is 0 if the urb is cancelled, or -EINPROGRESS if + USB_ASYNC_UNLINK is set and the function is successfully started. +*/ +static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb) +{ + unsigned long flags; + urb_t * urbp; + pauerchainelement_t acep; + struct list_head *tmp; + + dbg ("auerchain_unlink_urb called"); + + /* search the chain of waiting elements */ + spin_lock_irqsave (&acp->lock, flags); + list_for_each (tmp, &acp->waiting_list) { + acep = list_entry (tmp, auerchainelement_t, list); + if (acep->urbp == urb) { + list_del (tmp); + urb->context = acep->context; + urb->complete = acep->complete; + list_add_tail (&acep->list, &acp->free_list); + spin_unlock_irqrestore (&acp->lock, flags); + dbg ("unlink waiting urb"); + urb->status = -ENOENT; + urb->complete (urb); + return 0; + } + } + /* not found. */ + spin_unlock_irqrestore (&acp->lock, flags); + + /* get the active urb */ + acep = acp->active; + if (acep) { + urbp = acep->urbp; + + /* check if we have to cancel the active urb */ + if (urbp == urb) { + /* note that there is a race condition between the check above + and the unlink() call because of no lock. This race is harmless, + because the usb module will detect the unlink() after completion. + We can't use the acp->lock here because the completion function + wants to grab it. + */ + dbg ("unlink active urb"); + return usb_unlink_urb (urbp); + } + } + + /* not found anyway + ... is some kind of success + */ + dbg ("urb to unlink not found in chain"); + return 0; +} + +/* cancel all urbs which are in the chain. + this function must not be called from interrupt or completion handler. +*/ +static void auerchain_unlink_all (pauerchain_t acp) +{ + unsigned long flags; + urb_t * urbp; + pauerchainelement_t acep; + + dbg ("auerchain_unlink_all called"); + + /* clear the chain of waiting elements */ + spin_lock_irqsave (&acp->lock, flags); + while (!list_empty (&acp->waiting_list)) { + /* get the next entry */ + struct list_head *tmp = acp->waiting_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + urbp = acep->urbp; + urbp->context = acep->context; + urbp->complete = acep->complete; + list_add_tail (&acep->list, &acp->free_list); + spin_unlock_irqrestore (&acp->lock, flags); + dbg ("unlink waiting urb"); + urbp->status = -ENOENT; + urbp->complete (urbp); + spin_lock_irqsave (&acp->lock, flags); + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* clear the active urb */ + acep = acp->active; + if (acep) { + urbp = acep->urbp; + urbp->transfer_flags &= ~USB_ASYNC_UNLINK; + dbg ("unlink active urb"); + usb_unlink_urb (urbp); + } +} + + +/* free the chain. + this function must not be called from interrupt or completion handler. +*/ +static void auerchain_free (pauerchain_t acp) +{ + unsigned long flags; + pauerchainelement_t acep; + + dbg ("auerchain_free called"); + + /* first, cancel all pending urbs */ + auerchain_unlink_all (acp); + + /* free the elements */ + spin_lock_irqsave (&acp->lock, flags); + while (!list_empty (&acp->free_list)) { + /* get the next entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + spin_unlock_irqrestore (&acp->lock, flags); + acep = list_entry (tmp, auerchainelement_t, list); + kfree (acep); + spin_lock_irqsave (&acp->lock, flags); + } + spin_unlock_irqrestore (&acp->lock, flags); +} + + +/* Init the chain control structure */ +static void auerchain_init (pauerchain_t acp) +{ + /* init the chain data structure */ + acp->active = NULL; + spin_lock_init (&acp->lock); + INIT_LIST_HEAD (&acp->waiting_list); + INIT_LIST_HEAD (&acp->free_list); +} + +/* setup a chain. + It is assumed that there is no concurrency while setting up the chain + requirement: auerchain_init() +*/ +static int auerchain_setup (pauerchain_t acp, unsigned int numElements) +{ + pauerchainelement_t acep; + + dbg ("auerchain_setup called with %d elements", numElements); + + /* fill the list of free elements */ + for (;numElements; numElements--) { + acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL); + if (!acep) goto ac_fail; + memset (acep, 0, sizeof (auerchainelement_t)); + INIT_LIST_HEAD (&acep->list); + list_add_tail (&acep->list, &acp->free_list); + } + return 0; + +ac_fail:/* free the elements */ + while (!list_empty (&acp->free_list)) { + /* get the next entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + kfree (acep); + } + return -ENOMEM; +} + + +/* completion handler for synchronous chained URBs */ +static void auerchain_blocking_completion (urb_t *urb) +{ + pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context; + pchs->done = 1; + wmb(); + wake_up (&pchs->wqh); +} + + +/* Starts chained urb and waits for completion or timeout */ +static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length) +{ + DECLARE_WAITQUEUE (wait, current); + auerchain_chs_t chs; + int status; + + dbg ("auerchain_start_wait_urb called"); + init_waitqueue_head (&chs.wqh); + chs.done = 0; + + set_current_state (TASK_UNINTERRUPTIBLE); + add_wait_queue (&chs.wqh, &wait); + urb->context = &chs; + status = auerchain_submit_urb (acp, urb); + if (status) { + /* something went wrong */ + set_current_state (TASK_RUNNING); + remove_wait_queue (&chs.wqh, &wait); + return status; + } + + while (timeout && !chs.done) + { + timeout = schedule_timeout (timeout); + set_current_state(TASK_UNINTERRUPTIBLE); + rmb(); + } + + set_current_state (TASK_RUNNING); + remove_wait_queue (&chs.wqh, &wait); + + if (!timeout && !chs.done) { + if (urb->status != -EINPROGRESS) { /* No callback?!! */ + dbg ("auerchain_start_wait_urb: raced timeout"); + status = urb->status; + } else { + dbg ("auerchain_start_wait_urb: timeout"); + auerchain_unlink_urb (acp, urb); /* remove urb safely */ + status = -ETIMEDOUT; + } + } else + status = urb->status; + + if (actual_length) + *actual_length = urb->actual_length; + + return status; +} + + +/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion + acp: pointer to the auerchain + dev: pointer to the usb device to send the message to + pipe: endpoint "pipe" to send the message to + request: USB message request value + requesttype: USB message request type value + value: USB message value + index: USB message index value + data: pointer to the data to send + size: length in bytes of the data to send + timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + + This function sends a simple control message to a specified endpoint + and waits for the message to complete, or timeout. + + If successful, it returns the transfered length, othwise a negative error number. + + Don't use this function from within an interrupt context, like a + bottom half handler. If you need a asyncronous message, or need to send + a message from within interrupt context, use auerchain_submit_urb() +*/ +static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, + __u16 value, __u16 index, void *data, __u16 size, int timeout) +{ + int ret; + devrequest *dr; + urb_t *urb; + int length; + + dbg ("auerchain_control_msg"); + dr = kmalloc (sizeof (devrequest), GFP_KERNEL); + if (!dr) + return -ENOMEM; + urb = usb_alloc_urb (0); + if (!urb) { + kfree (dr); + return -ENOMEM; + } + + dr->requesttype = requesttype; + dr->request = request; + dr->value = cpu_to_le16 (value); + dr->index = cpu_to_le16 (index); + dr->length = cpu_to_le16 (size); + + FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size, /* build urb */ + (usb_complete_t)auerchain_blocking_completion,0); + ret = auerchain_start_wait_urb (acp, urb, timeout, &length); + + usb_free_urb (urb); + kfree (dr); + + if (ret < 0) + return ret; + else + return length; +} + + +/*-------------------------------------------------------------------*/ +/* Buffer List helper functions */ + +/* free a single auerbuf */ +static void auerbuf_free (pauerbuf_t bp) +{ + if (bp->bufp) { + kfree (bp->bufp); + } + if (bp->dr) { + kfree (bp->dr); + } + if (bp->urbp) { + usb_free_urb (bp->urbp); + } + kfree (bp); +} + +/* free the buffers from an auerbuf list */ +static void auerbuf_free_list (struct list_head *q) +{ + struct list_head *tmp; + struct list_head *p; + pauerbuf_t bp; + + dbg ("auerbuf_free_list"); + for (p = q->next; p != q;) { + bp = list_entry (p, auerbuf_t, buff_list); + tmp = p->next; + list_del (p); + p = tmp; + auerbuf_free (bp); + } +} + +/* init the members of a list control block */ +static void auerbuf_init (pauerbufctl_t bcp) +{ + dbg ("auerbuf_init"); + spin_lock_init (&bcp->lock); + INIT_LIST_HEAD (&bcp->free_buff_list); + INIT_LIST_HEAD (&bcp->rec_buff_list); +} + +/* free all buffers from an auerbuf chain */ +static void auerbuf_free_buffers (pauerbufctl_t bcp) +{ + unsigned long flags; + dbg ("auerbuf_free_buffers"); + + spin_lock_irqsave (&bcp->lock, flags); + + auerbuf_free_list (&bcp->free_buff_list); + auerbuf_free_list (&bcp->rec_buff_list); + + spin_unlock_irqrestore (&bcp->lock, flags); +} + +/* setup a list of buffers */ +/* requirement: auerbuf_init() */ +static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned int bufsize) +{ + pauerbuf_t bep; + + dbg ("auerbuf_setup called with %d elements of %d bytes", numElements, bufsize); + + /* fill the list of free elements */ + for (;numElements; numElements--) { + bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL); + if (!bep) goto bl_fail; + memset (bep, 0, sizeof (auerbuf_t)); + bep->list = bcp; + INIT_LIST_HEAD (&bep->buff_list); + bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL); + if (!bep->bufp) goto bl_fail; + bep->dr = (devrequest *) kmalloc (sizeof (devrequest), GFP_KERNEL); + if (!bep->dr) goto bl_fail; + bep->urbp = usb_alloc_urb (0); + if (!bep->urbp) goto bl_fail; + list_add_tail (&bep->buff_list, &bcp->free_buff_list); + } + return 0; + +bl_fail:/* not enought memory. Free allocated elements */ + dbg ("auerbuf_setup: no more memory"); + auerbuf_free_buffers (bcp); + return -ENOMEM; +} + +/* insert a used buffer into the free list */ +static void auerbuf_releasebuf( pauerbuf_t bp) +{ + unsigned long flags; + pauerbufctl_t bcp = bp->list; + bp->retries = 0; + + dbg ("auerbuf_releasebuf called"); + spin_lock_irqsave (&bcp->lock, flags); + list_add_tail (&bp->buff_list, &bcp->free_buff_list); + spin_unlock_irqrestore (&bcp->lock, flags); +} + + +/*-------------------------------------------------------------------*/ +/* Completion handlers */ + +/* Values of urb->status or results of usb_submit_urb(): +0 Initial, OK +-EINPROGRESS during submission until end +-ENOENT if urb is unlinked +-ETIMEDOUT Transfer timed out, NAK +-ENOMEM Memory Overflow +-ENODEV Specified USB-device or bus doesn't exist +-ENXIO URB already queued +-EINVAL a) Invalid transfer type specified (or not supported) + b) Invalid interrupt interval (0n256) +-EAGAIN a) Specified ISO start frame too early + b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again. +-EFBIG Too much ISO frames requested (currently uhci900) +-EPIPE Specified pipe-handle/Endpoint is already stalled +-EMSGSIZE Endpoint message size is zero, do interface/alternate setting +-EPROTO a) Bitstuff error + b) Unknown USB error +-EILSEQ CRC mismatch +-ENOSR Buffer error +-EREMOTEIO Short packet detected +-EXDEV ISO transfer only partially completed look at individual frame status for details +-EINVAL ISO madness, if this happens: Log off and go home +-EOVERFLOW babble +*/ + +/* check if a status code allows a retry */ +static int auerswald_status_retry (int status) +{ + switch (status) { + case 0: + case -ETIMEDOUT: + case -EOVERFLOW: + case -EAGAIN: + case -EPIPE: + case -EPROTO: + case -EILSEQ: + case -ENOSR: + case -EREMOTEIO: + return 1; /* do a retry */ + } + return 0; /* no retry possible */ +} + +/* Completion of asynchronous write block */ +static void auerchar_ctrlwrite_complete (urb_t * urb) +{ + pauerbuf_t bp = (pauerbuf_t) urb->context; + pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + dbg ("auerchar_ctrlwrite_complete called"); + + /* reuse the buffer */ + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); +} + +/* Completion handler for dummy retry packet */ +static void auerswald_ctrlread_wretcomplete (urb_t * urb) +{ + pauerbuf_t bp = (pauerbuf_t) urb->context; + pauerswald_t cp; + int ret; + dbg ("auerswald_ctrlread_wretcomplete called"); + dbg ("complete with status: %d", urb->status); + cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + + /* check if it is possible to advance */ + if (!auerswald_status_retry (urb->status) || !cp->usbdev) { + /* reuse the buffer */ + err ("control dummy: transmission error %d, can not retry", urb->status); + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + return; + } + + /* fill the control message */ + bp->dr->requesttype = AUT_RREQ; + bp->dr->request = AUV_RBLOCK; + bp->dr->length = bp->dr->value; /* temporary stored */ + bp->dr->value = cpu_to_le16 (1); /* Retry Flag */ + /* bp->dr->index = channel id; remains */ + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->length), + (usb_complete_t)auerswald_ctrlread_complete,bp); + + /* submit the control msg as next paket */ + ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); + if (ret) { + dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_complete (bp->urbp); + } +} + +/* completion handler for receiving of control messages */ +static void auerswald_ctrlread_complete (urb_t * urb) +{ + unsigned int serviceid; + pauerswald_t cp; + pauerscon_t scp; + pauerbuf_t bp = (pauerbuf_t) urb->context; + int ret; + dbg ("auerswald_ctrlread_complete called"); + + cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + + /* check if there is valid data in this urb */ + if (urb->status) { + dbg ("complete with non-zero status: %d", urb->status); + /* should we do a retry? */ + if (!auerswald_status_retry (urb->status) + || !cp->usbdev + || (cp->version < AUV_RETRY) + || (bp->retries >= AU_RETRIES)) { + /* reuse the buffer */ + err ("control read: transmission error %d, can not retry", urb->status); + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + return; + } + bp->retries++; + dbg ("Retry count = %d", bp->retries); + /* send a long dummy control-write-message to allow device firmware to react */ + bp->dr->requesttype = AUT_WREQ; + bp->dr->request = AUV_DUMMY; + bp->dr->value = bp->dr->length; /* temporary storage */ + // bp->dr->index channel ID remains + bp->dr->length = cpu_to_le16 (32); /* >= 8 bytes */ + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, 32, + (usb_complete_t)auerswald_ctrlread_wretcomplete,bp); + + /* submit the control msg as next paket */ + ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); + if (ret) { + dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_wretcomplete (bp->urbp); + } + return; + } + + /* get the actual bytecount (incl. headerbyte) */ + bp->len = urb->actual_length; + serviceid = bp->bufp[0] & AUH_TYPEMASK; + dbg ("Paket with serviceid %d and %d bytes received", serviceid, bp->len); + + /* dispatch the paket */ + scp = cp->services[serviceid]; + if (scp) { + /* look, Ma, a listener! */ + scp->dispatch (scp, bp); + } + + /* release the paket */ + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); +} + +/*-------------------------------------------------------------------*/ +/* Handling of Interrupt Endpoint */ +/* This interrupt Endpoint is used to inform the host about waiting + messages from the USB device. +*/ +/* int completion handler. */ +static void auerswald_int_complete (urb_t * urb) +{ + unsigned long flags; + unsigned int channelid; + unsigned int bytecount; + int ret; + pauerbuf_t bp = NULL; + pauerswald_t cp = (pauerswald_t) urb->context; + + dbg ("auerswald_int_complete called"); + + /* do not respond to an error condition */ + if (urb->status != 0) { + dbg ("nonzero URB status = %d", urb->status); + return; + } + + /* check if all needed data was received */ + if (urb->actual_length < AU_IRQMINSIZE) { + dbg ("invalid data length received: %d bytes", urb->actual_length); + return; + } + + /* check the command code */ + if (cp->intbufp[0] != AU_IRQCMDID) { + dbg ("invalid command received: %d", cp->intbufp[0]); + return; + } + + /* check the command type */ + if (cp->intbufp[1] != AU_BLOCKRDY) { + dbg ("invalid command type received: %d", cp->intbufp[1]); + return; + } + + /* now extract the information */ + channelid = cp->intbufp[2]; + bytecount = le16_to_cpup (&cp->intbufp[3]); + + /* check the channel id */ + if (channelid >= AUH_TYPESIZE) { + dbg ("invalid channel id received: %d", channelid); + return; + } + + /* check the byte count */ + if (bytecount > (cp->maxControlLength+AUH_SIZE)) { + dbg ("invalid byte count received: %d", bytecount); + return; + } + dbg ("Service Channel = %d", channelid); + dbg ("Byte Count = %d", bytecount); + + /* get a buffer for the next data paket */ + spin_lock_irqsave (&cp->bufctl.lock, flags); + if (!list_empty (&cp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = cp->bufctl.free_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&cp->bufctl.lock, flags); + + /* if no buffer available: skip it */ + if (!bp) { + dbg ("auerswald_int_complete: no data buffer available"); + /* can we do something more? + This is a big problem: if this int packet is ignored, the + device will wait forever and not signal any more data. + The only real solution is: having enought buffers! + Or perhaps temporary disabling the int endpoint? + */ + return; + } + + /* fill the control message */ + bp->dr->requesttype = AUT_RREQ; + bp->dr->request = AUV_RBLOCK; + bp->dr->value = cpu_to_le16 (0); + bp->dr->index = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT); + bp->dr->length = cpu_to_le16 (bytecount); + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, bytecount, + (usb_complete_t)auerswald_ctrlread_complete,bp); + + /* submit the control msg */ + ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); + if (ret) { + dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_complete( bp->urbp); + /* here applies the same problem as above: device locking! */ + } +} + +/* int memory deallocation + NOTE: no mutex please! +*/ +static void auerswald_int_free (pauerswald_t cp) +{ + if (cp->inturbp) { + usb_free_urb (cp->inturbp); + cp->inturbp = NULL; + } + if (cp->intbufp) { + kfree (cp->intbufp); + cp->intbufp = NULL; + } +} + +/* This function is called to activate the interrupt + endpoint. This function returns 0 if successfull or an error code. + NOTE: no mutex please! +*/ +static int auerswald_int_open (pauerswald_t cp) +{ + int ret; + struct usb_endpoint_descriptor *ep; + int irqsize; + dbg ("auerswald_int_open"); + + ep = usb_epnum_to_ep_desc (cp->usbdev, USB_DIR_IN | AU_IRQENDP); + if (!ep) { + ret = -EFAULT; + goto intoend; + } + irqsize = ep->wMaxPacketSize; + cp->irqsize = irqsize; + + /* allocate the urb and data buffer */ + if (!cp->inturbp) { + cp->inturbp = usb_alloc_urb (0); + if (!cp->inturbp) { + ret = -ENOMEM; + goto intoend; + } + } + if (!cp->intbufp) { + cp->intbufp = (char *) kmalloc (irqsize, GFP_KERNEL); + if (!cp->intbufp) { + ret = -ENOMEM; + goto intoend; + } + } + /* setup urb */ + FILL_INT_URB (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->bInterval); + /* start the urb */ + cp->inturbp->status = 0; /* needed! */ + ret = usb_submit_urb (cp->inturbp); + +intoend: + if (ret < 0) { + /* activation of interrupt endpoint has failed. Now clean up. */ + dbg ("auerswald_int_open: activation of int endpoint failed"); + + /* deallocate memory */ + auerswald_int_free (cp); + } + return ret; +} + +/* This function is called to deactivate the interrupt + endpoint. This function returns 0 if successfull or an error code. + NOTE: no mutex please! +*/ +static int auerswald_int_release (pauerswald_t cp) +{ + int ret = 0; + dbg ("auerswald_int_release"); + + /* stop the int endpoint */ + if (cp->inturbp) { + ret = usb_unlink_urb (cp->inturbp); + if (ret) + dbg ("nonzero int unlink result received: %d", ret); + } + + /* deallocate memory */ + auerswald_int_free (cp); + + return ret; +} + +/* --------------------------------------------------------------------- */ +/* Helper functions */ + +/* wake up waiting readers */ +static void auerchar_disconnect (pauerscon_t scp) +{ + pauerchar_t ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); + dbg ("auerchar_disconnect called"); + ccp->removed = 1; + wake_up (&ccp->readwait); +} + + +/* dispatch a read paket to a waiting character device */ +static void auerchar_ctrlread_dispatch (pauerscon_t scp, pauerbuf_t bp) +{ + unsigned long flags; + pauerchar_t ccp; + pauerbuf_t newbp = NULL; + char * charp; + dbg ("auerchar_ctrlread_dispatch called"); + ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); + + /* get a read buffer from character device context */ + spin_lock_irqsave (&ccp->bufctl.lock, flags); + if (!list_empty (&ccp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = ccp->bufctl.free_buff_list.next; + list_del (tmp); + newbp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + + if (!newbp) { + dbg ("No read buffer available, discard paket!"); + return; /* no buffer, no dispatch */ + } + + /* copy information to new buffer element + (all buffers have the same length) */ + charp = newbp->bufp; + newbp->bufp = bp->bufp; + bp->bufp = charp; + newbp->len = bp->len; + + /* insert new buffer in read list */ + spin_lock_irqsave (&ccp->bufctl.lock, flags); + list_add_tail (&newbp->buff_list, &ccp->bufctl.rec_buff_list); + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + dbg ("read buffer appended to rec_list"); + + /* wake up pending synchronous reads */ + wake_up (&ccp->readwait); +} + + +/* Delete an auerswald driver context */ +static void auerswald_delete( pauerswald_t cp) +{ + dbg( "auerswald_delete"); + if (cp == NULL) return; + + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + + /* Cleaning up */ + auerswald_int_release (cp); + auerchain_free (&cp->controlchain); + auerbuf_free_buffers (&cp->bufctl); + + /* release the memory */ + kfree( cp); +} + + +/* Delete an auerswald character context */ +static void auerchar_delete( pauerchar_t ccp) +{ + dbg ("auerchar_delete"); + if (ccp == NULL) return; + + /* wake up pending synchronous reads */ + ccp->removed = 1; + wake_up (&ccp->readwait); + + /* remove the read buffer */ + if (ccp->readbuf) { + auerbuf_releasebuf (ccp->readbuf); + ccp->readbuf = NULL; + } + + /* remove the character buffers */ + auerbuf_free_buffers (&ccp->bufctl); + + /* release the memory */ + kfree( ccp); +} + + +/* add a new service to the device + scp->id must be set! + return: 0 if OK, else error code +*/ +static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp) +{ + int ret; + + /* is the device available? */ + if (!cp->usbdev) { + dbg ("usbdev == NULL"); + return -EIO; /*no: can not add a service, sorry*/ + } + + /* is the service available? */ + if (cp->services[scp->id]) { + dbg ("service is busy"); + return -EBUSY; + } + + /* device is available, service is free */ + cp->services[scp->id] = scp; + + /* register service in device */ + ret = auerchain_control_msg( + &cp->controlchain, /* pointer to control chain */ + cp->usbdev, /* pointer to device */ + usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ + AUV_CHANNELCTL, /* USB message request value */ + AUT_WREQ, /* USB message request type value */ + 0x01, /* open USB message value */ + scp->id, /* USB message index value */ + NULL, /* pointer to the data to send */ + 0, /* length in bytes of the data to send */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret < 0) { + dbg ("auerswald_addservice: auerchain_control_msg returned error code %d", ret); + /* undo above actions */ + cp->services[scp->id] = NULL; + return ret; + } + + dbg ("auerswald_addservice: channel open OK"); + return 0; +} + + +/* remove a service from the the device + scp->id must be set! */ +static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp) +{ + dbg ("auerswald_removeservice called"); + + /* check if we have a service allocated */ + if (scp->id == AUH_UNASSIGNED) return; + + /* If there is a device: close the channel */ + if (cp->usbdev) { + /* Close the service channel inside the device */ + int ret = auerchain_control_msg( + &cp->controlchain, /* pointer to control chain */ + cp->usbdev, /* pointer to device */ + usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ + AUV_CHANNELCTL, /* USB message request value */ + AUT_WREQ, /* USB message request type value */ + 0x00, // close /* USB message value */ + scp->id, /* USB message index value */ + NULL, /* pointer to the data to send */ + 0, /* length in bytes of the data to send */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret < 0) { + dbg ("auerswald_removeservice: auerchain_control_msg returned error code %d", ret); + } + else { + dbg ("auerswald_removeservice: channel close OK"); + } + } + + /* remove the service from the device */ + cp->services[scp->id] = NULL; + scp->id = AUH_UNASSIGNED; +} + + +/* --------------------------------------------------------------------- */ +/* Char device functions */ + +/* Open a new character device */ +static int auerchar_open (struct inode *inode, struct file *file) +{ + int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE; + pauerswald_t cp = NULL; + pauerchar_t ccp = NULL; + int ret; + + /* minor number in range? */ + if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) { + return -ENODEV; + } + /* usb device available? */ + if (down_interruptible (&dev_table_mutex)) { + return -ERESTARTSYS; + } + cp = dev_table[dtindex]; + if (cp == NULL) { + up (&dev_table_mutex); + return -ENODEV; + } + if (down_interruptible (&cp->mutex)) { + up (&dev_table_mutex); + return -ERESTARTSYS; + } + up (&dev_table_mutex); + + /* we have access to the device. Now lets allocate memory */ + ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); + if (ccp == NULL) { + err ("out of memory"); + ret = -ENOMEM; + goto ofail; + } + + /* Initialize device descriptor */ + memset( ccp, 0, sizeof(auerchar_t)); + init_MUTEX( &ccp->mutex); + init_MUTEX( &ccp->readmutex); + auerbuf_init (&ccp->bufctl); + ccp->scontext.id = AUH_UNASSIGNED; + ccp->scontext.dispatch = auerchar_ctrlread_dispatch; + ccp->scontext.disconnect = auerchar_disconnect; + init_waitqueue_head (&ccp->readwait); + + ret = auerbuf_setup (&ccp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE); + if (ret) { + goto ofail; + } + + cp->open_count++; + ccp->auerdev = cp; + dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name); + up (&cp->mutex); + + /* file IO stuff */ + file->f_pos = 0; + file->private_data = ccp; + return 0; + + /* Error exit */ +ofail: up (&cp->mutex); + auerchar_delete (ccp); + return ret; +} + + +/* IOCTL functions */ +static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + int ret = 0; + audevinfo_t devinfo; + pauerswald_t cp = NULL; + unsigned int u; + dbg ("ioctl"); + + /* get the mutexes */ + if (down_interruptible (&ccp->mutex)) { + return -ERESTARTSYS; + } + cp = ccp->auerdev; + if (!cp) { + up (&ccp->mutex); + return -ENODEV; + } + if (down_interruptible (&cp->mutex)) { + up(&ccp->mutex); + return -ERESTARTSYS; + } + + /* Check for removal */ + if (!cp->usbdev) { + up(&cp->mutex); + up(&ccp->mutex); + return -ENODEV; + } + + switch (cmd) { + + /* return != 0 if Transmitt channel ready to send */ + case IOCTL_AU_TXREADY: + dbg ("IOCTL_AU_TXREADY"); + u = ccp->auerdev + && (ccp->scontext.id != AUH_UNASSIGNED) + && !list_empty (&cp->bufctl.free_buff_list); + ret = put_user (u, (unsigned int *) arg); + break; + + /* return != 0 if connected to a service channel */ + case IOCTL_AU_CONNECT: + dbg ("IOCTL_AU_CONNECT"); + u = (ccp->scontext.id != AUH_UNASSIGNED); + ret = put_user (u, (unsigned int *) arg); + break; + + /* return != 0 if Receive Data available */ + case IOCTL_AU_RXAVAIL: + dbg ("IOCTL_AU_RXAVAIL"); + if (ccp->scontext.id == AUH_UNASSIGNED) { + ret = -EIO; + break; + } + u = 0; /* no data */ + if (ccp->readbuf) { + int restlen = ccp->readbuf->len - ccp->readoffset; + if (restlen > 0) u = 1; + } + if (!u) { + if (!list_empty (&ccp->bufctl.rec_buff_list)) { + u = 1; + } + } + ret = put_user (u, (unsigned int *) arg); + break; + + /* return the max. buffer length for the device */ + case IOCTL_AU_BUFLEN: + dbg ("IOCTL_AU_BUFLEN"); + u = cp->maxControlLength; + ret = put_user (u, (unsigned int *) arg); + break; + + /* requesting a service channel */ + case IOCTL_AU_SERVREQ: + dbg ("IOCTL_AU_SERVREQ"); + /* requesting a service means: release the previous one first */ + auerswald_removeservice (cp, &ccp->scontext); + /* get the channel number */ + ret = get_user (u, (unsigned int *) arg); + if (ret) { + break; + } + if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) { + ret = -EIO; + break; + } + dbg ("auerchar service request parameters are ok"); + ccp->scontext.id = u; + + /* request the service now */ + ret = auerswald_addservice (cp, &ccp->scontext); + if (ret) { + /* no: revert service entry */ + ccp->scontext.id = AUH_UNASSIGNED; + } + break; + + /* get a string descriptor for the device */ + case IOCTL_AU_DEVINFO: + dbg ("IOCTL_AU_DEVINFO"); + if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) { + ret = -EFAULT; + break; + } + u = strlen(cp->dev_desc)+1; + if (u > devinfo.bsize) { + u = devinfo.bsize; + } + ret = copy_to_user(devinfo.buf, cp->dev_desc, u); + break; + + /* get the max. string descriptor length */ + case IOCTL_AU_SLEN: + dbg ("IOCTL_AU_SLEN"); + u = AUSI_DLEN; + ret = put_user (u, (unsigned int *) arg); + break; + + default: + dbg ("IOCTL_AU_UNKNOWN"); + ret = -ENOIOCTLCMD; + break; + } + /* release the mutexes */ + up(&cp->mutex); + up(&ccp->mutex); + return ret; +} + + +/* Seek is not supported */ +static loff_t auerchar_llseek (struct file *file, loff_t offset, int origin) +{ + dbg ("auerchar_seek"); + return -ESPIPE; +} + + +/* Read data from the device */ +static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos) +{ + unsigned long flags; + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerbuf_t bp = NULL; + wait_queue_t wait; + + dbg ("auerchar_read"); + + /* Error checking */ + if (!ccp) + return -EIO; + if (*ppos) + return -ESPIPE; + if (count == 0) + return 0; + + /* get the mutex */ + if (down_interruptible (&ccp->mutex)) + return -ERESTARTSYS; + + /* Can we expect to read something? */ + if (ccp->scontext.id == AUH_UNASSIGNED) { + up (&ccp->mutex); + return -EIO; + } + + /* only one reader per device allowed */ + if (down_interruptible (&ccp->readmutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + + /* read data from readbuf, if available */ +doreadbuf: + bp = ccp->readbuf; + if (bp) { + /* read the maximum bytes */ + int restlen = bp->len - ccp->readoffset; + if (restlen < 0) + restlen = 0; + if (count > restlen) + count = restlen; + if (count) { + if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) { + dbg ("auerswald_read: copy_to_user failed"); + up (&ccp->readmutex); + up (&ccp->mutex); + return -EFAULT; + } + } + /* advance the read offset */ + ccp->readoffset += count; + restlen -= count; + // reuse the read buffer + if (restlen <= 0) { + auerbuf_releasebuf (bp); + ccp->readbuf = NULL; + } + /* return with number of bytes read */ + if (count) { + up (&ccp->readmutex); + up (&ccp->mutex); + return count; + } + } + + /* a read buffer is not available. Try to get the next data block. */ +doreadlist: + /* Preparing for sleep */ + init_waitqueue_entry (&wait, current); + set_current_state (TASK_INTERRUPTIBLE); + add_wait_queue (&ccp->readwait, &wait); + + bp = NULL; + spin_lock_irqsave (&ccp->bufctl.lock, flags); + if (!list_empty (&ccp->bufctl.rec_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = ccp->bufctl.rec_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + + /* have we got data? */ + if (bp) { + ccp->readbuf = bp; + ccp->readoffset = AUH_SIZE; /* for headerbyte */ + set_current_state (TASK_RUNNING); + remove_wait_queue (&ccp->readwait, &wait); + goto doreadbuf; /* now we can read! */ + } + + /* no data available. Should we wait? */ + if (file->f_flags & O_NONBLOCK) { + dbg ("No read buffer available, returning -EAGAIN"); + set_current_state (TASK_RUNNING); + remove_wait_queue (&ccp->readwait, &wait); + up (&ccp->readmutex); + up (&ccp->mutex); + return -EAGAIN; /* nonblocking, no data available */ + } + + /* yes, we should wait! */ + up (&ccp->mutex); /* allow other operations while we wait */ + schedule(); + remove_wait_queue (&ccp->readwait, &wait); + if (signal_pending (current)) { + /* waked up by a signal */ + up (&ccp->readmutex); + return -ERESTARTSYS; + } + + /* Anything left to read? */ + if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) { + up (&ccp->readmutex); + return -EIO; + } + + if (down_interruptible (&ccp->mutex)) { + up (&ccp->readmutex); + return -ERESTARTSYS; + } + + /* try to read the incomming data again */ + goto doreadlist; +} + + +/* Write a data block into the right service channel of the device */ +static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerswald_t cp = NULL; + pauerbuf_t bp; + unsigned long flags; + int ret; + wait_queue_t wait; + + dbg ("auerchar_write %d bytes", len); + + /* Error checking */ + if (!ccp) + return -EIO; + if (*ppos) + return -ESPIPE; + if (len == 0) + return 0; + +write_again: + /* get the mutex */ + if (down_interruptible (&ccp->mutex)) + return -ERESTARTSYS; + + /* Can we expect to write something? */ + if (ccp->scontext.id == AUH_UNASSIGNED) { + up (&ccp->mutex); + return -EIO; + } + + cp = ccp->auerdev; + if (!cp) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + if (down_interruptible (&cp->mutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + if (!cp->usbdev) { + up (&cp->mutex); + up (&ccp->mutex); + return -EIO; + } + /* Prepare for sleep */ + init_waitqueue_entry (&wait, current); + set_current_state (TASK_INTERRUPTIBLE); + add_wait_queue (&cp->bufferwait, &wait); + + /* Try to get a buffer from the device pool. + We can't use a buffer from ccp->bufctl because the write + command will last beond a release() */ + bp = NULL; + spin_lock_irqsave (&cp->bufctl.lock, flags); + if (!list_empty (&cp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = cp->bufctl.free_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&cp->bufctl.lock, flags); + + /* are there any buffers left? */ + if (!bp) { + up (&cp->mutex); + up (&ccp->mutex); + + /* NONBLOCK: don't wait */ + if (file->f_flags & O_NONBLOCK) { + set_current_state (TASK_RUNNING); + remove_wait_queue (&cp->bufferwait, &wait); + return -EAGAIN; + } + + /* BLOCKING: wait */ + schedule(); + remove_wait_queue (&cp->bufferwait, &wait); + if (signal_pending (current)) { + /* waked up by a signal */ + return -ERESTARTSYS; + } + goto write_again; + } else { + set_current_state (TASK_RUNNING); + remove_wait_queue (&cp->bufferwait, &wait); + } + + /* protect against too big write requests */ + if (len > cp->maxControlLength) len = cp->maxControlLength; + + /* Fill the buffer */ + if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) { + dbg ("copy_from_user failed"); + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + up (&cp->mutex); + up (&ccp->mutex); + return -EIO; + } + + /* set the header byte */ + *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT; + + /* Set the transfer Parameters */ + bp->len = len+AUH_SIZE; + bp->dr->requesttype = AUT_WREQ; + bp->dr->request = AUV_WBLOCK; + bp->dr->value = cpu_to_le16 (0); + bp->dr->index = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT); + bp->dr->length = cpu_to_le16 (len+AUH_SIZE); + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE, + auerchar_ctrlwrite_complete, bp); + /* up we go */ + ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); + up (&cp->mutex); + if (ret) { + dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret); + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + up (&ccp->mutex); + return -EIO; + } + else { + dbg ("auerchar_write: Write OK"); + up (&ccp->mutex); + return len; + } +} + + +/* Close a character device */ +static int auerchar_release (struct inode *inode, struct file *file) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerswald_t cp; + dbg("release"); + + /* get the mutexes */ + if (down_interruptible (&ccp->mutex)) { + return -ERESTARTSYS; + } + cp = ccp->auerdev; + if (cp) { + if (down_interruptible (&cp->mutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + /* remove an open service */ + auerswald_removeservice (cp, &ccp->scontext); + /* detach from device */ + if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) { + /* usb device waits for removal */ + up (&cp->mutex); + auerswald_delete (cp); + } else { + up (&cp->mutex); + } + cp = NULL; + ccp->auerdev = NULL; + } + up (&ccp->mutex); + auerchar_delete (ccp); + + return 0; +} + + +/*----------------------------------------------------------------------*/ +/* File operation structure */ +static struct file_operations auerswald_fops = +{ + owner: THIS_MODULE, + llseek: auerchar_llseek, + read: auerchar_read, + write: auerchar_write, + ioctl: auerchar_ioctl, + open: auerchar_open, + release: auerchar_release, +}; + + +/* --------------------------------------------------------------------- */ +/* Special USB driver functions */ + +/* Probe if this driver wants to serve an USB device + + This entry point is called whenever a new device is attached to the bus. + Then the device driver has to create a new instance of its internal data + structures for the new device. + + The dev argument specifies the device context, which contains pointers + to all USB descriptors. The interface argument specifies the interface + number. If a USB driver wants to bind itself to a particular device and + interface it has to return a pointer. This pointer normally references + the device driver's context structure. + + Probing normally is done by checking the vendor and product identifications + or the class and subclass definitions. If they match the interface number + is compared with the ones supported by the driver. When probing is done + class based it might be necessary to parse some more USB descriptors because + the device properties can differ in a wide range. +*/ +static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum, + const struct usb_device_id *id) +{ + pauerswald_t cp = NULL; + DECLARE_WAIT_QUEUE_HEAD (wqh); + unsigned int dtindex; + unsigned int u = 0; + char *pbuf; + int ret; + + dbg ("probe: vendor id 0x%x, device id 0x%x ifnum:%d", + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); + + /* See if the device offered us matches that we can accept */ + if (usbdev->descriptor.idVendor != ID_AUERSWALD) return NULL; + + /* we use only the first -and only- interface */ + if (ifnum != 0) return NULL; + + /* prevent module unloading while sleeping */ + MOD_INC_USE_COUNT; + + /* allocate memory for our device and intialize it */ + cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL); + if (cp == NULL) { + err ("out of memory"); + goto pfail; + } + + /* Initialize device descriptor */ + memset (cp, 0, sizeof(auerswald_t)); + init_MUTEX (&cp->mutex); + cp->usbdev = usbdev; + auerchain_init (&cp->controlchain); + auerbuf_init (&cp->bufctl); + init_waitqueue_head (&cp->bufferwait); + + /* find a free slot in the device table */ + down (&dev_table_mutex); + for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) { + if (dev_table[dtindex] == NULL) + break; + } + if ( dtindex >= AUER_MAX_DEVICES) { + err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES); + up (&dev_table_mutex); + goto pfail; + } + + /* Give the device a name */ + sprintf (cp->name, AU_PREFIX "%d", dtindex); + + /* Store the index */ + cp->dtindex = dtindex; + dev_table[dtindex] = cp; + up (&dev_table_mutex); + + /* initialize the devfs node for this device and register it */ + cp->devfs = devfs_register (usb_devfs_handle, cp->name, + DEVFS_FL_DEFAULT, USB_MAJOR, + AUER_MINOR_BASE + dtindex, + S_IFCHR | S_IRUGO | S_IWUGO, + &auerswald_fops, NULL); + + /* Get the usb version of the device */ + cp->version = cp->usbdev->descriptor.bcdDevice; + dbg ("Version is %X", cp->version); + + /* allow some time to settle the device */ + sleep_on_timeout (&wqh, HZ / 3 ); + + /* Try to get a suitable textual description of the device */ + /* Device name:*/ + ret = usb_string( cp->usbdev, AUSI_DEVICE, cp->dev_desc, AUSI_DLEN-1); + if (ret >= 0) { + u += ret; + /* Append Serial Number */ + memcpy(&cp->dev_desc[u], ",Ser# ", 6); + u += 6; + ret = usb_string( cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u], AUSI_DLEN-u-1); + if (ret >= 0) { + u += ret; + /* Append subscriber number */ + memcpy(&cp->dev_desc[u], ", ", 2); + u += 2; + ret = usb_string( cp->usbdev, AUSI_MSN, &cp->dev_desc[u], AUSI_DLEN-u-1); + if (ret >= 0) { + u += ret; + } + } + } + cp->dev_desc[u] = '\0'; + info("device is a %s", cp->dev_desc); + + /* get the maximum allowed control transfer length */ + pbuf = (char *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ + if (!pbuf) { + err( "out of memory"); + goto pfail; + } + ret = usb_control_msg(cp->usbdev, /* pointer to device */ + usb_rcvctrlpipe( cp->usbdev, 0 ), /* pipe to control endpoint */ + AUV_GETINFO, /* USB message request value */ + AUT_RREQ, /* USB message request type value */ + 0, /* USB message value */ + AUDI_MBCTRANS, /* USB message index value */ + pbuf, /* pointer to the receive buffer */ + 2, /* length of the buffer */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret == 2) { + cp->maxControlLength = le16_to_cpup(pbuf); + kfree(pbuf); + dbg("setup: max. allowed control transfersize is %d bytes", cp->maxControlLength); + } else { + kfree(pbuf); + err("setup: getting max. allowed control transfer length failed with error %d", ret); + goto pfail; + } + + /* allocate a chain for the control messages */ + if (auerchain_setup (&cp->controlchain, AUCH_ELEMENTS)) { + err ("out of memory"); + goto pfail; + } + + /* allocate buffers for control messages */ + if (auerbuf_setup (&cp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE)) { + err ("out of memory"); + goto pfail; + } + + /* start the interrupt endpoint */ + if (auerswald_int_open (cp)) { + err ("int endpoint failed"); + goto pfail; + } + + /* all OK */ + return cp; + + /* Error exit: clean up the memory */ +pfail: auerswald_delete (cp); + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* Disconnect driver from a served device + + This function is called whenever a device which was served by this driver + is disconnected. + + The argument dev specifies the device context and the driver_context + returns a pointer to the previously registered driver_context of the + probe function. After returning from the disconnect function the USB + framework completly deallocates all data structures associated with + this device. So especially the usb_device structure must not be used + any longer by the usb driver. +*/ +static void auerswald_disconnect (struct usb_device *usbdev, void *driver_context) +{ + pauerswald_t cp = (pauerswald_t) driver_context; + unsigned int u; + + down (&cp->mutex); + info ("device /dev/usb/%s now disconnecting", cp->name); + + /* remove from device table */ + /* Nobody can open() this device any more */ + down (&dev_table_mutex); + dev_table[cp->dtindex] = NULL; + up (&dev_table_mutex); + + /* remove our devfs node */ + /* Nobody can see this device any more */ + devfs_unregister (cp->devfs); + + /* Stop the interrupt endpoint */ + auerswald_int_release (cp); + + /* remove the control chain allocated in auerswald_probe + This has the benefit of + a) all pending (a)synchronous urbs are unlinked + b) all buffers dealing with urbs are reclaimed + */ + auerchain_free (&cp->controlchain); + + if (cp->open_count == 0) { + /* nobody is using this device. So we can clean up now */ + up (&cp->mutex);/* up() is possible here because no other task + can open the device (see above). I don't want + to kfree() a locked mutex. */ + auerswald_delete (cp); + } else { + /* device is used. Remove the pointer to the + usb device (it's not valid any more). The last + release() will do the clean up */ + cp->usbdev = NULL; + up (&cp->mutex); + /* Terminate waiting writers */ + wake_up (&cp->bufferwait); + /* Inform all waiting readers */ + for ( u = 0; u < AUH_TYPESIZE; u++) { + pauerscon_t scp = cp->services[u]; + if (scp) scp->disconnect( scp); + } + } + + /* The device releases this module */ + MOD_DEC_USE_COUNT; +} + +/* Descriptor for the devices which are served by this driver. + NOTE: this struct is parsed by the usbmanager install scripts. + Don't change without caution! +*/ +static struct usb_device_id auerswald_ids [] = { + { USB_DEVICE (ID_AUERSWALD, 0x00C0) }, /* COMpact 2104 USB */ + { USB_DEVICE (ID_AUERSWALD, 0x00DB) }, /* COMpact 4410/2206 USB */ + { USB_DEVICE (ID_AUERSWALD, 0x00F1) }, /* Comfort 2000 System Telephone */ + { USB_DEVICE (ID_AUERSWALD, 0x00F2) }, /* Comfort 1200 System Telephone */ + { } /* Terminating entry */ +}; + +/* Standard module device table */ +MODULE_DEVICE_TABLE (usb, auerswald_ids); + +/* Standard usb driver struct */ +static struct usb_driver auerswald_driver = { + name: "auerswald", + probe: auerswald_probe, + disconnect: auerswald_disconnect, + fops: &auerswald_fops, + minor: AUER_MINOR_BASE, + id_table: auerswald_ids, +}; + + +/* --------------------------------------------------------------------- */ +/* Module loading/unloading */ + +/* Driver initialisation. Called after module loading. + NOTE: there is no concurrency at _init +*/ +static int __init auerswald_init (void) +{ + int result; + dbg ("init"); + + /* initialize the device table */ + memset (&dev_table, 0, sizeof(dev_table)); + init_MUTEX (&dev_table_mutex); + + /* register driver at the USB subsystem */ + result = usb_register (&auerswald_driver); + if (result < 0) { + err ("driver could not be registered"); + return -1; + } + return 0; +} + +/* Driver deinit. Called before module removal. + NOTE: there is no concurrency at _cleanup +*/ +static void __exit auerswald_cleanup (void) +{ + dbg ("cleanup"); + usb_deregister (&auerswald_driver); +} + +/* --------------------------------------------------------------------- */ +/* Linux device driver module description */ + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_DESC); + +module_init (auerswald_init); +module_exit (auerswald_cleanup); + +/* --------------------------------------------------------------------- */ + diff -urN linux-2.4.18/drivers/usb/catc.c linux-2.4.19-pre5/drivers/usb/catc.c --- linux-2.4.18/drivers/usb/catc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/catc.c Sat Mar 30 22:55:35 2002 @@ -38,7 +38,9 @@ #include #include #include +#include #include +#include #undef DEBUG @@ -48,9 +50,10 @@ * Version information. */ -#define DRIVER_VERSION "v2.7" +#define DRIVER_VERSION "v2.8" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver" +#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -259,11 +262,15 @@ } } - if (data[1] & 0x40) + if (data[1] & 0x40) { + netif_carrier_on(catc->netdev); dbg("link ok"); + } - if (data[1] & 0x20) + if (data[1] & 0x20) { + netif_carrier_off(catc->netdev); dbg("link bad"); + } } /* @@ -564,6 +571,54 @@ } /* + * ioctl's + */ +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct catc *catc = dev->priv; + u32 cmd; + char tmp[40]; + + if (get_user(cmd, (u32 *)useraddr)) + return -EFAULT; + + switch (cmd) { + /* get driver info */ + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); + sprintf(tmp, "usb%d:%d", catc->usbdev->bus->busnum, catc->usbdev->devnum); + strncpy(info.bus_info, tmp,ETHTOOL_BUSINFO_LEN); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = netif_carrier_ok(dev); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + } + /* Note that the ethtool user space code requires EOPNOTSUPP */ + return -EOPNOTSUPP; +} + +static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + default: + return -ENOTTY; /* Apparently this is the standard ioctl errno */ + } +} + + +/* * Open, close. */ @@ -629,6 +684,7 @@ netdev->tx_timeout = catc_tx_timeout; netdev->watchdog_timeo = TX_TIMEOUT; netdev->set_multicast_list = catc_set_multicast_list; + netdev->do_ioctl = catc_ioctl; netdev->priv = catc; catc->usbdev = usbdev; diff -urN linux-2.4.18/drivers/usb/devices.c linux-2.4.19-pre5/drivers/usb/devices.c --- linux-2.4.18/drivers/usb/devices.c Sun Dec 23 16:23:49 2001 +++ linux-2.4.19-pre5/drivers/usb/devices.c Sat Mar 30 22:55:40 2002 @@ -105,8 +105,8 @@ "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; static char *format_endpt = -/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */ - "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n"; +/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */ + "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n"; /* @@ -166,24 +166,71 @@ return (clas_info[ix].class_name); } -static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc) -{ - char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."}; +static char *usb_dump_endpoint_descriptor ( + int speed, + char *start, + char *end, + const struct usb_endpoint_descriptor *desc +) +{ + char dir, unit, *type; + unsigned interval, in, bandwidth = 1; if (start > end) return start; - start += sprintf(start, format_endpt, desc->bEndpointAddress, - (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL - ? 'B' : /* bidirectional */ - (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O', - desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK], - desc->wMaxPacketSize, desc->bInterval); - return start; -} + in = (desc->bEndpointAddress & USB_DIR_IN); + dir = in ? 'I' : 'O'; + if (speed == USB_SPEED_HIGH) { + switch (desc->wMaxPacketSize & (0x03 << 11)) { + case 1 << 11: bandwidth = 2; break; + case 2 << 11: bandwidth = 3; break; + } + } -static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint) -{ - return usb_dump_endpoint_descriptor(start, end, endpoint); + /* this isn't checking for illegal values */ + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + type = "Ctrl"; + if (speed == USB_SPEED_HIGH) /* uframes per NAK */ + interval = desc->bInterval; + else + interval = 0; + dir = 'B'; /* ctrl is bidirectional */ + break; + case USB_ENDPOINT_XFER_ISOC: + type = "Isoc"; + interval = 1 << (desc->bInterval - 1); + break; + case USB_ENDPOINT_XFER_BULK: + type = "Bulk"; + if (speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + interval = desc->bInterval; + else + interval = 0; + break; + case USB_ENDPOINT_XFER_INT: + type = "Int."; + if (speed == USB_SPEED_HIGH) { + interval = 1 << (desc->bInterval - 1); + } else + interval = desc->bInterval; + break; + default: /* "can't happen" */ + return start; + } + interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000; + if (interval % 1000) + unit = 'u'; + else { + unit = 'm'; + interval /= 1000; + } + + start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, + desc->bmAttributes, type, + (desc->wMaxPacketSize & 0x07ff) * bandwidth, + interval, unit); + return start; } static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno) @@ -204,8 +251,13 @@ return start; } -static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno) -{ +static char *usb_dump_interface( + int speed, + char *start, + char *end, + const struct usb_interface *iface, + int setno +) { struct usb_interface_descriptor *desc = &iface->altsetting[setno]; int i; @@ -213,7 +265,8 @@ for (i = 0; i < desc->bNumEndpoints; i++) { if (start > end) return start; - start = usb_dump_endpoint(start, end, desc->endpoint + i); + start = usb_dump_endpoint_descriptor(speed, + start, end, desc->endpoint + i); } return start; } @@ -238,7 +291,13 @@ return start; } -static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active) +static char *usb_dump_config ( + int speed, + char *start, + char *end, + const struct usb_config_descriptor *config, + int active +) { int i, j; struct usb_interface *interface; @@ -255,7 +314,8 @@ for (j = 0; j < interface->num_altsetting; j++) { if (start > end) return start; - start = usb_dump_interface(start, end, interface, j); + start = usb_dump_interface(speed, + start, end, interface, j); } } return start; @@ -336,8 +396,10 @@ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) return start; - start = usb_dump_config(start, end, dev->config + i, - (dev->config + i) == dev->actconfig); /* active ? */ + start = usb_dump_config(dev->speed, + start, end, dev->config + i, + /* active ? */ + (dev->config + i) == dev->actconfig); } return start; } @@ -429,12 +491,26 @@ * count = device count at this level */ /* If this is the root hub, display the bandwidth information */ - if (level == 0) - data_end += sprintf(data_end, 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); - + if (level == 0) { + int max; + + /* high speed reserves 80%, full/low reserves 90% */ + if (usbdev->speed == USB_SPEED_HIGH) + max = 800; + else + max = FRAME_TIME_MAX_USECS_ALLOC; + + /* report "average" periodic allocation over a microsecond. + * the schedules are actually bursty, HCDs need to deal with + * that and just compute/report this average. + */ + data_end += sprintf(data_end, format_bandwidth, + bus->bandwidth_allocated, max, + (100 * bus->bandwidth_allocated + max / 2) + / max, + bus->bandwidth_int_reqs, + bus->bandwidth_isoc_reqs); + } data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev); if (data_end > (pages_start + (2 * PAGE_SIZE) - 256)) diff -urN linux-2.4.18/drivers/usb/emi26.c linux-2.4.19-pre5/drivers/usb/emi26.c --- linux-2.4.18/drivers/usb/emi26.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/emi26.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,239 @@ +/* + * Emagic EMI 2|6 usb audio interface firmware loader. + * Copyright (C) 2002 + * Tapio Laxström (tapio.laxstrom@iptime.fi) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, as published by + * the Free Software Foundation, version 2. + * + * emi26.c,v 1.13 2002/03/08 13:10:26 tapio Exp + */ +#include +#include +#include +#include +#include + +#define MAX_INTEL_HEX_RECORD_LENGTH 16 +typedef struct _INTEL_HEX_RECORD +{ + __u32 length; + __u32 address; + __u32 type; + __u8 data[MAX_INTEL_HEX_RECORD_LENGTH]; +} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; + +/* include firmware (variables) */ +#include "emi26_fw.h" + +#define EMI26_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */ +#define EMI26_PRODUCT_ID 0x0100 /* EMI 2|6 without firmware */ + +#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */ +#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */ +#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */ +#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */ +#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ +#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS) + +static int emi26_writememory( struct usb_device *dev, int address, unsigned char *data, int length, __u8 bRequest); +static int emi26_set_reset(struct usb_device *dev, unsigned char reset_bit); +static int emi26_load_firmware (struct usb_device *dev); +static void *emi26_probe(struct usb_device *dev, unsigned int if_num, const struct usb_device_id *id); +static void emi26_disconnect(struct usb_device *dev, void *drv_context); +static int __init emi26_init (void); +static void __exit emi26_exit (void); + + +/* thanks to drivers/usb/serial/keyspan_pda.c code */ +static int emi26_writememory (struct usb_device *dev, int address, unsigned char *data, int length, __u8 request) +{ + int result; + unsigned char *buffer = kmalloc (length, GFP_KERNEL); + + if (!buffer) { + printk(KERN_ERR "emi26: kmalloc(%d) failed.", length); + return -ENOMEM; + } + memcpy (buffer, data, length); + /* Note: usb_control_msg returns negative value on error or length of the + * data that was written! */ + result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); + kfree (buffer); + return result; +} + +/* thanks to drivers/usb/serial/keyspan_pda.c code */ +static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit) +{ + int response; + printk(KERN_INFO "%s - %d", __FUNCTION__, reset_bit); + /* printk(KERN_DEBUG "%s - %d", __FUNCTION__, reset_bit); */ + response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); + if (response < 0) { + printk(KERN_ERR "emi26: set_reset (%d) failed", reset_bit); + } + return response; +} + +static int emi26_load_firmware (struct usb_device *dev) +{ + int err; + int i; + int pos = 0; /* Position in hex record */ + __u32 addr; /* Address to write */ + __u8 buf[1023]; + + /* Assert reset (stop the CPU in the EMI) */ + err = emi26_set_reset(dev,1); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + + /* 1. We need to put the loader for the FPGA into the EZ-USB */ + for (i=0; g_Loader[i].type == 0; i++) { + err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + } + + /* De-assert reset (let the CPU run) */ + err = emi26_set_reset(dev,0); + + /* 2. We upload the FPGA firmware into the EMI + * Note: collect up to 1023 (yes!) bytes and send them with + * a single request. This is _much_ faster! */ + do { + i = 0; + addr = g_bitstream[pos].address; + + /* intel hex records are terminated with type 0 element */ + while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < sizeof(buf))) { + memcpy(buf + i, g_bitstream[pos].data, g_bitstream[pos].length); + i += g_bitstream[pos].length; + pos++; + } + err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + } while (i > 0); + + /* Assert reset (stop the CPU in the EMI) */ + err = emi26_set_reset(dev,1); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + + /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ + for (i=0; g_Loader[i].type == 0; i++) { + err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + } + + /* De-assert reset (let the CPU run) */ + err = emi26_set_reset(dev,0); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + + /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ + for (i=0; g_Firmware[i].type == 0; i++) { + if (!INTERNAL_RAM(g_Firmware[i].address)) { + err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + } + } + + /* Assert reset (stop the CPU in the EMI) */ + err = emi26_set_reset(dev,1); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + + for (i=0; g_Firmware[i].type == 0; i++) { + if (INTERNAL_RAM(g_Firmware[i].address)) { + err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + } + } + + /* De-assert reset (let the CPU run) */ + err = emi26_set_reset(dev,0); + if (err < 0) { + printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err); + return err; + } + + /* return 1 to fail the driver inialization + * and give real driver change to load */ + return 1; +} + +static __devinitdata struct usb_device_id id_table [] = { + { USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table); + +static void * emi26_probe(struct usb_device *dev, unsigned int if_num, const struct usb_device_id *id) +{ + printk(KERN_INFO "%s start", __FUNCTION__); + + if((dev->descriptor.idVendor == EMI26_VENDOR_ID) && (dev->descriptor.idProduct == EMI26_PRODUCT_ID)) { + emi26_load_firmware(dev); + } + + /* do not return the driver context, let real audio driver do that */ + return 0; +} + +static void emi26_disconnect(struct usb_device *dev, void *drv_context) +{ +} + +struct usb_driver emi26_driver = { +name: "emi26 - firmware loader", +probe: emi26_probe, +disconnect: emi26_disconnect, +id_table: NULL, +}; + +static int __init emi26_init (void) +{ + usb_register (&emi26_driver); + return 0; +} + +static void __exit emi26_exit (void) +{ + usb_deregister (&emi26_driver); +} + +module_init(emi26_init); +module_exit(emi26_exit); + +MODULE_AUTHOR("tapio laxström"); +MODULE_DESCRIPTION("Emagic EMI 2|6 firmware loader."); +MODULE_LICENSE("GPL"); + +/* vi:ai:syntax=c:sw=8:ts=8:tw=80 + */ diff -urN linux-2.4.18/drivers/usb/emi26_fw.h linux-2.4.19-pre5/drivers/usb/emi26_fw.h --- linux-2.4.18/drivers/usb/emi26_fw.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/emi26_fw.h Sat Mar 30 22:55:35 2002 @@ -0,0 +1,5775 @@ +/* + * This file is generated from three different files, provided by Emagic. + */ +/* generated Fri Mar 8 15:11:35 EET 2002 */ + +/* + * This firmware is for the Emagic EMI 2|6 Audio Interface + * + * The firmware contained herein is Copyright (c) 1999-2002 Emagic + * as an unpublished work. This notice does not imply unrestricted + * or public access to this firmware which is a trade secret of Emagic, + * and which may not be reproduced, used, sold or transferred to + * any third party without Emagic's written consent. All Rights Reserved. + * + * This firmware may not be modified and may only be used with the + * Emagic EMI 2|6 Audio Interface. Distribution and/or Modification of + * any driver which includes this firmware, in whole or in part, + * requires the inclusion of this statement. + */ +INTEL_HEX_RECORD g_bitstream[]={ +{ 16, 0x8010, 0, {0xff,0xff,0xff,0xff,0xaa,0x99,0x55,0x66,0x30,0x00,0x80,0x01,0x00,0x00,0x00,0x07 } }, +{ 16, 0x8020, 0, {0x30,0x01,0x60,0x01,0x00,0x00,0x00,0x0b,0x30,0x01,0x20,0x01,0x00,0x80,0x3f,0x2d } }, +{ 16, 0x8030, 0, {0x30,0x00,0xc0,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x80,0x01,0x00,0x00,0x00,0x09 } }, +{ 16, 0x8040, 0, {0x30,0x00,0x20,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x80,0x01,0x00,0x00,0x00,0x01 } }, +{ 16, 0x8050, 0, {0x30,0x00,0x40,0x00,0x50,0x00,0x3e,0x04,0x08,0x12,0x10,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8060, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8070, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x04 } }, +{ 16, 0x8080, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x10,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8090, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x84 } }, +{ 16, 0x80b0, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00 } }, +{ 16, 0x80e0, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8100, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8110, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8120, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8130, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04 } }, +{ 16, 0x8140, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x13,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8150, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8160, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8170, 0, {0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8180, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8190, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84 } }, +{ 16, 0x81a0, 0, {0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf7,0x10,0x01,0x14,0x00,0x25,0x00,0x05 } }, +{ 16, 0x81b0, 0, {0x40,0x01,0x50,0x00,0x94,0x00,0x15,0x00,0x07,0x40,0x01,0xd0,0x00,0x94,0x00,0x25 } }, +{ 16, 0x81c0, 0, {0x80,0x01,0x60,0x02,0xd8,0x00,0xf6,0x00,0x2f,0x80,0x02,0xe0,0x04,0xd8,0x37,0x44 } }, +{ 16, 0x81d0, 0, {0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf2,0x00,0xcc,0x90,0x39,0x20 } }, +{ 16, 0x81e0, 0, {0x0d,0x98,0x03,0xd2,0x00,0xe7,0x80,0x37,0x04,0x0e,0xf1,0x83,0x7e,0x00,0xdf,0x90 } }, +{ 16, 0x81f0, 0, {0x31,0xe4,0x8f,0x79,0x03,0x7c,0x20,0xdf,0x22,0x33,0xc0,0x0c,0xf0,0x22,0x30,0x00 } }, +{ 16, 0x8200, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0x62,0x00,0x80,0x24,0x22,0x20 } }, +{ 16, 0x8210, 0, {0x08,0x98,0x12,0xe2,0x00,0x8b,0x81,0x20,0x94,0x08,0x74,0x02,0x2e,0x00,0x8a,0x01 } }, +{ 16, 0x8220, 0, {0x22,0xc8,0x08,0x92,0x02,0x3d,0x80,0x8b,0x60,0x22,0x80,0x08,0xb0,0x02,0x20,0x04 } }, +{ 16, 0x8230, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc8,0x00,0xa0,0x00,0x20,0x00 } }, +{ 16, 0x8240, 0, {0x0b,0x10,0x02,0xc0,0x00,0xa1,0x00,0x24,0x09,0x4a,0x32,0x02,0x48,0x00,0xb1,0x00 } }, +{ 16, 0x8250, 0, {0x62,0xc0,0x09,0xa0,0x46,0xcc,0x24,0x93,0x49,0x2a,0x80,0x48,0x30,0x22,0x62,0x01 } }, +{ 16, 0x8260, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa8,0x12,0xa8,0x00,0x22,0x00 } }, +{ 16, 0x8270, 0, {0x08,0x90,0x02,0xe0,0x00,0x89,0x80,0x22,0x44,0x08,0xb0,0x12,0xa8,0x00,0xa9,0x40 } }, +{ 16, 0x8280, 0, {0x22,0xc0,0x08,0x90,0x82,0xac,0x00,0x9b,0x04,0x2a,0xc4,0x08,0xb0,0x02,0x70,0x04 } }, +{ 16, 0x8290, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x84,0x00,0xe9,0x80,0xb2,0x64 } }, +{ 16, 0x82a0, 0, {0x4d,0xa0,0x03,0xea,0x20,0xe9,0xc0,0x36,0x40,0x0e,0xb0,0x03,0x44,0x00,0xfb,0x90 } }, +{ 16, 0x82b0, 0, {0xb2,0x88,0x0d,0xbc,0x03,0xec,0x08,0x5b,0x00,0x38,0x60,0x2c,0xb0,0x63,0x40,0x04 } }, +{ 16, 0x82c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb4,0x26,0xdd,0x90,0x37,0x40 } }, +{ 16, 0x82d0, 0, {0x4f,0xe0,0x13,0xf2,0x80,0xfd,0x00,0x3d,0xa0,0x0d,0x70,0x03,0x75,0x00,0x5e,0x00 } }, +{ 16, 0x82e0, 0, {0x3f,0xa4,0x0d,0xf9,0x03,0x5c,0x10,0xeb,0x00,0x37,0x20,0x0f,0x30,0x03,0xb8,0x00 } }, +{ 16, 0x82f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xe9,0x80,0x32,0x40 } }, +{ 16, 0x8300, 0, {0x0c,0xa1,0x83,0xe8,0x00,0xe9,0x00,0x32,0x42,0x0e,0xb0,0x03,0xac,0x48,0xe9,0x00 } }, +{ 16, 0x8310, 0, {0x3a,0x80,0x0e,0xa4,0x03,0xec,0x00,0xeb,0x00,0xb2,0x03,0x0e,0xb0,0x0b,0x10,0x04 } }, +{ 16, 0x8320, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2e,0x80,0x89,0xd1,0x20,0x40 } }, +{ 16, 0x8330, 0, {0x08,0xa0,0x02,0xc0,0x00,0x81,0x80,0x22,0x58,0x08,0xf5,0x02,0x2f,0x40,0x8b,0x00 } }, +{ 16, 0x8340, 0, {0x20,0xc0,0x08,0x30,0x43,0x7c,0x00,0x87,0x00,0x22,0x40,0x08,0xf0,0x02,0x32,0x00 } }, +{ 16, 0x8350, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x42,0x01,0x9a,0x44,0x28,0xa2 } }, +{ 16, 0x8360, 0, {0x08,0x18,0x02,0xc0,0x80,0xa1,0x80,0xa0,0x00,0x08,0x30,0x02,0x8e,0x00,0xab,0x00 } }, +{ 16, 0x8370, 0, {0x2c,0x40,0x0a,0x30,0x02,0x0c,0x00,0xa3,0x00,0x20,0x44,0x0a,0x30,0x02,0x38,0x00 } }, +{ 16, 0x8380, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x32,0x00,0x96,0x82,0x2b,0xa2 } }, +{ 16, 0x8390, 0, {0x88,0x5a,0x02,0xf2,0x00,0x05,0x80,0x29,0xa0,0x08,0x78,0x42,0xbe,0x00,0x8e,0x84 } }, +{ 16, 0x83a0, 0, {0x2f,0x61,0x0a,0xd8,0x02,0x4e,0x10,0xa7,0x80,0x20,0x28,0x08,0x78,0x02,0x18,0x00 } }, +{ 16, 0x83b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x08,0x00,0xf2,0x24,0x38,0x80 } }, +{ 16, 0x83c0, 0, {0x2c,0x1a,0x03,0xc4,0x00,0xe0,0x58,0xa0,0x80,0x2e,0x30,0x03,0x88,0x41,0xe3,0x02 } }, +{ 16, 0x83d0, 0, {0x3c,0x40,0x06,0x20,0x03,0x8c,0x00,0xe3,0x00,0x10,0x00,0x0e,0x31,0x43,0x12,0x02 } }, +{ 16, 0x83e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0x98,0x00,0xee,0x01,0x37,0x84 } }, +{ 16, 0x83f0, 0, {0x9f,0xd9,0x03,0xf0,0x48,0xfd,0x10,0x37,0xc0,0x07,0xb0,0x03,0x5c,0x00,0xf6,0x10 } }, +{ 16, 0x8400, 0, {0x33,0xc0,0x0d,0xe1,0x03,0xed,0x20,0xdf,0x10,0x3f,0x48,0x0f,0xf0,0x23,0xd0,0x06 } }, +{ 16, 0x8410, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe4,0x02,0xcb,0x80,0x30,0xc0 } }, +{ 16, 0x8420, 0, {0x0c,0xa0,0x03,0xe2,0x02,0xc9,0x00,0x3a,0x40,0x0d,0xb6,0x03,0x64,0x00,0xeb,0x00 } }, +{ 16, 0x8430, 0, {0x3e,0xc0,0x0f,0xb0,0x03,0xed,0x00,0xfb,0x01,0x3e,0xe0,0x0c,0xb0,0x02,0xea,0x00 } }, +{ 16, 0x8440, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x94,0x00,0x87,0x00,0x21,0xc0 } }, +{ 16, 0x8450, 0, {0x28,0x60,0x02,0xd0,0x00,0x85,0x00,0x2d,0x80,0x48,0xf0,0x82,0x1c,0x00,0xb7,0x00 } }, +{ 16, 0x8460, 0, {0x2d,0x00,0x0b,0x50,0x02,0xdc,0x00,0xb7,0xa0,0x2f,0x80,0x28,0x7a,0x02,0xd2,0x04 } }, +{ 16, 0x8470, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0x00,0xbe,0x00,0x87,0x80,0x21,0xe0 } }, +{ 16, 0x8480, 0, {0x28,0x68,0x02,0xd7,0x00,0x84,0x80,0x2d,0xe0,0x49,0x79,0x06,0x53,0x09,0xb5,0x80 } }, +{ 16, 0x8490, 0, {0x2d,0xe2,0x0b,0x78,0x02,0xde,0x80,0xb7,0x90,0x2d,0xb0,0x08,0x79,0x02,0xf0,0x00 } }, +{ 16, 0x84a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x10,0x83,0x01,0x28,0xc8 } }, +{ 16, 0x84b0, 0, {0x08,0x20,0x02,0xc2,0x06,0x81,0x00,0x2c,0xc8,0x88,0x30,0x62,0x0e,0x21,0xb3,0xa0 } }, +{ 16, 0x84c0, 0, {0x2c,0xc1,0x0b,0xb6,0x02,0xcc,0x00,0xb3,0x00,0x2c,0xe0,0x08,0x30,0x02,0xd2,0x04 } }, +{ 16, 0x84d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xca,0x40,0xb0,0x80 } }, +{ 16, 0x84e0, 0, {0x0c,0x2c,0x02,0xf8,0x00,0xc6,0x20,0x3f,0x90,0x0d,0xa0,0x03,0x7b,0x01,0xee,0xe0 } }, +{ 16, 0x84f0, 0, {0x3f,0xb4,0x0f,0xec,0x03,0xe8,0x00,0xfa,0x00,0x3f,0xa0,0x0c,0xa0,0x03,0xfa,0x04 } }, +{ 16, 0x8500, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe3,0x00,0xf8,0x09,0x26,0x00 } }, +{ 16, 0x8510, 0, {0x0f,0xc1,0x83,0xe0,0x10,0xf8,0x40,0x3c,0x00,0x0f,0x80,0x03,0xe0,0x01,0xf8,0x00 } }, +{ 16, 0x8520, 0, {0x3e,0x00,0x0f,0x81,0x03,0xe0,0x04,0xf8,0x00,0x3e,0x10,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0x8530, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x02,0xc9,0x00,0x3e,0x40 } }, +{ 16, 0x8540, 0, {0x4f,0x90,0x63,0x26,0x84,0x39,0x02,0xb2,0x40,0x0c,0x91,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0x8550, 0, {0x3e,0x40,0x0f,0x90,0x03,0x24,0x00,0xf1,0x00,0x3a,0x44,0x0f,0x90,0x03,0xc2,0x04 } }, +{ 16, 0x8560, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x45,0x00,0x89,0x40,0x2e,0x40 } }, +{ 16, 0x8570, 0, {0x08,0x92,0x0a,0x24,0x00,0xb9,0x31,0x22,0x60,0x88,0x94,0x8a,0x24,0x20,0xb9,0x00 } }, +{ 16, 0x8580, 0, {0x2e,0x40,0x0b,0x90,0x02,0x24,0x00,0xb9,0x00,0x22,0x68,0x0b,0x90,0x02,0xe0,0x00 } }, +{ 16, 0x8590, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0xa0,0x8d,0x84,0x2f,0x40 } }, +{ 16, 0x85a0, 0, {0x0b,0xd1,0x02,0x24,0x00,0xb9,0x00,0x22,0x4a,0x08,0x10,0x02,0x2c,0x40,0xb9,0x00 } }, +{ 16, 0x85b0, 0, {0x2e,0x40,0x0b,0x90,0x02,0x24,0x00,0xb9,0x00,0x2a,0x40,0x0b,0x90,0x02,0xc6,0x00 } }, +{ 16, 0x85c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x14,0x00,0x85,0x80,0x2d,0x40 } }, +{ 16, 0x85d0, 0, {0x08,0x50,0x02,0x04,0x0c,0xb9,0x00,0xa0,0x50,0x08,0x14,0x22,0x04,0x00,0xb1,0x00 } }, +{ 16, 0x85e0, 0, {0x2c,0x40,0x0b,0x10,0x02,0x04,0x00,0xb1,0x28,0x20,0x4a,0x0b,0x13,0x02,0xc2,0x01 } }, +{ 16, 0x85f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x00,0xc0,0x50,0x3e,0x80 } }, +{ 16, 0x8600, 0, {0x0f,0xc0,0x43,0x20,0x00,0xf8,0x00,0x30,0x00,0x2c,0x80,0x23,0x20,0x00,0xf8,0x51 } }, +{ 16, 0x8610, 0, {0x3e,0x14,0x8f,0x85,0x0b,0x21,0x40,0xf8,0x70,0x3a,0x08,0x0f,0x84,0x83,0xee,0x03 } }, +{ 16, 0x8620, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xc4,0x00,0xf9,0x04,0x3e,0x40 } }, +{ 16, 0x8630, 0, {0x0f,0x90,0x23,0xd4,0x00,0xfd,0x00,0x3f,0x50,0x0f,0x94,0x03,0xf4,0x04,0xfd,0x00 } }, +{ 16, 0x8640, 0, {0x3f,0x41,0x8f,0xd0,0x43,0xe5,0x0c,0xf9,0x02,0x3f,0x4a,0x0f,0x92,0x03,0xe6,0x02 } }, +{ 16, 0x8650, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xd4,0x01,0xfd,0x00,0x3d,0x40 } }, +{ 16, 0x8660, 0, {0x0c,0xd0,0x13,0xf4,0x00,0xd5,0x00,0x33,0x6a,0x1c,0xdc,0x83,0x34,0x00,0xd1,0x04 } }, +{ 16, 0x8670, 0, {0x3e,0x50,0x0c,0x91,0x03,0xe6,0xc0,0xdd,0xb0,0x33,0x6a,0x2c,0x9c,0x83,0xe6,0x00 } }, +{ 16, 0x8680, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x09,0xf8,0x80,0x2e,0x00 } }, +{ 16, 0x8690, 0, {0x88,0x80,0x00,0xe8,0x00,0xba,0x00,0x22,0xb0,0x08,0x8e,0x02,0x28,0x00,0x88,0xa8 } }, +{ 16, 0x86a0, 0, {0x26,0x28,0x08,0x8a,0x22,0xe2,0x00,0x88,0xe4,0x22,0x30,0x08,0x8c,0x02,0xce,0x04 } }, +{ 16, 0x86b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x28,0x2e,0x40 } }, +{ 16, 0x86c0, 0, {0x08,0x10,0x02,0xc4,0x00,0x99,0x00,0x20,0x42,0x48,0x10,0x02,0x64,0x01,0x91,0x80 } }, +{ 16, 0x86d0, 0, {0x2c,0x48,0x08,0x10,0x02,0xc4,0xc0,0x81,0x40,0x20,0x4a,0x08,0x12,0x02,0xc2,0x01 } }, +{ 16, 0x86e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x94,0xa9,0x02,0x2e,0x40 } }, +{ 16, 0x86f0, 0, {0x0a,0x90,0x02,0x64,0x00,0xb9,0x00,0x82,0x60,0x08,0x90,0x02,0x66,0x00,0x89,0x10 } }, +{ 16, 0x8700, 0, {0x24,0x62,0x08,0x90,0x02,0xe4,0x00,0x89,0x02,0x22,0x40,0x18,0x90,0x02,0xc6,0x04 } }, +{ 16, 0x8710, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe6,0x00,0xb9,0x04,0x3e,0x40 } }, +{ 16, 0x8720, 0, {0x0c,0x90,0x13,0xe4,0x00,0xd1,0xc0,0x12,0x50,0x28,0x90,0x03,0x44,0x00,0xd9,0x00 } }, +{ 16, 0x8730, 0, {0x3e,0x40,0x28,0x92,0x03,0xe4,0x02,0xd9,0x00,0x32,0x42,0x8c,0x90,0x12,0xe8,0x04 } }, +{ 16, 0x8740, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa6,0x20,0xf9,0x00,0x3e,0x41 } }, +{ 16, 0x8750, 0, {0x2d,0x90,0x03,0xe4,0x00,0xf9,0x20,0x3e,0x40,0x4f,0x90,0x01,0xa4,0x00,0xf9,0x00 } }, +{ 16, 0x8760, 0, {0x36,0x40,0x8f,0x92,0x07,0xe4,0x00,0xf1,0x00,0xbe,0x40,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0x8770, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xc8,0x00,0x3e,0x20 } }, +{ 16, 0x8780, 0, {0x0c,0x80,0x03,0xe0,0x40,0xf8,0x00,0x36,0x12,0x2c,0x00,0x03,0xe0,0xc0,0xf8,0x00 } }, +{ 16, 0x8790, 0, {0x32,0x10,0x0d,0x84,0x03,0xa0,0x00,0xf8,0x02,0x3e,0x08,0x0f,0x80,0x00,0xca,0x04 } }, +{ 16, 0x87a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x3a,0x90,0x8e,0x00,0x2d,0xa0 } }, +{ 16, 0x87b0, 0, {0x80,0xe8,0x02,0xfa,0x00,0xbe,0x40,0x23,0x80,0x08,0xe8,0x02,0xfa,0x00,0x8a,0x00 } }, +{ 16, 0x87c0, 0, {0x36,0x80,0x08,0xa0,0x02,0xe8,0x00,0xba,0x00,0x2f,0x80,0x0b,0xa0,0x03,0x8a,0x00 } }, +{ 16, 0x87d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x46,0x02,0x83,0x00,0x2c,0x80 } }, +{ 16, 0x87e0, 0, {0x08,0x22,0x42,0xc6,0x80,0xb1,0x60,0x2e,0xf4,0x08,0x38,0x22,0xce,0x00,0xa3,0x00 } }, +{ 16, 0x87f0, 0, {0x20,0xc0,0x08,0x30,0x02,0xac,0x00,0xb1,0x00,0x2e,0x40,0x0b,0x30,0x02,0xca,0x00 } }, +{ 16, 0x8800, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1e,0x02,0x85,0x01,0x2d,0xc2 } }, +{ 16, 0x8810, 0, {0xa8,0x44,0x02,0xd4,0x00,0xbd,0x01,0x29,0x40,0x18,0x68,0xd2,0xdc,0x00,0x8f,0x80 } }, +{ 16, 0x8820, 0, {0x25,0xcc,0x28,0x73,0x42,0xdc,0x80,0xb5,0x30,0x2d,0xc0,0x1b,0x72,0x02,0xe8,0x00 } }, +{ 16, 0x8830, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x04,0xc6,0x82,0x3d,0xe0 } }, +{ 16, 0x8840, 0, {0x0c,0x48,0x12,0xd6,0x10,0xf5,0x80,0x3c,0xa0,0x0c,0x70,0x03,0xde,0x00,0xe7,0x90 } }, +{ 16, 0x8850, 0, {0x23,0xea,0x04,0x7a,0x03,0x9e,0x00,0xf5,0x80,0x3d,0xe0,0x0f,0x7a,0x03,0xea,0x02 } }, +{ 16, 0x8860, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0d,0xac,0x00,0x9c,0x00,0x3e,0xc0 } }, +{ 16, 0x8870, 0, {0x0f,0x80,0x03,0xe4,0x10,0xf9,0x00,0x36,0x01,0x0f,0xa0,0x03,0xc0,0x00,0xeb,0x00 } }, +{ 16, 0x8880, 0, {0x3e,0xd8,0x4e,0xb0,0x83,0xec,0x00,0xf9,0x00,0x3e,0xc0,0x0f,0xb4,0x43,0x82,0x06 } }, +{ 16, 0x8890, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xde,0x00,0xcf,0x84,0x31,0xe0 } }, +{ 16, 0x88a0, 0, {0x0e,0xc8,0x43,0xd6,0x00,0xcd,0x80,0x33,0xe0,0xcd,0xd9,0x03,0x3a,0x00,0xff,0x88 } }, +{ 16, 0x88b0, 0, {0x33,0xe0,0x0f,0xf9,0x13,0xfe,0x24,0xfd,0x80,0x3f,0x20,0x0c,0xf6,0x83,0x10,0x00 } }, +{ 16, 0x88c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0x85,0x00,0x21,0xc4 } }, +{ 16, 0x88d0, 0, {0x28,0x40,0x82,0xd0,0x00,0xd5,0x00,0x23,0x80,0x48,0xc9,0x02,0x1c,0x00,0xb7,0x00 } }, +{ 16, 0x88e0, 0, {0x21,0xc0,0x0b,0x71,0x02,0xde,0x80,0xb5,0x10,0x2d,0xc0,0x28,0xf0,0x02,0x2a,0x04 } }, +{ 16, 0x88f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x9c,0x00,0x96,0x00,0x21,0xc0 } }, +{ 16, 0x8900, 0, {0x0a,0x41,0x02,0xf5,0x40,0x8d,0x00,0x21,0x40,0x09,0x52,0x02,0x98,0x20,0xb7,0x00 } }, +{ 16, 0x8910, 0, {0x21,0xc0,0x0b,0x70,0x06,0xdc,0x80,0xb5,0x00,0x2d,0xc0,0x08,0x70,0x02,0x04,0x00 } }, +{ 16, 0x8920, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x14,0xcc,0x10,0x98,0x00,0x00,0xc0 } }, +{ 16, 0x8930, 0, {0x88,0x04,0x82,0xc0,0x00,0x91,0x04,0x20,0x03,0x09,0x00,0x02,0x8a,0x00,0xb3,0x0a } }, +{ 16, 0x8940, 0, {0x20,0xc4,0x8b,0x34,0x02,0xcc,0x00,0xb9,0x00,0x2c,0xc0,0x00,0x30,0x02,0x18,0x04 } }, +{ 16, 0x8950, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x15,0xac,0x00,0xdb,0x00,0xb0,0xc0 } }, +{ 16, 0x8960, 0, {0x0e,0x9c,0x02,0xc5,0x00,0xc1,0x10,0xb2,0xc0,0x0d,0xb0,0x0b,0xa7,0x08,0xff,0x00 } }, +{ 16, 0x8970, 0, {0xb3,0xc0,0x0f,0xfa,0x03,0xfc,0x00,0xfd,0x00,0x3e,0xd4,0x0c,0xf0,0x0b,0x2e,0x04 } }, +{ 16, 0x8980, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x04,0xed,0x00,0x3e,0x40 } }, +{ 16, 0x8990, 0, {0x0f,0x84,0x03,0xe5,0x40,0xf9,0x40,0x3e,0x60,0xce,0xb4,0x43,0x64,0x00,0xfb,0x80 } }, +{ 16, 0x89a0, 0, {0x3e,0xc2,0x0f,0xb0,0x13,0xec,0x00,0xf9,0x02,0x3e,0xc0,0x4f,0xb0,0x03,0xe1,0x00 } }, +{ 16, 0x89b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x10,0xff,0x00,0xce,0x00,0x33,0xc0 } }, +{ 16, 0x89c0, 0, {0x0e,0xc0,0x07,0x74,0x04,0xec,0x00,0x11,0x80,0x0c,0xca,0x03,0xfe,0x60,0xff,0x00 } }, +{ 16, 0x89d0, 0, {0x3f,0xc0,0x0f,0xf0,0x83,0x3c,0x00,0xdd,0x00,0xb3,0x50,0x2c,0xf0,0x03,0x20,0x04 } }, +{ 16, 0x89e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x00,0x4c,0x04,0x8b,0x0b,0x22,0x70 } }, +{ 16, 0x89f0, 0, {0x08,0x08,0x03,0x67,0x20,0x8a,0x88,0xa2,0x00,0x28,0x84,0x02,0xe7,0x00,0xbb,0x00 } }, +{ 16, 0x8a00, 0, {0x3e,0xc0,0x0b,0xb0,0x02,0x2c,0x00,0xb9,0x00,0x22,0x61,0x08,0xb0,0x03,0x60,0x40 } }, +{ 16, 0x8a10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x8b,0x20,0x22,0xe2 } }, +{ 16, 0x8a20, 0, {0x0a,0x8c,0x02,0x26,0x00,0xa9,0x80,0x2a,0xc0,0x08,0xb4,0x42,0xed,0x00,0xbb,0x00 } }, +{ 16, 0x8a30, 0, {0x2e,0xc0,0x0b,0x30,0x02,0x2c,0x00,0xb9,0x00,0x20,0x80,0x08,0x30,0x02,0x60,0x00 } }, +{ 16, 0x8a40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0e,0x01,0x81,0x00,0xa0,0xc0 } }, +{ 16, 0x8a50, 0, {0x08,0x81,0x02,0x44,0x00,0x81,0x00,0x28,0x81,0x08,0x32,0x02,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0x8a60, 0, {0x28,0xc0,0x0b,0x30,0x02,0x0c,0x80,0xb1,0x00,0x20,0xc0,0x08,0x30,0x12,0x42,0x01 } }, +{ 16, 0x8a70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0d,0x6c,0x00,0xc2,0x01,0x32,0xc0 } }, +{ 16, 0x8a80, 0, {0x2e,0x80,0x16,0x2c,0x08,0xe9,0x00,0x3a,0x40,0x0c,0x80,0x03,0xec,0x00,0xf7,0x00 } }, +{ 16, 0x8a90, 0, {0x2f,0xc0,0x0f,0xf0,0x0b,0x2c,0x00,0xd9,0x00,0x30,0x40,0x0c,0xf0,0x03,0x60,0x03 } }, +{ 16, 0x8aa0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x0d,0xf8,0x08,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0x8ab0, 0, {0x0f,0xc2,0x17,0xfc,0x00,0xf7,0x00,0x37,0x00,0x0f,0x84,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0x8ac0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xed,0x00,0xfd,0x00,0x3f,0x40,0x0f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0x8ad0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x00,0xcf,0x30,0x17,0x48 } }, +{ 16, 0x8ae0, 0, {0x0c,0x59,0x03,0xb9,0x00,0xdf,0x28,0x35,0x24,0x0d,0x82,0xa3,0x7c,0x80,0xff,0x00 } }, +{ 16, 0x8af0, 0, {0x3f,0xc8,0x0f,0xf2,0x03,0xe4,0xa0,0xef,0x80,0x3f,0xe1,0x8c,0xd8,0x43,0x30,0x00 } }, +{ 16, 0x8b00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xed,0x48,0x89,0x34,0xa3,0x70 } }, +{ 16, 0x8b10, 0, {0x28,0xb0,0x23,0x60,0x00,0x8b,0xc0,0x22,0x40,0x08,0xb4,0x82,0x2f,0x40,0xbf,0xd1 } }, +{ 16, 0x8b20, 0, {0x6f,0xf4,0x8e,0xbd,0x02,0xe7,0x00,0xbb,0x80,0x3a,0xe0,0x08,0x98,0x0a,0x28,0x04 } }, +{ 16, 0x8b30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc4,0xb0,0x91,0x00,0xa8,0x50 } }, +{ 16, 0x8b40, 0, {0x08,0xb2,0x02,0xc8,0x84,0x93,0x00,0x24,0x49,0x0b,0x02,0x02,0x4c,0x00,0xb3,0x04 } }, +{ 16, 0x8b50, 0, {0x2c,0xc0,0x0b,0x30,0x42,0x84,0x00,0xb3,0x00,0x2e,0x00,0x0a,0xb0,0x12,0x22,0x01 } }, +{ 16, 0x8b60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x11,0xac,0x02,0x99,0x18,0x2a,0x44 } }, +{ 16, 0x8b70, 0, {0x08,0xb8,0x82,0xa2,0x01,0xbb,0x00,0x28,0x60,0x0a,0xa0,0x12,0x6c,0x00,0xbb,0x00 } }, +{ 16, 0x8b80, 0, {0x6e,0xc0,0x0a,0xb0,0x02,0xe4,0x00,0xbb,0x00,0x2a,0x00,0x2a,0xb0,0x02,0x38,0x04 } }, +{ 16, 0x8b90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x11,0xe4,0x08,0xda,0xc0,0x3a,0x60 } }, +{ 16, 0x8ba0, 0, {0x0c,0x18,0x0a,0xeb,0x04,0xdb,0x00,0x36,0xe0,0x07,0x85,0x83,0x6c,0x00,0xfb,0x00 } }, +{ 16, 0x8bb0, 0, {0x2e,0xc0,0x0f,0xb0,0x43,0xe4,0x00,0xeb,0x00,0x3e,0x88,0x0e,0x18,0x03,0x10,0x04 } }, +{ 16, 0x8bc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x41,0x9c,0x10,0xe9,0x00,0x37,0x60 } }, +{ 16, 0x8bd0, 0, {0x87,0xf0,0x17,0x70,0x00,0xcf,0x01,0x37,0xc0,0x4c,0x98,0x03,0xbc,0x00,0xfb,0x00 } }, +{ 16, 0x8be0, 0, {0x3f,0xc2,0x0f,0xf0,0x03,0xe4,0x00,0xff,0x40,0x3f,0xe4,0x0d,0xd9,0x03,0xf0,0x00 } }, +{ 16, 0x8bf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa4,0x00,0xf4,0x00,0x30,0x40 } }, +{ 16, 0x8c00, 0, {0x0f,0xb4,0x03,0x99,0x00,0xfb,0x00,0x3e,0xc0,0x0d,0x04,0x23,0x2c,0x08,0xfb,0x88 } }, +{ 16, 0x8c10, 0, {0x32,0xc0,0x0f,0xb0,0x03,0xe6,0x00,0xdb,0x10,0x3e,0x02,0x0f,0xb0,0x83,0xd0,0x04 } }, +{ 16, 0x8c20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0xb9,0x50,0xa2,0x48 } }, +{ 16, 0x8c30, 0, {0x8b,0xb0,0x03,0x20,0x00,0xd7,0x80,0x2e,0xd8,0x00,0x80,0x02,0x3c,0x00,0xbf,0x80 } }, +{ 16, 0x8c40, 0, {0x23,0xe8,0x8b,0xf0,0x02,0xf4,0x40,0x8b,0x40,0x0c,0x42,0x03,0xb6,0x02,0xf2,0x00 } }, +{ 16, 0x8c50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb2,0x44,0x00,0xc8 } }, +{ 16, 0x8c60, 0, {0x0b,0x30,0x12,0x8c,0x00,0xa3,0x80,0x24,0xc8,0x0b,0x00,0x0a,0xcc,0x00,0xb3,0x44 } }, +{ 16, 0x8c70, 0, {0x04,0xc0,0x1b,0x36,0x02,0xc5,0x01,0x83,0x0c,0x2c,0xa0,0x0b,0x30,0x02,0xf8,0x00 } }, +{ 16, 0x8c80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x08,0xb7,0x90,0x21,0x64 } }, +{ 16, 0x8c90, 0, {0x0b,0xf8,0x02,0x4a,0x04,0x97,0x81,0x2f,0xe4,0x0a,0x78,0x02,0x9e,0x00,0xb7,0x80 } }, +{ 16, 0x8ca0, 0, {0x21,0xe0,0x8b,0x78,0x82,0xd6,0x86,0x87,0x84,0x2d,0xa0,0x0b,0x78,0x02,0xc0,0x00 } }, +{ 16, 0x8cb0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x04,0x00,0xf2,0x00,0x30,0xc0 } }, +{ 16, 0x8cc0, 0, {0x0f,0x30,0x03,0x8c,0x00,0xe3,0x0a,0x3c,0xc0,0x0f,0x18,0x03,0x8c,0x00,0xf3,0x02 } }, +{ 16, 0x8cd0, 0, {0x30,0xc0,0x1f,0x30,0x01,0xc6,0x80,0xc3,0x00,0x3c,0xc0,0x0f,0x12,0x03,0xda,0x02 } }, +{ 16, 0x8ce0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x0d,0xbc,0x00,0xff,0x00,0x3f,0x41 } }, +{ 16, 0x8cf0, 0, {0x0f,0xf0,0x03,0xb8,0x08,0xff,0x08,0x3f,0xc0,0x0d,0xf0,0x03,0x3c,0x20,0xff,0x08 } }, +{ 16, 0x8d00, 0, {0x3b,0xd2,0x0f,0xf0,0x03,0xf4,0x40,0xef,0x00,0x3f,0xc4,0x0f,0xd0,0x03,0xd0,0x06 } }, +{ 16, 0x8d10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe4,0x00,0xfe,0x00,0x32,0xc2 } }, +{ 16, 0x8d20, 0, {0x0c,0x30,0x0b,0x26,0x00,0xfb,0x80,0x36,0xc0,0x0d,0xa0,0x03,0xec,0x00,0xfb,0xe0 } }, +{ 16, 0x8d30, 0, {0x32,0xd0,0x0f,0xb8,0x43,0x64,0x44,0xdb,0x04,0x3e,0x80,0x0f,0xb0,0x03,0xe2,0x00 } }, +{ 16, 0x8d40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0xb7,0x00,0xa1,0xc0 } }, +{ 16, 0x8d50, 0, {0x88,0x70,0x03,0x10,0x00,0xb7,0x20,0x21,0xc0,0x08,0x70,0x02,0xdc,0x80,0xb3,0x30 } }, +{ 16, 0x8d60, 0, {0x31,0xc8,0x0b,0x74,0x02,0x14,0x00,0x87,0x40,0x2d,0xc0,0x4b,0x70,0x02,0xd2,0x00 } }, +{ 16, 0x8d70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x96,0x20,0xb6,0x80,0x20,0xe0 } }, +{ 16, 0x8d80, 0, {0x28,0xf8,0x02,0x94,0x10,0xb7,0x81,0x27,0xe2,0x09,0x78,0x02,0xde,0x00,0xb7,0xa0 } }, +{ 16, 0x8d90, 0, {0xa9,0xe8,0x0b,0x38,0x02,0x76,0x00,0x87,0x80,0x2d,0xa0,0x0b,0x58,0x02,0xf0,0x00 } }, +{ 16, 0x8da0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xce,0x10,0xb3,0x00,0x20,0xc4 } }, +{ 16, 0x8db0, 0, {0x08,0x20,0x02,0x80,0x10,0xb3,0x00,0x22,0xc8,0x08,0xb0,0x02,0xcc,0x11,0xb3,0x02 } }, +{ 16, 0x8dc0, 0, {0x28,0xc0,0x0b,0x30,0x02,0x04,0x00,0x93,0x80,0x2c,0xd2,0x0b,0x10,0x02,0xd2,0x04 } }, +{ 16, 0x8dd0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xfe,0x40,0x32,0xa0 } }, +{ 16, 0x8de0, 0, {0x0c,0xe4,0x03,0x98,0x80,0xfa,0x00,0x37,0xa0,0x0d,0xe0,0x83,0xe8,0x00,0xfe,0x00 } }, +{ 16, 0x8df0, 0, {0x3a,0x80,0x0b,0xa0,0x03,0x68,0x00,0xd8,0xa0,0x3f,0x90,0x0f,0xa0,0x03,0xfa,0x04 } }, +{ 16, 0x8e00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x08,0xf8,0x08,0x3e,0x00 } }, +{ 16, 0x8e10, 0, {0x0f,0x80,0x03,0x20,0x00,0xf8,0x40,0x3e,0x00,0x0f,0x80,0x03,0xe0,0x00,0xf8,0x04 } }, +{ 16, 0x8e20, 0, {0x30,0x10,0x0f,0x80,0x03,0xe0,0x02,0xe8,0x00,0x3e,0x00,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0x8e30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xf1,0x00,0x32,0x40 } }, +{ 16, 0x8e40, 0, {0x0e,0x90,0x83,0xa4,0x00,0xc9,0x80,0x3e,0x40,0x0e,0x90,0x03,0xa4,0x00,0xf9,0x00 } }, +{ 16, 0x8e50, 0, {0x3e,0x40,0x0c,0x90,0x03,0xe4,0x00,0xc8,0x00,0x3e,0x40,0x8f,0x90,0x03,0x02,0x04 } }, +{ 16, 0x8e60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x40,0xa0,0x62 } }, +{ 16, 0x8e70, 0, {0x08,0x10,0x02,0x24,0x10,0x89,0x00,0x2e,0x40,0x08,0x90,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0x8e80, 0, {0x2e,0x52,0x08,0x94,0x02,0xc4,0x00,0x89,0x40,0x2e,0x40,0x0b,0x10,0x03,0x60,0x10 } }, +{ 16, 0x8e90, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb9,0x18,0x22,0x44 } }, +{ 16, 0x8ea0, 0, {0x0a,0x90,0x02,0xac,0x00,0x89,0x10,0x2e,0xc0,0x0a,0x90,0x02,0xa4,0x00,0xb9,0x80 } }, +{ 16, 0x8eb0, 0, {0x2e,0x60,0x08,0x98,0x02,0xe6,0x02,0x89,0x08,0x2e,0x40,0x0b,0x90,0x02,0x06,0x00 } }, +{ 16, 0x8ec0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x80,0xb1,0x20,0xa0,0x48 } }, +{ 16, 0x8ed0, 0, {0x08,0x90,0x02,0x24,0x08,0x81,0x23,0x2c,0x50,0x08,0x10,0x02,0x04,0x80,0xb1,0x20 } }, +{ 16, 0x8ee0, 0, {0x2c,0x48,0x28,0x12,0x02,0xe4,0x80,0x81,0x20,0x2c,0x40,0x0b,0x98,0x02,0x42,0x05 } }, +{ 16, 0x8ef0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xf8,0x50,0x32,0x00 } }, +{ 16, 0x8f00, 0, {0x0e,0x85,0x03,0xa1,0xe0,0xca,0x00,0x3e,0x00,0x0e,0x85,0x03,0xa0,0x00,0xf8,0x00 } }, +{ 16, 0x8f10, 0, {0x2e,0x00,0x9c,0xa0,0x03,0xe0,0x00,0xc8,0x28,0x3e,0x00,0x0f,0x80,0x03,0x2e,0x01 } }, +{ 16, 0x8f20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x40,0xf5,0x10,0x3f,0x44 } }, +{ 16, 0x8f30, 0, {0x0f,0xd0,0x03,0xf4,0x00,0xf1,0x10,0x3d,0x40,0x8f,0xd4,0x03,0xe4,0x50,0xf9,0x10 } }, +{ 16, 0x8f40, 0, {0x3e,0x45,0x0f,0x91,0x03,0xd4,0x40,0xfc,0x00,0x3f,0xc0,0x8f,0xd0,0x23,0xe6,0x04 } }, +{ 16, 0x8f50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe6,0x20,0xcd,0xa8,0x33,0x40 } }, +{ 16, 0x8f60, 0, {0x8d,0xd0,0x03,0x26,0x80,0xcd,0x00,0x3d,0x50,0x0c,0x9a,0x03,0x64,0x00,0xf9,0xa0 } }, +{ 16, 0x8f70, 0, {0x7a,0x6a,0x0f,0x9a,0x63,0xe6,0x80,0xc9,0x80,0x3e,0x40,0x0f,0x90,0x03,0x06,0x00 } }, +{ 16, 0x8f80, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x00,0x88,0xe0,0x36,0x00 } }, +{ 16, 0x8f90, 0, {0x08,0x80,0x0a,0x21,0x42,0xc8,0x00,0x2e,0x29,0x0c,0xa4,0x42,0x20,0x00,0xb8,0x40 } }, +{ 16, 0x8fa0, 0, {0x2e,0x00,0x0b,0x81,0x02,0xe1,0x00,0x88,0x02,0x3a,0x01,0x0b,0xc0,0x02,0x0e,0x04 } }, +{ 16, 0x8fb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x02,0x81,0x08,0x24,0x40 } }, +{ 16, 0x8fc0, 0, {0x09,0x10,0x02,0x04,0x00,0x91,0x00,0x2c,0x40,0x4b,0x14,0x02,0x44,0x00,0xb5,0x10 } }, +{ 16, 0x8fd0, 0, {0x29,0x40,0x0b,0x50,0x02,0xf5,0x00,0xb5,0x00,0x2d,0x40,0x0b,0xd0,0x02,0x02,0x01 } }, +{ 16, 0x8fe0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa6,0x01,0x89,0x00,0x26,0x40 } }, +{ 16, 0x8ff0, 0, {0x08,0x94,0x02,0x24,0x01,0x89,0x00,0x2e,0x40,0x1a,0x90,0x02,0x6c,0x00,0xbf,0x02 } }, +{ 16, 0x9000, 0, {0x2f,0x40,0x0b,0xd0,0x02,0xf4,0x02,0xbd,0x80,0x2b,0x40,0x8b,0xd8,0x3a,0x06,0x04 } }, +{ 16, 0x9010, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xc9,0x05,0x36,0x41 } }, +{ 16, 0x9020, 0, {0x0d,0x1c,0x03,0x24,0x00,0xd9,0x00,0x3e,0x42,0x2f,0x94,0x03,0x64,0x00,0xf9,0x00 } }, +{ 16, 0x9030, 0, {0x3a,0x40,0x0f,0x90,0x03,0xc4,0x00,0xf9,0x00,0x3e,0x70,0x0f,0x10,0x03,0x28,0x04 } }, +{ 16, 0x9040, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x84,0x08,0xf9,0x24,0x3e,0x40 } }, +{ 16, 0x9050, 0, {0x0f,0x91,0x03,0xe4,0x00,0xf9,0x00,0x3e,0x41,0x0d,0x10,0x03,0xa4,0x00,0xf9,0x00 } }, +{ 16, 0x9060, 0, {0x3e,0x40,0x0f,0x90,0x03,0xe4,0x00,0xc9,0x00,0x3e,0x64,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0x9070, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x08,0xc8,0x80,0x32,0x02 } }, +{ 16, 0x9080, 0, {0x0f,0x80,0x03,0x00,0x00,0xc8,0x08,0x3a,0x10,0xce,0x84,0x03,0xe0,0x00,0xfc,0x00 } }, +{ 16, 0x9090, 0, {0x3f,0x00,0x8f,0xc0,0x03,0xf0,0x80,0xfc,0x00,0x3f,0x18,0x0f,0xc0,0x43,0xca,0x04 } }, +{ 16, 0x90a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x8e,0x00,0xa1,0x80 } }, +{ 16, 0x90b0, 0, {0x0b,0xe0,0x02,0x28,0x00,0xde,0xc2,0x23,0x90,0x00,0xa0,0x02,0xe8,0x00,0xba,0x00 } }, +{ 16, 0x90c0, 0, {0x2e,0x80,0x0b,0xa0,0x02,0xe8,0x00,0xfa,0x00,0x2e,0x80,0x0b,0xa0,0x02,0xca,0x00 } }, +{ 16, 0x90d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x99,0x81,0x60,0xc0 } }, +{ 16, 0x90e0, 0, {0x0b,0x10,0x02,0x0c,0x00,0x90,0x10,0x2a,0xfc,0x0b,0x30,0x02,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0x90f0, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x00,0xb3,0x00,0x2c,0xc0,0x0b,0x30,0x02,0xca,0x00 } }, +{ 16, 0x9100, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x82,0x95,0x40,0x21,0xc0 } }, +{ 16, 0x9110, 0, {0x0b,0x50,0x02,0x1c,0x80,0x90,0x80,0x23,0x01,0x09,0x72,0x12,0xdc,0x00,0xb6,0x00 } }, +{ 16, 0x9120, 0, {0x2d,0x00,0x0b,0x40,0x02,0xd0,0x00,0xb4,0x09,0x2d,0x00,0x4b,0x40,0x82,0xe8,0x00 } }, +{ 16, 0x9130, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x3e,0x80,0xdd,0x80,0xb1,0xe0 } }, +{ 16, 0x9140, 0, {0x0f,0xda,0x03,0x0f,0x80,0xd4,0x80,0x39,0xe0,0x0b,0x7a,0x03,0xde,0x00,0xf5,0x80 } }, +{ 16, 0x9150, 0, {0x3d,0x20,0x0f,0x48,0x03,0xd6,0x10,0xf6,0x81,0x3d,0xe0,0x8f,0x68,0x03,0xea,0x02 } }, +{ 16, 0x9160, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xed,0x00,0x3e,0x00 } }, +{ 16, 0x9170, 0, {0x0f,0x91,0x0b,0xec,0x10,0xf8,0x00,0x3e,0x00,0x0e,0xb0,0x03,0xec,0x00,0xf8,0x00 } }, +{ 16, 0x9180, 0, {0x3e,0xc0,0x4f,0xb0,0x03,0xe8,0x00,0xe9,0x01,0x3e,0x00,0x0f,0x90,0x03,0xc2,0x06 } }, +{ 16, 0x9190, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x20,0xbf,0x81,0x33,0xa4 } }, +{ 16, 0x91a0, 0, {0x8c,0x19,0x03,0x3e,0x00,0xcd,0x80,0x3f,0xe0,0x0f,0xf8,0x83,0x3e,0x00,0xef,0x80 } }, +{ 16, 0x91b0, 0, {0x3f,0xe0,0x0f,0xf9,0x13,0xfa,0x10,0xfd,0x80,0x3f,0xa4,0x0f,0xd8,0x03,0xc0,0x00 } }, +{ 16, 0x91c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xbf,0x20,0x31,0xc2 } }, +{ 16, 0x91d0, 0, {0x08,0x5a,0x02,0x3c,0x02,0x87,0x00,0x2d,0x94,0x0b,0x70,0x0a,0x1c,0x40,0x86,0x10 } }, +{ 16, 0x91e0, 0, {0x2d,0x00,0x0b,0x40,0x02,0xd4,0x00,0xf6,0x00,0x2d,0x40,0x4b,0x60,0x02,0xea,0x04 } }, +{ 16, 0x91f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xb7,0x01,0x23,0x80 } }, +{ 16, 0x9200, 0, {0x28,0x50,0x02,0x1c,0x00,0x84,0x00,0x2d,0xc0,0x0b,0x30,0x02,0x1c,0x00,0xb5,0x00 } }, +{ 16, 0x9210, 0, {0x2d,0x00,0x0b,0x40,0x06,0xd0,0x40,0xb4,0x08,0x2d,0x80,0x0b,0x48,0x02,0xc0,0x00 } }, +{ 16, 0x9220, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x00,0xb3,0x08,0xa0,0x20 } }, +{ 16, 0x9230, 0, {0x08,0x11,0x8a,0x0e,0x00,0x80,0x00,0x2c,0x90,0x0b,0x37,0x02,0x0c,0x00,0x90,0x00 } }, +{ 16, 0x9240, 0, {0x2c,0xc0,0x0b,0x30,0x42,0xcc,0x04,0xa3,0x80,0x2c,0x50,0x0b,0x30,0x02,0xc8,0x04 } }, +{ 16, 0x9250, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xf9,0x80,0x32,0x60 } }, +{ 16, 0x9260, 0, {0x0c,0xd4,0x03,0x3c,0x80,0x88,0x00,0x3e,0xd0,0x0f,0xf8,0x03,0x28,0x00,0xfa,0x00 } }, +{ 16, 0x9270, 0, {0x3e,0xc0,0x0f,0xb0,0x07,0xec,0x01,0xbb,0x80,0x3e,0x54,0x0f,0xb0,0x06,0xea,0x04 } }, +{ 16, 0x9280, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xee,0x08,0xf9,0x80,0x3a,0xc0 } }, +{ 16, 0x9290, 0, {0x0f,0x90,0x03,0xec,0x00,0xf8,0x40,0x3e,0x58,0x0f,0xb0,0x43,0xe9,0x00,0xeb,0x44 } }, +{ 16, 0x92a0, 0, {0x3e,0x00,0x0f,0x80,0x03,0xe0,0x0d,0xf8,0x00,0x3e,0x80,0x0f,0x80,0x03,0xe0,0x00 } }, +{ 16, 0x92b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xdc,0x00,0xcf,0x00,0x33,0x40 } }, +{ 16, 0x92c0, 0, {0x0c,0xd0,0x03,0x3c,0x30,0xcc,0x00,0x3b,0xc0,0x2d,0xf0,0x03,0xd8,0x02,0xcc,0x00 } }, +{ 16, 0x92d0, 0, {0x3d,0x00,0x0c,0xc0,0x03,0xf4,0x00,0xee,0x02,0x37,0x40,0x0c,0xe0,0x03,0xc0,0x44 } }, +{ 16, 0x92e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x18,0x83,0x84,0x20,0x00 } }, +{ 16, 0x92f0, 0, {0x4a,0x10,0x02,0x0c,0x00,0xa8,0x48,0x2e,0x60,0x08,0xb0,0x02,0xe9,0x00,0x89,0x40 } }, +{ 16, 0x9300, 0, {0x2e,0xc0,0x08,0xb0,0x02,0xe8,0x10,0xb1,0x01,0x20,0x80,0x0a,0x90,0x03,0xa0,0x40 } }, +{ 16, 0x9310, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x8b,0x82,0x22,0x08 } }, +{ 16, 0x9320, 0, {0x08,0x90,0x02,0x2c,0x14,0x88,0x04,0x2c,0x08,0x08,0xb0,0x12,0xe8,0x00,0x8a,0x00 } }, +{ 16, 0x9330, 0, {0x2e,0xc0,0x0a,0xb0,0x02,0xe8,0x01,0xb9,0x00,0x26,0x04,0x08,0x90,0x02,0xe0,0x00 } }, +{ 16, 0x9340, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0x83,0x80,0xa2,0xc0 } }, +{ 16, 0x9350, 0, {0x0a,0x92,0x02,0x2c,0x00,0xa2,0x00,0x2c,0x00,0x08,0x34,0x02,0xc8,0x00,0x83,0x00 } }, +{ 16, 0x9360, 0, {0x2c,0x00,0x28,0x00,0x02,0xc4,0x01,0xba,0x00,0x22,0xc0,0x02,0x20,0x06,0xc2,0x01 } }, +{ 16, 0x9370, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xca,0x00,0xb2,0x00 } }, +{ 16, 0x9380, 0, {0x0c,0x92,0x0b,0x2c,0x04,0xc8,0x04,0x3a,0x00,0x0c,0xb4,0x03,0xe8,0x00,0xc8,0x00 } }, +{ 16, 0x9390, 0, {0x2e,0x00,0x0c,0x80,0x33,0xe1,0x40,0xe8,0x00,0x36,0x00,0x0c,0x80,0x03,0xc0,0x03 } }, +{ 16, 0x93a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xff,0x00,0x3d,0x00 } }, +{ 16, 0x93b0, 0, {0x0f,0xd1,0x0b,0xfc,0x01,0xfc,0x00,0x3f,0x00,0x0f,0xf0,0x03,0xd8,0x00,0xfd,0x00 } }, +{ 16, 0x93c0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xfc,0x80,0xff,0x00,0x3f,0xc0,0x0f,0xf0,0x07,0xa8,0x06 } }, +{ 16, 0x93d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xf3,0x00,0xcf,0x80,0x35,0x60 } }, +{ 16, 0x93e0, 0, {0x4e,0x68,0x43,0x5c,0x00,0xe7,0x80,0x39,0xc0,0x0c,0xc1,0x03,0x7e,0x00,0xcf,0x34 } }, +{ 16, 0x93f0, 0, {0x35,0xe1,0x4d,0xf2,0x03,0x7c,0x00,0xdf,0x38,0x3f,0xc8,0x0f,0xf8,0x03,0xf0,0x00 } }, +{ 16, 0x9400, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x18,0xc8,0x00,0xdb,0x84,0x22,0x60 } }, +{ 16, 0x9410, 0, {0x08,0xac,0x0a,0x2c,0x00,0x8b,0x80,0x22,0x30,0x08,0x91,0x22,0x2c,0x90,0x27,0x61 } }, +{ 16, 0x9420, 0, {0x22,0xca,0x88,0xfc,0x22,0xbf,0x00,0x8b,0x62,0x2f,0xd0,0x09,0xb8,0x03,0xb0,0x04 } }, +{ 16, 0x9430, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0xe2,0x80,0xa9,0x02,0x24,0x40 } }, +{ 16, 0x9440, 0, {0x82,0x34,0x42,0x04,0x00,0xa9,0x00,0x28,0xc5,0x48,0x32,0x02,0x4c,0x20,0x83,0x30 } }, +{ 16, 0x9450, 0, {0x20,0xc0,0x08,0x31,0x02,0x0d,0x00,0xb3,0x20,0x2c,0xc4,0x0b,0x30,0x02,0xf2,0x01 } }, +{ 16, 0x9460, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xaa,0x02,0xb9,0x04,0x22,0x60 } }, +{ 16, 0x9470, 0, {0x28,0xb2,0x02,0x26,0x00,0x89,0x88,0x02,0xc0,0x08,0x31,0x12,0xec,0x00,0x8b,0x00 } }, +{ 16, 0x9480, 0, {0x2a,0xd0,0x08,0xb0,0x02,0xac,0x00,0x2b,0x00,0x2e,0xc0,0x0b,0xb0,0x02,0xb0,0x04 } }, +{ 16, 0x9490, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xe2,0x00,0xe3,0x00,0x36,0x20 } }, +{ 16, 0x94a0, 0, {0x0e,0xa4,0x63,0x6e,0x00,0xe1,0xc0,0x1a,0xc1,0x0c,0x80,0x03,0x68,0x70,0xcb,0x00 } }, +{ 16, 0x94b0, 0, {0x36,0x80,0x0d,0xb0,0x03,0x4c,0x00,0xfb,0x04,0x3e,0xc1,0x0f,0xb0,0x03,0xd0,0x04 } }, +{ 16, 0x94c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb8,0x04,0xdf,0x00,0x3f,0x00 } }, +{ 16, 0x94d0, 0, {0x0f,0xe8,0x03,0xfc,0x00,0xfd,0x00,0x3f,0x00,0x2b,0x98,0x03,0x3a,0x00,0x77,0x00 } }, +{ 16, 0x94e0, 0, {0x27,0xe4,0x0f,0xf0,0x03,0xfc,0x00,0xdf,0x00,0x3e,0xc0,0x0d,0xf0,0x43,0xf8,0x00 } }, +{ 16, 0x94f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0xa4,0x68,0xcb,0x20,0x3a,0x90 } }, +{ 16, 0x9500, 0, {0x0f,0x24,0xa3,0xac,0x00,0xe9,0x50,0x3a,0xc0,0x0e,0xb4,0x83,0x2c,0x08,0xeb,0x00 } }, +{ 16, 0x9510, 0, {0x3a,0x90,0x0e,0xb0,0x8b,0xec,0x80,0xfb,0x00,0x3e,0xc0,0x0e,0xb0,0x03,0x90,0x04 } }, +{ 16, 0x9520, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x01,0x0a,0x00,0x8b,0xa0,0x20,0x80 } }, +{ 16, 0x9530, 0, {0x0d,0xa8,0x02,0x2c,0x04,0x89,0x40,0x28,0xe8,0x08,0xb2,0x02,0x2c,0x00,0xaf,0x00 } }, +{ 16, 0x9540, 0, {0x02,0x80,0x08,0x7c,0x03,0x3d,0x80,0x3f,0x00,0x2f,0xc0,0x08,0xb0,0x02,0x36,0x00 } }, +{ 16, 0x9550, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x49,0x00,0x03,0x40,0x28,0xc0 } }, +{ 16, 0x9560, 0, {0x2b,0x28,0x4a,0x28,0x00,0xa1,0x00,0x68,0xd2,0x0a,0x20,0x42,0xa4,0x01,0xa3,0x00 } }, +{ 16, 0x9570, 0, {0x02,0x40,0x0a,0x34,0x02,0x0d,0x00,0x33,0x00,0x2c,0xc0,0x0a,0x30,0x00,0xb8,0x00 } }, +{ 16, 0x9580, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x01,0x1a,0x00,0x87,0x90,0x21,0xe4 } }, +{ 16, 0x9590, 0, {0x2b,0xc8,0x12,0x3a,0x00,0x85,0xc0,0x2b,0x21,0x28,0x68,0x02,0xb6,0x00,0xa7,0x84 } }, +{ 16, 0x95a0, 0, {0x23,0x60,0x08,0x38,0x80,0x1e,0x00,0xb7,0x80,0x2d,0xe0,0x08,0x78,0x02,0x2e,0x00 } }, +{ 16, 0x95b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x08,0x00,0xc1,0x00,0x38,0x54 } }, +{ 16, 0x95c0, 0, {0x0f,0x26,0x83,0x80,0x00,0xe0,0x34,0x28,0xc8,0x0e,0x2c,0x0b,0x8c,0x00,0xe3,0x00 } }, +{ 16, 0x95d0, 0, {0x78,0x45,0x0e,0x30,0x03,0x8e,0x80,0xf3,0x00,0x3c,0xc8,0x0e,0x30,0x03,0x92,0x02 } }, +{ 16, 0x95e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xb8,0x00,0xf5,0x02,0x3f,0x44 } }, +{ 16, 0x95f0, 0, {0x0d,0x90,0x03,0xf8,0x00,0xbd,0x14,0x1f,0xc0,0x0f,0xe1,0x23,0x5c,0x44,0x9f,0x42 } }, +{ 16, 0x9600, 0, {0x3f,0xc0,0x0f,0xf4,0x82,0x7d,0x40,0xff,0x10,0x3f,0xc0,0x4f,0x70,0x07,0xd0,0x06 } }, +{ 16, 0x9610, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe8,0x02,0xcb,0x00,0x38,0xc0 } }, +{ 16, 0x9620, 0, {0x3c,0xa0,0x03,0xec,0x00,0xe9,0x00,0x3e,0xc0,0x0c,0xb0,0x03,0x20,0x04,0xfb,0x21 } }, +{ 16, 0x9630, 0, {0x3e,0x80,0x4f,0xb4,0x03,0xcf,0x00,0xcb,0x00,0x3e,0xcc,0x4f,0xb0,0x43,0xea,0x00 } }, +{ 16, 0x9640, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x91,0x98,0x00,0x87,0x00,0x21,0xc0 } }, +{ 16, 0x9650, 0, {0x08,0x40,0x02,0xdc,0x04,0xb5,0x00,0x2d,0x00,0x2d,0x70,0x02,0x1c,0x1c,0xb7,0x02 } }, +{ 16, 0x9660, 0, {0x2d,0xc0,0x0b,0x72,0x02,0xdc,0x00,0x87,0x40,0x2d,0xca,0x8b,0x70,0x02,0xf2,0x04 } }, +{ 16, 0x9670, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xba,0x00,0x87,0x88,0x2b,0xe0 } }, +{ 16, 0x9680, 0, {0x18,0x78,0x22,0xd6,0x11,0xa4,0x82,0x2f,0xe0,0x08,0x78,0x02,0x12,0x00,0xb7,0x94 } }, +{ 16, 0x9690, 0, {0x6d,0x60,0x4b,0x7a,0x02,0xde,0x40,0xb7,0xa0,0x2d,0xe0,0x0b,0x78,0x06,0xe0,0x00 } }, +{ 16, 0x96a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xc9,0x12,0x83,0x82,0x28,0xd4 } }, +{ 16, 0x96b0, 0, {0x98,0x00,0x06,0xef,0x05,0xb1,0x90,0x2c,0xc1,0x09,0xb4,0x02,0x0c,0x04,0xb3,0x01 } }, +{ 16, 0x96c0, 0, {0x6c,0xf0,0x0b,0x30,0x02,0xcc,0x00,0xbb,0x00,0x2e,0xc0,0x0b,0x30,0x02,0xd2,0x04 } }, +{ 16, 0x96d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xb8,0x40,0xca,0x80,0x3b,0xa0 } }, +{ 16, 0x96e0, 0, {0x4c,0xe5,0x02,0xf8,0x80,0xee,0x00,0x3d,0x80,0x2c,0xe0,0x0f,0x38,0x80,0xfa,0x00 } }, +{ 16, 0x96f0, 0, {0x3f,0xa9,0x0f,0xa0,0x03,0xe8,0x00,0xba,0x02,0x3e,0x80,0x8b,0xa0,0x03,0xfa,0x04 } }, +{ 16, 0x9700, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x10,0xf8,0x00,0x26,0x02 } }, +{ 16, 0x9710, 0, {0x0f,0x84,0x03,0xe0,0x24,0xf8,0x00,0x3e,0x00,0x4f,0x80,0xa3,0xe0,0x30,0xf8,0x00 } }, +{ 16, 0x9720, 0, {0x36,0x02,0x0f,0x80,0x23,0xe0,0x04,0x08,0x00,0x3e,0x00,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0x9730, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xd9,0x00,0xb6,0x41 } }, +{ 16, 0x9740, 0, {0x4e,0x99,0x0b,0xa4,0x00,0x69,0x10,0x3e,0x40,0x0c,0x90,0x03,0xa4,0x10,0xc9,0x00 } }, +{ 16, 0x9750, 0, {0x3e,0x40,0x0d,0x92,0x03,0xe6,0x00,0xf9,0x00,0x3a,0x40,0x0e,0x90,0x03,0xc2,0x04 } }, +{ 16, 0x9760, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x81,0x00,0x20,0x42 } }, +{ 16, 0x9770, 0, {0x08,0x14,0x9a,0x24,0x00,0x89,0x00,0x6e,0x50,0x00,0x90,0x02,0x24,0x10,0xd9,0x02 } }, +{ 16, 0x9780, 0, {0x6e,0x40,0x0b,0x94,0x03,0xa7,0x00,0xb9,0x00,0x22,0x40,0x08,0x90,0x03,0xe0,0x00 } }, +{ 16, 0x9790, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x06,0x00,0x99,0x00,0xa6,0x41 } }, +{ 16, 0x97a0, 0, {0x0a,0x90,0x06,0x2c,0x00,0xa9,0x09,0x6e,0x50,0x08,0x91,0x02,0x84,0x04,0x89,0x00 } }, +{ 16, 0x97b0, 0, {0x0e,0x40,0x0b,0x94,0x02,0xe5,0x49,0xb9,0x00,0x0a,0x40,0x0a,0x90,0x02,0xc6,0x00 } }, +{ 16, 0x97c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x06,0x00,0x81,0x00,0x22,0x40 } }, +{ 16, 0x97d0, 0, {0x08,0x12,0x22,0x04,0x81,0xa1,0x00,0x2c,0x40,0x08,0x16,0x02,0x04,0x00,0x91,0x20 } }, +{ 16, 0x97e0, 0, {0x2c,0x40,0x0b,0x12,0x42,0x84,0x89,0xb1,0x20,0x20,0x48,0x08,0x10,0x02,0xc2,0x01 } }, +{ 16, 0x97f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xd8,0x00,0x36,0x00 } }, +{ 16, 0x9800, 0, {0x0a,0x80,0x03,0xa1,0x40,0xe8,0x00,0x2e,0x00,0x0c,0x00,0x23,0xa1,0x40,0xc8,0x50 } }, +{ 16, 0x9810, 0, {0x2e,0x14,0x0d,0x80,0x03,0xe0,0x00,0xf8,0x50,0x3a,0x00,0x0e,0x80,0x03,0xee,0x03 } }, +{ 16, 0x9820, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x1d,0xd4,0x00,0xf5,0x00,0xbf,0x40 } }, +{ 16, 0x9830, 0, {0x0f,0xd1,0x03,0xf4,0x44,0xdd,0x02,0x3d,0x50,0x2b,0xd1,0x23,0xf4,0x00,0xf9,0x10 } }, +{ 16, 0x9840, 0, {0x3f,0x40,0x0d,0x91,0x03,0xa4,0x48,0xf9,0x12,0x3e,0x4e,0x1f,0x90,0x03,0xa6,0x02 } }, +{ 16, 0x9850, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xf4,0x00,0xc5,0x04,0x3b,0x40 } }, +{ 16, 0x9860, 0, {0x0f,0xd8,0x03,0xa7,0x80,0xfd,0x00,0xb3,0x68,0x0d,0xd8,0x43,0xa5,0x10,0xc9,0xa0 } }, +{ 16, 0x9870, 0, {0x32,0x51,0x4f,0x5a,0x43,0x36,0x00,0xc9,0xa0,0x7a,0x68,0x0b,0xd0,0x03,0xc6,0x01 } }, +{ 16, 0x9880, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x18,0xca,0x88,0x88,0x02,0x02,0x00 } }, +{ 16, 0x9890, 0, {0x8d,0x84,0x22,0x23,0x42,0xf8,0x00,0x22,0x04,0x28,0x8a,0xa2,0xaa,0x94,0x88,0xe9 } }, +{ 16, 0x98a0, 0, {0x20,0xa8,0x0a,0x80,0x0a,0x21,0x40,0x80,0xe2,0x2e,0x28,0x0b,0x80,0x02,0xce,0x04 } }, +{ 16, 0x98b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x05,0xc4,0x20,0xa1,0x04,0xa8,0xc0 } }, +{ 16, 0x98c0, 0, {0x0b,0x1c,0x2a,0x24,0x00,0x39,0x04,0x20,0x40,0x2a,0x1e,0x02,0xe4,0x80,0xb1,0x10 } }, +{ 16, 0x98d0, 0, {0x2a,0x48,0x09,0x14,0x46,0x04,0x00,0x81,0x38,0x2c,0x5b,0x0b,0x10,0x02,0xd2,0x00 } }, +{ 16, 0x98e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xa4,0x12,0xa9,0x24,0x22,0x40 } }, +{ 16, 0x98f0, 0, {0x29,0x90,0x02,0x24,0x00,0x39,0x00,0x02,0x58,0x08,0x18,0x10,0xe6,0x01,0xb9,0x00 } }, +{ 16, 0x9900, 0, {0xaa,0x44,0x08,0x90,0x02,0x24,0x00,0x89,0x00,0x0e,0x41,0x0b,0x90,0x02,0xc6,0x04 } }, +{ 16, 0x9910, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x05,0xe4,0x00,0xe1,0x01,0x2a,0x64 } }, +{ 16, 0x9920, 0, {0x2f,0x94,0x13,0x24,0x02,0x71,0x60,0x12,0x60,0x4d,0x90,0x00,0xc5,0x02,0xf9,0x00 } }, +{ 16, 0x9930, 0, {0x3a,0x40,0x0f,0x90,0x23,0x24,0x02,0xc9,0x02,0x3a,0x40,0x0f,0x90,0x02,0xe8,0x04 } }, +{ 16, 0x9940, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x01,0xa4,0x00,0xd9,0x00,0x3e,0x60 } }, +{ 16, 0x9950, 0, {0xaf,0x90,0x83,0x64,0x88,0xf9,0x20,0x3e,0x62,0x03,0x90,0x83,0xa4,0x00,0xc9,0x00 } }, +{ 16, 0x9960, 0, {0x36,0x60,0x0f,0x10,0x03,0xc4,0x00,0xf9,0x00,0x7e,0x40,0x0f,0x90,0x03,0xda,0x00 } }, +{ 16, 0x9970, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0xa1,0x00,0xc8,0x82,0x32,0x00 } }, +{ 16, 0x9980, 0, {0x6f,0x00,0x03,0xa0,0x00,0xd8,0x40,0x30,0x00,0x0e,0x80,0x03,0x60,0x04,0xf8,0x01 } }, +{ 16, 0x9990, 0, {0x3e,0x10,0x4f,0x80,0x8b,0x22,0x00,0xf8,0x00,0x32,0x01,0x0e,0x80,0x03,0xca,0x04 } }, +{ 16, 0x99a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x38,0x00,0x0e,0x00,0xa9,0x90 } }, +{ 16, 0x99b0, 0, {0x2f,0xe6,0x20,0x88,0x00,0x9e,0x80,0x23,0x80,0x0a,0xe8,0x03,0x28,0x00,0xba,0x00 } }, +{ 16, 0x99c0, 0, {0x18,0x80,0x0d,0xec,0x02,0x38,0x80,0xba,0x00,0xa2,0x80,0x08,0xa0,0x03,0x8a,0x00 } }, +{ 16, 0x99d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x6c,0x02,0x83,0x80,0x20,0xc8 } }, +{ 16, 0x99e0, 0, {0x0b,0x20,0x02,0x0c,0x01,0x92,0x10,0x68,0xc0,0x3a,0x3c,0x02,0xcc,0x10,0x3b,0x02 } }, +{ 16, 0x99f0, 0, {0x0c,0xc0,0x28,0x3c,0x02,0x4e,0x00,0xb3,0x00,0x28,0xc0,0x28,0x30,0x02,0xca,0x00 } }, +{ 16, 0x9a00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x14,0x00,0x87,0x42,0x2b,0xc0 } }, +{ 16, 0x9a10, 0, {0x29,0x70,0x22,0x9c,0x00,0xb6,0x00,0x2b,0xc2,0x0a,0x60,0x86,0x1c,0x00,0xb7,0x21 } }, +{ 16, 0x9a20, 0, {0x29,0xc0,0x00,0x74,0x02,0x5c,0x00,0x37,0x91,0x01,0xe0,0x08,0x74,0x02,0xa8,0x00 } }, +{ 16, 0x9a30, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xc7,0x80,0x21,0xe0 } }, +{ 16, 0x9a40, 0, {0x2f,0x78,0x02,0x9e,0x00,0x96,0x80,0x39,0xe0,0x2e,0xf8,0x03,0xde,0x30,0xf7,0xd0 } }, +{ 16, 0x9a50, 0, {0x2d,0xf2,0x00,0x78,0x03,0x52,0x00,0xf7,0xa2,0x3b,0xe0,0x0e,0x78,0x07,0xea,0x02 } }, +{ 16, 0x9a60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xb4,0x00,0xfb,0x00,0x0c,0xc0 } }, +{ 16, 0x9a70, 0, {0x0f,0x30,0x03,0xec,0x10,0xd3,0x00,0xb4,0xc0,0x2f,0x80,0x03,0x6c,0x48,0xfb,0x00 } }, +{ 16, 0x9a80, 0, {0x3e,0xc8,0x4d,0x90,0x03,0xa4,0x00,0xfb,0x20,0x1e,0xc0,0x0f,0xb0,0x03,0xc2,0x06 } }, +{ 16, 0x9a90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xcc,0x80,0x2b,0x2c } }, +{ 16, 0x9aa0, 0, {0x2f,0xf8,0x03,0x7e,0x00,0x6e,0x80,0x3b,0xa1,0x0d,0xd8,0x43,0x3e,0x00,0xff,0x90 } }, +{ 16, 0x9ab0, 0, {0x33,0xe0,0x0f,0xe9,0x33,0xfe,0x00,0xcf,0xc0,0x3f,0xe2,0x0f,0xd8,0x03,0xc0,0x00 } }, +{ 16, 0x9ac0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0xb4,0x40,0x87,0x00,0x21,0x04 } }, +{ 16, 0x9ad0, 0, {0x08,0x78,0x02,0x1c,0x00,0x86,0x00,0x21,0xc0,0x28,0x90,0x02,0xdc,0x00,0xb7,0x10 } }, +{ 16, 0x9ae0, 0, {0x21,0xc0,0x0f,0x73,0x02,0xcc,0x00,0x87,0x00,0x2d,0xc0,0x0b,0x50,0x02,0xea,0x00 } }, +{ 16, 0x9af0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9d,0x00,0xa4,0x00,0x29,0x48 } }, +{ 16, 0x9b00, 0, {0x6a,0xf0,0x82,0x4c,0x00,0xae,0x00,0xa1,0xc4,0x29,0x74,0x02,0x5c,0x40,0xa3,0x10 } }, +{ 16, 0x9b10, 0, {0x61,0xc2,0x0b,0x60,0x06,0xc8,0x00,0x87,0x00,0x2d,0xc0,0x0b,0x50,0x02,0xc0,0x04 } }, +{ 16, 0x9b20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xe6,0x01,0xa3,0x02,0x20,0x40 } }, +{ 16, 0x9b30, 0, {0x28,0x3c,0x02,0x0c,0x00,0x83,0x42,0x20,0xc8,0x08,0x10,0x02,0xcd,0x00,0xb3,0x00 } }, +{ 16, 0x9b40, 0, {0x28,0xf0,0x0b,0x30,0x02,0xcc,0x01,0x83,0x04,0x2c,0xc0,0x83,0x10,0x02,0xc8,0x04 } }, +{ 16, 0x9b50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xaa,0x80,0xeb,0x00,0x38,0xc0 } }, +{ 16, 0x9b60, 0, {0x0a,0x90,0x03,0x7c,0x22,0xa2,0x40,0x32,0x48,0x0d,0xb0,0x0b,0x3e,0x00,0xff,0x00 } }, +{ 16, 0x9b70, 0, {0x33,0xf4,0x0f,0x90,0x03,0xec,0x00,0x8f,0x02,0x3f,0xc0,0x0f,0x90,0x03,0xea,0x04 } }, +{ 16, 0x9b80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe0,0x00,0xd9,0x02,0x3e,0xc0 } }, +{ 16, 0x9b90, 0, {0x0e,0xb6,0x03,0xec,0x00,0xfa,0x20,0x3e,0xc0,0x4f,0x24,0x23,0xac,0x60,0xfb,0x00 } }, +{ 16, 0x9ba0, 0, {0xa6,0xc0,0x0e,0x90,0x03,0xe4,0x00,0xfb,0x00,0x3c,0xc1,0x0f,0x90,0x03,0xe0,0x00 } }, +{ 16, 0x9bb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xf8,0x02,0xcf,0x00,0x33,0xe0 } }, +{ 16, 0x9bc0, 0, {0x2c,0xf0,0x13,0xbc,0x00,0x2e,0x10,0xb1,0x64,0x2e,0xf0,0x02,0x3c,0x00,0xff,0x02 } }, +{ 16, 0x9bd0, 0, {0x3f,0xc1,0x4d,0xec,0x63,0xfe,0x00,0xb7,0x00,0x3b,0xc0,0x0c,0xd8,0x03,0xc0,0x44 } }, +{ 16, 0x9be0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x6c,0x28,0x81,0x81,0x22,0xe0 } }, +{ 16, 0x9bf0, 0, {0x0a,0x38,0x02,0x3c,0x04,0xba,0xc9,0x32,0xe0,0x20,0x84,0x02,0x2c,0x00,0xbb,0x00 } }, +{ 16, 0x9c00, 0, {0x2e,0xc0,0x0b,0x9c,0x02,0xe7,0x81,0xbb,0x04,0x22,0xc0,0x0a,0x99,0x02,0xe0,0x00 } }, +{ 16, 0x9c10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x28,0x40,0x88,0x80,0x22,0x88 } }, +{ 16, 0x9c20, 0, {0x28,0xbc,0x42,0xac,0x00,0xba,0x00,0x2a,0x80,0x08,0x84,0x02,0xac,0x00,0xbb,0x00 } }, +{ 16, 0x9c30, 0, {0x2e,0xc0,0x0b,0xb0,0x82,0xe8,0x90,0xab,0x00,0x62,0xc0,0x08,0xb0,0x12,0xe0,0x00 } }, +{ 16, 0x9c40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x89,0x00,0x2a,0x80 } }, +{ 16, 0x9c50, 0, {0x28,0xb2,0x02,0x0c,0x00,0xba,0x00,0x20,0xc0,0x08,0x00,0x02,0x8c,0x00,0xb3,0x00 } }, +{ 16, 0x9c60, 0, {0x2c,0xc0,0x0b,0x30,0x20,0x4c,0x14,0xb3,0x00,0x20,0xc0,0x08,0x30,0x02,0xc2,0x01 } }, +{ 16, 0x9c70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x68,0x00,0xc8,0x00,0xb2,0xc0 } }, +{ 16, 0x9c80, 0, {0x2c,0xb2,0x03,0xac,0x00,0xfa,0x00,0x3a,0xc0,0x4e,0xa5,0x03,0xbc,0x00,0xff,0x00 } }, +{ 16, 0x9c90, 0, {0x3f,0xc0,0x09,0xa0,0x03,0xe9,0x04,0xef,0x00,0xba,0xc0,0x0c,0xb0,0x01,0xc0,0x01 } }, +{ 16, 0x9ca0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xfc,0x00,0xf5,0x00,0x35,0xc0 } }, +{ 16, 0x9cb0, 0, {0xaf,0x34,0x03,0xfc,0x00,0xf4,0x00,0x39,0xc0,0x0f,0xc2,0x03,0x7c,0x00,0xff,0x01 } }, +{ 16, 0x9cc0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xfc,0xa0,0xff,0x00,0x3f,0xc0,0x0f,0xf0,0x03,0xe8,0x05 } }, +{ 16, 0x9cd0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x00,0xff,0x29,0x3d,0x20 } }, +{ 16, 0x9ce0, 0, {0x8e,0xc1,0x03,0x32,0x48,0xdc,0x80,0x23,0x25,0x0e,0xf2,0x03,0x3c,0xc0,0xdf,0x84 } }, +{ 16, 0x9cf0, 0, {0x33,0xc9,0x0f,0xf2,0x03,0xfc,0x00,0xcf,0x80,0x33,0x40,0x0c,0xf2,0x03,0x30,0x00 } }, +{ 16, 0x9d00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xec,0xc0,0xbb,0x60,0x2e,0x08 } }, +{ 16, 0x9d10, 0, {0x08,0x81,0x02,0x20,0x04,0x88,0x20,0x20,0x48,0x08,0xf1,0x82,0x2d,0xc0,0x83,0x00 } }, +{ 16, 0x9d20, 0, {0x22,0xd4,0x09,0xf5,0x02,0xfc,0x08,0x8b,0x01,0x22,0x40,0x28,0xb4,0x02,0x20,0x04 } }, +{ 16, 0x9d30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0x20,0xb3,0x09,0x2c,0x82 } }, +{ 16, 0x9d40, 0, {0x08,0x10,0x16,0xa0,0x10,0x90,0x08,0x28,0x48,0x0a,0x32,0x02,0x0c,0x00,0xbb,0x00 } }, +{ 16, 0x9d50, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x02,0x93,0x01,0x20,0x00,0x8a,0x31,0x22,0xe2,0x01 } }, +{ 16, 0x9d60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x04,0xbb,0x00,0x2c,0x80 } }, +{ 16, 0x9d70, 0, {0x08,0x86,0x02,0xa0,0x20,0xa0,0x00,0x2a,0x60,0x0a,0xb0,0x10,0x2c,0x00,0xab,0x0c } }, +{ 16, 0x9d80, 0, {0x6e,0xc0,0x09,0xb0,0x02,0xcc,0x00,0x9b,0x00,0x22,0x60,0x0a,0xb0,0x02,0xf0,0x04 } }, +{ 16, 0x9d90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xec,0x00,0xbb,0x00,0x3e,0x34 } }, +{ 16, 0x9da0, 0, {0x08,0xa0,0x0b,0x83,0x00,0xd9,0x02,0x3a,0xe0,0x2e,0xb0,0x0b,0x2c,0x00,0xf8,0x80 } }, +{ 16, 0x9db0, 0, {0x3e,0xc0,0x4f,0xb0,0x03,0xec,0x00,0xca,0x40,0xb2,0x72,0x0e,0xb0,0x0b,0xc0,0x04 } }, +{ 16, 0x9dc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xbc,0x10,0xfb,0x00,0x3f,0x00 } }, +{ 16, 0x9dd0, 0, {0x0d,0xf8,0x13,0x70,0x48,0xdd,0x40,0x37,0xc2,0x8d,0xf0,0x03,0xdc,0x00,0xdd,0xc8 } }, +{ 16, 0x9de0, 0, {0x13,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xee,0x40,0x7f,0x40,0x0d,0x70,0x03,0x38,0x00 } }, +{ 16, 0x9df0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xfb,0x01,0x32,0xc0 } }, +{ 16, 0x9e00, 0, {0x04,0x10,0x03,0x20,0x40,0xe8,0x10,0x3a,0xc0,0x0d,0xb0,0x03,0xac,0x08,0xf8,0x40 } }, +{ 16, 0x9e10, 0, {0xb2,0xc0,0x2c,0xb0,0x33,0xa4,0x82,0xda,0x40,0xba,0x40,0x0f,0xb0,0x03,0xd0,0x04 } }, +{ 16, 0x9e20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x3c,0x08,0xbf,0x80,0x22,0xc8 } }, +{ 16, 0x9e30, 0, {0x08,0xb7,0x00,0x23,0x44,0x88,0xd0,0x22,0xd0,0x08,0x70,0x82,0xfc,0x00,0xb2,0xe0 } }, +{ 16, 0x9e40, 0, {0x03,0xf4,0x08,0xf5,0x02,0x37,0x04,0x8b,0xd1,0x22,0x60,0x4b,0xfd,0x02,0xf2,0x00 } }, +{ 16, 0x9e50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb3,0x10,0xa4,0x40 } }, +{ 16, 0x9e60, 0, {0x08,0x00,0x02,0x48,0x00,0xa0,0x42,0x2a,0xd0,0x01,0x30,0x02,0x8c,0x00,0xb3,0x80 } }, +{ 16, 0x9e70, 0, {0x2c,0xc0,0x09,0x31,0x02,0xcc,0x00,0x89,0x00,0x22,0xe8,0x03,0x38,0x02,0xf8,0x00 } }, +{ 16, 0x9e80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x1e,0x00,0xb7,0x80,0x27,0x64 } }, +{ 16, 0x9e90, 0, {0x68,0x4a,0x02,0x52,0x00,0x8c,0x80,0x21,0xe0,0x08,0x78,0x02,0xde,0x00,0xb7,0x80 } }, +{ 16, 0x9ea0, 0, {0x2d,0xe2,0x19,0x39,0x02,0x5e,0x30,0x85,0x98,0x21,0xe4,0x0b,0x79,0x02,0xd8,0x00 } }, +{ 16, 0x9eb0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x00,0xf3,0x20,0x34,0x00 } }, +{ 16, 0x9ec0, 0, {0x0c,0xb8,0x03,0x48,0x80,0xe2,0x22,0x38,0xc0,0x0d,0x30,0x03,0x8c,0x00,0xf3,0x00 } }, +{ 16, 0x9ed0, 0, {0x3e,0xc0,0x0d,0x31,0x03,0xec,0x00,0xcb,0x00,0x38,0x06,0x0f,0x30,0x83,0xd2,0x02 } }, +{ 16, 0x9ee0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x00,0xff,0x00,0x3b,0x01 } }, +{ 16, 0x9ef0, 0, {0x0f,0xd0,0x03,0x90,0x00,0xf6,0x00,0x3f,0xc0,0x0f,0xf4,0x01,0xfc,0x00,0xff,0x01 } }, +{ 16, 0x9f00, 0, {0x33,0xc2,0x0e,0xf5,0x13,0xbc,0x00,0xed,0x00,0x3f,0xc4,0x0f,0xf0,0x03,0xd0,0x06 } }, +{ 16, 0x9f10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xec,0x00,0xfb,0x00,0x3c,0xc0 } }, +{ 16, 0x9f20, 0, {0x0e,0xa0,0x01,0x64,0x01,0xd8,0x00,0x32,0xe0,0x2c,0xb5,0x03,0x2c,0x00,0xf2,0x00 } }, +{ 16, 0x9f30, 0, {0x7a,0xc0,0x0d,0xb4,0x03,0x2d,0x80,0xc9,0x02,0x32,0xc0,0x0c,0xb0,0x03,0x2a,0x00 } }, +{ 16, 0x9f40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x80,0xb7,0x00,0x2d,0xc0 } }, +{ 16, 0x9f50, 0, {0x0d,0x60,0x02,0xd0,0x01,0x84,0x00,0x21,0xc0,0x08,0x30,0x02,0x1d,0x00,0xb7,0x00 } }, +{ 16, 0x9f60, 0, {0x21,0xc8,0x0b,0xf4,0x03,0x1e,0xc0,0x86,0x00,0x21,0xc0,0x08,0x7c,0x03,0x52,0x04 } }, +{ 16, 0x9f70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0xc0,0xb7,0x90,0x2d,0xe0 } }, +{ 16, 0x9f80, 0, {0x08,0x78,0x06,0xd6,0x01,0xb4,0x82,0x21,0xe0,0x08,0x78,0x0a,0x1e,0x00,0xb5,0xc0 } }, +{ 16, 0x9f90, 0, {0x29,0xe8,0x09,0x78,0x02,0x36,0xc1,0x97,0x80,0x28,0xb0,0x0a,0x7a,0x02,0x30,0x00 } }, +{ 16, 0x9fa0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0xbb,0x00,0x2c,0xe0 } }, +{ 16, 0x9fb0, 0, {0x09,0x35,0x82,0xc0,0xc1,0xa0,0x51,0x20,0xe4,0x08,0x30,0x02,0x8c,0x00,0xbb,0xc4 } }, +{ 16, 0x9fc0, 0, {0x20,0xc0,0x0b,0x30,0x02,0x06,0x00,0x93,0x18,0xaa,0xb0,0x2a,0x30,0x0a,0x52,0x04 } }, +{ 16, 0x9fd0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xfa,0x01,0x3d,0xac } }, +{ 16, 0x9fe0, 0, {0x4c,0xec,0x13,0x78,0x10,0xf6,0x80,0xb3,0x90,0x0c,0xa0,0x03,0x28,0x00,0xfe,0x00 } }, +{ 16, 0x9ff0, 0, {0x3a,0x81,0x0d,0xa0,0x0f,0x2a,0x80,0xde,0x04,0x3b,0xa0,0x0e,0xa0,0x03,0x3a,0x04 } }, +{ 16, 0xa000, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x00,0xf8,0x00,0x3e,0x00 } }, +{ 16, 0xa010, 0, {0x0d,0x80,0x02,0xe1,0x00,0xd8,0x48,0x3e,0x12,0x0f,0x80,0x13,0x60,0x00,0xf8,0x60 } }, +{ 16, 0xa020, 0, {0x3e,0x00,0x07,0x80,0x03,0xa0,0x02,0xe8,0x04,0x26,0x08,0x05,0x80,0x03,0x92,0x00 } }, +{ 16, 0xa030, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xf9,0x04,0x3a,0x40 } }, +{ 16, 0xa040, 0, {0x0c,0x12,0x03,0x24,0x82,0xc9,0x00,0x36,0x44,0x0f,0x10,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0xa050, 0, {0x36,0x40,0x04,0x90,0x03,0x04,0x00,0xc9,0x00,0x12,0x40,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xa060, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x81,0x22,0x40 } }, +{ 16, 0xa070, 0, {0x08,0x90,0x1a,0x24,0x00,0x89,0x00,0x22,0x68,0x0b,0x99,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xa080, 0, {0x22,0x40,0x68,0x90,0x0a,0x24,0x00,0x89,0x00,0xa2,0x40,0x08,0x90,0x0a,0x20,0x00 } }, +{ 16, 0xa090, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb9,0x10,0x22,0xe0 } }, +{ 16, 0xa0a0, 0, {0x08,0x94,0x00,0x04,0x04,0x8b,0x08,0x26,0xc0,0x0b,0x90,0x02,0x24,0x04,0xb9,0x0c } }, +{ 16, 0xa0b0, 0, {0x24,0x40,0x0a,0x10,0x02,0x24,0x00,0x23,0x02,0x2a,0x40,0xa8,0x10,0x02,0x06,0x00 } }, +{ 16, 0xa0c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x90,0xb1,0x20,0x22,0x40 } }, +{ 16, 0xa0d0, 0, {0x08,0x12,0x02,0x0c,0x10,0x81,0x02,0xa0,0x50,0x0b,0x12,0x02,0x04,0x80,0xb1,0x05 } }, +{ 16, 0xa0e0, 0, {0x00,0x48,0x0a,0x10,0x02,0x04,0xa0,0xa1,0x00,0x28,0x4a,0x08,0x12,0x00,0x02,0x01 } }, +{ 16, 0xa0f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xf8,0x50,0xba,0x14 } }, +{ 16, 0xa100, 0, {0x0c,0x85,0x03,0x01,0x42,0xc8,0x50,0x34,0x00,0x0f,0x85,0x03,0x21,0x40,0xf8,0x00 } }, +{ 16, 0xa110, 0, {0x36,0x00,0x0e,0x80,0x13,0x20,0x80,0xe0,0x00,0x1a,0x08,0x0c,0x00,0x03,0x2e,0x03 } }, +{ 16, 0xa120, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xe4,0x44,0xf9,0x10,0x3f,0x40 } }, +{ 16, 0xa130, 0, {0x2f,0xd1,0x13,0xf4,0x04,0xf5,0x00,0x3f,0x40,0x0f,0x91,0x0b,0xe4,0x40,0xff,0x28 } }, +{ 16, 0xa140, 0, {0xbe,0x4e,0x0d,0x96,0x83,0xd4,0xa2,0xdd,0x28,0x37,0x4a,0x0f,0x93,0x83,0xe6,0x06 } }, +{ 16, 0xa150, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x05,0xe4,0x10,0xcd,0x00,0x3f,0x40 } }, +{ 16, 0xa160, 0, {0x0f,0xd0,0x03,0x35,0x02,0x5d,0x01,0x31,0x44,0x0f,0xd0,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0xa170, 0, {0x32,0x60,0x0c,0x98,0x83,0xe6,0x40,0xd9,0x00,0x36,0x6a,0x0c,0x9e,0x83,0x26,0x01 } }, +{ 16, 0xa180, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x00,0x88,0x00,0x2e,0x00 } }, +{ 16, 0xa190, 0, {0x0b,0x80,0x42,0x02,0x80,0x8a,0x00,0x22,0x20,0x88,0x80,0x03,0x20,0x08,0xb8,0x82 } }, +{ 16, 0xa1a0, 0, {0x22,0x21,0x08,0x88,0x82,0xe2,0x42,0x88,0xa8,0x22,0x20,0x08,0xce,0x02,0x0e,0x04 } }, +{ 16, 0xa1b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x02,0x81,0x00,0x68,0x40 } }, +{ 16, 0xa1c0, 0, {0x0b,0x10,0x02,0x84,0x01,0xb9,0x00,0x20,0x40,0x49,0x10,0x0a,0x04,0x00,0xb5,0x08 } }, +{ 16, 0xa1d0, 0, {0x21,0x46,0x08,0x50,0x02,0xd4,0x00,0x8d,0x20,0x25,0x4a,0x0b,0x50,0x02,0x42,0x01 } }, +{ 16, 0xa1e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa4,0x00,0x89,0x04,0x6e,0x54 } }, +{ 16, 0xa1f0, 0, {0x0b,0x10,0x12,0xa4,0x01,0xa9,0x00,0xa2,0x40,0x18,0x90,0x16,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xa200, 0, {0x23,0x40,0x18,0xd0,0x02,0xf4,0x00,0x8d,0x40,0x21,0x4a,0x0b,0xd0,0x02,0x46,0x04 } }, +{ 16, 0xa210, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xc9,0x00,0x3a,0x50 } }, +{ 16, 0xa220, 0, {0x8f,0x96,0x0b,0x84,0x02,0xf1,0x01,0x30,0x48,0x8d,0x90,0x03,0x24,0x10,0xf9,0x00 } }, +{ 16, 0xa230, 0, {0xb2,0x40,0x2c,0x90,0x03,0xe6,0x40,0xd1,0xc0,0x36,0x50,0x2f,0x90,0x0b,0x68,0x04 } }, +{ 16, 0xa240, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x00,0x3e,0x60 } }, +{ 16, 0xa250, 0, {0x0f,0x99,0xc3,0x64,0x00,0xd9,0x28,0x3e,0x40,0x0d,0x90,0x03,0xa4,0x00,0xf9,0x40 } }, +{ 16, 0xa260, 0, {0x3e,0x40,0x0f,0x90,0x03,0xe4,0x20,0xf9,0x40,0x3e,0x40,0x0c,0x90,0x03,0x8a,0x00 } }, +{ 16, 0xa270, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xf8,0x01,0x36,0x00 } }, +{ 16, 0xa280, 0, {0x8f,0x80,0x03,0xe0,0x02,0xf8,0x04,0x32,0x00,0x0d,0x80,0x43,0x20,0x02,0xcc,0x00 } }, +{ 16, 0xa290, 0, {0x3f,0x00,0x0f,0xc0,0x13,0x90,0x02,0xdc,0x40,0x3f,0x10,0x4c,0xc0,0x23,0x0a,0x04 } }, +{ 16, 0xa2a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0xba,0x00,0x22,0x80 } }, +{ 16, 0xa2b0, 0, {0x0b,0xe8,0x20,0xf8,0x00,0x4e,0xc0,0x23,0xa0,0x08,0xa0,0x03,0x68,0x00,0x8a,0x00 } }, +{ 16, 0xa2c0, 0, {0x2e,0x80,0x1f,0xa0,0x02,0x2a,0x06,0x8a,0x00,0x2e,0xa0,0x02,0x60,0x03,0x0a,0x00 } }, +{ 16, 0xa2d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x6c,0x00,0xb3,0x00,0x20,0xc0 } }, +{ 16, 0xa2e0, 0, {0x0b,0x3d,0x02,0xc0,0x03,0x23,0x00,0x20,0xe0,0x01,0xb0,0x06,0x4c,0x00,0x8b,0x00 } }, +{ 16, 0xa2f0, 0, {0x2e,0xc0,0x4b,0x30,0x02,0x8e,0x08,0x83,0x80,0x2c,0xc4,0x00,0x34,0x8e,0x4a,0x00 } }, +{ 16, 0xa300, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x80,0xb5,0x80,0x61,0xc0 } }, +{ 16, 0xa310, 0, {0x0b,0x40,0x02,0xd4,0x00,0x84,0x08,0x23,0xc2,0x08,0x50,0x02,0x5e,0xc0,0x84,0x01 } }, +{ 16, 0xa320, 0, {0x2d,0x00,0x8a,0x08,0x02,0x10,0x24,0x84,0x08,0x6d,0x00,0x0a,0x03,0x12,0x28,0x00 } }, +{ 16, 0xa330, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xf5,0x82,0x21,0x60 } }, +{ 16, 0xa340, 0, {0x0f,0x78,0x03,0xd6,0x04,0xae,0x80,0x31,0xe0,0x0d,0x58,0x23,0x7e,0x00,0xc6,0x80 } }, +{ 16, 0xa350, 0, {0x2d,0xe0,0x0b,0x78,0x03,0x8e,0x00,0xd7,0x82,0x3d,0xf0,0x0c,0x7a,0x03,0x6a,0x02 } }, +{ 16, 0xa360, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xf1,0x00,0xba,0xd8 } }, +{ 16, 0xa370, 0, {0x0f,0x80,0x03,0xe4,0x12,0xf8,0x00,0xbe,0x80,0x0e,0x10,0x03,0xec,0x00,0xf9,0x00 } }, +{ 16, 0xa380, 0, {0x3e,0x00,0x5f,0x80,0x03,0xe0,0x08,0xf8,0x04,0x3c,0x00,0x0f,0x80,0x03,0xc2,0x06 } }, +{ 16, 0xa390, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x05,0xfe,0x20,0xff,0x80,0x3f,0xf0 } }, +{ 16, 0xa3a0, 0, {0x0f,0xf8,0x03,0xd2,0x00,0xef,0x84,0xb3,0x61,0x0c,0xb9,0x03,0xfe,0x00,0xff,0x80 } }, +{ 16, 0xa3b0, 0, {0x33,0xe0,0x0c,0xf8,0x13,0x22,0x11,0xcd,0x90,0x3f,0x60,0x0c,0xe8,0x03,0x10,0x00 } }, +{ 16, 0xa3c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xf5,0x00,0x2d,0xc0 } }, +{ 16, 0xa3d0, 0, {0x0b,0x00,0x02,0xd4,0x04,0x84,0x20,0x23,0x40,0x08,0x5a,0x02,0xdc,0x00,0xb4,0x00 } }, +{ 16, 0xa3e0, 0, {0x21,0x00,0x28,0xc2,0x02,0x1e,0x04,0x86,0x04,0x2d,0x88,0x08,0xd0,0x02,0x2a,0x04 } }, +{ 16, 0xa3f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x9c,0x00,0xb5,0x00,0x2d,0x40 } }, +{ 16, 0xa400, 0, {0x0b,0x70,0x02,0xf4,0x20,0xa7,0x04,0x21,0xc0,0x0a,0x50,0x02,0xdc,0x00,0xbe,0x00 } }, +{ 16, 0xa410, 0, {0x21,0xc0,0x08,0x70,0x12,0x00,0x00,0x85,0x00,0x2d,0x40,0x88,0x68,0x0a,0x04,0x00 } }, +{ 16, 0xa420, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x14,0xcc,0x00,0xa1,0x00,0x2e,0xc0 } }, +{ 16, 0xa430, 0, {0x1b,0x08,0x06,0xc4,0x20,0x80,0x00,0x20,0x98,0x1a,0x10,0x02,0xcc,0x00,0xb1,0x08 } }, +{ 16, 0xa440, 0, {0x20,0x00,0x08,0x00,0x02,0x0c,0x01,0x82,0xc0,0x2c,0xac,0x28,0x90,0x22,0x18,0x04 } }, +{ 16, 0xa450, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xb3,0x00,0x3e,0x40 } }, +{ 16, 0xa460, 0, {0x0f,0xba,0x03,0xe5,0x02,0xe9,0x04,0x32,0x90,0xae,0xb0,0x03,0xfc,0x10,0xfb,0x40 } }, +{ 16, 0xa470, 0, {0xb2,0x00,0x0c,0x80,0x0b,0x2c,0x02,0x82,0x18,0x3f,0xa0,0x0c,0xd0,0x03,0x2e,0x04 } }, +{ 16, 0xa480, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0xec,0x04,0xfb,0x01,0x3e,0x40 } }, +{ 16, 0xa490, 0, {0x0f,0xb6,0x43,0xe4,0x00,0xf8,0x00,0x3e,0x80,0x01,0x90,0x03,0xec,0x00,0xf8,0x81 } }, +{ 16, 0xa4a0, 0, {0x3e,0xd0,0x0d,0xb4,0x53,0xe0,0x00,0xf9,0x40,0x3e,0x40,0x0f,0xa0,0x03,0xe0,0x00 } }, +{ 16, 0xa4b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xdc,0x02,0xcd,0x80,0x33,0x60 } }, +{ 16, 0xa4c0, 0, {0x2c,0xda,0x03,0xfc,0x00,0xec,0x00,0x33,0x40,0x0f,0xf2,0x03,0x7c,0x04,0xfe,0x00 } }, +{ 16, 0xa4d0, 0, {0x32,0x00,0x0c,0xc8,0x03,0x3c,0x00,0xce,0x00,0x31,0x80,0x0c,0xd1,0x03,0x24,0x04 } }, +{ 16, 0xa4e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x04,0x6c,0x00,0x09,0x00,0x2a,0x64 } }, +{ 16, 0xa4f0, 0, {0x08,0x8e,0x02,0xc2,0x10,0xa0,0x10,0x3e,0x10,0x0b,0x98,0x02,0xec,0x00,0xb9,0x00 } }, +{ 16, 0xa500, 0, {0x02,0xd8,0x08,0xbe,0x22,0x20,0x00,0x89,0x00,0x22,0x50,0x08,0xa0,0x02,0x20,0x40 } }, +{ 16, 0xa510, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x0b,0x20,0x22,0x40 } }, +{ 16, 0xa520, 0, {0x08,0xa0,0x02,0xe5,0x42,0xab,0x04,0x22,0x18,0x0b,0xb0,0x02,0x6c,0x00,0xb3,0x00 } }, +{ 16, 0xa530, 0, {0x20,0x04,0x08,0x01,0x02,0x00,0x04,0xa8,0x40,0x22,0x10,0x08,0x80,0x02,0x20,0x00 } }, +{ 16, 0xa540, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x08,0x83,0x00,0x28,0x40 } }, +{ 16, 0xa550, 0, {0x08,0x04,0x02,0xc4,0x02,0xa8,0x00,0x2c,0x00,0x0b,0x12,0x02,0xcc,0x00,0xb0,0x00 } }, +{ 16, 0xa560, 0, {0x20,0xc0,0x40,0x30,0x02,0x0c,0x00,0x8b,0x00,0xa8,0xc0,0x08,0x30,0x02,0x02,0x11 } }, +{ 16, 0xa570, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0d,0x6c,0x00,0xc9,0x00,0x33,0x40 } }, +{ 16, 0xa580, 0, {0x0c,0xb0,0x03,0xec,0x02,0xeb,0x00,0x32,0x40,0x0f,0xb0,0x03,0x6c,0x00,0xfa,0x00 } }, +{ 16, 0xa590, 0, {0x32,0x00,0x0c,0x80,0x03,0x20,0x80,0xc8,0x00,0x30,0x00,0x0c,0x80,0x03,0x20,0x03 } }, +{ 16, 0xa5a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xfc,0x00,0xfd,0x00,0x3f,0x40 } }, +{ 16, 0xa5b0, 0, {0x0f,0xc2,0x13,0xf0,0x00,0xf4,0x00,0x3f,0x00,0x4f,0xd4,0x03,0xfc,0x00,0xf5,0x00 } }, +{ 16, 0xa5c0, 0, {0x3f,0xc0,0x8f,0xf0,0x03,0xfc,0x40,0xff,0x00,0x37,0xc0,0x2f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0xa5d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf0,0x00,0xcc,0x00,0x33,0x00 } }, +{ 16, 0xa5e0, 0, {0x0e,0xd0,0x0b,0x33,0x00,0xcc,0x00,0x33,0xe0,0x0f,0xc0,0x83,0x7c,0x00,0xcf,0x20 } }, +{ 16, 0xa5f0, 0, {0x7b,0x09,0x8c,0xf8,0x03,0xfe,0x50,0xcf,0x38,0x3f,0xe1,0x0d,0xc2,0x03,0xf0,0x00 } }, +{ 16, 0xa600, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe2,0x00,0x98,0x08,0x20,0x80 } }, +{ 16, 0xa610, 0, {0x08,0x98,0x02,0x20,0x00,0x88,0xd0,0x22,0xe0,0x0e,0xb4,0x22,0x7d,0x19,0x9f,0x69 } }, +{ 16, 0xa620, 0, {0x2e,0x90,0x08,0x30,0x92,0x28,0x81,0xdb,0x64,0x2e,0xe1,0x88,0x16,0xa2,0xe0,0x04 } }, +{ 16, 0xa630, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc8,0x00,0x90,0x24,0x20,0x01 } }, +{ 16, 0xa640, 0, {0x08,0x10,0x16,0x00,0x82,0x83,0x01,0x28,0xc1,0x0b,0x02,0x82,0x0c,0xe0,0xa3,0x10 } }, +{ 16, 0xa650, 0, {0x28,0x0e,0x1b,0x92,0x02,0x84,0x84,0x93,0x20,0x2e,0xc0,0x08,0x31,0x02,0xe2,0x01 } }, +{ 16, 0xa660, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa8,0x10,0x98,0x00,0x22,0x80 } }, +{ 16, 0xa670, 0, {0x08,0x90,0x02,0x00,0x60,0x8a,0x10,0x2a,0xc0,0x0a,0x20,0x02,0x6c,0x18,0xbb,0x00 } }, +{ 16, 0xa680, 0, {0x6e,0x60,0x2b,0x90,0x02,0x46,0x20,0x8b,0x00,0x2e,0xc2,0x08,0xb1,0x82,0xf0,0x04 } }, +{ 16, 0xa690, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x11,0xe4,0x02,0xcb,0x00,0xb2,0x40 } }, +{ 16, 0xa6a0, 0, {0x2c,0x92,0x03,0x27,0x00,0x88,0x00,0xba,0xc0,0x0f,0x88,0x03,0x2c,0x00,0xeb,0x04 } }, +{ 16, 0xa6b0, 0, {0x3a,0xa0,0xcf,0x2c,0xa3,0xed,0x00,0x9b,0x00,0x3c,0xf0,0x2d,0x8c,0x33,0xd0,0x04 } }, +{ 16, 0xa6c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb4,0x04,0xef,0x00,0x3f,0xc0 } }, +{ 16, 0xa6d0, 0, {0x0d,0x51,0x03,0xf0,0x00,0xf1,0x81,0x37,0xc0,0x0e,0xf4,0x03,0x9c,0x10,0xcf,0x00 } }, +{ 16, 0xa6e0, 0, {0x3d,0x80,0x0c,0xec,0x07,0xb8,0x08,0xff,0x02,0x1f,0xc4,0x0f,0xc8,0x03,0xf8,0x00 } }, +{ 16, 0xa6f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0x9e,0x00,0xc3,0x00,0x38,0x40 } }, +{ 16, 0xa700, 0, {0x0c,0x92,0x03,0xa4,0x80,0xfb,0x20,0x3a,0xc0,0x0d,0x94,0x03,0x2c,0x40,0xfb,0x00 } }, +{ 16, 0xa710, 0, {0x3e,0x01,0x0f,0x80,0x03,0xe5,0x00,0xeb,0x00,0x3a,0xc0,0x0d,0x84,0x0b,0x10,0x04 } }, +{ 16, 0xa720, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x08,0x8b,0x02,0x22,0xc0 } }, +{ 16, 0xa730, 0, {0x08,0x92,0x03,0x21,0x00,0x8b,0x48,0x22,0xc0,0x0b,0xb7,0x02,0x3d,0x40,0x3f,0x01 } }, +{ 16, 0xa740, 0, {0x22,0x74,0x0b,0x90,0x02,0x28,0x04,0xbf,0x00,0xb2,0xc0,0x0b,0x85,0x02,0x32,0x00 } }, +{ 16, 0xa750, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x40,0x01,0x80,0x00,0x28,0x00 } }, +{ 16, 0xa760, 0, {0x08,0x2c,0x12,0x88,0x40,0xb0,0x40,0x08,0xc0,0x0b,0x18,0x02,0x0e,0x00,0xb3,0x00 } }, +{ 16, 0xa770, 0, {0x28,0x20,0x11,0x30,0x02,0x0c,0x00,0xb3,0x00,0x24,0x00,0x09,0x00,0x06,0x38,0x00 } }, +{ 16, 0xa780, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x12,0x00,0x84,0x80,0x21,0xa0 } }, +{ 16, 0xa790, 0, {0x28,0x68,0x12,0x3a,0x00,0x84,0x80,0x25,0xe0,0x8b,0x58,0x02,0x1e,0x40,0xb7,0x82 } }, +{ 16, 0xa7a0, 0, {0x21,0xa6,0x0b,0x78,0x02,0x1a,0x00,0xb7,0x80,0x21,0x20,0x0b,0x58,0x02,0x08,0x00 } }, +{ 16, 0xa7b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x08,0x00,0xc8,0x21,0x38,0x09 } }, +{ 16, 0xa7c0, 0, {0x0c,0x28,0x03,0x80,0x01,0xf1,0x00,0x38,0xc0,0x0d,0x85,0x02,0x0c,0x00,0xfb,0x00 } }, +{ 16, 0xa7d0, 0, {0x38,0x85,0x0f,0x10,0x03,0x8c,0x00,0xeb,0x10,0x3c,0xc8,0x0d,0x30,0x03,0x12,0x02 } }, +{ 16, 0xa7e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0x98,0x00,0xfc,0x01,0x3f,0x80 } }, +{ 16, 0xa7f0, 0, {0x0f,0x68,0x03,0xd0,0x40,0xfc,0x00,0x3b,0xc0,0x0d,0xc0,0x03,0xfc,0x20,0xff,0x00 } }, +{ 16, 0xa800, 0, {0x3b,0xc5,0x0f,0xf0,0x0b,0xb4,0x40,0xff,0x18,0x3f,0x00,0x0f,0xf1,0x03,0xd0,0x06 } }, +{ 16, 0xa810, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe4,0x00,0xeb,0x00,0xb0,0x41 } }, +{ 16, 0xa820, 0, {0x0c,0xa0,0x03,0xe0,0x04,0xca,0x04,0xb0,0xe0,0x0e,0xb0,0x03,0xec,0x80,0xcb,0x20 } }, +{ 16, 0xa830, 0, {0x32,0x81,0x0c,0xa0,0x03,0xee,0x00,0xdb,0x00,0x3e,0x00,0x0e,0xb0,0x03,0x2a,0x00 } }, +{ 16, 0xa840, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x94,0x04,0x87,0x00,0x21,0xc0 } }, +{ 16, 0xa850, 0, {0x48,0x60,0x02,0xf0,0x00,0x87,0x00,0x21,0xc0,0x08,0x70,0x02,0xfc,0xa0,0x83,0x28 } }, +{ 16, 0xa860, 0, {0xa3,0x80,0x08,0x60,0x02,0xdc,0x00,0x87,0x20,0x2d,0xc0,0x0b,0x70,0x02,0x12,0x04 } }, +{ 16, 0xa870, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9c,0x02,0xa3,0x80,0x21,0x60 } }, +{ 16, 0xa880, 0, {0x08,0x68,0x02,0xd2,0x00,0x87,0x80,0x21,0xe0,0x29,0x78,0x02,0xde,0x80,0x87,0x90 } }, +{ 16, 0xa890, 0, {0x21,0xa0,0x19,0x48,0x02,0xfe,0x00,0x97,0x80,0x2d,0xe0,0x0a,0x38,0x82,0x30,0x00 } }, +{ 16, 0xa8a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x01,0x83,0x80,0x20,0xc0 } }, +{ 16, 0xa8b0, 0, {0x08,0x20,0x42,0xc0,0x30,0x83,0x70,0xa0,0xc0,0x89,0x34,0x02,0xcc,0x02,0x83,0x00 } }, +{ 16, 0xa8c0, 0, {0x60,0xc0,0x29,0x00,0x02,0xce,0x00,0x83,0x00,0x2c,0xc8,0x0b,0xbc,0x02,0x12,0x04 } }, +{ 16, 0xa8d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa9,0x00,0xea,0xe2,0x32,0x90 } }, +{ 16, 0xa8e0, 0, {0x2c,0xe0,0x03,0xfb,0x02,0xce,0xc0,0x32,0x80,0x0f,0xe4,0x03,0xe8,0x00,0x8a,0x00 } }, +{ 16, 0xa8f0, 0, {0x33,0x88,0x0d,0x64,0xc3,0xfa,0x00,0xda,0x00,0x3d,0x90,0x0e,0xe0,0x0b,0x3a,0x04 } }, +{ 16, 0xa900, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xc0,0x24,0xf8,0x08,0x3e,0x12 } }, +{ 16, 0xa910, 0, {0x0f,0xc0,0x03,0xe0,0x48,0xf0,0x00,0x3e,0x00,0x0e,0x80,0x93,0xc0,0x00,0xf8,0x00 } }, +{ 16, 0xa920, 0, {0x7e,0x01,0x0e,0x80,0xc2,0xe0,0x40,0xf8,0x00,0x7e,0x00,0x8f,0x84,0x03,0xd2,0x00 } }, +{ 16, 0xa930, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe5,0x00,0xc1,0x01,0x32,0x48 } }, +{ 16, 0xa940, 0, {0x0c,0x98,0x03,0xe6,0x40,0xc9,0x00,0x32,0x40,0x0f,0x90,0x03,0x66,0x00,0xc9,0x00 } }, +{ 16, 0xa950, 0, {0x18,0x61,0x0c,0x90,0x03,0x64,0x20,0xf9,0x05,0x3e,0x40,0x0c,0x90,0x83,0x02,0x04 } }, +{ 16, 0xa960, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x66,0x20,0x89,0x00,0x20,0x52 } }, +{ 16, 0xa970, 0, {0x28,0x10,0xc2,0x26,0x02,0xa9,0x00,0x22,0x40,0x0b,0x90,0x0a,0x27,0x00,0xa9,0x00 } }, +{ 16, 0xa980, 0, {0x22,0x70,0x08,0x90,0x02,0x24,0x08,0xb9,0x00,0x2e,0x40,0x0a,0x90,0x0a,0x20,0x00 } }, +{ 16, 0xa990, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x02,0x8d,0x00,0x23,0x40 } }, +{ 16, 0xa9a0, 0, {0x08,0xd1,0x02,0x84,0x20,0x89,0x00,0x22,0x60,0x0b,0x11,0xf2,0x24,0xb0,0x81,0x00 } }, +{ 16, 0xa9b0, 0, {0x2a,0x46,0x08,0x90,0x42,0x64,0x08,0xb9,0x00,0x2e,0x40,0x08,0x92,0x02,0x06,0x00 } }, +{ 16, 0xa9c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x14,0x80,0x85,0x20,0x23,0x48 } }, +{ 16, 0xa9d0, 0, {0x08,0x52,0x02,0x84,0x08,0x81,0x00,0x20,0x40,0x0b,0x12,0x02,0x04,0x80,0xa1,0x20 } }, +{ 16, 0xa9e0, 0, {0x28,0x49,0x28,0x90,0x02,0x04,0x00,0x31,0x20,0x2e,0x40,0x08,0x32,0x02,0x02,0x01 } }, +{ 16, 0xa9f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x00,0xc8,0x50,0xb2,0x14 } }, +{ 16, 0xaa00, 0, {0x0c,0xc0,0x03,0xa1,0x40,0xc8,0x00,0xb2,0x00,0x07,0x85,0x03,0x21,0x40,0xc8,0x50 } }, +{ 16, 0xaa10, 0, {0x3a,0x15,0x0c,0x85,0x03,0x61,0x40,0xf8,0x51,0x3e,0x00,0x2c,0x85,0x03,0x2e,0x03 } }, +{ 16, 0xaa20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xc4,0x48,0xf9,0x10,0x3e,0x44 } }, +{ 16, 0xaa30, 0, {0x4f,0x91,0x03,0x74,0x00,0xf5,0x44,0x3e,0x40,0x0f,0xd1,0x03,0xe4,0x40,0xf9,0x10 } }, +{ 16, 0xaa40, 0, {0x37,0x44,0x0f,0xd0,0x03,0xd4,0x00,0xf9,0x10,0x3f,0xc0,0x0f,0xd1,0x03,0xe6,0x06 } }, +{ 16, 0xaa50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xf6,0xa0,0xdd,0x8c,0x33,0x78 } }, +{ 16, 0xaa60, 0, {0x0e,0xda,0x03,0x35,0x00,0xcd,0xa0,0x33,0x40,0x0d,0xf8,0x0b,0x36,0x81,0xe9,0x80 } }, +{ 16, 0xaa70, 0, {0x33,0x70,0x0c,0x91,0x03,0xe4,0x40,0xf9,0xc0,0x3e,0xc0,0x0f,0xdc,0x03,0xc6,0x00 } }, +{ 16, 0xaa80, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x04,0xb8,0x40,0x20,0x3c } }, +{ 16, 0xaa90, 0, {0x0c,0x85,0x02,0x02,0x84,0x8a,0x40,0x22,0x00,0x08,0x8f,0x82,0x23,0x00,0xb8,0xe8 } }, +{ 16, 0xaaa0, 0, {0x22,0x20,0x08,0x88,0x02,0xe2,0x00,0xb8,0xd0,0x2e,0x00,0x0b,0x8c,0x02,0xce,0x04 } }, +{ 16, 0xaab0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0x91,0x00,0x60,0x48 } }, +{ 16, 0xaac0, 0, {0x4b,0x10,0x02,0x04,0x8a,0x81,0x40,0x60,0x40,0x49,0x10,0x02,0x8d,0xa0,0xa1,0x41 } }, +{ 16, 0xaad0, 0, {0x20,0x50,0x09,0x12,0x22,0xc4,0x80,0xb1,0x20,0x2c,0x40,0x4b,0x3e,0x02,0xc2,0x01 } }, +{ 16, 0xaae0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x08,0xb9,0x04,0xa0,0x40 } }, +{ 16, 0xaaf0, 0, {0x48,0xb0,0x02,0x24,0x00,0x89,0x00,0x82,0x40,0x08,0x90,0xa6,0xa4,0x00,0xb9,0x04 } }, +{ 16, 0xab00, 0, {0x22,0x54,0x29,0x95,0x02,0xe5,0x40,0xb9,0x00,0x6e,0x40,0x0b,0x92,0x02,0xc6,0x04 } }, +{ 16, 0xab10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x05,0xe4,0x00,0x91,0x00,0x32,0x40 } }, +{ 16, 0xab20, 0, {0x0f,0x90,0x09,0x24,0x00,0x89,0x90,0x32,0x40,0x0d,0x94,0x03,0xa4,0x00,0xe9,0x02 } }, +{ 16, 0xab30, 0, {0x72,0x60,0x0d,0x94,0x03,0xe4,0x01,0xf9,0x01,0x3e,0x60,0x0f,0x90,0x03,0xe8,0x04 } }, +{ 16, 0xab40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x40,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0xab50, 0, {0x4f,0x90,0x03,0xe7,0x10,0xf9,0x80,0x3e,0x40,0x0f,0x10,0x13,0x64,0x00,0xf1,0x00 } }, +{ 16, 0xab60, 0, {0xbe,0x40,0x0e,0x90,0x03,0xe6,0x08,0xf9,0x01,0x3e,0x64,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0xab70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0xa0,0x00,0xf8,0x00,0x32,0x08 } }, +{ 16, 0xab80, 0, {0x0c,0x01,0x0b,0x20,0x40,0xc8,0x40,0x32,0x00,0x0e,0x84,0x83,0x20,0x00,0xf8,0x04 } }, +{ 16, 0xab90, 0, {0x3e,0x04,0x0f,0x80,0x03,0x21,0x00,0xe8,0x00,0x3e,0x10,0x0f,0x88,0x03,0xca,0x04 } }, +{ 16, 0xaba0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x38,0x00,0x3e,0x04,0x23,0x80 } }, +{ 16, 0xabb0, 0, {0x08,0xec,0x12,0x39,0x44,0xa6,0x00,0x28,0x81,0x08,0xe0,0x00,0x38,0x08,0xba,0x00 } }, +{ 16, 0xabc0, 0, {0x3f,0x80,0x0b,0xa0,0x02,0xa8,0x00,0x8a,0x02,0x2e,0x80,0x0b,0xe0,0x02,0xca,0x00 } }, +{ 16, 0xabd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x48,0x00,0x31,0x00,0x24,0xd0 } }, +{ 16, 0xabe0, 0, {0x08,0x3e,0x12,0xae,0x08,0x81,0xa0,0x2c,0xc0,0x0a,0x38,0x00,0x4c,0x00,0xb3,0x00 } }, +{ 16, 0xabf0, 0, {0x6e,0xc0,0x0a,0x30,0x02,0x0c,0x00,0xa3,0x00,0x6c,0xc0,0x0b,0x30,0x02,0xca,0x00 } }, +{ 16, 0xac00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x18,0x00,0xb5,0x10,0x25,0xc0 } }, +{ 16, 0xac10, 0, {0x28,0x60,0x12,0x90,0x10,0xa5,0x08,0x2d,0xc2,0x08,0x64,0x22,0x58,0x18,0xb7,0x00 } }, +{ 16, 0xac20, 0, {0x2d,0x80,0x0b,0x79,0x02,0xbe,0xc0,0x87,0x01,0x6d,0xc0,0x0b,0x60,0x02,0xe8,0x00 } }, +{ 16, 0xac30, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xf5,0x84,0x35,0x20 } }, +{ 16, 0xac40, 0, {0x8c,0x18,0x02,0x92,0x10,0xc5,0x80,0x3d,0x60,0x0e,0xc8,0x0b,0x5a,0x08,0x77,0xf3 } }, +{ 16, 0xac50, 0, {0x3d,0xa0,0x0f,0xf8,0x03,0x1e,0xb0,0xe7,0x85,0x3d,0xe0,0x0f,0x78,0x03,0xea,0x02 } }, +{ 16, 0xac60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xf1,0x04,0xba,0x01 } }, +{ 16, 0xac70, 0, {0x0f,0xa0,0x43,0x60,0x09,0xe1,0x00,0x38,0x40,0x0e,0xa0,0x03,0xa8,0x14,0xfb,0x20 } }, +{ 16, 0xac80, 0, {0x3a,0x80,0x0f,0xb4,0x1b,0x4c,0x80,0xfb,0x29,0x3e,0xc0,0x0f,0xb0,0x23,0xc2,0x06 } }, +{ 16, 0xac90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfa,0x00,0xcd,0x80,0x3b,0xe0 } }, +{ 16, 0xaca0, 0, {0x4e,0xf8,0x03,0xf2,0x02,0xd4,0x81,0x3b,0xe0,0x8e,0x98,0x07,0x3e,0x44,0xef,0x91 } }, +{ 16, 0xacb0, 0, {0x3f,0xe0,0x4f,0xfc,0x07,0xee,0xd0,0xcf,0x98,0x33,0xe4,0x0f,0xf8,0x03,0xc0,0x00 } }, +{ 16, 0xacc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x01,0x98,0x00,0x85,0x10,0x2d,0xc4 } }, +{ 16, 0xacd0, 0, {0x0d,0x11,0x02,0xf0,0x00,0x85,0x20,0x31,0xc4,0x0b,0x7b,0x00,0x38,0x40,0xd7,0x10 } }, +{ 16, 0xace0, 0, {0x2d,0x80,0x0b,0x70,0x62,0xfe,0xe1,0x87,0x14,0x39,0xc0,0x0b,0x60,0x02,0xea,0x04 } }, +{ 16, 0xacf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xbc,0x40,0xa5,0x00,0x29,0x40 } }, +{ 16, 0xad00, 0, {0x0b,0x50,0x82,0xdc,0x40,0x84,0x04,0x2d,0xc0,0x0b,0x10,0x06,0x58,0x44,0xa7,0x10 } }, +{ 16, 0xad10, 0, {0x2d,0x80,0x0b,0x71,0x02,0xdc,0x00,0x87,0x04,0x21,0xc2,0x0b,0x50,0x02,0xc0,0x10 } }, +{ 16, 0xad20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x0a,0xa1,0x01,0x2c,0x40 } }, +{ 16, 0xad30, 0, {0x89,0x18,0x02,0xc1,0x00,0xa1,0x08,0x20,0xc0,0x0b,0x34,0x06,0x40,0x00,0x93,0x05 } }, +{ 16, 0xad40, 0, {0x2c,0x14,0x0b,0x3c,0x86,0xce,0x10,0x83,0x01,0x28,0xf1,0x0b,0x14,0x02,0xc8,0x04 } }, +{ 16, 0xad50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xa0,0x00,0xed,0x00,0x3a,0xc0 } }, +{ 16, 0xad60, 0, {0x07,0xbc,0x63,0xed,0x00,0x81,0x40,0x3e,0xc0,0x0e,0x88,0x03,0x64,0x00,0xef,0x00 } }, +{ 16, 0xad70, 0, {0x7e,0x50,0x0f,0xf0,0x02,0xfd,0x42,0xcf,0x00,0x72,0xc0,0x1f,0xb4,0x03,0xea,0x04 } }, +{ 16, 0xad80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe8,0x00,0x99,0x00,0x3e,0xe0 } }, +{ 16, 0xad90, 0, {0x4f,0xb4,0x83,0xed,0x90,0x09,0x40,0x3e,0xc0,0x0f,0xa1,0x83,0xa8,0x01,0xeb,0x01 } }, +{ 16, 0xada0, 0, {0x3e,0x00,0x0f,0xb1,0x13,0xec,0x0c,0xfb,0x00,0x3a,0xc0,0x5f,0x20,0x23,0xe0,0x00 } }, +{ 16, 0xadb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xf8,0x00,0xfd,0x04,0x3f,0xb0 } }, +{ 16, 0xadc0, 0, {0x0d,0x60,0x03,0x3e,0x00,0xcd,0x00,0x33,0xf0,0x0f,0xf2,0x01,0xf0,0x00,0xff,0x03 } }, +{ 16, 0xadd0, 0, {0x3f,0x03,0x0f,0xf0,0x01,0xfc,0x00,0xfb,0x02,0x33,0xc2,0x0f,0xf0,0xe3,0x00,0x44 } }, +{ 16, 0xade0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6a,0x00,0xb9,0x02,0x2e,0xa0 } }, +{ 16, 0xadf0, 0, {0x4a,0xac,0x02,0x0e,0x80,0xf9,0xc0,0x36,0xe1,0x0b,0xa0,0x02,0x2a,0x08,0xbb,0x00 } }, +{ 16, 0xae00, 0, {0x2e,0x20,0x0e,0xb0,0x02,0xec,0x00,0xeb,0x00,0x22,0xc0,0x8b,0xb0,0x02,0x20,0x40 } }, +{ 16, 0xae10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x23,0x00,0xa9,0x00,0x28,0xc0 } }, +{ 16, 0xae20, 0, {0x09,0xb2,0x22,0x6c,0x40,0x89,0x89,0x2a,0xc0,0x0b,0x14,0x06,0x26,0x00,0xab,0x02 } }, +{ 16, 0xae30, 0, {0x6e,0xe0,0x09,0xb0,0x06,0x6c,0x00,0xb3,0x02,0x22,0xc0,0x0b,0xb0,0x02,0x20,0x00 } }, +{ 16, 0xae40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x08,0x00,0xb1,0x00,0x2c,0xc0 } }, +{ 16, 0xae50, 0, {0x0a,0x30,0x02,0x2c,0x00,0xbb,0x00,0x64,0xc0,0x0b,0x32,0x0a,0x08,0x00,0x33,0x00 } }, +{ 16, 0xae60, 0, {0x6c,0x80,0x02,0x30,0x46,0xcc,0x18,0xa3,0x00,0x20,0xc0,0x0b,0x28,0x02,0x02,0x11 } }, +{ 16, 0xae70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x68,0x00,0xe9,0x00,0x38,0xc1 } }, +{ 16, 0xae80, 0, {0x0d,0xb1,0x0b,0x2c,0x00,0x89,0x00,0x3a,0xc0,0x0b,0x90,0x03,0x60,0x00,0xff,0x02 } }, +{ 16, 0xae90, 0, {0x3e,0x80,0x0f,0xf0,0x03,0xfc,0x80,0xff,0x00,0x32,0xc0,0x8f,0x80,0x0b,0x00,0x03 } }, +{ 16, 0xaea0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x11,0xd8,0x00,0xfd,0x04,0x3f,0xc0 } }, +{ 16, 0xaeb0, 0, {0x2f,0xf2,0x03,0xfc,0x11,0xef,0x00,0x3f,0xc0,0x0f,0xf4,0x43,0x70,0x00,0xff,0x00 } }, +{ 16, 0xaec0, 0, {0x3f,0x00,0x46,0xf0,0x03,0xfd,0x00,0xef,0x00,0x3f,0xc0,0x0f,0xc0,0x03,0xe8,0x06 } }, +{ 16, 0xaed0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfe,0x00,0xff,0x80,0x3d,0xe0 } }, +{ 16, 0xaee0, 0, {0x0c,0xf9,0x13,0xde,0x00,0x7f,0x80,0xb3,0xe0,0x0f,0xfc,0x03,0xbe,0x40,0xcf,0x80 } }, +{ 16, 0xaef0, 0, {0x33,0xf0,0x0f,0xf8,0x03,0x7c,0x04,0xcc,0x80,0x33,0xa0,0x0c,0xf0,0x0b,0x30,0x01 } }, +{ 16, 0xaf00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe0,0x20,0x88,0x00,0x2e,0x20 } }, +{ 16, 0xaf10, 0, {0x08,0x82,0x12,0xe0,0x80,0xa8,0x81,0x22,0x02,0x0b,0x80,0x02,0x20,0x80,0xa8,0x80 } }, +{ 16, 0xaf20, 0, {0x22,0x08,0x0b,0x80,0x02,0x2c,0x02,0x88,0x04,0xaa,0x20,0x08,0xb0,0x02,0x20,0x04 } }, +{ 16, 0xaf30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xec,0x00,0xa3,0x08,0x2c,0x80 } }, +{ 16, 0xaf40, 0, {0x08,0x32,0x02,0xc4,0x20,0xa3,0x00,0x28,0x40,0x0b,0x92,0x02,0x84,0x00,0xa9,0x01 } }, +{ 16, 0xaf50, 0, {0x28,0xc8,0x1b,0x12,0x82,0xcc,0x40,0xa8,0x00,0x24,0xe0,0x0a,0x30,0x42,0x22,0x01 } }, +{ 16, 0xaf60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x11,0xa8,0x80,0xa8,0x02,0x2e,0x40 } }, +{ 16, 0xaf70, 0, {0x68,0x80,0x10,0xc8,0x00,0xb8,0x40,0x2a,0x90,0x0b,0xa0,0x00,0x28,0x00,0xaa,0x08 } }, +{ 16, 0xaf80, 0, {0x2a,0x02,0x03,0x20,0x02,0x8c,0x00,0xa8,0x88,0x2e,0x20,0x0a,0xb0,0x02,0x30,0x04 } }, +{ 16, 0xaf90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xe8,0x04,0xfa,0x00,0x3c,0x40 } }, +{ 16, 0xafa0, 0, {0x0c,0xa0,0x03,0xe8,0x00,0xeb,0x00,0x3a,0xc0,0x0f,0x20,0x53,0xa8,0x00,0xe3,0x40 } }, +{ 16, 0xafb0, 0, {0x2a,0x40,0x0f,0xa0,0x03,0x6c,0x00,0xa8,0x80,0x34,0x20,0x1e,0xb0,0x03,0x10,0x04 } }, +{ 16, 0xafc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb4,0x00,0x9d,0x91,0x3f,0x80 } }, +{ 16, 0xafd0, 0, {0x0f,0xda,0x23,0xf4,0x00,0xcc,0x20,0x37,0x00,0x07,0xd0,0x13,0x74,0x00,0xbc,0x00 } }, +{ 16, 0xafe0, 0, {0xb7,0x80,0x0b,0xd0,0x43,0x7c,0x00,0xdc,0x04,0x3b,0x00,0x6d,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0xaff0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa8,0x00,0xfa,0x80,0x3a,0x00 } }, +{ 16, 0xb000, 0, {0x2c,0xa0,0x0b,0x20,0x02,0xcb,0x62,0x3e,0x50,0x0e,0x88,0x03,0x20,0x00,0xd9,0x10 } }, +{ 16, 0xb010, 0, {0x3e,0x70,0x8c,0x80,0x33,0xec,0x80,0xd8,0x40,0x3a,0x02,0x0d,0xb0,0x03,0x10,0x04 } }, +{ 16, 0xb020, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x01,0x0c,0x00,0x39,0x80,0x22,0xc0 } }, +{ 16, 0xb030, 0, {0x0c,0x9d,0x82,0x2c,0x10,0xd0,0x40,0x2e,0xa0,0x08,0xb8,0x03,0x4e,0x02,0x8a,0x40 } }, +{ 16, 0xb040, 0, {0x0e,0xa0,0x0d,0xb0,0x03,0x3d,0x00,0xd0,0x90,0x36,0x10,0x0b,0xf0,0x02,0xb2,0x00 } }, +{ 16, 0xb050, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb1,0x00,0x60,0xc0 } }, +{ 16, 0xb060, 0, {0x8a,0x18,0x02,0x8c,0x08,0x80,0x40,0x0c,0xa0,0x02,0x30,0x02,0xce,0x00,0x82,0x48 } }, +{ 16, 0xb070, 0, {0x2c,0x80,0x2b,0x30,0x06,0x8c,0x00,0x81,0x02,0x20,0x90,0x09,0xb0,0x02,0x38,0x00 } }, +{ 16, 0xb080, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x12,0x00,0xb6,0x90,0xa3,0x30 } }, +{ 16, 0xb090, 0, {0x08,0xe8,0x22,0xb2,0x14,0x87,0x80,0x2d,0x60,0x08,0x49,0x12,0x12,0x61,0x95,0x90 } }, +{ 16, 0xb0a0, 0, {0x2d,0x61,0x0a,0x48,0x16,0x1e,0x80,0x95,0x80,0x25,0x20,0x0b,0x78,0x02,0x88,0x00 } }, +{ 16, 0xb0b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x00,0xf1,0x00,0x28,0x8c } }, +{ 16, 0xb0c0, 0, {0x8e,0x10,0x03,0x84,0x80,0x80,0x00,0x2c,0x02,0x0a,0x9a,0x02,0xe4,0x00,0xd0,0x00 } }, +{ 16, 0xb0d0, 0, {0x3e,0x80,0x0b,0x91,0x03,0x8e,0x80,0xc2,0x08,0x38,0x80,0x0d,0xb0,0x03,0x12,0x02 } }, +{ 16, 0xb0e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xb0,0x00,0xf6,0x00,0x3f,0x44 } }, +{ 16, 0xb0f0, 0, {0x0f,0x21,0x13,0x78,0x00,0xff,0x00,0x3d,0xc0,0x0f,0xe0,0x03,0x78,0x00,0xef,0x04 } }, +{ 16, 0xb100, 0, {0x3f,0x40,0x8d,0xe8,0x03,0xdc,0x04,0xf6,0x00,0x3f,0x00,0x0f,0xf0,0x83,0xd0,0x06 } }, +{ 16, 0xb110, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe8,0x00,0xe8,0x80,0x32,0x40 } }, +{ 16, 0xb120, 0, {0x0f,0x88,0x0b,0x28,0x00,0x78,0x02,0x3e,0x80,0x0e,0x28,0x03,0x28,0x00,0xca,0x80 } }, +{ 16, 0xb130, 0, {0x32,0x00,0x0f,0xa0,0x03,0xec,0x00,0xc9,0x80,0x32,0x80,0x0f,0xb0,0x03,0x2a,0x00 } }, +{ 16, 0xb140, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x8c,0x00,0x8f,0x00,0xa1,0x80 } }, +{ 16, 0xb150, 0, {0x0b,0x70,0x42,0x14,0x00,0xb7,0x00,0x2d,0x41,0x0b,0x50,0x42,0x14,0x00,0xa5,0x00 } }, +{ 16, 0xb160, 0, {0xa1,0xc0,0x0b,0x50,0x02,0xfc,0x80,0xa5,0x00,0x21,0x00,0x0b,0xf2,0x02,0x12,0x04 } }, +{ 16, 0xb170, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xba,0x00,0xa4,0x80,0x29,0x30 } }, +{ 16, 0xb180, 0, {0x4b,0x48,0x06,0x52,0x08,0xb4,0x80,0x2d,0x20,0x0b,0x48,0x42,0x32,0x00,0x84,0x80 } }, +{ 16, 0xb190, 0, {0x21,0x20,0x0b,0x48,0x12,0xde,0x40,0x86,0x81,0x29,0xa0,0x0b,0x78,0x0a,0x30,0x00 } }, +{ 16, 0xb1a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0x83,0x05,0x20,0xe0 } }, +{ 16, 0xb1b0, 0, {0x0b,0x34,0x02,0x6c,0x10,0xb3,0x00,0x2c,0xc0,0x0b,0x36,0x4a,0x0d,0x0d,0xa3,0x00 } }, +{ 16, 0xb1c0, 0, {0x20,0xc0,0x0b,0x34,0x82,0xcc,0x02,0xa2,0x00,0x28,0x00,0x0b,0x30,0x02,0x12,0x04 } }, +{ 16, 0xb1d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa9,0x20,0xea,0x40,0x30,0xa0 } }, +{ 16, 0xb1e0, 0, {0x07,0xa0,0x43,0x69,0x40,0xfa,0x00,0x3c,0x80,0x0f,0xa0,0x03,0x08,0x40,0xca,0x00 } }, +{ 16, 0xb1f0, 0, {0x30,0xa0,0x0f,0xa4,0x03,0xe8,0x00,0xce,0x00,0x3b,0x98,0x0f,0xa0,0x03,0x3a,0x04 } }, +{ 16, 0xb200, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xd2,0x00,0xfc,0x08,0x3f,0x00 } }, +{ 16, 0xb210, 0, {0x0b,0xc2,0x03,0xb0,0x00,0xfc,0x00,0x3f,0x00,0x0f,0xc0,0x03,0xf0,0x00,0xfc,0x00 } }, +{ 16, 0xb220, 0, {0x3f,0x04,0x0f,0xc0,0x03,0xe0,0x00,0xf8,0x00,0xb6,0x02,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xb230, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xd9,0x00,0x3e,0x68 } }, +{ 16, 0xb240, 0, {0x4c,0x91,0x01,0xe4,0x08,0xc9,0x00,0x3e,0x40,0x2c,0x92,0x03,0xe4,0x02,0xc9,0xa0 } }, +{ 16, 0xb250, 0, {0x3e,0x70,0x0e,0x90,0x03,0xc6,0x42,0xc9,0x00,0x3e,0x40,0x0f,0x10,0x03,0x02,0x04 } }, +{ 16, 0xb260, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x89,0x86,0x0e,0x60 } }, +{ 16, 0xb270, 0, {0x08,0x98,0x02,0xe4,0x08,0x89,0x10,0x2e,0x60,0x08,0x90,0x02,0xe4,0x00,0x89,0x0c } }, +{ 16, 0xb280, 0, {0x2e,0x60,0x08,0x90,0x02,0xe6,0x88,0x89,0x00,0x2e,0x40,0x0b,0x90,0x02,0xa0,0x00 } }, +{ 16, 0xb290, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0x9d,0x10,0x2f,0x40 } }, +{ 16, 0xb2a0, 0, {0x28,0xd0,0x06,0xf4,0x02,0xad,0x00,0x2f,0x60,0x08,0xd0,0x02,0xf4,0x00,0x8d,0x00 } }, +{ 16, 0xb2b0, 0, {0x2f,0x40,0x0a,0xd0,0x02,0xe4,0x00,0x89,0x00,0x2e,0x60,0x0b,0x90,0x02,0x06,0x00 } }, +{ 16, 0xb2c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x34,0x00,0x85,0x00,0x2d,0x40 } }, +{ 16, 0xb2d0, 0, {0x08,0x58,0x02,0xd4,0x00,0xa5,0x02,0x2d,0x40,0x08,0x50,0x00,0xd4,0x00,0x85,0x00 } }, +{ 16, 0xb2e0, 0, {0x2d,0x40,0x08,0x54,0x02,0xc4,0x80,0x81,0x00,0x2c,0x60,0x0b,0x14,0x02,0x82,0x01 } }, +{ 16, 0xb2f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xd8,0x52,0x3e,0x00 } }, +{ 16, 0xb300, 0, {0x0c,0x05,0x03,0xe1,0x40,0xe8,0x04,0x3e,0x14,0x0c,0x85,0x03,0xe1,0x40,0xc8,0x00 } }, +{ 16, 0xb310, 0, {0x3e,0x14,0x0e,0xc0,0x03,0xe0,0x00,0xc0,0x02,0x3e,0x00,0x4f,0x80,0x23,0x2e,0x03 } }, +{ 16, 0xb320, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x00,0xf9,0x01,0x3e,0x40 } }, +{ 16, 0xb330, 0, {0x4f,0x90,0x13,0xe4,0x00,0xd9,0x00,0x1e,0x40,0x0f,0x90,0x03,0xc4,0x10,0xf1,0x00 } }, +{ 16, 0xb340, 0, {0x1e,0x40,0x0f,0x90,0x03,0xe4,0xe0,0xfd,0x28,0x3f,0x40,0x0f,0x94,0x03,0xe6,0x06 } }, +{ 16, 0xb350, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xa4,0x00,0xfd,0x00,0x3f,0x40 } }, +{ 16, 0xb360, 0, {0x4d,0x50,0x02,0xe4,0x00,0x95,0x04,0x33,0x40,0x28,0xd0,0x03,0xf4,0x00,0xfd,0x00 } }, +{ 16, 0xb370, 0, {0x33,0x40,0x0f,0x91,0x03,0x34,0x00,0xcd,0x40,0x33,0x40,0x0f,0x98,0x81,0x06,0x00 } }, +{ 16, 0xb380, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x10,0xb8,0x00,0x2e,0x00 } }, +{ 16, 0xb390, 0, {0x0b,0x80,0x02,0xe0,0x10,0xb8,0x00,0x22,0x00,0x08,0x80,0x02,0xe0,0x00,0xb8,0x00 } }, +{ 16, 0xb3a0, 0, {0x22,0x00,0x0b,0x88,0x03,0xc2,0x80,0x88,0x80,0x22,0x00,0x0b,0x8c,0x02,0x0e,0x04 } }, +{ 16, 0xb3b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0xc4,0x00,0xb1,0x00,0x2c,0xc0 } }, +{ 16, 0xb3c0, 0, {0x0b,0x10,0x02,0xc4,0x00,0xbb,0x00,0x22,0x40,0x08,0x10,0x02,0xc4,0x01,0xb9,0x00 } }, +{ 16, 0xb3d0, 0, {0x20,0x40,0x1b,0x90,0x02,0x04,0x22,0x89,0x00,0x20,0x60,0x0b,0x12,0x82,0x02,0x01 } }, +{ 16, 0xb3e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x44,0xb9,0x00,0x2e,0xc0 } }, +{ 16, 0xb3f0, 0, {0x4b,0x90,0x02,0xe4,0x10,0xb9,0x02,0x02,0x40,0x08,0x91,0x42,0xe4,0x00,0xb9,0x80 } }, +{ 16, 0xb400, 0, {0x22,0x40,0x0b,0x92,0x02,0xc4,0x00,0x99,0x40,0x22,0x40,0x4b,0x90,0x12,0x06,0x04 } }, +{ 16, 0xb410, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe6,0x00,0xb9,0x01,0x3e,0x58 } }, +{ 16, 0xb420, 0, {0x0d,0x90,0x03,0xe6,0x00,0xd1,0x00,0x32,0x60,0x0c,0x98,0x02,0xe6,0x40,0xf9,0x00 } }, +{ 16, 0xb430, 0, {0xb2,0x40,0x0f,0x18,0x03,0x24,0x00,0xc9,0x80,0x32,0x50,0x0f,0x90,0x23,0x28,0x04 } }, +{ 16, 0xb440, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x00,0x3e,0x42 } }, +{ 16, 0xb450, 0, {0x0b,0x90,0x03,0xe7,0x08,0xf9,0x00,0xbe,0x48,0x0f,0x90,0x03,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0xb460, 0, {0x3e,0x40,0x0f,0x98,0x03,0xa4,0x00,0xe9,0xa0,0xbe,0x40,0x0f,0x10,0x0b,0x4a,0x00 } }, +{ 16, 0xb470, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xd8,0x01,0x3e,0x00 } }, +{ 16, 0xb480, 0, {0x0f,0x80,0x8b,0x20,0x00,0xf8,0x20,0x3e,0x01,0x0f,0x81,0x03,0xe0,0x00,0xf8,0x08 } }, +{ 16, 0xb490, 0, {0x3a,0x00,0x0c,0x80,0x03,0xe0,0x00,0xd8,0x40,0x32,0x00,0x0f,0x80,0x13,0x0a,0x04 } }, +{ 16, 0xb4a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x8a,0x80,0x2f,0x91 } }, +{ 16, 0xb4b0, 0, {0x0b,0xee,0x02,0x28,0x01,0xbe,0x00,0x20,0x80,0x0b,0xa0,0x02,0xea,0x80,0xb6,0x48 } }, +{ 16, 0xb4c0, 0, {0x22,0x80,0x0d,0xa0,0x02,0xfa,0x02,0x86,0x41,0xa3,0xa6,0x0b,0xa0,0x03,0x0a,0x00 } }, +{ 16, 0xb4d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x93,0x80,0x2c,0xc0 } }, +{ 16, 0xb4e0, 0, {0x0b,0x30,0x02,0x0c,0x10,0xb3,0x00,0x28,0xc0,0x0b,0x38,0x02,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0xb4f0, 0, {0x28,0xc0,0x09,0x30,0x02,0xc6,0x01,0x83,0x60,0x20,0x70,0x0b,0x30,0x0a,0x4a,0x00 } }, +{ 16, 0xb500, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x2e,0x88,0x85,0x08,0x2d,0x80 } }, +{ 16, 0xb510, 0, {0x4b,0xf8,0x06,0x1c,0x80,0xb7,0x00,0x21,0xc0,0x0b,0x50,0x02,0xd4,0x00,0xb6,0x00 } }, +{ 16, 0xb520, 0, {0x29,0x60,0x09,0x70,0x02,0xd0,0xa0,0x8d,0x00,0x21,0x40,0x0b,0x32,0x02,0x28,0x00 } }, +{ 16, 0xb530, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xd5,0x80,0x3d,0xe0 } }, +{ 16, 0xb540, 0, {0x8f,0x78,0x03,0x1e,0x84,0xb7,0x82,0x3d,0x60,0x0f,0x59,0x03,0xde,0x00,0xf7,0x80 } }, +{ 16, 0xb550, 0, {0x29,0x60,0x15,0x78,0x03,0xde,0x00,0xc7,0x80,0x31,0x60,0x0f,0x7c,0x03,0x6a,0x02 } }, +{ 16, 0xb560, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x40,0xe9,0x00,0x3e,0x80 } }, +{ 16, 0xb570, 0, {0x0f,0xa0,0x03,0xed,0x30,0xfb,0x00,0x36,0xc1,0x0f,0x96,0x03,0xe4,0x00,0xb3,0x00 } }, +{ 16, 0xb580, 0, {0x34,0x40,0x0f,0xb7,0x83,0xec,0x40,0x21,0x00,0x3e,0x40,0x0f,0xb0,0x03,0xc2,0x06 } }, +{ 16, 0xb590, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xff,0x81,0x33,0xe0 } }, +{ 16, 0xb5a0, 0, {0x0f,0xf9,0x03,0xde,0x20,0xcf,0x81,0x3f,0xe0,0x07,0x78,0x03,0x3e,0x00,0xff,0x80 } }, +{ 16, 0xb5b0, 0, {0x3f,0xe0,0x04,0xf8,0x13,0xfe,0x02,0xde,0x80,0x33,0x60,0x0f,0xf8,0x03,0x00,0x00 } }, +{ 16, 0xb5c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xb7,0x00,0x21,0xc4 } }, +{ 16, 0xb5d0, 0, {0x0b,0x5a,0x02,0xdc,0x48,0x86,0x50,0x2d,0xc0,0x0b,0x31,0x02,0x94,0x60,0xb4,0x18 } }, +{ 16, 0xb5e0, 0, {0x2d,0x40,0x48,0x70,0x02,0xe8,0x00,0xa5,0x10,0x21,0x40,0x0b,0x71,0x02,0x2a,0x04 } }, +{ 16, 0xb5f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xbd,0x00,0x21,0x42 } }, +{ 16, 0xb600, 0, {0x0b,0x70,0x02,0xfc,0x02,0x85,0x00,0x25,0x40,0x0b,0x50,0x02,0x9c,0x00,0xb7,0x00 } }, +{ 16, 0xb610, 0, {0x2f,0x40,0x28,0x71,0x02,0xdc,0x00,0xa6,0x00,0x21,0xc0,0x0b,0x70,0x02,0x00,0x00 } }, +{ 16, 0xb620, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0x6d,0x80,0xb1,0x20,0xa0,0x50 } }, +{ 16, 0xb630, 0, {0x0b,0xb2,0x06,0xce,0x00,0xa0,0x34,0x2e,0xf0,0x0b,0x18,0x02,0x85,0x20,0xb3,0x4a } }, +{ 16, 0xb640, 0, {0x2c,0x54,0x88,0x38,0x02,0xcc,0x10,0xa1,0x00,0x20,0xb0,0x0b,0x30,0x02,0x08,0x04 } }, +{ 16, 0xb650, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbe,0x80,0xf3,0x08,0x10,0x54 } }, +{ 16, 0xb660, 0, {0x0b,0x88,0x13,0xff,0x00,0xc0,0x80,0x3e,0x64,0x0f,0xb4,0x83,0x07,0x00,0xf9,0xc0 } }, +{ 16, 0xb670, 0, {0x3e,0xf0,0x0c,0xfc,0x13,0xf4,0x00,0xea,0x00,0x32,0x70,0x0f,0xf0,0x0b,0x2a,0x04 } }, +{ 16, 0xb680, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xf9,0x00,0x3e,0x10 } }, +{ 16, 0xb690, 0, {0x07,0x91,0x03,0xec,0xc0,0x58,0x00,0x3e,0x44,0x0f,0x92,0x03,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0xb6a0, 0, {0x3e,0xc0,0x8f,0xb3,0x03,0xe0,0x00,0xbb,0x00,0xbe,0x44,0x0f,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0xb6b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x02,0xcd,0x04,0x33,0xe0 } }, +{ 16, 0xb6c0, 0, {0x0c,0xc0,0x03,0x3c,0x08,0xfe,0x00,0x33,0x60,0x2c,0xd0,0x02,0xb4,0x80,0xcf,0x00 } }, +{ 16, 0xb6d0, 0, {0x3f,0x52,0x07,0xf0,0x13,0xfc,0x00,0xce,0x10,0x33,0x42,0x0c,0xb0,0x03,0xc0,0x44 } }, +{ 16, 0xb6e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x00,0x89,0x00,0x2a,0xb0 } }, +{ 16, 0xb6f0, 0, {0x08,0x88,0x02,0x2c,0x00,0xba,0x00,0x36,0x44,0x08,0x90,0x00,0x26,0x00,0xdb,0xc0 } }, +{ 16, 0xb700, 0, {0x2e,0x40,0x0b,0xb0,0x02,0xec,0x00,0x83,0xc0,0x28,0x40,0x0a,0xb0,0x02,0xe0,0x40 } }, +{ 16, 0xb710, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x8b,0x00,0x22,0x08 } }, +{ 16, 0xb720, 0, {0x1a,0xa2,0x02,0x2c,0x10,0xb9,0x20,0x22,0x40,0x08,0x30,0x02,0x2c,0x04,0xaa,0x54 } }, +{ 16, 0xb730, 0, {0x2e,0xc0,0x0b,0xb0,0x12,0xcc,0x00,0x8b,0x08,0x22,0x40,0x08,0xb0,0x02,0xe0,0x00 } }, +{ 16, 0xb740, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0x83,0x04,0x2a,0x00 } }, +{ 16, 0xb750, 0, {0x0a,0x08,0x82,0x0c,0x00,0xb8,0x00,0x64,0x40,0x08,0x30,0x02,0xa4,0x00,0xb0,0x00 } }, +{ 16, 0xb760, 0, {0x2c,0xc0,0x8b,0x30,0x10,0xc8,0x02,0x8b,0x00,0x2a,0x40,0x0a,0x30,0x02,0xc2,0x01 } }, +{ 16, 0xb770, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xc9,0x00,0x32,0x00 } }, +{ 16, 0xb780, 0, {0x1a,0x82,0x03,0x3c,0x00,0xf9,0x00,0x32,0x40,0x0c,0xd1,0x03,0xac,0x00,0xeb,0x00 } }, +{ 16, 0xb790, 0, {0x3e,0x40,0x0f,0xf0,0x03,0xed,0x00,0xc3,0x00,0x32,0xc0,0x8c,0xb0,0x03,0xc0,0x03 } }, +{ 16, 0xb7a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xfc,0x00,0xf5,0x00,0x3f,0x00 } }, +{ 16, 0xb7b0, 0, {0x0d,0x80,0x4b,0xfc,0x00,0x7c,0x00,0x3f,0x40,0x0f,0xd2,0x0b,0x74,0x00,0xdf,0x00 } }, +{ 16, 0xb7c0, 0, {0x1d,0x40,0x8f,0xf0,0x03,0xfc,0xa0,0xff,0x00,0x3f,0x80,0x0f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0xb7d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x00,0xdf,0x84,0x3b,0xe0 } }, +{ 16, 0xb7e0, 0, {0x0f,0xf8,0x0b,0x3e,0x00,0xec,0x80,0x33,0xe1,0x0c,0x30,0x03,0x3c,0x80,0xcf,0x48 } }, +{ 16, 0xb7f0, 0, {0x37,0xc0,0x0e,0x40,0x03,0xe0,0xc0,0xc7,0x91,0xb3,0x04,0x0c,0xf0,0x03,0x30,0x00 } }, +{ 16, 0xb800, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xef,0x04,0x8b,0x80,0x22,0x41 } }, +{ 16, 0xb810, 0, {0x0b,0xb0,0x82,0x2e,0x00,0x88,0x80,0xa2,0xe0,0x0a,0xa2,0x92,0xad,0x80,0x87,0x42 } }, +{ 16, 0xb820, 0, {0x23,0xd8,0x8a,0xad,0x02,0xe0,0xc0,0x8b,0x00,0x20,0x4c,0x48,0xa4,0x02,0x20,0x04 } }, +{ 16, 0xb830, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0x58,0xbb,0x00,0x28,0x80 } }, +{ 16, 0xb840, 0, {0x0b,0xb2,0x42,0x24,0x00,0xa8,0x00,0x2a,0xc0,0x0a,0x10,0x02,0x04,0x60,0xa3,0x20 } }, +{ 16, 0xb850, 0, {0x24,0xd2,0x08,0x00,0x42,0x8c,0x83,0x9b,0x01,0x20,0x49,0x08,0x33,0xc2,0x22,0x01 } }, +{ 16, 0xb860, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x00,0xab,0x88,0x22,0xa0 } }, +{ 16, 0xb870, 0, {0x0b,0xb8,0x02,0x26,0x0c,0xa8,0x00,0x2a,0xc0,0x0a,0x92,0x02,0xa4,0x00,0xab,0x06 } }, +{ 16, 0xb880, 0, {0x22,0xc0,0x0a,0xb0,0x02,0xe8,0x00,0x9b,0x00,0x02,0x40,0x08,0xa0,0x42,0x30,0x04 } }, +{ 16, 0xb890, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xd3,0x80,0x3a,0xe0 } }, +{ 16, 0xb8a0, 0, {0x0f,0x18,0x01,0x06,0x00,0xe8,0x30,0x38,0x66,0x0e,0xb8,0x03,0x2a,0x40,0xeb,0x00 } }, +{ 16, 0xb8b0, 0, {0x36,0xc1,0x0e,0x96,0x03,0xe2,0x80,0xda,0x08,0x32,0x80,0x2c,0xbb,0x03,0x10,0x04 } }, +{ 16, 0xb8c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x9c,0x00,0xdf,0x00,0x3f,0xc0 } }, +{ 16, 0xb8d0, 0, {0x0f,0xd0,0x03,0xf4,0x00,0xdc,0x80,0x37,0x60,0x0f,0xe8,0x03,0xfa,0x00,0xdf,0x01 } }, +{ 16, 0xb8e0, 0, {0x3f,0xc0,0x0f,0xc0,0x43,0xe6,0x4c,0xef,0xa0,0x3f,0x44,0x0f,0xa0,0x03,0xf8,0x00 } }, +{ 16, 0xb8f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x40,0xdb,0x00,0x36,0x80 } }, +{ 16, 0xb900, 0, {0x0c,0x98,0x03,0x26,0x00,0xf8,0x00,0x3e,0xc0,0x0e,0x18,0x03,0x84,0x02,0xe3,0x01 } }, +{ 16, 0xb910, 0, {0x38,0xc1,0x0e,0xb4,0x03,0xac,0x80,0xca,0x18,0x3a,0xd0,0x2c,0x30,0x03,0x10,0x04 } }, +{ 16, 0xb920, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x3f,0x40,0xb9,0x88,0x2e,0x80 } }, +{ 16, 0xb930, 0, {0x08,0xbc,0x02,0xa3,0x00,0xb0,0x00,0x0e,0xc0,0x08,0xb0,0x06,0x20,0x00,0x8f,0x04 } }, +{ 16, 0xb940, 0, {0x23,0xc1,0x08,0xb9,0x12,0x2f,0x00,0x83,0x80,0x36,0x40,0x08,0xad,0x02,0x32,0x00 } }, +{ 16, 0xb950, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb2,0x00,0x2c,0xc0 } }, +{ 16, 0xb960, 0, {0x09,0x32,0x02,0x84,0x00,0x33,0x00,0x2c,0xb2,0x0a,0x36,0x12,0x8c,0x08,0x93,0x05 } }, +{ 16, 0xb970, 0, {0x20,0xc0,0x0b,0x18,0x02,0xed,0x00,0x91,0x80,0x6a,0x00,0x08,0x10,0x02,0x38,0x00 } }, +{ 16, 0xb980, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x00,0xb7,0x80,0x2d,0xe0 } }, +{ 16, 0xb990, 0, {0x09,0x78,0x02,0x97,0x40,0xb4,0x80,0x2f,0xa0,0x08,0xe8,0x02,0x0e,0x40,0x97,0x82 } }, +{ 16, 0xb9a0, 0, {0x21,0xe0,0x98,0x68,0x82,0x1a,0x18,0x9d,0x90,0x2d,0xa1,0x18,0x58,0x02,0x08,0x00 } }, +{ 16, 0xb9b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0xc0,0xf3,0x00,0x3e,0xc0 } }, +{ 16, 0xb9c0, 0, {0x0d,0xb0,0x43,0x84,0x40,0xf0,0x00,0x3c,0x82,0x0e,0x38,0x12,0x8c,0x44,0xf3,0x30 } }, +{ 16, 0xb9d0, 0, {0xba,0xc1,0x1e,0x10,0x47,0x8e,0x22,0xd1,0x10,0x38,0x18,0x0c,0x30,0x83,0x12,0x02 } }, +{ 16, 0xb9e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x40,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0xb9f0, 0, {0x0e,0xe0,0x03,0xf4,0x40,0xfc,0x00,0x3d,0xc4,0x0f,0xd0,0x01,0xf4,0x41,0xef,0x18 } }, +{ 16, 0xba00, 0, {0x3f,0xc4,0x1f,0xf0,0x03,0xf8,0x48,0xef,0x14,0x33,0x80,0x0f,0xc1,0x03,0xd0,0x06 } }, +{ 16, 0xba10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xfc,0x40,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xba20, 0, {0x0f,0x98,0x03,0x24,0x00,0xcb,0x00,0x3e,0x40,0x0f,0xb0,0x03,0xa8,0x00,0xdb,0x28 } }, +{ 16, 0xba30, 0, {0x3e,0xc4,0x1f,0x90,0x23,0xec,0x00,0xca,0x00,0x32,0xe0,0x0c,0x90,0x03,0xea,0x00 } }, +{ 16, 0xba40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x80,0xb7,0x00,0x2d,0xc0 } }, +{ 16, 0xba50, 0, {0x4b,0x50,0x52,0x14,0x00,0xd4,0x01,0x2d,0x80,0x0b,0x60,0x02,0xd8,0x00,0xa7,0x20 } }, +{ 16, 0xba60, 0, {0x2d,0xc5,0x0b,0x40,0x16,0xdc,0x00,0x84,0x00,0x23,0xc0,0x08,0x40,0x02,0xd2,0x04 } }, +{ 16, 0xba70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x80,0xb7,0x80,0x2d,0xe0 } }, +{ 16, 0xba80, 0, {0x0b,0x78,0x0a,0x96,0x00,0x94,0x80,0x2d,0x60,0x1b,0x78,0x06,0xd2,0x00,0xa7,0x80 } }, +{ 16, 0xba90, 0, {0x2d,0xe0,0x0b,0x78,0x22,0xde,0x00,0x87,0x82,0x21,0xe0,0x08,0x58,0x02,0xf0,0x00 } }, +{ 16, 0xbaa0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0xb3,0xe4,0x2c,0xc0 } }, +{ 16, 0xbab0, 0, {0x1b,0x21,0x02,0x81,0x00,0x90,0x00,0x2c,0xc8,0x0b,0x39,0x02,0xce,0x00,0xa3,0x00 } }, +{ 16, 0xbac0, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xcd,0x00,0x8b,0x20,0x20,0xf0,0x08,0xb2,0x02,0xd2,0x04 } }, +{ 16, 0xbad0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xfe,0xa0,0x3f,0x82 } }, +{ 16, 0xbae0, 0, {0x0f,0xe8,0x03,0x98,0x30,0xd6,0x00,0x3f,0xa0,0x0f,0xe0,0x03,0xba,0xc0,0xfa,0x00 } }, +{ 16, 0xbaf0, 0, {0x3e,0x80,0x0f,0xec,0x33,0xf8,0x02,0xce,0x00,0xb3,0xb8,0x2c,0xec,0x83,0xfa,0x04 } }, +{ 16, 0xbb00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x18,0xf8,0x40,0x3e,0x00 } }, +{ 16, 0xbb10, 0, {0x0f,0x80,0x02,0x60,0x84,0xf8,0x05,0x2e,0x04,0x8f,0x80,0x41,0xe0,0x00,0x78,0x02 } }, +{ 16, 0xbb20, 0, {0x3e,0x00,0x0f,0x81,0x83,0xe0,0x20,0xf8,0x00,0xbe,0x02,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xbb30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe6,0x18,0xf9,0x20,0x3e,0x40 } }, +{ 16, 0xbb40, 0, {0x0f,0x9c,0x03,0xe4,0x40,0xc9,0x00,0x32,0x61,0x0c,0x90,0x13,0xc4,0x08,0xc9,0x01 } }, +{ 16, 0xbb50, 0, {0x3e,0x41,0x0f,0x18,0x03,0x24,0x00,0xc9,0xa0,0x32,0x40,0x0f,0x98,0x43,0x02,0x04 } }, +{ 16, 0xbb60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x65,0x00,0xb1,0xc0,0x22,0x40 } }, +{ 16, 0xbb70, 0, {0x0b,0x9c,0x02,0xe7,0x10,0x89,0x00,0x28,0x44,0x08,0x94,0x22,0xe4,0x10,0x89,0x00 } }, +{ 16, 0xbb80, 0, {0x2e,0x40,0x0b,0x9f,0x22,0x26,0x60,0x89,0x80,0x22,0x40,0x0b,0x91,0x0a,0x20,0x00 } }, +{ 16, 0xbb90, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x80,0xb9,0x00,0x2e,0xc0 } }, +{ 16, 0xbba0, 0, {0x4b,0xb4,0x02,0xe4,0x20,0x89,0x20,0x22,0x40,0x08,0x94,0x02,0xec,0x00,0x89,0x00 } }, +{ 16, 0xbbb0, 0, {0x2e,0x41,0x0b,0x90,0x02,0x04,0x00,0x89,0x40,0x22,0x40,0x0b,0x90,0x02,0x06,0x00 } }, +{ 16, 0xbbc0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0xb1,0x04,0x20,0x40 } }, +{ 16, 0xbbd0, 0, {0x8b,0x10,0x02,0xe4,0x05,0x81,0x00,0x28,0x40,0x28,0x12,0x12,0xc4,0x82,0x81,0x20 } }, +{ 16, 0xbbe0, 0, {0x2c,0x48,0x0b,0x12,0x0a,0x04,0x82,0x81,0x00,0x20,0x48,0x0b,0x12,0x02,0x02,0x01 } }, +{ 16, 0xbbf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x68,0xa0,0xfa,0x02,0x3e,0x14 } }, +{ 16, 0xbc00, 0, {0x0f,0x85,0x03,0xe0,0x00,0xc8,0x00,0x32,0x00,0x0c,0x85,0x03,0xc1,0x40,0xc8,0x53 } }, +{ 16, 0xbc10, 0, {0x3e,0x14,0x0f,0x80,0x03,0x01,0x48,0xc0,0x50,0xb2,0x14,0x0f,0x85,0x03,0x2e,0x03 } }, +{ 16, 0xbc20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xe4,0x00,0xfd,0x00,0xbf,0x40 } }, +{ 16, 0xbc30, 0, {0x0f,0x50,0x13,0xd4,0x02,0xfd,0x00,0x2f,0xc0,0x0f,0xd1,0x03,0xf4,0x40,0xf9,0x10 } }, +{ 16, 0xbc40, 0, {0x3e,0x44,0x0f,0xd1,0x03,0xf4,0x40,0xff,0x00,0xbf,0x44,0x0f,0xd1,0x03,0xe6,0x06 } }, +{ 16, 0xbc50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe6,0xa0,0xfd,0x01,0x3e,0x44 } }, +{ 16, 0xbc60, 0, {0x0f,0xd1,0x03,0xd4,0x00,0xc5,0x00,0x33,0x41,0x0f,0xdb,0x03,0x27,0x20,0xd9,0xe0 } }, +{ 16, 0xbc70, 0, {0xb2,0x70,0x0d,0xda,0x83,0xf6,0x40,0xcf,0x10,0x32,0x78,0x2d,0xda,0x03,0x06,0x00 } }, +{ 16, 0xbc80, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x00,0xb8,0x00,0x2e,0x28 } }, +{ 16, 0xbc90, 0, {0x0b,0x88,0x42,0xe0,0x10,0xd8,0x00,0x22,0x00,0x0b,0x8c,0x0a,0x23,0x00,0x88,0xc0 } }, +{ 16, 0xbca0, 0, {0x22,0x28,0x08,0x84,0x02,0xc2,0x80,0x80,0xa0,0x22,0x30,0x48,0xaa,0x82,0x0e,0x04 } }, +{ 16, 0xbcb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x00,0x2c,0x40 } }, +{ 16, 0xbcc0, 0, {0x8b,0x12,0x02,0xc4,0x00,0x99,0x02,0x28,0x40,0x8b,0x16,0x02,0x84,0x81,0x91,0x30 } }, +{ 16, 0xbcd0, 0, {0x20,0x58,0x09,0x10,0x02,0xc5,0x00,0x81,0x00,0x64,0x4d,0x08,0x34,0x02,0x02,0x01 } }, +{ 16, 0xbce0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xac,0x0c,0xb9,0x04,0x2e,0x48 } }, +{ 16, 0xbcf0, 0, {0x0b,0x94,0x06,0xe4,0x00,0x99,0x40,0xaa,0x40,0x0b,0x92,0x22,0xa4,0x00,0x89,0x00 } }, +{ 16, 0xbd00, 0, {0x60,0x40,0x08,0x94,0x02,0xe4,0x00,0x89,0x80,0xa6,0x50,0x08,0x92,0x02,0x06,0x04 } }, +{ 16, 0xbd10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0x98,0x3e,0x48 } }, +{ 16, 0xbd20, 0, {0x0f,0x98,0x03,0xe5,0x20,0xd9,0x00,0x3a,0x64,0x0f,0x94,0x83,0xa4,0xc0,0xd9,0x02 } }, +{ 16, 0xbd30, 0, {0x72,0x40,0x4d,0x90,0x42,0xe4,0x82,0xc9,0x40,0x36,0x40,0x0c,0x90,0x0b,0x28,0x04 } }, +{ 16, 0xbd40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xac,0x28,0xf9,0x88,0x3e,0x40 } }, +{ 16, 0xbd50, 0, {0x0f,0x99,0x13,0xe7,0x00,0xf9,0xc0,0x36,0x60,0x0f,0x90,0x03,0x66,0x00,0xf1,0x00 } }, +{ 16, 0xbd60, 0, {0x7e,0x40,0x0f,0x99,0x07,0xe4,0x60,0xf9,0x00,0x38,0x40,0x0f,0x98,0x03,0xca,0x00 } }, +{ 16, 0xbd70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xf8,0x10,0x32,0x00 } }, +{ 16, 0xbd80, 0, {0x0f,0x82,0x0b,0x21,0x00,0xe8,0x00,0x36,0x04,0x0c,0x86,0x03,0xe1,0x00,0xd8,0x00 } }, +{ 16, 0xbd90, 0, {0x32,0x00,0x0f,0x80,0x03,0x61,0x00,0xc8,0x00,0x32,0x00,0x0f,0x00,0x03,0x0a,0x04 } }, +{ 16, 0xbda0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x20,0xbe,0x00,0x22,0x80 } }, +{ 16, 0xbdb0, 0, {0x28,0xec,0x02,0x19,0x04,0x82,0x00,0x03,0x80,0x0d,0xe4,0x82,0xe8,0x00,0x8a,0x01 } }, +{ 16, 0xbdc0, 0, {0xaa,0x80,0x8b,0xed,0x82,0x3b,0x80,0x8e,0x90,0x36,0x80,0x0b,0xe0,0x03,0x4a,0x00 } }, +{ 16, 0xbdd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x42,0x00,0xb3,0x80,0x20,0xc0 } }, +{ 16, 0xbde0, 0, {0x6b,0x34,0x16,0x40,0xc0,0x83,0x10,0x24,0x72,0x88,0xb0,0x02,0xec,0x00,0x83,0x00 } }, +{ 16, 0xbdf0, 0, {0x24,0xc0,0x0b,0x04,0x02,0x6f,0x09,0x9b,0x00,0x24,0xc0,0x0b,0x30,0x02,0x0a,0x00 } }, +{ 16, 0xbe00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x14,0x00,0xb7,0x80,0x23,0xe4 } }, +{ 16, 0xbe10, 0, {0x28,0x78,0x82,0x74,0x14,0x8f,0x00,0x61,0xe0,0x09,0x50,0x12,0xdc,0x04,0x87,0x22 } }, +{ 16, 0xbe20, 0, {0x25,0xc8,0x1b,0x78,0x02,0x14,0x00,0x94,0x40,0xa5,0xc0,0x0b,0x60,0x22,0x68,0x00 } }, +{ 16, 0xbe30, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x12,0x20,0xb7,0x80,0xb1,0xe0 } }, +{ 16, 0xbe40, 0, {0x8f,0xf8,0x03,0x12,0x02,0xe7,0x80,0x35,0xe0,0x0c,0x68,0x06,0xcf,0xc2,0xcf,0xb0 } }, +{ 16, 0xbe50, 0, {0x25,0xf4,0x0f,0x58,0x03,0x5a,0x02,0xd5,0x80,0x75,0xfa,0x4f,0xf8,0x03,0x2a,0x02 } }, +{ 16, 0xbe60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xa5,0x90,0xf3,0x00,0x3d,0xc0 } }, +{ 16, 0xbe70, 0, {0x4f,0xb0,0x13,0xa8,0x04,0xfb,0x00,0x3c,0xc0,0x0f,0x80,0x43,0xec,0x80,0xeb,0x60 } }, +{ 16, 0xbe80, 0, {0x3a,0xc9,0x0f,0x30,0x03,0xec,0x00,0xe9,0x00,0x3e,0xc8,0x0f,0xa0,0x03,0xc2,0x06 } }, +{ 16, 0xbe90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xf6,0x00,0xee,0x80,0x3f,0xe0 } }, +{ 16, 0xbea0, 0, {0x0d,0x89,0x03,0xd2,0x40,0xe5,0x81,0x39,0xe0,0x3c,0xf9,0x07,0xfe,0x00,0xcf,0x88 } }, +{ 16, 0xbeb0, 0, {0x3f,0xe0,0x0f,0xe8,0x03,0xf2,0x08,0xce,0x80,0x33,0xe0,0x0c,0xf8,0x03,0x00,0x00 } }, +{ 16, 0xbec0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x94,0x44,0xc6,0x00,0x2f,0xc0 } }, +{ 16, 0xbed0, 0, {0x08,0x58,0x02,0xd0,0xc4,0x85,0x24,0x21,0x90,0x08,0x54,0x12,0xdc,0x82,0x07,0x00 } }, +{ 16, 0xbee0, 0, {0x2d,0xc0,0x0b,0x70,0x06,0xd4,0x00,0x8e,0x48,0x21,0xc0,0x0a,0x60,0x02,0x2a,0x04 } }, +{ 16, 0xbef0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xa7,0x40,0x2d,0xc0 } }, +{ 16, 0xbf00, 0, {0x08,0x42,0x02,0xd0,0x00,0xad,0x00,0x29,0xc0,0x08,0x70,0x22,0xdc,0x28,0x87,0x00 } }, +{ 16, 0xbf10, 0, {0x2d,0xc0,0x0b,0x40,0x02,0x98,0x00,0x97,0x00,0xa0,0xc4,0x08,0x70,0x02,0x00,0x00 } }, +{ 16, 0xbf20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x08,0x93,0x00,0x2c,0xe0 } }, +{ 16, 0xbf30, 0, {0x08,0x3c,0x22,0xc1,0x00,0x81,0x00,0x20,0x80,0x88,0x15,0x02,0xce,0x30,0x83,0x00 } }, +{ 16, 0xbf40, 0, {0x2c,0xc0,0x0b,0x3c,0x02,0xcc,0x04,0x93,0xc0,0x20,0xf4,0x4a,0x0c,0x82,0x08,0x04 } }, +{ 16, 0xbf50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xa0,0x00,0xe3,0xc0,0x1f,0xe0 } }, +{ 16, 0xbf60, 0, {0x6c,0x10,0x83,0xe0,0x04,0xeb,0x00,0x3a,0x52,0x4c,0xb4,0x03,0xfe,0x02,0xcf,0x00 } }, +{ 16, 0xbf70, 0, {0x3f,0xc0,0x0f,0x84,0x43,0xe1,0x02,0xd8,0xc2,0x33,0xc0,0x0c,0x84,0x0b,0x2a,0x04 } }, +{ 16, 0xbf80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe9,0x00,0xeb,0x10,0x3e,0xc4 } }, +{ 16, 0xbf90, 0, {0x0e,0x94,0x03,0xe4,0x00,0xfb,0x18,0x3e,0xc2,0x0f,0xb6,0x03,0xec,0x00,0xfb,0x01 } }, +{ 16, 0xbfa0, 0, {0x3e,0xc0,0x0f,0x35,0x03,0xc4,0x28,0xea,0x42,0x3e,0xc0,0x0f,0x81,0x03,0xe0,0x00 } }, +{ 16, 0xbfb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x40,0xff,0x00,0x33,0xc0 } }, +{ 16, 0xbfc0, 0, {0x0c,0xc0,0xa3,0x30,0x28,0xcd,0xa0,0x33,0xc0,0x0c,0xe8,0x03,0x0c,0x00,0xef,0x05 } }, +{ 16, 0xbfd0, 0, {0x3d,0xc0,0x0c,0xca,0x83,0x3c,0x00,0xcd,0x08,0x3f,0xc2,0x0c,0xa0,0x03,0xc0,0x44 } }, +{ 16, 0xbfe0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x67,0x00,0xbb,0x80,0x20,0xc0 } }, +{ 16, 0xbff0, 0, {0x08,0xaa,0x02,0x08,0x00,0xa1,0x01,0x34,0xd1,0x08,0xa4,0x12,0x2c,0x00,0x8b,0x00 } }, +{ 16, 0xc000, 0, {0x6e,0xc0,0x88,0xb2,0x02,0x2c,0x08,0x89,0x80,0x2e,0xc0,0x0a,0xa8,0x03,0xa0,0x40 } }, +{ 16, 0xc010, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0xba,0x80,0xa2,0xc0 } }, +{ 16, 0xc020, 0, {0x08,0xa8,0x0a,0xa0,0x00,0x8b,0x00,0xa2,0xc0,0x48,0x11,0x02,0xac,0x04,0x8b,0x00 } }, +{ 16, 0xc030, 0, {0x2e,0xc0,0x00,0x80,0x12,0x2a,0x08,0x8b,0x14,0x2c,0xc0,0x08,0x88,0x02,0xe0,0x00 } }, +{ 16, 0xc040, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0xb2,0x00,0x22,0xc0 } }, +{ 16, 0xc050, 0, {0x08,0xb2,0x12,0x80,0x00,0xab,0x01,0x24,0xc0,0x08,0x00,0x02,0x0c,0x04,0x83,0x00 } }, +{ 16, 0xc060, 0, {0x2c,0xc0,0x08,0x30,0x02,0x07,0x00,0x82,0x00,0x24,0xc0,0x08,0x08,0x02,0x82,0x01 } }, +{ 16, 0xc070, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xfb,0x00,0x32,0xc0 } }, +{ 16, 0xc080, 0, {0x0c,0xa2,0x03,0xa0,0x00,0xc9,0x00,0x32,0xc0,0x24,0x94,0x03,0x3c,0x02,0xcf,0x00 } }, +{ 16, 0xc090, 0, {0x2f,0xc0,0x04,0x80,0x0b,0x09,0x02,0xcb,0x01,0x3f,0xc0,0x2c,0xa0,0x03,0xc0,0x03 } }, +{ 16, 0xc0a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xdc,0x00,0xfd,0x02,0x3f,0xc0 } }, +{ 16, 0xc0b0, 0, {0x4f,0xe4,0x13,0x70,0x00,0xfd,0x00,0x3f,0xc0,0x0f,0xc2,0x83,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xc0c0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xff,0x00,0x3f,0xc0,0x0f,0xc0,0x03,0xa8,0x06 } }, +{ 16, 0xc0d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x20,0xef,0x30,0x3f,0x04 } }, +{ 16, 0xc0e0, 0, {0x6c,0x88,0x03,0x3a,0x42,0xe4,0x91,0x3f,0x0d,0x0d,0x48,0x03,0x3c,0xc0,0xff,0x02 } }, +{ 16, 0xc0f0, 0, {0x33,0x44,0x0c,0xf4,0x03,0xfc,0x82,0xdf,0x30,0x33,0x60,0x0d,0xf1,0x03,0x30,0x00 } }, +{ 16, 0xc100, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0xed,0x00,0x8b,0x70,0x2e,0x18 } }, +{ 16, 0xc110, 0, {0x88,0x22,0x4a,0x2c,0x82,0xea,0x26,0x2e,0x0c,0x0b,0xb8,0x42,0x3d,0x80,0xbf,0x90 } }, +{ 16, 0xc120, 0, {0x2a,0x54,0x28,0xb4,0x02,0xcd,0x00,0xdb,0x40,0x2a,0x4a,0x48,0x30,0x02,0xa0,0x04 } }, +{ 16, 0xc130, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0xb0,0xa3,0x00,0x6c,0x10 } }, +{ 16, 0xc140, 0, {0x09,0x00,0x82,0x20,0x82,0xa0,0x20,0x2c,0x88,0x4b,0x80,0x00,0x0c,0x40,0xb3,0x01 } }, +{ 16, 0xc150, 0, {0x20,0x48,0x0b,0x36,0x02,0x8c,0xe0,0x83,0x64,0x24,0x40,0x28,0x32,0x02,0x22,0x01 } }, +{ 16, 0xc160, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x11,0xac,0x00,0x8b,0x00,0x2e,0x00 } }, +{ 16, 0xc170, 0, {0x09,0x80,0x80,0xa6,0x00,0xba,0x11,0x2e,0x88,0x0b,0xb0,0x00,0x2c,0x00,0xbb,0x02 } }, +{ 16, 0xc180, 0, {0x02,0x40,0x09,0xb0,0x02,0xec,0x00,0x8b,0x00,0x2c,0xc8,0x08,0xb8,0x82,0xb0,0x04 } }, +{ 16, 0xc190, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xeb,0x00,0x3e,0x92 } }, +{ 16, 0xc1a0, 0, {0x0d,0x80,0x03,0x0a,0x20,0xe9,0x00,0x3e,0x50,0x45,0x80,0x01,0x2c,0x04,0xf3,0x00 } }, +{ 16, 0xc1b0, 0, {0x90,0x60,0x09,0xb0,0x03,0xec,0x00,0x8b,0x02,0x26,0x50,0x8d,0xbc,0x03,0x10,0x04 } }, +{ 16, 0xc1c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0xbc,0x00,0xff,0x02,0x3f,0x80 } }, +{ 16, 0xc1d0, 0, {0x0e,0xf9,0x02,0x7c,0x22,0xaf,0x00,0x3f,0x60,0x03,0xc0,0x0b,0xfc,0x10,0xff,0x00 } }, +{ 16, 0xc1e0, 0, {0x3f,0x4a,0x4e,0xf0,0x03,0xfc,0x00,0xf7,0x00,0x2b,0x60,0x0f,0x70,0x03,0xf8,0x00 } }, +{ 16, 0xc1f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xfb,0x00,0xb0,0x00 } }, +{ 16, 0xc200, 0, {0x0f,0x82,0x0b,0xa9,0x00,0xc9,0x00,0x32,0xd2,0x0f,0xa0,0x83,0xac,0x00,0xcb,0x10 } }, +{ 16, 0xc210, 0, {0x3e,0x40,0x0c,0xb0,0x03,0xec,0x00,0xdb,0x00,0x32,0x50,0x2c,0x95,0x03,0x10,0x04 } }, +{ 16, 0xc220, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x3c,0x04,0xbf,0x02,0x22,0x80 } }, +{ 16, 0xc230, 0, {0x0b,0x98,0x00,0x29,0x00,0xcb,0x40,0x22,0xc0,0x0b,0x24,0x02,0x3c,0x08,0x8f,0x50 } }, +{ 16, 0xc240, 0, {0x2e,0x50,0x0d,0xf0,0x02,0xfd,0x42,0x8f,0x58,0x22,0xe0,0x48,0xb5,0x02,0x32,0x00 } }, +{ 16, 0xc250, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x6c,0x00,0xb3,0x00,0x24,0x40 } }, +{ 16, 0xc260, 0, {0x4b,0x94,0x00,0x49,0x00,0x90,0x80,0x04,0x30,0x09,0x00,0x0e,0x4c,0x00,0x83,0x80 } }, +{ 16, 0xc270, 0, {0x2c,0xc0,0x09,0x30,0x22,0x6e,0x42,0x83,0x80,0x20,0x48,0x08,0x38,0x02,0x38,0x00 } }, +{ 16, 0xc280, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x00,0xb7,0x80,0x65,0x20 } }, +{ 16, 0xc290, 0, {0x0b,0x78,0x82,0x7a,0x08,0x8c,0xc0,0x25,0xa3,0x4b,0x78,0x02,0x5e,0x04,0x87,0x84 } }, +{ 16, 0xc2a0, 0, {0x2d,0x61,0x89,0x78,0x02,0xde,0x04,0x87,0x80,0xe9,0x62,0x08,0x78,0x02,0x08,0x00 } }, +{ 16, 0xc2b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x00,0xfb,0x00,0x34,0x48 } }, +{ 16, 0xc2c0, 0, {0x0f,0x3b,0x03,0x48,0x00,0x93,0x48,0x34,0x50,0x0d,0x00,0x03,0x6c,0x00,0xc3,0x10 } }, +{ 16, 0xc2d0, 0, {0x1c,0xc2,0x05,0x30,0x03,0xcc,0x40,0xcb,0x00,0x32,0x40,0x0c,0x20,0x03,0x12,0x02 } }, +{ 16, 0xc2e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x20,0xff,0x01,0x03,0x40 } }, +{ 16, 0xc2f0, 0, {0x0f,0xf0,0x23,0x1c,0x00,0xff,0x00,0x3b,0x80,0x0f,0xb0,0x23,0x3c,0x02,0xff,0x50 } }, +{ 16, 0xc300, 0, {0x3d,0xc4,0x0f,0xf1,0x03,0xec,0x00,0xef,0x00,0xb7,0xc0,0x0f,0xe1,0x03,0xd0,0x06 } }, +{ 16, 0xc310, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xec,0x00,0xfb,0x02,0x3e,0xe0 } }, +{ 16, 0xc320, 0, {0x0c,0x80,0x03,0x48,0x02,0xc8,0x81,0x32,0x00,0x0f,0x90,0x42,0xec,0xa0,0xfb,0x10 } }, +{ 16, 0xc330, 0, {0x3e,0xe0,0x0c,0xb1,0x03,0xec,0x40,0xfb,0x10,0x32,0x40,0x1f,0xf0,0x03,0x2a,0x00 } }, +{ 16, 0xc340, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0xb7,0x24,0x2d,0x80 } }, +{ 16, 0xc350, 0, {0x08,0x70,0x42,0xd8,0x10,0x8c,0x02,0x21,0x40,0x0b,0x50,0x02,0xdd,0x00,0xe7,0x20 } }, +{ 16, 0xc360, 0, {0x2f,0x40,0x08,0x70,0x02,0xdc,0x05,0xb7,0x00,0x21,0xc0,0x0b,0xf0,0x02,0x12,0x04 } }, +{ 16, 0xc370, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0xb7,0x90,0x2f,0x40 } }, +{ 16, 0xc380, 0, {0x0a,0x68,0x02,0x7a,0x00,0x97,0x80,0x21,0xe0,0x0b,0x78,0x02,0xde,0x00,0xb7,0x80 } }, +{ 16, 0xc390, 0, {0x2d,0xe0,0x08,0x78,0x06,0xde,0x00,0xb7,0xa0,0x21,0x60,0x0b,0x78,0x42,0x30,0x00 } }, +{ 16, 0xc3a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0xb3,0x00,0x2c,0xc0 } }, +{ 16, 0xc3b0, 0, {0x0a,0x34,0x02,0xc8,0x00,0x83,0x4a,0x20,0xf8,0x0b,0x31,0x02,0xcc,0x00,0xa3,0x00 } }, +{ 16, 0xc3c0, 0, {0x2c,0xc0,0x08,0x30,0x02,0xcc,0x00,0xb3,0x00,0x20,0xb2,0x0b,0x20,0x42,0x12,0x04 } }, +{ 16, 0xc3d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xba,0x00,0x3f,0x88 } }, +{ 16, 0xc3e0, 0, {0x2e,0xe0,0x43,0x59,0x88,0xde,0x00,0x33,0xb0,0x0f,0x6c,0x03,0xe8,0x00,0xfa,0x00 } }, +{ 16, 0xc3f0, 0, {0x3e,0x80,0x2c,0xa0,0x03,0xe8,0x04,0xfa,0x00,0x23,0xb8,0x0f,0xe0,0x8b,0x3a,0x04 } }, +{ 16, 0xc400, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x04,0xf8,0x01,0x3e,0x00 } }, +{ 16, 0xc410, 0, {0x09,0x82,0x21,0xe0,0x00,0xf8,0x40,0xbe,0x14,0x0f,0x84,0x81,0xe0,0x00,0xe8,0x00 } }, +{ 16, 0xc420, 0, {0x3e,0x00,0x1f,0x80,0x03,0xe0,0x00,0xf8,0x00,0xbe,0x00,0x0f,0x88,0x03,0xd2,0x00 } }, +{ 16, 0xc430, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xe1,0x00,0x32,0x40 } }, +{ 16, 0xc440, 0, {0x0c,0x90,0x43,0xe4,0x20,0xd9,0x00,0x3c,0x44,0x08,0x90,0x03,0x24,0x00,0xf9,0x01 } }, +{ 16, 0xc450, 0, {0x3e,0x48,0x0f,0x10,0x43,0x25,0x00,0xc9,0x00,0xb2,0x40,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xc460, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x00,0xa0,0x40 } }, +{ 16, 0xc470, 0, {0x08,0x98,0x02,0xe6,0x08,0xa9,0x60,0x2e,0x49,0x08,0x94,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xc480, 0, {0x2e,0x70,0x0b,0x90,0x02,0x26,0x02,0x89,0x00,0xa0,0x40,0x0a,0x90,0x0a,0x20,0x00 } }, +{ 16, 0xc490, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb9,0x00,0x22,0x40 } }, +{ 16, 0xc4a0, 0, {0x08,0x98,0x04,0xe6,0x00,0x99,0x80,0x2e,0x40,0x0a,0xb1,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xc4b0, 0, {0x0e,0x40,0x0b,0x90,0x0a,0x04,0x00,0x81,0x01,0x22,0xc0,0x08,0x10,0x02,0x06,0x00 } }, +{ 16, 0xc4c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x80,0xb1,0x20,0x22,0x48 } }, +{ 16, 0xc4d0, 0, {0x08,0x18,0x06,0xc4,0x00,0xa1,0x00,0x2c,0x48,0x2a,0x30,0x02,0x04,0x80,0xb1,0x22 } }, +{ 16, 0xc4e0, 0, {0x2c,0x48,0x0b,0x12,0x02,0x05,0x80,0x81,0x60,0x22,0x50,0x0a,0x14,0x02,0x02,0x01 } }, +{ 16, 0xc4f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xf8,0x50,0x32,0x14 } }, +{ 16, 0xc500, 0, {0x0c,0x85,0x03,0xe1,0x40,0xd8,0x50,0x3e,0x14,0x0e,0x80,0x0b,0x21,0x40,0xfa,0x00 } }, +{ 16, 0xc510, 0, {0x3e,0x94,0x0f,0x85,0x03,0x20,0x00,0xc0,0x00,0x32,0x00,0x0c,0x80,0x03,0x2e,0x03 } }, +{ 16, 0xc520, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xe4,0x41,0xf9,0x10,0x3d,0x45 } }, +{ 16, 0xc530, 0, {0x0f,0xd0,0x03,0xf4,0x00,0xff,0x00,0x3f,0x45,0x0d,0xd0,0x03,0xe4,0x40,0xf9,0x10 } }, +{ 16, 0xc540, 0, {0x3f,0x44,0x0f,0x91,0x03,0xe4,0x42,0xf9,0x10,0x3f,0x40,0x0f,0xd4,0x03,0xe6,0x06 } }, +{ 16, 0xc550, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe4,0x00,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0xc560, 0, {0x0c,0xd0,0x03,0xf4,0x08,0x8d,0x02,0x3f,0x40,0x0f,0xd0,0x03,0xe4,0x00,0xcd,0x00 } }, +{ 16, 0xc570, 0, {0x33,0x40,0x0c,0x90,0x03,0x24,0x00,0xf9,0x00,0x32,0x40,0x4c,0x98,0x23,0x06,0x00 } }, +{ 16, 0xc580, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x00,0xe8,0x00,0x2e,0x00 } }, +{ 16, 0xc590, 0, {0x48,0x80,0x02,0xe8,0x00,0xd0,0x00,0x2e,0x80,0x0b,0x80,0x12,0xe0,0x02,0x88,0x00 } }, +{ 16, 0xc5a0, 0, {0xa2,0x00,0x0a,0x80,0x12,0x22,0x00,0xb8,0x81,0x22,0x28,0x08,0xcf,0x02,0x0e,0x04 } }, +{ 16, 0xc5b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x00,0x2c,0x40 } }, +{ 16, 0xc5c0, 0, {0x28,0x10,0x02,0xc4,0x00,0x81,0x00,0x2c,0x40,0x0b,0x10,0x02,0xc4,0x00,0x91,0x00 } }, +{ 16, 0xc5d0, 0, {0x26,0x40,0x09,0x10,0x02,0x54,0xa0,0xb5,0x2c,0xa5,0x42,0x08,0x50,0x82,0x02,0x01 } }, +{ 16, 0xc5e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x00,0xa9,0x00,0x2e,0x50 } }, +{ 16, 0xc5f0, 0, {0x58,0x90,0x02,0xe4,0x80,0x9b,0x00,0x2e,0x45,0x8b,0x92,0x02,0xe4,0x00,0x99,0x00 } }, +{ 16, 0xc600, 0, {0x26,0x44,0x0b,0x90,0x02,0x64,0x08,0xb5,0x00,0x25,0x4a,0x08,0x51,0x02,0x06,0x04 } }, +{ 16, 0xc610, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0x00,0x3e,0x54 } }, +{ 16, 0xc620, 0, {0x0c,0x90,0x43,0xc4,0x00,0xc9,0x90,0x3e,0x70,0x0f,0x98,0x03,0xe4,0x00,0xd9,0x00 } }, +{ 16, 0xc630, 0, {0x34,0x60,0x4d,0x90,0x0a,0x64,0x00,0xf9,0x00,0x36,0x40,0x2c,0x9e,0x03,0x28,0x04 } }, +{ 16, 0xc640, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x00,0x3c,0x40 } }, +{ 16, 0xc650, 0, {0x0f,0x9c,0x03,0xe6,0x30,0xf9,0x00,0x3e,0x62,0x0f,0x90,0x03,0xe4,0x00,0xe9,0x00 } }, +{ 16, 0xc660, 0, {0x3a,0x40,0x4e,0x90,0x03,0xa4,0x00,0x79,0x0c,0x3a,0x40,0x0f,0x90,0x1b,0xca,0x00 } }, +{ 16, 0xc670, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xf8,0x00,0x3e,0x00 } }, +{ 16, 0xc680, 0, {0x0c,0x81,0x13,0xe1,0x08,0xc8,0x48,0x32,0x00,0x3c,0x80,0x03,0xc0,0x00,0xf0,0x10 } }, +{ 16, 0xc690, 0, {0x3e,0x06,0x0c,0x80,0x03,0xf0,0x08,0xcc,0x00,0x33,0x04,0x0c,0xc0,0x03,0x0a,0x04 } }, +{ 16, 0xc6a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0xba,0x00,0x2e,0x80 } }, +{ 16, 0xc6b0, 0, {0x08,0xec,0x42,0xfa,0x20,0x8e,0x00,0x23,0xa0,0x08,0xe8,0x42,0xe8,0x00,0xbe,0x80 } }, +{ 16, 0xc6c0, 0, {0x2f,0x80,0x08,0xa0,0x02,0xe8,0x00,0xda,0x00,0x22,0x80,0x48,0xe0,0x02,0x0a,0x00 } }, +{ 16, 0xc6d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0xb3,0x00,0x2c,0xc0 } }, +{ 16, 0xc6e0, 0, {0x09,0x34,0x82,0xc9,0x00,0x83,0x80,0x20,0xf0,0x08,0x30,0x82,0xcc,0x00,0xb3,0x80 } }, +{ 16, 0xc6f0, 0, {0x2c,0xf0,0x08,0xb0,0x02,0xc1,0x20,0x80,0x00,0xa0,0x32,0x08,0x00,0x02,0x0a,0x00 } }, +{ 16, 0xc700, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0xc0,0xb7,0x01,0x2f,0xc8 } }, +{ 16, 0xc710, 0, {0x89,0x50,0x02,0xd8,0x02,0x87,0xc4,0x21,0xe2,0x48,0x70,0x82,0xdc,0x00,0xb7,0x00 } }, +{ 16, 0xc720, 0, {0x2c,0x40,0x08,0x72,0x02,0xce,0x00,0x97,0x08,0x23,0xc0,0x08,0x70,0x02,0x28,0x00 } }, +{ 16, 0xc730, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xf7,0xe1,0x3d,0xe8 } }, +{ 16, 0xc740, 0, {0x2d,0x68,0x03,0xf2,0x00,0xc7,0x80,0xb0,0xe0,0x08,0x68,0x03,0xdf,0x80,0xf6,0x80 } }, +{ 16, 0xc750, 0, {0x3d,0xe0,0x8c,0x7e,0x03,0xda,0x00,0xcc,0x80,0x31,0x20,0x0c,0xc8,0x0b,0x2a,0x02 } }, +{ 16, 0xc760, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x08,0xfb,0x00,0x3c,0xc0 } }, +{ 16, 0xc770, 0, {0x0e,0x80,0x03,0xe0,0x08,0xf9,0x00,0x3e,0x40,0x0f,0xb0,0x02,0xec,0x00,0xfa,0x00 } }, +{ 16, 0xc780, 0, {0x3e,0x40,0x2f,0xb0,0x03,0xe4,0x00,0xfb,0x00,0x3c,0xc0,0x2f,0xb0,0x03,0xc2,0x06 } }, +{ 16, 0xc790, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xff,0x92,0x7f,0xea } }, +{ 16, 0xc7a0, 0, {0x0c,0xf8,0x03,0xfe,0x00,0xcc,0xa0,0x3f,0x20,0x0d,0xf9,0x03,0x3e,0x00,0xcf,0x80 } }, +{ 16, 0xc7b0, 0, {0x33,0x60,0x0f,0xf8,0x03,0xf6,0x00,0xef,0x84,0x33,0xe0,0x2c,0xc8,0x03,0x00,0x00 } }, +{ 16, 0xc7c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xb7,0x00,0x2f,0xc8 } }, +{ 16, 0xc7d0, 0, {0x08,0x54,0x02,0xd8,0x00,0xd6,0x04,0x2d,0x01,0x08,0x69,0x02,0x1c,0x00,0x85,0x00 } }, +{ 16, 0xc7e0, 0, {0x21,0x43,0x0b,0x70,0x03,0x9a,0xc0,0x8c,0x00,0xa3,0x02,0x08,0xf1,0x02,0x2a,0x04 } }, +{ 16, 0xc7f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xb7,0x01,0x2d,0xcc } }, +{ 16, 0xc800, 0, {0x08,0x70,0x02,0xd4,0x00,0x94,0x28,0x2d,0xc2,0x08,0xc2,0x02,0x5c,0x00,0x86,0x00 } }, +{ 16, 0xc810, 0, {0x21,0x80,0x0b,0x71,0x02,0xdc,0x00,0xa7,0x10,0x21,0xc0,0x08,0x48,0x02,0x40,0x00 } }, +{ 16, 0xc820, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x08,0xb3,0x00,0x2c,0xf0 } }, +{ 16, 0xc830, 0, {0x08,0x05,0x02,0xc0,0x20,0x90,0x80,0x2e,0x00,0x08,0x00,0x82,0x4c,0x02,0x80,0x00 } }, +{ 16, 0xc840, 0, {0xa0,0x61,0x0b,0x30,0x02,0xa0,0x00,0x80,0x00,0xa0,0x30,0x88,0xb1,0x0a,0x48,0x04 } }, +{ 16, 0xc850, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xff,0x00,0x2d,0xc8 } }, +{ 16, 0xc860, 0, {0x0c,0x3d,0x03,0xe4,0x00,0xdb,0x02,0x3e,0xf0,0x2c,0x90,0x4b,0x7c,0x00,0xc1,0x00 } }, +{ 16, 0xc870, 0, {0x32,0x20,0x4f,0xf0,0x13,0xe0,0x00,0xe8,0x01,0x32,0x00,0x8c,0xac,0x03,0x6a,0x04 } }, +{ 16, 0xc880, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xfb,0x04,0x3e,0xc2 } }, +{ 16, 0xc890, 0, {0x4f,0xb0,0x03,0xe0,0x04,0xfa,0x40,0x3e,0xc2,0x4e,0x98,0x23,0xac,0x10,0xf8,0x00 } }, +{ 16, 0xc8a0, 0, {0x3e,0x50,0x07,0xb0,0x13,0xac,0x00,0xfb,0x00,0x3e,0xc2,0x0f,0x92,0x03,0xa0,0x00 } }, +{ 16, 0xc8b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xdc,0x00,0xcf,0x00,0x3f,0xc0 } }, +{ 16, 0xc8c0, 0, {0x0c,0xc8,0x23,0x36,0x82,0xcf,0x80,0x3f,0x80,0x0c,0xe0,0x03,0xec,0x00,0xf9,0x20 } }, +{ 16, 0xc8d0, 0, {0x33,0xc0,0x0e,0xf0,0x03,0xf8,0x10,0xdc,0x00,0x33,0x00,0x4c,0xe8,0x21,0x00,0x44 } }, +{ 16, 0xc8e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x00,0xab,0x00,0x2e,0xc0 } }, +{ 16, 0xc8f0, 0, {0x4a,0x8d,0x42,0x21,0x00,0x8b,0x42,0x2e,0xd2,0x08,0xb0,0x03,0xec,0x00,0xb8,0x88 } }, +{ 16, 0xc900, 0, {0x34,0x62,0x0d,0xb0,0x02,0xe4,0x00,0x8b,0x00,0x22,0xc0,0x08,0x90,0x0a,0x20,0x40 } }, +{ 16, 0xc910, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x8b,0x00,0x2e,0xc0 } }, +{ 16, 0xc920, 0, {0x08,0xa0,0x02,0x0d,0x00,0x89,0x10,0x2e,0x08,0x28,0x92,0x02,0xec,0x04,0xbb,0x00 } }, +{ 16, 0xc930, 0, {0x22,0xa0,0x08,0xb0,0x02,0x64,0x02,0xb3,0x02,0x20,0xc0,0x08,0xa2,0x02,0xa0,0x00 } }, +{ 16, 0xc940, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0xa3,0x00,0x2e,0xc0 } }, +{ 16, 0xc950, 0, {0x0a,0x90,0x22,0x0c,0x10,0x80,0x00,0x2c,0x00,0x18,0x02,0x82,0xcc,0x00,0xb0,0x00 } }, +{ 16, 0xc960, 0, {0x26,0x40,0x09,0x30,0x02,0xc8,0x20,0x80,0x00,0x20,0x00,0x08,0x10,0x06,0x82,0x01 } }, +{ 16, 0xc970, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xcb,0x00,0x2e,0xc0 } }, +{ 16, 0xc980, 0, {0x0c,0xa1,0x02,0x24,0x00,0x88,0x00,0x3c,0x00,0x0c,0x80,0x03,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xc990, 0, {0x32,0x80,0x0e,0xb0,0x03,0xcc,0x80,0xdb,0x00,0x32,0xc0,0x0c,0xa0,0x03,0x80,0x03 } }, +{ 16, 0xc9a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0xc9b0, 0, {0x4f,0xc2,0x13,0xd4,0x10,0xfc,0x00,0x3f,0x00,0x0f,0x00,0x03,0xbc,0x00,0xfc,0x00 } }, +{ 16, 0xc9c0, 0, {0x3f,0x40,0x0f,0xf0,0x23,0xe0,0x12,0xfc,0x01,0xbf,0x00,0x0f,0xd0,0x03,0x68,0x02 } }, +{ 16, 0xc9d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x00,0xc7,0x80,0x33,0xc0 } }, +{ 16, 0xc9e0, 0, {0x8b,0xb4,0x03,0xb0,0xc0,0xcf,0x2e,0x1f,0x0c,0x4f,0xc3,0x03,0x30,0x80,0xff,0x01 } }, +{ 16, 0xc9f0, 0, {0x3f,0x08,0x0f,0xf0,0x00,0x7c,0x00,0xff,0x21,0x33,0xe4,0x0c,0xe0,0x03,0x30,0x00 } }, +{ 16, 0xca00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xee,0x00,0x8b,0x82,0x23,0xf0 } }, +{ 16, 0xca10, 0, {0x0b,0xb5,0x12,0x0d,0x88,0x88,0xc0,0x0e,0x98,0x0b,0x86,0x02,0x21,0x00,0xbb,0xc0 } }, +{ 16, 0xca20, 0, {0x2e,0xe4,0x4b,0xf7,0x83,0x2f,0x44,0xbf,0x90,0x22,0xc8,0x48,0xa6,0x82,0x20,0x04 } }, +{ 16, 0xca30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0x09,0x8a,0x00,0x20,0x50 } }, +{ 16, 0xca40, 0, {0x4b,0xb2,0x0a,0x80,0xcc,0x83,0x01,0x0c,0x8c,0x0b,0x23,0x0a,0x04,0x60,0xb3,0x14 } }, +{ 16, 0xca50, 0, {0x24,0x40,0x4b,0x30,0x02,0xcc,0x10,0xb3,0x00,0x20,0xc8,0xe9,0x11,0x06,0x62,0x01 } }, +{ 16, 0xca60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x01,0x8a,0x80,0xa2,0x44 } }, +{ 16, 0xca70, 0, {0x0b,0xb0,0x02,0xa1,0x04,0x88,0x40,0x2e,0xa0,0x0b,0x20,0x02,0x28,0x20,0xbb,0x40 } }, +{ 16, 0xca80, 0, {0x2e,0x40,0x0b,0xb0,0x02,0x2c,0x08,0xbb,0x00,0x22,0xc0,0x09,0xb0,0x02,0x70,0x04 } }, +{ 16, 0xca90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xc3,0x83,0x32,0xe0 } }, +{ 16, 0xcaa0, 0, {0x8f,0x00,0x03,0xa0,0x02,0xcb,0xc4,0x3e,0x28,0x07,0x8b,0x03,0x21,0x00,0xf9,0xc0 } }, +{ 16, 0xcab0, 0, {0x3e,0x10,0x0f,0xb0,0x03,0xec,0x00,0x7b,0x00,0x32,0xc0,0x0d,0xa0,0x03,0x50,0x04 } }, +{ 16, 0xcac0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x9c,0x02,0xff,0x00,0x3f,0xe0 } }, +{ 16, 0xcad0, 0, {0x0f,0xf4,0x43,0x5e,0x80,0xfc,0x94,0x3f,0x00,0x0f,0xc0,0x2b,0xf2,0x50,0xfd,0x21 } }, +{ 16, 0xcae0, 0, {0x7e,0x84,0x8f,0xf0,0x03,0x6c,0x0c,0xff,0x00,0x3f,0xc0,0x0e,0x62,0x03,0xb8,0x00 } }, +{ 16, 0xcaf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xeb,0x00,0x32,0x40 } }, +{ 16, 0xcb00, 0, {0x2c,0x80,0x03,0x69,0x00,0xcb,0x30,0xb2,0x00,0x4f,0xb3,0x43,0xe5,0x00,0xcb,0x40 } }, +{ 16, 0xcb10, 0, {0x72,0x18,0x2c,0xb0,0x03,0xec,0x28,0xc3,0x21,0x3a,0xc1,0x0f,0x94,0x03,0x10,0x04 } }, +{ 16, 0xcb20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x3c,0x00,0x8b,0x20,0x22,0x50 } }, +{ 16, 0xcb30, 0, {0x08,0xb0,0x02,0x28,0x00,0x88,0xc0,0x2a,0x00,0x8b,0xb4,0x02,0xe8,0x00,0xdb,0x00 } }, +{ 16, 0xcb40, 0, {0x62,0x30,0x08,0xf0,0x02,0xfc,0x00,0x8f,0x80,0x22,0xc0,0x0b,0x95,0x47,0x32,0x00 } }, +{ 16, 0xcb50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb1,0x00,0x20,0xc2 } }, +{ 16, 0xcb60, 0, {0x48,0x30,0x02,0x49,0x80,0x83,0x42,0x60,0x12,0x0b,0x30,0x02,0xc8,0x00,0x82,0x02 } }, +{ 16, 0xcb70, 0, {0x2c,0x30,0x09,0xb0,0x02,0xcf,0x01,0x83,0x50,0x2a,0xc0,0x0b,0x20,0x02,0xb8,0x00 } }, +{ 16, 0xcb80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x00,0x9d,0x80,0xa0,0xe0 } }, +{ 16, 0xcb90, 0, {0x08,0x79,0x22,0x5e,0x60,0x87,0x90,0x29,0xa0,0x0b,0x78,0x02,0xc6,0x00,0x92,0x81 } }, +{ 16, 0xcba0, 0, {0x05,0xe0,0x09,0x78,0x02,0xde,0x40,0x87,0x80,0x21,0xe0,0x0b,0x29,0x02,0x08,0x00 } }, +{ 16, 0xcbb0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x40,0xf2,0x00,0x30,0xc0 } }, +{ 16, 0xcbc0, 0, {0x08,0x3a,0x03,0x44,0x04,0xc3,0x14,0x30,0xc0,0x0f,0x22,0x03,0xcc,0x80,0xc2,0x00 } }, +{ 16, 0xcbd0, 0, {0xa4,0xd2,0x0d,0x30,0x13,0xcc,0x20,0xc3,0x00,0x38,0xc4,0x4f,0x04,0x43,0x12,0x02 } }, +{ 16, 0xcbe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0x9c,0x00,0xee,0x00,0x3f,0xe0 } }, +{ 16, 0xcbf0, 0, {0x0f,0x70,0x03,0xb4,0x02,0xf4,0x10,0x3f,0xc0,0x8f,0xa0,0x03,0xfc,0x00,0x7e,0x00 } }, +{ 16, 0xcc00, 0, {0x3b,0xc0,0x0e,0xf0,0x83,0xec,0x00,0xf7,0x00,0x3f,0xc0,0x0f,0xc0,0x03,0xd0,0x06 } }, +{ 16, 0xcc10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xfc,0x00,0xf9,0x00,0x3e,0xc0 } }, +{ 16, 0xcc20, 0, {0x0f,0xa0,0x03,0xaa,0x12,0xcb,0x01,0x32,0x80,0x0f,0xb0,0x13,0x28,0x14,0xf9,0x80 } }, +{ 16, 0xcc30, 0, {0x3a,0x40,0x03,0xb4,0x03,0xec,0x42,0xcb,0x18,0x3e,0xc0,0x0f,0xb0,0x03,0x2a,0x00 } }, +{ 16, 0xcc40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9d,0x00,0xb5,0x00,0x2d,0xc4 } }, +{ 16, 0xcc50, 0, {0x0b,0x70,0x4b,0x7c,0x00,0x84,0x00,0x21,0x80,0x0b,0x70,0x02,0x94,0x10,0xb2,0x00 } }, +{ 16, 0xcc60, 0, {0x29,0xc0,0x0b,0x72,0x82,0xdc,0x00,0x87,0x20,0x2d,0xc1,0x0e,0x70,0x02,0x12,0x04 } }, +{ 16, 0xcc70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0xb7,0x80,0x2d,0xe0 } }, +{ 16, 0xcc80, 0, {0x0b,0x68,0x02,0x9e,0x00,0x83,0x80,0x21,0xe0,0x5b,0x38,0x02,0x1e,0x00,0xb4,0xc0 } }, +{ 16, 0xcc90, 0, {0x25,0xe0,0x09,0x78,0x32,0xce,0x00,0x97,0x80,0x2d,0xe0,0x0b,0x5c,0x4e,0x30,0x00 } }, +{ 16, 0xcca0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0xb3,0x44,0x2c,0xc0 } }, +{ 16, 0xccb0, 0, {0x0b,0x3c,0x02,0xcc,0x40,0x93,0x08,0x20,0xe0,0x0b,0x30,0x02,0x8c,0x10,0xb3,0xc0 } }, +{ 16, 0xccc0, 0, {0x28,0xd8,0x1b,0x30,0x02,0xcc,0x08,0x93,0x01,0x6c,0xc0,0x0a,0xb8,0x82,0x12,0x04 } }, +{ 16, 0xccd0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xf6,0x10,0x3e,0x80 } }, +{ 16, 0xcce0, 0, {0x4b,0xed,0x83,0xb8,0x00,0xce,0xe4,0xb3,0xa3,0x0f,0xe0,0x03,0x38,0x00,0xfe,0x00 } }, +{ 16, 0xccf0, 0, {0x3b,0x80,0x0d,0xa0,0x02,0xe8,0x00,0xda,0x00,0x3e,0x80,0x0f,0xe8,0x02,0x3a,0x04 } }, +{ 16, 0xcd00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x10,0xf8,0x40,0x3e,0x00 } }, +{ 16, 0xcd10, 0, {0x0f,0x80,0x13,0x60,0x00,0xe0,0x00,0x3e,0x00,0x43,0x08,0x03,0xe0,0x00,0xf8,0x08 } }, +{ 16, 0xcd20, 0, {0x3a,0x00,0x0f,0x80,0x03,0xe0,0x00,0xe8,0x40,0x3e,0x00,0x0e,0x80,0x23,0xd2,0x00 } }, +{ 16, 0xcd30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xc4,0x00,0xd9,0xc0,0xbe,0x40 } }, +{ 16, 0xcd40, 0, {0x0f,0x90,0x03,0xe6,0x00,0xf9,0x00,0x32,0x40,0x01,0x9a,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0xcd50, 0, {0x3e,0x40,0x0f,0x90,0x03,0xc4,0x40,0x09,0x10,0x0e,0x40,0x0f,0x9a,0x03,0x02,0x04 } }, +{ 16, 0xcd60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x04,0x89,0x04,0xa2,0x60 } }, +{ 16, 0xcd70, 0, {0x8b,0x9d,0x80,0xa6,0x00,0xb9,0x80,0x22,0x40,0x48,0x98,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xcd80, 0, {0x2e,0x40,0x8b,0x90,0x02,0xe4,0x94,0x89,0x60,0x2e,0x40,0x0b,0x94,0x0b,0x20,0x00 } }, +{ 16, 0xcd90, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0x99,0x08,0xae,0x48 } }, +{ 16, 0xcda0, 0, {0x4b,0x10,0x02,0xe5,0x81,0xb9,0x10,0x20,0x44,0x1b,0x94,0x02,0x24,0x10,0xb9,0x00 } }, +{ 16, 0xcdb0, 0, {0x6e,0x60,0x0b,0x90,0x02,0xe4,0x00,0x89,0x00,0x2e,0x40,0x0b,0x94,0x02,0x06,0x00 } }, +{ 16, 0xcdc0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x80,0x89,0x00,0xa0,0x68 } }, +{ 16, 0xcdd0, 0, {0x0b,0x12,0x02,0x84,0x89,0xb1,0x20,0x20,0x48,0x1a,0x12,0x12,0x04,0x80,0xb1,0x22 } }, +{ 16, 0xcde0, 0, {0x0c,0x48,0x0b,0x12,0x02,0xc4,0x81,0xa1,0x20,0x2c,0x40,0x0b,0x12,0x02,0x02,0x01 } }, +{ 16, 0xcdf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x00,0xd8,0x00,0xbe,0x00 } }, +{ 16, 0xce00, 0, {0x0f,0x05,0x0b,0xe1,0x40,0xf8,0x00,0x32,0x14,0x0f,0x85,0x03,0x21,0x40,0xf8,0x00 } }, +{ 16, 0xce10, 0, {0x2e,0x80,0x0f,0x85,0x13,0xe0,0x02,0xc8,0x00,0x3e,0x14,0x0f,0x05,0x01,0x2e,0x03 } }, +{ 16, 0xce20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xe4,0x40,0xfd,0x00,0xbf,0x44 } }, +{ 16, 0xce30, 0, {0x0f,0xd1,0x03,0xf4,0x40,0x7d,0x10,0xbf,0x44,0x45,0xf1,0x2b,0xf4,0x40,0xfd,0x10 } }, +{ 16, 0xce40, 0, {0x3f,0x44,0x0f,0x91,0x03,0xe4,0x40,0xd9,0x10,0x3e,0x40,0x0f,0xd1,0x03,0xa6,0x06 } }, +{ 16, 0xce50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf6,0x00,0xfd,0x00,0x1f,0x62 } }, +{ 16, 0xce60, 0, {0x0f,0xd8,0x82,0x36,0x00,0xbd,0xa0,0x3b,0x68,0x0c,0xdc,0x83,0x26,0xc8,0xd9,0xa0 } }, +{ 16, 0xce70, 0, {0x33,0x60,0x0d,0x99,0x83,0x56,0x20,0xd5,0xa8,0x2e,0x44,0x0c,0xd8,0x83,0x86,0x04 } }, +{ 16, 0xce80, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x48,0xb8,0x00,0x2e,0x00 } }, +{ 16, 0xce90, 0, {0x0b,0x0a,0x82,0x22,0x20,0xb8,0x50,0x22,0xba,0x08,0x8a,0x22,0x22,0x80,0x88,0x00 } }, +{ 16, 0xcea0, 0, {0x22,0x01,0x08,0x0c,0x02,0x20,0x00,0x88,0x00,0x2e,0x28,0x88,0x88,0x02,0xce,0x04 } }, +{ 16, 0xceb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x00,0x2c,0x40 } }, +{ 16, 0xcec0, 0, {0x1b,0x10,0x0a,0x84,0x40,0xb1,0x00,0x28,0x58,0x0a,0x32,0x02,0x05,0x00,0x99,0x40 } }, +{ 16, 0xced0, 0, {0x20,0x65,0x09,0x10,0x42,0xc4,0x00,0x91,0x00,0x2c,0x40,0x0a,0x30,0x82,0xc2,0x01 } }, +{ 16, 0xcee0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa4,0x00,0xb9,0x00,0x2e,0x40 } }, +{ 16, 0xcef0, 0, {0x1b,0x90,0x02,0xa5,0x80,0xb9,0x10,0x22,0x48,0x08,0x10,0x42,0x04,0x10,0x09,0x00 } }, +{ 16, 0xcf00, 0, {0x22,0x40,0x08,0x90,0x02,0xe4,0x00,0x9b,0x00,0x2c,0x40,0x0a,0x94,0x22,0xc6,0x04 } }, +{ 16, 0xcf10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0x20,0x3e,0x40 } }, +{ 16, 0xcf20, 0, {0x0f,0x90,0x13,0xa7,0x10,0xf9,0x60,0xba,0x50,0x2e,0x9c,0x0a,0x25,0x84,0xd1,0xf0 } }, +{ 16, 0xcf30, 0, {0xb2,0x60,0x0d,0x90,0x03,0xe4,0x00,0xd9,0x00,0x3e,0x40,0x0e,0x90,0x03,0xa8,0x00 } }, +{ 16, 0xcf40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x0c,0xf9,0x90,0x3e,0x6a } }, +{ 16, 0xcf50, 0, {0x8f,0x90,0x23,0x66,0x00,0xf1,0x08,0x3c,0x40,0x0f,0x9c,0x43,0xe4,0x40,0xf9,0x80 } }, +{ 16, 0xcf60, 0, {0x3a,0x44,0x0f,0x90,0x03,0x24,0x04,0xe9,0x02,0x3e,0x40,0x2d,0x91,0x13,0xca,0x00 } }, +{ 16, 0xcf70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xe8,0x20,0x3e,0x01 } }, +{ 16, 0xcf80, 0, {0x0c,0x00,0x03,0xa1,0x20,0xe8,0x50,0x32,0x10,0x2c,0x8c,0x03,0x21,0x00,0xe8,0x00 } }, +{ 16, 0xcf90, 0, {0x32,0x02,0x0f,0x00,0x13,0x20,0x88,0xc8,0x08,0x32,0x00,0x0f,0x8c,0x03,0xca,0x00 } }, +{ 16, 0xcfa0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x20,0x8e,0xe3,0x2f,0x90 } }, +{ 16, 0xcfb0, 0, {0x0a,0xe0,0x06,0x3b,0x00,0xee,0x04,0x23,0x90,0x08,0xe0,0x02,0x28,0x08,0x8a,0x02 } }, +{ 16, 0xcfc0, 0, {0x75,0x90,0x8b,0xa0,0x41,0x58,0x90,0x8e,0x80,0x2a,0x81,0x0b,0xe0,0x03,0x8a,0x10 } }, +{ 16, 0xcfd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4e,0x00,0xa3,0x00,0x6c,0x60 } }, +{ 16, 0xcfe0, 0, {0x08,0x38,0x1a,0x8e,0x40,0xa0,0x80,0x20,0xcc,0x09,0x30,0x02,0x0c,0x05,0xa3,0x04 } }, +{ 16, 0xcff0, 0, {0x28,0xc4,0x0b,0x30,0x02,0x0d,0x01,0x83,0xc0,0x20,0xc0,0x0b,0x30,0x02,0xca,0x00 } }, +{ 16, 0xd000, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1e,0x08,0x87,0x00,0x2d,0x62 } }, +{ 16, 0xd010, 0, {0x0b,0x70,0x92,0x1c,0x08,0xa0,0x00,0x61,0xc0,0x09,0x60,0x06,0x1c,0x80,0xa7,0x00 } }, +{ 16, 0xd020, 0, {0x21,0xc0,0x0b,0x72,0x02,0x58,0x01,0x87,0x88,0x29,0xc0,0x0b,0x60,0x12,0xa8,0x00 } }, +{ 16, 0xd030, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xe6,0x80,0x3d,0x60 } }, +{ 16, 0xd040, 0, {0x0c,0x78,0x42,0x96,0x00,0xe4,0x80,0xa3,0x60,0x0d,0x78,0x03,0x3f,0x00,0xe3,0x80 } }, +{ 16, 0xd050, 0, {0x21,0xe0,0x0f,0x7b,0x03,0x16,0x08,0xc7,0x80,0x31,0xe2,0x4f,0x78,0x43,0xea,0x02 } }, +{ 16, 0xd060, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0x8c,0x01,0xf8,0x00,0x3c,0x40 } }, +{ 16, 0xd070, 0, {0x0e,0xb0,0x02,0xec,0x00,0xf8,0x01,0x3e,0x40,0x4e,0x30,0x33,0xed,0x20,0xdb,0x01 } }, +{ 16, 0xd080, 0, {0xbe,0xc0,0x0f,0xb4,0x03,0xec,0x00,0xfb,0x00,0x3e,0xd8,0x0f,0xa0,0x03,0xc2,0x06 } }, +{ 16, 0xd090, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xc7,0x84,0x23,0x60 } }, +{ 16, 0xd0a0, 0, {0x0c,0x78,0x0b,0xbe,0x00,0xfd,0x80,0x3f,0xe0,0x0f,0xeb,0x03,0x3e,0x00,0xcf,0x80 } }, +{ 16, 0xd0b0, 0, {0x3b,0x25,0x0c,0xf8,0x83,0x7e,0x40,0xcd,0x80,0x33,0xe2,0x0b,0xf9,0x03,0x00,0x00 } }, +{ 16, 0xd0c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x02,0x87,0x00,0x15,0x48 } }, +{ 16, 0xd0d0, 0, {0x08,0x70,0x02,0x14,0x20,0xb6,0x00,0x35,0x9a,0x49,0xc8,0x03,0x9c,0x84,0xa7,0x00 } }, +{ 16, 0xd0e0, 0, {0x39,0xd0,0x0a,0x70,0x02,0x1a,0x08,0xa4,0x00,0x21,0xc0,0x09,0x61,0x42,0x2a,0x04 } }, +{ 16, 0xd0f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0x87,0x00,0x21,0x40 } }, +{ 16, 0xd100, 0, {0x08,0x71,0x02,0x94,0x00,0xb5,0x00,0x2d,0x40,0x0b,0xf1,0x22,0x5c,0x02,0x07,0x08 } }, +{ 16, 0xd110, 0, {0x2c,0x50,0x08,0x70,0x02,0x50,0x00,0x87,0x00,0x2d,0xc4,0x0b,0x50,0x42,0x00,0x00 } }, +{ 16, 0xd120, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x00,0x83,0x02,0x24,0x40 } }, +{ 16, 0xd130, 0, {0x18,0x3d,0x0a,0x01,0x00,0xb0,0x58,0x24,0x20,0x09,0x30,0x02,0x8f,0x40,0x83,0xe0 } }, +{ 16, 0xd140, 0, {0x2c,0xc1,0x0a,0x30,0x42,0x08,0x00,0xb3,0x01,0x6c,0xc0,0x09,0x08,0x16,0x08,0x04 } }, +{ 16, 0xd150, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0x8c,0x00,0x8b,0x00,0x32,0x40 } }, +{ 16, 0xd160, 0, {0x0c,0x25,0x03,0xa8,0x48,0xf8,0x81,0x3e,0x80,0x0f,0x80,0x63,0x7c,0x00,0xcb,0x80 } }, +{ 16, 0xd170, 0, {0x3a,0xc0,0x0c,0xf0,0x03,0x6c,0x00,0xca,0x02,0xbf,0xc0,0x0f,0x98,0x8b,0x2a,0x04 } }, +{ 16, 0xd180, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xf9,0x00,0x3e,0x50 } }, +{ 16, 0xd190, 0, {0x2f,0xa4,0x0b,0xc8,0x00,0xf0,0x40,0x3e,0xd0,0x0f,0xa0,0x33,0xec,0x20,0xfb,0x04 } }, +{ 16, 0xd1a0, 0, {0x7a,0xe0,0x0f,0xb0,0x03,0xed,0x08,0xe9,0x03,0x32,0xc0,0x0d,0x90,0x03,0xe0,0x00 } }, +{ 16, 0xd1b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xec,0x40,0xee,0x00,0x3e,0xc0 } }, +{ 16, 0xd1c0, 0, {0x0c,0xda,0x03,0x70,0x04,0xcc,0x02,0xb1,0xa0,0x0e,0xf0,0x23,0xec,0x00,0xff,0x00 } }, +{ 16, 0xd1d0, 0, {0x37,0x20,0xcd,0xb0,0x73,0xec,0x88,0xfb,0x80,0x3f,0xc0,0x0f,0x30,0x03,0x00,0x44 } }, +{ 16, 0xd1e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6e,0x00,0x88,0x80,0x2c,0xe1 } }, +{ 16, 0xd1f0, 0, {0x08,0x94,0x0a,0xa9,0x02,0x88,0x40,0x22,0xd0,0x08,0xb9,0x42,0xec,0x04,0xbb,0x00 } }, +{ 16, 0xd200, 0, {0x2c,0xd4,0x0d,0xb0,0x02,0xed,0x20,0xbb,0xd0,0x2e,0xc0,0x0b,0xb0,0x02,0xa0,0x40 } }, +{ 16, 0xd210, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x24,0x00,0xab,0x80,0x2e,0xf0 } }, +{ 16, 0xd220, 0, {0x29,0xa0,0x82,0x6d,0x00,0x88,0x08,0x22,0x04,0x08,0x90,0x42,0xec,0x00,0xbb,0x00 } }, +{ 16, 0xd230, 0, {0x2a,0x81,0x08,0xb0,0x02,0xe4,0x09,0xba,0x04,0x2e,0xc1,0x4b,0x98,0x82,0x20,0x00 } }, +{ 16, 0xd240, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0x83,0x00,0x2c,0xc0 } }, +{ 16, 0xd250, 0, {0x0a,0x21,0x02,0x84,0x10,0x82,0x00,0xe0,0x00,0x18,0x0a,0x12,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0xd260, 0, {0x0c,0xc0,0x09,0x30,0x02,0xcc,0x90,0xb0,0x00,0x2c,0xc0,0x0b,0x10,0x02,0x82,0x01 } }, +{ 16, 0xd270, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x64,0x00,0xeb,0x00,0x3e,0x00 } }, +{ 16, 0xd280, 0, {0x2c,0xb4,0x03,0x64,0x08,0x88,0x00,0xb2,0x00,0x0c,0xb2,0x43,0xfc,0x00,0xfb,0x00 } }, +{ 16, 0xd290, 0, {0x56,0x00,0x0c,0xf0,0x01,0xe4,0x00,0xfb,0x00,0x3f,0xc0,0x0f,0x80,0x0b,0x00,0x03 } }, +{ 16, 0xd2a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xf4,0x00,0xff,0x00,0x3f,0x40 } }, +{ 16, 0xd2b0, 0, {0x2d,0xf0,0x61,0xf0,0x00,0xf4,0x00,0x27,0x01,0x0d,0xb1,0x11,0xfc,0x00,0xff,0x02 } }, +{ 16, 0xd2c0, 0, {0x07,0xc0,0x0f,0xf0,0x03,0xec,0x40,0xff,0x00,0x3f,0xc0,0x0f,0xc0,0x03,0x68,0x06 } }, +{ 16, 0xd2d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf6,0x00,0xef,0x90,0x3d,0x4c } }, +{ 16, 0xd2e0, 0, {0x2c,0xc0,0x13,0xf4,0x08,0xfd,0x20,0x37,0x4c,0x8e,0x82,0x83,0x74,0x84,0xdc,0xc2 } }, +{ 16, 0xd2f0, 0, {0x3f,0xd8,0x0d,0xf2,0x03,0xec,0xc0,0xff,0x81,0x3f,0x00,0x0c,0xf8,0x03,0xf0,0x00 } }, +{ 16, 0xd300, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe6,0x00,0x8b,0x24,0x2e,0x5c } }, +{ 16, 0xd310, 0, {0x08,0x8d,0x02,0xff,0x48,0xb9,0x90,0x2f,0x54,0x0b,0x84,0x82,0x3e,0x40,0xa0,0x80 } }, +{ 16, 0xd320, 0, {0x2e,0xc4,0x0a,0xfc,0x42,0xed,0x80,0xb9,0x80,0x2e,0x60,0x0a,0x98,0x12,0xe0,0x04 } }, +{ 16, 0xd330, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xe4,0x01,0xa3,0x00,0x28,0x48 } }, +{ 16, 0xd340, 0, {0x0a,0x00,0x42,0xc4,0x00,0xb1,0x00,0x2c,0x49,0x0b,0x0a,0x42,0x04,0xa2,0x91,0x21 } }, +{ 16, 0xd350, 0, {0x2c,0xc9,0x08,0x31,0x02,0x8c,0xc1,0xa3,0x00,0x2c,0x40,0x08,0x18,0x02,0xa2,0x01 } }, +{ 16, 0xd360, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa0,0x20,0x8b,0x82,0x2e,0x44 } }, +{ 16, 0xd370, 0, {0x58,0x80,0x02,0xe4,0x00,0xbb,0x10,0x2e,0x40,0x0b,0xa1,0x12,0x0c,0x01,0x89,0x10 } }, +{ 16, 0xd380, 0, {0x2e,0xc0,0x0a,0xb0,0x02,0xec,0x01,0xb8,0x80,0x2e,0xe2,0x0a,0xa1,0x02,0xf0,0x04 } }, +{ 16, 0xd390, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xeb,0x40,0xeb,0x40,0x3e,0x60 } }, +{ 16, 0xd3a0, 0, {0x0e,0x87,0x33,0xe4,0x00,0xb9,0xa1,0x36,0xc0,0x0e,0xa8,0x0b,0x26,0x00,0xda,0xc0 } }, +{ 16, 0xd3b0, 0, {0x3e,0xc0,0x8d,0xb0,0x03,0xec,0x00,0xfb,0x85,0x3e,0xe1,0x08,0xb8,0x03,0x90,0x05 } }, +{ 16, 0xd3c0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb8,0x00,0xff,0x02,0x2f,0x60 } }, +{ 16, 0xd3d0, 0, {0x03,0xe8,0x83,0xfc,0x10,0xfd,0x80,0x1f,0x40,0x1f,0xd0,0x13,0xbe,0x40,0xee,0x04 } }, +{ 16, 0xd3e0, 0, {0x3f,0xc0,0x0f,0xf0,0x43,0xfc,0x08,0xfd,0x00,0x3c,0xc0,0x0f,0xd0,0x11,0xf8,0x00 } }, +{ 16, 0xd3f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa4,0x00,0xdb,0x00,0xb2,0x40 } }, +{ 16, 0xd400, 0, {0x0e,0x94,0x03,0x24,0x00,0xd9,0x00,0xba,0xc0,0x0c,0x20,0x03,0xe4,0x90,0xfb,0x00 } }, +{ 16, 0xd410, 0, {0x3a,0xc0,0x0c,0xb0,0x03,0xec,0x01,0xfa,0x00,0x3e,0xd0,0x2c,0x98,0x03,0x90,0x04 } }, +{ 16, 0xd420, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x03,0x00,0x8b,0x00,0x22,0x48 } }, +{ 16, 0xd430, 0, {0x08,0x84,0x22,0x2c,0x00,0xb9,0x00,0x22,0xc0,0x08,0xa0,0x02,0xed,0x00,0x8b,0xa0 } }, +{ 16, 0xd440, 0, {0x21,0xc0,0x08,0xf0,0x02,0xfc,0x00,0xb9,0x80,0x2e,0xc0,0x08,0xa0,0x02,0x32,0x00 } }, +{ 16, 0xd450, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x45,0x20,0x93,0x00,0x22,0xf8 } }, +{ 16, 0xd460, 0, {0x0b,0x30,0x0a,0x84,0x40,0xb2,0x00,0x20,0x40,0x08,0x10,0x02,0xc4,0x00,0x80,0x80 } }, +{ 16, 0xd470, 0, {0x28,0xc0,0x28,0x39,0x02,0x4c,0x00,0xb1,0x00,0x2c,0xc0,0x08,0x30,0x02,0xb8,0x00 } }, +{ 16, 0xd480, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x36,0x00,0x9f,0x80,0x21,0x60 } }, +{ 16, 0xd490, 0, {0x09,0x38,0x02,0x9e,0x00,0xb2,0xc0,0x20,0x60,0x48,0x48,0x12,0xd6,0xc6,0x86,0xd0 } }, +{ 16, 0xd4a0, 0, {0x21,0xe0,0x08,0x78,0x00,0xde,0x80,0xb7,0x82,0x2d,0xe0,0x08,0xf8,0x02,0x08,0x00 } }, +{ 16, 0xd4b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x20,0xd3,0x10,0x30,0xc8 } }, +{ 16, 0xd4c0, 0, {0x0f,0x30,0x03,0x84,0x00,0xf1,0x00,0x30,0x40,0x24,0x19,0x03,0xe4,0xc0,0xe0,0x40 } }, +{ 16, 0xd4d0, 0, {0x3a,0xc0,0x0c,0x32,0x03,0xce,0x80,0xb1,0x28,0x3c,0xc0,0x0c,0x30,0x13,0x92,0x02 } }, +{ 16, 0xd4e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0x9c,0x00,0xe6,0x00,0x7f,0xc0 } }, +{ 16, 0xd4f0, 0, {0x0e,0xf0,0x23,0x74,0x40,0xff,0x10,0x3f,0x40,0x4f,0xd0,0x03,0xfc,0xd2,0xce,0x04 } }, +{ 16, 0xd500, 0, {0x3f,0xc0,0x0f,0xf4,0x03,0xfc,0x00,0xfe,0x00,0x3f,0xc0,0x0f,0x71,0x03,0xd0,0x12 } }, +{ 16, 0xd510, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xee,0x00,0xcb,0x00,0x16,0xc0 } }, +{ 16, 0xd520, 0, {0x0d,0x80,0x03,0x27,0x20,0xcb,0x00,0x3e,0xc2,0x0a,0xb0,0x53,0xe4,0x28,0xc1,0x81 } }, +{ 16, 0xd530, 0, {0x32,0xc1,0x0e,0xb9,0x03,0x2c,0x00,0xf1,0x80,0x35,0xe0,0x0c,0xb8,0x03,0x2a,0x04 } }, +{ 16, 0xd540, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x02,0x87,0x10,0x2d,0x40 } }, +{ 16, 0xd550, 0, {0x08,0x70,0x03,0x5c,0x00,0xa7,0x00,0x2d,0x40,0x28,0x70,0x02,0xd4,0x04,0x87,0x04 } }, +{ 16, 0xd560, 0, {0xa1,0xd0,0x0b,0x72,0x02,0x1d,0x00,0xf7,0x00,0x21,0xc0,0x0d,0x50,0x02,0x12,0x04 } }, +{ 16, 0xd570, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0x85,0x80,0x25,0xe0 } }, +{ 16, 0xd580, 0, {0x09,0x78,0x02,0x37,0x03,0x87,0x80,0x2f,0xe0,0x08,0x78,0x12,0xc6,0x10,0x8d,0x80 } }, +{ 16, 0xd590, 0, {0x25,0xe8,0x0b,0x38,0x02,0x1e,0x80,0xbc,0x84,0x25,0xe0,0x08,0x58,0x02,0x70,0x00 } }, +{ 16, 0xd5a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcd,0x80,0x83,0x88,0x2c,0xc0 } }, +{ 16, 0xd5b0, 0, {0x08,0x3c,0x02,0x4e,0x01,0xa3,0xd2,0x2e,0xc4,0x08,0xb1,0x02,0xcc,0x00,0x83,0x80 } }, +{ 16, 0xd5c0, 0, {0x24,0xc1,0x0b,0x30,0x02,0x0c,0x00,0xb3,0x40,0xa0,0xd2,0x09,0x30,0x12,0x52,0x00 } }, +{ 16, 0xd5d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xba,0x00,0xca,0xc0,0x36,0x80 } }, +{ 16, 0xd5e0, 0, {0x0d,0x67,0x13,0x28,0x00,0xce,0x00,0x3e,0xa0,0x0c,0xed,0x03,0xe8,0x00,0xce,0xe0 } }, +{ 16, 0xd5f0, 0, {0x36,0x80,0x1e,0xa0,0x0b,0x28,0x04,0xfe,0x00,0xb7,0xb2,0x0c,0xe0,0x0b,0x7a,0x00 } }, +{ 16, 0xd600, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x40,0xf8,0x10,0x2e,0x10 } }, +{ 16, 0xd610, 0, {0x0f,0x80,0x03,0xe0,0x01,0xd8,0x0a,0x3e,0x00,0x0f,0x80,0x03,0xc0,0x02,0xf8,0x08 } }, +{ 16, 0xd620, 0, {0x3a,0x00,0x0f,0x80,0x03,0xe0,0x10,0xe8,0x20,0xbe,0x00,0x0f,0x80,0x13,0x92,0x00 } }, +{ 16, 0xd630, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe5,0x00,0xfb,0x00,0x3e,0x40 } }, +{ 16, 0xd640, 0, {0x0c,0x91,0x03,0x26,0x00,0x61,0x80,0x32,0x40,0x0c,0x90,0x03,0x24,0x00,0xc9,0x00 } }, +{ 16, 0xd650, 0, {0x1e,0x40,0x0c,0x9c,0x03,0xe4,0x01,0xf9,0x00,0x3e,0x40,0x0f,0x90,0x03,0xc2,0x00 } }, +{ 16, 0xd660, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x67,0x00,0xb9,0x00,0x2c,0x40 } }, +{ 16, 0xd670, 0, {0x00,0x9c,0x02,0xa6,0x00,0x79,0x00,0x22,0x40,0x28,0x90,0x02,0x24,0x00,0x89,0x00 } }, +{ 16, 0xd680, 0, {0x2c,0x44,0x08,0x98,0x02,0xe4,0x00,0xb9,0x80,0x2e,0x40,0x0b,0x90,0x02,0xe0,0x01 } }, +{ 16, 0xd690, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0x24,0x00,0xbb,0x00,0x26,0x50 } }, +{ 16, 0xd6a0, 0, {0x28,0x90,0x82,0x24,0x84,0x99,0x20,0x22,0x40,0x49,0x90,0x02,0x24,0x00,0x89,0x00 } }, +{ 16, 0xd6b0, 0, {0x2e,0x40,0x08,0x90,0x02,0xe4,0x00,0xb9,0x60,0x2e,0x40,0x0b,0x90,0x02,0xc6,0x04 } }, +{ 16, 0xd6c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x06,0x00,0xb1,0x00,0x2e,0x48 } }, +{ 16, 0xd6d0, 0, {0x08,0x12,0x02,0x84,0x80,0xb1,0x20,0xa0,0x48,0x09,0x12,0x0a,0x04,0x80,0x81,0x00 } }, +{ 16, 0xd6e0, 0, {0x2c,0x48,0x28,0x12,0x42,0xc4,0x88,0x31,0x00,0x2c,0x40,0x0b,0x18,0x02,0xc2,0x01 } }, +{ 16, 0xd6f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x00,0xf8,0x50,0x36,0x14 } }, +{ 16, 0xd700, 0, {0x0c,0x80,0x03,0x20,0x00,0xe8,0x00,0x32,0x14,0x0c,0x85,0x03,0x21,0x40,0xc8,0x50 } }, +{ 16, 0xd710, 0, {0x3e,0x14,0x0c,0x80,0x03,0xe1,0x40,0x38,0x00,0x3e,0x00,0x8f,0x80,0x03,0xee,0x03 } }, +{ 16, 0xd720, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xd4,0x00,0xfb,0x04,0x3d,0x44 } }, +{ 16, 0xd730, 0, {0x0f,0x51,0x23,0xd4,0x48,0xed,0x10,0x3d,0x44,0x4e,0xd1,0x23,0xf4,0x42,0xfd,0x00 } }, +{ 16, 0xd740, 0, {0x3e,0x44,0x8f,0x91,0x03,0xe4,0x58,0xfd,0x00,0x3f,0x50,0x0f,0x50,0x03,0xe6,0x06 } }, +{ 16, 0xd750, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf4,0x00,0xf9,0x00,0x3d,0x40 } }, +{ 16, 0xd760, 0, {0x0c,0xd0,0x03,0xf4,0x00,0xdd,0x02,0x3e,0x40,0x0c,0x90,0x03,0xe4,0x40,0xc9,0x10 } }, +{ 16, 0xd770, 0, {0x37,0x40,0x07,0xd0,0x07,0x24,0x00,0xe5,0x00,0x2f,0x6a,0x0f,0x70,0x03,0x06,0x00 } }, +{ 16, 0xd780, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x00,0xb8,0x00,0x3a,0x00 } }, +{ 16, 0xd790, 0, {0x80,0x80,0x02,0xe0,0x00,0x88,0x00,0x2e,0x00,0x0a,0x80,0x53,0xa2,0x80,0x2c,0xa0 } }, +{ 16, 0xd7a0, 0, {0x22,0x00,0x0b,0x80,0x0a,0x20,0x00,0xb8,0x00,0x2e,0x10,0x09,0x80,0x03,0x0e,0x04 } }, +{ 16, 0xd7b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x00,0x6c,0x40 } }, +{ 16, 0xd7c0, 0, {0x2a,0x10,0x02,0x84,0x01,0x81,0x80,0x2e,0x40,0x09,0x10,0x02,0xf4,0x00,0x8d,0x04 } }, +{ 16, 0xd7d0, 0, {0x20,0x40,0x0b,0x10,0x02,0x84,0x00,0xb1,0x00,0x2c,0x40,0x0b,0x98,0x02,0x42,0x01 } }, +{ 16, 0xd7e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa4,0x20,0xb9,0x00,0x2a,0x40 } }, +{ 16, 0xd7f0, 0, {0x88,0xb4,0x02,0xe6,0x01,0xa9,0x20,0x2e,0x48,0x0a,0x90,0x00,0xa4,0x40,0xad,0x40 } }, +{ 16, 0xd800, 0, {0x22,0x40,0x0b,0x90,0x12,0xa4,0x04,0xb9,0x01,0x2e,0x41,0x0b,0x90,0x02,0x06,0x04 } }, +{ 16, 0xd810, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0xc0,0x3e,0x60 } }, +{ 16, 0xd820, 0, {0x0c,0x94,0x13,0xa6,0x02,0xd9,0x42,0x1c,0x60,0x0c,0x9e,0x01,0xc6,0x04,0xc1,0x00 } }, +{ 16, 0xd830, 0, {0xb2,0x40,0x1f,0x90,0x02,0xa4,0x00,0xe9,0x08,0x3e,0x68,0x4f,0x98,0x0b,0x68,0x04 } }, +{ 16, 0xd840, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa6,0x40,0xf9,0x20,0x38,0x70 } }, +{ 16, 0xd850, 0, {0x0f,0x91,0x03,0xe4,0x00,0xd9,0x80,0x3e,0x40,0x0f,0x9c,0x13,0xa4,0x00,0xf9,0x00 } }, +{ 16, 0xd860, 0, {0x3e,0x40,0x0f,0x10,0x03,0x64,0x10,0xf9,0x0a,0x3e,0x50,0x0d,0x9a,0x03,0xca,0x00 } }, +{ 16, 0xd870, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa1,0x00,0xd8,0x04,0x3e,0x00 } }, +{ 16, 0xd880, 0, {0x0c,0x81,0x13,0xc0,0x02,0xd8,0x20,0x3e,0x00,0x2d,0x84,0x03,0xe0,0x00,0xcc,0x08 } }, +{ 16, 0xd890, 0, {0x3a,0x00,0x0f,0x80,0x43,0xe0,0x00,0xf8,0x41,0x32,0x00,0x07,0x81,0x8b,0x0a,0x04 } }, +{ 16, 0xd8a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x3a,0x60,0x8a,0x00,0x2f,0xa8 } }, +{ 16, 0xd8b0, 0, {0x0a,0xe0,0x22,0xe8,0x02,0x7e,0x48,0x2e,0x80,0x08,0xa0,0x42,0xe8,0x04,0x8e,0x00 } }, +{ 16, 0xd8c0, 0, {0x23,0xa8,0x0b,0xa8,0x82,0xe8,0x00,0xee,0x00,0xa2,0x80,0x4b,0x60,0x02,0x0a,0x00 } }, +{ 16, 0xd8d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x93,0x00,0x6c,0xc0 } }, +{ 16, 0xd8e0, 0, {0x08,0x30,0x02,0xcc,0x00,0x13,0x81,0x2c,0xc0,0x08,0x30,0x02,0xce,0x40,0x82,0x40 } }, +{ 16, 0xd8f0, 0, {0x28,0xe0,0x0b,0x38,0x02,0xcc,0x00,0xb3,0x10,0x24,0xc0,0x8b,0x38,0x02,0x0a,0x00 } }, +{ 16, 0xd900, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1e,0x00,0x87,0x20,0x2f,0xc0 } }, +{ 16, 0xd910, 0, {0x0a,0x70,0x02,0xdc,0x0a,0xb6,0x00,0x2c,0xc8,0x88,0x72,0x06,0xd8,0x00,0x86,0x00 } }, +{ 16, 0xd920, 0, {0x21,0xc0,0x0b,0x70,0x02,0xdc,0x84,0xaf,0x80,0xa5,0xc0,0x0b,0xd0,0x02,0x28,0x00 } }, +{ 16, 0xd930, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xd7,0x80,0x3d,0xa0 } }, +{ 16, 0xd940, 0, {0x1c,0x78,0x13,0xd6,0x02,0xd7,0x80,0x3d,0xec,0x08,0x7e,0x23,0xfe,0x00,0xce,0x80 } }, +{ 16, 0xd950, 0, {0x39,0x60,0x0f,0x78,0x03,0xdf,0x00,0xf6,0x80,0x75,0xe0,0x0f,0x78,0x03,0x2a,0x02 } }, +{ 16, 0xd960, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0x8c,0x00,0xfb,0x10,0x3e,0x80 } }, +{ 16, 0xd970, 0, {0x1f,0xa0,0x21,0xcc,0x00,0xfa,0x00,0x3e,0xc0,0x0e,0xb0,0x03,0xe8,0x02,0xfa,0x00 } }, +{ 16, 0xd980, 0, {0x3e,0x40,0x0f,0xb0,0x13,0xec,0x00,0xea,0x01,0x3a,0xc0,0x0f,0x90,0x03,0xc2,0x06 } }, +{ 16, 0xd990, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfc,0x00,0xff,0x80,0x3f,0x60 } }, +{ 16, 0xd9a0, 0, {0x08,0x99,0x07,0x7e,0x00,0xdd,0x80,0x3f,0xe2,0x0c,0xf8,0x03,0xf6,0x02,0xdf,0x80 } }, +{ 16, 0xd9b0, 0, {0xb3,0xe0,0x0c,0xf8,0x03,0x3e,0x41,0xcc,0x80,0x33,0xe4,0x0f,0xf8,0x03,0xc0,0x00 } }, +{ 16, 0xd9c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x40,0xb7,0x00,0x2d,0xc0 } }, +{ 16, 0xd9d0, 0, {0x0d,0x5a,0x22,0xdc,0x80,0x75,0x00,0x2d,0xc0,0x08,0x71,0x02,0xf0,0x20,0x87,0x00 } }, +{ 16, 0xd9e0, 0, {0x21,0xc0,0x0a,0x70,0x02,0x1c,0x00,0xd4,0x28,0x21,0xc0,0x0b,0x72,0x02,0xea,0x04 } }, +{ 16, 0xd9f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x40,0xb7,0x00,0x2d,0x00 } }, +{ 16, 0xda00, 0, {0x08,0x72,0x22,0xf4,0x00,0x87,0x00,0x2d,0xc2,0x08,0x70,0x02,0xd4,0x00,0x87,0x80 } }, +{ 16, 0xda10, 0, {0x25,0x40,0x09,0x30,0x02,0x5c,0x01,0xad,0x00,0x29,0xd0,0x4b,0x70,0x02,0xc0,0x00 } }, +{ 16, 0xda20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x00,0xbb,0xc8,0x2c,0xa0 } }, +{ 16, 0xda30, 0, {0x09,0x20,0x02,0xce,0x00,0xa3,0x00,0x2c,0xe0,0xa8,0x3d,0x42,0xc2,0x00,0x8b,0x80 } }, +{ 16, 0xda40, 0, {0x24,0x40,0x0b,0x30,0x0a,0x6c,0x08,0xa3,0x40,0xa8,0xe0,0x0b,0x34,0x02,0xc8,0x04 } }, +{ 16, 0xda50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xad,0x00,0xff,0x48,0x3c,0x28 } }, +{ 16, 0xda60, 0, {0x0c,0xa9,0x23,0x6c,0x80,0x8b,0x00,0x3f,0xc0,0x0c,0xfc,0x03,0xec,0x00,0xd8,0x80 } }, +{ 16, 0xda70, 0, {0x34,0x40,0x0d,0x30,0x03,0x7c,0x02,0xa3,0x40,0x38,0x68,0x0f,0x24,0x03,0xea,0x04 } }, +{ 16, 0xda80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xed,0x88,0xfb,0x00,0x3e,0x50 } }, +{ 16, 0xda90, 0, {0x0f,0xa1,0x03,0xec,0x04,0x3a,0xc0,0x3e,0xc0,0x0f,0xb0,0x83,0xe8,0x02,0xf8,0x10 } }, +{ 16, 0xdaa0, 0, {0x3a,0x41,0x0e,0x90,0x03,0xac,0x00,0x9b,0x08,0xb6,0x40,0x0f,0x81,0x03,0xe0,0x00 } }, +{ 16, 0xdab0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xff,0x00,0xb3,0x20 } }, +{ 16, 0xdac0, 0, {0x0c,0x50,0x13,0x1c,0x09,0xcd,0x83,0x33,0xc0,0x83,0x70,0x00,0x3c,0x00,0xdc,0x10 } }, +{ 16, 0xdad0, 0, {0x32,0x60,0x0e,0xf1,0x43,0x2c,0x00,0xce,0x04,0x3b,0x70,0x0c,0xf0,0x83,0x00,0x44 } }, +{ 16, 0xdae0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x67,0x80,0xbb,0x01,0x62,0x21 } }, +{ 16, 0xdaf0, 0, {0x8a,0x89,0x20,0x2c,0x00,0x80,0xe0,0x22,0xc0,0x0b,0xb0,0x03,0xd8,0x10,0x8c,0x04 } }, +{ 16, 0xdb00, 0, {0x22,0x40,0x05,0x90,0x02,0xac,0x00,0xd8,0x80,0x36,0x40,0x0a,0x90,0x02,0x20,0x40 } }, +{ 16, 0xdb10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x26,0x00,0xbb,0x00,0x22,0x06 } }, +{ 16, 0xdb20, 0, {0x08,0x80,0x02,0x2e,0x00,0x88,0x20,0x22,0xc0,0x09,0xb0,0x02,0xa4,0x00,0x99,0x00 } }, +{ 16, 0xdb30, 0, {0x62,0xc4,0x08,0xb0,0x06,0x2c,0x00,0x88,0x80,0x22,0x41,0x08,0xa0,0x02,0x20,0x00 } }, +{ 16, 0xdb40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0xb3,0x00,0x20,0x40 } }, +{ 16, 0xdb50, 0, {0x0a,0x00,0x82,0x0c,0x00,0x80,0x00,0x20,0xc0,0x0b,0x30,0x22,0xa0,0x00,0x81,0x00 } }, +{ 16, 0xdb60, 0, {0xa0,0xc0,0x09,0x30,0x02,0x8c,0x00,0x90,0x00,0x24,0x40,0x0a,0x28,0x02,0x02,0x01 } }, +{ 16, 0xdb70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x60,0x00,0xfb,0x02,0x20,0x00 } }, +{ 16, 0xdb80, 0, {0x2c,0x92,0x03,0x2c,0x02,0x88,0x00,0x31,0xc0,0x0b,0xb5,0x02,0xa4,0x00,0xd1,0x04 } }, +{ 16, 0xdb90, 0, {0x32,0x40,0x0e,0x90,0x03,0x2c,0x40,0xc9,0x00,0x3a,0x40,0x8c,0xa0,0x03,0x00,0x03 } }, +{ 16, 0xdba0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xf4,0x00,0xff,0x00,0x2f,0x00 } }, +{ 16, 0xdbb0, 0, {0x0f,0xc0,0x03,0xdc,0x00,0xfc,0x00,0x3f,0xc1,0x0f,0xf0,0x43,0xf0,0x00,0xfd,0x00 } }, +{ 16, 0xdbc0, 0, {0x3f,0x40,0x4f,0xd0,0x03,0xfc,0x00,0xf5,0x00,0x3f,0x40,0x0f,0xe0,0x03,0xe8,0x06 } }, +{ 16, 0xdbd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xd8,0x80,0xcc,0x00,0xb7,0x04 } }, +{ 16, 0xdbe0, 0, {0x4e,0xe1,0x03,0x3c,0x20,0xdf,0x10,0x31,0x80,0x06,0xf0,0x03,0x7f,0x00,0xff,0xc0 } }, +{ 16, 0xdbf0, 0, {0x3b,0xc0,0x0e,0xf2,0x03,0x5e,0x00,0xef,0x10,0x33,0xd0,0x2c,0xf2,0x03,0x30,0x00 } }, +{ 16, 0xdc00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x10,0xe9,0x00,0x88,0xc6,0x20,0x5c } }, +{ 16, 0xdc10, 0, {0x08,0xa4,0x57,0x65,0x00,0x8f,0x52,0x2a,0xf0,0x09,0xfc,0x02,0x04,0x00,0xbb,0x00 } }, +{ 16, 0xdc20, 0, {0x2d,0xd9,0x09,0x74,0x83,0x64,0x28,0x83,0x44,0x22,0x84,0x88,0x06,0x82,0x30,0x04 } }, +{ 16, 0xdc30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0xc9,0x00,0x80,0x10,0x20,0x08 } }, +{ 16, 0xdc40, 0, {0x08,0x31,0x12,0x04,0xb2,0xa3,0x00,0x20,0x84,0x1b,0x34,0x02,0x0c,0x80,0xb3,0x20 } }, +{ 16, 0xdc50, 0, {0x2c,0xc7,0x09,0x36,0x02,0x8c,0x80,0x93,0x40,0xac,0xc8,0x08,0x31,0x28,0x32,0x01 } }, +{ 16, 0xdc60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa9,0x00,0x88,0x00,0xa2,0x50 } }, +{ 16, 0xdc70, 0, {0x08,0x35,0x02,0x24,0x00,0x8b,0x04,0x2e,0xc1,0x09,0xb0,0x02,0x24,0x94,0xbb,0x00 } }, +{ 16, 0xdc80, 0, {0x2e,0xc0,0x0b,0xb0,0x02,0xcc,0x60,0x8b,0x00,0x2e,0x80,0x08,0x80,0x00,0x30,0x04 } }, +{ 16, 0xdc90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xe7,0x02,0xcb,0x18,0xb2,0x80 } }, +{ 16, 0xdca0, 0, {0x2c,0xac,0x0a,0x2e,0x08,0xeb,0x00,0x32,0x12,0x4e,0xb0,0x03,0x2b,0x80,0xfb,0x00 } }, +{ 16, 0xdcb0, 0, {0x3a,0xc0,0x0a,0xb0,0x03,0xab,0x08,0xeb,0x04,0x2e,0x48,0x0c,0xb8,0x83,0x00,0x04 } }, +{ 16, 0xdcc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb6,0x80,0xff,0x80,0x39,0xca } }, +{ 16, 0xdcd0, 0, {0x0d,0xe8,0x03,0xd6,0x40,0xe7,0x04,0x3b,0x66,0x4e,0x70,0x03,0xb8,0x00,0xff,0x01 } }, +{ 16, 0xdce0, 0, {0x3f,0xc0,0x6c,0xf0,0x03,0x70,0x06,0xe7,0x00,0x31,0x04,0x0f,0xc1,0x43,0xf8,0x00 } }, +{ 16, 0xdcf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0x85,0x00,0xcb,0x40,0x32,0x90 } }, +{ 16, 0xdd00, 0, {0x2f,0xb0,0x0b,0x64,0x80,0xfb,0x08,0xba,0x10,0x0d,0xb0,0xa7,0x2d,0x00,0xfb,0x04 } }, +{ 16, 0xdd10, 0, {0x3e,0xc0,0x8e,0xb0,0x03,0x6d,0x00,0xdb,0x01,0x32,0x40,0x8c,0x33,0x03,0x90,0x04 } }, +{ 16, 0xdd20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0x24,0x00,0x83,0xe0,0xa2,0xd0 } }, +{ 16, 0xdd30, 0, {0x40,0xb0,0x02,0x25,0x04,0xbf,0x80,0xa0,0x50,0x08,0xf8,0x02,0x20,0x00,0x8b,0x02 } }, +{ 16, 0xdd40, 0, {0x2f,0xd0,0x08,0xf0,0x02,0x24,0x00,0x8f,0x80,0x36,0x01,0x08,0x84,0x42,0x36,0x00 } }, +{ 16, 0xdd50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x05,0x44,0x00,0x83,0x48,0x20,0xc4 } }, +{ 16, 0xdd60, 0, {0x09,0x00,0x02,0x46,0x00,0xb3,0x01,0xa8,0x90,0x19,0x30,0x12,0x8c,0x00,0xa3,0x04 } }, +{ 16, 0xdd70, 0, {0x2e,0xe2,0x0a,0xb0,0x02,0x0c,0x00,0x83,0x49,0x28,0xc0,0x09,0x3c,0x02,0x38,0x00 } }, +{ 16, 0xdd80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x01,0x36,0x04,0x83,0x80,0x21,0xe1 } }, +{ 16, 0xdd90, 0, {0x08,0x38,0x12,0x1e,0x28,0xb3,0x98,0x21,0xa0,0x19,0x38,0x82,0x96,0x00,0x87,0x83 } }, +{ 16, 0xdda0, 0, {0x2d,0xe2,0x08,0x78,0x22,0x36,0x8c,0x87,0x80,0x2d,0xe0,0x09,0x79,0x02,0x3e,0x00 } }, +{ 16, 0xddb0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x04,0x00,0xc3,0x30,0x30,0xc8 } }, +{ 16, 0xddc0, 0, {0x4d,0x00,0x0b,0x4c,0x80,0xf3,0x12,0x38,0xc0,0x0d,0x3a,0x02,0x8c,0x80,0xf3,0x00 } }, +{ 16, 0xddd0, 0, {0x3c,0xc0,0x0e,0x30,0x0b,0x0e,0x00,0xc3,0x0c,0x3a,0xc0,0x0d,0x30,0x03,0x12,0x02 } }, +{ 16, 0xdde0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xb4,0x06,0xff,0x10,0x3f,0xc0 } }, +{ 16, 0xddf0, 0, {0x0f,0xb0,0x13,0xbc,0x00,0xff,0x10,0x7f,0xc0,0x0e,0xf1,0xa3,0x7c,0x00,0xff,0x12 } }, +{ 16, 0xde00, 0, {0x3f,0xc2,0x0f,0xf5,0x23,0xbc,0x41,0xef,0x18,0x37,0x80,0xae,0xc0,0x03,0x50,0x06 } }, +{ 16, 0xde10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe4,0x00,0xdb,0x00,0x3e,0xda } }, +{ 16, 0xde20, 0, {0x0c,0x80,0x03,0x66,0x10,0x8b,0x00,0x32,0x80,0x8c,0xb6,0x03,0x4a,0x00,0x4b,0x80 } }, +{ 16, 0xde30, 0, {0x32,0xc8,0x0c,0xb4,0x03,0x0a,0x10,0xdb,0x00,0x3e,0xc1,0x0c,0xb0,0x43,0x2a,0x00 } }, +{ 16, 0xde40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x11,0xb4,0x00,0x87,0x04,0x2c,0xc0 } }, +{ 16, 0xde50, 0, {0x0d,0x70,0x03,0x1c,0x08,0x87,0x48,0x20,0x81,0x0d,0x72,0x82,0x5c,0x00,0xd7,0x00 } }, +{ 16, 0xde60, 0, {0x21,0xcc,0x28,0xf0,0x02,0x1c,0x10,0x87,0x20,0x2c,0x00,0x08,0x40,0x0a,0x32,0x04 } }, +{ 16, 0xde70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x96,0x00,0xb7,0x81,0x2d,0xe0 } }, +{ 16, 0xde80, 0, {0x08,0x48,0x02,0x0e,0x04,0x87,0x80,0x21,0xe0,0x08,0x78,0x02,0x3e,0x01,0x87,0x80 } }, +{ 16, 0xde90, 0, {0x21,0xe0,0x18,0x79,0x02,0x3a,0x01,0x97,0xa0,0x2d,0x60,0x08,0x38,0x02,0x20,0x00 } }, +{ 16, 0xdea0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xc6,0x00,0xa3,0xc6,0x2c,0xc0 } }, +{ 16, 0xdeb0, 0, {0x09,0x30,0x02,0x0c,0x01,0x83,0x00,0x20,0xe0,0x09,0x30,0x02,0x4e,0x00,0x93,0x00 } }, +{ 16, 0xdec0, 0, {0x20,0xc0,0x49,0x30,0x22,0x0f,0x64,0x83,0x02,0x6c,0xd4,0x28,0x30,0x02,0x12,0x04 } }, +{ 16, 0xded0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x11,0xab,0x80,0xfa,0xe0,0x3c,0x88 } }, +{ 16, 0xdee0, 0, {0x0c,0xe0,0x02,0x28,0x02,0xca,0x00,0xb3,0xa9,0x0c,0xa0,0x03,0x3b,0x10,0xca,0x00 } }, +{ 16, 0xdef0, 0, {0xa2,0x80,0x0c,0xa0,0x0b,0x38,0x00,0xda,0x00,0x3f,0xb0,0x0c,0xe6,0x03,0x3a,0x04 } }, +{ 16, 0xdf00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xc0,0x20,0x98,0x08,0x3e,0x00 } }, +{ 16, 0xdf10, 0, {0x0f,0x80,0x0b,0xe1,0x00,0xf8,0x01,0x3c,0x10,0x4f,0x00,0x03,0xa0,0x40,0xf8,0x00 } }, +{ 16, 0xdf20, 0, {0x3e,0x10,0x0e,0x80,0x03,0xe0,0x00,0xf8,0x00,0x3c,0x02,0x2f,0x04,0x93,0xd2,0x00 } }, +{ 16, 0xdf30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xc1,0xc1,0x32,0x40 } }, +{ 16, 0xdf40, 0, {0x0c,0x98,0x03,0x26,0x40,0xf9,0x00,0x32,0x40,0x0c,0x98,0x03,0x24,0x24,0xf9,0x00 } }, +{ 16, 0xdf50, 0, {0x3c,0x60,0x0c,0x10,0x03,0xa4,0x00,0xf9,0x82,0x32,0x40,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xdf60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x89,0x00,0x22,0x50 } }, +{ 16, 0xdf70, 0, {0x0d,0x98,0x02,0x25,0x80,0xb9,0x00,0x22,0x52,0x0d,0x9c,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xdf80, 0, {0x2e,0x60,0x08,0x90,0x42,0x24,0x00,0xb9,0x40,0x36,0x40,0x08,0x90,0x0a,0x20,0x00 } }, +{ 16, 0xdf90, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0x8d,0x00,0x23,0x40 } }, +{ 16, 0xdfa0, 0, {0x08,0x12,0x02,0x24,0x00,0xa1,0x10,0xa2,0x60,0x08,0x92,0x8a,0x24,0x00,0xb9,0x01 } }, +{ 16, 0xdfb0, 0, {0x2e,0x46,0x08,0x90,0x02,0xa4,0x00,0xb1,0x50,0x22,0x40,0x28,0x90,0x82,0x06,0x00 } }, +{ 16, 0xdfc0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x84,0x85,0x20,0xa1,0xd8 } }, +{ 16, 0xdfd0, 0, {0x09,0x10,0x02,0x04,0x80,0xb3,0x20,0x20,0x40,0x29,0x12,0x06,0x04,0x00,0xb1,0x01 } }, +{ 16, 0xdfe0, 0, {0x2c,0x48,0x28,0x12,0x02,0x04,0x00,0xb1,0x20,0x24,0x48,0x08,0x12,0x02,0x02,0x01 } }, +{ 16, 0xdff0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x42,0x8a,0x00,0xb3,0x00 } }, +{ 16, 0xe000, 0, {0x0c,0x05,0x03,0x21,0x40,0xe0,0x50,0xb2,0x00,0x2c,0x80,0x02,0x21,0x40,0xf0,0x50 } }, +{ 16, 0xe010, 0, {0x3c,0x14,0x0c,0x85,0x13,0xa1,0x50,0xf8,0x50,0x32,0x14,0x0c,0x85,0x23,0x2e,0x03 } }, +{ 16, 0xe020, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x40,0xf9,0x10,0x3e,0x44 } }, +{ 16, 0xe030, 0, {0x0f,0xd4,0x0b,0xf4,0x44,0xf9,0x10,0x3f,0x50,0x4f,0x11,0x03,0xf4,0x00,0xf9,0x00 } }, +{ 16, 0xe040, 0, {0x3e,0x44,0x0f,0x91,0x53,0xf4,0x14,0xf9,0x10,0x3f,0x44,0x0f,0xd1,0x03,0xe6,0x02 } }, +{ 16, 0xe050, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x05,0xe6,0xa0,0xdd,0x88,0xb3,0x66 } }, +{ 16, 0xe060, 0, {0x0c,0xdc,0x83,0x36,0x88,0xbd,0xa0,0x37,0x6a,0x0c,0xda,0x0b,0x25,0x02,0xc9,0x40 } }, +{ 16, 0xe070, 0, {0x3f,0x78,0x4f,0x98,0xb3,0xe5,0x04,0xcd,0xa0,0x72,0x78,0x0c,0xd8,0x8b,0x26,0x14 } }, +{ 16, 0xe080, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe3,0x00,0x88,0x42,0x22,0x31 } }, +{ 16, 0xe090, 0, {0x08,0x0a,0x02,0x22,0xa0,0xb8,0xf9,0x22,0x10,0x0d,0x84,0x12,0x6a,0x80,0x88,0x80 } }, +{ 16, 0xe0a0, 0, {0x2e,0x20,0x0b,0x08,0x02,0xe2,0x80,0xa8,0xa8,0xa2,0x38,0x48,0xa8,0x02,0x0e,0x00 } }, +{ 16, 0xe0b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x05,0xc4,0xa2,0x81,0x00,0x20,0x48 } }, +{ 16, 0xe0c0, 0, {0x08,0x12,0x42,0x45,0x00,0xb1,0x00,0x24,0x40,0x09,0x14,0x02,0x24,0x00,0x81,0x20 } }, +{ 16, 0xe0d0, 0, {0x2c,0x58,0x0b,0x10,0x82,0xc4,0x04,0x91,0x40,0x64,0x6c,0x08,0x30,0x82,0x12,0x05 } }, +{ 16, 0xe0e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x00,0x89,0x00,0x22,0x41 } }, +{ 16, 0xe0f0, 0, {0x08,0x90,0x8a,0x64,0x80,0xb9,0x00,0x22,0x50,0x09,0x90,0x06,0x64,0x08,0x99,0x00 } }, +{ 16, 0xe100, 0, {0x2e,0x40,0x0b,0x90,0x06,0xc4,0x01,0xb9,0x02,0x26,0x61,0x88,0x90,0x02,0x06,0x04 } }, +{ 16, 0xe110, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xc9,0x00,0x22,0x40 } }, +{ 16, 0xe120, 0, {0x2c,0x94,0x23,0x64,0x00,0xb9,0x00,0x36,0x40,0x09,0x90,0x13,0x05,0x00,0xc9,0x00 } }, +{ 16, 0xe130, 0, {0x3e,0x40,0x4f,0x90,0x13,0xe5,0xc0,0xd9,0x00,0x26,0x40,0x2c,0x94,0x03,0x28,0x00 } }, +{ 16, 0xe140, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x01,0xa4,0x02,0xe9,0x08,0x3c,0x40 } }, +{ 16, 0xe150, 0, {0x0f,0x90,0x0b,0xa4,0x00,0xf1,0x00,0x3e,0x41,0x0f,0x90,0x43,0xa4,0x88,0xe9,0x04 } }, +{ 16, 0xe160, 0, {0x3e,0x40,0x0f,0x90,0x03,0xe6,0x00,0xe1,0x00,0x3a,0x40,0x9f,0x92,0x63,0xda,0x00 } }, +{ 16, 0xe170, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0x80,0x10,0xe0,0x01,0x32,0x00 } }, +{ 16, 0xe180, 0, {0x8f,0x80,0x03,0x20,0x00,0xd8,0x08,0x30,0x01,0x8c,0x00,0x03,0xe1,0x02,0xc8,0x04 } }, +{ 16, 0xe190, 0, {0x3e,0x00,0x0c,0x80,0x0b,0x21,0x00,0xc8,0x00,0x78,0x00,0x0f,0x86,0x03,0x0a,0x00 } }, +{ 16, 0xe1a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x8e,0x40,0x2b,0x82 } }, +{ 16, 0xe1b0, 0, {0x0b,0xa0,0x02,0x3a,0x00,0x8e,0x80,0x23,0x82,0x08,0xe2,0x02,0x28,0x10,0x8a,0x00 } }, +{ 16, 0xe1c0, 0, {0x2f,0x98,0x28,0xa0,0x12,0x28,0x00,0x8e,0x20,0x2e,0x80,0x4b,0xe4,0x02,0x0a,0x00 } }, +{ 16, 0xe1d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x02,0xa2,0x40,0x20,0x80 } }, +{ 16, 0xe1e0, 0, {0x0b,0xb0,0x02,0x4e,0x40,0x93,0xc0,0xa0,0x20,0x08,0x36,0x02,0x8c,0x00,0x93,0x00 } }, +{ 16, 0xe1f0, 0, {0x2c,0xe2,0x08,0x30,0x06,0x4c,0x12,0x93,0x08,0x28,0xc0,0x0b,0xb0,0x02,0x0a,0x00 } }, +{ 16, 0xe200, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x08,0x82,0x40,0x29,0x40 } }, +{ 16, 0xe210, 0, {0x0b,0x70,0x02,0x5e,0x08,0x84,0x08,0x23,0x40,0x08,0x70,0x06,0x1c,0x80,0x87,0x00 } }, +{ 16, 0xe220, 0, {0x2d,0x20,0x08,0x79,0x12,0x5c,0x00,0x94,0x00,0x2d,0xc0,0x0b,0x30,0x42,0x28,0x00 } }, +{ 16, 0xe230, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x3e,0x00,0xe4,0x80,0x31,0xa1 } }, +{ 16, 0xe240, 0, {0x0f,0x58,0x13,0x76,0x00,0xd0,0x80,0x31,0xc0,0x0c,0x38,0x03,0xbe,0x80,0xd7,0x81 } }, +{ 16, 0xe250, 0, {0x3f,0x20,0x8c,0x79,0x03,0x7f,0x01,0xd6,0x80,0x39,0xe8,0x4f,0x68,0x03,0x2a,0x00 } }, +{ 16, 0xe260, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xbe,0x00,0xfa,0x00,0x3e,0x00 } }, +{ 16, 0xe270, 0, {0x8f,0x96,0x0b,0xa4,0x00,0xea,0x00,0x3c,0xc0,0x0f,0x90,0x03,0xac,0x20,0xfb,0x40 } }, +{ 16, 0xe280, 0, {0x2e,0x00,0x0f,0xb2,0x03,0xad,0xa0,0xea,0x00,0x3e,0xc0,0x0f,0xa0,0x1b,0xc2,0x04 } }, +{ 16, 0xe290, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x05,0xfe,0x08,0xde,0x81,0x33,0xa4 } }, +{ 16, 0xe2a0, 0, {0x0e,0xfc,0x13,0x3e,0x00,0xfc,0x80,0x13,0x20,0x0c,0x68,0x03,0x3e,0x20,0xff,0xc8 } }, +{ 16, 0xe2b0, 0, {0x3f,0x60,0x1d,0xf8,0x03,0x7e,0x00,0xc7,0x80,0x33,0xe2,0x0c,0xd8,0x03,0x10,0x00 } }, +{ 16, 0xe2c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0x86,0x41,0x31,0xc4 } }, +{ 16, 0xe2d0, 0, {0x08,0x79,0x42,0x9c,0x00,0xbc,0x10,0x21,0x40,0x85,0x35,0x03,0x5c,0x00,0xb7,0x00 } }, +{ 16, 0xe2e0, 0, {0x2d,0xc0,0x08,0x72,0x02,0x2c,0x00,0xa7,0x01,0x37,0xc0,0x08,0x51,0x42,0x2a,0x00 } }, +{ 16, 0xe2f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x8c,0x40,0x82,0x00,0x24,0x81 } }, +{ 16, 0xe300, 0, {0x08,0xd8,0x02,0x14,0x20,0xb5,0x00,0x20,0x40,0x09,0x60,0x02,0x1c,0x40,0xb7,0x00 } }, +{ 16, 0xe310, 0, {0x2c,0x40,0x0b,0x30,0x22,0xdc,0x00,0x97,0x00,0x21,0xc4,0x08,0x40,0x02,0x44,0x00 } }, +{ 16, 0xe320, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x14,0xec,0x00,0x92,0x06,0x20,0x90 } }, +{ 16, 0xe330, 0, {0x38,0x15,0x02,0x86,0x00,0xb8,0x00,0x60,0x50,0x09,0x30,0x02,0x4e,0x01,0xbb,0x00 } }, +{ 16, 0xe340, 0, {0x2e,0x40,0x0b,0x30,0x02,0xce,0x20,0xb3,0x00,0x24,0xf0,0x48,0x02,0x0a,0x58,0x04 } }, +{ 16, 0xe350, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xca,0x00,0xa6,0x94 } }, +{ 16, 0xe360, 0, {0x2c,0x90,0x03,0x2e,0x00,0xfb,0x05,0xb2,0x85,0x0d,0x90,0x03,0x3f,0x90,0xff,0x00 } }, +{ 16, 0xe370, 0, {0x7e,0x80,0x1f,0xf0,0x43,0xfc,0x21,0x9a,0x00,0x33,0xc8,0x3c,0xb2,0x03,0x6a,0x04 } }, +{ 16, 0xe380, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0xec,0x02,0xea,0x40,0x3d,0x80 } }, +{ 16, 0xe390, 0, {0x0f,0x10,0x93,0xed,0x00,0xfb,0x40,0x3e,0x90,0x8f,0x30,0x03,0xec,0x80,0xfb,0x00 } }, +{ 16, 0xe3a0, 0, {0x3e,0x91,0x1c,0xb0,0x03,0x2c,0x10,0xe8,0x00,0x3e,0xc8,0x1f,0x90,0x03,0xa5,0x10 } }, +{ 16, 0xe3b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xfc,0x02,0xe4,0x00,0x73,0xa0 } }, +{ 16, 0xe3c0, 0, {0x0c,0xfc,0x03,0x7c,0x02,0xff,0x10,0x13,0xc4,0x1c,0xc0,0x03,0x3c,0x00,0xff,0x00 } }, +{ 16, 0xe3d0, 0, {0x37,0xe0,0x0d,0xf0,0x03,0xfc,0x00,0xed,0x80,0x31,0xc0,0x0c,0x32,0x63,0x20,0x04 } }, +{ 16, 0xe3e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x00,0x6c,0x00,0x8a,0xc0,0x22,0xb1 } }, +{ 16, 0xe3f0, 0, {0x8a,0xb8,0x43,0x4a,0x10,0xdb,0x20,0x20,0xf0,0x0a,0x94,0x03,0x6c,0x00,0xbb,0x07 } }, +{ 16, 0xe400, 0, {0x22,0xb8,0x08,0xb0,0x02,0xec,0x11,0xe8,0xc0,0xb2,0xc0,0x2a,0x92,0x1a,0x20,0x00 } }, +{ 16, 0xe410, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x2c,0x00,0xaa,0x80,0x22,0x98 } }, +{ 16, 0xe420, 0, {0x08,0x90,0x02,0x2f,0x03,0xbb,0x01,0x2a,0x83,0x08,0xb2,0x4e,0x2c,0x04,0xab,0x02 } }, +{ 16, 0xe430, 0, {0x22,0xc4,0x28,0xb0,0x22,0xec,0x09,0xb3,0x50,0x62,0xc0,0x08,0xb0,0x02,0x20,0x00 } }, +{ 16, 0xe440, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x01,0x83,0x00,0x60,0x80 } }, +{ 16, 0xe450, 0, {0x08,0x12,0x0a,0x44,0x00,0x93,0x00,0x2a,0x80,0x4a,0x30,0x02,0x0c,0x00,0xb3,0x00 } }, +{ 16, 0xe460, 0, {0x60,0xc0,0x08,0x30,0x02,0xcc,0x00,0xb3,0x02,0x60,0xc0,0x08,0x00,0x46,0x02,0x01 } }, +{ 16, 0xe470, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0d,0x6c,0x00,0xe8,0x02,0x22,0x80 } }, +{ 16, 0xe480, 0, {0x2c,0xf2,0x43,0x2c,0x00,0xfb,0x00,0xba,0xc0,0x08,0xa5,0x02,0x3c,0x00,0xef,0x00 } }, +{ 16, 0xe490, 0, {0x36,0xc0,0x4d,0xf0,0x13,0xfd,0x51,0xfb,0x00,0x32,0xc0,0x0c,0xb0,0x03,0x20,0x01 } }, +{ 16, 0xe4a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0x7e,0x04,0x3f,0x80 } }, +{ 16, 0xe4b0, 0, {0x0f,0x31,0x43,0xf0,0x02,0xff,0x00,0x37,0xc0,0x0f,0xf0,0x03,0xfc,0x08,0xff,0x00 } }, +{ 16, 0xe4c0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xef,0x00,0x3b,0xc0,0x0f,0xc0,0x03,0xe8,0x16 } }, +{ 16, 0xe4d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf2,0x40,0xfc,0x80,0x3f,0x24 } }, +{ 16, 0xe4e0, 0, {0x0d,0xd8,0x53,0xd6,0x04,0xdf,0x32,0x3f,0xcc,0x4c,0xc0,0x43,0xfc,0x00,0xdf,0x60 } }, +{ 16, 0xe4f0, 0, {0x37,0xc0,0x0f,0xc4,0x03,0x7c,0xd0,0xdf,0x20,0x33,0xd8,0x0d,0xf8,0x43,0xf0,0x00 } }, +{ 16, 0xe500, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x18,0xe8,0x80,0xb0,0x01,0x2e,0x08 } }, +{ 16, 0xe510, 0, {0x88,0x90,0x02,0xec,0x20,0x8b,0x70,0x2f,0xcc,0x08,0xb3,0x82,0xfd,0xe0,0xbf,0x40 } }, +{ 16, 0xe520, 0, {0x22,0xd8,0x0b,0x93,0x02,0xfd,0xc0,0xaf,0x10,0x28,0xf0,0x08,0xbc,0x12,0xf0,0x04 } }, +{ 16, 0xe530, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc4,0x00,0xb0,0x00,0x2e,0x01 } }, +{ 16, 0xe540, 0, {0x0a,0x12,0x82,0xec,0x80,0xb3,0x00,0x2c,0xc8,0x0a,0x00,0x32,0x8c,0x00,0xa3,0x30 } }, +{ 16, 0xe550, 0, {0x20,0xd2,0x09,0x00,0x02,0x8c,0x80,0x83,0x00,0x28,0xd8,0x0b,0x34,0x12,0xf2,0x01 } }, +{ 16, 0xe560, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xac,0x01,0xb8,0x02,0x2e,0x00 } }, +{ 16, 0xe570, 0, {0x0a,0x90,0x12,0xec,0x10,0x8b,0x00,0x2e,0xc0,0x0a,0xb0,0x00,0xec,0x00,0xb3,0x00 } }, +{ 16, 0xe580, 0, {0x22,0xc1,0x0b,0x92,0x02,0xcc,0x01,0xab,0x00,0x2a,0xc0,0x02,0xb0,0x02,0xf0,0x04 } }, +{ 16, 0xe590, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xe0,0x00,0xfa,0x0c,0x3e,0xc0 } }, +{ 16, 0xe5a0, 0, {0x0f,0xa0,0x13,0xee,0x20,0xdb,0x00,0x3e,0xc0,0x2e,0x88,0x53,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xe5b0, 0, {0xb2,0xc0,0x8f,0xac,0x83,0xac,0x08,0xdb,0x00,0x1a,0xc0,0x4f,0xb0,0x03,0xc0,0x04 } }, +{ 16, 0xe5c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb8,0x00,0xfe,0x00,0x3f,0xc0 } }, +{ 16, 0xe5d0, 0, {0x2d,0xe0,0x03,0xfe,0x80,0x7f,0x00,0x3f,0xc0,0x0d,0xd2,0x03,0xfc,0x00,0xbf,0x01 } }, +{ 16, 0xe5e0, 0, {0x3e,0xc0,0x0d,0xc8,0x03,0xfc,0x0c,0xff,0x00,0x3f,0xc0,0x09,0xf0,0x23,0xf8,0x00 } }, +{ 16, 0xe5f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa4,0x00,0xfa,0x40,0x32,0xc1 } }, +{ 16, 0xe600, 0, {0x0f,0xa0,0x03,0x29,0x08,0xdb,0x00,0x3e,0xc0,0x0e,0x85,0x03,0xec,0x20,0xcb,0x00 } }, +{ 16, 0xe610, 0, {0x3a,0xc0,0x0e,0xa4,0x03,0xec,0x00,0xfb,0x00,0x3a,0xc2,0x0e,0xb0,0x03,0x10,0x04 } }, +{ 16, 0xe620, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0xba,0x60,0x20,0xc0 } }, +{ 16, 0xe630, 0, {0x0b,0xa0,0x02,0x08,0x00,0xaf,0x00,0x2f,0xd0,0x0b,0xb5,0x02,0xfe,0x02,0x8f,0x00 } }, +{ 16, 0xe640, 0, {0x2f,0xc0,0x0d,0x80,0x0a,0x3c,0x00,0xb7,0x00,0x23,0xc2,0x05,0xf0,0x22,0x36,0x00 } }, +{ 16, 0xe650, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x04,0x40,0x00,0xb1,0x88,0x20,0x00 } }, +{ 16, 0xe660, 0, {0x0b,0x10,0x02,0x0c,0x00,0x83,0x00,0x2e,0xc8,0x0b,0x08,0x06,0x4d,0x40,0x83,0x00 } }, +{ 16, 0xe670, 0, {0x20,0xc0,0x08,0x30,0x06,0x0c,0x08,0x93,0x20,0x0a,0xe0,0x4a,0x30,0x02,0x38,0x00 } }, +{ 16, 0xe680, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x10,0x5a,0x00,0xb5,0x90,0x21,0x20 } }, +{ 16, 0xe690, 0, {0x0b,0x58,0x42,0x3e,0x00,0xa7,0x80,0x2d,0xe0,0x0b,0x69,0x02,0xde,0x40,0x87,0x92 } }, +{ 16, 0xe6a0, 0, {0x2d,0xe0,0x09,0x18,0x02,0x9e,0x01,0xb7,0x80,0x29,0xe0,0x03,0x70,0x02,0x3e,0x00 } }, +{ 16, 0xe6b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x44,0x00,0xf1,0x01,0x30,0x00 } }, +{ 16, 0xe6c0, 0, {0x5f,0x18,0x03,0x0c,0x10,0x83,0x00,0x3c,0xc4,0x0e,0x04,0x03,0xec,0x00,0x83,0x00 } }, +{ 16, 0xe6d0, 0, {0x30,0xc4,0x0c,0x31,0x03,0x8c,0x00,0xf3,0x00,0x38,0xc8,0x0e,0x31,0x03,0x12,0x02 } }, +{ 16, 0xe6e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xbc,0x00,0xfd,0x04,0xbf,0x04 } }, +{ 16, 0xe6f0, 0, {0x4f,0x58,0x03,0xf8,0x08,0xef,0x08,0x3f,0xc0,0x0f,0xf0,0x01,0xfc,0x00,0xff,0x4c } }, +{ 16, 0xe700, 0, {0x3f,0xc1,0x0f,0xd0,0x03,0x3c,0x00,0xf7,0x00,0x37,0xc2,0x0d,0x72,0x03,0xd0,0x06 } }, +{ 16, 0xe710, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xe2,0x00,0xdb,0x00,0x32,0xc0 } }, +{ 16, 0xe720, 0, {0x4d,0xa8,0x03,0x2c,0x08,0xfb,0x00,0x7e,0xc8,0x8f,0xb0,0x0b,0x6f,0x45,0xeb,0xc2 } }, +{ 16, 0xe730, 0, {0x36,0xc0,0x07,0xa0,0x03,0xef,0x20,0xcb,0x50,0xb2,0xc0,0x0c,0x79,0x03,0x2a,0x00 } }, +{ 16, 0xe740, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x19,0x98,0x00,0x8f,0x00,0x21,0xc0 } }, +{ 16, 0xe750, 0, {0x0b,0x60,0x03,0x5c,0x00,0x37,0x00,0x2d,0xd2,0x0b,0x30,0x02,0x0c,0xa8,0x87,0x24 } }, +{ 16, 0xe760, 0, {0x21,0xd0,0x09,0x70,0x02,0xdd,0x88,0x87,0x2a,0x23,0xe8,0x08,0x70,0x02,0x32,0x04 } }, +{ 16, 0xe770, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xb6,0x00,0x97,0x80,0x21,0xe0 } }, +{ 16, 0xe780, 0, {0x0b,0x68,0x02,0x1e,0x00,0xb7,0x80,0x2d,0xe8,0x8b,0x48,0x82,0x1e,0x80,0xa3,0x84 } }, +{ 16, 0xe790, 0, {0x25,0xe8,0x0b,0x68,0x02,0xce,0x02,0x87,0x80,0x21,0xe0,0x08,0x7a,0x02,0x20,0x00 } }, +{ 16, 0xe7a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x04,0xcc,0x08,0x83,0x82,0x20,0xe0 } }, +{ 16, 0xe7b0, 0, {0x8b,0x2a,0x02,0x48,0x40,0xb3,0x00,0x2c,0xc0,0x0b,0x30,0x82,0x0c,0x00,0x83,0x00 } }, +{ 16, 0xe7c0, 0, {0x00,0xc1,0x09,0x31,0x02,0xcc,0x00,0x83,0x00,0x20,0xc0,0x08,0x30,0x0a,0x12,0x04 } }, +{ 16, 0xe7d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xe8,0x00,0xda,0xa0,0x32,0xa8 } }, +{ 16, 0xe7e0, 0, {0x8d,0xa8,0x03,0x3b,0x00,0xfa,0x00,0x3e,0x80,0x0f,0xe4,0x03,0x68,0x00,0xea,0x02 } }, +{ 16, 0xe7f0, 0, {0x36,0x80,0x0f,0xe4,0x03,0xe8,0x00,0xca,0x00,0x32,0x80,0x2c,0xa0,0x03,0x3a,0x04 } }, +{ 16, 0xe800, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x01,0xa0,0x10,0xf8,0x00,0xbe,0x20 } }, +{ 16, 0xe810, 0, {0x8f,0xc1,0x03,0xe0,0x24,0xf8,0x00,0x3e,0x10,0x0f,0x84,0x03,0xe0,0x00,0xf8,0x01 } }, +{ 16, 0xe820, 0, {0x3e,0x00,0x0f,0x80,0x03,0xe0,0x00,0xf8,0x01,0xbe,0x10,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xe830, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xa4,0x00,0xf9,0x40,0x32,0x40 } }, +{ 16, 0xe840, 0, {0xcf,0x90,0x03,0xe4,0x00,0xc9,0x00,0x0e,0x50,0x0f,0x1a,0x03,0x26,0x00,0xf9,0x00 } }, +{ 16, 0xe850, 0, {0x3e,0x40,0x0f,0x90,0x81,0xe4,0x00,0xf9,0x80,0x32,0x40,0x0c,0x90,0x03,0xc2,0x04 } }, +{ 16, 0xe860, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x04,0xb1,0x04,0x22,0x40 } }, +{ 16, 0xe870, 0, {0x0b,0x90,0x02,0xe4,0x00,0xa9,0x00,0x2e,0x53,0x0b,0x92,0x0a,0x26,0x48,0xb9,0x04 } }, +{ 16, 0xe880, 0, {0x2e,0x40,0x0b,0x90,0x02,0xe4,0x00,0xb9,0x80,0x02,0x50,0x08,0x90,0x02,0xe0,0x00 } }, +{ 16, 0xe890, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x05,0x24,0x00,0xbd,0x00,0x23,0x40 } }, +{ 16, 0xe8a0, 0, {0x0b,0xd0,0x12,0xc4,0x00,0x89,0x02,0x2e,0x40,0x0b,0x90,0x22,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xe8b0, 0, {0x2e,0x40,0x0b,0x90,0x02,0xe4,0x00,0xb1,0x20,0x20,0x40,0x68,0x90,0x22,0xc6,0x00 } }, +{ 16, 0xe8c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x14,0x14,0x00,0xbf,0x12,0xa1,0x40 } }, +{ 16, 0xe8d0, 0, {0x0b,0x50,0x02,0xc4,0x00,0xa1,0x20,0x2c,0x48,0x0b,0x12,0x02,0x04,0x10,0xb1,0x11 } }, +{ 16, 0xe8e0, 0, {0x2c,0x48,0x0b,0x13,0x22,0xc4,0x00,0xb1,0x40,0x20,0x5a,0x08,0x10,0x02,0xc2,0x01 } }, +{ 16, 0xe8f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xf8,0x40,0x32,0x14 } }, +{ 16, 0xe900, 0, {0x0f,0x45,0x03,0xe1,0x40,0xc8,0x50,0x3e,0x15,0x8f,0x85,0x03,0x21,0xe8,0xf8,0x68 } }, +{ 16, 0xe910, 0, {0x3e,0x14,0x0f,0x84,0x03,0xe1,0xe0,0xf0,0x28,0x32,0xa8,0xcc,0x80,0x23,0xee,0x03 } }, +{ 16, 0xe920, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x15,0xc4,0x10,0xf9,0x20,0x3e,0x40 } }, +{ 16, 0xe930, 0, {0x0f,0x90,0x03,0xf4,0x00,0xf9,0x10,0x3e,0x44,0x0f,0xd1,0x03,0xe4,0x00,0xf9,0x20 } }, +{ 16, 0xe940, 0, {0x3e,0x44,0x0f,0xd3,0x03,0xe4,0x00,0xf9,0x00,0xbe,0x40,0x0f,0x94,0x03,0xe6,0x06 } }, +{ 16, 0xe950, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xe4,0x00,0xfd,0x10,0x33,0x40 } }, +{ 16, 0xe960, 0, {0x0c,0xd0,0x03,0x24,0x00,0xd9,0x00,0x3f,0x40,0x4c,0xd0,0x03,0xf6,0x00,0xfd,0x90 } }, +{ 16, 0xe970, 0, {0x3a,0x40,0x0c,0x90,0x03,0xe6,0xa0,0xfd,0xa8,0x37,0x68,0x0c,0xd8,0x83,0x26,0x00 } }, +{ 16, 0xe980, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x08,0xc8,0xa0,0x22,0x00 } }, +{ 16, 0xe990, 0, {0x08,0x80,0x02,0x20,0x00,0x88,0x00,0x2e,0x00,0x0c,0x80,0x12,0xe0,0x00,0xb8,0x80 } }, +{ 16, 0xe9a0, 0, {0x22,0x00,0x0d,0x0a,0x02,0xe3,0x80,0xb0,0xc0,0x20,0x34,0x08,0x84,0x03,0x4e,0x04 } }, +{ 16, 0xe9b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x84,0x09,0xa1,0x00,0x20,0x41 } }, +{ 16, 0xe9c0, 0, {0x08,0x90,0x02,0x24,0x00,0x91,0x00,0x2c,0x40,0x08,0x10,0x02,0xc5,0x00,0xb1,0x60 } }, +{ 16, 0xe9d0, 0, {0x20,0x40,0x08,0x10,0xa2,0xc4,0x20,0xb1,0x28,0x24,0x4a,0x08,0x10,0x02,0x52,0x01 } }, +{ 16, 0xe9e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x14,0xa4,0x01,0x81,0x00,0xa2,0x40 } }, +{ 16, 0xe9f0, 0, {0xa8,0x90,0x00,0x25,0x40,0x89,0x01,0x2c,0x40,0x08,0x94,0x02,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0xea00, 0, {0x2a,0x40,0x09,0x90,0x02,0xe4,0x01,0xb9,0x04,0x22,0x41,0x48,0x90,0x02,0x46,0x04 } }, +{ 16, 0xea10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x14,0xa5,0x20,0xe9,0x00,0x32,0x40 } }, +{ 16, 0xea20, 0, {0x4c,0x10,0x0b,0x26,0x00,0xd9,0x00,0x3e,0x40,0x2c,0x98,0x03,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0xea30, 0, {0xb2,0x40,0x0c,0x90,0x03,0xe4,0x00,0xf9,0x00,0x36,0x40,0x2c,0x90,0x03,0x68,0x04 } }, +{ 16, 0xea40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x01,0xa4,0x00,0xe9,0x00,0x3e,0x40 } }, +{ 16, 0xea50, 0, {0x0f,0x90,0x03,0xe6,0x00,0xf9,0x00,0x3e,0x40,0x0e,0x9a,0x03,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0xea60, 0, {0x36,0x40,0x0f,0x90,0x03,0xe4,0x00,0xf9,0x00,0x3c,0x40,0x0f,0x90,0x03,0xda,0x00 } }, +{ 16, 0xea70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xa1,0x00,0xf8,0x00,0x32,0x00 } }, +{ 16, 0xea80, 0, {0x0f,0x80,0x13,0xa0,0x00,0xc8,0x00,0x32,0x04,0x8c,0x80,0x03,0xa0,0xc0,0xf8,0x00 } }, +{ 16, 0xea90, 0, {0x3a,0x00,0x0f,0x80,0x03,0x20,0x00,0xc0,0x09,0x32,0x00,0x4c,0x80,0x01,0x0a,0x04 } }, +{ 16, 0xeaa0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0xbe,0x00,0x20,0x80 } }, +{ 16, 0xeab0, 0, {0x0b,0xe0,0x02,0x88,0x00,0xaa,0x00,0x03,0xa0,0x0a,0xe6,0x02,0xfa,0x00,0x8a,0x00 } }, +{ 16, 0xeac0, 0, {0x32,0x80,0x0b,0xa0,0x02,0x28,0x00,0x8e,0x80,0xa3,0x80,0x28,0x20,0x02,0x8a,0x00 } }, +{ 16, 0xead0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x6c,0x00,0xb3,0x48,0x20,0x40 } }, +{ 16, 0xeae0, 0, {0x0b,0x10,0x02,0x0c,0x00,0x83,0x00,0x20,0xc0,0x08,0x34,0x82,0x8e,0x04,0x99,0x00 } }, +{ 16, 0xeaf0, 0, {0x0a,0xc0,0x1b,0x30,0x02,0x0c,0x02,0x90,0x50,0x20,0x60,0x08,0x30,0x02,0x0a,0x00 } }, +{ 16, 0xeb00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x11,0x1c,0x80,0xbd,0x0a,0x21,0x48 } }, +{ 16, 0xeb10, 0, {0x0b,0x52,0x02,0x9c,0x40,0xa3,0xa0,0x20,0x80,0x0a,0x60,0x02,0xce,0x00,0x85,0x20 } }, +{ 16, 0xeb20, 0, {0x21,0xc4,0x0b,0x7a,0x06,0x1e,0x80,0x95,0x20,0x21,0x90,0x08,0x70,0x02,0x28,0x00 } }, +{ 16, 0xeb30, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x08,0x1e,0x80,0xf7,0x80,0xb1,0x79 } }, +{ 16, 0xeb40, 0, {0x0f,0xdb,0x02,0x3e,0x20,0xc7,0xa0,0xb1,0x60,0xcc,0x78,0x13,0x96,0x00,0xf1,0xf0 } }, +{ 16, 0xeb50, 0, {0x39,0xe2,0x0f,0x7b,0x13,0x0f,0x00,0xd4,0xa0,0x31,0x60,0x2c,0x70,0x03,0x2a,0x02 } }, +{ 16, 0xeb60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x15,0xac,0x00,0xf7,0x00,0x3e,0x40 } }, +{ 16, 0xeb70, 0, {0x0f,0x90,0x03,0xed,0x80,0xfb,0x10,0x3e,0x40,0x0b,0xb0,0x23,0xec,0x00,0xf9,0x20 } }, +{ 16, 0xeb80, 0, {0x3a,0xd8,0x0f,0xb0,0x0b,0xed,0x81,0xed,0x10,0x3e,0x80,0x0f,0x30,0x03,0xc2,0x06 } }, +{ 16, 0xeb90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xbe,0x20,0xee,0x80,0x33,0x60 } }, +{ 16, 0xeba0, 0, {0x0c,0xd8,0x83,0x1e,0x00,0x6f,0x80,0x33,0xe0,0x0f,0xb8,0x11,0x32,0x04,0xf5,0x80 } }, +{ 16, 0xebb0, 0, {0x33,0xe0,0x0f,0xf8,0x83,0x2f,0x40,0xfe,0x80,0xb3,0xe0,0x0c,0xf8,0x03,0x10,0x00 } }, +{ 16, 0xebc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x18,0x9c,0x00,0xbc,0x00,0xa1,0x44 } }, +{ 16, 0xebd0, 0, {0x08,0x10,0x03,0x5c,0x00,0x8f,0x00,0x21,0x80,0x0b,0xea,0x22,0x1c,0x80,0xb5,0x01 } }, +{ 16, 0xebe0, 0, {0x21,0xc0,0x0b,0xf0,0x02,0x1e,0x80,0xbe,0x00,0x23,0x80,0x2a,0x70,0x02,0x2a,0x04 } }, +{ 16, 0xebf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x20,0xa7,0x00,0x23,0x40 } }, +{ 16, 0xec00, 0, {0x0b,0x50,0x0a,0x3c,0x00,0xa7,0x00,0x25,0xc0,0x0a,0x43,0x02,0x10,0x00,0xb5,0x00 } }, +{ 16, 0xec10, 0, {0x21,0xc0,0x0b,0x70,0x82,0x1c,0x80,0xb4,0x00,0x21,0xc0,0x08,0x70,0x02,0x04,0x00 } }, +{ 16, 0xec20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x04,0x8e,0x04,0xb3,0x00,0x22,0x40 } }, +{ 16, 0xec30, 0, {0x09,0x14,0x02,0x4c,0x00,0x83,0x00,0x20,0xc0,0x0b,0x24,0x82,0x04,0x00,0xb1,0x00 } }, +{ 16, 0xec40, 0, {0x20,0xc0,0x8b,0x3a,0x02,0x2c,0x01,0xb0,0x00,0x20,0x80,0x0a,0x30,0x02,0x1a,0x04 } }, +{ 16, 0xec50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0x9e,0x00,0xeb,0x04,0x33,0x40 } }, +{ 16, 0xec60, 0, {0x2d,0xdc,0x03,0x1d,0x60,0xef,0x00,0x32,0x00,0xcf,0x9a,0x03,0x28,0x00,0xfd,0x00 } }, +{ 16, 0xec70, 0, {0x33,0xc1,0x8b,0xfc,0x0b,0x3c,0x00,0xfc,0x00,0x32,0x80,0x0c,0x90,0x03,0x2a,0x04 } }, +{ 16, 0xec80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xac,0x10,0xf8,0x00,0x3e,0x40 } }, +{ 16, 0xec90, 0, {0x0e,0x98,0x23,0xac,0x04,0xfb,0x00,0x3c,0x00,0x0f,0x84,0x20,0xed,0x00,0xf9,0x00 } }, +{ 16, 0xeca0, 0, {0x3e,0xc0,0x4f,0xb0,0x03,0xec,0x00,0xfd,0x00,0x3e,0x80,0x0f,0x90,0x03,0xe4,0x00 } }, +{ 16, 0xecb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x10,0xfc,0x00,0xcf,0x80,0x33,0x40 } }, +{ 16, 0xecc0, 0, {0x0c,0xd0,0x83,0xfc,0x00,0xef,0x00,0x3f,0x40,0x0c,0xf1,0x41,0x30,0x10,0xcd,0x00 } }, +{ 16, 0xecd0, 0, {0x3f,0xc0,0x00,0x70,0x13,0x3c,0x00,0xe4,0x00,0xb1,0xd0,0x0c,0x10,0x03,0x20,0x04 } }, +{ 16, 0xece0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa1,0x04,0x2c,0x00,0x8a,0xe4,0x2a,0x40 } }, +{ 16, 0xecf0, 0, {0x28,0x90,0x02,0xec,0x00,0x8b,0x00,0x3e,0x02,0x0a,0x80,0x02,0x2c,0x82,0x89,0x04 } }, +{ 16, 0xed00, 0, {0x2e,0xc1,0x0a,0xb0,0x0a,0x2c,0x00,0x89,0x02,0x22,0xf2,0x2a,0x98,0x02,0x20,0x00 } }, +{ 16, 0xed10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x02,0x80,0x14,0x2a,0x40 } }, +{ 16, 0xed20, 0, {0x08,0x90,0x02,0xec,0x08,0xab,0x04,0x2e,0x84,0x08,0x10,0x82,0x80,0x10,0x89,0x03 } }, +{ 16, 0xed30, 0, {0x2c,0xc0,0x4a,0xb0,0x22,0x2c,0x00,0xaa,0x00,0x22,0x80,0x08,0x91,0x02,0x20,0x00 } }, +{ 16, 0xed40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x2c,0x00,0x80,0x00,0x28,0x40 } }, +{ 16, 0xed50, 0, {0x08,0x11,0x02,0xec,0x00,0x83,0x00,0x2c,0x81,0x0a,0x00,0x5a,0x88,0x00,0x01,0x00 } }, +{ 16, 0xed60, 0, {0x2c,0xc0,0x0a,0x30,0x02,0x0c,0x00,0x82,0x00,0x20,0x80,0x0a,0x10,0x02,0x02,0x01 } }, +{ 16, 0xed70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xc9,0x00,0x3a,0x40 } }, +{ 16, 0xed80, 0, {0x0c,0xd4,0x03,0xfc,0x00,0xeb,0x00,0x3e,0x40,0x0c,0x92,0x03,0xa0,0x00,0x4d,0x00 } }, +{ 16, 0xed90, 0, {0x3f,0xc0,0x0e,0xf0,0x33,0x3c,0x80,0xe8,0x00,0x32,0xc0,0x0c,0x90,0x03,0x20,0x03 } }, +{ 16, 0xeda0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x11,0xfc,0x00,0xfc,0x00,0x3d,0x40 } }, +{ 16, 0xedb0, 0, {0x0f,0x50,0x03,0xfc,0x02,0x3f,0x04,0x3b,0x01,0x4f,0xc4,0x13,0x70,0x00,0xfd,0x00 } }, +{ 16, 0xedc0, 0, {0x3f,0xc0,0x1f,0xf0,0x01,0xfc,0x40,0xfc,0x00,0x3f,0xc0,0x0f,0xd0,0x13,0xe8,0x06 } }, +{ 16, 0xedd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf8,0xe0,0xff,0x80,0x3d,0xc0 } }, +{ 16, 0xede0, 0, {0x0d,0xf3,0x82,0xf0,0x80,0xff,0x40,0x31,0xcb,0x0c,0xf3,0x03,0xfd,0x04,0xef,0xc1 } }, +{ 16, 0xedf0, 0, {0x33,0xe0,0x0f,0x79,0x03,0xfe,0x00,0xcf,0x42,0x33,0xf0,0x4c,0xf8,0x03,0x30,0x00 } }, +{ 16, 0xee00, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x10,0xe9,0x08,0xb9,0x81,0x2f,0xf0 } }, +{ 16, 0xee10, 0, {0x08,0xf4,0x52,0xe9,0x20,0xbf,0x40,0x23,0xf0,0x0a,0xf3,0x02,0xfd,0x08,0x8b,0x00 } }, +{ 16, 0xee20, 0, {0x36,0xe0,0x0b,0x80,0x22,0xe8,0x80,0x8f,0x40,0x22,0xc0,0x08,0xb0,0x82,0x30,0x04 } }, +{ 16, 0xee30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0xcc,0x00,0xb1,0x80,0x2c,0xc5 } }, +{ 16, 0xee40, 0, {0x09,0x32,0x42,0xc8,0xc0,0xb3,0x31,0x20,0xc1,0x08,0x32,0x02,0xcc,0xd4,0xbb,0x20 } }, +{ 16, 0xee50, 0, {0x68,0xc0,0x0b,0x30,0x02,0xcc,0x20,0x93,0x60,0x20,0x88,0x08,0x32,0x02,0x32,0x01 } }, +{ 16, 0xee60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x15,0xa0,0x00,0xbb,0x80,0x2e,0xc0 } }, +{ 16, 0xee70, 0, {0x08,0xb0,0x02,0xea,0x00,0xbb,0x00,0x62,0xc1,0x0a,0xb0,0x02,0xcc,0x00,0xab,0x00 } }, +{ 16, 0xee80, 0, {0x2e,0xc0,0x0b,0xa0,0x00,0xe8,0x00,0x83,0x00,0x22,0xc1,0x08,0x30,0x02,0x30,0x04 } }, +{ 16, 0xee90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xe8,0x90,0xfb,0x80,0x3e,0xc0 } }, +{ 16, 0xeea0, 0, {0x0d,0xb0,0x03,0xe2,0x10,0xfb,0x00,0x32,0xc0,0x4c,0xb0,0x13,0xec,0x00,0xe9,0x54 } }, +{ 16, 0xeeb0, 0, {0x3a,0xc0,0x0f,0xb0,0x03,0xe6,0x00,0xcb,0x00,0xb2,0x40,0x0c,0xb0,0x03,0x04,0x04 } }, +{ 16, 0xeec0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb8,0x00,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0xeed0, 0, {0x8f,0xf0,0x03,0xf0,0x00,0xf7,0x02,0xbf,0xc1,0x0f,0xf0,0x23,0xfc,0x00,0xdf,0x06 } }, +{ 16, 0xeee0, 0, {0x37,0xc0,0x8f,0xc9,0x07,0xfa,0x92,0xff,0x04,0x3f,0x50,0x2f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0xeef0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x10,0xac,0x00,0xc9,0x00,0x3e,0xc2 } }, +{ 16, 0xef00, 0, {0x0e,0xb0,0x23,0xe4,0x00,0xeb,0x00,0x3a,0xc8,0x0e,0xb0,0x03,0xec,0x00,0xf9,0x00 } }, +{ 16, 0xef10, 0, {0x3e,0xc0,0x0f,0xb4,0x03,0xa4,0x00,0xfb,0x00,0x3e,0x80,0x0f,0xb0,0x83,0xd0,0x04 } }, +{ 16, 0xef20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x28,0x00,0x8b,0x74,0x2d,0xc0 } }, +{ 16, 0xef30, 0, {0x08,0xf0,0x02,0xe4,0x00,0x8f,0x00,0x21,0xf0,0x08,0xf0,0x02,0xfc,0x10,0xd3,0x00 } }, +{ 16, 0xef40, 0, {0x2e,0xc0,0x0b,0x90,0x12,0x2c,0x00,0xef,0x00,0x2e,0xc0,0x0b,0xb6,0x02,0xf6,0x00 } }, +{ 16, 0xef50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x05,0x48,0x00,0xa3,0x00,0x2c,0xc4 } }, +{ 16, 0xef60, 0, {0x0a,0x30,0x02,0xc0,0x00,0xa3,0x00,0x68,0xf0,0x0a,0x30,0x12,0xcc,0x04,0xa2,0x00 } }, +{ 16, 0xef70, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xec,0x00,0xb3,0x01,0x2e,0xc0,0x0b,0x34,0x02,0xf8,0x00 } }, +{ 16, 0xef80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x01,0x0c,0x00,0x87,0x80,0x2d,0xe8 } }, +{ 16, 0xef90, 0, {0x08,0x78,0x42,0xda,0x00,0x87,0x80,0x25,0xe0,0x08,0x79,0x02,0xce,0x00,0x96,0x80 } }, +{ 16, 0xefa0, 0, {0x2d,0xe0,0x0b,0xd9,0x02,0xde,0x00,0xa7,0x80,0x2d,0xe0,0x0b,0x78,0x02,0xfc,0x00 } }, +{ 16, 0xefb0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x40,0xe3,0x10,0x3c,0xc0 } }, +{ 16, 0xefc0, 0, {0x0a,0x38,0x03,0xe8,0x00,0xeb,0x00,0x38,0xc2,0x0a,0x30,0x03,0xcc,0x00,0xe3,0x40 } }, +{ 16, 0xefd0, 0, {0x3c,0xc0,0x0f,0x34,0x03,0xcd,0x00,0xf3,0x20,0x3c,0x88,0x0f,0x30,0x03,0xd2,0x02 } }, +{ 16, 0xefe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xb4,0x80,0xff,0x04,0x3f,0xc8 } }, +{ 16, 0xeff0, 0, {0x0f,0xf0,0x83,0xf8,0x40,0xff,0x18,0x3b,0xc0,0x0f,0xf4,0x83,0xfc,0x00,0xee,0x02 } }, +{ 16, 0xf000, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0x3c,0x00,0xef,0x08,0x3f,0x80,0x0f,0xf0,0x13,0xd0,0x06 } }, +{ 16, 0xf010, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xe8,0x00,0xcb,0x00,0x3e,0xf2 } }, +{ 16, 0xf020, 0, {0x4d,0xb2,0x13,0xe8,0x04,0xcb,0x01,0x32,0xf8,0x4d,0xb2,0x13,0x6d,0x20,0xf8,0x00 } }, +{ 16, 0xf030, 0, {0x3e,0xc0,0x0f,0x30,0x03,0x24,0x00,0xfb,0x00,0x3e,0x40,0x8f,0xb8,0x03,0x2a,0x00 } }, +{ 16, 0xf040, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x11,0x8c,0x00,0x86,0x00,0x2c,0xc0 } }, +{ 16, 0xf050, 0, {0x08,0x73,0x02,0xd8,0x12,0x87,0x30,0x20,0xcb,0x08,0xf2,0x02,0x1d,0x05,0xb5,0x00 } }, +{ 16, 0xf060, 0, {0x2d,0xc0,0x0b,0x60,0x03,0x50,0x10,0xb7,0x09,0x2d,0xc0,0x0b,0xf0,0x02,0x32,0x04 } }, +{ 16, 0xf070, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x9e,0x00,0x87,0x80,0x2d,0xe4 } }, +{ 16, 0xf080, 0, {0x09,0x7a,0x02,0xce,0x01,0x87,0x80,0x21,0xec,0x09,0x78,0x02,0x5e,0x80,0xb7,0xc0 } }, +{ 16, 0xf090, 0, {0x2d,0xe0,0x0b,0xf8,0x02,0x1e,0x00,0xb7,0xa0,0x2d,0x60,0x0b,0x78,0x02,0x20,0x00 } }, +{ 16, 0xf0a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xee,0x00,0x82,0x80,0x2c,0xc0 } }, +{ 16, 0xf0b0, 0, {0x08,0x30,0x02,0xec,0x00,0x83,0x00,0xa0,0xc0,0x08,0x30,0x02,0x0c,0x00,0xb3,0x80 } }, +{ 16, 0xf0c0, 0, {0x2c,0xc1,0x0b,0x30,0x02,0x4e,0x00,0xb3,0x00,0x2c,0xf1,0x0b,0x30,0x0a,0x12,0x04 } }, +{ 16, 0xf0d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xba,0x80,0xc6,0x00,0x3e,0x80 } }, +{ 16, 0xf0e0, 0, {0x0d,0xa0,0x03,0xf8,0x40,0xca,0x00,0x32,0x80,0x0d,0xa0,0x13,0x68,0x00,0xfe,0x02 } }, +{ 16, 0xf0f0, 0, {0x7e,0x80,0x0f,0xed,0x83,0x39,0x10,0xfa,0x00,0x3f,0x8c,0x0f,0xa0,0x03,0x3a,0x04 } }, +{ 16, 0xf100, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x12,0xf8,0x90,0x3e,0x00 } }, +{ 16, 0xf110, 0, {0x0f,0x80,0x03,0xe0,0x00,0xf8,0x05,0x3e,0x00,0x0e,0x00,0x03,0xe0,0x00,0xf8,0x80 } }, +{ 16, 0xf120, 0, {0x3e,0x00,0x0f,0x80,0x03,0xe0,0x60,0xf8,0x00,0x7e,0x00,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xf130, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xc9,0x80,0x32,0x64 } }, +{ 16, 0xf140, 0, {0x0f,0x90,0x43,0xe4,0x06,0xc1,0x04,0x3a,0x40,0x0f,0x90,0x03,0xe4,0x00,0xe9,0x00 } }, +{ 16, 0xf150, 0, {0x32,0x40,0x0f,0x90,0x03,0x24,0x00,0xc1,0x01,0x32,0x40,0x0c,0x90,0x03,0xc2,0x04 } }, +{ 16, 0xf160, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x89,0xc0,0x22,0x40 } }, +{ 16, 0xf170, 0, {0x0b,0x90,0x02,0x24,0x00,0x89,0x00,0x22,0x50,0x1b,0x90,0x22,0x24,0x00,0x81,0x00 } }, +{ 16, 0xf180, 0, {0x22,0x40,0x0b,0x90,0x22,0x24,0x08,0xc9,0x00,0x20,0x40,0x08,0x94,0x02,0xe0,0x00 } }, +{ 16, 0xf190, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0x99,0x20,0x22,0x40 } }, +{ 16, 0xf1a0, 0, {0x0b,0x10,0x02,0xa4,0x00,0x89,0x00,0x2a,0x58,0x0b,0x90,0x02,0x84,0x00,0xa9,0x00 } }, +{ 16, 0xf1b0, 0, {0x22,0x40,0x0b,0x10,0x0a,0x04,0x00,0x99,0x02,0x22,0xc1,0x08,0x90,0x82,0xc6,0x00 } }, +{ 16, 0xf1c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0x91,0x02,0xa0,0xc8 } }, +{ 16, 0xf1d0, 0, {0x0b,0x12,0x02,0x04,0x80,0x81,0x22,0x20,0x48,0x9b,0x12,0x02,0x04,0x90,0x89,0x01 } }, +{ 16, 0xf1e0, 0, {0x20,0x40,0x0b,0x10,0x02,0x04,0x02,0x81,0x22,0x22,0x40,0x08,0x10,0x02,0xc2,0x01 } }, +{ 16, 0xf1f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x42,0xda,0x01,0x32,0x01 } }, +{ 16, 0xf200, 0, {0x0f,0x85,0x03,0xa1,0x40,0xc0,0x50,0x3a,0x01,0x8b,0x85,0x23,0xa1,0x44,0xe8,0x50 } }, +{ 16, 0xf210, 0, {0xb2,0x00,0x0f,0x85,0x03,0x21,0x48,0xd8,0x51,0x32,0x14,0x2c,0x85,0x03,0xee,0x03 } }, +{ 16, 0xf220, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf5,0x00,0xed,0x02,0x3e,0x44 } }, +{ 16, 0xf230, 0, {0x0f,0x91,0x03,0xf4,0x40,0xf9,0x10,0x3e,0x44,0x0f,0x91,0x03,0xe4,0x40,0xfd,0x00 } }, +{ 16, 0xf240, 0, {0x3e,0x40,0x0f,0xd0,0x03,0xf4,0x00,0xe9,0x10,0xbf,0x40,0x0f,0x90,0x03,0x66,0x06 } }, +{ 16, 0xf250, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe6,0x21,0xc5,0x00,0x33,0x68 } }, +{ 16, 0xf260, 0, {0x0f,0x9a,0x03,0x6f,0x88,0xc9,0xc0,0x33,0x68,0x0c,0x9e,0x03,0x27,0x80,0xd9,0x40 } }, +{ 16, 0xf270, 0, {0x3e,0x40,0x0f,0x90,0x03,0xc5,0x10,0xd9,0xe8,0x36,0x50,0x0c,0xd0,0x03,0xe6,0x00 } }, +{ 16, 0xf280, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x08,0x88,0x00,0x82,0x00 } }, +{ 16, 0xf290, 0, {0x0b,0x8e,0x82,0xeb,0xc8,0x88,0xe0,0x22,0x00,0x28,0x88,0x42,0xa2,0x80,0x8a,0x80 } }, +{ 16, 0xf2a0, 0, {0x22,0x00,0x0b,0xaa,0x02,0xe2,0x00,0x88,0xc0,0x22,0xa9,0x08,0x8a,0x03,0x8e,0x04 } }, +{ 16, 0xf2b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x05,0xc4,0x00,0x81,0x00,0x20,0xd0 } }, +{ 16, 0xf2c0, 0, {0x0b,0x11,0x32,0x84,0x84,0x81,0x60,0x60,0x50,0x08,0x16,0x06,0x05,0x00,0x91,0x20 } }, +{ 16, 0xf2d0, 0, {0x20,0x40,0x0b,0x10,0x82,0xe4,0x09,0x91,0x20,0x24,0x40,0x08,0x10,0xc2,0xd2,0x01 } }, +{ 16, 0xf2e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x04,0x89,0x04,0x22,0x40 } }, +{ 16, 0xf2f0, 0, {0x0b,0x90,0x02,0xc4,0x00,0xa9,0x00,0x22,0x41,0x00,0x90,0x02,0xa4,0x00,0x81,0x00 } }, +{ 16, 0xf300, 0, {0x22,0x40,0x0b,0x92,0x22,0xe5,0x80,0x99,0x01,0x22,0x61,0x08,0x90,0x02,0x86,0x04 } }, +{ 16, 0xf310, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x14,0xa5,0x82,0x81,0x90,0x32,0x40 } }, +{ 16, 0xf320, 0, {0x0f,0x90,0x13,0x67,0x02,0xc9,0x00,0x32,0x40,0x0c,0x90,0x23,0x24,0x04,0xd9,0xc0 } }, +{ 16, 0xf330, 0, {0xb2,0x40,0x0f,0x9c,0x03,0xe6,0x00,0xd9,0x00,0x36,0x50,0x0c,0x90,0x03,0xe8,0x04 } }, +{ 16, 0xf340, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0xa6,0x80,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0xf350, 0, {0x0f,0x90,0x03,0xe7,0x00,0xd9,0x00,0xbc,0x42,0x0f,0x90,0x53,0xe4,0x04,0xf9,0x10 } }, +{ 16, 0xf360, 0, {0x3e,0x40,0x0f,0x98,0x03,0xe6,0x04,0xe1,0x00,0x3e,0x40,0x2f,0x90,0x03,0xda,0x00 } }, +{ 16, 0xf370, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0x81,0x10,0x48,0x10,0x32,0x08 } }, +{ 16, 0xf380, 0, {0x0c,0x80,0x0f,0x21,0x02,0xc8,0x00,0x3a,0x04,0x0f,0x80,0x07,0x60,0x00,0xf8,0x40 } }, +{ 16, 0xf390, 0, {0xb2,0x00,0x0f,0x84,0x0b,0x20,0x00,0xd8,0x00,0x36,0x10,0x0c,0x80,0x03,0xca,0x04 } }, +{ 16, 0xf3a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x04,0x28,0x04,0x8e,0x80,0x23,0x80 } }, +{ 16, 0xf3b0, 0, {0x08,0xa0,0x42,0x28,0x00,0x8a,0x00,0x23,0xa0,0x4b,0xa0,0x02,0xe8,0x00,0xba,0x00 } }, +{ 16, 0xf3c0, 0, {0x76,0x80,0x0b,0xa0,0x02,0x08,0x00,0x8a,0x00,0x32,0x80,0x08,0xe0,0x03,0xca,0x00 } }, +{ 16, 0xf3d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x82,0x00,0x20,0xd0 } }, +{ 16, 0xf3e0, 0, {0x08,0x30,0x02,0x0c,0x00,0x9b,0x00,0x28,0xc0,0x1a,0xb0,0x02,0x6c,0x00,0xb3,0x02 } }, +{ 16, 0xf3f0, 0, {0x20,0xc0,0x0b,0x30,0x02,0x0c,0x00,0xa3,0x00,0x22,0xc0,0x28,0x34,0x82,0xca,0x00 } }, +{ 16, 0xf400, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1c,0x00,0x87,0x00,0x20,0xe0 } }, +{ 16, 0xf410, 0, {0x08,0x78,0x02,0x0c,0x00,0x97,0x20,0x25,0xc0,0x0b,0x71,0x02,0xdc,0x81,0xb7,0x20 } }, +{ 16, 0xf420, 0, {0x21,0xc0,0x0b,0x7a,0x42,0x3c,0x80,0x87,0x20,0x21,0xc0,0x08,0x70,0x02,0xe8,0x00 } }, +{ 16, 0xf430, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x08,0x0e,0x82,0xc7,0x80,0xb1,0xe0 } }, +{ 16, 0xf440, 0, {0x2c,0xfa,0x06,0x1e,0x08,0xd3,0xb1,0x39,0x60,0x4e,0x78,0x12,0x5e,0xa0,0xff,0xf0 } }, +{ 16, 0xf450, 0, {0x21,0xe0,0x0f,0xf8,0x03,0x1f,0x08,0xe3,0xa0,0x33,0xe0,0x0c,0x68,0x03,0xea,0x02 } }, +{ 16, 0xf460, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x40,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xf470, 0, {0x0f,0xb2,0x03,0xed,0xa8,0xeb,0x10,0x3a,0x80,0x0f,0xb0,0xc3,0xec,0x40,0xfb,0x00 } }, +{ 16, 0xf480, 0, {0x3e,0xc0,0x0f,0xb0,0x83,0xec,0x80,0xeb,0x70,0xbe,0xc4,0x0f,0xb0,0x03,0x82,0x06 } }, +{ 16, 0xf490, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x05,0xfe,0x00,0xce,0x80,0xb3,0x60 } }, +{ 16, 0xf4a0, 0, {0x0f,0xfc,0x83,0x7e,0x20,0xef,0xb0,0x3b,0xe0,0x0f,0xb8,0x03,0x3e,0x00,0xcf,0x81 } }, +{ 16, 0xf4b0, 0, {0x3f,0xe0,0x8f,0xf8,0x83,0xef,0x40,0xff,0xc2,0x33,0xe1,0x0c,0xf8,0x03,0xd0,0x00 } }, +{ 16, 0xf4c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x82,0x87,0x18,0x21,0x80 } }, +{ 16, 0xf4d0, 0, {0x0b,0x30,0x02,0x1c,0x60,0xd7,0x10,0x21,0xd0,0x0b,0x7b,0x02,0x3c,0x00,0xd7,0x00 } }, +{ 16, 0xf4e0, 0, {0x2d,0xc0,0x0b,0x70,0x02,0xde,0x00,0xbf,0x00,0xa3,0xc4,0x08,0x70,0x03,0xaa,0x04 } }, +{ 16, 0xf4f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x11,0x87,0x00,0x21,0xc0 } }, +{ 16, 0xf500, 0, {0x0b,0x30,0x02,0x1c,0x00,0x93,0x20,0x69,0xc0,0x0b,0x70,0x02,0x1c,0x00,0x87,0x00 } }, +{ 16, 0xf510, 0, {0x2d,0xc0,0x0b,0x71,0x02,0xdc,0x20,0xb7,0x10,0x21,0xc0,0x08,0x60,0x02,0x84,0x00 } }, +{ 16, 0xf520, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x14,0xcd,0x00,0x83,0x40,0x20,0xc0 } }, +{ 16, 0xf530, 0, {0x4b,0x30,0x02,0x0c,0x01,0x83,0x00,0x20,0xc0,0x0b,0x30,0x02,0x0c,0x00,0x93,0x80 } }, +{ 16, 0xf540, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x01,0xb3,0x00,0x20,0xc0,0x08,0x30,0x22,0x98,0x04 } }, +{ 16, 0xf550, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbf,0x20,0xca,0xc0,0x32,0x80 } }, +{ 16, 0xf560, 0, {0x0f,0xf0,0x03,0x3e,0x00,0x9f,0x00,0x3a,0x80,0x0f,0xf0,0x0b,0x3c,0x00,0xcf,0x98 } }, +{ 16, 0xf570, 0, {0x3e,0xc0,0x0f,0xf6,0x03,0xff,0x00,0xff,0x00,0x31,0xe0,0x2c,0xb0,0x03,0xae,0x04 } }, +{ 16, 0xf580, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xcc,0x80,0xfb,0x00,0x3e,0x50 } }, +{ 16, 0xf590, 0, {0x0f,0xb0,0x03,0xac,0x02,0xfb,0x00,0x7e,0x50,0x0f,0xb0,0x03,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xf5a0, 0, {0x3e,0xc0,0x0f,0xb2,0x03,0xec,0x20,0xf3,0x00,0x3e,0xc6,0x0f,0x90,0x03,0xa0,0x00 } }, +{ 16, 0xf5b0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x02,0xcf,0x98,0x73,0xc8 } }, +{ 16, 0xf5c0, 0, {0x0f,0x70,0x03,0x3c,0x00,0xff,0x00,0x33,0x28,0x0f,0xb0,0x02,0x1c,0x00,0x4f,0x00 } }, +{ 16, 0xf5d0, 0, {0x3f,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xff,0x01,0x33,0xc0,0x0c,0xe4,0x03,0xe4,0x04 } }, +{ 16, 0xf5e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x6c,0x00,0x83,0x80,0xa2,0xf8 } }, +{ 16, 0xf5f0, 0, {0x0b,0xb0,0x42,0x2c,0x00,0xbb,0x00,0x32,0x10,0x0f,0xb0,0x03,0x6c,0x04,0xab,0x00 } }, +{ 16, 0xf600, 0, {0x2e,0xc0,0x0b,0xb0,0x12,0xec,0x04,0xeb,0x00,0x22,0xc0,0x4a,0x94,0x82,0xe0,0x00 } }, +{ 16, 0xf610, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x6c,0x00,0x8a,0x00,0x22,0x00 } }, +{ 16, 0xf620, 0, {0x0b,0xb0,0x02,0x2c,0x00,0xb3,0x00,0xa2,0xc0,0x0b,0x30,0x02,0xac,0x00,0xab,0x04 } }, +{ 16, 0xf630, 0, {0x2e,0xc0,0x0b,0xb0,0x42,0xec,0x00,0xbb,0x00,0x22,0xc0,0x08,0xb0,0x22,0xe0,0x00 } }, +{ 16, 0xf640, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0c,0x00,0x8b,0x01,0x20,0x00 } }, +{ 16, 0xf650, 0, {0x0b,0x30,0x06,0x0c,0x00,0xb3,0x00,0x20,0xc0,0x0a,0x32,0x0a,0xcc,0x00,0xa3,0x00 } }, +{ 16, 0xf660, 0, {0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x00,0xa3,0x00,0x22,0xc0,0x4a,0x00,0x12,0xc2,0x01 } }, +{ 16, 0xf670, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x6c,0x00,0x8b,0x04,0x22,0xc0 } }, +{ 16, 0xf680, 0, {0x0f,0xf1,0x03,0x1c,0x00,0xff,0x04,0x32,0xc0,0x0b,0xf2,0x03,0xbc,0x00,0xef,0x00 } }, +{ 16, 0xf690, 0, {0x3e,0xc0,0x07,0xf0,0x03,0xfc,0x80,0xff,0x00,0xb2,0xc0,0x0c,0xa0,0x03,0xe0,0x03 } }, +{ 16, 0xf6a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xdc,0x00,0xf5,0x00,0x3f,0xc0 } }, +{ 16, 0xf6b0, 0, {0x0f,0xf0,0x03,0xfc,0x01,0xff,0x02,0x3b,0xc0,0x0f,0xf1,0x03,0x7c,0x00,0xff,0x00 } }, +{ 16, 0xf6c0, 0, {0x3f,0xc0,0x0f,0xf0,0x13,0xfc,0x40,0xef,0x00,0x3f,0xc0,0x0f,0xc0,0x03,0xe8,0x06 } }, +{ 16, 0xf6d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xf2,0x40,0xcc,0x80,0x37,0x20 } }, +{ 16, 0xf6e0, 0, {0x0c,0xd8,0x03,0xb0,0x44,0xfc,0x08,0x3f,0x0e,0x0f,0xc1,0x03,0xfc,0x00,0xcc,0x94 } }, +{ 16, 0xf6f0, 0, {0x3f,0x0a,0x2e,0xc4,0x03,0x7d,0x80,0xcf,0x10,0x3f,0xc0,0x0f,0xc0,0x83,0x30,0x00 } }, +{ 16, 0xf700, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0xe0,0x90,0x88,0x02,0x22,0x81 } }, +{ 16, 0xf710, 0, {0x08,0x92,0x13,0xa4,0x40,0x3b,0x60,0x22,0x18,0x0b,0x81,0x02,0xfc,0xd4,0x81,0x00 } }, +{ 16, 0xf720, 0, {0x3a,0xb0,0x0a,0x94,0x02,0x3d,0x40,0xaf,0x63,0x2f,0xdf,0x0b,0x98,0x00,0x20,0x04 } }, +{ 16, 0xf730, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xe0,0x00,0x88,0x00,0x20,0x40 } }, +{ 16, 0xf740, 0, {0x88,0x30,0x82,0xc0,0x00,0xb0,0x08,0x28,0x80,0x0a,0x10,0x02,0xcc,0x20,0x80,0x01 } }, +{ 16, 0xf750, 0, {0x2c,0x40,0x1b,0x06,0x02,0x8c,0x90,0x93,0x60,0x68,0xc0,0x4a,0x00,0x42,0x22,0x01 } }, +{ 16, 0xf760, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xa0,0x02,0x88,0x00,0x22,0xc0 } }, +{ 16, 0xf770, 0, {0x08,0xb0,0x02,0xe4,0x20,0xbb,0x88,0x26,0x98,0x0b,0x80,0x42,0xcc,0x18,0x8a,0x00 } }, +{ 16, 0xf780, 0, {0x2e,0xc2,0x1b,0x98,0x02,0xac,0x00,0xab,0x00,0x2e,0xc0,0x0b,0x98,0x82,0x30,0x04 } }, +{ 16, 0xf790, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0xe3,0xc0,0xcb,0x02,0x32,0x00 } }, +{ 16, 0xf7a0, 0, {0x2c,0x80,0x03,0xae,0x08,0xb9,0x00,0x3e,0x70,0x0f,0xb9,0x03,0xec,0x02,0x48,0x48 } }, +{ 16, 0xf7b0, 0, {0x3c,0xc0,0x0f,0x8c,0x93,0xec,0x00,0xdb,0x00,0x1a,0xc0,0x0e,0xac,0x03,0x10,0x04 } }, +{ 16, 0xf7c0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb2,0x00,0xff,0x00,0xbb,0x80 } }, +{ 16, 0xf7d0, 0, {0x0f,0xc0,0x43,0xb6,0x40,0xbd,0x00,0x3b,0x60,0x0f,0xe8,0x03,0xfc,0x00,0xff,0x94 } }, +{ 16, 0xf7e0, 0, {0x3b,0xe4,0x0e,0x60,0x0f,0x6c,0x08,0xef,0x01,0x3f,0xc0,0x0f,0x60,0x03,0xf8,0x00 } }, +{ 16, 0xf7f0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa1,0x00,0xfb,0x00,0x3e,0x60 } }, +{ 16, 0xf800, 0, {0x0f,0xa0,0x03,0xed,0x00,0xf9,0x40,0x3a,0x00,0x0f,0x90,0x03,0xec,0x02,0xc9,0x04 } }, +{ 16, 0xf810, 0, {0x32,0xd0,0x0f,0x90,0x03,0x2c,0x08,0xdb,0x00,0xb6,0xc0,0x0d,0xb4,0x03,0xd0,0x04 } }, +{ 16, 0xf820, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x00,0x00,0xb3,0x89,0x2e,0xe0 } }, +{ 16, 0xf830, 0, {0x0b,0xa4,0x03,0xa4,0x01,0xb9,0x00,0x2e,0x01,0x0b,0x90,0x42,0xfc,0x10,0x89,0x50 } }, +{ 16, 0xf840, 0, {0xa2,0xc0,0x8d,0xb4,0x02,0x3c,0x44,0x8f,0x00,0x23,0xc0,0x08,0xb0,0x02,0xf2,0x00 } }, +{ 16, 0xf850, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x04,0x0c,0x00,0xb0,0x80,0x2e,0x00 } }, +{ 16, 0xf860, 0, {0x0b,0x12,0x02,0xc8,0x00,0xba,0x00,0x2c,0xc0,0x0b,0x20,0x02,0xcc,0x00,0xa2,0x00 } }, +{ 16, 0xf870, 0, {0x20,0x00,0x2b,0x2d,0x9a,0x2e,0x42,0x83,0x00,0x28,0xc0,0x08,0x20,0x02,0xf8,0x00 } }, +{ 16, 0xf880, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x1e,0x04,0xb4,0x80,0x2d,0xa0 } }, +{ 16, 0xf890, 0, {0x0b,0x58,0x02,0x92,0x00,0xb6,0x80,0x2d,0xe0,0x0b,0x68,0x02,0xde,0x40,0xa6,0x80 } }, +{ 16, 0xf8a0, 0, {0x21,0x24,0x29,0x48,0x02,0x1e,0x80,0x87,0x80,0x69,0xe0,0x08,0x61,0x02,0xc8,0x00 } }, +{ 16, 0xf8b0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x18,0x0c,0x00,0xf0,0x30,0x3c,0x4c } }, +{ 16, 0xf8c0, 0, {0x0f,0x32,0x03,0xc8,0x80,0xb2,0x00,0x38,0x80,0x0f,0x1b,0x03,0xec,0x00,0xe0,0x30 } }, +{ 16, 0xf8d0, 0, {0x30,0x04,0x0f,0xb1,0x03,0x0e,0x85,0xcb,0x00,0x3a,0xc0,0x0c,0x31,0x03,0xd2,0x02 } }, +{ 16, 0xf8e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1c,0xbc,0x00,0xfc,0x11,0x3f,0xc4 } }, +{ 16, 0xf8f0, 0, {0x0f,0xb8,0x13,0xb0,0x04,0xfe,0x02,0x3f,0x80,0x0f,0xc0,0x03,0xfd,0x00,0xdf,0x12 } }, +{ 16, 0xf900, 0, {0x1d,0x04,0x0f,0xd0,0x43,0xbc,0x01,0xef,0x10,0x33,0xc4,0x0e,0xf3,0x03,0xd0,0x06 } }, +{ 16, 0xf910, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xee,0x00,0xcb,0x00,0x3e,0x00 } }, +{ 16, 0xf920, 0, {0x0f,0x80,0x03,0x28,0x00,0xf8,0x00,0x3e,0x40,0x3d,0xb0,0x03,0xef,0x08,0xc9,0x00 } }, +{ 16, 0xf930, 0, {0x3a,0x00,0x0c,0xa0,0x03,0xec,0x98,0xfb,0x20,0x32,0xd2,0x0c,0xa8,0x03,0x2a,0x02 } }, +{ 16, 0xf940, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0x87,0x01,0x2d,0x80 } }, +{ 16, 0xf950, 0, {0x0b,0x40,0x42,0x1c,0x04,0x37,0x00,0xa1,0x40,0x08,0x60,0x02,0xcc,0x80,0x87,0x00 } }, +{ 16, 0xf960, 0, {0x2d,0x80,0x2e,0x70,0x02,0xdc,0xa9,0xb7,0x28,0x21,0xd0,0x08,0x70,0x02,0x12,0x00 } }, +{ 16, 0xf970, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xbe,0x02,0x87,0x80,0x2d,0x60 } }, +{ 16, 0xf980, 0, {0x4b,0xe8,0x02,0x5a,0x01,0xb4,0x88,0x28,0xe0,0x88,0x78,0xc2,0xde,0x52,0x86,0xc0 } }, +{ 16, 0xf990, 0, {0x29,0x60,0x08,0x68,0x02,0xde,0x40,0xb3,0x92,0xe1,0xe8,0x28,0x28,0x02,0x70,0x00 } }, +{ 16, 0xf9a0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x14,0xcc,0x00,0x8b,0x80,0x2e,0xc0 } }, +{ 16, 0xf9b0, 0, {0x0b,0x20,0x02,0x4d,0x80,0x9b,0x20,0x20,0xe0,0x08,0x38,0x02,0xcc,0x00,0x83,0x80 } }, +{ 16, 0xf9c0, 0, {0x2c,0xc0,0x0a,0xb0,0x02,0xcc,0x08,0xb3,0x00,0x20,0xc0,0x08,0x31,0x02,0x52,0x04 } }, +{ 16, 0xf9d0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x05,0xa8,0x00,0xca,0xe0,0x3e,0x80 } }, +{ 16, 0xf9e0, 0, {0x1f,0xa4,0x0b,0x79,0x00,0xfe,0x00,0x3f,0x82,0x1d,0xe0,0x03,0xe8,0x00,0xce,0x40 } }, +{ 16, 0xf9f0, 0, {0x3b,0x88,0x2c,0xe4,0x03,0xe8,0x01,0xfa,0x00,0x32,0x80,0x0c,0xe8,0x03,0x7a,0x04 } }, +{ 16, 0xfa00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0xa0,0x00,0xf8,0x09,0x3e,0x00 } }, +{ 16, 0xfa10, 0, {0x8f,0xc0,0x83,0xa0,0x18,0xf8,0x00,0x3c,0x20,0x0f,0x88,0x03,0xe0,0x00,0xf8,0x08 } }, +{ 16, 0xfa20, 0, {0x3e,0x20,0x0e,0x80,0x83,0xe1,0x01,0xf0,0x00,0x3c,0x00,0x0f,0x80,0x0b,0x92,0x00 } }, +{ 16, 0xfa30, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xa4,0x00,0xf9,0x42,0x32,0x40 } }, +{ 16, 0xfa40, 0, {0x4c,0x98,0x03,0x04,0x00,0xc9,0x00,0x3a,0x40,0x0f,0x90,0x23,0x24,0x00,0xb9,0x81 } }, +{ 16, 0xfa50, 0, {0x3c,0x40,0x0c,0x92,0x03,0x24,0x00,0xf9,0x05,0x32,0x40,0x6c,0x90,0xc3,0xc2,0x04 } }, +{ 16, 0xfa60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x24,0x14,0xb9,0x00,0xa2,0x54 } }, +{ 16, 0xfa70, 0, {0x08,0x9b,0x1a,0x24,0x02,0x89,0x00,0x22,0x40,0x28,0x90,0x02,0xa4,0x00,0xb9,0x90 } }, +{ 16, 0xfa80, 0, {0x2e,0x40,0x28,0x9c,0x82,0x25,0x04,0xb9,0x00,0x22,0x40,0x08,0x98,0x12,0xe0,0x00 } }, +{ 16, 0xfa90, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xad,0x00,0x23,0x40 } }, +{ 16, 0xfaa0, 0, {0x08,0x50,0x02,0x64,0x00,0x89,0x00,0x2a,0x40,0x08,0x10,0x02,0x64,0x00,0xb9,0x00 } }, +{ 16, 0xfab0, 0, {0x6e,0x40,0x08,0x90,0x02,0x25,0x00,0xa9,0x00,0x22,0x40,0x08,0x91,0x06,0xc6,0x00 } }, +{ 16, 0xfac0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x14,0x00,0xb5,0x10,0xa1,0x44 } }, +{ 16, 0xfad0, 0, {0x28,0x50,0x02,0x44,0x80,0x81,0x30,0x20,0x48,0x08,0x12,0x02,0x84,0x40,0xb1,0x80 } }, +{ 16, 0xfae0, 0, {0x6c,0xc8,0x08,0x12,0x02,0x04,0x80,0xb1,0x34,0x20,0x48,0x08,0x12,0x02,0xc2,0x01 } }, +{ 16, 0xfaf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xe8,0x40,0x32,0x90 } }, +{ 16, 0xfb00, 0, {0x0c,0xc5,0x03,0x61,0x40,0xc0,0x40,0x3a,0x14,0x0f,0x85,0x03,0x21,0xb0,0xf8,0x50 } }, +{ 16, 0xfb10, 0, {0x3e,0x00,0x0c,0x85,0x03,0x21,0x40,0xf8,0x40,0xb0,0x14,0x0c,0x80,0x03,0xee,0x01 } }, +{ 16, 0xfb20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x1d,0xc4,0x04,0xf9,0x22,0x0e,0x48 } }, +{ 16, 0xfb30, 0, {0x0f,0x10,0x13,0xb4,0x40,0xfd,0x30,0x3f,0x44,0x4f,0xd1,0x00,0xe4,0x84,0xff,0x01 } }, +{ 16, 0xfb40, 0, {0x3d,0x44,0x0f,0xd1,0x0b,0xe4,0x40,0xf9,0x30,0x3e,0x44,0x0f,0xd1,0x03,0xe6,0x04 } }, +{ 16, 0xfb50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x05,0xe4,0x00,0xdd,0x40,0x3f,0x50 } }, +{ 16, 0xfb60, 0, {0x0c,0xd0,0x03,0x2c,0x00,0xc9,0x00,0x36,0x40,0x0f,0x90,0x13,0x27,0x04,0xf5,0x01 } }, +{ 16, 0xfb70, 0, {0x37,0x40,0x0c,0xf0,0x03,0xf6,0x20,0xf9,0xa8,0x32,0x68,0x0c,0xd0,0x03,0xc6,0x00 } }, +{ 16, 0xfb80, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xe0,0x00,0x88,0xa0,0x2e,0x28 } }, +{ 16, 0xfb90, 0, {0x28,0x80,0x02,0x20,0x00,0x88,0xa0,0x22,0x00,0x0b,0x80,0x0a,0x62,0x80,0xb8,0x00 } }, +{ 16, 0xfba0, 0, {0x22,0x00,0x08,0x80,0x02,0xe1,0x00,0xb8,0xe0,0x22,0x3a,0x08,0xa0,0x02,0xce,0x04 } }, +{ 16, 0xfbb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x84,0x02,0x81,0x00,0x2e,0x40 } }, +{ 16, 0xfbc0, 0, {0x08,0x10,0x0a,0x44,0x02,0x81,0x08,0x24,0x40,0x0a,0x10,0x02,0x45,0x80,0xb9,0x00 } }, +{ 16, 0xfbd0, 0, {0x24,0x40,0x29,0x10,0x02,0xc4,0x00,0xb1,0x08,0x24,0x44,0x08,0x10,0x02,0xc2,0x01 } }, +{ 16, 0xfbe0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x14,0xa4,0x04,0x89,0x01,0x2e,0x50 } }, +{ 16, 0xfbf0, 0, {0x48,0xb2,0x02,0x64,0x00,0x91,0x00,0x22,0x46,0x0b,0x90,0x02,0x64,0x00,0xb9,0x01 } }, +{ 16, 0xfc00, 0, {0x26,0xc0,0x09,0xb0,0x12,0xe4,0x00,0xb1,0x00,0x26,0x40,0x08,0x90,0x02,0xc6,0x04 } }, +{ 16, 0xfc10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x04,0xe4,0x00,0xc9,0x00,0x3c,0x40 } }, +{ 16, 0xfc20, 0, {0x0c,0x90,0x03,0x64,0x00,0xc9,0x02,0x36,0x50,0x0e,0x93,0x03,0x24,0x00,0xf9,0x90 } }, +{ 16, 0xfc30, 0, {0x36,0x48,0x0d,0x94,0x83,0xe4,0x08,0xf9,0x00,0xb6,0x40,0x0c,0x94,0x03,0xe8,0x04 } }, +{ 16, 0xfc40, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x10,0xa4,0x00,0xe9,0x00,0x3e,0x40 } }, +{ 16, 0xfc50, 0, {0x0f,0x90,0x13,0xa4,0x00,0xe9,0x02,0x2e,0x61,0x05,0x90,0x03,0xa4,0x00,0xf9,0x00 } }, +{ 16, 0xfc60, 0, {0x3a,0x40,0x0e,0x90,0x43,0xe4,0x10,0xf9,0x00,0x38,0x40,0x2f,0x90,0x03,0xca,0x00 } }, +{ 16, 0xfc70, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xd8,0x01,0x32,0x04 } }, +{ 16, 0xfc80, 0, {0x0f,0x80,0x43,0xc0,0x01,0xc8,0x00,0xb2,0x01,0x0c,0x80,0x03,0x20,0x00,0xc8,0x40 } }, +{ 16, 0xfc90, 0, {0x30,0x00,0x8c,0x84,0x83,0xe0,0x00,0xc8,0x00,0x32,0x00,0x6c,0x84,0x03,0xca,0x04 } }, +{ 16, 0xfca0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x28,0x00,0xba,0x00,0x23,0x80 } }, +{ 16, 0xfcb0, 0, {0x0b,0xea,0x02,0xe8,0x00,0xaa,0x00,0x22,0x80,0x08,0xa0,0x02,0x28,0x00,0x86,0x20 } }, +{ 16, 0xfcc0, 0, {0x37,0xa0,0x8d,0xe4,0x02,0xf8,0x00,0xda,0x00,0x22,0x80,0x08,0xa0,0x02,0xca,0x00 } }, +{ 16, 0xfcd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0x6c,0x00,0xb3,0x00,0x20,0xc0 } }, +{ 16, 0xfce0, 0, {0x0b,0xb8,0x02,0x4c,0x04,0x83,0x00,0x20,0xc0,0x08,0xb0,0x02,0x0c,0x02,0x83,0x00 } }, +{ 16, 0xfcf0, 0, {0x20,0x40,0x28,0x34,0x02,0xce,0x90,0x83,0x00,0xa0,0xc0,0x08,0x30,0x02,0xca,0x00 } }, +{ 16, 0xfd00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1c,0xc0,0xb5,0x88,0x21,0x40 } }, +{ 16, 0xfd10, 0, {0x0b,0x70,0x02,0xdc,0x80,0xa3,0x20,0x21,0xe0,0x48,0x32,0x42,0x0e,0x90,0x8e,0x01 } }, +{ 16, 0xfd20, 0, {0x65,0x50,0x09,0x70,0x02,0xde,0x20,0x93,0x21,0x21,0xc0,0x08,0x70,0x02,0xe8,0x00 } }, +{ 16, 0xfd30, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x18,0x1e,0x00,0xff,0x80,0xb1,0xa0 } }, +{ 16, 0xfd40, 0, {0x0f,0x48,0x02,0x7e,0x00,0x87,0xa0,0x33,0xe0,0x28,0x7a,0x0b,0x1f,0x00,0xc4,0x80 } }, +{ 16, 0xfd50, 0, {0x31,0x60,0x8c,0x58,0x03,0xfe,0x00,0xc7,0xc8,0x33,0xe8,0x0c,0x58,0x03,0xea,0x02 } }, +{ 16, 0xfd60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xff,0x00,0x3e,0x00 } }, +{ 16, 0xfd70, 0, {0x0f,0x90,0x23,0xec,0xa0,0xfb,0x40,0x3e,0xc0,0x8f,0xb5,0x03,0xed,0x80,0xf8,0x00 } }, +{ 16, 0xfd80, 0, {0x3c,0x40,0x0f,0xb0,0x03,0xe8,0x00,0xfb,0x02,0x3e,0xd0,0x0f,0x90,0x03,0xc2,0x06 } }, +{ 16, 0xfd90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x04,0xbe,0x00,0xff,0x80,0x3f,0xe0 } }, +{ 16, 0xfda0, 0, {0x0f,0xd9,0x03,0xfe,0x20,0xcf,0xc8,0x33,0xea,0x8f,0xfc,0x03,0x3f,0x00,0xfd,0x80 } }, +{ 16, 0xfdb0, 0, {0x3f,0x60,0x0e,0xe8,0x03,0xf2,0x00,0xcf,0x80,0x2f,0xfe,0x0c,0x78,0x03,0x00,0x00 } }, +{ 16, 0xfdc0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x00,0x9c,0x00,0xb5,0x02,0x2d,0xc0 } }, +{ 16, 0xfdd0, 0, {0x0b,0x58,0x42,0xdc,0x80,0xcf,0x00,0x21,0xc1,0x0b,0x30,0x12,0x1c,0x40,0xb4,0x02 } }, +{ 16, 0xfde0, 0, {0x2d,0x46,0x08,0x71,0x12,0xc8,0x00,0xe7,0x00,0x2d,0xc4,0x08,0x70,0x03,0x6a,0x04 } }, +{ 16, 0xfdf0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xb7,0x00,0x2d,0x02 } }, +{ 16, 0xfe00, 0, {0x0b,0x46,0x02,0xdc,0x08,0x97,0x00,0x21,0xc9,0x0a,0x30,0x22,0x1c,0x00,0xb4,0x00 } }, +{ 16, 0xfe10, 0, {0x2d,0x40,0x0a,0x50,0x82,0xc4,0x00,0xb7,0x00,0x2c,0xc8,0x28,0x50,0x02,0x40,0x10 } }, +{ 16, 0xfe20, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x14,0x8c,0x18,0xb3,0x00,0x2e,0x20 } }, +{ 16, 0xfe30, 0, {0x0b,0x18,0x02,0xcf,0x4a,0x83,0xc2,0x20,0xc1,0x0b,0x34,0x22,0x0c,0x04,0xb8,0x58 } }, +{ 16, 0xfe40, 0, {0x2c,0x40,0x0b,0x28,0x02,0xc8,0x00,0xa3,0x00,0x2c,0xc0,0x08,0x14,0x02,0x48,0x04 } }, +{ 16, 0xfe50, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xbc,0x00,0xfb,0x00,0x3e,0x80 } }, +{ 16, 0xfe60, 0, {0x0f,0xa0,0x02,0xfc,0x00,0xdf,0xa0,0xb3,0xc0,0x0e,0xf0,0x0b,0x3c,0x00,0xfb,0xc0 } }, +{ 16, 0xfe70, 0, {0x3c,0xa0,0x0e,0xbd,0x03,0xec,0x00,0xff,0x00,0x3f,0xc0,0x0c,0x30,0x03,0x6a,0x04 } }, +{ 16, 0xfe80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0xec,0x00,0xf9,0x00,0x3e,0x01 } }, +{ 16, 0xfe90, 0, {0x8f,0xb1,0x43,0xec,0x00,0xf3,0x00,0x3e,0xc0,0x4f,0xb0,0x13,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xfea0, 0, {0x3e,0x80,0x0c,0x84,0x03,0xe1,0x00,0x73,0x00,0x3e,0xc1,0x0f,0xb2,0x43,0xe0,0x00 } }, +{ 16, 0xfeb0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x50,0xfc,0x10,0xff,0x80,0x37,0xc0 } }, +{ 16, 0xfec0, 0, {0x0c,0xe0,0x03,0xfc,0x20,0xff,0x08,0x33,0xc0,0x0f,0xf0,0x83,0xbc,0x00,0xff,0x00 } }, +{ 16, 0xfed0, 0, {0x33,0xc0,0x2e,0x40,0x03,0x1c,0x01,0xcf,0x00,0x11,0xc0,0x4c,0xd0,0x03,0x00,0x44 } }, +{ 16, 0xfee0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x04,0xb3,0x02,0x22,0x72 } }, +{ 16, 0xfef0, 0, {0x08,0xa1,0x16,0xec,0x00,0xbb,0x04,0x22,0xc0,0x0b,0xb0,0x42,0xec,0x00,0xba,0x19 } }, +{ 16, 0xff00, 0, {0xb6,0xd0,0x08,0x9c,0x4a,0x26,0x80,0xdb,0x00,0x22,0xc0,0x08,0x90,0x03,0x60,0x40 } }, +{ 16, 0xff10, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0xb9,0x10,0x62,0x20 } }, +{ 16, 0xff20, 0, {0x48,0xa0,0x02,0xec,0x00,0xbb,0x00,0x22,0xc0,0x0b,0xb0,0x02,0xec,0x10,0xbb,0x00 } }, +{ 16, 0xff30, 0, {0x66,0x08,0x0a,0xa8,0x12,0x26,0x10,0x9b,0x00,0x2a,0xc0,0x28,0xb0,0x26,0x20,0x00 } }, +{ 16, 0xff40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0c,0x00,0xb9,0x00,0x20,0x00 } }, +{ 16, 0xff50, 0, {0x08,0x32,0x02,0xcc,0x04,0xb3,0x00,0x20,0xc0,0x4b,0x30,0x02,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0xff60, 0, {0x20,0x00,0x08,0x00,0x02,0x01,0x00,0x93,0x00,0x28,0xc0,0x08,0x30,0x06,0x42,0x11 } }, +{ 16, 0xff70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x6c,0x00,0xf9,0x00,0xb2,0x40 } }, +{ 16, 0xff80, 0, {0x0c,0x82,0x02,0xdc,0x01,0xff,0x00,0xb2,0xc0,0x0b,0xf1,0x03,0xbc,0x00,0xf9,0x00 } }, +{ 16, 0xff90, 0, {0x26,0x40,0x2e,0x80,0x03,0x21,0x04,0xcf,0x00,0xbb,0xc0,0x0c,0x90,0x03,0x00,0x03 } }, +{ 16, 0xffa0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xfd,0x00,0x3f,0x40 } }, +{ 16, 0xffb0, 0, {0x0f,0x81,0x03,0xfc,0x00,0xff,0x00,0x3f,0xc0,0x0f,0xf0,0x23,0xfc,0x00,0xfc,0x00 } }, +{ 16, 0xffc0, 0, {0x2d,0x40,0x2f,0xc0,0x03,0xf0,0x88,0xff,0x00,0x37,0xc0,0x8f,0xd0,0x03,0xe8,0x02 } }, +{ 16, 0xffd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfe,0x40,0xff,0x80,0x33,0xc2 } }, +{ 16, 0xffe0, 0, {0x0c,0xf8,0x03,0x7c,0xa0,0xff,0x90,0x3f,0xc4,0x2c,0xb4,0x03,0xbc,0x80,0xcf,0x40 } }, +{ 16, 0xfff0, 0, {0x37,0xe0,0x0f,0xf1,0x93,0x6e,0x44,0xbf,0x30,0x3f,0x20,0x2c,0xf8,0x63,0xf0,0x04 } }, +{ 16, 0x8010, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xec,0x00,0xeb,0x20,0x23,0xf0 } }, +{ 16, 0x8020, 0, {0x08,0xb8,0x52,0x3d,0x00,0xb3,0x00,0x2e,0xdc,0x08,0xf4,0x42,0x1c,0x42,0x8b,0x40 } }, +{ 16, 0x8030, 0, {0x22,0xc8,0x0b,0xf6,0x03,0x6c,0x88,0xbb,0x30,0x2e,0x00,0x08,0xb2,0x02,0xe0,0x04 } }, +{ 16, 0x8040, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0x00,0xbb,0x08,0x20,0xc0 } }, +{ 16, 0x8050, 0, {0x08,0x30,0x02,0x4c,0xa0,0xb3,0x20,0x26,0x80,0x88,0x36,0x02,0xcc,0xa0,0x93,0x60 } }, +{ 16, 0x8060, 0, {0xa4,0xc2,0x0a,0x32,0x42,0x4c,0x90,0xb3,0x20,0x2c,0x0b,0x88,0x30,0x82,0xe2,0x01 } }, +{ 16, 0x8070, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x08,0xbb,0x22,0xa2,0xc0 } }, +{ 16, 0x8080, 0, {0x08,0xb0,0x02,0x2c,0x00,0xbb,0x00,0x2e,0x90,0x08,0xb0,0x02,0xec,0x00,0x9b,0x00 } }, +{ 16, 0x8090, 0, {0x22,0xc0,0x0b,0xb0,0x02,0x6c,0x00,0xbb,0x02,0x2e,0x20,0x08,0xb0,0x02,0xf0,0x00 } }, +{ 16, 0x80a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xb1,0x83,0x32,0xc0 } }, +{ 16, 0x80b0, 0, {0x0c,0x1a,0x03,0x6c,0x10,0xfb,0x00,0x34,0xc0,0x0c,0xb0,0x03,0xec,0x08,0xda,0x00 } }, +{ 16, 0x80c0, 0, {0x36,0xc0,0x0e,0xb0,0x0b,0x6c,0x00,0xfb,0x00,0x3e,0x28,0x0c,0xb0,0x02,0xd0,0x00 } }, +{ 16, 0x80d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xbc,0x00,0xed,0x80,0x3f,0xc0 } }, +{ 16, 0x80e0, 0, {0x0f,0xd4,0x03,0xec,0x00,0xff,0x00,0x3f,0xc8,0x0f,0xb0,0x03,0x3c,0x00,0xee,0x40 } }, +{ 16, 0x80f0, 0, {0x3f,0xc0,0x0f,0x70,0x03,0xfc,0x00,0xff,0x00,0x3f,0x80,0x0f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0x8100, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xfb,0x20,0xb0,0xc0 } }, +{ 16, 0x8110, 0, {0x0f,0xb4,0x03,0xac,0x02,0xcb,0x00,0x32,0x90,0x0e,0xb0,0x03,0x6c,0x00,0xeb,0x00 } }, +{ 16, 0x8120, 0, {0x3a,0xc0,0x0c,0xb0,0x02,0xec,0x00,0xfb,0x00,0x3e,0x91,0x0f,0xb0,0x03,0x90,0x00 } }, +{ 16, 0x8130, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0xbb,0x80,0x23,0xd7 } }, +{ 16, 0x8140, 0, {0x0b,0x90,0x02,0x3c,0x14,0x8b,0x00,0x6a,0x08,0x28,0xf0,0x00,0xbc,0x00,0x83,0x00 } }, +{ 16, 0x8150, 0, {0xbe,0xc0,0x88,0xf0,0x13,0x2c,0x00,0xef,0x00,0x2e,0x80,0x0b,0xb0,0x07,0xb2,0x00 } }, +{ 16, 0x8160, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xb3,0x40,0x20,0xd0 } }, +{ 16, 0x8170, 0, {0x0b,0x28,0x02,0x8c,0x00,0x83,0x01,0x20,0xc0,0x1a,0xb8,0x00,0x6c,0x10,0xa1,0x00 } }, +{ 16, 0x8180, 0, {0x68,0xc0,0x2a,0x30,0x02,0x8c,0x00,0xb3,0x02,0x2e,0x00,0x4b,0x30,0x02,0xf8,0x04 } }, +{ 16, 0x8190, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x00,0xb7,0xa0,0x21,0xe0 } }, +{ 16, 0x81a0, 0, {0x0b,0xec,0xc2,0x1e,0x04,0x87,0x80,0x29,0xe4,0x08,0x79,0x82,0x9e,0x40,0xaf,0x90 } }, +{ 16, 0x81b0, 0, {0x29,0xe0,0x0a,0x38,0x00,0x1e,0x00,0xa7,0x90,0x2d,0x24,0x0b,0x78,0x02,0x88,0x00 } }, +{ 16, 0x81c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x50,0xfb,0x09,0x30,0xc0 } }, +{ 16, 0x81d0, 0, {0x0f,0x20,0x02,0x8c,0x40,0xc3,0x00,0x20,0xc0,0x0a,0x38,0x03,0x4c,0x44,0xe1,0x00 } }, +{ 16, 0x81e0, 0, {0xaa,0xc0,0x0e,0x31,0x43,0x8e,0x00,0xf3,0x00,0x3c,0x00,0x0f,0x30,0x03,0xd2,0x02 } }, +{ 16, 0x81f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x4d,0xbc,0x00,0xff,0x20,0x3f,0xd0 } }, +{ 16, 0x8200, 0, {0x4f,0x70,0x03,0xfc,0x00,0xff,0x00,0x3d,0xc0,0x0f,0xf3,0x43,0xfc,0x40,0xd7,0x00 } }, +{ 16, 0x8210, 0, {0xbf,0xc0,0x0d,0xf4,0xc3,0xfc,0x40,0xff,0x00,0x3f,0x40,0x0f,0xf0,0x03,0xd0,0x06 } }, +{ 16, 0x8220, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xec,0x00,0xfb,0x00,0x32,0xd0 } }, +{ 16, 0x8230, 0, {0x0d,0x90,0x01,0xed,0xc0,0xfb,0x00,0x3e,0xc0,0x1f,0xba,0x03,0xac,0xc0,0xc8,0x00 } }, +{ 16, 0x8240, 0, {0x32,0xe0,0x8d,0xb4,0x43,0xec,0x00,0xfb,0x00,0x36,0xa0,0x0c,0xb0,0x03,0x6a,0x00 } }, +{ 16, 0x8250, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0xb7,0x00,0x21,0xc8 } }, +{ 16, 0x8260, 0, {0x08,0x60,0x02,0xdc,0x20,0xb7,0x00,0x2d,0xc0,0x0f,0x74,0xa2,0x1c,0x28,0xd6,0x00 } }, +{ 16, 0x8270, 0, {0x35,0xc0,0x08,0x72,0x02,0x5c,0x08,0xb7,0x44,0xa1,0x80,0x48,0x70,0x02,0x12,0x00 } }, +{ 16, 0x8280, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0xb7,0x80,0x20,0xe4 } }, +{ 16, 0x8290, 0, {0x09,0x78,0x26,0xde,0x00,0xb7,0x80,0x2d,0xe2,0x0a,0x70,0x12,0x8c,0x88,0x81,0x80 } }, +{ 16, 0x82a0, 0, {0x21,0xe0,0x09,0x78,0x02,0xde,0x00,0xb3,0xa0,0x25,0xa0,0x28,0x78,0x02,0x70,0x04 } }, +{ 16, 0x82b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x01,0xbb,0x80,0x20,0xc0 } }, +{ 16, 0x82c0, 0, {0x08,0x30,0x42,0xec,0x00,0xb3,0x00,0x2c,0xc0,0x0a,0x30,0x22,0x0c,0x00,0x93,0x00 } }, +{ 16, 0x82d0, 0, {0x24,0xc1,0x08,0x30,0x02,0xcc,0x00,0xb3,0x00,0x20,0xe0,0x08,0xb0,0x02,0x12,0x04 } }, +{ 16, 0x82e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xfa,0x08,0xb2,0x80 } }, +{ 16, 0x82f0, 0, {0x0d,0xe2,0x03,0xe8,0x00,0xfa,0x00,0x3f,0x80,0x0a,0xa0,0x03,0xa8,0x00,0xce,0x50 } }, +{ 16, 0x8300, 0, {0x32,0x80,0x05,0xa0,0x03,0xe8,0x00,0xfa,0x00,0x37,0xa8,0x0c,0xa0,0x03,0x7a,0x04 } }, +{ 16, 0x8310, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x60,0x08,0xf8,0x00,0x3c,0x00 } }, +{ 16, 0x8320, 0, {0x0f,0x88,0x01,0xe0,0x00,0xf8,0x04,0x3c,0x00,0x4f,0x00,0x13,0xc0,0x00,0xf8,0x00 } }, +{ 16, 0x8330, 0, {0x3e,0x00,0x0f,0x80,0x03,0x60,0x00,0xf8,0x02,0x3e,0x01,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0x8340, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xf9,0x90,0x12,0x40 } }, +{ 16, 0x8350, 0, {0x0c,0x90,0x03,0xa4,0x00,0xc9,0x00,0x3e,0x70,0x0e,0x94,0x33,0x24,0x08,0xc9,0x00 } }, +{ 16, 0x8360, 0, {0x2a,0x40,0x0b,0x90,0x03,0xe4,0x00,0xf9,0x00,0x3a,0x40,0x0f,0x90,0x03,0x02,0x04 } }, +{ 16, 0x8370, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x42,0x22,0x60 } }, +{ 16, 0x8380, 0, {0x08,0x10,0x02,0x24,0x00,0x89,0x03,0x2e,0x40,0x08,0x90,0x02,0xa4,0x01,0x81,0x04 } }, +{ 16, 0x8390, 0, {0x3e,0x40,0x0b,0x90,0x02,0xe4,0x00,0xb9,0x02,0x22,0x40,0x0e,0x90,0x02,0x20,0x00 } }, +{ 16, 0x83a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb9,0x40,0x2a,0x4a } }, +{ 16, 0x83b0, 0, {0x08,0x91,0x02,0xa4,0x00,0x89,0x00,0x2e,0x40,0x1a,0x90,0x0a,0x24,0x04,0x89,0x00 } }, +{ 16, 0x83c0, 0, {0x2a,0x40,0x0b,0x90,0x02,0xe4,0x00,0xb1,0x00,0x2a,0x40,0x0b,0x90,0x02,0x06,0x00 } }, +{ 16, 0x83d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0xb1,0x01,0xa8,0x48 } }, +{ 16, 0x83e0, 0, {0x88,0x90,0x02,0x04,0x80,0x81,0x40,0x2c,0x50,0x18,0x14,0x0a,0x84,0x10,0x89,0x40 } }, +{ 16, 0x83f0, 0, {0x2c,0x40,0x0b,0x10,0x02,0xc4,0x00,0x31,0x20,0x20,0x40,0x0a,0x10,0x0a,0x02,0x01 } }, +{ 16, 0x8400, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xf0,0x50,0x3a,0x00 } }, +{ 16, 0x8410, 0, {0x2c,0xa0,0x02,0xa1,0x42,0xc8,0x00,0x3e,0x00,0xde,0x00,0x23,0x21,0x42,0x88,0x00 } }, +{ 16, 0x8420, 0, {0x38,0x14,0x0f,0x85,0x03,0xe1,0x40,0xf8,0x50,0x38,0x14,0x0f,0x05,0x03,0x2e,0x01 } }, +{ 16, 0x8430, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xe4,0x08,0xfd,0x00,0x36,0x44 } }, +{ 16, 0x8440, 0, {0x0f,0xd0,0x03,0x64,0x40,0xf9,0x00,0x3d,0x50,0x0f,0x94,0x03,0xe5,0x00,0x7d,0x40 } }, +{ 16, 0x8450, 0, {0x3e,0x40,0x0f,0x94,0x03,0xe4,0x00,0xf9,0x10,0x3f,0x40,0x0e,0x90,0x03,0xe6,0x04 } }, +{ 16, 0x8460, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe4,0x00,0xfd,0x40,0x33,0x68 } }, +{ 16, 0x8470, 0, {0x0c,0xd0,0x03,0xe7,0x81,0xf9,0x00,0x33,0x78,0x0d,0xd8,0x13,0x26,0xa0,0xcd,0xa0 } }, +{ 16, 0x8480, 0, {0x32,0x40,0x0d,0x9b,0x03,0x24,0x00,0xf9,0xa0,0x3c,0x44,0x2c,0x90,0x07,0x86,0x00 } }, +{ 16, 0x8490, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe0,0x00,0xb8,0xa0,0xa2,0x10 } }, +{ 16, 0x84a0, 0, {0x18,0x80,0x03,0x82,0x84,0xb8,0x80,0x36,0x2c,0x2e,0x0f,0x02,0xa3,0xa0,0xd8,0xe0 } }, +{ 16, 0x84b0, 0, {0x36,0x22,0x8b,0x08,0x03,0x42,0xa0,0xf8,0xe0,0x2e,0x28,0x08,0x88,0x02,0xce,0x04 } }, +{ 16, 0x84c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0xb1,0x00,0xa0,0x50 } }, +{ 16, 0x84d0, 0, {0x28,0x30,0x02,0xc5,0x80,0xb1,0x08,0x20,0x40,0x09,0x10,0xa2,0x44,0x08,0x81,0x48 } }, +{ 16, 0x84e0, 0, {0x20,0x40,0x0b,0x14,0x02,0x04,0x80,0xb1,0x38,0x2c,0x48,0x08,0x12,0x82,0x82,0x01 } }, +{ 16, 0x84f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa4,0x00,0xb1,0x00,0x22,0x40 } }, +{ 16, 0x8500, 0, {0x08,0x92,0x02,0xe4,0x00,0xb9,0x02,0x26,0x58,0x4a,0x90,0x02,0xe4,0x08,0x99,0x40 } }, +{ 16, 0x8510, 0, {0x26,0x40,0x0b,0x90,0x02,0x64,0x08,0xb9,0x01,0x2c,0x48,0x08,0x90,0x12,0xc6,0x04 } }, +{ 16, 0x8520, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0x80,0x32,0x40 } }, +{ 16, 0x8530, 0, {0x08,0x98,0x83,0xe4,0x04,0xb9,0x01,0x30,0x40,0x0d,0x90,0x0b,0x64,0x02,0xc9,0x00 } }, +{ 16, 0x8540, 0, {0x32,0x40,0x0f,0x90,0x03,0x24,0x00,0xf9,0x00,0x1e,0x58,0x0c,0x90,0x03,0xa8,0x04 } }, +{ 16, 0x8550, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x20,0x3c,0x40 } }, +{ 16, 0x8560, 0, {0x0f,0x98,0x03,0xa4,0x00,0xb9,0x00,0x3e,0x42,0x8e,0x10,0x4b,0x84,0x04,0xf9,0x00 } }, +{ 16, 0x8570, 0, {0x3e,0x40,0x8f,0x90,0x03,0xe4,0x00,0xe9,0x00,0x3e,0x40,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0x8580, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xd8,0x00,0x32,0x08 } }, +{ 16, 0x8590, 0, {0x0f,0x84,0x83,0xa0,0x04,0xc8,0x04,0x3e,0x00,0x83,0x80,0x01,0x20,0x00,0xc0,0x00 } }, +{ 16, 0x85a0, 0, {0x32,0x00,0x0f,0x00,0x03,0xa0,0x00,0xc8,0x00,0x32,0x10,0x4e,0x80,0x13,0xca,0x04 } }, +{ 16, 0x85b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x8e,0x90,0xa3,0x80 } }, +{ 16, 0x85c0, 0, {0x0b,0xe4,0x02,0x28,0x00,0xca,0x00,0x2f,0x80,0x4a,0xa0,0x13,0xa8,0x00,0xaa,0x00 } }, +{ 16, 0x85d0, 0, {0x36,0x81,0x0b,0xa0,0x02,0x28,0x00,0x8a,0x00,0x22,0x80,0x08,0xa0,0x03,0x8a,0x00 } }, +{ 16, 0x85e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x93,0xc0,0x20,0xd0 } }, +{ 16, 0x85f0, 0, {0x0b,0x34,0x02,0x8c,0x00,0x8b,0x00,0x2c,0xf0,0x8b,0x18,0x02,0x4c,0x00,0x83,0x00 } }, +{ 16, 0x8600, 0, {0x60,0xc0,0x0b,0x30,0x02,0x8c,0x02,0x83,0x00,0x28,0xc1,0x0a,0x30,0x02,0xca,0x00 } }, +{ 16, 0x8610, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1e,0x00,0xb4,0x0b,0x69,0xc0 } }, +{ 16, 0x8620, 0, {0x09,0x58,0x06,0x1e,0x80,0x97,0x10,0x2f,0xc2,0x48,0x70,0x82,0x9c,0x80,0xa7,0x08 } }, +{ 16, 0x8630, 0, {0x25,0xcc,0x0b,0x70,0x02,0x1e,0x81,0x87,0xa2,0xab,0xc4,0x08,0x73,0x02,0xe8,0x00 } }, +{ 16, 0x8640, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x3e,0x10,0xdc,0x84,0x21,0xe0 } }, +{ 16, 0x8650, 0, {0x0f,0x78,0x42,0x9f,0x02,0xc7,0x88,0x3d,0xe0,0x2f,0x71,0x03,0x4e,0x00,0xcf,0x80 } }, +{ 16, 0x8660, 0, {0x21,0xe2,0x0f,0x78,0x83,0x9e,0x49,0xcf,0xd0,0x39,0xe8,0x0e,0x78,0x03,0xea,0x02 } }, +{ 16, 0x8670, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x4d,0xac,0x40,0xca,0x00,0x36,0x00 } }, +{ 16, 0x8680, 0, {0x8f,0x30,0x23,0xec,0xa8,0xeb,0x40,0x3c,0xc0,0x0f,0x96,0x43,0xed,0x80,0xfb,0x00 } }, +{ 16, 0x8690, 0, {0x3e,0xd8,0x8f,0xb1,0x43,0xed,0x80,0xfb,0x20,0x36,0xca,0x0f,0xb0,0xa3,0x82,0x06 } }, +{ 16, 0x86a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x80,0xfc,0x80,0x31,0xe0 } }, +{ 16, 0x86b0, 0, {0x05,0xaa,0x10,0xfe,0x44,0xff,0x90,0x3f,0xe1,0xcf,0xf9,0x17,0x3f,0x20,0xd7,0x80 } }, +{ 16, 0x86c0, 0, {0x8b,0xe4,0x0f,0xf8,0x03,0x3e,0x30,0xff,0x80,0x37,0xe0,0x0f,0xf8,0x00,0x40,0x00 } }, +{ 16, 0x86d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xbd,0x10,0x21,0xc0 } }, +{ 16, 0x86e0, 0, {0x08,0x4a,0x02,0xdc,0xc0,0xb7,0x00,0x2d,0xc2,0x0c,0xd3,0x02,0x1c,0x80,0x87,0x00 } }, +{ 16, 0x86f0, 0, {0x29,0xc0,0x4b,0x72,0x02,0x1c,0x00,0xb7,0x01,0x21,0xc0,0x0b,0xf0,0x12,0x2a,0x04 } }, +{ 16, 0x8700, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x90,0x34,0x00,0x21,0x80 } }, +{ 16, 0x8710, 0, {0x09,0x70,0x00,0x5c,0x0c,0xb7,0x00,0x2d,0xc4,0x08,0x50,0x1a,0x0c,0x00,0x97,0x00 } }, +{ 16, 0x8720, 0, {0x21,0xc0,0x4b,0x30,0x02,0x1c,0x00,0xb7,0x00,0x25,0xc0,0x0b,0x70,0x02,0x40,0x00 } }, +{ 16, 0x8730, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x00,0xb0,0x00,0x60,0x00 } }, +{ 16, 0x8740, 0, {0x08,0x3e,0x02,0xcc,0x00,0xb3,0x02,0x0c,0xe0,0x2b,0xb0,0x02,0x0c,0x00,0x93,0x00 } }, +{ 16, 0x8750, 0, {0x28,0xc0,0x0b,0xb0,0x02,0x2c,0x10,0xb3,0x00,0x20,0xd6,0x03,0x30,0x02,0x08,0x04 } }, +{ 16, 0x8760, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xfb,0x00,0xb2,0x00 } }, +{ 16, 0x8770, 0, {0x05,0xbe,0x03,0x7c,0x00,0xff,0x00,0x3e,0x20,0x0c,0xb0,0x03,0x3c,0x00,0xd9,0x80 } }, +{ 16, 0x8780, 0, {0x33,0xc0,0x8b,0xf0,0x03,0x3c,0x00,0xff,0x00,0x37,0xe0,0x0f,0xf0,0x03,0x6a,0x04 } }, +{ 16, 0x8790, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xfb,0x04,0x3e,0x00 } }, +{ 16, 0x87a0, 0, {0x0f,0xa4,0x23,0xcc,0x00,0xfb,0x00,0x3e,0x81,0x08,0x90,0x03,0xec,0x00,0xe9,0x14 } }, +{ 16, 0x87b0, 0, {0x3e,0xc0,0x0f,0xb0,0x03,0xec,0x10,0xfb,0x00,0x3e,0xc0,0x0f,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0x87c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xff,0x00,0x37,0x80 } }, +{ 16, 0x87d0, 0, {0x0f,0xfa,0x03,0xfc,0x00,0xcf,0x00,0x3f,0x90,0x06,0xdc,0x23,0x3c,0x00,0xfd,0x10 } }, +{ 16, 0x87e0, 0, {0x33,0xc0,0x0f,0xf0,0x0b,0x3c,0x00,0x43,0x00,0x33,0xc0,0x0f,0xf0,0x03,0xc0,0x44 } }, +{ 16, 0x87f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x00,0x6c,0x09,0xbb,0x19,0x22,0x32 } }, +{ 16, 0x8800, 0, {0x0b,0xbe,0x03,0x6c,0x00,0x8b,0x00,0x2c,0x90,0x0d,0xb8,0x02,0xac,0x00,0xb1,0x00 } }, +{ 16, 0x8810, 0, {0xf2,0xc0,0x0b,0xb0,0x12,0xac,0x00,0x8b,0x00,0x22,0xc0,0x0b,0xb0,0x03,0xa0,0x40 } }, +{ 16, 0x8820, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x10,0xb3,0x00,0x26,0x20 } }, +{ 16, 0x8830, 0, {0x0b,0x90,0x12,0xec,0x01,0x8b,0x00,0x2a,0xc2,0x0a,0x90,0x02,0x2c,0x00,0xbb,0x00 } }, +{ 16, 0x8840, 0, {0xa2,0xc0,0x0b,0xb0,0x02,0x2c,0x00,0xab,0x00,0x2a,0xc0,0x0b,0xb0,0x02,0xe0,0x00 } }, +{ 16, 0x8850, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x01,0xb3,0x00,0x20,0x00 } }, +{ 16, 0x8860, 0, {0x0b,0x00,0x02,0x8c,0x00,0x83,0x00,0x2e,0xc0,0x0b,0x34,0x02,0x8c,0x00,0xbb,0x00 } }, +{ 16, 0x8870, 0, {0x20,0xc0,0x0b,0x30,0x02,0x0d,0x00,0xa3,0x00,0xa0,0xc0,0x0b,0x30,0x02,0x82,0x01 } }, +{ 16, 0x8880, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xbb,0x04,0x36,0x80 } }, +{ 16, 0x8890, 0, {0x0f,0xb2,0x02,0xfc,0x02,0xcf,0x02,0x38,0xc0,0x0e,0xf0,0x03,0x3c,0x00,0xfb,0x00 } }, +{ 16, 0x88a0, 0, {0x23,0xc0,0x0f,0xf0,0x03,0x3d,0x02,0xef,0x00,0x33,0xc0,0x0f,0xf0,0x43,0xc0,0x03 } }, +{ 16, 0x88b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xff,0x00,0x3f,0x00 } }, +{ 16, 0x88c0, 0, {0x0f,0xf4,0x23,0x7c,0x00,0xff,0x00,0x3f,0xc0,0x0d,0xd0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0x88d0, 0, {0x3b,0xc0,0x0f,0xf0,0x03,0xfc,0x88,0xdf,0x00,0x3f,0xc0,0x0f,0xf0,0x03,0xa8,0x06 } }, +{ 16, 0x88e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf0,0x50,0xce,0x12,0x33,0xd0 } }, +{ 16, 0x88f0, 0, {0x4c,0x86,0x83,0x30,0x80,0x5f,0x68,0x33,0xc4,0x0f,0xf3,0x83,0x3c,0xc0,0xcc,0x38 } }, +{ 16, 0x8900, 0, {0xb3,0x08,0x0c,0xc6,0x03,0xf1,0xa0,0xff,0x00,0x33,0x24,0x0c,0xc2,0x03,0xf0,0x00 } }, +{ 16, 0x8910, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xec,0x80,0xd2,0x20,0x23,0xd8 } }, +{ 16, 0x8920, 0, {0x0d,0x96,0x02,0x88,0x60,0xaf,0x40,0x23,0xdc,0x0b,0xf6,0x02,0x3c,0xc2,0x88,0x60 } }, +{ 16, 0x8930, 0, {0x22,0x52,0x08,0x91,0x22,0xe1,0x00,0xb7,0x24,0xa2,0x48,0x8a,0x84,0x82,0x60,0x04 } }, +{ 16, 0x8940, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc4,0x00,0x81,0x00,0xe0,0xc4 } }, +{ 16, 0x8950, 0, {0x0a,0x00,0x02,0x04,0x80,0xa3,0x20,0xa8,0xc0,0x1b,0x30,0x0a,0x0c,0x00,0xa0,0x00 } }, +{ 16, 0x8960, 0, {0x28,0x0c,0x09,0x02,0x02,0xc4,0x80,0xb3,0x1c,0x22,0x08,0x19,0x03,0x02,0xe2,0x11 } }, +{ 16, 0x8970, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa4,0x00,0x99,0x80,0x62,0xc0 } }, +{ 16, 0x8980, 0, {0x0b,0xa0,0x32,0xa4,0x51,0xab,0x00,0x2a,0xc0,0x8b,0xb0,0x00,0x0c,0x00,0xa9,0xc0 } }, +{ 16, 0x8990, 0, {0x2a,0x21,0x08,0xb8,0x22,0xe2,0x00,0xbb,0x00,0x22,0x84,0x1b,0xa8,0x42,0x70,0x04 } }, +{ 16, 0x89a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xe2,0x00,0xcb,0xc9,0x32,0xc0 } }, +{ 16, 0x89b0, 0, {0x0e,0x8b,0x13,0x22,0x10,0xdb,0x01,0x32,0xc0,0x0f,0xb0,0x0b,0x2c,0x00,0x68,0x81 } }, +{ 16, 0x89c0, 0, {0x3a,0x22,0x2c,0x88,0x23,0xe3,0x00,0xfb,0x00,0x30,0x30,0x8d,0x9c,0x83,0xd0,0x04 } }, +{ 16, 0x89d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xba,0x40,0xf7,0x04,0x3e,0xc2 } }, +{ 16, 0x89e0, 0, {0x0d,0xd8,0x23,0xd8,0x00,0x7b,0x00,0x37,0xc0,0x0f,0x70,0x33,0xfc,0x10,0xd2,0x00 } }, +{ 16, 0x89f0, 0, {0x35,0xc0,0x8f,0xc0,0x03,0xf4,0x00,0xf7,0x02,0x3f,0xe0,0x0e,0x80,0x03,0xf8,0x00 } }, +{ 16, 0x8a00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0x81,0x20,0xc8,0x08,0x30,0xc0 } }, +{ 16, 0x8a10, 0, {0x0c,0x00,0x83,0x24,0x40,0xc3,0x89,0x3a,0xc0,0x0e,0xb0,0x0b,0x2c,0x08,0xc9,0x48 } }, +{ 16, 0x8a20, 0, {0x72,0x54,0x0f,0x91,0x03,0xed,0x02,0xeb,0x8a,0x3a,0x62,0x8c,0x80,0x0b,0x10,0x04 } }, +{ 16, 0x8a30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2b,0x04,0x88,0x40,0xa3,0xc2 } }, +{ 16, 0x8a40, 0, {0x02,0xae,0x12,0x27,0x42,0x8f,0x44,0x23,0xc2,0x0b,0xf4,0x02,0x3d,0x00,0x0a,0x40 } }, +{ 16, 0x8a50, 0, {0x22,0xe0,0x0b,0xb5,0x02,0xec,0x20,0x8f,0x44,0xa2,0x40,0x8d,0xbd,0x23,0x32,0x00 } }, +{ 16, 0x8a60, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x49,0x40,0x83,0x81,0x24,0xc1 } }, +{ 16, 0x8a70, 0, {0x08,0x28,0x02,0x01,0x00,0x93,0x00,0xa0,0xe8,0x0a,0x30,0x82,0x8f,0x60,0xb3,0x90 } }, +{ 16, 0x8a80, 0, {0x60,0xb8,0x0b,0x28,0x12,0x4a,0x00,0x93,0x00,0x20,0x90,0x09,0x20,0x02,0x78,0x00 } }, +{ 16, 0x8a90, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x02,0x87,0xa8,0x25,0xe0 } }, +{ 16, 0x8aa0, 0, {0x0a,0x7b,0x02,0x1a,0x04,0x87,0x80,0x21,0xe4,0x0b,0x78,0x82,0x8e,0x02,0x96,0x91 } }, +{ 16, 0x8ab0, 0, {0x21,0x21,0x0b,0x69,0x40,0xdb,0x40,0x97,0x92,0x23,0xa0,0x89,0x58,0x82,0x08,0x00 } }, +{ 16, 0x8ac0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x25,0x82,0xc3,0x00,0x34,0xc0 } }, +{ 16, 0x8ad0, 0, {0x0c,0x9b,0x43,0x08,0xd0,0xd3,0x20,0x38,0xc0,0x0e,0xb0,0x03,0x8c,0x00,0xb3,0x00 } }, +{ 16, 0x8ae0, 0, {0x20,0x80,0x07,0x10,0x03,0xe0,0x00,0xd3,0x10,0x38,0x18,0x0d,0x30,0x03,0x52,0x02 } }, +{ 16, 0x8af0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xb4,0x00,0x7f,0x20,0x1b,0xd0 } }, +{ 16, 0x8b00, 0, {0x0f,0xf1,0x03,0xf8,0x40,0xef,0x00,0x3f,0xc0,0x0f,0xb4,0x03,0x7c,0x20,0xcf,0x04 } }, +{ 16, 0x8b10, 0, {0xbf,0x40,0x0f,0xf0,0x03,0xe4,0x10,0xef,0x18,0x3d,0xc0,0x0f,0xe0,0x03,0xd0,0x06 } }, +{ 16, 0x8b20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe8,0x00,0xe3,0x00,0xb2,0xc4 } }, +{ 16, 0x8b30, 0, {0x0c,0xa0,0x03,0x24,0x00,0xdb,0x68,0x32,0xc8,0x0c,0xb4,0x03,0xec,0x80,0xc8,0x80 } }, +{ 16, 0x8b40, 0, {0xb6,0xe0,0x0c,0xa0,0x03,0x2e,0x00,0xcb,0xe0,0xb2,0x60,0x0c,0xb8,0x0b,0x2a,0x00 } }, +{ 16, 0x8b50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x02,0x87,0x00,0xa1,0xc8 } }, +{ 16, 0x8b60, 0, {0x08,0x70,0x02,0x1c,0x08,0x97,0x02,0x21,0xd4,0x08,0x74,0x02,0xdc,0xc0,0x07,0x00 } }, +{ 16, 0x8b70, 0, {0x21,0xc0,0x88,0x70,0x02,0x18,0x00,0x83,0x08,0x21,0xc0,0x08,0x50,0x02,0x12,0x04 } }, +{ 16, 0x8b80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x20,0xad,0x80,0x29,0xe0 } }, +{ 16, 0x8b90, 0, {0x08,0x58,0x02,0x1e,0x00,0x97,0xb0,0x21,0xe8,0x08,0x78,0x02,0xde,0x10,0x15,0x80 } }, +{ 16, 0x8ba0, 0, {0x21,0xa1,0x08,0x48,0x02,0x5e,0x00,0x87,0xa4,0x65,0xa0,0x08,0x78,0x02,0x30,0x00 } }, +{ 16, 0x8bb0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcf,0x10,0x81,0x70,0xa8,0xc0 } }, +{ 16, 0x8bc0, 0, {0x38,0x30,0x0a,0x0d,0x00,0x93,0x00,0xa0,0xc1,0x28,0x30,0x02,0xcc,0x02,0x83,0x88 } }, +{ 16, 0x8bd0, 0, {0x20,0xe0,0x38,0x34,0x0a,0x4d,0x72,0x83,0x00,0x24,0xe8,0x28,0x34,0x82,0x12,0x04 } }, +{ 16, 0x8be0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xba,0x40,0xee,0xc0,0xba,0x80 } }, +{ 16, 0x8bf0, 0, {0x0c,0xe0,0x03,0x39,0x10,0xda,0x00,0x32,0x80,0x0c,0xa0,0x03,0xe8,0x00,0xde,0xc8 } }, +{ 16, 0x8c00, 0, {0x33,0xa0,0x0c,0xe0,0x03,0x7b,0x00,0xca,0x00,0x37,0xb1,0x0c,0xe4,0x23,0x3a,0x04 } }, +{ 16, 0x8c10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xc1,0x00,0xf8,0x00,0x36,0x00 } }, +{ 16, 0x8c20, 0, {0x0f,0x80,0x03,0xc0,0x20,0x38,0x00,0x3e,0x00,0x0f,0x00,0x03,0xe0,0x00,0xf8,0x02 } }, +{ 16, 0x8c30, 0, {0x3a,0x24,0x0f,0x80,0x83,0xa0,0x01,0xf8,0x04,0x3a,0x04,0x0d,0x80,0x13,0xd2,0x00 } }, +{ 16, 0x8c40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x44,0xc1,0x00,0x32,0x40 } }, +{ 16, 0x8c50, 0, {0x0c,0x90,0x32,0x24,0x0c,0xc1,0x06,0x38,0x40,0x0d,0x90,0x09,0x04,0x00,0xd9,0x00 } }, +{ 16, 0x8c60, 0, {0x3e,0x40,0x0f,0x18,0x03,0x24,0x00,0xf9,0x01,0x3e,0x40,0x0f,0x90,0x03,0xc2,0x04 } }, +{ 16, 0x8c70, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x06,0x89,0x00,0x2a,0x50 } }, +{ 16, 0x8c80, 0, {0x08,0x94,0x0a,0x24,0x00,0x89,0x42,0x22,0x50,0x0a,0x90,0x12,0x25,0x00,0x89,0x00 } }, +{ 16, 0x8c90, 0, {0x2e,0x50,0x0b,0x9c,0x0a,0x25,0x10,0xb9,0x00,0x2e,0x50,0x0b,0x90,0x02,0xe0,0x00 } }, +{ 16, 0x8ca0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x20,0x89,0x00,0x20,0x42 } }, +{ 16, 0x8cb0, 0, {0x08,0x10,0xc2,0xac,0x10,0x89,0x08,0x2a,0x42,0x09,0x90,0x02,0x24,0x20,0x99,0x00 } }, +{ 16, 0x8cc0, 0, {0x2e,0x42,0x0a,0xb1,0x82,0x2c,0x20,0xb9,0x00,0x6e,0x42,0x0b,0x90,0x02,0xc6,0x00 } }, +{ 16, 0x8cd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0x83,0x00,0x28,0x48 } }, +{ 16, 0x8ce0, 0, {0x08,0x12,0x62,0x8c,0x80,0x81,0x00,0x20,0x40,0x02,0x10,0x02,0x84,0x80,0x81,0x20 } }, +{ 16, 0x8cf0, 0, {0x2c,0x49,0x0b,0x12,0x06,0x04,0x84,0xb3,0x02,0x6c,0x40,0x0b,0x12,0x02,0xc2,0x01 } }, +{ 16, 0x8d00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x41,0xe0,0xc8,0x78,0x30,0x14 } }, +{ 16, 0x8d10, 0, {0x4c,0x05,0x13,0xa1,0x42,0xc0,0x78,0x38,0x1e,0x0d,0x87,0x83,0x01,0x40,0xd0,0x50 } }, +{ 16, 0x8d20, 0, {0x3c,0x14,0x0e,0x05,0x03,0x01,0x40,0xf8,0x78,0x3c,0x14,0x0f,0x05,0x03,0xee,0x03 } }, +{ 16, 0x8d30, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xfc,0x00,0xff,0x00,0x0e,0x44 } }, +{ 16, 0x8d40, 0, {0x2f,0xf1,0x03,0x74,0x40,0xf9,0x00,0x3e,0x40,0x0d,0x90,0x03,0x64,0x40,0xfd,0x10 } }, +{ 16, 0x8d50, 0, {0x3f,0x44,0x0f,0xd1,0x01,0xf4,0x40,0xf9,0x01,0x3f,0xc0,0x0f,0xd1,0x03,0xe6,0x06 } }, +{ 16, 0x8d60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xe6,0x22,0xe9,0x88,0xb2,0x40 } }, +{ 16, 0x8d70, 0, {0x0f,0x90,0x03,0x24,0x16,0xc9,0x8c,0x36,0x7b,0x8f,0x9c,0x83,0xa7,0x90,0xc9,0x00 } }, +{ 16, 0x8d80, 0, {0x3e,0x50,0x04,0x94,0x13,0x24,0x50,0xc9,0xe0,0x3e,0x50,0x0f,0x90,0x03,0x06,0x00 } }, +{ 16, 0x8d90, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe2,0x80,0x88,0xa0,0x22,0x28 } }, +{ 16, 0x8da0, 0, {0x0b,0x8a,0x02,0x2a,0x80,0x88,0xa4,0x22,0x30,0x08,0x8e,0x0a,0x22,0x02,0x88,0xa0 } }, +{ 16, 0x8db0, 0, {0x2e,0x28,0x88,0xaa,0x12,0x22,0x90,0x88,0xf4,0x2e,0x20,0x0b,0xc8,0x02,0x0e,0x04 } }, +{ 16, 0x8dc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xd4,0x20,0xa5,0x08,0x21,0x42 } }, +{ 16, 0x8dd0, 0, {0x0b,0x50,0x82,0x14,0x31,0x85,0x08,0x25,0x40,0x0a,0x50,0x22,0x94,0x40,0x85,0x08 } }, +{ 16, 0x8de0, 0, {0x6d,0x40,0x08,0x50,0x02,0x54,0x02,0x95,0x00,0x2d,0x48,0x0b,0x50,0x82,0x42,0x01 } }, +{ 16, 0x8df0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0x84,0x00,0x8d,0x10,0x23,0x40 } }, +{ 16, 0x8e00, 0, {0x0b,0xd0,0x00,0x34,0x01,0x8d,0x00,0x23,0x41,0x58,0xd0,0x02,0x34,0x00,0x8d,0x08 } }, +{ 16, 0x8e10, 0, {0x2f,0x50,0x08,0xd2,0x02,0x74,0x80,0x9d,0x00,0x2f,0x48,0x0b,0xdc,0x02,0x46,0x04 } }, +{ 16, 0x8e20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe7,0x40,0xe9,0xc0,0x32,0x40 } }, +{ 16, 0x8e30, 0, {0x0f,0x90,0x09,0x26,0x00,0xc9,0x04,0x36,0x40,0x1f,0x90,0x23,0xa4,0x08,0xc9,0x40 } }, +{ 16, 0x8e40, 0, {0x3e,0x40,0x0c,0x94,0x0b,0x64,0x20,0xd9,0x02,0x3e,0x41,0x0f,0x94,0x03,0x68,0x04 } }, +{ 16, 0x8e50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x80,0x3e,0x40 } }, +{ 16, 0x8e60, 0, {0x0f,0x14,0x03,0xc5,0x08,0xf9,0x00,0x3e,0x40,0x1f,0x90,0x23,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0x8e70, 0, {0x3c,0x40,0xaf,0x98,0x03,0x86,0x00,0xe9,0x00,0x3e,0x40,0x0f,0x10,0x0b,0x8a,0x00 } }, +{ 16, 0x8e80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xb0,0x00,0xdc,0x40,0xb3,0x00 } }, +{ 16, 0x8e90, 0, {0x0f,0xc0,0x03,0x31,0x02,0xc4,0x04,0xb1,0x00,0x3c,0x40,0x03,0x10,0x00,0xfc,0x40 } }, +{ 16, 0x8ea0, 0, {0x33,0x00,0x0c,0xc4,0x03,0xb1,0x00,0xcc,0x00,0xb3,0x00,0x0c,0xc4,0x03,0xca,0x04 } }, +{ 16, 0x8eb0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x8a,0x80,0x22,0xa0 } }, +{ 16, 0x8ec0, 0, {0x0b,0xa0,0x02,0x2a,0x00,0x8a,0x84,0x22,0xa1,0x08,0xa0,0x02,0x28,0x08,0xba,0x01 } }, +{ 16, 0x8ed0, 0, {0x22,0x80,0x08,0xa0,0x2b,0x28,0x00,0x8a,0x80,0x2a,0x80,0x08,0xe0,0x02,0xca,0x00 } }, +{ 16, 0x8ee0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x02,0x9b,0x81,0x20,0xe0 } }, +{ 16, 0x8ef0, 0, {0x8b,0x38,0x06,0xce,0x00,0x93,0x80,0x20,0xc0,0x08,0x38,0x02,0x0c,0x00,0xb3,0x80 } }, +{ 16, 0x8f00, 0, {0x6c,0xe0,0x0a,0xb0,0x02,0x4c,0x00,0x93,0x00,0x20,0xe0,0x08,0x30,0x02,0xca,0x00 } }, +{ 16, 0x8f10, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x10,0x04,0x80,0x08,0x21,0x02 } }, +{ 16, 0x8f20, 0, {0x4b,0x44,0x06,0xd0,0x20,0x90,0x08,0x21,0x02,0x80,0x44,0x02,0x10,0x00,0xb4,0xc0 } }, +{ 16, 0x8f30, 0, {0x2d,0x10,0x48,0x40,0x02,0x00,0x00,0x94,0x89,0x29,0x30,0x08,0x40,0x02,0xe8,0x00 } }, +{ 16, 0x8f40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x32,0x00,0xd6,0x80,0x31,0xa0 } }, +{ 16, 0x8f50, 0, {0x0f,0xe8,0x0b,0xca,0x00,0xd6,0x80,0x23,0xa0,0x04,0xf8,0x0b,0x1a,0x00,0xff,0x80 } }, +{ 16, 0x8f60, 0, {0xbf,0xa0,0x2e,0xc8,0x13,0xda,0x02,0x5e,0x80,0x73,0xa0,0x2c,0x78,0x03,0xea,0x02 } }, +{ 16, 0x8f70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0x8f80, 0, {0x0f,0x90,0x03,0x24,0x00,0xe9,0x00,0x3e,0x40,0x0e,0x80,0x03,0xe4,0x00,0xf8,0x00 } }, +{ 16, 0x8f90, 0, {0x32,0x40,0x0f,0xb0,0x03,0xe4,0x01,0xe9,0x04,0x36,0x40,0x0f,0x80,0x03,0xc2,0x06 } }, +{ 16, 0x8fa0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xcd,0x80,0x33,0x60 } }, +{ 16, 0x8fb0, 0, {0x0c,0xd8,0x43,0x36,0x00,0xcd,0x80,0x33,0x60,0x0c,0xd9,0x23,0xbe,0x00,0x4d,0x80 } }, +{ 16, 0x8fc0, 0, {0x33,0x60,0x08,0xf8,0x0b,0x3e,0x00,0xfd,0x84,0x3f,0x60,0x0f,0xf9,0x03,0xc0,0x00 } }, +{ 16, 0x8fd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x90,0x04,0xde,0x00,0x23,0x80 } }, +{ 16, 0x8fe0, 0, {0x08,0x60,0x02,0xb8,0x20,0x8e,0x04,0x23,0x80,0x08,0x68,0x02,0x10,0x00,0x8e,0x20 } }, +{ 16, 0x8ff0, 0, {0x23,0x82,0x08,0x40,0x02,0x12,0x00,0xf6,0x00,0x2d,0x80,0x0b,0x41,0xa0,0xea,0x04 } }, +{ 16, 0x9000, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x84,0x00,0x21,0x00 } }, +{ 16, 0x9010, 0, {0x08,0x41,0x02,0x50,0x40,0x94,0x00,0x21,0x00,0x0a,0x52,0x02,0xd8,0x00,0x85,0x02 } }, +{ 16, 0x9020, 0, {0x25,0x04,0x08,0x40,0x22,0x18,0x08,0xb4,0x00,0x2d,0x10,0x0b,0x78,0x40,0xc0,0x00 } }, +{ 16, 0x9030, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xee,0x22,0x93,0x00,0x20,0xc0 } }, +{ 16, 0x9040, 0, {0x08,0x38,0x02,0xec,0x00,0x93,0x00,0x20,0xc1,0x2a,0x20,0x02,0x64,0x02,0x82,0x10 } }, +{ 16, 0x9050, 0, {0x24,0xf0,0x0a,0x3c,0x42,0x24,0x28,0xb3,0x00,0x2c,0xe0,0x0b,0x88,0x82,0xc8,0x04 } }, +{ 16, 0x9060, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xad,0x00,0xcb,0x00,0xb2,0xc0 } }, +{ 16, 0x9070, 0, {0xac,0xbe,0x03,0x6e,0x02,0xdb,0x00,0xb2,0xc0,0x1e,0xa0,0x03,0xe4,0x00,0xca,0x11 } }, +{ 16, 0x9080, 0, {0xb6,0xd0,0xac,0xbc,0x03,0x24,0x00,0xfb,0x00,0x3e,0xc0,0xcf,0x84,0x03,0xea,0x04 } }, +{ 16, 0x9090, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe0,0x40,0xf8,0x00,0x3c,0x00 } }, +{ 16, 0x90a0, 0, {0x2f,0x82,0x03,0xa0,0x00,0xe8,0x00,0x3e,0x00,0x1d,0x90,0x13,0xa8,0x00,0xf9,0x00 } }, +{ 16, 0x90b0, 0, {0x3a,0x00,0x81,0x83,0x43,0xe8,0x00,0xe8,0x03,0x3e,0x04,0x0f,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0x90c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xe0,0x00,0xd6,0x00,0x37,0x80 } }, +{ 16, 0x90d0, 0, {0x0c,0xa0,0x03,0xf8,0x00,0xce,0x00,0x33,0x80,0x0d,0xa0,0x13,0x20,0x08,0xce,0x00 } }, +{ 16, 0x90e0, 0, {0x33,0x82,0x0c,0x40,0x73,0x30,0x18,0xce,0x00,0x1f,0x80,0x4f,0xc1,0x43,0x00,0x44 } }, +{ 16, 0x90f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x7c,0x00,0x8d,0x00,0x23,0x40 } }, +{ 16, 0x9100, 0, {0x0a,0xd0,0x02,0xf4,0x00,0x8d,0x00,0x23,0x40,0x08,0xd4,0x80,0x3e,0x42,0x8d,0x40 } }, +{ 16, 0x9110, 0, {0x23,0x40,0x08,0xf0,0x02,0x3e,0x40,0x8d,0x00,0x0f,0x40,0x0b,0xf4,0x02,0x20,0x40 } }, +{ 16, 0x9120, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x99,0x00,0xa6,0x40 } }, +{ 16, 0x9130, 0, {0x08,0x90,0x06,0xe4,0x00,0x91,0x00,0x20,0x40,0x88,0x00,0x02,0x24,0x08,0x80,0x40 } }, +{ 16, 0x9140, 0, {0x20,0x40,0x0a,0xb0,0x02,0x24,0x00,0x89,0x00,0x0e,0x40,0x0b,0x84,0x02,0x20,0x00 } }, +{ 16, 0x9150, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x82,0x00,0x20,0x80 } }, +{ 16, 0x9160, 0, {0x0a,0x21,0x06,0xc8,0x01,0x82,0x00,0x20,0x80,0x08,0x32,0x82,0x08,0x08,0x83,0x00 } }, +{ 16, 0x9170, 0, {0x60,0x80,0x0a,0x00,0x12,0x08,0x80,0x82,0x00,0x2c,0x80,0x0b,0x30,0x0a,0x02,0x01 } }, +{ 16, 0x9180, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x60,0x00,0xd8,0x00,0x36,0x00 } }, +{ 16, 0x9190, 0, {0x0c,0x84,0x23,0xe0,0x00,0xc8,0x00,0x32,0x00,0x0d,0x82,0x0b,0x20,0x02,0xc8,0x00 } }, +{ 16, 0x91a0, 0, {0x32,0x00,0x0e,0x00,0x03,0x20,0x02,0xc8,0x00,0x3e,0x00,0x0f,0x80,0x03,0x00,0x03 } }, +{ 16, 0x91b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xbf,0x00,0x3f,0xc0 } }, +{ 16, 0x91c0, 0, {0x0f,0xf0,0x03,0xfc,0x00,0xff,0x00,0xbf,0xc0,0x8f,0xb0,0x03,0xfc,0x08,0xff,0x02 } }, +{ 16, 0x91d0, 0, {0x3f,0xc0,0x0d,0xf0,0x03,0xed,0x00,0xff,0x02,0x3f,0xc0,0x0f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0x91e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0xf0,0x8c,0xff,0x00,0x3d,0x60 } }, +{ 16, 0x91f0, 0, {0x2c,0xb2,0x83,0x7c,0x90,0xdf,0x38,0x31,0xe0,0x0f,0xf8,0x03,0x3c,0x00,0xff,0x20 } }, +{ 16, 0x9200, 0, {0x3f,0xc4,0x0e,0xf4,0x03,0x7c,0x00,0xf4,0x80,0x33,0x00,0x0d,0xf8,0x03,0xf0,0x00 } }, +{ 16, 0x9210, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe1,0x20,0xbb,0x62,0x2e,0x42 } }, +{ 16, 0x9220, 0, {0x28,0xf4,0x42,0x3e,0x40,0x8f,0x44,0x22,0xe0,0x0b,0xb0,0x83,0x7f,0x44,0xbf,0xc1 } }, +{ 16, 0x9230, 0, {0x2d,0xdc,0x2a,0xf6,0x02,0x3f,0x45,0xb8,0x80,0x22,0x61,0x88,0xb8,0x02,0xe0,0x04 } }, +{ 16, 0x9240, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc5,0x80,0xb2,0x18,0x2e,0xc8 } }, +{ 16, 0x9250, 0, {0x29,0x30,0x32,0x0c,0x08,0xb3,0x20,0x20,0xc0,0x4b,0x92,0x02,0x0c,0x00,0xb3,0x40 } }, +{ 16, 0x9260, 0, {0x2c,0xc0,0x89,0x34,0x12,0x4c,0x00,0xb0,0x00,0x24,0xc1,0x49,0x30,0x02,0xe2,0x01 } }, +{ 16, 0x9270, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x11,0xa4,0x00,0xba,0x0c,0x2e,0xe0 } }, +{ 16, 0x9280, 0, {0xa9,0xb0,0x06,0x2c,0x00,0x8b,0x00,0xa2,0xc0,0x0b,0x90,0x00,0x6c,0x00,0xbb,0x00 } }, +{ 16, 0x9290, 0, {0x2e,0xc0,0x0b,0x30,0x02,0x6c,0x00,0xba,0x80,0x26,0xf0,0x08,0xb0,0x02,0xf0,0x04 } }, +{ 16, 0x92a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x11,0xee,0x00,0xfb,0xc4,0x3e,0x78 } }, +{ 16, 0x92b0, 0, {0x2d,0xb0,0x03,0x6c,0x08,0xfb,0x00,0x32,0xc0,0x8b,0x24,0x83,0x2c,0x00,0xfb,0x00 } }, +{ 16, 0x92c0, 0, {0x3e,0xc0,0x8f,0xb0,0x0b,0x6c,0x08,0xb2,0xe0,0x16,0x60,0x8d,0xb0,0x23,0xd0,0x04 } }, +{ 16, 0x92d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xbe,0x98,0xff,0x40,0x3f,0xc0 } }, +{ 16, 0x92e0, 0, {0x0e,0x70,0x03,0xdc,0x00,0xff,0x00,0x3f,0xc0,0x0f,0xe0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0x92f0, 0, {0x3f,0xc0,0x0e,0xf0,0x03,0xac,0x00,0xfe,0x00,0xb9,0xc0,0x0f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0x9300, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xad,0x00,0xfa,0x40,0x3e,0xd0 } }, +{ 16, 0x9310, 0, {0x0e,0xb2,0x03,0xec,0x00,0xc3,0x00,0x3e,0xc0,0x0c,0xa0,0x03,0x2c,0x01,0xfb,0x00 } }, +{ 16, 0x9320, 0, {0x3c,0xc0,0x0e,0xb8,0x03,0xec,0x00,0xda,0x00,0x3a,0xd0,0x4f,0xb0,0x23,0xd0,0x04 } }, +{ 16, 0x9330, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0xba,0x00,0x2c,0xc0 } }, +{ 16, 0x9340, 0, {0x08,0xf4,0x07,0xbc,0x14,0xdf,0x00,0x3e,0xc0,0x1a,0xa0,0x52,0xbc,0x00,0xbf,0x04 } }, +{ 16, 0x9350, 0, {0x3f,0xc0,0x8a,0xf0,0x03,0xbc,0x00,0xfa,0x00,0x22,0xc8,0x0f,0xb0,0x03,0xf2,0x00 } }, +{ 16, 0x9360, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x48,0x01,0xb1,0x00,0x6c,0xc2 } }, +{ 16, 0x9370, 0, {0x0a,0x30,0x42,0xcc,0x00,0x83,0x05,0x2c,0xc0,0x08,0x30,0x02,0x8c,0x01,0xb3,0x04 } }, +{ 16, 0x9380, 0, {0x2c,0xc0,0x0a,0x30,0x22,0x8c,0x00,0x80,0x80,0x28,0xc0,0x0b,0x30,0x22,0xf8,0x00 } }, +{ 16, 0x9390, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x08,0xb7,0x80,0x6f,0xe0 } }, +{ 16, 0x93a0, 0, {0x18,0x78,0x02,0x8e,0x40,0xb7,0x80,0x2d,0xe0,0x0a,0x78,0x02,0x9e,0x00,0xb7,0x80 } }, +{ 16, 0x93b0, 0, {0x29,0xe1,0x0a,0x78,0x02,0x9e,0x01,0xbc,0x80,0x29,0xe4,0x0b,0x78,0x02,0xc8,0x00 } }, +{ 16, 0x93c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x09,0x40,0xf1,0x20,0x3c,0xc4 } }, +{ 16, 0x93d0, 0, {0x0e,0x39,0x02,0xcc,0x00,0xc3,0x00,0x2c,0xc4,0x08,0x92,0x03,0x8c,0x88,0xb3,0x10 } }, +{ 16, 0x93e0, 0, {0x2c,0xc4,0x0e,0xb0,0x07,0x8c,0x00,0xc2,0x08,0x38,0xc0,0x0f,0x30,0x43,0xd2,0x02 } }, +{ 16, 0x93f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x10,0xfc,0x00,0x7f,0xc0 } }, +{ 16, 0x9400, 0, {0x0f,0xf0,0x83,0xfc,0x21,0xdf,0x08,0x3b,0xc0,0x8f,0x90,0x01,0xfc,0x21,0xff,0x0c } }, +{ 16, 0x9410, 0, {0x3f,0xc2,0x0f,0xf1,0x03,0xec,0x00,0xef,0x00,0x77,0xc0,0x1e,0xf0,0x03,0x90,0x06 } }, +{ 16, 0x9420, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe8,0x01,0xf9,0x00,0x32,0xc0 } }, +{ 16, 0x9430, 0, {0x0f,0xb2,0x03,0xee,0x90,0xdb,0xe1,0x3a,0xc0,0x4d,0x38,0x13,0x2d,0x30,0xfb,0x00 } }, +{ 16, 0x9440, 0, {0x3e,0xe0,0x4f,0xba,0x43,0x2c,0x40,0xfa,0x00,0x3f,0xc0,0x8c,0xb0,0x03,0xea,0x00 } }, +{ 16, 0x9450, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0xb1,0x00,0x21,0xc0 } }, +{ 16, 0x9460, 0, {0x0b,0x71,0x02,0xcc,0x20,0xa7,0x28,0x21,0xc0,0x0b,0x70,0x13,0x5c,0x08,0xb7,0x10 } }, +{ 16, 0x9470, 0, {0x2d,0xc4,0x4b,0x34,0x83,0x1c,0xc1,0xb7,0x02,0x2d,0xc0,0x1a,0x70,0x02,0xd2,0x04 } }, +{ 16, 0x9480, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9a,0x20,0xb4,0xc4,0x25,0xa2 } }, +{ 16, 0x9490, 0, {0x0b,0x78,0x06,0xde,0x00,0x83,0x80,0x29,0xe0,0x1b,0xf8,0x02,0x5e,0x80,0xa7,0xa0 } }, +{ 16, 0x94a0, 0, {0x2d,0xc8,0x0a,0x72,0x02,0x1e,0x00,0xa6,0x80,0x28,0xe0,0x08,0x78,0x02,0xf0,0x00 } }, +{ 16, 0x94b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xed,0x00,0xb3,0x40,0x24,0xc3 } }, +{ 16, 0x94c0, 0, {0x0b,0x30,0x42,0xcc,0x00,0xa3,0x00,0x20,0xc0,0x1b,0x34,0x02,0x4c,0x00,0xb3,0x00 } }, +{ 16, 0x94d0, 0, {0x2c,0xc0,0x4b,0x30,0x02,0x0c,0x00,0xb3,0x88,0x2c,0xd4,0x0a,0x30,0x02,0xd2,0x04 } }, +{ 16, 0x94e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xb8,0x00,0xfe,0x40,0xb7,0xa0 } }, +{ 16, 0x94f0, 0, {0x0f,0xa0,0x03,0xe8,0x00,0xda,0x00,0x3a,0x80,0x0f,0xe2,0x03,0x68,0x00,0xfa,0x00 } }, +{ 16, 0x9500, 0, {0x3e,0x80,0x0f,0xa0,0x0b,0x28,0x00,0xee,0xe0,0x3f,0xb0,0x04,0xa0,0x03,0xfa,0x04 } }, +{ 16, 0x9510, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x04,0xf0,0x08,0x3a,0x10 } }, +{ 16, 0x9520, 0, {0x0f,0x84,0x03,0xe0,0x10,0xf8,0x00,0x3e,0x00,0x4f,0x80,0x83,0xe0,0x00,0xf8,0x00 } }, +{ 16, 0x9530, 0, {0x3c,0x00,0x0f,0x80,0x03,0x80,0x00,0xf8,0x40,0x3e,0x09,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0x9540, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x20,0xe9,0x00,0x32,0x44 } }, +{ 16, 0x9550, 0, {0x0c,0x90,0x03,0x24,0x00,0xf9,0x00,0x3e,0x40,0x0f,0x90,0x13,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0x9560, 0, {0x1e,0x40,0x0c,0x10,0x03,0x24,0x00,0xc9,0xa0,0x3c,0x64,0x0c,0x90,0x03,0x82,0x04 } }, +{ 16, 0x9570, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x89,0x00,0x22,0x68 } }, +{ 16, 0x9580, 0, {0x08,0x13,0x02,0x24,0x08,0xf9,0x00,0x2e,0x48,0x1b,0x90,0x02,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0x9590, 0, {0x3e,0x40,0x0c,0x90,0x02,0x24,0x08,0xf9,0x40,0x2e,0x60,0x0a,0x90,0x06,0xe0,0x00 } }, +{ 16, 0x95a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0x24,0x00,0xa9,0x00,0x20,0x40 } }, +{ 16, 0x95b0, 0, {0x08,0x90,0x02,0x24,0x00,0xb9,0x01,0x2e,0x40,0x0b,0x90,0x02,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0x95c0, 0, {0x2e,0x40,0x08,0x92,0x22,0x24,0x00,0x89,0x00,0x2e,0x40,0x08,0x90,0x02,0xc6,0x00 } }, +{ 16, 0x95d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x80,0x81,0x21,0xe0,0x50 } }, +{ 16, 0x95e0, 0, {0x28,0x16,0x0a,0x04,0x80,0xa1,0x40,0x2c,0x40,0x4b,0x14,0x22,0xc4,0x00,0xb1,0x00 } }, +{ 16, 0x95f0, 0, {0x2c,0x50,0x09,0x14,0x02,0x04,0x04,0xb1,0x00,0x2c,0x40,0x0a,0x10,0x02,0xc2,0x01 } }, +{ 16, 0x9600, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xe8,0x50,0x32,0x00 } }, +{ 16, 0x9610, 0, {0x8c,0x80,0x02,0x20,0x00,0xb8,0x00,0x3e,0x00,0x0b,0x80,0x33,0xe0,0x10,0xf8,0x00 } }, +{ 16, 0x9620, 0, {0x3e,0x00,0x0c,0x80,0x03,0x20,0x08,0xca,0x00,0x3e,0x00,0x0c,0x80,0x03,0xae,0x03 } }, +{ 16, 0x9630, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xfc,0x40,0xfd,0x10,0x2f,0x41 } }, +{ 16, 0x9640, 0, {0x4f,0x91,0x03,0xe4,0x40,0xf9,0x40,0x3e,0x40,0x4f,0xd0,0x63,0xe5,0x00,0xf9,0x40 } }, +{ 16, 0x9650, 0, {0x3a,0x50,0x2e,0x94,0x03,0x65,0x00,0xed,0x00,0x3f,0x50,0x0f,0x90,0x03,0xe6,0x06 } }, +{ 16, 0x9660, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xe6,0x00,0xf9,0xe0,0x33,0x50 } }, +{ 16, 0x9670, 0, {0x0c,0xda,0x03,0xa6,0x00,0xd9,0x80,0x3f,0x40,0x0f,0x91,0x03,0xa6,0x00,0xf9,0x88 } }, +{ 16, 0x9680, 0, {0x3e,0x68,0x0c,0xde,0x03,0x66,0x00,0xed,0x00,0x3b,0x69,0x0c,0x90,0x03,0xc6,0x00 } }, +{ 16, 0x9690, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe1,0x08,0xb8,0xe0,0x20,0x20 } }, +{ 16, 0x96a0, 0, {0x18,0x8e,0x26,0xe1,0x00,0x80,0xa0,0x2e,0x00,0x4b,0x88,0x42,0xe1,0x50,0xb8,0x40 } }, +{ 16, 0x96b0, 0, {0x2e,0x2a,0x0d,0x0a,0x02,0x20,0x08,0xb8,0x00,0x2e,0x14,0x0d,0x80,0x02,0xce,0x04 } }, +{ 16, 0x96c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc5,0x00,0xb1,0x60,0x20,0x40 } }, +{ 16, 0x96d0, 0, {0x08,0x31,0xa2,0xc5,0x00,0x91,0x48,0x2c,0x40,0x1b,0x12,0x02,0x84,0x00,0xb1,0x00 } }, +{ 16, 0x96e0, 0, {0x2c,0x50,0x09,0x16,0x02,0x05,0x00,0xa3,0x04,0x28,0x40,0x08,0x10,0x02,0xc2,0x01 } }, +{ 16, 0x96f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xa4,0x00,0xb9,0x08,0x20,0x70 } }, +{ 16, 0x9700, 0, {0x28,0x90,0x02,0xe4,0x00,0x89,0x00,0x2e,0x40,0x0b,0x90,0x02,0xe4,0x08,0xb9,0x03 } }, +{ 16, 0x9710, 0, {0x2c,0x40,0x29,0x90,0x02,0x64,0x00,0xb9,0x00,0x2e,0x62,0x09,0x90,0x02,0xc6,0x04 } }, +{ 16, 0x9720, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x05,0xe5,0x00,0xf9,0xd0,0xb2,0x70 } }, +{ 16, 0x9730, 0, {0x08,0x90,0x03,0xe4,0x00,0xd9,0x04,0x3e,0x40,0x0f,0x90,0x03,0xa4,0x10,0xf9,0x02 } }, +{ 16, 0x9740, 0, {0x3e,0x40,0x0d,0x90,0x2b,0x64,0x00,0xe9,0x8d,0x3a,0x60,0x0c,0x90,0x03,0xe8,0x04 } }, +{ 16, 0x9750, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x80,0x3e,0x42 } }, +{ 16, 0x9760, 0, {0x0f,0x90,0x03,0xe4,0x00,0xf9,0x00,0x3e,0x40,0x0f,0x9a,0x03,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0x9770, 0, {0x3e,0x40,0x2f,0x10,0x03,0xa4,0x00,0xf9,0x22,0x3c,0x40,0x4f,0x90,0x03,0xca,0x00 } }, +{ 16, 0x9780, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0xa0,0x00,0xf0,0x40,0x32,0x00 } }, +{ 16, 0x9790, 0, {0x0c,0x80,0x03,0xc0,0x00,0xf8,0x00,0x32,0x20,0x1f,0x80,0x03,0xe0,0x00,0xc8,0x00 } }, +{ 16, 0x97a0, 0, {0x32,0x00,0x0c,0x80,0x02,0x20,0x00,0xc8,0xc0,0x3e,0x00,0x0c,0x80,0x03,0xca,0x04 } }, +{ 16, 0x97b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x15,0x28,0x10,0xba,0x00,0x23,0xa0 } }, +{ 16, 0x97c0, 0, {0x0a,0xe4,0x02,0xe8,0x00,0xba,0x00,0x2b,0xa1,0x0b,0xa0,0x02,0xe8,0x00,0xaa,0x00 } }, +{ 16, 0x97d0, 0, {0x2a,0x81,0x0a,0xa0,0x03,0xe8,0x08,0xde,0x00,0x2e,0x80,0x0a,0xa0,0x02,0xca,0x00 } }, +{ 16, 0x97e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0xb3,0x04,0xa0,0xb1 } }, +{ 16, 0x97f0, 0, {0x08,0x36,0x22,0xcc,0x00,0xb3,0x00,0x20,0xe4,0x0b,0x30,0x02,0xcc,0x00,0x83,0x00 } }, +{ 16, 0x9800, 0, {0x20,0xc0,0x08,0x18,0x02,0x0c,0x00,0x91,0x01,0x2c,0xc0,0x08,0x30,0x06,0xca,0x00 } }, +{ 16, 0x9810, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0xc8,0xb3,0x21,0x21,0xc2 } }, +{ 16, 0x9820, 0, {0x2a,0x70,0x02,0xdc,0x00,0xb7,0xa0,0x29,0xc0,0x0b,0x72,0x02,0xce,0x00,0xa7,0x81 } }, +{ 16, 0x9830, 0, {0x29,0xc0,0x4a,0x74,0x02,0xfe,0x00,0x97,0x01,0x2c,0xc0,0x0a,0x70,0x12,0xe8,0x00 } }, +{ 16, 0x9840, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x80,0xf7,0xc0,0x31,0xe0 } }, +{ 16, 0x9850, 0, {0x0c,0x48,0x03,0xde,0x11,0xf7,0x80,0x21,0xe0,0x0b,0x7a,0x03,0xde,0x00,0xc3,0x80 } }, +{ 16, 0x9860, 0, {0x33,0xd8,0x6c,0x78,0x03,0x3e,0x00,0xd6,0x80,0x3d,0xe0,0x0c,0x78,0x03,0xea,0x02 } }, +{ 16, 0x9870, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0d,0xac,0x08,0xfb,0x80,0x3e,0xc0 } }, +{ 16, 0x9880, 0, {0x0f,0xd0,0x03,0xec,0x04,0xfb,0x3c,0x3e,0xc0,0x0f,0xb6,0x07,0x6c,0x01,0xfb,0x00 } }, +{ 16, 0x9890, 0, {0x3e,0xd0,0x0f,0x94,0x07,0xec,0x01,0xea,0x00,0x3e,0xc0,0x0f,0xb0,0x03,0xc2,0x06 } }, +{ 16, 0x98a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xfe,0x00,0xcf,0xa4,0x3b,0x60 } }, +{ 16, 0x98b0, 0, {0x08,0xd9,0x03,0x7e,0x00,0xcf,0x80,0x3f,0x25,0x4f,0xfc,0x87,0xbe,0x00,0xcf,0x80 } }, +{ 16, 0x98c0, 0, {0x7f,0xfc,0x0c,0xfc,0x03,0x7c,0x00,0xf6,0x90,0x33,0xe0,0x0f,0xf8,0x03,0xc0,0x00 } }, +{ 16, 0x98d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x08,0x8f,0x28,0x21,0x40 } }, +{ 16, 0x98e0, 0, {0x08,0xd0,0x02,0x1c,0x40,0xa7,0x20,0x31,0x04,0x1b,0x78,0x02,0xdc,0x80,0xd7,0x00 } }, +{ 16, 0x98f0, 0, {0x2f,0xc4,0x1a,0xd0,0x02,0x1e,0x48,0xb6,0x00,0x61,0xc0,0x0b,0x70,0x06,0xea,0x04 } }, +{ 16, 0x9900, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x00,0x87,0x30,0x69,0x44 } }, +{ 16, 0x9910, 0, {0x08,0x50,0x22,0x0c,0x00,0x87,0x01,0x2d,0x44,0x8b,0x70,0x06,0x8c,0x10,0x87,0x00 } }, +{ 16, 0x9920, 0, {0x29,0xc9,0x08,0x50,0x02,0x1c,0x44,0xa6,0x00,0x61,0xc0,0x0b,0x70,0x02,0xc0,0x00 } }, +{ 16, 0x9930, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcd,0x00,0x83,0x88,0x60,0x40 } }, +{ 16, 0x9940, 0, {0x00,0x10,0x02,0x4c,0x00,0x2b,0x00,0x2c,0x41,0x1b,0x30,0x02,0xcc,0x00,0x93,0x00 } }, +{ 16, 0x9950, 0, {0x2c,0xc0,0x0a,0x30,0x42,0x0c,0x00,0xb2,0x40,0x20,0xf1,0x0b,0x30,0x02,0xc8,0x04 } }, +{ 16, 0x9960, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbd,0x41,0xcf,0xc0,0xba,0xf0 } }, +{ 16, 0x9970, 0, {0x28,0x90,0x1b,0x6c,0x08,0xcf,0x00,0x2c,0xc0,0x0f,0xf0,0x03,0xac,0x00,0x8b,0x00 } }, +{ 16, 0x9980, 0, {0x3f,0xc0,0x6c,0xb0,0x4b,0x2c,0x01,0xfb,0x40,0x22,0xc8,0x0f,0xb0,0x03,0xea,0x04 } }, +{ 16, 0x9990, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x04,0xfb,0x04,0x3f,0xd4 } }, +{ 16, 0x99a0, 0, {0x0f,0x10,0x03,0xac,0x00,0xfb,0x00,0x32,0xc0,0x5f,0xb0,0x03,0xec,0x00,0xfb,0x04 } }, +{ 16, 0x99b0, 0, {0x3e,0xc0,0x4f,0x10,0x13,0xec,0x00,0xfb,0x88,0x3e,0xc0,0x4f,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0x99c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xdc,0x00,0xc7,0x00,0x33,0x62 } }, +{ 16, 0x99d0, 0, {0x0c,0xc0,0x0b,0x3c,0x00,0xef,0x00,0x33,0xe0,0x1c,0xf0,0x13,0x3c,0x08,0xf7,0x00 } }, +{ 16, 0x99e0, 0, {0x31,0xc0,0x0e,0xd8,0x03,0xbc,0x00,0xfe,0x00,0x3d,0xc6,0x0c,0xf0,0x03,0xc0,0x44 } }, +{ 16, 0x99f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x00,0xcb,0x03,0x22,0x47 } }, +{ 16, 0x9a00, 0, {0x08,0x98,0x42,0x2c,0x00,0x9b,0x00,0x2a,0xc0,0x0a,0xb0,0x02,0x2c,0x00,0xbb,0x04 } }, +{ 16, 0x9a10, 0, {0x2a,0xc0,0x0a,0xb0,0x02,0xac,0x08,0xfa,0x00,0x2e,0x60,0x08,0xb0,0x02,0xe0,0x40 } }, +{ 16, 0x9a20, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x9b,0x00,0x20,0x40 } }, +{ 16, 0x9a30, 0, {0x08,0x98,0x02,0x2c,0x00,0xbb,0x00,0x22,0x88,0x08,0x30,0x02,0x2c,0x00,0xbb,0x00 } }, +{ 16, 0x9a40, 0, {0x22,0xc0,0x8a,0x92,0x02,0xac,0x00,0xaa,0x80,0x2e,0xc0,0x08,0xb0,0x06,0xe0,0x00 } }, +{ 16, 0x9a50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0x83,0x00,0xa0,0x40 } }, +{ 16, 0x9a60, 0, {0x08,0x10,0x02,0x0c,0x00,0xb3,0x00,0x28,0x80,0x0a,0x32,0x12,0x0c,0x00,0xb3,0x04 } }, +{ 16, 0x9a70, 0, {0x28,0xc0,0x0a,0x30,0x22,0x8c,0x20,0xb2,0x00,0x2c,0xc0,0x08,0x30,0x02,0xc2,0x01 } }, +{ 16, 0x9a80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x02,0xcb,0x00,0x30,0x40 } }, +{ 16, 0x9a90, 0, {0x1c,0x94,0x03,0x2c,0x00,0xef,0x00,0x32,0xc0,0x88,0xf0,0x8b,0x2c,0x00,0xfb,0x00 } }, +{ 16, 0x9aa0, 0, {0x33,0xc0,0xae,0xf0,0x03,0xac,0x80,0xea,0x01,0x3e,0xc0,0x2c,0xb0,0x03,0xc0,0x03 } }, +{ 16, 0x9ab0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xff,0x00,0x2f,0x40 } }, +{ 16, 0x9ac0, 0, {0x07,0xd2,0x83,0xfc,0x00,0xdf,0x04,0x3f,0xc0,0x0f,0xb0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0x9ad0, 0, {0x3f,0xc0,0x0f,0xd0,0x0b,0xec,0x00,0xee,0x00,0x3f,0x40,0x0f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0x9ae0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf5,0x00,0xcf,0x08,0x3f,0x48 } }, +{ 16, 0x9af0, 0, {0x0f,0xc3,0x93,0x70,0xd0,0xdc,0x30,0x3f,0xd8,0x0c,0xb2,0x03,0x3c,0xc0,0xff,0x40 } }, +{ 16, 0x9b00, 0, {0x33,0xc4,0x2c,0xf1,0x03,0x62,0x50,0xfc,0x34,0x33,0x00,0x0f,0x5c,0x03,0xf0,0x00 } }, +{ 16, 0x9b10, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xc4,0x80,0x8b,0x00,0x2f,0x5a } }, +{ 16, 0x9b20, 0, {0x0b,0xa6,0x12,0x21,0xc0,0x89,0x70,0x2f,0xdc,0x08,0xf2,0xc2,0x3d,0xd0,0xbf,0x40 } }, +{ 16, 0x9b30, 0, {0x37,0xdc,0x88,0xf5,0x0a,0x20,0x80,0xe8,0x10,0x2a,0x16,0x0b,0x90,0x02,0xe0,0x04 } }, +{ 16, 0x9b40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc0,0x00,0x83,0x08,0x2c,0x44 } }, +{ 16, 0x9b50, 0, {0x0b,0x02,0x02,0x0c,0x00,0x80,0x00,0x2c,0xc8,0x08,0x33,0x42,0x8c,0x90,0xb3,0x30 } }, +{ 16, 0x9b60, 0, {0x28,0xc8,0x4a,0x32,0x12,0x80,0x0c,0xb0,0xa0,0x28,0x28,0x0b,0x12,0x02,0xe2,0x01 } }, +{ 16, 0x9b70, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa2,0x00,0x8b,0x00,0x2e,0x48 } }, +{ 16, 0x9b80, 0, {0x0b,0xa0,0x22,0x20,0x20,0x88,0x80,0x2e,0xc0,0x28,0xb0,0x0a,0xac,0x00,0xbb,0x00 } }, +{ 16, 0x9b90, 0, {0x2e,0xc0,0x0a,0xb0,0x02,0xa0,0x00,0xab,0x82,0x2a,0xa0,0x0b,0xb2,0x02,0xf0,0x04 } }, +{ 16, 0x9ba0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xe7,0x00,0xcb,0x00,0x3e,0xc0 } }, +{ 16, 0x9bb0, 0, {0xcf,0x9c,0x0b,0x21,0x00,0xd8,0x88,0x3e,0xc0,0x0c,0xb0,0x03,0xac,0x00,0xfb,0x00 } }, +{ 16, 0x9bc0, 0, {0x3a,0xc0,0x0e,0xb0,0x43,0xe8,0x40,0xf8,0x80,0x3a,0x60,0x0f,0x98,0x03,0xd0,0x04 } }, +{ 16, 0x9bd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb4,0x00,0xff,0x00,0x0f,0xe0 } }, +{ 16, 0x9be0, 0, {0x07,0xa1,0x03,0xe8,0x02,0xfb,0x00,0x3f,0xc0,0x0f,0x70,0x23,0x7c,0x00,0xff,0x02 } }, +{ 16, 0x9bf0, 0, {0x35,0xc0,0x4d,0xb0,0x03,0x74,0x20,0xfc,0x01,0x3f,0x00,0x0f,0xf8,0x03,0xf8,0x00 } }, +{ 16, 0x9c00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa5,0x00,0xcb,0x00,0xba,0x40 } }, +{ 16, 0x9c10, 0, {0x0c,0x14,0x0b,0x2f,0x22,0xc9,0x40,0x32,0xc0,0x8e,0xb0,0x03,0xac,0x00,0xfb,0x00 } }, +{ 16, 0x9c20, 0, {0x3e,0xc0,0x0e,0xb0,0x03,0xe4,0x00,0xc9,0x00,0x32,0x00,0x2c,0x90,0x03,0x10,0x04 } }, +{ 16, 0x9c30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x01,0x24,0x00,0x8f,0x00,0x22,0x40 } }, +{ 16, 0x9c40, 0, {0x2c,0xa5,0x42,0x29,0x00,0x8b,0x04,0xa3,0xc1,0x0d,0xf0,0x0a,0x3c,0x00,0xbf,0x00 } }, +{ 16, 0x9c50, 0, {0x3f,0xc0,0x08,0xf0,0x01,0x69,0x00,0xda,0x05,0x22,0xd0,0x08,0x94,0x03,0x72,0x00 } }, +{ 16, 0x9c60, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x60,0x40,0x83,0x01,0x20,0xc0 } }, +{ 16, 0x9c70, 0, {0x09,0x00,0x02,0x20,0x00,0x82,0x60,0x22,0xc0,0x08,0x30,0x42,0x4c,0x10,0xbb,0x02 } }, +{ 16, 0x9c80, 0, {0x2c,0xc0,0x08,0xb0,0x12,0x05,0x00,0x9b,0x00,0x20,0x82,0x09,0x32,0x02,0x38,0x00 } }, +{ 16, 0x9c90, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x16,0x90,0x87,0x80,0x20,0xe0 } }, +{ 16, 0x9ca0, 0, {0x08,0x58,0x02,0x16,0x14,0x84,0x81,0x21,0xe0,0x29,0x39,0x02,0x5e,0x00,0xb7,0x80 } }, +{ 16, 0x9cb0, 0, {0x28,0xe0,0x08,0x78,0x02,0x7a,0x80,0x96,0x81,0x21,0xe0,0x09,0xf8,0x02,0x48,0x00 } }, +{ 16, 0x9cc0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x08,0x09,0x8b,0x10,0x38,0x44 } }, +{ 16, 0x9cd0, 0, {0x4d,0x25,0x12,0x0c,0x00,0xc2,0x10,0x22,0xc8,0x0a,0x38,0x03,0xcc,0x00,0xf3,0x10 } }, +{ 16, 0x9ce0, 0, {0x2c,0xc0,0x0c,0x30,0x03,0x8a,0xc0,0xd9,0x10,0x32,0x40,0x2d,0x10,0x03,0x12,0x02 } }, +{ 16, 0x9cf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x80,0xff,0x00,0x3f,0x40 } }, +{ 16, 0x9d00, 0, {0x0f,0xf0,0x03,0xf4,0x40,0xed,0x00,0x3f,0xc0,0x0e,0xf3,0x03,0xbc,0x04,0xff,0x00 } }, +{ 16, 0x9d10, 0, {0x3f,0xc2,0x0f,0xf0,0x0b,0xd4,0x00,0xff,0x10,0xbf,0x80,0x0e,0xf0,0x03,0xd0,0x06 } }, +{ 16, 0x9d20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xfa,0x00,0xcb,0x02,0x3e,0xc0 } }, +{ 16, 0x9d30, 0, {0x0f,0x90,0x03,0xa0,0x00,0xcb,0x00,0x3a,0xca,0x0c,0xb3,0x13,0xaf,0x24,0xcb,0x48 } }, +{ 16, 0x9d40, 0, {0x1e,0xc8,0x0f,0xb6,0x03,0x2c,0x00,0xfa,0x00,0x3e,0xc0,0x0f,0x90,0x03,0xea,0x00 } }, +{ 16, 0x9d50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x08,0x87,0x20,0x2d,0xc4 } }, +{ 16, 0x9d60, 0, {0x0b,0x50,0x12,0xdc,0x04,0x87,0x00,0x2c,0xc0,0x08,0x70,0xa2,0x1d,0x00,0xa7,0x40 } }, +{ 16, 0x9d70, 0, {0x25,0xcb,0x8b,0x74,0x82,0x1c,0x00,0xb7,0x00,0x2d,0xc1,0x0b,0x70,0x02,0xd2,0x04 } }, +{ 16, 0x9d80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9a,0x01,0x87,0x90,0x2d,0xe0 } }, +{ 16, 0x9d90, 0, {0x0b,0x78,0x02,0xce,0x00,0x86,0x80,0x2d,0xe4,0x29,0x7a,0x02,0x9e,0x80,0x87,0xa0 } }, +{ 16, 0x9da0, 0, {0x6d,0xe8,0x0b,0x78,0x02,0x1e,0x00,0xb5,0x80,0x2d,0x60,0x0b,0x78,0x02,0xf0,0x00 } }, +{ 16, 0x9db0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcd,0x00,0x83,0x02,0x2c,0xe0 } }, +{ 16, 0x9dc0, 0, {0x0b,0x30,0x02,0xcc,0x00,0x83,0xe0,0x2c,0xc0,0x08,0x30,0x02,0x0c,0x00,0xa3,0x00 } }, +{ 16, 0x9dd0, 0, {0x24,0xc0,0x0b,0xb0,0x02,0x0e,0x20,0xb3,0x08,0x2c,0xc0,0x0b,0x30,0x02,0xd2,0x04 } }, +{ 16, 0x9de0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xb8,0x82,0xca,0x00,0x3e,0xa8 } }, +{ 16, 0x9df0, 0, {0x0f,0xe0,0x03,0xf8,0x02,0x8e,0x80,0x3e,0x80,0x0d,0xa0,0x5b,0xa8,0x00,0xca,0x00 } }, +{ 16, 0x9e00, 0, {0x3e,0x80,0x0f,0xa0,0x03,0x3b,0x80,0xfe,0x42,0x2f,0x80,0x0f,0xa8,0x03,0xfa,0x04 } }, +{ 16, 0x9e10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x20,0xf8,0x00,0x3e,0x00 } }, +{ 16, 0x9e20, 0, {0x0f,0x06,0x03,0xc0,0x00,0xf8,0x11,0x3e,0x00,0x0f,0x00,0x03,0xe0,0x00,0xf8,0x00 } }, +{ 16, 0x9e30, 0, {0x36,0x00,0x0f,0x80,0x0b,0xe0,0x00,0xf8,0x04,0x3e,0x20,0x0f,0x81,0x03,0xd2,0x00 } }, +{ 16, 0x9e40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x00,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0x9e50, 0, {0x0c,0x9a,0x03,0x24,0x40,0xc9,0xc0,0x3e,0x40,0x4c,0x90,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0x9e60, 0, {0x36,0x40,0x07,0x90,0x03,0x24,0x00,0xc9,0x04,0x32,0x60,0x0f,0x90,0x03,0xc2,0x04 } }, +{ 16, 0x9e70, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x02,0x2e,0x40 } }, +{ 16, 0x9e80, 0, {0x0a,0x92,0x02,0x25,0x02,0x89,0xe0,0x2e,0x40,0x98,0x90,0x02,0x24,0x00,0xb9,0x00 } }, +{ 16, 0x9e90, 0, {0x22,0x40,0x09,0x90,0x02,0x04,0x00,0xd9,0x00,0x22,0x44,0x0b,0x9c,0x02,0xe0,0x00 } }, +{ 16, 0x9ea0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x2c,0x00,0xb9,0x00,0x2c,0x40 } }, +{ 16, 0x9eb0, 0, {0x08,0x90,0x02,0x24,0x28,0x89,0x00,0x2c,0x40,0x68,0x90,0x42,0x24,0x0c,0xb1,0x04 } }, +{ 16, 0x9ec0, 0, {0x26,0x40,0x0b,0x90,0x0a,0x2c,0x80,0x81,0x00,0x22,0x40,0xcb,0x92,0x82,0xc6,0x00 } }, +{ 16, 0x9ed0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0xb1,0x20,0x2c,0x48 } }, +{ 16, 0x9ee0, 0, {0x0a,0x12,0x02,0x04,0x80,0x81,0x21,0x2c,0x4c,0x08,0x11,0x02,0x04,0x08,0xb1,0x10 } }, +{ 16, 0x9ef0, 0, {0x20,0x4c,0x09,0x12,0x02,0x24,0x01,0x91,0x20,0xa0,0x48,0x0b,0x10,0x02,0xc2,0x01 } }, +{ 16, 0x9f00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x41,0xe0,0xf8,0x50,0x3e,0x14 } }, +{ 16, 0x9f10, 0, {0x0c,0x85,0x03,0x21,0x40,0xc8,0x50,0x3e,0x10,0x08,0x06,0x83,0x01,0xf0,0xf8,0x68 } }, +{ 16, 0x9f20, 0, {0x36,0x10,0x0f,0x05,0x03,0x29,0x40,0xc8,0x50,0x32,0x94,0x0f,0x85,0x03,0xee,0x03 } }, +{ 16, 0x9f30, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x00,0xf9,0x10,0x3f,0x44 } }, +{ 16, 0x9f40, 0, {0x0f,0xd1,0x0b,0xf4,0x40,0xfd,0x12,0x2e,0x4c,0x03,0x92,0x0b,0xe4,0x00,0xf9,0x20 } }, +{ 16, 0x9f50, 0, {0x3e,0x4c,0x0f,0x91,0x03,0xfc,0x00,0xfd,0x10,0x3f,0x44,0x0f,0xd0,0x03,0xe6,0x06 } }, +{ 16, 0x9f60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf6,0x20,0xc9,0x01,0x3e,0x40 } }, +{ 16, 0x9f70, 0, {0x0f,0xd0,0x03,0x3c,0x00,0xbd,0x00,0x32,0x63,0x0c,0x9e,0x43,0x27,0x00,0xe9,0xc0 } }, +{ 16, 0x9f80, 0, {0x3e,0x68,0x0c,0x98,0x03,0x34,0x00,0xf9,0x10,0x3f,0x40,0x0f,0xd0,0x03,0xc6,0x00 } }, +{ 16, 0x9f90, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xc2,0x20,0xd8,0x00,0x2e,0x00 } }, +{ 16, 0x9fa0, 0, {0x0b,0x80,0x52,0x28,0x04,0xb8,0x00,0x22,0x38,0x08,0x88,0x03,0x62,0x00,0x88,0xf0 } }, +{ 16, 0x9fb0, 0, {0x2e,0x3a,0x48,0x8f,0x0a,0x20,0x00,0xb0,0x80,0x2e,0x00,0x0b,0x80,0x02,0xce,0x04 } }, +{ 16, 0x9fc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x80,0x81,0x00,0x2c,0x40 } }, +{ 16, 0x9fd0, 0, {0x0b,0x10,0x02,0x04,0x00,0xb1,0x00,0x20,0x42,0x48,0x14,0x42,0x05,0x80,0xa1,0x20 } }, +{ 16, 0x9fe0, 0, {0x2c,0x44,0x08,0x10,0x82,0x04,0x00,0xb1,0x20,0x2c,0x40,0x0b,0x10,0x02,0xc2,0x01 } }, +{ 16, 0x9ff0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa5,0x01,0x99,0x00,0x2e,0x40 } }, +{ 16, 0xa000, 0, {0x0b,0x90,0x02,0x24,0x40,0xbb,0x01,0x22,0x41,0x08,0x90,0x12,0x24,0x00,0xa9,0x00 } }, +{ 16, 0xa010, 0, {0x2c,0x40,0x08,0x10,0x40,0x24,0x08,0xb9,0x40,0x6e,0x50,0x0b,0x92,0x02,0xc6,0x04 } }, +{ 16, 0xa020, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe7,0x14,0xc9,0x05,0x3e,0x41 } }, +{ 16, 0xa030, 0, {0x0f,0x90,0x0b,0x24,0x04,0xf9,0x08,0xb2,0x40,0x2c,0x90,0x0a,0x24,0x00,0xe9,0x00 } }, +{ 16, 0xa040, 0, {0x3e,0x40,0x2c,0x90,0x03,0x27,0x00,0xf9,0x80,0x3e,0x60,0x0f,0x90,0x03,0xe8,0x04 } }, +{ 16, 0xa050, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x84,0x88,0xf9,0x00,0x3e,0x48 } }, +{ 16, 0xa060, 0, {0x0f,0x99,0x03,0xe6,0x00,0xf9,0x02,0x3c,0x40,0xaf,0x10,0x03,0xe4,0x12,0xd9,0x04 } }, +{ 16, 0xa070, 0, {0x3e,0x40,0x0f,0x90,0x03,0xe5,0x00,0xf9,0xc0,0x3e,0x64,0x0f,0x90,0x83,0xca,0x00 } }, +{ 16, 0xa080, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa1,0x00,0xc8,0x00,0x3e,0x00 } }, +{ 16, 0xa090, 0, {0x0f,0x80,0x03,0x21,0x00,0xc8,0x40,0xb2,0x00,0x0c,0x80,0x03,0x20,0x10,0xc8,0x00 } }, +{ 16, 0xa0a0, 0, {0x32,0x00,0x0c,0x80,0x03,0xe0,0x80,0xf8,0x04,0x32,0x00,0x2c,0x80,0x0b,0x0a,0x04 } }, +{ 16, 0xa0b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0xca,0x00,0x2e,0x80 } }, +{ 16, 0xa0c0, 0, {0x0b,0xe8,0x0a,0x38,0x10,0x8e,0xc0,0x22,0x80,0x0d,0xa0,0x02,0x28,0x00,0x0a,0x04 } }, +{ 16, 0xa0d0, 0, {0x02,0x80,0x28,0xa0,0x02,0xfb,0x00,0xba,0x00,0x37,0xb0,0x48,0xea,0x02,0x0a,0x00 } }, +{ 16, 0xa0e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0x93,0x01,0x2c,0xc0 } }, +{ 16, 0xa0f0, 0, {0x8b,0xb0,0x42,0x0c,0x90,0x9b,0x20,0x20,0xc0,0x48,0x30,0x42,0x2c,0x00,0x83,0x00 } }, +{ 16, 0xa100, 0, {0x20,0xc0,0x08,0x30,0x02,0xcd,0x40,0xb3,0x00,0x24,0xc8,0x08,0x38,0x02,0x0a,0x00 } }, +{ 16, 0xa110, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x14,0x00,0x87,0x00,0x2d,0xc0 } }, +{ 16, 0xa120, 0, {0x0b,0x24,0x06,0x16,0x00,0x93,0x08,0x21,0xc8,0x09,0x31,0x02,0x0c,0x80,0x87,0xa0 } }, +{ 16, 0xa130, 0, {0x21,0xc0,0x18,0x72,0x02,0xdc,0x00,0xb7,0xb4,0x24,0xe3,0x08,0x78,0x02,0x28,0x00 } }, +{ 16, 0xa140, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x02,0x97,0xa0,0x3d,0xf0 } }, +{ 16, 0xa150, 0, {0x0f,0x48,0x03,0x3e,0x00,0xd6,0x80,0x30,0xe0,0x2c,0x7a,0x02,0x1e,0x82,0xc3,0xf0 } }, +{ 16, 0xa160, 0, {0x33,0xec,0x0c,0x7c,0x03,0xd6,0x00,0xf7,0x80,0x35,0xe0,0x0c,0xd8,0x03,0x2a,0x02 } }, +{ 16, 0xa170, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x19,0xa5,0xa0,0xfb,0x00,0x3e,0xca } }, +{ 16, 0xa180, 0, {0x0f,0x80,0x03,0xec,0x02,0xea,0x00,0x3e,0xc6,0x0f,0xb4,0x0b,0xed,0x40,0xfb,0x00 } }, +{ 16, 0xa190, 0, {0xbe,0xc0,0x0f,0xb6,0x43,0xe0,0x00,0xfb,0x02,0x3e,0x80,0x0f,0x90,0x03,0xc2,0x06 } }, +{ 16, 0xa1a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x02,0xcf,0x88,0x3f,0xe0 } }, +{ 16, 0xa1b0, 0, {0x0c,0xb9,0x03,0xfe,0x00,0xdd,0x81,0x33,0xe0,0x8c,0xfc,0x03,0x3f,0x04,0xcf,0x80 } }, +{ 16, 0xa1c0, 0, {0x33,0xe2,0x4f,0xfc,0x03,0x3e,0x00,0xcf,0xc0,0x33,0x64,0x0c,0xf8,0x03,0xc0,0x00 } }, +{ 16, 0xa1d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x94,0x40,0x87,0x00,0x2f,0xc1 } }, +{ 16, 0xa1e0, 0, {0x0d,0x69,0xa2,0xd0,0x40,0xbc,0x00,0x23,0xc0,0x08,0xf0,0x02,0x9c,0x00,0x87,0x00 } }, +{ 16, 0xa1f0, 0, {0x21,0xc0,0x0b,0x70,0x0a,0x3c,0x04,0x87,0x10,0x21,0x4c,0x08,0x60,0x02,0xea,0x04 } }, +{ 16, 0xa200, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9e,0x00,0x87,0x00,0x2d,0xc0 } }, +{ 16, 0xa210, 0, {0x09,0x62,0x02,0xd8,0x00,0x97,0x00,0x21,0xc4,0x08,0x70,0x02,0x0c,0x40,0x97,0x00 } }, +{ 16, 0xa220, 0, {0x21,0xc4,0x0b,0x30,0x02,0x58,0x00,0xa7,0x08,0x21,0x80,0x08,0x60,0x82,0xc0,0x00 } }, +{ 16, 0xa230, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xe4,0x25,0x83,0x00,0x2c,0xc0 } }, +{ 16, 0xa240, 0, {0x09,0x22,0x02,0xcc,0x20,0xb2,0x00,0x20,0xc0,0x28,0xb0,0x02,0x8c,0x00,0x93,0x00 } }, +{ 16, 0xa250, 0, {0x20,0xc0,0x0b,0x30,0x42,0x6c,0x20,0x83,0x08,0x20,0xe2,0x08,0xb8,0x02,0xc8,0x04 } }, +{ 16, 0xa260, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xa4,0x00,0xcf,0x00,0x3f,0xc0 } }, +{ 16, 0xa270, 0, {0x0d,0x9c,0x03,0xe8,0x00,0xdb,0x80,0x33,0xc0,0x0c,0xf0,0x0b,0x3c,0x06,0xdf,0x00 } }, +{ 16, 0xa280, 0, {0xb3,0xc0,0x0b,0xf0,0x07,0x68,0x00,0xef,0x40,0x32,0xa8,0x0c,0xa8,0x03,0xea,0x04 } }, +{ 16, 0xa290, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xfb,0x00,0x2e,0xc0 } }, +{ 16, 0xa2a0, 0, {0x0f,0x94,0x03,0xc5,0x40,0xfa,0x30,0x3e,0xc0,0x0f,0xb0,0x03,0x6c,0x00,0xeb,0x00 } }, +{ 16, 0xa2b0, 0, {0x3e,0xc0,0x0f,0x30,0x13,0xad,0x40,0xfb,0x02,0x3e,0xd0,0x0f,0xb4,0x03,0xe0,0x00 } }, +{ 16, 0xa2c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xe4,0x00,0xc7,0x00,0x31,0xc1 } }, +{ 16, 0xa2d0, 0, {0x8c,0xd0,0x03,0x34,0x00,0xcd,0x00,0x3d,0xc0,0x0c,0xf0,0x01,0x7c,0x00,0xdb,0x01 } }, +{ 16, 0xa2e0, 0, {0x3d,0xc0,0x4c,0xf0,0x0b,0x30,0x02,0xc3,0x00,0x32,0x00,0x0f,0xd0,0x03,0x00,0x44 } }, +{ 16, 0xa2f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6e,0x40,0x8b,0x00,0x2a,0xc0 } }, +{ 16, 0xa300, 0, {0x28,0x84,0x42,0x22,0x80,0x88,0x80,0x3a,0xc0,0x0d,0xb0,0x02,0xac,0x08,0x8b,0x00 } }, +{ 16, 0xa310, 0, {0x2e,0xc0,0x08,0xb0,0x02,0x23,0x20,0x8b,0x00,0x22,0x30,0x8b,0x8c,0x02,0x20,0x40 } }, +{ 16, 0xa320, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x24,0x00,0x8b,0x00,0x22,0xc0 } }, +{ 16, 0xa330, 0, {0x08,0x38,0x86,0x2a,0x00,0x89,0x80,0x2a,0xc0,0x08,0xb0,0x02,0xcc,0x00,0x9b,0x00 } }, +{ 16, 0xa340, 0, {0x2e,0xc0,0x08,0xb0,0x42,0x26,0x00,0x8b,0x00,0x22,0x71,0x0b,0x8c,0x02,0x20,0x00 } }, +{ 16, 0xa350, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0x83,0x00,0x28,0xc0 } }, +{ 16, 0xa360, 0, {0x08,0x32,0x42,0x00,0x00,0x81,0x00,0x28,0xc0,0x09,0x30,0x52,0x8c,0x08,0x83,0x00 } }, +{ 16, 0xa370, 0, {0x2c,0xc0,0x18,0x30,0x06,0x00,0x00,0x83,0x00,0xa0,0x00,0x0b,0x00,0x02,0x02,0x01 } }, +{ 16, 0xa380, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x74,0x02,0x8b,0x00,0x33,0xc0 } }, +{ 16, 0xa390, 0, {0x0c,0x92,0x0b,0x20,0x02,0xc8,0x00,0x3b,0xc0,0x0c,0xf5,0x03,0xfc,0x00,0xdf,0x01 } }, +{ 16, 0xa3a0, 0, {0x3f,0xc1,0x04,0xf0,0x33,0x21,0x40,0xcf,0x00,0x32,0x00,0x0f,0x80,0x0b,0x00,0x03 } }, +{ 16, 0xa3b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x19,0xfc,0x00,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0xa3c0, 0, {0x0f,0xc4,0x03,0xf0,0x00,0x9c,0x00,0x3b,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xa3d0, 0, {0x2f,0xc0,0x0f,0xf0,0x03,0xf0,0x80,0xff,0x00,0x3f,0x00,0x0f,0xc0,0x03,0xe8,0x06 } }, +{ 16, 0xa3e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf0,0xc0,0xff,0xa0,0x31,0x24 } }, +{ 16, 0xa3f0, 0, {0x0e,0xf0,0x63,0x10,0x04,0xef,0x64,0x3f,0xc0,0x4c,0xf3,0x03,0x1c,0x80,0xdf,0x08 } }, +{ 16, 0xa400, 0, {0x37,0xc0,0x0f,0xf0,0x03,0xf0,0xa0,0xfc,0x00,0x31,0x08,0x2c,0xd2,0x03,0xf0,0x00 } }, +{ 16, 0xa410, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe1,0x00,0xbb,0xc1,0x22,0x48 } }, +{ 16, 0xa420, 0, {0x08,0xfd,0x02,0x2e,0x00,0x97,0x00,0x2f,0xc2,0x48,0x71,0x23,0x7e,0x40,0xbf,0x00 } }, +{ 16, 0xa430, 0, {0x21,0xc5,0x4b,0xf5,0x02,0xef,0x00,0xbb,0x40,0x36,0xe0,0x08,0xa8,0x02,0xe0,0x04 } }, +{ 16, 0xa440, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc5,0x84,0xb3,0x11,0xa2,0xc9 } }, +{ 16, 0xa450, 0, {0x0a,0x30,0x02,0x00,0x01,0xb3,0x30,0x28,0xc4,0x08,0x32,0x42,0x0c,0x00,0xa3,0x08 } }, +{ 16, 0xa460, 0, {0xa0,0xca,0x0a,0x32,0x82,0x80,0x10,0xb0,0x41,0x24,0x11,0x08,0x31,0x02,0xe2,0x01 } }, +{ 16, 0xa470, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa5,0x00,0xbb,0x00,0x22,0xe1 } }, +{ 16, 0xa480, 0, {0x28,0xb0,0x02,0x2c,0x80,0x9b,0x00,0x2e,0xc0,0x08,0xb0,0x02,0x6c,0x00,0xb3,0x00 } }, +{ 16, 0xa490, 0, {0x22,0xc0,0x0b,0xb0,0x00,0xec,0x20,0xbb,0x00,0x26,0xc0,0x08,0x80,0x02,0xf0,0x04 } }, +{ 16, 0xa4a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xe3,0x40,0xf7,0x04,0x32,0xc0 } }, +{ 16, 0xa4b0, 0, {0x4e,0xb0,0x23,0x2e,0x20,0xeb,0x00,0x1e,0xc0,0x0c,0xb0,0x01,0x2c,0x00,0xfb,0x00 } }, +{ 16, 0xa4c0, 0, {0x36,0xc0,0x1f,0xb0,0x03,0xe1,0x40,0xfb,0x00,0x36,0x98,0x0c,0x90,0x03,0xd0,0x04 } }, +{ 16, 0xa4d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb6,0x04,0xff,0x02,0x3f,0xc0 } }, +{ 16, 0xa4e0, 0, {0x0f,0xf0,0x03,0xfe,0x00,0xef,0x02,0x3d,0xc0,0x0f,0xf0,0x23,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xa4f0, 0, {0x3f,0xc0,0x4f,0xf0,0x03,0xfc,0x00,0xf4,0x00,0x3b,0x40,0x0f,0xa0,0x13,0xf8,0x00 } }, +{ 16, 0xa500, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xaa,0x20,0xeb,0x10,0x36,0xc0 } }, +{ 16, 0xa510, 0, {0x0d,0xb0,0x07,0xec,0x20,0xdb,0x00,0x32,0xc0,0x0c,0xb0,0x02,0x6c,0x20,0xeb,0x00 } }, +{ 16, 0xa520, 0, {0x3e,0xc1,0x0d,0xb0,0x03,0xe0,0x20,0xdb,0xa0,0x32,0x90,0x4c,0xb0,0x0b,0x10,0x04 } }, +{ 16, 0xa530, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2d,0x00,0x8f,0x80,0x20,0xc1 } }, +{ 16, 0xa540, 0, {0x08,0x70,0x12,0xcf,0x00,0x8f,0x00,0xa3,0xc0,0x0d,0xf0,0x02,0x3c,0x00,0x8f,0x00 } }, +{ 16, 0xa550, 0, {0x37,0xc0,0x88,0xf0,0x02,0xec,0x00,0x88,0x00,0x20,0x40,0x08,0x80,0x02,0x32,0x00 } }, +{ 16, 0xa560, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4c,0x00,0xa3,0x80,0x24,0x81 } }, +{ 16, 0xa570, 0, {0x09,0x30,0x06,0xcc,0x40,0x93,0x00,0x28,0xc1,0x08,0xb0,0x02,0xcf,0x40,0xa3,0x00 } }, +{ 16, 0xa580, 0, {0x2c,0xc0,0x09,0x30,0x02,0xcd,0x00,0x90,0x40,0x60,0x40,0x28,0x10,0x02,0x38,0x00 } }, +{ 16, 0xa590, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x0e,0x00,0x87,0x80,0x23,0xe0 } }, +{ 16, 0xa5a0, 0, {0x48,0x79,0x02,0xde,0x41,0x97,0x80,0x29,0xe0,0x19,0x78,0x06,0x9e,0x00,0x87,0x80 } }, +{ 16, 0xa5b0, 0, {0x25,0xe0,0x08,0x78,0x02,0xd2,0x03,0x83,0x80,0x21,0xa0,0x08,0x68,0x02,0x08,0x00 } }, +{ 16, 0xa5c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x00,0xa3,0x00,0x34,0xc0 } }, +{ 16, 0xa5d0, 0, {0x0d,0x30,0x42,0xcc,0x01,0xd3,0x10,0x3a,0xc5,0x0c,0x39,0x03,0xcc,0x00,0xe3,0x04 } }, +{ 16, 0xa5e0, 0, {0x3c,0xc4,0x0d,0x30,0x03,0xce,0x00,0xd0,0x00,0x30,0x40,0x0c,0x30,0x03,0x12,0x02 } }, +{ 16, 0xa5f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x00,0xf7,0x00,0x3f,0xc0 } }, +{ 16, 0xa600, 0, {0x1f,0xf0,0x53,0xfc,0x00,0xef,0x08,0x37,0xd1,0x0f,0xf0,0x83,0x7c,0x00,0xf7,0x40 } }, +{ 16, 0xa610, 0, {0x3f,0xc1,0x0f,0xf1,0x03,0xd0,0x00,0xff,0x00,0xbf,0x84,0x0f,0xc8,0x03,0xd0,0x06 } }, +{ 16, 0xa620, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xe0,0x00,0xfb,0x00,0x3e,0xe0 } }, +{ 16, 0xa630, 0, {0x2c,0xbe,0x83,0xec,0x00,0xeb,0x40,0x3e,0xc0,0x0f,0xb4,0x03,0xed,0x20,0xfb,0x10 } }, +{ 16, 0xa640, 0, {0xb6,0xd2,0x0f,0xb4,0x83,0xec,0x00,0xdb,0x80,0x36,0xc1,0x0c,0x90,0x21,0x2a,0x00 } }, +{ 16, 0xa650, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x94,0x00,0xb7,0x00,0x2f,0xc0 } }, +{ 16, 0xa660, 0, {0x08,0x36,0x02,0x0c,0x08,0x87,0x30,0x2d,0xd9,0x8b,0x72,0x86,0xdd,0x00,0xb3,0x20 } }, +{ 16, 0xa670, 0, {0x21,0xc8,0x0b,0x74,0x02,0xd0,0x02,0x84,0x00,0xa0,0x00,0x28,0x20,0x02,0x12,0x04 } }, +{ 16, 0xa680, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9a,0x00,0xb7,0x80,0x2d,0xe0 } }, +{ 16, 0xa690, 0, {0x08,0x7a,0x02,0x9d,0x00,0xa7,0xa0,0x2d,0xe0,0x0b,0x78,0x02,0x9e,0x80,0xa7,0x80 } }, +{ 16, 0xa6a0, 0, {0x21,0xe4,0x08,0x7a,0x26,0x9e,0x18,0x83,0x04,0x21,0xe0,0x08,0x78,0x0a,0x70,0x00 } }, +{ 16, 0xa6b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0xb3,0x00,0x2c,0xe0 } }, +{ 16, 0xa6c0, 0, {0x58,0x30,0x12,0x0e,0x82,0x83,0x00,0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x01,0xb3,0x00 } }, +{ 16, 0xa6d0, 0, {0x20,0xc1,0x0b,0x30,0x02,0xc0,0x08,0x88,0xd2,0x20,0x20,0x08,0x00,0x02,0x52,0x04 } }, +{ 16, 0xa6e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xb8,0x60,0xfa,0x00,0x3f,0x82 } }, +{ 16, 0xa6f0, 0, {0x0c,0xa0,0x03,0xfa,0x00,0xaa,0x00,0x1e,0x80,0x8f,0xa0,0x03,0xe8,0x00,0xf2,0x00 } }, +{ 16, 0xa700, 0, {0x32,0x80,0x1f,0xa0,0x03,0xe8,0x00,0xda,0x00,0x36,0x88,0xac,0xe0,0x03,0x7a,0x04 } }, +{ 16, 0xa710, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe1,0x00,0xf8,0x00,0x3e,0x20 } }, +{ 16, 0xa720, 0, {0x4f,0x80,0x03,0xe1,0x00,0xf0,0x00,0x3c,0x00,0x0b,0x80,0x03,0xe0,0x00,0xf8,0x02 } }, +{ 16, 0xa730, 0, {0x3a,0x00,0x0f,0x80,0x43,0xf1,0x00,0xfc,0x0a,0x3d,0x00,0x0f,0xc0,0x03,0x92,0x00 } }, +{ 16, 0xa740, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe6,0x00,0xc9,0x90,0x3e,0x40 } }, +{ 16, 0xa750, 0, {0x0f,0x92,0x03,0xe4,0x00,0xd9,0x00,0x32,0x40,0x04,0x90,0x07,0xe7,0x00,0xf9,0x10 } }, +{ 16, 0xa760, 0, {0x30,0x40,0x0c,0x90,0x43,0xe4,0x09,0xd9,0x80,0x22,0x40,0x2c,0x10,0x0b,0x02,0x04 } }, +{ 16, 0xa770, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x60,0x89,0xc0,0x2e,0x40 } }, +{ 16, 0xa780, 0, {0x0b,0x98,0x26,0xc5,0x80,0x89,0x00,0x22,0x40,0x28,0x90,0x12,0xe7,0x10,0xb9,0x00 } }, +{ 16, 0xa790, 0, {0x36,0x40,0x28,0x90,0x12,0xc5,0x83,0xc9,0x80,0xb6,0x40,0x08,0x90,0x02,0x20,0x00 } }, +{ 16, 0xa7a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x04,0x00,0x89,0x40,0x2e,0x41 } }, +{ 16, 0xa7b0, 0, {0x4b,0x90,0x02,0xe4,0x00,0x99,0x00,0xa2,0x40,0x0a,0x90,0x02,0xe5,0x00,0xb9,0x00 } }, +{ 16, 0xa7c0, 0, {0xe2,0x41,0x08,0x90,0x42,0xe4,0x00,0x9d,0x50,0xab,0x4a,0x08,0xd0,0x26,0x06,0x00 } }, +{ 16, 0xa7d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x82,0x81,0x20,0x2c,0x50 } }, +{ 16, 0xa7e0, 0, {0x0b,0x10,0x02,0xe4,0x00,0x81,0x40,0x20,0x50,0x4a,0x14,0x32,0xc4,0x00,0xb1,0x40 } }, +{ 16, 0xa7f0, 0, {0x24,0x51,0x18,0x14,0x12,0xd4,0x00,0x85,0x40,0x2d,0x40,0x08,0x50,0x06,0x02,0x01 } }, +{ 16, 0xa800, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xc8,0x00,0x3e,0x00 } }, +{ 16, 0xa810, 0, {0x0f,0x80,0x02,0xe0,0x00,0xd8,0x00,0x32,0x00,0x0a,0x80,0x02,0xe0,0x10,0xf8,0x00 } }, +{ 16, 0xa820, 0, {0x32,0x00,0x04,0x80,0x03,0xe0,0x00,0xd8,0x00,0x3a,0x00,0x0c,0xc0,0x03,0x2e,0x03 } }, +{ 16, 0xa830, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x40,0xf9,0x10,0x3f,0x41 } }, +{ 16, 0xa840, 0, {0x0f,0x94,0x03,0xf5,0x00,0xf9,0x40,0x3e,0x50,0x0d,0x94,0x03,0xe5,0x10,0xf9,0x40 } }, +{ 16, 0xa850, 0, {0x3e,0x50,0x4f,0x94,0x03,0xc5,0x00,0xe9,0x41,0x36,0x50,0x0f,0x94,0x03,0xe6,0x06 } }, +{ 16, 0xa860, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf6,0x00,0xfd,0xa8,0x3a,0x40 } }, +{ 16, 0xa870, 0, {0x0c,0xd8,0x23,0x36,0x00,0xe9,0xa0,0x3e,0x78,0x0f,0x9e,0x03,0xb6,0x80,0xcd,0xe2 } }, +{ 16, 0xa880, 0, {0x32,0x68,0x0c,0x9b,0x03,0x36,0x82,0x4d,0xa0,0x37,0x68,0x8c,0x98,0x03,0x06,0x00 } }, +{ 16, 0xa890, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xeb,0xa0,0xb8,0x40,0x20,0x20 } }, +{ 16, 0xa8a0, 0, {0x08,0x85,0x02,0x21,0x51,0x88,0xc0,0x2e,0x29,0x0b,0x8e,0x02,0xe1,0x00,0xd8,0xe0 } }, +{ 16, 0xa8b0, 0, {0x22,0x32,0x0d,0x8d,0x23,0x61,0x48,0x98,0xd4,0xa2,0x10,0x28,0x84,0x02,0x0e,0x04 } }, +{ 16, 0xa8c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc5,0x00,0xb3,0x00,0x2a,0x4a } }, +{ 16, 0xa8d0, 0, {0x28,0x10,0x4e,0xa4,0x08,0xa1,0x68,0x28,0x44,0x0b,0x14,0x02,0xc5,0x00,0x81,0x40 } }, +{ 16, 0xa8e0, 0, {0xa0,0x50,0x08,0x10,0x02,0x04,0x02,0x91,0x2a,0x20,0x44,0x28,0x14,0x4a,0x02,0x01 } }, +{ 16, 0xa8f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xac,0x80,0xb9,0x00,0x22,0x40 } }, +{ 16, 0xa900, 0, {0x48,0x90,0x06,0xa4,0x00,0xa9,0x00,0x2e,0x40,0x0b,0x90,0x22,0xe4,0x00,0x99,0x00 } }, +{ 16, 0xa910, 0, {0x22,0x40,0x09,0x10,0x02,0x64,0x02,0x99,0x00,0x22,0x40,0x08,0x90,0x02,0x06,0x04 } }, +{ 16, 0xa920, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xf9,0x00,0x38,0x58 } }, +{ 16, 0xa930, 0, {0x0c,0x90,0x53,0x84,0x14,0xa9,0x04,0x3e,0x40,0x0f,0x90,0x03,0xe4,0x00,0xc9,0x00 } }, +{ 16, 0xa940, 0, {0x32,0x40,0x0c,0x90,0x03,0x24,0x04,0xd9,0x00,0xb6,0x40,0x4c,0x90,0x0b,0x28,0x04 } }, +{ 16, 0xa950, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x00,0xf9,0x02,0x3e,0x49 } }, +{ 16, 0xa960, 0, {0x0f,0x10,0x43,0x64,0x00,0xd9,0x00,0x3e,0x40,0x0f,0x90,0x03,0xc4,0x00,0xf1,0x02 } }, +{ 16, 0xa970, 0, {0x3e,0x40,0x0f,0x90,0x03,0xc4,0x02,0xe9,0x04,0x3c,0x40,0x0f,0x1c,0x03,0xca,0x00 } }, +{ 16, 0xa980, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa1,0x80,0xc8,0x20,0x3e,0x00 } }, +{ 16, 0xa990, 0, {0x8c,0x80,0x0b,0x20,0x00,0xe8,0x02,0x3e,0x00,0x0f,0x80,0x03,0xa0,0x82,0xc8,0x00 } }, +{ 16, 0xa9a0, 0, {0x6c,0x00,0x0f,0x80,0x03,0x20,0x10,0xc8,0x00,0x32,0x02,0x0c,0x80,0x03,0x0a,0x04 } }, +{ 16, 0xa9b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x38,0x00,0x86,0x00,0x2e,0x80 } }, +{ 16, 0xa9c0, 0, {0x68,0xa8,0x80,0x3a,0x00,0x8a,0x00,0x2e,0x80,0x0b,0xa0,0x02,0xf8,0x00,0x8a,0x00 } }, +{ 16, 0xa9d0, 0, {0x2e,0x80,0x0b,0xa0,0x0a,0x3a,0x00,0x8e,0x10,0x23,0x80,0x08,0xa0,0x03,0x0a,0x00 } }, +{ 16, 0xa9e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4d,0x00,0x83,0x00,0x2c,0xc0 } }, +{ 16, 0xa9f0, 0, {0x08,0x38,0x00,0x0c,0x60,0x23,0x00,0x2c,0xc0,0x0b,0x30,0x02,0xcc,0x40,0x83,0x00 } }, +{ 16, 0xaa00, 0, {0x2c,0xc0,0x0b,0x30,0x02,0x0c,0x02,0x8a,0x80,0xa0,0xe0,0x28,0x30,0x0a,0x4a,0x00 } }, +{ 16, 0xaa10, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x16,0x20,0x87,0x02,0x2d,0xc1 } }, +{ 16, 0xaa20, 0, {0x48,0x70,0x12,0x7c,0x00,0xa7,0x20,0x2d,0xc9,0x0b,0x72,0x00,0xdc,0x00,0x87,0x08 } }, +{ 16, 0xaa30, 0, {0x2d,0xc4,0x1b,0x32,0x02,0x1d,0x01,0x87,0x42,0x21,0xc2,0x08,0x70,0x02,0x28,0x00 } }, +{ 16, 0xaa40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x3e,0x02,0xc7,0x80,0x3d,0xec } }, +{ 16, 0xaa50, 0, {0x0c,0x58,0x03,0x1e,0x00,0xe7,0x80,0x3d,0xec,0x0f,0x7f,0x03,0x96,0x00,0xc7,0x80 } }, +{ 16, 0xaa60, 0, {0x2d,0xe2,0x07,0x79,0x03,0x0a,0x06,0xc3,0x80,0x30,0x20,0x8c,0x38,0x03,0x6a,0x02 } }, +{ 16, 0xaa70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xaa80, 0, {0x0f,0x10,0x43,0x8c,0x00,0xdb,0x38,0x3e,0xd8,0x0f,0xb0,0x03,0xcc,0x04,0xfb,0x44 } }, +{ 16, 0xaa90, 0, {0x3e,0xc0,0x8f,0xb6,0x13,0xec,0x02,0xff,0x02,0x3e,0x00,0x0f,0xb0,0x03,0xc2,0x06 } }, +{ 16, 0xaaa0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfa,0x00,0xff,0x80,0x31,0xe3 } }, +{ 16, 0xaab0, 0, {0x0e,0xf8,0x23,0xfe,0x02,0xdf,0x80,0xb7,0xe2,0x0e,0xf8,0x03,0x7e,0x00,0x6d,0xd0 } }, +{ 16, 0xaac0, 0, {0x33,0xe0,0x0c,0xf8,0x9b,0x76,0xc0,0xdf,0x84,0xb3,0xe0,0x04,0xf8,0x03,0xc0,0x00 } }, +{ 16, 0xaad0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x90,0x40,0xb7,0x02,0x21,0xc4 } }, +{ 16, 0xaae0, 0, {0x08,0x7b,0x42,0xdc,0x00,0x87,0x00,0x21,0xc4,0x0b,0x30,0x00,0x10,0x80,0x8d,0x00 } }, +{ 16, 0xaaf0, 0, {0x23,0xc0,0x0d,0xf2,0x02,0x04,0x42,0x8f,0x00,0x29,0xc8,0x28,0x70,0x02,0xea,0x04 } }, +{ 16, 0xab00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x00,0xb6,0x00,0x23,0xc0 } }, +{ 16, 0xab10, 0, {0x0a,0x72,0x02,0x8c,0x00,0x87,0x00,0x21,0xc0,0x0a,0x30,0x02,0x04,0x01,0xa7,0x02 } }, +{ 16, 0xab20, 0, {0x21,0xc0,0x08,0x70,0x42,0x00,0x8a,0x87,0x00,0x21,0xc0,0x28,0x70,0x02,0xc0,0x00 } }, +{ 16, 0xab30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xc5,0x00,0xb0,0x00,0xa0,0xd0 } }, +{ 16, 0xab40, 0, {0x08,0xb0,0x02,0xc9,0x42,0x8b,0x00,0x20,0xc0,0x0b,0x30,0x22,0x04,0x00,0x83,0x00 } }, +{ 16, 0xab50, 0, {0xa0,0xc0,0x49,0x30,0x02,0x45,0x40,0x93,0xc0,0xa8,0xd4,0x00,0x35,0x02,0xc8,0x04 } }, +{ 16, 0xab60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xac,0x00,0xbb,0x00,0x31,0xc0 } }, +{ 16, 0xab70, 0, {0x0e,0xb0,0x23,0xcd,0x00,0xdf,0x00,0x37,0xc0,0x0e,0xf0,0x01,0x68,0x00,0xe3,0x00 } }, +{ 16, 0xab80, 0, {0x33,0xc0,0x1c,0xf0,0x03,0x45,0x00,0xda,0xc8,0x92,0xd4,0x2c,0xb4,0x03,0xea,0x04 } }, +{ 16, 0xab90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe5,0x20,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xaba0, 0, {0x0f,0xb0,0x03,0xec,0x00,0xfb,0x00,0x3e,0xc0,0x4f,0xb0,0x03,0xad,0x00,0xfb,0x00 } }, +{ 16, 0xabb0, 0, {0x7e,0xc0,0x1f,0x30,0x03,0xa4,0x80,0xe9,0x20,0x3c,0xc0,0x0f,0x32,0x03,0xe0,0x00 } }, +{ 16, 0xabc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xdc,0x00,0xc7,0x00,0x33,0xc2 } }, +{ 16, 0xabd0, 0, {0x2c,0xf0,0x03,0x3e,0x20,0xdb,0x00,0x13,0xc0,0x0c,0x70,0x03,0x3c,0x80,0xef,0x04 } }, +{ 16, 0xabe0, 0, {0x73,0xc1,0x0f,0xf0,0x22,0x30,0x00,0xc6,0x00,0xb2,0xc0,0x0c,0xf0,0x03,0x00,0x44 } }, +{ 16, 0xabf0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x00,0x69,0x00,0x8b,0x44,0xa2,0xc1 } }, +{ 16, 0xac00, 0, {0x88,0xb0,0x03,0x6c,0x00,0x8b,0x00,0x22,0xc0,0x28,0xb0,0x0a,0x2d,0x00,0xbb,0x00 } }, +{ 16, 0xac10, 0, {0x62,0xc0,0x0b,0xb0,0x02,0x26,0x02,0x8b,0x80,0x22,0xc0,0x08,0xb0,0x03,0x20,0x40 } }, +{ 16, 0xac20, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x28,0x01,0x8a,0x08,0x22,0xc0 } }, +{ 16, 0xac30, 0, {0x08,0xb2,0x02,0x6c,0x40,0x9b,0x00,0x28,0xc0,0x48,0xb0,0x16,0x29,0x04,0xb9,0x01 } }, +{ 16, 0xac40, 0, {0x22,0xc0,0x49,0xb0,0x06,0xae,0x09,0x8b,0x80,0x22,0xe0,0x48,0xb0,0x02,0x20,0x00 } }, +{ 16, 0xac50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x02,0x82,0x00,0x22,0xc0 } }, +{ 16, 0xac60, 0, {0x88,0xb0,0x02,0x44,0x00,0x83,0x00,0x28,0xc0,0x08,0x30,0x02,0x08,0x00,0xb1,0x00 } }, +{ 16, 0xac70, 0, {0x20,0xc0,0x0b,0x30,0x02,0x8c,0x00,0x83,0x80,0x20,0xe0,0x08,0x30,0x0a,0x02,0x01 } }, +{ 16, 0xac80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x64,0x00,0xca,0x00,0x33,0xc0 } }, +{ 16, 0xac90, 0, {0x0c,0xb2,0x03,0x2c,0x00,0xdf,0x00,0x3b,0xc0,0x4c,0xf5,0x13,0x2c,0x04,0xef,0x00 } }, +{ 16, 0xaca0, 0, {0xa3,0xc0,0x0d,0xf0,0x03,0xa8,0x40,0xcb,0x00,0xb2,0x00,0x2c,0xb0,0x03,0x00,0x03 } }, +{ 16, 0xacb0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xf0,0x00,0xf4,0x00,0x3f,0xc0 } }, +{ 16, 0xacc0, 0, {0x0f,0xb1,0x03,0xf0,0x00,0xff,0x00,0x37,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xacd0, 0, {0x3f,0xc0,0x07,0xf0,0x0b,0x7c,0x08,0xff,0x01,0x3f,0x00,0x0f,0xf0,0x03,0xa8,0x06 } }, +{ 16, 0xace0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf0,0xc5,0xed,0x33,0x3b,0xcc } }, +{ 16, 0xacf0, 0, {0x0c,0xf0,0x03,0x30,0x40,0xff,0x25,0x3f,0xcc,0x0c,0xf3,0x83,0x3c,0xd0,0xdf,0x48 } }, +{ 16, 0xad00, 0, {0x37,0x30,0x4c,0xf3,0x03,0xfd,0x80,0xcf,0x28,0x33,0xd8,0x0c,0xf1,0x03,0x30,0x00 } }, +{ 16, 0xad10, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xec,0xd0,0xbb,0x31,0x20,0xcc } }, +{ 16, 0xad20, 0, {0x88,0xf3,0x42,0x20,0x50,0xbf,0x90,0x2f,0xc4,0x0a,0xf6,0x02,0x7d,0xc0,0x8f,0x40 } }, +{ 16, 0xad30, 0, {0x26,0x40,0x8f,0xf6,0x02,0xfd,0x00,0xff,0x08,0x39,0xc8,0x08,0xf6,0x02,0xa0,0x04 } }, +{ 16, 0xad40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc4,0x80,0xa1,0x20,0x28,0xc9 } }, +{ 16, 0xad50, 0, {0x08,0x30,0x9a,0x00,0x09,0xb3,0x00,0x2c,0xc0,0x20,0x30,0x02,0x4c,0x90,0x83,0x20 } }, +{ 16, 0xad60, 0, {0x02,0x08,0x0b,0x33,0x12,0xcd,0x80,0x93,0x20,0x24,0xd8,0x08,0x34,0x22,0x22,0x01 } }, +{ 16, 0xad70, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x11,0xae,0x00,0xbb,0x10,0x22,0xc0 } }, +{ 16, 0xad80, 0, {0x08,0xb0,0x02,0x26,0x01,0x3b,0x01,0x6e,0xc0,0x08,0xb0,0x02,0x4c,0x08,0x8b,0x00 } }, +{ 16, 0xad90, 0, {0xa2,0x89,0x0b,0xb0,0x02,0xec,0x00,0xab,0x00,0x6a,0xc1,0x28,0xb0,0x02,0xb0,0x04 } }, +{ 16, 0xada0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0x6e,0x00,0xe8,0xc1,0x3a,0xc0 } }, +{ 16, 0xadb0, 0, {0x2c,0xb0,0x43,0x26,0x00,0xfb,0x06,0x3e,0xc1,0x0c,0xb0,0x0b,0x2c,0x02,0xcb,0x00 } }, +{ 16, 0xadc0, 0, {0x34,0x22,0x9f,0xb0,0x43,0xec,0x00,0x9b,0x02,0x36,0xc1,0x8c,0xb0,0x03,0x10,0x04 } }, +{ 16, 0xadd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xbc,0x00,0xfc,0x80,0x3d,0xd0 } }, +{ 16, 0xade0, 0, {0x2f,0xf0,0x03,0xfc,0x00,0xfb,0x00,0x3d,0xc0,0x07,0x30,0x03,0xbc,0x00,0xef,0x04 } }, +{ 16, 0xadf0, 0, {0x3f,0xe0,0x5e,0xb0,0x01,0xfc,0x00,0xff,0x00,0x1b,0xc0,0x0f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0xae00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xcb,0x01,0x3e,0xc9 } }, +{ 16, 0xae10, 0, {0x0c,0xb0,0x17,0x20,0x84,0xeb,0x00,0xb2,0xc1,0x0d,0xb0,0x03,0x6c,0x00,0xc3,0x00 } }, +{ 16, 0xae20, 0, {0x32,0x50,0x0f,0xb0,0x03,0x0c,0x40,0xc3,0x00,0x7e,0xc0,0x0c,0x30,0x03,0x10,0x04 } }, +{ 16, 0xae30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0x8a,0x58,0x2e,0xe0 } }, +{ 16, 0xae40, 0, {0x48,0xf0,0x02,0x2d,0x00,0xef,0x01,0x23,0xc0,0x08,0xf0,0x22,0x3c,0x04,0x8f,0x60 } }, +{ 16, 0xae50, 0, {0x36,0x54,0x0b,0xf0,0x0a,0x3d,0x40,0x8f,0x00,0x2f,0xc0,0x08,0xf0,0x03,0x72,0x00 } }, +{ 16, 0xae60, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x40,0x00,0x89,0x80,0x2c,0x10 } }, +{ 16, 0xae70, 0, {0x08,0xb0,0x02,0x49,0x00,0xa3,0xa0,0x24,0xc0,0x09,0x30,0x02,0x4c,0x00,0x83,0xc9 } }, +{ 16, 0xae80, 0, {0x20,0x90,0x42,0x30,0x12,0x4d,0x00,0x83,0x00,0x6a,0xc0,0x09,0x30,0x02,0x38,0x00 } }, +{ 16, 0xae90, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x16,0x00,0x85,0x80,0x6d,0x62 } }, +{ 16, 0xaea0, 0, {0x08,0x7e,0x02,0x56,0x40,0x27,0x80,0x25,0xe0,0x19,0x78,0x06,0x0e,0x00,0x83,0x80 } }, +{ 16, 0xaeb0, 0, {0x61,0xa0,0x0b,0x78,0x02,0x4e,0x00,0x87,0x82,0x6d,0xe0,0x09,0x79,0x02,0x48,0x00 } }, +{ 16, 0xaec0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x2c,0x02,0xc3,0x61,0x3c,0x88 } }, +{ 16, 0xaed0, 0, {0x2c,0xba,0x12,0x49,0x10,0xe3,0x2c,0x36,0xc0,0x0d,0x30,0x53,0x4c,0x44,0xc3,0x00 } }, +{ 16, 0xaee0, 0, {0x20,0x01,0x0f,0x31,0x03,0x4c,0x00,0xc3,0x01,0x3c,0xc0,0x2d,0xb1,0x03,0x12,0x02 } }, +{ 16, 0xaef0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x00,0xff,0x00,0x3f,0x00 } }, +{ 16, 0xaf00, 0, {0x4f,0xf1,0x09,0xb0,0x00,0xff,0x00,0x3b,0xc0,0x0e,0xf4,0x01,0xfd,0x24,0xff,0x40 } }, +{ 16, 0xaf10, 0, {0xbf,0xc0,0x07,0xf0,0x03,0xbc,0x00,0x6f,0x10,0x3f,0xc4,0x1e,0xf1,0x83,0xd0,0x06 } }, +{ 16, 0xaf20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xc4,0x00,0xe8,0x04,0x32,0x00 } }, +{ 16, 0xaf30, 0, {0x0c,0xb6,0x03,0xe8,0x02,0xcb,0x00,0x36,0xca,0x0f,0xb5,0x03,0xad,0x00,0xfb,0x20 } }, +{ 16, 0xaf40, 0, {0x3e,0x40,0x0f,0xb3,0x03,0xec,0x80,0xfb,0xa8,0x32,0xc6,0x8c,0xb6,0x03,0x2a,0x00 } }, +{ 16, 0xaf50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x94,0x02,0xe6,0x00,0x20,0x00 } }, +{ 16, 0xaf60, 0, {0x08,0x73,0x02,0xdc,0x00,0x87,0x70,0x2d,0xd0,0x0b,0xf0,0x02,0x1c,0x84,0xb7,0x20 } }, +{ 16, 0xaf70, 0, {0x2d,0xc0,0x0b,0x70,0x82,0xdd,0x24,0xb7,0x40,0x34,0xc9,0x28,0x72,0x82,0x92,0x04 } }, +{ 16, 0xaf80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xbe,0x02,0xac,0x80,0xa1,0x20 } }, +{ 16, 0xaf90, 0, {0x08,0x79,0x00,0xce,0x04,0x87,0x80,0x65,0xe0,0x0b,0x7a,0x02,0x9e,0x00,0xb7,0x90 } }, +{ 16, 0xafa0, 0, {0x6d,0xa0,0x0b,0x78,0x02,0xde,0x00,0xb7,0x80,0x21,0xe0,0x08,0x78,0x02,0x30,0x00 } }, +{ 16, 0xafb0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xed,0x82,0xab,0xe0,0x20,0xe4 } }, +{ 16, 0xafc0, 0, {0x08,0x30,0x02,0xee,0x04,0x83,0x00,0x2c,0xc1,0x1b,0x30,0x02,0x0c,0x08,0xb3,0x00 } }, +{ 16, 0xafd0, 0, {0x64,0xf6,0x0b,0xb0,0x02,0xcc,0x04,0xb3,0x00,0x26,0xc0,0x08,0x30,0x02,0x92,0x04 } }, +{ 16, 0xafe0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xbb,0x80,0xee,0x49,0x31,0xa0 } }, +{ 16, 0xaff0, 0, {0x2c,0xa0,0x03,0xfa,0x00,0xca,0x02,0x36,0x80,0x0f,0xa0,0x03,0xa8,0x00,0xfa,0x02 } }, +{ 16, 0xb000, 0, {0x3f,0x90,0x0f,0xa0,0x63,0xe8,0x00,0xfa,0x00,0x32,0x80,0x0c,0xa0,0x23,0x3a,0x04 } }, +{ 16, 0xb010, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x0a,0xe8,0x00,0x3e,0x08 } }, +{ 16, 0xb020, 0, {0x0f,0x80,0x03,0xe3,0x50,0xf0,0x00,0x3e,0x00,0x0f,0x80,0x13,0xe0,0x00,0xf8,0x00 } }, +{ 16, 0xb030, 0, {0x3e,0x00,0x0f,0x80,0x03,0xe0,0x01,0xf8,0x01,0x7e,0x00,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xb040, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x40,0xc9,0xa1,0x32,0x40 } }, +{ 16, 0xb050, 0, {0x20,0x11,0x01,0xa6,0x40,0xc9,0x84,0x36,0x40,0x0d,0x90,0x03,0x44,0x00,0x41,0x00 } }, +{ 16, 0xb060, 0, {0x32,0x40,0x0f,0x90,0x0b,0x24,0x00,0xf9,0x00,0x3e,0x40,0x4c,0x10,0x03,0x02,0x04 } }, +{ 16, 0xb070, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0x89,0x82,0xa2,0x40 } }, +{ 16, 0xb080, 0, {0x08,0x9c,0x02,0x25,0x00,0x89,0xc8,0x22,0x40,0x08,0x90,0x42,0x24,0x00,0x89,0x20 } }, +{ 16, 0xb090, 0, {0x22,0x60,0x0b,0x90,0x02,0x24,0x10,0xb9,0x00,0x2e,0x40,0x08,0x90,0x03,0x60,0x00 } }, +{ 16, 0xb0a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0x89,0x04,0x22,0xca } }, +{ 16, 0xb0b0, 0, {0x0a,0x90,0x0a,0x25,0x02,0x89,0x20,0x20,0x40,0x28,0x10,0x02,0x64,0x01,0xa9,0x00 } }, +{ 16, 0xb0c0, 0, {0x22,0x4b,0x0b,0x90,0x02,0x24,0x01,0xb9,0x00,0x2e,0x41,0x28,0x90,0x02,0x06,0x00 } }, +{ 16, 0xb0d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x90,0x81,0xa0,0x20,0x48 } }, +{ 16, 0xb0e0, 0, {0x0a,0x32,0x02,0x04,0x80,0x81,0x00,0x20,0x44,0x08,0x11,0x02,0x04,0xd0,0xa1,0x20 } }, +{ 16, 0xb0f0, 0, {0x20,0x40,0x0b,0x11,0x02,0x06,0x00,0xb1,0x31,0x2c,0x48,0x08,0x14,0x02,0x42,0x01 } }, +{ 16, 0xb100, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x42,0xc8,0x54,0x32,0x14 } }, +{ 16, 0xb110, 0, {0x0e,0x85,0x03,0x21,0x44,0xc8,0x28,0xb2,0x1a,0x4c,0x86,0x93,0x61,0x14,0xe8,0x50 } }, +{ 16, 0xb120, 0, {0x22,0x14,0x0f,0x86,0x83,0x21,0x40,0xf0,0x40,0x1e,0x14,0x0c,0x00,0x03,0x2e,0x03 } }, +{ 16, 0xb130, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0x74,0x44,0xf5,0x10,0x3f,0x44 } }, +{ 16, 0xb140, 0, {0x0d,0x91,0x03,0x74,0x40,0xf9,0x00,0x3e,0x48,0x0b,0x92,0x03,0xe4,0xc2,0xd9,0x10 } }, +{ 16, 0xb150, 0, {0xbf,0x40,0x0f,0x92,0x03,0xe5,0x04,0xf9,0x30,0x3e,0x44,0x0f,0x94,0x43,0xe6,0x06 } }, +{ 16, 0xb160, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf6,0x22,0xcd,0xa1,0x33,0x61 } }, +{ 16, 0xb170, 0, {0x0c,0xd8,0xd3,0x34,0x10,0xcd,0xa8,0x3e,0x60,0x8e,0x9c,0x93,0xa7,0x08,0xcd,0x80 } }, +{ 16, 0xb180, 0, {0x33,0x40,0x0e,0x9a,0xd3,0x36,0xa0,0xc9,0x80,0x32,0x60,0x0c,0x99,0x03,0x06,0x00 } }, +{ 16, 0xb190, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe3,0x88,0x8a,0xa0,0x20,0x28 } }, +{ 16, 0xb1a0, 0, {0x08,0x80,0x22,0x20,0x12,0x88,0x40,0x2c,0x28,0x08,0x8a,0x02,0x22,0x00,0x88,0x00 } }, +{ 16, 0xb1b0, 0, {0x22,0x00,0x0b,0x8c,0x03,0x21,0x00,0x88,0xd0,0xa2,0x3e,0x28,0x8d,0x02,0x0e,0x04 } }, +{ 16, 0xb1c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xce,0x20,0xa1,0x48,0x20,0x52 } }, +{ 16, 0xb1d0, 0, {0x29,0x10,0x02,0x24,0x03,0x81,0x00,0x2c,0x52,0x0a,0x10,0x12,0x85,0x10,0x91,0x40 } }, +{ 16, 0xb1e0, 0, {0xa4,0x40,0x0a,0x12,0x82,0x44,0x00,0x91,0x28,0x24,0x40,0x28,0x12,0x02,0x02,0x01 } }, +{ 16, 0xb1f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x00,0xa9,0x14,0x22,0x40 } }, +{ 16, 0xb200, 0, {0x09,0x90,0x02,0xa4,0x01,0x89,0x04,0x2c,0x40,0x08,0x90,0x02,0x24,0x00,0x99,0x00 } }, +{ 16, 0xb210, 0, {0x22,0x44,0x4b,0x10,0x42,0x24,0x14,0x99,0x00,0x26,0x40,0x08,0x10,0x02,0x06,0x04 } }, +{ 16, 0xb220, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x40,0xe9,0x40,0xb2,0x78 } }, +{ 16, 0xb230, 0, {0x0d,0x90,0x0b,0x24,0x22,0xc9,0x03,0x3e,0x41,0x0e,0x90,0x03,0xa4,0x02,0xd9,0x00 } }, +{ 16, 0xb240, 0, {0x16,0x58,0x06,0x90,0x0b,0x64,0x02,0xd9,0x00,0x36,0x40,0x0c,0x90,0x0b,0x28,0x04 } }, +{ 16, 0xb250, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x84,0x00,0xd9,0x80,0x3e,0x4a } }, +{ 16, 0xb260, 0, {0x0e,0x90,0x03,0x64,0x20,0xf9,0x08,0x3e,0x41,0x0f,0x90,0x03,0xe4,0x00,0xe1,0x08 } }, +{ 16, 0xb270, 0, {0x3e,0x40,0x0f,0x90,0x03,0xc4,0x00,0xe1,0x00,0x38,0x40,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0xb280, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x09,0xf0,0x40,0xb0,0x10 } }, +{ 16, 0xb290, 0, {0x4c,0x00,0x0b,0x20,0x00,0xf8,0x00,0x3a,0x00,0x1c,0x00,0x03,0xe0,0x00,0xc8,0x00 } }, +{ 16, 0xb2a0, 0, {0x36,0x00,0x0c,0x80,0x03,0x20,0x00,0xc8,0x00,0x32,0x00,0x0f,0x80,0x03,0x0a,0x04 } }, +{ 16, 0xb2b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x28,0x00,0x3e,0x88,0x23,0xa2 } }, +{ 16, 0xb2c0, 0, {0x48,0xe0,0x00,0x19,0x80,0xbe,0x88,0x2e,0x80,0x0d,0xa0,0x42,0xe8,0x00,0x8e,0x00 } }, +{ 16, 0xb2d0, 0, {0x23,0x90,0x08,0xa0,0x0a,0x3a,0x00,0xda,0x00,0x36,0x80,0x0b,0xa0,0x0a,0x0a,0x00 } }, +{ 16, 0xb2e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0xb3,0x80,0x20,0xe0 } }, +{ 16, 0xb2f0, 0, {0x28,0x30,0xc2,0x0f,0x10,0xb3,0x40,0x28,0xc0,0x0b,0x30,0x02,0xec,0x11,0x83,0x40 } }, +{ 16, 0xb300, 0, {0x28,0xd2,0x0a,0x30,0x02,0x0c,0xc0,0x83,0x00,0x20,0xc0,0x0b,0x30,0x02,0x0a,0x00 } }, +{ 16, 0xb310, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x00,0xb6,0x00,0x21,0xc0 } }, +{ 16, 0xb320, 0, {0x08,0x20,0xc2,0x1c,0x10,0xb5,0x00,0x2d,0xc8,0x0a,0x72,0x02,0xdc,0x40,0x85,0x08 } }, +{ 16, 0xb330, 0, {0x29,0xa2,0x1a,0x72,0x22,0x0c,0x00,0x93,0x30,0x05,0xc4,0x0b,0x32,0x22,0x28,0x00 } }, +{ 16, 0xb340, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x16,0x00,0xb2,0x80,0x31,0x20 } }, +{ 16, 0xb350, 0, {0x0c,0x58,0x03,0x1e,0x00,0xf7,0x80,0x39,0xf8,0x0b,0x7c,0x22,0xce,0x40,0xcf,0x80 } }, +{ 16, 0xb360, 0, {0x9b,0x60,0x2e,0x3b,0x03,0x1a,0x00,0xc7,0xa8,0x11,0xe0,0x0f,0x78,0x03,0x2a,0x02 } }, +{ 16, 0xb370, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xa4,0x00,0xfa,0x00,0x3e,0xc0 } }, +{ 16, 0xb380, 0, {0x0f,0x90,0x23,0xe8,0x00,0xfb,0x00,0x3e,0xd0,0x2d,0xb6,0x03,0xed,0x02,0xf9,0x00 } }, +{ 16, 0xb390, 0, {0x32,0x40,0x0d,0xb0,0x07,0xec,0x00,0xfb,0x60,0x3e,0xc8,0x0f,0xb5,0x03,0xc2,0x06 } }, +{ 16, 0xb3a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xff,0x80,0x33,0xa0 } }, +{ 16, 0xb3b0, 0, {0x0c,0xf8,0x0b,0x32,0x40,0xce,0x81,0x37,0xf0,0x0c,0xbc,0x03,0xfe,0x00,0xff,0x84 } }, +{ 16, 0xb3c0, 0, {0x33,0xe0,0x2c,0xf8,0x83,0xe6,0x02,0xcf,0x85,0x33,0xf0,0x0c,0xfc,0x03,0x00,0x14 } }, +{ 16, 0xb3d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0xbe,0x00,0x35,0xc6 } }, +{ 16, 0xb3e0, 0, {0x28,0x30,0x02,0x30,0x40,0x87,0x00,0x23,0xc0,0x08,0x7a,0x02,0xdc,0x00,0xbe,0x00 } }, +{ 16, 0xb3f0, 0, {0x23,0xc0,0x08,0x70,0x12,0xfe,0x00,0x87,0x00,0x21,0xc0,0x08,0xf0,0x02,0x2a,0x04 } }, +{ 16, 0xb400, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x20,0xb6,0x00,0x20,0x80 } }, +{ 16, 0xb410, 0, {0x08,0x31,0x02,0x5c,0x01,0x87,0x00,0x25,0xc0,0x08,0x72,0x02,0xdc,0x00,0xb6,0x00 } }, +{ 16, 0xb420, 0, {0x21,0xd0,0x09,0x70,0x02,0xd4,0x08,0x93,0x00,0x20,0xc0,0x08,0x70,0x02,0x00,0x00 } }, +{ 16, 0xb430, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xc4,0x00,0xb0,0xe0,0x24,0x60 } }, +{ 16, 0xb440, 0, {0x08,0x20,0x06,0x48,0x01,0x80,0x00,0x20,0xc0,0x08,0x30,0x02,0xcc,0x04,0xb3,0x00 } }, +{ 16, 0xb450, 0, {0x20,0x84,0x0b,0x30,0x02,0xe8,0x00,0x9b,0x00,0x20,0xc0,0x08,0x30,0x02,0x08,0x04 } }, +{ 16, 0xb460, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xac,0x00,0xb9,0xe0,0x32,0x80 } }, +{ 16, 0xb470, 0, {0x6c,0xb0,0x23,0x6f,0x00,0xc3,0x00,0x37,0xc1,0x3c,0xf0,0x03,0xfc,0x00,0xfa,0x00 } }, +{ 16, 0xb480, 0, {0xb0,0xc0,0x09,0xf0,0x03,0xec,0x10,0xdf,0x00,0x73,0xc0,0x0c,0xf0,0x0b,0x2a,0x00 } }, +{ 16, 0xb490, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x10,0xf8,0x00,0x3e,0x42 } }, +{ 16, 0xb4a0, 0, {0x0f,0x24,0x03,0xa8,0x60,0xf8,0x00,0x3c,0xc1,0x0f,0xb0,0x03,0xec,0x00,0xf9,0x40 } }, +{ 16, 0xb4b0, 0, {0x3e,0x80,0x04,0xb0,0x23,0xe1,0x00,0xeb,0x00,0x3e,0xc0,0x0f,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0xb4c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xf4,0x00,0xee,0x00,0x3d,0x30 } }, +{ 16, 0xb4d0, 0, {0x0c,0xc0,0x03,0x14,0x00,0xcc,0xa0,0xb3,0xc0,0x4c,0x70,0x03,0x5c,0x10,0xdf,0x00 } }, +{ 16, 0xb4e0, 0, {0x3f,0x00,0x0c,0xf0,0x03,0xf8,0x00,0xcf,0x00,0x23,0xc0,0x0c,0xf0,0x03,0x00,0x40 } }, +{ 16, 0xb4f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x64,0x00,0xba,0x81,0x2e,0x58 } }, +{ 16, 0xb500, 0, {0x08,0x88,0x02,0x27,0x80,0x89,0x20,0x22,0xc0,0x28,0xb0,0x02,0x2c,0x00,0x88,0x83 } }, +{ 16, 0xb510, 0, {0x2e,0x20,0x05,0xb0,0x62,0xe3,0x00,0x8b,0x00,0x2a,0xc0,0x08,0xb0,0x03,0x60,0x40 } }, +{ 16, 0xb520, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x26,0x00,0xb9,0x81,0x2e,0x40 } }, +{ 16, 0xb530, 0, {0x08,0x8c,0x06,0x26,0x00,0x88,0x00,0x22,0xc0,0x08,0xb0,0x16,0x6c,0x00,0x98,0x88 } }, +{ 16, 0xb540, 0, {0x2e,0x20,0x08,0xb0,0x04,0xe3,0x01,0x0b,0x00,0x28,0xc0,0x08,0x30,0x02,0x20,0x00 } }, +{ 16, 0xb550, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0xb0,0x00,0x2c,0xc0 } }, +{ 16, 0xb560, 0, {0x28,0x00,0x0e,0x00,0x10,0x80,0x00,0x20,0xc0,0x08,0x32,0x02,0x0c,0x00,0x80,0x04 } }, +{ 16, 0xb570, 0, {0x2e,0x20,0x09,0x30,0x02,0xc4,0x12,0x83,0x00,0x28,0xc0,0x08,0x30,0x02,0x42,0x01 } }, +{ 16, 0xb580, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xfa,0x00,0x3e,0x00 } }, +{ 16, 0xb590, 0, {0x2c,0x91,0x03,0x20,0x00,0x8a,0x00,0x33,0xc0,0x0c,0xf0,0x03,0x7c,0x00,0xd8,0x00 } }, +{ 16, 0xb5a0, 0, {0x2e,0x40,0x0c,0xf0,0x03,0xe0,0x80,0xcf,0x00,0x3b,0xc0,0x0c,0xf0,0x03,0x00,0x03 } }, +{ 16, 0xb5b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xfc,0x00,0xfc,0x01,0x3f,0x40 } }, +{ 16, 0xb5c0, 0, {0x0f,0xc0,0x13,0xf0,0x00,0xf4,0x00,0x3f,0xc1,0x0f,0xf4,0x23,0xfc,0x08,0xfc,0x00 } }, +{ 16, 0xb5d0, 0, {0x3f,0x00,0x0f,0xf0,0x03,0xf0,0x40,0xff,0x00,0x3f,0xc0,0x0f,0xf0,0x03,0xe8,0x06 } }, +{ 16, 0xb5e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfc,0x20,0xcd,0x10,0x39,0xc8 } }, +{ 16, 0xb5f0, 0, {0x0d,0xc1,0x03,0x3c,0x80,0xef,0x90,0x23,0xd8,0x0f,0xf8,0x00,0xfe,0x00,0xcf,0x80 } }, +{ 16, 0xb600, 0, {0x1f,0xd0,0x0f,0xf9,0x03,0xff,0x00,0xe7,0xc0,0x33,0xc4,0x0f,0xf0,0x03,0xb0,0x00 } }, +{ 16, 0xb610, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x10,0xfe,0x02,0x89,0x40,0x23,0xf0 } }, +{ 16, 0xb620, 0, {0x08,0x85,0x10,0x3c,0x00,0x8b,0x00,0xa3,0xdc,0x4b,0xb2,0x82,0xec,0x20,0x8b,0x00 } }, +{ 16, 0xb630, 0, {0x26,0xc0,0x4b,0xb0,0x02,0xec,0x10,0xb9,0x04,0x2a,0xc9,0x0b,0xb5,0x80,0xf0,0x04 } }, +{ 16, 0xb640, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0xcc,0x00,0x81,0x64,0x28,0xc4 } }, +{ 16, 0xb650, 0, {0x09,0xb2,0x0a,0x0c,0xf0,0xa3,0x20,0x20,0xc8,0x0b,0x32,0x02,0xec,0x02,0x83,0x08 } }, +{ 16, 0xb660, 0, {0x2c,0xc8,0x09,0x32,0x02,0xcc,0x80,0xab,0xa0,0x20,0xc8,0x0b,0x32,0x00,0xb2,0x01 } }, +{ 16, 0xb670, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x10,0x89,0x00,0x22,0xc0 } }, +{ 16, 0xb680, 0, {0x08,0xb2,0x12,0x2c,0x02,0x0b,0x00,0x22,0xc0,0x0b,0xb8,0x02,0xec,0x00,0x8b,0x00 } }, +{ 16, 0xb690, 0, {0x26,0xc0,0x4b,0xb0,0x46,0xec,0x00,0xb9,0x00,0x0a,0xc0,0x0b,0xb0,0x02,0xf0,0x04 } }, +{ 16, 0xb6a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x15,0xec,0x10,0xc9,0xe0,0x3a,0xc0 } }, +{ 16, 0xb6b0, 0, {0x0d,0x28,0x03,0x2c,0x00,0xeb,0x10,0x32,0xc0,0x0f,0x82,0x03,0xc4,0x00,0xcb,0x00 } }, +{ 16, 0xb6c0, 0, {0x3e,0xc1,0x0f,0xb0,0x06,0xec,0x08,0xe9,0x00,0xb2,0xc0,0x0f,0xb0,0x13,0x90,0x04 } }, +{ 16, 0xb6d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x9c,0x00,0xf5,0xa0,0x3f,0xc0 } }, +{ 16, 0xb6e0, 0, {0x0f,0xe8,0x03,0xfc,0x08,0xff,0x00,0x3f,0xc0,0x8f,0xc0,0x03,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xb6f0, 0, {0x37,0xc0,0x0f,0xf0,0x03,0xfc,0x00,0xff,0x04,0x3e,0xc0,0x0f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0xb700, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x10,0xac,0x00,0xf9,0x40,0x34,0xc0 } }, +{ 16, 0xb710, 0, {0x0d,0xb4,0x03,0x2c,0x00,0xdb,0x40,0x3e,0xc0,0x2c,0x80,0x03,0x64,0x08,0xfb,0x10 } }, +{ 16, 0xb720, 0, {0x3e,0xc6,0x8f,0xb0,0x03,0xec,0x00,0xf9,0x80,0x32,0xc0,0x0c,0xb0,0x0b,0x14,0x04 } }, +{ 16, 0xb730, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x3e,0x20,0xe9,0xc8,0x37,0xd4 } }, +{ 16, 0xb740, 0, {0x48,0xaa,0x22,0x1c,0x00,0x8b,0x00,0x6f,0xe0,0x08,0x85,0x82,0xed,0x40,0xbb,0x84 } }, +{ 16, 0xb750, 0, {0x2f,0xc0,0x4b,0xb8,0x03,0xad,0x40,0xb3,0x00,0x23,0xd4,0x08,0xf7,0x02,0x32,0x00 } }, +{ 16, 0xb760, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x4c,0x00,0xb1,0x64,0xa4,0xc0 } }, +{ 16, 0xb770, 0, {0x09,0x20,0x0a,0x0c,0x04,0xb8,0x00,0x6c,0xc0,0x08,0x38,0x02,0xc8,0x40,0xb3,0x80 } }, +{ 16, 0xb780, 0, {0x2c,0xd1,0x0b,0x30,0x02,0xcc,0x04,0xb3,0x00,0x28,0xc0,0x08,0x30,0x02,0x3a,0x00 } }, +{ 16, 0xb790, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x01,0x1e,0x00,0xa5,0x80,0x25,0xe0 } }, +{ 16, 0xb7a0, 0, {0x88,0x3a,0x12,0x1e,0x00,0xa6,0x90,0x2d,0xe2,0x08,0x79,0x02,0xda,0x00,0xb7,0x82 } }, +{ 16, 0xb7b0, 0, {0x2d,0xe0,0x03,0x78,0x82,0x9e,0x00,0xbc,0xc1,0x29,0xe0,0x08,0x78,0x02,0x2c,0x10 } }, +{ 16, 0xb7c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x08,0x0c,0x00,0xf3,0x00,0x34,0xc0 } }, +{ 16, 0xb7d0, 0, {0x0d,0x3e,0x03,0x0c,0x00,0xf0,0x40,0x2e,0xc0,0x0c,0x30,0x43,0xc8,0x00,0xf3,0x00 } }, +{ 16, 0xb7e0, 0, {0x3c,0xc0,0x07,0x30,0x03,0xcc,0x80,0xf2,0x00,0x38,0xc0,0x0c,0x30,0x03,0x12,0x02 } }, +{ 16, 0xb7f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x19,0xbd,0x20,0xf7,0x00,0x3f,0xc2 } }, +{ 16, 0xb800, 0, {0x0f,0xf1,0x0b,0xdc,0x20,0xde,0x04,0x3f,0xd2,0x07,0xf0,0x13,0xf8,0x40,0xff,0x00 } }, +{ 16, 0xb810, 0, {0x3f,0xc0,0x07,0xf0,0x03,0xfc,0x00,0xfd,0x00,0x37,0xc0,0x0f,0x70,0x03,0xd0,0x06 } }, +{ 16, 0xb820, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x05,0xcf,0x00,0xdc,0x00,0x3e,0xca } }, +{ 16, 0xb830, 0, {0x0f,0xa0,0x00,0xac,0x92,0xc9,0x00,0x32,0xc0,0x0f,0xb0,0x11,0xa4,0x08,0xfb,0x00 } }, +{ 16, 0xb840, 0, {0x2e,0xc0,0x4f,0xb0,0x23,0xec,0x00,0xf9,0x00,0x3e,0xc4,0x0f,0xb0,0x03,0xea,0x00 } }, +{ 16, 0xb850, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x91,0x9c,0x00,0x84,0x00,0x01,0xc0 } }, +{ 16, 0xb860, 0, {0x4b,0x70,0x22,0x1c,0xc0,0x87,0x00,0x21,0xc0,0x4b,0x70,0x02,0x1c,0x00,0xb7,0x01 } }, +{ 16, 0xb870, 0, {0x25,0xd8,0x0b,0x70,0x22,0xdc,0x00,0xb6,0x00,0x2d,0xc0,0x0b,0x72,0x22,0xf2,0x04 } }, +{ 16, 0xb880, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x9e,0x80,0x97,0x80,0xa9,0xe0 } }, +{ 16, 0xb890, 0, {0x0b,0xf8,0x02,0xce,0x08,0x85,0x80,0x29,0xe8,0x0b,0xfc,0x02,0x17,0x00,0xb7,0x80 } }, +{ 16, 0xb8a0, 0, {0x2d,0xe0,0x8b,0x78,0x02,0xde,0x00,0xb4,0xc0,0x2d,0xe8,0x0b,0x79,0x02,0xe0,0x00 } }, +{ 16, 0xb8b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0x83,0x08,0xa0,0xc0 } }, +{ 16, 0xb8c0, 0, {0x8b,0x3c,0x02,0x4c,0x00,0x83,0x00,0xa0,0xc0,0x1b,0x3c,0x0a,0x0f,0x29,0xb3,0x00 } }, +{ 16, 0xb8d0, 0, {0x24,0xc0,0x0b,0x30,0x02,0xcc,0x00,0xb3,0x80,0x2c,0xc0,0x0b,0x30,0x02,0xd2,0x04 } }, +{ 16, 0xb8e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xde,0x00,0x3a,0x80 } }, +{ 16, 0xb8f0, 0, {0x0f,0xea,0x02,0xe8,0x00,0xce,0x00,0x3a,0x80,0x0f,0xe0,0x03,0x38,0x00,0xfa,0x00 } }, +{ 16, 0xb900, 0, {0x3e,0x80,0x0f,0xa0,0x03,0xe8,0x00,0xfe,0x00,0x3e,0x80,0x0b,0xa0,0x03,0xfa,0x04 } }, +{ 16, 0xb910, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x00,0xf8,0x04,0xba,0x01 } }, +{ 16, 0xb920, 0, {0x0f,0x82,0x0b,0x80,0x04,0xf8,0x80,0x3e,0x00,0x0f,0x86,0x03,0x60,0x00,0xf8,0x00 } }, +{ 16, 0xb930, 0, {0x36,0x00,0x0f,0x80,0x23,0xe1,0x00,0xf8,0x00,0x3e,0x00,0x0f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xb940, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x01,0xf9,0x00,0x32,0x40 } }, +{ 16, 0xb950, 0, {0x0f,0x90,0x03,0xe4,0x00,0x49,0x00,0x32,0x40,0x0b,0x90,0x03,0x24,0x00,0x49,0x00 } }, +{ 16, 0xb960, 0, {0x3c,0x40,0x0d,0x90,0x03,0xe4,0x08,0xc9,0x00,0x3e,0x60,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xb970, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x00,0xb9,0x40,0xa2,0x64 } }, +{ 16, 0xb980, 0, {0x0b,0x18,0x02,0x25,0x00,0xd1,0x50,0x36,0x50,0x4e,0x90,0x0a,0x24,0x02,0x89,0x40 } }, +{ 16, 0xb990, 0, {0x3a,0x51,0x08,0x94,0x02,0xe5,0x22,0x89,0x44,0x2e,0x60,0x28,0x90,0x0a,0x20,0x00 } }, +{ 16, 0xb9a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0x24,0x00,0xb1,0x08,0x22,0x40 } }, +{ 16, 0xb9b0, 0, {0x4b,0x92,0x82,0xa5,0x00,0xa9,0x08,0x22,0x50,0x0a,0x10,0x02,0x0c,0x00,0xa9,0x40 } }, +{ 16, 0xb9c0, 0, {0x6e,0x50,0x0b,0x94,0x02,0xc4,0x04,0x89,0x44,0x6c,0x48,0x88,0x10,0x02,0x46,0x00 } }, +{ 16, 0xb9d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x00,0xb1,0x40,0xe0,0x40 } }, +{ 16, 0xb9e0, 0, {0x1b,0x14,0x0a,0x04,0x00,0xb9,0x00,0x24,0x40,0x1a,0x10,0x22,0x04,0x00,0xa1,0x00 } }, +{ 16, 0xb9f0, 0, {0x28,0x40,0x0a,0x10,0x12,0xc4,0x00,0x81,0x02,0x6c,0x40,0x08,0x12,0x02,0x42,0x01 } }, +{ 16, 0xba00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x08,0xb0,0x00,0x32,0x00 } }, +{ 16, 0xba10, 0, {0x4f,0x80,0x02,0xa1,0x50,0xe0,0x50,0x32,0x14,0x0e,0xa5,0x23,0x21,0x40,0xe8,0x50 } }, +{ 16, 0xba20, 0, {0x3e,0x14,0x0f,0x85,0x03,0xe1,0x40,0xc8,0x50,0x1e,0x14,0x0c,0x85,0x43,0x6e,0x03 } }, +{ 16, 0xba30, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd8,0x19,0xe5,0x00,0xfd,0x40,0x3e,0x50 } }, +{ 16, 0xba40, 0, {0x0f,0x74,0x03,0xa5,0x00,0x5d,0x00,0x3e,0x50,0x0a,0x50,0x13,0xf4,0x00,0xd9,0x00 } }, +{ 16, 0xba50, 0, {0x3a,0x50,0x0d,0x90,0x13,0xe4,0x00,0xff,0x00,0x3e,0x50,0x0f,0x91,0x03,0xa6,0x06 } }, +{ 16, 0xba60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf6,0x90,0xbd,0xe8,0x23,0x6b } }, +{ 16, 0xba70, 0, {0x0b,0xda,0x0b,0x36,0x80,0xc9,0x00,0x32,0x68,0x46,0x90,0x43,0xe4,0x00,0x49,0x00 } }, +{ 16, 0xba80, 0, {0x32,0x68,0x0c,0x90,0x03,0x24,0x40,0xf9,0x00,0x32,0x60,0x0c,0x9c,0x03,0xc6,0x01 } }, +{ 16, 0xba90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x10,0xe1,0x00,0xb8,0xe0,0xa2,0x11 } }, +{ 16, 0xbaa0, 0, {0x0b,0x8e,0x0a,0x23,0x22,0x88,0x80,0x2a,0x31,0x28,0x88,0x02,0x62,0x00,0x88,0x80 } }, +{ 16, 0xbab0, 0, {0xa2,0x30,0x28,0x88,0x8a,0x22,0x00,0xb8,0xa8,0xa2,0x39,0x08,0xca,0x02,0xce,0x04 } }, +{ 16, 0xbac0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x05,0xc5,0x08,0x21,0x00,0x00,0x40 } }, +{ 16, 0xbad0, 0, {0x03,0x14,0x82,0x85,0x80,0xad,0x08,0x21,0x52,0x98,0x50,0x82,0x34,0x23,0x85,0x08 } }, +{ 16, 0xbae0, 0, {0x21,0x52,0x08,0x50,0x06,0x54,0x00,0xb5,0x20,0x21,0x5a,0x09,0x54,0x02,0xd2,0x01 } }, +{ 16, 0xbaf0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x11,0xa4,0x00,0xb9,0x61,0x22,0x40 } }, +{ 16, 0xbb00, 0, {0x0b,0x90,0x06,0x04,0x00,0xad,0x00,0x69,0x40,0x08,0xd0,0x02,0x74,0x00,0x85,0x00 } }, +{ 16, 0xbb10, 0, {0x01,0x40,0x00,0x70,0x06,0x74,0x04,0xb5,0x00,0x23,0x40,0x09,0xd0,0x02,0xc6,0x04 } }, +{ 16, 0xbb20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x14,0xa4,0x00,0xe9,0x00,0x32,0x40 } }, +{ 16, 0xbb30, 0, {0x4f,0x95,0x0b,0xa4,0x00,0xe9,0x00,0x32,0x40,0x8c,0x90,0x03,0x24,0x00,0xc9,0x00 } }, +{ 16, 0xbb40, 0, {0x32,0x40,0x0c,0x90,0x03,0x64,0x08,0xf9,0x00,0x32,0x40,0x3d,0x90,0x03,0xe8,0x04 } }, +{ 16, 0xbb50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x01,0xa4,0x08,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0xbb60, 0, {0x4f,0x90,0x8b,0xe4,0x04,0xd9,0x01,0x3e,0x40,0x0d,0x90,0x03,0x64,0x00,0xd9,0x01 } }, +{ 16, 0xbb70, 0, {0x3e,0x40,0x0f,0x90,0x03,0xa4,0x00,0xf9,0x00,0x3c,0x40,0x0e,0x90,0x03,0xda,0x00 } }, +{ 16, 0xbb80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xf8,0x40,0x36,0x20 } }, +{ 16, 0xbb90, 0, {0x17,0x84,0x03,0x20,0x21,0xc8,0x00,0x7e,0x02,0x2c,0x80,0x43,0x20,0x00,0xe8,0x02 } }, +{ 16, 0xbba0, 0, {0x3e,0x01,0x0f,0x80,0x03,0xe0,0x00,0xc8,0x40,0x1e,0x00,0x0f,0x80,0x03,0xca,0x04 } }, +{ 16, 0xbbb0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x2a,0x88,0xb6,0x02,0x23,0xa0 } }, +{ 16, 0xbbc0, 0, {0x0b,0xec,0x42,0x2b,0x00,0xd2,0x80,0x6e,0xb1,0x08,0xa0,0x22,0x08,0x00,0xea,0x04 } }, +{ 16, 0xbbd0, 0, {0x3a,0x80,0x9f,0xa0,0x03,0xa8,0x00,0x8a,0x04,0x2e,0x80,0x0b,0xa8,0x02,0xca,0x00 } }, +{ 16, 0xbbe0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0xb2,0x00,0xa4,0xe1 } }, +{ 16, 0xbbf0, 0, {0x8b,0xb4,0x32,0x47,0x45,0x83,0x90,0x2c,0xf4,0x4b,0x38,0x12,0x0e,0x44,0xa3,0x01 } }, +{ 16, 0xbc00, 0, {0x2c,0xc0,0x4b,0x30,0x02,0xce,0x00,0x93,0x00,0x6c,0xc0,0x0b,0x38,0x02,0xca,0x00 } }, +{ 16, 0xbc10, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x00,0xb7,0x44,0x21,0xc2 } }, +{ 16, 0xbc20, 0, {0x0b,0x54,0x02,0x54,0x05,0x87,0x00,0x2c,0x40,0x9b,0x6c,0x02,0x18,0x10,0xa7,0x04 } }, +{ 16, 0xbc30, 0, {0x29,0xc0,0x0a,0x70,0x02,0x9b,0x00,0x97,0x04,0x0d,0x80,0x0b,0x60,0x82,0xe8,0x00 } }, +{ 16, 0xbc40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xf3,0x80,0x35,0xe0 } }, +{ 16, 0xbc50, 0, {0x0b,0x38,0x02,0x52,0x10,0x84,0x80,0x2d,0xa0,0x0f,0xf8,0x0b,0x1e,0x00,0xe6,0x80 } }, +{ 16, 0xbc60, 0, {0x1d,0xa0,0x0b,0x68,0x03,0xfe,0x02,0xd6,0x80,0x3d,0xe0,0x0f,0x78,0x03,0xea,0x02 } }, +{ 16, 0xbc70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1d,0xac,0x00,0xfb,0x00,0x3e,0xc1 } }, +{ 16, 0xbc80, 0, {0x8b,0x90,0x0b,0x80,0x0a,0xb8,0x01,0x2e,0x00,0x0c,0xb0,0x03,0xe8,0x00,0xfa,0x00 } }, +{ 16, 0xbc90, 0, {0x3e,0xc0,0x0f,0xa0,0x43,0xec,0x00,0xeb,0x00,0x3e,0x80,0x0f,0xa6,0x23,0xc2,0x02 } }, +{ 16, 0xbca0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfe,0x00,0xfe,0x80,0x33,0x20 } }, +{ 16, 0xbcb0, 0, {0x4e,0xc9,0x12,0xf6,0x50,0xef,0x90,0x3f,0xe0,0x0c,0x19,0x00,0xb6,0x42,0xcf,0x21 } }, +{ 16, 0xbcc0, 0, {0x3f,0xe0,0x0e,0xf9,0x02,0xe6,0xc0,0xff,0x80,0x3f,0xe0,0x4c,0xdc,0x03,0x40,0x00 } }, +{ 16, 0xbcd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x11,0x94,0x00,0xb7,0x00,0x81,0x40 } }, +{ 16, 0xbce0, 0, {0x08,0x03,0x02,0x14,0xc4,0x87,0x01,0x2d,0xc8,0x08,0x6a,0x12,0x38,0x40,0x87,0x02 } }, +{ 16, 0xbcf0, 0, {0x2d,0xc0,0x08,0x71,0x12,0xd2,0x80,0xb7,0x00,0x2d,0x80,0x08,0x60,0x02,0x2a,0x04 } }, +{ 16, 0xbd00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0xb7,0x10,0x21,0x80 } }, +{ 16, 0xbd10, 0, {0x08,0xf4,0x12,0x94,0x04,0xa6,0x00,0x2c,0xc0,0x18,0xd2,0x02,0x14,0x48,0x86,0x10 } }, +{ 16, 0xbd20, 0, {0x2d,0x80,0x0a,0x61,0x32,0xd4,0x00,0xb6,0x18,0x2d,0xc4,0x08,0x58,0x02,0x00,0x10 } }, +{ 16, 0xbd30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xc4,0x00,0xb3,0x00,0x20,0xc0 } }, +{ 16, 0xbd40, 0, {0x40,0xb0,0x22,0x04,0x00,0x82,0x81,0x0c,0xc0,0x08,0x30,0x0a,0x0a,0x00,0x8a,0x00 } }, +{ 16, 0xbd50, 0, {0x2e,0xc0,0x08,0xa0,0x02,0xc4,0x00,0xbb,0x00,0x2e,0x80,0x08,0x20,0x02,0x08,0x04 } }, +{ 16, 0xbd60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xac,0x00,0xfb,0x00,0xa0,0xc0 } }, +{ 16, 0xbd70, 0, {0x24,0x94,0x23,0xac,0x10,0xeb,0xa0,0x0e,0xc0,0x0c,0xb0,0x02,0x2e,0x20,0xc9,0x00 } }, +{ 16, 0xbd80, 0, {0x2e,0x40,0x0e,0x90,0x03,0xec,0x00,0xf9,0x80,0x3e,0x40,0x6c,0xa0,0x0b,0x2a,0x04 } }, +{ 16, 0xbd90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xcc,0x00,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xbda0, 0, {0x89,0x90,0x03,0x2c,0x00,0xfb,0x02,0x3e,0x40,0x4f,0xa0,0x03,0x6d,0x01,0xfb,0x41 } }, +{ 16, 0xbdb0, 0, {0x3e,0xc0,0x8f,0xb4,0x03,0xe8,0x00,0xfb,0x20,0x3e,0x50,0x0f,0xa4,0x03,0xe0,0x00 } }, +{ 16, 0xbdc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xc3,0x20,0xb2,0xc0 } }, +{ 16, 0xbdd0, 0, {0x0d,0xd0,0x03,0x38,0x00,0xcd,0x00,0x3f,0x80,0x0d,0xf0,0x03,0xfc,0x00,0xfd,0x02 } }, +{ 16, 0xbde0, 0, {0x36,0x00,0x0c,0xd0,0x03,0x3f,0x08,0xfc,0x04,0x12,0xc0,0x0c,0xa0,0x03,0xc0,0x44 } }, +{ 16, 0xbdf0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x6c,0x02,0x8b,0xc8,0x22,0xc0 } }, +{ 16, 0xbe00, 0, {0x08,0x98,0x0a,0x2a,0x40,0x89,0x20,0x2e,0x01,0x8e,0xb0,0x12,0xec,0x80,0xbb,0xf0 } }, +{ 16, 0xbe10, 0, {0x22,0xe5,0x08,0xbd,0x02,0x2e,0x00,0xbb,0x90,0x22,0xed,0x08,0xa2,0x02,0xe0,0x00 } }, +{ 16, 0xbe20, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0x8b,0x01,0x22,0x00 } }, +{ 16, 0xbe30, 0, {0x49,0xa8,0x1e,0x04,0x00,0x8b,0x01,0x2e,0xc0,0x49,0x90,0x02,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0xbe40, 0, {0x22,0x40,0x0a,0x90,0x02,0x2c,0x00,0xb9,0x00,0x2a,0x40,0x08,0x80,0x02,0xe0,0x00 } }, +{ 16, 0xbe50, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x00,0x81,0x00,0x20,0x40 } }, +{ 16, 0xbe60, 0, {0x08,0x20,0x02,0x04,0x00,0x83,0x00,0x2c,0xc0,0x0a,0x20,0x42,0xcc,0x00,0xb3,0x00 } }, +{ 16, 0xbe70, 0, {0x20,0xc0,0x02,0x30,0x02,0x08,0x84,0xb3,0x04,0x08,0x40,0x08,0x20,0x02,0xc2,0x11 } }, +{ 16, 0xbe80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0x8b,0x00,0xb2,0x80 } }, +{ 16, 0xbe90, 0, {0x0d,0xb1,0x03,0x24,0x02,0xcb,0x01,0x3e,0xc0,0x4d,0x90,0x43,0xe4,0x00,0xf9,0x00 } }, +{ 16, 0xbea0, 0, {0xb2,0x00,0x2e,0x90,0x0b,0x2c,0x80,0xf8,0x00,0xba,0xc0,0x2c,0x80,0x03,0xc0,0x03 } }, +{ 16, 0xbeb0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xf4,0x00,0x7d,0x00,0x3f,0xc0 } }, +{ 16, 0xbec0, 0, {0x0f,0x72,0x03,0xd4,0x00,0xff,0x00,0x3f,0xc0,0x0e,0xf1,0x47,0xfc,0x00,0xff,0x00 } }, +{ 16, 0xbed0, 0, {0x3b,0xc0,0x0d,0xf0,0x13,0xfc,0x50,0xff,0x00,0x37,0xc0,0x0f,0xe0,0x03,0xe8,0x06 } }, +{ 16, 0xbee0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf0,0xc4,0xcc,0x33,0x3f,0x04 } }, +{ 16, 0xbef0, 0, {0x2c,0xf6,0x03,0x38,0x60,0xcc,0x90,0xb3,0x20,0x0f,0xf1,0x23,0xf0,0x60,0xff,0x01 } }, +{ 16, 0xbf00, 0, {0x23,0xc8,0x0c,0xf2,0x8a,0x3c,0x81,0xdf,0x30,0x3f,0x64,0x0c,0xd8,0x03,0x30,0x04 } }, +{ 16, 0xbf10, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe0,0xc2,0x8a,0x30,0x2e,0x18 } }, +{ 16, 0xbf20, 0, {0x08,0xf5,0x30,0xa5,0x94,0x58,0x22,0x22,0x21,0x4b,0xf3,0x02,0xe1,0x00,0x9f,0x70 } }, +{ 16, 0xbf30, 0, {0x2b,0xe4,0x0a,0xf4,0x12,0x1d,0x40,0xaf,0x72,0x2c,0x49,0x2f,0x30,0x82,0xa0,0x06 } }, +{ 16, 0xbf40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc4,0x80,0x80,0xa0,0x2c,0x98 } }, +{ 16, 0xbf50, 0, {0x08,0x32,0x22,0x08,0x00,0x82,0x00,0x28,0x00,0x03,0x32,0x02,0xc0,0x84,0xb3,0x0c } }, +{ 16, 0xbf60, 0, {0x20,0xc0,0x58,0x32,0x92,0x8c,0x30,0xa3,0x20,0x2e,0xc0,0x48,0x12,0x42,0x62,0x01 } }, +{ 16, 0xbf70, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xa8,0x00,0x8b,0x00,0x2e,0x20 } }, +{ 16, 0xbf80, 0, {0x08,0xb0,0x0a,0x20,0x01,0x98,0x00,0x2a,0x22,0x0b,0xb0,0x02,0xe6,0x00,0x9b,0x00 } }, +{ 16, 0xbf90, 0, {0x22,0xc0,0x0a,0xb0,0x12,0xac,0x04,0xab,0x00,0x2e,0xc0,0x03,0xb0,0x02,0xf0,0x00 } }, +{ 16, 0xbfa0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xe5,0x00,0xc8,0x00,0x3e,0xb0 } }, +{ 16, 0xbfb0, 0, {0x0c,0xb0,0x03,0x29,0x00,0xc8,0x00,0x3a,0x20,0x4f,0xb0,0x03,0xe2,0x20,0xfb,0x01 } }, +{ 16, 0xbfc0, 0, {0xb0,0xc0,0x0c,0xb0,0x03,0x2c,0x00,0xfb,0x02,0x3c,0x41,0x0c,0x90,0x43,0x48,0x04 } }, +{ 16, 0xbfd0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xa2,0x80,0xfe,0x40,0x3e,0x00 } }, +{ 16, 0xbfe0, 0, {0x0f,0xf0,0x63,0xec,0x00,0xbf,0xc4,0x17,0x42,0x0f,0xf0,0x03,0xec,0x00,0xff,0x00 } }, +{ 16, 0xbff0, 0, {0x1f,0xc1,0x0f,0xb0,0x03,0x5c,0x00,0xfb,0x00,0x3f,0x40,0x4f,0xf0,0x00,0xb8,0x00 } }, +{ 16, 0xc000, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xa5,0x02,0xc8,0x00,0x3e,0x90 } }, +{ 16, 0xc010, 0, {0x2c,0xb0,0x0b,0x01,0x06,0xcb,0x01,0x3e,0x50,0x5f,0xb0,0x13,0x21,0x10,0xcb,0x00 } }, +{ 16, 0xc020, 0, {0x7e,0xc0,0x0c,0xb0,0x0b,0x2c,0x00,0xcb,0x00,0x32,0xc0,0x0c,0x90,0x03,0x10,0x04 } }, +{ 16, 0xc030, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x28,0x01,0x8b,0xd0,0x2c,0x34 } }, +{ 16, 0xc040, 0, {0x48,0xff,0x02,0x30,0x00,0xaa,0x04,0x2e,0x69,0x0f,0xf0,0x03,0x68,0x10,0xdf,0x00 } }, +{ 16, 0xc050, 0, {0x2f,0xd4,0x0d,0xf0,0x02,0x3e,0x00,0x5f,0x04,0xb6,0xc0,0x08,0xb0,0x03,0x72,0x00 } }, +{ 16, 0xc060, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x69,0x90,0x81,0x80,0x2c,0x00 } }, +{ 16, 0xc070, 0, {0x48,0xb8,0x02,0x08,0x09,0x99,0x00,0x4c,0xb0,0x0b,0x30,0x02,0x0c,0x00,0x8b,0x00 } }, +{ 16, 0xc080, 0, {0x2c,0xc0,0x09,0xb0,0x40,0x0c,0x40,0x83,0x00,0x00,0x40,0x0a,0x90,0x02,0x30,0x00 } }, +{ 16, 0xc090, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x16,0x00,0x84,0x88,0x2d,0xe4 } }, +{ 16, 0xc0a0, 0, {0x48,0x39,0x02,0x16,0x00,0xb4,0x80,0x2d,0xe0,0x0a,0x7b,0x06,0x5e,0x00,0x97,0x80 } }, +{ 16, 0xc0b0, 0, {0x2d,0xe2,0x09,0x78,0x02,0x1e,0x90,0x97,0x80,0x25,0x64,0x8a,0x78,0x02,0x48,0x00 } }, +{ 16, 0xc0c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0d,0x00,0x81,0x10,0x2c,0x96 } }, +{ 16, 0xc0d0, 0, {0x08,0x31,0x23,0x0c,0x00,0x90,0x20,0x3c,0xc4,0x1b,0xb8,0x02,0x08,0x40,0xc3,0x00 } }, +{ 16, 0xc0e0, 0, {0x2c,0xc4,0x0d,0x30,0x03,0x0e,0x40,0xc3,0x10,0x30,0xc0,0x4e,0x10,0x07,0x1a,0x12 } }, +{ 16, 0xc0f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xbc,0x00,0x7d,0x05,0x3f,0xc5 } }, +{ 16, 0xc100, 0, {0x0f,0xb1,0x0b,0xf4,0x00,0xef,0x00,0x1f,0x45,0x0f,0xf0,0x43,0xfc,0x01,0xff,0x40 } }, +{ 16, 0xc110, 0, {0x3d,0xc4,0x1f,0xf0,0x06,0xfc,0x10,0xff,0x00,0x3b,0xc1,0x2d,0xf1,0x03,0xd0,0x06 } }, +{ 16, 0xc120, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xec,0x04,0xcb,0x04,0x3e,0xa0 } }, +{ 16, 0xc130, 0, {0x44,0xb6,0x03,0x28,0x04,0xcb,0x80,0x32,0x80,0x0f,0xb3,0x93,0x60,0x08,0xfb,0x20 } }, +{ 16, 0xc140, 0, {0x3e,0xd2,0x1f,0xb3,0x03,0x2d,0x80,0xfb,0x61,0x7e,0x40,0x8c,0x98,0x03,0x2a,0x00 } }, +{ 16, 0xc150, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x84,0x0c,0x86,0x05,0x2d,0xc0 } }, +{ 16, 0xc160, 0, {0x08,0xf4,0x82,0x8c,0x90,0x85,0x00,0xa1,0xc0,0x0b,0xf0,0x02,0x5c,0x00,0x37,0x00 } }, +{ 16, 0xc170, 0, {0x2d,0xd0,0x0b,0x71,0x02,0x1c,0xc8,0xb7,0x48,0x2d,0x40,0x0a,0x70,0x02,0x12,0x04 } }, +{ 16, 0xc180, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0x87,0x80,0x2d,0xa1 } }, +{ 16, 0xc190, 0, {0x60,0x78,0x4a,0x16,0xd0,0xa7,0x80,0x29,0xe0,0x0b,0x78,0x52,0x96,0x01,0xb7,0x90 } }, +{ 16, 0xc1a0, 0, {0x2d,0xe8,0x0b,0x7a,0x22,0x5e,0x40,0xb7,0xa0,0x2f,0xe1,0x48,0x50,0x22,0x30,0x00 } }, +{ 16, 0xc1b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x10,0x83,0x84,0x2c,0xc0 } }, +{ 16, 0xc1c0, 0, {0x08,0x30,0x02,0xa4,0x10,0x83,0xcb,0x28,0xe0,0x0b,0x30,0x2a,0x4f,0x40,0x93,0x00 } }, +{ 16, 0xc1d0, 0, {0x2c,0xc0,0x0b,0x30,0x02,0x4c,0x10,0xb3,0x02,0x2c,0xc0,0xaa,0x30,0x02,0x12,0x04 } }, +{ 16, 0xc1e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xb8,0x00,0xce,0xa0,0x3f,0x80 } }, +{ 16, 0xc1f0, 0, {0x4c,0xa0,0x2b,0x3a,0x00,0xce,0x40,0x3b,0xb8,0x0f,0xa0,0x03,0xb9,0x00,0xba,0x00 } }, +{ 16, 0xc200, 0, {0x3e,0x80,0x0f,0xa0,0x03,0x68,0x00,0xfa,0x00,0x7e,0x80,0x1c,0xa0,0x0b,0x3a,0x04 } }, +{ 16, 0xc210, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x02,0xf8,0x00,0x3e,0x04 } }, +{ 16, 0xc220, 0, {0x8f,0x00,0x03,0xe0,0x4a,0xf8,0x10,0x26,0x18,0x0f,0x80,0x03,0xa0,0x80,0xf8,0x02 } }, +{ 16, 0xc230, 0, {0x3e,0x00,0x8f,0x00,0x0b,0xa0,0x00,0xf8,0x02,0x3e,0x00,0x0f,0x80,0x13,0xd2,0x00 } }, +{ 16, 0xc240, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x20,0xc9,0x00,0x32,0x40 } }, +{ 16, 0xc250, 0, {0x4d,0x99,0x03,0x24,0x00,0xc9,0x02,0x3e,0x68,0x0f,0x90,0x02,0x24,0x00,0xe9,0x00 } }, +{ 16, 0xc260, 0, {0x30,0x40,0x8c,0x90,0x03,0x04,0x40,0xc9,0x00,0x3e,0x40,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xc270, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x20,0x89,0x06,0x22,0x50 } }, +{ 16, 0xc280, 0, {0x8b,0x9c,0xc2,0x24,0x00,0xd9,0x01,0x2e,0x40,0x0b,0x90,0x42,0x24,0x08,0xb9,0x01 } }, +{ 16, 0xc290, 0, {0x22,0x46,0x0d,0x90,0x0a,0x26,0x02,0x89,0x00,0x2c,0x40,0x0a,0x10,0x02,0x20,0x00 } }, +{ 16, 0xc2a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0x06,0x00,0x91,0x40,0x42,0x70 } }, +{ 16, 0xc2b0, 0, {0x0b,0x90,0x12,0x2c,0x02,0x8b,0x00,0x2e,0x40,0x0b,0x10,0x22,0xe4,0x10,0xb1,0x00 } }, +{ 16, 0xc2c0, 0, {0xa2,0x40,0x48,0x90,0x12,0x24,0x08,0x99,0x02,0x2e,0x40,0x08,0x90,0x02,0x06,0x00 } }, +{ 16, 0xc2d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x92,0x91,0x20,0xe0,0x48 } }, +{ 16, 0xc2e0, 0, {0x0b,0x12,0x02,0x04,0x02,0x91,0x10,0x2c,0xc0,0x0b,0x10,0x06,0x84,0xc0,0xb1,0x10 } }, +{ 16, 0xc2f0, 0, {0x20,0x48,0x89,0x11,0x02,0x05,0x80,0x91,0x40,0x2e,0x44,0x2a,0x94,0x02,0x02,0x01 } }, +{ 16, 0xc300, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x61,0x40,0xd8,0x50,0x30,0x14 } }, +{ 16, 0xc310, 0, {0x0f,0x85,0x0b,0x21,0xe0,0x80,0x40,0x3e,0x00,0x0f,0x87,0x8b,0xe1,0x0c,0xf8,0x6c } }, +{ 16, 0xc320, 0, {0x32,0x00,0x84,0x06,0x83,0x20,0x04,0xd8,0x28,0x3e,0x10,0x0c,0x00,0x03,0x2e,0x03 } }, +{ 16, 0xc330, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x40,0xad,0x10,0x3f,0x45 } }, +{ 16, 0xc340, 0, {0x0f,0x91,0x03,0xfc,0x18,0x7d,0x20,0x1f,0x41,0x0f,0x90,0x03,0x74,0xc0,0xf9,0x21 } }, +{ 16, 0xc350, 0, {0x3e,0x44,0x0f,0x92,0x01,0xe4,0x40,0xe9,0x00,0x3d,0x48,0x4f,0xd0,0x03,0xe6,0x06 } }, +{ 16, 0xc360, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0xf7,0x80,0xfd,0xe0,0x33,0x70 } }, +{ 16, 0xc370, 0, {0x0c,0xda,0x03,0x26,0x20,0xc9,0x40,0x31,0x40,0x0e,0x9a,0x03,0x24,0x00,0xf9,0x80 } }, +{ 16, 0xc380, 0, {0x3b,0x60,0x0f,0x9c,0x83,0x36,0xa0,0xf9,0xa1,0xb0,0x40,0x0f,0x91,0x03,0xc6,0x00 } }, +{ 16, 0xc390, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe2,0x90,0xb8,0xa0,0x22,0x28 } }, +{ 16, 0xc3a0, 0, {0x28,0x88,0x0a,0x22,0x02,0x88,0xa0,0x22,0x00,0x08,0x88,0x02,0xc2,0x80,0xb8,0x88 } }, +{ 16, 0xc3b0, 0, {0x22,0x04,0x0b,0x8e,0x03,0x22,0x80,0xb8,0xd0,0x2a,0x20,0x0b,0x88,0x02,0xce,0x04 } }, +{ 16, 0xc3c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc5,0x80,0xb1,0x61,0x00,0x58 } }, +{ 16, 0xc3d0, 0, {0x48,0x16,0x8a,0x04,0xa0,0x89,0x01,0x22,0x40,0x1a,0x14,0x88,0x04,0x20,0xb1,0x40 } }, +{ 16, 0xc3e0, 0, {0x28,0x40,0x0b,0x10,0x0a,0x04,0x20,0xb1,0x2c,0x20,0x4a,0x0b,0x12,0x02,0xc2,0x01 } }, +{ 16, 0xc3f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa5,0x90,0xbb,0x40,0x20,0x40 } }, +{ 16, 0xc400, 0, {0x08,0x90,0x02,0x24,0x40,0x89,0x42,0x62,0x58,0x08,0x10,0x02,0xe5,0x00,0xb9,0x03 } }, +{ 16, 0xc410, 0, {0x22,0xc0,0x0b,0x90,0x02,0xa4,0x14,0x31,0x00,0x2a,0x44,0x0b,0x90,0x02,0xc6,0x04 } }, +{ 16, 0xc420, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0xa5,0x00,0xf9,0x01,0x32,0x40 } }, +{ 16, 0xc430, 0, {0x8c,0x90,0x03,0x27,0x00,0xc1,0x94,0x30,0x40,0x0e,0x90,0x03,0x24,0x00,0xf9,0x00 } }, +{ 16, 0xc440, 0, {0x3a,0x40,0x0f,0x90,0x03,0x24,0x00,0xf9,0x00,0x32,0x60,0x07,0x90,0x27,0xe8,0x05 } }, +{ 16, 0xc450, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0xa4,0x18,0xf9,0x00,0xbe,0x44 } }, +{ 16, 0xc460, 0, {0x0f,0x90,0x03,0xc4,0x00,0xf9,0x00,0xbe,0x61,0x8f,0x90,0x03,0xa4,0x00,0xf1,0x00 } }, +{ 16, 0xc470, 0, {0x1e,0x40,0x0f,0x10,0x03,0x24,0x08,0xf9,0x00,0x7e,0x40,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0xc480, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa1,0x81,0xf8,0x00,0x32,0x04 } }, +{ 16, 0xc490, 0, {0x0c,0x00,0xd3,0x21,0x00,0xd8,0x04,0x3a,0x14,0x9c,0x80,0x03,0x21,0x01,0xc8,0x00 } }, +{ 16, 0xc4a0, 0, {0x36,0x00,0x0c,0x80,0x13,0x20,0x10,0xc8,0x00,0x32,0x00,0x2c,0x80,0x03,0xca,0x04 } }, +{ 16, 0xc4b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x04,0x3a,0x00,0xbe,0x84,0x23,0x85 } }, +{ 16, 0xc4c0, 0, {0x08,0xec,0x83,0x68,0x04,0x8a,0x00,0x2f,0x90,0x4d,0xa0,0x02,0x28,0x01,0xda,0x00 } }, +{ 16, 0xc4d0, 0, {0x23,0xb0,0x0a,0xa0,0x02,0x2a,0x08,0xda,0x01,0x22,0x80,0x0f,0xa0,0x02,0xca,0x00 } }, +{ 16, 0xc4e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x00,0xbb,0xf0,0x20,0xc0 } }, +{ 16, 0xc4f0, 0, {0x08,0x3c,0x0a,0x0c,0x00,0x93,0x01,0x28,0xc8,0x89,0x30,0x06,0x4c,0x00,0x83,0x02 } }, +{ 16, 0xc500, 0, {0x2c,0xf6,0x08,0x30,0x02,0x04,0x00,0xa3,0x00,0x20,0xc0,0x0a,0x30,0x02,0xca,0x00 } }, +{ 16, 0xc510, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1d,0x11,0xb3,0x00,0xa0,0xc0 } }, +{ 16, 0xc520, 0, {0x08,0x50,0x02,0x5c,0x10,0x87,0x01,0x6d,0x81,0x49,0x32,0x52,0x1e,0xc3,0x87,0x00 } }, +{ 16, 0xc530, 0, {0x28,0xe0,0x0a,0x32,0x26,0x1f,0x00,0x37,0x00,0x23,0xe0,0x0b,0x72,0x02,0xc8,0x00 } }, +{ 16, 0xc540, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x08,0x12,0x00,0xb7,0x82,0x31,0x20 } }, +{ 16, 0xc550, 0, {0x08,0x08,0x37,0x0f,0x08,0xd7,0xe0,0x39,0x60,0x19,0x7a,0x0b,0x5e,0x0c,0x83,0xb2 } }, +{ 16, 0xc560, 0, {0x7d,0xe0,0x0c,0x7a,0x0b,0x3e,0x02,0xaf,0xa0,0xb1,0xe0,0x0e,0x7a,0x03,0xca,0x02 } }, +{ 16, 0xc570, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xa0,0x10,0xfb,0x00,0x3e,0xc0 } }, +{ 16, 0xc580, 0, {0x6f,0xb0,0x43,0xec,0x11,0xfb,0x00,0x3e,0x40,0x0f,0xb5,0x03,0xec,0x20,0xfb,0x50 } }, +{ 16, 0xc590, 0, {0x36,0x00,0x0f,0xb5,0x43,0xe5,0xa1,0xdb,0x78,0x3e,0xc0,0x0f,0xb4,0x03,0xc2,0x06 } }, +{ 16, 0xc5a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x05,0xfe,0x00,0xff,0xa0,0x3f,0xa0 } }, +{ 16, 0xc5b0, 0, {0x0d,0xc9,0x13,0x3e,0x00,0xcf,0xd0,0x3d,0xe8,0x02,0xff,0x13,0x3e,0x00,0xcf,0x82 } }, +{ 16, 0xc5c0, 0, {0x3f,0x60,0x0c,0xfc,0x23,0x3e,0x10,0xef,0x80,0x33,0xf2,0x0c,0xfc,0x83,0x10,0x00 } }, +{ 16, 0xc5d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x40,0xb5,0x01,0x2d,0xd0 } }, +{ 16, 0xc5e0, 0, {0x08,0x58,0x02,0x1c,0x40,0x57,0x10,0x2d,0x5a,0x28,0x31,0x02,0xbc,0x01,0x97,0x10 } }, +{ 16, 0xc5f0, 0, {0x2d,0x00,0x0a,0x70,0x02,0x84,0x04,0xcf,0x00,0x29,0xc0,0x0a,0xf0,0x02,0x2a,0x04 } }, +{ 16, 0xc600, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0xb7,0x2a,0x2d,0x82 } }, +{ 16, 0xc610, 0, {0x08,0x42,0x22,0x3c,0x00,0x87,0x11,0x0d,0xcc,0x88,0x32,0x02,0x1d,0x00,0x97,0x00 } }, +{ 16, 0xc620, 0, {0x2c,0xc4,0x08,0x30,0x02,0x14,0x00,0xa7,0x00,0x23,0xc0,0x09,0x70,0x82,0x00,0x00 } }, +{ 16, 0xc630, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x14,0xc0,0x20,0xb0,0x20,0x2c,0x50 } }, +{ 16, 0xc640, 0, {0x08,0x10,0x02,0x2d,0xc0,0x93,0xe2,0x2c,0x21,0x08,0x30,0x02,0x0e,0x08,0x93,0x00 } }, +{ 16, 0xc650, 0, {0x2c,0x40,0x0a,0x30,0x02,0x8c,0x00,0x93,0x00,0x2a,0xc0,0x0b,0x30,0x02,0x18,0x04 } }, +{ 16, 0xc660, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xac,0x00,0xf8,0xc0,0x3e,0x80 } }, +{ 16, 0xc670, 0, {0x2c,0xa0,0x0b,0x3f,0x00,0xc7,0x60,0x3e,0xd0,0x0c,0xf0,0x0b,0x3c,0x00,0xcf,0x00 } }, +{ 16, 0xc680, 0, {0x3e,0x80,0x0c,0xf0,0x0b,0x2c,0x00,0xef,0x00,0x33,0xc1,0x0d,0xf0,0x0b,0x2a,0x04 } }, +{ 16, 0xc690, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x40,0xf3,0x40,0x3e,0x50 } }, +{ 16, 0xc6a0, 0, {0x8e,0xb4,0x03,0xec,0x10,0xfb,0x00,0x3e,0x09,0x0f,0xb0,0x13,0xec,0x42,0xeb,0x00 } }, +{ 16, 0xc6b0, 0, {0x3c,0x00,0x8f,0xb0,0x13,0xc4,0x11,0xe3,0x00,0x3e,0xc0,0x0e,0xb0,0x03,0xe0,0x00 } }, +{ 16, 0xc6c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xfc,0x80,0x31,0x22 } }, +{ 16, 0xc6d0, 0, {0x0c,0xa8,0x03,0x3c,0x00,0xcf,0x00,0x33,0xa0,0x0e,0xf0,0x03,0xdc,0x00,0xcf,0x00 } }, +{ 16, 0xc6e0, 0, {0x1f,0xf0,0x0c,0xf0,0x03,0xf4,0x00,0xcf,0x02,0x33,0xc0,0x0c,0xf0,0x02,0x00,0x54 } }, +{ 16, 0xc6f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6f,0x00,0xbb,0xc0,0x22,0x70 } }, +{ 16, 0xc700, 0, {0x0a,0xb9,0x42,0x2c,0x10,0x8b,0x00,0x76,0x11,0x83,0xb0,0x02,0xec,0x10,0xab,0x00 } }, +{ 16, 0xc710, 0, {0x2e,0xb0,0x0a,0xb0,0x03,0xec,0x04,0x8b,0x00,0xa2,0xc0,0x28,0xb0,0x02,0x20,0x40 } }, +{ 16, 0xc720, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x65,0x40,0xb8,0x20,0x22,0x44 } }, +{ 16, 0xc730, 0, {0x58,0x34,0x0a,0x2c,0x00,0x8b,0x00,0x22,0x84,0x4b,0xb0,0x02,0xec,0x00,0x8b,0x00 } }, +{ 16, 0xc740, 0, {0x6e,0xc0,0x08,0xb0,0x42,0xe6,0x04,0x8b,0x00,0x02,0xc0,0x08,0x30,0x02,0xa0,0x01 } }, +{ 16, 0xc750, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0xb1,0x00,0x20,0xc0 } }, +{ 16, 0xc760, 0, {0x0a,0x30,0x0a,0x0c,0x00,0x8b,0x03,0x24,0x80,0x0b,0x30,0x02,0xcc,0x00,0xa3,0x00 } }, +{ 16, 0xc770, 0, {0x6c,0x00,0x0a,0x30,0x02,0x8d,0x00,0x83,0x00,0x20,0xc0,0x18,0x30,0x02,0x82,0x00 } }, +{ 16, 0xc780, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x64,0x00,0xf8,0x00,0x30,0x00 } }, +{ 16, 0xc790, 0, {0x4c,0xa0,0x0b,0x2c,0x02,0xcf,0x00,0x22,0x40,0x0e,0xf5,0x03,0xfc,0x00,0xcf,0x01 } }, +{ 16, 0xc7a0, 0, {0x3e,0x00,0x0c,0xf0,0x12,0xdd,0x02,0xcf,0x02,0x33,0xc0,0x4c,0xf0,0x0b,0x80,0x03 } }, +{ 16, 0xc7b0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x19,0xf0,0x00,0xfc,0x00,0x3f,0x40 } }, +{ 16, 0xc7c0, 0, {0x0f,0xb1,0x03,0xdc,0x00,0xbf,0x01,0x3f,0x00,0x0f,0xf2,0x23,0xfc,0x10,0xff,0x00 } }, +{ 16, 0xc7d0, 0, {0x3f,0x00,0x0f,0xf0,0x01,0xf4,0x84,0xff,0x00,0x3d,0xc0,0x4f,0xf0,0x13,0x68,0x06 } }, +{ 16, 0xc7e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xfe,0x40,0xdf,0x80,0x33,0xc8 } }, +{ 16, 0xc7f0, 0, {0x0c,0xf8,0x03,0x3c,0x0a,0x9f,0xc0,0x3f,0xf0,0x08,0xb8,0x02,0x3e,0x00,0xff,0x80 } }, +{ 16, 0xc800, 0, {0x3f,0xd8,0x0c,0xf9,0x61,0x2e,0x40,0x6f,0x90,0x3f,0xe4,0x8f,0xf1,0x83,0x30,0x00 } }, +{ 16, 0xc810, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xec,0x04,0x8b,0x80,0x23,0xf0 } }, +{ 16, 0xc820, 0, {0x08,0xb8,0x02,0x3d,0x40,0xab,0x00,0x0e,0x08,0x48,0x22,0x82,0x6c,0x20,0xbb,0x00 } }, +{ 16, 0xc830, 0, {0x2f,0xd0,0x48,0xb0,0x02,0x2c,0x00,0xbb,0x00,0x2e,0xc1,0x0b,0xb0,0x02,0x30,0x04 } }, +{ 16, 0xc840, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xcc,0x02,0x83,0x01,0xa0,0xc5 } }, +{ 16, 0xc850, 0, {0x08,0xb0,0x4a,0x4c,0xa0,0x80,0x24,0x28,0xc8,0x09,0x32,0x02,0x4c,0x00,0xb3,0x08 } }, +{ 16, 0xc860, 0, {0x2e,0xd1,0x29,0xb2,0x3a,0x0c,0x84,0xa3,0x21,0x2c,0xc8,0x4b,0xb2,0x0a,0x32,0x01 } }, +{ 16, 0xc870, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x08,0x8b,0x00,0x22,0xc0 } }, +{ 16, 0xc880, 0, {0x08,0xb0,0x02,0x4c,0x00,0x88,0x21,0x24,0x21,0x09,0xb0,0x46,0x6c,0x00,0xbb,0x06 } }, +{ 16, 0xc890, 0, {0x2e,0xc0,0x09,0xb0,0x02,0x2c,0x10,0xbb,0x00,0x2e,0xc0,0x0b,0xb0,0x02,0x30,0x04 } }, +{ 16, 0xc8a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xcb,0x00,0x32,0xc0 } }, +{ 16, 0xc8b0, 0, {0x0c,0xb9,0x02,0x6c,0x00,0xcb,0xc8,0x3a,0xc0,0x2d,0x90,0x0b,0x2c,0x08,0xfb,0x00 } }, +{ 16, 0xc8c0, 0, {0x3e,0xc0,0x0d,0x30,0x42,0x2c,0x00,0xeb,0x00,0x3e,0xc0,0x0f,0xb0,0x13,0x00,0x04 } }, +{ 16, 0xc8d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xbc,0x00,0xef,0x00,0x3d,0xc0 } }, +{ 16, 0xc8e0, 0, {0x0f,0xf0,0x03,0xbc,0x06,0xef,0x82,0x3f,0x40,0x4e,0xc9,0x83,0xbc,0x00,0xff,0x00 } }, +{ 16, 0xc8f0, 0, {0x7f,0xc0,0x1c,0xf0,0x13,0x7c,0x00,0xff,0x04,0x3f,0xc0,0x0f,0xf0,0x03,0xf8,0x00 } }, +{ 16, 0xc900, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xfb,0x02,0x3e,0xc0 } }, +{ 16, 0xc910, 0, {0x0e,0xb0,0x03,0xac,0x20,0xd8,0x40,0x3e,0xc0,0x8c,0x90,0x0b,0x2c,0x00,0xfb,0x00 } }, +{ 16, 0xc920, 0, {0x3e,0xc9,0x0d,0xb0,0x33,0xec,0x08,0xfb,0x02,0x3e,0xc0,0x0f,0xb0,0x0b,0x54,0x04 } }, +{ 16, 0xc930, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2c,0x00,0xb3,0x00,0x2f,0xc0 } }, +{ 16, 0xc940, 0, {0x0b,0x30,0x12,0xfc,0x00,0x88,0xa0,0x2e,0x40,0x28,0x94,0x02,0x2c,0x10,0xbb,0x04 } }, +{ 16, 0xc950, 0, {0x2d,0xc0,0x28,0xb0,0x02,0xec,0x00,0xbb,0x00,0x2e,0xc0,0x0b,0x72,0x06,0x32,0x00 } }, +{ 16, 0xc960, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x6c,0x00,0xb3,0x00,0x2c,0xe0 } }, +{ 16, 0xc970, 0, {0x0a,0x10,0x02,0xcd,0x00,0x93,0x00,0x2c,0xc0,0x08,0xb0,0x02,0x4c,0x00,0xb3,0x00 } }, +{ 16, 0xc980, 0, {0x28,0xc0,0x08,0x30,0x02,0xcc,0x00,0xb3,0x00,0x2c,0xc0,0x0b,0x30,0x02,0x3a,0x00 } }, +{ 16, 0xc990, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x1e,0x40,0xb7,0x80,0x2d,0xe2 } }, +{ 16, 0xc9a0, 0, {0x0b,0x58,0x02,0xde,0x02,0x97,0x81,0x2f,0xa0,0x08,0x68,0x02,0x5e,0x00,0xb7,0x81 } }, +{ 16, 0xc9b0, 0, {0x2f,0xe0,0x08,0x79,0x02,0xde,0x00,0xb7,0x81,0x2d,0xe0,0x0b,0x78,0x02,0x3c,0x00 } }, +{ 16, 0xc9c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x0c,0x00,0xf3,0x00,0x3c,0xc0 } }, +{ 16, 0xc9d0, 0, {0x0e,0x32,0x03,0xcc,0x80,0xd3,0x00,0x3c,0xc4,0x0c,0x39,0x03,0x4c,0x08,0xf3,0x1a } }, +{ 16, 0xc9e0, 0, {0x3c,0xc6,0x0d,0x30,0x03,0xce,0x20,0xf3,0x08,0x3c,0xc0,0x0f,0x30,0x03,0x52,0x02 } }, +{ 16, 0xc9f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x1d,0xac,0x00,0xfb,0x00,0x2e,0xc0 } }, +{ 16, 0xca00, 0, {0x0b,0xb0,0x03,0xcc,0x20,0xeb,0x00,0x3c,0x80,0x0f,0xb0,0x41,0xac,0x00,0xfb,0x00 } }, +{ 16, 0xca10, 0, {0x3c,0xc2,0x0f,0xb0,0x03,0xec,0x40,0xfb,0x00,0x3e,0xc0,0x0f,0x30,0x03,0xd0,0x06 } }, +{ 16, 0xca20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xee,0x02,0xc3,0x80,0x30,0xce } }, +{ 16, 0xca30, 0, {0x0d,0x98,0x03,0xac,0xa0,0xc3,0x80,0xb2,0xc0,0x0f,0xb0,0x03,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xca40, 0, {0x3e,0xd2,0x4f,0xb0,0x09,0x2e,0x08,0x4b,0x01,0x3e,0xc0,0x24,0xb0,0x03,0xea,0x00 } }, +{ 16, 0xca50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x9c,0x00,0x87,0x01,0x21,0xc0 } }, +{ 16, 0xca60, 0, {0x48,0x50,0x12,0x4c,0x00,0x87,0x00,0x35,0xc0,0x4b,0x60,0x02,0xdc,0x04,0xb7,0x01 } }, +{ 16, 0xca70, 0, {0x2d,0xc0,0x0b,0x70,0x02,0x1c,0x00,0x87,0x00,0x2d,0xc1,0x0c,0x72,0x02,0xf2,0x04 } }, +{ 16, 0xca80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0x87,0x80,0x23,0xe0 } }, +{ 16, 0xca90, 0, {0x08,0xf8,0x02,0xde,0x80,0x8f,0x81,0x21,0xe0,0x4b,0x78,0x12,0xde,0x04,0x37,0x80 } }, +{ 16, 0xcaa0, 0, {0x2d,0xe8,0x0b,0xf8,0x02,0x3e,0x18,0x87,0x80,0x2f,0xe0,0x09,0x79,0x02,0xe0,0x00 } }, +{ 16, 0xcab0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x00,0x83,0x00,0xa0,0xc0 } }, +{ 16, 0xcac0, 0, {0x28,0x30,0x42,0x4c,0x00,0x83,0x00,0x24,0xc0,0x0b,0x38,0x06,0xcc,0x04,0xb3,0x00 } }, +{ 16, 0xcad0, 0, {0x2c,0xc0,0x0b,0x30,0x02,0x0c,0x02,0x83,0x00,0x2c,0xc0,0x08,0x30,0x02,0xd2,0x04 } }, +{ 16, 0xcae0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xa8,0x00,0xca,0x00,0x31,0x80 } }, +{ 16, 0xcaf0, 0, {0x08,0xe0,0x02,0x98,0x02,0xce,0x00,0x33,0x84,0x0b,0xea,0x03,0xe8,0x00,0xba,0x00 } }, +{ 16, 0xcb00, 0, {0x3f,0x81,0x0f,0xa0,0x03,0x28,0x00,0xca,0x00,0x3e,0x80,0x0d,0xe0,0x03,0xfa,0x04 } }, +{ 16, 0xcb10, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x00,0xf8,0x00,0x3e,0x00 } }, +{ 16, 0xcb20, 0, {0x0e,0x84,0x23,0xa0,0x00,0xf8,0x00,0x3a,0x10,0x0f,0x80,0x03,0xe0,0x00,0xf8,0x00 } }, +{ 16, 0xcb30, 0, {0x3e,0x10,0x0f,0x80,0x13,0xe0,0x00,0xf8,0x00,0x3e,0x00,0x0d,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xcb40, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0xe4,0x01,0xf9,0x00,0x3e,0x40 } }, +{ 16, 0xcb50, 0, {0x0c,0x9a,0x13,0xe4,0x00,0xc9,0x00,0x3e,0x40,0x0c,0x98,0x23,0xe4,0x80,0xf9,0x00 } }, +{ 16, 0xcb60, 0, {0x3e,0x40,0x2c,0x98,0x03,0x64,0x00,0xf9,0x00,0x3e,0x40,0x0c,0x90,0x03,0xc2,0x04 } }, +{ 16, 0xcb70, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x04,0xb9,0x00,0x2e,0x40 } }, +{ 16, 0xcb80, 0, {0x68,0x9c,0x22,0xe4,0x02,0x89,0x01,0x7c,0x50,0x8d,0x98,0x22,0xe4,0x80,0xb9,0x20 } }, +{ 16, 0xcb90, 0, {0x2e,0x50,0x48,0x10,0x0b,0x25,0x00,0xb9,0x44,0x2c,0x40,0x28,0x90,0x00,0xe0,0x00 } }, +{ 16, 0xcba0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb9,0x00,0x2e,0x50 } }, +{ 16, 0xcbb0, 0, {0x08,0x90,0x02,0xe4,0x04,0x89,0x00,0x2e,0x50,0x0a,0x92,0x02,0xe4,0x00,0xb9,0x00 } }, +{ 16, 0xcbc0, 0, {0x2c,0x40,0x08,0x91,0x02,0x24,0x00,0xb9,0x00,0x2e,0x40,0x08,0x90,0x02,0xc6,0x00 } }, +{ 16, 0xcbd0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x05,0x00,0xb1,0x01,0x2c,0x40 } }, +{ 16, 0xcbe0, 0, {0x48,0x30,0x02,0xe4,0x00,0x81,0x00,0x2a,0x40,0x4b,0x10,0x02,0xc4,0x00,0xb1,0x00 } }, +{ 16, 0xcbf0, 0, {0x0c,0xc0,0x08,0x90,0x02,0x0c,0x00,0xb3,0x00,0x2e,0x40,0x48,0x12,0x02,0xc2,0x01 } }, +{ 16, 0xcc00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x60,0x00,0xb8,0x01,0x3e,0x00 } }, +{ 16, 0xcc10, 0, {0x1c,0x80,0x07,0xe1,0x50,0xc8,0x50,0x2e,0x14,0x1e,0x85,0x03,0xe1,0x41,0xf8,0x50 } }, +{ 16, 0xcc20, 0, {0x3e,0x14,0x0c,0x85,0x13,0x21,0x48,0xf8,0x50,0x3e,0x14,0x0c,0x85,0x43,0xee,0x03 } }, +{ 16, 0xcc30, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x19,0xc4,0x00,0xf9,0x00,0x3e,0x51 } }, +{ 16, 0xcc40, 0, {0x0f,0x50,0x03,0xe5,0x00,0xfd,0x00,0x3f,0x40,0x1d,0xd0,0x03,0xf4,0x10,0xf9,0x00 } }, +{ 16, 0xcc50, 0, {0x3e,0x50,0x0f,0x50,0x00,0x94,0x00,0xf9,0x00,0x3d,0x40,0x0f,0x91,0x03,0xe6,0x06 } }, +{ 16, 0xcc60, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0xe4,0x50,0xcd,0x00,0x31,0x60 } }, +{ 16, 0xcc70, 0, {0x04,0xd0,0x03,0x36,0x80,0xc1,0x42,0x2e,0x50,0x1f,0x94,0x03,0xe5,0x00,0xe9,0x02 } }, +{ 16, 0xcc80, 0, {0x2e,0x72,0x0a,0x90,0x22,0x05,0x08,0xe9,0x40,0x3e,0x50,0x40,0x9c,0x03,0x26,0x00 } }, +{ 16, 0xcc90, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xc2,0x82,0x88,0x00,0x22,0x15 } }, +{ 16, 0xcca0, 0, {0x08,0x80,0x02,0x23,0x58,0x88,0xa0,0x2e,0x28,0x0b,0xaa,0x42,0xe2,0x82,0x88,0x80 } }, +{ 16, 0xccb0, 0, {0x2e,0x38,0x28,0x88,0x02,0x22,0x80,0xb8,0xa0,0x3a,0x28,0x08,0xcd,0x02,0x0e,0x04 } }, +{ 16, 0xccc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0x81,0x00,0xa6,0x40 } }, +{ 16, 0xccd0, 0, {0x28,0x10,0x0a,0x24,0x26,0x95,0x00,0x0d,0x40,0x0b,0x50,0x02,0x74,0x00,0x85,0x08 } }, +{ 16, 0xcce0, 0, {0x2f,0x40,0x79,0xd2,0xaa,0x14,0x00,0xa5,0x01,0x2f,0x40,0x38,0x50,0x02,0x12,0x01 } }, +{ 16, 0xccf0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x04,0x89,0x00,0x26,0x40 } }, +{ 16, 0xcd00, 0, {0x08,0x91,0x02,0x24,0x10,0x9d,0x08,0x2f,0x40,0x0b,0xd0,0x02,0xf4,0x00,0x8d,0x02 } }, +{ 16, 0xcd10, 0, {0x2f,0x40,0x09,0xd0,0x00,0x34,0x00,0xbd,0x00,0x0b,0x40,0x18,0x70,0x02,0x06,0x04 } }, +{ 16, 0xcd20, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xc4,0x00,0xc9,0x05,0x36,0x41 } }, +{ 16, 0xcd30, 0, {0x4c,0x90,0x63,0x24,0x00,0xd9,0x00,0x3e,0x40,0x0b,0x90,0x03,0x44,0x08,0xc9,0x00 } }, +{ 16, 0xcd40, 0, {0x3e,0x40,0x15,0x10,0x03,0x24,0x00,0xe9,0x00,0x3c,0x40,0x0c,0x90,0x03,0x28,0x04 } }, +{ 16, 0xcd50, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0xa4,0x04,0xf9,0x00,0x3a,0x40 } }, +{ 16, 0xcd60, 0, {0x4f,0x98,0x03,0xe4,0x00,0xe9,0x99,0x3e,0x40,0x4f,0x90,0x03,0xe4,0x20,0xf9,0x0a } }, +{ 16, 0xcd70, 0, {0x3e,0x40,0x0e,0x90,0x43,0x64,0x24,0xf9,0x08,0x3a,0x42,0x0f,0x90,0x8b,0xda,0x00 } }, +{ 16, 0xcd80, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xc8,0x00,0x12,0x00 } }, +{ 16, 0xcd90, 0, {0x0c,0x80,0x43,0xe0,0x00,0xc8,0x40,0x32,0x00,0x0f,0x84,0x53,0xe0,0x10,0xf8,0x00 } }, +{ 16, 0xcda0, 0, {0x3e,0x00,0x0d,0x80,0x23,0x20,0x00,0xd8,0x00,0x3e,0x00,0x0f,0x80,0x03,0x0a,0x04 } }, +{ 16, 0xcdb0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x38,0x02,0x82,0x00,0xa1,0x88 } }, +{ 16, 0xcdc0, 0, {0x08,0x60,0x22,0xc8,0x00,0x8a,0x40,0x36,0xa1,0x0b,0xa0,0x02,0xe9,0x10,0xba,0x44 } }, +{ 16, 0xcdd0, 0, {0x2c,0x80,0x0c,0xa4,0x12,0x29,0x02,0x8a,0x44,0x2e,0x98,0x0b,0xa4,0x02,0x0a,0x00 } }, +{ 16, 0xcde0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4c,0x10,0x83,0x00,0x20,0xe0 } }, +{ 16, 0xcdf0, 0, {0x18,0x30,0x92,0xc4,0x08,0x93,0x40,0x20,0xe0,0x0b,0x30,0x02,0xcd,0x00,0xb3,0x40 } }, +{ 16, 0xce00, 0, {0x2c,0xc0,0x0b,0x3a,0x42,0xcd,0x00,0x83,0x40,0x2c,0xd0,0x0b,0x38,0x02,0x4a,0x00 } }, +{ 16, 0xce10, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x41,0x1c,0x00,0x87,0x00,0x21,0xc0 } }, +{ 16, 0xce20, 0, {0x28,0x70,0x02,0xd1,0x00,0x9d,0x80,0x25,0xc2,0x4b,0x60,0x02,0xdc,0x08,0xb7,0x02 } }, +{ 16, 0xce30, 0, {0x2c,0xc0,0x0a,0x74,0x02,0xfe,0x00,0x87,0x00,0x2d,0xc0,0x0b,0x34,0x02,0x68,0x00 } }, +{ 16, 0xce40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x1e,0x00,0xc7,0x84,0x31,0xe0 } }, +{ 16, 0xce50, 0, {0x0c,0x68,0x03,0xd6,0x00,0x97,0x80,0x31,0xa0,0x0f,0x58,0x13,0xde,0x08,0xf7,0x82 } }, +{ 16, 0xce60, 0, {0x3d,0xa0,0x0f,0xf8,0x0b,0xde,0x00,0xc7,0x80,0x3d,0xe0,0x0f,0x78,0x8b,0x6a,0x02 } }, +{ 16, 0xce70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xad,0x80,0xf3,0x00,0x3e,0xc1 } }, +{ 16, 0xce80, 0, {0x0f,0xa0,0x23,0xc0,0x02,0xe9,0x00,0x3e,0x81,0x0f,0x80,0x03,0xec,0x00,0xfb,0x00 } }, +{ 16, 0xce90, 0, {0x3e,0xc0,0x0d,0xb0,0x13,0x2c,0x00,0xeb,0x00,0x3e,0xc0,0x0f,0xb0,0x03,0x82,0x02 } }, +{ 16, 0xcea0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xff,0x32,0xc7,0x80,0x33,0x60 } }, +{ 16, 0xceb0, 0, {0x0f,0x78,0x03,0x3e,0xc8,0x4e,0x80,0x23,0x64,0x0c,0xf8,0x03,0x3a,0x00,0xce,0x80 } }, +{ 16, 0xcec0, 0, {0x13,0xec,0x06,0xd8,0x03,0x3a,0x00,0xde,0x80,0x33,0xa4,0x0c,0xc8,0x03,0xd0,0x00 } }, +{ 16, 0xced0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0x9c,0x00,0x87,0x10,0x01,0xc0 } }, +{ 16, 0xcee0, 0, {0x0b,0x70,0x02,0x18,0x50,0x84,0x00,0x2b,0x44,0x08,0x60,0x12,0x98,0x00,0x86,0x13 } }, +{ 16, 0xcef0, 0, {0x21,0xc4,0x88,0x50,0x02,0x18,0x80,0x86,0x00,0x21,0x80,0x08,0x61,0x02,0xea,0x04 } }, +{ 16, 0xcf00, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0x87,0x00,0x21,0x40 } }, +{ 16, 0xcf10, 0, {0x0b,0xf1,0x02,0x5c,0x80,0x06,0x00,0x21,0x00,0x88,0xd0,0x02,0x5c,0x00,0x87,0x00 } }, +{ 16, 0xcf20, 0, {0x20,0x89,0x8a,0xf1,0x02,0x1c,0x08,0x87,0x10,0x21,0x81,0x88,0x48,0x02,0xc6,0x00 } }, +{ 16, 0xcf30, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x10,0x83,0x04,0xa0,0xc1 } }, +{ 16, 0xcf40, 0, {0x0b,0x30,0x0a,0x48,0x0c,0x88,0x06,0x60,0x38,0x08,0x04,0x42,0xec,0x01,0x8b,0x04 } }, +{ 16, 0xcf50, 0, {0x22,0xc1,0x08,0x30,0x0a,0x2c,0x00,0x8b,0x00,0x22,0x80,0x00,0x20,0x02,0xd8,0x04 } }, +{ 16, 0xcf60, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xbc,0x00,0xc3,0x00,0x22,0x80 } }, +{ 16, 0xcf70, 0, {0x8f,0x90,0x03,0x64,0x0a,0xcb,0x02,0xb2,0xf2,0x20,0x35,0x12,0x64,0x0a,0xc9,0x00 } }, +{ 16, 0xcf80, 0, {0xb2,0x40,0x0e,0xa0,0x03,0x24,0x0a,0xc9,0x00,0xa2,0x40,0x2c,0xa0,0x03,0xee,0x04 } }, +{ 16, 0xcf90, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xec,0x00,0xfb,0x00,0x3c,0x80 } }, +{ 16, 0xcfa0, 0, {0x0f,0x90,0x03,0xa5,0x00,0xdb,0x40,0x3e,0xd0,0x4d,0xb4,0x13,0xa4,0x08,0xfb,0x01 } }, +{ 16, 0xcfb0, 0, {0x3e,0xc0,0x1c,0xa0,0x03,0x6c,0x00,0xfb,0x04,0x3e,0x50,0x4f,0xa4,0x03,0xe0,0x00 } }, +{ 16, 0xcfc0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xff,0x00,0x33,0xc0 } }, +{ 16, 0xcfd0, 0, {0x0c,0xe8,0x43,0x26,0x00,0xdf,0x80,0xb3,0xe0,0x0f,0xf8,0x03,0x7c,0x00,0xcd,0x00 } }, +{ 16, 0xcfe0, 0, {0x33,0x04,0x0c,0xe0,0x23,0x34,0x40,0xcd,0x00,0x23,0x40,0x0c,0xe0,0x03,0xe0,0x04 } }, +{ 16, 0xcff0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x6c,0x10,0xbb,0x00,0xa2,0xd2 } }, +{ 16, 0xd000, 0, {0x08,0x28,0x02,0x04,0x60,0x8b,0x19,0x22,0xc6,0x0e,0xb1,0x8a,0x2e,0x40,0x8b,0x90 } }, +{ 16, 0xd010, 0, {0x22,0xc1,0x08,0xa4,0x82,0x2c,0x00,0x8b,0x90,0x22,0x64,0x48,0xa4,0x02,0xe0,0x00 } }, +{ 16, 0xd020, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x2c,0x00,0xbb,0x00,0x22,0x00 } }, +{ 16, 0xd030, 0, {0x08,0x91,0x2e,0x24,0x00,0x9b,0x00,0x22,0xc0,0x8b,0xb0,0x12,0x20,0x04,0x88,0x00 } }, +{ 16, 0xd040, 0, {0x22,0x40,0x08,0x10,0x22,0x20,0x00,0x88,0x01,0x2a,0xd0,0x08,0x80,0x42,0xe0,0x00 } }, +{ 16, 0xd050, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x0c,0x00,0xb3,0x04,0x20,0x80 } }, +{ 16, 0xd060, 0, {0x08,0x10,0x06,0x04,0x10,0x83,0x00,0x20,0xc0,0x8b,0xb0,0x12,0x00,0x00,0x82,0x00 } }, +{ 16, 0xd070, 0, {0x20,0xc0,0x28,0x10,0x42,0x09,0x06,0x82,0x00,0x28,0xc0,0x08,0x20,0x02,0xc2,0x01 } }, +{ 16, 0xd080, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x7c,0x00,0xbb,0x00,0x32,0x40 } }, +{ 16, 0xd090, 0, {0x2c,0xb0,0x03,0x24,0x00,0xd3,0x00,0x32,0xc0,0x5f,0xb5,0x03,0x0c,0x02,0xc1,0x00 } }, +{ 16, 0xd0a0, 0, {0xb2,0x00,0x0c,0xb0,0x0b,0x05,0x00,0xc1,0x00,0xb8,0xc0,0x2c,0x80,0x13,0xe0,0x03 } }, +{ 16, 0xd0b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xdc,0x00,0xff,0x00,0x1f,0xc0 } }, +{ 16, 0xd0c0, 0, {0x87,0xf0,0x01,0xf4,0x00,0xff,0x00,0x3f,0xc0,0x0e,0x70,0x43,0xfc,0x10,0x7f,0x00 } }, +{ 16, 0xd0d0, 0, {0x3f,0xc0,0x0f,0x70,0x03,0xfc,0x00,0xff,0x00,0x37,0xc0,0x0f,0xe0,0x03,0xe8,0x06 } }, +{ 16, 0xd0e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x05,0xf1,0x84,0xfe,0x61,0x31,0xd8 } }, +{ 16, 0xd0f0, 0, {0x0c,0xb2,0xc3,0xfc,0xe0,0xcc,0x80,0x7b,0xc0,0x0e,0xf1,0x03,0x7c,0xe0,0xcc,0x83 } }, +{ 16, 0xd100, 0, {0x3f,0x20,0x0f,0xf0,0xcb,0x32,0x44,0xdc,0x84,0x3f,0x25,0x4c,0xf2,0x43,0x30,0x00 } }, +{ 16, 0xd110, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,0xe4,0x48,0xb0,0x10,0x22,0xdc } }, +{ 16, 0xd120, 0, {0x08,0xb6,0x02,0xfd,0x92,0x88,0x85,0x23,0xf4,0x40,0xf1,0x02,0xed,0x00,0x88,0x2d } }, +{ 16, 0xd130, 0, {0x0e,0x60,0x0b,0xbc,0x12,0x2c,0x10,0xa8,0x82,0x2e,0x00,0x0a,0xfc,0x22,0xa0,0x04 } }, +{ 16, 0xd140, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x05,0xc0,0x80,0xb3,0x22,0x28,0xc0 } }, +{ 16, 0xd150, 0, {0x08,0x30,0x82,0xcc,0x01,0x88,0x00,0x2c,0xc0,0x4a,0x32,0x02,0xcc,0x00,0x01,0x01 } }, +{ 16, 0xd160, 0, {0x28,0x00,0x4b,0xb0,0x02,0xa0,0x00,0x80,0x00,0x2c,0x09,0x08,0x34,0x02,0x62,0x01 } }, +{ 16, 0xd170, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x15,0xac,0x04,0xb2,0x10,0x2a,0xc1 } }, +{ 16, 0xd180, 0, {0x08,0xb0,0x02,0xec,0x10,0x89,0x80,0x22,0xc0,0x08,0xb0,0x02,0xec,0x08,0x88,0x00 } }, +{ 16, 0xd190, 0, {0x2e,0x40,0x83,0xb0,0x02,0xa0,0x40,0xb9,0x80,0x2c,0x21,0x0a,0xb0,0x02,0xf0,0x04 } }, +{ 16, 0xd1a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x15,0xec,0x00,0xfa,0x00,0xba,0xc0 } }, +{ 16, 0xd1b0, 0, {0x2c,0xb0,0x43,0xec,0x00,0xc0,0x80,0x3e,0xc0,0x8e,0xb0,0x03,0x4c,0x0c,0xc8,0x10 } }, +{ 16, 0xd1c0, 0, {0x3e,0x80,0x8f,0xb0,0x03,0x82,0x10,0xd8,0x82,0x3e,0x28,0x0c,0xb0,0x0b,0x50,0x04 } }, +{ 16, 0xd1d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0xb6,0x80,0xfd,0x02,0x37,0xc1 } }, +{ 16, 0xd1e0, 0, {0x0f,0xb0,0x03,0xfc,0x00,0xfd,0x00,0x3e,0xc0,0x0f,0xb0,0x53,0xfc,0x02,0xff,0x01 } }, +{ 16, 0xd1f0, 0, {0x2f,0xa4,0x8b,0xf0,0x83,0x7c,0x00,0xad,0x02,0x2f,0x40,0x03,0x70,0x03,0xb8,0x00 } }, +{ 16, 0xd200, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x10,0xac,0x00,0xfb,0x04,0x32,0xc0 } }, +{ 16, 0xd210, 0, {0x4c,0xb0,0x23,0x2c,0x00,0xf8,0x40,0x3e,0xc2,0x0c,0xb0,0x03,0x2c,0x00,0xfb,0x41 } }, +{ 16, 0xd220, 0, {0x32,0xc2,0x0f,0xb0,0x43,0x2d,0x00,0xc8,0x50,0x3e,0x40,0x0c,0xb0,0x0b,0x10,0x04 } }, +{ 16, 0xd230, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x05,0x2f,0x90,0xb9,0x50,0x03,0xc0 } }, +{ 16, 0xd240, 0, {0x18,0xf0,0x1a,0x3c,0x00,0xb9,0x32,0x2d,0xe0,0x38,0xf0,0x60,0x3c,0x04,0xf9,0x00 } }, +{ 16, 0xd250, 0, {0x3e,0xf0,0x0b,0x7c,0x80,0x2c,0x00,0xd9,0xc0,0x2e,0x40,0x0d,0xf0,0x02,0x32,0x00 } }, +{ 16, 0xd260, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x05,0x4b,0x24,0xb2,0x10,0x02,0xc1 } }, +{ 16, 0xd270, 0, {0x28,0x30,0x02,0x6c,0x04,0xb2,0xc1,0x2c,0xc0,0x08,0x30,0x00,0x0c,0x00,0xb2,0x00 } }, +{ 16, 0xd280, 0, {0x28,0x24,0x03,0x3c,0x0a,0x00,0x00,0x82,0xc8,0x2c,0xa0,0x08,0x30,0x02,0x38,0x00 } }, +{ 16, 0xd290, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x01,0x16,0x00,0xb4,0x80,0x21,0xe4 } }, +{ 16, 0xd2a0, 0, {0x48,0x7b,0x02,0x5e,0x00,0xb6,0x80,0x6d,0xe2,0x48,0x79,0x22,0x1e,0x40,0xac,0x84 } }, +{ 16, 0xd2b0, 0, {0x2d,0xe0,0x0b,0xfa,0x00,0x52,0x40,0x96,0x80,0x2d,0xe8,0x19,0x38,0x02,0x08,0x00 } }, +{ 16, 0xd2c0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x08,0x40,0xf3,0x10,0xb0,0xc4 } }, +{ 16, 0xd2d0, 0, {0x08,0x3a,0x02,0x4c,0x90,0xf3,0x10,0x3c,0xcc,0x08,0x31,0x03,0x0c,0x49,0xb0,0x40 } }, +{ 16, 0xd2e0, 0, {0x30,0x05,0x0f,0x30,0x07,0x21,0x40,0x43,0x01,0x3e,0xc2,0x1c,0x30,0x43,0x12,0x02 } }, +{ 16, 0xd2f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x0d,0xbc,0x10,0xfc,0x10,0x3f,0xc5 } }, +{ 16, 0xd300, 0, {0x0f,0xf1,0x01,0xbc,0x04,0xff,0x04,0x3f,0xc4,0x0f,0xb1,0x4b,0xfc,0x64,0xf7,0x00 } }, +{ 16, 0xd310, 0, {0x37,0xc0,0x0f,0x72,0x53,0xac,0x44,0xff,0x01,0x3f,0xc9,0x0f,0xf4,0x03,0xd0,0x06 } }, +{ 16, 0xd320, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x05,0xec,0x08,0xfa,0x00,0x3e,0xe0 } }, +{ 16, 0xd330, 0, {0x0c,0xb0,0x03,0x2c,0x00,0xcb,0x02,0x3e,0xca,0x0f,0xb2,0x07,0x2e,0x00,0xdb,0x02 } }, +{ 16, 0xd340, 0, {0x32,0x08,0x0f,0x31,0x03,0x2c,0x00,0xcb,0x04,0x3e,0x80,0x0c,0x35,0x03,0x2a,0x00 } }, +{ 16, 0xd350, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x11,0x94,0x00,0xb5,0x00,0x2d,0xc8 } }, +{ 16, 0xd360, 0, {0x08,0x70,0x0a,0x1c,0x22,0x87,0x00,0x2d,0xc9,0x0b,0xf2,0x82,0x9c,0x80,0xa6,0x00 } }, +{ 16, 0xd370, 0, {0x09,0x8b,0x0b,0x70,0x0a,0x1c,0x02,0x85,0x00,0x2d,0x40,0x08,0x70,0x02,0x92,0x04 } }, +{ 16, 0xd380, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x9e,0x00,0xb7,0x80,0x2c,0xec } }, +{ 16, 0xd390, 0, {0x08,0x7b,0x02,0x5e,0x40,0x85,0x89,0x2d,0xec,0x8b,0x7b,0x02,0x4e,0x84,0x8f,0x80 } }, +{ 16, 0xd3a0, 0, {0x25,0x64,0x0b,0xfa,0x02,0x12,0x08,0x97,0x80,0x6f,0xe1,0x08,0x7a,0x02,0x30,0x00 } }, +{ 16, 0xd3b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x14,0xcc,0x20,0xb3,0x64,0x2c,0xc0 } }, +{ 16, 0xd3c0, 0, {0x08,0x30,0x06,0x0c,0x10,0x83,0x8a,0x6c,0xc0,0x5b,0x30,0x42,0xcc,0x00,0xab,0x10 } }, +{ 16, 0xd3d0, 0, {0x2c,0xf2,0x0b,0x30,0x02,0x0d,0x00,0x93,0x04,0x2c,0xd5,0x08,0x30,0x0a,0x92,0x04 } }, +{ 16, 0xd3e0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x15,0xbb,0x00,0xfe,0xc0,0x3e,0x80 } }, +{ 16, 0xd3f0, 0, {0x2c,0xa0,0x03,0x68,0x00,0xc6,0x40,0x3f,0x80,0x0f,0xa0,0x02,0x68,0x00,0xce,0x44 } }, +{ 16, 0xd400, 0, {0x36,0x90,0x4f,0x60,0x03,0x1b,0x70,0xde,0xd8,0x3f,0xa0,0x0c,0x20,0x03,0x3a,0x04 } }, +{ 16, 0xd410, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0xe0,0x40,0xf8,0x10,0x3e,0x00 } }, +{ 16, 0xd420, 0, {0x0f,0x80,0x03,0xa0,0x10,0xf8,0x42,0x3e,0x10,0x1f,0x80,0x03,0xa0,0x00,0xe8,0x0c } }, +{ 16, 0xd430, 0, {0x3a,0x04,0x1f,0x80,0x03,0xe0,0x00,0xe8,0x45,0x7e,0x02,0x2f,0x80,0x03,0xd2,0x00 } }, +{ 16, 0xd440, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x64,0x00,0xe9,0x80,0x32,0x40 } }, +{ 16, 0xd450, 0, {0x0f,0x90,0x0b,0x04,0x08,0xd9,0x80,0x36,0x40,0x0f,0x10,0x13,0x24,0x08,0xf9,0x00 } }, +{ 16, 0xd460, 0, {0x72,0x70,0x0f,0x91,0x13,0x24,0x10,0xc9,0x10,0x3e,0x69,0x0c,0x90,0x03,0x02,0x04 } }, +{ 16, 0xd470, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x64,0x08,0xb9,0x80,0x22,0x40 } }, +{ 16, 0xd480, 0, {0x0b,0x10,0x02,0x24,0x00,0x89,0xc4,0x22,0x52,0x0b,0x90,0x42,0x24,0x00,0xb9,0x00 } }, +{ 16, 0xd490, 0, {0x22,0xe0,0x0b,0x90,0x12,0x24,0x04,0xd9,0x4a,0x2e,0x60,0x08,0x90,0x03,0x60,0x00 } }, +{ 16, 0xd4a0, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x05,0x24,0x00,0xb1,0x18,0x22,0x40 } }, +{ 16, 0xd4b0, 0, {0x0b,0x90,0x02,0x24,0x00,0x8b,0x20,0x26,0x49,0x0b,0x90,0x02,0x64,0x00,0xb9,0x00 } }, +{ 16, 0xd4c0, 0, {0xa2,0x40,0x0b,0x90,0x8a,0x24,0x00,0x8b,0x00,0x2c,0x40,0xa8,0x90,0x02,0x06,0x00 } }, +{ 16, 0xd4d0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x04,0x84,0xb1,0x20,0xa0,0x48 } }, +{ 16, 0xd4e0, 0, {0x0b,0x11,0x06,0x04,0x00,0x83,0x00,0x00,0x40,0x4b,0x11,0x02,0x04,0x49,0xb1,0x10 } }, +{ 16, 0xd4f0, 0, {0x28,0x40,0x0b,0x10,0x02,0x24,0x41,0x91,0x00,0x2c,0x50,0x08,0x10,0x02,0x42,0x01 } }, +{ 16, 0xd500, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x69,0x40,0xe8,0x50,0x32,0x14 } }, +{ 16, 0xd510, 0, {0x0f,0x86,0x93,0x21,0xe2,0xc8,0x00,0x36,0x0a,0x0b,0x86,0x8b,0x61,0xa8,0xf8,0x40 } }, +{ 16, 0xd520, 0, {0x22,0x80,0x0f,0x82,0xa3,0x21,0x08,0xc8,0x02,0x3e,0x00,0x0c,0x80,0x43,0x2e,0x03 } }, +{ 16, 0xd530, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x1d,0xf4,0x48,0xfd,0x12,0x3e,0x44 } }, +{ 16, 0xd540, 0, {0x0f,0x12,0x03,0xc4,0x00,0x7d,0x01,0x1e,0x40,0x0b,0x92,0x03,0xe4,0x80,0xf5,0x20 } }, +{ 16, 0xd550, 0, {0x36,0x40,0x0f,0x90,0x03,0xd4,0x90,0x7d,0x00,0x3d,0x40,0x0f,0x94,0x03,0xe6,0x06 } }, +{ 16, 0xd560, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x01,0xf6,0xc1,0xdd,0x88,0x32,0x72 } }, +{ 16, 0xd570, 0, {0x0c,0x98,0x03,0x26,0x22,0xdd,0x00,0x3f,0x62,0x2c,0x99,0x83,0x46,0xa0,0xc9,0x40 } }, +{ 16, 0xd580, 0, {0xb2,0x40,0x0f,0xd8,0x03,0x24,0x00,0xfd,0x00,0x33,0x51,0x2c,0xd8,0x83,0x06,0x00 } }, +{ 16, 0xd590, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0xe3,0xc2,0x88,0xc0,0x22,0x30 } }, +{ 16, 0xd5a0, 0, {0x08,0x8c,0x42,0x22,0x11,0x8a,0x01,0x2e,0x00,0x08,0x88,0x52,0x23,0x00,0x80,0xa3 } }, +{ 16, 0xd5b0, 0, {0x2a,0x00,0x4b,0x80,0x42,0x22,0xa0,0xb8,0x00,0x22,0x28,0x08,0x84,0x02,0x8e,0x04 } }, +{ 16, 0xd5c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0xc4,0x00,0x81,0x2d,0x20,0x48 } }, +{ 16, 0xd5d0, 0, {0x68,0x14,0x80,0x04,0x20,0x81,0x00,0x2e,0x40,0x0b,0x12,0x12,0x04,0x24,0x81,0x20 } }, +{ 16, 0xd5e0, 0, {0x20,0x40,0x0b,0x94,0x32,0x04,0x90,0xb9,0x00,0x20,0x40,0x48,0x10,0x4a,0x02,0x01 } }, +{ 16, 0xd5f0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x15,0xa4,0x00,0x89,0x20,0x22,0x40 } }, +{ 16, 0xd600, 0, {0x08,0x90,0x12,0x24,0x00,0x89,0x00,0x2e,0x40,0x08,0x90,0x02,0x24,0x08,0x89,0x40 } }, +{ 16, 0xd610, 0, {0x22,0x50,0x0b,0xb0,0x02,0x24,0x20,0xb9,0x09,0xa2,0x44,0x08,0x90,0x02,0x86,0x04 } }, +{ 16, 0xd620, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x15,0xe4,0x00,0xd9,0x08,0xb2,0x40 } }, +{ 16, 0xd630, 0, {0x4c,0x10,0x23,0x04,0x04,0xd9,0xc1,0x3e,0x40,0x8f,0x90,0x0b,0x04,0x08,0xc1,0x40 } }, +{ 16, 0xd640, 0, {0x12,0x40,0x0f,0x90,0x43,0x24,0x04,0xf1,0x41,0x30,0x78,0x0c,0x90,0x03,0x28,0x04 } }, +{ 16, 0xd650, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x01,0x86,0x64,0xf9,0x80,0x3e,0x40 } }, +{ 16, 0xd660, 0, {0x0f,0x90,0x0b,0xe4,0x00,0xf9,0x98,0x3e,0x40,0x2f,0x10,0x03,0xa4,0x02,0xf9,0x10 } }, +{ 16, 0xd670, 0, {0x3e,0x40,0x0f,0x90,0x0b,0xe6,0x40,0xf9,0x90,0x3e,0x60,0x0f,0x90,0x03,0xca,0x00 } }, +{ 16, 0xd680, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x10,0xa0,0x00,0xc8,0x41,0x32,0x00 } }, +{ 16, 0xd690, 0, {0x0c,0x80,0x07,0x20,0x10,0xc8,0x10,0x3e,0x0c,0x0e,0x80,0x03,0xe0,0x04,0xc8,0x00 } }, +{ 16, 0xd6a0, 0, {0xba,0x00,0x0f,0x81,0x43,0x20,0x00,0xf8,0x70,0x3e,0x00,0x0f,0x00,0x0b,0x0a,0x04 } }, +{ 16, 0xd6b0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x39,0x02,0x8e,0x20,0xa3,0x80 } }, +{ 16, 0xd6c0, 0, {0x28,0xe0,0x0a,0x38,0x10,0xae,0x04,0x3d,0xa1,0x8e,0xe0,0x02,0xf8,0x00,0x8e,0x00 } }, +{ 16, 0xd6d0, 0, {0x76,0x80,0x0b,0x60,0x03,0x78,0x00,0xbe,0x40,0x2f,0x82,0x0b,0xa0,0x03,0xca,0x00 } }, +{ 16, 0xd6e0, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x05,0x4d,0x00,0x8b,0x88,0x22,0xc0 } }, +{ 16, 0xd6f0, 0, {0x18,0x30,0x02,0x0c,0x00,0x83,0x44,0x2c,0xd0,0x1b,0x30,0x12,0xcc,0x06,0x83,0x00 } }, +{ 16, 0xd700, 0, {0x20,0xc1,0x0b,0x30,0x82,0x0c,0x01,0xb3,0x00,0x2c,0x40,0x0b,0x30,0x02,0x0a,0x00 } }, +{ 16, 0xd710, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01,0x1c,0x00,0x85,0x00,0x20,0xcc } }, +{ 16, 0xd720, 0, {0x08,0x70,0x06,0x1c,0x84,0xa7,0x01,0x29,0xc0,0x0b,0x72,0x22,0xdc,0x80,0x87,0x34 } }, +{ 16, 0xd730, 0, {0x61,0x80,0x0b,0x10,0x02,0x5c,0x00,0xb7,0x00,0x2d,0xc0,0x0b,0x70,0x02,0xe8,0x00 } }, +{ 16, 0xd740, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x08,0x0e,0x00,0x8c,0x80,0x31,0xe0 } }, +{ 16, 0xd750, 0, {0x0c,0xfe,0x02,0x3f,0x00,0xc5,0x80,0x2d,0xe0,0x0e,0x78,0x03,0xdf,0xa0,0xc7,0xa0 } }, +{ 16, 0xd760, 0, {0x21,0x60,0x0f,0x78,0x03,0x1e,0x80,0xf7,0x80,0x3d,0xe0,0x0f,0x78,0x03,0x2a,0x02 } }, +{ 16, 0xd770, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1d,0xac,0x00,0xf9,0x00,0x3e,0xc0 } }, +{ 16, 0xd780, 0, {0x0f,0xb0,0x03,0xec,0x00,0xfa,0x00,0x3e,0xc0,0x06,0xb0,0x03,0xec,0x80,0xfb,0x28 } }, +{ 16, 0xd790, 0, {0x36,0xd8,0x4f,0xa0,0x03,0xec,0x10,0xfa,0x00,0x3e,0x50,0x0f,0x30,0x03,0xc2,0x06 } }, +{ 16, 0xd7a0, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xfa,0x00,0xcc,0x80,0xb3,0xe0 } }, +{ 16, 0xd7b0, 0, {0x0f,0xf8,0x03,0x3e,0x00,0xcf,0x90,0x3f,0x60,0x4f,0xf8,0xc3,0x3e,0x00,0xef,0x80 } }, +{ 16, 0xd7c0, 0, {0x33,0xf0,0x0c,0x7a,0x03,0x3e,0x70,0xc5,0x90,0x33,0xf1,0x0c,0x78,0x03,0x00,0x00 } }, +{ 16, 0xd7d0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x11,0xb8,0x00,0x87,0x00,0x21,0xc0 } }, +{ 16, 0xd7e0, 0, {0x0b,0x70,0x4a,0x1c,0x00,0x87,0x10,0x2d,0xc0,0x4b,0x71,0x0a,0x3c,0x44,0x8f,0x12 } }, +{ 16, 0xd7f0, 0, {0x21,0x86,0x0d,0x72,0x02,0x1e,0x00,0x87,0x00,0x23,0x40,0x08,0x70,0x0a,0x2a,0x04 } }, +{ 16, 0xd800, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x00,0x84,0x00,0x25,0xc0 } }, +{ 16, 0xd810, 0, {0x0b,0x71,0x0a,0x0c,0x00,0xa7,0x12,0x2d,0x84,0x0b,0x70,0x0a,0x1c,0x00,0xb7,0x08 } }, +{ 16, 0xd820, 0, {0x23,0x40,0x09,0xf3,0x1a,0x5c,0x86,0x97,0x08,0x25,0x40,0x08,0x70,0x02,0x00,0x00 } }, +{ 16, 0xd830, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x14,0xcc,0x20,0x81,0x20,0x26,0xc0 } }, +{ 16, 0xd840, 0, {0x0b,0x30,0x02,0x2c,0x00,0x82,0x42,0x2c,0x80,0x0b,0x30,0x22,0x0c,0x08,0x9b,0x80 } }, +{ 16, 0xd850, 0, {0x20,0xe0,0x09,0x20,0x02,0x4d,0x08,0x92,0x00,0x24,0xe5,0x08,0x30,0x0a,0x08,0x04 } }, +{ 16, 0xd860, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x15,0xae,0x82,0xca,0xe0,0xb7,0xc0 } }, +{ 16, 0xd870, 0, {0x0f,0xf0,0x13,0x3c,0x0a,0xc9,0xc8,0x3e,0x40,0x0f,0xf0,0x03,0x3c,0x04,0xff,0x84 } }, +{ 16, 0xd880, 0, {0x32,0xc0,0x0d,0x90,0x13,0x7c,0x00,0xd9,0x00,0xf6,0xc0,0x2c,0x10,0x03,0x2a,0x04 } }, +{ 16, 0xd890, 0, {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xe4,0x00,0xf3,0x00,0x3a,0xc1 } }, +{ 16, 0xd8a0, 0, {0x4f,0xb0,0x03,0xec,0x00,0xf9,0x08,0x3c,0x00,0x0f,0x30,0x13,0xec,0x00,0xeb,0x04 } }, +{ 16, 0xd8b0, 0, {0xbe,0x18,0x0f,0x90,0x23,0xac,0x60,0xe9,0x02,0x3a,0x40,0x4f,0x90,0x03,0xe0,0x00 } }, +{ 16, 0xd8c0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0xfc,0x00,0xca,0x00,0x33,0xc0 } }, +{ 16, 0xd8d0, 0, {0x0c,0xf0,0x03,0xfc,0x00,0xcd,0x02,0x7f,0x40,0x0c,0xf0,0x42,0x3c,0x00,0xcf,0x08 } }, +{ 16, 0xd8e0, 0, {0x37,0x10,0x0f,0xd0,0x03,0xfc,0x10,0xcd,0x08,0x3f,0x66,0x2c,0xd9,0x03,0x00,0x44 } }, +{ 16, 0xd8f0, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x04,0x63,0x80,0x8b,0xe0,0x22,0xc0 } }, +{ 16, 0xd900, 0, {0x08,0xb0,0x22,0xec,0x00,0xd8,0x80,0x6e,0x20,0x68,0xb0,0x1a,0x2c,0x01,0xfb,0x00 } }, +{ 16, 0xd910, 0, {0x22,0x18,0x0b,0x88,0x43,0x4c,0x00,0x88,0xa0,0x2c,0xc0,0x1d,0x90,0x02,0x20,0x40 } }, +{ 16, 0xd920, 0, {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x08,0x80,0x8b,0x20,0x22,0xc0 } }, +{ 16, 0xd930, 0, {0x08,0xb0,0x22,0xec,0x00,0x88,0x88,0x2e,0x62,0x48,0xb0,0x1a,0xcc,0x00,0x8b,0x00 } }, +{ 16, 0xd940, 0, {0x26,0xc0,0x4a,0x88,0x02,0xec,0x00,0x08,0x84,0x2e,0x40,0x09,0x90,0x02,0x20,0x00 } }, +{ 16, 0xd950, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x83,0x00,0x60,0xc0 } }, +{ 16, 0xd960, 0, {0x08,0x30,0x02,0xcc,0x00,0x90,0x06,0x6c,0x00,0x08,0x30,0x02,0x8c,0x00,0xa3,0x04 } }, +{ 16, 0xd970, 0, {0x20,0x00,0x8b,0x00,0x06,0x4c,0x21,0x80,0x00,0x6c,0xc0,0x49,0x10,0x0a,0x02,0x01 } }, +{ 16, 0xd980, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x6c,0x00,0xca,0x00,0xb2,0xc1 } }, +{ 16, 0xd990, 0, {0x88,0xb4,0x03,0xec,0x10,0xc8,0x00,0x2e,0x00,0x0c,0xb0,0x0b,0xbc,0x08,0x8f,0x00 } }, +{ 16, 0xd9a0, 0, {0x36,0x00,0x06,0x80,0x03,0xec,0x80,0xc8,0x02,0x3f,0xc1,0x0c,0x90,0x03,0x00,0x03 } }, +{ 16, 0xd9b0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x1d,0xf0,0x00,0xff,0x00,0x3f,0xc0 } }, +{ 16, 0xd9c0, 0, {0x0f,0x72,0x83,0xfc,0x18,0xfc,0x03,0x3f,0x00,0x8f,0x70,0x03,0x7c,0x00,0xff,0x00 } }, +{ 16, 0xd9d0, 0, {0x3d,0x00,0x0f,0xc0,0x23,0x8c,0x06,0xfc,0x00,0x3f,0x40,0x0e,0xd0,0x03,0xe8,0x06 } }, +{ 16, 0xd9e0, 0, {0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x41,0x03,0x70,0x40,0xdc,0x10 } }, +{ 16, 0xd9f0, 0, {0x37,0x04,0x0d,0xc1,0x03,0x70,0x40,0xdc,0x10,0x37,0x04,0x0d,0xc1,0x01,0x70,0x40 } }, +{ 16, 0xda00, 0, {0x9c,0x10,0x17,0x14,0x05,0xc1,0x03,0x70,0x40,0xdc,0x10,0x17,0x04,0x0d,0xc0,0x31 } }, +{ 16, 0xda10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x44,0x05,0x71,0x01,0x5c,0x40 } }, +{ 16, 0xda20, 0, {0x57,0x10,0x15,0xc4,0x05,0x21,0x01,0x5c,0x40,0x57,0x10,0x15,0xc4,0x01,0x71,0x01 } }, +{ 16, 0xda30, 0, {0x5c,0x40,0x17,0x10,0x05,0xc4,0x05,0x71,0x05,0x5c,0x41,0x57,0x10,0x15,0xc0,0x11 } }, +{ 16, 0xda40, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x02,0x01,0x20,0x80,0x48,0x20 } }, +{ 16, 0xda50, 0, {0x12,0x08,0x04,0x82,0x01,0x20,0x80,0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x20,0x80 } }, +{ 16, 0xda60, 0, {0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x20,0x80,0x48,0x20,0x12,0x08,0x04,0x80,0x20 } }, +{ 16, 0xda70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x60,0x00,0x58,0x00 } }, +{ 16, 0xda80, 0, {0x16,0x00,0x05,0x80,0x01,0x60,0x00,0x58,0x00,0x16,0x00,0x05,0x80,0x05,0x60,0x00 } }, +{ 16, 0xda90, 0, {0x58,0x00,0x16,0x18,0x01,0x80,0x01,0x60,0x00,0x58,0x00,0x56,0x00,0x05,0x80,0x20 } }, +{ 16, 0xdaa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x48,0x05,0x22,0x01,0x1c,0x80 } }, +{ 16, 0xdab0, 0, {0x47,0x20,0x11,0xc8,0x04,0x72,0x01,0x5c,0x80,0x57,0x20,0x11,0xc8,0x04,0x72,0x41 } }, +{ 16, 0xdac0, 0, {0x5c,0x80,0x57,0x20,0x11,0xc8,0x04,0x72,0x01,0x1c,0x80,0x47,0x20,0x15,0xc0,0x31 } }, +{ 16, 0xdad0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x40,0x00,0x60,0x00,0x18,0x00 } }, +{ 16, 0xdae0, 0, {0x06,0x00,0x01,0x80,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x60,0x00 } }, +{ 16, 0xdaf0, 0, {0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x31 } }, +{ 16, 0xdb00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x48,0x04,0x22,0x01,0x08,0x80 } }, +{ 16, 0xdb10, 0, {0x42,0x20,0x10,0x88,0x04,0x22,0x01,0x08,0x80,0x42,0x20,0x10,0x80,0x04,0x23,0x01 } }, +{ 16, 0xdb20, 0, {0x08,0x80,0x42,0x20,0x10,0x88,0x04,0x22,0x01,0x08,0x00,0x42,0x20,0x10,0x80,0x21 } }, +{ 16, 0xdb30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x4a,0x05,0x42,0x81,0x50,0xa0 } }, +{ 16, 0xdb40, 0, {0x44,0x2c,0x11,0x0b,0x04,0x42,0x81,0x10,0xe0,0x54,0x28,0x11,0x02,0x00,0x42,0x81 } }, +{ 16, 0xdb50, 0, {0x10,0xa0,0x44,0x38,0x11,0x0b,0x05,0x42,0x81,0x10,0x21,0x14,0x28,0x15,0x00,0x31 } }, +{ 16, 0xdb60, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0c,0x01,0x57,0x00,0x54,0xc0 } }, +{ 16, 0xdb70, 0, {0x15,0x30,0x04,0x4c,0x01,0x13,0x00,0x54,0xc0,0x15,0x70,0x05,0x4c,0x01,0x53,0x00 } }, +{ 16, 0xdb80, 0, {0x54,0xc0,0x15,0x30,0x85,0x4c,0x01,0x13,0x00,0x54,0xc0,0x15,0x30,0x05,0x40,0x21 } }, +{ 16, 0xdb90, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x10,0x00 } }, +{ 16, 0xdba0, 0, {0x04,0x00,0x00,0x40,0x00,0x10,0x00,0x10,0x62,0x04,0x00,0x01,0x08,0x04,0x41,0x00 } }, +{ 16, 0xdbb0, 0, {0x10,0x00,0x44,0x18,0x11,0x00,0x00,0x10,0x00,0x10,0x80,0x04,0x00,0x01,0x01,0x20 } }, +{ 16, 0xdbc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x60,0x02,0x08,0x00,0x82,0x00 } }, +{ 16, 0xdbd0, 0, {0x20,0x80,0x08,0x60,0x02,0x18,0x00,0x82,0x00,0x20,0x80,0x08,0x20,0x00,0x08,0x20 } }, +{ 16, 0xdbe0, 0, {0x82,0x00,0x00,0x80,0x80,0x20,0x02,0x18,0x00,0x82,0x00,0x20,0x80,0x08,0x01,0x31 } }, +{ 16, 0xdbf0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x40,0x05,0x64,0x01,0x58,0x00 } }, +{ 16, 0xdc00, 0, {0x56,0x00,0x15,0x80,0x05,0x60,0x01,0x58,0x00,0x56,0x40,0x15,0x80,0x05,0x60,0x01 } }, +{ 16, 0xdc10, 0, {0x58,0x00,0x56,0x00,0x15,0x80,0x05,0x60,0x01,0x58,0x00,0x76,0x00,0x15,0x80,0x31 } }, +{ 16, 0xdc20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x40,0x03,0x60,0x00,0xd8,0x00 } }, +{ 16, 0xdc30, 0, {0x36,0x00,0x0d,0x80,0x03,0x60,0x00,0x98,0x00,0x36,0x00,0x1d,0x88,0x05,0x60,0x00 } }, +{ 16, 0xdc40, 0, {0xd8,0x00,0x16,0x00,0x0d,0x80,0x03,0x60,0x00,0xd8,0x80,0x46,0x00,0x0d,0x80,0x31 } }, +{ 16, 0xdc50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x42,0x04,0x30,0x81,0x0c,0x20 } }, +{ 16, 0xdc60, 0, {0x43,0x08,0x10,0xc2,0x04,0x30,0x81,0x0c,0x22,0x41,0x08,0x18,0xc2,0x04,0x30,0x89 } }, +{ 16, 0xdc70, 0, {0x0c,0x20,0x03,0x08,0x10,0xc2,0x04,0x30,0x81,0x0c,0x20,0x43,0x08,0x10,0xc0,0x10 } }, +{ 16, 0xdc80, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x30,0x00,0x0c,0x00 } }, +{ 16, 0xdc90, 0, {0x03,0x00,0x00,0xc0,0x00,0x30,0x00,0x0c,0x00,0x03,0x00,0x00,0xc0,0x00,0x30,0x00 } }, +{ 16, 0xdca0, 0, {0x0c,0x00,0x03,0x00,0x00,0xc0,0x00,0x30,0x00,0x0c,0x00,0x03,0x00,0x00,0xc0,0x01 } }, +{ 16, 0xdcb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x02,0x01,0x30,0x80,0x4c,0x20 } }, +{ 16, 0xdcc0, 0, {0x13,0x08,0x04,0xc2,0x01,0x30,0x80,0x4c,0x20,0x13,0x08,0x04,0xc3,0x01,0x30,0x80 } }, +{ 16, 0xdcd0, 0, {0x4c,0x20,0x13,0x08,0x04,0xc2,0x01,0x30,0x80,0x4c,0x30,0x13,0x08,0x04,0xc0,0x21 } }, +{ 16, 0xdce0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x42,0x05,0x60,0x81,0x58,0x20 } }, +{ 16, 0xdcf0, 0, {0x56,0x08,0x11,0x82,0x05,0x60,0x81,0x58,0x20,0x56,0x08,0x11,0x83,0x00,0x60,0x81 } }, +{ 16, 0xdd00, 0, {0x58,0x20,0x46,0x08,0x11,0x82,0x04,0x60,0x81,0x18,0x30,0x56,0x08,0x15,0x80,0x30 } }, +{ 16, 0xdd10, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x42,0x00,0x20,0x80,0x08,0x20 } }, +{ 16, 0xdd20, 0, {0x02,0x08,0x00,0x82,0x00,0x20,0x80,0x08,0x20,0x02,0x08,0x00,0x82,0x00,0x30,0x80 } }, +{ 16, 0xdd30, 0, {0x08,0x20,0x02,0x00,0x00,0x82,0x00,0x20,0x80,0x08,0x20,0x03,0x08,0x00,0x80,0x31 } }, +{ 16, 0xdd40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x42,0x04,0x60,0x81,0x18,0x20 } }, +{ 16, 0xdd50, 0, {0x46,0x48,0x11,0x92,0x04,0x60,0x81,0x19,0x20,0x46,0x28,0x11,0x82,0x00,0x34,0x81 } }, +{ 16, 0xdd60, 0, {0x18,0x20,0x46,0x48,0x11,0x92,0x04,0x60,0x81,0x18,0x20,0x43,0x08,0x11,0x80,0x11 } }, +{ 16, 0xdd70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x60,0x04,0x58,0x01,0x56,0x00 } }, +{ 16, 0xdd80, 0, {0x55,0x80,0x15,0x60,0x04,0x58,0x01,0x16,0x00,0x55,0x80,0x01,0x60,0x04,0x18,0x01 } }, +{ 16, 0xdd90, 0, {0x56,0x00,0x45,0x80,0x11,0x60,0x04,0x58,0x01,0x16,0x00,0x41,0x80,0x11,0x40,0x31 } }, +{ 16, 0xdda0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x06,0x01,0x41,0x80,0x50,0x60 } }, +{ 16, 0xddb0, 0, {0x14,0x18,0x05,0x06,0x01,0x41,0x80,0x50,0x60,0x04,0x18,0x05,0x06,0x00,0x41,0x80 } }, +{ 16, 0xddc0, 0, {0x10,0x60,0x14,0x18,0x05,0x06,0x01,0x41,0x80,0x50,0x60,0x14,0x18,0x05,0x00,0x20 } }, +{ 16, 0xddd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x80,0x40,0x20 } }, +{ 16, 0xdde0, 0, {0x10,0x48,0x04,0x12,0x01,0x00,0x80,0x41,0x20,0x10,0x08,0x04,0x02,0x01,0x04,0x80 } }, +{ 16, 0xddf0, 0, {0x40,0x20,0x50,0x48,0x04,0x12,0x01,0x00,0x84,0x40,0x20,0x10,0x08,0x04,0x00,0x20 } }, +{ 16, 0xde00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x46,0x03,0x51,0x80,0xd4,0x60 } }, +{ 16, 0xde10, 0, {0x30,0x18,0x0d,0x46,0x03,0x51,0x80,0xd5,0x60,0x35,0x18,0x0d,0x46,0x03,0x05,0x80 } }, +{ 16, 0xde20, 0, {0xd4,0x60,0x15,0x18,0x0d,0x46,0x03,0x11,0x80,0xd4,0x60,0x35,0x18,0x0d,0x40,0x31 } }, +{ 16, 0xde30, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x46,0x05,0x71,0x80,0x5c,0x60 } }, +{ 16, 0xde40, 0, {0x97,0x18,0x15,0xc6,0x05,0x71,0x81,0x5c,0x20,0x57,0x18,0x15,0xc6,0x03,0x70,0x81 } }, +{ 16, 0xde50, 0, {0x5c,0x60,0x57,0x18,0x11,0xc6,0x05,0x31,0x81,0x5c,0x60,0x77,0x18,0x15,0xc0,0x31 } }, +{ 16, 0xde60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x46,0x03,0x71,0x80,0xdc,0x60 } }, +{ 16, 0xde70, 0, {0x37,0x18,0x0d,0xc6,0x03,0x71,0x80,0xdd,0x60,0x37,0x18,0x05,0xc6,0x01,0x75,0x81 } }, +{ 16, 0xde80, 0, {0xdc,0x60,0x37,0x18,0x0d,0xc6,0x03,0x71,0x84,0x5c,0x60,0x17,0x18,0x19,0xc0,0x11 } }, +{ 16, 0xde90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x46,0x05,0x71,0x81,0x5c,0x60 } }, +{ 16, 0xdea0, 0, {0x57,0x18,0x14,0x86,0x05,0x71,0x81,0x5c,0x60,0x57,0x18,0x05,0xc6,0x04,0x31,0x81 } }, +{ 16, 0xdeb0, 0, {0x5c,0x60,0x57,0x18,0x15,0xc6,0x05,0x71,0x80,0x5c,0x60,0x43,0x18,0x15,0xc0,0x11 } }, +{ 16, 0xdec0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x20,0x80,0x48,0x20 } }, +{ 16, 0xded0, 0, {0x12,0x08,0x04,0x82,0x01,0x20,0x80,0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x70,0x80 } }, +{ 16, 0xdee0, 0, {0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x20,0x80,0x48,0x20,0x17,0x08,0x04,0x80,0x00 } }, +{ 16, 0xdef0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x61,0x80,0x58,0x60 } }, +{ 16, 0xdf00, 0, {0x16,0x18,0x41,0x86,0x01,0x61,0x80,0x18,0x60,0x06,0x3c,0x05,0x86,0x04,0x61,0x80 } }, +{ 16, 0xdf10, 0, {0x18,0x60,0x16,0x18,0x01,0x86,0x00,0x61,0x80,0x58,0x60,0x56,0x18,0x15,0x80,0x10 } }, +{ 16, 0xdf20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40,0x05,0x70,0x01,0x5c,0x00 } }, +{ 16, 0xdf30, 0, {0x57,0x00,0x15,0xc0,0x04,0x70,0x01,0x5c,0x00,0x57,0x00,0x10,0xc0,0x04,0x70,0x00 } }, +{ 16, 0xdf40, 0, {0x1c,0x00,0x47,0x00,0x11,0xc0,0x04,0x70,0x01,0x5c,0x00,0x47,0x00,0x01,0xc0,0x11 } }, +{ 16, 0xdf50, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x42,0x00,0x60,0x80,0x18,0x20 } }, +{ 16, 0xdf60, 0, {0x06,0x08,0x01,0x82,0x00,0x60,0x80,0x18,0x20,0x06,0x08,0x00,0x82,0x00,0x60,0x80 } }, +{ 16, 0xdf70, 0, {0x18,0x20,0x06,0x08,0x01,0x82,0x00,0x60,0x80,0x18,0x20,0x06,0x08,0x01,0x80,0x11 } }, +{ 16, 0xdf80, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x42,0x04,0x20,0x81,0x08,0x20 } }, +{ 16, 0xdf90, 0, {0x42,0x08,0x10,0x82,0x04,0x20,0x81,0x08,0x20,0x42,0x08,0x11,0x82,0x04,0x20,0x80 } }, +{ 16, 0xdfa0, 0, {0x08,0x20,0x42,0x08,0x10,0x82,0x04,0x20,0x81,0x08,0x20,0x42,0x08,0x00,0x80,0x11 } }, +{ 16, 0xdfb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x42,0x05,0x40,0x81,0x50,0x20 } }, +{ 16, 0xdfc0, 0, {0x54,0x08,0x15,0x02,0x05,0x40,0x81,0x10,0x20,0x54,0x0c,0x15,0x42,0x00,0x40,0x81 } }, +{ 16, 0xdfd0, 0, {0x50,0x20,0x44,0x08,0x11,0x02,0x05,0x40,0x81,0x10,0x20,0x14,0x08,0x05,0x00,0x11 } }, +{ 16, 0xdfe0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x01,0x50,0xc0,0x54,0x30 } }, +{ 16, 0xdff0, 0, {0x15,0x08,0x05,0x42,0x01,0x50,0xc0,0x54,0x30,0x15,0x0c,0x05,0x43,0x01,0x50,0xc0 } }, +{ 16, 0xe000, 0, {0x54,0x30,0x15,0x0c,0x05,0x42,0x01,0x50,0xc0,0x54,0x30,0x15,0x0c,0x05,0x40,0x10 } }, +{ 16, 0xe010, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x42,0x00,0x10,0x80 } }, +{ 16, 0xe020, 0, {0x04,0x20,0x01,0x88,0x00,0x62,0x00,0x10,0x80,0x04,0x00,0x11,0x08,0x00,0x42,0x00 } }, +{ 16, 0xe030, 0, {0x10,0x80,0x04,0x20,0x01,0x08,0x00,0x42,0x01,0x10,0x80,0x04,0x20,0x01,0x00,0x00 } }, +{ 16, 0xe040, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x42,0x02,0x00,0x80,0x80,0x20 } }, +{ 16, 0xe050, 0, {0x20,0x08,0x08,0x02,0x02,0x20,0x80,0x80,0x20,0x20,0x28,0x00,0x02,0x02,0x00,0x80 } }, +{ 16, 0xe060, 0, {0x80,0x20,0x20,0x0a,0x08,0x02,0x02,0x00,0x80,0x00,0x20,0x20,0x08,0x08,0x00,0x11 } }, +{ 16, 0xe070, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40,0x05,0x60,0x01,0x58,0x00 } }, +{ 16, 0xe080, 0, {0x56,0x00,0x05,0x80,0x05,0x60,0x01,0x58,0x08,0x56,0x00,0x15,0x80,0x07,0x60,0x02 } }, +{ 16, 0xe090, 0, {0x58,0x00,0x56,0x40,0x15,0x80,0x05,0x60,0x03,0x18,0x00,0x76,0x00,0x15,0x80,0x11 } }, +{ 16, 0xe0a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x40,0x03,0x60,0x00,0xd8,0x00 } }, +{ 16, 0xe0b0, 0, {0x36,0x00,0x0d,0x80,0x01,0x60,0x00,0xd8,0x0a,0x36,0x00,0x0d,0x80,0x05,0x70,0x09 } }, +{ 16, 0xe0c0, 0, {0xd8,0x01,0x36,0x00,0x0d,0x80,0x03,0x60,0x00,0xd8,0x00,0x57,0x00,0x0d,0x80,0x00 } }, +{ 16, 0xe0d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x30,0x01,0x0c,0x00 } }, +{ 16, 0xe0e0, 0, {0x43,0x00,0x10,0xc0,0x00,0x30,0x01,0x0c,0x00,0x43,0x20,0x10,0xc0,0x04,0x60,0x01 } }, +{ 16, 0xe0f0, 0, {0x0c,0x00,0x43,0x40,0x50,0xc1,0x04,0x30,0x01,0x0c,0x00,0x46,0x00,0x10,0xc0,0x00 } }, +{ 16, 0xe100, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x0c,0x00 } }, +{ 16, 0xe110, 0, {0x01,0x00,0x00,0xc0,0x00,0x30,0x00,0x0c,0x00,0x03,0x00,0x00,0xd0,0x00,0x20,0x00 } }, +{ 16, 0xe120, 0, {0x0c,0x00,0x03,0x40,0x00,0xc0,0x00,0x30,0x00,0x0d,0x00,0x02,0x00,0x00,0xc0,0x00 } }, +{ 16, 0xe130, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,0x31,0x40,0x4c,0x50 } }, +{ 16, 0xe140, 0, {0x13,0x10,0x04,0xc4,0x01,0x31,0x40,0x4c,0x50,0x13,0x14,0x04,0xc5,0x11,0x31,0x41 } }, +{ 16, 0xe150, 0, {0x4c,0x50,0x13,0x14,0x04,0xc5,0x01,0x31,0x40,0x4c,0x50,0x13,0x14,0x04,0xc0,0x00 } }, +{ 16, 0xe160, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x05,0x68,0xc1,0x5a,0x30 } }, +{ 16, 0xe170, 0, {0x56,0x8c,0x11,0xa3,0x04,0x68,0xc1,0x1a,0x30,0x56,0x8c,0x11,0xa3,0x05,0x68,0xc0 } }, +{ 16, 0xe180, 0, {0x5a,0x30,0x46,0x8c,0x11,0xa3,0x04,0x68,0xc1,0x5a,0x30,0x16,0x8c,0x15,0x80,0x00 } }, +{ 16, 0xe190, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x08,0x00 } }, +{ 16, 0xe1a0, 0, {0x02,0x00,0x00,0x80,0x00,0x20,0x00,0x08,0x00,0x02,0x20,0x00,0x90,0x00,0x20,0x00 } }, +{ 16, 0xe1b0, 0, {0x08,0x00,0x02,0x40,0x00,0x80,0x00,0x20,0x00,0x09,0x00,0x02,0x00,0x00,0x80,0x00 } }, +{ 16, 0xe1c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x44,0x62,0x01,0x18,0x84 } }, +{ 16, 0xe1d0, 0, {0x46,0x21,0x11,0x88,0x44,0x62,0x11,0x18,0x84,0x46,0x01,0x11,0x88,0x44,0x62,0x10 } }, +{ 16, 0xe1e0, 0, {0x18,0x84,0x46,0x21,0x11,0x88,0x44,0x62,0x11,0x18,0x84,0x06,0x21,0x11,0x80,0x00 } }, +{ 16, 0xe1f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x50,0x11,0x54,0x04 } }, +{ 16, 0xe200, 0, {0x55,0x01,0x11,0x40,0x45,0x50,0x11,0x14,0x00,0x45,0x01,0x11,0x40,0x44,0x50,0x00 } }, +{ 16, 0xe210, 0, {0x14,0x04,0x45,0x00,0x15,0x40,0x44,0x50,0x11,0x14,0x04,0x55,0x01,0x11,0x40,0x00 } }, +{ 16, 0xe220, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x21,0x42,0x08,0x50,0x82 } }, +{ 16, 0xe230, 0, {0x14,0x20,0x85,0x08,0x21,0x42,0x08,0x50,0x82,0x04,0x20,0x85,0x08,0x21,0x42,0x08 } }, +{ 16, 0xe240, 0, {0x50,0x82,0x14,0x20,0x05,0x08,0x21,0x42,0x08,0x50,0x82,0x14,0x20,0x85,0x00,0x00 } }, +{ 16, 0xe250, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x01,0x02,0x80,0x40,0xa0 } }, +{ 16, 0xe260, 0, {0x10,0x28,0x04,0x0a,0x01,0x02,0x80,0x40,0xa0,0x10,0x28,0x40,0x0a,0x01,0x02,0x80 } }, +{ 16, 0xe270, 0, {0x40,0xa0,0x10,0x28,0x44,0x0a,0x01,0x02,0x80,0x40,0xa0,0x10,0x28,0x04,0x00,0x00 } }, +{ 16, 0xe280, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x03,0x53,0x00,0xd4,0xc0 } }, +{ 16, 0xe290, 0, {0x35,0x30,0x0d,0x4c,0x01,0x53,0x00,0xd4,0xc0,0x35,0x10,0x0c,0x4c,0x03,0x53,0x00 } }, +{ 16, 0xe2a0, 0, {0xd4,0xc0,0x35,0x30,0x0d,0x4c,0x03,0x53,0x00,0xd4,0xc0,0x35,0x30,0x0d,0x40,0x00 } }, +{ 16, 0xe2b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x05,0x72,0x01,0x5c,0x80 } }, +{ 16, 0xe2c0, 0, {0x17,0x20,0x05,0xc8,0x06,0x72,0x01,0x5c,0x80,0x57,0x20,0x15,0xc8,0x02,0x72,0x01 } }, +{ 16, 0xe2d0, 0, {0x5c,0x80,0x57,0x20,0x15,0xc8,0x05,0x72,0x01,0x5c,0x80,0x37,0x20,0x11,0xc0,0x00 } }, +{ 16, 0xe2e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x18,0x40,0xc6,0x12,0x31 } }, +{ 16, 0xe2f0, 0, {0x84,0x8c,0x21,0x23,0x08,0x48,0xc6,0x12,0x30,0x84,0x0c,0x61,0x23,0x10,0x48,0xc2 } }, +{ 16, 0xe300, 0, {0x12,0x31,0x84,0x8c,0x01,0x23,0x08,0x48,0xc6,0x12,0x31,0x04,0x8c,0x61,0x00,0x00 } }, +{ 16, 0xe310, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0x4f,0xff,0xd3,0xff } }, +{ 16, 0xe320, 0, {0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff,0xd3,0xff,0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff } }, +{ 16, 0xe330, 0, {0xd3,0xff,0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff,0xd3,0xff,0xf4,0xff,0xfd,0x00,0x00 } }, +{ 16, 0xe340, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xe350, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xe360, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xe370, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xdb,0x0f,0xb6,0xc2,0xcd } }, +{ 16, 0xe380, 0, {0xb0,0xb3,0x6c,0x2c,0xdb,0x0b,0x36,0xc2,0xdf,0xb0,0xb3,0x6c,0x2c,0xdb,0x0b,0x7e } }, +{ 16, 0xe390, 0, {0xc2,0xcd,0xb0,0xb7,0xfd,0x2c,0xdb,0x0b,0x36,0xc2,0xcd,0xb0,0xb3,0x6c,0x00,0x00 } }, +{ 16, 0xe3a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x3c,0x4f,0xcf,0x13,0x33 } }, +{ 16, 0xe3b0, 0, {0xc4,0xcc,0xf1,0x33,0x3c,0x4c,0xcf,0x13,0x3f,0xc4,0xcc,0xf1,0x33,0x3c,0x4c,0xff } }, +{ 16, 0xe3c0, 0, {0x13,0x33,0xc4,0xcf,0xfd,0x33,0x3c,0x4c,0xcf,0x13,0x33,0xc4,0xcc,0xf1,0x00,0x00 } }, +{ 16, 0xe3d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x7e,0x4e,0xdf,0x93,0xb7 } }, +{ 16, 0xe3e0, 0, {0xe4,0xec,0x79,0x3b,0x1e,0x4e,0xdf,0x93,0xbf,0xe4,0x8d,0xf9,0x3b,0x78,0x4e,0xff } }, +{ 16, 0xe3f0, 0, {0x93,0xb7,0xe4,0xed,0xfd,0x3b,0x1e,0x4e,0xdf,0x93,0xb7,0x84,0xed,0xf9,0x00,0x00 } }, +{ 16, 0xe400, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x70,0x40,0x9c,0x10 } }, +{ 16, 0xe410, 0, {0x27,0x1c,0x09,0xc1,0x01,0x30,0x40,0x1c,0x10,0x67,0x04,0x09,0xc1,0x02,0x70,0x41 } }, +{ 16, 0xe420, 0, {0x9c,0x11,0x07,0x14,0x01,0xc1,0x02,0x70,0x40,0x9c,0x50,0x07,0x1c,0x01,0xc0,0x00 } }, +{ 16, 0xe430, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x05,0x71,0x01,0x5c,0x40 } }, +{ 16, 0xe440, 0, {0x57,0x10,0x55,0xc4,0x01,0x31,0x00,0x5c,0x40,0x57,0x10,0x15,0xc4,0x05,0x71,0x01 } }, +{ 16, 0xe450, 0, {0xdc,0x40,0x17,0x18,0x1d,0xc4,0x05,0x71,0x05,0x5c,0x40,0x57,0x10,0x1d,0xc0,0x00 } }, +{ 16, 0xe460, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x20,0x80,0x48,0x20 } }, +{ 16, 0xe470, 0, {0x12,0x00,0x04,0x82,0x01,0x20,0x80,0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x20,0x80 } }, +{ 16, 0xe480, 0, {0x48,0x20,0x12,0x08,0x04,0x82,0x01,0x20,0x80,0x48,0x60,0x12,0x08,0x04,0x80,0x00 } }, +{ 16, 0xe490, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00 } }, +{ 16, 0xe4a0, 0, {0x06,0x00,0x41,0x80,0x00,0x60,0x00,0x18,0x00,0x46,0x00,0x01,0x80,0x00,0x60,0x00 } }, +{ 16, 0xe4b0, 0, {0x10,0x00,0x06,0x10,0x01,0x80,0x00,0x60,0x00,0x18,0x20,0x46,0x10,0x01,0x80,0x00 } }, +{ 16, 0xe4c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x72,0x01,0x1c,0x80 } }, +{ 16, 0xe4d0, 0, {0x47,0x20,0x11,0xc8,0x04,0x72,0x01,0x1c,0x80,0x07,0x20,0x11,0xc8,0x04,0x73,0x00 } }, +{ 16, 0xe4e0, 0, {0x1c,0x80,0x47,0x20,0x11,0xcc,0x04,0x72,0x01,0x1c,0x80,0x47,0x20,0x11,0xc0,0x00 } }, +{ 16, 0xe4f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x18,0x00 } }, +{ 16, 0xe500, 0, {0x06,0x00,0x01,0x84,0x00,0x60,0x00,0x18,0x00,0x06,0x00,0x01,0x80,0x00,0x60,0x40 } }, +{ 16, 0xe510, 0, {0x18,0x00,0x06,0x04,0x01,0x81,0x00,0x60,0x00,0x18,0x00,0x06,0x14,0x01,0x80,0x00 } }, +{ 16, 0xe520, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x22,0x01,0x08,0x80 } }, +{ 16, 0xe530, 0, {0x42,0x70,0x10,0x8c,0x04,0x22,0x01,0x08,0xc0,0x02,0x20,0x10,0x88,0x04,0x22,0x00 } }, +{ 16, 0xe540, 0, {0x08,0x80,0x42,0x50,0x10,0x08,0x04,0x22,0x01,0x09,0x00,0x42,0x40,0x10,0x80,0x00 } }, +{ 16, 0xe550, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x04,0x4a,0x81,0x12,0xa0 } }, +{ 16, 0xe560, 0, {0x44,0xa8,0x11,0x2a,0x04,0x4a,0x81,0x12,0xa0,0x04,0xa8,0x11,0x2a,0x04,0x4b,0x80 } }, +{ 16, 0xe570, 0, {0x12,0xa0,0x44,0x88,0x01,0x2e,0x04,0x4a,0x81,0x12,0x20,0x04,0x98,0x01,0x00,0x00 } }, +{ 16, 0xe580, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc0,0x0e,0x00,0x53,0x00,0x14,0xc0 } }, +{ 16, 0xe590, 0, {0x05,0x30,0x01,0x4c,0x00,0x53,0x00,0x14,0xe0,0x05,0x30,0x01,0x4c,0x00,0x53,0x00 } }, +{ 16, 0xe5a0, 0, {0x04,0xc0,0x05,0x30,0x00,0x4c,0x00,0x03,0x00,0x14,0xc0,0x05,0x30,0x00,0x40,0x10 } }, +{ 16, 0xe5b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc0,0x04,0x00,0x40,0x00,0x10,0x00 } }, +{ 16, 0xe5c0, 0, {0x04,0x58,0x01,0x04,0x00,0x40,0x00,0x10,0x00,0x04,0x00,0x01,0x00,0x00,0x41,0x00 } }, +{ 16, 0xe5d0, 0, {0x04,0x00,0x44,0x58,0x10,0x44,0x00,0x00,0x00,0x11,0x80,0x04,0x50,0x10,0x40,0x30 } }, +{ 16, 0xe5e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc0,0x40,0x02,0x00,0x00,0x80,0x00 } }, +{ 16, 0xe5f0, 0, {0x20,0x00,0x08,0x00,0x40,0x00,0x00,0x00,0x00,0x20,0x00,0x08,0x00,0x02,0x00,0x00 } }, +{ 16, 0xe600, 0, {0x84,0x00,0x00,0x00,0x08,0x40,0x02,0x00,0x00,0x80,0x00,0x20,0x00,0x08,0x40,0x30 } }, +{ 16, 0xe610, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc0,0x40,0x00,0x60,0x01,0x18,0x00 } }, +{ 16, 0xe620, 0, {0x46,0x00,0x01,0x80,0x06,0x60,0x01,0x98,0x00,0x46,0x00,0x11,0x80,0x04,0x60,0x01 } }, +{ 16, 0xe630, 0, {0x18,0x00,0x46,0x00,0x11,0x80,0x04,0x20,0x01,0x18,0x00,0x66,0x00,0x11,0x80,0x30 } }, +{ 16, 0xe640, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x01,0x40,0x00,0x60,0x00,0x98,0x00 } }, +{ 16, 0xe650, 0, {0x26,0x00,0x09,0x80,0x02,0x60,0x01,0x98,0x00,0x06,0x00,0x0c,0x80,0x02,0x60,0x00 } }, +{ 16, 0xe660, 0, {0x18,0x00,0x06,0x00,0x01,0x80,0x02,0x60,0x00,0x98,0x80,0x06,0x00,0x01,0x82,0x00 } }, +{ 16, 0xe670, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x42,0x00,0x30,0x81,0x0c,0x20 } }, +{ 16, 0xe680, 0, {0x43,0x08,0x10,0xc2,0x24,0x30,0x81,0x8c,0x20,0x03,0x08,0x10,0xc2,0x04,0x20,0x80 } }, +{ 16, 0xe690, 0, {0x0c,0x20,0x03,0x08,0x18,0xc2,0x04,0x30,0x81,0x0c,0x20,0x43,0x08,0x18,0xc0,0x11 } }, +{ 16, 0xe6a0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x30,0x00,0x0c,0x00 } }, +{ 16, 0xe6b0, 0, {0x03,0x00,0x00,0xc0,0x40,0x30,0x00,0x0c,0x00,0x03,0x00,0x00,0x80,0x00,0x30,0x00 } }, +{ 16, 0xe6c0, 0, {0x0c,0x00,0x03,0x20,0x00,0xc0,0x00,0x30,0x00,0x0c,0x00,0x03,0x20,0x00,0xc0,0x00 } }, +{ 16, 0xe6d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x02,0x10,0x30,0x80,0x0c,0x20 } }, +{ 16, 0xe6e0, 0, {0x03,0x08,0x00,0xc2,0x00,0x30,0x80,0x0c,0x20,0x03,0x08,0x00,0xc2,0x01,0x20,0x80 } }, +{ 16, 0xe6f0, 0, {0x0c,0x20,0x03,0x2c,0x00,0xc2,0x00,0x30,0x80,0x0c,0x30,0x43,0x2c,0x00,0xc0,0x00 } }, +{ 16, 0xe700, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x42,0x04,0x60,0x81,0x18,0x20 } }, +{ 16, 0xe710, 0, {0x46,0x08,0x11,0x82,0x04,0x60,0x80,0x18,0x20,0x46,0x08,0x11,0x82,0x04,0x60,0x81 } }, +{ 16, 0xe720, 0, {0x18,0x20,0x46,0x0c,0x11,0xc2,0x04,0x60,0x81,0x18,0x30,0x46,0x0c,0x11,0xc0,0x11 } }, +{ 16, 0xe730, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x42,0x00,0x20,0x80,0x08,0x20 } }, +{ 16, 0xe740, 0, {0x02,0x28,0x00,0x82,0x00,0x20,0x80,0x08,0x20,0x02,0x08,0x00,0x82,0x00,0x20,0x80 } }, +{ 16, 0xe750, 0, {0x08,0x20,0x02,0x08,0x01,0x82,0x00,0x20,0x80,0x08,0x20,0x03,0x08,0x01,0x80,0x00 } }, +{ 16, 0xe760, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x01,0x42,0x04,0x60,0x81,0x18,0x20 } }, +{ 16, 0xe770, 0, {0x46,0x28,0x11,0x82,0x04,0x60,0x80,0x18,0x20,0x46,0x08,0x11,0x82,0x04,0x60,0x81 } }, +{ 16, 0xe780, 0, {0x18,0x20,0x46,0x08,0x10,0x82,0x04,0x60,0x81,0x18,0x20,0x43,0x08,0x10,0x80,0x00 } }, +{ 16, 0xe790, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x40,0x04,0x50,0x01,0x14,0x00 } }, +{ 16, 0xe7a0, 0, {0x45,0x00,0x11,0x40,0x25,0x00,0x00,0x14,0x00,0x45,0x00,0x11,0x40,0x04,0x50,0x01 } }, +{ 16, 0xe7b0, 0, {0x14,0x00,0x45,0x00,0x00,0x40,0x04,0x50,0x01,0x40,0x00,0x01,0x00,0x00,0x42,0x11 } }, +{ 16, 0xe7c0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x06,0x00,0x41,0x80,0x10,0x60 } }, +{ 16, 0xe7d0, 0, {0x04,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x04,0x18,0x01,0x06,0x00,0x41,0x80 } }, +{ 16, 0xe7e0, 0, {0x10,0x60,0x04,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x04,0x18,0x01,0x00,0x00 } }, +{ 16, 0xe7f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x02,0x05,0x00,0x80,0x40,0x21 } }, +{ 16, 0xe800, 0, {0x10,0x08,0x04,0x00,0x01,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,0x80 } }, +{ 16, 0xe810, 0, {0x40,0x20,0x50,0x08,0x14,0x02,0x11,0x00,0x84,0x40,0x20,0x10,0x08,0x14,0x00,0x00 } }, +{ 16, 0xe820, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x46,0x01,0x51,0x80,0xd4,0x60 } }, +{ 16, 0xe830, 0, {0x35,0x18,0x0d,0x46,0x03,0x51,0x80,0xd4,0x60,0x15,0x18,0x0d,0x46,0x03,0x51,0x80 } }, +{ 16, 0xe840, 0, {0x54,0x60,0x15,0x18,0x0d,0x46,0x03,0x51,0x80,0xd4,0x60,0x35,0x18,0x0d,0x40,0x11 } }, +{ 16, 0xe850, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x46,0x04,0x71,0x81,0x1c,0x60 } }, +{ 16, 0xe860, 0, {0x45,0x18,0x11,0xd6,0x04,0x71,0x81,0x1c,0x60,0x67,0x18,0x11,0xc6,0x04,0x71,0x81 } }, +{ 16, 0xe870, 0, {0x9c,0x60,0x47,0x18,0x11,0xc6,0x04,0x71,0x81,0x1c,0x60,0x67,0x18,0x11,0xc0,0x00 } }, +{ 16, 0xe880, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x46,0x02,0x71,0x80,0x9c,0x60 } }, +{ 16, 0xe890, 0, {0x27,0x18,0x09,0xc6,0x00,0x71,0x80,0x9c,0x60,0x67,0x18,0x09,0xc6,0x02,0x71,0x80 } }, +{ 16, 0xe8a0, 0, {0x9c,0x61,0x27,0x18,0x01,0xc6,0x02,0x71,0x80,0x9c,0x60,0x07,0x18,0x01,0xc0,0x00 } }, +{ 16, 0xe8b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x46,0x05,0x71,0x81,0x5c,0x60 } }, +{ 16, 0xe8c0, 0, {0x57,0x18,0x55,0xd6,0x01,0x71,0x81,0x5c,0x60,0x57,0x18,0x15,0xc6,0x05,0x71,0x81 } }, +{ 16, 0xe8d0, 0, {0x5c,0x60,0x57,0x18,0x18,0xc6,0x05,0x71,0x81,0x5c,0x60,0x43,0x18,0x18,0x82,0x11 } }, +{ 16, 0xe8e0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x52,0x01,0x20,0x80,0x48,0x20 } }, +{ 16, 0xe8f0, 0, {0x12,0x48,0x04,0x90,0x01,0x20,0x80,0x49,0x20,0x12,0x08,0x04,0x82,0x01,0x24,0x80 } }, +{ 16, 0xe900, 0, {0x48,0x20,0x12,0x48,0x00,0x92,0x01,0x20,0x80,0x48,0x20,0x17,0x48,0x04,0x80,0x01 } }, +{ 16, 0xe910, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x06,0x00,0x61,0x80,0x18,0x60 } }, +{ 16, 0xe920, 0, {0x06,0x3c,0x01,0x86,0x00,0x61,0x80,0x18,0x60,0x46,0x18,0x01,0x86,0x00,0x61,0x80 } }, +{ 16, 0xe930, 0, {0x18,0x60,0x06,0x18,0x01,0x86,0x00,0x61,0x80,0x18,0x60,0x46,0x18,0x01,0x80,0x01 } }, +{ 16, 0xe940, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x60,0x04,0x78,0x01,0x1e,0x00 } }, +{ 16, 0xe950, 0, {0x47,0x80,0x11,0xe0,0x24,0x78,0x01,0x1e,0x00,0x07,0x80,0x11,0xe0,0x04,0x78,0x01 } }, +{ 16, 0xe960, 0, {0x1e,0x00,0x47,0x80,0x11,0xe0,0x04,0x38,0x01,0x1e,0x00,0x47,0x80,0x11,0xc0,0x11 } }, +{ 16, 0xe970, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x12,0x00,0x60,0x80,0x18,0x20 } }, +{ 16, 0xe980, 0, {0x06,0x48,0x01,0x92,0x00,0x60,0x80,0x19,0x20,0x06,0x08,0x01,0x82,0x00,0x64,0x80 } }, +{ 16, 0xe990, 0, {0x18,0x20,0x06,0x48,0x01,0x93,0x00,0x20,0x80,0x18,0x20,0x06,0x48,0x01,0x80,0x00 } }, +{ 16, 0xe9a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x42,0x04,0x20,0x81,0x08,0x20 } }, +{ 16, 0xe9b0, 0, {0x42,0x08,0x10,0x82,0x04,0x20,0x81,0x08,0x20,0x02,0x08,0x10,0x82,0x04,0x20,0x81 } }, +{ 16, 0xe9c0, 0, {0x08,0x20,0x42,0x08,0x10,0x8a,0x04,0x60,0x81,0x08,0x20,0x42,0x08,0x10,0x80,0x00 } }, +{ 16, 0xe9d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x42,0x04,0x40,0x81,0x10,0x20 } }, +{ 16, 0xe9e0, 0, {0x44,0x08,0x11,0x02,0x04,0x40,0x81,0x10,0x20,0x04,0x08,0x11,0x02,0x04,0x40,0x81 } }, +{ 16, 0xe9f0, 0, {0x10,0x21,0x44,0x08,0x01,0x02,0x04,0x50,0x81,0x10,0x20,0x04,0x08,0x01,0x00,0x11 } }, +{ 16, 0xea00, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x03,0x00,0x50,0xc0,0x14,0x30 } }, +{ 16, 0xea10, 0, {0x05,0x0c,0x01,0x43,0x00,0x50,0xc0,0x14,0x30,0x05,0x0c,0x01,0x43,0x00,0x50,0x80 } }, +{ 16, 0xea20, 0, {0x14,0x30,0x05,0x08,0x01,0x4a,0x00,0x50,0xc0,0x14,0x30,0x05,0x08,0x01,0x40,0x00 } }, +{ 16, 0xea30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x00,0x42,0x00,0x10,0x80 } }, +{ 16, 0xea40, 0, {0x04,0x20,0x01,0x08,0x00,0x42,0x00,0x10,0x80,0x04,0x20,0x01,0x08,0x00,0x42,0x00 } }, +{ 16, 0xea50, 0, {0x10,0x80,0x04,0x20,0x11,0x00,0x00,0x42,0x00,0x10,0x80,0x04,0x20,0x11,0x00,0x10 } }, +{ 16, 0xea60, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x42,0x02,0x00,0x80,0x80,0x20 } }, +{ 16, 0xea70, 0, {0x20,0x08,0x08,0x02,0x00,0x00,0x80,0x80,0x20,0x20,0x08,0x08,0x02,0x02,0x00,0x80 } }, +{ 16, 0xea80, 0, {0x80,0x20,0x20,0x08,0x08,0x02,0x02,0x00,0x80,0x80,0x20,0x20,0x08,0x08,0x00,0x11 } }, +{ 16, 0xea90, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x40,0x00,0x60,0x01,0x18,0x00 } }, +{ 16, 0xeaa0, 0, {0x46,0x00,0x11,0x80,0x06,0x60,0x01,0x18,0x00,0x46,0x00,0x11,0x80,0x04,0x60,0x01 } }, +{ 16, 0xeab0, 0, {0x18,0x00,0x46,0x00,0x11,0x80,0x04,0x60,0x01,0x18,0x00,0x66,0x00,0x11,0x80,0x10 } }, +{ 16, 0xeac0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x40,0x02,0x64,0x00,0x98,0x00 } }, +{ 16, 0xead0, 0, {0x26,0x00,0x09,0x90,0x06,0x60,0x01,0x98,0x00,0x26,0x40,0x09,0x80,0x02,0x60,0x00 } }, +{ 16, 0xeae0, 0, {0x98,0x00,0x26,0x00,0x00,0x90,0x02,0x60,0x00,0x98,0x00,0x07,0x00,0x01,0x80,0x00 } }, +{ 16, 0xeaf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x60,0x04,0x38,0x05,0x0e,0x00 } }, +{ 16, 0xeb00, 0, {0x43,0x80,0x10,0xe0,0x44,0x38,0x01,0x0e,0x00,0x43,0x80,0x10,0xe0,0x04,0x38,0x01 } }, +{ 16, 0xeb10, 0, {0x0e,0x00,0x43,0x80,0x18,0xa0,0x04,0x38,0x01,0x0e,0x00,0x46,0x80,0x18,0x80,0x11 } }, +{ 16, 0xeb20, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x01,0x00,0x30,0x40,0x0c,0x10 } }, +{ 16, 0xeb30, 0, {0x03,0x04,0x00,0xc5,0x00,0x30,0x40,0x0c,0x10,0x03,0x14,0x00,0xc1,0x00,0x30,0x40 } }, +{ 16, 0xeb40, 0, {0x0c,0x10,0x03,0x04,0x00,0x87,0x40,0x30,0x40,0x0c,0x10,0x02,0x04,0x00,0x80,0x00 } }, +{ 16, 0xeb50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x05,0x00,0x35,0x40,0x0c,0x50 } }, +{ 16, 0xeb60, 0, {0x03,0x14,0x00,0xd5,0x04,0x31,0x41,0x0c,0x50,0x03,0x5c,0x00,0xc5,0x00,0x31,0x00 } }, +{ 16, 0xeb70, 0, {0x0c,0x50,0x03,0x10,0x00,0x94,0x00,0x31,0x40,0x0c,0x50,0x43,0x10,0x00,0xc2,0x00 } }, +{ 16, 0xeb80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x43,0x05,0x20,0xc1,0x18,0x30 } }, +{ 16, 0xeb90, 0, {0x46,0x0c,0x11,0x97,0x00,0x60,0xc0,0x18,0x30,0x46,0x1c,0x11,0x83,0x04,0x60,0xc1 } }, +{ 16, 0xeba0, 0, {0x18,0x30,0x52,0x0c,0x11,0x87,0x04,0x60,0xc1,0x18,0x30,0x46,0x0c,0x11,0x80,0x11 } }, +{ 16, 0xebb0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x21,0x40,0x08,0x00 } }, +{ 16, 0xebc0, 0, {0x02,0x00,0x00,0x80,0x00,0x20,0x00,0x08,0x00,0x02,0x00,0x00,0x80,0x00,0x20,0x00 } }, +{ 16, 0xebd0, 0, {0x08,0x00,0x02,0x00,0x00,0x80,0x00,0x20,0x00,0x08,0x00,0x02,0x00,0x00,0x80,0x00 } }, +{ 16, 0xebe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x48,0x44,0x22,0x01,0x18,0x84 } }, +{ 16, 0xebf0, 0, {0x46,0x21,0x11,0x98,0x00,0x62,0x10,0x18,0x84,0x44,0x20,0x11,0x88,0x44,0x62,0x11 } }, +{ 16, 0xec00, 0, {0x18,0x84,0x42,0x21,0x11,0x80,0x44,0x62,0x11,0x18,0x84,0x46,0x21,0x11,0x80,0x00 } }, +{ 16, 0xec10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x40,0x04,0x50,0x11,0x14,0x04 } }, +{ 16, 0xec20, 0, {0x45,0x00,0x11,0x41,0x00,0x50,0x10,0x14,0x00,0x45,0x01,0x11,0x40,0x44,0x50,0x11 } }, +{ 16, 0xec30, 0, {0x14,0x04,0x45,0x01,0x01,0x40,0x44,0x50,0x11,0x14,0x04,0x05,0x01,0x01,0x40,0x11 } }, +{ 16, 0xec40, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x08,0x20,0x42,0x08,0x10,0x82 } }, +{ 16, 0xec50, 0, {0x04,0x20,0x01,0x08,0x20,0x42,0x08,0x10,0x82,0x04,0x20,0x81,0x08,0x20,0x42,0x08 } }, +{ 16, 0xec60, 0, {0x10,0x82,0x04,0x22,0x81,0x08,0x20,0x52,0x08,0x10,0x8a,0x04,0x22,0x81,0x00,0x00 } }, +{ 16, 0xec70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x01,0x02,0x84,0x40,0xa1 } }, +{ 16, 0xec80, 0, {0x10,0x28,0x00,0x0a,0x01,0x02,0x80,0x40,0xa0,0x10,0x28,0x04,0x0a,0x01,0x02,0x80 } }, +{ 16, 0xec90, 0, {0x40,0xa0,0x10,0x2c,0x14,0x0a,0x00,0x02,0x80,0x40,0xb0,0x10,0x2c,0x14,0x00,0x00 } }, +{ 16, 0xeca0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x45,0x4d,0x03,0x53,0x40,0xd4,0xd0 } }, +{ 16, 0xecb0, 0, {0x35,0x30,0x0c,0x4d,0x03,0x53,0x40,0xd4,0xd0,0x35,0x34,0x0d,0x4d,0x03,0x53,0x40 } }, +{ 16, 0xecc0, 0, {0xd4,0xd0,0x35,0x34,0x0d,0x4d,0x02,0x13,0x40,0xd4,0xd0,0x35,0x34,0x0d,0x40,0x11 } }, +{ 16, 0xecd0, 0, {0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x08,0x04,0x72,0x01,0x1c,0x80 } }, +{ 16, 0xece0, 0, {0x47,0x20,0x15,0xc8,0x04,0x72,0x01,0x1c,0x80,0x47,0x20,0x11,0xc8,0x04,0x72,0x11 } }, +{ 16, 0xecf0, 0, {0x1c,0x80,0x47,0x26,0x11,0xc8,0x44,0x72,0x01,0x1c,0x90,0x67,0x26,0x11,0xc0,0x00 } }, +{ 16, 0xed00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x08,0x40,0xc6,0x12,0x31 } }, +{ 16, 0xed10, 0, {0x84,0x8c,0x01,0x03,0x08,0x48,0xc6,0x12,0x30,0x84,0x0c,0x61,0x23,0x18,0x48,0xc2 } }, +{ 16, 0xed20, 0, {0x12,0x31,0x84,0x8c,0x01,0x03,0x08,0x48,0xc6,0x12,0x31,0x04,0x8c,0x01,0x00,0x00 } }, +{ 16, 0xed30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0x4f,0xff,0xd3,0xff } }, +{ 16, 0xed40, 0, {0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff,0xd3,0xff,0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff } }, +{ 16, 0xed50, 0, {0xd3,0xff,0xf4,0xff,0xfd,0x3f,0xff,0x4f,0xff,0xd3,0xff,0xf4,0xff,0xfd,0x00,0x00 } }, +{ 16, 0xed60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xed70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xed80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xed90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2d,0xfb,0x0f,0xb6,0xc2,0xcd } }, +{ 16, 0xeda0, 0, {0xb0,0xb7,0xfd,0x3f,0xfb,0x0b,0x36,0xc2,0xdf,0xb0,0xfb,0x6c,0x2c,0xdb,0x0b,0x7e } }, +{ 16, 0xedb0, 0, {0xc2,0xcd,0xb0,0xb7,0xfd,0x3f,0xfb,0x0b,0x36,0xc2,0xcd,0xf4,0xb7,0xfd,0x00,0x00 } }, +{ 16, 0xedc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0xfc,0x4f,0xcf,0x13,0x33 } }, +{ 16, 0xedd0, 0, {0xc4,0xcf,0xfd,0x3f,0xfc,0x4c,0xcf,0x13,0x3f,0xc4,0xfc,0xf1,0x33,0x3c,0x4c,0xff } }, +{ 16, 0xede0, 0, {0x13,0x33,0xc4,0xcf,0xfd,0x3f,0xfc,0x4c,0xcf,0x13,0x33,0xf4,0xcf,0xfd,0x00,0x00 } }, +{ 16, 0xedf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x7e,0x4e,0xdf,0x93,0xb7 } }, +{ 16, 0xee00, 0, {0xe4,0xed,0xf9,0x3f,0xfe,0x4e,0xdf,0x93,0xb7,0xe4,0xed,0xf9,0x3b,0x7e,0x4e,0xc7 } }, +{ 16, 0xee10, 0, {0x93,0xb7,0xe4,0xec,0x61,0x23,0x1e,0x4e,0xdf,0x93,0xb7,0x84,0xec,0x61,0x00,0x00 } }, +{ 16, 0xee20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x24,0xa1,0x4a,0x24 } }, +{ 16, 0xee30, 0, {0x63,0x01,0x14,0x02,0x44,0x00,0x81,0x0b,0x28,0x71,0x02,0x10,0x82,0x40,0x38,0x11 } }, +{ 16, 0xee40, 0, {0x41,0x04,0x50,0x08,0x18,0x82,0x87,0x38,0x31,0xc3,0x2c,0x52,0x0a,0x10,0x00,0x00 } }, +{ 16, 0xee50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x45,0x12,0x81,0x44,0x80 } }, +{ 16, 0xee60, 0, {0x71,0x21,0x1c,0x0a,0x07,0x1a,0x81,0x02,0xa0,0x52,0x20,0x14,0x48,0x07,0x12,0x81 } }, +{ 16, 0xee70, 0, {0xc6,0x80,0x60,0x20,0x08,0x88,0x47,0x02,0x01,0x4a,0x80,0x70,0x20,0x10,0x00,0x00 } }, +{ 16, 0xee80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc5,0x2c,0x01,0x4a,0x00 } }, +{ 16, 0xee90, 0, {0x52,0x09,0x1c,0x80,0x07,0x24,0x21,0x08,0x08,0x71,0x02,0x10,0x80,0x45,0x20,0xa1 } }, +{ 16, 0xeea0, 0, {0x49,0x28,0x52,0x01,0x14,0xc0,0x45,0x00,0x91,0xc4,0x00,0x72,0x02,0x10,0x00,0x00 } }, +{ 16, 0xeeb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x07,0x20,0x01,0xc1,0x00 } }, +{ 16, 0xeec0, 0, {0x71,0x09,0x10,0x80,0x07,0x00,0x01,0x01,0x00,0x70,0x08,0x18,0x80,0x07,0x00,0x01 } }, +{ 16, 0xeed0, 0, {0x89,0x20,0x52,0x01,0x0c,0x80,0x46,0x30,0x81,0x45,0x04,0x60,0x00,0x10,0x00,0x00 } }, +{ 16, 0xeee0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xc2,0x02,0x20,0x00,0x88 } }, +{ 16, 0xeef0, 0, {0x20,0x22,0x00,0x08,0xc2,0x22,0x80,0x40,0x88,0x02,0x22,0x00,0x08,0x82,0x0a,0xa0 } }, +{ 16, 0xef00, 0, {0x0c,0xa8,0x02,0x22,0x00,0x08,0x80,0x0a,0x00,0x80,0x8c,0x02,0x22,0x00,0x00,0x00 } }, +{ 16, 0xef10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x02,0x43,0x00,0x00,0x40,0x20 } }, +{ 16, 0xef20, 0, {0x30,0x08,0x04,0x40,0x41,0x30,0x10,0xc8,0x00,0x00,0x00,0x00,0x02,0x03,0x00,0x10 } }, +{ 16, 0xef30, 0, {0xc0,0x00,0x11,0x08,0x00,0xc2,0x43,0x10,0x80,0xc0,0x20,0x01,0x08,0x00,0x02,0x00 } }, +{ 16, 0xef40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0xc3,0x0a,0x20,0xc1,0x8c } }, +{ 16, 0xef50, 0, {0x12,0x22,0x04,0x88,0x01,0x36,0x20,0xc3,0x08,0x12,0x28,0x04,0x08,0x01,0x04,0x00 } }, +{ 16, 0xef60, 0, {0x4a,0xa8,0x22,0x01,0x04,0xc8,0x41,0x26,0x30,0xc0,0x88,0x02,0x21,0x00,0x02,0x00 } }, +{ 16, 0xef70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x0a,0x10,0xc1,0x80 } }, +{ 16, 0xef80, 0, {0x32,0x21,0x0c,0x88,0x43,0x02,0x80,0x44,0x80,0x12,0x29,0x04,0x08,0x42,0x0a,0x90 } }, +{ 16, 0xef90, 0, {0x8a,0x80,0x00,0x20,0x04,0x48,0x03,0x0a,0x10,0x82,0x80,0x00,0x20,0x00,0x02,0x00 } }, +{ 16, 0xefa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x87,0x02,0xa1,0x80,0xac } }, +{ 16, 0xefb0, 0, {0x43,0x29,0x14,0x8a,0x84,0x02,0xa1,0x00,0xac,0x41,0x20,0x10,0x08,0x06,0x26,0x31 } }, +{ 16, 0xefc0, 0, {0x80,0xa4,0x60,0x20,0x14,0x4a,0x44,0x32,0x81,0x81,0xac,0x60,0x2a,0x18,0x02,0x00 } }, +{ 16, 0xefd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x07,0x22,0x01,0xc5,0x80 } }, +{ 16, 0xefe0, 0, {0x73,0x21,0x1c,0xc8,0x07,0x2a,0x01,0x0c,0x80,0x72,0x20,0x10,0x48,0x47,0x26,0x11 } }, +{ 16, 0xeff0, 0, {0xc5,0x80,0x73,0x20,0x1c,0x88,0x07,0x2a,0x11,0x49,0x80,0x70,0x20,0x14,0x02,0x00 } }, +{ 16, 0xf000, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x10,0x31,0xc9,0x0c } }, +{ 16, 0xf010, 0, {0x73,0x02,0x1c,0xc0,0x47,0x04,0x01,0x0a,0x0c,0x51,0x0a,0x10,0x82,0x47,0x20,0x31 } }, +{ 16, 0xf020, 0, {0xc8,0x00,0x72,0x02,0x1c,0x40,0x05,0x30,0x11,0xc4,0x00,0x72,0x01,0x18,0x02,0x00 } }, +{ 16, 0xf030, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x10,0x06,0x24,0x01,0x45,0x04 } }, +{ 16, 0xf040, 0, {0x51,0x81,0x18,0x90,0x47,0x14,0x01,0x04,0x04,0x71,0x88,0x10,0x12,0x05,0x34,0x01 } }, +{ 16, 0xf050, 0, {0x44,0x04,0x51,0x40,0x18,0xd0,0x07,0x38,0x01,0xc4,0x04,0x52,0x01,0x14,0xc2,0x04 } }, +{ 16, 0xf060, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x00,0x21,0x89,0x0c } }, +{ 16, 0xf070, 0, {0x60,0x01,0x1c,0xd0,0x45,0x24,0x01,0xc1,0x0c,0x42,0x01,0x00,0x00,0xc5,0x20,0x31 } }, +{ 16, 0xf080, 0, {0x41,0x08,0x40,0x00,0x18,0x80,0x45,0x00,0x21,0x41,0x0c,0x70,0x42,0x1c,0xc2,0x00 } }, +{ 16, 0xf090, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x1c,0x80,0xc4,0x20 } }, +{ 16, 0xf0a0, 0, {0x31,0x08,0x10,0x42,0x42,0x08,0x80,0xc6,0x20,0x31,0x09,0x00,0x20,0x03,0x1c,0x90 } }, +{ 16, 0xf0b0, 0, {0xc4,0x20,0x01,0x49,0x0c,0x42,0x43,0x10,0x80,0x44,0x20,0x31,0x08,0x10,0x00,0x00 } }, +{ 16, 0xf0c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x83,0x20,0x30,0x48,0x0c } }, +{ 16, 0xf0d0, 0, {0x32,0x40,0x10,0x90,0x81,0x24,0x20,0xc8,0x04,0x32,0x40,0x10,0x20,0xc3,0x20,0x80 } }, +{ 16, 0xf0e0, 0, {0xc8,0x00,0x02,0x4a,0x0c,0xa0,0x01,0x24,0x10,0xc8,0x08,0x32,0x41,0x10,0x00,0x00 } }, +{ 16, 0xf0f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x90,0x03,0x00,0x00,0xc9,0x04 } }, +{ 16, 0xf100, 0, {0x30,0x40,0x00,0x90,0x00,0x20,0x00,0x80,0x00,0x10,0x40,0x10,0x00,0x40,0x20,0x10 } }, +{ 16, 0xf110, 0, {0xc2,0x00,0x00,0x80,0x08,0x20,0x43,0x08,0x10,0x81,0x00,0x32,0x40,0x0c,0xc0,0x04 } }, +{ 16, 0xf120, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x40,0x00,0x00,0x00 } }, +{ 16, 0xf130, 0, {0x10,0x00,0x00,0xf0,0x10,0x20,0x00,0x00,0x00,0x10,0x00,0x00,0xf0,0x10,0x80,0x40 } }, +{ 16, 0xf140, 0, {0x00,0x00,0x00,0x40,0x00,0xf0,0x10,0x90,0x80,0x00,0x00,0x00,0x00,0x00,0xc0,0x00 } }, +{ 16, 0xf150, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x10,0x80,0x90,0x40,0x00,0x00 } }, +{ 16, 0xf160, 0, {0x00,0x80,0x10,0x90,0xa0,0x90,0x00,0x00,0x00,0x00,0x00,0x10,0x90,0x80,0x80,0x00 } }, +{ 16, 0xf170, 0, {0x00,0x00,0x00,0x00,0x10,0x90,0x80,0x90,0x00,0x00,0x00,0x00,0x40,0x10,0x8f,0x0f } }, +{ 16, 0xf180, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xc6,0xba,0x06,0xc0,0x1c } }, +{ 16, 0xf190, 0, {0x49,0x28,0x61,0x14,0x2b,0x1c,0x0e,0x40,0x3f,0xd9,0xbf,0xd9,0xaa,0xbc,0x1a,0x5f } }, +{ 16, 0xf1a0, 0, {0x00,0x10,0xa6,0x50,0x3b,0x61,0xb3,0x25,0xbc,0x40,0x19,0xbf,0xff,0xe9,0x80,0x00 } }, +{ 16, 0xf1b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x92,0x14,0x94,0x80,0x0c } }, +{ 16, 0xf1c0, 0, {0x07,0x3f,0x2b,0x94,0x86,0x14,0x84,0x80,0x28,0x00,0x00,0x49,0x14,0x04,0x86,0x12 } }, +{ 16, 0xf1d0, 0, {0x80,0x00,0x41,0x27,0x34,0xd0,0x90,0x84,0x92,0x00,0x2d,0x8a,0x21,0x1e,0x80,0x00 } }, +{ 16, 0xf1e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xa2 } }, +{ 16, 0xf1f0, 0, {0xb1,0x01,0x01,0x00,0x00,0x00,0x00,0x08,0x84,0xb1,0x78,0x28,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf200, 0, {0x08,0xb1,0x32,0x14,0x14,0x00,0x00,0x00,0x00,0x08,0xa8,0x23,0x54,0x21,0x40,0x00 } }, +{ 16, 0xf210, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf220, 0, {0x00,0x00,0x00,0x2f,0xff,0xfe,0xf7,0xc0,0x00,0x00,0x00,0x00,0x2f,0xd7,0xfe,0xef } }, +{ 16, 0xf230, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0x7f,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf240, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf250, 0, {0x00,0x00,0x00,0x0f,0xef,0x77,0xff,0xc0,0x00,0x00,0x00,0x00,0x3e,0xff,0xfe,0xef } }, +{ 16, 0xf260, 0, {0x40,0x00,0x00,0x00,0x00,0x3f,0xff,0xbf,0xff,0x40,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf270, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf280, 0, {0x00,0x00,0x00,0x3f,0xff,0xdf,0xff,0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff } }, +{ 16, 0xf290, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0x7f,0x2f,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf2a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf2b0, 0, {0x00,0x00,0x00,0x1f,0xff,0xff,0xef,0xc0,0x00,0x00,0x00,0x00,0x1f,0xef,0xef,0xef } }, +{ 16, 0xf2c0, 0, {0xc0,0x00,0x00,0x00,0x00,0x2f,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf2d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf2e0, 0, {0x00,0x00,0x00,0x3f,0xff,0xef,0xff,0xc0,0x00,0x00,0x00,0x00,0x2f,0xaf,0xdf,0xff } }, +{ 16, 0xf2f0, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xef,0xff,0xf7,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf300, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf310, 0, {0x00,0x00,0x00,0x3f,0xdf,0xdf,0xff,0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff } }, +{ 16, 0xf320, 0, {0xc0,0x00,0x00,0x00,0x00,0x1f,0xff,0xdf,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf330, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc4,0x24,0xa1,0x00,0x2c } }, +{ 16, 0xf340, 0, {0x52,0x0b,0x18,0xc2,0x86,0x2c,0xa1,0x80,0x38,0x62,0x0a,0x08,0x40,0xc4,0x2c,0xa1 } }, +{ 16, 0xf350, 0, {0x08,0x28,0x42,0x0b,0x14,0x00,0x85,0x14,0xa1,0x08,0x28,0x43,0x0a,0x10,0x00,0x00 } }, +{ 16, 0xf360, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x12,0x01,0x03,0x80 } }, +{ 16, 0xf370, 0, {0x61,0x20,0x10,0x08,0x07,0x12,0x41,0x42,0x80,0x70,0x20,0x1c,0x08,0x04,0x1a,0x01 } }, +{ 16, 0xf380, 0, {0x84,0x81,0x40,0x20,0x18,0x08,0x46,0x36,0x81,0x05,0x80,0x63,0x20,0x10,0x00,0x01 } }, +{ 16, 0xf390, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x24,0x21,0x00,0x0c } }, +{ 16, 0xf3a0, 0, {0x52,0x02,0x14,0x00,0x87,0x28,0x21,0x81,0x08,0x72,0x06,0x1c,0x82,0x84,0x20,0x21 } }, +{ 16, 0xf3b0, 0, {0x48,0x18,0x42,0x03,0x54,0x80,0x45,0x30,0x25,0x4a,0x18,0x53,0x02,0x10,0x00,0x01 } }, +{ 16, 0xf3c0, 0, {0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x22,0x01,0x01,0x80 } }, +{ 16, 0xf3d0, 0, {0x42,0x20,0x18,0xc8,0x44,0x22,0x01,0x80,0x84,0x42,0x20,0x1c,0x88,0x04,0x22,0x01 } }, +{ 16, 0xf3e0, 0, {0x00,0x80,0x40,0x20,0x10,0x88,0x44,0x36,0x01,0x40,0x80,0x41,0x00,0x10,0x00,0x00 } }, +{ 16, 0xf3f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x08,0x20,0x00,0x0c } }, +{ 16, 0xf400, 0, {0x22,0x03,0x04,0x40,0x81,0x00,0x20,0x84,0x08,0x03,0x00,0x00,0x80,0xc2,0x00,0x20 } }, +{ 16, 0xf410, 0, {0xc4,0x08,0x00,0x03,0x08,0x88,0x82,0x16,0xa0,0x40,0x88,0x32,0x22,0x80,0x00,0x00 } }, +{ 16, 0xf420, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x02,0x01,0x00,0x80,0x04,0x20 } }, +{ 16, 0xf430, 0, {0x10,0x08,0x0c,0xc2,0x12,0x10,0x84,0xc8,0x22,0x12,0x08,0x04,0x02,0x03,0x00,0x88 } }, +{ 16, 0xf440, 0, {0x00,0x21,0x00,0x0c,0x0c,0x40,0x41,0x30,0x00,0x84,0x20,0x10,0x08,0x00,0x02,0x00 } }, +{ 16, 0xf450, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x82,0x06,0x20,0x08,0x8c } }, +{ 16, 0xf460, 0, {0x32,0x22,0x0c,0x88,0x81,0x26,0x20,0x4d,0x88,0x23,0x22,0x80,0x88,0x83,0x06,0x20 } }, +{ 16, 0xf470, 0, {0x08,0x88,0x00,0x23,0x04,0x8a,0x81,0x36,0x20,0x4b,0x88,0x32,0x22,0x00,0x00,0x00 } }, +{ 16, 0xf480, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x02,0x02,0x00,0x09,0x80 } }, +{ 16, 0xf490, 0, {0x32,0x20,0x04,0x88,0x60,0x22,0x00,0x89,0x84,0x00,0x20,0x08,0x98,0x00,0x02,0x00 } }, +{ 16, 0xf4a0, 0, {0x00,0x80,0x00,0x20,0x00,0x08,0x02,0x3a,0x80,0x48,0x80,0x30,0x20,0x00,0x02,0x00 } }, +{ 16, 0xf4b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0a,0xc4,0x1a,0xa1,0x80,0xa8 } }, +{ 16, 0xf4c0, 0, {0x41,0x2a,0x10,0xca,0xc7,0x1a,0xa1,0x04,0xad,0x71,0x2a,0x18,0x4a,0xd4,0x06,0xb1 } }, +{ 16, 0xf4d0, 0, {0x00,0xa8,0x71,0x2a,0x10,0x08,0x84,0x26,0x29,0x06,0xac,0x52,0x2a,0x10,0x02,0x00 } }, +{ 16, 0xf4e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x04,0x2a,0x01,0x41,0x80 } }, +{ 16, 0xf4f0, 0, {0x42,0x20,0x1c,0x00,0x04,0x0a,0x01,0x09,0x84,0x51,0x20,0x1c,0x88,0x44,0x02,0x01 } }, +{ 16, 0xf500, 0, {0x08,0x80,0x40,0x20,0x10,0x4a,0x47,0x02,0x01,0x48,0x80,0x63,0x20,0x10,0x02,0x00 } }, +{ 16, 0xf510, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xc4,0x10,0x21,0x81,0x0c } }, +{ 16, 0xf520, 0, {0x41,0x02,0x0c,0x00,0xc0,0x20,0x61,0x0d,0x0e,0x72,0x02,0x1c,0x40,0xc4,0x08,0x31 } }, +{ 16, 0xf530, 0, {0x04,0x18,0x42,0x02,0x10,0x80,0x87,0x20,0xb1,0xc4,0x0c,0x53,0x02,0x10,0x00,0x00 } }, +{ 16, 0xf540, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x20,0x07,0x24,0x01,0xcc,0x00 } }, +{ 16, 0xf550, 0, {0x72,0x40,0x14,0x00,0x04,0x24,0x01,0x08,0x00,0x73,0x41,0x10,0xc0,0x07,0x30,0x11 } }, +{ 16, 0xf560, 0, {0xcc,0x00,0x71,0x01,0x10,0x02,0x04,0x20,0x81,0x46,0x10,0x42,0x40,0x10,0x02,0x04 } }, +{ 16, 0xf570, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xc5,0x10,0x21,0x00,0x08 } }, +{ 16, 0xf580, 0, {0x62,0x02,0x1c,0x90,0xc5,0x24,0x21,0x00,0x0c,0x70,0x82,0x1c,0x10,0xc4,0x20,0x31 } }, +{ 16, 0xf590, 0, {0x88,0x02,0x40,0x06,0x1c,0x00,0x85,0x00,0xa1,0x00,0x0c,0x40,0x42,0x00,0x02,0x00 } }, +{ 16, 0xf5a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x05,0x14,0x80,0x01,0x20 } }, +{ 16, 0xf5b0, 0, {0x30,0x08,0x0c,0x42,0x06,0x00,0x80,0x01,0x24,0x51,0x08,0x0c,0x02,0x41,0x00,0x80 } }, +{ 16, 0xf5c0, 0, {0x4c,0x20,0x00,0x08,0x0c,0x30,0x42,0x04,0x00,0x04,0x20,0x00,0x08,0x00,0x00,0x00 } }, +{ 16, 0xf5d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xc6,0x24,0x20,0x00,0x0c } }, +{ 16, 0xf5e0, 0, {0x32,0xc2,0x04,0x80,0xc7,0x30,0x20,0x00,0x0c,0x53,0xc2,0x04,0x10,0xc2,0x28,0x70 } }, +{ 16, 0xf5f0, 0, {0x0c,0x09,0x02,0x02,0x4c,0x80,0x81,0x04,0x30,0x09,0x0c,0x02,0x42,0x10,0x00,0x00 } }, +{ 16, 0xf600, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x80,0x01,0x38,0x00,0x02,0x00 } }, +{ 16, 0xf610, 0, {0x12,0x40,0x0c,0x20,0x07,0x34,0x04,0x02,0x00,0x63,0x01,0x08,0x10,0x00,0x24,0x10 } }, +{ 16, 0xf620, 0, {0x04,0x00,0x02,0x01,0x04,0x82,0x01,0x08,0x80,0x09,0x10,0x02,0x40,0x10,0x00,0x04 } }, +{ 16, 0xf630, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x20,0x10,0x80,0x00,0x00 } }, +{ 16, 0xf640, 0, {0x20,0x80,0x00,0xf0,0x20,0x10,0x80,0x00,0x00,0x20,0x80,0x00,0xd0,0x80,0x00,0x00 } }, +{ 16, 0xf650, 0, {0x40,0x00,0x00,0x00,0x00,0x30,0x10,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0xcc,0x40 } }, +{ 16, 0xf660, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x10,0x80,0x80,0x00,0x00,0x00 } }, +{ 16, 0xf670, 0, {0x00,0x00,0x10,0x90,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x10,0x90,0x80,0x00,0x90 } }, +{ 16, 0xf680, 0, {0x80,0x00,0x10,0x00,0x00,0x10,0xa0,0x80,0x00,0x00,0x00,0x20,0x00,0x10,0x8c,0x08 } }, +{ 16, 0xf690, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x1a,0xbe,0x17,0x80,0x00 } }, +{ 16, 0xf6a0, 0, {0x3e,0x40,0x26,0x6f,0xba,0xe3,0x24,0x80,0x00,0x16,0x59,0xbd,0x82,0x81,0x82,0xd8 } }, +{ 16, 0xf6b0, 0, {0x80,0x00,0x00,0x19,0x99,0x86,0x80,0x64,0x80,0xc0,0x3f,0xd9,0x99,0x80,0x00,0x01 } }, +{ 16, 0xf6c0, 0, {0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x16,0x02,0x94,0x00,0x16 } }, +{ 16, 0xf6d0, 0, {0xc0,0x16,0x94,0x82,0x90,0x16,0x10,0x80,0x21,0x18,0x28,0x28,0x02,0x0a,0x02,0x08 } }, +{ 16, 0xf6e0, 0, {0x80,0x00,0x00,0x00,0x00,0x02,0x82,0x80,0x14,0x00,0x01,0x14,0x11,0xa0,0x40,0x00 } }, +{ 16, 0xf6f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x84 } }, +{ 16, 0xf700, 0, {0x02,0x84,0xa8,0x80,0x00,0x00,0x00,0x08,0x91,0x22,0x84,0x41,0xa2,0x08,0x24,0x01 } }, +{ 16, 0xf710, 0, {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x84,0x01,0x44,0x01,0x00,0x00 } }, +{ 16, 0xf720, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf730, 0, {0x00,0x00,0x00,0x3e,0xf7,0xff,0xf7,0xc0,0x00,0x00,0x00,0x00,0x2f,0xe7,0xb7,0xff } }, +{ 16, 0xf740, 0, {0xc0,0x00,0x00,0x00,0x00,0x2f,0xfe,0x7f,0xf7,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf750, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf760, 0, {0x00,0x00,0x00,0x36,0xbf,0xfe,0xdf,0xc0,0x00,0x00,0x00,0x00,0x0f,0xf7,0xdf,0xff } }, +{ 16, 0xf770, 0, {0xc0,0x00,0x00,0x00,0x00,0x3d,0xb7,0xb7,0xef,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf780, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf790, 0, {0x00,0x00,0x00,0x1f,0xdf,0xdf,0xff,0xc0,0x00,0x00,0x00,0x00,0x0f,0xdf,0xdf,0xff } }, +{ 16, 0xf7a0, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xef,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf7b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf7c0, 0, {0x00,0x00,0x00,0x3f,0xbf,0x7f,0xff,0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0x7f,0xf7 } }, +{ 16, 0xf7d0, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xdf,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf7e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf7f0, 0, {0x00,0x00,0x00,0x3f,0x7e,0xff,0xff,0x40,0x00,0x00,0x00,0x00,0x3f,0xfe,0xff,0xff } }, +{ 16, 0xf800, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf810, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00 } }, +{ 16, 0xf820, 0, {0x00,0x00,0x00,0x37,0xff,0x6f,0xff,0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff } }, +{ 16, 0xf830, 0, {0xc0,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf840, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf850, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf860, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf870, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x20,0x01,0x02,0x00,0x00,0x00 } }, +{ 16, 0xf880, 0, {0x30,0x00,0x43,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf890, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf8f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x00,0x00,0x00,0x00,0x30 } }, +{ 16, 0xf900, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf910, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf920, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf930, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf940, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf950, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x30,0xc0,0x00 } }, +{ 16, 0xf960, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf970, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf980, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf990, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf9a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf9b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x30,0xc0,0x30,0xc0,0x30 } }, +{ 16, 0xf9c0, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf9d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf9e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xf9f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x0f } }, +{ 16, 0xfa20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x00,0x00,0x00,0x00,0x3f } }, +{ 16, 0xfa80, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfa90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfaa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfab0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfac0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfad0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x30,0xc0,0x30,0xc0,0x0f } }, +{ 16, 0xfae0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfaf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x6b,0x00,0xc0,0x00,0xcf,0x2c } }, +{ 16, 0xfb40, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfb90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x00 } }, +{ 16, 0xfba0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfbb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfbc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfbd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfbe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfbf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x0f,0x00,0x0f,0x00,0x30 } }, +{ 16, 0xfc00, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x3f,0xc0,0x00 } }, +{ 16, 0xfc60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfc90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfca0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfcb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x3f,0xc0,0x3f,0xc0,0x30 } }, +{ 16, 0xfcc0, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfcd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfce0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfcf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f } }, +{ 16, 0xfd20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x0f,0x00,0x0f,0x00,0x3f } }, +{ 16, 0xfd80, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfd90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfda0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfdb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfdc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfdd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x3f,0xc0,0x3f,0xc0,0x0f } }, +{ 16, 0xfde0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfdf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x33,0x5d,0x80,0xc0,0x00,0xfd,0xac } }, +{ 16, 0xfe40, 0, {0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfe90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfea0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfeb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfec0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfed0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfee0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfef0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x00,0x00,0x00,0x00,0x30 } }, +{ 16, 0xff00, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x30,0xc0,0x00 } }, +{ 16, 0xff60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xff90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xffa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xffb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x30,0xc0,0x30,0xc0,0x30 } }, +{ 16, 0xffc0, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xffd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xffe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0xfff0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8010, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8020, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x0f } }, +{ 16, 0x8030, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8040, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8050, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8060, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8070, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8080, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x00,0x00,0x00,0x00,0x3f } }, +{ 16, 0x8090, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x80e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x30,0xc0,0x30,0xc0,0x0f } }, +{ 16, 0x80f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8100, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8110, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8120, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8130, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8140, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x74,0xc0,0xc0,0x00,0xf0,0xec } }, +{ 16, 0x8150, 0, {0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8160, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8170, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8180, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8190, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x81a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x00 } }, +{ 16, 0x81b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x81c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x81d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x81e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x81f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8200, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc0,0x0f,0x00,0x0f,0x00,0x30 } }, +{ 16, 0x8210, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8220, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8230, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8240, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8250, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8260, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x3f,0xc0,0x00 } }, +{ 16, 0x8270, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8280, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8290, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x82a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x82b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x82c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x86,0x10,0x80,0x30,0x82,0x3d } }, +{ 16, 0x82d0, 0, {0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x82e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x82f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8300, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8310, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8320, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x0f,0x00,0x0f,0x00,0x0f } }, +{ 16, 0x8330, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8340, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8350, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8360, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8370, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8380, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xc0,0x0f,0x00,0x0f,0x00,0x3f } }, +{ 16, 0x8390, 0, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x83a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x83b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x83c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x83d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x83e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x3f,0xc0,0x3f,0xc0,0x0f } }, +{ 16, 0x83f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8400, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8410, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8420, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8430, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8440, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x65,0x25,0xe4,0x80,0x00,0xb0,0x88 } }, +{ 16, 0x8450, 0, {0xab,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8460, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8470, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8480, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8490, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x84a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x84b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x84c0, 0, {0x00,0x00,0x00,0x00,0x30,0x00,0x20,0x01,0x02,0x02,0x00,0x00,0x30,0x00,0x43,0x00 } }, +{ 16, 0x84d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x84e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x84f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8500, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8510, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8520, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8530, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8540, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8550, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8560, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8570, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8580, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8590, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x85f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8600, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8610, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8620, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8630, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8640, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8650, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8660, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8670, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8680, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8690, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x86f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8700, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8710, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8720, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8730, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8740, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8750, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8760, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8770, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8780, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8790, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x87f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8800, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8810, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8820, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8830, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8840, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8850, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8860, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8870, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8880, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8890, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x88f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8900, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8910, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8920, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8930, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8940, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8950, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8960, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8970, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8980, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8990, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89d0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89e0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x89f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8a90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8aa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ab0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ac0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ad0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ae0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8af0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8b90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ba0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8bb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8bc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8bd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8be0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8bf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8c90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ca0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8cb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8cc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8cd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ce0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8cf0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8d90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8da0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8db0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8dc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8dd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8de0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8df0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8e90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ea0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8eb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ec0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ed0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ee0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ef0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f00, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f10, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f20, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f30, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f40, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f50, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f60, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f70, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f80, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8f90, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8fa0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8fb0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8fc0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8fd0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8fe0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x8ff0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9000, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9010, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9020, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9030, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9040, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9050, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9060, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9070, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9080, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9090, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x90a0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x90b0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x90c0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x90d0, 0, {0x30,0x00,0x00,0x01,0x00,0x00,0x44,0x72,0x30,0x00,0x80,0x01,0x00,0x00,0x00,0x03 } }, +{ 16, 0x90e0, 0, {0x30,0x00,0x40,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x90f0, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9100, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 16, 0x9110, 0, {0x00,0x00,0x00,0x00,0x30,0x00,0x80,0x01,0x00,0x00,0x00,0x05,0x30,0x00,0xa0,0x01 } }, +{ 16, 0x9120, 0, {0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x01,0x00,0x00,0xe1,0x5a,0x00,0x00,0x00,0x00 } }, +{ 12, 0x9130, 0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, +{ 0 , 0x0000, 1, {0 }} +}; +// VERSION=1.1.1.131 +// DATE=2001dec06 +// PRODUCT=EMI 2|6 +/* + * This firmware is for the Emagic EMI 2|6 Audio Interface + * + * The firmware contained herein is Copyright (c) 1999-2002 Emagic + * as an unpublished work. This notice does not imply unrestricted + * or public access to this firmware which is a trade secret of Emagic, + * and which may not be reproduced, used, sold or transferred to + * any third party without Emagic's written consent. All Rights Reserved. + * + * This firmware may not be modified and may only be used with the + * Emagic EMI 2|6 Audio Interface. Distribution and/or Modification of + * any driver which includes this firmware, in whole or in part, + * requires the inclusion of this statement. + */ +INTEL_HEX_RECORD g_Firmware[] = { +{ 3,0x0000,0,{0x02,0x43,0x56} }, +{ 3,0x0003,0,{0x02,0x4b,0xcd} }, +{ 3,0x000b,0,{0x02,0x4b,0xd2} }, +{ 3,0x0013,0,{0x02,0x4b,0x92} }, +{ 3,0x001b,0,{0x02,0x4b,0xd5} }, +{ 3,0x0023,0,{0x02,0x1b,0x39} }, +{ 3,0x002b,0,{0x02,0x43,0xe2} }, +{ 3,0x0033,0,{0x02,0x3f,0xf3} }, +{ 3,0x003b,0,{0x02,0x4b,0xc0} }, +{ 3,0x0043,0,{0x02,0x47,0x00} }, +{ 3,0x004b,0,{0x02,0x3f,0xfc} }, +{ 3,0x0053,0,{0x02,0x37,0xfa} }, +{ 3,0x005b,0,{0x02,0x4b,0xc7} }, +{ 3,0x0063,0,{0x02,0x46,0xfc} }, +{ 16,0x0500,0,{0x12,0x01,0x10,0x01,0x00,0x00,0x00,0x40,0x6a,0x08,0x01,0x01,0x00,0x01,0x01,0x02} }, +{ 16,0x0510,0,{0x00,0x01,0x09,0x02,0xb8,0x01,0x03,0x01,0x00,0x80,0xa0,0x09,0x04,0x00,0x00,0x00} }, +{ 16,0x0520,0,{0x01,0x01,0x00,0x00,0x0a,0x24,0x01,0x00,0x01,0x56,0x00,0x02,0x01,0x02,0x0c,0x24} }, +{ 16,0x0530,0,{0x02,0x01,0x01,0x01,0x00,0x06,0x00,0x00,0x00,0x00,0x15,0x24,0x06,0x05,0x01,0x02} }, +{ 16,0x0540,0,{0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09} }, +{ 16,0x0550,0,{0x24,0x03,0x02,0x04,0x03,0x00,0x05,0x00,0x0c,0x24,0x02,0x03,0x01,0x02,0x00,0x02} }, +{ 16,0x0560,0,{0x00,0x00,0x00,0x00,0x0d,0x24,0x06,0x06,0x03,0x02,0x03,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x0570,0,{0x00,0x09,0x24,0x03,0x04,0x01,0x01,0x00,0x06,0x00,0x09,0x04,0x01,0x00,0x00,0x01} }, +{ 16,0x0580,0,{0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x02,0x01,0x02,0x00,0x00,0x07,0x24,0x01,0x01} }, +{ 16,0x0590,0,{0x00,0x01,0x00,0x11,0x24,0x02,0x01,0x02,0x02,0x10,0x03,0x44,0xac,0x00,0x80,0xbb} }, +{ 16,0x05a0,0,{0x00,0x00,0x77,0x01,0x09,0x05,0x0a,0x05,0x84,0x01,0x01,0x00,0x8f,0x07,0x25,0x01} }, +{ 16,0x05b0,0,{0x01,0x00,0x00,0x00,0x09,0x05,0x8f,0x01,0x03,0x00,0x01,0x06,0x00,0x09,0x04,0x01} }, +{ 16,0x05c0,0,{0x02,0x02,0x01,0x02,0x00,0x00,0x07,0x24,0x01,0x01,0x00,0x01,0x00,0x0e,0x24,0x02} }, +{ 16,0x05d0,0,{0x01,0x06,0x02,0x10,0x02,0x44,0xac,0x00,0x80,0xbb,0x00,0x09,0x05,0x0a,0x05,0x4c} }, +{ 16,0x05e0,0,{0x02,0x01,0x00,0x8f,0x07,0x25,0x01,0x01,0x00,0x00,0x00,0x09,0x05,0x8f,0x01,0x03} }, +{ 16,0x05f0,0,{0x00,0x01,0x06,0x00,0x09,0x04,0x01,0x03,0x02,0x01,0x02,0x00,0x00,0x07,0x24,0x01} }, +{ 16,0x0600,0,{0x01,0x00,0x01,0x00,0x0e,0x24,0x02,0x01,0x06,0x03,0x18,0x02,0x44,0xac,0x00,0x80} }, +{ 16,0x0610,0,{0xbb,0x00,0x09,0x05,0x0a,0x05,0x72,0x03,0x01,0x00,0x8f,0x07,0x25,0x01,0x01,0x00} }, +{ 16,0x0620,0,{0x00,0x00,0x09,0x05,0x8f,0x01,0x03,0x00,0x01,0x06,0x00,0x09,0x04,0x01,0x04,0x02} }, +{ 16,0x0630,0,{0x01,0x02,0x00,0x00,0x07,0x24,0x01,0x01,0x00,0x01,0x00,0x0b,0x24,0x02,0x01,0x02} }, +{ 16,0x0640,0,{0x03,0x18,0x01,0x00,0x77,0x01,0x09,0x05,0x0a,0x05,0x46,0x02,0x01,0x00,0x8f,0x07} }, +{ 16,0x0650,0,{0x25,0x01,0x01,0x00,0x00,0x00,0x09,0x05,0x8f,0x01,0x03,0x00,0x01,0x06,0x00,0x09} }, +{ 16,0x0660,0,{0x04,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x09,0x04,0x02,0x01,0x01,0x01,0x02,0x00} }, +{ 16,0x0670,0,{0x00,0x07,0x24,0x01,0x04,0x00,0x01,0x00,0x11,0x24,0x02,0x01,0x02,0x02,0x10,0x03} }, +{ 16,0x0680,0,{0x44,0xac,0x00,0x80,0xbb,0x00,0x00,0x77,0x01,0x09,0x05,0x8c,0x05,0x84,0x01,0x01} }, +{ 16,0x0690,0,{0x00,0x00,0x07,0x25,0x01,0x01,0x02,0x00,0x00,0x09,0x04,0x02,0x02,0x01,0x01,0x02} }, +{ 16,0x06a0,0,{0x00,0x00,0x07,0x24,0x01,0x04,0x00,0x01,0x00,0x11,0x24,0x02,0x01,0x02,0x03,0x18} }, +{ 16,0x06b0,0,{0x03,0x44,0xac,0x00,0x80,0xbb,0x00,0x00,0x77,0x01,0x09,0x05,0x8c,0x05,0x46,0x02} }, +{ 16,0x06c0,0,{0x01,0x00,0x00,0x07,0x25,0x01,0x01,0x02,0x00,0x00,0x05,0x0c,0x09,0x01,0xa1,0x01} }, +{ 16,0x06d0,0,{0x05,0x0c,0x09,0xe9,0x05,0x0c,0x09,0xea,0x15,0x00,0x25,0x01,0x95,0x02,0x75,0x01} }, +{ 16,0x06e0,0,{0x81,0x42,0x95,0x01,0x75,0x06,0x81,0x01,0x05,0x0c,0x09,0x00,0x05,0x0c,0x09,0x00} }, +{ 16,0x06f0,0,{0x15,0x00,0x25,0x01,0x95,0x02,0x75,0x01,0x91,0x06,0x95,0x01,0x75,0x06,0x91,0x03} }, +{ 16,0x0700,0,{0xc0,0x04,0x03,0x09,0x04,0x18,0x03,0x45,0x00,0x4d,0x00,0x41,0x00,0x47,0x00,0x49} }, +{ 16,0x0710,0,{0x00,0x43,0x00,0x20,0x00,0x47,0x00,0x6d,0x00,0x62,0x00,0x48,0x00,0x1e,0x03,0x45} }, +{ 16,0x0720,0,{0x00,0x6d,0x00,0x61,0x00,0x67,0x00,0x69,0x00,0x63,0x00,0x20,0x00,0x45,0x00,0x4d} }, +{ 16,0x0730,0,{0x00,0x49,0x00,0x20,0x00,0x32,0x00,0x7c,0x00,0x36,0x00,0x2a,0x03,0x43,0x00,0x6f} }, +{ 16,0x0740,0,{0x00,0x6e,0x00,0x66,0x00,0x69,0x00,0x67,0x00,0x75,0x00,0x72,0x00,0x61,0x00,0x74} }, +{ 16,0x0750,0,{0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69} }, +{ 16,0x0760,0,{0x00,0x6e,0x00,0x67,0x00,0x22,0x03,0x49,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x72} }, +{ 16,0x0770,0,{0x00,0x66,0x00,0x61,0x00,0x63,0x00,0x65,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x72} }, +{ 9,0x0780,0,{0x00,0x69,0x00,0x6e,0x00,0x67,0x00,0x00,0x00} }, +{ 16,0x0789,0,{0x74,0x00,0xf5,0x86,0x90,0xfd,0xa5,0x7c,0x05,0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} }, +{ 1,0x0799,0,{0x22} }, +{ 16,0x079a,0,{0x90,0x7f,0xd6,0xe0,0x44,0x80,0xf0,0x43,0x87,0x01,0x00,0x00,0x00,0x00,0x00,0x22} }, +{ 16,0x07aa,0,{0xc0,0xd0,0xc0,0xe0,0x8f,0xe0,0xc0,0xe0,0x8e,0xe0,0xc0,0xe0,0x8d,0xe0,0xc0,0xe0} }, +{ 16,0x07ba,0,{0x8c,0xe0,0xc0,0xe0,0xc0,0x82,0xc0,0x83,0x05,0x86,0xc0,0x84,0xc0,0x85,0xe5,0x18} }, +{ 16,0x07ca,0,{0xb4,0x02,0x03,0x02,0x07,0xd9,0xb4,0x01,0x03,0x02,0x07,0xde,0x02,0x07,0xfa,0x7d} }, +{ 16,0x07da,0,{0x01,0x02,0x08,0x16,0xe5,0x19,0x14,0xf5,0x19,0xc3,0xb5,0x13,0x03,0x02,0x07,0xf5} }, +{ 16,0x07ea,0,{0x50,0x09,0xb4,0x00,0xea,0x75,0x19,0x0a,0x02,0x07,0xd9,0x7d,0x00,0x02,0x08,0x16} }, +{ 16,0x07fa,0,{0xe5,0x19,0x14,0xf5,0x19,0xc3,0xb5,0x14,0x03,0x02,0x08,0x11,0x50,0x09,0xb4,0x00} }, +{ 16,0x080a,0,{0xce,0x75,0x19,0x0a,0x02,0x07,0xd9,0x7d,0x02,0x02,0x08,0x16,0x7c,0x05,0x90,0x7f} }, +{ 16,0x081a,0,{0x99,0xe0,0x54,0x40,0xdc,0x03,0x02,0x08,0x43,0xb4,0x00,0x1d,0x90,0x7f,0xe3,0x74} }, +{ 16,0x082a,0,{0x7b,0xf0,0xa3,0x74,0x80,0xf0,0x90,0x7f,0xe2,0x74,0x40,0xf0,0x90,0x7f,0xe5,0xf0} }, +{ 16,0x083a,0,{0x90,0x7f,0xe2,0x74,0x00,0xf0,0x02,0x08,0x18,0x05,0x86,0x90,0x7f,0xe2,0x74,0x80} }, +{ 16,0x084a,0,{0xf0,0x90,0x79,0x65,0xe0,0xb4,0x01,0x03,0x02,0x08,0x9e,0xb4,0x02,0x03,0x02,0x08} }, +{ 16,0x085a,0,{0x96,0xb4,0x03,0x03,0x02,0x08,0x8e,0xb4,0x04,0x03,0x02,0x08,0x86,0xb4,0x05,0x03} }, +{ 16,0x086a,0,{0x02,0x08,0x7e,0xb4,0x06,0x03,0x02,0x08,0x76,0x02,0x08,0xf4,0x05,0x86,0x90,0x7f} }, +{ 16,0x087a,0,{0x6c,0x02,0x08,0xe9,0x05,0x86,0x90,0x7f,0x6c,0x02,0x08,0xdd,0x05,0x86,0x90,0x7f} }, +{ 16,0x088a,0,{0x6c,0x02,0x08,0xcf,0x05,0x86,0x90,0x7f,0x6c,0x02,0x08,0xc0,0x05,0x86,0x90,0x7f} }, +{ 16,0x089a,0,{0x6c,0x02,0x08,0xb2,0x05,0x86,0x90,0x7f,0x6c,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xf0} }, +{ 16,0x08aa,0,{0x0d,0xed,0xb4,0x2d,0xf4,0x02,0x08,0xf4,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0d,0xed} }, +{ 16,0x08ba,0,{0xb4,0x2d,0xf5,0x02,0x08,0xf4,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xf0,0x0d,0xed,0xb4} }, +{ 16,0x08ca,0,{0x31,0xf4,0x02,0x08,0xf4,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0d,0xed,0xb4,0x31,0xf5} }, +{ 16,0x08da,0,{0x02,0x08,0xf4,0xf0,0xf0,0xf0,0xf0,0x0d,0xed,0xb4,0x61,0xf7,0x02,0x08,0xf4,0xf0} }, +{ 16,0x08ea,0,{0xf0,0xf0,0xf0,0xf0,0xf0,0x0d,0xed,0xb4,0x61,0xf5,0x90,0x7f,0xe2,0x74,0x00,0xf0} }, +{ 16,0x08fa,0,{0xd0,0x85,0xd0,0x84,0x05,0x86,0xd0,0x83,0xd0,0x82,0xd0,0xe0,0xfc,0xd0,0xe0,0xfd} }, +{ 5,0x090a,0,{0xd0,0xe0,0xfe,0xd0,0xe0} }, +{ 6,0x090f,0,{0xff,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0915,0,{0xc0,0xd0,0xc0,0xe0,0xc0,0x82,0xc0,0x83,0x90,0x7f,0x6f,0xe5,0x0c,0xf0,0xe5,0x0d} }, +{ 13,0x0925,0,{0xf0,0xe5,0x0e,0xf0,0xd0,0x83,0xd0,0x82,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0932,0,{0xc0,0xd0,0xc0,0xe0,0x8f,0xe0,0xc0,0xe0,0x8e,0xe0,0xc0,0xe0,0xc0,0x82,0xc0,0x83} }, +{ 16,0x0942,0,{0x05,0x86,0xc0,0x84,0xc0,0x85,0x90,0x79,0x70,0xe0,0xff,0xbf,0x00,0x03,0x02,0x0a} }, +{ 16,0x0952,0,{0xb8,0x90,0x7f,0x96,0xe0,0x44,0x80,0xf0,0x90,0x7f,0xe2,0x74,0x80,0xf0,0x90,0x7f} }, +{ 16,0x0962,0,{0x62,0xe0,0x05,0x86,0x90,0x7f,0xe2,0x74,0x00,0xf0,0x90,0x7f,0x96,0xe0,0x54,0x7f} }, +{ 16,0x0972,0,{0xf0,0x90,0x7f,0xe2,0x74,0x80,0xf0,0x90,0x79,0x88,0xe0,0xb4,0x01,0x03,0x02,0x09} }, +{ 16,0x0982,0,{0xbe,0xb4,0x02,0x03,0x02,0x09,0xc3,0xb4,0x03,0x03,0x02,0x09,0xac,0xb4,0x04,0x03} }, +{ 16,0x0992,0,{0x02,0x09,0x9a,0x05,0x86,0x02,0x0a,0xb2,0xef,0x54,0x03,0xfe,0xef,0x03,0x03,0x54} }, +{ 16,0x09a2,0,{0x3f,0xff,0x90,0x7f,0x63,0x05,0x86,0x02,0x09,0xc9,0xef,0x54,0x03,0xfe,0xef,0x03} }, +{ 16,0x09b2,0,{0x03,0x54,0x3f,0xff,0x90,0x7f,0x63,0x05,0x86,0x02,0x0a,0x36,0x05,0x86,0x02,0x0a} }, +{ 16,0x09c2,0,{0xa5,0x05,0x86,0x02,0x0a,0x8e,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0} }, +{ 16,0x09d2,0,{0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0x05,0x86} }, +{ 16,0x09e2,0,{0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0} }, +{ 16,0x09f2,0,{0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0x05,0x86,0xdf,0xca,0xee,0xb4,0x00,0x03} }, +{ 16,0x0a02,0,{0x02,0x0a,0xb2,0xb4,0x01,0x03,0x02,0x0a,0x25,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05} }, +{ 16,0x0a12,0,{0x86,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0} }, +{ 16,0x0a22,0,{0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0x05,0x86} }, +{ 16,0x0a32,0,{0x02,0x0a,0xb2,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0} }, +{ 13,0x0a42,0,{0xe0,0x05,0x86,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0x05,0x86} }, +{ 16,0x0a4f,0,{0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0x05,0x86,0xdf,0xd6} }, +{ 16,0x0a5f,0,{0xee,0xb4,0x00,0x03,0x02,0x0a,0xb2,0xb4,0x01,0x03,0x02,0x0a,0x80,0xe0,0xe0,0xe0} }, +{ 16,0x0a6f,0,{0xe0,0x05,0x86,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0x05} }, +{ 16,0x0a7f,0,{0x86,0xe0,0xe0,0xe0,0xe0,0x05,0x86,0xe0,0xe0,0x05,0x86,0x02,0x0a,0xb2,0xe0,0xe0} }, +{ 16,0x0a8f,0,{0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0} }, +{ 16,0x0a9f,0,{0xdf,0xec,0x02,0x0a,0xb2,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0} }, +{ 16,0x0aaf,0,{0xe0,0xdf,0xf2,0x90,0x7f,0xe2,0x74,0x00,0xf0,0xd0,0x85,0xd0,0x84,0x05,0x86,0xd0} }, +{ 14,0x0abf,0,{0x83,0xd0,0x82,0xd0,0xe0,0xfe,0xd0,0xe0,0xff,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0acd,0,{0xc0,0x82,0xc0,0x83,0xc0,0xe0,0xe8,0xc0,0xe0,0x78,0xd1,0xe8,0x14,0xf8,0x70,0xfb} }, +{ 10,0x0add,0,{0xd0,0xe0,0xf8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0x22} }, +{ 16,0x0ae7,0,{0xc0,0xd0,0xc0,0xe0,0x8f,0xe0,0xc0,0xe0,0x8e,0xe0,0xc0,0xe0,0x8d,0xe0,0xc0,0xe0} }, +{ 16,0x0af7,0,{0x8c,0xe0,0xc0,0xe0,0x75,0x86,0x00,0xc0,0x82,0xc0,0x83,0x05,0x86,0xc0,0x84,0xc0} }, +{ 16,0x0b07,0,{0x85,0x7e,0x00,0x90,0x79,0x8e,0xe0,0xb4,0x00,0x16,0x74,0x01,0xf0,0x90,0x06,0xca} }, +{ 16,0x0b17,0,{0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xe0,0xff,0x90,0x79,0x8d,0xf0,0x02,0x0b,0x39} }, +{ 16,0x0b27,0,{0x90,0x79,0x8d,0xe0,0xff,0x90,0x79,0x8f,0xe0,0xfd,0x90,0x79,0x90,0xe0,0xfc,0x02} }, +{ 16,0x0b37,0,{0x0b,0x46,0x90,0x06,0xca,0x05,0x86,0x90,0x7f,0x00,0x05,0x86,0x02,0x0b,0x51,0x8d} }, +{ 16,0x0b47,0,{0x84,0x8c,0x85,0x05,0x86,0x90,0x7f,0x00,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xa3} }, +{ 16,0x0b57,0,{0x0e,0xee,0xb4,0x40,0x03,0x02,0x0b,0x6c,0x05,0x86,0xdf,0xee,0x90,0x79,0x8e,0x74} }, +{ 16,0x0b67,0,{0x00,0xf0,0x02,0x0b,0x82,0x05,0x86,0xad,0x84,0xac,0x85,0x90,0x79,0x8f,0xed,0xf0} }, +{ 16,0x0b77,0,{0x90,0x79,0x90,0xec,0xf0,0x90,0x79,0x8d,0x1f,0xef,0xf0,0x90,0x7f,0xb5,0xee,0xf0} }, +{ 16,0x0b87,0,{0xd0,0x85,0xd0,0x84,0x05,0x86,0xd0,0x83,0xd0,0x82,0xd0,0xe0,0xfc,0xd0,0xe0,0xfd} }, +{ 11,0x0b97,0,{0xd0,0xe0,0xfe,0xd0,0xe0,0xff,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0ba2,0,{0xc0,0xd0,0xc0,0xe0,0xc0,0x82,0xc0,0x83,0x90,0x7f,0xae,0xe0,0x54,0xe0,0xf0,0x90} }, +{ 16,0x0bb2,0,{0x7f,0x96,0xe0,0x44,0x08,0x54,0xfb,0xf0,0x90,0x7f,0x97,0xe0,0x54,0xbf,0xf0,0x90} }, +{ 16,0x0bc2,0,{0x7f,0xe3,0x74,0x7b,0xf0,0x90,0x7f,0xe4,0x74,0x40,0xf0,0x90,0x79,0x78,0xe0,0x90} }, +{ 16,0x0bd2,0,{0x7b,0x40,0xf0,0x90,0x7f,0xe2,0x74,0x48,0xf0,0x90,0x7f,0xe5,0xe0,0x90,0x7f,0xe2} }, +{ 16,0x0be2,0,{0x74,0x00,0xf0,0x90,0x7f,0x96,0xe0,0x54,0xf7,0x44,0x04,0xf0,0x90,0x7f,0xe3,0x74} }, +{ 16,0x0bf2,0,{0x7b,0xf0,0x90,0x7f,0xe4,0x74,0x40,0xf0,0x90,0x79,0x79,0xe0,0x90,0x7b,0x40,0xf0} }, +{ 16,0x0c02,0,{0x90,0x7f,0xe2,0x74,0x48,0xf0,0x90,0x7f,0xe5,0xe0,0x90,0x7f,0xe2,0x74,0x00,0xf0} }, +{ 16,0x0c12,0,{0x90,0x7f,0x96,0xe0,0x54,0xf3,0xf0,0x90,0x7f,0xae,0xe0,0x44,0x1f,0xf0,0xd0,0x83} }, +{ 7,0x0c22,0,{0xd0,0x82,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0c29,0,{0xc0,0xd0,0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x90,0x79,0x2f,0xe0,0x64,0xff,0xc3,0x24} }, +{ 11,0x0c39,0,{0x01,0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0xd0,0xd0,0x22} }, +{ 16,0x0c44,0,{0xbb,0x01,0x06,0x89,0x82,0x8a,0x83,0xe0,0x22,0x50,0x02,0xe7,0x22,0xbb,0xfe,0x02} }, +{ 9,0x0c54,0,{0xe3,0x22,0x89,0x82,0x8a,0x83,0xe4,0x93,0x22} }, +{ 16,0x0c5d,0,{0xbb,0x01,0x0c,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0xe0,0x22,0x50} }, +{ 16,0x0c6d,0,{0x06,0xe9,0x25,0x82,0xf8,0xe6,0x22,0xbb,0xfe,0x06,0xe9,0x25,0x82,0xf8,0xe2,0x22} }, +{ 13,0x0c7d,0,{0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0xe4,0x93,0x22} }, +{ 16,0x0c8a,0,{0xbb,0x01,0x06,0x89,0x82,0x8a,0x83,0xf0,0x22,0x50,0x02,0xf7,0x22,0xbb,0xfe,0x01} }, +{ 2,0x0c9a,0,{0xf3,0x22} }, +{ 16,0x0c9c,0,{0xf8,0xbb,0x01,0x0d,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0xe8,0xf0} }, +{ 16,0x0cac,0,{0x22,0x50,0x06,0xe9,0x25,0x82,0xc8,0xf6,0x22,0xbb,0xfe,0x05,0xe9,0x25,0x82,0xc8} }, +{ 2,0x0cbc,0,{0xf2,0x22} }, +{ 16,0x0cbe,0,{0xc2,0xd5,0xec,0x30,0xe7,0x09,0xb2,0xd5,0xe4,0xc3,0x9d,0xfd,0xe4,0x9c,0xfc,0xee} }, +{ 16,0x0cce,0,{0x30,0xe7,0x15,0xb2,0xd5,0xe4,0xc3,0x9f,0xff,0xe4,0x9e,0xfe,0x12,0x0e,0x40,0xc3} }, +{ 16,0x0cde,0,{0xe4,0x9d,0xfd,0xe4,0x9c,0xfc,0x80,0x03,0x12,0x0e,0x40,0x30,0xd5,0x07,0xc3,0xe4} }, +{ 6,0x0cee,0,{0x9f,0xff,0xe4,0x9e,0xfe,0x22} }, +{ 16,0x0cf4,0,{0xc5,0xf0,0xf8,0xa3,0xe0,0x28,0xf0,0xc5,0xf0,0xf8,0xe5,0x82,0x15,0x82,0x70,0x02} }, +{ 6,0x0d04,0,{0x15,0x83,0xe0,0x38,0xf0,0x22} }, +{ 16,0x0d0a,0,{0xbb,0x01,0x10,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0xe0,0xf5,0xf0} }, +{ 16,0x0d1a,0,{0xa3,0xe0,0x22,0x50,0x09,0xe9,0x25,0x82,0xf8,0x86,0xf0,0x08,0xe6,0x22,0xbb,0xfe} }, +{ 16,0x0d2a,0,{0x0a,0xe9,0x25,0x82,0xf8,0xe2,0xf5,0xf0,0x08,0xe2,0x22,0xe5,0x83,0x2a,0xf5,0x83} }, +{ 8,0x0d3a,0,{0xe9,0x93,0xf5,0xf0,0xa3,0xe9,0x93,0x22} }, +{ 16,0x0d42,0,{0xe8,0x8f,0xf0,0xa4,0xcc,0x8b,0xf0,0xa4,0x2c,0xfc,0xe9,0x8e,0xf0,0xa4,0x2c,0xfc} }, +{ 16,0x0d52,0,{0x8a,0xf0,0xed,0xa4,0x2c,0xfc,0xea,0x8e,0xf0,0xa4,0xcd,0xa8,0xf0,0x8b,0xf0,0xa4} }, +{ 16,0x0d62,0,{0x2d,0xcc,0x38,0x25,0xf0,0xfd,0xe9,0x8f,0xf0,0xa4,0x2c,0xcd,0x35,0xf0,0xfc,0xeb} }, +{ 16,0x0d72,0,{0x8e,0xf0,0xa4,0xfe,0xa9,0xf0,0xeb,0x8f,0xf0,0xa4,0xcf,0xc5,0xf0,0x2e,0xcd,0x39} }, +{ 15,0x0d82,0,{0xfe,0xe4,0x3c,0xfc,0xea,0xa4,0x2d,0xce,0x35,0xf0,0xfd,0xe4,0x3c,0xfc,0x22} }, +{ 16,0x0d91,0,{0xeb,0x9f,0xf5,0xf0,0xea,0x9e,0x42,0xf0,0xe9,0x9d,0x42,0xf0,0xe8,0x9c,0x45,0xf0} }, +{ 1,0x0da1,0,{0x22} }, +{ 16,0x0da2,0,{0xbb,0x01,0x0d,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0x02,0x0e,0xa1} }, +{ 16,0x0db2,0,{0x50,0x07,0xe9,0x25,0x82,0xf8,0x02,0x0e,0x95,0xbb,0xfe,0x07,0xe9,0x25,0x82,0xf8} }, +{ 16,0x0dc2,0,{0x02,0x0e,0xad,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0x02,0x0e,0xb9} }, +{ 16,0x0dd2,0,{0xbb,0x01,0x0d,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0x02,0x0e,0xd5} }, +{ 16,0x0de2,0,{0x50,0x07,0xe9,0x25,0x82,0xf8,0x02,0x0e,0xc9,0xbb,0xfe,0x07,0xe9,0x25,0x82,0xf8} }, +{ 4,0x0df2,0,{0x02,0x0e,0xe1,0x22} }, +{ 16,0x0df6,0,{0xbb,0x01,0x0d,0xe5,0x82,0x29,0xf5,0x82,0xe5,0x83,0x3a,0xf5,0x83,0x02,0x0f,0x06} }, +{ 16,0x0e06,0,{0x50,0x07,0xe9,0x25,0x82,0xf8,0x02,0x0e,0xed,0xbb,0xfe,0x07,0xe9,0x25,0x82,0xf8} }, +{ 4,0x0e16,0,{0x02,0x0f,0x37,0x22} }, +{ 16,0x0e1a,0,{0xd0,0x83,0xd0,0x82,0xf8,0xe4,0x93,0x70,0x12,0x74,0x01,0x93,0x70,0x0d,0xa3,0xa3} }, +{ 16,0x0e2a,0,{0x93,0xf8,0x74,0x01,0x93,0xf5,0x82,0x88,0x83,0xe4,0x73,0x74,0x02,0x93,0x68,0x60} }, +{ 6,0x0e3a,0,{0xef,0xa3,0xa3,0xa3,0x80,0xdf} }, +{ 16,0x0e40,0,{0xbc,0x00,0x0b,0xbe,0x00,0x29,0xef,0x8d,0xf0,0x84,0xff,0xad,0xf0,0x22,0xe4,0xcc} }, +{ 16,0x0e50,0,{0xf8,0x75,0xf0,0x08,0xef,0x2f,0xff,0xee,0x33,0xfe,0xec,0x33,0xfc,0xee,0x9d,0xec} }, +{ 16,0x0e60,0,{0x98,0x40,0x05,0xfc,0xee,0x9d,0xfe,0x0f,0xd5,0xf0,0xe9,0xe4,0xce,0xfd,0x22,0xed} }, +{ 16,0x0e70,0,{0xf8,0xf5,0xf0,0xee,0x84,0x20,0xd2,0x1c,0xfe,0xad,0xf0,0x75,0xf0,0x08,0xef,0x2f} }, +{ 16,0x0e80,0,{0xff,0xed,0x33,0xfd,0x40,0x07,0x98,0x50,0x06,0xd5,0xf0,0xf2,0x22,0xc3,0x98,0xfd} }, +{ 5,0x0e90,0,{0x0f,0xd5,0xf0,0xea,0x22} }, +{ 12,0x0e95,0,{0xe6,0xfc,0x08,0xe6,0xfd,0x08,0xe6,0xfe,0x08,0xe6,0xff,0x22} }, +{ 12,0x0ea1,0,{0xe0,0xfc,0xa3,0xe0,0xfd,0xa3,0xe0,0xfe,0xa3,0xe0,0xff,0x22} }, +{ 12,0x0ead,0,{0xe2,0xfc,0x08,0xe2,0xfd,0x08,0xe2,0xfe,0x08,0xe2,0xff,0x22} }, +{ 16,0x0eb9,0,{0xe4,0x93,0xfc,0xa3,0xe4,0x93,0xfd,0xa3,0xe4,0x93,0xfe,0xa3,0xe4,0x93,0xff,0x22} }, +{ 12,0x0ec9,0,{0xec,0xf6,0x08,0xed,0xf6,0x08,0xee,0xf6,0x08,0xef,0xf6,0x22} }, +{ 12,0x0ed5,0,{0xec,0xf0,0xa3,0xed,0xf0,0xa3,0xee,0xf0,0xa3,0xef,0xf0,0x22} }, +{ 12,0x0ee1,0,{0xec,0xf2,0x08,0xed,0xf2,0x08,0xee,0xf2,0x08,0xef,0xf2,0x22} }, +{ 16,0x0eed,0,{0xd0,0x83,0xd0,0x82,0xe4,0x93,0xf6,0x08,0x74,0x01,0x93,0xf6,0x08,0x74,0x02,0x93} }, +{ 9,0x0efd,0,{0xf6,0x08,0x74,0x03,0x93,0xf6,0x74,0x04,0x73} }, +{ 16,0x0f06,0,{0xa8,0x82,0x85,0x83,0xf0,0xd0,0x83,0xd0,0x82,0x12,0x0f,0x1d,0x12,0x0f,0x1d,0x12} }, +{ 16,0x0f16,0,{0x0f,0x1d,0x12,0x0f,0x1d,0xe4,0x73,0xe4,0x93,0xa3,0xc5,0x83,0xc5,0xf0,0xc5,0x83} }, +{ 16,0x0f26,0,{0xc8,0xc5,0x82,0xc8,0xf0,0xa3,0xc5,0x83,0xc5,0xf0,0xc5,0x83,0xc8,0xc5,0x82,0xc8} }, +{ 1,0x0f36,0,{0x22} }, +{ 16,0x0f37,0,{0xd0,0x83,0xd0,0x82,0xe4,0x93,0xf2,0x08,0x74,0x01,0x93,0xf2,0x08,0x74,0x02,0x93} }, +{ 9,0x0f47,0,{0xf2,0x08,0x74,0x03,0x93,0xf2,0x74,0x04,0x73} }, +{ 16,0x0f50,0,{0xc2,0xaf,0xd2,0x2c,0x90,0x7f,0x93,0x74,0x30,0xf0,0x90,0x7f,0x9c,0x74,0xbf,0xf0} }, +{ 16,0x0f60,0,{0x90,0x7f,0x96,0xe0,0x54,0x30,0xf0,0x90,0x7f,0x94,0x74,0x30,0xf0,0x90,0x7f,0x9d} }, +{ 16,0x0f70,0,{0x74,0xcf,0xf0,0x90,0x7f,0x97,0x74,0xa0,0xf0,0x90,0x7f,0x95,0x74,0xcc,0xf0,0xe4} }, +{ 16,0x0f80,0,{0x90,0x7f,0x9e,0xf0,0xc2,0x2d,0xc2,0x2a,0xc2,0x2b,0xc2,0x2e,0x90,0x79,0x74,0x04} }, +{ 16,0x0f90,0,{0xf0,0x12,0x2e,0x94,0x12,0x49,0xe2,0x12,0x4b,0xe6,0x12,0x32,0x0d,0x12,0x3b,0x0d} }, +{ 16,0x0fa0,0,{0x12,0x41,0xfd,0x12,0x3e,0x99,0xe5,0x1f,0x70,0x18,0x75,0x1f,0x01,0x12,0x17,0xff} }, +{ 16,0x0fb0,0,{0x12,0x2f,0xff,0x12,0x49,0xc8,0x12,0x4b,0xd8,0x12,0x4b,0xda,0x12,0x49,0x6f,0x12} }, +{ 16,0x0fc0,0,{0x1b,0x40,0x12,0x39,0x8d,0x90,0x7f,0xaf,0xe0,0x44,0x01,0xf0,0x90,0x7f,0xae,0xe0} }, +{ 16,0x0fd0,0,{0x44,0x1f,0xf0,0x90,0x7f,0xac,0x74,0xff,0xf0,0x90,0x7f,0xad,0xf0,0x90,0x7f,0xde} }, +{ 16,0x0fe0,0,{0xf0,0x90,0x7f,0xdf,0xf0,0x90,0x7f,0xab,0xf0,0x90,0x7f,0xa9,0xf0,0x90,0x7f,0xaa} }, +{ 16,0x0ff0,0,{0xf0,0x53,0x91,0xef,0x43,0xd8,0x20,0xd2,0xe8,0x43,0xd8,0x20,0x43,0xa8,0x80,0x22} }, +{ 16,0x1000,0,{0x90,0x79,0x63,0xe0,0x14,0x60,0x44,0x14,0x70,0x02,0x21,0xd0,0x14,0x70,0x02,0x41} }, +{ 16,0x1010,0,{0xd9,0x14,0x70,0x02,0x61,0xd7,0x24,0x04,0x60,0x02,0x81,0x56,0xe4,0x90,0x79,0x78} }, +{ 16,0x1020,0,{0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x54,0xfd,0xf0,0x90} }, +{ 16,0x1030,0,{0x79,0x7b,0xf0,0xe4,0x90,0x79,0x88,0xf0,0xa2,0xaf,0x33,0xf5,0x12,0xc2,0xaf,0x12} }, +{ 16,0x1040,0,{0x0b,0xa2,0xe5,0x12,0x70,0x02,0x81,0x56,0xd2,0xaf,0x22,0x90,0x79,0x2d,0xe0,0x64} }, +{ 16,0x1050,0,{0x01,0x70,0x79,0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0x30,0xf0,0x90,0x7f,0xff} }, +{ 16,0x1060,0,{0x74,0xfc,0xf0,0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0} }, +{ 16,0x1070,0,{0x44,0x01,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12} }, +{ 16,0x1080,0,{0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90} }, +{ 16,0x1090,0,{0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe} }, +{ 16,0x10a0,0,{0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x54,0xfd} }, +{ 16,0x10b0,0,{0xf0,0x54,0xfb,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74,0x04} }, +{ 16,0x10c0,0,{0xf0,0x90,0x79,0x88,0x14,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x90,0x79,0x2d,0xe0} }, +{ 16,0x10d0,0,{0x64,0x02,0x70,0x79,0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0x34,0xf0,0x90,0x7f} }, +{ 16,0x10e0,0,{0xff,0x74,0xfc,0xf0,0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79} }, +{ 16,0x10f0,0,{0xf0,0x44,0x01,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5} }, +{ 16,0x1100,0,{0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0} }, +{ 16,0x1110,0,{0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54} }, +{ 16,0x1120,0,{0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44} }, +{ 16,0x1130,0,{0x02,0xf0,0x54,0xfb,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74} }, +{ 16,0x1140,0,{0x04,0xf0,0x90,0x79,0x88,0x14,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x90,0x79,0x2d} }, +{ 16,0x1150,0,{0xe0,0x64,0x03,0x60,0x02,0x81,0x56,0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0x64} }, +{ 16,0x1160,0,{0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0} }, +{ 16,0x1170,0,{0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7b,0xf0,0xa2,0xaf} }, +{ 16,0x1180,0,{0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90} }, +{ 16,0x1190,0,{0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79} }, +{ 16,0x11a0,0,{0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79} }, +{ 16,0x11b0,0,{0x79,0xe0,0x44,0x04,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74} }, +{ 16,0x11c0,0,{0x04,0xf0,0x90,0x79,0x88,0x14,0xf0,0xe5,0x12,0x70,0x02,0x81,0x56,0xd2,0xaf,0x22} }, +{ 16,0x11d0,0,{0x90,0x79,0x2d,0xe0,0x64,0x01,0x70,0x7a,0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74} }, +{ 16,0x11e0,0,{0x88,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b} }, +{ 16,0x11f0,0,{0xe0,0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x54,0xfd,0xf0,0x90,0x79,0x7b,0xf0,0xa2} }, +{ 16,0x1200,0,{0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0} }, +{ 16,0x1210,0,{0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90} }, +{ 16,0x1220,0,{0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90} }, +{ 16,0x1230,0,{0x79,0x79,0xe0,0x54,0xfd,0xf0,0x54,0xfb,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2} }, +{ 16,0x1240,0,{0x90,0x79,0x82,0x74,0x0c,0xf0,0x90,0x79,0x88,0x74,0x01,0xf0,0xe5,0x12,0x60,0x02} }, +{ 16,0x1250,0,{0xd2,0xaf,0x90,0x79,0x2d,0xe0,0x64,0x02,0x60,0x02,0x81,0x56,0x90,0x7f,0xf2,0xf0} }, +{ 16,0x1260,0,{0x90,0x7f,0xf3,0x74,0x94,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0xe4,0x90,0x79,0x78} }, +{ 16,0x1270,0,{0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x54,0xfd,0xf0,0x90} }, +{ 16,0x1280,0,{0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79} }, +{ 16,0x1290,0,{0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0} }, +{ 16,0x12a0,0,{0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0} }, +{ 16,0x12b0,0,{0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44,0x02,0xf0,0x54,0xfb,0xf0,0x90,0x79,0x84} }, +{ 16,0x12c0,0,{0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74,0x0c,0xf0,0x90,0x79,0x88,0x74,0x01,0xf0} }, +{ 16,0x12d0,0,{0xe5,0x12,0x70,0x02,0x81,0x56,0xd2,0xaf,0x22,0x90,0x79,0x2d,0xe0,0x64,0x01,0x70} }, +{ 16,0x12e0,0,{0x77,0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0xcc,0xf0,0x90,0x7f,0xff,0x74,0xfc} }, +{ 16,0x12f0,0,{0xf0,0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0,0x54,0xfc} }, +{ 16,0x1300,0,{0xf0,0x90,0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2} }, +{ 16,0x1310,0,{0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79} }, +{ 16,0x1320,0,{0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79} }, +{ 16,0x1330,0,{0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x54,0xfd,0xf0,0x54,0xfb,0xf0,0x90} }, +{ 16,0x1340,0,{0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74,0x12,0xf0,0x90,0x79,0x88,0x74} }, +{ 16,0x1350,0,{0x02,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x90,0x79,0x2d,0xe0,0x64,0x02,0x70,0x77} }, +{ 16,0x1360,0,{0x90,0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0xe0,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0} }, +{ 16,0x1370,0,{0xe4,0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0,0x54,0xfc,0xf0} }, +{ 16,0x1380,0,{0x90,0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90} }, +{ 16,0x1390,0,{0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f} }, +{ 16,0x13a0,0,{0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79} }, +{ 16,0x13b0,0,{0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44,0x02,0xf0,0x54,0xfb,0xf0,0x90,0x79} }, +{ 16,0x13c0,0,{0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74,0x12,0xf0,0x90,0x79,0x88,0x74,0x02} }, +{ 16,0x13d0,0,{0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x90,0x79,0x2d,0xe0,0x64,0x03,0x70,0x77,0x90} }, +{ 16,0x13e0,0,{0x7f,0xf2,0xf0,0x90,0x7f,0xf3,0x74,0x94,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0xe4} }, +{ 16,0x13f0,0,{0x90,0x79,0x78,0xf0,0x90,0x79,0x7b,0xe0,0x90,0x79,0x79,0xf0,0x54,0xfe,0xf0,0x44} }, +{ 16,0x1400,0,{0x02,0xf0,0x90,0x79,0x7b,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b} }, +{ 16,0x1410,0,{0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90} }, +{ 16,0x1420,0,{0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90} }, +{ 16,0x1430,0,{0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x90,0x79,0x84} }, +{ 16,0x1440,0,{0xf0,0x12,0x0b,0xa2,0x90,0x79,0x82,0x74,0x06,0xf0,0x90,0x79,0x88,0x74,0x04,0xf0} }, +{ 7,0x1450,0,{0xe5,0x12,0x60,0x02,0xd2,0xaf,0x22} }, +{ 16,0x1457,0,{0xc2,0x28,0xc2,0x29,0x90,0x7f,0xe8,0xe0,0x12,0x0e,0x1a,0x14,0x84,0x00,0x14,0xe0} }, +{ 16,0x1467,0,{0x01,0x14,0xf6,0x02,0x16,0x7c,0x21,0x16,0xbe,0x22,0x15,0x91,0x80,0x15,0xd1,0x81} }, +{ 16,0x1477,0,{0x16,0x2e,0x82,0x16,0xcf,0xa1,0x17,0x05,0xa2,0x00,0x00,0x17,0x0a,0x90,0x7f,0xe9} }, +{ 16,0x1487,0,{0xe0,0x14,0x60,0x11,0x24,0xfe,0x60,0x28,0x24,0xfe,0x60,0x3b,0x24,0xfc,0x70,0x40} }, +{ 16,0x1497,0,{0x12,0x4a,0x2a,0xe1,0x16,0x12,0x4b,0xe0,0x40,0x02,0xe1,0x16,0x90,0x7f,0xea,0xe0} }, +{ 16,0x14a7,0,{0xb4,0x01,0x04,0xc2,0x2a,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16} }, +{ 16,0x14b7,0,{0x12,0x4b,0xe2,0x90,0x7f,0xea,0xe0,0xb4,0x01,0x04,0xd2,0x2a,0xe1,0x16,0x90,0x7f} }, +{ 16,0x14c7,0,{0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16} }, +{ 16,0x14d7,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xe9,0xe0,0x24,0xf5,0x70} }, +{ 16,0x14e7,0,{0x05,0x12,0x47,0x9c,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90} }, +{ 16,0x14f7,0,{0x7f,0xe9,0xe0,0x24,0xfd,0x60,0x54,0x24,0x02,0x60,0x02,0xa1,0x88,0x12,0x4b,0xe0} }, +{ 16,0x1507,0,{0x40,0x02,0xe1,0x16,0x90,0x7f,0xea,0xe0,0x70,0x38,0x90,0x7f,0xec,0xe0,0xf4,0x54} }, +{ 16,0x1517,0,{0x80,0xff,0xc4,0x54,0x0f,0xff,0xe0,0x54,0x07,0x2f,0x25,0xe0,0x24,0xb4,0xf5,0x82} }, +{ 16,0x1527,0,{0xe4,0x34,0x7f,0xf5,0x83,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0x54,0x80,0xff,0x13,0x13} }, +{ 16,0x1537,0,{0x13,0x54,0x1f,0xff,0xe0,0x54,0x07,0x2f,0x90,0x7f,0xd7,0xf0,0xe0,0x44,0x20,0xf0} }, +{ 16,0x1547,0,{0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x12,0x4b,0xe2,0x40,0x02} }, +{ 16,0x1557,0,{0xe1,0x16,0x90,0x7f,0xea,0xe0,0x70,0x20,0x90,0x7f,0xec,0xe0,0xf4,0x54,0x80,0xff} }, +{ 16,0x1567,0,{0xc4,0x54,0x0f,0xff,0xe0,0x54,0x07,0x2f,0x25,0xe0,0x24,0xb4,0xf5,0x82,0xe4,0x34} }, +{ 16,0x1577,0,{0x7f,0xf5,0x83,0x74,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1} }, +{ 16,0x1587,0,{0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xe9,0xe0,0x60,0x12} }, +{ 16,0x1597,0,{0x24,0xf8,0x60,0x09,0x24,0x02,0x70,0x29,0x12,0x17,0x1e,0xe1,0x16,0x12,0x4b,0xa0} }, +{ 16,0x15a7,0,{0xe1,0x16,0x12,0x4b,0xde,0xa2,0x2a,0xe4,0x33,0xff,0x25,0xe0,0xff,0xa2,0x2b,0xe4} }, +{ 16,0x15b7,0,{0x33,0x4f,0x90,0x7f,0x00,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0xe1} }, +{ 16,0x15c7,0,{0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xe9,0xe0,0x60,0x37} }, +{ 16,0x15d7,0,{0x24,0xf6,0x60,0x2e,0x24,0x04,0x70,0x41,0x90,0x7f,0xeb,0xe0,0x24,0xde,0x60,0x0e} }, +{ 16,0x15e7,0,{0x04,0x70,0x16,0xd2,0x29,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0xd2,0x29} }, +{ 16,0x15f7,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 16,0x1607,0,{0xe1,0x16,0x12,0x44,0x63,0xe1,0x16,0x12,0x4b,0xde,0xe4,0x90,0x7f,0x00,0xf0,0xa3} }, +{ 16,0x1617,0,{0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0xe1,0x16,0x20,0x29,0x07,0x90,0x7f,0xb4,0xe0} }, +{ 16,0x1627,0,{0x44,0x01,0xf0,0xc2,0x29,0xe1,0x16,0x90,0x7f,0xe9,0xe0,0x24,0xf4,0x60,0x34,0x24} }, +{ 16,0x1637,0,{0x0c,0x70,0x39,0x12,0x4b,0xde,0x90,0x7f,0xec,0xe0,0xf4,0x54,0x80,0xff,0xc4,0x54} }, +{ 16,0x1647,0,{0x0f,0xff,0xe0,0x54,0x07,0x2f,0x25,0xe0,0x24,0xb4,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, +{ 16,0x1657,0,{0x83,0xe0,0x54,0xfd,0x90,0x7f,0x00,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x02} }, +{ 16,0x1667,0,{0xf0,0xe1,0x16,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xb4,0xe0} }, +{ 16,0x1677,0,{0x44,0x01,0xf0,0xe1,0x16,0x90,0x7f,0xe9,0xe0,0x24,0xf6,0x60,0x12,0x14,0x60,0x1a} }, +{ 16,0x1687,0,{0x24,0x02,0x70,0x1d,0xd2,0x28,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x80,0x12,0xd2} }, +{ 16,0x1697,0,{0x28,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x80,0x07,0x90,0x7f,0xb4,0xe0,0x44,0x01} }, +{ 16,0x16a7,0,{0xf0,0x20,0x28,0x0f,0x90,0x79,0x85,0x74,0x01,0xf0,0x12,0x49,0x6f,0x90,0x7f,0xc5} }, +{ 16,0x16b7,0,{0x74,0x02,0xf0,0xc2,0x28,0x80,0x58,0x90,0x79,0x86,0x74,0x01,0xf0,0x12,0x49,0x6f} }, +{ 16,0x16c7,0,{0x90,0x7f,0xc5,0x74,0x02,0xf0,0x80,0x47,0x90,0x7f,0xe9,0xe0,0x24,0xfe,0x60,0x12} }, +{ 16,0x16d7,0,{0x14,0x60,0x1a,0x24,0x02,0x70,0x1d,0xd2,0x28,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 16,0x16e7,0,{0x80,0x12,0xd2,0x28,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x80,0x07,0x90,0x7f,0xb4} }, +{ 16,0x16f7,0,{0xe0,0x44,0x01,0xf0,0x20,0x28,0x03,0x12,0x1a,0x7b,0xc2,0x28,0x80,0x11,0x12,0x2c} }, +{ 16,0x1707,0,{0x2b,0x80,0x0c,0x12,0x4b,0xe4,0x50,0x07,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x90} }, +{ 7,0x1717,0,{0x7f,0xb4,0xe0,0x44,0x02,0xf0,0x22} }, +{ 16,0x171e,0,{0x12,0x4b,0xdc,0x40,0x02,0xe1,0xe3,0x90,0x7f,0xeb,0xe0,0x24,0xfe,0x60,0x1e,0x14} }, +{ 16,0x172e,0,{0x60,0x46,0x14,0x60,0x6e,0x14,0x70,0x02,0xe1,0xd4,0x24,0x04,0x60,0x02,0xe1,0xdc} }, +{ 16,0x173e,0,{0x74,0x05,0x90,0x7f,0xd4,0xf0,0x74,0x00,0x90,0x7f,0xd5,0xf0,0x22,0x90,0x7f,0xea} }, +{ 16,0x174e,0,{0xe0,0xff,0x12,0x3f,0xa2,0x8b,0x33,0x8a,0x34,0x89,0x35,0xea,0x49,0x60,0x11,0xce} }, +{ 16,0x175e,0,{0xea,0xce,0xee,0x90,0x7f,0xd4,0xf0,0xcf,0xe9,0xcf,0xef,0x90,0x7f,0xd5,0xf0,0x22} }, +{ 16,0x176e,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xea,0xe0,0xff,0x12,0x48,0x00} }, +{ 16,0x177e,0,{0x8b,0x33,0x8a,0x34,0x89,0x35,0xea,0x49,0x60,0x11,0xce,0xea,0xce,0xee,0x90,0x7f} }, +{ 16,0x178e,0,{0xd4,0xf0,0xcf,0xe9,0xcf,0xef,0x90,0x7f,0xd5,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44} }, +{ 16,0x179e,0,{0x01,0xf0,0x22,0x90,0x7f,0xea,0xe0,0xff,0x90,0x7e,0xc0,0xe0,0xfd,0xa3,0xe0,0xfb} }, +{ 16,0x17ae,0,{0x12,0x44,0xd2,0x8b,0x33,0x8a,0x34,0x89,0x35,0xea,0x49,0x60,0x11,0xce,0xea,0xce} }, +{ 16,0x17be,0,{0xee,0x90,0x7f,0xd4,0xf0,0xcf,0xe9,0xcf,0xef,0x90,0x7f,0xd5,0xf0,0x22,0x90,0x7f} }, +{ 16,0x17ce,0,{0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f} }, +{ 5,0x17de,0,{0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x17e3,0,{0x22} }, +{ 16,0x17e4,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x90,0x7f,0xc4,0xe4,0xf0,0x53,0x91,0xef,0x90,0x7f} }, +{ 11,0x17f4,0,{0xab,0x74,0x04,0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 1,0x17ff,0,{0x22} }, +{ 16,0x1800,0,{0xe4,0x90,0x78,0x15,0xf0,0x7b,0x01,0x90,0x78,0x12,0x04,0xf0,0xa3,0x74,0x78,0xf0} }, +{ 16,0x1810,0,{0xa3,0x74,0x58,0xf0,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90} }, +{ 16,0x1820,0,{0x00,0x01,0x12,0x0c,0x5d,0xff,0x90,0x79,0x9a,0xe0,0x6f,0x60,0x18,0x90,0x78,0x15} }, +{ 16,0x1830,0,{0xe0,0xc3,0x94,0x06,0x50,0x0f,0xe0,0x04,0xf0,0x90,0x78,0x13,0xe4,0x75,0xf0,0x0f} }, +{ 16,0x1840,0,{0x12,0x0c,0xf4,0x80,0xcf,0x90,0x78,0x15,0xe0,0xb4,0x06,0x08,0x90,0x7f,0xb4,0xe0} }, +{ 16,0x1850,0,{0x44,0x01,0xf0,0x22,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x12} }, +{ 16,0x1860,0,{0x0c,0x44,0xff,0x24,0xbf,0x70,0x02,0x41,0x7a,0x24,0xe0,0x70,0x02,0x41,0x4c,0x24} }, +{ 16,0x1870,0,{0x21,0x60,0x02,0x41,0x73,0x90,0x79,0x97,0xe0,0x24,0xfe,0x70,0x02,0x21,0x9a,0x14} }, +{ 16,0x1880,0,{0x70,0x02,0x21,0xef,0x24,0x02,0x60,0x02,0x41,0x44,0x90,0x79,0x2d,0xe0,0xa3,0xf0} }, +{ 16,0x1890,0,{0x90,0x79,0x23,0xe0,0xff,0xe4,0xfc,0xfd,0xfe,0xfb,0xfa,0x79,0x01,0xf8,0x12,0x0d} }, +{ 16,0x18a0,0,{0x42,0xc8,0xec,0xc8,0xc9,0xed,0xc9,0xca,0xee,0xca,0xcb,0xef,0xcb,0x90,0x79,0x22} }, +{ 16,0x18b0,0,{0xe0,0xfe,0xe4,0xfc,0xfd,0x2b,0xfb,0xea,0x3e,0xfa,0xed,0x39,0xf9,0xec,0x38,0xf8} }, +{ 16,0x18c0,0,{0x90,0x79,0x21,0xe0,0xff,0xe4,0xfe,0xeb,0x2f,0xff,0xee,0x3a,0xfe,0xed,0x39,0xfd} }, +{ 16,0x18d0,0,{0xec,0x38,0xfc,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00} }, +{ 16,0x18e0,0,{0x02,0x12,0x0d,0xd2,0x90,0x00,0x02,0x12,0x0d,0xa2,0x7b,0x44,0x7a,0xac,0x79,0x00} }, +{ 16,0x18f0,0,{0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x05,0x90,0x79,0x2d,0x04,0xf0,0x90,0x78,0x12} }, +{ 16,0x1900,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02,0x12,0x0d,0xa2,0x7b,0x80} }, +{ 16,0x1910,0,{0x7a,0xbb,0x79,0x00,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x06,0x90,0x79,0x2d,0x74} }, +{ 16,0x1920,0,{0x02,0xf0,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02} }, +{ 16,0x1930,0,{0x12,0x0d,0xa2,0x7b,0x00,0x7a,0x77,0x79,0x01,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70} }, +{ 16,0x1940,0,{0x06,0x90,0x79,0x2d,0x74,0x03,0xf0,0x90,0x79,0x2d,0xe0,0xff,0xb4,0x01,0x09,0x75} }, +{ 16,0x1950,0,{0x0c,0x67,0x75,0x0d,0x06,0x75,0x0e,0x0b,0xef,0xb4,0x02,0x08,0xe4,0xf5,0x0c,0xf5} }, +{ 16,0x1960,0,{0x0d,0x75,0x0e,0x0c,0xef,0xb4,0x03,0x08,0xe4,0xf5,0x0c,0xf5,0x0d,0x75,0x0e,0x18} }, +{ 16,0x1970,0,{0xef,0xb4,0x03,0x0d,0x90,0x79,0x2e,0xe0,0x64,0x03,0x60,0x05,0xd2,0x2f,0x12,0x3d} }, +{ 16,0x1980,0,{0x79,0x90,0x79,0x2d,0xe0,0x64,0x03,0x60,0x0a,0xa3,0xe0,0xb4,0x03,0x05,0xc2,0x2f} }, +{ 16,0x1990,0,{0x12,0x3d,0x79,0x12,0x10,0x00,0x12,0x28,0x01,0x22,0x90,0x79,0x23,0xe0,0xff,0xe4} }, +{ 16,0x19a0,0,{0xfc,0xfd,0xfe,0xfb,0xfa,0x79,0x01,0xf8,0x12,0x0d,0x42,0xc8,0xec,0xc8,0xc9,0xed} }, +{ 16,0x19b0,0,{0xc9,0xca,0xee,0xca,0xcb,0xef,0xcb,0x90,0x79,0x22,0xe0,0xfe,0xe4,0xfc,0xfd,0x2b} }, +{ 16,0x19c0,0,{0xfb,0xea,0x3e,0xfa,0xed,0x39,0xf9,0xec,0x38,0xf8,0x90,0x79,0x21,0xe0,0xff,0xe4} }, +{ 16,0x19d0,0,{0xfe,0xeb,0x2f,0xff,0xee,0x3a,0xfe,0xed,0x39,0xfd,0xec,0x38,0xfc,0x90,0x78,0x12} }, +{ 16,0x19e0,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x06,0x12,0x0d,0xd2,0x22,0x90} }, +{ 16,0x19f0,0,{0x79,0x23,0xe0,0xff,0xe4,0xfc,0xfd,0xfe,0xfb,0xfa,0x79,0x01,0xf8,0x12,0x0d,0x42} }, +{ 16,0x1a00,0,{0xc8,0xec,0xc8,0xc9,0xed,0xc9,0xca,0xee,0xca,0xcb,0xef,0xcb,0x90,0x79,0x22,0xe0} }, +{ 16,0x1a10,0,{0xfe,0xe4,0xfc,0xfd,0x2b,0xfb,0xea,0x3e,0xfa,0xed,0x39,0xf9,0xec,0x38,0xf8,0x90} }, +{ 16,0x1a20,0,{0x79,0x21,0xe0,0xff,0xe4,0xfe,0xeb,0x2f,0xff,0xee,0x3a,0xfe,0xed,0x39,0xfd,0xec} }, +{ 16,0x1a30,0,{0x38,0xfc,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x0a} }, +{ 16,0x1a40,0,{0x12,0x0d,0xd2,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x97,0xe0} }, +{ 16,0x1a50,0,{0x14,0x70,0x18,0x90,0x79,0x21,0xe0,0xff,0x90,0x78,0x12,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x1a60,0,{0xa3,0xe0,0xf9,0x90,0x00,0x0e,0xef,0x12,0x0c,0x9c,0x22,0x90,0x7f,0xb4,0xe0,0x44} }, +{ 10,0x1a70,0,{0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x1a7a,0,{0x22} }, +{ 16,0x1a7b,0,{0xe4,0xff,0xfe,0x7b,0x01,0x90,0x78,0x0f,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74} }, +{ 16,0x1a8b,0,{0x2b,0xf0,0x90,0x78,0x0f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02} }, +{ 16,0x1a9b,0,{0x12,0x0c,0x5d,0xfd,0x90,0x7f,0xec,0xe0,0x6d,0x60,0x13,0xef,0xc3,0x94,0x05,0x50} }, +{ 16,0x1aab,0,{0x0d,0x0f,0x90,0x78,0x10,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x80,0xd4,0x8d,0x33} }, +{ 16,0x1abb,0,{0x90,0x78,0x0f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x12,0x0c} }, +{ 16,0x1acb,0,{0x5d,0xfd,0x90,0x7f,0xed,0xe0,0x6d,0x60,0x13,0xee,0xc3,0x94,0x0b,0x50,0x0d,0x0e} }, +{ 16,0x1adb,0,{0x90,0x78,0x10,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x80,0xd4,0x90,0x7f,0xed,0xe0} }, +{ 16,0x1aeb,0,{0xf5,0x34,0xef,0x64,0x05,0x60,0x03,0xbe,0x0b,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01} }, +{ 16,0x1afb,0,{0xf0,0x22,0x90,0x78,0x0f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x12,0x0c,0x44} }, +{ 16,0x1b0b,0,{0xff,0x24,0xf0,0x60,0x08,0x24,0x0f,0x70,0x0e,0x12,0x49,0x2a,0x22,0x12,0x4b,0x83} }, +{ 14,0x1b1b,0,{0x90,0x79,0x20,0xe5,0x34,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x1b29,0,{0x22} }, +{ 15,0x1b2a,0,{0x90,0x7f,0xea,0xe0,0xb4,0xff,0x04,0x12,0x34,0x16,0x22,0x12,0x38,0x00,0x22} }, +{ 7,0x1b39,0,{0x53,0x98,0xfe,0x53,0x98,0xfd,0x32} }, +{ 16,0x1b40,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1b50,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1b60,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1b70,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1b80,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1b90,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ba0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1bb0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1bc0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1bd0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1be0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1bf0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c00,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c10,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c20,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c30,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c40,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c50,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c60,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c70,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c80,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1c90,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ca0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1cb0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1cc0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1cd0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ce0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1cf0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d00,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d10,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d20,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d30,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d40,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d50,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d60,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d70,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d80,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1d90,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1da0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1db0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1dc0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1dd0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1de0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1df0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e00,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e10,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e20,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e30,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e40,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e50,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e60,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e70,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e80,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1e90,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ea0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 14,0x1eb0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ebe,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ece,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ede,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1eee,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1efe,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f0e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f1e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f2e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 2,0x1f3e,0,{0x00,0x00} }, +{ 16,0x1f40,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f50,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f60,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f70,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f80,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1f90,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1fa0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1fb0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1fc0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1fd0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1fe0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x1ff0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2000,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2010,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2020,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2030,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2040,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2050,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2060,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2070,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2080,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2090,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20a0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20b0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20c0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20d0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20e0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x20f0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2100,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2110,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2120,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2130,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2140,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2150,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2160,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2170,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2180,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2190,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21a0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21b0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21c0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21d0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21e0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x21f0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2200,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2210,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2220,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2230,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2240,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2250,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2260,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2270,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2280,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2290,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22a0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22b0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22c0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22d0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22e0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x22f0,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2300,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2310,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2320,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2330,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2340,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2350,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x2360,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 14,0x2370,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x237e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x238e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x239e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23ae,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23be,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23ce,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23de,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23ee,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x23fe,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x240e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x241e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x242e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x243e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x244e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x245e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x246e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x247e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x248e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x249e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24ae,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24be,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24ce,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24de,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24ee,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x24fe,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x250e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x251e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x252e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x253e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x254e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x255e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x256e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x257e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x258e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x259e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25ae,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25be,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25ce,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25de,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25ee,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x25fe,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x260e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x261e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x262e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x263e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x264e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x265e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x266e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x267e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x268e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x269e,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x26ae,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x26be,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x26ce,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x26de,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 14,0x26ee,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x26fc,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x270c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x271c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x272c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x273c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x274c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x275c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x276c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x277c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x278c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x279c,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x27ac,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x27bc,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x27cc,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x27dc,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 16,0x27ec,0,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, +{ 5,0x27fc,0,{0x00,0x00,0x00,0x00,0x22} }, +{ 16,0x2801,0,{0x90,0x79,0x64,0xe0,0x14,0x60,0x46,0x14,0x70,0x02,0x41,0x3c,0x24,0x02,0x60,0x02} }, +{ 16,0x2811,0,{0x81,0x2a,0x90,0x7f,0xfc,0x74,0xcc,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0x90,0x79} }, +{ 16,0x2821,0,{0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0x54,0xfd,0xf0,0x44} }, +{ 16,0x2831,0,{0x01,0xf0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b} }, +{ 16,0x2841,0,{0xa2,0xe5,0x12,0x60,0x02,0xd2,0xaf,0xe4,0x90,0x79,0x7a,0xf0,0x22,0x90,0x79,0x2d} }, +{ 16,0x2851,0,{0xe0,0x64,0x01,0x60,0x02,0x01,0xf1,0x90,0x7f,0xfc,0x74,0xcc,0xf0,0x90,0x7f,0xff} }, +{ 16,0x2861,0,{0x74,0xfc,0xf0,0x90,0x79,0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79} }, +{ 16,0x2871,0,{0xf0,0x44,0x01,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7e,0xe0,0xb4,0x01,0x09,0x90,0x79} }, +{ 16,0x2881,0,{0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb,0xf0,0x90,0x79} }, +{ 16,0x2891,0,{0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b} }, +{ 16,0x28a1,0,{0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90} }, +{ 16,0x28b1,0,{0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90} }, +{ 16,0x28c1,0,{0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x54,0xfd,0xf0,0x54,0xfb,0xf0} }, +{ 16,0x28d1,0,{0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x7a,0x74,0x01,0xf0,0x90,0x79,0x65} }, +{ 16,0x28e1,0,{0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0xe4,0x90,0x79,0x8c,0xf0,0x90,0x79,0x8b,0xf0} }, +{ 16,0x28f1,0,{0x90,0x79,0x2d,0xe0,0x64,0x02,0x60,0x02,0x21,0x96,0x90,0x7f,0xfc,0x74,0xc8,0xf0} }, +{ 16,0x2901,0,{0x90,0x7f,0xff,0x74,0xfc,0xf0,0x90,0x79,0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0} }, +{ 16,0x2911,0,{0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7e,0xe0,0xb4,0x01} }, +{ 16,0x2921,0,{0x09,0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb} }, +{ 16,0x2931,0,{0xf0,0x90,0x79,0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2} }, +{ 16,0x2941,0,{0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79} }, +{ 16,0x2951,0,{0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0} }, +{ 16,0x2961,0,{0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44,0x02,0xf0} }, +{ 16,0x2971,0,{0x54,0xfb,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x7a,0x74,0x01,0xf0} }, +{ 16,0x2981,0,{0x90,0x79,0x65,0x74,0x03,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0xe4,0x90,0x79,0x8c} }, +{ 16,0x2991,0,{0xf0,0x90,0x79,0x8b,0xf0,0x90,0x79,0x2d,0xe0,0x64,0x03,0x60,0x02,0x81,0x2a,0x90} }, +{ 16,0x29a1,0,{0x7f,0xfc,0x74,0x98,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0x90,0x79,0x78,0x74,0x01} }, +{ 16,0x29b1,0,{0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0x44,0x01,0xf0,0x44,0x02,0xf0,0x90} }, +{ 16,0x29c1,0,{0x79,0x7e,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90} }, +{ 16,0x29d1,0,{0x79,0x79,0xe0,0x54,0xfb,0xf0,0x90,0x79,0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf} }, +{ 16,0x29e1,0,{0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90} }, +{ 16,0x29f1,0,{0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79} }, +{ 16,0x2a01,0,{0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79} }, +{ 16,0x2a11,0,{0x79,0xe0,0x54,0xfd,0xf0,0x44,0x04,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90} }, +{ 16,0x2a21,0,{0x79,0x7a,0x74,0x01,0xf0,0x90,0x79,0x65,0x74,0x05,0xf0,0xe5,0x12,0x60,0x02,0xd2} }, +{ 16,0x2a31,0,{0xaf,0xe4,0x90,0x79,0x8c,0xf0,0x90,0x79,0x8b,0xf0,0x22,0x90,0x79,0x2d,0xe0,0x64} }, +{ 16,0x2a41,0,{0x01,0x60,0x02,0x41,0xe0,0x90,0x7f,0xfc,0x74,0xb4,0xf0,0x90,0x7f,0xff,0x74,0xfc} }, +{ 16,0x2a51,0,{0xf0,0x90,0x79,0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0x54} }, +{ 16,0x2a61,0,{0xfe,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7e,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0} }, +{ 16,0x2a71,0,{0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb,0xf0,0x90,0x79,0x79,0xe0} }, +{ 16,0x2a81,0,{0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90} }, +{ 16,0x2a91,0,{0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f} }, +{ 16,0x2aa1,0,{0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79} }, +{ 16,0x2ab1,0,{0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x54,0xfd,0xf0,0x54,0xfb,0xf0,0x90,0x79} }, +{ 16,0x2ac1,0,{0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x7a,0x74,0x01,0xf0,0x90,0x79,0x65,0x04,0xf0} }, +{ 16,0x2ad1,0,{0xe5,0x12,0x60,0x02,0xd2,0xaf,0xe4,0x90,0x79,0x8c,0xf0,0x90,0x79,0x8b,0xf0,0x90} }, +{ 16,0x2ae1,0,{0x79,0x2d,0xe0,0x64,0x02,0x60,0x02,0x61,0x85,0x90,0x7f,0xfc,0x74,0xb0,0xf0,0x90} }, +{ 16,0x2af1,0,{0x7f,0xff,0x74,0xfc,0xf0,0x90,0x79,0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0,0x90} }, +{ 16,0x2b01,0,{0x79,0x79,0xf0,0x54,0xfe,0xf0,0x44,0x02,0xf0,0x90,0x79,0x7e,0xe0,0xb4,0x01,0x09} }, +{ 16,0x2b11,0,{0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb,0xf0} }, +{ 16,0x2b21,0,{0x90,0x79,0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf} }, +{ 16,0x2b31,0,{0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79} }, +{ 16,0x2b41,0,{0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80} }, +{ 16,0x2b51,0,{0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x44,0x02,0xf0,0x54} }, +{ 16,0x2b61,0,{0xfb,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x7a,0x74,0x01,0xf0,0x90} }, +{ 16,0x2b71,0,{0x79,0x65,0x74,0x04,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf,0xe4,0x90,0x79,0x8c,0xf0} }, +{ 16,0x2b81,0,{0x90,0x79,0x8b,0xf0,0x90,0x79,0x2d,0xe0,0x64,0x03,0x60,0x02,0x81,0x2a,0x90,0x7f} }, +{ 16,0x2b91,0,{0xfc,0x74,0x68,0xf0,0x90,0x7f,0xff,0x74,0xfc,0xf0,0x90,0x79,0x78,0x74,0x01,0xf0} }, +{ 16,0x2ba1,0,{0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0x54,0xfe,0xf0,0x44,0x02,0xf0,0x90,0x79} }, +{ 16,0x2bb1,0,{0x7e,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79} }, +{ 16,0x2bc1,0,{0x79,0xe0,0x54,0xfb,0xf0,0x90,0x79,0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4} }, +{ 16,0x2bd1,0,{0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x02,0xf0,0x90,0x79} }, +{ 16,0x2be1,0,{0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09,0x90,0x79,0x79} }, +{ 16,0x2bf1,0,{0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79} }, +{ 16,0x2c01,0,{0xe0,0x54,0xfd,0xf0,0x44,0x04,0xf0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79} }, +{ 16,0x2c11,0,{0x7a,0x74,0x01,0xf0,0x90,0x79,0x65,0x74,0x06,0xf0,0xe5,0x12,0x60,0x02,0xd2,0xaf} }, +{ 10,0x2c21,0,{0xe4,0x90,0x79,0x8c,0xf0,0x90,0x79,0x8b,0xf0,0x22} }, +{ 16,0x2c2b,0,{0xe4,0xff,0x7b,0x01,0x90,0x78,0x16,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0x58} }, +{ 16,0x2c3b,0,{0xf0,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x12} }, +{ 16,0x2c4b,0,{0x0c,0x5d,0xfe,0x90,0x7f,0xec,0xe0,0x6e,0x60,0x13,0xef,0xc3,0x94,0x06,0x50,0x0d} }, +{ 16,0x2c5b,0,{0x0f,0x90,0x78,0x17,0xe4,0x75,0xf0,0x0f,0x12,0x0c,0xf4,0x80,0xd4,0xbf,0x06,0x08} }, +{ 16,0x2c6b,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x2c7b,0,{0xa3,0xe0,0xf9,0x12,0x0c,0x44,0xff,0x24,0x9f,0x70,0x02,0xc1,0x66,0x24,0x21,0x60} }, +{ 16,0x2c8b,0,{0x02,0xc1,0x8c,0x90,0x7f,0xe9,0xe0,0x24,0x7e,0x70,0x02,0xa1,0x30,0x14,0x70,0x02} }, +{ 16,0x2c9b,0,{0xa1,0xc8,0x24,0x02,0x60,0x02,0xc1,0x5e,0x90,0x00,0x02,0x12,0x0d,0xa2,0x7b,0x44} }, +{ 16,0x2cab,0,{0x7a,0xac,0x79,0x00,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x13,0x90,0x7f,0x00,0x74} }, +{ 16,0x2cbb,0,{0x44,0xf0,0xa3,0x74,0xac,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x03,0xf0,0x90} }, +{ 16,0x2ccb,0,{0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02,0x12,0x0d,0xa2} }, +{ 16,0x2cdb,0,{0x7b,0x80,0x7a,0xbb,0x79,0x00,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x13,0x90,0x7f} }, +{ 16,0x2ceb,0,{0x00,0x74,0x80,0xf0,0xa3,0x74,0xbb,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x03} }, +{ 16,0x2cfb,0,{0xf0,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02,0x12} }, +{ 16,0x2d0b,0,{0x0d,0xa2,0x7b,0x00,0x7a,0x77,0x79,0x01,0x78,0x00,0xc3,0x12,0x0d,0x91,0x60,0x02} }, +{ 16,0x2d1b,0,{0xc1,0x93,0x90,0x7f,0x00,0xf0,0xa3,0x74,0x77,0xf0,0xa3,0x74,0x01,0xf0,0x90,0x7f} }, +{ 16,0x2d2b,0,{0xb5,0x74,0x03,0xf0,0x22,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9} }, +{ 16,0x2d3b,0,{0x90,0x00,0x06,0x12,0x0d,0xa2,0x7b,0x44,0x7a,0xac,0x79,0x00,0x78,0x00,0xc3,0x12} }, +{ 16,0x2d4b,0,{0x0d,0x91,0x70,0x13,0x90,0x7f,0x00,0x74,0x44,0xf0,0xa3,0x74,0xac,0xf0,0xe4,0xa3} }, +{ 16,0x2d5b,0,{0xf0,0x90,0x7f,0xb5,0x74,0x03,0xf0,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3} }, +{ 16,0x2d6b,0,{0xe0,0xf9,0x90,0x00,0x06,0x12,0x0d,0xa2,0x7b,0x80,0x7a,0xbb,0x79,0x00,0x78,0x00} }, +{ 16,0x2d7b,0,{0xc3,0x12,0x0d,0x91,0x70,0x13,0x90,0x7f,0x00,0x74,0x80,0xf0,0xa3,0x74,0xbb,0xf0} }, +{ 16,0x2d8b,0,{0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x03,0xf0,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0} }, +{ 16,0x2d9b,0,{0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x06,0x12,0x0d,0xa2,0x7b,0x00,0x7a,0x77,0x79,0x01} }, +{ 16,0x2dab,0,{0x78,0x00,0xc3,0x12,0x0d,0x91,0x60,0x02,0xc1,0x93,0x90,0x7f,0x00,0xf0,0xa3,0x74} }, +{ 16,0x2dbb,0,{0x77,0xf0,0xa3,0x74,0x01,0xf0,0x90,0x7f,0xb5,0x74,0x03,0xf0,0x22,0x90,0x78,0x16} }, +{ 16,0x2dcb,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x0a,0x12,0x0d,0xa2,0x7b,0x44} }, +{ 16,0x2ddb,0,{0x7a,0xac,0x79,0x00,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x13,0x90,0x7f,0x00,0x74} }, +{ 16,0x2deb,0,{0x44,0xf0,0xa3,0x74,0xac,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x03,0xf0,0x90} }, +{ 16,0x2dfb,0,{0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x0a,0x12,0x0d,0xa2} }, +{ 16,0x2e0b,0,{0x7b,0x80,0x7a,0xbb,0x79,0x00,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x13,0x90,0x7f} }, +{ 16,0x2e1b,0,{0x00,0x74,0x80,0xf0,0xa3,0x74,0xbb,0xf0,0xe4,0xa3,0xf0,0x90,0x7f,0xb5,0x74,0x03} }, +{ 16,0x2e2b,0,{0xf0,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x0a,0x12} }, +{ 16,0x2e3b,0,{0x0d,0xa2,0x7b,0x00,0x7a,0x77,0x79,0x01,0x78,0x00,0xc3,0x12,0x0d,0x91,0x70,0x48} }, +{ 16,0x2e4b,0,{0x90,0x7f,0x00,0xf0,0xa3,0x74,0x77,0xf0,0xa3,0x74,0x01,0xf0,0x90,0x7f,0xb5,0x74} }, +{ 16,0x2e5b,0,{0x03,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xe9,0xe0,0x24} }, +{ 16,0x2e6b,0,{0x7f,0x70,0x16,0x90,0x78,0x16,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00} }, +{ 16,0x2e7b,0,{0x0e,0x12,0x0c,0x5d,0x90,0x7f,0x00,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 8,0x2e8b,0,{0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x2e93,0,{0x22} }, +{ 16,0x2e94,0,{0x75,0x36,0x25,0x75,0x37,0x24,0x90,0x79,0x74,0xe0,0x64,0x01,0x70,0x54,0xf0,0xf5} }, +{ 16,0x2ea4,0,{0x35,0x75,0x22,0x01,0xe5,0x22,0x64,0x01,0x70,0x48,0x90,0x7f,0xa5,0xe0,0x44,0x80} }, +{ 16,0x2eb4,0,{0xf0,0x90,0x7f,0xa6,0xe5,0x36,0xf0,0x12,0x46,0xc0,0x74,0x4f,0x25,0x35,0xf5,0x82} }, +{ 16,0x2ec4,0,{0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12,0x46,0xc0,0x74,0x35,0x25} }, +{ 16,0x2ed4,0,{0x35,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12,0x46,0xc0} }, +{ 16,0x2ee4,0,{0x90,0x7f,0xa5,0x74,0x40,0xf0,0x12,0x0a,0xcd,0x05,0x35,0xe5,0x35,0xc3,0x94,0x0d} }, +{ 16,0x2ef4,0,{0x40,0xb2,0x90,0x79,0x75,0xe0,0x64,0x01,0x60,0x02,0xe1,0xde,0xf0,0x90,0x79,0x20} }, +{ 16,0x2f04,0,{0xe0,0x64,0x05,0x60,0x02,0xe1,0x8d,0x7b,0x01,0x90,0x79,0x5c,0x04,0xf0,0xa3,0x74} }, +{ 16,0x2f14,0,{0x78,0xf0,0xa3,0x74,0xb2,0xf0,0x75,0x33,0x07,0x90,0x79,0x5c,0xe0,0xfb,0xa3,0xe0} }, +{ 16,0x2f24,0,{0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x12,0x0c,0x5d,0x70,0x0f,0x90,0x00,0x04,0x12} }, +{ 16,0x2f34,0,{0x0c,0x5d,0x90,0x79,0x2f,0xf0,0x12,0x0c,0x29,0x80,0x06,0x90,0x79,0x2f,0x74,0xff} }, +{ 16,0x2f44,0,{0xf0,0xe4,0xf5,0x35,0x75,0x22,0x01,0x75,0x34,0x02,0xe5,0x22,0x64,0x01,0x70,0x39} }, +{ 16,0x2f54,0,{0x90,0x7f,0xa5,0xe0,0x44,0x80,0xf0,0x90,0x7f,0xa6,0xe5,0x36,0xf0,0x12,0x46,0xc0} }, +{ 16,0x2f64,0,{0xaf,0x34,0x05,0x34,0x90,0x7f,0xa6,0xef,0xf0,0x12,0x46,0xc0,0x90,0x79,0x2f,0xe0} }, +{ 16,0x2f74,0,{0x90,0x7f,0xa6,0xf0,0x12,0x46,0xc0,0x90,0x7f,0xa5,0x74,0x40,0xf0,0x12,0x0a,0xcd} }, +{ 16,0x2f84,0,{0x05,0x35,0xe5,0x35,0xc3,0x94,0x06,0x40,0xc1,0x90,0x79,0x20,0xe0,0x64,0x06,0x70} }, +{ 16,0x2f94,0,{0x49,0x7b,0x01,0x90,0x79,0x5f,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xff,0xf0} }, +{ 16,0x2fa4,0,{0x75,0x33,0x03,0x90,0x79,0x5f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00} }, +{ 16,0x2fb4,0,{0x01,0x12,0x0c,0x5d,0x70,0x1c,0x90,0x00,0x04,0x12,0x0c,0x5d,0x90,0x79,0x33,0xf0} }, +{ 16,0x2fc4,0,{0x70,0x03,0x74,0xff,0xf0,0x90,0x79,0x33,0xe0,0x54,0x7f,0xff,0xf0,0x25,0xe0,0xf0} }, +{ 10,0x2fd4,0,{0x80,0x05,0xe4,0x90,0x79,0x33,0xf0,0x12,0x47,0xdf} }, +{ 1,0x2fde,0,{0x22} }, +{ 16,0x2fdf,0,{0x90,0x79,0x78,0x74,0x03,0xf0,0x90,0x79,0x83,0xe0,0x90,0x79,0x79,0xf0,0xa2,0xaf} }, +{ 16,0x2fef,0,{0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x22} }, +{ 1,0x2fff,0,{0x22} }, +{ 16,0x3000,0,{0xe4,0xfe,0x90,0x79,0x20,0xe0,0xfd,0xb4,0x05,0x11,0x90,0x78,0x25,0x74,0x01,0xf0} }, +{ 16,0x3010,0,{0xa3,0x74,0x78,0xf0,0xa3,0x74,0xb2,0xf0,0x75,0x35,0x07,0xed,0xb4,0x06,0x11,0x90} }, +{ 16,0x3020,0,{0x78,0x25,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xff,0xf0,0x75,0x35,0x03} }, +{ 16,0x3030,0,{0x90,0x7f,0xeb,0xe0,0x14,0x60,0x11,0x14,0x60,0x5b,0x24,0x02,0x60,0x02,0x41,0x05} }, +{ 16,0x3040,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xe9,0xe0,0x24,0x7f,0x70,0x3d} }, +{ 16,0x3050,0,{0xe4,0xff,0xef,0xc3,0x95,0x35,0x50,0x2f,0x90,0x78,0x25,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x3060,0,{0xa3,0xe0,0xf9,0x90,0x00,0x01,0x12,0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00} }, +{ 16,0x3070,0,{0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x78,0x26,0xe4,0x75,0xf0} }, +{ 16,0x3080,0,{0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xcb,0x90,0x7f,0xb5,0xee,0xf0,0x22,0x90,0x7f,0xb4} }, +{ 16,0x3090,0,{0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xe9,0xe0,0x24,0x7e,0x60,0x64,0x14,0x70,0x02} }, +{ 16,0x30a0,0,{0x21,0x55,0x14,0x70,0x02,0x21,0xa9,0x24,0x03,0x60,0x02,0x21,0xfd,0xe4,0xff,0xef} }, +{ 16,0x30b0,0,{0xc3,0x95,0x35,0x50,0x46,0x90,0x78,0x25,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9} }, +{ 16,0x30c0,0,{0x90,0x00,0x03,0x12,0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82} }, +{ 16,0x30d0,0,{0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x00,0x04,0x12,0x0c,0x5d,0xfd,0xcc,0xee} }, +{ 16,0x30e0,0,{0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x78} }, +{ 16,0x30f0,0,{0x26,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb4,0x90,0x7f,0xb5,0xee,0xf0} }, +{ 16,0x3100,0,{0x22,0xe4,0xff,0xef,0xc3,0x95,0x35,0x50,0x46,0x90,0x78,0x25,0xe0,0xfb,0xa3,0xe0} }, +{ 16,0x3110,0,{0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x05,0x12,0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74} }, +{ 16,0x3120,0,{0x00,0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x00,0x06,0x12,0x0c} }, +{ 16,0x3130,0,{0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83} }, +{ 16,0x3140,0,{0xed,0xf0,0x90,0x78,0x26,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb4,0x90} }, +{ 16,0x3150,0,{0x7f,0xb5,0xee,0xf0,0x22,0xe4,0xff,0xef,0xc3,0x95,0x35,0x50,0x46,0x90,0x78,0x25} }, +{ 16,0x3160,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x07,0x12,0x0c,0x5d,0xfd,0xcc} }, +{ 16,0x3170,0,{0xee,0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90} }, +{ 16,0x3180,0,{0x00,0x08,0x12,0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82,0xe4} }, +{ 16,0x3190,0,{0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x78,0x26,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4} }, +{ 16,0x31a0,0,{0x0f,0x80,0xb4,0x90,0x7f,0xb5,0xee,0xf0,0x22,0xe4,0xff,0xef,0xc3,0x95,0x35,0x50} }, +{ 16,0x31b0,0,{0x46,0x90,0x78,0x25,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x09,0x12} }, +{ 16,0x31c0,0,{0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00,0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, +{ 16,0x31d0,0,{0x83,0xed,0xf0,0x90,0x00,0x0a,0x12,0x0c,0x5d,0xfd,0xcc,0xee,0xcc,0x0e,0x74,0x00} }, +{ 16,0x31e0,0,{0x2c,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xed,0xf0,0x90,0x78,0x26,0xe4,0x75,0xf0} }, +{ 16,0x31f0,0,{0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb4,0x90,0x7f,0xb5,0xee,0xf0,0x22,0x90,0x7f,0xb4} }, +{ 12,0x3200,0,{0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x320c,0,{0x22} }, +{ 16,0x320d,0,{0x7b,0x01,0x7a,0x78,0x79,0x2b,0x90,0x78,0x00,0xeb,0xf0,0xa3,0xea,0xf0,0xa3,0xe9} }, +{ 16,0x321d,0,{0xf0,0x74,0x01,0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x322d,0,{0xf9,0x90,0x00,0x01,0x74,0x01,0x12,0x0c,0x9c,0x90,0x00,0x02,0xe4,0x12,0x0c,0x9c} }, +{ 16,0x323d,0,{0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3} }, +{ 16,0x324d,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x10,0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3} }, +{ 16,0x325d,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x05,0x12,0x0c,0x9c,0x90,0x00,0x02} }, +{ 16,0x326d,0,{0xe4,0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78} }, +{ 16,0x327d,0,{0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x02,0x12,0x0c,0x8a,0x90,0x78} }, +{ 16,0x328d,0,{0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x02,0x12,0x0c} }, +{ 16,0x329d,0,{0x9c,0x90,0x00,0x02,0xe4,0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12} }, +{ 16,0x32ad,0,{0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x01,0x12} }, +{ 16,0x32bd,0,{0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01} }, +{ 16,0x32cd,0,{0x74,0x03,0x12,0x0c,0x9c,0x90,0x00,0x02,0xe4,0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4} }, +{ 16,0x32dd,0,{0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x32ed,0,{0xf9,0x74,0x10,0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x32fd,0,{0xf9,0x90,0x00,0x01,0x74,0x06,0x12,0x0c,0x9c,0x90,0x00,0x02,0xe4,0x12,0x0c,0x9c} }, +{ 16,0x330d,0,{0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3} }, +{ 16,0x331d,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x02,0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3} }, +{ 16,0x332d,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x04,0x12,0x0c,0x9c,0x90,0x00,0x02} }, +{ 16,0x333d,0,{0xe4,0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78} }, +{ 16,0x334d,0,{0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x02,0x12,0x0c,0x8a,0x90,0x78} }, +{ 16,0x335d,0,{0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x04,0x12,0x0c} }, +{ 16,0x336d,0,{0x9c,0x90,0x00,0x02,0x74,0x04,0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4,0x75,0xf0,0x03} }, +{ 16,0x337d,0,{0x12,0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x02} }, +{ 16,0x338d,0,{0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00} }, +{ 16,0x339d,0,{0x01,0x74,0x03,0x12,0x0c,0x9c,0x90,0x00,0x02,0x74,0x04,0x12,0x0c,0x9c,0x90,0x78} }, +{ 16,0x33ad,0,{0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x33bd,0,{0xa3,0xe0,0xf9,0x74,0x02,0x12,0x0c,0x8a,0x90,0x78,0x00,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x33cd,0,{0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x02,0x12,0x0c,0x9c,0x90,0x00,0x02,0x74,0x04} }, +{ 16,0x33dd,0,{0x12,0x0c,0x9c,0x90,0x78,0x01,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x00} }, +{ 16,0x33ed,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x02,0x12,0x0c,0x8a,0x90,0x78,0x00} }, +{ 16,0x33fd,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x01,0x12,0x0c,0x9c} }, +{ 8,0x340d,0,{0x90,0x00,0x02,0x74,0x04,0x12,0x0c,0x9c} }, +{ 1,0x3415,0,{0x22} }, +{ 16,0x3416,0,{0xe4,0xfe,0x90,0x79,0x20,0xe0,0xfd,0xb4,0x05,0x11,0x90,0x78,0x1f,0x74,0x01,0xf0} }, +{ 16,0x3426,0,{0xa3,0x74,0x78,0xf0,0xa3,0x74,0xb2,0xf0,0x75,0x35,0x07,0xed,0xb4,0x06,0x11,0x90} }, +{ 16,0x3436,0,{0x78,0x1f,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xff,0xf0,0x75,0x35,0x03} }, +{ 16,0x3446,0,{0x90,0x79,0x99,0xe0,0x14,0x60,0x11,0x14,0x60,0x5b,0x24,0x02,0x60,0x02,0xc1,0x06} }, +{ 16,0x3456,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x97,0xe0,0x14,0x70,0x3e,0xe4} }, +{ 16,0x3466,0,{0xff,0xef,0xc3,0x95,0x35,0x50,0x2f,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5,0x82} }, +{ 16,0x3476,0,{0xe4,0x34,0x79,0xf5,0x83,0xe0,0xfd,0x90,0x78,0x1f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3} }, +{ 16,0x3486,0,{0xe0,0xf9,0x90,0x00,0x01,0xed,0x12,0x0c,0x9c,0x90,0x78,0x20,0xe4,0x75,0xf0,0x0b} }, +{ 16,0x3496,0,{0x12,0x0c,0xf4,0x0f,0x80,0xcb,0x90,0x79,0x75,0x74,0x01,0xf0,0x22,0x90,0x7f,0xb4} }, +{ 16,0x34a6,0,{0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x97,0xe0,0x24,0xfe,0x60,0x63,0x14,0x70,0x02} }, +{ 16,0x34b6,0,{0xa1,0x64,0x14,0x70,0x02,0xa1,0xb2,0x24,0x03,0x60,0x02,0xa1,0xfe,0xe4,0xff,0xef} }, +{ 16,0x34c6,0,{0xc3,0x95,0x35,0x50,0x44,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5,0x82,0xe4,0x34} }, +{ 16,0x34d6,0,{0x79,0xf5,0x83,0xe0,0xfd,0x90,0x78,0x1f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9} }, +{ 16,0x34e6,0,{0x90,0x00,0x03,0xed,0x12,0x0c,0x9c,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5,0x82} }, +{ 16,0x34f6,0,{0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x00,0x04,0x12,0x0c,0x9c,0x90,0x78,0x20,0xe4} }, +{ 16,0x3506,0,{0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb6,0x90,0x79,0x75,0x74,0x01,0xf0,0x22} }, +{ 16,0x3516,0,{0xe4,0xff,0xef,0xc3,0x95,0x35,0x40,0x02,0xc1,0x0d,0xcd,0xee,0xcd,0x0e,0x74,0x21} }, +{ 16,0x3526,0,{0x2d,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0xfd,0x90,0x78,0x1f,0xe0,0xfb,0xa3} }, +{ 16,0x3536,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x05,0xed,0x12,0x0c,0x9c,0xcd,0xee,0xcd,0x0e} }, +{ 16,0x3546,0,{0x74,0x21,0x2d,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x00,0x06,0x12,0x0c} }, +{ 16,0x3556,0,{0x9c,0x90,0x78,0x20,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb4,0xe4,0xff} }, +{ 16,0x3566,0,{0xef,0xc3,0x95,0x35,0x40,0x02,0xc1,0x0d,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5} }, +{ 16,0x3576,0,{0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0xfd,0x90,0x78,0x1f,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x3586,0,{0xa3,0xe0,0xf9,0x90,0x00,0x07,0xed,0x12,0x0c,0x9c,0xcd,0xee,0xcd,0x0e,0x74,0x21} }, +{ 16,0x3596,0,{0x2d,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x00,0x08,0x12,0x0c,0x9c,0x90} }, +{ 16,0x35a6,0,{0x78,0x20,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb4,0xe4,0xff,0xef,0xc3} }, +{ 16,0x35b6,0,{0x95,0x35,0x50,0x53,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5,0x82,0xe4,0x34,0x79} }, +{ 16,0x35c6,0,{0xf5,0x83,0xe0,0xfd,0x90,0x78,0x1f,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90} }, +{ 16,0x35d6,0,{0x00,0x09,0xed,0x12,0x0c,0x9c,0xcd,0xee,0xcd,0x0e,0x74,0x21,0x2d,0xf5,0x82,0xe4} }, +{ 16,0x35e6,0,{0x34,0x79,0xf5,0x83,0xe0,0x90,0x00,0x0a,0x12,0x0c,0x9c,0x90,0x78,0x20,0xe4,0x75} }, +{ 16,0x35f6,0,{0xf0,0x0b,0x12,0x0c,0xf4,0x0f,0x80,0xb6,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22} }, +{ 7,0x3606,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x360d,0,{0x22} }, +{ 16,0x360e,0,{0xe4,0xfe,0x90,0x79,0x20,0xe0,0xfd,0xb4,0x05,0x10,0x90,0x78,0x28,0x74,0x01,0xf0} }, +{ 16,0x361e,0,{0xa3,0x74,0x78,0xf0,0xa3,0x74,0xb2,0xf0,0x7f,0x07,0xed,0xb4,0x06,0x10,0x90,0x78} }, +{ 16,0x362e,0,{0x28,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xff,0xf0,0x7f,0x03,0x90,0x78} }, +{ 16,0x363e,0,{0x28,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x12,0x0c,0x44,0xfd,0x90,0x7f,0xea} }, +{ 16,0x364e,0,{0xe0,0x6d,0x60,0x12,0xee,0xc3,0x9f,0x50,0x0d,0x90,0x78,0x29,0xe4,0x75,0xf0,0x0b} }, +{ 16,0x365e,0,{0x12,0x0c,0xf4,0x0e,0x80,0xd8,0x90,0x7f,0xeb,0xe0,0x14,0x60,0x11,0x14,0x60,0x46} }, +{ 16,0x366e,0,{0x24,0x02,0x60,0x02,0xe1,0x9a,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f} }, +{ 16,0x367e,0,{0xe9,0xe0,0x24,0x7f,0x70,0x28,0xee,0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01} }, +{ 16,0x368e,0,{0xf0,0x22,0x90,0x78,0x28,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01} }, +{ 16,0x369e,0,{0x12,0x0c,0x5d,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0,0x22,0x90,0x7f} }, +{ 16,0x36ae,0,{0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xe9,0xe0,0x24,0x7e,0x60,0x40,0x14,0x60} }, +{ 16,0x36be,0,{0x6f,0x14,0x70,0x02,0xe1,0x60,0x24,0x03,0x60,0x02,0xe1,0x92,0xee,0x6f,0x70,0x08} }, +{ 16,0x36ce,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78,0x28,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x36de,0,{0xa3,0xe0,0xf9,0x90,0x00,0x03,0x12,0x0c,0x5d,0x90,0x7f,0x00,0xf0,0x90,0x00,0x04} }, +{ 16,0x36ee,0,{0x12,0x0c,0x5d,0x90,0x7f,0x01,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x22,0xee,0x6f} }, +{ 16,0x36fe,0,{0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78,0x28,0xe0,0xfb,0xa3} }, +{ 16,0x370e,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x05,0x12,0x0c,0x5d,0x90,0x7f,0x00,0xf0,0x90} }, +{ 16,0x371e,0,{0x00,0x06,0x12,0x0c,0x5d,0x90,0x7f,0x01,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x22} }, +{ 16,0x372e,0,{0xee,0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78,0x28,0xe0} }, +{ 16,0x373e,0,{0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x07,0x12,0x0c,0x5d,0x90,0x7f,0x00} }, +{ 16,0x374e,0,{0xf0,0x90,0x00,0x08,0x12,0x0c,0x5d,0x90,0x7f,0x01,0xf0,0x90,0x7f,0xb5,0x74,0x02} }, +{ 16,0x375e,0,{0xf0,0x22,0xee,0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78} }, +{ 16,0x376e,0,{0x28,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x09,0x12,0x0c,0x5d,0x90} }, +{ 16,0x377e,0,{0x7f,0x00,0xf0,0x90,0x00,0x0a,0x12,0x0c,0x5d,0x90,0x7f,0x01,0xf0,0x90,0x7f,0xb5} }, +{ 16,0x378e,0,{0x74,0x02,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0} }, +{ 3,0x379e,0,{0x44,0x01,0xf0} }, +{ 1,0x37a1,0,{0x22} }, +{ 16,0x37a2,0,{0xc0,0xe0,0xc0,0xf0,0xc0,0x83,0xc0,0x82,0xc0,0xd0,0xe8,0xc0,0xe0,0xe9,0xc0,0xe0} }, +{ 16,0x37b2,0,{0xea,0xc0,0xe0,0xeb,0xc0,0xe0,0xec,0xc0,0xe0,0xed,0xc0,0xe0,0xee,0xc0,0xe0,0xef} }, +{ 16,0x37c2,0,{0xc0,0xe0,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x10,0xf0,0x90,0x79,0x83,0xe0,0x54} }, +{ 16,0x37d2,0,{0xfd,0xf0,0x12,0x2f,0xdf,0xd0,0xe0,0xff,0xd0,0xe0,0xfe,0xd0,0xe0,0xfd,0xd0,0xe0} }, +{ 16,0x37e2,0,{0xfc,0xd0,0xe0,0xfb,0xd0,0xe0,0xfa,0xd0,0xe0,0xf9,0xd0,0xe0,0xf8,0xd0,0xd0,0xd0} }, +{ 8,0x37f2,0,{0x82,0xd0,0x83,0xd0,0xf0,0xd0,0xe0,0x32} }, +{ 6,0x37fa,0,{0x53,0x91,0xbf,0xd2,0x26,0x32} }, +{ 16,0x3800,0,{0xe4,0xfe,0x90,0x79,0x20,0xe0,0xfd,0xb4,0x05,0x10,0x90,0x78,0x22,0x74,0x01,0xf0} }, +{ 16,0x3810,0,{0xa3,0x74,0x78,0xf0,0xa3,0x74,0xb2,0xf0,0x7f,0x07,0xed,0xb4,0x06,0x10,0x90,0x78} }, +{ 16,0x3820,0,{0x22,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xff,0xf0,0x7f,0x03,0x90,0x78} }, +{ 16,0x3830,0,{0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x12,0x0c,0x44,0xfd,0x90,0x79,0x98} }, +{ 16,0x3840,0,{0xe0,0x6d,0x60,0x12,0xee,0xc3,0x9f,0x50,0x0d,0x90,0x78,0x23,0xe4,0x75,0xf0,0x0b} }, +{ 16,0x3850,0,{0x12,0x0c,0xf4,0x0e,0x80,0xd8,0x90,0x79,0x99,0xe0,0x14,0x60,0x11,0x14,0x60,0x48} }, +{ 16,0x3860,0,{0x24,0x02,0x60,0x02,0x21,0x85,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79} }, +{ 16,0x3870,0,{0x97,0xe0,0x14,0x70,0x2b,0xee,0x6f,0x70,0x09,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 16,0x3880,0,{0x80,0x17,0x90,0x79,0x21,0xe0,0xfd,0x90,0x78,0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3} }, +{ 16,0x3890,0,{0xe0,0xf9,0x90,0x00,0x01,0xed,0x12,0x0c,0x9c,0x90,0x79,0x75,0x74,0x01,0xf0,0x22} }, +{ 16,0x38a0,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x97,0xe0,0x24,0xfe,0x60,0x43} }, +{ 16,0x38b0,0,{0x14,0x60,0x6e,0x14,0x70,0x02,0x21,0x4f,0x24,0x03,0x60,0x02,0x21,0x7d,0xee,0x6f} }, +{ 16,0x38c0,0,{0x70,0x09,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x80,0x21,0x90,0x79,0x21,0xe0,0xfd} }, +{ 16,0x38d0,0,{0x90,0x78,0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x03,0xed,0x12} }, +{ 16,0x38e0,0,{0x0c,0x9c,0x90,0x79,0x22,0xe0,0x90,0x00,0x04,0x12,0x0c,0x9c,0x90,0x79,0x75,0x74} }, +{ 16,0x38f0,0,{0x01,0xf0,0x22,0xee,0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90} }, +{ 16,0x3900,0,{0x79,0x21,0xe0,0xfd,0x90,0x78,0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90} }, +{ 16,0x3910,0,{0x00,0x05,0xed,0x12,0x0c,0x9c,0x90,0x79,0x22,0xe0,0x90,0x00,0x06,0x12,0x0c,0x9c} }, +{ 16,0x3920,0,{0x22,0xee,0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x21} }, +{ 16,0x3930,0,{0xe0,0xfd,0x90,0x78,0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x07} }, +{ 16,0x3940,0,{0xed,0x12,0x0c,0x9c,0x90,0x79,0x22,0xe0,0x90,0x00,0x08,0x12,0x0c,0x9c,0x22,0xee} }, +{ 16,0x3950,0,{0x6f,0x70,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x79,0x21,0xe0,0xfe} }, +{ 16,0x3960,0,{0x90,0x78,0x22,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x09,0xee,0x12} }, +{ 16,0x3970,0,{0x0c,0x9c,0x90,0x79,0x22,0xe0,0x90,0x00,0x0a,0x12,0x0c,0x9c,0x22,0x90,0x7f,0xb4} }, +{ 12,0x3980,0,{0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x398c,0,{0x22} }, +{ 16,0x398d,0,{0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xe4,0x90,0x79,0x83,0xf0,0x12,0x2f,0xdf,0x90,0x7f} }, +{ 16,0x399d,0,{0xe0,0x74,0x90,0xf0,0x90,0x7f,0xe1,0x74,0x04,0xf0,0xe4,0x90,0x7f,0xdd,0xf0,0x90} }, +{ 16,0x39ad,0,{0x7f,0xa1,0xf0,0x53,0x8e,0xf8,0x75,0x88,0x05,0x75,0xb8,0x20,0x75,0xf8,0x01,0x43} }, +{ 16,0x39bd,0,{0x8e,0x30,0xf5,0xc8,0x75,0xca,0x7f,0x75,0xcb,0xf8,0x43,0xa8,0x20,0x90,0x79,0x74} }, +{ 16,0x39cd,0,{0x04,0xf0,0xc2,0x22,0xe4,0xf5,0x0f,0x90,0x79,0x78,0xf0,0xa3,0xf0,0x90,0x79,0x62} }, +{ 16,0x39dd,0,{0xf0,0xa3,0xf0,0xa3,0xf0,0x90,0x79,0x66,0xf0,0xa3,0xf0,0x90,0x79,0x7b,0xf0,0xa3} }, +{ 16,0x39ed,0,{0xf0,0x90,0x79,0x84,0xf0,0x90,0x79,0x7d,0xf0,0x90,0x79,0x75,0xf0,0xa3,0xf0,0xa3} }, +{ 16,0x39fd,0,{0xf0,0xc2,0x23,0xc2,0x24,0xc2,0x25,0xc2,0x26,0xc2,0x20,0x90,0x7f,0x9b,0xe0,0xf5} }, +{ 16,0x3a0d,0,{0x0a,0x54,0x20,0xf5,0x0a,0x70,0x06,0x90,0x79,0x7e,0xf0,0x80,0x06,0x90,0x79,0x7e} }, +{ 16,0x3a1d,0,{0x74,0x01,0xf0,0x90,0x7f,0x9b,0xe0,0xf5,0x0a,0x54,0x02,0xf5,0x0a,0x70,0x06,0x90} }, +{ 16,0x3a2d,0,{0x79,0x7f,0xf0,0x80,0x06,0x90,0x79,0x7f,0x74,0x01,0xf0,0x90,0x79,0x78,0x74,0x02} }, +{ 16,0x3a3d,0,{0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7f,0xe0,0xb4,0x01,0x09} }, +{ 16,0x3a4d,0,{0x90,0x79,0x79,0xe0,0x54,0xfe,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0} }, +{ 16,0x3a5d,0,{0x90,0x79,0x79,0xe0,0x90,0x79,0x84,0xf0,0x12,0x0b,0xa2,0x90,0x79,0x78,0x74,0x01} }, +{ 16,0x3a6d,0,{0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0x90,0x79,0x7e,0xe0,0xb4,0x01,0x09} }, +{ 16,0x3a7d,0,{0x90,0x79,0x79,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb,0xf0} }, +{ 16,0x3a8d,0,{0x90,0x79,0x79,0xe0,0x90,0x79,0x7c,0xf0,0x12,0x0b,0xa2,0xe4,0x90,0x79,0x78,0xf0} }, +{ 16,0x3a9d,0,{0xa3,0x04,0xf0,0xe4,0x90,0x79,0x88,0xf0,0x12,0x0b,0xa2,0x90,0x7f,0xfc,0x74,0xdd} }, +{ 16,0x3aad,0,{0xf0,0x90,0x7f,0xff,0x74,0xff,0xf0,0x90,0x79,0x78,0x74,0x01,0xf0,0xa3,0xf0,0x12} }, +{ 16,0x3abd,0,{0x0b,0xa2,0xe4,0x90,0x79,0x7a,0xf0,0x90,0x79,0x83,0x04,0xf0,0x12,0x2f,0xdf,0xe4} }, +{ 16,0x3acd,0,{0x90,0x79,0x30,0xf0,0x90,0x79,0x85,0xf0,0xa3,0xf0,0xa3,0xf0,0x12,0x2e,0x94,0x90} }, +{ 16,0x3add,0,{0x79,0x2d,0x74,0x02,0xf0,0x90,0x79,0x88,0x14,0xf0,0xc2,0x2f,0xe4,0x90,0x79,0x68} }, +{ 16,0x3aed,0,{0xf0,0x90,0x79,0x8a,0xf0,0x90,0x79,0x6a,0xf0,0xa3,0xf0,0x75,0x13,0x08,0x75,0x14} }, +{ 16,0x3afd,0,{0x08,0xf5,0x16,0xf5,0x15,0xf5,0x17,0x90,0x79,0x8c,0xf0,0x90,0x79,0x8b,0xf0,0x22} }, +{ 16,0x3b0d,0,{0x7b,0x01,0x7a,0x78,0x79,0x58,0x90,0x78,0x03,0xeb,0xf0,0xa3,0xea,0xf0,0xa3,0xe9} }, +{ 16,0x3b1d,0,{0xf0,0x74,0x40,0x12,0x0c,0x8a,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x3b2d,0,{0xf9,0x90,0x00,0x01,0x74,0x0a,0x12,0x0c,0x9c,0x90,0x00,0x02,0x12,0x0d,0xf6,0x00} }, +{ 16,0x3b3d,0,{0x00,0xbb,0x80,0x90,0x00,0x06,0x12,0x0d,0xf6,0x00,0x00,0xac,0x44,0x90,0x00,0x0a} }, +{ 16,0x3b4d,0,{0x12,0x0d,0xf6,0x00,0x01,0x77,0x00,0x90,0x78,0x04,0xe4,0x75,0xf0,0x0f,0x12,0x0c} }, +{ 16,0x3b5d,0,{0xf4,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x40,0x12,0x0c} }, +{ 16,0x3b6d,0,{0x8a,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74} }, +{ 16,0x3b7d,0,{0x8c,0x12,0x0c,0x9c,0x90,0x00,0x02,0x12,0x0d,0xf6,0x00,0x00,0xbb,0x80,0x90,0x00} }, +{ 16,0x3b8d,0,{0x06,0x12,0x0d,0xf6,0x00,0x00,0xac,0x44,0x90,0x00,0x0a,0x12,0x0d,0xf6,0x00,0x01} }, +{ 16,0x3b9d,0,{0x77,0x00,0x90,0x78,0x04,0xe4,0x75,0xf0,0x0f,0x12,0x0c,0xf4,0x90,0x78,0x03,0xe0} }, +{ 16,0x3bad,0,{0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x40,0x12,0x0c,0x8a,0x90,0x78,0x03,0xe0} }, +{ 16,0x3bbd,0,{0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x8f,0x12,0x0c,0x9c,0x90} }, +{ 16,0x3bcd,0,{0x78,0x04,0xe4,0x75,0xf0,0x0f,0x12,0x0c,0xf4,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0} }, +{ 16,0x3bdd,0,{0xfa,0xa3,0xe0,0xf9,0x74,0x41,0x12,0x0c,0x8a,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0} }, +{ 16,0x3bed,0,{0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x84,0x12,0x0c,0x9c,0x90,0x78,0x04,0xe4} }, +{ 16,0x3bfd,0,{0x75,0xf0,0x0f,0x12,0x0c,0xf4,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x3c0d,0,{0xf9,0x74,0x61,0x12,0x0c,0x8a,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0} }, +{ 16,0x3c1d,0,{0xf9,0x90,0x00,0x01,0x74,0x81,0x12,0x0c,0x9c,0x90,0x78,0x04,0xe4,0x75,0xf0,0x0f} }, +{ 16,0x3c2d,0,{0x12,0x0c,0xf4,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x74,0x61} }, +{ 16,0x3c3d,0,{0x12,0x0c,0x8a,0x90,0x78,0x03,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00} }, +{ 6,0x3c4d,0,{0x01,0x74,0x01,0x12,0x0c,0x9c} }, +{ 1,0x3c53,0,{0x22} }, +{ 16,0x3c54,0,{0xc0,0xe0,0xc0,0xf0,0xc0,0x83,0xc0,0x82,0xc0,0xd0,0xe8,0xc0,0xe0,0xe9,0xc0,0xe0} }, +{ 16,0x3c64,0,{0xea,0xc0,0xe0,0xeb,0xc0,0xe0,0xec,0xc0,0xe0,0xed,0xc0,0xe0,0xee,0xc0,0xe0,0xef} }, +{ 2,0x3c74,0,{0xc0,0xe0} }, +{ 16,0x3c76,0,{0x90,0x7f,0xa2,0xe0,0xf5,0x0b,0x90,0x7f,0x74,0xe0,0x90,0x79,0x70,0xf0,0x90,0x7f} }, +{ 16,0x3c86,0,{0x75,0xe0,0x90,0x79,0x71,0xf0,0x90,0x79,0x83,0xe0,0xff,0xfe,0x54,0x02,0xfe,0x70} }, +{ 16,0x3c96,0,{0x0d,0xef,0x44,0x02,0xf0,0x12,0x2f,0xdf,0x90,0x79,0x74,0x74,0x01,0xf0,0xe5,0x0b} }, +{ 16,0x3ca6,0,{0x20,0xe2,0x28,0x90,0x79,0x70,0xe0,0xfe,0xa3,0xe0,0x7c,0x00,0x24,0x00,0xf5,0x11} }, +{ 16,0x3cb6,0,{0xec,0x3e,0xf5,0x10,0x90,0x79,0x82,0xe0,0xfd,0xae,0x10,0xaf,0x11,0x12,0x0c,0xbe} }, +{ 16,0x3cc6,0,{0x90,0x79,0x70,0xef,0xf0,0x90,0x79,0x89,0x74,0x01,0xf0,0x12,0x48,0x43,0x12,0x48} }, +{ 16,0x3cd6,0,{0x76,0x90,0x79,0x89,0xe0,0x64,0x01,0x70,0x32,0x12,0x41,0x08,0x90,0x79,0x89,0xe4} }, +{ 16,0x3ce6,0,{0xf0,0x90,0x7f,0x98,0xe0,0x44,0x40,0xf0,0x90,0x7f,0x9e,0xe0,0x44,0x40,0xf0,0x90} }, +{ 16,0x3cf6,0,{0x7f,0x95,0x74,0x80,0xf0,0x75,0xe8,0x01,0x12,0x09,0x32,0x75,0xe8,0x0d,0x90,0x7f} }, +{ 16,0x3d06,0,{0x95,0x74,0xc0,0xf0,0x75,0xe8,0x0d,0xd2,0x20,0x80,0x05,0x75,0xe8,0x01,0xc2,0x20} }, +{ 16,0x3d16,0,{0x20,0x20,0x2b,0x90,0x79,0x2d,0xe0,0xff,0xb4,0x01,0x09,0x75,0x0c,0x67,0x75,0x0d} }, +{ 16,0x3d26,0,{0x06,0x75,0x0e,0x0b,0xef,0xb4,0x02,0x09,0x75,0x0c,0x00,0x75,0x0d,0x00,0x75,0x0e} }, +{ 16,0x3d36,0,{0x0c,0xef,0xb4,0x03,0x09,0x75,0x0c,0x00,0x75,0x0d,0x00,0x75,0x0e,0x18,0x75,0xca} }, +{ 16,0x3d46,0,{0x6f,0x75,0xcb,0xfe,0xd2,0xca,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x02,0xf0,0xf0} }, +{ 16,0x3d56,0,{0xd0,0xe0,0xff,0xd0,0xe0,0xfe,0xd0,0xe0,0xfd,0xd0,0xe0,0xfc,0xd0,0xe0,0xfb,0xd0} }, +{ 16,0x3d66,0,{0xe0,0xfa,0xd0,0xe0,0xf9,0xd0,0xe0,0xf8,0xd0,0xd0,0xd0,0x82,0xd0,0x83,0xd0,0xf0} }, +{ 3,0x3d76,0,{0xd0,0xe0,0x32} }, +{ 16,0x3d79,0,{0x75,0x33,0x25,0x75,0x34,0x24,0x90,0x79,0x5c,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0} }, +{ 16,0x3d89,0,{0xa3,0x74,0xb2,0xf0,0x20,0x2f,0x02,0xc1,0x17,0xe4,0xf5,0x35,0x75,0x22,0x01,0x90} }, +{ 16,0x3d99,0,{0x79,0x5c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x04,0x12,0x0c,0x5d} }, +{ 16,0x3da9,0,{0xf5,0x36,0x75,0x35,0x06,0x74,0x42,0x25,0x35,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83} }, +{ 16,0x3db9,0,{0xe5,0x36,0xf0,0x05,0x35,0xe5,0x35,0xb4,0x0c,0xeb,0xe5,0x35,0xc3,0x94,0x0d,0x40} }, +{ 16,0x3dc9,0,{0x02,0xc1,0x98,0xe5,0x22,0x64,0x01,0x60,0x02,0xc1,0x98,0x90,0x7f,0xa5,0xe0,0x44} }, +{ 16,0x3dd9,0,{0x80,0xf0,0x90,0x7f,0xa6,0xe5,0x33,0xf0,0x12,0x46,0xc0,0x74,0x4f,0x25,0x35,0xf5} }, +{ 16,0x3de9,0,{0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12,0x46,0xc0,0x74,0x42} }, +{ 16,0x3df9,0,{0x25,0x35,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12,0x46} }, +{ 16,0x3e09,0,{0xc0,0x90,0x7f,0xa5,0x74,0x40,0xf0,0x12,0x0a,0xcd,0x05,0x35,0x80,0xac,0xe4,0xf5} }, +{ 16,0x3e19,0,{0x35,0x75,0x22,0x01,0x90,0x79,0x5c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90} }, +{ 16,0x3e29,0,{0x00,0x04,0x12,0x0c,0x5d,0xf5,0x36,0x75,0x35,0x06,0x74,0x35,0x25,0x35,0xf5,0x82} }, +{ 16,0x3e39,0,{0xe4,0x34,0x79,0xf5,0x83,0xe5,0x36,0xf0,0x05,0x35,0xe5,0x35,0xb4,0x0c,0xeb,0xe5} }, +{ 16,0x3e49,0,{0x35,0xc3,0x94,0x0d,0x50,0x49,0xe5,0x22,0x64,0x01,0x70,0x43,0x90,0x7f,0xa5,0xe0} }, +{ 16,0x3e59,0,{0x44,0x80,0xf0,0x90,0x7f,0xa6,0xe5,0x33,0xf0,0x12,0x46,0xc0,0x74,0x4f,0x25,0x35} }, +{ 16,0x3e69,0,{0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12,0x46,0xc0,0x74} }, +{ 16,0x3e79,0,{0x35,0x25,0x35,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xe0,0x90,0x7f,0xa6,0xf0,0x12} }, +{ 15,0x3e89,0,{0x46,0xc0,0x90,0x7f,0xa5,0x74,0x40,0xf0,0x12,0x0a,0xcd,0x05,0x35,0x80,0xb0} }, +{ 1,0x3e98,0,{0x22} }, +{ 16,0x3e99,0,{0x90,0x78,0x09,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0xb2,0xf0,0xe4,0xff} }, +{ 16,0x3ea9,0,{0xfe,0x90,0x78,0x09,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0xef,0x12,0x0c,0x8a} }, +{ 16,0x3eb9,0,{0x90,0x78,0x09,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0xe4,0x12} }, +{ 16,0x3ec9,0,{0x0c,0x9c,0x90,0x00,0x02,0x74,0x15,0x12,0x0c,0x9c,0x90,0x00,0x03,0xe4,0x12,0x0c} }, +{ 16,0x3ed9,0,{0x9c,0x90,0x00,0x04,0x74,0xff,0x12,0x0c,0x9c,0x90,0x00,0x05,0xe4,0x12,0x0c,0x9c} }, +{ 16,0x3ee9,0,{0x90,0x00,0x06,0x74,0xc3,0x12,0x0c,0x9c,0x90,0x00,0x07,0xe4,0x12,0x0c,0x9c,0x90} }, +{ 16,0x3ef9,0,{0x00,0x08,0xe4,0x12,0x0c,0x9c,0x90,0x00,0x09,0xe4,0x12,0x0c,0x9c,0x90,0x00,0x0a} }, +{ 16,0x3f09,0,{0x74,0x01,0x12,0x0c,0x9c,0x90,0x78,0x0a,0xe4,0x75,0xf0,0x0b,0x12,0x0c,0xf4,0x0f} }, +{ 16,0x3f19,0,{0x0e,0xbe,0x07,0x8d,0x90,0x78,0x09,0x74,0x01,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74} }, +{ 16,0x3f29,0,{0xff,0xf0,0xe4,0xff,0xfe,0x90,0x78,0x09,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9} }, +{ 16,0x3f39,0,{0xef,0x12,0x0c,0x8a,0x90,0x78,0x09,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90} }, +{ 16,0x3f49,0,{0x00,0x01,0xe4,0x12,0x0c,0x9c,0x90,0x00,0x02,0x74,0x15,0x12,0x0c,0x9c,0x90,0x00} }, +{ 16,0x3f59,0,{0x03,0xe4,0x12,0x0c,0x9c,0x90,0x00,0x04,0x74,0x80,0x12,0x0c,0x9c,0x90,0x00,0x05} }, +{ 16,0x3f69,0,{0xe4,0x12,0x0c,0x9c,0x90,0x00,0x06,0x74,0xc3,0x12,0x0c,0x9c,0x90,0x00,0x07,0xe4} }, +{ 16,0x3f79,0,{0x12,0x0c,0x9c,0x90,0x00,0x08,0xe4,0x12,0x0c,0x9c,0x90,0x00,0x09,0xe4,0x12,0x0c} }, +{ 16,0x3f89,0,{0x9c,0x90,0x00,0x0a,0x74,0x01,0x12,0x0c,0x9c,0x90,0x78,0x0a,0xe4,0x75,0xf0,0x0b} }, +{ 8,0x3f99,0,{0x12,0x0c,0xf4,0x0f,0x0e,0xbe,0x03,0x8d} }, +{ 1,0x3fa1,0,{0x22} }, +{ 16,0x3fa2,0,{0xe4,0xfe,0x75,0x3d,0xff,0x75,0x3e,0x05,0x75,0x3f,0x12,0xab,0x3d,0xaa,0x3e,0xa9} }, +{ 16,0x3fb2,0,{0x3f,0x90,0x00,0x01,0x12,0x0c,0x5d,0x64,0x02,0x70,0x2f,0xcd,0xee,0xcd,0x0e,0xed} }, +{ 16,0x3fc2,0,{0x6f,0x70,0x01,0x22,0x90,0x00,0x02,0x12,0x0d,0x0a,0x85,0xf0,0x3b,0xf5,0x3c,0x62} }, +{ 16,0x3fd2,0,{0x3b,0xe5,0x3b,0x62,0x3c,0xe5,0x3c,0x62,0x3b,0x29,0xfd,0xe5,0x3b,0x3a,0xc9,0xed} }, +{ 16,0x3fe2,0,{0xc9,0x75,0x3d,0xff,0xf5,0x3e,0x89,0x3f,0x80,0xc1,0x7b,0x00,0x7a,0x00,0x79,0x00} }, +{ 1,0x3ff2,0,{0x22} }, +{ 9,0x3ff3,0,{0x53,0xd8,0xef,0x43,0xd8,0x20,0xc2,0x2d,0x32} }, +{ 4,0x3ffc,0,{0x53,0x91,0xdf,0x32} }, +{ 16,0x4000,0,{0x90,0x79,0x87,0xe0,0xb4,0x01,0x1d,0x90,0x79,0x85,0xe0,0xb4,0x01,0x03,0x12,0x42} }, +{ 16,0x4010,0,{0xaa,0x90,0x79,0x86,0xe0,0xb4,0x01,0x03,0x12,0x18,0x00,0xe4,0x90,0x79,0x85,0xf0} }, +{ 16,0x4020,0,{0xa3,0xf0,0xa3,0xf0,0x12,0x2e,0x94,0x90,0x7f,0x9b,0xe0,0xf5,0x0a,0x54,0x02,0xf5} }, +{ 16,0x4030,0,{0x0a,0x70,0x04,0x90,0x79,0x7f,0xf0,0x90,0x7f,0x9b,0xe0,0xf5,0x0a,0x54,0x02,0xff} }, +{ 16,0x4040,0,{0xf5,0x0a,0xbf,0x02,0x06,0x90,0x79,0x7f,0x74,0x01,0xf0,0x90,0x7f,0x9b,0xe0,0xf5} }, +{ 16,0x4050,0,{0x0a,0x54,0x20,0xf5,0x0a,0x70,0x04,0x90,0x79,0x7e,0xf0,0x90,0x7f,0x9b,0xe0,0xf5} }, +{ 16,0x4060,0,{0x0a,0x54,0x20,0xff,0xf5,0x0a,0xbf,0x20,0x06,0x90,0x79,0x7e,0x74,0x01,0xf0,0x90} }, +{ 16,0x4070,0,{0x79,0x7f,0xe0,0xff,0x90,0x79,0x81,0xe0,0x6f,0x60,0x38,0x90,0x79,0x78,0x74,0x02} }, +{ 16,0x4080,0,{0xf0,0x90,0x79,0x84,0xe0,0x90,0x79,0x79,0xf0,0xef,0xb4,0x01,0x06,0xe0,0x54,0xfe} }, +{ 16,0x4090,0,{0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x44,0x01,0xf0,0x90,0x79,0x79,0xe0,0x90,0x79} }, +{ 16,0x40a0,0,{0x84,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0xe5,0x12,0x60} }, +{ 16,0x40b0,0,{0x02,0xd2,0xaf,0x90,0x79,0x7e,0xe0,0xff,0x90,0x79,0x80,0xe0,0x6f,0x60,0x38,0x90} }, +{ 16,0x40c0,0,{0x79,0x78,0x74,0x01,0xf0,0x90,0x79,0x7c,0xe0,0x90,0x79,0x79,0xf0,0xef,0xb4,0x01} }, +{ 16,0x40d0,0,{0x06,0xe0,0x44,0x04,0xf0,0x80,0x07,0x90,0x79,0x79,0xe0,0x54,0xfb,0xf0,0x90,0x79} }, +{ 16,0x40e0,0,{0x79,0xe0,0x90,0x79,0x7c,0xf0,0xa2,0xaf,0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b} }, +{ 16,0x40f0,0,{0xa2,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x90,0x79,0x7f,0xe0,0x90,0x79,0x81,0xf0,0x90} }, +{ 8,0x4100,0,{0x79,0x7e,0xe0,0x90,0x79,0x80,0xf0,0x22} }, +{ 16,0x4108,0,{0x90,0x79,0x2d,0xe0,0x64,0x01,0x70,0x35,0x90,0x79,0x70,0xe0,0xff,0xd3,0x94,0x2d} }, +{ 16,0x4118,0,{0x40,0x2b,0x90,0x79,0x69,0x74,0x01,0xf0,0x90,0x79,0x68,0xe0,0x04,0xf0,0xe0,0xd3} }, +{ 16,0x4128,0,{0x94,0x0f,0x40,0x19,0xe4,0xf0,0xef,0xd3,0x94,0x31,0x40,0x08,0x90,0x79,0x2d,0x74} }, +{ 16,0x4138,0,{0x03,0xf0,0x80,0x06,0x90,0x79,0x2d,0x74,0x02,0xf0,0x12,0x10,0x00,0x90,0x79,0x2d} }, +{ 16,0x4148,0,{0xe0,0xb4,0x02,0x2c,0x90,0x79,0x70,0xe0,0xff,0xc3,0x94,0x2f,0x50,0x22,0xef,0xd3} }, +{ 16,0x4158,0,{0x94,0x2a,0x40,0x1c,0x90,0x79,0x69,0x74,0x01,0xf0,0x90,0x79,0x68,0xe0,0x04,0xf0} }, +{ 16,0x4168,0,{0xe0,0xd3,0x94,0x0f,0x40,0x0a,0xe4,0xf0,0x90,0x79,0x2d,0x04,0xf0,0x12,0x10,0x00} }, +{ 16,0x4178,0,{0x90,0x79,0x2d,0xe0,0xb4,0x02,0x26,0x90,0x79,0x70,0xe0,0xd3,0x94,0x31,0x40,0x1d} }, +{ 16,0x4188,0,{0x90,0x79,0x69,0x74,0x01,0xf0,0x90,0x79,0x68,0xe0,0x04,0xf0,0xe0,0xd3,0x94,0x0f} }, +{ 16,0x4198,0,{0x40,0x0b,0xe4,0xf0,0x90,0x79,0x2d,0x74,0x03,0xf0,0x12,0x10,0x00,0x90,0x79,0x2d} }, +{ 16,0x41a8,0,{0xe0,0x64,0x03,0x70,0x3f,0x90,0x79,0x70,0xe0,0xff,0xc3,0x94,0x5f,0x50,0x35,0x90} }, +{ 16,0x41b8,0,{0x79,0x69,0x74,0x01,0xf0,0x90,0x79,0x68,0xe0,0x04,0xf0,0xe0,0xd3,0x94,0x0f,0x40} }, +{ 16,0x41c8,0,{0x23,0xe4,0xf0,0xef,0xc3,0x94,0x2f,0x50,0x0c,0xef,0xd3,0x94,0x2a,0x40,0x06,0x90} }, +{ 16,0x41d8,0,{0x79,0x2d,0x74,0x01,0xf0,0xef,0xd3,0x94,0x2f,0x40,0x06,0x90,0x79,0x2d,0x74,0x02} }, +{ 16,0x41e8,0,{0xf0,0x12,0x10,0x00,0x90,0x79,0x69,0xe0,0x70,0x05,0x90,0x79,0x68,0xf0,0x22,0xe4} }, +{ 5,0x41f8,0,{0x90,0x79,0x69,0xf0,0x22} }, +{ 16,0x41fd,0,{0x7b,0x01,0x7a,0x78,0x79,0x4c,0x90,0x78,0x06,0xeb,0xf0,0xa3,0xea,0xf0,0xa3,0xe9} }, +{ 16,0x420d,0,{0xf0,0xe4,0x12,0x0c,0x8a,0x90,0x78,0x06,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9} }, +{ 16,0x421d,0,{0x90,0x00,0x01,0x74,0x01,0x12,0x0c,0x9c,0x90,0x78,0x07,0xe4,0x75,0xf0,0x03,0x12} }, +{ 16,0x422d,0,{0x0c,0xf4,0x90,0x78,0x06,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0xe4,0x12,0x0c} }, +{ 16,0x423d,0,{0x8a,0x90,0x78,0x06,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74} }, +{ 16,0x424d,0,{0x02,0x12,0x0c,0x9c,0x90,0x78,0x07,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78} }, +{ 16,0x425d,0,{0x06,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0xe4,0x12,0x0c,0x8a,0x90,0x78,0x06} }, +{ 16,0x426d,0,{0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x03,0x12,0x0c,0x9c} }, +{ 16,0x427d,0,{0x90,0x78,0x07,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x90,0x78,0x06,0xe0,0xfb,0xa3} }, +{ 16,0x428d,0,{0xe0,0xfa,0xa3,0xe0,0xf9,0xe4,0x12,0x0c,0x8a,0x90,0x78,0x06,0xe0,0xfb,0xa3,0xe0} }, +{ 12,0x429d,0,{0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x74,0x04,0x12,0x0c,0x9c} }, +{ 1,0x42a9,0,{0x22} }, +{ 16,0x42aa,0,{0xe4,0xff,0xfe,0x7b,0x01,0x90,0x78,0x0c,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74} }, +{ 16,0x42ba,0,{0x2b,0xf0,0x90,0x78,0x0c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02} }, +{ 16,0x42ca,0,{0x12,0x0c,0x5d,0xfd,0x90,0x79,0x9a,0xe0,0x6d,0x60,0x13,0xef,0xc3,0x94,0x05,0x50} }, +{ 16,0x42da,0,{0x0d,0x0f,0x90,0x78,0x0d,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x80,0xd4,0x8d,0x33} }, +{ 16,0x42ea,0,{0x90,0x78,0x0c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x01,0x12,0x0c} }, +{ 16,0x42fa,0,{0x5d,0xfd,0x90,0x79,0x9b,0xe0,0xfc,0x6d,0x60,0x13,0xee,0xc3,0x94,0x0b,0x50,0x0d} }, +{ 16,0x430a,0,{0x0e,0x90,0x78,0x0d,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x80,0xd3,0x8c,0x34,0xef} }, +{ 16,0x431a,0,{0x64,0x05,0x60,0x03,0xbe,0x0b,0x08,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90} }, +{ 16,0x432a,0,{0x78,0x0c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x12,0x0c,0x44,0xff,0x24,0xf0} }, +{ 16,0x433a,0,{0x60,0x08,0x24,0x0e,0x70,0x0e,0x12,0x49,0x4d,0x22,0x90,0x79,0x20,0xe5,0x34,0xf0} }, +{ 11,0x434a,0,{0x12,0x1b,0x2a,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0} }, +{ 1,0x4355,0,{0x22} }, +{ 12,0x4356,0,{0x78,0x7f,0xe4,0xf6,0xd8,0xfd,0x75,0x81,0x3f,0x02,0x43,0x9d} }, +{ 16,0x4362,0,{0x02,0x48,0xa9,0xe4,0x93,0xa3,0xf8,0xe4,0x93,0xa3,0x40,0x03,0xf6,0x80,0x01,0xf2} }, +{ 16,0x4372,0,{0x08,0xdf,0xf4,0x80,0x29,0xe4,0x93,0xa3,0xf8,0x54,0x07,0x24,0x0c,0xc8,0xc3,0x33} }, +{ 16,0x4382,0,{0xc4,0x54,0x0f,0x44,0x20,0xc8,0x83,0x40,0x04,0xf4,0x56,0x80,0x01,0x46,0xf6,0xdf} }, +{ 16,0x4392,0,{0xe4,0x80,0x0b,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x90,0x46,0x61,0xe4,0x7e} }, +{ 16,0x43a2,0,{0x01,0x93,0x60,0xbc,0xa3,0xff,0x54,0x3f,0x30,0xe5,0x09,0x54,0x1f,0xfe,0xe4,0x93} }, +{ 16,0x43b2,0,{0xa3,0x60,0x01,0x0e,0xcf,0x54,0xc0,0x25,0xe0,0x60,0xa8,0x40,0xb8,0xe4,0x93,0xa3} }, +{ 16,0x43c2,0,{0xfa,0xe4,0x93,0xa3,0xf8,0xe4,0x93,0xa3,0xc8,0xc5,0x82,0xc8,0xca,0xc5,0x83,0xca} }, +{ 16,0x43d2,0,{0xf0,0xa3,0xc8,0xc5,0x82,0xc8,0xca,0xc5,0x83,0xca,0xdf,0xe9,0xde,0xe7,0x80,0xbe} }, +{ 16,0x43e2,0,{0xc0,0xe0,0xc0,0xf0,0xc0,0x83,0xc0,0x82,0xc0,0xd0,0xe8,0xc0,0xe0,0xe9,0xc0,0xe0} }, +{ 16,0x43f2,0,{0xea,0xc0,0xe0,0xeb,0xc0,0xe0,0xec,0xc0,0xe0,0xed,0xc0,0xe0,0xee,0xc0,0xe0,0xef} }, +{ 16,0x4402,0,{0xc0,0xe0,0xc2,0xca,0xc2,0xcf,0x90,0x79,0x7a,0xe0,0xb4,0x01,0x1f,0x12,0x4b,0xae} }, +{ 16,0x4412,0,{0x12,0x47,0x58,0x53,0xa8,0xa0,0x90,0x7f,0xae,0xe4,0xf0,0x12,0x07,0xaa,0x12,0x4b} }, +{ 16,0x4422,0,{0xb7,0x90,0x7f,0xae,0x74,0x1f,0xf0,0x43,0xa8,0x05,0x80,0x03,0x53,0xa8,0xa0,0x53} }, +{ 16,0x4432,0,{0xa8,0xfa,0x75,0xe8,0x01,0x12,0x09,0x15,0x75,0xe8,0x0d,0x43,0xa8,0x05,0xd0,0xe0} }, +{ 16,0x4442,0,{0xff,0xd0,0xe0,0xfe,0xd0,0xe0,0xfd,0xd0,0xe0,0xfc,0xd0,0xe0,0xfb,0xd0,0xe0,0xfa} }, +{ 16,0x4452,0,{0xd0,0xe0,0xf9,0xd0,0xe0,0xf8,0xd0,0xd0,0xd0,0x82,0xd0,0x83,0xd0,0xf0,0xd0,0xe0} }, +{ 1,0x4462,0,{0x32} }, +{ 16,0x4463,0,{0x90,0x7f,0xec,0xe0,0xf5,0x09,0x14,0x60,0x1d,0x14,0x60,0x2a,0x14,0x60,0x37,0x14} }, +{ 16,0x4473,0,{0x60,0x44,0x24,0x04,0x70,0x50,0x90,0x79,0x62,0xe0,0x90,0x7f,0x00,0xf0,0x90,0x7f} }, +{ 16,0x4483,0,{0xb5,0x74,0x01,0xf0,0x80,0x47,0x90,0x79,0x63,0xe0,0x90,0x7f,0x00,0xf0,0x90,0x7f} }, +{ 16,0x4493,0,{0xb5,0x74,0x01,0xf0,0x80,0x37,0x90,0x79,0x64,0xe0,0x90,0x7f,0x00,0xf0,0x90,0x7f} }, +{ 16,0x44a3,0,{0xb5,0x74,0x01,0xf0,0x80,0x27,0x90,0x79,0x66,0xe0,0x90,0x7f,0x00,0xf0,0x90,0x7f} }, +{ 16,0x44b3,0,{0xb5,0x74,0x01,0xf0,0x80,0x17,0x90,0x79,0x67,0xe0,0x90,0x7f,0x00,0xf0,0x90,0x7f} }, +{ 15,0x44c3,0,{0xb5,0x74,0x01,0xf0,0x80,0x07,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0xd3,0x22} }, +{ 4,0x44d2,0,{0x8d,0x36,0x8b,0x37} }, +{ 16,0x44d6,0,{0x12,0x3f,0xa2,0xea,0x49,0x60,0x57,0x12,0x0c,0x44,0x7e,0x00,0x29,0xff,0xee,0x3a} }, +{ 16,0x44e6,0,{0xc9,0xef,0xc9,0x75,0x38,0xff,0xf5,0x39,0x89,0x3a,0xab,0x38,0xaa,0x39,0xa9,0x3a} }, +{ 16,0x44f6,0,{0x90,0x00,0x01,0x12,0x0c,0x5d,0xff,0x64,0x04,0x60,0x05,0xef,0x64,0x05,0x70,0x2e} }, +{ 16,0x4506,0,{0xef,0xb4,0x04,0x15,0x90,0x00,0x02,0x12,0x0c,0x5d,0x65,0x36,0x70,0x0b,0x90,0x00} }, +{ 16,0x4516,0,{0x03,0x12,0x0c,0x5d,0x65,0x37,0x70,0x01,0x22,0x12,0x0c,0x44,0x7e,0x00,0x29,0xff} }, +{ 16,0x4526,0,{0xee,0x3a,0xc9,0xef,0xc9,0x75,0x38,0xff,0xf5,0x39,0x89,0x3a,0x80,0xbc,0x7b,0x00} }, +{ 4,0x4536,0,{0x7a,0x00,0x79,0x00} }, +{ 1,0x453a,0,{0x22} }, +{ 16,0x453b,0,{0xe4,0xff,0x7b,0x01,0x90,0x78,0x1c,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0x4c} }, +{ 16,0x454b,0,{0xf0,0x90,0x78,0x1c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02,0x12} }, +{ 16,0x455b,0,{0x0c,0x5d,0xfe,0x90,0x7f,0xec,0xe0,0x6e,0x60,0x13,0xef,0xc3,0x94,0x04,0x50,0x0d} }, +{ 16,0x456b,0,{0x90,0x78,0x1d,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x0f,0x80,0xd4,0xbf,0x04,0x09} }, +{ 16,0x457b,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x80,0x14,0x90,0x79,0x21,0xe0,0xff,0x90,0x78} }, +{ 16,0x458b,0,{0x1c,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0xef,0x12,0x0c,0x8a,0x90,0x7f,0xc5} }, +{ 3,0x459b,0,{0x74,0x01,0xf0} }, +{ 1,0x459e,0,{0x22} }, +{ 14,0x459f,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0xc0,0xd0,0xee,0xc0,0xe0,0xef,0xc0,0xe0} }, +{ 16,0x45ad,0,{0x90,0x79,0x85,0xe0,0x64,0x01,0x60,0x05,0xa3,0xe0,0xb4,0x01,0x2d,0x90,0x79,0x87} }, +{ 16,0x45bd,0,{0x74,0x01,0xf0,0xe4,0xff,0x90,0x7f,0xc5,0xe0,0xfe,0xef,0xc3,0x9e,0x50,0x1b,0x74} }, +{ 16,0x45cd,0,{0xc0,0x2f,0xf5,0x82,0xe4,0x34,0x7e,0xf5,0x83,0xe0,0xfe,0x74,0x21,0x2f,0xf5,0x82} }, +{ 16,0x45dd,0,{0xe4,0x34,0x79,0xf5,0x83,0xee,0xf0,0x0f,0x80,0xdb,0x53,0x91,0xef,0x90,0x7f,0xaa} }, +{ 4,0x45ed,0,{0xe0,0x44,0x01,0xf0} }, +{ 15,0x45f1,0,{0xd0,0xe0,0xff,0xd0,0xe0,0xfe,0xd0,0xd0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4600,0,{0xe4,0xff,0x7b,0x01,0x90,0x78,0x19,0x04,0xf0,0xa3,0x74,0x78,0xf0,0xa3,0x74,0x4c} }, +{ 16,0x4610,0,{0xf0,0x90,0x78,0x19,0xe0,0xfb,0xa3,0xe0,0xfa,0xa3,0xe0,0xf9,0x90,0x00,0x02,0x12} }, +{ 16,0x4620,0,{0x0c,0x5d,0xfe,0x90,0x7f,0xec,0xe0,0x6e,0x60,0x13,0xef,0xc3,0x94,0x04,0x50,0x0d} }, +{ 16,0x4630,0,{0x90,0x78,0x1a,0xe4,0x75,0xf0,0x03,0x12,0x0c,0xf4,0x0f,0x80,0xd4,0xbf,0x04,0x08} }, +{ 16,0x4640,0,{0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x78,0x19,0xe0,0xfb,0xa3,0xe0,0xfa} }, +{ 16,0x4650,0,{0xa3,0xe0,0xf9,0x12,0x0c,0x44,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, +{ 1,0x4660,0,{0x22} }, +{ 16,0x4661,0,{0x01,0x18,0x02,0x01,0x19,0x0a,0x01,0x1c,0x00,0xc1,0x28,0xc1,0x29,0x01,0x1f,0x01} }, +{ 15,0x4671,0,{0x44,0x79,0x9f,0x00,0x00,0x00,0x00,0x41,0x79,0xa3,0x00,0x41,0x79,0xa4,0x00} }, +{ 4,0x4680,0,{0x41,0x79,0x89,0x00} }, +{ 16,0x4684,0,{0x01,0x22,0x01,0x41,0x79,0x31,0xff,0x41,0x79,0x34,0x00,0x4d,0x79,0x35,0x3f,0x3f} }, +{ 16,0x4694,0,{0x00,0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x4d,0x79,0x42,0x3f,0x3f} }, +{ 16,0x46a4,0,{0x06,0x08,0x04,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x4d,0x79,0x4f,0x0a,0x0a} }, +{ 11,0x46b4,0,{0x09,0x00,0x01,0x09,0x02,0x03,0x04,0x05,0x06,0x07,0x08} }, +{ 1,0x46bf,0,{0x00} }, +{ 16,0x46c0,0,{0x12,0x0a,0xcd,0x90,0x7f,0xa5,0xe0,0xf5,0x21,0xe5,0x21,0x54,0x01,0xf5,0x21,0x64} }, +{ 16,0x46d0,0,{0x01,0x60,0x28,0xe5,0x22,0x64,0x01,0x70,0x22,0x90,0x7f,0xa5,0xe0,0xf5,0x21,0x54} }, +{ 16,0x46e0,0,{0x02,0xf5,0x21,0x70,0x03,0x75,0x22,0x01,0x90,0x7f,0xa5,0xe0,0xf5,0x21,0x54,0x04} }, +{ 12,0x46f0,0,{0xff,0xf5,0x21,0xbf,0x04,0xd3,0x75,0x22,0x01,0x80,0xce,0x22} }, +{ 4,0x46fc,0,{0x53,0xd8,0xf7,0x32} }, +{ 16,0x4700,0,{0x02,0x49,0xfa,0x00,0x02,0x3c,0x54,0x00,0x02,0x17,0xe4,0x00,0x02,0x4a,0x12,0x00} }, +{ 16,0x4710,0,{0x02,0x37,0xa2,0x00,0x02,0x47,0xff,0x00,0x02,0x4a,0x41,0x00,0x02,0x45,0x9f,0x00} }, +{ 16,0x4720,0,{0x02,0x49,0x8e,0x00,0x02,0x49,0xab,0x00,0x02,0x4a,0x58,0x00,0x02,0x4a,0x6f,0x00} }, +{ 16,0x4730,0,{0x02,0x4a,0x86,0x00,0x02,0x4a,0x9d,0x00,0x02,0x4a,0xb4,0x00,0x02,0x4a,0xcb,0x00} }, +{ 16,0x4740,0,{0x02,0x4a,0xe2,0x00,0x02,0x4a,0xf9,0x00,0x02,0x4b,0x10,0x00,0x02,0x4b,0x27,0x00} }, +{ 8,0x4750,0,{0x02,0x4b,0x3e,0x00,0x02,0x4b,0x55,0x00} }, +{ 16,0x4758,0,{0xe5,0x18,0x70,0x14,0x90,0x79,0x8c,0xe0,0x04,0xf0,0x90,0x79,0x8b,0xe0,0xc3,0x94} }, +{ 16,0x4768,0,{0x00,0x40,0x15,0xe0,0x14,0xf0,0x80,0x10,0x90,0x79,0x8b,0xe0,0x04,0xf0,0xa3,0xe0} }, +{ 16,0x4778,0,{0xc3,0x94,0x00,0x40,0x03,0xe0,0x14,0xf0,0x90,0x79,0x8b,0xe0,0xd3,0x94,0x14,0x40} }, +{ 16,0x4788,0,{0x04,0xe4,0xf5,0x18,0xf0,0x90,0x79,0x8c,0xe0,0xd3,0x94,0x14,0x40,0x05,0x75,0x18} }, +{ 4,0x4798,0,{0x01,0xe4,0xf0,0x22} }, +{ 16,0x479c,0,{0x90,0x7f,0xd7,0xe0,0xf5,0x33,0x90,0x7f,0xec,0xe0,0xf5,0x09,0x14,0x60,0x11,0x14} }, +{ 16,0x47ac,0,{0x60,0x1b,0x24,0x02,0x70,0x24,0x90,0x7f,0xea,0xe0,0x90,0x79,0x62,0xf0,0x80,0x21} }, +{ 16,0x47bc,0,{0x90,0x7f,0xea,0xe0,0x90,0x79,0x63,0xf0,0x12,0x10,0x00,0x80,0x14,0x90,0x7f,0xea} }, +{ 16,0x47cc,0,{0xe0,0x90,0x79,0x64,0xf0,0x12,0x28,0x01,0x80,0x07,0x90,0x7f,0xb4,0xe0,0x44,0x01} }, +{ 2,0x47dc,0,{0xf0,0xd3} }, +{ 1,0x47de,0,{0x22} }, +{ 16,0x47df,0,{0x90,0x79,0x78,0x74,0x04,0xf0,0x90,0x79,0x33,0xe0,0x90,0x79,0x79,0xf0,0xa2,0xaf} }, +{ 16,0x47ef,0,{0xe4,0x33,0xf5,0x12,0xc2,0xaf,0x12,0x0b,0xa2,0xe5,0x12,0x60,0x02,0xd2,0xaf,0x22} }, +{ 1,0x47ff,0,{0x32} }, +{ 2,0x4800,0,{0x8f,0x36} }, +{ 16,0x4802,0,{0xe4,0xf5,0x37,0x75,0x38,0xff,0x75,0x39,0x07,0x75,0x3a,0x01,0xab,0x38,0xaa,0x39} }, +{ 16,0x4812,0,{0xa9,0x3a,0x90,0x00,0x01,0x12,0x0c,0x5d,0xb4,0x03,0x1f,0xaf,0x37,0x05,0x37,0xef} }, +{ 16,0x4822,0,{0x65,0x36,0x70,0x01,0x22,0x12,0x0c,0x44,0x7e,0x00,0x29,0xff,0xee,0x3a,0xc9,0xef} }, +{ 16,0x4832,0,{0xc9,0x75,0x38,0xff,0xf5,0x39,0x89,0x3a,0x80,0xd2,0x7b,0x00,0x7a,0x00,0x79,0x00} }, +{ 1,0x4842,0,{0x22} }, +{ 16,0x4843,0,{0x30,0x26,0x2f,0xc2,0x26,0x90,0x79,0x2d,0xe0,0xff,0xb4,0x01,0x09,0xe4,0xf5,0x0c} }, +{ 16,0x4853,0,{0x75,0x0d,0xf8,0x75,0x0e,0x0a,0xef,0xb4,0x02,0x09,0xe4,0xf5,0x0c,0x75,0x0d,0xf0} }, +{ 16,0x4863,0,{0x75,0x0e,0x0b,0xef,0xb4,0x03,0x09,0xe4,0xf5,0x0c,0x75,0x0d,0xf8,0x75,0x0e,0x17} }, +{ 3,0x4873,0,{0xd2,0x22,0x22} }, +{ 16,0x4876,0,{0x30,0x25,0x2f,0xc2,0x25,0x90,0x79,0x2d,0xe0,0xff,0xb4,0x01,0x09,0x75,0x0c,0xc0} }, +{ 16,0x4886,0,{0x75,0x0d,0x14,0x75,0x0e,0x0b,0xef,0xb4,0x02,0x09,0xe4,0xf5,0x0c,0x75,0x0d,0x10} }, +{ 16,0x4896,0,{0x75,0x0e,0x0c,0xef,0xb4,0x03,0x09,0xe4,0xf5,0x0c,0x75,0x0d,0x18,0x75,0x0e,0x18} }, +{ 3,0x48a6,0,{0xd2,0x22,0x22} }, +{ 16,0x48a9,0,{0xe4,0xf5,0x32,0x12,0x0f,0x50,0x20,0x2e,0x10,0xe5,0x32,0xc3,0x94,0x02,0x50,0x09} }, +{ 16,0x48b9,0,{0x05,0x32,0xd2,0x30,0x12,0x49,0x05,0x80,0xed,0x30,0x2e,0x05,0x12,0x14,0x57,0xc2} }, +{ 15,0x48c9,0,{0x2e,0x30,0x2d,0x06,0x12,0x07,0x9a,0x12,0x48,0xd9,0x12,0x40,0x00,0x80,0xea} }, +{ 1,0x48d8,0,{0x22} }, +{ 16,0x48d9,0,{0x90,0x7f,0xd6,0xe0,0xf5,0x1d,0x54,0x80,0xf5,0x1d,0x64,0x80,0x70,0x1d,0xc2,0xaf} }, +{ 16,0x48e9,0,{0xe0,0x44,0x80,0xf0,0xe0,0x44,0x01,0xf0,0x7f,0x0c,0x7e,0x00,0x12,0x4b,0x6c,0x90} }, +{ 12,0x48f9,0,{0x7f,0xd6,0xe0,0x54,0xfe,0xf0,0x53,0x87,0xfe,0xd2,0xaf,0x22} }, +{ 16,0x4905,0,{0x90,0x7f,0xd6,0xe0,0x54,0xfb,0xf0,0xe0,0x44,0x08,0xf0,0x30,0x30,0x04,0xe0,0x44} }, +{ 16,0x4915,0,{0x02,0xf0,0x7f,0xdc,0x7e,0x05,0x12,0x4b,0x6c,0x90,0x7f,0xd6,0xe0,0x54,0xf7,0xf0} }, +{ 5,0x4925,0,{0xe0,0x44,0x04,0xf0,0x22} }, +{ 16,0x492a,0,{0x90,0x7f,0xeb,0xe0,0x14,0x70,0x14,0x90,0x7f,0xe9,0xe0,0x24,0x7f,0x70,0x04,0x12} }, +{ 16,0x493a,0,{0x46,0x00,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44} }, +{ 3,0x494a,0,{0x01,0xf0,0x22} }, +{ 16,0x494d,0,{0x90,0x7f,0xeb,0xe0,0x14,0x70,0x13,0x90,0x7f,0xe9,0xe0,0x14,0x70,0x04,0x12,0x45} }, +{ 16,0x495d,0,{0x3b,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x22,0x90,0x7f,0xb4,0xe0,0x44,0x01} }, +{ 2,0x496d,0,{0xf0,0x22} }, +{ 16,0x496f,0,{0xe4,0xff,0x74,0xe8,0x2f,0xf5,0x82,0xe4,0x34,0x7f,0xf5,0x83,0xe0,0xfe,0x74,0x96} }, +{ 14,0x497f,0,{0x2f,0xf5,0x82,0xe4,0x34,0x79,0xf5,0x83,0xee,0xf0,0x0f,0xbf,0x08,0xe4} }, +{ 1,0x498d,0,{0x22} }, +{ 16,0x498e,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x02,0xf0} }, +{ 13,0x499e,0,{0x90,0x7f,0xb7,0x74,0x03,0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x49ab,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x02,0xf0} }, +{ 13,0x49bb,0,{0x90,0x7f,0xc7,0x74,0x03,0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x49c8,0,{0x90,0x7f,0xd6,0xe0,0x30,0xe7,0x12,0xe0,0x44,0x01,0xf0,0x7f,0x14,0x7e,0x00,0x12} }, +{ 10,0x49d8,0,{0x4b,0x6c,0x90,0x7f,0xd6,0xe0,0x54,0xfe,0xf0,0x22} }, +{ 16,0x49e2,0,{0xe4,0xf5,0x1a,0x75,0x1b,0x01,0x90,0x79,0x91,0x04,0xf0,0xa3,0xf0,0xe4,0xa3,0xf0} }, +{ 8,0x49f2,0,{0xa3,0x74,0x0a,0xf0,0xe4,0xa3,0xf0,0x22} }, +{ 16,0x49fa,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0xd2,0x2e,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x01} }, +{ 8,0x4a0a,0,{0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a12,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0xd2,0x2d,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x08} }, +{ 8,0x4a22,0,{0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a2a,0,{0x90,0x7f,0xea,0xe0,0xf5,0x08,0xe4,0x90,0x79,0x62,0xf0,0xa3,0xf0,0xa3,0xf0,0x90} }, +{ 7,0x4a3a,0,{0x79,0x66,0xf0,0xa3,0xf0,0xd3,0x22} }, +{ 16,0x4a41,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x01,0xf0} }, +{ 7,0x4a51,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a58,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x04,0xf0} }, +{ 7,0x4a68,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a6f,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x04,0xf0} }, +{ 7,0x4a7f,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a86,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x08,0xf0} }, +{ 7,0x4a96,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4a9d,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x08,0xf0} }, +{ 7,0x4aad,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4ab4,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x10,0xf0} }, +{ 7,0x4ac4,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4acb,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x10,0xf0} }, +{ 7,0x4adb,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4ae2,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x20,0xf0} }, +{ 7,0x4af2,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4af9,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x20,0xf0} }, +{ 7,0x4b09,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4b10,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x40,0xf0} }, +{ 7,0x4b20,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4b27,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x40,0xf0} }, +{ 7,0x4b37,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4b3e,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xa9,0xe0,0x44,0x80,0xf0} }, +{ 7,0x4b4e,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4b55,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xaa,0xe0,0x44,0x80,0xf0} }, +{ 7,0x4b65,0,{0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x4b6c,0,{0x8e,0x33,0x8f,0x34,0xe5,0x34,0x15,0x34,0xae,0x33,0x70,0x02,0x15,0x33,0x4e,0x60} }, +{ 7,0x4b7c,0,{0x05,0x12,0x07,0x89,0x80,0xee,0x22} }, +{ 15,0x4b83,0,{0x90,0x7f,0xea,0xe0,0xb4,0xff,0x04,0x12,0x30,0x00,0x22,0x12,0x36,0x0e,0x22} }, +{ 14,0x4b92,0,{0xc0,0xe0,0xc2,0x8b,0xd2,0x24,0x30,0x23,0x02,0xc2,0x23,0xd0,0xe0,0x32} }, +{ 14,0x4ba0,0,{0x90,0x7f,0x00,0xe5,0x08,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0,0xd3,0x22} }, +{ 9,0x4bae,0,{0x30,0x24,0x05,0xc2,0x24,0x75,0x18,0x01,0x22} }, +{ 9,0x4bb7,0,{0x30,0x23,0x05,0xc2,0x23,0xe4,0xf5,0x18,0x22} }, +{ 7,0x4bc0,0,{0x53,0xc0,0xfe,0x53,0xc0,0xfd,0x32} }, +{ 6,0x4bc7,0,{0x53,0x91,0x7f,0xd2,0x25,0x32} }, +{ 5,0x4bcd,0,{0xc2,0x89,0xd2,0x23,0x32} }, +{ 3,0x4bd2,0,{0xc2,0x8d,0x32} }, +{ 3,0x4bd5,0,{0xc2,0x8f,0x32} }, +{ 2,0x4bd8,0,{0xd3,0x22} }, +{ 2,0x4bda,0,{0xd3,0x22} }, +{ 2,0x4bdc,0,{0xd3,0x22} }, +{ 2,0x4bde,0,{0xd3,0x22} }, +{ 2,0x4be0,0,{0xd3,0x22} }, +{ 2,0x4be2,0,{0xd3,0x22} }, +{ 2,0x4be4,0,{0xc3,0x22} }, +{ 1,0x4be6,0,{0x22} }, +{ 0,0x0000,1,{0 }} +}; +/* +VERSION=1.0.2.916 +DATE=12.02.2002 +*/ +/* + * This firmware is for the Emagic EMI 2|6 Audio Interface + * + * The firmware contained herein is Copyright (c) 1999-2002 Emagic + * as an unpublished work. This notice does not imply unrestricted + * or public access to this firmware which is a trade secret of Emagic, + * and which may not be reproduced, used, sold or transferred to + * any third party without Emagic's written consent. All Rights Reserved. + * + * This firmware may not be modified and may only be used with the + * Emagic EMI 2|6 Audio Interface. Distribution and/or Modification of + * any driver which includes this firmware, in whole or in part, + * requires the inclusion of this statement. + */ +INTEL_HEX_RECORD g_Loader[] = { +{ 3,0x0000,0,{0x02,0x03,0x1c} }, +{ 3,0x0043,0,{0x02,0x04,0x00} }, +{ 16,0x0100,0,{0x90,0x7f,0xe9,0xe0,0x24,0x5b,0x60,0x60,0x24,0x02,0x60,0x03,0x02,0x01,0xbe,0x90} }, +{ 16,0x0110,0,{0x7f,0xea,0xe0,0x75,0x0a,0x00,0xf5,0x0b,0xa3,0xe0,0xfe,0xe4,0xee,0x42,0x0a,0x90} }, +{ 16,0x0120,0,{0x7f,0xee,0xe0,0x75,0x15,0x00,0xf5,0x16,0xa3,0xe0,0xfe,0xe4,0xee,0x42,0x15,0xe5} }, +{ 16,0x0130,0,{0x16,0x45,0x15,0x70,0x03,0x02,0x01,0xbe,0xe4,0x90,0x7f,0xc5,0xf0,0x90,0x7f,0xb4} }, +{ 16,0x0140,0,{0xe0,0x20,0xe3,0xf9,0x90,0x7f,0xc5,0xe0,0xf5,0x0c,0x12,0x02,0x77,0xaf,0x0c,0x7e} }, +{ 16,0x0150,0,{0x00,0xef,0x25,0x0b,0xf5,0x0b,0xee,0x35,0x0a,0xf5,0x0a,0xc3,0xe5,0x16,0x9f,0xf5} }, +{ 16,0x0160,0,{0x16,0xe5,0x15,0x9e,0xf5,0x15,0x80,0xc7,0x90,0x7f,0xea,0xe0,0x75,0x0a,0x00,0xf5} }, +{ 16,0x0170,0,{0x0b,0xa3,0xe0,0xfe,0xe4,0xee,0x42,0x0a,0x90,0x7f,0xee,0xe0,0x75,0x15,0x00,0xf5} }, +{ 16,0x0180,0,{0x16,0xa3,0xe0,0xfe,0xe4,0xee,0x42,0x15,0xe5,0x16,0x45,0x15,0x60,0x30,0xe4,0x90} }, +{ 16,0x0190,0,{0x7f,0xc5,0xf0,0x90,0x7f,0xb4,0xe0,0x20,0xe3,0xf9,0x90,0x7f,0xc5,0xe0,0xf5,0x0c} }, +{ 16,0x01a0,0,{0x12,0x02,0x8f,0xaf,0x0c,0x7e,0x00,0xef,0x25,0x0b,0xf5,0x0b,0xee,0x35,0x0a,0xf5} }, +{ 15,0x01b0,0,{0x0a,0xc3,0xe5,0x16,0x9f,0xf5,0x16,0xe5,0x15,0x9e,0xf5,0x15,0x80,0xca,0xc3} }, +{ 1,0x01bf,0,{0x22} }, +{ 16,0x01c0,0,{0xc2,0x20,0xd2,0xe8,0x43,0xd8,0x20,0x90,0x7f,0xab,0x74,0xff,0xf0,0x90,0x7f,0xa9} }, +{ 16,0x01d0,0,{0xf0,0x90,0x7f,0xaa,0xf0,0x53,0x91,0xef,0x90,0x7f,0x95,0xe0,0x44,0xc0,0xf0,0x90} }, +{ 16,0x01e0,0,{0x7f,0x98,0xe0,0x44,0xc0,0xf0,0x90,0x7f,0x9e,0xe0,0x44,0xc0,0xf0,0xe4,0x90,0x7f} }, +{ 16,0x01f0,0,{0x94,0xf0,0x90,0x7f,0x9d,0xe0,0x44,0x0f,0xf0,0x90,0x7f,0x97,0xe0,0x54,0xf0,0xf0} }, +{ 16,0x0200,0,{0x90,0x7f,0xaf,0xe0,0x44,0x01,0xf0,0x90,0x7f,0xae,0xe0,0x44,0x0d,0xf0,0xd2,0xaf} }, +{ 16,0x0210,0,{0x90,0x7f,0x97,0xe0,0x54,0xf0,0xf0,0x20,0x20,0x42,0x75,0x14,0x00,0x75,0x13,0x00} }, +{ 16,0x0220,0,{0x75,0x12,0x00,0x75,0x11,0x00,0x7f,0x48,0x7e,0x92,0x7d,0x00,0x7c,0x00,0xab,0x14} }, +{ 16,0x0230,0,{0xaa,0x13,0xa9,0x12,0xa8,0x11,0xc3,0x12,0x04,0x9a,0x50,0xdb,0x20,0x20,0xd8,0x7a} }, +{ 16,0x0240,0,{0x00,0x79,0x00,0x78,0x00,0xe5,0x14,0x24,0x01,0xf5,0x14,0xea,0x35,0x13,0xf5,0x13} }, +{ 16,0x0250,0,{0xe9,0x35,0x12,0xf5,0x12,0xe8,0x35,0x11,0xf5,0x11,0x80,0xca,0x30,0x20,0xfd,0x12} }, +{ 16,0x0260,0,{0x01,0x00,0x50,0x07,0x90,0x7f,0xb4,0xe0,0x44,0x01,0xf0,0x90,0x7f,0xb4,0xe0,0x44} }, +{ 6,0x0270,0,{0x02,0xf0,0xc2,0x20,0x80,0xe6} }, +{ 1,0x0276,0,{0x22} }, +{ 16,0x0277,0,{0xe5,0x0c,0xff,0xe5,0x0b,0xf5,0x82,0xe5,0x0a,0xf5,0x83,0x75,0x92,0x7e,0x74,0xc0} }, +{ 8,0x0287,0,{0xf8,0xe2,0x08,0xf0,0xa3,0xdf,0xfa,0x22} }, +{ 16,0x028f,0,{0x90,0x7f,0x96,0x85,0x83,0x92,0xa8,0x82,0x79,0x02,0x90,0x00,0x00,0xe0,0xb4,0x00} }, +{ 16,0x029f,0,{0x37,0x74,0x01,0xf0,0x90,0x7f,0x93,0xe0,0x54,0xfc,0xf0,0x90,0x7f,0x96,0xe0,0x54} }, +{ 16,0x02af,0,{0xfc,0xf0,0x90,0x7f,0x9c,0xe0,0x44,0x03,0xf0,0x90,0x7f,0x94,0xe0,0x54,0x7f,0xf0} }, +{ 16,0x02bf,0,{0x90,0x7f,0x97,0xe0,0x44,0x80,0xf0,0x90,0x7f,0x9d,0xe0,0x44,0x80,0xf0,0x90,0x7f} }, +{ 16,0x02cf,0,{0x97,0xe0,0x54,0x7f,0xf0,0x44,0x80,0xf0,0xe5,0x0c,0xff,0x90,0x7e,0xc0,0xe0,0xf5} }, +{ 16,0x02df,0,{0x28,0xe4,0xa2,0x47,0x33,0xf2,0x69,0xf2,0xe4,0xa2,0x46,0x33,0xf2,0x69,0xf2,0xe4} }, +{ 16,0x02ef,0,{0xa2,0x45,0x33,0xf2,0x69,0xf2,0xe4,0xa2,0x44,0x33,0xf2,0x69,0xf2,0xe4,0xa2,0x43} }, +{ 16,0x02ff,0,{0x33,0xf2,0x69,0xf2,0xe4,0xa2,0x42,0x33,0xf2,0x69,0xf2,0xe4,0xa2,0x41,0x33,0xf2} }, +{ 13,0x030f,0,{0x69,0xf2,0xe4,0xa2,0x40,0x33,0xf2,0x69,0xf2,0xa3,0xdf,0xc2,0x22} }, +{ 12,0x031c,0,{0x78,0x7f,0xe4,0xf6,0xd8,0xfd,0x75,0x81,0x29,0x02,0x03,0x63} }, +{ 16,0x0328,0,{0x02,0x01,0xc0,0xe4,0x93,0xa3,0xf8,0xe4,0x93,0xa3,0x40,0x03,0xf6,0x80,0x01,0xf2} }, +{ 16,0x0338,0,{0x08,0xdf,0xf4,0x80,0x29,0xe4,0x93,0xa3,0xf8,0x54,0x07,0x24,0x0c,0xc8,0xc3,0x33} }, +{ 16,0x0348,0,{0xc4,0x54,0x0f,0x44,0x20,0xc8,0x83,0x40,0x04,0xf4,0x56,0x80,0x01,0x46,0xf6,0xdf} }, +{ 16,0x0358,0,{0xe4,0x80,0x0b,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x90,0x04,0x84,0xe4,0x7e} }, +{ 16,0x0368,0,{0x01,0x93,0x60,0xbc,0xa3,0xff,0x54,0x3f,0x30,0xe5,0x09,0x54,0x1f,0xfe,0xe4,0x93} }, +{ 16,0x0378,0,{0xa3,0x60,0x01,0x0e,0xcf,0x54,0xc0,0x25,0xe0,0x60,0xa8,0x40,0xb8,0xe4,0x93,0xa3} }, +{ 16,0x0388,0,{0xfa,0xe4,0x93,0xa3,0xf8,0xe4,0x93,0xa3,0xc8,0xc5,0x82,0xc8,0xca,0xc5,0x83,0xca} }, +{ 16,0x0398,0,{0xf0,0xa3,0xc8,0xc5,0x82,0xc8,0xca,0xc5,0x83,0xca,0xdf,0xe9,0xde,0xe7,0x80,0xbe} }, +{ 16,0x03a8,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x90,0x7f,0xc4,0xe4,0xf0,0x53,0x91,0xef,0x90,0x7f} }, +{ 11,0x03b8,0,{0xab,0x74,0x04,0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x03c3,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0xd2,0x20,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x01} }, +{ 8,0x03d3,0,{0xf0,0xd0,0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x03db,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x02,0xf0,0xd0} }, +{ 6,0x03eb,0,{0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 1,0x03f1,0,{0x32} }, +{ 1,0x03f2,0,{0x32} }, +{ 1,0x03f3,0,{0x32} }, +{ 1,0x03f4,0,{0x32} }, +{ 1,0x03f5,0,{0x32} }, +{ 1,0x03f6,0,{0x32} }, +{ 1,0x03f7,0,{0x32} }, +{ 1,0x03f8,0,{0x32} }, +{ 1,0x03f9,0,{0x32} }, +{ 1,0x03fa,0,{0x32} }, +{ 1,0x03fb,0,{0x32} }, +{ 1,0x03fc,0,{0x32} }, +{ 1,0x03fd,0,{0x32} }, +{ 1,0x03fe,0,{0x32} }, +{ 1,0x03ff,0,{0x32} }, +{ 16,0x0400,0,{0x02,0x03,0xc3,0x00,0x02,0x03,0xdb,0x00,0x02,0x03,0xa8,0x00,0x02,0x04,0x6e,0x00} }, +{ 16,0x0410,0,{0x02,0x04,0x58,0x00,0x02,0x03,0xf1,0x00,0x02,0x03,0xf2,0x00,0x02,0x03,0xf3,0x00} }, +{ 16,0x0420,0,{0x02,0x03,0xf4,0x00,0x02,0x03,0xf5,0x00,0x02,0x03,0xf6,0x00,0x02,0x03,0xf7,0x00} }, +{ 16,0x0430,0,{0x02,0x03,0xf8,0x00,0x02,0x03,0xf9,0x00,0x02,0x03,0xfa,0x00,0x02,0x03,0xfb,0x00} }, +{ 16,0x0440,0,{0x02,0x03,0xfc,0x00,0x02,0x03,0xfd,0x00,0x02,0x03,0xfe,0x00,0x02,0x03,0xff,0x00} }, +{ 8,0x0450,0,{0x02,0x04,0xab,0x00,0x02,0x04,0xac,0x00} }, +{ 16,0x0458,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x10,0xf0,0xd0} }, +{ 6,0x0468,0,{0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x046e,0,{0xc0,0xe0,0xc0,0x83,0xc0,0x82,0x53,0x91,0xef,0x90,0x7f,0xab,0x74,0x08,0xf0,0xd0} }, +{ 6,0x047e,0,{0x82,0xd0,0x83,0xd0,0xe0,0x32} }, +{ 16,0x0484,0,{0x02,0x0a,0x00,0x0f,0x01,0x0c,0x11,0x04,0x0d,0x00,0x00,0x00,0x00,0x41,0x00,0x00} }, +{ 1,0x0494,0,{0x00} }, +{ 4,0x0495,0,{0x02,0x17,0x00,0x00} }, +{ 1,0x0499,0,{0x00} }, +{ 16,0x049a,0,{0xeb,0x9f,0xf5,0xf0,0xea,0x9e,0x42,0xf0,0xe9,0x9d,0x42,0xf0,0xe8,0x9c,0x45,0xf0} }, +{ 1,0x04aa,0,{0x22} }, +{ 1,0x04ab,0,{0x32} }, +{ 1,0x04ac,0,{0x32} }, +{ 16,0x1100,0,{0x12,0x01,0x10,0x01,0x00,0x00,0x00,0x40,0x6a,0x08,0x01,0x01,0x00,0x01,0x01,0x02} }, +{ 16,0x1110,0,{0x00,0x01,0x09,0x02,0x20,0x00,0x01,0x01,0x03,0xa0,0x00,0x09,0x04,0x00,0x00,0x02} }, +{ 16,0x1120,0,{0xff,0x00,0x00,0x04,0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40} }, +{ 16,0x1130,0,{0x00,0x00,0x04,0x03,0x09,0x04,0x26,0x03,0x41,0x00,0x6e,0x00,0x63,0x00,0x68,0x00} }, +{ 16,0x1140,0,{0x6f,0x00,0x72,0x00,0x20,0x00,0x43,0x00,0x68,0x00,0x69,0x00,0x70,0x00,0x73,0x00} }, +{ 16,0x1150,0,{0x2c,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x28,0x03,0x46,0x00} }, +{ 16,0x1160,0,{0x69,0x00,0x72,0x00,0x6d,0x00,0x77,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x20,0x00} }, +{ 16,0x1170,0,{0x46,0x00,0x72,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x57,0x00,0x6f,0x00,0x72,0x00} }, +{ 16,0x1180,0,{0x6b,0x00,0x73,0x00,0x2a,0x03,0x43,0x00,0x6f,0x00,0x6e,0x00,0x66,0x00,0x69,0x00} }, +{ 16,0x1190,0,{0x67,0x00,0x75,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00} }, +{ 16,0x11a0,0,{0x20,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x67,0x00,0x22,0x03} }, +{ 16,0x11b0,0,{0x49,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x66,0x00,0x61,0x00,0x63,0x00} }, +{ 16,0x11c0,0,{0x65,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x67,0x00} }, +{ 2,0x11d0,0,{0x00,0x00} }, +{ 0,0x0000,1,{0 }} +}; diff -urN linux-2.4.18/drivers/usb/hcd/Config.in linux-2.4.19-pre5/drivers/usb/hcd/Config.in --- linux-2.4.18/drivers/usb/hcd/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/Config.in Sat Mar 30 22:55:29 2002 @@ -0,0 +1,7 @@ +# +# USB Host Controller Drivers +# +dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL +# dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL +# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL + diff -urN linux-2.4.18/drivers/usb/hcd/Makefile linux-2.4.19-pre5/drivers/usb/hcd/Makefile --- linux-2.4.18/drivers/usb/hcd/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/Makefile Sat Mar 30 22:55:29 2002 @@ -0,0 +1,27 @@ +# +# Makefile for USB Host Controller Driver +# framework and drivers +# + +O_TARGET := + +obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o +# obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o +# obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o + +# 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))) + +# 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. +OX_OBJS := $(obj-y) +MX_OBJS := $(obj-m) +MIX_OBJS := $(int-m) + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/usb/hcd/ehci-dbg.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-dbg.c --- linux-2.4.18/drivers/usb/hcd/ehci-dbg.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-dbg.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + +#ifdef EHCI_VERBOSE_DEBUG +# define vdbg dbg +#else + static inline void vdbg (char *fmt, ...) { } +#endif + +#ifdef DEBUG + +/* check the values in the HCSPARAMS register - host controller structural parameters */ +/* see EHCI 0.95 Spec, Table 2-4 for each value */ +static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) +{ + u32 params = readl (&ehci->caps->hcs_params); + + dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d", + label, params, + HCS_DEBUG_PORT (params), + HCS_INDICATOR (params) ? " ind" : "", + HCS_N_CC (params), + HCS_N_PCC (params), + HCS_PORTROUTED (params) ? "" : " ordered", + HCS_PPC (params) ? "" : " !ppc", + HCS_N_PORTS (params) + ); + /* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */ + if (HCS_PORTROUTED (params)) { + int i; + char buf [46], tmp [7], byte; + + buf[0] = 0; + for (i = 0; i < HCS_N_PORTS (params); i++) { + byte = readb (&ehci->caps->portroute[(i>>1)]); + sprintf(tmp, "%d ", + ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf))); + strcat(buf, tmp); + } + dbg ("%s: %s portroute %s", + ehci->hcd.bus_name, label, + buf); + } +} +#else + +static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} + +#endif + +#ifdef DEBUG + +/* check the values in the HCCPARAMS register - host controller capability parameters */ +/* see EHCI 0.95 Spec, Table 2-5 for each value */ +static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) +{ + u32 params = readl (&ehci->caps->hcc_params); + + if (HCC_EXT_CAPS (params)) { + // EHCI 0.96 ... could interpret these (legacy?) + dbg ("%s extended capabilities at pci %d", + label, HCC_EXT_CAPS (params)); + } + if (HCC_ISOC_CACHE (params)) { + dbg ("%s hcc_params 0x%04x caching frame %s%s%s", + label, params, + HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", + HCC_CANPARK (params) ? " park" : "", + HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); + } else { + dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s", + label, + params, + HCC_ISOC_THRES (params), + HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", + HCC_CANPARK (params) ? " park" : "", + HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); + } +} +#else + +static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} + +#endif + +#ifdef DEBUG + +#if 0 +static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label, + qh, qh->hw_info1, qh->hw_info2, + qh->hw_current, qh->hw_qtd_next); + dbg (" alt+errs= %x, token= %x, page0= %x, page1= %x", + qh->hw_alt_next, qh->hw_token, + qh->hw_buf [0], qh->hw_buf [1]); + if (qh->hw_buf [2]) { + dbg (" page2= %x, page3= %x, page4= %x", + qh->hw_buf [2], qh->hw_buf [3], + qh->hw_buf [4]); + } +} +#endif + +static const char *const fls_strings [] = + { "1024", "512", "256", "??" }; + +#else +#if 0 +static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {} +#endif +#endif /* DEBUG */ + +/* functions have the "wrong" filename when they're output... */ + +#define dbg_status(ehci, label, status) \ + dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \ + label, status, \ + (status & STS_ASS) ? " Async" : "", \ + (status & STS_PSS) ? " Periodic" : "", \ + (status & STS_RECL) ? " Recl" : "", \ + (status & STS_HALT) ? " Halt" : "", \ + (status & STS_IAA) ? " IAA" : "", \ + (status & STS_FATAL) ? " FATAL" : "", \ + (status & STS_FLR) ? " FLR" : "", \ + (status & STS_PCD) ? " PCD" : "", \ + (status & STS_ERR) ? " ERR" : "", \ + (status & STS_INT) ? " INT" : "" \ + ) + +#define dbg_cmd(ehci, label, command) \ + dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \ + label, command, \ + (command & CMD_PARK) ? "park" : "(park)", \ + CMD_PARK_CNT (command), \ + (command >> 16) & 0x3f, \ + (command & CMD_LRESET) ? " LReset" : "", \ + (command & CMD_IAAD) ? " IAAD" : "", \ + (command & CMD_ASE) ? " Async" : "", \ + (command & CMD_PSE) ? " Periodic" : "", \ + fls_strings [(command >> 2) & 0x3], \ + (command & CMD_RESET) ? " Reset" : "", \ + (command & CMD_RUN) ? "RUN" : "HALT" \ + ) + +#define dbg_port(hcd, label, port, status) \ + dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \ + label, port, status, \ + (status & PORT_OWNER) ? " OWNER" : "", \ + (status & PORT_POWER) ? " POWER" : "", \ + (status >> 10) & 3, \ + (status & PORT_RESET) ? " RESET" : "", \ + (status & PORT_SUSPEND) ? " SUSPEND" : "", \ + (status & PORT_RESUME) ? " RESUME" : "", \ + (status & PORT_OCC) ? " OCC" : "", \ + (status & PORT_OC) ? " OC" : "", \ + (status & PORT_PEC) ? " PEC" : "", \ + (status & PORT_PE) ? " PE" : "", \ + (status & PORT_CSC) ? " CSC" : "", \ + (status & PORT_CONNECT) ? " CONNECT" : "" \ + ) + diff -urN linux-2.4.18/drivers/usb/hcd/ehci-hcd.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-hcd.c --- linux-2.4.18/drivers/usb/hcd/ehci-hcd.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-hcd.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,761 @@ +/* + * Copyright (c) 2000-2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_USB_DEBUG + #define CONFIG_USB_DEBUG /* this is still experimental! */ +#endif + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include "../hcd.h" + +#include +#include +#include +#include + +//#undef KERN_DEBUG +//#define KERN_DEBUG "" + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI hc_driver implementation ... experimental, incomplete. + * Based on the 0.96 register interface specification. + * + * There are lots of things to help out with here ... notably + * everything "periodic", and of course testing with all sorts + * of usb 2.0 devices and configurations. + * + * USB 2.0 shows up in upcoming www.pcmcia.org technology. + * First was PCMCIA, like ISA; then CardBus, which is PCI. + * Next comes "CardBay", using USB 2.0 signals. + * + * Contains additional contributions by: + * Brad Hards + * Rory Bolt + * ... + * + * HISTORY: + * 2002-01-14 Minor cleanup; version synch. + * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers. + * 2002-01-04 Control/Bulk queuing behaves. + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. + */ + +#define DRIVER_VERSION "$Revision: 1.1 $" +#define DRIVER_AUTHOR "David Brownell" +#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" + + +// #define EHCI_VERBOSE_DEBUG +// #define have_iso + +#ifdef CONFIG_DEBUG_SLAB +# define EHCI_SLAB_FLAGS (SLAB_POISON) +#else +# define EHCI_SLAB_FLAGS 0 +#endif + +/* magic numbers that can affect system performance */ +#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define EHCI_TUNE_RL_HS 0 /* nak throttle; see 4.9 */ +#define EHCI_TUNE_RL_TT 0 +#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define EHCI_TUNE_MULT_TT 1 + +/* Initial IRQ latency: lower than default */ +static int log2_irq_thresh = 0; // 0 to 6 +MODULE_PARM (log2_irq_thresh, "i"); +MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); + +#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) + +/*-------------------------------------------------------------------------*/ + +#include "ehci.h" +#include "ehci-dbg.c" + +/*-------------------------------------------------------------------------*/ + +/* + * hc states include: unknown, halted, ready, running + * transitional states are messy just now + * trying to avoid "running" unless urbs are active + * a "ready" hc can be finishing prefetched work + */ + +/* halt a non-running controller */ +static void ehci_reset (struct ehci_hcd *ehci) +{ + u32 command = readl (&ehci->regs->command); + + command |= CMD_RESET; + dbg_cmd (ehci, "reset", command); + writel (command, &ehci->regs->command); + while (readl (&ehci->regs->command) & CMD_RESET) + continue; + ehci->hcd.state = USB_STATE_HALT; +} + +/* idle the controller (from running) */ +static void ehci_ready (struct ehci_hcd *ehci) +{ + u32 command; + +#ifdef DEBUG + if (!HCD_IS_RUNNING (ehci->hcd.state)) + BUG (); +#endif + + while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS))) + udelay (100); + command = readl (&ehci->regs->command); + command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); + writel (command, &ehci->regs->command); + + // hardware can take 16 microframes to turn off ... + ehci->hcd.state = USB_STATE_READY; +} + +/*-------------------------------------------------------------------------*/ + +#include "ehci-hub.c" +#include "ehci-mem.c" +#include "ehci-q.c" +#include "ehci-sched.c" + +/*-------------------------------------------------------------------------*/ + +static void ehci_tasklet (unsigned long param); + +/* called by khubd or root hub init threads */ + +static int ehci_start (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp; + struct usb_device *udev; + int retval; + u32 hcc_params; + u8 tempbyte; + + // FIXME: given EHCI 0.96 or later, and a controller with + // the USBLEGSUP/USBLEGCTLSTS extended capability, make sure + // the BIOS doesn't still own this controller. + + spin_lock_init (&ehci->lock); + + ehci->caps = (struct ehci_caps *) hcd->regs; + ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length); + dbg_hcs_params (ehci, "ehci_start"); + dbg_hcc_params (ehci, "ehci_start"); + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + ehci->periodic_size = DEFAULT_I_TDPS; + if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0) + return retval; + hcc_params = readl (&ehci->caps->hcc_params); + + /* controllers may cache some of the periodic schedule ... */ + if (HCC_ISOC_CACHE (hcc_params)) // full frame cache + ehci->i_thresh = 8; + else // N microframes cached + ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params); + + ehci->async = 0; + ehci->reclaim = 0; + ehci->next_frame = -1; + + /* controller state: unknown --> reset */ + + /* EHCI spec section 4.1 */ + ehci_reset (ehci); + writel (INTR_MASK, &ehci->regs->intr_enable); + writel (ehci->periodic_dma, &ehci->regs->frame_list); + + /* + * hcc_params controls whether ehci->regs->segment must (!!!) + * be used; it constrains QH/ITD/SITD and QTD locations. + * By default, pci_alloc_consistent() won't hand out addresses + * above 4GB (via pdev->dma_mask) so we know this value. + * + * NOTE: that pdev->dma_mask setting means that all DMA mappings + * for I/O buffers will have the same restriction, though it's + * neither necessary nor desirable in that case. + */ + if (HCC_64BIT_ADDR (hcc_params)) { + writel (0, &ehci->regs->segment); + info ("using segment 0 for 64bit DMA addresses ..."); + } + + /* clear interrupt enables, set irq latency */ + temp = readl (&ehci->regs->command) & 0xff; + if (log2_irq_thresh < 0 || log2_irq_thresh > 6) + log2_irq_thresh = 0; + temp |= 1 << (16 + log2_irq_thresh); + // keeping default periodic framelist size + temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE), + writel (temp, &ehci->regs->command); + dbg_cmd (ehci, "init", temp); + + /* set async sleep time = 10 us ... ? */ + + ehci->tasklet.func = ehci_tasklet; + ehci->tasklet.data = (unsigned long) ehci; + + /* wire up the root hub */ + hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus); + if (!udev) { +done2: + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices + * are explicitly handed to companion controller(s), so no TT is + * involved with the root hub. + */ + ehci->hcd.state = USB_STATE_READY; + writel (FLAG_CF, &ehci->regs->configured_flag); + readl (&ehci->regs->command); /* unblock posted write */ + + /* PCI Serial Bus Release Number is at 0x60 offset */ + pci_read_config_byte(hcd->pdev, 0x60, &tempbyte); + temp = readw (&ehci->caps->hci_version); + info ("USB %x.%x support enabled, EHCI rev %x.%2x", + ((tempbyte & 0xf0)>>4), + (tempbyte & 0x0f), + temp >> 8, + temp & 0xff); + + /* + * From here on, khubd concurrently accesses the root + * hub; drivers will be talking to enumerated devices. + * + * Before this point the HC was idle/ready. After, khubd + * and device drivers may start it running. + */ + usb_connect (udev); + udev->speed = USB_SPEED_HIGH; + if (usb_new_device (udev) != 0) { + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + ehci_reset (ehci); + // usb_disconnect (udev); + hcd->bus->root_hub = 0; + usb_free_dev (udev); + retval = -ENODEV; + goto done2; + } + + return 0; +} + +/* always called by thread; normally rmmod */ + +static void ehci_stop (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + + dbg ("%s: stop", hcd->bus_name); + + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + ehci_reset (ehci); + + // root hub is shut down separately (first, when possible) + scan_async (ehci); + if (ehci->next_frame != -1) + scan_periodic (ehci); + ehci_mem_cleanup (ehci); + + dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); +} + +static int ehci_get_frame (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM + +/* suspend/resume, section 4.3 */ + +static int ehci_suspend (struct usb_hcd *hcd, u32 state) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params; + int ports; + int i; + + dbg ("%s: suspend to %d", hcd->bus_name, state); + + params = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (params); + + // FIXME: This assumes what's probably a D3 level suspend... + + // FIXME: usb wakeup events on this bus should resume the machine. + // pci config register PORTWAKECAP controls which ports can do it; + // bios may have initted the register... + + /* suspend each port, then stop the hc */ + for (i = 0; i < ports; i++) { + int temp = readl (&ehci->regs->port_status [i]); + + if ((temp & PORT_PE) == 0 + || (temp & PORT_OWNER) != 0) + continue; +dbg ("%s: suspend port %d", hcd->bus_name, i); + temp |= PORT_SUSPEND; + writel (temp, &ehci->regs->port_status [i]); + } + + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command); + +// save pci FLADJ value + + /* who tells PCI to reduce power consumption? */ + + return 0; +} + +static int ehci_resume (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params; + int ports; + int i; + + dbg ("%s: resume", hcd->bus_name); + + params = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (params); + + // FIXME: if controller didn't retain state, + // return and let generic code clean it up + // test configured_flag ? + + /* resume HC and each port */ +// restore pci FLADJ value + // khubd and drivers will set HC running, if needed; + hcd->state = USB_STATE_READY; + for (i = 0; i < ports; i++) { + int temp = readl (&ehci->regs->port_status [i]); + + if ((temp & PORT_PE) == 0 + || (temp & PORT_SUSPEND) != 0) + continue; +dbg ("%s: resume port %d", hcd->bus_name, i); + temp |= PORT_RESUME; + writel (temp, &ehci->regs->port_status [i]); + readl (&ehci->regs->command); /* unblock posted writes */ + + wait_ms (20); + temp &= ~PORT_RESUME; + writel (temp, &ehci->regs->port_status [i]); + } + readl (&ehci->regs->command); /* unblock posted writes */ + return 0; +} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * tasklet scheduled by some interrupts and other events + * calls driver completion functions ... but not in_irq() + */ +static void ehci_tasklet (unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + + if (ehci->reclaim_ready) + end_unlink_async (ehci); + scan_async (ehci); + if (ehci->next_frame != -1) + scan_periodic (ehci); + + // FIXME: when nothing is connected to the root hub, + // turn off the RUN bit so the host can enter C3 "sleep" power + // saving mode; make root hub code scan memory less often. +} + +/*-------------------------------------------------------------------------*/ + +static void ehci_irq (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 status = readl (&ehci->regs->status); + int bh = 0; + + /* clear (just) interrupts */ + status &= INTR_MASK; + writel (status, &ehci->regs->status); + readl (&ehci->regs->command); /* unblock posted write */ + + if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ + return; + +#ifdef EHCI_VERBOSE_DEBUG + /* unrequested/ignored: Port Change Detect, Frame List Rollover */ + if (status & INTR_MASK) + dbg_status (ehci, "irq", status); +#endif + + /* INT, ERR, and IAA interrupt rates can be throttled */ + + /* normal [4.15.1.2] or error [4.15.1.1] completion */ + if (likely ((status & (STS_INT|STS_ERR)) != 0)) + bh = 1; + + /* complete the unlinking of some qh [4.15.2.3] */ + if (status & STS_IAA) { + ehci->reclaim_ready = 1; + bh = 1; + } + + /* PCI errors [4.15.2.4] */ + if (unlikely ((status & STS_FATAL) != 0)) { + err ("%s: fatal error, state %x", hcd->bus_name, hcd->state); + ehci_reset (ehci); + // generic layer kills/unlinks all urbs + // then tasklet cleans up the rest + bh = 1; + } + + /* most work doesn't need to be in_irq() */ + if (likely (bh == 1)) + tasklet_schedule (&ehci->tasklet); +} + +/*-------------------------------------------------------------------------*/ + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + * + * urb + dev is in hcd_dev.urb_list + * we're queueing TDs onto software and hardware lists + * + * hcd-specific init for hcpriv hasn't been done yet + * + * NOTE: EHCI queues control and bulk requests transparently, like OHCI. + */ +static int ehci_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + struct list_head qtd_list; + + urb->transfer_flags &= ~EHCI_STATE_UNLINK; + INIT_LIST_HEAD (&qtd_list); + switch (usb_pipetype (urb->pipe)) { + + case PIPE_CONTROL: + case PIPE_BULK: + if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) + return -ENOMEM; + submit_async (ehci, urb, &qtd_list, mem_flags); + break; + + case PIPE_INTERRUPT: + if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return intr_submit (ehci, urb, &qtd_list, mem_flags); + + case PIPE_ISOCHRONOUS: +#ifdef have_iso + if (urb->dev->speed == USB_SPEED_HIGH) + return itd_submit (ehci, urb); + else + return sitd_submit (ehci, urb); +#else + // FIXME highspeed iso stuff is written but never run/tested. + // and the split iso support isn't even written yet. + dbg ("no iso support yet"); + return -ENOSYS; +#endif /* have_iso */ + + } + return 0; +} + +/* remove from hardware lists + * completions normally happen asynchronously + */ + +static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; + unsigned long flags; + + dbg ("%s urb_dequeue %p qh state %d", + hcd->bus_name, urb, qh->qh_state); + + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + spin_lock_irqsave (&ehci->lock, flags); + if (ehci->reclaim) { +dbg ("dq: reclaim busy, %s", RUN_CONTEXT); + if (in_interrupt ()) { + spin_unlock_irqrestore (&ehci->lock, flags); + return -EAGAIN; + } + while (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && ehci->hcd.state != USB_STATE_HALT + ) { + spin_unlock_irqrestore (&ehci->lock, flags); +// yeech ... this could spin for up to two frames! +dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d", + qh->qh_state, ehci->reclaim, ehci->hcd.state +); + udelay (100); + spin_lock_irqsave (&ehci->lock, flags); + } + } + if (qh->qh_state == QH_STATE_LINKED) + start_unlink_async (ehci, qh); + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; + + case PIPE_INTERRUPT: + intr_deschedule (ehci, urb->start_frame, qh, urb->interval); + if (ehci->hcd.state == USB_STATE_HALT) + urb->status = -ESHUTDOWN; + qh_completions (ehci, &qh->qtd_list, 1); + return 0; + + case PIPE_ISOCHRONOUS: + // itd or sitd ... + + // wait till next completion, do it then. + // completion irqs can wait up to 128 msec, + urb->transfer_flags |= EHCI_STATE_UNLINK; + return 0; + } + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + +// bulk qh holds the data toggle + +static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev) +{ + struct hcd_dev *dev = (struct hcd_dev *)udev->hcpriv; + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + int i; + unsigned long flags; + + /* ASSERT: nobody can be submitting urbs for this any more */ + + dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum); + + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < 32; i++) { + if (dev->ep [i]) { + struct ehci_qh *qh; + + // FIXME: this might be an itd/sitd too ... + // or an interrupt urb (not on async list) + // can use "union ehci_shadow" + + qh = (struct ehci_qh *) dev->ep [i]; + vdbg ("free_config, ep 0x%02x qh %p", i, qh); + if (!list_empty (&qh->qtd_list)) { + dbg ("ep 0x%02x qh %p not empty!", i, qh); + BUG (); + } + dev->ep [i] = 0; + + /* wait_ms() won't spin here -- we're a thread */ + while (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && ehci->hcd.state != USB_STATE_HALT + ) { + spin_unlock_irqrestore (&ehci->lock, flags); + wait_ms (1); + spin_lock_irqsave (&ehci->lock, flags); + } + if (qh->qh_state == QH_STATE_LINKED) { + start_unlink_async (ehci, qh); + while (qh->qh_state != QH_STATE_IDLE) { + spin_unlock_irqrestore (&ehci->lock, + flags); + wait_ms (1); + spin_lock_irqsave (&ehci->lock, flags); + } + } + qh_unput (ehci, qh); + } + } + + spin_unlock_irqrestore (&ehci->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +static const char hcd_name [] = "ehci-hcd"; + +static const struct hc_driver ehci_driver = { + description: hcd_name, + + /* + * generic hardware linkage + */ + irq: ehci_irq, + flags: HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + start: ehci_start, +#ifdef CONFIG_PM + suspend: ehci_suspend, + resume: ehci_resume, +#endif + stop: ehci_stop, + + /* + * memory lifecycle (except per-request) + */ + hcd_alloc: ehci_hcd_alloc, + hcd_free: ehci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + urb_enqueue: ehci_urb_enqueue, + urb_dequeue: ehci_urb_dequeue, + free_config: ehci_free_config, + + /* + * scheduling support + */ + get_frame_number: ehci_get_frame, + + /* + * root hub support + */ + hub_status_data: ehci_hub_status_data, + hub_control: ehci_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +/* EHCI spec says PCI is required. */ + +/* PCI driver selection metadata; PCI hotplugging uses this */ +static const struct pci_device_id __devinitdata pci_ids [] = { { + + /* handle any USB 2.0 EHCI controller */ + + class: ((PCI_CLASS_SERIAL_USB << 8) | 0x20), + class_mask: ~0, + driver_data: (unsigned long) &ehci_driver, + + /* no matter who makes it */ + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + +}, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver ehci_pci_driver = { + name: (char *) hcd_name, + id_table: pci_ids, + + probe: usb_hcd_pci_probe, + remove: usb_hcd_pci_remove, + +#ifdef CONFIG_PM + suspend: usb_hcd_pci_suspend, + resume: usb_hcd_pci_resume, +#endif +}; + +#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC + +EXPORT_NO_SYMBOLS; +MODULE_DESCRIPTION (DRIVER_INFO); +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_LICENSE ("GPL"); + +static int __init init (void) +{ + dbg (DRIVER_INFO); + dbg ("block sizes: qh %d qtd %d itd %d sitd %d", + sizeof (struct ehci_qh), sizeof (struct ehci_qtd), + sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); + + return pci_module_init (&ehci_pci_driver); +} +module_init (init); + +static void __exit cleanup (void) +{ + pci_unregister_driver (&ehci_pci_driver); +} +module_exit (cleanup); diff -urN linux-2.4.18/drivers/usb/hcd/ehci-hub.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-hub.c --- linux-2.4.18/drivers/usb/hcd/ehci-hub.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-hub.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Root Hub ... the nonsharable stuff + * + * Registers don't need cpu_to_le32, that happens transparently + */ + +/*-------------------------------------------------------------------------*/ + +static int check_reset_complete ( + struct ehci_hcd *ehci, + int index, + int port_status +) { + if (!(port_status & PORT_CONNECT)) { + ehci->reset_done [index] = 0; + return port_status; + } + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + dbg ("%s port %d full speed, give to companion, 0x%x", + ehci->hcd.bus_name, index + 1, port_status); + + // what happens if HCS_N_CC(params) == 0 ? + port_status |= PORT_OWNER; + writel (port_status, &ehci->regs->port_status [index]); + + } else + dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1); + + return port_status; +} + +/*-------------------------------------------------------------------------*/ + + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +ehci_hub_status_data (struct usb_hcd *hcd, char *buf) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp, status = 0; + int ports, i, retval = 1; + unsigned long flags; + + /* init status to no-changes */ + buf [0] = 0; + temp = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (temp); + if (ports > 7) { + buf [1] = 0; + retval++; + } + + /* no hub change reports (bit 0) for now (power, ...) */ + + /* port N changes (bit N)? */ + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < ports; i++) { + temp = readl (&ehci->regs->port_status [i]); + if (temp & PORT_OWNER) { + /* don't report this in GetPortStatus */ + if (temp & PORT_CSC) { + temp &= ~PORT_CSC; + writel (temp, &ehci->regs->port_status [i]); + } + continue; + } + if (!(temp & PORT_CONNECT)) + ehci->reset_done [i] = 0; + if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) { + set_bit (i, buf); + status = STS_PCD; + } + } + spin_unlock_irqrestore (&ehci->lock, flags); + return status ? retval : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +ehci_hub_descriptor ( + struct ehci_hcd *ehci, + struct usb_hub_descriptor *desc +) { + u32 params = readl (&ehci->caps->hcs_params); + int ports = HCS_N_PORTS (params); + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 0; /* FIXME: f(system power) */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset (&desc->bitmap [0], 0, temp); + memset (&desc->bitmap [temp], 0xff, temp); + + temp = 0x0008; /* per-port overcurrent reporting */ + if (HCS_PPC (params)) /* per-port power control */ + temp |= 0x0001; + if (HCS_INDICATOR (params)) /* per-port indicators (LEDs) */ + temp |= 0x0080; + desc->wHubCharacteristics = cpu_to_le16 (temp); +} + +/*-------------------------------------------------------------------------*/ + +static int ehci_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params = readl (&ehci->caps->hcs_params); + int ports = HCS_N_PORTS (params); + u32 temp; + unsigned long flags; + int retval = 0; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave (&ehci->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = readl (&ehci->regs->port_status [wIndex]); + if (temp & PORT_OWNER) + break; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + writel (temp & ~PORT_PE, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_ENABLE: + writel (temp | PORT_PEC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_SUSPEND: + case USB_PORT_FEAT_C_SUSPEND: + /* ? */ + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC (params)) + writel (temp & ~PORT_POWER, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_CONNECTION: + writel (temp | PORT_CSC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + writel (temp | PORT_OCC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + readl (&ehci->regs->command); /* unblock posted write */ + break; + case GetHubDescriptor: + ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset (buf, 0, 4); + //cpu_to_le32s ((u32 *) buf); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + memset (buf, 0, 4); + temp = readl (&ehci->regs->port_status [wIndex]); + + // wPortChange bits + if (temp & PORT_CSC) + set_bit (USB_PORT_FEAT_C_CONNECTION, buf); + if (temp & PORT_PEC) + set_bit (USB_PORT_FEAT_C_ENABLE, buf); + // USB_PORT_FEAT_C_SUSPEND + if (temp & PORT_OCC) + set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf); + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && jiffies > ehci->reset_done [wIndex]) { + set_bit (USB_PORT_FEAT_C_RESET, buf); + + /* force reset to complete */ + writel (temp & ~PORT_RESET, + &ehci->regs->port_status [wIndex]); + do { + temp = readl ( + &ehci->regs->port_status [wIndex]); + udelay (10); + } while (temp & PORT_RESET); + + /* see what we found out */ + temp = check_reset_complete (ehci, wIndex, temp); + } + + // don't show wPortStatus if it's owned by a companion hc + if (!(temp & PORT_OWNER)) { + if (temp & PORT_CONNECT) { + set_bit (USB_PORT_FEAT_CONNECTION, buf); + set_bit (USB_PORT_FEAT_HIGHSPEED, buf); + } + if (temp & PORT_PE) + set_bit (USB_PORT_FEAT_ENABLE, buf); + if (temp & PORT_SUSPEND) + set_bit (USB_PORT_FEAT_SUSPEND, buf); + if (temp & PORT_OC) + set_bit (USB_PORT_FEAT_OVER_CURRENT, buf); + if (temp & PORT_RESET) + set_bit (USB_PORT_FEAT_RESET, buf); + if (temp & PORT_POWER) + set_bit (USB_PORT_FEAT_POWER, buf); + } + +#ifndef EHCI_VERBOSE_DEBUG + if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ +#endif + dbg_port (hcd, "GetStatus", wIndex + 1, temp); + cpu_to_le32s ((u32 *) buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = readl (&ehci->regs->port_status [wIndex]); + if (temp & PORT_OWNER) + break; + + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + writel (temp | PORT_SUSPEND, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC (params)) + writel (temp | PORT_POWER, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_RESET: + /* line status bits may report this as low speed */ + if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && PORT_USB11 (temp)) { + dbg ("%s port %d low speed, give to companion", + hcd->bus_name, wIndex + 1); + temp |= PORT_OWNER; + } else { + vdbg ("%s port %d reset", + hcd->bus_name, wIndex + 1); + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + ehci->reset_done [wIndex] = jiffies + + ((50 /* msec */ * HZ) / 1000); + } + writel (temp, &ehci->regs->port_status [wIndex]); + break; + default: + goto error; + } + readl (&ehci->regs->command); /* unblock posted writes */ + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore (&ehci->lock, flags); + return retval; +} diff -urN linux-2.4.18/drivers/usb/hcd/ehci-mem.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-mem.c --- linux-2.4.18/drivers/usb/hcd/ehci-mem.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-mem.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use pci_pool or pci_alloc_consistent + * - driver buffers, read/written by HC ... single shot DMA mapped + * + * There's also PCI "register" data, which is memory mapped. + * No memory seen by this driver is pagable. + */ + +/*-------------------------------------------------------------------------*/ +/* + * Allocator / cleanup for the per device structure + * Called by hcd init / removal code + */ +static struct usb_hcd *ehci_hcd_alloc (void) +{ + struct ehci_hcd *ehci; + + ehci = (struct ehci_hcd *) + kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL); + if (ehci != 0) { + memset (ehci, 0, sizeof (struct ehci_hcd)); + return &ehci->hcd; + } + return 0; +} + +static void ehci_hcd_free (struct usb_hcd *hcd) +{ + kfree (hcd_to_ehci (hcd)); +} + +/*-------------------------------------------------------------------------*/ + +/* Allocate the key transfer structures from the previously allocated pool */ + +static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) +{ + struct ehci_qtd *qtd; + dma_addr_t dma; + + qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); + if (qtd != 0) { + memset (qtd, 0, sizeof *qtd); + qtd->qtd_dma = dma; + qtd->hw_next = EHCI_LIST_END; + qtd->hw_alt_next = EHCI_LIST_END; + INIT_LIST_HEAD (&qtd->qtd_list); + } + return qtd; +} + +static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) +{ + pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma); +} + + +static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) +{ + struct ehci_qh *qh; + dma_addr_t dma; + + qh = (struct ehci_qh *) + pci_pool_alloc (ehci->qh_pool, flags, &dma); + if (qh) { + memset (qh, 0, sizeof *qh); + atomic_set (&qh->refcount, 1); + qh->qh_dma = dma; + // INIT_LIST_HEAD (&qh->qh_list); + INIT_LIST_HEAD (&qh->qtd_list); + } + return qh; +} + +/* to share a qh (cpu threads, or hc) */ +static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh) +{ + // dbg ("put %p (%d++)", qh, qh->refcount.counter); + atomic_inc (&qh->refcount); + return qh; +} + +static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + // dbg ("unput %p (--%d)", qh, qh->refcount.counter); + if (!atomic_dec_and_test (&qh->refcount)) + return; + /* clean qtds first, and know this is not linked */ + if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { + dbg ("unused qh not empty!"); + BUG (); + } + pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); +} + +/*-------------------------------------------------------------------------*/ + +/* The queue heads and transfer descriptors are managed from pools tied + * to each of the "per device" structures. + * This is the initialisation and cleanup code. + */ + +static void ehci_mem_cleanup (struct ehci_hcd *ehci) +{ + /* PCI consistent memory and pools */ + if (ehci->qtd_pool) + pci_pool_destroy (ehci->qtd_pool); + ehci->qtd_pool = 0; + + if (ehci->qh_pool) { + pci_pool_destroy (ehci->qh_pool); + ehci->qh_pool = 0; + } + + if (ehci->itd_pool) + pci_pool_destroy (ehci->itd_pool); + ehci->itd_pool = 0; + + if (ehci->sitd_pool) + pci_pool_destroy (ehci->sitd_pool); + ehci->sitd_pool = 0; + + if (ehci->periodic) + pci_free_consistent (ehci->hcd.pdev, + ehci->periodic_size * sizeof (u32), + ehci->periodic, ehci->periodic_dma); + ehci->periodic = 0; + + /* shadow periodic table */ + if (ehci->pshadow) + kfree (ehci->pshadow); + ehci->pshadow = 0; +} + +/* remember to add cleanup code (above) if you add anything here */ +static int ehci_mem_init (struct ehci_hcd *ehci, int flags) +{ + int i; + + /* QTDs for control/bulk/intr transfers */ + ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev, + sizeof (struct ehci_qtd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->qtd_pool) { + dbg ("no qtd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* QH for control/bulk/intr transfers */ + ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev, + sizeof (struct ehci_qh), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->qh_pool) { + dbg ("no qh pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* ITD for high speed ISO transfers */ + ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev, + sizeof (struct ehci_itd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->itd_pool) { + dbg ("no itd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* SITD for full/low speed split ISO transfers */ + ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev, + sizeof (struct ehci_sitd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->sitd_pool) { + dbg ("no sitd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* Hardware periodic table */ + ehci->periodic = (u32 *) + pci_alloc_consistent (ehci->hcd.pdev, + ehci->periodic_size * sizeof (u32), + &ehci->periodic_dma); + if (ehci->periodic == 0) { + dbg ("no hw periodic table"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic [i] = EHCI_LIST_END; + + /* software shadow of hardware table */ + ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), + flags & ~EHCI_SLAB_FLAGS); + if (ehci->pshadow == 0) { + dbg ("no shadow periodic table"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *)); + + return 0; +} diff -urN linux-2.4.18/drivers/usb/hcd/ehci-q.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-q.c --- linux-2.4.18/drivers/usb/hcd/ehci-q.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-q.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI hardware queue manipulation + * + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned + * buffers needed for the larger number). We use one QH per endpoint, queue + * multiple (bulk or control) urbs per endpoint. URBs may need several qtds. + * A scheduled interrupt qh always has one qtd, one urb. + * + * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with + * interrupts) needs careful scheduling. Performance improvements can be + * an ongoing challenge. + * + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using + * (b) special fields in qh entries or (c) split iso entries. TTs will + * buffer low/full speed data so the host collects it at high speed. + */ + +/*-------------------------------------------------------------------------*/ + +/* fill a qtd, returning how much of the buffer we were able to queue up */ + +static int +qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token) +{ + int i, count; + + /* one buffer entry per 4K ... first might be short or unaligned */ + qtd->hw_buf [0] = cpu_to_le32 (buf); + count = 0x1000 - (buf & 0x0fff); /* rest of that page */ + if (likely (len < count)) /* ... iff needed */ + count = len; + else { + buf += 0x1000; + buf &= ~0x0fff; + + /* per-qtd limit: from 16K to 20K (best alignment) */ + for (i = 1; count < len && i < 5; i++) { + u64 addr = buf; + qtd->hw_buf [i] = cpu_to_le32 ((u32)addr); + qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32)); + buf += 0x1000; + if ((count + 0x1000) < len) + count += 0x1000; + else + count = len; + } + } + qtd->hw_token = cpu_to_le32 ((count << 16) | token); + qtd->length = count; + +#if 0 + vdbg (" qtd_fill %p, token %8x bytes %d dma %x", + qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]); +#endif + + return count; +} + +/*-------------------------------------------------------------------------*/ + +/* update halted (but potentially linked) qh */ + +static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd) +{ + qh->hw_current = 0; + qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); + qh->hw_alt_next = EHCI_LIST_END; + + /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ + qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); +} + +/*-------------------------------------------------------------------------*/ + +static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token) +{ + /* count IN/OUT bytes, not SETUP (even short packets) */ + if (likely (QTD_PID (token) != 2)) + urb->actual_length += length - QTD_LENGTH (token); + + /* don't modify error codes */ + if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) { + if (token & QTD_STS_BABBLE) { + urb->status = -EOVERFLOW; + } else if (!QTD_CERR (token)) { + if (token & QTD_STS_DBE) + urb->status = (QTD_PID (token) == 1) /* IN ? */ + ? -ENOSR /* hc couldn't read data */ + : -ECOMM; /* hc couldn't write data */ + else if (token & QTD_STS_MMF) /* missed tt uframe */ + urb->status = -EPROTO; + else if (token & QTD_STS_XACT) { + if (QTD_LENGTH (token)) + urb->status = -EPIPE; + else { + dbg ("3strikes"); + urb->status = -EPROTO; + } + } else /* presumably a stall */ + urb->status = -EPIPE; + + /* CERR nonzero + data left + halt --> stall */ + } else if (QTD_LENGTH (token)) + urb->status = -EPIPE; + else /* unknown */ + urb->status = -EPROTO; + dbg ("ep %d-%s qtd token %08x --> status %d", + /* devpath */ + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + token, urb->status); + + /* stall indicates some recovery action is needed */ + if (urb->status == -EPIPE) { + int pipe = urb->pipe; + + if (!usb_pipecontrol (pipe)) + usb_endpoint_halt (urb->dev, + usb_pipeendpoint (pipe), + usb_pipeout (pipe)); + if (urb->dev->tt && !usb_pipeint (pipe)) { +err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d", + urb->dev->ttport, /* devpath */ + urb->dev->tt->multi ? "" : " (all-ports TT)", + urb->dev->devnum, usb_pipeendpoint (urb->pipe)); + // FIXME something (khubd?) should make the hub + // CLEAR_TT_BUFFER ASAP, it's blocking other + // fs/ls requests... hub_tt_clear_buffer() ? + } + } + } +} + +static void ehci_urb_complete ( + struct ehci_hcd *ehci, + dma_addr_t addr, + struct urb *urb +) { + if (urb->transfer_buffer_length && usb_pipein (urb->pipe)) + pci_dma_sync_single (ehci->hcd.pdev, addr, + urb->transfer_buffer_length, + PCI_DMA_FROMDEVICE); + + /* cleanse status if we saw no error */ + if (likely (urb->status == -EINPROGRESS)) { + if (urb->actual_length != urb->transfer_buffer_length + && (urb->transfer_flags & USB_DISABLE_SPD)) + urb->status = -EREMOTEIO; + else + urb->status = 0; + } + + /* only report unlinks once */ + if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN)) + urb->complete (urb); +} + +/* urb->lock ignored from here on (hcd is done with urb) */ + +static void ehci_urb_done ( + struct ehci_hcd *ehci, + dma_addr_t addr, + struct urb *urb +) { + if (urb->transfer_buffer_length) + pci_unmap_single (ehci->hcd.pdev, + addr, + urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (likely (urb->hcpriv != 0)) { + qh_unput (ehci, (struct ehci_qh *) urb->hcpriv); + urb->hcpriv = 0; + } + + if (likely (urb->status == -EINPROGRESS)) { + if (urb->actual_length != urb->transfer_buffer_length + && (urb->transfer_flags & USB_DISABLE_SPD)) + urb->status = -EREMOTEIO; + else + urb->status = 0; + } + + /* hand off urb ownership */ + usb_hcd_giveback_urb (&ehci->hcd, urb); +} + + +/* + * Process completed qtds for a qh, issuing completions if needed. + * When freeing: frees qtds, unmaps buf, returns URB to driver. + * When not freeing (queued periodic qh): retain qtds, mapping, and urb. + * Races up to qh->hw_current; returns number of urb completions. + */ +static int +qh_completions ( + struct ehci_hcd *ehci, + struct list_head *qtd_list, + int freeing +) { + struct ehci_qtd *qtd, *last; + struct list_head *next; + struct ehci_qh *qh = 0; + int unlink = 0, halted = 0; + unsigned long flags; + int retval = 0; + + spin_lock_irqsave (&ehci->lock, flags); + if (unlikely (list_empty (qtd_list))) { + spin_unlock_irqrestore (&ehci->lock, flags); + return retval; + } + + /* scan QTDs till end of list, or we reach an active one */ + for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list), + last = 0, next = 0; + next != qtd_list; + last = qtd, qtd = list_entry (next, + struct ehci_qtd, qtd_list)) { + struct urb *urb = qtd->urb; + u32 token = 0; + + /* qh is non-null iff these qtds were queued to the HC */ + qh = (struct ehci_qh *) urb->hcpriv; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely (last->urb != urb)) { + /* complete() can reenter this HCD */ + spin_unlock_irqrestore (&ehci->lock, flags); + if (likely (freeing != 0)) + ehci_urb_done (ehci, last->buf_dma, + last->urb); + else + ehci_urb_complete (ehci, last->buf_dma, + last->urb); + spin_lock_irqsave (&ehci->lock, flags); + retval++; + } + + /* qh overlays can have HC's old cached copies of + * next qtd ptrs, if an URB was queued afterwards. + */ + if (qh && cpu_to_le32 (last->qtd_dma) == qh->hw_current + && last->hw_next != qh->hw_qtd_next) { + qh->hw_alt_next = last->hw_alt_next; + qh->hw_qtd_next = last->hw_next; + } + + if (likely (freeing != 0)) + ehci_qtd_free (ehci, last); + last = 0; + } + next = qtd->qtd_list.next; + + /* if these qtds were queued to the HC, some may be active. + * else we're cleaning up after a failed URB submission. + */ + if (likely (qh != 0)) { + int qh_halted; + + qh_halted = __constant_cpu_to_le32 (QTD_STS_HALT) + & qh->hw_token; + token = le32_to_cpu (qtd->hw_token); + halted = halted + || qh_halted + || (ehci->hcd.state == USB_STATE_HALT) + || (qh->qh_state == QH_STATE_IDLE); + + /* QH halts only because of fault or unlink; in both + * cases, queued URBs get unlinked. But for unlink, + * URBs at the head of the queue can stay linked. + */ + if (unlikely (halted != 0)) { + + /* unlink everything because of HC shutdown? */ + if (ehci->hcd.state == USB_STATE_HALT) { + freeing = unlink = 1; + urb->status = -ESHUTDOWN; + + /* explicit unlink, starting here? */ + } else if (qh->qh_state == QH_STATE_IDLE + && (urb->status == -ECONNRESET + || urb->status == -ENOENT)) { + freeing = unlink = 1; + + /* unlink everything because of error? */ + } else if (qh_halted + && !(token & QTD_STS_HALT)) { + freeing = unlink = 1; + if (urb->status == -EINPROGRESS) + urb->status = -ECONNRESET; + + /* unlink the rest? */ + } else if (unlink) { + urb->status = -ECONNRESET; + + /* QH halted to unlink urbs after this? */ + } else if ((token & QTD_STS_ACTIVE) != 0) { + qtd = 0; + continue; + } + + /* Else QH is active, so we must not modify QTDs + * that HC may be working on. Break from loop. + */ + } else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) { + next = qtd_list; + qtd = 0; + continue; + } + + spin_lock (&urb->lock); + qtd_copy_status (urb, qtd->length, token); + spin_unlock (&urb->lock); + } + + /* + * NOTE: this won't work right with interrupt urbs that + * need multiple qtds ... only the first scan of qh->qtd_list + * starts at the right qtd, yet multiple scans could happen + * for transfers that are scheduled across multiple uframes. + * (Such schedules are not currently allowed!) + */ + if (likely (freeing != 0)) + list_del (&qtd->qtd_list); + else { + /* restore everything the HC could change + * from an interrupt QTD + */ + qtd->hw_token = (qtd->hw_token + & ~__constant_cpu_to_le32 (0x8300)) + | cpu_to_le32 (qtd->length << 16) + | __constant_cpu_to_le32 (QTD_IOC + | (EHCI_TUNE_CERR << 10) + | QTD_STS_ACTIVE); + qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff); + + /* this offset, and the length above, + * are likely wrong on QTDs #2..N + */ + qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma); + } + +#if 0 + if (urb->status == -EINPROGRESS) + vdbg (" qtd %p ok, urb %p, token %8x, len %d", + qtd, urb, token, urb->actual_length); + else + vdbg ("urb %p status %d, qtd %p, token %8x, len %d", + urb, urb->status, qtd, token, + urb->actual_length); +#endif + + /* SETUP for control urb? */ + if (unlikely (QTD_PID (token) == 2)) + pci_unmap_single (ehci->hcd.pdev, + qtd->buf_dma, sizeof (devrequest), + PCI_DMA_TODEVICE); + } + + /* patch up list head? */ + if (unlikely (halted && qh && !list_empty (qtd_list))) { + qh_update (qh, list_entry (qtd_list->next, + struct ehci_qtd, qtd_list)); + } + spin_unlock_irqrestore (&ehci->lock, flags); + + /* last urb's completion might still need calling */ + if (likely (last != 0)) { + if (likely (freeing != 0)) { + ehci_urb_done (ehci, last->buf_dma, last->urb); + ehci_qtd_free (ehci, last); + } else + ehci_urb_complete (ehci, last->buf_dma, last->urb); + retval++; + } + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head * +qh_urb_transaction ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *head, + int flags +) { + struct ehci_qtd *qtd, *qtd_prev; + dma_addr_t buf, map_buf; + int len, maxpacket; + u32 token; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + return 0; + qtd_prev = 0; + list_add_tail (&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (EHCI_TUNE_CERR << 10); + /* for split transactions, SplitXState initialized to zero */ + + if (usb_pipecontrol (urb->pipe)) { + /* control request data is passed in the "setup" pid */ + + /* NOTE: this isn't smart about 64bit DMA, since it uses the + * default (32bit) mask rather than using the whole address + * space. we could set pdev->dma_mask to all-ones while + * getting this mapping, locking it and restoring before + * allocating qtd/qh/... or maybe only do that for the main + * data phase (below). + */ + qtd->buf_dma = pci_map_single ( + ehci->hcd.pdev, + urb->setup_packet, + sizeof (devrequest), + PCI_DMA_TODEVICE); + if (unlikely (!qtd->buf_dma)) + goto cleanup; + + /* SETUP pid */ + qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest), + token | (2 /* "setup" */ << 8)); + + /* ... and always at least one more pid */ + token ^= QTD_TOGGLE; + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + } + + /* + * data transfer stage: buffer setup + */ + len = urb->transfer_buffer_length; + if (likely (len > 0)) { + /* NOTE: sub-optimal mapping with 64bit DMA (see above) */ + buf = map_buf = pci_map_single (ehci->hcd.pdev, + urb->transfer_buffer, len, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (unlikely (!buf)) + goto cleanup; + } else + buf = map_buf = 0; + + if (!buf || usb_pipein (urb->pipe)) + token |= (1 /* "in" */ << 8); + /* else it's already initted to "out" pid (0 << 8) */ + + maxpacket = usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + qtd->urb = urb; + qtd->buf_dma = map_buf; + this_qtd_len = qtd_fill (qtd, buf, len, token); + len -= this_qtd_len; + buf += this_qtd_len; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + + if (likely (len <= 0)) + break; + + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + } + + /* + * control requests may need a terminating data "status" ack; + * bulk ones may need a terminating short packet (zero length). + */ + if (likely (buf != 0)) { + int one_more = 0; + + if (usb_pipecontrol (urb->pipe)) { + one_more = 1; + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + } else if (usb_pipebulk (urb->pipe) + && (urb->transfer_flags & USB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill (qtd, 0, 0, token); + } + } + + /* by default, enable interrupt on urb completion */ + if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); + return head; + +cleanup: + urb->status = -ENOMEM; + qh_completions (ehci, head, 1); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Hardware maintains data toggle (like OHCI) ... here we (re)initialize + * the hardware data toggle in the QH, and set the pseudo-toggle in udev + * so we can see if usb_clear_halt() was called. NOP for control, since + * we set up qh->hw_info1 to always use the QTD toggle bits. + */ +static inline void +clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh) +{ + vdbg ("clear toggle, dev %d ep 0x%x-%s", + udev->devnum, ep, is_out ? "out" : "in"); + qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); + usb_settoggle (udev, ep, is_out, 1); +} + +// Would be best to create all qh's from config descriptors, +// when each interface/altsetting is established. Unlink +// any previous qh and cancel its urbs first; endpoints are +// implicitly reset then (data toggle too). +// That'd mean updating how usbcore talks to HCDs. (2.5?) + + +/* + * Each QH holds a qtd list; a QH is used for everything except iso. + * + * For interrupt urbs, the scheduler must set the microframe scheduling + * mask(s) each time the QH gets scheduled. For highspeed, that's + * just one microframe in the s-mask. For split interrupt transactions + * there are additional complications: c-mask, maybe FSTNs. + */ +static struct ehci_qh * +ehci_qh_make ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int flags +) { + struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); + u32 info1 = 0, info2 = 0; + + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + info1 |= usb_pipeendpoint (urb->pipe) << 8; + info1 |= usb_pipedevice (urb->pipe) << 0; + + /* using TT? */ + switch (urb->dev->speed) { + case USB_SPEED_LOW: + info1 |= (1 << 12); /* EPS "low" */ + /* FALL THROUGH */ + + case USB_SPEED_FULL: + /* EPS 0 means "full" */ + info1 |= (EHCI_TUNE_RL_TT << 28); + if (usb_pipecontrol (urb->pipe)) { + info1 |= (1 << 27); /* for TT */ + info1 |= 1 << 14; /* toggle from qtd */ + } + info1 |= usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)) << 16; + + info2 |= (EHCI_TUNE_MULT_TT << 30); + info2 |= urb->dev->ttport << 23; + info2 |= urb->dev->tt->hub->devnum << 16; + + /* NOTE: if (usb_pipeint (urb->pipe)) { scheduler sets c-mask } + * ... and a 0.96 scheduler might use FSTN nodes too + */ + break; + + case USB_SPEED_HIGH: /* no TT involved */ + info1 |= (2 << 12); /* EPS "high" */ + info1 |= (EHCI_TUNE_RL_HS << 28); + if (usb_pipecontrol (urb->pipe)) { + info1 |= 64 << 16; /* usb2 fixed maxpacket */ + info1 |= 1 << 14; /* toggle from qtd */ + } else if (usb_pipebulk (urb->pipe)) { + info1 |= 512 << 16; /* usb2 fixed maxpacket */ + info2 |= (EHCI_TUNE_MULT_HS << 30); + } else + info1 |= usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)) << 16; + break; + default: +#ifdef DEBUG + BUG (); +#endif + } + + /* NOTE: if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */ + + qh->qh_state = QH_STATE_IDLE; + qh->hw_info1 = cpu_to_le32 (info1); + qh->hw_info2 = cpu_to_le32 (info2); + + /* initialize sw and hw queues with these qtds */ + list_splice (qtd_list, &qh->qtd_list); + qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list)); + + /* initialize data toggle state */ + if (!usb_pipecontrol (urb->pipe)) + clear_toggle (urb->dev, + usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe), + qh); + + return qh; +} + +/*-------------------------------------------------------------------------*/ + +/* move qh (and its qtds) onto async queue; maybe enable queue. */ + +static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + u32 dma = QH_NEXT (qh->qh_dma); + struct ehci_qh *q; + + if (unlikely (!(q = ehci->async))) { + u32 cmd = readl (&ehci->regs->command); + + /* in case a clear of CMD_ASE didn't take yet */ + while (readl (&ehci->regs->status) & STS_ASS) + udelay (100); + + qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ + qh->qh_next.qh = qh; + qh->hw_next = dma; + ehci->async = qh; + writel ((u32)qh->qh_dma, &ehci->regs->async_next); + cmd |= CMD_ASE | CMD_RUN; + writel (cmd, &ehci->regs->command); + ehci->hcd.state = USB_STATE_RUNNING; + /* posted write need not be known to HC yet ... */ + } else { + /* splice right after "start" of ring */ + qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ + qh->qh_next = q->qh_next; + qh->hw_next = q->hw_next; + q->qh_next.qh = qh; + q->hw_next = dma; + } + qh->qh_state = QH_STATE_LINKED; + /* qtd completions reported later by interrupt */ +} + +/*-------------------------------------------------------------------------*/ + +static void +submit_async ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int mem_flags +) { + struct ehci_qtd *qtd; + struct hcd_dev *dev; + int epnum; + unsigned long flags; + struct ehci_qh *qh = 0; + + qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); + dev = (struct hcd_dev *)urb->dev->hcpriv; + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) + epnum |= 0x10; + + vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]", + ehci->hcd.bus_name, urb, urb->transfer_buffer_length, + epnum & 0x0f, (epnum & 0x10) ? "in" : "out", + qtd, dev ? dev->ep [epnum] : (void *)~0); + + spin_lock_irqsave (&ehci->lock, flags); + + qh = (struct ehci_qh *) dev->ep [epnum]; + if (likely (qh != 0)) { + u32 hw_next = QTD_NEXT (qtd->qtd_dma); + + /* maybe patch the qh used for set_address */ + if (unlikely (epnum == 0 + && le32_to_cpu (qh->hw_info1 & 0x7f) == 0)) + qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe)); + + /* is an URB is queued to this qh already? */ + if (unlikely (!list_empty (&qh->qtd_list))) { + struct ehci_qtd *last_qtd; + int short_rx = 0; + + /* update the last qtd's "next" pointer */ + // dbg_qh ("non-empty qh", ehci, qh); + last_qtd = list_entry (qh->qtd_list.prev, + struct ehci_qtd, qtd_list); + last_qtd->hw_next = hw_next; + + /* previous urb allows short rx? maybe optimize. */ + if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD) + && (epnum & 0x10)) { + // only the last QTD for now + last_qtd->hw_alt_next = hw_next; + short_rx = 1; + } + + /* Adjust any old copies in qh overlay too. + * Interrupt code must cope with case of HC having it + * cached, and clobbering these updates. + * ... complicates getting rid of extra interrupts! + */ + if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) { + wmb (); + qh->hw_qtd_next = hw_next; + if (short_rx) + qh->hw_alt_next = hw_next + | (qh->hw_alt_next & 0x1e); + vdbg ("queue to qh %p, patch", qh); + } + + /* no URB queued */ + } else { + // dbg_qh ("empty qh", ehci, qh); + +// FIXME: how handle usb_clear_halt() for an EP with queued URBs? +// usbcore may not let us handle that cleanly... +// likely must cancel them all first! + + /* usb_clear_halt() means qh data toggle gets reset */ + if (usb_pipebulk (urb->pipe) + && unlikely (!usb_gettoggle (urb->dev, + (epnum & 0x0f), + !(epnum & 0x10)))) { + clear_toggle (urb->dev, + epnum & 0x0f, !(epnum & 0x10), qh); + } + qh_update (qh, qtd); + } + list_splice (qtd_list, qh->qtd_list.prev); + + } else { + /* can't sleep here, we have ehci->lock... */ + qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC); + if (likely (qh != 0)) { + // dbg_qh ("new qh", ehci, qh); + dev->ep [epnum] = qh; + } else + urb->status = -ENOMEM; + } + + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely (qh != 0)) { + urb->hcpriv = qh_put (qh); + if (likely (qh->qh_state == QH_STATE_IDLE)) + qh_link_async (ehci, qh_put (qh)); + } + spin_unlock_irqrestore (&ehci->lock, flags); + if (unlikely (!qh)) + qh_completions (ehci, qtd_list, 1); +} + +/*-------------------------------------------------------------------------*/ + +/* the async qh for the qtds being reclaimed are now unlinked from the HC */ +/* caller must not own ehci->lock */ + +static void end_unlink_async (struct ehci_hcd *ehci) +{ + struct ehci_qh *qh = ehci->reclaim; + + qh->qh_state = QH_STATE_IDLE; + qh->qh_next.qh = 0; + qh_unput (ehci, qh); // refcount from reclaim + ehci->reclaim = 0; + ehci->reclaim_ready = 0; + + qh_completions (ehci, &qh->qtd_list, 1); + + // unlink any urb should now unlink all following urbs, so that + // relinking only happens for urbs before the unlinked ones. + if (!list_empty (&qh->qtd_list) + && HCD_IS_RUNNING (ehci->hcd.state)) + qh_link_async (ehci, qh); + else + qh_unput (ehci, qh); // refcount from async list +} + + +/* makes sure the async qh will become idle */ +/* caller must own ehci->lock */ + +static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + int cmd = readl (&ehci->regs->command); + struct ehci_qh *prev; + +#ifdef DEBUG + if (ehci->reclaim + || !ehci->async + || qh->qh_state != QH_STATE_LINKED +#ifdef CONFIG_SMP +// this macro lies except on SMP compiles + || !spin_is_locked (&ehci->lock) +#endif + ) + BUG (); +#endif + + qh->qh_state = QH_STATE_UNLINK; + ehci->reclaim = qh = qh_put (qh); + + // dbg_qh ("start unlink", ehci, qh); + + /* Remove the last QH (qhead)? Stop async schedule first. */ + if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) { + /* can't get here without STS_ASS set */ + if (ehci->hcd.state != USB_STATE_HALT) { + if (cmd & CMD_PSE) + writel (cmd & ~CMD_ASE, &ehci->regs->command); + else { + ehci_ready (ehci); + while (readl (&ehci->regs->status) & STS_ASS) + udelay (100); + } + } + qh->qh_next.qh = ehci->async = 0; + + ehci->reclaim_ready = 1; + tasklet_schedule (&ehci->tasklet); + return; + } + + if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { + ehci->reclaim_ready = 1; + tasklet_schedule (&ehci->tasklet); + return; + } + + prev = ehci->async; + while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async) + prev = prev->qh_next.qh; +#ifdef DEBUG + if (prev->qh_next.qh != qh) + BUG (); +#endif + + if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) { + ehci->async = prev; + prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); + } + prev->hw_next = qh->hw_next; + prev->qh_next = qh->qh_next; + + ehci->reclaim_ready = 0; + cmd |= CMD_IAAD; + writel (cmd, &ehci->regs->command); + /* posted write need not be known to HC yet ... */ +} + +/*-------------------------------------------------------------------------*/ + +static void scan_async (struct ehci_hcd *ehci) +{ + struct ehci_qh *qh; + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); +rescan: + qh = ehci->async; + if (likely (qh != 0)) { + do { + /* clean any finished work for this qh */ + if (!list_empty (&qh->qtd_list)) { + // dbg_qh ("scan_async", ehci, qh); + qh = qh_put (qh); + spin_unlock_irqrestore (&ehci->lock, flags); + + /* concurrent unlink could happen here */ + qh_completions (ehci, &qh->qtd_list, 1); + + spin_lock_irqsave (&ehci->lock, flags); + qh_unput (ehci, qh); + } + + /* unlink idle entries (reduces PCI usage) */ + if (list_empty (&qh->qtd_list) && !ehci->reclaim) { + if (qh->qh_next.qh != qh) { + // dbg ("irq/empty"); + start_unlink_async (ehci, qh); + } else { + // FIXME: arrange to stop + // after it's been idle a while. + } + } + qh = qh->qh_next.qh; + if (!qh) /* unlinked? */ + goto rescan; + } while (qh != ehci->async); + } + + spin_unlock_irqrestore (&ehci->lock, flags); +} diff -urN linux-2.4.18/drivers/usb/hcd/ehci-sched.c linux-2.4.19-pre5/drivers/usb/hcd/ehci-sched.c --- linux-2.4.18/drivers/usb/hcd/ehci-sched.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci-sched.c Sat Mar 30 22:55:29 2002 @@ -0,0 +1,1056 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI scheduled transaction support: interrupt, iso, split iso + * These are called "periodic" transactions in the EHCI spec. + */ + +/* + * Ceiling microseconds (typical) for that many bytes at high speed + * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed + * to preallocate bandwidth) + */ +#define EHCI_HOST_DELAY 5 /* nsec, guess */ +#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + EHCI_HOST_DELAY) +#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + EHCI_HOST_DELAY) + +static int ehci_get_frame (struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* + * periodic_next_shadow - return "next" pointer on shadow list + * @periodic: host pointer to qh/itd/sitd + * @tag: hardware tag for type of this record + */ +static union ehci_shadow * +periodic_next_shadow (union ehci_shadow *periodic, int tag) +{ + switch (tag) { + case Q_TYPE_QH: + return &periodic->qh->qh_next; + case Q_TYPE_FSTN: + return &periodic->fstn->fstn_next; +#ifdef have_iso + case Q_TYPE_ITD: + return &periodic->itd->itd_next; + case Q_TYPE_SITD: + return &periodic->sitd->sitd_next; +#endif /* have_iso */ + } + dbg ("BAD shadow %p tag %d", periodic->ptr, tag); + // BUG (); + return 0; +} + +/* returns true after successful unlink */ +/* caller must hold ehci->lock */ +static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) +{ + union ehci_shadow *prev_p = &ehci->pshadow [frame]; + u32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow here = *prev_p; + union ehci_shadow *next_p; + + /* find predecessor of "ptr"; hw and shadow lists are in sync */ + while (here.ptr && here.ptr != ptr) { + prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p)); + hw_p = &here.qh->hw_next; + here = *prev_p; + } + /* an interrupt entry (at list end) could have been shared */ + if (!here.ptr) { + dbg ("entry %p no longer on frame [%d]", ptr, frame); + return 0; + } + // vdbg ("periodic unlink %p from frame %d", ptr, frame); + + /* update hardware list ... HC may still know the old structure, so + * don't change hw_next until it'll have purged its cache + */ + next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p)); + *hw_p = here.qh->hw_next; + + /* unlink from shadow list; HCD won't see old structure again */ + *prev_p = *next_p; + next_p->ptr = 0; + + return 1; +} + +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) +{ + u32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow *q = &ehci->pshadow [frame]; + unsigned usecs = 0; +#ifdef have_iso + u32 temp = 0; +#endif + + while (q->ptr) { + switch (Q_NEXT_TYPE (*hw_p)) { + case Q_TYPE_QH: + /* is it in the S-mask? */ + if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) + usecs += q->qh->usecs; + q = &q->qh->qh_next; + break; + case Q_TYPE_FSTN: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != EHCI_LIST_END) { + dbg ("not counting FSTN bandwidth yet ..."); + } + q = &q->fstn->fstn_next; + break; +#ifdef have_iso + case Q_TYPE_ITD: + temp = le32_to_cpu (q->itd->transaction [uframe]); + temp >>= 16; + temp &= 0x0fff; + if (temp) + usecs += HS_USECS_ISO (temp); + q = &q->itd->itd_next; + break; + case Q_TYPE_SITD: + temp = q->sitd->hw_fullspeed_ep & + __constant_cpu_to_le32 (1 << 31); + + // FIXME: this doesn't count data bytes right... + + /* is it in the S-mask? (count SPLIT, DATA) */ + if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { + if (temp) + usecs += HS_USECS (188); + else + usecs += HS_USECS (1); + } + + /* ... C-mask? (count CSPLIT, DATA) */ + if (q->sitd->hw_uframe & + cpu_to_le32 (1 << (8 + uframe))) { + if (temp) + usecs += HS_USECS (0); + else + usecs += HS_USECS (188); + } + q = &q->sitd->sitd_next; + break; +#endif /* have_iso */ + default: + BUG (); + } + } +#ifdef DEBUG + if (usecs > 100) + err ("overallocated uframe %d, periodic is %d usecs", + frame * 8 + uframe, usecs); +#endif + return usecs; +} + +/*-------------------------------------------------------------------------*/ + +static void intr_deschedule ( + struct ehci_hcd *ehci, + unsigned frame, + struct ehci_qh *qh, + unsigned period +) { + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); + + do { + periodic_unlink (ehci, frame, qh); + qh_unput (ehci, qh); + frame += period; + } while (frame < ehci->periodic_size); + + qh->qh_state = QH_STATE_UNLINK; + qh->qh_next.ptr = 0; + ehci->periodic_urbs--; + + /* maybe turn off periodic schedule */ + if (!ehci->periodic_urbs) { + u32 cmd = readl (&ehci->regs->command); + + /* did setting PSE not take effect yet? + * takes effect only at frame boundaries... + */ + while (!(readl (&ehci->regs->status) & STS_PSS)) + udelay (20); + + cmd &= ~CMD_PSE; + writel (cmd, &ehci->regs->command); + /* posted write ... */ + + ehci->next_frame = -1; + } else + vdbg ("periodic schedule still enabled"); + + spin_unlock_irqrestore (&ehci->lock, flags); + + /* + * If the hc may be looking at this qh, then delay a uframe + * (yeech!) to be sure it's done. + * No other threads may be mucking with this qh. + */ + if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0) + udelay (125); + + qh->qh_state = QH_STATE_IDLE; + qh->hw_next = EHCI_LIST_END; + + vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d", + qh, period, frame, + atomic_read (&qh->refcount), ehci->periodic_urbs); +} + +static int intr_submit ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int mem_flags +) { + unsigned epnum, period; + unsigned temp; + unsigned short mult, usecs; + unsigned long flags; + struct ehci_qh *qh; + struct hcd_dev *dev; + int status = 0; + + /* get endpoint and transfer data */ + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) { + temp = urb->dev->epmaxpacketin [epnum]; + epnum |= 0x10; + } else + temp = urb->dev->epmaxpacketout [epnum]; + mult = 1; + if (urb->dev->speed == USB_SPEED_HIGH) { + /* high speed "high bandwidth" is coded in ep maxpacket */ + mult += (temp >> 11) & 0x03; + temp &= 0x03ff; + } else { + dbg ("no intr/tt scheduling yet"); + status = -ENOSYS; + goto done; + } + + /* + * NOTE: current completion/restart logic doesn't handle more than + * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this. + * such big requests need many periods to transfer. + */ + if (unlikely (qtd_list->next != qtd_list->prev)) { + dbg ("only one intr qtd per urb allowed"); + status = -EINVAL; + goto done; + } + + usecs = HS_USECS (urb->transfer_buffer_length); + + /* + * force a power-of-two (frames) sized polling interval + * + * NOTE: endpoint->bInterval for highspeed is measured in uframes, + * while for full/low speeds it's in frames. Here we "know" that + * urb->interval doesn't give acccess to high interrupt rates. + */ + period = ehci->periodic_size; + temp = period; + if (unlikely (urb->interval < 1)) + urb->interval = 1; + while (temp > urb->interval) + temp >>= 1; + period = urb->interval = temp; + + spin_lock_irqsave (&ehci->lock, flags); + + /* get the qh (must be empty and idle) */ + dev = (struct hcd_dev *)urb->dev->hcpriv; + qh = (struct ehci_qh *) dev->ep [epnum]; + if (qh) { + /* only allow one queued interrupt urb per EP */ + if (unlikely (qh->qh_state != QH_STATE_IDLE + || !list_empty (&qh->qtd_list))) { + dbg ("interrupt urb already queued"); + status = -EBUSY; + } else { + /* maybe reset hardware's data toggle in the qh */ + if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f, + !(epnum & 0x10)))) { + qh->hw_token |= + __constant_cpu_to_le32 (QTD_TOGGLE); + usb_settoggle (urb->dev, epnum & 0x0f, + !(epnum & 0x10), 1); + } + /* trust the QH was set up as interrupt ... */ + list_splice (qtd_list, &qh->qtd_list); + qh_update (qh, list_entry (qtd_list->next, + struct ehci_qtd, qtd_list)); + } + } else { + /* can't sleep here, we have ehci->lock... */ + qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC); + qtd_list = &qh->qtd_list; + if (likely (qh != 0)) { + // dbg ("new INTR qh %p", qh); + dev->ep [epnum] = qh; + } else + status = -ENOMEM; + } + + /* Schedule this periodic QH. */ + if (likely (status == 0)) { + unsigned frame = urb->interval; + + qh->hw_next = EHCI_LIST_END; + qh->hw_info2 |= cpu_to_le32 (mult << 30); + qh->usecs = usecs; + + urb->hcpriv = qh_put (qh); + status = -ENOSPC; + + /* pick a set of schedule slots, link the QH into them */ + do { + int uframe; + + /* Select some frame 0..(urb->interval - 1) with a + * microframe that can hold this transaction. + * + * FIXME for TT splits, need uframes for start and end. + * FSTNs can put end into next frame (uframes 0 or 1). + */ + frame--; + for (uframe = 0; uframe < 8; uframe++) { + int claimed; + claimed = periodic_usecs (ehci, frame, uframe); + /* 80% periodic == 100 usec max committed */ + if ((claimed + usecs) <= 100) { + vdbg ("frame %d.%d: %d usecs, plus %d", + frame, uframe, claimed, usecs); + break; + } + } + if (uframe == 8) + continue; +// FIXME delete when code below handles non-empty queues + if (ehci->pshadow [frame].ptr) + continue; + + /* QH will run once each period, starting there */ + urb->start_frame = frame; + status = 0; + + /* set S-frame mask */ + qh->hw_info2 |= cpu_to_le32 (1 << uframe); + // dbg_qh ("Schedule INTR qh", ehci, qh); + + /* stuff into the periodic schedule */ + qh->qh_state = QH_STATE_LINKED; + vdbg ("qh %p usecs %d period %d starting frame %d.%d", + qh, qh->usecs, period, frame, uframe); + do { + if (unlikely (ehci->pshadow [frame].ptr != 0)) { +// FIXME -- just link to the end, before any qh with a shorter period, +// AND handle it already being (implicitly) linked into this frame + BUG (); + } else { + ehci->pshadow [frame].qh = qh_put (qh); + ehci->periodic [frame] = + QH_NEXT (qh->qh_dma); + } + frame += period; + } while (frame < ehci->periodic_size); + + /* update bandwidth utilization records (for usbfs) */ + usb_claim_bandwidth (urb->dev, urb, usecs, 0); + + /* maybe enable periodic schedule processing */ + if (!ehci->periodic_urbs++) { + u32 cmd; + + /* did clearing PSE did take effect yet? + * takes effect only at frame boundaries... + */ + while (readl (&ehci->regs->status) & STS_PSS) + udelay (20); + + cmd = readl (&ehci->regs->command) | CMD_PSE; + writel (cmd, &ehci->regs->command); + /* posted write ... PSS happens later */ + ehci->hcd.state = USB_STATE_RUNNING; + + /* make sure tasklet scans these */ + ehci->next_frame = ehci_get_frame (&ehci->hcd); + } + break; + + } while (frame); + } + spin_unlock_irqrestore (&ehci->lock, flags); +done: + if (status) { + usb_complete_t complete = urb->complete; + + urb->complete = 0; + urb->status = status; + qh_completions (ehci, qtd_list, 1); + urb->complete = complete; + } + return status; +} + +static unsigned long +intr_complete ( + struct ehci_hcd *ehci, + unsigned frame, + struct ehci_qh *qh, + unsigned long flags /* caller owns ehci->lock ... */ +) { + struct ehci_qtd *qtd; + struct urb *urb; + int unlinking; + + /* nothing to report? */ + if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE)) + != 0)) + return flags; + + qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); + urb = qtd->urb; + unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET); + + /* call any completions, after patching for reactivation */ + spin_unlock_irqrestore (&ehci->lock, flags); + /* NOTE: currently restricted to one qtd per qh! */ + if (qh_completions (ehci, &qh->qtd_list, 0) == 0) + urb = 0; + spin_lock_irqsave (&ehci->lock, flags); + + /* never reactivate requests that were unlinked ... */ + if (likely (urb != 0)) { + if (unlinking + || urb->status == -ECONNRESET + || urb->status == -ENOENT + // || (urb->dev == null) + || ehci->hcd.state == USB_STATE_HALT) + urb = 0; + // FIXME look at all those unlink cases ... we always + // need exactly one completion that reports unlink. + // the one above might not have been it! + } + + /* normally reactivate */ + if (likely (urb != 0)) { + if (usb_pipeout (urb->pipe)) + pci_dma_sync_single (ehci->hcd.pdev, + qtd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_TODEVICE); + urb->status = -EINPROGRESS; + urb->actual_length = 0; + + /* patch qh and restart */ + qh_update (qh, qtd); + } + return flags; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef have_iso + +static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd) +{ + pci_pool_free (ehci->itd_pool, itd, itd->itd_dma); +} + +/* + * Create itd and allocate into uframes within specified frame. + * Caller must update the resulting uframe links. + */ +static struct ehci_itd * +itd_make ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned index, // urb->iso_frame_desc [index] + unsigned frame, // scheduled start + dma_addr_t dma, // mapped transfer buffer + int mem_flags +) { + struct ehci_itd *itd; + u64 temp; + u32 buf1; + unsigned epnum, maxp, multi, usecs; + unsigned length; + unsigned i, bufnum; + + /* allocate itd, start to fill it */ + itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma); + if (!itd) + return itd; + + itd->hw_next = EHCI_LIST_END; + itd->urb = urb; + itd->index = index; + INIT_LIST_HEAD (&itd->itd_list); + itd->uframe = (frame * 8) % ehci->periodic_size; + + /* tell itd about the buffer its transfers will consume */ + length = urb->iso_frame_desc [index].length; + dma += urb->iso_frame_desc [index].offset; + temp = dma & ~0x0fff; + for (i = 0; i < 7; i++) { + itd->hw_bufp [i] = cpu_to_le32 ((u32) temp); + itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32)); + temp += 0x0fff; + } + + /* + * this might be a "high bandwidth" highspeed endpoint, + * as encoded in the ep descriptor's maxpacket field + */ + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) { + maxp = urb->dev->epmaxpacketin [epnum]; + buf1 = (1 << 11) | maxp; + } else { + maxp = urb->dev->epmaxpacketout [epnum]; + buf1 = maxp; + } + multi = 1; + multi += (temp >> 11) & 0x03; + maxp &= 0x03ff; + + /* "plus" info in low order bits of buffer pointers */ + itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum); + itd->hw_bufp [1] |= cpu_to_le32 (buf1); + itd->hw_bufp [2] |= cpu_to_le32 (multi); + + /* schedule as many uframes as needed */ + maxp *= multi; + usecs = HS_USECS_ISO (maxp); + bufnum = 0; + for (i = 0; i < 8; i++) { + unsigned t, offset, scratch; + + if (length <= 0) { + itd->hw_transaction [i] = 0; + continue; + } + + /* don't commit more than 80% periodic == 100 usec */ + if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100) + continue; + + /* we'll use this uframe; figure hw_transaction */ + t = EHCI_ISOC_ACTIVE; + t |= bufnum << 12; // which buffer? + offset = temp & 0x0fff; // offset therein + t |= offset; + if ((offset + maxp) >= 4096) // hc auto-wraps end-of-"page" + bufnum++; + if (length <= maxp) { + // interrupt only needed at end-of-urb + if ((index + 1) == urb->number_of_packets) + t |= EHCI_ITD_IOC; + scratch = length; + } else + scratch = maxp; + t |= scratch << 16; + t = cpu_to_le32 (t); + + itd->hw_transaction [i] = itd->transaction [i] = t; + length -= scratch; + } + if (length > 0) { + dbg ("iso frame too big, urb %p [%d], %d extra (of %d)", + urb, index, length, urb->iso_frame_desc [index].length); + itd_free (ehci, itd); + itd = 0; + } + return itd; +} + +static inline void +itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) +{ + u32 ptr; + + ptr = cpu_to_le32 (itd->itd_dma); // type 0 == itd + if (ehci->pshadow [frame].ptr) { + if (!itd->itd_next.ptr) { + itd->itd_next = ehci->pshadow [frame]; + itd->hw_next = ehci->periodic [frame]; + } else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) { + dbg ("frame %d itd link goof", frame); + BUG (); + } + } + ehci->pshadow [frame].itd = itd; + ehci->periodic [frame] = ptr; +} + +#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) + +static unsigned long +itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags) +{ + struct urb *urb = itd->urb; + + /* if not unlinking: */ + if (!(urb->transfer_flags & EHCI_STATE_UNLINK) + && ehci->hcd.state != USB_STATE_HALT) { + int i; + iso_packet_descriptor_t *desc; + struct ehci_itd *first_itd = urb->hcpriv; + + /* update status for this frame's transfers */ + desc = &urb->iso_frame_desc [itd->index]; + desc->status = 0; + desc->actual_length = 0; + for (i = 0; i < 8; i++) { + u32 t = itd->hw_transaction [i]; + if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) { + if (t & EHCI_ISOC_ACTIVE) + desc->status = -EXDEV; + else if (t & EHCI_ISOC_BUF_ERR) + desc->status = usb_pipein (urb->pipe) + ? -ENOSR /* couldn't read */ + : -ECOMM; /* couldn't write */ + else if (t & EHCI_ISOC_BABBLE) + desc->status = -EOVERFLOW; + else /* (t & EHCI_ISOC_XACTERR) */ + desc->status = -EPROTO; + break; + } + desc->actual_length += EHCI_ITD_LENGTH (t); + } + + /* handle completion now? */ + if ((itd->index + 1) != urb->number_of_packets) + return flags; + + i = usb_pipein (urb->pipe); + if (i) + pci_dma_sync_single (ehci->hcd.pdev, + first_itd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_FROMDEVICE); + + /* call completion with no locks; it can unlink ... */ + spin_unlock_irqrestore (&ehci->lock, flags); + urb->complete (urb); + spin_lock_irqsave (&ehci->lock, flags); + + /* re-activate this URB? or unlink? */ + if (!(urb->transfer_flags & EHCI_STATE_UNLINK) + && ehci->hcd.state != USB_STATE_HALT) { + if (!i) + pci_dma_sync_single (ehci->hcd.pdev, + first_itd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_TODEVICE); + + itd = urb->hcpriv; + do { + for (i = 0; i < 8; i++) + itd->hw_transaction [i] + = itd->transaction [i]; + itd = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + } while (itd != urb->hcpriv); + return flags; + } + + /* unlink done only on the last itd */ + } else if ((itd->index + 1) != urb->number_of_packets) + return flags; + + /* we're unlinking ... */ + + /* decouple urb from the hcd */ + spin_unlock_irqrestore (&ehci->lock, flags); + if (ehci->hcd.state == USB_STATE_HALT) + urb->status = -ESHUTDOWN; + itd = urb->hcpriv; + urb->hcpriv = 0; + ehci_urb_done (ehci, itd->buf_dma, urb); + spin_lock_irqsave (&ehci->lock, flags); + + /* take itds out of the hc's periodic schedule */ + list_entry (itd->itd_list.prev, struct ehci_itd, itd_list) + ->itd_list.next = 0; + do { + struct ehci_itd *next; + + if (itd->itd_list.next) + next = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + else + next = 0; + + // FIXME: hc WILL (!) lap us here, if we get behind + // by 128 msec (or less, with smaller periodic_size). + // Reading/caching these itds will cause trouble... + + periodic_unlink (ehci, itd->uframe, itd); + itd_free (ehci, itd); + itd = next; + } while (itd); + return flags; +} + +/*-------------------------------------------------------------------------*/ + +static int itd_submit (struct ehci_hcd *ehci, struct urb *urb) +{ + struct ehci_itd *first_itd = 0, *itd; + unsigned frame_index; + dma_addr_t dma; + unsigned long flags; + + dbg ("itd_submit"); + + /* set up one dma mapping for this urb */ + dma = pci_map_single (ehci->hcd.pdev, + urb->transfer_buffer, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (dma == 0) + return -ENOMEM; + + /* + * Schedule as needed. This is VERY optimistic about free + * bandwidth! But the API assumes drivers can pick frames + * intelligently (how?), so there's no other good option. + * + * FIXME this doesn't handle urb->next rings, or try to + * use the iso periodicity. + */ + if (urb->transfer_flags & USB_ISO_ASAP) { + urb->start_frame = ehci_get_frame (&ehci->hcd); + urb->start_frame++; + } + urb->start_frame %= ehci->periodic_size; + + /* create and populate itds (doing uframe scheduling) */ + spin_lock_irqsave (&ehci->lock, flags); + for (frame_index = 0; + frame_index < urb->number_of_packets; + frame_index++) { + itd = itd_make (ehci, urb, frame_index, + urb->start_frame + frame_index, + dma, SLAB_ATOMIC); + if (itd) { + if (first_itd) + list_add_tail (&itd->itd_list, + &first_itd->itd_list); + else + first_itd = itd; + } else { + spin_unlock_irqrestore (&ehci->lock, flags); + if (first_itd) { + while (!list_empty (&first_itd->itd_list)) { + itd = list_entry ( + first_itd->itd_list.next, + struct ehci_itd, itd_list); + list_del (&itd->itd_list); + itd_free (ehci, itd); + } + itd_free (ehci, first_itd); + } + pci_unmap_single (ehci->hcd.pdev, + dma, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + return -ENOMEM; + } + } + + /* stuff into the schedule */ + itd = first_itd; + do { + unsigned i; + + for (i = 0; i < 8; i++) { + if (!itd->hw_transaction [i]) + continue; + itd_link (ehci, itd->uframe + i, itd); + } + itd = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + } while (itd != first_itd); + urb->hcpriv = first_itd; + + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * "Split ISO TDs" ... used for USB 1.1 devices going through + * the TTs in USB 2.0 hubs. + */ + +static inline void +sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd) +{ + pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma); +} + +static struct ehci_sitd * +sitd_make ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned index, // urb->iso_frame_desc [index] + unsigned uframe, // scheduled start + dma_addr_t dma, // mapped transfer buffer + int mem_flags +) { + struct ehci_sitd *sitd; + unsigned length; + + sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma); + if (!sitd) + return sitd; + sitd->urb = urb; + length = urb->iso_frame_desc [index].length; + dma += urb->iso_frame_desc [index].offset; + +#if 0 + // FIXME: do the rest! +#else + sitd_free (ehci, sitd); + return 0; +#endif + +} + +static inline void +sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd) +{ + u32 ptr; + + ptr = cpu_to_le32 (sitd->sitd_dma | 2); // type 2 == sitd + if (ehci->pshadow [frame].ptr) { + if (!sitd->sitd_next.ptr) { + sitd->sitd_next = ehci->pshadow [frame]; + sitd->hw_next = ehci->periodic [frame]; + } else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) { + dbg ("frame %d sitd link goof", frame); + BUG (); + } + } + ehci->pshadow [frame].sitd = sitd; + ehci->periodic [frame] = ptr; +} + +static unsigned long +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + unsigned long flags +) { + // FIXME -- implement! + + dbg ("NYI -- sitd_complete"); + return flags; +} + +/*-------------------------------------------------------------------------*/ + +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb) +{ + // struct ehci_sitd *first_sitd = 0; + unsigned frame_index; + dma_addr_t dma; + int mem_flags; + + dbg ("NYI -- sitd_submit"); + + // FIXME -- implement! + + // FIXME: setup one big dma mapping + dma = 0; + + mem_flags = SLAB_ATOMIC; + + for (frame_index = 0; + frame_index < urb->number_of_packets; + frame_index++) { + struct ehci_sitd *sitd; + unsigned uframe; + + // FIXME: use real arguments, schedule this! + uframe = -1; + + sitd = sitd_make (ehci, urb, frame_index, + uframe, dma, mem_flags); + + if (sitd) { + /* + if (first_sitd) + list_add_tail (&sitd->sitd_list, + &first_sitd->sitd_list); + else + first_sitd = sitd; + */ + } else { + // FIXME: clean everything up + } + } + + // if we have a first sitd, then + // store them all into the periodic schedule! + // urb->hcpriv = first sitd in sitd_list + + return -ENOSYS; +} + +#endif /* have_iso */ + +/*-------------------------------------------------------------------------*/ + +static void scan_periodic (struct ehci_hcd *ehci) +{ + unsigned frame; + unsigned clock; + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); + + /* + * When running, scan from last scan point up to "now" + * Touches as few pages as possible: cache-friendly. + * It's safe to scan entries more than once, though. + */ + if (HCD_IS_RUNNING (ehci->hcd.state)) { + frame = ehci->next_frame; + clock = ehci_get_frame (&ehci->hcd); + + /* when shutting down, scan everything for thoroughness */ + } else { + frame = 0; + clock = ehci->periodic_size - 1; + } + for (;;) { + union ehci_shadow q; + u32 type; + +restart: + q.ptr = ehci->pshadow [frame].ptr; + type = Q_NEXT_TYPE (ehci->periodic [frame]); + + /* scan each element in frame's queue for completions */ + while (q.ptr != 0) { + int last; + union ehci_shadow temp; + + switch (type) { + case Q_TYPE_QH: + last = (q.qh->hw_next == EHCI_LIST_END); + flags = intr_complete (ehci, frame, + qh_put (q.qh), flags); + type = Q_NEXT_TYPE (q.qh->hw_next); + temp = q.qh->qh_next; + qh_unput (ehci, q.qh); + q = temp; + break; + case Q_TYPE_FSTN: + last = (q.fstn->hw_next == EHCI_LIST_END); + /* for "save place" FSTNs, look at QH entries + * in the previous frame for completions. + */ + if (q.fstn->hw_prev != EHCI_LIST_END) { + dbg ("ignoring completions from FSTNs"); + } + type = Q_NEXT_TYPE (q.fstn->hw_next); + temp = q.fstn->fstn_next; + break; +#ifdef have_iso + case Q_TYPE_ITD: + last = (q.itd->hw_next == EHCI_LIST_END); + flags = itd_complete (ehci, q.itd, flags); + type = Q_NEXT_TYPE (q.itd->hw_next); + q = q.itd->itd_next; + break; + case Q_TYPE_SITD: + last = (q.sitd->hw_next == EHCI_LIST_END); + flags = sitd_complete (ehci, q.sitd, flags); + type = Q_NEXT_TYPE (q.sitd->hw_next); + q = q.sitd->sitd_next; + break; +#endif /* have_iso */ + default: + dbg ("corrupt type %d frame %d shadow %p", + type, frame, q.ptr); + // BUG (); + last = 1; + q.ptr = 0; + } + + /* did completion remove an interior q entry? */ + if (unlikely (q.ptr == 0 && !last)) + goto restart; + } + + /* stop when we catch up to the HC */ + + // FIXME: this assumes we won't get lapped when + // latencies climb; that should be rare, but... + // detect it, and just go all the way around. + // FLR might help detect this case, so long as latencies + // don't exceed periodic_size msec (default 1.024 sec). + + // FIXME: likewise assumes HC doesn't halt mid-scan + + if (frame == clock) { + unsigned now; + + if (!HCD_IS_RUNNING (ehci->hcd.state)) + break; + ehci->next_frame = clock; + now = ehci_get_frame (&ehci->hcd); + if (clock == now) + break; + clock = now; + } else if (++frame >= ehci->periodic_size) + frame = 0; + } + spin_unlock_irqrestore (&ehci->lock, flags); + } diff -urN linux-2.4.18/drivers/usb/hcd/ehci.h linux-2.4.19-pre5/drivers/usb/hcd/ehci.h --- linux-2.4.18/drivers/usb/hcd/ehci.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd/ehci.h Sat Mar 30 22:55:29 2002 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_EHCI_HCD_H +#define __LINUX_EHCI_HCD_H + +/* definitions used for the EHCI driver */ + +/* ehci_hcd->lock guards shared data against other CPUs: + * ehci_hcd: async, reclaim, periodic (and shadow), ... + * hcd_dev: ep[] + * ehci_qh: qh_next, qtd_list + * ehci_qtd: qtd_list + * + * Also, hold this lock when talking to HC registers or + * when updating hw_* fields in shared qh/qtd/... structures. + */ + +#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */ + +struct ehci_hcd { /* one per controller */ + spinlock_t lock; + + /* async schedule support */ + struct ehci_qh *async; + struct ehci_qh *reclaim; + int reclaim_ready; + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ + unsigned periodic_size; + u32 *periodic; /* hw periodic table */ + dma_addr_t periodic_dma; + unsigned i_thresh; /* uframes HC might cache */ + + union ehci_shadow *pshadow; /* mirror hw periodic table */ + int next_frame; /* scan periodic, start here */ + unsigned periodic_urbs; /* how many urbs scheduled? */ + + /* deferred work from IRQ, etc */ + struct tasklet_struct tasklet; + + /* per root hub port */ + unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; + + /* glue to PCI and HCD framework */ + struct usb_hcd hcd; + struct ehci_caps *caps; + struct ehci_regs *regs; + + /* per-HC memory pools (could be per-PCI-bus, but ...) */ + struct pci_pool *qh_pool; /* qh per active urb */ + struct pci_pool *qtd_pool; /* one or more per qh */ + struct pci_pool *itd_pool; /* itd per iso urb */ + struct pci_pool *sitd_pool; /* sitd per split iso urb */ +}; + +/* unwrap an HCD pointer to get an EHCI_HCD pointer */ +#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd) + +/* NOTE: urb->transfer_flags expected to not use this bit !!! */ +#define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */ + +/*-------------------------------------------------------------------------*/ + +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ + +/* Section 2.2 Host Controller Capability Registers */ +struct ehci_caps { + u8 length; /* CAPLENGTH - size of this struct */ + u8 reserved; /* offset 0x1 */ + u16 hci_version; /* HCIVERSION - offset 0x2 */ + u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ +#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ +#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ +#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ + + u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */ +#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ +#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ + u8 portroute [8]; /* nibbles for routing - offset 0xC */ +} __attribute__ ((packed)); + + +/* Section 2.3 Host Controller Operational Registers */ +struct ehci_regs { + + /* USBCMD: offset 0x00 */ + u32 command; +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +#define CMD_PARK (1<<11) /* enable "park" on async qh */ +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +#define CMD_ASE (1<<5) /* async schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ +/* 3:2 is periodic frame list size */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ + + /* USBSTS: offset 0x04 */ + u32 status; +#define STS_ASS (1<<15) /* Async Schedule Status */ +#define STS_PSS (1<<14) /* Periodic Schedule Status */ +#define STS_RECL (1<<13) /* Reclamation */ +#define STS_HALT (1<<12) /* Not running (any reason) */ +/* some bits reserved */ + /* these STS_* flags are also intr_enable bits (USBINTR) */ +#define STS_IAA (1<<5) /* Interrupted on async advance */ +#define STS_FATAL (1<<4) /* such as some PCI access errors */ +#define STS_FLR (1<<3) /* frame list rolled over */ +#define STS_PCD (1<<2) /* port change detect */ +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +#define STS_INT (1<<0) /* "normal" completion (short, ...) */ + + /* USBINTR: offset 0x08 */ + u32 intr_enable; + + /* FRINDEX: offset 0x0C */ + u32 frame_index; /* current microframe number */ + /* CTRLDSSEGMENT: offset 0x10 */ + u32 segment; /* address bits 63:32 if needed */ + /* PERIODICLISTBASE: offset 0x14 */ + u32 frame_list; /* points to periodic list */ + /* ASYNCICLISTADDR: offset 0x18 */ + u32 async_next; /* address of next async queue head */ + + u32 reserved [9]; + + /* CONFIGFLAG: offset 0x40 */ + u32 configured_flag; +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + + /* PORTSC: offset 0x44 */ + u32 port_status [0]; /* up to N_PORTS */ +/* 31:23 reserved */ +#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ +#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ +#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ +/* 19:16 for port testing */ +/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */ +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */ +/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ +/* 9 reserved */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_OCC (1<<5) /* over current change */ +#define PORT_OC (1<<4) /* over current active */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +#define QTD_NEXT(dma) cpu_to_le32((u32)dma) + +/* + * EHCI Specification 0.95 Section 3.5 + * QTD: describe data transfer components (buffer, direction, ...) + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". + * + * These are associated only with "QH" (Queue Head) structures, + * used with control, bulk, and interrupt transfers. + */ +struct ehci_qtd { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.5.1 */ + u32 hw_alt_next; /* see EHCI 3.5.2 */ + u32 hw_token; /* see EHCI 3.5.3 */ +#define QTD_TOGGLE (1 << 31) /* data toggle */ +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define QTD_IOC (1 << 15) /* interrupt on complete */ +#define QTD_CERR(tok) (((tok)>>10) & 0x3) +#define QTD_PID(tok) (((tok)>>8) & 0x3) +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ +#define QTD_STS_HALT (1 << 6) /* halted on error */ +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ +#define QTD_STS_STS (1 << 1) /* split transaction state */ +#define QTD_STS_PING (1 << 0) /* issue PING? */ + u32 hw_buf [5]; /* see EHCI 3.5.4 */ + u32 hw_buf_hi [5]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t qtd_dma; /* qtd address */ + struct list_head qtd_list; /* sw qtd list */ + + /* dma same in urb's qtds, except 1st control qtd (setup buffer) */ + struct urb *urb; /* qtd's urb */ + dma_addr_t buf_dma; /* buffer address */ + size_t length; /* length of buffer */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* type tag from {qh,itd,sitd,fstn}->hw_next */ +#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1)) + +/* values for that type tag */ +#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1) +#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1) +#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1) +#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1) + +/* next async queue entry, or pointer to interrupt/periodic QH */ +#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH) + +/* for periodic/async schedules and qtd lists, mark end of list */ +#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */ + +/* + * Entries in periodic shadow table are pointers to one of four kinds + * of data structure. That's dictated by the hardware; a type tag is + * encoded in the low bits of the hardware's periodic schedule. Use + * Q_NEXT_TYPE to get the tag. + * + * For entries in the async schedule, the type tag always says "qh". + */ +union ehci_shadow { + struct ehci_qh *qh; /* Q_TYPE_QH */ + struct ehci_itd *itd; /* Q_TYPE_ITD */ + struct ehci_sitd *sitd; /* Q_TYPE_SITD */ + struct ehci_fstn *fstn; /* Q_TYPE_FSTN */ + void *ptr; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.6 + * QH: describes control/bulk/interrupt endpoints + * See Fig 3-7 "Queue Head Structure Layout". + * + * These appear in both the async and (for interrupt) periodic schedules. + */ + +struct ehci_qh { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.6.1 */ + u32 hw_info1; /* see EHCI 3.6.2 */ +#define QH_HEAD 0x00008000 + u32 hw_info2; /* see EHCI 3.6.2 */ + u32 hw_current; /* qtd list - see EHCI 3.6.4 */ + + /* qtd overlay (hardware parts of a struct ehci_qtd) */ + u32 hw_qtd_next; + u32 hw_alt_next; + u32 hw_token; + u32 hw_buf [5]; + u32 hw_buf_hi [5]; + + /* the rest is HCD-private */ + dma_addr_t qh_dma; /* address of qh */ + union ehci_shadow qh_next; /* ptr to qh; or periodic */ + struct list_head qtd_list; /* sw qtd list */ + + atomic_t refcount; + unsigned short usecs; /* intr bandwidth */ + short qh_state; +#define QH_STATE_LINKED 1 /* HC sees this */ +#define QH_STATE_UNLINK 2 /* HC may still see this */ +#define QH_STATE_IDLE 3 /* HC doesn't see this */ + +#ifdef EHCI_SOFT_RETRIES + int retries; +#endif +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.3 + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" + * + * Schedule records for high speed iso xfers + */ +struct ehci_itd { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.3.1 */ + u32 hw_transaction [8]; /* see EHCI 3.3.2 */ +#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ +#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */ +#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */ +#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ +#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */ + + u32 hw_bufp [7]; /* see EHCI 3.3.3 */ + u32 hw_bufp_hi [7]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t itd_dma; /* for this itd */ + union ehci_shadow itd_next; /* ptr to periodic q entry */ + + struct urb *urb; + unsigned index; /* in urb->iso_frame_desc */ + struct list_head itd_list; /* list of urb frames' itds */ + dma_addr_t buf_dma; /* frame's buffer address */ + + unsigned uframe; /* in periodic schedule */ + u32 transaction [8]; /* copy of hw_transaction */ + +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.4 + * siTD, aka split-transaction isochronous Transfer Descriptor + * ... describe low/full speed iso xfers through TT in hubs + * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) + */ +struct ehci_sitd { + /* first part defined by EHCI spec */ + u32 hw_next; +/* uses bit field macros above - see EHCI 0.95 Table 3-8 */ + u32 hw_fullspeed_ep; /* see EHCI table 3-9 */ + u32 hw_uframe; /* see EHCI table 3-10 */ + u32 hw_tx_results1; /* see EHCI table 3-11 */ + u32 hw_tx_results2; /* see EHCI table 3-12 */ + u32 hw_tx_results3; /* see EHCI table 3-12 */ + u32 hw_backpointer; /* see EHCI table 3-13 */ + u32 hw_buf_hi [2]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t sitd_dma; + union ehci_shadow sitd_next; /* ptr to periodic q entry */ + struct urb *urb; + dma_addr_t buf_dma; /* buffer address */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.96 Section 3.7 + * Periodic Frame Span Traversal Node (FSTN) + * + * Manages split interrupt transactions (using TT) that span frame boundaries + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. + */ +struct ehci_fstn { + u32 hw_next; /* any periodic q entry */ + u32 hw_prev; /* qh or EHCI_LIST_END */ + + /* the rest is HCD-private */ + dma_addr_t fstn_dma; + union ehci_shadow fstn_next; /* ptr to periodic q entry */ +} __attribute__ ((aligned (32))); + +#endif /* __LINUX_EHCI_HCD_H */ diff -urN linux-2.4.18/drivers/usb/hcd.c linux-2.4.19-pre5/drivers/usb/hcd.c --- linux-2.4.18/drivers/usb/hcd.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd.c Sat Mar 30 22:55:35 2002 @@ -0,0 +1,1307 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for UTS_SYSNAME */ + +#ifndef CONFIG_USB_DEBUG + #define CONFIG_USB_DEBUG /* this is experimental! */ +#endif + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include "hcd.h" + +#include +#include +#include +#include + + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver framework + * + * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing + * HCD-specific behaviors/bugs. + * + * This does error checks, tracks devices and urbs, and delegates to a + * "hc_driver" only for code (and data) that really needs to know about + * hardware differences. That includes root hub registers, i/o queues, + * and so on ... but as little else as possible. + * + * Shared code includes most of the "root hub" code (these are emulated, + * though each HC's hardware works differently) and PCI glue, plus request + * tracking overhead. The HCD code should only block on spinlocks or on + * hardware handshaking; blocking on software events (such as other kernel + * threads releasing resources, or completing actions) is all generic. + * + * Happens the USB 2.0 spec says this would be invisible inside the "USBD", + * and includes mostly a "HCDI" (HCD Interface) along with some APIs used + * only by the hub driver ... and that neither should be seen or used by + * usb client device drivers. + * + * Contributors of ideas or unattributed patches include: David Brownell, + * Roman Weissgaerber, Rory Bolt, ... + * + * HISTORY: + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. + */ + +/*-------------------------------------------------------------------------*/ + +/* host controllers we manage */ +static LIST_HEAD (hcd_list); + +/* used when updating list of hcds */ +static DECLARE_MUTEX (hcd_list_lock); + +/* used when updating hcd data */ +static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; + +static struct usb_operations hcd_operations; + +/*-------------------------------------------------------------------------*/ + +/* + * Sharable chunks of root hub code. + */ + +/*-------------------------------------------------------------------------*/ + +/* usb 2.0 root hub device descriptor */ +static const u8 usb2_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ + +/* usb 1.1 root hub device descriptor */ +static const u8 usb11_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/*-------------------------------------------------------------------------*/ + +/* Configuration descriptor for all our root hubs */ + +static const u8 rh_config_descriptor [] = { + + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __u16 wTotalLength; */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, + 6: Self-powered, + 5 Remote-wakwup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x0c /* __u8 ep_bInterval; (12ms -- usb 2.0 spec) */ +}; + +/*-------------------------------------------------------------------------*/ + +/* + * helper routine for returning string descriptors in UTF-16LE + * input can actually be ISO-8859-1; ASCII is its 7-bit subset + */ +static int ascii2utf (char *ascii, u8 *utf, int utfmax) +{ + int retval; + + for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { + *utf++ = *ascii++ & 0x7f; + *utf++ = 0; + } + return retval; +} + +/* + * rh_string - provides manufacturer, product and serial strings for root hub + * @id: the string ID number (1: serial number, 2: product, 3: vendor) + * @pci_desc: PCI device descriptor for the relevant HC + * @type: string describing our driver + * @data: return packet in UTF-16 LE + * @len: length of the return packet + * + * Produces either a manufacturer, product or serial number string for the + * virtual root hub device. + */ +static int rh_string ( + int id, + struct pci_dev *pci_desc, + char *type, + u8 *data, + int len +) { + char buf [100]; + + // language ids + if (id == 0) { + *data++ = 4; *data++ = 3; /* 4 bytes string data */ + *data++ = 0; *data++ = 0; /* some language id */ + return 4; + + // serial number + } else if (id == 1) { + strcpy (buf, pci_desc->slot_name); + + // product description + } else if (id == 2) { + strcpy (buf, pci_desc->name); + + // id 3 == vendor description + } else if (id == 3) { + sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type); + + // unsupported IDs --> "protocol stall" + } else + return 0; + + data [0] = 2 + ascii2utf (buf, data + 2, len - 2); + data [1] = 3; /* type == string */ + return data [0]; +} + + +/* Root hub control transfers execute synchronously */ +static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) +{ + devrequest *cmd = (devrequest *) urb->setup_packet; + u16 typeReq, wValue, wIndex, wLength; + const u8 *bufp = 0; + u8 *ubuf = urb->transfer_buffer; + int len = 0; + + typeReq = (cmd->requesttype << 8) | cmd->request; + wValue = le16_to_cpu (cmd->value); + wIndex = le16_to_cpu (cmd->index); + wLength = le16_to_cpu (cmd->length); + + if (wLength > urb->transfer_buffer_length) + goto error; + + /* set up for success */ + urb->status = 0; + urb->actual_length = wLength; + switch (typeReq) { + + /* DEVICE REQUESTS */ + + case DeviceRequest | USB_REQ_GET_STATUS: + // DEVICE_REMOTE_WAKEUP + ubuf [0] = 1; // selfpowered + ubuf [1] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + case DeviceOutRequest | USB_REQ_SET_FEATURE: + dbg ("no device features yet yet"); + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + ubuf [0] = 1; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (wValue & 0xff00) { + case USB_DT_DEVICE << 8: + if (hcd->driver->flags & HCD_USB2) + bufp = usb2_rh_dev_descriptor; + else if (hcd->driver->flags & HCD_USB11) + bufp = usb11_rh_dev_descriptor; + else + goto error; + len = 18; + break; + case USB_DT_CONFIG << 8: + bufp = rh_config_descriptor; + len = sizeof rh_config_descriptor; + break; + case USB_DT_STRING << 8: + urb->actual_length = rh_string ( + wValue & 0xff, + hcd->pdev, + (char *) hcd->description, + ubuf, wLength); + break; + default: + goto error; + } + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + ubuf [0] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + // wValue == urb->dev->devaddr + dbg ("%s root hub device address %d", + hcd->bus_name, wValue); + break; + + /* INTERFACE REQUESTS (no defined feature/status flags) */ + + /* ENDPOINT REQUESTS */ + + case EndpointRequest | USB_REQ_GET_STATUS: + // ENDPOINT_HALT flag + ubuf [0] = 0; + ubuf [1] = 0; + /* FALLTHROUGH */ + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + case EndpointOutRequest | USB_REQ_SET_FEATURE: + dbg ("no endpoint features yet"); + break; + + /* CLASS REQUESTS (and errors) */ + + default: + /* non-generic request */ + urb->status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + ubuf, wLength); + break; +error: + /* "protocol stall" on error */ + urb->status = -EPIPE; + dbg ("unsupported hub control message (maxchild %d)", + urb->dev->maxchild); + } + if (urb->status) { + urb->actual_length = 0; + dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d", + typeReq, wValue, wIndex, wLength, urb->status); + } + if (bufp) { + if (urb->transfer_buffer_length < len) + len = urb->transfer_buffer_length; + urb->actual_length = len; + // always USB_DIR_IN, toward host + memcpy (ubuf, bufp, len); + } + + /* any errors get returned through the urb completion */ + usb_hcd_giveback_urb (hcd, urb); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Root Hub interrupt transfers are synthesized with a timer. + * Completions are called in_interrupt() but not in_irq(). + */ + +static void rh_report_status (unsigned long ptr); + +static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) +{ + int len = 1 + (urb->dev->maxchild / 8); + + /* rh_timer protected by hcd_data_lock */ + if (timer_pending (&hcd->rh_timer) + || urb->status != -EINPROGRESS + || !HCD_IS_RUNNING (hcd->state) + || urb->transfer_buffer_length < len) { + dbg ("not queuing status urb, stat %d", urb->status); + return -EINVAL; + } + + urb->hcpriv = hcd; /* nonzero to indicate it's queued */ + init_timer (&hcd->rh_timer); + hcd->rh_timer.function = rh_report_status; + hcd->rh_timer.data = (unsigned long) urb; + hcd->rh_timer.expires = jiffies + + (HZ * (urb->interval < 30 + ? 30 + : urb->interval)) / 1000; + add_timer (&hcd->rh_timer); + return 0; +} + +/* timer callback */ + +static void rh_report_status (unsigned long ptr) +{ + struct urb *urb; + struct usb_hcd *hcd; + int length; + unsigned long flags; + + urb = (struct urb *) ptr; + spin_lock_irqsave (&urb->lock, flags); + if (!urb->dev) { + spin_unlock_irqrestore (&urb->lock, flags); + return; + } + + hcd = urb->dev->bus->hcpriv; + if (urb->status == -EINPROGRESS) { + if (HCD_IS_RUNNING (hcd->state)) { + length = hcd->driver->hub_status_data (hcd, + urb->transfer_buffer); + spin_unlock_irqrestore (&urb->lock, flags); + if (length > 0) { + urb->actual_length = length; + urb->status = 0; + urb->complete (urb); + } + spin_lock_irqsave (&hcd_data_lock, flags); + urb->status = -EINPROGRESS; + if (HCD_IS_RUNNING (hcd->state) + && rh_status_urb (hcd, urb) != 0) { + /* another driver snuck in? */ + dbg ("%s, can't resubmit roothub status urb?", + hcd->bus_name); + spin_unlock_irqrestore (&hcd_data_lock, flags); + BUG (); + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + } else + spin_unlock_irqrestore (&urb->lock, flags); + } else { + /* this urb's been unlinked */ + urb->hcpriv = 0; + spin_unlock_irqrestore (&urb->lock, flags); + + usb_hcd_giveback_urb (hcd, urb); + } +} + +/*-------------------------------------------------------------------------*/ + +static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) +{ + if (usb_pipeint (urb->pipe)) { + int retval; + unsigned long flags; + + spin_lock_irqsave (&hcd_data_lock, flags); + retval = rh_status_urb (hcd, urb); + spin_unlock_irqrestore (&hcd_data_lock, flags); + return retval; + } + if (usb_pipecontrol (urb->pipe)) + return rh_call_control (hcd, urb); + else + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + +static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; + + spin_lock_irqsave (&hcd_data_lock, flags); + del_timer_sync (&hcd->rh_timer); + hcd->rh_timer.data = 0; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + /* we rely on RH callback code not unlinking its URB! */ + usb_hcd_giveback_urb (hcd, urb); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PCI + +/* PCI-based HCs are normal, but custom bus glue should be ok */ + +static void hcd_irq (int irq, void *__hcd, struct pt_regs *r); +static void hc_died (struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_pci_probe - initialize PCI-based HCDs + * @dev: USB Host Controller being probed + * @id: pci hotplug id connecting controller to HCD framework + * + * Allocates basic PCI resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + struct hc_driver *driver; + unsigned long resource, len; + void *base; + u8 latency, limit; + struct usb_bus *bus; + struct usb_hcd *hcd; + int retval, region; + char buf [8], *bufp = buf; + + if (!id || !(driver = (struct hc_driver *) id->driver_data)) + return -EINVAL; + + if (pci_enable_device (dev) < 0) + return -ENODEV; + + if (!dev->irq) { + err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", + dev->slot_name); + return -ENODEV; + } + + if (driver->flags & HCD_MEMORY) { // EHCI, OHCI + region = 0; + resource = pci_resource_start (dev, 0); + len = pci_resource_len (dev, 0); + if (!request_mem_region (resource, len, driver->description)) { + dbg ("controller already in use"); + return -EBUSY; + } + base = ioremap_nocache (resource, len); + if (base == NULL) { + dbg ("error mapping memory"); + retval = -EFAULT; +clean_1: + release_mem_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + + } else { // UHCI + resource = len = 0; + for (region = 0; region < PCI_ROM_RESOURCE; region++) { + if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) + continue; + + resource = pci_resource_start (dev, region); + len = pci_resource_len (dev, region); + if (request_region (resource, len, + driver->description)) + break; + } + if (region == PCI_ROM_RESOURCE) { + dbg ("no i/o regions available"); + return -EBUSY; + } + base = (void *) resource; + } + + // driver->start(), later on, will transfer device from + // control by SMM/BIOS to control by Linux (if needed) + + pci_set_master (dev); + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd alloc fail"); + retval = -ENOMEM; +clean_2: + if (driver->flags & HCD_MEMORY) { + iounmap (base); + goto clean_1; + } else { + release_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + } + dev->driver_data = hcd; + hcd->driver = driver; + hcd->description = driver->description; + hcd->pdev = dev; + info ("%s @ %s, %s", hcd->description, dev->slot_name, dev->name); + + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte (dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) { + dbg ("PCI latency reduced to max %d", limit); + pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); + } + } + +#ifndef __sparc__ + sprintf (buf, "%d", dev->irq); +#else + bufp = __irq_itoa(dev->irq); +#endif + if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd) + != 0) { + err ("request interrupt %s failed", bufp); + retval = -EBUSY; +clean_3: + driver->hcd_free (hcd); + goto clean_2; + } + hcd->irq = dev->irq; + + hcd->regs = base; + hcd->region = region; + info ("irq %s, %s %p", bufp, + (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", + base); + +// FIXME simpler: make "bus" be that data, not pointer to it. + bus = usb_alloc_bus (&hcd_operations); + if (bus == NULL) { + dbg ("usb_alloc_bus fail"); + retval = -ENOMEM; + free_irq (dev->irq, hcd); + goto clean_3; + } + hcd->bus = bus; + hcd->bus_name = dev->slot_name; + bus->hcpriv = (void *) hcd; + + INIT_LIST_HEAD (&hcd->dev_list); + INIT_LIST_HEAD (&hcd->hcd_list); + + down (&hcd_list_lock); + list_add (&hcd->hcd_list, &hcd_list); + up (&hcd_list_lock); + + usb_register_bus (bus); + + if ((retval = driver->start (hcd)) < 0) + usb_hcd_pci_remove (dev); + + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_probe); + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs + * @dev: USB Host Controller being removed + * + * Reverses the effect of usb_hcd_pci_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + * Store this function in the HCD's struct pci_driver as remove(). + */ +void usb_hcd_pci_remove (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + struct usb_device *hub; + + hcd = (struct usb_hcd *) dev->driver_data; + if (!hcd) + return; + info ("remove: %s, state %x", hcd->bus_name, hcd->state); + + if (in_interrupt ()) BUG (); + + hub = hcd->bus->root_hub; + hcd->state = USB_STATE_QUIESCING; + + dbg ("%s: roothub graceful disconnect", hcd->bus_name); + usb_disconnect (&hub); + // usb_disconnect (&hcd->bus->root_hub); + + hcd->driver->stop (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + if (hcd->driver->flags & HCD_MEMORY) { + iounmap (hcd->regs); + release_mem_region (pci_resource_start (dev, 0), + pci_resource_len (dev, 0)); + } else { + release_region (pci_resource_start (dev, hcd->region), + pci_resource_len (dev, hcd->region)); + } + + down (&hcd_list_lock); + list_del (&hcd->hcd_list); + up (&hcd_list_lock); + + usb_deregister_bus (hcd->bus); + usb_free_bus (hcd->bus); + hcd->bus = NULL; + + hcd->driver->hcd_free (hcd); +} +EXPORT_SYMBOL (usb_hcd_pci_remove); + + +#ifdef CONFIG_PM + +/* + * Some "sleep" power levels imply updating struct usb_driver + * to include a callback asking hcds to do their bit by checking + * if all the drivers can suspend. Gets involved with remote wakeup. + * + * If there are pending urbs, then HCs will need to access memory, + * causing extra power drain. New sleep()/wakeup() PM calls might + * be needed, beyond PCI suspend()/resume(). The root hub timer + * still be accessing memory though ... + * + * FIXME: USB should have some power budgeting support working with + * all kinds of hubs. + * + * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. + * D1 and D2 states should do something, yes? + * + * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() + * for all supported states, so that USB remote wakeup can work for any + * devices that support it (and are connected via powered hubs). + * + * FIXME: resume doesn't seem to work right any more... + */ + + +// 2.4 kernels have issued concurrent resumes (w/APM) +// we defend against that error; PCI doesn't yet. + +/** + * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD + * @dev: USB Host Controller being suspended + * + * Store this function in the HCD's struct pci_driver as suspend(). + */ +int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) +{ + struct usb_hcd *hcd; + int retval; + + hcd = (struct usb_hcd *) dev->driver_data; + info ("suspend %s to state %d", hcd->bus_name, state); + + pci_save_state (dev, hcd->pci_state); + + // FIXME for all connected devices, leaf-to-root: + // driver->suspend() + // proposed "new 2.5 driver model" will automate that + + /* driver may want to disable DMA etc */ + retval = hcd->driver->suspend (hcd, state); + hcd->state = USB_STATE_SUSPENDED; + + pci_set_power_state (dev, state); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_suspend); + +/** + * usb_hcd_pci_resume - power management resume of a PCI-based HCD + * @dev: USB Host Controller being resumed + * + * Store this function in the HCD's struct pci_driver as resume(). + */ +int usb_hcd_pci_resume (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + int retval; + + hcd = (struct usb_hcd *) dev->driver_data; + info ("resume %s", hcd->bus_name); + + /* guard against multiple resumes (APM bug?) */ + atomic_inc (&hcd->resume_count); + if (atomic_read (&hcd->resume_count) != 1) { + err ("concurrent PCI resumes for %s", hcd->bus_name); + retval = 0; + goto done; + } + + retval = -EBUSY; + if (hcd->state != USB_STATE_SUSPENDED) { + dbg ("can't resume, not suspended!"); + goto done; + } + hcd->state = USB_STATE_RESUMING; + + pci_set_power_state (dev, 0); + pci_restore_state (dev, hcd->pci_state); + + retval = hcd->driver->resume (hcd); + if (!HCD_IS_RUNNING (hcd->state)) { + dbg ("resume %s failure, retval %d", hcd->bus_name, retval); + hc_died (hcd); +// FIXME: recover, reset etc. + } else { + // FIXME for all connected devices, root-to-leaf: + // driver->resume (); + // proposed "new 2.5 driver model" will automate that + } + +done: + atomic_dec (&hcd->resume_count); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_resume); + +#endif /* CONFIG_PM */ + +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * Generic HC operations. + */ + +/*-------------------------------------------------------------------------*/ + +/* called from khubd, or root hub init threads for hcd-private init */ +static int hcd_alloc_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || udev->hcpriv) + return -EINVAL; + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + hcd = udev->bus->hcpriv; + if (hcd->state == USB_STATE_QUIESCING) + return -ENOLINK; + + dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + + INIT_LIST_HEAD (&dev->dev_list); + INIT_LIST_HEAD (&dev->urb_list); + + spin_lock_irqsave (&hcd_data_lock, flags); + list_add (&dev->dev_list, &hcd->dev_list); + // refcount is implicit + udev->hcpriv = dev; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void hc_died (struct usb_hcd *hcd) +{ + struct list_head *devlist, *urblist; + struct hcd_dev *dev; + struct urb *urb; + unsigned long flags; + + /* flag every pending urb as done */ + spin_lock_irqsave (&hcd_data_lock, flags); + list_for_each (devlist, &hcd->dev_list) { + dev = list_entry (devlist, struct hcd_dev, dev_list); + list_for_each (urblist, &dev->urb_list) { + urb = list_entry (urblist, struct urb, urb_list); + dbg ("shutdown %s urb %p pipe %x, current status %d", + hcd->bus_name, urb, urb->pipe, urb->status); + if (urb->status == -EINPROGRESS) + urb->status = -ESHUTDOWN; + } + } + urb = (struct urb *) hcd->rh_timer.data; + if (urb) + urb->status = -ESHUTDOWN; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + if (urb) + rh_status_dequeue (hcd, urb); + hcd->driver->stop (hcd); +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount */ +/* caller surrenders "ownership" of urb (and chain at urb->next). */ + +static int hcd_submit_urb (struct urb *urb) +{ + int status; + struct usb_hcd *hcd; + struct hcd_dev *dev; + unsigned long flags; + int pipe; + int mem_flags; + + if (!urb || urb->hcpriv || !urb->complete) + return -EINVAL; + + urb->status = -EINPROGRESS; + urb->actual_length = 0; + INIT_LIST_HEAD (&urb->urb_list); + + if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0) + return -ENODEV; + hcd = urb->dev->bus->hcpriv; + dev = urb->dev->hcpriv; + if (!hcd || !dev) + return -ENODEV; + + /* can't submit new urbs when quiescing, halted, ... */ + if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state)) + return -ESHUTDOWN; + pipe = urb->pipe; + if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), + usb_pipeout (pipe))) + return -EPIPE; + + // FIXME paging/swapping requests over USB should not use GFP_KERNEL + // and might even need to use GFP_NOIO ... that flag actually needs + // to be passed from the higher level. + mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; + +#ifdef DEBUG + { + unsigned int orig_flags = urb->transfer_flags; + unsigned int allowed; + + /* enforce simple/standard policy */ + allowed = USB_ASYNC_UNLINK; // affects later unlinks + allowed |= USB_NO_FSBR; // only affects UHCI + switch (usb_pipetype (pipe)) { + case PIPE_CONTROL: + allowed |= USB_DISABLE_SPD; + break; + case PIPE_BULK: + allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK + | USB_ZERO_PACKET | URB_NO_INTERRUPT; + break; + case PIPE_INTERRUPT: + allowed |= USB_DISABLE_SPD; + break; + case PIPE_ISOCHRONOUS: + allowed |= USB_ISO_ASAP; + break; + } + urb->transfer_flags &= allowed; + + /* warn if submitter gave bogus flags */ + if (urb->transfer_flags != orig_flags) + warn ("BOGUS urb flags, %x --> %x", + orig_flags, urb->transfer_flags); + } +#endif + /* + * FIXME: alloc periodic bandwidth here, for interrupt and iso? + * Need to look at the ring submit mechanism for iso tds ... they + * aren't actually "periodic" in 2.4 kernels. + * + * FIXME: make urb timeouts be generic, keeping the HCD cores + * as simple as possible. + */ + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) + // It would catch submission paths for all urbs. + + /* + * Atomically queue the urb, first to our records, then to the HCD. + * Access to urb->status is controlled by urb->lock ... changes on + * i/o completion (normal or fault) or unlinking. + */ + + // FIXME: verify that quiescing hc works right (RH cleans up) + + spin_lock_irqsave (&hcd_data_lock, flags); + if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { + usb_inc_dev_use (urb->dev); + list_add (&urb->urb_list, &dev->urb_list); + status = 0; + } else { + INIT_LIST_HEAD (&urb->urb_list); + status = -ESHUTDOWN; + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + + if (!status) { + if (urb->dev == hcd->bus->root_hub) + status = rh_urb_enqueue (hcd, urb); + else + status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); + } + if (status) { + if (urb->dev) { + urb->status = status; + usb_hcd_giveback_urb (hcd, urb); + } + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* called in any context */ +static int hcd_get_frame_number (struct usb_device *udev) +{ + struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + return hcd->driver->get_frame_number (hcd); +} + +/*-------------------------------------------------------------------------*/ + +struct completion_splice { // modified urb context: + /* did we complete? */ + int done; + + /* original urb data */ + void (*complete)(struct urb *); + void *context; +}; + +static void unlink_complete (struct urb *urb) +{ + struct completion_splice *splice; + + splice = (struct completion_splice *) urb->context; + + /* issue original completion call */ + urb->complete = splice->complete; + urb->context = splice->context; + urb->complete (urb); + + splice->done = 1; +} + +/* + * called in any context; note ASYNC_UNLINK restrictions + * + * caller guarantees urb won't be recycled till both unlink() + * and the urb's completion function return + */ +static int hcd_unlink_urb (struct urb *urb) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd = 0; + unsigned long flags; + struct completion_splice splice; + int retval; + + if (!urb) + return -EINVAL; + + // FIXME: add some explicit records to flag the + // state where the URB is "in periodic completion". + // Workaround is for driver to set the urb status + // to "-EINPROGRESS", so it can get through here + // and unlink from the completion handler. + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + */ + spin_lock_irqsave (&urb->lock, flags); + if (!urb->hcpriv + || urb->status != -EINPROGRESS + || urb->transfer_flags & USB_TIMEOUT_KILLED) { + retval = -EINVAL; + goto done; + } + + if (!urb->dev || !urb->dev->bus) { + retval = -ENODEV; + goto done; + } + dev = urb->dev->hcpriv; + hcd = urb->dev->bus->hcpriv; + if (!dev || !hcd) { + retval = -ENODEV; + goto done; + } + + /* maybe set up to block on completion notification */ + if ((urb->transfer_flags & USB_TIMEOUT_KILLED)) + urb->status = -ETIMEDOUT; + else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { + if (in_interrupt ()) { + dbg ("non-async unlink in_interrupt"); + retval = -EWOULDBLOCK; + goto done; + } + /* synchronous unlink: block till we see the completion */ + splice.done = 0; + splice.complete = urb->complete; + splice.context = urb->context; + urb->complete = unlink_complete; + urb->context = &splice; + urb->status = -ENOENT; + } else { + /* asynchronous unlink */ + urb->status = -ECONNRESET; + } + spin_unlock_irqrestore (&urb->lock, flags); + + if (urb == (struct urb *) hcd->rh_timer.data) { + rh_status_dequeue (hcd, urb); + retval = 0; + } else { + retval = hcd->driver->urb_dequeue (hcd, urb); +// FIXME: if retval and we tried to splice, whoa!! +if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval); + } + + /* block till giveback, if needed */ + if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED)) + && HCD_IS_RUNNING (hcd->state) + && !retval) { + while (!splice.done) { + set_current_state (TASK_UNINTERRUPTIBLE); + schedule_timeout ((2/*msec*/ * HZ) / 1000); + dbg ("%s: wait for giveback urb %p", + hcd->bus_name, urb); + } + } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) { + return -EINPROGRESS; + } + goto bye; +done: + spin_unlock_irqrestore (&urb->lock, flags); +bye: + if (retval) + dbg ("%s: hcd_unlink_urb fail %d", + hcd ? hcd->bus_name : "(no bus?)", + retval); + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */ + +// FIXME: likely best to have explicit per-setting (config+alt) +// setup primitives in the usbcore-to-hcd driver API, so nothing +// is implicit. kernel 2.5 needs a bunch of config cleanup... + +static int hcd_free_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || !udev->hcpriv) + return -EINVAL; + + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + + // should udev->devnum == -1 ?? + + dev = udev->hcpriv; + hcd = udev->bus->hcpriv; + + /* device driver problem with refcounts? */ + if (!list_empty (&dev->urb_list)) { + dbg ("free busy dev, %s devnum %d (bug!)", + hcd->bus_name, udev->devnum); + return -EINVAL; + } + + hcd->driver->free_config (hcd, udev); + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del (&dev->dev_list); + udev->hcpriv = NULL; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + kfree (dev); + return 0; +} + +static struct usb_operations hcd_operations = { + allocate: hcd_alloc_dev, + get_frame_number: hcd_get_frame_number, + submit_urb: hcd_submit_urb, + unlink_urb: hcd_unlink_urb, + deallocate: hcd_free_dev, +}; + +/*-------------------------------------------------------------------------*/ + +static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + int start = hcd->state; + + hcd->driver->irq (hcd); + if (hcd->state != start && hcd->state == USB_STATE_HALT) + hc_died (hcd); +} + +/*-------------------------------------------------------------------------*/ + +/** + * usb_hcd_giveback_urb - return URB from HCD to device driver + * @hcd: host controller returning the URB + * @urb: urb being returned to the USB device driver. + * + * This hands the URB from HCD to its USB device driver, using its + * completion function. The HCD has freed all per-urb resources + * (and is done using urb->hcpriv). It also released all HCD locks; + * the device driver won't cause deadlocks if it resubmits this URB, + * and won't confuse things by modifying and resubmitting this one. + * Bandwidth and other resources will be deallocated. + * + * HCDs must not use this for periodic URBs that are still scheduled + * and will be reissued. They should just call their completion handlers + * until the urb is returned to the device driver by unlinking. + * + * In common cases, urb->next will be submitted before the completion + * function gets called. That's not done if the URB includes error + * status (including unlinking). + */ +void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; + struct usb_device *dev; + + /* Release periodic transfer bandwidth */ + if (urb->bandwidth) { + switch (usb_pipetype (urb->pipe)) { + case PIPE_INTERRUPT: + usb_release_bandwidth (urb->dev, urb, 0); + break; + case PIPE_ISOCHRONOUS: + usb_release_bandwidth (urb->dev, urb, 1); + break; + } + } + + /* clear all state linking urb to this dev (and hcd) */ + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del_init (&urb->urb_list); + dev = urb->dev; + urb->dev = NULL; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) + // It would catch exit/unlink paths for all urbs, but non-exit + // completions for periodic urbs need hooks inside the HCD. + // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) + + if (urb->status) + dbg ("giveback urb %p status %d", urb, urb->status); + + /* if no error, make sure urb->next progresses */ + else if (urb->next) { + int status; + + status = usb_submit_urb (urb->next); + if (status) { + dbg ("urb %p chain fail, %d", urb->next, status); + urb->next->status = -ENOTCONN; + } + + /* HCDs never modify the urb->next chain, and only use it here, + * so that if urb->complete sees an URB there with -ENOTCONN, + * it knows the driver chained it but it couldn't be submitted. + */ + } + + /* pass ownership to the completion handler */ + usb_dec_dev_use (dev); + urb->complete (urb); +} +EXPORT_SYMBOL (usb_hcd_giveback_urb); diff -urN linux-2.4.18/drivers/usb/hcd.h linux-2.4.19-pre5/drivers/usb/hcd.h --- linux-2.4.18/drivers/usb/hcd.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.19-pre5/drivers/usb/hcd.h Sat Mar 30 22:55:29 2002 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver (usb_hcd) framework + * + * Since "struct usb_bus" is so thin, you can't share much code in it. + * This framework is a layer over that, and should be more sharable. + */ + +/*-------------------------------------------------------------------------*/ + +struct usb_hcd { /* usb_bus.hcpriv points to this */ + + /* + * housekeeping + */ + struct usb_bus *bus; /* hcd is-a bus */ + struct list_head hcd_list; + + const char *bus_name; + + const char *description; /* "ehci-hcd" etc */ + + struct timer_list rh_timer; /* drives root hub */ + struct list_head dev_list; /* devices on this bus */ + + /* + * hardware info/state + */ + struct hc_driver *driver; /* hw-specific hooks */ + int irq; /* irq allocated */ + void *regs; /* device memory/io */ + +#ifdef CONFIG_PCI + /* a few non-PCI controllers exist, mostly for OHCI */ + struct pci_dev *pdev; /* pci is typical */ + int region; /* pci region for regs */ + u32 pci_state [16]; /* for PM state save */ + atomic_t resume_count; /* multiple resumes issue */ +#endif + + int state; +# define __ACTIVE 0x01 +# define __SLEEPY 0x02 +# define __SUSPEND 0x04 +# define __TRANSIENT 0x80 + +# define USB_STATE_HALT 0 +# define USB_STATE_RUNNING (__ACTIVE) +# define USB_STATE_READY (__ACTIVE|__SLEEPY) +# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) +# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT) +# define USB_STATE_SUSPENDED (__SUSPEND) + +#define HCD_IS_RUNNING(state) ((state) & __ACTIVE) +#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND) + + /* more shared queuing code would be good; it should support + * smarter scheduling, handle transaction translators, etc; + * input size of periodic table to an interrupt scheduler. + * (ohci 32, uhci 1024, ehci 256/512/1024). + */ +}; + +struct hcd_dev { /* usb_device.hcpriv points to this */ + struct list_head dev_list; /* on this hcd */ + struct list_head urb_list; /* pending on this dev */ + + /* per-configuration HC/HCD state, such as QH or ED */ + void *ep[32]; +}; + +// urb.hcpriv is really hardware-specific + +struct hcd_timeout { /* timeouts we allocate */ + struct list_head timeout_list; + struct timer_list timer; +}; + +/*-------------------------------------------------------------------------*/ + +/* each driver provides one of these, and hardware init support */ + +struct hc_driver { + const char *description; /* "ehci-hcd" etc */ + + /* irq handler */ + void (*irq) (struct usb_hcd *hcd); + + int flags; +#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_USB11 0x0010 /* USB 1.1 */ +#define HCD_USB2 0x0020 /* USB 2.0 */ + + /* called to init HCD and root hub */ + int (*start) (struct usb_hcd *hcd); + + /* called after all devices were suspended */ + int (*suspend) (struct usb_hcd *hcd, u32 state); + + /* called before any devices get resumed */ + int (*resume) (struct usb_hcd *hcd); + + /* cleanly make HCD stop writing memory and doing I/O */ + void (*stop) (struct usb_hcd *hcd); + + /* return current frame number */ + int (*get_frame_number) (struct usb_hcd *hcd); + +// FIXME: rework generic-to-specific HCD linkage (specific contains generic) + + /* memory lifecycle */ + struct usb_hcd *(*hcd_alloc) (void); + void (*hcd_free) (struct usb_hcd *hcd); + + /* manage i/o requests, device state */ + int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, + int mem_flags); + int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + + // frees configuration resources -- allocated as needed during + // urb_enqueue, and not freed by urb_dequeue + void (*free_config) (struct usb_hcd *hcd, + struct usb_device *dev); + + /* root hub support */ + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, + char *buf, u16 wLength); +}; + +extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); + +#ifdef CONFIG_PCI + +extern int usb_hcd_pci_probe (struct pci_dev *dev, + const struct pci_device_id *id); +extern void usb_hcd_pci_remove (struct pci_dev *dev); + +#ifdef CONFIG_PM +// FIXME: see Documentation/power/pci.txt (2.4.6 and later?) +// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_resume (struct pci_dev *dev); +// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg); +#endif /* CONFIG_PM */ + +#endif /* CONFIG_PCI */ + +/*-------------------------------------------------------------------------*/ + +/* + * HCD Root Hub support + */ + +#include "hub.h" + +/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ +#define DeviceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define DeviceOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) + +#define InterfaceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +#define EndpointRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define EndpointOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +/* table 9.6 standard features */ +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 0 + +/* class requests from the USB 2.0 hub spec, table 11-15 */ +/* GetBusState and SetHubDescriptor are optional, omitted */ +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + + +/*-------------------------------------------------------------------------*/ + +/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ +// bleech -- resurfaced in 2.4.11 or 2.4.12 +#define bitmap DeviceRemovable + + +/*-------------------------------------------------------------------------*/ + +/* random stuff */ + +#define RUN_CONTEXT (in_irq () ? "in_irq" \ + : (in_interrupt () ? "in_interrupt" : "can sleep")) diff -urN linux-2.4.18/drivers/usb/hid-core.c linux-2.4.19-pre5/drivers/usb/hid-core.c --- linux-2.4.18/drivers/usb/hid-core.c Sun Dec 23 16:23:49 2001 +++ linux-2.4.19-pre5/drivers/usb/hid-core.c Sat Mar 30 22:55:40 2002 @@ -897,6 +897,9 @@ u8 data[len]; int read; + if (hid->quirks & HID_QUIRK_NOGET) + return; + if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) { dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read); return; @@ -1076,16 +1079,25 @@ #define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 +#define USB_VENDOR_ID_ATEN 0x0557 +#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 +#define USB_DEVICE_ID_ATEN_CS124U 0x2202 +#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; + unsigned quirks; } hid_blacklist[] = { - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { 0, 0 } }; @@ -1094,13 +1106,17 @@ struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; struct hid_device *hid; - unsigned rsize = 0; + unsigned quirks = 0, rsize = 0; char *buf; int n; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; + (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) + quirks = hid_blacklist[n].quirks; + + if (quirks & HID_QUIRK_IGNORE) + return NULL; if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc))) { @@ -1137,6 +1153,8 @@ return NULL; } } + + hid->quirks = quirks; for (n = 0; n < interface->bNumEndpoints; n++) { diff -urN linux-2.4.18/drivers/usb/hid.h linux-2.4.19-pre5/drivers/usb/hid.h --- linux-2.4.18/drivers/usb/hid.h Sat Mar 30 13:53:37 2002 +++ linux-2.4.19-pre5/drivers/usb/hid.h Sat Mar 30 22:55:40 2002 @@ -184,6 +184,8 @@ #define HID_QUIRK_INVERT 0x01 #define HID_QUIRK_NOTOUCH 0x02 +#define HID_QUIRK_IGNORE 0x04 +#define HID_QUIRK_NOGET 0x08 /* * This is the global enviroment of the parser. This information is diff -urN linux-2.4.18/drivers/usb/hpusbscsi.c linux-2.4.19-pre5/drivers/usb/hpusbscsi.c --- linux-2.4.18/drivers/usb/hpusbscsi.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/hpusbscsi.c Sat Mar 30 22:55:40 2002 @@ -120,6 +120,9 @@ if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl))) goto err_out; + new->sense_command[0] = REQUEST_SENSE; + new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH; + /* adding to list for module unload */ list_add (&hpusbscsi_devices, &new->lh); @@ -163,7 +166,6 @@ int result; INIT_LIST_HEAD (&hpusbscsi_devices); - DEBUG ("Driver loaded\n"); if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) { printk (KERN_ERR "hpusbscsi: driver registration failed\n"); @@ -185,7 +187,8 @@ tmp = tmp->next; o = (struct hpusbscsi *)old; usb_unlink_urb(&o->controlurb); - scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl); + if(scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl)<0) + printk(KERN_CRIT"Deregistering failed!\n"); kfree(old); } @@ -270,7 +273,13 @@ /* Now we need to decide which callback to give to the urb we send the command with */ if (!srb->bufflen) { - usb_callback = simple_command_callback; + if (srb->cmnd[0] == REQUEST_SENSE){ + /* the usual buffer is not used, needs a special case */ + hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in); + usb_callback = request_sense_callback; + } else { + usb_callback = simple_command_callback; + } } else { if (srb->use_sg) { usb_callback = scatter_gather_callback; @@ -332,8 +341,8 @@ struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]); printk(KERN_DEBUG"SCSI reset requested.\n"); - usb_reset_device(hpusbscsi->dev); - printk(KERN_DEBUG"SCSI reset completed.\n"); + //usb_reset_device(hpusbscsi->dev); + //printk(KERN_DEBUG"SCSI reset completed.\n"); hpusbscsi->state = HP_STATE_FREE; return 0; @@ -342,10 +351,9 @@ static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb) { struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]); - printk(KERN_DEBUG"Requested is canceled.\n"); + printk(KERN_DEBUG"Request is canceled.\n"); usb_unlink_urb(&hpusbscsi->dataurb); - usb_unlink_urb(&hpusbscsi->controlurb); hpusbscsi->state = HP_STATE_FREE; return SCSI_ABORT_PENDING; @@ -365,6 +373,7 @@ static void control_interrupt_callback (struct urb *u) { struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; + u8 scsi_state; DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte); if(u->status < 0) { @@ -372,10 +381,23 @@ handle_usb_error(hpusbscsi); return; } - hpusbscsi->srb->result &= SCSI_ERR_MASK; - hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte<<1; - if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT) + scsi_state = hpusbscsi->scsi_state_byte; + if (hpusbscsi->state != HP_STATE_ERROR) { + hpusbscsi->srb->result &= SCSI_ERR_MASK; + hpusbscsi->srb->result |= scsi_state; + } + + if (scsi_state == CHECK_CONDITION << 1) { + if (hpusbscsi->state == HP_STATE_WAIT) { + issue_request_sense(hpusbscsi); + } else { + /* we request sense after an eventual data transfer */ + hpusbscsi->state = HP_STATE_ERROR; + } + } + + if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1) /* we do a callback to the scsi layer if and only if all data has been transfered */ hpusbscsi->scallback(hpusbscsi->srb); @@ -390,6 +412,8 @@ hpusbscsi->state = HP_STATE_PREMATURE; TRACE_STATE; break; + case HP_STATE_ERROR: + break; default: printk(KERN_ERR"hpusbscsi: Unexpected status report.\n"); TRACE_STATE; @@ -453,7 +477,7 @@ res = usb_submit_urb(u); if (res) - hpusbscsi->state = HP_STATE_ERROR; + handle_usb_error(hpusbscsi); TRACE_STATE; } @@ -468,11 +492,16 @@ DEBUG("Data transfer done\n"); TRACE_STATE; if (hpusbscsi->state != HP_STATE_PREMATURE) { - if (u->status < 0) - hpusbscsi->state = HP_STATE_ERROR; - else - hpusbscsi->state = HP_STATE_WAIT; + if (u->status < 0) { + handle_usb_error(hpusbscsi); + } else { + if (hpusbscsi->state != HP_STATE_ERROR) { + hpusbscsi->state = HP_STATE_WAIT; + } else { + issue_request_sense(hpusbscsi); + } TRACE_STATE; + } } else { if (hpusbscsi->scallback != NULL) hpusbscsi->scallback(hpusbscsi->srb); @@ -509,11 +538,51 @@ if (hpusbscsi->state != HP_STATE_PREMATURE) { hpusbscsi->state = HP_STATE_WORKING; TRACE_STATE; - } else { - if (hpusbscsi->scallback != NULL) - hpusbscsi->scallback(hpusbscsi->srb); - hpusbscsi->state = HP_STATE_FREE; - TRACE_STATE; } } +static void request_sense_callback (struct urb *u) +{ + struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; + + if (u->status<0) { + handle_usb_error(hpusbscsi); + return; + } + + FILL_BULK_URB( + u, + hpusbscsi->dev, + hpusbscsi->current_data_pipe, + hpusbscsi->srb->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + simple_done, + hpusbscsi + ); + + if (0 > usb_submit_urb(u)) { + handle_usb_error(hpusbscsi); + return; + } + if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR) + hpusbscsi->state = HP_STATE_WORKING; +} + +static void issue_request_sense (struct hpusbscsi *hpusbscsi) +{ + FILL_BULK_URB( + &hpusbscsi->dataurb, + hpusbscsi->dev, + usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out), + &hpusbscsi->sense_command, + SENSE_COMMAND_SIZE, + request_sense_callback, + hpusbscsi + ); + + hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in); + + if (0 > usb_submit_urb(&hpusbscsi->dataurb)) { + handle_usb_error(hpusbscsi); + } +} diff -urN linux-2.4.18/drivers/usb/hpusbscsi.h linux-2.4.19-pre5/drivers/usb/hpusbscsi.h --- linux-2.4.18/drivers/usb/hpusbscsi.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/hpusbscsi.h Sat Mar 30 22:55:40 2002 @@ -4,9 +4,14 @@ /* large parts based on or taken from code by John Fremlin and Matt Dharm */ /* this file is licensed under the GPL */ +/* A big thanks to Jose for untiring testing */ + typedef void (*usb_urb_callback) (struct urb *); typedef void (*scsi_callback)(Scsi_Cmnd *); +#define SENSE_COMMAND_SIZE 6 +#define HPUSBSCSI_SENSE_LENGTH 0x16 + struct hpusbscsi { struct list_head lh; @@ -21,6 +26,7 @@ int number; scsi_callback scallback; Scsi_Cmnd *srb; + u8 sense_command[SENSE_COMMAND_SIZE]; int use_count; wait_queue_head_t pending; @@ -51,11 +57,13 @@ static void simple_command_callback(struct urb *u); static void scatter_gather_callback(struct urb *u); static void simple_payload_callback (struct urb *u); -static void control_interrupt_callback (struct urb *u); +static void control_interrupt_callback (struct urb *u); +static void request_sense_callback (struct urb *u); static void simple_done (struct urb *u); static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback); static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb); static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb); +static void issue_request_sense (struct hpusbscsi *hpusbscsi); static Scsi_Host_Template hpusbscsi_scsi_host_template = { name: "hpusbscsi", diff -urN linux-2.4.18/drivers/usb/hub.c linux-2.4.19-pre5/drivers/usb/hub.c --- linux-2.4.18/drivers/usb/hub.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/hub.c Sat Mar 30 22:55:40 2002 @@ -217,9 +217,12 @@ break; case 1: dbg("Single TT"); + hub->tt.hub = dev; break; case 2: - dbg("Multiple TT"); + dbg("TT per port"); + hub->tt.hub = dev; + hub->tt.multi = 1; break; default: dbg("Unrecognized hub protocol %d", @@ -496,6 +499,29 @@ err("cannot disconnect hub %d", dev->devnum); } +static int usb_hub_port_status(struct usb_device *hub, int port, + u16 *status, u16 *change) +{ + struct usb_port_status *portsts; + int ret = -ENOMEM; + + portsts = kmalloc(sizeof(*portsts), GFP_KERNEL); + if (portsts) { + ret = usb_get_port_status(hub, port + 1, portsts); + if (ret < 0) + err("%s (%d) failed (err = %d)", __FUNCTION__, hub->devnum, ret); + else { + *status = le16_to_cpu(portsts->wPortStatus); + *change = le16_to_cpu(portsts->wPortChange); + dbg("port %d, portstatus %x, change %x, %s", port + 1, + *status, *change, portspeed(*status)); + ret = 0; + } + kfree(portsts); + } + return ret; +} + #define HUB_RESET_TRIES 5 #define HUB_PROBE_TRIES 2 #define HUB_SHORT_RESET_TIME 10 @@ -507,24 +533,22 @@ struct usb_device *dev, unsigned int delay) { int delay_time, ret; - struct usb_port_status portsts; - unsigned short portchange, portstatus; + u16 portstatus; + u16 portchange; for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) { /* wait to give the device a chance to reset */ wait_ms(delay); /* read and decode port status */ - ret = usb_get_port_status(hub, port + 1, &portsts); + ret = usb_hub_port_status(hub, port, &portstatus, &portchange); if (ret < 0) { - err("get_port_status(%d) failed (err = %d)", port + 1, ret); return -1; } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - dbg("port %d, portstatus %x, change %x, %s", port + 1, - portstatus, portchange, portspeed (portstatus)); + /* Device went away? */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) + return 1; /* bomb out completely if something weird happened */ if ((portchange & USB_PORT_STAT_C_CONNECTION)) @@ -592,17 +616,58 @@ port + 1, hub->devnum, ret); } -static void usb_hub_port_connect_change(struct usb_device *hub, int port, - struct usb_port_status *portsts) +/* USB 2.0 spec, 7.1.7.3 / fig 7-29: + * + * Between connect detection and reset signaling there must be a delay + * of 100ms at least for debounce and power-settling. The corresponding + * timer shall restart whenever the downstream port detects a disconnect. + * + * Apparently there are some bluetooth and irda-dongles and a number + * of low-speed devices which require longer delays of about 200-400ms. + * Not covered by the spec - but easy to deal with. + * + * This implementation uses 400ms minimum debounce timeout and checks + * every 100ms for transient disconnects to restart the delay. + */ + +#define HUB_DEBOUNCE_TIMEOUT 400 +#define HUB_DEBOUNCE_STEP 100 + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int usb_hub_port_debounce(struct usb_device *hub, int port) { + int ret; + unsigned delay_time; + u16 portchange, portstatus; + + for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; /* empty */ ) { + + /* wait debounce step increment */ + wait_ms(HUB_DEBOUNCE_STEP); + + ret = usb_hub_port_status(hub, port, &portstatus, &portchange); + if (ret < 0) + return -1; + + if ((portchange & USB_PORT_STAT_C_CONNECTION)) { + usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); + delay_time = 0; + } + else + delay_time += HUB_DEBOUNCE_STEP; + } + return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; +} + +static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, + u16 portstatus, u16 portchange) +{ + struct usb_device *hub = hubstate->dev; struct usb_device *dev; - unsigned short portstatus, portchange; unsigned int delay = HUB_SHORT_RESET_TIME; int i; char *portstr, *tempstr; - portstatus = le16_to_cpu(portsts->wPortStatus); - portchange = le16_to_cpu(portsts->wPortChange); dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus, portchange, portspeed (portstatus)); @@ -621,11 +686,10 @@ return; } - /* Some low speed devices have problems with the quick delay, so */ - /* be a bit pessimistic with those devices. RHbug #23670 */ - if (portstatus & USB_PORT_STAT_LOW_SPEED) { - wait_ms(400); - delay = HUB_LONG_RESET_TIME; + if (usb_hub_port_debounce(hub, port)) { + err("connect-debounce failed, port %d disabled", port+1); + usb_hub_port_disable(hub, port); + return; } down(&usb_address0_sem); @@ -654,6 +718,16 @@ /* Find a new device ID for it */ usb_connect(dev); + /* Set up TT records, if needed */ + if (hub->tt) { + dev->tt = hub->tt; + dev->ttport = hub->ttport; + } else if (dev->speed != USB_SPEED_HIGH + && hub->speed == USB_SPEED_HIGH) { + dev->tt = &hubstate->tt; + dev->ttport = port + 1; + } + /* Create a readable topology string */ cdev = dev; pdev = dev->parent; @@ -709,7 +783,10 @@ struct usb_device *dev; struct usb_hub *hub; struct usb_hub_status hubsts; - unsigned short hubstatus, hubchange; + u16 hubstatus; + u16 hubchange; + u16 portstatus; + u16 portchange; int i, ret; /* @@ -751,22 +828,15 @@ } for (i = 0; i < hub->descriptor->bNbrPorts; i++) { - struct usb_port_status portsts; - unsigned short portstatus, portchange; - - ret = usb_get_port_status(dev, i + 1, &portsts); + ret = usb_hub_port_status(dev, i, &portstatus, &portchange); if (ret < 0) { - err("get_port_status failed (err = %d)", ret); continue; } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - if (portchange & USB_PORT_STAT_C_CONNECTION) { dbg("port %d connection change", i + 1); - usb_hub_port_connect_change(dev, i, &portsts); + usb_hub_port_connect_change(hub, i, portstatus, portchange); } else if (portchange & USB_PORT_STAT_C_ENABLE) { dbg("port %d enable change, status %x", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); @@ -780,7 +850,7 @@ (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { err("already running port %i disabled by hub (EMI?), re-enabling...", i + 1); - usb_hub_port_connect_change(dev, i, &portsts); + usb_hub_port_connect_change(hub, i, portstatus, portchange); } } @@ -834,6 +904,7 @@ */ daemonize(); + reparent_to_init(); /* Setup a nice name */ strcpy(current->comm, "khubd"); diff -urN linux-2.4.18/drivers/usb/hub.h linux-2.4.19-pre5/drivers/usb/hub.h --- linux-2.4.18/drivers/usb/hub.h Thu Jan 24 23:59:46 2002 +++ linux-2.4.19-pre5/drivers/usb/hub.h Sat Mar 30 22:55:29 2002 @@ -2,6 +2,7 @@ #define __LINUX_HUB_H #include +#include /* likely()/unlikely() */ /* * Hub request types @@ -136,6 +137,7 @@ struct usb_hub_descriptor *descriptor; struct semaphore khubd_sem; + struct usb_tt tt; /* Transaction Translator */ }; #endif /* __LINUX_HUB_H */ diff -urN linux-2.4.18/drivers/usb/ibmcam.c linux-2.4.19-pre5/drivers/usb/ibmcam.c --- linux-2.4.18/drivers/usb/ibmcam.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/ibmcam.c Sat Mar 30 22:55:29 2002 @@ -1,7 +1,8 @@ /* * USB IBM C-It Video Camera driver * - * Supports IBM C-It Video Camera. + * Supports Xirlink C-It Video Camera, IBM PC Camera, + * IBM NetCamera and Veo Stingray. * * This driver is based on earlier work of: * @@ -33,9 +34,11 @@ #include "usbvideo.h" -#define IBMCAM_VENDOR_ID 0x0545 -#define IBMCAM_PRODUCT_ID 0x8080 +#define IBMCAM_VENDOR_ID 0x0545 +#define IBMCAM_PRODUCT_ID 0x8080 #define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */ +#define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */ +#define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */ #define MAX_IBMCAM 4 /* How many devices we allow to connect */ #define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ @@ -3671,6 +3674,8 @@ if (dev->descriptor.idVendor != IBMCAM_VENDOR_ID) return NULL; if ((dev->descriptor.idProduct != IBMCAM_PRODUCT_ID) && + (dev->descriptor.idProduct != VEO_800C_PRODUCT_ID) && + (dev->descriptor.idProduct != VEO_800D_PRODUCT_ID) && (dev->descriptor.idProduct != NETCAM_PRODUCT_ID)) return NULL; @@ -3684,7 +3689,8 @@ case 0x030A: if (ifnum != 0) return NULL; - if (dev->descriptor.idProduct == NETCAM_PRODUCT_ID) + if ((dev->descriptor.idProduct == NETCAM_PRODUCT_ID) || + (dev->descriptor.idProduct == VEO_800D_PRODUCT_ID)) model = IBMCAM_MODEL_4; else model = IBMCAM_MODEL_2; @@ -3699,8 +3705,28 @@ dev->descriptor.bcdDevice); return NULL; } - info("IBM USB camera found (model %d, rev. 0x%04x)", - model, dev->descriptor.bcdDevice); + + /* Print detailed info on what we found so far */ + do { + char *brand = NULL; + switch (dev->descriptor.idProduct) { + case NETCAM_PRODUCT_ID: + brand = "IBM NetCamera"; + break; + case VEO_800C_PRODUCT_ID: + brand = "Veo Stingray [800C]"; + break; + case VEO_800D_PRODUCT_ID: + brand = "Veo Stingray [800D]"; + break; + case IBMCAM_PRODUCT_ID: + default: + brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ + break; + } + info("%s USB camera found (model %d, rev. 0x%04x)", + brand, model, dev->descriptor.bcdDevice); + } while (0); /* Validate found interface: must have one ISO endpoint */ nas = dev->actconfig->interface[ifnum].num_altsetting; @@ -3908,18 +3934,16 @@ usbvideo_Deregister(&cams); } -#if defined(usb_device_id_ver) - static __devinitdata struct usb_device_id id_table[] = { { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ + { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); - -#endif /* defined(usb_device_id_ver) */ module_init(ibmcam_init); module_exit(ibmcam_cleanup); diff -urN linux-2.4.18/drivers/usb/ibmcam.h linux-2.4.19-pre5/drivers/usb/ibmcam.h --- linux-2.4.18/drivers/usb/ibmcam.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/ibmcam.h Thu Jan 1 01:00:00 1970 @@ -1,240 +0,0 @@ -/* - * Header file for USB IBM C-It Video Camera driver. - * - * Supports IBM C-It Video Camera. - * - * This driver is based on earlier work of: - * - * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Randy Dunlap - */ - -#ifndef __LINUX_IBMCAM_H -#define __LINUX_IBMCAM_H - -#include - -#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ - -/* Video Size 384 x 288 x 3 bytes for RGB */ -/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */ -#define V4L_FRAME_WIDTH 384 -#define V4L_FRAME_WIDTH_USED 352 -#define V4L_FRAME_HEIGHT 288 -#define V4L_BYTES_PER_PIXEL 3 -#define MAX_FRAME_SIZE (V4L_FRAME_WIDTH * V4L_FRAME_HEIGHT * V4L_BYTES_PER_PIXEL) - -/* Camera capabilities (maximum) */ -#define CAMERA_IMAGE_WIDTH 352 -#define CAMERA_IMAGE_HEIGHT 288 -#define CAMERA_IMAGE_LINE_SZ ((CAMERA_IMAGE_WIDTH * 3) / 2) /* Bytes */ -#define CAMERA_URB_FRAMES 32 -#define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ - -#define IBMCAM_NUMFRAMES 2 -#define IBMCAM_NUMSBUF 2 - -#define FRAMES_PER_DESC (CAMERA_URB_FRAMES) -#define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) - -/* This macro restricts an int variable to an inclusive range */ -#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } - -/* - * This macro performs bounds checking - use it when working with - * new formats, or else you may get oopses all over the place. - * If pixel falls out of bounds then it gets shoved back (as close - * to place of offence as possible) and is painted bright red. - */ -#define IBMCAM_PUTPIXEL(fr, ix, iy, vr, vg, vb) { \ - register unsigned char *pf; \ - int limiter = 0, mx, my; \ - mx = ix; \ - my = iy; \ - if (mx < 0) { \ - mx=0; \ - limiter++; \ - } else if (mx >= 352) { \ - mx=351; \ - limiter++; \ - } \ - if (my < 0) { \ - my = 0; \ - limiter++; \ - } else if (my >= V4L_FRAME_HEIGHT) { \ - my = V4L_FRAME_HEIGHT - 1; \ - limiter++; \ - } \ - pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*352 + (ix)); \ - if (limiter) { \ - *pf++ = 0; \ - *pf++ = 0; \ - *pf++ = 0xFF; \ - } else { \ - *pf++ = (vb); \ - *pf++ = (vg); \ - *pf++ = (vr); \ - } \ -} - -/* - * We use macros to do YUV -> RGB conversion because this is - * very important for speed and totally unimportant for size. - * - * YUV -> RGB Conversion - * --------------------- - * - * B = 1.164*(Y-16) + 2.018*(V-128) - * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) - * R = 1.164*(Y-16) + 1.596*(U-128) - * - * If you fancy integer arithmetics (as you should), hear this: - * - * 65536*B = 76284*(Y-16) + 132252*(V-128) - * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) - * 65536*R = 76284*(Y-16) + 104595*(U-128) - * - * Make sure the output values are within [0..255] range. - */ -#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) -#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ - int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ - mm_y = (my) - 16; \ - mm_u = (mu) - 128; \ - mm_v = (mv) - 128; \ - mm_yc= mm_y * 76284; \ - mm_b = (mm_yc + 132252*mm_v ) >> 16; \ - mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ - mm_r = (mm_yc + 104595*mm_u ) >> 16; \ - mb = LIMIT_RGB(mm_b); \ - mg = LIMIT_RGB(mm_g); \ - mr = LIMIT_RGB(mm_r); \ -} - -/* Debugging aid */ -#define IBMCAM_SAY_AND_WAIT(what) { \ - wait_queue_head_t wq; \ - init_waitqueue_head(&wq); \ - printk(KERN_INFO "Say: %s\n", what); \ - 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 */ -}; - -enum { - FRAME_UNUSED, /* Unused (no MCAPTURE) */ - FRAME_READY, /* Ready to start grabbing */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_ERROR, /* Something bad happened while processing */ -}; - -struct usb_device; - -struct ibmcam_sbuf { - char *data; - urb_t *urb; -}; - -struct ibmcam_frame { - char *data; /* Frame buffer */ - int order_uv; /* True=UV False=VU */ - int order_yc; /* True=Yc False=cY ('c'=either U or V) */ - unsigned char hdr_sig; /* "00 FF 00 ??" where 'hdr_sig' is '??' */ - - int width; /* Width application is expecting */ - int height; /* Height */ - - int frmwidth; /* Width the frame actually is */ - int frmheight; /* Height */ - - volatile int grabstate; /* State of grabbing */ - int scanstate; /* State of scanning */ - - int curline; /* Line of frame we're working on */ - - long scanlength; /* uncompressed, raw data length of frame */ - long bytes_read; /* amount of scanlength that has been read from *data */ - - wait_queue_head_t wq; /* Processes waiting */ -}; - -#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */ -#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */ - -struct usb_ibmcam { - struct video_device vdev; - - /* Device structure */ - struct usb_device *dev; - - 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 camera_model; /* What type of IBM camera we got? */ - 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? */ - - char *fbuf; /* Videodev buffer area */ - int fbuf_size; /* Videodev buffer size */ - - int curframe; - struct ibmcam_frame frame[IBMCAM_NUMFRAMES]; /* Double buffering */ - - int cursbuf; /* Current receiving sbuf */ - struct ibmcam_sbuf sbuf[IBMCAM_NUMSBUF]; /* Double buffering */ - volatile int remove_pending; /* If set then about to exit */ - - /* - * Scratch space from the Isochronous pipe. - * Scratch buffer should contain at least one pair of lines - * (CAMERA_IMAGE_LINE_SZ). We set it to two pairs here. - * This will be approximately 2 KB. HOWEVER in reality this - * buffer must be as large as hundred of KB because otherwise - * you'll get lots of overflows because V4L client may request - * frames not as uniformly as USB sources them. - */ - unsigned char *scratch; - int scratchlen; - - struct video_picture vpic, vpic_old; /* Picture settings */ - struct video_capability vcap; /* Video capabilities */ - struct video_channel vchan; /* May be used for tuner support */ - unsigned char video_endp; /* 0x82 for IBM camera */ - int has_hdr; - int frame_num; - int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ - - /* Statistics that can be overlayed on screen */ - unsigned long urb_count; /* How many URBs we received so far */ - unsigned long urb_length; /* Length of last URB */ - unsigned long data_count; /* How many bytes we received */ - unsigned long header_count; /* How many frame headers we found */ - unsigned long scratch_ovf_count;/* How many times we overflowed scratch */ - unsigned long iso_skip_count; /* How many empty ISO packets received */ - unsigned long iso_err_count; /* How many bad ISO packets received */ -}; - -#endif /* __LINUX_IBMCAM_H */ diff -urN linux-2.4.18/drivers/usb/inode.c linux-2.4.19-pre5/drivers/usb/inode.c --- linux-2.4.18/drivers/usb/inode.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/inode.c Sat Mar 30 22:55:35 2002 @@ -654,7 +654,13 @@ return NULL; } +/* + * The usbdevfs name is now deprecated (as of 2.4.19). + * It will be removed when the 2.7.x development cycle is started. + * You have been warned :) + */ static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE); +static DECLARE_FSTYPE(usbfs_type, "usbfs", usbdevfs_read_super, FS_SINGLE); /* --------------------------------------------------------------------- */ @@ -751,6 +757,11 @@ usb_deregister(&usbdevfs_driver); return ret; } + if ((ret = register_filesystem(&usbfs_type))) { + usb_deregister(&usbdevfs_driver); + unregister_filesystem(&usbdevice_fs_type); + return ret; + } #ifdef CONFIG_PROC_FS /* create mount point for usbdevfs */ usbdir = proc_mkdir("usb", proc_bus); @@ -762,6 +773,7 @@ { usb_deregister(&usbdevfs_driver); unregister_filesystem(&usbdevice_fs_type); + unregister_filesystem(&usbfs_type); #ifdef CONFIG_PROC_FS if (usbdir) remove_proc_entry("usb", proc_bus); diff -urN linux-2.4.18/drivers/usb/kaweth.c linux-2.4.19-pre5/drivers/usb/kaweth.c --- linux-2.4.18/drivers/usb/kaweth.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/kaweth.c Sat Mar 30 22:55:40 2002 @@ -123,6 +123,7 @@ { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ + { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ @@ -238,8 +239,7 @@ return -EBUSY; } - dr = kmalloc(sizeof(devrequest), - in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + dr = kmalloc(sizeof(devrequest), GFP_ATOMIC); if(!dr) { @@ -587,14 +587,10 @@ { struct kaweth_device *kaweth = urb->context; - spin_lock(&kaweth->device_lock); - if (urb->status) kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); - - spin_unlock(&kaweth->device_lock); } /**************************************************************** @@ -722,6 +718,7 @@ kaweth->stats.tx_errors++; net->trans_start = jiffies; + kaweth->tx_urb->transfer_flags |= USB_ASYNC_UNLINK; usb_unlink_urb(kaweth->tx_urb); } @@ -825,6 +822,7 @@ /* Device will now disappear for a moment... */ kaweth_info("Firmware loaded. I'll be back..."); + kfree(kaweth); return NULL; } @@ -926,6 +924,9 @@ kaweth_warn("unregistering non-existant device"); return; } + + usb_unlink_urb(kaweth->rx_urb); + usb_unlink_urb(kaweth->tx_urb); if(kaweth->net) { if(kaweth->net->flags & IFF_UP) { diff -urN linux-2.4.18/drivers/usb/ov511.c linux-2.4.19-pre5/drivers/usb/ov511.c --- linux-2.4.18/drivers/usb/ov511.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/ov511.c Sat Mar 30 22:55:35 2002 @@ -1,7 +1,7 @@ /* * OmniVision OV511 Camera-to-USB Bridge Driver * - * Copyright (c) 1999-2001 Mark W. McClelland + * Copyright (c) 1999-2002 Mark W. McClelland * Original decompression code Copyright 1998-2000 OmniVision Technologies * Many improvements by Bret Wallach * Color fixes by by Orion Sky Lawlor (2/26/2000) @@ -57,7 +57,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.48a for Linux 2.4" +#define DRIVER_VERSION "v1.50 for Linux 2.4" #define EMAIL "mmcclell@bigfoot.com" #define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ @@ -308,7 +308,7 @@ static inline int sensor_get_picture(struct usb_ov511 *, struct video_picture *); static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); -static int ov511_control_ioctl(struct inode *, struct file *, unsigned int, +static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, unsigned long); /********************************************************************** @@ -331,6 +331,7 @@ { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 192, "Webeye 2000B" }, { -1, NULL } }; @@ -493,7 +494,7 @@ extern struct proc_dir_entry *video_proc_entry; static struct file_operations ov511_control_fops = { - ioctl: ov511_control_ioctl, + ioctl: ov51x_control_ioctl, }; #define YES_NO(x) ((x) ? "yes" : "no") @@ -505,29 +506,29 @@ { char *out = page; int i, j, len; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; struct video_picture p; unsigned char exp; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - sensor_get_picture(ov511, &p); - sensor_get_exposure(ov511, &exp); + sensor_get_picture(ov, &p); + sensor_get_exposure(ov, &exp); /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); - out += sprintf(out, "custom_id : %d\n", ov511->customid); - out += sprintf(out, "model : %s\n", ov511->desc ? - clist[ov511->desc].description : "unknown"); - out += sprintf(out, "streaming : %s\n", YES_NO(ov511->streaming)); - out += sprintf(out, "grabbing : %s\n", YES_NO(ov511->grabbing)); - out += sprintf(out, "compress : %s\n", YES_NO(ov511->compress)); - out += sprintf(out, "subcapture : %s\n", YES_NO(ov511->sub_flag)); + out += sprintf(out, "custom_id : %d\n", ov->customid); + out += sprintf(out, "model : %s\n", ov->desc ? + clist[ov->desc].description : "unknown"); + out += sprintf(out, "streaming : %s\n", YES_NO(ov->streaming)); + out += sprintf(out, "grabbing : %s\n", YES_NO(ov->grabbing)); + out += sprintf(out, "compress : %s\n", YES_NO(ov->compress)); + out += sprintf(out, "subcapture : %s\n", YES_NO(ov->sub_flag)); out += sprintf(out, "sub_size : %d %d %d %d\n", - ov511->subx, ov511->suby, ov511->subw, ov511->subh); + ov->subx, ov->suby, ov->subw, ov->subh); out += sprintf(out, "data_format : %s\n", force_rgb ? "RGB" : "BGR"); out += sprintf(out, "brightness : %d\n", p.brightness >> 8); @@ -539,12 +540,12 @@ for (i = 0; i < OV511_NUMFRAMES; i++) { out += sprintf(out, "frame : %d\n", i); out += sprintf(out, " depth : %d\n", - ov511->frame[i].depth); + ov->frame[i].depth); out += sprintf(out, " size : %d %d\n", - ov511->frame[i].width, ov511->frame[i].height); + ov->frame[i].width, ov->frame[i].height); out += sprintf(out, " format : "); for (j = 0; plist[j].num >= 0; j++) { - if (plist[j].num == ov511->frame[i].format) { + if (plist[j].num == ov->frame[i].format) { out += sprintf(out, "%s\n", plist[j].name); break; } @@ -552,29 +553,28 @@ if (plist[j].num < 0) out += sprintf(out, "unknown\n"); out += sprintf(out, " data_buffer : 0x%p\n", - ov511->frame[i].data); + ov->frame[i].data); } - out += sprintf(out, "snap_enabled : %s\n", - YES_NO(ov511->snap_enabled)); + out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov->snap_enabled)); out += sprintf(out, "bridge : %s\n", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); out += sprintf(out, "sensor : %s\n", - ov511->sensor == SEN_OV6620 ? "OV6620" : - ov511->sensor == SEN_OV6630 ? "OV6630" : - ov511->sensor == SEN_OV7610 ? "OV7610" : - ov511->sensor == SEN_OV7620 ? "OV7620" : - ov511->sensor == SEN_OV7620AE ? "OV7620AE" : - ov511->sensor == SEN_OV8600 ? "OV8600" : - ov511->sensor == SEN_KS0127 ? "KS0127" : - ov511->sensor == SEN_KS0127B ? "KS0127B" : - ov511->sensor == SEN_SAA7111A ? "SAA7111A" : + ov->sensor == SEN_OV6620 ? "OV6620" : + ov->sensor == SEN_OV6630 ? "OV6630" : + ov->sensor == SEN_OV7610 ? "OV7610" : + ov->sensor == SEN_OV7620 ? "OV7620" : + ov->sensor == SEN_OV7620AE ? "OV7620AE" : + ov->sensor == SEN_OV8600 ? "OV8600" : + ov->sensor == SEN_KS0127 ? "KS0127" : + ov->sensor == SEN_KS0127B ? "KS0127B" : + ov->sensor == SEN_SAA7111A ? "SAA7111A" : "unknown"); - out += sprintf(out, "packet_size : %d\n", ov511->packet_size); - out += sprintf(out, "framebuffer : 0x%p\n", ov511->fbuf); + out += sprintf(out, "packet_size : %d\n", ov->packet_size); + out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); len = out - page; len -= off; @@ -607,16 +607,16 @@ { char *out = page; int len, status; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - status = ov51x_check_snapshot(ov511); + status = ov51x_check_snapshot(ov); out += sprintf(out, "%d", status); if (status) - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); len = out - page; len -= off; @@ -636,18 +636,19 @@ static void create_proc_ov511_cam(struct usb_ov511 *ov511) { - char dirname[4]; + char dirname[10]; if (!ov511_proc_entry || !ov511) return; /* Create per-device directory */ - sprintf(dirname, "%d", ov511->vdev.minor); + snprintf(dirname, 10, "%d", ov511->vdev.minor); PDEBUG(4, "creating /proc/video/ov511/%s/", dirname); ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry); if (!ov511->proc_devdir) return; + ov511->proc_devdir->owner = THIS_MODULE; /* Create "info" entry (human readable device information) */ PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname); @@ -656,6 +657,7 @@ ov511_read_proc_info, ov511); if (!ov511->proc_info) return; + ov511->proc_info->owner = THIS_MODULE; /* Don't create it if old snapshot mode on (would cause race cond.) */ if (!snapshot) { @@ -667,6 +669,7 @@ if (!ov511->proc_button) return; } + ov511->proc_button->owner = THIS_MODULE; /* Create "control" entry (ioctl() interface) */ PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); @@ -677,6 +680,7 @@ unlock_kernel(); return; } + ov511->proc_control->owner = THIS_MODULE; ov511->proc_control->data = ov511; ov511->proc_control->proc_fops = &ov511_control_fops; unlock_kernel(); @@ -685,12 +689,12 @@ static void destroy_proc_ov511_cam(struct usb_ov511 *ov511) { - char dirname[4]; + char dirname[10]; if (!ov511 || !ov511->proc_devdir) return; - sprintf(dirname, "%d", ov511->vdev.minor); + snprintf(dirname, 10, "%d", ov511->vdev.minor); /* Destroy "control" entry */ if (ov511->proc_control) { @@ -758,18 +762,22 @@ * **********************************************************************/ +/* Write an OV51x register */ static int -ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + down(&ov->cbuf_lock); + ov->cbuf[0] = value; + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, &value, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d", rc); @@ -777,45 +785,48 @@ return rc; } +/* Read from an OV51x register */ /* returns: negative is error, pos or zero is data */ static int -ov511_reg_read(struct usb_device *dev, unsigned char reg) +reg_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - unsigned char buffer[1]; - rc = usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), + down(&ov->cbuf_lock); + rc = usb_control_msg(ov->dev, + usb_rcvctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, buffer, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); - PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]); + PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); - if (rc < 0) { + if (rc < 0) err("reg read: error %d", rc); - return rc; - } else { - return buffer[0]; - } + else + rc = ov->cbuf[0]; + + up(&ov->cbuf_lock); + + return rc; } /* - * Writes bits at positions specified by mask to a reg. Bits that are in + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */ static int -ov511_reg_write_mask(struct usb_device *dev, - unsigned char reg, - unsigned char value, - unsigned char mask) +reg_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int ret; unsigned char oldval, newval; - ret = ov511_reg_read(dev, reg); + ret = reg_r(ov, reg); if (ret < 0) return ret; @@ -824,31 +835,30 @@ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ - return (ov511_reg_write(dev, reg, newval)); + return (reg_w(ov, reg, newval)); } -/* Writes multiple (n) values to a single register. Only valid with certain - * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */ +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ static int -ov518_reg_write_multi(struct usb_device *dev, - unsigned char reg, - unsigned char *values, - int n) +ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) { int rc; - PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n); // FIXME + PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); - if (values == NULL) { - err("reg write multiple: NULL buffer"); - return -EINVAL; - } + down(&ov->cbuf_lock); + + *((u32 *)ov->cbuf) = __cpu_to_le32(val); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, values, n, HZ); + 0, (__u16)reg, ov->cbuf, n, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d", rc); @@ -857,12 +867,12 @@ } static int -ov511_upload_quan_tables(struct usb_device *dev) +ov511_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -875,7 +885,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -887,8 +897,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV511_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -901,12 +910,12 @@ /* OV518 quantization tables are 8x4 (instead of 8x8) */ static int -ov518_upload_quan_tables(struct usb_device *dev) +ov518_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -919,7 +928,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -931,8 +940,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -943,13 +951,39 @@ return 0; } +static int +ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) +{ + int rc; + + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov->bclass == BCL_OV518) + reset_type &= 0xfe; + + PDEBUG(4, "Reset: type=0x%X", reset_type); + + rc = reg_w(ov, R51x_SYS_RESET, reset_type); + rc = reg_w(ov, R51x_SYS_RESET, 0); + + if (rc < 0) + err("reset: command failed"); + + return rc; +} + +/********************************************************************** + * + * I2C (sensor) I/O + * + **********************************************************************/ + /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_write(). Note that this function + * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_write_internal(struct usb_device *dev, +ov518_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -958,15 +992,15 @@ PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R518_I2C_CTL, 0x01); if (rc < 0) goto error; return 0; @@ -978,7 +1012,7 @@ /* NOTE: Do not call this function directly! */ static int -ov511_i2c_write_internal(struct usb_device *dev, +ov511_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -989,19 +1023,18 @@ /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R511_I2C_CTL, 0x01); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1009,7 +1042,7 @@ break; #if 0 /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); #endif if (--retries < 0) { err("i2c write retries exhausted"); @@ -1027,27 +1060,27 @@ /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_read(). Note that this function + * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value; /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R518_I2C_CTL, 0x03); if (rc < 0) goto error; /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R518_I2C_CTL, 0x05); if (rc < 0) goto error; - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); @@ -1061,22 +1094,21 @@ /* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */ static int -ov511_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R511_I2C_CTL, 0x03); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1084,7 +1116,7 @@ break; /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); @@ -1096,10 +1128,10 @@ /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1107,7 +1139,7 @@ break; /* I2C abort */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + rc = reg_w(ov, R511_I2C_CTL, 0x10); if (rc < 0) goto error; if (--retries < 0) { @@ -1117,12 +1149,12 @@ } } - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); - /* This is needed to make ov51x_i2c_write() work */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + /* This is needed to make i2c_w() work */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; @@ -1135,48 +1167,42 @@ /* returns: negative is error, pos or zero is data */ static int -ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg) +i2c_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } static int -ov51x_i2c_write(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value) +i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_write_internal(dev, reg, value); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_write_internal(ov, reg, value); else - rc = ov511_i2c_write_internal(dev, reg, value); + rc = ov511_i2c_write_internal(ov, reg, value); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Do not call this function directly! */ static int -ov51x_i2c_write_mask_internal(struct usb_device *dev, +ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask) @@ -1187,11 +1213,10 @@ if (mask == 0xff) { newval = value; } else { - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); if (rc < 0) return rc; @@ -1201,11 +1226,10 @@ newval = oldval | value; /* Set the desired bits */ } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - return (ov518_i2c_write_internal(dev, reg, newval)); + if (ov->bclass == BCL_OV518) + return (ov518_i2c_write_internal(ov, reg, newval)); else - return (ov511_i2c_write_internal(dev, reg, newval)); + return (ov511_i2c_write_internal(ov, reg, newval)); } /* Writes bits at positions specified by mask to an I2C reg. Bits that are in @@ -1214,126 +1238,138 @@ * of their respective state in "value". */ static int -ov51x_i2c_write_mask(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); - up(&ov511->i2c_lock); + down(&ov->i2c_lock); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + up(&ov->i2c_lock); return rc; } /* Write to a specific I2C slave ID and register, using the specified mask */ static int -ov51x_i2c_write_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc = 0; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Read from a specific I2C slave ID and register */ static int -ov51x_i2c_read_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg) +i2c_r_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } +/* Sets I2C read and write slave IDs. Returns <0 for error */ static int -ov511_write_regvals(struct usb_ov511 *ov511, - struct ov511_regvals * pRegvals) +ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) +{ + down(&ov->i2c_lock); + + if (reg_w(ov, R51x_I2C_W_SID, sid) < 0) + return -EIO; + + if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0) + return -EIO; + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + up(&ov->i2c_lock); + + return 0; +} + +static int +write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) { int rc; - struct usb_device *dev = ov511->dev; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { - if ((rc = ov511_reg_write(dev, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else if (pRegvals->bus == OV511_I2C_BUS) { - if ((rc = ov51x_i2c_write(ov511, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else { err("Bad regval array"); @@ -1351,57 +1387,60 @@ #ifdef OV511_DEBUG static void -ov511_dump_i2c_range(struct usb_ov511 *ov511, int reg1, int regn) +dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov51x_i2c_read(ov511, i); + rc = i2c_r(ov, i); info("OV7610[0x%X] = 0x%X", i, rc); } } static void -ov51x_dump_i2c_regs(struct usb_ov511 *ov511) +dump_i2c_regs(struct usb_ov511 *ov) { info("I2C REGS"); - ov511_dump_i2c_range(ov511, 0x00, 0x7C); + dump_i2c_range(ov, 0x00, 0x7C); } static void -ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn) +dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov511_reg_read(dev, i); - info("OV511[0x%X] = 0x%X", i, rc); + rc = reg_r(ov, i); + info("OV511[0x%X] = 0x%X", i, rc); } } +/* FIXME: Should there be an OV518 version of this? */ static void -ov511_dump_regs(struct usb_device *dev) +ov511_dump_regs(struct usb_ov511 *ov) { info("CAMERA INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x10, 0x1f); + dump_reg_range(ov, 0x10, 0x1f); info("DRAM INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x20, 0x23); + dump_reg_range(ov, 0x20, 0x23); info("ISO FIFO REGS"); - ov511_dump_reg_range(dev, 0x30, 0x31); + dump_reg_range(ov, 0x30, 0x31); info("PIO REGS"); - ov511_dump_reg_range(dev, 0x38, 0x39); - ov511_dump_reg_range(dev, 0x3e, 0x3e); + dump_reg_range(ov, 0x38, 0x39); + dump_reg_range(ov, 0x3e, 0x3e); info("I2C REGS"); - ov511_dump_reg_range(dev, 0x40, 0x49); + dump_reg_range(ov, 0x40, 0x49); info("SYSTEM CONTROL REGS"); - ov511_dump_reg_range(dev, 0x50, 0x55); - ov511_dump_reg_range(dev, 0x5e, 0x5f); + dump_reg_range(ov, 0x50, 0x55); + dump_reg_range(ov, 0x5e, 0x5f); info("OmniCE REGS"); - ov511_dump_reg_range(dev, 0x70, 0x79); + dump_reg_range(ov, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ - ov511_dump_reg_range(dev, 0x80, 0x9f); - ov511_dump_reg_range(dev, 0xa0, 0xbf); + dump_reg_range(ov, 0x80, 0x9f); + dump_reg_range(ov, 0xa0, 0xbf); } #endif @@ -1414,7 +1453,7 @@ /* For as-yet unimplemented I2C interface */ static void -call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd, +call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd, void *arg) { /* Do nothing */ @@ -1422,59 +1461,33 @@ /*****************************************************************************/ -static int -ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type) -{ - int rc; - - /* Setting bit 0 not allowed on 518/518Plus */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - reset_type &= 0xfe; - - PDEBUG(4, "Reset: type=0x%X", reset_type); - - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type); - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0); - - if (rc < 0) - err("reset: command failed"); - - return rc; -} - /* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */ static inline int -ov511_stop(struct usb_ov511 *ov511) +ov51x_stop(struct usb_ov511 *ov) { PDEBUG(4, "stopping"); - ov511->stopped = 1; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3a)); + ov->stopped = 1; + if (ov->bclass == BCL_OV518) + return (reg_w(ov, R51x_SYS_RESET, 0x3a)); else - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3d)); + return (reg_w(ov, R51x_SYS_RESET, 0x3d)); } /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */ static inline int -ov511_restart(struct usb_ov511 *ov511) +ov51x_restart(struct usb_ov511 *ov) { - if (ov511->stopped) { + if (ov->stopped) { PDEBUG(4, "restarting"); - ov511->stopped = 0; + ov->stopped = 0; /* Reinitialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write(ov511->dev, 0x2f, 0x80); + if (ov->bclass == BCL_OV518) + reg_w(ov, 0x2f, 0x80); - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x00)); + return (reg_w(ov, R51x_SYS_RESET, 0x00)); } return 0; @@ -1482,14 +1495,13 @@ /* Resets the hardware snapshot button */ static void -ov51x_clear_snapshot(struct usb_ov511 *ov511) +ov51x_clear_snapshot(struct usb_ov511 *ov) { - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + if (ov->bclass == BCL_OV511) { + reg_w(ov, R51x_SYS_SNAP, 0x01); + reg_w(ov, R51x_SYS_SNAP, 0x03); + reg_w(ov, R51x_SYS_SNAP, 0x01); + } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); @@ -1500,19 +1512,18 @@ /* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */ static int -ov51x_check_snapshot(struct usb_ov511 *ov511) +ov51x_check_snapshot(struct usb_ov511 *ov) { int ret, status = 0; - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT); + if (ov->bclass == BCL_OV511) { + ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); @@ -1521,53 +1532,33 @@ return status; } -/* Sets I2C read and write slave IDs. Returns <0 for error */ -static int -ov51x_set_slave_ids(struct usb_ov511 *ov511, - unsigned char write_id, - unsigned char read_id) -{ - struct usb_device *dev = ov511->dev; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, write_id) < 0) - return -EIO; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, read_id) < 0) - return -EIO; - - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) - return -EIO; - - return 0; -} - /* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 for failure. */ static int -ov51x_init_ov_sensor(struct usb_ov511 *ov511) +init_ov_sensor(struct usb_ov511 *ov) { int i, success; /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout (1 + 150 * HZ / 1000); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((ov51x_i2c_read(ov511, OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; continue; } /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); /* Dummy read to sync I2C */ - if (ov51x_i2c_read(ov511, 0x00) < 0) return -EIO; + if (i2c_r(ov, 0x00) < 0) return -EIO; } if (!success) @@ -1579,16 +1570,16 @@ } static int -ov511_set_packet_size(struct usb_ov511 *ov511, int size) +ov51x_set_packet_size(struct usb_ov511 *ov, int size) { int alt, mult; - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; mult = size >> 5; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; @@ -1598,7 +1589,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (size == 0) alt = OV511PLUS_ALT_SIZE_0; else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; @@ -1611,8 +1602,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (size == 0) alt = OV518_ALT_SIZE_0; else if (size == 128) alt = OV518_ALT_SIZE_128; else if (size == 256) alt = OV518_ALT_SIZE_256; @@ -1633,32 +1623,30 @@ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt); // FIXME: Don't know how to do this on OV518 yet - if (ov511->bridge != BRG_OV518 && - ov511->bridge != BRG_OV518PLUS) { - if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + if (ov->bclass == BCL_OV511) { + if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) { return -EIO; } } - if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } /* Initialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - if (ov511_reg_write(ov511->dev, 0x2f, 0x80) < 0) + if (ov->bclass == BCL_OV518) + if (reg_w(ov, 0x2f, 0x80) < 0) return -EIO; // FIXME - Should we only reset the FIFO? - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; - ov511->packet_size = size; + ov->packet_size = size; - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return 0; @@ -1666,51 +1654,49 @@ /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov511_init_compression(struct usb_ov511 *ov511) +ov511_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - ov511_reg_write(dev, 0x70, phy); - ov511_reg_write(dev, 0x71, phuv); - ov511_reg_write(dev, 0x72, pvy); - ov511_reg_write(dev, 0x73, pvuv); - ov511_reg_write(dev, 0x74, qhy); - ov511_reg_write(dev, 0x75, qhuv); - ov511_reg_write(dev, 0x76, qvy); - ov511_reg_write(dev, 0x77, qvuv); + reg_w(ov, 0x70, phy); + reg_w(ov, 0x71, phuv); + reg_w(ov, 0x72, pvy); + reg_w(ov, 0x73, pvuv); + reg_w(ov, 0x74, qhy); + reg_w(ov, 0x75, qhuv); + reg_w(ov, 0x76, qvy); + reg_w(ov, 0x77, qvuv); - if (ov511_upload_quan_tables(dev) < 0) { + if (ov511_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov518_init_compression(struct usb_ov511 *ov511) +ov518_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - if (ov518_upload_quan_tables(dev) < 0) { + if (ov518_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } @@ -1719,22 +1705,22 @@ /* Sets sensor's contrast setting to "val" */ static int -sensor_set_contrast(struct usb_ov511 *ov511, unsigned short val) +sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: { - rc = ov51x_i2c_write(ov511, OV7610_REG_CNT, val >> 8); + rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); if (rc < 0) goto out; break; @@ -1747,14 +1733,14 @@ }; /* Use Y gamma control instead. Bit 0 enables it. */ - rc = ov51x_i2c_write(ov511, 0x64, ctab[val>>12]); + rc = i2c_w(ov, 0x64, ctab[val>>12]); if (rc < 0) goto out; break; } case SEN_SAA7111A: { - rc = ov51x_i2c_write(ov511, 0x0b, val >> 9); + rc = i2c_w(ov, 0x0b, val >> 9); if (rc < 0) goto out; break; @@ -1768,9 +1754,9 @@ } rc = 0; /* Success */ - ov511->contrast = val; + ov->contrast = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1778,15 +1764,15 @@ /* Gets sensor's contrast setting */ static int -sensor_get_contrast(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_CNT); + rc = i2c_r(ov, OV7610_REG_CNT); if (rc < 0) return rc; else @@ -1794,14 +1780,14 @@ break; case SEN_OV7620: /* Use Y gamma reg instead. Bit 0 is the enable bit. */ - rc = ov51x_i2c_read(ov511, 0x64); + rc = i2c_r(ov, 0x64); if (rc < 0) return rc; else *val = (rc & 0xfe) << 8; break; case SEN_SAA7111A: - *val = ov511->contrast; + *val = ov->contrast; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1809,7 +1795,7 @@ } PDEBUG(3, "%d", *val); - ov511->contrast = *val; + ov->contrast = *val; return 0; } @@ -1818,35 +1804,35 @@ /* Sets sensor's brightness setting to "val" */ static int -sensor_set_brightness(struct usb_ov511 *ov511, unsigned short val) +sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(4, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: /* 7620 doesn't like manual changes when in auto mode */ - if (!ov511->auto_brt) { - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + if (!ov->auto_brt) { + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; } break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0a, val >> 8); + rc = i2c_w(ov, 0x0a, val >> 8); if (rc < 0) goto out; break; @@ -1857,9 +1843,9 @@ } rc = 0; /* Success */ - ov511->brightness = val; + ov->brightness = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1867,24 +1853,24 @@ /* Gets sensor's brightness setting */ static int -sensor_get_brightness(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV7620: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BRT); + rc = i2c_r(ov, OV7610_REG_BRT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->brightness; + *val = ov->brightness; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1892,7 +1878,7 @@ } PDEBUG(3, "%d", *val); - ov511->brightness = *val; + ov->brightness = *val; return 0; } @@ -1901,36 +1887,36 @@ /* Sets sensor's saturation (color intensity) setting to "val" */ static int -sensor_set_saturation(struct usb_ov511 *ov511, unsigned short val) +sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ -// rc = ov511_i2c_write(ov511->dev, 0x62, (val >> 9) & 0x7e); +// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); // if (rc < 0) // goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0c, val >> 9); + rc = i2c_w(ov, 0x0c, val >> 9); if (rc < 0) goto out; break; @@ -1941,9 +1927,9 @@ } rc = 0; /* Success */ - ov511->colour = val; + ov->colour = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1951,16 +1937,16 @@ /* Gets sensor's saturation (color intensity) setting */ static int -sensor_get_saturation(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else @@ -1968,19 +1954,19 @@ break; case SEN_OV7620: // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ -// rc = ov51x_i2c_read(ov511, 0x62); +// rc = i2c_r(ov, 0x62); // if (rc < 0) // return rc; // else // *val = (rc & 0x7e) << 9; - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->colour; + *val = ov->colour; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1988,7 +1974,7 @@ } PDEBUG(3, "%d", *val); - ov511->colour = *val; + ov->colour = *val; return 0; } @@ -1997,44 +1983,42 @@ /* Sets sensor's hue (red/blue balance) setting to "val" */ static int -sensor_set_hue(struct usb_ov511 *ov511, unsigned short val) +sensor_set_hue(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_RED, 0xFF - (val >> 8)); + rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_BLUE, val >> 8); + rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // Hue control is causing problems. I will enable it once it's fixed. #if 0 - rc = ov51x_i2c_write(ov511, 0x7a, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, 0x79, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; #endif break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0d, (val + 32768) >> 8); + rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); if (rc < 0) goto out; break; @@ -2045,9 +2029,9 @@ } rc = 0; /* Success */ - ov511->hue = val; + ov->hue = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2055,29 +2039,29 @@ /* Gets sensor's hue (red/blue balance) setting */ static int -sensor_get_hue(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BLUE); + rc = i2c_r(ov, OV7610_REG_BLUE); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_OV7620: - rc = ov51x_i2c_read(ov511, 0x7a); + rc = i2c_r(ov, 0x7a); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->hue; + *val = ov->hue; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -2085,7 +2069,7 @@ } PDEBUG(3, "%d", *val); - ov511->hue = *val; + ov->hue = *val; return 0; } @@ -2093,30 +2077,30 @@ /* -------------------------------------------------------------------------- */ static inline int -sensor_set_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; PDEBUG(4, "sensor_set_picture"); - ov511->whiteness = p->whiteness; + ov->whiteness = p->whiteness; /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_set_contrast(ov511, p->contrast); + rc = sensor_set_contrast(ov, p->contrast); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_brightness(ov511, p->brightness); + rc = sensor_set_brightness(ov, p->brightness); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_saturation(ov511, p->colour); + rc = sensor_set_saturation(ov, p->colour); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_hue(ov511, p->hue); + rc = sensor_set_hue(ov, p->hue); if (FATAL_ERROR(rc)) return rc; @@ -2124,7 +2108,7 @@ } static inline int -sensor_get_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; @@ -2133,27 +2117,27 @@ /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_get_contrast(ov511, &(p->contrast)); + rc = sensor_get_contrast(ov, &(p->contrast)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_brightness(ov511, &(p->brightness)); + rc = sensor_get_brightness(ov, &(p->brightness)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_saturation(ov511, &(p->colour)); + rc = sensor_get_saturation(ov, &(p->colour)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_hue(ov511, &(p->hue)); + rc = sensor_get_hue(ov, &(p->hue)); if (FATAL_ERROR(rc)) return rc; p->whiteness = 105 << 8; /* Can we get these from frame[0]? -claudio? */ - p->depth = ov511->frame[0].depth; - p->palette = ov511->frame[0].format; + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; return 0; } @@ -2162,24 +2146,24 @@ /* Sets current exposure for sensor. This only has an effect if auto-exposure * is off */ static inline int -sensor_set_exposure(struct usb_ov511 *ov511, unsigned char val) +sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV6620: case SEN_OV6630: case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_write(ov511, 0x10, val); + rc = i2c_w(ov, 0x10, val); if (rc < 0) goto out; @@ -2195,9 +2179,9 @@ } rc = 0; /* Success */ - ov511->exposure = val; + ov->exposure = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2206,18 +2190,18 @@ /* Gets current exposure level from sensor, regardless of whether it is under * manual control. */ static int -sensor_get_exposure(struct usb_ov511 *ov511, unsigned char *val) +sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_read(ov511, 0x10); + rc = i2c_r(ov, 0x10); if (rc < 0) return rc; else @@ -2235,24 +2219,22 @@ } PDEBUG(3, "%d", *val); - ov511->exposure = *val; + ov->exposure = *val; return 0; } /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ static inline void -ov51x_led_control(struct usb_ov511 *ov511, int enable) +ov51x_led_control(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, - enable ? 1 : 0); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write_mask(ov511->dev, OV518_REG_GPIO_OUT, - enable ? 0x02 : 0x00, 0x02); + if (ov->bridge == BRG_OV511PLUS) + reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); + else if (ov->bclass == BCL_OV518) + reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); + return; } @@ -2266,7 +2248,7 @@ * Returns: 0 for success */ static int -sensor_set_light_freq(struct usb_ov511 *ov511, int freq) +sensor_set_light_freq(struct usb_ov511 *ov, int freq) { int sixty; @@ -2281,24 +2263,24 @@ return -EINVAL; } - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x13, 0x10, 0x10); - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x10); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x13, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x10); break; case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x76, 0x01, 0x01); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x76, 0x01, 0x01); break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x2b, sixty?0xa8:0x28); - ov51x_i2c_write(ov511, 0x2a, sixty?0x84:0xa4); + i2c_w(ov, 0x2b, sixty?0xa8:0x28); + i2c_w(ov, 0x2a, sixty?0x84:0xa4); break; case SEN_KS0127: case SEN_KS0127B: @@ -2310,7 +2292,7 @@ return -EINVAL; } - ov511->lightfreq = freq; + ov->lightfreq = freq; return 0; } @@ -2325,23 +2307,23 @@ * Returns: 0 for success */ static inline int -sensor_set_banding_filter(struct usb_ov511 *ov511, int enable) +sensor_set_banding_filter(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x04:0x00, 0x04); + rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); if (rc < 0) return rc; - ov511->bandfilt = enable; + ov->bandfilt = enable; return 0; } @@ -2353,23 +2335,23 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_brightness(struct usb_ov511 *ov511, int enable) +sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x10:0x00, 0x10); + rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); if (rc < 0) return rc; - ov511->auto_brt = enable; + ov->auto_brt = enable; return 0; } @@ -2381,22 +2363,22 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_exposure(struct usb_ov511 *ov511, int enable) +sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x29, enable?0x00:0x80, 0x80); + i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); break; case SEN_OV6620: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x13, enable?0x01:0x00, 0x01); + i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x28, enable?0x00:0x10, 0x10); + i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); break; case SEN_KS0127: case SEN_KS0127B: @@ -2408,7 +2390,7 @@ return -EINVAL; } - ov511->auto_exp = enable; + ov->auto_exp = enable; return 0; } @@ -2421,27 +2403,27 @@ * Returns: 0 for success */ static int -sensor_set_backlight(struct usb_ov511 *ov511, int enable) +sensor_set_backlight(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7620: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x68, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV6620: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x0e, enable?0x80:0x00, 0x80); + i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0x80:0x60, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV7610: case SEN_OV7620AE: @@ -2455,7 +2437,7 @@ return -EINVAL; } - ov511->backlight = enable; + ov->backlight = enable; return 0; } @@ -2464,7 +2446,7 @@ * planar or not), or zero for unsupported format. */ static inline int -ov511_get_depth(int palette) +get_depth(int palette) { switch (palette) { case VIDEO_PALETTE_GREY: return 8; @@ -2487,55 +2469,55 @@ return 0; else return ((frame->width * frame->height - * ov511_get_depth(frame->format)) >> 3); + * get_depth(frame->format)) >> 3); } static int -mode_init_ov_sensor_regs(struct usb_ov511 *ov511, int width, int height, +mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag, int qvga) { int clock; /******** Mode (VGA/QVGA) and sensor specific regs ********/ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); // FIXME: Does this improve the image quality or frame rate? #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, 0x10); - ov51x_i2c_write(ov511, 0x25, qvga?0x40:0x8a); - ov51x_i2c_write(ov511, 0x2f, qvga?0x30:0xb0); - ov51x_i2c_write(ov511, 0x35, qvga?0x1c:0x9c); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); #endif break; case SEN_OV7620: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xf0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); break; case SEN_OV7620AE: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); // FIXME: Enable this once 7620AE uses 7620 initial settings #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xb0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); #endif break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); /* No special settings yet */ break; default: @@ -2546,19 +2528,17 @@ /******** Palette-specific regs ********/ if (mode == VIDEO_PALETTE_GREY) { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* these aren't valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x40, 0x40); + i2c_w_mask(ov, 0x0e, 0x40, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x20, 0x20); + i2c_w_mask(ov, 0x13, 0x20, 0x20); } else { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* not valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x00, 0x40); + i2c_w_mask(ov, 0x0e, 0x00, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x20); + i2c_w_mask(ov, 0x13, 0x00, 0x20); } /******** Clock programming ********/ @@ -2567,13 +2547,13 @@ /* The OV6620 needs special handling. This prevents the * severe banding that normally occurs */ - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { /* Clock down */ - ov51x_i2c_write(ov511, 0x2a, 0x04); + i2c_w(ov, 0x2a, 0x04); - if (ov511->compress) { + if (ov->compress) { // clock = 0; /* This ensures the highest frame rate */ clock = 3; } else if (clockdiv == -1) { /* If user didn't override it */ @@ -2584,21 +2564,21 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); - ov51x_i2c_write(ov511, 0x2a, 0x84); + i2c_w(ov, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ - ov51x_i2c_write(ov511, 0x2d, 0x85); + i2c_w(ov, 0x2d, 0x85); } else { - if (ov511->compress) { + if (ov->compress) { clock = 1; /* This ensures the highest frame rate */ } else if (clockdiv == -1) { /* If user didn't override it */ /* Calculate and set the clock divisor */ - clock = ((sub_flag ? ov511->subw * ov511->subh + clock = ((sub_flag ? ov->subw * ov->subh : width * height) * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) / 66000; @@ -2608,45 +2588,44 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); } /******** Special Features ********/ if (framedrop >= 0) - ov51x_i2c_write(ov511, 0x16, framedrop); + i2c_w(ov, 0x16, framedrop); /* We only have code to convert GBR -> RGB24 */ if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) - ov51x_i2c_write_mask(ov511, 0x12, 0x08, 0x08); + i2c_w_mask(ov, 0x12, 0x08, 0x08); else - ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x08); + i2c_w_mask(ov, 0x12, 0x00, 0x08); /* Test Pattern */ - ov51x_i2c_write_mask(ov511, 0x12, (testpat?0x02:0x00), 0x02); + i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); /* Auto white balance */ // if (awb) - ov51x_i2c_write_mask(ov511, 0x12, 0x04, 0x04); + i2c_w_mask(ov, 0x12, 0x04, 0x04); // else -// ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x04); +// i2c_w_mask(ov, 0x12, 0x00, 0x04); - // This will go away as soon as ov511_mode_init_sensor_regs() + // This will go away as soon as ov51x_mode_init_sensor_regs() // is fully tested. /* 7620/6620/6630? don't have register 0x35, so play it safe */ - if (ov511->sensor == SEN_OV7610 || - ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { if (width == 640 && height == 480) - ov51x_i2c_write(ov511, 0x35, 0x9e); + i2c_w(ov, 0x35, 0x9e); else - ov51x_i2c_write(ov511, 0x35, 0x1e); + i2c_w(ov, 0x35, 0x1e); } return 0; } static int -set_ov_sensor_window(struct usb_ov511 *ov511, int width, int height, int mode, +set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int ret; @@ -2655,7 +2634,7 @@ /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: hwsbase = 0x38; @@ -2679,9 +2658,9 @@ return -EINVAL; } - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) { + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { if (width > 176 && height > 144) { /* CIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2693,7 +2672,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QCIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2702,7 +2681,7 @@ } } else { if (width > 320 && height > 240) { /* VGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2714,7 +2693,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QVGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2730,24 +2709,20 @@ /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ if (sub_flag) { - ov51x_i2c_write(ov511, 0x17, hwsbase+(ov511->subx>>hwscale)); - ov51x_i2c_write(ov511, 0x18, - hwebase+((ov511->subx+ov511->subw)>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase+(ov511->suby>>vwscale)); - ov51x_i2c_write(ov511, 0x1a, - vwebase+((ov511->suby+ov511->subh)>>vwscale)); + i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); + i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); + i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); + i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); } else { - ov51x_i2c_write(ov511, 0x17, hwsbase + hoffset); - ov51x_i2c_write(ov511, 0x18, - hwebase + hoffset + (hwsize>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase + voffset); - ov51x_i2c_write(ov511, 0x1a, - vwebase + voffset + (vwsize>>vwscale)); + i2c_w(ov, 0x17, hwsbase + hoffset); + i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); + i2c_w(ov, 0x19, vwsbase + voffset); + i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); } #ifdef OV511_DEBUG if (dump_sensor) - ov51x_dump_i2c_regs(ov511); + dump_i2c_regs(ov); #endif return 0; @@ -2758,18 +2733,14 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov511_mode_init_regs(struct usb_ov511 *ov511, +ov511_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int lncnt, pxcnt, rc = 0; - struct usb_device *dev = ov511->dev; - - if (!ov511 || !dev) - return -EFAULT; if (sub_flag) { - width = ov511->subw; - height = ov511->subh; + width = ov->subw; + height = ov->subh; } PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", @@ -2777,7 +2748,7 @@ // FIXME: This should be moved to a 7111a-specific function once // subcapture is dealt with properly - if (ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_SAA7111A) { if (width == 320 && height == 240) { /* No need to do anything special */ } else if (width == 640 && height == 480) { @@ -2796,26 +2767,22 @@ return -EINVAL; } - if (width < ov511->minwidth || height < ov511->minheight) { + if (width < ov->minwidth || height < ov->minheight) { err("Requested dimensions are too small"); return -EINVAL; } - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; if (mode == VIDEO_PALETTE_GREY) { - ov511_reg_write(dev, 0x16, 0x00); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x00); - ov511_reg_write(dev, 0x1f, 0x01); + reg_w(ov, R511_CAM_UV_EN, 0x00); + reg_w(ov, R511_SNAP_UV_EN, 0x00); + reg_w(ov, R511_SNAP_OPTS, 0x01); } else { - ov511_reg_write(dev, 0x16, 0x01); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x01); - ov511_reg_write(dev, 0x1f, 0x03); + reg_w(ov, R511_CAM_UV_EN, 0x01); + reg_w(ov, R511_SNAP_UV_EN, 0x01); + reg_w(ov, R511_SNAP_OPTS, 0x03); } /* Here I'm assuming that snapshot size == image size. @@ -2824,25 +2791,28 @@ pxcnt = (width >> 3) - 1; lncnt = (height >> 3) - 1; - ov511_reg_write(dev, 0x12, pxcnt); - ov511_reg_write(dev, 0x13, lncnt); - ov511_reg_write(dev, 0x14, 0x00); - ov511_reg_write(dev, 0x15, 0x00); - ov511_reg_write(dev, 0x18, 0x03); /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_PXCNT, pxcnt); + reg_w(ov, R511_CAM_LNCNT, lncnt); + reg_w(ov, R511_CAM_PXDIV, 0x00); + reg_w(ov, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_OPTS, 0x03); /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, pxcnt); - ov511_reg_write(dev, 0x1b, lncnt); - ov511_reg_write(dev, 0x1c, 0x00); - ov511_reg_write(dev, 0x1d, 0x00); - - if (ov511->compress) { - ov511_reg_write(dev, 0x78, 0x07); // Turn on Y & UV compression - ov511_reg_write(dev, 0x79, 0x03); // Enable LUTs - ov511_reset(ov511, OV511_RESET_OMNICE); + reg_w(ov, R511_SNAP_PXCNT, pxcnt); + reg_w(ov, R511_SNAP_LNCNT, lncnt); + reg_w(ov, R511_SNAP_PXDIV, 0x00); + reg_w(ov, R511_SNAP_LNDIV, 0x00); + + if (ov->compress) { + /* Enable Y and UV quantization and compression */ + reg_w(ov, R511_COMP_EN, 0x07); + reg_w(ov, R511_COMP_LUT_EN, 0x03); + ov51x_reset(ov, OV511_RESET_OMNICE); } //out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2866,17 +2836,15 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov518_mode_init_regs(struct usb_ov511 *ov511, +ov518_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int i; - struct usb_device *dev = ov511->dev; - unsigned char b[3]; /* Multiple-value reg buffer */ PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; for (i = 0; mlist518[i].width; i++) { @@ -2894,113 +2862,94 @@ // pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; // lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; // -// ov511_reg_write(dev, 0x12, pxcnt); -// ov511_reg_write(dev, 0x13, lncnt); +// reg_w(ov511, 0x12, pxcnt); +// reg_w(ov511, 0x13, lncnt); /******** Set the mode ********/ /* Mode independent regs */ - ov511_reg_write(dev, 0x2b, 0x00); - ov511_reg_write(dev, 0x2d, 0x00); - ov511_reg_write(dev, 0x3b, 0x00); - ov511_reg_write(dev, 0x3d, 0x00); + reg_w(ov, 0x2b, 0x00); + reg_w(ov, 0x2d, 0x00); + reg_w(ov, 0x3b, 0x00); + reg_w(ov, 0x3d, 0x00); /* Mode dependent regs. Regs 38 - 3e are always the same as * regs 28 - 2e */ - ov511_reg_write_mask(dev, 0x28, mlist518[i].reg28 + reg_w_mask(ov, 0x28, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x29, mlist518[i].reg29); - ov511_reg_write(dev, 0x2a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x2c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x2e, mlist518[i].reg2e); - ov511_reg_write_mask(dev, 0x38, mlist518[i].reg28 + reg_w(ov, 0x29, mlist518[i].reg29); + reg_w(ov, 0x2a, mlist518[i].reg2a); + reg_w(ov, 0x2c, mlist518[i].reg2c); + reg_w(ov, 0x2e, mlist518[i].reg2e); + reg_w_mask(ov, 0x38, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x39, mlist518[i].reg29); - ov511_reg_write(dev, 0x3a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x3c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x3e, mlist518[i].reg2e); - ov511_reg_write(dev, 0x24, mlist518[i].reg24); - ov511_reg_write(dev, 0x25, mlist518[i].reg25); + reg_w(ov, 0x39, mlist518[i].reg29); + reg_w(ov, 0x3a, mlist518[i].reg2a); + reg_w(ov, 0x3c, mlist518[i].reg2c); + reg_w(ov, 0x3e, mlist518[i].reg2e); + reg_w(ov, 0x24, mlist518[i].reg24); + reg_w(ov, 0x25, mlist518[i].reg25); /* Windows driver does this here; who knows why */ - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /******** Set the framerate (to 15 FPS) ********/ /* Mode independent, but framerate dependent, regs */ /* These are for 15 FPS only */ - ov511_reg_write(dev, 0x51, 0x08); - ov511_reg_write(dev, 0x22, 0x18); - ov511_reg_write(dev, 0x23, 0xff); - ov511_reg_write(dev, 0x71, 0x19); /* Compression-related? */ + reg_w(ov, 0x51, 0x08); + reg_w(ov, 0x22, 0x18); + reg_w(ov, 0x23, 0xff); + reg_w(ov, 0x71, 0x19); /* Compression-related? */ // FIXME: Sensor-specific /* Bit 5 is what matters here. Of course, it is "reserved" */ - ov51x_i2c_write(ov511, 0x54, 0x23); + i2c_w(ov, 0x54, 0x23); - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /* Mode dependent regs */ if ((width == 352 && height == 288) || (width == 320 && height == 240)) { - b[0]=0x80; b[1]=0x02; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0x90; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x8e; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x1a; b[1]=0x00; b[2]=0x02; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x14; b[1]=0x02; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xd0; b[1]=0x07; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x20; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x60; b[1]=0x02; - ov518_reg_write_multi(dev, 0xce, b, 2); - + /* 640 (280h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 640, 2); /* 280h */ + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ } else if ((width == 176 && height == 144) || (width == 160 && height == 120)) { - b[0]=0x80; b[1]=0x01; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0xc8; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x60; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x0f; b[1]=0x33; b[2]=0x01; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xec; b[1]=0x04; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x13; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x6d; b[1]=0x01; - ov518_reg_write_multi(dev, 0xce, b, 2); + /* 384 (180h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 384, 2); /* 180h */ + ov518_reg_w32(ov, 0xc4, 200, 2); /* c8h */ + ov518_reg_w32(ov, 0xc6, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc7, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc8, 96, 2); /* 60h */ + ov518_reg_w32(ov, 0xca, 78607, 3); /* 1330fh */ + ov518_reg_w32(ov, 0xcb, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xcc, 1260, 2); /* 4ech */ + ov518_reg_w32(ov, 0xcd, 19, 2); /* 13h */ + ov518_reg_w32(ov, 0xce, 365, 2); /* 16dh */ } else { /* Can't happen, since we already handled this case */ err("ov518_mode_init_regs(): **** logic error ****"); } - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); break; } - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; /* Reset it just for good measure */ - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; if (mlist518[i].width == 0) { @@ -3013,29 +2962,31 @@ /* This is a wrapper around the OV511, OV518, and sensor specific functions */ static int -mode_init_regs(struct usb_ov511 *ov511, +mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int rc = 0; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - rc = ov518_mode_init_regs(ov511, width, height, mode, sub_flag); + if (!ov || !ov->dev) + return -EFAULT; + + if (ov->bclass == BCL_OV518) { + rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); } else { - rc = ov511_mode_init_regs(ov511, width, height, mode, sub_flag); + rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); } if (FATAL_ERROR(rc)) return rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: case SEN_OV6620: case SEN_OV6630: - rc = set_ov_sensor_window(ov511, width, height, mode, sub_flag); + rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); break; case SEN_KS0127: case SEN_KS0127B: @@ -3043,10 +2994,10 @@ rc = -EINVAL; break; case SEN_SAA7111A: -// rc = mode_init_saa_sensor_regs(ov511, width, height, mode, +// rc = mode_init_saa_sensor_regs(ov, width, height, mode, // sub_flag); - PDEBUG(1, "SAA status = 0X%x", ov51x_i2c_read(ov511, 0x1f)); + PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f)); break; default: err("Unknown sensor"); @@ -3057,25 +3008,25 @@ return rc; /* Sensor-independent settings */ - rc = sensor_set_auto_brightness(ov511, ov511->auto_brt); + rc = sensor_set_auto_brightness(ov, ov->auto_brt); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_auto_exposure(ov511, ov511->auto_exp); + rc = sensor_set_auto_exposure(ov, ov->auto_exp); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_banding_filter(ov511, bandingfilter); + rc = sensor_set_banding_filter(ov, bandingfilter); if (FATAL_ERROR(rc)) return rc; - if (ov511->lightfreq) { - rc = sensor_set_light_freq(ov511, lightfreq); + if (ov->lightfreq) { + rc = sensor_set_light_freq(ov, lightfreq); if (FATAL_ERROR(rc)) return rc; } - rc = sensor_set_backlight(ov511, ov511->backlight); + rc = sensor_set_backlight(ov, ov->backlight); if (FATAL_ERROR(rc)) return rc; @@ -3086,28 +3037,28 @@ * useful for apps that use read() and do not set these. */ static int -ov51x_set_default_params(struct usb_ov511 *ov511) +ov51x_set_default_params(struct usb_ov511 *ov) { int i; - PDEBUG(3, "%dx%d, RGB24", ov511->maxwidth, ov511->maxheight); + PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight); /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = ov511->maxwidth; - ov511->frame[i].height = ov511->maxheight; - ov511->frame[i].bytes_read = 0; + ov->frame[i].width = ov->maxwidth; + ov->frame[i].height = ov->maxheight; + ov->frame[i].bytes_read = 0; if (force_palette) - ov511->frame[i].format = force_palette; + ov->frame[i].format = force_palette; else - ov511->frame[i].format = VIDEO_PALETTE_RGB24; - ov511->frame[i].depth = ov511_get_depth(ov511->frame[i].format); + ov->frame[i].format = VIDEO_PALETTE_RGB24; + ov->frame[i].depth = get_depth(ov->frame[i].format); } /* Initialize to max width/height, RGB24 */ - if (mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, - ov511->frame[0].format, 0) < 0) + if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, + ov->frame[0].format, 0) < 0) return -EINVAL; return 0; @@ -3121,18 +3072,17 @@ /* Set analog input port of decoder */ static int -decoder_set_input(struct usb_ov511 *ov511, int input) +decoder_set_input(struct usb_ov511 *ov, int input) { PDEBUG(4, "port %d", input); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { /* Select mode */ - ov51x_i2c_write_mask(ov511, 0x02, input, 0x07); + i2c_w_mask(ov, 0x02, input, 0x07); /* Bypass chrominance trap for modes 4..7 */ - ov51x_i2c_write_mask(ov511, 0x09, - (input > 3) ? 0x80:0x00, 0x80); + i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); break; } default: @@ -3144,9 +3094,9 @@ /* Get ASCII name of video input */ static int -decoder_get_input_name(struct usb_ov511 *ov511, int input, char *name) +decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) { - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { if (input < 0 || input > 7) @@ -3167,11 +3117,11 @@ /* Set norm (NTSC, PAL, SECAM, AUTO) */ static int -decoder_set_norm(struct usb_ov511 *ov511, int norm) +decoder_set_norm(struct usb_ov511 *ov, int norm) { PDEBUG(4, "%d", norm); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { int reg_8, reg_e; @@ -3192,8 +3142,8 @@ return -EINVAL; } - ov51x_i2c_write_mask(ov511, 0x08, reg_8, 0xc0); - ov51x_i2c_write_mask(ov511, 0x0e, reg_e, 0x70); + i2c_w_mask(ov, 0x08, reg_8, 0xc0); + i2c_w_mask(ov, 0x0e, reg_e, 0x70); break; } default: @@ -3240,8 +3190,8 @@ #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16))) static inline void -ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, - int rowPixels, unsigned char * rgb, int bits) +move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb, int bits) { const int rvScale = 91881; const int guScale = -22553; @@ -3311,10 +3261,10 @@ **********************************************************************/ /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the - * array at pOut is specified by w. + * image at pOut is specified by w. */ static inline void -ov511_make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) { unsigned char *pOut1 = pOut; int x, y; @@ -3352,7 +3302,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; } @@ -3411,8 +3361,8 @@ for (y = 0; y < frame->rawheight - 1; y += 16) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 16) { - ov511_make_8x8(pIn, pOut, w); - ov511_make_8x8(pIn + 64, pOut + a/4, w); + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); pIn += 384; pOut += 8; } @@ -3426,7 +3376,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; if ((++k) > 3) { @@ -3483,17 +3433,17 @@ * **********************************************************************/ -/* Chooses a decompression module, locks it, and sets ov511->decomp_ops +/* Chooses a decompression module, locks it, and sets ov->decomp_ops * accordingly. Returns -ENXIO if decompressor is not available, otherwise * returns 0 if no other error. */ static int -ov51x_request_decompressor(struct usb_ov511 *ov511) +request_decompressor(struct usb_ov511 *ov) { - if (!ov511) + if (!ov) return -ENODEV; - if (ov511->decomp_ops) { + if (ov->decomp_ops) { err("ERROR: Decompressor already requested!"); return -EINVAL; } @@ -3501,24 +3451,23 @@ lock_kernel(); /* Try to get MMX, and fall back on no-MMX if necessary */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + if (ov->bclass == BCL_OV511) { if (ov511_mmx_decomp_ops) { PDEBUG(3, "Using OV511 MMX decompressor"); - ov511->decomp_ops = ov511_mmx_decomp_ops; + ov->decomp_ops = ov511_mmx_decomp_ops; } else if (ov511_decomp_ops) { PDEBUG(3, "Using OV511 decompressor"); - ov511->decomp_ops = ov511_decomp_ops; + ov->decomp_ops = ov511_decomp_ops; } else { err("No decompressor available"); } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (ov518_mmx_decomp_ops) { PDEBUG(3, "Using OV518 MMX decompressor"); - ov511->decomp_ops = ov518_mmx_decomp_ops; + ov->decomp_ops = ov518_mmx_decomp_ops; } else if (ov518_decomp_ops) { PDEBUG(3, "Using OV518 decompressor"); - ov511->decomp_ops = ov518_decomp_ops; + ov->decomp_ops = ov518_decomp_ops; } else { err("No decompressor available"); } @@ -3526,13 +3475,13 @@ err("Unknown bridge"); } - if (ov511->decomp_ops) { - if (!ov511->decomp_ops->decomp_lock) { - ov511->decomp_ops = NULL; + if (ov->decomp_ops) { + if (!ov->decomp_ops->decomp_lock) { + ov->decomp_ops = NULL; unlock_kernel(); return -ENOSYS; } - ov511->decomp_ops->decomp_lock(); + ov->decomp_ops->decomp_lock(); unlock_kernel(); return 0; } else { @@ -3541,25 +3490,25 @@ } } -/* Unlocks decompression module and nulls ov511->decomp_ops. Safe to call even - * if ov511->decomp_ops is NULL. +/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even + * if ov->decomp_ops is NULL. */ static void -ov51x_release_decompressor(struct usb_ov511 *ov511) +release_decompressor(struct usb_ov511 *ov) { int released = 0; /* Did we actually do anything? */ - if (!ov511) + if (!ov) return; lock_kernel(); - if (ov511->decomp_ops && ov511->decomp_ops->decomp_unlock) { - ov511->decomp_ops->decomp_unlock(); + if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) { + ov->decomp_ops->decomp_unlock(); released = 1; } - ov511->decomp_ops = NULL; + ov->decomp_ops = NULL; unlock_kernel(); @@ -3568,26 +3517,26 @@ } static void -ov51x_decompress(struct usb_ov511 *ov511, struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) +decompress(struct usb_ov511 *ov, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) { - if (!ov511->decomp_ops) - if (ov51x_request_decompressor(ov511)) + if (!ov->decomp_ops) + if (request_decompressor(ov)) return; PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); if (frame->format == VIDEO_PALETTE_GREY - && ov511->decomp_ops->decomp_400) { - int ret = ov511->decomp_ops->decomp_400( + && ov->decomp_ops->decomp_400) { + int ret = ov->decomp_ops->decomp_400( pIn0, pOut0, frame->rawwidth, frame->rawheight, frame->bytes_recvd); PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); - } else if (ov511->decomp_ops->decomp_420) { - int ret = ov511->decomp_ops->decomp_420( + } else if (ov->decomp_ops->decomp_420) { + int ret = ov->decomp_ops->decomp_420( pIn0, pOut0, frame->rawwidth, @@ -3627,8 +3576,8 @@ u = (*pU++) - 128; v = (*pV++) - 128; - ov511_move_420_block(y00, y01, y10, y11, u, v, - frame->width, pOut, bits); + move_420_block(y00, y01, y10, y11, u, v, + frame->width, pOut, bits); pY += 2; pOut += 2 * bytes; @@ -3783,11 +3732,11 @@ * 4. Fix the RGB offset, if necessary */ static void -ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame) +ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) { if (dumppix) { memset(frame->data, 0, - MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); memmove(frame->data, frame->rawdata, frame->bytes_recvd); return; @@ -3796,9 +3745,9 @@ /* YUV400 must be handled separately */ if (frame->format == VIDEO_PALETTE_GREY) { /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3808,7 +3757,7 @@ frame->data); } else { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->data); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3820,12 +3769,12 @@ /* Process frame->data to frame->rawdata */ if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, frame->tempdata); + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata); /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { memmove(frame->rawdata, frame->tempdata, MAX_RAW_DATA_SIZE(frame->width, frame->height)); deinterlace(frame, RAWFMT_YUV420, frame->rawdata, @@ -3879,7 +3828,7 @@ **********************************************************************/ static int -ov511_move_data(struct usb_ov511 *ov511, urb_t *urb) +ov511_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int data_size, num, offset, i, totlen = 0; @@ -3889,7 +3838,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); - data_size = ov511->packet_size - 1; + data_size = ov->packet_size - 1; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -3900,15 +3849,15 @@ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; + aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1; - if (!n || ov511->curframe == -1) + if (!n || ov->curframe == -1) continue; if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; + frame = &ov->frame[ov->curframe]; /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the @@ -3926,7 +3875,7 @@ if (printph) { info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", - cdata[ov511->packet_size - 1], + cdata[ov->packet_size - 1], cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5], cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]); } @@ -3940,7 +3889,7 @@ /* Frame end */ if (cdata[8] & 0x80) { ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); /* Get the actual frame size from the EOF header */ @@ -3948,21 +3897,21 @@ frame->rawheight = ((int)(cdata[10]) + 1) * 8; PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, - (int)(cdata[ov511->packet_size - 1]), + ov->curframe, + (int)(cdata[ov->packet_size - 1]), frame->rawwidth, frame->rawheight, frame->bytes_recvd); /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -3976,20 +3925,20 @@ /* 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; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; } } else { PDEBUG(5, "Frame done, but not scanning"); @@ -3999,7 +3948,7 @@ */ } else { /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ @@ -4048,24 +3997,24 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n - 1; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - (n - 1), &cdata[0], n - 1); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else if (!frame->compressed && !remove_zeros) { frame->bytes_recvd += num; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - num, &cdata[offset], num); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ int b, in = 0, allzero, copied=0; if (offset) { @@ -4088,7 +4037,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 32 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 32); copied += 32; @@ -4112,7 +4061,7 @@ } static int -ov518_move_data(struct usb_ov511 *ov511, urb_t *urb) +ov518_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int i, data_size, totlen = 0; @@ -4122,7 +4071,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); /* OV518(+) has no packet numbering */ - data_size = ov511->packet_size; + data_size = ov->packet_size; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -4138,7 +4087,7 @@ continue; } - if (ov511->curframe == -1) { + if (ov->curframe == -1) { PDEBUG(4, "No frame currently active"); continue; } @@ -4146,21 +4095,7 @@ if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; - -#if 0 - { - int d; - /* Print all data */ - for (d = 0; d <= data_size - 16; d += 16) { - info("%4x: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", d, - cdata[d], cdata[d+1], cdata[d+2], cdata[d+3], - cdata[d+4], cdata[d+5], cdata[d+6], cdata[d+7], - cdata[d+8], cdata[d+9], cdata[d+10], cdata[d+11], - cdata[d+12], cdata[d+13], cdata[d+14], cdata[d+15]); - } - } -#endif + frame = &ov->frame[ov->curframe]; if (printph) { info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", @@ -4178,7 +4113,7 @@ goto eof; } else { //scanstate == STATE_SCANNING /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); goto sof; } } else { @@ -4187,11 +4122,11 @@ eof: ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, + ov->curframe, (int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd); // FIXME: Since we don't know the header formats yet, @@ -4200,13 +4135,13 @@ frame->rawheight = frame->height; /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -4220,21 +4155,21 @@ /* 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; - frame = &ov511->frame[iFrameNext]; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; + frame = &ov->frame[iFrameNext]; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; PDEBUG(4, "SOF dropped (no active frame)"); continue; /* Nowhere to store this frame */ } @@ -4267,31 +4202,26 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - n, &cdata[0], n); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* All incoming data are divided into 8-byte segments. If the * segment contains all zero bytes, it must be skipped. These * zero-segments allow the OV518 to mainain a constant data rate * regardless of the effectiveness of the compression. Segments * are aligned relative to the beginning of each isochronous - * packet. The first segment is a header. + * packet. The first segment is a header (the decompressor + * skips it later). */ int b, in = 0, allzero, copied=0; -// Decompressor expects the header -#if 0 - if (frame->bytes_recvd == 0) - in += 8; /* Skip header */ -#endif - while (in < n) { allzero = 1; for (b = 0; b < 8; b++) { @@ -4305,7 +4235,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 8 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 8); copied += 8; @@ -4323,43 +4253,41 @@ } static void -ov511_isoc_irq(struct urb *urb) +ov51x_isoc_irq(struct urb *urb) { int len; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; if (!urb->context) { PDEBUG(4, "no context"); return; } - ov511 = (struct usb_ov511 *) urb->context; + ov = (struct usb_ov511 *) urb->context; - if (!ov511->dev || !ov511->user) { + if (!ov || !ov->dev || !ov->user) { PDEBUG(4, "no device, or not open"); return; } - if (!ov511->streaming) { + if (!ov->streaming) { PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } /* Copy the data received into our frame buffer */ - if (ov511->curframe >= 0) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - len = ov511_move_data(ov511, urb); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - len = ov518_move_data(ov511, urb); + if (ov->curframe >= 0) { + if (ov->bclass == BCL_OV511) + len = ov511_move_data(ov, urb); + else if (ov->bclass == BCL_OV518) + len = ov518_move_data(ov, urb); else - err("Unknown bridge device (%d)", ov511->bridge); - } else if (waitqueue_active(&ov511->wq)) { - wake_up_interruptible(&ov511->wq); + err("Unknown bridge device (%d)", ov->bridge); + } else if (waitqueue_active(&ov->wq)) { + wake_up_interruptible(&ov->wq); } - urb->dev = ov511->dev; + urb->dev = ov->dev; return; } @@ -4371,16 +4299,16 @@ ***************************************************************************/ static int -ov511_init_isoc(struct usb_ov511 *ov511) +ov51x_init_isoc(struct usb_ov511 *ov) { - urb_t *urb; + struct urb *urb; int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); - ov511->curframe = -1; + ov->curframe = -1; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (cams == 1) size = 993; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4388,7 +4316,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (cams == 1) size = 961; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4398,8 +4326,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (cams == 1) size = 896; else if (cams == 2) size = 512; else if (cams == 3 || cams == 4) size = 256; @@ -4415,14 +4342,13 @@ if (packetsize == -1) { // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_set_packet_size(ov511, 640); + if (ov->bclass == BCL_OV518) + ov51x_set_packet_size(ov, 640); else - ov511_set_packet_size(ov511, size); + ov51x_set_packet_size(ov, size); } else { info("Forcing packet size to %d", packetsize); - ov511_set_packet_size(ov511, packetsize); + ov51x_set_packet_size(ov, packetsize); } for (n = 0; n < OV511_NUMSBUF; n++) { @@ -4432,32 +4358,30 @@ err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } - ov511->sbuf[n].urb = urb; - urb->dev = ov511->dev; - urb->context = ov511; - urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); + ov->sbuf[n].urb = urb; + urb->dev = ov->dev; + urb->context = ov; + urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ov511->sbuf[n].data; - urb->complete = ov511_isoc_irq; + urb->transfer_buffer = ov->sbuf[n].data; + urb->complete = ov51x_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = - ov511->packet_size * FRAMES_PER_DESC; + urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = - ov511->packet_size * fx; - urb->iso_frame_desc[fx].length = ov511->packet_size; + urb->iso_frame_desc[fx].offset = ov->packet_size * fx; + urb->iso_frame_desc[fx].length = ov->packet_size; } } - ov511->streaming = 1; + ov->streaming = 1; - ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb; + ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb; for (n = 0; n < OV511_NUMSBUF - 1; n++) - ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb; + ov->sbuf[n].urb->next = ov->sbuf[n+1].urb; for (n = 0; n < OV511_NUMSBUF; n++) { - ov511->sbuf[n].urb->dev = ov511->dev; - err = usb_submit_urb(ov511->sbuf[n].urb); + ov->sbuf[n].urb->dev = ov->dev; + err = usb_submit_urb(ov->sbuf[n].urb); if (err) err("init isoc: usb_submit_urb(%d) ret %d", n, err); } @@ -4466,51 +4390,51 @@ } static void -ov511_stop_isoc(struct usb_ov511 *ov511) +ov51x_stop_isoc(struct usb_ov511 *ov) { int n; - if (!ov511->streaming || !ov511->dev) + if (!ov->streaming || !ov->dev) return; PDEBUG(3, "*** Stopping capture ***"); - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } } static int -ov511_new_frame(struct usb_ov511 *ov511, int framenum) +ov51x_new_frame(struct usb_ov511 *ov, int framenum) { struct ov511_frame *frame; int newnum; - PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, - framenum); - if (!ov511->dev) + PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); + + if (!ov->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) { + if (ov->curframe == -1) { newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; - if (ov511->frame[newnum].grabstate == FRAME_READY) + if (ov->frame[newnum].grabstate == FRAME_READY) framenum = newnum; } else return 0; - frame = &ov511->frame[framenum]; + frame = &ov->frame[framenum]; PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, frame->width, frame->height); @@ -4519,16 +4443,16 @@ frame->scanstate = STATE_SCANNING; frame->snapshot = 0; - ov511->curframe = framenum; + ov->curframe = framenum; /* Make sure it's not too big */ - if (frame->width > ov511->maxwidth) - frame->width = ov511->maxwidth; + if (frame->width > ov->maxwidth) + frame->width = ov->maxwidth; frame->width &= ~7L; /* Multiple of 8 */ - if (frame->height > ov511->maxheight) - frame->height = ov511->maxheight; + if (frame->height > ov->maxheight) + frame->height = ov->maxheight; frame->height &= ~3L; /* Multiple of 4 */ @@ -4540,84 +4464,86 @@ * Buffer management * ***************************************************************************/ + static int -ov511_alloc(struct usb_ov511 *ov511) +ov51x_alloc(struct usb_ov511 *ov) { int i; - int w = ov511->maxwidth; - int h = ov511->maxheight; + const int w = ov->maxwidth; + const int h = ov->maxheight; + const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); + const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; - del_timer(&ov511->buf_timer); + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; + del_timer(&ov->buf_timer); } - if (ov511->buf_state == BUF_ALLOCATED) + if (ov->buf_state == BUF_ALLOCATED) goto out; - ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - if (!ov511->fbuf) + ov->fbuf = rvmalloc(data_bufsize); + if (!ov->fbuf) goto error; - ov511->rawfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->rawfbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->rawfbuf = vmalloc(raw_bufsize); + if (!ov->rawfbuf) { + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->rawfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->rawfbuf, 0, raw_bufsize); - ov511->tempfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->tempfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->tempfbuf = vmalloc(raw_bufsize); + if (!ov->tempfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->tempfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->tempfbuf, 0, raw_bufsize); for (i = 0; i < OV511_NUMSBUF; i++) { - ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC * + ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ov511->sbuf[i].data) { + if (!ov->sbuf[i].data) { while (--i) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, - OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); + PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE(w, h); - ov511->frame[i].rawdata = ov511->rawfbuf + ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); + ov->frame[i].rawdata = ov->rawfbuf + i * MAX_RAW_DATA_SIZE(w, h); - ov511->frame[i].tempdata = ov511->tempfbuf + ov->frame[i].tempdata = ov->tempfbuf + i * MAX_RAW_DATA_SIZE(w, h); - PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); + PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); } - ov511->buf_state = BUF_ALLOCATED; + ov->buf_state = BUF_ALLOCATED; out: - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); return 0; error: - ov511->buf_state = BUF_NOT_ALLOCATED; - up(&ov511->buf_lock); + ov->buf_state = BUF_NOT_ALLOCATED; + up(&ov->buf_lock); PDEBUG(4, "errored"); return -ENOMEM; } @@ -4628,206 +4554,212 @@ * them if you explicitly free them somewhere else! */ static void -ov511_do_dealloc(struct usb_ov511 *ov511) +ov51x_do_dealloc(struct usb_ov511 *ov) { int i; PDEBUG(4, "entered"); - if (ov511->fbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); - ov511->fbuf = NULL; + if (ov->fbuf) { + rvfree(ov->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + ov->fbuf = NULL; } - if (ov511->rawfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; + if (ov->rawfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; } - if (ov511->tempfbuf) { - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; + if (ov->tempfbuf) { + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; } for (i = 0; i < OV511_NUMSBUF; i++) { - if (ov511->sbuf[i].data) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + if (ov->sbuf[i].data) { + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = NULL; - ov511->frame[i].rawdata = NULL; - ov511->frame[i].tempdata = NULL; + ov->frame[i].data = NULL; + ov->frame[i].rawdata = NULL; + ov->frame[i].tempdata = NULL; } PDEBUG(4, "buffer memory deallocated"); - ov511->buf_state = BUF_NOT_ALLOCATED; + ov->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving"); } static void -ov511_buf_callback(unsigned long data) +ov51x_buf_callback(unsigned long data) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)data; + struct usb_ov511 *ov = (struct usb_ov511 *)data; PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) - ov511_do_dealloc(ov511); + if (ov->buf_state == BUF_PEND_DEALLOC) + ov51x_do_dealloc(ov); - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } static void -ov511_dealloc(struct usb_ov511 *ov511, int now) +ov51x_dealloc(struct usb_ov511 *ov, int now) { - struct timer_list *bt = &(ov511->buf_timer); + struct timer_list *bt = &(ov->buf_timer); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later"); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; del_timer(bt); } if (now) - ov511_do_dealloc(ov511); + ov51x_do_dealloc(ov); else { - ov511->buf_state = BUF_PEND_DEALLOC; + ov->buf_state = BUF_PEND_DEALLOC; init_timer(bt); - bt->function = ov511_buf_callback; - bt->data = (unsigned long)ov511; + bt->function = ov51x_buf_callback; + bt->data = (unsigned long)ov; bt->expires = jiffies + buf_timeout * HZ; add_timer(bt); } - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } /**************************************************************************** * - * V4L API + * V4L 1 API * ***************************************************************************/ static int -ov511_open(struct video_device *vdev, int flags) +ov51x_v4l1_open(struct video_device *vdev, int flags) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int err, i; PDEBUG(4, "opening"); - down(&ov511->lock); + down(&ov->lock); err = -EBUSY; - if (ov511->user) + if (ov->user) goto out; err = -ENOMEM; - if (ov511_alloc(ov511)) + if (ov51x_alloc(ov)) goto out; - ov511->sub_flag = 0; + ov->sub_flag = 0; /* In case app doesn't set them... */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto out; /* Make sure frames are reset */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].grabstate = FRAME_UNUSED; - ov511->frame[i].bytes_read = 0; + ov->frame[i].grabstate = FRAME_UNUSED; + ov->frame[i].bytes_read = 0; } /* If compression is on, make sure now that a * decompressor can be loaded */ - if (ov511->compress && !ov511->decomp_ops) { - err = ov51x_request_decompressor(ov511); - if (err) + if (ov->compress && !ov->decomp_ops) { + err = request_decompressor(ov); + if (err && !dumppix) goto out; } - err = ov511_init_isoc(ov511); + err = ov51x_init_isoc(ov); if (err) { - ov511_dealloc(ov511, 0); + ov51x_dealloc(ov, 0); goto out; } - ov511->user++; + ov->user++; - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 1); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 1); out: - up(&ov511->lock); + up(&ov->lock); return err; } static void -ov511_close(struct video_device *dev) +ov51x_v4l1_close(struct video_device *vdev) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(4, "ov511_close"); - down(&ov511->lock); + down(&ov->lock); - ov511->user--; - ov511_stop_isoc(ov511); + ov->user--; + ov51x_stop_isoc(ov); - ov51x_release_decompressor(ov511); + release_decompressor(ov); - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); - if (ov511->dev) - ov511_dealloc(ov511, 0); + if (ov->dev) + ov51x_dealloc(ov, 0); - up(&ov511->lock); + up(&ov->lock); /* Device unplugged while open. Only a minimum of unregistration is done * here; the disconnect callback already did the rest. */ - if (!ov511->dev) { - ov511_dealloc(ov511, 1); - video_unregister_device(&ov511->vdev); - kfree(ov511); - ov511 = NULL; + if (!ov->dev) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + video_unregister_device(&ov->vdev); + kfree(ov); + ov = NULL; } } static int -ov511_init_done(struct video_device *vdev) +ov51x_v4l1_init_done(struct video_device *vdev) { #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_ov511_cam((struct usb_ov511 *)vdev); + create_proc_ov511_cam(vdev->priv); #endif return 0; } static long -ov511_write(struct video_device *vdev, const char *buf, - unsigned long count, int noblock) +ov51x_v4l1_write(struct video_device *vdev, const char *buf, + unsigned long count, int noblock) { return -EINVAL; } /* Do not call this function directly! */ static int -ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, + void *arg) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(5, "IOCtl: 0x%X", cmd); - if (!ov511->dev) + if (!ov->dev) return -EIO; switch (cmd) { @@ -4839,20 +4771,20 @@ memset(&b, 0, sizeof(b)); sprintf(b.name, "%s USB Camera", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; - if (ov511->has_tuner) + if (ov->has_tuner) b.type |= VID_TYPE_TUNER; - b.channels = ov511->num_inputs; - b.audios = ov511->has_audio_proc ? 1:0; - b.maxwidth = ov511->maxwidth; - b.maxheight = ov511->maxheight; - b.minwidth = ov511->minwidth; - b.minheight = ov511->minheight; + b.channels = ov->num_inputs; + b.audios = ov->has_audio_proc ? 1:0; + b.maxwidth = ov->maxwidth; + b.maxheight = ov->maxheight; + b.minwidth = ov->minwidth; + b.minheight = ov->minheight; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; @@ -4868,18 +4800,18 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - v.norm = ov511->norm; - v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; - v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0; - v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0; -// v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0; - v.tuners = (ov511->has_tuner) ? 1:0; - decoder_get_input_name(ov511, v.channel, v.name); + v.norm = ov->norm; + v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; + v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0; + v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0; +// v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; + v.tuners = (ov->has_tuner) ? 1:0; + decoder_get_input_name(ov, v.channel, v.name); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -4897,7 +4829,7 @@ return -EFAULT; /* Make sure it's not a camera */ - if (!ov511->has_decoder) { + if (!ov->has_decoder) { if (v.channel == 0) return 0; else @@ -4912,16 +4844,16 @@ return -EINVAL; } - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - err = decoder_set_input(ov511, v.channel); + err = decoder_set_input(ov, v.channel); if (err) return err; - err = decoder_set_norm(ov511, v.norm); + err = decoder_set_norm(ov, v.norm); if (err) return err; @@ -4935,7 +4867,7 @@ memset(&p, 0, sizeof(p)); - if (sensor_get_picture(ov511, &p)) + if (sensor_get_picture(ov, &p)) return -EIO; if (copy_to_user(arg, &p, sizeof(p))) @@ -4953,10 +4885,10 @@ if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - if (!ov511_get_depth(p.palette)) + if (!get_depth(p.palette)) return -EINVAL; - if (sensor_set_picture(ov511, &p)) + if (sensor_set_picture(ov, &p)) return -EIO; if (force_palette && p.palette != force_palette) { @@ -4965,23 +4897,22 @@ } // FIXME: Format should be independent of frames - if (p.palette != ov511->frame[0].format) { + if (p.palette != ov->frame[0].format) { PDEBUG(4, "Detected format change"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - mode_init_regs(ov511, ov511->frame[0].width, - ov511->frame[0].height, p.palette, - ov511->sub_flag); + mode_init_regs(ov, ov->frame[0].width, + ov->frame[0].height, p.palette, ov->sub_flag); } PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].depth = p.depth; - ov511->frame[i].format = p.palette; + ov->frame[i].depth = p.depth; + ov->frame[i].format = p.palette; } return 0; @@ -4994,7 +4925,7 @@ if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; - ov511->sub_flag = vf; + ov->sub_flag = vf; return 0; } case VIDIOCSCAPTURE: @@ -5022,10 +4953,10 @@ if (vc.height == 0) vc.height = 16; - ov511->subx = vc.x; - ov511->suby = vc.y; - ov511->subw = vc.width; - ov511->subh = vc.height; + ov->subx = vc.x; + ov->suby = vc.y; + ov->subw = vc.width; + ov->subh = vc.height; return 0; } @@ -5045,25 +4976,25 @@ return -EINVAL; if (vw.clipcount) return -EINVAL; - if (vw.height != ov511->maxheight) + if (vw.height != ov->maxheight) return -EINVAL; - if (vw.width != ov511->maxwidth) + if (vw.width != ov->maxwidth) return -EINVAL; #endif /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - result = mode_init_regs(ov511, vw.width, vw.height, - ov511->frame[0].format, ov511->sub_flag); + result = mode_init_regs(ov, vw.width, vw.height, + ov->frame[0].format, ov->sub_flag); if (result < 0) return result; for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = vw.width; - ov511->frame[i].height = vw.height; + ov->frame[i].width = vw.width; + ov->frame[i].height = vw.height; } return 0; @@ -5075,8 +5006,8 @@ memset(&vw, 0, sizeof(vw)); vw.x = 0; /* FIXME */ vw.y = 0; - vw.width = ov511->frame[0].width; - vw.height = ov511->frame[0].height; + vw.width = ov->frame[0].width; + vw.height = ov->frame[0].height; vw.flags = 30; PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); @@ -5095,13 +5026,13 @@ memset(&vm, 0, sizeof(vm)); vm.size = OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); vm.frames = OV511_NUMFRAMES; vm.offsets[0] = 0; for (i = 1; i < OV511_NUMFRAMES; i++) { vm.offsets[i] = vm.offsets[i-1] - + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); } if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) @@ -5121,7 +5052,7 @@ PDEBUG(4, "frame: %d, size: %dx%d, format: %d", vm.frame, vm.width, vm.height, vm.format); - depth = ov511_get_depth(vm.format); + depth = get_depth(vm.format); if (!depth) { err("VIDIOCMCAPTURE: invalid format (%d)", vm.format); return -EINVAL; @@ -5132,13 +5063,13 @@ return -EINVAL; } - if (vm.width > ov511->maxwidth - || vm.height > ov511->maxheight) { + if (vm.width > ov->maxwidth + || vm.height > ov->maxheight) { err("VIDIOCMCAPTURE: requested dimensions too big"); return -EINVAL; } - if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) { + if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) { PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); return -EBUSY; } @@ -5148,38 +5079,38 @@ return -EINVAL; } - if ((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].depth != depth)) { + if ((ov->frame[vm.frame].width != vm.width) || + (ov->frame[vm.frame].height != vm.height) || + (ov->frame[vm.frame].format != vm.format) || + (ov->frame[vm.frame].sub_flag != ov->sub_flag) || + (ov->frame[vm.frame].depth != depth)) { PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - ret = mode_init_regs(ov511, vm.width, vm.height, - vm.format, ov511->sub_flag); + ret = mode_init_regs(ov, vm.width, vm.height, + vm.format, ov->sub_flag); #if 0 if (ret < 0) { PDEBUG(1, "Got error while initializing regs "); return ret; } #endif - 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].depth = depth; + ov->frame[vm.frame].width = vm.width; + ov->frame[vm.frame].height = vm.height; + ov->frame[vm.frame].format = vm.format; + ov->frame[vm.frame].sub_flag = ov->sub_flag; + ov->frame[vm.frame].depth = depth; } /* Mark it as ready */ - ov511->frame[vm.frame].grabstate = FRAME_READY; + ov->frame[vm.frame].grabstate = FRAME_READY; PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame); - return ov511_new_frame(ov511, vm.frame); + return ov51x_new_frame(ov, vm.frame); } case VIDIOCSYNC: { @@ -5194,7 +5125,7 @@ return -EINVAL; } - frame = &ov511->frame[fnum]; + frame = &ov->frame[fnum]; PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, frame->grabstate); @@ -5206,7 +5137,7 @@ case FRAME_GRABBING: case FRAME_ERROR: redo: - if (!ov511->dev) + if (!ov->dev) return -EIO; rc = wait_event_interruptible(frame->wq, @@ -5219,15 +5150,15 @@ if (frame->grabstate == FRAME_ERROR) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } /* Fall through */ case FRAME_DONE: - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } @@ -5236,13 +5167,13 @@ /* Reset the hardware snapshot button */ /* FIXME - Is this the best place for this? */ - if ((ov511->snap_enabled) && (frame->snapshot)) { + if ((ov->snap_enabled) && (frame->snapshot)) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); break; } /* end switch */ @@ -5271,7 +5202,7 @@ memset(&vu, 0, sizeof(vu)); - vu.video = ov511->vdev.minor; /* Video minor */ + vu.video = ov->vdev.minor; /* Video minor */ vu.vbi = VIDEO_NO_UNIT; /* VBI minor */ vu.radio = VIDEO_NO_UNIT; /* Radio minor */ vu.audio = VIDEO_NO_UNIT; /* Audio minor */ @@ -5291,7 +5222,7 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (!ov511->has_tuner || v.tuner) // Only tuner 0 + if (!ov->has_tuner || v.tuner) // Only tuner 0 return -EINVAL; strcpy(v.name, "Television"); @@ -5305,7 +5236,7 @@ v.mode = 0; /* FIXME: Not sure what this is yet */ v.signal = 0xFFFF; /* unknown */ - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -5323,7 +5254,7 @@ return -EFAULT; /* Only no or one tuner for now */ - if (!ov511->has_tuner || v.tuner) + if (!ov->has_tuner || v.tuner) return -EINVAL; /* and it only has certain valid modes */ @@ -5332,21 +5263,21 @@ v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; /* Is this right/necessary? */ - err = decoder_set_norm(ov511, v.mode); + err = decoder_set_norm(ov, v.mode); if (err) return err; - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); return 0; } case VIDIOCGFREQ: { - unsigned long v = ov511->freq; + unsigned long v = ov->freq; PDEBUG(4, "VIDIOCGFREQ"); - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; #if 0 /* FIXME: this is necessary for testing */ @@ -5361,7 +5292,7 @@ { unsigned long v; - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; if (copy_from_user(&v, arg, sizeof(v))) @@ -5369,8 +5300,8 @@ PDEBUG(4, "VIDIOCSFREQ: %lx", v); - ov511->freq = v; - call_i2c_clients(ov511, cmd, &v); + ov->freq = v; + call_i2c_clients(ov, cmd, &v); return 0; } @@ -5389,29 +5320,29 @@ } static int -ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { int rc; - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - rc = ov511_ioctl_internal(vdev, cmd, arg); + rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg); - up(&ov511->lock); + up(&ov->lock); return rc; } static inline long -ov511_read(struct video_device *vdev, char *buf, unsigned long count, - int noblock) +ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, + int noblock) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int i, rc = 0, frmx = -1; struct ov511_frame *frame; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); @@ -5421,16 +5352,16 @@ goto error; } - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } // FIXME: Only supports two frames /* See if a frame is completed, then use it. */ - if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; - else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ frmx = 1; /* If nonblocking we return immediately */ @@ -5442,24 +5373,24 @@ /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ /* See if a frame is in process (grabbing), then use it. */ if (frmx == -1) { - if (ov511->frame[0].grabstate == FRAME_GRABBING) + if (ov->frame[0].grabstate == FRAME_GRABBING) frmx = 0; - else if (ov511->frame[1].grabstate == FRAME_GRABBING) + else if (ov->frame[1].grabstate == FRAME_GRABBING) frmx = 1; } /* If no frame is active, start one. */ if (frmx == -1) { - if ((rc = ov511_new_frame(ov511, frmx = 0))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx = 0))) { + err("read: ov51x_new_frame error"); goto error; } } - frame = &ov511->frame[frmx]; + frame = &ov->frame[frmx]; restart: - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } @@ -5478,9 +5409,9 @@ if (frame->grabstate == FRAME_ERROR) { frame->bytes_read = 0; - err("** ick! ** Errored frame %d", ov511->curframe); - if (ov511_new_frame(ov511, frmx)) { - err("read: ov511_new_frame error"); + err("** ick! ** Errored frame %d", ov->curframe); + if (ov51x_new_frame(ov, frmx)) { + err("read: ov51x_new_frame error"); goto error; } goto restart; @@ -5488,25 +5419,25 @@ /* Repeat until we get a snapshot frame */ - if (ov511->snap_enabled) + if (ov->snap_enabled) PDEBUG(4, "Waiting snapshot frame"); - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { frame->bytes_read = 0; - if ((rc = ov511_new_frame(ov511, frmx))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx))) { + err("read: ov51x_new_frame error"); goto error; } goto restart; } /* Clear the snapshot */ - if (ov511->snap_enabled && frame->snapshot) { + if (ov->snap_enabled && frame->snapshot) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, frame->bytes_read, @@ -5538,48 +5469,48 @@ // FIXME: Only supports two frames /* Mark it as available to be used again. */ - ov511->frame[frmx].grabstate = FRAME_UNUSED; - if ((rc = ov511_new_frame(ov511, !frmx))) { - err("ov511_new_frame returned error"); + ov->frame[frmx].grabstate = FRAME_UNUSED; + if ((rc = ov51x_new_frame(ov, !frmx))) { + err("ov51x_new_frame returned error"); goto error; } } PDEBUG(4, "read finished, returning %ld (sweet)", count); - up(&ov511->lock); + up(&ov->lock); return count; error: - up(&ov511->lock); + up(&ov->lock); return rc; } static int -ov511_mmap(struct video_device *vdev, const char *adr, unsigned long size) +ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; unsigned long start = (unsigned long)adr; unsigned long page, pos; - if (ov511->dev == NULL) + if (ov->dev == NULL) return -EIO; PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); if (size > (((OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight) + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) return -EINVAL; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - pos = (unsigned long)ov511->fbuf; + pos = (unsigned long)ov->fbuf; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&ov511->lock); + up(&ov->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -5590,43 +5521,42 @@ size = 0; } - up(&ov511->lock); + up(&ov->lock); return 0; } -static struct video_device ov511_template = { +static struct video_device vdev_template = { owner: THIS_MODULE, name: "OV511 USB Camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_OV511, - open: ov511_open, - close: ov511_close, - read: ov511_read, - write: ov511_write, - ioctl: ov511_ioctl, - mmap: ov511_mmap, - initialize: ov511_init_done, + open: ov51x_v4l1_open, + close: ov51x_v4l1_close, + read: ov51x_v4l1_read, + write: ov51x_v4l1_write, + ioctl: ov51x_v4l1_ioctl, + mmap: ov51x_v4l1_mmap, + initialize: ov51x_v4l1_init_done, }; #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) static int -ov511_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ularg) { - struct proc_dir_entry *pde; - struct usb_ov511 *ov511; + struct proc_dir_entry *pde = inode->u.generic_ip; + struct usb_ov511 *ov; void *arg = (void *) ularg; int rc; - pde = (struct proc_dir_entry *) inode->u.generic_ip; if (!pde) return -ENOENT; - ov511 = (struct usb_ov511 *) pde->data; - if (!ov511) + ov = pde->data; + if (!ov) return -ENODEV; - if (!ov511->dev) + if (!ov->dev) return -EIO; /* Should we pass through standard V4L IOCTLs? */ @@ -5651,19 +5581,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_get_brightness(ov511, &(opt.val)); + rc = sensor_get_brightness(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_get_saturation(ov511, &(opt.val)); + rc = sensor_get_saturation(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_get_hue(ov511, &(opt.val)); + rc = sensor_get_hue(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_get_contrast(ov511, &(opt.val)); + rc = sensor_get_contrast(ov, &(opt.val)); if (rc) return rc; break; default: @@ -5685,19 +5615,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_set_brightness(ov511, opt.val); + rc = sensor_set_brightness(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_set_saturation(ov511, opt.val); + rc = sensor_set_saturation(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_set_hue(ov511, opt.val); + rc = sensor_set_hue(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_set_contrast(ov511, opt.val); + rc = sensor_set_contrast(ov, opt.val); if (rc) return rc; break; default: @@ -5716,19 +5646,19 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - opt.val = ov511->lightfreq; + opt.val = ov->lightfreq; break; case OV511_UIOPT_BFILTER: - opt.val = ov511->bandfilt; + opt.val = ov->bandfilt; break; case OV511_UIOPT_LED: - opt.val = ov511->led_policy; + opt.val = ov->led_policy; break; case OV511_UIOPT_DEBUG: opt.val = debug; break; case OV511_UIOPT_COMPRESS: - opt.val = ov511->compress; + opt.val = ov->compress; break; default: err("Invalid get int option number"); @@ -5749,20 +5679,20 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - rc = sensor_set_light_freq(ov511, opt.val); + rc = sensor_set_light_freq(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_BFILTER: - rc = sensor_set_banding_filter(ov511, opt.val); + rc = sensor_set_banding_filter(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_LED: if (opt.val <= 2) { - ov511->led_policy = opt.val; - if (ov511->led_policy == LED_OFF) - ov51x_led_control(ov511, 0); - else if (ov511->led_policy == LED_ON) - ov51x_led_control(ov511, 1); + ov->led_policy = opt.val; + if (ov->led_policy == LED_OFF) + ov51x_led_control(ov, 0); + else if (ov->led_policy == LED_ON) + ov51x_led_control(ov, 1); } else { return -EINVAL; } @@ -5774,14 +5704,12 @@ return -EINVAL; break; case OV511_UIOPT_COMPRESS: - ov511->compress = opt.val; - if (ov511->compress) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - ov511_init_compression(ov511); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov518_init_compression(ov511); + ov->compress = opt.val; + if (ov->compress) { + if (ov->bclass == BCL_OV511) + ov511_init_compression(ov); + else if (ov->bclass == BCL_OV518) + ov518_init_compression(ov); } break; default: @@ -5798,7 +5726,7 @@ if (copy_from_user(&w, arg, sizeof(w))) return -EFAULT; - return ov51x_i2c_write_slave(ov511, w.slave, w.reg, w.value, + return i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask); } case OV511IOC_RI2C: @@ -5808,7 +5736,7 @@ if (copy_from_user(&r, arg, sizeof(r))) return -EFAULT; - rc = ov51x_i2c_read_slave(ov511, r.slave, r.reg); + rc = i2c_r_slave(ov, r.slave, r.reg); if (rc < 0) return rc; @@ -5837,7 +5765,7 @@ * the same register settings as the OV7610, since they are very similar. */ static int -ov7xx0_configure(struct usb_ov511 *ov511) +ov7xx0_configure(struct usb_ov511 *ov) { int i, success; int rc; @@ -5954,16 +5882,15 @@ PDEBUG(4, "starting configuration"); /* This looks redundant, but is necessary for WebCam 3 */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) return -1; - if (ov51x_init_ov_sensor(ov511) >= 0) { + if (init_ov_sensor(ov) >= 0) { PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); } else { /* Reset the 76xx */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -1; + if (i2c_w(ov, 0x12, 0x80) < 0) return -1; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); @@ -5971,10 +5898,8 @@ i = 0; success = 0; while (i <= i2c_detect_tries) { - if ((ov51x_i2c_read(ov511, - OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, - OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; break; } else { @@ -5998,17 +5923,17 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 3) { info("Sensor is an OV7610"); - ov511->sensor = SEN_OV7610; + ov->sensor = SEN_OV7610; } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet */ - if (ov51x_i2c_read(ov511, 0x15) & 1) + if (i2c_r(ov, 0x15) & 1) info("Sensor is an OV7620AE"); else info("Sensor is an OV76BE"); @@ -6016,48 +5941,48 @@ /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ - if (ov511->bridge == BRG_OV511PLUS) { + if (ov->bridge == BRG_OV511PLUS) { info("Enabling 511+/7620AE workaround"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { - ov511->sensor = SEN_OV7620AE; + ov->sensor = SEN_OV7620AE; } } else if ((rc & 3) == 0) { info("Sensor is an OV7620"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { err("Unknown image sensor version: %d", rc & 3); return -1; } - if (ov511->sensor == SEN_OV7620) { + if (ov->sensor == SEN_OV7620) { PDEBUG(4, "Writing 7620 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7620)) + if (write_regvals(ov, aRegvalsNorm7620)) return -1; } else { PDEBUG(4, "Writing 7610 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7610)) + if (write_regvals(ov, aRegvalsNorm7610)) return -1; } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; return 0; } /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ static int -ov6xx0_configure(struct usb_ov511 *ov511) +ov6xx0_configure(struct usb_ov511 *ov) { int rc; @@ -6183,7 +6108,7 @@ PDEBUG(4, "starting sensor configuration"); - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Failed to read sensor ID. You might not have an OV6xx0,"); err("or it may be not responding. Report this to " EMAIL); return -1; @@ -6192,50 +6117,44 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 0) { info("Sensor is an OV6630"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 1) { info("Sensor is an OV6620"); - ov511->sensor = SEN_OV6620; + ov->sensor = SEN_OV6620; } else if ((rc & 3) == 2) { info("Sensor is an OV6630AE"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 3) { info("Sensor is an OV6630AF"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } /* Set sensor-specific vars */ - if (ov511->sensor == SEN_OV6620) { - ov511->maxwidth = 352; - ov511->maxheight = 288; - } else { - /* 352x288 not working with OV518 yet */ - ov511->maxwidth = 320; - ov511->maxheight = 240; - } - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 352; + ov->maxheight = 288; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; - if (ov511->sensor == SEN_OV6620) { + if (ov->sensor == SEN_OV6620) { PDEBUG(4, "Writing 6x20 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x20)) + if (write_regvals(ov, aRegvalsNorm6x20)) return -1; } else { PDEBUG(4, "Writing 6x30 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x30)) + if (write_regvals(ov, aRegvalsNorm6x30)) return -1; } @@ -6244,13 +6163,13 @@ /* This initializes the KS0127 and KS0127B video decoders. */ static int -ks0127_configure(struct usb_ov511 *ov511) +ks0127_configure(struct usb_ov511 *ov) { int rc; // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_ks_sensor(ov511) < 0) { + if (ov51x_init_ks_sensor(ov) < 0) { err("Failed to initialize the KS0127"); return -1; } else { @@ -6259,21 +6178,21 @@ #endif /* Detect decoder subtype */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov, 0x00); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if (rc & 0x08) { - rc = ov51x_i2c_read(ov511, 0x3d); + rc = i2c_r(ov, 0x3d); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 0x0f) == 0) { info("Sensor is a KS0127"); - ov511->sensor = SEN_KS0127; + ov->sensor = SEN_KS0127; } else if ((rc & 0x0f) == 9) { info("Sensor is a KS0127B Rev. A"); - ov511->sensor = SEN_KS0127B; + ov->sensor = SEN_KS0127B; } } else { err("Error: Sensor is an unsupported KS0122"); @@ -6281,16 +6200,16 @@ } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; /* This device is not supported yet. Bail out now... */ err("This sensor is not supported yet."); @@ -6303,7 +6222,6 @@ static int saa7111a_configure(struct usb_ov511 *ov511) { - struct usb_device *dev = ov511->dev; int rc; /* Since there is no register reset command, all registers must be @@ -6338,7 +6256,7 @@ // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_saa_sensor(ov511) < 0) { + if (ov51x_init_saa_sensor(ov) < 0) { err("Failed to initialize the SAA7111A"); return -1; } else { @@ -6365,12 +6283,12 @@ ov511->hue = 32768; PDEBUG(4, "Writing SAA7111A registers"); - if (ov511_write_regvals(ov511, aRegvalsNormSAA7111A)) + if (write_regvals(ov511, aRegvalsNormSAA7111A)) return -1; /* Detect version of decoder. This must be done after writing the * initial regs or the decoder will lock up. */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov511, 0x00); if (rc < 0) { err("Error detecting sensor version"); @@ -6383,8 +6301,8 @@ // FIXME: Fix this for OV518(+) /* Latch to negative edge of clock. Otherwise, we get incorrect * colors and jitter in the digital signal. */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(dev, 0x11, 0x00); + if (ov511->bclass == BCL_OV511) + reg_w(ov511, 0x11, 0x00); else warn("SAA7111A not yet supported with OV518/OV518+"); @@ -6393,144 +6311,138 @@ /* This initializes the OV511/OV511+ and the sensor */ static int -ov511_configure(struct usb_ov511 *ov511) +ov511_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int i; static struct ov511_regvals aRegvalsInit511[] = { - { 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_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, { OV511_DONE_BUS, 0x0, 0x00}, }; static struct ov511_regvals aRegvalsNorm511[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; static struct ov511_regvals aRegvalsNorm511Plus[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0xff }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0xff }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); - ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); - if (ov511->customid < 0) { + ov->customid = reg_r(ov, R511_SYS_CUST_ID); + if (ov->customid < 0) { err("Unable to read camera bridge registers"); goto error; } - ov511->desc = -1; - PDEBUG (1, "CustomID = %d", ov511->customid); + ov->desc = -1; + PDEBUG (1, "CustomID = %d", ov->customid); for (i = 0; clist[i].id >= 0; i++) { - if (ov511->customid == clist[i].id) { + if (ov->customid == clist[i].id) { info("model: %s", clist[i].description); - ov511->desc = i; + ov->desc = i; break; } } if (clist[i].id == -1) { - err("Camera type (%d) not recognized", ov511->customid); + err("Camera type (%d) not recognized", ov->customid); err("Please notify " EMAIL " of the name,"); err("manufacturer, model, and this number of your camera."); err("Also include the output of the detection process."); } if (clist[i].id == 6) { /* USB Life TV (NTSC) */ - ov511->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ + ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ } - if (ov511_write_regvals(ov511, aRegvalsInit511)) goto error; + if (write_regvals(ov, aRegvalsInit511)) goto error; - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); /* The OV511+ has undocumented bits in the flow control register. * Setting it to 0xff fixes the corruption with moving objects. */ - if (ov511->bridge == BRG_OV511) { - if (ov511_write_regvals(ov511, aRegvalsNorm511)) goto error; - } else if (ov511->bridge == BRG_OV511PLUS) { - if (ov511_write_regvals(ov511, aRegvalsNorm511Plus)) goto error; + if (ov->bridge == BRG_OV511) { + if (write_regvals(ov, aRegvalsNorm511)) goto error; + } else if (ov->bridge == BRG_OV511PLUS) { + if (write_regvals(ov, aRegvalsNorm511Plus)) goto error; } else { err("Invalid bridge"); } - if (ov511_init_compression(ov511)) goto error; + if (ov511_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 7xx0 */ PDEBUG(3, "Testing for 0V7xx0"); - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 6xx0 */ PDEBUG(3, "Testing for 0V6xx0"); - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 8xx0 */ PDEBUG(3, "Testing for 0V8xx0"); - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID)) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for SAA7111A */ PDEBUG(3, "Testing for SAA7111A"); - ov511->primary_i2c_slave = SAA7111A_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, SAA7111A_I2C_WRITE_ID, - SAA7111A_I2C_READ_ID)) + ov->primary_i2c_slave = SAA7111A_SID; + if (ov51x_set_slave_ids(ov, SAA7111A_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x0d, 0x00) < 0) { + if (i2c_w(ov, 0x0d, 0x00) < 0) { /* Test for KS0127 */ PDEBUG(3, "Testing for KS0127"); - ov511->primary_i2c_slave = KS0127_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, KS0127_I2C_WRITE_ID, - KS0127_I2C_READ_ID)) + ov->primary_i2c_slave = KS0127_SID; + if (ov51x_set_slave_ids(ov, KS0127_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x10, 0x00) < 0) { + if (i2c_w(ov, 0x10, 0x00) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { - if(ks0127_configure(ov511) < 0) { + if (ks0127_configure(ov) < 0) { err("Failed to configure KS0127"); goto error; } } } else { - if(saa7111a_configure(ov511) < 0) { + if (saa7111a_configure(ov) < 0) { err("Failed to configure SAA7111A"); goto error; } @@ -6540,13 +6452,13 @@ goto error; } } else { - if(ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if(ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } @@ -6562,96 +6474,90 @@ /* This initializes the OV518/OV518+ and the sensor */ static int -ov518_configure(struct usb_ov511 *ov511) +ov518_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; - static struct ov511_regvals aRegvalsInit518[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x40 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3e }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x00 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, 0x46, 0x00 }, - { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00}, }; /* New values, based on Windows driver. Since what they do is not * known yet, this may be incorrect. */ static struct ov511_regvals aRegvalsNorm518[] = { - { OV511_REG_BUS, 0x52, 0x02 }, /* Reset snapshot */ - { OV511_REG_BUS, 0x52, 0x01 }, /* Enable snapshot */ - { OV511_REG_BUS, 0x31, 0x0f }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_REG_BUS, 0x24, 0x9f }, - { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ - { OV511_REG_BUS, 0x51, 0x04 }, - { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); /* First 5 bits of custom ID reg are a revision ID on OV518 */ - info("Device revision %d", - 0x1F & ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID)); + info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); - if (ov511_write_regvals(ov511, aRegvalsInit518)) goto error; + if (write_regvals(ov, aRegvalsInit518)) goto error; /* Set LED GPIO pin to output mode */ - if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error; + if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error; /* LED is off by default with OV518; have to explicitly turn it on */ - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); else - ov51x_led_control(ov511, 1); + ov51x_led_control(ov, 1); /* Don't require compression if dumppix is enabled; otherwise it's * required. OV518 has no uncompressed mode, to save RAM. */ - if (!dumppix && !ov511->compress) { - ov511->compress = 1; + if (!dumppix && !ov->compress) { + ov->compress = 1; warn("Compression required with OV518...enabling"); } - if (ov511_write_regvals(ov511, aRegvalsNorm518)) goto error; + if (write_regvals(ov, aRegvalsNorm518)) goto error; - if (ov511_reg_write(dev, 0x2f,0x80) < 0) goto error; + if (reg_w(ov, 0x2f, 0x80) < 0) goto error; - if (ov518_init_compression(ov511)) goto error; + if (ov518_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 76xx */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; /* The OV518 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 6xx0 */ - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 8xx0 */ - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { @@ -6659,21 +6565,25 @@ goto error; } } else { - if (ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if (ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } } + // FIXME: Sizes > 320x240 are not working yet + ov->maxwidth = 320; + ov->maxheight = 240; + // The OV518 cannot go as low as the sensor can - ov511->minwidth = 160; - ov511->minheight = 120; + ov->minwidth = 160; + ov->minheight = 120; return 0; @@ -6695,7 +6605,7 @@ const struct usb_device_id *id) { struct usb_interface_descriptor *interface; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; int i; int registered = 0; @@ -6716,54 +6626,54 @@ /* Since code below may sleep, we use this as a lock */ MOD_INC_USE_COUNT; - if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { - err("couldn't kmalloc ov511 struct"); - goto error_unlock; - } - - memset(ov511, 0, sizeof(*ov511)); - - ov511->dev = dev; - ov511->iface = interface->bInterfaceNumber; - ov511->led_policy = led; - ov511->compress = compress; - ov511->lightfreq = lightfreq; - ov511->num_inputs = 1; /* Video decoder init functs. change this */ - ov511->stop_during_set = !fastset; - ov511->tuner_type = tuner; - ov511->backlight = backlight; - - ov511->auto_brt = autobright; - ov511->auto_gain = autogain; - ov511->auto_exp = autoexp; + if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc ov struct"); + goto error_out; + } + + memset(ov, 0, sizeof(*ov)); + + ov->dev = dev; + ov->iface = interface->bInterfaceNumber; + ov->led_policy = led; + ov->compress = compress; + ov->lightfreq = lightfreq; + ov->num_inputs = 1; /* Video decoder init functs. change this */ + ov->stop_during_set = !fastset; + ov->tuner_type = tuner; + ov->backlight = backlight; + + ov->auto_brt = autobright; + ov->auto_gain = autogain; + ov->auto_exp = autoexp; switch (dev->descriptor.idProduct) { case PROD_OV511: info("USB OV511 camera found"); - ov511->bridge = BRG_OV511; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511; + ov->bclass = BCL_OV511; break; case PROD_OV511PLUS: info("USB OV511+ camera found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; case PROD_OV518: info("USB OV518 camera found"); - ov511->bridge = BRG_OV518; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518; + ov->bclass = BCL_OV518; break; case PROD_OV518PLUS: info("USB OV518+ camera found"); - ov511->bridge = BRG_OV518PLUS; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518PLUS; + ov->bclass = BCL_OV518; break; case PROD_ME2CAM: if (dev->descriptor.idVendor != VEND_MATTEL) goto error; info("Intel Play Me2Cam (OV511+) found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; default: err("Unknown product ID 0x%x", dev->descriptor.idProduct); @@ -6775,47 +6685,53 @@ if (force_rgb) info("data format set to RGB"); - init_waitqueue_head(&ov511->wq); + init_waitqueue_head(&ov->wq); - init_MUTEX(&ov511->lock); /* to 1 == available */ - init_MUTEX(&ov511->buf_lock); - init_MUTEX(&ov511->param_lock); - init_MUTEX(&ov511->i2c_lock); - ov511->buf_state = BUF_NOT_ALLOCATED; - - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - if (ov518_configure(ov511) < 0) + init_MUTEX(&ov->lock); /* to 1 == available */ + init_MUTEX(&ov->buf_lock); + init_MUTEX(&ov->param_lock); + init_MUTEX(&ov->i2c_lock); + init_MUTEX(&ov->cbuf_lock); + + ov->buf_state = BUF_NOT_ALLOCATED; + + /* Must be kmalloc()'ed, for DMA accessibility */ + ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); + if (!ov->cbuf) + goto error; + + if (ov->bclass == BCL_OV518) { + if (ov518_configure(ov) < 0) goto error; } else { - if (ov511_configure(ov511) < 0) + if (ov511_configure(ov) < 0) goto error; } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].framenum = i; - init_waitqueue_head(&ov511->frame[i].wq); + ov->frame[i].framenum = i; + init_waitqueue_head(&ov->frame[i].wq); } /* Unnecessary? (This is done on open(). Need to make sure variables * are properly initialized without this before removing it, though). */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto error; #ifdef OV511_DEBUG if (dump_bridge) - ov511_dump_regs(dev); + ov511_dump_regs(ov); #endif - memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); - ov511->vdev.priv = ov511; + memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template)); + ov->vdev.priv = ov; for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { /* Minor 0 cannot be specified; assume user wants autodetect */ if (unit_video[i] == 0) break; - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, + if (video_register_device(&ov->vdev, VFL_TYPE_GRABBER, unit_video[i]) >= 0) { registered = 1; break; @@ -6824,34 +6740,41 @@ /* Use the next available one */ if (!registered && - video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, -1) < 0) { + video_register_device(&ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { err("video_register_device failed"); goto error; } - info("Device registered on minor %d", ov511->vdev.minor); + info("Device registered on minor %d", ov->vdev.minor); MOD_DEC_USE_COUNT; - return ov511; + return ov; error: err("Camera initialization failed"); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) /* Safe to call even if entry doesn't exist */ - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif + if (ov->cbuf) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + } + usb_driver_release_interface(&ov511_driver, - &dev->actconfig->interface[ov511->iface]); + &dev->actconfig->interface[ov->iface]); error_dealloc: - if (ov511) { - kfree(ov511); - ov511 = NULL; + if (ov) { + kfree(ov); + ov = NULL; } -error_unlock: +error_out: MOD_DEC_USE_COUNT; return NULL; } @@ -6860,7 +6783,7 @@ static void ov51x_disconnect(struct usb_device *dev, void *ptr) { - struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; + struct usb_ov511 *ov = (struct usb_ov511 *) ptr; int n; MOD_INC_USE_COUNT; @@ -6868,48 +6791,53 @@ PDEBUG(3, ""); /* We don't want people trying to open up the device */ - if (!ov511->user) - video_unregister_device(&ov511->vdev); + if (!ov->user) + video_unregister_device(&ov->vdev); else PDEBUG(3, "Device open...deferring video_unregister_device"); for (n = 0; n < OV511_NUMFRAMES; n++) - ov511->frame[n].grabstate = FRAME_ERROR; + ov->frame[n].grabstate = FRAME_ERROR; - ov511->curframe = -1; + ov->curframe = -1; /* This will cause the process to request another frame */ for (n = 0; n < OV511_NUMFRAMES; n++) - if (waitqueue_active(&ov511->frame[n].wq)) - wake_up_interruptible(&ov511->frame[n].wq); - if (waitqueue_active(&ov511->wq)) - wake_up_interruptible(&ov511->wq); + if (waitqueue_active(&ov->frame[n].wq)) + wake_up_interruptible(&ov->frame[n].wq); + if (waitqueue_active(&ov->wq)) + wake_up_interruptible(&ov->wq); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif usb_driver_release_interface(&ov511_driver, - &ov511->dev->actconfig->interface[ov511->iface]); - ov511->dev = NULL; + &ov->dev->actconfig->interface[ov->iface]); + ov->dev = NULL; /* Free the memory */ - if (ov511 && !ov511->user) { - ov511_dealloc(ov511, 1); - kfree(ov511); - ov511 = NULL; + if (ov && !ov->user) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + kfree(ov); + ov = NULL; } MOD_DEC_USE_COUNT; diff -urN linux-2.4.18/drivers/usb/ov511.h linux-2.4.19-pre5/drivers/usb/ov511.h --- linux-2.4.18/drivers/usb/ov511.h Sat Mar 16 21:16:33 2002 +++ linux-2.4.19-pre5/drivers/usb/ov511.h Sat Mar 30 22:55:35 2002 @@ -9,11 +9,11 @@ #define OV511_DEBUG /* Turn on debug messages */ #ifdef OV511_DEBUG -# define PDEBUG(level, fmt, args...) \ -if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \ - ## args) + #define PDEBUG(level, fmt, args...) \ + if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\ + __LINE__ , ## args) #else -# define PDEBUG(level, fmt, args...) do {} while(0) + #define PDEBUG(level, fmt, args...) do {} while(0) #endif /* This macro restricts an int variable to an inclusive range */ @@ -36,98 +36,105 @@ #define VEND_MATTEL 0x0813 #define PROD_ME2CAM 0x0002 +/* --------------------------------- */ +/* OV51x REGISTER MNEMONICS */ +/* --------------------------------- */ + /* Camera interface register numbers */ -#define OV511_REG_CAMERA_DELAY_MODE 0x10 -#define OV511_REG_CAMERA_EDGE_MODE 0x11 -#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12 -#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13 -#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14 -#define OV511_REG_CAMERA_LINE_DIVISOR 0x15 -#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16 -#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17 -#define OV511_REG_CAMERA_BITMASK 0x18 +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 /* Snapshot mode camera interface register numbers */ -#define OV511_REG_SNAP_CAPTURED_FRAME 0x19 -#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A -#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B -#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C -#define OV511_REG_SNAP_LINE_DIVISOR 0x1D -#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E -#define OV511_REG_SNAP_BITMASK 0x1F +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1A +#define R511_SNAP_LNCNT 0x1B +#define R511_SNAP_PXDIV 0x1C +#define R511_SNAP_LNDIV 0x1D +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_OPTS 0x1F /* DRAM register numbers */ -#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20 -#define OV511_REG_DRAM_READ_CYCLE_PREDICT 0x21 -#define OV511_REG_DRAM_MANUAL_READ_CYCLE 0x22 -#define OV511_REG_DRAM_REFRESH_COUNTER 0x23 +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_DRAM_ARCP 0x21 +#define R511_DRAM_MRC 0x22 +#define R511_DRAM_RFC 0x23 /* ISO FIFO register numbers */ -#define OV511_REG_FIFO_PACKET_SIZE 0x30 -#define OV511_REG_FIFO_BITMASK 0x31 +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R511_FIFO_OPTS 0x31 -/* PIO register numbers */ -#define OV511_REG_PIO_BITMASK 0x38 -#define OV511_REG_PIO_DATA_PORT 0x39 -#define OV511_REG_PIO_BIST 0x3E - -/* I2C register numbers */ -#define OV511_REG_I2C_CONTROL 0x40 -#define OV518_REG_I2C_CONTROL 0x47 /* OV518(+) only */ -#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 -#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 -#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 -#define OV511_REG_I2C_SLAVE_ID_READ 0x44 -#define OV511_REG_I2C_DATA_PORT 0x45 -#define OV511_REG_I2C_CLOCK_PRESCALER 0x46 -#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47 - -/* I2C snapshot register numbers */ -#define OV511_REG_I2C_SNAP_SUB_ADDRESS 0x48 -#define OV511_REG_I2C_SNAP_DATA_PORT 0x49 - -/* System control register numbers */ -#define OV511_REG_SYSTEM_RESET 0x50 -#define OV511_RESET_UDC 0x01 -#define OV511_RESET_I2C 0x02 -#define OV511_RESET_FIFO 0x04 -#define OV511_RESET_OMNICE 0x08 -#define OV511_RESET_DRAM_INTF 0x10 -#define OV511_RESET_CAMERA_INTF 0x20 -#define OV511_RESET_OV511 0x40 -#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ -#define OV511_RESET_ALL 0x7F -#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 -#define OV511_REG_SYSTEM_SNAPSHOT 0x52 -#define OV511_REG_SYSTEM_INIT 0x53 -#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+/OV518(+) only */ -#define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */ -#define OV518_REG_GPIO_IN 0x55 /* OV518(+) only */ -#define OV518_REG_GPIO_OUT 0x56 /* OV518(+) only */ -#define OV518_REG_GPIO_CTL 0x57 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_IN 0x58 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_POLARITY 0x5a /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_EN 0x5b /* OV518(+) only */ -#define OV518_REG_GPIO_RESET 0x5c /* OV518(+) only */ -#define OV511_REG_SYSTEM_USER_DEFINED 0x5E -#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F - -/* OmniCE register numbers */ -#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70 -#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71 -#define OV511_OMNICE_PREDICTION_VERT_Y 0x72 -#define OV511_OMNICE_PREDICTION_VERT_UV 0x73 -#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74 -#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75 -#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76 -#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77 -#define OV511_OMNICE_ENABLE 0x78 -#define OV511_OMNICE_LUT_ENABLE 0x79 -#define OV511_OMNICE_Y_LUT_BEGIN 0x80 -#define OV511_OMNICE_Y_LUT_END 0x9F -#define OV511_OMNICE_UV_LUT_BEGIN 0xA0 -#define OV511_OMNICE_UV_LUT_END 0xBF +/* Parallel IO register numbers */ +#define R511_PIO_OPTS 0x38 +#define R511_PIO_DATA 0x39 +#define R511_PIO_BIST 0x3E +#define R518_GPIO_IN 0x55 /* OV518(+) only */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ +#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ +#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ +#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ +#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ +#define R518_GPIO_RESET 0x5c /* OV518(+) only */ + +/* I2C registers */ +#define R511_I2C_CTL 0x40 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R51x_I2C_CLOCK 0x46 +#define R51x_I2C_TIMEOUT 0x47 + +/* I2C snapshot registers */ +#define R511_SI2C_SADDR_3 0x48 +#define R511_SI2C_DATA 0x49 + +/* System control registers */ +#define R51x_SYS_RESET 0x50 + /* Reset type definitions */ +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2C 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM 0x10 +#define OV511_RESET_CAM_INT 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F + +#define R511_SYS_CLOCK_DIV 0x51 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_INIT 0x53 +#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_SYS_USER 0x5E +#define R511_SYS_CUST_ID 0x5F + +/* OmniCE (compression) registers */ +#define R511_COMP_PHY 0x70 +#define R511_COMP_PHUV 0x71 +#define R511_COMP_PVY 0x72 +#define R511_COMP_PVUV 0x73 +#define R511_COMP_QHY 0x74 +#define R511_COMP_QHUV 0x75 +#define R511_COMP_QVY 0x76 +#define R511_COMP_QVUV 0x77 +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 +#define R511_COMP_LUT_BEGIN 0x80 + +/* --------------------------------- */ +/* ALTERNATE NUMBERS */ +/* --------------------------------- */ /* Alternate numbers for various max packet sizes (OV511 only) */ #define OV511_ALT_SIZE_992 0 @@ -159,6 +166,10 @@ #define OV518_ALT_SIZE_768 6 #define OV518_ALT_SIZE_896 7 +/* --------------------------------- */ +/* OV7610 REGISTER MNEMONICS */ +/* --------------------------------- */ + /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ #define OV7610_REG_BLUE 0x01 /* blue channel balance */ @@ -210,26 +221,27 @@ /* 36-37 reserved */ #define OV7610_REG_COM_K 0x38 /* misc registers */ +/* --------------------------------- */ +/* I2C ADDRESSES */ +/* --------------------------------- */ + +#define OV7xx0_SID 0x42 +#define OV6xx0_SID 0xC0 +#define OV8xx0_SID 0xA0 +#define KS0127_SID 0xD8 +#define SAA7111A_SID 0x48 + +/* --------------------------------- */ +/* MISCELLANEOUS DEFINES */ +/* --------------------------------- */ + +#define I2C_CLOCK_PRESCALER 0x03 + #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ -#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */ #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ #define PIXELS_PER_SEG 256 /* Pixels per segment */ -#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ - -/* I2C addresses */ -#define OV7xx0_I2C_WRITE_ID 0x42 -#define OV7xx0_I2C_READ_ID 0x43 -#define OV6xx0_I2C_WRITE_ID 0xC0 -#define OV6xx0_I2C_READ_ID 0xC1 -#define OV8xx0_I2C_WRITE_ID 0xA0 -#define OV8xx0_I2C_READ_ID 0xA1 -#define KS0127_I2C_WRITE_ID 0xD8 -#define KS0127_I2C_READ_ID 0xD9 -#define SAA7111A_I2C_WRITE_ID 0x48 -#define SAA7111A_I2C_READ_ID 0x49 - -#define OV511_I2C_CLOCK_PRESCALER 0x03 +#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ /* Bridge types */ enum { @@ -366,7 +378,7 @@ struct ov511_sbuf { char *data; - urb_t *urb; + struct urb *urb; }; enum { @@ -429,11 +441,14 @@ #define OV511_NUMFRAMES 2 #if OV511_NUMFRAMES > VIDEO_MAX_FRAME -#error "OV511_NUMFRAMES is too high" + #error "OV511_NUMFRAMES is too high" #endif #define OV511_NUMSBUF 2 +/* Control transfers use up to 4 bytes */ +#define OV511_CBUF_SIZE 4 + struct usb_ov511 { struct video_device vdev; @@ -535,6 +550,10 @@ /* I2C interface to kernel */ struct semaphore i2c_lock; /* Protect I2C controller regs */ unsigned char primary_i2c_slave; /* I2C write id of sensor */ + + /* Control transaction stuff */ + unsigned char *cbuf; /* Buffer for payload */ + struct semaphore cbuf_lock; }; struct cam_list { diff -urN linux-2.4.18/drivers/usb/pegasus.c linux-2.4.19-pre5/drivers/usb/pegasus.c --- linux-2.4.18/drivers/usb/pegasus.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/pegasus.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* ** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller ** -** Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com) +** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net) ** ** ** ChangeLog: @@ -21,6 +21,7 @@ ** TODO: suppressing HCD warnings spewage on disconnect. ** v0.4.13 Ethernet address is now set at probe(), not at open() ** time as this seems to break dhcpd. +** v0.4.25 ethtool support added. */ /* @@ -46,23 +47,29 @@ #include #include #include +#include +#include #include #include +#include #include "pegasus.h" /* * Version Information */ -#define DRIVER_VERSION "v0.4.22 (2001/12/07)" -#define DRIVER_AUTHOR "Petko Manolov " +#define DRIVER_VERSION "v0.4.26 (2002/03/21)" +#define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define PEGASUS_USE_INTR #define PEGASUS_WRITE_EEPROM +#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ + BMSR_100FULL | BMSR_ANEGCAPABLE) static int loopback = 0; -static int mii_mode = 0; +static int mii_mode = 1; static int multicast_filter_limit = 32; +static DECLARE_MUTEX(gsem); static struct usb_eth_dev usb_dev_id[] = { #define PEGASUS_DEV(pn, vid, pid, flags) \ @@ -94,7 +101,7 @@ static int update_eth_regs_async( pegasus_t * ); /* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback( urb_t *urb ) +static void ctrl_callback( struct urb *urb ) { pegasus_t *pegasus = urb->context; @@ -102,7 +109,7 @@ return; switch ( urb->status ) { - case USB_ST_NOERROR: + case 0: if ( pegasus->flags & ETH_REGS_CHANGE ) { pegasus->flags &= ~ETH_REGS_CHANGE; pegasus->flags |= ETH_REGS_CHANGED; @@ -110,12 +117,12 @@ return; } break; - case USB_ST_URB_PENDING: + case -EINPROGRESS: return; - case USB_ST_URB_KILLED: + case -ENOENT: break; default: - warn( __FUNCTION__ " status %d", urb->status); + warn("%s: status %d", __FUNCTION__, urb->status); } pegasus->flags &= ~ETH_REGS_CHANGED; wake_up(&pegasus->ctrl_wait ); @@ -147,9 +154,9 @@ pegasus->dr.value = cpu_to_le16 (0); pegasus->dr.index = cpu_to_le16p(&indx); pegasus->dr.length = cpu_to_le16p(&size); - pegasus->ctrl_urb.transfer_buffer_length = size; + pegasus->ctrl_urb->transfer_buffer_length = size; - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb, usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, buffer, size, ctrl_callback, pegasus ); @@ -157,8 +164,8 @@ add_wait_queue( &pegasus->ctrl_wait, &wait ); set_current_state( TASK_UNINTERRUPTIBLE ); - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { - err( __FUNCTION__ " BAD CTRLs %d", ret); + if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) { + err("%s: BAD CTRLs %d", __FUNCTION__, ret); goto out; } @@ -197,9 +204,9 @@ pegasus->dr.value = cpu_to_le16 (0); pegasus->dr.index = cpu_to_le16p( &indx ); pegasus->dr.length = cpu_to_le16p( &size ); - pegasus->ctrl_urb.transfer_buffer_length = size; + pegasus->ctrl_urb->transfer_buffer_length = size; - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, buffer, size, ctrl_callback, pegasus ); @@ -207,8 +214,8 @@ add_wait_queue( &pegasus->ctrl_wait, &wait ); set_current_state( TASK_UNINTERRUPTIBLE ); - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { - err( __FUNCTION__ " BAD CTRL %d", ret); + if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) { + err("%s: BAD CTRL %d", __FUNCTION__, ret); goto out; } @@ -247,9 +254,9 @@ pegasus->dr.value = cpu_to_le16p( &dat); pegasus->dr.index = cpu_to_le16p( &indx ); pegasus->dr.length = cpu_to_le16( 1 ); - pegasus->ctrl_urb.transfer_buffer_length = 1; + pegasus->ctrl_urb->transfer_buffer_length = 1; - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, buffer, 1, ctrl_callback, pegasus ); @@ -257,8 +264,8 @@ add_wait_queue( &pegasus->ctrl_wait, &wait ); set_current_state( TASK_UNINTERRUPTIBLE ); - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { - err( __FUNCTION__ " BAD CTRL %d", ret); + if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) { + err("%s: BAD CTRL %d", __FUNCTION__, ret); goto out; } @@ -280,15 +287,15 @@ pegasus->dr.value = 0; pegasus->dr.index = cpu_to_le16(EthCtrl0); pegasus->dr.length = cpu_to_le16(3); - pegasus->ctrl_urb.transfer_buffer_length = 3; + pegasus->ctrl_urb->transfer_buffer_length = 3; - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, pegasus->eth_regs, 3, ctrl_callback, pegasus ); - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags ); + if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) + err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags); return ret; } @@ -313,7 +320,7 @@ *regd = le16_to_cpu(regdi); return 0; } - warn( __FUNCTION__ " failed" ); + warn("%s: failed", __FUNCTION__); return 1; } @@ -335,7 +342,7 @@ } if ( i < REG_TIMEOUT ) return 0; - warn( __FUNCTION__ " failed" ); + warn("%s: failed", __FUNCTION__); return 1; } @@ -361,7 +368,7 @@ *retdata = le16_to_cpu (retdatai); return 0; } - warn( __FUNCTION__ " failed" ); + warn("%s: failed", __FUNCTION__); return -1; } @@ -405,7 +412,7 @@ disable_eprom_write( pegasus ); if ( i < REG_TIMEOUT ) return 0; - warn( __FUNCTION__ " failed" ); + warn("%s: failed", __FUNCTION__); return -1; } #endif /* PEGASUS_WRITE_EEPROM */ @@ -455,14 +462,18 @@ if ( i == REG_TIMEOUT ) return 1; - if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || - usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) { + if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || + usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { __u16 auxmode; - read_mii_word( pegasus, 0, 0x1b, &auxmode ); - write_mii_word( pegasus, 0, 0x1b, auxmode | 4 ); + read_mii_word(pegasus, 1, 0x1b, &auxmode); + write_mii_word(pegasus, 1, 0x1b, auxmode | 4); + } + if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { + __u16 auxmode; + read_mii_word(pegasus, 3, 0x1b, &auxmode); + write_mii_word(pegasus, 3, 0x1b, auxmode | 4); } - return 0; } @@ -476,19 +487,21 @@ if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) return 1; +#if 0 if ( !(bmsr & 0x20) && !loopback ) warn( "%s: link NOT established (0x%x) - check the cable.", dev->name, bmsr ); - if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) ) +#endif + if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) ) return 2; if ( !(linkpart & 1) ) warn( "link partner stat %x", linkpart ); data[0] = 0xc9; data[1] = 0; - if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) ) + if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) ) data[1] |= 0x20; /* set full duplex */ - if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) ) + if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) ) data[1] |= 0x10; /* set 100 Mbps */ if ( mii_mode ) data[1] = 0; @@ -526,9 +539,9 @@ pegasus->flags |= PEGASUS_RX_BUSY; switch ( urb->status ) { - case USB_ST_NOERROR: + case 0: break; - case USB_ST_NORESPONSE: + case -ETIMEDOUT: dbg( "reset MAC" ); pegasus->flags &= ~PEGASUS_RX_BUSY; break; @@ -569,12 +582,12 @@ pegasus->stats.rx_bytes += pkt_len; goon: - FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb, + FILL_BULK_URB( pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), pegasus->rx_buff, PEGASUS_MAX_MTU, read_bulk_callback, pegasus ); - if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) - warn( __FUNCTION__ " failed submint rx_urb %d", res); + if ( (res = usb_submit_urb(pegasus->rx_urb)) ) + warn("%s: failed submint rx_urb %d", __FUNCTION__, res); pegasus->flags &= ~PEGASUS_RX_BUSY; } @@ -607,9 +620,9 @@ return; switch ( urb->status ) { - case USB_ST_NOERROR: + case 0: break; - case USB_ST_URB_KILLED: + case -ENOENT: return; default: info("intr status %d", urb->status); @@ -639,8 +652,8 @@ return; warn("%s: Tx timed out.", net->name); - pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; - usb_unlink_urb( &pegasus->tx_urb ); + pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK; + usb_unlink_urb( pegasus->tx_urb ); pegasus->stats.tx_errors++; } @@ -656,12 +669,12 @@ ((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 ); memcpy(pegasus->tx_buff+2, skb->data, skb->len); - FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb, + FILL_BULK_URB( pegasus->tx_urb, pegasus->usb, usb_sndbulkpipe(pegasus->usb, 2), pegasus->tx_buff, PEGASUS_MAX_MTU, write_bulk_callback, pegasus ); - pegasus->tx_urb.transfer_buffer_length = count; - if ((res = usb_submit_urb(&pegasus->tx_urb))) { + pegasus->tx_urb->transfer_buffer_length = count; + if ((res = usb_submit_urb(pegasus->tx_urb))) { warn("failed tx_urb %d", res); pegasus->stats.tx_errors++; netif_start_queue( net ); @@ -708,33 +721,56 @@ } +static void set_carrier(struct net_device *net) +{ + pegasus_t *pegasus; + short tmp; + + pegasus = net->priv; + read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp); + if (tmp & BMSR_LSTATUS) + netif_carrier_on(net); + else + netif_carrier_off(net); + +} + + static int pegasus_open(struct net_device *net) { pegasus_t *pegasus = (pegasus_t *)net->priv; int res; - if ( (res = enable_net_traffic(net, pegasus->usb)) ) { - err("can't enable_net_traffic() - %d", res); - return -EIO; - } - FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb, + + down(&pegasus->sem); + FILL_BULK_URB( pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), pegasus->rx_buff, PEGASUS_MAX_MTU, read_bulk_callback, pegasus ); - if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) - warn( __FUNCTION__ " failed rx_urb %d", res ); + if ( (res = usb_submit_urb(pegasus->rx_urb)) ) + warn("%s: failed rx_urb %d", __FUNCTION__, res); #ifdef PEGASUS_USE_INTR - FILL_INT_URB( &pegasus->intr_urb, pegasus->usb, + FILL_INT_URB( pegasus->intr_urb, pegasus->usb, usb_rcvintpipe(pegasus->usb, 3), pegasus->intr_buff, sizeof(pegasus->intr_buff), intr_callback, pegasus, pegasus->intr_interval ); - if ( (res = usb_submit_urb(&pegasus->intr_urb)) ) - warn( __FUNCTION__ " failed intr_urb %d", res); + if ( (res = usb_submit_urb(pegasus->intr_urb)) ) + warn("%s: failed intr_urb %d", __FUNCTION__, res); #endif netif_start_queue( net ); pegasus->flags |= PEGASUS_RUNNING; + if ( (res = enable_net_traffic(net, pegasus->usb)) ) { + err("can't enable_net_traffic() - %d", res); + res = -EIO; + goto exit; + } - return 0; + set_carrier(net); + res = 0; +exit: + up(&pegasus->sem); + + return res; } @@ -742,41 +778,132 @@ { pegasus_t *pegasus = net->priv; + down(&pegasus->sem); pegasus->flags &= ~PEGASUS_RUNNING; netif_stop_queue( net ); if ( !(pegasus->flags & PEGASUS_UNPLUG) ) disable_net_traffic( pegasus ); - usb_unlink_urb( &pegasus->rx_urb ); - usb_unlink_urb( &pegasus->tx_urb ); - usb_unlink_urb( &pegasus->ctrl_urb ); + usb_unlink_urb( pegasus->rx_urb ); + usb_unlink_urb( pegasus->tx_urb ); + usb_unlink_urb( pegasus->ctrl_urb ); #ifdef PEGASUS_USE_INTR - usb_unlink_urb( &pegasus->intr_urb ); + usb_unlink_urb( pegasus->intr_urb ); #endif - + up(&pegasus->sem); + return 0; } +static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) +{ + pegasus_t *pegasus; + int cmd; + char tmp[128]; + + pegasus = net->priv; + if (get_user(cmd, (int *)uaddr)) + return -EFAULT; + switch (cmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); + sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum, + pegasus->usb->devnum); + strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd; + short lpa, bmcr; + + if (copy_from_user(&ecmd, uaddr, sizeof(ecmd))) + return -EFAULT; + ecmd.supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP | + SUPPORTED_MII); + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.phy_address = pegasus->phy; + read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr); + read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa); + if (bmcr & BMCR_ANENABLE) { + ecmd.autoneg = AUTONEG_ENABLE; + ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ? + SPEED_100 : SPEED_10; + if (ecmd.speed == SPEED_100) + ecmd.duplex = lpa & LPA_100FULL ? + DUPLEX_FULL : DUPLEX_HALF; + else + ecmd.duplex = lpa & LPA_10FULL ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = bmcr & BMCR_SPEED100 ? + SPEED_100 : SPEED_10; + ecmd.duplex = bmcr & BMCR_FULLDPLX ? + DUPLEX_FULL : DUPLEX_HALF; + } + if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + + return 0; + } + case ETHTOOL_SSET: { + return -EOPNOTSUPP; + } + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = netif_carrier_ok(net); + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + default: + return -EOPNOTSUPP; + } +} + + static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) { __u16 *data = (__u16 *)&rq->ifr_data; pegasus_t *pegasus = net->priv; + int res; + down(&pegasus->sem); switch(cmd) { - case SIOCDEVPRIVATE: - data[0] = pegasus->phy; - case SIOCDEVPRIVATE+1: - read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]); - return 0; - case SIOCDEVPRIVATE+2: - if ( !capable(CAP_NET_ADMIN) ) - return -EPERM; - write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; + case SIOCETHTOOL: + res = pegasus_ethtool_ioctl(net, rq->ifr_data); + break; + case SIOCDEVPRIVATE: + data[0] = pegasus->phy; + case SIOCDEVPRIVATE+1: + read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]); + res = 0; + break; + case SIOCDEVPRIVATE+2: + if ( !capable(CAP_NET_ADMIN) ) { + up(&pegasus->sem); + return -EPERM; + } + write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); + res = 0; + break; + default: + res = -EOPNOTSUPP; } + up(&pegasus->sem); + + return res; } @@ -800,7 +927,7 @@ } pegasus->flags |= ETH_REGS_CHANGE; - ctrl_callback( &pegasus->ctrl_urb ); + ctrl_callback( pegasus->ctrl_urb ); netif_wake_queue(net); } @@ -846,9 +973,10 @@ return NULL; } + down(&gsem); if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) { err("out of memory allocating device structure"); - return NULL; + goto exit; } usb_inc_dev_use( dev ); @@ -856,12 +984,48 @@ pegasus->dev_index = dev_index; init_waitqueue_head( &pegasus->ctrl_wait ); + pegasus->ctrl_urb = usb_alloc_urb(0); + if (!pegasus->ctrl_urb) { + kfree (pegasus); + pegasus = NULL; + goto exit; + } + pegasus->rx_urb = usb_alloc_urb(0); + if (!pegasus->rx_urb) { + usb_free_urb (pegasus->ctrl_urb); + kfree (pegasus); + pegasus = NULL; + goto exit; + } + pegasus->tx_urb = usb_alloc_urb(0); + if (!pegasus->tx_urb) { + usb_free_urb (pegasus->rx_urb); + usb_free_urb (pegasus->ctrl_urb); + kfree (pegasus); + pegasus = NULL; + goto exit; + } + pegasus->intr_urb = usb_alloc_urb(0); + if (!pegasus->intr_urb) { + usb_free_urb (pegasus->tx_urb); + usb_free_urb (pegasus->rx_urb); + usb_free_urb (pegasus->ctrl_urb); + kfree (pegasus); + pegasus = NULL; + goto exit; + } + net = init_etherdev( NULL, 0 ); if ( !net ) { + usb_free_urb (pegasus->tx_urb); + usb_free_urb (pegasus->rx_urb); + usb_free_urb (pegasus->ctrl_urb); kfree( pegasus ); - return NULL; + pegasus = NULL; + goto exit; } - + + init_MUTEX(&pegasus->sem); pegasus->usb = dev; pegasus->net = net; SET_MODULE_OWNER(net); @@ -883,10 +1047,13 @@ if ( reset_mac(pegasus) ) { err("can't reset MAC"); unregister_netdev( pegasus->net ); + usb_free_urb (pegasus->tx_urb); + usb_free_urb (pegasus->rx_urb); + usb_free_urb (pegasus->ctrl_urb); kfree(pegasus->net); kfree(pegasus); pegasus = NULL; - return NULL; + goto exit; } info( "%s: %s", net->name, usb_dev_id[dev_index].name ); @@ -904,6 +1071,8 @@ pegasus->phy = 1; } +exit: + up(&gsem); return pegasus; } @@ -920,6 +1089,14 @@ pegasus->flags |= PEGASUS_UNPLUG; unregister_netdev( pegasus->net ); usb_dec_dev_use( dev ); + usb_unlink_urb(pegasus->intr_urb); + usb_unlink_urb(pegasus->tx_urb); + usb_unlink_urb(pegasus->rx_urb); + usb_unlink_urb(pegasus->ctrl_urb); + usb_free_urb(pegasus->intr_urb); + usb_free_urb(pegasus->tx_urb); + usb_free_urb(pegasus->rx_urb); + usb_free_urb(pegasus->ctrl_urb); kfree( pegasus->net ); kfree( pegasus ); pegasus = NULL; diff -urN linux-2.4.18/drivers/usb/pegasus.h linux-2.4.19-pre5/drivers/usb/pegasus.h --- linux-2.4.18/drivers/usb/pegasus.h Sun Dec 23 16:23:49 2001 +++ linux-2.4.19-pre5/drivers/usb/pegasus.h Sat Mar 30 22:55:40 2002 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.com) + * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,14 +31,6 @@ #define EPROM_WR_ENABLE 0x10 #define EPROM_LOAD 0x20 -#define MII_BMCR 0x00 -#define MII_BMSR 0x01 -#define BMSR_MEDIA 0x7808 -#define MII_ANLPA 0x05 -#define ANLPA_100TX_FD 0x0100 -#define ANLPA_100TX_HD 0x0080 -#define ANLPA_10T_FD 0x0040 -#define ANLPA_10T_HD 0x0020 #define PHY_DONE 0x80 #define PHY_READ 0x40 #define PHY_WRITE 0x20 @@ -107,10 +99,10 @@ unsigned features; int dev_index; int intr_interval; - struct urb ctrl_urb, rx_urb, tx_urb, intr_urb; + struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; devrequest dr; wait_queue_head_t ctrl_wait; - struct semaphore ctrl_sem; + struct semaphore sem; unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]); @@ -134,9 +126,12 @@ #define VENDOR_ALLIEDTEL 0x07c9 #define VENDOR_BELKIN 0x050d #define VENDOR_BILLIONTON 0x08dd +#define VENDOR_COMPAQ 0x049f #define VENDOR_COREGA 0x07aa #define VENDOR_DLINK 0x2001 +#define VENDOR_ELCON 0x0db7 #define VENDOR_ELSA 0x05cc +#define VENDOR_HAWKING 0x0e66 #define VENDOR_IODATA 0x04bb #define VENDOR_KINGSTON 0x0951 #define VENDOR_LANEED 0x056e @@ -145,7 +140,7 @@ #define VENDOR_SMARTBRIDGES 0x08d1 #define VENDOR_SMC 0x0707 #define VENDOR_SOHOWARE 0x15e8 - +#define VENDOR_SIEMENS 0x067c #else /* PEGASUS_DEV */ @@ -173,12 +168,16 @@ DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", VENDOR_ADMTEK, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)", VENDOR_ADMTEK, 0x0986, DEFAULT_GPIO_RESET | HAS_HOME_PNA ) +PEGASUS_DEV( "ADMtek AN986A USB MAC", VENDOR_ADMTEK, 0x1986, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, @@ -187,6 +186,8 @@ DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987, DEFAULT_GPIO_RESET | HAS_HOME_PNA ) +PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, @@ -207,10 +208,16 @@ DEFAULT_GPIO_RESET | HAS_HOME_PNA ) PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "ELCON EPLC10Mi USB to Powerline Adapter", VENDOR_ELCON, 0x0002, + DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a, DEFAULT_GPIO_RESET) PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, @@ -243,8 +250,11 @@ DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, DEFAULT_GPIO_RESET ) - +PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, + DEFAULT_GPIO_RESET ) #endif /* PEGASUS_DEV */ diff -urN linux-2.4.18/drivers/usb/printer.c linux-2.4.19-pre5/drivers/usb/printer.c --- linux-2.4.18/drivers/usb/printer.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/printer.c Sat Mar 30 22:55:40 2002 @@ -1,10 +1,12 @@ /* - * printer.c Version 0.8 + * printer.c Version 0.11 * * Copyright (c) 1999 Michael Gee * Copyright (c) 1999 Pavel Machek * Copyright (c) 2000 Randy Dunlap * Copyright (c) 2000 Vojtech Pavlik + # Copyright (c) 2001 Pete Zaitcev + # Copyright (c) 2001 David Paschal * * USB Printer Device Class driver for USB printers and printer cables * @@ -17,9 +19,11 @@ * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support * v0.6 - never time out - * v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) + * v0.7 - fixed bulk-IN read and poll (David Paschal) * v0.8 - add devfs support * v0.9 - fix unplug-while-open paths + * v0.10 - add proto_bias option (Pete Zaitcev) + * v0.11 - add hpoj.sourceforge.net ioctls (David Paschal) */ /* @@ -54,16 +58,36 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.8" -#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap" +#define DRIVER_VERSION "v0.11" +#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" #define DRIVER_DESC "USB Printer Device Class driver" #define USBLP_BUF_SIZE 8192 #define DEVICE_ID_SIZE 1024 -#define IOCNR_GET_DEVICE_ID 1 -#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */ +/* ioctls: */ #define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ +#define IOCNR_GET_DEVICE_ID 1 +#define IOCNR_GET_PROTOCOLS 2 +#define IOCNR_SET_PROTOCOL 3 +#define IOCNR_HP_SET_CHANNEL 4 +#define IOCNR_GET_BUS_ADDRESS 5 +#define IOCNR_GET_VID_PID 6 +/* Get device_id string: */ +#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) +/* The following ioctls were added for http://hpoj.sourceforge.net: */ +/* Get two-int array: + * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), + * [1]=supported protocol mask (mask&(1<dev); + dbg("devfs=0x%p", usblp->devfs); + dbg("buf=0x%p", usblp->buf); + dbg("readcount=%d", usblp->readcount); + dbg("ifnum=%d", usblp->ifnum); + for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { + dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); + dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); + dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); + } + dbg("current_protocol=%d", usblp->current_protocol); + dbg("minor=%d", usblp->minor); + dbg("quirks=%d", usblp->quirks); + dbg("used=%d", usblp->used); + dbg("bidir=%d", usblp->bidir); + dbg("device_id_string=\"%s\"", + usblp->device_id_string ? + usblp->device_id_string + 2 : + (unsigned char *)"(null)"); +} +#endif + extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ static struct usblp *usblp_table[USBLP_MINORS]; @@ -123,29 +188,52 @@ { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ + { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ + { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ + { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ + { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ + { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ + { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ + { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ + { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ { 0, 0 } }; +static int usblp_select_alts(struct usblp *usblp); +static int usblp_set_protocol(struct usblp *usblp, int protocol); +static int usblp_cache_device_id_string(struct usblp *usblp); + + /* * Functions for usblp control messages. */ -static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len) +static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) { int retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5); + request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", request, !!dir, recip, value, len, retval); return retval < 0 ? retval : 0; } #define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) #define usblp_get_id(usblp, config, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) #define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + +#define usblp_hp_channel_change_request(usblp, channel, buffer) \ + usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) + +/* + * See the description for usblp_select_alts() below for the usage + * explanation. Look into your /proc/bus/usb/devices and dmesg in + * case of any trouble. + */ +static int proto_bias = -1; /* * URB callback. @@ -257,13 +345,20 @@ { devfs_unregister (usblp->devfs); usblp_table [usblp->minor] = NULL; - info ("usblp%d: removed", usblp->minor); + info("usblp%d: removed", usblp->minor); kfree (usblp->writeurb.transfer_buffer); kfree (usblp->device_id_string); kfree (usblp); } +static void usblp_unlink_urbs(struct usblp *usblp) +{ + usb_unlink_urb(&usblp->writeurb); + if (usblp->bidir) + usb_unlink_urb(&usblp->readurb); +} + static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; @@ -272,9 +367,7 @@ lock_kernel(); usblp->used = 0; if (usblp->dev) { - if (usblp->bidir) - usb_unlink_urb(&usblp->readurb); - usb_unlink_urb(&usblp->writeurb); + usblp_unlink_urbs(usblp); up(&usblp->sem); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); @@ -294,8 +387,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct usblp *usblp = file->private_data; - int length, err; - unsigned char status; + int length, err, i; + unsigned char status, newChannel; + int twoints[2]; int retval = 0; down (&usblp->sem); @@ -314,32 +408,128 @@ goto done; } - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + length = usblp_cache_device_id_string(usblp); + if (length < 0) { + retval = length; + goto done; + } + if (length > _IOC_SIZE(cmd)) + length = _IOC_SIZE(cmd); /* truncate */ + + if (copy_to_user((unsigned char *) arg, + usblp->device_id_string, + (unsigned long) length)) { + retval = -EFAULT; + goto done; + } + + break; + + case IOCNR_GET_PROTOCOLS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->current_protocol; + twoints[1] = 0; + for (i = USBLP_FIRST_PROTOCOL; + i <= USBLP_LAST_PROTOCOL; i++) { + if (usblp->protocol[i].alt_setting >= 0) + twoints[1] |= (1<current_protocol); + } + break; + + case IOCNR_HP_SET_CHANNEL: + if (_IOC_DIR(cmd) != _IOC_WRITE || + usblp->dev->descriptor.idVendor != 0x03F0 || + usblp->quirks & USBLP_QUIRK_BIDIR) { + retval = -EINVAL; + goto done; + } + + err = usblp_hp_channel_change_request(usblp, + arg, &newChannel); if (err < 0) { - dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string", + err("usblp%d: error = %d setting " + "HP channel", usblp->minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; retval = -EIO; goto done; } - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; + dbg("usblp%d requested/got HP channel %ld/%d", + usblp->minor, arg, newChannel); + break; - dbg ("usblp%d Device ID string [%d/max %d]='%s'", - usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + case IOCNR_GET_BUS_ADDRESS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } - if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + twoints[0] = usblp->dev->bus->busnum; + twoints[1] = usblp->dev->devnum; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { + retval = -EFAULT; + goto done; + } - if (copy_to_user((unsigned char *) arg, - usblp->device_id_string, (unsigned long) length)) { + dbg("usblp%d is bus=%d, device=%d", + usblp->minor, twoints[0], twoints[1]); + break; + + case IOCNR_GET_VID_PID: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->dev->descriptor.idVendor; + twoints[1] = usblp->dev->descriptor.idProduct; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { retval = -EFAULT; goto done; } + dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", + usblp->minor, twoints[0], twoints[1]); break; default: @@ -545,137 +735,255 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *epread, *epwrite; - struct usblp *usblp; - int minor, i, bidir = 0, quirks; - int alts = dev->actconfig->interface[ifnum].act_altsetting; - int length, err; - char *buf; + struct usblp *usblp = 0; + int protocol; char name[6]; - /* If a bidirectional interface exists, use it. */ - for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { - - interface = &dev->actconfig->interface[ifnum].altsetting[i]; - - if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 || - interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 || - (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) - continue; - - if (interface->bInterfaceProtocol > 1) { - bidir = 1; - alts = i; - break; - } - } - - interface = &dev->actconfig->interface[ifnum].altsetting[alts]; - if (usb_set_interface(dev, ifnum, alts)) - err("can't set desired altsetting %d on interface %d", alts, ifnum); - - epwrite = interface->endpoint + 0; - epread = bidir ? interface->endpoint + 1 : NULL; - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) { - if (interface->bNumEndpoints == 1) - return NULL; - epwrite = interface->endpoint + 1; - epread = bidir ? interface->endpoint + 0 : NULL; - } - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) - return NULL; - - if (bidir && (epread->bEndpointAddress & 0x80) != 0x80) - return NULL; - - for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++); - if (usblp_table[minor]) { - err("no more free usblp devices"); - return NULL; - } - + /* Malloc and start initializing usblp structure so we can use it + * directly. */ if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) { - err("out of memory"); - return NULL; + err("out of memory for usblp"); + goto abort; } memset(usblp, 0, sizeof(struct usblp)); - init_MUTEX (&usblp->sem); - - /* lookup quirks for this printer */ - quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); - - if (bidir && (quirks & USBLP_QUIRK_BIDIR)) { - bidir = 0; - epread = NULL; - info ("Disabling reads from problem bidirectional printer on usblp%d", - minor); - } - usblp->dev = dev; - usblp->ifnum = ifnum; - usblp->minor = minor; - usblp->bidir = bidir; - usblp->quirks = quirks; - + init_MUTEX (&usblp->sem); init_waitqueue_head(&usblp->wait); + usblp->ifnum = ifnum; - if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) { - err("out of memory"); - kfree(usblp); - return NULL; + /* Look for a free usblp_table entry. */ + while (usblp_table[usblp->minor]) { + usblp->minor++; + if (usblp->minor >= USBLP_MINORS) { + err("no more free usblp devices"); + goto abort; + } } + /* Malloc device ID string buffer to the largest expected length, + * since we can re-query it on an ioctl and a dynamic string + * could change in length. */ if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { - err("out of memory"); - kfree(usblp); - kfree(buf); - return NULL; + err("out of memory for device_id_string"); + goto abort; } - FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf, 0, usblp_bulk, usblp); + /* Malloc write/read buffers in one chunk. We somewhat wastefully + * malloc both regardless of bidirectionality, because the + * alternate setting can be changed later via an ioctl. */ + if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) { + err("out of memory for buf"); + goto abort; + } + + /* Lookup quirks for this printer. */ + usblp->quirks = usblp_quirks( + dev->descriptor.idVendor, + dev->descriptor.idProduct); + + /* Analyze and pick initial alternate settings and endpoints. */ + protocol = usblp_select_alts(usblp); + if (protocol < 0) { + dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", + dev->descriptor.idVendor, + dev->descriptor.idProduct); + goto abort; + } + + /* Setup the selected alternate setting and endpoints. */ + if (usblp_set_protocol(usblp, protocol) < 0) + goto abort; - if (bidir) - FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp); - - /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */ - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); - if (err >= 0) { - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; - dbg ("usblp%d Device ID string [%d]=%s", - minor, length, &usblp->device_id_string[2]); - } - else { - err ("usblp%d: error = %d reading IEEE-1284 Device ID string", - minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - } + /* Retrieve and store the device ID string. */ + usblp_cache_device_id_string(usblp); #ifdef DEBUG usblp_check_status(usblp, 0); #endif - sprintf(name, "lp%d", minor); - - /* if we have devfs, create with perms=660 */ + /* If we have devfs, create with perms=660. */ + sprintf(name, "lp%d", usblp->minor); usblp->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, - USBLP_MINOR_BASE + minor, + USBLP_MINOR_BASE + usblp->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &usblp_fops, NULL); - info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", - minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); + info("usblp%d: USB %sdirectional printer dev %d " + "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X", + usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum, + usblp->protocol[usblp->current_protocol].alt_setting, + usblp->current_protocol, usblp->dev->descriptor.idVendor, + usblp->dev->descriptor.idProduct); + + return usblp_table[usblp->minor] = usblp; + +abort: + if (usblp) { + if (usblp->buf) kfree(usblp->buf); + if (usblp->device_id_string) kfree(usblp->device_id_string); + kfree(usblp); + } + return NULL; +} - return usblp_table[minor] = usblp; +/* + * We are a "new" style driver with usb_device_id table, + * but our requirements are too intricate for simple match to handle. + * + * The "proto_bias" option may be used to specify the preferred protocol + * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device + * supports the preferred protocol, then we bind to it. + * + * The best interface for us is 7/1/2, because it is compatible + * with a stream of characters. If we find it, we bind to it. + * + * Note that the people from hpoj.sourceforge.net need to be able to + * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. + * + * Failing 7/1/2, we look for 7/1/3, even though it's probably not + * stream-compatible, because this matches the behaviour of the old code. + * + * If nothing else, we bind to 7/1/1 - the unidirectional interface. + */ +static int usblp_select_alts(struct usblp *usblp) +{ + struct usb_interface *if_alt; + struct usb_interface_descriptor *ifd; + struct usb_endpoint_descriptor *epd, *epwrite, *epread; + int p, i, e; + + if_alt = &usblp->dev->actconfig->interface[usblp->ifnum]; + + for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) + usblp->protocol[p].alt_setting = -1; + + /* Find out what we have. */ + for (i = 0; i < if_alt->num_altsetting; i++) { + ifd = &if_alt->altsetting[i]; + + if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1) + continue; + + if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL || + ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL) + continue; + + /* Look for bulk OUT and IN endpoints. */ + epwrite = epread = 0; + for (e = 0; e < ifd->bNumEndpoints; e++) { + epd = &ifd->endpoint[e]; + + if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!= + USB_ENDPOINT_XFER_BULK) + continue; + + if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) { + if (!epwrite) epwrite=epd; + + } else { + if (!epread) epread=epd; + } + } + + /* Ignore buggy hardware without the right endpoints. */ + if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread)) + continue; + + /* Turn off reads for 7/1/1 (unidirectional) interfaces + * and buggy bidirectional printers. */ + if (ifd->bInterfaceProtocol == 1) { + epread = NULL; + } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { + info("Disabling reads from problem bidirectional " + "printer on usblp%d", usblp->minor); + epread = NULL; + } + + usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i; + usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite; + usblp->protocol[ifd->bInterfaceProtocol].epread = epread; + } + + /* If our requested protocol is supported, then use it. */ + if (proto_bias >= USBLP_FIRST_PROTOCOL && + proto_bias <= USBLP_LAST_PROTOCOL && + usblp->protocol[proto_bias].alt_setting != -1) + return proto_bias; + + /* Ordering is important here. */ + if (usblp->protocol[2].alt_setting != -1) return 2; + if (usblp->protocol[1].alt_setting != -1) return 1; + if (usblp->protocol[3].alt_setting != -1) return 3; + + /* If nothing is available, then don't bind to this device. */ + return -1; +} + +static int usblp_set_protocol(struct usblp *usblp, int protocol) +{ + int r, alts; + + if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) + return -EINVAL; + + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) return -EINVAL; + r = usb_set_interface(usblp->dev, usblp->ifnum, alts); + if (r < 0) { + err("can't set desired altsetting %d on interface %d", + alts, usblp->ifnum); + return r; + } + + FILL_BULK_URB(&usblp->writeurb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[protocol].epwrite->bEndpointAddress), + usblp->buf, 0, + usblp_bulk, usblp); + + usblp->bidir = (usblp->protocol[protocol].epread != 0); + if (usblp->bidir) + FILL_BULK_URB(&usblp->readurb, usblp->dev, + usb_rcvbulkpipe(usblp->dev, + usblp->protocol[protocol].epread->bEndpointAddress), + usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, + usblp_bulk, usblp); + + usblp->current_protocol = protocol; + dbg("usblp%d set protocol %d", usblp->minor, protocol); + return 0; +} + +/* Retrieves and caches device ID string. + * Returns length, including length bytes but not null terminator. + * On error, returns a negative errno value. */ +static int usblp_cache_device_id_string(struct usblp *usblp) +{ + int err, length; + + err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + if (err < 0) { + dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", + usblp->minor, err); + usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; + return -EIO; + } + + /* First two bytes are length in big-endian. + * They count themselves, and we copy them into + * the user's buffer. */ + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; + if (length < 2) + length = 2; + else if (length >= DEVICE_ID_SIZE) + length = DEVICE_ID_SIZE - 1; + usblp->device_id_string[length] = '\0'; + + dbg("usblp%d Device ID string [len=%d]=\"%s\"", + usblp->minor, length, &usblp->device_id_string[2]); + + return length; } static void usblp_disconnect(struct usb_device *dev, void *ptr) @@ -691,9 +999,7 @@ lock_kernel(); usblp->dev = NULL; - usb_unlink_urb(&usblp->writeurb); - if (usblp->bidir) - usb_unlink_urb(&usblp->readurb); + usblp_unlink_urbs(usblp); if (!usblp->used) usblp_cleanup (usblp); @@ -727,7 +1033,7 @@ { if (usb_register(&usblp_driver)) return -1; - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_VERSION ": " DRIVER_DESC); return 0; } @@ -741,5 +1047,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_PARM(proto_bias, "i"); +MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); - diff -urN linux-2.4.18/drivers/usb/pwc-ctrl.c linux-2.4.19-pre5/drivers/usb/pwc-ctrl.c --- linux-2.4.18/drivers/usb/pwc-ctrl.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/pwc-ctrl.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* Driver for Philips webcam Functions that send various control messages to the webcam, including video modes. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -78,10 +78,12 @@ #define READ_SHUTTER_FORMATTER 0x0600 #define READ_RED_GAIN_FORMATTER 0x0700 #define READ_BLUE_GAIN_FORMATTER 0x0800 +#define SENSOR_TYPE_FORMATTER1 0x0C00 #define READ_RAW_Y_MEAN_FORMATTER 0x3100 #define SET_POWER_SAVE_MODE_FORMATTER 0x3200 #define MIRROR_IMAGE_FORMATTER 0x3300 #define LED_FORMATTER 0x3400 +#define SENSOR_TYPE_FORMATTER2 0x3700 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 @@ -162,6 +164,21 @@ /****************************************************************************/ +#define SendControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + +#define RecvControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) #if PWC_DEBUG @@ -241,7 +258,7 @@ ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); if (ret < 0) return ret; - if (pEntry->compressed) + if (pEntry->compressed && pdev->decompressor != NULL) pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); /* Set various parameters */ @@ -911,7 +928,7 @@ int ret; ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, + GET_CHROM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_MANUAL_RED_GAIN_FORMATTER, pdev->vcinterface, @@ -950,7 +967,7 @@ int ret; ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, + GET_CHROM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_MANUAL_BLUE_GAIN_FORMATTER, pdev->vcinterface, @@ -962,6 +979,7 @@ return (buf << 8); } + /* The following two functions are different, since they only read the internal red/blue gains, which may be different from the manual gains set or read above. @@ -997,11 +1015,74 @@ &buf, 1, HZ / 2); if (ret < 0) - return ret; + return ret; return (buf << 8); } + +static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) +{ + unsigned char buf; + + /* useful range is 0x01..0x20 */ + buf = speed / 0x7f0; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_CHROM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_SPEED_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +static inline int pwc_get_wb_speed(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_CHROM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_SPEED_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return (buf * 0x7f0); +} + + +static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) +{ + unsigned char buf; + + /* useful range is 0x01..0x3F */ + buf = (delay >> 10); + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_CHROM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_DELAY_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +static inline int pwc_get_wb_delay(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_CHROM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AWB_CONTROL_DELAY_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return (buf << 10); +} + + int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) { unsigned char buf[2]; @@ -1055,53 +1136,242 @@ return 0; } +static inline int pwc_set_contour(struct pwc_device *pdev, int contour) +{ + unsigned char buf; + int ret; + + if (contour < 0) + buf = 0xff; /* auto contour on */ + else + buf = 0x0; /* auto contour off */ + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AUTO_CONTOUR_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + + if (contour < 0) + return 0; + if (contour > 0xffff) + contour = 0xffff; + + buf = (contour >> 10); /* contour preset is [0..3f] */ + ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + PRESET_CONTOUR_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) +{ + unsigned char buf; + int ret; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + AUTO_CONTOUR_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + + if (buf == 0) { + /* auto mode off, query current preset value */ + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + PRESET_CONTOUR_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + *contour = (buf << 10); + } + else + *contour = -1; + return 0; +} + + +static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) +{ + unsigned char buf; + + if (backlight) + buf = 0xff; + else + buf = 0x0; + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_LUM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + BACK_LIGHT_COMPENSATION_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); +} + +static inline int pwc_get_backlight(struct pwc_device *pdev) +{ + int ret; + unsigned char buf; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_LUM_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + BACK_LIGHT_COMPENSATION_FORMATTER, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + return buf; +} + + +static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) +{ + unsigned char buf; + + if (flicker) + buf = 0xff; + else + buf = 0x0; + return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); +} + +static inline int pwc_get_flicker(struct pwc_device *pdev) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); + if (ret < 0) + return ret; + return buf; +} + + +static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) +{ + unsigned char buf; + + if (noise < 0) + noise = 0; + if (noise > 3) + noise = 3; + buf = noise; + return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); +} + +static inline int pwc_get_dynamic_noise(struct pwc_device *pdev) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); + if (ret < 0) + return ret; +Debug("pwc_get_dynamic_noise = %d\n", buf); + return buf; +} + + +int pwc_get_cmos_sensor(struct pwc_device *pdev) +{ + unsigned char buf; + int ret = -1, request; + + if (pdev->type < 675) + request = SENSOR_TYPE_FORMATTER1; + else if (pdev->type < 730) + return -1; /* The Vesta series doesn't have this call */ + else + request = SENSOR_TYPE_FORMATTER2; + + ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), + GET_STATUS_CTL, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + request, + pdev->vcinterface, + &buf, 1, HZ / 2); + if (ret < 0) + return ret; + if (pdev->type < 675) + return buf | 0x100; + else + return buf; +} + + /* End of Add-Ons */ /* ************************************************* */ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { + int ret = 0; + switch(cmd) { case VIDIOCPWCRUSER: { if (pwc_restore_user(pdev)) - return -EINVAL; + ret = -EINVAL; break; } case VIDIOCPWCSUSER: { if (pwc_save_user(pdev)) - return -EINVAL; + ret = -EINVAL; break; } case VIDIOCPWCFACTORY: { if (pwc_restore_factory(pdev)) - return -EINVAL; + ret = -EINVAL; break; } case VIDIOCPWCSCQUAL: { - int qual, ret; + int qual; if (copy_from_user(&qual, arg, sizeof(int))) - return -EFAULT; - - if (qual < 0 || qual > 3) - return -EINVAL; - ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot); - if (ret < 0) - return ret; - pdev->vcompression = qual; + ret = -EFAULT; + else { + if (qual < 0 || qual > 3) + ret = -EINVAL; + else + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot); + if (ret >= 0) + pdev->vcompression = qual; + } break; } case VIDIOCPWCGCQUAL: { if (copy_to_user(arg, &pdev->vcompression, sizeof(int))) - return -EFAULT; + ret = -EFAULT; + break; + } + + case VIDIOCPWCPROBE: + { + struct pwc_probe probe; + + strcpy(probe.name, pdev->vdev->name); + probe.type = pdev->type; + if (copy_to_user(arg, &probe, sizeof(probe))) + ret = -EFAULT; break; } @@ -1110,10 +1380,10 @@ int agc; if (copy_from_user(&agc, arg, sizeof(agc))) - return -EFAULT; + ret = -EFAULT; else { if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc)) - return -EINVAL; + ret = -EINVAL; } break; } @@ -1123,42 +1393,36 @@ int agc; if (pwc_get_agc(pdev, &agc)) - return -EINVAL; - if (copy_to_user(arg, &agc, sizeof(agc))) - return -EFAULT; + ret = -EINVAL; + else + if (copy_to_user(arg, &agc, sizeof(agc))) + ret = -EFAULT; break; } case VIDIOCPWCSSHUTTER: { - int shutter_speed, ret; + int shutter_speed; if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed))) - return -EFAULT; - else { + ret = -EFAULT; + else ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed); - if (ret < 0) - return ret; - } break; } - - /* ************************************************* */ - /* Begin of Add-Ons for color compensation */ - case VIDIOCPWCSAWB: { struct pwc_whitebalance wb; - int ret; if (copy_from_user(&wb, arg, sizeof(wb))) - return -EFAULT; - - ret = pwc_set_awb(pdev, wb.mode); - if (ret >= 0 && wb.mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, wb.manual_red); - pwc_set_blue_gain(pdev, wb.manual_blue); + ret = -EFAULT; + else { + ret = pwc_set_awb(pdev, wb.mode); + if (ret >= 0 && wb.mode == PWC_WB_MANUAL) { + pwc_set_red_gain(pdev, wb.manual_red); + pwc_set_blue_gain(pdev, wb.manual_blue); + } } break; } @@ -1170,55 +1434,176 @@ memset(&wb, 0, sizeof(wb)); wb.mode = pwc_get_awb(pdev); if (wb.mode < 0) - return -EINVAL; - wb.manual_red = pwc_get_red_gain(pdev); - wb.manual_blue = pwc_get_blue_gain(pdev); - if (wb.mode == PWC_WB_AUTO) { - wb.read_red = pwc_read_red_gain(pdev); - wb.read_blue = pwc_read_blue_gain(pdev); + ret = -EINVAL; + else { + if (wb.mode == PWC_WB_MANUAL) { + wb.manual_red = pwc_get_red_gain(pdev); + wb.manual_blue = pwc_get_blue_gain(pdev); + } + if (wb.mode == PWC_WB_AUTO) { + wb.read_red = pwc_read_red_gain(pdev); + wb.read_blue = pwc_read_blue_gain(pdev); + } + if (copy_to_user(arg, &wb, sizeof(wb))) + ret= -EFAULT; } - if (copy_to_user(arg, &wb, sizeof(wb))) - return -EFAULT; + break; + } + + case VIDIOCPWCSAWBSPEED: + { + struct pwc_wb_speed wbs; + + if (copy_from_user(&wbs, arg, sizeof(wbs))) + ret = -EFAULT; + else { + if (wbs.control_speed > 0) { + ret = pwc_set_wb_speed(pdev, wbs.control_speed); + } + if (wbs.control_delay > 0) { + ret = pwc_set_wb_delay(pdev, wbs.control_delay); + } + } + break; + } + + case VIDIOCPWCGAWBSPEED: + { + struct pwc_wb_speed wbs; + + ret = pwc_get_wb_speed(pdev); + if (ret < 0) + break; + wbs.control_speed = ret; + ret = pwc_get_wb_delay(pdev); + if (ret < 0) + break; + wbs.control_delay = ret; + if (copy_to_user(arg, &wbs, sizeof(wbs))) + ret = -EFAULT; break; } case VIDIOCPWCSLED: { - int ret; struct pwc_leds leds; if (copy_from_user(&leds, arg, sizeof(leds))) - return -EFAULT; - - ret = pwc_set_leds(pdev, leds.led_on, leds.led_off); - if (ret<0) - return ret; - break; + ret = -EFAULT; + else + ret = pwc_set_leds(pdev, leds.led_on, leds.led_off); + break; } - case VIDIOCPWCGLED: { - int led; struct pwc_leds leds; - led = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); - if (led < 0) - return -EINVAL; + ret = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); + if (ret < 0) + break; if (copy_to_user(arg, &leds, sizeof(leds))) - return -EFAULT; + ret = -EFAULT; break; } - /* End of Add-Ons */ - /* ************************************************* */ + case VIDIOCPWCSCONTOUR: + { + int contour; + + if (copy_from_user(&contour, arg, sizeof(contour))) + ret = -EFAULT; + else + ret = pwc_set_contour(pdev, contour); + break; + } + + case VIDIOCPWCGCONTOUR: + { + int contour; + + ret = pwc_get_contour(pdev, &contour); + if (ret < 0) + break; + + if (copy_to_user(arg, &contour, sizeof(contour))) + ret = -EFAULT; + break; + } + + case VIDIOCPWCSBACKLIGHT: + { + int backlight; + + if (copy_from_user(&backlight, arg, sizeof(backlight))) + ret = -EFAULT; + else + ret = pwc_set_backlight(pdev, backlight); + break; + } + + case VIDIOCPWCGBACKLIGHT: + { + ret = pwc_get_backlight(pdev); + if (ret < 0) + break; + if (copy_to_user(arg, &ret, sizeof(ret))) + ret = -EFAULT; + break; + } + + case VIDIOCPWCSFLICKER: + { + int flicker; + + if (copy_from_user(&flicker, arg, sizeof(flicker))) + ret = -EFAULT; + else + ret = pwc_set_flicker(pdev, flicker); + break; + } + + case VIDIOCPWCGFLICKER: + { + ret = pwc_get_flicker(pdev); + if (ret < 0) + break; + if (copy_to_user(arg, &ret, sizeof(ret))) + ret = -EFAULT; + break; + } + + case VIDIOCPWCSDYNNOISE: + { + int dynnoise; + + if (copy_from_user(&dynnoise, arg, sizeof(dynnoise))) + ret = -EFAULT; + else + ret = pwc_set_dynamic_noise(pdev, dynnoise); + break; + } + + case VIDIOCPWCGDYNNOISE: + { + ret = pwc_get_dynamic_noise(pdev); + if (ret < 0) + break; + if (copy_to_user(arg, &ret, sizeof(ret))) + ret = -EFAULT; + break; + } + default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; break; } - return 0; + + if (ret > 0) + return 0; + return ret; } diff -urN linux-2.4.18/drivers/usb/pwc-if.c linux-2.4.19-pre5/drivers/usb/pwc-if.c --- linux-2.4.18/drivers/usb/pwc-if.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/pwc-if.c Sat Mar 30 22:55:40 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam USB and Video4Linux interface part. - (C) 1999-2001 Nemosoft Unv. + (C) 1999-2002 Nemosoft Unv. 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 @@ -66,7 +66,7 @@ /* hotplug device table support */ static __devinitdata struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ { USB_DEVICE(0x0471, 0x0303) }, { USB_DEVICE(0x0471, 0x0304) }, { USB_DEVICE(0x0471, 0x0307) }, @@ -75,12 +75,14 @@ { USB_DEVICE(0x0471, 0x0310) }, { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x069A, 0x0001) }, - { USB_DEVICE(0x046D, 0x08b0) }, - { USB_DEVICE(0x055D, 0x9000) }, + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, - { USB_DEVICE(0x04CC, 0x8116) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); @@ -105,7 +107,7 @@ static int default_mbufs = 2; /* Default number of mmap() buffers */ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; -static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */ +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; @@ -163,7 +165,7 @@ succeeded. The pwc_device struct links back to both structures. When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register as a V4L device, but + list of known USB devices; I also de-register it as a V4L device, but unfortunately I can't free the memory since the struct is still in use by the file descriptor. This free-ing is then deferend until the first opportunity. Crude, but it works. @@ -351,6 +353,8 @@ for (; i < MAX_IMAGES; i++) pdev->image_ptr[i] = NULL; + kbuf = NULL; + Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); return 0; } @@ -405,6 +409,7 @@ rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); } pdev->image_data = NULL; + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); } @@ -606,12 +611,10 @@ pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; } -/* 2001-10-14: The YUV420 is still there, but you can only set it from within - a program (YUV420P being the default) */ +/* 2001-10-14: YUV420P is the only palette remaining. */ static int pwc_set_palette(struct pwc_device *pdev, int pal) { - if ( pal == VIDEO_PALETTE_YUV420 - || pal == VIDEO_PALETTE_YUV420P + if ( pal == VIDEO_PALETTE_YUV420P #if PWC_DEBUG || pal == VIDEO_PALETTE_RAW #endif @@ -629,7 +632,7 @@ /* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */ -static void pwc_isoc_handler(purb_t urb) +static void pwc_isoc_handler(struct urb *urb) { struct pwc_device *pdev; int i, fst, flen; @@ -791,7 +794,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) { struct usb_device *udev; - purb_t urb; + struct urb *urb; int i, j, ret; struct usb_interface_descriptor *idesc; @@ -905,7 +908,6 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) { int ret; - /* Stop isoc stuff */ pwc_isoc_cleanup(pdev); /* Reset parameters */ @@ -968,6 +970,29 @@ if (usb_set_interface(pdev->udev, 0, 0)) Info("Failed to set alternate interface to 0.\n"); pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) { + /* Query CMOS sensor type */ + const char *sensor_type = NULL; + + i = pwc_get_cmos_sensor(pdev); + switch(i) { + case -1: /* Unknown, show nothing */; break; + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + if (sensor_type != NULL) + Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } } /* Turn on camera */ @@ -1590,6 +1615,7 @@ pdev = vdev->priv; /* FIXME - audit mmap during a read */ + /* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); @@ -1621,7 +1647,7 @@ int vendor_id, product_id, type_id; int i, hint; int video_nr = -1; /* default: use next available device */ - char serial_number[30]; + char serial_number[30], *name; free_mem_leak(); @@ -1642,38 +1668,47 @@ switch (product_id) { case 0x0302: Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; type_id = 750; break; default: @@ -1685,6 +1720,7 @@ switch(product_id) { case 0x0001: Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 645; break; default: @@ -1695,7 +1731,8 @@ else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - Info("Logitech QuickCam 3000 Pro detected.\n"); + Info("Logitech QuickCam 3000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam 3000 Pro"; type_id = 730; break; default: @@ -1711,10 +1748,12 @@ switch(product_id) { case 0x9000: Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; type_id = 675; break; default: @@ -1726,6 +1765,7 @@ switch(product_id) { case 0x400c: Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; type_id = 730; break; default: @@ -1736,7 +1776,8 @@ else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: - Info("SOTEC CMS-001 USB webcam detected.\n"); + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; type_id = 730; break; default: @@ -1744,7 +1785,25 @@ break; } } - else return NULL; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */ + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return NULL; + break; + } + } + else + return NULL; /* Not any of the know types; but the list keeps growing. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); @@ -1778,7 +1837,7 @@ return NULL; } memcpy(vdev, &pwc_template, sizeof(pwc_template)); - sprintf(vdev->name, "Philips %d webcam", pdev->type); + strcpy(vdev->name, name); SET_MODULE_OWNER(vdev); pdev->vdev = vdev; vdev->priv = pdev; @@ -1786,7 +1845,6 @@ pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) { if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && @@ -1951,11 +2009,12 @@ char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n"); - Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n"); + Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); if (fps) { - if (fps < 5 || fps > 30) { - Err("Framerate out of bounds (5-30).\n"); + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } default_fps = fps; @@ -2007,9 +2066,9 @@ if (power_save) Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) - led_on = leds[0] / 100; + led_on = leds[0]; if (leds[1] >= 0) - led_off = leds[1] / 100; + led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type diff -urN linux-2.4.18/drivers/usb/pwc-ioctl.h linux-2.4.19-pre5/drivers/usb/pwc-ioctl.h --- linux-2.4.18/drivers/usb/pwc-ioctl.h Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/pwc-ioctl.h Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ #ifndef PWC_IOCTL_H #define PWC_IOCTL_H -/* (C) 2001 Nemosoft Unv. webcam@smcc.demon.nl +/* (C) 2001-2002 Nemosoft Unv. webcam@smcc.demon.nl 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 @@ -18,7 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/* This is pwc-ioctl.h belonging to PWC 8.6 */ + +/* Changes 2001/08/03 Alvarado Added ioctl constants to access methods for changing white balance and red/blue gains @@ -52,6 +54,14 @@ #define PWC_FPS_SNAPSHOT 0x00400000 + +struct pwc_probe +{ + char name[32]; + int type; +}; + + /* pwc_whitebalance.mode values */ #define PWC_WB_INDOOR 0 #define PWC_WB_OUTDOOR 1 @@ -63,9 +73,9 @@ Set mode to one of the PWC_WB_* values above. *red and *blue are the respective gains of these colour components inside the camera; range 0..65535 - When mode == PWC_WB_MANUAL, manual_red and manual_blue are set or read; + When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; otherwise undefined. - read_red and read_blue are read-only. + 'read_red' and 'read_blue' are read-only. */ struct pwc_whitebalance @@ -75,6 +85,17 @@ int read_red, read_blue; /* R/O */ }; +/* + 'control_speed' and 'control_delay' are used in automatic whitebalance mode, + and tell the camera how fast it should react to changes in lighting, and + with how much delay. Valid values are 0..65535. +*/ +struct pwc_wb_speed +{ + int control_speed; + int control_delay; + +}; /* Used with VIDIOCPWC[SG]LED */ struct pwc_leds @@ -104,6 +125,19 @@ /* Get preferred compression quality */ #define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + /* This is a probe function; since so many devices are supported, it + becomes difficult to include all the names in programs that want to + check for the enhanced Philips stuff. So in stead, try this PROBE; + it returns a structure with the original name, and the corresponding + Philips type. + To use, fill the structure with zeroes, call PROBE and if that succeeds, + compare the name with that returned from VIDIOCGCAP; they should be the + same. If so, you can be assured it is a Philips (OEM) cam and the type + is valid. + */ +#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ #define VIDIOCPWCSAGC _IOW('v', 200, int) /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ @@ -115,9 +149,28 @@ #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - /* Turn LED on/off ; int range 0..65535 */ + /* Auto WB speed */ +#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) +#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) + + /* LEDs on/off/blink; int range 0..65535 */ #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) - /* Get state of LED; int range 0..65535 */ #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) + + /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ +#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) +#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) + + /* Backlight compensation; 0 = off, otherwise on */ +#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) +#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) + + /* Flickerless mode; = 0 off, otherwise on */ +#define VIDIOCPWCSFLICKER _IOW('v', 208, int) +#define VIDIOCPWCGFLICKER _IOR('v', 208, int) + + /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ +#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) +#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) #endif diff -urN linux-2.4.18/drivers/usb/pwc-misc.c linux-2.4.19-pre5/drivers/usb/pwc-misc.c --- linux-2.4.18/drivers/usb/pwc-misc.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/pwc-misc.c Sat Mar 30 22:55:40 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Various miscellaneous functions and tables. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -urN linux-2.4.18/drivers/usb/pwc-uncompress.c linux-2.4.19-pre5/drivers/usb/pwc-uncompress.c --- linux-2.4.18/drivers/usb/pwc-uncompress.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/pwc-uncompress.c Sat Mar 30 22:55:40 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Decompression frontend. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -urN linux-2.4.18/drivers/usb/pwc-uncompress.h linux-2.4.19-pre5/drivers/usb/pwc-uncompress.h --- linux-2.4.18/drivers/usb/pwc-uncompress.h Sat Mar 30 13:54:37 2002 +++ linux-2.4.19-pre5/drivers/usb/pwc-uncompress.h Sat Mar 30 22:55:40 2002 @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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,8 +20,8 @@ significant change should be reflected by increasing the pwc_decompressor_version major number. */ -#ifndef PWC_DEC_H -#define PWC_DEC_H +#ifndef PWC_UNCOMPRESS_H +#define PWC_UNCOMPRESS_H #include #include diff -urN linux-2.4.18/drivers/usb/pwc.h linux-2.4.19-pre5/drivers/usb/pwc.h --- linux-2.4.18/drivers/usb/pwc.h Sat Mar 30 13:53:46 2002 +++ linux-2.4.19-pre5/drivers/usb/pwc.h Sat Mar 30 22:55:40 2002 @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 5 -#define PWC_VERSION "8.5" +#define PWC_MINOR 6 +#define PWC_VERSION "8.6" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -96,7 +96,7 @@ void *data; int length; int read; - purb_t urb; + struct urb *urb; }; /* intermediate buffers with raw data from the USB cam */ @@ -247,6 +247,7 @@ extern int pwc_set_saturation(struct pwc_device *pdev, int value); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev); /* Power down or up the camera; not supported by all models */ extern int pwc_camera_power(struct pwc_device *pdev, int power); diff -urN linux-2.4.18/drivers/usb/serial/Config.in linux-2.4.19-pre5/drivers/usb/serial/Config.in --- linux-2.4.18/drivers/usb/serial/Config.in Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/serial/Config.in Sat Mar 30 22:55:35 2002 @@ -15,7 +15,7 @@ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL -dep_tristate ' USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL +dep_tristate ' USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff -urN linux-2.4.18/drivers/usb/serial/cyberjack.c linux-2.4.19-pre5/drivers/usb/serial/cyberjack.c --- linux-2.4.18/drivers/usb/serial/cyberjack.c Sun Dec 23 16:23:50 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/cyberjack.c Sat Mar 30 22:55:35 2002 @@ -238,13 +238,16 @@ if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) { /* To much data for buffer. Reset buffer. */ priv->wrfilled=0; + up (&port->sem); return (0); } /* Copy data */ if (from_user) { - if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) + if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) { + up (&port->sem); return -EFAULT; + } } else { memcpy (priv->wrbuf+priv->wrfilled, buf, count); } diff -urN linux-2.4.18/drivers/usb/serial/digi_acceleport.c linux-2.4.19-pre5/drivers/usb/serial/digi_acceleport.c --- linux-2.4.18/drivers/usb/serial/digi_acceleport.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/digi_acceleport.c Sat Mar 30 22:55:40 2002 @@ -734,7 +734,7 @@ while( count > 0 && ret == 0 ) { while( (port->write_urb->status == -EINPROGRESS - || priv->dp_write_urb_in_use) && jiffies < timeout ) { + || priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) { cond_wait_interruptible_timeout_irqrestore( &port->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); @@ -899,7 +899,7 @@ spin_lock_irqsave( &priv->dp_port_lock, flags ); - while( jiffies < timeout && !priv->dp_transmit_idle ) { + while( time_before(jiffies, timeout) && !priv->dp_transmit_idle ) { cond_wait_interruptible_timeout_irqrestore( &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); diff -urN linux-2.4.18/drivers/usb/serial/ftdi_sio.c linux-2.4.19-pre5/drivers/usb/serial/ftdi_sio.c --- linux-2.4.18/drivers/usb/serial/ftdi_sio.c Sun Dec 23 16:23:50 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/ftdi_sio.c Sat Mar 30 22:55:35 2002 @@ -138,6 +138,7 @@ static __devinitdata struct usb_device_id id_table_8U232AM [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { } /* Terminating entry */ }; @@ -145,6 +146,7 @@ static __devinitdata struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { } /* Terminating entry */ }; diff -urN linux-2.4.18/drivers/usb/serial/ftdi_sio.h linux-2.4.19-pre5/drivers/usb/serial/ftdi_sio.h --- linux-2.4.18/drivers/usb/serial/ftdi_sio.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/ftdi_sio.h Sat Mar 30 22:55:35 2002 @@ -22,6 +22,8 @@ #define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ +#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff -urN linux-2.4.18/drivers/usb/serial/io_edgeport.c linux-2.4.19-pre5/drivers/usb/serial/io_edgeport.c --- linux-2.4.18/drivers/usb/serial/io_edgeport.c Sun Dec 23 16:23:50 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/io_edgeport.c Sat Mar 30 22:55:35 2002 @@ -2,7 +2,7 @@ * Edgeport USB Serial Converter driver * * Copyright(c) 2000 Inside Out Networks, All rights reserved. - * Copyright(c) 2001 Greg Kroah-Hartman + * Copyright(c) 2001-2002 Greg Kroah-Hartman * * 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 @@ -25,6 +25,9 @@ * * Version history: * + * 2.3 2002_03_08 greg kroah-hartman + * - fixed bug when multiple devices were attached at the same time. + * * 2.2 2001_11_14 greg kroah-hartman * - fixed bug in edge_close that kept the port from being used more * than once. @@ -1449,8 +1452,8 @@ edge_port->write_in_progress = FALSE; return; } - buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number, count); - buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number, count); + buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count); + buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number - edge_port->port->serial->minor, count); /* now copy our data */ bytesleft = fifo->size - fifo->tail; @@ -2447,7 +2450,9 @@ currentCommand = buffer; - MAKE_CMD_EXT_CMD( ¤tCommand, &length, edge_port->port->number, command, param); + MAKE_CMD_EXT_CMD (¤tCommand, &length, + edge_port->port->number - edge_port->port->serial->minor, + command, param); status = write_cmd_usb (edge_port, buffer, length); if (status) { @@ -2527,9 +2532,9 @@ int cmdLen = 0; int divisor; int status; - unsigned char number = edge_port->port->number; + unsigned char number = edge_port->port->number - edge_port->port->serial->minor; - dbg(__FUNCTION__" - port = %d, baud = %d", number, baudRate); + dbg(__FUNCTION__" - port = %d, baud = %d", edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); if (status) { @@ -2632,7 +2637,9 @@ currCmd = cmdBuffer; // Build a cmd in the buffer to write the given register - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->number, regNum, regValue); + MAKE_CMD_WRITE_REG (&currCmd, &cmdLen, + edge_port->port->number - edge_port->port->serial->minor, + regNum, regValue); status = write_cmd_usb(edge_port, cmdBuffer, cmdLen); if (status) { diff -urN linux-2.4.18/drivers/usb/serial/ipaq.c linux-2.4.19-pre5/drivers/usb/serial/ipaq.c --- linux-2.4.18/drivers/usb/serial/ipaq.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/serial/ipaq.c Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* * USB Compaq iPAQ driver * - * Copyright (C) 2001 + * Copyright (C) 2001 - 2002 * Ganesh Varadarajan * * This program is free software; you can redistribute it and/or modify @@ -9,6 +9,23 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * (19/3/2002) ganesh + * Don't submit urbs while holding spinlocks. Thanks to Greg for pointing + * this out. + * + * (8/3/2002) ganesh + * The ipaq sometimes emits a '\0' before the CLIENT string. At this + * point of time, the ppp ldisc is not yet attached to the tty, so + * n_tty echoes "^ " to the ipaq, which messes up the chat. In 2.5.6-pre2 + * this causes a panic because echo_char() tries to sleep in interrupt + * context. + * The fix is to tell the upper layers that this is a raw device so that + * echoing is suppressed. Thanks to Lyle Lindholm for a detailed bug + * report. + * + * (25/2/2002) ganesh + * Added support for the HP Jornada 548 and 568. Completely untested. + * Thanks to info from Heath Robinson and Arieh Davidoff. */ #include @@ -39,9 +56,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.1" +#define DRIVER_VERSION "v0.2" #define DRIVER_AUTHOR "Ganesh Varadarajan " -#define DRIVER_DESC "USB Compaq iPAQ driver" +#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver" /* Function prototypes for an ipaq */ static int ipaq_open (struct usb_serial_port *port, struct file *filp); @@ -52,7 +69,7 @@ int count); static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); -static int ipaq_write_flush(struct usb_serial_port *port); +static void ipaq_write_gather(struct usb_serial_port *port); static void ipaq_read_bulk_callback (struct urb *urb); static void ipaq_write_bulk_callback(struct urb *urb); static int ipaq_write_room(struct usb_serial_port *port); @@ -61,7 +78,9 @@ static __devinitdata struct usb_device_id ipaq_id_table [] = { - { USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) }, + { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, { } /* Terminating entry */ }; @@ -71,10 +90,10 @@ struct usb_serial_device_type ipaq_device = { name: "Compaq iPAQ", id_table: ipaq_id_table, - needs_interrupt_in: MUST_HAVE_NOT, + needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, - num_interrupt_in: 0, + num_interrupt_in: NUM_DONT_CARE, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, @@ -149,6 +168,8 @@ */ port->tty->low_latency = 1; + port->tty->raw = 1; + port->tty->real_raw = 1; /* * Lose the small buffers usbserial provides. Make larger ones. @@ -365,17 +386,23 @@ priv->queue_len += count; if (priv->active == 0) { priv->active = 1; - result = ipaq_write_flush(port); + ipaq_write_gather(port); + spin_unlock_irqrestore(&write_list_lock, flags); + result = usb_submit_urb(port->write_urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + } + } else { + spin_unlock_irqrestore(&write_list_lock, flags); } - spin_unlock_irqrestore(&write_list_lock, flags); return result; } -static int ipaq_write_flush(struct usb_serial_port *port) +static void ipaq_write_gather(struct usb_serial_port *port) { struct ipaq_private *priv = (struct ipaq_private *)port->private; struct usb_serial *serial = port->serial; - int count, room, result; + int count, room; struct ipaq_packet *pkt; struct urb *urb = port->write_urb; struct list_head *tmp; @@ -383,7 +410,7 @@ if (urb->status == -EINPROGRESS) { /* Should never happen */ err(__FUNCTION__ " - flushing while urb is active !"); - return -EAGAIN; + return; } room = URBDATA_SIZE; for (tmp = priv->queue.next; tmp != &priv->queue;) { @@ -410,11 +437,7 @@ usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback, port); - result = usb_submit_urb(urb); - if (result) { - err(__FUNCTION__ " - failed submitting write urb, error %d", result); - } - return result; + return; } static void ipaq_write_bulk_callback(struct urb *urb) @@ -422,6 +445,7 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct ipaq_private *priv = (struct ipaq_private *)port->private; unsigned long flags; + int result; if (port_paranoia_check (port, __FUNCTION__)) { return; @@ -435,11 +459,16 @@ spin_lock_irqsave(&write_list_lock, flags); if (!list_empty(&priv->queue)) { - ipaq_write_flush(port); + ipaq_write_gather(port); + spin_unlock_irqrestore(&write_list_lock, flags); + result = usb_submit_urb(port->write_urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + } } else { priv->active = 0; + spin_unlock_irqrestore(&write_list_lock, flags); } - spin_unlock_irqrestore(&write_list_lock, flags); queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); diff -urN linux-2.4.18/drivers/usb/serial/ipaq.h linux-2.4.19-pre5/drivers/usb/serial/ipaq.h --- linux-2.4.18/drivers/usb/serial/ipaq.h Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/serial/ipaq.h Sat Mar 30 22:55:35 2002 @@ -1,7 +1,7 @@ /* * USB Compaq iPAQ driver * - * Copyright (C) 2001 + * Copyright (C) 2001 - 2002 * Ganesh Varadarajan * * This program is free software; you can redistribute it and/or modify @@ -16,8 +16,12 @@ #define __LINUX_USB_SERIAL_IPAQ_H -#define IPAQ_VENDOR_ID 0x049f -#define IPAQ_PRODUCT_ID 0x0003 +#define COMPAQ_VENDOR_ID 0x049f +#define COMPAQ_IPAQ_ID 0x0003 + +#define HP_VENDOR_ID 0x003f +#define HP_JORNADA_548_ID 0x1016 +#define HP_JORNADA_568_ID 0x1116 /* * Since we can't queue our bulk write urbs (don't know why - it just diff -urN linux-2.4.18/drivers/usb/serial/visor.c linux-2.4.19-pre5/drivers/usb/serial/visor.c --- linux-2.4.18/drivers/usb/serial/visor.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/serial/visor.c Sat Mar 30 22:55:40 2002 @@ -2,7 +2,7 @@ * USB HandSpring Visor, Palm m50x, and Sony Clie driver * (supports all of the Palm OS USB devices) * - * Copyright (C) 1999 - 2001 + * Copyright (C) 1999 - 2002 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -12,6 +12,16 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (03/21/2002) gkh + * Added support for the Palm m130 device, thanks to Udo Eisenbarth + * for the information. + * + * (02/21/2002) SilaS + * Added support for the Palm m515 devices. + * + * (02/15/2002) gkh + * Added support for the Clie S-360 device. + * * (12/18/2001) gkh * Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand * for the patch. @@ -160,7 +170,9 @@ static __devinitdata struct usb_device_id palm_4_0_id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, { } /* Terminating entry */ }; @@ -171,6 +183,7 @@ static __devinitdata struct usb_device_id clie_id_4_0_table [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, { } /* Terminating entry */ }; @@ -178,9 +191,12 @@ { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, { } /* Terminating entry */ }; diff -urN linux-2.4.18/drivers/usb/serial/visor.h linux-2.4.19-pre5/drivers/usb/serial/visor.h --- linux-2.4.18/drivers/usb/serial/visor.h Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/serial/visor.h Sat Mar 30 22:55:40 2002 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor driver * - * Copyright (C) 1999 - 2001 + * Copyright (C) 1999 - 2002 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -23,11 +23,14 @@ #define PALM_VENDOR_ID 0x0830 #define PALM_M500_ID 0x0001 #define PALM_M505_ID 0x0002 +#define PALM_M515_ID 0x0003 #define PALM_M125_ID 0x0040 +#define PALM_M130_ID 0x0050 #define SONY_VENDOR_ID 0x054C #define SONY_CLIE_3_5_ID 0x0038 #define SONY_CLIE_4_0_ID 0x0066 +#define SONY_CLIE_S360_ID 0x0095 /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) diff -urN linux-2.4.18/drivers/usb/storage/datafab.c linux-2.4.19-pre5/drivers/usb/storage/datafab.c --- linux-2.4.18/drivers/usb/storage/datafab.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/datafab.c Sat Mar 30 22:55:35 2002 @@ -1,16 +1,25 @@ /* Driver for Datafab USB Compact Flash reader * + * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * datafab driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Other contributors: + * (c) 2002 Alan Stern + * * 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) any @@ -102,7 +111,7 @@ if (result == -EPIPE) { US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -800,6 +809,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("datafab_transport: START_STOP.\n"); + /* the first datafab_id_device after a media change returns + an error (determined experimentally) */ + rc = datafab_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -urN linux-2.4.18/drivers/usb/storage/debug.c linux-2.4.19-pre5/drivers/usb/storage/debug.c --- linux-2.4.18/drivers/usb/storage/debug.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/storage/debug.c Sat Mar 30 22:55:35 2002 @@ -1,10 +1,13 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * - * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $ + * $Id: debug.c,v 1.8 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Developed with the assistance of: + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -300,9 +303,11 @@ case 0x1902: what="defect list error in primary list"; break; case 0x1903: what="defect list error in grown list"; break; case 0x1C00: what="defect list not found"; break; + case 0x2000: what="invalid command operation code"; break; case 0x2400: what="invalid field in CDB"; break; case 0x2703: what="associated write protect"; break; case 0x2800: what="not ready to ready transition"; break; + case 0x2900: what="device reset occurred"; break; case 0x2903: what="bus device reset function occurred"; break; case 0x2904: what="device internal reset"; break; case 0x2B00: what="copy can't execute / host can't disconnect"; break; @@ -325,6 +330,7 @@ case 0x3502: what="enclosure services unavailable"; break; case 0x3503: what="enclosure services transfer failure"; break; case 0x3504: what="enclosure services transfer refused"; break; + case 0x3A00: what="media not present"; break; case 0x3B0F: what="end of medium reached"; break; case 0x3F02: what="changed operating definition"; break; case 0x4100: what="data path failure (should use 40 NN)"; break; diff -urN linux-2.4.18/drivers/usb/storage/isd200.c linux-2.4.19-pre5/drivers/usb/storage/isd200.c --- linux-2.4.18/drivers/usb/storage/isd200.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/usb/storage/isd200.c Sat Mar 30 22:55:35 2002 @@ -1,9 +1,15 @@ /* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * - * First release + * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $ * - * Current development and maintenance by: - * (c) 2000 In-System Design, Inc. (support@in-system.com) + * Current development and maintenance: + * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) + * + * Developed with the assistance of: + * (C) 2002 Alan Stern + * + * Initial work: + * (C) 2000 In-System Design, Inc. (support@in-system.com) * * The ISD200 ASIC does not natively support ATA devices. The chip * does implement an interface, the ATA Command Block (ATACB) which provides @@ -27,6 +33,10 @@ * * 2001-02-24: Removed lots of duplicate code and simplified the structure. * (bjorn@haxx.se) + * 2002-01-16: Fixed endianness bug so it works on the ppc arch. + * (Luc Saillard ) + * 2002-01-17: All bitfields removed. + * (bjorn@haxx.se) */ @@ -45,15 +55,6 @@ #include #include -/* - * Inquiry defines. Used to interpret data returned from target as result - * of inquiry command. - * - * DeviceType field - */ - -#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ - /* Timeout defines (in Seconds) */ #define ISD200_ENUM_BSY_TIMEOUT 35 @@ -88,6 +89,19 @@ #define ACTION_SELECT_6 0x40 #define ACTION_SELECT_7 0x80 +/* Register Select bits */ +#define REG_ALTERNATE_STATUS 0x01 +#define REG_DEVICE_CONTROL 0x01 +#define REG_ERROR 0x02 +#define REG_FEATURES 0x02 +#define REG_SECTOR_COUNT 0x04 +#define REG_SECTOR_NUMBER 0x08 +#define REG_CYLINDER_LOW 0x10 +#define REG_CYLINDER_HIGH 0x20 +#define REG_DEVICE_HEAD 0x40 +#define REG_STATUS 0x80 +#define REG_COMMAND 0x80 + /* ATA error definitions not in */ #define ATA_ERROR_MEDIA_CHANGE 0x20 @@ -152,20 +166,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectAlternateStatus : 1; - unsigned char SelectError : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectStatus : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char AlternateStatusByte; unsigned char ErrorByte; @@ -181,20 +183,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectDeviceControl : 1; - unsigned char SelectFeatures : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectCommand : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char DeviceControlByte; unsigned char FeaturesByte; @@ -218,27 +208,20 @@ * includes fields through ProductRevisionLevel. */ +/* + * DeviceType field + */ +#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ +#define DEVICE_REMOVABLE 0x80 + struct inquiry_data { - unsigned char DeviceType : 5; - unsigned char DeviceTypeQualifier : 3; - unsigned char DeviceTypeModifier : 7; - unsigned char RemovableMedia : 1; + unsigned char DeviceType; + unsigned char DeviceTypeModifier; unsigned char Versions; - unsigned char ResponseDataFormat : 4; - unsigned char HiSupport : 1; - unsigned char NormACA : 1; - unsigned char ReservedBit : 1; - unsigned char AERC : 1; + unsigned char Format; unsigned char AdditionalLength; unsigned char Reserved[2]; - unsigned char SoftReset : 1; - unsigned char CommandQueue : 1; - unsigned char Reserved2 : 1; - unsigned char LinkedCommands : 1; - unsigned char Synchronous : 1; - unsigned char Wide16Bit : 1; - unsigned char Wide32Bit : 1; - unsigned char RelativeAddressing : 1; + unsigned char Capability; unsigned char VendorId[8]; unsigned char ProductId[16]; unsigned char ProductRevisionLevel[4]; @@ -257,25 +240,30 @@ * ISD200 CONFIG data struct */ +#define ATACFG_TIMING 0x0f +#define ATACFG_ATAPI_RESET 0x10 +#define ATACFG_MASTER 0x20 +#define ATACFG_BLOCKSIZE 0xa0 + +#define ATACFGE_LAST_LUN 0x07 +#define ATACFGE_DESC_OVERRIDE 0x08 +#define ATACFGE_STATE_SUSPEND 0x10 +#define ATACFGE_SKIP_BOOT 0x20 +#define ATACFGE_CONF_DESC2 0x40 +#define ATACFGE_INIT_STATUS 0x80 + +#define CFG_CAPABILITY_SRST 0x01 + struct isd200_config { unsigned char EventNotification; unsigned char ExternalClock; unsigned char ATAInitTimeout; - unsigned char ATATiming : 4; - unsigned char ATAPIReset : 1; - unsigned char MasterSlaveSelection : 1; - unsigned char ATAPICommandBlockSize : 2; + unsigned char ATAConfig; unsigned char ATAMajorCommand; unsigned char ATAMinorCommand; - unsigned char LastLUNIdentifier : 3; - unsigned char DescriptOverride : 1; - unsigned char ATA3StateSuspend : 1; - unsigned char SkipDeviceBoot : 1; - unsigned char ConfigDescriptor2 : 1; - unsigned char InitStatus : 1; - unsigned char SRSTEnable : 1; - unsigned char Reserved0 : 7; -}; + unsigned char ATAExtraConfig; + unsigned char Capability; +}__attribute__ ((packed)); /* @@ -321,15 +309,16 @@ * Sense Data Format */ +#define SENSE_ERRCODE 0x7f +#define SENSE_ERRCODE_VALID 0x80 +#define SENSE_FLAG_SENSE_KEY 0x0f +#define SENSE_FLAG_BAD_LENGTH 0x20 +#define SENSE_FLAG_END_OF_MEDIA 0x40 +#define SENSE_FLAG_FILE_MARK 0x80 struct sense_data { - unsigned char ErrorCode:7; - unsigned char Valid:1; - unsigned char SegmentNumber; - unsigned char SenseKey:4; - unsigned char Reserved:1; - unsigned char IncorrectLength:1; - unsigned char EndOfMedia:1; - unsigned char FileMark:1; + unsigned char ErrorCode; + unsigned char SegmentNumber; + unsigned char Flags; unsigned char Information[4]; unsigned char AdditionalSenseLength; unsigned char CommandSpecificInformation[4]; @@ -349,7 +338,6 @@ * Helper routines ***********************************************************************/ - /************************************************************************** * isd200_build_sense * @@ -366,38 +354,33 @@ unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; if(error & ATA_ERROR_MEDIA_CHANGE) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & MCR_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & TRK0_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = NOT_READY; + buf->Flags = NOT_READY; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & ECC_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = DATA_PROTECT; + buf->Flags = DATA_PROTECT; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else { buf->ErrorCode = 0; - buf->Valid = 0; buf->AdditionalSenseLength = 0; - buf->SenseKey = 0; + buf->Flags = 0; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } @@ -442,7 +425,7 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } /* did we send all the data? */ @@ -593,7 +576,7 @@ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), - bcb.DataTransferLength, bcb.Flags, bcb.Length); + le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); @@ -603,7 +586,7 @@ else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } else if (result) return ISD200_TRANSPORT_ERROR; @@ -633,7 +616,7 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -647,7 +630,7 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); return ISD200_TRANSPORT_ERROR; } } @@ -716,10 +699,9 @@ case ACTION_READ_STATUS: US_DEBUGP(" isd200_action(READ_STATUS)\n"); ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; - ata.read.SelectStatus = 1; - ata.read.SelectError = 1; - ata.read.SelectCylinderHigh = 1; - ata.read.SelectCylinderLow = 1; + ata.generic.RegisterSelect = + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_STATUS | REG_ERROR; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = pointer; srb.request_bufflen = value; @@ -730,7 +712,7 @@ ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -739,7 +721,7 @@ US_DEBUGP(" isd200_action(RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -748,7 +730,7 @@ US_DEBUGP(" isd200_action(REENABLE)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -756,16 +738,15 @@ case ACTION_SOFT_RESET: US_DEBUGP(" isd200_action(SOFT_RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.SelectCommand = 1; ata.write.CommandByte = WIN_SRST; srb.sc_data_direction = SCSI_DATA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); - ata.write.SelectCommand = 1; + ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = (void *)&info->drive; @@ -821,7 +802,7 @@ * Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to - * the device and recieve the response. + * the device and receive the response. */ void isd200_invoke_transport( struct us_data *us, Scsi_Cmnd *srb, @@ -886,6 +867,43 @@ srb->result = CHECK_CONDITION; } +#ifdef CONFIG_USB_STORAGE_DEBUG +static void isd200_log_config( struct isd200_info* info ) +{ + US_DEBUGP(" Event Notification: 0x%x\n", + info->ConfigData.EventNotification); + US_DEBUGP(" External Clock: 0x%x\n", + info->ConfigData.ExternalClock); + US_DEBUGP(" ATA Init Timeout: 0x%x\n", + info->ConfigData.ATAInitTimeout); + US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", + (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); + US_DEBUGP(" Master/Slave Selection: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_MASTER); + US_DEBUGP(" ATAPI Reset: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); + US_DEBUGP(" ATA Timing: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_TIMING); + US_DEBUGP(" ATA Major Command: 0x%x\n", + info->ConfigData.ATAMajorCommand); + US_DEBUGP(" ATA Minor Command: 0x%x\n", + info->ConfigData.ATAMinorCommand); + US_DEBUGP(" Init Status: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); + US_DEBUGP(" Config Descriptor 2: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); + US_DEBUGP(" Skip Device Boot: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); + US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); + US_DEBUGP(" Descriptor Override: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); + US_DEBUGP(" Last LUN Identifier: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); + US_DEBUGP(" SRST Enable: 0x%x\n", + info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); +} +#endif /************************************************************************** * isd200_write_config @@ -901,26 +919,11 @@ int retStatus = ISD200_GOOD; int result; - +#ifdef CONFIG_USB_STORAGE_DEBUG US_DEBUGP("Entering isd200_write_config\n"); - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); + isd200_log_config(info); +#endif /* let's send the command via the control pipe */ result = usb_stor_control_msg( @@ -941,8 +944,8 @@ /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -986,30 +989,17 @@ if (result >= 0) { US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); +#ifdef CONFIG_USB_STORAGE_DEBUG + isd200_log_config(info); +#endif } else { US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -1175,11 +1165,12 @@ break; } } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + break; } /* check for timeout on this request */ - if (jiffies >= endTime) { + if (time_after_eq(jiffies, endTime)) { if (!detect) US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); else @@ -1223,9 +1214,10 @@ } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; - if (info->ConfigData.MasterSlaveSelection != isslave) { + if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); - info->ConfigData.MasterSlaveSelection = isslave; + info->ConfigData.ATAConfig &= 0x3f; + info->ConfigData.ATAConfig |= (isslave<<6); retStatus = isd200_write_config(us); } } @@ -1272,6 +1264,8 @@ } else { /* ATA Command Identify successful */ int i; + __u16 *src, *dest; + ide_fix_driveid(&info->drive); US_DEBUGP(" Identify Data Structure:\n"); US_DEBUGP(" config = 0x%x\n", info->drive.config); @@ -1317,31 +1311,25 @@ if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ - info->InquiryData.RemovableMedia = 1; + info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ - for (i = 0; i < 20; i += 2) { - info->InquiryData.VendorId[i] = - info->drive.model[i + 1]; - info->InquiryData.VendorId[i+1] = - info->drive.model[i]; - } - - /* Initialize unused portion of product id */ - for (i = 0; i < 4; i++) { - info->InquiryData.ProductId[12+i] = ' '; - } - - /* Move firmware revision from IDENTIFY data to */ - /* product revision in INQUIRY data */ - for (i = 0; i < 4; i += 2) { - info->InquiryData.ProductRevisionLevel[i] = - info->drive.fw_rev[i+1]; - info->InquiryData.ProductRevisionLevel[i+1] = - info->drive.fw_rev[i]; - } + src = (__u16*)info->drive.model; + dest = (__u16*)info->InquiryData.VendorId; + for (i=0;i<4;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)(info->drive.model+8); + dest = (__u16*)info->InquiryData.ProductId; + for (i=0;i<8;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)info->drive.fw_rev; + dest = (__u16*)info->InquiryData.ProductRevisionLevel; + for (i=0;i<2;i++) + dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { @@ -1483,7 +1471,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1504,7 +1492,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1561,17 +1549,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_READ; break; @@ -1594,17 +1580,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_WRITE; break; @@ -1617,7 +1601,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; srb->request_bufflen = 0; @@ -1640,14 +1624,14 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 0; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; } else if ((srb->cmnd[4] & 0x3) == 0x1) { US_DEBUGP(" Get Media Status\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { diff -urN linux-2.4.18/drivers/usb/storage/jumpshot.c linux-2.4.19-pre5/drivers/usb/storage/jumpshot.c --- linux-2.4.18/drivers/usb/storage/jumpshot.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/jumpshot.c Sat Mar 30 22:55:35 2002 @@ -1,16 +1,26 @@ /* Driver for Lexar "Jumpshot" Compact Flash reader * + * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * jumpshot driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Developed with the assistance of: + * + * (C) 2002 Alan Stern + * * 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) any @@ -128,8 +138,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("jumpshot_send_control: -- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("jumpshot_send_control: -- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -161,7 +171,7 @@ if (result == -EPIPE) { US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -798,6 +808,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("jumpshot_transport: START_STOP.\n"); + /* the first jumpshot_id_device after a media change returns + an error (determined experimentally) */ + rc = jumpshot_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -urN linux-2.4.18/drivers/usb/storage/protocol.c linux-2.4.19-pre5/drivers/usb/storage/protocol.c --- linux-2.4.18/drivers/usb/storage/protocol.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/protocol.c Sat Mar 30 22:55:35 2002 @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $ + * $Id: protocol.c,v 1.13 2002/02/25 00:34:56 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2002 Alan Stern (stern@rowland.org) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -97,9 +98,11 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) @@ -168,13 +171,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } @@ -263,13 +268,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* Fix the data for an INQUIRY, if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* Fix the data for an INQUIRY, if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) @@ -330,13 +337,14 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE) - && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } diff -urN linux-2.4.18/drivers/usb/storage/sddr09.c linux-2.4.19-pre5/drivers/usb/storage/sddr09.c --- linux-2.4.18/drivers/usb/storage/sddr09.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/sddr09.c Sat Mar 30 22:55:35 2002 @@ -1,6 +1,6 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $ + * $Id: sddr09.c,v 1.23 2002/02/25 00:40:13 mdharm Exp $ * * SDDR09 driver v0.1: * @@ -9,6 +9,9 @@ * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * + * Developed with the assistance of: + * (c) 2002 Alan Stern + * * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. * This chip is a programmable USB controller. In the SDDR-09, it has * been programmed to obey a certain limited set of SCSI commands. This @@ -113,8 +116,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -146,7 +149,7 @@ US_DEBUGP("EPIPE: clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { diff -urN linux-2.4.18/drivers/usb/storage/shuttle_usbat.c linux-2.4.19-pre5/drivers/usb/storage/shuttle_usbat.c --- linux-2.4.18/drivers/usb/storage/shuttle_usbat.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/shuttle_usbat.c Sat Mar 30 22:55:35 2002 @@ -1,10 +1,13 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $ + * $Id: shuttle_usbat.c,v 1.16 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * + * Developed with the assistance of: + * (c) 2002 Alan Stern + * * Many originally ATAPI devices were slightly modified to meet the USB * market by using some kind of translation from ATAPI to USB on the host, * and the peripheral would translate from USB back to ATAPI. @@ -107,8 +110,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -140,7 +143,7 @@ US_DEBUGP("EPIPE: clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -515,7 +518,7 @@ */ if (direction==SCSI_DATA_READ && i==0) - usb_clear_halt(us->pusb_dev, + usb_stor_clear_halt(us, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* @@ -675,9 +678,15 @@ len = short_pack(data[7+9], data[7+8]); len <<= 16; len |= data[7+7]; + US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); srb->transfersize = srb->request_bufflen/len; } + if (!srb->transfersize) { + srb->transfersize = 2048; /* A guess */ + US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", + srb->transfersize); + } len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); diff -urN linux-2.4.18/drivers/usb/storage/transport.c linux-2.4.19-pre5/drivers/usb/storage/transport.c --- linux-2.4.18/drivers/usb/storage/transport.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/transport.c Sat Mar 30 22:55:35 2002 @@ -1,13 +1,14 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ + * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -335,31 +336,7 @@ len = srb->request_bufflen; } -return len; -} - -/* This is a version of usb_clear_halt() that doesn't read the status from - * the device -- this is because some devices crash their internal firmware - * when the status is requested after a halt - */ -int usb_stor_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, HZ * 3); - - /* this is a failure case */ - if (result < 0) - return result; - - /* reset the toggles and endpoint flags */ - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - - return 0; + return len; } /*********************************************************************** @@ -481,6 +458,34 @@ return us->current_urb->status; } +/* This is a version of usb_clear_halt() that doesn't read the status from + * the device -- this is because some devices crash their internal firmware + * when the status is requested after a halt + */ +int usb_stor_clear_halt(struct us_data *us, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); + + result = usb_stor_control_msg(us, + usb_sndctrlpipe(us->pusb_dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0); /* note: no 3*HZ timeout */ + US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); + + /* this is a failure case */ + if (result < 0) + return result; + + /* reset the toggles and endpoint flags */ + usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe)); + usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), 0); + + return 0; +} + /* * Transfer one SCSI scatter-gather buffer via bulk transfer * @@ -513,7 +518,13 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); + } + + /* did we abort this command? */ + if (result == -ENOENT) { + US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; } /* did we send all the data? */ @@ -522,21 +533,14 @@ return US_BULK_TRANSFER_GOOD; } - /* uh oh... we have an error code, so something went wrong. */ - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } + /* NAK - that means we've retried a few times already */ + if (result == -ETIMEDOUT) { + US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + return US_BULK_TRANSFER_FAILED; + } - /* the catch-all case */ + /* the catch-all error case */ + if (result) { US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); return US_BULK_TRANSFER_FAILED; } @@ -550,7 +554,7 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this + * Note that this uses usb_stor_transfer_partial to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ @@ -612,7 +616,7 @@ /* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to - * the device and recieve the response. + * the device and receive the response. */ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) { @@ -631,6 +635,14 @@ return; } + /* if there is a transport error, reset and don't auto-sense */ + if (result == USB_STOR_TRANSPORT_ERROR) { + US_DEBUGP("-- transport indicates error, resetting\n"); + us->transport_reset(us); + srb->result = DID_ERROR << 16; + return; + } + /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible @@ -660,7 +672,7 @@ } /* - * If we have an error, we're going to do a REQUEST_SENSE + * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ @@ -668,13 +680,6 @@ US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } - if (result == USB_STOR_TRANSPORT_ERROR) { - us->transport_reset(us); - US_DEBUGP("-- transport indicates transport failure\n"); - need_auto_sense = 0; - srb->result = DID_ERROR << 16; - return; - } /* * Also, if we have a short transfer on a command that can't have @@ -730,6 +735,19 @@ /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); + + /* let's clean up right away */ + srb->request_buffer = old_request_buffer; + srb->request_bufflen = old_request_bufflen; + srb->use_sg = old_sg; + srb->sc_data_direction = old_sc_data_direction; + memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); + + if (temp_result == USB_STOR_TRANSPORT_ABORTED) { + US_DEBUGP("-- auto-sense aborted\n"); + srb->result = DID_ABORT << 16; + return; + } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); @@ -760,13 +778,6 @@ /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION << 1; - /* we're done here, let's clean up */ - srb->request_buffer = old_request_buffer; - srb->request_bufflen = old_request_bufflen; - srb->use_sg = old_sg; - srb->sc_data_direction = old_sc_data_direction; - memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = GOOD << 1; @@ -798,7 +809,7 @@ { struct us_data *us = (struct us_data *)urb->context; - US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); + US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no); US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); US_DEBUGP("-- IRQ state is %d\n", urb->status); US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", @@ -864,21 +875,25 @@ if (result < 0) { /* Reset flag for status notification */ atomic_set(us->ip_wanted, 0); + } + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + + /* STALL must be cleared when it is detected */ + if (result == -EPIPE) { + US_DEBUGP("-- Stall on control pipe. Clearing\n"); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; + return USB_STOR_TRANSPORT_FAILED; + } - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - + if (result < 0) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } @@ -887,12 +902,18 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CBI data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) { + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { + atomic_set(us->ip_wanted, 0); return USB_STOR_TRANSPORT_ABORTED; } + if (result == US_BULK_TRANSFER_FAILED) { + atomic_set(us->ip_wanted, 0); + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -976,10 +997,12 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_FAILED; } @@ -991,11 +1014,16 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CB data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CB data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { return USB_STOR_TRANSPORT_ABORTED; + } + if (result == US_BULK_TRANSFER_FAILED) { + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -1016,7 +1044,8 @@ int result; int pipe; - /* issue the command */ + /* issue the command -- use usb_control_msg() because + * the state machine is not yet alive */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); result = usb_control_msg(us->pusb_dev, pipe, US_BULK_GET_MAX_LUN, @@ -1034,7 +1063,10 @@ /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + + /* Use usb_clear_halt() because the state machine + * is not yet alive */ + usb_clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -1051,10 +1083,6 @@ int pipe; int partial; - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); @@ -1088,7 +1116,12 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -1099,11 +1132,11 @@ /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { usb_stor_transfer(srb, us); - US_DEBUGP("Bulk data transfer result 0x%x\n", - srb->result); + result = srb->result; + US_DEBUGP("Bulk data transfer result 0x%x\n", result); /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + if (result == US_BULK_TRANSFER_ABORTED) return USB_STOR_TRANSPORT_ABORTED; } } @@ -1127,8 +1160,12 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, @@ -1141,7 +1178,11 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ERROR; } } @@ -1220,10 +1261,10 @@ set_current_state(TASK_RUNNING); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); /* return a result code based on the result of the control message */ @@ -1259,10 +1300,10 @@ schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("Bulk soft reset completed\n"); return SUCCESS; } diff -urN linux-2.4.18/drivers/usb/storage/transport.h linux-2.4.19-pre5/drivers/usb/storage/transport.h --- linux-2.4.18/drivers/usb/storage/transport.h Sat Mar 16 21:16:50 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/transport.h Sat Mar 30 22:55:35 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $ + * $Id: transport.h,v 1.17 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -112,7 +112,7 @@ #define US_BULK_GET_MAX_LUN 0xfe /* - * us_bulk_transfer() return codes + * usb_stor_transfer() return codes */ #define US_BULK_TRANSFER_GOOD 0 /* good transfer */ #define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */ @@ -151,6 +151,6 @@ unsigned int*); extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8, u16, u16, void*, u16); +extern int usb_stor_clear_halt(struct us_data*, int ); extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_clear_halt(struct usb_device*, int ); #endif diff -urN linux-2.4.18/drivers/usb/storage/unusual_devs.h linux-2.4.19-pre5/drivers/usb/storage/unusual_devs.h --- linux-2.4.18/drivers/usb/storage/unusual_devs.h Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/unusual_devs.h Sat Mar 30 22:55:35 2002 @@ -1,10 +1,10 @@ /* Driver for USB Mass Storage compliant devices * Ununsual Devices File * - * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $ + * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $ * * Current development and maintenance by: - * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. @@ -198,7 +198,7 @@ /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, "Sony", - "DSC-S30/S70/S75/505V/F505", + "DSC-S30/S70/S75/505V/F505/F707", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), @@ -289,9 +289,30 @@ "Lexar", "Jumpshot USB CF Reader", US_SC_SCSI, US_PR_JUMPSHOT, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif +/* Reported by Carlos Villegas + * This device needs an INQUIRY of exactly 36-bytes to function. + * That is the only reason this entry is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, + "SIIG", + "CompactFlash Card Reader", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + +/* Reported by Peter Marks + * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly + * 36 bytes of data. No more, no less. That is the only reason this entry + * is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, + "EagleTec", + "External Hard Disk", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -305,6 +326,14 @@ US_FL_SINGLE_LUN | US_FL_START_STOP ), #endif +/* Submitted by kedar@centillium + * Needed for START_STOP flag, but that is unconfirmed */ +UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, + "Minolta", + "Dimage S304", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), + /* Submitted by f.brugmans@hccnet.nl * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, @@ -381,7 +410,7 @@ "Datafab", "MDCFE-B USB CF Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* * The following Datafab-based devices may or may not work @@ -398,38 +427,38 @@ "SIIG/Datafab", "SIIG/Datafab Memory Stick+CF Reader/Writer", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff, "PNY/Datafab", "PNY/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff, "Simple Tech/Datafab", "Simple Tech/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* Submitted by Olaf Hering */ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, "Datafab Systems, Inc.", "USB to CF + SM Combo (LC1)", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant @@ -469,6 +498,8 @@ /* Reported by Dan Pilone * The device needs the flags only. + * Also reported by Brian Hall , again for flags. + * I also suspect this device may have a broken serial number. */ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, "CCYU TECHNOLOGY", diff -urN linux-2.4.18/drivers/usb/storage/usb.c linux-2.4.19-pre5/drivers/usb/storage/usb.c --- linux-2.4.18/drivers/usb/storage/usb.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/storage/usb.c Sat Mar 30 22:55:35 2002 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $ + * $Id: usb.c,v 1.73 2002/01/27 09:02:15 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) @@ -318,6 +318,7 @@ current->files = init_task.files; atomic_inc(¤t->files->count); daemonize(); + reparent_to_init(); /* avoid getting signals */ spin_lock_irq(¤t->sigmask_lock); @@ -958,6 +959,7 @@ ss->protocol_name = "Unknown"; kfree(ss->current_urb); kfree(ss); + usb_dec_dev_use(dev); return NULL; break; } @@ -965,6 +967,8 @@ /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { + kfree(ss->current_urb); + kfree(ss); usb_dec_dev_use(dev); return NULL; } diff -urN linux-2.4.18/drivers/usb/stv680.c linux-2.4.19-pre5/drivers/usb/stv680.c --- linux-2.4.18/drivers/usb/stv680.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/stv680.c Sat Mar 30 22:55:35 2002 @@ -50,6 +50,12 @@ * improve quality. Got rid of green line around * frame. Fix brightness reset when changing size * bug. Adjusted gamma filters slightly. + * + * ver 0.25 Jan, 2002 (kjs) + * Fixed a bug in which the driver sometimes attempted + * to set to a non-supported size. This allowed + * gnomemeeting to work. + * Fixed proc entry removal bug. */ #include @@ -87,7 +93,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.24" +#define DRIVER_VERSION "v0.25" #define DRIVER_AUTHOR "Kevin Sisson " #define DRIVER_DESC "STV0680 USB Camera Driver" @@ -659,7 +665,7 @@ if (stv680_proc_entry == NULL) return; - remove_proc_entry ("stv", video_proc_entry); + remove_proc_entry ("stv680", video_proc_entry); } #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ @@ -862,20 +868,23 @@ if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { width = stv680->maxwidth / 2; height = stv680->maxheight / 2; - } else if ((width >= 158) && (width <= 166)) { + } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) { width = 160; height = 120; - } else if ((width >= 172) && (width <= 180)) { + } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) { width = 176; height = 144; - } else if ((width >= 318) && (width <= 350)) { + } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) { width = 320; height = 240; - } else if ((width >= 350) && (width <= 358)) { + } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) { width = 352; height = 288; + } else { + PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); + return 1; } - + /* Stop a current stream and start it again at the new size */ if (wasstreaming) stv680_stop_stream (stv680); diff -urN linux-2.4.18/drivers/usb/uhci.c linux-2.4.19-pre5/drivers/usb/uhci.c --- linux-2.4.18/drivers/usb/uhci.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/uhci.c Sat Mar 30 22:55:40 2002 @@ -4,7 +4,7 @@ * Maintainer: Johannes Erdfelt * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2001 Johannes Erdfelt, johannes@erdfelt.com + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de @@ -57,7 +57,6 @@ #include - /* * Version Information */ @@ -65,7 +64,6 @@ #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" #define DRIVER_DESC "USB Universal Host Controller Interface driver" - /* * debug = 0, no debugging messages * debug = 1, dump failed URB's except for stalls @@ -100,6 +98,7 @@ /* If a transfer is still active after this much time, turn off FSBR */ #define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ +#define FSBR_DELAY (HZ / 20) /* 50 ms */ #define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */ @@ -240,10 +239,10 @@ unsigned long flags; /* If it's not inserted, don't remove it */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame == -1 && list_empty(&td->fl_list)) - return; + goto out; - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { uhci->fl->frame[td->frame] = td->link; @@ -268,6 +267,7 @@ list_del_init(&td->fl_list); td->frame = -1; +out: spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } @@ -358,6 +358,9 @@ pci_pool_free(uhci->qh_pool, qh, qh->dma_handle); } +/* + * MUST be called with uhci->frame_list_lock acquired + */ static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -417,11 +420,10 @@ return; /* Only go through the hoops if it's actually linked in */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (!list_empty(&qh->list)) { qh->urbp = NULL; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - pqh = list_entry(qh->list.prev, struct uhci_qh, list); if (pqh->urbp) { @@ -444,9 +446,8 @@ qh->element = qh->link = UHCI_PTR_TERM; list_del_init(&qh->list); - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); @@ -617,7 +618,7 @@ { struct urb_priv *urbp; - urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); + urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC); if (!urbp) { err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n"); return NULL; @@ -658,6 +659,9 @@ return urbp; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -667,6 +671,9 @@ list_add_tail(&td->list, &urbp->td_list); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_remove_td_from_urb(struct uhci_td *td) { if (list_empty(&td->list)) @@ -677,22 +684,22 @@ td->urb = NULL; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_destroy_urb_priv(struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp; struct uhci *uhci; - unsigned long flags; - - spin_lock_irqsave(&urb->lock, flags); urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) - goto out; + return; if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) { warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb); - goto out; + return; } if (!list_empty(&urb->urb_list)) @@ -715,20 +722,21 @@ uhci_free_td(uhci, td); } - if (urbp->setup_packet_dma_handle) + if (urbp->setup_packet_dma_handle) { pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); + urbp->setup_packet_dma_handle = 0; + } - if (urbp->transfer_buffer_dma_handle) + if (urbp->transfer_buffer_dma_handle) { pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + urbp->transfer_buffer_dma_handle = 0; + } urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); - -out: - spin_unlock_irqrestore(&urb->lock, flags); } static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb) @@ -757,7 +765,7 @@ if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) - uhci->skel_term_qh->link = UHCI_PTR_TERM; + uhci->fsbrtimeout = jiffies + FSBR_DELAY; } spin_unlock_irqrestore(&uhci->frame_list_lock, flags); @@ -870,7 +878,7 @@ * It's IN if the pipe is an output pipe or we're not expecting * data back. */ - destination &= ~TD_PID; + destination &= ~TD_TOKEN_PID_MASK; if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) destination |= USB_PID_IN; else @@ -1308,9 +1316,7 @@ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct list_head *tmp, *head; int ret = 0; - unsigned long flags; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1333,8 +1339,6 @@ } else ret = -1; /* no previous urb found */ - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - return ret; } @@ -1442,34 +1446,30 @@ return ret; } +/* + * MUST be called with uhci->urb_list_lock acquired + */ static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb) { struct list_head *tmp, *head; - unsigned long flags; - struct urb *u = NULL; /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { - u = list_entry(tmp, struct urb, urb_list); + struct urb *u = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; if (u->dev == urb->dev && u->pipe == urb->pipe && u->status == -EINPROGRESS) - goto out; + return u; } - u = NULL; -out: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - - return u; + return NULL; } static int uhci_submit_urb(struct urb *urb) @@ -1493,13 +1493,15 @@ INIT_LIST_HEAD(&urb->urb_list); usb_inc_dev_use(urb->dev); - spin_lock_irqsave(&urb->lock, flags); + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || urb->status == -ECONNABORTED) { dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status); /* Since we can have problems on the out path */ - spin_unlock_irqrestore(&urb->lock, flags); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); usb_dec_dev_use(urb->dev); return ret; @@ -1568,19 +1570,24 @@ out: urb->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - if (ret == -EINPROGRESS) { - spin_lock_irqsave(&uhci->urb_list_lock, flags); /* We use _tail to make find_urb_ep more efficient */ list_add_tail(&urb->urb_list, &uhci->urb_list); + + spin_unlock(&urb->lock); spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; } uhci_unlink_generic(uhci, urb); - uhci_call_completion(urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + + /* Only call completion if it was successful */ + if (!ret) + uhci_call_completion(urb); return ret; } @@ -1588,7 +1595,7 @@ /* * Return the result of a transfer * - * Must be called with urb_list_lock acquired + * MUST be called with urb_list_lock acquired */ static void uhci_transfer_result(struct uhci *uhci, struct urb *urb) { @@ -1627,10 +1634,10 @@ urbp->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - - if (ret == -EINPROGRESS) + if (ret == -EINPROGRESS) { + spin_unlock_irqrestore(&urb->lock, flags); return; + } switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1646,6 +1653,7 @@ /* Interrupts are an exception */ if (urb->interval) { uhci_add_complete(urb); + spin_unlock_irqrestore(&urb->lock, flags); return; /* <-- note return */ } @@ -1660,15 +1668,22 @@ usb_pipetype(urb->pipe), urb); } + /* Remove it from uhci->urb_list */ list_del_init(&urb->urb_list); uhci_add_complete(urb); + + spin_unlock_irqrestore(&urb->lock, flags); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp = urb->hcpriv; + int prevactive = 1; /* We can get called when urbp allocation fails, so check */ if (!urbp) @@ -1676,6 +1691,19 @@ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + /* + * Now we need to find out what the last successful toggle was + * so we can update the local data toggle for the next transfer + * + * There's 3 way's the last successful completed TD is found: + * + * 1) The TD is NOT active and the actual length < expected length + * 2) The TD is NOT active and it's the last TD in the chain + * 3) The TD is active and the previous TD is NOT active + * + * Control and Isochronous ignore the toggle, so this is safe + * for all types + */ head = &urbp->td_list; tmp = head->next; while (tmp != head) { @@ -1683,15 +1711,18 @@ tmp = tmp->next; - /* Control and Isochronous ignore the toggle, so this */ - /* is safe for all types */ - if ((!(td->status & TD_CTRL_ACTIVE) && - (uhci_actual_length(td->status) < uhci_expected_length(td->info)) || - tmp == head)) { + if (!(td->status & TD_CTRL_ACTIVE) && + (uhci_actual_length(td->status) < uhci_expected_length(td->info) || + tmp == head)) usb_settoggle(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info), uhci_toggle(td->info) ^ 1); - } + else if ((td->status & TD_CTRL_ACTIVE) && !prevactive) + usb_settoggle(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info), + uhci_toggle(td->info)); + + prevactive = td->status & TD_CTRL_ACTIVE; } uhci_delete_queued_urb(uhci, urb); @@ -1714,6 +1745,9 @@ uhci = (struct uhci *)urb->dev->bus->hcpriv; + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); + /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) { @@ -1729,35 +1763,41 @@ } } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS) { + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; + } - spin_lock_irqsave(&uhci->urb_list_lock, flags); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); uhci_unlink_generic(uhci, urb); /* Short circuit the virtual root hub */ if (urb->dev == uhci->rh.dev) { rh_unlink_urb(urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } else { if (urb->transfer_flags & USB_ASYNC_UNLINK) { - /* urb_list is available now since we called */ - /* uhci_unlink_generic already */ - urbp->status = urb->status = -ECONNABORTED; - spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); + spin_lock(&uhci->urb_remove_list_lock); - /* Check to see if the remove list is empty */ + /* If we're the first, set the next interrupt bit */ if (list_empty(&uhci->urb_remove_list)) uhci_set_next_interrupt(uhci); list_add(&urb->urb_list, &uhci->urb_remove_list); - spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); + spin_unlock(&uhci->urb_remove_list_lock); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + } else { urb->status = -ENOENT; @@ -1770,6 +1810,9 @@ } else schedule_timeout(1+1*HZ/1000); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } } @@ -1903,12 +1946,14 @@ /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ static int rh_send_irq(struct urb *urb) { - int i, len = 1; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; unsigned int io_addr = uhci->io_addr; + unsigned long flags; + int i, len = 1; __u16 data = 0; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + spin_lock_irqsave(&urb->lock, flags); for (i = 0; i < uhci->rh.numports; i++) { data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); len = (i + 1) / 8 + 1; @@ -1918,6 +1963,8 @@ urb->actual_length = len; urbp->status = 0; + spin_unlock_irqrestore(&urb->lock, flags); + 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); @@ -1944,7 +1991,6 @@ spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; - tmp = head->next; while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); @@ -1952,6 +1998,8 @@ tmp = tmp->next; + spin_lock(&urb->lock); + /* Check if the FSBR timed out */ if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); @@ -1961,6 +2009,8 @@ list_del(&u->urb_list); list_add_tail(&u->urb_list, &list); } + + spin_unlock(&urb->lock); } spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -1975,6 +2025,12 @@ uhci_unlink_urb(u); } + /* Really disable FSBR */ + if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { + uhci->fsbrtimeout = 0; + uhci->skel_term_qh->link = UHCI_PTR_TERM; + } + /* enter global suspend if nothing connected */ if (!uhci->is_suspended && !ports_active(uhci)) suspend_hc(uhci); @@ -2194,6 +2250,9 @@ return stat; } +/* + * MUST be called with urb->lock acquired + */ static int rh_unlink_urb(struct urb *urb) { struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; @@ -2229,16 +2288,25 @@ static void uhci_call_completion(struct urb *urb) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct urb_priv *urbp; struct usb_device *dev = urb->dev; struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; int is_ring = 0, killed, resubmit_interrupt, status; struct urb *nurb; + unsigned long flags; + + spin_lock_irqsave(&urb->lock, flags); + + urbp = (struct urb_priv *)urb->hcpriv; + if (!urbp || !urb->dev) { + spin_unlock_irqrestore(&urb->lock, flags); + return; + } killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || urb->status == -ECONNRESET); resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && - urb->interval && !killed); + urb->interval); nurb = urb->next; if (nurb && !killed) { @@ -2263,14 +2331,6 @@ is_ring = (nurb == urb); } - status = urbp->status; - if (!resubmit_interrupt) - /* We don't need urb_priv anymore */ - uhci_destroy_urb_priv(urb); - - if (!killed) - urb->status = status; - if (urbp->transfer_buffer_dma_handle) pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? @@ -2280,11 +2340,28 @@ pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); + status = urbp->status; + if (!resubmit_interrupt || killed) + /* We don't need urb_priv anymore */ + uhci_destroy_urb_priv(urb); + + if (!killed) + urb->status = status; + urb->dev = NULL; - if (urb->complete) + spin_unlock_irqrestore(&urb->lock, flags); + + if (urb->complete) { urb->complete(urb); - if (resubmit_interrupt) { + /* Recheck the status. The completion handler may have */ + /* unlinked the resubmitting interrupt URB */ + killed = (urb->status == -ENOENT || + urb->status == -ECONNABORTED || + urb->status == -ECONNRESET); + } + + if (resubmit_interrupt && !killed) { urb->dev = dev; uhci_reset_interrupt(urb); } else { @@ -2311,11 +2388,14 @@ struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); struct urb *urb = urbp->urb; - tmp = tmp->next; - list_del_init(&urbp->complete_list); + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); uhci_call_completion(urb); + + spin_lock_irqsave(&uhci->complete_list_lock, flags); + head = &uhci->complete_list; + tmp = head->next; } spin_unlock_irqrestore(&uhci->complete_list_lock, flags); } @@ -2337,7 +2417,8 @@ list_del_init(&urb->urb_list); urbp->status = urb->status = -ECONNRESET; - uhci_call_completion(urb); + + uhci_add_complete(urb); } spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } @@ -3070,3 +3151,4 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + diff -urN linux-2.4.18/drivers/usb/uhci.h linux-2.4.19-pre5/drivers/usb/uhci.h --- linux-2.4.18/drivers/usb/uhci.h Mon Feb 18 06:31:00 2002 +++ linux-2.4.19-pre5/drivers/usb/uhci.h Sat Mar 30 22:55:35 2002 @@ -121,15 +121,16 @@ * for TD : (a.k.a. Token) */ #define TD_TOKEN_TOGGLE 19 -#define TD_PID 0xFF +#define TD_TOKEN_PID_MASK 0xFF +#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */ #define uhci_maxlen(token) ((token) >> 21) -#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ +#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */ #define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) #define uhci_endpoint(token) (((token) >> 15) & 0xf) #define uhci_devaddr(token) (((token) >> 8) & 0x7f) #define uhci_devep(token) (((token) >> 8) & 0x7ff) -#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetid(token) ((token) & TD_TOKEN_PID_MASK) #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) @@ -163,7 +164,7 @@ struct list_head list; /* P: urb->lock */ int frame; - struct list_head fl_list; /* P: frame_list_lock */ + struct list_head fl_list; /* P: uhci->frame_list_lock */ } __attribute__((aligned(16))); /* @@ -306,21 +307,26 @@ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ spinlock_t frame_list_lock; - struct uhci_frame_list *fl; /* Frame list */ + struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ int fsbr; /* Full speed bandwidth reclamation */ + unsigned long fsbrtimeout; /* FSBR delay */ int is_suspended; + /* Main list of URB's currently controlled by this HC */ + spinlock_t urb_list_lock; + struct list_head urb_list; /* P: uhci->urb_list_lock */ + + /* List of QH's that are done, but waiting to be unlinked (race) */ spinlock_t qh_remove_list_lock; - struct list_head qh_remove_list; + struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ + /* List of asynchronously unlinked URB's */ spinlock_t urb_remove_list_lock; - struct list_head urb_remove_list; - - spinlock_t urb_list_lock; - struct list_head urb_list; + struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ + /* List of URB's awaiting completion callback */ spinlock_t complete_list_lock; - struct list_head complete_list; + struct list_head complete_list; /* P: uhci->complete_list_lock */ struct virt_root_hub rh; /* private data of the virtual root hub */ }; @@ -333,7 +339,7 @@ dma_addr_t transfer_buffer_dma_handle; struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; + struct list_head td_list; /* P: urb->lock */ int fsbr : 1; /* URB turned on FSBR */ int fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -345,11 +351,36 @@ int status; /* Final status */ unsigned long inserttime; /* In jiffies */ - unsigned long fsbrtime; /* In jiffies */ + unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; - struct list_head complete_list; + struct list_head queue_list; /* P: uhci->frame_list_lock */ + struct list_head complete_list; /* P: uhci->complete_list_lock */ }; + +/* + * Locking in uhci.c + * + * spinlocks are used extensively to protect the many lists and data + * structures we have. It's not that pretty, but it's necessary. We + * need to be done with all of the locks (except complete_list_lock) when + * we call urb->complete. I've tried to make it simple enough so I don't + * have to spend hours racking my brain trying to figure out if the + * locking is safe. + * + * Here's the safe locking order to prevent deadlocks: + * + * #1 uhci->urb_list_lock + * #2 urb->lock + * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, + * uhci->qh_remove_list_lock + * #4 uhci->complete_list_lock + * + * If you're going to grab 2 or more locks at once, ALWAYS grab the lock + * at the lowest level FIRST and NEVER grab locks at the same level at the + * same time. + * + * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock + */ /* ------------------------------------------------------------------------- Virtual Root HUB diff -urN linux-2.4.18/drivers/usb/usb-ohci.c linux-2.4.19-pre5/drivers/usb/usb-ohci.c --- linux-2.4.18/drivers/usb/usb-ohci.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/usb-ohci.c Sat Mar 30 22:55:40 2002 @@ -11,6 +11,9 @@ * * * History: + * + * 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and + * make interrupt unlink-in-completion work (db) * * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes) * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt) @@ -486,9 +489,8 @@ /* implicitly requeued */ urb->actual_length = 0; - urb->status = USB_ST_URB_PENDING; - if (urb_priv->state != URB_DEL) - td_submit_urb (urb); + urb->status = -EINPROGRESS; + td_submit_urb (urb); break; case PIPE_ISOCHRONOUS: @@ -790,6 +792,7 @@ /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; spin_unlock_irqrestore (&usb_ed_lock, flags); + return -EINPROGRESS; } } else { urb_rm_priv (urb); diff -urN linux-2.4.18/drivers/usb/usb-skeleton.c linux-2.4.19-pre5/drivers/usb/usb-skeleton.c --- linux-2.4.18/drivers/usb/usb-skeleton.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/usb-skeleton.c Sat Mar 30 22:55:36 2002 @@ -1,5 +1,5 @@ /* - * USB Skeleton driver - 0.6 + * USB Skeleton driver - 0.7 * * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * @@ -22,6 +22,9 @@ * * History: * + * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do + * not have both a bulk in and bulk out endpoint. + * Thanks to Holger Waechtler for the fix. * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. * Thanks to Pete Zaitcev for the fix. * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux @@ -540,6 +543,7 @@ err ("Out of memory"); goto exit; } + memset (dev, 0x00, sizeof (*dev)); minor_table[minor] = dev; interface = &udev->actconfig->interface[ifnum]; diff -urN linux-2.4.18/drivers/usb/usb.c linux-2.4.19-pre5/drivers/usb/usb.c --- linux-2.4.18/drivers/usb/usb.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/usb.c Sat Mar 30 22:55:40 2002 @@ -1955,7 +1955,7 @@ /* 9.4.10 says devices don't need this, if the interface only has one alternate setting */ if (iface->num_altsetting == 1) { - warn("ignoring set_interface for dev %d, iface %d, alt %d", + dbg("ignoring set_interface for dev %d, iface %d, alt %d", dev->devnum, interface, alternate); return 0; } diff -urN linux-2.4.18/drivers/usb/vicam.c linux-2.4.19-pre5/drivers/usb/vicam.c --- linux-2.4.18/drivers/usb/vicam.c Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/usb/vicam.c Sat Mar 30 22:55:36 2002 @@ -79,7 +79,7 @@ static struct usb_driver vicam_driver; static char *buf, *buf2; -static int change_pending = 0; +static volatile int change_pending = 0; static int vicam_parameters(struct usb_vicam *vicam); @@ -330,8 +330,14 @@ static void synchronize(struct usb_vicam *vicam) { + DECLARE_WAITQUEUE(wait, current); change_pending = 1; - interruptible_sleep_on(&vicam->wait); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&vicam->wait, &wait); + if (change_pending) + schedule(); + remove_wait_queue(&vicam->wait, &wait); + set_current_state(TASK_RUNNING); vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); mdelay(10); vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); @@ -890,13 +896,16 @@ vicam->win.contrast = 10; /* FIXME */ - if (vicam_init(vicam)) + if (vicam_init(vicam)) { + kfree(vicam); return NULL; + } memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { err("video_register_device"); + kfree(vicam); return NULL; } diff -urN linux-2.4.18/drivers/video/Config.in linux-2.4.19-pre5/drivers/video/Config.in --- linux-2.4.18/drivers/video/Config.in Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/video/Config.in Sat Mar 30 22:55:40 2002 @@ -26,6 +26,9 @@ fi fi fi + if [ "$CONFIG_PCI" = "y" ]; then + tristate ' Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3 + fi fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then bool ' Acorn VIDC support' CONFIG_FB_ACORN @@ -128,7 +131,7 @@ dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C fi fi - dep_tristate ' G450/G550 second head support' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100 + dep_tristate ' G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100 bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY @@ -143,6 +146,7 @@ bool ' SIS 630/540/730 support' CONFIG_FB_SIS_300 bool ' SIS 315H/315 support' CONFIG_FB_SIS_315 fi + tristate ' NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX tristate ' 3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1 tristate ' Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT @@ -263,13 +267,14 @@ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \ - "$CONFIG_FB_SIS" = "y" ]; then + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -283,13 +288,14 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \ "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_TX3912" = "m" ]; then + "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi fi @@ -302,10 +308,12 @@ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ - "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then + "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \ + "$CONFIG_FB_NEOMAGIC" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -317,10 +325,12 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ - "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then + "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \ + "$CONFIG_FB_NEOMAGIC" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -329,7 +339,7 @@ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ - "$CONFIG_FB_VOODOO1" = "y" ]; then + "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then define_tristate CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ @@ -337,7 +347,7 @@ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \ - "$CONFIG_FB_VOODOO1" = "m" ]; then + "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then define_tristate CONFIG_FBCON_CFB24 m fi fi @@ -346,6 +356,7 @@ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ @@ -358,6 +369,7 @@ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ diff -urN linux-2.4.18/drivers/video/Makefile linux-2.4.19-pre5/drivers/video/Makefile --- linux-2.4.18/drivers/video/Makefile Sun Mar 3 17:17:08 2002 +++ linux-2.4.19-pre5/drivers/video/Makefile Sat Mar 30 22:55:40 2002 @@ -44,11 +44,13 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_AMIGA) += amifb.o obj-$(CONFIG_FB_PM2) += pm2fb.o fbgen.o +obj-$(CONFIG_FB_PM3) += pm3fb.o fbgen.o obj-$(CONFIG_FB_APOLLO) += dnfb.o obj-$(CONFIG_FB_Q40) += q40fb.o obj-$(CONFIG_FB_ATARI) += atafb.o obj-$(CONFIG_FB_ATY128) += aty128fb.o obj-$(CONFIG_FB_RADEON) += radeonfb.o +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o obj-$(CONFIG_FB_IGA) += igafb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o diff -urN linux-2.4.18/drivers/video/acornfb.c linux-2.4.19-pre5/drivers/video/acornfb.c --- linux-2.4.18/drivers/video/acornfb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/video/acornfb.c Sat Mar 30 22:55:36 2002 @@ -1139,9 +1139,6 @@ off += start; vma->vm_pgoff = off >> PAGE_SHIFT; - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; - #ifdef CONFIG_CPU_32 pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; #endif diff -urN linux-2.4.18/drivers/video/amifb.c linux-2.4.19-pre5/drivers/video/amifb.c --- linux-2.4.18/drivers/video/amifb.c Sat Dec 1 18:27:13 2001 +++ linux-2.4.19-pre5/drivers/video/amifb.c Sat Mar 30 22:55:36 2002 @@ -61,7 +61,6 @@ #include #include #include -#include #include